From d9c0f602a2d2b36b0e46466e37c0d09da5ab33e0 Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 27 Oct 2019 18:42:40 +0300 Subject: [PATCH 001/830] Allow users into server based on addons count --- src/network/protocols/server_lobby.cpp | 100 ++++++++++++++++++++++--- src/network/protocols/server_lobby.hpp | 9 +++ src/network/server_config.hpp | 24 ++++++ src/network/stk_peer.hpp | 8 ++ 4 files changed, 131 insertions(+), 10 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 0504cfa9089..2922da59674 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -152,6 +152,15 @@ ServerLobby::ServerLobby() : LobbyProtocol() track_manager->getArenasInGroup("standard", false); std::vector all_soccers = track_manager->getArenasInGroup("standard", true); + std::vector addon_karts = + kart_properties_manager->getKartsInGroup("Add-Ons"); + std::vector addon_tracks = + track_manager->getTracksInGroup("Add-Ons"); + std::vector addon_arenas = + track_manager->getArenasInGroup("Add-Ons", false); + std::vector addon_soccers = + track_manager->getArenasInGroup("Add-Ons", true); + std::vector all_tracks = all_t; all_t.insert(all_t.end(), all_arenas.begin(), all_arenas.end()); all_t.insert(all_t.end(), all_soccers.begin(), all_soccers.end()); @@ -168,6 +177,31 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_official_kts.second.insert(t->getIdent()); } + for (int kart : addon_karts) + { + const KartProperties* kp = kart_properties_manager->getKartById(kart); + if (!kp->isAddon()) + m_addon_kts.first.insert(kp->getIdent()); + } + for (int track : addon_tracks) + { + Track* t = track_manager->getTrack(track); + if (!t->isAddon()) + m_addon_kts.second.insert(t->getIdent()); + } + for (int arena : addon_arenas) + { + Track* t = track_manager->getTrack(arena); + if (!t->isAddon()) + m_addon_arenas.insert(t->getIdent()); + } + for (int soccer : addon_soccers) + { + Track* t = track_manager->getTrack(soccer); + if (!t->isAddon()) + m_addon_soccers.insert(t->getIdent()); + } + m_rs_state.store(RS_NONE); m_last_success_poll_time.store(StkTime::getMonoTimeMs() + 30000); m_server_owner_id.store(-1); @@ -283,7 +317,11 @@ void ServerLobby::initServerStatsTable() " version TEXT NOT NULL, -- SuperTuxKart version of the host (with OS info)\n" " connected_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Time when connected\n" " disconnected_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Time when disconnected (saved when disconnected)\n" - " ping INTEGER UNSIGNED NOT NULL DEFAULT 0 -- Ping of the host\n" + " ping INTEGER UNSIGNED NOT NULL DEFAULT 0, -- Ping of the host\n" + " addon_karts_count INTEGER UNSIGNED NOT NULL DEFAULT 0, -- Number of addon karts of the host\n" + " addon_tracks_count INTEGER UNSIGNED NOT NULL DEFAULT 0, -- Number of addon tracks of the host\n" + " addon_arenas_count INTEGER UNSIGNED NOT NULL DEFAULT 0, -- Number of addon arenas of the host\n" + " addon_soccers_count INTEGER UNSIGNED NOT NULL DEFAULT 0 -- Number of addon soccers of the host\n" ") WITHOUT ROWID;"; std::string query = oss.str(); sqlite3_stmt* stmt = NULL; @@ -337,7 +375,9 @@ void ServerLobby::initServerStatsTable() oss << " port, online_id, username, player_num,\n" << " " << m_server_stats_table << ".country_code AS country_code, country_flag, country_name, version,\n" << " ROUND((STRFTIME(\"%s\", disconnected_time) - STRFTIME(\"%s\", connected_time)) / 60.0, 2) AS time_played,\n" - << " connected_time, disconnected_time, ping FROM " << m_server_stats_table << "\n" + << " connected_time, disconnected_time, ping,\n" + << " addon_karts_count, addon_tracks_count, addon_arenas_count,\n" + << " addon_soccers_count FROM " << m_server_stats_table << "\n" << " LEFT JOIN " << country_table_name << " ON " << country_table_name << ".country_code = " << m_server_stats_table << ".country_code\n" << " ORDER BY connected_time DESC;"; @@ -360,7 +400,9 @@ void ServerLobby::initServerStatsTable() oss << " port, online_id, username, player_num,\n" << " " << m_server_stats_table << ".country_code AS country_code, country_flag, country_name, version,\n" << " ROUND((STRFTIME(\"%s\", 'now') - STRFTIME(\"%s\", connected_time)) / 60.0, 2) AS time_played,\n" - << " connected_time, ping FROM " << m_server_stats_table << "\n" + << " connected_time, ping, " + << " addon_karts_count, addon_tracks_count, addon_arenas_count,\n" + << " addon_soccers_count FROM " << m_server_stats_table << "\n" << " LEFT JOIN " << country_table_name << " ON " << country_table_name << ".country_code = " << m_server_stats_table << ".country_code\n" << " WHERE connected_time = disconnected_time;"; @@ -2981,11 +3023,18 @@ void ServerLobby::connectionRequested(Event* event) // as server float okt = 0.0f; float ott = 0.0f; + int addon_karts = 0; + int addon_tracks = 0; + int addon_arenas = 0; + int addon_soccers = 0; for (auto& client_kart : client_karts) { if (m_official_kts.first.find(client_kart) != m_official_kts.first.end()) okt += 1.0f; + if (m_addon_kts.first.find(client_kart) != + m_addon_kts.first.end()) + ++addon_karts; } okt = okt / (float)m_official_kts.first.size(); for (auto& client_track : client_tracks) @@ -2993,6 +3042,15 @@ void ServerLobby::connectionRequested(Event* event) if (m_official_kts.second.find(client_track) != m_official_kts.second.end()) ott += 1.0f; + if (m_addon_kts.second.find(client_track) != + m_addon_kts.second.end()) + ++addon_tracks; + if (m_addon_arenas.find(client_track) != + m_addon_arenas.end()) + ++addon_arenas; + if (m_addon_soccers.find(client_track) != + m_addon_soccers.end()) + ++addon_soccers; } ott = ott / (float)m_official_kts.second.size(); @@ -3012,10 +3070,26 @@ void ServerLobby::connectionRequested(Event* event) } } + Log::info("ServerLobby", "Player has the following addons: %d/%d karts," + " %d/%d tracks, %d/%d arenas, %d/%d soccer fields.", addon_karts, + ServerConfig::m_addon_karts_threshold, addon_tracks, + ServerConfig::m_addon_tracks_threshold, addon_arenas, + ServerConfig::m_addon_arenas_threshold, addon_soccers, + ServerConfig::m_addon_soccers_threshold); + + peer->addon_karts_count = addon_karts; + peer->addon_tracks_count = addon_tracks; + peer->addon_arenas_count = addon_arenas; + peer->addon_soccers_count = addon_soccers; + if (karts_erase.size() == m_available_kts.first.size() || tracks_erase.size() == m_available_kts.second.size() || okt < ServerConfig::m_official_karts_threshold || - ott < ServerConfig::m_official_tracks_threshold) + ott < ServerConfig::m_official_tracks_threshold || + addon_karts < ServerConfig::m_addon_karts_threshold || + addon_tracks < ServerConfig::m_addon_tracks_threshold || + addon_arenas < ServerConfig::m_addon_arenas_threshold || + addon_soccers < ServerConfig::m_addon_soccers_threshold) { NetworkString *message = getNetworkString(2); message->setSynchronous(true); @@ -3299,22 +3373,28 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, query = StringUtils::insertValues( "INSERT INTO %s " "(host_id, ip, ipv6 ,port, online_id, username, player_num, " - "country_code, version, ping) " - "VALUES (%u, 0, \"%s\" ,%u, %u, ?, %u, ?, ?, %u);", + "country_code, version, ping, addon_karts_count, addon_tracks_count, " + "addon_arenas_count, addon_soccers_count) " + "VALUES (%u, 0, \"%s\" ,%u, %u, ?, %u, ?, ?, %u, %d, %d, %d, %d);", m_server_stats_table.c_str(), peer->getHostId(), peer->getIPV6Address(), peer->getAddress().getPort(), online_id, - player_count, peer->getAveragePing()); + player_count, peer->getAveragePing(), peer->addon_karts_count, + peer->addon_tracks_count, peer->addon_arenas_count, + peer->addon_soccers_count); } else { query = StringUtils::insertValues( "INSERT INTO %s " "(host_id, ip, port, online_id, username, player_num, " - "country_code, version, ping) " - "VALUES (%u, %u, %u, %u, ?, %u, ?, ?, %u);", + "country_code, version, ping, addon_karts_count, addon_tracks_count, " + "addon_arenas_count, addon_soccers_count) " + "VALUES (%u, %u, %u, %u, ?, %u, ?, ?, %u, %d, %d, %d, %d);", m_server_stats_table.c_str(), peer->getHostId(), peer->getAddress().getIP(), peer->getAddress().getPort(), - online_id, player_count, peer->getAveragePing()); + online_id, player_count, peer->getAveragePing(), peer->addon_karts_count, + peer->addon_tracks_count, peer->addon_arenas_count, + peer->addon_soccers_count); } easySQLQuery(query, [peer, country_code](sqlite3_stmt* stmt) { diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index f339d777bd1..7e790cde79b 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -125,6 +125,15 @@ class ServerLobby : public LobbyProtocol /** Official karts and tracks available in server. */ std::pair, std::set > m_official_kts; + /** Addon karts and tracks available in server. */ + std::pair, std::set > m_addon_kts; + + /** Addon arenas available in server. */ + std::set m_addon_arenas; + + /** Addon soccers available in server. */ + std::set m_addon_soccers; + /** Available karts and tracks for all clients, this will be initialized * with data in server first. */ std::pair, std::set > m_available_kts; diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 069c00e0ce6..9538527128c 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -211,6 +211,30 @@ namespace ServerConfig "android players from joining this server, because STK android apk " "has some official tracks removed.")); + SERVER_CFG_PREFIX IntServerConfigParam m_addon_karts_threshold + SERVER_CFG_DEFAULT(IntServerConfigParam(0, + "addon_karts_threshold", + "Clients below this value will be rejected from joining this server. " + "It's determined by number of addon karts in client")); + + SERVER_CFG_PREFIX IntServerConfigParam m_addon_tracks_threshold + SERVER_CFG_DEFAULT(IntServerConfigParam(0, + "addon_tracks_threshold", + "Clients below this value will be rejected from joining this server. " + "It's determined by number of addon tracks in client")); + + SERVER_CFG_PREFIX IntServerConfigParam m_addon_arenas_threshold + SERVER_CFG_DEFAULT(IntServerConfigParam(0, + "addon_arenas_threshold", + "Clients below this value will be rejected from joining this server. " + "It's determined by number of addon arenas in client")); + + SERVER_CFG_PREFIX IntServerConfigParam m_addon_soccers_threshold + SERVER_CFG_DEFAULT(IntServerConfigParam(0, + "addon_soccers_threshold", + "Clients below this value will be rejected from joining this server. " + "It's determined by number of addon soccer fields in client")); + SERVER_CFG_PREFIX IntServerConfigParam m_min_start_game_players SERVER_CFG_DEFAULT(IntServerConfigParam(2, "min-start-game-players", "Only auto start kart selection when number of " diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index aa913286142..af773976d9d 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -250,6 +250,14 @@ class STKPeer : public NoCopy { return m_client_capabilities; } // ------------------------------------------------------------------------ bool isAIPeer() const { return m_user_version == "AI"; } + // ------------------------------------------------------------------------ + int addon_karts_count = 0; + // ------------------------------------------------------------------------ + int addon_tracks_count = 0; + // ------------------------------------------------------------------------ + int addon_arenas_count = 0; + // ------------------------------------------------------------------------ + int addon_soccers_count = 0; }; // STKPeer #endif // STK_PEER_HPP From 7b7b5568d43ba748b8c2abc923b8869bd7642eb7 Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 28 Oct 2019 16:39:01 +0300 Subject: [PATCH 002/830] Fix bugs --- src/network/protocols/server_lobby.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 2922da59674..bf5e2861a7e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -180,25 +180,25 @@ ServerLobby::ServerLobby() : LobbyProtocol() for (int kart : addon_karts) { const KartProperties* kp = kart_properties_manager->getKartById(kart); - if (!kp->isAddon()) + if (kp->isAddon()) m_addon_kts.first.insert(kp->getIdent()); } for (int track : addon_tracks) { Track* t = track_manager->getTrack(track); - if (!t->isAddon()) + if (t->isAddon()) m_addon_kts.second.insert(t->getIdent()); } for (int arena : addon_arenas) { Track* t = track_manager->getTrack(arena); - if (!t->isAddon()) + if (t->isAddon()) m_addon_arenas.insert(t->getIdent()); } for (int soccer : addon_soccers) { Track* t = track_manager->getTrack(soccer); - if (!t->isAddon()) + if (t->isAddon()) m_addon_soccers.insert(t->getIdent()); } @@ -3072,10 +3072,10 @@ void ServerLobby::connectionRequested(Event* event) Log::info("ServerLobby", "Player has the following addons: %d/%d karts," " %d/%d tracks, %d/%d arenas, %d/%d soccer fields.", addon_karts, - ServerConfig::m_addon_karts_threshold, addon_tracks, - ServerConfig::m_addon_tracks_threshold, addon_arenas, - ServerConfig::m_addon_arenas_threshold, addon_soccers, - ServerConfig::m_addon_soccers_threshold); + (int)ServerConfig::m_addon_karts_threshold, addon_tracks, + (int)ServerConfig::m_addon_tracks_threshold, addon_arenas, + (int)ServerConfig::m_addon_arenas_threshold, addon_soccers, + (int)ServerConfig::m_addon_soccers_threshold); peer->addon_karts_count = addon_karts; peer->addon_tracks_count = addon_tracks; @@ -3086,10 +3086,10 @@ void ServerLobby::connectionRequested(Event* event) tracks_erase.size() == m_available_kts.second.size() || okt < ServerConfig::m_official_karts_threshold || ott < ServerConfig::m_official_tracks_threshold || - addon_karts < ServerConfig::m_addon_karts_threshold || - addon_tracks < ServerConfig::m_addon_tracks_threshold || - addon_arenas < ServerConfig::m_addon_arenas_threshold || - addon_soccers < ServerConfig::m_addon_soccers_threshold) + addon_karts < (int)ServerConfig::m_addon_karts_threshold || + addon_tracks < (int)ServerConfig::m_addon_tracks_threshold || + addon_arenas < (int)ServerConfig::m_addon_arenas_threshold || + addon_soccers < (int)ServerConfig::m_addon_soccers_threshold) { NetworkString *message = getNetworkString(2); message->setSynchronous(true); From cff6275a1969f8c910362c1a11e22293b64510b9 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 4 Dec 2019 12:39:45 +0300 Subject: [PATCH 003/830] Added possibility to force players have certain tracks; added restriction on played tracks --- src/network/protocols/server_lobby.cpp | 41 ++++++++++++++++++++++++-- src/network/protocols/server_lobby.hpp | 6 ++++ src/network/server_config.hpp | 10 +++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 214ceb0e035..0744fd528b9 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -211,6 +211,18 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_addon_kts.second.insert(t->getIdent()); } + if (ServerConfig::m_only_played_tracks_string.empty()) + m_restricting_config = false; + else + { + std::vector available_tracks = StringUtils::split(ServerConfig::m_only_played_tracks_string, ' ', false); + for (unsigned i = 0; i < available_tracks.size(); i++) + { + m_config_available_tracks.insert(available_tracks[i]); + } + } + m_must_have_tracks = StringUtils::split(ServerConfig::m_must_have_tracks_string, ' ', false); + m_rs_state.store(RS_NONE); m_last_success_poll_time.store(StkTime::getMonoTimeMs() + 30000); m_server_owner_id.store(-1); @@ -628,7 +640,20 @@ void ServerLobby::updateTracksForMode() assert(false); break; } - + if (m_restricting_config) + { + std::set erase_tracks; + auto it = m_available_kts.second.begin(); + while (it != m_available_kts.second.end()) + { + if (m_config_available_tracks.find(*it) == m_config_available_tracks.end()) + erase_tracks.insert(*it); + it++; + } + for (const std::string& track : erase_tracks) { + m_available_kts.second.erase(track); + } + } } // updateTracksForMode //----------------------------------------------------------------------------- @@ -3035,6 +3060,17 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) const } } + bool has_required_tracks = true; + for (const std::string& required_track : m_must_have_tracks) + { + if (client_tracks.find(required_track) == client_tracks.end()) + { + has_required_tracks = false; + Log::info("ServerLobby", "Player does not have a required track '%s'.", required_track); + break; + } + } + Log::info("ServerLobby", "Player has the following addons: %d/%d karts," " %d/%d tracks, %d/%d arenas, %d/%d soccer fields.", addon_karts, (int)ServerConfig::m_addon_karts_threshold, addon_tracks, @@ -3054,7 +3090,8 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) const addon_karts < (int)ServerConfig::m_addon_karts_threshold || addon_tracks < (int)ServerConfig::m_addon_tracks_threshold || addon_arenas < (int)ServerConfig::m_addon_arenas_threshold || - addon_soccers < (int)ServerConfig::m_addon_soccers_threshold) + addon_soccers < (int)ServerConfig::m_addon_soccers_threshold || + !has_required_tracks) { NetworkString *message = getNetworkString(2); message->setSynchronous(true); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index ab524397e26..b4dc0626161 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -230,6 +230,12 @@ class ServerLobby : public LobbyProtocol // Calculated before each game started unsigned m_ai_count; + std::vector m_must_have_tracks; + + bool m_restricting_config; + + std::set m_config_available_tracks; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 1b41504edc4..b3949984b54 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -236,6 +236,16 @@ namespace ServerConfig "Clients below this value will be rejected from joining this server. " "It's determined by number of addon soccer fields in client")); + SERVER_CFG_PREFIX StringServerConfigParam m_must_have_tracks_string + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "must-have-tracks", "Tracks needed to enter the server, " + "leave empty for no restriction.")); + + SERVER_CFG_PREFIX StringServerConfigParam m_only_played_tracks_string + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "only-played-tracks", "List of tracks that can be played on a server, " + "leave empty for no restriction.")); + SERVER_CFG_PREFIX IntServerConfigParam m_min_start_game_players SERVER_CFG_DEFAULT(IntServerConfigParam(2, "min-start-game-players", "Only auto start kart selection when number of " From cac7dfd85608bc21617575ecc12a6123537ac3c9 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 4 Dec 2019 13:03:27 +0300 Subject: [PATCH 004/830] Fixed bugs, added possibility to *not* list some tracks --- src/network/protocols/server_lobby.cpp | 14 +++++++++++--- src/network/protocols/server_lobby.hpp | 2 ++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 0744fd528b9..9b302a5f90e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -211,12 +211,20 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_addon_kts.second.insert(t->getIdent()); } - if (ServerConfig::m_only_played_tracks_string.empty()) + + m_inverted_config_restriction = false; + m_restricting_config = true; + if (((std::string)(ServerConfig::m_only_played_tracks_string)).empty()) m_restricting_config = false; else { std::vector available_tracks = StringUtils::split(ServerConfig::m_only_played_tracks_string, ' ', false); - for (unsigned i = 0; i < available_tracks.size(); i++) + int start = 0; + if (available_tracks[0] == "not") { + start = 1; + m_inverted_config_restriction = true; + } + for (unsigned i = start; i < available_tracks.size(); i++) { m_config_available_tracks.insert(available_tracks[i]); } @@ -646,7 +654,7 @@ void ServerLobby::updateTracksForMode() auto it = m_available_kts.second.begin(); while (it != m_available_kts.second.end()) { - if (m_config_available_tracks.find(*it) == m_config_available_tracks.end()) + if (m_inverted_config_restriction ^ (m_config_available_tracks.find(*it) == m_config_available_tracks.end())) erase_tracks.insert(*it); it++; } diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index b4dc0626161..345e20b81ff 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -234,6 +234,8 @@ class ServerLobby : public LobbyProtocol bool m_restricting_config; + bool m_inverted_config_restriction; + std::set m_config_available_tracks; // connection management From 389719c5a5a51390f816aad6d321249f5fccd872 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 4 Dec 2019 13:55:37 +0300 Subject: [PATCH 005/830] Add possibility to race without official tracks --- src/network/protocols/server_lobby.cpp | 4 ++-- src/network/server_config.hpp | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 9b302a5f90e..791311fface 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2346,7 +2346,7 @@ void ServerLobby::startSelection(const Event *event) else it++; } - if (official_tracks.empty()) + if (ServerConfig::m_official_tracks_needed && official_tracks.empty()) { Log::error("ServerLobby", "No official tracks for playing!"); return; @@ -3074,7 +3074,7 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) const if (client_tracks.find(required_track) == client_tracks.end()) { has_required_tracks = false; - Log::info("ServerLobby", "Player does not have a required track '%s'.", required_track); + Log::info("ServerLobby", "Player does not have a required track '%s'.", required_track.c_str()); break; } } diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index b3949984b54..d5f325d0f03 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -246,6 +246,11 @@ namespace ServerConfig "only-played-tracks", "List of tracks that can be played on a server, " "leave empty for no restriction.")); + SERVER_CFG_PREFIX BoolServerConfigParam m_official_tracks_needed + SERVER_CFG_DEFAULT(BoolServerConfigParam(true, "official-tracks-needed", + "If this value is set to true, players and the server must have at least " + "one common official track.")); + SERVER_CFG_PREFIX IntServerConfigParam m_min_start_game_players SERVER_CFG_DEFAULT(IntServerConfigParam(2, "min-start-game-players", "Only auto start kart selection when number of " From 8633da9a06c63ff789eb854cdd3f4191beff47c4 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 4 Dec 2019 14:15:48 +0300 Subject: [PATCH 006/830] Fix bugs --- src/network/protocols/server_lobby.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 791311fface..4eb840a532f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2301,7 +2301,7 @@ void ServerLobby::startSelection(const Event *event) if (supportsAI()) { unsigned total_ai_available = - (unsigned)ai->getPlayerProfiles().size(); + (unsigned)ai-addon_>getPlayerProfiles().size(); m_ai_count = max_player > total_ai_available ? 0 : total_ai_available - max_player + 1; // Disable ai peer for this game @@ -2352,8 +2352,15 @@ void ServerLobby::startSelection(const Event *event) return; } RandomGenerator rg; - it = official_tracks.begin(); - std::advance(it, rg.get((int)official_tracks.size())); + const auto& all_k = m_available_kts.first; + const auto& all_t = m_available_kts.second; + if (!official_tracks.empty()) { + it = official_tracks.begin(); + std::advance(it, rg.get((int)official_tracks.size())); + } else { + it = m_available_kts.second.begin(); + std::advance(it, rg.get((int)m_available_kts.second.size())); + } m_default_vote->m_track_name = *it; switch (race_manager->getMinorMode()) { @@ -2423,8 +2430,6 @@ void ServerLobby::startSelection(const Event *event) .addUInt8(ServerConfig::m_auto_game_time_ratio > 0.0f ? 1 : 0) .addUInt8(ServerConfig::m_track_voting ? 1 : 0); - const auto& all_k = m_available_kts.first; - const auto& all_t = m_available_kts.second; ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size()); for (const std::string& kart : all_k) { From 7a9a58ee67cc1ce8034b995dabceb1ccb6428060 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 4 Dec 2019 14:22:18 +0300 Subject: [PATCH 007/830] Fix another bug causing CE --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 4eb840a532f..62142d57e41 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2301,7 +2301,7 @@ void ServerLobby::startSelection(const Event *event) if (supportsAI()) { unsigned total_ai_available = - (unsigned)ai-addon_>getPlayerProfiles().size(); + (unsigned)ai->getPlayerProfiles().size(); m_ai_count = max_player > total_ai_available ? 0 : total_ai_available - max_player + 1; // Disable ai peer for this game From 199a4d59fbd52d9b0e20fa51417c61bfd43f57c4 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 11 Dec 2019 13:38:32 +0300 Subject: [PATCH 008/830] Change max-moveable-objects to 30 --- data/stk_config.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/stk_config.xml b/data/stk_config.xml index 4563a5ee4ed..954b7617320 100644 --- a/data/stk_config.xml +++ b/data/stk_config.xml @@ -233,7 +233,7 @@ larger than this value. --> + max-moveable-objects="30"/> + + + + + + + + + + + + + + + + + + + + + @@ -254,7 +275,12 @@ CREATE TABLE IF NOT EXISTS (table name above) os TEXT NOT NULL, -- Operating system of the host connected_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Time when connected disconnected_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Time when disconnected (saved when disconnected) - ping INTEGER UNSIGNED NOT NULL DEFAULT 0 -- Ping of the host + ping INTEGER UNSIGNED NOT NULL DEFAULT 0, -- Ping of the host + packet_loss INTEGER NOT NULL DEFAULT 0, -- Mean packet loss count from ENet (saved when disconnected) + addon_karts_count INTEGER UNSIGNED NOT NULL DEFAULT 0, -- Number of addon karts of the host + addon_tracks_count INTEGER UNSIGNED NOT NULL DEFAULT 0, -- Number of addon tracks of the host + addon_arenas_count INTEGER UNSIGNED NOT NULL DEFAULT 0, -- Number of addon arenas of the host + addon_soccers_count INTEGER UNSIGNED NOT NULL DEFAULT 0 -- Number of addon soccers of the host ) WITHOUT ROWID; ``` @@ -282,7 +308,7 @@ CREATE TABLE IF NOT EXISTS (table name above) If you want to see flags and readable names of countries in the above views, you need to initialize `v(server database version)_countries` table, check [this script](tools/generate-countries-table.py). -For IPv4 and online ID ban list, player reports or IP mapping, you need to create one yourself: +For IPv4 and online ID ban list, player reports or IP mapping (in case your server doesn't communicate with STK addons server, which can do IP mapping instead of your server), you need to create one yourself: ```sql CREATE TABLE ip_ban ( diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 506b0813a9e..d904285af0e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -153,15 +153,6 @@ ServerLobby::ServerLobby() : LobbyProtocol() track_manager->getArenasInGroup("standard", false); std::vector all_soccers = track_manager->getArenasInGroup("standard", true); - std::vector addon_karts = - kart_properties_manager->getKartsInGroup("Add-Ons"); - std::vector addon_tracks = - track_manager->getTracksInGroup("Add-Ons"); - std::vector addon_arenas = - track_manager->getArenasInGroup("Add-Ons", false); - std::vector addon_soccers = - track_manager->getArenasInGroup("Add-Ons", true); - std::vector all_tracks = all_t; all_t.insert(all_t.end(), all_arenas.begin(), all_arenas.end()); all_t.insert(all_t.end(), all_soccers.begin(), all_soccers.end()); @@ -177,6 +168,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() if (!t->isAddon()) m_official_kts.second.insert(t->getIdent()); } + std::set total_addons; for (unsigned i = 0; i < kart_properties_manager->getNumberOfKarts(); i++) { diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 60dcec1272f..05cb5417219 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -250,12 +250,13 @@ namespace ServerConfig SERVER_CFG_PREFIX StringServerConfigParam m_only_played_tracks_string SERVER_CFG_DEFAULT(StringServerConfigParam("", "only-played-tracks", "List of tracks that can be played on a server, " - "leave empty for no restriction.")); + "leave empty for no restriction or put 'not' before the list " + "to name tracks that cannot be played.")); SERVER_CFG_PREFIX BoolServerConfigParam m_official_tracks_needed SERVER_CFG_DEFAULT(BoolServerConfigParam(true, "official-tracks-needed", - "If this value is set to true, players and the server must have at least " - "one common official track.")); + "If this value is set to true, players and the server must have " + "at least one common official track.")); SERVER_CFG_PREFIX IntServerConfigParam m_min_start_game_players SERVER_CFG_DEFAULT(IntServerConfigParam(2, "min-start-game-players", From 55da39ca674c364f15876e6dd2bb398c0c613198 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 24 Dec 2019 23:30:51 +0300 Subject: [PATCH 010/830] Trying to support additional /help messages --- NETWORKING.md | 5 ++++- src/network/game_setup.cpp | 21 +-------------------- src/network/protocols/server_lobby.cpp | 11 +++++++++++ src/network/protocols/server_lobby.hpp | 2 ++ src/network/server_config.cpp | 26 +++++++++++++++++++++++++- src/network/server_config.hpp | 11 +++++++++-- 6 files changed, 52 insertions(+), 24 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index e6748e8022a..645ed2502d8 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -57,9 +57,12 @@ The current server configuration xml looks like this (this is only an example, j - + + + + diff --git a/src/network/game_setup.cpp b/src/network/game_setup.cpp index e4bbed74ca7..2a7ddc80336 100644 --- a/src/network/game_setup.cpp +++ b/src/network/game_setup.cpp @@ -40,26 +40,7 @@ //----------------------------------------------------------------------------- GameSetup::GameSetup() { - const std::string& motd = ServerConfig::m_motd; - if (motd.find(".txt") != std::string::npos) - { - const std::string& path = ServerConfig::getConfigDirectory() + "/" + - motd; - std::ifstream message(FileUtils::getPortableReadingPath(path)); - if (message.is_open()) - { - for (std::string line; std::getline(message, line); ) - { - m_message_of_today += StringUtils::utf8ToWide(line).trim() + - L"\n"; - } - // Remove last newline - m_message_of_today.erase(m_message_of_today.size() - 1); - } - } - else if (!motd.empty()) - m_message_of_today = StringUtils::xmlDecode(motd); - + m_message_of_today = ServerConfig::readOrLoadFromFile(ServerConfig::m_motd); const std::string& server_name = ServerConfig::m_server_name; m_server_name_utf8 = StringUtils::wideToUtf8 (StringUtils::xmlDecode(server_name)); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index d904285af0e..f655f93089e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -145,6 +145,8 @@ sqlite3_extension_init(sqlite3* db, char** pzErrMsg, ServerLobby::ServerLobby() : LobbyProtocol() { m_lobby_players.store(0); + m_help_message = ServerConfig::readOrLoadFromFile(ServerConfig::m_help); + std::vector all_k = kart_properties_manager->getKartsInGroup("standard"); std::vector all_t = @@ -5289,6 +5291,15 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; } + else if (argv[0] == "help") + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(m_help_message); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + } else { NetworkString* chat = getNetworkString(); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index af31a80fbab..f69dd639fd5 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -238,6 +238,8 @@ class ServerLobby : public LobbyProtocol std::set m_config_available_tracks; + irr::core::stringw m_help_message; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 29c5b8c19bf..b5f4b45c947 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -415,4 +415,28 @@ std::string getConfigDirectory() } // getConfigDirectory } - +// ---------------------------------------------------------------------------- +irr::core::stringw readOrLoadFromFile(std::string& value) +{ + const std::string& temp = value; + irr::core::stringw answer; + if (temp.find(".txt") != std::string::npos) + { + const std::string& path = ServerConfig::getConfigDirectory() + "/" + + temp; + std::ifstream message(FileUtils::getPortableReadingPath(path)); + if (message.is_open()) + { + for (std::string line; std::getline(message, line); ) + { + answer += StringUtils::utf8ToWide(line).trim() + + L"\n"; + } + // Remove last newline + answer.erase(answer.size() - 1); + } + } + else if (!temp.empty()) + answer = StringUtils::xmlDecode(temp); + return answer; +} diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 05cb5417219..de77420ce94 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -141,8 +141,13 @@ namespace ServerConfig SERVER_CFG_PREFIX StringServerConfigParam m_motd SERVER_CFG_DEFAULT(StringServerConfigParam("", - "motd", "Message of today shown in lobby, you can enter encoded XML " - "words here or a file.txt and let STK load it.")); + "motd", "Message of today shown in lobby, you can enter here " + "encoded XML words or a .txt file and let STK load it.")); + + SERVER_CFG_PREFIX StringServerConfigParam m_help + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "help", "Help message shown after sending /help. You can enter here " + "the message or a .txt file and let STK load it.")); SERVER_CFG_PREFIX BoolServerConfigParam m_chat SERVER_CFG_DEFAULT(BoolServerConfigParam(true, "chat", @@ -491,6 +496,8 @@ namespace ServerConfig void loadServerLobbyFromConfig(); // ------------------------------------------------------------------------ std::string getConfigDirectory(); + // ------------------------------------------------------------------------ + irr::core::stringw readOrLoadFromFile(std::string& value); }; // namespace ServerConfig From 875d88c0dabad4c7557373875ac32297412e1d36 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 25 Dec 2019 00:12:34 +0300 Subject: [PATCH 011/830] Fix bugs, move readOrLoadFromFile to gameSetup --- src/network/game_setup.cpp | 28 +++++++++++++++++++++++++- src/network/game_setup.hpp | 2 ++ src/network/protocols/server_lobby.cpp | 3 ++- src/network/server_config.cpp | 25 ----------------------- src/network/server_config.hpp | 2 -- 5 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/network/game_setup.cpp b/src/network/game_setup.cpp index 2a7ddc80336..31ecedf283a 100644 --- a/src/network/game_setup.cpp +++ b/src/network/game_setup.cpp @@ -40,7 +40,8 @@ //----------------------------------------------------------------------------- GameSetup::GameSetup() { - m_message_of_today = ServerConfig::readOrLoadFromFile(ServerConfig::m_motd); + m_message_of_today = readOrLoadFromFile + ((std::string&) ServerConfig::m_motd); const std::string& server_name = ServerConfig::m_server_name; m_server_name_utf8 = StringUtils::wideToUtf8 (StringUtils::xmlDecode(server_name)); @@ -198,3 +199,28 @@ void GameSetup::setRace(const PeerVote &vote) m_laps = vote.m_num_laps; m_reverse = vote.m_reverse; } // setRace +// ---------------------------------------------------------------------------- +irr::core::stringw readOrLoadFromFile(std::string& value) +{ + const std::string& temp = value; + irr::core::stringw answer; + if (temp.find(".txt") != std::string::npos) + { + const std::string& path = ServerConfig::getConfigDirectory() + "/" + + temp; + std::ifstream message(FileUtils::getPortableReadingPath(path)); + if (message.is_open()) + { + for (std::string line; std::getline(message, line); ) + { + answer += StringUtils::utf8ToWide(line).trim() + + L"\n"; + } + // Remove last newline + answer.erase(answer.size() - 1); + } + } + else if (!temp.empty()) + answer = StringUtils::xmlDecode(temp); + return answer; +} diff --git a/src/network/game_setup.hpp b/src/network/game_setup.hpp index 39e86b887cd..47199111859 100644 --- a/src/network/game_setup.hpp +++ b/src/network/game_setup.hpp @@ -144,6 +144,8 @@ class GameSetup } // ------------------------------------------------------------------------ const std::string& getServerNameUtf8() const { return m_server_name_utf8; } + // ------------------------------------------------------------------------ + irr::core::stringw readOrLoadFromFile(std::string& value); }; #endif // GAME_SETUP_HPP diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index f655f93089e..cf7cd5ade9f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -145,7 +145,8 @@ sqlite3_extension_init(sqlite3* db, char** pzErrMsg, ServerLobby::ServerLobby() : LobbyProtocol() { m_lobby_players.store(0); - m_help_message = ServerConfig::readOrLoadFromFile(ServerConfig::m_help); + m_help_message = GameSetup::readOrLoadFromFile + ((std::string&) ServerConfig::m_help); std::vector all_k = kart_properties_manager->getKartsInGroup("standard"); diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index b5f4b45c947..5fd8f16b2b0 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -415,28 +415,3 @@ std::string getConfigDirectory() } // getConfigDirectory } -// ---------------------------------------------------------------------------- -irr::core::stringw readOrLoadFromFile(std::string& value) -{ - const std::string& temp = value; - irr::core::stringw answer; - if (temp.find(".txt") != std::string::npos) - { - const std::string& path = ServerConfig::getConfigDirectory() + "/" + - temp; - std::ifstream message(FileUtils::getPortableReadingPath(path)); - if (message.is_open()) - { - for (std::string line; std::getline(message, line); ) - { - answer += StringUtils::utf8ToWide(line).trim() + - L"\n"; - } - // Remove last newline - answer.erase(answer.size() - 1); - } - } - else if (!temp.empty()) - answer = StringUtils::xmlDecode(temp); - return answer; -} diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index de77420ce94..e4622214cb1 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -496,8 +496,6 @@ namespace ServerConfig void loadServerLobbyFromConfig(); // ------------------------------------------------------------------------ std::string getConfigDirectory(); - // ------------------------------------------------------------------------ - irr::core::stringw readOrLoadFromFile(std::string& value); }; // namespace ServerConfig From 076f603b297c734a8dfce583b07c24dd7e51b34c Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 25 Dec 2019 00:23:17 +0300 Subject: [PATCH 012/830] Fix bugs --- src/network/game_setup.hpp | 2 +- src/network/protocols/server_lobby.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/game_setup.hpp b/src/network/game_setup.hpp index 47199111859..0e32b2c2e24 100644 --- a/src/network/game_setup.hpp +++ b/src/network/game_setup.hpp @@ -145,7 +145,7 @@ class GameSetup // ------------------------------------------------------------------------ const std::string& getServerNameUtf8() const { return m_server_name_utf8; } // ------------------------------------------------------------------------ - irr::core::stringw readOrLoadFromFile(std::string& value); + static irr::core::stringw readOrLoadFromFile(std::string& value); }; #endif // GAME_SETUP_HPP diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index cf7cd5ade9f..defb3128968 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -145,7 +145,7 @@ sqlite3_extension_init(sqlite3* db, char** pzErrMsg, ServerLobby::ServerLobby() : LobbyProtocol() { m_lobby_players.store(0); - m_help_message = GameSetup::readOrLoadFromFile + m_help_message = getGameSetup()->readOrLoadFromFile ((std::string&) ServerConfig::m_help); std::vector all_k = From 36fb12986256cfd1257f92da87370ed0ace315fe Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 24 Dec 2019 21:53:12 +0000 Subject: [PATCH 013/830] Fixed my weak knowledge of linker --- src/network/game_setup.cpp | 4 ++-- src/network/game_setup.hpp | 2 +- src/network/protocols/server_lobby.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/network/game_setup.cpp b/src/network/game_setup.cpp index 31ecedf283a..9907d197d5f 100644 --- a/src/network/game_setup.cpp +++ b/src/network/game_setup.cpp @@ -41,7 +41,7 @@ GameSetup::GameSetup() { m_message_of_today = readOrLoadFromFile - ((std::string&) ServerConfig::m_motd); + ((std::string) ServerConfig::m_motd); const std::string& server_name = ServerConfig::m_server_name; m_server_name_utf8 = StringUtils::wideToUtf8 (StringUtils::xmlDecode(server_name)); @@ -200,7 +200,7 @@ void GameSetup::setRace(const PeerVote &vote) m_reverse = vote.m_reverse; } // setRace // ---------------------------------------------------------------------------- -irr::core::stringw readOrLoadFromFile(std::string& value) +irr::core::stringw GameSetup::readOrLoadFromFile(std::string value) { const std::string& temp = value; irr::core::stringw answer; diff --git a/src/network/game_setup.hpp b/src/network/game_setup.hpp index 0e32b2c2e24..bc659c7166e 100644 --- a/src/network/game_setup.hpp +++ b/src/network/game_setup.hpp @@ -145,7 +145,7 @@ class GameSetup // ------------------------------------------------------------------------ const std::string& getServerNameUtf8() const { return m_server_name_utf8; } // ------------------------------------------------------------------------ - static irr::core::stringw readOrLoadFromFile(std::string& value); + irr::core::stringw readOrLoadFromFile(std::string value); }; #endif // GAME_SETUP_HPP diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index defb3128968..27faeb87f17 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -146,7 +146,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() { m_lobby_players.store(0); m_help_message = getGameSetup()->readOrLoadFromFile - ((std::string&) ServerConfig::m_help); + ((std::string) ServerConfig::m_help); std::vector all_k = kart_properties_manager->getKartsInGroup("standard"); From bb1ed587daaac453cdc1ff78148fa9e64763ba61 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 25 Dec 2019 14:21:30 +0300 Subject: [PATCH 014/830] Add /commands --- src/network/protocols/server_lobby.cpp | 13 +++++++++++++ src/network/protocols/server_lobby.hpp | 2 ++ 2 files changed, 15 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 27faeb87f17..f034fd898be 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -148,6 +148,10 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_help_message = getGameSetup()->readOrLoadFromFile ((std::string) ServerConfig::m_help); + m_available_commands = "help commands music kick installpack " + "installaddon uninstalladdon liststkaddon listlocaladdon " + "listserveraddon playerhasaddon playeraddonscore serverhasaddon"; + std::vector all_k = kart_properties_manager->getKartsInGroup("standard"); std::vector all_t = @@ -5301,6 +5305,15 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; } + else if (argv[0] == "commands") + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true);chat->encodeString16 + (StringUtils::utf8ToWide(m_available_commands)); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + } else { NetworkString* chat = getNetworkString(); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index f69dd639fd5..91fcd75fcd6 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -240,6 +240,8 @@ class ServerLobby : public LobbyProtocol irr::core::stringw m_help_message; + std::string m_available_commands; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); From e1d1df088f1293f72eb4114630838fdbcb6d1f45 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 25 Dec 2019 11:34:59 +0000 Subject: [PATCH 015/830] Remove unimplemented /installpack from commands list --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index f034fd898be..d2b265625bf 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -148,7 +148,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_help_message = getGameSetup()->readOrLoadFromFile ((std::string) ServerConfig::m_help); - m_available_commands = "help commands music kick installpack " + m_available_commands = "help commands music kick " "installaddon uninstalladdon liststkaddon listlocaladdon " "listserveraddon playerhasaddon playeraddonscore serverhasaddon"; From 68e21856cfec9b0984f15a40251011740cd2a5cb Mon Sep 17 00:00:00 2001 From: Benau Date: Sat, 4 Jan 2020 02:47:06 +0800 Subject: [PATCH 016/830] Create final 1.1 branch --- CMakeLists.txt | 2 +- data/{supertuxkart.git => supertuxkart.1.1} | 0 tools/windows_installer/supertuxkart-64bit-mingw.nsi | 6 +++--- tools/windows_installer/supertuxkart-mingw.nsi | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) rename data/{supertuxkart.git => supertuxkart.1.1} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 87c171ca7e1..597ce38b2d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8.4) # root CMakeLists for the SuperTuxKart project project(SuperTuxKart) -set(PROJECT_VERSION "git") +set(PROJECT_VERSION "1.1") add_definitions( -DSUPERTUXKART_VERSION="${PROJECT_VERSION}" ) if(NOT (CMAKE_MAJOR_VERSION VERSION_LESS 3)) diff --git a/data/supertuxkart.git b/data/supertuxkart.1.1 similarity index 100% rename from data/supertuxkart.git rename to data/supertuxkart.1.1 diff --git a/tools/windows_installer/supertuxkart-64bit-mingw.nsi b/tools/windows_installer/supertuxkart-64bit-mingw.nsi index 669919f7e62..1569baa0110 100644 --- a/tools/windows_installer/supertuxkart-64bit-mingw.nsi +++ b/tools/windows_installer/supertuxkart-64bit-mingw.nsi @@ -29,11 +29,11 @@ ; Version information ; TOOD get these from the source code directly - !define VERSION_MAJOR 0 - !define VERSION_MINOR 10 + !define VERSION_MAJOR 1 + !define VERSION_MINOR 1 !define VERSION_REVISION 0 ; Empty means stable, could be -git, -rc1 - !define VERSION_BUILD "-git" + !define VERSION_BUILD "" ;Name and file !define APPNAME "SuperTuxKart" diff --git a/tools/windows_installer/supertuxkart-mingw.nsi b/tools/windows_installer/supertuxkart-mingw.nsi index 92fa69b562d..093d527b8ce 100644 --- a/tools/windows_installer/supertuxkart-mingw.nsi +++ b/tools/windows_installer/supertuxkart-mingw.nsi @@ -29,11 +29,11 @@ ; Version information ; TOOD get these from the source code directly - !define VERSION_MAJOR 0 - !define VERSION_MINOR 10 + !define VERSION_MAJOR 1 + !define VERSION_MINOR 1 !define VERSION_REVISION 0 ; Empty means stable, could be -git, -rc1 - !define VERSION_BUILD "-git" + !define VERSION_BUILD "" ;Name and file !define APPNAME "SuperTuxKart" From 6f0f029ea4da6a9898e9290498ac12e946bc9edd Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 11 Jan 2020 17:06:27 +0300 Subject: [PATCH 017/830] Added sleeping server possibility and verbose output for the reason player cannot enter --- NETWORKING.md | 3 +++ src/network/protocols/server_lobby.cpp | 24 ++++++++++++++++++++++++ src/network/server_config.hpp | 5 +++++ 3 files changed, 32 insertions(+) diff --git a/NETWORKING.md b/NETWORKING.md index 645ed2502d8..0d589ccaf15 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -210,6 +210,9 @@ The current server configuration xml looks like this (this is only an example, j + + + ``` diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index baa4e7bdb9e..b0272ebc832 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2272,6 +2272,11 @@ void ServerLobby::startSelection(const Event *event) m_state.load()); return; } + if (ServerConfig::m_sleeping_server) { + Log::info("ServerLobby", + "An attempt to start a race on a sleeping server. Lol."); + return; + } if (ServerConfig::m_owner_less) { m_peers_ready.at(event->getPeerSP()) = @@ -3130,6 +3135,25 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) const peer->addon_arenas_count = addon_arenas; peer->addon_soccers_count = addon_soccers; + if (karts_erase.size() == m_available_kts.first.size()) + Log::verbose("ServerLobby", "Bad player: no common karts with server"); + if (tracks_erase.size() == m_available_kts.second.size()) + Log::verbose("ServerLobby", "Bad player: no common tracks with server"); + if (okt < ServerConfig::m_official_karts_threshold) + Log::verbose("ServerLobby", "Bad player: bad official kart threshold"); + if (ott < ServerConfig::m_official_tracks_threshold) + Log::verbose("ServerLobby", "Bad player: bad official track threshold"); + if (addon_karts < (int)ServerConfig::m_addon_karts_threshold) + Log::verbose("ServerLobby", "Bad player: too little addon karts"); + if (addon_tracks < (int)ServerConfig::m_addon_tracks_threshold) + Log::verbose("ServerLobby", "Bad player: too little addon tracks"); + if (addon_arenas < (int)ServerConfig::m_addon_arenas_threshold) + Log::verbose("ServerLobby", "Bad player: too little addon arenas"); + if (addon_soccers < (int)ServerConfig::m_addon_soccers_threshold) + Log::verbose("ServerLobby", "Bad player: too little addon soccers"); + if (!has_required_tracks) + Log::verbose("ServerLobby", "Bad player: no required tracks"); + if (karts_erase.size() == m_available_kts.first.size() || tracks_erase.size() == m_available_kts.second.size() || okt < ServerConfig::m_official_karts_threshold || diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index e4622214cb1..4a154e19e03 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -463,6 +463,11 @@ namespace ServerConfig "network-ai=x, which will kick N - 1 bot(s) where N is the number " "of human players. Only use this for non-GP racing server.")); + SERVER_CFG_PREFIX BoolServerConfigParam m_sleeping_server + SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "sleeping-server", + "If true no one can start a race and everyone should use the " + "server for sleeping/chatting only.")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; From f209a47b6ead59fbeacf05af35998f08e63624ef Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 11 Jan 2020 17:33:30 +0300 Subject: [PATCH 018/830] Fix m_min_start_game_players for sleeping server --- src/network/server_config.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 5fd8f16b2b0..20b5302d683 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -358,10 +358,17 @@ void loadServerLobbyFromConfig() m_owner_less = true; m_strict_players = true; } + if (m_sleeping_server) { + m_owner_less = true; + } if (m_owner_less) { - if (m_min_start_game_players > m_server_max_players) - m_min_start_game_players = 1; + if (m_sleeping_server) { + m_min_start_game_players = 123456; + } else { + if (m_min_start_game_players > m_server_max_players) + m_min_start_game_players = 1; + } if (!m_live_players) m_team_choosing = false; m_server_configurable = false; From b3ea43feb925e04f6bead32b957816d921265006 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 11 Jan 2020 17:35:10 +0300 Subject: [PATCH 019/830] Fix m_official_karts_threshold for sleeping server --- src/network/server_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 20b5302d683..c4b205d6ec0 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -328,7 +328,7 @@ void loadServerLobbyFromConfig() if (m_official_tracks_threshold > 1.0f) m_official_tracks_threshold = 1.0f; - if (m_live_players) + if (m_live_players && !m_sleeping_server) m_official_karts_threshold = 1.0f; if (m_high_ping_workaround) m_kick_high_ping_players = false; From 27c81be10f27d8f907f384180b92e6559bd7f57a Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 20 Jan 2020 17:05:22 +0300 Subject: [PATCH 020/830] Added useless gnu elimination commands --- src/network/protocols/server_lobby.cpp | 60 ++++++++++++++++++++++++++ src/network/protocols/server_lobby.hpp | 2 + 2 files changed, 62 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3b933a2f9d8..d1bd2fcf221 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -174,6 +174,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() "installaddon uninstalladdon liststkaddon listlocaladdon " "listserveraddon playerhasaddon playeraddonscore serverhasaddon"; + m_gnu_elimination = false; + std::vector all_k = kart_properties_manager->getKartsInGroup("standard"); std::vector all_t = @@ -5447,6 +5449,64 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; } + else if (argv[0] == "gnu") + { + if (m_server_owner.lock() != peer) + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(L"You are not server owner"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + return; + } else if (m_gnu_elimination) { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->encodeString16( + L"Gnu Elimination mode was already enabled!"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + } else if (false/* one player */) { + + } else { + NetworkString* chat = getNetworkString(); + m_gnu_elimination = true; + chat->addUInt8(LE_CHAT); + chat->encodeString16( + L"Gnu Elimination starts"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + } + } + else if (argv[0] == "nognu") + { + if (m_server_owner.lock() != peer) + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(L"You are not server owner"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + return; + } else if (!m_gnu_elimination) { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->encodeString16( + L"Gnu Elimination mode was already off!"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + } else { + NetworkString* chat = getNetworkString(); + m_gnu_elimination = false; + chat->addUInt8(LE_CHAT); + chat->encodeString16( + L"Gnu Elimination is off"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + } + } else { NetworkString* chat = getNetworkString(); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index f6fef802cb2..8abad56b572 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -246,6 +246,8 @@ class ServerLobby : public LobbyProtocol std::string m_available_commands; + bool m_gnu_elimination; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); From 8a39bf752479a303242a8e195e02339530dc1201 Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 20 Jan 2020 17:43:59 +0300 Subject: [PATCH 021/830] Make handleServerCommand non-const (how to make it const back?) for elimination --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index d1bd2fcf221..04a8edbcb41 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -5179,7 +5179,7 @@ bool ServerLobby::checkPeersReady(bool ignore_ai_peer) const //----------------------------------------------------------------------------- void ServerLobby::handleServerCommand(Event* event, - std::shared_ptr peer) const + std::shared_ptr peer) /*const*/ { NetworkString& data = event->data(); std::string language; From d1862fe0aa61eff001b02cab3f526a76136c9890 Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 20 Jan 2020 17:53:46 +0300 Subject: [PATCH 022/830] Make m_gnu_elimination a pointer --- src/network/protocols/server_lobby.cpp | 14 ++++++++------ src/network/protocols/server_lobby.hpp | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 04a8edbcb41..eb0eb7ff9d5 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -174,7 +174,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() "installaddon uninstalladdon liststkaddon listlocaladdon " "listserveraddon playerhasaddon playeraddonscore serverhasaddon"; - m_gnu_elimination = false; + m_gnu_elimination = new bool[1]; + *m_gnu_elimination = false; std::vector all_k = kart_properties_manager->getKartsInGroup("standard"); @@ -284,6 +285,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() */ ServerLobby::~ServerLobby() { + delete [] m_gnu_elimination; if (NetworkConfig::get()->isNetworking() && NetworkConfig::get()->isWAN()) { @@ -5179,7 +5181,7 @@ bool ServerLobby::checkPeersReady(bool ignore_ai_peer) const //----------------------------------------------------------------------------- void ServerLobby::handleServerCommand(Event* event, - std::shared_ptr peer) /*const*/ + std::shared_ptr peer) const { NetworkString& data = event->data(); std::string language; @@ -5460,7 +5462,7 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; return; - } else if (m_gnu_elimination) { + } else if (*m_gnu_elimination) { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->encodeString16( @@ -5471,7 +5473,7 @@ void ServerLobby::handleServerCommand(Event* event, } else { NetworkString* chat = getNetworkString(); - m_gnu_elimination = true; + *m_gnu_elimination = true; chat->addUInt8(LE_CHAT); chat->encodeString16( L"Gnu Elimination starts"); @@ -5490,7 +5492,7 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; return; - } else if (!m_gnu_elimination) { + } else if (!*m_gnu_elimination) { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->encodeString16( @@ -5499,7 +5501,7 @@ void ServerLobby::handleServerCommand(Event* event, delete chat; } else { NetworkString* chat = getNetworkString(); - m_gnu_elimination = false; + *m_gnu_elimination = false; chat->addUInt8(LE_CHAT); chat->encodeString16( L"Gnu Elimination is off"); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 8abad56b572..29aaf4a4e7c 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -246,7 +246,7 @@ class ServerLobby : public LobbyProtocol std::string m_available_commands; - bool m_gnu_elimination; + bool* m_gnu_elimination; // connection management void clientDisconnected(Event* event); From 1fdc916272f3d23b573cd7a217571a597efb8a93 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 25 Jan 2020 00:28:04 +0300 Subject: [PATCH 023/830] Added chat commands for restricted messaging --- src/network/protocols/server_lobby.cpp | 48 ++++++++++++++++++++++++-- src/network/protocols/server_lobby.hpp | 4 ++- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index eb0eb7ff9d5..7571c485ac2 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -809,9 +809,14 @@ void ServerLobby::handleChat(Event* event) chat->setSynchronous(true); chat->addUInt8(LE_CHAT).encodeString16(message); const bool game_started = m_state.load() != WAITING_FOR_START_GAME; + STKPeer* sender = event->getPeer(); + auto can_receive = m_message_receivers[sender]; STKHost::get()->sendPacketToAllPeersWith( - [game_started, sender_in_game](STKPeer* p) + [game_started, sender_in_game, can_receive, sender](STKPeer* p) { + if (sender == p) { + return true; + } if (game_started) { if (p->isWaitingForGame() && !sender_in_game) @@ -819,7 +824,17 @@ void ServerLobby::handleChat(Event* event) if (!p->isWaitingForGame() && sender_in_game) return false; } - return true; + if (can_receive.empty()) { + return true; + } + for (auto& profile : p->getPlayerProfiles()) + { + if (can_receive.find(profile->getName()) != can_receive.end()) + { + return true; + } + } + return false; }, chat); event->getPeer()->updateLastMessage(); delete chat; @@ -5181,7 +5196,7 @@ bool ServerLobby::checkPeersReady(bool ignore_ai_peer) const //----------------------------------------------------------------------------- void ServerLobby::handleServerCommand(Event* event, - std::shared_ptr peer) const + std::shared_ptr peer) //const { NetworkString& data = event->data(); std::string language; @@ -5465,6 +5480,7 @@ void ServerLobby::handleServerCommand(Event* event, } else if (*m_gnu_elimination) { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); chat->encodeString16( L"Gnu Elimination mode was already enabled!"); peer->sendPacket(chat, true/*reliable*/); @@ -5475,6 +5491,7 @@ void ServerLobby::handleServerCommand(Event* event, NetworkString* chat = getNetworkString(); *m_gnu_elimination = true; chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); chat->encodeString16( L"Gnu Elimination starts"); peer->sendPacket(chat, true/*reliable*/); @@ -5495,6 +5512,7 @@ void ServerLobby::handleServerCommand(Event* event, } else if (!*m_gnu_elimination) { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); chat->encodeString16( L"Gnu Elimination mode was already off!"); peer->sendPacket(chat, true/*reliable*/); @@ -5503,12 +5521,36 @@ void ServerLobby::handleServerCommand(Event* event, NetworkString* chat = getNetworkString(); *m_gnu_elimination = false; chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); chat->encodeString16( L"Gnu Elimination is off"); peer->sendPacket(chat, true/*reliable*/); delete chat; } } + else if (argv[0] == "to") + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + m_message_receivers[peer.get()].clear(); + for (int i = 1; i < argv.size(); ++i) { + m_message_receivers[peer.get()].insert( + StringUtils::utf8ToWide(argv[i])); + } + peer->sendPacket(chat, true/*reliable*/); + delete chat; +// m_message_receivers + } + else if (argv[0] == "public") + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + m_message_receivers[peer.get()].clear(); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + } else { NetworkString* chat = getNetworkString(); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 29aaf4a4e7c..b48c016bc4c 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -246,6 +246,8 @@ class ServerLobby : public LobbyProtocol std::string m_available_commands; + std::map> m_message_receivers; + bool* m_gnu_elimination; // connection management @@ -349,7 +351,7 @@ class ServerLobby : public LobbyProtocol std::vector > getLivePlayers() const; void setPlayerKarts(const NetworkString& ns, STKPeer* peer) const; bool handleAssets(const NetworkString& ns, STKPeer* peer) const; - void handleServerCommand(Event* event, std::shared_ptr peer) const; + void handleServerCommand(Event* event, std::shared_ptr peer) /*const*/; void liveJoinRequest(Event* event); void rejectLiveJoin(STKPeer* peer, BackLobbyReason blr); bool canLiveJoinNow() const; From 5367bd0bd355f064ad48929d9d196afaa25ffe16 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 25 Jan 2020 03:41:21 +0300 Subject: [PATCH 024/830] Forbid /to with no parameters --- src/network/protocols/server_lobby.cpp | 28 +++++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 7571c485ac2..8054a3b1933 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -5530,17 +5530,25 @@ void ServerLobby::handleServerCommand(Event* event, } else if (argv[0] == "to") { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - m_message_receivers[peer.get()].clear(); - for (int i = 1; i < argv.size(); ++i) { - m_message_receivers[peer.get()].insert( - StringUtils::utf8ToWide(argv[i])); + if (argv.size() == 1) { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(L"Usage: /to (username1) ... (usernameN)"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + } else { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + m_message_receivers[peer.get()].clear(); + for (int i = 1; i < argv.size(); ++i) { + m_message_receivers[peer.get()].insert( + StringUtils::utf8ToWide(argv[i])); + } + peer->sendPacket(chat, true/*reliable*/); + delete chat; } - peer->sendPacket(chat, true/*reliable*/); - delete chat; -// m_message_receivers } else if (argv[0] == "public") { From 049344ed319a173263b4b8e8a6a6cc4d702dd417 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 25 Jan 2020 03:45:02 +0300 Subject: [PATCH 025/830] Added responses to /to and /public --- src/network/protocols/server_lobby.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 8054a3b1933..fb4e78a3195 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -5546,6 +5546,7 @@ void ServerLobby::handleServerCommand(Event* event, m_message_receivers[peer.get()].insert( StringUtils::utf8ToWide(argv[i])); } + chat->encodeString16(L"Successfully changed chat settings"); peer->sendPacket(chat, true/*reliable*/); delete chat; } @@ -5556,6 +5557,7 @@ void ServerLobby::handleServerCommand(Event* event, chat->addUInt8(LE_CHAT); chat->setSynchronous(true); m_message_receivers[peer.get()].clear(); + chat->encodeString16(L"Your messages are now public"); peer->sendPacket(chat, true/*reliable*/); delete chat; } From d2e6a215033522cfd4460bfe00d1b13a3fcbd2a7 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 25 Jan 2020 03:45:51 +0300 Subject: [PATCH 026/830] Fixed available commands --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index fb4e78a3195..8e234beac65 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -170,7 +170,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_help_message = getGameSetup()->readOrLoadFromFile ((std::string) ServerConfig::m_help); - m_available_commands = "help commands music kick " + m_available_commands = "help commands music kick to public " "installaddon uninstalladdon liststkaddon listlocaladdon " "listserveraddon playerhasaddon playeraddonscore serverhasaddon"; From e3bac07e9e92e818872347d89038da7b12555c3a Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 11 Feb 2020 19:30:14 +0300 Subject: [PATCH 027/830] Add false-ip to be able to use floating IP --- NETWORKING.md | 3 +++ src/network/protocols/server_lobby.cpp | 7 +++++-- src/network/server_config.hpp | 9 +++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index 8ce27f4f390..9151b479d9c 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -216,6 +216,9 @@ The current server configuration xml looks like this (this is only an example, j + + + ``` diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index da3ee9ecba3..faf60f6d43f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2313,8 +2313,11 @@ bool ServerLobby::registerServer(bool now) std::dynamic_pointer_cast(shared_from_this())); NetworkConfig::get()->setServerDetails(request, "create"); const SocketAddress& addr = STKHost::get()->getPublicAddress(); - request->addParameter("address", addr.getIP() ); - request->addParameter("port", addr.getPort() ); + if (ServerConfig::m_false_ip == 0) + request->addParameter("address", addr.getIP() ); + else + request->addParameter("address", ServerConfig::m_false_ip); + request->addParameter("port", addr.getPort() ); request->addParameter("private_port", STKHost::get()->getPrivatePort() ); request->addParameter("name", m_game_setup->getServerNameUtf8()); diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index cd42b25cb11..e387dc72039 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -478,6 +478,15 @@ namespace ServerConfig "If true no one can start a race and everyone should use the " "server for sleeping/chatting only.")); + SERVER_CFG_PREFIX IntServerConfigParam m_false_ip + SERVER_CFG_DEFAULT(IntServerConfigParam(0, "false-ip", + "IP that should be used to connect to a server, set 0 for a " + "default IP. You need this only if the server's IP shouldn't be " + "used for some reason (e.g. blocking) and there is another IP " + "('good') that points to the same server. In this case, you " + "should write a good IP here as a number. Only IPv4 is " + "supported.")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; From 24f6b676fec70cc5e0bda59ba89ca74417d40560 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 11 Feb 2020 20:37:56 +0300 Subject: [PATCH 028/830] Add more false ip --- src/network/protocols/server_lobby.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index faf60f6d43f..cec9104c053 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2308,7 +2308,7 @@ bool ServerLobby::registerServer(bool now) RegisterServerRequest(bool now, std::shared_ptr sl) : XMLRequest(), m_server_lobby(sl), m_execute_now(now) {} }; // RegisterServerRequest - +Online::XMLRequest auto request = std::make_shared(now, std::dynamic_pointer_cast(shared_from_this())); NetworkConfig::get()->setServerDetails(request, "create"); @@ -2369,7 +2369,10 @@ void ServerLobby::unregisterServer(bool now) NetworkConfig::get()->setServerDetails(request, "stop"); const SocketAddress& addr = STKHost::get()->getPublicAddress(); - request->addParameter("address", addr.getIP()); + if (ServerConfig::m_false_ip == 0) + request->addParameter("address", addr.getIP() ); + else + request->addParameter("address", ServerConfig::m_false_ip); request->addParameter("port", addr.getPort()); bool ipv6_only = addr.isUnset(); if (!ipv6_only) @@ -2750,7 +2753,10 @@ void ServerLobby::checkIncomingConnectionRequests() NetworkConfig::get()->setServerDetails(request, "poll-connection-requests"); const SocketAddress& addr = STKHost::get()->getPublicAddress(); - request->addParameter("address", addr.getIP() ); + if (ServerConfig::m_false_ip == 0) + request->addParameter("address", addr.getIP() ); + else + request->addParameter("address", ServerConfig::m_false_ip); request->addParameter("port", addr.getPort()); request->addParameter("current-players", getLobbyPlayers()); request->addParameter("game-started", @@ -4941,7 +4947,10 @@ void ServerLobby::handleServerConfiguration(Event* event) auto request = std::make_shared(); NetworkConfig::get()->setServerDetails(request, "update-config"); const SocketAddress& addr = STKHost::get()->getPublicAddress(); - request->addParameter("address", addr.getIP()); + if (ServerConfig::m_false_ip == 0) + request->addParameter("address", addr.getIP() ); + else + request->addParameter("address", ServerConfig::m_false_ip); request->addParameter("port", addr.getPort()); request->addParameter("new-difficulty", new_difficulty); request->addParameter("new-game-mode", new_game_mode); From d18897278c41f0a335e111e0846009a9f317affa Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 11 Feb 2020 20:41:50 +0300 Subject: [PATCH 029/830] Fix typo --- src/network/protocols/server_lobby.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index cec9104c053..128f2871d15 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2308,7 +2308,6 @@ bool ServerLobby::registerServer(bool now) RegisterServerRequest(bool now, std::shared_ptr sl) : XMLRequest(), m_server_lobby(sl), m_execute_now(now) {} }; // RegisterServerRequest -Online::XMLRequest auto request = std::make_shared(now, std::dynamic_pointer_cast(shared_from_this())); NetworkConfig::get()->setServerDetails(request, "create"); From 26746b0cd969a80636d868fa288f5caa22a61216 Mon Sep 17 00:00:00 2001 From: kimden Date: Thu, 13 Feb 2020 18:50:13 +0300 Subject: [PATCH 030/830] Added gnu elimintation except of kart choice and results --- src/network/protocols/server_lobby.cpp | 118 ++++++++++++++++++++----- src/network/protocols/server_lobby.hpp | 5 +- 2 files changed, 98 insertions(+), 25 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 128f2871d15..6ba469d22ee 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -177,8 +177,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() "installaddon uninstalladdon liststkaddon listlocaladdon " "listserveraddon playerhasaddon playeraddonscore serverhasaddon"; - m_gnu_elimination = new bool[1]; - *m_gnu_elimination = false; + m_gnu_elimination = false; + m_gnu_remained = 0; std::vector all_k = kart_properties_manager->getKartsInGroup("standard"); @@ -288,7 +288,6 @@ ServerLobby::ServerLobby() : LobbyProtocol() */ ServerLobby::~ServerLobby() { - delete [] m_gnu_elimination; if (NetworkConfig::get()->isNetworking() && NetworkConfig::get()->isWAN()) { @@ -2308,15 +2307,13 @@ bool ServerLobby::registerServer(bool now) RegisterServerRequest(bool now, std::shared_ptr sl) : XMLRequest(), m_server_lobby(sl), m_execute_now(now) {} }; // RegisterServerRequest + auto request = std::make_shared(now, std::dynamic_pointer_cast(shared_from_this())); NetworkConfig::get()->setServerDetails(request, "create"); const SocketAddress& addr = STKHost::get()->getPublicAddress(); - if (ServerConfig::m_false_ip == 0) - request->addParameter("address", addr.getIP() ); - else - request->addParameter("address", ServerConfig::m_false_ip); - request->addParameter("port", addr.getPort() ); + request->addParameter("address", addr.getIP() ); + request->addParameter("port", addr.getPort() ); request->addParameter("private_port", STKHost::get()->getPrivatePort() ); request->addParameter("name", m_game_setup->getServerNameUtf8()); @@ -2368,10 +2365,7 @@ void ServerLobby::unregisterServer(bool now) NetworkConfig::get()->setServerDetails(request, "stop"); const SocketAddress& addr = STKHost::get()->getPublicAddress(); - if (ServerConfig::m_false_ip == 0) - request->addParameter("address", addr.getIP() ); - else - request->addParameter("address", ServerConfig::m_false_ip); + request->addParameter("address", addr.getIP()); request->addParameter("port", addr.getPort()); bool ipv6_only = addr.isUnset(); if (!ipv6_only) @@ -2752,10 +2746,7 @@ void ServerLobby::checkIncomingConnectionRequests() NetworkConfig::get()->setServerDetails(request, "poll-connection-requests"); const SocketAddress& addr = STKHost::get()->getPublicAddress(); - if (ServerConfig::m_false_ip == 0) - request->addParameter("address", addr.getIP() ); - else - request->addParameter("address", ServerConfig::m_false_ip); + request->addParameter("address", addr.getIP() ); request->addParameter("port", addr.getPort()); request->addParameter("current-players", getLobbyPlayers()); request->addParameter("game-started", @@ -2838,6 +2829,10 @@ void ServerLobby::checkRaceFinished() ranking_changes_indication = 1; m_result_ns->addUInt8(ranking_changes_indication); + if (m_gnu_elimination) { + updateGnuElimination(); + } + if (ServerConfig::m_ranked) { computeNewRankings(); @@ -4946,10 +4941,7 @@ void ServerLobby::handleServerConfiguration(Event* event) auto request = std::make_shared(); NetworkConfig::get()->setServerDetails(request, "update-config"); const SocketAddress& addr = STKHost::get()->getPublicAddress(); - if (ServerConfig::m_false_ip == 0) - request->addParameter("address", addr.getIP() ); - else - request->addParameter("address", ServerConfig::m_false_ip); + request->addParameter("address", addr.getIP()); request->addParameter("port", addr.getPort()); request->addParameter("new-difficulty", new_difficulty); request->addParameter("new-game-mode", new_game_mode); @@ -5595,7 +5587,7 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; return; - } else if (*m_gnu_elimination) { + } else if (m_gnu_elimination) { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); @@ -5607,7 +5599,9 @@ void ServerLobby::handleServerCommand(Event* event, } else { NetworkString* chat = getNetworkString(); - *m_gnu_elimination = true; + m_gnu_elimination = true; + m_gnu_remained = -1; + m_gnu_participants.clear(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); chat->encodeString16( @@ -5627,7 +5621,7 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; return; - } else if (!*m_gnu_elimination) { + } else if (!m_gnu_elimination) { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); @@ -5637,7 +5631,9 @@ void ServerLobby::handleServerCommand(Event* event, delete chat; } else { NetworkString* chat = getNetworkString(); - *m_gnu_elimination = false; + m_gnu_elimination = false; + m_gnu_remained = 0; + m_gnu_participants.clear(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); chat->encodeString16( @@ -5646,6 +5642,18 @@ void ServerLobby::handleServerCommand(Event* event, delete chat; } } + else if (argv[0] == "standings") + { + Log::info("GnuElimination", "total %d participants", (int)m_gnu_participants.size()); + for (int i = 0; i < (int)m_gnu_participants.size(); i++) + { + std::string line = (i < m_gnu_remained ? + std::to_string(i + 1) : "[" + std::to_string(i + 1) + "]"); + line.push_back("\t"); + line += std::string(m_gnu_participants[i]); + Log::info("GnuElimination", line.c_str()); + } + } else if (argv[0] == "to") { if (argv.size() == 1) { @@ -5691,3 +5699,65 @@ void ServerLobby::handleServerCommand(Event* event, delete chat; } } // handleServerCommand +//----------------------------------------------------------------------------- +void ServerLobby::updateGnuElimination() +{ + + for (int i = 0; i < player_count; i++) + { + irr:core::stringw username = race_manager->getKartInfo(i).getPlayerName(); + double time = race_manager->getKartRaceTime(i); + } + World* w = World::getWorld(); + assert(w); + assert(m_gnu_remained != 0); + int player_count = race_manager->getNumPlayers(); + const double INF = 1e9; + std::vector> order; + if (m_gnu_remained < 0) + { + for (int i = 0; i < player_count; i++) + { + irr:core::stringw username = race_manager->getKartInfo(i).getPlayerName(); + double elapsed_time = (w->getKart(i)->isEliminated(i) ? INF : + race_manager->getKartRaceTime(i)); + order.emplace_back(elapsed_time, username); + } + m_gnu_remained = player_count; + } + else + { + for (int i = 0; i < m_gnu_participants.size(); i++) + { + order.emplace_back(INF, m_gnu_participants[i]); + } + // the number of players is very small and I don't want maps + for (int i = 0; i < player_count; i++) + { + irr:core::stringw username = race_manager->getKartInfo(i).getPlayerName(); + double elapsed_time = (w->getKart(i)->isEliminated(i) ? INF : + race_manager->getKartRaceTime(i)); + for (int j = 0; j < m_gnu_remained; j++) + { + if (m_gnu_participants[j] == username) + { + order[j].first = elapsed_time; + break; + } + } + } + } + std::stable_sort(order.begin(), order.begin() + m_gnu_remained); + bool all_quit = false;//order[0].first == INF; + for (int i = 0; i < m_gnu_remained; i++) + m_gnu_participants[i] = order[i].second; + --m_gnu_remained; + if (!all_quit) + { + while (m_gnu_remained - 1 >= 0 && order[m_gnu_remained - 1].first == INF) + --m_gnu_remained; + } + if (m_gnu_remained == 0) { + m_gnu_elimination = false; + } +} \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 353076e1962..40ea1a2bfef 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -252,7 +252,9 @@ class ServerLobby : public LobbyProtocol std::map> m_message_receivers; - bool* m_gnu_elimination; + bool m_gnu_elimination; + int m_gnu_remained; + std::vector m_gnu_participants; // connection management void clientDisconnected(Event* event); @@ -372,6 +374,7 @@ class ServerLobby : public LobbyProtocol void writeDisconnectInfoTable(STKPeer* peer); void writePlayerReport(Event* event); bool supportsAI(); + void updateGnuElimination(); public: ServerLobby(); virtual ~ServerLobby(); From 2aa2aec90155dd4e3042e0bd715eda4ec551d284 Mon Sep 17 00:00:00 2001 From: kimden Date: Thu, 13 Feb 2020 19:11:54 +0300 Subject: [PATCH 031/830] Fixed CE bugs --- src/network/protocols/server_lobby.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 6ba469d22ee..d02523edb2b 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -5649,9 +5649,9 @@ void ServerLobby::handleServerCommand(Event* event, { std::string line = (i < m_gnu_remained ? std::to_string(i + 1) : "[" + std::to_string(i + 1) + "]"); - line.push_back("\t"); - line += std::string(m_gnu_participants[i]); - Log::info("GnuElimination", line.c_str()); + line.push_back('\t'); + line += "%s"; + Log::info("GnuElimination", line.c_str(), m_gnu_participants[i]); } } else if (argv[0] == "to") @@ -5702,12 +5702,6 @@ void ServerLobby::handleServerCommand(Event* event, //----------------------------------------------------------------------------- void ServerLobby::updateGnuElimination() { - - for (int i = 0; i < player_count; i++) - { - irr:core::stringw username = race_manager->getKartInfo(i).getPlayerName(); - double time = race_manager->getKartRaceTime(i); - } World* w = World::getWorld(); assert(w); assert(m_gnu_remained != 0); @@ -5718,8 +5712,8 @@ void ServerLobby::updateGnuElimination() { for (int i = 0; i < player_count; i++) { - irr:core::stringw username = race_manager->getKartInfo(i).getPlayerName(); - double elapsed_time = (w->getKart(i)->isEliminated(i) ? INF : + irr::core::stringw username = race_manager->getKartInfo(i).getPlayerName(); + double elapsed_time = (w->getKart(i)->isEliminated() ? INF : race_manager->getKartRaceTime(i)); order.emplace_back(elapsed_time, username); } @@ -5734,8 +5728,8 @@ void ServerLobby::updateGnuElimination() // the number of players is very small and I don't want maps for (int i = 0; i < player_count; i++) { - irr:core::stringw username = race_manager->getKartInfo(i).getPlayerName(); - double elapsed_time = (w->getKart(i)->isEliminated(i) ? INF : + irr::core::stringw username = race_manager->getKartInfo(i).getPlayerName(); + double elapsed_time = (w->getKart(i)->isEliminated() ? INF : race_manager->getKartRaceTime(i)); for (int j = 0; j < m_gnu_remained; j++) { From 8cfa6fb4f47b59b5a361311ddb3385c3aba1b8a5 Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 16 Feb 2020 19:32:27 +0300 Subject: [PATCH 032/830] Fixed bugs --- src/network/protocols/server_lobby.cpp | 23 +++++++++++++++-------- src/network/protocols/server_lobby.hpp | 2 +- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index d02523edb2b..ed900016243 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -5645,14 +5645,20 @@ void ServerLobby::handleServerCommand(Event* event, else if (argv[0] == "standings") { Log::info("GnuElimination", "total %d participants", (int)m_gnu_participants.size()); + std::string result = "Gnu Elimination standings:"; for (int i = 0; i < (int)m_gnu_participants.size(); i++) { - std::string line = (i < m_gnu_remained ? + std::string line = "\n" + (i < m_gnu_remained ? std::to_string(i + 1) : "[" + std::to_string(i + 1) + "]"); - line.push_back('\t'); - line += "%s"; - Log::info("GnuElimination", line.c_str(), m_gnu_participants[i]); + line += ". " + m_gnu_participants[i]; + result += line; } + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(StringUtils::utf8ToWide(result)); + peer->sendPacket(chat, true/*reliable*/); + delete chat; } else if (argv[0] == "to") { @@ -5707,15 +5713,16 @@ void ServerLobby::updateGnuElimination() assert(m_gnu_remained != 0); int player_count = race_manager->getNumPlayers(); const double INF = 1e9; - std::vector> order; + std::vector> order; if (m_gnu_remained < 0) { for (int i = 0; i < player_count; i++) { - irr::core::stringw username = race_manager->getKartInfo(i).getPlayerName(); + std::string username = StringUtils::wideToUtf8(race_manager->getKartInfo(i).getPlayerName()); double elapsed_time = (w->getKart(i)->isEliminated() ? INF : race_manager->getKartRaceTime(i)); order.emplace_back(elapsed_time, username); + m_gnu_participants.push_back(username); } m_gnu_remained = player_count; } @@ -5728,7 +5735,7 @@ void ServerLobby::updateGnuElimination() // the number of players is very small and I don't want maps for (int i = 0; i < player_count; i++) { - irr::core::stringw username = race_manager->getKartInfo(i).getPlayerName(); + std::string username = StringUtils::wideToUtf8(race_manager->getKartInfo(i).getPlayerName()); double elapsed_time = (w->getKart(i)->isEliminated() ? INF : race_manager->getKartRaceTime(i)); for (int j = 0; j < m_gnu_remained; j++) @@ -5751,7 +5758,7 @@ void ServerLobby::updateGnuElimination() while (m_gnu_remained - 1 >= 0 && order[m_gnu_remained - 1].first == INF) --m_gnu_remained; } - if (m_gnu_remained == 0) { + if (m_gnu_remained <= 1) { m_gnu_elimination = false; } } \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 40ea1a2bfef..b9fb032110e 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -254,7 +254,7 @@ class ServerLobby : public LobbyProtocol bool m_gnu_elimination; int m_gnu_remained; - std::vector m_gnu_participants; + std::vector m_gnu_participants; // connection management void clientDisconnected(Event* event); From 0c5ccaa4ea018bacb81c81840cfecb387b3f78d4 Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 17 Feb 2020 00:50:18 +0300 Subject: [PATCH 033/830] Initial working version of gnu elimination --- src/network/protocols/server_lobby.cpp | 73 ++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index ed900016243..d797f8cde24 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -247,7 +247,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() { std::vector available_tracks = StringUtils::split(ServerConfig::m_only_played_tracks_string, ' ', false); int start = 0; - if (available_tracks[0] == "not") { + if (available_tracks[0] == "not") + { start = 1; m_inverted_config_restriction = true; } @@ -840,7 +841,7 @@ void ServerLobby::handleChat(Event* event) } return false; }, chat); - event->getPeer()->updateLastMessage(); + event->getPeer()->updateLastMessage(); delete chat; } } // handleChat @@ -2406,7 +2407,7 @@ void ServerLobby::startSelection(const Event *event) return; } if (ServerConfig::m_sleeping_server) { - Log::info("ServerLobby", + Log::warn("ServerLobby", "An attempt to start a race on a sleeping server. Lol."); return; } @@ -2612,8 +2613,70 @@ void ServerLobby::startSelection(const Event *event) ns->encodeString(track); } - sendMessageToPeers(ns, /*reliable*/true); - delete ns; + if (!m_gnu_elimination || m_gnu_remained < 0) + { + sendMessageToPeers(ns, /*reliable*/true); + delete ns; + } + else + { + auto remaining_begin = m_gnu_participants.begin(); + auto remaining_end = remaining_begin + m_gnu_remained; + STKHost::get()->sendPacketToAllPeersWith( + [remaining_begin, remaining_end](STKPeer* p) + { + for (auto& profile : p->getPlayerProfiles()) + { + if (std::find( + remaining_begin, remaining_end, + StringUtils::wideToUtf8(profile->getName())) != remaining_end) + { + return true; + } + } + return false; + }, ns, /*reliable*/true); + delete ns; + bool has_gnu = false; + for (auto it = all_k.begin(); it != all_k.end(); it++) + { + has_gnu |= (*it == "gnu"); + } + + // The same NetworkString but without any non-Gnu karts + NetworkString *ns = getNetworkString(1); + ns->setSynchronous(true); + ns->addUInt8(LE_START_SELECTION) + .addFloat(ServerConfig::m_voting_timeout) + .addUInt8(m_game_setup->isGrandPrixStarted() ? 1 : 0) + .addUInt8(ServerConfig::m_auto_game_time_ratio > 0.0f ? 1 : 0) + .addUInt8(ServerConfig::m_track_voting ? 1 : 0); + + ns->addUInt16((uint16_t)(has_gnu ? 1 : 0)).addUInt16((uint16_t)all_t.size()); + if (has_gnu) + { + ns->encodeString(std::string("gnu")); + } + for (const std::string& track : all_t) + { + ns->encodeString(track); + } + + STKHost::get()->sendPacketToAllPeersWith( + [remaining_begin, remaining_end](STKPeer* p) + { + for (auto& profile : p->getPlayerProfiles()) + { + if (std::find( + remaining_begin, remaining_end, + StringUtils::wideToUtf8(profile->getName())) != remaining_end) + { + return false; + } + } + return true; + }, ns, /*reliable*/true); + } m_state = SELECTING; if (!allowJoinedPlayersWaiting()) From f3979d7bba47d5cb092e89ca540ad5d1cdd7bd78 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 19 Feb 2020 14:11:40 +0300 Subject: [PATCH 034/830] Add fixed lap count servers possibility --- NETWORKING.md | 3 +++ src/network/protocols/server_lobby.cpp | 5 +++++ src/network/server_config.hpp | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/NETWORKING.md b/NETWORKING.md index 9151b479d9c..86b168d9461 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -117,6 +117,9 @@ The current server configuration xml looks like this (this is only an example, j + + + diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index d797f8cde24..9ba011d05d2 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1577,6 +1577,11 @@ void ServerLobby::asynchronousUpdate() } if (go_on_race) { + if (ServerConfig::m_fixed_lap_count > 0) + { + winner_vote.m_num_laps = ServerConfig::m_fixed_lap_count; + Log::info("ServerLobby", "Enforcing %d lap race", ServerConfig::m_fixed_lap_count); + } *m_default_vote = winner_vote; m_item_seed = (uint32_t)StkTime::getTimeSinceEpoch(); ItemManager::updateRandomSeed(m_item_seed); diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index e387dc72039..3c69ce6c161 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -258,6 +258,10 @@ namespace ServerConfig "leave empty for no restriction or put 'not' before the list " "to name tracks that cannot be played.")); + SERVER_CFG_PREFIX IntServerConfigParam m_fixed_lap_count + SERVER_CFG_DEFAULT(IntServerConfigParam(-1, "fixed-lap-count", + "Use fixed lap count, negative or zero to disable.")); + SERVER_CFG_PREFIX BoolServerConfigParam m_official_tracks_needed SERVER_CFG_DEFAULT(BoolServerConfigParam(true, "official-tracks-needed", "If this value is set to true, players and the server must have " From 761ac77ada29508820afab7fa7bc5fdcb75c2e65 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 3 Mar 2020 02:42:25 +0300 Subject: [PATCH 035/830] Fix gnu elimination kart choice when nothing selected and some labels --- src/network/protocols/server_lobby.cpp | 57 ++++++++++++++++++++------ 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 32383464be9..8ed838fb920 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -175,6 +175,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() ((std::string) ServerConfig::m_help); m_available_commands = "help commands music kick to public " + "gnu nognu standings " "installaddon uninstalladdon liststkaddon listlocaladdon " "listserveraddon playerhasaddon playeraddonscore serverhasaddon"; @@ -1632,12 +1633,32 @@ void ServerLobby::asynchronousUpdate() { if (players[i]->getKartName().empty()) { - RandomGenerator rg; - std::set::iterator it = - m_available_kts.first.begin(); - std::advance(it, - rg.get((int)m_available_kts.first.size())); - players[i]->setKartName(*it); + bool gnu_eliminated = m_gnu_elimination; + auto remaining_begin = m_gnu_participants.begin(); + auto remaining_end = remaining_begin + m_gnu_remained; + for (auto& profile : players) + { + if (std::find( + remaining_begin, remaining_end, + StringUtils::wideToUtf8(profile->getName())) != remaining_end) + { + gnu_eliminated = false; + break; + } + } + if (gnu_eliminated) + { + + } + else + { + RandomGenerator rg; + std::set::iterator it = + m_available_kts.first.begin(); + std::advance(it, + rg.get((int)m_available_kts.first.size())); + players[i]->setKartName(*it); + } } } @@ -5682,8 +5703,8 @@ void ServerLobby::handleServerCommand(Event* event, chat->addUInt8(LE_CHAT); chat->setSynchronous(true); chat->encodeString16( - L"Gnu Elimination starts"); - peer->sendPacket(chat, true/*reliable*/); + L"Gnu Elimination starts now! Use /standings after each race for results."); + sendMessageToPeers(chat); delete chat; } } @@ -5714,15 +5735,20 @@ void ServerLobby::handleServerCommand(Event* event, chat->addUInt8(LE_CHAT); chat->setSynchronous(true); chat->encodeString16( - L"Gnu Elimination is off"); - peer->sendPacket(chat, true/*reliable*/); + L"Gnu Elimination is now off"); + sendMessageToPeers(chat); delete chat; } } else if (argv[0] == "standings") { - Log::info("GnuElimination", "total %d participants", (int)m_gnu_participants.size()); - std::string result = "Gnu Elimination standings:"; + // Log::info("ServerLobby", "Gnu Elimination: total %d participants", (int)m_gnu_participants.size()); + std::string result = "Gnu Elimination "; + if (m_gnu_elimination) + result += "is running"; + else + result += "is disabled"; + result += ", standings:"; for (int i = 0; i < (int)m_gnu_participants.size(); i++) { std::string line = "\n" + (i < m_gnu_remained ? @@ -5837,5 +5863,12 @@ void ServerLobby::updateGnuElimination() } if (m_gnu_remained <= 1) { m_gnu_elimination = false; + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + std::string message = "Gnu Elimination has finished! Congratulations to " + m_gnu_participants[0] + " !"; + chat->encodeString16(StringUtils::utf8ToWide(message)); + sendMessageToPeers(chat); + delete chat; } } \ No newline at end of file From 7db311034ce58d1218e6d663bc2bb1429d6faabb Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 3 Mar 2020 03:13:51 +0300 Subject: [PATCH 036/830] Fix absent gnu kart choice in gnu elimination --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 8ed838fb920..d26e26a593f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1648,7 +1648,7 @@ void ServerLobby::asynchronousUpdate() } if (gnu_eliminated) { - + players[i]->setKartName("gnu"); } else { From d749850022c1abe6d0603ee24a0b4d31483cd8c8 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 3 Mar 2020 15:36:44 +0300 Subject: [PATCH 037/830] Fix bots choosing gnu --- src/network/protocols/server_lobby.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index d26e26a593f..7596c0c8c9d 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1633,17 +1633,23 @@ void ServerLobby::asynchronousUpdate() { if (players[i]->getKartName().empty()) { - bool gnu_eliminated = m_gnu_elimination; - auto remaining_begin = m_gnu_participants.begin(); - auto remaining_end = remaining_begin + m_gnu_remained; - for (auto& profile : players) + bool gnu_eliminated = m_gnu_elimination && m_gnu_remained >= 0; + if (gnu_eliminated) { - if (std::find( - remaining_begin, remaining_end, - StringUtils::wideToUtf8(profile->getName())) != remaining_end) + auto remaining_begin = m_gnu_participants.begin(); + auto remaining_end = remaining_begin + m_gnu_remained; + for (auto& profile : players) { - gnu_eliminated = false; - break; + if (std::find( + remaining_begin, remaining_end, + StringUtils::wideToUtf8(profile->getName())) != remaining_end) + { + Log::info("ServerLobby", + "Player %s with no chosen kart is not eliminated!", + StringUtils::wideToUtf8(profile->getName()).c_str()); + gnu_eliminated = false; + break; + } } } if (gnu_eliminated) From 53e4e5442fff6507ae51f029d4b9fd30b0e19f86 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 3 Mar 2020 16:33:47 +0300 Subject: [PATCH 038/830] Fix absense of choice for gnu --- src/network/protocols/server_lobby.cpp | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 7596c0c8c9d..c9827ab9ccd 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1629,27 +1629,19 @@ void ServerLobby::asynchronousUpdate() // Add placeholder players for live join addLiveJoinPlaceholder(players); // If player chose random / hasn't chose any kart + bool possible_gnu_enforcement = m_gnu_elimination && m_gnu_remained >= 0; for (unsigned i = 0; i < players.size(); i++) { if (players[i]->getKartName().empty()) { - bool gnu_eliminated = m_gnu_elimination && m_gnu_remained >= 0; + bool gnu_eliminated = possible_gnu_enforcement; if (gnu_eliminated) { - auto remaining_begin = m_gnu_participants.begin(); - auto remaining_end = remaining_begin + m_gnu_remained; - for (auto& profile : players) + if (std::find(m_gnu_participants.begin(), + m_gnu_participants.begin() + m_gnu_remained, + StringUtils::wideToUtf8(players[i]->getName())) != remaining_end) { - if (std::find( - remaining_begin, remaining_end, - StringUtils::wideToUtf8(profile->getName())) != remaining_end) - { - Log::info("ServerLobby", - "Player %s with no chosen kart is not eliminated!", - StringUtils::wideToUtf8(profile->getName()).c_str()); - gnu_eliminated = false; - break; - } + gnu_eliminated = false; } } if (gnu_eliminated) From ca4aae4d659ea2cecea9ac2411c3f2fe7ca8eb0c Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 3 Mar 2020 16:39:02 +0300 Subject: [PATCH 039/830] Fix CE --- src/network/protocols/server_lobby.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index c9827ab9ccd..077b54c84f7 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1639,7 +1639,8 @@ void ServerLobby::asynchronousUpdate() { if (std::find(m_gnu_participants.begin(), m_gnu_participants.begin() + m_gnu_remained, - StringUtils::wideToUtf8(players[i]->getName())) != remaining_end) + StringUtils::wideToUtf8(players[i]->getName())) != + m_gnu_participants.begin() + m_gnu_remained) { gnu_eliminated = false; } From 5cf92e495c623ab7358cd0bf06970e08a13bc305 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 4 Mar 2020 01:58:16 +0300 Subject: [PATCH 040/830] Create custom message for incompatible data refusal (terminal only) --- NETWORKING.md | 4 ++++ src/network/protocols/server_lobby.cpp | 13 +++++++++++++ src/network/server_config.hpp | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/NETWORKING.md b/NETWORKING.md index 86b168d9461..7e97812bcbd 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -222,6 +222,10 @@ The current server configuration xml looks like this (this is only an example, j + + + + ``` diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 077b54c84f7..336b660fa56 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3412,6 +3412,19 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) const message->setSynchronous(true); message->addUInt8(LE_CONNECTION_REFUSED) .addUInt8(RR_INCOMPATIBLE_DATA); + + std::string advice = ServerConfig::m_incompatible_advice; + if (!advice.empty()) + { + NetworkString* incompatible_reason = getNetworkString(); + incompatible_reason->addUInt8(LE_CHAT); + incompatible_reason->setSynchronous(true); + incompatible_reason->encodeString16(StringUtils::utf8ToWide(advice)); + peer->sendPacket(incompatible_reason, true/*reliable*/, false/*encrypted*/); + Log::info("ServerLobby", "Sent advice"); + delete incompatible_reason; + } + peer->cleanPlayerProfiles(); peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); peer->reset(); diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 3c69ce6c161..0713c7803cd 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -491,6 +491,12 @@ namespace ServerConfig "should write a good IP here as a number. Only IPv4 is " "supported.")); + SERVER_CFG_PREFIX StringServerConfigParam m_incompatible_advice + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "incompatible-advice", + "A string given to a peer if it has incompatible data, so " + "that it can know why it cannot enter, empty to disable.")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; From e8ffea31f9929e77c4d345d30ff6331ca04ede0f Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 4 Mar 2020 02:53:38 +0300 Subject: [PATCH 041/830] Store race results in a table inside db --- NETWORKING.md | 3 ++ src/network/protocols/server_lobby.cpp | 54 +++++++++++++++++++++++++- src/network/protocols/server_lobby.hpp | 3 ++ src/network/server_config.hpp | 5 +++ 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/NETWORKING.md b/NETWORKING.md index 7e97812bcbd..9d8487f6ff6 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -222,6 +222,9 @@ The current server configuration xml looks like this (this is only an example, j + + + diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 336b660fa56..1c32e70f373 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -427,6 +427,21 @@ void ServerLobby::initServerStatsTable() ") WITHOUT ROWID;", country_table_name.c_str()); easySQLQuery(query); + // Extra default table _results: + // Server owner need to initialise this table himself, check NETWORKING.md + m_results_table_name = std::string("v") + StringUtils::toString( + ServerConfig::m_server_db_version) + "_results"; + query = StringUtils::insertValues( + "CREATE TABLE IF NOT EXISTS %s (\n" + " time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Timestamp of the result\n" + " username TEXT NOT NULL, -- User who set the result\n" + " venue TEXT NOT NULL, -- Track for a race\n" + " mode INTEGER NOT NULL, -- Racing mode\n" + " laps INTEGER NOT NULL, -- Number of laps\n" + " result REAL NOT NULL -- Elapsed time for a race, possibly with autofinish\n" + ") WITHOUT ROWID;", m_results_table_name.c_str()); + easySQLQuery(query); + // Default views: // _full_stats // Full stats with ip in human readable format and time played of each @@ -2930,6 +2945,15 @@ void ServerLobby::checkRaceFinished() updateGnuElimination(); } + if (ServerConfig::m_store_results) + { + bool racing_mode = false; + racing_mode |= race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE; + racing_mode |= race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL; + if (racing_mode) + storeResults(); + } + if (ServerConfig::m_ranked) { computeNewRankings(); @@ -5883,4 +5907,32 @@ void ServerLobby::updateGnuElimination() sendMessageToPeers(chat); delete chat; } -} \ No newline at end of file +} // updateGnuElimination +//----------------------------------------------------------------------------- +void ServerLobby::storeResults() +{ +#ifdef ENABLE_SQLITE3 + World* w = World::getWorld(); + assert(w); + std::string mode_name = race_manager->getMinorModeName(); + int player_count = race_manager->getNumPlayers(); + int laps_number = race_manager->getNumLaps(); + std::string track_name = race_manager->getTrackName(); + for (int i = 0; i < player_count; i++) + { + if (w->getKart(i)->isEliminated()) + continue; + std::string username = StringUtils::wideToUtf8(race_manager->getKartInfo(i).getPlayerName()); + double elapsed_time = race_manager->getKartRaceTime(i); + std::string query = StringUtils::insertValues( + "INSERT INTO %s " + "(username, venue, mode, laps, result) " + "VALUES (\"%s\", \"%s\", \"%s\", %d, %f);", + m_results_table_name.c_str(), username.c_str(), track_name.c_str(), + mode_name.c_str(), laps_number, elapsed_time + ); + easySQLQuery(query); + } +#endif +} // storeResults +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 8af8698a866..7d170f5b45a 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -84,6 +84,8 @@ class ServerLobby : public LobbyProtocol std::string m_server_stats_table; + std::string m_results_table_name; + bool m_ip_ban_table_exists; bool m_ipv6_ban_table_exists; @@ -407,6 +409,7 @@ class ServerLobby : public LobbyProtocol void initServerStatsTable(); bool isAIProfile(const std::shared_ptr& npp) const { return m_ai_profiles.find(npp) != m_ai_profiles.end(); } + void storeResults(); }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 0713c7803cd..0d1e90076ef 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -491,6 +491,11 @@ namespace ServerConfig "should write a good IP here as a number. Only IPv4 is " "supported.")); + SERVER_CFG_PREFIX BoolServerConfigParam m_store_results + SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "store-results", + "When true, stores race results in a separate table for each " + "server.")); + SERVER_CFG_PREFIX StringServerConfigParam m_incompatible_advice SERVER_CFG_DEFAULT(StringServerConfigParam("", "incompatible-advice", From ca2eb1bdb2088cff2e78d6bac8009e245c2f6f9c Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 4 Mar 2020 02:58:38 +0300 Subject: [PATCH 042/830] Fix typo --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 1c32e70f373..5d06fc5ca95 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -436,7 +436,7 @@ void ServerLobby::initServerStatsTable() " time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Timestamp of the result\n" " username TEXT NOT NULL, -- User who set the result\n" " venue TEXT NOT NULL, -- Track for a race\n" - " mode INTEGER NOT NULL, -- Racing mode\n" + " mode TEXT NOT NULL, -- Racing mode\n" " laps INTEGER NOT NULL, -- Number of laps\n" " result REAL NOT NULL -- Elapsed time for a race, possibly with autofinish\n" ") WITHOUT ROWID;", m_results_table_name.c_str()); From 616bc36b425d3ffc8331385629be6426cee16b0d Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 4 Mar 2020 03:05:18 +0300 Subject: [PATCH 043/830] Fixed table name and a bug --- src/network/protocols/server_lobby.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 5d06fc5ca95..2bf2d3df725 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -430,7 +430,7 @@ void ServerLobby::initServerStatsTable() // Extra default table _results: // Server owner need to initialise this table himself, check NETWORKING.md m_results_table_name = std::string("v") + StringUtils::toString( - ServerConfig::m_server_db_version) + "_results"; + ServerConfig::m_server_db_version) + "_" + ServerConfig::m_server_uid + "_results"; query = StringUtils::insertValues( "CREATE TABLE IF NOT EXISTS %s (\n" " time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Timestamp of the result\n" @@ -439,7 +439,7 @@ void ServerLobby::initServerStatsTable() " mode TEXT NOT NULL, -- Racing mode\n" " laps INTEGER NOT NULL, -- Number of laps\n" " result REAL NOT NULL -- Elapsed time for a race, possibly with autofinish\n" - ") WITHOUT ROWID;", m_results_table_name.c_str()); + ");", m_results_table_name.c_str()); easySQLQuery(query); // Default views: From 0151b37a8624e1e6bc166ce84ceeed8f0cae16c3 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 4 Mar 2020 03:27:24 +0300 Subject: [PATCH 044/830] Add direction to results table --- src/network/protocols/server_lobby.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 2bf2d3df725..bfa3f899349 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -436,6 +436,7 @@ void ServerLobby::initServerStatsTable() " time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Timestamp of the result\n" " username TEXT NOT NULL, -- User who set the result\n" " venue TEXT NOT NULL, -- Track for a race\n" + " reverse TEXT NOT NULL, -- Direction\n" " mode TEXT NOT NULL, -- Racing mode\n" " laps INTEGER NOT NULL, -- Number of laps\n" " result REAL NOT NULL -- Elapsed time for a race, possibly with autofinish\n" @@ -5918,6 +5919,7 @@ void ServerLobby::storeResults() int player_count = race_manager->getNumPlayers(); int laps_number = race_manager->getNumLaps(); std::string track_name = race_manager->getTrackName(); + std::string reverse_string = (race_manager->getReverseTrack() ? "reverse" : "normal"); for (int i = 0; i < player_count; i++) { if (w->getKart(i)->isEliminated()) @@ -5926,10 +5928,10 @@ void ServerLobby::storeResults() double elapsed_time = race_manager->getKartRaceTime(i); std::string query = StringUtils::insertValues( "INSERT INTO %s " - "(username, venue, mode, laps, result) " + "(username, venue, reverse, mode, laps, result) " "VALUES (\"%s\", \"%s\", \"%s\", %d, %f);", m_results_table_name.c_str(), username.c_str(), track_name.c_str(), - mode_name.c_str(), laps_number, elapsed_time + reverse_string.c_str(), mode_name.c_str(), laps_number, elapsed_time ); easySQLQuery(query); } From bd564c390ac980a84d5a9af22f37678b9d55d0f1 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 4 Mar 2020 03:35:29 +0300 Subject: [PATCH 045/830] Fix a bug --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index bfa3f899349..40c454a3fb2 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -5929,7 +5929,7 @@ void ServerLobby::storeResults() std::string query = StringUtils::insertValues( "INSERT INTO %s " "(username, venue, reverse, mode, laps, result) " - "VALUES (\"%s\", \"%s\", \"%s\", %d, %f);", + "VALUES (\"%s\", \"%s\", \"%s\", \"%s\", %d, %f);", m_results_table_name.c_str(), username.c_str(), track_name.c_str(), reverse_string.c_str(), mode_name.c_str(), laps_number, elapsed_time ); From a344710933dcd440079311c9944c3f574b1220ed Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 6 Mar 2020 16:28:14 +0300 Subject: [PATCH 046/830] Make RaceManager singleton as it should be in the correct merge --- src/network/protocols/server_lobby.cpp | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 7b94efdaec5..4fc42b18a4e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2950,8 +2950,8 @@ void ServerLobby::checkRaceFinished() if (ServerConfig::m_store_results) { bool racing_mode = false; - racing_mode |= race_manager->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE; - racing_mode |= race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL; + racing_mode |= RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE; + racing_mode |= RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL; if (racing_mode) storeResults(); } @@ -5900,16 +5900,16 @@ void ServerLobby::updateGnuElimination() World* w = World::getWorld(); assert(w); assert(m_gnu_remained != 0); - int player_count = race_manager->getNumPlayers(); + int player_count = RaceManager::get()->getNumPlayers(); const double INF = 1e9; std::vector> order; if (m_gnu_remained < 0) { for (int i = 0; i < player_count; i++) { - std::string username = StringUtils::wideToUtf8(race_manager->getKartInfo(i).getPlayerName()); + std::string username = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(i).getPlayerName()); double elapsed_time = (w->getKart(i)->isEliminated() ? INF : - race_manager->getKartRaceTime(i)); + RaceManager::get()->getKartRaceTime(i)); order.emplace_back(elapsed_time, username); m_gnu_participants.push_back(username); } @@ -5924,9 +5924,9 @@ void ServerLobby::updateGnuElimination() // the number of players is very small and I don't want maps for (int i = 0; i < player_count; i++) { - std::string username = StringUtils::wideToUtf8(race_manager->getKartInfo(i).getPlayerName()); + std::string username = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(i).getPlayerName()); double elapsed_time = (w->getKart(i)->isEliminated() ? INF : - race_manager->getKartRaceTime(i)); + RaceManager::get()->getKartRaceTime(i)); for (int j = 0; j < m_gnu_remained; j++) { if (m_gnu_participants[j] == username) @@ -5964,17 +5964,17 @@ void ServerLobby::storeResults() #ifdef ENABLE_SQLITE3 World* w = World::getWorld(); assert(w); - std::string mode_name = race_manager->getMinorModeName(); - int player_count = race_manager->getNumPlayers(); - int laps_number = race_manager->getNumLaps(); - std::string track_name = race_manager->getTrackName(); - std::string reverse_string = (race_manager->getReverseTrack() ? "reverse" : "normal"); + std::string mode_name = RaceManager::get()->getMinorModeName(); + int player_count = RaceManager::get()->getNumPlayers(); + int laps_number = RaceManager::get()->getNumLaps(); + std::string track_name = RaceManager::get()->getTrackName(); + std::string reverse_string = (RaceManager::get()->getReverseTrack() ? "reverse" : "normal"); for (int i = 0; i < player_count; i++) { if (w->getKart(i)->isEliminated()) continue; - std::string username = StringUtils::wideToUtf8(race_manager->getKartInfo(i).getPlayerName()); - double elapsed_time = race_manager->getKartRaceTime(i); + std::string username = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(i).getPlayerName()); + double elapsed_time = RaceManager::get()->getKartRaceTime(i); std::string query = StringUtils::insertValues( "INSERT INTO %s " "(username, venue, reverse, mode, laps, result) " From 4401b73df4ee134544ec1f0112ade13e9adb17ae Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 8 Mar 2020 02:31:54 +0300 Subject: [PATCH 047/830] Add possibility of any kart elimination --- src/network/protocols/server_lobby.cpp | 11 ++++++++--- src/network/protocols/server_lobby.hpp | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 4fc42b18a4e..e4b9bd002f5 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1655,7 +1655,7 @@ void ServerLobby::asynchronousUpdate() } if (gnu_eliminated) { - players[i]->setKartName("gnu"); + players[i]->setKartName(m_gnu_kart); } else { @@ -2686,7 +2686,7 @@ void ServerLobby::startSelection(const Event *event) bool has_gnu = false; for (auto it = all_k.begin(); it != all_k.end(); it++) { - has_gnu |= (*it == "gnu"); + has_gnu |= (*it == m_gnu_kart); } // The same NetworkString but without any non-Gnu karts @@ -2701,7 +2701,7 @@ void ServerLobby::startSelection(const Event *event) ns->addUInt16((uint16_t)(has_gnu ? 1 : 0)).addUInt16((uint16_t)all_t.size()); if (has_gnu) { - ns->encodeString(std::string("gnu")); + ns->encodeString(std::string(m_gnu_kart)); } for (const std::string& track : all_t) { @@ -5782,6 +5782,11 @@ void ServerLobby::handleServerCommand(Event* event, } else if (false/* one player */) { } else { + if (argv.size() > 1 && m_available_kts.first.count(argv[1]) > 0) { + m_gnu_kart = argv[1]; + } else { + m_gnu_kart = "gnu"; + } NetworkString* chat = getNetworkString(); m_gnu_elimination = true; m_gnu_remained = -1; diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index b37b1f84587..69291f5d5d8 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -254,6 +254,7 @@ class ServerLobby : public LobbyProtocol bool m_gnu_elimination; int m_gnu_remained; + std::string m_gnu_kart; std::vector m_gnu_participants; // connection management From fd5239b9dcae3fffe6588d78403a0ab3cd3a1527 Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 8 Mar 2020 03:16:31 +0300 Subject: [PATCH 048/830] Paint bots in boring colors --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index e4b9bd002f5..6d320ed2b21 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3815,7 +3815,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, if (i > 0) name += core::stringw(" ") + StringUtils::toWString(i); m_ai_profiles.insert(std::make_shared - (peer, name, peer->getHostId(), 0.0f, 0, HANDICAP_NONE, + (peer, name, peer->getHostId(), (44 + 13 * i) % 100 + 1., 0, HANDICAP_NONE, player_count + i, KART_TEAM_NONE, "")); } } From f668e0c415c2182df9865ffa4e8042d5f7bae393 Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 8 Mar 2020 03:23:09 +0300 Subject: [PATCH 049/830] Fix a bug --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 6d320ed2b21..e1b93a9dfad 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3815,7 +3815,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, if (i > 0) name += core::stringw(" ") + StringUtils::toWString(i); m_ai_profiles.insert(std::make_shared - (peer, name, peer->getHostId(), (44 + 13 * i) % 100 + 1., 0, HANDICAP_NONE, + (peer, name, peer->getHostId(), (44 + 13 * i) % 100 * 0.01 + 0.01, 0, HANDICAP_NONE, player_count + i, KART_TEAM_NONE, "")); } } From 6f779865e74f8da527142e2e3810840fb09e5892 Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 8 Mar 2020 16:02:20 +0300 Subject: [PATCH 050/830] Add beating the record message --- NETWORKING.md | 3 + src/network/protocols/server_lobby.cpp | 109 ++++++++++++++++++++++++- src/network/protocols/server_lobby.hpp | 4 + src/network/server_config.hpp | 7 ++ 4 files changed, 121 insertions(+), 2 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index 5347b9ef85a..5c33aa0d4a8 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -225,6 +225,9 @@ The current server configuration xml looks like this (this is only an example, j + + + diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index e1b93a9dfad..68bb6467429 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1163,6 +1163,48 @@ bool ServerLobby::easySQLQuery(const std::string& query, return true; } // easySQLQuery +//----------------------------------------------------------------------------- +std::pair>> +ServerLobby::vectorSQLQuery(const std::string& query, + int columns, std::function bind_function) const +{ + std::vector> ans(columns); + if (!m_db) + return {false, {}}; + sqlite3_stmt* stmt = NULL; + int ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0); + if (ret == SQLITE_OK) + { + if (bind_function) + bind_function(stmt); + ret = sqlite3_step(stmt); + while (sqlite3_column_text(stmt, 0)) + { + for (int i = 0; i < columns; i++) + { + ans[i].push_back(std::string((char*)sqlite3_column_text(stmt, i))); + } + ret = sqlite3_step(stmt); + } + ret = sqlite3_finalize(stmt); + if (ret != SQLITE_OK) + { + Log::error("ServerLobby", + "Error finalize database for vector query %s: %s", + query.c_str(), sqlite3_errmsg(m_db)); + return {false, {}}; + } + } + else + { + Log::error("ServerLobby", + "Error preparing database for vector query %s: %s", + query.c_str(), sqlite3_errmsg(m_db)); + return {false, {}}; + } + return {true, ans}; +} // vectorSQLQuery + //----------------------------------------------------------------------------- /* Write true to result if table name exists in database. */ void ServerLobby::checkTableExists(const std::string& table, bool& result) @@ -5969,17 +6011,57 @@ void ServerLobby::storeResults() #ifdef ENABLE_SQLITE3 World* w = World::getWorld(); assert(w); + std::string records_table_name = ServerConfig::m_records_table_name; std::string mode_name = RaceManager::get()->getMinorModeName(); int player_count = RaceManager::get()->getNumPlayers(); int laps_number = RaceManager::get()->getNumLaps(); std::string track_name = RaceManager::get()->getTrackName(); - std::string reverse_string = (RaceManager::get()->getReverseTrack() ? "reverse" : "normal"); + std::string reverse_string = + (RaceManager::get()->getReverseTrack() ? "reverse" : "normal"); + + bool record_fetched = false; + bool record_exists = false; + double best_result = 0.0; + std::string best_user = ""; + + if (!records_table_name.empty()) + { + std::string get_query = StringUtils::insertValues("SELECT username, " + "result FROM %s INNER JOIN " + "(SELECT venue as v, reverse as r, mode as m, laps as l, " + "min(result) as min_res FROM %s group by v, r, m, l) " + "ON venue = v and reverse = r and mode = m and laps = l " + "and result = min_res " + "WHERE venue = \"%s\" and reverse = \"%s\" " + "and mode = \"%s\" and laps = %d;", + records_table_name.c_str(), records_table_name.c_str(), + track_name.c_str(), reverse_string.c_str(), mode_name.c_str(), + laps_number); + auto ret = vectorSQLQuery(get_query, 2); + record_fetched = ret.first; + if (record_fetched && ret.second[0].size() > 0){ + record_exists = true; + best_user = ret.second[0][0]; + parseString(ret.second[1][0], &best_result); + } + } + + int best_cur_player_idx = -1; + std::string best_cur_player_name = ""; + double best_cur_time = 1e18; for (int i = 0; i < player_count; i++) { if (w->getKart(i)->isEliminated()) continue; - std::string username = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(i).getPlayerName()); + std::string username = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(i).getPlayerName()); double elapsed_time = RaceManager::get()->getKartRaceTime(i); + if (best_cur_player_idx == -1 || elapsed_time < best_cur_time) + { + best_cur_player_idx = i; + best_cur_time = elapsed_time; + best_cur_player_name = username; + } std::string query = StringUtils::insertValues( "INSERT INTO %s " "(username, venue, reverse, mode, laps, result) " @@ -5989,6 +6071,29 @@ void ServerLobby::storeResults() ); easySQLQuery(query); } + if (record_fetched && best_cur_player_idx != -1) + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + std::string message; + if (!record_exists) + { + message = StringUtils::insertValues( + "%s has just set a server record: %s\nThis is the first time set.", + best_cur_player_name, StringUtils::timeToString(best_cur_time)); + } + else if (best_result > best_cur_time) + { + message = StringUtils::insertValues( + "%s has just beaten a server record: %s\nPrevious record: %s by %s", + best_cur_player_name, StringUtils::timeToString(best_cur_time), + best_result, best_user); + } + chat->encodeString16(StringUtils::utf8ToWide(message)); + sendMessageToPeers(chat); + delete chat; + } #endif } // storeResults //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 69291f5d5d8..03d0a57e11a 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -103,6 +103,10 @@ class ServerLobby : public LobbyProtocol bool easySQLQuery(const std::string& query, std::function bind_function = nullptr) const; + std::pair>> + vectorSQLQuery(const std::string& query, int columns, + std::function bind_function) const; + void checkTableExists(const std::string& table, bool& result); std::string ip2Country(const SocketAddress& addr) const; diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index f0f1c40f90e..c7c89a9ee82 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -498,6 +498,13 @@ namespace ServerConfig "When true, stores race results in a separate table for each " "server.")); + SERVER_CFG_PREFIX StringServerConfigParam m_records_table_name + SERVER_CFG_DEFAULT(BoolServerConfigParam("", "records-table-name", + "When non-empty, server is telling whether a player has beaten " + "a server record, records are taken from the table specified " + "in this field. So it can be the results table for this server " + "or for all servers hosted on the machine.")); + SERVER_CFG_PREFIX StringServerConfigParam m_incompatible_advice SERVER_CFG_DEFAULT(StringServerConfigParam("", "incompatible-advice", From af6cf0bb09a56e8013371e6f2db653416a38ce0a Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 8 Mar 2020 16:02:47 +0300 Subject: [PATCH 051/830] Make hours visible --- src/utils/string_utils.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index cf8414e9491..a75cbe56230 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -49,7 +49,7 @@ namespace StringUtils std::string ticksTimeToString(int time); std::string timeToString(float time, unsigned int precision = 3, - bool display_minutes_if_zero = true, bool display_hours = false); + bool display_minutes_if_zero = true, bool display_hours = true); irr::core::stringw loadingDots(float interval = 0.5f, int max_dots = 3); irr::core::stringw loadingDots(const irr::core::stringw& s); std::string toUpperCase(const std::string&); From 4496a7c8e89d2f7cc7cd297abcbe95fb47ad939a Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 8 Mar 2020 16:19:10 +0300 Subject: [PATCH 052/830] Fix bugs --- src/network/protocols/server_lobby.cpp | 3 ++- src/network/protocols/server_lobby.hpp | 2 +- src/network/server_config.hpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 68bb6467429..6d2fbc24da3 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6042,7 +6042,8 @@ void ServerLobby::storeResults() if (record_fetched && ret.second[0].size() > 0){ record_exists = true; best_user = ret.second[0][0]; - parseString(ret.second[1][0], &best_result); + if (!StringUtils::parseString(ret.second[1][0], &best_result)) + record_fetched = false; } } diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 03d0a57e11a..6430a2e4f8b 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -105,7 +105,7 @@ class ServerLobby : public LobbyProtocol std::pair>> vectorSQLQuery(const std::string& query, int columns, - std::function bind_function) const; + std::function bind_function = nullptr) const; void checkTableExists(const std::string& table, bool& result); diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index c7c89a9ee82..378b456e570 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -499,7 +499,7 @@ namespace ServerConfig "server.")); SERVER_CFG_PREFIX StringServerConfigParam m_records_table_name - SERVER_CFG_DEFAULT(BoolServerConfigParam("", "records-table-name", + SERVER_CFG_DEFAULT(StringServerConfigParam("", "records-table-name", "When non-empty, server is telling whether a player has beaten " "a server record, records are taken from the table specified " "in this field. So it can be the results table for this server " From 11fcfea662e32def235ee85f631e0203db17a432 Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 8 Mar 2020 17:14:42 +0300 Subject: [PATCH 053/830] Fix bugs and style, add /record --- src/network/protocols/server_lobby.cpp | 111 +++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 7 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 6d2fbc24da3..4c1ee72b78b 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -176,7 +176,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() ((std::string) ServerConfig::m_help); m_available_commands = "help commands music kick to public " - "gnu nognu standings " + "gnu nognu standings record" "installaddon uninstalladdon liststkaddon listlocaladdon " "listserveraddon playerhasaddon playeraddonscore serverhasaddon"; @@ -5813,7 +5813,9 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; return; - } else if (m_gnu_elimination) { + } + else if (m_gnu_elimination) + { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); @@ -5821,9 +5823,13 @@ void ServerLobby::handleServerCommand(Event* event, L"Gnu Elimination mode was already enabled!"); peer->sendPacket(chat, true/*reliable*/); delete chat; - } else if (false/* one player */) { + } + else if (false/* one player */) + { - } else { + } + else + { if (argv.size() > 1 && m_available_kts.first.count(argv[1]) > 0) { m_gnu_kart = argv[1]; } else { @@ -5852,7 +5858,9 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; return; - } else if (!m_gnu_elimination) { + } + else if (!m_gnu_elimination) + { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); @@ -5860,7 +5868,9 @@ void ServerLobby::handleServerCommand(Event* event, L"Gnu Elimination mode was already off!"); peer->sendPacket(chat, true/*reliable*/); delete chat; - } else { + } + else + { NetworkString* chat = getNetworkString(); m_gnu_elimination = false; m_gnu_remained = 0; @@ -5929,6 +5939,93 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; } + else if (argv[0] == "record") + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); +#ifdef ENABLE_SQLITE3 + if (argv.size() < 5) + { + chat->encodeString16(L"Usage: /record (track id) " + "(normal/time-trial) (normal/reverse) (laps)\n" + "Receives the server record for the race settings if any"); + } else { + bool error = false; + std::string track_name = argv[1]; + std::string mode_name = (argv[2] == "t" || argv[2] == "tt" + || argv[2] == "time-trial" || argv[2] == "timetrial" ? + "time-trial" : "normal"); + std::string reverse_name = (argv[3] == "r" || + argv[3] == "rev" || argv[3] == "reverse" ? "reverse" : + "normal"); + int laps_count = -1; + if (!StringUtils::parseString(argv[4], &laps_count)) + error = true; + if (!error && laps_count < 0) + error = true; + if (error) + { + chat->encodeString16(L"Invalid lap count"); + } + else + { + std::string records_table_name = ServerConfig::m_records_table_name; + if (!records_table_name.empty()) + { + std::string get_query = StringUtils::insertValues("SELECT username, " + "result FROM %s INNER JOIN " + "(SELECT venue as v, reverse as r, mode as m, laps as l, " + "min(result) as min_res FROM %s group by v, r, m, l) " + "ON venue = v and reverse = r and mode = m and laps = l " + "and result = min_res " + "WHERE venue = \"%s\" and reverse = \"%s\" " + "and mode = \"%s\" and laps = %d;", + records_table_name.c_str(), records_table_name.c_str(), + track_name.c_str(), reverse_name.c_str(), mode_name.c_str(), + laps_count); + auto ret = vectorSQLQuery(get_query, 2); + if (!ret.first) + { + chat->encodeString16(L"Failed to make a query"); + } + else if (ret.second[0].size() > 0) + { + double best_result = 1e18; + if (!StringUtils::parseString( + ret.second[1][0], &best_result)) + { + chat->encodeString16(L"A strange error occured, " + "please take a screenshot " + "and contact the server owner."); + } + else + { + std::string message = StringUtils::insertValues( + "The record is %s by %s", + StringUtils::timeToString(best_result), + ret.second[0][0]); + chat->encodeString16( + StringUtils::utf8ToWide(message)); + } + } + else + { + chat->encodeString16(L"No time set yet. Or there is a typo."); + } + } + else + { + chat->encodeString16(L"No table storing records!"); + } + } + } +#else + chat->encodeString16(L"This command is not supported."); +#endif + peer->sendPacket(chat, true/*reliable*/); + delete chat; + } else { NetworkString* chat = getNetworkString(); @@ -6089,7 +6186,7 @@ void ServerLobby::storeResults() message = StringUtils::insertValues( "%s has just beaten a server record: %s\nPrevious record: %s by %s", best_cur_player_name, StringUtils::timeToString(best_cur_time), - best_result, best_user); + StringUtils::timeToString(best_result), best_user); } chat->encodeString16(StringUtils::utf8ToWide(message)); sendMessageToPeers(chat); From aff1fa0490147206ca09b8bd1bef6ad8960238e9 Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 8 Mar 2020 23:46:07 +0300 Subject: [PATCH 054/830] Fix empty message bug --- src/network/protocols/server_lobby.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 4c1ee72b78b..fdff0adc600 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6187,6 +6187,9 @@ void ServerLobby::storeResults() "%s has just beaten a server record: %s\nPrevious record: %s by %s", best_cur_player_name, StringUtils::timeToString(best_cur_time), StringUtils::timeToString(best_result), best_user); + } else { + delete chat; + return; } chat->encodeString16(StringUtils::utf8ToWide(message)); sendMessageToPeers(chat); From 99d42bb81b9ea9348a6704f2d5832c65a928464a Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 14 Mar 2020 19:07:44 +0300 Subject: [PATCH 055/830] Add possibility of partly configurable servers --- NETWORKING.md | 3 ++ src/network/protocols/server_lobby.cpp | 46 +++++++++++++++++++++++++- src/network/protocols/server_lobby.hpp | 8 +++++ src/network/server_config.hpp | 7 ++++ 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/NETWORKING.md b/NETWORKING.md index 5c33aa0d4a8..b5e27a6ef76 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -141,6 +141,9 @@ The current server configuration xml looks like this (this is only an example, j + + + diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index fdff0adc600..2a22e9872a5 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -176,13 +176,15 @@ ServerLobby::ServerLobby() : LobbyProtocol() ((std::string) ServerConfig::m_help); m_available_commands = "help commands music kick to public " - "gnu nognu standings record" + "gnu nognu standings record " "installaddon uninstalladdon liststkaddon listlocaladdon " "listserveraddon playerhasaddon playeraddonscore serverhasaddon"; m_gnu_elimination = false; m_gnu_remained = 0; + initAvailableModes(); + std::vector all_k = kart_properties_manager->getKartsInGroup("standard"); std::vector all_t = @@ -5098,6 +5100,20 @@ void ServerLobby::handleServerConfiguration(Event* event) NetworkString& data = event->data(); int new_difficulty = data.getUInt8(); int new_game_mode = data.getUInt8(); + if (m_available_difficulties.count(new_difficulty) == 0 || + m_available_modes.count(new_game_mode) == 0) + { + Log::error("ServerLobby", "Mode %d and/or difficulty %d are not permitted."); + auto peer = event->getPeerSP(); + NetworkString* chat = getNetworkString(); + // I don't know for now which type to choose... + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(L"Mode or difficulty are not permitted on this server"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + return; + } bool new_soccer_goal_target = data.getUInt8() == 1; auto modes = ServerConfig::getLocalGameMode(new_game_mode); if (modes.second == RaceManager::MAJOR_MODE_GRAND_PRIX) @@ -6197,4 +6213,32 @@ void ServerLobby::storeResults() } #endif } // storeResults +//----------------------------------------------------------------------------- +void ServerLobby::initAvailableModes() +{ + std::vector statements = + StringUtils::split(ServerConfig::m_available_modes, ' ', false); + + for (const std::string& s: statements) + { + if (s.length() <= 1) { + continue; + } + bool difficulty = s[0] == 'd'; + if (difficulty) + { + for (unsigned i = 1; i < s.length(); i++) + { + m_available_difficulties.insert(s[i] - '0'); + } + } + else + { + for (unsigned i = 1; i < s.length(); i++) + { + m_available_modes.insert(s[i] - '0'); + } + } + } +} // initAvailableModes //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 6430a2e4f8b..3cf432d43e7 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -257,10 +257,17 @@ class ServerLobby : public LobbyProtocol std::map> m_message_receivers; bool m_gnu_elimination; + int m_gnu_remained; + std::string m_gnu_kart; + std::vector m_gnu_participants; + std::set m_available_difficulties; + + std::set m_available_modes; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); @@ -414,6 +421,7 @@ class ServerLobby : public LobbyProtocol void storeResults(); uint32_t getServerIdOnline() const { return m_server_id_online; } void setClientServerHostId(uint32_t id) { m_client_server_host_id = id; } + void initAvailableModes(); }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 378b456e570..56330bc2395 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -307,6 +307,13 @@ namespace ServerConfig "was created using the in-game GUI. The changed difficulty and game " "mode will not be saved in this config file.")); + SERVER_CFG_PREFIX StringServerConfigParam m_available_modes + SERVER_CFG_DEFAULT(StringServerConfigParam("d0123 m012345678", "available-modes", + "Description of modes and difficulties that can be set " + "on a configurable server. Doesn't affect initial mode " + "and doesn't affect unconfigurable servers. Use the " + "format \"d0123 m012345678\".")); + SERVER_CFG_PREFIX BoolServerConfigParam m_live_players SERVER_CFG_DEFAULT(BoolServerConfigParam(true, "live-players", "If true, players can live join or spectate the in-progress game. " From 20018b8b85d94649cc823b2bc8f36ee2ec33bb83 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 14 Mar 2020 19:12:14 +0300 Subject: [PATCH 056/830] Shorten lines --- src/network/protocols/server_lobby.cpp | 41 ++++++++++++++++++-------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 2a22e9872a5..15d7842312c 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -250,7 +250,9 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_restricting_config = false; else { - std::vector available_tracks = StringUtils::split(ServerConfig::m_only_played_tracks_string, ' ', false); + std::vector available_tracks = + StringUtils::split(ServerConfig::m_only_played_tracks_string, + ' ', false); int start = 0; if (available_tracks[0] == "not") { @@ -262,7 +264,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_config_available_tracks.insert(available_tracks[i]); } } - m_must_have_tracks = StringUtils::split(ServerConfig::m_must_have_tracks_string, ' ', false); + m_must_have_tracks = StringUtils::split( + ServerConfig::m_must_have_tracks_string, ' ', false); m_rs_state.store(RS_NONE); m_last_success_poll_time.store(StkTime::getMonoTimeMs() + 30000); @@ -433,7 +436,8 @@ void ServerLobby::initServerStatsTable() // Extra default table _results: // Server owner need to initialise this table himself, check NETWORKING.md m_results_table_name = std::string("v") + StringUtils::toString( - ServerConfig::m_server_db_version) + "_" + ServerConfig::m_server_uid + "_results"; + ServerConfig::m_server_db_version) + "_" + + ServerConfig::m_server_uid + "_results"; query = StringUtils::insertValues( "CREATE TABLE IF NOT EXISTS %s (\n" " time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Timestamp of the result\n" @@ -708,7 +712,9 @@ void ServerLobby::updateTracksForMode() auto it = m_available_kts.second.begin(); while (it != m_available_kts.second.end()) { - if (m_inverted_config_restriction ^ (m_config_available_tracks.find(*it) == m_config_available_tracks.end())) + if (m_inverted_config_restriction ^ + (m_config_available_tracks.find(*it) == + m_config_available_tracks.end())) erase_tracks.insert(*it); it++; } @@ -855,7 +861,8 @@ void ServerLobby::handleChat(Event* event) } for (auto& profile : p->getPlayerProfiles()) { - if (can_receive.find(profile->getName()) != can_receive.end()) + if (can_receive.find(profile->getName()) != + can_receive.end()) { return true; } @@ -1184,7 +1191,8 @@ ServerLobby::vectorSQLQuery(const std::string& query, { for (int i = 0; i < columns; i++) { - ans[i].push_back(std::string((char*)sqlite3_column_text(stmt, i))); + ans[i].push_back(std::string( + (char*)sqlite3_column_text(stmt, i))); } ret = sqlite3_step(stmt); } @@ -1681,7 +1689,8 @@ void ServerLobby::asynchronousUpdate() // Add placeholder players for live join addLiveJoinPlaceholder(players); // If player chose random / hasn't chose any kart - bool possible_gnu_enforcement = m_gnu_elimination && m_gnu_remained >= 0; + bool possible_gnu_enforcement = + m_gnu_elimination && m_gnu_remained >= 0; for (unsigned i = 0; i < players.size(); i++) { if (players[i]->getKartName().empty()) @@ -2742,7 +2751,8 @@ void ServerLobby::startSelection(const Event *event) .addUInt8(ServerConfig::m_auto_game_time_ratio > 0.0f ? 1 : 0) .addUInt8(ServerConfig::m_track_voting ? 1 : 0); - ns->addUInt16((uint16_t)(has_gnu ? 1 : 0)).addUInt16((uint16_t)all_t.size()); + ns->addUInt16((uint16_t)(has_gnu ? 1 : 0)).addUInt16( + (uint16_t)all_t.size()); if (has_gnu) { ns->encodeString(std::string(m_gnu_kart)); @@ -2759,7 +2769,8 @@ void ServerLobby::startSelection(const Event *event) { if (std::find( remaining_begin, remaining_end, - StringUtils::wideToUtf8(profile->getName())) != remaining_end) + StringUtils::wideToUtf8(profile->getName())) + != remaining_end) { return false; } @@ -2994,8 +3005,10 @@ void ServerLobby::checkRaceFinished() if (ServerConfig::m_store_results) { bool racing_mode = false; - racing_mode |= RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE; - racing_mode |= RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL; + racing_mode |= RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_NORMAL_RACE; + racing_mode |= RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_TIME_TRIAL; if (racing_mode) storeResults(); } @@ -3489,8 +3502,10 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) const NetworkString* incompatible_reason = getNetworkString(); incompatible_reason->addUInt8(LE_CHAT); incompatible_reason->setSynchronous(true); - incompatible_reason->encodeString16(StringUtils::utf8ToWide(advice)); - peer->sendPacket(incompatible_reason, true/*reliable*/, false/*encrypted*/); + incompatible_reason->encodeString16( + StringUtils::utf8ToWide(advice)); + peer->sendPacket(incompatible_reason, + true/*reliable*/, false/*encrypted*/); Log::info("ServerLobby", "Sent advice"); delete incompatible_reason; } From abdc16a17831404ad61ea90108dbe9b00e36e0ae Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 15 Mar 2020 03:53:08 +0300 Subject: [PATCH 057/830] Change query statement when telling if the time is the new record --- src/network/protocols/server_lobby.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 4d09f8c6b9c..19defd2f29e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6034,13 +6034,12 @@ void ServerLobby::handleServerCommand(Event* event, if (!records_table_name.empty()) { std::string get_query = StringUtils::insertValues("SELECT username, " - "result FROM %s INNER JOIN " + "result FROM %s LEFT JOIN " "(SELECT venue as v, reverse as r, mode as m, laps as l, " "min(result) as min_res FROM %s group by v, r, m, l) " "ON venue = v and reverse = r and mode = m and laps = l " - "and result = min_res " "WHERE venue = \"%s\" and reverse = \"%s\" " - "and mode = \"%s\" and laps = %d;", + "and mode = \"%s\" and laps = %d and result = min_res;", records_table_name.c_str(), records_table_name.c_str(), track_name.c_str(), reverse_name.c_str(), mode_name.c_str(), laps_count); From f46499c8878190fe560ad15c5937de8b02dea0a3 Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 16 Mar 2020 23:13:30 +0000 Subject: [PATCH 058/830] Fix the required number of players to start for sleeping server --- src/network/server_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 6dbf0fe07ea..d6a9c2e474e 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -362,7 +362,7 @@ void loadServerLobbyFromConfig() if (m_owner_less) { if (m_sleeping_server) { - m_min_start_game_players = 123456; + m_min_start_game_players = m_server_max_players; } else { if (m_min_start_game_players > m_server_max_players) m_min_start_game_players = 1; From d8001791c02852793b2ae5f6a248d4083ed0e13d Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 16 Mar 2020 23:23:43 +0000 Subject: [PATCH 059/830] Fix the same bug but properly --- src/network/server_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index d6a9c2e474e..f37fcdbfa54 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -362,7 +362,7 @@ void loadServerLobbyFromConfig() if (m_owner_less) { if (m_sleeping_server) { - m_min_start_game_players = m_server_max_players; + m_min_start_game_players = m_server_max_players + 1; } else { if (m_min_start_game_players > m_server_max_players) m_min_start_game_players = 1; From 33766a88334f17aa6c84a1546facd46a0c9cd030 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 24 Mar 2020 14:58:35 +0300 Subject: [PATCH 060/830] Fix sql quotes for records storing --- src/network/protocols/server_lobby.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index b2a63491b8c..2aeb1283d26 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6038,8 +6038,8 @@ void ServerLobby::handleServerCommand(Event* event, "(SELECT venue as v, reverse as r, mode as m, laps as l, " "min(result) as min_res FROM %s group by v, r, m, l) " "ON venue = v and reverse = r and mode = m and laps = l " - "WHERE venue = \"%s\" and reverse = \"%s\" " - "and mode = \"%s\" and laps = %d and result = min_res;", + "WHERE venue = '%s' and reverse = '%s' " + "and mode = '%s' and laps = %d and result = min_res;", records_table_name.c_str(), records_table_name.c_str(), track_name.c_str(), reverse_name.c_str(), mode_name.c_str(), laps_count); @@ -6188,8 +6188,8 @@ void ServerLobby::storeResults() "min(result) as min_res FROM %s group by v, r, m, l) " "ON venue = v and reverse = r and mode = m and laps = l " "and result = min_res " - "WHERE venue = \"%s\" and reverse = \"%s\" " - "and mode = \"%s\" and laps = %d;", + "WHERE venue = '%s' and reverse = '%s' " + "and mode = '%s' and laps = %d;", records_table_name.c_str(), records_table_name.c_str(), track_name.c_str(), reverse_string.c_str(), mode_name.c_str(), laps_number); @@ -6222,7 +6222,7 @@ void ServerLobby::storeResults() std::string query = StringUtils::insertValues( "INSERT INTO %s " "(username, venue, reverse, mode, laps, result) " - "VALUES (\"%s\", \"%s\", \"%s\", \"%s\", %d, %f);", + "VALUES ('%s', '%s', '%s', '%s', %d, %f);", m_results_table_name.c_str(), username.c_str(), track_name.c_str(), reverse_string.c_str(), mode_name.c_str(), laps_number, elapsed_time ); From 79b62662e1b26d5267d7dc909d661cbb8ba91e9f Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 24 Mar 2020 15:10:35 +0300 Subject: [PATCH 061/830] Inform players about gnu kart choice --- src/network/protocols/server_lobby.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 2aeb1283d26..a8cc98a5d8d 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -5901,8 +5901,19 @@ void ServerLobby::handleServerCommand(Event* event, m_gnu_participants.clear(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); - chat->encodeString16( - L"Gnu Elimination starts now! Use /standings after each race for results."); + if (m_gnu_kart == "gnu") + { + chat->encodeString16( + L"Gnu Elimination starts now! Use /standings " + "after each race for results."); + } + else + { + chat->encodeString16(StringUtils::utf8ToWide( + StringUtils::insertValues("Gnu Elimination starts now " + "(elimination kart: %s)! Use /standings " + "after each race for results.", m_gnu_kart))); + } sendMessageToPeers(chat); delete chat; } @@ -5980,7 +5991,7 @@ void ServerLobby::handleServerCommand(Event* event, chat->addUInt8(LE_CHAT); chat->setSynchronous(true); m_message_receivers[peer.get()].clear(); - for (int i = 1; i < argv.size(); ++i) { + for (unsigned i = 1; i < argv.size(); ++i) { m_message_receivers[peer.get()].insert( StringUtils::utf8ToWide(argv[i])); } @@ -6120,7 +6131,7 @@ void ServerLobby::updateGnuElimination() } else { - for (int i = 0; i < m_gnu_participants.size(); i++) + for (unsigned i = 0; i < m_gnu_participants.size(); i++) { order.emplace_back(INF, m_gnu_participants[i]); } From 129d195e1caa7a2645ad8c85ae6149c4dfea30d7 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 24 Mar 2020 15:29:32 +0300 Subject: [PATCH 062/830] Add a note for a player entering a server with gnu elimination --- src/network/protocols/server_lobby.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index a8cc98a5d8d..3c94522368b 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4017,6 +4017,20 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, } ); #endif + if (m_gnu_elimination) + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + std::string gnu_warning = StringUtils::insertValues( + "Gnu Elimination is played right now on this server, " + "you will be forced to use kart %d until it ends. " + "Use /standings to see the results.", + m_gnu_kart); + chat->encodeString16(StringUtils::utf8ToWide(gnu_warning)); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + } } // handleUnencryptedConnection //----------------------------------------------------------------------------- From 1bf92cde4c1dd312b412ec09a929b4b31c469bd0 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 28 Mar 2020 01:34:02 +0300 Subject: [PATCH 063/830] Reset server to initial mode/difficulty when it's empty and is in normal state --- src/network/protocols/server_lobby.cpp | 35 ++++++++++++++++++++------ src/network/protocols/server_lobby.hpp | 1 + 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3c94522368b..e994f8496ac 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3326,6 +3326,11 @@ void ServerLobby::clientDisconnected(Event* event) Log::info("ServerLobby", "%s disconnected", name.c_str()); } + unsigned players_number; + STKHost::get()->updatePlayers(NULL, NULL, &players_number); + if (players_number == 0) + resetToDefaultSettings(); + // Don't show waiting peer disconnect message to in game player STKHost::get()->sendPacketToAllPeersWith([waiting_peer_disconnected] (STKPeer* p) @@ -5148,18 +5153,27 @@ void ServerLobby::handleServerConfiguration(Event* event) Log::warn("ServerLobby", "server-configurable is not enabled."); return; } - if (event->getPeerSP() != m_server_owner.lock()) + if (event != NULL && event->getPeerSP() != m_server_owner.lock()) { Log::warn("ServerLobby", "Client %d is not authorised to config server.", event->getPeer()->getHostId()); return; } - NetworkString& data = event->data(); - int new_difficulty = data.getUInt8(); - int new_game_mode = data.getUInt8(); - if (m_available_difficulties.count(new_difficulty) == 0 || - m_available_modes.count(new_game_mode) == 0) + int new_difficulty = ServerConfig::m_server_difficulty; + int new_game_mode = ServerConfig::m_server_mode; + bool new_soccer_goal_target = ServerConfig::m_soccer_goal_target; + if (event != NULL) + { + NetworkString& data = event->data(); + new_difficulty = data.getUInt8(); + new_game_mode = data.getUInt8(); + new_soccer_goal_target = data.getUInt8() == 1; + } + // Actually event == NULL implies no errors... + if (event != NULL && + (m_available_difficulties.count(new_difficulty) == 0 || + m_available_modes.count(new_game_mode) == 0)) { Log::error("ServerLobby", "Mode %d and/or difficulty %d are not permitted."); auto peer = event->getPeerSP(); @@ -5172,7 +5186,6 @@ void ServerLobby::handleServerConfiguration(Event* event) delete chat; return; } - bool new_soccer_goal_target = data.getUInt8() == 1; auto modes = ServerConfig::getLocalGameMode(new_game_mode); if (modes.second == RaceManager::MAJOR_MODE_GRAND_PRIX) { @@ -6309,4 +6322,10 @@ void ServerLobby::initAvailableModes() } } } // initAvailableModes -//----------------------------------------------------------------------------- \ No newline at end of file +//----------------------------------------------------------------------------- +void ServerLobby::resetToDefaultSettings() +{ + handleServerConfiguration(NULL); + // m_gnu_elimination = false; +} // resetToDefaultSettings +//----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index fc6d3fb3a47..335fbfbb1ab 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -423,6 +423,7 @@ class ServerLobby : public LobbyProtocol uint32_t getServerIdOnline() const { return m_server_id_online; } void setClientServerHostId(uint32_t id) { m_client_server_host_id = id; } void initAvailableModes(); + void resetToDefaultSettings(); }; // class ServerLobby #endif // SERVER_LOBBY_HPP From 3080bfa86a73722ffa2e6792cfe764485a684db2 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 28 Mar 2020 02:16:03 +0300 Subject: [PATCH 064/830] Avoid gnu elimination with non-racing modes --- src/network/protocols/server_lobby.cpp | 28 ++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index e994f8496ac..baf2c280728 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -5256,6 +5256,22 @@ void ServerLobby::handleServerConfiguration(Event* event) sendMessageToPeers(server_info); delete server_info; updatePlayerList(); + + if (m_gnu_elimination && + RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_NORMAL_RACE && + RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) + { + m_gnu_elimination = false; + m_gnu_remained = 0; + m_gnu_participants.clear(); + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16( + L"Gnu Elimination is disabled because of non-racing mode"); + sendMessageToPeers(chat); + delete chat; + } } // handleServerConfiguration //----------------------------------------------------------------------------- @@ -5911,9 +5927,17 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; } - else if (false/* one player */) + else if ( + RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_NORMAL_RACE && + RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) { - + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16( + L"Gnu Elimination is available only with racing modes"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; } else { From eef5bf81d73fb0074f20af5e08ee1164c3ce0d0c Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 28 Mar 2020 04:31:55 +0300 Subject: [PATCH 065/830] Made something to make only host play, no success --- src/network/protocols/server_lobby.cpp | 10 +++++++++- src/network/server_config.hpp | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index baf2c280728..2f3184e3c1c 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2572,6 +2572,9 @@ void ServerLobby::startSelection(const Event *event) auto peers = STKHost::get()->getPeers(); for (auto peer : peers) { + if (ServerConfig::m_only_host_riding && m_server_owner.lock() != peer) { + continue; + } if (!peer->isValidated() || peer->isWaitingForGame()) continue; peer->eraseServerKarts(m_available_kts.first, karts_erase); @@ -2733,7 +2736,12 @@ void ServerLobby::startSelection(const Event *event) ns->encodeString(track); } - if (!m_gnu_elimination || m_gnu_remained < 0) + if (ServerConfig::m_only_host_riding) { + auto owner = m_server_owner.lock(); + owner->sendPacket(ns, true/*reliable*/); + delete ns; + } + else if (!m_gnu_elimination || m_gnu_remained < 0) { sendMessageToPeers(ns, /*reliable*/true); delete ns; diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 74b9e813524..40bc7614529 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -518,6 +518,11 @@ namespace ServerConfig "A string given to a peer if it has incompatible data, so " "that it can know why it cannot enter, empty to disable.")); + SERVER_CFG_PREFIX BoolServerConfigParam m_only_host_riding + SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "only-host-riding", + "A temporary feature to make others only spectate. Not ideal. " + "Maybe not even working.")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; From b53f06958337b40e5ead1607802898f321f3a73a Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 5 Apr 2020 02:08:24 +0300 Subject: [PATCH 066/830] Add team chat for CTF/soccer --- src/network/protocols/server_lobby.cpp | 37 ++++++++++++++++++++++---- src/network/protocols/server_lobby.hpp | 2 ++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 2f3184e3c1c..3c80c92adf6 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -860,12 +860,21 @@ void ServerLobby::handleChat(Event* event) const bool game_started = m_state.load() != WAITING_FOR_START_GAME; STKPeer* sender = event->getPeer(); auto can_receive = m_message_receivers[sender]; + bool team_speak = m_team_speakers.find(sender) != m_team_speakers.end(); + team_speak &= ( + RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER || + RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG + ); + std::set teams; + for (auto& profile: sender->getPlayerProfiles()) + teams.insert(profile->getTeam()); + STKHost::get()->sendPacketToAllPeersWith( - [game_started, sender_in_game, can_receive, sender](STKPeer* p) + [game_started, sender_in_game, can_receive, + sender, team_speak, teams](STKPeer* p) { - if (sender == p) { + if (sender == p) return true; - } if (game_started) { if (p->isWaitingForGame() && !sender_in_game) @@ -873,9 +882,15 @@ void ServerLobby::handleChat(Event* event) if (!p->isWaitingForGame() && sender_in_game) return false; } - if (can_receive.empty()) { - return true; + if (team_speak) + { + for (auto& profile: p->getPlayerProfiles()) + if (teams.count(profile->getTeam()) > 0) + return true; + return false; } + if (can_receive.empty()) + return true; for (auto& profile : p->getPlayerProfiles()) { if (can_receive.find(profile->getName()) != @@ -6036,6 +6051,17 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; } + else if (argv[0] == "teamchat") + { + std::set m_team_speakers; + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + m_team_speakers.insert(peer.get()); + chat->encodeString16(L"Your messages are now addressed to team only"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + } else if (argv[0] == "to") { if (argv.size() == 1) { @@ -6065,6 +6091,7 @@ void ServerLobby::handleServerCommand(Event* event, chat->addUInt8(LE_CHAT); chat->setSynchronous(true); m_message_receivers[peer.get()].clear(); + m_team_speakers.erase(peer.get()); chat->encodeString16(L"Your messages are now public"); peer->sendPacket(chat, true/*reliable*/); delete chat; diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 335fbfbb1ab..a288598b968 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -256,6 +256,8 @@ class ServerLobby : public LobbyProtocol std::map> m_message_receivers; + std::set m_team_speakers; + bool m_gnu_elimination; int m_gnu_remained; From 3669b03ffa22c6334390d3c8db2d15450482beb9 Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 6 Apr 2020 04:25:16 +0300 Subject: [PATCH 067/830] Revert 20bcd1a as it seems to break powerup compatibility --- src/modes/soccer_world.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp index d6d19cab3ea..f7bfabb2899 100644 --- a/src/modes/soccer_world.cpp +++ b/src/modes/soccer_world.cpp @@ -442,8 +442,8 @@ void SoccerWorld::update(int ticks) // We only use kart position for spliting team in race gui drawing beginSetKartPositions(); int pos = 1; - if (!Track::getCurrentTrack()->getMinimapInvert()) - std::swap(red_id, blue_id); + // if (!Track::getCurrentTrack()->getMinimapInvert()) + // std::swap(red_id, blue_id); for (int id : red_id) setKartPosition(id, pos++); for (int id : blue_id) From 49351782a9f4a3a5f186844550e36859287a9c53 Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 6 Apr 2020 16:09:42 +0300 Subject: [PATCH 068/830] Fix bug in /teamchat --- src/network/protocols/server_lobby.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 413a76573c3..593181317af 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6053,12 +6053,11 @@ void ServerLobby::handleServerCommand(Event* event, } else if (argv[0] == "teamchat") { - std::set m_team_speakers; NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); m_team_speakers.insert(peer.get()); - chat->encodeString16(L"Your messages are now addressed to team only"); + chat->encodeString16(L"Your messages are now addressed to team only"); peer->sendPacket(chat, true/*reliable*/); delete chat; } From e5e1252d53bce4e61c3359f63ae62a2045ac7243 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 7 Apr 2020 14:52:42 +0300 Subject: [PATCH 069/830] Create FORK_CHANGES.md --- FORK_CHANGES.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 FORK_CHANGES.md diff --git a/FORK_CHANGES.md b/FORK_CHANGES.md new file mode 100644 index 00000000000..c837dedcf79 --- /dev/null +++ b/FORK_CHANGES.md @@ -0,0 +1,31 @@ +# This fork's changes compared to main STK + +This is only a short description. + +1. Allowed partly configurable servers (the main game allows either no configuration or full configuration, while this version allows for example enforcing SuperTux difficulty and allowing racing modes only). + +2. Resetting server to initial mode and difficulty after all players are gone (doesn't work if players quit mid-race for now). + +3. `max-moveable-objects > 24` for bowling addon + +4. `/help` and `/commands` + +5. Gnu elimination mode: `/gnu`, `/nognu`, `/standings` + +6. Allowed forcing players to have certain tracks to enter the server; limiting played tracks to make very custom servers or forbid tracks that crash online + +7. Allowed forcing players to have certain number of addons (differentiated by its type) to make addons servers + +8. Private chat (`/to`, `/public`) and soccer / ctf `/teamchat` + +9. Fixed lap count servers + +10. Non-racing servers + +11. Official tracks can be not required + +12. Allowed storing race results + +13. Allowed `/records` queries to server + +Of course, there are some further plans ~~which will be announced when they are implemented or when I realize they cannot~~. From 25031160848015a2ad61afac58e60a01b3259981 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 8 Apr 2020 05:13:44 +0300 Subject: [PATCH 070/830] Add /tell-ing to server owner --- src/network/protocols/server_lobby.cpp | 110 +++++++++++++++++++++++++ src/network/protocols/server_lobby.hpp | 1 + 2 files changed, 111 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 593181317af..b022c36d122 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6028,6 +6028,30 @@ void ServerLobby::handleServerCommand(Event* event, delete chat; } } + else if (argv[0] == "tell") + { + if (argv.size() == 1) + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(L"Tell something non-empty"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + return; + } + else + { + std::string ans; + for (unsigned i = 1; i < argv.size(); ++i) + { + if (i > 1) + ans.push_back(' '); + ans += argv[i]; + } + writeOwnReport(peer.get(), ans); + } + } else if (argv[0] == "standings") { // Log::info("ServerLobby", "Gnu Elimination: total %d participants", (int)m_gnu_participants.size()); @@ -6387,3 +6411,89 @@ void ServerLobby::resetToDefaultSettings() // m_gnu_elimination = false; } // resetToDefaultSettings //----------------------------------------------------------------------------- +void ServerLobby::writeOwnReport(STKPeer* reporter, const std::string& info) +{ +#ifdef ENABLE_SQLITE3 + if (!m_db || !m_player_reports_table_exists) + return; + if (!reporter->hasPlayerProfiles()) + return; + auto reporter_npp = reporter->getPlayerProfiles()[0]; + + if (info.empty()) + return; + + auto reporting_peer = reporter; + auto reporting_npp = reporting_peer->getPlayerProfiles()[0]; + + std::string query; + if (ServerConfig::m_ipv6_connection) + { + query = StringUtils::insertValues( + "INSERT INTO %s " + "(server_uid, reporter_ip, reporter_ipv6, reporter_online_id, reporter_username, " + "info, reporting_ip, reporting_ipv6, reporting_online_id, reporting_username) " + "VALUES (?, %u, \"%s\", %u, ?, ?, %u, \"%s\", %u, ?);", + ServerConfig::m_player_reports_table.c_str(), + !reporter->getAddress().isIPv6() ? reporter->getAddress().getIP() : 0, + reporter->getAddress().isIPv6() ? reporter->getAddress().toString(false) : "", + reporter_npp->getOnlineId(), + !reporting_peer->getAddress().isIPv6() ? reporting_peer->getAddress().getIP() : 0, + reporting_peer->getAddress().isIPv6() ? reporting_peer->getAddress().toString(false) : "", + reporting_npp->getOnlineId()); + } + else + { + query = StringUtils::insertValues( + "INSERT INTO %s " + "(server_uid, reporter_ip, reporter_online_id, reporter_username, " + "info, reporting_ip, reporting_online_id, reporting_username) " + "VALUES (?, %u, %u, ?, ?, %u, %u, ?);", + ServerConfig::m_player_reports_table.c_str(), + reporter->getAddress().getIP(), reporter_npp->getOnlineId(), + reporting_peer->getAddress().getIP(), reporting_npp->getOnlineId()); + } + bool written = easySQLQuery(query, + [reporter_npp, reporting_npp, info](sqlite3_stmt* stmt) + { + // SQLITE_TRANSIENT to copy string + if (sqlite3_bind_text(stmt, 1, ServerConfig::m_server_uid.c_str(), + -1, SQLITE_TRANSIENT) != SQLITE_OK) + { + Log::error("easySQLQuery", "Failed to bind %s.", + ServerConfig::m_server_uid.c_str()); + } + if (sqlite3_bind_text(stmt, 2, + StringUtils::wideToUtf8(reporter_npp->getName()).c_str(), + -1, SQLITE_TRANSIENT) != SQLITE_OK) + { + Log::error("easySQLQuery", "Failed to bind %s.", + StringUtils::wideToUtf8(reporter_npp->getName()).c_str()); + } + if (sqlite3_bind_text(stmt, 3, + info.c_str(), + -1, SQLITE_TRANSIENT) != SQLITE_OK) + { + Log::error("easySQLQuery", "Failed to bind %s.", + info.c_str()); + } + if (sqlite3_bind_text(stmt, 4, + StringUtils::wideToUtf8(reporting_npp->getName()).c_str(), + -1, SQLITE_TRANSIENT) != SQLITE_OK) + { + Log::error("easySQLQuery", "Failed to bind %s.", + StringUtils::wideToUtf8(reporting_npp->getName()).c_str()); + } + }); + if (written) + { + NetworkString* success = getNetworkString(); + success->setSynchronous(true); + success->addUInt8(LE_REPORT_PLAYER).addUInt8(1) + .encodeString(ServerConfig::m_server_name); + reporter->sendPacket(success, true/*reliable*/); + delete success; + } +#endif +} // writeOwnReport +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 52cd10daef1..2dbb8243c98 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -430,6 +430,7 @@ class ServerLobby : public LobbyProtocol void setClientServerHostId(uint32_t id) { m_client_server_host_id = id; } void initAvailableModes(); void resetToDefaultSettings(); + void writeOwnReport(STKPeer* reporter, const std::string& info); }; // class ServerLobby #endif // SERVER_LOBBY_HPP From 1de4ea8fc43b3ae9e63f11916a22241d92b45e14 Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 27 Apr 2020 14:07:42 +0300 Subject: [PATCH 071/830] Add possibility of tracking kicks --- src/network/protocols/server_lobby.cpp | 46 ++++++++++++++++++++------ src/network/protocols/server_lobby.hpp | 2 +- src/network/server_config.hpp | 5 +++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index b022c36d122..3e2a890c9db 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -176,7 +176,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() ((std::string) ServerConfig::m_help); m_available_commands = "help commands music kick to public " - "gnu nognu standings record " + "teamchat gnu nognu standings record tell " "installaddon uninstalladdon liststkaddon listlocaladdon " "listserveraddon playerhasaddon playeraddonscore serverhasaddon"; @@ -944,7 +944,23 @@ void ServerLobby::kickHost(Event* event) std::shared_ptr peer = STKHost::get()->findPeerByHostId(host_id); // Ignore kicking ai peer if ai handling is on if (peer && (!ServerConfig::m_ai_handling || !peer->isAIPeer())) + { + if (!peer->hasPlayerProfiles()) + { + Log::info("ServerLobby", "Crown player kicks a player"); + } + else + { + auto npp = peer->getPlayerProfiles()[0]; + std::string player_name = StringUtils::wideToUtf8(npp->getName()); + Log::info("ServerLobby", "Crown player kicks %s", player_name.c_str()); + } peer->kick(); + if (ServerConfig::m_track_kicks) { + std::string auto_report = "[ Auto report caused by kick ]"; + writeOwnReport(peer.get(), event->getPeerSP().get(), auto_report); + } + } } // kickHost //----------------------------------------------------------------------------- @@ -5831,7 +5847,12 @@ void ServerLobby::handleServerCommand(Event* event, } else { + Log::info("ServerLobby", "Crown player kicks %s", player_name.c_str()); player_peer->kick(); + if (ServerConfig::m_track_kicks) { + std::string auto_report = "[ Auto report caused by kick ]"; + writeOwnReport(player_peer.get(), peer.get(), auto_report); + } } } else if (StringUtils::startsWith(cmd, "playeraddonscore")) @@ -6049,7 +6070,7 @@ void ServerLobby::handleServerCommand(Event* event, ans.push_back(' '); ans += argv[i]; } - writeOwnReport(peer.get(), ans); + writeOwnReport(peer.get(), peer.get(), ans); } } else if (argv[0] == "standings") @@ -6411,7 +6432,7 @@ void ServerLobby::resetToDefaultSettings() // m_gnu_elimination = false; } // resetToDefaultSettings //----------------------------------------------------------------------------- -void ServerLobby::writeOwnReport(STKPeer* reporter, const std::string& info) +void ServerLobby::writeOwnReport(STKPeer* reporter, STKPeer* reporting, const std::string& info) { #ifdef ENABLE_SQLITE3 if (!m_db || !m_player_reports_table_exists) @@ -6423,8 +6444,9 @@ void ServerLobby::writeOwnReport(STKPeer* reporter, const std::string& info) if (info.empty()) return; - auto reporting_peer = reporter; - auto reporting_npp = reporting_peer->getPlayerProfiles()[0]; + if (!reporting->hasPlayerProfiles()) + return; + auto reporting_npp = reporting->getPlayerProfiles()[0]; std::string query; if (ServerConfig::m_ipv6_connection) @@ -6438,8 +6460,8 @@ void ServerLobby::writeOwnReport(STKPeer* reporter, const std::string& info) !reporter->getAddress().isIPv6() ? reporter->getAddress().getIP() : 0, reporter->getAddress().isIPv6() ? reporter->getAddress().toString(false) : "", reporter_npp->getOnlineId(), - !reporting_peer->getAddress().isIPv6() ? reporting_peer->getAddress().getIP() : 0, - reporting_peer->getAddress().isIPv6() ? reporting_peer->getAddress().toString(false) : "", + !reporting->getAddress().isIPv6() ? reporting->getAddress().getIP() : 0, + reporting->getAddress().isIPv6() ? reporting->getAddress().toString(false) : "", reporting_npp->getOnlineId()); } else @@ -6451,7 +6473,7 @@ void ServerLobby::writeOwnReport(STKPeer* reporter, const std::string& info) "VALUES (?, %u, %u, ?, ?, %u, %u, ?);", ServerConfig::m_player_reports_table.c_str(), reporter->getAddress().getIP(), reporter_npp->getOnlineId(), - reporting_peer->getAddress().getIP(), reporting_npp->getOnlineId()); + reporting->getAddress().getIP(), reporting_npp->getOnlineId()); } bool written = easySQLQuery(query, [reporter_npp, reporting_npp, info](sqlite3_stmt* stmt) @@ -6489,8 +6511,12 @@ void ServerLobby::writeOwnReport(STKPeer* reporter, const std::string& info) { NetworkString* success = getNetworkString(); success->setSynchronous(true); - success->addUInt8(LE_REPORT_PLAYER).addUInt8(1) - .encodeString(ServerConfig::m_server_name); + if (reporter == reporting) + success->addUInt8(LE_REPORT_PLAYER).addUInt8(1) + .encodeString(ServerConfig::m_server_name); + else + success->addUInt8(LE_REPORT_PLAYER).addUInt8(1) + .encodeString(reporting_npp->getName()); reporter->sendPacket(success, true/*reliable*/); delete success; } diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 2dbb8243c98..6edf77949ed 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -430,7 +430,7 @@ class ServerLobby : public LobbyProtocol void setClientServerHostId(uint32_t id) { m_client_server_host_id = id; } void initAvailableModes(); void resetToDefaultSettings(); - void writeOwnReport(STKPeer* reporter, const std::string& info); + void writeOwnReport(STKPeer* reporter, STKPeer* reporting, const std::string& info); }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 40bc7614529..ed8d8360b1c 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -512,6 +512,11 @@ namespace ServerConfig "in this field. So it can be the results table for this server " "or for all servers hosted on the machine.")); + SERVER_CFG_PREFIX BoolServerConfigParam m_track_kicks + SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "track-kicks", + "When true, stores the info about each forced kick in a database " + "(if it exists).")); + SERVER_CFG_PREFIX StringServerConfigParam m_incompatible_advice SERVER_CFG_DEFAULT(StringServerConfigParam("", "incompatible-advice", From ba333ae154dba1bb4b1e9e40b41956d39fc97d64 Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 1 May 2020 16:31:31 +0300 Subject: [PATCH 072/830] Add soccer tournament mode --- src/network/protocols/server_lobby.cpp | 343 ++++++++++++++++++++++--- src/network/protocols/server_lobby.hpp | 12 + src/network/server_config.cpp | 27 ++ src/network/server_config.hpp | 20 +- 4 files changed, 369 insertions(+), 33 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3e2a890c9db..fde2502c84c 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -256,6 +256,11 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_default_vote = new PeerVote(); m_player_reports_table_exists = false; initDatabase(); + + if (ServerConfig::m_soccer_tournament) { + initTournamentPlayers(); + m_tournament_game = 0; + } } // ServerLobby //----------------------------------------------------------------------------- @@ -917,16 +922,19 @@ void ServerLobby::changeTeam(Event* event) uint8_t local_id = data.getUInt8(); auto& player = event->getPeer()->getPlayerProfiles().at(local_id); auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); + if (ServerConfig::m_soccer_tournament) { + return; // message here? + } // At most 7 players on each team (for live join) if (player->getTeam() == KART_TEAM_BLUE) { - if (red_blue.first >= 7) + if (red_blue.first >= 7 && !ServerConfig::m_free_teams) return; player->setTeam(KART_TEAM_RED); } else { - if (red_blue.second >= 7) + if (red_blue.second >= 7 && !ServerConfig::m_free_teams) return; player->setTeam(KART_TEAM_BLUE); } @@ -1690,7 +1698,7 @@ void ServerLobby::asynchronousUpdate() if (ServerConfig::m_fixed_lap_count > 0) { winner_vote.m_num_laps = ServerConfig::m_fixed_lap_count; - Log::info("ServerLobby", "Enforcing %d lap race", ServerConfig::m_fixed_lap_count); + Log::info("ServerLobby", "Enforcing %d lap race", (int)ServerConfig::m_fixed_lap_count); } *m_default_vote = winner_vote; m_item_seed = (uint32_t)StkTime::getTimeSinceEpoch(); @@ -1784,6 +1792,18 @@ void ServerLobby::asynchronousUpdate() // Reset for next state usage resetPeersReady(); + + for (auto p : m_peers_ready) + { + auto peer = p.first.lock(); + if (!peer) + continue; + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + Log::info("ServerLobby", "m_peers_ready: there is a peer %s", username.c_str()); + } + + m_state = LOAD_WORLD; sendMessageToPeers(load_world_message); delete load_world_message; @@ -2547,6 +2567,7 @@ void ServerLobby::unregisterServer(bool now, std::weak_ptr sl) */ void ServerLobby::startSelection(const Event *event) { + bool need_to_update = false; if (event != NULL) { if (m_state != WAITING_FOR_START_GAME) @@ -2579,7 +2600,7 @@ void ServerLobby::startSelection(const Event *event) if (!ServerConfig::m_owner_less && ServerConfig::m_team_choosing && - RaceManager::get()->teamEnabled()) + !ServerConfig::m_soccer_tournament && RaceManager::get()->teamEnabled()) { auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); if ((red_blue.first == 0 || red_blue.second == 0) && @@ -2603,14 +2624,27 @@ void ServerLobby::startSelection(const Event *event) auto peers = STKHost::get()->getPeers(); for (auto peer : peers) { + if (!peer->isValidated() || peer->isWaitingForGame()) + continue; if (ServerConfig::m_only_host_riding && m_server_owner.lock() != peer) { continue; } - if (!peer->isValidated() || peer->isWaitingForGame()) - continue; + if (ServerConfig::m_soccer_tournament) { + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (m_tournament_red_players.count(username) == 0 && + m_tournament_blue_players.count(username) == 0) + { + peer->setWaitingForGame(true); + m_peers_ready.erase(peer); + need_to_update = true; + continue; + } + } peer->eraseServerKarts(m_available_kts.first, karts_erase); peer->eraseServerTracks(m_available_kts.second, tracks_erase); } + for (const std::string& kart_erase : karts_erase) { m_available_kts.first.erase(kart_erase); @@ -2714,21 +2748,29 @@ void ServerLobby::startSelection(const Event *event) } case RaceManager::MINOR_MODE_SOCCER: { - if (m_game_setup->isSoccerGoalTarget()) + if (ServerConfig::m_soccer_tournament) { - m_default_vote->m_num_laps = - (uint8_t)(UserConfigParams::m_num_goals); - if (m_default_vote->m_num_laps > 10) - m_default_vote->m_num_laps = (uint8_t)5; + m_default_vote->m_num_laps = 10; + m_default_vote->m_reverse = false; } else { - m_default_vote->m_num_laps = - (uint8_t)(UserConfigParams::m_soccer_time_limit); - if (m_default_vote->m_num_laps > 15) - m_default_vote->m_num_laps = (uint8_t)7; + if (m_game_setup->isSoccerGoalTarget()) + { + m_default_vote->m_num_laps = + (uint8_t)(UserConfigParams::m_num_goals); + if (m_default_vote->m_num_laps > 10) + m_default_vote->m_num_laps = (uint8_t)5; + } + else + { + m_default_vote->m_num_laps = + (uint8_t)(UserConfigParams::m_soccer_time_limit); + if (m_default_vote->m_num_laps > 15) + m_default_vote->m_num_laps = (uint8_t)7; + } + m_default_vote->m_reverse = rg.get(2) == 0; } - m_default_vote->m_reverse = rg.get(2) == 0; break; } default: @@ -2772,12 +2814,7 @@ void ServerLobby::startSelection(const Event *event) owner->sendPacket(ns, true/*reliable*/); delete ns; } - else if (!m_gnu_elimination || m_gnu_remained < 0) - { - sendMessageToPeers(ns, /*reliable*/true); - delete ns; - } - else + else if (m_gnu_elimination && m_gnu_remained >= 0) { auto remaining_begin = m_gnu_participants.begin(); auto remaining_end = remaining_begin + m_gnu_remained; @@ -2838,8 +2875,60 @@ void ServerLobby::startSelection(const Event *event) return true; }, ns, /*reliable*/true); } + else if (ServerConfig::m_soccer_tournament) + { + delete ns; + std::set soccer_t; + for (auto& s: all_t) + { + if ((m_tournament_game == 2) ^ (s == "icy_soccer_field")) + soccer_t.insert(s); + } + ns = getNetworkString(1); + ns->setSynchronous(true); + ns->addUInt8(LE_START_SELECTION) + .addFloat(ServerConfig::m_voting_timeout) + .addUInt8(m_game_setup->isGrandPrixStarted() ? 1 : 0) + .addUInt8(ServerConfig::m_auto_game_time_ratio > 0.0f ? 1 : 0) + .addUInt8(ServerConfig::m_track_voting ? 1 : 0); + + + ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)soccer_t.size()); + for (const std::string& kart : all_k) + { + ns->encodeString(kart); + } + for (const std::string& track : soccer_t) + { + ns->encodeString(track); + } + + + std::set all_players; + for (const std::string& s: m_tournament_red_players) { + all_players.insert(s); + } + for (const std::string& s: m_tournament_blue_players) { + all_players.insert(s); + } + STKHost::get()->sendPacketToAllPeersWith( + [all_players](STKPeer* p) -> bool + { + std::string username = StringUtils::wideToUtf8( + p->getPlayerProfiles()[0]->getName()); + return all_players.count(username) > 0; + }, ns, /*reliable*/true); + delete ns; + } + else + { + sendMessageToPeers(ns, /*reliable*/true); + delete ns; + } m_state = SELECTING; + if (need_to_update) + updatePlayerList(); if (!allowJoinedPlayersWaiting()) { // Drop all pending players and keys if doesn't allow joinning-waiting @@ -3860,12 +3949,14 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, #endif auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); + std::string utf8_online_name = StringUtils::wideToUtf8(online_name); for (unsigned i = 0; i < player_count; i++) { core::stringw name; data.decodeStringW(&name); if (name.empty()) name = L"unnamed"; + std::string utf8_name = StringUtils::wideToUtf8(name); float default_kart_color = data.getFloat(); HandicapLevel handicap = (HandicapLevel)data.getUInt8(); auto player = std::make_shared @@ -3874,7 +3965,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, peer->getHostId(), default_kart_color, i == 0 ? online_id : 0, handicap, (uint8_t)i, KART_TEAM_NONE, country_code); - if (ServerConfig::m_team_choosing) + if (ServerConfig::m_team_choosing && !ServerConfig::m_soccer_tournament) { KartTeam cur_team = KART_TEAM_NONE; if (red_blue.first > red_blue.second) @@ -3889,6 +3980,22 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, } player->setTeam(cur_team); } + Log::info("ServerLobby", "Validated player utf8_name: %s, " + "online_name: %s", utf8_name.c_str(), + utf8_online_name.c_str()); + if (ServerConfig::m_soccer_tournament) { + if (m_tournament_red_players.count(utf8_online_name)) + player->setTeam(KART_TEAM_RED); + else if (m_tournament_blue_players.count(utf8_online_name)) + player->setTeam(KART_TEAM_BLUE); + if (m_tournament_game & 2) + { + if (player->getTeam() == KART_TEAM_BLUE) + player->setTeam(KART_TEAM_RED); + else if (player->getTeam() == KART_TEAM_RED) + player->setTeam(KART_TEAM_BLUE); + } + } peer->addPlayer(player); } @@ -4279,7 +4386,10 @@ void ServerLobby::handlePlayerVote(Event* event) } // Remove / adjust any invalid settings - if (RaceManager::get()->modeHasLaps()) + if (ServerConfig::m_soccer_tournament) { + vote.m_reverse = false; + } + else if (RaceManager::get()->modeHasLaps()) { if (ServerConfig::m_auto_game_time_ratio > 0.0f) { @@ -4326,6 +4436,9 @@ void ServerLobby::handlePlayerVote(Event* event) vote.m_num_laps = 0; vote.m_reverse = false; } + if (ServerConfig::m_fixed_lap_count > 0) { + vote.m_num_laps = ServerConfig::m_fixed_lap_count; + } // Store vote: vote.m_player_name = event->getPeer()->getPlayerProfiles()[0]->getName(); @@ -5588,7 +5701,7 @@ void ServerLobby::clientInGameWantsToBackLobby(Event* event) server_info->setSynchronous(true); server_info->addUInt8(LE_SERVER_INFO); m_game_setup->addServerInfo(server_info); - peer->sendPacket(server_info, /*reliable*/true); + peer->sendPacket(server_info, /*relsiable*/true); delete server_info; } // clientInGameWantsToBackLobby @@ -6131,14 +6244,10 @@ void ServerLobby::handleServerCommand(Event* event, } else if (argv[0] == "public") { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); m_message_receivers[peer.get()].clear(); m_team_speakers.erase(peer.get()); - chat->encodeString16(L"Your messages are now public"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; + std::string s = "Your messages are now public"; + sendStringToPeer(s, peer); } else if (argv[0] == "record") { @@ -6226,6 +6335,121 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; } + else if (ServerConfig::m_soccer_tournament) + { + std::string peer_username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (m_tournament_referees.count(peer_username) == 0) { + std::string msg = "You are not a referee"; + sendStringToPeer(msg, peer); + return; + } + if (argv[0] == "game") + { + int old_game = m_tournament_game; + if (argv.size() < 2) { + ++m_tournament_game; + } else { + if (!StringUtils::parseString(argv[1], &m_tournament_game)) + { + std::string msg = "Please specify a correct number. " + "Format: /game 2"; + sendStringToPeer(msg, peer); + return; + } + } + if ((m_tournament_game ^ old_game) & 2) + changeColors(); + std::string msg = StringUtils::insertValues( + "Ready to start game %d", m_tournament_game); + sendStringToAllPeers(msg); + } + else if (argv[0] == "role") + { + if (argv.size() < 3) + { + std::string msg = "Format: /role (R|B|J|S) username"; + sendStringToPeer(msg, peer); + return; + } + std::string role = argv[1]; + std::string username = argv[2]; + if (role.length() != 1) + std::swap(role, username); + if (role.length() != 1) + { + std::string msg = "Please specify one-letter role (R/B/J/S) and player"; + sendStringToPeer(msg, peer); + return; + } + m_tournament_red_players.erase(username); + m_tournament_blue_players.erase(username); + m_tournament_referees.erase(username); + std::string role_changed = "The referee has updated your role - you are now %s"; + std::shared_ptr player_peer = STKHost::get()->findPeerByName( + StringUtils::utf8ToWide(username)); + switch (role[0]) + { + case 'R': + case 'r': + { + m_tournament_red_players.insert(username); + if (player_peer) + { + role_changed = StringUtils::insertValues(role_changed, "first team player"); + if (m_tournament_game & 2) + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_BLUE); + else + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_RED); + sendStringToPeer(role_changed, player_peer); + } + break; + } + case 'B': + case 'b': + { + m_tournament_blue_players.insert(username); + if (player_peer) + { + role_changed = StringUtils::insertValues(role_changed, "second team player"); + if (m_tournament_game & 2) + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_RED); + else + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_BLUE); + sendStringToPeer(role_changed, player_peer); + } + break; + } + case 'J': + case 'j': + { + m_tournament_referees.insert(username); + if (player_peer) + { + role_changed = StringUtils::insertValues(role_changed, "referee"); + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); + sendStringToPeer(role_changed, player_peer); + } + break; + } + case 'S': + case 's': + { + if (player_peer) + { + role_changed = StringUtils::insertValues(role_changed, "spectator"); + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); + sendStringToPeer(role_changed, player_peer); + } + break; + } + } + std::string msg = StringUtils::insertValues( + "Successfully changed role to %s for %s", role, username); + sendStringToPeer(msg, peer); + updatePlayerList(); + } + } else { NetworkString* chat = getNetworkString(); @@ -6513,7 +6737,7 @@ void ServerLobby::writeOwnReport(STKPeer* reporter, STKPeer* reporting, const st success->setSynchronous(true); if (reporter == reporting) success->addUInt8(LE_REPORT_PLAYER).addUInt8(1) - .encodeString(ServerConfig::m_server_name); + .encodeString(m_game_setup->getServerNameUtf8()); else success->addUInt8(LE_REPORT_PLAYER).addUInt8(1) .encodeString(reporting_npp->getName()); @@ -6522,4 +6746,59 @@ void ServerLobby::writeOwnReport(STKPeer* reporter, STKPeer* reporting, const st } #endif } // writeOwnReport +//----------------------------------------------------------------------------- +void ServerLobby::initTournamentPlayers() +{ + std::vector tokens = StringUtils::split( + ServerConfig::m_soccer_tournament_players, ' '); + std::string type = ""; + for (std::string& s: tokens) + { + if (s.length() == 1) + type = s; + else if (type == "R") + m_tournament_red_players.insert(s); + else if (type == "B") + m_tournament_blue_players.insert(s); + else if (type == "J") + m_tournament_referees.insert(s); + } +} // initTournamentPlayers +//----------------------------------------------------------------------------- +void ServerLobby::changeColors() +{ + auto peers = STKHost::get()->getPeers(); + for (auto peer : peers) + { + if (peer->hasPlayerProfiles()) + { + auto pp = peer->getPlayerProfiles()[0]; + if (pp->getTeam() == KART_TEAM_RED) + pp->setTeam(KART_TEAM_BLUE); + else if (pp->getTeam() == KART_TEAM_BLUE) + pp->setTeam(KART_TEAM_RED); + } + } + updatePlayerList(); +} // changeColors +//----------------------------------------------------------------------------- +void ServerLobby::sendStringToPeer(std::string& s, std::shared_ptr& peer) const +{ + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(StringUtils::utf8ToWide(s)); + peer->sendPacket(chat, true/*reliable*/); + delete chat; +} // sendStringToPeer +//----------------------------------------------------------------------------- +void ServerLobby::sendStringToAllPeers(std::string& s) +{ + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(StringUtils::utf8ToWide(s)); + sendMessageToPeers(chat, true/*reliable*/); + delete chat; +} // sendStringToAllPeers //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 6edf77949ed..9655dfddf1a 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -271,6 +271,14 @@ class ServerLobby : public LobbyProtocol std::set m_available_modes; + std::set m_tournament_red_players; + + std::set m_tournament_blue_players; + + std::set m_tournament_referees; + + int m_tournament_game; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); @@ -391,6 +399,10 @@ class ServerLobby : public LobbyProtocol bool supportsAI(); void updateGnuElimination(); void updateAddons(); + void initTournamentPlayers(); + void changeColors(); + void sendStringToPeer(std::string& s, std::shared_ptr& peer) const; + void sendStringToAllPeers(std::string& s); public: ServerLobby(); virtual ~ServerLobby(); diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 7ccc48d9baa..418df468182 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -349,6 +349,33 @@ void loadServerLobbyFromConfig() #endif } + if (m_soccer_tournament) { + m_server_mode = 6; + m_server_difficulty = 3; + m_fixed_lap_count = 10; + if (m_server_max_players < 7) { + m_server_max_players = 7; + } + m_voting_timeout = 15; + m_soccer_goal_target = false; + m_official_tracks_needed = false; + m_owner_less = false; + m_official_karts_threshold = 1.0f; + m_official_tracks_threshold = 0.0f; + m_addon_karts_threshold = 0; + m_addon_tracks_threshold = 0; + m_addon_arenas_threshold = 0; + m_addon_soccers_threshold = 0; // maybe 1 ? + m_must_have_tracks_string = "icy_soccer_field soccer_field lasdunassoccer"; + m_team_choosing = true; + m_ranked = false; + m_server_configurable = false; + m_live_players = true; + m_sleeping_server = false; + m_free_teams = true; + m_validating_player = true; + } + if (m_ranked) { m_validating_player = true; diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index ed8d8360b1c..6a6576cbd47 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -515,7 +515,25 @@ namespace ServerConfig SERVER_CFG_PREFIX BoolServerConfigParam m_track_kicks SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "track-kicks", "When true, stores the info about each forced kick in a database " - "(if it exists).")); + "(if it exists).")); + + SERVER_CFG_PREFIX BoolServerConfigParam m_free_teams + SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "free-teams", + "When true, the server allows changing teams freely.")); + + SERVER_CFG_PREFIX BoolServerConfigParam m_soccer_tournament + SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "soccer-tournament", + "When true, the server has the functionality to host soccer " + "tournaments. Rules may change so better ask STK players about " + "the actual rules.")); + + SERVER_CFG_PREFIX StringServerConfigParam m_soccer_tournament_players + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "soccer-tournament-players", + "List of players and judges. Use the format \"R red red " + "red B blue blue blue J judge judge\" where " + "the category is preceded by its letter. Categories can " + "be empty or absent and can go in any order.")); SERVER_CFG_PREFIX StringServerConfigParam m_incompatible_advice SERVER_CFG_DEFAULT(StringServerConfigParam("", From a57852a40bb18998bf3b311903d149349e431843 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 2 May 2020 22:18:33 +0300 Subject: [PATCH 073/830] Fix random track selection in soccer tournament, make results precise --- src/network/protocols/server_lobby.cpp | 77 ++++++++++++++++---------- 1 file changed, 49 insertions(+), 28 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index fde2502c84c..d4ca4136e67 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -61,6 +61,8 @@ #include #include #include +#include +#include #include // We use max priority for all server requests to avoid downloading of addons @@ -2644,6 +2646,10 @@ void ServerLobby::startSelection(const Event *event) peer->eraseServerKarts(m_available_kts.first, karts_erase); peer->eraseServerTracks(m_available_kts.second, tracks_erase); } + if (ServerConfig::m_soccer_tournament && m_tournament_game % 2 == 0) + { + tracks_erase.insert("icy_soccer_field"); + } for (const std::string& kart_erase : karts_erase) { @@ -2653,6 +2659,19 @@ void ServerLobby::startSelection(const Event *event) { m_available_kts.second.erase(track_erase); } + if (ServerConfig::m_soccer_tournament && m_tournament_game % 2 == 1) + { + if (m_available_kts.second.count("icy_soccer_field")) + { + m_available_kts.second.clear(); + m_available_kts.second.insert("icy_soccer_field"); + } + else + { + m_available_kts.second.clear(); + } + } + unsigned max_player = 0; STKHost::get()->updatePlayers(&max_player); @@ -2714,7 +2733,7 @@ void ServerLobby::startSelection(const Event *event) RandomGenerator rg; const auto& all_k = m_available_kts.first; const auto& all_t = m_available_kts.second; - if (!official_tracks.empty()) { + if (!official_tracks.empty() && !ServerConfig::m_soccer_tournament) { it = official_tracks.begin(); std::advance(it, rg.get((int)official_tracks.size())); } else { @@ -2877,31 +2896,31 @@ void ServerLobby::startSelection(const Event *event) } else if (ServerConfig::m_soccer_tournament) { - delete ns; - std::set soccer_t; - for (auto& s: all_t) - { - if ((m_tournament_game == 2) ^ (s == "icy_soccer_field")) - soccer_t.insert(s); - } - ns = getNetworkString(1); - ns->setSynchronous(true); - ns->addUInt8(LE_START_SELECTION) - .addFloat(ServerConfig::m_voting_timeout) - .addUInt8(m_game_setup->isGrandPrixStarted() ? 1 : 0) - .addUInt8(ServerConfig::m_auto_game_time_ratio > 0.0f ? 1 : 0) - .addUInt8(ServerConfig::m_track_voting ? 1 : 0); - - - ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)soccer_t.size()); - for (const std::string& kart : all_k) - { - ns->encodeString(kart); - } - for (const std::string& track : soccer_t) - { - ns->encodeString(track); - } + // delete ns; + // std::set soccer_t; + // for (auto& s: all_t) + // { + // if ((m_tournament_game == 2) ^ (s == "icy_soccer_field")) + // soccer_t.insert(s); + // } + // ns = getNetworkString(1); + // ns->setSynchronous(true); + // ns->addUInt8(LE_START_SELECTION) + // .addFloat(ServerConfig::m_voting_timeout) + // .addUInt8(m_game_setup->isGrandPrixStarted() ? 1 : 0) + // .addUInt8(ServerConfig::m_auto_game_time_ratio > 0.0f ? 1 : 0) + // .addUInt8(ServerConfig::m_track_voting ? 1 : 0); + + + // ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)soccer_t.size()); + // for (const std::string& kart : all_k) + // { + // ns->encodeString(kart); + // } + // for (const std::string& track : soccer_t) + // { + // ns->encodeString(track); + // } std::set all_players; @@ -6578,6 +6597,8 @@ void ServerLobby::storeResults() std::string username = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(i).getPlayerName()); double elapsed_time = RaceManager::get()->getKartRaceTime(i); + std::stringstream elapsed_string; + elapsed_string << std::setprecision(4) << std::fixed << elapsed_time; if (best_cur_player_idx == -1 || elapsed_time < best_cur_time) { best_cur_player_idx = i; @@ -6587,9 +6608,9 @@ void ServerLobby::storeResults() std::string query = StringUtils::insertValues( "INSERT INTO %s " "(username, venue, reverse, mode, laps, result) " - "VALUES ('%s', '%s', '%s', '%s', %d, %f);", + "VALUES ('%s', '%s', '%s', '%s', %d, '%s');", m_results_table_name.c_str(), username.c_str(), track_name.c_str(), - reverse_string.c_str(), mode_name.c_str(), laps_number, elapsed_time + reverse_string.c_str(), mode_name.c_str(), laps_number, elapsed_string.str() ); easySQLQuery(query); } From 2b4558fe373ff153e2f9657c9495dfa1ab275c58 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 5 May 2020 15:33:25 +0300 Subject: [PATCH 074/830] Remove redundant debug output, update help --- FORK_CHANGES.md | 4 +++- NETWORKING.md | 14 +++++++++++++- src/network/protocols/server_lobby.cpp | 23 ++--------------------- 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/FORK_CHANGES.md b/FORK_CHANGES.md index c837dedcf79..361c73c9dba 100644 --- a/FORK_CHANGES.md +++ b/FORK_CHANGES.md @@ -28,4 +28,6 @@ This is only a short description. 13. Allowed `/records` queries to server -Of course, there are some further plans ~~which will be announced when they are implemented or when I realize they cannot~~. +14. Allowed to have a server in soccer tournament mode. + +Of course, there are some further plans ~~which will be announced when they are implemented or when I realize they cannot be implemented~~. diff --git a/NETWORKING.md b/NETWORKING.md index 911d29d65f2..6d6a7a9c193 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -223,7 +223,7 @@ The current server configuration xml looks like this (this is only an example, j - + @@ -231,6 +231,18 @@ The current server configuration xml looks like this (this is only an example, j + + + + + + + + + + + + diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index d4ca4136e67..6798a59a6ed 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -848,12 +848,8 @@ void ServerLobby::handleChat(Event* event) event->getPeer()->getConsecutiveMessages() > ServerConfig::m_chat_consecutive_interval / 2) { - NetworkString* chat = getNetworkString(); - chat->setSynchronous(true); - core::stringw warn = "Spam detected"; - chat->addUInt8(LE_CHAT).encodeString16(warn); - event->getPeer()->sendPacket(chat, true/*reliable*/); - delete chat; + std::string warn = "Spam detected"; + sendStringToPeer(warn, event->getPeer()); return; } @@ -1795,17 +1791,6 @@ void ServerLobby::asynchronousUpdate() // Reset for next state usage resetPeersReady(); - for (auto p : m_peers_ready) - { - auto peer = p.first.lock(); - if (!peer) - continue; - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - Log::info("ServerLobby", "m_peers_ready: there is a peer %s", username.c_str()); - } - - m_state = LOAD_WORLD; sendMessageToPeers(load_world_message); delete load_world_message; @@ -3999,9 +3984,6 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, } player->setTeam(cur_team); } - Log::info("ServerLobby", "Validated player utf8_name: %s, " - "online_name: %s", utf8_name.c_str(), - utf8_online_name.c_str()); if (ServerConfig::m_soccer_tournament) { if (m_tournament_red_players.count(utf8_online_name)) player->setTeam(KART_TEAM_RED); @@ -6207,7 +6189,6 @@ void ServerLobby::handleServerCommand(Event* event, } else if (argv[0] == "standings") { - // Log::info("ServerLobby", "Gnu Elimination: total %d participants", (int)m_gnu_participants.size()); std::string result = "Gnu Elimination "; if (m_gnu_elimination) result += "is running"; From e14355b1b960beaef670a2422d2ad797f32b12d5 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 5 May 2020 15:40:25 +0300 Subject: [PATCH 075/830] Fix stupid compilation error --- src/network/protocols/server_lobby.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 6798a59a6ed..f36e08769d8 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -848,8 +848,12 @@ void ServerLobby::handleChat(Event* event) event->getPeer()->getConsecutiveMessages() > ServerConfig::m_chat_consecutive_interval / 2) { - std::string warn = "Spam detected"; - sendStringToPeer(warn, event->getPeer()); + NetworkString* chat = getNetworkString(); + chat->setSynchronous(true); + core::stringw warn = "Spam detected"; + chat->addUInt8(LE_CHAT).encodeString16(warn); + event->getPeer()->sendPacket(chat, true/*reliable*/); + delete chat; return; } From a0114054d76d471956c688044645bc0358de86ba Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 12 May 2020 01:28:09 +0300 Subject: [PATCH 076/830] Add temporary bans and referee control for tournament, generalize ability to race, change GP to more free, add ability to preselect gp tracks --- NETWORKING.md | 5 + src/network/game_setup.hpp | 2 + src/network/protocols/server_lobby.cpp | 354 ++++++++++++++++++------- src/network/protocols/server_lobby.hpp | 12 + src/network/server_config.cpp | 1 + src/network/server_config.hpp | 9 + 6 files changed, 285 insertions(+), 98 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index 6d6a7a9c193..04ff6948dfe 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -246,6 +246,11 @@ The current server configuration xml looks like this (this is only an example, j + + + + + diff --git a/src/network/game_setup.hpp b/src/network/game_setup.hpp index bc659c7166e..f6d84f2693e 100644 --- a/src/network/game_setup.hpp +++ b/src/network/game_setup.hpp @@ -125,6 +125,8 @@ class GameSetup m_tracks.size() != getTotalGrandPrixTracks(); } // ------------------------------------------------------------------------ + void cancelOneRace() { m_tracks.pop_back(); } + // ------------------------------------------------------------------------ void stopGrandPrix() { m_tracks.clear(); } // ------------------------------------------------------------------------ const std::vector& getAllTracks() const { return m_tracks; } diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index f36e08769d8..5a4984e549d 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -185,6 +185,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_gnu_elimination = false; m_gnu_remained = 0; + m_fixed_lap = ServerConfig::m_fixed_lap_count; + initAvailableModes(); std::vector all_k = @@ -263,6 +265,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() initTournamentPlayers(); m_tournament_game = 0; } + loadTracksQueueFromConfig(); } // ServerLobby //----------------------------------------------------------------------------- @@ -1515,8 +1518,8 @@ void ServerLobby::asynchronousUpdate() if (ServerConfig::m_ranked && m_state.load() == WAITING_FOR_START_GAME) clearDisconnectedRankedPlayer(); - if (allowJoinedPlayersWaiting() || (m_game_setup->isGrandPrix() && - m_state.load() == WAITING_FOR_START_GAME)) + if (allowJoinedPlayersWaiting() /*|| (m_game_setup->isGrandPrix() && + m_state.load() == WAITING_FOR_START_GAME)*/) { // Only poll the STK server if server has been registered. if (m_server_id_online.load() != 0 && @@ -1690,17 +1693,17 @@ void ServerLobby::asynchronousUpdate() bool go_on_race = false; if (ServerConfig::m_track_voting) go_on_race = handleAllVotes(&winner_vote, &m_winner_peer_id); - else if (m_game_setup->isGrandPrixStarted() || isVotingOver()) + else if (/*m_game_setup->isGrandPrixStarted() || */isVotingOver()) { winner_vote = *m_default_vote; go_on_race = true; } if (go_on_race) { - if (ServerConfig::m_fixed_lap_count > 0) + if (m_fixed_lap >= 0) { - winner_vote.m_num_laps = ServerConfig::m_fixed_lap_count; - Log::info("ServerLobby", "Enforcing %d lap race", (int)ServerConfig::m_fixed_lap_count); + winner_vote.m_num_laps = m_fixed_lap; + Log::info("ServerLobby", "Enforcing %d lap race", (int)m_fixed_lap); } *m_default_vote = winner_vote; m_item_seed = (uint32_t)StkTime::getTimeSinceEpoch(); @@ -2275,8 +2278,8 @@ void ServerLobby::update(int ticks) STKHost::get()->updatePlayers(); if (m_rs_state.load() == RS_NONE && - (m_state.load() > WAITING_FOR_START_GAME || - m_game_setup->isGrandPrixStarted()) && + (m_state.load() > WAITING_FOR_START_GAME/* || + m_game_setup->isGrandPrixStarted()*/) && (STKHost::get()->getPlayersInGame() == 0 || all_players_in_world_disconnected)) { @@ -2304,9 +2307,11 @@ void ServerLobby::update(int ticks) ai->sendPacket(back_to_lobby, /*reliable*/true); delete back_to_lobby; } - + if (all_players_in_world_disconnected) + m_game_setup->cancelOneRace(); resetVotingTime(); - m_game_setup->stopGrandPrix(); + // m_game_setup->cancelOneRace(); + //m_game_setup->stopGrandPrix(); m_rs_state.store(RS_WAITING); return; } @@ -2326,7 +2331,8 @@ void ServerLobby::update(int ticks) sendMessageToPeers(back_lobby, /*reliable*/true); delete back_lobby; resetVotingTime(); - m_game_setup->stopGrandPrix(); + // m_game_setup->cancelOneRace(); + //m_game_setup->stopGrandPrix(); m_rs_state.store(RS_ASYNC_RESET); } @@ -2591,7 +2597,7 @@ void ServerLobby::startSelection(const Event *event) if (!ServerConfig::m_owner_less && ServerConfig::m_team_choosing && - !ServerConfig::m_soccer_tournament && RaceManager::get()->teamEnabled()) + !ServerConfig::m_free_teams && RaceManager::get()->teamEnabled()) { auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); if ((red_blue.first == 0 || red_blue.second == 0) && @@ -2612,29 +2618,29 @@ void ServerLobby::startSelection(const Event *event) // Remove karts / tracks from server that are not supported on all clients std::set karts_erase, tracks_erase; + bool has_peers = false; auto peers = STKHost::get()->getPeers(); for (auto peer : peers) { if (!peer->isValidated() || peer->isWaitingForGame()) continue; - if (ServerConfig::m_only_host_riding && m_server_owner.lock() != peer) { + if (!canRace(peer)) + { + peer->setWaitingForGame(true); + m_peers_ready.erase(peer); + need_to_update = true; continue; } - if (ServerConfig::m_soccer_tournament) { - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - if (m_tournament_red_players.count(username) == 0 && - m_tournament_blue_players.count(username) == 0) - { - peer->setWaitingForGame(true); - m_peers_ready.erase(peer); - need_to_update = true; - continue; - } - } + has_peers = true; peer->eraseServerKarts(m_available_kts.first, karts_erase); peer->eraseServerTracks(m_available_kts.second, tracks_erase); } + if (!has_peers) + { + Log::warn("ServerLobby", + "An attempt to start a race while no one is able to race."); + return; + } if (ServerConfig::m_soccer_tournament && m_tournament_game % 2 == 0) { tracks_erase.insert("icy_soccer_field"); @@ -2648,18 +2654,26 @@ void ServerLobby::startSelection(const Event *event) { m_available_kts.second.erase(track_erase); } - if (ServerConfig::m_soccer_tournament && m_tournament_game % 2 == 1) + if (ServerConfig::m_soccer_tournament) { - if (m_available_kts.second.count("icy_soccer_field")) + if (m_tournament_game % 2 == 1) { - m_available_kts.second.clear(); - m_available_kts.second.insert("icy_soccer_field"); - } - else - { - m_available_kts.second.clear(); + if (m_available_kts.second.count("icy_soccer_field")) + { + m_available_kts.second.clear(); + m_available_kts.second.insert("icy_soccer_field"); + } + else + { + m_available_kts.second.clear(); + } } } + else if (!m_tracks_queue.empty()) + { + m_available_kts.second.clear(); + m_available_kts.second.insert(m_tracks_queue.front()); + } unsigned max_player = 0; @@ -2722,7 +2736,7 @@ void ServerLobby::startSelection(const Event *event) RandomGenerator rg; const auto& all_k = m_available_kts.first; const auto& all_t = m_available_kts.second; - if (!official_tracks.empty() && !ServerConfig::m_soccer_tournament) { + if (!official_tracks.empty() && !ServerConfig::m_random_selects_addons) { it = official_tracks.begin(); std::advance(it, rg.get((int)official_tracks.size())); } else { @@ -2803,8 +2817,9 @@ void ServerLobby::startSelection(const Event *event) ns->setSynchronous(true); ns->addUInt8(LE_START_SELECTION) .addFloat(ServerConfig::m_voting_timeout) - .addUInt8(m_game_setup->isGrandPrixStarted() ? 1 : 0) - .addUInt8(ServerConfig::m_auto_game_time_ratio > 0.0f ? 1 : 0) + .addUInt8(/*m_game_setup->isGrandPrixStarted() ? 1 : */0) + .addUInt8((ServerConfig::m_fixed_lap_count >= 0 + || ServerConfig::m_auto_game_time_ratio > 0.0f) ? 1 : 0) .addUInt8(ServerConfig::m_track_voting ? 1 : 0); ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size()); @@ -2817,12 +2832,7 @@ void ServerLobby::startSelection(const Event *event) ns->encodeString(track); } - if (ServerConfig::m_only_host_riding) { - auto owner = m_server_owner.lock(); - owner->sendPacket(ns, true/*reliable*/); - delete ns; - } - else if (m_gnu_elimination && m_gnu_remained >= 0) + if (m_gnu_elimination && m_gnu_remained >= 0) { auto remaining_begin = m_gnu_participants.begin(); auto remaining_end = remaining_begin + m_gnu_remained; @@ -2852,7 +2862,7 @@ void ServerLobby::startSelection(const Event *event) ns->setSynchronous(true); ns->addUInt8(LE_START_SELECTION) .addFloat(ServerConfig::m_voting_timeout) - .addUInt8(m_game_setup->isGrandPrixStarted() ? 1 : 0) + .addUInt8(/*m_game_setup->isGrandPrixStarted() ? 1 : */0) .addUInt8(ServerConfig::m_auto_game_time_ratio > 0.0f ? 1 : 0) .addUInt8(ServerConfig::m_track_voting ? 1 : 0); @@ -2883,56 +2893,25 @@ void ServerLobby::startSelection(const Event *event) return true; }, ns, /*reliable*/true); } - else if (ServerConfig::m_soccer_tournament) + else { - // delete ns; - // std::set soccer_t; - // for (auto& s: all_t) - // { - // if ((m_tournament_game == 2) ^ (s == "icy_soccer_field")) - // soccer_t.insert(s); - // } - // ns = getNetworkString(1); - // ns->setSynchronous(true); - // ns->addUInt8(LE_START_SELECTION) - // .addFloat(ServerConfig::m_voting_timeout) - // .addUInt8(m_game_setup->isGrandPrixStarted() ? 1 : 0) - // .addUInt8(ServerConfig::m_auto_game_time_ratio > 0.0f ? 1 : 0) - // .addUInt8(ServerConfig::m_track_voting ? 1 : 0); - - - // ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)soccer_t.size()); - // for (const std::string& kart : all_k) - // { - // ns->encodeString(kart); + // std::set all_players; + // for (const std::string& s: m_tournament_red_players) { + // all_players.insert(s); + // } + // for (const std::string& s: m_tournament_blue_players) { + // all_players.insert(s); // } - // for (const std::string& track : soccer_t) - // { - // ns->encodeString(track); - // } - - - std::set all_players; - for (const std::string& s: m_tournament_red_players) { - all_players.insert(s); - } - for (const std::string& s: m_tournament_blue_players) { - all_players.insert(s); - } STKHost::get()->sendPacketToAllPeersWith( - [all_players](STKPeer* p) -> bool + [/*all_players*/this](STKPeer* p) -> bool { - std::string username = StringUtils::wideToUtf8( - p->getPlayerProfiles()[0]->getName()); - return all_players.count(username) > 0; + // std::string username = StringUtils::wideToUtf8( + // p->getPlayerProfiles()[0]->getName()); + // return all_players.count(username) > 0; + return canRace(p); }, ns, /*reliable*/true); delete ns; } - else - { - sendMessageToPeers(ns, /*reliable*/true); - delete ns; - } m_state = SELECTING; if (need_to_update) @@ -3176,6 +3155,14 @@ void ServerLobby::checkRaceFinished() submitRankingsToAddons(); } m_state.store(WAIT_FOR_RACE_STOPPED); + + if (!m_tracks_queue.empty()) + { + m_tracks_queue.pop_front(); + // Reload GP tracks if GP ends + if (m_tracks_queue.empty() && m_game_setup->isGrandPrix()) + loadTracksQueueFromConfig(); + } } // checkRaceFinished //----------------------------------------------------------------------------- @@ -3754,8 +3741,8 @@ void ServerLobby::connectionRequested(Event* event) // can we add the player ? if (!allowJoinedPlayersWaiting() && - (m_state.load() != WAITING_FOR_START_GAME || - m_game_setup->isGrandPrixStarted())) + (m_state.load() != WAITING_FOR_START_GAME /*|| + m_game_setup->isGrandPrixStarted()*/)) { NetworkString *message = getNetworkString(2); message->setSynchronous(true); @@ -3896,6 +3883,29 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, std::string password; data.decodeString(&password); const std::string& server_pw = ServerConfig::m_private_server_password; + if (ServerConfig::m_soccer_tournament && online_id > 0) + { + std::string username = StringUtils::wideToUtf8(online_name); + if (m_temp_banned.count(username)) + { + NetworkString* message = getNetworkString(2); + message->setSynchronous(true); + message->addUInt8(LE_CONNECTION_REFUSED) + .addUInt8(RR_BANNED); + std::string tempban = "You were banned from the server. Please behave well next time."; + message->encodeString(tempban); + peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); + peer->reset(); + delete message; + Log::verbose("ServerLobby", "Player refused: invalid player"); + return; + } + bool privileged = (m_tournament_red_players.count(username) > 0); + privileged |= (m_tournament_blue_players.count(username) > 0); + privileged |= (m_tournament_referees.count(username) > 0); + if (privileged) + password = server_pw; + } if (password != server_pw) { NetworkString *message = getNetworkString(2); @@ -4338,7 +4348,7 @@ void ServerLobby::updateServerOwner() */ void ServerLobby::kartSelectionRequested(Event* event) { - if (m_state != SELECTING || m_game_setup->isGrandPrixStarted()) + if (m_state != SELECTING /*|| m_game_setup->isGrandPrixStarted()*/) { Log::warn("ServerLobby", "Received kart selection while in state %d.", m_state.load()); @@ -4441,8 +4451,8 @@ void ServerLobby::handlePlayerVote(Event* event) vote.m_num_laps = 0; vote.m_reverse = false; } - if (ServerConfig::m_fixed_lap_count > 0) { - vote.m_num_laps = ServerConfig::m_fixed_lap_count; + if (m_fixed_lap >= 0) { + vote.m_num_laps = m_fixed_lap; } // Store vote: @@ -4708,8 +4718,8 @@ void ServerLobby::playerFinishedResult(Event *event) //----------------------------------------------------------------------------- bool ServerLobby::waitingForPlayers() const { - if (m_game_setup->isGrandPrix() && m_game_setup->isGrandPrixStarted()) - return false; + // if (m_game_setup->isGrandPrix() && m_game_setup->isGrandPrixStarted()) + // return false; return m_state.load() >= WAITING_FOR_START_GAME; } // waitingForPlayers @@ -4961,7 +4971,7 @@ void ServerLobby::configPeersStartTime() //----------------------------------------------------------------------------- bool ServerLobby::allowJoinedPlayersWaiting() const { - return !m_game_setup->isGrandPrix(); + return true; //!m_game_setup->isGrandPrix(); } // allowJoinedPlayersWaiting //----------------------------------------------------------------------------- @@ -5938,7 +5948,7 @@ void ServerLobby::handleServerCommand(Event* event, } else if (StringUtils::startsWith(cmd, "kick")) { - if (m_server_owner.lock() != peer) + if (!hasHostRights(peer)) { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); @@ -5949,8 +5959,15 @@ void ServerLobby::handleServerCommand(Event* event, return; } std::string player_name; - if (cmd.length() > 5) + if (StringUtils::startsWith(cmd, "kickban")) + { + if (cmd.length() > 8) + player_name = cmd.substr(8); + } + else if (cmd.length() > 5) + { player_name = cmd.substr(5); + } std::shared_ptr player_peer = STKHost::get()->findPeerByName( StringUtils::utf8ToWide(player_name)); if (player_name.empty() || !player_peer || player_peer->isAIPeer()) @@ -5971,6 +5988,77 @@ void ServerLobby::handleServerCommand(Event* event, std::string auto_report = "[ Auto report caused by kick ]"; writeOwnReport(player_peer.get(), peer.get(), auto_report); } + if (StringUtils::startsWith(cmd, "kickban")) + { + Log::info("ServerLobby", "%s is now banned", player_name.c_str()); + m_temp_banned.insert(player_name); + } + } + } + else if (StringUtils::startsWith(cmd, "unban")) + { + if (!hasHostRights(peer)) + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(L"You are not server owner"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + return; + } + std::string player_name; + if (cmd.length() > 6) + { + player_name = cmd.substr(6); + } + if (player_name.empty()) + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16( + L"Usage: /unban [player name]"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + } + else + { + Log::info("ServerLobby", "%s is now unbanned", player_name.c_str()); + m_temp_banned.erase(player_name); + } + } + else if (StringUtils::startsWith(cmd, "ban")) + { + if (!hasHostRights(peer)) + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(L"You are not server owner"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + return; + } + std::string player_name; + if (cmd.length() > 4) + { + player_name = cmd.substr(4); + } + if (player_name.empty()) + { + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16( + L"Usage: /ban [player name]"); + peer->sendPacket(chat, true/*reliable*/); + delete chat; + } + else + { + Log::info("ServerLobby", "%s is now banned", player_name.c_str()); + m_temp_banned.insert(player_name); } } else if (StringUtils::startsWith(cmd, "playeraddonscore")) @@ -6353,19 +6441,33 @@ void ServerLobby::handleServerCommand(Event* event, int old_game = m_tournament_game; if (argv.size() < 2) { ++m_tournament_game; + m_fixed_lap = 10; } else { if (!StringUtils::parseString(argv[1], &m_tournament_game)) { std::string msg = "Please specify a correct number. " - "Format: /game 2"; + "Format: /game [number] [length]"; sendStringToPeer(msg, peer); return; } + int length = 10; + if (argv.size() >= 3) + { + bool ok = StringUtils::parseString(argv[2], &length); + if (!ok || length <= 0) + { + std::string msg = "Please specify a correct number. " + "Format: /game [number] [length]"; + sendStringToPeer(msg, peer); + return; + } + } + m_fixed_lap = length; } if ((m_tournament_game ^ old_game) & 2) changeColors(); std::string msg = StringUtils::insertValues( - "Ready to start game %d", m_tournament_game); + "Ready to start game %d for %d minutes", m_tournament_game, m_fixed_lap); sendStringToAllPeers(msg); } else if (argv[0] == "role") @@ -6807,4 +6909,60 @@ void ServerLobby::sendStringToAllPeers(std::string& s) sendMessageToPeers(chat, true/*reliable*/); delete chat; } // sendStringToAllPeers +//----------------------------------------------------------------------------- +bool ServerLobby::canRace(std::shared_ptr& peer) const +{ + return canRace(peer.get()); +} // canRace +//----------------------------------------------------------------------------- +bool ServerLobby::canRace(STKPeer* peer) const +{ + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (ServerConfig::m_soccer_tournament) + { + return m_tournament_red_players.count(username) > 0 || + m_tournament_blue_players.count(username) > 0; + } + else if (ServerConfig::m_only_host_riding) + { + return peer == m_server_owner.lock().get(); + } + else if (!m_tracks_queue.empty()) + { + return peer->getClientAssets().second.count(m_tracks_queue.front()); + } + else + { + return true; + } +} // canRace + +//----------------------------------------------------------------------------- +bool ServerLobby::hasHostRights(std::shared_ptr& peer) const +{ + return hasHostRights(peer.get()); +} // hasHostRights +//----------------------------------------------------------------------------- +bool ServerLobby::hasHostRights(STKPeer* peer) const +{ + if (peer == m_server_owner.lock().get()) + return true; + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (ServerConfig::m_soccer_tournament) + { + return m_tournament_referees.count(username) > 0; + } + return false; +} // hasHostRights +//----------------------------------------------------------------------------- +void ServerLobby::loadTracksQueueFromConfig() +{ + std::vector tokens = StringUtils::split( + ServerConfig::m_tracks_order, ' '); + m_tracks_queue.clear(); + for (std::string& s: tokens) + m_tracks_queue.push_back(s); +} // loadTracksQueueFromConfig //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 9655dfddf1a..f386a2ad522 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef ENABLE_SQLITE3 #include @@ -277,8 +278,14 @@ class ServerLobby : public LobbyProtocol std::set m_tournament_referees; + std::set m_temp_banned; + + std::deque m_tracks_queue; + int m_tournament_game; + int m_fixed_lap; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); @@ -403,6 +410,11 @@ class ServerLobby : public LobbyProtocol void changeColors(); void sendStringToPeer(std::string& s, std::shared_ptr& peer) const; void sendStringToAllPeers(std::string& s); + bool canRace(std::shared_ptr& peer) const; + bool canRace(STKPeer* peer) const; + bool hasHostRights(std::shared_ptr& peer) const; + bool hasHostRights(STKPeer* peer) const; + void loadTracksQueueFromConfig(); public: ServerLobby(); virtual ~ServerLobby(); diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 418df468182..afd27dc1fd5 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -374,6 +374,7 @@ void loadServerLobbyFromConfig() m_sleeping_server = false; m_free_teams = true; m_validating_player = true; + m_random_selects_addons = true; } if (m_ranked) diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 6a6576cbd47..f89976a53fa 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -546,6 +546,15 @@ namespace ServerConfig "A temporary feature to make others only spectate. Not ideal. " "Maybe not even working.")); + SERVER_CFG_PREFIX BoolServerConfigParam m_random_selects_addons + SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "random-selects-addons", + "If true and no track is selected, then an addon track can be picked.")); + + SERVER_CFG_PREFIX StringServerConfigParam m_tracks_order + SERVER_CFG_DEFAULT(StringServerConfigParam("", "tracks-queue", + "If non-empty, these tracks are played in the order until " + "the list ends. Can be useful for grands prix.")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; From b02a9340052aab625e7c20ff1dbf22787fe974c7 Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 15 May 2020 19:06:18 +0300 Subject: [PATCH 077/830] Allow customizable grand prix scoring in server config --- NETWORKING.md | 3 + src/modes/world_with_rank.cpp | 67 +++++++++++- src/modes/world_with_rank.hpp | 19 +++- src/network/protocols/server_lobby.cpp | 142 +++++++++++++++++++++---- src/network/protocols/server_lobby.hpp | 27 +++++ src/network/server_config.hpp | 5 + 6 files changed, 235 insertions(+), 28 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index 04ff6948dfe..23f6355ab7a 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -252,6 +252,9 @@ The current server configuration xml looks like this (this is only an example, j + + + ``` diff --git a/src/modes/world_with_rank.cpp b/src/modes/world_with_rank.cpp index 30bfee10f93..66bb02c0720 100644 --- a/src/modes/world_with_rank.cpp +++ b/src/modes/world_with_rank.cpp @@ -50,7 +50,10 @@ void WorldWithRank::init() m_position_used.resize(m_karts.size()); m_position_setting_initialised = false; #endif - stk_config->getAllScores(&m_score_for_position, getNumKarts()); + if (!m_custom_scoring) + stk_config->getAllScores(&m_score_for_position, getNumKarts()); + else + refreshCustomScores(getNumKarts()); Track *track = Track::getCurrentTrack(); // Don't init track sector if navmesh is not found in arena @@ -59,7 +62,6 @@ void WorldWithRank::init() for (unsigned int i = 0; i < m_karts.size(); i++) m_kart_track_sector.push_back(new TrackSector()); - } // init //----------------------------------------------------------------------------- @@ -213,9 +215,14 @@ unsigned int WorldWithRank::getRescuePositionIndex(AbstractKart *kart) */ int WorldWithRank::getScoreForPosition(int p) { - assert(p-1 >= 0); - assert(p - 1 <(int) m_score_for_position.size()); - return m_score_for_position[p - 1]; + assert(p - 1 >= 0); + assert(p - 1 < (int)m_score_for_position.size()); + if (!m_custom_scoring) + return m_score_for_position[p - 1]; + else + { + return m_score_for_position[p - 1]; // oh really? + } } // getScoreForPosition //----------------------------------------------------------------------------- @@ -260,3 +267,53 @@ void WorldWithRank::updateSectorForKarts() getTrackSector(i)->update(m_karts[i]->getXYZ()); } } // updateSectorForKarts +//----------------------------------------------------------------------------- + +void WorldWithRank::setCustomScoringSystem(std::string& type, std::vector& params) +{ + m_custom_scoring = true; + m_custom_scoring_type = type; + m_custom_scoring_params = params; + refreshCustomScores(getNumKarts()); +} // setCustomScoringSystem +//----------------------------------------------------------------------------- + +void WorldWithRank::refreshCustomScores(int num_karts) +{ + if (m_custom_scoring_type == "inc") + { + m_score_for_position.clear(); + for (unsigned i = 2; i < m_custom_scoring_params.size(); i++) + m_score_for_position.push_back(m_custom_scoring_params[i]); + sort(m_score_for_position.begin(), m_score_for_position.end()); + for (unsigned i = 1; i < m_score_for_position.size(); i++) + m_score_for_position[i] += m_score_for_position[i - 1]; + reverse(m_score_for_position.begin(), m_score_for_position.end()); + m_score_for_position.resize(num_karts, 0); + } + else if (m_custom_scoring_type == "fixed") + { + + m_score_for_position.clear(); + for (unsigned i = 2; i < m_custom_scoring_params.size(); i++) + m_score_for_position.push_back(m_custom_scoring_params[i]); + m_score_for_position.resize(num_karts, 0); + } +} // refreshCustomScores +//----------------------------------------------------------------------------- + +int WorldWithRank::getFastestLapPoints() const +{ + if (!m_custom_scoring) + return 0; + return m_custom_scoring_params[1]; +} // getFastestLapPoints +//----------------------------------------------------------------------------- + +int WorldWithRank::getPolePoints() const +{ + if (!m_custom_scoring) + return 0; + return m_custom_scoring_params[0]; +} // getPolePoints +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/modes/world_with_rank.hpp b/src/modes/world_with_rank.hpp index 3b6f7e87def..55d2aa805e4 100644 --- a/src/modes/world_with_rank.hpp +++ b/src/modes/world_with_rank.hpp @@ -48,6 +48,12 @@ class WorldWithRank : public World * 0 based, so using race-position - 1. */ std::vector m_score_for_position; + bool m_custom_scoring; + + std::vector m_custom_scoring_params; + + std::string m_custom_scoring_type; + #ifdef DEBUG /** Used for debugging to help detect if the same kart position * is used more than once. */ @@ -68,7 +74,9 @@ class WorldWithRank : public World void updateSectorForKarts(); public: - WorldWithRank() : World() {} + WorldWithRank() : World() { + m_custom_scoring = false; + } virtual ~WorldWithRank(); /** call just after instanciating. can't be moved to the contructor as child classes must be instanciated, otherwise polymorphism will fail and the @@ -101,6 +109,15 @@ class WorldWithRank : public World bool isOnRoad(unsigned int kart_index) const; // ------------------------------------------------------------------------ int getSectorForKart(const AbstractKart *kart) const; + // ------------------------------------------------------------------------ + void setCustomScoringSystem(std::string& type, std::vector& params); + // ------------------------------------------------------------------------ + void refreshCustomScores(int num_karts); + // ------------------------------------------------------------------------ + int getFastestLapPoints() const; + // ------------------------------------------------------------------------ + int getPolePoints() const; + // ------------------------------------------------------------------------ }; // WorldWithRank diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 9903f6cd97d..46f99982229 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -266,6 +266,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_tournament_game = 0; } loadTracksQueueFromConfig(); + loadCustomScoring(); } // ServerLobby //----------------------------------------------------------------------------- @@ -2379,6 +2380,7 @@ void ServerLobby::update(int ticks) Log::info("ServerLobbyRoom", "Starting the race loading."); // This will create the world instance, i.e. load track and karts loadWorld(); + updateWorldScoring(); m_state = WAIT_FOR_WORLD_LOADED; break; case RACING: @@ -2954,6 +2956,8 @@ void ServerLobby::startSelection(const Event *event) // Will be changed after the first vote received m_timeout.store(std::numeric_limits::max()); + if (!m_game_setup->isGrandPrixStarted()) + m_gp_scores.clear(); } // startSelection //----------------------------------------------------------------------------- @@ -3113,8 +3117,25 @@ void ServerLobby::checkRaceFinished() int fastest_lap = static_cast(World::getWorld())->getFastestLapTicks(); m_result_ns->addUInt32(fastest_lap); - m_result_ns->encodeString(static_cast(World::getWorld()) - ->getFastestLapKartName()); + irr::core::stringw fastest_kart_wide = + static_cast(World::getWorld()) + ->getFastestLapKartName(); + m_result_ns->encodeString(fastest_kart_wide); + std::string fastest_kart = StringUtils::wideToUtf8(fastest_kart_wide); + + int points_fl = 0; + int points_pole = 0; + WorldWithRank *wwr = dynamic_cast(World::getWorld()); + if (wwr) + { + points_fl = wwr->getFastestLapPoints(); + points_pole = wwr->getPolePoints(); + } + else + { + Log::error("ServerLobby", + "World with scores that is not a WorldWithRank??"); + } // all gp tracks m_result_ns->addUInt8((uint8_t)m_game_setup->getTotalGrandPrixTracks()) @@ -3132,11 +3153,18 @@ void ServerLobby::checkRaceFinished() if (auto player = RaceManager::get()->getKartInfo(i).getNetworkPlayerProfile().lock()) { - last_score = player->getScore(); + std::string username = StringUtils::wideToUtf8(player->getName()); + last_score = m_gp_scores[username].score; cur_score += last_score; - overall_time = overall_time + player->getOverallTime(); + if (username == fastest_kart) + cur_score += points_fl; + + overall_time = overall_time + m_gp_scores[username].time; player->setScore(cur_score); player->setOverallTime(overall_time); + + m_gp_scores[username].score = cur_score; + m_gp_scores[username].time = overall_time; } m_result_ns->addUInt32(last_score).addUInt32(cur_score) .addFloat(overall_time); @@ -6303,25 +6331,25 @@ void ServerLobby::handleServerCommand(Event* event, } else if (argv[0] == "standings") { - std::string result = "Gnu Elimination "; - if (m_gnu_elimination) - result += "is running"; - else - result += "is disabled"; - result += ", standings:"; - for (int i = 0; i < (int)m_gnu_participants.size(); i++) + if (argv.size() > 1) { - std::string line = "\n" + (i < m_gnu_remained ? - std::to_string(i + 1) : "[" + std::to_string(i + 1) + "]"); - line += ". " + m_gnu_participants[i]; - result += line; + if (argv[1] == "gp") + sendGrandPrixStandingsToPeer(peer); + else if (argv[1] == "gnu") + sendGnuStandingsToPeer(peer); + else + { + std::string msg = "Usage: /standings [gp | gnu]"; + sendStringToPeer(msg, peer); + } + return; } - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16(StringUtils::utf8ToWide(result)); - peer->sendPacket(chat, true/*reliable*/); - delete chat; + if (m_game_setup->isGrandPrix()) + { + sendGrandPrixStandingsToPeer(peer); + return; + } + sendGnuStandingsToPeer(peer); } else if (argv[0] == "teamchat") { @@ -6987,4 +7015,74 @@ void ServerLobby::loadTracksQueueFromConfig() for (std::string& s: tokens) m_tracks_queue.push_back(s); } // loadTracksQueueFromConfig -//----------------------------------------------------------------------------- \ No newline at end of file +//----------------------------------------------------------------------------- +void ServerLobby::sendGnuStandingsToPeer(std::shared_ptr peer) const +{ + std::string result = "Gnu Elimination "; + if (m_gnu_elimination) + result += "is running"; + else + result += "is disabled"; + if (!m_gnu_participants.empty()) + result += ", standings:"; + for (int i = 0; i < (int)m_gnu_participants.size(); i++) + { + std::string line = "\n" + (i < m_gnu_remained ? + std::to_string(i + 1) : "[" + std::to_string(i + 1) + "]"); + line += ". " + m_gnu_participants[i]; + result += line; + } + sendStringToPeer(result, peer); +} // sendGnuStandingsToPeer +//----------------------------------------------------------------------------- +void ServerLobby::sendGrandPrixStandingsToPeer(std::shared_ptr peer) const +{ + std::vector> results; + for (auto& p: m_gp_scores) + results.emplace_back(p.second, p.first); + std::stable_sort(results.rbegin(), results.rend()); + std::stringstream response; + response << "Grand Prix standings\n"; + for (int i = 0; i < results.size(); i++) + { + response << (i + 1) << ". "; + response << " " << results[i].second; + response << " " << results[i].first.score; + response << " " << "(" << StringUtils::timeToString(results[i].first.time) << ")"; + response << "\n"; + } + std::string answer = response.str(); + sendStringToPeer(answer, peer); +} // sendGnuStandingsToPeer +//----------------------------------------------------------------------------- +void ServerLobby::loadCustomScoring() +{ + m_scoring_int_params.clear(); + m_scoring_type = ""; + std::string scoring = ServerConfig::m_gp_scoring; + if (!scoring.empty()) + { + std::vector params = StringUtils::split(scoring, ' '); + if (params.empty()) + return; + m_scoring_type = params[0]; + for (unsigned i = 1; i < params.size(); i++) + { + int param; + if (!StringUtils::fromString(params[i], param)) + { + Log::warn("ServerLobby", "Unable to parse integer from custom scoring data"); + return; + } + m_scoring_int_params.push_back(param); + } + } +} // loadCustomScoring +//----------------------------------------------------------------------------- +void ServerLobby::updateWorldScoring() +{ + WorldWithRank *wwr = dynamic_cast(World::getWorld()); + if (wwr) + wwr->setCustomScoringSystem(m_scoring_type, m_scoring_int_params); +} // updateWorldScoring +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index f386a2ad522..a6d6e4922a2 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -51,6 +51,23 @@ namespace Online class Request; } +// I know it should be in a more suitable place, but for now I have no idea +// how to make this with the current system. Sorry. Hope to refactor later. + +struct GPScore +{ + int score = 0; + double time = 0.; + bool operator < (const GPScore& rhs) const + { + return (score < rhs.score || (score == rhs.score && time > rhs.time)); + } + bool operator > (const GPScore& rhs) const + { + return (score > rhs.score || (score == rhs.score && time < rhs.time)); + } +}; + class ServerLobby : public LobbyProtocol { public: @@ -282,10 +299,16 @@ class ServerLobby : public LobbyProtocol std::deque m_tracks_queue; + std::map m_gp_scores; + int m_tournament_game; int m_fixed_lap; + std::vector m_scoring_int_params; + + std::string m_scoring_type; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); @@ -415,6 +438,10 @@ class ServerLobby : public LobbyProtocol bool hasHostRights(std::shared_ptr& peer) const; bool hasHostRights(STKPeer* peer) const; void loadTracksQueueFromConfig(); + void sendGnuStandingsToPeer(std::shared_ptr peer) const; + void sendGrandPrixStandingsToPeer(std::shared_ptr peer) const; + void loadCustomScoring(); + void updateWorldScoring(); public: ServerLobby(); virtual ~ServerLobby(); diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index f89976a53fa..4add05ab15d 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -555,6 +555,11 @@ namespace ServerConfig "If non-empty, these tracks are played in the order until " "the list ends. Can be useful for grands prix.")); + SERVER_CFG_PREFIX StringServerConfigParam m_gp_scoring + SERVER_CFG_DEFAULT(StringServerConfigParam("", "grand-prix-scoring", + "A custom Grand Prix scoring system to be used, " + "empty for default.")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; From 1345b1127d6a0ba91e118de26dc5934cd1b9eee1 Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 15 May 2020 19:59:24 +0300 Subject: [PATCH 078/830] Fix wrong merge --- src/network/protocols/server_lobby.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index f92ccda5964..8d1ea307c04 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2853,6 +2853,8 @@ void ServerLobby::startSelection(const Event *event) || ServerConfig::m_auto_game_time_ratio > 0.0f) ? 1 : 0) .addUInt8(ServerConfig::m_track_voting ? 1 : 0); + const auto& all_k = m_available_kts.first; + const auto& all_t = m_available_kts.second; ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size()); for (const std::string& kart : all_k) { From 2b2542fab72d274977174e7947443e60bf689dca Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 16 May 2020 14:58:23 +0300 Subject: [PATCH 079/830] Make /spectate not affect track choice, adapt it for tournament, fix minor bugs --- NETWORKING.md | 3 + src/network/protocols/server_lobby.cpp | 106 ++++++++++++++++++++----- src/network/protocols/server_lobby.hpp | 9 +++ src/network/server_config.hpp | 6 ++ 4 files changed, 105 insertions(+), 19 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index 23f6355ab7a..8953362b576 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -255,6 +255,9 @@ The current server configuration xml looks like this (this is only an example, j + + + ``` diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 8d1ea307c04..83ca839de7f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -267,6 +267,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() } loadTracksQueueFromConfig(); loadCustomScoring(); + loadWhiteList(); } // ServerLobby //----------------------------------------------------------------------------- @@ -654,6 +655,7 @@ void ServerLobby::updateAddons() m_available_kts.first = m_official_kts.first; else m_available_kts.first = { all_k.begin(), all_k.end() }; + m_entering_kts = m_available_kts; } // updateAddons //----------------------------------------------------------------------------- @@ -750,6 +752,7 @@ void ServerLobby::updateTracksForMode() m_available_kts.second.erase(track); } } + m_entering_kts = m_available_kts; } // updateTracksForMode //----------------------------------------------------------------------------- @@ -1732,6 +1735,31 @@ void ServerLobby::asynchronousUpdate() m_item_seed = (uint32_t)StkTime::getTimeSinceEpoch(); ItemManager::updateRandomSeed(m_item_seed); m_game_setup->setRace(winner_vote); + std::string track_name = winner_vote.m_track_name; + auto peers = STKHost::get()->getPeers(); + std::set bad_spectators; + for (auto peer : peers) + { + if (peer->alwaysSpectate() && + peer->getClientAssets().second.count(track_name) == 0) + { + peer->setAlwaysSpectate(false); + peer->setWaitingForGame(true); + m_peers_ready.erase(peer); + bad_spectators.insert(peer.get()); + } + } + // if (!bad_spectators.empty()) + // { + // NetworkString* back_lobby = getNetworkString(2); + // back_lobby->setSynchronous(true); + // back_lobby->addUInt8(LE_BACK_LOBBY).addUInt8(BLR_NONE); + // STKHost::get()->sendPacketToAllPeersWith( + // [bad_spectators](STKPeer* peer) { + // return bad_spectators.find(peer) != + // bad_spectators.end(); }, back_lobby, /*reliable*/true); + // delete back_lobby; + // } bool has_always_on_spectators = false; auto players = STKHost::get() ->getPlayersForNewGame(&has_always_on_spectators); @@ -1827,7 +1855,7 @@ void ServerLobby::asynchronousUpdate() sendMessageToPeers(load_world_message); // updatePlayerList so the in lobby players (if any) can see always // spectators join the game - if (has_always_on_spectators) + if (has_always_on_spectators || !bad_spectators.empty()) updatePlayerList(); delete load_world_message; } @@ -2655,20 +2683,31 @@ void ServerLobby::startSelection(const Event *event) { if (!peer->isValidated() || peer->isWaitingForGame()) continue; - if (!canRace(peer)) + bool can_race = canRace(peer); + if (!can_race) + { + if (ServerConfig::m_soccer_tournament) + peer->setAlwaysSpectate(true); + } + if (!can_race && !peer->alwaysSpectate()) { peer->setWaitingForGame(true); m_peers_ready.erase(peer); need_to_update = true; continue; } + else if (peer->alwaysSpectate()) + { + always_spectate_peers.insert(peer.get()); + continue; + } peer->eraseServerKarts(m_available_kts.first, karts_erase); peer->eraseServerTracks(m_available_kts.second, tracks_erase); - if (peer->alwaysSpectate()) - always_spectate_peers.insert(peer.get()); - else if (!peer->isAIPeer()) + if (!peer->isAIPeer()) has_peer_plays_game = true; } + m_default_always_spectate_peers = always_spectate_peers; + // kimden thinks if someone wants to race he should disable spectating // // Disable always spectate peers if no players join the game if (!has_peer_plays_game) @@ -2896,7 +2935,8 @@ void ServerLobby::startSelection(const Event *event) ns->addUInt8(LE_START_SELECTION) .addFloat(ServerConfig::m_voting_timeout) .addUInt8(/*m_game_setup->isGrandPrixStarted() ? 1 : */0) - .addUInt8(ServerConfig::m_auto_game_time_ratio > 0.0f ? 1 : 0) + .addUInt8((ServerConfig::m_fixed_lap_count >= 0 + || ServerConfig::m_auto_game_time_ratio > 0.0f) ? 1 : 0) .addUInt8(ServerConfig::m_track_voting ? 1 : 0); ns->addUInt16((uint16_t)(has_gnu ? 1 : 0)).addUInt16( @@ -3643,14 +3683,14 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) ott = ott / (float)m_official_kts.second.size(); std::set karts_erase, tracks_erase; - for (const std::string& server_kart : m_available_kts.first) + for (const std::string& server_kart : m_entering_kts.first) { if (client_karts.find(server_kart) == client_karts.end()) { karts_erase.insert(server_kart); } } - for (const std::string& server_track : m_available_kts.second) + for (const std::string& server_track : m_entering_kts.second) { if (client_tracks.find(server_track) == client_tracks.end()) { @@ -3681,9 +3721,9 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) peer->addon_arenas_count = addon_arenas; peer->addon_soccers_count = addon_soccers; - if (karts_erase.size() == m_available_kts.first.size()) + if (karts_erase.size() == m_entering_kts.first.size()) Log::verbose("ServerLobby", "Bad player: no common karts with server"); - if (tracks_erase.size() == m_available_kts.second.size()) + if (tracks_erase.size() == m_entering_kts.second.size()) Log::verbose("ServerLobby", "Bad player: no common tracks with server"); if (okt < ServerConfig::m_official_karts_threshold) Log::verbose("ServerLobby", "Bad player: bad official kart threshold"); @@ -3700,8 +3740,8 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) if (!has_required_tracks) Log::verbose("ServerLobby", "Bad player: no required tracks"); - if (karts_erase.size() == m_available_kts.first.size() || - tracks_erase.size() == m_available_kts.second.size() || + if (karts_erase.size() == m_entering_kts.first.size() || + tracks_erase.size() == m_entering_kts.second.size() || okt < ServerConfig::m_official_karts_threshold || ott < ServerConfig::m_official_tracks_threshold || addon_karts < (int)ServerConfig::m_addon_karts_threshold || @@ -3953,7 +3993,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, std::string password; data.decodeString(&password); const std::string& server_pw = ServerConfig::m_private_server_password; - if (ServerConfig::m_soccer_tournament && online_id > 0) + if (ServerConfig::m_validating_player && online_id > 0) { std::string username = StringUtils::wideToUtf8(online_name); if (m_temp_banned.count(username)) @@ -3969,11 +4009,8 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, delete message; Log::verbose("ServerLobby", "Player refused: invalid player"); return; - } - bool privileged = (m_tournament_red_players.count(username) > 0); - privileged |= (m_tournament_blue_players.count(username) > 0); - privileged |= (m_tournament_referees.count(username) > 0); - if (privileged) + } + if (m_usernames_white_list.count(username) > 0) password = server_pw; } if (password != server_pw) @@ -4281,6 +4318,23 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) const bool game_started = m_state.load() != WAITING_FOR_START_GAME && !update_when_reset_server; + if (update_when_reset_server) + { + if (!ServerConfig::m_soccer_tournament) + { + for (auto& peer : m_default_always_spectate_peers) + peer->setAlwaysSpectate(true); + } + else + { + auto peers = STKHost::get()->getPeers(); + for (auto& peer: peers) + { + peer->setAlwaysSpectate(false); + } + } + } + auto all_profiles = STKHost::get()->getAllPlayerProfiles(); size_t all_profiles_size = all_profiles.size(); for (auto& profile : all_profiles) @@ -5893,7 +5947,13 @@ void ServerLobby::handleServerCommand(Event* event, return; if (argv[0] == "spectate") { - if (m_game_setup->isGrandPrix() || !ServerConfig::m_live_players) + if (ServerConfig::m_soccer_tournament) + { + std::string msg = "All spectators already have auto spectate ability"; + sendStringToPeer(msg, peer); + return; + } + if (/*m_game_setup->isGrandPrix() || */!ServerConfig::m_live_players) { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); @@ -7161,4 +7221,12 @@ void ServerLobby::updateWorldScoring() if (wwr) wwr->setCustomScoringSystem(m_scoring_type, m_scoring_int_params); } // updateWorldScoring +//----------------------------------------------------------------------------- +void ServerLobby::loadWhiteList() +{ + std::vector tokens = StringUtils::split( + ServerConfig::m_white_list, ' '); + for (std::string& s: tokens) + m_usernames_white_list.insert(s); +} // loadWhiteList //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index a6d6e4922a2..19dac524840 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -179,6 +179,10 @@ class ServerLobby : public LobbyProtocol * with data in server first. */ std::pair, std::set > m_available_kts; + /** Available karts and tracks for all clients, this will be initialized + * with data in server first. */ + std::pair, std::set > m_entering_kts; + /** Keeps track of the server state. */ std::atomic_bool m_server_has_loaded_world; @@ -309,6 +313,10 @@ class ServerLobby : public LobbyProtocol std::string m_scoring_type; + std::set m_default_always_spectate_peers; + + std::set m_usernames_white_list; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); @@ -442,6 +450,7 @@ class ServerLobby : public LobbyProtocol void sendGrandPrixStandingsToPeer(std::shared_ptr peer) const; void loadCustomScoring(); void updateWorldScoring(); + void loadWhiteList(); public: ServerLobby(); virtual ~ServerLobby(); diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 4add05ab15d..6845f85e1e7 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -560,6 +560,12 @@ namespace ServerConfig "A custom Grand Prix scoring system to be used, " "empty for default.")); + SERVER_CFG_PREFIX StringServerConfigParam m_white_list + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "white-list", + "For a private server, a list of players who can enter with " + "any password. Works only for online accounts.")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; From b2ae6f5e515863252924742aee083b11de6a3d65 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 30 May 2020 13:06:36 +0300 Subject: [PATCH 080/830] Allow to count own goals differently --- NETWORKING.md | 6 ++ src/modes/soccer_world.cpp | 83 ++++++++++++++++++++++---- src/modes/soccer_world.hpp | 17 ++++++ src/network/protocols/server_lobby.cpp | 34 +++++++++-- src/network/protocols/server_lobby.hpp | 2 +- src/network/server_config.hpp | 10 ++++ 6 files changed, 136 insertions(+), 16 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index 8953362b576..2d48d5a0f9f 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -258,6 +258,12 @@ The current server configuration xml looks like this (this is only an example, j + + + + + + ``` diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp index f36808a5720..ec7d48954ad 100644 --- a/src/modes/soccer_world.cpp +++ b/src/modes/soccer_world.cpp @@ -23,6 +23,7 @@ #include "config/user_config.hpp" #include "io/file_manager.hpp" #include "graphics/irr_driver.hpp" +#include "guiengine/message_queue.hpp" #include "karts/abstract_kart_animation.hpp" #include "karts/kart_model.hpp" #include "karts/kart_properties.hpp" @@ -43,6 +44,7 @@ #include "tracks/track_object_manager.hpp" #include "tracks/track_sector.hpp" #include "utils/constants.hpp" +#include "utils/translation.hpp" #include "utils/string_utils.hpp" #include @@ -281,6 +283,13 @@ void SoccerWorld::init() m_goal_target = RaceManager::get()->getMaxGoal(); m_goal_sound = SFXManager::get()->createSoundSource("goal_scored"); + + m_red_ball_hitter = -1; + m_blue_ball_hitter = -1; + m_red_hit_ticks = -1; + m_blue_hit_ticks = -1; + m_scoring_policy = GoalScoringPolicy::STANDARD; + Track *track = Track::getCurrentTrack(); if (track->hasNavMesh()) { @@ -494,29 +503,64 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) } ScorerData sd = {}; - sd.m_id = m_ball_hitter; - sd.m_correct_goal = isCorrectGoal(m_ball_hitter, first_goal); - sd.m_kart = getKart(m_ball_hitter)->getIdent(); - sd.m_player = getKart(m_ball_hitter)->getController() + + if (m_scoring_policy == GoalScoringPolicy::STANDARD) + { + sd.m_id = m_ball_hitter; + } + else if (m_scoring_policy == GoalScoringPolicy::NO_OWN_GOALS) + { + int hitter = (first_goal ? m_red_ball_hitter : m_blue_ball_hitter); + if (hitter < 0) + hitter = m_ball_hitter; + sd.m_id = hitter; + } + else if (m_scoring_policy == GoalScoringPolicy::ADVANCED) + { + // will be changed when we come up with something better + sd.m_id = m_ball_hitter; + } + m_red_hit_ticks = -1; + m_blue_hit_ticks = -1; + m_red_ball_hitter = -1; + m_blue_ball_hitter = -1; + sd.m_correct_goal = isCorrectGoal(sd.m_id, first_goal); + sd.m_kart = getKart(sd.m_id)->getIdent(); + sd.m_player = getKart(sd.m_id)->getController() ->getName(false/*include_handicap_string*/); - sd.m_handicap_level = getKart(m_ball_hitter)->getHandicap(); - if (RaceManager::get()->getKartGlobalPlayerId(m_ball_hitter) > -1) + sd.m_handicap_level = getKart(sd.m_id)->getHandicap(); + if (RaceManager::get()->getKartGlobalPlayerId(sd.m_id) > -1) { sd.m_country_code = - RaceManager::get()->getKartInfo(m_ball_hitter).getCountryCode(); + RaceManager::get()->getKartInfo(sd.m_id).getCountryCode(); } + std::string team_name = (first_goal ? "red team" : "blue team"); + std::string player_name = StringUtils::wideToUtf8(sd.m_player); if (sd.m_correct_goal) { - m_karts[m_ball_hitter]->getKartModel() + Log::info("SoccerWorld", "[Goal] %s scored a goal for %s", + player_name.c_str(), team_name.c_str()); + m_karts[sd.m_id]->getKartModel() ->setAnimation(KartModel::AF_WIN_START, true/* play_non_loop*/); } - else if (!sd.m_correct_goal) { - m_karts[m_ball_hitter]->getKartModel() + Log::info("SoccerWorld", "[Goal] %s scored an own goal for %s", + player_name.c_str(), team_name.c_str()); + m_karts[sd.m_id]->getKartModel() ->setAnimation(KartModel::AF_LOSE_START, true/* play_non_loop*/); } +#ifndef SERVER_ONLY + // show a message once a goal is made + core::stringw msg; + if (sd.m_correct_goal) + msg = _("%s scored a goal!", sd.m_player); + else + msg = _("Oops, %s made an own goal!", sd.m_player); + MessageQueue::add(MessageQueue::MT_GENERIC, msg); +#endif + if (first_goal) { if (RaceManager::get()->hasTimeTarget()) @@ -623,6 +667,14 @@ void SoccerWorld::handlePlayerGoalFromServer(const NetworkString& ns) m_blue_scorers.push_back(sd); } + // show a message once a goal is made + core::stringw msg; + if (sd.m_correct_goal) + msg = _("%s scored a goal!", sd.m_player); + else + msg = _("Oops, %s made an own goal!", sd.m_player); + MessageQueue::add(MessageQueue::MT_GENERIC, msg); + if (ticks_now >= ticks_back_to_own_goal && !isStartPhase()) { Log::warn("SoccerWorld", "Server ticks %d is too close to client ticks " @@ -688,6 +740,17 @@ void SoccerWorld::resetKartsToSelfGoals() void SoccerWorld::setBallHitter(unsigned int kart_id) { m_ball_hitter = kart_id; + KartTeam team = getKartTeam(kart_id); + if (team == KART_TEAM_RED) + { + m_red_ball_hitter = kart_id; + m_red_hit_ticks = m_time_ticks; + } + else if (team == KART_TEAM_BLUE) + { + m_blue_ball_hitter = kart_id; + m_blue_hit_ticks = m_time_ticks; + } } // setBallHitter //----------------------------------------------------------------------------- diff --git a/src/modes/soccer_world.hpp b/src/modes/soccer_world.hpp index 05d551f6086..0e641b46106 100644 --- a/src/modes/soccer_world.hpp +++ b/src/modes/soccer_world.hpp @@ -97,6 +97,20 @@ class SoccerWorld : public WorldWithRank int m_ball_invalid_timer; int m_ball_hitter; + int m_red_hit_ticks; + int m_blue_hit_ticks; + + int m_red_ball_hitter; + int m_blue_ball_hitter; + + enum GoalScoringPolicy { + STANDARD = 0, + NO_OWN_GOALS = 1, + ADVANCED = 2 + }; + + GoalScoringPolicy m_scoring_policy; + /** Goals data of each team scored */ std::vector m_red_scorers; std::vector m_blue_scorers; @@ -249,6 +263,9 @@ class SoccerWorld : public WorldWithRank // ------------------------------------------------------------------------ AbstractKart* getKartAtDrawingPosition(unsigned int p) const OVERRIDE { return getKart(m_team_icon_draw_id[p - 1]); } + // ------------------------------------------------------------------------ + void setGoalScoringPolicy(int value) + { m_scoring_policy = (GoalScoringPolicy)value;} }; // SoccerWorld diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 83ca839de7f..835c382a245 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -27,6 +27,7 @@ #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" #include "modes/capture_the_flag.hpp" +#include "modes/soccer_world.hpp" #include "modes/linear_world.hpp" #include "network/crypto.hpp" #include "network/event.hpp" @@ -2414,7 +2415,7 @@ void ServerLobby::update(int ticks) Log::info("ServerLobbyRoom", "Starting the race loading."); // This will create the world instance, i.e. load track and karts loadWorld(); - updateWorldScoring(); + updateWorldSettings(); m_state = WAIT_FOR_WORLD_LOADED; break; case RACING: @@ -5965,8 +5966,7 @@ void ServerLobby::handleServerCommand(Event* event, return; } - if (argv.size() != 2 || (argv[1] != "0" && argv[1] != "1") || - m_state.load() != WAITING_FOR_START_GAME) + if (argv.size() != 2 || (argv[1] != "0" && argv[1] != "1")) { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); @@ -5978,6 +5978,17 @@ void ServerLobby::handleServerCommand(Event* event, return; } + if (m_state.load() != WAITING_FOR_START_GAME) + { + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (argv[1] == "1") + m_default_always_spectate_peers.insert(peer.get()); + else + m_default_always_spectate_peers.erase(peer.get()); + return; + } + if (argv[1] == "1") { if (m_process_type == PT_CHILD && @@ -7215,12 +7226,25 @@ void ServerLobby::loadCustomScoring() } } // loadCustomScoring //----------------------------------------------------------------------------- -void ServerLobby::updateWorldScoring() +void ServerLobby::updateWorldSettings() { WorldWithRank *wwr = dynamic_cast(World::getWorld()); if (wwr) wwr->setCustomScoringSystem(m_scoring_type, m_scoring_int_params); -} // updateWorldScoring + SoccerWorld *sw = dynamic_cast(World::getWorld()); + if (sw) + { + std::string policy = ServerConfig::m_soccer_goals_policy; + if (policy == "standard") + sw->setGoalScoringPolicy(0); + else if (policy == "no-own-goals") + sw->setGoalScoringPolicy(1); + else if (policy == "advanced") + sw->setGoalScoringPolicy(2); + else + Log::warn("ServerLobby", "Soccer goals policy %s does not exist", policy.c_str()); + } +} // updateWorldSettings //----------------------------------------------------------------------------- void ServerLobby::loadWhiteList() { diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 19dac524840..eb0d5d5c4b8 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -449,7 +449,7 @@ class ServerLobby : public LobbyProtocol void sendGnuStandingsToPeer(std::shared_ptr peer) const; void sendGrandPrixStandingsToPeer(std::shared_ptr peer) const; void loadCustomScoring(); - void updateWorldScoring(); + void updateWorldSettings(); void loadWhiteList(); public: ServerLobby(); diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 6845f85e1e7..629621cc549 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -566,6 +566,16 @@ namespace ServerConfig "For a private server, a list of players who can enter with " "any password. Works only for online accounts.")); + SERVER_CFG_PREFIX BoolServerConfigParam m_expose_mobile + SERVER_CFG_DEFAULT(BoolServerConfigParam(true, "expose-mobile", + "If true, all mobile peers get a corresponding icon into the name.")); + + SERVER_CFG_PREFIX StringServerConfigParam m_soccer_goals_policy + SERVER_CFG_DEFAULT(StringServerConfigParam("standard", + "soccer-goals-policy", + "Specifies how to count own goals: standard - last touching player " + "is counted, no-own-goals - last touching player of scoring team " + "is counted if existing, advanced - as standard for now.")); // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; From 5208048baf5fd2ec30b9dc55498df76e3ffc1135 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 30 May 2020 18:51:08 +0300 Subject: [PATCH 081/830] Add expose-mobile option --- src/network/protocols/server_lobby.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 66150dabcd2..f35bb57a2b3 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4397,7 +4397,8 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) auto version_os = StringUtils::extractVersionOS(profile->getPeer()->getUserVersion()); std::string os_type_str = version_os.second; // if mobile OS - if (os_type_str == "iOS" || os_type_str == "Android") + if (ServerConfig::m_expose_mobile && + (os_type_str == "iOS" || os_type_str == "Android")) { // Add a Mobile emoji for mobile OS pl->addUInt32(profile->getHostId()).addUInt32(profile->getOnlineId()) .addUInt8(profile->getLocalPlayerId()) From d0a6e66723f5c63f52ab743f4e37b80daad390a3 Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 31 May 2020 18:04:35 +0300 Subject: [PATCH 082/830] Initial commit on June tournament changes --- src/network/protocols/server_lobby.cpp | 92 ++++++++++++++++++++++---- src/network/protocols/server_lobby.hpp | 4 ++ src/network/server_config.cpp | 17 +++-- 3 files changed, 97 insertions(+), 16 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index f35bb57a2b3..599124375ed 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1655,7 +1655,8 @@ void ServerLobby::asynchronousUpdate() updatePlayerList(); m_timeout.store(std::numeric_limits::max()); } - if (m_timeout.load() < (int64_t)StkTime::getMonoTimeMs() || + if ((!ServerConfig::m_soccer_tournament && + m_timeout.load() < (int64_t)StkTime::getMonoTimeMs()) || (checkPeersReady(true/*ignore_ai_peer*/) && (int)players >= ServerConfig::m_min_start_game_players)) { @@ -2640,10 +2641,20 @@ void ServerLobby::startSelection(const Event *event) } if (ServerConfig::m_owner_less) { - m_peers_ready.at(event->getPeerSP()) = - !m_peers_ready.at(event->getPeerSP()); - updatePlayerList(); - return; + auto peer = event->getPeerSP(); + if (!canRace(peer)) + { + std::string msg = "You cannot play so pressing ready has no action"; + sendStringToPeer(msg, peer); + return; + } + else + { + m_peers_ready.at(event->getPeerSP()) = + !m_peers_ready.at(event->getPeerSP()); + updatePlayerList(); + return; + } } if (event->getPeerSP() != m_server_owner.lock()) { @@ -2730,7 +2741,7 @@ void ServerLobby::startSelection(const Event *event) peer->setWaitingForGame(true); } - if (ServerConfig::m_soccer_tournament && m_tournament_game % 2 == 0) + if (ServerConfig::m_soccer_tournament && !tournamentHasIcy(m_tournament_game)) { tracks_erase.insert("icy_soccer_field"); } @@ -2745,7 +2756,7 @@ void ServerLobby::startSelection(const Event *event) } if (ServerConfig::m_soccer_tournament) { - if (m_tournament_game % 2 == 1) + if (tournamentHasIcy(m_tournament_game)) { if (m_available_kts.second.count("icy_soccer_field")) { @@ -4115,7 +4126,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, player->setTeam(KART_TEAM_RED); else if (m_tournament_blue_players.count(utf8_online_name)) player->setTeam(KART_TEAM_BLUE); - if (m_tournament_game & 2) + if (tournamentColorsSwapped(m_tournament_game)) { if (player->getTeam() == KART_TEAM_BLUE) player->setTeam(KART_TEAM_RED); @@ -5939,18 +5950,22 @@ bool ServerLobby::supportsAI() bool ServerLobby::checkPeersReady(bool ignore_ai_peer) const { bool all_ready = true; + bool someone_races = false; for (auto p : m_peers_ready) { auto peer = p.first.lock(); if (!peer) continue; + if (!canRace(peer)) + continue; if (ignore_ai_peer && peer->isAIPeer()) continue; + someone_races = true; all_ready = all_ready && p.second; if (!all_ready) return false; } - return true; + return someone_races; } // checkPeersReady //----------------------------------------------------------------------------- @@ -6680,10 +6695,13 @@ void ServerLobby::handleServerCommand(Event* event, } m_fixed_lap = length; } - if ((m_tournament_game ^ old_game) & 2) + if (tournamentColorsSwapped(m_tournament_game) ^ tournamentColorsSwapped(old_game)) changeColors(); + if (tournamentGoalsLimit(m_tournament_game) ^ tournamentGoalsLimit(old_game)) + changeLimitForTournament(tournamentGoalsLimit(m_tournament_game)); std::string msg = StringUtils::insertValues( - "Ready to start game %d for %d minutes", m_tournament_game, m_fixed_lap); + "Ready to start game %d for %d ", m_tournament_game, m_fixed_lap) + + (tournamentGoalsLimit(m_tournament_game) ? "goals" : "minutes"); sendStringToAllPeers(msg); } else if (argv[0] == "role") @@ -7272,4 +7290,54 @@ void ServerLobby::loadWhiteList() for (std::string& s: tokens) m_usernames_white_list.insert(s); } // loadWhiteList -//----------------------------------------------------------------------------- \ No newline at end of file +//----------------------------------------------------------------------------- +void ServerLobby::changeLimitForTournament(bool goal_target) +{ + m_game_setup->setSoccerGoalTarget(goal_target); + NetworkString* server_info = getNetworkString(); + server_info->setSynchronous(true); + server_info->addUInt8(LE_SERVER_INFO); + m_game_setup->addServerInfo(server_info); + sendMessageToPeers(server_info); + delete server_info; + updatePlayerList(); +} // changeLimitForTournament +//----------------------------------------------------------------------------- +/* +Tournament states are defined by taking the number of game modulo 8. +Below for each state the limit, colors (for first and second teams) and +icy / non-icy (listed as "addon") arena choice, are isted: +0: time, red blue, addon +1: time, red blue, icy +2: time, blue red, addon +3: time, blue red, icy +4: goals, red blue, icy +5: goals, red blue, addon +6: goals, blue red, icy +7: goals, blue red, addon +*/ +//----------------------------------------------------------------------------- +bool ServerLobby::tournamentGoalsLimit(int game) const +{ + int rem = game % 8; + if (rem < 0) + rem += 8; + return (rem >> 2) & 1; +} // tournamentGoalsLimit +//----------------------------------------------------------------------------- +bool ServerLobby::tournamentColorsSwapped(int game) const +{ + int rem = game % 8; + if (rem < 0) + rem += 8; + return (rem >> 1) & 1; +} // tournamentColorsSwapped +//----------------------------------------------------------------------------- +bool ServerLobby::tournamentHasIcy(int game) const +{ + int rem = game % 8; + if (rem < 0) + rem += 8; + return (rem ^ (rem >> 2)) & 1; +} // tournamentHasIcy +//----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index eb0d5d5c4b8..84bbd7ecdbe 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -451,6 +451,10 @@ class ServerLobby : public LobbyProtocol void loadCustomScoring(); void updateWorldSettings(); void loadWhiteList(); + void changeLimitForTournament(bool goal_target); + bool tournamentGoalsLimit(int game) const; + bool tournamentColorsSwapped(int game) const; + bool tournamentHasIcy(int game) const; public: ServerLobby(); virtual ~ServerLobby(); diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index afd27dc1fd5..bc06e38eaa8 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -353,20 +353,20 @@ void loadServerLobbyFromConfig() m_server_mode = 6; m_server_difficulty = 3; m_fixed_lap_count = 10; - if (m_server_max_players < 7) { - m_server_max_players = 7; + if (m_server_max_players < 9) { + m_server_max_players = 9; } m_voting_timeout = 15; m_soccer_goal_target = false; m_official_tracks_needed = false; - m_owner_less = false; + // m_owner_less = false; m_official_karts_threshold = 1.0f; m_official_tracks_threshold = 0.0f; m_addon_karts_threshold = 0; m_addon_tracks_threshold = 0; m_addon_arenas_threshold = 0; m_addon_soccers_threshold = 0; // maybe 1 ? - m_must_have_tracks_string = "icy_soccer_field soccer_field lasdunassoccer"; + m_must_have_tracks_string = "icy_soccer_field soccer_field lasdunassoccer addon_tournament-field"; m_team_choosing = true; m_ranked = false; m_server_configurable = false; @@ -375,6 +375,15 @@ void loadServerLobbyFromConfig() m_free_teams = true; m_validating_player = true; m_random_selects_addons = true; + if (m_owner_less) + { + m_min_start_game_players = 1; + m_start_game_counter = 1000001; + } + else + { + + } } if (m_ranked) From 89e1d633d1ea6342f54881e31296c62ecc5b085c Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 14 Jul 2020 12:52:14 +0300 Subject: [PATCH 083/830] Added tokens, hammer mode, fix role command, allow limit track choice --- CMakeLists.txt | 6 + data/{supertuxkart.1.1 => supertuxkart.git} | 0 src/network/protocols/server_lobby.cpp | 382 ++++++++++++++++---- src/network/protocols/server_lobby.hpp | 16 + src/network/server_config.hpp | 16 + src/network/stk_peer.cpp | 1 + src/network/stk_peer.hpp | 8 +- 7 files changed, 348 insertions(+), 81 deletions(-) rename data/{supertuxkart.1.1 => supertuxkart.git} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16f3f291ace..b397d11ce2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ option(USE_SYSTEM_WIIUSE "Use system WiiUse instead of the built-in version, whe option(USE_SQLITE3 "Use sqlite to manage server stats and ban list." ON) option(USE_CRYPTO_OPENSSL "Use OpenSSL instead of Nettle for cryptography in STK." ON) +option(WEB_SUPPORT "Website integration tools" OFF) CMAKE_DEPENDENT_OPTION(BUILD_RECORDER "Build opengl recorder" ON "NOT SERVER_ONLY;NOT APPLE" OFF) CMAKE_DEPENDENT_OPTION(USE_SYSTEM_SQUISH "Use system Squish library instead of the built-in version, when available." ON @@ -453,6 +454,11 @@ if(USE_SQLITE3) endif() endif() +# Web support +if(WEB_SUPPORT) + add_definitions(-DENABLE_WEB_SUPPORT) +endif() + # Set some compiler options if(UNIX OR MINGW) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") diff --git a/data/supertuxkart.1.1 b/data/supertuxkart.git similarity index 100% rename from data/supertuxkart.1.1 rename to data/supertuxkart.git diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 599124375ed..9452be9c90c 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -215,28 +215,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() } updateAddons(); - m_inverted_config_restriction = false; - m_restricting_config = true; - if (((std::string)(ServerConfig::m_only_played_tracks_string)).empty()) - m_restricting_config = false; - else - { - std::vector available_tracks = - StringUtils::split(ServerConfig::m_only_played_tracks_string, - ' ', false); - int start = 0; - if (available_tracks[0] == "not") - { - start = 1; - m_inverted_config_restriction = true; - } - for (unsigned i = start; i < available_tracks.size(); i++) - { - m_config_available_tracks.insert(available_tracks[i]); - } - } - m_must_have_tracks = StringUtils::split( - ServerConfig::m_must_have_tracks_string, ' ', false); + initAvailableTracks(); m_rs_state.store(RS_NONE); m_last_success_poll_time.store(StkTime::getMonoTimeMs() + 30000); @@ -266,9 +245,14 @@ ServerLobby::ServerLobby() : LobbyProtocol() initTournamentPlayers(); m_tournament_game = 0; } + m_allowed_to_start = true; loadTracksQueueFromConfig(); loadCustomScoring(); loadWhiteList(); +#ifdef ENABLE_WEB_SUPPORT + m_token_generation_tries.store(0); + loadAllTokens(); +#endif } // ServerLobby //----------------------------------------------------------------------------- @@ -985,6 +969,14 @@ void ServerLobby::kickHost(Event* event) // Ignore kicking ai peer if ai handling is on if (peer && (!ServerConfig::m_ai_handling || !peer->isAIPeer())) { + if (peer->isAngryHost()) + { + std::string msg = "This player is the owner of this server, " + "and is protected from your actions now"; + auto crown = event->getPeerSP(); + sendStringToPeer(msg, crown); + return; + } if (!peer->hasPlayerProfiles()) { Log::info("ServerLobby", "Crown player kicks a player"); @@ -2639,9 +2631,14 @@ void ServerLobby::startSelection(const Event *event) "An attempt to start a race on a sleeping server. Lol."); return; } + auto peer = event->getPeerSP(); if (ServerConfig::m_owner_less) { - auto peer = event->getPeerSP(); + if (!m_allowed_to_start) { + std::string msg = "Starting the game is forbidden by server owner"; + sendStringToPeer(msg, peer); + return; + } if (!canRace(peer)) { std::string msg = "You cannot play so pressing ready has no action"; @@ -2656,16 +2653,25 @@ void ServerLobby::startSelection(const Event *event) return; } } - if (event->getPeerSP() != m_server_owner.lock()) + if (!m_allowed_to_start) { + std::string msg = "Starting the game is forbidden by server owner"; + sendStringToPeer(msg, peer); + return; + } + if (peer != m_server_owner.lock()) { Log::warn("ServerLobby", "Client %d is not authorised to start selection.", event->getPeer()->getHostId()); return; } + } else { + if (!m_allowed_to_start) { + // Produce no log spam + return; + } } - if (!ServerConfig::m_owner_less && ServerConfig::m_team_choosing && !ServerConfig::m_free_teams && RaceManager::get()->teamEnabled()) { @@ -2698,7 +2704,7 @@ void ServerLobby::startSelection(const Event *event) bool can_race = canRace(peer); if (!can_race) { - if (ServerConfig::m_soccer_tournament) + if (ServerConfig::m_soccer_tournament || ServerConfig::m_only_host_riding) peer->setAlwaysSpectate(true); } if (!can_race && !peer->alwaysSpectate()) @@ -2806,7 +2812,7 @@ void ServerLobby::startSelection(const Event *event) auto it = m_available_kts.second.begin(); while (it != m_available_kts.second.end()) { - Track* t = track_manager->getTrack(*it); + Track* t = track_manager->getTrack(*it); if (t->getMaxArenaPlayers() < max_player) { it = m_available_kts.second.erase(it); @@ -2816,6 +2822,17 @@ void ServerLobby::startSelection(const Event *event) } } + auto iter = m_available_kts.second.begin(); + while (iter != m_available_kts.second.end()) + { + // Initial version which will be brought into a separate fuction + std::string track = *iter; + if (getTrackMaxPlayers(track) < max_player) + iter = m_available_kts.second.erase(iter); + else + iter++; + } + if (m_available_kts.second.empty()) { Log::error("ServerLobby", "No tracks for playing!"); @@ -4005,7 +4022,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, std::string password; data.decodeString(&password); const std::string& server_pw = ServerConfig::m_private_server_password; - if (ServerConfig::m_validating_player && online_id > 0) + if (online_id > 0) { std::string username = StringUtils::wideToUtf8(online_name); if (m_temp_banned.count(username)) @@ -4014,7 +4031,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, message->setSynchronous(true); message->addUInt8(LE_CONNECTION_REFUSED) .addUInt8(RR_BANNED); - std::string tempban = "You were banned from the server. Please behave well next time."; + std::string tempban = "Please behave well next time."; message->encodeString(tempban); peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); peer->reset(); @@ -4406,21 +4423,20 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) { // get OS information auto version_os = StringUtils::extractVersionOS(profile->getPeer()->getUserVersion()); + bool angry_host = profile->getPeer()->isAngryHost(); std::string os_type_str = version_os.second; - // if mobile OS + auto profile_name = profile->getName(); + // Add a Mobile emoji for mobile OS if (ServerConfig::m_expose_mobile && (os_type_str == "iOS" || os_type_str == "Android")) - { // Add a Mobile emoji for mobile OS - pl->addUInt32(profile->getHostId()).addUInt32(profile->getOnlineId()) - .addUInt8(profile->getLocalPlayerId()) - .encodeString(StringUtils::utf32ToWide({0x1F4F1}) + profile->getName()); - } - else - { - pl->addUInt32(profile->getHostId()).addUInt32(profile->getOnlineId()) - .addUInt8(profile->getLocalPlayerId()) - .encodeString(profile->getName()); - } + profile_name = StringUtils::utf32ToWide({0x1F4F1}) + profile_name; + // Add a hammer emoji for angry host + if (angry_host) + profile_name = StringUtils::utf32ToWide({0x1F528}) + profile_name; + + pl->addUInt32(profile->getHostId()).addUInt32(profile->getOnlineId()) + .addUInt8(profile->getLocalPlayerId()) + .encodeString(profile_name); std::shared_ptr p = profile->getPeer(); uint8_t boolean_combine = 0; @@ -5982,7 +5998,7 @@ void ServerLobby::handleServerCommand(Event* event, return; if (argv[0] == "spectate") { - if (ServerConfig::m_soccer_tournament) + if (ServerConfig::m_soccer_tournament || ServerConfig::m_only_host_riding) { std::string msg = "All spectators already have auto spectate ability"; sendStringToPeer(msg, peer); @@ -5990,25 +6006,15 @@ void ServerLobby::handleServerCommand(Event* event, } if (/*m_game_setup->isGrandPrix() || */!ServerConfig::m_live_players) { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); std::string msg = "Server doesn't support spectate"; - chat->encodeString16(StringUtils::utf8ToWide(msg)); - peer->sendPacket(chat, true/*reliable*/); - delete chat; + sendStringToPeer(msg, peer); return; } if (argv.size() != 2 || (argv[1] != "0" && argv[1] != "1")) { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); std::string msg = "Usage: spectate [0 or 1], before game started"; - chat->encodeString16(StringUtils::utf8ToWide(msg)); - peer->sendPacket(chat, true/*reliable*/); - delete chat; + sendStringToPeer(msg, peer); return; } @@ -6028,13 +6034,8 @@ void ServerLobby::handleServerCommand(Event* event, if (m_process_type == PT_CHILD && peer->getHostId() == m_client_server_host_id.load()) { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); std::string msg = "Graphical client server cannot spectate"; - chat->encodeString16(StringUtils::utf8ToWide(msg)); - peer->sendPacket(chat, true/*reliable*/); - delete chat; + sendStringToPeer(msg, peer); return; } peer->setAlwaysSpectate(true); @@ -6078,22 +6079,22 @@ void ServerLobby::handleServerCommand(Event* event, } std::set total_addons; - if(type.empty() || // not specify addon type + if (type.empty() || // not specify addon type (!type.empty() && type.compare("kart") == 0)) // list kart addon { total_addons.insert(m_addon_kts.first.begin(), m_addon_kts.first.end()); } - if(type.empty() || // not specify addon type + if (type.empty() || // not specify addon type (!type.empty() && type.compare("track") == 0)) { total_addons.insert(m_addon_kts.second.begin(), m_addon_kts.second.end()); } - if(type.empty() || // not specify addon type + if (type.empty() || // not specify addon type (!type.empty() && type.compare("arena") == 0)) { total_addons.insert(m_addon_arenas.begin(), m_addon_arenas.end()); } - if(type.empty() || // not specify addon type + if (type.empty() || // not specify addon type (!type.empty() && type.compare("soccer") == 0)) { total_addons.insert(m_addon_soccers.begin(), m_addon_soccers.end()); @@ -6211,6 +6212,13 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; } + else if (player_peer->isAngryHost()) + { + std::string msg = "This player is the owner of this server, " + "and is protected from your actions now"; + sendStringToPeer(msg, peer); + return; + } else { Log::info("ServerLobby", "Crown player kicks %s", player_name.c_str()); @@ -6221,19 +6229,30 @@ void ServerLobby::handleServerCommand(Event* event, } if (StringUtils::startsWith(cmd, "kickban")) { - Log::info("ServerLobby", "%s is now banned", player_name.c_str()); - m_temp_banned.insert(player_name); + if (peer->isAngryHost() || ServerConfig::m_soccer_tournament) + { + Log::info("ServerLobby", "%s is now banned", player_name.c_str()); + m_temp_banned.insert(player_name); + std::string msg = StringUtils::insertValues( + "%s is now banned", player_name.c_str()); + sendStringToPeer(msg, peer); + } + else + { + std::string msg = "You cannot ban players"; + sendStringToPeer(msg, peer); + } } } } else if (StringUtils::startsWith(cmd, "unban")) { - if (!hasHostRights(peer)) + if (!hasHostRights(peer) || !(peer->isAngryHost() || ServerConfig::m_soccer_tournament)) { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); - chat->encodeString16(L"You are not server owner"); + chat->encodeString16(L"You cannot unban players"); peer->sendPacket(chat, true/*reliable*/); delete chat; return; @@ -6255,18 +6274,21 @@ void ServerLobby::handleServerCommand(Event* event, } else { + std::string msg = StringUtils::insertValues( + "%s is now unbanned", player_name.c_str()); Log::info("ServerLobby", "%s is now unbanned", player_name.c_str()); m_temp_banned.erase(player_name); + sendStringToPeer(msg, peer); } } else if (StringUtils::startsWith(cmd, "ban")) { - if (!hasHostRights(peer)) + if (!hasHostRights(peer) || !(peer->isAngryHost() || ServerConfig::m_soccer_tournament)) { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); - chat->encodeString16(L"You are not server owner"); + chat->encodeString16(L"You cannot ban players"); peer->sendPacket(chat, true/*reliable*/); delete chat; return; @@ -6290,6 +6312,9 @@ void ServerLobby::handleServerCommand(Event* event, { Log::info("ServerLobby", "%s is now banned", player_name.c_str()); m_temp_banned.insert(player_name); + std::string msg = StringUtils::insertValues( + "%s is now banned", player_name.c_str()); + sendStringToPeer(msg, peer); } } else if (StringUtils::startsWith(cmd, "playeraddonscore")) @@ -6658,6 +6683,94 @@ void ServerLobby::handleServerCommand(Event* event, peer->sendPacket(chat, true/*reliable*/); delete chat; } + else if (argv[0] == "power") + { + if (peer->isAngryHost()) + { + peer->setAngryHost(false); + std::string msg = "You are now a normal player"; + sendStringToPeer(msg, peer); + updatePlayerList(); + return; + } + std::string password = ServerConfig::m_power_password; + if (password.empty() || argv.size() <= 1 || argv[1] != password) + { + std::string msg = "You need to provide the password to have the power"; + sendStringToPeer(msg, peer); + return; + } + peer->setAngryHost(true); + std::string msg = "Now you finally have the power!"; + sendStringToPeer(msg, peer); + updatePlayerList(); + return; + } + else if (argv[0] == "admin") + { + std::string msg; + if (!peer->isAngryHost() && !ServerConfig::m_soccer_tournament) { + msg = "You cannot control this server"; + sendStringToPeer(msg, peer); + return; + } + if (argv.size() == 1) { + msg = "Usage: /admin command arg1 arg2 ..."; + sendStringToPeer(msg, peer); + return; + } + if (argv[1] == "start") { + if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) { + msg = "Usage: /admin start [0/1] - allow or forbid starting a race"; + sendStringToPeer(msg, peer); + return; + } + if (argv[2] == "0") { + m_allowed_to_start = false; + msg = "Now starting a race is forbidden"; + } else { + m_allowed_to_start = true; + msg = "Now starting a race is allowed"; + } + sendStringToPeer(msg, peer); + return; + } + } +#ifdef ENABLE_WEB_SUPPORT + else if (argv[0] == "token") + { + int online_id = peer->getPlayerProfiles()[0]->getOnlineId(); + if (online_id <= 0) + { + std::string msg = "Please join with a valid online STK account."; + sendStringToPeer(msg, peer); + return; + } + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + std::string token = getToken(); + while (m_web_tokens.count(token)) + token = getToken(); + m_web_tokens.insert(token); + std::string msg = "Your token is " + token; +#ifdef ENABLE_SQLITE3 + std::string tokens_table_name = ServerConfig::m_tokens_table; + std::string query = StringUtils::insertValues( + "INSERT INTO %s (username, token) " + "VALUES (\"%s\", \"%s\");", + tokens_table_name.c_str(), username.c_str(), token.c_str() + ); + if (easySQLQuery(query)) + msg += "\nRetype it to log in with your STK account. " + "Do not tell it to anyone!"; + else + msg = "An error occurred, please try again."; +#else + msg += "\nThough it is useless..."; +#endif + sendStringToPeer(msg, peer); + } +#endif else if (ServerConfig::m_soccer_tournament) { std::string peer_username = StringUtils::wideToUtf8( @@ -6733,14 +6846,14 @@ void ServerLobby::handleServerCommand(Event* event, case 'R': case 'r': { - m_tournament_red_players.insert(username); if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, "first team player"); - if (m_tournament_game & 2) - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_BLUE); + role_changed = StringUtils::insertValues(role_changed, "red player"); + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_RED); + if (tournamentColorsSwapped(m_tournament_game)) + m_tournament_blue_players.insert(username); else - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_RED); + m_tournament_red_players.insert(username); sendStringToPeer(role_changed, player_peer); } break; @@ -6748,14 +6861,14 @@ void ServerLobby::handleServerCommand(Event* event, case 'B': case 'b': { - m_tournament_blue_players.insert(username); if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, "second team player"); - if (m_tournament_game & 2) - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_RED); + role_changed = StringUtils::insertValues(role_changed, "blue player"); + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_BLUE); + if (tournamentColorsSwapped(m_tournament_game)) + m_tournament_red_players.insert(username); else - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_BLUE); + m_tournament_blue_players.insert(username); sendStringToPeer(role_changed, player_peer); } break; @@ -7182,6 +7295,8 @@ bool ServerLobby::hasHostRights(STKPeer* peer) const { if (peer == m_server_owner.lock().get()) return true; + if (peer->isAngryHost()) + return true; std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); if (ServerConfig::m_soccer_tournament) @@ -7341,3 +7456,110 @@ bool ServerLobby::tournamentHasIcy(int game) const return (rem ^ (rem >> 2)) & 1; } // tournamentHasIcy //----------------------------------------------------------------------------- +void ServerLobby::initAvailableTracks() +{ + m_must_have_tracks = StringUtils::split( + ServerConfig::m_must_have_tracks_string, ' ', false); + m_inverted_config_restriction = false; + m_restricting_config = true; + if (((std::string)(ServerConfig::m_only_played_tracks_string)).empty()) + { + m_restricting_config = false; + return; + } + std::vector available_tracks = + StringUtils::split(ServerConfig::m_only_played_tracks_string, + ' ', false); + + for (unsigned i = 0; i < available_tracks.size(); i++) + if (available_tracks[i] == "not") + m_inverted_config_restriction = true; + + for (unsigned i = 0; i < available_tracks.size(); i++) + { + if (available_tracks[i] == "not") + continue; + int separator = available_tracks[i].find(':'); + if (separator != std::string::npos) + { + std::string track = available_tracks[i].substr(0, separator); + std::string params_str = available_tracks[i].substr(separator + 1); + std::vector params = StringUtils::split( + params_str, ',', false); + m_config_track_limitations[track] = params; + } + else + m_config_available_tracks.insert(available_tracks[i]); + } +} // initAvailableTracks +//----------------------------------------------------------------------------- +int ServerLobby::getTrackMaxPlayers(std::string& name) const +{ + auto map_entry = m_config_track_limitations.find(name); + if (map_entry == m_config_track_limitations.end()) + return INT_MAX; + std::string key = "max_players"; + auto map_value = map_entry->second; + auto where = std::find(map_value.begin(), map_value.end(), key); + auto end = map_value.end(); + if (where == end) + return INT_MAX; + where++; + if (where == end) + return INT_MAX; + int track_max_players; + std::string max_str = *where; + if (!StringUtils::parseString(max_str, &track_max_players)) + { + Log::warn("ServerLobby", "Bad max_players value for track %s", name.c_str()); + return INT_MAX; + } + return track_max_players; +} // getTrackMaxPlayers +//----------------------------------------------------------------------------- + +#ifdef ENABLE_WEB_SUPPORT + +void ServerLobby::loadAllTokens() +{ +#ifdef ENABLE_SQLITE3 + std::string tokens_table_name = ServerConfig::m_tokens_table; + std::string get_query = StringUtils::insertValues( + "SELECT distinct tokens from %s;", + tokens_table_name.c_str()); + auto ret = vectorSQLQuery(get_query, 1); + if (!ret.first) + { + Log::warn("ServerLobby", "Could not make a query to retrieve tokens."); + } + else if (ret.second[0].size() > 0) + { + Log::info("ServerLobby", "Successfully loaded %d tokens.", (int)ret.second[0].size()); + for (std::string& s: ret.second[0]) + m_web_tokens.insert(s); + } +#endif +} // loadAllTokens +//----------------------------------------------------------------------------- + +std::string ServerLobby::getToken() +{ + int tries = m_token_generation_tries.load(); + m_token_generation_tries.store(tries + 1); + std::mt19937 mt(time(nullptr) + tries); + std::string token; + for (int i = 0; i < 16; ++i) { + int z = mt() % 36; + if (z < 26) + token.push_back('a' + z); + else + token.push_back('0' + z - 26); + if ((i & 3) == 3) + token.push_back(' '); + } + token.pop_back(); + return token; +} // getToken +//----------------------------------------------------------------------------- + +#endif // ENABLE_WEB_SUPPORT \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 84bbd7ecdbe..4fcd912bd78 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -273,6 +273,8 @@ class ServerLobby : public LobbyProtocol std::set m_config_available_tracks; + std::map> m_config_track_limitations; + irr::core::stringw m_help_message; std::string m_available_commands; @@ -317,6 +319,14 @@ class ServerLobby : public LobbyProtocol std::set m_usernames_white_list; + bool m_allowed_to_start; + +#ifdef ENABLE_WEB_SUPPORT + std::set m_web_tokens; + + std::atomic m_token_generation_tries; +#endif + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); @@ -455,6 +465,10 @@ class ServerLobby : public LobbyProtocol bool tournamentGoalsLimit(int game) const; bool tournamentColorsSwapped(int game) const; bool tournamentHasIcy(int game) const; +#ifdef ENABLE_WEB_SUPPORT + void loadAllTokens(); + std::string getToken(); +#endif public: ServerLobby(); virtual ~ServerLobby(); @@ -492,9 +506,11 @@ class ServerLobby : public LobbyProtocol void storeResults(); uint32_t getServerIdOnline() const { return m_server_id_online; } void setClientServerHostId(uint32_t id) { m_client_server_host_id = id; } + void initAvailableTracks(); void initAvailableModes(); void resetToDefaultSettings(); void writeOwnReport(STKPeer* reporter, STKPeer* reporting, const std::string& info); + int getTrackMaxPlayers(std::string& name) const; }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 629621cc549..d360ca8d873 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -576,6 +576,22 @@ namespace ServerConfig "Specifies how to count own goals: standard - last touching player " "is counted, no-own-goals - last touching player of scoring team " "is counted if existing, advanced - as standard for now.")); + +#ifdef ENABLE_WEB_SUPPORT + + SERVER_CFG_PREFIX StringServerConfigParam m_tokens_table + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "tokens-table", + "A table containing tokens for website authentication using " + "STK account only.")); +#endif + + SERVER_CFG_PREFIX StringServerConfigParam m_power_password + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "power-password", + "Allows server owner (not crowned player!) to go to power mode " + "to kick players using GUI and not be kicked, empty to disable.")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; diff --git a/src/network/stk_peer.cpp b/src/network/stk_peer.cpp index 92f0938f7bd..70889ef080c 100644 --- a/src/network/stk_peer.cpp +++ b/src/network/stk_peer.cpp @@ -53,6 +53,7 @@ STKPeer::STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id) m_warned_for_high_ping.store(false); m_last_activity.store((int64_t)StkTime::getMonoTimeMs()); m_last_message.store(0); + m_angry_host.store(false); m_consecutive_messages = 0; } // STKPeer diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index 26cb4889c40..4e4ec775bd9 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -124,6 +124,8 @@ class STKPeer : public NoCopy std::set m_client_capabilities; std::array m_addons_scores; + + std::atomic_bool m_angry_host; public: STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id); // ------------------------------------------------------------------------ @@ -305,7 +307,11 @@ class STKPeer : public NoCopy void setAlwaysSpectate(bool val) { m_always_spectate.store(val); } // ------------------------------------------------------------------------ bool alwaysSpectate() const { return m_always_spectate.load(); } - + // ------------------------------------------------------------------------ + bool isAngryHost() const { return m_angry_host.load(); } + // ------------------------------------------------------------------------ + void setAngryHost(bool val) { m_angry_host.store(val); } + // ------------------------------------------------------------------------ }; // STKPeer #endif // STK_PEER_HPP From 3c2ac2396adae17f9d6bc040ea2c4fd539a41c50 Mon Sep 17 00:00:00 2001 From: Denis Kim Date: Wed, 15 Jul 2020 14:52:20 +0300 Subject: [PATCH 084/830] Make changes description more clear in README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c8eba56d4fa..0cb53923650 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ The SuperTuxKart homepage can be found at . There is Latest release binaries can be found [here](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart/1.0/). +**You are viewing a modified version of STK**, most important changes are listed [here](/FORK_CHANGES.md). + ## Hardware Requirements To run SuperTuxKart, make sure that your computer's specifications are equal or higher than the following specifications: From a125d4edbba7e7597a1976216222d0b0cc0357f4 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 21 Jul 2020 16:12:13 +0300 Subject: [PATCH 085/830] Change token label --- src/network/protocols/server_lobby.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index a3c2c193d11..ad116ab22a5 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6761,8 +6761,7 @@ void ServerLobby::handleServerCommand(Event* event, tokens_table_name.c_str(), username.c_str(), token.c_str() ); if (easySQLQuery(query)) - msg += "\nRetype it to log in with your STK account. " - "Do not tell it to anyone!"; + msg += "\nRetype it on the website to connect your STK account. "; else msg = "An error occurred, please try again."; #else @@ -7562,4 +7561,4 @@ std::string ServerLobby::getToken() } // getToken //----------------------------------------------------------------------------- -#endif // ENABLE_WEB_SUPPORT \ No newline at end of file +#endif // ENABLE_WEB_SUPPORT From c46966727fba84f31d279329bd45d6d2d2767fab Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 25 Jul 2020 03:29:28 +0300 Subject: [PATCH 086/830] Add possibility to forbid kicks --- NETWORKING.md | 3 +++ src/network/protocols/server_lobby.cpp | 13 +++++++++++++ src/network/server_config.hpp | 5 +++++ 3 files changed, 21 insertions(+) diff --git a/NETWORKING.md b/NETWORKING.md index 89de22d766a..992408b0177 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -269,6 +269,9 @@ The current server configuration xml looks like this (this is only an example, j + + + ``` diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 5014d8d6f58..1e1f2aed99f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -967,6 +967,13 @@ void ServerLobby::kickHost(Event* event) { if (m_server_owner.lock() != event->getPeerSP()) return; + if (!ServerConfig::m_kicks_allowed) + { + std::string msg = "Kicking players is not allowed on this server"; + auto crown = event->getPeerSP(); + sendStringToPeer(msg, crown); + return; + } if (!checkDataSize(event, 4)) return; NetworkString& data = event->data(); uint32_t host_id = data.getUInt32(); @@ -6233,6 +6240,12 @@ void ServerLobby::handleServerCommand(Event* event, } else { + if (!peer->isAngryHost() && !ServerConfig::m_kicks_allowed) + { + std::string msg = "Kicking players is not allowed on this server"; + sendStringToPeer(msg, peer); + return; + } Log::info("ServerLobby", "Crown player kicks %s", player_name.c_str()); player_peer->kick(); if (ServerConfig::m_track_kicks) { diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index e5aa0bd6395..155acc5578b 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -597,6 +597,11 @@ namespace ServerConfig "If true this server will allow AI instance to be connected from " "anywhere. (other than LAN network only)")); + SERVER_CFG_PREFIX BoolServerConfigParam m_kicks_allowed + SERVER_CFG_DEFAULT(BoolServerConfigParam(true, "kicks-allowed", + "If true, the server owner can kick players, either via " + "the UI button or using /kick command.")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; From 3ea1f8f09d7604e550ec087c7663eb0e623bf496 Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 3 Aug 2020 16:38:42 +0300 Subject: [PATCH 087/830] Generalize tournament mode --- src/modes/soccer_world.cpp | 152 ++++++++-- src/modes/soccer_world.hpp | 30 +- src/network/protocols/server_lobby.cpp | 393 ++++++++++++++++++++----- src/network/protocols/server_lobby.hpp | 29 +- src/network/server_config.cpp | 2 +- src/network/server_config.hpp | 21 +- src/utils/track_filter.cpp | 183 ++++++++++++ src/utils/track_filter.hpp | 54 ++++ 8 files changed, 770 insertions(+), 94 deletions(-) create mode 100644 src/utils/track_filter.cpp create mode 100644 src/utils/track_filter.hpp diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp index 909b31f386d..f7b40351f82 100644 --- a/src/modes/soccer_world.cpp +++ b/src/modes/soccer_world.cpp @@ -247,6 +247,12 @@ SoccerWorld::SoccerWorld() : WorldWithRank() WorldStatus::setClockMode(CLOCK_CHRONO); } + stopped = false; + m_explicit_stop = false; + m_bad_red_goals = 0; + m_bad_blue_goals = 0; + m_init_red_goals = 0; + m_init_blue_goals = 0; m_frame_count = 0; m_use_highscores = false; m_red_ai = 0; @@ -387,6 +393,7 @@ void SoccerWorld::reset(bool restart) //----------------------------------------------------------------------------- void SoccerWorld::onGo() { + Log::info("SoccerWorld", "The game starts now."); m_ball->setEnabled(true); m_ball->reset(); WorldWithRank::onGo(); @@ -430,6 +437,20 @@ void SoccerWorld::update(int ticks) WorldWithRank::update(ticks); WorldWithRank::updateTrack(ticks); + // if (stopped) + // { + // for (unsigned int i = 0; i < m_karts.size(); i++) + // { + // auto& kart = m_karts[i]; + // if (kart->isEliminated()) + // continue; + // kart->getBody()->setLinearVelocity(Vec3(0.0f)); + // kart->getBody()->setAngularVelocity(Vec3(0.0f)); + // kart->getBody()->proceedToTransform(m_goal_transforms[i]); + // kart->setTrans(m_goal_transforms[i]); + // } + // } + if (isGoalPhase()) { for (unsigned int i = 0; i < m_karts.size(); i++) @@ -535,19 +556,34 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) } std::string team_name = (first_goal ? "red team" : "blue team"); std::string player_name = StringUtils::wideToUtf8(sd.m_player); - if (sd.m_correct_goal) - { - Log::info("SoccerWorld", "[Goal] %s scored a goal for %s", - player_name.c_str(), team_name.c_str()); - m_karts[sd.m_id]->getKartModel() - ->setAnimation(KartModel::AF_WIN_START, true/* play_non_loop*/); - } - else if (!sd.m_correct_goal) + // if (!stopped) + // { + if (sd.m_correct_goal) + { + if (!stopped) + Log::info("SoccerWorld", "[Goal] %s scored a goal for %s", + player_name.c_str(), team_name.c_str()); + m_karts[sd.m_id]->getKartModel() + ->setAnimation(KartModel::AF_WIN_START, true/* play_non_loop*/); + } + else if (!sd.m_correct_goal) + { + if (!stopped) + Log::info("SoccerWorld", "[Goal] %s scored an own goal for %s", + player_name.c_str(), team_name.c_str()); + m_karts[sd.m_id]->getKartModel() + ->setAnimation(KartModel::AF_LOSE_START, true/* play_non_loop*/); + } + // } + + if (stopped) { - Log::info("SoccerWorld", "[Goal] %s scored an own goal for %s", - player_name.c_str(), team_name.c_str()); - m_karts[sd.m_id]->getKartModel() - ->setAnimation(KartModel::AF_LOSE_START, true/* play_non_loop*/); + if (first_goal) + ++m_bad_red_goals; + else + ++m_bad_blue_goals; + player_name += " (not counted)"; + sd.m_player = StringUtils::utf8ToWide(player_name); } #ifndef SERVER_ONLY @@ -575,7 +611,8 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) sd.m_time = getTime(); // Notice: true first_goal means it's blue goal being shoot, // so red team can score - m_red_scorers.push_back(sd); + // if (!stopped) + m_red_scorers.push_back(sd); } else { @@ -585,7 +622,8 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) } else sd.m_time = getTime(); - m_blue_scorers.push_back(sd); + // if (!stopped) + m_blue_scorers.push_back(sd); } if (NetworkConfig::get()->isNetworking() && NetworkConfig::get()->isServer()) @@ -601,6 +639,7 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) NetworkString p_1_1 = p; p_1_1.encodeString(sd.m_country_code) .addUInt8(sd.m_handicap_level); + auto peers = STKHost::get()->getPeers(); for (auto& peer : peers) { @@ -617,6 +656,9 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) } } } + + // if you tell me how to make ServerLobby send that, i'd be glad + tellCountIfDiffers(); } } for (unsigned i = 0; i < m_karts.size(); i++) @@ -626,6 +668,13 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) kart->getBody()->setAngularVelocity(Vec3(0.0f)); m_goal_transforms[i] = kart->getBody()->getWorldTransform(); } + // if (stopped) + // { + // m_red_scorers = m_backup_red_scorers; + // m_blue_scorers = m_backup_blue_scorers; + // m_reset_ball_ticks = m_backup_reset_ball_ticks; + // m_ticks_back_to_own_goal = m_backup_ticks_back_to_own_goal; + // } } // onCheckGoalTriggered //----------------------------------------------------------------------------- @@ -772,7 +821,7 @@ void SoccerWorld::setBallHitter(unsigned int kart_id) */ bool SoccerWorld::isRaceOver() { - if (m_unfair_team) + if (m_unfair_team || m_explicit_stop) return true; if (RaceManager::get()->hasTimeTarget()) @@ -782,8 +831,10 @@ bool SoccerWorld::isRaceOver() // One team scored the target goals ... else { - return (getScore(KART_TEAM_BLUE) >= m_goal_target || - getScore(KART_TEAM_RED) >= m_goal_target); + return (getScore(KART_TEAM_BLUE) + m_init_blue_goals + - m_bad_blue_goals >= m_goal_target || + getScore(KART_TEAM_RED) + m_init_red_goals + - m_bad_red_goals >= m_goal_target); } } // isRaceOver @@ -1201,3 +1252,70 @@ void SoccerWorld::getKartsDisplayInfo( } } } // getKartsDisplayInfo +// ---------------------------------------------------------------------------- + +void SoccerWorld::stop() +{ + stopped = true; + Log::info("SoccerWorld", "The game is stopped."); + + m_backup_red_scorers = m_red_scorers; + m_backup_blue_scorers = m_blue_scorers; + m_backup_reset_ball_ticks = m_reset_ball_ticks; + m_backup_ticks_back_to_own_goal = m_ticks_back_to_own_goal; + + // resetKartsToSelfGoals(); + // if (UserConfigParams::m_arena_ai_stats) + // getKart(8)->flyUp(); +} // stop +// ---------------------------------------------------------------------------- + +void SoccerWorld::resume() +{ + stopped = false; + Log::info("SoccerWorld", "The game is resumed."); + + // m_red_scorers = m_backup_red_scorers; + // m_blue_scorers = m_backup_blue_scorers; + // m_reset_ball_ticks = m_backup_reset_ball_ticks; + // m_ticks_back_to_own_goal = m_backup_ticks_back_to_own_goal; +} // resume +// ---------------------------------------------------------------------------- + +void SoccerWorld::setInitialCount(int red, int blue) +{ + m_init_red_goals = red; + m_init_blue_goals = blue; +} // setInitialCount +// ---------------------------------------------------------------------------- + +void SoccerWorld::tellCount() const +{ + auto peers = STKHost::get()->getPeers(); + NetworkString* chat = new NetworkString(PROTOCOL_LOBBY_ROOM); + chat->addUInt8(17); // LE_CHAT + chat->setSynchronous(true); + int real_red = (int)m_red_scorers.size() - m_bad_red_goals + + m_init_red_goals; + int real_blue = (int)m_blue_scorers.size() - m_bad_blue_goals + + m_init_blue_goals; + std::string real_count = + std::to_string(real_red) + " : " + std::to_string(real_blue); + chat->encodeString16(StringUtils::utf8ToWide(real_count)); + for (auto& peer : peers) + if (peer->isValidated() && !peer->isWaitingForGame()) + peer->sendPacket(chat, true/*reliable*/); + + delete chat; +} // tellCount +// ---------------------------------------------------------------------------- + +void SoccerWorld::tellCountIfDiffers() const +{ + if (m_init_red_goals - m_bad_red_goals != 0 || + m_init_blue_goals - m_bad_blue_goals != 0) + { + tellCount(); + } +} // tellCountIfDiffers +// ---------------------------------------------------------------------------- diff --git a/src/modes/soccer_world.hpp b/src/modes/soccer_world.hpp index 0e641b46106..e6cfdc20d41 100644 --- a/src/modes/soccer_world.hpp +++ b/src/modes/soccer_world.hpp @@ -44,7 +44,7 @@ class SoccerWorld : public WorldWithRank { /** World ID of kart which scores. */ unsigned int m_id; - /** Whether this goal is socred correctly (identify for own goal). */ + /** Whether this goal is scored correctly (identify for own goal). */ bool m_correct_goal; /** Time goal. */ float m_time; @@ -122,6 +122,8 @@ class SoccerWorld : public WorldWithRank std::vector m_team_icon_draw_id; + bool stopped; + std::vector m_goal_transforms; /** Function to update the location the ball on the polygon map */ void updateBallPosition(int ticks); @@ -139,6 +141,18 @@ class SoccerWorld : public WorldWithRank void resetKartsToSelfGoals(); + + std::vector m_backup_red_scorers; + std::vector m_backup_blue_scorers; + int m_backup_reset_ball_ticks; + int m_backup_ticks_back_to_own_goal; + + bool m_explicit_stop; + int m_bad_red_goals; + int m_bad_blue_goals; + int m_init_red_goals; + int m_init_blue_goals; + public: SoccerWorld(); @@ -266,6 +280,20 @@ class SoccerWorld : public WorldWithRank // ------------------------------------------------------------------------ void setGoalScoringPolicy(int value) { m_scoring_policy = (GoalScoringPolicy)value;} + // ------------------------------------------------------------------------ + void stop(); + // ------------------------------------------------------------------------ + void resume(); + // ------------------------------------------------------------------------ + void allToLobby() { m_explicit_stop = true; } + // ------------------------------------------------------------------------ + void setInitialCount(int red, int blue); + // ------------------------------------------------------------------------ + void tellCount() const; + // ------------------------------------------------------------------------ + void tellCountIfDiffers() const; + // ------------------------------------------------------------------------ + bool getStopped() { return stopped; } }; // SoccerWorld diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 1e1f2aed99f..80b1b8764d7 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -725,7 +725,7 @@ void ServerLobby::updateTracksForMode() assert(false); break; } - if (m_restricting_config) + /*if (m_restricting_config) { std::set erase_tracks; auto it = m_available_kts.second.begin(); @@ -740,7 +740,7 @@ void ServerLobby::updateTracksForMode() for (const std::string& track : erase_tracks) { m_available_kts.second.erase(track); } - } + }*/ m_entering_kts = m_available_kts; } // updateTracksForMode @@ -883,10 +883,35 @@ void ServerLobby::handleChat(Event* event) std::set teams; for (auto& profile: sender->getPlayerProfiles()) teams.insert(profile->getTeam()); + bool tournament_limit = false; + std::set important_players; + if (ServerConfig::m_soccer_tournament && m_tournament_limited_chat) + { + tournament_limit = true; + for (auto& profile: sender->getPlayerProfiles()) + { + std::string name = StringUtils::wideToUtf8( + profile->getName()); + if (m_tournament_referees.count(name) > 0 || + m_tournament_red_players.count(name) > 0 || + m_tournament_blue_players.count(name) > 0) + tournament_limit = false; + } + } + if (tournament_limit) + { + for (const std::string& s: m_tournament_referees) + important_players.insert(s); + for (const std::string& s: m_tournament_red_players) + important_players.insert(s); + for (const std::string& s: m_tournament_blue_players) + important_players.insert(s); + } STKHost::get()->sendPacketToAllPeersWith( [game_started, sender_in_game, target_team, can_receive, - sender, team_speak, teams](STKPeer* p) + sender, team_speak, teams, tournament_limit, + important_players](STKPeer* p) { if (sender == p) return true; @@ -896,6 +921,21 @@ void ServerLobby::handleChat(Event* event) return false; if (!p->isWaitingForGame() && sender_in_game) return false; + if (tournament_limit) { + bool all_are_important = true; + for (auto& player : p->getPlayerProfiles()) + { + std::string name = StringUtils::wideToUtf8( + player->getName()); + if (important_players.count(name) == 0) + { + all_are_important = false; + break; + } + } + if (all_are_important) + return false; + } if (target_team != KART_TEAM_NONE) { if (p->isSpectator()) @@ -1742,6 +1782,8 @@ void ServerLobby::asynchronousUpdate() ItemManager::updateRandomSeed(m_item_seed); m_game_setup->setRace(winner_vote); std::string track_name = winner_vote.m_track_name; + if (ServerConfig::m_soccer_tournament) + m_tournament_arenas[m_tournament_game] = track_name; auto peers = STKHost::get()->getPeers(); std::set bad_spectators; for (auto peer : peers) @@ -2759,10 +2801,10 @@ void ServerLobby::startSelection(const Event *event) peer->setWaitingForGame(true); } - if (ServerConfig::m_soccer_tournament && !tournamentHasIcy(m_tournament_game)) - { - tracks_erase.insert("icy_soccer_field"); - } + // if (ServerConfig::m_soccer_tournament && !tournamentHasIcy(m_tournament_game)) + // { + // tracks_erase.insert("icy_soccer_field"); + // } for (const std::string& kart_erase : karts_erase) { @@ -2772,22 +2814,22 @@ void ServerLobby::startSelection(const Event *event) { m_available_kts.second.erase(track_erase); } - if (ServerConfig::m_soccer_tournament) - { - if (tournamentHasIcy(m_tournament_game)) - { - if (m_available_kts.second.count("icy_soccer_field")) - { - m_available_kts.second.clear(); - m_available_kts.second.insert("icy_soccer_field"); - } - else - { - m_available_kts.second.clear(); - } - } - } - else if (!m_tracks_queue.empty()) + // if (ServerConfig::m_soccer_tournament) + // { + // if (tournamentHasIcy(m_tournament_game)) + // { + // if (m_available_kts.second.count("icy_soccer_field")) + // { + // m_available_kts.second.clear(); + // m_available_kts.second.insert("icy_soccer_field"); + // } + // else + // { + // m_available_kts.second.clear(); + // } + // } + // } + if (!m_tracks_queue.empty()) { m_available_kts.second.clear(); m_available_kts.second.insert(m_tracks_queue.front()); @@ -2833,8 +2875,14 @@ void ServerLobby::startSelection(const Event *event) it++; } } - - auto iter = m_available_kts.second.begin(); + + m_global_filter.apply(max_player, m_available_kts.second); + if (ServerConfig::m_soccer_tournament) + { + m_tournament_track_filters[m_tournament_game].apply( + max_player, m_available_kts.second, m_tournament_arenas); + } + /* auto iter = m_available_kts.second.begin(); while (iter != m_available_kts.second.end()) { // Initial version which will be brought into a separate fuction @@ -2843,7 +2891,7 @@ void ServerLobby::startSelection(const Event *event) iter = m_available_kts.second.erase(iter); else iter++; - } + }*/ if (m_available_kts.second.empty()) { @@ -3201,6 +3249,15 @@ void ServerLobby::checkRaceFinished() assert(World::getWorld()); if (!RaceEventManager::get()->isRaceOver()) return; + if (ServerConfig::m_soccer_tournament) + { + World* w = World::getWorld(); + if (w) + { + SoccerWorld *sw = dynamic_cast(w); + sw->tellCountIfDiffers(); + } + } Log::info("ServerLobby", "The game is considered finished."); // notify the network world that it is stopped RaceEventManager::get()->stop(); @@ -3960,8 +4017,18 @@ void ServerLobby::connectionRequested(Event* event) unsigned total_players = 0; STKHost::get()->updatePlayers(NULL, NULL, &total_players); + unsigned max_players_mode = (unsigned)ServerConfig::m_server_max_players; + if (RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_FREE_FOR_ALL) + max_players_mode = std::min(10, max_players_mode); + if (RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) + max_players_mode = std::min(14, max_players_mode); + if (RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_SOCCER) + max_players_mode = std::min(14, max_players_mode); if (total_players + player_count + m_ai_profiles.size() > - (unsigned)ServerConfig::m_server_max_players) + max_players_mode) { NetworkString *message = getNetworkString(2); message->setSynchronous(true); @@ -5529,6 +5596,20 @@ void ServerLobby::handleServerConfiguration(Event* event) new_game_mode = data.getUInt8(); new_soccer_goal_target = data.getUInt8() == 1; } + unsigned total_players = 0; + STKHost::get()->updatePlayers(NULL, NULL, &total_players); + if ((new_game_mode == 6 && total_players > 14) || + (new_game_mode == 7 && total_players > 10) || + (new_game_mode == 8 && total_players > 14)) + { + Log::error("ServerLobby", "Too many players (%d) to change mode to %d.", + total_players, new_game_mode); + auto peer = event->getPeerSP(); + std::string msg = "Too many players present to activate this mode. " + "Soccer and CTF require at most 14, and FFA requires at most 10."; + sendStringToPeer(msg, peer); + return; + } // Actually event == NULL implies no errors... if (event != NULL && (m_available_difficulties.count(new_difficulty) == 0 || @@ -6761,6 +6842,11 @@ void ServerLobby::handleServerCommand(Event* event, return; } } + else if (argv[0] == "version") + { + std::string msg = "1.2-rc1-kimden 200728"; + sendStringToPeer(msg, peer); + } #ifdef ENABLE_WEB_SUPPORT else if (argv[0] == "token") { @@ -6809,12 +6895,17 @@ void ServerLobby::handleServerCommand(Event* event, int old_game = m_tournament_game; if (argv.size() < 2) { ++m_tournament_game; + if (m_tournament_game == m_tournament_max_games) + m_tournament_game = 0; m_fixed_lap = 10; } else { - if (!StringUtils::parseString(argv[1], &m_tournament_game)) + if (!StringUtils::parseString(argv[1], &m_tournament_game) + || m_tournament_game < 0 + || m_tournament_game >= m_tournament_max_games) { std::string msg = "Please specify a correct number. " - "Format: /game [number] [length]"; + "Format: /game [number 0.." + + std::to_string(m_tournament_max_games - 1) + "] [length]"; sendStringToPeer(msg, peer); return; } @@ -6851,6 +6942,8 @@ void ServerLobby::handleServerCommand(Event* event, } std::string role = argv[1]; std::string username = argv[2]; + bool permanent = (argv.size() >= 4 && + (argv[3] == "p" || argv[3] == "permanent")); if (role.length() != 1) std::swap(role, username); if (role.length() != 1) @@ -6862,6 +6955,12 @@ void ServerLobby::handleServerCommand(Event* event, m_tournament_red_players.erase(username); m_tournament_blue_players.erase(username); m_tournament_referees.erase(username); + if (permanent) + { + m_tournament_init_red.erase(username); + m_tournament_init_blue.erase(username); + m_tournament_init_ref.erase(username); + } std::string role_changed = "The referee has updated your role - you are now %s"; std::shared_ptr player_peer = STKHost::get()->findPeerByName( StringUtils::utf8ToWide(username)); @@ -6875,9 +6974,17 @@ void ServerLobby::handleServerCommand(Event* event, role_changed = StringUtils::insertValues(role_changed, "red player"); player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_RED); if (tournamentColorsSwapped(m_tournament_game)) + { m_tournament_blue_players.insert(username); + if (permanent) + m_tournament_init_blue.insert(username); + } else + { m_tournament_red_players.insert(username); + if (permanent) + m_tournament_init_red.insert(username); + } sendStringToPeer(role_changed, player_peer); } break; @@ -6890,9 +6997,17 @@ void ServerLobby::handleServerCommand(Event* event, role_changed = StringUtils::insertValues(role_changed, "blue player"); player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_BLUE); if (tournamentColorsSwapped(m_tournament_game)) + { m_tournament_red_players.insert(username); + if (permanent) + m_tournament_init_red.insert(username); + } else + { m_tournament_blue_players.insert(username); + if (permanent) + m_tournament_init_blue.insert(username); + } sendStringToPeer(role_changed, player_peer); } break; @@ -6901,6 +7016,8 @@ void ServerLobby::handleServerCommand(Event* event, case 'j': { m_tournament_referees.insert(username); + if (permanent) + m_tournament_init_ref.insert(username); if (player_peer) { role_changed = StringUtils::insertValues(role_changed, "referee"); @@ -6926,6 +7043,60 @@ void ServerLobby::handleServerCommand(Event* event, sendStringToPeer(msg, peer); updatePlayerList(); } + else if (argv[0] == "stop") + { + World* w = World::getWorld(); + if (!w) + return; + SoccerWorld *sw = dynamic_cast(w); + sw->stop(); + std::string msg = "The game is stopped."; + sendStringToAllPeers(msg); + } + else if (argv[0] == "go" || argv[0] == "play" || argv[0] == "resume") + { + World* w = World::getWorld(); + if (!w) + return; + SoccerWorld *sw = dynamic_cast(w); + sw->resume(); + std::string msg = "The game is resumed."; + sendStringToAllPeers(msg); + } + else if (argv[0] == "lobby") + { + World* w = World::getWorld(); + if (!w) + return; + SoccerWorld *sw = dynamic_cast(w); + sw->allToLobby(); + std::string msg = "The game will be restarted."; + sendStringToAllPeers(msg); + } + else if (argv[0] == "init") + { + int red, blue; + if (argv.size() < 3 || + !StringUtils::parseString(argv[1], &red) || + !StringUtils::parseString(argv[2], &blue)) + { + std::string msg = "Usage: /init [red_count] [blue_count]"; + sendStringToPeer(msg, peer); + return; + } + World* w = World::getWorld(); + if (!w) + { + std::string msg = "Please set the count when the karts " + "are ready. Setting the initial count in lobby is " + "not implemented yet, sorry."; + sendStringToPeer(msg, peer); + return; + } + SoccerWorld *sw = dynamic_cast(w); + sw->setInitialCount(red, blue); + sw->tellCount(); + } } else { @@ -7131,7 +7302,8 @@ void ServerLobby::initAvailableModes() //----------------------------------------------------------------------------- void ServerLobby::resetToDefaultSettings() { - handleServerConfiguration(NULL); + if (ServerConfig::m_server_configurable) + handleServerConfiguration(NULL); // m_gnu_elimination = false; } // resetToDefaultSettings //----------------------------------------------------------------------------- @@ -7228,13 +7400,41 @@ void ServerLobby::writeOwnReport(STKPeer* reporter, STKPeer* reporting, const st //----------------------------------------------------------------------------- void ServerLobby::initTournamentPlayers() { + // Init categories std::vector tokens = StringUtils::split( ServerConfig::m_soccer_tournament_players, ' '); + std::string category = ""; + for (std::string& s: tokens) + { + if (s.empty()) + continue; + else if (s[0] == '#') + category = s.substr(1); + else + m_tournament_player_categories[category].push_back(s); + } + + // Init playing teams + tokens = StringUtils::split( + ServerConfig::m_soccer_tournament_match, ' '); std::string type = ""; for (std::string& s: tokens) { if (s.length() == 1) type = s; + else if (s.empty()) + continue; + else if (s[0] == '#') + { + std::string cat_name = s.substr(1); + std::set& dest = ( + type == "R" ? m_tournament_red_players : + type == "B" ? m_tournament_blue_players : + m_tournament_referees); + for (std::string& member: + m_tournament_player_categories[cat_name]) + dest.insert(member); + } else if (type == "R") m_tournament_red_players.insert(s); else if (type == "B") @@ -7242,6 +7442,56 @@ void ServerLobby::initTournamentPlayers() else if (type == "J") m_tournament_referees.insert(s); } + m_tournament_init_red = m_tournament_red_players; + m_tournament_init_blue = m_tournament_blue_players; + m_tournament_init_ref = m_tournament_referees; + + // Init tournament format + tokens = StringUtils::split( + ServerConfig::m_soccer_tournament_rules, ';'); + bool fallback = tokens.size() < 2; + std::vector general; + if (!fallback) + { + general = StringUtils::split(tokens[0], ' '); + if (general.size() < 4) + fallback = true; + } + if (fallback) + { + Log::warn("ServerLobby", "Tournament rules not complete, fallback to default"); + general.clear(); + general.push_back("nochat"); + general.push_back("10"); + general.push_back("GGGGT"); + general.push_back("RRBBR"); + tokens.clear(); + tokens.push_back("nochat 10 GGGT RRBBR"); + tokens.push_back(""); + tokens.push_back(""); + tokens.push_back("not %0"); + tokens.push_back("not %0" " %1"); + tokens.push_back(""); + } + m_tournament_limited_chat = false; + m_tournament_length = 10; + if (general[0] == "nochat") + m_tournament_limited_chat = true; + if (StringUtils::parseString(general[1], &m_tournament_length)) + { + if (m_tournament_length <= 0) + m_tournament_length = 10; + } + else + m_tournament_length = 10; + + m_tournament_game_limits = general[2]; + m_tournament_colors = general[3]; + m_tournament_max_games = std::min(general[2].length(), general[3].length()); + m_tournament_max_games = std::min(m_tournament_max_games, (int)tokens.size() - 1); + m_tournament_arenas.resize(m_tournament_max_games, ""); + for (unsigned i = 0; i < m_tournament_max_games; i++) + m_tournament_track_filters.emplace_back(tokens[i + 1]); } // initTournamentPlayers //----------------------------------------------------------------------------- void ServerLobby::changeColors() @@ -7458,33 +7708,36 @@ icy / non-icy (listed as "addon") arena choice, are isted: //----------------------------------------------------------------------------- bool ServerLobby::tournamentGoalsLimit(int game) const { - int rem = game % 8; - if (rem < 0) - rem += 8; - return (rem >> 2) & 1; + return m_tournament_game_limits[game] == 'G'; + // int rem = game % 8; + // if (rem < 0) + // rem += 8; + // return (rem >> 2) & 1; } // tournamentGoalsLimit //----------------------------------------------------------------------------- bool ServerLobby::tournamentColorsSwapped(int game) const { - int rem = game % 8; - if (rem < 0) - rem += 8; - return (rem >> 1) & 1; + return m_tournament_colors[game] == 'B'; + // int rem = game % 8; + // if (rem < 0) + // rem += 8; + // return (rem >> 1) & 1; } // tournamentColorsSwapped //----------------------------------------------------------------------------- -bool ServerLobby::tournamentHasIcy(int game) const -{ - int rem = game % 8; - if (rem < 0) - rem += 8; - return (rem ^ (rem >> 2)) & 1; -} // tournamentHasIcy +// bool ServerLobby::tournamentHasIcy(int game) const +// { +// int rem = game % 8; +// if (rem < 0) +// rem += 8; +// return (rem ^ (rem >> 2)) & 1; +// } // tournamentHasIcy //----------------------------------------------------------------------------- void ServerLobby::initAvailableTracks() { + m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); m_must_have_tracks = StringUtils::split( ServerConfig::m_must_have_tracks_string, ' ', false); - m_inverted_config_restriction = false; + /*m_inverted_config_restriction = false; m_restricting_config = true; if (((std::string)(ServerConfig::m_only_played_tracks_string)).empty()) { @@ -7514,32 +7767,32 @@ void ServerLobby::initAvailableTracks() } else m_config_available_tracks.insert(available_tracks[i]); - } + }*/ } // initAvailableTracks //----------------------------------------------------------------------------- -int ServerLobby::getTrackMaxPlayers(std::string& name) const -{ - auto map_entry = m_config_track_limitations.find(name); - if (map_entry == m_config_track_limitations.end()) - return INT_MAX; - std::string key = "max_players"; - auto map_value = map_entry->second; - auto where = std::find(map_value.begin(), map_value.end(), key); - auto end = map_value.end(); - if (where == end) - return INT_MAX; - where++; - if (where == end) - return INT_MAX; - int track_max_players; - std::string max_str = *where; - if (!StringUtils::parseString(max_str, &track_max_players)) - { - Log::warn("ServerLobby", "Bad max_players value for track %s", name.c_str()); - return INT_MAX; - } - return track_max_players; -} // getTrackMaxPlayers +// int ServerLobby::getTrackMaxPlayers(std::string& name) const +// { +// auto map_entry = m_config_track_limitations.find(name); +// if (map_entry == m_config_track_limitations.end()) +// return INT_MAX; +// std::string key = "max_players"; +// auto map_value = map_entry->second; +// auto where = std::find(map_value.begin(), map_value.end(), key); +// auto end = map_value.end(); +// if (where == end) +// return INT_MAX; +// where++; +// if (where == end) +// return INT_MAX; +// int track_max_players; +// std::string max_str = *where; +// if (!StringUtils::parseString(max_str, &track_max_players)) +// { +// Log::warn("ServerLobby", "Bad max_players value for track %s", name.c_str()); +// return INT_MAX; +// } +// return track_max_players; +// } // getTrackMaxPlayers //----------------------------------------------------------------------------- #ifdef ENABLE_WEB_SUPPORT diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 4fcd912bd78..1062652fc5b 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -22,6 +22,7 @@ #include "network/protocols/lobby_protocol.hpp" #include "utils/cpp2011.hpp" #include "utils/time.hpp" +#include "utils/track_filter.hpp" #include "irrString.h" @@ -295,12 +296,36 @@ class ServerLobby : public LobbyProtocol std::set m_available_modes; + std::map> m_tournament_player_categories; + std::set m_tournament_red_players; std::set m_tournament_blue_players; std::set m_tournament_referees; + std::set m_tournament_init_red; + + std::set m_tournament_init_blue; + + std::set m_tournament_init_ref; + + bool m_tournament_limited_chat; + + int m_tournament_length; + + int m_tournament_max_games; + + std::string m_tournament_game_limits; + + std::string m_tournament_colors; + + std::vector m_tournament_arenas; + + std::vector m_tournament_track_filters; + + TrackFilter m_global_filter; + std::set m_temp_banned; std::deque m_tracks_queue; @@ -464,7 +489,7 @@ class ServerLobby : public LobbyProtocol void changeLimitForTournament(bool goal_target); bool tournamentGoalsLimit(int game) const; bool tournamentColorsSwapped(int game) const; - bool tournamentHasIcy(int game) const; + // bool tournamentHasIcy(int game) const; #ifdef ENABLE_WEB_SUPPORT void loadAllTokens(); std::string getToken(); @@ -510,7 +535,7 @@ class ServerLobby : public LobbyProtocol void initAvailableModes(); void resetToDefaultSettings(); void writeOwnReport(STKPeer* reporter, STKPeer* reporting, const std::string& info); - int getTrackMaxPlayers(std::string& name) const; + // int getTrackMaxPlayers(std::string& name) const; }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index c9f8ef3655c..df7766a4798 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -333,7 +333,7 @@ void loadServerLobbyFromConfig() RaceManager::get()->setDifficulty(RaceManager::Difficulty(difficulty)); if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL && - m_server_max_players > 10) + m_server_max_players > 10 && !m_server_configurable) m_server_max_players = 10; if (m_ipv6_connection) diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 155acc5578b..3f0d9910a9a 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -527,13 +527,28 @@ namespace ServerConfig "tournaments. Rules may change so better ask STK players about " "the actual rules.")); - SERVER_CFG_PREFIX StringServerConfigParam m_soccer_tournament_players + SERVER_CFG_PREFIX StringServerConfigParam m_soccer_tournament_match SERVER_CFG_DEFAULT(StringServerConfigParam("", - "soccer-tournament-players", + "soccer-tournament-match", "List of players and judges. Use the format \"R red red " "red B blue blue blue J judge judge\" where " "the category is preceded by its letter. Categories can " - "be empty or absent and can go in any order.")); + "be empty or absent and can go in any order. You can use " + "a category (#A) instead of listing all players.")); + + SERVER_CFG_PREFIX StringServerConfigParam m_soccer_tournament_players + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "soccer-tournament-players", + "List of tournament players with categories (teams). Use the " + "format #Category player1 ... playerN #Category ...")); + + SERVER_CFG_PREFIX StringServerConfigParam m_soccer_tournament_rules + SERVER_CFG_DEFAULT(StringServerConfigParam("nochat 10 TTTTG RRBBR;" + ";;not %1;" + "not %1 " + "%2;;;", + "soccer-tournament-rules", + "A string specifying the match format.")); SERVER_CFG_PREFIX StringServerConfigParam m_incompatible_advice SERVER_CFG_DEFAULT(StringServerConfigParam("", diff --git a/src/utils/track_filter.cpp b/src/utils/track_filter.cpp new file mode 100644 index 00000000000..0b40b21de86 --- /dev/null +++ b/src/utils/track_filter.cpp @@ -0,0 +1,183 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2004-2020 Steve Baker , +// Copyright (C) 2004-2020 Ingo Ruhnke +// Copyright (C) 2006-2020 SuperTuxKart-Team +// Copyright (C) 2020 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/track_filter.hpp" + +#include "utils/string_utils.hpp" +#include "utils/log.hpp" +#include +#include +#include +#include +#include +#include +#include + +TrackFilter::TrackFilter() +{ + +} // TrackFilter +//----------------------------------------------------------------------------- + +TrackFilter::TrackFilter(std::string input) +{ + auto tokens = StringUtils::split(input, ' '); + bool good = true; + others = false; + if (tokens.size() == 0) + others = true; + for (unsigned i = 0; i < tokens.size(); i++) + { + if (tokens[i] == "" || tokens[i] == " ") + continue; + else if (tokens[i] == "not" || tokens[i] == "no") + { + good = false; + if (i == 0) + others = true; + } + else if (tokens[i] == "yes" || tokens[i] == "ok") + { + good = true; + } + else if (tokens[i] == "other:yes") + { + others = true; + } + else if (tokens[i] == "other:no") + { + others = false; + } + else if (tokens[i][0] == '%') + { + int index; + std::string cut = tokens[i].substr(1); + if (!StringUtils::parseString(cut, &index) || index < 0) + { + Log::warn("TrackFilter", "Unable to parse wildcard index " + "from \"%s\", omitting it", tokens[i].c_str()); + continue; + } + if (good) + w_allowed.push_back(index); + else + w_forbidden.push_back(index); + } + else + { + int separator = tokens[i].find(':'); + if (separator != std::string::npos) + { + std::string track = tokens[i].substr(0, separator); + std::string params_str = tokens[i].substr(separator + 1); + int value; + if (!StringUtils::parseString(params_str, &value)) + { + Log::warn("TrackFilter", "Incorrect integer value %s of " + "max-players for track %s", params_str.c_str(), + track.c_str()); + } + max_players[track] = value; + // std::vector params = StringUtils::split( + // params_str, ',', false); + // parameters[track] = params; + } + else + { + if (good) + allowed.push_back(tokens[i]); + else + forbidden.push_back(tokens[i]); + } + } + } +} // TrackFilter +//----------------------------------------------------------------------------- +std::string TrackFilter::get(std::vector& vec, int index) +{ + if (index >= 0 && index < vec.size()) + return vec[index]; + return ""; +} // get +//----------------------------------------------------------------------------- + +void TrackFilter::apply(int num_players, std::set& input) const +{ + std::vector empty; + apply(num_players, input, empty); +} // apply +//----------------------------------------------------------------------------- + +void TrackFilter::apply(int num_players, std::set& input, + std::vector& wildcards) const +{ + std::set copy = input; + input.clear(); + + for (const std::string& s: copy) + { + bool yes = false; + bool no = false; + auto it = max_players.find(s); + if (it != max_players.end() && it->second < num_players) + continue; + for (int x: w_allowed) + if (get(wildcards, x) == s) + { + yes = true; + break; + } + for (int x: w_forbidden) + if (get(wildcards, x) == s) + { + no = true; + break; + } + for (std::string x: allowed) + if (x == s) + { + yes = true; + break; + } + for (std::string x: forbidden) + if (x == s) + { + no = true; + break; + } + if (yes && no) + { + Log::warn("TrackFilter", "Track requirements contradict for %s, " + "please check your config. Force allowing it.", s.c_str()); + no = false; + } + if (!yes && !no) + if (others) + yes = true; + else + no = true; + if (yes) + input.insert(s); + } +} // apply (2) +//----------------------------------------------------------------------------- + +/* EOF */ diff --git a/src/utils/track_filter.hpp b/src/utils/track_filter.hpp new file mode 100644 index 00000000000..e25341799af --- /dev/null +++ b/src/utils/track_filter.hpp @@ -0,0 +1,54 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2004-2020 Steve Baker , +// Copyright (C) 2004-2020 Ingo Ruhnke +// Copyright (C) 2006-2020 SuperTuxKart-Team +// Copyright (C) 2020 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_TRACK_FILTER_HPP +#define HEADER_TRACK_FILTER_HPP + +#include "utils/types.hpp" +#include +#include +#include +#include +#include +#include + +// A structure to apply requirements to the track set. allowed contains +// the only tracks to be allowed, forbidden contains the only tracks to be +// forbidden. Putting one track into both vectors produces undefined behaviour +// for now. Works with wildcards (indices are integers: %0, %1, ...). + +struct TrackFilter +{ + std::vector allowed; + std::vector forbidden; + std::vector w_allowed; // wildcards + std::vector w_forbidden; // wildcards + std::map max_players; + bool others; // whether not specified tracks are allowed + TrackFilter(); + TrackFilter(std::string input); + static std::string get(std::vector& vec, int index); + void apply(int num_players, std::set& input) const; + void apply(int num_players, std::set& input, + std::vector& wildcards) const; +}; + +#endif From 2a79bf5b9632a4288eae9255bfdbe65b31bb2f6b Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 28 Aug 2020 17:33:59 +0300 Subject: [PATCH 088/830] Fix wrong merge --- src/network/protocols/server_lobby.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index c64c869f152..3a800644c83 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1791,7 +1791,7 @@ void ServerLobby::asynchronousUpdate() if (peer->alwaysSpectate() && peer->getClientAssets().second.count(track_name) == 0) { - peer->setAlwaysSpectate(false); + peer->setAlwaysSpectate(ASM_NONE); peer->setWaitingForGame(true); m_peers_ready.erase(peer); bad_spectators.insert(peer.get()); @@ -2759,7 +2759,7 @@ void ServerLobby::startSelection(const Event *event) if (!can_race) { if (ServerConfig::m_soccer_tournament || ServerConfig::m_only_host_riding) - peer->setAlwaysSpectate(true); + peer->setAlwaysSpectate(ASM_COMMAND); } if (!can_race && !peer->alwaysSpectate()) { @@ -2790,7 +2790,7 @@ void ServerLobby::startSelection(const Event *event) "An attempt to start a game while no one is able to play."); return; // for (STKPeer* peer : always_spectate_peers) - // peer->setAlwaysSpectate(false); + // peer->setAlwaysSpectate(ASM_NONE); // always_spectate_peers.clear(); } else @@ -2827,7 +2827,7 @@ void ServerLobby::startSelection(const Event *event) std::sort(peers.begin(), peers.end(), [](const std::shared_ptr& a, const std::shared_ptr& b) - { return a->getReadyToRaceTime() < b->getReadyToRaceTime(); }); + { return a->getHostId() > b->getHostId(); }); int remove_player = max_player; for (unsigned i = 0; i < peers.size(); i++) { @@ -4601,14 +4601,14 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) if (!ServerConfig::m_soccer_tournament) { for (auto& peer : m_default_always_spectate_peers) - peer->setAlwaysSpectate(true); + peer->setAlwaysSpectate(ASM_COMMAND); } else { auto peers = STKHost::get()->getPeers(); for (auto& peer: peers) { - peer->setAlwaysSpectate(false); + peer->setAlwaysSpectate(ASM_NONE); } } } From 7c1a48557d18d128dfe52c64e7be365b7ae346a4 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 1 Sep 2020 14:48:48 +0300 Subject: [PATCH 089/830] Finally fix wrong merge and add /register command --- src/network/protocols/server_lobby.cpp | 87 +++++++++++++++++++++++--- src/network/protocols/server_lobby.hpp | 5 +- src/network/server_config.hpp | 6 ++ 3 files changed, 90 insertions(+), 8 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3a800644c83..920768269a7 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2809,18 +2809,21 @@ void ServerLobby::startSelection(const Event *event) // } unsigned max_player = 0; STKHost::get()->updatePlayers(&max_player); + int remove_player = max_player; if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) - max_player -= 14; - if (RaceManager::get()->getMinorMode() == + remove_player -= 14; + else if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) - max_player -= 10; - if (RaceManager::get()->getMinorMode() == + remove_player -= 10; + else if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) - max_player -= 14; + remove_player -= 14; + else + remove_player -= 1000000; - if (max_player > 0) + if (remove_player > 0) { // Set late coming player to spectate if too many players in battle or // soccer @@ -2828,7 +2831,6 @@ void ServerLobby::startSelection(const Event *event) [](const std::shared_ptr& a, const std::shared_ptr& b) { return a->getHostId() > b->getHostId(); }); - int remove_player = max_player; for (unsigned i = 0; i < peers.size(); i++) { auto& peer = peers[i]; @@ -7029,6 +7031,30 @@ void ServerLobby::handleServerCommand(Event* event, std::string msg = "1.2-kimden 200828 beta"; sendStringToPeer(msg, peer); } + else if (argv[0] == "register") + { + int online_id = peer->getPlayerProfiles()[0]->getOnlineId(); + if (online_id <= 0) + { + std::string msg = "Please join with a valid online STK account."; + sendStringToPeer(msg, peer); + return; + } + std::string ans = ""; + for (unsigned i = 1; i < argv.size(); ++i) + { + if (i > 1) + ans.push_back(' '); + ans += argv[i]; + } + std::string message_ok = "Your registration request is being processed"; + std::string message_wrong = "Sorry, an error occurred. Please try again."; + if (writeOnePlayerReport(peer.get(), ServerConfig::m_register_table_name, + ans)) + sendStringToPeer(message_ok, peer); + else + sendStringToPeer(message_wrong, peer); + } #ifdef ENABLE_WEB_SUPPORT else if (argv[0] == "token") { @@ -7861,6 +7887,53 @@ void ServerLobby::loadWhiteList() for (std::string& s: tokens) m_usernames_white_list.insert(s); } // loadWhiteList +//----------------------------------------------------------------------------- +bool ServerLobby::writeOnePlayerReport(STKPeer* reporter, + const std::string& table, const std::string& info) +{ +#ifdef ENABLE_SQLITE3 + if (!m_db) + return false; + if (!reporter->hasPlayerProfiles()) + return false; + auto reporter_npp = reporter->getPlayerProfiles()[0]; + + std::string query = StringUtils::insertValues( + "INSERT INTO %s " + "(server_uid, reporter_online_id, reporter_username, " + "info) " + "VALUES (?, %u, ?, ?);", + table.c_str(), + reporter_npp->getOnlineId()); + + bool written = easySQLQuery(query, + [reporter_npp, info](sqlite3_stmt* stmt) + { + // SQLITE_TRANSIENT to copy string + if (sqlite3_bind_text(stmt, 1, ServerConfig::m_server_uid.c_str(), + -1, SQLITE_TRANSIENT) != SQLITE_OK) + { + Log::error("easySQLQuery", "Failed to bind %s.", + ServerConfig::m_server_uid.c_str()); + } + if (sqlite3_bind_text(stmt, 2, + StringUtils::wideToUtf8(reporter_npp->getName()).c_str(), + -1, SQLITE_TRANSIENT) != SQLITE_OK) + { + Log::error("easySQLQuery", "Failed to bind %s.", + StringUtils::wideToUtf8(reporter_npp->getName()).c_str()); + } + if (sqlite3_bind_text(stmt, 3, + info.c_str(), + -1, SQLITE_TRANSIENT) != SQLITE_OK) + { + Log::error("easySQLQuery", "Failed to bind %s.", + info.c_str()); + } + }); + return written; +#endif +} // writeOnePlayerReport //----------------------------------------------------------------------------- void ServerLobby::changeLimitForTournament(bool goal_target) { diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index b61ae967c00..43a04c3b48b 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -551,7 +551,10 @@ class ServerLobby : public LobbyProtocol void initAvailableTracks(); void initAvailableModes(); void resetToDefaultSettings(); - void writeOwnReport(STKPeer* reporter, STKPeer* reporting, const std::string& info); + void writeOwnReport(STKPeer* reporter, STKPeer* reporting, + const std::string& info); + bool writeOnePlayerReport(STKPeer* reporter, const std::string& table, + const std::string& info); // int getTrackMaxPlayers(std::string& name) const; }; // class ServerLobby diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 3f0d9910a9a..0edfe29569b 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -617,6 +617,12 @@ namespace ServerConfig "If true, the server owner can kick players, either via " "the UI button or using /kick command.")); + SERVER_CFG_PREFIX StringServerConfigParam m_register_table_name + SERVER_CFG_DEFAULT(StringServerConfigParam("", "registration-table-name", + "When non-empty, stores input given by /register command in " + "the corresponding table. Otherwise, /register command does " + "nothing")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; From 7c4a3465abd85806e1cea0dbecd6f5674a5b24ab Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 7 Nov 2020 21:14:58 +0300 Subject: [PATCH 090/830] Soccer tournament logging, gnu elimination rewritten, minor fixes --- src/modes/soccer_world.cpp | 8 +- src/network/protocols/server_lobby.cpp | 739 ++++++++++--------------- src/network/protocols/server_lobby.hpp | 16 +- src/utils/kart_elimination.cpp | 160 ++++++ src/utils/kart_elimination.hpp | 57 ++ 5 files changed, 526 insertions(+), 454 deletions(-) create mode 100644 src/utils/kart_elimination.cpp create mode 100644 src/utils/kart_elimination.hpp diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp index 533129eaeba..f16984f5143 100644 --- a/src/modes/soccer_world.cpp +++ b/src/modes/soccer_world.cpp @@ -393,7 +393,9 @@ void SoccerWorld::reset(bool restart) //----------------------------------------------------------------------------- void SoccerWorld::onGo() { - Log::info("SoccerWorld", "The game starts now."); + Log::info("SoccerWorld", "SoccerMatchLog: The game starts now."); + Log::info("SoccerWorld", "SoccerMatchLog: The arena is %s", + RaceManager::get()->getTrackName().c_str()); m_ball->setEnabled(true); m_ball->reset(); WorldWithRank::onGo(); @@ -561,7 +563,7 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) if (sd.m_correct_goal) { if (!stopped) - Log::info("SoccerWorld", "[Goal] %s scored a goal for %s", + Log::info("SoccerWorld", "SoccerMatchLog: [Goal] %s scored a goal for %s", player_name.c_str(), team_name.c_str()); m_karts[sd.m_id]->getKartModel() ->setAnimation(KartModel::AF_WIN_START, true/* play_non_loop*/); @@ -569,7 +571,7 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) else if (!sd.m_correct_goal) { if (!stopped) - Log::info("SoccerWorld", "[Goal] %s scored an own goal for %s", + Log::info("SoccerWorld", "SoccerMatchLog: [Goal] %s scored an own goal for %s", player_name.c_str(), team_name.c_str()); m_karts[sd.m_id]->getKartModel() ->setAnimation(KartModel::AF_LOSE_START, true/* play_non_loop*/); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 920768269a7..8e3a0114031 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -183,9 +183,6 @@ ServerLobby::ServerLobby() : LobbyProtocol() "installaddon uninstalladdon liststkaddon listlocaladdon " "listserveraddon playerhasaddon playeraddonscore serverhasaddon"; - m_gnu_elimination = false; - m_gnu_remained = 0; - m_fixed_lap = ServerConfig::m_fixed_lap_count; initAvailableModes(); @@ -725,22 +722,6 @@ void ServerLobby::updateTracksForMode() assert(false); break; } - /*if (m_restricting_config) - { - std::set erase_tracks; - auto it = m_available_kts.second.begin(); - while (it != m_available_kts.second.end()) - { - if (m_inverted_config_restriction ^ - (m_config_available_tracks.find(*it) == - m_config_available_tracks.end())) - erase_tracks.insert(*it); - it++; - } - for (const std::string& track : erase_tracks) { - m_available_kts.second.erase(track); - } - }*/ m_entering_kts = m_available_kts; } // updateTracksForMode @@ -1797,17 +1778,6 @@ void ServerLobby::asynchronousUpdate() bad_spectators.insert(peer.get()); } } - // if (!bad_spectators.empty()) - // { - // NetworkString* back_lobby = getNetworkString(2); - // back_lobby->setSynchronous(true); - // back_lobby->addUInt8(LE_BACK_LOBBY).addUInt8(BLR_NONE); - // STKHost::get()->sendPacketToAllPeersWith( - // [bad_spectators](STKPeer* peer) { - // return bad_spectators.find(peer) != - // bad_spectators.end(); }, back_lobby, /*reliable*/true); - // delete back_lobby; - // } bool has_always_on_spectators = false; auto players = STKHost::get() ->getPlayersForNewGame(&has_always_on_spectators); @@ -1851,26 +1821,14 @@ void ServerLobby::asynchronousUpdate() // Add placeholder players for live join addLiveJoinPlaceholder(players); // If player chose random / hasn't chose any kart - bool possible_gnu_enforcement = - m_gnu_elimination && m_gnu_remained >= 0; for (unsigned i = 0; i < players.size(); i++) { if (players[i]->getKartName().empty()) { - bool gnu_eliminated = possible_gnu_enforcement; - if (gnu_eliminated) + if (m_kart_elimination.isEliminated( + StringUtils::wideToUtf8(players[i]->getName()))) { - if (std::find(m_gnu_participants.begin(), - m_gnu_participants.begin() + m_gnu_remained, - StringUtils::wideToUtf8(players[i]->getName())) != - m_gnu_participants.begin() + m_gnu_remained) - { - gnu_eliminated = false; - } - } - if (gnu_eliminated) - { - players[i]->setKartName(m_gnu_kart); + players[i]->setKartName(m_kart_elimination.getKart()); } else { @@ -1891,6 +1849,10 @@ void ServerLobby::asynchronousUpdate() uint16_t flag_return_time = (uint16_t)stk_config->time2Ticks( ServerConfig::m_flag_return_timeout); RaceManager::get()->setFlagReturnTicks(flag_return_time); + if (ServerConfig::m_only_host_riding && + RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_TIME_TRIAL) + RaceManager::get()->setRecordRace(true); uint16_t flag_deactivated_time = (uint16_t)stk_config->time2Ticks( ServerConfig::m_flag_deactivated_time); RaceManager::get()->setFlagDeactivatedTicks(flag_deactivated_time); @@ -1906,6 +1868,23 @@ void ServerLobby::asynchronousUpdate() if (has_always_on_spectators || !bad_spectators.empty()) updatePlayerList(); delete load_world_message; + + if (RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_SOCCER) + { + for (unsigned i = 0; i < RaceManager::get()->getNumPlayers(); i++) + { + if (auto player = + RaceManager::get()->getKartInfo(i).getNetworkPlayerProfile().lock()) + { + std::string username = StringUtils::wideToUtf8(player->getName()); + if (username.empty()) + continue; + Log::info("ServerLobby", "SoccerMatchLog: There is a player %s.", + username.c_str()); + } + } + } } break; } @@ -2803,10 +2782,6 @@ void ServerLobby::startSelection(const Event *event) peer->setWaitingForGame(true); } - // if (ServerConfig::m_soccer_tournament && !tournamentHasIcy(m_tournament_game)) - // { - // tracks_erase.insert("icy_soccer_field"); - // } unsigned max_player = 0; STKHost::get()->updatePlayers(&max_player); int remove_player = max_player; @@ -2860,21 +2835,6 @@ void ServerLobby::startSelection(const Event *event) { m_available_kts.second.erase(track_erase); } - // if (ServerConfig::m_soccer_tournament) - // { - // if (tournamentHasIcy(m_tournament_game)) - // { - // if (m_available_kts.second.count("icy_soccer_field")) - // { - // m_available_kts.second.clear(); - // m_available_kts.second.insert("icy_soccer_field"); - // } - // else - // { - // m_available_kts.second.clear(); - // } - // } - // } if (!m_tracks_queue.empty()) { m_available_kts.second.clear(); @@ -3039,18 +2999,18 @@ void ServerLobby::startSelection(const Event *event) ns->encodeString(track); } - if (m_gnu_elimination && m_gnu_remained >= 0) + auto remaining = m_kart_elimination.getRemainingParticipants(); + if (!remaining.empty()) { - auto remaining_begin = m_gnu_participants.begin(); - auto remaining_end = remaining_begin + m_gnu_remained; + // Seems like I assumed the kart elimination cannot have + // preselected tracks. Not sure I really wanted this. STKHost::get()->sendPacketToAllPeersWith( - [remaining_begin, remaining_end](STKPeer* p) + [remaining](STKPeer* p) { for (auto& profile : p->getPlayerProfiles()) { - if (std::find( - remaining_begin, remaining_end, - StringUtils::wideToUtf8(profile->getName())) != remaining_end) + if (remaining.count( + StringUtils::wideToUtf8(profile->getName())) != 0) { return true; } @@ -3061,10 +3021,10 @@ void ServerLobby::startSelection(const Event *event) bool has_gnu = false; for (auto it = all_k.begin(); it != all_k.end(); it++) { - has_gnu |= (*it == m_gnu_kart); + has_gnu |= (*it == m_kart_elimination.getKart()); } - // The same NetworkString but without any non-Gnu karts + // The same NetworkString but without any non-elimination karts NetworkString *ns = getNetworkString(1); ns->setSynchronous(true); ns->addUInt8(LE_START_SELECTION) @@ -3078,7 +3038,7 @@ void ServerLobby::startSelection(const Event *event) (uint16_t)all_t.size()); if (has_gnu) { - ns->encodeString(std::string(m_gnu_kart)); + ns->encodeString(std::string(m_kart_elimination.getKart())); } for (const std::string& track : all_t) { @@ -3086,14 +3046,12 @@ void ServerLobby::startSelection(const Event *event) } STKHost::get()->sendPacketToAllPeersWith( - [remaining_begin, remaining_end](STKPeer* p) + [remaining](STKPeer* p) { for (auto& profile : p->getPlayerProfiles()) { - if (std::find( - remaining_begin, remaining_end, - StringUtils::wideToUtf8(profile->getName())) - != remaining_end) + if (remaining.count( + StringUtils::wideToUtf8(profile->getName())) != 0) { return false; } @@ -3103,19 +3061,9 @@ void ServerLobby::startSelection(const Event *event) } else { - // std::set all_players; - // for (const std::string& s: m_tournament_red_players) { - // all_players.insert(s); - // } - // for (const std::string& s: m_tournament_blue_players) { - // all_players.insert(s); - // } STKHost::get()->sendPacketToAllPeersWith( - [/*all_players*/this](STKPeer* p) -> bool + [this](STKPeer* p) -> bool { - // std::string username = StringUtils::wideToUtf8( - // p->getPlayerProfiles()[0]->getName()); - // return all_players.count(username) > 0; return canRace(p); }, ns, /*reliable*/true); delete ns; @@ -3304,7 +3252,11 @@ void ServerLobby::checkRaceFinished() sw->tellCountIfDiffers(); } } - Log::info("ServerLobby", "The game is considered finished."); + if (RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_SOCCER) + Log::info("ServerLobby", "SoccerMatchLog: The game is considered finished."); + else + Log::info("ServerLobby", "The game is considered finished."); // notify the network world that it is stopped RaceEventManager::get()->stop(); @@ -3388,7 +3340,9 @@ void ServerLobby::checkRaceFinished() ranking_changes_indication = 1; m_result_ns->addUInt8(ranking_changes_indication); - if (m_gnu_elimination) { + if (m_kart_elimination.isEnabled()) { + // ServerLobby's function because we need to take + // the list of players from somewhere updateGnuElimination(); } @@ -4193,7 +4147,7 @@ void ServerLobby::connectionRequested(Event* event) RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) max_players_mode = std::min(14, max_players_mode); if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_SOCCER) + RaceManager::MINOR_MODE_SOCCER && !ServerConfig::m_soccer_tournament) max_players_mode = std::min(14, max_players_mode); if (total_players + player_count + m_ai_profiles.size() > max_players_mode) @@ -4570,17 +4524,13 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, } ); #endif - if (m_gnu_elimination) + if (m_kart_elimination.isEnabled()) { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); - std::string gnu_warning = StringUtils::insertValues( - "Gnu Elimination is played right now on this server, " - "you will be forced to use kart %d until it ends. " - "Use /standings to see the results.", - m_gnu_kart); - chat->encodeString16(StringUtils::utf8ToWide(gnu_warning)); + std::string warning = m_kart_elimination.getWarningMessage(); + chat->encodeString16(StringUtils::utf8ToWide(warning)); peer->sendPacket(chat, true/*reliable*/); delete chat; } @@ -5738,18 +5688,9 @@ float ServerLobby::getStartupBoostOrPenaltyForKart(uint32_t ping, } // getStartupBoostOrPenaltyForKart //----------------------------------------------------------------------------- -/*! \brief Called when the server owner request to change game mode or - * difficulty. - * \param event : Event providing the information. - * - * Format of the data : - * Byte 0 1 2 - * ----------------------------------------------- - * Size | 1 | 1 | 1 | - * Data | difficulty | game mode | soccer goal target | - * ----------------------------------------------- - */ -void ServerLobby::handleServerConfiguration(Event* event) + +void ServerLobby::handleServerConfiguration(std::shared_ptr peer, + int difficulty, int mode, bool soccer_goal_target) { if (m_state != WAITING_FOR_START_GAME) { @@ -5763,54 +5704,28 @@ void ServerLobby::handleServerConfiguration(Event* event) Log::warn("ServerLobby", "server-configurable is not enabled."); return; } - if (event != NULL && event->getPeerSP() != m_server_owner.lock()) - { - Log::warn("ServerLobby", - "Client %d is not authorised to config server.", - event->getPeer()->getHostId()); - return; - } - int new_difficulty = ServerConfig::m_server_difficulty; - int new_game_mode = ServerConfig::m_server_mode; - bool new_soccer_goal_target = ServerConfig::m_soccer_goal_target; - if (event != NULL) - { - NetworkString& data = event->data(); - new_difficulty = data.getUInt8(); - new_game_mode = data.getUInt8(); - new_soccer_goal_target = data.getUInt8() == 1; - } unsigned total_players = 0; STKHost::get()->updatePlayers(NULL, NULL, &total_players); - if ((new_game_mode == 6 && total_players > 14) || - (new_game_mode == 7 && total_players > 10) || - (new_game_mode == 8 && total_players > 14)) + if ((mode == 6 && total_players > 14) || + (mode == 7 && total_players > 10) || + (mode == 8 && total_players > 14)) { Log::error("ServerLobby", "Too many players (%d) to change mode to %d.", - total_players, new_game_mode); - auto peer = event->getPeerSP(); + total_players, mode); std::string msg = "Too many players present to activate this mode. " "Soccer and CTF require at most 14, and FFA requires at most 10."; sendStringToPeer(msg, peer); return; } - // Actually event == NULL implies no errors... - if (event != NULL && - (m_available_difficulties.count(new_difficulty) == 0 || - m_available_modes.count(new_game_mode) == 0)) + if ((m_available_difficulties.count(difficulty) == 0 || + m_available_modes.count(mode) == 0)) { Log::error("ServerLobby", "Mode %d and/or difficulty %d are not permitted."); - auto peer = event->getPeerSP(); - NetworkString* chat = getNetworkString(); - // I don't know for now which type to choose... - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16(L"Mode or difficulty are not permitted on this server"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; + std::string msg = "Mode or difficulty are not permitted on this server"; + sendStringToPeer(msg, peer); return; } - auto modes = ServerConfig::getLocalGameMode(new_game_mode); + auto modes = ServerConfig::getLocalGameMode(mode); if (modes.second == RaceManager::MAJOR_MODE_GRAND_PRIX) { Log::warn("ServerLobby", "Grand prix is used for new mode."); @@ -5819,30 +5734,30 @@ void ServerLobby::handleServerConfiguration(Event* event) RaceManager::get()->setMinorMode(modes.first); RaceManager::get()->setMajorMode(modes.second); - RaceManager::get()->setDifficulty(RaceManager::Difficulty(new_difficulty)); + RaceManager::get()->setDifficulty(RaceManager::Difficulty(difficulty)); m_game_setup->resetExtraServerInfo(); if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) - m_game_setup->setSoccerGoalTarget(new_soccer_goal_target); + m_game_setup->setSoccerGoalTarget(soccer_goal_target); if (NetworkConfig::get()->isWAN() && - (m_difficulty.load() != new_difficulty || - m_game_mode.load() != new_game_mode)) + (m_difficulty.load() != difficulty || + m_game_mode.load() != mode)) { Log::info("ServerLobby", "Updating server info with new " - "difficulty: %d, game mode: %d to stk-addons.", new_difficulty, - new_game_mode); + "difficulty: %d, game mode: %d to stk-addons.", difficulty, + mode); int priority = Online::RequestManager::HTTP_MAX_PRIORITY; auto request = std::make_shared(priority); NetworkConfig::get()->setServerDetails(request, "update-config"); const SocketAddress& addr = STKHost::get()->getPublicAddress(); request->addParameter("address", addr.getIP()); request->addParameter("port", addr.getPort()); - request->addParameter("new-difficulty", new_difficulty); - request->addParameter("new-game-mode", new_game_mode); + request->addParameter("new-difficulty", difficulty); + request->addParameter("new-game-mode", mode); request->queue(); } - m_difficulty.store(new_difficulty); - m_game_mode.store(new_game_mode); + m_difficulty.store(difficulty); + m_game_mode.store(mode); updateTracksForMode(); auto peers = STKHost::get()->getPeers(); @@ -5881,13 +5796,11 @@ void ServerLobby::handleServerConfiguration(Event* event) delete server_info; updatePlayerList(); - if (m_gnu_elimination && + if (m_kart_elimination.isEnabled() && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_NORMAL_RACE && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) { - m_gnu_elimination = false; - m_gnu_remained = 0; - m_gnu_participants.clear(); + m_kart_elimination.disable(); NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); @@ -5897,6 +5810,41 @@ void ServerLobby::handleServerConfiguration(Event* event) delete chat; } } // handleServerConfiguration +//----------------------------------------------------------------------------- +/*! \brief Called when the server owner request to change game mode or + * difficulty. + * \param event : Event providing the information. + * + * Format of the data : + * Byte 0 1 2 + * ----------------------------------------------- + * Size | 1 | 1 | 1 | + * Data | difficulty | game mode | soccer goal target | + * ----------------------------------------------- + */ +void ServerLobby::handleServerConfiguration(Event* event) +{ + if (event != NULL && event->getPeerSP() != m_server_owner.lock()) + { + Log::warn("ServerLobby", + "Client %d is not authorised to config server.", + event->getPeer()->getHostId()); + return; + } + int new_difficulty = ServerConfig::m_server_difficulty; + int new_game_mode = ServerConfig::m_server_mode; + bool new_soccer_goal_target = ServerConfig::m_soccer_goal_target; + if (event != NULL) + { + NetworkString& data = event->data(); + new_difficulty = data.getUInt8(); + new_game_mode = data.getUInt8(); + new_soccer_goal_target = data.getUInt8() == 1; + } + handleServerConfiguration( + (event ? event->getPeerSP() : std::shared_ptr()), + new_difficulty, new_game_mode, new_soccer_goal_target); +} // handleServerConfiguration //----------------------------------------------------------------------------- /*! \brief Called when a player want to change his handicap @@ -6048,6 +5996,13 @@ void ServerLobby::setPlayerKarts(const NetworkString& ns, STKPeer* peer) const { std::string kart; ns.decodeString(&kart); + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[i]->getName()); + if (m_kart_elimination.isEliminated(username)) + { + peer->getPlayerProfiles()[i]->setKartName(m_kart_elimination.getKart()); + continue; + } if (kart.find("randomkart") != std::string::npos || (kart.find("addon_") == std::string::npos && m_available_kts.first.find(kart) == m_available_kts.first.end())) @@ -6280,7 +6235,67 @@ void ServerLobby::handleServerCommand(Event* event, auto argv = StringUtils::split(cmd, ' '); if (argv.size() == 0) return; - if (argv[0] == "spectate") + if (argv[0] == "start") + { + if (!ServerConfig::m_owner_less && !hasHostRights(peer)) + { + std::string msg = "You are not server owner"; + sendStringToPeer(msg, peer); + return; + } + startSelection(event); + } + else if (argv[0] == "config") + { + if (!hasHostRights(peer)) + { + std::string msg = "You are not server owner"; + sendStringToPeer(msg, peer); + return; + } + int difficulty = getDifficulty(); + int mode = getGameMode(); + bool goal_target = m_game_setup->isSoccerGoalTarget(); + bool gp = false; + for (unsigned i = 1; i < argv.size(); i++) + { + if (argv[i] == "tt" || argv[i] == "time-trial"|| + argv[i] == "trial" || argv[i] == "m4") + mode = 4; + if (argv[i] == "normal" || argv[i] == "normal-race" || + argv[i] == "race" || argv[i] == "m3") + mode = 3; + if (argv[i] == "soccer" || argv[i] == "football" || + argv[i] == "m6") + mode = 6; + if (argv[i] == "ffa" || argv[i] == "free-for-all" || + argv[i] == "free" || argv[i] == "for" || + argv[i] == "all" || argv[i] == "m7") + mode = 7; + if (argv[i] == "ctf" || argv[i] == "capture-the-flag" + || argv[i] == "capture" || argv[i] == "the" || + argv[i] == "flag" || argv[i] == "m8") + mode = 8; + // if (argv[i] == "gp" || argv[i] == "grand-prix") + // gp = true; + if (argv[i] == "d0" || argv[i] == "novice" || argv[i] == "easy") + difficulty = 0; + if (argv[i] == "d1" || argv[i] == "intermediate" || argv[i] == "medium") + difficulty = 1; + if (argv[i] == "d2" || argv[i] == "expert" || argv[i] == "hard") + difficulty = 2; + if (argv[i] == "d3" || argv[i] == "supertux" || argv[i] == "super" || argv[i] == "best") + difficulty = 3; + if (argv[i] == "goal-limit" || argv[i] == "gl" || argv[i] == "goal" || argv[i] == "goals") + goal_target = true; + if (argv[i] == "time-limit" || argv[i] == "tl" || argv[i] == "time" || argv[i] == "minutes") + goal_target = false; + } + // if (gp && (mode == 3 || mode == 4)) + // mode -= 3; + handleServerConfiguration(peer, difficulty, mode, goal_target); + } + else if (argv[0] == "spectate") { if (ServerConfig::m_soccer_tournament || ServerConfig::m_only_host_riding) { @@ -6294,10 +6309,29 @@ void ServerLobby::handleServerCommand(Event* event, sendStringToPeer(msg, peer); return; } + if (argv.size() == 1) + { + if (m_state.load() != WAITING_FOR_START_GAME) + { + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (m_default_always_spectate_peers.count(peer.get())) + argv.push_back("0"); + else + argv.push_back("1"); + } + else + { + if (peer->alwaysSpectate()) + argv.push_back("0"); + else + argv.push_back("1"); + } + } if (argv.size() != 2 || (argv[1] != "0" && argv[1] != "1")) { - std::string msg = "Usage: spectate [0 or 1], before game started"; + std::string msg = "Usage: /spectate [empty or 0 or 1], sets or resets (or changes) the spectating mode."; sendStringToPeer(msg, peer); return; } @@ -6705,100 +6739,52 @@ void ServerLobby::handleServerCommand(Event* event, { if (m_server_owner.lock() != peer) { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16(L"You are not server owner"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; + std::string msg = "You are not server owner"; + sendStringToPeer(msg, peer); return; } - else if (m_gnu_elimination) + else if (m_kart_elimination.isEnabled()) { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16( - L"Gnu Elimination mode was already enabled!"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; + std::string msg = "Gnu Elimination mode was already enabled!"; + sendStringToPeer(msg, peer); } else if ( RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_NORMAL_RACE && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16( - L"Gnu Elimination is available only with racing modes"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; + std::string msg = "Gnu Elimination is available only with racing modes"; + sendStringToPeer(msg, peer); } else { if (argv.size() > 1 && m_available_kts.first.count(argv[1]) > 0) { - m_gnu_kart = argv[1]; + m_kart_elimination.enable(argv[1]); } else { - m_gnu_kart = "gnu"; + m_kart_elimination.enable("gnu"); } - NetworkString* chat = getNetworkString(); - m_gnu_elimination = true; - m_gnu_remained = -1; - m_gnu_participants.clear(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - if (m_gnu_kart == "gnu") - { - chat->encodeString16( - L"Gnu Elimination starts now! Use /standings " - "after each race for results."); - } - else - { - chat->encodeString16(StringUtils::utf8ToWide( - StringUtils::insertValues("Gnu Elimination starts now " - "(elimination kart: %s)! Use /standings " - "after each race for results.", m_gnu_kart))); - } - sendMessageToPeers(chat); - delete chat; + std::string msg = m_kart_elimination.getStartingMessage(); + sendStringToAllPeers(msg); } } else if (argv[0] == "nognu") { if (m_server_owner.lock() != peer) { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16(L"You are not server owner"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; + std::string msg = "You are not server owner"; + sendStringToPeer(msg, peer); return; } - else if (!m_gnu_elimination) + else if (!m_kart_elimination.isEnabled()) { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16( - L"Gnu Elimination mode was already off!"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; + std::string msg = "Gnu Elimination mode was already off!"; + sendStringToPeer(msg, peer); + return; } else { - NetworkString* chat = getNetworkString(); - m_gnu_elimination = false; - m_gnu_remained = 0; - m_gnu_participants.clear(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16( - L"Gnu Elimination is now off"); - sendMessageToPeers(chat); - delete chat; + m_kart_elimination.disable(); + std::string msg = "Gnu Elimination is now off"; + sendStringToAllPeers(msg); } } else if (argv[0] == "tell") @@ -6827,25 +6813,23 @@ void ServerLobby::handleServerCommand(Event* event, } else if (argv[0] == "standings") { + std::string msg; if (argv.size() > 1) { if (argv[1] == "gp") - sendGrandPrixStandingsToPeer(peer); + msg = getGrandPrixStandings(); else if (argv[1] == "gnu") - sendGnuStandingsToPeer(peer); + msg = m_kart_elimination.getStandings(); else - { - std::string msg = "Usage: /standings [gp | gnu]"; - sendStringToPeer(msg, peer); - } + msg = "Usage: /standings [gp | gnu]"; + sendStringToPeer(msg, peer); return; } if (m_game_setup->isGrandPrix()) - { - sendGrandPrixStandingsToPeer(peer); - return; - } - sendGnuStandingsToPeer(peer); + msg = getGrandPrixStandings(); + else + msg = m_kart_elimination.getStandings(); + sendStringToPeer(msg, peer); } else if (argv[0] == "teamchat") { @@ -7028,7 +7012,7 @@ void ServerLobby::handleServerCommand(Event* event, } else if (argv[0] == "version") { - std::string msg = "1.2-kimden 200828 beta"; + std::string msg = "1.2-kimden 201107 beta"; sendStringToPeer(msg, peer); } else if (argv[0] == "register") @@ -7139,6 +7123,8 @@ void ServerLobby::handleServerCommand(Event* event, "Ready to start game %d for %d ", m_tournament_game, m_fixed_lap) + (tournamentGoalsLimit(m_tournament_game) ? "goals" : "minutes"); sendStringToAllPeers(msg); + Log::info("ServerLobby", "SoccerMatchLog: Game number changed from %d to %d", + old_game, m_tournament_game); } else if (argv[0] == "role") { @@ -7160,6 +7146,10 @@ void ServerLobby::handleServerCommand(Event* event, sendStringToPeer(msg, peer); return; } + if (role[0] >= 'A' && role[0] <= 'Z') + role[0] += 'a' - 'A'; + Log::info("ServerLobby", "SoccerMatchLog: Role of %s changed to %s", + username.c_str(), role.c_str()); m_tournament_red_players.erase(username); m_tournament_blue_players.erase(username); m_tournament_referees.erase(username); @@ -7177,22 +7167,22 @@ void ServerLobby::handleServerCommand(Event* event, case 'R': case 'r': { + if (tournamentColorsSwapped(m_tournament_game)) + { + m_tournament_blue_players.insert(username); + if (permanent) + m_tournament_init_blue.insert(username); + } + else + { + m_tournament_red_players.insert(username); + if (permanent) + m_tournament_init_red.insert(username); + } if (player_peer) { role_changed = StringUtils::insertValues(role_changed, "red player"); player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_RED); - if (tournamentColorsSwapped(m_tournament_game)) - { - m_tournament_blue_players.insert(username); - if (permanent) - m_tournament_init_blue.insert(username); - } - else - { - m_tournament_red_players.insert(username); - if (permanent) - m_tournament_init_red.insert(username); - } sendStringToPeer(role_changed, player_peer); } break; @@ -7200,22 +7190,22 @@ void ServerLobby::handleServerCommand(Event* event, case 'B': case 'b': { + if (tournamentColorsSwapped(m_tournament_game)) + { + m_tournament_red_players.insert(username); + if (permanent) + m_tournament_init_red.insert(username); + } + else + { + m_tournament_blue_players.insert(username); + if (permanent) + m_tournament_init_blue.insert(username); + } if (player_peer) { role_changed = StringUtils::insertValues(role_changed, "blue player"); player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_BLUE); - if (tournamentColorsSwapped(m_tournament_game)) - { - m_tournament_red_players.insert(username); - if (permanent) - m_tournament_init_red.insert(username); - } - else - { - m_tournament_blue_players.insert(username); - if (permanent) - m_tournament_init_blue.insert(username); - } sendStringToPeer(role_changed, player_peer); } break; @@ -7260,6 +7250,7 @@ void ServerLobby::handleServerCommand(Event* event, sw->stop(); std::string msg = "The game is stopped."; sendStringToAllPeers(msg); + Log::info("ServerLobby", "SoccerMatchLog: The game is stopped"); } else if (argv[0] == "go" || argv[0] == "play" || argv[0] == "resume") { @@ -7270,6 +7261,7 @@ void ServerLobby::handleServerCommand(Event* event, sw->resume(); std::string msg = "The game is resumed."; sendStringToAllPeers(msg); + Log::info("ServerLobby", "SoccerMatchLog: The game is resumed"); } else if (argv[0] == "lobby") { @@ -7323,64 +7315,19 @@ void ServerLobby::updateGnuElimination() { World* w = World::getWorld(); assert(w); - assert(m_gnu_remained != 0); int player_count = RaceManager::get()->getNumPlayers(); - const double INF = 1e9; - std::vector> order; - if (m_gnu_remained < 0) - { - for (int i = 0; i < player_count; i++) - { - std::string username = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(i).getPlayerName()); - double elapsed_time = (w->getKart(i)->isEliminated() ? INF : - RaceManager::get()->getKartRaceTime(i)); - order.emplace_back(elapsed_time, username); - m_gnu_participants.push_back(username); - } - m_gnu_remained = player_count; - } - else - { - for (unsigned i = 0; i < m_gnu_participants.size(); i++) - { - order.emplace_back(INF, m_gnu_participants[i]); - } - // the number of players is very small and I don't want maps - for (int i = 0; i < player_count; i++) - { - std::string username = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(i).getPlayerName()); - double elapsed_time = (w->getKart(i)->isEliminated() ? INF : - RaceManager::get()->getKartRaceTime(i)); - for (int j = 0; j < m_gnu_remained; j++) - { - if (m_gnu_participants[j] == username) - { - order[j].first = elapsed_time; - break; - } - } - } - } - std::stable_sort(order.begin(), order.begin() + m_gnu_remained); - bool all_quit = false;//order[0].first == INF; - for (int i = 0; i < m_gnu_remained; i++) - m_gnu_participants[i] = order[i].second; - --m_gnu_remained; - if (!all_quit) + std::map order; + for (int i = 0; i < player_count; i++) { - while (m_gnu_remained - 1 >= 0 && order[m_gnu_remained - 1].first == INF) - --m_gnu_remained; - } - if (m_gnu_remained <= 1) { - m_gnu_elimination = false; - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - std::string message = "Gnu Elimination has finished! Congratulations to " + m_gnu_participants[0] + " !"; - chat->encodeString16(StringUtils::utf8ToWide(message)); - sendMessageToPeers(chat); - delete chat; + std::string username = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(i).getPlayerName()); + if (w->getKart(i)->isEliminated()) + order[username] = KartElimination::INF_TIME; + else + order[username] = RaceManager::get()->getKartRaceTime(i); } + std::string msg = m_kart_elimination.update(order); + if (!msg.empty()) + sendStringToAllPeers(msg); } // updateGnuElimination //----------------------------------------------------------------------------- void ServerLobby::storeResults() @@ -7512,7 +7459,7 @@ void ServerLobby::resetToDefaultSettings() { if (ServerConfig::m_server_configurable) handleServerConfiguration(NULL); - // m_gnu_elimination = false; + m_kart_elimination.disable(); } // resetToDefaultSettings //----------------------------------------------------------------------------- void ServerLobby::writeOwnReport(STKPeer* reporter, STKPeer* reporting, const std::string& info) @@ -7650,6 +7597,21 @@ void ServerLobby::initTournamentPlayers() else if (type == "J") m_tournament_referees.insert(s); } + for (const std::string& s: m_tournament_red_players) + { + Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to r", + s.c_str()); + } + for (const std::string& s: m_tournament_blue_players) + { + Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to b", + s.c_str()); + } + for (const std::string& s: m_tournament_referees) + { + Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to j", + s.c_str()); + } m_tournament_init_red = m_tournament_red_players; m_tournament_init_blue = m_tournament_blue_players; m_tournament_init_ref = m_tournament_referees; @@ -7680,7 +7642,13 @@ void ServerLobby::initTournamentPlayers() tokens.push_back("not %0"); tokens.push_back("not %0" " %1"); tokens.push_back(""); + ServerConfig::m_soccer_tournament_rules = "nochat 10 TTTTG RRBBR;" + ";;not %1;" + "not %1 " + "%2;;;"; } + Log::info("ServerLobby", "SoccerMatchLog: Tournament rules are set to \"%s\"", + ServerConfig::m_soccer_tournament_rules.c_str()); m_tournament_limited_chat = false; m_tournament_length = 10; if (general[0] == "nochat") @@ -7698,7 +7666,7 @@ void ServerLobby::initTournamentPlayers() m_tournament_max_games = std::min(general[2].length(), general[3].length()); m_tournament_max_games = std::min(m_tournament_max_games, (int)tokens.size() - 1); m_tournament_arenas.resize(m_tournament_max_games, ""); - for (unsigned i = 0; i < m_tournament_max_games; i++) + for (int i = 0; i < m_tournament_max_games; i++) m_tournament_track_filters.emplace_back(tokens[i + 1]); } // initTournamentPlayers //----------------------------------------------------------------------------- @@ -7721,6 +7689,8 @@ void ServerLobby::changeColors() //----------------------------------------------------------------------------- void ServerLobby::sendStringToPeer(std::string& s, std::shared_ptr& peer) const { + if (!peer) + return; NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); @@ -7749,22 +7719,14 @@ bool ServerLobby::canRace(STKPeer* peer) const std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); if (ServerConfig::m_soccer_tournament) - { return m_tournament_red_players.count(username) > 0 || m_tournament_blue_players.count(username) > 0; - } else if (ServerConfig::m_only_host_riding) - { return peer == m_server_owner.lock().get(); - } else if (!m_tracks_queue.empty()) - { return peer->getClientAssets().second.count(m_tracks_queue.front()); - } else - { return true; - } } // canRace //----------------------------------------------------------------------------- @@ -7797,26 +7759,7 @@ void ServerLobby::loadTracksQueueFromConfig() m_tracks_queue.push_back(s); } // loadTracksQueueFromConfig //----------------------------------------------------------------------------- -void ServerLobby::sendGnuStandingsToPeer(std::shared_ptr peer) const -{ - std::string result = "Gnu Elimination "; - if (m_gnu_elimination) - result += "is running"; - else - result += "is disabled"; - if (!m_gnu_participants.empty()) - result += ", standings:"; - for (int i = 0; i < (int)m_gnu_participants.size(); i++) - { - std::string line = "\n" + (i < m_gnu_remained ? - std::to_string(i + 1) : "[" + std::to_string(i + 1) + "]"); - line += ". " + m_gnu_participants[i]; - result += line; - } - sendStringToPeer(result, peer); -} // sendGnuStandingsToPeer -//----------------------------------------------------------------------------- -void ServerLobby::sendGrandPrixStandingsToPeer(std::shared_ptr peer) const +std::string ServerLobby::getGrandPrixStandings() const { std::vector> results; for (auto& p: m_gp_scores) @@ -7824,7 +7767,7 @@ void ServerLobby::sendGrandPrixStandingsToPeer(std::shared_ptr peer) co std::stable_sort(results.rbegin(), results.rend()); std::stringstream response; response << "Grand Prix standings\n"; - for (int i = 0; i < results.size(); i++) + for (unsigned i = 0; i < results.size(); i++) { response << (i + 1) << ". "; response << " " << results[i].second; @@ -7832,9 +7775,8 @@ void ServerLobby::sendGrandPrixStandingsToPeer(std::shared_ptr peer) co response << " " << "(" << StringUtils::timeToString(results[i].first.time) << ")"; response << "\n"; } - std::string answer = response.str(); - sendStringToPeer(answer, peer); -} // sendGnuStandingsToPeer + return response.str(); +} // getGrandPrixStandings //----------------------------------------------------------------------------- void ServerLobby::loadCustomScoring() { @@ -7947,108 +7889,23 @@ void ServerLobby::changeLimitForTournament(bool goal_target) updatePlayerList(); } // changeLimitForTournament //----------------------------------------------------------------------------- -/* -Tournament states are defined by taking the number of game modulo 8. -Below for each state the limit, colors (for first and second teams) and -icy / non-icy (listed as "addon") arena choice, are isted: -0: time, red blue, addon -1: time, red blue, icy -2: time, blue red, addon -3: time, blue red, icy -4: goals, red blue, icy -5: goals, red blue, addon -6: goals, blue red, icy -7: goals, blue red, addon -*/ -//----------------------------------------------------------------------------- bool ServerLobby::tournamentGoalsLimit(int game) const { return m_tournament_game_limits[game] == 'G'; - // int rem = game % 8; - // if (rem < 0) - // rem += 8; - // return (rem >> 2) & 1; } // tournamentGoalsLimit //----------------------------------------------------------------------------- bool ServerLobby::tournamentColorsSwapped(int game) const { return m_tournament_colors[game] == 'B'; - // int rem = game % 8; - // if (rem < 0) - // rem += 8; - // return (rem >> 1) & 1; } // tournamentColorsSwapped //----------------------------------------------------------------------------- -// bool ServerLobby::tournamentHasIcy(int game) const -// { -// int rem = game % 8; -// if (rem < 0) -// rem += 8; -// return (rem ^ (rem >> 2)) & 1; -// } // tournamentHasIcy -//----------------------------------------------------------------------------- void ServerLobby::initAvailableTracks() { m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); m_must_have_tracks = StringUtils::split( ServerConfig::m_must_have_tracks_string, ' ', false); - /*m_inverted_config_restriction = false; - m_restricting_config = true; - if (((std::string)(ServerConfig::m_only_played_tracks_string)).empty()) - { - m_restricting_config = false; - return; - } - std::vector available_tracks = - StringUtils::split(ServerConfig::m_only_played_tracks_string, - ' ', false); - - for (unsigned i = 0; i < available_tracks.size(); i++) - if (available_tracks[i] == "not") - m_inverted_config_restriction = true; - - for (unsigned i = 0; i < available_tracks.size(); i++) - { - if (available_tracks[i] == "not") - continue; - int separator = available_tracks[i].find(':'); - if (separator != std::string::npos) - { - std::string track = available_tracks[i].substr(0, separator); - std::string params_str = available_tracks[i].substr(separator + 1); - std::vector params = StringUtils::split( - params_str, ',', false); - m_config_track_limitations[track] = params; - } - else - m_config_available_tracks.insert(available_tracks[i]); - }*/ } // initAvailableTracks //----------------------------------------------------------------------------- -// int ServerLobby::getTrackMaxPlayers(std::string& name) const -// { -// auto map_entry = m_config_track_limitations.find(name); -// if (map_entry == m_config_track_limitations.end()) -// return INT_MAX; -// std::string key = "max_players"; -// auto map_value = map_entry->second; -// auto where = std::find(map_value.begin(), map_value.end(), key); -// auto end = map_value.end(); -// if (where == end) -// return INT_MAX; -// where++; -// if (where == end) -// return INT_MAX; -// int track_max_players; -// std::string max_str = *where; -// if (!StringUtils::parseString(max_str, &track_max_players)) -// { -// Log::warn("ServerLobby", "Bad max_players value for track %s", name.c_str()); -// return INT_MAX; -// } -// return track_max_players; -// } // getTrackMaxPlayers -//----------------------------------------------------------------------------- #ifdef ENABLE_WEB_SUPPORT diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 43a04c3b48b..fe45e0008ee 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -23,6 +23,7 @@ #include "utils/cpp2011.hpp" #include "utils/time.hpp" #include "utils/track_filter.hpp" +#include "utils/kart_elimination.hpp" #include "irrString.h" @@ -299,13 +300,7 @@ class ServerLobby : public LobbyProtocol std::set m_team_speakers; - bool m_gnu_elimination; - - int m_gnu_remained; - - std::string m_gnu_kart; - - std::vector m_gnu_participants; + KartElimination m_kart_elimination; std::set m_available_difficulties; @@ -386,6 +381,8 @@ class ServerLobby : public LobbyProtocol void updatePlayerList(bool update_when_reset_server = false); void updateServerOwner(); void handleServerConfiguration(Event* event); + void handleServerConfiguration(std::shared_ptr peer, + int difficulty, int mode, bool soccer_goal_target); void updateTracksForMode(); bool checkPeersReady(bool ignore_ai_peer) const; void resetPeersReady() @@ -487,7 +484,6 @@ class ServerLobby : public LobbyProtocol void writeDisconnectInfoTable(STKPeer* peer); void writePlayerReport(Event* event); bool supportsAI(); - void updateGnuElimination(); void updateAddons(); void initTournamentPlayers(); void changeColors(); @@ -498,8 +494,7 @@ class ServerLobby : public LobbyProtocol bool hasHostRights(std::shared_ptr& peer) const; bool hasHostRights(STKPeer* peer) const; void loadTracksQueueFromConfig(); - void sendGnuStandingsToPeer(std::shared_ptr peer) const; - void sendGrandPrixStandingsToPeer(std::shared_ptr peer) const; + std::string getGrandPrixStandings() const; void loadCustomScoring(); void updateWorldSettings(); void loadWhiteList(); @@ -556,6 +551,7 @@ class ServerLobby : public LobbyProtocol bool writeOnePlayerReport(STKPeer* reporter, const std::string& table, const std::string& info); // int getTrackMaxPlayers(std::string& name) const; + void updateGnuElimination(); }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/utils/kart_elimination.cpp b/src/utils/kart_elimination.cpp new file mode 100644 index 00000000000..56f9815c55c --- /dev/null +++ b/src/utils/kart_elimination.cpp @@ -0,0 +1,160 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2004-2020 Steve Baker , +// Copyright (C) 2004-2020 Ingo Ruhnke +// Copyright (C) 2006-2020 SuperTuxKart-Team +// Copyright (C) 2020 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/kart_elimination.hpp" + +#include "utils/string_utils.hpp" +#include "utils/log.hpp" +#include +#include +#include +#include +#include +#include +#include + + +//----------------------------------------------------------------------------- +KartElimination::KartElimination() +{ + m_enabled = false; + m_remained = 0; + m_kart = ""; +} // KartElimination +//----------------------------------------------------------------------------- +bool KartElimination::isEliminated(std::string username) const +{ + if (!m_enabled || m_remained < 0) + return false; + for (int i = 0; i < m_remained; i++) + if (m_participants[i] == username) + return false; + return true; +} // isEliminated +//----------------------------------------------------------------------------- +std::set KartElimination::getRemainingParticipants() const +{ + std::set ans; + if (!m_enabled) + return ans; + for (int i = 0; i < m_remained; i++) + ans.insert(m_participants[i]); + return ans; +} // getRemainingParticipants +//----------------------------------------------------------------------------- +std::string KartElimination::getStandings() const +{ + std::string result = "Gnu Elimination "; + if (m_enabled) + result += "is running"; + else + result += "is disabled"; + if (!m_participants.empty()) + result += ", standings:"; + for (int i = 0; i < (int)m_participants.size(); i++) + { + std::string line = "\n" + (i < m_remained ? + std::to_string(i + 1) : "[" + std::to_string(i + 1) + "]"); + line += ". " + m_participants[i]; + result += line; + } + return result; +} // getStandings +//----------------------------------------------------------------------------- +void KartElimination::disable() +{ + m_kart = ""; + m_enabled = false; + m_remained = 0; + m_participants.clear(); +} // disable +//----------------------------------------------------------------------------- +void KartElimination::enable(std::string kart) +{ + m_kart = kart; + m_enabled = true; + m_remained = -1; + m_participants.clear(); +} // enable +//----------------------------------------------------------------------------- +std::string KartElimination::getStartingMessage() const +{ + if (m_kart == "gnu") + return "Gnu Elimination starts now! Use /standings " + "after each race for results."; + else + return StringUtils::insertValues("Gnu Elimination starts now " + "(elimination kart: %s)! Use /standings " + "after each race for results.", m_kart.c_str()); +} // getStartingMessage +//----------------------------------------------------------------------------- +std::string KartElimination::getWarningMessage() const +{ + return StringUtils::insertValues( + "Gnu Elimination is played right now on this server, " + "you will be forced to use kart %s until it ends. " + "Use /standings to see the results.", + m_kart.c_str()); +} // getWarningMessage +//----------------------------------------------------------------------------- + +std::string KartElimination::update( + std::map& order) +{ + assert(m_remained != 0); + if (m_remained < 0) + { + m_remained = order.size(); + for (const auto& p: order) + m_participants.push_back(p.first); + } + for (int i = 0; i < m_remained; i++) + { + if (order.count(m_participants[i]) == 0) + order[m_participants[i]] = KartElimination::INF_TIME; + } + std::stable_sort(m_participants.begin(), m_participants.begin() + m_remained, + [order](const std::string& a, const std::string& b) -> bool { + auto it1 = order.find(a); + auto it2 = order.find(b); + return it1->second < it2->second; + }); + std::string msg = ""; + msg += m_participants[--m_remained]; + bool alone = true; + while (m_remained - 1 >= 0 && order[m_participants[m_remained - 1]] == KartElimination::INF_TIME) + { + msg += ", " + m_participants[--m_remained]; + alone = false; + } + if (alone) + msg += " is now eliminated."; + else + msg += " are now eliminated."; + if (m_remained <= 1) { + m_enabled = false; + msg += "\nGnu Elimination has finished! Congratulations to " + m_participants[0] + " !"; + } + return msg; +} // update +//----------------------------------------------------------------------------- + +/* EOF */ diff --git a/src/utils/kart_elimination.hpp b/src/utils/kart_elimination.hpp new file mode 100644 index 00000000000..e8d310f8bae --- /dev/null +++ b/src/utils/kart_elimination.hpp @@ -0,0 +1,57 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2004-2020 Steve Baker , +// Copyright (C) 2004-2020 Ingo Ruhnke +// Copyright (C) 2006-2020 SuperTuxKart-Team +// Copyright (C) 2020 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_KART_ELIMINATION_HPP +#define HEADER_KART_ELIMINATION_HPP + +#include "utils/types.hpp" +#include "utils/string_utils.hpp" +#include +#include +#include +#include +#include + +// A class that contains Gnu Elimination data + +class KartElimination { +private: + bool m_enabled; + int m_remained; + std::string m_kart; + std::vector m_participants; + +public: + static constexpr double INF_TIME = 1e9; + KartElimination(); + bool isEliminated(std::string username) const; + std::string getKart() const { return m_kart; } + std::set getRemainingParticipants() const; + bool isEnabled() const { return m_enabled; } + void enable(std::string kart); // done + void disable(); // done + std::string getStandings() const; // done + std::string getStartingMessage() const; // done + std::string getWarningMessage() const; // done + std::string update(std::map& order); +}; + +#endif From 16bd27f23113167f7f14e0da6ee11e01084f4aea Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 20 Dec 2020 18:57:53 +0300 Subject: [PATCH 091/830] Allow recording replays, add initial support for server-to-player delayed messages, fix bugs, allow spectators to enter tournament server without arenas, allow tournaments with different time limit --- FORK_CHANGES.md | 105 +++++--- src/network/protocols/server_lobby.cpp | 352 +++++++++++++++++++++---- src/network/protocols/server_lobby.hpp | 12 + src/network/server_config.cpp | 4 +- src/network/server_config.hpp | 16 +- src/replay/replay_recorder.cpp | 6 +- 6 files changed, 406 insertions(+), 89 deletions(-) diff --git a/FORK_CHANGES.md b/FORK_CHANGES.md index 361c73c9dba..043300a5e9a 100644 --- a/FORK_CHANGES.md +++ b/FORK_CHANGES.md @@ -1,33 +1,76 @@ # This fork's changes compared to main STK -This is only a short description. - -1. Allowed partly configurable servers (the main game allows either no configuration or full configuration, while this version allows for example enforcing SuperTux difficulty and allowing racing modes only). - -2. Resetting server to initial mode and difficulty after all players are gone (doesn't work if players quit mid-race for now). - -3. `max-moveable-objects > 24` for bowling addon - -4. `/help` and `/commands` - -5. Gnu elimination mode: `/gnu`, `/nognu`, `/standings` - -6. Allowed forcing players to have certain tracks to enter the server; limiting played tracks to make very custom servers or forbid tracks that crash online - -7. Allowed forcing players to have certain number of addons (differentiated by its type) to make addons servers - -8. Private chat (`/to`, `/public`) and soccer / ctf `/teamchat` - -9. Fixed lap count servers - -10. Non-racing servers - -11. Official tracks can be not required - -12. Allowed storing race results - -13. Allowed `/records` queries to server - -14. Allowed to have a server in soccer tournament mode. - -Of course, there are some further plans ~~which will be announced when they are implemented or when I realize they cannot be implemented~~. +I could forget something. + +## Major features + +* Possibility to have a proper Grand Prix server: doesn't become private after the start, players can use different karts in different races, players can join or leave, added custom scoring, in-game (short) and in-lobby (longer) standings. +* Possibility to play a Gnu Elimination. +* Soccer tournament mode: the first mode to have players colored in 3 colors, enforces rules of soccer tournament provided in config file. The number of matches, their duration, team colors, allowed arenas, tournament teams, special labels can be changed. Referees have multiple commands to control the game flow. +* Possibility to have a table of records for racing servers and notify a player if he has beaten a record. +* Possibility to record ghost replays on a server if the player agrees. +* Angry owner mode: with password available only to owner, the owner can become invulnerable to kicks and kick (or temporarily ban) annoying players even being not a crowned player. There are also some other functions like forbidding to start the game. +* Possibility to force players to have certain number of certain addons (karts, tracks, battle arenas and/or soccer fields) to enter the server. +* Possibility to send messages only to certain players. +* /teamchat: a command that makes messages to be received only by teammates in team-based gamemodes. Unlike built-in button (that appeared much later), works also in the lobby. +* Auto spectating mode (/spectate) slightly differs from the main STK and is actively used in servers on which not all players are intended to play. +* Possibility to make a server where only the crowned player can play. + +## Minor features + +* Possibility to provide information to players using /help command without making server description long. +* Possibility to force players to have certain tracks/arenas to enter the server. +* Possibility to enable (or disable) only a fixed subset of tracks/arenas on the server. +* Possibility to have a server with fixed lap count (up to 255) and/or fixed number of goals/duration of soccer game. +* Possibility to forbid certain difficulties and/or modes on a configurable server. +* Possibility to create chat-only server. +* Possibility to disable kicks on a server with crowned player. +* Possibility for players to send a message to the server owner (works like a report in the database), and for the server owner to send one-time messages to certain players. +* Possibility to store the facts of one player kicking another in a database with reports. +* Possibility to have "unfair teams" in team-based gamemodes (like 1 vs 7). +* Possibility to predefine the first several tracks played on the server. +* Possibility to allow a predefined list of players to enter anything as a password for a private server. +* Possibility to not show mobile icons near players' names. +* Possibility to get rid of own goals and replace most of them with normal goals using the principle "the scorer is the one who touched last from the scoring team". +* max-moveable-objects is changed to 30 to allow tracks like bowling to work. +* Servers try to reset to initial mode and difficulty when all players are gone (doesn't work if players quit mid-race for now). + +## Commands + +Standard STK server commands work in the same way, with the exception of `/spectate`, which toggles your autospectate state on and off, and the game does *not* start if all players want to spectate. + +* `/standings [gp|gnu]` - a command to show the standings of an ongoing Grand Prix or Gnu elimination. One can specify which standings to show in the (rare) case when there are both. +* `/gnu [kart_id]` - starts a Gnu elimination with Gnu kart (or another kart if specified). +* `/nognu` - stops a Gnu elimination. +* `/record (track_id) (time-trial|normal) (normal|reverse) (laps)` - finds the best time in the database corresponding to the specified race settings. +* `/replay (0|1)` - tells the server to record or to not record a ghost replay. +* `/to [player] [...] [player]` - forces the server to send your messages only to specified players. A lock emoji is displayed in case the message is not sent to everyone. +* `/public` - erases `/to` limitations. +* `/teamchat` - forces the server to send your messages only to your teammates in soccer and CTF modes. Note that there is an official GUI alternative, but it works only in-game. `/teamchat` also works in lobby, but doesn't work with splitscreen multiplayer. You can use any combination of two teamchats at any moment. +* `/start` - has the same effect as pressing the green ready button. +* `/config (parameters)` - set the server difficulty and/or mode to a specified value. It is equivalent to choosing from a GUI menu. +* `/commands` - lists some of available commands. +* `/tell (info)` - sends a report to a server. +* `/version` - displays the version. It is set manually in the code for now, and server owners can change it at their own decision. If you change the version, we recommend to make sure the version is informative enough to compare different servers. +* `/register (info)` - allows to register for an event, the information is stored as a report in a specified table in a database. + + +## Soccer tournament referee commands +* `/role (player) (role_id)`, `/role (player) (role_id)` - sets a role to a player, where `role_id` is one of characters in `RrBbJjSs`. +* `/game [number [duration]]` - starts the next (or specified) game with the default (or specified) duration (in minutes or goals, depending on the tournament format). +* `/stop` - stops the goal count during the game. +* `/go | /resume | /continue` - resumes the goal count of game. +* `/lobby` - stops the game fully, forcing all players to move to the lobby. +* `/init (red_goals) (blue_goals)` - sets the initial goal count of the game to a specific value (during the game). Players will see it at the bottom of the screen. + +Referees can also use all server admin commands and crowned player commands (`/kick`, etc.). + +## Server admin commands + +* `/power (password)` - switches the admin to invulnerable mode, in which no one can kick the admin, but the admin can kick anyone regardless of who is the crowned player (if any), and invoke additional commands. +* `/admin (command)` - can only be invoked in invulnerable mode. +* `/admin start (0|1)` - allows or forbids to start the game. Can be useful for scheduled events, or to prevent players from starting too fast. +* `/kickban [player]`, `/ban [player]` - temporarily bans a player (it is reset upon server restart). The first version also kicks the player from the server, and thus can be used only when that player is on the server. +* `/unban [player]` - removes temporary ban from a player. Note that database-stored bans are not affected by `/ban`, `/kickban`, and `/unban` commands. + +Invulnerable mode also allows invoking server owner commands. diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 8e3a0114031..dd9c62931be 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -178,10 +178,14 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_help_message = getGameSetup()->readOrLoadFromFile ((std::string) ServerConfig::m_help); - m_available_commands = "help commands music kick to public " - "teamchat gnu nognu standings record tell " - "installaddon uninstalladdon liststkaddon listlocaladdon " - "listserveraddon playerhasaddon playeraddonscore serverhasaddon"; + m_available_commands = "admin ban commands config game gnu go help init " + "installaddon kick kickban listlocaladdon listserveraddon " + "liststkaddon lobby nognu play playeraddonscore playerhasaddon " + "power public record register replay resume role serverhasaddon " + "spectate standings start stop teamchat tell to token unban " + "uninstalladdon version"; + + m_consent_on_replays = false; m_fixed_lap = ServerConfig::m_fixed_lap_count; @@ -242,7 +246,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_player_reports_table_exists = false; initDatabase(); - if (ServerConfig::m_soccer_tournament) { + if (ServerConfig::m_soccer_tournament) + { initTournamentPlayers(); m_tournament_game = 0; } @@ -852,10 +857,11 @@ void ServerLobby::handleChat(Event* event) NetworkString* chat = getNetworkString(); chat->setSynchronous(true); - chat->addUInt8(LE_CHAT).encodeString16(message); const bool game_started = m_state.load() != WAITING_FOR_START_GAME; STKPeer* sender = event->getPeer(); auto can_receive = m_message_receivers[sender]; + if (!can_receive.empty()) + message = StringUtils::utf32ToWide({0x1f512, 0x20}) + message; bool team_speak = m_team_speakers.find(sender) != m_team_speakers.end(); team_speak &= ( RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER || @@ -888,7 +894,7 @@ void ServerLobby::handleChat(Event* event) for (const std::string& s: m_tournament_blue_players) important_players.insert(s); } - + chat->addUInt8(LE_CHAT).encodeString16(message); STKHost::get()->sendPacketToAllPeersWith( [game_started, sender_in_game, target_team, can_receive, sender, team_speak, teams, tournament_limit, @@ -902,7 +908,8 @@ void ServerLobby::handleChat(Event* event) return false; if (!p->isWaitingForGame() && sender_in_game) return false; - if (tournament_limit) { + if (tournament_limit) + { bool all_are_important = true; for (auto& player : p->getPlayerProfiles()) { @@ -964,9 +971,9 @@ void ServerLobby::changeTeam(Event* event) uint8_t local_id = data.getUInt8(); auto& player = event->getPeer()->getPlayerProfiles().at(local_id); auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); - if (ServerConfig::m_soccer_tournament) { + if (ServerConfig::m_soccer_tournament) return; // message here? - } + // At most 7 players on each team (for live join) if (player->getTeam() == KART_TEAM_BLUE) { @@ -1021,7 +1028,8 @@ void ServerLobby::kickHost(Event* event) Log::info("ServerLobby", "Crown player kicks %s", player_name.c_str()); } peer->kick(); - if (ServerConfig::m_track_kicks) { + if (ServerConfig::m_track_kicks) + { std::string auto_report = "[ Auto report caused by kick ]"; writeOwnReport(peer.get(), event->getPeerSP().get(), auto_report); } @@ -1849,9 +1857,9 @@ void ServerLobby::asynchronousUpdate() uint16_t flag_return_time = (uint16_t)stk_config->time2Ticks( ServerConfig::m_flag_return_timeout); RaceManager::get()->setFlagReturnTicks(flag_return_time); - if (ServerConfig::m_only_host_riding && - RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_TIME_TRIAL) + if (ServerConfig::m_record_replays && m_consent_on_replays && + (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL || + RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE)) RaceManager::get()->setRecordRace(true); uint16_t flag_deactivated_time = (uint16_t)stk_config->time2Ticks( ServerConfig::m_flag_deactivated_time); @@ -2659,7 +2667,8 @@ void ServerLobby::startSelection(const Event *event) m_state.load()); return; } - if (ServerConfig::m_sleeping_server) { + if (ServerConfig::m_sleeping_server) + { Log::warn("ServerLobby", "An attempt to start a race on a sleeping server. Lol."); return; @@ -2667,7 +2676,8 @@ void ServerLobby::startSelection(const Event *event) auto peer = event->getPeerSP(); if (ServerConfig::m_owner_less) { - if (!m_allowed_to_start) { + if (!m_allowed_to_start) + { std::string msg = "Starting the game is forbidden by server owner"; sendStringToPeer(msg, peer); return; @@ -2686,7 +2696,8 @@ void ServerLobby::startSelection(const Event *event) return; } } - if (!m_allowed_to_start) { + if (!m_allowed_to_start) + { std::string msg = "Starting the game is forbidden by server owner"; sendStringToPeer(msg, peer); return; @@ -2699,7 +2710,8 @@ void ServerLobby::startSelection(const Event *event) return; } } else { - if (!m_allowed_to_start) { + if (!m_allowed_to_start) + { // Produce no log spam return; } @@ -2983,7 +2995,7 @@ void ServerLobby::startSelection(const Event *event) ns->addUInt8(LE_START_SELECTION) .addFloat(ServerConfig::m_voting_timeout) .addUInt8(/*m_game_setup->isGrandPrixStarted() ? 1 : */0) - .addUInt8((ServerConfig::m_fixed_lap_count >= 0 + .addUInt8((m_fixed_lap >= 0 || ServerConfig::m_auto_game_time_ratio > 0.0f) ? 1 : 0) .addUInt8(ServerConfig::m_track_voting ? 1 : 0); @@ -3030,7 +3042,7 @@ void ServerLobby::startSelection(const Event *event) ns->addUInt8(LE_START_SELECTION) .addFloat(ServerConfig::m_voting_timeout) .addUInt8(/*m_game_setup->isGrandPrixStarted() ? 1 : */0) - .addUInt8((ServerConfig::m_fixed_lap_count >= 0 + .addUInt8((m_fixed_lap >= 0 || ServerConfig::m_auto_game_time_ratio > 0.0f) ? 1 : 0) .addUInt8(ServerConfig::m_track_voting ? 1 : 0); @@ -3076,9 +3088,11 @@ void ServerLobby::startSelection(const Event *event) back_lobby->setSynchronous(true); back_lobby->addUInt8(LE_BACK_LOBBY).addUInt8(BLR_SPECTATING_NEXT_GAME); STKHost::get()->sendPacketToAllPeersWith( - [always_spectate_peers](STKPeer* peer) { - return always_spectate_peers.find(peer) != - always_spectate_peers.end(); }, back_lobby, /*reliable*/true); + [always_spectate_peers](STKPeer* peer) + { + return always_spectate_peers.find(peer) != + always_spectate_peers.end(); + }, back_lobby, /*reliable*/true); delete back_lobby; updatePlayerList(); } @@ -3340,7 +3354,8 @@ void ServerLobby::checkRaceFinished() ranking_changes_indication = 1; m_result_ns->addUInt8(ranking_changes_indication); - if (m_kart_elimination.isEnabled()) { + if (m_kart_elimination.isEnabled()) + { // ServerLobby's function because we need to take // the list of players from somewhere updateGnuElimination(); @@ -3550,7 +3565,8 @@ void ServerLobby::computeNewRankings() // on how expected the result was (upsets can increase RD) // If there was a disconnect in this race, RD was handled once already - if (!w->getKart(i)->isEliminated()) { + if (!w->getKart(i)->isEliminated()) + { // First the RD reduction based on accuracy and current RD double rd_change_factor = accuracy * 0.0016; double rd_change = (-1) * prev_rating_deviations[i] * rd_change_factor; @@ -4305,6 +4321,10 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); std::string utf8_online_name = StringUtils::wideToUtf8(online_name); + bool erased_from_tournament_roles = false; + std::vector missing_assets; + if (ServerConfig::m_soccer_tournament) + missing_assets = getMissingTournamentAssets(peer); for (unsigned i = 0; i < player_count; i++) { core::stringw name; @@ -4339,7 +4359,17 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, } player->setTeam(cur_team); } - if (ServerConfig::m_soccer_tournament) { + if (ServerConfig::m_soccer_tournament) + { + if (!missing_assets.empty()) + { + erased_from_tournament_roles |= m_tournament_red_players.count(utf8_online_name) > 0; + erased_from_tournament_roles |= m_tournament_blue_players.count(utf8_online_name) > 0; + erased_from_tournament_roles |= m_tournament_referees.count(utf8_online_name) > 0; + m_tournament_red_players.erase(utf8_online_name); + m_tournament_blue_players.erase(utf8_online_name); + m_tournament_referees.erase(utf8_online_name); + } if (m_tournament_red_players.count(utf8_online_name)) player->setTeam(KART_TEAM_RED); else if (m_tournament_blue_players.count(utf8_online_name)) @@ -4534,6 +4564,32 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, peer->sendPacket(chat, true/*reliable*/); delete chat; } + if (ServerConfig::m_record_replays) + { + std::string msg; + if (m_consent_on_replays) + msg = "Recording ghost replays is enabled. " + "The crowned player can change that " + "using /replay 0 (to disable) or /replay 1 (to enable). " + "Do not race under this feature if you don't want to be recorded."; + else + msg = "Recording ghost replays is disabled. " + "The crowned player can change that " + "using /replay 0 (to disable) or /replay 1 (to enable). "; + sendStringToPeer(msg, peer); + } + if (erased_from_tournament_roles) + { + std::string msg = "You are now spectator because you lack the following assets:"; + for (unsigned i = 0; i < missing_assets.size(); i++) + { + if (i) + msg.push_back(','); + msg += " " + missing_assets[i]; + } + sendStringToPeer(msg, peer); + } + getMessagesFromHost(peer.get(), online_id); } // handleUnencryptedConnection //----------------------------------------------------------------------------- @@ -4623,6 +4679,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) bool angry_host = profile->getPeer()->isAngryHost(); std::string os_type_str = version_os.second; auto profile_name = profile->getName(); + std::string utf8_profile_name = StringUtils::wideToUtf8(profile_name); // Add a Mobile emoji for mobile OS if (ServerConfig::m_expose_mobile && (os_type_str == "iOS" || os_type_str == "Android")) @@ -4631,6 +4688,20 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) if (angry_host) profile_name = StringUtils::utf32ToWide({0x1F528}) + profile_name; + std::string prefix = ""; + for (const std::string& category: m_categories_for_player[utf8_profile_name]) + { + if (m_tournament_displayed_categories.count(category)) + prefix += category + ", "; + } + if (!prefix.empty()) + { + prefix.resize((int)prefix.size() - 2); + prefix = "[" + prefix + "] "; + } + + profile_name = StringUtils::utf8ToWide(prefix) + profile_name; + pl->addUInt32(profile->getHostId()).addUInt32(profile->getOnlineId()) .addUInt8(profile->getLocalPlayerId()) .encodeString(profile_name); @@ -4777,7 +4848,8 @@ void ServerLobby::handlePlayerVote(Event* event) } // Remove / adjust any invalid settings - if (ServerConfig::m_soccer_tournament) { + if (ServerConfig::m_soccer_tournament) + { vote.m_reverse = false; } else if (RaceManager::get()->modeHasLaps()) @@ -4827,7 +4899,8 @@ void ServerLobby::handlePlayerVote(Event* event) vote.m_num_laps = 0; vote.m_reverse = false; } - if (m_fixed_lap >= 0) { + if (m_fixed_lap >= 0) + { vote.m_num_laps = m_fixed_lap; } @@ -5490,6 +5563,62 @@ void ServerLobby::testBannedForIP(STKPeer* peer) const #endif } // testBannedForIP +//----------------------------------------------------------------------------- +void ServerLobby::getMessagesFromHost(STKPeer* peer, int online_id) const +{ +#ifdef ENABLE_SQLITE3 + if (!m_db || !m_player_reports_table_exists || online_id == 0) + return; + + int row_id; + // At most one message for now, sorry + std::string query = StringUtils::insertValues( + "SELECT rowid, reported_time, info FROM \"%s\" " + "WHERE reporter_online_id = %u " + "AND reporting_online_id = -1 " + "AND (server_uid = \"\" OR server_uid = \"%s\") LIMIT 1;", + ServerConfig::m_player_reports_table.c_str(), + online_id, ServerConfig::m_server_uid.c_str()); + + sqlite3_stmt* stmt = NULL; + int ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0); + if (ret == SQLITE_OK) + { + ret = sqlite3_step(stmt); + if (ret == SQLITE_ROW) + { + row_id = sqlite3_column_int(stmt, 0); + const char* timestamp = (char*)sqlite3_column_text(stmt, 1); + const char* info = (char*)sqlite3_column_text(stmt, 2); + Log::info("ServerLobby", "A message from server was delivered"); + std::string msg = "A message from the server (" + + std::string(timestamp) + "):\n" + std::string(info); + sendStringToPeer(msg, peer); + } + ret = sqlite3_finalize(stmt); + if (ret != SQLITE_OK) + { + Log::error("ServerLobby", + "Error finalize database for query %s: %s", + query.c_str(), sqlite3_errmsg(m_db)); + } + } + else + { + Log::error("ServerLobby", "Error preparing database for query %s: %s", + query.c_str(), sqlite3_errmsg(m_db)); + return; + } + if (row_id != -1) + { + query = StringUtils::insertValues( + "DELETE FROM \"%s\" WHERE rowid = %u;", + ServerConfig::m_player_reports_table.c_str(), row_id); + easySQLQuery(query); + } +#endif +} // getMessagesFromHost + //----------------------------------------------------------------------------- void ServerLobby::testBannedForIPv6(STKPeer* peer) const { @@ -6235,7 +6364,34 @@ void ServerLobby::handleServerCommand(Event* event, auto argv = StringUtils::split(cmd, ' '); if (argv.size() == 0) return; - if (argv[0] == "start") + if (argv[0] == "replay") + { + if (!ServerConfig::m_owner_less && !hasHostRights(peer)) + { + std::string msg = "You are not server owner"; + sendStringToPeer(msg, peer); + return; + } + if (ServerConfig::m_record_replays) + { + if (argv.size() >= 2 && argv[1] == "0") + m_consent_on_replays = false; + else if (argv.size() >= 2 && argv[1] == "1") + m_consent_on_replays = true; + else + m_consent_on_replays ^= 1; + + std::string msg = "Recording ghost replays is now "; + msg += (m_consent_on_replays ? "on" : "off"); + sendStringToAllPeers(msg); + } + else + { + std::string msg = "This server doesn't allow recording replays"; + sendStringToPeer(msg, peer); + } + } + else if (argv[0] == "start") { if (!ServerConfig::m_owner_less && !hasHostRights(peer)) { @@ -6547,7 +6703,8 @@ void ServerLobby::handleServerCommand(Event* event, } Log::info("ServerLobby", "Crown player kicks %s", player_name.c_str()); player_peer->kick(); - if (ServerConfig::m_track_kicks) { + if (ServerConfig::m_track_kicks) + { std::string auto_report = "[ Auto report caused by kick ]"; writeOwnReport(player_peer.get(), peer.get(), auto_report); } @@ -6757,7 +6914,8 @@ void ServerLobby::handleServerCommand(Event* event, } else { - if (argv.size() > 1 && m_available_kts.first.count(argv[1]) > 0) { + if (argv.size() > 1 && m_available_kts.first.count(argv[1]) > 0) + { m_kart_elimination.enable(argv[1]); } else { m_kart_elimination.enable("gnu"); @@ -6843,7 +7001,8 @@ void ServerLobby::handleServerCommand(Event* event, } else if (argv[0] == "to") { - if (argv.size() == 1) { + if (argv.size() == 1) + { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); @@ -6855,7 +7014,8 @@ void ServerLobby::handleServerCommand(Event* event, chat->addUInt8(LE_CHAT); chat->setSynchronous(true); m_message_receivers[peer.get()].clear(); - for (unsigned i = 1; i < argv.size(); ++i) { + for (unsigned i = 1; i < argv.size(); ++i) + { m_message_receivers[peer.get()].insert( StringUtils::utf8ToWide(argv[i])); } @@ -6983,23 +7143,28 @@ void ServerLobby::handleServerCommand(Event* event, else if (argv[0] == "admin") { std::string msg; - if (!peer->isAngryHost() && !ServerConfig::m_soccer_tournament) { + bool can = (peer->isAngryHost() || (ServerConfig::m_soccer_tournament && hasHostRights(peer))); + if (!can) { msg = "You cannot control this server"; sendStringToPeer(msg, peer); return; } - if (argv.size() == 1) { + if (argv.size() == 1) + { msg = "Usage: /admin command arg1 arg2 ..."; sendStringToPeer(msg, peer); return; } - if (argv[1] == "start") { - if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) { + if (argv[1] == "start") + { + if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) + { msg = "Usage: /admin start [0/1] - allow or forbid starting a race"; sendStringToPeer(msg, peer); return; } - if (argv[2] == "0") { + if (argv[2] == "0") + { m_allowed_to_start = false; msg = "Now starting a race is forbidden"; } else { @@ -7009,10 +7174,24 @@ void ServerLobby::handleServerCommand(Event* event, sendStringToPeer(msg, peer); return; } + if (argv[1] == "timeout") + { + int seconds; + if (argv.size() < 3 || !StringUtils::parseString(argv[2], &seconds) || seconds <= 0) + { + msg = "Usage: /admin timeout [positive int x] - set timeout to x seconds"; + sendStringToPeer(msg, peer); + return; + } + m_timeout.store((int64_t)StkTime::getMonoTimeMs() + + (int64_t)(seconds * 1000.0f)); + updatePlayerList(); + return; + } } else if (argv[0] == "version") { - std::string msg = "1.2-kimden 201107 beta"; + std::string msg = "1.2-kimden 201220 beta"; sendStringToPeer(msg, peer); } else if (argv[0] == "register") @@ -7077,7 +7256,8 @@ void ServerLobby::handleServerCommand(Event* event, { std::string peer_username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); - if (m_tournament_referees.count(peer_username) == 0) { + if (m_tournament_referees.count(peer_username) == 0) + { std::string msg = "You are not a referee"; sendStringToPeer(msg, peer); return; @@ -7085,11 +7265,12 @@ void ServerLobby::handleServerCommand(Event* event, if (argv[0] == "game") { int old_game = m_tournament_game; - if (argv.size() < 2) { + if (argv.size() < 2) + { ++m_tournament_game; if (m_tournament_game == m_tournament_max_games) m_tournament_game = 0; - m_fixed_lap = 10; + m_fixed_lap = ServerConfig::m_fixed_lap_count; } else { if (!StringUtils::parseString(argv[1], &m_tournament_game) || m_tournament_game < 0 @@ -7162,11 +7343,20 @@ void ServerLobby::handleServerCommand(Event* event, std::string role_changed = "The referee has updated your role - you are now %s"; std::shared_ptr player_peer = STKHost::get()->findPeerByName( StringUtils::utf8ToWide(username)); + std::vector missing_assets; + if (player_peer) + missing_assets = getMissingTournamentAssets(player_peer); + bool fail = false; switch (role[0]) { case 'R': case 'r': { + if (!missing_assets.empty()) + { + fail = true; + break; + } if (tournamentColorsSwapped(m_tournament_game)) { m_tournament_blue_players.insert(username); @@ -7190,6 +7380,11 @@ void ServerLobby::handleServerCommand(Event* event, case 'B': case 'b': { + if (!missing_assets.empty()) + { + fail = true; + break; + } if (tournamentColorsSwapped(m_tournament_game)) { m_tournament_red_players.insert(username); @@ -7213,6 +7408,11 @@ void ServerLobby::handleServerCommand(Event* event, case 'J': case 'j': { + if (!missing_assets.empty()) + { + fail = true; + break; + } m_tournament_referees.insert(username); if (permanent) m_tournament_init_ref.insert(username); @@ -7236,8 +7436,21 @@ void ServerLobby::handleServerCommand(Event* event, break; } } - std::string msg = StringUtils::insertValues( - "Successfully changed role to %s for %s", role, username); + std::string msg; + if (!fail) + msg = StringUtils::insertValues( + "Successfully changed role to %s for %s", role, username); + else + { + msg = StringUtils::insertValues( + "Failed to change role to %s for %s - missing assets:", role, username); + for (unsigned i = 0; i < missing_assets.size(); i++) + { + if (i) + msg.push_back(','); + msg += " " + missing_assets[i]; + } + } sendStringToPeer(msg, peer); updatePlayerList(); } @@ -7363,7 +7576,8 @@ void ServerLobby::storeResults() laps_number); auto ret = vectorSQLQuery(get_query, 2); record_fetched = ret.first; - if (record_fetched && ret.second[0].size() > 0){ + if (record_fetched && ret.second[0].size() > 0) + { record_exists = true; best_user = ret.second[0][0]; if (!StringUtils::parseString(ret.second[1][0], &best_result)) @@ -7434,9 +7648,8 @@ void ServerLobby::initAvailableModes() for (const std::string& s: statements) { - if (s.length() <= 1) { + if (s.length() <= 1) continue; - } bool difficulty = s[0] == 'd'; if (difficulty) { @@ -7564,9 +7777,20 @@ void ServerLobby::initTournamentPlayers() if (s.empty()) continue; else if (s[0] == '#') - category = s.substr(1); + { + if (s.length() > 1 && s[1] == '#') + { + category = s.substr(2); + m_tournament_displayed_categories.insert(category); + } + else + category = s.substr(1); + } else + { m_tournament_player_categories[category].push_back(s); + m_categories_for_player[s].insert(category); + } } // Init playing teams @@ -7660,6 +7884,7 @@ void ServerLobby::initTournamentPlayers() } else m_tournament_length = 10; + ServerConfig::m_fixed_lap_count = m_tournament_length; m_tournament_game_limits = general[2]; m_tournament_colors = general[3]; @@ -7699,6 +7924,18 @@ void ServerLobby::sendStringToPeer(std::string& s, std::shared_ptr& pee delete chat; } // sendStringToPeer //----------------------------------------------------------------------------- +void ServerLobby::sendStringToPeer(std::string& s, STKPeer* peer) const +{ + if (!peer) + return; + NetworkString* chat = getNetworkString(); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(StringUtils::utf8ToWide(s)); + peer->sendPacket(chat, true/*reliable*/); + delete chat; +} // sendStringToPeer +//----------------------------------------------------------------------------- void ServerLobby::sendStringToAllPeers(std::string& s) { NetworkString* chat = getNetworkString(); @@ -7904,8 +8141,24 @@ void ServerLobby::initAvailableTracks() m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); m_must_have_tracks = StringUtils::split( ServerConfig::m_must_have_tracks_string, ' ', false); + m_tournament_must_have_tracks = StringUtils::split( + ServerConfig::m_soccer_tournament_enforced_tracks_string, ' ', false); } // initAvailableTracks //----------------------------------------------------------------------------- +std::vector ServerLobby::getMissingTournamentAssets(std::shared_ptr& peer) const +{ + return getMissingTournamentAssets(peer.get()); +} // getMissingTournamentAssets +//----------------------------------------------------------------------------- +std::vector ServerLobby::getMissingTournamentAssets(STKPeer* peer) const +{ + std::vector ans; + for (const std::string& required_track : m_tournament_must_have_tracks) + if (peer->getClientAssets().second.count(required_track) == 0) + ans.push_back(required_track); + return ans; +} // getMissingTournamentAssets +//----------------------------------------------------------------------------- #ifdef ENABLE_WEB_SUPPORT @@ -7937,7 +8190,8 @@ std::string ServerLobby::getToken() m_token_generation_tries.store(tries + 1); std::mt19937 mt(time(nullptr) + tries); std::string token; - for (int i = 0; i < 16; ++i) { + for (int i = 0; i < 16; ++i) + { int z = mt() % 36; if (z < 26) token.push_back('a' + z); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index fe45e0008ee..83d03818fe1 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -284,6 +284,8 @@ class ServerLobby : public LobbyProtocol std::vector m_must_have_tracks; + std::vector m_tournament_must_have_tracks; + bool m_restricting_config; bool m_inverted_config_restriction; @@ -308,6 +310,10 @@ class ServerLobby : public LobbyProtocol std::map> m_tournament_player_categories; + std::set m_tournament_displayed_categories; + + std::map> m_categories_for_player; + std::set m_tournament_red_players; std::set m_tournament_blue_players; @@ -356,6 +362,8 @@ class ServerLobby : public LobbyProtocol bool m_allowed_to_start; + bool m_consent_on_replays; + #ifdef ENABLE_WEB_SUPPORT std::set m_web_tokens; @@ -481,6 +489,7 @@ class ServerLobby : public LobbyProtocol void testBannedForIP(STKPeer* peer) const; void testBannedForIPv6(STKPeer* peer) const; void testBannedForOnlineId(STKPeer* peer, uint32_t online_id) const; + void getMessagesFromHost(STKPeer* peer, int online_id) const; void writeDisconnectInfoTable(STKPeer* peer); void writePlayerReport(Event* event); bool supportsAI(); @@ -488,11 +497,14 @@ class ServerLobby : public LobbyProtocol void initTournamentPlayers(); void changeColors(); void sendStringToPeer(std::string& s, std::shared_ptr& peer) const; + void sendStringToPeer(std::string& s, STKPeer* peer) const; void sendStringToAllPeers(std::string& s); bool canRace(std::shared_ptr& peer) const; bool canRace(STKPeer* peer) const; bool hasHostRights(std::shared_ptr& peer) const; bool hasHostRights(STKPeer* peer) const; + std::vector getMissingTournamentAssets(std::shared_ptr& peer) const; + std::vector getMissingTournamentAssets(STKPeer* peer) const; void loadTracksQueueFromConfig(); std::string getGrandPrixStandings() const; void loadCustomScoring(); diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index df7766a4798..290f5b7fcca 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -346,7 +346,6 @@ void loadServerLobbyFromConfig() if (m_soccer_tournament) { m_server_mode = 6; m_server_difficulty = 3; - m_fixed_lap_count = 10; if (m_server_max_players < 9) { m_server_max_players = 9; } @@ -360,7 +359,6 @@ void loadServerLobbyFromConfig() m_addon_tracks_threshold = 0; m_addon_arenas_threshold = 0; m_addon_soccers_threshold = 0; // maybe 1 ? - m_must_have_tracks_string = "icy_soccer_field soccer_field lasdunassoccer addon_tournament-field"; m_team_choosing = true; m_ranked = false; m_server_configurable = false; @@ -393,7 +391,7 @@ void loadServerLobbyFromConfig() if (m_owner_less) { if (m_sleeping_server) { - m_min_start_game_players = m_server_max_players + 1; + m_min_start_game_players = 256; } else { if (m_min_start_game_players > m_server_max_players) m_min_start_game_players = 1; diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index b0d22dcabba..c0af230c9d3 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -551,6 +551,12 @@ namespace ServerConfig "soccer-tournament-rules", "A string specifying the match format.")); + SERVER_CFG_PREFIX StringServerConfigParam m_soccer_tournament_enforced_tracks_string + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "soccer-tournament-enforced-tracks", + "List of tracks tournament players should have to enter " + "(doesn't apply to spectators).")); + SERVER_CFG_PREFIX StringServerConfigParam m_incompatible_advice SERVER_CFG_DEFAULT(StringServerConfigParam("", "incompatible-advice", @@ -559,8 +565,12 @@ namespace ServerConfig SERVER_CFG_PREFIX BoolServerConfigParam m_only_host_riding SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "only-host-riding", - "A temporary feature to make others only spectate. Not ideal. " - "Maybe not even working.")); + "A feature to make others only spectate.")); + + SERVER_CFG_PREFIX BoolServerConfigParam m_record_replays + SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "record-replays", + "If true, normal race and time trial games are recorded into ghost " + "replays.")); SERVER_CFG_PREFIX BoolServerConfigParam m_random_selects_addons SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "random-selects-addons", @@ -599,7 +609,7 @@ namespace ServerConfig SERVER_CFG_DEFAULT(StringServerConfigParam("", "tokens-table", "A table containing tokens for website authentication using " - "STK account only.")); + "STK account only.")); #endif SERVER_CFG_PREFIX StringServerConfigParam m_power_password diff --git a/src/replay/replay_recorder.cpp b/src/replay/replay_recorder.cpp index c32a8e97414..667860565cb 100644 --- a/src/replay/replay_recorder.cpp +++ b/src/replay/replay_recorder.cpp @@ -306,7 +306,7 @@ void ReplayRecorder::update(int ticks) r->m_jumping = kart->isJumping(); } // for i - if (world->getPhase() == World::RESULT_DISPLAY_PHASE && !m_complete_replay) + if ((world->getPhase() == World::RESULT_DISPLAY_PHASE || world->getPhase() == World::DELAY_FINISH_PHASE) && !m_complete_replay) { m_complete_replay = true; save(); @@ -410,12 +410,12 @@ void ReplayRecorder::save() fprintf(fd, "kart: %s %s\n", kart->getIdent().c_str(), StringUtils::xmlEncode(kart->getController()->getName()).c_str()); - if (kart->getController()->isPlayerController()) +/* if (kart->getController()->isPlayerController()) { fprintf(fd, "kart_color: %f\n", StateManager::get()->getActivePlayer(player_count)->getConstProfile()->getDefaultKartColor()); player_count++; } - else + else*/ fprintf(fd, "kart_color: 0\n"); } From 16f7c6a4f1b7144da3f6072c6e7f4dd3637cef6d Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 24 May 2021 12:30:55 +0300 Subject: [PATCH 092/830] Apply changes --- src/modes/world_with_rank.hpp | 7 +- src/network/network_player_profile.cpp | 2 + src/network/network_player_profile.hpp | 17 +- src/network/protocols/server_lobby.cpp | 661 ++++++++++++++++++++----- src/network/protocols/server_lobby.hpp | 17 +- src/network/server_config.cpp | 4 +- src/network/server_config.hpp | 14 +- src/race/race_manager.cpp | 33 +- src/race/race_manager.hpp | 5 + 9 files changed, 620 insertions(+), 140 deletions(-) diff --git a/src/modes/world_with_rank.hpp b/src/modes/world_with_rank.hpp index 55d2aa805e4..fabf408f612 100644 --- a/src/modes/world_with_rank.hpp +++ b/src/modes/world_with_rank.hpp @@ -54,6 +54,8 @@ class WorldWithRank : public World std::string m_custom_scoring_type; + bool m_shuffled; + #ifdef DEBUG /** Used for debugging to help detect if the same kart position * is used more than once. */ @@ -118,7 +120,10 @@ class WorldWithRank : public World // ------------------------------------------------------------------------ int getPolePoints() const; // ------------------------------------------------------------------------ - + bool isShuffled() const { return m_shuffled; } + // ------------------------------------------------------------------------ + void setShuffled(bool value) { m_shuffled = value; } + // ------------------------------------------------------------------------ }; // WorldWithRank #endif diff --git a/src/network/network_player_profile.cpp b/src/network/network_player_profile.cpp index b00045d075e..b50bcec7a91 100644 --- a/src/network/network_player_profile.cpp +++ b/src/network/network_player_profile.cpp @@ -20,6 +20,8 @@ #include "network/network_config.hpp" #include "network/stk_host.hpp" +float NetworkPlayerProfile::m_team_color[20] = {1.00, 0.08, 0.15, 0.30, 0.60, 0.80, 0.50, 0.70, 0.90, 0.00}; + // ---------------------------------------------------------------------------- /** Returns true if this player is local, i.e. running on this computer. This * is done by comparing the host id of this player with the host id of this diff --git a/src/network/network_player_profile.hpp b/src/network/network_player_profile.hpp index d0141f36c3d..99d0f320810 100644 --- a/src/network/network_player_profile.hpp +++ b/src/network/network_player_profile.hpp @@ -72,6 +72,10 @@ class NetworkPlayerProfile /** 2-letter country code of player. */ std::string m_country_code; + int m_temporary_team; + + static float m_team_color[20]; + public: // ------------------------------------------------------------------------ static std::shared_ptr @@ -91,6 +95,7 @@ class NetworkPlayerProfile m_handicap.store((HandicapLevel)0); m_local_player_id = 0; m_team.store(team); + m_temporary_team = -1; resetGrandPrixData(); } // ------------------------------------------------------------------------ @@ -110,6 +115,7 @@ class NetworkPlayerProfile m_local_player_id = local_player_id; m_team.store(team); m_country_code = country_code; + m_temporary_team = -1; resetGrandPrixData(); } // ------------------------------------------------------------------------ @@ -137,7 +143,12 @@ class NetworkPlayerProfile /** Returns the name of this player. */ const irr::core::stringw& getName() const { return m_player_name; } // ------------------------------------------------------------------------ - float getDefaultKartColor() const { return m_default_kart_color; } + float getDefaultKartColor() const + { + if (m_temporary_team == -1) + return m_default_kart_color; + return m_team_color[m_temporary_team]; + } // ------------------------------------------------------------------------ uint32_t getOnlineId() const { return m_online_id; } // ------------------------------------------------------------------------ @@ -163,6 +174,10 @@ class NetworkPlayerProfile // ------------------------------------------------------------------------ KartTeam getTeam() const { return m_team.load(); } // ------------------------------------------------------------------------ + void setTemporaryTeam(int team) { m_temporary_team = team; } + // ------------------------------------------------------------------------ + int getTemporaryTeam() const { return m_temporary_team; } + // ------------------------------------------------------------------------ const std::string& getCountryCode() const { return m_country_code; } }; // class NetworkPlayerProfile diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index dd9c62931be..2b326908e24 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -185,6 +185,27 @@ ServerLobby::ServerLobby() : LobbyProtocol() "spectate standings start stop teamchat tell to token unban " "uninstalladdon version"; + m_team_name_to_index = { + {"red", 1}, {"r", 1}, {StringUtils::utf32ToUtf8({0x1f7e5}), -1}, + {"orange", 2}, {"o", 2}, {StringUtils::utf32ToUtf8({0x1f7e7}), -2}, + {"yellow", 3}, {"y", 3}, {StringUtils::utf32ToUtf8({0x1f7e8}), -3}, + {"green", 4}, {"g", 4}, {StringUtils::utf32ToUtf8({0x1f7e9}), -4}, + {"blue", 5}, {"b", 5}, {StringUtils::utf32ToUtf8({0x1f7e6}), -5}, + {"purple", 6}, {"p", 6}, {StringUtils::utf32ToUtf8({0x1f7ea}), -6}, + {"violet", 6}, {"v", 6} + }; + + m_team_name = {"No Team", + StringUtils::utf32ToUtf8({0x1f7e5}) + "Red", + StringUtils::utf32ToUtf8({0x1f7e7}) + "Orange", + StringUtils::utf32ToUtf8({0x1f7e8}) + "Yellow", + StringUtils::utf32ToUtf8({0x1f7e9}) + "Green", + StringUtils::utf32ToUtf8({0x1f7e6}) + "Blue", + StringUtils::utf32ToUtf8({0x1f7ea}) + "Purple" + }; + + m_shuffle_gp = ServerConfig::m_shuffle_gp; + m_consent_on_replays = false; m_fixed_lap = ServerConfig::m_fixed_lap_count; @@ -246,6 +267,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_player_reports_table_exists = false; initDatabase(); + initCategories(); if (ServerConfig::m_soccer_tournament) { initTournamentPlayers(); @@ -633,9 +655,9 @@ void ServerLobby::updateAddons() continue; if (t->isArena()) m_addon_arenas.insert(t->getIdent()); - else if (t->isSoccer()) + if (t->isSoccer()) m_addon_soccers.insert(t->getIdent()); - else + if (!t->isArena() && !t->isSoccer()) m_addon_kts.second.insert(t->getIdent()); } @@ -3114,7 +3136,10 @@ void ServerLobby::startSelection(const Event *event) // Will be changed after the first vote received m_timeout.store(std::numeric_limits::max()); if (!m_game_setup->isGrandPrixStarted()) + { m_gp_scores.clear(); + m_gp_team_scores.clear(); + } } // startSelection //----------------------------------------------------------------------------- @@ -3281,6 +3306,7 @@ void ServerLobby::checkRaceFinished() // Save race result before delete the world m_result_ns->clear(); m_result_ns->addUInt8(LE_RACE_FINISHED); + std::vector gp_changes; if (m_game_setup->isGrandPrix()) { // fastest lap @@ -3317,25 +3343,35 @@ void ServerLobby::checkRaceFinished() m_result_ns->addUInt8((uint8_t)RaceManager::get()->getNumPlayers()); for (unsigned i = 0; i < RaceManager::get()->getNumPlayers(); i++) { - int last_score = RaceManager::get()->getKartScore(i); + int last_score = (World::getWorld()->getKart(i)->isEliminated() ? + 0 : RaceManager::get()->getKartScore(i)); + gp_changes.push_back((float)last_score); int cur_score = last_score; float overall_time = RaceManager::get()->getOverallTime(i); + std::string username = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(i).getPlayerName()); + if (username == fastest_kart) + { + gp_changes.back() += points_fl; + cur_score += points_fl; + } + int team = m_team_for_player[username]; + if (team > 0) + { + m_gp_team_scores[team].score += cur_score; + m_gp_team_scores[team].time += overall_time; + } + last_score = m_gp_scores[username].score; + cur_score += last_score; + overall_time = overall_time + m_gp_scores[username].time; if (auto player = RaceManager::get()->getKartInfo(i).getNetworkPlayerProfile().lock()) { - std::string username = StringUtils::wideToUtf8(player->getName()); - last_score = m_gp_scores[username].score; - cur_score += last_score; - if (username == fastest_kart) - cur_score += points_fl; - - overall_time = overall_time + m_gp_scores[username].time; player->setScore(cur_score); player->setOverallTime(overall_time); - - m_gp_scores[username].score = cur_score; - m_gp_scores[username].time = overall_time; } + m_gp_scores[username].score = cur_score; + m_gp_scores[username].time = overall_time; m_result_ns->addUInt32(last_score).addUInt32(cur_score) .addFloat(overall_time); } @@ -3352,6 +3388,8 @@ void ServerLobby::checkRaceFinished() uint8_t ranking_changes_indication = 0; if (ServerConfig::m_ranked && RaceManager::get()->modeHasLaps()) ranking_changes_indication = 1; + if (m_game_setup->isGrandPrix()) + ranking_changes_indication = 1; m_result_ns->addUInt8(ranking_changes_indication); if (m_kart_elimination.isEnabled()) @@ -3377,6 +3415,15 @@ void ServerLobby::checkRaceFinished() computeNewRankings(); submitRankingsToAddons(); } + else if (m_game_setup->isGrandPrix()) + { + unsigned player_count = RaceManager::get()->getNumPlayers(); + m_result_ns->addUInt8((uint8_t)player_count); + for (unsigned i = 0; i < player_count; i++) + { + m_result_ns->addFloat(gp_changes[i]); + } + } m_state.store(WAIT_FOR_RACE_STOPPED); if (!m_tracks_queue.empty()) @@ -3389,6 +3436,7 @@ void ServerLobby::checkRaceFinished() } // checkRaceFinished //----------------------------------------------------------------------------- + /** Compute the new player's rankings used in ranked servers */ void ServerLobby::computeNewRankings() @@ -4382,6 +4430,21 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, player->setTeam(KART_TEAM_BLUE); } } + std::string username = StringUtils::wideToUtf8(player->getName()); + if (m_game_setup->isGrandPrix()) + { + auto it = m_gp_scores.find(username); + if (it != m_gp_scores.end()) + { + player->setScore(it->second.score); + player->setOverallTime(it->second.time); + } + } + auto it2 = m_team_for_player.find(username); + if (it2 != m_team_for_player.end()) + { + player->setTemporaryTeam(it2->second - 1); + } peer->addPlayer(player); } @@ -4691,7 +4754,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) std::string prefix = ""; for (const std::string& category: m_categories_for_player[utf8_profile_name]) { - if (m_tournament_displayed_categories.count(category)) + if (!m_hidden_categories.count(category)) prefix += category + ", "; } if (!prefix.empty()) @@ -6121,6 +6184,7 @@ void ServerLobby::addLiveJoinPlaceholder( void ServerLobby::setPlayerKarts(const NetworkString& ns, STKPeer* peer) const { unsigned player_count = ns.getUInt8(); + player_count = std::min(player_count, (unsigned)peer->getPlayerProfiles().size()); for (unsigned i = 0; i < player_count; i++) { std::string kart; @@ -6518,6 +6582,75 @@ void ServerLobby::handleServerCommand(Event* event, peer->setAlwaysSpectate(ASM_NONE); updatePlayerList(); } + else if (argv[0] == "addons") + { + if (argv.size() == 1) + { + argv.push_back(""); + switch (m_game_mode.load()) + { + case 0: + case 1: + case 3: + case 4: + argv[1] = "track"; + break; + case 6: + argv[1] = "soccer"; + break; + case 7: + case 8: + argv[1] = "arena"; + break; + } + } + const std::set& from = + (argv[1] == "kart" ? m_addon_kts.first : + (argv[1] == "track" ? m_addon_kts.second : + (argv[1] == "arena" ? m_addon_arenas : + /*argv[1] == "soccer" ?*/ m_addon_soccers + ))); + std::vector result[2]; + for (const std::string& s: from) + result[0].push_back(s); + + auto peers = STKHost::get()->getPeers(); + bool anyone = false; + for (auto peer : peers) + { + if (!peer || !peer->isValidated() || peer->isWaitingForGame() || !canRace(peer)) + continue; + anyone = true; + const auto& kt = peer->getClientAssets(); + const auto& container = (argv[1] == "kart" ? kt.first : kt.second); + result[1].clear(); + for (const std::string& s: result[0]) + if (container.find(s) != container.end()) + result[1].push_back(s); + std::swap(result[0], result[1]); + } + const std::vector answer = result[0]; + std::string response; + if (anyone) { + response = "Found " + std::to_string(answer.size()) + " asset(s)"; + bool nothing = true; + for (const std::string& s: answer) + { + if (s.length() < 6 || s.substr(0, 6) != "addon_") + continue; + response.push_back(nothing ? ':' : ','); + nothing = false; + response.push_back(' '); + response += s.substr(6); + } + if (response.length() > 100) + response += "\nTotal: " + std::to_string(answer.size()); + } else { + response = "No one in the lobby can play. Found " + + std::to_string(answer.size()) + " assets on the server."; + } + sendStringToPeer(response, peer); + } else if (argv[0] == "listserveraddon") { NetworkString* chat = getNetworkString(); @@ -7174,6 +7307,25 @@ void ServerLobby::handleServerCommand(Event* event, sendStringToPeer(msg, peer); return; } + if (argv[1] == "shuffle") + { + if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) + { + msg = "Usage: /admin shuffle [0/1] - make the GP grid shuffled all the time, or make it result-based"; + sendStringToPeer(msg, peer); + return; + } + if (argv[2] == "0") + { + m_shuffle_gp = false; + msg = "Now the GP grid is sorted by score"; + } else { + m_shuffle_gp = true; + msg = "Now the GP grid is shuffled"; + } + sendStringToPeer(msg, peer); + return; + } if (argv[1] == "timeout") { int seconds; @@ -7188,6 +7340,174 @@ void ServerLobby::handleServerCommand(Event* event, updatePlayerList(); return; } + if (argv[1] == "team") + { + if (argv.size() != 4) { + msg = "Usage: /admin team (color/0..6) (player) - move a player " + "to a team, or remove from teams (none/0)"; + sendStringToPeer(msg, peer); + return; + } + auto it = m_team_name_to_index.find(argv[2]); + int index = (it == m_team_name_to_index.end() ? 0 : it->second); + std::string player = argv[3]; + for (const auto& pair: m_team_name_to_index) + { + if (pair.second < 0) + { + if (pair.second == -index) + { + m_player_categories[pair.first].insert(player); + m_categories_for_player[player].insert(pair.first); + } + else + { + m_player_categories[pair.first].erase(player); + m_categories_for_player[player].erase(pair.first); + } + } + } + index = abs(index); + m_team_for_player[player] = index; + auto wide_player_name = StringUtils::utf8ToWide(player); + std::shared_ptr player_peer = STKHost::get()->findPeerByName( + wide_player_name); + if (player_peer) + { + for (auto& profile : player_peer.get()->getPlayerProfiles()) + { + if (profile->getName() == wide_player_name) + { + profile->setTemporaryTeam(index - 1); + break; + } + } + } + updatePlayerList(); + return; + } + if (argv[1] == "cat+") + { + if (argv.size() != 4) { + msg = "Usage: /admin cat+ (category) (player) - add a player to a category"; + sendStringToPeer(msg, peer); + return; + } + std::string category = argv[2]; + std::string player = argv[3]; + m_player_categories[category].insert(player); + m_categories_for_player[player].insert(category); + updatePlayerList(); + return; + } + if (argv[1] == "cat-") + { + if (argv.size() != 4) { + msg = "Usage: /admin cat- (category) (player) - remove a player from a category"; + sendStringToPeer(msg, peer); + return; + } + std::string category = argv[2]; + std::string player = argv[3]; + m_player_categories[category].erase(player); + m_categories_for_player[player].erase(category); + updatePlayerList(); + return; + } + if (argv[1] == "cat*") + { + int displayed; + if (argv.size() != 4 || !StringUtils::parseString(argv[3], &displayed) + || displayed < 0 || displayed > 1) { + msg = "Usage: /admin cat* (category) (0|1) - make category displayed or not"; + sendStringToPeer(msg, peer); + return; + } + std::string category = argv[2]; + if (displayed) { + m_hidden_categories.erase(category); + } else { + m_hidden_categories.insert(category); + } + updatePlayerList(); + return; + } + if (argv[1] == "queue") + { + std::string format_string = "Format: /admin queue (show | push[_front] (track) | pop[_back])"; + if (argv.size() < 3) + { + sendStringToPeer(format_string, peer); + return; + } + if (argv[2] == "show") + { + std::string msg = "Queue:"; + for (const std::string& s: m_tracks_queue) { + msg += " " + s; + } + sendStringToPeer(msg, peer); + } + else if (argv[2] == "push" || argv[2] == "push_back") + { + if (argv.size() < 4) + { + sendStringToPeer(format_string, peer); + return; + } + m_tracks_queue.push_back(argv[3]); + std::string msg = "Pushed " + argv[3] + + " to the back of queue, current queue size: " + + std::to_string(m_tracks_queue.size()); + sendStringToPeer(msg, peer); + } + else if (argv[2] == "push_front") + { + if (argv.size() < 4) + { + sendStringToPeer(format_string, peer); + return; + } + m_tracks_queue.push_front(argv[3]); + std::string msg = "Pushed " + argv[3] + + " to the front of queue, current queue size: " + + std::to_string(m_tracks_queue.size()); + sendStringToPeer(msg, peer); + } + else if (argv[2] == "pop" || argv[2] == "pop_back") + { + std::string msg = ""; + if (m_tracks_queue.empty()) { + msg = "Queue was empty before."; + } + else + { + std::string msg = "Popped " + m_tracks_queue.front() + + "from the queue,"; + m_tracks_queue.pop_front(); + msg += " current queue size: " + + std::to_string(m_tracks_queue.size()); + } + sendStringToPeer(msg, peer); + } + else if (argv[2] == "pop_back") + { + std::string msg = ""; + if (m_tracks_queue.empty()) { + msg = "Queue was empty before."; + } + else + { + std::string msg = "Popped " + m_tracks_queue.back() + + "from the queue,"; + m_tracks_queue.pop_back(); + msg += " current queue size: " + + std::to_string(m_tracks_queue.size()); + } + sendStringToPeer(msg, peer); + } + return; + } } else if (argv[0] == "version") { @@ -7329,129 +7649,152 @@ void ServerLobby::handleServerCommand(Event* event, } if (role[0] >= 'A' && role[0] <= 'Z') role[0] += 'a' - 'A'; - Log::info("ServerLobby", "SoccerMatchLog: Role of %s changed to %s", - username.c_str(), role.c_str()); - m_tournament_red_players.erase(username); - m_tournament_blue_players.erase(username); - m_tournament_referees.erase(username); - if (permanent) - { - m_tournament_init_red.erase(username); - m_tournament_init_blue.erase(username); - m_tournament_init_ref.erase(username); - } - std::string role_changed = "The referee has updated your role - you are now %s"; - std::shared_ptr player_peer = STKHost::get()->findPeerByName( - StringUtils::utf8ToWide(username)); - std::vector missing_assets; - if (player_peer) - missing_assets = getMissingTournamentAssets(player_peer); - bool fail = false; - switch (role[0]) + std::vector changed_usernames; + if (!username.empty()) { - case 'R': - case 'r': + if (username[0] == '#') { - if (!missing_assets.empty()) - { - fail = true; - break; - } - if (tournamentColorsSwapped(m_tournament_game)) - { - m_tournament_blue_players.insert(username); - if (permanent) - m_tournament_init_blue.insert(username); - } - else + std::string category = username.substr(1); + auto it = m_player_categories.find(category); + if (it != m_player_categories.end()) { - m_tournament_red_players.insert(username); - if (permanent) - m_tournament_init_red.insert(username); - } - if (player_peer) - { - role_changed = StringUtils::insertValues(role_changed, "red player"); - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_RED); - sendStringToPeer(role_changed, player_peer); + for (const std::string& s: it->second) + { + changed_usernames.push_back(s); + } } - break; } - case 'B': - case 'b': + else { - if (!missing_assets.empty()) + changed_usernames.push_back(username); + } + } + for (const std::string& username: changed_usernames) + { + Log::info("ServerLobby", "SoccerMatchLog: Role of %s changed to %s", + username.c_str(), role.c_str()); + m_tournament_red_players.erase(username); + m_tournament_blue_players.erase(username); + m_tournament_referees.erase(username); + if (permanent) + { + m_tournament_init_red.erase(username); + m_tournament_init_blue.erase(username); + m_tournament_init_ref.erase(username); + } + std::string role_changed = "The referee has updated your role - you are now %s"; + std::shared_ptr player_peer = STKHost::get()->findPeerByName( + StringUtils::utf8ToWide(username)); + std::vector missing_assets; + if (player_peer) + missing_assets = getMissingTournamentAssets(player_peer); + bool fail = false; + switch (role[0]) + { + case 'R': + case 'r': { - fail = true; + if (!missing_assets.empty()) + { + fail = true; + break; + } + if (tournamentColorsSwapped(m_tournament_game)) + { + m_tournament_blue_players.insert(username); + if (permanent) + m_tournament_init_blue.insert(username); + } + else + { + m_tournament_red_players.insert(username); + if (permanent) + m_tournament_init_red.insert(username); + } + if (player_peer) + { + role_changed = StringUtils::insertValues(role_changed, "red player"); + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_RED); + sendStringToPeer(role_changed, player_peer); + } break; } - if (tournamentColorsSwapped(m_tournament_game)) + case 'B': + case 'b': { - m_tournament_red_players.insert(username); - if (permanent) - m_tournament_init_red.insert(username); + if (!missing_assets.empty()) + { + fail = true; + break; + } + if (tournamentColorsSwapped(m_tournament_game)) + { + m_tournament_red_players.insert(username); + if (permanent) + m_tournament_init_red.insert(username); + } + else + { + m_tournament_blue_players.insert(username); + if (permanent) + m_tournament_init_blue.insert(username); + } + if (player_peer) + { + role_changed = StringUtils::insertValues(role_changed, "blue player"); + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_BLUE); + sendStringToPeer(role_changed, player_peer); + } + break; } - else + case 'J': + case 'j': { - m_tournament_blue_players.insert(username); + if (!missing_assets.empty()) + { + fail = true; + break; + } + m_tournament_referees.insert(username); if (permanent) - m_tournament_init_blue.insert(username); - } - if (player_peer) - { - role_changed = StringUtils::insertValues(role_changed, "blue player"); - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_BLUE); - sendStringToPeer(role_changed, player_peer); - } - break; - } - case 'J': - case 'j': - { - if (!missing_assets.empty()) - { - fail = true; + m_tournament_init_ref.insert(username); + if (player_peer) + { + role_changed = StringUtils::insertValues(role_changed, "referee"); + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); + sendStringToPeer(role_changed, player_peer); + } break; } - m_tournament_referees.insert(username); - if (permanent) - m_tournament_init_ref.insert(username); - if (player_peer) + case 'S': + case 's': { - role_changed = StringUtils::insertValues(role_changed, "referee"); - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); - sendStringToPeer(role_changed, player_peer); + if (player_peer) + { + role_changed = StringUtils::insertValues(role_changed, "spectator"); + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); + sendStringToPeer(role_changed, player_peer); + } + break; } - break; } - case 'S': - case 's': + std::string msg; + if (!fail) + msg = StringUtils::insertValues( + "Successfully changed role to %s for %s", role, username); + else { - if (player_peer) + msg = StringUtils::insertValues( + "Failed to change role to %s for %s - missing assets:", role, username); + for (unsigned i = 0; i < missing_assets.size(); i++) { - role_changed = StringUtils::insertValues(role_changed, "spectator"); - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); - sendStringToPeer(role_changed, player_peer); + if (i) + msg.push_back(','); + msg += " " + missing_assets[i]; } - break; - } - } - std::string msg; - if (!fail) - msg = StringUtils::insertValues( - "Successfully changed role to %s for %s", role, username); - else - { - msg = StringUtils::insertValues( - "Failed to change role to %s for %s - missing assets:", role, username); - for (unsigned i = 0; i < missing_assets.size(); i++) - { - if (i) - msg.push_back(','); - msg += " " + missing_assets[i]; } + sendStringToPeer(msg, peer); } - sendStringToPeer(msg, peer); updatePlayerList(); } else if (argv[0] == "stop") @@ -7594,6 +7937,10 @@ void ServerLobby::storeResults() continue; std::string username = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(i).getPlayerName()); + auto profile = RaceManager::get()->getKartInfo(i).getNetworkPlayerProfile().lock(); + // TODO fix this properly. + if (profile && profile->getOnlineId() == 0) + username = "* " + username; double elapsed_time = RaceManager::get()->getKartRaceTime(i); std::stringstream elapsed_string; elapsed_string << std::setprecision(4) << std::fixed << elapsed_time; @@ -7766,35 +8113,80 @@ void ServerLobby::writeOwnReport(STKPeer* reporter, STKPeer* reporting, const st #endif } // writeOwnReport //----------------------------------------------------------------------------- -void ServerLobby::initTournamentPlayers() +void ServerLobby::initCategories() { - // Init categories std::vector tokens = StringUtils::split( - ServerConfig::m_soccer_tournament_players, ' '); + ServerConfig::m_categories, ' '); std::string category = ""; + bool isTeam = false; for (std::string& s: tokens) { if (s.empty()) continue; else if (s[0] == '#') { + isTeam = false; if (s.length() > 1 && s[1] == '#') { category = s.substr(2); - m_tournament_displayed_categories.insert(category); + m_hidden_categories.insert(category); } else category = s.substr(1); } + else if (s[0] == '$') + { + isTeam = true; + category = s.substr(1); + } else { - m_tournament_player_categories[category].push_back(s); - m_categories_for_player[s].insert(category); + if (!isTeam) { + m_player_categories[category].insert(s); + m_categories_for_player[s].insert(category); + } + else + { + m_team_for_player[s] = category[0] - '0' + 1; + } } } - + /* + Temporary team indexing: + network_player_profile.hpp: -1 for none, [0..5] for teams + server config: (-1 for none,) [0..5] for teams + server lobby command: 0 for none, [1..6] for teams + m_team_for_player: 0 for none, [1..6] for teams + Sorry for the confusion. + */ + // change categories according to the teams + for (const auto& who: m_team_for_player) + { + int idx = who.second; + std::string player = who.first; + for (const auto& pair: m_team_name_to_index) + { + if (pair.second < 0) + { + if (pair.second == -idx) + { + m_player_categories[pair.first].insert(player); + m_categories_for_player[player].insert(pair.first); + } + else + { + m_player_categories[pair.first].erase(player); + m_categories_for_player[player].erase(pair.first); + } + } + } + } +} // initCategories +//----------------------------------------------------------------------------- +void ServerLobby::initTournamentPlayers() +{ // Init playing teams - tokens = StringUtils::split( + std::vector tokens = StringUtils::split( ServerConfig::m_soccer_tournament_match, ' '); std::string type = ""; for (std::string& s: tokens) @@ -7810,8 +8202,8 @@ void ServerLobby::initTournamentPlayers() type == "R" ? m_tournament_red_players : type == "B" ? m_tournament_blue_players : m_tournament_referees); - for (std::string& member: - m_tournament_player_categories[cat_name]) + for (const std::string& member: + m_player_categories[cat_name]) dest.insert(member); } else if (type == "R") @@ -8012,6 +8404,24 @@ std::string ServerLobby::getGrandPrixStandings() const response << " " << "(" << StringUtils::timeToString(results[i].first.time) << ")"; response << "\n"; } + results.clear(); + + if (!m_gp_team_scores.empty()) + { + std::vector> results2; + response << "\n"; + for (auto& p: m_gp_team_scores) + results2.emplace_back(p.second, p.first); + std::stable_sort(results2.rbegin(), results2.rend()); + for (unsigned i = 0; i < results2.size(); i++) + { + response << (i + 1) << ". "; + response << " " << m_team_name[results2[i].second]; + response << " " << results2[i].first.score; + response << " " << "(" << StringUtils::timeToString(results2[i].first.time) << ")"; + response << "\n"; + } + } return response.str(); } // getGrandPrixStandings //----------------------------------------------------------------------------- @@ -8043,7 +8453,10 @@ void ServerLobby::updateWorldSettings() { WorldWithRank *wwr = dynamic_cast(World::getWorld()); if (wwr) + { wwr->setCustomScoringSystem(m_scoring_type, m_scoring_int_params); + wwr->setShuffled(m_shuffle_gp); + } SoccerWorld *sw = dynamic_cast(World::getWorld()); if (sw) { diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 83d03818fe1..61e7090e498 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -308,12 +308,16 @@ class ServerLobby : public LobbyProtocol std::set m_available_modes; - std::map> m_tournament_player_categories; + std::map> m_player_categories; - std::set m_tournament_displayed_categories; + std::set m_hidden_categories; + + std::set m_special_categories; std::map> m_categories_for_player; + std::map m_team_for_player; + std::set m_tournament_red_players; std::set m_tournament_blue_players; @@ -348,6 +352,10 @@ class ServerLobby : public LobbyProtocol std::map m_gp_scores; + std::map m_gp_team_scores; + + std::vector m_team_name; + int m_tournament_game; int m_fixed_lap; @@ -363,6 +371,10 @@ class ServerLobby : public LobbyProtocol bool m_allowed_to_start; bool m_consent_on_replays; + + std::map m_team_name_to_index; + + bool m_shuffle_gp; #ifdef ENABLE_WEB_SUPPORT std::set m_web_tokens; @@ -494,6 +506,7 @@ class ServerLobby : public LobbyProtocol void writePlayerReport(Event* event); bool supportsAI(); void updateAddons(); + void initCategories(); void initTournamentPlayers(); void changeColors(); void sendStringToPeer(std::string& s, std::shared_ptr& peer) const; diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 290f5b7fcca..12a3b09cc64 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -349,7 +349,7 @@ void loadServerLobbyFromConfig() if (m_server_max_players < 9) { m_server_max_players = 9; } - m_voting_timeout = 15; + // m_voting_timeout = 15; m_soccer_goal_target = false; m_official_tracks_needed = false; // m_owner_less = false; @@ -365,7 +365,7 @@ void loadServerLobbyFromConfig() m_live_players = true; m_sleeping_server = false; m_free_teams = true; - m_validating_player = true; + // m_validating_player = true; m_random_selects_addons = true; if (m_owner_less) { diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index c0af230c9d3..c8e6ec139b4 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -537,11 +537,12 @@ namespace ServerConfig "be empty or absent and can go in any order. You can use " "a category (#A) instead of listing all players.")); - SERVER_CFG_PREFIX StringServerConfigParam m_soccer_tournament_players + SERVER_CFG_PREFIX StringServerConfigParam m_categories SERVER_CFG_DEFAULT(StringServerConfigParam("", - "soccer-tournament-players", - "List of tournament players with categories (teams). Use the " - "format #Category player1 ... playerN #Category ...")); + "categories", + "List of players with categories (teams, etc.). Use the " + "format #Category1 player1 ... playerN #Category2 ... " + "Use ## to hide the category from the player list.")); SERVER_CFG_PREFIX StringServerConfigParam m_soccer_tournament_rules SERVER_CFG_DEFAULT(StringServerConfigParam("nochat 10 TTTTG RRBBR;" @@ -634,6 +635,11 @@ namespace ServerConfig "the corresponding table. Otherwise, /register command does " "nothing")); + SERVER_CFG_PREFIX BoolServerConfigParam m_shuffle_gp + SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "shuffle-grand-prix-grid", + "If true, the GP grid is shuffled before each race, not only before " + "the first one.")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index 5ca54da78ba..086d3552dff 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -20,6 +20,7 @@ #include #include +#include #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" @@ -544,13 +545,33 @@ void RaceManager::startNextRace() player_last_offset = (int)m_player_karts.size(); } - std::sort(m_kart_status.begin()+offset, - m_kart_status.end() - player_last_offset); - // reverse kart order if flagged in user's config - if (UserConfigParams::m_gp_most_points_first) + WorldWithRank *wwr = dynamic_cast(World::getWorld()); + bool shuffle_instead = false; + if (wwr) + bool shuffle_instead = wwr->isShuffled(); + else { - std::reverse(m_kart_status.begin()+offset, - m_kart_status.end() - player_last_offset); + Log::error("RaceManager", + "World with scores that is not a WorldWithRank??"); + } + + if (shuffle_instead) + { + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(m_kart_status.begin()+offset, + m_kart_status.end() - player_last_offset, g); + } + else + { + std::sort(m_kart_status.begin()+offset, + m_kart_status.end() - player_last_offset); + // reverse kart order if flagged in user's config + if (UserConfigParams::m_gp_most_points_first) + { + std::reverse(m_kart_status.begin()+offset, + m_kart_status.end() - player_last_offset); + } } } // not first race diff --git a/src/race/race_manager.hpp b/src/race/race_manager.hpp index 2abae41a4b2..b885d3e908c 100644 --- a/src/race/race_manager.hpp +++ b/src/race/race_manager.hpp @@ -620,6 +620,11 @@ class RaceManager return m_kart_status[kart].m_ident; } // getKartIdent // ---------------------------------------------------------------------------------------- + const std::string& getPlayerName(int kart) const + { + return m_kart_status[kart].m_player_name; + } // getKartName + // ---------------------------------------------------------------------------------------- int getKartScore(int krt) const { return m_kart_status[krt].m_score; } // ---------------------------------------------------------------------------------------- int getKartPrevScore(int krt) const From 1930ee5fdaae543be88c6998ec37924315278571 Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 24 May 2021 13:22:57 +0300 Subject: [PATCH 093/830] Update version --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 94a41628a26..f7d360c5273 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7634,7 +7634,7 @@ void ServerLobby::handleServerCommand(Event* event, } else if (argv[0] == "version") { - std::string msg = "1.2-kimden 201220 beta"; + std::string msg = "1.2-kimden 210524 beta"; sendStringToPeer(msg, peer); } else if (argv[0] == "register") From b49ce26316290876a8cb7a3d82a0aedd2f1c00e9 Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 21 Jun 2021 15:11:07 +0300 Subject: [PATCH 094/830] Add /moreaddons, /clear, fix tournament assets requirements, allow to send from console to all, increase replay size --- data/stk_config.xml | 2 +- src/network/network_console.cpp | 17 +++ src/network/protocols/server_lobby.cpp | 183 ++++++++++++++++++------- src/network/protocols/server_lobby.hpp | 7 +- 4 files changed, 155 insertions(+), 54 deletions(-) diff --git a/data/stk_config.xml b/data/stk_config.xml index 6c2b1740968..a8fbd47eacf 100644 --- a/data/stk_config.xml +++ b/data/stk_config.xml @@ -185,7 +185,7 @@ new transform event is generated before maximum time. delta-steering If the steering angle difference exceeds this delta, new transform event is generated before maximum time. --> - + + + + + + + + + + + + + +### Things to note +* The system can be fooled of course, but it should be a lot harder to troll. Testing would be necessary. However, when I set up a test server, most players coming by just wanted to play normally... +* The system should not warn or kick weak players who get lost or stuck on obstacles (too quickly). The current configuration values are most probably not yet perfect. +* Players should probably be informed about the system, because waiting for others (like some pros do when giving weaker players some advice or driving lessons) would be punished, so the system should not be activated in those cases. +* If a player presses UP-key early, the timer is increased during time punishment at the beginning of the race (1 sec). I don't know how to find out if a player is in that state. +* **There may still be bugs** (of course)... ;) diff --git a/src/main_loop.cpp b/src/main_loop.cpp index f4d52291373..d52345ce529 100644 --- a/src/main_loop.cpp +++ b/src/main_loop.cpp @@ -600,6 +600,22 @@ void MainLoop::run() PROFILER_POP_CPU_MARKER(); } } + else + { + if (World::getWorld()) + { + // test if player is driving backward + float frame_duration = num_steps * dt; + LinearWorld *lin_world = dynamic_cast(World::getWorld()); + if (lin_world && lin_world->getTicksSinceStart() > 0) + { + for (unsigned int i = 0; i < lin_world->getNumKarts(); i++) + { + lin_world->serverCheckForWrongDirection(i,frame_duration); + } + } + } + } // Some protocols in network will use RequestManager if (!m_download_assets) { diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index 60492cf3fa5..c0d29b07216 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -1095,6 +1095,75 @@ void LinearWorld::checkForWrongDirection(unsigned int i, float dt) } // checkForWrongDirection +//----------------------------------------------------------------------------- +/** Checks if a kart is going in the wrong direction. + * This is the online server only version to kick players + * who misbehave. + * \param i Kart id. + * \param dt Time step size. + */ +void LinearWorld::serverCheckForWrongDirection(unsigned int i, float dt) +{ + KartInfo &ki = m_kart_info[i]; + + const AbstractKart *kart=m_karts[i].get(); + // If the kart can go in more than one directions from the current track + // don't do any reverse message handling, since it is likely that there + // will be one direction in which it isn't going backwards anyway. + int sector = getTrackSector(i)->getCurrentGraphNode(); + + if (DriveGraph::get()->getNumberOfSuccessors(sector) > 1) + return; + + // check if the player is going in the wrong direction + const DriveNode* node = DriveGraph::get()->getNode(sector); + Vec3 center_line = node->getUpperCenter() - node->getLowerCenter(); + float angle_diff = kart->getVelocity().angle(center_line); + + if (angle_diff > M_PI) + angle_diff -= 2*M_PI; + else if (angle_diff < -M_PI) + angle_diff += 2*M_PI; + + // if the kart is going back way, i.e. if angle + // is too big(unless the kart has already finished the race). + // record how long this happens + if ((angle_diff > DEGREE_TO_RAD * 120.0f || + angle_diff < -DEGREE_TO_RAD * 120.0f) && + kart->getVelocityLC().getY() > 0.0f && + !kart->hasFinishedRace()) + { + ki.m_wrong_way_timer += dt; + } + else + { + if (!kart->hasFinishedRace() && !kart->getKartAnimation()) + { + if (kart->getSpeed() < ServerConfig::m_troll_max_stop_speed) + // stopping is also trolling + ki.m_wrong_way_timer += dt; + else if(kart->getSpeed() > ServerConfig::m_troll_min_normal_speed) + { + // racing normally reduces timer + ki.m_wrong_way_timer -= dt; + if (ki.m_wrong_way_timer < 0) + ki.m_wrong_way_timer = 0; + } + } + } + + // If a kart is going wrong way for too long, take action + if (ki.m_warn_level == 0 && ki.m_wrong_way_timer > ServerConfig::m_troll_warning_time) + { // warning + ki.m_warn_level = 1; + ki.m_wrong_way_timer = 0; + } + if (ki.m_warn_level == 1 && ki.m_wrong_way_timer > ServerConfig::m_troll_kick_time) + { // kick + ki.m_warn_level = 2; + } +} // serverCheckForWrongDirection + //----------------------------------------------------------------------------- void LinearWorld::setLastTriggeredCheckline(unsigned int kart_index, int index) { diff --git a/src/modes/linear_world.hpp b/src/modes/linear_world.hpp index ab3a0d2904d..7cdd8ac3caf 100644 --- a/src/modes/linear_world.hpp +++ b/src/modes/linear_world.hpp @@ -104,6 +104,9 @@ class LinearWorld : public WorldWithRank * direction so that a message can be displayed. */ float m_wrong_way_timer; + int m_warn_level; + int m_warn_issued; + /** Initialises all fields. */ KartInfo() { reset(); } // -------------------------------------------------------------------- @@ -116,6 +119,8 @@ class LinearWorld : public WorldWithRank m_estimated_finish = -1.0f; m_overall_distance = 0.0f; m_wrong_way_timer = 0.0f; + m_warn_level = 0; + m_warn_issued = 0; } // reset // -------------------------------------------------------------------- void saveCompleteState(BareNetworkString* bns); @@ -192,6 +197,17 @@ class LinearWorld : public WorldWithRank { return m_kart_info[kart_index].m_overall_distance; } // getOverallDistance + /** Returns the warn level + * \param kart_index World kart id of the kart. */ + int getWarnLevel(unsigned int kart_index) + { + if (m_kart_info[kart_index].m_warn_level > m_kart_info[kart_index].m_warn_issued) + { + m_kart_info[kart_index].m_warn_issued = m_kart_info[kart_index].m_warn_level; + return m_kart_info[kart_index].m_warn_level; + } + return 0; + } // getWarnLevel // ------------------------------------------------------------------------ /** Returns time for the fastest laps */ float getFastestLap() const @@ -236,6 +252,8 @@ class LinearWorld : public WorldWithRank void updateCheckLinesClient(const BareNetworkString& b); // ------------------------------------------------------------------------ void handleServerCheckStructureCount(unsigned count); + + void serverCheckForWrongDirection(unsigned int i, float dt); }; // LinearWorld #endif diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index d99c8660266..09f4a67012f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -245,6 +245,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_fixed_lap = ServerConfig::m_fixed_lap_count; + m_troll_active = ServerConfig::m_troll_active; + initAvailableModes(); std::vector all_k = @@ -2422,6 +2424,35 @@ void ServerLobby::update(int ticks) StringUtils::wideToUtf8(rki.getPlayerName()).c_str(), sec); peer->kick(); } + if (m_troll_active && !peer->isAIPeer()) + { + // for all human players + // if they troll, kick them + LinearWorld *lin_world = dynamic_cast(w); + if (lin_world) { + // check warn level for each player + switch(lin_world->getWarnLevel(i)) + { + case 0: // fine + break; + case 1: // print WARNING + { + std::string msg = ServerConfig::m_troll_warn_msg; + sendStringToPeer(msg, peer); + std::string player_name = StringUtils::wideToUtf8(peer->getPlayerProfiles()[0]->getName()); + Log::info("ServerLobby-AntiTroll", "Sent WARNING to %s", player_name.c_str()); + break; + } + default: // kick !! + { + std::string player_name = StringUtils::wideToUtf8(peer->getPlayerProfiles()[0]->getName()); + Log::info("ServerLobby-AntiTroll", "KICKING %s", player_name.c_str()); + peer->kick(); + break; + } + } + } + } } } if (w) @@ -7698,6 +7729,25 @@ void ServerLobby::handleServerCommand(Event* event, } return; } + if (argv[1] == "troll") + { + if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) + { + msg = "Usage: /admin troll [0/1] - disable or enable anti troll system"; + sendStringToPeer(msg, peer); + return; + } + if (argv[2] == "0") + { + m_troll_active = false; + msg = "Trolls can stay"; + } else { + m_troll_active = true; + msg = "Trolls will be kicked"; + } + sendStringToPeer(msg, peer); + return; + } } else if (argv[0] == "version") { diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 22147d0c967..0a6029bcb1c 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -387,6 +387,9 @@ class ServerLobby : public LobbyProtocol std::atomic m_token_generation_tries; #endif + // config for troll system + bool m_troll_active; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 4a3ce511967..68dade50f80 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -270,6 +270,31 @@ namespace ServerConfig "If this value is set to true, players and the server must have " "at least one common official track.")); + SERVER_CFG_PREFIX BoolServerConfigParam m_troll_active + SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "use-anti-troll-system", + "If this value is set to true, warn and kick players who troll others.")); + + SERVER_CFG_PREFIX StringServerConfigParam m_troll_warn_msg + SERVER_CFG_DEFAULT(StringServerConfigParam("WARNING: You troll, you get kicked!", + "troll-warn-message", + "This message is shown as warning.")); + + SERVER_CFG_PREFIX FloatServerConfigParam m_troll_warning_time + SERVER_CFG_DEFAULT(FloatServerConfigParam(7.0f, "troll-warning-time", + "After this time (in sec) of backwards movement or stopping a warning is issued.")); + + SERVER_CFG_PREFIX FloatServerConfigParam m_troll_kick_time + SERVER_CFG_DEFAULT(FloatServerConfigParam(10.0f, "troll-kick-time", + "After this time (in sec) of backwards movement or stopping the player is kicked.")); + + SERVER_CFG_PREFIX FloatServerConfigParam m_troll_min_normal_speed + SERVER_CFG_DEFAULT(FloatServerConfigParam(12.0f, "troll-min-normal-speed", + "Minimum speed in correct direction to decrease wron_way timer.")); + + SERVER_CFG_PREFIX FloatServerConfigParam m_troll_max_stop_speed + SERVER_CFG_DEFAULT(FloatServerConfigParam(5.0f, "troll-max-stop-speed", + "A player going slower than this is considered stopping.")); + SERVER_CFG_PREFIX IntServerConfigParam m_min_start_game_players SERVER_CFG_DEFAULT(IntServerConfigParam(2, "min-start-game-players", "Only auto start kart selection when number of " From 3f40f3e0b2998775510a806f7ff8e97d1424c0ec Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 25 Jun 2021 15:45:16 +0300 Subject: [PATCH 106/830] Allow specifying powerup config as a command line parameter --- src/items/powerup_manager.cpp | 5 +++-- src/items/powerup_manager.hpp | 2 +- src/main.cpp | 7 ++++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/items/powerup_manager.cpp b/src/items/powerup_manager.cpp index 046dee96059..4faa6ebef04 100644 --- a/src/items/powerup_manager.cpp +++ b/src/items/powerup_manager.cpp @@ -123,9 +123,10 @@ PowerupManager::PowerupType //----------------------------------------------------------------------------- /** Loads powerups models and icons from the powerup.xml file. */ -void PowerupManager::loadPowerupsModels() +void PowerupManager::loadPowerupsModels(std::string filename) { - const std::string file_name = file_manager->getAsset("powerup.xml"); + const std::string load_from = (filename.empty() ? "powerup.xml" : filename); + const std::string file_name = file_manager->getAsset(load_from); XMLNode *root = file_manager->createXMLTree(file_name); for(unsigned int i=0; igetNumNodes(); i++) { diff --git a/src/items/powerup_manager.hpp b/src/items/powerup_manager.hpp index b7f61d8a251..22aabf387e9 100644 --- a/src/items/powerup_manager.hpp +++ b/src/items/powerup_manager.hpp @@ -163,7 +163,7 @@ class PowerupManager : public NoCopy PowerupManager (); ~PowerupManager (); - void loadPowerupsModels (); + void loadPowerupsModels (std::string& filename = ""); void loadWeights(const XMLNode *node, const std::string &category); void unloadPowerups (); void computeWeightsForRace(int num_karts); diff --git a/src/main.cpp b/src/main.cpp index bc7811dff78..aaa52f7808c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2300,7 +2300,12 @@ int main(int argc, char *argv[]) material_manager->addSharedMaterial(materials_file); } Referee::init(); - powerup_manager->loadPowerupsModels(); + + if (CommandLine::has("--powerup-file", &s)) + powerup_manager->loadPowerupsModels(s); + else + powerup_manager->loadPowerupsModels(); + ItemManager::loadDefaultItemMeshes(); GUIEngine::addLoadingIcon( irr_driver->getTexture(FileManager::GUI_ICON, From 14f55bd49a3310fe97e13ed56025adfe7a72cbc4 Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 25 Jun 2021 15:47:49 +0300 Subject: [PATCH 107/830] Fix compilation errors --- src/items/powerup_manager.cpp | 3 +-- src/items/powerup_manager.hpp | 2 +- src/main.cpp | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/items/powerup_manager.cpp b/src/items/powerup_manager.cpp index 4faa6ebef04..0c4a19240cb 100644 --- a/src/items/powerup_manager.cpp +++ b/src/items/powerup_manager.cpp @@ -125,8 +125,7 @@ PowerupManager::PowerupType */ void PowerupManager::loadPowerupsModels(std::string filename) { - const std::string load_from = (filename.empty() ? "powerup.xml" : filename); - const std::string file_name = file_manager->getAsset(load_from); + const std::string file_name = file_manager->getAsset(filename); XMLNode *root = file_manager->createXMLTree(file_name); for(unsigned int i=0; igetNumNodes(); i++) { diff --git a/src/items/powerup_manager.hpp b/src/items/powerup_manager.hpp index 22aabf387e9..1f438752a15 100644 --- a/src/items/powerup_manager.hpp +++ b/src/items/powerup_manager.hpp @@ -163,7 +163,7 @@ class PowerupManager : public NoCopy PowerupManager (); ~PowerupManager (); - void loadPowerupsModels (std::string& filename = ""); + void loadPowerupsModels (std::string& filename); void loadWeights(const XMLNode *node, const std::string &category); void unloadPowerups (); void computeWeightsForRace(int num_karts); diff --git a/src/main.cpp b/src/main.cpp index aaa52f7808c..1b9649bdd74 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2300,11 +2300,11 @@ int main(int argc, char *argv[]) material_manager->addSharedMaterial(materials_file); } Referee::init(); - + if (CommandLine::has("--powerup-file", &s)) powerup_manager->loadPowerupsModels(s); else - powerup_manager->loadPowerupsModels(); + powerup_manager->loadPowerupsModels("powerup.xml"); ItemManager::loadDefaultItemMeshes(); From cfcad15484245d6cd0cdcd0ad52475e2cf58dc43 Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 25 Jun 2021 15:50:13 +0300 Subject: [PATCH 108/830] Fix another compilation error --- src/items/powerup_manager.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/items/powerup_manager.hpp b/src/items/powerup_manager.hpp index 1f438752a15..4dcd6b029fe 100644 --- a/src/items/powerup_manager.hpp +++ b/src/items/powerup_manager.hpp @@ -163,7 +163,7 @@ class PowerupManager : public NoCopy PowerupManager (); ~PowerupManager (); - void loadPowerupsModels (std::string& filename); + void loadPowerupsModels (std::string filename); void loadWeights(const XMLNode *node, const std::string &category); void unloadPowerups (); void computeWeightsForRace(int num_karts); From 6af7e6d3611bf4ca1a73bb643de622e21c9d75f2 Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 25 Jun 2021 16:37:40 +0300 Subject: [PATCH 109/830] Fix compilation error part 3 --- src/items/powerup_manager.cpp | 9 +++++++++ src/items/powerup_manager.hpp | 1 + src/main.cpp | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/items/powerup_manager.cpp b/src/items/powerup_manager.cpp index 0c4a19240cb..83ceead56c4 100644 --- a/src/items/powerup_manager.cpp +++ b/src/items/powerup_manager.cpp @@ -120,6 +120,15 @@ PowerupManager::PowerupType return POWERUP_NOTHING; } // getPowerupType +//----------------------------------------------------------------------------- +/** Loads powerups models and icons from the powerup.xml file. + */ +void PowerupManager::loadPowerupsModels() +{ + loadPowerupsModels("powerup.xml"); +} // loadPowerupsModels + +//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- /** Loads powerups models and icons from the powerup.xml file. */ diff --git a/src/items/powerup_manager.hpp b/src/items/powerup_manager.hpp index 4dcd6b029fe..cca238c2bf4 100644 --- a/src/items/powerup_manager.hpp +++ b/src/items/powerup_manager.hpp @@ -163,6 +163,7 @@ class PowerupManager : public NoCopy PowerupManager (); ~PowerupManager (); + void loadPowerupsModels (); void loadPowerupsModels (std::string filename); void loadWeights(const XMLNode *node, const std::string &category); void unloadPowerups (); diff --git a/src/main.cpp b/src/main.cpp index 1b9649bdd74..41ed1aefd67 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2304,7 +2304,7 @@ int main(int argc, char *argv[]) if (CommandLine::has("--powerup-file", &s)) powerup_manager->loadPowerupsModels(s); else - powerup_manager->loadPowerupsModels("powerup.xml"); + powerup_manager->loadPowerupsModels(); ItemManager::loadDefaultItemMeshes(); From aaaac8abd5f63bbff7c7ece464913262e79b5a97 Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 25 Jun 2021 17:21:47 +0300 Subject: [PATCH 110/830] Fix powerup config name for all function calls --- src/items/powerup_manager.cpp | 12 ++---------- src/items/powerup_manager.hpp | 5 ++++- src/main.cpp | 5 ++--- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/items/powerup_manager.cpp b/src/items/powerup_manager.cpp index 83ceead56c4..721887bbf45 100644 --- a/src/items/powerup_manager.cpp +++ b/src/items/powerup_manager.cpp @@ -53,6 +53,7 @@ PowerupManager::PowerupManager() m_all_meshes[i] = NULL; m_all_icons[i] = (Material*)NULL; } + m_config_file = "powerup.xml"; } // PowerupManager //----------------------------------------------------------------------------- @@ -125,16 +126,7 @@ PowerupManager::PowerupType */ void PowerupManager::loadPowerupsModels() { - loadPowerupsModels("powerup.xml"); -} // loadPowerupsModels - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -/** Loads powerups models and icons from the powerup.xml file. - */ -void PowerupManager::loadPowerupsModels(std::string filename) -{ - const std::string file_name = file_manager->getAsset(filename); + const std::string file_name = file_manager->getAsset(m_config_file); XMLNode *root = file_manager->createXMLTree(file_name); for(unsigned int i=0; igetNumNodes(); i++) { diff --git a/src/items/powerup_manager.hpp b/src/items/powerup_manager.hpp index cca238c2bf4..b6070abff7b 100644 --- a/src/items/powerup_manager.hpp +++ b/src/items/powerup_manager.hpp @@ -158,13 +158,16 @@ class PowerupManager : public NoCopy * for network games it will use the start time from server. */ std::atomic m_random_seed; + std::string m_config_file; + public: static void unitTesting(); PowerupManager (); ~PowerupManager (); + void setFileName(std::string s) { m_config_file = s; } + std::string getFileName() { return m_config_file; } void loadPowerupsModels (); - void loadPowerupsModels (std::string filename); void loadWeights(const XMLNode *node, const std::string &category); void unloadPowerups (); void computeWeightsForRace(int num_karts); diff --git a/src/main.cpp b/src/main.cpp index 41ed1aefd67..1c7aaf7285c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2302,9 +2302,8 @@ int main(int argc, char *argv[]) Referee::init(); if (CommandLine::has("--powerup-file", &s)) - powerup_manager->loadPowerupsModels(s); - else - powerup_manager->loadPowerupsModels(); + powerup_manager->setFileName(s); + powerup_manager->loadPowerupsModels(); ItemManager::loadDefaultItemMeshes(); From 837ea11ad67fccb818eb36e7f60f7a4995bcbbff Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 26 Jun 2021 23:45:12 +0000 Subject: [PATCH 111/830] Fix kart color update while using wildcards for /admin team (#3) --- src/network/protocols/server_lobby.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 09f4a67012f..2b138217287 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7593,6 +7593,7 @@ void ServerLobby::handleServerCommand(Event* event, } index = abs(index); m_team_for_player[player] = index; + wide_player_name = StringUtils::utf8ToWide(player); if (player_peer) { for (auto& profile : player_peer.get()->getPlayerProfiles()) From a647e079b3226c7ff686f00b27954e8c03a5448c Mon Sep 17 00:00:00 2001 From: kimden Date: Sun, 18 Jul 2021 19:59:06 +0300 Subject: [PATCH 112/830] Change playeraddonscore to actual numbers --- src/network/protocols/server_lobby.cpp | 29 ++++++++++++-------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 2b138217287..ebbe3fa38bf 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4183,23 +4183,19 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) if (!m_addon_kts.first.empty()) { - addons_scores[AS_KART] = int - ((float)addon_kart / (float)m_addon_kts.first.size() * 100.0); + addons_scores[AS_KART] = addon_kart; } if (!m_addon_kts.second.empty()) { - addons_scores[AS_TRACK] = int - ((float)addon_track / (float)m_addon_kts.second.size() * 100.0); + addons_scores[AS_TRACK] = addon_track; } if (!m_addon_arenas.empty()) { - addons_scores[AS_ARENA] = int - ((float)addon_arena / (float)m_addon_arenas.size() * 100.0); + addons_scores[AS_ARENA] = addon_arena; } if (!m_addon_soccers.empty()) { - addons_scores[AS_SOCCER] = int - ((float)addon_soccer / (float)m_addon_soccers.size() * 100.0); + addons_scores[AS_SOCCER] = addon_soccer; } // Save available karts and tracks from clients in STKPeer so if this peer @@ -7046,7 +7042,8 @@ void ServerLobby::handleServerCommand(Event* event, if (player_name.empty() || !player_peer) { chat->encodeString16( - L"Usage: /playeraddonscore [player name] (return 0-100)"); + L"Usage: /playeraddonscore [player name] " + "(returns the number of addons, not a percentage)"); } else { @@ -7055,21 +7052,21 @@ void ServerLobby::handleServerCommand(Event* event, scores[AS_ARENA] == -1 && scores[AS_SOCCER] == -1) { chat->encodeString16(StringUtils::utf8ToWide - (player_name + " has no addon")); + (player_name + " has no addons")); } else { std::string msg = player_name; - msg += " addon:"; + msg += " addons:"; if (scores[AS_KART] != -1) - msg += " kart: " + StringUtils::toString(scores[AS_KART]) + ","; + msg += " karts: " + StringUtils::toString(scores[AS_KART]) + ","; if (scores[AS_TRACK] != -1) - msg += " track: " + StringUtils::toString(scores[AS_TRACK]) + ","; + msg += " tracks: " + StringUtils::toString(scores[AS_TRACK]) + ","; if (scores[AS_ARENA] != -1) - msg += " arena: " + StringUtils::toString(scores[AS_ARENA]) + ","; + msg += " arenas: " + StringUtils::toString(scores[AS_ARENA]) + ","; if (scores[AS_SOCCER] != -1) - msg += " soccer: " + StringUtils::toString(scores[AS_SOCCER]) + ","; - msg = msg.substr(0, msg.size() - 1); + msg += " fields: " + StringUtils::toString(scores[AS_SOCCER]) + ","; + msg.pop_back(); chat->encodeString16(StringUtils::utf8ToWide(msg)); } } From 8b8cd2c0d24732593374b1ceb7d9df7b4a900329 Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 23 Jul 2021 15:48:08 +0300 Subject: [PATCH 113/830] Allow to change between game length restrictions using commands --- src/network/protocols/server_lobby.cpp | 82 +++++++++++++++++++++++--- src/network/protocols/server_lobby.hpp | 2 + 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index ebbe3fa38bf..d9f0aebb18d 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -244,6 +244,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_consent_on_replays = false; m_fixed_lap = ServerConfig::m_fixed_lap_count; + m_default_lap_multiplier = ServerConfig::m_auto_game_time_ratio; m_troll_active = ServerConfig::m_troll_active; @@ -3111,7 +3112,7 @@ void ServerLobby::startSelection(const Event *event) .addFloat(ServerConfig::m_voting_timeout) .addUInt8(/*m_game_setup->isGrandPrixStarted() ? 1 : */0) .addUInt8((m_fixed_lap >= 0 - || ServerConfig::m_auto_game_time_ratio > 0.0f) ? 1 : 0) + || m_default_lap_multiplier > 0.0f) ? 1 : 0) .addUInt8(ServerConfig::m_track_voting ? 1 : 0); const auto& all_k = m_available_kts.first; @@ -3158,7 +3159,7 @@ void ServerLobby::startSelection(const Event *event) .addFloat(ServerConfig::m_voting_timeout) .addUInt8(/*m_game_setup->isGrandPrixStarted() ? 1 : */0) .addUInt8((m_fixed_lap >= 0 - || ServerConfig::m_auto_game_time_ratio > 0.0f) ? 1 : 0) + || m_default_lap_multiplier > 0.0f) ? 1 : 0) .addUInt8(ServerConfig::m_track_voting ? 1 : 0); ns->addUInt16((uint16_t)(has_gnu ? 1 : 0)).addUInt16( @@ -4988,11 +4989,11 @@ void ServerLobby::handlePlayerVote(Event* event) } else if (RaceManager::get()->modeHasLaps()) { - if (ServerConfig::m_auto_game_time_ratio > 0.0f) + if (m_default_lap_multiplier > 0.0f) { vote.m_num_laps = (uint8_t)(fmaxf(1.0f, (float)t->getDefaultNumberOfLaps() * - ServerConfig::m_auto_game_time_ratio)); + m_default_lap_multiplier)); } else if (vote.m_num_laps == 0 || vote.m_num_laps > 20) vote.m_num_laps = (uint8_t)3; @@ -5003,9 +5004,9 @@ void ServerLobby::handlePlayerVote(Event* event) { if (m_game_setup->isSoccerGoalTarget()) { - if (ServerConfig::m_auto_game_time_ratio > 0.0f) + if (m_default_lap_multiplier > 0.0f) { - vote.m_num_laps = (uint8_t)(ServerConfig::m_auto_game_time_ratio * + vote.m_num_laps = (uint8_t)(m_default_lap_multiplier * UserConfigParams::m_num_goals); } else if (vote.m_num_laps > 10) @@ -5013,9 +5014,9 @@ void ServerLobby::handlePlayerVote(Event* event) } else { - if (ServerConfig::m_auto_game_time_ratio > 0.0f) + if (m_default_lap_multiplier > 0.0f) { - vote.m_num_laps = (uint8_t)(ServerConfig::m_auto_game_time_ratio * + vote.m_num_laps = (uint8_t)(m_default_lap_multiplier * UserConfigParams::m_soccer_time_limit); } else if (vote.m_num_laps > 15) @@ -7502,13 +7503,76 @@ void ServerLobby::handleServerCommand(Event* event, { m_allowed_to_start = false; msg = "Now starting a race is forbidden"; - } else { + } + else + { m_allowed_to_start = true; msg = "Now starting a race is allowed"; } sendStringToPeer(msg, peer); return; } + if (argv[1] == "length") + { + if (argv.size() < 3) + { + msg = "Usage: /admin length (x (float) | = (int) | check | clear)"; + sendStringToPeer(msg, peer); + return; + } + if (argv[2] == "check") + { + if (m_default_lap_multiplier < 0 && m_fixed_lap < 0) + msg = "Game length is currently chosen by players"; + else if (m_default_lap_multiplier > 0) + msg = StringUtils::insertValues( + "Game length is %.4f x default", + m_default_lap_multiplier); + else if (m_fixed_lap > 0) + msg = StringUtils::insertValues( + "Game length is %d", m_fixed_lap); + else + msg = StringUtils::insertValues( + "An error: game length is both %.4f x default and %d", + m_default_lap_multiplier, m_fixed_lap); + sendStringToPeer(msg, peer); + return; + } + if (argv[2] == "clear") + { + m_default_lap_multiplier = -1.0; + m_fixed_lap = -1; + msg = "Game length will be chosen by players"; + sendStringToAllPeers(msg, peer); + return; + } + double temp_double = -1.0; + int temp_int = -1; + if (argv[2] == "x" && argv.size() >= 4 && + StringUtils::parseString(argv[3], &temp_double)) + { + m_default_lap_multiplier = std::max(0.0, temp_double); + m_fixed_lap = -1; + msg = StringUtils::insertValues( + "Game length is now %.4f x default", + m_default_lap_multiplier); + sendStringToAllPeers(msg, peer); + return; + } + if (argv[2] == "=" && argv.size() >= 4 && + StringUtils::parseString(argv[3], &temp_int)) + { + m_fixed_lap = std::max(0, temp_int); + m_default_lap_multiplier = -1.0; + msg = StringUtils::insertValues( + "Game length is now %d", m_fixed_lap); + sendStringToAllPeers(msg, peer); + return; + } + msg = "Usage: /admin length (x (float) | = (int) | check | clear)"; + sendStringToPeer(msg, peer); + return; + } if (argv[1] == "shuffle") { if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 0a6029bcb1c..182e1af9333 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -365,6 +365,8 @@ class ServerLobby : public LobbyProtocol int m_fixed_lap; + double m_default_lap_multiplier; + std::vector m_scoring_int_params; std::string m_scoring_type; From 45e2df667278e13291dbfececeda5acf0a265db7 Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 23 Jul 2021 15:53:20 +0300 Subject: [PATCH 114/830] Fix extra parameters --- src/network/protocols/server_lobby.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index d9f0aebb18d..24ebc9b1c40 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7543,7 +7543,7 @@ void ServerLobby::handleServerCommand(Event* event, m_default_lap_multiplier = -1.0; m_fixed_lap = -1; msg = "Game length will be chosen by players"; - sendStringToAllPeers(msg, peer); + sendStringToAllPeers(msg); return; } double temp_double = -1.0; @@ -7556,7 +7556,7 @@ void ServerLobby::handleServerCommand(Event* event, msg = StringUtils::insertValues( "Game length is now %.4f x default", m_default_lap_multiplier); - sendStringToAllPeers(msg, peer); + sendStringToAllPeers(msg); return; } if (argv[2] == "=" && argv.size() >= 4 && @@ -7566,7 +7566,7 @@ void ServerLobby::handleServerCommand(Event* event, m_default_lap_multiplier = -1.0; msg = StringUtils::insertValues( "Game length is now %d", m_fixed_lap); - sendStringToAllPeers(msg, peer); + sendStringToAllPeers(msg); return; } msg = "Usage: /admin length (x (float) | = (int) | check | clear)"; From 6ec639948b36d44f605b1c144b5ffbb5969d2ff5 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 28 Jul 2021 10:13:54 +0000 Subject: [PATCH 115/830] Fix formatting numbers in /admin length messages --- src/network/protocols/server_lobby.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 24ebc9b1c40..567ede28b1d 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7526,14 +7526,14 @@ void ServerLobby::handleServerCommand(Event* event, msg = "Game length is currently chosen by players"; else if (m_default_lap_multiplier > 0) msg = StringUtils::insertValues( - "Game length is %.4f x default", + "Game length is %f x default", m_default_lap_multiplier); else if (m_fixed_lap > 0) msg = StringUtils::insertValues( "Game length is %d", m_fixed_lap); else msg = StringUtils::insertValues( - "An error: game length is both %.4f x default and %d", + "An error: game length is both %f x default and %d", m_default_lap_multiplier, m_fixed_lap); sendStringToPeer(msg, peer); return; @@ -7554,7 +7554,7 @@ void ServerLobby::handleServerCommand(Event* event, m_default_lap_multiplier = std::max(0.0, temp_double); m_fixed_lap = -1; msg = StringUtils::insertValues( - "Game length is now %.4f x default", + "Game length is now %f x default", m_default_lap_multiplier); sendStringToAllPeers(msg); return; From 20d3a7d1b7d4f30ee441815c0b7d6d9ae4682d82 Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 9 Aug 2021 13:45:23 +0300 Subject: [PATCH 116/830] Add default values for gp scoring --- src/network/server_config.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 68dade50f80..f664263e3fa 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -608,7 +608,9 @@ namespace ServerConfig "the list ends. Can be useful for grands prix.")); SERVER_CFG_PREFIX StringServerConfigParam m_gp_scoring - SERVER_CFG_DEFAULT(StringServerConfigParam("", "grand-prix-scoring", + SERVER_CFG_DEFAULT(StringServerConfigParam( + "fixed 0 1 10 8 6 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", + "grand-prix-scoring", "A custom Grand Prix scoring system to be used, " "empty for default.")); From 79d79618c183dd56113ca6388829736d7798eba1 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 11 Aug 2021 03:11:03 +0300 Subject: [PATCH 117/830] Fix several sql queries to avoid injections --- src/network/protocols/server_lobby.cpp | 122 +++++++++++++++---------- src/network/protocols/server_lobby.hpp | 2 + 2 files changed, 75 insertions(+), 49 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 567ede28b1d..5bea1cf17a8 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7398,53 +7398,8 @@ void ServerLobby::handleServerCommand(Event* event, } else { - std::string records_table_name = ServerConfig::m_records_table_name; - if (!records_table_name.empty()) - { - std::string get_query = StringUtils::insertValues("SELECT username, " - "result FROM %s LEFT JOIN " - "(SELECT venue as v, reverse as r, mode as m, laps as l, " - "min(result) as min_res FROM %s group by v, r, m, l) " - "ON venue = v and reverse = r and mode = m and laps = l " - "WHERE venue = '%s' and reverse = '%s' " - "and mode = '%s' and laps = %d and result = min_res;", - records_table_name.c_str(), records_table_name.c_str(), - track_name.c_str(), reverse_name.c_str(), mode_name.c_str(), - laps_count); - auto ret = vectorSQLQuery(get_query, 2); - if (!ret.first) - { - chat->encodeString16(L"Failed to make a query"); - } - else if (ret.second[0].size() > 0) - { - double best_result = 1e18; - if (!StringUtils::parseString( - ret.second[1][0], &best_result)) - { - chat->encodeString16(L"A strange error occured, " - "please take a screenshot " - "and contact the server owner."); - } - else - { - std::string message = StringUtils::insertValues( - "The record is %s by %s", - StringUtils::timeToString(best_result), - ret.second[0][0]); - chat->encodeString16( - StringUtils::utf8ToWide(message)); - } - } - else - { - chat->encodeString16(L"No time set yet. Or there is a typo."); - } - } - else - { - chat->encodeString16(L"No table storing records!"); - } + std::string result = getRecord(track_name, mode_name, reverse_name, laps_count); + chat->encodeString16(StringUtils::utf8ToWide(result)); } } #else @@ -8288,11 +8243,19 @@ void ServerLobby::storeResults() std::string query = StringUtils::insertValues( "INSERT INTO %s " "(username, venue, reverse, mode, laps, result) " - "VALUES ('%s', '%s', '%s', '%s', %d, '%s');", + "VALUES ('%s', ?, '%s', '%s', %d, '%s');", m_results_table_name.c_str(), username.c_str(), track_name.c_str(), reverse_string.c_str(), mode_name.c_str(), laps_number, elapsed_string.str() ); - easySQLQuery(query); + bool written = easySQLQuery(query, [username](sqlite3_stmt* stmt) + { + if (sqlite3_bind_text(stmt, 1, username.c_str(), + -1, SQLITE_TRANSIENT) != SQLITE_OK) + { + Log::error("easySQLQuery", "Failed to bind %s.", + username.c_str()); + } + }); } if (record_fetched && best_cur_player_idx != -1) { @@ -8960,6 +8923,67 @@ void ServerLobby::updateTournamentRole(STKPeer* peer) } } // updateTournamentRole //----------------------------------------------------------------------------- +std::string ServerLobby::getRecord(std::string& track, std::string& mode, + std::string& direction, std::string& laps) +{ + std::string records_table_name = ServerConfig::m_records_table_name; + if (!records_table_name.empty()) + { + std::string get_query = StringUtils::insertValues("SELECT username, " + "result FROM %s LEFT JOIN " + "(SELECT venue as v, reverse as r, mode as m, laps as l, " + "min(result) as min_res FROM %s group by v, r, m, l) " + "ON venue = v and reverse = r and mode = m and laps = l " + "WHERE venue = ? and reverse = '%s' " + "and mode = '%s' and laps = %d and result = min_res;", + records_table_name.c_str(), records_table_name.c_str(), + direction.c_str(), mode.c_str(), + laps.c_str()); + auto ret = vectorSQLQuery(get_query, 2, + [track](sqlite3_stmt* stmt) + { + // SQLITE_TRANSIENT to copy string + if (sqlite3_bind_text(stmt, 1, track.c_str(), + -1, SQLITE_TRANSIENT) != SQLITE_OK) + { + Log::error("vectorSQLQuery", "Failed to bind %s.", + track.c_str()); + } + }); + if (!ret.first) + { + return "Failed to make a query"; + } + else if (ret.second[0].size() > 0) + { + double best_result = 1e18; + if (!StringUtils::parseString( + ret.second[1][0], &best_result)) + { + return "A strange error occured, " + "please take a screenshot " + "and contact the server owner."; + } + else + { + std::string message = StringUtils::insertValues( + "The record is %s by %s", + StringUtils::timeToString(best_result), + ret.second[0][0]); + return message; + } + } + else + { + return "No time set yet. Or there is a typo."; + } + } + else + { + return "No table storing records!"; + } +} // getRecord +//----------------------------------------------------------------------------- #ifdef ENABLE_WEB_SUPPORT diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 182e1af9333..07034a3fb7e 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -588,6 +588,8 @@ class ServerLobby : public LobbyProtocol void sendStringToPeer(std::string& s, std::shared_ptr& peer) const; void sendStringToPeer(std::string& s, STKPeer* peer) const; void sendStringToAllPeers(std::string& s); + std::string getRecord(std::string& track, std::string& mode, + std::string& direction, std::string& laps); }; // class ServerLobby #endif // SERVER_LOBBY_HPP From 9e24d1539fd633261b9c80e15aed8f3b832d51c3 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 11 Aug 2021 03:17:09 +0300 Subject: [PATCH 118/830] Fix compilation and logic errors --- src/network/protocols/server_lobby.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 5bea1cf17a8..3e1e50f47b5 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7398,7 +7398,7 @@ void ServerLobby::handleServerCommand(Event* event, } else { - std::string result = getRecord(track_name, mode_name, reverse_name, laps_count); + std::string result = getRecord(track_name, mode_name, reverse_name, std::to_string(laps_count)); chat->encodeString16(StringUtils::utf8ToWide(result)); } } @@ -8243,8 +8243,8 @@ void ServerLobby::storeResults() std::string query = StringUtils::insertValues( "INSERT INTO %s " "(username, venue, reverse, mode, laps, result) " - "VALUES ('%s', ?, '%s', '%s', %d, '%s');", - m_results_table_name.c_str(), username.c_str(), track_name.c_str(), + "VALUES (?, '%s', '%s', '%s', %d, '%s');", + m_results_table_name.c_str(), track_name.c_str(), reverse_string.c_str(), mode_name.c_str(), laps_number, elapsed_string.str() ); bool written = easySQLQuery(query, [username](sqlite3_stmt* stmt) From 945fab8f7664001b3a6951a6e11689024d92c9f6 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 11 Aug 2021 03:19:45 +0300 Subject: [PATCH 119/830] Fix more compilation errors --- src/network/protocols/server_lobby.cpp | 6 +++--- src/network/protocols/server_lobby.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3e1e50f47b5..ec35193419f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7398,7 +7398,7 @@ void ServerLobby::handleServerCommand(Event* event, } else { - std::string result = getRecord(track_name, mode_name, reverse_name, std::to_string(laps_count)); + std::string result = getRecord(track_name, mode_name, reverse_name, laps_count); chat->encodeString16(StringUtils::utf8ToWide(result)); } } @@ -8924,7 +8924,7 @@ void ServerLobby::updateTournamentRole(STKPeer* peer) } // updateTournamentRole //----------------------------------------------------------------------------- std::string ServerLobby::getRecord(std::string& track, std::string& mode, - std::string& direction, std::string& laps) + std::string& direction, int laps) { std::string records_table_name = ServerConfig::m_records_table_name; if (!records_table_name.empty()) @@ -8938,7 +8938,7 @@ std::string ServerLobby::getRecord(std::string& track, std::string& mode, "and mode = '%s' and laps = %d and result = min_res;", records_table_name.c_str(), records_table_name.c_str(), direction.c_str(), mode.c_str(), - laps.c_str()); + laps); auto ret = vectorSQLQuery(get_query, 2, [track](sqlite3_stmt* stmt) { diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 07034a3fb7e..fdb3cc2d667 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -589,7 +589,7 @@ class ServerLobby : public LobbyProtocol void sendStringToPeer(std::string& s, STKPeer* peer) const; void sendStringToAllPeers(std::string& s); std::string getRecord(std::string& track, std::string& mode, - std::string& direction, std::string& laps); + std::string& direction, int laps); }; // class ServerLobby #endif // SERVER_LOBBY_HPP From 6e0d7627b8aa168109b18cb94150bb425f903cc7 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 14 Aug 2021 01:35:51 +0300 Subject: [PATCH 120/830] Try to print full sql statement to the log in case it was successfully prepared --- src/network/protocols/server_lobby.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index ec35193419f..ce3d9223125 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1352,13 +1352,16 @@ bool ServerLobby::easySQLQuery(const std::string& query, { if (bind_function) bind_function(stmt); + char* actual_query_cstr = sqlite3_expanded_sql(stmt); + std::string actual_query(actual_query_cstr); + sqlite3_free(actual_query_cstr); ret = sqlite3_step(stmt); ret = sqlite3_finalize(stmt); if (ret != SQLITE_OK) { Log::error("ServerLobby", "Error finalize database for easy query %s: %s", - query.c_str(), sqlite3_errmsg(m_db)); + actual_query.c_str(), sqlite3_errmsg(m_db)); return false; } } @@ -1386,6 +1389,9 @@ ServerLobby::vectorSQLQuery(const std::string& query, { if (bind_function) bind_function(stmt); + char* actual_query_cstr = sqlite3_expanded_sql(stmt); + std::string actual_query(actual_query_cstr); + sqlite3_free(actual_query_cstr); ret = sqlite3_step(stmt); while (sqlite3_column_text(stmt, 0)) { @@ -1401,7 +1407,7 @@ ServerLobby::vectorSQLQuery(const std::string& query, { Log::error("ServerLobby", "Error finalize database for vector query %s: %s", - query.c_str(), sqlite3_errmsg(m_db)); + actual_query.c_str(), sqlite3_errmsg(m_db)); return {false, {}}; } } From 1281b21d0540dab1e05ab91b3cfefe7adb5aef7d Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 14 Aug 2021 02:26:48 +0300 Subject: [PATCH 121/830] Try to allow crowned players to manipulate game length and track queue on only-host servers --- src/network/protocols/server_lobby.cpp | 203 +++++++++++++------------ 1 file changed, 105 insertions(+), 98 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index ce3d9223125..6ebdfe6d995 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7441,7 +7441,8 @@ void ServerLobby::handleServerCommand(Event* event, { std::string msg; bool can = (peer->isAngryHost() || (ServerConfig::m_soccer_tournament && hasHostRights(peer))); - if (!can) { + bool weak_abilities = (ServerConfig::m_only_host_riding && hasHostRights(peer)); + if (!can && !weak_abilities) { msg = "You cannot control this server"; sendStringToPeer(msg, peer); return; @@ -7452,27 +7453,6 @@ void ServerLobby::handleServerCommand(Event* event, sendStringToPeer(msg, peer); return; } - if (argv[1] == "start") - { - if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) - { - msg = "Usage: /admin start [0/1] - allow or forbid starting a race"; - sendStringToPeer(msg, peer); - return; - } - if (argv[2] == "0") - { - m_allowed_to_start = false; - msg = "Now starting a race is forbidden"; - } - else - { - m_allowed_to_start = true; - msg = "Now starting a race is allowed"; - } - sendStringToPeer(msg, peer); - return; - } if (argv[1] == "length") { if (argv.size() < 3) @@ -7534,6 +7514,109 @@ void ServerLobby::handleServerCommand(Event* event, sendStringToPeer(msg, peer); return; } + if (argv[1] == "queue") + { + std::string format_string = "Format: /admin queue (show | push[_front] (track) | pop[_back])"; + if (argv.size() < 3) + { + sendStringToPeer(format_string, peer); + return; + } + if (argv[2] == "show") + { + std::string msg = "Queue:"; + for (const std::string& s: m_tracks_queue) { + msg += " " + s; + } + sendStringToPeer(msg, peer); + } + else if (argv[2] == "push" || argv[2] == "push_back") + { + if (argv.size() < 4) + { + sendStringToPeer(format_string, peer); + return; + } + m_tracks_queue.push_back(argv[3]); + std::string msg = "Pushed " + argv[3] + + " to the back of queue, current queue size: " + + std::to_string(m_tracks_queue.size()); + sendStringToPeer(msg, peer); + } + else if (argv[2] == "push_front") + { + if (argv.size() < 4) + { + sendStringToPeer(format_string, peer); + return; + } + m_tracks_queue.push_front(argv[3]); + std::string msg = "Pushed " + argv[3] + + " to the front of queue, current queue size: " + + std::to_string(m_tracks_queue.size()); + sendStringToPeer(msg, peer); + } + else if (argv[2] == "pop" || argv[2] == "pop_back") + { + std::string msg = ""; + if (m_tracks_queue.empty()) { + msg = "Queue was empty before."; + } + else + { + std::string msg = "Popped " + m_tracks_queue.front() + + "from the queue,"; + m_tracks_queue.pop_front(); + msg += " current queue size: " + + std::to_string(m_tracks_queue.size()); + } + sendStringToPeer(msg, peer); + } + else if (argv[2] == "pop_back") + { + std::string msg = ""; + if (m_tracks_queue.empty()) { + msg = "Queue was empty before."; + } + else + { + std::string msg = "Popped " + m_tracks_queue.back() + + "from the queue,"; + m_tracks_queue.pop_back(); + msg += " current queue size: " + + std::to_string(m_tracks_queue.size()); + } + sendStringToPeer(msg, peer); + } + return; + } + if (!can) { + msg = "You cannot control this server. As you are the crowned player, " + "you can invoke /admin length and /admin queue commands."; + sendStringToPeer(msg, peer); + return; + } + if (argv[1] == "start") + { + if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) + { + msg = "Usage: /admin start [0/1] - allow or forbid starting a race"; + sendStringToPeer(msg, peer); + return; + } + if (argv[2] == "0") + { + m_allowed_to_start = false; + msg = "Now starting a race is forbidden"; + } + else + { + m_allowed_to_start = true; + msg = "Now starting a race is allowed"; + } + sendStringToPeer(msg, peer); + return; + } if (argv[1] == "shuffle") { if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) @@ -7676,82 +7759,6 @@ void ServerLobby::handleServerCommand(Event* event, updatePlayerList(); return; } - if (argv[1] == "queue") - { - std::string format_string = "Format: /admin queue (show | push[_front] (track) | pop[_back])"; - if (argv.size() < 3) - { - sendStringToPeer(format_string, peer); - return; - } - if (argv[2] == "show") - { - std::string msg = "Queue:"; - for (const std::string& s: m_tracks_queue) { - msg += " " + s; - } - sendStringToPeer(msg, peer); - } - else if (argv[2] == "push" || argv[2] == "push_back") - { - if (argv.size() < 4) - { - sendStringToPeer(format_string, peer); - return; - } - m_tracks_queue.push_back(argv[3]); - std::string msg = "Pushed " + argv[3] - + " to the back of queue, current queue size: " - + std::to_string(m_tracks_queue.size()); - sendStringToPeer(msg, peer); - } - else if (argv[2] == "push_front") - { - if (argv.size() < 4) - { - sendStringToPeer(format_string, peer); - return; - } - m_tracks_queue.push_front(argv[3]); - std::string msg = "Pushed " + argv[3] - + " to the front of queue, current queue size: " - + std::to_string(m_tracks_queue.size()); - sendStringToPeer(msg, peer); - } - else if (argv[2] == "pop" || argv[2] == "pop_back") - { - std::string msg = ""; - if (m_tracks_queue.empty()) { - msg = "Queue was empty before."; - } - else - { - std::string msg = "Popped " + m_tracks_queue.front() - + "from the queue,"; - m_tracks_queue.pop_front(); - msg += " current queue size: " - + std::to_string(m_tracks_queue.size()); - } - sendStringToPeer(msg, peer); - } - else if (argv[2] == "pop_back") - { - std::string msg = ""; - if (m_tracks_queue.empty()) { - msg = "Queue was empty before."; - } - else - { - std::string msg = "Popped " + m_tracks_queue.back() - + "from the queue,"; - m_tracks_queue.pop_back(); - msg += " current queue size: " - + std::to_string(m_tracks_queue.size()); - } - sendStringToPeer(msg, peer); - } - return; - } if (argv[1] == "troll") { if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) From 3017ddb19a9a010fcdcd21e675ad9520ea208400 Mon Sep 17 00:00:00 2001 From: kimden Date: Mon, 16 Aug 2021 14:45:27 +0300 Subject: [PATCH 122/830] Change deadline for spectating from 90% to 250m to go --- src/network/protocols/server_lobby.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 6ebdfe6d995..a6cdee6b427 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2064,11 +2064,13 @@ bool ServerLobby::canLiveJoinNow() const } if (!fastest_kart) return false; - float progress = w->getOverallDistance( - fastest_kart->getWorldKartId()) / - (Track::getCurrentTrack()->getTrackLength() * - (float)RaceManager::get()->getNumLaps()); - if (progress > 0.9f) + float leader_distance = w->getOverallDistance( + fastest_kart->getWorldKartId()); + float total_distance = + Track::getCurrentTrack()->getTrackLength() * + (float)RaceManager::get()->getNumLaps(); + float progress = leader_distance / total_distance; + if (total_distance - leader_distance < 250.0) return false; } return live_join; From 4373b80283649f4da9157881db335dcfb3d29707 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 18 Aug 2021 00:49:17 +0300 Subject: [PATCH 123/830] Fix shuffling the GP grid --- src/modes/world_with_rank.hpp | 6 ----- src/network/game_setup.cpp | 5 ++-- src/network/game_setup.hpp | 3 ++- src/network/protocols/server_lobby.cpp | 2 +- src/race/race_manager.cpp | 32 +++++--------------------- 5 files changed, 12 insertions(+), 36 deletions(-) diff --git a/src/modes/world_with_rank.hpp b/src/modes/world_with_rank.hpp index fabf408f612..919f4cc20f6 100644 --- a/src/modes/world_with_rank.hpp +++ b/src/modes/world_with_rank.hpp @@ -54,8 +54,6 @@ class WorldWithRank : public World std::string m_custom_scoring_type; - bool m_shuffled; - #ifdef DEBUG /** Used for debugging to help detect if the same kart position * is used more than once. */ @@ -120,10 +118,6 @@ class WorldWithRank : public World // ------------------------------------------------------------------------ int getPolePoints() const; // ------------------------------------------------------------------------ - bool isShuffled() const { return m_shuffled; } - // ------------------------------------------------------------------------ - void setShuffled(bool value) { m_shuffled = value; } - // ------------------------------------------------------------------------ }; // WorldWithRank #endif diff --git a/src/network/game_setup.cpp b/src/network/game_setup.cpp index 2bdb962b870..f3a9a2019c9 100644 --- a/src/network/game_setup.cpp +++ b/src/network/game_setup.cpp @@ -147,12 +147,13 @@ void GameSetup::addServerInfo(NetworkString* ns) //----------------------------------------------------------------------------- void GameSetup::sortPlayersForGrandPrix( - std::vector >& players) const + std::vector >& players, + bool shuffle_instead) const { if (!isGrandPrix()) return; - if (m_tracks.size() == 1) + if (m_tracks.size() == 1 || shuffle_instead) { std::random_device rd; std::mt19937 g(rd()); diff --git a/src/network/game_setup.hpp b/src/network/game_setup.hpp index f6d84f2693e..509527ec3f5 100644 --- a/src/network/game_setup.hpp +++ b/src/network/game_setup.hpp @@ -134,7 +134,8 @@ class GameSetup const std::string& getCurrentTrack() const { return m_tracks.back(); } // ------------------------------------------------------------------------ void sortPlayersForGrandPrix( - std::vector >& players) const; + std::vector >& players, + bool shuffle_instead) const; // ------------------------------------------------------------------------ void sortPlayersForGame( std::vector >& players) const; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index a6cdee6b427..16f6f1c5f28 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1897,7 +1897,7 @@ void ServerLobby::asynchronousUpdate() m_ai_profiles.end()); } } - m_game_setup->sortPlayersForGrandPrix(players); + m_game_setup->sortPlayersForGrandPrix(players, m_shuffle_gp); m_game_setup->sortPlayersForGame(players); for (unsigned i = 0; i < players.size(); i++) { diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index 024b0b9a84c..8d0e4a7ce12 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -566,33 +566,13 @@ void RaceManager::startNextRace() player_last_offset = (int)m_player_karts.size(); } - WorldWithRank *wwr = dynamic_cast(World::getWorld()); - bool shuffle_instead = false; - if (wwr) - bool shuffle_instead = wwr->isShuffled(); - else + std::sort(m_kart_status.begin()+offset, + m_kart_status.end() - player_last_offset); + // reverse kart order if flagged in user's config + if (UserConfigParams::m_gp_most_points_first) { - Log::error("RaceManager", - "World with scores that is not a WorldWithRank??"); - } - - if (shuffle_instead) - { - std::random_device rd; - std::mt19937 g(rd()); - std::shuffle(m_kart_status.begin()+offset, - m_kart_status.end() - player_last_offset, g); - } - else - { - std::sort(m_kart_status.begin()+offset, - m_kart_status.end() - player_last_offset); - // reverse kart order if flagged in user's config - if (UserConfigParams::m_gp_most_points_first) - { - std::reverse(m_kart_status.begin()+offset, - m_kart_status.end() - player_last_offset); - } + std::reverse(m_kart_status.begin()+offset, + m_kart_status.end() - player_last_offset); } } // not first race From 5e8e479da9c0822c2d88313fd5b6c09f883cfd72 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 18 Aug 2021 00:56:23 +0300 Subject: [PATCH 124/830] Fixed the file that was unsaved locally --- src/network/protocols/server_lobby.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 16f6f1c5f28..aa8bbdb8a10 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -8768,7 +8768,6 @@ void ServerLobby::updateWorldSettings() if (wwr) { wwr->setCustomScoringSystem(m_scoring_type, m_scoring_int_params); - wwr->setShuffled(m_shuffle_gp); } SoccerWorld *sw = dynamic_cast(World::getWorld()); if (sw) From 2b0e9ff7b6501e3702f8784865e5c6aa1ab09b8c Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 18 Aug 2021 03:29:43 +0300 Subject: [PATCH 125/830] Add missing ifdef for sqlite --- src/network/protocols/server_lobby.cpp | 2 ++ src/network/protocols/server_lobby.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index a5b2e81d306..71b3c44092a 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -8938,6 +8938,7 @@ void ServerLobby::updateTournamentRole(STKPeer* peer) } } // updateTournamentRole //----------------------------------------------------------------------------- +#ifdef ENABLE_SQLITE3 std::string ServerLobby::getRecord(std::string& track, std::string& mode, std::string& direction, int laps) { @@ -8998,6 +8999,7 @@ std::string ServerLobby::getRecord(std::string& track, std::string& mode, return "No table storing records!"; } } // getRecord +#endif //----------------------------------------------------------------------------- #ifdef ENABLE_WEB_SUPPORT diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index fdb3cc2d667..dfd3e3bd9d5 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -588,8 +588,10 @@ class ServerLobby : public LobbyProtocol void sendStringToPeer(std::string& s, std::shared_ptr& peer) const; void sendStringToPeer(std::string& s, STKPeer* peer) const; void sendStringToAllPeers(std::string& s); +#ifdef ENABLE_SQLITE3 std::string getRecord(std::string& track, std::string& mode, std::string& direction, int laps); +#endif }; // class ServerLobby #endif // SERVER_LOBBY_HPP From 3ffc7844548ecef9c7371b5f22be0056e15a04ff Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 18 Aug 2021 03:43:36 +0300 Subject: [PATCH 126/830] Fix build status and separate info on anti-troll system --- ANTI_TROLL.md | 40 +++++++++++++++++++++++++++++++++++++ README.md | 55 +++++++++------------------------------------------ 2 files changed, 49 insertions(+), 46 deletions(-) create mode 100644 ANTI_TROLL.md diff --git a/ANTI_TROLL.md b/ANTI_TROLL.md new file mode 100644 index 00000000000..bc9a67d8aad --- /dev/null +++ b/ANTI_TROLL.md @@ -0,0 +1,40 @@ +## Info on experimental anti-troll system +If activated, a timer is kept for all players. System can be activated in xml config or in the lobby with command: +\admin troll [0,1] + +Timer is increased by the amount of time when +* a player drives in the wrong way +* a player moves below a given speed (troll-max-stop-speed) + +Timer is not increased when the player is hit or rescued (during animation). + +It is decreased (not below 0 obviously) when a player drives in correct direction with at least given speed (troll-min-normal-speed). + +If a player's timer exceeds the warning level (troll-warning-time), they get a warning (troll-warn-message). After that the timer is reset. +If a player got a warning and their timer exceeds the kick level (troll-kick-time), they get kicked. +Warnings and Kicks are logged. + +Config can be controlled in xml file like this: + + + + + + + + + + + + + + + +### Things to note +* The system can be fooled of course, but it should be a lot harder to troll. Testing would be necessary. However, when I set up a test server, most players coming by just wanted to play normally... +* The system should not warn or kick weak players who get lost or stuck on obstacles (too quickly). The current configuration values are most probably not yet perfect. +* Players should probably be informed about the system, because waiting for others (like some pros do when giving weaker players some advice or driving lessons) would be punished, so the system should not be activated in those cases. +* If a player presses UP-key early, the timer is increased during time punishment at the beginning of the race (1 sec). I don't know how to find out if a player is in that state. +* **There may still be bugs** (of course)... ;) diff --git a/README.md b/README.md index 7042b81d9eb..1a71d4f410a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # SuperTuxKart -[![Linux build status](https://github.com/supertuxkart/stk-code/actions/workflows/linux.yml/badge.svg)](https://github.com/supertuxkart/stk-code/actions/workflows/linux.yml) -[![Apple build status](https://github.com/supertuxkart/stk-code/actions/workflows/apple.yml/badge.svg)](https://github.com/supertuxkart/stk-code/actions/workflows/apple.yml) -[![Windows build status](https://github.com/supertuxkart/stk-code/actions/workflows/windows.yml/badge.svg)](https://github.com/supertuxkart/stk-code/actions/workflows/windows.yml) -[![Switch build status](https://github.com/supertuxkart/stk-code/actions/workflows/switch.yml/badge.svg)](https://github.com/supertuxkart/stk-code/actions/workflows/switch.yml) +[![Linux build status](https://github.com/kimden/stk-code/actions/workflows/linux.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/linux.yml) +[![Apple build status](https://github.com/kimden/stk-code/actions/workflows/apple.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/apple.yml) +[![Windows build status](https://github.com/kimden/stk-code/actions/workflows/windows.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/windows.yml) +[![Switch build status](https://github.com/kimden/stk-code/actions/workflows/switch.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/switch.yml) [![#supertuxkart on the libera IRC network](https://img.shields.io/badge/libera-%23supertuxkart-brightgreen.svg)](https://web.libera.chat/?channels=#supertuxkart) SuperTuxKart is a free kart racing game. It focuses on fun and not on realistic kart physics. Instructions can be found on the in-game help page. @@ -39,45 +39,8 @@ The export utilities perform the needed transformation, so in Blender you just ## Building from source -Building instructions can be found in [`INSTALL.md`](/INSTALL.md) - -## Info on experimental anti-troll system -If activated, a timer is kept for all players. System can be activated in xml config or in the lobby with command: -\admin troll [0,1] - -Timer is increased by the amount of time when -* a player drives in the wrong way -* a player moves below a given speed (troll-max-stop-speed) - -Timer is not increased when the player is hit or rescued (during animation). - -It is decreased (not below 0 obviously) when a player drives in correct direction with at least given speed (troll-min-normal-speed). - -If a player's timer exceeds the warning level (troll-warning-time), they get a warning (troll-warn-message). After that the timer is reset. -If a player got a warning and their timer exceeds the kick level (troll-kick-time), they get kicked. -Warnings and Kicks are logged. - -Config can be controlled in xml file like this: - - - - - - - - - - - - - - - -### Things to note -* The system can be fooled of course, but it should be a lot harder to troll. Testing would be necessary. However, when I set up a test server, most players coming by just wanted to play normally... -* The system should not warn or kick weak players who get lost or stuck on obstacles (too quickly). The current configuration values are most probably not yet perfect. -* Players should probably be informed about the system, because waiting for others (like some pros do when giving weaker players some advice or driving lessons) would be punished, so the system should not be activated in those cases. -* If a player presses UP-key early, the timer is increased during time punishment at the beginning of the race (1 sec). I don't know how to find out if a player is in that state. -* **There may still be bugs** (of course)... ;) +Building instructions can be found in [`INSTALL.md`](/INSTALL.md). + +## Additional guides + +Info on experimental anti-troll system can be found in [`ANTI_TROLL.md`](/ANTI_TROLL.md). \ No newline at end of file From 005d0b1dcefc02d0047b9a44c57d7f47456c7ea8 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 1 Sep 2021 14:59:50 +0300 Subject: [PATCH 127/830] Speed up getRecord() --- src/network/protocols/server_lobby.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 71b3c44092a..b77e512c09b 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -8946,14 +8946,9 @@ std::string ServerLobby::getRecord(std::string& track, std::string& mode, if (!records_table_name.empty()) { std::string get_query = StringUtils::insertValues("SELECT username, " - "result FROM %s LEFT JOIN " - "(SELECT venue as v, reverse as r, mode as m, laps as l, " - "min(result) as min_res FROM %s group by v, r, m, l) " - "ON venue = v and reverse = r and mode = m and laps = l " - "WHERE venue = ? and reverse = '%s' " - "and mode = '%s' and laps = %d and result = min_res;", - records_table_name.c_str(), records_table_name.c_str(), - direction.c_str(), mode.c_str(), + "result FROM '%s' WHERE venue = ? and reverse = '%s' " + "and mode = '%s' and laps = %d order by result asc, time asc limit 1;", + records_table_name.c_str(), direction.c_str(), mode.c_str(), laps); auto ret = vectorSQLQuery(get_query, 2, [track](sqlite3_stmt* stmt) From 6edbd8b22a6fdb650f21691f3da6ed825c1c8aed Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 1 Sep 2021 17:51:08 +0300 Subject: [PATCH 128/830] Also speed up retrieving records in storeResults() --- src/network/protocols/server_lobby.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index b77e512c09b..fa204b6a0b5 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -8213,15 +8213,9 @@ void ServerLobby::storeResults() if (!records_table_name.empty()) { std::string get_query = StringUtils::insertValues("SELECT username, " - "result FROM %s INNER JOIN " - "(SELECT venue as v, reverse as r, mode as m, laps as l, " - "min(result) as min_res FROM %s group by v, r, m, l) " - "ON venue = v and reverse = r and mode = m and laps = l " - "and result = min_res " - "WHERE venue = '%s' and reverse = '%s' " - "and mode = '%s' and laps = %d;", - records_table_name.c_str(), records_table_name.c_str(), - track_name.c_str(), reverse_string.c_str(), mode_name.c_str(), + "result FROM '%s' WHERE venue = '%s' and reverse = '%s' " + "and mode = '%s' and laps = %d order by result asc, time asc limit 1;", + records_table_name.c_str(), track_name.c_str(), reverse_string.c_str(), mode_name.c_str(), laps_number); auto ret = vectorSQLQuery(get_query, 2); record_fetched = ret.first; From 7182b9d7128325dcbbc63225734ed18dfd26dc97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Eichler?= <2162327+heuchi@users.noreply.github.com> Date: Fri, 3 Sep 2021 11:55:24 +0200 Subject: [PATCH 129/830] Team-GP: announce and/or punish teammate hits (#4) * Two new options for team GPs: 1) Send a message to everybody when a player makes a teammate explode or flattened 2) Punish players for hitting teammates (with cakes, bowls, swatter) * refactored teammate hit system to mostly work inside ServerLobby * fixed refactored teammate hit system: - only punish/announce hits when victim hasn't already finished the race - fixed punishment of deshielding (for cakes and bowls) - added a state flag to avoid collecting victims when not needed * added configuration option: set prefix for teammate hit messages --- src/items/bowling.cpp | 11 ++ src/items/cake.cpp | 11 ++ src/items/swatter.cpp | 16 ++ src/items/swatter.hpp | 2 + src/karts/explosion_animation.cpp | 5 + src/network/protocols/server_lobby.cpp | 264 ++++++++++++++++++++++++- src/network/protocols/server_lobby.hpp | 40 ++++ src/network/server_config.hpp | 13 ++ 8 files changed, 359 insertions(+), 3 deletions(-) diff --git a/src/items/bowling.cpp b/src/items/bowling.cpp index 39c28ce31a7..f888b2e5413 100644 --- a/src/items/bowling.cpp +++ b/src/items/bowling.cpp @@ -26,6 +26,8 @@ #include "karts/abstract_kart.hpp" #include "modes/linear_world.hpp" +#include "network/protocols/server_lobby.hpp" + #include "utils/log.hpp" //TODO: remove after debugging is done float Bowling::m_st_max_distance; // maximum distance for a bowling ball to be attracted @@ -154,12 +156,20 @@ bool Bowling::updateAndDelete(int ticks) */ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) { + auto sl = LobbyProtocol::get(); + if (sl) sl->setTeamMateHitOwner(getOwnerId(),m_ticks_since_thrown); + bool was_real_hit = Flyable::hit(kart, obj); if(was_real_hit) { if(kart && kart->isShielded()) { kart->decreaseShieldTime(); + if (sl) + { + sl->registerTeamMateHit(kart->getWorldKartId()); + sl->handleTeamMateHits(); + } return true; } else @@ -168,6 +178,7 @@ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) explode(kart, obj, /*hit_secondary*/false); } } + if (sl) sl->handleTeamMateHits(); return was_real_hit; } // hit diff --git a/src/items/cake.cpp b/src/items/cake.cpp index 4195625f7bd..fb4d57000b2 100644 --- a/src/items/cake.cpp +++ b/src/items/cake.cpp @@ -26,6 +26,8 @@ #include "utils/constants.hpp" #include "utils/random_generator.hpp" +#include "network/protocols/server_lobby.hpp" + #include "utils/log.hpp" //TODO: remove after debugging is done float Cake::m_st_max_distance_squared; @@ -63,17 +65,26 @@ void Cake::init(const XMLNode &node, scene::IMesh *cake_model) */ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj) { + auto sl = LobbyProtocol::get(); + if (sl) sl->setTeamMateHitOwner(getOwnerId()); + bool was_real_hit = Flyable::hit(kart, obj); if(was_real_hit) { if(kart && kart->isShielded()) { kart->decreaseShieldTime(); + if (sl) + { + sl->registerTeamMateHit(kart->getWorldKartId()); + sl->handleTeamMateHits(); + } return false; //Not sure if a shield hit is a real hit. } explode(kart, obj); } + if (sl) sl->handleTeamMateHits(); return was_real_hit; } // hit diff --git a/src/items/swatter.cpp b/src/items/swatter.cpp index dabf8ec9d60..ec3bafc28bf 100644 --- a/src/items/swatter.cpp +++ b/src/items/swatter.cpp @@ -43,6 +43,8 @@ #include "network/network_string.hpp" #include "network/rewind_manager.hpp" +#include "network/protocols/server_lobby.hpp" + #define SWAT_POS_OFFSET core::vector3df(0.0, 0.2f, -0.4f) #define SWAT_ANGLE_MIN 45 #define SWAT_ANGLE_MAX 135 @@ -65,6 +67,8 @@ Swatter::Swatter(AbstractKart *kart, int16_t bomb_ticks, int ticks, m_animation_phase = SWATTER_AIMING; m_discard_now = false; m_closest_kart = NULL; + m_has_hit_kart = false; + m_created_ticks = World::getWorld()->getTicksSinceStart(); m_discard_ticks = World::getWorld()->getTicksSinceStart() + ticks; m_bomb_remaining = bomb_ticks; m_scene_node = NULL; @@ -396,10 +400,21 @@ void Swatter::squashThingsAround() float slowdown = kp->getSwatterSquashSlowdown(); // The squash attempt may fail because of invulnerability, shield, etc. // Making a bomb explode counts as a success + bool wasHit = !m_closest_kart->isInvulnerable() && !m_closest_kart->getKartAnimation(); bool success = m_closest_kart->setSquash(duration, slowdown); const bool has_created_explosion_animation = success && m_closest_kart->getKartAnimation() != NULL; + // we can't use success here, because unshielding a kart is not considered a succes + // punishment system however, does consider it a hit + if (wasHit) + { + // check if we are in team gp and hit a teammate and should punish attacker + auto sl = LobbyProtocol::get(); + if (sl && !m_closest_kart->hasFinishedRace()) + sl->handleSwatterHit(m_kart->getWorldKartId(), m_closest_kart->getWorldKartId(), success, m_has_hit_kart, + World::getWorld()->getTicksSinceStart() - m_created_ticks); + } if (success) { World::getWorld()->kartHit(m_closest_kart->getWorldKartId(), @@ -424,6 +439,7 @@ void Swatter::squashThingsAround() PlayerManager::increaseAchievement(AchievementsStatus::ALL_HITS_1RACE, 1); } } + m_has_hit_kart = true; } if (!GUIEngine::isNoGraphics() && has_created_explosion_animation && diff --git a/src/items/swatter.hpp b/src/items/swatter.hpp index f3c11cfcea7..e25c2755ad0 100644 --- a/src/items/swatter.hpp +++ b/src/items/swatter.hpp @@ -72,6 +72,8 @@ class Swatter : public NoCopy, public AttachmentPlugin scene::IAnimatedMeshSceneNode *m_bomb_scene_node; int m_discard_ticks; + int m_created_ticks; + bool m_has_hit_kart; int m_swatter_duration; diff --git a/src/karts/explosion_animation.cpp b/src/karts/explosion_animation.cpp index d3e09aa5756..1f39955dc7a 100644 --- a/src/karts/explosion_animation.cpp +++ b/src/karts/explosion_animation.cpp @@ -28,6 +28,7 @@ #include "modes/follow_the_leader.hpp" #include "network/network_string.hpp" #include "network/protocols/client_lobby.hpp" +#include "network/protocols/server_lobby.hpp" #include "race/race_manager.hpp" #include "tracks/track.hpp" #include "utils/mini_glm.hpp" @@ -55,9 +56,12 @@ ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart, // Ignore explosion that are too far away. if(!direct_hit && pos.distance2(kart->getXYZ())>r*r) return NULL; + auto sl = LobbyProtocol::get(); + if(kart->isShielded()) { kart->decreaseShieldTime(); + if (sl) sl->registerTeamMateHit(kart->getWorldKartId()); return NULL; } @@ -69,6 +73,7 @@ ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart, ftl_world->leaderHit(); } + if (sl) sl->registerTeamMateExplode(kart->getWorldKartId()); return new ExplosionAnimation(kart, direct_hit); } // create diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index fa204b6a0b5..5d7eefad8b5 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -22,7 +22,7 @@ #include "config/user_config.hpp" #include "items/network_item_manager.hpp" #include "items/powerup_manager.hpp" -#include "karts/abstract_kart.hpp" +#include "items/attachment.hpp" #include "karts/controller/player_controller.hpp" #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" @@ -249,6 +249,12 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_troll_active = ServerConfig::m_troll_active; + m_show_teammate_hits = ServerConfig::m_show_teammate_hits; + m_teammate_hit_mode = ServerConfig::m_teammate_hit_mode; + m_last_teammate_hit_msg = 0; + m_teammate_swatter_punish.clear(); + m_collecting_teammate_hit_info = false; + initAvailableModes(); std::vector all_k = @@ -801,6 +807,7 @@ void ServerLobby::setup() m_winner_peer_id = 0; m_client_starting_time = 0; m_ai_count = 0; + m_collecting_teammate_hit_info = false; auto players = STKHost::get()->getPlayersForNewGame(); if (m_game_setup->isGrandPrix() && !m_game_setup->isGrandPrixStarted()) { @@ -1802,6 +1809,10 @@ void ServerLobby::asynchronousUpdate() // For WAIT_FOR_WORLD_LOADED and SELECTING make sure there are enough // players to start next game, otherwise exiting and let main thread // reset + + // maybe this is not the best place for this? + m_last_teammate_hit_msg = 0; + if (m_end_voting_period.load() == 0) return; @@ -2463,6 +2474,16 @@ void ServerLobby::update(int ticks) } } } + if (m_teammate_swatter_punish.size() > 0) + { + // punish players who swattered teammates + for (auto kart : m_teammate_swatter_punish) + { + kart->getAttachment()->set(Attachment::ATTACH_ANVIL,stk_config->time2Ticks(kart->getKartProperties()->getAnvilDuration())); + kart->adjustSpeed(kart->getKartProperties()->getAnvilSpeedFactor()); + } + m_teammate_swatter_punish.clear(); + } } } if (w) @@ -7781,10 +7802,50 @@ void ServerLobby::handleServerCommand(Event* event, sendStringToPeer(msg, peer); return; } + if (argv[1] == "hitmsg") + { + if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) + { + msg = "Usage: /admin hitmsg [0/1] - disable or enable messages if a player makes a teammate explode"; + sendStringToPeer(msg, peer); + return; + } + if (argv[2] == "0") + { + m_show_teammate_hits = false; + msg = "Teammate hits will not be send"; + } else { + m_show_teammate_hits = true; + msg = "Teammate hits will be send to all players"; + } + sendStringToPeer(msg, peer); + return; + } + if (argv[1] == "teamhit") + { + if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) + { + msg = "Usage: /admin teamhit [0/1] - disable or enable punish mode when hitting team mates"; + sendStringToPeer(msg, peer); + return; + } + if (argv[2] == "0") + { + m_teammate_hit_mode = false; + msg = "Normal mode"; + } + else + { + m_teammate_hit_mode = true; + msg = "Teammate hits get punished"; + } + sendStringToPeer(msg, peer); + return; + } } else if (argv[0] == "version") { - std::string msg = "1.2-kimden 210621 beta"; + std::string msg = "1.2-kimden 210903 beta"; sendStringToPeer(msg, peer); } else if (argv[0] == "clear") @@ -9035,5 +9096,202 @@ std::string ServerLobby::getToken() return token; } // getToken //----------------------------------------------------------------------------- - #endif // ENABLE_WEB_SUPPORT + +// this is called when collisions of an item are handled +// so we keep track of hits caused by that item +void ServerLobby::setTeamMateHitOwner(unsigned int ownerID, uint16_t ticks_since_thrown) +{ + m_teammate_current_item_ownerID = ownerID; + m_teammate_ticks_since_thrown = ticks_since_thrown; + m_teammate_karts_hit.clear(); + m_teammate_karts_exploded.clear(); + m_collecting_teammate_hit_info = true; +} + +void ServerLobby::registerTeamMateHit(unsigned int kartID) +{ + // only register if we know the item owner and victim is still racing + if (m_collecting_teammate_hit_info && !World::getWorld()->getKart(kartID)->hasFinishedRace()) + m_teammate_karts_hit.push_back(kartID); +} + +void ServerLobby::registerTeamMateExplode(unsigned int kartID) +{ + // only register if we know the item owner and victim is still racing + if (m_collecting_teammate_hit_info && !World::getWorld()->getKart(kartID)->hasFinishedRace()) + m_teammate_karts_exploded.push_back(kartID); +} + +void ServerLobby::sendTeamMateHitMsg(std::string& s) +{ + if (World* w = World::getWorld()) + { + int ticks = w->getTicksSinceStart(); + if (ticks - m_last_teammate_hit_msg > stk_config->time2Ticks(1.5f)) + { + m_last_teammate_hit_msg = ticks; + sendStringToAllPeers(s); + } + } +} + +void ServerLobby::handleTeamMateHits() +{ + m_collecting_teammate_hit_info = false; + // get team of owner of item + const std::string ownername = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_current_item_ownerID).getPlayerName()); + const int ownerTeam = m_team_for_player[ownername]; + + if (ownerTeam == 0) // no team, no punishment + return; + + AbstractKart *owner = World::getWorld()->getKart(m_teammate_current_item_ownerID); + + // if item is too old, it doesn't count + // currently only bowling balls have their creation time registered + // so cakes will always count + + if (m_teammate_ticks_since_thrown > stk_config->time2Ticks(MAX_BOWL_TEAMMATE_HIT_TIME)) + return; + + // Show message? + if (showTeamMateHits()) + { + // prepare string + int num_victims = 0; + std::string msg = ServerConfig::m_teammate_hit_msg_prefix; + std::string victims; + msg+=ownername; + msg+=" just shot "; + + for (unsigned int i=0; i < m_teammate_karts_exploded.size(); i++) + { + const std::string playername = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); + const int playerTeam = m_team_for_player[playername]; + if (ownerTeam == playerTeam) + { + // hit teammate + if (num_victims > 0) + victims+=" and "; + victims+=StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); + num_victims++; + } + } + if (num_victims > 0) // we found victims, so send message + { + msg += (num_victims > 1) ? "teammates " : "teammate "; + msg += victims; + sendTeamMateHitMsg(msg); + } + } + + if (useTeamMateHitMode()) + { + bool punished = false; + // first check if we exploded at least one teammate + for (unsigned int i=0; i < m_teammate_karts_exploded.size() && !punished; i++) + { + const std::string playername = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); + const int playerTeam = m_team_for_player[playername]; + if (ownerTeam == playerTeam) + { + // we did, so punish + punished = true; + if(owner->getAttachment()->getType()==Attachment::ATTACH_BOMB) + { + // make bomb explode + owner->getAttachment()->update(10000); + } + else if(owner->isShielded()) + { + // if owner is shielded, take away shield + owner->decreaseShieldTime(); + } + else + { + int left_over_ticks = 0; + // if owner already has an anvil or a parachute, make new anvil last longer + if (owner->getAttachment()->getType()==Attachment::ATTACH_ANVIL + || owner->getAttachment()->getType()==Attachment::ATTACH_PARACHUTE) + { + left_over_ticks = owner->getAttachment()->getTicksLeft(); + } + owner->getAttachment()->set(Attachment::ATTACH_ANVIL, + stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) + left_over_ticks); + owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor()); + } + } + } + + // now check for deshielding teammates + for (unsigned int i=0; i < m_teammate_karts_hit.size() && !punished; i++) + { + const std::string playername = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_karts_hit[i]).getPlayerName()); + const int playerTeam = m_team_for_player[playername]; + if (ownerTeam == playerTeam) + { + // we did, so punish + punished = true; + if(owner->getAttachment()->getType()==Attachment::ATTACH_BOMB) + { + // make bomb explode + owner->getAttachment()->update(10000); + } + else if(owner->isShielded()) + { + // if owner is shielded, take away shield + owner->decreaseShieldTime(); + } + else + { + // since teammate didn't explode, make anvil less severe + int left_over_ticks = 0; + // if owner already has an anvil or a parachute, make new anvil last longer + if (owner->getAttachment()->getType()==Attachment::ATTACH_ANVIL + || owner->getAttachment()->getType()==Attachment::ATTACH_PARACHUTE) + { + left_over_ticks = owner->getAttachment()->getTicksLeft(); + } + owner->getAttachment()->set(Attachment::ATTACH_ANVIL, + stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) / 2 + left_over_ticks); + owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor() * 2.0f); + } + } + } + } +} + +void ServerLobby::handleSwatterHit(unsigned int ownerID, unsigned int victimID, bool success, bool has_hit_kart, uint16_t ticks_active) +{ + const std::string ownername = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(ownerID).getPlayerName()); + const int ownerTeam = m_team_for_player[ownername]; + if (ownerTeam == 0) + return; + + const std::string victimname = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(victimID).getPlayerName()); + const int victimTeam = m_team_for_player[victimname]; + if (victimTeam != ownerTeam) + return; + + // should we tell the world? + if (showTeamMateHits() && success) + { + std::string msg = ServerConfig::m_teammate_hit_msg_prefix; + msg+=ownername; + msg+=" just swattered teammate "; + msg+=victimname; + sendTeamMateHitMsg(msg); + } + if (useTeamMateHitMode()) + { + // remove swatter + AbstractKart *owner = World::getWorld()->getKart(ownerID); + owner->getAttachment()->setTicksLeft(0); + // if this is the first kart hit and the swatter is in use for less than 3s + // the attacker also gets an anvil + if (!has_hit_kart && ticks_active < stk_config->time2Ticks(3.0f) && success) + // we cannot do this here, will be done in update() + m_teammate_swatter_punish.push_back(owner); + } +} diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index dfd3e3bd9d5..33e8743a5c2 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -24,6 +24,7 @@ #include "utils/time.hpp" #include "utils/track_filter.hpp" #include "utils/kart_elimination.hpp" +#include "karts/controller/player_controller.hpp" #include "irrString.h" @@ -392,6 +393,31 @@ class ServerLobby : public LobbyProtocol // config for troll system bool m_troll_active; + // teammate hits + // show messages about team hits? + bool m_show_teammate_hits; + // give anvils to attackers? + bool m_teammate_hit_mode; + // time index of last team mate hit + // make sure not to send too many of them + int m_last_teammate_hit_msg; + // we have to keep track of the karts affected by a hit + // we store IDs, because we need to find the team by name (by ID) + // m_collecting_teammate_hit_info is set to true if we are processing a + // cake or bowl hit, so we make sure we never fill the vectors with + // unneeded data. + bool m_collecting_teammate_hit_info; + unsigned int m_teammate_current_item_ownerID; + uint16_t m_teammate_ticks_since_thrown; + std::vector m_teammate_karts_hit; + std::vector m_teammate_karts_exploded; + // store karts to punish for swattering a teammate + std::vector m_teammate_swatter_punish; + + // after a certain time a bowl can be avoided and doesn't + // trigger teammate hits anymore + const float MAX_BOWL_TEAMMATE_HIT_TIME = 2.0f; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); @@ -534,6 +560,7 @@ class ServerLobby : public LobbyProtocol bool tournamentGoalsLimit(int game) const; bool tournamentColorsSwapped(int game) const; void updateTournamentRole(STKPeer* peer); + // bool tournamentHasIcy(int game) const; #ifdef ENABLE_WEB_SUPPORT void loadAllTokens(); @@ -592,6 +619,19 @@ class ServerLobby : public LobbyProtocol std::string getRecord(std::string& track, std::string& mode, std::string& direction, int laps); #endif + + // handle cakes and bowls + void setTeamMateHitOwner(unsigned int ownerID, uint16_t ticks_since_thrown = 0); + void registerTeamMateHit(unsigned int kartID); + void registerTeamMateExplode(unsigned int kartID); + void handleTeamMateHits(); + + // handle swatters + void handleSwatterHit(unsigned int ownerID, unsigned int victimID, bool success, bool has_hit_kart, uint16_t ticks_active); + + void sendTeamMateHitMsg(std::string& s); + bool showTeamMateHits() const { return m_show_teammate_hits; } + bool useTeamMateHitMode() const { return m_teammate_hit_mode; } }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index f664263e3fa..ffe8dfeb374 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -295,6 +295,19 @@ namespace ServerConfig SERVER_CFG_DEFAULT(FloatServerConfigParam(5.0f, "troll-max-stop-speed", "A player going slower than this is considered stopping.")); + SERVER_CFG_PREFIX BoolServerConfigParam m_show_teammate_hits + SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "show-teammate-hits", + "If this value is set to true, a message is send to everybody if a player makes a teammate explode.")); + + SERVER_CFG_PREFIX BoolServerConfigParam m_teammate_hit_mode + SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "teammate-hit-mode", + "Punish teammate hits? If set to true players get an anvil when they hit teammates.")); + + SERVER_CFG_PREFIX StringServerConfigParam m_teammate_hit_msg_prefix + SERVER_CFG_DEFAULT(StringServerConfigParam("LOL: ", + "teammate-hit-msg-prefix", + "This string is the prefix for the messages if players hit teammates. (Make sure it ends with a whitespace if non-empty.)")); + SERVER_CFG_PREFIX IntServerConfigParam m_min_start_game_players SERVER_CFG_DEFAULT(IntServerConfigParam(2, "min-start-game-players", "Only auto start kart selection when number of " From 7005abe5567a8cf59d898268e58b9a2c1001abb2 Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 3 Sep 2021 13:18:10 +0300 Subject: [PATCH 130/830] Fix formatting a bit, send team-gp-punishment-mode-changing message to everyone --- src/items/bowling.cpp | 10 ++-- src/items/cake.cpp | 10 ++-- src/items/swatter.cpp | 5 +- src/karts/explosion_animation.cpp | 6 +- src/network/protocols/server_lobby.cpp | 76 ++++++++++++++------------ 5 files changed, 61 insertions(+), 46 deletions(-) diff --git a/src/items/bowling.cpp b/src/items/bowling.cpp index f888b2e5413..639764d0033 100644 --- a/src/items/bowling.cpp +++ b/src/items/bowling.cpp @@ -157,12 +157,13 @@ bool Bowling::updateAndDelete(int ticks) bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) { auto sl = LobbyProtocol::get(); - if (sl) sl->setTeamMateHitOwner(getOwnerId(),m_ticks_since_thrown); + if (sl) + sl->setTeamMateHitOwner(getOwnerId(),m_ticks_since_thrown); bool was_real_hit = Flyable::hit(kart, obj); - if(was_real_hit) + if (was_real_hit) { - if(kart && kart->isShielded()) + if (kart && kart->isShielded()) { kart->decreaseShieldTime(); if (sl) @@ -178,7 +179,8 @@ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) explode(kart, obj, /*hit_secondary*/false); } } - if (sl) sl->handleTeamMateHits(); + if (sl) + sl->handleTeamMateHits(); return was_real_hit; } // hit diff --git a/src/items/cake.cpp b/src/items/cake.cpp index fb4d57000b2..6e095c9dc66 100644 --- a/src/items/cake.cpp +++ b/src/items/cake.cpp @@ -66,12 +66,13 @@ void Cake::init(const XMLNode &node, scene::IMesh *cake_model) bool Cake::hit(AbstractKart* kart, PhysicalObject* obj) { auto sl = LobbyProtocol::get(); - if (sl) sl->setTeamMateHitOwner(getOwnerId()); + if (sl) + sl->setTeamMateHitOwner(getOwnerId()); bool was_real_hit = Flyable::hit(kart, obj); - if(was_real_hit) + if (was_real_hit) { - if(kart && kart->isShielded()) + if (kart && kart->isShielded()) { kart->decreaseShieldTime(); if (sl) @@ -84,7 +85,8 @@ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj) explode(kart, obj); } - if (sl) sl->handleTeamMateHits(); + if (sl) + sl->handleTeamMateHits(); return was_real_hit; } // hit diff --git a/src/items/swatter.cpp b/src/items/swatter.cpp index ec3bafc28bf..e7ced836672 100644 --- a/src/items/swatter.cpp +++ b/src/items/swatter.cpp @@ -412,8 +412,9 @@ void Swatter::squashThingsAround() // check if we are in team gp and hit a teammate and should punish attacker auto sl = LobbyProtocol::get(); if (sl && !m_closest_kart->hasFinishedRace()) - sl->handleSwatterHit(m_kart->getWorldKartId(), m_closest_kart->getWorldKartId(), success, m_has_hit_kart, - World::getWorld()->getTicksSinceStart() - m_created_ticks); + sl->handleSwatterHit(m_kart->getWorldKartId(), + m_closest_kart->getWorldKartId(), success, m_has_hit_kart, + World::getWorld()->getTicksSinceStart() - m_created_ticks); } if (success) { diff --git a/src/karts/explosion_animation.cpp b/src/karts/explosion_animation.cpp index 1f39955dc7a..8b8040297fd 100644 --- a/src/karts/explosion_animation.cpp +++ b/src/karts/explosion_animation.cpp @@ -61,7 +61,8 @@ ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart, if(kart->isShielded()) { kart->decreaseShieldTime(); - if (sl) sl->registerTeamMateHit(kart->getWorldKartId()); + if (sl) + sl->registerTeamMateHit(kart->getWorldKartId()); return NULL; } @@ -73,7 +74,8 @@ ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart, ftl_world->leaderHit(); } - if (sl) sl->registerTeamMateExplode(kart->getWorldKartId()); + if (sl) + sl->registerTeamMateExplode(kart->getWorldKartId()); return new ExplosionAnimation(kart, direct_hit); } // create diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 5d7eefad8b5..2b724f63d7d 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2477,9 +2477,10 @@ void ServerLobby::update(int ticks) if (m_teammate_swatter_punish.size() > 0) { // punish players who swattered teammates - for (auto kart : m_teammate_swatter_punish) + for (auto& kart : m_teammate_swatter_punish) { - kart->getAttachment()->set(Attachment::ATTACH_ANVIL,stk_config->time2Ticks(kart->getKartProperties()->getAnvilDuration())); + kart->getAttachment()->set(Attachment::ATTACH_ANVIL, + stk_config->time2Ticks(kart->getKartProperties()->getAnvilDuration())); kart->adjustSpeed(kart->getKartProperties()->getAnvilSpeedFactor()); } m_teammate_swatter_punish.clear(); @@ -7813,12 +7814,12 @@ void ServerLobby::handleServerCommand(Event* event, if (argv[2] == "0") { m_show_teammate_hits = false; - msg = "Teammate hits will not be send"; + msg = "Teammate hits will not be sent"; } else { m_show_teammate_hits = true; - msg = "Teammate hits will be send to all players"; + msg = "Teammate hits will be sent to all players"; } - sendStringToPeer(msg, peer); + sendStringToAllPeers(msg); return; } if (argv[1] == "teamhit") @@ -7832,14 +7833,14 @@ void ServerLobby::handleServerCommand(Event* event, if (argv[2] == "0") { m_teammate_hit_mode = false; - msg = "Normal mode"; + msg = "Teammate hits are not punished now"; } else { m_teammate_hit_mode = true; - msg = "Teammate hits get punished"; + msg = "Teammate hits are punished now"; } - sendStringToPeer(msg, peer); + sendStringToAllPeers(msg); return; } } @@ -9140,7 +9141,8 @@ void ServerLobby::handleTeamMateHits() { m_collecting_teammate_hit_info = false; // get team of owner of item - const std::string ownername = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_current_item_ownerID).getPlayerName()); + const std::string ownername = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(m_teammate_current_item_ownerID).getPlayerName()); const int ownerTeam = m_team_for_player[ownername]; if (ownerTeam == 0) // no team, no punishment @@ -9162,19 +9164,20 @@ void ServerLobby::handleTeamMateHits() int num_victims = 0; std::string msg = ServerConfig::m_teammate_hit_msg_prefix; std::string victims; - msg+=ownername; - msg+=" just shot "; + msg += ownername; + msg += " just shot "; - for (unsigned int i=0; i < m_teammate_karts_exploded.size(); i++) + for (unsigned int i = 0; i < m_teammate_karts_exploded.size(); i++) { - const std::string playername = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); + const std::string playername = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); const int playerTeam = m_team_for_player[playername]; if (ownerTeam == playerTeam) { // hit teammate if (num_victims > 0) - victims+=" and "; - victims+=StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); + victims += " and "; + victims += StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); num_victims++; } } @@ -9192,18 +9195,19 @@ void ServerLobby::handleTeamMateHits() // first check if we exploded at least one teammate for (unsigned int i=0; i < m_teammate_karts_exploded.size() && !punished; i++) { - const std::string playername = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); + const std::string playername = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); const int playerTeam = m_team_for_player[playername]; if (ownerTeam == playerTeam) { // we did, so punish punished = true; - if(owner->getAttachment()->getType()==Attachment::ATTACH_BOMB) + if(owner->getAttachment()->getType() == Attachment::ATTACH_BOMB) { // make bomb explode owner->getAttachment()->update(10000); } - else if(owner->isShielded()) + else if (owner->isShielded()) { // if owner is shielded, take away shield owner->decreaseShieldTime(); @@ -9212,33 +9216,34 @@ void ServerLobby::handleTeamMateHits() { int left_over_ticks = 0; // if owner already has an anvil or a parachute, make new anvil last longer - if (owner->getAttachment()->getType()==Attachment::ATTACH_ANVIL - || owner->getAttachment()->getType()==Attachment::ATTACH_PARACHUTE) + if (owner->getAttachment()->getType() == Attachment::ATTACH_ANVIL + || owner->getAttachment()->getType() == Attachment::ATTACH_PARACHUTE) { left_over_ticks = owner->getAttachment()->getTicksLeft(); } owner->getAttachment()->set(Attachment::ATTACH_ANVIL, - stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) + left_over_ticks); + stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) + left_over_ticks); owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor()); } } } // now check for deshielding teammates - for (unsigned int i=0; i < m_teammate_karts_hit.size() && !punished; i++) + for (unsigned int i = 0; i < m_teammate_karts_hit.size() && !punished; i++) { - const std::string playername = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_karts_hit[i]).getPlayerName()); + const std::string playername = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(m_teammate_karts_hit[i]).getPlayerName()); const int playerTeam = m_team_for_player[playername]; if (ownerTeam == playerTeam) { // we did, so punish punished = true; - if(owner->getAttachment()->getType()==Attachment::ATTACH_BOMB) + if (owner->getAttachment()->getType() == Attachment::ATTACH_BOMB) { // make bomb explode owner->getAttachment()->update(10000); } - else if(owner->isShielded()) + else if (owner->isShielded()) { // if owner is shielded, take away shield owner->decreaseShieldTime(); @@ -9248,13 +9253,13 @@ void ServerLobby::handleTeamMateHits() // since teammate didn't explode, make anvil less severe int left_over_ticks = 0; // if owner already has an anvil or a parachute, make new anvil last longer - if (owner->getAttachment()->getType()==Attachment::ATTACH_ANVIL - || owner->getAttachment()->getType()==Attachment::ATTACH_PARACHUTE) + if (owner->getAttachment()->getType() == Attachment::ATTACH_ANVIL + || owner->getAttachment()->getType() == Attachment::ATTACH_PARACHUTE) { left_over_ticks = owner->getAttachment()->getTicksLeft(); } owner->getAttachment()->set(Attachment::ATTACH_ANVIL, - stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) / 2 + left_over_ticks); + stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) / 2 + left_over_ticks); owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor() * 2.0f); } } @@ -9262,14 +9267,17 @@ void ServerLobby::handleTeamMateHits() } } -void ServerLobby::handleSwatterHit(unsigned int ownerID, unsigned int victimID, bool success, bool has_hit_kart, uint16_t ticks_active) +void ServerLobby::handleSwatterHit(unsigned int ownerID, unsigned int victimID, + bool success, bool has_hit_kart, uint16_t ticks_active) { - const std::string ownername = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(ownerID).getPlayerName()); + const std::string ownername = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(ownerID).getPlayerName()); const int ownerTeam = m_team_for_player[ownername]; if (ownerTeam == 0) return; - const std::string victimname = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(victimID).getPlayerName()); + const std::string victimname = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(victimID).getPlayerName()); const int victimTeam = m_team_for_player[victimname]; if (victimTeam != ownerTeam) return; @@ -9278,9 +9286,9 @@ void ServerLobby::handleSwatterHit(unsigned int ownerID, unsigned int victimID, if (showTeamMateHits() && success) { std::string msg = ServerConfig::m_teammate_hit_msg_prefix; - msg+=ownername; - msg+=" just swattered teammate "; - msg+=victimname; + msg += ownername; + msg += " just swattered teammate "; + msg += victimname; sendTeamMateHitMsg(msg); } if (useTeamMateHitMode()) From 00f56c433279248c31ed36ad5dcb902c15b3cce3 Mon Sep 17 00:00:00 2001 From: kimden Date: Fri, 3 Sep 2021 13:24:58 +0300 Subject: [PATCH 131/830] Change version to 1.3-rc1 210903 --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 2b724f63d7d..4962c9ad419 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7846,7 +7846,7 @@ void ServerLobby::handleServerCommand(Event* event, } else if (argv[0] == "version") { - std::string msg = "1.2-kimden 210903 beta"; + std::string msg = "1.3-rc1 k 210903 beta"; sendStringToPeer(msg, peer); } else if (argv[0] == "clear") From 64a451ce99bbca43474d15e2d0c443e19f03ac4b Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 7 Sep 2021 01:22:39 +0300 Subject: [PATCH 132/830] Fix server-only bots crashing on startup --- src/states_screens/online/networking_lobby.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/states_screens/online/networking_lobby.cpp b/src/states_screens/online/networking_lobby.cpp index 9d6d3ba945d..c124d1b08e0 100644 --- a/src/states_screens/online/networking_lobby.cpp +++ b/src/states_screens/online/networking_lobby.cpp @@ -880,6 +880,8 @@ void NetworkingLobby::setStartingTimerTo(float t) // ---------------------------------------------------------------------------- void NetworkingLobby::setHeader(const core::stringw& header) { + if (!m_header) + return; if (m_header->getText() == header) return; m_header_text_width = From 795dba8abb53321d97419e5711a6bcff726c6c68 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 7 Sep 2021 13:17:07 +0300 Subject: [PATCH 133/830] Create a new, yet useless command manager --- src/network/protocols/command_manager.cpp | 93 ++ src/network/protocols/command_manager.hpp | 68 + src/network/protocols/server_lobby.cpp | 1729 +-------------------- src/network/protocols/server_lobby.hpp | 4 + 4 files changed, 170 insertions(+), 1724 deletions(-) create mode 100644 src/network/protocols/command_manager.cpp create mode 100644 src/network/protocols/command_manager.hpp diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp new file mode 100644 index 00000000000..000f37428b5 --- /dev/null +++ b/src/network/protocols/command_manager.cpp @@ -0,0 +1,93 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2021 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "network/protocols/command_manager.hpp" + +#include "addons/addon.hpp" +#include "config/user_config.hpp" +#include "items/network_item_manager.hpp" +#include "items/powerup_manager.hpp" +#include "items/attachment.hpp" +#include "karts/controller/player_controller.hpp" +#include "karts/kart_properties.hpp" +#include "karts/kart_properties_manager.hpp" +#include "karts/official_karts.hpp" +#include "modes/capture_the_flag.hpp" +#include "modes/soccer_world.hpp" +#include "modes/linear_world.hpp" +#include "network/crypto.hpp" +#include "network/event.hpp" +#include "network/game_setup.hpp" +#include "network/network.hpp" +#include "network/network_config.hpp" +#include "network/network_player_profile.hpp" +#include "network/peer_vote.hpp" +#include "network/protocol_manager.hpp" +#include "network/protocols/connect_to_peer.hpp" +#include "network/protocols/game_protocol.hpp" +#include "network/protocols/game_events_protocol.hpp" +#include "network/protocols/server_lobby.hpp" +#include "network/race_event_manager.hpp" +#include "network/server_config.hpp" +#include "network/socket_address.hpp" +#include "network/stk_host.hpp" +#include "network/stk_ipv6.hpp" +#include "network/stk_peer.hpp" +#include "online/online_profile.hpp" +#include "online/request_manager.hpp" +#include "online/xml_request.hpp" +#include "race/race_manager.hpp" +#include "tracks/check_manager.hpp" +#include "tracks/track.hpp" +#include "tracks/track_manager.hpp" +#include "utils/log.hpp" +#include "utils/random_generator.hpp" +#include "utils/string_utils.hpp" +#include "utils/time.hpp" +#include "utils/translation.hpp" + +#include +#include +#include +#include +#include +#include + + +// ======================================================================== + +void CommandManager::initCommands() +{ + m_commands.emplace_back("commands"); +} // initCommands + +// ======================================================================== + +void CommandManager::handleCommand(Event* event, std::shared_ptr peer) +{ + std::string result = ""; + for (const Command& c: m_commands) + { + result += c.m_name + " "; + } + if (!result.empty()) + result.pop_back(); + m_lobby->sendStringToPeer(result, peer); +} // handleCommand + +// ======================================================================== \ No newline at end of file diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp new file mode 100644 index 00000000000..4509e7599ca --- /dev/null +++ b/src/network/protocols/command_manager.hpp @@ -0,0 +1,68 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2021 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef COMMAND_MANAGER_HPP +#define COMMAND_MANAGER_HPP + +#include "irrString.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_SQLITE3 +#include +#endif + +class ServerLobby; +class Event; +class STKPeer; + +class CommandManager { + + struct Command { + std::string m_name; + + Command(std::string name): m_name(name) {} + }; + +private: + + ServerLobby* m_lobby; + + std::vector m_commands; + + void initCommands(); + +public: + + CommandManager(ServerLobby* lobby = nullptr): m_lobby(lobby) { initCommands(); } + + void handleCommand(Event* event, std::shared_ptr peer); + + bool isInitialized() { return m_lobby != nullptr; } +}; + +#endif // COMMAND_MANAGER_HPP \ No newline at end of file diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 4962c9ad419..0683cf54166 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -214,6 +214,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_help_message = getGameSetup()->readOrLoadFromFile ((std::string) ServerConfig::m_help); + m_command_manager = CommandManager(nullptr); + m_available_commands = "admin ban commands config game gnu go help init " "installaddon kick kickban listlocaladdon listserveraddon " "liststkaddon lobby nognu play playeraddonscore playerhasaddon " @@ -6507,1732 +6509,11 @@ bool ServerLobby::checkPeersReady(bool ignore_ai_peer) const void ServerLobby::handleServerCommand(Event* event, std::shared_ptr peer) { - NetworkString& data = event->data(); - std::string language; - data.decodeString(&language); - std::string cmd; - data.decodeString(&cmd); - auto argv = StringUtils::split(cmd, ' '); - if (argv.size() == 0) - return; - if (argv[0] == "replay") - { - if (!ServerConfig::m_owner_less && !hasHostRights(peer)) - { - std::string msg = "You are not server owner"; - sendStringToPeer(msg, peer); - return; - } - if (ServerConfig::m_record_replays) - { - if (argv.size() >= 2 && argv[1] == "0") - m_consent_on_replays = false; - else if (argv.size() >= 2 && argv[1] == "1") - m_consent_on_replays = true; - else - m_consent_on_replays ^= 1; - - std::string msg = "Recording ghost replays is now "; - msg += (m_consent_on_replays ? "on" : "off"); - sendStringToAllPeers(msg); - } - else - { - std::string msg = "This server doesn't allow recording replays"; - sendStringToPeer(msg, peer); - } - } - else if (argv[0] == "start") - { - if (!ServerConfig::m_owner_less && !hasHostRights(peer)) - { - std::string msg = "You are not server owner"; - sendStringToPeer(msg, peer); - return; - } - startSelection(event); - } - else if (argv[0] == "config") - { - if (!hasHostRights(peer)) - { - std::string msg = "You are not server owner"; - sendStringToPeer(msg, peer); - return; - } - int difficulty = getDifficulty(); - int mode = getGameMode(); - bool goal_target = m_game_setup->isSoccerGoalTarget(); - bool gp = false; - for (unsigned i = 1; i < argv.size(); i++) - { - if (argv[i] == "tt" || argv[i] == "time-trial"|| - argv[i] == "trial" || argv[i] == "m4") - mode = 4; - if (argv[i] == "normal" || argv[i] == "normal-race" || - argv[i] == "race" || argv[i] == "m3") - mode = 3; - if (argv[i] == "soccer" || argv[i] == "football" || - argv[i] == "m6") - mode = 6; - if (argv[i] == "ffa" || argv[i] == "free-for-all" || - argv[i] == "free" || argv[i] == "for" || - argv[i] == "all" || argv[i] == "m7") - mode = 7; - if (argv[i] == "ctf" || argv[i] == "capture-the-flag" - || argv[i] == "capture" || argv[i] == "the" || - argv[i] == "flag" || argv[i] == "m8") - mode = 8; - // if (argv[i] == "gp" || argv[i] == "grand-prix") - // gp = true; - if (argv[i] == "d0" || argv[i] == "novice" || argv[i] == "easy") - difficulty = 0; - if (argv[i] == "d1" || argv[i] == "intermediate" || argv[i] == "medium") - difficulty = 1; - if (argv[i] == "d2" || argv[i] == "expert" || argv[i] == "hard") - difficulty = 2; - if (argv[i] == "d3" || argv[i] == "supertux" || argv[i] == "super" || argv[i] == "best") - difficulty = 3; - if (argv[i] == "goal-limit" || argv[i] == "gl" || argv[i] == "goal" || argv[i] == "goals") - goal_target = true; - if (argv[i] == "time-limit" || argv[i] == "tl" || argv[i] == "time" || argv[i] == "minutes") - goal_target = false; - } - // if (gp && (mode == 3 || mode == 4)) - // mode -= 3; - handleServerConfiguration(peer, difficulty, mode, goal_target); - } - else if (argv[0] == "spectate") - { - if (ServerConfig::m_soccer_tournament || ServerConfig::m_only_host_riding) - { - std::string msg = "All spectators already have auto spectate ability"; - sendStringToPeer(msg, peer); - return; - } - if (/*m_game_setup->isGrandPrix() || */!ServerConfig::m_live_players) - { - std::string msg = "Server doesn't support spectate"; - sendStringToPeer(msg, peer); - return; - } - if (argv.size() == 1) - { - if (m_state.load() != WAITING_FOR_START_GAME) - { - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - if (m_default_always_spectate_peers.count(peer.get())) - argv.push_back("0"); - else - argv.push_back("1"); - } - else - { - if (peer->alwaysSpectate()) - argv.push_back("0"); - else - argv.push_back("1"); - } - } - - if (argv.size() != 2 || (argv[1] != "0" && argv[1] != "1")) - { - std::string msg = "Usage: /spectate [empty or 0 or 1], sets or resets (or changes) the spectating mode."; - sendStringToPeer(msg, peer); - return; - } - - if (m_state.load() != WAITING_FOR_START_GAME) - { - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - if (argv[1] == "1") - m_default_always_spectate_peers.insert(peer.get()); - else - m_default_always_spectate_peers.erase(peer.get()); - return; - } - - if (argv[1] == "1") - { - if (m_process_type == PT_CHILD && - peer->getHostId() == m_client_server_host_id.load()) - { - std::string msg = "Graphical client server cannot spectate"; - sendStringToPeer(msg, peer); - return; - } - peer->setAlwaysSpectate(ASM_COMMAND); - } - else - peer->setAlwaysSpectate(ASM_NONE); - updatePlayerList(); - } - else if (argv[0] == "addons" || argv[0] == "moreaddons") - { - bool more = (argv[0] == "moreaddons"); - if (argv.size() == 1) - { - argv.push_back(""); - switch (m_game_mode.load()) - { - case 0: - case 1: - case 3: - case 4: - argv[1] = "track"; - break; - case 6: - argv[1] = "soccer"; - break; - case 7: - case 8: - argv[1] = "arena"; - break; - } - } - const std::set& from = - (argv[1] == "kart" ? m_addon_kts.first : - (argv[1] == "track" ? m_addon_kts.second : - (argv[1] == "arena" ? m_addon_arenas : - /*argv[1] == "soccer" ?*/ m_addon_soccers - ))); - std::vector>> result; - for (const std::string& s: from) - result.push_back({s, {}}); - - auto peers = STKHost::get()->getPeers(); - int num_players = 0; - for (auto peer : peers) - { - if (!peer || !peer->isValidated() || peer->isWaitingForGame() || !canRace(peer)) - continue; - ++num_players; - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - const auto& kt = peer->getClientAssets(); - const auto& container = (argv[1] == "kart" ? kt.first : kt.second); - for (auto& p: result) - if (container.find(p.first) == container.end()) - p.second.push_back(username); - } - std::random_device rd; - std::mt19937 g(rd()); - std::shuffle(result.begin(), result.end(), g); - std::stable_sort(result.begin(), result.end(), - [](const std::pair>& a, - const std::pair>& b) -> bool { - if (a.second.size() != b.second.size()) - return a.second.size() > b.second.size(); - return false; - }); - std::string response; - const int NEXT_ADDONS = 5; - std::vector all_have; - while (!result.empty() && (int)result.back().second.size() == 0) - { - all_have.push_back(result.back().first); - result.pop_back(); - } - if (num_players > 0) { - response = "Found " + std::to_string(all_have.size()) + " asset(s)"; - std::reverse(result.begin(), result.end()); - if (result.size() > NEXT_ADDONS) - result.resize(NEXT_ADDONS); - if (!more) - { - bool nothing = true; - for (const std::string& s: all_have) - { - if (s.length() < 6 || s.substr(0, 6) != "addon_") - continue; - response.push_back(nothing ? ':' : ','); - nothing = false; - response.push_back(' '); - response += s.substr(6); - } - if (response.length() > 100) - response += "\nTotal: " + std::to_string(all_have.size()); - } - else - { - if (result.empty()) - response += "\nNothing more to install!"; - else - { - response += ". More addons to install:"; - for (unsigned i = 0; i < result.size(); ++i) - { - response += "\n" + result[i].first + ", missing for " - + std::to_string(result[i].second.size()) - + " player(s):"; - std::sort(result[i].second.begin(), result[i].second.end()); - for (unsigned j = 0; j < result[i].second.size(); ++j) - { - response += " " + result[i].second[j]; - } - } - } - } - } else { - response = "No one in the lobby can play. Found " - + std::to_string(all_have.size()) + " assets on the server."; - } - sendStringToPeer(response, peer); - } - else if (argv[0] == "listserveraddon") - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - bool has_options = argv.size() > 1 && - (argv[1].compare("-track") == 0 || - argv[1].compare("-arena") == 0 || - argv[1].compare("-kart") == 0 || - argv[1].compare("-soccer") == 0); - if (argv.size() == 1 || argv.size() > 3 || argv[1].size() < 3 || - (argv.size() == 2 && (argv[1].size() < 3 || has_options)) || - (argv.size() == 3 && (!has_options || argv[2].size() < 3))) - { - chat->encodeString16( - L"Usage: /listserveraddon [option][addon string to find " - "(at least 3 characters)]. Available options: " - "-track, -arena, -kart, -soccer."); - } - else - { - std::string type = ""; - std::string text = ""; - if(argv.size() > 1) - { - if(argv[1].compare("-track") == 0 || - argv[1].compare("-arena") == 0 || - argv[1].compare("-kart" ) == 0 || - argv[1].compare("-soccer" ) == 0) - type = argv[1].substr(1); - if((argv.size() == 2 && type.empty()) || argv.size() == 3) - text = argv[argv.size()-1]; - } - - std::set total_addons; - if (type.empty() || // not specify addon type - (!type.empty() && type.compare("kart") == 0)) // list kart addon - { - total_addons.insert(m_addon_kts.first.begin(), m_addon_kts.first.end()); - } - if (type.empty() || // not specify addon type - (!type.empty() && type.compare("track") == 0)) - { - total_addons.insert(m_addon_kts.second.begin(), m_addon_kts.second.end()); - } - if (type.empty() || // not specify addon type - (!type.empty() && type.compare("arena") == 0)) - { - total_addons.insert(m_addon_arenas.begin(), m_addon_arenas.end()); - } - if (type.empty() || // not specify addon type - (!type.empty() && type.compare("soccer") == 0)) - { - total_addons.insert(m_addon_soccers.begin(), m_addon_soccers.end()); - } - std::string msg = ""; - for (auto& addon : total_addons) - { - // addon_ (6 letters) - if (!text.empty() && addon.find(text, 6) == std::string::npos) - continue; - - msg += addon.substr(6); - msg += ", "; - } - if (msg.empty()) - chat->encodeString16(L"Addon not found"); - else - { - msg = msg.substr(0, msg.size() - 2); - chat->encodeString16(StringUtils::utf8ToWide( - std::string("Server addon: ") + msg)); - } - } - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } - else if (StringUtils::startsWith(cmd, "playerhasaddon")) - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - std::string part; - if (cmd.length() > 15) - part = cmd.substr(15); - std::string addon_id = part.substr(0, part.find(' ')); - std::string player_name; - if (part.length() > addon_id.length() + 1) - player_name = part.substr(addon_id.length() + 1); - std::shared_ptr player_peer = STKHost::get()->findPeerByName( - StringUtils::utf8ToWide(player_name)); - if (player_name.empty() || !player_peer || addon_id.empty()) - { - chat->encodeString16( - L"Usage: /playerhasaddon [addon_identity] [player name]"); - } - else - { - std::string addon_id_test = Addon::createAddonId(addon_id); - bool found = false; - const auto& kt = player_peer->getClientAssets(); - for (auto& kart : kt.first) - { - if (kart == addon_id_test) - { - found = true; - break; - } - } - if (!found) - { - for (auto& track : kt.second) - { - if (track == addon_id_test) - { - found = true; - break; - } - } - } - if (found) - { - chat->encodeString16(StringUtils::utf8ToWide - (player_name + " has addon " + addon_id)); - } - else - { - chat->encodeString16(StringUtils::utf8ToWide - (player_name + " has no addon " + addon_id)); - } - } - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } - else if (StringUtils::startsWith(cmd, "kick")) - { - if (!hasHostRights(peer)) - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16(L"You are not server owner"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; - return; - } - std::string player_name; - if (StringUtils::startsWith(cmd, "kickban")) - { - if (cmd.length() > 8) - player_name = cmd.substr(8); - } - else if (cmd.length() > 5) - { - player_name = cmd.substr(5); - } - std::shared_ptr player_peer = STKHost::get()->findPeerByName( - StringUtils::utf8ToWide(player_name)); - if (player_name.empty() || !player_peer || player_peer->isAIPeer()) - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16( - L"Usage: /kick [player name]"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } - else if (player_peer->isAngryHost()) - { - std::string msg = "This player is the owner of this server, " - "and is protected from your actions now"; - sendStringToPeer(msg, peer); - return; - } - else - { - if (!peer->isAngryHost() && !ServerConfig::m_kicks_allowed) - { - std::string msg = "Kicking players is not allowed on this server"; - sendStringToPeer(msg, peer); - return; - } - Log::info("ServerLobby", "Crown player kicks %s", player_name.c_str()); - player_peer->kick(); - if (ServerConfig::m_track_kicks) - { - std::string auto_report = "[ Auto report caused by kick ]"; - writeOwnReport(player_peer.get(), peer.get(), auto_report); - } - if (StringUtils::startsWith(cmd, "kickban")) - { - if (peer->isAngryHost() || ServerConfig::m_soccer_tournament) - { - Log::info("ServerLobby", "%s is now banned", player_name.c_str()); - m_temp_banned.insert(player_name); - std::string msg = StringUtils::insertValues( - "%s is now banned", player_name.c_str()); - sendStringToPeer(msg, peer); - } - else - { - std::string msg = "You cannot ban players"; - sendStringToPeer(msg, peer); - } - } - } - } - else if (StringUtils::startsWith(cmd, "unban")) - { - if (!hasHostRights(peer) || !(peer->isAngryHost() || ServerConfig::m_soccer_tournament)) - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16(L"You cannot unban players"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; - return; - } - std::string player_name; - if (cmd.length() > 6) - { - player_name = cmd.substr(6); - } - if (player_name.empty()) - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16( - L"Usage: /unban [player name]"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } - else - { - std::string msg = StringUtils::insertValues( - "%s is now unbanned", player_name.c_str()); - Log::info("ServerLobby", "%s is now unbanned", player_name.c_str()); - m_temp_banned.erase(player_name); - sendStringToPeer(msg, peer); - } - } - else if (StringUtils::startsWith(cmd, "ban")) - { - if (!hasHostRights(peer) || !(peer->isAngryHost() || ServerConfig::m_soccer_tournament)) - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16(L"You cannot ban players"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; - return; - } - std::string player_name; - if (cmd.length() > 4) - { - player_name = cmd.substr(4); - } - if (player_name.empty()) - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16( - L"Usage: /ban [player name]"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } - else - { - Log::info("ServerLobby", "%s is now banned", player_name.c_str()); - m_temp_banned.insert(player_name); - std::string msg = StringUtils::insertValues( - "%s is now banned", player_name.c_str()); - sendStringToPeer(msg, peer); - } - } - else if (StringUtils::startsWith(cmd, "playeraddonscore")) - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - std::string player_name; - if (cmd.length() > 17) - player_name = cmd.substr(17); - std::shared_ptr player_peer = STKHost::get()->findPeerByName( - StringUtils::utf8ToWide(player_name)); - if (player_name.empty() || !player_peer) - { - chat->encodeString16( - L"Usage: /playeraddonscore [player name] " - "(returns the number of addons, not a percentage)"); - } - else - { - auto& scores = player_peer->getAddonsScores(); - if (scores[AS_KART] == -1 && scores[AS_TRACK] == -1 && - scores[AS_ARENA] == -1 && scores[AS_SOCCER] == -1) - { - chat->encodeString16(StringUtils::utf8ToWide - (player_name + " has no addons")); - } - else - { - std::string msg = player_name; - msg += " addons:"; - if (scores[AS_KART] != -1) - msg += " karts: " + StringUtils::toString(scores[AS_KART]) + ","; - if (scores[AS_TRACK] != -1) - msg += " tracks: " + StringUtils::toString(scores[AS_TRACK]) + ","; - if (scores[AS_ARENA] != -1) - msg += " arenas: " + StringUtils::toString(scores[AS_ARENA]) + ","; - if (scores[AS_SOCCER] != -1) - msg += " fields: " + StringUtils::toString(scores[AS_SOCCER]) + ","; - msg.pop_back(); - chat->encodeString16(StringUtils::utf8ToWide(msg)); - } - } - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } - else if (argv[0] == "serverhasaddon") - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - if (argv.size() != 2) - { - chat->encodeString16( - L"Usage: /serverhasaddon [addon_identity]"); - } - else - { - std::set total_addons; - total_addons.insert(m_addon_kts.first.begin(), m_addon_kts.first.end()); - total_addons.insert(m_addon_kts.second.begin(), m_addon_kts.second.end()); - total_addons.insert(m_addon_arenas.begin(), m_addon_arenas.end()); - total_addons.insert(m_addon_soccers.begin(), m_addon_soccers.end()); - std::string addon_id_test = Addon::createAddonId(argv[1]); - bool found = total_addons.find(addon_id_test) != total_addons.end(); - if (found) - { - chat->encodeString16(StringUtils::utf8ToWide(std::string - ("Server has addon ") + argv[1])); - } - else - { - chat->encodeString16(StringUtils::utf8ToWide(std::string - ("Server has no addon ") + argv[1])); - } - } - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } - else if (argv[0] == "mute") + if (!m_command_manager.isInitialized()) { - std::shared_ptr player_peer; - std::string result_msg; - core::stringw player_name; - NetworkString* result = NULL; - - if (argv.size() != 2 || argv[1].empty()) - goto mute_error; - - player_name = StringUtils::utf8ToWide(argv[1]); - player_peer = STKHost::get()->findPeerByName(player_name); - - if (!player_peer || player_peer == peer) - goto mute_error; - - m_peers_muted_players[peer].insert(player_name); - result = getNetworkString(); - result->addUInt8(LE_CHAT); - result->setSynchronous(true); - result_msg = "Muted player "; - result_msg += argv[1]; - result->encodeString16(StringUtils::utf8ToWide(result_msg)); - peer->sendPacket(result, true/*reliable*/); - delete result; - return; - -mute_error: - NetworkString* error = getNetworkString(); - error->addUInt8(LE_CHAT); - error->setSynchronous(true); - std::string msg = "Usage: /mute player_name (not including yourself)"; - error->encodeString16(StringUtils::utf8ToWide(msg)); - peer->sendPacket(error, true/*reliable*/); - delete error; - } - else if (argv[0] == "unmute") - { - std::shared_ptr player_peer; - std::string result_msg; - core::stringw player_name; - NetworkString* result = NULL; - - if (argv.size() != 2 || argv[1].empty()) - goto unmute_error; - - player_name = StringUtils::utf8ToWide(argv[1]); - for (auto it = m_peers_muted_players[peer].begin(); - it != m_peers_muted_players[peer].end();) - { - if (*it == player_name) - { - it = m_peers_muted_players[peer].erase(it); - goto unmute_found; - } - else - { - it++; - } - } - goto unmute_error; - -unmute_found: - result = getNetworkString(); - result->addUInt8(LE_CHAT); - result->setSynchronous(true); - result_msg = "Unmuted player "; - result_msg += argv[1]; - result->encodeString16(StringUtils::utf8ToWide(result_msg)); - peer->sendPacket(result, true/*reliable*/); - delete result; - return; - -unmute_error: - NetworkString* error = getNetworkString(); - error->addUInt8(LE_CHAT); - error->setSynchronous(true); - std::string msg = "Usage: /unmute player_name"; - error->encodeString16(StringUtils::utf8ToWide(msg)); - peer->sendPacket(error, true/*reliable*/); - delete error; - } - else if (argv[0] == "listmute") - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - core::stringw total; - for (auto& name : m_peers_muted_players[peer]) - { - total += name; - total += " "; - } - if (total.empty()) - chat->encodeString16("No player has been muted by you"); - else - { - total += "muted"; - chat->encodeString16(total); - } - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } - else if (argv[0] == "help") - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16(m_help_message); - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } - else if (argv[0] == "commands") - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true);chat->encodeString16 - (StringUtils::utf8ToWide(m_available_commands)); - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } - else if (argv[0] == "gnu") - { - if (m_server_owner.lock() != peer) - { - std::string msg = "You are not server owner"; - sendStringToPeer(msg, peer); - return; - } - else if (m_kart_elimination.isEnabled()) - { - std::string msg = "Gnu Elimination mode was already enabled!"; - sendStringToPeer(msg, peer); - } - else if ( - RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_NORMAL_RACE && - RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) - { - std::string msg = "Gnu Elimination is available only with racing modes"; - sendStringToPeer(msg, peer); - } - else - { - if (argv.size() > 1 && m_available_kts.first.count(argv[1]) > 0) - { - m_kart_elimination.enable(argv[1]); - } else { - m_kart_elimination.enable("gnu"); - } - std::string msg = m_kart_elimination.getStartingMessage(); - sendStringToAllPeers(msg); - } - } - else if (argv[0] == "nognu") - { - if (m_server_owner.lock() != peer) - { - std::string msg = "You are not server owner"; - sendStringToPeer(msg, peer); - return; - } - else if (!m_kart_elimination.isEnabled()) - { - std::string msg = "Gnu Elimination mode was already off!"; - sendStringToPeer(msg, peer); - return; - } - else - { - m_kart_elimination.disable(); - std::string msg = "Gnu Elimination is now off"; - sendStringToAllPeers(msg); - } - } - else if (argv[0] == "tell") - { - if (argv.size() == 1) - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16(L"Tell something non-empty"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; - return; - } - else - { - std::string ans; - for (unsigned i = 1; i < argv.size(); ++i) - { - if (i > 1) - ans.push_back(' '); - ans += argv[i]; - } - writeOwnReport(peer.get(), peer.get(), ans); - } - } - else if (argv[0] == "standings") - { - std::string msg; - if (argv.size() > 1) - { - if (argv[1] == "gp") - msg = getGrandPrixStandings(); - else if (argv[1] == "gnu") - msg = m_kart_elimination.getStandings(); - else - msg = "Usage: /standings [gp | gnu]"; - sendStringToPeer(msg, peer); - return; - } - if (m_game_setup->isGrandPrix()) - msg = getGrandPrixStandings(); - else - msg = m_kart_elimination.getStandings(); - sendStringToPeer(msg, peer); - } - else if (argv[0] == "teamchat") - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - m_team_speakers.insert(peer.get()); - chat->encodeString16(L"Your messages are now addressed to team only"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } - else if (argv[0] == "to") - { - if (argv.size() == 1) - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16(L"Usage: /to (username1) ... (usernameN)"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } else { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - m_message_receivers[peer.get()].clear(); - for (unsigned i = 1; i < argv.size(); ++i) - { - m_message_receivers[peer.get()].insert( - StringUtils::utf8ToWide(argv[i])); - } - chat->encodeString16(L"Successfully changed chat settings"); - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } - } - else if (argv[0] == "public") - { - m_message_receivers[peer.get()].clear(); - m_team_speakers.erase(peer.get()); - std::string s = "Your messages are now public"; - sendStringToPeer(s, peer); - } - else if (argv[0] == "record") - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); -#ifdef ENABLE_SQLITE3 - if (argv.size() < 5) - { - chat->encodeString16(L"Usage: /record (track id) " - "(normal/time-trial) (normal/reverse) (laps)\n" - "Receives the server record for the race settings if any"); - } else { - bool error = false; - std::string track_name = argv[1]; - std::string mode_name = (argv[2] == "t" || argv[2] == "tt" - || argv[2] == "time-trial" || argv[2] == "timetrial" ? - "time-trial" : "normal"); - std::string reverse_name = (argv[3] == "r" || - argv[3] == "rev" || argv[3] == "reverse" ? "reverse" : - "normal"); - int laps_count = -1; - if (!StringUtils::parseString(argv[4], &laps_count)) - error = true; - if (!error && laps_count < 0) - error = true; - if (error) - { - chat->encodeString16(L"Invalid lap count"); - } - else - { - std::string result = getRecord(track_name, mode_name, reverse_name, laps_count); - chat->encodeString16(StringUtils::utf8ToWide(result)); - } - } -#else - chat->encodeString16(L"This command is not supported."); -#endif - peer->sendPacket(chat, true/*reliable*/); - delete chat; - } - else if (argv[0] == "power") - { - if (peer->isAngryHost()) - { - peer->setAngryHost(false); - std::string msg = "You are now a normal player"; - sendStringToPeer(msg, peer); - updatePlayerList(); - return; - } - std::string password = ServerConfig::m_power_password; - if (password.empty() || argv.size() <= 1 || argv[1] != password) - { - std::string msg = "You need to provide the password to have the power"; - sendStringToPeer(msg, peer); - return; - } - peer->setAngryHost(true); - std::string msg = "Now you finally have the power!"; - sendStringToPeer(msg, peer); - updatePlayerList(); - return; - } - else if (argv[0] == "admin") - { - std::string msg; - bool can = (peer->isAngryHost() || (ServerConfig::m_soccer_tournament && hasHostRights(peer))); - bool weak_abilities = (ServerConfig::m_only_host_riding && hasHostRights(peer)); - if (!can && !weak_abilities) { - msg = "You cannot control this server"; - sendStringToPeer(msg, peer); - return; - } - if (argv.size() == 1) - { - msg = "Usage: /admin command arg1 arg2 ..."; - sendStringToPeer(msg, peer); - return; - } - if (argv[1] == "length") - { - if (argv.size() < 3) - { - msg = "Usage: /admin length (x (float) | = (int) | check | clear)"; - sendStringToPeer(msg, peer); - return; - } - if (argv[2] == "check") - { - if (m_default_lap_multiplier < 0 && m_fixed_lap < 0) - msg = "Game length is currently chosen by players"; - else if (m_default_lap_multiplier > 0) - msg = StringUtils::insertValues( - "Game length is %f x default", - m_default_lap_multiplier); - else if (m_fixed_lap > 0) - msg = StringUtils::insertValues( - "Game length is %d", m_fixed_lap); - else - msg = StringUtils::insertValues( - "An error: game length is both %f x default and %d", - m_default_lap_multiplier, m_fixed_lap); - sendStringToPeer(msg, peer); - return; - } - if (argv[2] == "clear") - { - m_default_lap_multiplier = -1.0; - m_fixed_lap = -1; - msg = "Game length will be chosen by players"; - sendStringToAllPeers(msg); - return; - } - double temp_double = -1.0; - int temp_int = -1; - if (argv[2] == "x" && argv.size() >= 4 && - StringUtils::parseString(argv[3], &temp_double)) - { - m_default_lap_multiplier = std::max(0.0, temp_double); - m_fixed_lap = -1; - msg = StringUtils::insertValues( - "Game length is now %f x default", - m_default_lap_multiplier); - sendStringToAllPeers(msg); - return; - } - if (argv[2] == "=" && argv.size() >= 4 && - StringUtils::parseString(argv[3], &temp_int)) - { - m_fixed_lap = std::max(0, temp_int); - m_default_lap_multiplier = -1.0; - msg = StringUtils::insertValues( - "Game length is now %d", m_fixed_lap); - sendStringToAllPeers(msg); - return; - } - msg = "Usage: /admin length (x (float) | = (int) | check | clear)"; - sendStringToPeer(msg, peer); - return; - } - if (argv[1] == "queue") - { - std::string format_string = "Format: /admin queue (show | push[_front] (track) | pop[_back])"; - if (argv.size() < 3) - { - sendStringToPeer(format_string, peer); - return; - } - if (argv[2] == "show") - { - std::string msg = "Queue:"; - for (const std::string& s: m_tracks_queue) { - msg += " " + s; - } - sendStringToPeer(msg, peer); - } - else if (argv[2] == "push" || argv[2] == "push_back") - { - if (argv.size() < 4) - { - sendStringToPeer(format_string, peer); - return; - } - m_tracks_queue.push_back(argv[3]); - std::string msg = "Pushed " + argv[3] - + " to the back of queue, current queue size: " - + std::to_string(m_tracks_queue.size()); - sendStringToPeer(msg, peer); - } - else if (argv[2] == "push_front") - { - if (argv.size() < 4) - { - sendStringToPeer(format_string, peer); - return; - } - m_tracks_queue.push_front(argv[3]); - std::string msg = "Pushed " + argv[3] - + " to the front of queue, current queue size: " - + std::to_string(m_tracks_queue.size()); - sendStringToPeer(msg, peer); - } - else if (argv[2] == "pop" || argv[2] == "pop_back") - { - std::string msg = ""; - if (m_tracks_queue.empty()) { - msg = "Queue was empty before."; - } - else - { - std::string msg = "Popped " + m_tracks_queue.front() - + "from the queue,"; - m_tracks_queue.pop_front(); - msg += " current queue size: " - + std::to_string(m_tracks_queue.size()); - } - sendStringToPeer(msg, peer); - } - else if (argv[2] == "pop_back") - { - std::string msg = ""; - if (m_tracks_queue.empty()) { - msg = "Queue was empty before."; - } - else - { - std::string msg = "Popped " + m_tracks_queue.back() - + "from the queue,"; - m_tracks_queue.pop_back(); - msg += " current queue size: " - + std::to_string(m_tracks_queue.size()); - } - sendStringToPeer(msg, peer); - } - return; - } - if (!can) { - msg = "You cannot control this server. As you are the crowned player, " - "you can invoke /admin length and /admin queue commands."; - sendStringToPeer(msg, peer); - return; - } - if (argv[1] == "start") - { - if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) - { - msg = "Usage: /admin start [0/1] - allow or forbid starting a race"; - sendStringToPeer(msg, peer); - return; - } - if (argv[2] == "0") - { - m_allowed_to_start = false; - msg = "Now starting a race is forbidden"; - } - else - { - m_allowed_to_start = true; - msg = "Now starting a race is allowed"; - } - sendStringToPeer(msg, peer); - return; - } - if (argv[1] == "shuffle") - { - if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) - { - msg = "Usage: /admin shuffle [0/1] - make the GP grid shuffled all the time, or make it result-based"; - sendStringToPeer(msg, peer); - return; - } - if (argv[2] == "0") - { - m_shuffle_gp = false; - msg = "Now the GP grid is sorted by score"; - } else { - m_shuffle_gp = true; - msg = "Now the GP grid is shuffled"; - } - sendStringToPeer(msg, peer); - return; - } - if (argv[1] == "timeout") - { - int seconds; - if (argv.size() < 3 || !StringUtils::parseString(argv[2], &seconds) || seconds <= 0) - { - msg = "Usage: /admin timeout [positive int x] - set timeout to x seconds"; - sendStringToPeer(msg, peer); - return; - } - m_timeout.store((int64_t)StkTime::getMonoTimeMs() + - (int64_t)(seconds * 1000.0f)); - updatePlayerList(); - return; - } - if (argv[1] == "team") - { - if (argv.size() != 4) { - msg = "Usage: /admin team (color/0..6) (player) - move a player " - "to a team, or remove from teams (none/0)"; - sendStringToPeer(msg, peer); - return; - } - auto it = m_team_name_to_index.find(argv[2]); - int index = (it == m_team_name_to_index.end() ? 0 : it->second); - std::string player; - auto wide_player_name = StringUtils::utf8ToWide(argv[3]); - std::shared_ptr player_peer = STKHost::get()->findPeerByWildcard( - wide_player_name, player); - // if player not found - if (!player_peer) - { - // don't use if wildcard - if (wide_player_name.find("*") != -1 || wide_player_name.find("?") != -1) - { - msg = "Player not found or not unique"; - sendStringToPeer(msg, peer); - return; - } - else - { - // if no wildcard, reset player name to use for absent players - player = argv[3]; - } - } - for (const auto& pair: m_team_name_to_index) - { - if (pair.second < 0) - { - if (pair.second == -index) - { - m_player_categories[pair.first].insert(player); - m_categories_for_player[player].insert(pair.first); - } - else - { - m_player_categories[pair.first].erase(player); - m_categories_for_player[player].erase(pair.first); - } - } - } - index = abs(index); - m_team_for_player[player] = index; - wide_player_name = StringUtils::utf8ToWide(player); - if (player_peer) - { - for (auto& profile : player_peer.get()->getPlayerProfiles()) - { - if (profile->getName() == wide_player_name) - { - profile->setTemporaryTeam(index - 1); - break; - } - } - } - updatePlayerList(); - return; - } - if (argv[1] == "cat+") - { - if (argv.size() != 4) { - msg = "Usage: /admin cat+ (category) (player) - add a player to a category"; - sendStringToPeer(msg, peer); - return; - } - std::string category = argv[2]; - std::string player = argv[3]; - m_player_categories[category].insert(player); - m_categories_for_player[player].insert(category); - updatePlayerList(); - return; - } - if (argv[1] == "cat-") - { - if (argv.size() != 4) { - msg = "Usage: /admin cat- (category) (player) - remove a player from a category"; - sendStringToPeer(msg, peer); - return; - } - std::string category = argv[2]; - std::string player = argv[3]; - m_player_categories[category].erase(player); - m_categories_for_player[player].erase(category); - updatePlayerList(); - return; - } - if (argv[1] == "cat*") - { - int displayed; - if (argv.size() != 4 || !StringUtils::parseString(argv[3], &displayed) - || displayed < 0 || displayed > 1) { - msg = "Usage: /admin cat* (category) (0|1) - make category displayed or not"; - sendStringToPeer(msg, peer); - return; - } - std::string category = argv[2]; - if (displayed) { - m_hidden_categories.erase(category); - } else { - m_hidden_categories.insert(category); - } - updatePlayerList(); - return; - } - if (argv[1] == "troll") - { - if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) - { - msg = "Usage: /admin troll [0/1] - disable or enable anti troll system"; - sendStringToPeer(msg, peer); - return; - } - if (argv[2] == "0") - { - m_troll_active = false; - msg = "Trolls can stay"; - } else { - m_troll_active = true; - msg = "Trolls will be kicked"; - } - sendStringToPeer(msg, peer); - return; - } - if (argv[1] == "hitmsg") - { - if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) - { - msg = "Usage: /admin hitmsg [0/1] - disable or enable messages if a player makes a teammate explode"; - sendStringToPeer(msg, peer); - return; - } - if (argv[2] == "0") - { - m_show_teammate_hits = false; - msg = "Teammate hits will not be sent"; - } else { - m_show_teammate_hits = true; - msg = "Teammate hits will be sent to all players"; - } - sendStringToAllPeers(msg); - return; - } - if (argv[1] == "teamhit") - { - if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) - { - msg = "Usage: /admin teamhit [0/1] - disable or enable punish mode when hitting team mates"; - sendStringToPeer(msg, peer); - return; - } - if (argv[2] == "0") - { - m_teammate_hit_mode = false; - msg = "Teammate hits are not punished now"; - } - else - { - m_teammate_hit_mode = true; - msg = "Teammate hits are punished now"; - } - sendStringToAllPeers(msg); - return; - } - } - else if (argv[0] == "version") - { - std::string msg = "1.3-rc1 k 210903 beta"; - sendStringToPeer(msg, peer); - } - else if (argv[0] == "clear") - { - std::string msg(30, '\n'); - sendStringToPeer(msg, peer); - } - else if (argv[0] == "register") - { - int online_id = peer->getPlayerProfiles()[0]->getOnlineId(); - if (online_id <= 0) - { - std::string msg = "Please join with a valid online STK account."; - sendStringToPeer(msg, peer); - return; - } - std::string ans = ""; - for (unsigned i = 1; i < argv.size(); ++i) - { - if (i > 1) - ans.push_back(' '); - ans += argv[i]; - } - std::string message_ok = "Your registration request is being processed"; - std::string message_wrong = "Sorry, an error occurred. Please try again."; - if (writeOnePlayerReport(peer.get(), ServerConfig::m_register_table_name, - ans)) - sendStringToPeer(message_ok, peer); - else - sendStringToPeer(message_wrong, peer); - } -#ifdef ENABLE_WEB_SUPPORT - else if (argv[0] == "token") - { - int online_id = peer->getPlayerProfiles()[0]->getOnlineId(); - if (online_id <= 0) - { - std::string msg = "Please join with a valid online STK account."; - sendStringToPeer(msg, peer); - return; - } - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - std::string token = getToken(); - while (m_web_tokens.count(token)) - token = getToken(); - m_web_tokens.insert(token); - std::string msg = "Your token is " + token; -#ifdef ENABLE_SQLITE3 - std::string tokens_table_name = ServerConfig::m_tokens_table; - std::string query = StringUtils::insertValues( - "INSERT INTO %s (username, token) " - "VALUES (\"%s\", \"%s\");", - tokens_table_name.c_str(), username.c_str(), token.c_str() - ); - if (easySQLQuery(query)) - msg += "\nRetype it on the website to connect your STK account. "; - else - msg = "An error occurred, please try again."; -#else - msg += "\nThough it is useless..."; -#endif - sendStringToPeer(msg, peer); - } -#endif - else if (ServerConfig::m_soccer_tournament) - { - std::string peer_username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - - if (m_tournament_limited_chat && argv[0] == "muteall") - { - if (argv.size() >= 2 && argv[1] == "0") - { - m_tournament_mutealls.erase(peer_username); - } - else if (argv.size() >= 2 && argv[1] == "1") - { - m_tournament_mutealls.insert(peer_username); - } - else - { - if (m_tournament_mutealls.count(peer_username)) - m_tournament_mutealls.erase(peer_username); - else - m_tournament_mutealls.insert(peer_username); - } - std::string msg; - if (m_tournament_mutealls.count(peer_username)) - msg = "You are now receiving messages only from players and referees"; - else - msg = "You are now receiving messages from spectators too"; - sendStringToPeer(msg, peer); - } - - // Referee-only commands - - if (m_tournament_referees.count(peer_username) == 0) - { - std::string msg = "You are not a referee"; - sendStringToPeer(msg, peer); - return; - } - if (argv[0] == "game") - { - int old_game = m_tournament_game; - if (argv.size() < 2) - { - ++m_tournament_game; - if (m_tournament_game == m_tournament_max_games) - m_tournament_game = 0; - m_fixed_lap = ServerConfig::m_fixed_lap_count; - } else { - if (!StringUtils::parseString(argv[1], &m_tournament_game) - || m_tournament_game < 0 - || m_tournament_game >= m_tournament_max_games) - { - std::string msg = "Please specify a correct number. " - "Format: /game [number 0.." - + std::to_string(m_tournament_max_games - 1) + "] [length]"; - sendStringToPeer(msg, peer); - return; - } - int length = 10; - if (argv.size() >= 3) - { - bool ok = StringUtils::parseString(argv[2], &length); - if (!ok || length <= 0) - { - std::string msg = "Please specify a correct number. " - "Format: /game [number] [length]"; - sendStringToPeer(msg, peer); - return; - } - } - m_fixed_lap = length; - } - if (tournamentColorsSwapped(m_tournament_game) ^ tournamentColorsSwapped(old_game)) - changeColors(); - if (tournamentGoalsLimit(m_tournament_game) ^ tournamentGoalsLimit(old_game)) - changeLimitForTournament(tournamentGoalsLimit(m_tournament_game)); - std::string msg = StringUtils::insertValues( - "Ready to start game %d for %d ", m_tournament_game, m_fixed_lap) - + (tournamentGoalsLimit(m_tournament_game) ? "goals" : "minutes"); - sendStringToAllPeers(msg); - Log::info("ServerLobby", "SoccerMatchLog: Game number changed from %d to %d", - old_game, m_tournament_game); - } - else if (argv[0] == "role") - { - if (argv.size() < 3) - { - std::string msg = "Format: /role (R|B|J|S) username"; - sendStringToPeer(msg, peer); - return; - } - std::string role = argv[1]; - std::string username = argv[2]; - bool permanent = (argv.size() >= 4 && - (argv[3] == "p" || argv[3] == "permanent")); - if (role.length() != 1) - std::swap(role, username); - if (role.length() != 1) - { - std::string msg = "Please specify one-letter role (R/B/J/S) and player"; - sendStringToPeer(msg, peer); - return; - } - if (role[0] >= 'A' && role[0] <= 'Z') - role[0] += 'a' - 'A'; - std::vector changed_usernames; - if (!username.empty()) - { - if (username[0] == '#') - { - std::string category = username.substr(1); - auto it = m_player_categories.find(category); - if (it != m_player_categories.end()) - { - for (const std::string& s: it->second) - { - changed_usernames.push_back(s); - } - } - } - else - { - changed_usernames.push_back(username); - } - } - for (const std::string& username: changed_usernames) - { - Log::info("ServerLobby", "SoccerMatchLog: Role of %s changed to %s", - username.c_str(), role.c_str()); - m_tournament_red_players.erase(username); - m_tournament_blue_players.erase(username); - m_tournament_referees.erase(username); - if (permanent) - { - m_tournament_init_red.erase(username); - m_tournament_init_blue.erase(username); - m_tournament_init_ref.erase(username); - } - std::string role_changed = "The referee has updated your role - you are now %s"; - std::shared_ptr player_peer = STKHost::get()->findPeerByName( - StringUtils::utf8ToWide(username)); - std::vector missing_assets; - if (player_peer) - missing_assets = getMissingTournamentAssets(player_peer); - bool fail = false; - switch (role[0]) - { - case 'R': - case 'r': - { - if (!missing_assets.empty()) - { - fail = true; - break; - } - if (tournamentColorsSwapped(m_tournament_game)) - { - m_tournament_blue_players.insert(username); - if (permanent) - m_tournament_init_blue.insert(username); - } - else - { - m_tournament_red_players.insert(username); - if (permanent) - m_tournament_init_red.insert(username); - } - if (player_peer) - { - role_changed = StringUtils::insertValues(role_changed, "red player"); - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_RED); - sendStringToPeer(role_changed, player_peer); - } - break; - } - case 'B': - case 'b': - { - if (!missing_assets.empty()) - { - fail = true; - break; - } - if (tournamentColorsSwapped(m_tournament_game)) - { - m_tournament_red_players.insert(username); - if (permanent) - m_tournament_init_red.insert(username); - } - else - { - m_tournament_blue_players.insert(username); - if (permanent) - m_tournament_init_blue.insert(username); - } - if (player_peer) - { - role_changed = StringUtils::insertValues(role_changed, "blue player"); - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_BLUE); - sendStringToPeer(role_changed, player_peer); - } - break; - } - case 'J': - case 'j': - { - if (!missing_assets.empty()) - { - fail = true; - break; - } - m_tournament_referees.insert(username); - if (permanent) - m_tournament_init_ref.insert(username); - if (player_peer) - { - role_changed = StringUtils::insertValues(role_changed, "referee"); - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); - sendStringToPeer(role_changed, player_peer); - } - break; - } - case 'S': - case 's': - { - if (player_peer) - { - role_changed = StringUtils::insertValues(role_changed, "spectator"); - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); - sendStringToPeer(role_changed, player_peer); - } - break; - } - } - std::string msg; - if (!fail) - msg = StringUtils::insertValues( - "Successfully changed role to %s for %s", role, username); - else - { - msg = StringUtils::insertValues( - "Failed to change role to %s for %s - missing assets:", role, username); - for (unsigned i = 0; i < missing_assets.size(); i++) - { - if (i) - msg.push_back(','); - msg += " " + missing_assets[i]; - } - } - sendStringToPeer(msg, peer); - } - updatePlayerList(); - } - else if (argv[0] == "stop") - { - World* w = World::getWorld(); - if (!w) - return; - SoccerWorld *sw = dynamic_cast(w); - sw->stop(); - std::string msg = "The game is stopped."; - sendStringToAllPeers(msg); - Log::info("ServerLobby", "SoccerMatchLog: The game is stopped"); - } - else if (argv[0] == "go" || argv[0] == "play" || argv[0] == "resume") - { - World* w = World::getWorld(); - if (!w) - return; - SoccerWorld *sw = dynamic_cast(w); - sw->resume(); - std::string msg = "The game is resumed."; - sendStringToAllPeers(msg); - Log::info("ServerLobby", "SoccerMatchLog: The game is resumed"); - } - else if (argv[0] == "lobby") - { - World* w = World::getWorld(); - if (!w) - return; - SoccerWorld *sw = dynamic_cast(w); - sw->allToLobby(); - std::string msg = "The game will be restarted."; - sendStringToAllPeers(msg); - } - else if (argv[0] == "init") - { - int red, blue; - if (argv.size() < 3 || - !StringUtils::parseString(argv[1], &red) || - !StringUtils::parseString(argv[2], &blue)) - { - std::string msg = "Usage: /init [red_count] [blue_count]"; - sendStringToPeer(msg, peer); - return; - } - World* w = World::getWorld(); - if (!w) - { - std::string msg = "Please set the count when the karts " - "are ready. Setting the initial count in lobby is " - "not implemented yet, sorry."; - sendStringToPeer(msg, peer); - return; - } - SoccerWorld *sw = dynamic_cast(w); - sw->setInitialCount(red, blue); - sw->tellCount(); - } - } - else - { - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - std::string msg = "Unknown command: "; - msg += cmd; - chat->encodeString16(StringUtils::utf8ToWide(msg)); - peer->sendPacket(chat, true/*reliable*/); - delete chat; + m_command_manager = CommandManager(this); } + m_command_manager.handleCommand(event, peer); } // handleServerCommand //----------------------------------------------------------------------------- void ServerLobby::updateGnuElimination() diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 33e8743a5c2..c59c893d7a3 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -25,6 +25,7 @@ #include "utils/track_filter.hpp" #include "utils/kart_elimination.hpp" #include "karts/controller/player_controller.hpp" +#include "network/protocols/command_manager.hpp" #include "irrString.h" @@ -48,6 +49,7 @@ class NetworkString; class NetworkPlayerProfile; class STKPeer; class SocketAddress; +// class CommandManager; namespace Online { @@ -418,6 +420,8 @@ class ServerLobby : public LobbyProtocol // trigger teammate hits anymore const float MAX_BOWL_TEAMMATE_HIT_TIME = 2.0f; + CommandManager m_command_manager; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); From f5f54295cf4a277e16e5b83a24c458f3ab920847 Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 8 Sep 2021 22:17:21 +0300 Subject: [PATCH 134/830] Add permissions and several commands, fix style a bit --- src/network/protocols/command_manager.cpp | 150 ++++++++++++++++-- src/network/protocols/command_manager.hpp | 49 ++++-- src/network/protocols/command_permissions.hpp | 35 ++++ src/network/protocols/server_lobby.cpp | 57 ++++++- src/network/protocols/server_lobby.hpp | 8 +- 5 files changed, 265 insertions(+), 34 deletions(-) create mode 100644 src/network/protocols/command_permissions.hpp diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 000f37428b5..06f5100b38e 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -39,6 +39,7 @@ #include "network/peer_vote.hpp" #include "network/protocol_manager.hpp" #include "network/protocols/connect_to_peer.hpp" +#include "network/protocols/command_permissions.hpp" #include "network/protocols/game_protocol.hpp" #include "network/protocols/game_events_protocol.hpp" #include "network/protocols/server_lobby.hpp" @@ -68,26 +69,151 @@ #include #include - // ======================================================================== void CommandManager::initCommands() { - m_commands.emplace_back("commands"); + m_commands.emplace_back("commands", &CommandManager::process_commands, UP_EVERYONE); + m_commands.emplace_back("replay", &CommandManager::process_replay, UP_SINGLE); + m_commands.emplace_back("start", &CommandManager::process_start, UP_EVERYONE); + m_commands.emplace_back("config", &CommandManager::process_config, UP_CROWNED); } // initCommands - // ======================================================================== void CommandManager::handleCommand(Event* event, std::shared_ptr peer) { - std::string result = ""; - for (const Command& c: m_commands) - { - result += c.m_name + " "; - } - if (!result.empty()) - result.pop_back(); - m_lobby->sendStringToPeer(result, peer); + NetworkString& data = event->data(); + std::string language; + data.decodeString(&language); + std::string cmd; + data.decodeString(&cmd); + auto argv = StringUtils::split(cmd, ' '); + if (argv.size() == 0) + return; + + int permissions = m_lobby->getPermissions(peer); + bool found_command = false; + + for (const auto& command: m_commands) + { + if (argv[0] == command.m_name) + { + found_command = true; + if ((permissions & command.m_permissions) == 0) + { + std::string msg = "You don't have permissions to invoke this command"; + m_lobby->sendStringToPeer(msg, peer); + } + else + { + Context context(event, peer, argv); + (this->*command.m_action)(context); + } + } + } + + if (!found_command) + { + std::string msg = "Command " + argv[0] + " not found"; + m_lobby->sendStringToPeer(msg, peer); + } + + // TODO: process commands with typos + // TODO: add votedness + } // handleCommand +// ======================================================================== + +void CommandManager::process_commands(Context& context) +{ + std::string result = ""; + for (const Command& c: m_commands) + { + result += c.m_name + " "; + } + + if (!result.empty()) + result.pop_back(); -// ======================================================================== \ No newline at end of file + m_lobby->sendStringToPeer(result, context.m_peer); +} // process_commands +// ======================================================================== + +void CommandManager::process_replay(Context& context) +{ + const auto& argv = context.m_argv; + if (ServerConfig::m_record_replays) + { + bool current_state = m_lobby->hasConsentOnReplays(); + if (argv.size() >= 2 && argv[1] == "0") + current_state = false; + else if (argv.size() >= 2 && argv[1] == "1") + current_state = true; + else + current_state ^= 1; + + m_lobby->setConsentOnReplays(current_state); + std::string msg = "Recording ghost replays is now "; + msg += (current_state ? "on" : "off"); + m_lobby->sendStringToAllPeers(msg); + } + else + { + std::string msg = "This server doesn't allow recording replays"; + m_lobby->sendStringToPeer(msg, context.m_peer); + } +} // process_replay +// ======================================================================== + +void CommandManager::process_start(Context& context) +{ + m_lobby->startSelection(context.m_event); +} // process_start +// ======================================================================== + +void CommandManager::process_config(Context& context) +{ + const auto& argv = context.m_argv; + int difficulty = m_lobby->getDifficulty(); + int mode = m_lobby->getGameMode(); + bool goal_target = m_lobby->isSoccerGoalTarget(); + bool gp = false; + for (unsigned i = 1; i < argv.size(); i++) + { + if (argv[i] == "tt" || argv[i] == "time-trial"|| + argv[i] == "trial" || argv[i] == "m4") + mode = 4; + if (argv[i] == "normal" || argv[i] == "normal-race" || + argv[i] == "race" || argv[i] == "m3") + mode = 3; + if (argv[i] == "soccer" || argv[i] == "football" || + argv[i] == "m6") + mode = 6; + if (argv[i] == "ffa" || argv[i] == "free-for-all" || + argv[i] == "free" || argv[i] == "for" || + argv[i] == "all" || argv[i] == "m7") + mode = 7; + if (argv[i] == "ctf" || argv[i] == "capture-the-flag" + || argv[i] == "capture" || argv[i] == "the" || + argv[i] == "flag" || argv[i] == "m8") + mode = 8; + // if (argv[i] == "gp" || argv[i] == "grand-prix") + // gp = true; + if (argv[i] == "d0" || argv[i] == "novice" || argv[i] == "easy") + difficulty = 0; + if (argv[i] == "d1" || argv[i] == "intermediate" || argv[i] == "medium") + difficulty = 1; + if (argv[i] == "d2" || argv[i] == "expert" || argv[i] == "hard") + difficulty = 2; + if (argv[i] == "d3" || argv[i] == "supertux" || argv[i] == "super" || argv[i] == "best") + difficulty = 3; + if (argv[i] == "goal-limit" || argv[i] == "gl" || argv[i] == "goal" || argv[i] == "goals") + goal_target = true; + if (argv[i] == "time-limit" || argv[i] == "tl" || argv[i] == "time" || argv[i] == "minutes") + goal_target = false; + } + // if (gp && (mode == 3 || mode == 4)) + // mode -= 3; + m_lobby->handleServerConfiguration(context.m_peer, difficulty, mode, goal_target); +} // process_config +// ======================================================================== diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 4509e7599ca..d6bc2b35173 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -40,29 +40,50 @@ class ServerLobby; class Event; class STKPeer; -class CommandManager { +class CommandManager +{ + struct Context + { + Event* m_event; + std::shared_ptr m_peer; + std::vector m_argv; + Context(Event* event, std::shared_ptr peer, std::vector& argv): + m_event(event), m_peer(peer), m_argv(argv) {} + }; - struct Command { - std::string m_name; + struct Command + { + std::string m_name; - Command(std::string name): m_name(name) {} - }; + int m_permissions; + + void (CommandManager::*m_action)(Context& context); + + Command(std::string name, + void (CommandManager::*f)(Context& context), int permissions): + m_name(name), m_permissions(permissions), m_action(f) {} + }; private: - - ServerLobby* m_lobby; - std::vector m_commands; + ServerLobby* m_lobby; + + std::vector m_commands; - void initCommands(); + void initCommands(); + + void process_commands(Context& context); + void process_replay(Context& context); + void process_start(Context& context); + void process_config(Context& context); public: - - CommandManager(ServerLobby* lobby = nullptr): m_lobby(lobby) { initCommands(); } - - void handleCommand(Event* event, std::shared_ptr peer); - bool isInitialized() { return m_lobby != nullptr; } + CommandManager(ServerLobby* lobby = nullptr): m_lobby(lobby) { initCommands(); } + + void handleCommand(Event* event, std::shared_ptr peer); + + bool isInitialized() { return m_lobby != nullptr; } }; #endif // COMMAND_MANAGER_HPP \ No newline at end of file diff --git a/src/network/protocols/command_permissions.hpp b/src/network/protocols/command_permissions.hpp new file mode 100644 index 00000000000..9627f1844a3 --- /dev/null +++ b/src/network/protocols/command_permissions.hpp @@ -0,0 +1,35 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2021 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef COMMAND_PERMISSIONS_HPP +#define COMMAND_PERMISSIONS_HPP + +enum CommandPermissions : unsigned int +{ + PE_USUAL = 1, + PE_VOTED = 2, + PE_CROWNED = 4, + PE_SINGLE = 8, + PE_HAMMER = 16, + UP_HAMMER = PE_HAMMER, + UP_SINGLE = UP_HAMMER | PE_SINGLE, + UP_CROWNED = UP_SINGLE | PE_CROWNED, + UP_EVERYONE = UP_CROWNED | PE_USUAL +}; + +#endif // COMMAND_PERMISSIONS_HPP \ No newline at end of file diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 0683cf54166..8975f6cacff 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -39,6 +39,7 @@ #include "network/peer_vote.hpp" #include "network/protocol_manager.hpp" #include "network/protocols/connect_to_peer.hpp" +#include "network/protocols/command_permissions.hpp" #include "network/protocols/game_protocol.hpp" #include "network/protocols/game_events_protocol.hpp" #include "network/race_event_manager.hpp" @@ -2851,7 +2852,7 @@ void ServerLobby::startSelection(const Event *event) sendStringToPeer(msg, peer); return; } - if (peer != m_server_owner.lock()) + if (!hasHostRights(peer)) { Log::warn("ServerLobby", "Client %d is not authorised to start selection.", @@ -7030,6 +7031,36 @@ bool ServerLobby::hasHostRights(STKPeer* peer) const return false; } // hasHostRights //----------------------------------------------------------------------------- +int ServerLobby::getPermissions(std::shared_ptr& peer) const +{ + return getPermissions(peer.get()); +} // getPermissions +//----------------------------------------------------------------------------- +int ServerLobby::getPermissions(STKPeer* peer) const +{ + int mask = 0; + mask |= CommandPermissions::PE_USUAL; + mask |= CommandPermissions::PE_VOTED; + if (peer == m_server_owner.lock().get()) + { + mask |= CommandPermissions::PE_CROWNED; + if (ServerConfig::m_only_host_riding) + mask |= CommandPermissions::PE_SINGLE; + } + if (peer->isAngryHost()) + { + mask |= CommandPermissions::PE_HAMMER; + } + else if (ServerConfig::m_soccer_tournament) + { + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (m_tournament_referees.count(username) > 0) + mask |= CommandPermissions::PE_HAMMER; + } + return mask; +} // getPermissions +//----------------------------------------------------------------------------- void ServerLobby::loadTracksQueueFromConfig() { std::vector tokens = StringUtils::split( @@ -7389,21 +7420,24 @@ void ServerLobby::setTeamMateHitOwner(unsigned int ownerID, uint16_t ticks_since m_teammate_karts_hit.clear(); m_teammate_karts_exploded.clear(); m_collecting_teammate_hit_info = true; -} +} // setTeamMateHitOwner +//----------------------------------------------------------------------------- void ServerLobby::registerTeamMateHit(unsigned int kartID) { // only register if we know the item owner and victim is still racing if (m_collecting_teammate_hit_info && !World::getWorld()->getKart(kartID)->hasFinishedRace()) m_teammate_karts_hit.push_back(kartID); -} +} // registerTeamMateHit +//----------------------------------------------------------------------------- void ServerLobby::registerTeamMateExplode(unsigned int kartID) { // only register if we know the item owner and victim is still racing if (m_collecting_teammate_hit_info && !World::getWorld()->getKart(kartID)->hasFinishedRace()) m_teammate_karts_exploded.push_back(kartID); -} +} // registerTeamMateExplode +//----------------------------------------------------------------------------- void ServerLobby::sendTeamMateHitMsg(std::string& s) { @@ -7416,7 +7450,8 @@ void ServerLobby::sendTeamMateHitMsg(std::string& s) sendStringToAllPeers(s); } } -} +} // sendTeamMateHitMsg +//----------------------------------------------------------------------------- void ServerLobby::handleTeamMateHits() { @@ -7546,7 +7581,8 @@ void ServerLobby::handleTeamMateHits() } } } -} +} // handleTeamMateHits +//----------------------------------------------------------------------------- void ServerLobby::handleSwatterHit(unsigned int ownerID, unsigned int victimID, bool success, bool has_hit_kart, uint16_t ticks_active) @@ -7583,4 +7619,11 @@ void ServerLobby::handleSwatterHit(unsigned int ownerID, unsigned int victimID, // we cannot do this here, will be done in update() m_teammate_swatter_punish.push_back(owner); } -} +} // handleSwatterHit +//----------------------------------------------------------------------------- + +bool ServerLobby::isSoccerGoalTarget() const +{ + return m_game_setup->isSoccerGoalTarget(); +} // isSoccerGoalTarget +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index c59c893d7a3..7e3456129ce 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -49,7 +49,6 @@ class NetworkString; class NetworkPlayerProfile; class STKPeer; class SocketAddress; -// class CommandManager; namespace Online { @@ -420,6 +419,7 @@ class ServerLobby : public LobbyProtocol // trigger teammate hits anymore const float MAX_BOWL_TEAMMATE_HIT_TIME = 2.0f; + friend CommandManager; CommandManager m_command_manager; // connection management @@ -619,6 +619,12 @@ class ServerLobby : public LobbyProtocol void sendStringToPeer(std::string& s, std::shared_ptr& peer) const; void sendStringToPeer(std::string& s, STKPeer* peer) const; void sendStringToAllPeers(std::string& s); + int getPermissions(std::shared_ptr& peer) const; + int getPermissions(STKPeer* peer) const; + bool hasConsentOnReplays() const { return m_consent_on_replays; } + void setConsentOnReplays(bool value) { m_consent_on_replays = value; } + bool isSoccerGoalTarget() const; + #ifdef ENABLE_SQLITE3 std::string getRecord(std::string& track, std::string& mode, std::string& direction, int laps); From 502e523fec65274b63337f35efc7fe3572cf375f Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 11 Sep 2021 00:22:07 +0300 Subject: [PATCH 135/830] Add the remaining commands, fix them a bit, fix muteall --- src/network/protocols/command_manager.cpp | 1749 ++++++++++++++++++++- src/network/protocols/command_manager.hpp | 83 +- src/network/protocols/server_lobby.cpp | 17 +- 3 files changed, 1797 insertions(+), 52 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 06f5100b38e..84d98d5d6e5 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -19,48 +19,48 @@ #include "network/protocols/command_manager.hpp" #include "addons/addon.hpp" -#include "config/user_config.hpp" -#include "items/network_item_manager.hpp" -#include "items/powerup_manager.hpp" -#include "items/attachment.hpp" -#include "karts/controller/player_controller.hpp" -#include "karts/kart_properties.hpp" -#include "karts/kart_properties_manager.hpp" -#include "karts/official_karts.hpp" -#include "modes/capture_the_flag.hpp" +// #include "config/user_config.hpp" +// #include "items/network_item_manager.hpp" +// #include "items/powerup_manager.hpp" +// #include "items/attachment.hpp" +// #include "karts/controller/player_controller.hpp" +// #include "karts/kart_properties.hpp" +// #include "karts/kart_properties_manager.hpp" +// #include "karts/official_karts.hpp" +// #include "modes/capture_the_flag.hpp" #include "modes/soccer_world.hpp" -#include "modes/linear_world.hpp" +// #include "modes/linear_world.hpp" #include "network/crypto.hpp" #include "network/event.hpp" #include "network/game_setup.hpp" -#include "network/network.hpp" -#include "network/network_config.hpp" +// #include "network/network.hpp" +// #include "network/network_config.hpp" #include "network/network_player_profile.hpp" -#include "network/peer_vote.hpp" -#include "network/protocol_manager.hpp" -#include "network/protocols/connect_to_peer.hpp" +// #include "network/peer_vote.hpp" +// #include "network/protocol_manager.hpp" +// #include "network/protocols/connect_to_peer.hpp" #include "network/protocols/command_permissions.hpp" -#include "network/protocols/game_protocol.hpp" -#include "network/protocols/game_events_protocol.hpp" +// #include "network/protocols/game_protocol.hpp" +// #include "network/protocols/game_events_protocol.hpp" #include "network/protocols/server_lobby.hpp" -#include "network/race_event_manager.hpp" +// #include "network/race_event_manager.hpp" #include "network/server_config.hpp" -#include "network/socket_address.hpp" +// #include "network/socket_address.hpp" #include "network/stk_host.hpp" -#include "network/stk_ipv6.hpp" +// #include "network/stk_ipv6.hpp" #include "network/stk_peer.hpp" -#include "online/online_profile.hpp" -#include "online/request_manager.hpp" -#include "online/xml_request.hpp" -#include "race/race_manager.hpp" -#include "tracks/check_manager.hpp" -#include "tracks/track.hpp" -#include "tracks/track_manager.hpp" +// #include "online/online_profile.hpp" +// #include "online/request_manager.hpp" +// #include "online/xml_request.hpp" +// #include "race/race_manager.hpp" +// #include "tracks/check_manager.hpp" +// #include "tracks/track.hpp" +// #include "tracks/track_manager.hpp" #include "utils/log.hpp" #include "utils/random_generator.hpp" #include "utils/string_utils.hpp" -#include "utils/time.hpp" -#include "utils/translation.hpp" +// #include "utils/time.hpp" +// #include "utils/translation.hpp" #include #include @@ -73,13 +73,79 @@ void CommandManager::initCommands() { - m_commands.emplace_back("commands", &CommandManager::process_commands, UP_EVERYONE); - m_commands.emplace_back("replay", &CommandManager::process_replay, UP_SINGLE); - m_commands.emplace_back("start", &CommandManager::process_start, UP_EVERYONE); - m_commands.emplace_back("config", &CommandManager::process_config, UP_CROWNED); + m_commands.emplace_back("commands", &CommandManager::process_commands, UP_EVERYONE); + m_commands.emplace_back("replay", &CommandManager::process_replay, UP_SINGLE); + m_commands.emplace_back("start", &CommandManager::process_start, UP_EVERYONE); + m_commands.emplace_back("config", &CommandManager::process_config, UP_CROWNED); + m_commands.emplace_back("spectate", &CommandManager::process_spectate, UP_EVERYONE); + m_commands.emplace_back("addons", &CommandManager::process_addons, UP_EVERYONE); + m_commands.emplace_back("moreaddons", &CommandManager::process_addons, UP_EVERYONE); + m_commands.emplace_back("listserveraddon", &CommandManager::process_lsa, UP_EVERYONE); + m_commands.emplace_back("playerhasaddon", &CommandManager::process_pha, UP_EVERYONE); + m_commands.emplace_back("kick", &CommandManager::process_kick, UP_CROWNED); + m_commands.emplace_back("kickban", &CommandManager::process_kick, UP_HAMMER); + m_commands.emplace_back("unban", &CommandManager::process_unban, UP_HAMMER); + m_commands.emplace_back("ban", &CommandManager::process_unban, UP_HAMMER); + m_commands.emplace_back("playeraddonscore", &CommandManager::process_pas, UP_EVERYONE); + m_commands.emplace_back("serverhasaddon", &CommandManager::process_sha, UP_EVERYONE); + m_commands.emplace_back("mute", &CommandManager::process_mute, UP_EVERYONE); + m_commands.emplace_back("unmute", &CommandManager::process_unmute, UP_EVERYONE); + m_commands.emplace_back("listmute", &CommandManager::process_listmute, UP_EVERYONE); + m_commands.emplace_back("help", &CommandManager::process_text, UP_EVERYONE); + m_commands.emplace_back("gnu", &CommandManager::process_gnu, UP_CROWNED); + m_commands.emplace_back("nognu", &CommandManager::process_nognu, UP_CROWNED); + m_commands.emplace_back("tell", &CommandManager::process_tell, UP_EVERYONE); + m_commands.emplace_back("standings", &CommandManager::process_standings, UP_EVERYONE); + m_commands.emplace_back("teamchat" , &CommandManager::process_teamchat, UP_EVERYONE); + m_commands.emplace_back("to", &CommandManager::process_to, UP_EVERYONE); + m_commands.emplace_back("public", &CommandManager::process_public, UP_EVERYONE); + m_commands.emplace_back("record", &CommandManager::process_record, UP_EVERYONE); + m_commands.emplace_back("power", &CommandManager::process_power, UP_EVERYONE); + m_commands.emplace_back("length", &CommandManager::process_length, UP_SINGLE); + m_commands.emplace_back("queue", &CommandManager::process_queue, UP_SINGLE); + m_commands.emplace_back("adminstart", &CommandManager::process_adminstart, UP_HAMMER); + m_commands.emplace_back("shuffle", &CommandManager::process_shuffle, UP_HAMMER); + m_commands.emplace_back("timeout", &CommandManager::process_timeout, UP_HAMMER); + m_commands.emplace_back("team", &CommandManager::process_team, UP_HAMMER); + m_commands.emplace_back("cat+", &CommandManager::process_cat, UP_HAMMER); + m_commands.emplace_back("cat-", &CommandManager::process_cat, UP_HAMMER); + m_commands.emplace_back("cat*", &CommandManager::process_cat, UP_HAMMER); + m_commands.emplace_back("troll", &CommandManager::process_troll, UP_HAMMER); + m_commands.emplace_back("hitmsg", &CommandManager::process_hitmsg, UP_HAMMER); + m_commands.emplace_back("teamhit", &CommandManager::process_teamhit, UP_HAMMER); + m_commands.emplace_back("version", &CommandManager::process_text, UP_EVERYONE); + m_commands.emplace_back("clear", &CommandManager::process_text, UP_EVERYONE); + m_commands.emplace_back("register", &CommandManager::process_register, UP_EVERYONE); +#ifdef ENABLE_WEB_SUPPORT + m_commands.emplace_back("token", &CommandManager::process_token, UP_EVERYONE); +#endif + m_commands.emplace_back("muteall", &CommandManager::process_muteall, UP_EVERYONE, CS_SOCCER_TOURNAMENT); + m_commands.emplace_back("game", &CommandManager::process_game, UP_HAMMER, CS_SOCCER_TOURNAMENT); + m_commands.emplace_back("role", &CommandManager::process_role, UP_HAMMER, CS_SOCCER_TOURNAMENT); + m_commands.emplace_back("stop", &CommandManager::process_stop, UP_HAMMER, CS_SOCCER_TOURNAMENT); + m_commands.emplace_back("go", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT); + m_commands.emplace_back("play", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT); + m_commands.emplace_back("resume", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT); + m_commands.emplace_back("lobby", &CommandManager::process_lobby, UP_HAMMER, CS_SOCCER_TOURNAMENT); + m_commands.emplace_back("init", &CommandManager::process_init, UP_HAMMER, CS_SOCCER_TOURNAMENT); + + m_commands.emplace_back("mimiz", &CommandManager::process_mimiz, UP_EVERYONE); + + addTextResponse("help", StringUtils::wideToUtf8(m_lobby->m_help_message)); + addTextResponse("version", "1.3-rc1 k 210fff beta"); + addTextResponse("clear", std::string(30, '\n')); } // initCommands // ======================================================================== +CommandManager::CommandManager(ServerLobby* lobby): + m_lobby(lobby) +{ + if (!lobby) + return; + initCommands(); +} // CommandManager +// ======================================================================== + void CommandManager::handleCommand(Event* event, std::shared_ptr peer) { NetworkString& data = event->data(); @@ -94,7 +160,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) int permissions = m_lobby->getPermissions(peer); bool found_command = false; - for (const auto& command: m_commands) + for (auto& command: m_commands) { if (argv[0] == command.m_name) { @@ -106,7 +172,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) } else { - Context context(event, peer, argv); + Context context(event, peer, argv, cmd, permissions); (this->*command.m_action)(context); } } @@ -124,17 +190,44 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) } // handleCommand // ======================================================================== +int CommandManager::getCurrentScope() +{ + int mask = CS_ALWAYS; + if (ServerConfig::m_soccer_tournament) + mask |= CS_SOCCER_TOURNAMENT; + return mask; +} // getCurrentScope +// ======================================================================== + +bool CommandManager::isAvailable(const Command& c) +{ + return (getCurrentScope() & c.m_scope) != 0; +} // getCurrentScope +// ======================================================================== + +void CommandManager::process_text(Context& context) +{ + std::string response; + auto it = m_text_response.find(context.m_argv[0]); + if (it == m_text_response.end()) + response = "Error: a text command " + context.m_argv[0] + + " is defined without text"; + else + response = it->second; + m_lobby->sendStringToPeer(response, context.m_peer); +} // process_commands +// ======================================================================== + void CommandManager::process_commands(Context& context) { - std::string result = ""; + std::string result = "Available commands:"; for (const Command& c: m_commands) { - result += c.m_name + " "; + if ((context.m_user_permissions & c.m_permissions) != 0 + && isAvailable(c)) + result += " " + c.m_name; } - if (!result.empty()) - result.pop_back(); - m_lobby->sendStringToPeer(result, context.m_peer); } // process_commands // ======================================================================== @@ -217,3 +310,1579 @@ void CommandManager::process_config(Context& context) m_lobby->handleServerConfiguration(context.m_peer, difficulty, mode, goal_target); } // process_config // ======================================================================== + +void CommandManager::process_spectate(Context& context) +{ + std::string response = ""; + auto& argv = context.m_argv; + auto peer = context.m_peer; + + if (ServerConfig::m_soccer_tournament || ServerConfig::m_only_host_riding) + response = "All spectators already have auto spectate ability"; + + if (/*m_game_setup->isGrandPrix() || */!ServerConfig::m_live_players) + response = "Server doesn't support spectating"; + + if (!response.empty()) + { + m_lobby->sendStringToPeer(response, peer); + return; + } + + if (argv.size() == 1) + { + if (m_lobby->m_state.load() != m_lobby->WAITING_FOR_START_GAME) + { + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (m_lobby->m_default_always_spectate_peers.count(peer.get())) + argv.push_back("0"); + else + argv.push_back("1"); + } + else + { + if (peer->alwaysSpectate()) + argv.push_back("0"); + else + argv.push_back("1"); + } + } + + if (argv.size() != 2 || (argv[1] != "0" && argv[1] != "1")) + { + std::string msg = "Usage: /spectate [empty or 0 or 1]"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + + if (m_lobby->m_state.load() != m_lobby->WAITING_FOR_START_GAME) + { + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (argv[1] == "1") + m_lobby->m_default_always_spectate_peers.insert(peer.get()); + else + m_lobby->m_default_always_spectate_peers.erase(peer.get()); + return; + } + + if (argv[1] == "1") + { + if (m_lobby->m_process_type == PT_CHILD && + peer->getHostId() == m_lobby->m_client_server_host_id.load()) + { + std::string msg = "Graphical client server cannot spectate"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + peer->setAlwaysSpectate(ASM_COMMAND); + } + else + peer->setAlwaysSpectate(ASM_NONE); + m_lobby->updatePlayerList(); +} // process_spectate +// ======================================================================== + +void CommandManager::process_addons(Context& context) +{ + auto& argv = context.m_argv; + bool more = (argv[0] == "moreaddons"); + if (argv.size() == 1) + { + argv.push_back(""); + switch (m_lobby->m_game_mode.load()) + { + case 0: + case 1: + case 3: + case 4: + argv[1] = "track"; + break; + case 6: + argv[1] = "soccer"; + break; + case 7: + case 8: + argv[1] = "arena"; + break; + } + } + const std::set& from = + (argv[1] == "kart" ? m_lobby->m_addon_kts.first : + (argv[1] == "track" ? m_lobby->m_addon_kts.second : + (argv[1] == "arena" ? m_lobby->m_addon_arenas : + /*argv[1] == "soccer" ?*/ m_lobby->m_addon_soccers + ))); + std::vector>> result; + for (const std::string& s: from) + result.push_back({s, {}}); + + auto peers = STKHost::get()->getPeers(); + int num_players = 0; + for (auto peer : peers) + { + if (!peer || !peer->isValidated() || peer->isWaitingForGame() || !m_lobby->canRace(peer)) + continue; + ++num_players; + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + const auto& kt = peer->getClientAssets(); + const auto& container = (argv[1] == "kart" ? kt.first : kt.second); + for (auto& p: result) + if (container.find(p.first) == container.end()) + p.second.push_back(username); + } + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(result.begin(), result.end(), g); + std::stable_sort(result.begin(), result.end(), + [](const std::pair>& a, + const std::pair>& b) -> bool { + if (a.second.size() != b.second.size()) + return a.second.size() > b.second.size(); + return false; + }); + std::string response; + const int NEXT_ADDONS = 5; + std::vector all_have; + while (!result.empty() && (int)result.back().second.size() == 0) + { + all_have.push_back(result.back().first); + result.pop_back(); + } + if (num_players > 0) { + response = "Found " + std::to_string(all_have.size()) + " asset(s)"; + std::reverse(result.begin(), result.end()); + if (result.size() > NEXT_ADDONS) + result.resize(NEXT_ADDONS); + if (!more) + { + bool nothing = true; + for (const std::string& s: all_have) + { + if (s.length() < 6 || s.substr(0, 6) != "addon_") + continue; + response.push_back(nothing ? ':' : ','); + nothing = false; + response.push_back(' '); + response += s.substr(6); + } + if (response.length() > 100) + response += "\nTotal: " + std::to_string(all_have.size()); + } + else + { + if (result.empty()) + response += "\nNothing more to install!"; + else + { + response += ". More addons to install:"; + for (unsigned i = 0; i < result.size(); ++i) + { + response += "\n" + result[i].first + ", missing for " + + std::to_string(result[i].second.size()) + + " player(s):"; + std::sort(result[i].second.begin(), result[i].second.end()); + for (unsigned j = 0; j < result[i].second.size(); ++j) + { + response += " " + result[i].second[j]; + } + } + } + } + } else { + response = "No one in the lobby can play. Found " + + std::to_string(all_have.size()) + " assets on the server."; + } + m_lobby->sendStringToPeer(response, context.m_peer); +} // process_addons +// ======================================================================== + +void CommandManager::process_lsa(Context& context) +{ + std::string response = ""; + auto& argv = context.m_argv; + bool has_options = argv.size() > 1 && + (argv[1].compare("-track") == 0 || + argv[1].compare("-arena") == 0 || + argv[1].compare("-kart") == 0 || + argv[1].compare("-soccer") == 0); + if (argv.size() == 1 || argv.size() > 3 || argv[1].size() < 3 || + (argv.size() == 2 && (argv[1].size() < 3 || has_options)) || + (argv.size() == 3 && (!has_options || argv[2].size() < 3))) + { + response = "Usage: /listserveraddon [option][addon string to find " + "(at least 3 characters)]. Available options: " + "-track, -arena, -kart, -soccer."; + } + else + { + std::string type = ""; + std::string text = ""; + if (argv.size() > 1) + { + if (argv[1].compare("-track") == 0 || + argv[1].compare("-arena") == 0 || + argv[1].compare("-kart") == 0 || + argv[1].compare("-soccer") == 0) + type = argv[1].substr(1); + if ((argv.size() == 2 && type.empty()) || argv.size() == 3) + text = argv[argv.size() - 1]; + } + + std::set total_addons; + if (type.empty() || // not specify addon type + (!type.empty() && type.compare("kart") == 0)) // list kart addon + { + total_addons.insert(m_lobby->m_addon_kts.first.begin(), m_lobby->m_addon_kts.first.end()); + } + if (type.empty() || // not specify addon type + (!type.empty() && type.compare("track") == 0)) + { + total_addons.insert(m_lobby->m_addon_kts.second.begin(), m_lobby->m_addon_kts.second.end()); + } + if (type.empty() || // not specify addon type + (!type.empty() && type.compare("arena") == 0)) + { + total_addons.insert(m_lobby->m_addon_arenas.begin(), m_lobby->m_addon_arenas.end()); + } + if (type.empty() || // not specify addon type + (!type.empty() && type.compare("soccer") == 0)) + { + total_addons.insert(m_lobby->m_addon_soccers.begin(), m_lobby->m_addon_soccers.end()); + } + std::string msg = ""; + for (auto& addon : total_addons) + { + // addon_ (6 letters) + if (!text.empty() && addon.find(text, 6) == std::string::npos) + continue; + + msg += addon.substr(6); + msg += ", "; + } + if (msg.empty()) + response = "Addon not found"; + else + { + msg = msg.substr(0, msg.size() - 2); + response = "Server's addons: " + msg; + } + } + m_lobby->sendStringToPeer(response, context.m_peer); +} // process_lsa +// ======================================================================== + +void CommandManager::process_pha(Context& context) +{ + std::string response = ""; + std::string cmd = context.m_cmd; + std::string part; + if (cmd.length() > 15) + part = cmd.substr(15); + std::string addon_id = part.substr(0, part.find(' ')); + std::string player_name; + if (part.length() > addon_id.length() + 1) + player_name = part.substr(addon_id.length() + 1); + std::shared_ptr player_peer = STKHost::get()->findPeerByName( + StringUtils::utf8ToWide(player_name)); + if (player_name.empty() || !player_peer || addon_id.empty()) + { + response = "Usage: /playerhasaddon [addon_identity] [player name]"; + } + else + { + std::string addon_id_test = Addon::createAddonId(addon_id); + bool found = false; + const auto& kt = player_peer->getClientAssets(); + for (auto& kart : kt.first) + { + if (kart == addon_id_test) + { + found = true; + break; + } + } + if (!found) + { + for (auto& track : kt.second) + { + if (track == addon_id_test) + { + found = true; + break; + } + } + } + if (found) + { + response = player_name + " has addon " + addon_id; + } + else + { + response = player_name + " has no addon " + addon_id; + } + } + m_lobby->sendStringToPeer(response, context.m_peer); +} // process_pha +// ======================================================================== + +void CommandManager::process_kick(Context& context) +{ + auto& cmd = context.m_cmd; + auto& peer = context.m_peer; + std::string player_name; + if (StringUtils::startsWith(cmd, "kickban")) + { + if (cmd.length() > 8) + player_name = cmd.substr(8); + } + else if (cmd.length() > 5) + { + player_name = cmd.substr(5); + } + std::shared_ptr player_peer = STKHost::get()->findPeerByName( + StringUtils::utf8ToWide(player_name)); + if (player_name.empty() || !player_peer || player_peer->isAIPeer()) + { + std::string msg = "Usage: /kick [player name]"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (player_peer->isAngryHost()) + { + std::string msg = "This player is the owner of this server, " + "and is protected from your actions now"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (!peer->isAngryHost() && !ServerConfig::m_kicks_allowed) + { + std::string msg = "Kicking players is not allowed on this server"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + Log::info("CommandManager", "Crown player kicks %s", player_name.c_str()); + player_peer->kick(); + if (ServerConfig::m_track_kicks) + { + std::string auto_report = "[ Auto report caused by kick ]"; + m_lobby->writeOwnReport(player_peer.get(), peer.get(), auto_report); + } + if (StringUtils::startsWith(cmd, "kickban")) + { + Log::info("CommandManager", "%s is now banned", player_name.c_str()); + m_lobby->m_temp_banned.insert(player_name); + std::string msg = StringUtils::insertValues( + "%s is now banned", player_name.c_str()); + m_lobby->sendStringToPeer(msg, peer); + } +} // process_kick +// ======================================================================== + +void CommandManager::process_unban(Context& context) +{ + std::string player_name; + auto& cmd = context.m_cmd; + if (cmd.length() > 6) + { + player_name = cmd.substr(6); + } + if (player_name.empty()) + { + std::string msg = "Usage: /unban [player name]"; + m_lobby->sendStringToPeer(msg, context.m_peer); + } + else + { + Log::info("CommandManager", "%s is now unbanned", player_name.c_str()); + m_lobby->m_temp_banned.erase(player_name); + std::string msg = StringUtils::insertValues( + "%s is now unbanned", player_name.c_str()); + m_lobby->sendStringToPeer(msg, context.m_peer); + } +} // process_unban +// ======================================================================== + +void CommandManager::process_ban(Context& context) +{ + std::string player_name; + auto& cmd = context.m_cmd; + if (cmd.length() > 4) + { + player_name = cmd.substr(4); + } + if (player_name.empty()) + { + std::string msg = "Usage: /ban [player name]"; + m_lobby->sendStringToPeer(msg, context.m_peer); + } + else + { + Log::info("CommandManager", "%s is now banned", player_name.c_str()); + m_lobby->m_temp_banned.insert(player_name); + std::string msg = StringUtils::insertValues( + "%s is now banned", player_name.c_str()); + m_lobby->sendStringToPeer(msg, context.m_peer); + } +} // process_ban +// ======================================================================== + +void CommandManager::process_pas(Context& context) +{ + std::string response; + std::string player_name; + auto& cmd = context.m_cmd; + if (cmd.length() > 17) + player_name = cmd.substr(17); + std::shared_ptr player_peer = STKHost::get()->findPeerByName( + StringUtils::utf8ToWide(player_name)); + if (player_name.empty() || !player_peer) + { + response = "Usage: /playeraddonscore [player name] " + "(returns the number of addons, not a percentage)"; + } + else + { + auto& scores = player_peer->getAddonsScores(); + if (scores[AS_KART] == -1 && scores[AS_TRACK] == -1 && + scores[AS_ARENA] == -1 && scores[AS_SOCCER] == -1) + { + response = player_name + " has no addons"; + } + else + { + std::string msg = player_name; + msg += " addons:"; + if (scores[AS_KART] != -1) + msg += " karts: " + StringUtils::toString(scores[AS_KART]) + ","; + if (scores[AS_TRACK] != -1) + msg += " tracks: " + StringUtils::toString(scores[AS_TRACK]) + ","; + if (scores[AS_ARENA] != -1) + msg += " arenas: " + StringUtils::toString(scores[AS_ARENA]) + ","; + if (scores[AS_SOCCER] != -1) + msg += " fields: " + StringUtils::toString(scores[AS_SOCCER]) + ","; + msg.pop_back(); + response = msg; + } + } + m_lobby->sendStringToPeer(response, context.m_peer); +} // process_pas +// ======================================================================== + +void CommandManager::process_sha(Context& context) +{ + std::string response; + auto& argv = context.m_argv; + if (argv.size() != 2) + { + response = "Usage: /serverhasaddon [addon_identity]"; + } + else + { + std::set total_addons; + total_addons.insert(m_lobby->m_addon_kts.first.begin(), m_lobby->m_addon_kts.first.end()); + total_addons.insert(m_lobby->m_addon_kts.second.begin(), m_lobby->m_addon_kts.second.end()); + total_addons.insert(m_lobby->m_addon_arenas.begin(), m_lobby->m_addon_arenas.end()); + total_addons.insert(m_lobby->m_addon_soccers.begin(), m_lobby->m_addon_soccers.end()); + std::string addon_id_test = Addon::createAddonId(argv[1]); + bool found = total_addons.find(addon_id_test) != total_addons.end(); + if (found) + { + response = "Server has addon " + argv[1]; + } + else + { + response = "Server has no addon " + argv[1]; + } + } + m_lobby->sendStringToPeer(response, context.m_peer); +} // process_sha +// ======================================================================== + +void CommandManager::process_mute(Context& context) +{ + std::shared_ptr player_peer; + auto& argv = context.m_argv; + auto& peer = context.m_peer; + std::string result_msg; + core::stringw player_name; + + if (argv.size() != 2 || argv[1].empty()) + { + std::string msg = "Usage: /mute player_name (not including yourself)"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + + player_name = StringUtils::utf8ToWide(argv[1]); + player_peer = STKHost::get()->findPeerByName(player_name); + + if (!player_peer || player_peer == peer) + { + std::string msg = "Usage: /mute player_name (not including yourself)"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + + m_lobby->m_peers_muted_players[peer].insert(player_name); + result_msg = "Muted player " + argv[1]; + m_lobby->sendStringToPeer(result_msg, context.m_peer); +} // process_mute +// ======================================================================== + +void CommandManager::process_unmute(Context& context) +{ + std::shared_ptr player_peer; + auto& argv = context.m_argv; + auto& peer = context.m_peer; + std::string result_msg; + core::stringw player_name; + + if (argv.size() != 2 || argv[1].empty()) + { + result_msg = "Usage: /unmute player_name"; + m_lobby->sendStringToPeer(result_msg, context.m_peer); + return; + } + + player_name = StringUtils::utf8ToWide(argv[1]); + for (auto it = m_lobby->m_peers_muted_players[peer].begin(); + it != m_lobby->m_peers_muted_players[peer].end();) + { + if (*it == player_name) + { + it = m_lobby->m_peers_muted_players[peer].erase(it); + result_msg = "Unmuted player " + argv[1]; + m_lobby->sendStringToPeer(result_msg, context.m_peer); + return; + } + else + { + it++; + } + } + + result_msg = "Usage: /unmute player_name"; + m_lobby->sendStringToPeer(result_msg, context.m_peer); +} // process_unmute +// ======================================================================== + +void CommandManager::process_listmute(Context& context) +{ + auto& peer = context.m_peer; + std::string response; + int num_players = 0; + for (auto& name : m_lobby->m_peers_muted_players[peer]) + { + response += StringUtils::wideToUtf8(name); + response += " "; + ++num_players; + } + if (num_players == 0) + response = "No player has been muted by you"; + else + { + response += (num_players == 1 ? "is" : "are"); + response += " muted (total: " + std::to_string(num_players) + ")"; + } + + m_lobby->sendStringToPeer(response, peer); +} // process_listmute +// ======================================================================== + +void CommandManager::process_gnu(Context& context) +{ + if (m_lobby->m_kart_elimination.isEnabled()) + { + std::string msg = "Gnu Elimination mode was already enabled!"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_NORMAL_RACE && + RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) + { + std::string msg = "Gnu Elimination is available only with racing modes"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + auto& argv = context.m_argv; + if (argv.size() > 1 && m_lobby->m_available_kts.first.count(argv[1]) > 0) + { + m_lobby->m_kart_elimination.enable(argv[1]); + } else { + m_lobby->m_kart_elimination.enable("gnu"); + } + std::string msg = m_lobby->m_kart_elimination.getStartingMessage(); + m_lobby->sendStringToAllPeers(msg); +} // process_gnu +// ======================================================================== + +void CommandManager::process_nognu(Context& context) +{ + if (!m_lobby->m_kart_elimination.isEnabled()) + { + std::string msg = "Gnu Elimination mode was already off!"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + + m_lobby->m_kart_elimination.disable(); + std::string msg = "Gnu Elimination is now off"; + m_lobby->sendStringToAllPeers(msg); +} // process_nognu +// ======================================================================== + +void CommandManager::process_tell(Context& context) +{ + auto& argv = context.m_argv; + if (argv.size() == 1) + { + std::string response = "Tell something non-empty"; + m_lobby->sendStringToPeer(response, context.m_peer); + return; + } + std::string ans; + for (unsigned i = 1; i < argv.size(); ++i) + { + if (i > 1) + ans.push_back(' '); + ans += argv[i]; + } + m_lobby->writeOwnReport(context.m_peer.get(), context.m_peer.get(), ans); +} // process_tell +// ======================================================================== + +void CommandManager::process_standings(Context& context) +{ + std::string msg; + auto& argv = context.m_argv; + if (argv.size() > 1) + { + if (argv[1] == "gp") + msg = m_lobby->getGrandPrixStandings(); + else if (argv[1] == "gnu") + msg = m_lobby->m_kart_elimination.getStandings(); + else + msg = "Usage: /standings [gp | gnu]"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (m_lobby->m_game_setup->isGrandPrix()) + msg = m_lobby->getGrandPrixStandings(); + else + msg = m_lobby->m_kart_elimination.getStandings(); + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_standings +// ======================================================================== + +void CommandManager::process_teamchat(Context& context) +{ + m_lobby->m_team_speakers.insert(context.m_peer.get()); + std::string msg = "Your messages are now addressed to team only"; + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_teamchat +// ======================================================================== + +void CommandManager::process_to(Context& context) +{ + auto& argv = context.m_argv; + if (argv.size() == 1) + { + std::string msg = "Usage: /to (username1) ... (usernameN)"; + m_lobby->sendStringToPeer(msg, context.m_peer); + } else { + auto& peer = context.m_peer; + m_lobby->m_message_receivers[peer.get()].clear(); + for (unsigned i = 1; i < argv.size(); ++i) + { + m_lobby->m_message_receivers[peer.get()].insert( + StringUtils::utf8ToWide(argv[i])); + } + std::string msg = "Successfully changed chat settings"; + m_lobby->sendStringToPeer(msg, peer); + } +} // process_to +// ======================================================================== + +void CommandManager::process_public(Context& context) +{ + auto& peer = context.m_peer; + m_lobby->m_message_receivers[peer.get()].clear(); + m_lobby->m_team_speakers.erase(peer.get()); + std::string s = "Your messages are now public"; + m_lobby->sendStringToPeer(s, peer); +} // process_public +// ======================================================================== + +void CommandManager::process_record(Context& context) +{ + std::string response; + auto& argv = context.m_argv; +#ifdef ENABLE_SQLITE3 + if (argv.size() < 5) + { + response = "Usage: /record (track id) " + "(normal/time-trial) (normal/reverse) (laps)\n" + "Receives the server record for the race settings if any"; + } else { + bool error = false; + std::string track_name = argv[1]; + std::string mode_name = (argv[2] == "t" || argv[2] == "tt" + || argv[2] == "time-trial" || argv[2] == "timetrial" ? + "time-trial" : "normal"); + std::string reverse_name = (argv[3] == "r" || + argv[3] == "rev" || argv[3] == "reverse" ? "reverse" : + "normal"); + int laps_count = -1; + if (!StringUtils::parseString(argv[4], &laps_count)) + error = true; + if (!error && laps_count < 0) + error = true; + if (error) + { + response = "Invalid lap count"; + } + else + { + response = m_lobby->getRecord(track_name, mode_name, reverse_name, laps_count); + } + } +#else + response = "This command is not supported."; +#endif + m_lobby->sendStringToPeer(response, context.m_peer); +} // process_record +// ======================================================================== + +void CommandManager::process_power(Context& context) +{ + auto& peer = context.m_peer; + auto& argv = context.m_argv; + if (peer->isAngryHost()) + { + peer->setAngryHost(false); + std::string msg = "You are now a normal player"; + m_lobby->sendStringToPeer(msg, peer); + m_lobby->updatePlayerList(); + return; + } + std::string password = ServerConfig::m_power_password; + if (password.empty() || argv.size() <= 1 || argv[1] != password) + { + std::string msg = "You need to provide the password to have the power"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + peer->setAngryHost(true); + std::string msg = "Now you finally have the power!"; + m_lobby->sendStringToPeer(msg, peer); + m_lobby->updatePlayerList(); +} // process_power +// ======================================================================== + +void CommandManager::process_length(Context& context) +{ + auto& argv = context.m_argv; + std::string msg; + if (argv.size() < 3) + { + msg = "Usage: /length (x (float) | = (int) | check | clear)"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (argv[1] == "check") + { + if (m_lobby->m_default_lap_multiplier < 0 && m_lobby->m_fixed_lap < 0) + msg = "Game length is currently chosen by players"; + else if (m_lobby->m_default_lap_multiplier > 0) + msg = StringUtils::insertValues( + "Game length is %f x default", + m_lobby->m_default_lap_multiplier); + else if (m_lobby->m_fixed_lap > 0) + msg = StringUtils::insertValues( + "Game length is %d", m_lobby->m_fixed_lap); + else + msg = StringUtils::insertValues( + "An error: game length is both %f x default and %d", + m_lobby->m_default_lap_multiplier, m_lobby->m_fixed_lap); + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (argv[1] == "clear") + { + m_lobby->m_default_lap_multiplier = -1.0; + m_lobby->m_fixed_lap = -1; + msg = "Game length will be chosen by players"; + m_lobby->sendStringToAllPeers(msg); + return; + } + double temp_double = -1.0; + int temp_int = -1; + if (argv[1] == "x" && argv.size() >= 3 && + StringUtils::parseString(argv[2], &temp_double)) + { + m_lobby->m_default_lap_multiplier = std::max(0.0, temp_double); + m_lobby->m_fixed_lap = -1; + msg = StringUtils::insertValues( + "Game length is now %f x default", + m_lobby->m_default_lap_multiplier); + m_lobby->sendStringToAllPeers(msg); + return; + } + if (argv[1] == "=" && argv.size() >= 3 && + StringUtils::parseString(argv[2], &temp_int)) + { + m_lobby->m_fixed_lap = std::max(0, temp_int); + m_lobby->m_default_lap_multiplier = -1.0; + msg = StringUtils::insertValues( + "Game length is now %d", m_lobby->m_fixed_lap); + m_lobby->sendStringToAllPeers(msg); + return; + } + msg = "Usage: /length (x (float) | = (int) | check | clear)"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; +} // process_length +// ======================================================================== + +void CommandManager::process_queue(Context& context) +{ + std::string msg; + auto& argv = context.m_argv; + std::string format_string = "Format: /queue (show | push[_front] (track) | pop[_back])"; + if (argv.size() < 3) + { + m_lobby->sendStringToPeer(format_string, context.m_peer); + return; + } + if (argv[1] == "show") + { + msg = "Queue:"; + for (const std::string& s: m_lobby->m_tracks_queue) { + msg += " " + s; + } + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (argv[1] == "push" || argv[1] == "push_back") + { + if (argv.size() < 3) + { + m_lobby->sendStringToPeer(format_string, context.m_peer); + return; + } + m_lobby->m_tracks_queue.push_back(argv[2]); + std::string msg = "Pushed " + argv[2] + + " to the back of queue, current queue size: " + + std::to_string(m_lobby->m_tracks_queue.size()); + m_lobby->sendStringToPeer(msg, context.m_peer); + } + else if (argv[1] == "push_front") + { + if (argv.size() < 3) + { + m_lobby->sendStringToPeer(format_string, context.m_peer); + return; + } + m_lobby->m_tracks_queue.push_front(argv[2]); + std::string msg = "Pushed " + argv[2] + + " to the front of queue, current queue size: " + + std::to_string(m_lobby->m_tracks_queue.size()); + m_lobby->sendStringToPeer(msg, context.m_peer); + } + else if (argv[1] == "pop" || argv[1] == "pop_back") + { + msg = ""; + if (m_lobby->m_tracks_queue.empty()) { + msg = "Queue was empty before."; + } + else + { + std::string msg = "Popped " + m_lobby->m_tracks_queue.front() + + "from the queue,"; + m_lobby->m_tracks_queue.pop_front(); + msg += " current queue size: " + + std::to_string(m_lobby->m_tracks_queue.size()); + } + m_lobby->sendStringToPeer(msg, context.m_peer); + } + else if (argv[1] == "pop_back") + { + msg = ""; + if (m_lobby->m_tracks_queue.empty()) { + msg = "Queue was empty before."; + } + else + { + std::string msg = "Popped " + m_lobby->m_tracks_queue.back() + + "from the queue,"; + m_lobby->m_tracks_queue.pop_back(); + msg += " current queue size: " + + std::to_string(m_lobby->m_tracks_queue.size()); + } + m_lobby->sendStringToPeer(msg, context.m_peer); + } +} // process_queue +// ======================================================================== + +void CommandManager::process_adminstart(Context& context) +{ + std::string msg; + auto& argv = context.m_argv; + if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) + { + msg = "Usage: /adminstart [0/1] - allow or forbid starting a race"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (argv[1] == "0") + { + m_lobby->m_allowed_to_start = false; + msg = "Now starting a race is forbidden"; + } + else + { + m_lobby->m_allowed_to_start = true; + msg = "Now starting a race is allowed"; + } + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_adminstart +// ======================================================================== + +void CommandManager::process_shuffle(Context& context) +{ + std::string msg; + auto& argv = context.m_argv; + if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) + { + msg = "Usage: /shuffle [0/1] - make the GP grid shuffled all the time, or make it result-based"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (argv[1] == "0") + { + m_lobby->m_shuffle_gp = false; + msg = "Now the GP grid is sorted by score"; + } else { + m_lobby->m_shuffle_gp = true; + msg = "Now the GP grid is shuffled"; + } + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_shuffle +// ======================================================================== + +void CommandManager::process_timeout(Context& context) +{ + std::string msg; + int seconds; + auto& argv = context.m_argv; + if (argv.size() < 2 || !StringUtils::parseString(argv[1], &seconds) || seconds <= 0) + { + msg = "Usage: /timeout [positive int x] - set timeout to x seconds"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + m_lobby->m_timeout.store((int64_t)StkTime::getMonoTimeMs() + + (int64_t)(seconds * 1000.0f)); + m_lobby->updatePlayerList(); + msg = "Successfully changed timeout"; + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_timeout +// ======================================================================== + +void CommandManager::process_team(Context& context) +{ + std::string msg; + auto& argv = context.m_argv; + if (argv.size() != 3) { + msg = "Usage: /team (color/0..6) (player) - move a player " + "to a team, or remove from teams (none/0)"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + auto it = m_lobby->m_team_name_to_index.find(argv[1]); + int index = (it == m_lobby->m_team_name_to_index.end() ? 0 : it->second); + std::string player; + auto wide_player_name = StringUtils::utf8ToWide(argv[2]); + std::shared_ptr player_peer = STKHost::get()->findPeerByWildcard( + wide_player_name, player); + // if player not found + if (!player_peer) + { + // don't use if wildcard + if (wide_player_name.find("*") != -1 || wide_player_name.find("?") != -1) + { + msg = "Player not found or not unique"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + else + { + // if no wildcard, reset player name to use for absent players + player = argv[2]; + } + } + for (const auto& pair: m_lobby->m_team_name_to_index) + { + if (pair.second < 0) + { + if (pair.second == -index) + { + m_lobby->m_player_categories[pair.first].insert(player); + m_lobby->m_categories_for_player[player].insert(pair.first); + } + else + { + m_lobby->m_player_categories[pair.first].erase(player); + m_lobby->m_categories_for_player[player].erase(pair.first); + } + } + } + index = abs(index); + m_lobby->m_team_for_player[player] = index; + wide_player_name = StringUtils::utf8ToWide(player); + if (player_peer) + { + for (auto& profile : player_peer.get()->getPlayerProfiles()) + { + if (profile->getName() == wide_player_name) + { + profile->setTemporaryTeam(index - 1); + break; + } + } + } + m_lobby->updatePlayerList(); +} // process_team +// ======================================================================== + +void CommandManager::process_cat(Context& context) +{ + std::string msg; + auto& argv = context.m_argv; + if (argv[0] == "cat+") + { + if (argv.size() != 3) { + msg = "Usage: /cat+ (category) (player) - add a player to a category"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + std::string category = argv[1]; + std::string player = argv[2]; + m_lobby->m_player_categories[category].insert(player); + m_lobby->m_categories_for_player[player].insert(category); + m_lobby->updatePlayerList(); + return; + } + if (argv[0] == "cat-") + { + if (argv.size() != 3) { + msg = "Usage: /cat- (category) (player) - remove a player from a category"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + std::string category = argv[1]; + std::string player = argv[2]; + m_lobby->m_player_categories[category].erase(player); + m_lobby->m_categories_for_player[player].erase(category); + m_lobby->updatePlayerList(); + return; + } + if (argv[0] == "cat*") + { + int displayed; + if (argv.size() != 3 || !StringUtils::parseString(argv[2], &displayed) + || displayed < 0 || displayed > 1) { + msg = "Usage: /cat* (category) (0|1) - make category displayed or not"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + std::string category = argv[1]; + if (displayed) { + m_lobby->m_hidden_categories.erase(category); + } else { + m_lobby->m_hidden_categories.insert(category); + } + m_lobby->updatePlayerList(); + return; + } +} // process_cat +// ======================================================================== + +void CommandManager::process_troll(Context& context) +{ + std::string msg; + auto& argv = context.m_argv; + if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) + { + msg = "Usage: /troll [0/1] - disable or enable anti troll system"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (argv[1] == "0") + { + m_lobby->m_troll_active = false; + msg = "Trolls can stay"; + } else { + m_lobby->m_troll_active = true; + msg = "Trolls will be kicked"; + } + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_troll +// ======================================================================== + +void CommandManager::process_hitmsg(Context& context) +{ + std::string msg; + auto& argv = context.m_argv; + if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) + { + msg = "Usage: /hitmsg [0/1] - disable or enable messages " + "if a player makes a teammate explode"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (argv[1] == "0") + { + m_lobby->m_show_teammate_hits = false; + msg = "Teammate hits will not be sent"; + } else { + m_lobby->m_show_teammate_hits = true; + msg = "Teammate hits will be sent to all players"; + } + m_lobby->sendStringToAllPeers(msg); +} // process_hitmsg +// ======================================================================== + +void CommandManager::process_teamhit(Context& context) +{ + std::string msg; + auto& argv = context.m_argv; + if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) + { + msg = "Usage: /teamhit [0/1] - disable or enable punish mode when hitting team mates"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (argv[1] == "0") + { + m_lobby->m_teammate_hit_mode = false; + msg = "Teammate hits are not punished now"; + } + else + { + m_lobby->m_teammate_hit_mode = true; + msg = "Teammate hits are punished now"; + } + m_lobby->sendStringToAllPeers(msg); +} // process_teamhit +// ======================================================================== + +void CommandManager::process_register(Context& context) +{ + auto& argv = context.m_argv; + auto& peer = context.m_peer; + int online_id = peer->getPlayerProfiles()[0]->getOnlineId(); + if (online_id <= 0) + { + std::string msg = "Please join with a valid online STK account."; + m_lobby->sendStringToPeer(msg, peer); + return; + } + std::string ans = ""; + for (unsigned i = 1; i < argv.size(); ++i) + { + if (i > 1) + ans.push_back(' '); + ans += argv[i]; + } + std::string message_ok = "Your registration request is being processed"; + std::string message_wrong = "Sorry, an error occurred. Please try again."; + if (m_lobby->writeOnePlayerReport(peer.get(), ServerConfig::m_register_table_name, + ans)) + m_lobby->sendStringToPeer(message_ok, peer); + else + m_lobby->sendStringToPeer(message_wrong, peer); +} // process_register +// ======================================================================== + +#ifdef ENABLE_WEB_SUPPORT +void CommandManager::process_token(Context& context) +{ + auto& peer = context.m_peer; + int online_id = peer->getPlayerProfiles()[0]->getOnlineId(); + if (online_id <= 0) + { + std::string msg = "Please join with a valid online STK account."; + m_lobby->sendStringToPeer(msg, peer); + return; + } + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + std::string token = m_lobby->getToken(); + while (m_lobby->m_web_tokens.count(token)) + token = m_lobby->getToken(); + m_lobby->m_web_tokens.insert(token); + std::string msg = "Your token is " + token; +#ifdef ENABLE_SQLITE3 + std::string tokens_table_name = ServerConfig::m_tokens_table; + std::string query = StringUtils::insertValues( + "INSERT INTO %s (username, token) " + "VALUES (\"%s\", \"%s\");", + tokens_table_name.c_str(), username.c_str(), token.c_str() + ); + // TODO fix injection!! + if (m_lobby->easySQLQuery(query)) + msg += "\nRetype it on the website to connect your STK account. "; + else + msg = "An error occurred, please try again."; +#else + msg += "\nThough it is useless..."; +#endif + m_lobby->sendStringToPeer(msg, peer); +} // process_token +#endif +// ======================================================================== + +void CommandManager::process_muteall(Context& context) +{ + auto& argv = context.m_argv; + auto& peer = context.m_peer; + std::string peer_username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (argv.size() >= 2 && argv[1] == "0") + { + m_lobby->m_tournament_mutealls.erase(peer_username); + } + else if (argv.size() >= 2 && argv[1] == "1") + { + m_lobby->m_tournament_mutealls.insert(peer_username); + } + else + { + if (m_lobby->m_tournament_mutealls.count(peer_username)) + m_lobby->m_tournament_mutealls.erase(peer_username); + else + m_lobby->m_tournament_mutealls.insert(peer_username); + } + std::string msg; + if (m_lobby->m_tournament_mutealls.count(peer_username)) + msg = "You are now receiving messages only from players and referees"; + else + msg = "You are now receiving messages from spectators too"; + m_lobby->sendStringToPeer(msg, peer); +} // process_muteall +// ======================================================================== + +void CommandManager::process_game(Context& context) +{ + auto& argv = context.m_argv; + auto& peer = context.m_peer; + std::string peer_username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + int old_game = m_lobby->m_tournament_game; + if (argv.size() < 2) + { + ++m_lobby->m_tournament_game; + if (m_lobby->m_tournament_game == m_lobby->m_tournament_max_games) + m_lobby->m_tournament_game = 0; + m_lobby->m_fixed_lap = ServerConfig::m_fixed_lap_count; + } else { + if (!StringUtils::parseString(argv[1], &m_lobby->m_tournament_game) + || m_lobby->m_tournament_game < 0 + || m_lobby->m_tournament_game >= m_lobby->m_tournament_max_games) + { + std::string msg = "Please specify a correct number. " + "Format: /game [number 0.." + + std::to_string(m_lobby->m_tournament_max_games - 1) + "] [length]"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + int length = 10; + if (argv.size() >= 3) + { + bool ok = StringUtils::parseString(argv[2], &length); + if (!ok || length <= 0) + { + std::string msg = "Please specify a correct number. " + "Format: /game [number] [length]"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + } + m_lobby->m_fixed_lap = length; + } + if (m_lobby->tournamentColorsSwapped(m_lobby->m_tournament_game) + ^ m_lobby->tournamentColorsSwapped(old_game)) + m_lobby->changeColors(); + if (m_lobby->tournamentGoalsLimit(m_lobby->m_tournament_game) + ^ m_lobby->tournamentGoalsLimit(old_game)) + m_lobby->changeLimitForTournament(m_lobby->tournamentGoalsLimit(m_lobby->m_tournament_game)); + std::string msg = StringUtils::insertValues( + "Ready to start game %d for %d ", m_lobby->m_tournament_game, m_lobby->m_fixed_lap) + + (m_lobby->tournamentGoalsLimit(m_lobby->m_tournament_game) ? "goals" : "minutes"); + m_lobby->sendStringToAllPeers(msg); + Log::info("CommandManager", "SoccerMatchLog: Game number changed from %d to %d", + old_game, m_lobby->m_tournament_game); +} // process_game +// ======================================================================== + +void CommandManager::process_role(Context& context) +{ + auto& argv = context.m_argv; + auto& peer = context.m_peer; + std::string peer_username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (argv.size() < 3) + { + std::string msg = "Format: /role (R|B|J|S) username"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + std::string role = argv[1]; + std::string username = argv[2]; + bool permanent = (argv.size() >= 4 && + (argv[3] == "p" || argv[3] == "permanent")); + if (role.length() != 1) + std::swap(role, username); + if (role.length() != 1) + { + std::string msg = "Please specify one-letter role (R/B/J/S) and player"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + if (role[0] >= 'A' && role[0] <= 'Z') + role[0] += 'a' - 'A'; + std::vector changed_usernames; + if (!username.empty()) + { + if (username[0] == '#') + { + std::string category = username.substr(1); + auto it = m_lobby->m_player_categories.find(category); + if (it != m_lobby->m_player_categories.end()) + { + for (const std::string& s: it->second) + { + changed_usernames.push_back(s); + } + } + } + else + { + changed_usernames.push_back(username); + } + } + for (const std::string& username: changed_usernames) + { + Log::info("CommandManager", "SoccerMatchLog: Role of %s changed to %s", + username.c_str(), role.c_str()); + m_lobby->m_tournament_red_players.erase(username); + m_lobby->m_tournament_blue_players.erase(username); + m_lobby->m_tournament_referees.erase(username); + if (permanent) + { + m_lobby->m_tournament_init_red.erase(username); + m_lobby->m_tournament_init_blue.erase(username); + m_lobby->m_tournament_init_ref.erase(username); + } + std::string role_changed = "The referee has updated your role - you are now %s"; + std::shared_ptr player_peer = STKHost::get()->findPeerByName( + StringUtils::utf8ToWide(username)); + std::vector missing_assets; + if (player_peer) + missing_assets = m_lobby->getMissingTournamentAssets(player_peer); + bool fail = false; + switch (role[0]) + { + case 'R': + case 'r': + { + if (!missing_assets.empty()) + { + fail = true; + break; + } + if (m_lobby->tournamentColorsSwapped(m_lobby->m_tournament_game)) + { + m_lobby->m_tournament_blue_players.insert(username); + if (permanent) + m_lobby->m_tournament_init_blue.insert(username); + } + else + { + m_lobby->m_tournament_red_players.insert(username); + if (permanent) + m_lobby->m_tournament_init_red.insert(username); + } + if (player_peer) + { + role_changed = StringUtils::insertValues(role_changed, "red player"); + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_RED); + m_lobby->sendStringToPeer(role_changed, player_peer); + } + break; + } + case 'B': + case 'b': + { + if (!missing_assets.empty()) + { + fail = true; + break; + } + if (m_lobby->tournamentColorsSwapped(m_lobby->m_tournament_game)) + { + m_lobby->m_tournament_red_players.insert(username); + if (permanent) + m_lobby->m_tournament_init_red.insert(username); + } + else + { + m_lobby->m_tournament_blue_players.insert(username); + if (permanent) + m_lobby->m_tournament_init_blue.insert(username); + } + if (player_peer) + { + role_changed = StringUtils::insertValues(role_changed, "blue player"); + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_BLUE); + m_lobby->sendStringToPeer(role_changed, player_peer); + } + break; + } + case 'J': + case 'j': + { + if (!missing_assets.empty()) + { + fail = true; + break; + } + m_lobby->m_tournament_referees.insert(username); + if (permanent) + m_lobby->m_tournament_init_ref.insert(username); + if (player_peer) + { + role_changed = StringUtils::insertValues(role_changed, "referee"); + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); + m_lobby->sendStringToPeer(role_changed, player_peer); + } + break; + } + case 'S': + case 's': + { + if (player_peer) + { + role_changed = StringUtils::insertValues(role_changed, "spectator"); + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); + m_lobby->sendStringToPeer(role_changed, player_peer); + } + break; + } + } + std::string msg; + if (!fail) + msg = StringUtils::insertValues( + "Successfully changed role to %s for %s", role, username); + else + { + msg = StringUtils::insertValues( + "Failed to change role to %s for %s - missing assets:", role, username); + for (unsigned i = 0; i < missing_assets.size(); i++) + { + if (i) + msg.push_back(','); + msg += " " + missing_assets[i]; + } + } + m_lobby->sendStringToPeer(msg, peer); + } + m_lobby->updatePlayerList(); +} // process_role +// ======================================================================== + +void CommandManager::process_stop(Context& context) +{ + World* w = World::getWorld(); + if (!w) + return; + SoccerWorld *sw = dynamic_cast(w); + sw->stop(); + std::string msg = "The game is stopped."; + m_lobby->sendStringToAllPeers(msg); + Log::info("CommandManager", "SoccerMatchLog: The game is stopped"); +} // process_stop +// ======================================================================== + +void CommandManager::process_go(Context& context) +{ + World* w = World::getWorld(); + if (!w) + return; + SoccerWorld *sw = dynamic_cast(w); + sw->resume(); + std::string msg = "The game is resumed."; + m_lobby->sendStringToAllPeers(msg); + Log::info("CommandManager", "SoccerMatchLog: The game is resumed"); +} // process_go +// ======================================================================== + +void CommandManager::process_lobby(Context& context) +{ + World* w = World::getWorld(); + if (!w) + return; + SoccerWorld *sw = dynamic_cast(w); + sw->allToLobby(); + std::string msg = "The game will be restarted."; + m_lobby->sendStringToAllPeers(msg); +} // process_lobby +// ======================================================================== + +void CommandManager::process_init(Context& context) +{ + auto& argv = context.m_argv; + auto& peer = context.m_peer; + std::string peer_username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + int red, blue; + if (argv.size() < 3 || + !StringUtils::parseString(argv[1], &red) || + !StringUtils::parseString(argv[2], &blue)) + { + std::string msg = "Usage: /init [red_count] [blue_count]"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + World* w = World::getWorld(); + if (!w) + { + std::string msg = "Please set the count when the karts " + "are ready. Setting the initial count in lobby is " + "not implemented yet, sorry."; + m_lobby->sendStringToPeer(msg, peer); + return; + } + SoccerWorld *sw = dynamic_cast(w); + sw->setInitialCount(red, blue); + sw->tellCount(); +} // process_init +// ======================================================================== + +void CommandManager::process_mimiz(Context& context) +{ + auto& peer = context.m_peer; + auto& argv = context.m_argv; + auto& cmd = context.m_cmd; + std::string msg; + if (argv.size() == 1) + msg = "please provide text"; + else + msg = cmd.substr(argv[0].length() + 1); + m_lobby->sendStringToPeer(msg, peer); +} // process_mimiz +// ======================================================================== diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index d6bc2b35173..d1a21d87d2e 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -42,13 +42,29 @@ class STKPeer; class CommandManager { + enum CommandScope: int { + CS_ALWAYS = 1, + CS_SOCCER_TOURNAMENT = 2 + // add more powers of two if needed + }; + struct Context { Event* m_event; + std::shared_ptr m_peer; + std::vector m_argv; - Context(Event* event, std::shared_ptr peer, std::vector& argv): - m_event(event), m_peer(peer), m_argv(argv) {} + + std::string m_cmd; + + int m_user_permissions; + + Context(Event* event, std::shared_ptr peer, + std::vector& argv, std::string& cmd, + int user_permissions): + m_event(event), m_peer(peer), m_argv(argv), + m_cmd(cmd), m_user_permissions(user_permissions) {} }; struct Command @@ -59,9 +75,11 @@ class CommandManager void (CommandManager::*m_action)(Context& context); + int m_scope; + Command(std::string name, - void (CommandManager::*f)(Context& context), int permissions): - m_name(name), m_permissions(permissions), m_action(f) {} + void (CommandManager::*f)(Context& context), int permissions, int scope = CS_ALWAYS): + m_name(name), m_permissions(permissions), m_action(f), m_scope(scope) {} }; private: @@ -70,20 +88,75 @@ class CommandManager std::vector m_commands; + std::map m_text_response; + void initCommands(); + int getCurrentScope(); + + bool isAvailable(const Command& c); + + void process_text(Context& context); void process_commands(Context& context); void process_replay(Context& context); void process_start(Context& context); void process_config(Context& context); + void process_spectate(Context& context); + void process_addons(Context& context); + void process_lsa(Context& context); + void process_pha(Context& context); + void process_kick(Context& context); + void process_unban(Context& context); + void process_ban(Context& context); + void process_pas(Context& context); + void process_sha(Context& context); + void process_mute(Context& context); + void process_unmute(Context& context); + void process_listmute(Context& context); + void process_gnu(Context& context); + void process_nognu(Context& context); + void process_tell(Context& context); + void process_standings(Context& context); + void process_teamchat(Context& context); + void process_to(Context& context); + void process_public(Context& context); + void process_record(Context& context); + void process_power(Context& context); + void process_length(Context& context); + void process_queue(Context& context); + void process_adminstart(Context& context); + void process_shuffle(Context& context); + void process_timeout(Context& context); + void process_team(Context& context); + void process_cat(Context& context); + void process_troll(Context& context); + void process_hitmsg(Context& context); + void process_teamhit(Context& context); + void process_register(Context& context); +#ifdef ENABLE_WEB_SUPPORT + void process_token(Context& context); +#endif + // soccer tournament commands + void process_muteall(Context& context); + void process_game(Context& context); + void process_role(Context& context); + void process_stop(Context& context); + void process_go(Context& context); + void process_lobby(Context& context); + void process_init(Context& context); + void process_mimiz(Context& context); public: - CommandManager(ServerLobby* lobby = nullptr): m_lobby(lobby) { initCommands(); } + CommandManager(ServerLobby* lobby = nullptr); void handleCommand(Event* event, std::shared_ptr peer); bool isInitialized() { return m_lobby != nullptr; } + + template + void addTextResponse(std::string key, T&& value) + { m_text_response[key] = value; } }; #endif // COMMAND_MANAGER_HPP \ No newline at end of file diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 8975f6cacff..990ac48d40d 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -943,7 +943,7 @@ void ServerLobby::handleChat(Event* event) teams.insert(profile->getTeam()); bool tournament_limit = false; std::set important_players; - if (ServerConfig::m_soccer_tournament && m_tournament_limited_chat) + if (ServerConfig::m_soccer_tournament) { tournament_limit = true; for (auto& profile: sender->getPlayerProfiles()) @@ -959,12 +959,15 @@ void ServerLobby::handleChat(Event* event) // Note that mutealls are still spectators if (tournament_limit) { - for (const std::string& s: m_tournament_referees) - important_players.insert(s); - for (const std::string& s: m_tournament_red_players) - important_players.insert(s); - for (const std::string& s: m_tournament_blue_players) - important_players.insert(s); + if (m_tournament_limited_chat) + { + for (const std::string& s: m_tournament_referees) + important_players.insert(s); + for (const std::string& s: m_tournament_red_players) + important_players.insert(s); + for (const std::string& s: m_tournament_blue_players) + important_players.insert(s); + } for (const std::string& s: m_tournament_mutealls) important_players.insert(s); } From 24118ee212cac429becbe7a26d6a1c0bb29a3caa Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 11 Sep 2021 01:15:15 +0300 Subject: [PATCH 136/830] Fix bugs --- src/network/protocols/command_manager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 84d98d5d6e5..fe125e1cda5 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -85,7 +85,7 @@ void CommandManager::initCommands() m_commands.emplace_back("kick", &CommandManager::process_kick, UP_CROWNED); m_commands.emplace_back("kickban", &CommandManager::process_kick, UP_HAMMER); m_commands.emplace_back("unban", &CommandManager::process_unban, UP_HAMMER); - m_commands.emplace_back("ban", &CommandManager::process_unban, UP_HAMMER); + m_commands.emplace_back("ban", &CommandManager::process_ban, UP_HAMMER); m_commands.emplace_back("playeraddonscore", &CommandManager::process_pas, UP_EVERYONE); m_commands.emplace_back("serverhasaddon", &CommandManager::process_sha, UP_EVERYONE); m_commands.emplace_back("mute", &CommandManager::process_mute, UP_EVERYONE); @@ -1086,7 +1086,7 @@ void CommandManager::process_length(Context& context) { auto& argv = context.m_argv; std::string msg; - if (argv.size() < 3) + if (argv.size() < 2) { msg = "Usage: /length (x (float) | = (int) | check | clear)"; m_lobby->sendStringToPeer(msg, context.m_peer); @@ -1152,7 +1152,7 @@ void CommandManager::process_queue(Context& context) std::string msg; auto& argv = context.m_argv; std::string format_string = "Format: /queue (show | push[_front] (track) | pop[_back])"; - if (argv.size() < 3) + if (argv.size() < 2) { m_lobby->sendStringToPeer(format_string, context.m_peer); return; From 481e930d26525f5a7ea8e7458151dee4b3950b51 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 11 Sep 2021 01:50:47 +0300 Subject: [PATCH 137/830] Fix more bugs --- src/network/protocols/command_manager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index fe125e1cda5..f90ae22b849 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -165,7 +165,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) if (argv[0] == command.m_name) { found_command = true; - if ((permissions & command.m_permissions) == 0) + if ((permissions & command.m_permissions) == 0 || !isAvailable(command)) { std::string msg = "You don't have permissions to invoke this command"; m_lobby->sendStringToPeer(msg, peer); @@ -1192,7 +1192,7 @@ void CommandManager::process_queue(Context& context) + std::to_string(m_lobby->m_tracks_queue.size()); m_lobby->sendStringToPeer(msg, context.m_peer); } - else if (argv[1] == "pop" || argv[1] == "pop_back") + else if (argv[1] == "pop" || argv[1] == "pop_front") { msg = ""; if (m_lobby->m_tracks_queue.empty()) { @@ -1200,7 +1200,7 @@ void CommandManager::process_queue(Context& context) } else { - std::string msg = "Popped " + m_lobby->m_tracks_queue.front() + msg = "Popped " + m_lobby->m_tracks_queue.front() + "from the queue,"; m_lobby->m_tracks_queue.pop_front(); msg += " current queue size: " @@ -1216,7 +1216,7 @@ void CommandManager::process_queue(Context& context) } else { - std::string msg = "Popped " + m_lobby->m_tracks_queue.back() + msg = "Popped " + m_lobby->m_tracks_queue.back() + "from the queue,"; m_lobby->m_tracks_queue.pop_back(); msg += " current queue size: " From c12a19fc741e1b135ef2f8e1a4e3eb0ddfc87491 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 11 Sep 2021 01:56:42 +0300 Subject: [PATCH 138/830] Fix strings --- src/network/protocols/command_manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index f90ae22b849..332af1703f4 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -1201,7 +1201,7 @@ void CommandManager::process_queue(Context& context) else { msg = "Popped " + m_lobby->m_tracks_queue.front() - + "from the queue,"; + + " from the front of the queue,"; m_lobby->m_tracks_queue.pop_front(); msg += " current queue size: " + std::to_string(m_lobby->m_tracks_queue.size()); @@ -1217,7 +1217,7 @@ void CommandManager::process_queue(Context& context) else { msg = "Popped " + m_lobby->m_tracks_queue.back() - + "from the queue,"; + + " from the back of the queue,"; m_lobby->m_tracks_queue.pop_back(); msg += " current queue size: " + std::to_string(m_lobby->m_tracks_queue.size()); From e39e49701f0ff114c83832c02d0ada0faea5656e Mon Sep 17 00:00:00 2001 From: luva <65125735+iluvatyr@users.noreply.github.com> Date: Mon, 20 Sep 2021 23:20:00 +0200 Subject: [PATCH 139/830] Update Networking.md (#6) Added options from heuchi-mod (show-teammate-hits, teammate-hit-mode) --- NETWORKING.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NETWORKING.md b/NETWORKING.md index 28f28e245d1..42b7c4ff991 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -95,6 +95,12 @@ The current server configuration xml looks like this (this is only an example, j + + + + + + From deaed1e9712795fc67f10d4bf002c42ddcf62687 Mon Sep 17 00:00:00 2001 From: kimden Date: Tue, 21 Sep 2021 20:06:49 +0300 Subject: [PATCH 140/830] Try to add some votable commands --- src/network/protocols/command_manager.cpp | 154 ++++++++++++++++-- src/network/protocols/command_manager.hpp | 19 ++- src/network/protocols/command_permissions.hpp | 1 + src/network/protocols/command_voting.cpp | 92 +++++++++++ src/network/protocols/command_voting.hpp | 49 ++++++ src/network/protocols/server_lobby.cpp | 16 +- src/network/protocols/server_lobby.hpp | 6 +- 7 files changed, 314 insertions(+), 23 deletions(-) create mode 100644 src/network/protocols/command_voting.cpp create mode 100644 src/network/protocols/command_voting.hpp diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 332af1703f4..731019f0952 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -40,6 +40,7 @@ // #include "network/protocol_manager.hpp" // #include "network/protocols/connect_to_peer.hpp" #include "network/protocols/command_permissions.hpp" +// #include "network/protocols/command_voting.hpp" // #include "network/protocols/game_protocol.hpp" // #include "network/protocols/game_events_protocol.hpp" #include "network/protocols/server_lobby.hpp" @@ -82,8 +83,8 @@ void CommandManager::initCommands() m_commands.emplace_back("moreaddons", &CommandManager::process_addons, UP_EVERYONE); m_commands.emplace_back("listserveraddon", &CommandManager::process_lsa, UP_EVERYONE); m_commands.emplace_back("playerhasaddon", &CommandManager::process_pha, UP_EVERYONE); - m_commands.emplace_back("kick", &CommandManager::process_kick, UP_CROWNED); - m_commands.emplace_back("kickban", &CommandManager::process_kick, UP_HAMMER); + m_commands.emplace_back("kick", &CommandManager::process_kick, UP_CROWNED | PE_VOTED); + m_commands.emplace_back("kickban", &CommandManager::process_kick, UP_HAMMER | PE_VOTED); m_commands.emplace_back("unban", &CommandManager::process_unban, UP_HAMMER); m_commands.emplace_back("ban", &CommandManager::process_ban, UP_HAMMER); m_commands.emplace_back("playeraddonscore", &CommandManager::process_pas, UP_EVERYONE); @@ -91,7 +92,7 @@ void CommandManager::initCommands() m_commands.emplace_back("mute", &CommandManager::process_mute, UP_EVERYONE); m_commands.emplace_back("unmute", &CommandManager::process_unmute, UP_EVERYONE); m_commands.emplace_back("listmute", &CommandManager::process_listmute, UP_EVERYONE); - m_commands.emplace_back("help", &CommandManager::process_text, UP_EVERYONE); + m_commands.emplace_back("moreinfo", &CommandManager::process_text, UP_EVERYONE); m_commands.emplace_back("gnu", &CommandManager::process_gnu, UP_CROWNED); m_commands.emplace_back("nognu", &CommandManager::process_nognu, UP_CROWNED); m_commands.emplace_back("tell", &CommandManager::process_tell, UP_EVERYONE); @@ -128,12 +129,25 @@ void CommandManager::initCommands() m_commands.emplace_back("resume", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT); m_commands.emplace_back("lobby", &CommandManager::process_lobby, UP_HAMMER, CS_SOCCER_TOURNAMENT); m_commands.emplace_back("init", &CommandManager::process_init, UP_HAMMER, CS_SOCCER_TOURNAMENT); + m_commands.emplace_back("vote", &CommandManager::special, UP_EVERYONE); m_commands.emplace_back("mimiz", &CommandManager::process_mimiz, UP_EVERYONE); + m_commands.emplace_back("test", &CommandManager::process_test, UP_EVERYONE | PE_VOTED); - addTextResponse("help", StringUtils::wideToUtf8(m_lobby->m_help_message)); + addTextResponse("moreinfo", StringUtils::wideToUtf8(m_lobby->m_help_message)); addTextResponse("version", "1.3-rc1 k 210fff beta"); addTextResponse("clear", std::string(30, '\n')); + + std::sort(m_commands.begin(), m_commands.end(), [](const Command& a, const Command& b) -> bool { + return a.m_name < b.m_name; + }); + + m_votables.emplace("replay", 1.0); + m_votables.emplace("start", 0.9); + m_votables.emplace("config", 0.6); + m_votables.emplace("kick", 0.9); + m_votables.emplace("kickban", 0.9); + } // initCommands // ======================================================================== @@ -159,21 +173,64 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) int permissions = m_lobby->getPermissions(peer); bool found_command = false; + bool voting = false; + std::string action = "invoke"; + if (argv[0] == "vote") + { + if (argv.size() == 1 || argv[1] == "vote") + { + std::string msg = "Usage: /vote (a command with arguments)"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + std::reverse(argv.begin(), argv.end()); + argv.pop_back(); + std::reverse(argv.begin(), argv.end()); + voting = true; + action = "vote for"; + } for (auto& command: m_commands) { - if (argv[0] == command.m_name) + if (argv[0] != command.m_name) + continue; + + found_command = true; + if (!isAvailable(command)) { - found_command = true; - if ((permissions & command.m_permissions) == 0 || !isAvailable(command)) - { - std::string msg = "You don't have permissions to invoke this command"; - m_lobby->sendStringToPeer(msg, peer); - } - else + std::string msg = "You don't have permissions to " + action + " this command"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + int mask = (permissions & command.m_permissions); + if (mask == 0) + { + std::string msg = "You don't have permissions to " + action + " this command"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + int mask_without_voting = (mask & ~PE_VOTED); + if (mask != PE_NONE && mask_without_voting == PE_NONE) + voting = true; + + Context context(event, peer, argv, cmd, permissions, voting); + (this->*command.m_action)(context); + + auto it = m_votables.find(argv[0]); + if (it != m_votables.end() && it->second.needsCheck()) + { + auto res = it->second.process(m_users); + if (!res.empty()) { - Context context(event, peer, argv, cmd, permissions); - (this->*command.m_action)(context); + for (auto& p: res) + { + std::string new_cmd = p.first + " " + p.second; + std::string msg = "Command \"" + new_cmd + "\" has been successfully voted"; + m_lobby->sendStringToAllPeers(msg); + auto new_argv = StringUtils::split(new_cmd, ' '); + Context new_context(event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); + (this->*command.m_action)(new_context); + } } } } @@ -205,6 +262,20 @@ bool CommandManager::isAvailable(const Command& c) } // getCurrentScope // ======================================================================== +void CommandManager::vote(Context& context, std::string category, std::string value) +{ + auto& cmd = context.m_cmd; + auto& peer = context.m_peer; + auto& argv = context.m_argv; + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + auto& votable = m_votables[argv[0]]; + int count = votable.castVote(username, category, value); + std::string msg = username + " voted \"" + cmd + "\", there are " + std::to_string(count) + " such votes"; + m_lobby->sendStringToAllPeers(msg); +} // vote +// ======================================================================== + void CommandManager::process_text(Context& context) { std::string response; @@ -657,13 +728,18 @@ void CommandManager::process_kick(Context& context) m_lobby->sendStringToPeer(msg, context.m_peer); return; } + if (context.m_voting) + { + vote(context, "kick " + player_name, ""); + return; + } if (!peer->isAngryHost() && !ServerConfig::m_kicks_allowed) { std::string msg = "Kicking players is not allowed on this server"; m_lobby->sendStringToPeer(msg, peer); return; } - Log::info("CommandManager", "Crown player kicks %s", player_name.c_str()); + Log::info("CommandManager", "%s kicks %s", (peer.get() ? "Crown player" : "Vote"), player_name.c_str()); player_peer->kick(); if (ServerConfig::m_track_kicks) { @@ -1886,3 +1962,51 @@ void CommandManager::process_mimiz(Context& context) m_lobby->sendStringToPeer(msg, peer); } // process_mimiz // ======================================================================== + +void CommandManager::process_test(Context& context) +{ + auto& argv = context.m_argv; + argv.resize(3, ""); + auto& peer = context.m_peer; + if (context.m_voting) + { + vote(context, "test " + argv[1], argv[2]); + return; + } + std::string username = "Vote"; + if (peer.get()) + { + username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + } + std::string msg = username + ", " + argv[1] + ", " + argv[2]; + m_lobby->sendStringToAllPeers(msg); +} // process_test +// ======================================================================== + +void CommandManager::special(Context& context) +{ + // This function is used as a function for /vote and possibly several + // other future special functions that are never executed "as usual" + // but need to be displayed in /commands output. So, in fact, this + // function is only a placeholder and should be never executed. +} // special +// ======================================================================== + +void CommandManager::addUser(std::string& s) +{ + m_users.insert(s); +} // addUser +// ======================================================================== + +void CommandManager::deleteUser(std::string& s) +{ + auto it = m_users.find(s); + if (it == m_users.end()) + { + Log::error("CommandManager", "No user %s in user list!", s.c_str()); + return; + } + m_users.erase(it); +} // deleteUser +// ======================================================================== \ No newline at end of file diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index d1a21d87d2e..373fcee91a5 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -32,10 +32,13 @@ #include #include + #ifdef ENABLE_SQLITE3 #include #endif +#include "network/protocols/command_voting.hpp" + class ServerLobby; class Event; class STKPeer; @@ -60,11 +63,13 @@ class CommandManager int m_user_permissions; + bool m_voting; + Context(Event* event, std::shared_ptr peer, std::vector& argv, std::string& cmd, - int user_permissions): + int user_permissions, bool voting): m_event(event), m_peer(peer), m_argv(argv), - m_cmd(cmd), m_user_permissions(user_permissions) {} + m_cmd(cmd), m_user_permissions(user_permissions), m_voting(voting) {} }; struct Command @@ -88,14 +93,19 @@ class CommandManager std::vector m_commands; + std::multiset m_users; + std::map m_text_response; + std::map m_votables; + void initCommands(); int getCurrentScope(); bool isAvailable(const Command& c); + void vote(Context& context, std::string category, std::string value); void process_text(Context& context); void process_commands(Context& context); void process_replay(Context& context); @@ -145,6 +155,8 @@ class CommandManager void process_lobby(Context& context); void process_init(Context& context); void process_mimiz(Context& context); + void process_test(Context& context); + void special(Context& context); public: @@ -157,6 +169,9 @@ class CommandManager template void addTextResponse(std::string key, T&& value) { m_text_response[key] = value; } + + void addUser(std::string& s); + void deleteUser(std::string& s); }; #endif // COMMAND_MANAGER_HPP \ No newline at end of file diff --git a/src/network/protocols/command_permissions.hpp b/src/network/protocols/command_permissions.hpp index 9627f1844a3..545fbc86250 100644 --- a/src/network/protocols/command_permissions.hpp +++ b/src/network/protocols/command_permissions.hpp @@ -21,6 +21,7 @@ enum CommandPermissions : unsigned int { + PE_NONE = 0, PE_USUAL = 1, PE_VOTED = 2, PE_CROWNED = 4, diff --git a/src/network/protocols/command_voting.cpp b/src/network/protocols/command_voting.cpp new file mode 100644 index 00000000000..80525691187 --- /dev/null +++ b/src/network/protocols/command_voting.cpp @@ -0,0 +1,92 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2021 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "network/protocols/command_voting.hpp" + +CommandVoting::CommandVoting(double threshold): m_threshold(threshold) +{ + +} // CommandVoting +// ======================================================================== + +int CommandVoting::castVote(std::string player, std::string category, std::string vote) +{ + uncastVote(player, category); + m_votes_by_player[player][category] = vote; + m_votes_by_poll[category][vote].insert(player); + m_need_check = true; + return m_votes_by_poll[category][vote].size(); +} // castVote +// ======================================================================== + +void CommandVoting::uncastVote(std::string player, std::string category) +{ + auto it = m_votes_by_player[player].find(category); + if (it != m_votes_by_player[player].end()) + { + std::string previous_vote = it->second; + m_votes_by_poll[category][previous_vote].erase(player); + } + m_need_check = true; +} // uncastVote +// ======================================================================== + +std::map CommandVoting::process(std::multiset& all_users) +{ + m_need_check = false; + std::map result; + int required_number = (int)(all_users.size() * m_threshold); + for (const auto& p: m_votes_by_poll) + { + std::string category = p.first; + std::map category_results; + for (const std::string& user: all_users) + { + auto it = m_votes_by_player.find(user); + if (it == m_votes_by_player.end()) + continue; + auto it2 = it->second.find(category); + if (it2 == it->second.end()) + continue; + ++category_results[it2->second]; + } + for (const auto& q: category_results) + { + if (q.second >= required_number) + { + result[category] = q.first; + break; + } + } + } + for (const auto& p: result) + { + std::string category = p.first; + for (const auto& q: m_votes_by_poll[category]) + { + std::string vote = q.first; + for (const auto& player: q.second) + { + m_votes_by_player[player].erase(category); + } + } + m_votes_by_poll[category].clear(); + } + return result; +} // process +// ======================================================================== \ No newline at end of file diff --git a/src/network/protocols/command_voting.hpp b/src/network/protocols/command_voting.hpp new file mode 100644 index 00000000000..130bc0c9652 --- /dev/null +++ b/src/network/protocols/command_voting.hpp @@ -0,0 +1,49 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2021 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef COMMAND_VOTING_HPP +#define COMMAND_VOTING_HPP + +#include "irrString.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class CommandVoting +{ + double m_threshold; + bool m_need_check = false; +private: + std::map>> m_votes_by_poll; + std::map> m_votes_by_player; +public: + CommandVoting(double threshold = 0.500001); + bool needsCheck() { return m_need_check; } + int castVote(std::string player, std::string category, std::string vote); + void uncastVote(std::string player, std::string category); + std::map process(std::multiset& all_users); +}; + +#endif // COMMAND_VOTING_HPP \ No newline at end of file diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 990ac48d40d..4c1ce50051c 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3969,6 +3969,7 @@ void ServerLobby::clientDisconnected(Event* event) std::string name = StringUtils::wideToUtf8(p->getName()); msg->encodeString(name); Log::info("ServerLobby", "%s disconnected", name.c_str()); + m_command_manager.deleteUser(name); } unsigned players_number; @@ -4510,6 +4511,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, name = name.subString(0, 30); std::string utf8_name = StringUtils::wideToUtf8(name); + m_command_manager.addUser(utf8_name); float default_kart_color = data.getFloat(); HandicapLevel handicap = (HandicapLevel)data.getUInt8(); auto player = std::make_shared @@ -5702,7 +5704,7 @@ void ServerLobby::testBannedForIP(STKPeer* peer) const } // testBannedForIP //----------------------------------------------------------------------------- -void ServerLobby::getMessagesFromHost(STKPeer* peer, int online_id) const +void ServerLobby::getMessagesFromHost(STKPeer* peer, int online_id) { #ifdef ENABLE_SQLITE3 if (!m_db || !m_player_reports_table_exists || online_id == 0) @@ -6682,6 +6684,8 @@ void ServerLobby::writeOwnReport(STKPeer* reporter, STKPeer* reporting, const st #ifdef ENABLE_SQLITE3 if (!m_db || !m_player_reports_table_exists) return; + if (!reporting) + reporting = reporter; if (!reporter->hasPlayerProfiles()) return; auto reporter_npp = reporter->getPlayerProfiles()[0]; @@ -6959,10 +6963,13 @@ void ServerLobby::changeColors() updatePlayerList(); } // changeColors //----------------------------------------------------------------------------- -void ServerLobby::sendStringToPeer(std::string& s, std::shared_ptr& peer) const +void ServerLobby::sendStringToPeer(std::string& s, std::shared_ptr& peer) { if (!peer) + { + sendStringToAllPeers(s); return; + } NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); @@ -6971,10 +6978,13 @@ void ServerLobby::sendStringToPeer(std::string& s, std::shared_ptr& pee delete chat; } // sendStringToPeer //----------------------------------------------------------------------------- -void ServerLobby::sendStringToPeer(std::string& s, STKPeer* peer) const +void ServerLobby::sendStringToPeer(std::string& s, STKPeer* peer) { if (!peer) + { + sendStringToAllPeers(s); return; + } NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 7e3456129ce..442928ca0ac 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -541,7 +541,7 @@ class ServerLobby : public LobbyProtocol void testBannedForIP(STKPeer* peer) const; void testBannedForIPv6(STKPeer* peer) const; void testBannedForOnlineId(STKPeer* peer, uint32_t online_id) const; - void getMessagesFromHost(STKPeer* peer, int online_id) const; + void getMessagesFromHost(STKPeer* peer, int online_id); void writeDisconnectInfoTable(STKPeer* peer); void writePlayerReport(Event* event); bool supportsAI(); @@ -616,8 +616,8 @@ class ServerLobby : public LobbyProtocol const std::string& info); // int getTrackMaxPlayers(std::string& name) const; void updateGnuElimination(); - void sendStringToPeer(std::string& s, std::shared_ptr& peer) const; - void sendStringToPeer(std::string& s, STKPeer* peer) const; + void sendStringToPeer(std::string& s, std::shared_ptr& peer); + void sendStringToPeer(std::string& s, STKPeer* peer); void sendStringToAllPeers(std::string& s); int getPermissions(std::shared_ptr& peer) const; int getPermissions(STKPeer* peer) const; From 4345426774784bfaf2252a7cc26974a391039afd Mon Sep 17 00:00:00 2001 From: kimden Date: Wed, 22 Sep 2021 02:41:19 +0300 Subject: [PATCH 141/830] Fix bugs in initialization, counting votes, usernames --- src/network/protocols/command_manager.cpp | 12 ++++++++---- src/network/protocols/command_voting.cpp | 20 ++++++++++++++------ src/network/protocols/command_voting.hpp | 6 ++++-- src/network/protocols/server_lobby.cpp | 21 ++++++++++++++------- src/network/protocols/server_lobby.hpp | 1 + 5 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 731019f0952..9b8fbe7cc48 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -219,7 +219,13 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) auto it = m_votables.find(argv[0]); if (it != m_votables.end() && it->second.needsCheck()) { - auto res = it->second.process(m_users); + auto response = it->second.process(m_users); + int count = response.first; + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + std::string msg = username + " voted \"" + cmd + "\", there are " + std::to_string(count) + " such votes"; + m_lobby->sendStringToAllPeers(msg); + auto res = response.second; if (!res.empty()) { for (auto& p: res) @@ -270,9 +276,7 @@ void CommandManager::vote(Context& context, std::string category, std::string va std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); auto& votable = m_votables[argv[0]]; - int count = votable.castVote(username, category, value); - std::string msg = username + " voted \"" + cmd + "\", there are " + std::to_string(count) + " such votes"; - m_lobby->sendStringToAllPeers(msg); + votable.castVote(username, category, value); } // vote // ======================================================================== diff --git a/src/network/protocols/command_voting.cpp b/src/network/protocols/command_voting.cpp index 80525691187..28c51b7d03d 100644 --- a/src/network/protocols/command_voting.cpp +++ b/src/network/protocols/command_voting.cpp @@ -24,13 +24,14 @@ CommandVoting::CommandVoting(double threshold): m_threshold(threshold) } // CommandVoting // ======================================================================== -int CommandVoting::castVote(std::string player, std::string category, std::string vote) +void CommandVoting::castVote(std::string player, std::string category, std::string vote) { uncastVote(player, category); m_votes_by_player[player][category] = vote; m_votes_by_poll[category][vote].insert(player); m_need_check = true; - return m_votes_by_poll[category][vote].size(); + m_selected_category = category; + m_selected_option = vote; } // castVote // ======================================================================== @@ -43,14 +44,16 @@ void CommandVoting::uncastVote(std::string player, std::string category) m_votes_by_poll[category][previous_vote].erase(player); } m_need_check = true; + m_selected_category = ""; + m_selected_option = ""; } // uncastVote // ======================================================================== -std::map CommandVoting::process(std::multiset& all_users) +std::pair> CommandVoting::process(std::multiset& all_users) { - m_need_check = false; std::map result; - int required_number = (int)(all_users.size() * m_threshold); + int num_votes = 0; + int required_number = std::max(1, (int)ceil((double)all_users.size() * m_threshold)); for (const auto& p: m_votes_by_poll) { std::string category = p.first; @@ -67,6 +70,8 @@ std::map CommandVoting::process(std::multiset= required_number) { result[category] = q.first; @@ -74,6 +79,9 @@ std::map CommandVoting::process(std::multiset CommandVoting::process(std::multiset>> m_votes_by_poll; std::map> m_votes_by_player; public: CommandVoting(double threshold = 0.500001); bool needsCheck() { return m_need_check; } - int castVote(std::string player, std::string category, std::string vote); + void castVote(std::string player, std::string category, std::string vote); void uncastVote(std::string player, std::string category); - std::map process(std::multiset& all_users); + std::pair> process(std::multiset& all_users); }; #endif // COMMAND_VOTING_HPP \ No newline at end of file diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 4c1ce50051c..458a2da0f13 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3969,7 +3969,7 @@ void ServerLobby::clientDisconnected(Event* event) std::string name = StringUtils::wideToUtf8(p->getName()); msg->encodeString(name); Log::info("ServerLobby", "%s disconnected", name.c_str()); - m_command_manager.deleteUser(name); + getCommandManager().deleteUser(name); } unsigned players_number; @@ -4511,7 +4511,6 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, name = name.subString(0, 30); std::string utf8_name = StringUtils::wideToUtf8(name); - m_command_manager.addUser(utf8_name); float default_kart_color = data.getFloat(); HandicapLevel handicap = (HandicapLevel)data.getUInt8(); auto player = std::make_shared @@ -4550,6 +4549,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, } } std::string username = StringUtils::wideToUtf8(player->getName()); + getCommandManager().addUser(username); if (m_game_setup->isGrandPrix()) { auto it = m_gp_scores.find(username); @@ -6515,11 +6515,7 @@ bool ServerLobby::checkPeersReady(bool ignore_ai_peer) const void ServerLobby::handleServerCommand(Event* event, std::shared_ptr peer) { - if (!m_command_manager.isInitialized()) - { - m_command_manager = CommandManager(this); - } - m_command_manager.handleCommand(event, peer); + getCommandManager().handleCommand(event, peer); } // handleServerCommand //----------------------------------------------------------------------------- void ServerLobby::updateGnuElimination() @@ -7319,6 +7315,17 @@ void ServerLobby::updateTournamentRole(STKPeer* peer) } } // updateTournamentRole //----------------------------------------------------------------------------- + +CommandManager& ServerLobby::getCommandManager() +{ + if (!m_command_manager.isInitialized()) + { + m_command_manager = CommandManager(this); + } + return m_command_manager; +} // getCommandManager +//----------------------------------------------------------------------------- + #ifdef ENABLE_SQLITE3 std::string ServerLobby::getRecord(std::string& track, std::string& mode, std::string& direction, int laps) diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 442928ca0ac..b9e60e0504f 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -564,6 +564,7 @@ class ServerLobby : public LobbyProtocol bool tournamentGoalsLimit(int game) const; bool tournamentColorsSwapped(int game) const; void updateTournamentRole(STKPeer* peer); + CommandManager& getCommandManager(); // bool tournamentHasIcy(int game) const; #ifdef ENABLE_WEB_SUPPORT From 924de746e76edc03b6f5cd40a85ae3d56c38ffc7 Mon Sep 17 00:00:00 2001 From: kimden Date: Thu, 23 Sep 2021 03:00:13 +0300 Subject: [PATCH 142/830] Add /help and commands' descriptions --- src/network/protocols/command_manager.cpp | 326 ++++++++++++---------- src/network/protocols/command_manager.hpp | 25 +- 2 files changed, 202 insertions(+), 149 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 9b8fbe7cc48..0ddec2ae775 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -74,65 +74,65 @@ void CommandManager::initCommands() { - m_commands.emplace_back("commands", &CommandManager::process_commands, UP_EVERYONE); - m_commands.emplace_back("replay", &CommandManager::process_replay, UP_SINGLE); - m_commands.emplace_back("start", &CommandManager::process_start, UP_EVERYONE); - m_commands.emplace_back("config", &CommandManager::process_config, UP_CROWNED); - m_commands.emplace_back("spectate", &CommandManager::process_spectate, UP_EVERYONE); - m_commands.emplace_back("addons", &CommandManager::process_addons, UP_EVERYONE); - m_commands.emplace_back("moreaddons", &CommandManager::process_addons, UP_EVERYONE); - m_commands.emplace_back("listserveraddon", &CommandManager::process_lsa, UP_EVERYONE); - m_commands.emplace_back("playerhasaddon", &CommandManager::process_pha, UP_EVERYONE); - m_commands.emplace_back("kick", &CommandManager::process_kick, UP_CROWNED | PE_VOTED); - m_commands.emplace_back("kickban", &CommandManager::process_kick, UP_HAMMER | PE_VOTED); - m_commands.emplace_back("unban", &CommandManager::process_unban, UP_HAMMER); - m_commands.emplace_back("ban", &CommandManager::process_ban, UP_HAMMER); - m_commands.emplace_back("playeraddonscore", &CommandManager::process_pas, UP_EVERYONE); - m_commands.emplace_back("serverhasaddon", &CommandManager::process_sha, UP_EVERYONE); - m_commands.emplace_back("mute", &CommandManager::process_mute, UP_EVERYONE); - m_commands.emplace_back("unmute", &CommandManager::process_unmute, UP_EVERYONE); - m_commands.emplace_back("listmute", &CommandManager::process_listmute, UP_EVERYONE); - m_commands.emplace_back("moreinfo", &CommandManager::process_text, UP_EVERYONE); - m_commands.emplace_back("gnu", &CommandManager::process_gnu, UP_CROWNED); - m_commands.emplace_back("nognu", &CommandManager::process_nognu, UP_CROWNED); - m_commands.emplace_back("tell", &CommandManager::process_tell, UP_EVERYONE); - m_commands.emplace_back("standings", &CommandManager::process_standings, UP_EVERYONE); - m_commands.emplace_back("teamchat" , &CommandManager::process_teamchat, UP_EVERYONE); - m_commands.emplace_back("to", &CommandManager::process_to, UP_EVERYONE); - m_commands.emplace_back("public", &CommandManager::process_public, UP_EVERYONE); - m_commands.emplace_back("record", &CommandManager::process_record, UP_EVERYONE); - m_commands.emplace_back("power", &CommandManager::process_power, UP_EVERYONE); - m_commands.emplace_back("length", &CommandManager::process_length, UP_SINGLE); - m_commands.emplace_back("queue", &CommandManager::process_queue, UP_SINGLE); - m_commands.emplace_back("adminstart", &CommandManager::process_adminstart, UP_HAMMER); - m_commands.emplace_back("shuffle", &CommandManager::process_shuffle, UP_HAMMER); - m_commands.emplace_back("timeout", &CommandManager::process_timeout, UP_HAMMER); - m_commands.emplace_back("team", &CommandManager::process_team, UP_HAMMER); - m_commands.emplace_back("cat+", &CommandManager::process_cat, UP_HAMMER); - m_commands.emplace_back("cat-", &CommandManager::process_cat, UP_HAMMER); - m_commands.emplace_back("cat*", &CommandManager::process_cat, UP_HAMMER); - m_commands.emplace_back("troll", &CommandManager::process_troll, UP_HAMMER); - m_commands.emplace_back("hitmsg", &CommandManager::process_hitmsg, UP_HAMMER); - m_commands.emplace_back("teamhit", &CommandManager::process_teamhit, UP_HAMMER); - m_commands.emplace_back("version", &CommandManager::process_text, UP_EVERYONE); - m_commands.emplace_back("clear", &CommandManager::process_text, UP_EVERYONE); - m_commands.emplace_back("register", &CommandManager::process_register, UP_EVERYONE); + m_commands.emplace_back("commands", &CommandManager::process_commands, UP_EVERYONE, CS_ALWAYS, "/commands", "everyone", "Prints the list of commands available to you. This list may differ depending on server settings and your permissions."); + m_commands.emplace_back("replay", &CommandManager::process_replay, UP_SINGLE, CS_ALWAYS, "/replay [0 | 1]", "hammers, singleplayers", "Toggles whether the replay of the race is recorded."); + m_commands.emplace_back("start", &CommandManager::process_start, UP_EVERYONE, CS_ALWAYS, "/start", "everyone", "Basically clicks on the green “Ready” button."); + m_commands.emplace_back("config", &CommandManager::process_config, UP_CROWNED, CS_ALWAYS, "/config ", "crowns", "Changes game mode and difficulty if allowed."); + m_commands.emplace_back("spectate", &CommandManager::process_spectate, UP_EVERYONE, CS_ALWAYS, "/spectate [0 | 1]", "everyone", "Toggles autospectate mode."); + m_commands.emplace_back("addons", &CommandManager::process_addons, UP_EVERYONE, CS_ALWAYS, "/addons [type]", "everyone", "Lists addons installed for all players that can play, in random order. Limits the list to a certain addon type if specified."); + m_commands.emplace_back("moreaddons", &CommandManager::process_addons, UP_EVERYONE, CS_ALWAYS, "/moreaddons [type]", "everyone", "Lists top 5 addons that are missing for at least one player, sorted by the number of players that don’t have the addon ascending, random for equal number of players. Limits the list to a certain addon type if specified."); + m_commands.emplace_back("listserveraddon", &CommandManager::process_lsa, UP_EVERYONE, CS_ALWAYS, "/listserveraddon [-type] (substring)", "everyone", "Lists addons installed on the server that have a specified substring in their id. Limits the list to a certain addon type if specified."); + m_commands.emplace_back("playerhasaddon", &CommandManager::process_pha, UP_EVERYONE, CS_ALWAYS, "/playerhasaddon (addon) (username)", "everyone", "Checks whether a player has a certain addon."); + m_commands.emplace_back("kick", &CommandManager::process_kick, UP_CROWNED | PE_VOTED, CS_ALWAYS, "/kick (username)", "crowns if server allows, hammers; votable", "Kicks a player from the server."); + m_commands.emplace_back("kickban", &CommandManager::process_kick, UP_HAMMER | PE_VOTED, CS_ALWAYS, "/kickban (username)", "hammers; votable", "Kicks a player from the server and temporarily bans him."); + m_commands.emplace_back("unban", &CommandManager::process_unban, UP_HAMMER, CS_ALWAYS, "/unban (username)", "hammers", "Removes a temporary ban from a player."); + m_commands.emplace_back("ban", &CommandManager::process_ban, UP_HAMMER, CS_ALWAYS, "/ban (username)", "hammers", "Adds a temporary ban to a player without kicking."); + m_commands.emplace_back("playeraddonscore", &CommandManager::process_pas, UP_EVERYONE, CS_ALWAYS, "/playeraddonscore (username)", "everyone", "Returns the number (not the percentage!) of addons of different types installed by a player."); + m_commands.emplace_back("serverhasaddon", &CommandManager::process_sha, UP_EVERYONE, CS_ALWAYS, "/serverhasaddon (addon)", "everyone", "Checks whether the server has a certain addon."); + m_commands.emplace_back("mute", &CommandManager::process_mute, UP_EVERYONE, CS_ALWAYS, "/mute (username)", "everyone", "Temporarily blocks player’s messages from reaching you (until the server restart)."); + m_commands.emplace_back("unmute", &CommandManager::process_unmute, UP_EVERYONE, CS_ALWAYS, "/unmute (username)", "everyone", "Unblocks player’s messages from reaching you."); + m_commands.emplace_back("listmute", &CommandManager::process_listmute, UP_EVERYONE, CS_ALWAYS, "/listmute", "everyone", "Lists players whom you blocked using /mute command."); + m_commands.emplace_back("moreinfo", &CommandManager::process_text, UP_EVERYONE, CS_ALWAYS, "/moreinfo", "everyone", "Displays an additional server message."); + m_commands.emplace_back("gnu", &CommandManager::process_gnu, UP_CROWNED, CS_ALWAYS, "/gnu [kart]", "crowns", "Starts kart elimination with Gnu (or a specified kart)."); + m_commands.emplace_back("nognu", &CommandManager::process_nognu, UP_CROWNED, CS_ALWAYS, "/nognu", "crowns", "Cancels kart elimination."); + m_commands.emplace_back("tell", &CommandManager::process_tell, UP_EVERYONE, CS_ALWAYS, "/tell (report contents)", "everyone", "Makes a report to the server owner (if the server has a database to store the reports)."); + m_commands.emplace_back("standings", &CommandManager::process_standings, UP_EVERYONE, CS_ALWAYS, "/standings [gp | gnu]", "everyone", "Displays standings of grand prix or kart elimination, picks whatever of them is played now."); + m_commands.emplace_back("teamchat", &CommandManager::process_teamchat, UP_EVERYONE, CS_ALWAYS, "/teamchat", "everyone", "Limits your future messages to be sent only to your teammates."); + m_commands.emplace_back("to", &CommandManager::process_to, UP_EVERYONE, CS_ALWAYS, "/to (username1) ... (usernameN)", "everyone", "Limits your future messages to be sent only to specified usernames."); + m_commands.emplace_back("public", &CommandManager::process_public, UP_EVERYONE, CS_ALWAYS, "/public", "everyone", "Allows your future messages to be sent to everyone."); + m_commands.emplace_back("record", &CommandManager::process_record, UP_EVERYONE, CS_ALWAYS, "/record (track id) (mode) (direction) (laps)", "everyone", "Receives the server record for the race settings if there is any (and if the server has a database to store the records)."); + m_commands.emplace_back("power", &CommandManager::process_power, UP_EVERYONE, CS_ALWAYS, "/power (password)", "everyone", "Enters the hammer mode if the password is correct."); + m_commands.emplace_back("length", &CommandManager::process_length, UP_SINGLE, CS_ALWAYS, "/length (x (float) | = (int) | check | clear)", "hammers, singleplayers", "Manipulates the length of the games, “= n” fixes the number of laps to n, “x k” sets it to k times default number of laps, “check” displays the setting, “clear” allows players to choose it freely."); + m_commands.emplace_back("queue", &CommandManager::process_queue, UP_SINGLE, CS_ALWAYS, "/queue (show | push[_front] (track) | pop[_back])", "hammers, singleplayers", "Manipulates the track queue aka the next played tracks. “show” displays it, “push” adds the track to the end of the queue, “pop” removes a track at the front. You can use “_back” and “_front” to specify on which end of the queue to add or remove the tracks."); + m_commands.emplace_back("adminstart", &CommandManager::process_adminstart, UP_HAMMER, CS_ALWAYS, "/adminstart [0 | 1]", "hammers", "Toggles whether the game can be started on the server."); + m_commands.emplace_back("shuffle", &CommandManager::process_shuffle, UP_HAMMER, CS_ALWAYS, "/shuffle [0 | 1]", "hammers", "Toggles whether the Grand Prix grid is shuffled before each race (1), or it corresponds to the standings (0)."); + m_commands.emplace_back("timeout", &CommandManager::process_timeout, UP_HAMMER, CS_ALWAYS, "/timeout [positive int x]", "hammers", "Sets the timeout in seconds, whatever it may mean."); + m_commands.emplace_back("team", &CommandManager::process_team, UP_HAMMER, CS_ALWAYS, "/team ([roygbp-]) (username)", "hammers", "Move a player to one of six teams denoted by square emojis (r - red, o - orange, y - yellow, g - green, b - blue, p – purple), or removes the player from the teams (“-”)."); + m_commands.emplace_back("cat+", &CommandManager::process_cat, UP_HAMMER, CS_ALWAYS, "/cat+ (category) (username)", "hammers", "Adds the player to a certain category."); + m_commands.emplace_back("cat-", &CommandManager::process_cat, UP_HAMMER, CS_ALWAYS, "/cat- (category) (username)", "hammers", "Removes the player from a certain category."); + m_commands.emplace_back("cat*", &CommandManager::process_cat, UP_HAMMER, CS_ALWAYS, "/cat* (category) (0 | 1)", "hammers", "Toggles whether a category is displayed in the player list."); + m_commands.emplace_back("troll", &CommandManager::process_troll, UP_HAMMER, CS_ALWAYS, "/troll [0 | 1]", "hammers", "Toggles anti-troll system."); + m_commands.emplace_back("hitmsg", &CommandManager::process_hitmsg, UP_HAMMER, CS_ALWAYS, "/hitmsg [0 | 1]", "hammers", "Toggles whether the messages about teammate hits are displayed."); + m_commands.emplace_back("teamhit", &CommandManager::process_teamhit, UP_HAMMER, CS_ALWAYS, "/teamhit [0 | 1]", "hammers", "Toggles whether the teammate hits are punished ingame."); + m_commands.emplace_back("version", &CommandManager::process_text, UP_EVERYONE, CS_ALWAYS, "/version", "everyone", "Displays version."); + m_commands.emplace_back("clear", &CommandManager::process_text, UP_EVERYONE, CS_ALWAYS, "/clear", "everyone", "Puts newlines onto the screen so that the previous messages are not visible."); + m_commands.emplace_back("register", &CommandManager::process_register, UP_EVERYONE, CS_ALWAYS, "/register [info]", "everyone", "The command is used to register to an event (if the server has a database to store the registrations). Players can provide information while registering."); #ifdef ENABLE_WEB_SUPPORT - m_commands.emplace_back("token", &CommandManager::process_token, UP_EVERYONE); + m_commands.emplace_back("token", &CommandManager::process_token, UP_EVERYONE, CS_ALWAYS, "/token", "everyone", "Produces a token for a player and stores it in the database (if the server has a database to store tokens). Tokens may be used to authenticate players using their STK accounts."); #endif - m_commands.emplace_back("muteall", &CommandManager::process_muteall, UP_EVERYONE, CS_SOCCER_TOURNAMENT); - m_commands.emplace_back("game", &CommandManager::process_game, UP_HAMMER, CS_SOCCER_TOURNAMENT); - m_commands.emplace_back("role", &CommandManager::process_role, UP_HAMMER, CS_SOCCER_TOURNAMENT); - m_commands.emplace_back("stop", &CommandManager::process_stop, UP_HAMMER, CS_SOCCER_TOURNAMENT); - m_commands.emplace_back("go", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT); - m_commands.emplace_back("play", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT); - m_commands.emplace_back("resume", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT); - m_commands.emplace_back("lobby", &CommandManager::process_lobby, UP_HAMMER, CS_SOCCER_TOURNAMENT); - m_commands.emplace_back("init", &CommandManager::process_init, UP_HAMMER, CS_SOCCER_TOURNAMENT); - m_commands.emplace_back("vote", &CommandManager::special, UP_EVERYONE); - - m_commands.emplace_back("mimiz", &CommandManager::process_mimiz, UP_EVERYONE); - m_commands.emplace_back("test", &CommandManager::process_test, UP_EVERYONE | PE_VOTED); + m_commands.emplace_back("muteall", &CommandManager::process_muteall, UP_EVERYONE, CS_SOCCER_TOURNAMENT, "/muteall [0 | 1]", "everyone in soccer tournament mode", "Toggles whether a player wants to receive messages from anyone except acting players and referees in soccer tournament mode (this may be forced for acting player and referees using config)."); + m_commands.emplace_back("game", &CommandManager::process_game, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/game [number] [length]", "soccer tournament referees", "Prepares the server for a certain game, with certain duration or number of goals."); + m_commands.emplace_back("role", &CommandManager::process_role, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/role ([rbjsRBJS]) (username | #Category)", "soccer tournament referees", "Assigns a role to a player. Roles include: “r” and “b” - acting players with red and blue colors, respectively; “j” - judge/referee, “s” – spectator. May be done simultaneously for a specified category. Fails if the player doesn’t satisfy the requirements for the role."); + m_commands.emplace_back("stop", &CommandManager::process_stop, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/stop", "soccer tournament referees", "Disables goal counting during the game."); + m_commands.emplace_back("go", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/go", "soccer tournament referees", "Enables goal counting during the game."); + m_commands.emplace_back("play", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/play", "soccer tournament referees", "Enables goal counting during the game."); + m_commands.emplace_back("resume", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/resume", "soccer tournament referees", "Enables goal counting during the game."); + m_commands.emplace_back("lobby", &CommandManager::process_lobby, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/lobby", "soccer tournament referees", "Forces players to the lobby through the final screen, stoppng the game."); + m_commands.emplace_back("init", &CommandManager::process_init, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/init (red count) (blue count)", "soccer tournament referees", "Initializes the match score to start from (red count):(blue count) instead of 0:0."); + m_commands.emplace_back("vote", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/vote (command with arguments, without “/”)", "everyone", "Casts a vote for the provided command, if it can be voted. Only useful for those players who can enforce their command but opt to vote instead of forcing; for those players who cannot invoke the command alone, /(command) is equivalent to /vote (command)."); + m_commands.emplace_back("mimiz", &CommandManager::process_mimiz, UP_EVERYONE, CS_ALWAYS, "/mimiz [text]", "everyone", "A joke command."); + m_commands.emplace_back("test", &CommandManager::process_test, UP_EVERYONE | PE_VOTED, CS_ALWAYS, "/test [poll name] [option name]", "everyone; votable", "A test command."); + m_commands.emplace_back("help", &CommandManager::process_help, UP_EVERYONE, CS_ALWAYS, "/help (command name)", "everyone", "Gives description of a given command."); addTextResponse("moreinfo", StringUtils::wideToUtf8(m_lobby->m_help_message)); addTextResponse("version", "1.3-rc1 k 210fff beta"); @@ -141,6 +141,8 @@ void CommandManager::initCommands() std::sort(m_commands.begin(), m_commands.end(), [](const Command& a, const Command& b) -> bool { return a.m_name < b.m_name; }); + for (auto& command: m_commands) + m_name_to_command[command.m_name] = command; m_votables.emplace("replay", 1.0); m_votables.emplace("start", 0.9); @@ -190,12 +192,12 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) action = "vote for"; } - for (auto& command: m_commands) - { - if (argv[0] != command.m_name) - continue; + auto command_iterator = m_name_to_command.find(argv[0]); + found_command = (command_iterator != m_name_to_command.end()); - found_command = true; + if (found_command) + { + const auto& command = command_iterator->second; if (!isAvailable(command)) { std::string msg = "You don't have permissions to " + action + " this command"; @@ -239,15 +241,13 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) } } } - } - - if (!found_command) - { - std::string msg = "Command " + argv[0] + " not found"; - m_lobby->sendStringToPeer(msg, peer); + return; } // TODO: process commands with typos + std::string msg = "Command " + argv[0] + " not found"; + m_lobby->sendStringToPeer(msg, peer); + // TODO: add votedness } // handleCommand @@ -280,6 +280,63 @@ void CommandManager::vote(Context& context, std::string category, std::string va } // vote // ======================================================================== +void CommandManager::update() +{ + for (auto& votable_pairs: m_votables) + { + auto& votable = votable_pairs.second; + auto response = votable.process(m_users); + auto res = response.second; + if (!res.empty()) + { + for (auto& p: res) + { + std::string new_cmd = p.first + " " + p.second; + std::string msg = "Command \"" + new_cmd + "\" has been successfully voted"; + m_lobby->sendStringToAllPeers(msg); + auto new_argv = StringUtils::split(new_cmd, ' '); + auto& command = m_name_to_command[new_argv[0]]; + // We don't know the event though it is only needed in + // ServerLobby::startSelection where it is nullptr when they vote + Context new_context(nullptr, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); + (this->*command.m_action)(new_context); + } + } + } +} // update +// ======================================================================== + +void CommandManager::error(Context& context) +{ + std::string command = context.m_argv[0]; + // Here we assume that the command argv[0] exists, + // as we intend to invoke error() from process_* functions + std::string msg = m_name_to_command[command].getUsage(); + if (msg.empty()) + msg = "An error occurred while invoking command \"" + context.m_argv[0] + "\"."; + m_lobby->sendStringToPeer(msg, context.m_peer); +} // error +// ======================================================================== + +void CommandManager::process_help(Context& context) +{ + auto argv = context.m_argv; + if (argv.size() < 2) + { + error(context); + return; + } + std::string msg; + auto it = m_name_to_command.find(argv[1]); + if (it == m_name_to_command.end()) + msg = "Unknown command \"" + argv[1] + "\""; + else + msg = it->second.getHelp(); + + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_commands +// ======================================================================== + void CommandManager::process_text(Context& context) { std::string response; @@ -290,7 +347,7 @@ void CommandManager::process_text(Context& context) else response = it->second; m_lobby->sendStringToPeer(response, context.m_peer); -} // process_commands +} // process_text // ======================================================================== void CommandManager::process_commands(Context& context) @@ -426,8 +483,7 @@ void CommandManager::process_spectate(Context& context) if (argv.size() != 2 || (argv[1] != "0" && argv[1] != "1")) { - std::string msg = "Usage: /spectate [empty or 0 or 1]"; - m_lobby->sendStringToPeer(msg, peer); + error(context); return; } @@ -707,22 +763,16 @@ void CommandManager::process_kick(Context& context) { auto& cmd = context.m_cmd; auto& peer = context.m_peer; - std::string player_name; - if (StringUtils::startsWith(cmd, "kickban")) - { - if (cmd.length() > 8) - player_name = cmd.substr(8); - } - else if (cmd.length() > 5) - { - player_name = cmd.substr(5); - } + auto& argv = context.m_argv; + + int arg_length = argv[0].size(); + std::string player_name = cmd.substr(arg_length + 1); + std::shared_ptr player_peer = STKHost::get()->findPeerByName( StringUtils::utf8ToWide(player_name)); if (player_name.empty() || !player_peer || player_peer->isAIPeer()) { - std::string msg = "Usage: /kick [player name]"; - m_lobby->sendStringToPeer(msg, context.m_peer); + error(context); return; } if (player_peer->isAngryHost()) @@ -891,8 +941,7 @@ void CommandManager::process_mute(Context& context) if (argv.size() != 2 || argv[1].empty()) { - std::string msg = "Usage: /mute player_name (not including yourself)"; - m_lobby->sendStringToPeer(msg, context.m_peer); + error(context); return; } @@ -901,8 +950,7 @@ void CommandManager::process_mute(Context& context) if (!player_peer || player_peer == peer) { - std::string msg = "Usage: /mute player_name (not including yourself)"; - m_lobby->sendStringToPeer(msg, context.m_peer); + error(context); return; } @@ -922,8 +970,7 @@ void CommandManager::process_unmute(Context& context) if (argv.size() != 2 || argv[1].empty()) { - result_msg = "Usage: /unmute player_name"; - m_lobby->sendStringToPeer(result_msg, context.m_peer); + error(context); return; } @@ -944,8 +991,7 @@ void CommandManager::process_unmute(Context& context) } } - result_msg = "Usage: /unmute player_name"; - m_lobby->sendStringToPeer(result_msg, context.m_peer); + error(context); } // process_unmute // ======================================================================== @@ -1019,8 +1065,7 @@ void CommandManager::process_tell(Context& context) auto& argv = context.m_argv; if (argv.size() == 1) { - std::string response = "Tell something non-empty"; - m_lobby->sendStringToPeer(response, context.m_peer); + error(context); return; } std::string ans; @@ -1038,21 +1083,22 @@ void CommandManager::process_standings(Context& context) { std::string msg; auto& argv = context.m_argv; - if (argv.size() > 1) + if (argv.size() == 1) { - if (argv[1] == "gp") - msg = m_lobby->getGrandPrixStandings(); - else if (argv[1] == "gnu") - msg = m_lobby->m_kart_elimination.getStandings(); + if (m_lobby->m_game_setup->isGrandPrix()) + argv.push_back("gp"); else - msg = "Usage: /standings [gp | gnu]"; - m_lobby->sendStringToPeer(msg, context.m_peer); - return; + argv.push_back("gnu"); } - if (m_lobby->m_game_setup->isGrandPrix()) + if (argv[1] == "gp") msg = m_lobby->getGrandPrixStandings(); - else + else if (argv[1] == "gnu") msg = m_lobby->m_kart_elimination.getStandings(); + else + { + error(context); + return; + } m_lobby->sendStringToPeer(msg, context.m_peer); } // process_standings // ======================================================================== @@ -1168,8 +1214,7 @@ void CommandManager::process_length(Context& context) std::string msg; if (argv.size() < 2) { - msg = "Usage: /length (x (float) | = (int) | check | clear)"; - m_lobby->sendStringToPeer(msg, context.m_peer); + error(context); return; } if (argv[1] == "check") @@ -1221,9 +1266,8 @@ void CommandManager::process_length(Context& context) m_lobby->sendStringToAllPeers(msg); return; } - msg = "Usage: /length (x (float) | = (int) | check | clear)"; - m_lobby->sendStringToPeer(msg, context.m_peer); - return; + + error(context); } // process_length // ======================================================================== @@ -1231,10 +1275,9 @@ void CommandManager::process_queue(Context& context) { std::string msg; auto& argv = context.m_argv; - std::string format_string = "Format: /queue (show | push[_front] (track) | pop[_back])"; if (argv.size() < 2) { - m_lobby->sendStringToPeer(format_string, context.m_peer); + error(context); return; } if (argv[1] == "show") @@ -1250,7 +1293,7 @@ void CommandManager::process_queue(Context& context) { if (argv.size() < 3) { - m_lobby->sendStringToPeer(format_string, context.m_peer); + error(context); return; } m_lobby->m_tracks_queue.push_back(argv[2]); @@ -1263,7 +1306,7 @@ void CommandManager::process_queue(Context& context) { if (argv.size() < 3) { - m_lobby->sendStringToPeer(format_string, context.m_peer); + error(context); return; } m_lobby->m_tracks_queue.push_front(argv[2]); @@ -1313,8 +1356,7 @@ void CommandManager::process_adminstart(Context& context) auto& argv = context.m_argv; if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) { - msg = "Usage: /adminstart [0/1] - allow or forbid starting a race"; - m_lobby->sendStringToPeer(msg, context.m_peer); + error(context); return; } if (argv[1] == "0") @@ -1337,8 +1379,7 @@ void CommandManager::process_shuffle(Context& context) auto& argv = context.m_argv; if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) { - msg = "Usage: /shuffle [0/1] - make the GP grid shuffled all the time, or make it result-based"; - m_lobby->sendStringToPeer(msg, context.m_peer); + error(context); return; } if (argv[1] == "0") @@ -1360,8 +1401,7 @@ void CommandManager::process_timeout(Context& context) auto& argv = context.m_argv; if (argv.size() < 2 || !StringUtils::parseString(argv[1], &seconds) || seconds <= 0) { - msg = "Usage: /timeout [positive int x] - set timeout to x seconds"; - m_lobby->sendStringToPeer(msg, context.m_peer); + error(context); return; } m_lobby->m_timeout.store((int64_t)StkTime::getMonoTimeMs() + @@ -1376,10 +1416,9 @@ void CommandManager::process_team(Context& context) { std::string msg; auto& argv = context.m_argv; - if (argv.size() != 3) { - msg = "Usage: /team (color/0..6) (player) - move a player " - "to a team, or remove from teams (none/0)"; - m_lobby->sendStringToPeer(msg, context.m_peer); + if (argv.size() != 3) + { + error(context); return; } auto it = m_lobby->m_team_name_to_index.find(argv[1]); @@ -1444,9 +1483,9 @@ void CommandManager::process_cat(Context& context) auto& argv = context.m_argv; if (argv[0] == "cat+") { - if (argv.size() != 3) { - msg = "Usage: /cat+ (category) (player) - add a player to a category"; - m_lobby->sendStringToPeer(msg, context.m_peer); + if (argv.size() != 3) + { + error(context); return; } std::string category = argv[1]; @@ -1458,9 +1497,9 @@ void CommandManager::process_cat(Context& context) } if (argv[0] == "cat-") { - if (argv.size() != 3) { - msg = "Usage: /cat- (category) (player) - remove a player from a category"; - m_lobby->sendStringToPeer(msg, context.m_peer); + if (argv.size() != 3) + { + error(context); return; } std::string category = argv[1]; @@ -1474,9 +1513,9 @@ void CommandManager::process_cat(Context& context) { int displayed; if (argv.size() != 3 || !StringUtils::parseString(argv[2], &displayed) - || displayed < 0 || displayed > 1) { - msg = "Usage: /cat* (category) (0|1) - make category displayed or not"; - m_lobby->sendStringToPeer(msg, context.m_peer); + || displayed < 0 || displayed > 1) + { + error(context); return; } std::string category = argv[1]; @@ -1497,8 +1536,7 @@ void CommandManager::process_troll(Context& context) auto& argv = context.m_argv; if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) { - msg = "Usage: /troll [0/1] - disable or enable anti troll system"; - m_lobby->sendStringToPeer(msg, context.m_peer); + error(context); return; } if (argv[1] == "0") @@ -1519,9 +1557,7 @@ void CommandManager::process_hitmsg(Context& context) auto& argv = context.m_argv; if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) { - msg = "Usage: /hitmsg [0/1] - disable or enable messages " - "if a player makes a teammate explode"; - m_lobby->sendStringToPeer(msg, context.m_peer); + error(context); return; } if (argv[1] == "0") @@ -1542,8 +1578,7 @@ void CommandManager::process_teamhit(Context& context) auto& argv = context.m_argv; if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) { - msg = "Usage: /teamhit [0/1] - disable or enable punish mode when hitting team mates"; - m_lobby->sendStringToPeer(msg, context.m_peer); + error(context); return; } if (argv[1] == "0") @@ -1686,9 +1721,7 @@ void CommandManager::process_game(Context& context) bool ok = StringUtils::parseString(argv[2], &length); if (!ok || length <= 0) { - std::string msg = "Please specify a correct number. " - "Format: /game [number] [length]"; - m_lobby->sendStringToPeer(msg, peer); + error(context); return; } } @@ -1717,8 +1750,7 @@ void CommandManager::process_role(Context& context) peer->getPlayerProfiles()[0]->getName()); if (argv.size() < 3) { - std::string msg = "Format: /role (R|B|J|S) username"; - m_lobby->sendStringToPeer(msg, peer); + error(context); return; } std::string role = argv[1]; @@ -1729,8 +1761,7 @@ void CommandManager::process_role(Context& context) std::swap(role, username); if (role.length() != 1) { - std::string msg = "Please specify one-letter role (R/B/J/S) and player"; - m_lobby->sendStringToPeer(msg, peer); + error(context); return; } if (role[0] >= 'A' && role[0] <= 'Z') @@ -1934,8 +1965,7 @@ void CommandManager::process_init(Context& context) !StringUtils::parseString(argv[1], &red) || !StringUtils::parseString(argv[2], &blue)) { - std::string msg = "Usage: /init [red_count] [blue_count]"; - m_lobby->sendStringToPeer(msg, peer); + error(context); return; } World* w = World::getWorld(); @@ -2000,6 +2030,7 @@ void CommandManager::special(Context& context) void CommandManager::addUser(std::string& s) { m_users.insert(s); + update(); } // addUser // ======================================================================== @@ -2012,5 +2043,6 @@ void CommandManager::deleteUser(std::string& s) return; } m_users.erase(it); + update(); } // deleteUser // ======================================================================== \ No newline at end of file diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 373fcee91a5..d2635b81b35 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -82,9 +82,24 @@ class CommandManager int m_scope; + std::string m_usage; + + std::string m_description; + + std::string m_verbose_permissions; + + Command() {} + Command(std::string name, - void (CommandManager::*f)(Context& context), int permissions, int scope = CS_ALWAYS): - m_name(name), m_permissions(permissions), m_action(f), m_scope(scope) {} + void (CommandManager::*f)(Context& context), int permissions, int scope = CS_ALWAYS, + std::string usage = "", std::string verbose_permissions = "", std::string description = ""): + m_name(name), m_permissions(permissions), m_action(f), m_scope(scope), + m_usage(usage), m_description(description), + m_verbose_permissions(verbose_permissions) {} + + std::string getUsage() { return "Usage: " + m_usage; } + + std::string getHelp() { return "Usage: " + m_usage + "\n" + m_verbose_permissions + "\n" + m_description; } }; private: @@ -93,6 +108,8 @@ class CommandManager std::vector m_commands; + std::map m_name_to_command; + std::multiset m_users; std::map m_text_response; @@ -106,6 +123,10 @@ class CommandManager bool isAvailable(const Command& c); void vote(Context& context, std::string category, std::string value); + void update(); + void error(Context& context); + + void process_help(Context& context); void process_text(Context& context); void process_commands(Context& context); void process_replay(Context& context); From 6d29c8a52d3346ffe08a3ff4c547e48c21887ea6 Mon Sep 17 00:00:00 2001 From: kimden Date: Sat, 25 Sep 2021 01:56:49 +0300 Subject: [PATCH 143/830] Fix argv for voted commands, parse quoted arguments with spaces inside --- src/network/protocols/command_manager.cpp | 407 +++++++++++----------- src/network/protocols/command_manager.hpp | 2 +- src/utils/string_utils.cpp | 68 ++++ src/utils/string_utils.hpp | 1 + 4 files changed, 272 insertions(+), 206 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 0ddec2ae775..9b25930dea0 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -145,10 +145,10 @@ void CommandManager::initCommands() m_name_to_command[command.m_name] = command; m_votables.emplace("replay", 1.0); - m_votables.emplace("start", 0.9); + m_votables.emplace("start", 0.81); m_votables.emplace("config", 0.6); - m_votables.emplace("kick", 0.9); - m_votables.emplace("kickban", 0.9); + m_votables.emplace("kick", 0.81); + m_votables.emplace("kickban", 0.81); } // initCommands // ======================================================================== @@ -169,7 +169,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) data.decodeString(&language); std::string cmd; data.decodeString(&cmd); - auto argv = StringUtils::split(cmd, ' '); + auto argv = StringUtils::splitQuoted(cmd, ' ', '"', '\\'); if (argv.size() == 0) return; @@ -185,6 +185,11 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) m_lobby->sendStringToPeer(msg, peer); return; } + std::reverse(cmd.begin(), cmd.end()); + cmd.resize((int)cmd.size() - 4); + while (!cmd.empty() && cmd.back() == ' ') + cmd.pop_back(); + std::reverse(cmd.begin(), cmd.end()); std::reverse(argv.begin(), argv.end()); argv.pop_back(); std::reverse(argv.begin(), argv.end()); @@ -235,7 +240,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) std::string new_cmd = p.first + " " + p.second; std::string msg = "Command \"" + new_cmd + "\" has been successfully voted"; m_lobby->sendStringToAllPeers(msg); - auto new_argv = StringUtils::split(new_cmd, ' '); + auto new_argv = StringUtils::splitQuoted(cmd, ' ', '"', '\\'); Context new_context(event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); (this->*command.m_action)(new_context); } @@ -294,7 +299,7 @@ void CommandManager::update() std::string new_cmd = p.first + " " + p.second; std::string msg = "Command \"" + new_cmd + "\" has been successfully voted"; m_lobby->sendStringToAllPeers(msg); - auto new_argv = StringUtils::split(new_cmd, ' '); + auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '\\'); auto& command = m_name_to_command[new_argv[0]]; // We don't know the event though it is only needed in // ServerLobby::startSelection where it is nullptr when they vote @@ -320,7 +325,7 @@ void CommandManager::error(Context& context) void CommandManager::process_help(Context& context) { - auto argv = context.m_argv; + auto& argv = context.m_argv; if (argv.size() < 2) { error(context); @@ -447,7 +452,7 @@ void CommandManager::process_spectate(Context& context) { std::string response = ""; auto& argv = context.m_argv; - auto peer = context.m_peer; + auto& peer = context.m_peer; if (ServerConfig::m_soccer_tournament || ServerConfig::m_only_host_riding) response = "All spectators already have auto spectate ability"; @@ -643,63 +648,59 @@ void CommandManager::process_lsa(Context& context) (argv.size() == 2 && (argv[1].size() < 3 || has_options)) || (argv.size() == 3 && (!has_options || argv[2].size() < 3))) { - response = "Usage: /listserveraddon [option][addon string to find " - "(at least 3 characters)]. Available options: " - "-track, -arena, -kart, -soccer."; + error(context); + return; } - else + std::string type = ""; + std::string text = ""; + if (argv.size() > 1) { - std::string type = ""; - std::string text = ""; - if (argv.size() > 1) - { - if (argv[1].compare("-track") == 0 || - argv[1].compare("-arena") == 0 || - argv[1].compare("-kart") == 0 || - argv[1].compare("-soccer") == 0) - type = argv[1].substr(1); - if ((argv.size() == 2 && type.empty()) || argv.size() == 3) - text = argv[argv.size() - 1]; - } + if (argv[1].compare("-track") == 0 || + argv[1].compare("-arena") == 0 || + argv[1].compare("-kart") == 0 || + argv[1].compare("-soccer") == 0) + type = argv[1].substr(1); + if ((argv.size() == 2 && type.empty()) || argv.size() == 3) + text = argv[argv.size() - 1]; + } - std::set total_addons; - if (type.empty() || // not specify addon type - (!type.empty() && type.compare("kart") == 0)) // list kart addon - { - total_addons.insert(m_lobby->m_addon_kts.first.begin(), m_lobby->m_addon_kts.first.end()); - } - if (type.empty() || // not specify addon type - (!type.empty() && type.compare("track") == 0)) - { - total_addons.insert(m_lobby->m_addon_kts.second.begin(), m_lobby->m_addon_kts.second.end()); - } - if (type.empty() || // not specify addon type - (!type.empty() && type.compare("arena") == 0)) - { - total_addons.insert(m_lobby->m_addon_arenas.begin(), m_lobby->m_addon_arenas.end()); - } - if (type.empty() || // not specify addon type - (!type.empty() && type.compare("soccer") == 0)) - { - total_addons.insert(m_lobby->m_addon_soccers.begin(), m_lobby->m_addon_soccers.end()); - } - std::string msg = ""; - for (auto& addon : total_addons) - { - // addon_ (6 letters) - if (!text.empty() && addon.find(text, 6) == std::string::npos) - continue; + std::set total_addons; + if (type.empty() || // not specify addon type + (!type.empty() && type.compare("kart") == 0)) // list kart addon + { + total_addons.insert(m_lobby->m_addon_kts.first.begin(), m_lobby->m_addon_kts.first.end()); + } + if (type.empty() || // not specify addon type + (!type.empty() && type.compare("track") == 0)) + { + total_addons.insert(m_lobby->m_addon_kts.second.begin(), m_lobby->m_addon_kts.second.end()); + } + if (type.empty() || // not specify addon type + (!type.empty() && type.compare("arena") == 0)) + { + total_addons.insert(m_lobby->m_addon_arenas.begin(), m_lobby->m_addon_arenas.end()); + } + if (type.empty() || // not specify addon type + (!type.empty() && type.compare("soccer") == 0)) + { + total_addons.insert(m_lobby->m_addon_soccers.begin(), m_lobby->m_addon_soccers.end()); + } + std::string msg = ""; + for (auto& addon : total_addons) + { + // addon_ (6 letters) + if (!text.empty() && addon.find(text, 6) == std::string::npos) + continue; - msg += addon.substr(6); - msg += ", "; - } - if (msg.empty()) - response = "Addon not found"; - else - { - msg = msg.substr(0, msg.size() - 2); - response = "Server's addons: " + msg; - } + msg += addon.substr(6); + msg += ", "; + } + if (msg.empty()) + response = "Addon not found"; + else + { + msg = msg.substr(0, msg.size() - 2); + response = "Server's addons: " + msg; } m_lobby->sendStringToPeer(response, context.m_peer); } // process_lsa @@ -708,52 +709,52 @@ void CommandManager::process_lsa(Context& context) void CommandManager::process_pha(Context& context) { std::string response = ""; - std::string cmd = context.m_cmd; - std::string part; - if (cmd.length() > 15) - part = cmd.substr(15); - std::string addon_id = part.substr(0, part.find(' ')); - std::string player_name; - if (part.length() > addon_id.length() + 1) - player_name = part.substr(addon_id.length() + 1); + auto& argv = context.m_argv; + if (argv.size() < 3) + { + error(context); + return; + } + + std::string addon_id = argv[1]; + std::string player_name = argv[2]; std::shared_ptr player_peer = STKHost::get()->findPeerByName( StringUtils::utf8ToWide(player_name)); if (player_name.empty() || !player_peer || addon_id.empty()) { - response = "Usage: /playerhasaddon [addon_identity] [player name]"; + error(context); + return; } - else + + std::string addon_id_test = Addon::createAddonId(addon_id); + bool found = false; + const auto& kt = player_peer->getClientAssets(); + for (auto& kart : kt.first) { - std::string addon_id_test = Addon::createAddonId(addon_id); - bool found = false; - const auto& kt = player_peer->getClientAssets(); - for (auto& kart : kt.first) + if (kart == addon_id_test) { - if (kart == addon_id_test) - { - found = true; - break; - } + found = true; + break; } - if (!found) + } + if (!found) + { + for (auto& track : kt.second) { - for (auto& track : kt.second) + if (track == addon_id_test) { - if (track == addon_id_test) - { - found = true; - break; - } + found = true; + break; } } - if (found) - { - response = player_name + " has addon " + addon_id; - } - else - { - response = player_name + " has no addon " + addon_id; - } + } + if (found) + { + response = player_name + " has addon " + addon_id; + } + else + { + response = player_name + " has no addon " + addon_id; } m_lobby->sendStringToPeer(response, context.m_peer); } // process_pha @@ -761,12 +762,15 @@ void CommandManager::process_pha(Context& context) void CommandManager::process_kick(Context& context) { - auto& cmd = context.m_cmd; auto& peer = context.m_peer; auto& argv = context.m_argv; - int arg_length = argv[0].size(); - std::string player_name = cmd.substr(arg_length + 1); + if (argv.size() < 2) + { + error(context); + return; + } + std::string player_name = argv[1]; std::shared_ptr player_peer = STKHost::get()->findPeerByName( StringUtils::utf8ToWide(player_name)); @@ -800,7 +804,7 @@ void CommandManager::process_kick(Context& context) std::string auto_report = "[ Auto report caused by kick ]"; m_lobby->writeOwnReport(player_peer.get(), peer.get(), auto_report); } - if (StringUtils::startsWith(cmd, "kickban")) + if (argv[0] == "kickban") { Log::info("CommandManager", "%s is now banned", player_name.c_str()); m_lobby->m_temp_banned.insert(player_name); @@ -813,49 +817,46 @@ void CommandManager::process_kick(Context& context) void CommandManager::process_unban(Context& context) { - std::string player_name; - auto& cmd = context.m_cmd; - if (cmd.length() > 6) + auto& argv = context.m_argv; + if (argv.size() < 2) { - player_name = cmd.substr(6); + error(context); + return; } + std::string player_name = argv[1]; if (player_name.empty()) { - std::string msg = "Usage: /unban [player name]"; - m_lobby->sendStringToPeer(msg, context.m_peer); - } - else - { - Log::info("CommandManager", "%s is now unbanned", player_name.c_str()); - m_lobby->m_temp_banned.erase(player_name); - std::string msg = StringUtils::insertValues( - "%s is now unbanned", player_name.c_str()); - m_lobby->sendStringToPeer(msg, context.m_peer); + error(context); + return; } + Log::info("CommandManager", "%s is now unbanned", player_name.c_str()); + m_lobby->m_temp_banned.erase(player_name); + std::string msg = StringUtils::insertValues( + "%s is now unbanned", player_name.c_str()); + m_lobby->sendStringToPeer(msg, context.m_peer); } // process_unban // ======================================================================== void CommandManager::process_ban(Context& context) { std::string player_name; - auto& cmd = context.m_cmd; - if (cmd.length() > 4) + auto& argv = context.m_argv; + if (argv.size() < 2) { - player_name = cmd.substr(4); + error(context); + return; } + player_name = argv[1]; if (player_name.empty()) { - std::string msg = "Usage: /ban [player name]"; - m_lobby->sendStringToPeer(msg, context.m_peer); - } - else - { - Log::info("CommandManager", "%s is now banned", player_name.c_str()); - m_lobby->m_temp_banned.insert(player_name); - std::string msg = StringUtils::insertValues( - "%s is now banned", player_name.c_str()); - m_lobby->sendStringToPeer(msg, context.m_peer); + error(context); + return; } + Log::info("CommandManager", "%s is now banned", player_name.c_str()); + m_lobby->m_temp_banned.insert(player_name); + std::string msg = StringUtils::insertValues( + "%s is now banned", player_name.c_str()); + m_lobby->sendStringToPeer(msg, context.m_peer); } // process_ban // ======================================================================== @@ -863,39 +864,40 @@ void CommandManager::process_pas(Context& context) { std::string response; std::string player_name; - auto& cmd = context.m_cmd; - if (cmd.length() > 17) - player_name = cmd.substr(17); + auto& argv = context.m_argv; + if (argv.size() < 2) + { + error(context); + return; + } + player_name = argv[1]; std::shared_ptr player_peer = STKHost::get()->findPeerByName( StringUtils::utf8ToWide(player_name)); if (player_name.empty() || !player_peer) { - response = "Usage: /playeraddonscore [player name] " - "(returns the number of addons, not a percentage)"; + error(context); + return; + } + auto& scores = player_peer->getAddonsScores(); + if (scores[AS_KART] == -1 && scores[AS_TRACK] == -1 && + scores[AS_ARENA] == -1 && scores[AS_SOCCER] == -1) + { + response = player_name + " has no addons"; } else { - auto& scores = player_peer->getAddonsScores(); - if (scores[AS_KART] == -1 && scores[AS_TRACK] == -1 && - scores[AS_ARENA] == -1 && scores[AS_SOCCER] == -1) - { - response = player_name + " has no addons"; - } - else - { - std::string msg = player_name; - msg += " addons:"; - if (scores[AS_KART] != -1) - msg += " karts: " + StringUtils::toString(scores[AS_KART]) + ","; - if (scores[AS_TRACK] != -1) - msg += " tracks: " + StringUtils::toString(scores[AS_TRACK]) + ","; - if (scores[AS_ARENA] != -1) - msg += " arenas: " + StringUtils::toString(scores[AS_ARENA]) + ","; - if (scores[AS_SOCCER] != -1) - msg += " fields: " + StringUtils::toString(scores[AS_SOCCER]) + ","; - msg.pop_back(); - response = msg; - } + std::string msg = player_name; + msg += " addons:"; + if (scores[AS_KART] != -1) + msg += " karts: " + StringUtils::toString(scores[AS_KART]) + ","; + if (scores[AS_TRACK] != -1) + msg += " tracks: " + StringUtils::toString(scores[AS_TRACK]) + ","; + if (scores[AS_ARENA] != -1) + msg += " arenas: " + StringUtils::toString(scores[AS_ARENA]) + ","; + if (scores[AS_SOCCER] != -1) + msg += " fields: " + StringUtils::toString(scores[AS_SOCCER]) + ","; + msg.pop_back(); + response = msg; } m_lobby->sendStringToPeer(response, context.m_peer); } // process_pas @@ -907,25 +909,23 @@ void CommandManager::process_sha(Context& context) auto& argv = context.m_argv; if (argv.size() != 2) { - response = "Usage: /serverhasaddon [addon_identity]"; + error(context); + return; + } + std::set total_addons; + total_addons.insert(m_lobby->m_addon_kts.first.begin(), m_lobby->m_addon_kts.first.end()); + total_addons.insert(m_lobby->m_addon_kts.second.begin(), m_lobby->m_addon_kts.second.end()); + total_addons.insert(m_lobby->m_addon_arenas.begin(), m_lobby->m_addon_arenas.end()); + total_addons.insert(m_lobby->m_addon_soccers.begin(), m_lobby->m_addon_soccers.end()); + std::string addon_id_test = Addon::createAddonId(argv[1]); + bool found = total_addons.find(addon_id_test) != total_addons.end(); + if (found) + { + response = "Server has addon " + argv[1]; } else { - std::set total_addons; - total_addons.insert(m_lobby->m_addon_kts.first.begin(), m_lobby->m_addon_kts.first.end()); - total_addons.insert(m_lobby->m_addon_kts.second.begin(), m_lobby->m_addon_kts.second.end()); - total_addons.insert(m_lobby->m_addon_arenas.begin(), m_lobby->m_addon_arenas.end()); - total_addons.insert(m_lobby->m_addon_soccers.begin(), m_lobby->m_addon_soccers.end()); - std::string addon_id_test = Addon::createAddonId(argv[1]); - bool found = total_addons.find(addon_id_test) != total_addons.end(); - if (found) - { - response = "Server has addon " + argv[1]; - } - else - { - response = "Server has no addon " + argv[1]; - } + response = "Server has no addon " + argv[1]; } m_lobby->sendStringToPeer(response, context.m_peer); } // process_sha @@ -1116,19 +1116,18 @@ void CommandManager::process_to(Context& context) auto& argv = context.m_argv; if (argv.size() == 1) { - std::string msg = "Usage: /to (username1) ... (usernameN)"; - m_lobby->sendStringToPeer(msg, context.m_peer); - } else { - auto& peer = context.m_peer; - m_lobby->m_message_receivers[peer.get()].clear(); - for (unsigned i = 1; i < argv.size(); ++i) - { - m_lobby->m_message_receivers[peer.get()].insert( - StringUtils::utf8ToWide(argv[i])); - } - std::string msg = "Successfully changed chat settings"; - m_lobby->sendStringToPeer(msg, peer); + error(context); + return; + } + auto& peer = context.m_peer; + m_lobby->m_message_receivers[peer.get()].clear(); + for (unsigned i = 1; i < argv.size(); ++i) + { + m_lobby->m_message_receivers[peer.get()].insert( + StringUtils::utf8ToWide(argv[i])); } + std::string msg = "Successfully changed chat settings"; + m_lobby->sendStringToPeer(msg, peer); } // process_to // ======================================================================== @@ -1149,31 +1148,29 @@ void CommandManager::process_record(Context& context) #ifdef ENABLE_SQLITE3 if (argv.size() < 5) { - response = "Usage: /record (track id) " - "(normal/time-trial) (normal/reverse) (laps)\n" - "Receives the server record for the race settings if any"; - } else { - bool error = false; - std::string track_name = argv[1]; - std::string mode_name = (argv[2] == "t" || argv[2] == "tt" - || argv[2] == "time-trial" || argv[2] == "timetrial" ? - "time-trial" : "normal"); - std::string reverse_name = (argv[3] == "r" || - argv[3] == "rev" || argv[3] == "reverse" ? "reverse" : - "normal"); - int laps_count = -1; - if (!StringUtils::parseString(argv[4], &laps_count)) - error = true; - if (!error && laps_count < 0) - error = true; - if (error) - { - response = "Invalid lap count"; - } - else - { - response = m_lobby->getRecord(track_name, mode_name, reverse_name, laps_count); - } + error(context); + return; + } + bool error = false; + std::string track_name = argv[1]; + std::string mode_name = (argv[2] == "t" || argv[2] == "tt" + || argv[2] == "time-trial" || argv[2] == "timetrial" ? + "time-trial" : "normal"); + std::string reverse_name = (argv[3] == "r" || + argv[3] == "rev" || argv[3] == "reverse" ? "reverse" : + "normal"); + int laps_count = -1; + if (!StringUtils::parseString(argv[4], &laps_count)) + error = true; + if (!error && laps_count < 0) + error = true; + if (error) + { + response = "Invalid lap count"; + } + else + { + response = m_lobby->getRecord(track_name, mode_name, reverse_name, laps_count); } #else response = "This command is not supported."; diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index d2635b81b35..68294347f2a 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -99,7 +99,7 @@ class CommandManager std::string getUsage() { return "Usage: " + m_usage; } - std::string getHelp() { return "Usage: " + m_usage + "\n" + m_verbose_permissions + "\n" + m_description; } + std::string getHelp() { return "Usage: " + m_usage + "\nAvailable to: " + m_verbose_permissions + "\n" + m_description + "\n"; } }; private: diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index eb7b66eb298..b6918472010 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -143,6 +143,74 @@ namespace StringUtils return name; } // toLowerCase + //------------------------------------------------------------------------- + /** Splits a string into substrings separated by a certain character `c`, + * and returns a std::vector of all those substrings. The only exception + * from that is when a substring is enclosed into `d` chars, `c` chars + * inside do not split the substring. `d` chars are escaped with `e`, just + * as `e` chars. E.g.: + * splitQuoted("a b=c |multi word phrase| /|o //", ' ', '|', '/') --> + * ["a", "b=c", "multi word phrase", "|o", "/"] + * \param s The string to split. + * \param c The character by which the string is split. + */ + std::vector splitQuoted(const std::string& s, char c, + char d, char e) + { + std::vector result; + + try + { + result.emplace_back(); + bool quoted = false; + bool escaped = false; + for (unsigned i = 0; i < s.length(); ++i) + { + if (s[i] == e) + { + if (escaped) + result.back().push_back(e); + else + escaped = true; + } + else if (s[i] == d && !escaped) + { + quoted ^= 1; + } + else if (s[i] == c && !quoted) + { + result.emplace_back(); + } + else + { + result.back().push_back(s[i]); + } + } + std::vector cleared_result; + for (const std::string& s: result) + { + if (!s.empty()) + cleared_result.push_back(s); + } + return cleared_result; + } + catch (std::exception& e) + { + Log::error("StringUtils", + "Error in splitQuoted(std::string) : %s @ line %i : %s.", + __FILE__, __LINE__, e.what()); + Log::error("StringUtils", "Splitting '%s'.", s.c_str()); + + for (int n = 0; n < (int)result.size(); n++) + { + Log::error("StringUtils", "Split : %s", result[n].c_str()); + } + + assert(false); // in debug mode, trigger debugger + exit(1); + } + } // split + //------------------------------------------------------------------------- /** Splits a string into substrings separated by a certain character, and * returns a std::vector of all those substring. E.g.: diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index a75cbe56230..de6fdd117b6 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -54,6 +54,7 @@ namespace StringUtils irr::core::stringw loadingDots(const irr::core::stringw& s); std::string toUpperCase(const std::string&); std::string toLowerCase(const std::string&); + std::vector splitQuoted(const std::string& s, char c, char d, char e); std::vector split(const std::string& s, char c, bool keepSplitChar=false); std::vector split(const std::u32string& s, char32_t c, From 770563f2e3a09ca82ad1a599dec38e2d73e0005d Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 21 Oct 2021 03:05:26 +0300 Subject: [PATCH 144/830] Fix crash, try to add votability for /start, /config, /kick, /gnu, add custom thresholds --- src/network/protocols/command_manager.cpp | 258 ++++++++++++++-------- src/network/protocols/command_manager.hpp | 4 +- src/network/protocols/command_voting.cpp | 63 +++++- src/network/protocols/command_voting.hpp | 7 + src/network/protocols/server_lobby.cpp | 2 + src/network/protocols/server_lobby.hpp | 12 +- 6 files changed, 244 insertions(+), 102 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 9b25930dea0..523d9f56b57 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -74,16 +74,21 @@ void CommandManager::initCommands() { + auto kick_permissions = ((ServerConfig::m_kicks_allowed ? UP_CROWNED : UP_HAMMER) | PE_VOTED); + auto start_permissions = (ServerConfig::m_owner_less ? UP_EVERYONE : UP_CROWNED | PE_VOTED); m_commands.emplace_back("commands", &CommandManager::process_commands, UP_EVERYONE, CS_ALWAYS, "/commands", "everyone", "Prints the list of commands available to you. This list may differ depending on server settings and your permissions."); m_commands.emplace_back("replay", &CommandManager::process_replay, UP_SINGLE, CS_ALWAYS, "/replay [0 | 1]", "hammers, singleplayers", "Toggles whether the replay of the race is recorded."); - m_commands.emplace_back("start", &CommandManager::process_start, UP_EVERYONE, CS_ALWAYS, "/start", "everyone", "Basically clicks on the green “Ready” button."); - m_commands.emplace_back("config", &CommandManager::process_config, UP_CROWNED, CS_ALWAYS, "/config ", "crowns", "Changes game mode and difficulty if allowed."); + m_commands.emplace_back("start", &CommandManager::process_start, UP_EVERYONE | PE_VOTED, CS_ALWAYS, "/start", "everyone", "Basically clicks on the green “Ready” button."); + if (ServerConfig::m_server_configurable) + { + m_commands.emplace_back("config", &CommandManager::process_config, UP_CROWNED | PE_VOTED, CS_ALWAYS, "/config ", "crowns; votable", "Changes game mode and difficulty if allowed."); + } m_commands.emplace_back("spectate", &CommandManager::process_spectate, UP_EVERYONE, CS_ALWAYS, "/spectate [0 | 1]", "everyone", "Toggles autospectate mode."); m_commands.emplace_back("addons", &CommandManager::process_addons, UP_EVERYONE, CS_ALWAYS, "/addons [type]", "everyone", "Lists addons installed for all players that can play, in random order. Limits the list to a certain addon type if specified."); m_commands.emplace_back("moreaddons", &CommandManager::process_addons, UP_EVERYONE, CS_ALWAYS, "/moreaddons [type]", "everyone", "Lists top 5 addons that are missing for at least one player, sorted by the number of players that don’t have the addon ascending, random for equal number of players. Limits the list to a certain addon type if specified."); m_commands.emplace_back("listserveraddon", &CommandManager::process_lsa, UP_EVERYONE, CS_ALWAYS, "/listserveraddon [-type] (substring)", "everyone", "Lists addons installed on the server that have a specified substring in their id. Limits the list to a certain addon type if specified."); m_commands.emplace_back("playerhasaddon", &CommandManager::process_pha, UP_EVERYONE, CS_ALWAYS, "/playerhasaddon (addon) (username)", "everyone", "Checks whether a player has a certain addon."); - m_commands.emplace_back("kick", &CommandManager::process_kick, UP_CROWNED | PE_VOTED, CS_ALWAYS, "/kick (username)", "crowns if server allows, hammers; votable", "Kicks a player from the server."); + m_commands.emplace_back("kick", &CommandManager::process_kick, kick_permissions, CS_ALWAYS, "/kick (username)", "crowns if server allows, hammers; votable", "Kicks a player from the server."); m_commands.emplace_back("kickban", &CommandManager::process_kick, UP_HAMMER | PE_VOTED, CS_ALWAYS, "/kickban (username)", "hammers; votable", "Kicks a player from the server and temporarily bans him."); m_commands.emplace_back("unban", &CommandManager::process_unban, UP_HAMMER, CS_ALWAYS, "/unban (username)", "hammers", "Removes a temporary ban from a player."); m_commands.emplace_back("ban", &CommandManager::process_ban, UP_HAMMER, CS_ALWAYS, "/ban (username)", "hammers", "Adds a temporary ban to a player without kicking."); @@ -93,8 +98,8 @@ void CommandManager::initCommands() m_commands.emplace_back("unmute", &CommandManager::process_unmute, UP_EVERYONE, CS_ALWAYS, "/unmute (username)", "everyone", "Unblocks player’s messages from reaching you."); m_commands.emplace_back("listmute", &CommandManager::process_listmute, UP_EVERYONE, CS_ALWAYS, "/listmute", "everyone", "Lists players whom you blocked using /mute command."); m_commands.emplace_back("moreinfo", &CommandManager::process_text, UP_EVERYONE, CS_ALWAYS, "/moreinfo", "everyone", "Displays an additional server message."); - m_commands.emplace_back("gnu", &CommandManager::process_gnu, UP_CROWNED, CS_ALWAYS, "/gnu [kart]", "crowns", "Starts kart elimination with Gnu (or a specified kart)."); - m_commands.emplace_back("nognu", &CommandManager::process_nognu, UP_CROWNED, CS_ALWAYS, "/nognu", "crowns", "Cancels kart elimination."); + m_commands.emplace_back("gnu", &CommandManager::process_gnu, UP_HAMMER | PE_VOTED, CS_ALWAYS, "/gnu [kart]", "hammers; voted", "Starts kart elimination with Gnu (or a specified kart)."); + m_commands.emplace_back("nognu", &CommandManager::process_gnu, UP_HAMMER | PE_VOTED, CS_ALWAYS, "/nognu", "hammers; voted", "Cancels kart elimination."); m_commands.emplace_back("tell", &CommandManager::process_tell, UP_EVERYONE, CS_ALWAYS, "/tell (report contents)", "everyone", "Makes a report to the server owner (if the server has a database to store the reports)."); m_commands.emplace_back("standings", &CommandManager::process_standings, UP_EVERYONE, CS_ALWAYS, "/standings [gp | gnu]", "everyone", "Displays standings of grand prix or kart elimination, picks whatever of them is played now."); m_commands.emplace_back("teamchat", &CommandManager::process_teamchat, UP_EVERYONE, CS_ALWAYS, "/teamchat", "everyone", "Limits your future messages to be sent only to your teammates."); @@ -144,11 +149,13 @@ void CommandManager::initCommands() for (auto& command: m_commands) m_name_to_command[command.m_name] = command; - m_votables.emplace("replay", 1.0); + // m_votables.emplace("replay", 1.0); m_votables.emplace("start", 0.81); m_votables.emplace("config", 0.6); m_votables.emplace("kick", 0.81); m_votables.emplace("kickban", 0.81); + m_votables.emplace("gnu", 0.81); + m_votables["gnu"].setCustomThreshold("gnu kart", 1.1); } // initCommands // ======================================================================== @@ -223,26 +230,31 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) Context context(event, peer, argv, cmd, permissions, voting); (this->*command.m_action)(context); - auto it = m_votables.find(argv[0]); - if (it != m_votables.end() && it->second.needsCheck()) + while (!m_triggered_votables.empty()) { - auto response = it->second.process(m_users); - int count = response.first; - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - std::string msg = username + " voted \"" + cmd + "\", there are " + std::to_string(count) + " such votes"; - m_lobby->sendStringToAllPeers(msg); - auto res = response.second; - if (!res.empty()) + std::string votable_name = m_triggered_votables.front(); + m_triggered_votables.pop(); + auto it = m_votables.find(argv[0]); + if (it != m_votables.end() && it->second.needsCheck()) { - for (auto& p: res) + auto response = it->second.process(m_users); + int count = response.first; + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + std::string msg = username + " voted \"" + cmd + "\", there are " + std::to_string(count) + " such votes"; + m_lobby->sendStringToAllPeers(msg); + auto res = response.second; + if (!res.empty()) { - std::string new_cmd = p.first + " " + p.second; - std::string msg = "Command \"" + new_cmd + "\" has been successfully voted"; - m_lobby->sendStringToAllPeers(msg); - auto new_argv = StringUtils::splitQuoted(cmd, ' ', '"', '\\'); - Context new_context(event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); - (this->*command.m_action)(new_context); + for (auto& p: res) + { + std::string new_cmd = p.first + " " + p.second; + std::string msg = "Command \"" + new_cmd + "\" has been successfully voted"; + m_lobby->sendStringToAllPeers(msg); + auto new_argv = StringUtils::splitQuoted(cmd, ' ', '"', '\\'); + Context new_context(event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); + (this->*command.m_action)(new_context); + } } } } @@ -282,6 +294,8 @@ void CommandManager::vote(Context& context, std::string category, std::string va peer->getPlayerProfiles()[0]->getName()); auto& votable = m_votables[argv[0]]; votable.castVote(username, category, value); + if (votable.needsCheck()) + m_triggered_votables.push(argv[0]); } // vote // ======================================================================== @@ -397,6 +411,11 @@ void CommandManager::process_replay(Context& context) void CommandManager::process_start(Context& context) { + if (context.m_voting) + { + vote(context, "start", ""); + return; + } m_lobby->startSelection(context.m_event); } // process_start // ======================================================================== @@ -408,42 +427,74 @@ void CommandManager::process_config(Context& context) int mode = m_lobby->getGameMode(); bool goal_target = m_lobby->isSoccerGoalTarget(); bool gp = false; + std::vector> mode_aliases = { + {"m0"}, + {"m1"}, + {"m2"}, + {"m3", "normal", "normal-race", "race"}, + {"m4", "tt", "time-trial", "trial"}, + {"m5"}, + {"m6", "soccer", "football"}, + {"m7", "ffa", "free-for-all", "free", "for", "all"}, + {"m8", "ctf", "capture-the-flag", "capture", "the", "flag"} + }; + std::vector> difficulty_aliases = { + {"d0", "novice", "easy"}, + {"d1", "intermediate", "medium"}, + {"d2", "expert", "hard"}, + {"d3", "supertux", "super", "best"} + }; + std::vector> goal_aliases = { + {"gl", "goal-limit", "goal", "goals"}, + {"tl", "time-limit", "time", "minutes"} + }; for (unsigned i = 1; i < argv.size(); i++) { - if (argv[i] == "tt" || argv[i] == "time-trial"|| - argv[i] == "trial" || argv[i] == "m4") - mode = 4; - if (argv[i] == "normal" || argv[i] == "normal-race" || - argv[i] == "race" || argv[i] == "m3") - mode = 3; - if (argv[i] == "soccer" || argv[i] == "football" || - argv[i] == "m6") - mode = 6; - if (argv[i] == "ffa" || argv[i] == "free-for-all" || - argv[i] == "free" || argv[i] == "for" || - argv[i] == "all" || argv[i] == "m7") - mode = 7; - if (argv[i] == "ctf" || argv[i] == "capture-the-flag" - || argv[i] == "capture" || argv[i] == "the" || - argv[i] == "flag" || argv[i] == "m8") - mode = 8; - // if (argv[i] == "gp" || argv[i] == "grand-prix") - // gp = true; - if (argv[i] == "d0" || argv[i] == "novice" || argv[i] == "easy") - difficulty = 0; - if (argv[i] == "d1" || argv[i] == "intermediate" || argv[i] == "medium") - difficulty = 1; - if (argv[i] == "d2" || argv[i] == "expert" || argv[i] == "hard") - difficulty = 2; - if (argv[i] == "d3" || argv[i] == "supertux" || argv[i] == "super" || argv[i] == "best") - difficulty = 3; - if (argv[i] == "goal-limit" || argv[i] == "gl" || argv[i] == "goal" || argv[i] == "goals") - goal_target = true; - if (argv[i] == "time-limit" || argv[i] == "tl" || argv[i] == "time" || argv[i] == "minutes") - goal_target = false; - } - // if (gp && (mode == 3 || mode == 4)) - // mode -= 3; + for (int j = 0; j < mode_aliases.size(); ++j) { + if (j <= 2 || j == 5) { + // Switching to GP or modes 2, 5 is not supported yet + continue; + } + for (std::string& alias: mode_aliases[j]) { + if (argv[i] == alias) { + mode = j; + } + } + } + for (int j = 0; j < difficulty_aliases.size(); ++j) { + for (std::string& alias: difficulty_aliases[j]) { + if (argv[i] == alias) { + difficulty = j; + } + } + } + for (int j = 0; j < goal_aliases.size(); ++j) { + for (std::string& alias: goal_aliases[j]) { + if (argv[i] == alias) { + goal_target = (bool)j; + } + } + } + } + // if (mode != 6) { + // goal_target = false; + // } + if (!m_lobby->isDifficultyAvailable(difficulty) + || !m_lobby->isModeAvailable(mode)) + { + std::string response = "Mode or difficulty are not permitted on this server"; + m_lobby->sendStringToPeer(response, context.m_peer); + return; + } + if (context.m_voting) + { + // Definitely not the best format as there are extra words + // but I'll think how to resolve it + vote(context, "config mode", mode_aliases[mode][0]); + vote(context, "config difficulty", difficulty_aliases[difficulty][0]); + vote(context, "config target", goal_aliases[goal_target ? 1 : 0][0]); + return; + } m_lobby->handleServerConfiguration(context.m_peer, difficulty, mode, goal_target); } // process_config // ======================================================================== @@ -788,13 +839,7 @@ void CommandManager::process_kick(Context& context) } if (context.m_voting) { - vote(context, "kick " + player_name, ""); - return; - } - if (!peer->isAngryHost() && !ServerConfig::m_kicks_allowed) - { - std::string msg = "Kicking players is not allowed on this server"; - m_lobby->sendStringToPeer(msg, peer); + vote(context, argv[0] + " " + player_name, ""); return; } Log::info("CommandManager", "%s kicks %s", (peer.get() ? "Crown player" : "Vote"), player_name.c_str()); @@ -1020,44 +1065,85 @@ void CommandManager::process_listmute(Context& context) void CommandManager::process_gnu(Context& context) { - if (m_lobby->m_kart_elimination.isEnabled()) + auto& argv = context.m_argv; + if (argv[0] != "gnu") + { + argv[0] = "gnu"; + if (argv.size() < 2) { + argv.resize(2); + } + argv[1] = "off"; + } + // "nognu" and "gnu off" are equivalent + bool turn_on = (argv[2] != "off"); + if (turn_on && m_lobby->m_kart_elimination.isEnabled()) { std::string msg = "Gnu Elimination mode was already enabled!"; m_lobby->sendStringToPeer(msg, context.m_peer); return; } - if (RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_NORMAL_RACE && + if (!turn_on && !m_lobby->m_kart_elimination.isEnabled()) + { + std::string msg = "Gnu Elimination mode was already off!"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (turn_on && + RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_NORMAL_RACE && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) { std::string msg = "Gnu Elimination is available only with racing modes"; m_lobby->sendStringToPeer(msg, context.m_peer); return; } - auto& argv = context.m_argv; - if (argv.size() > 1 && m_lobby->m_available_kts.first.count(argv[1]) > 0) + std::string kart; + if (!turn_on) { - m_lobby->m_kart_elimination.enable(argv[1]); - } else { - m_lobby->m_kart_elimination.enable("gnu"); + kart = "off"; + m_votables["gnu"].reset("gnu kart"); } - std::string msg = m_lobby->m_kart_elimination.getStartingMessage(); - m_lobby->sendStringToAllPeers(msg); -} // process_gnu -// ======================================================================== - -void CommandManager::process_nognu(Context& context) -{ - if (!m_lobby->m_kart_elimination.isEnabled()) + else { - std::string msg = "Gnu Elimination mode was already off!"; - m_lobby->sendStringToPeer(msg, context.m_peer); + if (context.m_peer) + { + kart = "gnu"; + if (argv.size() > 1 && m_lobby->m_available_kts.first.count(argv[1]) > 0) + { + kart = argv[1]; + } + } + else // voted + { + kart = m_votables["gnu"].getAnyBest("gnu kart"); + m_votables["gnu"].reset("gnu kart"); + } + } + if (context.m_voting) + { + if (kart != "off") + { + vote(context, "gnu", "on"); + vote(context, "gnu kart", kart); + } + else + { + vote(context, "gnu", "off"); + } return; } - - m_lobby->m_kart_elimination.disable(); - std::string msg = "Gnu Elimination is now off"; - m_lobby->sendStringToAllPeers(msg); -} // process_nognu + if (kart == "off") + { + m_lobby->m_kart_elimination.disable(); + std::string msg = "Gnu Elimination is now off"; + m_lobby->sendStringToAllPeers(msg); + } + else + { + m_lobby->m_kart_elimination.enable(kart); + std::string msg = m_lobby->m_kart_elimination.getStartingMessage(); + m_lobby->sendStringToAllPeers(msg); + } +} // process_gnu // ======================================================================== void CommandManager::process_tell(Context& context) diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 68294347f2a..d953073bf85 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef ENABLE_SQLITE3 @@ -116,6 +117,8 @@ class CommandManager std::map m_votables; + std::queue m_triggered_votables; + void initCommands(); int getCurrentScope(); @@ -145,7 +148,6 @@ class CommandManager void process_unmute(Context& context); void process_listmute(Context& context); void process_gnu(Context& context); - void process_nognu(Context& context); void process_tell(Context& context); void process_standings(Context& context); void process_teamchat(Context& context); diff --git a/src/network/protocols/command_voting.cpp b/src/network/protocols/command_voting.cpp index 28c51b7d03d..fe07b6f8bce 100644 --- a/src/network/protocols/command_voting.cpp +++ b/src/network/protocols/command_voting.cpp @@ -17,6 +17,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "network/protocols/command_voting.hpp" +#include "utils/random_generator.hpp" CommandVoting::CommandVoting(double threshold): m_threshold(threshold) { @@ -53,10 +54,15 @@ std::pair> CommandVoting::process(std::m { std::map result; int num_votes = 0; - int required_number = std::max(1, (int)ceil((double)all_users.size() * m_threshold)); + int required_number; for (const auto& p: m_votes_by_poll) { std::string category = p.first; + double category_threshold = m_threshold; + auto it = m_custom_thresholds.find(category); + if (it != m_custom_thresholds.end()) + category_threshold = it->second; + required_number = std::max(1, (int)ceil((double)all_users.size() * category_threshold)); std::map category_results; for (const std::string& user: all_users) { @@ -85,16 +91,51 @@ std::pair> CommandVoting::process(std::m for (const auto& p: result) { std::string category = p.first; - for (const auto& q: m_votes_by_poll[category]) - { - std::string vote = q.first; - for (const auto& player: q.second) - { - m_votes_by_player[player].erase(category); - } - } - m_votes_by_poll[category].clear(); + reset(category); } return make_pair(num_votes, result); } // process -// ======================================================================== \ No newline at end of file +// ======================================================================== + +std::string CommandVoting::getAnyBest(std::string category) +{ + int best = 0; + std::vector best_options; + for (auto& vote_to_set: m_votes_by_poll[category]) + { + unsigned int count = vote_to_set.second.size(); + std::string option = vote_to_set.first; + if (count > best) + { + best_options.clear(); + best_options.push_back(option); + } + else if (count == best) + { + best_options.push_back(option); + } + } + if (best_options.empty()) + return ""; // shouldn't happen mainly + RandomGenerator rg; + std::vector::iterator it = best_options.begin(); + std::advance(it, rg.get((int)best_options.size())); + return *it; +} // getAnyBest +// ======================================================================== + +void CommandVoting::reset(std::string category) +{ + for (auto& vote_to_set: m_votes_by_poll[category]) + { + std::string vote = vote_to_set.first; + auto& players = vote_to_set.second; + for (const std::string& player: players) + { + m_votes_by_player[player].erase(category); + } + } + m_votes_by_poll[category].clear(); +} // reset +// ======================================================================== + diff --git a/src/network/protocols/command_voting.hpp b/src/network/protocols/command_voting.hpp index 9eee02e9795..11bb4dbe31e 100644 --- a/src/network/protocols/command_voting.hpp +++ b/src/network/protocols/command_voting.hpp @@ -40,12 +40,19 @@ class CommandVoting private: std::map>> m_votes_by_poll; std::map> m_votes_by_player; + std::map m_custom_thresholds; public: CommandVoting(double threshold = 0.500001); + void setCustomThreshold(std::string category, double value) + { m_custom_thresholds[category] = value; } + void resetCustomThreshold(std::string category) + { m_custom_thresholds.erase(category); } bool needsCheck() { return m_need_check; } void castVote(std::string player, std::string category, std::string vote); void uncastVote(std::string player, std::string category); std::pair> process(std::multiset& all_users); + std::string getAnyBest(std::string category); + void reset(std::string category); }; #endif // COMMAND_VOTING_HPP \ No newline at end of file diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 458a2da0f13..b70c6171c36 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -5989,6 +5989,8 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, if ((m_available_difficulties.count(difficulty) == 0 || m_available_modes.count(mode) == 0)) { + // It remains just in case, but kimden thinks that + // this is already covered in command manager (?) Log::error("ServerLobby", "Mode %d and/or difficulty %d are not permitted."); std::string msg = "Mode or difficulty are not permitted on this server"; sendStringToPeer(msg, peer); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index b9e60e0504f..90e1cdac7d8 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -622,8 +622,8 @@ class ServerLobby : public LobbyProtocol void sendStringToAllPeers(std::string& s); int getPermissions(std::shared_ptr& peer) const; int getPermissions(STKPeer* peer) const; - bool hasConsentOnReplays() const { return m_consent_on_replays; } - void setConsentOnReplays(bool value) { m_consent_on_replays = value; } + bool hasConsentOnReplays() const { return m_consent_on_replays; } + void setConsentOnReplays(bool value) { m_consent_on_replays = value; } bool isSoccerGoalTarget() const; #ifdef ENABLE_SQLITE3 @@ -641,8 +641,12 @@ class ServerLobby : public LobbyProtocol void handleSwatterHit(unsigned int ownerID, unsigned int victimID, bool success, bool has_hit_kart, uint16_t ticks_active); void sendTeamMateHitMsg(std::string& s); - bool showTeamMateHits() const { return m_show_teammate_hits; } - bool useTeamMateHitMode() const { return m_teammate_hit_mode; } + bool showTeamMateHits() const { return m_show_teammate_hits; } + bool useTeamMateHitMode() const { return m_teammate_hit_mode; } + bool isDifficultyAvailable(int difficulty) const + { return m_available_difficulties.count(difficulty) > 0; } + bool isModeAvailable(int mode) const + { return m_available_modes.count(mode) > 0; } }; // class ServerLobby #endif // SERVER_LOBBY_HPP From 3d034c1d55db5e402ec8b576c4542469ca1fc40c Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 21 Oct 2021 04:19:08 +0300 Subject: [PATCH 145/830] Fix some bugs --- src/network/protocols/command_manager.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 523d9f56b57..2937abc7b3f 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -445,8 +445,8 @@ void CommandManager::process_config(Context& context) {"d3", "supertux", "super", "best"} }; std::vector> goal_aliases = { - {"gl", "goal-limit", "goal", "goals"}, - {"tl", "time-limit", "time", "minutes"} + {"tl", "time-limit", "time", "minutes"}, + {"gl", "goal-limit", "goal", "goals"} }; for (unsigned i = 1; i < argv.size(); i++) { @@ -1075,7 +1075,7 @@ void CommandManager::process_gnu(Context& context) argv[1] = "off"; } // "nognu" and "gnu off" are equivalent - bool turn_on = (argv[2] != "off"); + bool turn_on = (argv.size() < 2 || argv[1] != "off"); if (turn_on && m_lobby->m_kart_elimination.isEnabled()) { std::string msg = "Gnu Elimination mode was already enabled!"; @@ -1100,7 +1100,6 @@ void CommandManager::process_gnu(Context& context) if (!turn_on) { kart = "off"; - m_votables["gnu"].reset("gnu kart"); } else { @@ -1115,7 +1114,6 @@ void CommandManager::process_gnu(Context& context) else // voted { kart = m_votables["gnu"].getAnyBest("gnu kart"); - m_votables["gnu"].reset("gnu kart"); } } if (context.m_voting) @@ -1131,6 +1129,7 @@ void CommandManager::process_gnu(Context& context) } return; } + m_votables["gnu"].reset("gnu kart"); if (kart == "off") { m_lobby->m_kart_elimination.disable(); From 2dc65462f31b30d51c753cf64ad804af68e732cb Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 5 Nov 2021 16:50:36 +0300 Subject: [PATCH 146/830] Allow to end tournament games with non-integer number of minutes automatically, add /seconds --- src/network/game_setup.cpp | 8 +++--- src/network/game_setup.hpp | 4 ++- src/network/protocols/server_lobby.cpp | 37 +++++++++++++++++++++++++- src/network/protocols/server_lobby.hpp | 2 ++ 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/network/game_setup.cpp b/src/network/game_setup.cpp index f3a9a2019c9..6342c0d1744 100644 --- a/src/network/game_setup.cpp +++ b/src/network/game_setup.cpp @@ -47,6 +47,7 @@ GameSetup::GameSetup() m_server_name_utf8 = StringUtils::wideToUtf8 (StringUtils::xmlDecode(server_name)); m_extra_server_info = -1; + m_extra_seconds = 0.0f; m_is_grand_prix.store(false); reset(); } // GameSetup @@ -78,12 +79,12 @@ void GameSetup::loadWorld() if (isSoccerGoalTarget()) RaceManager::get()->setMaxGoal(m_laps); else - RaceManager::get()->setTimeTarget((float)m_laps * 60.0f); + RaceManager::get()->setTimeTarget((float)m_laps * 60.0f - m_extra_seconds); } else { RaceManager::get()->setHitCaptureTime(m_hit_capture_limit, - m_battle_time_limit); + m_battle_time_limit - m_extra_seconds); } RaceManager::get()->startSingleRace(m_tracks.back(), -1, false/*from_overworld*/); @@ -195,11 +196,12 @@ void GameSetup::sortPlayersForGame( } // sortPlayersForGame // ---------------------------------------------------------------------------- -void GameSetup::setRace(const PeerVote &vote) +void GameSetup::setRace(const PeerVote &vote, float extra_seconds) { m_tracks.push_back(vote.m_track_name); m_laps = vote.m_num_laps; m_reverse = vote.m_reverse; + m_extra_seconds = extra_seconds; } // setRace // ---------------------------------------------------------------------------- irr::core::stringw GameSetup::readOrLoadFromFile(std::string value) diff --git a/src/network/game_setup.hpp b/src/network/game_setup.hpp index 509527ec3f5..a539acb50d3 100644 --- a/src/network/game_setup.hpp +++ b/src/network/game_setup.hpp @@ -61,13 +61,15 @@ class GameSetup /** Utf8 server name (with xml decoded) */ std::string m_server_name_utf8; + float m_extra_seconds; + public: // ------------------------------------------------------------------------ GameSetup(); // ------------------------------------------------------------------------ ~GameSetup() {} // ------------------------------------------------------------------------ - void setRace(const PeerVote &vote); + void setRace(const PeerVote &vote, float extra_seconds = 0.0f); // ------------------------------------------------------------------------ void reset() { diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 9671f5a3877..7473d262c44 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -245,6 +245,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_consent_on_replays = false; m_fixed_lap = ServerConfig::m_fixed_lap_count; + m_extra_seconds = 0.0f; m_default_lap_multiplier = ServerConfig::m_auto_game_time_ratio; m_troll_active = ServerConfig::m_troll_active; @@ -1870,7 +1871,7 @@ void ServerLobby::asynchronousUpdate() *m_default_vote = winner_vote; m_item_seed = (uint32_t)StkTime::getTimeSinceEpoch(); ItemManager::updateRandomSeed(m_item_seed); - m_game_setup->setRace(winner_vote); + m_game_setup->setRace(winner_vote, m_extra_seconds); std::string track_name = winner_vote.m_track_name; if (ServerConfig::m_soccer_tournament) m_tournament_arenas[m_tournament_game] = track_name; @@ -7620,6 +7621,19 @@ void ServerLobby::handleServerCommand(Event* event, sendStringToPeer(msg, peer); return; } + if (argv[1] == "seconds") + { + float seconds = 0.0f; + std::string msg = "Usage: /admin seconds [how many seconds to subtract from time]"; + if (argv.size() >= 3 && StringUtils::parseString(argv[2], &seconds)) + { + m_extra_seconds = seconds; + std::string msg = StringUtils::toString(seconds) + + " second(s) will be subtracted from the time"; + } + sendStringToPeer(msg, peer); + return; + } if (argv[1] == "start") { if (argv.size() == 2 || !(argv[2] == "0" || argv[2] == "1")) @@ -7952,6 +7966,7 @@ void ServerLobby::handleServerCommand(Event* event, if (argv[0] == "game") { int old_game = m_tournament_game; + int addition = 0; if (argv.size() < 2) { ++m_tournament_game; @@ -7982,6 +7997,24 @@ void ServerLobby::handleServerCommand(Event* event, } } m_fixed_lap = length; + if (argv.size() >= 4) + { + bool ok = StringUtils::parseString(argv[3], &addition); + if (!ok || addition < 0 || addition > 59) + { + std::string msg = "Please specify a correct number. " + "Format: /game [number] [length] [0..59 additional seconds]"; + sendStringToPeer(msg, peer); + return; + } + m_extra_seconds = 0.0f; + if (addition > 0) { + ++m_fixed_lap; + m_extra_seconds = 60.0f - addition; + } + } else { + m_extra_seconds = 0.0f; + } } if (tournamentColorsSwapped(m_tournament_game) ^ tournamentColorsSwapped(old_game)) changeColors(); @@ -7990,6 +8023,8 @@ void ServerLobby::handleServerCommand(Event* event, std::string msg = StringUtils::insertValues( "Ready to start game %d for %d ", m_tournament_game, m_fixed_lap) + (tournamentGoalsLimit(m_tournament_game) ? "goals" : "minutes"); + if (!tournamentGoalsLimit(m_tournament_game) && addition > 0) + msg += " " + std::to_string(addition) + " seconds"; sendStringToAllPeers(msg); Log::info("ServerLobby", "SoccerMatchLog: Game number changed from %d to %d", old_game, m_tournament_game); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 33e8743a5c2..016d8c9a3dd 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -366,6 +366,8 @@ class ServerLobby : public LobbyProtocol int m_fixed_lap; + float m_extra_seconds; + double m_default_lap_multiplier; std::vector m_scoring_int_params; From fb929de82e8da4454f64756ef2e9d8e2b2890223 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 5 Nov 2021 18:09:42 +0300 Subject: [PATCH 147/830] Fix a typo --- src/network/protocols/server_lobby.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 7473d262c44..ac002fcc72d 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -8009,7 +8009,6 @@ void ServerLobby::handleServerCommand(Event* event, } m_extra_seconds = 0.0f; if (addition > 0) { - ++m_fixed_lap; m_extra_seconds = 60.0f - addition; } } else { @@ -8024,7 +8023,10 @@ void ServerLobby::handleServerCommand(Event* event, "Ready to start game %d for %d ", m_tournament_game, m_fixed_lap) + (tournamentGoalsLimit(m_tournament_game) ? "goals" : "minutes"); if (!tournamentGoalsLimit(m_tournament_game) && addition > 0) + { msg += " " + std::to_string(addition) + " seconds"; + ++m_fixed_lap; + } sendStringToAllPeers(msg); Log::info("ServerLobby", "SoccerMatchLog: Game number changed from %d to %d", old_game, m_tournament_game); From 4d3beaee95c74142c7724cea5566ee37046c9880 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 5 Nov 2021 18:15:22 +0300 Subject: [PATCH 148/830] Allow to select 0 minutes goals for the sake of less-than-minute games --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index ac002fcc72d..a0be051562c 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7988,7 +7988,7 @@ void ServerLobby::handleServerCommand(Event* event, if (argv.size() >= 3) { bool ok = StringUtils::parseString(argv[2], &length); - if (!ok || length <= 0) + if (!ok || length < 0) { std::string msg = "Please specify a correct number. " "Format: /game [number] [length]"; From 31ba1292ee49cd149593536d6fd13688cac0cd95 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 21 Dec 2021 02:11:20 +0300 Subject: [PATCH 149/830] Try to replace only-host-riding with max-players-in-game = 1 in terms of spectators --- src/network/protocols/server_lobby.cpp | 8 ++++---- src/network/server_config.cpp | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index c5d83112e61..c66b591276e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2902,7 +2902,7 @@ void ServerLobby::startSelection(const Event *event) bool can_race = canRace(peer); if (!can_race) { - if (ServerConfig::m_soccer_tournament || ServerConfig::m_only_host_riding) + if (ServerConfig::m_soccer_tournament/* || ServerConfig::m_only_host_riding*/) peer->setAlwaysSpectate(ASM_COMMAND); } if (!can_race && !peer->alwaysSpectate()) @@ -6657,7 +6657,7 @@ void ServerLobby::handleServerCommand(Event* event, } else if (argv[0] == "spectate") { - if (ServerConfig::m_soccer_tournament || ServerConfig::m_only_host_riding) + if (ServerConfig::m_soccer_tournament /*|| ServerConfig::m_only_host_riding*/) { std::string msg = "All spectators already have auto spectate ability"; sendStringToPeer(msg, peer); @@ -8809,8 +8809,8 @@ bool ServerLobby::canRace(STKPeer* peer) const if (ServerConfig::m_soccer_tournament) return m_tournament_red_players.count(username) > 0 || m_tournament_blue_players.count(username) > 0; - else if (ServerConfig::m_only_host_riding) - return peer == m_server_owner.lock().get(); + // else if (ServerConfig::m_only_host_riding) + // return peer == m_server_owner.lock().get(); else if (!m_tracks_queue.empty()) return peer->getClientAssets().second.count(m_tracks_queue.front()); else diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 0c92a6d73d4..bd52015cc5b 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -370,6 +370,10 @@ void loadServerLobbyFromConfig() #endif } + if (m_only_host_riding) { + m_max_players_in_game = 1; + } + if (m_soccer_tournament) { m_server_mode = 6; m_server_difficulty = 3; From 6fe2ba9a397e2196739490eb78def38d798a0b70 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 21 Dec 2021 03:07:33 +0300 Subject: [PATCH 150/830] Try to fix maps missing due to spectators who lack slots --- src/network/protocols/server_lobby.cpp | 44 ++++++++++++-------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index c66b591276e..0b628e8f0a0 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2890,6 +2890,24 @@ void ServerLobby::startSelection(const Event *event) } } + unsigned max_player = 0; + STKHost::get()->updatePlayers(&max_player); + + // Set late coming player to spectate if too many players + auto spectators_by_limit = getSpectatorsByLimit(); + if (spectators_by_limit.size() == peers.size()) + { + Log::error("ServerLobby", "Too many players and cannot set " + "spectate for late coming players!"); + return; + } + for (auto &peer : spectators_by_limit) + { + peer->setAlwaysSpectate(ASM_FULL); + peer->setWaitingForGame(true); + always_spectate_peers.insert(peer.get()); + } + // Remove karts / tracks from server that are not supported on all clients std::set karts_erase, tracks_erase; auto peers = STKHost::get()->getPeers(); @@ -2900,13 +2918,10 @@ void ServerLobby::startSelection(const Event *event) if (!peer->isValidated() || peer->isWaitingForGame()) continue; bool can_race = canRace(peer); - if (!can_race) + if (!can_race && !peer->alwaysSpectate()) { if (ServerConfig::m_soccer_tournament/* || ServerConfig::m_only_host_riding*/) peer->setAlwaysSpectate(ASM_COMMAND); - } - if (!can_race && !peer->alwaysSpectate()) - { peer->setWaitingForGame(true); m_peers_ready.erase(peer); need_to_update = true; @@ -2922,7 +2937,7 @@ void ServerLobby::startSelection(const Event *event) if (!peer->isAIPeer()) has_peer_plays_game = true; } - m_default_always_spectate_peers = always_spectate_peers; + // m_default_always_spectate_peers = always_spectate_peers; // kimden thinks if someone wants to race he should disable spectating // // Disable always spectate peers if no players join the game @@ -2947,24 +2962,6 @@ void ServerLobby::startSelection(const Event *event) peer->setWaitingForGame(true); } - unsigned max_player = 0; - STKHost::get()->updatePlayers(&max_player); - - // Set late coming player to spectate if too many players - auto spectators_by_limit = getSpectatorsByLimit(); - if (spectators_by_limit.size() == peers.size()) - { - Log::error("ServerLobby", "Too many players and cannot set " - "spectate for late coming players!"); - return; - } - for(auto &peer : spectators_by_limit) - { - peer->setAlwaysSpectate(ASM_FULL); - peer->setWaitingForGame(true); - always_spectate_peers.insert(peer.get()); - } - for (const std::string& kart_erase : karts_erase) { m_available_kts.first.erase(kart_erase); @@ -6461,7 +6458,6 @@ std::set> ServerLobby::getSpectatorsByLimit() std::set> spectators_by_limit; auto peers = STKHost::get()->getPeers(); - std::set> always_spectate_peers; unsigned player_limit = ServerConfig::m_max_players_in_game; // only 10 players allowed for FFA and 14 for CTF and soccer From f40fb028a7af19591df0dfadd66425b7f055b56d Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 21 Dec 2021 03:09:27 +0300 Subject: [PATCH 151/830] Fix CE --- src/network/protocols/server_lobby.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 0b628e8f0a0..62fdd492399 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2892,6 +2892,8 @@ void ServerLobby::startSelection(const Event *event) unsigned max_player = 0; STKHost::get()->updatePlayers(&max_player); + auto peers = STKHost::get()->getPeers(); + std::set always_spectate_peers; // Set late coming player to spectate if too many players auto spectators_by_limit = getSpectatorsByLimit(); @@ -2910,8 +2912,6 @@ void ServerLobby::startSelection(const Event *event) // Remove karts / tracks from server that are not supported on all clients std::set karts_erase, tracks_erase; - auto peers = STKHost::get()->getPeers(); - std::set always_spectate_peers; bool has_peer_plays_game = false; for (auto peer : peers) { From f800fb4bf804323459486480e9e03c8a529b5cd1 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 21 Dec 2021 03:22:28 +0300 Subject: [PATCH 152/830] Set canRace to out-of-slots players to false --- src/network/protocols/server_lobby.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 62fdd492399..d11d3c8619f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -8805,6 +8805,8 @@ bool ServerLobby::canRace(STKPeer* peer) const if (ServerConfig::m_soccer_tournament) return m_tournament_red_players.count(username) > 0 || m_tournament_blue_players.count(username) > 0; + else if (spectators_by_limit.find(peer) != spectators_by_limit.end()) + return false; // else if (ServerConfig::m_only_host_riding) // return peer == m_server_owner.lock().get(); else if (!m_tracks_queue.empty()) From cccac2f2cffb6938063cdecc0f17828880cd27f2 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 21 Dec 2021 03:33:41 +0300 Subject: [PATCH 153/830] Make spectators_by_limit stored in memory instead of being calculated all the time, fix CE --- src/network/protocols/server_lobby.cpp | 23 +++++++++++++---------- src/network/protocols/server_lobby.hpp | 4 +++- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index d11d3c8619f..9b6d03ed88e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2148,7 +2148,7 @@ void ServerLobby::liveJoinRequest(Event* event) peer->clearAvailableKartIDs(); if (!spectator) { - auto spectators_by_limit = getSpectatorsByLimit(); + auto& spectators_by_limit = getSpectatorsByLimit(); setPlayerKarts(data, peer); std::vector used_id; @@ -2896,7 +2896,7 @@ void ServerLobby::startSelection(const Event *event) std::set always_spectate_peers; // Set late coming player to spectate if too many players - auto spectators_by_limit = getSpectatorsByLimit(); + auto& spectators_by_limit = getSpectatorsByLimit(); if (spectators_by_limit.size() == peers.size()) { Log::error("ServerLobby", "Too many players and cannot set " @@ -4770,7 +4770,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) all_profiles_size--; } - auto spectators_by_limit = getSpectatorsByLimit(); + auto& spectators_by_limit = getSpectatorsByLimit(true); // N - 1 AI auto ai_instance = m_ai_peer.lock(); @@ -6453,9 +6453,12 @@ void ServerLobby::clientSelectingAssetsWantsToBackLobby(Event* event) } // clientSelectingAssetsWantsToBackLobby //----------------------------------------------------------------------------- -std::set> ServerLobby::getSpectatorsByLimit() +std::set>& ServerLobby::getSpectatorsByLimit(bool update) { - std::set> spectators_by_limit; + if (!update) + return m_spectators_by_limit; + + m_spectators_by_limit.clear(); auto peers = STKHost::get()->getPeers(); @@ -6476,7 +6479,7 @@ std::set> ServerLobby::getSpectatorsByLimit() unsigned ingame_players = 0, waiting_players = 0, total_players = 0; STKHost::get()->updatePlayers(&ingame_players, &waiting_players, &total_players); if (total_players <= player_limit) - return spectators_by_limit; + return m_spectators_by_limit; std::sort(peers.begin(), peers.end(), [](const std::shared_ptr& a, @@ -6502,7 +6505,7 @@ std::set> ServerLobby::getSpectatorsByLimit() continue; player_count += (unsigned)peer->getPlayerProfiles().size(); if (player_count > player_limit) - spectators_by_limit.insert(peer); + m_spectators_by_limit.insert(peer); } else { @@ -6510,10 +6513,10 @@ std::set> ServerLobby::getSpectatorsByLimit() continue; player_count += (unsigned)peer->getPlayerProfiles().size(); if (peer->isWaitingForGame() && (player_count > player_limit || ingame_players >= player_limit)) - spectators_by_limit.insert(peer); + m_spectators_by_limit.insert(peer); } } - return spectators_by_limit; + return m_spectators_by_limit; } // getSpectatorsByLimit //----------------------------------------------------------------------------- @@ -8805,7 +8808,7 @@ bool ServerLobby::canRace(STKPeer* peer) const if (ServerConfig::m_soccer_tournament) return m_tournament_red_players.count(username) > 0 || m_tournament_blue_players.count(username) > 0; - else if (spectators_by_limit.find(peer) != spectators_by_limit.end()) + else if (m_spectators_by_limit.find(peer) != m_spectators_by_limit.end()) return false; // else if (ServerConfig::m_only_host_riding) // return peer == m_server_owner.lock().get(); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 1d8fa80c791..5da7dcc094d 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -286,6 +286,8 @@ class ServerLobby : public LobbyProtocol // Calculated before each game started unsigned m_ai_count; + std::set> m_spectators_by_limit; + std::vector m_must_have_tracks; std::vector m_tournament_must_have_tracks; @@ -535,7 +537,7 @@ class ServerLobby : public LobbyProtocol void handleKartInfo(Event* event); void clientInGameWantsToBackLobby(Event* event); void clientSelectingAssetsWantsToBackLobby(Event* event); - std::set> getSpectatorsByLimit(); + std::set>& getSpectatorsByLimit(bool update = false); void kickPlayerWithReason(STKPeer* peer, const char* reason) const; void testBannedForIP(STKPeer* peer) const; void testBannedForIPv6(STKPeer* peer) const; From 5f0a4e3004d110e7324620e38d786e2728033196 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 21 Dec 2021 04:10:48 +0300 Subject: [PATCH 154/830] Make spectators_by_limit a set of raw pointers temporarily as there is no easy way to rewrite all functions to shared_ptr - main stk also uses raw pointers --- src/network/protocols/server_lobby.cpp | 12 ++++++------ src/network/protocols/server_lobby.hpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 9b6d03ed88e..a1620f278ee 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2160,7 +2160,7 @@ void ServerLobby::liveJoinRequest(Event* event) used_id.push_back(id); } if ((used_id.size() != peer->getPlayerProfiles().size()) || - (spectators_by_limit.find(event->getPeerSP()) != spectators_by_limit.end())) + (spectators_by_limit.find(event->getPeerSP().get()) != spectators_by_limit.end())) { for (unsigned i = 0; i < peer->getPlayerProfiles().size(); i++) peer->getPlayerProfiles()[i]->setKartName(""); @@ -2907,7 +2907,7 @@ void ServerLobby::startSelection(const Event *event) { peer->setAlwaysSpectate(ASM_FULL); peer->setWaitingForGame(true); - always_spectate_peers.insert(peer.get()); + always_spectate_peers.insert(peer); } // Remove karts / tracks from server that are not supported on all clients @@ -4831,7 +4831,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) profile_name = StringUtils::utf32ToWide({0x1F4F1}) + profile_name; // Add an hourglass emoji for players waiting because of the player limit - if (spectators_by_limit.find(profile->getPeer()) != spectators_by_limit.end()) + if (spectators_by_limit.find(profile->getPeer().get()) != spectators_by_limit.end()) profile_name = StringUtils::utf32ToWide({ 0x231B }) + profile_name; // Add a hammer emoji for angry host @@ -6453,7 +6453,7 @@ void ServerLobby::clientSelectingAssetsWantsToBackLobby(Event* event) } // clientSelectingAssetsWantsToBackLobby //----------------------------------------------------------------------------- -std::set>& ServerLobby::getSpectatorsByLimit(bool update) +std::set& ServerLobby::getSpectatorsByLimit(bool update) { if (!update) return m_spectators_by_limit; @@ -6505,7 +6505,7 @@ std::set>& ServerLobby::getSpectatorsByLimit(bool updat continue; player_count += (unsigned)peer->getPlayerProfiles().size(); if (player_count > player_limit) - m_spectators_by_limit.insert(peer); + m_spectators_by_limit.insert(peer.get()); } else { @@ -6513,7 +6513,7 @@ std::set>& ServerLobby::getSpectatorsByLimit(bool updat continue; player_count += (unsigned)peer->getPlayerProfiles().size(); if (peer->isWaitingForGame() && (player_count > player_limit || ingame_players >= player_limit)) - m_spectators_by_limit.insert(peer); + m_spectators_by_limit.insert(peer.get()); } } return m_spectators_by_limit; diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 5da7dcc094d..51b8c83b724 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -286,7 +286,7 @@ class ServerLobby : public LobbyProtocol // Calculated before each game started unsigned m_ai_count; - std::set> m_spectators_by_limit; + std::set m_spectators_by_limit; std::vector m_must_have_tracks; From d444c90620d053c3503a7639d7e15b099eb7cdf8 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 21 Dec 2021 04:14:08 +0300 Subject: [PATCH 155/830] Fix wrong prototype --- src/network/protocols/server_lobby.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 51b8c83b724..d744e971fec 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -537,7 +537,7 @@ class ServerLobby : public LobbyProtocol void handleKartInfo(Event* event); void clientInGameWantsToBackLobby(Event* event); void clientSelectingAssetsWantsToBackLobby(Event* event); - std::set>& getSpectatorsByLimit(bool update = false); + std::set& getSpectatorsByLimit(bool update = false); void kickPlayerWithReason(STKPeer* peer, const char* reason) const; void testBannedForIP(STKPeer* peer) const; void testBannedForIPv6(STKPeer* peer) const; From 98c9e963a10975da2be8c8b560e66c659888c7d1 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 23 Dec 2021 03:44:29 +0300 Subject: [PATCH 156/830] Fix splitQuoted, add fixing typos in command names --- src/network/protocols/command_manager.cpp | 184 +++++++++++++++------- src/network/protocols/command_manager.hpp | 14 +- src/utils/set_typo_fixer.cpp | 65 ++++++++ src/utils/set_typo_fixer.hpp | 44 ++++++ src/utils/string_utils.cpp | 88 ++++++++--- src/utils/string_utils.hpp | 7 +- 6 files changed, 322 insertions(+), 80 deletions(-) create mode 100644 src/utils/set_typo_fixer.cpp create mode 100644 src/utils/set_typo_fixer.hpp diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 2937abc7b3f..331e7bda581 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -138,6 +138,11 @@ void CommandManager::initCommands() m_commands.emplace_back("mimiz", &CommandManager::process_mimiz, UP_EVERYONE, CS_ALWAYS, "/mimiz [text]", "everyone", "A joke command."); m_commands.emplace_back("test", &CommandManager::process_test, UP_EVERYONE | PE_VOTED, CS_ALWAYS, "/test [poll name] [option name]", "everyone; votable", "A test command."); m_commands.emplace_back("help", &CommandManager::process_help, UP_EVERYONE, CS_ALWAYS, "/help (command name)", "everyone", "Gives description of a given command."); + m_commands.emplace_back("1", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/1", "everyone", "This command allows to choose 1st of suggested options when a typo is made"); + m_commands.emplace_back("2", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/2", "everyone", "This command allows to choose 2nd of suggested options when a typo is made"); + m_commands.emplace_back("3", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/3", "everyone", "This command allows to choose 3rd of suggested options when a typo is made"); + m_commands.emplace_back("4", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/4", "everyone", "This command allows to choose 4th of suggested options when a typo is made"); + m_commands.emplace_back("5", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/5", "everyone", "This command allows to choose 5th of suggested options when a typo is made"); addTextResponse("moreinfo", StringUtils::wideToUtf8(m_lobby->m_help_message)); addTextResponse("version", "1.3-rc1 k 210fff beta"); @@ -157,6 +162,9 @@ void CommandManager::initCommands() m_votables.emplace("gnu", 0.81); m_votables["gnu"].setCustomThreshold("gnu kart", 1.1); + for (const Command& command: m_commands) { + m_stf_command_names.add(command.m_name); + } } // initCommands // ======================================================================== @@ -176,14 +184,18 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) data.decodeString(&language); std::string cmd; data.decodeString(&cmd); - auto argv = StringUtils::splitQuoted(cmd, ' ', '"', '\\'); + auto argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); if (argv.size() == 0) return; + CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); int permissions = m_lobby->getPermissions(peer); bool found_command = false; bool voting = false; std::string action = "invoke"; + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (argv[0] == "vote") { if (argv.size() == 1 || argv[1] == "vote") @@ -192,81 +204,111 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) m_lobby->sendStringToPeer(msg, peer); return; } - std::reverse(cmd.begin(), cmd.end()); - cmd.resize((int)cmd.size() - 4); - while (!cmd.empty() && cmd.back() == ' ') - cmd.pop_back(); - std::reverse(cmd.begin(), cmd.end()); std::reverse(argv.begin(), argv.end()); argv.pop_back(); std::reverse(argv.begin(), argv.end()); + CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); voting = true; action = "vote for"; } + for (int i = 1; i <= 5; ++i) { + if (argv[0] == std::to_string(i)) { + if (i - 1 < m_user_command_replacements[username].size()) { + cmd = m_user_command_replacements[username][i - 1]; + argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); + if (argv.size() == 0) + return; + CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + break; + } else { + std::string msg = "Pick one of " + + std::to_string(m_user_command_replacements[username].size()) + + " options using /1, etc., or type a different command"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + } + } + m_user_command_replacements.erase(username); + + auto closest_commands = m_stf_command_names.getClosest(argv[0], 3, false); + if (closest_commands.empty()) + { + std::string msg = "Command " + argv[0] + " not found"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + if (closest_commands[0].second != 0) + { + m_user_command_replacements[username].clear(); + std::string initial_command = argv[0]; + std::string response = "You invoked \"" + cmd + "\", but there is " + "no command \"" + initial_command + "\". Choose a fix or ignore:"; + + for (int i = 0; i < closest_commands.size(); ++i) { + argv[0] = closest_commands[i].first; + CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + m_user_command_replacements[username].push_back(cmd); + response += "\ntype /" + std::to_string(i + 1) + " to choose /" + argv[0]; + } + argv[0] = initial_command; + CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + m_lobby->sendStringToPeer(response, peer); + return; + } auto command_iterator = m_name_to_command.find(argv[0]); - found_command = (command_iterator != m_name_to_command.end()); - if (found_command) + const auto& command = command_iterator->second; + + if (!isAvailable(command)) { - const auto& command = command_iterator->second; - if (!isAvailable(command)) - { - std::string msg = "You don't have permissions to " + action + " this command"; - m_lobby->sendStringToPeer(msg, peer); - return; - } - int mask = (permissions & command.m_permissions); - if (mask == 0) - { - std::string msg = "You don't have permissions to " + action + " this command"; - m_lobby->sendStringToPeer(msg, peer); - return; - } - int mask_without_voting = (mask & ~PE_VOTED); - if (mask != PE_NONE && mask_without_voting == PE_NONE) - voting = true; + std::string msg = "You don't have permissions to " + action + " this command"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + int mask = (permissions & command.m_permissions); + if (mask == 0) + { + std::string msg = "You don't have permissions to " + action + " this command"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + int mask_without_voting = (mask & ~PE_VOTED); + if (mask != PE_NONE && mask_without_voting == PE_NONE) + voting = true; - Context context(event, peer, argv, cmd, permissions, voting); - (this->*command.m_action)(context); + Context context(event, peer, argv, cmd, permissions, voting); + (this->*command.m_action)(context); - while (!m_triggered_votables.empty()) + while (!m_triggered_votables.empty()) + { + std::string votable_name = m_triggered_votables.front(); + m_triggered_votables.pop(); + auto it = m_votables.find(argv[0]); + if (it != m_votables.end() && it->second.needsCheck()) { - std::string votable_name = m_triggered_votables.front(); - m_triggered_votables.pop(); - auto it = m_votables.find(argv[0]); - if (it != m_votables.end() && it->second.needsCheck()) + auto response = it->second.process(m_users); + int count = response.first; + std::string msg = username + " voted \"" + cmd + "\", there are " + std::to_string(count) + " such votes"; + m_lobby->sendStringToAllPeers(msg); + auto res = response.second; + if (!res.empty()) { - auto response = it->second.process(m_users); - int count = response.first; - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - std::string msg = username + " voted \"" + cmd + "\", there are " + std::to_string(count) + " such votes"; - m_lobby->sendStringToAllPeers(msg); - auto res = response.second; - if (!res.empty()) + for (auto& p: res) { - for (auto& p: res) - { - std::string new_cmd = p.first + " " + p.second; - std::string msg = "Command \"" + new_cmd + "\" has been successfully voted"; - m_lobby->sendStringToAllPeers(msg); - auto new_argv = StringUtils::splitQuoted(cmd, ' ', '"', '\\'); - Context new_context(event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); - (this->*command.m_action)(new_context); - } + std::string new_cmd = p.first + " " + p.second; + auto new_argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); + CommandManager::restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); + std::string msg = "Command \"" + new_cmd + "\" has been successfully voted"; + m_lobby->sendStringToAllPeers(msg); + Context new_context(event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); + (this->*command.m_action)(new_context); } } } - return; } - // TODO: process commands with typos - std::string msg = "Command " + argv[0] + " not found"; - m_lobby->sendStringToPeer(msg, peer); - - // TODO: add votedness - } // handleCommand // ======================================================================== @@ -311,9 +353,10 @@ void CommandManager::update() for (auto& p: res) { std::string new_cmd = p.first + " " + p.second; + auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '"', '\\'); + CommandManager::restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); std::string msg = "Command \"" + new_cmd + "\" has been successfully voted"; m_lobby->sendStringToAllPeers(msg); - auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '\\'); auto& command = m_name_to_command[new_argv[0]]; // We don't know the event though it is only needed in // ServerLobby::startSelection where it is nullptr when they vote @@ -2127,4 +2170,31 @@ void CommandManager::deleteUser(std::string& s) m_users.erase(it); update(); } // deleteUser +// ======================================================================== + +void CommandManager::restoreCmdByArgv(std::string& cmd, std::vector& argv, char c, char d, char e, char f) +{ + cmd.clear(); + for (int i = 0; i < argv.size(); ++i) { + bool quoted = false; + if (argv[i].find(c) != std::string::npos || argv[i].empty()) { + quoted = true; + } + if (i > 0) { + cmd.push_back(c); + } + if (quoted) { + cmd.push_back(d); + } + for (int j = 0; j < argv[i].size(); ++j) { + if (argv[i][j] == d || argv[i][j] == e || argv[i][j] == f) { + cmd.push_back(f); + } + cmd.push_back(argv[i][j]); + } + if (quoted) { + cmd.push_back(e); + } + } +} // restoreCmdByArgv // ======================================================================== \ No newline at end of file diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index d953073bf85..df5161aebe6 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -39,6 +39,7 @@ #endif #include "network/protocols/command_voting.hpp" +#include "utils/set_typo_fixer.hpp" class ServerLobby; class Event; @@ -100,7 +101,7 @@ class CommandManager std::string getUsage() { return "Usage: " + m_usage; } - std::string getHelp() { return "Usage: " + m_usage + "\nAvailable to: " + m_verbose_permissions + "\n" + m_description + "\n"; } + std::string getHelp() { return "Usage: " + m_usage + "\nAvailable to: " + m_verbose_permissions + "\n" + m_description; } }; private: @@ -119,6 +120,14 @@ class CommandManager std::queue m_triggered_votables; + std::map> m_user_command_replacements; + + SetTypoFixer m_stf_command_names; + + SetTypoFixer m_stf_present_users; + + SetTypoFixer m_stf_maps; + void initCommands(); int getCurrentScope(); @@ -194,7 +203,10 @@ class CommandManager { m_text_response[key] = value; } void addUser(std::string& s); + void deleteUser(std::string& s); + + static void restoreCmdByArgv(std::string& cmd, std::vector& argv, char c, char d, char e, char f); }; #endif // COMMAND_MANAGER_HPP \ No newline at end of file diff --git a/src/utils/set_typo_fixer.cpp b/src/utils/set_typo_fixer.cpp new file mode 100644 index 00000000000..07e3ad28dda --- /dev/null +++ b/src/utils/set_typo_fixer.cpp @@ -0,0 +1,65 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2021 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/set_typo_fixer.hpp" +#include "utils/string_utils.hpp" + +void SetTypoFixer::add(const std::string& value) +{ + m_set.insert(value); +} // add +// ======================================================================== + +void SetTypoFixer::remove(const std::string& value) +{ + m_set.erase(m_set.find(value)); +} // remove +// ======================================================================== + +std::vector> SetTypoFixer::getClosest( + const std::string& query, int count, bool case_sensitive) const +{ + std::vector> ans; + if (m_set.empty()) + return ans; + auto it = m_set.find(query); + if (it != m_set.end()) + { + ans.emplace_back(query, 0); + return ans; + } + const std::string& query_ref = query; + for (const std::string& s: m_set) + { + int distance = StringUtils::getEditDistance(s, + query_ref, case_sensitive); + + ans.emplace_back(s, distance); + } + std::sort(ans.begin(), ans.end(), + [](const std::pair& a, const std::pair& b) -> bool + { + if (a.second != b.second) + return a.second < b.second; + return a.first < b.first; + }); + if (ans.size() > count) + ans.resize(count); + return ans; +} // getClosest +// ======================================================================== diff --git a/src/utils/set_typo_fixer.hpp b/src/utils/set_typo_fixer.hpp new file mode 100644 index 00000000000..3a969a69ff0 --- /dev/null +++ b/src/utils/set_typo_fixer.hpp @@ -0,0 +1,44 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2021 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef SET_TYPO_FIXER_HPP +#define SET_TYPO_FIXER_HPP + +#include "irrString.h" + +#include +#include +#include +#include + +// A lazy class that stores a set of strings. +// For a query string, it finds exactly the same string in the set +// if it exists, otherwise iterates over the set and suggests to you +// the closest string according to edit distance. + +class SetTypoFixer +{ +private: + std::multiset m_set; +public: + void add(const std::string& value); + void remove(const std::string& value); + std::vector> getClosest( + const std::string& query, int count = 3, bool case_sensitive = true) const; +}; +#endif // SET_TYPO_FIXER_HPP \ No newline at end of file diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index b6918472010..ae82bfcfc35 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -146,16 +146,21 @@ namespace StringUtils //------------------------------------------------------------------------- /** Splits a string into substrings separated by a certain character `c`, * and returns a std::vector of all those substrings. The only exception - * from that is when a substring is enclosed into `d` chars, `c` chars - * inside do not split the substring. `d` chars are escaped with `e`, just - * as `e` chars. E.g.: - * splitQuoted("a b=c |multi word phrase| /|o //", ' ', '|', '/') --> - * ["a", "b=c", "multi word phrase", "|o", "/"] + * from that is when a substring is enclosed into `d` and `e` chars, + * `c` chars inside do not split the substring. `d` and `e` chars are + * escaped with `f`, just as `f` chars. E.g.: + * splitQuoted("a b=c /', '/') --> + * ["a", "b=c", "multi word phrase", " splitQuoted(const std::string& s, char c, - char d, char e) + char d, char e, char f) { std::vector result; @@ -164,35 +169,40 @@ namespace StringUtils result.emplace_back(); bool quoted = false; bool escaped = false; + bool previous_space = true; for (unsigned i = 0; i < s.length(); ++i) { - if (s[i] == e) + if (s[i] == f) { - if (escaped) - result.back().push_back(e); + if (escaped) { + result.back().push_back(f); + escaped = false; + } else escaped = true; } - else if (s[i] == d && !escaped) + else if (s[i] == d && quoted == 0 && !escaped) { - quoted ^= 1; + quoted = 1; } - else if (s[i] == c && !quoted) + else if (s[i] == e && quoted == 1 && !escaped) { - result.emplace_back(); + quoted = 0; + } + else if (s[i] == c && !quoted && !escaped) + { + if (!result.back().empty() || !previous_space) { + result.emplace_back(); + } } else { result.back().push_back(s[i]); + escaped = false; } + previous_space = (s[i] == c); } - std::vector cleared_result; - for (const std::string& s: result) - { - if (!s.empty()) - cleared_result.push_back(s); - } - return cleared_result; + return result; } catch (std::exception& e) { @@ -1494,6 +1504,42 @@ namespace StringUtils unit = _("%s KB", 1); return unit; } // getReadableFileSize + // ------------------------------------------------------------------------ + bool isEqual(char a, char b, bool case_sensitive) + { + if (a == b) + return true; + return case_sensitive && toupper(a) == toupper(b); + } // isEqual + // ------------------------------------------------------------------------ + int getEditDistance(const std::string& a, const std::string& b, + bool case_sensitive) + { + int n = a.length(); + int m = b.length(); + std::vector> distance(n + 1, + std::vector(m + 1, n + m)); + distance[0][0] = 0; + for (int i = 0; i <= n; ++i) { + for (int j = 0; j <= m; ++j) { + if (i < n) { + distance[i + 1][j] = std::min(distance[i + 1][j], + distance[i][j] + 1); + } + if (j < m) { + distance[i][j + 1] = std::min(distance[i][j + 1], + distance[i][j] + 1); + } + if (i < n && j < m) { + int value = distance[i][j] + (isEqual(a[i], b[j], + case_sensitive) ? 0 : 1); + distance[i + 1][j + 1] = std::min( + distance[i + 1][j + 1], value); + } + } + } + return distance[n][m]; + } // getEditDistance } // namespace StringUtils /* EOF */ diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index de6fdd117b6..a5863fdeafa 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -54,7 +54,8 @@ namespace StringUtils irr::core::stringw loadingDots(const irr::core::stringw& s); std::string toUpperCase(const std::string&); std::string toLowerCase(const std::string&); - std::vector splitQuoted(const std::string& s, char c, char d, char e); + std::vector splitQuoted(const std::string& s, char c, + char d, char e, char f); std::vector split(const std::string& s, char c, bool keepSplitChar=false); std::vector split(const std::u32string& s, char32_t c, @@ -339,6 +340,10 @@ namespace StringUtils } } } + // ------------------------------------------------------------------------ + bool isEqual(char a, char b, bool case_sensitive = true); + int getEditDistance(const std::string& a, const std::string& b, + bool case_sensitive = true); } // namespace StringUtils From aa3cd9cb6a96d42d1b27b97a35dec796a5abeff5 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 23 Dec 2021 05:11:16 +0300 Subject: [PATCH 157/830] Add #include --- src/utils/set_typo_fixer.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/set_typo_fixer.hpp b/src/utils/set_typo_fixer.hpp index 3a969a69ff0..5e27264bb5f 100644 --- a/src/utils/set_typo_fixer.hpp +++ b/src/utils/set_typo_fixer.hpp @@ -25,6 +25,7 @@ #include #include #include +#include // A lazy class that stores a set of strings. // For a query string, it finds exactly the same string in the set @@ -41,4 +42,4 @@ class SetTypoFixer std::vector> getClosest( const std::string& query, int count = 3, bool case_sensitive = true) const; }; -#endif // SET_TYPO_FIXER_HPP \ No newline at end of file +#endif // SET_TYPO_FIXER_HPP From 26ec732aa347c673a6f31c9fa4888787cf7a9d14 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 23 Dec 2021 15:39:35 +0300 Subject: [PATCH 158/830] Fix failing /nognu and similar --- src/network/protocols/command_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 331e7bda581..b8eebd6964b 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -285,7 +285,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) { std::string votable_name = m_triggered_votables.front(); m_triggered_votables.pop(); - auto it = m_votables.find(argv[0]); + auto it = m_votables.find(votable_name); if (it != m_votables.end() && it->second.needsCheck()) { auto response = it->second.process(m_users); From de678b238d283ff41958115d25ea1d970d6c8811 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 24 Dec 2021 02:05:24 +0300 Subject: [PATCH 159/830] Allow to change the number of playable slots, without really fixing permissions for now though --- src/network/protocols/command_manager.cpp | 28 +++++++++++++++++++++++ src/network/protocols/command_manager.hpp | 1 + src/network/protocols/server_lobby.cpp | 4 +++- src/network/protocols/server_lobby.hpp | 2 ++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index b8eebd6964b..4e625de9417 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -143,6 +143,7 @@ void CommandManager::initCommands() m_commands.emplace_back("3", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/3", "everyone", "This command allows to choose 3rd of suggested options when a typo is made"); m_commands.emplace_back("4", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/4", "everyone", "This command allows to choose 4th of suggested options when a typo is made"); m_commands.emplace_back("5", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/5", "everyone", "This command allows to choose 5th of suggested options when a typo is made"); + m_commands.emplace_back("slots", &CommandManager::process_slots, UP_HAMMER | PE_VOTED, CS_ALWAYS, "/slots (number of slots)", "hammers; voted", "Sets the number of playable slots to a certain value"); addTextResponse("moreinfo", StringUtils::wideToUtf8(m_lobby->m_help_message)); addTextResponse("version", "1.3-rc1 k 210fff beta"); @@ -2143,6 +2144,33 @@ void CommandManager::process_test(Context& context) } // process_test // ======================================================================== +void CommandManager::process_slots(Context& context) +{ + auto& argv = context.m_argv; + auto& peer = context.m_peer; + bool fail = false; + unsigned number = 0; + if (argv.size() < 2 || !StringUtils::parseString(argv[1], &number)) + fail = true; + else if (number <= 0 || number > ServerConfig::m_server_max_players) + fail = true; + if (fail) + { + error(context); + return; + } + if (context.m_voting) + { + vote(context, "slots", argv[1]); + return; + } + m_lobby->m_current_max_players_in_game.store(number); + m_lobby->updatePlayerList(); + std::string msg = "Number of playable slots is now " + argv[1]; + m_lobby->sendStringToAllPeers(msg); +} // process_slots +// ======================================================================== + void CommandManager::special(Context& context) { // This function is used as a function for /vote and possibly several diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index df5161aebe6..b199f96222e 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -188,6 +188,7 @@ class CommandManager void process_init(Context& context); void process_mimiz(Context& context); void process_test(Context& context); + void process_slots(Context& context); void special(Context& context); public: diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 0f77e79ab0f..88aa54c0e1d 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -245,6 +245,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_shuffle_gp = ServerConfig::m_shuffle_gp; + m_current_max_players_in_game.store(ServerConfig::m_max_players_in_game); + m_consent_on_replays = false; m_fixed_lap = ServerConfig::m_fixed_lap_count; @@ -6472,7 +6474,7 @@ std::set& ServerLobby::getSpectatorsByLimit(bool update) auto peers = STKHost::get()->getPeers(); - unsigned player_limit = ServerConfig::m_max_players_in_game; + unsigned player_limit = m_current_max_players_in_game.load(); // only 10 players allowed for FFA and 14 for CTF and soccer if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 9963ae6187b..719498fbdde 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -389,6 +389,8 @@ class ServerLobby : public LobbyProtocol bool m_shuffle_gp; + std::atomic m_current_max_players_in_game; + #ifdef ENABLE_WEB_SUPPORT std::set m_web_tokens; From 30b4a4f51da28cf885b98c502f497308b1a95c9d Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 27 Dec 2021 16:04:03 +0300 Subject: [PATCH 160/830] Add another permission level for network console --- src/network/protocols/command_permissions.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/command_permissions.hpp b/src/network/protocols/command_permissions.hpp index 545fbc86250..c19e71e753d 100644 --- a/src/network/protocols/command_permissions.hpp +++ b/src/network/protocols/command_permissions.hpp @@ -27,7 +27,9 @@ enum CommandPermissions : unsigned int PE_CROWNED = 4, PE_SINGLE = 8, PE_HAMMER = 16, - UP_HAMMER = PE_HAMMER, + PE_CONSOLE = 32, + UP_CONSOLE = PE_CONSOLE, + UP_HAMMER = UP_CONSOLE | PE_HAMMER, UP_SINGLE = UP_HAMMER | PE_SINGLE, UP_CROWNED = UP_SINGLE | PE_CROWNED, UP_EVERYONE = UP_CROWNED | PE_USUAL From a3bd6b86cfbb1e85bf4694d122150198337da530 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 27 Dec 2021 16:35:28 +0300 Subject: [PATCH 161/830] Try to fix /start failing for non-crowned players --- src/network/protocols/command_manager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 4e625de9417..20533952ee6 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -455,6 +455,10 @@ void CommandManager::process_replay(Context& context) void CommandManager::process_start(Context& context) { + if (!ServerConfig::m_owner_less && (m_user_permissions & UP_HAMMER) == 0) + { + context.m_voting = true; + } if (context.m_voting) { vote(context, "start", ""); From c401c566aebb5e51588cf56e4c0e9eebd8686f4d Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 27 Dec 2021 16:55:26 +0300 Subject: [PATCH 162/830] Fix CE and several warnings --- src/network/protocols/command_manager.cpp | 24 ++++++++++------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 20533952ee6..15eef6380b6 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -75,7 +75,6 @@ void CommandManager::initCommands() { auto kick_permissions = ((ServerConfig::m_kicks_allowed ? UP_CROWNED : UP_HAMMER) | PE_VOTED); - auto start_permissions = (ServerConfig::m_owner_less ? UP_EVERYONE : UP_CROWNED | PE_VOTED); m_commands.emplace_back("commands", &CommandManager::process_commands, UP_EVERYONE, CS_ALWAYS, "/commands", "everyone", "Prints the list of commands available to you. This list may differ depending on server settings and your permissions."); m_commands.emplace_back("replay", &CommandManager::process_replay, UP_SINGLE, CS_ALWAYS, "/replay [0 | 1]", "hammers, singleplayers", "Toggles whether the replay of the race is recorded."); m_commands.emplace_back("start", &CommandManager::process_start, UP_EVERYONE | PE_VOTED, CS_ALWAYS, "/start", "everyone", "Basically clicks on the green “Ready” button."); @@ -191,7 +190,6 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); int permissions = m_lobby->getPermissions(peer); - bool found_command = false; bool voting = false; std::string action = "invoke"; std::string username = StringUtils::wideToUtf8( @@ -214,7 +212,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) } for (int i = 1; i <= 5; ++i) { if (argv[0] == std::to_string(i)) { - if (i - 1 < m_user_command_replacements[username].size()) { + if (i - 1 < (int)m_user_command_replacements[username].size()) { cmd = m_user_command_replacements[username][i - 1]; argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); if (argv.size() == 0) @@ -246,7 +244,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) std::string response = "You invoked \"" + cmd + "\", but there is " "no command \"" + initial_command + "\". Choose a fix or ignore:"; - for (int i = 0; i < closest_commands.size(); ++i) { + for (unsigned i = 0; i < closest_commands.size(); ++i) { argv[0] = closest_commands[i].first; CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); m_user_command_replacements[username].push_back(cmd); @@ -330,7 +328,6 @@ bool CommandManager::isAvailable(const Command& c) void CommandManager::vote(Context& context, std::string category, std::string value) { - auto& cmd = context.m_cmd; auto& peer = context.m_peer; auto& argv = context.m_argv; std::string username = StringUtils::wideToUtf8( @@ -455,7 +452,7 @@ void CommandManager::process_replay(Context& context) void CommandManager::process_start(Context& context) { - if (!ServerConfig::m_owner_less && (m_user_permissions & UP_HAMMER) == 0) + if (!ServerConfig::m_owner_less && (context.m_user_permissions & UP_HAMMER) == 0) { context.m_voting = true; } @@ -474,7 +471,7 @@ void CommandManager::process_config(Context& context) int difficulty = m_lobby->getDifficulty(); int mode = m_lobby->getGameMode(); bool goal_target = m_lobby->isSoccerGoalTarget(); - bool gp = false; + // bool gp = false; std::vector> mode_aliases = { {"m0"}, {"m1"}, @@ -498,7 +495,7 @@ void CommandManager::process_config(Context& context) }; for (unsigned i = 1; i < argv.size(); i++) { - for (int j = 0; j < mode_aliases.size(); ++j) { + for (unsigned j = 0; j < mode_aliases.size(); ++j) { if (j <= 2 || j == 5) { // Switching to GP or modes 2, 5 is not supported yet continue; @@ -509,14 +506,14 @@ void CommandManager::process_config(Context& context) } } } - for (int j = 0; j < difficulty_aliases.size(); ++j) { + for (unsigned j = 0; j < difficulty_aliases.size(); ++j) { for (std::string& alias: difficulty_aliases[j]) { if (argv[i] == alias) { difficulty = j; } } } - for (int j = 0; j < goal_aliases.size(); ++j) { + for (unsigned j = 0; j < goal_aliases.size(); ++j) { for (std::string& alias: goal_aliases[j]) { if (argv[i] == alias) { goal_target = (bool)j; @@ -2151,12 +2148,11 @@ void CommandManager::process_test(Context& context) void CommandManager::process_slots(Context& context) { auto& argv = context.m_argv; - auto& peer = context.m_peer; bool fail = false; unsigned number = 0; if (argv.size() < 2 || !StringUtils::parseString(argv[1], &number)) fail = true; - else if (number <= 0 || number > ServerConfig::m_server_max_players) + else if (number <= 0 || (int)number > ServerConfig::m_server_max_players) fail = true; if (fail) { @@ -2207,7 +2203,7 @@ void CommandManager::deleteUser(std::string& s) void CommandManager::restoreCmdByArgv(std::string& cmd, std::vector& argv, char c, char d, char e, char f) { cmd.clear(); - for (int i = 0; i < argv.size(); ++i) { + for (unsigned i = 0; i < argv.size(); ++i) { bool quoted = false; if (argv[i].find(c) != std::string::npos || argv[i].empty()) { quoted = true; @@ -2218,7 +2214,7 @@ void CommandManager::restoreCmdByArgv(std::string& cmd, std::vector if (quoted) { cmd.push_back(d); } - for (int j = 0; j < argv[i].size(); ++j) { + for (unsigned j = 0; j < argv[i].size(); ++j) { if (argv[i][j] == d || argv[i][j] == e || argv[i][j] == f) { cmd.push_back(f); } From db1c8591182efcc2b7fae7ba87c305de1398a031 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 28 Dec 2021 14:10:02 +0300 Subject: [PATCH 163/830] Add /time --- src/network/protocols/command_manager.cpp | 9 +++++++++ src/network/protocols/command_manager.hpp | 1 + 2 files changed, 10 insertions(+) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 15eef6380b6..476aa7f1c84 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -143,6 +143,7 @@ void CommandManager::initCommands() m_commands.emplace_back("4", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/4", "everyone", "This command allows to choose 4th of suggested options when a typo is made"); m_commands.emplace_back("5", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/5", "everyone", "This command allows to choose 5th of suggested options when a typo is made"); m_commands.emplace_back("slots", &CommandManager::process_slots, UP_HAMMER | PE_VOTED, CS_ALWAYS, "/slots (number of slots)", "hammers; voted", "Sets the number of playable slots to a certain value"); + m_commands.emplace_back("time", &CommandManager::process_time, UP_EVERYONE, CS_ALWAYS, "/time", "everyone", "Displays server time"); addTextResponse("moreinfo", StringUtils::wideToUtf8(m_lobby->m_help_message)); addTextResponse("version", "1.3-rc1 k 210fff beta"); @@ -2171,6 +2172,14 @@ void CommandManager::process_slots(Context& context) } // process_slots // ======================================================================== +void CommandManager::process_time(Context& context) +{ + auto& peer = context.m_peer; + std::string msg = "Server time: " + StkTime::getLogTime(); + m_lobby->sendStringToPeer(msg, peer); +} // process_time +// ======================================================================== + void CommandManager::special(Context& context) { // This function is used as a function for /vote and possibly several diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index b199f96222e..e2a0714447e 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -189,6 +189,7 @@ class CommandManager void process_mimiz(Context& context); void process_test(Context& context); void process_slots(Context& context); + void process_time(Context& context); void special(Context& context); public: From 321e4004ae63faa34723445168221c10a7898575 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 28 Dec 2021 17:40:13 +0300 Subject: [PATCH 164/830] Try to add /checkaddon --- src/network/protocols/command_manager.cpp | 109 +++++++++++++++++++++- src/network/protocols/command_manager.hpp | 1 + 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 476aa7f1c84..3b3235417b1 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -85,6 +85,7 @@ void CommandManager::initCommands() m_commands.emplace_back("spectate", &CommandManager::process_spectate, UP_EVERYONE, CS_ALWAYS, "/spectate [0 | 1]", "everyone", "Toggles autospectate mode."); m_commands.emplace_back("addons", &CommandManager::process_addons, UP_EVERYONE, CS_ALWAYS, "/addons [type]", "everyone", "Lists addons installed for all players that can play, in random order. Limits the list to a certain addon type if specified."); m_commands.emplace_back("moreaddons", &CommandManager::process_addons, UP_EVERYONE, CS_ALWAYS, "/moreaddons [type]", "everyone", "Lists top 5 addons that are missing for at least one player, sorted by the number of players that don’t have the addon ascending, random for equal number of players. Limits the list to a certain addon type if specified."); + m_commands.emplace_back("checkaddon", &CommandManager::process_checkaddon, UP_EVERYONE, CS_ALWAYS, "/checkaddon (addon)", "everyone", "Displays numbers of players who have the corresponding addon, and whether server has it. Displays up to 5 random players from each category."); m_commands.emplace_back("listserveraddon", &CommandManager::process_lsa, UP_EVERYONE, CS_ALWAYS, "/listserveraddon [-type] (substring)", "everyone", "Lists addons installed on the server that have a specified substring in their id. Limits the list to a certain addon type if specified."); m_commands.emplace_back("playerhasaddon", &CommandManager::process_pha, UP_EVERYONE, CS_ALWAYS, "/playerhasaddon (addon) (username)", "everyone", "Checks whether a player has a certain addon."); m_commands.emplace_back("kick", &CommandManager::process_kick, kick_permissions, CS_ALWAYS, "/kick (username)", "crowns if server allows, hammers; votable", "Kicks a player from the server."); @@ -126,7 +127,7 @@ void CommandManager::initCommands() #endif m_commands.emplace_back("muteall", &CommandManager::process_muteall, UP_EVERYONE, CS_SOCCER_TOURNAMENT, "/muteall [0 | 1]", "everyone in soccer tournament mode", "Toggles whether a player wants to receive messages from anyone except acting players and referees in soccer tournament mode (this may be forced for acting player and referees using config)."); m_commands.emplace_back("game", &CommandManager::process_game, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/game [number] [length]", "soccer tournament referees", "Prepares the server for a certain game, with certain duration or number of goals."); - m_commands.emplace_back("role", &CommandManager::process_role, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/role ([rbjsRBJS]) (username | #Category)", "soccer tournament referees", "Assigns a role to a player. Roles include: “r” and “b” - acting players with red and blue colors, respectively; “j” - judge/referee, “s” – spectator. May be done simultaneously for a specified category. Fails if the player doesn’t satisfy the requirements for the role."); + m_commands.emplace_back("role", &CommandManager::process_role, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/role ([rbjsRBJS]) (username | #Category)", "soccer tournament referees", "Assigns a role to a player. Roles include: “r” and “b” - acting players with red and blue colors, respectively; “j” - judge/referee, “s” – spectator. May be done simultaneously for a specified category. Fails if the player doesn't satisfy the requirements for the role."); m_commands.emplace_back("stop", &CommandManager::process_stop, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/stop", "soccer tournament referees", "Disables goal counting during the game."); m_commands.emplace_back("go", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/go", "soccer tournament referees", "Enables goal counting during the game."); m_commands.emplace_back("play", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/play", "soccer tournament referees", "Enables goal counting during the game."); @@ -732,6 +733,112 @@ void CommandManager::process_addons(Context& context) } // process_addons // ======================================================================== +void CommandManager::process_checkaddon(Context& context) +{ + auto& argv = context.m_argv; + if (argv.size() < 2) + { + error(context); + return; + } + std::string id = "addon_" + argv[1]; + const unsigned HAS_KART = 1; + const unsigned HAS_MAP = 2; + + unsigned server_status = 0; + std::vector players[4]; + + if (m_lobby->m_addon_kts.first.count(id)) + server_status |= HAS_KART; + if (m_lobby->m_addon_kts.second.count(id)) + server_status |= HAS_MAP; + + auto peers = STKHost::get()->getPeers(); + unsigned total_players = 0; + for (auto peer : peers) + { + if (!peer || !peer->isValidated() || peer->isWaitingForGame() || !m_lobby->canRace(peer)) + continue; + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + const auto& kt = peer->getClientAssets(); + unsigned status = 0; + if (kt.first.find(id) != kt.first.end()) + status |= HAS_KART; + if (kt.second.find(id) != kt.second.end()) + status |= HAS_MAP; + players[status].push_back(username); + ++total_players; + } + + std::string response = ""; + std::string item_name[3]; + bool needed[3]; + item_name[HAS_KART] = "kart"; + item_name[HAS_MAP] = "map"; + needed[HAS_KART] = (players[HAS_KART].size() + players[HAS_MAP | HAS_KART].size() > 0); + needed[HAS_MAP] = (players[HAS_MAP].size() + players[HAS_MAP | HAS_KART].size() > 0); + if (server_status & HAS_KART) + needed[HAS_KART] = true; + if (server_status & HAS_MAP) + needed[HAS_MAP] = true; + + if (!needed[HAS_KART] && !needed[HAS_MAP]) + { + response = "Neither server nor clients have addon " + argv[1] + " installed"; + } + else + { + std::random_device rd; + std::mt19937 g(rd()); + std::string installed_text[2] = {"Not installed", "Installed"}; + for (unsigned item = 1; item <= 2; ++item) + { + if (!needed[item]) + continue; + response += "Server "; + if (server_status & item) + response += "has"; + else + response += "doesn't have"; + response += " " + item_name[item] + " " + argv[1] + "\n"; + + std::vector categories[2]; + for (unsigned status = 0; status < 4; ++status) + { + for (const std::string& s: players[status]) + categories[(status & item ? 1 : 0)].push_back(s); + } + for (int i = 0; i < 2; ++i) + shuffle(categories[i].begin(), categories[i].end(), g); + if (categories[0].empty()) + response += "Everyone who can play has this " + item_name[item] + "\n"; + else if (categories[1].empty()) + response += "No one of those who can play has this " + item_name[item] + "\n"; + else + { + for (int i = 1; i >= 0; --i) + { + response += installed_text[i] + " for "; + response += std::to_string(categories[i].size()) + " player(s): "; + for (int j = 0; j < 5 && j < (int)categories[i].size(); ++j) + { + if (j) + response += ", "; + response += categories[i][j]; + } + if (categories[i].size() > 5) + response += ", ..."; + response += "\n"; + } + } + } + response.pop_back(); + } + m_lobby->sendStringToPeer(response, context.m_peer); +} // process_checkaddon +// ======================================================================== + void CommandManager::process_lsa(Context& context) { std::string response = ""; diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index e2a0714447e..a3d1415d4cc 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -146,6 +146,7 @@ class CommandManager void process_config(Context& context); void process_spectate(Context& context); void process_addons(Context& context); + void process_checkaddon(Context& context); void process_lsa(Context& context); void process_pha(Context& context); void process_kick(Context& context); From 1332f4767a1ecc4ab75b923f7d4eeef8c42d5a4d Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 28 Dec 2021 21:09:16 +0300 Subject: [PATCH 165/830] Try to change crown order to "order by the last moment the peer was spectator or absent asc", and also try to fix all spectate modes --- src/network/protocols/command_manager.cpp | 32 +++------------- src/network/protocols/server_lobby.cpp | 46 ++++++++++------------- src/network/protocols/server_lobby.hpp | 2 - src/network/stk_peer.cpp | 1 + src/network/stk_peer.hpp | 13 ++++++- 5 files changed, 38 insertions(+), 56 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 3b3235417b1..d2555a5c8a0 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -566,41 +566,18 @@ void CommandManager::process_spectate(Context& context) if (argv.size() == 1) { - if (m_lobby->m_state.load() != m_lobby->WAITING_FOR_START_GAME) - { - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - if (m_lobby->m_default_always_spectate_peers.count(peer.get())) - argv.push_back("0"); - else - argv.push_back("1"); - } + if (peer->isCommandSpectator()) + argv.push_back("0"); else - { - if (peer->alwaysSpectate()) - argv.push_back("0"); - else - argv.push_back("1"); - } + argv.push_back("1"); } - if (argv.size() != 2 || (argv[1] != "0" && argv[1] != "1")) + if (argv.size() < 2 || (argv[1] != "0" && argv[1] != "1")) { error(context); return; } - if (m_lobby->m_state.load() != m_lobby->WAITING_FOR_START_GAME) - { - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - if (argv[1] == "1") - m_lobby->m_default_always_spectate_peers.insert(peer.get()); - else - m_lobby->m_default_always_spectate_peers.erase(peer.get()); - return; - } - if (argv[1] == "1") { if (m_lobby->m_process_type == PT_CHILD && @@ -614,6 +591,7 @@ void CommandManager::process_spectate(Context& context) } else peer->setAlwaysSpectate(ASM_NONE); + m_lobby->updateServerOwner(); m_lobby->updatePlayerList(); } // process_spectate // ======================================================================== diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 88aa54c0e1d..7b736dc02bd 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1893,7 +1893,7 @@ void ServerLobby::asynchronousUpdate() if (peer->alwaysSpectate() && peer->getClientAssets().second.count(track_name) == 0) { - peer->setAlwaysSpectate(ASM_NONE); + // peer->setAlwaysSpectate(ASM_NONE); peer->setWaitingForGame(true); m_peers_ready.erase(peer); bad_spectators.insert(peer.get()); @@ -2928,11 +2928,11 @@ void ServerLobby::startSelection(const Event *event) bool can_race = canRace(peer); if (!can_race && !peer->alwaysSpectate()) { - if (ServerConfig::m_soccer_tournament/* || ServerConfig::m_only_host_riding*/) - peer->setAlwaysSpectate(ASM_COMMAND); + peer->setAlwaysSpectate(ASM_FULL); peer->setWaitingForGame(true); m_peers_ready.erase(peer); need_to_update = true; + always_spectate_peers.insert(peer.get()); continue; } else if (peer->alwaysSpectate()) @@ -2945,7 +2945,6 @@ void ServerLobby::startSelection(const Event *event) if (!peer->isAIPeer()) has_peer_plays_game = true; } - // m_default_always_spectate_peers = always_spectate_peers; // kimden thinks if someone wants to race he should disable spectating // // Disable always spectate peers if no players join the game @@ -4755,23 +4754,6 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) const bool game_started = m_state.load() != WAITING_FOR_START_GAME && !update_when_reset_server; - if (update_when_reset_server) - { - if (!ServerConfig::m_soccer_tournament) - { - for (auto& peer : m_default_always_spectate_peers) - peer->setAlwaysSpectate(ASM_COMMAND); - } - else - { - auto peers = STKHost::get()->getPeers(); - for (auto& peer: peers) - { - peer->setAlwaysSpectate(ASM_NONE); - } - } - } - auto all_profiles = STKHost::get()->getAllPlayerProfiles(); size_t all_profiles_size = all_profiles.size(); for (auto& profile : all_profiles) @@ -4920,7 +4902,9 @@ void ServerLobby::updateServerOwner() std::sort(peers.begin(), peers.end(), [](const std::shared_ptr a, const std::shared_ptr b)->bool { - return a->getHostId() < b->getHostId(); + if (a->isCommandSpectator() ^ b->isCommandSpectator()) + return b->isCommandSpectator(); + return a->getRejoinTime() < b->getRejoinTime(); }); std::shared_ptr owner; @@ -6493,10 +6477,20 @@ std::set& ServerLobby::getSpectatorsByLimit(bool update) if (total_players <= player_limit) return m_spectators_by_limit; + for (int i = 0; i < (int)peers.size(); ++i) + { + if (!peers[i]->isValidated() || peers[i]->isCommandSpectator()) + { + swap(peers[i], peers.back()); + peers.pop_back(); + --i; + } + } + std::sort(peers.begin(), peers.end(), [](const std::shared_ptr& a, const std::shared_ptr& b) - { return a->getHostId() < b->getHostId(); }); + { return a->getRejoinTime() < b->getRejoinTime(); }); if (m_state.load() >= RACING) { @@ -6521,10 +6515,10 @@ std::set& ServerLobby::getSpectatorsByLimit(bool update) } else { - if (peer->isSpectator()) - continue; + // if (peer->isSpectator()) + // continue; player_count += (unsigned)peer->getPlayerProfiles().size(); - if (peer->isWaitingForGame() && (player_count > player_limit || ingame_players >= player_limit)) + if (/*peer->isWaitingForGame() && */(player_count > player_limit || ingame_players >= player_limit)) m_spectators_by_limit.insert(peer.get()); } } diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 719498fbdde..4b5b3e2bd6c 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -377,8 +377,6 @@ class ServerLobby : public LobbyProtocol std::string m_scoring_type; - std::set m_default_always_spectate_peers; - std::set m_usernames_white_list; bool m_allowed_to_start; diff --git a/src/network/stk_peer.cpp b/src/network/stk_peer.cpp index 96ce41e8ce2..b42a09172fc 100644 --- a/src/network/stk_peer.cpp +++ b/src/network/stk_peer.cpp @@ -43,6 +43,7 @@ STKPeer::STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id) m_enet_peer = enet_peer; m_host_id = host_id; m_connected_time = StkTime::getMonoTimeMs(); + m_rejoin_time = m_connected_time; m_validated.store(false); m_always_spectate.store(ASM_NONE); m_average_ping.store(0); diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index 25652b50ab9..c7b0196c74e 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -105,6 +105,8 @@ class STKPeer : public NoCopy uint64_t m_connected_time; + uint64_t m_rejoin_time; + std::atomic m_last_activity; std::atomic m_last_message; @@ -312,11 +314,20 @@ class STKPeer : public NoCopy const SocketAddress& getAddress() const { return *m_socket_address.get(); } // ------------------------------------------------------------------------ void setAlwaysSpectate(AlwaysSpectateMode mode) - { m_always_spectate.store(mode); } + { + if (m_always_spectate.load() == ASM_COMMAND && mode == ASM_NONE) + m_rejoin_time = StkTime::getMonoTimeMs(); + m_always_spectate.store(mode); + } // ------------------------------------------------------------------------ bool alwaysSpectate() const { return m_always_spectate.load() != ASM_NONE; } // ------------------------------------------------------------------------ + bool isCommandSpectator() const + { return m_always_spectate.load() == ASM_COMMAND; } + // ------------------------------------------------------------------------ + uint64_t getRejoinTime() const { return m_rejoin_time; } + // ------------------------------------------------------------------------ void resetAlwaysSpectateFull() { if (m_always_spectate.load() == ASM_FULL) From 7f504badcfb655adcb3f8c5dcae49785a768967a Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 28 Dec 2021 23:05:59 +0300 Subject: [PATCH 166/830] Try to remove some limitations --- src/network/protocols/server_lobby.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 7b736dc02bd..b00eec3cbf2 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4890,12 +4890,12 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) //----------------------------------------------------------------------------- void ServerLobby::updateServerOwner() { - if (m_state.load() < WAITING_FOR_START_GAME || - m_state.load() > RESULT_DISPLAY || + if (/*m_state.load() < WAITING_FOR_START_GAME || + m_state.load() > RESULT_DISPLAY ||*/ ServerConfig::m_owner_less) return; - if (!m_server_owner.expired()) - return; + // if (!m_server_owner.expired()) + // return; auto peers = STKHost::get()->getPeers(); if (peers.empty()) return; From 66533adee7cfc149a6ae5ab88542585fec1fdf3e Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 28 Dec 2021 23:23:57 +0300 Subject: [PATCH 167/830] Avoid receiving 500 "you are now owner" messages per second lol --- src/network/protocols/command_manager.cpp | 2 +- src/network/protocols/server_lobby.cpp | 10 +++++----- src/network/protocols/server_lobby.hpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index d2555a5c8a0..d87c406565a 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -591,7 +591,7 @@ void CommandManager::process_spectate(Context& context) } else peer->setAlwaysSpectate(ASM_NONE); - m_lobby->updateServerOwner(); + m_lobby->updateServerOwner(true); m_lobby->updatePlayerList(); } // process_spectate // ======================================================================== diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index b00eec3cbf2..b7fdccbeeae 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4888,14 +4888,14 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) } // updatePlayerList //----------------------------------------------------------------------------- -void ServerLobby::updateServerOwner() +void ServerLobby::updateServerOwner(bool force) { - if (/*m_state.load() < WAITING_FOR_START_GAME || - m_state.load() > RESULT_DISPLAY ||*/ + if (m_state.load() < WAITING_FOR_START_GAME || + m_state.load() > RESULT_DISPLAY || ServerConfig::m_owner_less) return; - // if (!m_server_owner.expired()) - // return; + if (!force && !m_server_owner.expired()) + return; auto peers = STKHost::get()->getPeers(); if (peers.empty()) return; diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 4b5b3e2bd6c..8cfd95c1009 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -443,7 +443,7 @@ class ServerLobby : public LobbyProtocol void unregisterServer(bool now, std::weak_ptr sl = std::weak_ptr()); void updatePlayerList(bool update_when_reset_server = false); - void updateServerOwner(); + void updateServerOwner(bool force = false); void handleServerConfiguration(Event* event); void handleServerConfiguration(std::shared_ptr peer, int difficulty, int mode, bool soccer_goal_target); From 8b9447f38a5bf368a1df383bd88d20b7b8d70382 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 29 Dec 2021 03:49:35 +0300 Subject: [PATCH 168/830] Fix /checkaddon behaviour towards arenas, exclude ASM_COMMAND players from addon stat commands, try to avoid extra owner messages --- src/network/protocols/command_manager.cpp | 13 ++++++++++--- src/network/protocols/server_lobby.cpp | 13 ++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index d87c406565a..73c79c60abe 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -335,8 +335,9 @@ void CommandManager::vote(Context& context, std::string category, std::string va std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); auto& votable = m_votables[argv[0]]; + bool neededCheck = votable.needsCheck(); votable.castVote(username, category, value); - if (votable.needsCheck()) + if (votable.needsCheck() && !neededCheck) m_triggered_votables.push(argv[0]); } // vote // ======================================================================== @@ -634,7 +635,8 @@ void CommandManager::process_addons(Context& context) int num_players = 0; for (auto peer : peers) { - if (!peer || !peer->isValidated() || peer->isWaitingForGame() || !m_lobby->canRace(peer)) + if (!peer || !peer->isValidated() || peer->isWaitingForGame() + || !m_lobby->canRace(peer) || peer->isCommandSpectator()) continue; ++num_players; std::string username = StringUtils::wideToUtf8( @@ -730,12 +732,17 @@ void CommandManager::process_checkaddon(Context& context) server_status |= HAS_KART; if (m_lobby->m_addon_kts.second.count(id)) server_status |= HAS_MAP; + if (m_lobby->m_addon_arenas.count(id)) + server_status |= HAS_MAP; + if (m_lobby->m_addon_soccers.count(id)) + server_status |= HAS_MAP; auto peers = STKHost::get()->getPeers(); unsigned total_players = 0; for (auto peer : peers) { - if (!peer || !peer->isValidated() || peer->isWaitingForGame() || !m_lobby->canRace(peer)) + if (!peer || !peer->isValidated() || peer->isWaitingForGame() + || !m_lobby->canRace(peer) || peer->isCommandSpectator()) continue; std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index b7fdccbeeae..3112644da40 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4922,11 +4922,14 @@ void ServerLobby::updateServerOwner(bool force) } if (owner) { - NetworkString* ns = getNetworkString(); - ns->setSynchronous(true); - ns->addUInt8(LE_SERVER_OWNERSHIP); - owner->sendPacket(ns); - delete ns; + if (m_server_owner.expired() || m_server_owner.lock() != owner) + { + NetworkString* ns = getNetworkString(); + ns->setSynchronous(true); + ns->addUInt8(LE_SERVER_OWNERSHIP); + owner->sendPacket(ns); + delete ns; + } m_server_owner = owner; m_server_owner_id.store(owner->getHostId()); updatePlayerList(); From 77373a3e416f160fcef283cedc77c710f591c345 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 1 Jan 2022 16:16:41 +0300 Subject: [PATCH 169/830] Display installaddon command instead of addon id for /moreaddons --- src/network/protocols/command_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 73c79c60abe..7e699c3a7a9 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -694,7 +694,7 @@ void CommandManager::process_addons(Context& context) response += ". More addons to install:"; for (unsigned i = 0; i < result.size(); ++i) { - response += "\n" + result[i].first + ", missing for " + response += "\n/installaddon " + result[i].first.substr(6) + ", missing for " + std::to_string(result[i].second.size()) + " player(s):"; std::sort(result[i].second.begin(), result[i].second.end()); From e51268d743fa79f98be9ce0cf9604f31323c719d Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 1 Jan 2022 19:40:57 +0300 Subject: [PATCH 170/830] Move commands' information to data folder, add output-only commands, add descriptions for client commands --- data/commands.xml | 371 ++++++++++++++++++++++ src/network/protocols/command_manager.cpp | 192 +++++++---- src/network/protocols/command_manager.hpp | 39 ++- 3 files changed, 520 insertions(+), 82 deletions(-) create mode 100644 data/commands.xml diff --git a/data/commands.xml b/data/commands.xml new file mode 100644 index 00000000000..a0fa9f79a15 --- /dev/null +++ b/data/commands.xml @@ -0,0 +1,371 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 7e699c3a7a9..cd959c76456 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -20,6 +20,7 @@ #include "addons/addon.hpp" // #include "config/user_config.hpp" +#include "io/file_manager.hpp" // #include "items/network_item_manager.hpp" // #include "items/powerup_manager.hpp" // #include "items/attachment.hpp" @@ -72,84 +73,139 @@ // ======================================================================== +void CommandManager::initCommandsInfo() +{ + const std::string file_name = file_manager->getAsset("commands.xml"); + const XMLNode *root = file_manager->createXMLTree(file_name); + unsigned int num_nodes = root->getNumNodes(); + uint32_t version = 1; + root->get("version", &version); + if (version != 1) + Log::warn("CommandManager", "command.xml has version %d which is not supported", version); + for (unsigned int i = 0; i < num_nodes; i++) + { + const XMLNode *node = root->getNode(i); + std::string node_name = node->getName(); + if (node_name == "command") + { + std::string name = ""; + std::string usage = ""; + std::string permissions = ""; + std::string description = ""; + node->get("name", &name); + node->get("usage", &usage); + node->get("permissions", &permissions); + node->get("description", &description); + m_config_descriptions[name] = CommandDescription(usage, permissions, description); + } + else if (node_name == "text-command") + { + std::string name = ""; + std::string text = ""; + node->get("name", &name); + node->get("text", &text); + m_commands.emplace_back(name, &CommandManager::process_text, UP_EVERYONE, CS_ALWAYS); + addTextResponse(name, text); + } + } +} // initCommandsInfo +// ======================================================================== + void CommandManager::initCommands() { + initCommandsInfo(); + using CM = CommandManager; auto kick_permissions = ((ServerConfig::m_kicks_allowed ? UP_CROWNED : UP_HAMMER) | PE_VOTED); - m_commands.emplace_back("commands", &CommandManager::process_commands, UP_EVERYONE, CS_ALWAYS, "/commands", "everyone", "Prints the list of commands available to you. This list may differ depending on server settings and your permissions."); - m_commands.emplace_back("replay", &CommandManager::process_replay, UP_SINGLE, CS_ALWAYS, "/replay [0 | 1]", "hammers, singleplayers", "Toggles whether the replay of the race is recorded."); - m_commands.emplace_back("start", &CommandManager::process_start, UP_EVERYONE | PE_VOTED, CS_ALWAYS, "/start", "everyone", "Basically clicks on the green “Ready” button."); + auto& v = m_commands; + v.emplace_back("commands", &CM::process_commands, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("replay", &CM::process_replay, UP_SINGLE, CS_ALWAYS); + v.emplace_back("start", &CM::process_start, UP_EVERYONE | PE_VOTED, CS_ALWAYS); if (ServerConfig::m_server_configurable) { - m_commands.emplace_back("config", &CommandManager::process_config, UP_CROWNED | PE_VOTED, CS_ALWAYS, "/config ", "crowns; votable", "Changes game mode and difficulty if allowed."); - } - m_commands.emplace_back("spectate", &CommandManager::process_spectate, UP_EVERYONE, CS_ALWAYS, "/spectate [0 | 1]", "everyone", "Toggles autospectate mode."); - m_commands.emplace_back("addons", &CommandManager::process_addons, UP_EVERYONE, CS_ALWAYS, "/addons [type]", "everyone", "Lists addons installed for all players that can play, in random order. Limits the list to a certain addon type if specified."); - m_commands.emplace_back("moreaddons", &CommandManager::process_addons, UP_EVERYONE, CS_ALWAYS, "/moreaddons [type]", "everyone", "Lists top 5 addons that are missing for at least one player, sorted by the number of players that don’t have the addon ascending, random for equal number of players. Limits the list to a certain addon type if specified."); - m_commands.emplace_back("checkaddon", &CommandManager::process_checkaddon, UP_EVERYONE, CS_ALWAYS, "/checkaddon (addon)", "everyone", "Displays numbers of players who have the corresponding addon, and whether server has it. Displays up to 5 random players from each category."); - m_commands.emplace_back("listserveraddon", &CommandManager::process_lsa, UP_EVERYONE, CS_ALWAYS, "/listserveraddon [-type] (substring)", "everyone", "Lists addons installed on the server that have a specified substring in their id. Limits the list to a certain addon type if specified."); - m_commands.emplace_back("playerhasaddon", &CommandManager::process_pha, UP_EVERYONE, CS_ALWAYS, "/playerhasaddon (addon) (username)", "everyone", "Checks whether a player has a certain addon."); - m_commands.emplace_back("kick", &CommandManager::process_kick, kick_permissions, CS_ALWAYS, "/kick (username)", "crowns if server allows, hammers; votable", "Kicks a player from the server."); - m_commands.emplace_back("kickban", &CommandManager::process_kick, UP_HAMMER | PE_VOTED, CS_ALWAYS, "/kickban (username)", "hammers; votable", "Kicks a player from the server and temporarily bans him."); - m_commands.emplace_back("unban", &CommandManager::process_unban, UP_HAMMER, CS_ALWAYS, "/unban (username)", "hammers", "Removes a temporary ban from a player."); - m_commands.emplace_back("ban", &CommandManager::process_ban, UP_HAMMER, CS_ALWAYS, "/ban (username)", "hammers", "Adds a temporary ban to a player without kicking."); - m_commands.emplace_back("playeraddonscore", &CommandManager::process_pas, UP_EVERYONE, CS_ALWAYS, "/playeraddonscore (username)", "everyone", "Returns the number (not the percentage!) of addons of different types installed by a player."); - m_commands.emplace_back("serverhasaddon", &CommandManager::process_sha, UP_EVERYONE, CS_ALWAYS, "/serverhasaddon (addon)", "everyone", "Checks whether the server has a certain addon."); - m_commands.emplace_back("mute", &CommandManager::process_mute, UP_EVERYONE, CS_ALWAYS, "/mute (username)", "everyone", "Temporarily blocks player’s messages from reaching you (until the server restart)."); - m_commands.emplace_back("unmute", &CommandManager::process_unmute, UP_EVERYONE, CS_ALWAYS, "/unmute (username)", "everyone", "Unblocks player’s messages from reaching you."); - m_commands.emplace_back("listmute", &CommandManager::process_listmute, UP_EVERYONE, CS_ALWAYS, "/listmute", "everyone", "Lists players whom you blocked using /mute command."); - m_commands.emplace_back("moreinfo", &CommandManager::process_text, UP_EVERYONE, CS_ALWAYS, "/moreinfo", "everyone", "Displays an additional server message."); - m_commands.emplace_back("gnu", &CommandManager::process_gnu, UP_HAMMER | PE_VOTED, CS_ALWAYS, "/gnu [kart]", "hammers; voted", "Starts kart elimination with Gnu (or a specified kart)."); - m_commands.emplace_back("nognu", &CommandManager::process_gnu, UP_HAMMER | PE_VOTED, CS_ALWAYS, "/nognu", "hammers; voted", "Cancels kart elimination."); - m_commands.emplace_back("tell", &CommandManager::process_tell, UP_EVERYONE, CS_ALWAYS, "/tell (report contents)", "everyone", "Makes a report to the server owner (if the server has a database to store the reports)."); - m_commands.emplace_back("standings", &CommandManager::process_standings, UP_EVERYONE, CS_ALWAYS, "/standings [gp | gnu]", "everyone", "Displays standings of grand prix or kart elimination, picks whatever of them is played now."); - m_commands.emplace_back("teamchat", &CommandManager::process_teamchat, UP_EVERYONE, CS_ALWAYS, "/teamchat", "everyone", "Limits your future messages to be sent only to your teammates."); - m_commands.emplace_back("to", &CommandManager::process_to, UP_EVERYONE, CS_ALWAYS, "/to (username1) ... (usernameN)", "everyone", "Limits your future messages to be sent only to specified usernames."); - m_commands.emplace_back("public", &CommandManager::process_public, UP_EVERYONE, CS_ALWAYS, "/public", "everyone", "Allows your future messages to be sent to everyone."); - m_commands.emplace_back("record", &CommandManager::process_record, UP_EVERYONE, CS_ALWAYS, "/record (track id) (mode) (direction) (laps)", "everyone", "Receives the server record for the race settings if there is any (and if the server has a database to store the records)."); - m_commands.emplace_back("power", &CommandManager::process_power, UP_EVERYONE, CS_ALWAYS, "/power (password)", "everyone", "Enters the hammer mode if the password is correct."); - m_commands.emplace_back("length", &CommandManager::process_length, UP_SINGLE, CS_ALWAYS, "/length (x (float) | = (int) | check | clear)", "hammers, singleplayers", "Manipulates the length of the games, “= n” fixes the number of laps to n, “x k” sets it to k times default number of laps, “check” displays the setting, “clear” allows players to choose it freely."); - m_commands.emplace_back("queue", &CommandManager::process_queue, UP_SINGLE, CS_ALWAYS, "/queue (show | push[_front] (track) | pop[_back])", "hammers, singleplayers", "Manipulates the track queue aka the next played tracks. “show” displays it, “push” adds the track to the end of the queue, “pop” removes a track at the front. You can use “_back” and “_front” to specify on which end of the queue to add or remove the tracks."); - m_commands.emplace_back("adminstart", &CommandManager::process_adminstart, UP_HAMMER, CS_ALWAYS, "/adminstart [0 | 1]", "hammers", "Toggles whether the game can be started on the server."); - m_commands.emplace_back("shuffle", &CommandManager::process_shuffle, UP_HAMMER, CS_ALWAYS, "/shuffle [0 | 1]", "hammers", "Toggles whether the Grand Prix grid is shuffled before each race (1), or it corresponds to the standings (0)."); - m_commands.emplace_back("timeout", &CommandManager::process_timeout, UP_HAMMER, CS_ALWAYS, "/timeout [positive int x]", "hammers", "Sets the timeout in seconds, whatever it may mean."); - m_commands.emplace_back("team", &CommandManager::process_team, UP_HAMMER, CS_ALWAYS, "/team ([roygbp-]) (username)", "hammers", "Move a player to one of six teams denoted by square emojis (r - red, o - orange, y - yellow, g - green, b - blue, p – purple), or removes the player from the teams (“-”)."); - m_commands.emplace_back("cat+", &CommandManager::process_cat, UP_HAMMER, CS_ALWAYS, "/cat+ (category) (username)", "hammers", "Adds the player to a certain category."); - m_commands.emplace_back("cat-", &CommandManager::process_cat, UP_HAMMER, CS_ALWAYS, "/cat- (category) (username)", "hammers", "Removes the player from a certain category."); - m_commands.emplace_back("cat*", &CommandManager::process_cat, UP_HAMMER, CS_ALWAYS, "/cat* (category) (0 | 1)", "hammers", "Toggles whether a category is displayed in the player list."); - m_commands.emplace_back("troll", &CommandManager::process_troll, UP_HAMMER, CS_ALWAYS, "/troll [0 | 1]", "hammers", "Toggles anti-troll system."); - m_commands.emplace_back("hitmsg", &CommandManager::process_hitmsg, UP_HAMMER, CS_ALWAYS, "/hitmsg [0 | 1]", "hammers", "Toggles whether the messages about teammate hits are displayed."); - m_commands.emplace_back("teamhit", &CommandManager::process_teamhit, UP_HAMMER, CS_ALWAYS, "/teamhit [0 | 1]", "hammers", "Toggles whether the teammate hits are punished ingame."); - m_commands.emplace_back("version", &CommandManager::process_text, UP_EVERYONE, CS_ALWAYS, "/version", "everyone", "Displays version."); - m_commands.emplace_back("clear", &CommandManager::process_text, UP_EVERYONE, CS_ALWAYS, "/clear", "everyone", "Puts newlines onto the screen so that the previous messages are not visible."); - m_commands.emplace_back("register", &CommandManager::process_register, UP_EVERYONE, CS_ALWAYS, "/register [info]", "everyone", "The command is used to register to an event (if the server has a database to store the registrations). Players can provide information while registering."); + v.emplace_back("config", &CM::process_config, UP_CROWNED | PE_VOTED, CS_ALWAYS); + } + v.emplace_back("spectate", &CM::process_spectate, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("addons", &CM::process_addons, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("moreaddons", &CM::process_addons, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("checkaddon", &CM::process_checkaddon, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("listserveraddon", &CM::process_lsa, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("playerhasaddon", &CM::process_pha, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("kick", &CM::process_kick, kick_permissions, CS_ALWAYS); + v.emplace_back("kickban", &CM::process_kick, UP_HAMMER | PE_VOTED, CS_ALWAYS); + v.emplace_back("unban", &CM::process_unban, UP_HAMMER, CS_ALWAYS); + v.emplace_back("ban", &CM::process_ban, UP_HAMMER, CS_ALWAYS); + v.emplace_back("playeraddonscore", &CM::process_pas, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("serverhasaddon", &CM::process_sha, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("mute", &CM::process_mute, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("unmute", &CM::process_unmute, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("listmute", &CM::process_listmute, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("moreinfo", &CM::process_text, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("gnu", &CM::process_gnu, UP_HAMMER | PE_VOTED, CS_ALWAYS); + v.emplace_back("nognu", &CM::process_gnu, UP_HAMMER | PE_VOTED, CS_ALWAYS); + v.emplace_back("tell", &CM::process_tell, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("standings", &CM::process_standings, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("teamchat", &CM::process_teamchat, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("to", &CM::process_to, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("public", &CM::process_public, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("record", &CM::process_record, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("power", &CM::process_power, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("length", &CM::process_length, UP_SINGLE, CS_ALWAYS); + v.emplace_back("queue", &CM::process_queue, UP_SINGLE, CS_ALWAYS); + v.emplace_back("adminstart", &CM::process_adminstart, UP_HAMMER, CS_ALWAYS); + v.emplace_back("shuffle", &CM::process_shuffle, UP_HAMMER, CS_ALWAYS); + v.emplace_back("timeout", &CM::process_timeout, UP_HAMMER, CS_ALWAYS); + v.emplace_back("team", &CM::process_team, UP_HAMMER, CS_ALWAYS); + v.emplace_back("cat+", &CM::process_cat, UP_HAMMER, CS_ALWAYS); + v.emplace_back("cat-", &CM::process_cat, UP_HAMMER, CS_ALWAYS); + v.emplace_back("cat*", &CM::process_cat, UP_HAMMER, CS_ALWAYS); + v.emplace_back("troll", &CM::process_troll, UP_HAMMER, CS_ALWAYS); + v.emplace_back("hitmsg", &CM::process_hitmsg, UP_HAMMER, CS_ALWAYS); + v.emplace_back("teamhit", &CM::process_teamhit, UP_HAMMER, CS_ALWAYS); + v.emplace_back("version", &CM::process_text, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("clear", &CM::process_text, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("register", &CM::process_register, UP_EVERYONE, CS_ALWAYS); #ifdef ENABLE_WEB_SUPPORT - m_commands.emplace_back("token", &CommandManager::process_token, UP_EVERYONE, CS_ALWAYS, "/token", "everyone", "Produces a token for a player and stores it in the database (if the server has a database to store tokens). Tokens may be used to authenticate players using their STK accounts."); + v.emplace_back("token", &CM::process_token, UP_EVERYONE, CS_ALWAYS); #endif - m_commands.emplace_back("muteall", &CommandManager::process_muteall, UP_EVERYONE, CS_SOCCER_TOURNAMENT, "/muteall [0 | 1]", "everyone in soccer tournament mode", "Toggles whether a player wants to receive messages from anyone except acting players and referees in soccer tournament mode (this may be forced for acting player and referees using config)."); - m_commands.emplace_back("game", &CommandManager::process_game, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/game [number] [length]", "soccer tournament referees", "Prepares the server for a certain game, with certain duration or number of goals."); - m_commands.emplace_back("role", &CommandManager::process_role, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/role ([rbjsRBJS]) (username | #Category)", "soccer tournament referees", "Assigns a role to a player. Roles include: “r” and “b” - acting players with red and blue colors, respectively; “j” - judge/referee, “s” – spectator. May be done simultaneously for a specified category. Fails if the player doesn't satisfy the requirements for the role."); - m_commands.emplace_back("stop", &CommandManager::process_stop, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/stop", "soccer tournament referees", "Disables goal counting during the game."); - m_commands.emplace_back("go", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/go", "soccer tournament referees", "Enables goal counting during the game."); - m_commands.emplace_back("play", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/play", "soccer tournament referees", "Enables goal counting during the game."); - m_commands.emplace_back("resume", &CommandManager::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/resume", "soccer tournament referees", "Enables goal counting during the game."); - m_commands.emplace_back("lobby", &CommandManager::process_lobby, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/lobby", "soccer tournament referees", "Forces players to the lobby through the final screen, stoppng the game."); - m_commands.emplace_back("init", &CommandManager::process_init, UP_HAMMER, CS_SOCCER_TOURNAMENT, "/init (red count) (blue count)", "soccer tournament referees", "Initializes the match score to start from (red count):(blue count) instead of 0:0."); - m_commands.emplace_back("vote", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/vote (command with arguments, without “/”)", "everyone", "Casts a vote for the provided command, if it can be voted. Only useful for those players who can enforce their command but opt to vote instead of forcing; for those players who cannot invoke the command alone, /(command) is equivalent to /vote (command)."); - m_commands.emplace_back("mimiz", &CommandManager::process_mimiz, UP_EVERYONE, CS_ALWAYS, "/mimiz [text]", "everyone", "A joke command."); - m_commands.emplace_back("test", &CommandManager::process_test, UP_EVERYONE | PE_VOTED, CS_ALWAYS, "/test [poll name] [option name]", "everyone; votable", "A test command."); - m_commands.emplace_back("help", &CommandManager::process_help, UP_EVERYONE, CS_ALWAYS, "/help (command name)", "everyone", "Gives description of a given command."); - m_commands.emplace_back("1", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/1", "everyone", "This command allows to choose 1st of suggested options when a typo is made"); - m_commands.emplace_back("2", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/2", "everyone", "This command allows to choose 2nd of suggested options when a typo is made"); - m_commands.emplace_back("3", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/3", "everyone", "This command allows to choose 3rd of suggested options when a typo is made"); - m_commands.emplace_back("4", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/4", "everyone", "This command allows to choose 4th of suggested options when a typo is made"); - m_commands.emplace_back("5", &CommandManager::special, UP_EVERYONE, CS_ALWAYS, "/5", "everyone", "This command allows to choose 5th of suggested options when a typo is made"); - m_commands.emplace_back("slots", &CommandManager::process_slots, UP_HAMMER | PE_VOTED, CS_ALWAYS, "/slots (number of slots)", "hammers; voted", "Sets the number of playable slots to a certain value"); - m_commands.emplace_back("time", &CommandManager::process_time, UP_EVERYONE, CS_ALWAYS, "/time", "everyone", "Displays server time"); + v.emplace_back("muteall", &CM::process_muteall, UP_EVERYONE, CS_SOCCER_TOURNAMENT); + v.emplace_back("game", &CM::process_game, UP_HAMMER, CS_SOCCER_TOURNAMENT); + v.emplace_back("role", &CM::process_role, UP_HAMMER, CS_SOCCER_TOURNAMENT); + v.emplace_back("stop", &CM::process_stop, UP_HAMMER, CS_SOCCER_TOURNAMENT); + v.emplace_back("go", &CM::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT); + v.emplace_back("play", &CM::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT); + v.emplace_back("resume", &CM::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT); + v.emplace_back("lobby", &CM::process_lobby, UP_HAMMER, CS_SOCCER_TOURNAMENT); + v.emplace_back("init", &CM::process_init, UP_HAMMER, CS_SOCCER_TOURNAMENT); + v.emplace_back("vote", &CM::special, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("mimiz", &CM::process_mimiz, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("test", &CM::process_test, UP_EVERYONE | PE_VOTED, CS_ALWAYS); + v.emplace_back("help", &CM::process_help, UP_EVERYONE, CS_ALWAYS); + // v.emplace_back("1", &CM::special, UP_EVERYONE, CS_ALWAYS); + // v.emplace_back("2", &CM::special, UP_EVERYONE, CS_ALWAYS); + // v.emplace_back("3", &CM::special, UP_EVERYONE, CS_ALWAYS); + // v.emplace_back("4", &CM::special, UP_EVERYONE, CS_ALWAYS); + // v.emplace_back("5", &CM::special, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("slots", &CM::process_slots, UP_HAMMER | PE_VOTED, CS_ALWAYS); + v.emplace_back("time", &CM::process_time, UP_EVERYONE, CS_ALWAYS); + + v.emplace_back("addondownloadprogress", &CM::special, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("stopaddondownload", &CM::special, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("installaddon", &CM::special, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("uninstalladdon", &CM::special, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("music", &CM::special, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("addonrevision", &CM::special, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("liststkaddon", &CM::special, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("listlocaladdon", &CM::special, UP_EVERYONE, CS_ALWAYS); addTextResponse("moreinfo", StringUtils::wideToUtf8(m_lobby->m_help_message)); addTextResponse("version", "1.3-rc1 k 210fff beta"); addTextResponse("clear", std::string(30, '\n')); + for (Command& command: m_commands) { + m_stf_command_names.add(command.m_name); + command.m_description = m_config_descriptions[command.m_name]; + } + std::sort(m_commands.begin(), m_commands.end(), [](const Command& a, const Command& b) -> bool { return a.m_name < b.m_name; }); @@ -163,10 +219,6 @@ void CommandManager::initCommands() m_votables.emplace("kickban", 0.81); m_votables.emplace("gnu", 0.81); m_votables["gnu"].setCustomThreshold("gnu kart", 1.1); - - for (const Command& command: m_commands) { - m_stf_command_names.add(command.m_name); - } } // initCommands // ======================================================================== diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index a3d1415d4cc..7384187887a 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -74,6 +74,25 @@ class CommandManager m_cmd(cmd), m_user_permissions(user_permissions), m_voting(voting) {} }; + struct CommandDescription + { + std::string m_usage; + std::string m_permissions; + std::string m_description; + CommandDescription(std::string usage = "", std::string permissions = "", + std::string description = ""): m_usage(usage), + m_permissions(permissions), m_description(description) {} + + std::string getUsage() { return "Usage: " + m_usage; } + + std::string getHelp() + { + return "Usage: " + m_usage + + "\nAvailable to: " + m_permissions + + "\n" + m_description; + } + }; + struct Command { std::string m_name; @@ -84,24 +103,17 @@ class CommandManager int m_scope; - std::string m_usage; - - std::string m_description; - - std::string m_verbose_permissions; + CommandDescription m_description; Command() {} Command(std::string name, - void (CommandManager::*f)(Context& context), int permissions, int scope = CS_ALWAYS, - std::string usage = "", std::string verbose_permissions = "", std::string description = ""): - m_name(name), m_permissions(permissions), m_action(f), m_scope(scope), - m_usage(usage), m_description(description), - m_verbose_permissions(verbose_permissions) {} + void (CommandManager::*f)(Context& context), int permissions, int scope = CS_ALWAYS): + m_name(name), m_permissions(permissions), m_action(f), m_scope(scope) {} - std::string getUsage() { return "Usage: " + m_usage; } + std::string getUsage() { return m_description.getUsage(); } - std::string getHelp() { return "Usage: " + m_usage + "\nAvailable to: " + m_verbose_permissions + "\n" + m_description; } + std::string getHelp() { return m_description.getHelp(); } }; private: @@ -122,12 +134,15 @@ class CommandManager std::map> m_user_command_replacements; + std::map m_config_descriptions; + SetTypoFixer m_stf_command_names; SetTypoFixer m_stf_present_users; SetTypoFixer m_stf_maps; + void initCommandsInfo(); void initCommands(); int getCurrentScope(); From 2f8feed4ccd53a34431cf7c70b863f81eb8e55fb Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 1 Jan 2022 20:02:46 +0300 Subject: [PATCH 171/830] Small fix to make links installaddonable --- src/network/protocols/command_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index cd959c76456..f5a57cde8c0 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -746,7 +746,7 @@ void CommandManager::process_addons(Context& context) response += ". More addons to install:"; for (unsigned i = 0; i < result.size(); ++i) { - response += "\n/installaddon " + result[i].first.substr(6) + ", missing for " + response += "\n/installaddon " + result[i].first.substr(6) + " , missing for " + std::to_string(result[i].second.size()) + " player(s):"; std::sort(result[i].second.begin(), result[i].second.end()); From 929d1984642cd4aa6083c3793fac5abe052e8b06 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 2 Jan 2022 02:00:19 +0300 Subject: [PATCH 172/830] Try to avoid client spectator crash when a played track is not installed --- src/network/protocols/server_lobby.cpp | 8 +++++--- src/network/stk_peer.hpp | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3112644da40..c1871717f89 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1887,21 +1887,23 @@ void ServerLobby::asynchronousUpdate() if (ServerConfig::m_soccer_tournament) m_tournament_arenas[m_tournament_game] = track_name; auto peers = STKHost::get()->getPeers(); - std::set bad_spectators; + std::map, AlwaysSpectateMode> bad_spectators; for (auto peer : peers) { if (peer->alwaysSpectate() && peer->getClientAssets().second.count(track_name) == 0) { - // peer->setAlwaysSpectate(ASM_NONE); + bad_spectators[peer] = peer->getAlwaysSpectate(); + peer->setAlwaysSpectate(ASM_NONE); peer->setWaitingForGame(true); m_peers_ready.erase(peer); - bad_spectators.insert(peer.get()); } } bool has_always_on_spectators = false; auto players = STKHost::get() ->getPlayersForNewGame(&has_always_on_spectators); + for (auto& p: bad_spectators) + p.first->setAlwaysSpectate(p.second); auto ai_instance = m_ai_peer.lock(); if (supportsAI()) { diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index c7b0196c74e..b397734ba89 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -323,6 +323,9 @@ class STKPeer : public NoCopy bool alwaysSpectate() const { return m_always_spectate.load() != ASM_NONE; } // ------------------------------------------------------------------------ + AlwaysSpectateMode getAlwaysSpectate() const + { return (AlwaysSpectateMode)m_always_spectate.load(); } + // ------------------------------------------------------------------------ bool isCommandSpectator() const { return m_always_spectate.load() == ASM_COMMAND; } // ------------------------------------------------------------------------ From b6e67e393b83902da4c1c15c4a172d4755cbcdbc Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 2 Jan 2022 18:50:12 +0300 Subject: [PATCH 173/830] Remove unnecessary limitation on the number of players as there is already getSpectatorsByLimit --- src/network/protocols/server_lobby.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index c1871717f89..1d5d7ecc20b 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4312,18 +4312,8 @@ void ServerLobby::connectionRequested(Event* event) unsigned total_players = 0; STKHost::get()->updatePlayers(NULL, NULL, &total_players); - unsigned max_players_mode = (unsigned)ServerConfig::m_server_max_players; - if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_FREE_FOR_ALL) - max_players_mode = std::min(10, max_players_mode); - if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) - max_players_mode = std::min(14, max_players_mode); - if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_SOCCER && !ServerConfig::m_soccer_tournament) - max_players_mode = std::min(14, max_players_mode); if (total_players + player_count + m_ai_profiles.size() > - max_players_mode) + (unsigned)ServerConfig::m_server_max_players) { NetworkString *message = getNetworkString(2); message->setSynchronous(true); From 72fab553939feff921ee6214ccfbb7ccb8d3acb6 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 3 Jan 2022 01:46:12 +0300 Subject: [PATCH 174/830] Fix typo recognition case sensitiveness, try to fix typos in usernames of present players where applicable --- src/network/protocols/command_manager.cpp | 133 +++++++++++++++++----- src/network/protocols/command_manager.hpp | 10 +- src/utils/string_utils.cpp | 2 +- 3 files changed, 112 insertions(+), 33 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index f5a57cde8c0..62a56aca86c 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -264,51 +264,33 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) voting = true; action = "vote for"; } - for (int i = 1; i <= 5; ++i) { + bool restored = false; + for (int i = 0; i <= 5; ++i) { if (argv[0] == std::to_string(i)) { - if (i - 1 < (int)m_user_command_replacements[username].size()) { - cmd = m_user_command_replacements[username][i - 1]; + if (i < (int)m_user_command_replacements[username].size() && + !m_user_command_replacements[username][i].empty()) { + cmd = m_user_command_replacements[username][i]; argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); if (argv.size() == 0) return; CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + restored = true; break; } else { std::string msg = "Pick one of " + - std::to_string(m_user_command_replacements[username].size()) - + " options using /1, etc., or type a different command"; + std::to_string(-1 + (int)m_user_command_replacements[username].size()) + + " options using /1, etc., or use /0, or type a different command"; m_lobby->sendStringToPeer(msg, peer); return; } } } m_user_command_replacements.erase(username); + if (!restored) + m_user_correct_arguments.erase(username); - auto closest_commands = m_stf_command_names.getClosest(argv[0], 3, false); - if (closest_commands.empty()) - { - std::string msg = "Command " + argv[0] + " not found"; - m_lobby->sendStringToPeer(msg, peer); + if (hasTypo(peer, argv, cmd, 0, m_stf_command_names, 3, false, false)) return; - } - if (closest_commands[0].second != 0) - { - m_user_command_replacements[username].clear(); - std::string initial_command = argv[0]; - std::string response = "You invoked \"" + cmd + "\", but there is " - "no command \"" + initial_command + "\". Choose a fix or ignore:"; - - for (unsigned i = 0; i < closest_commands.size(); ++i) { - argv[0] = closest_commands[i].first; - CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); - m_user_command_replacements[username].push_back(cmd); - response += "\ntype /" + std::to_string(i + 1) + " to choose /" + argv[0]; - } - argv[0] = initial_command; - CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); - m_lobby->sendStringToPeer(response, peer); - return; - } auto command_iterator = m_name_to_command.find(argv[0]); @@ -956,6 +938,9 @@ void CommandManager::process_pha(Context& context) error(context); return; } + if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + 2, m_stf_present_users, 3, false, false)) + return; std::string addon_id = argv[1]; std::string player_name = argv[2]; @@ -1011,6 +996,11 @@ void CommandManager::process_kick(Context& context) error(context); return; } + + if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + 1, m_stf_present_users, 3, false, false)) + return; + std::string player_name = argv[1]; std::shared_ptr player_peer = STKHost::get()->findPeerByName( @@ -1105,6 +1095,11 @@ void CommandManager::process_pas(Context& context) error(context); return; } + + if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + 1, m_stf_present_users, 3, false, false)) + return; + player_name = argv[1]; std::shared_ptr player_peer = STKHost::get()->findPeerByName( StringUtils::utf8ToWide(player_name)); @@ -1180,6 +1175,10 @@ void CommandManager::process_mute(Context& context) return; } + if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + 1, m_stf_present_users, 3, false, false)) + return; + player_name = StringUtils::utf8ToWide(argv[1]); player_peer = STKHost::get()->findPeerByName(player_name); @@ -1398,6 +1397,9 @@ void CommandManager::process_to(Context& context) m_lobby->m_message_receivers[peer.get()].clear(); for (unsigned i = 1; i < argv.size(); ++i) { + if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + i, m_stf_present_users, 3, false, true)) + return; m_lobby->m_message_receivers[peer.get()].insert( StringUtils::utf8ToWide(argv[i])); } @@ -1761,6 +1763,9 @@ void CommandManager::process_cat(Context& context) return; } std::string category = argv[1]; + if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + 2, m_stf_present_users, 3, false, true)) + return; std::string player = argv[2]; m_lobby->m_player_categories[category].insert(player); m_lobby->m_categories_for_player[player].insert(category); @@ -1776,6 +1781,9 @@ void CommandManager::process_cat(Context& context) } std::string category = argv[1]; std::string player = argv[2]; + if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + 2, m_stf_present_users, 3, false, true)) + return; m_lobby->m_player_categories[category].erase(player); m_lobby->m_categories_for_player[player].erase(category); m_lobby->updatePlayerList(); @@ -2025,12 +2033,17 @@ void CommandManager::process_role(Context& context) error(context); return; } + if (argv[1].length() > argv[2].length()) + { + swap(argv[1], argv[2]); + } + if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + 2, m_stf_present_users, 3, false, true)) + return; std::string role = argv[1]; std::string username = argv[2]; bool permanent = (argv.size() >= 4 && (argv[3] == "p" || argv[3] == "permanent")); - if (role.length() != 1) - std::swap(role, username); if (role.length() != 1) { error(context); @@ -2336,6 +2349,7 @@ void CommandManager::special(Context& context) void CommandManager::addUser(std::string& s) { m_users.insert(s); + m_stf_present_users.add(s); update(); } // addUser // ======================================================================== @@ -2349,6 +2363,7 @@ void CommandManager::deleteUser(std::string& s) return; } m_users.erase(it); + m_stf_present_users.remove(s); update(); } // deleteUser // ======================================================================== @@ -2378,4 +2393,60 @@ void CommandManager::restoreCmdByArgv(std::string& cmd, std::vector } } } // restoreCmdByArgv +// ======================================================================== + +bool CommandManager::hasTypo(std::shared_ptr peer, + std::vector& argv, std::string& cmd, int idx, + SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is) +{ + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (idx < m_user_correct_arguments[username]) + return false; + auto closest_commands = stf.getClosest(argv[idx], top, case_sensitive); + if (closest_commands.empty()) + { + std::string msg = "Command " + cmd + " not found"; + m_lobby->sendStringToPeer(msg, peer); + return true; + } + if (closest_commands[0].second != 0 || (closest_commands[0].second == 0 + && closest_commands.size() > 1 && closest_commands[1].second == 0)) + { + m_user_command_replacements[username].clear(); + m_user_correct_arguments[username] = idx + 1; + std::string initial_argument = argv[idx]; + std::string response = ""; + if (idx == 0) + response += "There is no command \"" + argv[idx] + "\""; + else + response += "Argument \"" + argv[idx] + "\" may be invalid"; + + if (allow_as_is) + { + response += ". Type /0 to continue, or choose a fix:"; + m_user_command_replacements[username].push_back(cmd); + } + else + { + response += ". Choose a fix or ignore:"; + m_user_command_replacements[username].push_back(""); + } + for (unsigned i = 0; i < closest_commands.size(); ++i) { + argv[idx] = closest_commands[i].first; + CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + m_user_command_replacements[username].push_back(cmd); + response += "\ntype /" + std::to_string(i + 1) + " to choose \"" + argv[idx] + "\""; + } + argv[idx] = initial_argument; + CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + m_lobby->sendStringToPeer(response, peer); + return true; + } + + argv[idx] = closest_commands[0].first; // converts case or regex + CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + return false; + +} // hasTypo // ======================================================================== \ No newline at end of file diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 7384187887a..37d85a7b157 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -134,13 +134,17 @@ class CommandManager std::map> m_user_command_replacements; + std::map m_user_correct_arguments; + std::map m_config_descriptions; SetTypoFixer m_stf_command_names; SetTypoFixer m_stf_present_users; - SetTypoFixer m_stf_maps; + SetTypoFixer m_stf_all_maps; + + SetTypoFixer m_stf_addon_maps; void initCommandsInfo(); void initCommands(); @@ -225,6 +229,10 @@ class CommandManager void deleteUser(std::string& s); static void restoreCmdByArgv(std::string& cmd, std::vector& argv, char c, char d, char e, char f); + + bool hasTypo(std::shared_ptr peer, + std::vector& argv, std::string& cmd, int idx, + SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is); }; #endif // COMMAND_MANAGER_HPP \ No newline at end of file diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index c010423032f..bc717cd1589 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -1335,7 +1335,7 @@ namespace StringUtils { if (a == b) return true; - return case_sensitive && toupper(a) == toupper(b); + return !case_sensitive && toupper(a) == toupper(b); } // isEqual // ------------------------------------------------------------------------ int getEditDistance(const std::string& a, const std::string& b, From c96e7178fb465e99dffd16f07b3e44ef99897048 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 18 Jan 2022 18:14:57 +0300 Subject: [PATCH 175/830] Fix missing erase in uncastVote --- src/network/protocols/command_voting.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/command_voting.cpp b/src/network/protocols/command_voting.cpp index fe07b6f8bce..a99ccba7ad9 100644 --- a/src/network/protocols/command_voting.cpp +++ b/src/network/protocols/command_voting.cpp @@ -38,11 +38,13 @@ void CommandVoting::castVote(std::string player, std::string category, std::stri void CommandVoting::uncastVote(std::string player, std::string category) { + std::string previous_vote = ""; auto it = m_votes_by_player[player].find(category); if (it != m_votes_by_player[player].end()) { - std::string previous_vote = it->second; + previous_vote = it->second; m_votes_by_poll[category][previous_vote].erase(player); + m_votes_by_player[player].erase(it); } m_need_check = true; m_selected_category = ""; @@ -77,7 +79,9 @@ std::pair> CommandVoting::process(std::m for (const auto& q: category_results) { if (category == m_selected_category && q.first == m_selected_option) + { num_votes = q.second; + } if (q.second >= required_number) { result[category] = q.first; From cc4b51407451146f55112f14560dc2e0fff43ae7 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 19 Jan 2022 02:20:57 +0300 Subject: [PATCH 176/830] Preserve voting while fixing typos, don't fix typos when already voted, add wildcards to typo fixer --- src/network/protocols/command_manager.cpp | 25 ++++++++++++++--------- src/network/protocols/command_manager.hpp | 4 +++- src/utils/set_typo_fixer.cpp | 2 +- src/utils/string_utils.cpp | 10 ++++----- src/utils/string_utils.hpp | 2 +- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 62a56aca86c..c5fa5e00dbb 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -274,6 +274,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) if (argv.size() == 0) return; CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + voting = m_user_saved_voting[username]; restored = true; break; } else { @@ -289,7 +290,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) if (!restored) m_user_correct_arguments.erase(username); - if (hasTypo(peer, argv, cmd, 0, m_stf_command_names, 3, false, false)) + if (hasTypo(peer, voting, argv, cmd, 0, m_stf_command_names, 3, false, false)) return; auto command_iterator = m_name_to_command.find(argv[0]); @@ -938,7 +939,7 @@ void CommandManager::process_pha(Context& context) error(context); return; } - if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_present_users, 3, false, false)) return; @@ -997,7 +998,7 @@ void CommandManager::process_kick(Context& context) return; } - if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 1, m_stf_present_users, 3, false, false)) return; @@ -1096,7 +1097,7 @@ void CommandManager::process_pas(Context& context) return; } - if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 1, m_stf_present_users, 3, false, false)) return; @@ -1175,7 +1176,7 @@ void CommandManager::process_mute(Context& context) return; } - if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 1, m_stf_present_users, 3, false, false)) return; @@ -1397,7 +1398,7 @@ void CommandManager::process_to(Context& context) m_lobby->m_message_receivers[peer.get()].clear(); for (unsigned i = 1; i < argv.size(); ++i) { - if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, i, m_stf_present_users, 3, false, true)) return; m_lobby->m_message_receivers[peer.get()].insert( @@ -1763,7 +1764,7 @@ void CommandManager::process_cat(Context& context) return; } std::string category = argv[1]; - if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_present_users, 3, false, true)) return; std::string player = argv[2]; @@ -1781,7 +1782,7 @@ void CommandManager::process_cat(Context& context) } std::string category = argv[1]; std::string player = argv[2]; - if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_present_users, 3, false, true)) return; m_lobby->m_player_categories[category].erase(player); @@ -2037,7 +2038,7 @@ void CommandManager::process_role(Context& context) { swap(argv[1], argv[2]); } - if (hasTypo(context.m_peer, context.m_argv, context.m_cmd, + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_present_users, 3, false, true)) return; std::string role = argv[1]; @@ -2395,10 +2396,12 @@ void CommandManager::restoreCmdByArgv(std::string& cmd, std::vector } // restoreCmdByArgv // ======================================================================== -bool CommandManager::hasTypo(std::shared_ptr peer, +bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, std::vector& argv, std::string& cmd, int idx, SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is) { + if (!peer.get()) // voted + return false; std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); if (idx < m_user_correct_arguments[username]) @@ -2422,6 +2425,8 @@ bool CommandManager::hasTypo(std::shared_ptr peer, else response += "Argument \"" + argv[idx] + "\" may be invalid"; + m_user_saved_voting[username] = voting; + if (allow_as_is) { response += ". Type /0 to continue, or choose a fix:"; diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 37d85a7b157..2ad96b7c66c 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -134,6 +134,8 @@ class CommandManager std::map> m_user_command_replacements; + std::map m_user_saved_voting; + std::map m_user_correct_arguments; std::map m_config_descriptions; @@ -230,7 +232,7 @@ class CommandManager static void restoreCmdByArgv(std::string& cmd, std::vector& argv, char c, char d, char e, char f); - bool hasTypo(std::shared_ptr peer, + bool hasTypo(std::shared_ptr peer, bool voting, std::vector& argv, std::string& cmd, int idx, SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is); }; diff --git a/src/utils/set_typo_fixer.cpp b/src/utils/set_typo_fixer.cpp index 07e3ad28dda..c8d58640008 100644 --- a/src/utils/set_typo_fixer.cpp +++ b/src/utils/set_typo_fixer.cpp @@ -47,7 +47,7 @@ std::vector> SetTypoFixer::getClosest( for (const std::string& s: m_set) { int distance = StringUtils::getEditDistance(s, - query_ref, case_sensitive); + query_ref, case_sensitive, '*'); ans.emplace_back(s, distance); } diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index bc717cd1589..332db156e3d 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -1339,7 +1339,7 @@ namespace StringUtils } // isEqual // ------------------------------------------------------------------------ int getEditDistance(const std::string& a, const std::string& b, - bool case_sensitive) + bool case_sensitive, char wildcard) { int n = a.length(); int m = b.length(); @@ -1350,15 +1350,15 @@ namespace StringUtils for (int j = 0; j <= m; ++j) { if (i < n) { distance[i + 1][j] = std::min(distance[i + 1][j], - distance[i][j] + 1); + distance[i][j] + (j < m && b[j] == wildcard ? 0 : 1)); } if (j < m) { distance[i][j + 1] = std::min(distance[i][j + 1], - distance[i][j] + 1); + distance[i][j] + (i < n && a[i] == wildcard ? 0 : 1)); } if (i < n && j < m) { - int value = distance[i][j] + (isEqual(a[i], b[j], - case_sensitive) ? 0 : 1); + int value = distance[i][j] + ((isEqual(a[i], b[j], + case_sensitive) || a[i] == wildcard || b[j] == wildcard) ? 0 : 1); distance[i + 1][j + 1] = std::min( distance[i + 1][j + 1], value); } diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index 84b643ae17b..5e915eb7c14 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -339,7 +339,7 @@ namespace StringUtils // ------------------------------------------------------------------------ bool isEqual(char a, char b, bool case_sensitive = true); int getEditDistance(const std::string& a, const std::string& b, - bool case_sensitive = true); + bool case_sensitive = true, char wildcard = 0); } // namespace StringUtils From 8a2b13ed349ebe8d3f61903843e49d5460b5f82b Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 19 Jan 2022 03:47:20 +0300 Subject: [PATCH 177/830] Remove m_available_commands, add /description --- data/commands.xml | 5 +++++ src/network/protocols/command_manager.cpp | 3 +++ src/network/protocols/server_lobby.cpp | 7 ------- src/network/protocols/server_lobby.hpp | 2 -- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index a0fa9f79a15..d23259e2adc 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -96,6 +96,11 @@ permissions="everyone" description="Lists players whom you blocked using /mute command." /> + m_help_message)); addTextResponse("version", "1.3-rc1 k 210fff beta"); addTextResponse("clear", std::string(30, '\n')); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 1d5d7ecc20b..606b3b0872c 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -217,13 +217,6 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_command_manager = CommandManager(nullptr); - m_available_commands = "admin ban commands config game gnu go help init " - "installaddon kick kickban listlocaladdon listserveraddon " - "liststkaddon lobby nognu play playeraddonscore playerhasaddon " - "power public record register replay resume role serverhasaddon " - "spectate standings start stop teamchat tell to token unban " - "uninstalladdon version"; - m_team_name_to_index = { {"red", 1}, {"r", 1}, {StringUtils::utf32ToUtf8({0x1f7e5}), -1}, {"orange", 2}, {"o", 2}, {StringUtils::utf32ToUtf8({0x1f7e7}), -2}, diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 8cfd95c1009..6574e535959 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -303,8 +303,6 @@ class ServerLobby : public LobbyProtocol irr::core::stringw m_help_message; - std::string m_available_commands; - std::map> m_message_receivers; std::set m_team_speakers; From 64e7cfea3c165893a98369c1eaaddb530b47e785 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 19 Jan 2022 12:49:48 +0300 Subject: [PATCH 178/830] Add /getaddons --- data/commands.xml | 5 +++++ src/network/protocols/command_manager.cpp | 25 ++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/data/commands.xml b/data/commands.xml index d23259e2adc..f2e8b94b770 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -36,6 +36,11 @@ permissions="everyone" description="Lists top 5 addons that are missing for at least one player, sorted by the number of players that don’t have the addon ascending, random for equal number of players. Limits the list to a certain addon type if specified." /> + 0) { response = "Found " + std::to_string(all_have.size()) + " asset(s)"; std::reverse(result.begin(), result.end()); + if (more_own) + { + auto result2 = result; + result.clear(); + std::string asking_username = StringUtils::wideToUtf8( + context.m_peer->getPlayerProfiles()[0]->getName()); + for (int i = 0; i < result2.size(); ++i) + { + bool present = false; + for (int j = 0; j < result2[i].second.size(); ++j) + { + if (result2[i].second[j] == asking_username) + { + present = true; + break; + } + } + if (present) + result.push_back(result2[i]); + } + } if (result.size() > NEXT_ADDONS) result.resize(NEXT_ADDONS); - if (!more) + if (!more && !more_own) { bool nothing = true; for (const std::string& s: all_have) From 160bb8e7419c16fe6f92baff0fe300dc51ea48f5 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 19 Jan 2022 15:46:55 +0300 Subject: [PATCH 179/830] Add file commands, including with updates --- src/network/protocols/command_manager.cpp | 84 +++++++++++++++++++++++ src/network/protocols/command_manager.hpp | 23 ++++++- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 5157395b950..9712d63d4f4 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -58,6 +58,7 @@ // #include "tracks/check_manager.hpp" // #include "tracks/track.hpp" // #include "tracks/track_manager.hpp" +#include "utils/file_utils.hpp" #include "utils/log.hpp" #include "utils/random_generator.hpp" #include "utils/string_utils.hpp" @@ -73,6 +74,51 @@ // ======================================================================== + +CommandManager::FileResource::FileResource(std::string file_name, uint64_t interval) +{ + m_file_name = file_name; + m_interval = interval; + m_contents = ""; + m_last_invoked = 0; + read(); +} // FileResource::FileResource +// ======================================================================== + +void CommandManager::FileResource::read() +{ + if (m_file_name.empty()) // in case it is not properly initialized + return; + // idk what to do with absolute or relative paths + const std::string& path = /*ServerConfig::getConfigDirectory() + "/" + */m_file_name; + std::ifstream message(FileUtils::getPortableReadingPath(path)); + std::string answer = ""; + if (message.is_open()) + { + for (std::string line; std::getline(message, line); ) + { + answer += line; + answer.push_back('\n'); + } + if (!answer.empty()) + answer.pop_back(); + } + m_contents = answer; + m_last_invoked = StkTime::getMonoTimeMs(); +} // FileResource::read +// ======================================================================== + +std::string CommandManager::FileResource::get() +{ + uint64_t current_time = StkTime::getMonoTimeMs(); + if (m_interval == 0 || current_time < m_interval + m_last_invoked) + return m_contents; + read(); + return m_contents; +} // FileResource::get +// ======================================================================== + + void CommandManager::initCommandsInfo() { const std::string file_name = file_manager->getAsset("commands.xml"); @@ -102,10 +148,35 @@ void CommandManager::initCommandsInfo() { std::string name = ""; std::string text = ""; + std::string usage = ""; + std::string permissions = ""; + std::string description = ""; node->get("name", &name); node->get("text", &text); m_commands.emplace_back(name, &CommandManager::process_text, UP_EVERYONE, CS_ALWAYS); addTextResponse(name, text); + node->get("usage", &usage); + node->get("permissions", &permissions); + node->get("description", &description); + m_config_descriptions[name] = CommandDescription(usage, permissions, description); + } + else if (node_name == "file-command") + { + std::string name = ""; + std::string file = ""; + std::string usage = ""; + std::string permissions = ""; + std::string description = ""; + uint64_t interval = 0; + node->get("name", &name); + node->get("file", &file); + node->get("interval", &interval); + m_commands.emplace_back(name, &CommandManager::process_file, UP_EVERYONE, CS_ALWAYS); + addFileResource(name, file, interval); + node->get("usage", &usage); + node->get("permissions", &permissions); + node->get("description", &description); + m_config_descriptions[name] = CommandDescription(usage, permissions, description); } } } // initCommandsInfo @@ -452,6 +523,19 @@ void CommandManager::process_text(Context& context) } // process_text // ======================================================================== +void CommandManager::process_file(Context& context) +{ + std::string response; + auto it = m_file_resources.find(context.m_argv[0]); + if (it == m_file_resources.end()) + response = "Error: file not found for a file command " + + context.m_argv[0]; + else + response = it->second.get(); + m_lobby->sendStringToPeer(response, context.m_peer); +} // process_text +// ======================================================================== + void CommandManager::process_commands(Context& context) { std::string result = "Available commands:"; diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 2ad96b7c66c..a69bf1f7128 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -47,7 +47,22 @@ class STKPeer; class CommandManager { - enum CommandScope: int { + struct FileResource + { + std::string m_file_name; + uint64_t m_interval; + uint64_t m_last_invoked; + std::string m_contents; + + FileResource(std::string file_name = "", uint64_t interval = 0); + + void read(); + + std::string get(); + }; + + enum CommandScope: int + { CS_ALWAYS = 1, CS_SOCCER_TOURNAMENT = 2 // add more powers of two if needed @@ -128,6 +143,8 @@ class CommandManager std::map m_text_response; + std::map m_file_resources; + std::map m_votables; std::queue m_triggered_votables; @@ -161,6 +178,7 @@ class CommandManager void process_help(Context& context); void process_text(Context& context); + void process_file(Context& context); void process_commands(Context& context); void process_replay(Context& context); void process_start(Context& context); @@ -226,6 +244,9 @@ class CommandManager void addTextResponse(std::string key, T&& value) { m_text_response[key] = value; } + void addFileResource(std::string key, std::string file, uint64_t interval) + { m_file_resources[key] = FileResource(file, interval); } + void addUser(std::string& s); void deleteUser(std::string& s); From 802e1164018753fef2e8b6f9c9b343ad982a7b1e Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 21 Jan 2022 02:40:11 +0300 Subject: [PATCH 180/830] Allow to set a command only for certain servers / forbid it on certain servers --- src/network/protocols/command_manager.cpp | 66 +++++++++++++---------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 9712d63d4f4..17779ae3495 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -132,50 +132,62 @@ void CommandManager::initCommandsInfo() { const XMLNode *node = root->getNode(i); std::string node_name = node->getName(); + // here the commands go + std::string name = ""; + std::string text = ""; // for text-command + std::string file = ""; // for file-command + uint64_t interval = 0; // for file-command + std::string usage = ""; + std::string permissions = ""; + std::string description = ""; + // If enabled is not empty, command is added iff the server name is in enabled + // Otherwise it is added iff the server name is not in disabled + std::string enabled = ""; + std::string disabled = ""; + node->get("enabled", &enabled); + node->get("disabled", &disabled); + std::vector enabled_split = StringUtils::split(enabled, ' '); + std::vector disabled_split = StringUtils::split(disabled, ' '); + bool ok; + if (!enabled.empty()) + { + ok = false; + for (const std::string& s: enabled_split) + if (s == ServerConfig::m_server_uid) + ok = true; + } + else + { + ok = true; + for (const std::string& s: disabled_split) + if (s == ServerConfig::m_server_uid) + ok = false; + } + if (!ok) + continue; + + node->get("name", &name); + node->get("usage", &usage); + node->get("permissions", &permissions); + node->get("description", &description); + if (node_name == "command") { - std::string name = ""; - std::string usage = ""; - std::string permissions = ""; - std::string description = ""; - node->get("name", &name); - node->get("usage", &usage); - node->get("permissions", &permissions); - node->get("description", &description); m_config_descriptions[name] = CommandDescription(usage, permissions, description); } else if (node_name == "text-command") { - std::string name = ""; - std::string text = ""; - std::string usage = ""; - std::string permissions = ""; - std::string description = ""; - node->get("name", &name); node->get("text", &text); m_commands.emplace_back(name, &CommandManager::process_text, UP_EVERYONE, CS_ALWAYS); addTextResponse(name, text); - node->get("usage", &usage); - node->get("permissions", &permissions); - node->get("description", &description); m_config_descriptions[name] = CommandDescription(usage, permissions, description); } else if (node_name == "file-command") { - std::string name = ""; - std::string file = ""; - std::string usage = ""; - std::string permissions = ""; - std::string description = ""; - uint64_t interval = 0; - node->get("name", &name); node->get("file", &file); node->get("interval", &interval); m_commands.emplace_back(name, &CommandManager::process_file, UP_EVERYONE, CS_ALWAYS); addFileResource(name, file, interval); - node->get("usage", &usage); - node->get("permissions", &permissions); - node->get("description", &description); m_config_descriptions[name] = CommandDescription(usage, permissions, description); } } From 3016c93a2c8cd81f20c73a883728e2a75914f3c4 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 27 Jan 2022 02:40:20 +0300 Subject: [PATCH 181/830] Make sure context parts are the same everywhere, which fixes voting+wildcard --- src/network/protocols/command_manager.cpp | 15 ++++++++++----- src/network/protocols/command_manager.hpp | 4 ++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 17779ae3495..0d75fd804be 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -323,15 +323,21 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) NetworkString& data = event->data(); std::string language; data.decodeString(&language); - std::string cmd; + + Context context(event, peer); + auto& argv = context.m_argv; + auto& cmd = context.m_cmd; + auto& permissions = context.m_user_permissions; + auto& voting = context.m_voting; + data.decodeString(&cmd); - auto argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); + argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); if (argv.size() == 0) return; CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); - int permissions = m_lobby->getPermissions(peer); - bool voting = false; + permissions = m_lobby->getPermissions(peer); + voting = false; std::string action = "invoke"; std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); @@ -401,7 +407,6 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) if (mask != PE_NONE && mask_without_voting == PE_NONE) voting = true; - Context context(event, peer, argv, cmd, permissions, voting); (this->*command.m_action)(context); while (!m_triggered_votables.empty()) diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index a69bf1f7128..e5dd2f6a6cd 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -82,6 +82,10 @@ class CommandManager bool m_voting; + Context(Event* event, std::shared_ptr peer): + m_event(event), m_peer(peer), m_argv(), + m_cmd(""), m_user_permissions(0), m_voting(false) {} + Context(Event* event, std::shared_ptr peer, std::vector& argv, std::string& cmd, int user_permissions, bool voting): From 77a9f84626053e394549bf0767d104c47eaa1d52 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 27 Jan 2022 05:06:07 +0300 Subject: [PATCH 182/830] Don't invoke most commands when we are not in the lobby, fix command manager leaks --- src/network/protocols/command_manager.cpp | 204 +++++++++++++--------- src/network/protocols/command_manager.hpp | 30 +++- src/network/protocols/command_voting.cpp | 8 + src/network/protocols/command_voting.hpp | 4 +- src/network/protocols/server_lobby.cpp | 5 +- 5 files changed, 155 insertions(+), 96 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 0d75fd804be..16f1caba92d 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -178,7 +178,7 @@ void CommandManager::initCommandsInfo() else if (node_name == "text-command") { node->get("text", &text); - m_commands.emplace_back(name, &CommandManager::process_text, UP_EVERYONE, CS_ALWAYS); + m_commands.emplace_back(name, &CommandManager::process_text, UP_EVERYONE, MS_DEFAULT); addTextResponse(name, text); m_config_descriptions[name] = CommandDescription(usage, permissions, description); } @@ -186,11 +186,12 @@ void CommandManager::initCommandsInfo() { node->get("file", &file); node->get("interval", &interval); - m_commands.emplace_back(name, &CommandManager::process_file, UP_EVERYONE, CS_ALWAYS); + m_commands.emplace_back(name, &CommandManager::process_file, UP_EVERYONE, MS_DEFAULT); addFileResource(name, file, interval); m_config_descriptions[name] = CommandDescription(usage, permissions, description); } } + delete root; } // initCommandsInfo // ======================================================================== @@ -200,87 +201,86 @@ void CommandManager::initCommands() using CM = CommandManager; auto kick_permissions = ((ServerConfig::m_kicks_allowed ? UP_CROWNED : UP_HAMMER) | PE_VOTED); auto& v = m_commands; - v.emplace_back("commands", &CM::process_commands, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("replay", &CM::process_replay, UP_SINGLE, CS_ALWAYS); - v.emplace_back("start", &CM::process_start, UP_EVERYONE | PE_VOTED, CS_ALWAYS); - if (ServerConfig::m_server_configurable) - { - v.emplace_back("config", &CM::process_config, UP_CROWNED | PE_VOTED, CS_ALWAYS); - } - v.emplace_back("spectate", &CM::process_spectate, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("addons", &CM::process_addons, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("moreaddons", &CM::process_addons, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("getaddons", &CM::process_addons, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("checkaddon", &CM::process_checkaddon, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("listserveraddon", &CM::process_lsa, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("playerhasaddon", &CM::process_pha, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("kick", &CM::process_kick, kick_permissions, CS_ALWAYS); - v.emplace_back("kickban", &CM::process_kick, UP_HAMMER | PE_VOTED, CS_ALWAYS); - v.emplace_back("unban", &CM::process_unban, UP_HAMMER, CS_ALWAYS); - v.emplace_back("ban", &CM::process_ban, UP_HAMMER, CS_ALWAYS); - v.emplace_back("playeraddonscore", &CM::process_pas, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("serverhasaddon", &CM::process_sha, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("mute", &CM::process_mute, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("unmute", &CM::process_unmute, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("listmute", &CM::process_listmute, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("description", &CM::process_text, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("moreinfo", &CM::process_text, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("gnu", &CM::process_gnu, UP_HAMMER | PE_VOTED, CS_ALWAYS); - v.emplace_back("nognu", &CM::process_gnu, UP_HAMMER | PE_VOTED, CS_ALWAYS); - v.emplace_back("tell", &CM::process_tell, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("standings", &CM::process_standings, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("teamchat", &CM::process_teamchat, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("to", &CM::process_to, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("public", &CM::process_public, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("record", &CM::process_record, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("power", &CM::process_power, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("length", &CM::process_length, UP_SINGLE, CS_ALWAYS); - v.emplace_back("queue", &CM::process_queue, UP_SINGLE, CS_ALWAYS); - v.emplace_back("adminstart", &CM::process_adminstart, UP_HAMMER, CS_ALWAYS); - v.emplace_back("shuffle", &CM::process_shuffle, UP_HAMMER, CS_ALWAYS); - v.emplace_back("timeout", &CM::process_timeout, UP_HAMMER, CS_ALWAYS); - v.emplace_back("team", &CM::process_team, UP_HAMMER, CS_ALWAYS); - v.emplace_back("cat+", &CM::process_cat, UP_HAMMER, CS_ALWAYS); - v.emplace_back("cat-", &CM::process_cat, UP_HAMMER, CS_ALWAYS); - v.emplace_back("cat*", &CM::process_cat, UP_HAMMER, CS_ALWAYS); - v.emplace_back("troll", &CM::process_troll, UP_HAMMER, CS_ALWAYS); - v.emplace_back("hitmsg", &CM::process_hitmsg, UP_HAMMER, CS_ALWAYS); - v.emplace_back("teamhit", &CM::process_teamhit, UP_HAMMER, CS_ALWAYS); - v.emplace_back("version", &CM::process_text, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("clear", &CM::process_text, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("register", &CM::process_register, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("commands", &CM::process_commands, UP_EVERYONE); + v.emplace_back("replay", &CM::process_replay, UP_SINGLE); + v.emplace_back("start", &CM::process_start, UP_EVERYONE | PE_VOTED, MS_DEFAULT, SS_LOBBY); + if (ServerConfig::m_server_configurable) { + v.emplace_back("config", &CM::process_config, UP_CROWNED | PE_VOTED, MS_DEFAULT, SS_LOBBY); + } + v.emplace_back("spectate", &CM::process_spectate, UP_EVERYONE); + v.emplace_back("addons", &CM::process_addons, UP_EVERYONE); + v.emplace_back("moreaddons", &CM::process_addons, UP_EVERYONE); + v.emplace_back("getaddons", &CM::process_addons, UP_EVERYONE); + v.emplace_back("checkaddon", &CM::process_checkaddon, UP_EVERYONE); + v.emplace_back("listserveraddon", &CM::process_lsa, UP_EVERYONE); + v.emplace_back("playerhasaddon", &CM::process_pha, UP_EVERYONE); + v.emplace_back("kick", &CM::process_kick, kick_permissions); + v.emplace_back("kickban", &CM::process_kick, UP_HAMMER | PE_VOTED); + v.emplace_back("unban", &CM::process_unban, UP_HAMMER); + v.emplace_back("ban", &CM::process_ban, UP_HAMMER); + v.emplace_back("playeraddonscore", &CM::process_pas, UP_EVERYONE); + v.emplace_back("serverhasaddon", &CM::process_sha, UP_EVERYONE); + v.emplace_back("mute", &CM::process_mute, UP_EVERYONE); + v.emplace_back("unmute", &CM::process_unmute, UP_EVERYONE); + v.emplace_back("listmute", &CM::process_listmute, UP_EVERYONE); + v.emplace_back("description", &CM::process_text, UP_EVERYONE); + v.emplace_back("moreinfo", &CM::process_text, UP_EVERYONE); + v.emplace_back("gnu", &CM::process_gnu, UP_HAMMER | PE_VOTED, MS_DEFAULT, SS_LOBBY); + v.emplace_back("nognu", &CM::process_gnu, UP_HAMMER | PE_VOTED, MS_DEFAULT, SS_LOBBY); + v.emplace_back("tell", &CM::process_tell, UP_EVERYONE); + v.emplace_back("standings", &CM::process_standings, UP_EVERYONE); + v.emplace_back("teamchat", &CM::process_teamchat, UP_EVERYONE); + v.emplace_back("to", &CM::process_to, UP_EVERYONE); + v.emplace_back("public", &CM::process_public, UP_EVERYONE); + v.emplace_back("record", &CM::process_record, UP_EVERYONE); + v.emplace_back("power", &CM::process_power, UP_EVERYONE); + v.emplace_back("length", &CM::process_length, UP_SINGLE); + v.emplace_back("queue", &CM::process_queue, UP_SINGLE); + v.emplace_back("adminstart", &CM::process_adminstart, UP_HAMMER); + v.emplace_back("shuffle", &CM::process_shuffle, UP_HAMMER); + v.emplace_back("timeout", &CM::process_timeout, UP_HAMMER); + v.emplace_back("team", &CM::process_team, UP_HAMMER); + v.emplace_back("cat+", &CM::process_cat, UP_HAMMER); + v.emplace_back("cat-", &CM::process_cat, UP_HAMMER); + v.emplace_back("cat*", &CM::process_cat, UP_HAMMER); + v.emplace_back("troll", &CM::process_troll, UP_HAMMER); + v.emplace_back("hitmsg", &CM::process_hitmsg, UP_HAMMER); + v.emplace_back("teamhit", &CM::process_teamhit, UP_HAMMER); + v.emplace_back("version", &CM::process_text, UP_EVERYONE); + v.emplace_back("clear", &CM::process_text, UP_EVERYONE); + v.emplace_back("register", &CM::process_register, UP_EVERYONE); #ifdef ENABLE_WEB_SUPPORT - v.emplace_back("token", &CM::process_token, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("token", &CM::process_token, UP_EVERYONE); #endif - v.emplace_back("muteall", &CM::process_muteall, UP_EVERYONE, CS_SOCCER_TOURNAMENT); - v.emplace_back("game", &CM::process_game, UP_HAMMER, CS_SOCCER_TOURNAMENT); - v.emplace_back("role", &CM::process_role, UP_HAMMER, CS_SOCCER_TOURNAMENT); - v.emplace_back("stop", &CM::process_stop, UP_HAMMER, CS_SOCCER_TOURNAMENT); - v.emplace_back("go", &CM::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT); - v.emplace_back("play", &CM::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT); - v.emplace_back("resume", &CM::process_go, UP_HAMMER, CS_SOCCER_TOURNAMENT); - v.emplace_back("lobby", &CM::process_lobby, UP_HAMMER, CS_SOCCER_TOURNAMENT); - v.emplace_back("init", &CM::process_init, UP_HAMMER, CS_SOCCER_TOURNAMENT); - v.emplace_back("vote", &CM::special, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("mimiz", &CM::process_mimiz, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("test", &CM::process_test, UP_EVERYONE | PE_VOTED, CS_ALWAYS); - v.emplace_back("help", &CM::process_help, UP_EVERYONE, CS_ALWAYS); - // v.emplace_back("1", &CM::special, UP_EVERYONE, CS_ALWAYS); - // v.emplace_back("2", &CM::special, UP_EVERYONE, CS_ALWAYS); - // v.emplace_back("3", &CM::special, UP_EVERYONE, CS_ALWAYS); - // v.emplace_back("4", &CM::special, UP_EVERYONE, CS_ALWAYS); - // v.emplace_back("5", &CM::special, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("slots", &CM::process_slots, UP_HAMMER | PE_VOTED, CS_ALWAYS); - v.emplace_back("time", &CM::process_time, UP_EVERYONE, CS_ALWAYS); - - v.emplace_back("addondownloadprogress", &CM::special, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("stopaddondownload", &CM::special, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("installaddon", &CM::special, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("uninstalladdon", &CM::special, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("music", &CM::special, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("addonrevision", &CM::special, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("liststkaddon", &CM::special, UP_EVERYONE, CS_ALWAYS); - v.emplace_back("listlocaladdon", &CM::special, UP_EVERYONE, CS_ALWAYS); + v.emplace_back("muteall", &CM::process_muteall, UP_EVERYONE, MS_SOCCER_TOURNAMENT); + v.emplace_back("game", &CM::process_game, UP_HAMMER, MS_SOCCER_TOURNAMENT); + v.emplace_back("role", &CM::process_role, UP_HAMMER, MS_SOCCER_TOURNAMENT); + v.emplace_back("stop", &CM::process_stop, UP_HAMMER, MS_SOCCER_TOURNAMENT); + v.emplace_back("go", &CM::process_go, UP_HAMMER, MS_SOCCER_TOURNAMENT); + v.emplace_back("play", &CM::process_go, UP_HAMMER, MS_SOCCER_TOURNAMENT); + v.emplace_back("resume", &CM::process_go, UP_HAMMER, MS_SOCCER_TOURNAMENT); + v.emplace_back("lobby", &CM::process_lobby, UP_HAMMER, MS_SOCCER_TOURNAMENT); + v.emplace_back("init", &CM::process_init, UP_HAMMER, MS_SOCCER_TOURNAMENT); + v.emplace_back("vote", &CM::special, UP_EVERYONE); + v.emplace_back("mimiz", &CM::process_mimiz, UP_EVERYONE); + v.emplace_back("test", &CM::process_test, UP_EVERYONE | PE_VOTED); + v.emplace_back("help", &CM::process_help, UP_EVERYONE); +// v.emplace_back("1", &CM::special, UP_EVERYONE, MS_DEFAULT); +// v.emplace_back("2", &CM::special, UP_EVERYONE, MS_DEFAULT); +// v.emplace_back("3", &CM::special, UP_EVERYONE, MS_DEFAULT); +// v.emplace_back("4", &CM::special, UP_EVERYONE, MS_DEFAULT); +// v.emplace_back("5", &CM::special, UP_EVERYONE, MS_DEFAULT); + v.emplace_back("slots", &CM::process_slots, UP_HAMMER | PE_VOTED, MS_DEFAULT, SS_LOBBY); + v.emplace_back("time", &CM::process_time, UP_EVERYONE); + + v.emplace_back("addondownloadprogress", &CM::special, UP_EVERYONE); + v.emplace_back("stopaddondownload", &CM::special, UP_EVERYONE); + v.emplace_back("installaddon", &CM::special, UP_EVERYONE); + v.emplace_back("uninstalladdon", &CM::special, UP_EVERYONE); + v.emplace_back("music", &CM::special, UP_EVERYONE); + v.emplace_back("addonrevision", &CM::special, UP_EVERYONE); + v.emplace_back("liststkaddon", &CM::special, UP_EVERYONE); + v.emplace_back("listlocaladdon", &CM::special, UP_EVERYONE); addTextResponse("description", ServerConfig::m_motd); @@ -305,6 +305,7 @@ void CommandManager::initCommands() m_votables.emplace("kick", 0.81); m_votables.emplace("kickban", 0.81); m_votables.emplace("gnu", 0.81); + m_votables.emplace("slots", CommandVoting::DEFAULT_THRESHOLD); m_votables["gnu"].setCustomThreshold("gnu kart", 1.1); } // initCommands // ======================================================================== @@ -440,19 +441,32 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) } // handleCommand // ======================================================================== -int CommandManager::getCurrentScope() +int CommandManager::getCurrentModeScope() { - int mask = CS_ALWAYS; + int mask = MS_DEFAULT; if (ServerConfig::m_soccer_tournament) - mask |= CS_SOCCER_TOURNAMENT; + mask |= MS_SOCCER_TOURNAMENT; return mask; -} // getCurrentScope +} // getCurrentModeScope +// ======================================================================== + +int CommandManager::getCurrentStateScope() +{ + auto state = m_lobby->m_state.load(); + if (state < ServerLobby::WAITING_FOR_START_GAME + || state > ServerLobby::RESULT_DISPLAY) + return 0; + if (state == ServerLobby::WAITING_FOR_START_GAME) + return SS_LOBBY; + return SS_INGAME; +} // getCurrentStateScope // ======================================================================== bool CommandManager::isAvailable(const Command& c) { - return (getCurrentScope() & c.m_scope) != 0; -} // getCurrentScope + return (getCurrentModeScope() & c.m_mode_scope) != 0 + && (getCurrentStateScope() & c.m_state_scope) != 0; +} // getCurrentModeScope // ======================================================================== void CommandManager::vote(Context& context, std::string category, std::string value) @@ -2581,4 +2595,20 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, return false; } // hasTypo +// ======================================================================== + +void CommandManager::onResetServer() +{ + update(); +} // onResetServer +// ======================================================================== + +void CommandManager::onStartSelection() +{ + m_votables["start"].resetAllVotes(); + m_votables["config"].resetAllVotes(); + m_votables["gnu"].resetAllVotes(); + m_votables["slots"].resetAllVotes(); + update(); +} // onStartSelection // ======================================================================== \ No newline at end of file diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index e5dd2f6a6cd..296d3a9173d 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -61,13 +61,20 @@ class CommandManager std::string get(); }; - enum CommandScope: int + enum ModeScope: int { - CS_ALWAYS = 1, - CS_SOCCER_TOURNAMENT = 2 + MS_DEFAULT = 1, + MS_SOCCER_TOURNAMENT = 2 // add more powers of two if needed }; + enum StateScope: int + { + SS_LOBBY = 1, + SS_INGAME = 2, + SS_ALWAYS = SS_LOBBY | SS_INGAME + }; + struct Context { Event* m_event; @@ -120,15 +127,19 @@ class CommandManager void (CommandManager::*m_action)(Context& context); - int m_scope; + int m_mode_scope; + + int m_state_scope; CommandDescription m_description; Command() {} Command(std::string name, - void (CommandManager::*f)(Context& context), int permissions, int scope = CS_ALWAYS): - m_name(name), m_permissions(permissions), m_action(f), m_scope(scope) {} + void (CommandManager::*f)(Context& context), int permissions, + int mode_scope = MS_DEFAULT, int state_scope = SS_ALWAYS): + m_name(name), m_permissions(permissions), m_action(f), + m_mode_scope(mode_scope), m_state_scope(state_scope) {} std::string getUsage() { return m_description.getUsage(); } @@ -172,7 +183,8 @@ class CommandManager void initCommandsInfo(); void initCommands(); - int getCurrentScope(); + int getCurrentModeScope(); + int getCurrentStateScope(); bool isAvailable(const Command& c); @@ -260,6 +272,10 @@ class CommandManager bool hasTypo(std::shared_ptr peer, bool voting, std::vector& argv, std::string& cmd, int idx, SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is); + + void onResetServer(); + + void onStartSelection(); }; #endif // COMMAND_MANAGER_HPP \ No newline at end of file diff --git a/src/network/protocols/command_voting.cpp b/src/network/protocols/command_voting.cpp index a99ccba7ad9..25ea40cc000 100644 --- a/src/network/protocols/command_voting.cpp +++ b/src/network/protocols/command_voting.cpp @@ -19,6 +19,8 @@ #include "network/protocols/command_voting.hpp" #include "utils/random_generator.hpp" +const double CommandVoting::DEFAULT_THRESHOLD = 0.500001; + CommandVoting::CommandVoting(double threshold): m_threshold(threshold) { @@ -143,3 +145,9 @@ void CommandVoting::reset(std::string category) } // reset // ======================================================================== +void CommandVoting::resetAllVotes() +{ + m_votes_by_poll.clear(); + m_votes_by_player.clear(); +} // resetAllVotes +// ======================================================================== diff --git a/src/network/protocols/command_voting.hpp b/src/network/protocols/command_voting.hpp index 11bb4dbe31e..455373f3c83 100644 --- a/src/network/protocols/command_voting.hpp +++ b/src/network/protocols/command_voting.hpp @@ -42,7 +42,8 @@ class CommandVoting std::map> m_votes_by_player; std::map m_custom_thresholds; public: - CommandVoting(double threshold = 0.500001); + static const double DEFAULT_THRESHOLD; + CommandVoting(double threshold = DEFAULT_THRESHOLD); void setCustomThreshold(std::string category, double value) { m_custom_thresholds[category] = value; } void resetCustomThreshold(std::string category) @@ -53,6 +54,7 @@ class CommandVoting std::pair> process(std::multiset& all_users); std::string getAnyBest(std::string category); void reset(std::string category); + void resetAllVotes(); }; #endif // COMMAND_VOTING_HPP \ No newline at end of file diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 606b3b0872c..323ce20c045 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -845,6 +845,7 @@ void ServerLobby::setup() resetPeersReady(); m_timeout.store(std::numeric_limits::max()); m_server_started_at = m_server_delay = 0; + getCommandManager().onResetServer(); Log::info("ServerLobby", "Resetting the server to its initial state."); } // setup @@ -2816,7 +2817,7 @@ void ServerLobby::startSelection(const Event *event) bool need_to_update = false; if (event != NULL) { - if (m_state != WAITING_FOR_START_GAME) + if (m_state.load() != WAITING_FOR_START_GAME) { Log::warn("ServerLobby", "Received startSelection while being in state %d.", @@ -3243,6 +3244,8 @@ void ServerLobby::startSelection(const Event *event) m_gp_scores.clear(); m_gp_team_scores.clear(); } + + getCommandManager().onStartSelection(); } // startSelection //----------------------------------------------------------------------------- From 16f6307b800bc8e34d9df18fca51cc968979f224 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 27 Jan 2022 16:38:25 +0300 Subject: [PATCH 183/830] Try to fix server parameters when no one can play (before it caused players being unable to play, etc.) --- src/network/protocols/server_lobby.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 323ce20c045..66f7d19b258 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2950,6 +2950,7 @@ void ServerLobby::startSelection(const Event *event) // spectating commands, I'll try to fix it later but beware Log::warn("ServerLobby", "An attempt to start a game while no one is able to play."); + addWaitingPlayersToGame(); return; // for (STKPeer* peer : always_spectate_peers) // peer->setAlwaysSpectate(ASM_NONE); From 65ce2d5938935ca92c79a243ad0c233d329cfe32 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 28 Jan 2022 02:17:32 +0300 Subject: [PATCH 184/830] Allow single char wildcards, change process_team to use standard typo fixing system --- src/network/protocols/command_manager.cpp | 30 +++++++---------------- src/utils/set_typo_fixer.cpp | 2 +- src/utils/string_utils.cpp | 17 ++++++++----- src/utils/string_utils.hpp | 4 +-- 4 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 16f1caba92d..8bf1ab209c0 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -1839,26 +1839,12 @@ void CommandManager::process_team(Context& context) } auto it = m_lobby->m_team_name_to_index.find(argv[1]); int index = (it == m_lobby->m_team_name_to_index.end() ? 0 : it->second); - std::string player; - auto wide_player_name = StringUtils::utf8ToWide(argv[2]); - std::shared_ptr player_peer = STKHost::get()->findPeerByWildcard( - wide_player_name, player); - // if player not found - if (!player_peer) - { - // don't use if wildcard - if (wide_player_name.find("*") != -1 || wide_player_name.find("?") != -1) - { - msg = "Player not found or not unique"; - m_lobby->sendStringToPeer(msg, context.m_peer); - return; - } - else - { - // if no wildcard, reset player name to use for absent players - player = argv[2]; - } - } + + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + 2, m_stf_present_users, 3, false, true)) + return; + + std::string player = argv[2]; for (const auto& pair: m_lobby->m_team_name_to_index) { if (pair.second < 0) @@ -1877,7 +1863,9 @@ void CommandManager::process_team(Context& context) } index = abs(index); m_lobby->m_team_for_player[player] = index; - wide_player_name = StringUtils::utf8ToWide(player); + irr::core::stringw wide_player_name = StringUtils::utf8ToWide(player); + std::shared_ptr player_peer = STKHost::get()->findPeerByName( + wide_player_name); if (player_peer) { for (auto& profile : player_peer.get()->getPlayerProfiles()) diff --git a/src/utils/set_typo_fixer.cpp b/src/utils/set_typo_fixer.cpp index c8d58640008..dc8922eee2d 100644 --- a/src/utils/set_typo_fixer.cpp +++ b/src/utils/set_typo_fixer.cpp @@ -47,7 +47,7 @@ std::vector> SetTypoFixer::getClosest( for (const std::string& s: m_set) { int distance = StringUtils::getEditDistance(s, - query_ref, case_sensitive, '*'); + query_ref, case_sensitive, '*', '?'); ans.emplace_back(s, distance); } diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index 332db156e3d..37d9f051530 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -1331,15 +1331,17 @@ namespace StringUtils return unit; } // getReadableFileSize // ------------------------------------------------------------------------ - bool isEqual(char a, char b, bool case_sensitive) + bool isEqual(char a, char b, char any_char, bool case_sensitive) { + if (a == any_char || b == any_char) + return true; if (a == b) return true; return !case_sensitive && toupper(a) == toupper(b); } // isEqual // ------------------------------------------------------------------------ int getEditDistance(const std::string& a, const std::string& b, - bool case_sensitive, char wildcard) + bool case_sensitive, char any_substr, char any_char) { int n = a.length(); int m = b.length(); @@ -1350,15 +1352,18 @@ namespace StringUtils for (int j = 0; j <= m; ++j) { if (i < n) { distance[i + 1][j] = std::min(distance[i + 1][j], - distance[i][j] + (j < m && b[j] == wildcard ? 0 : 1)); + distance[i][j] + (j < m && b[j] == any_substr ? 0 : 1)); } if (j < m) { distance[i][j + 1] = std::min(distance[i][j + 1], - distance[i][j] + (i < n && a[i] == wildcard ? 0 : 1)); + distance[i][j] + (i < n && a[i] == any_substr ? 0 : 1)); } if (i < n && j < m) { - int value = distance[i][j] + ((isEqual(a[i], b[j], - case_sensitive) || a[i] == wildcard || b[j] == wildcard) ? 0 : 1); + int value = distance[i][j] + 1; + if (isEqual(a[i], b[j], any_char, case_sensitive)) + --value; + else if (a[i] == any_substr || b[j] == any_substr) + --value; distance[i + 1][j + 1] = std::min( distance[i + 1][j + 1], value); } diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index 5e915eb7c14..7384700ee4f 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -337,9 +337,9 @@ namespace StringUtils } } // ------------------------------------------------------------------------ - bool isEqual(char a, char b, bool case_sensitive = true); + bool isEqual(char a, char b, char any_char, bool case_sensitive = true); int getEditDistance(const std::string& a, const std::string& b, - bool case_sensitive = true, char wildcard = 0); + bool case_sensitive = true, char any_substr = 0, char any_char = 0); } // namespace StringUtils From 6db143d8b33afceba4fb9caad9bae80e7cfc0661 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 28 Jan 2022 04:18:59 +0300 Subject: [PATCH 185/830] Add /resetteams and /randomteams --- data/commands.xml | 12 ++- src/network/protocols/command_manager.cpp | 101 +++++++++++++++------- src/network/protocols/command_manager.hpp | 2 + src/network/protocols/server_lobby.cpp | 76 ++++++++++++++-- src/network/protocols/server_lobby.hpp | 6 ++ 5 files changed, 158 insertions(+), 39 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index f2e8b94b770..3d9fb87cdab 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -182,10 +182,20 @@ description="Sets the timeout in seconds, whatever it may mean." /> + + m_team_name_to_index.find(argv[1]); - int index = (it == m_lobby->m_team_name_to_index.end() ? 0 : it->second); - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_present_users, 3, false, true)) return; - std::string player = argv[2]; - for (const auto& pair: m_lobby->m_team_name_to_index) + m_lobby->setTemporaryTeam(player, argv[1]); + + m_lobby->updatePlayerList(); +} // process_team +// ======================================================================== + +void CommandManager::process_resetteams(Context& context) +{ + std::string msg = "Teams are reset now"; + m_lobby->clearTemporaryTeams(); + m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->updatePlayerList(); +} // process_resetteams +// ======================================================================== + +void CommandManager::process_randomteams(Context& context) +{ + auto& argv = context.m_argv; + int players_number = 0; + for (auto& peer : STKHost::get()->getPeers()) { - if (pair.second < 0) - { - if (pair.second == -index) - { - m_lobby->m_player_categories[pair.first].insert(player); - m_lobby->m_categories_for_player[player].insert(pair.first); - } - else - { - m_lobby->m_player_categories[pair.first].erase(player); - m_lobby->m_categories_for_player[player].erase(pair.first); - } - } + if (peer->alwaysSpectate()) + continue; + players_number += peer->getPlayerProfiles().size(); + for (auto& profile : peer->getPlayerProfiles()) + profile->setTemporaryTeam(-1); } - index = abs(index); - m_lobby->m_team_for_player[player] = index; - irr::core::stringw wide_player_name = StringUtils::utf8ToWide(player); - std::shared_ptr player_peer = STKHost::get()->findPeerByName( - wide_player_name); - if (player_peer) + + int teams_number = -1; + if (argv.size() < 2 || !StringUtils::parseString(argv[1], &teams_number) + || teams_number < 2 || teams_number > 6) { - for (auto& profile : player_peer.get()->getPlayerProfiles()) - { - if (profile->getName() == wide_player_name) - { - profile->setTemporaryTeam(index - 1); - break; - } + teams_number = (int)round(sqrt(players_number)); + if (teams_number > 6) + teams_number = 6; + if (players_number > 1 && teams_number <= 1) + teams_number = 2; + } + + std::string msg = StringUtils::insertValues( + "Created %d teams for %d players", teams_number, players_number); + std::vector available_colors; + std::vector profile_colors; + for (int i = 1; i <= 6; ++i) + available_colors.push_back(i); + + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(available_colors.begin(), available_colors.end(), g); + available_colors.resize(teams_number); + + for (int i = 0; i < players_number; ++i) + profile_colors.push_back(available_colors[i % teams_number]); + + std::shuffle(profile_colors.begin(), profile_colors.end(), g); + + m_lobby->clearTemporaryTeams(); + for (auto& peer : STKHost::get()->getPeers()) + { + if (peer->alwaysSpectate()) + continue; + for (auto& profile : peer->getPlayerProfiles()) { + std::string name = StringUtils::wideToUtf8(profile->getName()); + std::string color = m_lobby->m_team_default_names[profile_colors.back()]; + m_lobby->setTemporaryTeam(name, color); + if (profile_colors.size() > 1) // prevent crash just in case + profile_colors.pop_back(); } } + + m_lobby->sendStringToPeer(msg, context.m_peer); m_lobby->updatePlayerList(); -} // process_team +} // process_resetteams // ======================================================================== void CommandManager::process_cat(Context& context) diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 296d3a9173d..4e49e9e7a24 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -226,6 +226,8 @@ class CommandManager void process_shuffle(Context& context); void process_timeout(Context& context); void process_team(Context& context); + void process_resetteams(Context& context); + void process_randomteams(Context& context); void process_cat(Context& context); void process_troll(Context& context); void process_hitmsg(Context& context); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 66f7d19b258..bd9c9a8bda3 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -218,15 +218,26 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_command_manager = CommandManager(nullptr); m_team_name_to_index = { - {"red", 1}, {"r", 1}, {StringUtils::utf32ToUtf8({0x1f7e5}), -1}, - {"orange", 2}, {"o", 2}, {StringUtils::utf32ToUtf8({0x1f7e7}), -2}, - {"yellow", 3}, {"y", 3}, {StringUtils::utf32ToUtf8({0x1f7e8}), -3}, - {"green", 4}, {"g", 4}, {StringUtils::utf32ToUtf8({0x1f7e9}), -4}, - {"blue", 5}, {"b", 5}, {StringUtils::utf32ToUtf8({0x1f7e6}), -5}, - {"purple", 6}, {"p", 6}, {StringUtils::utf32ToUtf8({0x1f7ea}), -6}, + {"red", 1}, {"r", 1}, + {"orange", 2}, {"o", 2}, + {"yellow", 3}, {"y", 3}, + {"green", 4}, {"g", 4}, + {"blue", 5}, {"b", 5}, + {"purple", 6}, {"p", 6}, {"violet", 6}, {"v", 6} }; + m_team_default_names = {"none", "red", "orange", "yellow", "green", "blue", "purple"}; + + m_team_index_to_icon = { + {1, StringUtils::utf32ToUtf8({0x1f7e5})}, + {2, StringUtils::utf32ToUtf8({0x1f7e7})}, + {3, StringUtils::utf32ToUtf8({0x1f7e8})}, + {4, StringUtils::utf32ToUtf8({0x1f7e9})}, + {5, StringUtils::utf32ToUtf8({0x1f7e6})}, + {6, StringUtils::utf32ToUtf8({0x1f7ea})} + }; + m_team_name = {"No Team", StringUtils::utf32ToUtf8({0x1f7e5}) + "Red", StringUtils::utf32ToUtf8({0x1f7e7}) + "Orange", @@ -7690,4 +7701,57 @@ bool ServerLobby::isSoccerGoalTarget() const { return m_game_setup->isSoccerGoalTarget(); } // isSoccerGoalTarget +//----------------------------------------------------------------------------- + +// This should be moved later to another unit. +void ServerLobby::setTemporaryTeam(const std::string& username, std::string& arg) +{ + auto it = m_team_name_to_index.find(arg); + int index = (it == m_team_name_to_index.end() ? 0 : it->second); + for (const auto& pair: m_team_index_to_icon) + { + if (pair.first == index) + { + m_player_categories[pair.second].insert(username); + m_categories_for_player[username].insert(pair.second); + } + else + { + m_player_categories[pair.second].erase(username); + m_categories_for_player[username].erase(pair.second); + } + } + m_team_for_player[username] = index; + irr::core::stringw wide_player_name = StringUtils::utf8ToWide(username); + std::shared_ptr player_peer = STKHost::get()->findPeerByName( + wide_player_name); + if (player_peer) + { + for (auto& profile : player_peer.get()->getPlayerProfiles()) + { + if (profile->getName() == wide_player_name) + { + profile->setTemporaryTeam(index - 1); + break; + } + } + } +} // setTemporaryTeam +//----------------------------------------------------------------------------- + +// This should be moved later to another unit. +void ServerLobby::clearTemporaryTeams() +{ + for (const auto& pair: m_team_index_to_icon) + { + for (const std::string& username: m_player_categories[pair.second]) + m_categories_for_player[username].erase(pair.second); + m_player_categories[pair.second].clear(); + } + m_team_for_player.clear(); + + for (auto& peer : STKHost::get()->getPeers()) + for (auto& profile : peer->getPlayerProfiles()) + profile->setTemporaryTeam(-1); +} // clearTemporaryTeams //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 6574e535959..535789f5e1f 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -383,6 +383,10 @@ class ServerLobby : public LobbyProtocol std::map m_team_name_to_index; + std::vector m_team_default_names; + + std::map m_team_index_to_icon; + bool m_shuffle_gp; std::atomic m_current_max_players_in_game; @@ -650,6 +654,8 @@ class ServerLobby : public LobbyProtocol { return m_available_difficulties.count(difficulty) > 0; } bool isModeAvailable(int mode) const { return m_available_modes.count(mode) > 0; } + void setTemporaryTeam(const std::string& username, std::string& arg); + void clearTemporaryTeams(); }; // class ServerLobby #endif // SERVER_LOBBY_HPP From 9223d197bbb8b9978ce19a4fac1373c81d3ba0e6 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 28 Jan 2022 04:22:13 +0300 Subject: [PATCH 186/830] Do not limit changing server mode due to max number of players --- src/network/protocols/server_lobby.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index bd9c9a8bda3..8828961c65e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -5949,17 +5949,6 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, } unsigned total_players = 0; STKHost::get()->updatePlayers(NULL, NULL, &total_players); - if ((mode == 6 && total_players > 14) || - (mode == 7 && total_players > 10) || - (mode == 8 && total_players > 14)) - { - Log::error("ServerLobby", "Too many players (%d) to change mode to %d.", - total_players, mode); - std::string msg = "Too many players present to activate this mode. " - "Soccer and CTF require at most 14, and FFA requires at most 10."; - sendStringToPeer(msg, peer); - return; - } if ((m_available_difficulties.count(difficulty) == 0 || m_available_modes.count(mode) == 0)) { From 477b956354a91fa67bf04d7b95c69c36eb35f365 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 28 Jan 2022 04:55:29 +0300 Subject: [PATCH 187/830] Add /resetgp and try to localize some commands as lobby-only or ingame-only --- data/commands.xml | 5 +++ src/network/protocols/command_manager.cpp | 39 ++++++++++++++--------- src/network/protocols/command_manager.hpp | 1 + src/network/protocols/server_lobby.cpp | 16 ++++++++++ src/network/protocols/server_lobby.hpp | 1 + 5 files changed, 47 insertions(+), 15 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index 3d9fb87cdab..24b85b21348 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -196,6 +196,11 @@ permissions="hammers" description="Put all players into a certain number of teams. The default number of teams is max(2, min(6, round(sqrt(number of players)))) unless there is 1 player." /> + sendStringToPeer(msg, context.m_peer); m_lobby->updatePlayerList(); -} // process_resetteams +} // process_randomteams +// ======================================================================== + +void CommandManager::process_resetgp(Context& context) +{ + std::string msg = "GP is now reset"; + m_lobby->resetGrandPrix(); + m_lobby->sendStringToAllPeers(msg); +} // process_resetgp // ======================================================================== void CommandManager::process_cat(Context& context) diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 4e49e9e7a24..aeb6d58aab4 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -228,6 +228,7 @@ class CommandManager void process_team(Context& context); void process_resetteams(Context& context); void process_randomteams(Context& context); + void process_resetgp(Context& context); void process_cat(Context& context); void process_troll(Context& context); void process_hitmsg(Context& context); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 8828961c65e..337c47cbf68 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7743,4 +7743,20 @@ void ServerLobby::clearTemporaryTeams() for (auto& profile : peer->getPlayerProfiles()) profile->setTemporaryTeam(-1); } // clearTemporaryTeams +//----------------------------------------------------------------------------- + +void ServerLobby::resetGrandPrix() +{ + m_gp_scores.clear(); + m_gp_team_scores.clear(); + m_game_setup->stopGrandPrix(); + + NetworkString* server_info = getNetworkString(); + server_info->setSynchronous(true); + server_info->addUInt8(LE_SERVER_INFO); + m_game_setup->addServerInfo(server_info); + sendMessageToPeers(server_info); + delete server_info; + updatePlayerList(); +} // resetGrandPrix //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 535789f5e1f..fa2cfc3abff 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -656,6 +656,7 @@ class ServerLobby : public LobbyProtocol { return m_available_modes.count(mode) > 0; } void setTemporaryTeam(const std::string& username, std::string& arg); void clearTemporaryTeams(); + void resetGrandPrix(); }; // class ServerLobby #endif // SERVER_LOBBY_HPP From 834bc7e2243c9e5943906cd215d376743a571c98 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 28 Jan 2022 19:49:41 +0300 Subject: [PATCH 188/830] Fix /start not working when the last voted player has no host rights, allow /randomteams 1 --- src/network/protocols/command_manager.cpp | 16 ++++++++++++---- src/network/protocols/command_manager.hpp | 6 ++++++ src/network/protocols/server_lobby.cpp | 11 +++++++---- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 73bf94f16d9..1fd1029279f 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -411,7 +411,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) if (mask != PE_NONE && mask_without_voting == PE_NONE) voting = true; - (this->*command.m_action)(context); + execute(command, context); while (!m_triggered_votables.empty()) { @@ -435,7 +435,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) std::string msg = "Command \"" + new_cmd + "\" has been successfully voted"; m_lobby->sendStringToAllPeers(msg); Context new_context(event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); - (this->*command.m_action)(new_context); + execute(command, new_context); } } } @@ -506,7 +506,7 @@ void CommandManager::update() // We don't know the event though it is only needed in // ServerLobby::startSelection where it is nullptr when they vote Context new_context(nullptr, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); - (this->*command.m_action)(new_context); + execute(command, new_context); } } } @@ -525,6 +525,14 @@ void CommandManager::error(Context& context) } // error // ======================================================================== +void CommandManager::execute(const Command& command, Context& context) +{ + m_current_argv = context.m_argv; + (this->*command.m_action)(context); + m_current_argv = {}; +} // execute +// ======================================================================== + void CommandManager::process_help(Context& context) { auto& argv = context.m_argv; @@ -1874,7 +1882,7 @@ void CommandManager::process_randomteams(Context& context) int teams_number = -1; if (argv.size() < 2 || !StringUtils::parseString(argv[1], &teams_number) - || teams_number < 2 || teams_number > 6) + || teams_number < 1 || teams_number > 6) { teams_number = (int)round(sqrt(players_number)); if (teams_number > 6) diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index aeb6d58aab4..012be408625 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -180,6 +180,8 @@ class CommandManager SetTypoFixer m_stf_addon_maps; + std::vector m_current_argv; + void initCommandsInfo(); void initCommands(); @@ -192,6 +194,8 @@ class CommandManager void update(); void error(Context& context); + void execute(const Command& command, Context& context); + void process_help(Context& context); void process_text(Context& context); void process_file(Context& context); @@ -279,6 +283,8 @@ class CommandManager void onResetServer(); void onStartSelection(); + + std::vector getCurrentArgv() { return m_current_argv; } }; #endif // COMMAND_MANAGER_HPP \ No newline at end of file diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 337c47cbf68..c914fed9041 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2872,10 +2872,13 @@ void ServerLobby::startSelection(const Event *event) } if (!hasHostRights(peer)) { - Log::warn("ServerLobby", - "Client %d is not authorised to start selection.", - event->getPeer()->getHostId()); - return; + auto argv = getCommandManager().getCurrentArgv(); + if (argv.size() <= 1 || argv[0] != "start") { + Log::warn("ServerLobby", + "Client %d is not authorised to start selection.", + event->getPeer()->getHostId()); + return; + } } } else { if (!m_allowed_to_start) From 2ad48e1d44beecd9257aed64f9d6c1216ab6dec8 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 28 Jan 2022 20:09:57 +0300 Subject: [PATCH 189/830] Fix a typo --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index c914fed9041..46b4f7e3ba0 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2873,7 +2873,7 @@ void ServerLobby::startSelection(const Event *event) if (!hasHostRights(peer)) { auto argv = getCommandManager().getCurrentArgv(); - if (argv.size() <= 1 || argv[0] != "start") { + if (argv.empty() || argv[0] != "start") { Log::warn("ServerLobby", "Client %d is not authorised to start selection.", event->getPeer()->getHostId()); From 2a4e4b2d4efbdc7dfa6326329ff29bc5859a6e7e Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 9 Feb 2022 18:16:24 +0300 Subject: [PATCH 190/830] Add disconnects somehow in the database (the format will be changed later) --- src/network/protocols/server_lobby.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 46b4f7e3ba0..3d3327bf9c8 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6621,17 +6621,18 @@ void ServerLobby::storeResults() int best_cur_player_idx = -1; std::string best_cur_player_name = ""; double best_cur_time = 1e18; + const double DISCONNECT_TIME = 123454321; for (int i = 0; i < player_count; i++) { - if (w->getKart(i)->isEliminated()) - continue; std::string username = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(i).getPlayerName()); auto profile = RaceManager::get()->getKartInfo(i).getNetworkPlayerProfile().lock(); // TODO fix this properly. if (profile && profile->getOnlineId() == 0) username = "* " + username; - double elapsed_time = RaceManager::get()->getKartRaceTime(i); + double elapsed_time = DISCONNECT_TIME; + if (!w->getKart(i)->isEliminated()) + elapsed_time = RaceManager::get()->getKartRaceTime(i); std::stringstream elapsed_string; elapsed_string << std::setprecision(4) << std::fixed << elapsed_time; if (best_cur_player_idx == -1 || elapsed_time < best_cur_time) From f956a3b52b002cd13b63ca2f0efdc6a055a0df6d Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 11 Feb 2022 00:04:06 +0300 Subject: [PATCH 191/830] Allow players to stay but not play if certain assets/number of assets isn't installed [CONFIG CHANGE] Remove underscores, clarify names Fix bugs --- src/network/protocols/command_manager.cpp | 4 + src/network/protocols/server_lobby.cpp | 109 ++++++++++++++-------- src/network/protocols/server_lobby.hpp | 2 + src/network/server_config.cpp | 8 +- src/network/server_config.hpp | 45 +++++++-- 5 files changed, 115 insertions(+), 53 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 1fd1029279f..560bdf59638 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -1728,6 +1728,7 @@ void CommandManager::process_queue(Context& context) + " to the back of queue, current queue size: " + std::to_string(m_lobby->m_tracks_queue.size()); m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->updatePlayerList(); } else if (argv[1] == "push_front") { @@ -1741,6 +1742,7 @@ void CommandManager::process_queue(Context& context) + " to the front of queue, current queue size: " + std::to_string(m_lobby->m_tracks_queue.size()); m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->updatePlayerList(); } else if (argv[1] == "pop" || argv[1] == "pop_front") { @@ -1757,6 +1759,7 @@ void CommandManager::process_queue(Context& context) + std::to_string(m_lobby->m_tracks_queue.size()); } m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->updatePlayerList(); } else if (argv[1] == "pop_back") { @@ -1773,6 +1776,7 @@ void CommandManager::process_queue(Context& context) + std::to_string(m_lobby->m_tracks_queue.size()); } m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->updatePlayerList(); } } // process_queue // ======================================================================== diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3d3327bf9c8..e5d18bc28f5 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2963,7 +2963,9 @@ void ServerLobby::startSelection(const Event *event) // The always spectating code will probably behave kinda weird with // spectating commands, I'll try to fix it later but beware Log::warn("ServerLobby", - "An attempt to start a game while no one is able to play."); + "An attempt to start a game while no one can play."); + std::string msg = "No one can play!"; + sendStringToPeer(msg, event->getPeer()); addWaitingPlayersToGame(); return; // for (STKPeer* peer : always_spectate_peers) @@ -4116,10 +4118,10 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) Log::info("ServerLobby", "Player has the following addons: %d/%d karts," " %d/%d tracks, %d/%d arenas, %d/%d soccer fields.", addon_karts, - (int)ServerConfig::m_addon_karts_threshold, addon_tracks, - (int)ServerConfig::m_addon_tracks_threshold, addon_arenas, - (int)ServerConfig::m_addon_arenas_threshold, addon_soccers, - (int)ServerConfig::m_addon_soccers_threshold); + (int)ServerConfig::m_addon_karts_join_threshold, addon_tracks, + (int)ServerConfig::m_addon_tracks_join_threshold, addon_arenas, + (int)ServerConfig::m_addon_arenas_join_threshold, addon_soccers, + (int)ServerConfig::m_addon_soccers_join_threshold); peer->addon_karts_count = addon_karts; peer->addon_tracks_count = addon_tracks; @@ -4134,13 +4136,13 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) Log::verbose("ServerLobby", "Bad player: bad official kart threshold"); if (ott < ServerConfig::m_official_tracks_threshold) Log::verbose("ServerLobby", "Bad player: bad official track threshold"); - if (addon_karts < (int)ServerConfig::m_addon_karts_threshold) + if (addon_karts < (int)ServerConfig::m_addon_karts_join_threshold) Log::verbose("ServerLobby", "Bad player: too little addon karts"); - if (addon_tracks < (int)ServerConfig::m_addon_tracks_threshold) + if (addon_tracks < (int)ServerConfig::m_addon_tracks_join_threshold) Log::verbose("ServerLobby", "Bad player: too little addon tracks"); - if (addon_arenas < (int)ServerConfig::m_addon_arenas_threshold) + if (addon_arenas < (int)ServerConfig::m_addon_arenas_join_threshold) Log::verbose("ServerLobby", "Bad player: too little addon arenas"); - if (addon_soccers < (int)ServerConfig::m_addon_soccers_threshold) + if (addon_soccers < (int)ServerConfig::m_addon_soccers_join_threshold) Log::verbose("ServerLobby", "Bad player: too little addon soccers"); if (!has_required_tracks) Log::verbose("ServerLobby", "Bad player: no required tracks"); @@ -4149,35 +4151,43 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) tracks_erase.size() == m_entering_kts.second.size() || okt < ServerConfig::m_official_karts_threshold || ott < ServerConfig::m_official_tracks_threshold || - addon_karts < (int)ServerConfig::m_addon_karts_threshold || - addon_tracks < (int)ServerConfig::m_addon_tracks_threshold || - addon_arenas < (int)ServerConfig::m_addon_arenas_threshold || - addon_soccers < (int)ServerConfig::m_addon_soccers_threshold || + addon_karts < (int)ServerConfig::m_addon_karts_join_threshold || + addon_tracks < (int)ServerConfig::m_addon_tracks_join_threshold || + addon_arenas < (int)ServerConfig::m_addon_arenas_join_threshold || + addon_soccers < (int)ServerConfig::m_addon_soccers_join_threshold || !has_required_tracks) { - NetworkString *message = getNetworkString(2); - message->setSynchronous(true); - message->addUInt8(LE_CONNECTION_REFUSED) - .addUInt8(RR_INCOMPATIBLE_DATA); - - std::string advice = ServerConfig::m_incompatible_advice; - if (!advice.empty()) + if (peer->isValidated()) { - NetworkString* incompatible_reason = getNetworkString(); - incompatible_reason->addUInt8(LE_CHAT); - incompatible_reason->setSynchronous(true); - incompatible_reason->encodeString16( - StringUtils::utf8ToWide(advice)); - peer->sendPacket(incompatible_reason, - true/*reliable*/, false/*encrypted*/); - Log::info("ServerLobby", "Sent advice"); - delete incompatible_reason; + std::string msg = "You deleted some assets that are required to stay on the server"; + sendStringToPeer(msg, peer); + peer->kick(); } + else + { + NetworkString *message = getNetworkString(2); + message->setSynchronous(true); + message->addUInt8(LE_CONNECTION_REFUSED) + .addUInt8(RR_INCOMPATIBLE_DATA); + + std::string advice = ServerConfig::m_incompatible_advice; + if (!advice.empty()) { + NetworkString *incompatible_reason = getNetworkString(); + incompatible_reason->addUInt8(LE_CHAT); + incompatible_reason->setSynchronous(true); + incompatible_reason->encodeString16( + StringUtils::utf8ToWide(advice)); + peer->sendPacket(incompatible_reason, + true/*reliable*/, false/*encrypted*/); + Log::info("ServerLobby", "Sent advice"); + delete incompatible_reason; + } - peer->cleanPlayerProfiles(); - peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); - peer->reset(); - delete message; + peer->cleanPlayerProfiles(); + peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); + peer->reset(); + delete message; + } Log::verbose("ServerLobby", "Player has incompatible karts / tracks."); return false; } @@ -4241,6 +4251,7 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) if (ServerConfig::m_soccer_tournament) updateTournamentRole(peer); + updatePlayerList(); return true; } // handleAssets @@ -6469,8 +6480,6 @@ std::set& ServerLobby::getSpectatorsByLimit(bool update) unsigned ingame_players = 0, waiting_players = 0, total_players = 0; STKHost::get()->updatePlayers(&ingame_players, &waiting_players, &total_players); - if (total_players <= player_limit) - return m_spectators_by_limit; for (int i = 0; i < (int)peers.size(); ++i) { @@ -6504,6 +6513,11 @@ std::set& ServerLobby::getSpectatorsByLimit(bool update) { if (peer->alwaysSpectate() || peer->isWaitingForGame()) continue; + if (!canRace(peer)) + { + m_spectators_by_limit.insert(peer.get()); + continue; + } player_count += (unsigned)peer->getPlayerProfiles().size(); if (player_count > player_limit) m_spectators_by_limit.insert(peer.get()); @@ -7059,12 +7073,23 @@ bool ServerLobby::canRace(STKPeer* peer) const m_tournament_blue_players.count(username) > 0; else if (m_spectators_by_limit.find(peer) != m_spectators_by_limit.end()) return false; - // else if (ServerConfig::m_only_host_riding) - // return peer == m_server_owner.lock().get(); - else if (!m_tracks_queue.empty()) - return peer->getClientAssets().second.count(m_tracks_queue.front()); - else - return true; + + if (!m_tracks_queue.empty()) + if (peer->getClientAssets().second.count(m_tracks_queue.front()) == 0) + return false; + if (!m_play_requirement_tracks.empty()) + for (const std::string& track: m_play_requirement_tracks) + if (peer->getClientAssets().second.count(track) == 0) + return false; + if (peer->addon_karts_count < ServerConfig::m_addon_karts_play_threshold) + return false; + if (peer->addon_tracks_count < ServerConfig::m_addon_tracks_play_threshold) + return false; + if (peer->addon_arenas_count < ServerConfig::m_addon_arenas_play_threshold) + return false; + if (peer->addon_soccers_count < ServerConfig::m_addon_soccers_play_threshold) + return false; + return true; } // canRace //----------------------------------------------------------------------------- @@ -7292,6 +7317,8 @@ void ServerLobby::initAvailableTracks() m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); m_must_have_tracks = StringUtils::split( ServerConfig::m_must_have_tracks_string, ' ', false); + m_play_requirement_tracks = StringUtils::split( + ServerConfig::m_play_requirement_tracks_string, ' ', false); m_tournament_must_have_tracks = StringUtils::split( ServerConfig::m_soccer_tournament_enforced_tracks_string, ' ', false); } // initAvailableTracks diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index fa2cfc3abff..5344b8095e0 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -291,6 +291,8 @@ class ServerLobby : public LobbyProtocol std::vector m_must_have_tracks; + std::vector m_play_requirement_tracks; + std::vector m_tournament_must_have_tracks; bool m_restricting_config; diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index bd52015cc5b..b06416f2d1c 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -386,10 +386,10 @@ void loadServerLobbyFromConfig() // m_owner_less = false; m_official_karts_threshold = 1.0f; m_official_tracks_threshold = 0.0f; - m_addon_karts_threshold = 0; - m_addon_tracks_threshold = 0; - m_addon_arenas_threshold = 0; - m_addon_soccers_threshold = 0; // maybe 1 ? + m_addon_karts_join_threshold = 0; + m_addon_tracks_join_threshold = 0; + m_addon_arenas_join_threshold = 0; + m_addon_soccers_join_threshold = 0; // maybe 1 ? m_team_choosing = true; m_ranked = false; m_server_configurable = false; diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 38b80211869..10d7ea1d656 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -232,35 +232,64 @@ namespace ServerConfig "android players from joining this server, because STK android apk " "has some official tracks removed.")); - SERVER_CFG_PREFIX IntServerConfigParam m_addon_karts_threshold + SERVER_CFG_PREFIX IntServerConfigParam m_addon_karts_join_threshold SERVER_CFG_DEFAULT(IntServerConfigParam(0, - "addon_karts_threshold", + "addon-karts-join-threshold", "Clients below this value will be rejected from joining this server. " "It's determined by number of addon karts in client")); - SERVER_CFG_PREFIX IntServerConfigParam m_addon_tracks_threshold + SERVER_CFG_PREFIX IntServerConfigParam m_addon_tracks_join_threshold SERVER_CFG_DEFAULT(IntServerConfigParam(0, - "addon_tracks_threshold", + "addon-tracks-join-threshold", "Clients below this value will be rejected from joining this server. " "It's determined by number of addon tracks in client")); - SERVER_CFG_PREFIX IntServerConfigParam m_addon_arenas_threshold + SERVER_CFG_PREFIX IntServerConfigParam m_addon_arenas_join_threshold SERVER_CFG_DEFAULT(IntServerConfigParam(0, - "addon_arenas_threshold", + "addon-arenas-join-threshold", "Clients below this value will be rejected from joining this server. " "It's determined by number of addon arenas in client")); - SERVER_CFG_PREFIX IntServerConfigParam m_addon_soccers_threshold + SERVER_CFG_PREFIX IntServerConfigParam m_addon_soccers_join_threshold SERVER_CFG_DEFAULT(IntServerConfigParam(0, - "addon_soccers_threshold", + "addon-soccers-join-threshold", "Clients below this value will be rejected from joining this server. " "It's determined by number of addon soccer fields in client")); + SERVER_CFG_PREFIX IntServerConfigParam m_addon_karts_play_threshold + SERVER_CFG_DEFAULT(IntServerConfigParam(0, + "addon-karts-play-threshold", + "Clients below this value will be rejected from playing games. " + "It's determined by number of addon karts in client")); + + SERVER_CFG_PREFIX IntServerConfigParam m_addon_tracks_play_threshold + SERVER_CFG_DEFAULT(IntServerConfigParam(0, + "addon-tracks-play-threshold", + "Clients below this value will be rejected from playing games. " + "It's determined by number of addon tracks in client")); + + SERVER_CFG_PREFIX IntServerConfigParam m_addon_arenas_play_threshold + SERVER_CFG_DEFAULT(IntServerConfigParam(0, + "addon-arenas-play-threshold", + "Clients below this value will be rejected from playing games. " + "It's determined by number of addon arenas in client")); + + SERVER_CFG_PREFIX IntServerConfigParam m_addon_soccers_play_threshold + SERVER_CFG_DEFAULT(IntServerConfigParam(0, + "addon-soccers-play-threshold", + "Clients below this value will be rejected from playing games. " + "It's determined by number of addon soccer fields in client")); + SERVER_CFG_PREFIX StringServerConfigParam m_must_have_tracks_string SERVER_CFG_DEFAULT(StringServerConfigParam("", "must-have-tracks", "Tracks needed to enter the server, " "leave empty for no restriction.")); + SERVER_CFG_PREFIX StringServerConfigParam m_play_requirement_tracks_string + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "play-requirement-tracks", "Tracks needed to be able to play, " + "leave empty for no restriction.")); + SERVER_CFG_PREFIX StringServerConfigParam m_only_played_tracks_string SERVER_CFG_DEFAULT(StringServerConfigParam("", "only-played-tracks", "List of tracks that can be played on a server, " From 5de24a540c60c9fecca60e1d3490c83f29245c10 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 13 Feb 2022 16:32:44 +0300 Subject: [PATCH 192/830] Allow to call /standings for players and/or teams only --- src/network/protocols/command_manager.cpp | 36 ++++++++++---- src/network/protocols/server_lobby.cpp | 59 ++++++++++++++--------- src/network/protocols/server_lobby.hpp | 2 +- 3 files changed, 64 insertions(+), 33 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 560bdf59638..d98f0845f72 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -1510,22 +1510,38 @@ void CommandManager::process_standings(Context& context) { std::string msg; auto& argv = context.m_argv; - if (argv.size() == 1) + bool isGP = false; + bool isGnu = false; + bool isGPTeams = false; + bool isGPPlayers = false; + for (int i = 1; i < argv.size(); ++i) + { + if (argv[i] == "gp") + isGP = true; + else if (argv[i] == "gnu") + isGnu = true; + else if (argv[i] == "team" || argv[i] == "teams") + isGPTeams = true; + else if (argv[i] == "player" || argv[i] == "players") + isGPPlayers = true; + else if (argv[i] == "both" || argv[i] == "all") + isGPPlayers = isGPTeams = true; + } + if (!isGP && !isGnu) { if (m_lobby->m_game_setup->isGrandPrix()) - argv.push_back("gp"); + isGP = true; else - argv.push_back("gnu"); + isGnu = true; } - if (argv[1] == "gp") - msg = m_lobby->getGrandPrixStandings(); - else if (argv[1] == "gnu") - msg = m_lobby->m_kart_elimination.getStandings(); - else + if (isGP) { - error(context); - return; + // the function will decide itself what to show if nothing is specified: + // if there are teams, teams will be shown, otherwise players + msg = m_lobby->getGrandPrixStandings(isGPPlayers, isGPTeams); } + else if (isGnu) + msg = m_lobby->m_kart_elimination.getStandings(); m_lobby->sendStringToPeer(msg, context.m_peer); } // process_standings // ======================================================================== diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index e5d18bc28f5..953f55f2ae9 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7152,40 +7152,55 @@ void ServerLobby::loadTracksQueueFromConfig() m_tracks_queue.push_back(s); } // loadTracksQueueFromConfig //----------------------------------------------------------------------------- -std::string ServerLobby::getGrandPrixStandings() const +std::string ServerLobby::getGrandPrixStandings(bool showIndividual, bool showTeam) const { - std::vector> results; - for (auto& p: m_gp_scores) - results.emplace_back(p.second, p.first); - std::stable_sort(results.rbegin(), results.rend()); std::stringstream response; response << "Grand Prix standings\n"; - for (unsigned i = 0; i < results.size(); i++) + + if (!showIndividual && !showTeam) { - response << (i + 1) << ". "; - response << " " << results[i].second; - response << " " << results[i].first.score; - response << " " << "(" << StringUtils::timeToString(results[i].first.time) << ")"; - response << "\n"; + if (m_gp_team_scores.empty()) + showIndividual = true; + else + showTeam = true; } - results.clear(); - if (!m_gp_team_scores.empty()) + if (showIndividual) { - std::vector> results2; - response << "\n"; - for (auto& p: m_gp_team_scores) - results2.emplace_back(p.second, p.first); - std::stable_sort(results2.rbegin(), results2.rend()); - for (unsigned i = 0; i < results2.size(); i++) + std::vector> results; + for (auto &p: m_gp_scores) + results.emplace_back(p.second, p.first); + std::stable_sort(results.rbegin(), results.rend()); + for (unsigned i = 0; i < results.size(); i++) { response << (i + 1) << ". "; - response << " " << m_team_name[results2[i].second]; - response << " " << results2[i].first.score; - response << " " << "(" << StringUtils::timeToString(results2[i].first.time) << ")"; + response << " " << results[i].second; + response << " " << results[i].first.score; + response << " " << "(" << StringUtils::timeToString(results[i].first.time) << ")"; response << "\n"; } } + + if (showTeam) + { + if (!m_gp_team_scores.empty()) + { + std::vector> results2; + if (showIndividual) + response << "\n"; + for (auto &p: m_gp_team_scores) + results2.emplace_back(p.second, p.first); + std::stable_sort(results2.rbegin(), results2.rend()); + for (unsigned i = 0; i < results2.size(); i++) + { + response << (i + 1) << ". "; + response << " " << m_team_name[results2[i].second]; + response << " " << results2[i].first.score; + response << " " << "(" << StringUtils::timeToString(results2[i].first.time) << ")"; + response << "\n"; + } + } + } return response.str(); } // getGrandPrixStandings //----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 5344b8095e0..9e0df90118e 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -565,7 +565,7 @@ class ServerLobby : public LobbyProtocol std::vector getMissingTournamentAssets(std::shared_ptr& peer) const; std::vector getMissingTournamentAssets(STKPeer* peer) const; void loadTracksQueueFromConfig(); - std::string getGrandPrixStandings() const; + std::string getGrandPrixStandings(bool showIndividual = false, bool showTeam = true) const; void loadCustomScoring(); void updateWorldSettings(); void loadWhiteList(); From a1e1afbf43f125017b783de0fbec8cdf1f073cfb Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 13 Feb 2022 17:54:37 +0300 Subject: [PATCH 193/830] Try to forbid spectators voting for most commands (as they affect gameplay for everyone except them) --- data/commands.xml | 14 ++++----- src/network/protocols/command_manager.cpp | 31 ++++++++++--------- src/network/protocols/command_permissions.hpp | 10 ++++-- src/network/protocols/server_lobby.cpp | 15 +++++++-- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index 24b85b21348..2eaa0ab0b94 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -13,12 +13,12 @@ /> m_help_message)); addTextResponse("version", "1.3-rc1 k 210fff beta"); diff --git a/src/network/protocols/command_permissions.hpp b/src/network/protocols/command_permissions.hpp index c19e71e753d..caeebe75f07 100644 --- a/src/network/protocols/command_permissions.hpp +++ b/src/network/protocols/command_permissions.hpp @@ -22,17 +22,21 @@ enum CommandPermissions : unsigned int { PE_NONE = 0, - PE_USUAL = 1, - PE_VOTED = 2, + PE_SPECTATOR = 1, + PE_USUAL = 2, PE_CROWNED = 4, PE_SINGLE = 8, PE_HAMMER = 16, PE_CONSOLE = 32, + PE_VOTED_SPECTATOR = 1024, + PE_VOTED_NORMAL = 2048, + PE_VOTED = PE_VOTED_SPECTATOR | PE_VOTED_NORMAL, UP_CONSOLE = PE_CONSOLE, UP_HAMMER = UP_CONSOLE | PE_HAMMER, UP_SINGLE = UP_HAMMER | PE_SINGLE, UP_CROWNED = UP_SINGLE | PE_CROWNED, - UP_EVERYONE = UP_CROWNED | PE_USUAL + UP_NORMAL = UP_CROWNED | PE_USUAL, + UP_EVERYONE = UP_NORMAL | PE_SPECTATOR }; #endif // COMMAND_PERMISSIONS_HPP \ No newline at end of file diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 953f55f2ae9..163914238b1 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7121,8 +7121,19 @@ int ServerLobby::getPermissions(std::shared_ptr& peer) const int ServerLobby::getPermissions(STKPeer* peer) const { int mask = 0; - mask |= CommandPermissions::PE_USUAL; - mask |= CommandPermissions::PE_VOTED; + if (!peer) + return mask; + bool isSpectator = (peer->alwaysSpectate()); + if (isSpectator) + { + mask |= CommandPermissions::PE_SPECTATOR; + mask |= CommandPermissions::PE_VOTED_SPECTATOR; + } + else + { + mask |= CommandPermissions::PE_USUAL; + mask |= CommandPermissions::PE_VOTED_NORMAL; + } if (peer == m_server_owner.lock().get()) { mask |= CommandPermissions::PE_CROWNED; From 551d964b95cfcd190a2c0c80d4496b4751b60ced Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 13 Feb 2022 19:14:03 +0300 Subject: [PATCH 194/830] Fix typos in parameters of /help --- src/network/protocols/command_manager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 7c89b999a85..7e5c54f13f2 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -542,6 +542,10 @@ void CommandManager::process_help(Context& context) error(context); return; } + + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 1, m_stf_command_names, 3, false, false)) + return; + std::string msg; auto it = m_name_to_command.find(argv[1]); if (it == m_name_to_command.end()) From cff2fb24983187ce7f0f2d06a1531f74b3d3b845 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 13 Feb 2022 19:43:35 +0300 Subject: [PATCH 195/830] Rename some commands --- data/commands.xml | 8 ++++---- src/network/protocols/command_manager.cpp | 10 +++++----- src/network/protocols/command_manager.hpp | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index 2eaa0ab0b94..88147b85371 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -166,8 +166,8 @@ permissions="hammers, singleplayers" description="Manipulates the track queue aka the next played tracks. “show” displays it, “push” adds the track to the end of the queue, “pop” removes a track at the front. You can use “_back” and “_front” to specify on which end of the queue to add or remove the tracks." /> - @@ -211,8 +211,8 @@ permissions="hammers" description="Removes the player from a certain category." /> - diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 7e5c54f13f2..d3ffd8388bb 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -236,7 +236,7 @@ void CommandManager::initCommands() v.emplace_back("power", &CM::process_power, UP_EVERYONE); v.emplace_back("length", &CM::process_length, UP_SINGLE, MS_DEFAULT, SS_LOBBY); v.emplace_back("queue", &CM::process_queue, UP_SINGLE, MS_DEFAULT, SS_LOBBY); - v.emplace_back("adminstart", &CM::process_adminstart, UP_HAMMER); + v.emplace_back("allowstart", &CM::process_allowstart, UP_HAMMER); v.emplace_back("shuffle", &CM::process_shuffle, UP_HAMMER); v.emplace_back("timeout", &CM::process_timeout, UP_HAMMER); v.emplace_back("team", &CM::process_team, UP_HAMMER); @@ -245,7 +245,7 @@ void CommandManager::initCommands() v.emplace_back("resetgp", &CM::process_resetgp, UP_HAMMER, MS_DEFAULT, SS_LOBBY); v.emplace_back("cat+", &CM::process_cat, UP_HAMMER); v.emplace_back("cat-", &CM::process_cat, UP_HAMMER); - v.emplace_back("catsee", &CM::process_cat, UP_HAMMER); + v.emplace_back("catshow", &CM::process_cat, UP_HAMMER); v.emplace_back("troll", &CM::process_troll, UP_HAMMER, MS_DEFAULT, SS_LOBBY); v.emplace_back("hitmsg", &CM::process_hitmsg, UP_HAMMER, MS_DEFAULT, SS_LOBBY); v.emplace_back("teamhit", &CM::process_teamhit, UP_HAMMER, MS_DEFAULT, SS_LOBBY); @@ -1802,7 +1802,7 @@ void CommandManager::process_queue(Context& context) } // process_queue // ======================================================================== -void CommandManager::process_adminstart(Context& context) +void CommandManager::process_allowstart(Context& context) { std::string msg; auto& argv = context.m_argv; @@ -1822,7 +1822,7 @@ void CommandManager::process_adminstart(Context& context) msg = "Now starting a race is allowed"; } m_lobby->sendStringToPeer(msg, context.m_peer); -} // process_adminstart +} // process_allowstart // ======================================================================== void CommandManager::process_shuffle(Context& context) @@ -1998,7 +1998,7 @@ void CommandManager::process_cat(Context& context) m_lobby->updatePlayerList(); return; } - if (argv[0] == "cat*") + if (argv[0] == "catshow") { int displayed; if (argv.size() != 3 || !StringUtils::parseString(argv[2], &displayed) diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 012be408625..fb1681c0394 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -226,7 +226,7 @@ class CommandManager void process_power(Context& context); void process_length(Context& context); void process_queue(Context& context); - void process_adminstart(Context& context); + void process_allowstart(Context& context); void process_shuffle(Context& context); void process_timeout(Context& context); void process_team(Context& context); From 5ac12b95f8d79ab0079d1e43fa286613a01a08aa Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 14 Feb 2022 16:20:40 +0300 Subject: [PATCH 196/830] Allow /spectate and forbid /slots on singleplayer servers --- src/network/protocols/command_manager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index d3ffd8388bb..afe617d568b 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -273,7 +273,8 @@ void CommandManager::initCommands() // v.emplace_back("3", &CM::special, UP_EVERYONE, MS_DEFAULT); // v.emplace_back("4", &CM::special, UP_EVERYONE, MS_DEFAULT); // v.emplace_back("5", &CM::special, UP_EVERYONE, MS_DEFAULT); - v.emplace_back("slots", &CM::process_slots, UP_HAMMER | PE_VOTED_NORMAL, MS_DEFAULT, SS_LOBBY); + if (!ServerConfig::m_only_host_riding) + v.emplace_back("slots", &CM::process_slots, UP_HAMMER | PE_VOTED_NORMAL, MS_DEFAULT, SS_LOBBY); v.emplace_back("time", &CM::process_time, UP_EVERYONE); v.emplace_back("addondownloadprogress", &CM::special, UP_EVERYONE); @@ -723,9 +724,6 @@ void CommandManager::process_spectate(Context& context) auto& argv = context.m_argv; auto& peer = context.m_peer; - if (ServerConfig::m_soccer_tournament || ServerConfig::m_only_host_riding) - response = "All spectators already have auto spectate ability"; - if (/*m_game_setup->isGrandPrix() || */!ServerConfig::m_live_players) response = "Server doesn't support spectating"; From b5640d7967a217938c94a4f5381f20e0f02a63c3 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 14 Feb 2022 18:16:45 +0300 Subject: [PATCH 197/830] Add aliases to SetTypoFixer and to commands --- data/commands.xml | 6 +++++ src/network/protocols/command_manager.cpp | 13 ++++++++++ src/network/protocols/command_manager.hpp | 2 ++ src/utils/set_typo_fixer.cpp | 31 ++++++++++++++++++----- src/utils/set_typo_fixer.hpp | 17 ++++++++----- 5 files changed, 56 insertions(+), 13 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index 88147b85371..37eabc95ec1 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -35,6 +35,7 @@ usage="/moreaddons [type]" permissions="everyone" description="Lists top 5 addons that are missing for at least one player, sorted by the number of players that don’t have the addon ascending, random for equal number of players. Limits the list to a certain addon type if specified." + aliases="more" /> get("usage", &usage); node->get("permissions", &permissions); node->get("description", &description); + node->get("aliases", &aliases); + std::vector aliases_split = StringUtils::split(aliases, ' '); + for (const std::string& alias_name: aliases_split) + m_aliases[name].push_back(alias_name); if (node_name == "command") { @@ -303,6 +308,14 @@ void CommandManager::initCommands() }); for (auto& command: m_commands) m_name_to_command[command.m_name] = command; + for (auto& p: m_aliases) + { + for (const std::string& alias_name: p.second) + { + m_stf_command_names.add(alias_name, p.first); + m_name_to_command[alias_name] = m_name_to_command[p.first]; + } + } // m_votables.emplace("replay", 1.0); m_votables.emplace("start", 0.81); diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index fb1681c0394..cc9a224f2b3 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -172,6 +172,8 @@ class CommandManager std::map m_config_descriptions; + std::map> m_aliases; + SetTypoFixer m_stf_command_names; SetTypoFixer m_stf_present_users; diff --git a/src/utils/set_typo_fixer.cpp b/src/utils/set_typo_fixer.cpp index dc8922eee2d..0108f3df83d 100644 --- a/src/utils/set_typo_fixer.cpp +++ b/src/utils/set_typo_fixer.cpp @@ -19,28 +19,39 @@ #include "utils/set_typo_fixer.hpp" #include "utils/string_utils.hpp" -void SetTypoFixer::add(const std::string& value) +void SetTypoFixer::add(const std::string& key) { - m_set.insert(value); + m_set.insert(key); + m_map[key] = key; } // add // ======================================================================== -void SetTypoFixer::remove(const std::string& value) +void SetTypoFixer::add(const std::string& key, const std::string& value) { - m_set.erase(m_set.find(value)); + m_set.insert(key); + m_map[key] = value; +} // add +// ======================================================================== + +void SetTypoFixer::remove(const std::string& key) +{ + m_set.erase(m_set.find(key)); + if (m_set.find(key) == m_set.end()) + m_map.erase(key); } // remove // ======================================================================== std::vector> SetTypoFixer::getClosest( const std::string& query, int count, bool case_sensitive) const { + std::map ans_map; std::vector> ans; if (m_set.empty()) return ans; auto it = m_set.find(query); if (it != m_set.end()) { - ans.emplace_back(query, 0); + ans.emplace_back(m_map.find(query)->second, 0); return ans; } const std::string& query_ref = query; @@ -48,9 +59,15 @@ std::vector> SetTypoFixer::getClosest( { int distance = StringUtils::getEditDistance(s, query_ref, case_sensitive, '*', '?'); - - ans.emplace_back(s, distance); + + std::string value = m_map.find(s)->second; + if (ans_map.count(value)) + ans_map[value] = std::min(ans_map[value], distance); + else + ans_map[value] = distance; } + for (const auto& p: ans_map) + ans.emplace_back(p.first, p.second); std::sort(ans.begin(), ans.end(), [](const std::pair& a, const std::pair& b) -> bool { diff --git a/src/utils/set_typo_fixer.hpp b/src/utils/set_typo_fixer.hpp index 5e27264bb5f..f44b598d235 100644 --- a/src/utils/set_typo_fixer.hpp +++ b/src/utils/set_typo_fixer.hpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2021 kimden +// Copyright (C) 2021-2022 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -26,20 +26,25 @@ #include #include #include +#include // A lazy class that stores a set of strings. // For a query string, it finds exactly the same string in the set // if it exists, otherwise iterates over the set and suggests to you // the closest string according to edit distance. +// You can also use it as a map after you found +// the closest key. class SetTypoFixer { private: - std::multiset m_set; + std::multiset m_set; + std::map m_map; public: - void add(const std::string& value); - void remove(const std::string& value); - std::vector> getClosest( - const std::string& query, int count = 3, bool case_sensitive = true) const; + void add(const std::string& key); + void add(const std::string& key, const std::string& value); + void remove(const std::string& key); + std::vector> getClosest( + const std::string& query, int count = 3, bool case_sensitive = true) const; }; #endif // SET_TYPO_FIXER_HPP From c7398fe9757fbb82fd08dc988306f6e88272b96f Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 14 Feb 2022 21:17:32 +0300 Subject: [PATCH 198/830] Suggest typo fixes for tracks (but don't take played mode into account yet) --- src/network/protocols/command_manager.cpp | 59 ++++++++++++++++++++++- src/network/protocols/command_manager.hpp | 2 + 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 6e7a0deca1d..3be1242e164 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -57,7 +57,7 @@ // #include "race/race_manager.hpp" // #include "tracks/check_manager.hpp" // #include "tracks/track.hpp" -// #include "tracks/track_manager.hpp" +#include "tracks/track_manager.hpp" #include "utils/file_utils.hpp" #include "utils/log.hpp" #include "utils/random_generator.hpp" @@ -328,12 +328,49 @@ void CommandManager::initCommands() } // initCommands // ======================================================================== +void CommandManager::initAssets() +{ + auto all_t = track_manager->getAllTrackIdentifiers(); + std::map what_exists; + for (std::string& s: all_t) + { + if (StringUtils::startsWith(s, "addon_")) + what_exists[s.substr(6)] |= 2; + else + what_exists[s] |= 1; + } + for (const auto& p: what_exists) + { + if (p.second != 3) + { + bool is_addon = (p.second == 2); + std::string value = (is_addon ? "addon_" : "") + p.first; + m_stf_all_maps.add(p.first, value); + m_stf_all_maps.add("addon_" + p.first, value); + if (is_addon) + { + m_stf_addon_maps.add(p.first, value); + m_stf_addon_maps.add("addon_" + p.first, value); + } + } + else + { + m_stf_all_maps.add(p.first, p.first); + m_stf_all_maps.add("addon_" + p.first, "addon_" + p.first); + m_stf_addon_maps.add(p.first, "addon_" + p.first); + m_stf_addon_maps.add("addon_" + p.first, "addon_" + p.first); + } + } +} // initAssets +// ======================================================================== + CommandManager::CommandManager(ServerLobby* lobby): m_lobby(lobby) { if (!lobby) return; initCommands(); + initAssets(); } // CommandManager // ======================================================================== @@ -924,7 +961,10 @@ void CommandManager::process_checkaddon(Context& context) error(context); return; } - std::string id = "addon_" + argv[1]; + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + 1, m_stf_addon_maps, 3, false, true)) + return; + std::string id = argv[1]; const unsigned HAS_KART = 1; const unsigned HAS_MAP = 2; @@ -1107,11 +1147,17 @@ void CommandManager::process_pha(Context& context) error(context); return; } + + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + 1, m_stf_addon_maps, 3, false, true)) + return; if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_present_users, 3, false, false)) return; std::string addon_id = argv[1]; + if (StringUtils::startsWith(addon_id, "addon_")) + addon_id = addon_id.substr(6); std::string player_name = argv[2]; std::shared_ptr player_peer = STKHost::get()->findPeerByName( StringUtils::utf8ToWide(player_name)); @@ -1614,6 +1660,9 @@ void CommandManager::process_record(Context& context) return; } bool error = false; + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + 1, m_stf_all_maps, 3, false, true)) + return; std::string track_name = argv[1]; std::string mode_name = (argv[2] == "t" || argv[2] == "tt" || argv[2] == "time-trial" || argv[2] == "timetrial" ? @@ -1755,6 +1804,9 @@ void CommandManager::process_queue(Context& context) error(context); return; } + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + 2, m_stf_all_maps, 3, false, false)) + return; m_lobby->m_tracks_queue.push_back(argv[2]); std::string msg = "Pushed " + argv[2] + " to the back of queue, current queue size: " @@ -1769,6 +1821,9 @@ void CommandManager::process_queue(Context& context) error(context); return; } + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + 2, m_stf_all_maps, 3, false, false)) + return; m_lobby->m_tracks_queue.push_front(argv[2]); std::string msg = "Pushed " + argv[2] + " to the front of queue, current queue size: " diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index cc9a224f2b3..be246bb43c8 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -187,6 +187,8 @@ class CommandManager void initCommandsInfo(); void initCommands(); + void initAssets(); + int getCurrentModeScope(); int getCurrentStateScope(); From 68e0e994fba69fa030e10b8c21132c6a175c33f5 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 17 Feb 2022 01:44:41 +0300 Subject: [PATCH 199/830] Fix crash for ownerless server no-one-can-play situation --- src/network/protocols/server_lobby.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 163914238b1..eb866d8f653 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2960,12 +2960,14 @@ void ServerLobby::startSelection(const Event *event) // // Disable always spectate peers if no players join the game if (!has_peer_plays_game) { - // The always spectating code will probably behave kinda weird with - // spectating commands, I'll try to fix it later but beware - Log::warn("ServerLobby", - "An attempt to start a game while no one can play."); - std::string msg = "No one can play!"; - sendStringToPeer(msg, event->getPeer()); + if (event) + { + // inside if to not produce log spam for ownerless + Log::warn("ServerLobby", + "An attempt to start a game while no one can play."); + std::string msg = "No one can play!"; + sendStringToPeer(msg, event->getPeer()); + } addWaitingPlayersToGame(); return; // for (STKPeer* peer : always_spectate_peers) From 55b67e45761667507f54837c74d4cc9216423758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Eichler?= <2162327+heuchi@users.noreply.github.com> Date: Sat, 5 Mar 2022 19:33:51 +0100 Subject: [PATCH 200/830] Punish use of anchor (anvil) against teammates in Team GP (#13) --- src/items/powerup.cpp | 7 ++++ src/network/protocols/server_lobby.cpp | 58 ++++++++++++++++++++++++++ src/network/protocols/server_lobby.hpp | 2 + 3 files changed, 67 insertions(+) diff --git a/src/items/powerup.cpp b/src/items/powerup.cpp index ef92cbd50e0..4ca2ef88793 100644 --- a/src/items/powerup.cpp +++ b/src/items/powerup.cpp @@ -38,6 +38,8 @@ #include "utils/string_utils.hpp" #include "utils/log.hpp" //TODO: remove after debugging is done +#include "network/protocols/server_lobby.hpp" + //----------------------------------------------------------------------------- /** Constructor, stores the kart to which this powerup belongs. * \param kart The kart to which this powerup belongs. @@ -400,6 +402,11 @@ void Powerup::use() if(kart == m_kart) continue; if(kart->getPosition() == 1) { + // check if we are in team gp and hit a teammate and should punish the attacker + auto sl = LobbyProtocol::get(); + if(sl && !kart->hasFinishedRace()) + sl->handleAnvilHit(m_kart->getWorldKartId(), kart->getWorldKartId()); + kart->getAttachment()->set(Attachment::ATTACH_ANVIL, stk_config-> time2Ticks(kp->getAnvilDuration()) ); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index a1620f278ee..abd99fcaacc 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -9393,3 +9393,61 @@ void ServerLobby::handleSwatterHit(unsigned int ownerID, unsigned int victimID, m_teammate_swatter_punish.push_back(owner); } } + +void ServerLobby::handleAnvilHit(unsigned int ownerID, unsigned int victimID) +{ + const std::string ownername = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(ownerID).getPlayerName()); + const int ownerTeam = m_team_for_player[ownername]; + if (ownerTeam == 0) + return; + + const std::string victimname = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(victimID).getPlayerName()); + const int victimTeam = m_team_for_player[victimname]; + if (victimTeam != ownerTeam) + return; + + AbstractKart *owner = World::getWorld()->getKart(ownerID); + + // should we tell the world? + if (showTeamMateHits()) + { + std::string msg = ServerConfig::m_teammate_hit_msg_prefix; + msg += ownername; + msg += " just gave an anchor to teammate "; + msg += victimname; + sendTeamMateHitMsg(msg); + } + if (useTeamMateHitMode()) + { + if (owner->getAttachment()->getType() == Attachment::ATTACH_BOMB) + { + // make bomb explode + owner->getAttachment()->update(10000); + } + else + { + if (owner->isShielded()) + { + // if owner is shielded, take away shield + // since the anvil will also destroy the shield of the victim + // we also punish this severely + owner->decreaseShieldTime(); + } + + // now give anvil to owner + int left_over_ticks = 0; + // if owner already has an anvil or a parachute, make new anvil last longer + if (owner->getAttachment()->getType() == Attachment::ATTACH_ANVIL + || owner->getAttachment()->getType() == Attachment::ATTACH_PARACHUTE) + { + left_over_ticks = owner->getAttachment()->getTicksLeft(); + } + owner->getAttachment()->set(Attachment::ATTACH_ANVIL, + stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) + left_over_ticks); + // the powerup anvil is very strong, copy these values (from powerup.cpp) + owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor() * 0.5f); + } + } +} diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index d744e971fec..c3f6a5ad4e6 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -633,6 +633,8 @@ class ServerLobby : public LobbyProtocol // handle swatters void handleSwatterHit(unsigned int ownerID, unsigned int victimID, bool success, bool has_hit_kart, uint16_t ticks_active); + // handle anvil + void handleAnvilHit(unsigned int ownerID, unsigned int victimID); void sendTeamMateHitMsg(std::string& s); bool showTeamMateHits() const { return m_show_teammate_hits; } From 4131d6db6f4331c84a5c6c8419c6468154f6cf68 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 15 Mar 2022 13:30:34 +0300 Subject: [PATCH 201/830] Fix autospectator's screen on selection start; try to fix bad cases of /spectate-ing after the selection start --- src/network/protocols/command_manager.cpp | 20 ++++++++++++++++++-- src/network/protocols/server_lobby.cpp | 8 +++++--- src/network/protocols/server_lobby.hpp | 2 ++ src/network/stk_peer.cpp | 1 + src/network/stk_peer.hpp | 11 +++++++++++ 5 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 3be1242e164..ae75730b384 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -797,6 +797,10 @@ void CommandManager::process_spectate(Context& context) return; } + bool selection_started = (m_lobby->m_state.load() >= ServerLobby::SELECTING); + bool no_racing_yet = (m_lobby->m_state.load() < ServerLobby::RACING); +// if (selection_started) +// m_lobby->erasePeerReady(peer); if (argv[1] == "1") { if (m_lobby->m_process_type == PT_CHILD && @@ -806,10 +810,22 @@ void CommandManager::process_spectate(Context& context) m_lobby->sendStringToPeer(msg, peer); return; } - peer->setAlwaysSpectate(ASM_COMMAND); + peer->setDefaultAlwaysSpectate(ASM_COMMAND); + if (!selection_started || !no_racing_yet) + peer->setAlwaysSpectate(ASM_COMMAND); } else - peer->setAlwaysSpectate(ASM_NONE); + { + peer->setDefaultAlwaysSpectate(ASM_NONE); + if (!selection_started || !no_racing_yet) + peer->setAlwaysSpectate(ASM_NONE); + else + { + m_lobby->erasePeerReady(peer); + peer->setAlwaysSpectate(ASM_NONE); + peer->setWaitingForGame(true); + } + } m_lobby->updateServerOwner(true); m_lobby->updatePlayerList(); } // process_spectate diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 8b4a5a86aa8..65e3f885791 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3167,7 +3167,8 @@ void ServerLobby::startSelection(const Event *event) for (auto& profile : p->getPlayerProfiles()) { if (remaining.count( - StringUtils::wideToUtf8(profile->getName())) != 0) + StringUtils::wideToUtf8(profile->getName())) != 0 + && !p->isWaitingForGame()) { return true; } @@ -3208,7 +3209,8 @@ void ServerLobby::startSelection(const Event *event) for (auto& profile : p->getPlayerProfiles()) { if (remaining.count( - StringUtils::wideToUtf8(profile->getName())) != 0) + StringUtils::wideToUtf8(profile->getName())) != 0 + && !p->isWaitingForGame()) { return false; } @@ -3221,7 +3223,7 @@ void ServerLobby::startSelection(const Event *event) STKHost::get()->sendPacketToAllPeersWith( [this](STKPeer* p) -> bool { - return canRace(p); + return canRace(p) && !p->isWaitingForGame(); }, ns, /*reliable*/true); delete ns; } diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 595370d79ec..5078ba978cc 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -661,6 +661,8 @@ class ServerLobby : public LobbyProtocol void setTemporaryTeam(const std::string& username, std::string& arg); void clearTemporaryTeams(); void resetGrandPrix(); + void erasePeerReady(std::shared_ptr peer) + { m_peers_ready.erase(peer); } }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/network/stk_peer.cpp b/src/network/stk_peer.cpp index b42a09172fc..bca21c598a1 100644 --- a/src/network/stk_peer.cpp +++ b/src/network/stk_peer.cpp @@ -46,6 +46,7 @@ STKPeer::STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id) m_rejoin_time = m_connected_time; m_validated.store(false); m_always_spectate.store(ASM_NONE); + m_default_always_spectate.store(ASM_NONE); m_average_ping.store(0); m_packet_loss.store(0); m_waiting_for_game.store(true); diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index b397734ba89..068970a2c50 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -94,6 +94,8 @@ class STKPeer : public NoCopy std::atomic m_always_spectate; + std::atomic m_default_always_spectate; + /** Host id of this peer. */ uint32_t m_host_id; @@ -320,6 +322,13 @@ class STKPeer : public NoCopy m_always_spectate.store(mode); } // ------------------------------------------------------------------------ + void setDefaultAlwaysSpectate(AlwaysSpectateMode mode) + { + if (m_default_always_spectate.load() == ASM_COMMAND && mode == ASM_NONE) + m_rejoin_time = StkTime::getMonoTimeMs(); + m_default_always_spectate.store(mode); + } + // ------------------------------------------------------------------------ bool alwaysSpectate() const { return m_always_spectate.load() != ASM_NONE; } // ------------------------------------------------------------------------ @@ -335,6 +344,8 @@ class STKPeer : public NoCopy { if (m_always_spectate.load() == ASM_FULL) m_always_spectate.store(ASM_NONE); + if (m_always_spectate.load() != m_default_always_spectate.load()) + m_always_spectate.store(m_default_always_spectate.load()); } // ------------------------------------------------------------------------ bool isAngryHost() const { return m_angry_host.load(); } From 2a40665d2fc19a9580d3efa31bba1993635876e1 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 15 Mar 2022 17:14:20 +0300 Subject: [PATCH 202/830] Apply tournament game length from config everywhere --- src/network/protocols/command_manager.cpp | 2 +- src/network/protocols/server_lobby.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index ae75730b384..4a81d904e54 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2286,7 +2286,7 @@ void CommandManager::process_game(Context& context) m_lobby->sendStringToPeer(msg, peer); return; } - int length = 10; + int length = m_lobby->m_tournament_length; if (argv.size() >= 3) { bool ok = StringUtils::parseString(argv[2], &length); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 65e3f885791..463d61e5d07 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3094,7 +3094,7 @@ void ServerLobby::startSelection(const Event *event) { if (ServerConfig::m_soccer_tournament) { - m_default_vote->m_num_laps = 10; + m_default_vote->m_num_laps = m_tournament_length; m_default_vote->m_reverse = false; } else From 8449c95d2288db9a70eca957c0929cb0e4e9e2e7 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 15 Mar 2022 18:09:32 +0300 Subject: [PATCH 203/830] Allow no timer for ownerless for the cost of ready button, change it for soccer-tournament --- src/network/game_setup.cpp | 2 +- src/network/protocols/server_lobby.cpp | 13 ++++++++++--- src/network/server_config.cpp | 3 ++- src/network/server_config.hpp | 3 ++- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/network/game_setup.cpp b/src/network/game_setup.cpp index 6342c0d1744..e5833b03d73 100644 --- a/src/network/game_setup.cpp +++ b/src/network/game_setup.cpp @@ -136,7 +136,7 @@ void GameSetup::addServerInfo(NetworkString* ns) if (ServerConfig::m_owner_less) { ns->addUInt8(ServerConfig::m_min_start_game_players) - .addFloat(ServerConfig::m_start_game_counter); + .addFloat(std::max(0.0f, ServerConfig::m_start_game_counter)); } else ns->addUInt8(0).addFloat(0.0f); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 463d61e5d07..3eb7ceed442 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1790,9 +1790,16 @@ void ServerLobby::asynchronousUpdate() m_game_setup->isGrandPrixStarted()) && m_timeout.load() == std::numeric_limits::max()) { - m_timeout.store((int64_t)StkTime::getMonoTimeMs() + - (int64_t) - (ServerConfig::m_start_game_counter * 1000.0f)); + if (ServerConfig::m_start_game_counter >= -1e-5) + { + m_timeout.store((int64_t)StkTime::getMonoTimeMs() + + (int64_t) + (ServerConfig::m_start_game_counter * 1000.0f)); + } + else + { + m_timeout.store(std::numeric_limits::max()); + } } else if ((int)players < ServerConfig::m_min_start_game_players && !m_game_setup->isGrandPrixStarted()) diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index b06416f2d1c..8443b0898c1 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -401,7 +401,8 @@ void loadServerLobbyFromConfig() if (m_owner_less) { m_min_start_game_players = 1; - m_start_game_counter = 1000001; + m_start_game_counter = -1; +// m_start_game_counter = 1000001; } else { diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 10d7ea1d656..c607f207858 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -214,7 +214,8 @@ namespace ServerConfig SERVER_CFG_DEFAULT(FloatServerConfigParam(60.0f, "start-game-counter", "Time to wait before entering kart selection screen " "if satisfied min-start-game-players below for owner less or ranked " - "server.")); + "server. Negative to disable the timer, you will need to use /start " + "then instead of the button.")); SERVER_CFG_PREFIX FloatServerConfigParam m_official_karts_threshold SERVER_CFG_DEFAULT(FloatServerConfigParam(1.0f, From c1ba9eccfcd4ee9d5609be2603a00d3b4879cd0c Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 16 Mar 2022 01:27:50 +0300 Subject: [PATCH 204/830] Allow specifying soccer-tournament game time in seconds (with minutes timer) --- src/network/protocols/command_manager.cpp | 25 ++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 4a81d904e54..792a4aa5a44 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2269,6 +2269,7 @@ void CommandManager::process_game(Context& context) std::string peer_username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); int old_game = m_lobby->m_tournament_game; + int addition = 0; if (argv.size() < 2) { ++m_lobby->m_tournament_game; @@ -2290,13 +2291,30 @@ void CommandManager::process_game(Context& context) if (argv.size() >= 3) { bool ok = StringUtils::parseString(argv[2], &length); - if (!ok || length <= 0) + if (!ok || length < 0) { error(context); return; } } m_lobby->m_fixed_lap = length; + if (argv.size() >= 4) + { + bool ok = StringUtils::parseString(argv[3], &addition); + if (!ok || addition < 0 || addition > 59) + { + std::string msg = "Please specify a correct number. " + "Format: /game [number] [length] [0..59 additional seconds]"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + m_lobby->m_extra_seconds = 0.0f; + if (addition > 0) { + m_lobby->m_extra_seconds = 60.0f - addition; + } + } else { + m_lobby->m_extra_seconds = 0.0f; + } } if (m_lobby->tournamentColorsSwapped(m_lobby->m_tournament_game) ^ m_lobby->tournamentColorsSwapped(old_game)) @@ -2307,6 +2325,11 @@ void CommandManager::process_game(Context& context) std::string msg = StringUtils::insertValues( "Ready to start game %d for %d ", m_lobby->m_tournament_game, m_lobby->m_fixed_lap) + (m_lobby->tournamentGoalsLimit(m_lobby->m_tournament_game) ? "goals" : "minutes"); + if (!m_lobby->tournamentGoalsLimit(m_lobby->m_tournament_game) && addition > 0) + { + msg += " " + std::to_string(addition) + " seconds"; + ++m_lobby->m_fixed_lap; + } m_lobby->sendStringToAllPeers(msg); Log::info("CommandManager", "SoccerMatchLog: Game number changed from %d to %d", old_game, m_lobby->m_tournament_game); From ca5195d428c4bbe6fb51a1d5c76b71b73b446aa5 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 16 Mar 2022 01:57:44 +0300 Subject: [PATCH 205/830] Don't change soccer-tournament game number if something failed in /game command --- src/network/protocols/command_manager.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 792a4aa5a44..04c293cee0b 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2277,9 +2277,11 @@ void CommandManager::process_game(Context& context) m_lobby->m_tournament_game = 0; m_lobby->m_fixed_lap = ServerConfig::m_fixed_lap_count; } else { - if (!StringUtils::parseString(argv[1], &m_lobby->m_tournament_game) - || m_lobby->m_tournament_game < 0 - || m_lobby->m_tournament_game >= m_lobby->m_tournament_max_games) + int new_game_number; + int new_length = m_lobby->m_tournament_length; + if (!StringUtils::parseString(argv[1], &new_game_number) + || new_game_number < 0 + || new_game_number >= m_lobby->m_tournament_max_games) { std::string msg = "Please specify a correct number. " "Format: /game [number 0.." @@ -2287,17 +2289,15 @@ void CommandManager::process_game(Context& context) m_lobby->sendStringToPeer(msg, peer); return; } - int length = m_lobby->m_tournament_length; if (argv.size() >= 3) { - bool ok = StringUtils::parseString(argv[2], &length); - if (!ok || length < 0) + bool ok = StringUtils::parseString(argv[2], &new_length); + if (!ok || new_length < 0) { error(context); return; } } - m_lobby->m_fixed_lap = length; if (argv.size() >= 4) { bool ok = StringUtils::parseString(argv[3], &addition); @@ -2315,6 +2315,8 @@ void CommandManager::process_game(Context& context) } else { m_lobby->m_extra_seconds = 0.0f; } + m_lobby->m_tournament_game = new_game_number; + m_lobby->m_fixed_lap = new_length; } if (m_lobby->tournamentColorsSwapped(m_lobby->m_tournament_game) ^ m_lobby->tournamentColorsSwapped(old_game)) From 4a865df29af0ba4808162f2e6b6349df7b0bab6f Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 16 Mar 2022 03:56:13 +0300 Subject: [PATCH 206/830] Show Grand Prix progress in /standings gp --- src/network/protocols/server_lobby.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3eb7ceed442..9f6790e22db 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7177,7 +7177,7 @@ void ServerLobby::loadTracksQueueFromConfig() std::string ServerLobby::getGrandPrixStandings(bool showIndividual, bool showTeam) const { std::stringstream response; - response << "Grand Prix standings\n"; + response << "Grand Prix standings"; if (!showIndividual && !showTeam) { @@ -7187,6 +7187,13 @@ std::string ServerLobby::getGrandPrixStandings(bool showIndividual, bool showTea showTeam = true; } + uint8_t passed = (uint8_t)m_game_setup->getAllTracks().size(); + uint8_t total = m_game_setup->getExtraServerInfo(); + if (passed != 0) + response << " after " << (int)passed << " of " << (int)total << " games:\n"; + else + response << ", " << (int)total << " games:\n"; + if (showIndividual) { std::vector> results; From d8d1bea81423de919820269537b95435f0978455 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 19 Mar 2022 02:41:36 +0300 Subject: [PATCH 207/830] Fix some documentation in server config --- src/network/server_config.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index c607f207858..d7032f4003a 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -104,8 +104,7 @@ namespace ServerConfig "Game mode in server, 0 is normal race (grand prix), " "1 is time trial (grand prix), 3 is normal race, " "4 time trial, 6 is soccer, 7 is free-for-all and " - "8 is capture the flag. Notice: grand prix server doesn't " - "allow for players to join and wait for ongoing game.")); + "8 is capture the flag.")); SERVER_CFG_PREFIX IntServerConfigParam m_server_difficulty SERVER_CFG_DEFAULT(IntServerConfigParam(0, "server-difficulty", @@ -661,7 +660,8 @@ namespace ServerConfig "fixed 0 1 10 8 6 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "grand-prix-scoring", "A custom Grand Prix scoring system to be used, " - "empty for default.")); + "should have format 'type int int int int ...', where " + "type is either 'inc' or 'fixed'.")); SERVER_CFG_PREFIX StringServerConfigParam m_white_list SERVER_CFG_DEFAULT(StringServerConfigParam("", From 92114ce28cd2521be7c5894911eca495c7d8f322 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 19 Mar 2022 02:54:33 +0300 Subject: [PATCH 208/830] Fix crashing isSoccerGoalTarget call --- src/network/protocols/command_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 04c293cee0b..7c11571c547 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -694,7 +694,7 @@ void CommandManager::process_config(Context& context) const auto& argv = context.m_argv; int difficulty = m_lobby->getDifficulty(); int mode = m_lobby->getGameMode(); - bool goal_target = m_lobby->isSoccerGoalTarget(); + bool goal_target = (m_lobby->m_game_setup->hasExtraSeverInfo() ? m_lobby->isSoccerGoalTarget() : false); // bool gp = false; std::vector> mode_aliases = { {"m0"}, From 3650bab8ea2e4ef4b0f834bc46d254031ea29ba8 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 20 Mar 2022 21:33:11 +0300 Subject: [PATCH 209/830] Try to add /result for soccer ongoing game, rename some functions --- data/commands.xml | 5 +++ src/modes/soccer_world.cpp | 37 +++++++++++++++++++---- src/modes/soccer_world.hpp | 6 +++- src/network/protocols/command_manager.cpp | 24 ++++++++++++++- src/network/protocols/command_manager.hpp | 1 + 5 files changed, 65 insertions(+), 8 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index 37eabc95ec1..e1f7a509a6a 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -359,6 +359,11 @@ permissions="everyone" description="Displays server time." /> + SoccerWorld::getCount() const { + int red = (int)m_red_scorers.size() - m_bad_red_goals + + m_init_red_goals; + int blue = (int)m_blue_scorers.size() - m_bad_blue_goals + + m_init_blue_goals; + return std::make_pair(red, blue); +} // getCount +// ---------------------------------------------------------------------------- + +void SoccerWorld::tellCountToEveryoneInGame() const { auto peers = STKHost::get()->getPeers(); NetworkString* chat = new NetworkString(PROTOCOL_LOBBY_ROOM); chat->addUInt8(17); // LE_CHAT chat->setSynchronous(true); - int real_red = (int)m_red_scorers.size() - m_bad_red_goals - + m_init_red_goals; - int real_blue = (int)m_blue_scorers.size() - m_bad_blue_goals - + m_init_blue_goals; + auto real_score = getCount(); + int real_red = real_score.first; + int real_blue = real_score.second; std::string real_count = std::to_string(real_red) + " : " + std::to_string(real_blue); chat->encodeString16(StringUtils::utf8ToWide(real_count)); @@ -1315,6 +1323,23 @@ void SoccerWorld::tellCount() const peer->sendPacket(chat, true/*reliable*/); delete chat; +} // tellCountToEveryoneInGame +// ---------------------------------------------------------------------------- +void SoccerWorld::tellCount(std::shared_ptr peer) const +{ + if (!peer->isValidated()) + return; + NetworkString* chat = new NetworkString(PROTOCOL_LOBBY_ROOM); + chat->addUInt8(17); // LE_CHAT + chat->setSynchronous(true); + auto real_score = getCount(); + int real_red = real_score.first; + int real_blue = real_score.second; + std::string real_count = + std::to_string(real_red) + " : " + std::to_string(real_blue); + chat->encodeString16(StringUtils::utf8ToWide(real_count)); + peer->sendPacket(chat, true/*reliable*/); + delete chat; } // tellCount // ---------------------------------------------------------------------------- @@ -1323,7 +1348,7 @@ void SoccerWorld::tellCountIfDiffers() const if (m_init_red_goals - m_bad_red_goals != 0 || m_init_blue_goals - m_bad_blue_goals != 0) { - tellCount(); + tellCountToEveryoneInGame(); } } // tellCountIfDiffers // ---------------------------------------------------------------------------- diff --git a/src/modes/soccer_world.hpp b/src/modes/soccer_world.hpp index 5135a6ddcd4..d8a561cf9a8 100644 --- a/src/modes/soccer_world.hpp +++ b/src/modes/soccer_world.hpp @@ -289,7 +289,11 @@ class SoccerWorld : public WorldWithRank // ------------------------------------------------------------------------ void setInitialCount(int red, int blue); // ------------------------------------------------------------------------ - void tellCount() const; + std::pair getCount() const; + // ------------------------------------------------------------------------ + void tellCountToEveryoneInGame() const; + // ------------------------------------------------------------------------ + void tellCount(std::shared_ptr peer) const; // ------------------------------------------------------------------------ void tellCountIfDiffers() const; // ------------------------------------------------------------------------ diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 7c11571c547..9ad75d3697e 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -281,6 +281,7 @@ void CommandManager::initCommands() if (!ServerConfig::m_only_host_riding) v.emplace_back("slots", &CM::process_slots, UP_HAMMER | PE_VOTED_NORMAL, MS_DEFAULT, SS_LOBBY); v.emplace_back("time", &CM::process_time, UP_EVERYONE); + v.emplace_back("result", &CM::process_result, UP_EVERYONE); v.emplace_back("addondownloadprogress", &CM::special, UP_EVERYONE); v.emplace_back("stopaddondownload", &CM::special, UP_EVERYONE); @@ -2580,7 +2581,7 @@ void CommandManager::process_init(Context& context) } SoccerWorld *sw = dynamic_cast(w); sw->setInitialCount(red, blue); - sw->tellCount(); + sw->tellCountToEveryoneInGame(); } // process_init // ======================================================================== @@ -2653,6 +2654,27 @@ void CommandManager::process_time(Context& context) } // process_time // ======================================================================== +void CommandManager::process_result(Context& context) +{ + auto& peer = context.m_peer; + std::string msg = ""; + if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) + { + SoccerWorld *sw = dynamic_cast(World::getWorld()); + if (sw) + { + sw->tellCount(peer); + return; + } + else + msg = "No game to show the score!"; + } + else + msg = "This command is not yet supported for this game mode"; + m_lobby->sendStringToPeer(msg, peer); +} // process_time +// ======================================================================== + void CommandManager::special(Context& context) { // This function is used as a function for /vote and possibly several diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index be246bb43c8..524984325ef 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -257,6 +257,7 @@ class CommandManager void process_test(Context& context); void process_slots(Context& context); void process_time(Context& context); + void process_result(Context& context); void special(Context& context); public: From d31fe3e04f8e0e0607a003bddc0372beecfcc97d Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 20 Mar 2022 22:51:28 +0300 Subject: [PATCH 210/830] Make /getaddons show addons for command invoker also --- src/network/protocols/command_manager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 9ad75d3697e..2ed8a3208a7 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -871,8 +871,10 @@ void CommandManager::process_addons(Context& context) int num_players = 0; for (auto peer : peers) { - if (!peer || !peer->isValidated() || peer->isWaitingForGame() - || !m_lobby->canRace(peer) || peer->isCommandSpectator()) + if (!peer || !peer->isValidated()) + continue; + if ((!more_own || peer != context.m_peer) && (peer->isWaitingForGame() + || !m_lobby->canRace(peer) || peer->isCommandSpectator())) continue; ++num_players; std::string username = StringUtils::wideToUtf8( From 28cf108aaec2e5acecef65a593a5f0457f254de1 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 24 Mar 2022 14:38:44 +0300 Subject: [PATCH 211/830] Make crowned start with button non-votable --- src/network/protocols/command_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 2ed8a3208a7..1fe078f5d03 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -677,7 +677,7 @@ void CommandManager::process_replay(Context& context) void CommandManager::process_start(Context& context) { - if (!ServerConfig::m_owner_less && (context.m_user_permissions & UP_HAMMER) == 0) + if (!ServerConfig::m_owner_less && (context.m_user_permissions & UP_CROWNED) == 0) { context.m_voting = true; } From 173fd8e9e35ed95df9c578047acf0f01a9899bec Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 11 May 2022 22:26:53 +0300 Subject: [PATCH 212/830] Allow changing whether a team can vote or no in soccer-tournament mode --- src/network/protocols/server_lobby.cpp | 33 ++++++++++++++++++++++---- src/network/protocols/server_lobby.hpp | 4 ++++ src/network/server_config.hpp | 2 +- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 9f6790e22db..9d096d04c06 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -5004,6 +5004,8 @@ void ServerLobby::handlePlayerVote(Event* event) if (isVotingOver()) return; + if (!canVote(event->getPeer())) return; + NetworkString& data = event->data(); PeerVote vote(data); Log::debug("ServerLobby", @@ -6966,17 +6968,18 @@ void ServerLobby::initTournamentPlayers() if (!fallback) { general = StringUtils::split(tokens[0], ' '); - if (general.size() < 4) + if (general.size() < 5) fallback = true; } if (fallback) { - Log::warn("ServerLobby", "Tournament rules not complete, fallback to default"); + Log::warn("ServerLobby", "Tournament rules are not complete, fallback to default"); general.clear(); general.push_back("nochat"); general.push_back("10"); general.push_back("GGGGT"); general.push_back("RRBBR"); + general.push_back("+++++"); tokens.clear(); tokens.push_back("nochat 10 GGGT RRBBR"); tokens.push_back(""); @@ -6984,7 +6987,7 @@ void ServerLobby::initTournamentPlayers() tokens.push_back("not %0"); tokens.push_back("not %0" " %1"); tokens.push_back(""); - ServerConfig::m_soccer_tournament_rules = "nochat 10 TTTTG RRBBR;" + ServerConfig::m_soccer_tournament_rules = "nochat 10 TTTTG RRBBR +++++;" ";;not %1;" "not %1 " "%2;;;"; @@ -7008,6 +7011,7 @@ void ServerLobby::initTournamentPlayers() m_tournament_colors = general[3]; m_tournament_max_games = std::min(general[2].length(), general[3].length()); m_tournament_max_games = std::min(m_tournament_max_games, (int)tokens.size() - 1); + m_tournament_votability = general[4]; m_tournament_arenas.resize(m_tournament_max_games, ""); for (int i = 0; i < m_tournament_max_games; i++) m_tournament_track_filters.emplace_back(tokens[i + 1]); @@ -7102,7 +7106,28 @@ bool ServerLobby::canRace(STKPeer* peer) const return false; return true; } // canRace - +//----------------------------------------------------------------------------- +bool ServerLobby::canVote(std::shared_ptr& peer) const +{ + return canVote(peer.get()); +} // canVote +//----------------------------------------------------------------------------- +bool ServerLobby::canVote(STKPeer* peer) const +{ + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + if (ServerConfig::m_soccer_tournament) { + bool first = m_tournament_red_players.count(username) > 0; + bool second = m_tournament_blue_players.count(username) > 0; + if (!first && !second) + return false; + char votable = m_tournament_votability[m_tournament_game]; + if (votable == '+') + return true; + return (votable == 'F' && first) || (votable == 'S' && second); + } + return true; +} // canVote //----------------------------------------------------------------------------- bool ServerLobby::hasHostRights(std::shared_ptr& peer) const { diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 5078ba978cc..dc58b9e7298 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -349,6 +349,8 @@ class ServerLobby : public LobbyProtocol std::string m_tournament_colors; + std::string m_tournament_votability; + std::vector m_tournament_arenas; std::vector m_tournament_track_filters; @@ -560,6 +562,8 @@ class ServerLobby : public LobbyProtocol void changeColors(); bool canRace(std::shared_ptr& peer) const; bool canRace(STKPeer* peer) const; + bool canVote(std::shared_ptr& peer) const; + bool canVote(STKPeer* peer) const; bool hasHostRights(std::shared_ptr& peer) const; bool hasHostRights(STKPeer* peer) const; std::vector getMissingTournamentAssets(std::shared_ptr& peer) const; diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index d7032f4003a..9f2b5907b6a 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -618,7 +618,7 @@ namespace ServerConfig "Use ## to hide the category from the player list.")); SERVER_CFG_PREFIX StringServerConfigParam m_soccer_tournament_rules - SERVER_CFG_DEFAULT(StringServerConfigParam("nochat 10 TTTTG RRBBR;" + SERVER_CFG_DEFAULT(StringServerConfigParam("nochat 10 TTTTG RRBBR +++++;" ";;not %1;" "not %1 " "%2;;;", From 7f16a8d71fc2b9d548bec157b84c25ccb19abe74 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 12 May 2022 02:53:31 +0300 Subject: [PATCH 213/830] Allow adding random and random addon maps to the queue, make it publicly visible while it's unclear whether it should be --- src/network/protocols/command_manager.cpp | 45 ++++++++++++++++++++--- src/network/protocols/command_manager.hpp | 3 ++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 1fe078f5d03..3238ab2bd0d 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -56,7 +56,7 @@ // #include "online/xml_request.hpp" // #include "race/race_manager.hpp" // #include "tracks/check_manager.hpp" -// #include "tracks/track.hpp" +#include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/file_utils.hpp" #include "utils/log.hpp" @@ -1823,6 +1823,10 @@ void CommandManager::process_queue(Context& context) error(context); return; } + if (argv[2] == "-") + argv[2] = getRandomMap(); + else if (argv[2] == "-addon") + argv[2] = getRandomAddonMap(); if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_all_maps, 3, false, false)) return; @@ -1830,7 +1834,7 @@ void CommandManager::process_queue(Context& context) std::string msg = "Pushed " + argv[2] + " to the back of queue, current queue size: " + std::to_string(m_lobby->m_tracks_queue.size()); - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToAllPeers(msg); m_lobby->updatePlayerList(); } else if (argv[1] == "push_front") @@ -1840,6 +1844,10 @@ void CommandManager::process_queue(Context& context) error(context); return; } + if (argv[2] == "-") + argv[2] = getRandomMap(); + else if (argv[2] == "-addon") + argv[2] = getRandomAddonMap(); if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_all_maps, 3, false, false)) return; @@ -1847,7 +1855,7 @@ void CommandManager::process_queue(Context& context) std::string msg = "Pushed " + argv[2] + " to the front of queue, current queue size: " + std::to_string(m_lobby->m_tracks_queue.size()); - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToAllPeers(msg); m_lobby->updatePlayerList(); } else if (argv[1] == "pop" || argv[1] == "pop_front") @@ -1864,7 +1872,7 @@ void CommandManager::process_queue(Context& context) msg += " current queue size: " + std::to_string(m_lobby->m_tracks_queue.size()); } - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToAllPeers(msg); m_lobby->updatePlayerList(); } else if (argv[1] == "pop_back") @@ -1881,7 +1889,7 @@ void CommandManager::process_queue(Context& context) msg += " current queue size: " + std::to_string(m_lobby->m_tracks_queue.size()); } - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToAllPeers(msg); m_lobby->updatePlayerList(); } } // process_queue @@ -2686,6 +2694,33 @@ void CommandManager::special(Context& context) } // special // ======================================================================== +std::string CommandManager::getRandomMap() const +{ + if (m_lobby->m_entering_kts.second.empty()) + return ""; + RandomGenerator rg; + std::set::iterator it = m_lobby->m_entering_kts.second.begin(); + std::advance(it, rg.get((int)m_lobby->m_entering_kts.second.size())); + return *it; +} // getRandomMap +// ======================================================================== + +std::string CommandManager::getRandomAddonMap() const +{ + std::vector items; + for (const std::string& s: m_lobby->m_entering_kts.second) { + Track* t = track_manager->getTrack(s); + if (t->isAddon()) + items.push_back(s); + } + if (items.empty()) + return ""; + RandomGenerator rg; + std::vector::iterator it = items.begin(); + std::advance(it, rg.get((int)items.size())); + return *it; +} // getRandomAddonMap +// ======================================================================== void CommandManager::addUser(std::string& s) { m_users.insert(s); diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 524984325ef..5f92544dcb1 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -260,6 +260,9 @@ class CommandManager void process_result(Context& context); void special(Context& context); + std::string getRandomMap() const; + std::string getRandomAddonMap() const; + public: CommandManager(ServerLobby* lobby = nullptr); From dd4a8120b7487bfa2f614e153cb76e2c50b06a47 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 12 May 2022 14:52:37 +0300 Subject: [PATCH 214/830] Select only filtered arenas for /queue push, /(more/get)addons --- src/network/protocols/command_manager.cpp | 26 ++++++++---- src/network/protocols/server_lobby.cpp | 51 +++++++++++++---------- src/network/protocols/server_lobby.hpp | 1 + 3 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 3238ab2bd0d..e860f8fc3e6 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -837,9 +837,11 @@ void CommandManager::process_addons(Context& context) auto& argv = context.m_argv; bool more = (argv[0] == "moreaddons"); bool more_own = (argv[0] == "getaddons"); + bool apply_filters = false; if (argv.size() == 1) { argv.push_back(""); + apply_filters = true; switch (m_lobby->m_game_mode.load()) { case 0: @@ -857,12 +859,16 @@ void CommandManager::process_addons(Context& context) break; } } - const std::set& from = + // removed const reference so that i can modify `from` + // without changing the original container, we copy everything anyway + std::set from = (argv[1] == "kart" ? m_lobby->m_addon_kts.first : (argv[1] == "track" ? m_lobby->m_addon_kts.second : (argv[1] == "arena" ? m_lobby->m_addon_arenas : /*argv[1] == "soccer" ?*/ m_lobby->m_addon_soccers ))); + if (apply_filters) + m_lobby->applyAllFilters(from); std::vector>> result; for (const std::string& s: from) result.push_back({s, {}}); @@ -2696,27 +2702,33 @@ void CommandManager::special(Context& context) std::string CommandManager::getRandomMap() const { - if (m_lobby->m_entering_kts.second.empty()) + std::set items; + for (const std::string& s: m_lobby->m_entering_kts.second) { + items.insert(s); + } + m_lobby->applyAllFilters(items); + if (items.empty()) return ""; RandomGenerator rg; - std::set::iterator it = m_lobby->m_entering_kts.second.begin(); - std::advance(it, rg.get((int)m_lobby->m_entering_kts.second.size())); + std::set::iterator it = items.begin(); + std::advance(it, rg.get((int)items.size())); return *it; } // getRandomMap // ======================================================================== std::string CommandManager::getRandomAddonMap() const { - std::vector items; + std::set items; for (const std::string& s: m_lobby->m_entering_kts.second) { Track* t = track_manager->getTrack(s); if (t->isAddon()) - items.push_back(s); + items.insert(s); } + m_lobby->applyAllFilters(items); if (items.empty()) return ""; RandomGenerator rg; - std::vector::iterator it = items.begin(); + std::set::iterator it = items.begin(); std::advance(it, rg.get((int)items.size())); return *it; } // getRandomAddonMap diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 9d096d04c06..a6b746e6330 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3031,27 +3031,8 @@ void ServerLobby::startSelection(const Event *event) else m_ai_count = 0; - if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) - { - auto it = m_available_kts.second.begin(); - while (it != m_available_kts.second.end()) - { - Track* t = track_manager->getTrack(*it); - if (t->getMaxArenaPlayers() < max_player) - { - it = m_available_kts.second.erase(it); - } - else - it++; - } - } - - m_global_filter.apply(max_player, m_available_kts.second); - if (ServerConfig::m_soccer_tournament) - { - m_tournament_track_filters[m_tournament_game].apply( - max_player, m_available_kts.second, m_tournament_arenas); - } + applyAllFilters(m_available_kts.second); + /* auto iter = m_available_kts.second.begin(); while (iter != m_available_kts.second.end()) { @@ -7919,3 +7900,31 @@ void ServerLobby::resetGrandPrix() updatePlayerList(); } // resetGrandPrix //----------------------------------------------------------------------------- + +void ServerLobby::applyAllFilters(std::set& maps) +{ + unsigned max_player = 0; + STKHost::get()->updatePlayers(&max_player); + if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) + { + auto it = maps.begin(); + while (it != maps.end()) + { + Track* t = track_manager->getTrack(*it); + if (t->getMaxArenaPlayers() < max_player) + { + it = maps.erase(it); + } + else + it++; + } + } + + m_global_filter.apply(max_player, maps); + if (ServerConfig::m_soccer_tournament) + { + m_tournament_track_filters[m_tournament_game].apply( + max_player, maps, m_tournament_arenas); + } +} // applyAllFilters +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index dc58b9e7298..e62f3795be7 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -667,6 +667,7 @@ class ServerLobby : public LobbyProtocol void resetGrandPrix(); void erasePeerReady(std::shared_ptr peer) { m_peers_ready.erase(peer); } + void applyAllFilters(std::set& maps); }; // class ServerLobby #endif // SERVER_LOBBY_HPP From 2b9e2addb84d74a3489c915bb306403b3271ff2c Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 17 May 2022 00:53:36 +0300 Subject: [PATCH 215/830] Do not print SoccerMatchLog message when role fails to be updated --- src/network/protocols/command_manager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index e860f8fc3e6..117198257d6 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2406,8 +2406,6 @@ void CommandManager::process_role(Context& context) } for (const std::string& username: changed_usernames) { - Log::info("CommandManager", "SoccerMatchLog: Role of %s changed to %s", - username.c_str(), role.c_str()); m_lobby->m_tournament_red_players.erase(username); m_lobby->m_tournament_blue_players.erase(username); m_lobby->m_tournament_referees.erase(username); @@ -2515,8 +2513,12 @@ void CommandManager::process_role(Context& context) } std::string msg; if (!fail) + { msg = StringUtils::insertValues( "Successfully changed role to %s for %s", role, username); + Log::info("CommandManager", "SoccerMatchLog: Role of %s changed to %s", + username.c_str(), role.c_str()); + } else { msg = StringUtils::insertValues( From 8829efce8f570657d4ad089821370c1fe7bad36c Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 17 May 2022 01:04:02 +0300 Subject: [PATCH 216/830] Try to avoid having no hourglass for tournament players who cannot play --- src/network/protocols/server_lobby.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index a6b746e6330..83061f8056b 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7065,8 +7065,11 @@ bool ServerLobby::canRace(STKPeer* peer) const std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); if (ServerConfig::m_soccer_tournament) - return m_tournament_red_players.count(username) > 0 || - m_tournament_blue_players.count(username) > 0; + { + if (m_tournament_red_players.count(username) == 0 && + m_tournament_blue_players.count(username) == 0) + return false; + } else if (m_spectators_by_limit.find(peer) != m_spectators_by_limit.end()) return false; From 352c8ae16454425152ed8566320dfedc1f4a7ece Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 24 May 2022 23:05:18 +0300 Subject: [PATCH 217/830] Fix some warnings --- src/network/protocols/command_manager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 117198257d6..55d9e0cc918 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -918,10 +918,10 @@ void CommandManager::process_addons(Context& context) result.clear(); std::string asking_username = StringUtils::wideToUtf8( context.m_peer->getPlayerProfiles()[0]->getName()); - for (int i = 0; i < result2.size(); ++i) + for (unsigned i = 0; i < result2.size(); ++i) { bool present = false; - for (int j = 0; j < result2[i].second.size(); ++j) + for (unsigned j = 0; j < result2[i].second.size(); ++j) { if (result2[i].second[j] == asking_username) { @@ -1601,7 +1601,7 @@ void CommandManager::process_standings(Context& context) bool isGnu = false; bool isGPTeams = false; bool isGPPlayers = false; - for (int i = 1; i < argv.size(); ++i) + for (unsigned i = 1; i < argv.size(); ++i) { if (argv[i] == "gp") isGP = true; From a9d74f9e952a9f76cc4b74419011a9ac37ed82a0 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 7 Jun 2022 13:20:56 +0300 Subject: [PATCH 218/830] Join the options for required maps for tournament and normal mode, don't remove the tournament role if player doesn't have all assets (something could be forgotten?) --- src/network/protocols/command_manager.cpp | 11 +++---- src/network/protocols/server_lobby.cpp | 36 +++++++++++------------ src/network/protocols/server_lobby.hpp | 4 +-- src/network/server_config.hpp | 6 ---- 4 files changed, 25 insertions(+), 32 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 55d9e0cc918..5ea19eed6d6 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2420,7 +2420,7 @@ void CommandManager::process_role(Context& context) StringUtils::utf8ToWide(username)); std::vector missing_assets; if (player_peer) - missing_assets = m_lobby->getMissingTournamentAssets(player_peer); + missing_assets = m_lobby->getMissingAssets(player_peer); bool fail = false; switch (role[0]) { @@ -2430,7 +2430,7 @@ void CommandManager::process_role(Context& context) if (!missing_assets.empty()) { fail = true; - break; +// break; } if (m_lobby->tournamentColorsSwapped(m_lobby->m_tournament_game)) { @@ -2458,7 +2458,7 @@ void CommandManager::process_role(Context& context) if (!missing_assets.empty()) { fail = true; - break; +// break; } if (m_lobby->tournamentColorsSwapped(m_lobby->m_tournament_game)) { @@ -2486,7 +2486,7 @@ void CommandManager::process_role(Context& context) if (!missing_assets.empty()) { fail = true; - break; +// break; } m_lobby->m_tournament_referees.insert(username); if (permanent) @@ -2522,7 +2522,8 @@ void CommandManager::process_role(Context& context) else { msg = StringUtils::insertValues( - "Failed to change role to %s for %s - missing assets:", role, username); + "Successfully changed role to %s for %s, but there are missing assets:", + role, username); for (unsigned i = 0; i < missing_assets.size(); i++) { if (i) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 83061f8056b..72312ac7b10 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7372,23 +7372,21 @@ void ServerLobby::initAvailableTracks() ServerConfig::m_must_have_tracks_string, ' ', false); m_play_requirement_tracks = StringUtils::split( ServerConfig::m_play_requirement_tracks_string, ' ', false); - m_tournament_must_have_tracks = StringUtils::split( - ServerConfig::m_soccer_tournament_enforced_tracks_string, ' ', false); } // initAvailableTracks //----------------------------------------------------------------------------- -std::vector ServerLobby::getMissingTournamentAssets(std::shared_ptr& peer) const +std::vector ServerLobby::getMissingAssets(std::shared_ptr& peer) const { - return getMissingTournamentAssets(peer.get()); -} // getMissingTournamentAssets + return getMissingAssets(peer.get()); +} // getMissingAssets //----------------------------------------------------------------------------- -std::vector ServerLobby::getMissingTournamentAssets(STKPeer* peer) const +std::vector ServerLobby::getMissingAssets(STKPeer* peer) const { std::vector ans; - for (const std::string& required_track : m_tournament_must_have_tracks) + for (const std::string& required_track : m_play_requirement_tracks) if (peer->getClientAssets().second.count(required_track) == 0) ans.push_back(required_track); return ans; -} // getMissingTournamentAssets +} // getMissingAssets //----------------------------------------------------------------------------- void ServerLobby::updateTournamentRole(STKPeer* peer) { @@ -7400,16 +7398,16 @@ void ServerLobby::updateTournamentRole(STKPeer* peer) peer->getPlayerProfiles()[0]->getName()); bool erased_from_tournament_roles = false; std::vector missing_assets; - missing_assets = getMissingTournamentAssets(peer); - if (!missing_assets.empty()) - { - erased_from_tournament_roles |= m_tournament_red_players.count(utf8_online_name) > 0; - erased_from_tournament_roles |= m_tournament_blue_players.count(utf8_online_name) > 0; - erased_from_tournament_roles |= m_tournament_referees.count(utf8_online_name) > 0; - m_tournament_red_players.erase(utf8_online_name); - m_tournament_blue_players.erase(utf8_online_name); - m_tournament_referees.erase(utf8_online_name); - } + missing_assets = getMissingAssets(peer); +// if (!missing_assets.empty()) +// { +// erased_from_tournament_roles |= m_tournament_red_players.count(utf8_online_name) > 0; +// erased_from_tournament_roles |= m_tournament_blue_players.count(utf8_online_name) > 0; +// erased_from_tournament_roles |= m_tournament_referees.count(utf8_online_name) > 0; +// m_tournament_red_players.erase(utf8_online_name); +// m_tournament_blue_players.erase(utf8_online_name); +// m_tournament_referees.erase(utf8_online_name); +// } for (unsigned i = 0; i < peer->getPlayerProfiles().size(); i++) { auto player = peer->getPlayerProfiles()[i]; @@ -7431,7 +7429,7 @@ void ServerLobby::updateTournamentRole(STKPeer* peer) } if (erased_from_tournament_roles) { - std::string msg = "You are now spectator because you lack the following assets:"; + std::string msg = "You lack the following assets:"; for (unsigned i = 0; i < missing_assets.size(); i++) { if (i) diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index e62f3795be7..169add7f936 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -566,8 +566,8 @@ class ServerLobby : public LobbyProtocol bool canVote(STKPeer* peer) const; bool hasHostRights(std::shared_ptr& peer) const; bool hasHostRights(STKPeer* peer) const; - std::vector getMissingTournamentAssets(std::shared_ptr& peer) const; - std::vector getMissingTournamentAssets(STKPeer* peer) const; + std::vector getMissingAssets(std::shared_ptr& peer) const; + std::vector getMissingAssets(STKPeer* peer) const; void loadTracksQueueFromConfig(); std::string getGrandPrixStandings(bool showIndividual = false, bool showTeam = true) const; void loadCustomScoring(); diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 9f2b5907b6a..5188db14964 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -625,12 +625,6 @@ namespace ServerConfig "soccer-tournament-rules", "A string specifying the match format.")); - SERVER_CFG_PREFIX StringServerConfigParam m_soccer_tournament_enforced_tracks_string - SERVER_CFG_DEFAULT(StringServerConfigParam("", - "soccer-tournament-enforced-tracks", - "List of tracks tournament players should have to enter " - "(doesn't apply to spectators).")); - SERVER_CFG_PREFIX StringServerConfigParam m_incompatible_advice SERVER_CFG_DEFAULT(StringServerConfigParam("", "incompatible-advice", From 81fef890fb13a2b7b1f61c7c3bf91e5ce799e696 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 7 Jun 2022 18:41:06 +0300 Subject: [PATCH 219/830] Try to set hourglass only to those players who waits for a game in the lobby --- src/network/protocols/server_lobby.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 72312ac7b10..0e007d58d5a 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6477,7 +6477,7 @@ std::set& ServerLobby::getSpectatorsByLimit(bool update) for (int i = 0; i < (int)peers.size(); ++i) { - if (!peers[i]->isValidated() || peers[i]->isCommandSpectator()) + if (!peers[i]->isValidated()) { swap(peers[i], peers.back()); peers.pop_back(); @@ -6490,38 +6490,40 @@ std::set& ServerLobby::getSpectatorsByLimit(bool update) const std::shared_ptr& b) { return a->getRejoinTime() < b->getRejoinTime(); }); + unsigned player_count = 0; if (m_state.load() >= RACING) { for (auto &peer : peers) if (peer->isSpectator()) ingame_players -= (int)peer->getPlayerProfiles().size(); + player_count = ingame_players; } - unsigned player_count = 0; for (unsigned i = 0; i < peers.size(); i++) { auto& peer = peers[i]; if (!peer->isValidated()) continue; + bool ignore = false; if (m_state.load() < RACING) { if (peer->alwaysSpectate() || peer->isWaitingForGame()) - continue; - if (!canRace(peer)) + ignore = true; + else if (!canRace(peer)) { m_spectators_by_limit.insert(peer.get()); - continue; + ignore = true; } - player_count += (unsigned)peer->getPlayerProfiles().size(); - if (player_count > player_limit) - m_spectators_by_limit.insert(peer.get()); } else { - // if (peer->isSpectator()) - // continue; + if (!peer->isWaitingForGame()) + ignore = true; // we already counted them properly in ingame_players + } + if (!ignore) + { player_count += (unsigned)peer->getPlayerProfiles().size(); - if (/*peer->isWaitingForGame() && */(player_count > player_limit || ingame_players >= player_limit)) + if (player_count > player_limit) m_spectators_by_limit.insert(peer.get()); } } From 2580a21b3696afece4edc0f3c6167b4b4a1eb5f8 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 7 Jun 2022 19:49:34 +0300 Subject: [PATCH 220/830] Fix cat- not substituting the wildcard with player name --- src/network/protocols/command_manager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 5ea19eed6d6..1d670c5aa52 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2092,6 +2092,7 @@ void CommandManager::process_cat(Context& context) if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_present_users, 3, false, true)) return; + player = argv[2]; m_lobby->m_player_categories[category].erase(player); m_lobby->m_categories_for_player[player].erase(category); m_lobby->updatePlayerList(); From b5dd5c3aeb4adadb1656346659d85d4932bab352 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 7 Jun 2022 20:08:02 +0300 Subject: [PATCH 221/830] Minor cosmetic changes to code and messages --- src/network/protocols/command_manager.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 1d670c5aa52..f9522df0d87 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -475,7 +475,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) { auto response = it->second.process(m_users); int count = response.first; - std::string msg = username + " voted \"" + cmd + "\", there are " + std::to_string(count) + " such votes"; + std::string msg = username + " voted \"/" + cmd + "\", there are " + std::to_string(count) + " such votes"; m_lobby->sendStringToAllPeers(msg); auto res = response.second; if (!res.empty()) @@ -485,7 +485,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) std::string new_cmd = p.first + " " + p.second; auto new_argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); CommandManager::restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); - std::string msg = "Command \"" + new_cmd + "\" has been successfully voted"; + std::string msg = "Command \"/" + new_cmd + "\" has been successfully voted"; m_lobby->sendStringToAllPeers(msg); Context new_context(event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); execute(command, new_context); @@ -553,7 +553,7 @@ void CommandManager::update() std::string new_cmd = p.first + " " + p.second; auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '"', '\\'); CommandManager::restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); - std::string msg = "Command \"" + new_cmd + "\" has been successfully voted"; + std::string msg = "Command \"/" + new_cmd + "\" has been successfully voted"; m_lobby->sendStringToAllPeers(msg); auto& command = m_name_to_command[new_argv[0]]; // We don't know the event though it is only needed in @@ -1913,12 +1913,12 @@ void CommandManager::process_allowstart(Context& context) if (argv[1] == "0") { m_lobby->m_allowed_to_start = false; - msg = "Now starting a race is forbidden"; + msg = "Now starting a game is forbidden"; } else { m_lobby->m_allowed_to_start = true; - msg = "Now starting a race is allowed"; + msg = "Now starting a game is allowed"; } m_lobby->sendStringToPeer(msg, context.m_peer); } // process_allowstart @@ -2692,7 +2692,7 @@ void CommandManager::process_result(Context& context) else msg = "This command is not yet supported for this game mode"; m_lobby->sendStringToPeer(msg, peer); -} // process_time +} // process_result // ======================================================================== void CommandManager::special(Context& context) From 14262f09994ef6a5669587589c8f9aca1c1f6e40 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 29 Jun 2022 02:57:23 +0300 Subject: [PATCH 222/830] Try to add GP scoring based on gap to the leader --- src/modes/world_with_rank.cpp | 66 ++++++++++++++++++++++++++++++++--- src/modes/world_with_rank.hpp | 4 +++ src/race/race_manager.cpp | 39 +++++++++++++++++++-- src/race/race_manager.hpp | 4 +++ 4 files changed, 106 insertions(+), 7 deletions(-) diff --git a/src/modes/world_with_rank.cpp b/src/modes/world_with_rank.cpp index 66bb02c0720..e2625fd9655 100644 --- a/src/modes/world_with_rank.cpp +++ b/src/modes/world_with_rank.cpp @@ -214,17 +214,68 @@ unsigned int WorldWithRank::getRescuePositionIndex(AbstractKart *kart) * \param p Position (starting with 1). */ int WorldWithRank::getScoreForPosition(int p) +{ + return getScoreForPosition(p, 0.0f); +} // getScoreForPosition + +//----------------------------------------------------------------------------- +/** Returns the number of points for a kart at a specified position. + * \param p Position (starting with 1). + * \param time Time shown by the kart in the game. + */ +int WorldWithRank::getScoreForPosition(int p, float time) { assert(p - 1 >= 0); assert(p - 1 < (int)m_score_for_position.size()); + m_race_times[p] = time; if (!m_custom_scoring) return m_score_for_position[p - 1]; - else + if (m_custom_scoring_type == "inc" || m_custom_scoring_type == "fixed") + return m_score_for_position[p - 1]; + if (m_custom_scoring_type == "linear-gap" + || m_custom_scoring_type == "exp-gap") { - return m_score_for_position[p - 1]; // oh really? + double delta = time - m_race_times[1]; + if (m_custom_scoring_type == "exp-gap") + { + if (m_race_times[1] < 1e-6) // just in case + return 0; + delta = log(time / m_race_times[1]) / log(2); + } + double points = m_custom_scoring_params[2] * 0.001; + bool continuous = (m_custom_scoring_params[5] != 0); + double time_step = m_custom_scoring_params[3] * 0.001; + double decrease = m_custom_scoring_params[4] * 0.001; + delta /= time_step; + if (!continuous) + delta = floor(delta); + points -= delta * decrease; + if (points < 0.0) + points = 0.0; + return round(points); } } // getScoreForPosition +//----------------------------------------------------------------------------- +/** Returns true if and only if it can determine the score for position p + * if called right now. For standard point systems, it's always true; + * however, if the score depends on times of certain players (e.g. + * the current player and the winner), it can arrive here later than needed, + * thus we may need to invoke the function when it can be applied. + * \param p Position (starting with 1). + */ +bool WorldWithRank::canGetScoreForPosition(int p) +{ + if (m_custom_scoring_type == "linear-gap" + || m_custom_scoring_type == "exp-gap") + { + if (p == 1 || m_race_times.count(1)) + return true; + return false; + } + return true; +} // canGetScoreForPosition + //----------------------------------------------------------------------------- /** Returns true if the kart is on a valid graph quad. * \param kart_index Index of the kart. @@ -285,20 +336,25 @@ void WorldWithRank::refreshCustomScores(int num_karts) m_score_for_position.clear(); for (unsigned i = 2; i < m_custom_scoring_params.size(); i++) m_score_for_position.push_back(m_custom_scoring_params[i]); - sort(m_score_for_position.begin(), m_score_for_position.end()); + std::sort(m_score_for_position.begin(), m_score_for_position.end()); for (unsigned i = 1; i < m_score_for_position.size(); i++) m_score_for_position[i] += m_score_for_position[i - 1]; - reverse(m_score_for_position.begin(), m_score_for_position.end()); + std::reverse(m_score_for_position.begin(), m_score_for_position.end()); m_score_for_position.resize(num_karts, 0); } else if (m_custom_scoring_type == "fixed") { - m_score_for_position.clear(); for (unsigned i = 2; i < m_custom_scoring_params.size(); i++) m_score_for_position.push_back(m_custom_scoring_params[i]); m_score_for_position.resize(num_karts, 0); } + else if (m_custom_scoring_type == "linear-gap" + || m_custom_scoring_type == "exp-gap") + { + m_score_for_position.clear(); + m_score_for_position.resize(num_karts, 0); + } } // refreshCustomScores //----------------------------------------------------------------------------- diff --git a/src/modes/world_with_rank.hpp b/src/modes/world_with_rank.hpp index 919f4cc20f6..9c49adc09e3 100644 --- a/src/modes/world_with_rank.hpp +++ b/src/modes/world_with_rank.hpp @@ -54,6 +54,8 @@ class WorldWithRank : public World std::string m_custom_scoring_type; + std::map m_race_times; + #ifdef DEBUG /** Used for debugging to help detect if the same kart position * is used more than once. */ @@ -95,7 +97,9 @@ class WorldWithRank : public World * \param p Position of the kart. */ virtual AbstractKart* getKartAtDrawingPosition(unsigned int p) const { return getKartAtPosition(p); } + int getScoreForPosition(int p, float time); virtual int getScoreForPosition(int p); + virtual bool canGetScoreForPosition(int p); virtual unsigned int getRescuePositionIndex(AbstractKart *kart) OVERRIDE; // ------------------------------------------------------------------------ /** Returns the track_sector object for the specified kart. diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index 42d3b3ccc00..20258f5b2fd 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -381,6 +381,10 @@ void RaceManager::computeRandomKartList() */ void RaceManager::startNew(bool from_overworld) { + m_pending_karts_id.clear(); + m_pending_karts_pos.clear(); + m_pending_karts_time.clear(); + m_num_ghost_karts = 0; if (m_has_ghost_karts) m_num_ghost_karts = ReplayPlay::get()->getNumGhostKart(); @@ -1030,7 +1034,7 @@ void RaceManager::exitRace(bool delete_world) * \param kart The kart that finished the race. * \param time Time at which the kart finished the race. */ -void RaceManager::kartFinishedRace(const AbstractKart *kart, float time) +void RaceManager::kartFinishedRace(const AbstractKart *kart, float time = 0.0f) { unsigned int id = kart->getWorldKartId(); int pos = kart->getPosition(); @@ -1044,7 +1048,38 @@ void RaceManager::kartFinishedRace(const AbstractKart *kart, float time) // position 2, so adjust the points (#points for leader do not matter) WorldWithRank *wwr = dynamic_cast(World::getWorld()); if (wwr) - m_kart_status[id].m_score += wwr->getScoreForPosition(pos); + { + if (wwr->canGetScoreForPosition(pos)) + { + m_kart_status[id].m_score += wwr->getScoreForPosition(pos, time); + // checking whether we can add score for other karts + // which still await for that + for (unsigned i = 0; i < m_pending_karts_id.size(); ) + { + unsigned& id2 = m_pending_karts_id[i]; + float& time2 = m_pending_karts_time[i]; + int& pos2 = m_pending_karts_pos[i]; + if (wwr->canGetScoreForPosition(pos2)) + { + m_kart_status[id2].m_score += wwr->getScoreForPosition(pos2, time2); + std::swap(id2, m_pending_karts_id.back()); + std::swap(time2, m_pending_karts_time.back()); + std::swap(pos2, m_pending_karts_pos.back()); + m_pending_karts_id.pop_back(); + m_pending_karts_time.pop_back(); + m_pending_karts_pos.pop_back(); + } else { + ++i; + } + } + } + else + { + m_pending_karts_id.push_back(id); + m_pending_karts_time.push_back(time); + m_pending_karts_pos.push_back(pos); + } + } else { Log::error("RaceManager", diff --git a/src/race/race_manager.hpp b/src/race/race_manager.hpp index 46a5cb4fe12..d40f0504f6b 100644 --- a/src/race/race_manager.hpp +++ b/src/race/race_manager.hpp @@ -369,6 +369,10 @@ class RaceManager bool m_has_ghost_karts; bool m_watching_replay; + + std::vector m_pending_karts_id; + std::vector m_pending_karts_time; + std::vector m_pending_karts_pos; public: // ---------------------------------------------------------------------------------------- static RaceManager* get(); From 60089f853848bdd2454dd408c38b2eedaaca52a7 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 29 Jun 2022 18:56:44 +0300 Subject: [PATCH 223/830] Allow changing GP scoring between games using /scoring --- src/modes/world_with_rank.cpp | 6 +++++- src/network/protocols/command_manager.cpp | 25 ++++++++++++++++++++--- src/network/protocols/command_manager.hpp | 5 ++++- src/network/protocols/server_lobby.cpp | 20 ++++++++++++------ src/network/protocols/server_lobby.hpp | 2 +- 5 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/modes/world_with_rank.cpp b/src/modes/world_with_rank.cpp index e2625fd9655..54e61d42aa2 100644 --- a/src/modes/world_with_rank.cpp +++ b/src/modes/world_with_rank.cpp @@ -322,9 +322,13 @@ void WorldWithRank::updateSectorForKarts() void WorldWithRank::setCustomScoringSystem(std::string& type, std::vector& params) { - m_custom_scoring = true; m_custom_scoring_type = type; m_custom_scoring_params = params; + if (type == "" || type == "standard") { + m_custom_scoring = false; + return; + } + m_custom_scoring = true; refreshCustomScores(getNumKarts()); } // setCustomScoringSystem //----------------------------------------------------------------------------- diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index f9522df0d87..98764acc3c0 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -254,6 +254,7 @@ void CommandManager::initCommands() v.emplace_back("troll", &CM::process_troll, UP_HAMMER, MS_DEFAULT, SS_LOBBY); v.emplace_back("hitmsg", &CM::process_hitmsg, UP_HAMMER, MS_DEFAULT, SS_LOBBY); v.emplace_back("teamhit", &CM::process_teamhit, UP_HAMMER, MS_DEFAULT, SS_LOBBY); + v.emplace_back("scoring", &CM::process_scoring, UP_HAMMER, MS_DEFAULT, SS_LOBBY); v.emplace_back("version", &CM::process_text, UP_EVERYONE); v.emplace_back("clear", &CM::process_text, UP_EVERYONE); v.emplace_back("register", &CM::process_register, UP_EVERYONE); @@ -2184,6 +2185,22 @@ void CommandManager::process_teamhit(Context& context) } // process_teamhit // ======================================================================== +void CommandManager::process_scoring(Context& context) +{ + std::string msg; + auto& argv = context.m_argv; + std::string cmd2; + CommandManager::restoreCmdByArgv(cmd2, argv, ' ', '"', '"', '\\', 1); + if (m_lobby->loadCustomScoring(cmd2)) { + msg = "Scoring set to \"" + cmd2 + "\""; + m_lobby->sendStringToAllPeers(msg); + } else { + msg = "Scoring could not be parsed from \"" + cmd2 + "\""; + m_lobby->sendStringToPeer(msg, context.m_peer); + } +} // process_scoring +// ======================================================================== + void CommandManager::process_register(Context& context) { auto& argv = context.m_argv; @@ -2759,15 +2776,17 @@ void CommandManager::deleteUser(std::string& s) } // deleteUser // ======================================================================== -void CommandManager::restoreCmdByArgv(std::string& cmd, std::vector& argv, char c, char d, char e, char f) +void CommandManager::restoreCmdByArgv(std::string& cmd, + std::vector& argv, char c, char d, char e, char f, + int from) { cmd.clear(); - for (unsigned i = 0; i < argv.size(); ++i) { + for (unsigned i = from; i < argv.size(); ++i) { bool quoted = false; if (argv[i].find(c) != std::string::npos || argv[i].empty()) { quoted = true; } - if (i > 0) { + if (i > from) { cmd.push_back(c); } if (quoted) { diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 5f92544dcb1..a3d0f8388ab 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -241,6 +241,7 @@ class CommandManager void process_troll(Context& context); void process_hitmsg(Context& context); void process_teamhit(Context& context); + void process_scoring(Context& context); void process_register(Context& context); #ifdef ENABLE_WEB_SUPPORT void process_token(Context& context); @@ -282,7 +283,9 @@ class CommandManager void deleteUser(std::string& s); - static void restoreCmdByArgv(std::string& cmd, std::vector& argv, char c, char d, char e, char f); + static void restoreCmdByArgv(std::string& cmd, + std::vector& argv, char c, char d, char e, char f, + int from = 0); bool hasTypo(std::shared_ptr peer, bool voting, std::vector& argv, std::string& cmd, int idx, diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 0e007d58d5a..92512d3e950 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -321,7 +321,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() } m_allowed_to_start = true; loadTracksQueueFromConfig(); - loadCustomScoring(); + std::string scoring = ServerConfig::m_gp_scoring; + loadCustomScoring(scoring); loadWhiteList(); #ifdef ENABLE_WEB_SUPPORT m_token_generation_tries.store(0); @@ -7244,28 +7245,35 @@ std::string ServerLobby::getGrandPrixStandings(bool showIndividual, bool showTea return response.str(); } // getGrandPrixStandings //----------------------------------------------------------------------------- -void ServerLobby::loadCustomScoring() +bool ServerLobby::loadCustomScoring(std::string& scoring) { + auto previous_params = m_scoring_int_params; + auto previous_type = m_scoring_type; m_scoring_int_params.clear(); m_scoring_type = ""; - std::string scoring = ServerConfig::m_gp_scoring; if (!scoring.empty()) { std::vector params = StringUtils::split(scoring, ' '); if (params.empty()) - return; + { + m_scoring_type = ""; + return true; + } m_scoring_type = params[0]; for (unsigned i = 1; i < params.size(); i++) { int param; if (!StringUtils::fromString(params[i], param)) { - Log::warn("ServerLobby", "Unable to parse integer from custom scoring data"); - return; + Log::warn("ServerLobby", "Unable to parse integer from custom scoring data, fallback."); + m_scoring_int_params = previous_params; + m_scoring_type = previous_type; + return false; } m_scoring_int_params.push_back(param); } } + return true; } // loadCustomScoring //----------------------------------------------------------------------------- void ServerLobby::updateWorldSettings() diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 169add7f936..8cea771f7bf 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -570,7 +570,7 @@ class ServerLobby : public LobbyProtocol std::vector getMissingAssets(STKPeer* peer) const; void loadTracksQueueFromConfig(); std::string getGrandPrixStandings(bool showIndividual = false, bool showTeam = true) const; - void loadCustomScoring(); + bool loadCustomScoring(std::string& scoring); void updateWorldSettings(); void loadWhiteList(); void changeLimitForTournament(bool goal_target); From c8e4455e31947b73646bca2045b7f239bbf44984 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 30 Jun 2022 16:27:14 +0300 Subject: [PATCH 224/830] Add /scoring to data/commands.xml --- data/commands.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/data/commands.xml b/data/commands.xml index e1f7a509a6a..ac880758bf0 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -237,6 +237,11 @@ permissions="hammers" description="Toggles whether the teammate hits are punished ingame." /> + Date: Thu, 30 Jun 2022 17:17:22 +0300 Subject: [PATCH 225/830] Try to store kart name and difficulty in the records table [database schema change needed to use the option] --- CMakeLists.txt | 7 +++++++ src/network/protocols/server_lobby.cpp | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37113dc4b55..175b505099a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,8 @@ option(USE_SYSTEM_WIIUSE "Use system WiiUse instead of the built-in version, whe option(USE_SQLITE3 "Use sqlite to manage server stats and ban list." ON) option(WEB_SUPPORT "Website integration tools" OFF) +option(USE_RECORDS_V2 "Use records table with additional columns" OFF) + if(APPLE) CMAKE_DEPENDENT_OPTION(DLOPEN_MOLTENVK "Use dlopen to load MoltenVK for Apple." ON "NOT IOS;NOT SERVER_ONLY" OFF) @@ -480,6 +482,11 @@ if(WEB_SUPPORT) add_definitions(-DENABLE_WEB_SUPPORT) endif() +# Records table +if(USE_RECORDS_V2) + add_definitions(-DENABLE_RECORDS_V2) +endif() + # Set some compiler options if(UNIX OR MINGW) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 92512d3e950..89d6ea1994a 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6644,6 +6644,7 @@ void ServerLobby::storeResults() double elapsed_time = DISCONNECT_TIME; if (!w->getKart(i)->isEliminated()) elapsed_time = RaceManager::get()->getKartRaceTime(i); + std::string kart_name = w->getKart(i)->getIdent(); std::stringstream elapsed_string; elapsed_string << std::setprecision(4) << std::fixed << elapsed_time; if (best_cur_player_idx == -1 || elapsed_time < best_cur_time) @@ -6654,10 +6655,21 @@ void ServerLobby::storeResults() } std::string query = StringUtils::insertValues( "INSERT INTO %s " - "(username, venue, reverse, mode, laps, result) " - "VALUES (?, '%s', '%s', '%s', %d, '%s');", + "(username, venue, reverse, mode, laps, result" +#ifdef ENABLE_RECORDS_V2 + ", difficulty, kart, config" +#endif + ") " + "VALUES (?, '%s', '%s', '%s', %d, '%s'" +#ifdef ENABLE_RECORDS_V2 + ", %d, '%s', '%s'" +#endif + ");", m_results_table_name.c_str(), track_name.c_str(), reverse_string.c_str(), mode_name.c_str(), laps_number, elapsed_string.str() +#ifdef ENABLE_RECORDS_V2 + , getDifficulty(), kart_name.c_str(), "" +#endif ); bool written = easySQLQuery(query, [username](sqlite3_stmt* stmt) { From acaead7c40857998b510c69975f9eb51a7486ad9 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 1 Jul 2022 11:09:41 +0300 Subject: [PATCH 226/830] Allow changing Grand Prix duration when resetting it --- data/commands.xml | 4 ++-- src/network/protocols/command_manager.cpp | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index ac880758bf0..81569d37e61 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -203,9 +203,9 @@ description="Put all players into a certain number of teams. The default number of teams is max(2, min(6, round(sqrt(number of players)))) unless there is 1 player." /> = 2) { + int number_of_games; + if (!StringUtils::parseString(argv[1], &number_of_games) + || number_of_games <= 0) + { + error(context); + return; + } + m_lobby->getGameSetup()->setGrandPrixTrack(number_of_games); + } m_lobby->resetGrandPrix(); m_lobby->sendStringToAllPeers(msg); } // process_resetgp From 84235ba94ede9f2a5e9024ad01b45fd2b87af853 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 4 Jul 2022 22:21:51 +0300 Subject: [PATCH 227/830] Try to allow storing FFA game results in the database --- src/network/protocols/server_lobby.cpp | 63 ++++++++++++++++++-------- 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 89d6ea1994a..db79edd1d3d 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3517,13 +3517,7 @@ void ServerLobby::checkRaceFinished() if (ServerConfig::m_store_results) { - bool racing_mode = false; - racing_mode |= RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_NORMAL_RACE; - racing_mode |= RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_TIME_TRIAL; - if (racing_mode) - storeResults(); + storeResults(); } if (ServerConfig::m_ranked) @@ -6596,6 +6590,15 @@ void ServerLobby::updateGnuElimination() void ServerLobby::storeResults() { #ifdef ENABLE_SQLITE3 + bool racing_mode = false; + bool ffa = RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_FREE_FOR_ALL; + racing_mode |= RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_NORMAL_RACE; + racing_mode |= RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_TIME_TRIAL; + if (!racing_mode && !ffa) + return; World* w = World::getWorld(); assert(w); std::string records_table_name = ServerConfig::m_records_table_name; @@ -6603,15 +6606,16 @@ void ServerLobby::storeResults() int player_count = RaceManager::get()->getNumPlayers(); int laps_number = RaceManager::get()->getNumLaps(); std::string track_name = RaceManager::get()->getTrackName(); - std::string reverse_string = - (RaceManager::get()->getReverseTrack() ? "reverse" : "normal"); + std::string reverse_string = "normal"; + if (racing_mode && RaceManager::get()->getReverseTrack()) + reverse_string = "reverse"; bool record_fetched = false; bool record_exists = false; double best_result = 0.0; std::string best_user = ""; - if (!records_table_name.empty()) + if (racing_mode && !records_table_name.empty()) { std::string get_query = StringUtils::insertValues("SELECT username, " "result FROM '%s' WHERE venue = '%s' and reverse = '%s' " @@ -6633,6 +6637,13 @@ void ServerLobby::storeResults() std::string best_cur_player_name = ""; double best_cur_time = 1e18; const double DISCONNECT_TIME = 123454321; + FreeForAll* ffa_world = dynamic_cast(World::getWorld()); + if (ffa && ffa_world) + { + // I don't really know how to call this without using a kart from RaceManager + laps_number = round(stk_config->ticks2Time(ffa_world->getTicksSinceStart())); + } + // start of insertions for (int i = 0; i < player_count; i++) { std::string username = StringUtils::wideToUtf8( @@ -6641,17 +6652,30 @@ void ServerLobby::storeResults() // TODO fix this properly. if (profile && profile->getOnlineId() == 0) username = "* " + username; - double elapsed_time = DISCONNECT_TIME; - if (!w->getKart(i)->isEliminated()) - elapsed_time = RaceManager::get()->getKartRaceTime(i); + double score = DISCONNECT_TIME; std::string kart_name = w->getKart(i)->getIdent(); std::stringstream elapsed_string; - elapsed_string << std::setprecision(4) << std::fixed << elapsed_time; - if (best_cur_player_idx == -1 || elapsed_time < best_cur_time) + if (racing_mode) + { + if (!w->getKart(i)->isEliminated()) + score = RaceManager::get()->getKartRaceTime(i); + elapsed_string << std::setprecision(4) << std::fixed << score; + if (best_cur_player_idx == -1 || score < best_cur_time) + { + best_cur_player_idx = i; + best_cur_time = score; + best_cur_player_name = username; + } + } + else if (ffa) { - best_cur_player_idx = i; - best_cur_time = elapsed_time; - best_cur_player_name = username; + if (w->getKart(i)->isEliminated()) + continue; + if (ffa_world) + { + score = ffa_world->getKartScore(i); + } + elapsed_string << std::setprecision(0) << std::fixed << score; } std::string query = StringUtils::insertValues( "INSERT INTO %s " @@ -6681,7 +6705,8 @@ void ServerLobby::storeResults() } }); } - if (record_fetched && best_cur_player_idx != -1) + // end of insertions + if (record_fetched && best_cur_player_idx != -1) // implies racing_mode { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); From 8c2202ae87679fe7ebda274b3997cb05c8fba5ba Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 6 Jul 2022 16:51:06 +0300 Subject: [PATCH 228/830] Add an option that tries to preserve FFA scores for leaving/rejoining players [currently works for distinct names only] --- src/modes/free_for_all.cpp | 18 +++++++ src/modes/free_for_all.hpp | 8 +-- src/modes/world.hpp | 2 +- src/network/protocols/server_lobby.cpp | 72 +++++++++++++++++++++++--- src/network/protocols/server_lobby.hpp | 2 + src/network/server_config.hpp | 5 ++ 6 files changed, 97 insertions(+), 10 deletions(-) diff --git a/src/modes/free_for_all.cpp b/src/modes/free_for_all.cpp index 91ab8dafe8a..becde5c9d73 100644 --- a/src/modes/free_for_all.cpp +++ b/src/modes/free_for_all.cpp @@ -290,3 +290,21 @@ std::pair FreeForAll::getGameStartedProgress() const } return progress; } // getGameStartedProgress + +// ---------------------------------------------------------------------------- +/** Called when the score of the kart is nonzero and needs to be updated. + * \param id The world kart id of the kart whose score needs to be notified about. + */ +void FreeForAll::notifyAboutScoreIfNonzero(int id) +{ + if (NetworkConfig::get()->isNetworking() && + NetworkConfig::get()->isServer() && + m_scores[id] != 0) + { + NetworkString p(PROTOCOL_GAME_EVENTS); + p.setSynchronous(true); + p.addUInt8(GameEventsProtocol::GE_BATTLE_KART_SCORE); + p.addUInt8((uint8_t)id).addUInt16((int16_t)m_scores[id]); + STKHost::get()->sendPacketToAllPeers(&p, true); + } +} // notifyAboutScoreIfNonzero diff --git a/src/modes/free_for_all.hpp b/src/modes/free_for_all.hpp index ea772443061..07cfc24f8c5 100644 --- a/src/modes/free_for_all.hpp +++ b/src/modes/free_for_all.hpp @@ -74,16 +74,18 @@ class FreeForAll : public WorldWithRank virtual std::pair getGameStartedProgress() const OVERRIDE; // ------------------------------------------------------------------------ - virtual void addReservedKart(int kart_id) OVERRIDE + virtual void addReservedKart(int kart_id, int param = 0) OVERRIDE { - WorldWithRank::addReservedKart(kart_id); - m_scores.at(kart_id) = 0; + WorldWithRank::addReservedKart(kart_id, param); + m_scores.at(kart_id) = param; } // ------------------------------------------------------------------------ virtual void saveCompleteState(BareNetworkString* bns, STKPeer* peer) OVERRIDE; // ------------------------------------------------------------------------ virtual void restoreCompleteState(const BareNetworkString& b) OVERRIDE; + // ------------------------------------------------------------------------ + void notifyAboutScoreIfNonzero(int id); }; // FreeForAll diff --git a/src/modes/world.hpp b/src/modes/world.hpp index eb76b941e08..bd574644928 100644 --- a/src/modes/world.hpp +++ b/src/modes/world.hpp @@ -360,7 +360,7 @@ class World : public WorldStatus m_eliminated_players = 0; } // ------------------------------------------------------------------------ - virtual void addReservedKart(int kart_id) + virtual void addReservedKart(int kart_id, int param = 0) { if (m_eliminated_karts > 0) m_eliminated_karts--; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index db79edd1d3d..9ec88f80fde 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -858,6 +858,7 @@ void ServerLobby::setup() m_timeout.store(std::numeric_limits::max()); m_server_started_at = m_server_delay = 0; getCommandManager().onResetServer(); + m_saved_ffa_points.clear(); Log::info("ServerLobby", "Resetting the server to its initial state."); } // setup @@ -2370,10 +2371,13 @@ void ServerLobby::finishedLoadingLiveJoinClient(Event* event) live_join_start_time += 3000; bool spectator = false; + FreeForAll* ffa_world = dynamic_cast(World::getWorld()); for (const int id : peer->getAvailableKartIDs()) { - World::getWorld()->addReservedKart(id); const RemoteKartInfo& rki = RaceManager::get()->getKartInfo(id); + std::string name = StringUtils::wideToUtf8(rki.getPlayerName()); + int points = (ServerConfig::m_preserve_battle_scores ? m_saved_ffa_points[name] : 0); + World::getWorld()->addReservedKart(id, points); addLiveJoiningKart(id, rki, m_last_live_join_util_ticks); Log::info("ServerLobby", "%s succeeded live-joining with kart id %d.", peer->getAddress().toString().c_str(), id); @@ -3935,6 +3939,23 @@ void ServerLobby::clientDisconnected(Event* event) if (players_on_peer.empty()) return; + // section that handles unsaved FFA scores + World* w = World::getWorld(); + if (w) { + FreeForAll* ffa_world = dynamic_cast(w); + std::shared_ptr peer = event->getPeerSP(); + if (ffa_world && worldIsActive() && !peer->isWaitingForGame()) + { + for (const int id : peer->getAvailableKartIDs()) + { + RemoteKartInfo &rki = RaceManager::get()->getKartInfo(id); + m_saved_ffa_points[StringUtils::wideToUtf8(rki.getPlayerName())] + = ffa_world->getKartScore(id); + } + } + } + // end of FFA scores section + NetworkString* msg = getNetworkString(2); const bool waiting_peer_disconnected = event->getPeer()->isWaitingForGame(); @@ -6308,6 +6329,11 @@ void ServerLobby::handleKartInfo(Event* event) .encodeString(rki.getKartName()).encodeString(rki.getCountryCode()); peer->sendPacket(ns, true/*reliable*/); delete ns; + + + FreeForAll* ffa_world = dynamic_cast(World::getWorld()); + if (ffa_world) + ffa_world->notifyAboutScoreIfNonzero(kart_id); } // handleKartInfo //----------------------------------------------------------------------------- @@ -6357,9 +6383,15 @@ void ServerLobby::clientInGameWantsToBackLobby(Event* event) return; } + FreeForAll* ffa_world = dynamic_cast(World::getWorld()); for (const int id : peer->getAvailableKartIDs()) { RemoteKartInfo& rki = RaceManager::get()->getKartInfo(id); + + if (ffa_world) + m_saved_ffa_points[StringUtils::wideToUtf8(rki.getPlayerName())] + = ffa_world->getKartScore(id); + if (rki.getHostId() == peer->getHostId()) { Log::info("ServerLobby", "%s left the game with kart id %d.", @@ -6644,10 +6676,17 @@ void ServerLobby::storeResults() laps_number = round(stk_config->ticks2Time(ffa_world->getTicksSinceStart())); } // start of insertions + std::vector usernames; + std::vector scores; + std::vector karts; + std::vector lap_counts; for (int i = 0; i < player_count; i++) { std::string username = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(i).getPlayerName()); + for (std::string& username: usernames) { + m_saved_ffa_points.erase(username); + } auto profile = RaceManager::get()->getKartInfo(i).getNetworkPlayerProfile().lock(); // TODO fix this properly. if (profile && profile->getOnlineId() == 0) @@ -6655,6 +6694,7 @@ void ServerLobby::storeResults() double score = DISCONNECT_TIME; std::string kart_name = w->getKart(i)->getIdent(); std::stringstream elapsed_string; + if (racing_mode) { if (!w->getKart(i)->isEliminated()) @@ -6677,6 +6717,25 @@ void ServerLobby::storeResults() } elapsed_string << std::setprecision(0) << std::fixed << score; } + + usernames.push_back(username); + scores.push_back(elapsed_string.str()); + karts.push_back(kart_name); + lap_counts.push_back(laps_number); + } + if (ServerConfig::m_preserve_battle_scores) + { + for (auto &p: m_saved_ffa_points) + { + usernames.push_back(p.first); + lap_counts.push_back(0); + scores.push_back(std::to_string(p.second)); + karts.push_back("unknown"); + } + } + m_saved_ffa_points.clear(); + for (int i = 0; i < usernames.size(); ++i) + { std::string query = StringUtils::insertValues( "INSERT INTO %s " "(username, venue, reverse, mode, laps, result" @@ -6690,18 +6749,19 @@ void ServerLobby::storeResults() #endif ");", m_results_table_name.c_str(), track_name.c_str(), - reverse_string.c_str(), mode_name.c_str(), laps_number, elapsed_string.str() + reverse_string.c_str(), mode_name.c_str(), lap_counts[i], scores[i].c_str() #ifdef ENABLE_RECORDS_V2 - , getDifficulty(), kart_name.c_str(), "" + , getDifficulty(), karts[i].c_str(), "" #endif ); - bool written = easySQLQuery(query, [username](sqlite3_stmt* stmt) + std::string name = usernames[i]; + bool written = easySQLQuery(query, [name](sqlite3_stmt* stmt) { - if (sqlite3_bind_text(stmt, 1, username.c_str(), + if (sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) { Log::error("easySQLQuery", "Failed to bind %s.", - username.c_str()); + name.c_str()); } }); } diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 8cea771f7bf..7bce5022cd9 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -395,6 +395,8 @@ class ServerLobby : public LobbyProtocol std::atomic m_current_max_players_in_game; + std::map m_saved_ffa_points; + #ifdef ENABLE_WEB_SUPPORT std::set m_web_tokens; diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 5188db14964..c63b86bda3e 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -710,6 +710,11 @@ namespace ServerConfig "If true, the GP grid is shuffled before each race, not only before " "the first one.")); + SERVER_CFG_PREFIX BoolServerConfigParam m_preserve_battle_scores + SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "preserve-battle-scores", + "If true, when a player leaves and rejoins the battle server, " + "the score is preserved (works for distinct names only for now).")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; From 3e8b226b5f7201ecf2f0c43a3705d154e8786721 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 3 Aug 2022 21:35:56 +0300 Subject: [PATCH 229/830] Allow to configure what is reset when all players leave (e.g. for GPs) --- data/commands.xml | 5 +++ src/network/protocols/command_manager.cpp | 44 +++++++++++++++++++++++ src/network/protocols/command_manager.hpp | 1 + src/network/protocols/server_lobby.cpp | 27 ++++++++++++-- src/network/protocols/server_lobby.hpp | 3 ++ src/network/server_config.cpp | 1 + src/network/server_config.hpp | 6 ++++ 7 files changed, 85 insertions(+), 2 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index 81569d37e61..969411b2cab 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -369,6 +369,11 @@ permissions="everyone" description="Displays the result of an ongoing game." /> + = argv.size()) + { + error(context); + return; + } + if (argv.size() == 2) + { + if (argv[1] == "show") + { + msg = "Preserved settings:"; + for (const std::string& str: m_lobby->m_preserve) + msg += " " + str; + } + else + { + error(context); + return; + } + } + else + { + if (argv[2] == "0") + { + msg = StringUtils::insertValues( + "'%s' isn't preserved on server reset anymore", argv[1].c_str()); + m_lobby->m_preserve.erase(argv[1]); + } + else + { + msg = StringUtils::insertValues( + "'%s' is now preserved on server reset", argv[1].c_str()); + m_lobby->m_preserve.insert(argv[1]); + } + } + m_lobby->sendStringToPeer(msg, peer); +} // process_preserve +// ======================================================================== + void CommandManager::special(Context& context) { // This function is used as a function for /vote and possibly several diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index a3d0f8388ab..d1253941953 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -259,6 +259,7 @@ class CommandManager void process_slots(Context& context); void process_time(Context& context); void process_result(Context& context); + void process_preserve(Context& context); void special(Context& context); std::string getRandomMap() const; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 9ec88f80fde..6bf548e69ae 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -324,6 +324,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() std::string scoring = ServerConfig::m_gp_scoring; loadCustomScoring(scoring); loadWhiteList(); + loadPreservedSettings(); #ifdef ENABLE_WEB_SUPPORT m_token_generation_tries.store(0); loadAllTokens(); @@ -6824,9 +6825,23 @@ void ServerLobby::initAvailableModes() //----------------------------------------------------------------------------- void ServerLobby::resetToDefaultSettings() { - if (ServerConfig::m_server_configurable) + if (ServerConfig::m_server_configurable && !m_preserve.count("mode")) handleServerConfiguration(NULL); - m_kart_elimination.disable(); + + if (!m_preserve.count("elim")) + m_kart_elimination.disable(); + + if (!m_preserve.count("laps")) + { + m_default_lap_multiplier = -1.0; + m_fixed_lap = -1; + } + + if (!m_preserve.count("queue")) + m_tracks_queue.clear(); + + if (!m_preserve.count("replay")) + setConsentOnReplays(false); } // resetToDefaultSettings //----------------------------------------------------------------------------- void ServerLobby::writeOwnReport(STKPeer* reporter, STKPeer* reporting, const std::string& info) @@ -7402,6 +7417,14 @@ void ServerLobby::loadWhiteList() for (std::string& s: tokens) m_usernames_white_list.insert(s); } // loadWhiteList +//----------------------------------------------------------------------------- +void ServerLobby::loadPreservedSettings() +{ + std::vector what_to_preserve = + StringUtils::split(std::string(ServerConfig::m_preserve_on_reset), ' '); + for (std::string& str: what_to_preserve) + m_preserve.insert(str); +} // loadWhiteList //----------------------------------------------------------------------------- bool ServerLobby::writeOnePlayerReport(STKPeer* reporter, const std::string& table, const std::string& info) diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 7bce5022cd9..c75abf962e9 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -381,6 +381,8 @@ class ServerLobby : public LobbyProtocol std::set m_usernames_white_list; + std::set m_preserve; + bool m_allowed_to_start; bool m_consent_on_replays; @@ -575,6 +577,7 @@ class ServerLobby : public LobbyProtocol bool loadCustomScoring(std::string& scoring); void updateWorldSettings(); void loadWhiteList(); + void loadPreservedSettings(); void changeLimitForTournament(bool goal_target); bool tournamentGoalsLimit(int game) const; bool tournamentColorsSwapped(int game) const; diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 8443b0898c1..b6661ab6145 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -468,6 +468,7 @@ void loadServerLobbyFromConfig() m_time_limit_ctf.revertToDefaults(); } } + // The extra server info has to be set before the server lobby is started if (server_lobby) server_lobby->requestStart(); diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index c63b86bda3e..374711d9bf3 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -715,6 +715,12 @@ namespace ServerConfig "If true, when a player leaves and rejoins the battle server, " "the score is preserved (works for distinct names only for now).")); + SERVER_CFG_PREFIX StringServerConfigParam m_preserve_on_reset + SERVER_CFG_DEFAULT(StringServerConfigParam("", "preserve-on-reset", + "Whatever specified here wouldn't be reset when all players leave. " + "Possible options are mode, elim, laps, queue, replay, to include several " + "separate them by spaces, empty to include nothing.")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; From d7490c87afc24b52da3a4c5fc4f347d096ca1d47 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 3 Aug 2022 22:55:26 +0300 Subject: [PATCH 230/830] Fix edit distance --- src/utils/string_utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index e98c5ff69fb..d365e1f63b9 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -1353,11 +1353,11 @@ namespace StringUtils for (int j = 0; j <= m; ++j) { if (i < n) { distance[i + 1][j] = std::min(distance[i + 1][j], - distance[i][j] + (j < m && b[j] == any_substr ? 0 : 1)); + distance[i][j] + (a[i] == any_substr || (j < m && b[j] == any_substr) ? 0 : 1)); } if (j < m) { distance[i][j + 1] = std::min(distance[i][j + 1], - distance[i][j] + (i < n && a[i] == any_substr ? 0 : 1)); + distance[i][j] + (b[j] == any_substr || (i < n && a[i] == any_substr) ? 0 : 1)); } if (i < n && j < m) { int value = distance[i][j] + 1; From c63236768068def0f3941dec5118978a60c3ff9f Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 4 Aug 2022 14:05:54 +0300 Subject: [PATCH 231/830] Fix bugs in /vote config, merge commands voted by it, don't vote for not voted, show number of votes for all voted parameters --- src/network/protocols/command_manager.cpp | 37 +++++++++++++++++---- src/network/protocols/command_voting.cpp | 40 +++++++++++++++++------ src/network/protocols/command_voting.hpp | 40 +++++++++++++---------- 3 files changed, 82 insertions(+), 35 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 6a2c89806e3..c2f9fe5d0c4 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -328,6 +328,7 @@ void CommandManager::initCommands() m_votables.emplace("gnu", 0.81); m_votables.emplace("slots", CommandVoting::DEFAULT_THRESHOLD); m_votables["gnu"].setCustomThreshold("gnu kart", 1.1); + m_votables["config"].setMerge(7); } // initCommands // ======================================================================== @@ -476,8 +477,21 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) if (it != m_votables.end() && it->second.needsCheck()) { auto response = it->second.process(m_users); - int count = response.first; - std::string msg = username + " voted \"/" + cmd + "\", there are " + std::to_string(count) + " such votes"; + std::map counts = response.first; + std::string msg = username + " voted \"/" + cmd + "\", there are"; + if (counts.size() == 1) + msg += " " + std::to_string(counts.begin()->second) + " such votes"; + else + { + bool first_time = true; + for (auto& p: counts) + { + if (!first_time) + msg += ","; + msg += " " + std::to_string(p.second) + " votes for such '" + p.first + "'"; + first_time = false; + } + } m_lobby->sendStringToAllPeers(msg); auto res = response.second; if (!res.empty()) @@ -485,7 +499,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) for (auto& p: res) { std::string new_cmd = p.first + " " + p.second; - auto new_argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); + auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '"', '\\'); CommandManager::restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); std::string msg = "Command \"/" + new_cmd + "\" has been successfully voted"; m_lobby->sendStringToAllPeers(msg); @@ -698,6 +712,9 @@ void CommandManager::process_config(Context& context) int difficulty = m_lobby->getDifficulty(); int mode = m_lobby->getGameMode(); bool goal_target = (m_lobby->m_game_setup->hasExtraSeverInfo() ? m_lobby->isSoccerGoalTarget() : false); + bool user_chose_difficulty = false; + bool user_chose_mode = false; + bool user_chose_target = false; // bool gp = false; std::vector> mode_aliases = { {"m0"}, @@ -730,6 +747,7 @@ void CommandManager::process_config(Context& context) for (std::string& alias: mode_aliases[j]) { if (argv[i] == alias) { mode = j; + user_chose_mode = true; } } } @@ -737,6 +755,7 @@ void CommandManager::process_config(Context& context) for (std::string& alias: difficulty_aliases[j]) { if (argv[i] == alias) { difficulty = j; + user_chose_difficulty = true; } } } @@ -744,6 +763,7 @@ void CommandManager::process_config(Context& context) for (std::string& alias: goal_aliases[j]) { if (argv[i] == alias) { goal_target = (bool)j; + user_chose_target = true; } } } @@ -760,11 +780,14 @@ void CommandManager::process_config(Context& context) } if (context.m_voting) { - // Definitely not the best format as there are extra words + // Definitely not the best format as there are extra words, // but I'll think how to resolve it - vote(context, "config mode", mode_aliases[mode][0]); - vote(context, "config difficulty", difficulty_aliases[difficulty][0]); - vote(context, "config target", goal_aliases[goal_target ? 1 : 0][0]); + if (user_chose_mode) + vote(context, "config mode", mode_aliases[mode][0]); + if (user_chose_difficulty) + vote(context, "config difficulty", difficulty_aliases[difficulty][0]); + if (user_chose_target) + vote(context, "config target", goal_aliases[goal_target ? 1 : 0][0]); return; } m_lobby->handleServerConfiguration(context.m_peer, difficulty, mode, goal_target); diff --git a/src/network/protocols/command_voting.cpp b/src/network/protocols/command_voting.cpp index 25ea40cc000..e80e226e6e2 100644 --- a/src/network/protocols/command_voting.cpp +++ b/src/network/protocols/command_voting.cpp @@ -33,8 +33,7 @@ void CommandVoting::castVote(std::string player, std::string category, std::stri m_votes_by_player[player][category] = vote; m_votes_by_poll[category][vote].insert(player); m_need_check = true; - m_selected_category = category; - m_selected_option = vote; + m_selected_options[category] = vote; } // castVote // ======================================================================== @@ -49,15 +48,18 @@ void CommandVoting::uncastVote(std::string player, std::string category) m_votes_by_player[player].erase(it); } m_need_check = true; - m_selected_category = ""; - m_selected_option = ""; + // We add category to selected options because: + // - we need to see the number of votes even if the player unvoted + // - uncast is called inside cast, so we cannot clear the map entirely + m_selected_options[category] = ""; } // uncastVote // ======================================================================== -std::pair> CommandVoting::process(std::multiset& all_users) +std::pair, std::map> +CommandVoting::process(std::multiset& all_users) { std::map result; - int num_votes = 0; + std::map num_votes; int required_number; for (const auto& p: m_votes_by_poll) { @@ -78,11 +80,12 @@ std::pair> CommandVoting::process(std::m continue; ++category_results[it2->second]; } + auto it4 = m_selected_options.find(category); for (const auto& q: category_results) { - if (category == m_selected_category && q.first == m_selected_option) + if (it4 != m_selected_options.end() && q.first == it4->second) { - num_votes = q.second; + num_votes[category] = q.second; } if (q.second >= required_number) { @@ -92,13 +95,30 @@ std::pair> CommandVoting::process(std::m } } m_need_check = false; - m_selected_category = ""; - m_selected_option = ""; + m_selected_options.clear(); for (const auto& p: result) { std::string category = p.first; reset(category); } + if (m_merge != -1 && !result.empty()) + { + std::string new_category = ""; + std::string new_command = ""; + for (auto& p: result) { + if (new_command.empty()) + { + new_category = p.first; + new_command += p.second; + } + else + { + new_command += " " + p.first.substr(m_merge) + " " + p.second; + } + } + result.clear(); + result[new_category] = new_command; + } return make_pair(num_votes, result); } // process // ======================================================================== diff --git a/src/network/protocols/command_voting.hpp b/src/network/protocols/command_voting.hpp index 455373f3c83..50252d27b62 100644 --- a/src/network/protocols/command_voting.hpp +++ b/src/network/protocols/command_voting.hpp @@ -33,28 +33,32 @@ class CommandVoting { - double m_threshold; - bool m_need_check = false; - std::string m_selected_category = ""; - std::string m_selected_option = ""; + double m_threshold; + bool m_need_check = false; + std::map m_selected_options; + // If not -1, all commands voted from this votable will be merged into one, + // removing common prefix of length m_merge from all category names but one + int m_merge = -1; private: - std::map>> m_votes_by_poll; - std::map> m_votes_by_player; - std::map m_custom_thresholds; + std::map>> m_votes_by_poll; + std::map> m_votes_by_player; + std::map m_custom_thresholds; public: static const double DEFAULT_THRESHOLD; - CommandVoting(double threshold = DEFAULT_THRESHOLD); - void setCustomThreshold(std::string category, double value) - { m_custom_thresholds[category] = value; } - void resetCustomThreshold(std::string category) - { m_custom_thresholds.erase(category); } - bool needsCheck() { return m_need_check; } - void castVote(std::string player, std::string category, std::string vote); - void uncastVote(std::string player, std::string category); - std::pair> process(std::multiset& all_users); - std::string getAnyBest(std::string category); - void reset(std::string category); + CommandVoting(double threshold = DEFAULT_THRESHOLD); + void setCustomThreshold(std::string category, double value) + { m_custom_thresholds[category] = value; } + void resetCustomThreshold(std::string category) + { m_custom_thresholds.erase(category); } + bool needsCheck() { return m_need_check; } + void castVote(std::string player, std::string category, std::string vote); + void uncastVote(std::string player, std::string category); + std::pair, std::map> + process(std::multiset& all_users); + std::string getAnyBest(std::string category); + void reset(std::string category); void resetAllVotes(); + int setMerge(int value = -1) { m_merge = value; } }; #endif // COMMAND_VOTING_HPP \ No newline at end of file From 82ada64ccc93adc05afa745d12b7b9ffd60f8228 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 13 Aug 2022 20:21:59 +0300 Subject: [PATCH 232/830] Simplify TrackFilter's code, allow negative indices there; prevent m_tournament_arenas from having extra empty strings --- src/network/protocols/server_lobby.cpp | 5 ++- src/utils/track_filter.cpp | 51 ++++++++++++-------------- src/utils/track_filter.hpp | 4 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 6bf548e69ae..3df32e92eb2 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1900,7 +1900,11 @@ void ServerLobby::asynchronousUpdate() m_game_setup->setRace(winner_vote, m_extra_seconds); std::string track_name = winner_vote.m_track_name; if (ServerConfig::m_soccer_tournament) + { + if (m_tournament_game >= m_tournament_arenas.size()) + m_tournament_arenas.resize(m_tournament_game + 1, ""); m_tournament_arenas[m_tournament_game] = track_name; + } auto peers = STKHost::get()->getPeers(); std::map, AlwaysSpectateMode> bad_spectators; for (auto peer : peers) @@ -7108,7 +7112,6 @@ void ServerLobby::initTournamentPlayers() m_tournament_max_games = std::min(general[2].length(), general[3].length()); m_tournament_max_games = std::min(m_tournament_max_games, (int)tokens.size() - 1); m_tournament_votability = general[4]; - m_tournament_arenas.resize(m_tournament_max_games, ""); for (int i = 0; i < m_tournament_max_games; i++) m_tournament_track_filters.emplace_back(tokens[i + 1]); } // initTournamentPlayers diff --git a/src/utils/track_filter.cpp b/src/utils/track_filter.cpp index 0b40b21de86..f8fe1a047c1 100644 --- a/src/utils/track_filter.cpp +++ b/src/utils/track_filter.cpp @@ -70,7 +70,7 @@ TrackFilter::TrackFilter(std::string input) { int index; std::string cut = tokens[i].substr(1); - if (!StringUtils::parseString(cut, &index) || index < 0) + if (!StringUtils::parseString(cut, &index)) { Log::warn("TrackFilter", "Unable to parse wildcard index " "from \"%s\", omitting it", tokens[i].c_str()); @@ -103,9 +103,9 @@ TrackFilter::TrackFilter(std::string input) else { if (good) - allowed.push_back(tokens[i]); + allowed.insert(tokens[i]); else - forbidden.push_back(tokens[i]); + forbidden.insert(tokens[i]); } } } @@ -115,6 +115,8 @@ std::string TrackFilter::get(std::vector& vec, int index) { if (index >= 0 && index < vec.size()) return vec[index]; + if (index < 0 && index >= -(int)vec.size()) + return vec[(int)vec.size() + index]; return ""; } // get //----------------------------------------------------------------------------- @@ -132,6 +134,21 @@ void TrackFilter::apply(int num_players, std::set& input, std::set copy = input; input.clear(); + std::set names_allowed, names_forbidden; + + for (int x: w_allowed) + { + std::string name = get(wildcards, x); + if (!name.empty()) + names_allowed.insert(name); + } + for (int x: w_forbidden) + { + std::string name = get(wildcards, x); + if (!name.empty()) + names_forbidden.insert(name); + } + for (const std::string& s: copy) { bool yes = false; @@ -139,30 +156,10 @@ void TrackFilter::apply(int num_players, std::set& input, auto it = max_players.find(s); if (it != max_players.end() && it->second < num_players) continue; - for (int x: w_allowed) - if (get(wildcards, x) == s) - { - yes = true; - break; - } - for (int x: w_forbidden) - if (get(wildcards, x) == s) - { - no = true; - break; - } - for (std::string x: allowed) - if (x == s) - { - yes = true; - break; - } - for (std::string x: forbidden) - if (x == s) - { - no = true; - break; - } + if (names_allowed.count(s) || allowed.count(s)) + yes = true; + if (names_forbidden.count(s) || forbidden.count(s)) + no = true; if (yes && no) { Log::warn("TrackFilter", "Track requirements contradict for %s, " diff --git a/src/utils/track_filter.hpp b/src/utils/track_filter.hpp index e25341799af..ae88b11d822 100644 --- a/src/utils/track_filter.hpp +++ b/src/utils/track_filter.hpp @@ -37,8 +37,8 @@ struct TrackFilter { - std::vector allowed; - std::vector forbidden; + std::set allowed; + std::set forbidden; std::vector w_allowed; // wildcards std::vector w_forbidden; // wildcards std::map max_players; From 5ffa2e59d704ea6caabc2c3391267a22fb25edff Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 13 Aug 2022 20:25:05 +0300 Subject: [PATCH 233/830] Fix useless return type --- src/network/protocols/command_voting.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/command_voting.hpp b/src/network/protocols/command_voting.hpp index 50252d27b62..a89e27d577e 100644 --- a/src/network/protocols/command_voting.hpp +++ b/src/network/protocols/command_voting.hpp @@ -58,7 +58,7 @@ class CommandVoting std::string getAnyBest(std::string category); void reset(std::string category); void resetAllVotes(); - int setMerge(int value = -1) { m_merge = value; } + void setMerge(int value = -1) { m_merge = value; } }; #endif // COMMAND_VOTING_HPP \ No newline at end of file From 2fd11778abfd484378661c69dad72106f5159164 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 14 Aug 2022 02:29:14 +0300 Subject: [PATCH 234/830] Fix kart elimination rejoin message for those who are not eliminated yet --- src/network/protocols/server_lobby.cpp | 13 ++++++++++++- src/utils/kart_elimination.cpp | 13 +++++++------ src/utils/kart_elimination.hpp | 2 +- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3df32e92eb2..130d538da57 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4741,10 +4741,21 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, #endif if (m_kart_elimination.isEnabled()) { + bool hasEliminatedPlayer = false; + for (unsigned i = 0; i < peer->getPlayerProfiles().size(); ++i) + { + std::string name = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[i]->getName()); + if (m_kart_elimination.isEliminated(name)) + { + hasEliminatedPlayer = true; + break; + } + } NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); - std::string warning = m_kart_elimination.getWarningMessage(); + std::string warning = m_kart_elimination.getWarningMessage(hasEliminatedPlayer); chat->encodeString16(StringUtils::utf8ToWide(warning)); peer->sendPacket(chat, true/*reliable*/); delete chat; diff --git a/src/utils/kart_elimination.cpp b/src/utils/kart_elimination.cpp index 56f9815c55c..c99f478bd64 100644 --- a/src/utils/kart_elimination.cpp +++ b/src/utils/kart_elimination.cpp @@ -106,13 +106,14 @@ std::string KartElimination::getStartingMessage() const "after each race for results.", m_kart.c_str()); } // getStartingMessage //----------------------------------------------------------------------------- -std::string KartElimination::getWarningMessage() const +std::string KartElimination::getWarningMessage(bool isEliminated) const { - return StringUtils::insertValues( - "Gnu Elimination is played right now on this server, " - "you will be forced to use kart %s until it ends. " - "Use /standings to see the results.", - m_kart.c_str()); + std::string what = "Gnu Elimination is played right now on this server"; + what += (isEliminated ? + ", you will be forced to use kart %s until it ends." : + " with kart %s. You are not eliminated yet."); + what += " Use /standings to see the results."; + return StringUtils::insertValues(what, m_kart.c_str()); } // getWarningMessage //----------------------------------------------------------------------------- diff --git a/src/utils/kart_elimination.hpp b/src/utils/kart_elimination.hpp index e8d310f8bae..daa752cec58 100644 --- a/src/utils/kart_elimination.hpp +++ b/src/utils/kart_elimination.hpp @@ -50,7 +50,7 @@ class KartElimination { void disable(); // done std::string getStandings() const; // done std::string getStartingMessage() const; // done - std::string getWarningMessage() const; // done + std::string getWarningMessage(bool isEliminated) const; // done std::string update(std::map& order); }; From 6c03496e91101118cea194601e32d8dee48b3731 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 24 Aug 2022 20:21:12 +0300 Subject: [PATCH 235/830] Allow more keywords in TrackFilter --- src/utils/track_filter.cpp | 27 +++++++++++++++++++++++++++ src/utils/track_filter.hpp | 8 +++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/utils/track_filter.cpp b/src/utils/track_filter.cpp index f8fe1a047c1..03bb9d44025 100644 --- a/src/utils/track_filter.cpp +++ b/src/utils/track_filter.cpp @@ -23,6 +23,7 @@ #include "utils/string_utils.hpp" #include "utils/log.hpp" +#include "random_generator.hpp" #include #include #include @@ -48,6 +49,16 @@ TrackFilter::TrackFilter(std::string input) { if (tokens[i] == "" || tokens[i] == " ") continue; + else if (tokens[i] == "random") + m_pick_random = true; + else if (tokens[i] == "available") + m_include_unavailable = false; + else if (tokens[i] == "unavailable") + m_include_available = false; + else if (tokens[i] == "official") + m_include_addons = false; + else if (tokens[i] == "addon") + m_include_official = false; else if (tokens[i] == "not" || tokens[i] == "no") { good = false; @@ -151,6 +162,7 @@ void TrackFilter::apply(int num_players, std::set& input, for (const std::string& s: copy) { + bool addon = (s.length() >= 6 && s.substr(6) == "addon_"); bool yes = false; bool no = false; auto it = max_players.find(s); @@ -160,6 +172,12 @@ void TrackFilter::apply(int num_players, std::set& input, yes = true; if (names_forbidden.count(s) || forbidden.count(s)) no = true; + if ((!addon && !m_include_official) + || (addon && !m_include_addons)) + { + yes = false; // regardless of whether it's allowed or not + no = true; + } if (yes && no) { Log::warn("TrackFilter", "Track requirements contradict for %s, " @@ -174,6 +192,15 @@ void TrackFilter::apply(int num_players, std::set& input, if (yes) input.insert(s); } + if (m_pick_random && input.size() > 0) + { + RandomGenerator rg; + std::set::iterator it = input.begin(); + std::advance(it, rg.get((int)input.size())); + std::string choice = *it; + input.clear(); + input.insert(choice); + } } // apply (2) //----------------------------------------------------------------------------- diff --git a/src/utils/track_filter.hpp b/src/utils/track_filter.hpp index ae88b11d822..d35ba544aa4 100644 --- a/src/utils/track_filter.hpp +++ b/src/utils/track_filter.hpp @@ -33,10 +33,15 @@ // A structure to apply requirements to the track set. allowed contains // the only tracks to be allowed, forbidden contains the only tracks to be // forbidden. Putting one track into both vectors produces undefined behaviour -// for now. Works with wildcards (indices are integers: %0, %1, ...). +// for now. Works with wildcards (indices are integers: ..., %-1, %0, %1, ...). struct TrackFilter { + bool m_include_available = true; + bool m_include_unavailable = true; + bool m_include_official = true; + bool m_include_addons = true; + bool m_pick_random = false; std::set allowed; std::set forbidden; std::vector w_allowed; // wildcards @@ -49,6 +54,7 @@ struct TrackFilter void apply(int num_players, std::set& input) const; void apply(int num_players, std::set& input, std::vector& wildcards) const; + bool isPickingRandom() const { return m_pick_random; } }; #endif From 917d36cb0ca500d72d65ca75de1592bb7131b4fe Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 24 Aug 2022 20:38:16 +0300 Subject: [PATCH 236/830] Start the game on an ownerless server when all non-hourglass non-spectators are ready (and also get rid of unpressable button when everyone spectates) --- src/network/protocols/server_lobby.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 130d538da57..a601d37ca2c 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6599,6 +6599,8 @@ bool ServerLobby::checkPeersReady(bool ignore_ai_peer) const continue; if (!canRace(peer)) continue; + if (peer->alwaysSpectate()) + continue; if (ignore_ai_peer && peer->isAIPeer()) continue; someone_races = true; From 834297e6ae360af42a3b346235ce85edeef6d781 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 24 Aug 2022 21:29:43 +0300 Subject: [PATCH 237/830] Do not log chat messages with bots --- src/network/protocols/client_lobby.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp index f8db9bed6c2..f805119d3a1 100644 --- a/src/network/protocols/client_lobby.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -918,7 +918,6 @@ void ClientLobby::handleChat(Event* event) SFXManager::get()->quickSound("plopp"); core::stringw message; event->data().decodeString16(&message); - Log::info("ClientLobby", "%s", StringUtils::wideToUtf8(message).c_str()); if (GUIEngine::isNoGraphics()) return; if (message.size() > 0) From d9537d3d3817887a42e7a16ba585be78fc4f0c67 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 1 Sep 2022 12:47:11 +0300 Subject: [PATCH 238/830] Move team indicator out of [], add more team colors, change existing ones --- src/network/network_player_profile.cpp | 2 +- src/network/protocols/command_manager.cpp | 8 +++--- src/network/protocols/server_lobby.cpp | 35 ++++++++++++----------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/network/network_player_profile.cpp b/src/network/network_player_profile.cpp index b50bcec7a91..50b113274b1 100644 --- a/src/network/network_player_profile.cpp +++ b/src/network/network_player_profile.cpp @@ -20,7 +20,7 @@ #include "network/network_config.hpp" #include "network/stk_host.hpp" -float NetworkPlayerProfile::m_team_color[20] = {1.00, 0.08, 0.15, 0.30, 0.60, 0.80, 0.50, 0.70, 0.90, 0.00}; +float NetworkPlayerProfile::m_team_color[20] = {1.00, 0.05, 0.16, 0.33, 0.66, 0.78, 0.46, 0.94, 0.58, 0.00}; // ---------------------------------------------------------------------------- /** Returns true if this player is local, i.e. running on this computer. This diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index c2f9fe5d0c4..5bbe92e32e7 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2031,11 +2031,11 @@ void CommandManager::process_randomteams(Context& context) int teams_number = -1; if (argv.size() < 2 || !StringUtils::parseString(argv[1], &teams_number) - || teams_number < 1 || teams_number > 6) + || teams_number < 1 || teams_number > 9) { teams_number = (int)round(sqrt(players_number)); - if (teams_number > 6) - teams_number = 6; + if (teams_number > 9) + teams_number = 9; if (players_number > 1 && teams_number <= 1) teams_number = 2; } @@ -2044,7 +2044,7 @@ void CommandManager::process_randomteams(Context& context) "Created %d teams for %d players", teams_number, players_number); std::vector available_colors; std::vector profile_colors; - for (int i = 1; i <= 6; ++i) + for (int i = 1; i <= 9; ++i) available_colors.push_back(i); std::random_device rd; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index a601d37ca2c..3a01defc69b 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -224,10 +224,14 @@ ServerLobby::ServerLobby() : LobbyProtocol() {"green", 4}, {"g", 4}, {"blue", 5}, {"b", 5}, {"purple", 6}, {"p", 6}, - {"violet", 6}, {"v", 6} + {"violet", 6}, {"v", 6}, + {"cyan", 7}, {"c", 7}, + {"magenta", 8}, {"m", 8}, + {"pink", 8}, + {"sky", 9}, {"s", 9} }; - m_team_default_names = {"none", "red", "orange", "yellow", "green", "blue", "purple"}; + m_team_default_names = {"none", "red", "orange", "yellow", "green", "blue", "purple", "cyan", "magenta", "sky"}; m_team_index_to_icon = { {1, StringUtils::utf32ToUtf8({0x1f7e5})}, @@ -235,7 +239,10 @@ ServerLobby::ServerLobby() : LobbyProtocol() {3, StringUtils::utf32ToUtf8({0x1f7e8})}, {4, StringUtils::utf32ToUtf8({0x1f7e9})}, {5, StringUtils::utf32ToUtf8({0x1f7e6})}, - {6, StringUtils::utf32ToUtf8({0x1f7ea})} + {6, StringUtils::utf32ToUtf8({0x1f7ea})}, + {7, StringUtils::utf32ToUtf8({0x1f5fd})}, + {8, StringUtils::utf32ToUtf8({0x1f338})}, + {9, StringUtils::utf32ToUtf8({0x2604})} }; m_team_name = {"No Team", @@ -244,7 +251,10 @@ ServerLobby::ServerLobby() : LobbyProtocol() StringUtils::utf32ToUtf8({0x1f7e8}) + "Yellow", StringUtils::utf32ToUtf8({0x1f7e9}) + "Green", StringUtils::utf32ToUtf8({0x1f7e6}) + "Blue", - StringUtils::utf32ToUtf8({0x1f7ea}) + "Purple" + StringUtils::utf32ToUtf8({0x1f7ea}) + "Purple", + StringUtils::utf32ToUtf8({0x1f5fd}) + "Cyan", + StringUtils::utf32ToUtf8({0x1f338}) + "Magenta", + StringUtils::utf32ToUtf8({ 0x2604}) + "Sky" }; m_shuffle_gp = ServerConfig::m_shuffle_gp; @@ -4879,6 +4889,10 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) prefix.resize((int)prefix.size() - 2); prefix = "[" + prefix + "] "; } + int team = profile->getTemporaryTeam(); + if (team != -1) { + prefix = m_team_index_to_icon[team + 1] + " " + prefix; + } profile_name = StringUtils::utf8ToWide(prefix) + profile_name; @@ -7984,19 +7998,6 @@ void ServerLobby::setTemporaryTeam(const std::string& username, std::string& arg { auto it = m_team_name_to_index.find(arg); int index = (it == m_team_name_to_index.end() ? 0 : it->second); - for (const auto& pair: m_team_index_to_icon) - { - if (pair.first == index) - { - m_player_categories[pair.second].insert(username); - m_categories_for_player[username].insert(pair.second); - } - else - { - m_player_categories[pair.second].erase(username); - m_categories_for_player[username].erase(pair.second); - } - } m_team_for_player[username] = index; irr::core::stringw wide_player_name = StringUtils::utf8ToWide(username); std::shared_ptr player_peer = STKHost::get()->findPeerByName( From 4944000e08c9ede71d91d15cd18d3e896ec5d7cb Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 7 Sep 2022 12:47:26 +0300 Subject: [PATCH 239/830] Try to show commit hash + branch in /version --- CMakeLists.txt | 18 ++++++++++++++++++ src/network/protocols/command_manager.cpp | 9 ++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 175b505099a..a911145683b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,20 @@ cmake_minimum_required(VERSION 2.8.4) +execute_process( + COMMAND git rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_BRANCH + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +# Get the latest abbreviated commit hash of the working branch +execute_process( + COMMAND git --no-pager describe --tags --always --dirty + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_COMMIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE +) + # root CMakeLists for the SuperTuxKart project project(SuperTuxKart) set(PROJECT_VERSION "git") @@ -610,6 +625,9 @@ else() endif() endif() +target_compile_definitions(supertuxkart PRIVATE "-DGIT_BRANCH=\"${GIT_BRANCH}\"") +target_compile_definitions(supertuxkart PRIVATE "-DGIT_VERSION=\"${GIT_COMMIT_HASH}\"") + # check if linking against libatomic is required include(CheckCXXSourceCompiles) check_cxx_source_compiles(" diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 5bbe92e32e7..795088a057b 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -298,7 +298,14 @@ void CommandManager::initCommands() addTextResponse("description", ServerConfig::m_motd); addTextResponse("moreinfo", StringUtils::wideToUtf8(m_lobby->m_help_message)); - addTextResponse("version", "1.3-rc1 k 210fff beta"); + std::string version = "1.3 k 210fff beta"; +#ifdef GIT_VERSION + version = std::string(GIT_VERSION); + #ifdef GIT_BRANCH + version += ", branch " + std::string(GIT_BRANCH); + #endif +#endif + addTextResponse("version", version); addTextResponse("clear", std::string(30, '\n')); for (Command& command: m_commands) { From 7bd4f5b6742059e11ad69d8ce4abe67e0371cfad Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 7 Sep 2022 14:59:41 +0300 Subject: [PATCH 240/830] Fix wrongly displayed motd in the command --- src/network/protocols/command_manager.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 795088a057b..fa44a1c04b0 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -294,9 +294,8 @@ void CommandManager::initCommands() v.emplace_back("liststkaddon", &CM::special, UP_EVERYONE); v.emplace_back("listlocaladdon", &CM::special, UP_EVERYONE); - - - addTextResponse("description", ServerConfig::m_motd); + addTextResponse("description", StringUtils::wideToUtf8(m_lobby->getGameSetup()->readOrLoadFromFile + ((std::string)ServerConfig::m_motd))); addTextResponse("moreinfo", StringUtils::wideToUtf8(m_lobby->m_help_message)); std::string version = "1.3 k 210fff beta"; #ifdef GIT_VERSION From 635d424779b03663967c50af12e6dbf92f8721fa Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 9 Sep 2022 01:36:00 +0300 Subject: [PATCH 241/830] Try to fix wrong number of points and position debug errors when there are both autofinished and disconnected players --- src/modes/standard_race.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modes/standard_race.cpp b/src/modes/standard_race.cpp index 9ce8a4a0a4f..f4c1802e12e 100644 --- a/src/modes/standard_race.cpp +++ b/src/modes/standard_race.cpp @@ -145,7 +145,7 @@ void StandardRace::endRaceEarly() for (unsigned int i = 0; i < active_players.size(); i++) { int kartid = active_players[i]; - int position = getNumKarts() - (int) active_players.size() + 1 + i; + int position = getCurrentNumKarts() - (int) active_players.size() + 1 + i; setKartPosition(kartid, position); // Compute the finish time, with a different formula for networked races // to avoid making auto-end too punishing From ee0556fb91697a397875375d8ea760726b0fce8b Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 9 Sep 2022 03:20:50 +0300 Subject: [PATCH 242/830] Try to allow shuffling/swapping teams together with all players and standings; remove extraneous manipulation with categories --- data/commands.xml | 9 +++- src/network/protocols/command_manager.cpp | 55 +++++++++++++++++++++++ src/network/protocols/command_manager.hpp | 1 + src/network/protocols/server_lobby.cpp | 39 +++++++++++++--- src/network/protocols/server_lobby.hpp | 1 + 5 files changed, 96 insertions(+), 9 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index 969411b2cab..71e16f94b4e 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -188,9 +188,14 @@ description="Sets the timeout in seconds, whatever it may mean." /> + permutation_map; + std::map permutation_map_int; + for (char c: argv[1]) + { + std::string type(1, c); + // todo remove that link to first char, it is awful + if (m_lobby->m_team_name_to_index.count(type) == 0) + continue; + int index = m_lobby->m_team_name_to_index[type]; + char c1 = m_lobby->m_team_default_names[index][0]; + if (m_lobby->m_team_name_to_index.count(type)) { + permutation_map[c1] = 0; + } + } + std::string permutation; + for (auto& p: permutation_map) + permutation.push_back(p.first); + std::string msg = "Shuffled some teams: " + permutation + " -> "; + if (permutation.size() == 2) + swap(permutation[0], permutation[1]); + else + { + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(permutation.begin(), permutation.end(), g); + } + msg += permutation; + auto it = permutation_map.begin(); + for (unsigned i = 0; i < permutation.size(); i++, it++) + { + it->second = permutation[i]; + } + for (auto& p: permutation_map) + { + int from = m_lobby->m_team_name_to_index[std::string(1, p.first)]; + int to = m_lobby->m_team_name_to_index[std::string(1, p.second)]; + permutation_map_int[from] = to; + } + m_lobby->shuffleTemporaryTeams(permutation_map_int); + m_lobby->sendStringToPeer(msg, context.m_peer); // todo make public? + m_lobby->updatePlayerList(); +} // process_swapteams +// ======================================================================== + void CommandManager::process_resetteams(Context& context) { std::string msg = "Teams are reset now"; diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index d1253941953..61cc4d209ce 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -234,6 +234,7 @@ class CommandManager void process_shuffle(Context& context); void process_timeout(Context& context); void process_team(Context& context); + void process_swapteams(Context& context); void process_resetteams(Context& context); void process_randomteams(Context& context); void process_resetgp(Context& context); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3a01defc69b..5da092859c0 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -8016,15 +8016,9 @@ void ServerLobby::setTemporaryTeam(const std::string& username, std::string& arg } // setTemporaryTeam //----------------------------------------------------------------------------- -// This should be moved later to another unit. +// todo This should be moved later to another unit. void ServerLobby::clearTemporaryTeams() { - for (const auto& pair: m_team_index_to_icon) - { - for (const std::string& username: m_player_categories[pair.second]) - m_categories_for_player[username].erase(pair.second); - m_player_categories[pair.second].clear(); - } m_team_for_player.clear(); for (auto& peer : STKHost::get()->getPeers()) @@ -8033,6 +8027,37 @@ void ServerLobby::clearTemporaryTeams() } // clearTemporaryTeams //----------------------------------------------------------------------------- +// todo This should be moved later to another unit. +void ServerLobby::shuffleTemporaryTeams(const std::map& permutation) +{ + for (auto& p: m_team_for_player) + { + auto it = permutation.find(p.second); + if (it != permutation.end()) + p.second = it->second; + } + for (auto& peer : STKHost::get()->getPeers()) + { + for (auto &profile: peer->getPlayerProfiles()) + { + auto it = permutation.find(profile->getTemporaryTeam() + 1); + if (it != permutation.end()) + profile->setTemporaryTeam(it->second - 1); + } + } + auto old_scores = m_gp_team_scores; + m_gp_team_scores.clear(); + for (auto& p: old_scores) + { + auto it = permutation.find(p.first); + if (it != permutation.end()) + m_gp_team_scores[it->second] = p.second; + else + m_gp_team_scores[p.first] = p.second; + } +} // shuffleTemporaryTeams +//----------------------------------------------------------------------------- + void ServerLobby::resetGrandPrix() { m_gp_scores.clear(); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index c75abf962e9..db623057f1d 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -669,6 +669,7 @@ class ServerLobby : public LobbyProtocol { return m_available_modes.count(mode) > 0; } void setTemporaryTeam(const std::string& username, std::string& arg); void clearTemporaryTeams(); + void shuffleTemporaryTeams(const std::map& permutation); void resetGrandPrix(); void erasePeerReady(std::shared_ptr peer) { m_peers_ready.erase(peer); } From 449111167d061056d4b4b97acb4635b9f43e05df Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 19 Sep 2022 14:54:22 +0300 Subject: [PATCH 243/830] Allow hammers to check the number of slots, fix unsigned bug --- data/commands.xml | 4 ++-- src/network/protocols/command_manager.cpp | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index 71e16f94b4e..45618e490ee 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -360,9 +360,9 @@ /> --> (argv[1], &number)) + int number = 0; + if (argv.size() < 2) + { + int current = m_lobby->m_current_max_players_in_game.load(); + std::string msg = "Number of slots is currently " + std::to_string(current); + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + if (argv.size() < 2 || !StringUtils::parseString(argv[1], &number)) fail = true; - else if (number <= 0 || (int)number > ServerConfig::m_server_max_players) + else if (number <= 0 || number > ServerConfig::m_server_max_players) fail = true; if (fail) { @@ -2772,7 +2780,7 @@ void CommandManager::process_slots(Context& context) vote(context, "slots", argv[1]); return; } - m_lobby->m_current_max_players_in_game.store(number); + m_lobby->m_current_max_players_in_game.store((unsigned)number); m_lobby->updatePlayerList(); std::string msg = "Number of playable slots is now " + argv[1]; m_lobby->sendStringToAllPeers(msg); From 501669ade0bd1ac3563d29f6bf75d6b17e2ae062 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 24 Oct 2022 14:30:58 +0300 Subject: [PATCH 244/830] Show both join and play requirements in the log when someone joins --- src/network/protocols/server_lobby.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 1db0a1ea4cb..ea1674a4548 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4143,12 +4143,16 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) } } - Log::info("ServerLobby", "Player has the following addons: %d/%d karts," - " %d/%d tracks, %d/%d arenas, %d/%d soccer fields.", addon_karts, - (int)ServerConfig::m_addon_karts_join_threshold, addon_tracks, - (int)ServerConfig::m_addon_tracks_join_threshold, addon_arenas, - (int)ServerConfig::m_addon_arenas_join_threshold, addon_soccers, - (int)ServerConfig::m_addon_soccers_join_threshold); + Log::info("ServerLobby", "Player has the following addons: %d/%d(%d) karts," + " %d/%d(%d) tracks, %d/%d(%d) arenas, %d/%d(%d) soccer fields.", + addon_karts, (int)ServerConfig::m_addon_karts_join_threshold, + (int)ServerConfig::m_addon_karts_play_threshold, + addon_tracks, (int)ServerConfig::m_addon_tracks_join_threshold, + (int)ServerConfig::m_addon_tracks_play_threshold, + addon_arenas, (int)ServerConfig::m_addon_arenas_join_threshold, + (int)ServerConfig::m_addon_arenas_play_threshold, + addon_soccers, (int)ServerConfig::m_addon_soccers_join_threshold, + (int)ServerConfig::m_addon_soccers_play_threshold); peer->addon_karts_count = addon_karts; peer->addon_tracks_count = addon_tracks; From 90343fd9fb8cb5525806a0b16590aef9634e68d0 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 25 Oct 2022 16:14:20 +0300 Subject: [PATCH 245/830] Fix log and lobby messages when changing mode/difficulty --- src/network/protocols/server_lobby.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index ea1674a4548..3551547135e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6010,13 +6010,21 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, } unsigned total_players = 0; STKHost::get()->updatePlayers(NULL, NULL, &total_players); - if ((m_available_difficulties.count(difficulty) == 0 || - m_available_modes.count(mode) == 0)) + bool bad_mode = (m_available_modes.count(mode) == 0); + bool bad_difficulty = (m_available_difficulties.count(difficulty) == 0); + if (bad_mode || bad_difficulty) { // It remains just in case, but kimden thinks that // this is already covered in command manager (?) - Log::error("ServerLobby", "Mode %d and/or difficulty %d are not permitted."); - std::string msg = "Mode or difficulty are not permitted on this server"; + Log::error("ServerLobby", "Mode %d and/or difficulty %d are not permitted.", + difficulty, mode); + std::string msg = ""; + if (bad_mode && bad_difficulty) + msg = "Both mode and difficulty are not permitted on this server"; + else if (bad_mode) + msg = "This mode is not permitted on this server"; + else + msg = "This difficulty is not permitted on this server"; sendStringToPeer(msg, peer); return; } From 06da93a39775c8b3dc4b65759cb67daacb659ad7 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 25 Oct 2022 16:38:48 +0300 Subject: [PATCH 246/830] Don't recolor hourglasses in /randomteams, don't crash when there are 0 players --- src/network/protocols/command_manager.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 06da6e97fce..1d76c89ff76 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2083,13 +2083,19 @@ void CommandManager::process_randomteams(Context& context) int players_number = 0; for (auto& peer : STKHost::get()->getPeers()) { + if (!m_lobby->canRace(peer)) + continue; if (peer->alwaysSpectate()) continue; players_number += peer->getPlayerProfiles().size(); for (auto& profile : peer->getPlayerProfiles()) profile->setTemporaryTeam(-1); } - + if (players_number == 0) { + std::string msg = "No one can play!"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } int teams_number = -1; if (argv.size() < 2 || !StringUtils::parseString(argv[1], &teams_number) || teams_number < 1 || teams_number > 9) From 985d8435a907833f72532e391e4ca90d3c709b5f Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 25 Oct 2022 17:55:18 +0300 Subject: [PATCH 247/830] Allow specifying kart_characteristics config as a command line parameter --- src/main.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4df005eb3e0..d1a830137cf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1952,10 +1952,11 @@ void initRest() file_manager->getAddonsFile("tracks/")); } - { - XMLNode characteristicsNode(file_manager->getAsset("kart_characteristics.xml")); - kart_properties_manager->loadCharacteristics(&characteristicsNode); - } + std::string char_file; + if (!CommandLine::has("--char-file", &char_file)) + char_file = "kart_characteristics.xml"; + XMLNode characteristicsNode(file_manager->getAsset(char_file)); + kart_properties_manager->loadCharacteristics(&characteristicsNode); track_manager->loadTrackList(); music_manager->addMusicToTracks(); From 36f2bd3c82104da6b4fc93adaef60e336c42e283 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 18 Nov 2022 15:16:00 +0300 Subject: [PATCH 248/830] Don't assign custom teams to hourglassed (previous related commit only didn't check them to determine the number of players) --- src/network/protocols/command_manager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 1d76c89ff76..bcc9d87efa6 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2127,6 +2127,8 @@ void CommandManager::process_randomteams(Context& context) m_lobby->clearTemporaryTeams(); for (auto& peer : STKHost::get()->getPeers()) { + if (!m_lobby->canRace(peer)) + continue; if (peer->alwaysSpectate()) continue; for (auto& profile : peer->getPlayerProfiles()) { From f0b7c02cc0adea47eafed6bec43f94d42aca3f6f Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 18 Nov 2022 15:23:31 +0300 Subject: [PATCH 249/830] Avoid any occasional access to non-existing first player profile for any peer in command manager --- src/network/protocols/command_manager.cpp | 49 ++++++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index bcc9d87efa6..f3c5ebc698f 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -406,8 +406,10 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) permissions = m_lobby->getPermissions(peer); voting = false; std::string action = "invoke"; - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + std::string username = ""; + if (peer->hasPlayerProfiles()) + username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); if (argv[0] == "vote") { @@ -552,6 +554,8 @@ void CommandManager::vote(Context& context, std::string category, std::string va { auto& peer = context.m_peer; auto& argv = context.m_argv; + if (!peer->hasPlayerProfiles()) + return; std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); auto& votable = m_votables[argv[0]]; @@ -914,6 +918,8 @@ void CommandManager::process_addons(Context& context) if ((!more_own || peer != context.m_peer) && (peer->isWaitingForGame() || !m_lobby->canRace(peer) || peer->isCommandSpectator())) continue; + if (!peer->hasPlayerProfiles()) + continue; ++num_players; std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); @@ -948,7 +954,9 @@ void CommandManager::process_addons(Context& context) { auto result2 = result; result.clear(); - std::string asking_username = StringUtils::wideToUtf8( + std::string asking_username = ""; + if (context.m_peer->hasPlayerProfiles()) + asking_username = StringUtils::wideToUtf8( context.m_peer->getPlayerProfiles()[0]->getName()); for (unsigned i = 0; i < result2.size(); ++i) { @@ -1042,7 +1050,8 @@ void CommandManager::process_checkaddon(Context& context) for (auto peer : peers) { if (!peer || !peer->isValidated() || peer->isWaitingForGame() - || !m_lobby->canRace(peer) || peer->isCommandSpectator()) + || !m_lobby->canRace(peer) || peer->isCommandSpectator() + || !peer->hasPlayerProfiles()) continue; std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); @@ -2309,6 +2318,8 @@ void CommandManager::process_register(Context& context) { auto& argv = context.m_argv; auto& peer = context.m_peer; + if (!peer->hasPlayerProfiles()) + return; int online_id = peer->getPlayerProfiles()[0]->getOnlineId(); if (online_id <= 0) { @@ -2337,6 +2348,8 @@ void CommandManager::process_register(Context& context) void CommandManager::process_token(Context& context) { auto& peer = context.m_peer; + if (!peer->hasPlayerProfiles()) + return; int online_id = peer->getPlayerProfiles()[0]->getOnlineId(); if (online_id <= 0) { @@ -2375,6 +2388,8 @@ void CommandManager::process_muteall(Context& context) { auto& argv = context.m_argv; auto& peer = context.m_peer; + if (!peer->hasPlayerProfiles()) + return; std::string peer_username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); if (argv.size() >= 2 && argv[1] == "0") @@ -2405,6 +2420,8 @@ void CommandManager::process_game(Context& context) { auto& argv = context.m_argv; auto& peer = context.m_peer; + if (!peer->hasPlayerProfiles()) + return; std::string peer_username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); int old_game = m_lobby->m_tournament_game; @@ -2481,6 +2498,8 @@ void CommandManager::process_role(Context& context) { auto& argv = context.m_argv; auto& peer = context.m_peer; + if (!peer->hasPlayerProfiles()) + return; std::string peer_username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); if (argv.size() < 3) @@ -2569,7 +2588,8 @@ void CommandManager::process_role(Context& context) if (player_peer) { role_changed = StringUtils::insertValues(role_changed, "red player"); - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_RED); + if (player_peer->hasPlayerProfiles()) + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_RED); m_lobby->sendStringToPeer(role_changed, player_peer); } break; @@ -2597,7 +2617,8 @@ void CommandManager::process_role(Context& context) if (player_peer) { role_changed = StringUtils::insertValues(role_changed, "blue player"); - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_BLUE); + if (player_peer->hasPlayerProfiles()) + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_BLUE); m_lobby->sendStringToPeer(role_changed, player_peer); } break; @@ -2616,7 +2637,8 @@ void CommandManager::process_role(Context& context) if (player_peer) { role_changed = StringUtils::insertValues(role_changed, "referee"); - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); + if (player_peer->hasPlayerProfiles()) + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); m_lobby->sendStringToPeer(role_changed, player_peer); } break; @@ -2627,7 +2649,8 @@ void CommandManager::process_role(Context& context) if (player_peer) { role_changed = StringUtils::insertValues(role_changed, "spectator"); - player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); + if (player_peer->hasPlayerProfiles()) + player_peer->getPlayerProfiles()[0]->setTeam(KART_TEAM_NONE); m_lobby->sendStringToPeer(role_changed, player_peer); } break; @@ -2701,6 +2724,8 @@ void CommandManager::process_init(Context& context) { auto& argv = context.m_argv; auto& peer = context.m_peer; + if (!peer->hasPlayerProfiles()) + return; std::string peer_username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); int red, blue; @@ -2751,7 +2776,7 @@ void CommandManager::process_test(Context& context) return; } std::string username = "Vote"; - if (peer.get()) + if (peer.get() && peer->hasPlayerProfiles()) { username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); @@ -2966,8 +2991,10 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, { if (!peer.get()) // voted return false; - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + std::string username = ""; + if (peer->hasPlayerProfiles()) + username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); if (idx < m_user_correct_arguments[username]) return false; auto closest_commands = stf.getClosest(argv[idx], top, case_sensitive); From 314afacb6e70e183c56a691787424384ead13f4e Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 19 Nov 2022 21:37:01 +0300 Subject: [PATCH 250/830] Make inc scoring compliant with default stk_config.xml GP scoring --- src/modes/world_with_rank.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modes/world_with_rank.cpp b/src/modes/world_with_rank.cpp index 54e61d42aa2..ad7fe57385a 100644 --- a/src/modes/world_with_rank.cpp +++ b/src/modes/world_with_rank.cpp @@ -340,11 +340,11 @@ void WorldWithRank::refreshCustomScores(int num_karts) m_score_for_position.clear(); for (unsigned i = 2; i < m_custom_scoring_params.size(); i++) m_score_for_position.push_back(m_custom_scoring_params[i]); + m_score_for_position.resize(num_karts, 0); std::sort(m_score_for_position.begin(), m_score_for_position.end()); for (unsigned i = 1; i < m_score_for_position.size(); i++) m_score_for_position[i] += m_score_for_position[i - 1]; std::reverse(m_score_for_position.begin(), m_score_for_position.end()); - m_score_for_position.resize(num_karts, 0); } else if (m_custom_scoring_type == "fixed") { From 5be3cf57cebd021bc008becb6f00252b9186b41c Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 5 Jan 2023 18:26:33 +0300 Subject: [PATCH 251/830] Allow tournament to choose between no timer and button --- src/network/server_config.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 7b32824cc4c..331ac8a519f 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -404,8 +404,6 @@ void loadServerLobbyFromConfig() if (m_owner_less) { m_min_start_game_players = 1; - m_start_game_counter = -1; -// m_start_game_counter = 1000001; } else { From 745c9e9e2c6d2f7bc5a44f3aa29a53153e2e1527 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 5 Jan 2023 19:32:22 +0300 Subject: [PATCH 252/830] Don't wait for people who cannot vote, to vote --- src/network/protocols/server_lobby.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3551547135e..915c1b6ea4a 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -5172,6 +5172,8 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote, { if (peer->isAIPeer()) continue; + if (!canVote(peer)) + continue; if (peer->hasPlayerProfiles() && !peer->isWaitingForGame()) cur_players += 1.0f; } From 818804e04ceb10bc0f1cd21bf2b1533a63d0b5b4 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 7 Jan 2023 01:26:25 +0300 Subject: [PATCH 253/830] Don't check peers with no profiles in can* functions --- src/network/protocols/server_lobby.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 915c1b6ea4a..ccb436cf6cb 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7256,6 +7256,8 @@ bool ServerLobby::canRace(std::shared_ptr& peer) const //----------------------------------------------------------------------------- bool ServerLobby::canRace(STKPeer* peer) const { + if (!peer || peer->getPlayerProfiles().empty()) + return false; std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); if (ServerConfig::m_soccer_tournament) @@ -7292,6 +7294,8 @@ bool ServerLobby::canVote(std::shared_ptr& peer) const //----------------------------------------------------------------------------- bool ServerLobby::canVote(STKPeer* peer) const { + if (!peer || peer->getPlayerProfiles().empty()) + return false; std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); if (ServerConfig::m_soccer_tournament) { @@ -7314,6 +7318,8 @@ bool ServerLobby::hasHostRights(std::shared_ptr& peer) const //----------------------------------------------------------------------------- bool ServerLobby::hasHostRights(STKPeer* peer) const { + if (!peer || peer->getPlayerProfiles().empty()) + return false; if (peer == m_server_owner.lock().get()) return true; if (peer->isAngryHost()) From 0e205d931ef19590027ad0f5d40c7abd5d54edc9 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 7 Jan 2023 02:07:27 +0300 Subject: [PATCH 254/830] Remove forgotten <<<<<< --- src/network/protocols/server_lobby.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 047a460b863..26224af7482 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -626,7 +626,6 @@ class ServerLobby : public LobbyProtocol void storeResults(); uint32_t getServerIdOnline() const { return m_server_id_online; } void setClientServerHostId(uint32_t id) { m_client_server_host_id = id; } -<<<<<<< HEAD void initAvailableTracks(); void initAvailableModes(); void resetToDefaultSettings(); From 0c411e9218ddaa6a62b48b69c3b631e3f177b50f Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 20 Jan 2023 17:20:42 +0300 Subject: [PATCH 255/830] Indicate teamchatting for /teamchat-based one even in lobby (only for soccer and ctf for now) --- src/network/protocols/server_lobby.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index e3ffb8822ca..80f0efaa27e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -946,11 +946,13 @@ void ServerLobby::handleChat(Event* event) if (message.size() > 0) { + bool add_red_emoji = false; + bool add_blue_emoji = false; // Red or blue square emoji if (target_team == KART_TEAM_RED) - message = StringUtils::utf32ToWide({0x1f7e5, 0x20}) + message; + add_red_emoji = true; else if (target_team == KART_TEAM_BLUE) - message = StringUtils::utf32ToWide({0x1f7e6, 0x20}) + message; + add_blue_emoji = true; NetworkString* chat = getNetworkString(); chat->setSynchronous(true); @@ -967,6 +969,20 @@ void ServerLobby::handleChat(Event* event) std::set teams; for (auto& profile: sender->getPlayerProfiles()) teams.insert(profile->getTeam()); + if (team_speak) + { + for (auto &team: teams) + { + if (team == KART_TEAM_RED) + add_red_emoji = true; + else if (team == KART_TEAM_BLUE) + add_blue_emoji = true; + } + } + if (add_blue_emoji) + message = StringUtils::utf32ToWide({0x1f7e6, 0x20}) + message; + if (add_red_emoji) + message = StringUtils::utf32ToWide({0x1f7e5, 0x20}) + message; bool tournament_limit = false; std::set important_players; if (ServerConfig::m_soccer_tournament) From 63ba41d799607f338e71664c4b4fff7fb339fe0a Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 20 Jan 2023 17:50:53 +0300 Subject: [PATCH 256/830] Allow tournament referees to see teamchats (not sure whether it should be further customized, for example, allowing certain groups to see but not others? hmm, discussable) --- src/network/protocols/server_lobby.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 80f0efaa27e..73ec595f61f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -985,8 +985,12 @@ void ServerLobby::handleChat(Event* event) message = StringUtils::utf32ToWide({0x1f7e5, 0x20}) + message; bool tournament_limit = false; std::set important_players; + std::set sees_teamchats; if (ServerConfig::m_soccer_tournament) { + for (const std::string& s: m_tournament_referees) { + sees_teamchats.insert(s); + } tournament_limit = true; for (auto& profile: sender->getPlayerProfiles()) { @@ -1020,7 +1024,7 @@ void ServerLobby::handleChat(Event* event) STKHost::get()->sendPacketToAllPeersWith( [game_started, sender_in_game, target_team, can_receive, sender, team_speak, teams, tournament_limit, - important_players, sender_name, this](STKPeer* p) + important_players, sender_name, sees_teamchats, this](STKPeer* p) { if (sender == p) return true; @@ -1055,6 +1059,10 @@ void ServerLobby::handleChat(Event* event) { if (player->getTeam() == target_team) someone_good = true; + std::string name = StringUtils::wideToUtf8( + player->getName()); + if (sees_teamchats.count(name)) + someone_good = true; } if (!someone_good) return false; @@ -1073,8 +1081,14 @@ void ServerLobby::handleChat(Event* event) { bool someone_good = false; for (auto& profile: p->getPlayerProfiles()) + { if (teams.count(profile->getTeam()) > 0) someone_good = true; + std::string name = StringUtils::wideToUtf8( + profile->getName()); + if (sees_teamchats.count(name)) + someone_good = true; + } if (!someone_good) return false; } From a083ef3373c2de9e134233548e83082233908543 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 7 Feb 2023 18:57:53 +0300 Subject: [PATCH 257/830] Allow change direction to always forward/always reverse/chosen using /direction, also in server config --- data/commands.xml | 7 ++++- src/network/protocols/command_manager.cpp | 35 +++++++++++++++++++++++ src/network/protocols/command_manager.hpp | 1 + src/network/protocols/server_lobby.cpp | 13 +++++++++ src/network/protocols/server_lobby.hpp | 2 ++ src/network/server_config.hpp | 4 +++ 6 files changed, 61 insertions(+), 1 deletion(-) diff --git a/data/commands.xml b/data/commands.xml index 45618e490ee..7d9c0624fdf 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -167,6 +167,11 @@ permissions="hammers, singleplayers" description="Manipulates the length of the games, “= n” fixes the number of laps to n, “x k” sets it to k times default number of laps, “check” displays the setting, “clear” allows players to choose it freely." /> + diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index f3c5ebc698f..5b7acb9096d 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -240,6 +240,7 @@ void CommandManager::initCommands() v.emplace_back("record", &CM::process_record, UP_EVERYONE); v.emplace_back("power", &CM::process_power, UP_EVERYONE); v.emplace_back("length", &CM::process_length, UP_SINGLE, MS_DEFAULT, SS_LOBBY); + v.emplace_back("direction", &CM::process_direction, UP_SINGLE, MS_DEFAULT, SS_LOBBY); v.emplace_back("queue", &CM::process_queue, UP_SINGLE, MS_DEFAULT, SS_LOBBY); v.emplace_back("allowstart", &CM::process_allowstart, UP_HAMMER); v.emplace_back("shuffle", &CM::process_shuffle, UP_HAMMER); @@ -1843,6 +1844,40 @@ void CommandManager::process_length(Context& context) error(context); } // process_length +// ======================================================= + +void CommandManager::process_direction(Context& context) +{ + auto& argv = context.m_argv; + std::string msg; + if (argv.size() < 2) + { + error(context); + return; + } + int temp_int = -1; + if (!StringUtils::parseString(argv[1], &temp_int)) + { + error(context); + return; + } + if (temp_int < -1 || temp_int > 1) + { + error(context); + return; + } + m_lobby->m_fixed_direction = temp_int; + msg = "Direction is now "; + if (temp_int == -1) + { + msg += "chosen ingame"; + } else + { + msg += "set to "; + msg += (temp_int == 0 ? "forward" : "reverse"); + } + m_lobby->sendStringToAllPeers(msg); +} // process_direction // ======================================================================== void CommandManager::process_queue(Context& context) diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 61cc4d209ce..fb04320c6e5 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -229,6 +229,7 @@ class CommandManager void process_record(Context& context); void process_power(Context& context); void process_length(Context& context); + void process_direction(Context& context); void process_queue(Context& context); void process_allowstart(Context& context); void process_shuffle(Context& context); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 73ec595f61f..5972fd6f14f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -269,6 +269,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() if (m_default_fixed_laps != -1) { m_fixed_lap = m_default_fixed_laps; } + m_fixed_direction = ServerConfig::m_fixed_direction; m_extra_seconds = 0.0f; m_default_lap_multiplier = ServerConfig::m_auto_game_time_ratio; @@ -1939,6 +1940,11 @@ void ServerLobby::asynchronousUpdate() winner_vote.m_num_laps = m_fixed_lap; Log::info("ServerLobby", "Enforcing %d lap race", (int)m_fixed_lap); } + if (m_fixed_direction >= 0) + { + winner_vote.m_reverse = (m_fixed_direction == 1); + Log::info("ServerLobby", "Enforcing direction %d", (int)m_fixed_direction); + } *m_default_vote = winner_vote; m_item_seed = (uint32_t)StkTime::getTimeSinceEpoch(); ItemManager::updateRandomSeed(m_item_seed); @@ -3131,6 +3137,8 @@ void ServerLobby::startSelection(const Event *event) else if (m_fixed_lap >= 0) m_default_vote->m_num_laps = m_fixed_lap; m_default_vote->m_reverse = rg.get(2) == 0; + if (m_fixed_direction >= 0) + m_default_vote->m_reverse = (m_fixed_direction == 1); break; } case RaceManager::MINOR_MODE_FREE_FOR_ALL: @@ -5154,6 +5162,8 @@ void ServerLobby::handlePlayerVote(Event* event) { vote.m_num_laps = m_fixed_lap; } + if (m_fixed_direction >= 0) + vote.m_reverse = (m_fixed_direction == 1); // Store vote: vote.m_player_name = event->getPeer()->getPlayerProfiles()[0]->getName(); @@ -6960,6 +6970,9 @@ void ServerLobby::resetToDefaultSettings() m_fixed_lap = -1; } + if (!m_preserve.count("direction")) + m_fixed_direction = ServerConfig::m_fixed_direction; + if (!m_preserve.count("queue")) m_tracks_queue.clear(); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 26224af7482..05976260124 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -371,6 +371,8 @@ class ServerLobby : public LobbyProtocol int m_fixed_lap; + int m_fixed_direction; + float m_extra_seconds; double m_default_lap_multiplier; diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 4abb73d7217..a2efaa5dd46 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -300,6 +300,10 @@ namespace ServerConfig SERVER_CFG_DEFAULT(IntServerConfigParam(-1, "fixed-lap-count", "Use fixed lap count, negative or zero to disable.")); + SERVER_CFG_PREFIX IntServerConfigParam m_fixed_direction + SERVER_CFG_DEFAULT(IntServerConfigParam(-1, "fixed-direction", + "Use fixed direction (0 for forward or 1 for reverse), -1 to disable.")); + SERVER_CFG_PREFIX BoolServerConfigParam m_official_tracks_needed SERVER_CFG_DEFAULT(BoolServerConfigParam(true, "official-tracks-needed", "If this value is set to true, players and the server must have " From cb4594682e80322088cef0f8afed47783f7e60a6 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 11 Mar 2023 05:19:12 +0300 Subject: [PATCH 258/830] Allow negative troll-max-stop-speed with the effect that going backwards with little speed doesn't trigger troll timer --- src/modes/linear_world.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index d29a36d9aa5..1edb87b6632 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -1139,6 +1139,7 @@ void LinearWorld::serverCheckForWrongDirection(unsigned int i, float dt) if ((angle_diff > DEGREE_TO_RAD * 120.0f || angle_diff < -DEGREE_TO_RAD * 120.0f) && kart->getVelocityLC().getY() > 0.0f && + kart->getVelocityLC().getY() > -ServerConfig::m_troll_max_stop_speed && !kart->hasFinishedRace()) { ki.m_wrong_way_timer += dt; From 7fd18b4e6c21550ceba2c9fd544dd879394923f3 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 11 Mar 2023 07:59:29 +0300 Subject: [PATCH 259/830] Fix wrong speed in antitroll fixes + clarify what happens for negative values --- src/modes/linear_world.cpp | 2 +- src/network/server_config.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index 1edb87b6632..675bdc66b40 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -1139,7 +1139,7 @@ void LinearWorld::serverCheckForWrongDirection(unsigned int i, float dt) if ((angle_diff > DEGREE_TO_RAD * 120.0f || angle_diff < -DEGREE_TO_RAD * 120.0f) && kart->getVelocityLC().getY() > 0.0f && - kart->getVelocityLC().getY() > -ServerConfig::m_troll_max_stop_speed && + std::fabs(kart->getSpeed()) > -ServerConfig::m_troll_max_stop_speed && !kart->hasFinishedRace()) { ki.m_wrong_way_timer += dt; diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index a2efaa5dd46..8fb6dfc5f5b 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -332,7 +332,7 @@ namespace ServerConfig SERVER_CFG_PREFIX FloatServerConfigParam m_troll_max_stop_speed SERVER_CFG_DEFAULT(FloatServerConfigParam(5.0f, "troll-max-stop-speed", - "A player going slower than this is considered stopping.")); + "A player going slower than this is considered stopping. Negative speed allows to move with it in any direction.")); SERVER_CFG_PREFIX BoolServerConfigParam m_show_teammate_hits SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "show-teammate-hits", From cd1a4f120c7ec8c2d8bdcda27c582e05d861fd7e Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 15 Mar 2023 07:06:19 +0300 Subject: [PATCH 260/830] Initial version of TrackFilters in the queue instead of tracks, with official/addon hardcoded categories Adding a filter into the queue is currently made with pf(_back/front). Some wip tracks may be wrongly considered official for now as I only check for addon_ prefix. --- src/network/protocols/command_manager.cpp | 74 +++++++++++------------ src/network/protocols/server_lobby.cpp | 35 +++++++---- src/network/protocols/server_lobby.hpp | 6 +- src/utils/track_filter.cpp | 23 +++++-- src/utils/track_filter.hpp | 6 +- 5 files changed, 82 insertions(+), 62 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 5b7acb9096d..4f56b5c2224 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -905,7 +905,7 @@ void CommandManager::process_addons(Context& context) /*argv[1] == "soccer" ?*/ m_lobby->m_addon_soccers ))); if (apply_filters) - m_lobby->applyAllFilters(from); + m_lobby->applyAllFilters(from, false); std::vector>> result; for (const std::string& s: from) result.push_back({s, {}}); @@ -1882,6 +1882,7 @@ void CommandManager::process_direction(Context& context) void CommandManager::process_queue(Context& context) { + // todo update help when everything is changed std::string msg; auto& argv = context.m_argv; if (argv.size() < 2) @@ -1892,19 +1893,20 @@ void CommandManager::process_queue(Context& context) if (argv[1] == "show") { msg = "Queue:"; - for (const std::string& s: m_lobby->m_tracks_queue) { - msg += " " + s; + for (const TrackFilter& s: m_lobby->m_tracks_queue) { + msg += " " + s.toString(); } m_lobby->sendStringToPeer(msg, context.m_peer); return; } - if (argv[1] == "push" || argv[1] == "push_back") + if (argv[1] == "push" || argv[1] == "push_back" || argv[1] == "push_front") { if (argv.size() < 3) { error(context); return; } + bool to_front = (argv[1] == "push_front"); if (argv[2] == "-") argv[2] = getRandomMap(); else if (argv[2] == "-addon") @@ -1912,62 +1914,56 @@ void CommandManager::process_queue(Context& context) if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_all_maps, 3, false, false)) return; - m_lobby->m_tracks_queue.push_back(argv[2]); + if (to_front) + m_lobby->m_tracks_queue.emplace_front(argv[2]); + else + m_lobby->m_tracks_queue.emplace_back(argv[2]); std::string msg = "Pushed " + argv[2] - + " to the back of queue, current queue size: " + + " to the " + (to_front ? "front" : "back") + + " of queue, current queue size: " + std::to_string(m_lobby->m_tracks_queue.size()); m_lobby->sendStringToAllPeers(msg); m_lobby->updatePlayerList(); } - else if (argv[1] == "push_front") + else if (argv[1] == "pf" || argv[1] == "pf_back" || argv[1] == "pf_front") { if (argv.size() < 3) { error(context); return; } - if (argv[2] == "-") - argv[2] = getRandomMap(); - else if (argv[2] == "-addon") - argv[2] = getRandomAddonMap(); - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, - 2, m_stf_all_maps, 3, false, false)) - return; - m_lobby->m_tracks_queue.push_front(argv[2]); - std::string msg = "Pushed " + argv[2] - + " to the front of queue, current queue size: " - + std::to_string(m_lobby->m_tracks_queue.size()); - m_lobby->sendStringToAllPeers(msg); - m_lobby->updatePlayerList(); - } - else if (argv[1] == "pop" || argv[1] == "pop_front") - { - msg = ""; - if (m_lobby->m_tracks_queue.empty()) { - msg = "Queue was empty before."; + bool to_front = (argv[1] == "pf_front"); + std::string filter_text = argv[2]; + if (argv.size() > 3) { + CommandManager::restoreCmdByArgv(filter_text, argv, ' ', '"', '"', '\\', 2); } + if (to_front) + m_lobby->m_tracks_queue.emplace_front(filter_text); else - { - msg = "Popped " + m_lobby->m_tracks_queue.front() - + " from the front of the queue,"; - m_lobby->m_tracks_queue.pop_front(); - msg += " current queue size: " - + std::to_string(m_lobby->m_tracks_queue.size()); - } + m_lobby->m_tracks_queue.emplace_back(filter_text); + std::string msg = "Pushed { " + filter_text + " }" + + " to the " + (to_front ? "front" : "back") + + " of queue, current queue size: " + + std::to_string(m_lobby->m_tracks_queue.size()); m_lobby->sendStringToAllPeers(msg); m_lobby->updatePlayerList(); } - else if (argv[1] == "pop_back") + else if (argv[1] == "pop" || argv[1] == "pop_front" || argv[1] == "pop_back") { msg = ""; + bool from_back = (argv[1] == "pop_back"); if (m_lobby->m_tracks_queue.empty()) { msg = "Queue was empty before."; } else { - msg = "Popped " + m_lobby->m_tracks_queue.back() - + " from the back of the queue,"; - m_lobby->m_tracks_queue.pop_back(); + auto object = (from_back ? m_lobby->m_tracks_queue.back() : m_lobby->m_tracks_queue.front()); + msg = "Popped " + object.toString() + + " from the " + (from_back ? "back" : "front") + " of the queue,"; + if (from_back) + m_lobby->m_tracks_queue.pop_back(); + else + m_lobby->m_tracks_queue.pop_front(); msg += " current queue size: " + std::to_string(m_lobby->m_tracks_queue.size()); } @@ -2942,7 +2938,7 @@ std::string CommandManager::getRandomMap() const for (const std::string& s: m_lobby->m_entering_kts.second) { items.insert(s); } - m_lobby->applyAllFilters(items); + m_lobby->applyAllFilters(items, false); if (items.empty()) return ""; RandomGenerator rg; @@ -2960,7 +2956,7 @@ std::string CommandManager::getRandomAddonMap() const if (t->isAddon()) items.insert(s); } - m_lobby->applyAllFilters(items); + m_lobby->applyAllFilters(items, false); if (items.empty()) return ""; RandomGenerator rg; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 287a4b3309a..8844fdfdc5a 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3065,12 +3065,11 @@ void ServerLobby::startSelection(const Event *event) { m_available_kts.second.erase(track_erase); } - if (!m_tracks_queue.empty()) - { - m_available_kts.second.clear(); - m_available_kts.second.insert(m_tracks_queue.front()); - } - +// if (!m_tracks_queue.empty()) +// { +// m_available_kts.second.clear(); +// m_available_kts.second.insert(m_tracks_queue.front()); +// } max_player = 0; STKHost::get()->updatePlayers(&max_player); @@ -3097,7 +3096,7 @@ void ServerLobby::startSelection(const Event *event) else m_ai_count = 0; - applyAllFilters(m_available_kts.second); + applyAllFilters(m_available_kts.second, true); /* auto iter = m_available_kts.second.begin(); while (iter != m_available_kts.second.end()) @@ -3614,6 +3613,7 @@ void ServerLobby::checkRaceFinished() if (!m_tracks_queue.empty()) { + m_map_history.push_back(RaceManager::get()->getTrackName()); m_tracks_queue.pop_front(); // Reload GP tracks if GP ends if (m_tracks_queue.empty() && m_game_setup->isGrandPrix()) @@ -7333,8 +7333,12 @@ bool ServerLobby::canRace(STKPeer* peer) const return false; if (!m_tracks_queue.empty()) - if (peer->getClientAssets().second.count(m_tracks_queue.front()) == 0) + { + std::set st = peer->getClientAssets().second; + m_tracks_queue.front().apply(0, st, m_map_history); + if (st.empty()) return false; + } if (!m_play_requirement_tracks.empty()) for (const std::string& track: m_play_requirement_tracks) if (peer->getClientAssets().second.count(track) == 0) @@ -7443,7 +7447,7 @@ void ServerLobby::loadTracksQueueFromConfig() ServerConfig::m_tracks_order, ' '); m_tracks_queue.clear(); for (std::string& s: tokens) - m_tracks_queue.push_back(s); + m_tracks_queue.push_back(TrackFilter(s)); } // loadTracksQueueFromConfig //----------------------------------------------------------------------------- std::string ServerLobby::getGrandPrixStandings(bool showIndividual, bool showTeam) const @@ -8192,7 +8196,7 @@ void ServerLobby::resetGrandPrix() } // resetGrandPrix //----------------------------------------------------------------------------- -void ServerLobby::applyAllFilters(std::set& maps) +void ServerLobby::applyAllFilters(std::set& maps, bool use_history) { unsigned max_player = 0; STKHost::get()->updatePlayers(&max_player); @@ -8212,10 +8216,15 @@ void ServerLobby::applyAllFilters(std::set& maps) } m_global_filter.apply(max_player, maps); - if (ServerConfig::m_soccer_tournament) + if (use_history) { - m_tournament_track_filters[m_tournament_game].apply( - max_player, maps, m_tournament_arenas); + if (ServerConfig::m_soccer_tournament) + { + m_tournament_track_filters[m_tournament_game].apply( + max_player, maps, m_tournament_arenas); + } + if (!m_tracks_queue.empty()) + m_tracks_queue.front().apply(max_player, maps, m_map_history); } } // applyAllFilters //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index caf29b2f9fd..a8ce9a7fa5e 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -361,7 +361,9 @@ class ServerLobby : public LobbyProtocol std::set m_temp_banned; - std::deque m_tracks_queue; + std::deque m_tracks_queue; + + std::vector m_map_history; std::map m_gp_scores; @@ -677,7 +679,7 @@ class ServerLobby : public LobbyProtocol void resetGrandPrix(); void erasePeerReady(std::shared_ptr peer) { m_peers_ready.erase(peer); } - void applyAllFilters(std::set& maps); + void applyAllFilters(std::set& maps, bool use_history); static int m_default_fixed_laps; }; // class ServerLobby diff --git a/src/utils/track_filter.cpp b/src/utils/track_filter.cpp index 03bb9d44025..be99041ff07 100644 --- a/src/utils/track_filter.cpp +++ b/src/utils/track_filter.cpp @@ -40,11 +40,11 @@ TrackFilter::TrackFilter() TrackFilter::TrackFilter(std::string input) { + initial_string = input; auto tokens = StringUtils::split(input, ' '); bool good = true; others = false; - if (tokens.size() == 0) - others = true; + bool unknown_others = true; for (unsigned i = 0; i < tokens.size(); i++) { if (tokens[i] == "" || tokens[i] == " ") @@ -71,10 +71,12 @@ TrackFilter::TrackFilter(std::string input) } else if (tokens[i] == "other:yes") { + unknown_others = false; others = true; } else if (tokens[i] == "other:no") { + unknown_others = false; others = false; } else if (tokens[i][0] == '%') @@ -120,9 +122,14 @@ TrackFilter::TrackFilter(std::string input) } } } + if (unknown_others) + if (!allowed.empty() && !w_allowed.empty()) + others = false; + else + others = true; } // TrackFilter //----------------------------------------------------------------------------- -std::string TrackFilter::get(std::vector& vec, int index) +std::string TrackFilter::get(const std::vector& vec, int index) { if (index >= 0 && index < vec.size()) return vec[index]; @@ -140,7 +147,7 @@ void TrackFilter::apply(int num_players, std::set& input) const //----------------------------------------------------------------------------- void TrackFilter::apply(int num_players, std::set& input, - std::vector& wildcards) const + const std::vector& wildcards) const { std::set copy = input; input.clear(); @@ -162,7 +169,7 @@ void TrackFilter::apply(int num_players, std::set& input, for (const std::string& s: copy) { - bool addon = (s.length() >= 6 && s.substr(6) == "addon_"); + bool addon = (s.length() >= 6 && s.substr(0, 6) == "addon_"); bool yes = false; bool no = false; auto it = max_players.find(s); @@ -203,5 +210,9 @@ void TrackFilter::apply(int num_players, std::set& input, } } // apply (2) //----------------------------------------------------------------------------- - +std::string TrackFilter::toString() const +{ + return "{ " + initial_string + " }"; // todo make it shorter +} // toString +//----------------------------------------------------------------------------- /* EOF */ diff --git a/src/utils/track_filter.hpp b/src/utils/track_filter.hpp index d35ba544aa4..ffeddc69a82 100644 --- a/src/utils/track_filter.hpp +++ b/src/utils/track_filter.hpp @@ -37,6 +37,7 @@ struct TrackFilter { + std::string initial_string; bool m_include_available = true; bool m_include_unavailable = true; bool m_include_official = true; @@ -50,11 +51,12 @@ struct TrackFilter bool others; // whether not specified tracks are allowed TrackFilter(); TrackFilter(std::string input); - static std::string get(std::vector& vec, int index); + static std::string get(const std::vector& vec, int index); void apply(int num_players, std::set& input) const; void apply(int num_players, std::set& input, - std::vector& wildcards) const; + const std::vector& wildcards) const; bool isPickingRandom() const { return m_pick_random; } + std::string toString() const; }; #endif From a2d2ceafe3c79da46346918bdc32da08ad1b0bce Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 16 Mar 2023 04:04:26 +0300 Subject: [PATCH 261/830] Fix extra appearance of other:yes in the filter --- src/utils/track_filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/track_filter.cpp b/src/utils/track_filter.cpp index be99041ff07..7da504b114a 100644 --- a/src/utils/track_filter.cpp +++ b/src/utils/track_filter.cpp @@ -123,7 +123,7 @@ TrackFilter::TrackFilter(std::string input) } } if (unknown_others) - if (!allowed.empty() && !w_allowed.empty()) + if (!allowed.empty() || !w_allowed.empty()) others = false; else others = true; From 2720eed5207bd44c780c9e153c5e572c6e30f429 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 26 Mar 2023 02:55:08 +0300 Subject: [PATCH 262/830] Try to add auth commands (for openssl) No mbedtls support for now --- src/network/crypto_mbedtls.cpp | 21 ++++++++ src/network/crypto_mbedtls.hpp | 2 + src/network/crypto_openssl.cpp | 36 +++++++++++++ src/network/crypto_openssl.hpp | 4 ++ src/network/protocols/command_manager.cpp | 64 +++++++++++++++++++++++ src/network/protocols/command_manager.hpp | 18 +++++++ src/utils/string_utils.cpp | 10 ++++ src/utils/string_utils.hpp | 3 ++ 8 files changed, 158 insertions(+) diff --git a/src/network/crypto_mbedtls.cpp b/src/network/crypto_mbedtls.cpp index a1c0a13b0c1..42184d22c4b 100644 --- a/src/network/crypto_mbedtls.cpp +++ b/src/network/crypto_mbedtls.cpp @@ -41,6 +41,27 @@ std::string Crypto::base64(const std::vector& input) return result; } // base64 +// ============================================================================ +std::string Crypto::base64url(const std::vector& input) +{ + std::string result = base64(input); + while (!result.empty() && result.back() == '=') + result.pop_back(); + std::string answer = ""; + for (char& c: result) + { + if (c == '+') + answer.push_back('-'); + else if (c == '/') + answer.push_back('_'); + else if (c == '\n') + continue; + else + answer.push_back(c); + } + return answer; +} // base64url + // ============================================================================ std::vector Crypto::decode64(std::string input) { diff --git a/src/network/crypto_mbedtls.hpp b/src/network/crypto_mbedtls.hpp index 77447119007..381c6487770 100644 --- a/src/network/crypto_mbedtls.hpp +++ b/src/network/crypto_mbedtls.hpp @@ -59,6 +59,8 @@ class Crypto // ------------------------------------------------------------------------ static std::string base64(const std::vector& input); // ------------------------------------------------------------------------ + static std::string base64url(const std::vector& input); + // ------------------------------------------------------------------------ static std::vector decode64(std::string input); // ------------------------------------------------------------------------ static std::array sha256(const std::string& input); diff --git a/src/network/crypto_openssl.cpp b/src/network/crypto_openssl.cpp index 95be0cf4c73..d48f425de54 100644 --- a/src/network/crypto_openssl.cpp +++ b/src/network/crypto_openssl.cpp @@ -55,6 +55,27 @@ std::string Crypto::base64(const std::vector& input) return result; } // base64 +// ============================================================================ +std::string Crypto::base64url(const std::vector& input) +{ + std::string result = base64(input); + while (!result.empty() && result.back() == '=') + result.pop_back(); + std::string answer = ""; + for (char& c: result) + { + if (c == '+') + answer.push_back('-'); + else if (c == '/') + answer.push_back('_'); + else if (c == '\n') + continue; + else + answer.push_back(c); + } + return answer; +} // base64url + // ============================================================================ std::vector Crypto::decode64(std::string input) { @@ -90,6 +111,21 @@ std::array Crypto::sha256(const std::string& input) return result; } // sha256 +// ============================================================================ +std::vector Crypto::hmac_sha256_array(const std::string& key, const std::string& input) +{ + unsigned char res[100]; + unsigned result_len = 0; + HMAC(EVP_sha256(), + (const void*)key.c_str(), key.size(), + (const unsigned char*)(input.c_str()), input.size(), + res, &result_len); + std::vector output; + for (int i = 0; i < result_len; ++i) + output.push_back(res[i]); + return output; +} // hmac_sha256_array + // ============================================================================ std::string Crypto::m_client_key; std::string Crypto::m_client_iv; diff --git a/src/network/crypto_openssl.hpp b/src/network/crypto_openssl.hpp index 0ecd361b758..5cb75038ed2 100644 --- a/src/network/crypto_openssl.hpp +++ b/src/network/crypto_openssl.hpp @@ -80,10 +80,14 @@ class Crypto // ------------------------------------------------------------------------ static std::string base64(const std::vector& input); // ------------------------------------------------------------------------ + static std::string base64url(const std::vector& input); + // ------------------------------------------------------------------------ static std::vector decode64(std::string input); // ------------------------------------------------------------------------ static std::array sha256(const std::string& input); // ------------------------------------------------------------------------ + static std::vector hmac_sha256_array(const std::string& key, const std::string& input); + // ------------------------------------------------------------------------ static std::unique_ptr getClientCrypto() { assert(!m_client_key.empty()); diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 4f56b5c2224..39bc7faebad 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -118,6 +118,36 @@ std::string CommandManager::FileResource::get() } // FileResource::get // ======================================================================== +CommandManager::AuthResource::AuthResource(std::string secret, std::string server, + std::string link_format): + m_secret(secret), m_server(server), m_link_format(link_format) +{ + +} // AuthResource::AuthResource +// ======================================================================== + +std::string CommandManager::AuthResource::get(std::string username) +{ +#ifdef ENABLE_CRYPTO_OPENSSL + std::string header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"; + uint64_t timestamp = StkTime::getTimeSinceEpoch(); + uint64_t period = 3600; + std::string payload = "{\"name\":\"" + username + "\","; + payload += "\"iat\":\"" + std::to_string(timestamp) + "\","; + payload += "\"exp\":\"" + std::to_string(timestamp + period) + "\","; + payload += "\"serv\":\"" + m_server + "\"}"; + header = Crypto::base64url(StringUtils::toUInt8Vector(header)); + payload = Crypto::base64url(StringUtils::toUInt8Vector(payload)); + std::string message = header + "." + payload; + std::string signature = Crypto::base64url(Crypto::hmac_sha256_array(m_secret, message)); + std::string token = message + "." + signature; + std::string response = StringUtils::insertValues(m_link_format, token.c_str()); + return response; +#else + return "This command is currently only supported for OpenSSL"; +#endif +} // AuthResource::get +// ======================================================================== void CommandManager::initCommandsInfo() { @@ -141,6 +171,9 @@ void CommandManager::initCommandsInfo() std::string permissions = ""; std::string description = ""; std::string aliases = ""; + std::string secret = ""; // for auth-command + std::string link_format = ""; // for auth-command + std::string server = ""; // for auth-command // If enabled is not empty, command is added iff the server name is in enabled // Otherwise it is added iff the server name is not in disabled std::string enabled = ""; @@ -195,6 +228,15 @@ void CommandManager::initCommandsInfo() addFileResource(name, file, interval); m_config_descriptions[name] = CommandDescription(usage, permissions, description); } + else if (node_name == "auth-command") + { + node->get("secret", &secret); + node->get("server", &server); + node->get("link-format", &link_format); + m_commands.emplace_back(name, &CommandManager::process_auth, UP_EVERYONE, MS_DEFAULT); + addAuthResource(name, secret, server, link_format); + m_config_descriptions[name] = CommandDescription(usage, permissions, description); + } } delete root; } // initCommandsInfo @@ -663,6 +705,28 @@ void CommandManager::process_file(Context& context) } // process_text // ======================================================================== +void CommandManager::process_auth(Context& context) +{ + std::string response; + auto it = m_auth_resources.find(context.m_argv[0]); + if (it == m_auth_resources.end()) + response = "Error: auth method not found for a command " + + context.m_argv[0]; + else + { + auto profile = context.m_peer->getPlayerProfiles()[0]; + std::string username = StringUtils::wideToUtf8(profile->getName()); + int online_id = profile->getOnlineId(); + if (online_id == 0) + response = "Error: you need to join with an " + "online account to use auth methods"; + else + response = it->second.get(username); + } + m_lobby->sendStringToPeer(response, context.m_peer); +} // process_text +// ======================================================================== + void CommandManager::process_commands(Context& context) { std::string result = "Available commands:"; diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index fb04320c6e5..53a7f89dee9 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -61,6 +61,18 @@ class CommandManager std::string get(); }; + struct AuthResource + { + std::string m_secret; + std::string m_server; + std::string m_link_format; + + AuthResource(std::string secret = "", std::string server = "", + std::string link_format = ""); + + std::string get(std::string username); + }; + enum ModeScope: int { MS_DEFAULT = 1, @@ -160,6 +172,8 @@ class CommandManager std::map m_file_resources; + std::map m_auth_resources; + std::map m_votables; std::queue m_triggered_votables; @@ -203,6 +217,7 @@ class CommandManager void process_help(Context& context); void process_text(Context& context); void process_file(Context& context); + void process_auth(Context& context); void process_commands(Context& context); void process_replay(Context& context); void process_start(Context& context); @@ -282,6 +297,9 @@ class CommandManager void addFileResource(std::string key, std::string file, uint64_t interval) { m_file_resources[key] = FileResource(file, interval); } + void addAuthResource(std::string key, std::string secret, std::string server, std::string link_format) + { m_auth_resources[key] = AuthResource(secret, server, link_format); } + void addUser(std::string& s); void deleteUser(std::string& s); diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index d365e1f63b9..9c41998dd03 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -1372,6 +1372,16 @@ namespace StringUtils } return distance[n][m]; } // getEditDistance + // ------------------------------------------------------------------------ + + std::vector toUInt8Vector(const std::string& s) + { + std::vector result; + for (const char& c: s) + result.push_back((uint8_t)c); + return result; + } // toUInt8Vector + // ------------------------------------------------------------------------ } // namespace StringUtils /* EOF */ diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index 88559656177..37c499380b7 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -338,6 +338,9 @@ namespace StringUtils bool isEqual(char a, char b, char any_char, bool case_sensitive = true); int getEditDistance(const std::string& a, const std::string& b, bool case_sensitive = true, char any_substr = 0, char any_char = 0); + // ------------------------------------------------------------------------ + std::vector toUInt8Vector(const std::string& s); + // ------------------------------------------------------------------------ } // namespace StringUtils From 81c66c3c6fbb1eebfb864901faa5c42a029e7712 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 15 Apr 2023 03:08:21 +0300 Subject: [PATCH 263/830] Allow specifying number of maps to select randomly in track filter e.g. /queue pf random 5 --- src/utils/track_filter.cpp | 31 +++++++++++++++++++++++++------ src/utils/track_filter.hpp | 1 + 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/utils/track_filter.cpp b/src/utils/track_filter.cpp index 7da504b114a..a3a6a2499af 100644 --- a/src/utils/track_filter.cpp +++ b/src/utils/track_filter.cpp @@ -50,7 +50,18 @@ TrackFilter::TrackFilter(std::string input) if (tokens[i] == "" || tokens[i] == " ") continue; else if (tokens[i] == "random") + { m_pick_random = true; + m_random_count = 1; + int value = -1; + if (i + 1 < tokens.size() + && StringUtils::parseString(tokens[i + 1], &value) + && value > 0) + { + m_random_count = value; + ++i; + } + } else if (tokens[i] == "available") m_include_unavailable = false; else if (tokens[i] == "unavailable") @@ -199,14 +210,22 @@ void TrackFilter::apply(int num_players, std::set& input, if (yes) input.insert(s); } - if (m_pick_random && input.size() > 0) + if (m_pick_random && input.size() > m_random_count) { RandomGenerator rg; - std::set::iterator it = input.begin(); - std::advance(it, rg.get((int)input.size())); - std::string choice = *it; - input.clear(); - input.insert(choice); + std::vector take(m_random_count, 1); + take.resize(input.size(), 0); + // Shuffling the vector like it's not having the form 11..1100..00 + for (unsigned i = 1; i < input.size(); i++) + std::swap(take[rg.get(i)], take[i]); + std::set result; + for (std::set::iterator it = input.begin(); it != input.end(); it++) + { + if (take.back() == 1) + result.insert(*it); + take.pop_back(); + } + std::swap(result, input); } } // apply (2) //----------------------------------------------------------------------------- diff --git a/src/utils/track_filter.hpp b/src/utils/track_filter.hpp index ffeddc69a82..a074070f948 100644 --- a/src/utils/track_filter.hpp +++ b/src/utils/track_filter.hpp @@ -43,6 +43,7 @@ struct TrackFilter bool m_include_official = true; bool m_include_addons = true; bool m_pick_random = false; + int m_random_count = 0; std::set allowed; std::set forbidden; std::vector w_allowed; // wildcards From a8ae8bd01ea1e4cfd09049ab5901caab572a9eca Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 24 May 2023 15:30:48 +0300 Subject: [PATCH 264/830] Add /id command --- data/commands.xml | 5 +++++ src/network/protocols/command_manager.cpp | 18 ++++++++++++++++++ src/network/protocols/command_manager.hpp | 1 + 3 files changed, 24 insertions(+) diff --git a/data/commands.xml b/data/commands.xml index 7d9c0624fdf..c1745d267a0 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -47,6 +47,11 @@ permissions="everyone" description="Displays numbers of players who have the corresponding addon, and whether server has it. Displays up to 5 random players from each category." /> + sendStringToPeer(response, context.m_peer); +} // process_id +// ======================================================================== + void CommandManager::process_lsa(Context& context) { std::string response = ""; diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 53a7f89dee9..384214231c8 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -225,6 +225,7 @@ class CommandManager void process_spectate(Context& context); void process_addons(Context& context); void process_checkaddon(Context& context); + void process_id(Context& context); void process_lsa(Context& context); void process_pha(Context& context); void process_kick(Context& context); From 005ea991697f004c9383f24b361b33d225b71e4d Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 24 May 2023 16:25:08 +0300 Subject: [PATCH 265/830] Make /scoring, /length, /queue show current setting by default; small convenience changes /scoring without parameters no longer switches to default, use /scoring default /queue now shows size, can be shuffled and cleared /scoring does not accept unknown scoring types now --- data/commands.xml | 12 +++---- src/modes/world_with_rank.cpp | 2 +- src/network/protocols/command_manager.cpp | 42 +++++++++++++++++++---- src/network/protocols/server_lobby.cpp | 10 ++++++ 4 files changed, 52 insertions(+), 14 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index c1745d267a0..f899d5f6a0c 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -168,9 +168,9 @@ description="Enters the hammer mode if the password is correct." /> & { m_custom_scoring_type = type; m_custom_scoring_params = params; - if (type == "" || type == "standard") { + if (type == "" || type == "standard" || type == "default") { m_custom_scoring = false; return; } diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 4f4e8319657..20c5f212324 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -1871,8 +1871,7 @@ void CommandManager::process_length(Context& context) std::string msg; if (argv.size() < 2) { - error(context); - return; + argv.push_back("check"); } if (argv[1] == "check") { @@ -1969,12 +1968,11 @@ void CommandManager::process_queue(Context& context) auto& argv = context.m_argv; if (argv.size() < 2) { - error(context); - return; + argv.push_back("show"); } if (argv[1] == "show") { - msg = "Queue:"; + msg = StringUtils::insertValues("Queue (size = %d):", (int)m_lobby->m_tracks_queue.size()); for (const TrackFilter& s: m_lobby->m_tracks_queue) { msg += " " + s.toString(); } @@ -2052,6 +2050,25 @@ void CommandManager::process_queue(Context& context) m_lobby->sendStringToAllPeers(msg); m_lobby->updatePlayerList(); } + else if (argv[1] == "clear") + { + msg = StringUtils::insertValues( + "Queue is now empty (previous size: %d)", + (int)m_lobby->m_tracks_queue.size()); + m_lobby->m_tracks_queue.clear(); + m_lobby->sendStringToAllPeers(msg); + m_lobby->updatePlayerList(); + } + else if (argv[1] == "shuffle") + { + std::random_device rd; + std::mt19937 g(rd()); + auto& queue = m_lobby->m_tracks_queue; + std::shuffle(queue.begin(), queue.end(), g); + msg = "Queue is now shuffled"; + m_lobby->sendStringToAllPeers(msg); + m_lobby->updatePlayerList(); + } } // process_queue // ======================================================================== @@ -2417,10 +2434,21 @@ void CommandManager::process_scoring(Context& context) auto& argv = context.m_argv; std::string cmd2; CommandManager::restoreCmdByArgv(cmd2, argv, ' ', '"', '"', '\\', 1); - if (m_lobby->loadCustomScoring(cmd2)) { + if (cmd2 == "") + { + msg = "Current scoring is \"" + m_lobby->m_scoring_type; + for (int param: m_lobby->m_scoring_int_params) + msg += StringUtils::insertValues(" %d", param); + msg += "\""; + m_lobby->sendStringToPeer(msg, context.m_peer); + } + else if (m_lobby->loadCustomScoring(cmd2)) + { msg = "Scoring set to \"" + cmd2 + "\""; m_lobby->sendStringToAllPeers(msg); - } else { + } + else + { msg = "Scoring could not be parsed from \"" + cmd2 + "\""; m_lobby->sendStringToPeer(msg, context.m_peer); } diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 8844fdfdc5a..ae85dcc9363 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7511,6 +7511,9 @@ std::string ServerLobby::getGrandPrixStandings(bool showIndividual, bool showTea //----------------------------------------------------------------------------- bool ServerLobby::loadCustomScoring(std::string& scoring) { + std::set available_scoring_types = { + "standard", "default", "", "inc", "fixed", "linear-gap", "exp-gap" + }; auto previous_params = m_scoring_int_params; auto previous_type = m_scoring_type; m_scoring_int_params.clear(); @@ -7524,6 +7527,13 @@ bool ServerLobby::loadCustomScoring(std::string& scoring) return true; } m_scoring_type = params[0]; + if (available_scoring_types.count(m_scoring_type) == 0) + { + Log::warn("ServerLobby", "Unknown scoring type %s, fallback.", m_scoring_type.c_str()); + m_scoring_int_params = previous_params; + m_scoring_type = previous_type; + return false; + } for (unsigned i = 1; i < params.size(); i++) { int param; From 53f8184b0f6d3237022558d556395591dde20e1f Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 2 Jun 2023 00:47:02 +0300 Subject: [PATCH 266/830] [Database] Allow to save kart color, kart characteristics and powerup config names, disconnection time Please note that the results table schema may change later before merging #5. In this commit, the changes are: - added items TEXT, kart_color REAL, is_quit INTEGER - result stores kart's race time independently of whether it's a quit or not - config stores kart characteristics file name, items stores powerup file name, empty if the name is default. One may need to change NULL values in config and items to an empty string. --- src/karts/kart_properties_manager.hpp | 7 ++++++ src/main.cpp | 1 + src/network/protocols/server_lobby.cpp | 33 ++++++++++++++++++++------ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/karts/kart_properties_manager.hpp b/src/karts/kart_properties_manager.hpp index 9466020a60f..e0cd4c390ba 100644 --- a/src/karts/kart_properties_manager.hpp +++ b/src/karts/kart_properties_manager.hpp @@ -70,6 +70,8 @@ class KartPropertiesManager: public NoCopy std::map > m_kart_type_characteristics; std::map > m_player_characteristics; + std::string m_file_name; + protected: typedef PtrVector KartPropertiesVector; @@ -149,6 +151,11 @@ class KartPropertiesManager: public NoCopy // ------------------------------------------------------------------------ void onDemandLoadKartTextures(const std::set& kart_list, bool unload_unused = true); + // ------------------------------------------------------------------------ + void setFileName(const std::string file_name) { m_file_name = file_name; } + // ------------------------------------------------------------------------ + std::string getFileName() { return m_file_name; } + }; extern KartPropertiesManager *kart_properties_manager; diff --git a/src/main.cpp b/src/main.cpp index b7311b7ccfb..90d2d7f5763 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1960,6 +1960,7 @@ void initRest() std::string char_file; if (!CommandLine::has("--char-file", &char_file)) char_file = "kart_characteristics.xml"; + kart_properties_manager->setFileName(char_file); XMLNode characteristicsNode(file_manager->getAsset(char_file)); kart_properties_manager->loadCharacteristics(&characteristicsNode); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index ae85dcc9363..9ec83517fde 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6763,6 +6763,14 @@ void ServerLobby::updateGnuElimination() void ServerLobby::storeResults() { #ifdef ENABLE_SQLITE3 + std::string powerup_string = powerup_manager->getFileName(); + std::string kc_string = kart_properties_manager->getFileName(); + // TODO: don't use file names as constants + if (powerup_string == "powerup.xml") + powerup_string = ""; + if (kc_string == "kart_characteristics.xml") + kc_string = ""; + bool racing_mode = false; bool ffa = RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL; @@ -6792,9 +6800,11 @@ void ServerLobby::storeResults() { std::string get_query = StringUtils::insertValues("SELECT username, " "result FROM '%s' WHERE venue = '%s' and reverse = '%s' " - "and mode = '%s' and laps = %d order by result asc, time asc limit 1;", + "and mode = '%s' and laps = %d and config = '%s' " + "and items = '%s' and is_quit = 0 " + "order by result asc, time asc limit 1;", records_table_name.c_str(), track_name.c_str(), reverse_string.c_str(), mode_name.c_str(), - laps_number); + laps_number, kc_string.c_str(), powerup_string.c_str()); auto ret = vectorSQLQuery(get_query, 2); record_fetched = ret.first; if (record_fetched && ret.second[0].size() > 0) @@ -6821,8 +6831,11 @@ void ServerLobby::storeResults() std::vector scores; std::vector karts; std::vector lap_counts; + std::vector colors; + std::vector has_quit; for (int i = 0; i < player_count; i++) { + // TODO why I cannot use get()->getPlayerName? std::string username = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(i).getPlayerName()); for (std::string& username: usernames) { @@ -6835,11 +6848,12 @@ void ServerLobby::storeResults() double score = DISCONNECT_TIME; std::string kart_name = w->getKart(i)->getIdent(); std::stringstream elapsed_string; + float kart_color = RaceManager::get()->getKartColor(i); if (racing_mode) { - if (!w->getKart(i)->isEliminated()) - score = RaceManager::get()->getKartRaceTime(i); + score = RaceManager::get()->getKartRaceTime(i); + has_quit.push_back(w->getKart(i)->isEliminated() ? 1 : 0); elapsed_string << std::setprecision(4) << std::fixed << score; if (best_cur_player_idx == -1 || score < best_cur_time) { @@ -6852,6 +6866,7 @@ void ServerLobby::storeResults() { if (w->getKart(i)->isEliminated()) continue; + has_quit.push_back(0); if (ffa_world) { score = ffa_world->getKartScore(i); @@ -6863,6 +6878,7 @@ void ServerLobby::storeResults() scores.push_back(elapsed_string.str()); karts.push_back(kart_name); lap_counts.push_back(laps_number); + colors.push_back(kart_color); } if (ServerConfig::m_preserve_battle_scores) { @@ -6872,6 +6888,8 @@ void ServerLobby::storeResults() lap_counts.push_back(0); scores.push_back(std::to_string(p.second)); karts.push_back("unknown"); + colors.push_back(-1); + has_quit.push_back(1); } } m_saved_ffa_points.clear(); @@ -6881,18 +6899,19 @@ void ServerLobby::storeResults() "INSERT INTO %s " "(username, venue, reverse, mode, laps, result" #ifdef ENABLE_RECORDS_V2 - ", difficulty, kart, config" + ", difficulty, kart, config, items, kart_color, is_quit" #endif ") " "VALUES (?, '%s', '%s', '%s', %d, '%s'" #ifdef ENABLE_RECORDS_V2 - ", %d, '%s', '%s'" + ", %d, '%s', '%s', '%s', %f, %d" #endif ");", m_results_table_name.c_str(), track_name.c_str(), reverse_string.c_str(), mode_name.c_str(), lap_counts[i], scores[i].c_str() #ifdef ENABLE_RECORDS_V2 - , getDifficulty(), karts[i].c_str(), "" + , getDifficulty(), karts[i].c_str(), kc_string.c_str(), + powerup_string.c_str(), colors[i], has_quit[i] #endif ); std::string name = usernames[i]; From 6b0f730b4e2cc4705b6d4eb43c6f152f639c2c67 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 2 Jun 2023 01:42:42 +0300 Subject: [PATCH 267/830] Fix disconnecting players showing up in beaten record message --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 9ec83517fde..59035868486 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6855,7 +6855,7 @@ void ServerLobby::storeResults() score = RaceManager::get()->getKartRaceTime(i); has_quit.push_back(w->getKart(i)->isEliminated() ? 1 : 0); elapsed_string << std::setprecision(4) << std::fixed << score; - if (best_cur_player_idx == -1 || score < best_cur_time) + if (!w->getKart(i)->isEliminated() && (best_cur_player_idx == -1 || score < best_cur_time)) { best_cur_player_idx = i; best_cur_time = score; From ffc66fab677486ab810a14a6b5f3a10e90ade40f Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 19 Jun 2023 17:19:49 +0300 Subject: [PATCH 268/830] Subcommands big update, detailed description below - Allow subcommands - now commands form a tree, and not just an array - Move definitions of commands to commands.xml, that means, only the code for non-trivial commands and a few permissions for commands are hardcoded; otherwise, whether a command exists or who can use it is decided by server host only - Rewrite /commands and /help according to new structure - Split several commands into a public version without arguments for checking the value of the corresponding parameter, and a private version with arguments for editing the value - Add a message when invoking not implemented commands mentioned in commands.xml - Allow reading bitwise OR of bitmask enum values from XML (currently ints cannot be read though) Notes: - If a command has subcommands, it can only be invoked without arguments - The only subcommand of another command can be specified as omit-name="true", then it means it can be found by its name, but its name should not be written when invoking command. This is done to allow using e.g. /troll and /troll 1 at the same time, invoking "looking" and "editing" commands for them (instead of /troll = 1). --- data/commands.xml | 520 ++++++-- src/network/protocols/command_manager.cpp | 1325 +++++++++++++-------- src/network/protocols/command_manager.hpp | 95 +- src/utils/enum_extended_reader.cpp | 39 + src/utils/enum_extended_reader.hpp | 43 + 5 files changed, 1385 insertions(+), 637 deletions(-) create mode 100644 src/utils/enum_extended_reader.cpp create mode 100644 src/utils/enum_extended_reader.hpp diff --git a/data/commands.xml b/data/commands.xml index f899d5f6a0c..ec4af512130 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -1,432 +1,702 @@ + + usage="/config" + permissions-verbose="everyone" + description="Shows game mode and difficulty used right now." + permissions="UP_EVERYONE" + state-scope="SS_ALWAYS" + > + + + usage="/length" + permissions-verbose="everyone" + description="Contains functions related to length of the game. Without arguments, shows the current setting. Arguments can be used only with permissions, check /commands length and /help length (argument) for more details." + permissions="UP_EVERYONE" + state-scope="SS_ALWAYS" + > + + + + + usage="/direction" + permissions-verbose="everyone" + description="Prints the currently set direction of the game. Arguments can be used only with permissions, check /commands direction and /help direction = for more details." + permissions="UP_EVERYONE" + state-scope="SS_ALWAYS" + > + + + usage="/queue" + permissions-verbose="everyone" + description="Contains functions related to track queue. Without arguments, shows the current queue. Arguments can be used only with permissions, check /commands queue and /help queue (argument) for more details." + permissions="UP_EVERYONE" + state-scope="SS_ALWAYS" + > + + + + + + + + + + + + + + + usage="/allowstart" + permissions-verbose="everyone" + description="Shows if the game can start right now." + permissions="UP_EVERYONE" + > + + + usage="/shuffle" + permissions-verbose="everyone" + description="Shows if the Grand Prix grid is shuffled before each race, or it corresponds to the standings (0)." + permissions="UP_EVERYONE" + > + + + usage="/troll" + permissions-verbose="everyone" + description="Shows whether anti-troll system is enabled." + permissions="UP_EVERYONE" + state-scope="SS_ALWAYS" + > + + + usage="/hitmsg" + permissions-verbose="everyone" + description="Shows whether the messages about teammate hits are displayed." + permissions="UP_EVERYONE" + state-scope="SS_ALWAYS" + > + + + usage="/teamhit" + permissions-verbose="everyone" + description="Shows whether the teammate hits are punished ingame." + permissions="UP_EVERYONE" + state-scope="SS_ALWAYS" + > + + + usage="/scoring" + permissions-verbose="everyone" + description="Shows Grand Prix scoring used now." + permissions="UP_EVERYONE" + state-scope="SS_ALWAYS" + > + + + permissions-verbose="everyone; votable" + description="A test command. Deprecated. Try /commands test" + permissions="UP_EVERYONE | PE_VOTED"> + + + + usage="/slots" + permissions-verbose="everyone" + description="Shows the number of playable slots." + permissions="UP_EVERYONE" + state-scope="SS_LOBBY" + > + + + usage="/preserve" + permissions-verbose="everyone" + description="Shows which settings are preserved when all players leave. Possible settings: mode, elim, laps, queue, replay, direction." + permissions="UP_EVERYONE" + > + + diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 20c5f212324..2ea4050723f 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -71,13 +71,42 @@ #include #include #include - +#include + +// ======================================================================== +EnumExtendedReader CommandManager::mode_scope_reader({ + {"MS_DEFAULT", MS_DEFAULT}, + {"MS_SOCCER_TOURNAMENT", MS_SOCCER_TOURNAMENT} +}); +EnumExtendedReader CommandManager::state_scope_reader({ + {"SS_LOBBY", SS_LOBBY}, + {"SS_INGAME", SS_INGAME}, + {"SS_ALWAYS", SS_ALWAYS} +}); +EnumExtendedReader CommandManager::permission_reader({ + {"PE_NONE", PE_NONE}, + {"PE_SPECTATOR", PE_SPECTATOR}, + {"PE_USUAL", PE_USUAL}, + {"PE_CROWNED", PE_CROWNED}, + {"PE_SINGLE", PE_SINGLE}, + {"PE_HAMMER", PE_HAMMER}, + {"PE_CONSOLE", PE_CONSOLE}, + {"PE_VOTED_SPECTATOR", PE_VOTED_SPECTATOR}, + {"PE_VOTED_NORMAL", PE_VOTED_NORMAL}, + {"PE_VOTED", PE_VOTED}, + {"UP_CONSOLE", UP_CONSOLE}, + {"UP_HAMMER", UP_HAMMER}, + {"UP_SINGLE", UP_SINGLE}, + {"UP_CROWNED", UP_CROWNED}, + {"UP_NORMAL", UP_NORMAL}, + {"UP_EVERYONE", UP_EVERYONE} +}); // ======================================================================== CommandManager::FileResource::FileResource(std::string file_name, uint64_t interval) { - m_file_name = file_name; + m_file_name = std::move(file_name); m_interval = interval; m_contents = ""; m_last_invoked = 0; @@ -92,7 +121,7 @@ void CommandManager::FileResource::read() // idk what to do with absolute or relative paths const std::string& path = /*ServerConfig::getConfigDirectory() + "/" + */m_file_name; std::ifstream message(FileUtils::getPortableReadingPath(path)); - std::string answer = ""; + std::string answer; if (message.is_open()) { for (std::string line; std::getline(message, line); ) @@ -126,7 +155,7 @@ CommandManager::AuthResource::AuthResource(std::string secret, std::string serve } // AuthResource::AuthResource // ======================================================================== -std::string CommandManager::AuthResource::get(std::string username) +std::string CommandManager::AuthResource::get(const std::string& username) const { #ifdef ENABLE_CRYPTO_OPENSSL std::string header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"; @@ -149,6 +178,17 @@ std::string CommandManager::AuthResource::get(std::string username) } // AuthResource::get // ======================================================================== +CommandManager::Command::Command(std::string name, + void (CommandManager::*f)(Context& context), + int permissions, + int mode_scope, + int state_scope): + m_name(name), m_action(f), m_permissions(permissions), + m_mode_scope(mode_scope), m_state_scope(state_scope) +{ +} // Command::Command(5) +// ======================================================================== + void CommandManager::initCommandsInfo() { const std::string file_name = file_manager->getAsset("commands.xml"); @@ -158,186 +198,257 @@ void CommandManager::initCommandsInfo() root->get("version", &version); if (version != 1) Log::warn("CommandManager", "command.xml has version %d which is not supported", version); - for (unsigned int i = 0; i < num_nodes; i++) - { - const XMLNode *node = root->getNode(i); - std::string node_name = node->getName(); - // here the commands go - std::string name = ""; - std::string text = ""; // for text-command - std::string file = ""; // for file-command - uint64_t interval = 0; // for file-command - std::string usage = ""; - std::string permissions = ""; - std::string description = ""; - std::string aliases = ""; - std::string secret = ""; // for auth-command - std::string link_format = ""; // for auth-command - std::string server = ""; // for auth-command - // If enabled is not empty, command is added iff the server name is in enabled - // Otherwise it is added iff the server name is not in disabled - std::string enabled = ""; - std::string disabled = ""; - node->get("enabled", &enabled); - node->get("disabled", &disabled); - std::vector enabled_split = StringUtils::split(enabled, ' '); - std::vector disabled_split = StringUtils::split(disabled, ' '); - bool ok; - if (!enabled.empty()) - { - ok = false; - for (const std::string& s: enabled_split) - if (s == ServerConfig::m_server_uid) - ok = true; - } - else - { - ok = true; - for (const std::string& s: disabled_split) - if (s == ServerConfig::m_server_uid) - ok = false; - } - if (!ok) - continue; - node->get("name", &name); - node->get("usage", &usage); - node->get("permissions", &permissions); - node->get("description", &description); - node->get("aliases", &aliases); - std::vector aliases_split = StringUtils::split(aliases, ' '); - for (const std::string& alias_name: aliases_split) - m_aliases[name].push_back(alias_name); - - if (node_name == "command") - { - m_config_descriptions[name] = CommandDescription(usage, permissions, description); - } - else if (node_name == "text-command") + std::function command)> dfs = + [&](const XMLNode* current, const std::shared_ptr& command) { + for (unsigned int i = 0; i < current->getNumNodes(); i++) { - node->get("text", &text); - m_commands.emplace_back(name, &CommandManager::process_text, UP_EVERYONE, MS_DEFAULT); - addTextResponse(name, text); - m_config_descriptions[name] = CommandDescription(usage, permissions, description); - } - else if (node_name == "file-command") - { - node->get("file", &file); - node->get("interval", &interval); - m_commands.emplace_back(name, &CommandManager::process_file, UP_EVERYONE, MS_DEFAULT); - addFileResource(name, file, interval); - m_config_descriptions[name] = CommandDescription(usage, permissions, description); - } - else if (node_name == "auth-command") - { - node->get("secret", &secret); - node->get("server", &server); - node->get("link-format", &link_format); - m_commands.emplace_back(name, &CommandManager::process_auth, UP_EVERYONE, MS_DEFAULT); - addAuthResource(name, secret, server, link_format); - m_config_descriptions[name] = CommandDescription(usage, permissions, description); + const XMLNode *node = current->getNode(i); + std::string node_name = node->getName(); + // here the commands go + std::string name = ""; + std::string text = ""; // for text-command + std::string file = ""; // for file-command + uint64_t interval = 0; // for file-command + std::string usage = ""; + std::string permissions_s = "UP_EVERYONE"; + std::string mode_scope_s = "MS_DEFAULT"; + std::string state_scope_s = "SS_ALWAYS"; + bool omit_name = false; + int permissions; + int mode_scope; + int state_scope; + std::string permissions_str = ""; + std::string description = ""; + std::string aliases = ""; + std::string secret = ""; // for auth-command + std::string link_format = ""; // for auth-command + std::string server = ""; // for auth-command + // If enabled is not empty, command is added iff the server name is in enabled + // Otherwise it is added iff the server name is not in disabled + std::string enabled = ""; + std::string disabled = ""; + node->get("enabled", &enabled); + node->get("disabled", &disabled); + std::vector enabled_split = StringUtils::split(enabled, ' '); + std::vector disabled_split = StringUtils::split(disabled, ' '); + bool ok; + if (!enabled.empty()) + { + ok = false; + for (const std::string& s: enabled_split) + if (s == ServerConfig::m_server_uid) + ok = true; + } + else + { + ok = true; + for (const std::string& s: disabled_split) + if (s == ServerConfig::m_server_uid) + ok = false; + } + if (!ok) + continue; + + node->get("name", &name); + node->get("usage", &usage); + node->get("permissions", &permissions_s); + permissions = CommandManager::permission_reader.parse(permissions_s); + node->get("mode-scope", &mode_scope_s); + mode_scope = CommandManager::mode_scope_reader.parse(mode_scope_s); + node->get("state-scope", &state_scope_s); + state_scope = CommandManager::state_scope_reader.parse(state_scope_s); + node->get("permissions-verbose", &permissions_str); + node->get("description", &description); + node->get("omit-name", &omit_name); + node->get("aliases", &aliases); + std::vector aliases_split = StringUtils::split(aliases, ' '); + + std::shared_ptr c; + if (node_name == "command") + { + c = addChildCommand(command, name, &CommandManager::special, permissions, mode_scope, state_scope); + } + else if (node_name == "text-command") + { + c = addChildCommand(command, name, &CommandManager::process_text, permissions, mode_scope, state_scope); + node->get("text", &text); + addTextResponse(c->getFullName(), text); + } + else if (node_name == "file-command") + { + c = addChildCommand(command, name, &CommandManager::process_file, permissions, mode_scope, state_scope); + node->get("file", &file); + node->get("interval", &interval); + addFileResource(c->getFullName(), file, interval); + } + else if (node_name == "auth-command") + { + c = addChildCommand(command, name, &CommandManager::process_auth, permissions, mode_scope, state_scope); + node->get("secret", &secret); + node->get("server", &server); + node->get("link-format", &link_format); + addAuthResource(name, secret, server, link_format); + } + c->m_description = CommandDescription(usage, permissions_str, description); + m_all_commands.emplace_back(c); + m_full_name_to_command[c->getFullName()] = std::weak_ptr(c); + c->m_omit_name = omit_name; + command->m_stf_subcommand_names.add(name); + for (const std::string& alias_name: aliases_split) + { + command->m_stf_subcommand_names.add(alias_name, name); + command->m_name_to_subcommand[alias_name] = command->m_name_to_subcommand[name]; + } + dfs(node, c); } - } + }; + dfs(root, m_root_command); delete root; } // initCommandsInfo // ======================================================================== void CommandManager::initCommands() { - initCommandsInfo(); using CM = CommandManager; - auto kick_permissions = ((ServerConfig::m_kicks_allowed ? UP_CROWNED : UP_HAMMER) | PE_VOTED_NORMAL); - auto& v = m_commands; - - v.emplace_back("commands", &CM::process_commands, UP_EVERYONE); - v.emplace_back("replay", &CM::process_replay, UP_SINGLE, MS_DEFAULT, SS_LOBBY); - v.emplace_back("start", &CM::process_start, UP_NORMAL | PE_VOTED_NORMAL, MS_DEFAULT, SS_LOBBY); - if (ServerConfig::m_server_configurable) - v.emplace_back("config", &CM::process_config, UP_CROWNED | PE_VOTED_NORMAL, MS_DEFAULT, SS_LOBBY); - v.emplace_back("spectate", &CM::process_spectate, UP_EVERYONE); - v.emplace_back("addons", &CM::process_addons, UP_EVERYONE); - v.emplace_back("moreaddons", &CM::process_addons, UP_EVERYONE); - v.emplace_back("getaddons", &CM::process_addons, UP_EVERYONE); - v.emplace_back("checkaddon", &CM::process_checkaddon, UP_EVERYONE); - v.emplace_back("id", &CM::process_id, UP_EVERYONE); - v.emplace_back("listserveraddon", &CM::process_lsa, UP_EVERYONE); - v.emplace_back("playerhasaddon", &CM::process_pha, UP_EVERYONE); - v.emplace_back("kick", &CM::process_kick, kick_permissions); - v.emplace_back("kickban", &CM::process_kick, UP_HAMMER | PE_VOTED_NORMAL); - v.emplace_back("unban", &CM::process_unban, UP_HAMMER); - v.emplace_back("ban", &CM::process_ban, UP_HAMMER); - v.emplace_back("playeraddonscore", &CM::process_pas, UP_EVERYONE); - v.emplace_back("serverhasaddon", &CM::process_sha, UP_EVERYONE); - v.emplace_back("mute", &CM::process_mute, UP_EVERYONE); - v.emplace_back("unmute", &CM::process_unmute, UP_EVERYONE); - v.emplace_back("listmute", &CM::process_listmute, UP_EVERYONE); - v.emplace_back("description", &CM::process_text, UP_EVERYONE); - v.emplace_back("moreinfo", &CM::process_text, UP_EVERYONE); - v.emplace_back("gnu", &CM::process_gnu, UP_HAMMER | PE_VOTED_NORMAL, MS_DEFAULT, SS_LOBBY); - v.emplace_back("nognu", &CM::process_gnu, UP_HAMMER | PE_VOTED_NORMAL, MS_DEFAULT, SS_LOBBY); - v.emplace_back("tell", &CM::process_tell, UP_EVERYONE); - v.emplace_back("standings", &CM::process_standings, UP_EVERYONE); - v.emplace_back("teamchat", &CM::process_teamchat, UP_EVERYONE); - v.emplace_back("to", &CM::process_to, UP_EVERYONE); - v.emplace_back("public", &CM::process_public, UP_EVERYONE); - v.emplace_back("record", &CM::process_record, UP_EVERYONE); - v.emplace_back("power", &CM::process_power, UP_EVERYONE); - v.emplace_back("length", &CM::process_length, UP_SINGLE, MS_DEFAULT, SS_LOBBY); - v.emplace_back("direction", &CM::process_direction, UP_SINGLE, MS_DEFAULT, SS_LOBBY); - v.emplace_back("queue", &CM::process_queue, UP_SINGLE, MS_DEFAULT, SS_LOBBY); - v.emplace_back("allowstart", &CM::process_allowstart, UP_HAMMER); - v.emplace_back("shuffle", &CM::process_shuffle, UP_HAMMER); - v.emplace_back("timeout", &CM::process_timeout, UP_HAMMER); - v.emplace_back("team", &CM::process_team, UP_HAMMER); - v.emplace_back("swapteams", &CM::process_swapteams, UP_HAMMER); - v.emplace_back("resetteams", &CM::process_resetteams, UP_HAMMER); - v.emplace_back("randomteams", &CM::process_randomteams, UP_HAMMER); - v.emplace_back("resetgp", &CM::process_resetgp, UP_HAMMER, MS_DEFAULT, SS_LOBBY); - v.emplace_back("cat+", &CM::process_cat, UP_HAMMER); - v.emplace_back("cat-", &CM::process_cat, UP_HAMMER); - v.emplace_back("catshow", &CM::process_cat, UP_HAMMER); - v.emplace_back("troll", &CM::process_troll, UP_HAMMER, MS_DEFAULT, SS_LOBBY); - v.emplace_back("hitmsg", &CM::process_hitmsg, UP_HAMMER, MS_DEFAULT, SS_LOBBY); - v.emplace_back("teamhit", &CM::process_teamhit, UP_HAMMER, MS_DEFAULT, SS_LOBBY); - v.emplace_back("scoring", &CM::process_scoring, UP_HAMMER, MS_DEFAULT, SS_LOBBY); - v.emplace_back("version", &CM::process_text, UP_EVERYONE); - v.emplace_back("clear", &CM::process_text, UP_EVERYONE); - v.emplace_back("register", &CM::process_register, UP_EVERYONE); + auto& mp = m_full_name_to_command; + m_root_command = std::make_shared("", &CM::special); + + initCommandsInfo(); + + auto applyFunctionIfPossible = [&](std::string&& name, void (CommandManager::*f)(Context& context)) { + if (mp.count(name) == 0) + return; + std::shared_ptr command = mp[name].lock(); + if (!command) { + return; + } + command->changeFunction(f); + }; + // special permissions according to ServerConfig options + std::shared_ptr kick_command = mp["kick"].lock(); + if (kick_command) { + if (ServerConfig::m_kicks_allowed) + kick_command->m_permissions |= PE_CROWNED; + else + kick_command->m_permissions &= ~PE_CROWNED; + } + + applyFunctionIfPossible("commands", &CM::process_commands); + applyFunctionIfPossible("replay", &CM::process_replay); + applyFunctionIfPossible("start", &CM::process_start); + applyFunctionIfPossible("config", &CM::process_config); + applyFunctionIfPossible("config =", &CM::process_config_assign); + applyFunctionIfPossible("spectate", &CM::process_spectate); + applyFunctionIfPossible("addons", &CM::process_addons); + applyFunctionIfPossible("moreaddons", &CM::process_addons); + applyFunctionIfPossible("getaddons", &CM::process_addons); + applyFunctionIfPossible("checkaddon", &CM::process_checkaddon); + applyFunctionIfPossible("id", &CM::process_id); + applyFunctionIfPossible("listserveraddon", &CM::process_lsa); + applyFunctionIfPossible("playerhasaddon", &CM::process_pha); + applyFunctionIfPossible("kick", &CM::process_kick); // todo Actual permissions are (kick_permissions) + applyFunctionIfPossible("kickban", &CM::process_kick); + applyFunctionIfPossible("unban", &CM::process_unban); + applyFunctionIfPossible("ban", &CM::process_ban); + applyFunctionIfPossible("playeraddonscore", &CM::process_pas); + applyFunctionIfPossible("serverhasaddon", &CM::process_sha); + applyFunctionIfPossible("mute", &CM::process_mute); + applyFunctionIfPossible("unmute", &CM::process_unmute); + applyFunctionIfPossible("listmute", &CM::process_listmute); + applyFunctionIfPossible("description", &CM::process_text); + applyFunctionIfPossible("moreinfo", &CM::process_text); + applyFunctionIfPossible("gnu", &CM::process_gnu); + applyFunctionIfPossible("nognu", &CM::process_gnu); + applyFunctionIfPossible("tell", &CM::process_tell); + applyFunctionIfPossible("standings", &CM::process_standings); + applyFunctionIfPossible("teamchat", &CM::process_teamchat); + applyFunctionIfPossible("to", &CM::process_to); + applyFunctionIfPossible("public", &CM::process_public); + applyFunctionIfPossible("record", &CM::process_record); + applyFunctionIfPossible("power", &CM::process_power); + applyFunctionIfPossible("length", &CM::process_length); + applyFunctionIfPossible("length clear", &CM::process_length_clear); + applyFunctionIfPossible("length =", &CM::process_length_fixed); + applyFunctionIfPossible("length x", &CM::process_length_multi); + applyFunctionIfPossible("direction", &CM::process_direction); + applyFunctionIfPossible("direction =", &CM::process_direction_assign); + applyFunctionIfPossible("queue", &CM::process_queue); + applyFunctionIfPossible("queue push", &CM::process_queue_push); + applyFunctionIfPossible("queue push_back", &CM::process_queue_push); + applyFunctionIfPossible("queue push_front", &CM::process_queue_push); + // Temporary pf commands + applyFunctionIfPossible("queue pf", &CM::process_queue_pf); + applyFunctionIfPossible("queue pf_back", &CM::process_queue_pf); + applyFunctionIfPossible("queue pf_front", &CM::process_queue_pf); + // End of pf commands + applyFunctionIfPossible("queue pop", &CM::process_queue_pop); + applyFunctionIfPossible("queue pop_back", &CM::process_queue_pop); + applyFunctionIfPossible("queue pop_front", &CM::process_queue_pop); + applyFunctionIfPossible("queue clear", &CM::process_queue_clear); + applyFunctionIfPossible("queue shuffle", &CM::process_queue_shuffle); + applyFunctionIfPossible("allowstart", &CM::process_allowstart); + applyFunctionIfPossible("allowstart =", &CM::process_allowstart_assign); + applyFunctionIfPossible("shuffle", &CM::process_shuffle); + applyFunctionIfPossible("shuffle =", &CM::process_shuffle_assign); + applyFunctionIfPossible("timeout", &CM::process_timeout); + applyFunctionIfPossible("team", &CM::process_team); + applyFunctionIfPossible("swapteams", &CM::process_swapteams); + applyFunctionIfPossible("resetteams", &CM::process_resetteams); + applyFunctionIfPossible("randomteams", &CM::process_randomteams); + applyFunctionIfPossible("resetgp", &CM::process_resetgp); + applyFunctionIfPossible("cat+", &CM::process_cat); + applyFunctionIfPossible("cat-", &CM::process_cat); + applyFunctionIfPossible("catshow", &CM::process_cat); + applyFunctionIfPossible("troll", &CM::process_troll); + applyFunctionIfPossible("troll =", &CM::process_troll_assign); + applyFunctionIfPossible("hitmsg", &CM::process_hitmsg); + applyFunctionIfPossible("hitmsg =", &CM::process_hitmsg_assign); + applyFunctionIfPossible("teamhit", &CM::process_teamhit); + applyFunctionIfPossible("teamhit =", &CM::process_teamhit_assign); + applyFunctionIfPossible("scoring", &CM::process_scoring); + applyFunctionIfPossible("scoring =", &CM::process_scoring_assign); + applyFunctionIfPossible("version", &CM::process_text); + applyFunctionIfPossible("clear", &CM::process_text); + applyFunctionIfPossible("register", &CM::process_register); #ifdef ENABLE_WEB_SUPPORT - v.emplace_back("token", &CM::process_token, UP_EVERYONE); + applyFunctionIfPossible("token", &CM::process_token); #endif - v.emplace_back("muteall", &CM::process_muteall, UP_EVERYONE, MS_SOCCER_TOURNAMENT); - v.emplace_back("game", &CM::process_game, UP_HAMMER, MS_SOCCER_TOURNAMENT, SS_LOBBY); - v.emplace_back("role", &CM::process_role, UP_HAMMER, MS_SOCCER_TOURNAMENT); - v.emplace_back("stop", &CM::process_stop, UP_HAMMER, MS_SOCCER_TOURNAMENT, SS_INGAME); - v.emplace_back("go", &CM::process_go, UP_HAMMER, MS_SOCCER_TOURNAMENT, SS_INGAME); - v.emplace_back("play", &CM::process_go, UP_HAMMER, MS_SOCCER_TOURNAMENT, SS_INGAME); - v.emplace_back("resume", &CM::process_go, UP_HAMMER, MS_SOCCER_TOURNAMENT, SS_INGAME); - v.emplace_back("lobby", &CM::process_lobby, UP_HAMMER, MS_SOCCER_TOURNAMENT, SS_INGAME); - v.emplace_back("init", &CM::process_init, UP_HAMMER, MS_SOCCER_TOURNAMENT, SS_INGAME); - v.emplace_back("vote", &CM::special, UP_EVERYONE); - v.emplace_back("mimiz", &CM::process_mimiz, UP_EVERYONE); - v.emplace_back("test", &CM::process_test, UP_EVERYONE | PE_VOTED); - v.emplace_back("help", &CM::process_help, UP_EVERYONE); -// v.emplace_back("1", &CM::special, UP_EVERYONE, MS_DEFAULT); -// v.emplace_back("2", &CM::special, UP_EVERYONE, MS_DEFAULT); -// v.emplace_back("3", &CM::special, UP_EVERYONE, MS_DEFAULT); -// v.emplace_back("4", &CM::special, UP_EVERYONE, MS_DEFAULT); -// v.emplace_back("5", &CM::special, UP_EVERYONE, MS_DEFAULT); - if (!ServerConfig::m_only_host_riding) - v.emplace_back("slots", &CM::process_slots, UP_HAMMER | PE_VOTED_NORMAL, MS_DEFAULT, SS_LOBBY); - v.emplace_back("time", &CM::process_time, UP_EVERYONE); - v.emplace_back("result", &CM::process_result, UP_EVERYONE); - v.emplace_back("preserve", &CM::process_preserve, UP_HAMMER); - - v.emplace_back("addondownloadprogress", &CM::special, UP_EVERYONE); - v.emplace_back("stopaddondownload", &CM::special, UP_EVERYONE); - v.emplace_back("installaddon", &CM::special, UP_EVERYONE); - v.emplace_back("uninstalladdon", &CM::special, UP_EVERYONE); - v.emplace_back("music", &CM::special, UP_EVERYONE); - v.emplace_back("addonrevision", &CM::special, UP_EVERYONE); - v.emplace_back("liststkaddon", &CM::special, UP_EVERYONE); - v.emplace_back("listlocaladdon", &CM::special, UP_EVERYONE); + applyFunctionIfPossible("muteall", &CM::process_muteall); + applyFunctionIfPossible("game", &CM::process_game); + applyFunctionIfPossible("role", &CM::process_role); + applyFunctionIfPossible("stop", &CM::process_stop); + applyFunctionIfPossible("go", &CM::process_go); + applyFunctionIfPossible("play", &CM::process_go); + applyFunctionIfPossible("resume", &CM::process_go); + applyFunctionIfPossible("lobby", &CM::process_lobby); + applyFunctionIfPossible("init", &CM::process_init); + applyFunctionIfPossible("vote", &CM::special); + applyFunctionIfPossible("mimiz", &CM::process_mimiz); + applyFunctionIfPossible("test", &CM::process_test); + applyFunctionIfPossible("test test2", &CM::process_test); + applyFunctionIfPossible("test test3", &CM::process_test); + applyFunctionIfPossible("help", &CM::process_help); +// applyFunctionIfPossible("1", &CM::special); +// applyFunctionIfPossible("2", &CM::special); +// applyFunctionIfPossible("3", &CM::special); +// applyFunctionIfPossible("4", &CM::special); +// applyFunctionIfPossible("5", &CM::special); + applyFunctionIfPossible("slots", &CM::process_slots); + applyFunctionIfPossible("slots =", &CM::process_slots_assign); + applyFunctionIfPossible("time", &CM::process_time); + applyFunctionIfPossible("result", &CM::process_result); + applyFunctionIfPossible("preserve", &CM::process_preserve); + applyFunctionIfPossible("preserve =", &CM::process_preserve_assign); + + applyFunctionIfPossible("addondownloadprogress", &CM::special); + applyFunctionIfPossible("stopaddondownload", &CM::special); + applyFunctionIfPossible("installaddon", &CM::special); + applyFunctionIfPossible("uninstalladdon", &CM::special); + applyFunctionIfPossible("music", &CM::special); + applyFunctionIfPossible("addonrevision", &CM::special); + applyFunctionIfPossible("liststkaddon", &CM::special); + applyFunctionIfPossible("listlocaladdon", &CM::special); addTextResponse("description", StringUtils::wideToUtf8(m_lobby->getGameSetup()->readOrLoadFromFile ((std::string)ServerConfig::m_motd))); @@ -352,25 +463,6 @@ void CommandManager::initCommands() addTextResponse("version", version); addTextResponse("clear", std::string(30, '\n')); - for (Command& command: m_commands) { - m_stf_command_names.add(command.m_name); - command.m_description = m_config_descriptions[command.m_name]; - } - - std::sort(m_commands.begin(), m_commands.end(), [](const Command& a, const Command& b) -> bool { - return a.m_name < b.m_name; - }); - for (auto& command: m_commands) - m_name_to_command[command.m_name] = command; - for (auto& p: m_aliases) - { - for (const std::string& alias_name: p.second) - { - m_stf_command_names.add(alias_name, p.first); - m_name_to_command[alias_name] = m_name_to_command[p.first]; - } - } - // m_votables.emplace("replay", 1.0); m_votables.emplace("start", 0.81); m_votables.emplace("config", 0.6); @@ -426,6 +518,28 @@ CommandManager::CommandManager(ServerLobby* lobby): return; initCommands(); initAssets(); + + m_aux_mode_aliases = { + {"m0"}, + {"m1"}, + {"m2"}, + {"m3", "normal", "normal-race", "race"}, + {"m4", "tt", "time-trial", "trial"}, + {"m5"}, + {"m6", "soccer", "football"}, + {"m7", "ffa", "free-for-all", "free", "for", "all"}, + {"m8", "ctf", "capture-the-flag", "capture", "the", "flag"} + }; + m_aux_difficulty_aliases = { + {"d0", "novice", "easy"}, + {"d1", "intermediate", "medium"}, + {"d2", "expert", "hard"}, + {"d3", "supertux", "super", "best"} + }; + m_aux_goal_aliases = { + {"tl", "time-limit", "time", "minutes"}, + {"gl", "goal-limit", "goal", "goals"} + }; } // CommandManager // ======================================================================== @@ -443,7 +557,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) data.decodeString(&cmd); argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); - if (argv.size() == 0) + if (argv.empty()) return; CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); @@ -477,16 +591,20 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) !m_user_command_replacements[username][i].empty()) { cmd = m_user_command_replacements[username][i]; argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); - if (argv.size() == 0) + if (argv.empty()) return; CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); voting = m_user_saved_voting[username]; restored = true; break; } else { - std::string msg = "Pick one of " + - std::to_string(-1 + (int)m_user_command_replacements[username].size()) - + " options using /1, etc., or use /0, or type a different command"; + std::string msg; + if (m_user_command_replacements[username].empty()) + msg = "This command is for fixing typos. Try typing a different command"; + else + msg = "Pick one of " + + std::to_string(-1 + (int)m_user_command_replacements[username].size()) + + " options using /1, etc., or use /0, or type a different command"; m_lobby->sendStringToPeer(msg, peer); return; } @@ -496,31 +614,59 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) if (!restored) m_user_correct_arguments.erase(username); - if (hasTypo(peer, voting, argv, cmd, 0, m_stf_command_names, 3, false, false)) - return; + std::shared_ptr current_command = m_root_command; + std::shared_ptr executed_command; + for (int idx = 0; ; idx++) + { + bool one_omittable_subcommand = (current_command->m_subcommands.size() == 1 + && current_command->m_subcommands[0]->m_omit_name == true); - auto command_iterator = m_name_to_command.find(argv[0]); + std::shared_ptr command; + if (one_omittable_subcommand) + { + command = current_command->m_subcommands[0]; + } + else + { + if (hasTypo(peer, voting, argv, cmd, idx, current_command->m_stf_subcommand_names, 3, false, idx == 0)) + return; + auto command_iterator = current_command->m_name_to_subcommand.find(argv[idx]); + command = command_iterator->second.lock(); + } - const auto& command = command_iterator->second; + if (!command) + { + // todo change message + std::string msg = "There is no such command but there should be. Very strange. Please report it."; + m_lobby->sendStringToPeer(msg, peer); + return; + } + else if (!isAvailable(command)) + { + std::string msg = "You don't have permissions to " + action + " this command"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + int mask = (permissions & command->m_permissions); + if (mask == 0) + { + std::string msg = "You don't have permissions to " + action + " this command"; + m_lobby->sendStringToPeer(msg, peer); + return; + } + int mask_without_voting = (mask & ~PE_VOTED); + if (mask != PE_NONE && mask_without_voting == PE_NONE) + voting = true; - if (!isAvailable(command)) - { - std::string msg = "You don't have permissions to " + action + " this command"; - m_lobby->sendStringToPeer(msg, peer); - return; - } - int mask = (permissions & command.m_permissions); - if (mask == 0) - { - std::string msg = "You don't have permissions to " + action + " this command"; - m_lobby->sendStringToPeer(msg, peer); - return; + if (one_omittable_subcommand) + --idx; + current_command = command; + if (idx + 1 == argv.size() || command->m_subcommands.empty()) { + executed_command = command; + execute(command, context); + break; + } } - int mask_without_voting = (mask & ~PE_VOTED); - if (mask != PE_NONE && mask_without_voting == PE_NONE) - voting = true; - - execute(command, context); while (!m_triggered_votables.empty()) { @@ -554,10 +700,10 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) std::string new_cmd = p.first + " " + p.second; auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '"', '\\'); CommandManager::restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); - std::string msg = "Command \"/" + new_cmd + "\" has been successfully voted"; - m_lobby->sendStringToAllPeers(msg); + std::string msg2 = "Command \"/" + new_cmd + "\" has been successfully voted"; + m_lobby->sendStringToAllPeers(msg2); Context new_context(event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); - execute(command, new_context); + execute(executed_command, new_context); } } } @@ -587,10 +733,10 @@ int CommandManager::getCurrentStateScope() } // getCurrentStateScope // ======================================================================== -bool CommandManager::isAvailable(const Command& c) +bool CommandManager::isAvailable(std::shared_ptr c) { - return (getCurrentModeScope() & c.m_mode_scope) != 0 - && (getCurrentStateScope() & c.m_state_scope) != 0; + return (getCurrentModeScope() & c->m_mode_scope) != 0 + && (getCurrentStateScope() & c->m_state_scope) != 0; } // getCurrentModeScope // ======================================================================== @@ -602,11 +748,11 @@ void CommandManager::vote(Context& context, std::string category, std::string va return; std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); - auto& votable = m_votables[argv[0]]; + auto& votable = m_votables[context.m_command->m_prefix_name]; bool neededCheck = votable.needsCheck(); votable.castVote(username, category, value); if (votable.needsCheck() && !neededCheck) - m_triggered_votables.push(argv[0]); + m_triggered_votables.push(context.m_command->m_prefix_name); } // vote // ======================================================================== @@ -626,7 +772,13 @@ void CommandManager::update() CommandManager::restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); std::string msg = "Command \"/" + new_cmd + "\" has been successfully voted"; m_lobby->sendStringToAllPeers(msg); - auto& command = m_name_to_command[new_argv[0]]; + // Happily the name of the votable coincides with the command full name + std::shared_ptr command = m_full_name_to_command[votable_pairs.first].lock(); + if (!command) + { + Log::error("CommandManager", "For some reason command \"%s\" was not found??", votable_pairs.first.c_str()); + continue; + } // We don't know the event though it is only needed in // ServerLobby::startSelection where it is nullptr when they vote Context new_context(nullptr, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); @@ -639,20 +791,18 @@ void CommandManager::update() void CommandManager::error(Context& context) { - std::string command = context.m_argv[0]; - // Here we assume that the command argv[0] exists, - // as we intend to invoke error() from process_* functions - std::string msg = m_name_to_command[command].getUsage(); + std::string msg = context.m_command->getUsage(); if (msg.empty()) - msg = "An error occurred while invoking command \"" + context.m_argv[0] + "\"."; + msg = "An error occurred while invoking command \"" + context.m_command->getFullName() + "\"."; m_lobby->sendStringToPeer(msg, context.m_peer); } // error // ======================================================================== -void CommandManager::execute(const Command& command, Context& context) +void CommandManager::execute(std::shared_ptr command, Context& context) { m_current_argv = context.m_argv; - (this->*command.m_action)(context); + context.m_command = command; + (this->*(command->m_action))(context); m_current_argv = {}; } // execute // ======================================================================== @@ -660,32 +810,34 @@ void CommandManager::execute(const Command& command, Context& context) void CommandManager::process_help(Context& context) { auto& argv = context.m_argv; - if (argv.size() < 2) + std::shared_ptr command = m_root_command; + for (int i = 1; i < argv.size(); ++i) { + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, i, command->m_stf_subcommand_names, 3, false, false)) + return; + auto ptr = command->m_name_to_subcommand[argv[i]].lock(); + if (ptr) + command = ptr; + else + break; + if (command->m_subcommands.empty()) + break; + } + if (command == m_root_command) { error(context); return; } - - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, 1, m_stf_command_names, 3, false, false)) - return; - - std::string msg; - auto it = m_name_to_command.find(argv[1]); - if (it == m_name_to_command.end()) - msg = "Unknown command \"" + argv[1] + "\""; - else - msg = it->second.getHelp(); - + std::string msg = command->getHelp(); m_lobby->sendStringToPeer(msg, context.m_peer); -} // process_commands +} // process_help // ======================================================================== void CommandManager::process_text(Context& context) { std::string response; - auto it = m_text_response.find(context.m_argv[0]); + auto it = m_text_response.find(context.m_command->getFullName()); if (it == m_text_response.end()) - response = "Error: a text command " + context.m_argv[0] + response = "Error: a text command " + context.m_command->getFullName() + " is defined without text"; else response = it->second; @@ -696,10 +848,10 @@ void CommandManager::process_text(Context& context) void CommandManager::process_file(Context& context) { std::string response; - auto it = m_file_resources.find(context.m_argv[0]); + auto it = m_file_resources.find(context.m_command->getFullName()); if (it == m_file_resources.end()) response = "Error: file not found for a file command " - + context.m_argv[0]; + + context.m_command->getFullName(); else response = it->second.get(); m_lobby->sendStringToPeer(response, context.m_peer); @@ -709,10 +861,10 @@ void CommandManager::process_file(Context& context) void CommandManager::process_auth(Context& context) { std::string response; - auto it = m_auth_resources.find(context.m_argv[0]); + auto it = m_auth_resources.find(context.m_command->getFullName()); if (it == m_auth_resources.end()) response = "Error: auth method not found for a command " - + context.m_argv[0]; + + context.m_command->getFullName(); else { auto profile = context.m_peer->getPlayerProfiles()[0]; @@ -730,14 +882,63 @@ void CommandManager::process_auth(Context& context) void CommandManager::process_commands(Context& context) { - std::string result = "Available commands:"; - for (const Command& c: m_commands) + std::string result; + auto& argv = context.m_argv; + std::shared_ptr command = m_root_command; + bool valid_prefix = true; + for (int i = 1; i < argv.size(); ++i) { + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, i, command->m_stf_subcommand_names, 3, false, false)) + return; + auto ptr = command->m_name_to_subcommand[argv[i]].lock(); + if (!ptr) + break; + if ((context.m_user_permissions & ptr->m_permissions) != 0 + && isAvailable(ptr)) + command = ptr; + else + { + valid_prefix = false; + break; + } + if (command->m_subcommands.empty()) + break; + } + if (!valid_prefix) { - if ((context.m_user_permissions & c.m_permissions) != 0 - && isAvailable(c)) - result += " " + c.m_name; + result = "There are no available commands with such prefix"; + m_lobby->sendStringToPeer(result, context.m_peer); + return; } - + result = (command == m_root_command ? "Available commands" + : "Available subcommands for /" + command->getFullName()); + result += ":"; + bool had_any_subcommands = false; + std::map res; + for (std::shared_ptr& subcommand: command->m_subcommands) + { + if ((context.m_user_permissions & subcommand->m_permissions) != 0 + && isAvailable(subcommand)) + { + bool subcommands_available = false; + for (auto& c: subcommand->m_subcommands) + { + if ((context.m_user_permissions & c->m_permissions) != 0 + && isAvailable(c)) + subcommands_available = true; + } + res[subcommand->m_name] = subcommands_available; + if (subcommands_available) + had_any_subcommands = true; + } + } + for (const auto& p: res) + { + result += " " + p.first; + if (p.second) + result += "*"; + } + if (had_any_subcommands) + result += "\n* has subcommands"; m_lobby->sendStringToPeer(result, context.m_peer); } // process_commands // ======================================================================== @@ -785,6 +986,36 @@ void CommandManager::process_start(Context& context) void CommandManager::process_config(Context& context) { + int difficulty = m_lobby->getDifficulty(); + int mode = m_lobby->getGameMode(); + bool goal_target = (m_lobby->m_game_setup->hasExtraSeverInfo() ? m_lobby->isSoccerGoalTarget() : false); +// m_aux_goal_aliases[goal_target ? 1 : 0][0] + std::string msg = "Current config: "; + auto get_first_if_exists = [&](std::vector& v) -> std::string { + if (v.size() < 2) + return v[0]; + return v[1]; + }; + msg += " "; + msg += get_first_if_exists(m_aux_mode_aliases[mode]); + msg += " "; + msg += get_first_if_exists(m_aux_difficulty_aliases[difficulty]); + msg += " "; + msg += get_first_if_exists(m_aux_goal_aliases[goal_target ? 1 : 0]); + if (!ServerConfig::m_server_configurable) + msg += " (not configurable)"; + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_config +// ======================================================================== + +void CommandManager::process_config_assign(Context& context) +{ + if (!ServerConfig::m_server_configurable) + { + std::string msg = "Server is not configurable, this command cannot be invoked."; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } const auto& argv = context.m_argv; int difficulty = m_lobby->getDifficulty(); int mode = m_lobby->getGameMode(); @@ -793,51 +1024,30 @@ void CommandManager::process_config(Context& context) bool user_chose_mode = false; bool user_chose_target = false; // bool gp = false; - std::vector> mode_aliases = { - {"m0"}, - {"m1"}, - {"m2"}, - {"m3", "normal", "normal-race", "race"}, - {"m4", "tt", "time-trial", "trial"}, - {"m5"}, - {"m6", "soccer", "football"}, - {"m7", "ffa", "free-for-all", "free", "for", "all"}, - {"m8", "ctf", "capture-the-flag", "capture", "the", "flag"} - }; - std::vector> difficulty_aliases = { - {"d0", "novice", "easy"}, - {"d1", "intermediate", "medium"}, - {"d2", "expert", "hard"}, - {"d3", "supertux", "super", "best"} - }; - std::vector> goal_aliases = { - {"tl", "time-limit", "time", "minutes"}, - {"gl", "goal-limit", "goal", "goals"} - }; for (unsigned i = 1; i < argv.size(); i++) { - for (unsigned j = 0; j < mode_aliases.size(); ++j) { + for (unsigned j = 0; j < m_aux_mode_aliases.size(); ++j) { if (j <= 2 || j == 5) { // Switching to GP or modes 2, 5 is not supported yet continue; } - for (std::string& alias: mode_aliases[j]) { + for (std::string& alias: m_aux_mode_aliases[j]) { if (argv[i] == alias) { mode = j; user_chose_mode = true; } } } - for (unsigned j = 0; j < difficulty_aliases.size(); ++j) { - for (std::string& alias: difficulty_aliases[j]) { + for (unsigned j = 0; j < m_aux_difficulty_aliases.size(); ++j) { + for (std::string& alias: m_aux_difficulty_aliases[j]) { if (argv[i] == alias) { difficulty = j; user_chose_difficulty = true; } } } - for (unsigned j = 0; j < goal_aliases.size(); ++j) { - for (std::string& alias: goal_aliases[j]) { + for (unsigned j = 0; j < m_aux_goal_aliases.size(); ++j) { + for (std::string& alias: m_aux_goal_aliases[j]) { if (argv[i] == alias) { goal_target = (bool)j; user_chose_target = true; @@ -860,15 +1070,15 @@ void CommandManager::process_config(Context& context) // Definitely not the best format as there are extra words, // but I'll think how to resolve it if (user_chose_mode) - vote(context, "config mode", mode_aliases[mode][0]); + vote(context, "config mode", m_aux_mode_aliases[mode][0]); if (user_chose_difficulty) - vote(context, "config difficulty", difficulty_aliases[difficulty][0]); + vote(context, "config difficulty", m_aux_difficulty_aliases[difficulty][0]); if (user_chose_target) - vote(context, "config target", goal_aliases[goal_target ? 1 : 0][0]); + vote(context, "config target", m_aux_goal_aliases[goal_target ? 1 : 0][0]); return; } m_lobby->handleServerConfiguration(context.m_peer, difficulty, mode, goal_target); -} // process_config +} // process_config_assign // ======================================================================== void CommandManager::process_spectate(Context& context) @@ -1864,70 +2074,85 @@ void CommandManager::process_power(Context& context) m_lobby->updatePlayerList(); } // process_power // ======================================================================== - void CommandManager::process_length(Context& context) { - auto& argv = context.m_argv; std::string msg; - if (argv.size() < 2) - { - argv.push_back("check"); - } - if (argv[1] == "check") - { - if (m_lobby->m_default_lap_multiplier < 0 && m_lobby->m_fixed_lap < 0) - msg = "Game length is currently chosen by players"; - else if (m_lobby->m_default_lap_multiplier > 0) - msg = StringUtils::insertValues( + if (m_lobby->m_default_lap_multiplier < 0 && m_lobby->m_fixed_lap < 0) + msg = "Game length is currently chosen by players"; + else if (m_lobby->m_default_lap_multiplier > 0) + msg = StringUtils::insertValues( "Game length is %f x default", m_lobby->m_default_lap_multiplier); - else if (m_lobby->m_fixed_lap > 0) - msg = StringUtils::insertValues( + else if (m_lobby->m_fixed_lap > 0) + msg = StringUtils::insertValues( "Game length is %d", m_lobby->m_fixed_lap); - else - msg = StringUtils::insertValues( + else + msg = StringUtils::insertValues( "An error: game length is both %f x default and %d", m_lobby->m_default_lap_multiplier, m_lobby->m_fixed_lap); - m_lobby->sendStringToPeer(msg, context.m_peer); - return; - } - if (argv[1] == "clear") + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_length +// ======================================================================== +void CommandManager::process_length_multi(Context& context) +{ + auto& argv = context.m_argv; + double temp_double = -1.0; + if (argv.size() < 3 || + !StringUtils::parseString(argv[2], &temp_double)) { - m_lobby->m_default_lap_multiplier = -1.0; - m_lobby->m_fixed_lap = -1; - msg = "Game length will be chosen by players"; - m_lobby->sendStringToAllPeers(msg); + error(context); return; } - double temp_double = -1.0; - int temp_int = -1; - if (argv[1] == "x" && argv.size() >= 3 && - StringUtils::parseString(argv[2], &temp_double)) - { - m_lobby->m_default_lap_multiplier = std::max(0.0, temp_double); - m_lobby->m_fixed_lap = -1; - msg = StringUtils::insertValues( + m_lobby->m_default_lap_multiplier = std::max(0.0, temp_double); + m_lobby->m_fixed_lap = -1; + std::string msg = StringUtils::insertValues( "Game length is now %f x default", m_lobby->m_default_lap_multiplier); - m_lobby->sendStringToAllPeers(msg); - return; - } - if (argv[1] == "=" && argv.size() >= 3 && - StringUtils::parseString(argv[2], &temp_int)) + m_lobby->sendStringToAllPeers(msg); +} // process_length_multi +// ======================================================================== +void CommandManager::process_length_fixed(Context& context) +{ + auto& argv = context.m_argv; + int temp_int = -1; + if (argv.size() < 3 || + !StringUtils::parseString(argv[2], &temp_int)) { - m_lobby->m_fixed_lap = std::max(0, temp_int); - m_lobby->m_default_lap_multiplier = -1.0; - msg = StringUtils::insertValues( - "Game length is now %d", m_lobby->m_fixed_lap); - m_lobby->sendStringToAllPeers(msg); + error(context); return; } - - error(context); -} // process_length -// ======================================================= + m_lobby->m_fixed_lap = std::max(0, temp_int); + m_lobby->m_default_lap_multiplier = -1.0; + std::string msg = StringUtils::insertValues( + "Game length is now %d", m_lobby->m_fixed_lap); + m_lobby->sendStringToAllPeers(msg); +} // process_length_fixed +// ======================================================================== +void CommandManager::process_length_clear(Context& context) +{ + m_lobby->m_default_lap_multiplier = -1.0; + m_lobby->m_fixed_lap = -1; + std::string msg = "Game length will be chosen by players"; + m_lobby->sendStringToAllPeers(msg); +} // process_length_clear +// ======================================================================== void CommandManager::process_direction(Context& context) +{ + std::string msg = "Direction is "; + if (m_lobby->m_fixed_direction == -1) + { + msg += "chosen ingame"; + } else + { + msg += "set to "; + msg += (m_lobby->m_fixed_direction == 0 ? "forward" : "reverse"); + } + m_lobby->sendStringToAllPeers(msg); +} // process_direction +// ======================================================================== + +void CommandManager::process_direction_assign(Context& context) { auto& argv = context.m_argv; std::string msg; @@ -1958,121 +2183,138 @@ void CommandManager::process_direction(Context& context) msg += (temp_int == 0 ? "forward" : "reverse"); } m_lobby->sendStringToAllPeers(msg); -} // process_direction +} // process_direction_assign // ======================================================================== void CommandManager::process_queue(Context& context) { - // todo update help when everything is changed - std::string msg; + std::string msg = StringUtils::insertValues("Queue (size = %d):", + (int)m_lobby->m_tracks_queue.size()); + for (const TrackFilter& s: m_lobby->m_tracks_queue) { + msg += " " + s.toString(); + } + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_queue +// ======================================================================== + +void CommandManager::process_queue_push(Context& context) +{ auto& argv = context.m_argv; - if (argv.size() < 2) + + if (argv.size() < 3) { - argv.push_back("show"); + error(context); + return; } - if (argv[1] == "show") + bool to_front = (argv[1] == "push_front"); + if (argv[2] == "-") + argv[2] = getRandomMap(); + else if (argv[2] == "-addon") + argv[2] = getRandomAddonMap(); + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + 2, m_stf_all_maps, 3, false, false)) + return; + if (to_front) + m_lobby->m_tracks_queue.emplace_front(argv[2]); + else + m_lobby->m_tracks_queue.emplace_back(argv[2]); + std::string msg = "Pushed " + argv[2] + + " to the " + (to_front ? "front" : "back") + + " of queue, current queue size: " + + std::to_string(m_lobby->m_tracks_queue.size()); + m_lobby->sendStringToAllPeers(msg); + m_lobby->updatePlayerList(); +} // process_queue_push +// ======================================================================== + +void CommandManager::process_queue_pf(Context& context) +{ + auto& argv = context.m_argv; + + if (argv.size() < 3) { - msg = StringUtils::insertValues("Queue (size = %d):", (int)m_lobby->m_tracks_queue.size()); - for (const TrackFilter& s: m_lobby->m_tracks_queue) { - msg += " " + s.toString(); - } - m_lobby->sendStringToPeer(msg, context.m_peer); + error(context); return; } - if (argv[1] == "push" || argv[1] == "push_back" || argv[1] == "push_front") - { - if (argv.size() < 3) - { - error(context); - return; - } - bool to_front = (argv[1] == "push_front"); - if (argv[2] == "-") - argv[2] = getRandomMap(); - else if (argv[2] == "-addon") - argv[2] = getRandomAddonMap(); - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, - 2, m_stf_all_maps, 3, false, false)) - return; - if (to_front) - m_lobby->m_tracks_queue.emplace_front(argv[2]); - else - m_lobby->m_tracks_queue.emplace_back(argv[2]); - std::string msg = "Pushed " + argv[2] - + " to the " + (to_front ? "front" : "back") - + " of queue, current queue size: " - + std::to_string(m_lobby->m_tracks_queue.size()); - m_lobby->sendStringToAllPeers(msg); - m_lobby->updatePlayerList(); + bool to_front = (argv[1] == "pf_front"); + std::string filter_text = argv[2]; + if (argv.size() > 3) { + CommandManager::restoreCmdByArgv(filter_text, argv, ' ', '"', '"', '\\', 2); } - else if (argv[1] == "pf" || argv[1] == "pf_back" || argv[1] == "pf_front") - { - if (argv.size() < 3) - { - error(context); - return; - } - bool to_front = (argv[1] == "pf_front"); - std::string filter_text = argv[2]; - if (argv.size() > 3) { - CommandManager::restoreCmdByArgv(filter_text, argv, ' ', '"', '"', '\\', 2); - } - if (to_front) - m_lobby->m_tracks_queue.emplace_front(filter_text); - else - m_lobby->m_tracks_queue.emplace_back(filter_text); - std::string msg = "Pushed { " + filter_text + " }" - + " to the " + (to_front ? "front" : "back") - + " of queue, current queue size: " - + std::to_string(m_lobby->m_tracks_queue.size()); - m_lobby->sendStringToAllPeers(msg); - m_lobby->updatePlayerList(); + if (to_front) + m_lobby->m_tracks_queue.emplace_front(filter_text); + else + m_lobby->m_tracks_queue.emplace_back(filter_text); + std::string msg = "Pushed { " + filter_text + " }" + + " to the " + (to_front ? "front" : "back") + + " of queue, current queue size: " + + std::to_string(m_lobby->m_tracks_queue.size()); + m_lobby->sendStringToAllPeers(msg); + m_lobby->updatePlayerList(); +} // process_queue_pf +// ======================================================================== + +void CommandManager::process_queue_pop(Context& context) +{ + std::string msg; + auto& argv = context.m_argv; + + bool from_back = (argv[1] == "pop_back"); + if (m_lobby->m_tracks_queue.empty()) { + msg = "Queue was empty before."; } - else if (argv[1] == "pop" || argv[1] == "pop_front" || argv[1] == "pop_back") + else { - msg = ""; - bool from_back = (argv[1] == "pop_back"); - if (m_lobby->m_tracks_queue.empty()) { - msg = "Queue was empty before."; - } + auto object = (from_back ? m_lobby->m_tracks_queue.back() : m_lobby->m_tracks_queue.front()); + msg = "Popped " + object.toString() + + " from the " + (from_back ? "back" : "front") + " of the queue,"; + if (from_back) + m_lobby->m_tracks_queue.pop_back(); else - { - auto object = (from_back ? m_lobby->m_tracks_queue.back() : m_lobby->m_tracks_queue.front()); - msg = "Popped " + object.toString() - + " from the " + (from_back ? "back" : "front") + " of the queue,"; - if (from_back) - m_lobby->m_tracks_queue.pop_back(); - else - m_lobby->m_tracks_queue.pop_front(); - msg += " current queue size: " - + std::to_string(m_lobby->m_tracks_queue.size()); - } - m_lobby->sendStringToAllPeers(msg); - m_lobby->updatePlayerList(); - } - else if (argv[1] == "clear") - { - msg = StringUtils::insertValues( - "Queue is now empty (previous size: %d)", - (int)m_lobby->m_tracks_queue.size()); - m_lobby->m_tracks_queue.clear(); - m_lobby->sendStringToAllPeers(msg); - m_lobby->updatePlayerList(); - } - else if (argv[1] == "shuffle") - { - std::random_device rd; - std::mt19937 g(rd()); - auto& queue = m_lobby->m_tracks_queue; - std::shuffle(queue.begin(), queue.end(), g); - msg = "Queue is now shuffled"; - m_lobby->sendStringToAllPeers(msg); - m_lobby->updatePlayerList(); + m_lobby->m_tracks_queue.pop_front(); + msg += " current queue size: " + + std::to_string(m_lobby->m_tracks_queue.size()); } -} // process_queue + m_lobby->sendStringToAllPeers(msg); + m_lobby->updatePlayerList(); +} // process_queue_pop +// ======================================================================== + +void CommandManager::process_queue_clear(Context& context) +{ + std::string msg = StringUtils::insertValues( + "Queue is now empty (previous size: %d)", + (int)m_lobby->m_tracks_queue.size()); + m_lobby->m_tracks_queue.clear(); + m_lobby->sendStringToAllPeers(msg); + m_lobby->updatePlayerList(); +} // process_queue_clear +// ======================================================================== + +void CommandManager::process_queue_shuffle(Context& context) +{ + std::random_device rd; + std::mt19937 g(rd()); + auto& queue = m_lobby->m_tracks_queue; + std::shuffle(queue.begin(), queue.end(), g); + std::string msg = "Queue is now shuffled"; + m_lobby->sendStringToAllPeers(msg); + m_lobby->updatePlayerList(); +} // process_queue_shuffle // ======================================================================== void CommandManager::process_allowstart(Context& context) +{ + std::string msg; + if (m_lobby->m_allowed_to_start) + msg = "Starting the game is allowed"; + else + msg = "Starting the game is forbidden"; + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_allowstart +// ======================================================================== + +void CommandManager::process_allowstart_assign(Context& context) { std::string msg; auto& argv = context.m_argv; @@ -2091,11 +2333,22 @@ void CommandManager::process_allowstart(Context& context) m_lobby->m_allowed_to_start = true; msg = "Now starting a game is allowed"; } - m_lobby->sendStringToPeer(msg, context.m_peer); -} // process_allowstart + m_lobby->sendStringToAllPeers(msg); +} // process_allowstart_assign // ======================================================================== void CommandManager::process_shuffle(Context& context) +{ + std::string msg; + if (m_lobby->m_shuffle_gp) + msg = "The GP grid is sorted by score"; + else + msg = "The GP grid is shuffled"; + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_shuffle +// ======================================================================== + +void CommandManager::process_shuffle_assign(Context& context) { std::string msg; auto& argv = context.m_argv; @@ -2112,8 +2365,8 @@ void CommandManager::process_shuffle(Context& context) m_lobby->m_shuffle_gp = true; msg = "Now the GP grid is shuffled"; } - m_lobby->sendStringToPeer(msg, context.m_peer); -} // process_shuffle + m_lobby->sendStringToAllPeers(msg); +} // process_shuffle_assign // ======================================================================== void CommandManager::process_timeout(Context& context) @@ -2364,6 +2617,17 @@ void CommandManager::process_cat(Context& context) // ======================================================================== void CommandManager::process_troll(Context& context) +{ + std::string msg; + if (m_lobby->m_troll_active) + msg = "Trolls will be kicked"; + else + msg = "Trolls can stay"; + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_troll +// ======================================================================== + +void CommandManager::process_troll_assign(Context& context) { std::string msg; auto& argv = context.m_argv; @@ -2380,11 +2644,22 @@ void CommandManager::process_troll(Context& context) m_lobby->m_troll_active = true; msg = "Trolls will be kicked"; } - m_lobby->sendStringToPeer(msg, context.m_peer); -} // process_troll + m_lobby->sendStringToAllPeers(msg); +} // process_troll_assign // ======================================================================== void CommandManager::process_hitmsg(Context& context) +{ + std::string msg; + if (m_lobby->m_show_teammate_hits) + msg = "Teammate hits are sent to all players"; + else + msg = "Teammate hits are not sent"; + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_hitmsg +// ======================================================================== + +void CommandManager::process_hitmsg_assign(Context& context) { std::string msg; auto& argv = context.m_argv; @@ -2402,10 +2677,21 @@ void CommandManager::process_hitmsg(Context& context) msg = "Teammate hits will be sent to all players"; } m_lobby->sendStringToAllPeers(msg); -} // process_hitmsg +} // process_hitmsg_assign // ======================================================================== void CommandManager::process_teamhit(Context& context) +{ + std::string msg; + if (m_lobby->m_teammate_hit_mode) + msg = "Teammate hits are punished"; + else + msg = "Teammate hits are not punished"; + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_teamhit +// ======================================================================== + +void CommandManager::process_teamhit_assign(Context& context) { std::string msg; auto& argv = context.m_argv; @@ -2425,24 +2711,26 @@ void CommandManager::process_teamhit(Context& context) msg = "Teammate hits are punished now"; } m_lobby->sendStringToAllPeers(msg); -} // process_teamhit +} // process_teamhit_assign // ======================================================================== void CommandManager::process_scoring(Context& context) +{ + std::string msg = "Current scoring is \"" + m_lobby->m_scoring_type; + for (int param: m_lobby->m_scoring_int_params) + msg += StringUtils::insertValues(" %d", param); + msg += "\""; + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_scoring +// ======================================================================== + +void CommandManager::process_scoring_assign(Context& context) { std::string msg; auto& argv = context.m_argv; std::string cmd2; CommandManager::restoreCmdByArgv(cmd2, argv, ' ', '"', '"', '\\', 1); - if (cmd2 == "") - { - msg = "Current scoring is \"" + m_lobby->m_scoring_type; - for (int param: m_lobby->m_scoring_int_params) - msg += StringUtils::insertValues(" %d", param); - msg += "\""; - m_lobby->sendStringToPeer(msg, context.m_peer); - } - else if (m_lobby->loadCustomScoring(cmd2)) + if (m_lobby->loadCustomScoring(cmd2)) { msg = "Scoring set to \"" + cmd2 + "\""; m_lobby->sendStringToAllPeers(msg); @@ -2452,7 +2740,7 @@ void CommandManager::process_scoring(Context& context) msg = "Scoring could not be parsed from \"" + cmd2 + "\""; m_lobby->sendStringToPeer(msg, context.m_peer); } -} // process_scoring +} // process_scoring_assign // ======================================================================== void CommandManager::process_register(Context& context) @@ -2909,11 +3197,22 @@ void CommandManager::process_mimiz(Context& context) void CommandManager::process_test(Context& context) { auto& argv = context.m_argv; - argv.resize(3, ""); + if (argv.size() == 1) + { + std::string msg = "/test is now deprecated. Use /test *2 [something] [something]"; + m_lobby->sendStringToPeer(msg, context.m_peer); + return; + } + argv.resize(4, ""); auto& peer = context.m_peer; + if (argv[2] == "no" && argv[3] == "u") + { + error(context); + return; + } if (context.m_voting) { - vote(context, "test " + argv[1], argv[2]); + vote(context, "test " + argv[1] + " " + argv[2], argv[3]); return; } std::string username = "Vote"; @@ -2922,24 +3221,31 @@ void CommandManager::process_test(Context& context) username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); } - std::string msg = username + ", " + argv[1] + ", " + argv[2]; + username = "{" + argv[1].substr(4) + "} " + username; + std::string msg = username + ", " + argv[2] + ", " + argv[3]; m_lobby->sendStringToAllPeers(msg); } // process_test // ======================================================================== void CommandManager::process_slots(Context& context) { - // todo allow non-hammers to invoke /slots without parameters - auto& argv = context.m_argv; - bool fail = false; - int number = 0; - if (argv.size() < 2) + int current = m_lobby->m_current_max_players_in_game.load(); + std::string msg = "Number of slots is currently " + std::to_string(current); + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_slots +// ======================================================================== + +void CommandManager::process_slots_assign(Context& context) +{ + if (ServerConfig::m_only_host_riding) { - int current = m_lobby->m_current_max_players_in_game.load(); - std::string msg = "Number of slots is currently " + std::to_string(current); + std::string msg = "Changing slots is not possible in the singleplayer mode"; m_lobby->sendStringToPeer(msg, context.m_peer); return; } + auto& argv = context.m_argv; + bool fail = false; + int number = 0; if (argv.size() < 2 || !StringUtils::parseString(argv[1], &number)) fail = true; else if (number <= 0 || number > ServerConfig::m_server_max_players) @@ -2958,7 +3264,7 @@ void CommandManager::process_slots(Context& context) m_lobby->updatePlayerList(); std::string msg = "Number of playable slots is now " + argv[1]; m_lobby->sendStringToAllPeers(msg); -} // process_slots +} // process_slots_assign // ======================================================================== void CommandManager::process_time(Context& context) @@ -2991,46 +3297,38 @@ void CommandManager::process_result(Context& context) // ======================================================================== void CommandManager::process_preserve(Context& context) +{ + std::string msg = "Preserved settings:"; + for (const std::string& str: m_lobby->m_preserve) + msg += " " + str; + m_lobby->sendStringToPeer(msg, context.m_peer); +} // process_preserve +// ======================================================================== + +void CommandManager::process_preserve_assign(Context& context) { auto& peer = context.m_peer; auto& argv = context.m_argv; std::string msg = ""; - if (1 >= argv.size()) + if (argv.size() != 3) { error(context); return; } - if (argv.size() == 2) + if (argv[2] == "0") { - if (argv[1] == "show") - { - msg = "Preserved settings:"; - for (const std::string& str: m_lobby->m_preserve) - msg += " " + str; - } - else - { - error(context); - return; - } + msg = StringUtils::insertValues( + "'%s' isn't preserved on server reset anymore", argv[1].c_str()); + m_lobby->m_preserve.erase(argv[1]); } else { - if (argv[2] == "0") - { - msg = StringUtils::insertValues( - "'%s' isn't preserved on server reset anymore", argv[1].c_str()); - m_lobby->m_preserve.erase(argv[1]); - } - else - { - msg = StringUtils::insertValues( - "'%s' is now preserved on server reset", argv[1].c_str()); - m_lobby->m_preserve.insert(argv[1]); - } + msg = StringUtils::insertValues( + "'%s' is now preserved on server reset", argv[1].c_str()); + m_lobby->m_preserve.insert(argv[1]); } - m_lobby->sendStringToPeer(msg, peer); -} // process_preserve + m_lobby->sendStringToAllPeers(msg); +} // process_preserve_assign // ======================================================================== void CommandManager::special(Context& context) @@ -3039,6 +3337,14 @@ void CommandManager::special(Context& context) // other future special functions that are never executed "as usual" // but need to be displayed in /commands output. So, in fact, this // function is only a placeholder and should be never executed. + Log::warn("CommandManager", "Command %s was invoked " + "but not implemented or unavailable for this server", + context.m_command->getFullName().c_str()); + std::string msg = "This command (%s) is not implemented, or " + "not available for this server. " + "If you believe that is a bug, please report it."; + msg = StringUtils::insertValues(msg, context.m_command->getFullName()); + m_lobby->sendStringToPeer(msg, context.m_peer); } // special // ======================================================================== @@ -3075,6 +3381,7 @@ std::string CommandManager::getRandomAddonMap() const return *it; } // getRandomAddonMap // ======================================================================== + void CommandManager::addUser(std::string& s) { m_users.insert(s); @@ -3128,7 +3435,8 @@ void CommandManager::restoreCmdByArgv(std::string& cmd, bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, std::vector& argv, std::string& cmd, int idx, - SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is) + SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is, + bool dont_replace) { if (!peer.get()) // voted return false; @@ -3145,8 +3453,10 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, m_lobby->sendStringToPeer(msg, peer); return true; } - if (closest_commands[0].second != 0 || (closest_commands[0].second == 0 - && closest_commands.size() > 1 && closest_commands[1].second == 0)) + bool no_zeros = closest_commands[0].second != 0; + bool at_least_two_zeros = closest_commands.size() > 1 && closest_commands[1].second == 0; + bool there_is_only_one = closest_commands.size() == 1; + if ((no_zeros || at_least_two_zeros) && !(there_is_only_one && !allow_as_is)) { m_user_command_replacements[username].clear(); m_user_correct_arguments[username] = idx + 1; @@ -3181,10 +3491,12 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, return true; } - argv[idx] = closest_commands[0].first; // converts case or regex - CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + if (!dont_replace) + { + argv[idx] = closest_commands[0].first; // converts case or regex + CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + } return false; - } // hasTypo // ======================================================================== @@ -3202,4 +3514,29 @@ void CommandManager::onStartSelection() m_votables["slots"].resetAllVotes(); update(); } // onStartSelection +// ======================================================================== +std::shared_ptr CommandManager::addChildCommand(std::shared_ptr target, + std::string name, void (CommandManager::*f)(Context& context), + int permissions, int mode_scope, int state_scope) +{ + std::shared_ptr child = std::make_shared(name, f, + permissions, mode_scope, state_scope); + target->m_subcommands.push_back(child); + child->m_parent = std::weak_ptr(target); + if (target->m_prefix_name.empty()) + child->m_prefix_name = name; + else + child->m_prefix_name = target->m_prefix_name + " " + name; + target->m_name_to_subcommand[name] = std::weak_ptr(child); + return child; +} // addChildCommand +// ======================================================================== + +void CommandManager::Command::changePermissions(int permissions, + int mode_scope, int state_scope) +{ + m_permissions = permissions; + m_mode_scope = mode_scope; + m_state_scope = state_scope; +} // changePermissions // ======================================================================== \ No newline at end of file diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 384214231c8..676de990b55 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -39,6 +39,8 @@ #endif #include "network/protocols/command_voting.hpp" +#include "network/protocols/command_permissions.hpp" +#include "utils/enum_extended_reader.hpp" #include "utils/set_typo_fixer.hpp" class ServerLobby; @@ -70,9 +72,13 @@ class CommandManager AuthResource(std::string secret = "", std::string server = "", std::string link_format = ""); - std::string get(std::string username); + std::string get(const std::string& username) const; }; + static EnumExtendedReader permission_reader; + static EnumExtendedReader mode_scope_reader; + static EnumExtendedReader state_scope_reader; + enum ModeScope: int { MS_DEFAULT = 1, @@ -87,6 +93,8 @@ class CommandManager SS_ALWAYS = SS_LOBBY | SS_INGAME }; + struct Command; + struct Context { Event* m_event; @@ -97,6 +105,8 @@ class CommandManager std::string m_cmd; + std::shared_ptr m_command; + int m_user_permissions; bool m_voting; @@ -121,9 +131,9 @@ class CommandManager std::string description = ""): m_usage(usage), m_permissions(permissions), m_description(description) {} - std::string getUsage() { return "Usage: " + m_usage; } + std::string getUsage() const { return "Usage: " + m_usage; } - std::string getHelp() + std::string getHelp() const { return "Usage: " + m_usage + "\nAvailable to: " + m_permissions @@ -135,6 +145,8 @@ class CommandManager { std::string m_name; + std::string m_prefix_name; + int m_permissions; void (CommandManager::*m_action)(Context& context); @@ -143,28 +155,45 @@ class CommandManager int m_state_scope; + bool m_omit_name; + CommandDescription m_description; - Command() {} + std::weak_ptr m_parent; - Command(std::string name, - void (CommandManager::*f)(Context& context), int permissions, - int mode_scope = MS_DEFAULT, int state_scope = SS_ALWAYS): - m_name(name), m_permissions(permissions), m_action(f), - m_mode_scope(mode_scope), m_state_scope(state_scope) {} + std::map> m_name_to_subcommand; - std::string getUsage() { return m_description.getUsage(); } + std::vector> m_subcommands; - std::string getHelp() { return m_description.getHelp(); } + SetTypoFixer m_stf_subcommand_names; + + Command() {} + + Command(std::string name, + void (CommandManager::*f)(Context& context), + int permissions = UP_EVERYONE, + int mode_scope = MS_DEFAULT, int state_scope = SS_ALWAYS); + + void changeFunction(void (CommandManager::*f)(Context& context)) + { m_action = f; } + void changePermissions(int permissions = UP_EVERYONE, + int mode_scope = MS_DEFAULT, + int state_scope = SS_ALWAYS); + + std::string getUsage() const { return m_description.getUsage(); } + std::string getHelp() const { return m_description.getHelp(); } + std::string getFullName() const { return m_prefix_name; } }; private: ServerLobby* m_lobby; - std::vector m_commands; + std::vector> m_all_commands; - std::map m_name_to_command; + std::map> m_full_name_to_command; + + std::shared_ptr m_root_command; std::multiset m_users; @@ -188,8 +217,6 @@ class CommandManager std::map> m_aliases; - SetTypoFixer m_stf_command_names; - SetTypoFixer m_stf_present_users; SetTypoFixer m_stf_all_maps; @@ -198,6 +225,15 @@ class CommandManager std::vector m_current_argv; + // Auxiliary things, should be moved somewhere because they just help + // in commands but have nothing to do with CM itself + + std::vector> m_aux_mode_aliases; + std::vector> m_aux_difficulty_aliases; + std::vector> m_aux_goal_aliases; + + // End of auxiliary things + void initCommandsInfo(); void initCommands(); @@ -206,13 +242,13 @@ class CommandManager int getCurrentModeScope(); int getCurrentStateScope(); - bool isAvailable(const Command& c); + bool isAvailable(std::shared_ptr c); void vote(Context& context, std::string category, std::string value); void update(); void error(Context& context); - void execute(const Command& command, Context& context); + void execute(std::shared_ptr command, Context& context); void process_help(Context& context); void process_text(Context& context); @@ -222,6 +258,7 @@ class CommandManager void process_replay(Context& context); void process_start(Context& context); void process_config(Context& context); + void process_config_assign(Context& context); void process_spectate(Context& context); void process_addons(Context& context); void process_checkaddon(Context& context); @@ -245,10 +282,21 @@ class CommandManager void process_record(Context& context); void process_power(Context& context); void process_length(Context& context); + void process_length_multi(Context& context); + void process_length_fixed(Context& context); + void process_length_clear(Context& context); void process_direction(Context& context); + void process_direction_assign(Context& context); void process_queue(Context& context); + void process_queue_push(Context& context); + void process_queue_pf(Context& context); + void process_queue_pop(Context& context); + void process_queue_clear(Context& context); + void process_queue_shuffle(Context& context); void process_allowstart(Context& context); + void process_allowstart_assign(Context& context); void process_shuffle(Context& context); + void process_shuffle_assign(Context& context); void process_timeout(Context& context); void process_team(Context& context); void process_swapteams(Context& context); @@ -257,9 +305,13 @@ class CommandManager void process_resetgp(Context& context); void process_cat(Context& context); void process_troll(Context& context); + void process_troll_assign(Context& context); void process_hitmsg(Context& context); + void process_hitmsg_assign(Context& context); void process_teamhit(Context& context); + void process_teamhit_assign(Context& context); void process_scoring(Context& context); + void process_scoring_assign(Context& context); void process_register(Context& context); #ifdef ENABLE_WEB_SUPPORT void process_token(Context& context); @@ -275,9 +327,11 @@ class CommandManager void process_mimiz(Context& context); void process_test(Context& context); void process_slots(Context& context); + void process_slots_assign(Context& context); void process_time(Context& context); void process_result(Context& context); void process_preserve(Context& context); + void process_preserve_assign(Context& context); void special(Context& context); std::string getRandomMap() const; @@ -311,13 +365,18 @@ class CommandManager bool hasTypo(std::shared_ptr peer, bool voting, std::vector& argv, std::string& cmd, int idx, - SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is); + SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is, + bool dont_replace = false); void onResetServer(); void onStartSelection(); std::vector getCurrentArgv() { return m_current_argv; } + + std::shared_ptr addChildCommand(std::shared_ptr target, std::string name, + void (CommandManager::*f)(Context& context), int permissions = UP_EVERYONE, + int mode_scope = MS_DEFAULT, int state_scope = SS_ALWAYS); }; #endif // COMMAND_MANAGER_HPP \ No newline at end of file diff --git a/src/utils/enum_extended_reader.cpp b/src/utils/enum_extended_reader.cpp new file mode 100644 index 00000000000..62815e31673 --- /dev/null +++ b/src/utils/enum_extended_reader.cpp @@ -0,0 +1,39 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2021 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/enum_extended_reader.hpp" +#include "utils/log.hpp" +#include "utils/string_utils.hpp" + +// ======================================================================== + +int EnumExtendedReader::parse(std::string& text) +{ + std::string no_whitespaces = StringUtils::removeWhitespaces(text); + std::vector items = StringUtils::split(no_whitespaces, '|'); + int value = 0; + for (const std::string& key: items) { + auto it = values.find(key); + if (it == values.end()) + Log::warn("EnumExtendedReader", "Key \"%s\" not found - ignored.", key.c_str()); + else + value |= it->second; + } + return value; +} // parse +// ======================================================================== \ No newline at end of file diff --git a/src/utils/enum_extended_reader.hpp b/src/utils/enum_extended_reader.hpp new file mode 100644 index 00000000000..8b824016536 --- /dev/null +++ b/src/utils/enum_extended_reader.hpp @@ -0,0 +1,43 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2021-2022 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef ENUM_EXTENDED_READER_HPP +#define ENUM_EXTENDED_READER_HPP + +#include +#include + +// A lazy class that for string representations of enum values, +// allows to read expressions like "ENUM_1 | ENUM_2 | ENUM_3" +// as a number, so that the config is human readable. +// Names should not have spaces or vertical bars. +// Most likely, this class will be extended later for similar purposes, +// as for now it's simple and config may depend on other variables. + +class EnumExtendedReader { +private: + std::map values; +public: + EnumExtendedReader() {} + EnumExtendedReader(std::map&& values): values(values) {} + void add(std::string key, int value) { values[key] = value; } + void remove(std::string key) { values.erase(key); } + int parse(std::string& text); +}; + +#endif \ No newline at end of file From 1b0ed7519c07fb53cfd22081be0cb42171c4e3f1 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 20 Jun 2023 06:47:10 +0300 Subject: [PATCH 269/830] Add /everypas --- data/commands.xml | 9 +++- src/network/protocols/command_manager.cpp | 62 +++++++++++++++++++---- src/network/protocols/command_manager.hpp | 1 + 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index ec4af512130..65e65f6d79e 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -106,11 +106,16 @@ here later. For now, please refer to the code for the strings being used. --> permissions="UP_HAMMER" /> + getPlayerProfiles().empty()) + { + Log::warn("CommandManager", "pas: no existing player profiles??"); + error(context); + return; + } + player_name = StringUtils::wideToUtf8( + context.m_peer->getPlayerProfiles()[0]->getName()); + } + else + { + if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + 1, m_stf_present_users, 3, false, false)) + return; + player_name = argv[1]; } - - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, - 1, m_stf_present_users, 3, false, false)) - return; - - player_name = argv[1]; std::shared_ptr player_peer = STKHost::get()->findPeerByName( StringUtils::utf8ToWide(player_name)); if (player_name.empty() || !player_peer) @@ -1691,7 +1700,7 @@ void CommandManager::process_pas(Context& context) else { std::string msg = player_name; - msg += " addons:"; + msg += "'s addon score:"; if (scores[AS_KART] != -1) msg += " karts: " + StringUtils::toString(scores[AS_KART]) + ","; if (scores[AS_TRACK] != -1) @@ -1707,6 +1716,41 @@ void CommandManager::process_pas(Context& context) } // process_pas // ======================================================================== +void CommandManager::process_everypas(Context& context) +{ + std::string response = "Addon scores:"; + for (const auto& peer: STKHost::get()->getPeers()) + { + if (peer->isAIPeer()) + continue; + if (!peer->hasPlayerProfiles()) + continue; + std::string player_name = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + auto& scores = peer->getAddonsScores(); + if (scores[AS_KART] == -1 && scores[AS_TRACK] == -1 && + scores[AS_ARENA] == -1 && scores[AS_SOCCER] == -1) + response += player_name + " has no addons\n"; + else + { + std::string msg = "\n" + player_name; + msg += "'s addon score:"; + if (scores[AS_KART] != -1) + msg += " karts: " + StringUtils::toString(scores[AS_KART]) + ","; + if (scores[AS_TRACK] != -1) + msg += " tracks: " + StringUtils::toString(scores[AS_TRACK]) + ","; + if (scores[AS_ARENA] != -1) + msg += " arenas: " + StringUtils::toString(scores[AS_ARENA]) + ","; + if (scores[AS_SOCCER] != -1) + msg += " fields: " + StringUtils::toString(scores[AS_SOCCER]) + ","; + msg.pop_back(); + response += msg; + } + } + m_lobby->sendStringToPeer(response, context.m_peer); +} // process_everypas +// ======================================================================== + void CommandManager::process_sha(Context& context) { std::string response; diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 676de990b55..e5384760524 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -269,6 +269,7 @@ class CommandManager void process_unban(Context& context); void process_ban(Context& context); void process_pas(Context& context); + void process_everypas(Context& context); void process_sha(Context& context); void process_mute(Context& context); void process_unmute(Context& context); From 189c9e57066139c98486a4a1069d6e85a5539a7b Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 22 Jun 2023 23:00:43 +0300 Subject: [PATCH 270/830] Remove cyclic dependencies with smart pointers, fix some warnings Also spam the auto peer = ; if (!peer) error(); everywhere except the votable commands because there peer can be nullptr and it's ok --- src/network/protocols/command_manager.cpp | 690 +++++++++++++++++----- src/network/protocols/command_manager.hpp | 6 +- src/network/protocols/command_voting.hpp | 1 + 3 files changed, 532 insertions(+), 165 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index c239562210d..19e13f5a4ed 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -184,7 +184,8 @@ CommandManager::Command::Command(std::string name, int mode_scope, int state_scope): m_name(name), m_action(f), m_permissions(permissions), - m_mode_scope(mode_scope), m_state_scope(state_scope) + m_mode_scope(mode_scope), m_state_scope(state_scope), + m_omit_name(false) { } // Command::Command(5) // ======================================================================== @@ -620,7 +621,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) for (int idx = 0; ; idx++) { bool one_omittable_subcommand = (current_command->m_subcommands.size() == 1 - && current_command->m_subcommands[0]->m_omit_name == true); + && current_command->m_subcommands[0]->m_omit_name); std::shared_ptr command; if (one_omittable_subcommand) @@ -743,17 +744,23 @@ bool CommandManager::isAvailable(std::shared_ptr c) void CommandManager::vote(Context& context, std::string category, std::string value) { - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + auto command = context.m_command.lock(); + if (!peer || !command) + { + error(context, true); + return; + } auto& argv = context.m_argv; if (!peer->hasPlayerProfiles()) return; std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); - auto& votable = m_votables[context.m_command->m_prefix_name]; + auto& votable = m_votables[command->m_prefix_name]; bool neededCheck = votable.needsCheck(); votable.castVote(username, category, value); if (votable.needsCheck() && !neededCheck) - m_triggered_votables.push(context.m_command->m_prefix_name); + m_triggered_votables.push(command->m_prefix_name); } // vote // ======================================================================== @@ -790,12 +797,27 @@ void CommandManager::update() } // update // ======================================================================== -void CommandManager::error(Context& context) +void CommandManager::error(Context& context, bool is_error) { - std::string msg = context.m_command->getUsage(); + std::string msg; + if (is_error) + Log::error("CommandManager", "An error occurred while invoking %s", context.m_cmd.c_str()); + auto command = context.m_command.lock(); + auto peer = context.m_peer.lock(); + if (!command) { + Log::error("CommandManager", "CM::error: cannot load command"); + return; + } + if (!peer) { + Log::error("CommandManager", "CM::error: cannot load peer"); + return; + } + msg = command->getUsage(); if (msg.empty()) - msg = "An error occurred while invoking command \"" + context.m_command->getFullName() + "\"."; - m_lobby->sendStringToPeer(msg, context.m_peer); + msg = "An error occurred while invoking command \"" + command->getFullName() + "\"."; + if (is_error) + msg += "\n/!\\ Please report this error to the server owner"; + m_lobby->sendStringToPeer(msg, peer); } // error // ======================================================================== @@ -811,9 +833,15 @@ void CommandManager::execute(std::shared_ptr command, Context& context) void CommandManager::process_help(Context& context) { auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::shared_ptr command = m_root_command; for (int i = 1; i < argv.size(); ++i) { - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, i, command->m_stf_subcommand_names, 3, false, false)) + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, i, command->m_stf_subcommand_names, 3, false, false)) return; auto ptr = command->m_name_to_subcommand[argv[i]].lock(); if (ptr) @@ -829,46 +857,67 @@ void CommandManager::process_help(Context& context) return; } std::string msg = command->getHelp(); - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_help // ======================================================================== void CommandManager::process_text(Context& context) { std::string response; - auto it = m_text_response.find(context.m_command->getFullName()); + auto peer = context.m_peer.lock(); + auto command = context.m_command.lock(); + if (!peer || !command) + { + error(context, true); + return; + } + auto it = m_text_response.find(command->getFullName()); if (it == m_text_response.end()) - response = "Error: a text command " + context.m_command->getFullName() + response = "Error: a text command " + command->getFullName() + " is defined without text"; else response = it->second; - m_lobby->sendStringToPeer(response, context.m_peer); + m_lobby->sendStringToPeer(response, peer); } // process_text // ======================================================================== void CommandManager::process_file(Context& context) { std::string response; - auto it = m_file_resources.find(context.m_command->getFullName()); + auto peer = context.m_peer.lock(); + auto command = context.m_command.lock(); + if (!peer || !command) + { + error(context, true); + return; + } + auto it = m_file_resources.find(command->getFullName()); if (it == m_file_resources.end()) response = "Error: file not found for a file command " - + context.m_command->getFullName(); + + command->getFullName(); else response = it->second.get(); - m_lobby->sendStringToPeer(response, context.m_peer); + m_lobby->sendStringToPeer(response, peer); } // process_text // ======================================================================== void CommandManager::process_auth(Context& context) { std::string response; - auto it = m_auth_resources.find(context.m_command->getFullName()); + auto peer = context.m_peer.lock(); + auto command = context.m_command.lock(); + if (!peer || !command) + { + error(context, true); + return; + } + auto it = m_auth_resources.find(command->getFullName()); if (it == m_auth_resources.end()) response = "Error: auth method not found for a command " - + context.m_command->getFullName(); + + command->getFullName(); else { - auto profile = context.m_peer->getPlayerProfiles()[0]; + auto profile = peer->getPlayerProfiles()[0]; std::string username = StringUtils::wideToUtf8(profile->getName()); int online_id = profile->getOnlineId(); if (online_id == 0) @@ -877,18 +926,24 @@ void CommandManager::process_auth(Context& context) else response = it->second.get(username); } - m_lobby->sendStringToPeer(response, context.m_peer); + m_lobby->sendStringToPeer(response, peer); } // process_text // ======================================================================== void CommandManager::process_commands(Context& context) { std::string result; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } auto& argv = context.m_argv; std::shared_ptr command = m_root_command; bool valid_prefix = true; for (int i = 1; i < argv.size(); ++i) { - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, i, command->m_stf_subcommand_names, 3, false, false)) + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, i, command->m_stf_subcommand_names, 3, false, false)) return; auto ptr = command->m_name_to_subcommand[argv[i]].lock(); if (!ptr) @@ -907,7 +962,7 @@ void CommandManager::process_commands(Context& context) if (!valid_prefix) { result = "There are no available commands with such prefix"; - m_lobby->sendStringToPeer(result, context.m_peer); + m_lobby->sendStringToPeer(result, peer); return; } result = (command == m_root_command ? "Available commands" @@ -940,13 +995,19 @@ void CommandManager::process_commands(Context& context) } if (had_any_subcommands) result += "\n* has subcommands"; - m_lobby->sendStringToPeer(result, context.m_peer); + m_lobby->sendStringToPeer(result, peer); } // process_commands // ======================================================================== void CommandManager::process_replay(Context& context) { const auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (ServerConfig::m_record_replays) { bool current_state = m_lobby->hasConsentOnReplays(); @@ -965,7 +1026,7 @@ void CommandManager::process_replay(Context& context) else { std::string msg = "This server doesn't allow recording replays"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } } // process_replay // ======================================================================== @@ -987,6 +1048,12 @@ void CommandManager::process_start(Context& context) void CommandManager::process_config(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } int difficulty = m_lobby->getDifficulty(); int mode = m_lobby->getGameMode(); bool goal_target = (m_lobby->m_game_setup->hasExtraSeverInfo() ? m_lobby->isSoccerGoalTarget() : false); @@ -1005,16 +1072,17 @@ void CommandManager::process_config(Context& context) msg += get_first_if_exists(m_aux_goal_aliases[goal_target ? 1 : 0]); if (!ServerConfig::m_server_configurable) msg += " (not configurable)"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_config // ======================================================================== void CommandManager::process_config_assign(Context& context) { + auto peer = context.m_peer.lock(); if (!ServerConfig::m_server_configurable) { std::string msg = "Server is not configurable, this command cannot be invoked."; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); return; } const auto& argv = context.m_argv; @@ -1063,7 +1131,7 @@ void CommandManager::process_config_assign(Context& context) || !m_lobby->isModeAvailable(mode)) { std::string response = "Mode or difficulty are not permitted on this server"; - m_lobby->sendStringToPeer(response, context.m_peer); + m_lobby->sendStringToPeer(response, peer); return; } if (context.m_voting) @@ -1078,7 +1146,7 @@ void CommandManager::process_config_assign(Context& context) vote(context, "config target", m_aux_goal_aliases[goal_target ? 1 : 0][0]); return; } - m_lobby->handleServerConfiguration(context.m_peer, difficulty, mode, goal_target); + m_lobby->handleServerConfiguration(peer, difficulty, mode, goal_target); } // process_config_assign // ======================================================================== @@ -1086,7 +1154,12 @@ void CommandManager::process_spectate(Context& context) { std::string response = ""; auto& argv = context.m_argv; - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (/*m_game_setup->isGrandPrix() || */!ServerConfig::m_live_players) response = "Server doesn't support spectating"; @@ -1148,6 +1221,12 @@ void CommandManager::process_spectate(Context& context) void CommandManager::process_addons(Context& context) { auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } bool more = (argv[0] == "moreaddons"); bool more_own = (argv[0] == "getaddons"); bool apply_filters = false; @@ -1172,7 +1251,7 @@ void CommandManager::process_addons(Context& context) break; } } - // removed const reference so that i can modify `from` + // removed const reference so that I can modify `from` // without changing the original container, we copy everything anyway std::set from = (argv[1] == "kart" ? m_lobby->m_addon_kts.first : @@ -1188,23 +1267,23 @@ void CommandManager::process_addons(Context& context) auto peers = STKHost::get()->getPeers(); int num_players = 0; - for (auto peer : peers) + for (auto p : peers) { - if (!peer || !peer->isValidated()) + if (!p || !p->isValidated()) continue; - if ((!more_own || peer != context.m_peer) && (peer->isWaitingForGame() - || !m_lobby->canRace(peer) || peer->isCommandSpectator())) + if ((!more_own || p != peer) && (p->isWaitingForGame() + || !m_lobby->canRace(p) || p->isCommandSpectator())) continue; - if (!peer->hasPlayerProfiles()) + if (!p->hasPlayerProfiles()) continue; ++num_players; std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - const auto& kt = peer->getClientAssets(); + p->getPlayerProfiles()[0]->getName()); + const auto& kt = p->getClientAssets(); const auto& container = (argv[1] == "kart" ? kt.first : kt.second); - for (auto& p: result) - if (container.find(p.first) == container.end()) - p.second.push_back(username); + for (auto& pr: result) + if (container.find(pr.first) == container.end()) + pr.second.push_back(username); } std::random_device rd; std::mt19937 g(rd()); @@ -1232,9 +1311,9 @@ void CommandManager::process_addons(Context& context) auto result2 = result; result.clear(); std::string asking_username = ""; - if (context.m_peer->hasPlayerProfiles()) + if (peer->hasPlayerProfiles()) asking_username = StringUtils::wideToUtf8( - context.m_peer->getPlayerProfiles()[0]->getName()); + peer->getPlayerProfiles()[0]->getName()); for (unsigned i = 0; i < result2.size(); ++i) { bool present = false; @@ -1291,19 +1370,25 @@ void CommandManager::process_addons(Context& context) response = "No one in the lobby can play. Found " + std::to_string(all_have.size()) + " assets on the server."; } - m_lobby->sendStringToPeer(response, context.m_peer); + m_lobby->sendStringToPeer(response, peer); } // process_addons // ======================================================================== void CommandManager::process_checkaddon(Context& context) { auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (argv.size() < 2) { error(context); return; } - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 1, m_stf_addon_maps, 3, false, true)) return; std::string id = argv[1]; @@ -1324,15 +1409,15 @@ void CommandManager::process_checkaddon(Context& context) auto peers = STKHost::get()->getPeers(); unsigned total_players = 0; - for (auto peer : peers) + for (auto p : peers) { - if (!peer || !peer->isValidated() || peer->isWaitingForGame() - || !m_lobby->canRace(peer) || peer->isCommandSpectator() - || !peer->hasPlayerProfiles()) + if (!p || !p->isValidated() || p->isWaitingForGame() + || !m_lobby->canRace(p) || p->isCommandSpectator() + || !p->hasPlayerProfiles()) continue; std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - const auto& kt = peer->getClientAssets(); + p->getPlayerProfiles()[0]->getName()); + const auto& kt = p->getClientAssets(); unsigned status = 0; if (kt.first.find(id) != kt.first.end()) status |= HAS_KART; @@ -1406,29 +1491,41 @@ void CommandManager::process_checkaddon(Context& context) } response.pop_back(); } - m_lobby->sendStringToPeer(response, context.m_peer); + m_lobby->sendStringToPeer(response, peer); } // process_checkaddon // ======================================================================== void CommandManager::process_id(Context& context) { auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (argv.size() < 2) { error(context); return; } - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 1, m_stf_all_maps, 3, false, true)) return; std::string id = argv[1]; std::string response = "Server knows this map, copy it below:\n" + id; - m_lobby->sendStringToPeer(response, context.m_peer); + m_lobby->sendStringToPeer(response, peer); } // process_id // ======================================================================== void CommandManager::process_lsa(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string response = ""; auto& argv = context.m_argv; bool has_options = argv.size() > 1 && @@ -1494,12 +1591,18 @@ void CommandManager::process_lsa(Context& context) msg = msg.substr(0, msg.size() - 2); response = "Server's addons: " + msg; } - m_lobby->sendStringToPeer(response, context.m_peer); + m_lobby->sendStringToPeer(response, peer); } // process_lsa // ======================================================================== void CommandManager::process_pha(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string response = ""; auto& argv = context.m_argv; if (argv.size() < 3) @@ -1508,10 +1611,10 @@ void CommandManager::process_pha(Context& context) return; } - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 1, m_stf_addon_maps, 3, false, true)) return; - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_present_users, 3, false, false)) return; @@ -1557,22 +1660,21 @@ void CommandManager::process_pha(Context& context) { response = player_name + " has no addon " + addon_id; } - m_lobby->sendStringToPeer(response, context.m_peer); + m_lobby->sendStringToPeer(response, peer); } // process_pha // ======================================================================== void CommandManager::process_kick(Context& context) { - auto& peer = context.m_peer; auto& argv = context.m_argv; - + auto peer = context.m_peer.lock(); if (argv.size() < 2) { error(context); return; } - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 1, m_stf_present_users, 3, false, false)) return; @@ -1589,7 +1691,7 @@ void CommandManager::process_kick(Context& context) { std::string msg = "This player is the owner of this server, " "and is protected from your actions now"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); return; } if (context.m_voting) @@ -1618,6 +1720,12 @@ void CommandManager::process_kick(Context& context) void CommandManager::process_unban(Context& context) { auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (argv.size() < 2) { error(context); @@ -1633,12 +1741,18 @@ void CommandManager::process_unban(Context& context) m_lobby->m_temp_banned.erase(player_name); std::string msg = StringUtils::insertValues( "%s is now unbanned", player_name.c_str()); - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_unban // ======================================================================== void CommandManager::process_ban(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string player_name; auto& argv = context.m_argv; if (argv.size() < 2) @@ -1656,7 +1770,7 @@ void CommandManager::process_ban(Context& context) m_lobby->m_temp_banned.insert(player_name); std::string msg = StringUtils::insertValues( "%s is now banned", player_name.c_str()); - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_ban // ======================================================================== @@ -1665,21 +1779,27 @@ void CommandManager::process_pas(Context& context) std::string response; std::string player_name; auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (argv.size() < 2) { - if (context.m_peer->getPlayerProfiles().empty()) + if (peer->getPlayerProfiles().empty()) { Log::warn("CommandManager", "pas: no existing player profiles??"); error(context); return; } player_name = StringUtils::wideToUtf8( - context.m_peer->getPlayerProfiles()[0]->getName()); + peer->getPlayerProfiles()[0]->getName()); } else { - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 1, m_stf_present_users, 3, false, false)) return; player_name = argv[1]; @@ -1712,22 +1832,28 @@ void CommandManager::process_pas(Context& context) msg.pop_back(); response = msg; } - m_lobby->sendStringToPeer(response, context.m_peer); + m_lobby->sendStringToPeer(response, peer); } // process_pas // ======================================================================== void CommandManager::process_everypas(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string response = "Addon scores:"; - for (const auto& peer: STKHost::get()->getPeers()) + for (const auto& p: STKHost::get()->getPeers()) { - if (peer->isAIPeer()) + if (p->isAIPeer()) continue; - if (!peer->hasPlayerProfiles()) + if (!p->hasPlayerProfiles()) continue; std::string player_name = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - auto& scores = peer->getAddonsScores(); + p->getPlayerProfiles()[0]->getName()); + auto& scores = p->getAddonsScores(); if (scores[AS_KART] == -1 && scores[AS_TRACK] == -1 && scores[AS_ARENA] == -1 && scores[AS_SOCCER] == -1) response += player_name + " has no addons\n"; @@ -1747,12 +1873,18 @@ void CommandManager::process_everypas(Context& context) response += msg; } } - m_lobby->sendStringToPeer(response, context.m_peer); + m_lobby->sendStringToPeer(response, peer); } // process_everypas // ======================================================================== void CommandManager::process_sha(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string response; auto& argv = context.m_argv; if (argv.size() != 2) @@ -1775,7 +1907,7 @@ void CommandManager::process_sha(Context& context) { response = "Server has no addon " + argv[1]; } - m_lobby->sendStringToPeer(response, context.m_peer); + m_lobby->sendStringToPeer(response, peer); } // process_sha // ======================================================================== @@ -1783,7 +1915,12 @@ void CommandManager::process_mute(Context& context) { std::shared_ptr player_peer; auto& argv = context.m_argv; - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string result_msg; core::stringw player_name; @@ -1793,7 +1930,7 @@ void CommandManager::process_mute(Context& context) return; } - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 1, m_stf_present_users, 3, false, false)) return; @@ -1808,7 +1945,7 @@ void CommandManager::process_mute(Context& context) m_lobby->m_peers_muted_players[peer].insert(player_name); result_msg = "Muted player " + argv[1]; - m_lobby->sendStringToPeer(result_msg, context.m_peer); + m_lobby->sendStringToPeer(result_msg, peer); } // process_mute // ======================================================================== @@ -1816,7 +1953,12 @@ void CommandManager::process_unmute(Context& context) { std::shared_ptr player_peer; auto& argv = context.m_argv; - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string result_msg; core::stringw player_name; @@ -1834,7 +1976,7 @@ void CommandManager::process_unmute(Context& context) { it = m_lobby->m_peers_muted_players[peer].erase(it); result_msg = "Unmuted player " + argv[1]; - m_lobby->sendStringToPeer(result_msg, context.m_peer); + m_lobby->sendStringToPeer(result_msg, peer); return; } else @@ -1849,7 +1991,12 @@ void CommandManager::process_unmute(Context& context) void CommandManager::process_listmute(Context& context) { - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string response; int num_players = 0; for (auto& name : m_lobby->m_peers_muted_players[peer]) @@ -1873,6 +2020,7 @@ void CommandManager::process_listmute(Context& context) void CommandManager::process_gnu(Context& context) { auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); if (argv[0] != "gnu") { argv[0] = "gnu"; @@ -1886,13 +2034,13 @@ void CommandManager::process_gnu(Context& context) if (turn_on && m_lobby->m_kart_elimination.isEnabled()) { std::string msg = "Gnu Elimination mode was already enabled!"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); return; } if (!turn_on && !m_lobby->m_kart_elimination.isEnabled()) { std::string msg = "Gnu Elimination mode was already off!"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); return; } if (turn_on && @@ -1900,7 +2048,7 @@ void CommandManager::process_gnu(Context& context) RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) { std::string msg = "Gnu Elimination is available only with racing modes"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); return; } std::string kart; @@ -1910,7 +2058,7 @@ void CommandManager::process_gnu(Context& context) } else { - if (context.m_peer) + if (peer) { kart = "gnu"; if (argv.size() > 1 && m_lobby->m_available_kts.first.count(argv[1]) > 0) @@ -1955,6 +2103,12 @@ void CommandManager::process_gnu(Context& context) void CommandManager::process_tell(Context& context) { auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (argv.size() == 1) { error(context); @@ -1967,12 +2121,18 @@ void CommandManager::process_tell(Context& context) ans.push_back(' '); ans += argv[i]; } - m_lobby->writeOwnReport(context.m_peer.get(), context.m_peer.get(), ans); + m_lobby->writeOwnReport(peer.get(), peer.get(), ans); } // process_tell // ======================================================================== void CommandManager::process_standings(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string msg; auto& argv = context.m_argv; bool isGP = false; @@ -2007,31 +2167,42 @@ void CommandManager::process_standings(Context& context) } else if (isGnu) msg = m_lobby->m_kart_elimination.getStandings(); - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_standings // ======================================================================== void CommandManager::process_teamchat(Context& context) { - m_lobby->m_team_speakers.insert(context.m_peer.get()); + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } + m_lobby->m_team_speakers.insert(peer.get()); std::string msg = "Your messages are now addressed to team only"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_teamchat // ======================================================================== void CommandManager::process_to(Context& context) { auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (argv.size() == 1) { error(context); return; } - auto& peer = context.m_peer; m_lobby->m_message_receivers[peer.get()].clear(); for (unsigned i = 1; i < argv.size(); ++i) { - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, i, m_stf_present_users, 3, false, true)) return; m_lobby->m_message_receivers[peer.get()].insert( @@ -2044,7 +2215,12 @@ void CommandManager::process_to(Context& context) void CommandManager::process_public(Context& context) { - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } m_lobby->m_message_receivers[peer.get()].clear(); m_lobby->m_team_speakers.erase(peer.get()); std::string s = "Your messages are now public"; @@ -2056,6 +2232,12 @@ void CommandManager::process_record(Context& context) { std::string response; auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } #ifdef ENABLE_SQLITE3 if (argv.size() < 5) { @@ -2063,9 +2245,10 @@ void CommandManager::process_record(Context& context) return; } bool error = false; - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 1, m_stf_all_maps, 3, false, true)) return; + // todo replace with available aliases? std::string track_name = argv[1]; std::string mode_name = (argv[2] == "t" || argv[2] == "tt" || argv[2] == "time-trial" || argv[2] == "timetrial" ? @@ -2089,14 +2272,19 @@ void CommandManager::process_record(Context& context) #else response = "This command is not supported."; #endif - m_lobby->sendStringToPeer(response, context.m_peer); + m_lobby->sendStringToPeer(response, peer); } // process_record // ======================================================================== void CommandManager::process_power(Context& context) { - auto& peer = context.m_peer; auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (peer->isAngryHost()) { peer->setAngryHost(false); @@ -2120,6 +2308,12 @@ void CommandManager::process_power(Context& context) // ======================================================================== void CommandManager::process_length(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string msg; if (m_lobby->m_default_lap_multiplier < 0 && m_lobby->m_fixed_lap < 0) msg = "Game length is currently chosen by players"; @@ -2134,7 +2328,7 @@ void CommandManager::process_length(Context& context) msg = StringUtils::insertValues( "An error: game length is both %f x default and %d", m_lobby->m_default_lap_multiplier, m_lobby->m_fixed_lap); - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_length // ======================================================================== void CommandManager::process_length_multi(Context& context) @@ -2232,18 +2426,30 @@ void CommandManager::process_direction_assign(Context& context) void CommandManager::process_queue(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string msg = StringUtils::insertValues("Queue (size = %d):", (int)m_lobby->m_tracks_queue.size()); for (const TrackFilter& s: m_lobby->m_tracks_queue) { msg += " " + s.toString(); } - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_queue // ======================================================================== void CommandManager::process_queue_push(Context& context) { auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (argv.size() < 3) { @@ -2255,7 +2461,7 @@ void CommandManager::process_queue_push(Context& context) argv[2] = getRandomMap(); else if (argv[2] == "-addon") argv[2] = getRandomAddonMap(); - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_all_maps, 3, false, false)) return; if (to_front) @@ -2274,6 +2480,12 @@ void CommandManager::process_queue_push(Context& context) void CommandManager::process_queue_pf(Context& context) { auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (argv.size() < 3) { @@ -2302,6 +2514,12 @@ void CommandManager::process_queue_pop(Context& context) { std::string msg; auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } bool from_back = (argv[1] == "pop_back"); if (m_lobby->m_tracks_queue.empty()) { @@ -2350,11 +2568,17 @@ void CommandManager::process_queue_shuffle(Context& context) void CommandManager::process_allowstart(Context& context) { std::string msg; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (m_lobby->m_allowed_to_start) msg = "Starting the game is allowed"; else msg = "Starting the game is forbidden"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_allowstart // ======================================================================== @@ -2383,12 +2607,18 @@ void CommandManager::process_allowstart_assign(Context& context) void CommandManager::process_shuffle(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string msg; if (m_lobby->m_shuffle_gp) msg = "The GP grid is sorted by score"; else msg = "The GP grid is shuffled"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_shuffle // ======================================================================== @@ -2415,6 +2645,12 @@ void CommandManager::process_shuffle_assign(Context& context) void CommandManager::process_timeout(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string msg; int seconds; auto& argv = context.m_argv; @@ -2427,7 +2663,7 @@ void CommandManager::process_timeout(Context& context) (int64_t)(seconds * 1000.0f)); m_lobby->updatePlayerList(); msg = "Successfully changed timeout"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_timeout // ======================================================================== @@ -2435,12 +2671,18 @@ void CommandManager::process_team(Context& context) { std::string msg; auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (argv.size() != 3) { error(context); return; } - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_present_users, 3, false, true)) return; std::string player = argv[2]; @@ -2453,6 +2695,12 @@ void CommandManager::process_team(Context& context) void CommandManager::process_swapteams(Context& context) { auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (argv.size() != 2) { error(context); @@ -2499,16 +2747,22 @@ void CommandManager::process_swapteams(Context& context) permutation_map_int[from] = to; } m_lobby->shuffleTemporaryTeams(permutation_map_int); - m_lobby->sendStringToPeer(msg, context.m_peer); // todo make public? + m_lobby->sendStringToPeer(msg, peer); // todo make public? m_lobby->updatePlayerList(); } // process_swapteams // ======================================================================== void CommandManager::process_resetteams(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string msg = "Teams are reset now"; m_lobby->clearTemporaryTeams(); - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); m_lobby->updatePlayerList(); } // process_resetteams // ======================================================================== @@ -2516,20 +2770,26 @@ void CommandManager::process_resetteams(Context& context) void CommandManager::process_randomteams(Context& context) { auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } int players_number = 0; - for (auto& peer : STKHost::get()->getPeers()) + for (auto& p : STKHost::get()->getPeers()) { - if (!m_lobby->canRace(peer)) + if (!m_lobby->canRace(p)) continue; - if (peer->alwaysSpectate()) + if (p->alwaysSpectate()) continue; - players_number += peer->getPlayerProfiles().size(); - for (auto& profile : peer->getPlayerProfiles()) + players_number += p->getPlayerProfiles().size(); + for (auto& profile : p->getPlayerProfiles()) profile->setTemporaryTeam(-1); } if (players_number == 0) { std::string msg = "No one can play!"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); return; } int teams_number = -1; @@ -2561,13 +2821,13 @@ void CommandManager::process_randomteams(Context& context) std::shuffle(profile_colors.begin(), profile_colors.end(), g); m_lobby->clearTemporaryTeams(); - for (auto& peer : STKHost::get()->getPeers()) + for (auto& p : STKHost::get()->getPeers()) { - if (!m_lobby->canRace(peer)) + if (!m_lobby->canRace(p)) continue; - if (peer->alwaysSpectate()) + if (p->alwaysSpectate()) continue; - for (auto& profile : peer->getPlayerProfiles()) { + for (auto& profile : p->getPlayerProfiles()) { std::string name = StringUtils::wideToUtf8(profile->getName()); std::string color = m_lobby->m_team_default_names[profile_colors.back()]; m_lobby->setTemporaryTeam(name, color); @@ -2576,7 +2836,7 @@ void CommandManager::process_randomteams(Context& context) } } - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); m_lobby->updatePlayerList(); } // process_randomteams // ======================================================================== @@ -2604,6 +2864,12 @@ void CommandManager::process_cat(Context& context) { std::string msg; auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (argv[0] == "cat+") { if (argv.size() != 3) @@ -2612,7 +2878,7 @@ void CommandManager::process_cat(Context& context) return; } std::string category = argv[1]; - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_present_users, 3, false, true)) return; std::string player = argv[2]; @@ -2630,7 +2896,7 @@ void CommandManager::process_cat(Context& context) } std::string category = argv[1]; std::string player = argv[2]; - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_present_users, 3, false, true)) return; player = argv[2]; @@ -2663,11 +2929,17 @@ void CommandManager::process_cat(Context& context) void CommandManager::process_troll(Context& context) { std::string msg; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (m_lobby->m_troll_active) msg = "Trolls will be kicked"; else msg = "Trolls can stay"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_troll // ======================================================================== @@ -2695,11 +2967,17 @@ void CommandManager::process_troll_assign(Context& context) void CommandManager::process_hitmsg(Context& context) { std::string msg; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (m_lobby->m_show_teammate_hits) msg = "Teammate hits are sent to all players"; else msg = "Teammate hits are not sent"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_hitmsg // ======================================================================== @@ -2727,11 +3005,17 @@ void CommandManager::process_hitmsg_assign(Context& context) void CommandManager::process_teamhit(Context& context) { std::string msg; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (m_lobby->m_teammate_hit_mode) msg = "Teammate hits are punished"; else msg = "Teammate hits are not punished"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_teamhit // ======================================================================== @@ -2760,11 +3044,17 @@ void CommandManager::process_teamhit_assign(Context& context) void CommandManager::process_scoring(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string msg = "Current scoring is \"" + m_lobby->m_scoring_type; for (int param: m_lobby->m_scoring_int_params) msg += StringUtils::insertValues(" %d", param); msg += "\""; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_scoring // ======================================================================== @@ -2772,6 +3062,12 @@ void CommandManager::process_scoring_assign(Context& context) { std::string msg; auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string cmd2; CommandManager::restoreCmdByArgv(cmd2, argv, ' ', '"', '"', '\\', 1); if (m_lobby->loadCustomScoring(cmd2)) @@ -2782,7 +3078,7 @@ void CommandManager::process_scoring_assign(Context& context) else { msg = "Scoring could not be parsed from \"" + cmd2 + "\""; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } } // process_scoring_assign // ======================================================================== @@ -2790,7 +3086,12 @@ void CommandManager::process_scoring_assign(Context& context) void CommandManager::process_register(Context& context) { auto& argv = context.m_argv; - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (!peer->hasPlayerProfiles()) return; int online_id = peer->getPlayerProfiles()[0]->getOnlineId(); @@ -2820,7 +3121,12 @@ void CommandManager::process_register(Context& context) #ifdef ENABLE_WEB_SUPPORT void CommandManager::process_token(Context& context) { - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (!peer->hasPlayerProfiles()) return; int online_id = peer->getPlayerProfiles()[0]->getOnlineId(); @@ -2860,7 +3166,12 @@ void CommandManager::process_token(Context& context) void CommandManager::process_muteall(Context& context) { auto& argv = context.m_argv; - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (!peer->hasPlayerProfiles()) return; std::string peer_username = StringUtils::wideToUtf8( @@ -2892,7 +3203,12 @@ void CommandManager::process_muteall(Context& context) void CommandManager::process_game(Context& context) { auto& argv = context.m_argv; - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (!peer->hasPlayerProfiles()) return; std::string peer_username = StringUtils::wideToUtf8( @@ -2970,7 +3286,12 @@ void CommandManager::process_game(Context& context) void CommandManager::process_role(Context& context) { auto& argv = context.m_argv; - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (!peer->hasPlayerProfiles()) return; std::string peer_username = StringUtils::wideToUtf8( @@ -2984,7 +3305,7 @@ void CommandManager::process_role(Context& context) { swap(argv[1], argv[2]); } - if (hasTypo(context.m_peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 2, m_stf_present_users, 3, false, true)) return; std::string role = argv[1]; @@ -3018,20 +3339,20 @@ void CommandManager::process_role(Context& context) changed_usernames.push_back(username); } } - for (const std::string& username: changed_usernames) + for (const std::string& u: changed_usernames) { - m_lobby->m_tournament_red_players.erase(username); - m_lobby->m_tournament_blue_players.erase(username); - m_lobby->m_tournament_referees.erase(username); + m_lobby->m_tournament_red_players.erase(u); + m_lobby->m_tournament_blue_players.erase(u); + m_lobby->m_tournament_referees.erase(u); if (permanent) { - m_lobby->m_tournament_init_red.erase(username); - m_lobby->m_tournament_init_blue.erase(username); - m_lobby->m_tournament_init_ref.erase(username); + m_lobby->m_tournament_init_red.erase(u); + m_lobby->m_tournament_init_blue.erase(u); + m_lobby->m_tournament_init_ref.erase(u); } std::string role_changed = "The referee has updated your role - you are now %s"; std::shared_ptr player_peer = STKHost::get()->findPeerByName( - StringUtils::utf8ToWide(username)); + StringUtils::utf8ToWide(u)); std::vector missing_assets; if (player_peer) missing_assets = m_lobby->getMissingAssets(player_peer); @@ -3048,15 +3369,15 @@ void CommandManager::process_role(Context& context) } if (m_lobby->tournamentColorsSwapped(m_lobby->m_tournament_game)) { - m_lobby->m_tournament_blue_players.insert(username); + m_lobby->m_tournament_blue_players.insert(u); if (permanent) - m_lobby->m_tournament_init_blue.insert(username); + m_lobby->m_tournament_init_blue.insert(u); } else { - m_lobby->m_tournament_red_players.insert(username); + m_lobby->m_tournament_red_players.insert(u); if (permanent) - m_lobby->m_tournament_init_red.insert(username); + m_lobby->m_tournament_init_red.insert(u); } if (player_peer) { @@ -3077,15 +3398,15 @@ void CommandManager::process_role(Context& context) } if (m_lobby->tournamentColorsSwapped(m_lobby->m_tournament_game)) { - m_lobby->m_tournament_red_players.insert(username); + m_lobby->m_tournament_red_players.insert(u); if (permanent) - m_lobby->m_tournament_init_red.insert(username); + m_lobby->m_tournament_init_red.insert(u); } else { - m_lobby->m_tournament_blue_players.insert(username); + m_lobby->m_tournament_blue_players.insert(u); if (permanent) - m_lobby->m_tournament_init_blue.insert(username); + m_lobby->m_tournament_init_blue.insert(u); } if (player_peer) { @@ -3104,9 +3425,9 @@ void CommandManager::process_role(Context& context) fail = true; // break; } - m_lobby->m_tournament_referees.insert(username); + m_lobby->m_tournament_referees.insert(u); if (permanent) - m_lobby->m_tournament_init_ref.insert(username); + m_lobby->m_tournament_init_ref.insert(u); if (player_peer) { role_changed = StringUtils::insertValues(role_changed, "referee"); @@ -3133,15 +3454,15 @@ void CommandManager::process_role(Context& context) if (!fail) { msg = StringUtils::insertValues( - "Successfully changed role to %s for %s", role, username); + "Successfully changed role to %s for %s", role, u); Log::info("CommandManager", "SoccerMatchLog: Role of %s changed to %s", - username.c_str(), role.c_str()); + u.c_str(), role.c_str()); } else { msg = StringUtils::insertValues( "Successfully changed role to %s for %s, but there are missing assets:", - role, username); + role, u); for (unsigned i = 0; i < missing_assets.size(); i++) { if (i) @@ -3196,7 +3517,12 @@ void CommandManager::process_lobby(Context& context) void CommandManager::process_init(Context& context) { auto& argv = context.m_argv; - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } if (!peer->hasPlayerProfiles()) return; std::string peer_username = StringUtils::wideToUtf8( @@ -3226,7 +3552,12 @@ void CommandManager::process_init(Context& context) void CommandManager::process_mimiz(Context& context) { - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } auto& argv = context.m_argv; auto& cmd = context.m_cmd; std::string msg; @@ -3241,14 +3572,14 @@ void CommandManager::process_mimiz(Context& context) void CommandManager::process_test(Context& context) { auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); if (argv.size() == 1) { std::string msg = "/test is now deprecated. Use /test *2 [something] [something]"; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); return; } argv.resize(4, ""); - auto& peer = context.m_peer; if (argv[2] == "no" && argv[3] == "u") { error(context); @@ -3273,9 +3604,15 @@ void CommandManager::process_test(Context& context) void CommandManager::process_slots(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } int current = m_lobby->m_current_max_players_in_game.load(); std::string msg = "Number of slots is currently " + std::to_string(current); - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_slots // ======================================================================== @@ -3284,7 +3621,8 @@ void CommandManager::process_slots_assign(Context& context) if (ServerConfig::m_only_host_riding) { std::string msg = "Changing slots is not possible in the singleplayer mode"; - m_lobby->sendStringToPeer(msg, context.m_peer); + auto peer = context.m_peer.lock(); // may be nullptr, here we don't care + m_lobby->sendStringToPeer(msg, peer); return; } auto& argv = context.m_argv; @@ -3313,7 +3651,12 @@ void CommandManager::process_slots_assign(Context& context) void CommandManager::process_time(Context& context) { - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string msg = "Server time: " + StkTime::getLogTime(); m_lobby->sendStringToPeer(msg, peer); } // process_time @@ -3321,7 +3664,12 @@ void CommandManager::process_time(Context& context) void CommandManager::process_result(Context& context) { - auto& peer = context.m_peer; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string msg = ""; if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) { @@ -3342,17 +3690,28 @@ void CommandManager::process_result(Context& context) void CommandManager::process_preserve(Context& context) { + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string msg = "Preserved settings:"; for (const std::string& str: m_lobby->m_preserve) msg += " " + str; - m_lobby->sendStringToPeer(msg, context.m_peer); + m_lobby->sendStringToPeer(msg, peer); } // process_preserve // ======================================================================== void CommandManager::process_preserve_assign(Context& context) { - auto& peer = context.m_peer; auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } std::string msg = ""; if (argv.size() != 3) { @@ -3377,18 +3736,25 @@ void CommandManager::process_preserve_assign(Context& context) void CommandManager::special(Context& context) { + auto peer = context.m_peer.lock(); + auto command = context.m_command.lock(); + if (!peer || !command) + { + error(context, true); + return; + } // This function is used as a function for /vote and possibly several // other future special functions that are never executed "as usual" // but need to be displayed in /commands output. So, in fact, this // function is only a placeholder and should be never executed. Log::warn("CommandManager", "Command %s was invoked " "but not implemented or unavailable for this server", - context.m_command->getFullName().c_str()); + command->getFullName().c_str()); std::string msg = "This command (%s) is not implemented, or " "not available for this server. " "If you believe that is a bug, please report it."; - msg = StringUtils::insertValues(msg, context.m_command->getFullName()); - m_lobby->sendStringToPeer(msg, context.m_peer); + msg = StringUtils::insertValues(msg, command->getFullName()); + m_lobby->sendStringToPeer(msg, peer); } // special // ======================================================================== diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index e5384760524..5cf196b2d0b 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -99,13 +99,13 @@ class CommandManager { Event* m_event; - std::shared_ptr m_peer; + std::weak_ptr m_peer; std::vector m_argv; std::string m_cmd; - std::shared_ptr m_command; + std::weak_ptr m_command; int m_user_permissions; @@ -246,7 +246,7 @@ class CommandManager void vote(Context& context, std::string category, std::string value); void update(); - void error(Context& context); + void error(Context& context, bool is_error = false); void execute(std::shared_ptr command, Context& context); diff --git a/src/network/protocols/command_voting.hpp b/src/network/protocols/command_voting.hpp index a89e27d577e..86da0843fdd 100644 --- a/src/network/protocols/command_voting.hpp +++ b/src/network/protocols/command_voting.hpp @@ -30,6 +30,7 @@ #include #include #include +#include class CommandVoting { From 751579d67b4957e478620085f251476e404b547e Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 25 Jun 2023 23:46:16 +0300 Subject: [PATCH 271/830] Fix missing commands being still allowed to execute (and crash) --- src/network/protocols/command_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 19e13f5a4ed..6e826e7b00a 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -630,7 +630,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) } else { - if (hasTypo(peer, voting, argv, cmd, idx, current_command->m_stf_subcommand_names, 3, false, idx == 0)) + if (hasTypo(peer, voting, argv, cmd, idx, current_command->m_stf_subcommand_names, 3, false, false)) return; auto command_iterator = current_command->m_name_to_subcommand.find(argv[idx]); command = command_iterator->second.lock(); From 1ff9008348cc615a13baaff7b3ca92d82e544669 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 6 Aug 2023 21:30:39 +0300 Subject: [PATCH 272/830] Fix start button clearing m_available_kts if no tracks are available upon pressing Also known as "Team GP no addons /queue pf addon start bug" --- src/network/protocols/server_lobby.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 59035868486..edcd9a5f92a 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3096,6 +3096,7 @@ void ServerLobby::startSelection(const Event *event) else m_ai_count = 0; + std::set available_tracks_fallback = m_available_kts.second; applyAllFilters(m_available_kts.second, true); /* auto iter = m_available_kts.second.begin(); @@ -3112,6 +3113,7 @@ void ServerLobby::startSelection(const Event *event) if (m_available_kts.second.empty()) { Log::error("ServerLobby", "No tracks for playing!"); + m_available_kts.second = available_tracks_fallback; return; } From a03a99c0d950821474563158a78c4f235591dca0 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 6 Aug 2023 21:44:34 +0300 Subject: [PATCH 273/830] Show full command line in case a local/not implemented command is invoked Example: /installaddon any-track-id any positive number of words --- src/network/protocols/command_manager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 6e826e7b00a..826c6473e5c 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -3738,6 +3738,7 @@ void CommandManager::special(Context& context) { auto peer = context.m_peer.lock(); auto command = context.m_command.lock(); + auto cmd = context.m_cmd; if (!peer || !command) { error(context, true); @@ -3752,8 +3753,9 @@ void CommandManager::special(Context& context) command->getFullName().c_str()); std::string msg = "This command (%s) is not implemented, or " "not available for this server. " - "If you believe that is a bug, please report it."; - msg = StringUtils::insertValues(msg, command->getFullName()); + "If you believe that is a bug, please report it. Full input:\n" + "/%s"; + msg = StringUtils::insertValues(msg, command->getFullName(), cmd); m_lobby->sendStringToPeer(msg, peer); } // special // ======================================================================== From 885fe4a536998c2f27df2f20c77bc5b8263a87c4 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 7 Aug 2023 00:12:48 +0300 Subject: [PATCH 274/830] Allow sorting output of /everypas by any column By default it sorts according to the number of maps corresponding to the current game mode (never by karts) --- data/commands.xml | 4 +- src/network/protocols/command_manager.cpp | 100 +++++++++++++++------- src/network/protocols/command_manager.hpp | 4 + 3 files changed, 75 insertions(+), 33 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index 65e65f6d79e..06240dd9055 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -112,9 +112,9 @@ here later. For now, please refer to the code for the strings being used. --> aliases="pas" /> m_game_mode.load()) - { - case 0: - case 1: - case 3: - case 4: - argv[1] = "track"; - break; - case 6: - argv[1] = "soccer"; - break; - case 7: - case 8: - argv[1] = "arena"; - break; - } + argv[1] = getAddonPreferredType(); } // removed const reference so that I can modify `from` // without changing the original container, we copy everything anyway @@ -1839,12 +1824,21 @@ void CommandManager::process_pas(Context& context) void CommandManager::process_everypas(Context& context) { auto peer = context.m_peer.lock(); + auto argv = context.m_argv; if (!peer) { error(context, true); return; } + std::string sorting_type = getAddonPreferredType(); + std::string sorting_direction = "desc"; + if (argv.size() > 1) + sorting_type = argv[1]; + if (argv.size() > 2) + sorting_direction = argv[2]; std::string response = "Addon scores:"; + using Pair = std::pair>; + std::vector result; for (const auto& p: STKHost::get()->getPeers()) { if (p->isAIPeer()) @@ -1853,22 +1847,53 @@ void CommandManager::process_everypas(Context& context) continue; std::string player_name = StringUtils::wideToUtf8( p->getPlayerProfiles()[0]->getName()); - auto& scores = p->getAddonsScores(); - if (scores[AS_KART] == -1 && scores[AS_TRACK] == -1 && - scores[AS_ARENA] == -1 && scores[AS_SOCCER] == -1) - response += player_name + " has no addons\n"; + auto &scores = p->getAddonsScores(); + std::vector overall; + for (int item = 0; item < AS_TOTAL; item++) + overall.push_back(scores[item]); + result.emplace_back(player_name, overall); + } + int sorting_idx = -1; + if (sorting_type == "kart" || sorting_type == "karts") + sorting_idx = 0; + if (sorting_type == "track" || sorting_type == "tracks") + sorting_idx = 1; + if (sorting_type == "arena" || sorting_type == "arenas") + sorting_idx = 2; + if (sorting_type == "soccer" || sorting_type == "soccers") + sorting_idx = 3; + if (sorting_idx != -1) + { + if (sorting_direction == "asc") + std::sort(result.begin(), result.end(), [sorting_idx] + (const Pair& lhs, const Pair& rhs) -> bool { + int diff = lhs.second[sorting_idx] - rhs.second[sorting_idx]; + return (diff < 0 || (diff == 0 && lhs.first < rhs.first)); + }); + else + std::sort(result.begin(), result.end(), [sorting_idx] + (const Pair& lhs, const Pair& rhs) -> bool { + int diff = lhs.second[sorting_idx] - rhs.second[sorting_idx]; + return (diff > 0 || (diff == 0 && lhs.first < rhs.first)); + }); + } + // I don't really know if it should be soccer or field, both are used + // in different situations + std::vector desc = { "karts", "tracks", "arenas", "fields" }; + for (auto& row: result) + { + response += "\n" + row.first; + bool negative = true; + for (int item = 0; item < AS_TOTAL; item++) + negative &= row.second[item] == -1; + if (negative) + response += " has no addons"; else { - std::string msg = "\n" + player_name; - msg += "'s addon score:"; - if (scores[AS_KART] != -1) - msg += " karts: " + StringUtils::toString(scores[AS_KART]) + ","; - if (scores[AS_TRACK] != -1) - msg += " tracks: " + StringUtils::toString(scores[AS_TRACK]) + ","; - if (scores[AS_ARENA] != -1) - msg += " arenas: " + StringUtils::toString(scores[AS_ARENA]) + ","; - if (scores[AS_SOCCER] != -1) - msg += " fields: " + StringUtils::toString(scores[AS_SOCCER]) + ","; + std::string msg = "'s addon score:"; + for (int i = 0; i < AS_TOTAL; i++) + if (row.second[i] != -1) + msg += " " + desc[i] + ": " + StringUtils::toString(row.second[i]) + ","; msg.pop_back(); response += msg; } @@ -3951,4 +3976,17 @@ void CommandManager::Command::changePermissions(int permissions, m_mode_scope = mode_scope; m_state_scope = state_scope; } // changePermissions -// ======================================================================== \ No newline at end of file +// ======================================================================== + +std::string CommandManager::getAddonPreferredType() const +{ + int mode = m_lobby->m_game_mode.load(); + if (0 <= mode && mode <= 4) + return "track"; + if (mode == 6) + return "soccer"; + if (7 <= mode && mode <= 8) + return "arena"; + return "track"; // default choice +} // getAddonPreferredType +// ======================================================================== diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 5cf196b2d0b..b7094056c24 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -378,6 +378,10 @@ class CommandManager std::shared_ptr addChildCommand(std::shared_ptr target, std::string name, void (CommandManager::*f)(Context& context), int permissions = UP_EVERYONE, int mode_scope = MS_DEFAULT, int state_scope = SS_ALWAYS); + + // Helper functions, unrelated to CommandManager inner structure + std::string getAddonPreferredType() const; + }; #endif // COMMAND_MANAGER_HPP \ No newline at end of file From 9516a447487a2f84bcc74f8b6bb8e1714b007dcb Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 23 Aug 2023 11:17:30 +0300 Subject: [PATCH 275/830] Fix /record command listing quit times and force it to print only times corresponding to config --- src/network/protocols/server_lobby.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index edcd9a5f92a..f8bf248868e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7772,11 +7772,20 @@ std::string ServerLobby::getRecord(std::string& track, std::string& mode, std::string records_table_name = ServerConfig::m_records_table_name; if (!records_table_name.empty()) { + std::string powerup_string = powerup_manager->getFileName(); + std::string kc_string = kart_properties_manager->getFileName(); + // TODO [2]: don't use file names as constants + if (powerup_string == "powerup.xml") + powerup_string = ""; + if (kc_string == "kart_characteristics.xml") + kc_string = ""; std::string get_query = StringUtils::insertValues("SELECT username, " "result FROM '%s' WHERE venue = ? and reverse = '%s' " - "and mode = '%s' and laps = %d order by result asc, time asc limit 1;", + "and mode = '%s' and laps = %d and is_quit = 0 " + "and config = '%s' and items = '%s' " + "order by result asc, time asc limit 1;", records_table_name.c_str(), direction.c_str(), mode.c_str(), - laps); + laps, kc_string.c_str(), powerup_string.c_str()); auto ret = vectorSQLQuery(get_query, 2, [track](sqlite3_stmt* stmt) { From f6c766c7ab2863b9384730fb01ef7409bf7c9f6a Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 8 Nov 2023 19:58:56 +0300 Subject: [PATCH 276/830] Fix shuffle in TrackFilter that wasn't uniform --- src/utils/track_filter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/track_filter.cpp b/src/utils/track_filter.cpp index a3a6a2499af..da975d8cd37 100644 --- a/src/utils/track_filter.cpp +++ b/src/utils/track_filter.cpp @@ -216,8 +216,8 @@ void TrackFilter::apply(int num_players, std::set& input, std::vector take(m_random_count, 1); take.resize(input.size(), 0); // Shuffling the vector like it's not having the form 11..1100..00 - for (unsigned i = 1; i < input.size(); i++) - std::swap(take[rg.get(i)], take[i]); + for (unsigned i = 0; i < input.size(); i++) + std::swap(take[rg.get(i + 1)], take[i]); std::set result; for (std::set::iterator it = input.begin(); it != input.end(); it++) { From 8048f988f54e503fda1f5bd4be2624bc242be438 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 16 Nov 2023 01:38:48 +0300 Subject: [PATCH 277/830] Allow tournament referees to change what maps the server considers to be played Map history per tournament game can be viewed with /history, /history (index) (map id) tells the server to remember that the arena played in game index was (map id). By default, the server takes the last played map during /game X, but sometimes that needs to be overridden. --- data/commands.xml | 16 +++++++ src/network/protocols/command_manager.cpp | 51 +++++++++++++++++++++++ src/network/protocols/command_manager.hpp | 4 +- 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/data/commands.xml b/data/commands.xml index 06240dd9055..33887fc3c47 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -664,6 +664,22 @@ here later. For now, please refer to the code for the strings being used. --> permissions="UP_HAMMER" /> + + + m_tournament_arenas.size(); i++) + msg += StringUtils::insertValues(" [%d]: ", i) + m_lobby->m_tournament_arenas[i]; + m_lobby->sendStringToPeer(msg, peer); +} // process_history +// ======================================================================== + +void CommandManager::process_history_assign(Context& context) +{ + auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } + std::string msg = ""; + if (argv.size() != 3) + { + error(context); + return; + } + int index; + if (!StringUtils::fromString(argv[1], index) || index < 0) + { + error(context); + return; + } + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, + 2, m_stf_all_maps, 3, false, false)) + return; + std::string id = argv[2]; + if (index >= m_lobby->m_tournament_arenas.size()) + m_lobby->m_tournament_arenas.resize(index + 1, ""); + m_lobby->m_tournament_arenas[index] = id; + + msg = StringUtils::insertValues("Assigned [%d] to %s in the map history", index, id.c_str()); + m_lobby->sendStringToPeer(msg, peer); +} // process_history_assign +// ======================================================================== + void CommandManager::special(Context& context) { auto peer = context.m_peer.lock(); diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index b7094056c24..df6c53496bf 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -333,6 +333,8 @@ class CommandManager void process_result(Context& context); void process_preserve(Context& context); void process_preserve_assign(Context& context); + void process_history(Context& context); + void process_history_assign(Context& context); void special(Context& context); std::string getRandomMap() const; @@ -384,4 +386,4 @@ class CommandManager }; -#endif // COMMAND_MANAGER_HPP \ No newline at end of file +#endif // COMMAND_MANAGER_HPP From cf4e5b7ee1543febcd20046ba120249d1a39509b Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 26 Nov 2023 00:11:11 +0300 Subject: [PATCH 278/830] Update results table creation query with new fields --- src/network/protocols/server_lobby.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index f8bf248868e..95e144b76d3 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -498,11 +498,18 @@ void ServerLobby::initServerStatsTable() "CREATE TABLE IF NOT EXISTS %s (\n" " time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Timestamp of the result\n" " username TEXT NOT NULL, -- User who set the result\n" - " venue TEXT NOT NULL, -- Track for a race\n" + " venue TEXT NOT NULL, -- Map used in the game\n" " reverse TEXT NOT NULL, -- Direction\n" - " mode TEXT NOT NULL, -- Racing mode\n" - " laps INTEGER NOT NULL, -- Number of laps\n" - " result REAL NOT NULL -- Elapsed time for a race, possibly with autofinish\n" + " mode TEXT NOT NULL, -- Game mode\n" + " laps INTEGER NOT NULL, -- Length (number of laps or duration)\n" + " result REAL NOT NULL, -- Elapsed time for a race, possibly with autofinish\n" + " difficulty INTEGER, -- Di\n" + " kart TEXT,\n" + " config TEXT,\n" + " visible INTEGER DEFAULT 1,\n" + " items TEXT,\n" + " kart_color REAL DEFAULT 0,\n" + " is_quit INTEGER DEFAULT 0" ");", m_results_table_name.c_str()); easySQLQuery(query); @@ -8267,4 +8274,4 @@ void ServerLobby::applyAllFilters(std::set& maps, bool use_history) m_tracks_queue.front().apply(max_player, maps, m_map_history); } } // applyAllFilters -//----------------------------------------------------------------------------- \ No newline at end of file +//----------------------------------------------------------------------------- From 6573ebe09e335a39d65731b7551aba9f0efb4d23 Mon Sep 17 00:00:00 2001 From: Sonter <108224581+S0nter@users.noreply.github.com> Date: Wed, 17 Jan 2024 20:12:55 +0300 Subject: [PATCH 279/830] Fix #4960 (#5003) Adjust linked buttons. Enum MultitouchButtonType is here: https://github.com/supertuxkart/stk-code/blob/master/src/input/multitouch_device.hpp --- src/input/multitouch_device.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/multitouch_device.cpp b/src/input/multitouch_device.cpp index 95317d369e1..779031bb3a1 100644 --- a/src/input/multitouch_device.cpp +++ b/src/input/multitouch_device.cpp @@ -266,7 +266,7 @@ void MultitouchDevice::updateDeviceState(unsigned int event_id) if (button == NULL) return false; return button->type >= BUTTON_FIRE && - button->type <= BUTTON_RESCUE; + button->type <= BUTTON_LOOK_BACKWARDS; }; const MultitouchEvent& event = m_events[event_id]; From ec8362915d87a0f79a20960a225bcdfa598c01bf Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Thu, 18 Jan 2024 01:13:23 +0800 Subject: [PATCH 280/830] Fix #4984 & #4995 (#4998) --- data/shaders/utils/decodeNormal.frag | 12 +++++++----- data/shaders/utils/encode_normal.frag | 18 +++++++++++++++--- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/data/shaders/utils/decodeNormal.frag b/data/shaders/utils/decodeNormal.frag index d3601509c3a..f505baae748 100644 --- a/data/shaders/utils/decodeNormal.frag +++ b/data/shaders/utils/decodeNormal.frag @@ -1,7 +1,9 @@ - vec3 DecodeNormal(vec2 n) { - float z = dot(n, n) * 2. - 1.; - vec2 xy = normalize(n) * sqrt(1. - z * z); - return vec3(xy,z); -} \ No newline at end of file + n = n * 2.0 - 1.0; + vec3 ret = vec3(n.x, n.y, 1.0 - abs(n.x) - abs(n.y)); + float t = max(-ret.z, 0.0); + ret.x += ret.x >= 0.0 ? -t : t; + ret.y += ret.y >= 0.0 ? -t : t; + return normalize(ret); +} diff --git a/data/shaders/utils/encode_normal.frag b/data/shaders/utils/encode_normal.frag index ea0323588e4..2ed38143bfb 100644 --- a/data/shaders/utils/encode_normal.frag +++ b/data/shaders/utils/encode_normal.frag @@ -1,5 +1,17 @@ -// from Crytek "a bit more deferred CryEngine" +// Octahedron Normal Vector + +vec2 OctWrap(vec2 v) +{ + vec2 w = 1.0 - abs( v.yx ); + if (v.x < 0.0) w.x = -w.x; + if (v.y < 0.0) w.y = -w.y; + return w; +} + vec2 EncodeNormal(vec3 n) { - return normalize(n.xy) * sqrt(n.z * 0.5 + 0.5); -} \ No newline at end of file + n /= (abs(n.x) + abs(n.y) + abs(n.z)); + n.xy = n.z >= 0.0 ? n.xy : OctWrap(n.xy); + n.xy = n.xy * 0.5 + 0.5; + return n.xy; +} From e1454a007e7db1c9b22897213cd904f4ec95ff06 Mon Sep 17 00:00:00 2001 From: Benau Date: Thu, 25 Jan 2024 10:51:10 +0800 Subject: [PATCH 281/830] Fix memory corruption when vector being resized --- src/karts/kart_model.cpp | 14 ++++++++------ src/karts/kart_model.hpp | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index d9c749a0aea..933cd13a1c4 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -213,9 +213,11 @@ void KartModel::loadInfo(const XMLNode &node) { if (const XMLNode *speed_weighted_objects_node = node.getNode("speed-weighted-objects")) { - for (unsigned int i = 0 ;i < speed_weighted_objects_node->getNumNodes() ; i++) + unsigned speed_weighted_objects_size = speed_weighted_objects_node->getNumNodes(); + m_speed_weighted_objects.resize(speed_weighted_objects_size); + for (unsigned int i = 0 ;i < speed_weighted_objects_size; i++) { - loadSpeedWeightedInfo(speed_weighted_objects_node->getNode(i)); + loadSpeedWeightedInfo(speed_weighted_objects_node->getNode(i), i); } } if (const XMLNode* headlights_node = node.getNode("headlights")) @@ -797,9 +799,9 @@ void KartModel::loadNitroEmitterInfo(const XMLNode &node, } // loadNitroEmitterInfo // ---------------------------------------------------------------------------- - /** Loads a single speed weighted node. */ -void KartModel::loadSpeedWeightedInfo(const XMLNode* speed_weighted_node) +void KartModel::loadSpeedWeightedInfo(const XMLNode* speed_weighted_node, + int index) { SpeedWeightedObject obj; if (speed_weighted_node->getName() == "object") @@ -824,7 +826,7 @@ void KartModel::loadSpeedWeightedInfo(const XMLNode* speed_weighted_node) } if (!obj.m_name.empty()) { - m_speed_weighted_objects.push_back(obj); + m_speed_weighted_objects[index] = obj; float dx = 0.0f; float dy = 0.0f; float dt = 0.0f; @@ -835,7 +837,7 @@ void KartModel::loadSpeedWeightedInfo(const XMLNode* speed_weighted_node) speed_weighted_node->get("animated-by-step", &step); if (dx != 0.0f || dy != 0.0f) { - m_speed_weighted_objects.back().m_properties.m_moving_texture = + m_speed_weighted_objects[index].m_properties.m_moving_texture = new MovingTexture(dx, dy, dt, step); } } diff --git a/src/karts/kart_model.hpp b/src/karts/kart_model.hpp index 6e9c19cbdba..cc38b40f1d0 100644 --- a/src/karts/kart_model.hpp +++ b/src/karts/kart_model.hpp @@ -298,7 +298,7 @@ class KartModel : public scene::IAnimationEndCallBack, public NoCopy void loadNitroEmitterInfo(const XMLNode &node, const std::string &emitter_name, int index); - void loadSpeedWeightedInfo(const XMLNode* speed_weighted_node); + void loadSpeedWeightedInfo(const XMLNode* speed_weighted_node, int index); void loadHeadlights(const XMLNode &node); From 4617ff122a115e9063f0e47f0ec4fd638c4ba710 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 7 Feb 2024 19:01:09 +0400 Subject: [PATCH 282/830] Put temporary teams in a separate unit utils/team_utils.* Also remove unused code and fix inconsistent indexation inside temporary teams --- src/network/network_player_profile.cpp | 2 - src/network/network_player_profile.hpp | 11 ++- src/network/protocols/command_manager.cpp | 31 +++---- src/network/protocols/command_manager.hpp | 1 + src/network/protocols/server_lobby.cpp | 92 ++----------------- src/network/protocols/server_lobby.hpp | 11 +-- src/utils/team_utils.cpp | 94 ++++++++++++++++++++ src/utils/team_utils.hpp | 103 ++++++++++++++++++++++ 8 files changed, 230 insertions(+), 115 deletions(-) create mode 100644 src/utils/team_utils.cpp create mode 100644 src/utils/team_utils.hpp diff --git a/src/network/network_player_profile.cpp b/src/network/network_player_profile.cpp index 50b113274b1..b00045d075e 100644 --- a/src/network/network_player_profile.cpp +++ b/src/network/network_player_profile.cpp @@ -20,8 +20,6 @@ #include "network/network_config.hpp" #include "network/stk_host.hpp" -float NetworkPlayerProfile::m_team_color[20] = {1.00, 0.05, 0.16, 0.33, 0.66, 0.78, 0.46, 0.94, 0.58, 0.00}; - // ---------------------------------------------------------------------------- /** Returns true if this player is local, i.e. running on this computer. This * is done by comparing the host id of this player with the host id of this diff --git a/src/network/network_player_profile.hpp b/src/network/network_player_profile.hpp index 9decfc5e313..31b83011404 100644 --- a/src/network/network_player_profile.hpp +++ b/src/network/network_player_profile.hpp @@ -23,6 +23,7 @@ #define HEADER_NETWORK_PLAYER_PROFILE #include "network/kart_data.hpp" +#include "utils/team_utils.hpp" #include "utils/types.hpp" #include "irrString.h" @@ -75,8 +76,6 @@ class NetworkPlayerProfile int m_temporary_team; - static float m_team_color[20]; - KartData m_kart_data; public: // ------------------------------------------------------------------------ @@ -97,7 +96,7 @@ class NetworkPlayerProfile m_handicap.store((HandicapLevel)0); m_local_player_id = 0; m_team.store(team); - m_temporary_team = -1; + m_temporary_team = 0; resetGrandPrixData(); } // ------------------------------------------------------------------------ @@ -117,7 +116,7 @@ class NetworkPlayerProfile m_local_player_id = local_player_id; m_team.store(team); m_country_code = country_code; - m_temporary_team = -1; + m_temporary_team = 0; resetGrandPrixData(); } // ------------------------------------------------------------------------ @@ -151,9 +150,9 @@ class NetworkPlayerProfile // ------------------------------------------------------------------------ float getDefaultKartColor() const { - if (m_temporary_team == -1) + if (m_temporary_team == 0) return m_default_kart_color; - return m_team_color[m_temporary_team]; + return TeamUtils::getTeamByIndex(m_temporary_team).getColor(); } // ------------------------------------------------------------------------ uint32_t getOnlineId() const { return m_online_id; } diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 37e34b59ef5..d416e437382 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2739,15 +2739,15 @@ void CommandManager::process_swapteams(Context& context) std::map permutation_map_int; for (char c: argv[1]) { - std::string type(1, c); // todo remove that link to first char, it is awful - if (m_lobby->m_team_name_to_index.count(type) == 0) + // on the other hand, I'd better have roygbpcms than r,o,y,g,b,words + // so let it stay like that for now + std::string type(1, c); + int index = TeamUtils::getIndexByCode(type); + if (index == 0) continue; - int index = m_lobby->m_team_name_to_index[type]; - char c1 = m_lobby->m_team_default_names[index][0]; - if (m_lobby->m_team_name_to_index.count(type)) { - permutation_map[c1] = 0; - } + char c1 = TeamUtils::getTeamByIndex(index).getPrimaryCode()[0]; + permutation_map[c1] = 0; } std::string permutation; for (auto& p: permutation_map) @@ -2769,8 +2769,8 @@ void CommandManager::process_swapteams(Context& context) } for (auto& p: permutation_map) { - int from = m_lobby->m_team_name_to_index[std::string(1, p.first)]; - int to = m_lobby->m_team_name_to_index[std::string(1, p.second)]; + int from = TeamUtils::getIndexByCode(std::string(1, p.first)); + int to = TeamUtils::getIndexByCode(std::string(1, p.second)); permutation_map_int[from] = to; } m_lobby->shuffleTemporaryTeams(permutation_map_int); @@ -2812,7 +2812,7 @@ void CommandManager::process_randomteams(Context& context) continue; players_number += p->getPlayerProfiles().size(); for (auto& profile : p->getPlayerProfiles()) - profile->setTemporaryTeam(-1); + profile->setTemporaryTeam(0); } if (players_number == 0) { std::string msg = "No one can play!"; @@ -2820,12 +2820,13 @@ void CommandManager::process_randomteams(Context& context) return; } int teams_number = -1; + int max_number_of_teams = TeamUtils::getNumberOfTeams(); if (argv.size() < 2 || !StringUtils::parseString(argv[1], &teams_number) - || teams_number < 1 || teams_number > 9) + || teams_number < 1 || teams_number > max_number_of_teams) { teams_number = (int)round(sqrt(players_number)); - if (teams_number > 9) - teams_number = 9; + if (teams_number > max_number_of_teams) + teams_number = max_number_of_teams; if (players_number > 1 && teams_number <= 1) teams_number = 2; } @@ -2834,7 +2835,7 @@ void CommandManager::process_randomteams(Context& context) "Created %d teams for %d players", teams_number, players_number); std::vector available_colors; std::vector profile_colors; - for (int i = 1; i <= 9; ++i) + for (int i = 1; i <= max_number_of_teams; ++i) available_colors.push_back(i); std::random_device rd; @@ -2856,7 +2857,7 @@ void CommandManager::process_randomteams(Context& context) continue; for (auto& profile : p->getPlayerProfiles()) { std::string name = StringUtils::wideToUtf8(profile->getName()); - std::string color = m_lobby->m_team_default_names[profile_colors.back()]; + std::string color = TeamUtils::getTeamByIndex(profile_colors.back()).getPrimaryCode(); m_lobby->setTemporaryTeam(name, color); if (profile_colors.size() > 1) // prevent crash just in case profile_colors.pop_back(); diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index df6c53496bf..a3585aede3c 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -42,6 +42,7 @@ #include "network/protocols/command_permissions.hpp" #include "utils/enum_extended_reader.hpp" #include "utils/set_typo_fixer.hpp" +#include "utils/team_utils.hpp" class ServerLobby; class Event; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 95e144b76d3..3597f2b94c8 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -216,51 +216,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() ((std::string) ServerConfig::m_help); m_command_manager = CommandManager(nullptr); - - m_team_name_to_index = { - {"red", 1}, {"r", 1}, - {"orange", 2}, {"o", 2}, - {"yellow", 3}, {"y", 3}, - {"green", 4}, {"g", 4}, - {"blue", 5}, {"b", 5}, - {"purple", 6}, {"p", 6}, - {"violet", 6}, {"v", 6}, - {"cyan", 7}, {"c", 7}, - {"magenta", 8}, {"m", 8}, - {"pink", 8}, - {"sky", 9}, {"s", 9} - }; - - m_team_default_names = {"none", "red", "orange", "yellow", "green", "blue", "purple", "cyan", "magenta", "sky"}; - - m_team_index_to_icon = { - {1, StringUtils::utf32ToUtf8({0x1f7e5})}, - {2, StringUtils::utf32ToUtf8({0x1f7e7})}, - {3, StringUtils::utf32ToUtf8({0x1f7e8})}, - {4, StringUtils::utf32ToUtf8({0x1f7e9})}, - {5, StringUtils::utf32ToUtf8({0x1f7e6})}, - {6, StringUtils::utf32ToUtf8({0x1f7ea})}, - {7, StringUtils::utf32ToUtf8({0x1f5fd})}, - {8, StringUtils::utf32ToUtf8({0x1f338})}, - {9, StringUtils::utf32ToUtf8({0x2604})} - }; - - m_team_name = {"No Team", - StringUtils::utf32ToUtf8({0x1f7e5}) + "Red", - StringUtils::utf32ToUtf8({0x1f7e7}) + "Orange", - StringUtils::utf32ToUtf8({0x1f7e8}) + "Yellow", - StringUtils::utf32ToUtf8({0x1f7e9}) + "Green", - StringUtils::utf32ToUtf8({0x1f7e6}) + "Blue", - StringUtils::utf32ToUtf8({0x1f7ea}) + "Purple", - StringUtils::utf32ToUtf8({0x1f5fd}) + "Cyan", - StringUtils::utf32ToUtf8({0x1f338}) + "Magenta", - StringUtils::utf32ToUtf8({ 0x2604}) + "Sky" - }; - m_shuffle_gp = ServerConfig::m_shuffle_gp; - m_current_max_players_in_game.store(ServerConfig::m_max_players_in_game); - m_consent_on_replays = false; m_fixed_lap = ServerConfig::m_fixed_lap_count; @@ -4644,7 +4601,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, auto it2 = m_team_for_player.find(username); if (it2 != m_team_for_player.end()) { - player->setTemporaryTeam(it2->second - 1); + player->setTemporaryTeam(it2->second); } peer->addPlayer(player); } @@ -4964,8 +4921,8 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) prefix = "[" + prefix + "] "; } int team = profile->getTemporaryTeam(); - if (team != -1) { - prefix = m_team_index_to_icon[team + 1] + " " + prefix; + if (team != 0) { + prefix = TeamUtils::getTeamByIndex(team).getEmoji() + " " + prefix; } profile_name = StringUtils::utf8ToWide(prefix) + profile_name; @@ -7146,36 +7103,6 @@ void ServerLobby::initCategories() } } } - /* - Temporary team indexing: - network_player_profile.hpp: -1 for none, [0..5] for teams - server config: (-1 for none,) [0..5] for teams - server lobby command: 0 for none, [1..6] for teams - m_team_for_player: 0 for none, [1..6] for teams - Sorry for the confusion. - */ - // change categories according to the teams - for (const auto& who: m_team_for_player) - { - int idx = who.second; - std::string player = who.first; - for (const auto& pair: m_team_name_to_index) - { - if (pair.second < 0) - { - if (pair.second == -idx) - { - m_player_categories[pair.first].insert(player); - m_categories_for_player[player].insert(pair.first); - } - else - { - m_player_categories[pair.first].erase(player); - m_categories_for_player[player].erase(pair.first); - } - } - } - } } // initCategories //----------------------------------------------------------------------------- void ServerLobby::initTournamentPlayers() @@ -7527,7 +7454,7 @@ std::string ServerLobby::getGrandPrixStandings(bool showIndividual, bool showTea for (unsigned i = 0; i < results2.size(); i++) { response << (i + 1) << ". "; - response << " " << m_team_name[results2[i].second]; + response << " " << TeamUtils::getTeamByIndex(results2[i].second).getNameWithEmoji(); response << " " << results2[i].first.score; response << " " << "(" << StringUtils::timeToString(results2[i].first.time) << ")"; response << "\n"; @@ -8165,8 +8092,7 @@ bool ServerLobby::isSoccerGoalTarget() const // This should be moved later to another unit. void ServerLobby::setTemporaryTeam(const std::string& username, std::string& arg) { - auto it = m_team_name_to_index.find(arg); - int index = (it == m_team_name_to_index.end() ? 0 : it->second); + int index = TeamUtils::getIndexByCode(arg); m_team_for_player[username] = index; irr::core::stringw wide_player_name = StringUtils::utf8ToWide(username); std::shared_ptr player_peer = STKHost::get()->findPeerByName( @@ -8177,7 +8103,7 @@ void ServerLobby::setTemporaryTeam(const std::string& username, std::string& arg { if (profile->getName() == wide_player_name) { - profile->setTemporaryTeam(index - 1); + profile->setTemporaryTeam(index); break; } } @@ -8192,7 +8118,7 @@ void ServerLobby::clearTemporaryTeams() for (auto& peer : STKHost::get()->getPeers()) for (auto& profile : peer->getPlayerProfiles()) - profile->setTemporaryTeam(-1); + profile->setTemporaryTeam(0); } // clearTemporaryTeams //----------------------------------------------------------------------------- @@ -8209,9 +8135,9 @@ void ServerLobby::shuffleTemporaryTeams(const std::map& permutation) { for (auto &profile: peer->getPlayerProfiles()) { - auto it = permutation.find(profile->getTemporaryTeam() + 1); + auto it = permutation.find(profile->getTemporaryTeam()); if (it != permutation.end()) - profile->setTemporaryTeam(it->second - 1); + profile->setTemporaryTeam(it->second); } } auto old_scores = m_gp_team_scores; diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index a8ce9a7fa5e..25e47713725 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -21,9 +21,10 @@ #include "network/protocols/lobby_protocol.hpp" #include "utils/cpp2011.hpp" +#include "utils/kart_elimination.hpp" +#include "utils/team_utils.hpp" #include "utils/time.hpp" #include "utils/track_filter.hpp" -#include "utils/kart_elimination.hpp" #include "karts/controller/player_controller.hpp" #include "network/protocols/command_manager.hpp" @@ -369,8 +370,6 @@ class ServerLobby : public LobbyProtocol std::map m_gp_team_scores; - std::vector m_team_name; - int m_tournament_game; int m_fixed_lap; @@ -392,12 +391,6 @@ class ServerLobby : public LobbyProtocol bool m_allowed_to_start; bool m_consent_on_replays; - - std::map m_team_name_to_index; - - std::vector m_team_default_names; - - std::map m_team_index_to_icon; bool m_shuffle_gp; diff --git a/src/utils/team_utils.cpp b/src/utils/team_utils.cpp new file mode 100644 index 00000000000..9013a15d79f --- /dev/null +++ b/src/utils/team_utils.cpp @@ -0,0 +1,94 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2024 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/string_utils.hpp" +#include "utils/team_utils.hpp" + + +void TeamManager::addTeam(std::string hardcoded_code, + std::string hardcoded_name, + float hardcoded_color, std::string hardcoded_emoji) +{ + int index = m_teams.size(); + m_teams.emplace_back(hardcoded_code, hardcoded_name, + hardcoded_color, hardcoded_emoji); + m_finder_by_code[hardcoded_code] = index; + m_finder_by_name[hardcoded_name] = index; +} // addTeam +// ======================================================================== + +void TeamManager::addCode(int idx, std::string hardcoded_code) +{ + m_teams[idx].addCode(hardcoded_code); + m_finder_by_code[hardcoded_code] = idx; +} // addCode +// ======================================================================== + +void TeamManager::addName(int idx, std::string hardcoded_name) +{ + m_teams[idx].addName(hardcoded_name); + m_finder_by_name[hardcoded_name] = idx; +} // addName +// ======================================================================== + +const CustomTeam& TeamManager::operator[](int idx) const +{ + return m_teams[idx]; +} // getTeamByIndex +// ======================================================================== + +int TeamManager::getIndexByCode(const std::string& code) const +{ + auto it = m_finder_by_code.find(code); + if (it == m_finder_by_code.end()) + // I am not sure I shouldn't return -1 but I guess for now it + // breaks something. Check out the neighboring comment too + return 0; + return it->second; +} // getIndexByCode +// ======================================================================== + +int TeamManager::getIndexByName(const std::string& name) const +{ + auto it = m_finder_by_name.find(name); + if (it == m_finder_by_name.end()) + // I am not sure I shouldn't return -1 but I guess for now it + // breaks something. Check out the neighboring comment too + return 0; + return it->second; +} // getIndexByName +// ======================================================================== + +TeamManager::TeamManager() +{ + addTeam("-", "none", 0.00, ""); + addTeam("r", "red", 1.00, StringUtils::utf32ToUtf8({0x1f7e5})); // 1 + addTeam("o", "orange", 0.05, StringUtils::utf32ToUtf8({0x1f7e7})); // 2 + addTeam("y", "yellow", 0.16, StringUtils::utf32ToUtf8({0x1f7e8})); // 3 + addTeam("g", "green", 0.33, StringUtils::utf32ToUtf8({0x1f7e9})); // 4 + addTeam("b", "blue", 0.66, StringUtils::utf32ToUtf8({0x1f7e6})); // 5 + addTeam("p", "purple", 0.78, StringUtils::utf32ToUtf8({0x1f7ea})); // 6 + addTeam("c", "cyan", 0.46, StringUtils::utf32ToUtf8({0x1f5fd})); // 7 + addTeam("m", "magenta", 0.94, StringUtils::utf32ToUtf8({0x1f338})); // 8 + addTeam("s", "sky", 0.58, StringUtils::utf32ToUtf8({ 0x2604})); // 9 + addCode(6, "v"); + addName(6, "violet"); + addName(8, "pink"); +} // TeamManager +// ======================================================================== + diff --git a/src/utils/team_utils.hpp b/src/utils/team_utils.hpp new file mode 100644 index 00000000000..46a4146d512 --- /dev/null +++ b/src/utils/team_utils.hpp @@ -0,0 +1,103 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2024 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef TEAM_UTILS_HPP +#define TEAM_UTILS_HPP + +#include "irrString.h" +#include "utils/singleton.hpp" + +#include +#include +#include +#include +#include +#include + +// A set of classes that will manipulate teams, their names +// and representations such as emojis, and probably something else +// in the future. Those teams currently have no relation to soccer +// or CTF teams, but some kind of synchronization would be nice. + +// A class describing team properties. Properties are supposed to be +// initialized and remain unchanged for now. +class CustomTeam +{ +private: + // Codes currently should start with different chars + // as e.g. swapteams in CommandManager breaks otherwise + std::vector m_codes; // Must contain at least 1 (primary) code + std::vector m_names; // Must contain at least 1 (primary) name + float m_color; // One color only for now + std::string m_emoji; // Currently only one emoji +public: + CustomTeam(std::vector& codes, + std::vector& names, + float color, std::string& emoji): + m_codes(codes), m_names(names), m_color(color), m_emoji(emoji) {} + + CustomTeam(std::string& code, std::string& name, + float color, std::string& emoji): + m_codes(1, code), m_names(1, name), m_color(color), m_emoji(emoji) {} + + std::string getPrimaryCode() const { return m_codes[0]; } + std::string getPrimaryName() const { return m_names[0]; } + std::string getNameWithEmoji() const { return m_emoji + " " + m_names[0]; } + float getColor() const { return m_color; } + std::string getEmoji() const { return m_emoji; } + void addCode(const std::string& code) { m_codes.push_back(code); } + void addName(const std::string& name) { m_names.push_back(name); } +}; + +class TeamManager +{ +private: + std::vector m_teams; + std::map m_finder_by_code; + std::map m_finder_by_name; + void addTeam(std::string hardcoded_code, std::string hardcoded_name, + float hardcoded_color, std::string hardcoded_emoji); + void addCode(int idx, std::string hardcoded_code); + void addName(int idx, std::string hardcoded_name); +public: + TeamManager(); + // Teams are indexed from 1 to N, 0 means no team set (or undefined). + // Previously the code had 4-way inconsistent indexation + // but hopefully it's fixed now' + const CustomTeam& operator[](int idx) const; + int getIndexByCode(const std::string& code) const; + int getIndexByName(const std::string& name) const; + int getNumberOfTeams() const + { return (int)m_teams.size() - 1; } +}; + +class TeamUtils: public Singleton +{ +public: + static const CustomTeam& getTeamByIndex(int idx) + { return (*getInstance())[idx]; } + static int getIndexByCode(const std::string& code) + { return getInstance()->getIndexByCode(code); } + static int getIndexByName(const std::string& name) + { return getInstance()->getIndexByName(name); } + static int getNumberOfTeams() + { return (int)getInstance()->getNumberOfTeams(); } +}; + + +#endif // TEAM_UTILS_HPP From a254c7afc2401798f91b8cbeacf0f5e66c8b142f Mon Sep 17 00:00:00 2001 From: jacekpoz <64381190+jacekpoz@users.noreply.github.com> Date: Wed, 7 Feb 2024 16:18:25 +0100 Subject: [PATCH 283/830] make loopback checking more readable (#5016) * make loopback checking more readable * follow coding style --------- Co-authored-by: jacekpoz --- src/network/socket_address.cpp | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/network/socket_address.cpp b/src/network/socket_address.cpp index affd7e81cab..519f2755b9d 100644 --- a/src/network/socket_address.cpp +++ b/src/network/socket_address.cpp @@ -460,28 +460,18 @@ bool SocketAddress::isLoopback() const else if (m_family == AF_INET6) { sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data(); - uint8_t w0 = in6->sin6_addr.s6_addr[0]; - uint8_t w1 = in6->sin6_addr.s6_addr[1]; - uint8_t w2 = in6->sin6_addr.s6_addr[2]; - uint8_t w3 = in6->sin6_addr.s6_addr[3]; - uint8_t w4 = in6->sin6_addr.s6_addr[4]; - uint8_t w5 = in6->sin6_addr.s6_addr[5]; - uint8_t w6 = in6->sin6_addr.s6_addr[6]; - uint8_t w7 = in6->sin6_addr.s6_addr[7]; - uint8_t w8 = in6->sin6_addr.s6_addr[8]; - uint8_t w9 = in6->sin6_addr.s6_addr[9]; - uint8_t w10 = in6->sin6_addr.s6_addr[10]; - uint8_t w11 = in6->sin6_addr.s6_addr[11]; - uint8_t w12 = in6->sin6_addr.s6_addr[12]; - uint8_t w13 = in6->sin6_addr.s6_addr[13]; - uint8_t w14 = in6->sin6_addr.s6_addr[14]; + for (int i = 0; i < 15; i++) + { + uint8_t w_i = in6->sin6_addr.s6_addr[i]; + if (w_i != 0) + { + return false; + } + } // for (int i = 0; i < 15; i++) + // ::1/128 Loopback uint8_t w15 = in6->sin6_addr.s6_addr[15]; - if (w0 == 0 && w1 == 0 && w2 == 0 && w3 == 0 && w4 == 0 && - w5 == 0 && w6 == 0 && w7 == 0 && w8 == 0 && w9 == 0 && - w10 == 0 && w11 == 0 && w12 == 0 && w13 == 0 && w14 == 0 - && w15 == 1) + if (w15 == 1) { - // ::1/128 Loopback return true; } } From 15c67f5e4f8454a0731c8ea9345f41e189d2aa82 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 8 Feb 2024 15:46:39 +0400 Subject: [PATCH 284/830] Allow server to kick players for inactivity while there's no game (with other duration) --- NETWORKING.md | 3 +++ src/network/protocols/server_lobby.cpp | 26 +++++++++++++++++++++++++- src/network/server_config.hpp | 9 +++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/NETWORKING.md b/NETWORKING.md index 42b7c4ff991..9d5f4756817 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -192,6 +192,9 @@ The current server configuration xml looks like this (this is only an example, j + + + diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3597f2b94c8..cfd9ad5005e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2497,7 +2497,7 @@ void ServerLobby::update(int ticks) if (m_process_type == PT_CHILD && peer->getHostId() == m_client_server_host_id.load()) continue; - Log::info("ServerLobby", "%s %s has been idle for more than" + Log::info("ServerLobby", "%s %s has been idle ingame for more than" " %d seconds, kick.", peer->getAddress().toString().c_str(), StringUtils::wideToUtf8(rki.getPlayerName()).c_str(), sec); @@ -2545,6 +2545,30 @@ void ServerLobby::update(int ticks) } } } + if (m_state.load() == WAITING_FOR_START_GAME) { + sec = ServerConfig::m_kick_idle_lobby_player_seconds; + auto peers = STKHost::get()->getPeers(); + for (auto peer: peers) + { + if (!peer->isAIPeer() && + sec > 0 && peer->idleForSeconds() > sec && + !peer->isDisconnected() && NetworkConfig::get()->isWAN()) + { + // Don't kick in game GUI server host so he can idle in the lobby + if (m_process_type == PT_CHILD && + peer->getHostId() == m_client_server_host_id.load()) + continue; + std::string peer_name = ""; + if (peer->hasPlayerProfiles()) + peer_name = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()).c_str(); + Log::info("ServerLobby", "%s %s has been idle on the server for " + "more than %d seconds, kick.", + peer->getAddress().toString().c_str(), peer_name, sec); + peer->kick(); + } + } + } if (w) setGameStartedProgress(w->getGameStartedProgress()); else diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 8fb6dfc5f5b..ba0d2dd2337 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -476,6 +476,15 @@ namespace ServerConfig "Negative value to disable, and this option will always be disabled " "for LAN server.")); + SERVER_CFG_PREFIX IntServerConfigParam m_kick_idle_lobby_player_seconds + SERVER_CFG_DEFAULT(IntServerConfigParam(-1, + "kick-idle-lobby-player-seconds", + "Kick idle player which has no network activity to server for more " + "than some seconds, while in the lobby. Duration also includes the " + "period after the player finishes and waits for others to finish. " + "Be careful using it. Negative value to disable, and this option " + "will always be disabled for LAN server.")); + SERVER_CFG_PREFIX IntServerConfigParam m_state_frequency SERVER_CFG_DEFAULT(IntServerConfigParam(10, "state-frequency", From 11e2b26c17f631148e093a1d10e1ba5796c0a107 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 20 Feb 2024 00:22:19 +0400 Subject: [PATCH 285/830] Initial implementation of cyclic map queue [big description] Inside there are many things, including: - added server config option cyclic-tracks-queue - both queue options in the config allow filters enclosed in {} now - in parallel to /queue commands, added /qcyclic and /qboth to manipulate only cyclic queue and both queues at the same time - queue commands are completely rewritten - /queue pf commands (for filters) are united with /queue push (for single maps) by making everything a filter - the above also includes slight changes to hasTypo and TrackFilter so that parts of arguments could also be checked for typos and fixed interactively (maybe it's slightly dirty because the code around hasTypo call has to do some stuff too, but I cannot think where else I could need it) - pushing only to regular queue (no matter from which end) triggers pushing a placeholder into the FRONT (!) of cyclic queue so that first the regular queue is executed. Popping works the same way, and as placeholders should be only at the front (even though you can theoretically push one to the end), shuffling the cyclic queue also only affects non-placeholders. - fixed a bug where splitQuoted produced one empty item for an empty string - running a command now updates last activity, so you won't be kicked for being idle - some auxiliary stuff is added to CommandManager so that corresponding queues for karts could be easily integrated later (and also functions for simultaneous addition to several queues, no idea how to push the same thing as a map and as a kart but I'll see) - NETWORKING.md, data/commands.xml and server_config.hpp are updated ofc --- NETWORKING.md | 5 +- data/commands.xml | 149 ++++++++-- src/network/protocols/command_manager.cpp | 346 ++++++++++++++++------ src/network/protocols/command_manager.hpp | 24 +- src/network/protocols/server_lobby.cpp | 63 ++-- src/network/protocols/server_lobby.hpp | 4 +- src/network/server_config.hpp | 10 +- src/utils/string_utils.cpp | 3 +- src/utils/track_filter.cpp | 66 +++++ src/utils/track_filter.hpp | 14 + 10 files changed, 543 insertions(+), 141 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index 9d5f4756817..d5014aae380 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -261,9 +261,12 @@ The current server configuration xml looks like this (this is only an example, j - + + + + diff --git a/data/commands.xml b/data/commands.xml index 33887fc3c47..3553384c963 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -245,84 +245,189 @@ here later. For now, please refer to the code for the strings being used. --> - - - - + + + + + + + - + + + + + + + + + + #include +std::vector CommandManager::QUEUE_NAMES = {"", "queue", "qcyclic", "qboth"}; + // ======================================================================== EnumExtendedReader CommandManager::mode_scope_reader({ {"MS_DEFAULT", MS_DEFAULT}, @@ -375,20 +377,20 @@ void CommandManager::initCommands() applyFunctionIfPossible("length x", &CM::process_length_multi); applyFunctionIfPossible("direction", &CM::process_direction); applyFunctionIfPossible("direction =", &CM::process_direction_assign); - applyFunctionIfPossible("queue", &CM::process_queue); - applyFunctionIfPossible("queue push", &CM::process_queue_push); - applyFunctionIfPossible("queue push_back", &CM::process_queue_push); - applyFunctionIfPossible("queue push_front", &CM::process_queue_push); - // Temporary pf commands - applyFunctionIfPossible("queue pf", &CM::process_queue_pf); - applyFunctionIfPossible("queue pf_back", &CM::process_queue_pf); - applyFunctionIfPossible("queue pf_front", &CM::process_queue_pf); - // End of pf commands - applyFunctionIfPossible("queue pop", &CM::process_queue_pop); - applyFunctionIfPossible("queue pop_back", &CM::process_queue_pop); - applyFunctionIfPossible("queue pop_front", &CM::process_queue_pop); - applyFunctionIfPossible("queue clear", &CM::process_queue_clear); - applyFunctionIfPossible("queue shuffle", &CM::process_queue_shuffle); + for (const std::string& name: QUEUE_NAMES) + { + if (name.empty()) + continue; + applyFunctionIfPossible(name + "", &CM::process_queue); + applyFunctionIfPossible(name + " push", &CM::process_queue_push); + applyFunctionIfPossible(name + " push_back", &CM::process_queue_push); + applyFunctionIfPossible(name + " push_front", &CM::process_queue_push); + applyFunctionIfPossible(name + " pop", &CM::process_queue_pop); + applyFunctionIfPossible(name + " pop_back", &CM::process_queue_pop); + applyFunctionIfPossible(name + " pop_front", &CM::process_queue_pop); + applyFunctionIfPossible(name + " clear", &CM::process_queue_clear); + applyFunctionIfPossible(name + " shuffle", &CM::process_queue_shuffle); + } applyFunctionIfPossible("allowstart", &CM::process_allowstart); applyFunctionIfPossible("allowstart =", &CM::process_allowstart_assign); applyFunctionIfPossible("shuffle", &CM::process_shuffle); @@ -616,7 +618,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) } m_user_command_replacements.erase(username); if (!restored) - m_user_correct_arguments.erase(username); + m_user_last_correct_argument.erase(username); std::shared_ptr current_command = m_root_command; std::shared_ptr executed_command; @@ -2459,11 +2461,21 @@ void CommandManager::process_queue(Context& context) error(context, true); return; } - std::string msg = StringUtils::insertValues("Queue (size = %d):", - (int)m_lobby->m_tracks_queue.size()); - for (const TrackFilter& s: m_lobby->m_tracks_queue) { - msg += " " + s.toString(); + std::string msg = ""; + int mask = get_queue_mask(context.m_argv[0]); + for (int x = QM_START; x < QM_END; x <<= 1) + { + if (mask & x) + { + auto& queue = get_queue(x); + msg += StringUtils::insertValues("%s (size = %d):", + get_queue_name(x), (int)queue.size()); + for (const TrackFilter& s: queue) + msg += " " + s.toString(); + msg += "\n"; + } } + msg.pop_back(); m_lobby->sendStringToPeer(msg, peer); } // process_queue // ======================================================================== @@ -2483,63 +2495,87 @@ void CommandManager::process_queue_push(Context& context) error(context); return; } + int mask = get_queue_mask(argv[0]); bool to_front = (argv[1] == "push_front"); - if (argv[2] == "-") + + if (argv.size() == 3 && argv[2] == "-") // kept until there's filter-type replacement argv[2] = getRandomMap(); - else if (argv[2] == "-addon") + else if (argv.size() == 3 && argv[2] == "-addon") // kept until there's filter-type replacement argv[2] = getRandomAddonMap(); - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 2, m_stf_all_maps, 3, false, false)) - return; - if (to_front) - m_lobby->m_tracks_queue.emplace_front(argv[2]); - else - m_lobby->m_tracks_queue.emplace_back(argv[2]); - std::string msg = "Pushed " + argv[2] - + " to the " + (to_front ? "front" : "back") - + " of queue, current queue size: " - + std::to_string(m_lobby->m_tracks_queue.size()); - m_lobby->sendStringToAllPeers(msg); - m_lobby->updatePlayerList(); -} // process_queue_push -// ======================================================================== -void CommandManager::process_queue_pf(Context& context) -{ - auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) + std::string filter_text = ""; + CommandManager::restoreCmdByArgv(filter_text, argv, ' ', '"', '"', '\\', 2); + std::vector items = TrackFilter::prepareMapNames(filter_text); + + int last_index = -1; + int prefix_length = 0; + int suffix_length = 0; + int subidx = 0; + for (TrackFilter::SplitArgument& p: items) { - error(context, true); - return; + if (!p.is_map) + continue; + if (p.index != -1 && last_index != p.index) + { + last_index = p.index; + prefix_length = 0; + subidx = 0; + } + auto& cell = context.m_argv[2 + p.index]; + suffix_length = cell.length() - p.value.length() - prefix_length; + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, + 2 + p.index, m_stf_all_maps, 3, false, false, false, subidx, + prefix_length, cell.length() - suffix_length)) + return; + p.value = cell.substr(prefix_length, cell.length() - suffix_length - prefix_length); + prefix_length += cell.length() - suffix_length; } + filter_text = ""; + for (auto& p: items) + filter_text += p.value; - if (argv.size() < 3) + std::string msg = ""; + + for (int x = QM_START; x < QM_END; x <<= 1) { - error(context); - return; - } - bool to_front = (argv[1] == "pf_front"); - std::string filter_text = argv[2]; - if (argv.size() > 3) { - CommandManager::restoreCmdByArgv(filter_text, argv, ' ', '"', '"', '\\', 2); + if (mask & x) + { + int another = another_cyclic_queue(x); + if (to_front) + { + get_queue(x).emplace_front(filter_text); + if (another >= QM_START && !(mask & another)) + { + get_queue(another).emplace_front(TrackFilter::PLACEHOLDER_STRING); + } + } + else + { + get_queue(x).emplace_back(filter_text); + // here you have to push to FRONT and not back because onetime + // queue should be invoked strictly before + if (another >= QM_START && !(mask & another)) + { + get_queue(another).emplace_front(TrackFilter::PLACEHOLDER_STRING); + } + } + + msg += "Pushed { " + filter_text + " }" + + " to the " + (to_front ? "front" : "back") + + " of " + get_queue_name(x) + ", current queue size: " + + std::to_string(get_queue(x).size()) + "\n"; + } } - if (to_front) - m_lobby->m_tracks_queue.emplace_front(filter_text); - else - m_lobby->m_tracks_queue.emplace_back(filter_text); - std::string msg = "Pushed { " + filter_text + " }" - + " to the " + (to_front ? "front" : "back") - + " of queue, current queue size: " - + std::to_string(m_lobby->m_tracks_queue.size()); + + msg.pop_back(); m_lobby->sendStringToAllPeers(msg); m_lobby->updatePlayerList(); -} // process_queue_pf +} // process_queue_push // ======================================================================== void CommandManager::process_queue_pop(Context& context) { - std::string msg; + std::string msg = ""; auto& argv = context.m_argv; auto peer = context.m_peer.lock(); if (!peer) @@ -2547,23 +2583,46 @@ void CommandManager::process_queue_pop(Context& context) error(context, true); return; } - + int mask = get_queue_mask(argv[0]); bool from_back = (argv[1] == "pop_back"); - if (m_lobby->m_tracks_queue.empty()) { - msg = "Queue was empty before."; - } - else + + for (int x = QM_START; x < QM_END; x <<= 1) { - auto object = (from_back ? m_lobby->m_tracks_queue.back() : m_lobby->m_tracks_queue.front()); - msg = "Popped " + object.toString() - + " from the " + (from_back ? "back" : "front") + " of the queue,"; - if (from_back) - m_lobby->m_tracks_queue.pop_back(); - else - m_lobby->m_tracks_queue.pop_front(); - msg += " current queue size: " - + std::to_string(m_lobby->m_tracks_queue.size()); + if (mask & x) + { + int another = another_cyclic_queue(x); + if (get_queue(x).empty()) { + msg = "The " + get_queue_name(x) + " was empty before."; + } + else + { + auto object = (from_back ? get_queue(x).back() : get_queue(x).front()); + msg += "Popped " + object.toString() + + " from the " + (from_back ? "back" : "front") + " of the " + + get_queue_name(x) + ","; + if (from_back) + { + get_queue(x).pop_back(); + } + else + { + get_queue(x).pop_front(); + } + if (another >= QM_START && !(mask & another)) + { + // here you have to pop from FRONT and not back because it + // was pushed to the front - see process_queue_push + auto& q = get_queue(another); + if (!q.empty() && q.front().isPlaceholder()) + q.pop_front(); + } + msg += " current queue size: " + + std::to_string(get_queue(x).size()); + msg += "\n"; + } + } } + msg.pop_back(); m_lobby->sendStringToAllPeers(msg); m_lobby->updatePlayerList(); } // process_queue_pop @@ -2571,10 +2630,27 @@ void CommandManager::process_queue_pop(Context& context) void CommandManager::process_queue_clear(Context& context) { - std::string msg = StringUtils::insertValues( - "Queue is now empty (previous size: %d)", - (int)m_lobby->m_tracks_queue.size()); - m_lobby->m_tracks_queue.clear(); + int mask = get_queue_mask(context.m_argv[0]); + std::string msg = ""; + for (int x = QM_START; x < QM_END; x <<= 1) + { + if (mask & x) + { + int another = another_cyclic_queue(x); + msg += StringUtils::insertValues( + "The " + get_queue_name(x) + " is now empty (previous size: %d)", + (int)get_queue(x).size()) + "\n"; + get_queue(x).clear(); + + if (another >= QM_START && !(mask & another)) + { + auto& q = get_queue(another); + while (!q.empty() && q.front().isPlaceholder()) + q.pop_front(); + } + } + } + msg.pop_back(); m_lobby->sendStringToAllPeers(msg); m_lobby->updatePlayerList(); } // process_queue_clear @@ -2584,9 +2660,37 @@ void CommandManager::process_queue_shuffle(Context& context) { std::random_device rd; std::mt19937 g(rd()); - auto& queue = m_lobby->m_tracks_queue; - std::shuffle(queue.begin(), queue.end(), g); - std::string msg = "Queue is now shuffled"; + + int mask = get_queue_mask(context.m_argv[0]); + std::string msg = ""; + + // Note that as the size of this queue is not changed, + // we don't have to do anything with placeholders for the corresponding + // cyclic queue, BUT we have to not shuffle the placeholders in the + // current queue itself + for (int x = QM_START; x < QM_END; x <<= 1) + { + if (mask & x) + { + auto& queue = get_queue(x); + // As the placeholders can be only at the start of a queue, + // let's just do a binary search - in case there are many placeholders + int L = -1; + int R = queue.size(); + int mid; + while (R - L > 1) + { + mid = (L + R) / 2; + if (queue[mid].isPlaceholder()) + L = mid; + else + R = mid; + } + std::shuffle(queue.begin() + R, queue.end(), g); + msg += "The " + get_queue_name(x) + " is now shuffled\n"; + } + } + msg.pop_back(); m_lobby->sendStringToAllPeers(msg); m_lobby->updatePlayerList(); } // process_queue_shuffle @@ -3925,7 +4029,7 @@ void CommandManager::restoreCmdByArgv(std::string& cmd, bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, std::vector& argv, std::string& cmd, int idx, SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is, - bool dont_replace) + bool dont_replace, int subidx, int substr_l, int substr_r) { if (!peer.get()) // voted return false; @@ -3933,9 +4037,18 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, if (peer->hasPlayerProfiles()) username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); - if (idx < m_user_correct_arguments[username]) + if (std::make_pair(idx, subidx) < m_user_last_correct_argument[username]) return false; - auto closest_commands = stf.getClosest(argv[idx], top, case_sensitive); + std::string text = argv[idx]; + std::string prefix = ""; + std::string suffix = ""; + if (substr_r != -1) + { + prefix = text.substr(0, substr_l); + suffix = text.substr(substr_r); + text = text.substr(substr_l, substr_r - substr_l); + } + auto closest_commands = stf.getClosest(text, top, case_sensitive); if (closest_commands.empty()) { std::string msg = "Command " + cmd + " not found"; @@ -3948,13 +4061,13 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, if ((no_zeros || at_least_two_zeros) && !(there_is_only_one && !allow_as_is)) { m_user_command_replacements[username].clear(); - m_user_correct_arguments[username] = idx + 1; + m_user_last_correct_argument[username] = {idx, subidx}; std::string initial_argument = argv[idx]; std::string response = ""; if (idx == 0) - response += "There is no command \"" + argv[idx] + "\""; + response += "There is no command \"" + text + "\""; else - response += "Argument \"" + argv[idx] + "\" may be invalid"; + response += "Argument \"" + text + "\" may be invalid"; m_user_saved_voting[username] = voting; @@ -3969,10 +4082,10 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, m_user_command_replacements[username].push_back(""); } for (unsigned i = 0; i < closest_commands.size(); ++i) { - argv[idx] = closest_commands[i].first; + argv[idx] = prefix + closest_commands[i].first + suffix; CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); m_user_command_replacements[username].push_back(cmd); - response += "\ntype /" + std::to_string(i + 1) + " to choose \"" + argv[idx] + "\""; + response += "\ntype /" + std::to_string(i + 1) + " to choose \"" + closest_commands[i].first + "\""; } argv[idx] = initial_argument; CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); @@ -3982,7 +4095,7 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, if (!dont_replace) { - argv[idx] = closest_commands[0].first; // converts case or regex + argv[idx] = prefix + closest_commands[0].first + suffix; // converts case or regex CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); } return false; @@ -4042,3 +4155,54 @@ std::string CommandManager::getAddonPreferredType() const return "track"; // default choice } // getAddonPreferredType // ======================================================================== + +int CommandManager::get_queue_mask(std::string a) +{ + for (int i = 0; i < QUEUE_NAMES.size(); i++) + if (a == QUEUE_NAMES[i]) + return i; + return QM_NONE; +} // getAddonPreferredType +// ======================================================================== + +std::deque& CommandManager::get_queue(int x) const +{ + if (x == QM_MAP_ONETIME) + return m_lobby->m_onetime_tracks_queue; + if (x == QM_MAP_CYCLIC) + return m_lobby->m_cyclic_tracks_queue; + // if (x == QM_KART_ONETIME) + // return m_lobby->m_onetime_karts_queue; + // if (x == QM_KART_CYCLIC) + // return m_lobby->m_cyclic_karts_queue; + Log::error("CommandManager", + "Unknown queue mask %d, revert to map onetime", x); + return m_lobby->m_onetime_tracks_queue; + +} // get_queue +// ======================================================================== + +std::string CommandManager::get_queue_name(int x) +{ + if (x == QM_MAP_ONETIME) + return "regular map queue"; + if (x == QM_MAP_CYCLIC) + return "cyclic map queue"; + // if (x == QM_KART_ONETIME) + // return "regular kart queue"; + // if (x == QM_KART_CYCLIC) + // return "cyclic kart queue"; + return StringUtils::insertValues( + "[Error QN%d: please report with /tell about it] queue", x); +} // get_queue_name +// ======================================================================== + +int CommandManager::another_cyclic_queue(int x) +{ + if (x == QM_MAP_ONETIME) + return QM_MAP_CYCLIC; + // if (x == QM_KART_ONETIME) + // return QM_KART_CYCLIC; + return QM_NONE; +} // get_queue_name +// ======================================================================== diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index a3585aede3c..fab1b0a85b6 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -43,6 +43,8 @@ #include "utils/enum_extended_reader.hpp" #include "utils/set_typo_fixer.hpp" #include "utils/team_utils.hpp" +#include "utils/track_filter.hpp" +#include "utils/types.hpp" class ServerLobby; class Event; @@ -80,6 +82,23 @@ class CommandManager static EnumExtendedReader mode_scope_reader; static EnumExtendedReader state_scope_reader; + enum QueueMask: int { + QM_NONE = -1, + QM_MAP_ONETIME = 1, + QM_MAP_CYCLIC = 2, + // QM_KART_ONETIME = 4, + // QM_KART_CYCLIC = 8, + QM_START = 1, + QM_END = 4 + // QM_END = 16 + }; + + static std::vector QUEUE_NAMES; + static int get_queue_mask(std::string a); + std::deque& get_queue(int x) const; + static std::string get_queue_name(int x); + static int another_cyclic_queue(int x); + enum ModeScope: int { MS_DEFAULT = 1, @@ -212,7 +231,7 @@ class CommandManager std::map m_user_saved_voting; - std::map m_user_correct_arguments; + std::map> m_user_last_correct_argument; std::map m_config_descriptions; @@ -291,7 +310,6 @@ class CommandManager void process_direction_assign(Context& context); void process_queue(Context& context); void process_queue_push(Context& context); - void process_queue_pf(Context& context); void process_queue_pop(Context& context); void process_queue_clear(Context& context); void process_queue_shuffle(Context& context); @@ -370,7 +388,7 @@ class CommandManager bool hasTypo(std::shared_ptr peer, bool voting, std::vector& argv, std::string& cmd, int idx, SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is, - bool dont_replace = false); + bool dont_replace = false, int subidx = 0, int substr_l = -1, int substr_r = -1); void onResetServer(); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index cfd9ad5005e..dc8bfcb2e8b 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3053,11 +3053,6 @@ void ServerLobby::startSelection(const Event *event) { m_available_kts.second.erase(track_erase); } -// if (!m_tracks_queue.empty()) -// { -// m_available_kts.second.clear(); -// m_available_kts.second.insert(m_tracks_queue.front()); -// } max_player = 0; STKHost::get()->updatePlayers(&max_player); @@ -3601,13 +3596,18 @@ void ServerLobby::checkRaceFinished() } m_state.store(WAIT_FOR_RACE_STOPPED); - if (!m_tracks_queue.empty()) + m_map_history.push_back(RaceManager::get()->getTrackName()); + + if (!m_onetime_tracks_queue.empty()) + { + m_onetime_tracks_queue.pop_front(); + } + if (!m_cyclic_tracks_queue.empty()) { - m_map_history.push_back(RaceManager::get()->getTrackName()); - m_tracks_queue.pop_front(); - // Reload GP tracks if GP ends - if (m_tracks_queue.empty() && m_game_setup->isGrandPrix()) - loadTracksQueueFromConfig(); + auto item = m_cyclic_tracks_queue.front(); + m_cyclic_tracks_queue.pop_front(); + if (!item.isPlaceholder()) + m_cyclic_tracks_queue.push_back(item); } } // checkRaceFinished @@ -6728,6 +6728,8 @@ bool ServerLobby::checkPeersReady(bool ignore_ai_peer) const void ServerLobby::handleServerCommand(Event* event, std::shared_ptr peer) { + if (peer.get()) + peer->updateLastActivity(); getCommandManager().handleCommand(event, peer); } // handleServerCommand //----------------------------------------------------------------------------- @@ -6990,7 +6992,10 @@ void ServerLobby::resetToDefaultSettings() m_fixed_direction = ServerConfig::m_fixed_direction; if (!m_preserve.count("queue")) - m_tracks_queue.clear(); + m_onetime_tracks_queue.clear(); + + if (!m_preserve.count("qcyclic")) + m_cyclic_tracks_queue.clear(); if (!m_preserve.count("replay")) setConsentOnReplays(false); @@ -7311,10 +7316,17 @@ bool ServerLobby::canRace(STKPeer* peer) const else if (m_spectators_by_limit.find(peer) != m_spectators_by_limit.end()) return false; - if (!m_tracks_queue.empty()) + if (!m_onetime_tracks_queue.empty()) { std::set st = peer->getClientAssets().second; - m_tracks_queue.front().apply(0, st, m_map_history); + m_onetime_tracks_queue.front().apply(0, st, m_map_history); + if (st.empty()) + return false; + } + else if (!m_cyclic_tracks_queue.empty()) + { + std::set st = peer->getClientAssets().second; + m_cyclic_tracks_queue.front().apply(0, st, m_map_history); if (st.empty()) return false; } @@ -7422,11 +7434,20 @@ int ServerLobby::getPermissions(STKPeer* peer) const //----------------------------------------------------------------------------- void ServerLobby::loadTracksQueueFromConfig() { - std::vector tokens = StringUtils::split( - ServerConfig::m_tracks_order, ' '); - m_tracks_queue.clear(); + std::vector tokens; + m_onetime_tracks_queue.clear(); + m_cyclic_tracks_queue.clear(); + + tokens = StringUtils::splitQuoted(ServerConfig::m_tracks_order, ' ', '{', '}', '\\'); + for (std::string& s: tokens) + { + m_onetime_tracks_queue.push_back(TrackFilter(s)); + m_cyclic_tracks_queue.push_back(TrackFilter(TrackFilter::PLACEHOLDER_STRING)); + } + + tokens = StringUtils::splitQuoted(ServerConfig::m_cyclic_tracks_order, ' ', '{', '}', '\\'); for (std::string& s: tokens) - m_tracks_queue.push_back(TrackFilter(s)); + m_cyclic_tracks_queue.push_back(TrackFilter(s)); } // loadTracksQueueFromConfig //----------------------------------------------------------------------------- std::string ServerLobby::getGrandPrixStandings(bool showIndividual, bool showTeam) const @@ -8220,8 +8241,10 @@ void ServerLobby::applyAllFilters(std::set& maps, bool use_history) m_tournament_track_filters[m_tournament_game].apply( max_player, maps, m_tournament_arenas); } - if (!m_tracks_queue.empty()) - m_tracks_queue.front().apply(max_player, maps, m_map_history); + if (!m_onetime_tracks_queue.empty()) + m_onetime_tracks_queue.front().apply(max_player, maps, m_map_history); + if (!m_cyclic_tracks_queue.empty()) + m_cyclic_tracks_queue.front().apply(max_player, maps, m_map_history); } } // applyAllFilters //----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 25e47713725..39c7188b32b 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -362,7 +362,9 @@ class ServerLobby : public LobbyProtocol std::set m_temp_banned; - std::deque m_tracks_queue; + std::deque m_onetime_tracks_queue; + + std::deque m_cyclic_tracks_queue; std::vector m_map_history; diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index ba0d2dd2337..89fc553d0c8 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -666,8 +666,14 @@ namespace ServerConfig SERVER_CFG_PREFIX StringServerConfigParam m_tracks_order SERVER_CFG_DEFAULT(StringServerConfigParam("", "tracks-queue", - "If non-empty, these tracks are played in the order until " - "the list ends. Can be useful for grands prix.")); + "If non-empty, these tracks (or track filters if enclosed in curly braces) " + "are played in the order until the list ends.")); + + SERVER_CFG_PREFIX StringServerConfigParam m_cyclic_tracks_order + SERVER_CFG_DEFAULT(StringServerConfigParam("", "cyclic-tracks-queue", + "If non-empty, these tracks (or track filters if enclosed in curly braces) " + "are played in the order cyclically, " + "except if something is in the regular tracks queue.")); SERVER_CFG_PREFIX StringServerConfigParam m_gp_scoring SERVER_CFG_DEFAULT(StringServerConfigParam( diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index 9c41998dd03..f4d8c6497c5 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -166,7 +166,8 @@ namespace StringUtils try { - result.emplace_back(); + if (!s.empty()) + result.emplace_back(); bool quoted = false; bool escaped = false; bool previous_space = true; diff --git a/src/utils/track_filter.cpp b/src/utils/track_filter.cpp index da975d8cd37..11b2ddfe4b4 100644 --- a/src/utils/track_filter.cpp +++ b/src/utils/track_filter.cpp @@ -32,6 +32,8 @@ #include #include +std::string TrackFilter::PLACEHOLDER_STRING = ":placeholder"; + TrackFilter::TrackFilter() { @@ -40,7 +42,13 @@ TrackFilter::TrackFilter() TrackFilter::TrackFilter(std::string input) { + // Make sure to update prepareMapNames too! initial_string = input; + if (input == PLACEHOLDER_STRING) + { + m_placeholder = true; + return; + } auto tokens = StringUtils::split(input, ' '); bool good = true; others = false; @@ -140,6 +148,62 @@ TrackFilter::TrackFilter(std::string input) others = true; } // TrackFilter //----------------------------------------------------------------------------- + +std::vector TrackFilter::prepareMapNames(std::string& input) +{ + // Basically does the same as the constructor but splits the string + // into some kind of tokens such that some of them have to be checked for + // being maps and some of them don't have to + + auto tokens = StringUtils::split(input, ' '); + std::vector res; + if (input == PLACEHOLDER_STRING) + return {SplitArgument(input, -1, false)}; + + std::set keywords = { + "", " ", "random", "available", "unavailable", "official", "addon", "not", "no", "yes", "ok", "other:yes", "other:no" + }; + for (unsigned i = 0; i < tokens.size(); i++) + { + if (i) + res.emplace_back(" ", -1, false); + + if (keywords.find(tokens[i]) != keywords.end() || tokens[i][0] == '%') + { + res.emplace_back(tokens[i], i, false); + if (tokens[i] == "random" && i + 1 < tokens.size()) + { + res.emplace_back(" ", -1, false); + res.emplace_back(tokens[i + 1], i + 1, false); + i++; + } + } + else + { + int separator = tokens[i].find(':'); + if (separator != std::string::npos) + { + std::string track = tokens[i].substr(0, separator); + std::string rest = tokens[i].substr(separator); + res.emplace_back(track, i, true); + res.emplace_back(rest, i, false); + } + else + { + res.emplace_back(tokens[i], i, true); + } + } + } + // Log::info("prepareMapNames", "================================== %s", input.c_str()); + // for (auto& p: res) + // { + // Log::info("prepareMapNames", "\"%s\", %d, %d", p.value.c_str(), p.index, (p.is_map ? 1 : 0)); + // } + // Log::info("prepareMapNames", "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); + return res; +} // prepareMapNames +//----------------------------------------------------------------------------- + std::string TrackFilter::get(const std::vector& vec, int index) { if (index >= 0 && index < vec.size()) @@ -160,6 +224,8 @@ void TrackFilter::apply(int num_players, std::set& input) const void TrackFilter::apply(int num_players, std::set& input, const std::vector& wildcards) const { + if (isPlaceholder()) + return; std::set copy = input; input.clear(); diff --git a/src/utils/track_filter.hpp b/src/utils/track_filter.hpp index a074070f948..044417a30af 100644 --- a/src/utils/track_filter.hpp +++ b/src/utils/track_filter.hpp @@ -38,6 +38,7 @@ struct TrackFilter { std::string initial_string; + bool m_placeholder = false; bool m_include_available = true; bool m_include_unavailable = true; bool m_include_official = true; @@ -58,6 +59,19 @@ struct TrackFilter const std::vector& wildcards) const; bool isPickingRandom() const { return m_pick_random; } std::string toString() const; + bool isPlaceholder() const { return m_placeholder; } + + struct SplitArgument { + std::string value; + int index; + bool is_map; + + SplitArgument(const std::string& value, int index, bool is_map): + value(value), index(index), is_map(is_map) {} + }; + + static std::vector prepareMapNames(std::string& input); + static std::string PLACEHOLDER_STRING; }; #endif From 1a8dbbdc748017bc5915019de7d59ff8088e7a4f Mon Sep 17 00:00:00 2001 From: Benau Date: Fri, 23 Feb 2024 22:30:43 +0800 Subject: [PATCH 286/830] Fix #5024 --- src/states_screens/online/networking_lobby.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/states_screens/online/networking_lobby.cpp b/src/states_screens/online/networking_lobby.cpp index a25a52ee810..f42833491f8 100644 --- a/src/states_screens/online/networking_lobby.cpp +++ b/src/states_screens/online/networking_lobby.cpp @@ -891,6 +891,8 @@ void NetworkingLobby::tearDown() m_player_list = NULL; m_joined_server.reset(); m_header_text = _("Lobby"); + if (m_header) + m_header->setText(m_header_text, true); m_header_text_width = 0; // Server has a dummy network lobby too if (!NetworkConfig::get()->isClient()) From b5eeb68fbceb050522b442c27fe9dfecb9b4cba1 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 28 Feb 2024 19:32:25 +0400 Subject: [PATCH 287/830] Add kart queue (regular + cyclic), currently only for standard karts Added fields in server config: only-played-karts, karts-queue, cyclic-karts-queue Changed commands in commands.xml: preserve, all queue commands (now available options are: mqueue/queue, mcyclic, kqueue, kcyclic, qregular, qcyclic, qboth, the last three do not have push commands). Despite my efforts, currently kart elimination + kart queue usage is NOT acting like it should. I'll fix it later - and ideally kart elimination should use kart queue, but that will be only done when there's a filter for specific usernames only, which will happen only when usernames cannot be equal to keywords. A general approach of KartFilter is the same, there are allowed karts, forbidden karts, and additionally there are *random groups*, and also a parameter to ignore player's choice or not. If the player is not ignored, random groups turn into one of their elements that player has, and player can select from those karts or allowed/not forbidden ones. If the player is ignored, player is given all karts that could be picked by the server, and when the game is starting, the server picks a kart that player has installed from each group, and rolls a random over those karts and allowed/ not forbidden ones. Therefore, the filters are applied twice, when the selection starts and when it ends. Live join should also work, and canRace() includes kart filters, too. Kart- and TrackFilter were derived from a new class Filter to allow doing things for both at once. --- NETWORKING.md | 9 + data/commands.xml | 430 +++++++++++++++++++--- src/network/protocols/command_manager.cpp | 152 +++++--- src/network/protocols/command_manager.hpp | 14 +- src/network/protocols/server_lobby.cpp | 287 ++++++++------- src/network/protocols/server_lobby.hpp | 15 +- src/network/server_config.hpp | 17 + src/utils/track_filter.cpp | 282 ++++++++++++-- src/utils/track_filter.hpp | 97 ++++- 9 files changed, 998 insertions(+), 305 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index d5014aae380..e69b99d2309 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -123,6 +123,9 @@ The current server configuration xml looks like this (this is only an example, j + + + @@ -267,6 +270,12 @@ The current server configuration xml looks like this (this is only an example, j + + + + + + diff --git a/data/commands.xml b/data/commands.xml index 3553384c963..7d68f621fc0 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -242,194 +242,516 @@ here later. For now, please refer to the code for the strings being used. --> state-scope="SS_LOBBY" /> - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -758,11 +1080,11 @@ here later. For now, please refer to the code for the strings being used. --> #include -std::vector CommandManager::QUEUE_NAMES = {"", "queue", "qcyclic", "qboth"}; +std::vector CommandManager::QUEUE_NAMES = { + "", "mqueue", "mcyclic", "mboth", + "kqueue", "qregular", "", "", + "kcyclic", "", "qcyclic", "", + "kboth", "", "", "qboth" +}; // ======================================================================== EnumExtendedReader CommandManager::mode_scope_reader({ @@ -377,19 +382,23 @@ void CommandManager::initCommands() applyFunctionIfPossible("length x", &CM::process_length_multi); applyFunctionIfPossible("direction", &CM::process_direction); applyFunctionIfPossible("direction =", &CM::process_direction_assign); - for (const std::string& name: QUEUE_NAMES) + for (int i = 0; i < QUEUE_NAMES.size(); i++) { + const std::string& name = QUEUE_NAMES[i]; if (name.empty()) continue; applyFunctionIfPossible(name + "", &CM::process_queue); - applyFunctionIfPossible(name + " push", &CM::process_queue_push); - applyFunctionIfPossible(name + " push_back", &CM::process_queue_push); - applyFunctionIfPossible(name + " push_front", &CM::process_queue_push); - applyFunctionIfPossible(name + " pop", &CM::process_queue_pop); - applyFunctionIfPossible(name + " pop_back", &CM::process_queue_pop); applyFunctionIfPossible(name + " pop_front", &CM::process_queue_pop); applyFunctionIfPossible(name + " clear", &CM::process_queue_clear); applyFunctionIfPossible(name + " shuffle", &CM::process_queue_shuffle); + applyFunctionIfPossible(name + " pop", &CM::process_queue_pop); + applyFunctionIfPossible(name + " pop_back", &CM::process_queue_pop); + // No pushing into kart and track queues at the same time + if (((i & QM_ALL_KART_QUEUES) > 0) && ((i & QM_ALL_MAP_QUEUES) > 0)) + continue; + applyFunctionIfPossible(name + " push", &CM::process_queue_push); + applyFunctionIfPossible(name + " push_back", &CM::process_queue_push); + applyFunctionIfPossible(name + " push_front", &CM::process_queue_push); } applyFunctionIfPossible("allowstart", &CM::process_allowstart); applyFunctionIfPossible("allowstart =", &CM::process_allowstart_assign); @@ -1249,7 +1258,7 @@ void CommandManager::process_addons(Context& context) /*argv[1] == "soccer" ?*/ m_lobby->m_addon_soccers ))); if (apply_filters) - m_lobby->applyAllFilters(from, false); + m_lobby->applyAllFilters(from, false); // happily the type is never karts in this line std::vector>> result; for (const std::string& s: from) result.push_back({s, {}}); @@ -2470,8 +2479,8 @@ void CommandManager::process_queue(Context& context) auto& queue = get_queue(x); msg += StringUtils::insertValues("%s (size = %d):", get_queue_name(x), (int)queue.size()); - for (const TrackFilter& s: queue) - msg += " " + s.toString(); + for (std::shared_ptr& s: queue) + msg += " " + s->toString(); msg += "\n"; } } @@ -2505,34 +2514,41 @@ void CommandManager::process_queue_push(Context& context) std::string filter_text = ""; CommandManager::restoreCmdByArgv(filter_text, argv, ' ', '"', '"', '\\', 2); - std::vector items = TrackFilter::prepareMapNames(filter_text); - int last_index = -1; - int prefix_length = 0; - int suffix_length = 0; - int subidx = 0; - for (TrackFilter::SplitArgument& p: items) + // Fix typos only if track queues are used (majority of cases anyway) + // TODO: I don't know how to fix typos for both karts and tracks + // (there's no m_stf_all_karts anyway yet) but maybe it should be done + if ((mask & QM_ALL_KART_QUEUES) == 0) { - if (!p.is_map) - continue; - if (p.index != -1 && last_index != p.index) + std::vector items = prepareAssetNames(filter_text); + + int last_index = -1; + int prefix_length = 0; + int suffix_length = 0; + int subidx = 0; + for (SplitArgument& p: items) { - last_index = p.index; - prefix_length = 0; - subidx = 0; + if (!p.is_map) + continue; + if (p.index != -1 && last_index != p.index) + { + last_index = p.index; + prefix_length = 0; + subidx = 0; + } + auto& cell = context.m_argv[2 + p.index]; + suffix_length = cell.length() - p.value.length() - prefix_length; + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, + 2 + p.index, m_stf_all_maps, 3, false, false, false, subidx, + prefix_length, cell.length() - suffix_length)) + return; + p.value = cell.substr(prefix_length, cell.length() - suffix_length - prefix_length); + prefix_length += cell.length() - suffix_length; } - auto& cell = context.m_argv[2 + p.index]; - suffix_length = cell.length() - p.value.length() - prefix_length; - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 2 + p.index, m_stf_all_maps, 3, false, false, false, subidx, - prefix_length, cell.length() - suffix_length)) - return; - p.value = cell.substr(prefix_length, cell.length() - suffix_length - prefix_length); - prefix_length += cell.length() - suffix_length; + filter_text = ""; + for (auto& p: items) + filter_text += p.value; } - filter_text = ""; - for (auto& p: items) - filter_text += p.value; std::string msg = ""; @@ -2540,24 +2556,15 @@ void CommandManager::process_queue_push(Context& context) { if (mask & x) { - int another = another_cyclic_queue(x); - if (to_front) + if (mask & QM_ALL_KART_QUEUES) { - get_queue(x).emplace_front(filter_text); - if (another >= QM_START && !(mask & another)) - { - get_queue(another).emplace_front(TrackFilter::PLACEHOLDER_STRING); - } + // TODO Make sure to update the next branch too; unite them somehow? + add_to_queue(x, mask, to_front, filter_text); } else { - get_queue(x).emplace_back(filter_text); - // here you have to push to FRONT and not back because onetime - // queue should be invoked strictly before - if (another >= QM_START && !(mask & another)) - { - get_queue(another).emplace_front(TrackFilter::PLACEHOLDER_STRING); - } + // TODO Make sure to update the previous branch too; unite them somehow? + add_to_queue(x, mask, to_front, filter_text); } msg += "Pushed { " + filter_text + " }" @@ -2597,7 +2604,7 @@ void CommandManager::process_queue_pop(Context& context) else { auto object = (from_back ? get_queue(x).back() : get_queue(x).front()); - msg += "Popped " + object.toString() + msg += "Popped " + object->toString() + " from the " + (from_back ? "back" : "front") + " of the " + get_queue_name(x) + ","; if (from_back) @@ -2613,7 +2620,7 @@ void CommandManager::process_queue_pop(Context& context) // here you have to pop from FRONT and not back because it // was pushed to the front - see process_queue_push auto& q = get_queue(another); - if (!q.empty() && q.front().isPlaceholder()) + if (!q.empty() && q.front()->isPlaceholder()) q.pop_front(); } msg += " current queue size: " @@ -2645,7 +2652,7 @@ void CommandManager::process_queue_clear(Context& context) if (another >= QM_START && !(mask & another)) { auto& q = get_queue(another); - while (!q.empty() && q.front().isPlaceholder()) + while (!q.empty() && q.front()->isPlaceholder()) q.pop_front(); } } @@ -2681,7 +2688,7 @@ void CommandManager::process_queue_shuffle(Context& context) while (R - L > 1) { mid = (L + R) / 2; - if (queue[mid].isPlaceholder()) + if (queue[mid]->isPlaceholder()) L = mid; else R = mid; @@ -4165,16 +4172,16 @@ int CommandManager::get_queue_mask(std::string a) } // getAddonPreferredType // ======================================================================== -std::deque& CommandManager::get_queue(int x) const +std::deque>& CommandManager::get_queue(int x) const { if (x == QM_MAP_ONETIME) return m_lobby->m_onetime_tracks_queue; if (x == QM_MAP_CYCLIC) return m_lobby->m_cyclic_tracks_queue; - // if (x == QM_KART_ONETIME) - // return m_lobby->m_onetime_karts_queue; - // if (x == QM_KART_CYCLIC) - // return m_lobby->m_cyclic_karts_queue; + if (x == QM_KART_ONETIME) + return m_lobby->m_onetime_karts_queue; + if (x == QM_KART_CYCLIC) + return m_lobby->m_cyclic_karts_queue; Log::error("CommandManager", "Unknown queue mask %d, revert to map onetime", x); return m_lobby->m_onetime_tracks_queue; @@ -4188,10 +4195,10 @@ std::string CommandManager::get_queue_name(int x) return "regular map queue"; if (x == QM_MAP_CYCLIC) return "cyclic map queue"; - // if (x == QM_KART_ONETIME) - // return "regular kart queue"; - // if (x == QM_KART_CYCLIC) - // return "cyclic kart queue"; + if (x == QM_KART_ONETIME) + return "regular kart queue"; + if (x == QM_KART_CYCLIC) + return "cyclic kart queue"; return StringUtils::insertValues( "[Error QN%d: please report with /tell about it] queue", x); } // get_queue_name @@ -4206,3 +4213,28 @@ int CommandManager::another_cyclic_queue(int x) return QM_NONE; } // get_queue_name // ======================================================================== + +template +void CommandManager::add_to_queue(int x, int mask, bool to_front, std::string& s) const +{ + int another = another_cyclic_queue(x); + if (to_front) + { + get_queue(x).push_front(std::make_shared(s)); + if (another >= QM_START && !(mask & another)) + { + get_queue(another).push_front(std::make_shared(T::PLACEHOLDER_STRING)); + } + } + else + { + get_queue(x).push_back(std::make_shared(s)); + // here you have to push to FRONT and not back because onetime + // queue should be invoked strictly before + if (another >= QM_START && !(mask & another)) + { + get_queue(another).push_front(std::make_shared(T::PLACEHOLDER_STRING)); + } + } +} // add_to_queue +// ======================================================================== diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index fab1b0a85b6..3ae212b373a 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -86,19 +86,23 @@ class CommandManager QM_NONE = -1, QM_MAP_ONETIME = 1, QM_MAP_CYCLIC = 2, - // QM_KART_ONETIME = 4, - // QM_KART_CYCLIC = 8, + QM_KART_ONETIME = 4, + QM_KART_CYCLIC = 8, + QM_ALL_MAP_QUEUES = QM_MAP_ONETIME | QM_MAP_CYCLIC, + QM_ALL_KART_QUEUES = QM_KART_ONETIME | QM_KART_CYCLIC, QM_START = 1, - QM_END = 4 - // QM_END = 16 + QM_END = 16 }; static std::vector QUEUE_NAMES; static int get_queue_mask(std::string a); - std::deque& get_queue(int x) const; + std::deque>& get_queue(int x) const; static std::string get_queue_name(int x); static int another_cyclic_queue(int x); + template + void add_to_queue(int x, int mask, bool to_front, std::string& s) const; + enum ModeScope: int { MS_DEFAULT = 1, diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index dc8bfcb2e8b..b187c9c4216 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1981,23 +1981,11 @@ void ServerLobby::asynchronousUpdate() // If player chose random / hasn't chose any kart for (unsigned i = 0; i < players.size(); i++) { - if (players[i]->getKartName().empty()) - { - if (m_kart_elimination.isEliminated( - StringUtils::wideToUtf8(players[i]->getName()))) - { - players[i]->setKartName(m_kart_elimination.getKart()); - } - else - { - RandomGenerator rg; - std::set::iterator it = - m_available_kts.first.begin(); - std::advance(it, - rg.get((int)m_available_kts.first.size())); - players[i]->setKartName(*it); - } - } + std::string current_kart = players[i]->getKartName(); + if (areKartFiltersIgnoringKarts()) + current_kart = ""; + std::string name = StringUtils::wideToUtf8(players[i]->getName()); + players[i]->setKartName(getKartForBadKartChoice(name, current_kart)); } NetworkString* load_world_message = getLoadWorldMessage(players, @@ -3181,99 +3169,56 @@ void ServerLobby::startSelection(const Event *event) } startVotingPeriod(ServerConfig::m_voting_timeout); - NetworkString *ns = getNetworkString(1); - // Start selection - must be synchronous since the receiver pushes - // a new screen, which must be done from the main thread. - ns->setSynchronous(true); - ns->addUInt8(LE_START_SELECTION) - .addFloat(ServerConfig::m_voting_timeout) - .addUInt8(/*m_game_setup->isGrandPrixStarted() ? 1 : */0) - .addUInt8((m_fixed_lap >= 0 - || m_default_lap_multiplier > 0.0f) ? 1 : 0) - .addUInt8(ServerConfig::m_track_voting ? 1 : 0); - const auto& all_k = m_available_kts.first; - const auto& all_t = m_available_kts.second; - ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size()); - for (const std::string& kart : all_k) - { - ns->encodeString(kart); - } - for (const std::string& track : all_t) - { - ns->encodeString(track); - } + std::string ignored_choice_string = "The server will ignore your kart choice"; - auto remaining = m_kart_elimination.getRemainingParticipants(); - if (!remaining.empty()) + peers = STKHost::get()->getPeers(); + for (auto& peer: peers) { - // Seems like I assumed the kart elimination cannot have - // preselected tracks. Not sure I really wanted this. - STKHost::get()->sendPacketToAllPeersWith( - [remaining](STKPeer* p) - { - for (auto& profile : p->getPlayerProfiles()) - { - if (remaining.count( - StringUtils::wideToUtf8(profile->getName())) != 0 - && !p->isWaitingForGame()) - { - return true; - } - } - return false; - }, ns, /*reliable*/true); - delete ns; - bool has_gnu = false; - for (auto it = all_k.begin(); it != all_k.end(); it++) - { - has_gnu |= (*it == m_kart_elimination.getKart()); - } + if (peer->isDisconnected() && !peer->isValidated()) + continue; + if (!canRace(peer) || peer->isWaitingForGame()) + continue; // they are handled below - // The same NetworkString but without any non-elimination karts NetworkString *ns = getNetworkString(1); + // Start selection - must be synchronous since the receiver pushes + // a new screen, which must be done from the main thread. ns->setSynchronous(true); ns->addUInt8(LE_START_SELECTION) .addFloat(ServerConfig::m_voting_timeout) .addUInt8(/*m_game_setup->isGrandPrixStarted() ? 1 : */0) .addUInt8((m_fixed_lap >= 0 - || m_default_lap_multiplier > 0.0f) ? 1 : 0) + || m_default_lap_multiplier > 0.0f) ? 1 : 0) .addUInt8(ServerConfig::m_track_voting ? 1 : 0); - ns->addUInt16((uint16_t)(has_gnu ? 1 : 0)).addUInt16( - (uint16_t)all_t.size()); - if (has_gnu) + + std::set all_k = m_available_kts.first; + std::string username = StringUtils::wideToUtf8(peer->getPlayerProfiles()[0]->getName()); + // std::string username = StringUtils::wideToUtf8(profile->getName()); + applyAllKartFilters(username, all_k); + + if (!m_kart_elimination.getRemainingParticipants().empty() && m_kart_elimination.getRemainingParticipants().count(username) == 0) { - ns->encodeString(std::string(m_kart_elimination.getKart())); + if (all_k.count(m_kart_elimination.getKart())) + all_k = {m_kart_elimination.getKart()}; + else + all_k = {}; } + + + const auto& all_t = m_available_kts.second; + + ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size()); + for (const std::string& kart : all_k) + ns->encodeString(kart); for (const std::string& track : all_t) - { ns->encodeString(track); - } - STKHost::get()->sendPacketToAllPeersWith( - [remaining](STKPeer* p) - { - for (auto& profile : p->getPlayerProfiles()) - { - if (remaining.count( - StringUtils::wideToUtf8(profile->getName())) != 0 - && !p->isWaitingForGame()) - { - return false; - } - } - return true; - }, ns, /*reliable*/true); - } - else - { - STKHost::get()->sendPacketToAllPeersWith( - [this](STKPeer* p) -> bool - { - return canRace(p) && !p->isWaitingForGame(); - }, ns, /*reliable*/true); + peer->sendPacket(ns, /*reliable*/true); delete ns; + + if (areKartFiltersIgnoringKarts()) + sendStringToPeer(ignored_choice_string, peer); } m_state = SELECTING; @@ -3604,10 +3549,23 @@ void ServerLobby::checkRaceFinished() } if (!m_cyclic_tracks_queue.empty()) { - auto item = m_cyclic_tracks_queue.front(); + auto item = m_cyclic_tracks_queue.front().get()->getInitialString(); + bool is_placeholder = m_cyclic_tracks_queue.front()->isPlaceholder(); m_cyclic_tracks_queue.pop_front(); - if (!item.isPlaceholder()) - m_cyclic_tracks_queue.push_back(item); + if (!is_placeholder) + m_cyclic_tracks_queue.push_back(std::make_shared(item)); + } + if (!m_onetime_karts_queue.empty()) + { + m_onetime_karts_queue.pop_front(); + } + if (!m_cyclic_karts_queue.empty()) + { + auto item = m_cyclic_karts_queue.front().get()->getInitialString(); + bool is_placeholder = m_cyclic_karts_queue.front()->isPlaceholder(); + m_cyclic_karts_queue.pop_front(); + if (!is_placeholder) + m_cyclic_karts_queue.push_back(std::make_shared(item)); } } // checkRaceFinished @@ -6377,21 +6335,17 @@ void ServerLobby::setPlayerKarts(const NetworkString& ns, STKPeer* peer) const peer->getPlayerProfiles()[i]->setKartName(m_kart_elimination.getKart()); continue; } + std::string current_kart = kart; if (kart.find("randomkart") != std::string::npos || - (kart.find("addon_") == std::string::npos && - m_available_kts.first.find(kart) == m_available_kts.first.end())) - { - RandomGenerator rg; - std::set::iterator it = - m_available_kts.first.begin(); - std::advance(it, - rg.get((int)m_available_kts.first.size())); - peer->getPlayerProfiles()[i]->setKartName(*it); - } - else + (kart.find("addon_") == std::string::npos && + m_available_kts.first.find(kart) == m_available_kts.first.end())) { - peer->getPlayerProfiles()[i]->setKartName(kart); + current_kart = ""; } + if (areKartFiltersIgnoringKarts()) + current_kart = ""; + std::string name = StringUtils::wideToUtf8(peer->getPlayerProfiles()[i]->getName()); + peer->getPlayerProfiles()[i]->setKartName(getKartForBadKartChoice(name, current_kart)); } if (peer->getClientCapabilities().find("real_addon_karts") == peer->getClientCapabilities().end() || ns.size() == 0) @@ -6997,6 +6951,12 @@ void ServerLobby::resetToDefaultSettings() if (!m_preserve.count("qcyclic")) m_cyclic_tracks_queue.clear(); + if (!m_preserve.count("kqueue")) + m_onetime_karts_queue.clear(); + + if (!m_preserve.count("kcyclic")) + m_cyclic_karts_queue.clear(); + if (!m_preserve.count("replay")) setConsentOnReplays(false); } // resetToDefaultSettings @@ -7316,20 +7276,12 @@ bool ServerLobby::canRace(STKPeer* peer) const else if (m_spectators_by_limit.find(peer) != m_spectators_by_limit.end()) return false; - if (!m_onetime_tracks_queue.empty()) - { - std::set st = peer->getClientAssets().second; - m_onetime_tracks_queue.front().apply(0, st, m_map_history); - if (st.empty()) - return false; - } - else if (!m_cyclic_tracks_queue.empty()) - { - std::set st = peer->getClientAssets().second; - m_cyclic_tracks_queue.front().apply(0, st, m_map_history); - if (st.empty()) - return false; - } + std::set maps = peer->getClientAssets().second; + std::set karts = peer->getClientAssets().first; + + applyAllFilters(maps, true); + applyAllKartFilters(username, karts, false); + if (!m_play_requirement_tracks.empty()) for (const std::string& track: m_play_requirement_tracks) if (peer->getClientAssets().second.count(track) == 0) @@ -7437,17 +7389,31 @@ void ServerLobby::loadTracksQueueFromConfig() std::vector tokens; m_onetime_tracks_queue.clear(); m_cyclic_tracks_queue.clear(); + m_onetime_karts_queue.clear(); + m_cyclic_karts_queue.clear(); tokens = StringUtils::splitQuoted(ServerConfig::m_tracks_order, ' ', '{', '}', '\\'); for (std::string& s: tokens) { - m_onetime_tracks_queue.push_back(TrackFilter(s)); - m_cyclic_tracks_queue.push_back(TrackFilter(TrackFilter::PLACEHOLDER_STRING)); + m_onetime_tracks_queue.push_back(std::make_shared(s)); + m_cyclic_tracks_queue.push_back(std::make_shared(TrackFilter::PLACEHOLDER_STRING)); } tokens = StringUtils::splitQuoted(ServerConfig::m_cyclic_tracks_order, ' ', '{', '}', '\\'); for (std::string& s: tokens) - m_cyclic_tracks_queue.push_back(TrackFilter(s)); + m_cyclic_tracks_queue.push_back(std::make_shared(s)); + + + tokens = StringUtils::splitQuoted(ServerConfig::m_karts_order, ' ', '{', '}', '\\'); + for (std::string& s: tokens) + { + m_onetime_karts_queue.push_back(std::make_shared(s)); + m_cyclic_karts_queue.push_back(std::make_shared(KartFilter::PLACEHOLDER_STRING)); + } + + tokens = StringUtils::splitQuoted(ServerConfig::m_cyclic_karts_order, ' ', '{', '}', '\\'); + for (std::string& s: tokens) + m_cyclic_karts_queue.push_back(std::make_shared(s)); } // loadTracksQueueFromConfig //----------------------------------------------------------------------------- std::string ServerLobby::getGrandPrixStandings(bool showIndividual, bool showTeam) const @@ -7660,6 +7626,7 @@ bool ServerLobby::tournamentColorsSwapped(int game) const void ServerLobby::initAvailableTracks() { m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); + m_global_karts_filter = KartFilter(ServerConfig::m_only_played_karts_string); m_must_have_tracks = StringUtils::split( ServerConfig::m_must_have_tracks_string, ' ', false); m_play_requirement_tracks = StringUtils::split( @@ -8214,7 +8181,7 @@ void ServerLobby::resetGrandPrix() } // resetGrandPrix //----------------------------------------------------------------------------- -void ServerLobby::applyAllFilters(std::set& maps, bool use_history) +void ServerLobby::applyAllFilters(std::set& maps, bool use_history) const { unsigned max_player = 0; STKHost::get()->updatePlayers(&max_player); @@ -8233,18 +8200,78 @@ void ServerLobby::applyAllFilters(std::set& maps, bool use_history) } } - m_global_filter.apply(max_player, maps); + // Please note that use_history refers to using queue filters too - + // calls with false only get map sets, etc + FilterContext track_context; + track_context.username = ""; // unused + track_context.num_players = max_player; + track_context.wildcards = m_map_history; + track_context.applied_at_selection_start = true; + track_context.elements = maps; + m_global_filter.apply(track_context); if (use_history) { + track_context.wildcards = m_tournament_arenas; if (ServerConfig::m_soccer_tournament) { - m_tournament_track_filters[m_tournament_game].apply( - max_player, maps, m_tournament_arenas); + m_tournament_track_filters[m_tournament_game].apply(track_context); } + track_context.wildcards = m_map_history; if (!m_onetime_tracks_queue.empty()) - m_onetime_tracks_queue.front().apply(max_player, maps, m_map_history); + m_onetime_tracks_queue.front()->apply(track_context); if (!m_cyclic_tracks_queue.empty()) - m_cyclic_tracks_queue.front().apply(max_player, maps, m_map_history); + m_cyclic_tracks_queue.front()->apply(track_context); } + swap(maps, track_context.elements); } // applyAllFilters //----------------------------------------------------------------------------- + +void ServerLobby::applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection) const +{ + + FilterContext kart_context; + kart_context.username = username; + kart_context.num_players = 0; // unused + kart_context.wildcards = {}; // unused + kart_context.applied_at_selection_start = !afterSelection; + kart_context.elements = karts; + + m_global_karts_filter.apply(kart_context); + if (!m_onetime_karts_queue.empty()) + { + m_onetime_karts_queue.front()->apply(kart_context); + } + if (!m_cyclic_karts_queue.empty()) + { + m_cyclic_karts_queue.front()->apply(kart_context); + } + swap(karts, kart_context.elements); +} // applyAllKartFilters +//----------------------------------------------------------------------------- +bool ServerLobby::areKartFiltersIgnoringKarts() const +{ + if (!m_onetime_karts_queue.empty() && m_onetime_karts_queue.front()->ignoresPlayersInput()) + return true; + if (!m_cyclic_karts_queue.empty() && m_cyclic_karts_queue.front()->ignoresPlayersInput()) + return true; + return false; +} // applyAllKartFilters +//----------------------------------------------------------------------------- +std::string ServerLobby::getKartForBadKartChoice(const std::string& username, const std::string& check_choice) const +{ + std::set karts = m_available_kts.first; + applyAllKartFilters(username, karts, true); + if (m_kart_elimination.isEliminated(username) + && karts.count(m_kart_elimination.getKart())) + { + return m_kart_elimination.getKart(); + } + if (!check_choice.empty() && karts.count(check_choice)) // valid choice + return check_choice; + // choice is invalid, roll the random + RandomGenerator rg; + std::set::iterator it = karts.begin(); + std::advance(it, rg.get((int)karts.size())); + return *it; +} // getKartForRandomKartChoice +//----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 39c7188b32b..d56facde5e9 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -360,11 +360,17 @@ class ServerLobby : public LobbyProtocol TrackFilter m_global_filter; + KartFilter m_global_karts_filter; + std::set m_temp_banned; - std::deque m_onetime_tracks_queue; + std::deque> m_onetime_tracks_queue; + + std::deque> m_cyclic_tracks_queue; + + std::deque> m_onetime_karts_queue; - std::deque m_cyclic_tracks_queue; + std::deque> m_cyclic_karts_queue; std::vector m_map_history; @@ -674,7 +680,10 @@ class ServerLobby : public LobbyProtocol void resetGrandPrix(); void erasePeerReady(std::shared_ptr peer) { m_peers_ready.erase(peer); } - void applyAllFilters(std::set& maps, bool use_history); + void applyAllFilters(std::set& maps, bool use_history) const; + void applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection = false) const; + bool areKartFiltersIgnoringKarts() const; + std::string getKartForBadKartChoice(const std::string& username, const std::string& check_choice) const; static int m_default_fixed_laps; }; // class ServerLobby diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 89fc553d0c8..6fa4565c26f 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -290,6 +290,12 @@ namespace ServerConfig "play-requirement-tracks", "Tracks needed to be able to play, " "leave empty for no restriction.")); + SERVER_CFG_PREFIX StringServerConfigParam m_only_played_karts_string + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "only-played-karts", "List of karts that can be played on a server, " + "leave empty for no restriction or put 'not' before the list " + "to name tracks that cannot be played. It is not guaranteed to work with addons.")); + SERVER_CFG_PREFIX StringServerConfigParam m_only_played_tracks_string SERVER_CFG_DEFAULT(StringServerConfigParam("", "only-played-tracks", "List of tracks that can be played on a server, " @@ -675,6 +681,17 @@ namespace ServerConfig "are played in the order cyclically, " "except if something is in the regular tracks queue.")); + SERVER_CFG_PREFIX StringServerConfigParam m_karts_order + SERVER_CFG_DEFAULT(StringServerConfigParam("", "karts-queue", + "If non-empty, these karts (or kart filters if enclosed in curly braces) " + "are played in the order until the list ends.")); + + SERVER_CFG_PREFIX StringServerConfigParam m_cyclic_karts_order + SERVER_CFG_DEFAULT(StringServerConfigParam("", "cyclic-karts-queue", + "If non-empty, these karts (or kart filters if enclosed in curly braces) " + "are played in the order cyclically, " + "except if something is in the regular karts queue.")); + SERVER_CFG_PREFIX StringServerConfigParam m_gp_scoring SERVER_CFG_DEFAULT(StringServerConfigParam( "fixed 0 1 10 8 6 5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", diff --git a/src/utils/track_filter.cpp b/src/utils/track_filter.cpp index 11b2ddfe4b4..9e93ed74ed4 100644 --- a/src/utils/track_filter.cpp +++ b/src/utils/track_filter.cpp @@ -32,7 +32,7 @@ #include #include -std::string TrackFilter::PLACEHOLDER_STRING = ":placeholder"; +std::string Filter::PLACEHOLDER_STRING = ":placeholder"; TrackFilter::TrackFilter() { @@ -42,8 +42,8 @@ TrackFilter::TrackFilter() TrackFilter::TrackFilter(std::string input) { - // Make sure to update prepareMapNames too! - initial_string = input; + // Make sure to update prepareAssetNames too! + m_initial_string = input; if (input == PLACEHOLDER_STRING) { m_placeholder = true; @@ -149,7 +149,8 @@ TrackFilter::TrackFilter(std::string input) } // TrackFilter //----------------------------------------------------------------------------- -std::vector TrackFilter::prepareMapNames(std::string& input) +template +std::vector prepareAssetNames(std::string& input) { // Basically does the same as the constructor but splits the string // into some kind of tokens such that some of them have to be checked for @@ -157,7 +158,25 @@ std::vector TrackFilter::prepareMapNames(std::string auto tokens = StringUtils::split(input, ' '); std::vector res; - if (input == PLACEHOLDER_STRING) + if (input == Filter::PLACEHOLDER_STRING) + return {SplitArgument(input, -1, false)}; + + for (unsigned i = 0; i < tokens.size(); i++) + { + if (i) + res.emplace_back(" ", -1, false); + res.emplace_back(tokens[i], i, false); + } + return res; +} // Filter::prepareAssetNames +//----------------------------------------------------------------------------- + +template<> +std::vector prepareAssetNames(std::string& input) +{ + auto tokens = StringUtils::split(input, ' '); + std::vector res; + if (input == Filter::PLACEHOLDER_STRING) return {SplitArgument(input, -1, false)}; std::set keywords = { @@ -194,14 +213,8 @@ std::vector TrackFilter::prepareMapNames(std::string } } } - // Log::info("prepareMapNames", "================================== %s", input.c_str()); - // for (auto& p: res) - // { - // Log::info("prepareMapNames", "\"%s\", %d, %d", p.value.c_str(), p.index, (p.is_map ? 1 : 0)); - // } - // Log::info("prepareMapNames", "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); return res; -} // prepareMapNames +} // TrackFilter::prepareAssetNames //----------------------------------------------------------------------------- std::string TrackFilter::get(const std::vector& vec, int index) @@ -214,32 +227,26 @@ std::string TrackFilter::get(const std::vector& vec, int index) } // get //----------------------------------------------------------------------------- -void TrackFilter::apply(int num_players, std::set& input) const -{ - std::vector empty; - apply(num_players, input, empty); -} // apply -//----------------------------------------------------------------------------- - -void TrackFilter::apply(int num_players, std::set& input, - const std::vector& wildcards) const +void TrackFilter::apply(FilterContext& context) const { + // Does not use username and applied_at_selection_start + // as they are the parameters for KartFilter if (isPlaceholder()) return; - std::set copy = input; - input.clear(); + std::set copy = context.elements; + context.elements.clear(); std::set names_allowed, names_forbidden; for (int x: w_allowed) { - std::string name = get(wildcards, x); + std::string name = get(context.wildcards, x); if (!name.empty()) names_allowed.insert(name); } for (int x: w_forbidden) { - std::string name = get(wildcards, x); + std::string name = get(context.wildcards, x); if (!name.empty()) names_forbidden.insert(name); } @@ -250,7 +257,7 @@ void TrackFilter::apply(int num_players, std::set& input, bool yes = false; bool no = false; auto it = max_players.find(s); - if (it != max_players.end() && it->second < num_players) + if (it != max_players.end() && it->second < context.num_players) continue; if (names_allowed.count(s) || allowed.count(s)) yes = true; @@ -274,30 +281,233 @@ void TrackFilter::apply(int num_players, std::set& input, else no = true; if (yes) - input.insert(s); + context.elements.insert(s); } - if (m_pick_random && input.size() > m_random_count) + if (m_pick_random && context.elements.size() > m_random_count) { RandomGenerator rg; std::vector take(m_random_count, 1); - take.resize(input.size(), 0); + take.resize(context.elements.size(), 0); // Shuffling the vector like it's not having the form 11..1100..00 - for (unsigned i = 0; i < input.size(); i++) + for (unsigned i = 0; i < context.elements.size(); i++) std::swap(take[rg.get(i + 1)], take[i]); std::set result; - for (std::set::iterator it = input.begin(); it != input.end(); it++) + for (std::set::iterator it = context.elements.begin(); it != context.elements.end(); it++) { if (take.back() == 1) result.insert(*it); take.pop_back(); } - std::swap(result, input); + std::swap(result, context.elements); } -} // apply (2) +} // TrackFilter::apply //----------------------------------------------------------------------------- -std::string TrackFilter::toString() const + +KartFilter::KartFilter() { - return "{ " + initial_string + " }"; // todo make it shorter -} // toString + +} // KartFilter(0) //----------------------------------------------------------------------------- + +KartFilter::KartFilter(std::string input) +{ + // TODO: Make sure that username with spaces, quotes, bad chars, etc + // are handled properly. Currently usernames are enclosed by a random brace + // to prevent commonly used chars in a typical kart elimination. + + // TODO: Make sure player names never coincide with keywords + m_initial_string = input; + if (input == PLACEHOLDER_STRING) + { + m_placeholder = true; + return; + } + // TODO: remove <> and replace with "" once the usernames cannot be keywords + auto tokens = StringUtils::splitQuoted(input, ' ', '<', '>', '\\'); + bool good = true; + bool mode_karts = true; + bool unknown_unspecified = true; + m_ignore_players_input = false; + m_placeholder = false; + for (unsigned i = 0; i < tokens.size(); i++) + { + if (tokens[i] == "" || tokens[i] == " ") + continue; + else if (tokens[i] == "karts") + mode_karts = true; + // else if (tokens[i] == "for") + // { + // mode_karts = false; + // good = true; + // } + // else if (tokens[i] == "except") + // { + // mode_karts = false; + // good = false; + // } + else if (tokens[i] == "not") + { + good = false; + } + else if (tokens[i] == "ignore") + { + m_ignore_players_input = true; + } + else if (tokens[i] == "other:yes") + { + unknown_unspecified = false; + m_allow_unspecified_karts = true; + } + else if (tokens[i] == "other:no") + { + unknown_unspecified = false; + m_allow_unspecified_karts = false; + } + else if (StringUtils::startsWith(tokens[i], "random(")) + { + if (!mode_karts) + continue; + if (!good) { + continue; + } + std::string karts_together = tokens[i].substr(7, tokens[i].length() - 8); + auto karts_mentioned = StringUtils::split(karts_together, ','); + m_random_stuff.push_back(karts_mentioned); + } + else + { + if (good) + m_allowed_karts.insert(tokens[i]); + else + m_forbidden_karts.insert(tokens[i]); + } + } + // int random_stuff_size = m_random_stuff.size(); + // if (!m_random_stuff.empty()) + // { + // for (std::string& kart: m_allowed_karts) + // { + // m_random_stuff.emplace_back(); + // m_random_stuff.back().push_back(kart); + // } + // } + // for (int i = 0; i < random_stuff_size; i++) + // { + // for (std::string& kart: m_random_stuff[i]) + // m_allowed_karts.push_back(); + // } + + if (unknown_unspecified) + if (!m_allowed_karts.empty() || !m_random_stuff.empty()) + m_allow_unspecified_karts = false; + else + m_allow_unspecified_karts = true; +} // KartFilter(1) +//----------------------------------------------------------------------------- + +void KartFilter::apply(FilterContext& context) const +{ + // Not using wildcards and num_players as they are TrackFilter parameters + // Not username for now, subject to change later when username-keyword + // conflicts are resolved + + if (isPlaceholder()) + return; + + // if (m_except_players.count(context.username) > 0 || + // (m_for_players.count(context.username) == 0 && !m_apply_for_unspecified_players)) + // { + // return; + // } + + // Ignoring means that the random of allowed and randoms will be picked afterwards + // Not ignoring means that the player chooses from allowed + // and one instance of each random + std::set result; + + // delete forbidden karts + for (const std::string& kart: context.elements) { + if (m_allowed_karts.count(kart) > 0) + { + result.insert(kart); + } + else if (m_forbidden_karts.count(kart) > 0) + { + continue; + } + else if (m_allow_unspecified_karts) + { + result.insert(kart); + } + } + /* + * KartFilter currently has two ways to allow karts: individually or as a part of + * *random group*. + * + * There are two considerably different cases which this code tries to handle: + * 1. m_ignore_players_input is FALSE, which means that the filter gives player + * all individual karts and a kart from each random group, to choose from them. + * If a player has nothing non-forbidden from the group, it is ignored. + * 2. m_ignore_players_input is TRUE, which means that the filter chooses the + * kart ITSELF and only gives a list of all possible karts to player (so that + * the player is aware what can be encountered). The server chooses the random kart + * in the same way: picks one kart at random from every random group, adds individual + * karts and picks randomly from the result. Server chooses the kart when + * applied_at_selection_start is FALSE, that is, on the second run which is absent + * for (1). In this case, the random is invoked in go_on_race branch or in livejoin + * function, not here (for uniformity and because there can be other filters to apply). + */ + + // TODO: maybe would be bad in the future when + // we try to force karts but anyway forcing should be done before applying the filters + if ((!m_ignore_players_input && context.applied_at_selection_start) + || (m_ignore_players_input && !context.applied_at_selection_start)) + { + for (const auto& array: m_random_stuff) + { + std::vector available; + for (const std::string& kart: array) + { + if (m_forbidden_karts.count(kart) > 0) + { + continue; + } + if (context.elements.count(kart) == 0) + { + continue; + } + available.push_back(kart); + } + if (available.empty()) + continue; + RandomGenerator rg; + std::string s = available[rg.get(available.size())]; + result.insert(s); + } + } + else if (m_ignore_players_input && context.applied_at_selection_start) + { + for (const auto& array: m_random_stuff) + { + for (const std::string& kart: array) + { + if (m_forbidden_karts.count(kart) > 0) + continue; + // if (m_allowed_karts.count(kart) == 0 && !m_allow_unspecified_karts) + // continue; + if (context.elements.count(kart) == 0) + continue; + result.insert(kart); + } + } + } + else + { + Log::warn("TrackFilter", "Not ignoring player's input but was invoked for the second time"); + // should not happen + } + std::swap(result, context.elements); +} // KartFilter::apply +//----------------------------------------------------------------------------- + /* EOF */ diff --git a/src/utils/track_filter.hpp b/src/utils/track_filter.hpp index 044417a30af..2222e8874cc 100644 --- a/src/utils/track_filter.hpp +++ b/src/utils/track_filter.hpp @@ -35,10 +35,42 @@ // forbidden. Putting one track into both vectors produces undefined behaviour // for now. Works with wildcards (indices are integers: ..., %-1, %0, %1, ...). -struct TrackFilter -{ - std::string initial_string; +struct SplitArgument { + std::string value; + int index; + bool is_map; + + SplitArgument(const std::string& value, int index, bool is_map): + value(value), index(index), is_map(is_map) {} +}; + +struct FilterContext { + std::string username; + std::set elements; + int num_players; + std::vector wildcards; + bool applied_at_selection_start; +}; + +class Filter { +public: + std::string m_initial_string; + std::string toString() const { return "{ " + m_initial_string + " }"; } // toString + bool m_placeholder = false; + bool isPlaceholder() const { return m_placeholder; } + + Filter() {} + Filter(std::string input) {} + std::string getInitialString() const { return m_initial_string; } + virtual void apply(FilterContext& context) const = 0; + virtual bool ignoresPlayersInput() const { return false; } + static std::string PLACEHOLDER_STRING; +}; + +class TrackFilter: public Filter +{ +public: bool m_include_available = true; bool m_include_unavailable = true; bool m_include_official = true; @@ -54,24 +86,55 @@ struct TrackFilter TrackFilter(); TrackFilter(std::string input); static std::string get(const std::vector& vec, int index); - void apply(int num_players, std::set& input) const; - void apply(int num_players, std::set& input, - const std::vector& wildcards) const; + void apply(FilterContext& context) const override; bool isPickingRandom() const { return m_pick_random; } - std::string toString() const; - bool isPlaceholder() const { return m_placeholder; } +}; - struct SplitArgument { - std::string value; - int index; - bool is_map; +// A structure to apply requirements to the kart set. Currently +// supports a narrow set of filters, like forcing all players except +// to take a kart or a random kart set. +// It should be also used by Kart Elimination, even though for now +// Kart Elimination will NOT use KartFilter, as KartFilter is yet to +// support custom player sets to be included/excluded from the filter. +// Technically there are no issues with adding custom player sets, +// EXCEPT that it is completely unusable if local player names coincide +// with keywords; I would like to handle that later and VERY CAREFULLY - SplitArgument(const std::string& value, int index, bool is_map): - value(value), index(index), is_map(is_map) {} - }; +// Currently works only for standard karts, as addons are probably shown +// for the player anyway. If addons are forbidden by the filter but chosen, +// there is an additional check while the world is loading anyway. - static std::vector prepareMapNames(std::string& input); - static std::string PLACEHOLDER_STRING; +// Currently KartFilter does not support wildcards. + +class KartFilter: public Filter +{ +private: + bool m_ignore_players_input = false; + std::set m_allowed_karts; + std::set m_forbidden_karts; + std::vector> m_random_stuff; + bool m_allow_unspecified_karts; + // std::vector m_for_players; + // std::vector m_except_players; + // bool m_apply_for_unspecified_players; +public: + KartFilter(); + KartFilter(std::string input); + + bool ignoresPlayersInput() const override { return m_ignore_players_input; } + // apply is called when the selection starts just like for maps, + // while applyAfterwards is called when the selection ends to determine the + // random kart for a player who selected nothing (or a random kart, + // or if the filter ignores player's input. + void apply(FilterContext& context) const override; + bool isPlaceholder() const { return m_placeholder; } }; + + +// TODO: prepareMapNames ONLY WORKS FOR MAPS, THERE IS NO TYPO FIXING +// FOR KARTS. Maybe this should be changed but idk how yet. +template +std::vector prepareAssetNames(std::string& input); + #endif From a58210283c5789e992801dfd2be2d28195bee21a Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 29 Feb 2024 02:47:36 +0400 Subject: [PATCH 288/830] Bugfixes for kart queue + canRace is not invoked at 300 Hz now Fixed addons not appearing, wrong type, and stopped invoking KartFilter for the second time when not ignoring the player --- src/network/protocols/command_manager.cpp | 2 +- src/network/protocols/server_lobby.cpp | 46 ++++++++++++++--------- src/network/protocols/server_lobby.hpp | 10 +++-- src/utils/track_filter.cpp | 15 ++++---- 4 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 53f4b0cff15..79f91fc6282 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -4228,7 +4228,7 @@ void CommandManager::add_to_queue(int x, int mask, bool to_front, std::string& s } else { - get_queue(x).push_back(std::make_shared(s)); + get_queue(x).push_back(std::make_shared(s)); // here you have to push to FRONT and not back because onetime // queue should be invoked strictly before if (another >= QM_START && !(mask & another)) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index b187c9c4216..ae5e8d66309 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1985,7 +1985,7 @@ void ServerLobby::asynchronousUpdate() if (areKartFiltersIgnoringKarts()) current_kart = ""; std::string name = StringUtils::wideToUtf8(players[i]->getName()); - players[i]->setKartName(getKartForBadKartChoice(name, current_kart)); + players[i]->setKartName(getKartForBadKartChoice(players[i]->getPeer().get(), name, current_kart)); } NetworkString* load_world_message = getLoadWorldMessage(players, @@ -3192,7 +3192,7 @@ void ServerLobby::startSelection(const Event *event) .addUInt8(ServerConfig::m_track_voting ? 1 : 0); - std::set all_k = m_available_kts.first; + std::set all_k = peer->getClientAssets().first; std::string username = StringUtils::wideToUtf8(peer->getPlayerProfiles()[0]->getName()); // std::string username = StringUtils::wideToUtf8(profile->getName()); applyAllKartFilters(username, all_k); @@ -6345,7 +6345,7 @@ void ServerLobby::setPlayerKarts(const NetworkString& ns, STKPeer* peer) const if (areKartFiltersIgnoringKarts()) current_kart = ""; std::string name = StringUtils::wideToUtf8(peer->getPlayerProfiles()[i]->getName()); - peer->getPlayerProfiles()[i]->setKartName(getKartForBadKartChoice(name, current_kart)); + peer->getPlayerProfiles()[i]->setKartName(getKartForBadKartChoice(peer, name, current_kart)); } if (peer->getClientCapabilities().find("real_addon_karts") == peer->getClientCapabilities().end() || ns.size() == 0) @@ -6564,6 +6564,7 @@ std::set& ServerLobby::getSpectatorsByLimit(bool update) if (!update) return m_spectators_by_limit; + m_peers_ability_to_play.clear(); m_spectators_by_limit.clear(); auto peers = STKHost::get()->getPeers(); @@ -6655,7 +6656,7 @@ bool ServerLobby::supportsAI() } // supportsAI //----------------------------------------------------------------------------- -bool ServerLobby::checkPeersReady(bool ignore_ai_peer) const +bool ServerLobby::checkPeersReady(bool ignore_ai_peer) { bool all_ready = true; bool someone_races = false; @@ -7256,25 +7257,29 @@ void ServerLobby::sendStringToAllPeers(std::string& s) delete chat; } // sendStringToAllPeers //----------------------------------------------------------------------------- -bool ServerLobby::canRace(std::shared_ptr& peer) const +bool ServerLobby::canRace(std::shared_ptr& peer) { return canRace(peer.get()); } // canRace //----------------------------------------------------------------------------- -bool ServerLobby::canRace(STKPeer* peer) const +bool ServerLobby::canRace(STKPeer* peer) { + auto it = m_peers_ability_to_play.find(peer); + if (it != m_peers_ability_to_play.end()) + return it->second; + if (!peer || peer->getPlayerProfiles().empty()) - return false; + return m_peers_ability_to_play[peer] = false; std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); if (ServerConfig::m_soccer_tournament) { if (m_tournament_red_players.count(username) == 0 && m_tournament_blue_players.count(username) == 0) - return false; + return m_peers_ability_to_play[peer] = false; } else if (m_spectators_by_limit.find(peer) != m_spectators_by_limit.end()) - return false; + return m_peers_ability_to_play[peer] = false; std::set maps = peer->getClientAssets().second; std::set karts = peer->getClientAssets().first; @@ -7282,19 +7287,22 @@ bool ServerLobby::canRace(STKPeer* peer) const applyAllFilters(maps, true); applyAllKartFilters(username, karts, false); + if (maps.empty() || karts.empty()) + return m_peers_ability_to_play[peer] = false; + if (!m_play_requirement_tracks.empty()) for (const std::string& track: m_play_requirement_tracks) if (peer->getClientAssets().second.count(track) == 0) - return false; + return m_peers_ability_to_play[peer] = false; if (peer->addon_karts_count < ServerConfig::m_addon_karts_play_threshold) - return false; + return m_peers_ability_to_play[peer] = false; if (peer->addon_tracks_count < ServerConfig::m_addon_tracks_play_threshold) - return false; + return m_peers_ability_to_play[peer] = false; if (peer->addon_arenas_count < ServerConfig::m_addon_arenas_play_threshold) - return false; + return m_peers_ability_to_play[peer] = false; if (peer->addon_soccers_count < ServerConfig::m_addon_soccers_play_threshold) - return false; - return true; + return m_peers_ability_to_play[peer] = false; + return m_peers_ability_to_play[peer] = true; } // canRace //----------------------------------------------------------------------------- bool ServerLobby::canVote(std::shared_ptr& peer) const @@ -8218,9 +8226,13 @@ void ServerLobby::applyAllFilters(std::set& maps, bool use_history) } track_context.wildcards = m_map_history; if (!m_onetime_tracks_queue.empty()) + { m_onetime_tracks_queue.front()->apply(track_context); + } if (!m_cyclic_tracks_queue.empty()) + { m_cyclic_tracks_queue.front()->apply(track_context); + } } swap(maps, track_context.elements); } // applyAllFilters @@ -8257,9 +8269,9 @@ bool ServerLobby::areKartFiltersIgnoringKarts() const return false; } // applyAllKartFilters //----------------------------------------------------------------------------- -std::string ServerLobby::getKartForBadKartChoice(const std::string& username, const std::string& check_choice) const +std::string ServerLobby::getKartForBadKartChoice(STKPeer* peer, const std::string& username, const std::string& check_choice) const { - std::set karts = m_available_kts.first; + std::set karts = peer->getClientAssets().first; applyAllKartFilters(username, karts, true); if (m_kart_elimination.isEliminated(username) && karts.count(m_kart_elimination.getKart())) diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index d56facde5e9..abb056684e8 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -312,6 +312,8 @@ class ServerLobby : public LobbyProtocol std::set m_team_speakers; + std::map m_peers_ability_to_play; + KartElimination m_kart_elimination; std::set m_available_difficulties; @@ -465,7 +467,7 @@ class ServerLobby : public LobbyProtocol void handleServerConfiguration(std::shared_ptr peer, int difficulty, int mode, bool soccer_goal_target); void updateTracksForMode(); - bool checkPeersReady(bool ignore_ai_peer) const; + bool checkPeersReady(bool ignore_ai_peer); void resetPeersReady() { for (auto it = m_peers_ready.begin(); it != m_peers_ready.end();) @@ -571,8 +573,8 @@ class ServerLobby : public LobbyProtocol void initCategories(); void initTournamentPlayers(); void changeColors(); - bool canRace(std::shared_ptr& peer) const; - bool canRace(STKPeer* peer) const; + bool canRace(std::shared_ptr& peer); + bool canRace(STKPeer* peer); bool canVote(std::shared_ptr& peer) const; bool canVote(STKPeer* peer) const; bool hasHostRights(std::shared_ptr& peer) const; @@ -683,7 +685,7 @@ class ServerLobby : public LobbyProtocol void applyAllFilters(std::set& maps, bool use_history) const; void applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection = false) const; bool areKartFiltersIgnoringKarts() const; - std::string getKartForBadKartChoice(const std::string& username, const std::string& check_choice) const; + std::string getKartForBadKartChoice(STKPeer* peer, const std::string& username, const std::string& check_choice) const; static int m_default_fixed_laps; }; // class ServerLobby diff --git a/src/utils/track_filter.cpp b/src/utils/track_filter.cpp index 9e93ed74ed4..4b1d1d3bd65 100644 --- a/src/utils/track_filter.cpp +++ b/src/utils/track_filter.cpp @@ -420,6 +420,10 @@ void KartFilter::apply(FilterContext& context) const // return; // } + + if (!m_ignore_players_input && !context.applied_at_selection_start) + return; + // Ignoring means that the random of allowed and randoms will be picked afterwards // Not ignoring means that the player chooses from allowed // and one instance of each random @@ -492,20 +496,17 @@ void KartFilter::apply(FilterContext& context) const for (const std::string& kart: array) { if (m_forbidden_karts.count(kart) > 0) + { continue; - // if (m_allowed_karts.count(kart) == 0 && !m_allow_unspecified_karts) - // continue; + } if (context.elements.count(kart) == 0) + { continue; + } result.insert(kart); } } } - else - { - Log::warn("TrackFilter", "Not ignoring player's input but was invoked for the second time"); - // should not happen - } std::swap(result, context.elements); } // KartFilter::apply //----------------------------------------------------------------------------- From 3f217b0b180c69bfd50f2fdbaecdfff096722aae Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:23:57 +0400 Subject: [PATCH 289/830] More bug fixes for kart queue + AI choose standard karts only on the server Addons were pickable even when explicitly forbidden by filter, because apparently I need to call kart filter twice anyway. Happily it's quite beautiful, as one of cases is the exact inverse of the order of another case. --- src/network/protocols/server_lobby.cpp | 2 +- src/utils/track_filter.cpp | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index ae5e8d66309..d4e3aa682b4 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -8271,7 +8271,7 @@ bool ServerLobby::areKartFiltersIgnoringKarts() const //----------------------------------------------------------------------------- std::string ServerLobby::getKartForBadKartChoice(STKPeer* peer, const std::string& username, const std::string& check_choice) const { - std::set karts = peer->getClientAssets().first; + std::set karts = (peer->isAIPeer() ? m_available_kts.first : peer->getClientAssets().first); applyAllKartFilters(username, karts, true); if (m_kart_elimination.isEliminated(username) && karts.count(m_kart_elimination.getKart())) diff --git a/src/utils/track_filter.cpp b/src/utils/track_filter.cpp index 4b1d1d3bd65..55a9b7599ab 100644 --- a/src/utils/track_filter.cpp +++ b/src/utils/track_filter.cpp @@ -420,10 +420,6 @@ void KartFilter::apply(FilterContext& context) const // return; // } - - if (!m_ignore_players_input && !context.applied_at_selection_start) - return; - // Ignoring means that the random of allowed and randoms will be picked afterwards // Not ignoring means that the player chooses from allowed // and one instance of each random @@ -489,7 +485,8 @@ void KartFilter::apply(FilterContext& context) const result.insert(s); } } - else if (m_ignore_players_input && context.applied_at_selection_start) + else if ((m_ignore_players_input && context.applied_at_selection_start) + || (!m_ignore_players_input && !context.applied_at_selection_start)) { for (const auto& array: m_random_stuff) { From 4aed4344e216ecba33f185a3944bc7ddb884353a Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 1 Mar 2024 23:33:06 +0400 Subject: [PATCH 290/830] Prevent kart placeholders from null pointer dereferencing when setting karts Probably, not sure, it is almost certainly the case but I might be mistaken --- src/network/protocols/server_lobby.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index d4e3aa682b4..c3819b4f598 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1982,6 +1982,8 @@ void ServerLobby::asynchronousUpdate() for (unsigned i = 0; i < players.size(); i++) { std::string current_kart = players[i]->getKartName(); + if (!players[i]->getPeer().get()) + continue; if (areKartFiltersIgnoringKarts()) current_kart = ""; std::string name = StringUtils::wideToUtf8(players[i]->getName()); From e18cd66714c73dd2cd026840684a8d01e88bdaa0 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 2 Mar 2024 00:32:01 +0400 Subject: [PATCH 291/830] Avoid nullptr usage by not checking the number of players on FFA arenas not installed by server --- src/network/protocols/server_lobby.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index c3819b4f598..5544b36872f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -8201,7 +8201,7 @@ void ServerLobby::applyAllFilters(std::set& maps, bool use_history) while (it != maps.end()) { Track* t = track_manager->getTrack(*it); - if (t->getMaxArenaPlayers() < max_player) + if (t && t->getMaxArenaPlayers() < max_player) { it = maps.erase(it); } From 979077ababad2b8a87fd262cbacbad4562690bb3 Mon Sep 17 00:00:00 2001 From: oldherl Date: Wed, 20 Mar 2024 16:53:31 +1100 Subject: [PATCH 292/830] Update Cantarell font Update to Cantarell 0.303. Upstream releases only include VF files now. This single weight file was extracted from debian package fonts-cantarell_0.303.1-1_all.deb --- data/ttf/Cantarell-Regular.otf | Bin 198100 -> 103040 bytes data/ttf/LICENSE | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/data/ttf/Cantarell-Regular.otf b/data/ttf/Cantarell-Regular.otf index f65896848a674f2dda23d7a306c0592775913a7c..3451736457c673c6bf506658bc182f6f31808afc 100644 GIT binary patch literal 103040 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 Date: Tue, 26 Mar 2024 16:48:23 +0400 Subject: [PATCH 293/830] Don't (mistakenly) reset kart data upon loading the world Instead find it separately if it's different --- src/network/kart_data.hpp | 1 + src/network/protocols/server_lobby.cpp | 72 +++++++++++++++++++------- src/network/protocols/server_lobby.hpp | 3 ++ 3 files changed, 56 insertions(+), 20 deletions(-) diff --git a/src/network/kart_data.hpp b/src/network/kart_data.hpp index 6e6096d2e19..a9c750c234f 100644 --- a/src/network/kart_data.hpp +++ b/src/network/kart_data.hpp @@ -29,6 +29,7 @@ class KartData KartData(const BareNetworkString& ns); // ------------------------------------------------------------------------ void encode(BareNetworkString* ns) const; + }; // class KartData #endif // KART_DATA_HPP diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 5544b36872f..b80bd14fa0f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1987,7 +1987,23 @@ void ServerLobby::asynchronousUpdate() if (areKartFiltersIgnoringKarts()) current_kart = ""; std::string name = StringUtils::wideToUtf8(players[i]->getName()); - players[i]->setKartName(getKartForBadKartChoice(players[i]->getPeer().get(), name, current_kart)); + // Note 1: setKartName also resets KartData, and should be called + // only if current kart name is not suitable. + // Note 2: filters only support standard karts for now, so GKFBKC + // cannot return an addon; when addons are supported, this part of + // code will also have to provide kart data (or setKartName has to + // set the correct hitbox itself). + std::string new_kart = getKartForBadKartChoice( + players[i]->getPeer().get(), name, current_kart); + if (new_kart != current_kart) + { + // Filters only support standard karts for now, but when they + // start supporting addons, probably type should not be empty + players[i]->setKartName(new_kart); + KartData kart_data; + setKartDataProperly(kart_data, new_kart, players[i], ""); + players[i]->setKartData(kart_data); + } } NetworkString* load_world_message = getLoadWorldMessage(players, @@ -6358,25 +6374,7 @@ void ServerLobby::setPlayerKarts(const NetworkString& ns, STKPeer* peer) const std::string type = kart_data.m_kart_type; auto& player = peer->getPlayerProfiles()[i]; const std::string& kart_id = player->getKartName(); - if (NetworkConfig::get()->useTuxHitboxAddon() && - StringUtils::startsWith(kart_id, "addon_") && - kart_properties_manager->hasKartTypeCharacteristic(type)) - { - const KartProperties* real_addon = - kart_properties_manager->getKart(kart_id); - if (ServerConfig::m_real_addon_karts && real_addon) - { - kart_data = KartData(real_addon); - } - else - { - const KartProperties* tux_kp = - kart_properties_manager->getKart("tux"); - kart_data = KartData(tux_kp); - kart_data.m_kart_type = type; - } - player->setKartData(kart_data); - } + setKartDataProperly(kart_data, kart_id, player, type); } } // setPlayerKarts @@ -8289,3 +8287,37 @@ std::string ServerLobby::getKartForBadKartChoice(STKPeer* peer, const std::strin return *it; } // getKartForRandomKartChoice //----------------------------------------------------------------------------- +void ServerLobby::setKartDataProperly(KartData& kart_data, const std::string& kart_name, + std::shared_ptr player, + const std::string& type) const +{ + // This should set kart data for kart name at least in the following cases: + // 1. useTuxHitboxAddon() is true + // 2. kart_name is installed on the server + // (for addons; standard karts are not processed here it seems) + // 3. kart type is fine + // Maybe I'm mistaken and then it should be fixed. + // I extracted this into a separate function because if kart_name is set + // by the server (for random addon kart, or due to a filter), kart data + // has to be set in another place than default one. + if (NetworkConfig::get()->useTuxHitboxAddon() && + StringUtils::startsWith(kart_name, "addon_") && + kart_properties_manager->hasKartTypeCharacteristic(type)) + { + const KartProperties* real_addon = + kart_properties_manager->getKart(kart_name); + if (ServerConfig::m_real_addon_karts && real_addon) + { + kart_data = KartData(real_addon); + } + else + { + const KartProperties* tux_kp = + kart_properties_manager->getKart("tux"); + kart_data = KartData(tux_kp); + kart_data.m_kart_type = type; + } + player->setKartData(kart_data); + } +} // setKartDataProperly +//----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index abb056684e8..30bee5ff529 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -686,6 +686,9 @@ class ServerLobby : public LobbyProtocol void applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection = false) const; bool areKartFiltersIgnoringKarts() const; std::string getKartForBadKartChoice(STKPeer* peer, const std::string& username, const std::string& check_choice) const; + void setKartDataProperly(KartData& kart_data, const std::string& kart_name, + std::shared_ptr player, + const std::string& type) const; static int m_default_fixed_laps; }; // class ServerLobby From 4ee7c51131d4f84ed64e273ae741fbb16424495f Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 2 Apr 2024 00:42:33 +0400 Subject: [PATCH 294/830] Fix random choice of several equal votes in handleAllVotes --- src/network/protocols/server_lobby.cpp | 97 +++++++++++--------------- src/network/protocols/server_lobby.hpp | 3 + 2 files changed, 45 insertions(+), 55 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3516ffe0367..fd4d0ca37e3 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4308,7 +4308,7 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote, } std::string top_track = m_default_vote->m_track_name; - int top_laps = m_default_vote->m_num_laps; + unsigned top_laps = m_default_vote->m_num_laps; bool top_reverse = m_default_vote->m_reverse; std::map tracks; @@ -4319,7 +4319,6 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote, float tracks_rate = 0.0f; float laps_rate = 0.0f; float reverses_rate = 0.0f; - RandomGenerator rg; for (auto& p : m_peers_votes) { @@ -4340,57 +4339,9 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote, reverse_vote->second++; } - unsigned vote = 0; - auto track_vote = tracks.begin(); - // rg.get(2) == 0 will allow not always the "less" in map get picked - for (auto c_vote = tracks.begin(); c_vote != tracks.end(); c_vote++) - { - if (c_vote->second > vote || - (c_vote->second >= vote && rg.get(2) == 0)) - { - vote = c_vote->second; - track_vote = c_vote; - } - } - if (track_vote != tracks.end()) - { - top_track = track_vote->first; - tracks_rate = float(track_vote->second) / cur_players; - } - - vote = 0; - auto lap_vote = laps.begin(); - for (auto c_vote = laps.begin(); c_vote != laps.end(); c_vote++) - { - if (c_vote->second > vote || - (c_vote->second >= vote && rg.get(2) == 0)) - { - vote = c_vote->second; - lap_vote = c_vote; - } - } - if (lap_vote != laps.end()) - { - top_laps = lap_vote->first; - laps_rate = float(lap_vote->second) / cur_players; - } - - vote = 0; - auto reverse_vote = reverses.begin(); - for (auto c_vote = reverses.begin(); c_vote != reverses.end(); c_vote++) - { - if (c_vote->second > vote || - (c_vote->second >= vote && rg.get(2) == 0)) - { - vote = c_vote->second; - reverse_vote = c_vote; - } - } - if (reverse_vote != reverses.end()) - { - top_reverse = reverse_vote->first; - reverses_rate = float(reverse_vote->second) / cur_players; - } + findMajorityValue(tracks, cur_players, &top_track, &tracks_rate); + findMajorityValue(laps, cur_players, &top_laps, &laps_rate); + findMajorityValue(reverses, cur_players, &top_reverse, &reverses_rate); // End early if there is majority agreement which is all entries rate > 0.5 it = m_peers_votes.begin(); @@ -4424,10 +4375,10 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote, while (it != m_peers_votes.end()) { if (it->second.m_track_name == top_track && - std::abs((int)it->second.m_num_laps - top_laps) < diff) + std::abs((int)it->second.m_num_laps - (int)top_laps) < diff) { closest_lap = it; - diff = std::abs((int)it->second.m_num_laps - top_laps); + diff = std::abs((int)it->second.m_num_laps - (int)top_laps); } else it++; @@ -4439,6 +4390,42 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote, return false; } // handleAllVotes +// ---------------------------------------------------------------------------- +template +void ServerLobby::findMajorityValue(const std::map& choices, unsigned cur_players, + T* best_choice, float* rate) +{ + RandomGenerator rg; + unsigned max_votes = 0; + auto best_iter = choices.begin(); + unsigned best_iters_count = 1; + // Among choices with max votes, we need to pick one uniformly, + // thus we have to keep track of their number + for (auto iter = choices.begin(); iter != choices.end(); iter++) + { + if (iter->second > max_votes) + { + max_votes = iter->second; + best_iter = iter; + best_iters_count = 1; + } + else if (iter->second == max_votes) + { + best_iters_count++; + if (rg.get(best_iters_count) == 0) + { + max_votes = iter->second; + best_iter = iter; + } + } + } + if (best_iter != choices.end()) + { + *best_choice = best_iter->first; + *rate = float(best_iter->second) / cur_players; + } +} // findMajorityValue + // ---------------------------------------------------------------------------- void ServerLobby::getHitCaptureLimit() { diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 53d3acedaeb..a54f9f901bb 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -330,6 +330,9 @@ class ServerLobby : public LobbyProtocol const irr::core::stringw& online_name, const std::string& country_code); bool handleAllVotes(PeerVote* winner, uint32_t* winner_peer_id); + template + void findMajorityValue(const std::map& choices, unsigned cur_players, + T* best_choice, float* rate); void getRankingForPlayer(std::shared_ptr p); void submitRankingsToAddons(); void computeNewRankings(); From c520c441d3c481042d6f5aed91bf087b15ad92ca Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 2 Apr 2024 00:43:58 +0400 Subject: [PATCH 295/830] Don't pick first vote if vote majority is achieved but no vote coincides completely --- src/network/protocols/server_lobby.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index fd4d0ca37e3..8414b646741 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4358,9 +4358,11 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote, } if (it == m_peers_votes.end()) { + // Don't end if no vote matches all majority choices Log::warn("ServerLobby", "Missing track %s from majority.", top_track.c_str()); it = m_peers_votes.begin(); + return false; } *winner_peer_id = it->first; *winner_vote = it->second; From 31bdb52bfdde5c86bd1970476784b3fb13f51dfb Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 2 Apr 2024 01:00:32 +0400 Subject: [PATCH 296/830] Make sure handleAllVotes returns true at least once --- src/network/protocols/server_lobby.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 8414b646741..70283270d3d 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4362,13 +4362,14 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote, Log::warn("ServerLobby", "Missing track %s from majority.", top_track.c_str()); it = m_peers_votes.begin(); - return false; + if (!isVotingOver()) + return false; } *winner_peer_id = it->first; *winner_vote = it->second; return true; } - else if (isVotingOver()) + if (isVotingOver()) { // Pick the best lap (or soccer goal / time) from only the top track // if no majority agreement from all From dcfe18db882c7feacbbe5f9c92f1dd17605ab17e Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:20:24 +0400 Subject: [PATCH 297/830] Don't invoke canRace from checkPeersReady after selection has started It was invoked more than 100 times per second and even though I already have memoization it would be bad to not get rid of this --- src/network/protocols/server_lobby.cpp | 8 ++++---- src/network/protocols/server_lobby.hpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index b4d41fec490..b45be0ead93 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1825,7 +1825,7 @@ void ServerLobby::asynchronousUpdate() } if ((!ServerConfig::m_soccer_tournament && m_timeout.load() < (int64_t)StkTime::getMonoTimeMs()) || - (checkPeersReady(true/*ignore_ai_peer*/) && + (checkPeersReady(true/*ignore_ai_peer*/, true/*before_start*/) && (int)players >= ServerConfig::m_min_start_game_players)) { resetPeersReady(); @@ -6646,7 +6646,7 @@ bool ServerLobby::supportsAI() } // supportsAI //----------------------------------------------------------------------------- -bool ServerLobby::checkPeersReady(bool ignore_ai_peer) +bool ServerLobby::checkPeersReady(bool ignore_ai_peer, bool before_start) { bool all_ready = true; bool someone_races = false; @@ -6655,12 +6655,12 @@ bool ServerLobby::checkPeersReady(bool ignore_ai_peer) auto peer = p.first.lock(); if (!peer) continue; - if (!canRace(peer)) - continue; if (peer->alwaysSpectate()) continue; if (ignore_ai_peer && peer->isAIPeer()) continue; + if (before_start && !canRace(peer)) + continue; someone_races = true; all_ready = all_ready && p.second; if (!all_ready) diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index cee39850e1e..76caabb80b5 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -467,7 +467,7 @@ class ServerLobby : public LobbyProtocol void handleServerConfiguration(std::shared_ptr peer, int difficulty, int mode, bool soccer_goal_target); void updateTracksForMode(); - bool checkPeersReady(bool ignore_ai_peer); + bool checkPeersReady(bool ignore_ai_peer, bool before_start = false); void resetPeersReady() { for (auto it = m_peers_ready.begin(); it != m_peers_ready.end();) From e359adc35108668aa1d95b7c5d5067b58af93955 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 3 Apr 2024 19:03:00 +0400 Subject: [PATCH 298/830] Try to remove a compilation error and a few warnings in server_lobby.cpp --- src/network/protocols/server_lobby.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index b45be0ead93..8bbb61ad29e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1917,7 +1917,7 @@ void ServerLobby::asynchronousUpdate() std::string track_name = winner_vote.m_track_name; if (ServerConfig::m_soccer_tournament) { - if (m_tournament_game >= m_tournament_arenas.size()) + if (m_tournament_game >= (int)m_tournament_arenas.size()) m_tournament_arenas.resize(m_tournament_game + 1, ""); m_tournament_arenas[m_tournament_game] = track_name; } @@ -2138,7 +2138,8 @@ bool ServerLobby::canLiveJoinNow() const float total_distance = Track::getCurrentTrack()->getTrackLength() * (float)RaceManager::get()->getNumLaps(); - float progress = leader_distance / total_distance; + // standard version uses (leader_distance / total_distance > 0.9f) + // TODO: allow switching if (total_distance - leader_distance < 250.0) return false; } @@ -2400,7 +2401,6 @@ void ServerLobby::finishedLoadingLiveJoinClient(Event* event) live_join_start_time += 3000; bool spectator = false; - FreeForAll* ffa_world = dynamic_cast(World::getWorld()); for (const int id : peer->getAvailableKartIDs()) { const RemoteKartInfo& rki = RaceManager::get()->getKartInfo(id); @@ -2570,7 +2570,7 @@ void ServerLobby::update(int ticks) peer->getPlayerProfiles()[0]->getName()).c_str(); Log::info("ServerLobby", "%s %s has been idle on the server for " "more than %d seconds, kick.", - peer->getAddress().toString().c_str(), peer_name, sec); + peer->getAddress().toString().c_str(), peer_name.c_str(), sec); peer->kick(); } } @@ -6830,7 +6830,7 @@ void ServerLobby::storeResults() } } m_saved_ffa_points.clear(); - for (int i = 0; i < usernames.size(); ++i) + for (int i = 0; i < (int)usernames.size(); ++i) { std::string query = StringUtils::insertValues( "INSERT INTO %s " @@ -6852,7 +6852,8 @@ void ServerLobby::storeResults() #endif ); std::string name = usernames[i]; - bool written = easySQLQuery(query, [name](sqlite3_stmt* stmt) + //bool written = + easySQLQuery(query, [name](sqlite3_stmt* stmt) { if (sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) From e232bcf25c44f92cc8b9ec1ed5620af8d46a40ad Mon Sep 17 00:00:00 2001 From: ognevnydemon Date: Mon, 8 Apr 2024 16:38:39 +0300 Subject: [PATCH 299/830] improve MinGW build --- CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 25f70747117..a9ff6545629 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ if(APPLE) endif() CMAKE_DEPENDENT_OPTION(USE_CRYPTO_OPENSSL "Use OpenSSL instead of MbedTLS for cryptography in STK." ON - "NOT USE_SWITCH;NOT WIN32" OFF) + "NOT USE_SWITCH;NOT MSVC" OFF) CMAKE_DEPENDENT_OPTION(BUILD_RECORDER "Build opengl recorder" ON "NOT SERVER_ONLY;NOT APPLE;NOT USE_SWITCH" OFF) CMAKE_DEPENDENT_OPTION(USE_SYSTEM_SQUISH "Use system Squish library instead of the built-in version, when available." ON @@ -54,7 +54,7 @@ if (DLOPEN_MOLTENVK) ADD_DEFINITIONS(-DDLOPEN_MOLTENVK) endif() -if((UNIX AND NOT APPLE) OR NINTENDO_SWITCH) +if((UNIX AND NOT APPLE) OR NINTENDO_SWITCH OR MINGW) include(FindPkgConfig) endif() @@ -88,7 +88,7 @@ if (IOS) endif() if((UNIX AND NOT APPLE) AND NOT SERVER_ONLY) - if((${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") OR + if((${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "riscv64")) option(USE_GLES2 "Use OpenGL ES2 renderer" ON) @@ -199,7 +199,7 @@ if(UNIX OR MINGW) endif() endif() -if(UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS") +if((UNIX AND NOT APPLE OR MINGW) AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS") find_package(PkgConfig REQUIRED) if(NOT PKGCONFIG_FOUND) @@ -227,7 +227,7 @@ else() endif() # Find system ENet library or build it if missing -if((UNIX AND NOT APPLE) AND USE_SYSTEM_ENET AND NOT USE_IPV6) +if((UNIX AND NOT APPLE OR MINGW) AND USE_SYSTEM_ENET AND NOT USE_IPV6) pkg_check_modules(ENET libenet>=1.3.4) endif() @@ -615,7 +615,7 @@ else() else() add_executable(supertuxkart ${STK_SOURCES} ${STK_RESOURCES} ${STK_HEADERS}) endif() - if (NOT WIN32) + if (NOT MSVC) target_link_libraries(supertuxkart ${PTHREAD_LIBRARY}) endif() endif() From 581ba798b035efd958fd19a63dee5b4b758f42d0 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 9 Apr 2024 13:48:47 +0400 Subject: [PATCH 300/830] Update readme and fork changes to reflect latest commits and branches [skip ci] --- FORK_CHANGES.md | 170 ++++++++++++++++++++++++++---------------------- README.md | 42 +++++------- 2 files changed, 111 insertions(+), 101 deletions(-) diff --git a/FORK_CHANGES.md b/FORK_CHANGES.md index 043300a5e9a..cc73679df3b 100644 --- a/FORK_CHANGES.md +++ b/FORK_CHANGES.md @@ -1,76 +1,94 @@ -# This fork's changes compared to main STK - -I could forget something. - -## Major features - -* Possibility to have a proper Grand Prix server: doesn't become private after the start, players can use different karts in different races, players can join or leave, added custom scoring, in-game (short) and in-lobby (longer) standings. -* Possibility to play a Gnu Elimination. -* Soccer tournament mode: the first mode to have players colored in 3 colors, enforces rules of soccer tournament provided in config file. The number of matches, their duration, team colors, allowed arenas, tournament teams, special labels can be changed. Referees have multiple commands to control the game flow. -* Possibility to have a table of records for racing servers and notify a player if he has beaten a record. -* Possibility to record ghost replays on a server if the player agrees. -* Angry owner mode: with password available only to owner, the owner can become invulnerable to kicks and kick (or temporarily ban) annoying players even being not a crowned player. There are also some other functions like forbidding to start the game. -* Possibility to force players to have certain number of certain addons (karts, tracks, battle arenas and/or soccer fields) to enter the server. -* Possibility to send messages only to certain players. -* /teamchat: a command that makes messages to be received only by teammates in team-based gamemodes. Unlike built-in button (that appeared much later), works also in the lobby. -* Auto spectating mode (/spectate) slightly differs from the main STK and is actively used in servers on which not all players are intended to play. -* Possibility to make a server where only the crowned player can play. - -## Minor features - -* Possibility to provide information to players using /help command without making server description long. -* Possibility to force players to have certain tracks/arenas to enter the server. -* Possibility to enable (or disable) only a fixed subset of tracks/arenas on the server. -* Possibility to have a server with fixed lap count (up to 255) and/or fixed number of goals/duration of soccer game. -* Possibility to forbid certain difficulties and/or modes on a configurable server. -* Possibility to create chat-only server. -* Possibility to disable kicks on a server with crowned player. -* Possibility for players to send a message to the server owner (works like a report in the database), and for the server owner to send one-time messages to certain players. -* Possibility to store the facts of one player kicking another in a database with reports. -* Possibility to have "unfair teams" in team-based gamemodes (like 1 vs 7). -* Possibility to predefine the first several tracks played on the server. -* Possibility to allow a predefined list of players to enter anything as a password for a private server. -* Possibility to not show mobile icons near players' names. -* Possibility to get rid of own goals and replace most of them with normal goals using the principle "the scorer is the one who touched last from the scoring team". -* max-moveable-objects is changed to 30 to allow tracks like bowling to work. -* Servers try to reset to initial mode and difficulty when all players are gone (doesn't work if players quit mid-race for now). - -## Commands - -Standard STK server commands work in the same way, with the exception of `/spectate`, which toggles your autospectate state on and off, and the game does *not* start if all players want to spectate. - -* `/standings [gp|gnu]` - a command to show the standings of an ongoing Grand Prix or Gnu elimination. One can specify which standings to show in the (rare) case when there are both. -* `/gnu [kart_id]` - starts a Gnu elimination with Gnu kart (or another kart if specified). -* `/nognu` - stops a Gnu elimination. -* `/record (track_id) (time-trial|normal) (normal|reverse) (laps)` - finds the best time in the database corresponding to the specified race settings. -* `/replay (0|1)` - tells the server to record or to not record a ghost replay. -* `/to [player] [...] [player]` - forces the server to send your messages only to specified players. A lock emoji is displayed in case the message is not sent to everyone. -* `/public` - erases `/to` limitations. -* `/teamchat` - forces the server to send your messages only to your teammates in soccer and CTF modes. Note that there is an official GUI alternative, but it works only in-game. `/teamchat` also works in lobby, but doesn't work with splitscreen multiplayer. You can use any combination of two teamchats at any moment. -* `/start` - has the same effect as pressing the green ready button. -* `/config (parameters)` - set the server difficulty and/or mode to a specified value. It is equivalent to choosing from a GUI menu. -* `/commands` - lists some of available commands. -* `/tell (info)` - sends a report to a server. -* `/version` - displays the version. It is set manually in the code for now, and server owners can change it at their own decision. If you change the version, we recommend to make sure the version is informative enough to compare different servers. -* `/register (info)` - allows to register for an event, the information is stored as a report in a specified table in a database. - - -## Soccer tournament referee commands -* `/role (player) (role_id)`, `/role (player) (role_id)` - sets a role to a player, where `role_id` is one of characters in `RrBbJjSs`. -* `/game [number [duration]]` - starts the next (or specified) game with the default (or specified) duration (in minutes or goals, depending on the tournament format). -* `/stop` - stops the goal count during the game. -* `/go | /resume | /continue` - resumes the goal count of game. -* `/lobby` - stops the game fully, forcing all players to move to the lobby. -* `/init (red_goals) (blue_goals)` - sets the initial goal count of the game to a specific value (during the game). Players will see it at the bottom of the screen. - -Referees can also use all server admin commands and crowned player commands (`/kick`, etc.). - -## Server admin commands - -* `/power (password)` - switches the admin to invulnerable mode, in which no one can kick the admin, but the admin can kick anyone regardless of who is the crowned player (if any), and invoke additional commands. -* `/admin (command)` - can only be invoked in invulnerable mode. -* `/admin start (0|1)` - allows or forbids to start the game. Can be useful for scheduled events, or to prevent players from starting too fast. -* `/kickban [player]`, `/ban [player]` - temporarily bans a player (it is reset upon server restart). The first version also kicks the player from the server, and thus can be used only when that player is on the server. -* `/unban [player]` - removes temporary ban from a player. Note that database-stored bans are not affected by `/ban`, `/kickban`, and `/unban` commands. - -Invulnerable mode also allows invoking server owner commands. +This page lists the major changes of this repository compared to standard STK code, as of April 2024. Most changes (sadly, not all of them) here are implemented as options, that is, you can disable them and return to standard behaviour. + +You can find more information such as explanations and minor details in [wiki](https://github.com/kimden/stk-code/wiki/). It will be probably filled with even more data in the future. + +## Improved Grand Prix mode + +* Server doesn't become private +* Players can pick karts, join or leave +* Custom scoring systems +* Custom teams (up to 9) +* Standings ingame (short) and in the lobby (longer) +* Anti-troll and team hit punishment systems, by Heuchi1 +* Allows to shuffle the starting grid every race + +## Records, replays and stats + +* Game results for racing and battle modes can be saved to the database, together with game settings and kart statistics +* Public or private record tables can be created using that information +* Ghost replays can be recorded on servers if players agree +* Players who beat server records can be notified (includes separation of times set with different config files) +* Maximum replay size is increased + +## Chat + +* Private chat with an arbitrary set of players +* Teamchat during CTF and soccer which works both ingame and in the lobby +* Messages are never logged, even by the bots (though they pass through the server code) + +## Game configuration, available maps and karts, playing restrictions + +* Game length can be set to a fixed value, or to a certain multiple of default lap number, or to be chosen ingame +* Game direction can be set to forward or reverse, or to be chosen ingame +* For karts and maps, the next game can be customized so that the set of karts/maps available for choice is fixed, or defined by a certain algorithm (including "you have to play this track", "select from $N$ random maps from this set", "you can choose either Adiumy, or whatever is given to you by random of Suzanne and Konqi") +* The same is true for any number of next games, and the server can be set to repeat the customization every number of games + +All of the above settings can be changed arbitrarily when the server already runs, or in the config before the server starts. + +* Servers can be started with other powerup.xml or kart_characteristics.xml files being specified +* It's possible for a server to force certain maps for players to join the server or to join the game, or vice versa, disable certain maps (or all but a certain set of maps). There are various commands to find out which addons you (or other players) have or don't have, to make it easy to deal with the above +* The default setting of number of playable slots (playable places on the server) can be changed with a command +* If the player is unable to play due to imposed restrictions (lacking maps, being out of playable slots), that player doesn't affect the set of available maps, and is given the hourglass icon. + +## Command manager + +Command manager is an entity made to manipulate all existing server commands easier. It supports: + +* commands with voting +* text commands / commands reading external files +* auth commands +* setting permissions for commands without recompiling the code and/or depending on server +* subcommands and different permissions for them +* fixing errors in arguments (usernames, map names) +* showing available commands depending on permissions +* documentation for all commands via `/help` +* huge number of new commands + +All the commands and their descriptions are available in `data/commands.xml`. This file is also used to generate output for `/commands` and `/help`. + +## Moderation and permissions + +* It's possible to disable kicks attempted by the crowned player +* If a player kicks another player, the fact of the kick can be stored in the database table with reports +* Inactive players can be kicked automatically from the lobby too, not only from the game +* A hammer mode is added: players having a password can get a hammer, then they can change server settings and kick players +* There are commands to ban (or unban) a player temporary from a single server by username, as opposed to standard bans which are applied to all servers using the same database, and are usually banning by online id or IP address +* Players are allowed to report something to server owner without reporting other people +* Starting the game can be allowed or forbidden using a command + +## Game modes and their improvements + +These are not implemented as separate modes, but are rather additions to functionality of existing modes: + +* **Soccer tournament** mode: for hosting matches of several soccer games. The rules, the number of games and their duration, allowed arenas, tournament teams can be loaded from a config file. Referees have multiple commands to control the game flow +* **Gnu Elimination** mode: every race, the last (or quitting) non-eliminated player gets eliminated, and eliminated players use the same kart chosen in advance. The last standing player wins + +Separate changes for modes: + +* Soccer games produce a log of all goals / actions that happened (originally made for tournament mode, but can be used without it too), if the score is edited using tournament commands, the game shows it as a message after each goal and at the end +* FFA and CTF scores are preserved per username during the game, so that leaving the game is not punished + +## Other features + +* You can allow only the crowned player to play (speedrun server), or no one at all (chat server) +* Minor `/spectate` changes (you can invoke it ingame, game doesn't start with everyone spectating) +* For a configurable server, you can specify which exact difficulties and modes are allowed +* Players can send a message to the server owner (without reporting anyone else), and the server owner can send one-time messages to specific players +* For private servers, players can be whitelisted so that they can enter any password to join +* Different strategies to determine who scored a goal (allowing or forbidding own goals) +* `max-moveable-objects` is changed to 30 to allow tracks like `addon_bowling` to work +* Server can be customized to reset or preserve many settings like game mode, game length, ..., when everyone leaves it +* Server git version and whether it's modified is shown in `/version` +* Server console allows sending arbitrary messages to players +* Supported player categories aka sets of players (for now only displaying their names, and some minor usage) +* Minor additions in StringUtils used in typo fixing and string parsing \ No newline at end of file diff --git a/README.md b/README.md index 2b4363fdf9d..d8d4e84b4c0 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,38 @@ -# SuperTuxKart [![Linux build status](https://github.com/kimden/stk-code/actions/workflows/linux.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/linux.yml) [![Apple build status](https://github.com/kimden/stk-code/actions/workflows/apple.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/apple.yml) [![Windows build status](https://github.com/kimden/stk-code/actions/workflows/windows.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/windows.yml) [![Switch build status](https://github.com/kimden/stk-code/actions/workflows/switch.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/switch.yml) -[![#supertuxkart on the libera IRC network](https://img.shields.io/badge/libera-%23supertuxkart-brightgreen.svg)](https://web.libera.chat/?channels=#supertuxkart) -SuperTuxKart is a free kart racing game. It focuses on fun and not on realistic kart physics. Instructions can be found on the in-game help page. +This repository contains a **modified** version of SuperTuxKart (STK), mainly intended for server-side usage. Most important changes are listed [here](/FORK_CHANGES.md). Standard version of STK can be found [here](https://github.com/supertuxkart/stk-code/), and the changes between it and latest commits of this repo can be found [here](https://github.com/supertuxkart/stk-code/compare/master...kimden:stk-code:command-manager-prototype). -The SuperTuxKart homepage can be found at . There is also our [FAQ](https://supertuxkart.net/FAQ) and information on how get in touch with the [community](https://supertuxkart.net/Community). +## Important branches -Latest release binaries can be found [here](https://github.com/supertuxkart/stk-code/releases/latest), and preview release [here](https://github.com/supertuxkart/stk-code/releases/preview). +* [master](https://github.com/kimden/stk-code/): contains an old but stable version, which cannot be suddenly broken by recent commits (as almost all of them are currently in `command-manager-prototype` branch). -**You are viewing a modified version of STK**, most important changes are listed [here](/FORK_CHANGES.md). +* [command-manager-prototype](https://github.com/kimden/stk-code/tree/command-manager-prototype): contains all the latest commits, starting from introduction of command manager. As there are too many commits already, it will be merged into `master` branch soon, but not before the long-term database structure and similar important things are defined. -## Hardware Requirements -To run SuperTuxKart, make sure that your computer's specifications are equal or higher than the following specifications: +* [command-manager-2x](https://github.com/kimden/stk-code/tree/command-manager-2x): the branch combining `command-manager-prototype` and [BalanceSTK2](https://github.com/Alayan-stk-2/stk-code/tree/BalanceSTK2), which is currently the source code of 2.X development version. This branch might not have the latest commits, its purpose is to store game results while testing 2.X version. -* A graphics card capable of 3D rendering - NVIDIA GeForce 470 GTX, AMD Radeon 6870 HD series card or Intel HD Graphics 4000 and newer. OpenGL >= 3.3 -* You should have a dual-core CPU that's running at 1 GHz or faster. -* You'll need at least 512 MB of free VRAM (video memory). -* System memory: 1 GB -* Minimum disk space: 700 MB -* Ideally, you'll want a joystick with at least 6 buttons. +* [local-client](https://github.com/kimden/stk-code/tree/local-client): the version of client with some optimizations and edits, used by kimden. For now, this is the only branch of this repo that is really intended for client-side usage. -## License -The software is released under the GNU General Public License (GPL) which can be found in the file [`COPYING`](/COPYING) in the same directory as this file. +There are also several less important branches. --- -## 3D coordinates -A reminder for those who are looking at the code and 3D models: +The software is released under the GNU General Public License (GPL) which can be found in the file [`COPYING`](/COPYING) in the same directory as this file. + +Building instructions can be found in [`INSTALL.md`](/INSTALL.md). -SuperTuxKart: X right, Y up, Z forwards +Info on experimental anti-troll system can be found in [`ANTI_TROLL.md`](/ANTI_TROLL.md). -Blender: X right, Y forwards, Z up +--- -The export utilities perform the needed transformation, so in Blender you just work with the XY plane as ground, and things will appear fine in STK (using XZ as ground in the code, obviously). +## About SuperTuxKart -## Building from source +[![#supertuxkart on the libera IRC network](https://img.shields.io/badge/libera-%23supertuxkart-brightgreen.svg)](https://web.libera.chat/?channels=#supertuxkart) -Building instructions can be found in [`INSTALL.md`](/INSTALL.md). +SuperTuxKart is a free kart racing game. It focuses on fun and not on realistic kart physics. Instructions can be found on the in-game help page. -## Additional guides +The SuperTuxKart homepage can be found at . There is also our [FAQ](https://supertuxkart.net/FAQ) and information on how get in touch with the [community](https://supertuxkart.net/Community). -Info on experimental anti-troll system can be found in [`ANTI_TROLL.md`](/ANTI_TROLL.md). \ No newline at end of file +Latest release binaries can be found [here](https://github.com/supertuxkart/stk-code/releases/latest), and preview release [here](https://github.com/supertuxkart/stk-code/releases/preview). From f2f1f79209a6c20c1dd6ce3b0b9470b3568c5c76 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 9 Apr 2024 13:52:06 +0400 Subject: [PATCH 301/830] Update readme and fork changes to reflect latest commits and branches [skip ci] --- FORK_CHANGES.md | 170 ++++++++++++++++++++++++++---------------------- README.md | 42 +++++------- 2 files changed, 111 insertions(+), 101 deletions(-) diff --git a/FORK_CHANGES.md b/FORK_CHANGES.md index 043300a5e9a..cc73679df3b 100644 --- a/FORK_CHANGES.md +++ b/FORK_CHANGES.md @@ -1,76 +1,94 @@ -# This fork's changes compared to main STK - -I could forget something. - -## Major features - -* Possibility to have a proper Grand Prix server: doesn't become private after the start, players can use different karts in different races, players can join or leave, added custom scoring, in-game (short) and in-lobby (longer) standings. -* Possibility to play a Gnu Elimination. -* Soccer tournament mode: the first mode to have players colored in 3 colors, enforces rules of soccer tournament provided in config file. The number of matches, their duration, team colors, allowed arenas, tournament teams, special labels can be changed. Referees have multiple commands to control the game flow. -* Possibility to have a table of records for racing servers and notify a player if he has beaten a record. -* Possibility to record ghost replays on a server if the player agrees. -* Angry owner mode: with password available only to owner, the owner can become invulnerable to kicks and kick (or temporarily ban) annoying players even being not a crowned player. There are also some other functions like forbidding to start the game. -* Possibility to force players to have certain number of certain addons (karts, tracks, battle arenas and/or soccer fields) to enter the server. -* Possibility to send messages only to certain players. -* /teamchat: a command that makes messages to be received only by teammates in team-based gamemodes. Unlike built-in button (that appeared much later), works also in the lobby. -* Auto spectating mode (/spectate) slightly differs from the main STK and is actively used in servers on which not all players are intended to play. -* Possibility to make a server where only the crowned player can play. - -## Minor features - -* Possibility to provide information to players using /help command without making server description long. -* Possibility to force players to have certain tracks/arenas to enter the server. -* Possibility to enable (or disable) only a fixed subset of tracks/arenas on the server. -* Possibility to have a server with fixed lap count (up to 255) and/or fixed number of goals/duration of soccer game. -* Possibility to forbid certain difficulties and/or modes on a configurable server. -* Possibility to create chat-only server. -* Possibility to disable kicks on a server with crowned player. -* Possibility for players to send a message to the server owner (works like a report in the database), and for the server owner to send one-time messages to certain players. -* Possibility to store the facts of one player kicking another in a database with reports. -* Possibility to have "unfair teams" in team-based gamemodes (like 1 vs 7). -* Possibility to predefine the first several tracks played on the server. -* Possibility to allow a predefined list of players to enter anything as a password for a private server. -* Possibility to not show mobile icons near players' names. -* Possibility to get rid of own goals and replace most of them with normal goals using the principle "the scorer is the one who touched last from the scoring team". -* max-moveable-objects is changed to 30 to allow tracks like bowling to work. -* Servers try to reset to initial mode and difficulty when all players are gone (doesn't work if players quit mid-race for now). - -## Commands - -Standard STK server commands work in the same way, with the exception of `/spectate`, which toggles your autospectate state on and off, and the game does *not* start if all players want to spectate. - -* `/standings [gp|gnu]` - a command to show the standings of an ongoing Grand Prix or Gnu elimination. One can specify which standings to show in the (rare) case when there are both. -* `/gnu [kart_id]` - starts a Gnu elimination with Gnu kart (or another kart if specified). -* `/nognu` - stops a Gnu elimination. -* `/record (track_id) (time-trial|normal) (normal|reverse) (laps)` - finds the best time in the database corresponding to the specified race settings. -* `/replay (0|1)` - tells the server to record or to not record a ghost replay. -* `/to [player] [...] [player]` - forces the server to send your messages only to specified players. A lock emoji is displayed in case the message is not sent to everyone. -* `/public` - erases `/to` limitations. -* `/teamchat` - forces the server to send your messages only to your teammates in soccer and CTF modes. Note that there is an official GUI alternative, but it works only in-game. `/teamchat` also works in lobby, but doesn't work with splitscreen multiplayer. You can use any combination of two teamchats at any moment. -* `/start` - has the same effect as pressing the green ready button. -* `/config (parameters)` - set the server difficulty and/or mode to a specified value. It is equivalent to choosing from a GUI menu. -* `/commands` - lists some of available commands. -* `/tell (info)` - sends a report to a server. -* `/version` - displays the version. It is set manually in the code for now, and server owners can change it at their own decision. If you change the version, we recommend to make sure the version is informative enough to compare different servers. -* `/register (info)` - allows to register for an event, the information is stored as a report in a specified table in a database. - - -## Soccer tournament referee commands -* `/role (player) (role_id)`, `/role (player) (role_id)` - sets a role to a player, where `role_id` is one of characters in `RrBbJjSs`. -* `/game [number [duration]]` - starts the next (or specified) game with the default (or specified) duration (in minutes or goals, depending on the tournament format). -* `/stop` - stops the goal count during the game. -* `/go | /resume | /continue` - resumes the goal count of game. -* `/lobby` - stops the game fully, forcing all players to move to the lobby. -* `/init (red_goals) (blue_goals)` - sets the initial goal count of the game to a specific value (during the game). Players will see it at the bottom of the screen. - -Referees can also use all server admin commands and crowned player commands (`/kick`, etc.). - -## Server admin commands - -* `/power (password)` - switches the admin to invulnerable mode, in which no one can kick the admin, but the admin can kick anyone regardless of who is the crowned player (if any), and invoke additional commands. -* `/admin (command)` - can only be invoked in invulnerable mode. -* `/admin start (0|1)` - allows or forbids to start the game. Can be useful for scheduled events, or to prevent players from starting too fast. -* `/kickban [player]`, `/ban [player]` - temporarily bans a player (it is reset upon server restart). The first version also kicks the player from the server, and thus can be used only when that player is on the server. -* `/unban [player]` - removes temporary ban from a player. Note that database-stored bans are not affected by `/ban`, `/kickban`, and `/unban` commands. - -Invulnerable mode also allows invoking server owner commands. +This page lists the major changes of this repository compared to standard STK code, as of April 2024. Most changes (sadly, not all of them) here are implemented as options, that is, you can disable them and return to standard behaviour. + +You can find more information such as explanations and minor details in [wiki](https://github.com/kimden/stk-code/wiki/). It will be probably filled with even more data in the future. + +## Improved Grand Prix mode + +* Server doesn't become private +* Players can pick karts, join or leave +* Custom scoring systems +* Custom teams (up to 9) +* Standings ingame (short) and in the lobby (longer) +* Anti-troll and team hit punishment systems, by Heuchi1 +* Allows to shuffle the starting grid every race + +## Records, replays and stats + +* Game results for racing and battle modes can be saved to the database, together with game settings and kart statistics +* Public or private record tables can be created using that information +* Ghost replays can be recorded on servers if players agree +* Players who beat server records can be notified (includes separation of times set with different config files) +* Maximum replay size is increased + +## Chat + +* Private chat with an arbitrary set of players +* Teamchat during CTF and soccer which works both ingame and in the lobby +* Messages are never logged, even by the bots (though they pass through the server code) + +## Game configuration, available maps and karts, playing restrictions + +* Game length can be set to a fixed value, or to a certain multiple of default lap number, or to be chosen ingame +* Game direction can be set to forward or reverse, or to be chosen ingame +* For karts and maps, the next game can be customized so that the set of karts/maps available for choice is fixed, or defined by a certain algorithm (including "you have to play this track", "select from $N$ random maps from this set", "you can choose either Adiumy, or whatever is given to you by random of Suzanne and Konqi") +* The same is true for any number of next games, and the server can be set to repeat the customization every number of games + +All of the above settings can be changed arbitrarily when the server already runs, or in the config before the server starts. + +* Servers can be started with other powerup.xml or kart_characteristics.xml files being specified +* It's possible for a server to force certain maps for players to join the server or to join the game, or vice versa, disable certain maps (or all but a certain set of maps). There are various commands to find out which addons you (or other players) have or don't have, to make it easy to deal with the above +* The default setting of number of playable slots (playable places on the server) can be changed with a command +* If the player is unable to play due to imposed restrictions (lacking maps, being out of playable slots), that player doesn't affect the set of available maps, and is given the hourglass icon. + +## Command manager + +Command manager is an entity made to manipulate all existing server commands easier. It supports: + +* commands with voting +* text commands / commands reading external files +* auth commands +* setting permissions for commands without recompiling the code and/or depending on server +* subcommands and different permissions for them +* fixing errors in arguments (usernames, map names) +* showing available commands depending on permissions +* documentation for all commands via `/help` +* huge number of new commands + +All the commands and their descriptions are available in `data/commands.xml`. This file is also used to generate output for `/commands` and `/help`. + +## Moderation and permissions + +* It's possible to disable kicks attempted by the crowned player +* If a player kicks another player, the fact of the kick can be stored in the database table with reports +* Inactive players can be kicked automatically from the lobby too, not only from the game +* A hammer mode is added: players having a password can get a hammer, then they can change server settings and kick players +* There are commands to ban (or unban) a player temporary from a single server by username, as opposed to standard bans which are applied to all servers using the same database, and are usually banning by online id or IP address +* Players are allowed to report something to server owner without reporting other people +* Starting the game can be allowed or forbidden using a command + +## Game modes and their improvements + +These are not implemented as separate modes, but are rather additions to functionality of existing modes: + +* **Soccer tournament** mode: for hosting matches of several soccer games. The rules, the number of games and their duration, allowed arenas, tournament teams can be loaded from a config file. Referees have multiple commands to control the game flow +* **Gnu Elimination** mode: every race, the last (or quitting) non-eliminated player gets eliminated, and eliminated players use the same kart chosen in advance. The last standing player wins + +Separate changes for modes: + +* Soccer games produce a log of all goals / actions that happened (originally made for tournament mode, but can be used without it too), if the score is edited using tournament commands, the game shows it as a message after each goal and at the end +* FFA and CTF scores are preserved per username during the game, so that leaving the game is not punished + +## Other features + +* You can allow only the crowned player to play (speedrun server), or no one at all (chat server) +* Minor `/spectate` changes (you can invoke it ingame, game doesn't start with everyone spectating) +* For a configurable server, you can specify which exact difficulties and modes are allowed +* Players can send a message to the server owner (without reporting anyone else), and the server owner can send one-time messages to specific players +* For private servers, players can be whitelisted so that they can enter any password to join +* Different strategies to determine who scored a goal (allowing or forbidding own goals) +* `max-moveable-objects` is changed to 30 to allow tracks like `addon_bowling` to work +* Server can be customized to reset or preserve many settings like game mode, game length, ..., when everyone leaves it +* Server git version and whether it's modified is shown in `/version` +* Server console allows sending arbitrary messages to players +* Supported player categories aka sets of players (for now only displaying their names, and some minor usage) +* Minor additions in StringUtils used in typo fixing and string parsing \ No newline at end of file diff --git a/README.md b/README.md index 2b4363fdf9d..d8d4e84b4c0 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,38 @@ -# SuperTuxKart [![Linux build status](https://github.com/kimden/stk-code/actions/workflows/linux.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/linux.yml) [![Apple build status](https://github.com/kimden/stk-code/actions/workflows/apple.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/apple.yml) [![Windows build status](https://github.com/kimden/stk-code/actions/workflows/windows.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/windows.yml) [![Switch build status](https://github.com/kimden/stk-code/actions/workflows/switch.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/switch.yml) -[![#supertuxkart on the libera IRC network](https://img.shields.io/badge/libera-%23supertuxkart-brightgreen.svg)](https://web.libera.chat/?channels=#supertuxkart) -SuperTuxKart is a free kart racing game. It focuses on fun and not on realistic kart physics. Instructions can be found on the in-game help page. +This repository contains a **modified** version of SuperTuxKart (STK), mainly intended for server-side usage. Most important changes are listed [here](/FORK_CHANGES.md). Standard version of STK can be found [here](https://github.com/supertuxkart/stk-code/), and the changes between it and latest commits of this repo can be found [here](https://github.com/supertuxkart/stk-code/compare/master...kimden:stk-code:command-manager-prototype). -The SuperTuxKart homepage can be found at . There is also our [FAQ](https://supertuxkart.net/FAQ) and information on how get in touch with the [community](https://supertuxkart.net/Community). +## Important branches -Latest release binaries can be found [here](https://github.com/supertuxkart/stk-code/releases/latest), and preview release [here](https://github.com/supertuxkart/stk-code/releases/preview). +* [master](https://github.com/kimden/stk-code/): contains an old but stable version, which cannot be suddenly broken by recent commits (as almost all of them are currently in `command-manager-prototype` branch). -**You are viewing a modified version of STK**, most important changes are listed [here](/FORK_CHANGES.md). +* [command-manager-prototype](https://github.com/kimden/stk-code/tree/command-manager-prototype): contains all the latest commits, starting from introduction of command manager. As there are too many commits already, it will be merged into `master` branch soon, but not before the long-term database structure and similar important things are defined. -## Hardware Requirements -To run SuperTuxKart, make sure that your computer's specifications are equal or higher than the following specifications: +* [command-manager-2x](https://github.com/kimden/stk-code/tree/command-manager-2x): the branch combining `command-manager-prototype` and [BalanceSTK2](https://github.com/Alayan-stk-2/stk-code/tree/BalanceSTK2), which is currently the source code of 2.X development version. This branch might not have the latest commits, its purpose is to store game results while testing 2.X version. -* A graphics card capable of 3D rendering - NVIDIA GeForce 470 GTX, AMD Radeon 6870 HD series card or Intel HD Graphics 4000 and newer. OpenGL >= 3.3 -* You should have a dual-core CPU that's running at 1 GHz or faster. -* You'll need at least 512 MB of free VRAM (video memory). -* System memory: 1 GB -* Minimum disk space: 700 MB -* Ideally, you'll want a joystick with at least 6 buttons. +* [local-client](https://github.com/kimden/stk-code/tree/local-client): the version of client with some optimizations and edits, used by kimden. For now, this is the only branch of this repo that is really intended for client-side usage. -## License -The software is released under the GNU General Public License (GPL) which can be found in the file [`COPYING`](/COPYING) in the same directory as this file. +There are also several less important branches. --- -## 3D coordinates -A reminder for those who are looking at the code and 3D models: +The software is released under the GNU General Public License (GPL) which can be found in the file [`COPYING`](/COPYING) in the same directory as this file. + +Building instructions can be found in [`INSTALL.md`](/INSTALL.md). -SuperTuxKart: X right, Y up, Z forwards +Info on experimental anti-troll system can be found in [`ANTI_TROLL.md`](/ANTI_TROLL.md). -Blender: X right, Y forwards, Z up +--- -The export utilities perform the needed transformation, so in Blender you just work with the XY plane as ground, and things will appear fine in STK (using XZ as ground in the code, obviously). +## About SuperTuxKart -## Building from source +[![#supertuxkart on the libera IRC network](https://img.shields.io/badge/libera-%23supertuxkart-brightgreen.svg)](https://web.libera.chat/?channels=#supertuxkart) -Building instructions can be found in [`INSTALL.md`](/INSTALL.md). +SuperTuxKart is a free kart racing game. It focuses on fun and not on realistic kart physics. Instructions can be found on the in-game help page. -## Additional guides +The SuperTuxKart homepage can be found at . There is also our [FAQ](https://supertuxkart.net/FAQ) and information on how get in touch with the [community](https://supertuxkart.net/Community). -Info on experimental anti-troll system can be found in [`ANTI_TROLL.md`](/ANTI_TROLL.md). \ No newline at end of file +Latest release binaries can be found [here](https://github.com/supertuxkart/stk-code/releases/latest), and preview release [here](https://github.com/supertuxkart/stk-code/releases/preview). From 6cf094ab78bb96705a4e11e392e6e06df8622bfe Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 15 Apr 2024 01:48:58 +0200 Subject: [PATCH 302/830] Add new setting values for increased view distances Add 3 new setting values, increasing the distance at which a lower level of detail is used by factors of 1.6, 2.0 and 3.0 (default is 1.25). This allows players for which getting enough FPS is not an issue to reduce pop-in and improve the looks of tracks. In local testing with a strong CPU and a weak GPU, the performance impact of increasing the view distances is small and well worth it, but this may vary from system to system. More testing is needed on different systems, but this suggests room to increase minimum, default and maximum values in future releases. This patch also slightly changes the auto-computation of LoD distance, making the transition around a distance of 250 smoother. --- data/gui/dialogs/custom_video_settings.stkgui | 2 +- src/graphics/lod_node.cpp | 26 ++++++++++++------- .../dialogs/custom_video_settings.cpp | 19 +++++++++++--- src/tracks/track.cpp | 3 ++- 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/data/gui/dialogs/custom_video_settings.stkgui b/data/gui/dialogs/custom_video_settings.stkgui index 7986d810934..5c58c100808 100644 --- a/data/gui/dialogs/custom_video_settings.stkgui +++ b/data/gui/dialogs/custom_video_settings.stkgui @@ -164,7 +164,7 @@
diff --git a/src/graphics/lod_node.cpp b/src/graphics/lod_node.cpp index ac9ce2fa5d7..7bf1b767245 100644 --- a/src/graphics/lod_node.cpp +++ b/src/graphics/lod_node.cpp @@ -194,25 +194,33 @@ void LODNode::OnRegisterSceneNode() scene::ISceneNode::OnRegisterSceneNode(); } - +/* Each model with LoD has specific distances beyond which it is rendered at a lower +* detail level. This function compute the distances associated with the various +* LoD levels for a given model. +* @param scale The model's scale*/ void LODNode::autoComputeLevel(float scale) { m_area *= scale; // Amount of details based on user's input float agressivity = 1.0; - if(UserConfigParams::m_geometry_level == 0) agressivity = 1.25; - if(UserConfigParams::m_geometry_level == 1) agressivity = 1.0; - if(UserConfigParams::m_geometry_level == 2) agressivity = 0.75; + if( UserConfigParams::m_geometry_level == 0) agressivity = 1.25; + else if(UserConfigParams::m_geometry_level == 1) agressivity = 1.0; + else if(UserConfigParams::m_geometry_level == 2) agressivity = 0.75; + else if(UserConfigParams::m_geometry_level == 3) agressivity = 1.6; + else if(UserConfigParams::m_geometry_level == 4) agressivity = 2.0; + else if(UserConfigParams::m_geometry_level == 5) agressivity = 3.0; // First we try to estimate how far away we need to draw - float max_draw = 0.0; - max_draw = sqrtf((0.5 * m_area + 10) * 200) - 10; + // This first formula is equivalent to the one used up to STK 1.4 + float max_draw = 10*(sqrtf(m_area + 20) - 1); // If the draw distance is too big we artificially reduce it + // The formulas are still experimental and improvable. if(max_draw > 250) - { - max_draw = 250 + (max_draw * 0.06); - } + max_draw = 230 + (max_draw * 0.08); + // This effecte is cumulative + if (max_draw > 500) + max_draw = 200 + (max_draw * 0.6); max_draw *= agressivity; diff --git a/src/states_screens/dialogs/custom_video_settings.cpp b/src/states_screens/dialogs/custom_video_settings.cpp index 1b8add4c0e9..e2bd8815a36 100644 --- a/src/states_screens/dialogs/custom_video_settings.cpp +++ b/src/states_screens/dialogs/custom_video_settings.cpp @@ -76,11 +76,21 @@ void CustomVideoSettingsDialog::beforeAddingWidgets() geometry_level->addLabel(_("Very Low")); //I18N: Geometry level low : few details are displayed geometry_level->addLabel(_("Low")); - //I18N: Geometry level high : everything is displayed + //I18N: Geometry level medium : everything is displayed, Level-of-Details distances are medium + geometry_level->addLabel(_("Medium")); + //I18N: Geometry level high : everything is displayed, Level-of-Details distances are high geometry_level->addLabel(_("High")); + //I18N: Geometry level very high : everything is displayed, Level-of-Details distances are very high + geometry_level->addLabel(_("Very High")); + //I18N: Geometry level ultra : everything is displayed, Level-of-Details distances are extremely high + geometry_level->addLabel(_("Ultra")); + // This strange code is needed because a lower geometry level value + // used to be better. The values are now from best to worst: 5, 4, 3, 0, 1, 2. + // This keeps compatibility with 1.X installs. + // FIXME when profile-compatibility is not a concern. geometry_level->setValue( UserConfigParams::m_geometry_level == 2 ? 0 : - UserConfigParams::m_geometry_level == 0 ? 2 : 1); + UserConfigParams::m_geometry_level == 0 ? 2 : UserConfigParams::m_geometry_level); SpinnerWidget* filtering = getWidget("image_quality"); filtering->addLabel(_("Very Low")); @@ -188,7 +198,10 @@ GUIEngine::EventPropagation CustomVideoSettingsDialog::processEvent(const std::s const int val = getWidget("geometry_detail")->getValue(); - UserConfigParams::m_geometry_level = val == 2 ? 0 : val == 0 ? 2 : 1; + // This strange code is needed because a lower geometry level value + // used to be better. This keeps compatibility with 1.X installs. + UserConfigParams::m_geometry_level = val == 2 ? 0 : + val == 0 ? 2 : val; int quality = getWidget("image_quality")->getValue(); user_config->saveConfig(); diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 750f278dca0..1a7c78a556e 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -2357,7 +2357,8 @@ void Track::loadObjects(const XMLNode* root, const std::string& path, { int geo_level = 0; node->get("geometry-level", &geo_level); - if (UserConfigParams::m_geometry_level + geo_level - 2 > 0 && + if (UserConfigParams::m_geometry_level <= 2 && + UserConfigParams::m_geometry_level + geo_level - 2 > 0 && !NetworkConfig::get()->isNetworking()) continue; m_track_object_manager->add(*node, parent, model_def_loader, parent_library); From 8577408cec947baeafe3e114f07e482e3ad50da3 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 15 Apr 2024 22:30:08 +0800 Subject: [PATCH 303/830] LOD improvements (#5038) * Quick cull invisible LOD nodes * Reduce dynamic cast * Fix for Vulkan Maintainer's comment: Helps only in select tracks and more in already fast frames than in the more problematic slow frames, but an improvement nonetheless. --- src/graphics/draw_calls.cpp | 42 +++++++++++++++++---------- src/graphics/lod_node.cpp | 58 +++++++++++++++++++------------------ src/graphics/lod_node.hpp | 6 ++-- 3 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/graphics/draw_calls.cpp b/src/graphics/draw_calls.cpp index a642a720bbb..c8acf2f2e53 100644 --- a/src/graphics/draw_calls.cpp +++ b/src/graphics/draw_calls.cpp @@ -145,42 +145,52 @@ void DrawCalls::parseSceneManager(core::array &List, { for (unsigned i = 0; i < List.size(); ++i) { - if (LODNode *node = dynamic_cast(List[i])) - { - node->updateVisibility(); - } - List[i]->updateAbsolutePosition(); if (!List[i]->isVisible()) continue; - if (STKParticle *node = dynamic_cast(List[i])) + if (List[i]->getType() == ESNT_LOD_NODE) { + LODNode *node = static_cast(List[i]); + + core::array child; + if (node->getLevel() >= 0) + child.push_back(node->getAllNodes()[node->getLevel()]); + for (int i = 0; i < node->getChildren().size(); i++) + { + if (node->getNodesSet().find(node->getChildren()[i]) == node->getNodesSet().end()) + child.push_back(node->getChildren()[i]); + } + parseSceneManager(child, cam); + continue; + } + else if (List[i]->getType() == ESNT_ANIMATED_MESH) + { + SP::SPMeshNode* node = static_cast(List[i]); + SP::addObject(node); + } + else if (STKParticle *node = dynamic_cast(List[i])) + { + node->updateAbsolutePosition(); if (!isCulledPrecise(cam, List[i], irr_driver->getBoundingBoxesViz())) CPUParticleManager::getInstance()->addParticleNode(node); continue; } - - if (scene::IBillboardSceneNode *node = + else if (scene::IBillboardSceneNode *node = dynamic_cast(List[i])) { + node->updateAbsolutePosition(); if (!isCulledPrecise(cam, List[i])) CPUParticleManager::getInstance()->addBillboardNode(node); continue; } - - if (STKTextBillboard *tb = + else if (STKTextBillboard *tb = dynamic_cast(List[i])) { + node->updateAbsolutePosition(); if (!isCulledPrecise(cam, List[i], irr_driver->getBoundingBoxesViz())) TextBillboardDrawer::addTextBillboard(tb); continue; } - - SP::SPMeshNode* node = dynamic_cast(List[i]); - if (node) - { - SP::addObject(node); - } parseSceneManager(List[i]->getChildren(), cam); } } diff --git a/src/graphics/lod_node.cpp b/src/graphics/lod_node.cpp index 7bf1b767245..997faa0fc47 100644 --- a/src/graphics/lod_node.cpp +++ b/src/graphics/lod_node.cpp @@ -49,13 +49,8 @@ LODNode::LODNode(std::string group_name, scene::ISceneNode* parent, m_forced_lod = -1; m_area = 0; -#ifndef SERVER_ONLY - if (!CVS->isGLSL()) - { - m_current_level.reset(new int); - *m_current_level = -1; - } -#endif + m_current_level = -1; + m_current_level_dirty = true; } LODNode::~LODNode() @@ -76,8 +71,12 @@ int LODNode::getLevel() return -1; // If a level is forced, use it - if(m_forced_lod>-1) + if (m_forced_lod >- 1) return m_forced_lod; + + if (!m_current_level_dirty) + return m_current_level; + m_current_level_dirty = false; Camera* camera = Camera::getActiveCamera(); if (camera == NULL) @@ -90,9 +89,12 @@ int LODNode::getLevel() for (unsigned int n=0; n 0) { // update absolute position @@ -126,9 +130,8 @@ void LODNode::OnAnimate(u32 timeMs) #endif { int level = getLevel(); - *m_current_level = level; // Assume all the scene node have the same bouding box - if(level>=0) + if(level >= 0) { m_nodes[level]->setVisible(true); m_nodes[level]->OnAnimate(timeMs); @@ -154,29 +157,22 @@ void LODNode::OnAnimate(u32 timeMs) } } -void LODNode::updateVisibility(bool* shown) +void LODNode::updateVisibility() { if (!isVisible()) return; if (m_nodes.size() == 0) return; - unsigned int level = 0; - if (m_current_level) - level = *m_current_level; - else - level = getLevel(); + m_current_level_dirty = true; + unsigned int level = getLevel(); + for (size_t i = 0; i < m_nodes.size(); i++) { m_nodes[i]->setVisible(i == level); - if (i == level && shown != NULL) - *shown = (i > 0); } } void LODNode::OnRegisterSceneNode() { - bool shown = false; - updateVisibility(&shown); - #ifndef SERVER_ONLY if (CVS->isGLSL()) { @@ -184,14 +180,20 @@ void LODNode::OnRegisterSceneNode() } #endif -#ifndef SERVER_ONLY - if (!CVS->isGLSL()) + if (isVisible() && m_nodes.size() > 0) { - for (unsigned i = 0; i < Children.size(); ++i) - Children[i]->updateAbsolutePosition(); + int level = getLevel(); + + if (level >= 0) + { + m_nodes[level]->OnRegisterSceneNode(); + } + for (int i = 0; i < Children.size(); i++) + { + if (m_nodes_set.find(Children[i]) == m_nodes_set.end()) + Children[i]->OnRegisterSceneNode(); + } } -#endif - scene::ISceneNode::OnRegisterSceneNode(); } /* Each model with LoD has specific distances beyond which it is rendered at a lower diff --git a/src/graphics/lod_node.hpp b/src/graphics/lod_node.hpp index 174a0badce6..fe52253de79 100644 --- a/src/graphics/lod_node.hpp +++ b/src/graphics/lod_node.hpp @@ -63,7 +63,8 @@ class LODNode : public scene::ISceneNode * m_forced_lod is >=0, only this level is be used. */ int m_forced_lod; - std::unique_ptr m_current_level; + int m_current_level; + bool m_current_level_dirty; // Area of the bounding box (for autoLOD computation) float m_area; @@ -79,7 +80,7 @@ class LODNode : public scene::ISceneNode int getLevel(); - void updateVisibility(bool* shown = NULL); + void updateVisibility(); /* //! Returns a reference to the current relative transformation matrix. @@ -115,6 +116,7 @@ class LODNode : public scene::ISceneNode } std::vector& getAllNodes() { return m_nodes; } + std::set& getNodesSet() { return m_nodes_set; } //! OnAnimate() is called just before rendering the whole scene. /** This method will be called once per frame, independent From 797dcff745b6d43b943c7ab5335a3b5856683572 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 15 Apr 2024 22:18:28 +0400 Subject: [PATCH 304/830] Allow to forbid playing based on fraction of official assets --- NETWORKING.md | 6 ++++++ src/network/protocols/server_lobby.cpp | 23 +++++++++++++++++++++++ src/network/server_config.hpp | 18 +++++++++++++++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/NETWORKING.md b/NETWORKING.md index e69b99d2309..03295ea099e 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -108,6 +108,12 @@ The current server configuration xml looks like this (this is only an example, j + + + + + + diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 8bbb61ad29e..2fa6f0900d3 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -7285,6 +7285,7 @@ bool ServerLobby::canRace(STKPeer* peer) for (const std::string& track: m_play_requirement_tracks) if (peer->getClientAssets().second.count(track) == 0) return m_peers_ability_to_play[peer] = false; + if (peer->addon_karts_count < ServerConfig::m_addon_karts_play_threshold) return m_peers_ability_to_play[peer] = false; if (peer->addon_tracks_count < ServerConfig::m_addon_tracks_play_threshold) @@ -7293,6 +7294,28 @@ bool ServerLobby::canRace(STKPeer* peer) return m_peers_ability_to_play[peer] = false; if (peer->addon_soccers_count < ServerConfig::m_addon_soccers_play_threshold) return m_peers_ability_to_play[peer] = false; + + float karts_fraction = 0.0f; + float maps_fraction = 0.0f; + for (auto& kart : karts) + { + if (m_official_kts.first.find(kart) != + m_official_kts.first.end()) + karts_fraction += 1.0f; + } + for (auto& map : maps) + { + if (m_official_kts.second.find(map) != + m_official_kts.second.end()) + maps_fraction += 1.0f; + } + karts_fraction /= (float)m_official_kts.first.size(); + maps_fraction /= (float)m_official_kts.second.size(); + + if (karts_fraction < ServerConfig::m_official_karts_play_threshold) + return m_peers_ability_to_play[peer] = false; + if (maps_fraction < ServerConfig::m_official_tracks_play_threshold) + return m_peers_ability_to_play[peer] = false; return m_peers_ability_to_play[peer] = true; } // canRace //----------------------------------------------------------------------------- diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 6fa4565c26f..72ccea7d517 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -229,7 +229,23 @@ namespace ServerConfig "Clients below this value will be rejected from joining this server. " "It's determined by number of official tracks in client / number of " "official tracks in server, setting this value too high will prevent " - "android players from joining this server, because STK android apk " + "android players from playing on this server, because STK android apk " + "has some official tracks removed.")); + + SERVER_CFG_PREFIX FloatServerConfigParam m_official_karts_play_threshold + SERVER_CFG_DEFAULT(FloatServerConfigParam(1.0f, + "official-karts-play-threshold", + "Clients below this value will be rejected from playing on this server. " + "It's determined by number of official karts in client / number of " + "official karts in server.")); + + SERVER_CFG_PREFIX FloatServerConfigParam m_official_tracks_play_threshold + SERVER_CFG_DEFAULT(FloatServerConfigParam(0.7f, + "official-tracks-play-threshold", + "Clients below this value will be rejected from playing on this server. " + "It's determined by number of official tracks in client / number of " + "official tracks in server, setting this value too high will prevent " + "android players from playing on this server, because STK android apk " "has some official tracks removed.")); SERVER_CFG_PREFIX IntServerConfigParam m_addon_karts_join_threshold From a6cecd2279be4fb0f26d8a556a145cd282260e86 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Tue, 16 Apr 2024 05:46:30 +0200 Subject: [PATCH 305/830] First steps for a benchmark mode * Add a button in the graphics options to start a benchmark * Added logic to play a custom replay for benchmarking * Added logic to automatically start and end the profiling as the race starts and ends, when in benchmark mode * Disable the profiler drawings in benchmark mode, they take additional resources and are useless * Keep the race going when the pause menu is opened, as it would otherwise distort the results * Added logic to clean up the profiler data each time profiling is switched back from off to on. This avoids multiple profiling sessions piling up in one report, for example when benchmarking tw * Added a sped up Black Forest replay for use during the benchmark Missing features and known issues: * The end screen should display a benchmark result summary instead of a normal end screen * Entering and leaving the pause menu in benchmark mode makes some parts of the race UI disappear * The end screen should send the player back to the graphics settings, not the main menu * Pausing and quitting can leave the profiler enabled when it should not be * The options in the pause menu should be customized in benchmark mode * The replay used for benchmarking should be configurable in a data file * Automatically testing multiple graphics settings and providing an overall summary * And more advanced options. --- data/gui/screens/options_video.stkgui | 19 + data/replay/benchmark_black_forest.replay | 1162 +++++++++++++++++ src/modes/world.cpp | 8 +- src/modes/world_status.cpp | 15 + src/race/race_manager.cpp | 1 + src/race/race_manager.hpp | 15 +- .../dialogs/race_paused_dialog.cpp | 2 +- .../options/options_screen_video.cpp | 31 + src/utils/profiler.cpp | 34 +- src/utils/profiler.hpp | 10 +- 10 files changed, 1286 insertions(+), 11 deletions(-) create mode 100644 data/replay/benchmark_black_forest.replay diff --git a/data/gui/screens/options_video.stkgui b/data/gui/screens/options_video.stkgui index 028758ba15b..252b0613a4a 100644 --- a/data/gui/screens/options_video.stkgui +++ b/data/gui/screens/options_video.stkgui @@ -124,6 +124,25 @@ I18N="In the video settings" text="Apply new resolution" /> + + + +
+ + + ``` diff --git a/data/commands.xml b/data/commands.xml index 7d68f621fc0..36eff41c66f 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -1107,6 +1107,21 @@ here later. For now, please refer to the code for the strings being used. --> permissions="UP_HAMMER" />

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ⅅ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 H-+%o-(+5aQ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 8d3f2ab2b75..c65b8841c00 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Oct 23 13:51:26 PDT 2017 +#Sun Dec 03 18:24:53 EET 2023 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip diff --git a/android/gradlew b/android/gradlew index 9d82f789151..a69d9cb6c20 100755 --- a/android/gradlew +++ b/android/gradlew @@ -1,74 +1,129 @@ -#!/usr/bin/env bash +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum -warn ( ) { +warn () { echo "$*" -} +} >&2 -die ( ) { +die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -77,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -85,76 +140,101 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/android/make.sh b/android/make.sh index 3d5b6150cc3..31c62ae79ed 100755 --- a/android/make.sh +++ b/android/make.sh @@ -20,7 +20,7 @@ if [ -z "$STK_MIN_ANDROID_SDK" ]; then fi if [ -z "$STK_TARGET_ANDROID_SDK" ]; then - export STK_TARGET_ANDROID_SDK=33 + export STK_TARGET_ANDROID_SDK=34 fi if [ -z "$STK_NDK_VERSION" ]; then diff --git a/src/utils/download_assets_size.hpp b/src/utils/download_assets_size.hpp index 44993fe0778..1c241f5bb45 100644 --- a/src/utils/download_assets_size.hpp +++ b/src/utils/download_assets_size.hpp @@ -23,7 +23,7 @@ inline unsigned getDownloadAssetsSize() { // Todo: generated from some sed script - unsigned stk_assets_size = 223869285; + unsigned stk_assets_size = 223424823; return stk_assets_size; } #endif diff --git a/tools/android_builder.sh b/tools/android_builder.sh index a2c8be65886..f7846c1701c 100755 --- a/tools/android_builder.sh +++ b/tools/android_builder.sh @@ -158,6 +158,10 @@ fi #Build packages +if [ ! -d "./android-output" ]; then + mkdir ./android-output +fi + generate_lq_assets generate_full_assets generate_assets @@ -189,9 +193,9 @@ cp ./android/build/outputs/apk/release/android-release.apk \ cp ./android/build/outputs/bundle/release/android-release.aab \ ./android-output/SuperTuxKart-$PROJECT_VERSION.aab -for arch in $(ls ./android/build/intermediates/ndkBuild/release/obj/local); do - cp ./android/build/intermediates/ndkBuild/release/obj/local/$arch/libmain.so \ +for arch in $(ls ./android/build/intermediates/merged_native_libs/release/out/lib); do + cp ./android/build/intermediates/merged_native_libs/release/out/lib/$arch/libmain.so \ ./android-output/SuperTuxKart-$PROJECT_VERSION-$arch-libmain.so - cp ./android/build/intermediates/ndkBuild/release/obj/local/$arch/libSDL2.so \ + cp ./android/build/intermediates/merged_native_libs/release/out/lib/$arch/libSDL2.so \ ./android-output/SuperTuxKart-$PROJECT_VERSION-$arch-libSDL2.so done From 78c6f16d7985b4b5c3abc4168a530b645b7c4d40 Mon Sep 17 00:00:00 2001 From: Deve Date: Thu, 18 Apr 2024 19:27:18 +0200 Subject: [PATCH 308/830] Fixed a crash when entering story mode --- src/graphics/draw_calls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/draw_calls.cpp b/src/graphics/draw_calls.cpp index 3df22699743..d89a715f80c 100644 --- a/src/graphics/draw_calls.cpp +++ b/src/graphics/draw_calls.cpp @@ -187,7 +187,7 @@ void DrawCalls::parseSceneManager(core::array &List, else if (STKTextBillboard *tb = dynamic_cast(List[i])) { - node->updateAbsolutePosition(); + tb->updateAbsolutePosition(); if (!isCulledPrecise(cam, List[i], irr_driver->getBoundingBoxesViz())) TextBillboardDrawer::addTextBillboard(tb); continue; From 2f87966ff6651e00b6ba7624a39f53d2e4748cb1 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Fri, 19 Apr 2024 13:18:31 +0800 Subject: [PATCH 309/830] Add basic code for widget and screen resize --- .../abstract_top_level_container.cpp | 19 +++++++++++++++++++ .../abstract_top_level_container.hpp | 1 + src/guiengine/engine.cpp | 2 ++ src/guiengine/engine.hpp | 1 + src/guiengine/screen.cpp | 11 +++++++++++ src/guiengine/screen.hpp | 5 +++++ src/guiengine/widget.cpp | 14 ++++++++++---- src/guiengine/widget.hpp | 7 ++++++- 8 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/guiengine/abstract_top_level_container.cpp b/src/guiengine/abstract_top_level_container.cpp index cd504059fcf..72d8d3852f0 100644 --- a/src/guiengine/abstract_top_level_container.cpp +++ b/src/guiengine/abstract_top_level_container.cpp @@ -91,6 +91,25 @@ void AbstractTopLevelContainer::addWidgetsRecursively( } // addWidgetsRecursively +// ---------------------------------------------------------------------------- +/** This function invokes resize() of each widgets and its children. + * \param widgets The vector of widgets to resize + * \param parent The parent widget of the vector of widgets */ +void AbstractTopLevelContainer::resizeWidgetsRecursively(PtrVector& widgets) +{ + const unsigned short widgets_amount = widgets.size(); + + for (int n=0; n& widgets, Widget* parent=NULL); + void resizeWidgetsRecursively(PtrVector& widgets); public: AbstractTopLevelContainer(); diff --git a/src/guiengine/engine.cpp b/src/guiengine/engine.cpp index 272ed60e7d2..d3818835245 100644 --- a/src/guiengine/engine.cpp +++ b/src/guiengine/engine.cpp @@ -951,6 +951,8 @@ namespace GUIEngine } Debug::closeDebugMenu(); + if (!g_current_screen->isLoaded()) + g_current_screen->loadFromFile(); g_current_screen->beforeAddingWidget(); // show screen diff --git a/src/guiengine/engine.hpp b/src/guiengine/engine.hpp index acad0395a06..3e11ac12d29 100644 --- a/src/guiengine/engine.hpp +++ b/src/guiengine/engine.hpp @@ -102,6 +102,7 @@ namespace GUIEngine /** Widgets that need to be notified at every frame can add themselves there (FIXME: unclean) */ extern PtrVector needsUpdate; + extern PtrVector g_loaded_screens; /** * \brief Call this method to init the GUI engine. diff --git a/src/guiengine/screen.cpp b/src/guiengine/screen.cpp index ae6b9d126b7..1ca7af10644 100644 --- a/src/guiengine/screen.cpp +++ b/src/guiengine/screen.cpp @@ -229,6 +229,17 @@ void Screen::manualRemoveWidget(Widget* w) m_widgets.remove(w); } // manualRemoveWidget +// ----------------------------------------------------------------------------- +void Screen::onResize() +{ + m_width = irr_driver->getActualScreenSize().Width; + m_height = irr_driver->getActualScreenSize().Height; + + calculateLayout(); + + resizeWidgetsRecursively(m_widgets); +} // onResize + // ----------------------------------------------------------------------------- #if 0 diff --git a/src/guiengine/screen.hpp b/src/guiengine/screen.hpp index 5926eeda461..b9900f8f6df 100644 --- a/src/guiengine/screen.hpp +++ b/src/guiengine/screen.hpp @@ -289,6 +289,11 @@ namespace GUIEngine */ virtual void onDraw(float dt) { }; + /** + * \brief optional callback you can override to be notified at every resize. + */ + virtual void onResize(); + /** * \return which music to play at this screen */ diff --git a/src/guiengine/widget.cpp b/src/guiengine/widget.cpp index 19fcf642f5f..1a0e149a557 100644 --- a/src/guiengine/widget.cpp +++ b/src/guiengine/widget.cpp @@ -299,17 +299,23 @@ bool Widget::isFocusedForPlayer(const int playerID) // ----------------------------------------------------------------------------- -void Widget::move(const int x, const int y, const int w, const int h) +void Widget::resize() { assert(m_magic_number == 0xCAFEC001); + if (m_element) + moveIrrlichtElement(); +} + +// ----------------------------------------------------------------------------- + +void Widget::move(const int x, const int y, const int w, const int h) +{ m_x = x; m_y = y; m_w = w; m_h = h; - - if (m_element != NULL) - m_element->setRelativePosition( core::rect < s32 > (x, y, x+w, y+h) ); + resize(); } // ----------------------------------------------------------------------------- diff --git a/src/guiengine/widget.hpp b/src/guiengine/widget.hpp index 2170a4590aa..03aaac9f21f 100644 --- a/src/guiengine/widget.hpp +++ b/src/guiengine/widget.hpp @@ -405,7 +405,12 @@ namespace GUIEngine virtual EventPropagation onActivationInput(const int playerID) { return EVENT_LET; } /** - * Call to resize/move the widget. Not all widgets can resize gracefully. + * Call to resize the widget when its coordinations are updated. + */ + virtual void resize(); + + /** + * Move the widget to the given position. */ virtual void move(const int x, const int y, const int w, const int h); From 913a082528f6a5cf9d9c34f7c2553b1b09d3c4e3 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Fri, 19 Apr 2024 13:35:37 +0800 Subject: [PATCH 310/830] Keep multiplayer in kart selection screen after reloading --- src/states_screens/kart_selection.cpp | 1 + src/states_screens/kart_selection.hpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index bc67fb008a1..5a17d01e1a0 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -65,6 +65,7 @@ static const char ID_DONT_USE[] = "x"; static const char ID_LOCKED[] = "locked/"; KartSelectionScreen* KartSelectionScreen::m_instance_ptr = NULL; +bool KartSelectionScreen::m_multiplayer = false; int g_root_id; diff --git a/src/states_screens/kart_selection.hpp b/src/states_screens/kart_selection.hpp index 273f339a474..1f8c97d600d 100644 --- a/src/states_screens/kart_selection.hpp +++ b/src/states_screens/kart_selection.hpp @@ -62,7 +62,7 @@ class KartSelectionScreen : public GUIEngine::Screen friend class GUIEngine::ScreenSingleton; friend class GUIEngine::PlayerKartWidget; - bool m_multiplayer; + static bool m_multiplayer; /** Whether this screen is being visited from overworld or not */ bool m_from_overworld; From f70c2abe54d9844f7429b43d1eb575f84e1ae535 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Fri, 19 Apr 2024 15:55:56 +0800 Subject: [PATCH 311/830] Remove unneeded header file includes in online screens --- src/online/online_player_profile.cpp | 1 + src/states_screens/dialogs/user_info_dialog.cpp | 5 +++++ src/states_screens/dialogs/user_info_dialog.hpp | 2 +- src/states_screens/online/create_server_screen.cpp | 5 +++++ src/states_screens/online/create_server_screen.hpp | 8 +++++--- src/states_screens/online/online_lan.cpp | 1 + src/states_screens/online/online_lan.hpp | 2 -- .../online/online_profile_achievements.cpp | 2 ++ .../online/online_profile_achievements.hpp | 3 +-- src/states_screens/online/online_profile_base.cpp | 4 ++++ src/states_screens/online/online_profile_base.hpp | 5 ++--- .../online/online_profile_friends.cpp | 5 +++++ .../online/online_profile_friends.hpp | 5 ++--- .../online/online_profile_servers.cpp | 13 +++++++------ .../online/online_profile_servers.hpp | 1 - .../online/online_profile_settings.cpp | 4 ++++ .../online/online_profile_settings.hpp | 3 +-- src/states_screens/online/online_screen.cpp | 2 ++ src/states_screens/online/online_user_search.cpp | 5 +++++ src/states_screens/online/online_user_search.hpp | 7 +++++-- 20 files changed, 58 insertions(+), 25 deletions(-) diff --git a/src/online/online_player_profile.cpp b/src/online/online_player_profile.cpp index 30850244ea4..693391b13bb 100644 --- a/src/online/online_player_profile.cpp +++ b/src/online/online_player_profile.cpp @@ -23,6 +23,7 @@ #include "config/user_config.hpp" #include "guiengine/message_queue.hpp" #include "guiengine/screen.hpp" +#include "io/xml_node.hpp" #include "network/network_config.hpp" #include "online/online_profile.hpp" #include "online/profile_manager.hpp" diff --git a/src/states_screens/dialogs/user_info_dialog.cpp b/src/states_screens/dialogs/user_info_dialog.cpp index b95ba41f76a..4ca472abf90 100644 --- a/src/states_screens/dialogs/user_info_dialog.cpp +++ b/src/states_screens/dialogs/user_info_dialog.cpp @@ -20,7 +20,12 @@ #include "config/player_manager.hpp" #include "guiengine/dialog_queue.hpp" #include "guiengine/engine.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "io/xml_node.hpp" #include "online/online_profile.hpp" +#include "online/profile_manager.hpp" #include "online/xml_request.hpp" #include "states_screens/online/online_profile_achievements.hpp" #include "states_screens/online/online_profile_friends.hpp" diff --git a/src/states_screens/dialogs/user_info_dialog.hpp b/src/states_screens/dialogs/user_info_dialog.hpp index 517f670a30f..5ac587dfe7c 100644 --- a/src/states_screens/dialogs/user_info_dialog.hpp +++ b/src/states_screens/dialogs/user_info_dialog.hpp @@ -20,11 +20,11 @@ #define HEADER_USER_INFO_DIALOG_HPP #include "guiengine/modaldialog.hpp" -#include "guiengine/widgets.hpp" #include "utils/types.hpp" #include +namespace GUIEngine { class IconButtonWidget; class LabelWidget; class RibbonWidget; } namespace Online { class OnlineProfile; diff --git a/src/states_screens/online/create_server_screen.cpp b/src/states_screens/online/create_server_screen.cpp index 070b961991f..1e82d5daa96 100644 --- a/src/states_screens/online/create_server_screen.cpp +++ b/src/states_screens/online/create_server_screen.cpp @@ -20,6 +20,11 @@ #include "audio/sfx_manager.hpp" #include "config/player_manager.hpp" #include "config/user_config.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "guiengine/widgets/spinner_widget.hpp" +#include "guiengine/widgets/text_box_widget.hpp" #include "karts/controller/network_ai_controller.hpp" #include "network/network_config.hpp" #include "network/server.hpp" diff --git a/src/states_screens/online/create_server_screen.hpp b/src/states_screens/online/create_server_screen.hpp index 232d0d998cf..e396c4597e8 100644 --- a/src/states_screens/online/create_server_screen.hpp +++ b/src/states_screens/online/create_server_screen.hpp @@ -19,10 +19,12 @@ #define HEADER_CREATE_SERVER_SCREEN_HPP #include "guiengine/screen.hpp" -#include "guiengine/widgets.hpp" - -namespace GUIEngine { class Widget; class ListWidget; } +namespace GUIEngine +{ + class IconButtonWidget; class LabelWidget; class RibbonWidget; + class SpinnerWidget; class TextBoxWidget; class Widget; +} /** * \brief Handles the main menu diff --git a/src/states_screens/online/online_lan.cpp b/src/states_screens/online/online_lan.cpp index 418d61521f1..2fd0c27542d 100644 --- a/src/states_screens/online/online_lan.cpp +++ b/src/states_screens/online/online_lan.cpp @@ -18,6 +18,7 @@ #include "states_screens/online/online_profile_servers.hpp" #include "guiengine/screen.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" #include "network/network_config.hpp" #include "states_screens/state_manager.hpp" #include "states_screens/online/create_server_screen.hpp" diff --git a/src/states_screens/online/online_lan.hpp b/src/states_screens/online/online_lan.hpp index f96a208c873..1174bcd26c2 100644 --- a/src/states_screens/online/online_lan.hpp +++ b/src/states_screens/online/online_lan.hpp @@ -23,8 +23,6 @@ #include #include "guiengine/screen.hpp" -#include "guiengine/widgets.hpp" -#include "states_screens/online/online_profile_base.hpp" namespace GUIEngine { class Widget; } diff --git a/src/states_screens/online/online_profile_achievements.cpp b/src/states_screens/online/online_profile_achievements.cpp index efee9bcd0f7..73742ad3eb3 100644 --- a/src/states_screens/online/online_profile_achievements.cpp +++ b/src/states_screens/online/online_profile_achievements.cpp @@ -24,6 +24,8 @@ #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" #include "guiengine/widget.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" #include "online/online_profile.hpp" #include "states_screens/dialogs/achievement_progress_dialog.hpp" #include "states_screens/dialogs/player_rankings_dialog.hpp" diff --git a/src/states_screens/online/online_profile_achievements.hpp b/src/states_screens/online/online_profile_achievements.hpp index 36f8601529e..8c31665aad6 100644 --- a/src/states_screens/online/online_profile_achievements.hpp +++ b/src/states_screens/online/online_profile_achievements.hpp @@ -24,9 +24,8 @@ #include "achievements/achievement.hpp" #include "guiengine/screen.hpp" -#include "guiengine/widgets.hpp" +#include "guiengine/widgets/list_widget.hpp" #include "states_screens/online/online_profile_base.hpp" -#include "online/profile_manager.hpp" namespace GUIEngine { class Widget; } diff --git a/src/states_screens/online/online_profile_base.cpp b/src/states_screens/online/online_profile_base.cpp index 8b2d3fda72a..90f8d6edf23 100644 --- a/src/states_screens/online/online_profile_base.cpp +++ b/src/states_screens/online/online_profile_base.cpp @@ -22,7 +22,11 @@ #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" #include "guiengine/widget.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" #include "online/online_profile.hpp" +#include "online/profile_manager.hpp" #include "states_screens/state_manager.hpp" #include "utils/translation.hpp" #include "states_screens/online/online_profile_friends.hpp" diff --git a/src/states_screens/online/online_profile_base.hpp b/src/states_screens/online/online_profile_base.hpp index 0285edb4b5a..a514ad8d368 100644 --- a/src/states_screens/online/online_profile_base.hpp +++ b/src/states_screens/online/online_profile_base.hpp @@ -23,10 +23,9 @@ #include #include "guiengine/screen.hpp" -#include "guiengine/widgets.hpp" -#include "online/profile_manager.hpp" -namespace GUIEngine { class Widget; } +namespace GUIEngine { class IconButtonWidget; class LabelWidget; class RibbonWidget; class Widget; } +namespace Online { class OnlineProfile; } /** Online profile base screen. Used for displaying friends, achievements, diff --git a/src/states_screens/online/online_profile_friends.cpp b/src/states_screens/online/online_profile_friends.cpp index d3f12b4034f..ff9ce9cf084 100644 --- a/src/states_screens/online/online_profile_friends.cpp +++ b/src/states_screens/online/online_profile_friends.cpp @@ -21,6 +21,11 @@ #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" #include "guiengine/widget.hpp" +#include "guiengine/widgets/button_widget.hpp" +#include "guiengine/widgets/list_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "guiengine/widgets/text_box_widget.hpp" +#include "online/profile_manager.hpp" #include "states_screens/dialogs/user_info_dialog.hpp" #include "states_screens/online/online_user_search.hpp" #include "states_screens/state_manager.hpp" diff --git a/src/states_screens/online/online_profile_friends.hpp b/src/states_screens/online/online_profile_friends.hpp index 34f6935f2bc..346a350247c 100644 --- a/src/states_screens/online/online_profile_friends.hpp +++ b/src/states_screens/online/online_profile_friends.hpp @@ -23,12 +23,11 @@ #include #include "guiengine/screen.hpp" -#include "guiengine/widgets.hpp" +#include "guiengine/widgets/list_widget.hpp" #include "states_screens/online/online_profile_base.hpp" -#include "online/profile_manager.hpp" -namespace GUIEngine { class Widget; } +namespace GUIEngine { class ButtonWidget; class ListWidget; class TextBoxWidget; class Widget; } /** Online profile overview screen. diff --git a/src/states_screens/online/online_profile_servers.cpp b/src/states_screens/online/online_profile_servers.cpp index b53435068bb..6f770663bf5 100644 --- a/src/states_screens/online/online_profile_servers.cpp +++ b/src/states_screens/online/online_profile_servers.cpp @@ -22,6 +22,7 @@ #include "guiengine/engine.hpp" #include "guiengine/screen.hpp" #include "guiengine/widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" #include "network/network_config.hpp" #include "network/stk_host.hpp" #include "network/server_config.hpp" @@ -54,15 +55,15 @@ void OnlineProfileServers::init() if (!PlayerManager::getCurrentOnlineId()) { getWidget("back")->setFocusForPlayer(PLAYER_ID_GAME_MASTER); - getWidget("find_wan_server")->setActive(false); - getWidget("create_wan_server")->setActive(false); - getWidget("quick_wan_play")->setActive(false); + getWidget("find_wan_server")->setActive(false); + getWidget("create_wan_server")->setActive(false); + getWidget("quick_wan_play")->setActive(false); } else { - getWidget("find_wan_server")->setActive(true); - getWidget("create_wan_server")->setActive(true); - getWidget("quick_wan_play")->setActive(true); + getWidget("find_wan_server")->setActive(true); + getWidget("create_wan_server")->setActive(true); + getWidget("quick_wan_play")->setActive(true); RibbonWidget* ribbon = getWidget("wan"); assert(ribbon != NULL); ribbon->select("find_wan_server", PLAYER_ID_GAME_MASTER); diff --git a/src/states_screens/online/online_profile_servers.hpp b/src/states_screens/online/online_profile_servers.hpp index ace477afe81..ff777d45618 100644 --- a/src/states_screens/online/online_profile_servers.hpp +++ b/src/states_screens/online/online_profile_servers.hpp @@ -23,7 +23,6 @@ #include #include "guiengine/screen.hpp" -#include "guiengine/widgets.hpp" #include "states_screens/online/online_profile_base.hpp" namespace GUIEngine { class Widget; } diff --git a/src/states_screens/online/online_profile_settings.cpp b/src/states_screens/online/online_profile_settings.cpp index 7fb302fa55b..58632f57779 100644 --- a/src/states_screens/online/online_profile_settings.cpp +++ b/src/states_screens/online/online_profile_settings.cpp @@ -21,6 +21,10 @@ #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" #include "guiengine/widget.hpp" +#include "guiengine/widgets/button_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "guiengine/widgets/text_box_widget.hpp" #include "states_screens/state_manager.hpp" #include "states_screens/dialogs/change_password_dialog.hpp" #include "states_screens/dialogs/general_text_field_dialog.hpp" diff --git a/src/states_screens/online/online_profile_settings.hpp b/src/states_screens/online/online_profile_settings.hpp index e03f867d07a..665da10370d 100644 --- a/src/states_screens/online/online_profile_settings.hpp +++ b/src/states_screens/online/online_profile_settings.hpp @@ -23,10 +23,9 @@ #include #include "guiengine/screen.hpp" -#include "guiengine/widgets.hpp" #include "states_screens/online/online_profile_base.hpp" -namespace GUIEngine { class Widget; } +namespace GUIEngine { class ButtonWidget; class Widget; } /** diff --git a/src/states_screens/online/online_screen.cpp b/src/states_screens/online/online_screen.cpp index 308c8b2d34f..30cea0b7792 100644 --- a/src/states_screens/online/online_screen.cpp +++ b/src/states_screens/online/online_screen.cpp @@ -21,6 +21,7 @@ #include "config/player_manager.hpp" #include "config/user_config.hpp" #include "guiengine/message_queue.hpp" +#include "guiengine/widgets/button_widget.hpp" #include "guiengine/widgets/check_box_widget.hpp" #include "guiengine/widgets/label_widget.hpp" #include "guiengine/widgets/list_widget.hpp" @@ -34,6 +35,7 @@ #include "network/socket_address.hpp" #include "network/stk_host.hpp" #include "network/stk_peer.hpp" +#include "online/profile_manager.hpp" #include "online/request_manager.hpp" #include "states_screens/online/networking_lobby.hpp" #include "states_screens/online/online_lan.hpp" diff --git a/src/states_screens/online/online_user_search.cpp b/src/states_screens/online/online_user_search.cpp index 59e9ac5913c..916f939ea86 100644 --- a/src/states_screens/online/online_user_search.cpp +++ b/src/states_screens/online/online_user_search.cpp @@ -20,6 +20,11 @@ #include "audio/sfx_manager.hpp" #include "config/player_manager.hpp" #include "guiengine/modaldialog.hpp" +#include "guiengine/widgets/button_widget.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/list_widget.hpp" +#include "guiengine/widgets/text_box_widget.hpp" +#include "io/xml_node.hpp" #include "online/profile_manager.hpp" #include "online/xml_request.hpp" #include "states_screens/dialogs/user_info_dialog.hpp" diff --git a/src/states_screens/online/online_user_search.hpp b/src/states_screens/online/online_user_search.hpp index e59e168448c..bc849ccfe59 100644 --- a/src/states_screens/online/online_user_search.hpp +++ b/src/states_screens/online/online_user_search.hpp @@ -19,11 +19,14 @@ #define HEADER_ONLINE_USER_SEARCH_HPP #include "guiengine/screen.hpp" -#include "guiengine/widgets.hpp" #include "online/online_profile.hpp" #include "utils/ptr_vector.hpp" -namespace GUIEngine { class Widget; } +namespace GUIEngine +{ + class ButtonWidget; class IconButtonWidget; class ListWidget; + class TextBoxWidget; class Widget; +} namespace Online { class XMLRequest; } From 52edb8507e1d59d61cb25c71bdc35b4cd947e4b8 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Fri, 19 Apr 2024 17:28:11 +0800 Subject: [PATCH 312/830] Remove the remaining unneeded header file includes --- src/guiengine/skin.cpp | 10 +++++++++- src/network/protocols/client_lobby.cpp | 1 + src/states_screens/addons_screen.cpp | 2 ++ src/states_screens/addons_screen.hpp | 8 +++----- src/states_screens/dialogs/addons_loading.cpp | 6 +++++- src/states_screens/dialogs/addons_loading.hpp | 2 +- src/states_screens/dialogs/addons_pack.cpp | 5 +++++ src/states_screens/dialogs/addons_pack.hpp | 2 +- src/states_screens/dialogs/change_password_dialog.cpp | 5 ++++- src/states_screens/dialogs/download_assets.cpp | 7 ++++++- src/states_screens/dialogs/download_assets.hpp | 2 +- .../dialogs/ghost_replay_info_dialog.cpp | 5 +++++ .../dialogs/ghost_replay_info_dialog.hpp | 7 ++++++- src/states_screens/dialogs/high_score_info_dialog.cpp | 4 ++++ src/states_screens/dialogs/high_score_info_dialog.hpp | 7 ++++++- src/states_screens/dialogs/recovery_dialog.cpp | 4 ++++ src/states_screens/dialogs/recovery_dialog.hpp | 7 +++++-- src/states_screens/dialogs/registration_dialog.cpp | 3 ++- src/states_screens/dialogs/vote_dialog.cpp | 5 +++++ src/states_screens/dialogs/vote_dialog.hpp | 2 +- src/states_screens/edit_track_screen.cpp | 1 + src/states_screens/edit_track_screen.hpp | 3 +-- src/states_screens/ghost_replay_selection.cpp | 6 +++++- src/states_screens/ghost_replay_selection.hpp | 5 ++--- src/states_screens/high_score_selection.cpp | 3 +++ src/states_screens/high_score_selection.hpp | 4 ++-- src/states_screens/main_menu_screen.cpp | 1 + src/states_screens/online/tracks_screen.cpp | 1 + src/states_screens/options/user_screen.cpp | 1 + src/states_screens/track_info_screen.cpp | 2 ++ src/states_screens/track_info_screen.hpp | 3 ++- 31 files changed, 97 insertions(+), 27 deletions(-) diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index 778503fe411..a3b32407101 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -25,12 +25,20 @@ #include "config/user_config.hpp" #include "graphics/2dutils.hpp" #include "graphics/central_settings.hpp" +#include "graphics/irr_driver.hpp" #include "guiengine/engine.hpp" #include "guiengine/modaldialog.hpp" #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" #include "guiengine/screen_keyboard.hpp" -#include "guiengine/widgets.hpp" +#include "guiengine/widgets/bubble_widget.hpp" +#include "guiengine/widgets/check_box_widget.hpp" +#include "guiengine/widgets/list_widget.hpp" +#include "guiengine/widgets/model_view_widget.hpp" +#include "guiengine/widgets/progress_bar_widget.hpp" +#include "guiengine/widgets/rating_bar_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "guiengine/widgets/spinner_widget.hpp" #include "io/file_manager.hpp" #include "states_screens/state_manager.hpp" #include "utils/log.hpp" diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp index b1242272fd2..be9e3745d24 100644 --- a/src/network/protocols/client_lobby.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -30,6 +30,7 @@ #include "guiengine/screen_keyboard.hpp" #include "input/device_manager.hpp" #include "input/input_device.hpp" +#include "io/file_manager.hpp" #include "items/network_item_manager.hpp" #include "items/powerup_manager.hpp" #include "karts/abstract_kart.hpp" diff --git a/src/states_screens/addons_screen.cpp b/src/states_screens/addons_screen.cpp index 142fca0b9e8..d0a403956ac 100644 --- a/src/states_screens/addons_screen.cpp +++ b/src/states_screens/addons_screen.cpp @@ -20,11 +20,13 @@ #include "addons/addons_manager.hpp" #include "addons/news_manager.hpp" #include "config/user_config.hpp" +#include "graphics/irr_driver.hpp" #include "guiengine/CGUISpriteBank.hpp" #include "guiengine/modaldialog.hpp" #include "guiengine/scalable_font.hpp" #include "guiengine/widget.hpp" #include "guiengine/widgets/ribbon_widget.hpp" +#include "guiengine/widgets/spinner_widget.hpp" #include "io/file_manager.hpp" #include "online/request_manager.hpp" #include "states_screens/dialogs/addons_loading.hpp" diff --git a/src/states_screens/addons_screen.hpp b/src/states_screens/addons_screen.hpp index 8d929c040bb..53f51efda11 100644 --- a/src/states_screens/addons_screen.hpp +++ b/src/states_screens/addons_screen.hpp @@ -20,15 +20,15 @@ #include "addons/addons_manager.hpp" #include "guiengine/screen.hpp" -#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/list_widget.hpp" #include "guiengine/widgets/text_box_widget.hpp" -#include "states_screens/dialogs/addons_loading.hpp" /* used for the installed/unsinstalled icons*/ namespace irr { namespace gui { class STKModifiedSpriteBank; } } -namespace GUIEngine { class Widget; } +namespace GUIEngine { class LabelWidget; class Widget; } +class AddonsLoading; struct DateFilter { core::stringw label; int year; @@ -61,8 +61,6 @@ class AddonsScreen : public GUIEngine::Screen, irr::gui::STKModifiedSpriteBank *m_icon_bank; - GUIEngine::LabelWidget - *m_update_status; /** Currently selected type. */ std::string m_type; diff --git a/src/states_screens/dialogs/addons_loading.cpp b/src/states_screens/dialogs/addons_loading.cpp index 0a02fdd36ce..e65b0a87a82 100644 --- a/src/states_screens/dialogs/addons_loading.cpp +++ b/src/states_screens/dialogs/addons_loading.cpp @@ -25,7 +25,11 @@ #include "guiengine/engine.hpp" #include "guiengine/message_queue.hpp" #include "guiengine/scalable_font.hpp" -#include "guiengine/widgets.hpp" +#include "guiengine/widgets/bubble_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/rating_bar_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "guiengine/widgets/progress_bar_widget.hpp" #include "input/input_manager.hpp" #include "io/file_manager.hpp" #include "network/protocols/client_lobby.hpp" diff --git a/src/states_screens/dialogs/addons_loading.hpp b/src/states_screens/dialogs/addons_loading.hpp index c5e00a6cb56..9d6ad773aa6 100644 --- a/src/states_screens/dialogs/addons_loading.hpp +++ b/src/states_screens/dialogs/addons_loading.hpp @@ -21,11 +21,11 @@ #include "addons/addon.hpp" #include "addons/addons_manager.hpp" -#include "guiengine/widgets.hpp" #include "guiengine/modaldialog.hpp" #include "utils/cpp2011.hpp" #include "utils/synchronised.hpp" +namespace GUIEngine { class IconButtonWidget; class ProgressBarWidget; } namespace Online { class HTTPRequest; } /** diff --git a/src/states_screens/dialogs/addons_pack.cpp b/src/states_screens/dialogs/addons_pack.cpp index e9c10b085b2..a6aedb0d859 100644 --- a/src/states_screens/dialogs/addons_pack.cpp +++ b/src/states_screens/dialogs/addons_pack.cpp @@ -26,6 +26,11 @@ #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" #include "guiengine/message_queue.hpp" +#include "guiengine/widgets/bubble_widget.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/progress_bar_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" #include "network/protocols/client_lobby.hpp" #include "online/http_request.hpp" #include "states_screens/addons_screen.hpp" diff --git a/src/states_screens/dialogs/addons_pack.hpp b/src/states_screens/dialogs/addons_pack.hpp index 24b7ae3bec4..d4c4a1cb0f0 100644 --- a/src/states_screens/dialogs/addons_pack.hpp +++ b/src/states_screens/dialogs/addons_pack.hpp @@ -18,11 +18,11 @@ #ifndef HEADER_ADDONS_PACK_HPP #define HEADER_ADDONS_PACK_HPP -#include "guiengine/widgets.hpp" #include "guiengine/modaldialog.hpp" #include "utils/cpp2011.hpp" class AddonsPackRequest; +namespace GUIEngine { class LabelWidget; class ProgressBarWidget; } /** * \ingroup states_screens diff --git a/src/states_screens/dialogs/change_password_dialog.cpp b/src/states_screens/dialogs/change_password_dialog.cpp index 556189cc40d..3784cf33073 100644 --- a/src/states_screens/dialogs/change_password_dialog.cpp +++ b/src/states_screens/dialogs/change_password_dialog.cpp @@ -20,7 +20,10 @@ #include "audio/sfx_manager.hpp" #include "config/player_manager.hpp" #include "guiengine/engine.hpp" -#include "guiengine/widgets.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "guiengine/widgets/text_box_widget.hpp" #include "online/xml_request.hpp" #include "states_screens/dialogs/message_dialog.hpp" #include "states_screens/state_manager.hpp" diff --git a/src/states_screens/dialogs/download_assets.cpp b/src/states_screens/dialogs/download_assets.cpp index 13f5556d8db..e3dacf24c9b 100644 --- a/src/states_screens/dialogs/download_assets.cpp +++ b/src/states_screens/dialogs/download_assets.cpp @@ -20,9 +20,14 @@ #include "states_screens/dialogs/download_assets.hpp" #include "config/user_config.hpp" -#include "states_screens/dialogs/message_dialog.hpp" +#include "guiengine/widgets/bubble_widget.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/progress_bar_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" #include "io/file_manager.hpp" #include "online/http_request.hpp" +#include "states_screens/dialogs/message_dialog.hpp" #include "states_screens/state_manager.hpp" #include "utils/extract_mobile_assets.hpp" #include "utils/download_assets_size.hpp" diff --git a/src/states_screens/dialogs/download_assets.hpp b/src/states_screens/dialogs/download_assets.hpp index 98b8ace9774..15814bf0fa4 100644 --- a/src/states_screens/dialogs/download_assets.hpp +++ b/src/states_screens/dialogs/download_assets.hpp @@ -20,11 +20,11 @@ #ifdef MOBILE_STK -#include "guiengine/widgets.hpp" #include "guiengine/modaldialog.hpp" #include "utils/cpp2011.hpp" class DownloadAssetsRequest; +namespace GUIEngine { class IconButtonWidget; class ProgressBarWidget; } /** * \ingroup states_screens diff --git a/src/states_screens/dialogs/ghost_replay_info_dialog.cpp b/src/states_screens/dialogs/ghost_replay_info_dialog.cpp index adf89159ebe..7585a815c4a 100644 --- a/src/states_screens/dialogs/ghost_replay_info_dialog.cpp +++ b/src/states_screens/dialogs/ghost_replay_info_dialog.cpp @@ -21,6 +21,11 @@ #include "config/player_manager.hpp" #include "guiengine/CGUISpriteBank.hpp" #include "graphics/stk_tex_manager.hpp" +#include "guiengine/widgets/check_box_widget.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/list_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" #include "race/race_manager.hpp" diff --git a/src/states_screens/dialogs/ghost_replay_info_dialog.hpp b/src/states_screens/dialogs/ghost_replay_info_dialog.hpp index a8d9d1771bf..f8306934852 100644 --- a/src/states_screens/dialogs/ghost_replay_info_dialog.hpp +++ b/src/states_screens/dialogs/ghost_replay_info_dialog.hpp @@ -20,9 +20,14 @@ #define HEADER_GHOST_REPLAY_INFO_DIALOG_HPP #include "guiengine/modaldialog.hpp" -#include "guiengine/widgets.hpp" #include "replay/replay_play.hpp" +namespace GUIEngine +{ + class CheckBoxWidget; class IconButtonWidget; class ListWidget; + class RibbonWidget; +} + /** \brief Dialog that allows a user to do action with ghost replay file * \ingroup states_screens */ diff --git a/src/states_screens/dialogs/high_score_info_dialog.cpp b/src/states_screens/dialogs/high_score_info_dialog.cpp index 82459d3bb56..91ef7aa72d8 100644 --- a/src/states_screens/dialogs/high_score_info_dialog.cpp +++ b/src/states_screens/dialogs/high_score_info_dialog.cpp @@ -22,6 +22,10 @@ #include "config/user_config.hpp" #include "guiengine/CGUISpriteBank.hpp" #include "graphics/stk_tex_manager.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/list_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" #include "input/device_manager.hpp" #include "input/input_manager.hpp" #include "karts/kart_properties.hpp" diff --git a/src/states_screens/dialogs/high_score_info_dialog.hpp b/src/states_screens/dialogs/high_score_info_dialog.hpp index 6664f82b373..1e6c012f79a 100644 --- a/src/states_screens/dialogs/high_score_info_dialog.hpp +++ b/src/states_screens/dialogs/high_score_info_dialog.hpp @@ -20,10 +20,15 @@ #define HEADER_HIGH_SCORE_INFO_DIALOG_HPP #include "guiengine/modaldialog.hpp" -#include "guiengine/widgets.hpp" #include "race/grand_prix_data.hpp" #include "race/highscores.hpp" +namespace GUIEngine +{ + class IconButtonWidget; class LabelWidget; class ListWidget; + class RibbonWidget; +} + /** \brief Dialog that allows a user to manage a high score * \ingroup states_screens */ diff --git a/src/states_screens/dialogs/recovery_dialog.cpp b/src/states_screens/dialogs/recovery_dialog.cpp index 4d5e6d1475c..be128b7abea 100644 --- a/src/states_screens/dialogs/recovery_dialog.cpp +++ b/src/states_screens/dialogs/recovery_dialog.cpp @@ -20,6 +20,10 @@ #include "audio/sfx_manager.hpp" #include "config/player_manager.hpp" #include "guiengine/engine.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "guiengine/widgets/text_box_widget.hpp" #include "online/xml_request.hpp" #include "states_screens/state_manager.hpp" #include "utils/translation.hpp" diff --git a/src/states_screens/dialogs/recovery_dialog.hpp b/src/states_screens/dialogs/recovery_dialog.hpp index c2b2961caf2..b6f25c98acd 100644 --- a/src/states_screens/dialogs/recovery_dialog.hpp +++ b/src/states_screens/dialogs/recovery_dialog.hpp @@ -19,10 +19,13 @@ #ifndef HEADER_RECOVERY_DIALOG_HPP #define HEADER_RECOVERY_DIALOG_HPP - #include "guiengine/modaldialog.hpp" -#include "guiengine/widgets.hpp" +namespace GUIEngine +{ + class IconButtonWidget; class LabelWidget; class RibbonWidget; + class TextBoxWidget; +} namespace Online { class XMLRequest; diff --git a/src/states_screens/dialogs/registration_dialog.cpp b/src/states_screens/dialogs/registration_dialog.cpp index e2784f1784f..76ec2775c4e 100644 --- a/src/states_screens/dialogs/registration_dialog.cpp +++ b/src/states_screens/dialogs/registration_dialog.cpp @@ -18,7 +18,8 @@ #include "states_screens/dialogs/registration_dialog.hpp" #include "guiengine/engine.hpp" -#include "guiengine/widgets.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" #include "states_screens/state_manager.hpp" #include "states_screens/online/register_screen.hpp" #include "utils/translation.hpp" diff --git a/src/states_screens/dialogs/vote_dialog.cpp b/src/states_screens/dialogs/vote_dialog.cpp index fe827530ca7..56b4bf0b498 100644 --- a/src/states_screens/dialogs/vote_dialog.cpp +++ b/src/states_screens/dialogs/vote_dialog.cpp @@ -21,6 +21,11 @@ #include "audio/sfx_manager.hpp" #include "config/player_manager.hpp" #include "guiengine/engine.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/rating_bar_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "io/xml_node.hpp" #include "online/xml_request.hpp" #include "states_screens/state_manager.hpp" #include "utils/string_utils.hpp" diff --git a/src/states_screens/dialogs/vote_dialog.hpp b/src/states_screens/dialogs/vote_dialog.hpp index 714861dab09..ceabd73aad3 100644 --- a/src/states_screens/dialogs/vote_dialog.hpp +++ b/src/states_screens/dialogs/vote_dialog.hpp @@ -21,10 +21,10 @@ #include "guiengine/modaldialog.hpp" -#include "guiengine/widgets.hpp" #include +namespace GUIEngine { class IconButtonWidget; class LabelWidget; class RatingBarWidget; class RibbonWidget; } namespace Online { class XMLRequest; diff --git a/src/states_screens/edit_track_screen.cpp b/src/states_screens/edit_track_screen.cpp index a5c6a17aee5..ec2ff89192c 100644 --- a/src/states_screens/edit_track_screen.cpp +++ b/src/states_screens/edit_track_screen.cpp @@ -22,6 +22,7 @@ #include "guiengine/widgets/button_widget.hpp" #include "guiengine/widgets/check_box_widget.hpp" #include "guiengine/widgets/dynamic_ribbon_widget.hpp" +#include "guiengine/widgets/icon_button_widget.hpp" #include "guiengine/widgets/label_widget.hpp" #include "guiengine/widgets/ribbon_widget.hpp" #include "guiengine/widgets/spinner_widget.hpp" diff --git a/src/states_screens/edit_track_screen.hpp b/src/states_screens/edit_track_screen.hpp index d7cda62c0b3..c23ad30e2b2 100644 --- a/src/states_screens/edit_track_screen.hpp +++ b/src/states_screens/edit_track_screen.hpp @@ -19,9 +19,8 @@ #define HEADER_EDIT_TRACK_SCREEN_HPP #include "guiengine/screen.hpp" -#include "guiengine/widgets.hpp" -namespace GUIEngine { class Widget; } +namespace GUIEngine { class IconButtonWidget; class Widget; } namespace irr { namespace gui { class STKModifiedSpriteBank; } } diff --git a/src/states_screens/ghost_replay_selection.cpp b/src/states_screens/ghost_replay_selection.cpp index 6da76a686d8..17597aadc2a 100644 --- a/src/states_screens/ghost_replay_selection.cpp +++ b/src/states_screens/ghost_replay_selection.cpp @@ -20,8 +20,13 @@ #include "config/player_manager.hpp" #include "config/user_config.hpp" +#include "graphics/irr_driver.hpp" #include "graphics/material.hpp" #include "guiengine/CGUISpriteBank.hpp" +#include "guiengine/widgets/check_box_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "io/file_manager.hpp" #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" #include "states_screens/dialogs/ghost_replay_info_dialog.hpp" @@ -122,7 +127,6 @@ void GhostReplaySelection::loadedFromFile() m_compare_toggle_widget->setVisible(false); getWidget("compare-toggle-text")->setVisible(false); - m_mode_tabs = getWidget("race_mode"); m_active_mode = RaceManager::MINOR_MODE_TIME_TRIAL; m_active_mode_is_linear = true; diff --git a/src/states_screens/ghost_replay_selection.hpp b/src/states_screens/ghost_replay_selection.hpp index 33d115820d9..34b4704b570 100644 --- a/src/states_screens/ghost_replay_selection.hpp +++ b/src/states_screens/ghost_replay_selection.hpp @@ -20,11 +20,11 @@ #define HEADER_GHOST_REPLAY_SELECTION_HPP #include "guiengine/screen.hpp" -#include "guiengine/widgets.hpp" +#include "guiengine/widgets/list_widget.hpp" #include "race/race_manager.hpp" #include "states_screens/dialogs/message_dialog.hpp" -namespace GUIEngine { class Widget; } +namespace GUIEngine { class CheckBoxWidget; class Widget; } /** * \brief GhostReplaySelection @@ -48,7 +48,6 @@ class GhostReplaySelection : public GUIEngine::Screen, GUIEngine::CheckBoxWidget* m_replay_version_toggle_widget; GUIEngine::CheckBoxWidget* m_best_times_toggle_widget; GUIEngine::CheckBoxWidget* m_compare_toggle_widget; - GUIEngine::RibbonWidget* m_mode_tabs; RaceManager::Difficulty m_cur_difficulty; std::string m_file_to_be_deleted; std::vector m_best_times_index; diff --git a/src/states_screens/high_score_selection.cpp b/src/states_screens/high_score_selection.cpp index 85a54a4f08a..454257bab71 100644 --- a/src/states_screens/high_score_selection.cpp +++ b/src/states_screens/high_score_selection.cpp @@ -20,8 +20,11 @@ #include "config/player_manager.hpp" #include "config/user_config.hpp" +#include "graphics/irr_driver.hpp" #include "graphics/material.hpp" #include "guiengine/CGUISpriteBank.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "io/file_manager.hpp" #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" #include "race/grand_prix_data.hpp" diff --git a/src/states_screens/high_score_selection.hpp b/src/states_screens/high_score_selection.hpp index 081383a9a94..aa28af0751b 100644 --- a/src/states_screens/high_score_selection.hpp +++ b/src/states_screens/high_score_selection.hpp @@ -20,11 +20,11 @@ #define HEADER_HIGH_SCORE_SELECTION_HPP #include "guiengine/screen.hpp" -#include "guiengine/widgets.hpp" +#include "guiengine/widgets/list_widget.hpp" #include "race/race_manager.hpp" #include "states_screens/dialogs/message_dialog.hpp" -namespace GUIEngine { class Widget; } +namespace GUIEngine { class ListWidget; class RibbonWidget; class Widget; } /** * \brief HighScoreSelection diff --git a/src/states_screens/main_menu_screen.cpp b/src/states_screens/main_menu_screen.cpp index 907df460cd4..199d034c561 100644 --- a/src/states_screens/main_menu_screen.cpp +++ b/src/states_screens/main_menu_screen.cpp @@ -27,6 +27,7 @@ #include "graphics/irr_driver.hpp" #include "guiengine/dialog_queue.hpp" #include "guiengine/scalable_font.hpp" +#include "guiengine/widgets/button_widget.hpp" #include "guiengine/widgets/label_widget.hpp" #include "guiengine/widgets/list_widget.hpp" #include "guiengine/widgets/ribbon_widget.hpp" diff --git a/src/states_screens/online/tracks_screen.cpp b/src/states_screens/online/tracks_screen.cpp index a39d4ab219c..244cb0e6bfd 100644 --- a/src/states_screens/online/tracks_screen.cpp +++ b/src/states_screens/online/tracks_screen.cpp @@ -30,6 +30,7 @@ #include "guiengine/widgets/check_box_widget.hpp" #include "guiengine/widgets/dynamic_ribbon_widget.hpp" #include "guiengine/widgets/icon_button_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" #include "guiengine/widgets/list_widget.hpp" #include "guiengine/widgets/progress_bar_widget.hpp" #include "guiengine/widgets/spinner_widget.hpp" diff --git a/src/states_screens/options/user_screen.cpp b/src/states_screens/options/user_screen.cpp index c6fb518fbe0..e150b876990 100644 --- a/src/states_screens/options/user_screen.cpp +++ b/src/states_screens/options/user_screen.cpp @@ -24,6 +24,7 @@ #include "config/user_config.hpp" #include "graphics/central_settings.hpp" #include "guiengine/screen_keyboard.hpp" +#include "guiengine/widgets/button_widget.hpp" #include "guiengine/widgets/check_box_widget.hpp" #include "guiengine/widgets/dynamic_ribbon_widget.hpp" #include "guiengine/widgets/label_widget.hpp" diff --git a/src/states_screens/track_info_screen.cpp b/src/states_screens/track_info_screen.cpp index 968b1304e44..45b2d4413e0 100644 --- a/src/states_screens/track_info_screen.cpp +++ b/src/states_screens/track_info_screen.cpp @@ -21,6 +21,7 @@ #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" #include "config/user_config.hpp" +#include "graphics/irr_driver.hpp" #include "graphics/material.hpp" #include "graphics/stk_tex_manager.hpp" #include "guiengine/CGUISpriteBank.hpp" @@ -30,6 +31,7 @@ #include "guiengine/widgets/check_box_widget.hpp" #include "guiengine/widgets/icon_button_widget.hpp" #include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/list_widget.hpp" #include "guiengine/widgets/ribbon_widget.hpp" #include "guiengine/widgets/spinner_widget.hpp" #include "io/file_manager.hpp" diff --git a/src/states_screens/track_info_screen.hpp b/src/states_screens/track_info_screen.hpp index a28e5130d65..6ccc66e62bd 100644 --- a/src/states_screens/track_info_screen.hpp +++ b/src/states_screens/track_info_screen.hpp @@ -21,13 +21,14 @@ #define HEADER_TRACK_INFO_SCREEN_HPP #include "guiengine/screen.hpp" -#include "guiengine/widgets.hpp" +namespace irr { namespace gui { class STKModifiedSpriteBank; } } namespace GUIEngine { class CheckBoxWidget; class IconButtonWidget; class LabelWidget; + class ListWidget; class SpinnerWidget; class Widget; } From 0cea06d935c9cad285d5eb9f547eced7ad5a87e3 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Fri, 19 Apr 2024 20:21:54 +0800 Subject: [PATCH 313/830] Add resizing code for icon button widget --- src/guiengine/widgets/icon_button_widget.cpp | 252 ++++++++++--------- src/guiengine/widgets/icon_button_widget.hpp | 6 +- 2 files changed, 145 insertions(+), 113 deletions(-) diff --git a/src/guiengine/widgets/icon_button_widget.cpp b/src/guiengine/widgets/icon_button_widget.cpp index 58c58e04136..ef8ff03aee0 100644 --- a/src/guiengine/widgets/icon_button_widget.cpp +++ b/src/guiengine/widgets/icon_button_widget.cpp @@ -116,69 +116,8 @@ void IconButtonWidget::add() } - // irrlicht widgets don't support scaling while keeping aspect ratio - // so, happily, let's implement it ourselves - float useAspectRatio = -1.0f; - - if (m_properties[PROP_CUSTOM_RATIO] != "") - { - StringUtils::fromString(m_properties[PROP_CUSTOM_RATIO], - m_custom_aspect_ratio); - m_scale_mode = SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO; - } - - if (m_scale_mode == SCALE_MODE_KEEP_TEXTURE_ASPECT_RATIO || - m_scale_mode == SCALE_MODE_LIST_WIDGET) - { - assert(m_texture->getOriginalSize().Height > 0); - useAspectRatio = (float)m_texture->getOriginalSize().Width / - (float)m_texture->getOriginalSize().Height; - } - else if (m_scale_mode == SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO) - { - useAspectRatio = m_custom_aspect_ratio; - } - - int suggested_h = m_h; - int suggested_w = (int)((useAspectRatio < 0 ? m_w : useAspectRatio * suggested_h)); - - if (suggested_w > m_w) - { - const float needed_scale_factor = (float)m_w / (float)suggested_w; - suggested_w = (int)(suggested_w*needed_scale_factor); - suggested_h = (int)(suggested_h*needed_scale_factor); - } - - bool left_horizontal = m_properties[PROP_ICON_ALIGN] == "left"; - bool right_horizontal = m_properties[PROP_ICON_ALIGN] == "right"; - - // Assume left align if align property is not specified, but x property is specified - if (m_properties[PROP_X].size() > 0 && m_properties[PROP_ICON_ALIGN].empty()) - { - left_horizontal = true; - } - - const int x_from = right_horizontal ? m_x + (m_w - suggested_w) : - left_horizontal ? m_x : - m_x + (m_w - suggested_w)/2; - const int y_from = m_y + (m_h - suggested_h)/2; // center vertically - - rect widget_size = rect(x_from, - y_from, - x_from + suggested_w, - y_from + suggested_h); - - if (m_scale_mode == SCALE_MODE_LIST_WIDGET) - { - m_list_header_icon_rect = widget_size; - m_list_header_icon_rect.UpperLeftCorner.X = m_list_header_icon_rect.UpperLeftCorner.X + 4; - m_list_header_icon_rect.UpperLeftCorner.Y = m_list_header_icon_rect.UpperLeftCorner.Y + 4; - m_list_header_icon_rect.LowerRightCorner.X = m_list_header_icon_rect.LowerRightCorner.X - 4; - m_list_header_icon_rect.LowerRightCorner.Y = m_list_header_icon_rect.LowerRightCorner.Y - 4; - widget_size = rect(m_x, m_y, m_x + m_w, m_y + m_h); - } - - IGUIButton* btn = GUIEngine::getGUIEnv()->addButton(widget_size, + updateIconRect(); + IGUIButton* btn = GUIEngine::getGUIEnv()->addButton(m_icon_rect, m_parent, (m_tab_stop ? getNewID() : getNewNoFocusID()), L""); @@ -194,55 +133,10 @@ void IconButtonWidget::add() const stringw& message = getText(); if (message.size() > 0) { - const int label_extra_size = - ( m_properties[PROP_EXTEND_LABEL].size() == 0 ? - 0 : atoi(m_properties[PROP_EXTEND_LABEL].c_str()) ); - - const bool word_wrap = (m_properties[PROP_WORD_WRAP] == "true"); - - if (m_properties[PROP_LABELS_LOCATION] == "hover") - { - core::dimension2du text_size = GUIEngine::getFont()->getDimension(message.c_str()); - core::recti pos = btn->getAbsolutePosition(); - int center_x = pos.UpperLeftCorner.X + pos.getWidth() / 2; - int x1 = center_x - text_size.Width / 2 - label_extra_size / 2; - int y1 = pos.UpperLeftCorner.Y - (word_wrap ? GUIEngine::getFontHeight() * 2 : - GUIEngine::getFontHeight()) - 15; - int x2 = center_x + text_size.Width / 2 + label_extra_size / 2; - int y2 = pos.UpperLeftCorner.Y - 15; - - if (x1 < 0) - { - int diff = -x1; - x1 += diff; - x2 += diff; - } - else if (x2 > (int)irr_driver->getActualScreenSize().Width) - { - int diff = x2 - irr_driver->getActualScreenSize().Width; - x2 -= diff; - x1 -= diff; - } - - core::recti parent_pos = m_parent->getAbsolutePosition(); - x1 -= parent_pos.UpperLeftCorner.X; - x2 -= parent_pos.UpperLeftCorner.X; - y1 -= parent_pos.UpperLeftCorner.Y; - y2 -= parent_pos.UpperLeftCorner.Y; - widget_size = rect(x1, y1, x2, y2); - } - else - { - // leave enough room for two lines of text if word wrap is enabled, otherwise a single line - widget_size = rect(m_x - label_extra_size/2, - m_y + m_h, - m_x + m_w + label_extra_size/2, - m_y + m_h + (word_wrap ? GUIEngine::getFontHeight()*2 : - GUIEngine::getFontHeight())); - } - - m_label = GUIEngine::getGUIEnv()->addStaticText(message.c_str(), widget_size, - false, word_wrap, m_parent); + updateLabelRect(); + m_label = GUIEngine::getGUIEnv()->addStaticText(message.c_str(), m_label_rect, + false, m_properties[PROP_WORD_WRAP] == "true", + m_parent); m_label->setTextAlignment(EGUIA_CENTER, EGUIA_UPPERLEFT); m_label->setTabStop(false); m_label->setNotClipped(true); @@ -460,3 +354,137 @@ void IconButtonWidget::setVisible(bool visible) m_label->setVisible(visible); } +// ----------------------------------------------------------------------------- +void IconButtonWidget::updateIconRect() +{ + // irrlicht widgets don't support scaling while keeping aspect ratio + // so, happily, let's implement it ourselves + float useAspectRatio = -1.0f; + + if (m_properties[PROP_CUSTOM_RATIO] != "") + { + StringUtils::fromString(m_properties[PROP_CUSTOM_RATIO], + m_custom_aspect_ratio); + m_scale_mode = SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO; + } + + if (m_scale_mode == SCALE_MODE_KEEP_TEXTURE_ASPECT_RATIO || + m_scale_mode == SCALE_MODE_LIST_WIDGET) + { + assert(m_texture->getOriginalSize().Height > 0); + useAspectRatio = (float)m_texture->getOriginalSize().Width / + (float)m_texture->getOriginalSize().Height; + } + else if (m_scale_mode == SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO) + { + useAspectRatio = m_custom_aspect_ratio; + } + + int suggested_h = m_h; + int suggested_w = (int)((useAspectRatio < 0 ? m_w : useAspectRatio * suggested_h)); + + if (suggested_w > m_w) + { + const float needed_scale_factor = (float)m_w / (float)suggested_w; + suggested_w = (int)(suggested_w*needed_scale_factor); + suggested_h = (int)(suggested_h*needed_scale_factor); + } + + bool left_horizontal = m_properties[PROP_ICON_ALIGN] == "left"; + bool right_horizontal = m_properties[PROP_ICON_ALIGN] == "right"; + + // Assume left align if align property is not specified, but x property is specified + if (m_properties[PROP_X].size() > 0 && m_properties[PROP_ICON_ALIGN].empty()) + { + left_horizontal = true; + } + + const int x_from = right_horizontal ? m_x + (m_w - suggested_w) : + left_horizontal ? m_x : + m_x + (m_w - suggested_w)/2; + const int y_from = m_y + (m_h - suggested_h)/2; // center vertically + + m_icon_rect = rect(x_from, + y_from, + x_from + suggested_w, + y_from + suggested_h); + + if (m_scale_mode == SCALE_MODE_LIST_WIDGET) + { + m_list_header_icon_rect = m_icon_rect; + m_list_header_icon_rect.UpperLeftCorner.X = m_list_header_icon_rect.UpperLeftCorner.X + 4; + m_list_header_icon_rect.UpperLeftCorner.Y = m_list_header_icon_rect.UpperLeftCorner.Y + 4; + m_list_header_icon_rect.LowerRightCorner.X = m_list_header_icon_rect.LowerRightCorner.X - 4; + m_list_header_icon_rect.LowerRightCorner.Y = m_list_header_icon_rect.LowerRightCorner.Y - 4; + m_icon_rect = rect(m_x, m_y, m_x + m_w, m_y + m_h); + } +} + +// ----------------------------------------------------------------------------- +void IconButtonWidget::updateLabelRect() +{ + if (!m_element) + return; + + const stringw& message = getText(); + const int label_extra_size = + ( m_properties[PROP_EXTEND_LABEL].size() == 0 ? + 0 : atoi(m_properties[PROP_EXTEND_LABEL].c_str()) ); + + const bool word_wrap = (m_properties[PROP_WORD_WRAP] == "true"); + + if (m_properties[PROP_LABELS_LOCATION] == "hover") + { + core::dimension2du text_size = GUIEngine::getFont()->getDimension(message.c_str()); + core::recti pos = m_element->getAbsolutePosition(); + int center_x = pos.UpperLeftCorner.X + pos.getWidth() / 2; + int x1 = center_x - text_size.Width / 2 - label_extra_size / 2; + int y1 = pos.UpperLeftCorner.Y - (word_wrap ? GUIEngine::getFontHeight() * 2 : + GUIEngine::getFontHeight()) - 15; + int x2 = center_x + text_size.Width / 2 + label_extra_size / 2; + int y2 = pos.UpperLeftCorner.Y - 15; + + if (x1 < 0) + { + int diff = -x1; + x1 += diff; + x2 += diff; + } + else if (x2 > (int)irr_driver->getActualScreenSize().Width) + { + int diff = x2 - irr_driver->getActualScreenSize().Width; + x2 -= diff; + x1 -= diff; + } + + core::recti parent_pos = m_parent->getAbsolutePosition(); + x1 -= parent_pos.UpperLeftCorner.X; + x2 -= parent_pos.UpperLeftCorner.X; + y1 -= parent_pos.UpperLeftCorner.Y; + y2 -= parent_pos.UpperLeftCorner.Y; + m_label_rect = rect(x1, y1, x2, y2); + } + else + { + // leave enough room for two lines of text if word wrap is enabled, otherwise a single line + m_label_rect = rect(m_x - label_extra_size/2, + m_y + m_h, + m_x + m_w + label_extra_size/2, + m_y + m_h + (word_wrap ? GUIEngine::getFontHeight()*2 : + GUIEngine::getFontHeight())); + } +} + +// ----------------------------------------------------------------------------- +void IconButtonWidget::resize() +{ + updateIconRect(); + if (m_element) + m_element->setRelativePosition(m_icon_rect); + if (m_label) + { + updateLabelRect(); + m_label->setRelativePosition(m_label_rect); + setLabelFont(); + } +} diff --git a/src/guiengine/widgets/icon_button_widget.hpp b/src/guiengine/widgets/icon_button_widget.hpp index d26c02ed74c..458c9d88e4a 100644 --- a/src/guiengine/widgets/icon_button_widget.hpp +++ b/src/guiengine/widgets/icon_button_widget.hpp @@ -43,7 +43,7 @@ namespace GUIEngine class IconButtonWidget : public Widget { private: - irr::core::rect m_list_header_icon_rect; + irr::core::rect m_list_header_icon_rect, m_icon_rect, m_label_rect; irr::video::ITexture* m_texture; irr::video::ITexture* m_deactivated_texture; irr::video::ITexture* m_highlight_texture; @@ -51,6 +51,8 @@ namespace GUIEngine video::ITexture* getDeactivatedTexture(video::ITexture* texture); void setLabelFont(); + void updateIconRect(); + void updateLabelRect(); public: enum ScaleMode @@ -173,6 +175,8 @@ namespace GUIEngine m_label = NULL; } // -------------------------------------------------------------------- + virtual void resize() OVERRIDE; + // -------------------------------------------------------------------- const irr::core::rect& getListHeaderIconRect() const { return m_list_header_icon_rect; From 3641183121e56e2aa472d7cee8e16f7400a4c1e9 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sat, 20 Apr 2024 18:55:31 +0800 Subject: [PATCH 314/830] Add resizing code for ribbon widget --- .../widgets/dynamic_ribbon_widget.cpp | 1 + src/guiengine/widgets/ribbon_widget.cpp | 718 ++++++++++-------- src/guiengine/widgets/ribbon_widget.hpp | 12 +- src/states_screens/dialogs/addons_loading.cpp | 1 + .../dialogs/server_info_dialog.cpp | 1 + .../online/networking_lobby.cpp | 1 + 6 files changed, 408 insertions(+), 326 deletions(-) diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.cpp b/src/guiengine/widgets/dynamic_ribbon_widget.cpp index ad4b77bb438..8e7b5dc3d86 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.cpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include diff --git a/src/guiengine/widgets/ribbon_widget.cpp b/src/guiengine/widgets/ribbon_widget.cpp index 43185b95d2b..4c4358d62d1 100644 --- a/src/guiengine/widgets/ribbon_widget.cpp +++ b/src/guiengine/widgets/ribbon_widget.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include using namespace GUIEngine; @@ -82,6 +83,7 @@ void RibbonWidget::add() m_labels.clearWithoutDeleting(); + m_child_data.clear(); rect widget_size = rect(m_x, m_y, m_x + m_w, m_y + m_h); @@ -101,181 +103,34 @@ void RibbonWidget::add() } const int subbuttons_amount = m_active_children.size(); - // For some ribbon types, we can have unequal sizes depending on whether - // items have labels or not - int with_label = 0; - int without_label = 0; - - // ---- check how much space each child button will take and fit - // them within available space - int total_needed_space = 0; - for (int i=0; im_tab_stop = false; - } - - - bool has_label_underneath = m_active_children[i].m_text.size() > 0; - if (m_active_children[i].m_properties[PROP_LABELS_LOCATION].size() > 0) - { - has_label_underneath = false; - } - - if (has_label_underneath) with_label++; - else without_label++; - - total_needed_space += m_active_children[i].m_w; - } - - //int biggest_y = 0; - const int button_y = GUIEngine::getFontHeight() / 5; - - const int one_button_width = (subbuttons_amount == 0 ? m_w : - int(roundf((float)m_w / (float)subbuttons_amount))); - - const int one_button_height = (subbuttons_amount == 0 ? m_h : - int(roundf((float)m_h / (float)subbuttons_amount))); - - int widget_x = -1; - int widget_y = -1; - + rect init_rect = rect(0, 0, 1, 1); // ---- add children // TODO : the content of the ifs is way too large, separate functions would be better. // Several pre-loop variables are used inside the ifs, // so care must be taken to not break things for (int i=0; i tab_rect_abs; - - if (message.size() == 0) - { - tab_rect_abs = rect(widget_x - small_tab/2 + HORZ_MARGIN, VERT_MARGIN, - widget_x + small_tab/2 - HORZ_MARGIN, m_h - VERT_MARGIN); - } - else - { - tab_rect_abs = rect(widget_x - large_tab/2 + HORZ_MARGIN, VERT_MARGIN, - widget_x + large_tab/2 - HORZ_MARGIN, m_h - VERT_MARGIN); - } - - // Once height is available to us, adjust for scaling - TOP_BORDER = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)TOP_BORDER ); - BOTTOM_BORDER = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)BOTTOM_BORDER ); - LEFT_BORDER = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)LEFT_BORDER ); - RIGHT_BORDER = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)RIGHT_BORDER ); - - HORZ_PADDING = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)HORZ_PADDING ); - VERT_PADDING = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)VERT_PADDING ); - - // Automatically guess from position on-screen if tabs go up or down - RibbonFlip flip = getRibbonFlip(); - bool vertical_flip = (unsigned int)widget_size.UpperLeftCorner.Y < - irr_driver->getActualScreenSize().Height / 2; - // Force flip direction when the direction is defined - if(flip == FLIP_UP_LEFT) - vertical_flip = true; - else if(flip == FLIP_DOWN_RIGHT) - vertical_flip = false; - - if (vertical_flip) - swap(TOP_BORDER, BOTTOM_BORDER); - - // Used to position sub-elements, coords needs to be relative to tab_rect_abs - rect tab_contents_rect = rect(LEFT_BORDER + HORZ_PADDING, - TOP_BORDER + VERT_PADDING, - tab_rect_abs.getWidth() - RIGHT_BORDER - HORZ_PADDING, - tab_rect_abs.getHeight() - BOTTOM_BORDER - VERT_PADDING); - if (m_active_children[i].m_type == WTYPE_ICON_BUTTON || m_active_children[i].m_type == WTYPE_BUTTON) { - rect icon_part = rect(tab_contents_rect.UpperLeftCorner.X, - tab_contents_rect.UpperLeftCorner.Y, - tab_contents_rect.UpperLeftCorner.X + tab_contents_rect.getHeight(), - tab_contents_rect.UpperLeftCorner.Y + tab_contents_rect.getHeight()); - - if (message.size() == 0) - { - const int x = tab_contents_rect.getWidth()/2 - tab_contents_rect.getHeight()/2; - // no label, only icon, so center the icon - icon_part = rect(tab_contents_rect.UpperLeftCorner.X + x, - tab_contents_rect.UpperLeftCorner.Y, - tab_contents_rect.UpperLeftCorner.X + x + tab_contents_rect.getHeight(), - tab_contents_rect.UpperLeftCorner.Y + tab_contents_rect.getHeight()); - } - - rect label_part = rect(tab_contents_rect.UpperLeftCorner.X, - tab_contents_rect.UpperLeftCorner.Y, - tab_contents_rect.LowerRightCorner.X, - tab_contents_rect.LowerRightCorner.Y); - - // label at the *right* of the icon (for tabs) - if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) - label_part.UpperLeftCorner.X += icon_part.getWidth() + 15; - // use the same ID for all subcomponents; since event handling // is done per-ID, no matter which one your hover, this // widget will get it int same_id = getNewNoFocusID(); - tab = GUIEngine::getGUIEnv()->addButton(tab_rect_abs, btn, + tab = GUIEngine::getGUIEnv()->addButton(init_rect, btn, same_id, L"", L""); + IGUIButton* icon = NULL; if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) { - IGUIButton* icon = - GUIEngine::getGUIEnv()->addButton(icon_part, tab, + icon = + GUIEngine::getGUIEnv()->addButton(init_rect, tab, same_id, L""); icon->setScaleImage(true); std::string filename = GUIEngine::getSkin()->getThemedIcon( @@ -288,24 +143,16 @@ void RibbonWidget::add() IGUIStaticText* label = GUIEngine::getGUIEnv()->addStaticText(message.c_str(), - label_part, + init_rect, false /* border */, true /* word wrap */, tab, same_id); - if ((int)GUIEngine::getFont()->getDimension(message.c_str()) - .Width > label_part.getWidth()&& - message.findFirst(L' ') == -1 && - message.findFirst(L'\u00AD') == -1 ) - { - // if message too long and contains no space and no soft - // hyphen, make the font smaller - label->setOverrideFont(GUIEngine::getSmallFont()); - } label->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER); label->setTabStop(false); label->setNotClipped(true); m_labels.push_back(label); + m_child_data[i] = std::make_pair(label, icon); tab->setTabStop(false); tab->setTabGroup(false); @@ -316,74 +163,28 @@ void RibbonWidget::add() } m_active_children[i].m_element = tab; - - if (message.size() == 0) widget_x += small_tab/2; - else widget_x += large_tab/2; } // tabs // ---- vertical tab ribbons else if (getRibbonType() == RIBBON_VERTICAL_TABS) { - const int tab_width = (int)((with_label + without_label) - *m_w - / (with_label + without_label/2.0f)); - stringw& message = m_active_children[i].m_text; - widget_x = tab_width/2; - - if (widget_y == -1) - widget_y = 0; - else - widget_y += one_button_height; - IGUIButton * tab = NULL; - rect tab_rect_abs = rect(widget_x - (tab_width/2) - HORZ_MARGIN, widget_y + VERT_MARGIN, - widget_x + (tab_width/2) + HORZ_MARGIN, widget_y + one_button_height - VERT_MARGIN); - - // Once height is available to us, adjust for scaling - TOP_BORDER = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)TOP_BORDER ); - BOTTOM_BORDER = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)BOTTOM_BORDER ); - LEFT_BORDER = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)LEFT_BORDER ); - RIGHT_BORDER = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)RIGHT_BORDER ); - - HORZ_PADDING = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)HORZ_PADDING ); - VERT_PADDING = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)VERT_PADDING ); - - // Used to position sub-elements, coords needs to be relative to tab_rect_abs - rect tab_contents_rect = rect(LEFT_BORDER + HORZ_PADDING, - TOP_BORDER + VERT_PADDING, - tab_rect_abs.getWidth() - RIGHT_BORDER - HORZ_PADDING, - tab_rect_abs.getHeight() - BOTTOM_BORDER - VERT_PADDING); - // TODO Add support for BUTTON type when needed if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) { - int icon_size = std::min(tab_contents_rect.getHeight(), tab_contents_rect.getWidth()/2); - const int y = tab_contents_rect.getHeight()/2 - icon_size/2; - - rect icon_part = rect(tab_contents_rect.UpperLeftCorner.X, - tab_contents_rect.UpperLeftCorner.Y + y, - tab_contents_rect.UpperLeftCorner.X + icon_size, - tab_contents_rect.UpperLeftCorner.Y + y + icon_size); - - // label at the *right* of the icon (for tabs) - rect label_part = rect(icon_part.LowerRightCorner.X+5, - tab_contents_rect.UpperLeftCorner.Y, - tab_contents_rect.LowerRightCorner.X, - tab_contents_rect.LowerRightCorner.Y); - // use the same ID for all subcomponents; since event handling // is done per-ID, no matter which one your hover, this // widget will get it int same_id = getNewNoFocusID(); - tab = GUIEngine::getGUIEnv()->addButton(tab_rect_abs, btn, + tab = GUIEngine::getGUIEnv()->addButton(init_rect, btn, same_id, L"", L""); IGUIButton* icon = - GUIEngine::getGUIEnv()->addButton(icon_part, tab, + GUIEngine::getGUIEnv()->addButton(init_rect, tab, same_id, L""); icon->setScaleImage(true); std::string filename = GUIEngine::getSkin()->getThemedIcon( @@ -395,28 +196,16 @@ void RibbonWidget::add() IGUIStaticText* label = GUIEngine::getGUIEnv()->addStaticText(message.c_str(), - label_part, + init_rect, false /* border */, true /* word wrap */, tab, same_id); - if (((int)GUIEngine::getFont()->getDimension(message.c_str()) - .Width > label_part.getWidth() && - message.findFirst(L' ') == -1 && - message.findFirst(L'\u00AD') == -1) || - ((int)GUIEngine::getFont()->getDimension(message.c_str()) - .Width > label_part.getWidth() && - (int)GUIEngine::getFont()->getDimension(message.c_str()) - .Height*2 > label_part.getHeight())) - { - // if message is too long and contains no space and no soft - // hyphen, or too tall, make the font smaller - label->setOverrideFont(GUIEngine::getSmallFont()); - } label->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER); label->setTabStop(false); label->setNotClipped(true); m_labels.push_back(label); + m_child_data[i] = std::make_pair(label, icon); tab->setTabStop(false); tab->setTabGroup(false); @@ -433,111 +222,37 @@ void RibbonWidget::add() // ---- icon ribbons else if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) { - if (widget_x == -1) widget_x = one_button_width/2; + m_active_children.get(i)->m_parent = btn; + m_active_children.get(i)->add(); + } + else + { + Log::warn("RibbonWidget", "Invalid contents type in ribbon"); + } + //m_children[i].id = tab->getID(); + m_active_children[i].m_event_handler = this; + }// next sub-button - // find how much space to keep for the label under the button. - // consider font size, whether the label is multiline, etc... - bool has_label = m_active_children[i].m_text.size() > 0; + resize(); + id = m_element->getID(); + m_element->setTabOrder(id); + m_element->setTabGroup(false); + updateSelection(); - if (m_active_children[i].m_properties[PROP_LABELS_LOCATION].size() > 0) - { - has_label = false; - } + if (!m_is_visible) + setVisible(false); +} // add - const int needed_space_under_button = has_label - ? GUIEngine::getFontHeight() - : GUIEngine::getFontHeight() / 5; +// ---------------------------------------------------------------------------- - float imageRatio = - (float)m_active_children[i].m_w / (float)m_active_children[i].m_h; +void RibbonWidget::addTextChild(const core::stringw& text, const std::string &id) +{ + // This method should only be called BEFORE a widget is added + assert(m_element == NULL); - // calculate the size of the image - std::string filename = - GUIEngine::getSkin()->getThemedIcon(m_active_children[i].m_properties[PROP_ICON]); - - video::ITexture* image = - irr_driver->getTexture((filename).c_str()); - if(!image) - { - std::string file = file_manager->getAsset(FileManager::GUI_ICON,"main_help.png"); - image = irr_driver->getTexture(file); - if(!image) - Log::fatal("RibbonWidget", - "Can't find fallback texture 'main_help.png', aborting."); - } - - float image_h = (float)image->getSize().Height; - float image_w = image_h*imageRatio; - float zoom = (float) (m_h - button_y - needed_space_under_button) / image_h; - float zoom_x = (float) one_button_width / image_w; - if(zoom_x < zoom) - zoom = zoom_x; - - // ---- add bitmap button part - // backup and restore position in case the same object is added - // multiple times (FIXME: unclean) - int old_x = m_active_children[i].m_x; - int old_y = m_active_children[i].m_y; - int old_w = m_active_children[i].m_w; - int old_h = m_active_children[i].m_h; - - m_active_children[i].m_x = widget_x - int(image_w*zoom/2.0f); - m_active_children[i].m_y = button_y; - m_active_children[i].m_w = int(image_w*zoom); - m_active_children[i].m_h = int(image_h*zoom); - - IconButtonWidget* icon = ((IconButtonWidget*)m_active_children.get(i)); - - if (icon->m_properties[PROP_EXTEND_LABEL].size() == 0) - { - icon->m_properties[PROP_EXTEND_LABEL] = - StringUtils::toString(one_button_width - icon->m_w); - } - - m_active_children.get(i)->m_parent = btn; - m_active_children.get(i)->add(); - - // restore backuped size and location (see above for more info) - m_active_children[i].m_x = old_x; - m_active_children[i].m_y = old_y; - m_active_children[i].m_w = old_w; - m_active_children[i].m_h = old_h; - - // the label itself will be added by the icon widget. since it - // adds the label outside of the widget area it is assigned to, - // the label will appear in the area we want at the bottom - - widget_x += one_button_width; - } - else - { - Log::warn("RibbonWidget", "Invalid contents type in ribbon"); - } - - - //m_children[i].id = tab->getID(); - m_active_children[i].m_event_handler = this; - }// next sub-button - - id = m_element->getID(); - m_element->setTabOrder(id); - m_element->setTabGroup(false); - updateSelection(); - - if (!m_is_visible) - setVisible(false); -} // add - -// ---------------------------------------------------------------------------- - -void RibbonWidget::addTextChild(const core::stringw& text, const std::string &id) -{ - // This method should only be called BEFORE a widget is added - assert(m_element == NULL); - - ButtonWidget* item = new ButtonWidget(); - item->m_text = text; - item->m_properties[PROP_ID] = id; + ButtonWidget* item = new ButtonWidget(); + item->m_text = text; + item->m_properties[PROP_ID] = id; m_children.push_back(item); } // addTextChild @@ -1006,3 +721,358 @@ Widget* RibbonWidget::findWidgetNamed(const char* internalName) return m_children.get(id); return NULL; } // findWidgetNamed + +// ---------------------------------------------------------------------------- +void RibbonWidget::resize() +{ + Widget::resize(); + + rect widget_size = rect(m_x, m_y, m_x + m_w, m_y + m_h); + const int subbuttons_amount = m_active_children.size(); + + // For some ribbon types, we can have unequal sizes depending on whether + // items have labels or not + int with_label = 0; + int without_label = 0; + + // ---- check how much space each child button will take and fit + // them within available space + for (int i=0; i 0; + if (m_active_children[i].m_properties[PROP_LABELS_LOCATION].size() > 0) + { + has_label_underneath = false; + } + + if (has_label_underneath) with_label++; + else without_label++; + + } + + const int button_y = GUIEngine::getFontHeight() / 5; + + const int one_button_width = (subbuttons_amount == 0 ? m_w : + int(roundf((float)m_w / (float)subbuttons_amount))); + + const int one_button_height = (subbuttons_amount == 0 ? m_h : + int(roundf((float)m_h / (float)subbuttons_amount))); + + int widget_x = -1; + int widget_y = -1; + + // ---- add children + // TODO : the content of the ifs is way too large, separate functions would be better. + // Several pre-loop variables are used inside the ifs, + // so care must be taken to not break things + for (int i=0; i tab_rect_abs; + + if (message.size() == 0) + { + tab_rect_abs = rect(widget_x - small_tab/2 + HORZ_MARGIN, VERT_MARGIN, + widget_x + small_tab/2 - HORZ_MARGIN, m_h - VERT_MARGIN); + } + else + { + tab_rect_abs = rect(widget_x - large_tab/2 + HORZ_MARGIN, VERT_MARGIN, + widget_x + large_tab/2 - HORZ_MARGIN, m_h - VERT_MARGIN); + } + + // Once height is available to us, adjust for scaling + TOP_BORDER = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)TOP_BORDER ); + BOTTOM_BORDER = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)BOTTOM_BORDER ); + LEFT_BORDER = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)LEFT_BORDER ); + RIGHT_BORDER = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)RIGHT_BORDER ); + + HORZ_PADDING = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)HORZ_PADDING ); + VERT_PADDING = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)VERT_PADDING ); + + // Automatically guess from position on-screen if tabs go up or down + RibbonFlip flip = getRibbonFlip(); + bool vertical_flip = (unsigned int)widget_size.UpperLeftCorner.Y < + irr_driver->getActualScreenSize().Height / 2; + // Force flip direction when the direction is defined + if(flip == FLIP_UP_LEFT) + vertical_flip = true; + else if(flip == FLIP_DOWN_RIGHT) + vertical_flip = false; + + if (vertical_flip) + swap(TOP_BORDER, BOTTOM_BORDER); + + // Used to position sub-elements, coords needs to be relative to tab_rect_abs + rect tab_contents_rect = rect(LEFT_BORDER + HORZ_PADDING, + TOP_BORDER + VERT_PADDING, + tab_rect_abs.getWidth() - RIGHT_BORDER - HORZ_PADDING, + tab_rect_abs.getHeight() - BOTTOM_BORDER - VERT_PADDING); + + if (m_active_children[i].m_type == WTYPE_ICON_BUTTON || m_active_children[i].m_type == WTYPE_BUTTON) + { + rect icon_part = rect(tab_contents_rect.UpperLeftCorner.X, + tab_contents_rect.UpperLeftCorner.Y, + tab_contents_rect.UpperLeftCorner.X + tab_contents_rect.getHeight(), + tab_contents_rect.UpperLeftCorner.Y + tab_contents_rect.getHeight()); + + if (message.size() == 0) + { + const int x = tab_contents_rect.getWidth()/2 - tab_contents_rect.getHeight()/2; + // no label, only icon, so center the icon + icon_part = rect(tab_contents_rect.UpperLeftCorner.X + x, + tab_contents_rect.UpperLeftCorner.Y, + tab_contents_rect.UpperLeftCorner.X + x + tab_contents_rect.getHeight(), + tab_contents_rect.UpperLeftCorner.Y + tab_contents_rect.getHeight()); + } + + rect label_part = rect(tab_contents_rect.UpperLeftCorner.X, + tab_contents_rect.UpperLeftCorner.Y, + tab_contents_rect.LowerRightCorner.X, + tab_contents_rect.LowerRightCorner.Y); + + // label at the *right* of the icon (for tabs) + if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) + label_part.UpperLeftCorner.X += icon_part.getWidth() + 15; + + m_active_children[i].m_element->setRelativePosition(tab_rect_abs); + if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) + m_child_data.at(i).second->setRelativePosition(icon_part); + IGUIStaticText* label = m_child_data.at(i).first; + label->setRelativePosition(label_part); + + if ((int)GUIEngine::getFont()->getDimension(message.c_str()) + .Width > label_part.getWidth()&& + message.findFirst(L' ') == -1 && + message.findFirst(L'\u00AD') == -1 ) + { + // if message too long and contains no space and no soft + // hyphen, make the font smaller + label->setOverrideFont(GUIEngine::getSmallFont()); + } + else + { + label->setOverrideFont(GUIEngine::getFont()); + } + } + else + { + Log::error("RibbonWidget", "Invalid tab bar contents"); + } + + if (message.size() == 0) widget_x += small_tab/2; + else widget_x += large_tab/2; + } // tabs + + + // ---- vertical tab ribbons + else if (getRibbonType() == RIBBON_VERTICAL_TABS) + { + const int tab_width = (int)((with_label + without_label) + *m_w + / (with_label + without_label/2.0f)); + + stringw& message = m_active_children[i].m_text; + + widget_x = tab_width/2; + + if (widget_y == -1) + widget_y = 0; + else + widget_y += one_button_height; + + rect tab_rect_abs = rect(widget_x - (tab_width/2) - HORZ_MARGIN, widget_y + VERT_MARGIN, + widget_x + (tab_width/2) + HORZ_MARGIN, widget_y + one_button_height - VERT_MARGIN); + + // Once height is available to us, adjust for scaling + TOP_BORDER = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)TOP_BORDER ); + BOTTOM_BORDER = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)BOTTOM_BORDER ); + LEFT_BORDER = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)LEFT_BORDER ); + RIGHT_BORDER = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)RIGHT_BORDER ); + + HORZ_PADDING = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)HORZ_PADDING ); + VERT_PADDING = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)VERT_PADDING ); + + // Used to position sub-elements, coords needs to be relative to tab_rect_abs + rect tab_contents_rect = rect(LEFT_BORDER + HORZ_PADDING, + TOP_BORDER + VERT_PADDING, + tab_rect_abs.getWidth() - RIGHT_BORDER - HORZ_PADDING, + tab_rect_abs.getHeight() - BOTTOM_BORDER - VERT_PADDING); + + // TODO Add support for BUTTON type when needed + if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) + { + int icon_size = std::min(tab_contents_rect.getHeight(), tab_contents_rect.getWidth()/2); + const int y = tab_contents_rect.getHeight()/2 - icon_size/2; + + rect icon_part = rect(tab_contents_rect.UpperLeftCorner.X, + tab_contents_rect.UpperLeftCorner.Y + y, + tab_contents_rect.UpperLeftCorner.X + icon_size, + tab_contents_rect.UpperLeftCorner.Y + y + icon_size); + + // label at the *right* of the icon (for tabs) + rect label_part = rect(icon_part.LowerRightCorner.X+5, + tab_contents_rect.UpperLeftCorner.Y, + tab_contents_rect.LowerRightCorner.X, + tab_contents_rect.LowerRightCorner.Y); + + m_active_children[i].m_element->setRelativePosition(tab_rect_abs); + IGUIStaticText* label = m_child_data.at(i).first; + label->setRelativePosition(label_part); + m_child_data.at(i).second->setRelativePosition(icon_part); + + if (((int)GUIEngine::getFont()->getDimension(message.c_str()) + .Width > label_part.getWidth() && + message.findFirst(L' ') == -1 && + message.findFirst(L'\u00AD') == -1) || + ((int)GUIEngine::getFont()->getDimension(message.c_str()) + .Width > label_part.getWidth() && + (int)GUIEngine::getFont()->getDimension(message.c_str()) + .Height*2 > label_part.getHeight())) + { + // if message is too long and contains no space and no soft + // hyphen, or too tall, make the font smaller + label->setOverrideFont(GUIEngine::getSmallFont()); + } + else + { + label->setOverrideFont(GUIEngine::getFont()); + } + } + else + { + Log::error("RibbonWidget", "Invalid tab bar contents"); + } + + } // vertical-tabs + + + // ---- icon ribbons + else if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) + { + if (widget_x == -1) widget_x = one_button_width/2; + + // find how much space to keep for the label under the button. + // consider font size, whether the label is multiline, etc... + bool has_label = m_active_children[i].m_text.size() > 0; + + if (m_active_children[i].m_properties[PROP_LABELS_LOCATION].size() > 0) + { + has_label = false; + } + + const int needed_space_under_button = has_label + ? GUIEngine::getFontHeight() + : GUIEngine::getFontHeight() / 5; + + float imageRatio = + (float)m_active_children[i].m_w / (float)m_active_children[i].m_h; + + // calculate the size of the image + std::string filename = + GUIEngine::getSkin()->getThemedIcon(m_active_children[i].m_properties[PROP_ICON]); + + video::ITexture* image = + irr_driver->getTexture((filename).c_str()); + if(!image) + { + std::string file = file_manager->getAsset(FileManager::GUI_ICON,"main_help.png"); + image = irr_driver->getTexture(file); + if(!image) + Log::fatal("RibbonWidget", + "Can't find fallback texture 'main_help.png', aborting."); + } + + float image_h = (float)image->getSize().Height; + float image_w = image_h*imageRatio; + float zoom = (float) (m_h - button_y - needed_space_under_button) / image_h; + float zoom_x = (float) one_button_width / image_w; + if(zoom_x < zoom) + zoom = zoom_x; + + // ---- add bitmap button part + // backup and restore position in case the same object is added + // multiple times (FIXME: unclean) + int old_x = m_active_children[i].m_x; + int old_y = m_active_children[i].m_y; + int old_w = m_active_children[i].m_w; + int old_h = m_active_children[i].m_h; + + m_active_children[i].m_x = widget_x - int(image_w*zoom/2.0f); + m_active_children[i].m_y = button_y; + m_active_children[i].m_w = int(image_w*zoom); + m_active_children[i].m_h = int(image_h*zoom); + + IconButtonWidget* icon = ((IconButtonWidget*)m_active_children.get(i)); + + if (icon->m_properties[PROP_EXTEND_LABEL].size() == 0) + { + icon->m_properties[PROP_EXTEND_LABEL] = + StringUtils::toString(one_button_width - icon->m_w); + } + m_active_children.get(i)->resize(); + + // restore backuped size and location (see above for more info) + m_active_children[i].m_x = old_x; + m_active_children[i].m_y = old_y; + m_active_children[i].m_w = old_w; + m_active_children[i].m_h = old_h; + + // the label itself will be added by the icon widget. since it + // adds the label outside of the widget area it is assigned to, + // the label will appear in the area we want at the bottom + + widget_x += one_button_width; + } + else + { + Log::warn("RibbonWidget", "Invalid contents type in ribbon"); + } + + }// next sub-button + +} // resize diff --git a/src/guiengine/widgets/ribbon_widget.hpp b/src/guiengine/widgets/ribbon_widget.hpp index 5aa6aed6fb8..5cb05414052 100644 --- a/src/guiengine/widgets/ribbon_widget.hpp +++ b/src/guiengine/widgets/ribbon_widget.hpp @@ -28,7 +28,13 @@ #include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" -#include +#include + +namespace irr +{ + namespace gui { class IGUIButton; class IGUIStaticText; } +} + namespace GUIEngine { @@ -109,7 +115,7 @@ namespace GUIEngine IRibbonListener* m_listener; PtrVector m_active_children; - + std::map > m_child_data; public: LEAK_CHECK() @@ -224,6 +230,8 @@ namespace GUIEngine PtrVector& getRibbonChildren() { return m_children; } virtual EventPropagation onActivationInput(const int playerID) OVERRIDE; + + virtual void resize() OVERRIDE; }; } diff --git a/src/states_screens/dialogs/addons_loading.cpp b/src/states_screens/dialogs/addons_loading.cpp index e65b0a87a82..5361018750b 100644 --- a/src/states_screens/dialogs/addons_loading.cpp +++ b/src/states_screens/dialogs/addons_loading.cpp @@ -45,6 +45,7 @@ #include "utils/string_utils.hpp" #include "utils/translation.hpp" +#include #include using namespace GUIEngine; diff --git a/src/states_screens/dialogs/server_info_dialog.cpp b/src/states_screens/dialogs/server_info_dialog.cpp index 8999a455e6a..e23bd446224 100644 --- a/src/states_screens/dialogs/server_info_dialog.cpp +++ b/src/states_screens/dialogs/server_info_dialog.cpp @@ -38,6 +38,7 @@ #include #include +#include using namespace GUIEngine; using namespace irr; diff --git a/src/states_screens/online/networking_lobby.cpp b/src/states_screens/online/networking_lobby.cpp index f42833491f8..96f70f8ce7e 100644 --- a/src/states_screens/online/networking_lobby.cpp +++ b/src/states_screens/online/networking_lobby.cpp @@ -59,6 +59,7 @@ #include "utils/translation.hpp" #include +#include using namespace Online; using namespace GUIEngine; From 2a60d6508b2552156cebb425fb248c2bf3853be6 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 21 Apr 2024 13:24:07 +0800 Subject: [PATCH 315/830] Add resizing code for list widget --- src/guiengine/widgets/list_widget.cpp | 100 ++++++++++++++++---------- src/guiengine/widgets/list_widget.hpp | 5 ++ 2 files changed, 68 insertions(+), 37 deletions(-) diff --git a/src/guiengine/widgets/list_widget.cpp b/src/guiengine/widgets/list_widget.cpp index 8a6c05e000a..6f7d847d6db 100644 --- a/src/guiengine/widgets/list_widget.cpp +++ b/src/guiengine/widgets/list_widget.cpp @@ -93,22 +93,30 @@ void ListWidget::setIcons(STKModifiedSpriteBank* icons, int size) } - // ----------------------------------------------------------------------------- -void ListWidget::add() +int ListWidget::getHeaderHeight() const { - const int header_height = GUIEngine::getFontHeight() + 15; + return GUIEngine::getFontHeight() + 15; +} - rect widget_size = (m_header.size() > 0 ? rect(m_x, m_y + header_height, m_x + m_w, m_y + m_h) : - rect(m_x, m_y, m_x + m_w, m_y + m_h) ); +// ----------------------------------------------------------------------------- +rect ListWidget::getListBoxSize() const +{ + return m_header.size() > 0 ? + rect(m_x, m_y + getHeaderHeight(), m_x + m_w, m_y + m_h) : + rect(m_x, m_y, m_x + m_w, m_y + m_h); +} +// ----------------------------------------------------------------------------- +void ListWidget::add() +{ IGUISkin * current_skin = GUIEngine::getGUIEnv()->getSkin(); IGUIFont * current_font = GUIEngine::getGUIEnv()->getBuiltInFont(); CGUISTKListBox * list_box = new CGUISTKListBox( GUIEngine::getGUIEnv(), m_parent ? m_parent : GUIEngine::getGUIEnv()->getRootGUIElement(), getNewID(), - widget_size, + getListBoxSize(), true, true, false); @@ -140,20 +148,8 @@ void ListWidget::createHeader() if (m_header_created) return; - const int header_height = GUIEngine::getFontHeight() + 15; - if (m_header.size() > 0) { - //const int col_size = m_w / m_header.size(); - - int proportion_total = 0; - for (unsigned int n=0; ngetSize(EGDS_SCROLLBAR_SIZE); for (unsigned int n=0; nm_reserved_id = getNewNoFocusID(); - - header->m_y = m_y; - header->m_h = header_height; - - header->m_x = x; - if (n == m_header.size()) - { - header->m_w = scrollbar_width; - header->setActive(false); - } - else - { - int header_width = m_w - scrollbar_width; - header->m_w = (int)(header_width * float(m_header[n].m_proportion) - /float(proportion_total)); - } - - x += header->m_w; - header->m_properties[PROP_ID] = name.str(); header->add(); @@ -210,6 +187,8 @@ void ListWidget::createHeader() m_check_inside_me = true; } m_header_created = true; + + updateHeader(); } // createHeader // ----------------------------------------------------------------------------- @@ -671,3 +650,50 @@ void ListWidget::setActive(bool active) Widget::setActive(active); getIrrlichtElement()->setDisactivated(!active); } + +// ----------------------------------------------------------------------------- +void ListWidget::updateHeader() +{ + if (m_header.size() > 0) + { + int proportion_total = 0; + for (unsigned int n = 0; n < m_header.size(); n++) + { + proportion_total += m_header[n].m_proportion; + } + + int x = m_x; + int scrollbar_width = GUIEngine::getSkin()->getSize(EGDS_SCROLLBAR_SIZE); + for (unsigned int n = 0; n < m_header.size() + 1; n++) + { + Widget* header = m_header_elements.get(n); + header->m_y = m_y; + header->m_h = getHeaderHeight(); + + header->m_x = x; + if (n == m_header.size()) + { + header->m_w = scrollbar_width; + header->setActive(false); + } + else + { + int header_width = m_w - scrollbar_width; + header->m_w = (int)(header_width * float(m_header[n].m_proportion) + / float(proportion_total)); + header->setActive(true); + } + + x += header->m_w; + header->resize(); + } + } +} + +// ----------------------------------------------------------------------------- +void ListWidget::resize() +{ + if (m_element) + m_element->setRelativePosition(getListBoxSize()); + updateHeader(); +} diff --git a/src/guiengine/widgets/list_widget.hpp b/src/guiengine/widgets/list_widget.hpp index f72a891a262..d4b709a72d2 100644 --- a/src/guiengine/widgets/list_widget.hpp +++ b/src/guiengine/widgets/list_widget.hpp @@ -108,6 +108,10 @@ namespace GUIEngine m_sort_col = 0; } + void updateHeader(); + int getHeaderHeight() const; + irr::core::rect getListBoxSize() const; + public: typedef irr::gui::CGUISTKListBox::ListItem ListItem; typedef ListItem::ListCell ListCell; @@ -302,6 +306,7 @@ namespace GUIEngine void setSortable(bool sortable) { m_sortable = sortable; } void focusHeader(const NavigationDirection nav); virtual void setActive(bool active=true); + virtual void resize(); }; } From af1238d688e79762d4de4ccee153383874d9932c Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 21 Apr 2024 14:05:34 +0800 Subject: [PATCH 316/830] Backport irrlicht changes to CGUISTKListBox --- src/guiengine/widgets/CGUISTKListBox.cpp | 22 ++++++++++++++++------ src/guiengine/widgets/CGUISTKListBox.hpp | 1 + 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/guiengine/widgets/CGUISTKListBox.cpp b/src/guiengine/widgets/CGUISTKListBox.cpp index b4c5cc498fa..ecf7b0ff61a 100644 --- a/src/guiengine/widgets/CGUISTKListBox.cpp +++ b/src/guiengine/widgets/CGUISTKListBox.cpp @@ -40,11 +40,8 @@ CGUISTKListBox::CGUISTKListBox(IGUIEnvironment* environment, IGUIElement* parent #endif IGUISkin* skin = Environment->getSkin(); - const s32 s = skin->getSize(EGDS_SCROLLBAR_SIZE); - ScrollBar = Environment->addScrollBar(false, - core::rect(RelativeRect.getWidth() - s, 0, - RelativeRect.getWidth(), RelativeRect.getHeight()), this, -1); + ScrollBar = Environment->addScrollBar(false, core::recti(0, 0, 1, 1), this, -1); ScrollBar->grab(); ScrollBar->setSubElement(true); ScrollBar->setTabStop(false); @@ -52,6 +49,8 @@ CGUISTKListBox::CGUISTKListBox(IGUIEnvironment* environment, IGUIElement* parent ScrollBar->setVisible(false); ScrollBar->setPos(0); + updateScrollBarSize(skin->getSize(EGDS_SCROLLBAR_SIZE)); + setNotClipped(!clip); // this element can be tabbed to @@ -478,6 +477,7 @@ void CGUISTKListBox::draw() recalculateItemHeight(); // if the font changed IGUISkin* skin = Environment->getSkin(); + updateScrollBarSize(skin->getSize(EGDS_SCROLLBAR_SIZE)); core::rect* clipRect = 0; @@ -489,7 +489,7 @@ void CGUISTKListBox::draw() core::rect clientClip(AbsoluteRect); clientClip.UpperLeftCorner.Y += 1; if (ScrollBar->isVisible()) - clientClip.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE); + clientClip.LowerRightCorner.X -= ScrollBar->getRelativePosition().getWidth(); clientClip.LowerRightCorner.Y -= 1; clientClip.clipAgainst(AbsoluteClippingRect); @@ -501,7 +501,7 @@ void CGUISTKListBox::draw() frameRect = AbsoluteRect; if (ScrollBar->isVisible()) - frameRect.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE); + frameRect.LowerRightCorner.X -= ScrollBar->getRelativePosition().getWidth(); frameRect.LowerRightCorner.Y = AbsoluteRect.UpperLeftCorner.Y + ItemHeight; @@ -817,6 +817,16 @@ void CGUISTKListBox::setDrawBackground(bool draw) } +void CGUISTKListBox::updateScrollBarSize(s32 size) +{ + if (size != ScrollBar->getRelativePosition().getWidth()) + { + core::recti r(RelativeRect.getWidth() - size, 0, RelativeRect.getWidth(), RelativeRect.getHeight()); + ScrollBar->setRelativePosition(r); + } +} + + } // end namespace gui } // end namespace irr diff --git a/src/guiengine/widgets/CGUISTKListBox.hpp b/src/guiengine/widgets/CGUISTKListBox.hpp index c887b5d7c10..2d00a269627 100644 --- a/src/guiengine/widgets/CGUISTKListBox.hpp +++ b/src/guiengine/widgets/CGUISTKListBox.hpp @@ -183,6 +183,7 @@ namespace irr void recalculateItemHeight(); void selectNew(s32 ypos, bool onlyHover=false); void recalculateScrollPos(); + void updateScrollBarSize(s32 size); // extracted that function to avoid copy&paste code void recalculateIconWidth(); From 0d2fd6f62893ea9cfcbbb50baf5c7741164414ab Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 21 Apr 2024 14:08:39 +0800 Subject: [PATCH 317/830] Recalculate glyph layouts when list box resized --- src/guiengine/widgets/CGUISTKListBox.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/guiengine/widgets/CGUISTKListBox.cpp b/src/guiengine/widgets/CGUISTKListBox.cpp index ecf7b0ff61a..ceb87093c0a 100644 --- a/src/guiengine/widgets/CGUISTKListBox.cpp +++ b/src/guiengine/widgets/CGUISTKListBox.cpp @@ -462,6 +462,13 @@ void CGUISTKListBox::selectNew(s32 ypos, bool onlyHover) void CGUISTKListBox::updateAbsolutePosition() { IGUIElement::updateAbsolutePosition(); + for (int i = 0; i < Items.size(); i++) + { + for (int j = 0; j < Items[i].m_contents.size(); j++) + { + Items[i].m_contents[j].m_glyph_layouts.clear(); + } + } recalculateItemHeight(); } From 34119e1c5fcdfff2b060f6b5374848ed0efd672b Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 21 Apr 2024 14:40:10 +0800 Subject: [PATCH 318/830] Remove unneeded if in Widget::resize --- src/guiengine/widget.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/guiengine/widget.cpp b/src/guiengine/widget.cpp index 1a0e149a557..dd66aa463bf 100644 --- a/src/guiengine/widget.cpp +++ b/src/guiengine/widget.cpp @@ -303,14 +303,15 @@ void Widget::resize() { assert(m_magic_number == 0xCAFEC001); - if (m_element) - moveIrrlichtElement(); + moveIrrlichtElement(); } // ----------------------------------------------------------------------------- void Widget::move(const int x, const int y, const int w, const int h) { + assert(m_magic_number == 0xCAFEC001); + m_x = x; m_y = y; m_w = w; From f6836998f016628932981f6c9655904defa610a0 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 22 Apr 2024 10:56:01 +0800 Subject: [PATCH 319/830] Use a better setOverrideFont in ribbon widget --- src/guiengine/widgets/ribbon_widget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/guiengine/widgets/ribbon_widget.cpp b/src/guiengine/widgets/ribbon_widget.cpp index 4c4358d62d1..a252ecc3394 100644 --- a/src/guiengine/widgets/ribbon_widget.cpp +++ b/src/guiengine/widgets/ribbon_widget.cpp @@ -896,7 +896,7 @@ void RibbonWidget::resize() } else { - label->setOverrideFont(GUIEngine::getFont()); + label->setOverrideFont(NULL); } } else @@ -980,7 +980,7 @@ void RibbonWidget::resize() } else { - label->setOverrideFont(GUIEngine::getFont()); + label->setOverrideFont(NULL); } } else From 85e52de194b3383ed83d55baed4f22c154ceb125 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 22 Apr 2024 11:35:19 +0800 Subject: [PATCH 320/830] Add more resizing code to CGUISTKListBox --- src/guiengine/widgets/CGUISTKListBox.cpp | 17 +++++++++++++---- src/guiengine/widgets/CGUISTKListBox.hpp | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/guiengine/widgets/CGUISTKListBox.cpp b/src/guiengine/widgets/CGUISTKListBox.cpp index ceb87093c0a..2b197aa352f 100644 --- a/src/guiengine/widgets/CGUISTKListBox.cpp +++ b/src/guiengine/widgets/CGUISTKListBox.cpp @@ -161,6 +161,13 @@ void CGUISTKListBox::clear() } +void CGUISTKListBox::updateDefaultItemHeight() +{ + if (ItemHeightOverride == 0) + ItemHeight = Font->getHeightPerLine() + 4; +} + + void CGUISTKListBox::recalculateItemHeight() { IGUISkin* skin = Environment->getSkin(); @@ -176,9 +183,7 @@ void CGUISTKListBox::recalculateItemHeight() if (Font) { - if ( 0 == ItemHeightOverride ) - ItemHeight = Font->getHeightPerLine() + 4; - + updateDefaultItemHeight(); Font->grab(); } } @@ -470,7 +475,11 @@ void CGUISTKListBox::updateAbsolutePosition() } } - recalculateItemHeight(); + if (Font) + updateDefaultItemHeight(); + ItemsIconWidth = 0; + if (!Items.empty()) + recalculateIconWidth(); } diff --git a/src/guiengine/widgets/CGUISTKListBox.hpp b/src/guiengine/widgets/CGUISTKListBox.hpp index 2d00a269627..11899e45c61 100644 --- a/src/guiengine/widgets/CGUISTKListBox.hpp +++ b/src/guiengine/widgets/CGUISTKListBox.hpp @@ -181,6 +181,7 @@ namespace irr private: void recalculateItemHeight(); + void updateDefaultItemHeight(); void selectNew(s32 ypos, bool onlyHover=false); void recalculateScrollPos(); void updateScrollBarSize(s32 size); From 1319c9845b08c46bb473e7c2eebbe212216cbe04 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Tue, 23 Apr 2024 10:18:19 +0800 Subject: [PATCH 321/830] Remove list header properly --- src/guiengine/widgets/list_widget.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/guiengine/widgets/list_widget.cpp b/src/guiengine/widgets/list_widget.cpp index 6f7d847d6db..b79d7de0bc5 100644 --- a/src/guiengine/widgets/list_widget.cpp +++ b/src/guiengine/widgets/list_widget.cpp @@ -211,6 +211,9 @@ void ListWidget::clearColumns() m_header.clear(); for (unsigned int n=0; nremove(); m_header_elements[n].elementRemoved(); m_children.remove( m_header_elements.get(n) ); } From db2cc69d89f64bedb57a7c02cfb1d6993b55433a Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Tue, 23 Apr 2024 15:30:35 +0800 Subject: [PATCH 322/830] Refactor sprite scaling in STKModifiedSpriteBank Make it proportional to font height so that it can be auto-resized --- src/guiengine/CGUISpriteBank.cpp | 21 +++----- src/guiengine/CGUISpriteBank.hpp | 5 +- src/guiengine/widgets/list_widget.cpp | 52 +++++++++++-------- src/guiengine/widgets/list_widget.hpp | 5 +- src/states_screens/addons_screen.cpp | 7 ++- src/states_screens/addons_screen.hpp | 2 - .../dialogs/ghost_replay_info_dialog.cpp | 3 +- .../dialogs/high_score_info_dialog.cpp | 5 +- src/states_screens/edit_gp_screen.cpp | 4 +- src/states_screens/ghost_replay_selection.cpp | 9 ++-- src/states_screens/gp_info_screen.cpp | 8 ++- src/states_screens/high_score_selection.cpp | 7 +-- .../online/networking_lobby.cpp | 2 +- .../online/server_selection.cpp | 6 +-- src/states_screens/online/tracks_screen.cpp | 5 +- .../options/options_screen_device.cpp | 1 - .../options/options_screen_input.cpp | 4 +- src/states_screens/track_info_screen.cpp | 7 +-- 18 files changed, 69 insertions(+), 84 deletions(-) diff --git a/src/guiengine/CGUISpriteBank.cpp b/src/guiengine/CGUISpriteBank.cpp index 1edfe4650fd..fd772567143 100644 --- a/src/guiengine/CGUISpriteBank.cpp +++ b/src/guiengine/CGUISpriteBank.cpp @@ -11,6 +11,7 @@ #include #include "font/font_drawer.hpp" #include "graphics/2dutils.hpp" +#include "guiengine/engine.hpp" namespace irr { @@ -27,7 +28,7 @@ STKModifiedSpriteBank::STKModifiedSpriteBank(IGUIEnvironment* env) : #endif m_scale = 1.0f; - m_height = 0; + m_fixed_scale = 0.0f; m_target_icon_size = core::dimension2du(0, 0); if (Environment) { @@ -332,28 +333,22 @@ void STKModifiedSpriteBank::draw2DSpriteBatch(const core::array& indices, } } // draw2DSpriteBatch -// ---------------------------------------------------------------------------- -void STKModifiedSpriteBank::scaleToHeight(int height) -{ - m_height = height; -} - // ---------------------------------------------------------------------------- s32 STKModifiedSpriteBank::getScaledWidth(s32 width) const { - if (m_height == 0) - return (s32)((float)width * m_scale); + if (m_fixed_scale == 0.0f) + return (s32)(GUIEngine::getFontHeight() * (float)width * m_scale); else - return m_height; + return (s32)(GUIEngine::getFontHeight() * m_fixed_scale); } // ---------------------------------------------------------------------------- s32 STKModifiedSpriteBank::getScaledHeight(s32 height) const { - if (m_height == 0) - return (s32)((float)height * m_scale); + if (m_fixed_scale == 0.0f) + return (s32)(GUIEngine::getFontHeight() * (float)height * m_scale); else - return m_height; + return (s32)(GUIEngine::getFontHeight() * m_fixed_scale); } // ---------------------------------------------------------------------------- diff --git a/src/guiengine/CGUISpriteBank.hpp b/src/guiengine/CGUISpriteBank.hpp index b2533bc9724..3e953e949ab 100644 --- a/src/guiengine/CGUISpriteBank.hpp +++ b/src/guiengine/CGUISpriteBank.hpp @@ -67,7 +67,8 @@ class STKModifiedSpriteBank : public IGUISpriteBank m_scale = scale; } - void scaleToHeight(int height); + void setFixedScale(float scale) + { m_fixed_scale = scale; } void setTargetIconSize(int width, int height) { m_target_icon_size = core::dimension2du(width, height); } @@ -78,7 +79,7 @@ class STKModifiedSpriteBank : public IGUISpriteBank unsigned int m_magic_number; float m_scale; - int m_height; + float m_fixed_scale; struct SDrawBatch { diff --git a/src/guiengine/widgets/list_widget.cpp b/src/guiengine/widgets/list_widget.cpp index b79d7de0bc5..eea1fb82d21 100644 --- a/src/guiengine/widgets/list_widget.cpp +++ b/src/guiengine/widgets/list_widget.cpp @@ -48,11 +48,12 @@ ListWidget::ListWidget() : Widget(WTYPE_LIST) m_sortable = true; m_header_created = false; m_choosing_header = false; + m_icon_scale = -1.0f; } // ----------------------------------------------------------------------------- -void ListWidget::setIcons(STKModifiedSpriteBank* icons, int size) +void ListWidget::setIcons(STKModifiedSpriteBank* icons, float scale) { m_use_icons = (icons != NULL); m_icons = icons; @@ -63,34 +64,39 @@ void ListWidget::setIcons(STKModifiedSpriteBank* icons, int size) if (m_use_icons) { list->setSpriteBank(m_icons); + m_icon_scale = scale; + updateIconScale(); + } + else + { + list->setSpriteBank(NULL); + } - // determine needed height - int item_height = 0; - if (size > 0) - { - item_height = size; - } - else - { - const core::array< core::rect >& rects = m_icons->getPositions(); - const int count = rects.size(); - for (int n=0; n item_height) item_height = h; - } - } +} + +// ----------------------------------------------------------------------------- +void ListWidget::updateIconScale() +{ + CGUISTKListBox* list = getIrrlichtElement(); + assert(list != NULL); - if (item_height > 0) + // determine needed height + int item_height = (int)(m_icon_scale * GUIEngine::getFontHeight()); + if (m_icon_scale <= 0.0f) + { + const core::array< core::rect >& rects = m_icons->getPositions(); + const int count = rects.size(); + for (int n = 0; n < count; n++) { - list->setItemHeight( item_height ); + const int h = rects[n].getHeight(); + if (h > item_height) item_height = h; } } - else + + if (item_height > 0) { - list->setSpriteBank(NULL); + list->setItemHeight(item_height); } - } // ----------------------------------------------------------------------------- @@ -699,4 +705,6 @@ void ListWidget::resize() if (m_element) m_element->setRelativePosition(getListBoxSize()); updateHeader(); + if (m_use_icons) + updateIconScale(); } diff --git a/src/guiengine/widgets/list_widget.hpp b/src/guiengine/widgets/list_widget.hpp index d4b709a72d2..77d0595d5c0 100644 --- a/src/guiengine/widgets/list_widget.hpp +++ b/src/guiengine/widgets/list_widget.hpp @@ -98,6 +98,8 @@ namespace GUIEngine bool m_header_created; + float m_icon_scale; + void repairSortCol() { // Exclude scrollbar @@ -109,6 +111,7 @@ namespace GUIEngine } void updateHeader(); + void updateIconScale(); int getHeaderHeight() const; irr::core::rect getListBoxSize() const; @@ -140,7 +143,7 @@ namespace GUIEngine * you're done with it (but do not delete it when the list widget is still active) * \pre may only be called after the widget has been added to the screen with add() */ - void setIcons(irr::gui::STKModifiedSpriteBank* icons, int size=-1); + void setIcons(irr::gui::STKModifiedSpriteBank* icons, float scale = -1.0f); // ---- contents management diff --git a/src/states_screens/addons_screen.cpp b/src/states_screens/addons_screen.cpp index d0a403956ac..3f2bd59245c 100644 --- a/src/states_screens/addons_screen.cpp +++ b/src/states_screens/addons_screen.cpp @@ -157,11 +157,10 @@ void AddonsScreen::init() getWidget("list_addons"); // This defines the row height ! - m_icon_height = GUIEngine::getFontHeight() * 2; + m_icon_bank->setScale(1.0f / 72.0f); // 128 is the height of the image file - m_icon_bank->setScale((float)GUIEngine::getFontHeight() / 72.0f); - m_icon_bank->setTargetIconSize(128,128); - w_list->setIcons(m_icon_bank, (int)(m_icon_height)); + m_icon_bank->setTargetIconSize(128, 128); + w_list->setIcons(m_icon_bank, 2.0f); m_type = "kart"; diff --git a/src/states_screens/addons_screen.hpp b/src/states_screens/addons_screen.hpp index 53f51efda11..c61657bcc7a 100644 --- a/src/states_screens/addons_screen.hpp +++ b/src/states_screens/addons_screen.hpp @@ -69,8 +69,6 @@ class AddonsScreen : public GUIEngine::Screen, * addons_loading is being displayed. */ int m_selected_index; - float m_icon_height; - bool m_reloading; bool m_sort_desc; diff --git a/src/states_screens/dialogs/ghost_replay_info_dialog.cpp b/src/states_screens/dialogs/ghost_replay_info_dialog.cpp index 7585a815c4a..d94ed930707 100644 --- a/src/states_screens/dialogs/ghost_replay_info_dialog.cpp +++ b/src/states_screens/dialogs/ghost_replay_info_dialog.cpp @@ -83,8 +83,7 @@ GhostReplayInfoDialog::GhostReplayInfoDialog(unsigned int replay_id, /* Used to display kart icons for the selected replay(s) */ irr::gui::STKModifiedSpriteBank *icon_bank = GhostReplaySelection::getInstance()->getIconBank(); - int icon_height = GUIEngine::getFontHeight() * 3 / 2; - m_replay_info_widget->setIcons(icon_bank, (int)icon_height); + m_replay_info_widget->setIcons(icon_bank, 1.5f); updateReplayDisplayedInfo(); diff --git a/src/states_screens/dialogs/high_score_info_dialog.cpp b/src/states_screens/dialogs/high_score_info_dialog.cpp index 91ef7aa72d8..bc6372a724d 100644 --- a/src/states_screens/dialogs/high_score_info_dialog.cpp +++ b/src/states_screens/dialogs/high_score_info_dialog.cpp @@ -101,11 +101,10 @@ HighScoreInfoDialog::HighScoreInfoDialog(Highscores* highscore, bool is_linear, /* Used to display kart icons for the entries */ irr::gui::STKModifiedSpriteBank *icon_bank = HighScoreSelection::getInstance()->getIconBank(); - int icon_height = GUIEngine::getFontHeight() * 3 / 2; - icon_bank->setScale(icon_height/128.0f); + icon_bank->setScale(1.5f / 128.0f); icon_bank->setTargetIconSize(128, 128); - m_high_score_list->setIcons(icon_bank, (int)icon_height); + m_high_score_list->setIcons(icon_bank, 1.5f); updateHighscoreEntries(); diff --git a/src/states_screens/edit_gp_screen.cpp b/src/states_screens/edit_gp_screen.cpp index 824292bfd02..65bf5db2171 100644 --- a/src/states_screens/edit_gp_screen.cpp +++ b/src/states_screens/edit_gp_screen.cpp @@ -234,8 +234,8 @@ void EditGPScreen::loadList(const int selected) m_list->clear(); m_icons.clear(); m_icon_bank->clear(); - m_icon_bank->scaleToHeight (GUIEngine::getFontHeight() * 3 / 2); - m_list->setIcons(m_icon_bank, GUIEngine::getFontHeight() * 3 / 2); + m_icon_bank->setFixedScale(1.5f); + m_list->setIcons(m_icon_bank, 1.5f); for (unsigned int i = 0; i < m_gp->getNumberOfTracks(true); i++) { diff --git a/src/states_screens/ghost_replay_selection.cpp b/src/states_screens/ghost_replay_selection.cpp index 17597aadc2a..aae51d01f20 100644 --- a/src/states_screens/ghost_replay_selection.cpp +++ b/src/states_screens/ghost_replay_selection.cpp @@ -177,14 +177,11 @@ void GhostReplaySelection::init() { Screen::init(); m_cur_difficulty = RaceManager::get()->getDifficulty(); - - int icon_height = GUIEngine::getFontHeight(); - int row_height = GUIEngine::getFontHeight() * 5 / 4; - + // 128 is the height of the image file - m_icon_bank->setScale(icon_height/128.0f); + m_icon_bank->setScale(1.0f / 128.0f); m_icon_bank->setTargetIconSize(128, 128); - m_replay_list_widget->setIcons(m_icon_bank, (int)row_height); + m_replay_list_widget->setIcons(m_icon_bank, 1.25f); refresh(/*reload replay files*/ false, /* update columns */ true); } // init diff --git a/src/states_screens/gp_info_screen.cpp b/src/states_screens/gp_info_screen.cpp index c5bb06b6be3..679b1a121eb 100644 --- a/src/states_screens/gp_info_screen.cpp +++ b/src/states_screens/gp_info_screen.cpp @@ -291,11 +291,9 @@ void GPInfoScreen::init() getWidget("name")->setText(m_gp.getName(), false); m_gp.checkConsistency(); - int icon_height = GUIEngine::getFontHeight(); - int row_height = GUIEngine::getFontHeight() * 1.2f; - m_icon_bank->setScale(icon_height/128.0f); - m_icon_bank->setTargetIconSize(128,128); - m_highscore_list->setIcons(m_icon_bank,row_height); + m_icon_bank->setScale(1.0f / 128.0f); + m_icon_bank->setTargetIconSize(128, 128); + m_highscore_list->setIcons(m_icon_bank, 1.2f); RaceManager::get()->setNumKarts(RaceManager::get()->getNumLocalPlayers() + m_ai_kart_spinner->getValue()); // We don't save highscores for random gps so load highscores here updateHighscores(); diff --git a/src/states_screens/high_score_selection.cpp b/src/states_screens/high_score_selection.cpp index 454257bab71..1c78630ba5f 100644 --- a/src/states_screens/high_score_selection.cpp +++ b/src/states_screens/high_score_selection.cpp @@ -168,13 +168,10 @@ void HighScoreSelection::init() { Screen::init(); - int icon_height = GUIEngine::getFontHeight(); - int row_height = GUIEngine::getFontHeight() * 5 / 4; - // 128 is the height of the image file - m_icon_bank->setScale(icon_height/128.0f); + m_icon_bank->setScale(1.0f / 128.0f); m_icon_bank->setTargetIconSize(128, 128); - m_high_scores_list_widget->setIcons(m_icon_bank, (int)row_height); + m_high_scores_list_widget->setIcons(m_icon_bank, 1.25f); refresh(/*reload high score list*/ false, /* update columns */ true); } // init diff --git a/src/states_screens/online/networking_lobby.cpp b/src/states_screens/online/networking_lobby.cpp index 96f70f8ce7e..d6a950bef45 100644 --- a/src/states_screens/online/networking_lobby.cpp +++ b/src/states_screens/online/networking_lobby.cpp @@ -157,7 +157,7 @@ void NetworkingLobby::loadedFromFile() m_icon_bank->addTextureAsSprite(m_spectate_texture); m_icon_bank->addTextureAsSprite(icon_6); - m_icon_bank->setScale((float)GUIEngine::getFontHeight() / 96.0f); + m_icon_bank->setScale(1.0f / 96.0f); m_icon_bank->setTargetIconSize(128, 128); } // loadedFromFile diff --git a/src/states_screens/online/server_selection.cpp b/src/states_screens/online/server_selection.cpp index e55ee360f80..c83ae94dd00 100644 --- a/src/states_screens/online/server_selection.cpp +++ b/src/states_screens/online/server_selection.cpp @@ -174,7 +174,7 @@ void ServerSelection::init() m_searcher->clearListeners(); m_searcher->addListener(this); - m_icon_bank->setScale((float)GUIEngine::getFontHeight() / 72.0f); + m_icon_bank->setScale(1.0f / 72.0f); m_icon_bank->setTargetIconSize(128, 128); video::ITexture* icon1 = irr_driver->getTexture( @@ -204,10 +204,8 @@ void ServerSelection::init() assert(tex); m_icon_bank->addTextureAsSprite(tex); } - - int row_height = GUIEngine::getFontHeight() * 2; - m_server_list_widget->setIcons(m_icon_bank, row_height); + m_server_list_widget->setIcons(m_icon_bank, 2.0f); m_sort_desc = false; refresh(); m_ipv6_only_without_nat64 = false; diff --git a/src/states_screens/online/tracks_screen.cpp b/src/states_screens/online/tracks_screen.cpp index 244cb0e6bfd..49d53a0a8aa 100644 --- a/src/states_screens/online/tracks_screen.cpp +++ b/src/states_screens/online/tracks_screen.cpp @@ -451,10 +451,9 @@ void TracksScreen::init() m_track_icons->addTextureAsSprite(tex); } - int icon_height = getHeight() / 13; - m_track_icons->setScale(icon_height / 256.0f); + m_track_icons->setScale(1.0f / 128.0f); m_track_icons->setTargetIconSize(256, 256); - m_vote_list->setIcons(m_track_icons, (int)icon_height); + m_vote_list->setIcons(m_track_icons); const PeerVote* vote = cl->getVote(STKHost::get()->getMyHostId()); if (vote) diff --git a/src/states_screens/options/options_screen_device.cpp b/src/states_screens/options/options_screen_device.cpp index 59c5a340aae..767158c7984 100644 --- a/src/states_screens/options/options_screen_device.cpp +++ b/src/states_screens/options/options_screen_device.cpp @@ -18,7 +18,6 @@ #include "states_screens/options/options_screen_device.hpp" #include "config/user_config.hpp" -#include "guiengine/CGUISpriteBank.hpp" #include "guiengine/message_queue.hpp" #include "guiengine/scalable_font.hpp" #include "guiengine/screen.hpp" diff --git a/src/states_screens/options/options_screen_input.cpp b/src/states_screens/options/options_screen_input.cpp index 6609a55a0e3..019513d77cd 100644 --- a/src/states_screens/options/options_screen_input.cpp +++ b/src/states_screens/options/options_screen_input.cpp @@ -74,9 +74,7 @@ void OptionsScreenInput::loadedFromFile() m_icon_bank->addTextureAsSprite(icon4); m_icon_bank->addTextureAsSprite(icon5); - // scale icons depending on font height - const float scale = GUIEngine::getFontHeight() / 72.0f; - m_icon_bank->setScale(scale); + m_icon_bank->setScale(1.0f / 72.0f); m_icon_bank->setTargetIconSize(128, 128); m_gamepad_count = 0; } // loadFromFile diff --git a/src/states_screens/track_info_screen.cpp b/src/states_screens/track_info_screen.cpp index 45b2d4413e0..aca3e167c44 100644 --- a/src/states_screens/track_info_screen.cpp +++ b/src/states_screens/track_info_screen.cpp @@ -345,12 +345,9 @@ void TrackInfoScreen::init() if (has_highscores) { - int icon_height = GUIEngine::getFontHeight(); - int row_height = GUIEngine::getFontHeight() * 1.2f; - - m_icon_bank->setScale(icon_height/128.0f); + m_icon_bank->setScale(1.0f / 128.0f); m_icon_bank->setTargetIconSize(128, 128); - m_highscore_entries->setIcons(m_icon_bank, (int)row_height); + m_highscore_entries->setIcons(m_icon_bank, 1.2f); m_highscore_entries->setVisible(has_highscores); updateHighScores(); From 171ac3c0b06e1415123794c1f5152814bdccc403 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:29:05 +0200 Subject: [PATCH 323/830] Adapt the pause menu in benchmark mode * Use explicit activation and desactivation functions for the profiler to improve code clarity and robustness * In the pause dialog, only display the 'back to race' and 'exit' buttons in benchmark mode * Relabel the buttons in the pause menu in benchmark mode * Use 'Performance test' in user-facing texts to ensure better translations * Fix parts of the UI disappearing when leaving the pause menu in benchmark mode Additional known issue introduced in the previous benchmark commit: * With big text sizes, the performance test button overflows in the graphics settings. --- data/gui/screens/options_video.stkgui | 2 +- src/modes/world_status.cpp | 6 ++-- src/race/race_manager.cpp | 16 +++++++++ src/race/race_manager.hpp | 6 +--- .../dialogs/race_paused_dialog.cpp | 33 ++++++++++++++++--- src/utils/debug.cpp | 5 ++- src/utils/profiler.cpp | 25 +++++++++----- src/utils/profiler.hpp | 3 +- 8 files changed, 72 insertions(+), 24 deletions(-) diff --git a/data/gui/screens/options_video.stkgui b/data/gui/screens/options_video.stkgui index 252b0613a4a..f7414aed2d7 100644 --- a/data/gui/screens/options_video.stkgui +++ b/data/gui/screens/options_video.stkgui @@ -133,7 +133,7 @@

+ + + m_map_vote_handler.getAlgorithm()); + m_lobby->sendStringToPeer(msg, peer); +} // process_history +// ======================================================================== + +void CommandManager::process_voting_assign(Context& context) +{ + auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } + std::string msg = ""; + if (argv.size() < 2) + { + error(context); + return; + } + int value; + if (!StringUtils::fromString(argv[1], value) || value < 0 || value > 1) + { + error(context); + return; + } + m_lobby->m_map_vote_handler.setAlgorithm(value); + msg = StringUtils::insertValues("Set voting method to %s", value); + m_lobby->sendStringToPeer(msg, peer); +} // process_history_assign +// ======================================================================== + void CommandManager::special(Context& context) { auto peer = context.m_peer.lock(); diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 3ae212b373a..6e17b335025 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -358,6 +358,8 @@ class CommandManager void process_preserve_assign(Context& context); void process_history(Context& context); void process_history_assign(Context& context); + void process_voting(Context& context); + void process_voting_assign(Context& context); void special(Context& context); std::string getRandomMap() const; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 2fa6f0900d3..ad51c9be6c4 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -238,6 +238,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_teammate_swatter_punish.clear(); m_collecting_teammate_hit_info = false; + m_map_vote_handler.setAlgorithm(ServerConfig::m_map_vote_handling); + initAvailableModes(); m_current_ai_count.store(0); @@ -5161,13 +5163,6 @@ void ServerLobby::handlePlayerVote(Event* event) bool ServerLobby::handleAllVotes(PeerVote* winner_vote, uint32_t* winner_peer_id) { - // Determine majority agreement when 35% of voting time remains, - // reserve some time for kart selection so it's not 50% - if (getRemainingVotingTime() / getMaxVotingTime() > 0.35f) - { - return false; - } - // First remove all votes from disconnected hosts auto it = m_peers_votes.begin(); while (it != m_peers_votes.end()) @@ -5181,18 +5176,8 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote, it++; } - if (m_peers_votes.empty()) - { - if (isVotingOver()) - { - *winner_vote = *m_default_vote; - return true; - } - return false; - } - - // Count number of players - float cur_players = 0.0f; + // Count number of players + unsigned cur_players = 0; auto peers = STKHost::get()->getPeers(); for (auto peer : peers) { @@ -5201,131 +5186,20 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote, if (!canVote(peer)) continue; if (peer->hasPlayerProfiles() && !peer->isWaitingForGame()) - cur_players += 1.0f; - } - - std::string top_track = m_default_vote->m_track_name; - unsigned top_laps = m_default_vote->m_num_laps; - bool top_reverse = m_default_vote->m_reverse; - - std::map tracks; - std::map laps; - std::map reverses; - - // Ratio to determine majority agreement - float tracks_rate = 0.0f; - float laps_rate = 0.0f; - float reverses_rate = 0.0f; - - for (auto& p : m_peers_votes) - { - auto track_vote = tracks.find(p.second.m_track_name); - if (track_vote == tracks.end()) - tracks[p.second.m_track_name] = 1; - else - track_vote->second++; - auto lap_vote = laps.find(p.second.m_num_laps); - if (lap_vote == laps.end()) - laps[p.second.m_num_laps] = 1; - else - lap_vote->second++; - auto reverse_vote = reverses.find(p.second.m_reverse); - if (reverse_vote == reverses.end()) - reverses[p.second.m_reverse] = 1; - else - reverse_vote->second++; + cur_players++; } - findMajorityValue(tracks, cur_players, &top_track, &tracks_rate); - findMajorityValue(laps, cur_players, &top_laps, &laps_rate); - findMajorityValue(reverses, cur_players, &top_reverse, &reverses_rate); - - // End early if there is majority agreement which is all entries rate > 0.5 - it = m_peers_votes.begin(); - if (tracks_rate > 0.5f && laps_rate > 0.5f && reverses_rate > 0.5f) - { - while (it != m_peers_votes.end()) - { - if (it->second.m_track_name == top_track && - it->second.m_num_laps == top_laps && - it->second.m_reverse == top_reverse) - break; - else - it++; - } - if (it == m_peers_votes.end()) - { - // Don't end if no vote matches all majority choices - Log::warn("ServerLobby", - "Missing track %s from majority.", top_track.c_str()); - it = m_peers_votes.begin(); - if (!isVotingOver()) - return false; - } - *winner_peer_id = it->first; - *winner_vote = it->second; - return true; - } - if (isVotingOver()) - { - // Pick the best lap (or soccer goal / time) from only the top track - // if no majority agreement from all - int diff = std::numeric_limits::max(); - auto closest_lap = m_peers_votes.begin(); - while (it != m_peers_votes.end()) - { - if (it->second.m_track_name == top_track && - std::abs((int)it->second.m_num_laps - (int)top_laps) < diff) - { - closest_lap = it; - diff = std::abs((int)it->second.m_num_laps - (int)top_laps); - } - else - it++; - } - *winner_peer_id = closest_lap->first; - *winner_vote = closest_lap->second; - return true; - } - return false; + return m_map_vote_handler.handleAllVotes( + m_peers_votes, + getRemainingVotingTime(), + getMaxVotingTime(), + isVotingOver(), + cur_players, + m_default_vote, + winner_vote, winner_peer_id + ); } // handleAllVotes -// ---------------------------------------------------------------------------- -template -void ServerLobby::findMajorityValue(const std::map& choices, unsigned cur_players, - T* best_choice, float* rate) -{ - RandomGenerator rg; - unsigned max_votes = 0; - auto best_iter = choices.begin(); - unsigned best_iters_count = 1; - // Among choices with max votes, we need to pick one uniformly, - // thus we have to keep track of their number - for (auto iter = choices.begin(); iter != choices.end(); iter++) - { - if (iter->second > max_votes) - { - max_votes = iter->second; - best_iter = iter; - best_iters_count = 1; - } - else if (iter->second == max_votes) - { - best_iters_count++; - if (rg.get(best_iters_count) == 0) - { - max_votes = iter->second; - best_iter = iter; - } - } - } - if (best_iter != choices.end()) - { - *best_choice = best_iter->first; - *rate = float(best_iter->second) / cur_players; - } -} // findMajorityValue - // ---------------------------------------------------------------------------- void ServerLobby::getHitCaptureLimit() { diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 76caabb80b5..6c37f7f1c21 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -25,6 +25,7 @@ #include "utils/team_utils.hpp" #include "utils/time.hpp" #include "utils/track_filter.hpp" +#include "utils/map_vote_handler.hpp" #include "karts/controller/player_controller.hpp" #include "network/protocols/command_manager.hpp" @@ -316,6 +317,8 @@ class ServerLobby : public LobbyProtocol KartElimination m_kart_elimination; + MapVoteHandler m_map_vote_handler; + std::set m_available_difficulties; std::set m_available_modes; @@ -520,9 +523,6 @@ class ServerLobby : public LobbyProtocol const irr::core::stringw& online_name, const std::string& country_code); bool handleAllVotes(PeerVote* winner, uint32_t* winner_peer_id); - template - void findMajorityValue(const std::map& choices, unsigned cur_players, - T* best_choice, float* rate); void getRankingForPlayer(std::shared_ptr p); void submitRankingsToAddons(); void computeNewRankings(); diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 72ccea7d517..263a3955a63 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -780,6 +780,13 @@ namespace ServerConfig "Possible options are mode, elim, laps, queue, replay, to include several " "separate them by spaces, empty to include nothing.")); + SERVER_CFG_PREFIX IntServerConfigParam m_map_vote_handling + SERVER_CFG_DEFAULT(IntServerConfigParam(0, "map-vote-handling", + "Specifies how the server should decide which map vote wins in map " + "selection. 0 corresponds to standard system, 1 - to randomly selecting " + "one of votes." + )); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; diff --git a/src/utils/map_vote_handler.cpp b/src/utils/map_vote_handler.cpp new file mode 100644 index 00000000000..6402348b262 --- /dev/null +++ b/src/utils/map_vote_handler.cpp @@ -0,0 +1,209 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2024 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/map_vote_handler.hpp" +#include "utils/string_utils.hpp" +#include "utils/log.hpp" +#include "utils/random_generator.hpp" + +MapVoteHandler::MapVoteHandler(): algorithm(0) +{ + +} // MapVoteHandler +// ============================================================================ + + +template +void MapVoteHandler::findMajorityValue(const std::map& choices, unsigned cur_players, + T* best_choice, float* rate) +{ + RandomGenerator rg; + unsigned max_votes = 0; + auto best_iter = choices.begin(); + unsigned best_iters_count = 1; + // Among choices with max votes, we need to pick one uniformly, + // thus we have to keep track of their number + for (auto iter = choices.begin(); iter != choices.end(); iter++) + { + if (iter->second > max_votes) + { + max_votes = iter->second; + best_iter = iter; + best_iters_count = 1; + } + else if (iter->second == max_votes) + { + best_iters_count++; + if (rg.get(best_iters_count) == 0) + { + max_votes = iter->second; + best_iter = iter; + } + } + } + if (best_iter != choices.end()) + { + *best_choice = best_iter->first; + *rate = float(best_iter->second) / cur_players; + } +} // findMajorityValue +// ============================================================================ + +bool MapVoteHandler::handleAllVotes(std::map& peers_votes, + float remaining_time, float max_time, bool is_over, + unsigned cur_players, PeerVote* default_vote, + PeerVote* winner_vote, uint32_t* winner_peer_id) const +{ + if (algorithm == 0) + return standard(peers_votes, remaining_time, max_time, is_over, cur_players, default_vote, winner_vote, winner_peer_id); + else // if (algorithm == 1) + return random(peers_votes, remaining_time, max_time, is_over, cur_players, default_vote, winner_vote, winner_peer_id); +} // handleAllVotes +// ============================================================================ + +bool MapVoteHandler::random(std::map& peers_votes, + float remaining_time, float max_time, bool is_over, + unsigned cur_players, PeerVote* default_vote, + PeerVote* winner_vote, uint32_t* winner_peer_id) const +{ + if (!is_over) + return false; + + if (peers_votes.empty()) + { + *winner_vote = *default_vote; + return true; + } + + RandomGenerator rg; + std::map::iterator it = peers_votes.begin(); + std::advance(it, rg.get((int)peers_votes.size())); + *winner_peer_id = it->first; + *winner_vote = it->second; + return true; +} // random +// ============================================================================ + +bool MapVoteHandler::standard(std::map& peers_votes, + float remaining_time, float max_time, bool is_over, + unsigned cur_players, PeerVote* default_vote, + PeerVote* winner_vote, uint32_t* winner_peer_id) const +{ + // Determine majority agreement when 35% of voting time remains, + // reserve some time for kart selection so it's not 50% + if (remaining_time / max_time > 0.35f) + { + return false; + } + + if (peers_votes.empty()) + { + if (is_over) + { + *winner_vote = *default_vote; + return true; + } + return false; + } + + std::string top_track = default_vote->m_track_name; + unsigned top_laps = default_vote->m_num_laps; + bool top_reverse = default_vote->m_reverse; + + std::map tracks; + std::map laps; + std::map reverses; + + // Ratio to determine majority agreement + float tracks_rate = 0.0f; + float laps_rate = 0.0f; + float reverses_rate = 0.0f; + + for (auto& p : peers_votes) + { + auto track_vote = tracks.find(p.second.m_track_name); + if (track_vote == tracks.end()) + tracks[p.second.m_track_name] = 1; + else + track_vote->second++; + auto lap_vote = laps.find(p.second.m_num_laps); + if (lap_vote == laps.end()) + laps[p.second.m_num_laps] = 1; + else + lap_vote->second++; + auto reverse_vote = reverses.find(p.second.m_reverse); + if (reverse_vote == reverses.end()) + reverses[p.second.m_reverse] = 1; + else + reverse_vote->second++; + } + + findMajorityValue(tracks, cur_players, &top_track, &tracks_rate); + findMajorityValue(laps, cur_players, &top_laps, &laps_rate); + findMajorityValue(reverses, cur_players, &top_reverse, &reverses_rate); + + // End early if there is majority agreement which is all entries rate > 0.5 + auto it = peers_votes.begin(); + if (tracks_rate > 0.5f && laps_rate > 0.5f && reverses_rate > 0.5f) + { + while (it != peers_votes.end()) + { + if (it->second.m_track_name == top_track && + it->second.m_num_laps == top_laps && + it->second.m_reverse == top_reverse) + break; + else + it++; + } + if (it == peers_votes.end()) + { + // Don't end if no vote matches all majority choices + Log::warn("ServerLobby", + "Missing track %s from majority.", top_track.c_str()); + it = peers_votes.begin(); + if (!is_over) + return false; + } + *winner_peer_id = it->first; + *winner_vote = it->second; + return true; + } + if (is_over) + { + // Pick the best lap (or soccer goal / time) from only the top track + // if no majority agreement from all + int diff = std::numeric_limits::max(); + auto closest_lap = peers_votes.begin(); + while (it != peers_votes.end()) + { + if (it->second.m_track_name == top_track && + std::abs((int)it->second.m_num_laps - (int)top_laps) < diff) + { + closest_lap = it; + diff = std::abs((int)it->second.m_num_laps - (int)top_laps); + } + else + it++; + } + *winner_peer_id = closest_lap->first; + *winner_vote = closest_lap->second; + return true; + } + return false; +} // standard +// ======================================================================== diff --git a/src/utils/map_vote_handler.hpp b/src/utils/map_vote_handler.hpp new file mode 100644 index 00000000000..450509d457e --- /dev/null +++ b/src/utils/map_vote_handler.hpp @@ -0,0 +1,67 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2024 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef MAP_VOTE_HANDLER_HPP +#define MAP_VOTE_HANDLER_HPP + +#include "irrString.h" + +#include +#include +#include +#include +#include +#include + +#include "network/peer_vote.hpp" + +// A class containing different implementations for handling map votes +// in a server lobby. +// It can be extended to store some information about previous choices, +// but currently it doesn't store or use it. + +class MapVoteHandler +{ + // STANDARD = 0 + // RANDOM = 1 + // ADVANCED = 2 +private: + int algorithm; + template + static void findMajorityValue(const std::map& choices, unsigned cur_players, + T* best_choice, float* rate); + + bool standard(std::map& peers_votes, + float remaining_time, float max_time, bool is_over, + unsigned cur_players, PeerVote* default_vote, + PeerVote* winner_vote, uint32_t* winner_peer_id) const; + bool random(std::map& peers_votes, + float remaining_time, float max_time, bool is_over, + unsigned cur_players, PeerVote* default_vote, + PeerVote* winner_vote, uint32_t* winner_peer_id) const; +public: + MapVoteHandler(); + void setAlgorithm(int x) { algorithm = x; } + int getAlgorithm() const { return algorithm; } + bool handleAllVotes(std::map& peers_votes, + float remaining_time, float max_time, bool is_over, + unsigned cur_players, PeerVote* default_vote, + PeerVote* winner_vote, uint32_t* winner_peer_id) const; + +}; +#endif // MAP_VOTE_HANDLER_HPP From 97ca195e20a8ea2efd60bf3fc18f0adeee587864 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sat, 27 Apr 2024 15:05:52 +0800 Subject: [PATCH 336/830] Fix dynamic ribbon widget being shown above a dialog after resized --- lib/irrlicht/include/IGUIElement.h | 28 ++++++++++++++++++- lib/irrlicht/include/IGUIEnvironment.h | 2 ++ lib/irrlicht/include/irrList.h | 1 + .../source/Irrlicht/CGUIEnvironment.h | 2 ++ .../widgets/dynamic_ribbon_widget.cpp | 2 ++ 5 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/irrlicht/include/IGUIElement.h b/lib/irrlicht/include/IGUIElement.h index 378c25c5b93..282840bf66f 100644 --- a/lib/irrlicht/include/IGUIElement.h +++ b/lib/irrlicht/include/IGUIElement.h @@ -573,6 +573,27 @@ class IGUIElement : public virtual io::IAttributeExchangingObject, public IEvent } + virtual bool setChildEnd(IGUIElement* end) + { + if (end == 0) + { + ChildEnd = core::list::Iterator(); + return true; + } + + core::list::Iterator it = Children.begin(); + for (; it != Children.end(); ++it) + { + if (*it == end) + { + ChildEnd = it; + return true; + } + } + return false; + } + + //! Finds the first element with the given id. /** \param id: Id to search for. \param searchchildren: Set this to true, if also children of this @@ -823,7 +844,10 @@ class IGUIElement : public virtual io::IAttributeExchangingObject, public IEvent child->remove(); // remove from old parent child->LastParentRect = getAbsolutePosition(); child->Parent = this; - Children.push_back(child); + if (ChildEnd.isValid()) + Children.insert_after(ChildEnd, child); + else + Children.push_back(child); } } @@ -1027,6 +1051,8 @@ class IGUIElement : public virtual io::IAttributeExchangingObject, public IEvent //! type of element EGUI_ELEMENT_TYPE Type; + + core::list::Iterator ChildEnd; }; diff --git a/lib/irrlicht/include/IGUIEnvironment.h b/lib/irrlicht/include/IGUIEnvironment.h index 84c40924345..c5cd83a0ba1 100644 --- a/lib/irrlicht/include/IGUIEnvironment.h +++ b/lib/irrlicht/include/IGUIEnvironment.h @@ -612,6 +612,8 @@ class IGUIEnvironment : public virtual IReferenceCounted virtual void readGUIElement(io::IXMLReader* reader, IGUIElement* node) =0; virtual void removeHovered(IGUIElement* element) = 0; + + virtual bool setChildEnd(IGUIElement* end) = 0; }; diff --git a/lib/irrlicht/include/irrList.h b/lib/irrlicht/include/irrList.h index 54eed83447e..8c1153318d7 100644 --- a/lib/irrlicht/include/irrList.h +++ b/lib/irrlicht/include/irrList.h @@ -73,6 +73,7 @@ class list T & operator * () { return Current->Element; } T * operator ->() { return &Current->Element; } + bool isValid() const { return Current != 0; } private: explicit Iterator(SKListNode* begin) : Current(begin) {} diff --git a/lib/irrlicht/source/Irrlicht/CGUIEnvironment.h b/lib/irrlicht/source/Irrlicht/CGUIEnvironment.h index efe055f2538..3e5fef8171e 100644 --- a/lib/irrlicht/source/Irrlicht/CGUIEnvironment.h +++ b/lib/irrlicht/source/Irrlicht/CGUIEnvironment.h @@ -257,6 +257,8 @@ class CGUIEnvironment : public IGUIEnvironment, public IGUIElement virtual void readGUIElement(io::IXMLReader* reader, IGUIElement* node); virtual void removeHovered(IGUIElement* element); + + virtual bool setChildEnd(IGUIElement* end) { return IGUIElement::setChildEnd(end); } private: IGUIElement* getNextElement(bool reverse=false, bool group=false); diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.cpp b/src/guiengine/widgets/dynamic_ribbon_widget.cpp index d7057510276..06fc9109e99 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.cpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.cpp @@ -197,9 +197,11 @@ void DynamicRibbonWidget::resize() for (unsigned i = 0; i < MAX_PLAYER_COUNT; i++) selected[i] = getSelectionIDString(i); Widget::resize(); + GUIEngine::getGUIEnv()->setChildEnd(m_left_widget->m_element); updateForResizing(); buildInternalStructure(); updateItemDisplay(); + GUIEngine::getGUIEnv()->setChildEnd(NULL); for (unsigned i = 0; i < MAX_PLAYER_COUNT; i++) { if (!selected[i].empty()) From 17aa396640fb5c4348a79366dd8e01446c9b3943 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 27 Apr 2024 18:37:12 +0400 Subject: [PATCH 337/830] Add /whyhourglass to check if hourglass is caused by slots number or not --- data/commands.xml | 7 ++ src/network/protocols/command_manager.cpp | 96 +++++++++++++++++++++++ src/network/protocols/command_manager.hpp | 1 + src/network/protocols/server_lobby.cpp | 73 +++++++++++++---- src/network/protocols/server_lobby.hpp | 3 +- src/utils/hourglass_reason.hpp | 39 +++++++++ 6 files changed, 201 insertions(+), 18 deletions(-) create mode 100644 src/utils/hourglass_reason.hpp diff --git a/data/commands.xml b/data/commands.xml index 36eff41c66f..644aa561718 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -1122,6 +1122,13 @@ here later. For now, please refer to the code for the strings being used. --> permissions="UP_HAMMER" /> + getPlayerProfiles().empty()) + { + Log::warn("CommandManager", "whyhourglass: no existing player profiles??"); + error(context); + return; + } + player_name = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + } + else + { + if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, + 1, m_stf_present_users, 3, false, false)) + return; + player_name = argv[1]; + } + std::shared_ptr player_peer = STKHost::get()->findPeerByName( + StringUtils::utf8ToWide(player_name)); + if (player_name.empty() || !player_peer) + { + error(context); + return; + } + auto it = m_lobby->m_why_peer_cannot_play.find(player_peer.get()); + if (it == m_lobby->m_why_peer_cannot_play.end()) + { + response = "For some reason, server doesn't know about the hourglass status of this player."; + } + else + { + switch (it->second) + { + case HR_NONE: + response = "%s can play (but if hourglass is present, there are not enough slots on the server)."; + break; + case HR_ABSENT_PEER: + response = "Player %s is not present on the server."; + break; + case HR_NOT_A_TOURNAMENT_PLAYER: + response = "%s is not a tournament player for this game."; + break; + case HR_SPECTATOR_BY_LIMIT: + response = "Not enough slots to fit %s."; + break; + case HR_NO_KARTS_AFTER_FILTER: + response = "After applying all kart filters, %s doesn't have karts to play."; + break; + case HR_NO_MAPS_AFTER_FILTER: + response = "After applying all map filters, %s doesn't have maps to play."; + break; + case HR_LACKING_REQUIRED_MAPS: + response = "%s lacks required maps."; + break; + case HR_ADDON_KARTS_PLAY_THRESHOLD: + response = "Player %s doesn't have enough addon karts."; + break; + case HR_ADDON_TRACKS_PLAY_THRESHOLD: + response = "Player %s doesn't have enough addon tracks."; + break; + case HR_ADDON_ARENAS_PLAY_THRESHOLD: + response = "Player %s doesn't have enough addon arenas."; + break; + case HR_ADDON_FIELDS_PLAY_THRESHOLD: + response = "Player %s doesn't have enough addon fields."; + break; + case HR_OFFICIAL_KARTS_PLAY_THRESHOLD: + response = "The number of official karts for %s is lower than the threshold."; + break; + case HR_OFFICIAL_TRACKS_PLAY_THRESHOLD: + response = "The number of official tracks for %s is lower than the threshold."; + break; + default: + response = ""; + break; + } + response = StringUtils::insertValues(response, player_name.c_str()); + } + m_lobby->sendStringToPeer(response, peer); +} // process_why_hourglass +// ======================================================================== + void CommandManager::special(Context& context) { auto peer = context.m_peer.lock(); diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 6e17b335025..0d65ba4182d 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -360,6 +360,7 @@ class CommandManager void process_history_assign(Context& context); void process_voting(Context& context); void process_voting_assign(Context& context); + void process_why_hourglass(Context& context); void special(Context& context); std::string getRandomMap() const; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index ad51c9be6c4..32baf2ed782 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6428,7 +6428,7 @@ std::set& ServerLobby::getSpectatorsByLimit(bool update) if (!update) return m_spectators_by_limit; - m_peers_ability_to_play.clear(); + m_why_peer_cannot_play.clear(); m_spectators_by_limit.clear(); auto peers = STKHost::get()->getPeers(); @@ -7129,22 +7129,31 @@ bool ServerLobby::canRace(std::shared_ptr& peer) //----------------------------------------------------------------------------- bool ServerLobby::canRace(STKPeer* peer) { - auto it = m_peers_ability_to_play.find(peer); - if (it != m_peers_ability_to_play.end()) - return it->second; + auto it = m_why_peer_cannot_play.find(peer); + if (it != m_why_peer_cannot_play.end()) + return it->second == 0; if (!peer || peer->getPlayerProfiles().empty()) - return m_peers_ability_to_play[peer] = false; + { + m_why_peer_cannot_play[peer] = HR_ABSENT_PEER; + return false; + } std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); if (ServerConfig::m_soccer_tournament) { if (m_tournament_red_players.count(username) == 0 && m_tournament_blue_players.count(username) == 0) - return m_peers_ability_to_play[peer] = false; + { + m_why_peer_cannot_play[peer] = HR_NOT_A_TOURNAMENT_PLAYER; + return false; + } } else if (m_spectators_by_limit.find(peer) != m_spectators_by_limit.end()) - return m_peers_ability_to_play[peer] = false; + { + m_why_peer_cannot_play[peer] = HR_SPECTATOR_BY_LIMIT; + return false; + } std::set maps = peer->getClientAssets().second; std::set karts = peer->getClientAssets().first; @@ -7152,22 +7161,45 @@ bool ServerLobby::canRace(STKPeer* peer) applyAllFilters(maps, true); applyAllKartFilters(username, karts, false); - if (maps.empty() || karts.empty()) - return m_peers_ability_to_play[peer] = false; + if (karts.empty()) + { + m_why_peer_cannot_play[peer] = HR_NO_KARTS_AFTER_FILTER; + return false; + } + if (maps.empty()) + { + m_why_peer_cannot_play[peer] = HR_NO_MAPS_AFTER_FILTER; + return false; + } if (!m_play_requirement_tracks.empty()) for (const std::string& track: m_play_requirement_tracks) if (peer->getClientAssets().second.count(track) == 0) - return m_peers_ability_to_play[peer] = false; + { + m_why_peer_cannot_play[peer] = HR_LACKING_REQUIRED_MAPS; + return false; + } if (peer->addon_karts_count < ServerConfig::m_addon_karts_play_threshold) - return m_peers_ability_to_play[peer] = false; + { + m_why_peer_cannot_play[peer] = HR_ADDON_KARTS_PLAY_THRESHOLD; + return false; + } if (peer->addon_tracks_count < ServerConfig::m_addon_tracks_play_threshold) - return m_peers_ability_to_play[peer] = false; + { + m_why_peer_cannot_play[peer] = HR_ADDON_TRACKS_PLAY_THRESHOLD; + return false; + } if (peer->addon_arenas_count < ServerConfig::m_addon_arenas_play_threshold) - return m_peers_ability_to_play[peer] = false; + { + m_why_peer_cannot_play[peer] = HR_ADDON_ARENAS_PLAY_THRESHOLD; + return false; + } if (peer->addon_soccers_count < ServerConfig::m_addon_soccers_play_threshold) - return m_peers_ability_to_play[peer] = false; + { + m_why_peer_cannot_play[peer] = HR_ADDON_FIELDS_PLAY_THRESHOLD; + return false; + } float karts_fraction = 0.0f; float maps_fraction = 0.0f; @@ -7187,10 +7219,17 @@ bool ServerLobby::canRace(STKPeer* peer) maps_fraction /= (float)m_official_kts.second.size(); if (karts_fraction < ServerConfig::m_official_karts_play_threshold) - return m_peers_ability_to_play[peer] = false; + { + m_why_peer_cannot_play[peer] = HR_OFFICIAL_KARTS_PLAY_THRESHOLD; + return false; + } if (maps_fraction < ServerConfig::m_official_tracks_play_threshold) - return m_peers_ability_to_play[peer] = false; - return m_peers_ability_to_play[peer] = true; + { + m_why_peer_cannot_play[peer] = HR_OFFICIAL_TRACKS_PLAY_THRESHOLD; + return false; + } + m_why_peer_cannot_play[peer] = 0; + return true; } // canRace //----------------------------------------------------------------------------- bool ServerLobby::canVote(std::shared_ptr& peer) const diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 6c37f7f1c21..9a1c1f4a4c4 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -26,6 +26,7 @@ #include "utils/time.hpp" #include "utils/track_filter.hpp" #include "utils/map_vote_handler.hpp" +#include "utils/hourglass_reason.hpp" #include "karts/controller/player_controller.hpp" #include "network/protocols/command_manager.hpp" @@ -313,7 +314,7 @@ class ServerLobby : public LobbyProtocol std::set m_team_speakers; - std::map m_peers_ability_to_play; + std::map m_why_peer_cannot_play; KartElimination m_kart_elimination; diff --git a/src/utils/hourglass_reason.hpp b/src/utils/hourglass_reason.hpp new file mode 100644 index 00000000000..13de6e1a7a4 --- /dev/null +++ b/src/utils/hourglass_reason.hpp @@ -0,0 +1,39 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2013-2015 Lauri Kasanen +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HOURGLASS_REASON_H +#define HOURGLASS_REASON_H + +enum HourglassReason : int +{ + HR_NONE = 0, + HR_ABSENT_PEER = (1 << 0), + HR_NOT_A_TOURNAMENT_PLAYER = (1 << 1), + HR_SPECTATOR_BY_LIMIT = (1 << 2), + HR_NO_KARTS_AFTER_FILTER = (1 << 3), + HR_NO_MAPS_AFTER_FILTER = (1 << 4), + HR_LACKING_REQUIRED_MAPS = (1 << 5), + HR_ADDON_KARTS_PLAY_THRESHOLD = (1 << 6), + HR_ADDON_TRACKS_PLAY_THRESHOLD = (1 << 7), + HR_ADDON_ARENAS_PLAY_THRESHOLD = (1 << 8), + HR_ADDON_FIELDS_PLAY_THRESHOLD = (1 << 9), + HR_OFFICIAL_KARTS_PLAY_THRESHOLD = (1 << 10), + HR_OFFICIAL_TRACKS_PLAY_THRESHOLD = (1 << 11) +}; + +#endif From f6949972b3a7dbf429dc4dedcc718a418a4a9753 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 28 Apr 2024 11:15:41 +0800 Subject: [PATCH 338/830] Add resizing code for label widget --- src/guiengine/widgets/label_widget.cpp | 64 +++++++++++++------ src/guiengine/widgets/label_widget.hpp | 14 +++- src/states_screens/main_menu_screen.cpp | 2 +- .../online/networking_lobby.cpp | 2 +- 4 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/guiengine/widgets/label_widget.cpp b/src/guiengine/widgets/label_widget.cpp index 2df83216250..0ffbafbe191 100644 --- a/src/guiengine/widgets/label_widget.cpp +++ b/src/guiengine/widgets/label_widget.cpp @@ -40,7 +40,9 @@ LabelWidget::LabelWidget(LabelType type) : Widget(WTYPE_LABEL) { m_type = type; m_scroll_speed = 0; + m_per_character_size = 0; m_scroll_offset = 0; + m_expand_if_needed = false; if (m_type == BRIGHT) { @@ -109,6 +111,8 @@ void LabelWidget::add() irrwidget->setOverrideColor( video::SColor(255,255,255,255) ); irrwidget->setOverrideFont( GUIEngine::getTinyTitleFont() ); } + m_per_character_size = getCurrentFont()->getDimension(L"X").Height; + //irrwidget->setBackgroundColor( video::SColor(255,255,0,0) ); //irrwidget->setDrawBackground(true); @@ -129,19 +133,27 @@ void LabelWidget::add() void LabelWidget::setText(const core::stringw& text, bool expandIfNeeded) { m_scroll_offset = 0; + m_expand_if_needed = expandIfNeeded; + updateExpandedText(text); + Widget::setText(text); +} // setText + +// ---------------------------------------------------------------------------- +irr::gui::IGUIFont* LabelWidget::getCurrentFont() const +{ + IGUIFont* font = static_cast(m_element)->getOverrideFont(); + if (!font) + font = GUIEngine::getFont(); + return font; +} // getCurrentFont - if (expandIfNeeded) +// ---------------------------------------------------------------------------- +void LabelWidget::updateExpandedText(const irr::core::stringw& text) +{ + if (m_expand_if_needed) { assert(m_element != NULL); - int fwidth; - if(m_type == TITLE) - fwidth = GUIEngine::getTitleFont()->getDimension(text.c_str()).Width; - else if(m_type == SMALL_TITLE) - fwidth = GUIEngine::getSmallTitleFont()->getDimension(text.c_str()).Width; - else if(m_type == TINY_TITLE) - fwidth = GUIEngine::getTinyTitleFont()->getDimension(text.c_str()).Width; - else - fwidth = GUIEngine::getFont()->getDimension(text.c_str()).Width; + int fwidth = getCurrentFont()->getDimension(text.c_str()).Width; core::rect rect = m_element->getRelativePosition(); if (rect.getWidth() < fwidth) @@ -151,12 +163,7 @@ void LabelWidget::setText(const core::stringw& text, bool expandIfNeeded) m_element->updateAbsolutePosition(); } } - - if (m_scroll_speed > 0) - m_scroll_offset = (float)m_w; - - Widget::setText(text); -} // setText +} // updateExpandedText // ---------------------------------------------------------------------------- /** Needs to be called to update scrolling. @@ -166,8 +173,9 @@ void LabelWidget::update(float dt) { if (m_scroll_speed != 0) { - m_scroll_offset -= dt*m_scroll_speed*5.0f; - m_element->setRelativePosition( core::position2di( /*m_x +*/ (int)m_scroll_offset, + m_scroll_offset -= dt * m_scroll_speed * 5.0f; + int offset = (float)m_w + m_scroll_offset * m_per_character_size; + m_element->setRelativePosition( core::position2di( /*m_x +*/ offset, /*m_y*/ 0 ) ); } } // update @@ -177,7 +185,8 @@ bool LabelWidget::scrolledOff() const { // This method may only be called after this widget has been add()ed assert(m_element != NULL); - return m_scroll_offset <= -m_element->getAbsolutePosition().getWidth(); + return (float)m_w + m_scroll_offset * m_per_character_size <= + -1.0f * (float)m_element->getAbsolutePosition().getWidth(); } // ---------------------------------------------------------------------------- @@ -189,6 +198,23 @@ void LabelWidget::setScrollSpeed(float speed) // ---------------------------------------------------------------------------- +void LabelWidget::resize() +{ + m_per_character_size = getCurrentFont()->getDimension(L"X").Height; + if (m_scroll_speed != 0) + { + rect widget_size = rect(m_x, m_y, m_x + m_w, m_y + m_h); + core::rect r(core::position2di(0, 0), widget_size.getSize()); + m_element->getParent()->setRelativePosition(widget_size); + m_element->setRelativePosition(r); + updateExpandedText(m_text); + } + else + Widget::resize(); +} // resize + +// ---------------------------------------------------------------------------- + void LabelWidget::setColor(const irr::video::SColor& color) { assert(m_element != NULL); diff --git a/src/guiengine/widgets/label_widget.hpp b/src/guiengine/widgets/label_widget.hpp index e03808d6f95..26cf1c2df40 100644 --- a/src/guiengine/widgets/label_widget.hpp +++ b/src/guiengine/widgets/label_widget.hpp @@ -27,6 +27,11 @@ #include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" +namespace irr +{ + namespace gui { class IGUIFont; } +} + namespace GUIEngine { /** \brief A simple label widget. @@ -51,10 +56,16 @@ namespace GUIEngine LabelType m_type; irr::video::SColor m_color; bool m_has_color; + bool m_expand_if_needed; + + irr::gui::IGUIFont* getCurrentFont() const; + void updateExpandedText(const irr::core::stringw& text); /** Scroll speed in characters/seconds (0 if no scrolling). */ float m_scroll_speed; - + + float m_per_character_size; + /** Current scroll offset. */ float m_scroll_offset; @@ -114,6 +125,7 @@ namespace GUIEngine */ bool scrolledOff() const; + virtual void resize(); }; } diff --git a/src/states_screens/main_menu_screen.cpp b/src/states_screens/main_menu_screen.cpp index 6a91c728e87..91c4964fb34 100644 --- a/src/states_screens/main_menu_screen.cpp +++ b/src/states_screens/main_menu_screen.cpp @@ -86,7 +86,7 @@ MainMenuScreen::MainMenuScreen() : Screen("main_menu.stkgui") void MainMenuScreen::loadedFromFile() { LabelWidget* w = getWidget("info_addons"); - w->setScrollSpeed(GUIEngine::getFontHeight() / 2); + w->setScrollSpeed(0.5f); RibbonWidget* rw_top = getWidget("menu_toprow"); assert(rw_top != NULL); diff --git a/src/states_screens/online/networking_lobby.cpp b/src/states_screens/online/networking_lobby.cpp index d6a950bef45..6db6736da7f 100644 --- a/src/states_screens/online/networking_lobby.cpp +++ b/src/states_screens/online/networking_lobby.cpp @@ -450,7 +450,7 @@ void NetworkingLobby::onUpdate(float delta) m_header->getIrrlichtElement()->remove(); if (m_header_text_width > m_header->m_w) { - m_header->setScrollSpeed(GUIEngine::getTitleFontHeight() / 2); + m_header->setScrollSpeed(0.5f); m_header->add(); m_header->setText(m_header_text, true); } From 18094c505a125b6bb5b0c1f8dfd3befa37b7088b Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 28 Apr 2024 13:25:20 +0800 Subject: [PATCH 339/830] Add resizing code for networking lobby --- src/guiengine/widgets/label_widget.hpp | 3 +- .../online/networking_lobby.cpp | 28 +++++++++++++++++++ .../online/networking_lobby.hpp | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/guiengine/widgets/label_widget.hpp b/src/guiengine/widgets/label_widget.hpp index 26cf1c2df40..9f6a8c8156d 100644 --- a/src/guiengine/widgets/label_widget.hpp +++ b/src/guiengine/widgets/label_widget.hpp @@ -117,7 +117,8 @@ namespace GUIEngine void setScrollSpeed(float speed); // -------------------------------------------------------------------- - + float getScrollSpeed() const { return m_scroll_speed; } + // -------------------------------------------------------------------- /** * \brief Check if the current has been fully scrolled * \return true if the text has completely scrolled off diff --git a/src/states_screens/online/networking_lobby.cpp b/src/states_screens/online/networking_lobby.cpp index 6db6736da7f..cf26751d649 100644 --- a/src/states_screens/online/networking_lobby.cpp +++ b/src/states_screens/online/networking_lobby.cpp @@ -422,6 +422,34 @@ void NetworkingLobby::addMoreServerInfo(core::stringw info) #endif } // addMoreServerInfo +// ---------------------------------------------------------------------------- +void NetworkingLobby::onResize() +{ + Screen::onResize(); + const unsigned box_width = m_text_bubble->getDimension().Width; + const float box_height = m_text_bubble->getDimension().Height; + gui::IGUIFont* font = GUIEngine::getFont(); + gui::breakGlyphLayouts(m_server_info, box_width, + font->getInverseShaping(), font->getScale()); + gui::eraseTopLargerThan(m_server_info, font->getHeightPerLine(), + box_height); + updateServerInfos(); + + int header_text_width = + GUIEngine::getTitleFont()->getDimension(m_header_text.c_str()).Width; + if ((m_header->m_w < header_text_width && m_header->getScrollSpeed() == 0.0f) || + (m_header->m_w >= header_text_width && m_header->getScrollSpeed() != 0.0f)) + { + m_header->getIrrlichtElement()->remove(); + GUIEngine::getGUIEnv()->setChildEnd(m_back_widget->getIrrlichtElement()); + m_header->setScrollSpeed(m_header->m_w < header_text_width ? 0.5f: 0.0f); + m_header->add(); + m_header->setText(m_header_text, true); + GUIEngine::getGUIEnv()->setChildEnd(NULL); + } + m_header_text_width = header_text_width; +} // onResize + // ---------------------------------------------------------------------------- void NetworkingLobby::updateServerInfos() { diff --git a/src/states_screens/online/networking_lobby.hpp b/src/states_screens/online/networking_lobby.hpp index 554023d50ec..9184ce9c82e 100644 --- a/src/states_screens/online/networking_lobby.hpp +++ b/src/states_screens/online/networking_lobby.hpp @@ -149,6 +149,7 @@ class NetworkingLobby : public GUIEngine::Screen, void reloadServerInfos() { m_reload_server_info = true; } void setHeader(const core::stringw& header) { m_header_text = header; } void setAssignedPlayers(bool val) { m_assigned_players = val; } + virtual void onResize() OVERRIDE; }; // class NetworkingLobby #endif From 9206b923f706e91c79208038fd678653f8235233 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 28 Apr 2024 15:57:42 +0800 Subject: [PATCH 340/830] Use xmlDecode for news --- src/addons/news_manager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/addons/news_manager.cpp b/src/addons/news_manager.cpp index 7fb2220efa3..fda8a3d6a03 100644 --- a/src/addons/news_manager.cpp +++ b/src/addons/news_manager.cpp @@ -302,8 +302,9 @@ void NewsManager::updateNews(const XMLNode *xml, const std::string &filename) { const XMLNode *node = xml->getNode(i); if(node->getName()!="message") continue; - core::stringw news; - node->get("content", &news); + std::string raw_news; + node->get("content", &raw_news); + core::stringw news = StringUtils::xmlDecode(raw_news); int id=-1; node->get("id", &id); bool important=false; From 01d62be5dea3b263486311f0c2e0a501438cc19c Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sun, 28 Apr 2024 18:32:51 +0200 Subject: [PATCH 341/830] Fix crashing when turning the modern renderer on or off before benchmarking --- src/race/race_manager.cpp | 10 +++ src/race/race_manager.hpp | 7 ++ .../options/options_screen_video.cpp | 65 ++++++++++++++----- .../options/options_screen_video.hpp | 1 + 4 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index e45c2737e05..823ddf60680 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -146,6 +146,7 @@ RaceManager::RaceManager() setRaceGhostKarts(false); setWatchingReplay(false); setBenchmarking(false); + m_scheduled_benchmark = false; setTrack("jungle"); m_default_ai_list.clear(); setNumPlayers(0); @@ -1330,6 +1331,7 @@ core::stringw RaceManager::getDifficultyName(Difficulty diff) const void RaceManager::setBenchmarking(bool benchmark) { m_benchmarking = benchmark; + m_scheduled_benchmark = false; // If the benchmark mode is turned off and the profiler is still activated, // turn the profiler off and reset the drawing mode to default. @@ -1339,3 +1341,11 @@ void RaceManager::setBenchmarking(bool benchmark) profiler.setDrawing(true); } } // setBenchmarking + +//--------------------------------------------------------------------------------------------- +/** Schedule a benchmark. This function is used because the video options screen +* might need to be reloaded when switching between old and modern renderer.*/ +void RaceManager::scheduleBenchmark() +{ + m_scheduled_benchmark = true; +} // scheduleBenchmark \ No newline at end of file diff --git a/src/race/race_manager.hpp b/src/race/race_manager.hpp index 4341674b38f..3f5d28a659f 100644 --- a/src/race/race_manager.hpp +++ b/src/race/race_manager.hpp @@ -368,6 +368,7 @@ class RaceManager bool m_has_ghost_karts; bool m_watching_replay; bool m_benchmarking; + bool m_scheduled_benchmark; public: // ---------------------------------------------------------------------------------------- @@ -438,6 +439,7 @@ class RaceManager void setDefaultAIKartList(const std::vector &ai_list); void computeRandomKartList(); void setBenchmarking(bool benchmark); + void scheduleBenchmark(); // ---------------------------------------------------------------------------------------- bool hasTimeTarget() const { return m_time_target > 0.0f; } @@ -875,6 +877,11 @@ class RaceManager return m_benchmarking; } // isBenchmarking // ---------------------------------------------------------------------------------------- + bool isBenchmarkScheduled() const + { + return m_scheduled_benchmark; + } // isBenchmarkSchedule + // ---------------------------------------------------------------------------------------- void addSpareTireKart(const std::string& name) { m_kart_status.push_back(KartStatus(name, 0, -1, -1, diff --git a/src/states_screens/options/options_screen_video.cpp b/src/states_screens/options/options_screen_video.cpp index f8163365367..5c6de359c04 100644 --- a/src/states_screens/options/options_screen_video.cpp +++ b/src/states_screens/options/options_screen_video.cpp @@ -371,6 +371,12 @@ void OptionsScreenVideo::init() m_fullscreen_checkbox_focus = false; getWidget("fullscreen")->setFocusForPlayer(PLAYER_ID_GAME_MASTER); } + + // If a benchmark was requested and the game had to reload + // the graphics engine, start the benchmark when the + // video settings screen is loaded back afterwards. + if (RaceManager::get()->isBenchmarkScheduled()) + startBenchmark(); } // init // -------------------------------------------------------------------------------------------- @@ -882,7 +888,7 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name, updateBlurSlider(); } - else if (name == "vsync") + else if (name == "vsync") // Also handles the FPS limiter { GUIEngine::SpinnerWidget* vsync = getWidget("vsync"); assert( vsync != NULL ); @@ -904,7 +910,7 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name, #if !defined(SERVER_ONLY) && defined(_IRR_COMPILE_WITH_SDL_DEVICE_) update_swap_interval(UserConfigParams::m_swap_interval); #endif - } + } // vSync else if (name == "scale_rtts") { GUIEngine::SpinnerWidget* scale_rtts_level = @@ -924,7 +930,7 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name, } #endif updateScaleRTTsSlider(); - } + } // scale_rtts else if (name == "benchmarkCurrent") { // TODO - Add the possibility to benchmark more tracks and define replay benchmarks in @@ -935,20 +941,27 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name, if (!result) Log::fatal("OptionsScreenVideo", "Can't open replay for benchmark!"); - RaceManager::get()->setRaceGhostKarts(true); - - RaceManager::get()->setMinorMode(RaceManager::MINOR_MODE_TIME_TRIAL); - ReplayPlay::ReplayData bench_rd = ReplayPlay::get()->getCurrentReplayData(); - RaceManager::get()->setReverseTrack(bench_rd.m_reverse); - RaceManager::get()->setRecordRace(false); - RaceManager::get()->setWatchingReplay(true); - RaceManager::get()->setDifficulty((RaceManager::Difficulty)bench_rd.m_difficulty); - - // The race manager automatically adds karts for the ghosts - RaceManager::get()->setNumKarts(0); - RaceManager::get()->setBenchmarking(true); - RaceManager::get()->startWatchingReplay(bench_rd.m_track_name, bench_rd.m_laps); - } + + // Avoid crashing, when switching between advanced lighting and the old renderer + // before starting a performance test, ensure the image quality setting is applied + if (m_prev_adv_pipline != UserConfigParams::m_dynamic_lights && + CVS->isGLSL()) + { + irr_driver->sameRestart(); + // We cannot start the benchmark immediately, in case we just restarted the graphics engine + RaceManager::get()->scheduleBenchmark(); + } + else if (m_prev_img_quality != getImageQuality()) + { + // TODO - check if this is enough for the setting to be properly applied + irr_driver->setMaxTextureSize(); + startBenchmark(); + } + else + { + startBenchmark(); + } + } // benchmarkCurrent // TODO - Add a standard benchmark testing multiple presets /*else if (name == "benchmarkStandard") { @@ -998,6 +1011,24 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name, // -------------------------------------------------------------------------------------------- +void OptionsScreenVideo::startBenchmark() +{ + RaceManager::get()->setRaceGhostKarts(true); + RaceManager::get()->setMinorMode(RaceManager::MINOR_MODE_TIME_TRIAL); + ReplayPlay::ReplayData bench_rd = ReplayPlay::get()->getCurrentReplayData(); + RaceManager::get()->setReverseTrack(bench_rd.m_reverse); + RaceManager::get()->setRecordRace(false); + RaceManager::get()->setWatchingReplay(true); + RaceManager::get()->setDifficulty((RaceManager::Difficulty)bench_rd.m_difficulty); + + // The race manager automatically adds karts for the ghosts + RaceManager::get()->setNumKarts(0); + RaceManager::get()->setBenchmarking(true); // Also turns off the scheduled benchmark if needed + RaceManager::get()->startWatchingReplay(bench_rd.m_track_name, bench_rd.m_laps); +} // startBenchmark + +// -------------------------------------------------------------------------------------------- + void OptionsScreenVideo::tearDown() { if (getWidget("fullscreen")->isVisible() && diff --git a/src/states_screens/options/options_screen_video.hpp b/src/states_screens/options/options_screen_video.hpp index 38fcdbd3ecc..cbdbc2bbc7f 100644 --- a/src/states_screens/options/options_screen_video.hpp +++ b/src/states_screens/options/options_screen_video.hpp @@ -104,6 +104,7 @@ class OptionsScreenVideo : public GUIEngine::Screen, public GUIEngine::ScreenSin void updateResolutionsList(); void configResolutionsList(); void initPresets(); + void startBenchmark(); static void onScrollResolutionsList(void* data); public: friend class GUIEngine::ScreenSingleton; From e64e2d8cd512483259b2ca24b0a47f6f817c1fe3 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sun, 28 Apr 2024 21:43:42 +0200 Subject: [PATCH 342/830] Fix #4931 The assert could be triggered when a new sign-in request was sent before the first one was resolved, usually when using the enter key to request the sign in. Since it can happen in normal operations to have the player profile status different from signing out or signed out, an assert is incorrect. Also fix server-only compilation for the previous commit. --- src/online/online_player_profile.cpp | 10 +++++----- src/states_screens/options/options_screen_video.cpp | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/online/online_player_profile.cpp b/src/online/online_player_profile.cpp index 693391b13bb..6e21bdd5942 100644 --- a/src/online/online_player_profile.cpp +++ b/src/online/online_player_profile.cpp @@ -107,7 +107,6 @@ namespace Online m_online_state = OS_SIGNED_OUT; m_token = ""; m_profile = NULL; - } // OnlinePlayerProfile // ------------------------------------------------------------------------ @@ -136,10 +135,11 @@ namespace Online void OnlinePlayerProfile::requestSignIn(const core::stringw &username, const core::stringw &password) { - // If the player changes the online account, there can be a - // logout stil happening. - assert(m_online_state == OS_SIGNED_OUT || - m_online_state == OS_SIGNING_OUT); + // Avoid multiple sign in requests from happening at once, + // this can occur for example when using the enter key to request a sign-in. + if (m_online_state != OS_SIGNED_OUT && m_online_state != OS_SIGNING_OUT) + return; + auto request = std::make_shared(); // We can't use setUserDetail here, since there is no token yet diff --git a/src/states_screens/options/options_screen_video.cpp b/src/states_screens/options/options_screen_video.cpp index 5c6de359c04..e05d07b153a 100644 --- a/src/states_screens/options/options_screen_video.cpp +++ b/src/states_screens/options/options_screen_video.cpp @@ -933,6 +933,7 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name, } // scale_rtts else if (name == "benchmarkCurrent") { +#ifndef SERVER_ONLY // TODO - Add the possibility to benchmark more tracks and define replay benchmarks in // a config file const std::string bf_bench("benchmark_black_forest.replay"); @@ -961,6 +962,7 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name, { startBenchmark(); } +#endif } // benchmarkCurrent // TODO - Add a standard benchmark testing multiple presets /*else if (name == "benchmarkStandard") From 5ff449d6c94d1d74d79ecc7032691818186cddc0 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 29 Apr 2024 10:06:47 +0800 Subject: [PATCH 343/830] Remove an unneeded method --- lib/irrlicht/include/IGUIEnvironment.h | 2 -- lib/irrlicht/source/Irrlicht/CGUIEnvironment.h | 2 -- src/guiengine/widgets/dynamic_ribbon_widget.cpp | 4 ++-- src/states_screens/online/networking_lobby.cpp | 4 ++-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/irrlicht/include/IGUIEnvironment.h b/lib/irrlicht/include/IGUIEnvironment.h index c5cd83a0ba1..84c40924345 100644 --- a/lib/irrlicht/include/IGUIEnvironment.h +++ b/lib/irrlicht/include/IGUIEnvironment.h @@ -612,8 +612,6 @@ class IGUIEnvironment : public virtual IReferenceCounted virtual void readGUIElement(io::IXMLReader* reader, IGUIElement* node) =0; virtual void removeHovered(IGUIElement* element) = 0; - - virtual bool setChildEnd(IGUIElement* end) = 0; }; diff --git a/lib/irrlicht/source/Irrlicht/CGUIEnvironment.h b/lib/irrlicht/source/Irrlicht/CGUIEnvironment.h index 3e5fef8171e..efe055f2538 100644 --- a/lib/irrlicht/source/Irrlicht/CGUIEnvironment.h +++ b/lib/irrlicht/source/Irrlicht/CGUIEnvironment.h @@ -257,8 +257,6 @@ class CGUIEnvironment : public IGUIEnvironment, public IGUIElement virtual void readGUIElement(io::IXMLReader* reader, IGUIElement* node); virtual void removeHovered(IGUIElement* element); - - virtual bool setChildEnd(IGUIElement* end) { return IGUIElement::setChildEnd(end); } private: IGUIElement* getNextElement(bool reverse=false, bool group=false); diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.cpp b/src/guiengine/widgets/dynamic_ribbon_widget.cpp index 06fc9109e99..b7af7ead872 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.cpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.cpp @@ -197,11 +197,11 @@ void DynamicRibbonWidget::resize() for (unsigned i = 0; i < MAX_PLAYER_COUNT; i++) selected[i] = getSelectionIDString(i); Widget::resize(); - GUIEngine::getGUIEnv()->setChildEnd(m_left_widget->m_element); + GUIEngine::getGUIEnv()->getRootGUIElement()->setChildEnd(m_left_widget->m_element); updateForResizing(); buildInternalStructure(); updateItemDisplay(); - GUIEngine::getGUIEnv()->setChildEnd(NULL); + GUIEngine::getGUIEnv()->getRootGUIElement()->setChildEnd(NULL); for (unsigned i = 0; i < MAX_PLAYER_COUNT; i++) { if (!selected[i].empty()) diff --git a/src/states_screens/online/networking_lobby.cpp b/src/states_screens/online/networking_lobby.cpp index cf26751d649..217653c33fa 100644 --- a/src/states_screens/online/networking_lobby.cpp +++ b/src/states_screens/online/networking_lobby.cpp @@ -441,11 +441,11 @@ void NetworkingLobby::onResize() (m_header->m_w >= header_text_width && m_header->getScrollSpeed() != 0.0f)) { m_header->getIrrlichtElement()->remove(); - GUIEngine::getGUIEnv()->setChildEnd(m_back_widget->getIrrlichtElement()); + GUIEngine::getGUIEnv()->getRootGUIElement()->setChildEnd(m_back_widget->getIrrlichtElement()); m_header->setScrollSpeed(m_header->m_w < header_text_width ? 0.5f: 0.0f); m_header->add(); m_header->setText(m_header_text, true); - GUIEngine::getGUIEnv()->setChildEnd(NULL); + GUIEngine::getGUIEnv()->getRootGUIElement()->setChildEnd(NULL); } m_header_text_width = header_text_width; } // onResize From 3f8b78dc414eb7df385207fa036eff59925de26c Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 29 Apr 2024 10:18:51 +0800 Subject: [PATCH 344/830] Add resizing code for CGUIEditBox --- src/guiengine/widgets/CGUIEditBox.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/guiengine/widgets/CGUIEditBox.cpp b/src/guiengine/widgets/CGUIEditBox.cpp index 7af0c6b68c1..865997f24e1 100644 --- a/src/guiengine/widgets/CGUIEditBox.cpp +++ b/src/guiengine/widgets/CGUIEditBox.cpp @@ -307,6 +307,7 @@ bool CGUIEditBox::isOverrideColorEnabled() const void CGUIEditBox::updateAbsolutePosition() { IGUIElement::updateAbsolutePosition(); + calculateScrollPos(); } From 32a53827a862e7e4209e2f493fb390dc24d4bbfa Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 29 Apr 2024 10:55:55 +0200 Subject: [PATCH 345/830] Fix #5063 - Ensure that optional geometry objects are properly removed. This provides a massive performance boost, at the cost of visuals. Benchmark on graphics 2 with lowest geometry level: bugged has 202 steady FPS, 230 mostly stable FPS, fixed has 427 steady FPS, 495 mostly stable FPS. - Restrict the removal of objects based on geometry detail to the lowest geometry level. This ignore the different levels of geometry removal that track authors can set for objects, and which was mostly unused: all objects marked for removal at any level are either all removed or all kept. --- src/states_screens/dialogs/custom_video_settings.cpp | 4 ++-- src/tracks/track.cpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/states_screens/dialogs/custom_video_settings.cpp b/src/states_screens/dialogs/custom_video_settings.cpp index e2bd8815a36..131590872bd 100644 --- a/src/states_screens/dialogs/custom_video_settings.cpp +++ b/src/states_screens/dialogs/custom_video_settings.cpp @@ -72,9 +72,9 @@ void CustomVideoSettingsDialog::beforeAddingWidgets() particles_effects->setValue(UserConfigParams::m_particles_effects); SpinnerWidget* geometry_level = getWidget("geometry_detail"); - //I18N: Geometry level disabled : lowest level, no details + //I18N: Geometry level disabled : lowest level, no details, Level-of-Details distances are low geometry_level->addLabel(_("Very Low")); - //I18N: Geometry level low : few details are displayed + //I18N: Geometry level low : everything is displayed, Level-of-Details distances are low geometry_level->addLabel(_("Low")); //I18N: Geometry level medium : everything is displayed, Level-of-Details distances are medium geometry_level->addLabel(_("Medium")); diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 1a7c78a556e..93945edbbe1 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -2357,8 +2357,9 @@ void Track::loadObjects(const XMLNode* root, const std::string& path, { int geo_level = 0; node->get("geometry-level", &geo_level); - if (UserConfigParams::m_geometry_level <= 2 && - UserConfigParams::m_geometry_level + geo_level - 2 > 0 && + // Only remove objects in the "very low" geometry detail level. + // Other levels are used for LoD distance + if (UserConfigParams::m_geometry_level == 2 && geo_level >= 0 && !NetworkConfig::get()->isNetworking()) continue; m_track_object_manager->add(*node, parent, model_def_loader, parent_library); From 95c8f452dee58e7e3a94fcc0a8e854452c0fa970 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 29 Apr 2024 11:12:25 +0200 Subject: [PATCH 346/830] Update the LoD distance factors With the existing engine and tracks, when the framerate is rather GPU-limited, the performance cost of increasing LoD distance is minor. It becomes more significant at higher framerates when the CPU can be more of a limiting factor, but it also noticeably enhances the player experience by removing the distracting 'popping' when an object visibly changes shape or appears because of LoD. - Lowest is changed from 0.75 to 0.8 - Low is reduced to 0.8, just like Lowest. The difference is now only the display of optional geometry objects, but it's a big difference. - Medium is changed from 1.25 to 1.3 - High is changed from 1.3 to 1.8 - Very high is changed from 1.8 to 2.4 - Ultra is changed from 3.0 to 3.2 --- src/graphics/lod_node.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/graphics/lod_node.cpp b/src/graphics/lod_node.cpp index 60a26ca3be7..c99ec8a8713 100644 --- a/src/graphics/lod_node.cpp +++ b/src/graphics/lod_node.cpp @@ -191,12 +191,12 @@ void LODNode::autoComputeLevel(float scale) // Amount of details based on user's input float agressivity = 1.0; - if( UserConfigParams::m_geometry_level == 0) agressivity = 1.25; - else if(UserConfigParams::m_geometry_level == 1) agressivity = 1.0; - else if(UserConfigParams::m_geometry_level == 2) agressivity = 0.75; - else if(UserConfigParams::m_geometry_level == 3) agressivity = 1.6; - else if(UserConfigParams::m_geometry_level == 4) agressivity = 2.0; - else if(UserConfigParams::m_geometry_level == 5) agressivity = 3.0; + if( UserConfigParams::m_geometry_level == 0) agressivity = 1.3; + else if(UserConfigParams::m_geometry_level == 1) agressivity = 0.8; + else if(UserConfigParams::m_geometry_level == 2) agressivity = 0.8; // Also removes many objects + else if(UserConfigParams::m_geometry_level == 3) agressivity = 1.8; + else if(UserConfigParams::m_geometry_level == 4) agressivity = 2.4; + else if(UserConfigParams::m_geometry_level == 5) agressivity = 3.2; // First we try to estimate how far away we need to draw // This first formula is equivalent to the one used up to STK 1.4 From ec4f4065f54e521a5f705b356575c78a85ff2051 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:01:54 +0200 Subject: [PATCH 347/830] Enable a higher maximum shadow resolution in the video settings --- data/gui/dialogs/custom_video_settings.stkgui | 2 +- src/states_screens/dialogs/custom_video_settings.cpp | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/data/gui/dialogs/custom_video_settings.stkgui b/data/gui/dialogs/custom_video_settings.stkgui index 5c58c100808..1981d3d6547 100644 --- a/data/gui/dialogs/custom_video_settings.stkgui +++ b/data/gui/dialogs/custom_video_settings.stkgui @@ -29,7 +29,7 @@
diff --git a/src/states_screens/dialogs/custom_video_settings.cpp b/src/states_screens/dialogs/custom_video_settings.cpp index 131590872bd..7de363a7622 100644 --- a/src/states_screens/dialogs/custom_video_settings.cpp +++ b/src/states_screens/dialogs/custom_video_settings.cpp @@ -101,8 +101,11 @@ void CustomVideoSettingsDialog::beforeAddingWidgets() SpinnerWidget* shadows = getWidget("shadows"); shadows->addLabel(_("Disabled")); // 0 shadows->addLabel(_("Low")); // 1 - shadows->addLabel(_("High")); // 2 - shadows->setValue(UserConfigParams::m_shadows_resolution / 512); + shadows->addLabel(_("Medium")); // 2 + shadows->addLabel(_("High")); // 3 + shadows->setValue(UserConfigParams::m_shadows_resolution == 2048 ? 3 : + UserConfigParams::m_shadows_resolution == 1024 ? 2 : + UserConfigParams::m_shadows_resolution == 512 ? 1 : 0); getWidget("dynamiclight")->setState(UserConfigParams::m_dynamic_lights); getWidget("lightshaft")->setState(UserConfigParams::m_light_shaft); @@ -156,7 +159,9 @@ GUIEngine::EventPropagation CustomVideoSettingsDialog::processEvent(const std::s if (advanced_pipeline) { UserConfigParams::m_shadows_resolution = - getWidget("shadows")->getValue() * 512; + getWidget("shadows")->getValue() == 1 ? 512 : + getWidget("shadows")->getValue() == 2 ? 1024 : + getWidget("shadows")->getValue() == 3 ? 2048 : 0; } else { From 0716965df7239684de1eedb0ac1b4b8f18747bee Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 29 Apr 2024 21:47:17 +0200 Subject: [PATCH 348/830] Improve Auto-LoD - Increase the Auto-LoD distance on tracks with a low scene complexity (fix #5065) - Increase the Auto-LoD distance when the old formula gives a too low base distance (small objects). This helps with some of the worst popping issues for comparatively little performance cost. - Make the LoD distance auto-compute code clearer by moving the settings-related multiplier after the squaring step - Also fix a couple of unrelated warnings about comparison between signed and unsigned integers --- src/graphics/draw_calls.cpp | 2 +- src/graphics/irr_driver.cpp | 1 + src/graphics/irr_driver.hpp | 8 ++++++ src/graphics/lod_node.cpp | 49 +++++++++++++++++++++++++------------ src/graphics/lod_node.hpp | 1 + src/tracks/track.cpp | 23 ++++++++++++++++- 6 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/graphics/draw_calls.cpp b/src/graphics/draw_calls.cpp index d89a715f80c..f05c9ec3d57 100644 --- a/src/graphics/draw_calls.cpp +++ b/src/graphics/draw_calls.cpp @@ -156,7 +156,7 @@ void DrawCalls::parseSceneManager(core::array &List, core::array child; if (node->getLevel() >= 0) child.push_back(node->getAllNodes()[node->getLevel()]); - for (int i = 0; i < node->getChildren().size(); i++) + for (unsigned int i = 0; i < node->getChildren().size(); i++) { if (node->getNodesSet().find(node->getChildren()[i]) == node->getNodesSet().end()) child.push_back(node->getChildren()[i]); diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 71d1ac1daa2..0c29bbc2336 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -210,6 +210,7 @@ IrrDriver::IrrDriver() m_recording = false; m_sun_interposer = NULL; m_scene_complexity = 0; + m_lod_multiplier = 1.0f; #ifndef SERVER_ONLY for (unsigned i = 0; i < Q_LAST; i++) diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index 7f0e20421d7..6a183d012e7 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -155,6 +155,8 @@ class IrrDriver : public IEventReceiver, public NoCopy /** Store if the scene is complex (based on polycount, etc) */ int m_scene_complexity; + /** Used for auto-LoD adjustment in low-complexity scenes */ + float m_lod_multiplier; /** Internal method that applies the resolution in user settings. */ void applyResolutionSettings(bool recreate_device); @@ -368,12 +370,18 @@ class IrrDriver : public IEventReceiver, public NoCopy bool getBoundingBoxesViz() { return m_boundingboxesviz; } // ------------------------------------------------------------------------ int getSceneComplexity() { return m_scene_complexity; } + // ------------------------------------------------------------------------ void resetSceneComplexity() { m_scene_complexity = 0; } + // ------------------------------------------------------------------------ void addSceneComplexity(int complexity) { if (complexity > 1) m_scene_complexity += (complexity - 1); } // ------------------------------------------------------------------------ + float getLODMultiplier() { return m_lod_multiplier; } + // ------------------------------------------------------------------------ + void setLODMultiplier(float multiplier) { m_lod_multiplier = multiplier; } + // ------------------------------------------------------------------------ bool isRecording() const { return m_recording; } // ------------------------------------------------------------------------ void setRecording(bool val); diff --git a/src/graphics/lod_node.cpp b/src/graphics/lod_node.cpp index c99ec8a8713..79208d2a0a7 100644 --- a/src/graphics/lod_node.cpp +++ b/src/graphics/lod_node.cpp @@ -51,6 +51,7 @@ LODNode::LODNode(std::string group_name, scene::ISceneNode* parent, m_area = 0; m_current_level = -1; m_current_level_dirty = true; + m_lod_distances_updated = false; } LODNode::~LODNode() @@ -86,6 +87,15 @@ int LODNode::getLevel() const int dist = (int)((m_nodes[0]->getAbsolutePosition()).getDistanceFromSQ(pos.toIrrVector() )); + if (!m_lod_distances_updated) + { + for (unsigned int n=0; ngetLODMultiplier()); + } + m_lod_distances_updated = true; + } + for (unsigned int n=0; n 0 } void LODNode::updateVisibility() @@ -173,12 +182,12 @@ void LODNode::OnRegisterSceneNode() { m_nodes[level]->OnRegisterSceneNode(); } - for (int i = 0; i < Children.size(); i++) + for (unsigned i = 0; i < Children.size(); i++) { if (m_nodes_set.find(Children[i]) == m_nodes_set.end()) Children[i]->OnRegisterSceneNode(); } - } + } // if isVisible() && m_nodes.size() > 0 } /* Each model with LoD has specific distances beyond which it is rendered at a lower @@ -189,18 +198,14 @@ void LODNode::autoComputeLevel(float scale) { m_area *= scale; - // Amount of details based on user's input - float agressivity = 1.0; - if( UserConfigParams::m_geometry_level == 0) agressivity = 1.3; - else if(UserConfigParams::m_geometry_level == 1) agressivity = 0.8; - else if(UserConfigParams::m_geometry_level == 2) agressivity = 0.8; // Also removes many objects - else if(UserConfigParams::m_geometry_level == 3) agressivity = 1.8; - else if(UserConfigParams::m_geometry_level == 4) agressivity = 2.4; - else if(UserConfigParams::m_geometry_level == 5) agressivity = 3.2; - // First we try to estimate how far away we need to draw // This first formula is equivalent to the one used up to STK 1.4 float max_draw = 10*(sqrtf(m_area + 20) - 1); + // At really short distances, popping is more annoying even if + // the object is small, so we limit how small the distance can be + if (max_draw < 80) + max_draw = 30 + (max_draw * 0.625); + // If the draw distance is too big we artificially reduce it // The formulas are still experimental and improvable. if(max_draw > 250) @@ -209,9 +214,23 @@ void LODNode::autoComputeLevel(float scale) if (max_draw > 500) max_draw = 200 + (max_draw * 0.6); - max_draw *= agressivity; + // As it is faster to compute the squared distance than distance, at runtime + // we compare the distance saved in the LoD node with the square of the distance + // between the camera and the object. Therefore, we apply squaring here. + max_draw *= max_draw; + + // Amount of details based on the user's input + float aggressivity = 1.0; + if( UserConfigParams::m_geometry_level == 0) aggressivity = 1.5; + else if(UserConfigParams::m_geometry_level == 1) aggressivity = 0.65; + else if(UserConfigParams::m_geometry_level == 2) aggressivity = 0.65; // Also removes many objects + else if(UserConfigParams::m_geometry_level == 3) aggressivity = 4.5; + else if(UserConfigParams::m_geometry_level == 4) aggressivity = 5.75; + else if(UserConfigParams::m_geometry_level == 5) aggressivity = 15.0; + + max_draw *= aggressivity; - int step = (int) (max_draw * max_draw) / m_detail.size(); + int step = (int) (max_draw) / m_detail.size(); // Then we recompute the level of detail culling distance int biais = m_detail.size(); diff --git a/src/graphics/lod_node.hpp b/src/graphics/lod_node.hpp index fe52253de79..31daa1e6f16 100644 --- a/src/graphics/lod_node.hpp +++ b/src/graphics/lod_node.hpp @@ -70,6 +70,7 @@ class LODNode : public scene::ISceneNode float m_area; bool m_update_box_every_frame; + bool m_lod_distances_updated; public: LODNode(std::string group_name, scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id=-1); diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 93945edbbe1..d6b0f3d3582 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -2090,7 +2090,28 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) loadObjects(root, path, model_def_loader, true, NULL, NULL); main_loop->renderGUI(5000); - Log::info("Track", "Overall scene complexity estimated at %d", irr_driver->getSceneComplexity()); + // If the track is low complexity, increase distances for LoD nodes + // Scene complexity is not computed before LoD nodes are loaded, so + // instead we set a variable that will be used to update the distances + // later on. + float squared_multiplier = 1.0f; + if (irr_driver->getSceneComplexity() < 1500) + { + float ratio = 1.0f; + // Cap the potential effect + if (irr_driver->getSceneComplexity() < 100) + ratio = 15.0f; + else + ratio = 1500.0f / (float)(irr_driver->getSceneComplexity()); + + squared_multiplier = 0.3f + 0.7f * ratio; + } + irr_driver->setLODMultiplier(squared_multiplier); + // The LoD distances are stored squared in the node, therefore the real multiplier + // is the square root of the one that gets applied + Log::info("Track", "Overall scene complexity estimated at %d, Auto-LoD multiplier is %f", + irr_driver->getSceneComplexity(), sqrtf(squared_multiplier)); + // Correct the parenting of meta library for (auto& p : m_meta_library) { From c9d44736ed57e3807f9c0e0b4db0dd9fab51d0c4 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Tue, 30 Apr 2024 10:45:01 +0800 Subject: [PATCH 349/830] Add resizing code for bubble widget --- src/guiengine/widgets/bubble_widget.cpp | 57 +++++++++++++++++-------- src/guiengine/widgets/bubble_widget.hpp | 5 +++ 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/guiengine/widgets/bubble_widget.cpp b/src/guiengine/widgets/bubble_widget.cpp index 798b21c9803..d506f682686 100644 --- a/src/guiengine/widgets/bubble_widget.cpp +++ b/src/guiengine/widgets/bubble_widget.cpp @@ -41,13 +41,20 @@ BubbleWidget::BubbleWidget() : Widget(WTYPE_BUBBLE) // ---------------------------------------------------------------------------- +rect BubbleWidget::getShrinkedSize() +{ + recti size = rect(m_x, m_y, m_x + m_w - BUBBLE_MARGIN_ON_RIGHT, m_y + m_h); + size.LowerRightCorner.Y -= BOTTOM_MARGIN; + return size; +} + +// ---------------------------------------------------------------------------- + void BubbleWidget::add() { - m_shrinked_size = rect(m_x, m_y, m_x + m_w - BUBBLE_MARGIN_ON_RIGHT, m_y + m_h); + m_shrinked_size = getShrinkedSize(); stringw message = getText(); - m_shrinked_size.LowerRightCorner.Y -= BOTTOM_MARGIN; - IGUIStaticText* irrwidget; irrwidget = GUIEngine::getGUIEnv()->addStaticText(message.c_str(), m_shrinked_size, false, true /* word wrap */, m_parent, @@ -74,23 +81,20 @@ void BubbleWidget::add() m_element->setNotClipped(true); } -void BubbleWidget::replaceText() +void BubbleWidget::resize() { - IGUIStaticText* irrwidget = (IGUIStaticText*) m_element; - // Take border into account for line breaking (happens in setText) - irrwidget->setDrawBorder(true); - - stringw message = getText(); - - EGUI_ALIGNMENT align = EGUIA_UPPERLEFT; - if (m_properties[PROP_TEXT_ALIGN] == "center") align = EGUIA_CENTER; - else if (m_properties[PROP_TEXT_ALIGN] == "right") align = EGUIA_LOWERRIGHT; - - EGUI_ALIGNMENT valign = EGUIA_CENTER; - if (m_properties[PROP_TEXT_VALIGN] == "top") valign = EGUIA_UPPERLEFT; - if (m_properties[PROP_TEXT_VALIGN] == "bottom") valign = EGUIA_LOWERRIGHT; + m_shrinked_size = getShrinkedSize(); + m_element->setRelativePosition(m_shrinked_size); + updateForNewSize(); + updateSize(); +} +void BubbleWidget::updateForNewSize() +{ + IGUIStaticText* irrwidget = static_cast(m_element); // find expanded bubble size + stringw message = getText(); + irrwidget->setText(message); int text_height = irrwidget->getTextHeight(); m_expanded_size = m_shrinked_size; @@ -106,11 +110,28 @@ void BubbleWidget::replaceText() while (text_height > m_shrinked_size.getHeight() && message.size() > 10) { message = message.subString(0, message.size() - 10) + "..."; - irrwidget->setText(message.c_str()); + irrwidget->setText(message); text_height = irrwidget->getTextHeight(); } } m_shrinked_text = message; +} + +void BubbleWidget::replaceText() +{ + IGUIStaticText* irrwidget = (IGUIStaticText*) m_element; + // Take border into account for line breaking (happens in setText) + irrwidget->setDrawBorder(true); + + EGUI_ALIGNMENT align = EGUIA_UPPERLEFT; + if (m_properties[PROP_TEXT_ALIGN] == "center") align = EGUIA_CENTER; + else if (m_properties[PROP_TEXT_ALIGN] == "right") align = EGUIA_LOWERRIGHT; + + EGUI_ALIGNMENT valign = EGUIA_CENTER; + if (m_properties[PROP_TEXT_VALIGN] == "top") valign = EGUIA_UPPERLEFT; + if (m_properties[PROP_TEXT_VALIGN] == "bottom") valign = EGUIA_LOWERRIGHT; + + updateForNewSize(); irrwidget->setTextAlignment( align, valign ); } diff --git a/src/guiengine/widgets/bubble_widget.hpp b/src/guiengine/widgets/bubble_widget.hpp index 42beebd60dd..4792d60c737 100644 --- a/src/guiengine/widgets/bubble_widget.hpp +++ b/src/guiengine/widgets/bubble_widget.hpp @@ -55,6 +55,9 @@ namespace GUIEngine /** Will add/replace text in the bubble. If it doesn't fit, the text will get shrinked. **/ void replaceText(); + void updateForNewSize(); + + irr::core::rect getShrinkedSize(); public: LEAK_CHECK() @@ -70,6 +73,8 @@ namespace GUIEngine void setText(const irr::core::stringw &s); virtual int getHeightNeededAroundLabel() const { return 10; } + + virtual void resize(); }; } From ff186339e1981eb59e670a8dfe02584b7fe2b06e Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Wed, 1 May 2024 13:00:54 +0800 Subject: [PATCH 350/830] Use proper method to shrink text in bubble widget to fix #3432 --- src/font/font_manager.cpp | 80 +++++++++++++++++-------- src/font/font_manager.hpp | 5 ++ src/guiengine/widgets/bubble_widget.cpp | 72 ++++++++++++++++------ 3 files changed, 116 insertions(+), 41 deletions(-) diff --git a/src/font/font_manager.cpp b/src/font/font_manager.cpp index bd5e6476e47..ab4bd79faf2 100644 --- a/src/font/font_manager.cpp +++ b/src/font/font_manager.cpp @@ -112,8 +112,64 @@ namespace LineBreakingRules // like using "。"instead of a ".", you can add more characters if needed. // For full list please visit: // http://webapp.docx4java.org/OnlineDemo/ecma376/WordML/kinsoku.html + bool endSentence(char32_t c) + { + switch (c) + { + case '!': + return true; + case ',': + return true; + case '.': + return true; + case '?': + return true; + case ':': + return true; + case ';': + return true; + // ، + case 1548: + return true; + // ؛ + case 1563: + return true; + // ؟ + case 1567: + return true; + // ! + case 65281: + return true; + // ? + case 65311: + return true; + // , + case 65292: + return true; + // : + case 65306: + return true; + // ; + case 65307: + return true; + // . + case 65294: + return true; + // 。 + case 12290: + return true; + // 、 + case 12289: + return true; + default: + return false; + } + } // endSentence + //------------------------------------------------------------------------- bool noStartingLine(char32_t c) { + if (endSentence(c)) + return true; switch (c) { // ’ @@ -152,36 +208,12 @@ namespace LineBreakingRules // 〗 case 12311: return true; - // ! - case 65281: - return true; // % case 65285: return true; - // ? - case 65311: - return true; // ` case 65344: return true; - // , - case 65292: - return true; - // : - case 65306: - return true; - // ; - case 65307: - return true; - // . - case 65294: - return true; - // 。 - case 12290: - return true; - // 、 - case 12289: - return true; default: return false; } diff --git a/src/font/font_manager.hpp b/src/font/font_manager.hpp index 2d1f2f2cb89..604d1d88695 100644 --- a/src/font/font_manager.hpp +++ b/src/font/font_manager.hpp @@ -153,5 +153,10 @@ class FontManager : public NoCopy extern FontManager *font_manager; +namespace LineBreakingRules +{ + bool endSentence(char32_t c); +} + #endif /* EOF */ diff --git a/src/guiengine/widgets/bubble_widget.cpp b/src/guiengine/widgets/bubble_widget.cpp index d506f682686..8b5fe9db01e 100644 --- a/src/guiengine/widgets/bubble_widget.cpp +++ b/src/guiengine/widgets/bubble_widget.cpp @@ -15,14 +15,17 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include "font/font_manager.hpp" #include "guiengine/engine.hpp" #include "guiengine/widgets/bubble_widget.hpp" #include "online/link_helper.hpp" #include +#include #include #include #include +#include using namespace irr::core; using namespace irr::gui; @@ -77,8 +80,6 @@ void BubbleWidget::add() m_element->setTabOrder(m_id); m_element->setTabStop(true); - - m_element->setNotClipped(true); } void BubbleWidget::resize() @@ -93,9 +94,47 @@ void BubbleWidget::updateForNewSize() { IGUIStaticText* irrwidget = static_cast(m_element); // find expanded bubble size - stringw message = getText(); - irrwidget->setText(message); - int text_height = irrwidget->getTextHeight(); + m_shrinked_text = getText(); + irrwidget->setText(m_shrinked_text); + +start: + IGUIFont* font = irrwidget->getActiveFont(); + int text_height = font->getHeightPerLine(); + int max_cluster = -1; + bool has_newline = false; + auto& glyph_layouts = irrwidget->getGlyphLayouts(); + for (unsigned i = 0; i < glyph_layouts.size(); i++) + { + const GlyphLayout& glyph = glyph_layouts[i]; + if ((glyph.flags & GLF_NEWLINE) != 0) + { + has_newline = true; + text_height += font->getHeightPerLine(); + if (text_height > m_shrinked_size.getHeight()) + { + if (max_cluster != -1) + continue; + for (unsigned idx = 0; idx < i; idx++) + { + const GlyphLayout& gl = glyph_layouts[idx]; + for (int c : gl.cluster) + { + if (c > max_cluster) + max_cluster = c; + } + } + while (max_cluster > 0 && LineBreakingRules::endSentence( + m_shrinked_text[max_cluster - 1])) + max_cluster--; + m_shrinked_text = m_shrinked_text.subString(0, max_cluster) + + L"\u2026"; + irrwidget->setText(m_shrinked_text); + } + } + } + + irrwidget->setText(getText()); + text_height = irrwidget->getTextHeight(); m_expanded_size = m_shrinked_size; const int additionalNeededSize = std::max(0, text_height - m_shrinked_size.getHeight()); @@ -104,17 +143,11 @@ void BubbleWidget::updateForNewSize() { m_expanded_size.UpperLeftCorner.Y -= additionalNeededSize/2 + 10; m_expanded_size.LowerRightCorner.Y += additionalNeededSize/2 + 10; - - // reduce text to fit in the available space if it's too long - // FIXME : this loop is ugly - while (text_height > m_shrinked_size.getHeight() && message.size() > 10) - { - message = message.subString(0, message.size() - 10) + "..."; - irrwidget->setText(message); - text_height = irrwidget->getTextHeight(); - } } - m_shrinked_text = message; + irrwidget->setText(m_shrinked_text); + text_height = irrwidget->getTextHeight(); + if (has_newline && text_height > m_shrinked_size.getHeight()) + goto start; } void BubbleWidget::replaceText() @@ -122,6 +155,7 @@ void BubbleWidget::replaceText() IGUIStaticText* irrwidget = (IGUIStaticText*) m_element; // Take border into account for line breaking (happens in setText) irrwidget->setDrawBorder(true); + irrwidget->setNotClipped(true); EGUI_ALIGNMENT align = EGUIA_UPPERLEFT; if (m_properties[PROP_TEXT_ALIGN] == "center") align = EGUIA_CENTER; @@ -147,6 +181,9 @@ void BubbleWidget::setText(const irr::core::stringw &s) void BubbleWidget::updateSize() { + stringw real_text = getText(); + if (m_shrinked_text == real_text) + return; core::rect currsize = m_shrinked_size; const int y1_top = m_shrinked_size.UpperLeftCorner.Y; @@ -161,10 +198,11 @@ void BubbleWidget::updateSize() m_element->setRelativePosition(currsize); + IGUIStaticText* irrwidget = static_cast(m_element); if (m_zoom > 0.5f) - getIrrlichtElement()->setText(getText().c_str()); + irrwidget->setText(real_text); else - getIrrlichtElement()->setText(m_shrinked_text.c_str()); + irrwidget->setText(m_shrinked_text); } // ---------------------------------------------------------------------------- From f8a43b86ea56046b8333f8b51173eab4a50a47ae Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Wed, 1 May 2024 16:04:39 +0800 Subject: [PATCH 351/830] Fix server only build --- src/guiengine/widgets/bubble_widget.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/guiengine/widgets/bubble_widget.cpp b/src/guiengine/widgets/bubble_widget.cpp index 8b5fe9db01e..ce868b5c4a0 100644 --- a/src/guiengine/widgets/bubble_widget.cpp +++ b/src/guiengine/widgets/bubble_widget.cpp @@ -100,8 +100,9 @@ void BubbleWidget::updateForNewSize() start: IGUIFont* font = irrwidget->getActiveFont(); int text_height = font->getHeightPerLine(); - int max_cluster = -1; bool has_newline = false; +#ifndef SERVER_ONLY + int max_cluster = -1; auto& glyph_layouts = irrwidget->getGlyphLayouts(); for (unsigned i = 0; i < glyph_layouts.size(); i++) { @@ -132,7 +133,7 @@ void BubbleWidget::updateForNewSize() } } } - +#endif irrwidget->setText(getText()); text_height = irrwidget->getTextHeight(); From f73e56c204d02c7597f40e538811f338286c6fb4 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Thu, 2 May 2024 15:34:08 +0800 Subject: [PATCH 352/830] Add resizing code for dialog and screen keyboard --- src/guiengine/modaldialog.cpp | 61 ++++++++++++++++++++----------- src/guiengine/modaldialog.hpp | 4 ++ src/guiengine/screen_keyboard.cpp | 57 +++++++++++++++++++++-------- src/guiengine/screen_keyboard.hpp | 5 ++- 4 files changed, 88 insertions(+), 39 deletions(-) diff --git a/src/guiengine/modaldialog.cpp b/src/guiengine/modaldialog.cpp index 5732a41008d..b6560014182 100644 --- a/src/guiengine/modaldialog.cpp +++ b/src/guiengine/modaldialog.cpp @@ -96,6 +96,34 @@ void ModalDialog::doInit() pointer_was_shown = irr_driver->isPointerShown(); irr_driver->showPointer(); + setArea(); + + if (modalWindow != NULL) + { + delete modalWindow; + Log::warn("GUIEngine", "Showing a modal dialog while the previous one " + "is still open. Destroying the previous dialog."); + } + modalWindow = this; + + m_irrlicht_window = GUIEngine::getGUIEnv()->addWindow(m_area, + true /* modal */); + m_irrlicht_window->setDrawTitlebar(false); + m_irrlicht_window->getCloseButton()->setVisible(false); + if (!UserConfigParams::m_artist_debug_mode) + m_irrlicht_window->setDraggable(false); + + GUIEngine::getSkin()->m_dialog = true; + GUIEngine::getSkin()->m_dialog_size = 0.0f; + + m_previous_mode=input_manager->getMode(); + input_manager->setMode(InputManager::MENU); +} // doInit + +// ---------------------------------------------------------------------------- + +void ModalDialog::setArea() +{ const core::dimension2d& frame_size = GUIEngine::getDriver()->getCurrentRenderTargetSize(); @@ -134,28 +162,7 @@ void ModalDialog::doInit() { assert(false); } - - if (modalWindow != NULL) - { - delete modalWindow; - Log::warn("GUIEngine", "Showing a modal dialog while the previous one " - "is still open. Destroying the previous dialog."); - } - modalWindow = this; - - m_irrlicht_window = GUIEngine::getGUIEnv()->addWindow(m_area, - true /* modal */); - m_irrlicht_window->setDrawTitlebar(false); - m_irrlicht_window->getCloseButton()->setVisible(false); - if (!UserConfigParams::m_artist_debug_mode) - m_irrlicht_window->setDraggable(false); - - GUIEngine::getSkin()->m_dialog = true; - GUIEngine::getSkin()->m_dialog_size = 0.0f; - - m_previous_mode=input_manager->getMode(); - input_manager->setMode(InputManager::MENU); -} // doInit +} // setArea // ---------------------------------------------------------------------------- @@ -207,6 +214,16 @@ void ModalDialog::clearWindow() // ---------------------------------------------------------------------------- +void ModalDialog::onResize() +{ + setArea(); + m_irrlicht_window->setRelativePosition(m_area); + LayoutManager::calculateLayout(m_widgets, this); + resizeWidgetsRecursively(m_widgets); +} // onResize + +// ---------------------------------------------------------------------------- + void ModalDialog::dismiss() { if(modalWindow != NULL) delete modalWindow; diff --git a/src/guiengine/modaldialog.hpp b/src/guiengine/modaldialog.hpp index deb2f9b4364..e3b1c4da682 100644 --- a/src/guiengine/modaldialog.hpp +++ b/src/guiengine/modaldialog.hpp @@ -87,6 +87,7 @@ namespace GUIEngine */ virtual void loadedFromFile() {} void doInit(); + void setArea(); public: LEAK_CHECK() @@ -116,6 +117,9 @@ namespace GUIEngine /** Override to be notified of updates */ virtual void onUpdate(float dt) { } + /** Override to be notified of resizes */ + virtual void onResize(); + /** * \brief Optional callback invoked very early, before widgets have been added (contrast with * init(), which is invoked afer widgets were added) diff --git a/src/guiengine/screen_keyboard.cpp b/src/guiengine/screen_keyboard.cpp index 52c8a68ac2c..1271ff93225 100644 --- a/src/guiengine/screen_keyboard.cpp +++ b/src/guiengine/screen_keyboard.cpp @@ -147,10 +147,7 @@ ScreenKeyboard::~ScreenKeyboard() } // ~ScreenKeyboard // ---------------------------------------------------------------------------- -/** Screen keyboard initialization, needs to be called after new to take into - * account for runtime polymorphism - */ -void ScreenKeyboard::init() +void ScreenKeyboard::setArea() { const core::dimension2d& frame_size = irr_driver->getFrameSize(); @@ -176,7 +173,15 @@ void ScreenKeyboard::init() #endif m_area = core::rect(x, y, x + w, y + h); +} // setArea +// ---------------------------------------------------------------------------- +/** Screen keyboard initialization, needs to be called after new to take into + * account for runtime polymorphism + */ +void ScreenKeyboard::init() +{ + setArea(); m_irrlicht_window = GUIEngine::getGUIEnv()->addWindow(m_area, true); m_irrlicht_window->setDrawTitlebar(false); m_irrlicht_window->getCloseButton()->setVisible(false); @@ -185,7 +190,12 @@ void ScreenKeyboard::init() m_previous_mode=input_manager->getMode(); input_manager->setMode(InputManager::MENU); - createButtons(); + initButtons(); + + LayoutManager::calculateLayout(m_widgets, this); + addWidgetsRecursively(m_widgets); + assert(m_buttons.size() > 0); + m_buttons[0]->setFocusForPlayer(PLAYER_ID_GAME_MASTER); assignButtons(getDefaultButtonsType()); Widget* button_widget = getWidget("Back"); @@ -194,9 +204,9 @@ void ScreenKeyboard::init() } // init // ---------------------------------------------------------------------------- -/** Creates all button widgets +/** Initializes all button widgets */ -void ScreenKeyboard::createButtons() +void ScreenKeyboard::initButtons() { const auto& layout_proportions = getKeyboardLayoutProportions(); int rows_num = layout_proportions.size(); @@ -204,6 +214,7 @@ void ScreenKeyboard::createButtons() const int margin = 2; int height = (m_area.getHeight() - 2 * pos_y) / rows_num - margin; + unsigned index = 0; for (int i = 0; i < rows_num; i++) { @@ -230,7 +241,17 @@ void ScreenKeyboard::createButtons() for (int j = 0; j < cols_num; j++) { - ButtonWidget* button = new ButtonWidget(); + ButtonWidget* button = NULL; + if (index < m_buttons.size()) + { + button = m_buttons[index]; + } + else + { + button = new ButtonWidget(); + m_widgets.push_back(button); + m_buttons.push_back(button); + } float width = (float)total_width * layout_proportions[i][j] / total_proportions - margin; @@ -250,19 +271,13 @@ void ScreenKeyboard::createButtons() button->m_properties[PROP_HEIGHT] = height_str; button->m_properties[PROP_X] = pos_x_str; button->m_properties[PROP_Y] = pos_y_str; - m_widgets.push_back(button); - m_buttons.push_back(button); pos_x += width + margin; + index++; } } - LayoutManager::calculateLayout(m_widgets, this); - addWidgetsRecursively(m_widgets); - - assert(m_buttons.size() > 0); - m_buttons[0]->setFocusForPlayer(PLAYER_ID_GAME_MASTER); -} // createButtons +} // initButtons // ---------------------------------------------------------------------------- core::stringw ScreenKeyboard::getKeyName(std::string key_id) @@ -291,6 +306,16 @@ core::stringw ScreenKeyboard::getKeyName(std::string key_id) return key_name; } +// ---------------------------------------------------------------------------- +void ScreenKeyboard::onResize() +{ + setArea(); + m_irrlicht_window->setRelativePosition(m_area); + initButtons(); + LayoutManager::calculateLayout(m_widgets, this); + resizeWidgetsRecursively(m_widgets); +} // onResize + // ---------------------------------------------------------------------------- /** A function that allows to select one of the available buttons layout * \param buttons_type One of the available buttons type diff --git a/src/guiengine/screen_keyboard.hpp b/src/guiengine/screen_keyboard.hpp index bfb96593b16..410d0aed7f7 100644 --- a/src/guiengine/screen_keyboard.hpp +++ b/src/guiengine/screen_keyboard.hpp @@ -101,7 +101,7 @@ namespace GUIEngine /** Remembered input mode that was used before keyboard creation */ InputManager::InputDriverMode m_previous_mode; - void createButtons(); + void initButtons(); void assignButtons(ButtonsType buttons_type); core::stringw getKeyName(std::string key_id); @@ -112,6 +112,7 @@ namespace GUIEngine CGUIEditBox* edit_box); ~ScreenKeyboard(); + void setArea(); void init(); virtual EventPropagation processEvent(const std::string& eventSource); @@ -160,6 +161,8 @@ namespace GUIEngine { return BUTTONS_LOWER; } + + virtual void onResize(); }; } From 31239615ef4f2e2d41f47cc37f9b9d4592bae202 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Fri, 3 May 2024 17:54:13 +0800 Subject: [PATCH 353/830] Add resizing code for add device dialog --- .../dialogs/add_device_dialog.cpp | 127 +++++++++++------- .../dialogs/add_device_dialog.hpp | 14 +- 2 files changed, 92 insertions(+), 49 deletions(-) diff --git a/src/states_screens/dialogs/add_device_dialog.cpp b/src/states_screens/dialogs/add_device_dialog.cpp index 6cdcae7c5e2..0c8a10539cf 100644 --- a/src/states_screens/dialogs/add_device_dialog.cpp +++ b/src/states_screens/dialogs/add_device_dialog.cpp @@ -44,22 +44,6 @@ AddDeviceDialog::AddDeviceDialog() : ModalDialog(0.90f, 0.80f) { doInit(); - ScalableFont* font = GUIEngine::getFont(); - const int textHeight = GUIEngine::getFontHeight(); - const int buttonHeight = textHeight + 10; - -#ifdef ENABLE_WIIUSE - const int nbButtons = 3; -#else - const int nbButtons = 2; -#endif - - const int y_bottom = m_area.getHeight() - nbButtons*(buttonHeight + 10) - 10; - const int y_stride = buttonHeight+10; - int cur_y = y_bottom; - - core::rect text_area( 15, 15, m_area.getWidth()-15, y_bottom-15 ); - core::stringw msg = _("New gamepads and joysticks will automatically appear in the list " "when you connect them to this device.\n\nTo add a " @@ -69,14 +53,14 @@ AddDeviceDialog::AddDeviceDialog() : ModalDialog(0.90f, 0.80f) "gameplay. (You can, however, connect multiple keyboards to this " "device. Remember that everyone still needs different keybindings " "in this case.)"); - IGUIStaticText* b = + m_text = GUIEngine::getGUIEnv()->addStaticText(msg, - text_area, + core::rect(0, 0, 1, 1), /*border*/false , /*word wrap*/true, m_irrlicht_window); - b->setTabStop(false); - b->setText(msg); + m_text->setTabStop(false); + m_text->setText(msg); #ifdef ENABLE_WIIUSE { @@ -86,17 +70,13 @@ AddDeviceDialog::AddDeviceDialog() : ModalDialog(0.90f, 0.80f) //I18N: In the 'add new input device' dialog widget->setText( _("Add Wiimote") ); - const int textWidth = - font->getDimension( widget->getText().c_str() ).Width + 40; - - widget->m_x = m_area.getWidth()/2 - textWidth/2; - widget->m_y = cur_y; - widget->m_w = textWidth; - widget->m_h = buttonHeight; + widget->m_x = 0; + widget->m_y = 0; + widget->m_w = 1; + widget->m_h = 1; widget->setParent(m_irrlicht_window); m_widgets.push_back(widget); widget->add(); - cur_y += y_stride; } #endif // ENABLE_WIIUSE @@ -107,23 +87,58 @@ AddDeviceDialog::AddDeviceDialog() : ModalDialog(0.90f, 0.80f) //I18N: In the 'add new input device' dialog widget->setText( _("Add Keyboard Configuration") ); - const int textWidth = - font->getDimension( widget->getText().c_str() ).Width + 40; - - widget->m_x = m_area.getWidth()/2 - textWidth/2; - widget->m_y = cur_y; - widget->m_w = textWidth; - widget->m_h = buttonHeight; + widget->m_x = 0; + widget->m_y = 0; + widget->m_w = 1; + widget->m_h = 1; widget->setParent(m_irrlicht_window); m_widgets.push_back(widget); widget->add(); - cur_y += y_stride; } { ButtonWidget* widget = new ButtonWidget(); widget->m_properties[PROP_ID] = "cancel"; widget->setText( _("Cancel") ); + widget->m_x = 0; + widget->m_y = 0; + widget->m_w = 1; + widget->m_h = 1; + widget->setParent(m_irrlicht_window); + m_widgets.push_back(widget); + widget->add(); + + widget->setFocusForPlayer( PLAYER_ID_GAME_MASTER ); + + } + configDialog(); +} // AddDeviceDialog + +// ---------------------------------------------------------------------------- +void AddDeviceDialog::configDialog() +{ + ScalableFont* font = GUIEngine::getFont(); + const int textHeight = GUIEngine::getFontHeight(); + const int buttonHeight = textHeight + 10; + +#ifdef ENABLE_WIIUSE + const int nbButtons = 3; +#else + const int nbButtons = 2; +#endif + + const int y_bottom = m_area.getHeight() - nbButtons*(buttonHeight + 10) - 10; + const int y_stride = buttonHeight+10; + int cur_y = y_bottom; + + core::rect text_area( 15, 15, m_area.getWidth()-15, y_bottom-15 ); + m_text->setRelativePosition(text_area); + + auto itr = m_widgets.begin(); +#ifdef ENABLE_WIIUSE + { + Widget* widget = *itr; + const int textWidth = font->getDimension( widget->getText().c_str() ).Width + 40; @@ -131,24 +146,40 @@ AddDeviceDialog::AddDeviceDialog() : ModalDialog(0.90f, 0.80f) widget->m_y = cur_y; widget->m_w = textWidth; widget->m_h = buttonHeight; - widget->setParent(m_irrlicht_window); - m_widgets.push_back(widget); - widget->add(); + widget->resize(); + itr++; cur_y += y_stride; - - widget->setFocusForPlayer( PLAYER_ID_GAME_MASTER ); - } +#endif // ENABLE_WIIUSE -} // AddDeviceDialog + { + Widget* widget = *itr; -// ---------------------------------------------------------------------------- + const int textWidth = + font->getDimension( widget->getText().c_str() ).Width + 40; -void AddDeviceDialog::onEnterPressedInternal() -{ -} // onEnterPressedInternal + widget->m_x = m_area.getWidth()/2 - textWidth/2; + widget->m_y = cur_y; + widget->m_w = textWidth; + widget->m_h = buttonHeight; + widget->resize(); + itr++; + cur_y += y_stride; + } + { + Widget* widget = *itr; -// ---------------------------------------------------------------------------- + const int textWidth = + font->getDimension( widget->getText().c_str() ).Width + 40; + + widget->m_x = m_area.getWidth()/2 - textWidth/2; + widget->m_y = cur_y; + widget->m_w = textWidth; + widget->m_h = buttonHeight; + widget->resize(); + cur_y += y_stride; + } +} // configDialog // ---------------------------------------------------------------------------- GUIEngine::EventPropagation AddDeviceDialog::processEvent diff --git a/src/states_screens/dialogs/add_device_dialog.hpp b/src/states_screens/dialogs/add_device_dialog.hpp index 39858b3cba9..4729da3e568 100644 --- a/src/states_screens/dialogs/add_device_dialog.hpp +++ b/src/states_screens/dialogs/add_device_dialog.hpp @@ -21,6 +21,11 @@ #include "guiengine/modaldialog.hpp" +namespace irr +{ + namespace gui { class IGUIStaticText; } +} + /** * \brief Dialog that warns the user about the potential problems of * creating multiple keyboard configs. @@ -28,12 +33,19 @@ */ class AddDeviceDialog : public GUIEngine::ModalDialog { +private: + irr::gui::IGUIStaticText* m_text; + void configDialog(); public: AddDeviceDialog(); - void onEnterPressedInternal(); GUIEngine::EventPropagation processEvent(const std::string& eventSource); + void onResize() + { + GUIEngine::ModalDialog::onResize(); + configDialog(); + } }; From e52b2fafdcaaaee6b9395228a1cc01ac98cc3c03 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Fri, 3 May 2024 18:02:46 +0800 Subject: [PATCH 354/830] Add resizing code for soccer setup screen --- src/states_screens/soccer_setup_screen.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/states_screens/soccer_setup_screen.hpp b/src/states_screens/soccer_setup_screen.hpp index 532701c99a2..ee650224e08 100644 --- a/src/states_screens/soccer_setup_screen.hpp +++ b/src/states_screens/soccer_setup_screen.hpp @@ -78,6 +78,12 @@ class SoccerSetupScreen : public GUIEngine::Screen, virtual bool onEscapePressed() OVERRIDE; + virtual void onResize() OVERRIDE + { + Screen::onResize(); + updateKartViewsLayout(); + } + private: bool areAllKartsConfirmed() const; int getNumConfirmedKarts(); From 26aa328994b551037e95c0e20e6cb716bb3fb0ea Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Fri, 3 May 2024 20:20:03 +0800 Subject: [PATCH 355/830] Add resizing code for credits --- src/states_screens/credits.cpp | 13 +++++++++---- src/states_screens/credits.hpp | 8 +++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/states_screens/credits.cpp b/src/states_screens/credits.cpp index 555f8dc6e73..11cbe556ce6 100644 --- a/src/states_screens/credits.cpp +++ b/src/states_screens/credits.cpp @@ -215,16 +215,21 @@ void CreditsScreen::loadedFromFile() void CreditsScreen::init() { Screen::init(); + reset(); + updateAreaSize(); +} // init + +// ---------------------------------------------------------------------------- + +void CreditsScreen::updateAreaSize() +{ Widget* w = getWidget("animated_area"); assert(w != NULL); - - reset(); - setArea(w->m_x + GUIEngine::getFontHeight(), w->m_y + GUIEngine::getFontHeight() / 2, w->m_w - GUIEngine::getFontHeight() * 2, w->m_h - GUIEngine::getFontHeight()); -} // init +} // updateAreaSize // ---------------------------------------------------------------------------- diff --git a/src/states_screens/credits.hpp b/src/states_screens/credits.hpp index a9024149bf4..dc7a51f399e 100644 --- a/src/states_screens/credits.hpp +++ b/src/states_screens/credits.hpp @@ -59,7 +59,7 @@ class CreditsScreen : public GUIEngine::Screen, bool getLineAsWide(std::ifstream& file, core::stringw* out); bool m_is_victory_music; - + void updateAreaSize(); public: @@ -91,6 +91,12 @@ class CreditsScreen : public GUIEngine::Screen, else return stk_config->m_title_music; } + + virtual void onResize() OVERRIDE + { + Screen::onResize(); + updateAreaSize(); + } }; #endif From a14b9fd74724fe4636b6d90aff624d1adb6a644f Mon Sep 17 00:00:00 2001 From: Deve Date: Sat, 4 May 2024 00:52:07 +0200 Subject: [PATCH 356/830] Update linux build script --- tools/linux_builder.sh | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tools/linux_builder.sh b/tools/linux_builder.sh index ec771584c66..6dd02e8f6dd 100755 --- a/tools/linux_builder.sh +++ b/tools/linux_builder.sh @@ -51,10 +51,10 @@ export DIRNAME="$(dirname "$(readlink -f "$0")")" export STK_VERSION="git`date +%Y%m%d`" export THREADS_NUMBER=`nproc` -export SCHROOT_32BIT_NAME="chroot-stretch32" -export SCHROOT_64BIT_NAME="chroot-stretch64" -export SCHROOT_ARMV7_NAME="chroot-stretch-armhf" -export SCHROOT_ARM64_NAME="chroot-stretch-arm64" +export SCHROOT_32BIT_NAME="chroot-buster32" +export SCHROOT_64BIT_NAME="chroot-buster64" +export SCHROOT_ARMV7_NAME="chroot-buster-armhf" +export SCHROOT_ARM64_NAME="chroot-buster-arm64" export STKCODE_DIR="$DIRNAME/.." export STKASSETS_DIR="$STKCODE_DIR/../supertuxkart-assets" @@ -324,13 +324,15 @@ build_stk() -DBUILD_TESTING=0 \ -DBUILD_CURL_EXE=0 \ -DCURL_USE_MBEDTLS=1 \ - -DUSE_ZLIB=1 \ -DCURL_USE_OPENSSL=0 \ -DCURL_USE_LIBSSH=0 \ -DCURL_USE_LIBSSH2=0 \ -DCURL_USE_GSSAPI=0 \ + -DCURL_USE_LIBPSL=0 \ + -DUSE_ZLIB=1 \ -DUSE_NGHTTP2=0 \ -DUSE_QUICHE=0 \ + -DUSE_LIBIDN2=0 \ -DHTTP_ONLY=1 \ -DCURL_CA_BUNDLE=none \ -DCURL_CA_PATH=none \ @@ -450,7 +452,7 @@ build_stk() -DCMAKE_CXX_FLAGS="-fpic -O3 -g $ASTC_CFLAGS" \ -DNO_INVARIANCE=ON -DCLI=OFF && make -j$THREADS_NUMBER && - cp "$DEPENDENCIES_DIR/astc-encoder/Source/libastcenc.a" "$INSTALL_DIR/lib/" && + cp "$DEPENDENCIES_DIR/astc-encoder/Source/libastcenc-native-static.a" "$INSTALL_DIR/lib/" && cp "$DEPENDENCIES_DIR/astc-encoder/Source/astcenc.h" "$INSTALL_DIR/include/" check_error touch "$DEPENDENCIES_DIR/astc-encoder.stamp" @@ -535,7 +537,8 @@ build_stk() cd "$DEPENDENCIES_DIR/sqlite" cmake . -DCMAKE_FIND_ROOT_PATH="$INSTALL_DIR" \ -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" \ - -DINSTALL_PKGCONFIG_DIR="$PKG_CONFIG_PATH" && + -DINSTALL_PKGCONFIG_DIR="$PKG_CONFIG_PATH" \ + -DENABLE_READLINE=0 && make -j$THREADS_NUMBER && make install check_error @@ -742,7 +745,7 @@ create_package() echo "Compress package..." cd "$STK_INSTALL_DIR" - tar cf - "SuperTuxKart-$STK_VERSION-linux-$ARCH" | xz -T$THREADS_NUMBER -z -e -f - > "SuperTuxKart-$STK_VERSION-linux-$ARCH.tar.xz" + tar -czf "SuperTuxKart-$STK_VERSION-linux-$ARCH.tar.gz" "SuperTuxKart-$STK_VERSION-linux-$ARCH" cd - } From 0266b03809b81fcb81be7e05c23e8dbcec7fce42 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sat, 4 May 2024 15:38:18 +0800 Subject: [PATCH 357/830] Add minimum resizing code for race result screen --- src/states_screens/race_result_gui.cpp | 92 ++++++++++++++++++++------ src/states_screens/race_result_gui.hpp | 1 + 2 files changed, 74 insertions(+), 19 deletions(-) diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index fa0462cf889..f71517b4bfe 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -1784,6 +1784,8 @@ void RaceResultGUI::unload() GUIEngine::Widget* result_table = getWidget("result-table"); assert(result_table != NULL); + auto wit = m_gp_progress_widgets.begin(); + bool resize = !m_gp_progress_widgets.empty(); int currentTrack = RaceManager::get()->getTrackNumber(); int font_height = getFontHeight(); int w = (int)(UserConfigParams::m_width*0.17); @@ -1791,21 +1793,32 @@ void RaceResultGUI::unload() int y = (m_top + font_height + 5); //Current progress - GUIEngine::LabelWidget* status_label = new GUIEngine::LabelWidget(); + GUIEngine::LabelWidget* status_label = resize ? + static_cast(*wit++) : + new GUIEngine::LabelWidget(); status_label->m_properties[GUIEngine::PROP_ID] = "status_label"; status_label->m_properties[GUIEngine::PROP_TEXT_ALIGN] = "center"; status_label->m_x = x; status_label->m_y = y; status_label->m_w = w; status_label->m_h = font_height; - status_label->add(); - status_label->setText(_("Track %i/%i", currentTrack + 1, - RaceManager::get()->getGrandPrix().getNumberOfTracks()), true); - addGPProgressWidget(status_label); + if (resize) + { + status_label->resize(); + } + else + { + status_label->add(); + status_label->setText(_("Track %i/%i", currentTrack + 1, + RaceManager::get()->getGrandPrix().getNumberOfTracks()), true); + addGPProgressWidget(status_label); + } y = (status_label->m_y + status_label->m_h + 5); //Scroll up button - GUIEngine::IconButtonWidget* up_button = new GUIEngine::IconButtonWidget( + GUIEngine::IconButtonWidget* up_button = resize ? + static_cast(*wit++) : + new GUIEngine::IconButtonWidget( GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); up_button->m_properties[GUIEngine::PROP_ID] = "up_button"; @@ -1813,9 +1826,16 @@ void RaceResultGUI::unload() up_button->m_y = y; up_button->m_w = w; up_button->m_h = font_height; - up_button->add(); - up_button->setImage(file_manager->getAsset(FileManager::GUI_ICON, "scroll_up.png")); - addGPProgressWidget(up_button); + if (resize) + { + up_button->resize(); + } + else + { + up_button->add(); + up_button->setImage(file_manager->getAsset(FileManager::GUI_ICON, "scroll_up.png")); + addGPProgressWidget(up_button); + } y = (up_button->m_y + up_button->m_h + SSHOT_SEPARATION); //Track screenshots and labels @@ -1823,7 +1843,8 @@ void RaceResultGUI::unload() for (int i = m_start_track; i < m_end_track; i++) { //Screenshot - GUIEngine::IconButtonWidget* screenshot_widget = + GUIEngine::IconButtonWidget* screenshot_widget = resize ? + static_cast(*wit++) : new GUIEngine::IconButtonWidget( GUIEngine::IconButtonWidget:: SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, @@ -1836,11 +1857,20 @@ void RaceResultGUI::unload() screenshot_widget->m_h = m_sshot_height; screenshot_widget->m_properties[GUIEngine::PROP_ID] = ("sshot_" + StringUtils::toString(n_sshot)); - screenshot_widget->add(); - addGPProgressWidget(screenshot_widget); + if (resize) + { + screenshot_widget->resize(); + } + else + { + screenshot_widget->add(); + addGPProgressWidget(screenshot_widget); + } //Label - GUIEngine::LabelWidget* sshot_label = new GUIEngine::LabelWidget(); + GUIEngine::LabelWidget* sshot_label = resize ? + static_cast(*wit++) : + new GUIEngine::LabelWidget(); sshot_label->m_properties[GUIEngine::PROP_ID] = ("sshot_label_" + StringUtils::toString(n_sshot)); sshot_label->m_properties[GUIEngine::PROP_TEXT_ALIGN] = "left"; @@ -1848,8 +1878,15 @@ void RaceResultGUI::unload() sshot_label->m_y = (y + (m_sshot_height / 2) - (font_height / 2)); sshot_label->m_w = (w / 2); sshot_label->m_h = font_height; - sshot_label->add(); - addGPProgressWidget(sshot_label); + if (resize) + { + sshot_label->resize(); + } + else + { + sshot_label->add(); + addGPProgressWidget(sshot_label); + } y += (m_sshot_height + SSHOT_SEPARATION); n_sshot++; @@ -1857,7 +1894,9 @@ void RaceResultGUI::unload() displayScreenShots(); //Scroll down button - GUIEngine::IconButtonWidget* down_button = new GUIEngine::IconButtonWidget( + GUIEngine::IconButtonWidget* down_button = resize ? + static_cast(*wit++) : + new GUIEngine::IconButtonWidget( GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); down_button->m_properties[GUIEngine::PROP_ID] = "down_button"; @@ -1865,9 +1904,16 @@ void RaceResultGUI::unload() down_button->m_y = y; down_button->m_w = w; down_button->m_h = font_height; - down_button->add(); - down_button->setImage(file_manager->getAsset(FileManager::GUI_ICON, "scroll_down.png")); - addGPProgressWidget(down_button); + if (resize) + { + down_button->resize(); + } + else + { + down_button->add(); + down_button->setImage(file_manager->getAsset(FileManager::GUI_ICON, "scroll_down.png")); + addGPProgressWidget(down_button); + } } // if MAJOR_MODE_GRAND_PRIX) @@ -2250,3 +2296,11 @@ void RaceResultGUI::unload() assert(m_font != NULL); return m_font->getDimension(L"A").Height; //Could be any capital letter } + + // ---------------------------------------------------------------------------- + void RaceResultGUI::onResize() + { + Screen::onResize(); + if (!m_gp_progress_widgets.empty()) + enableGPProgress(); + } diff --git a/src/states_screens/race_result_gui.hpp b/src/states_screens/race_result_gui.hpp index 2dd8f2c22d5..d6704b1a681 100644 --- a/src/states_screens/race_result_gui.hpp +++ b/src/states_screens/race_result_gui.hpp @@ -270,6 +270,7 @@ class RaceResultGUI : public RaceGUIBase, virtual void onConfirm() OVERRIDE; void cleanupGPProgress(); + virtual void onResize() OVERRIDE; }; // RaceResultGUI #endif From 3a0a2eaf97848a791c420ebd709500f6c9bd16bf Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sat, 4 May 2024 16:54:09 +0800 Subject: [PATCH 358/830] Add resizing code for kart selection --- src/guiengine/widgets/player_kart_widget.cpp | 23 +++++++++------ src/guiengine/widgets/player_kart_widget.hpp | 11 +++++++ src/states_screens/kart_selection.cpp | 31 ++++++++++++++++++++ src/states_screens/kart_selection.hpp | 2 ++ 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/guiengine/widgets/player_kart_widget.cpp b/src/guiengine/widgets/player_kart_widget.cpp index 292ba7d672f..4e06b0af64d 100644 --- a/src/guiengine/widgets/player_kart_widget.cpp +++ b/src/guiengine/widgets/player_kart_widget.cpp @@ -542,6 +542,19 @@ void PlayerKartWidget::onUpdate(float delta) if (m_h < target_h) m_h = target_h; } + updateSize(); + // When coming from the overworld, we must rebuild the preview scene at + // least once, since the scene is being cleared by leaving the overworld + if (m_not_updated_yet) + { + m_model_view->clearRttProvider(); + m_not_updated_yet = false; + } +} // onUpdate + +// ------------------------------------------------------------------------- +void PlayerKartWidget::updateSize() +{ setSize(m_x, m_y, m_w, m_h); if (m_player_ident_spinner != NULL) @@ -580,15 +593,7 @@ void PlayerKartWidget::onUpdate(float delta) kart_name_y, kart_name_w, kart_name_h); - - // When coming from the overworld, we must rebuild the preview scene at - // least once, since the scene is being cleared by leaving the overworld - if (m_not_updated_yet) - { - m_model_view->clearRttProvider(); - m_not_updated_yet = false; - } -} // onUpdate +} // updateSize // ------------------------------------------------------------------------- /** Event callback */ diff --git a/src/guiengine/widgets/player_kart_widget.hpp b/src/guiengine/widgets/player_kart_widget.hpp index 7692563909a..9d8ace15894 100644 --- a/src/guiengine/widgets/player_kart_widget.hpp +++ b/src/guiengine/widgets/player_kart_widget.hpp @@ -72,6 +72,8 @@ namespace GUIEngine long m_magic_number; #endif + // ------------------------------------------------------------------------- + void updateSize(); public: LEAK_CHECK() @@ -166,6 +168,15 @@ namespace GUIEngine virtual GUIEngine::EventPropagation onSpinnerConfirmed(); // ------------------------------------------------------------------------- void enableHandicapForNetwork(); + // ------------------------------------------------------------------------- + void updateSizeNow(int x, int y, int w, int h) + { + target_x = m_x = x; + target_y = m_y = y; + target_w = m_w = w; + target_h = m_h = h; + updateSize(); + } }; // PlayerKartWidget } diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index bc67fb008a1..5497bf25b50 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -1639,3 +1639,34 @@ bool KartSelectionScreen::useContinueButton() const #pragma mark - #endif +// ---------------------------------------------------------------------------- +void KartSelectionScreen::onResize() +{ + // Remove dispatcher from m_widgets before calculateLayout otherwise a + // dummy button is shown in kart screen + bool removed_dispatcher = false; + if (m_widgets.contains(m_dispatcher)) + { + m_widgets.remove(m_dispatcher); + removed_dispatcher = true; + } + Screen::onResize(); + if (removed_dispatcher) + m_widgets.push_back(m_dispatcher); + if (m_multiplayer) + { + if (m_kart_widgets.size() < 2) + addMultiplayerMessage(); + if (m_kart_widgets.empty()) + return; + } + Widget* fullarea = getWidget("playerskarts"); + int split_width = fullarea->m_w / m_kart_widgets.size(); + if (m_multiplayer && m_kart_widgets.size() == 1) + split_width /= 2; + for (unsigned i = 0; i < m_kart_widgets.size(); i++) + { + m_kart_widgets[i].updateSizeNow(fullarea->m_x + split_width * i, + fullarea->m_y, split_width, fullarea->m_h); + } +} // onResize diff --git a/src/states_screens/kart_selection.hpp b/src/states_screens/kart_selection.hpp index 273f339a474..b03b4e4308c 100644 --- a/src/states_screens/kart_selection.hpp +++ b/src/states_screens/kart_selection.hpp @@ -180,6 +180,8 @@ class KartSelectionScreen : public GUIEngine::Screen * class GUIEngine::Screen */ virtual bool onEscapePressed() OVERRIDE; + virtual void onResize() OVERRIDE; + }; // KartSelectionScreen //!---------------------------------------------------------------------------- From 7a75f9e541f7f9ef9409c6020e253cf66216d679 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sat, 4 May 2024 19:14:48 +0200 Subject: [PATCH 359/830] Clean up the Race Result GUI code - Remove excessive indentations in race_result_gui.cpp - Move the bulk of the displayPostRaceInfo function into new functions: displayHighscores, displayLapDifficulty and displayChallengeInfo - Add comments for the closing braces of functions, for the closing braces of some large code blocks, and explaining some functions --- src/states_screens/race_result_gui.cpp | 2551 ++++++++++++------------ src/states_screens/race_result_gui.hpp | 3 + 2 files changed, 1297 insertions(+), 1257 deletions(-) diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index f71517b4bfe..0ed9a550844 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -836,1471 +836,1508 @@ void RaceResultGUI::displayCTFResults() draw2DImage(kart_icon, dest_rect, source_rect, NULL, NULL, true); } #endif -} +} // displayCTFResults + //----------------------------------------------------------------------------- void RaceResultGUI::unload() { cleanupGPProgress(); Screen::unload(); -} +} // unload //----------------------------------------------------------------------------- - void RaceResultGUI::onConfirm() - { - //RaceManager::get()->saveGP(); // Save the aborted GP - GUIEngine::ModalDialog::dismiss(); - cleanupGPProgress(); - StateManager::get()->popMenu(); - RaceManager::get()->exitRace(); - RaceManager::get()->setAIKartOverride(""); - StateManager::get()->resetAndGoToScreen( - MainMenuScreen::getInstance()); +void RaceResultGUI::onConfirm() +{ + //RaceManager::get()->saveGP(); // Save the aborted GP + GUIEngine::ModalDialog::dismiss(); + cleanupGPProgress(); + StateManager::get()->popMenu(); + RaceManager::get()->exitRace(); + RaceManager::get()->setAIKartOverride(""); + StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance()); - if (RaceManager::get()->raceWasStartedFromOverworld()) - { - OverWorld::enterOverWorld(); - } + if (RaceManager::get()->raceWasStartedFromOverworld()) + { + OverWorld::enterOverWorld(); } +} // onConfirm - //----------------------------------------------------------------------------- - /** This determines the layout, i.e. the size of all columns, font size etc. - */ - void RaceResultGUI::determineTableLayout() - { - GUIEngine::Widget *table_area = getWidget("result-table"); +//----------------------------------------------------------------------------- +/** This determines the layout, i.e. the size of all columns, font size etc. + */ +void RaceResultGUI::determineTableLayout() +{ + GUIEngine::Widget *table_area = getWidget("result-table"); - m_font = GUIEngine::getFont(); - assert(m_font); - //m_was_monospace = m_font->getMonospaceDigits(); - //m_font->setMonospaceDigits(true); - WorldWithRank *rank_world = (WorldWithRank*)World::getWorld(); + m_font = GUIEngine::getFont(); + assert(m_font); + //m_was_monospace = m_font->getMonospaceDigits(); + //m_font->setMonospaceDigits(true); + WorldWithRank *rank_world = (WorldWithRank*)World::getWorld(); - unsigned int first_position = 1; - unsigned int sta = RaceManager::get()->getNumSpareTireKarts(); - if (RaceManager::get()->isFollowMode()) - first_position = 2; + unsigned int first_position = 1; + unsigned int sta = RaceManager::get()->getNumSpareTireKarts(); + if (RaceManager::get()->isFollowMode()) + first_position = 2; - // Use only the karts that are supposed to be displayed (and - // ignore e.g. the leader in a FTL race). - unsigned int num_karts = RaceManager::get()->getNumberOfKarts() - first_position + 1 - sta; + // Use only the karts that are supposed to be displayed (and + // ignore e.g. the leader in a FTL race). + unsigned int num_karts = RaceManager::get()->getNumberOfKarts() - first_position + 1 - sta; - // Remove previous entries to avoid reserved kart in network being displayed - m_all_row_infos.clear(); - // In FTL races the leader kart is not displayed - m_all_row_infos.resize(num_karts); + // Remove previous entries to avoid reserved kart in network being displayed + m_all_row_infos.clear(); + // In FTL races the leader kart is not displayed + m_all_row_infos.resize(num_karts); - // Determine the kart to display in the right order, - // and the maximum width for the kart name column - // ------------------------------------------------- - m_width_kart_name = 0; - float max_finish_time = 0; + // Determine the kart to display in the right order, + // and the maximum width for the kart name column + // ------------------------------------------------- + m_width_kart_name = 0; + float max_finish_time = 0; - FreeForAll* ffa = dynamic_cast(World::getWorld()); + FreeForAll* ffa = dynamic_cast(World::getWorld()); - int time_precision = RaceManager::get()->currentModeTimePrecision(); - bool active_gp = (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX); + int time_precision = RaceManager::get()->currentModeTimePrecision(); + bool active_gp = (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX); - auto cl = LobbyProtocol::get(); - for (unsigned int position = first_position; + auto cl = LobbyProtocol::get(); + for (unsigned int position = first_position; position <= RaceManager::get()->getNumberOfKarts() - sta; position++) - { - const AbstractKart *kart = rank_world->getKartAtPosition(position); + { + const AbstractKart *kart = rank_world->getKartAtPosition(position); - if (ffa && kart->isEliminated()) - continue; - // Save a pointer to the current row_info entry - RowInfo *ri = &(m_all_row_infos[position - first_position]); - ri->m_kart_id = kart->getWorldKartId(); - ri->m_is_player_kart = kart->getController()->isLocalPlayerController(); - ri->m_kart_name = kart->getController()->getName(); - if (RaceManager::get()->getKartGlobalPlayerId(kart->getWorldKartId()) > -1) + if (ffa && kart->isEliminated()) + continue; + // Save a pointer to the current row_info entry + RowInfo *ri = &(m_all_row_infos[position - first_position]); + ri->m_kart_id = kart->getWorldKartId(); + ri->m_is_player_kart = kart->getController()->isLocalPlayerController(); + ri->m_kart_name = kart->getController()->getName(); + if (RaceManager::get()->getKartGlobalPlayerId(kart->getWorldKartId()) > -1) + { + const core::stringw& flag = StringUtils::getCountryFlag( + RaceManager::get()->getKartInfo(kart->getWorldKartId()).getCountryCode()); + if (!flag.empty()) { - const core::stringw& flag = StringUtils::getCountryFlag( - RaceManager::get()->getKartInfo(kart->getWorldKartId()).getCountryCode()); - if (!flag.empty()) - { - ri->m_kart_name += L" "; - ri->m_kart_name += flag; - } + ri->m_kart_name += L" "; + ri->m_kart_name += flag; } - video::ITexture *icon = - kart->getKartProperties()->getIconMaterial()->getTexture(); - ri->m_kart_icon = icon; - ri->m_kart_color = RaceManager::get()->getKartColor(kart->getWorldKartId()); + } + video::ITexture *icon = + kart->getKartProperties()->getIconMaterial()->getTexture(); + ri->m_kart_icon = icon; + ri->m_kart_color = RaceManager::get()->getKartColor(kart->getWorldKartId()); - // FTL karts will get a time assigned, they are not shown as eliminated - if (kart->isEliminated() && RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES) - { - ri->m_finish_time_string = core::stringw(_("Eliminated after %s", - StringUtils::toWString(StringUtils::timeToString(kart->getFinishTime(), time_precision)))); - } - else if (kart->isEliminated() && !(RaceManager::get()->isFollowMode())) - { - ri->m_finish_time_string = core::stringw(_("Eliminated")); - } - else if ( RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL - || RaceManager::get()->isCTFMode()) - { - assert(ffa); - ri->m_finish_time_string = - StringUtils::toWString(ffa->getKartScore(kart->getWorldKartId())); - } - else - { - const float time = kart->getFinishTime(); - if (time > max_finish_time) max_finish_time = time; - std::string time_string = StringUtils::timeToString(time, time_precision); - ri->m_finish_time_string = time_string.c_str(); - } - if (cl && !cl->getRankingChanges().empty()) + // FTL karts will get a time assigned, they are not shown as eliminated + if (kart->isEliminated() && RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES) + { + ri->m_finish_time_string = core::stringw(_("Eliminated after %s", + StringUtils::toWString(StringUtils::timeToString(kart->getFinishTime(), time_precision)))); + } + else if (kart->isEliminated() && !(RaceManager::get()->isFollowMode())) + { + ri->m_finish_time_string = core::stringw(_("Eliminated")); + } + else if ( RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL + || RaceManager::get()->isCTFMode()) + { + assert(ffa); + ri->m_finish_time_string = + StringUtils::toWString(ffa->getKartScore(kart->getWorldKartId())); + } + else + { + const float time = kart->getFinishTime(); + if (time > max_finish_time) max_finish_time = time; + std::string time_string = StringUtils::timeToString(time, time_precision); + ri->m_finish_time_string = time_string.c_str(); + } + if (cl && !cl->getRankingChanges().empty()) + { + unsigned kart_id = kart->getWorldKartId(); + if (kart_id < cl->getRankingChanges().size()) { - unsigned kart_id = kart->getWorldKartId(); - if (kart_id < cl->getRankingChanges().size()) + ri->m_finish_time_string += L" "; + float ranking_change = cl->getRankingChanges()[kart_id]; + if (ranking_change > 0) { - ri->m_finish_time_string += L" "; - float ranking_change = cl->getRankingChanges()[kart_id]; - if (ranking_change > 0) - { - ri->m_finish_time_string += L"+"; - ri->m_finish_time_string += StringUtils::toWString(ranking_change); - } - else - ri->m_finish_time_string += StringUtils::toWString(ranking_change); + ri->m_finish_time_string += L"+"; + ri->m_finish_time_string += StringUtils::toWString(ranking_change); } + else + ri->m_finish_time_string += StringUtils::toWString(ranking_change); } - ri->m_laps = World::getWorld()->raceHasLaps() ? - World::getWorld()->getFinishedLapsOfKart(ri->m_kart_id) : 0; - - core::dimension2du rect = - m_font->getDimension(ri->m_kart_name.c_str()); - if (rect.Width > m_width_kart_name) - m_width_kart_name = rect.Width; - } // for position - - std::string max_time = StringUtils::timeToString(max_finish_time, time_precision, true, /*display hours*/ active_gp); - core::stringw string_max_time(max_time.c_str()); - core::dimension2du r = m_font->getDimension(string_max_time.c_str()); - m_width_finish_time = r.Width; - - // Top pixel where to display text - m_top = table_area->m_y; - - // Height of the result display - unsigned int height = table_area->m_h; - - // Setup different timing information for the different phases - // ----------------------------------------------------------- - // How much time between consecutive rows - m_time_between_rows = 0.1f; - - // How long it takes for one line to scroll from right to left - m_time_single_scroll = 0.2f; - - // Time to rotate the entries to the proper GP position. - m_time_rotation = 1.0f; - - // The time the first phase is being displayed: add the start time - // of the last kart to the duration of the scroll plus some time - // of rest before the next phase starts - m_time_overall_scroll = (num_karts - 1)*m_time_between_rows - + m_time_single_scroll + 2.0f; - - // The time to increase the number of points. - m_time_for_points = 1.0f; - - // Determine text height - r = m_font->getDimension(L"Y"); - m_distance_between_rows = (int)(1.5f*r.Height); - m_distance_between_meta_rows = m_distance_between_rows; - - // If there are too many highscores, reduce size between rows - Highscores* scores = World::getWorld()->getHighscores(); - if (scores != NULL && - scores->getNumberEntries() * m_distance_between_meta_rows > height * 0.5f) - m_distance_between_meta_rows *= 0.8f; - - // If there are too many karts, reduce size between rows - if (m_distance_between_rows * num_karts > height) - m_distance_between_rows = height / num_karts; - - m_width_icon = std::min((int)(table_area->m_h / num_karts), + } + ri->m_laps = World::getWorld()->raceHasLaps() ? + World::getWorld()->getFinishedLapsOfKart(ri->m_kart_id) : 0; + + core::dimension2du rect = + m_font->getDimension(ri->m_kart_name.c_str()); + if (rect.Width > m_width_kart_name) + m_width_kart_name = rect.Width; + } // for position + + std::string max_time = StringUtils::timeToString(max_finish_time, time_precision, true, /*display hours*/ active_gp); + core::stringw string_max_time(max_time.c_str()); + core::dimension2du r = m_font->getDimension(string_max_time.c_str()); + m_width_finish_time = r.Width; + + // Top pixel where to display text + m_top = table_area->m_y; + + // Height of the result display + unsigned int height = table_area->m_h; + + // Setup different timing information for the different phases + // ----------------------------------------------------------- + // How much time between consecutive rows + m_time_between_rows = 0.1f; + + // How long it takes for one line to scroll from right to left + m_time_single_scroll = 0.2f; + + // Time to rotate the entries to the proper GP position. + m_time_rotation = 1.0f; + + // The time the first phase is being displayed: add the start time + // of the last kart to the duration of the scroll plus some time + // of rest before the next phase starts + m_time_overall_scroll = (num_karts - 1)*m_time_between_rows + + m_time_single_scroll + 2.0f; + + // The time to increase the number of points. + m_time_for_points = 1.0f; + + // Determine text height + r = m_font->getDimension(L"Y"); + m_distance_between_rows = (int)(1.5f*r.Height); + m_distance_between_meta_rows = m_distance_between_rows; + + // If there are too many highscores, reduce size between rows + Highscores* scores = World::getWorld()->getHighscores(); + if (scores != NULL && + scores->getNumberEntries() * m_distance_between_meta_rows > height * 0.5f) + m_distance_between_meta_rows *= 0.8f; + + // If there are too many karts, reduce size between rows + if (m_distance_between_rows * num_karts > height) + m_distance_between_rows = height / num_karts; + + m_width_icon = std::min((int)(table_area->m_h / num_karts), GUIEngine::getFontHeight()); - m_width_column_space = 10; + m_width_column_space = 10; - // Determine width of new points column + // Determine width of new points column - //m_font->setMonospaceDigits(true); - core::dimension2du r_new_p = m_font->getDimension(L"+99"); + //m_font->setMonospaceDigits(true); + core::dimension2du r_new_p = m_font->getDimension(L"+99"); - m_width_new_points = r_new_p.Width; + m_width_new_points = r_new_p.Width; - // Determine width of overall points column - core::dimension2du r_all_p = m_font->getDimension(L"999"); - //m_font->setMonospaceDigits(false); + // Determine width of overall points column + core::dimension2du r_all_p = m_font->getDimension(L"999"); + //m_font->setMonospaceDigits(false); - m_width_all_points = r_all_p.Width; + m_width_all_points = r_all_p.Width; - m_table_width = m_width_icon + m_width_column_space - + m_width_kart_name; + m_table_width = m_width_icon + m_width_column_space + m_width_kart_name; - if (!RaceManager::get()->isFollowMode()) - m_table_width += m_width_finish_time + m_width_column_space; + if (!RaceManager::get()->isFollowMode()) + m_table_width += m_width_finish_time + m_width_column_space; - // Only in GP mode are the points displayed. - if (active_gp) - m_table_width += m_width_new_points + m_width_all_points + // Only in GP mode are the points displayed. + if (active_gp) + m_table_width += m_width_new_points + m_width_all_points + 2 * m_width_column_space; - m_leftmost_column = table_area->m_x; - } // determineTableLayout - - //----------------------------------------------------------------------------- - /** This function is called when one of the player presses 'fire'. The next - * phase of the animation will be displayed. E.g. - * in a GP: pressing fire while/after showing the latest race result will - * start the animation for the current GP result - * in a normal race: when pressing fire while an animation is played, - * start the menu showing 'rerun, new race, back to main' etc. - */ - void RaceResultGUI::nextPhase() - { - // This will trigger the next phase in the next render call. - m_timer = 9999; - } // nextPhase - - //----------------------------------------------------------------------------- - /** If escape is pressed, don't do the default option (close the screen), but - * advance to the next animation phase. - */ - bool RaceResultGUI::onEscapePressed() - { - nextPhase(); - return false; // indicates 'do not close' - } // onEscapePressed - - //----------------------------------------------------------------------------- - /** This is called before an event is sent to a widget. Since in this case - * no widget is active, the event would be lost, so we act on fire events - * here and trigger the next phase. - */ - GUIEngine::EventPropagation RaceResultGUI::filterActions(PlayerAction action, - int deviceID, - const unsigned int value, - Input::InputType type, - int playerId) - { - if (action != PA_FIRE) return GUIEngine::EVENT_LET; + m_leftmost_column = table_area->m_x; +} // determineTableLayout - // If the buttons are already visible, let the event go through since - // it will be triggering eventCallback where this is handles. +//----------------------------------------------------------------------------- +/** This function is called when one of the player presses 'fire'. The next + * phase of the animation will be displayed. E.g. + * in a GP: pressing fire while/after showing the latest race result will + * start the animation for the current GP result + * in a normal race: when pressing fire while an animation is played, + * start the menu showing 'rerun, new race, back to main' etc. + */ +void RaceResultGUI::nextPhase() +{ + // This will trigger the next phase in the next render call. + m_timer = 9999; +} // nextPhase - if (m_animation_state == RR_WAIT_TILL_END) return GUIEngine::EVENT_LET; +//----------------------------------------------------------------------------- +/** If escape is pressed, don't do the default option (close the screen), but + * advance to the next animation phase. + */ +bool RaceResultGUI::onEscapePressed() +{ + nextPhase(); + return false; // indicates 'do not close' +} // onEscapePressed - nextPhase(); - return GUIEngine::EVENT_BLOCK; - } // filterActions +//----------------------------------------------------------------------------- +/** This is called before an event is sent to a widget. Since in this case + * no widget is active, the event would be lost, so we act on fire events + * here and trigger the next phase. + */ +GUIEngine::EventPropagation RaceResultGUI::filterActions(PlayerAction action, + int deviceID, const unsigned int value, Input::InputType type, int playerId) +{ + if (action != PA_FIRE) return GUIEngine::EVENT_LET; - //----------------------------------------------------------------------------- - /** Called once a frame */ - void RaceResultGUI::onUpdate(float dt) + // If the buttons are already visible, let the event go through since + // it will be triggering eventCallback where this is handles. + + if (m_animation_state == RR_WAIT_TILL_END) return GUIEngine::EVENT_LET; + + nextPhase(); + return GUIEngine::EVENT_BLOCK; +} // filterActions + +//----------------------------------------------------------------------------- +/** Called once a frame */ +void RaceResultGUI::onUpdate(float dt) +{ + // When the finish sound has been played, start the race over music. + if (!m_started_race_over_music && + m_finish_sound && m_finish_sound->getStatus() != SFXBase::SFX_PLAYING) { - // When the finish sound has been played, start the race over music. - if (!m_started_race_over_music && - m_finish_sound && m_finish_sound->getStatus() != SFXBase::SFX_PLAYING) + try { - try - { - // This call is done once each frame, but startMusic() is cheap - // if the music is already playing. - music_manager->startMusic(m_race_over_music); - m_started_race_over_music = true; - } - catch (std::exception& e) - { - Log::error("RaceResultGUI", "Exception caught when " - "trying to load music: %s", e.what()); - } + // This call is done once each frame, but startMusic() is cheap + // if the music is already playing. + music_manager->startMusic(m_race_over_music); + m_started_race_over_music = true; } - } // onUpdate - - //----------------------------------------------------------------------------- - /** Called once a frame, this now triggers the rendering of the actual - * race result gui. - */ - void RaceResultGUI::onDraw(float dt) - { - renderGlobal(dt); - } // onDraw + catch (std::exception& e) + { + Log::error("RaceResultGUI", "Exception caught when " + "trying to load music: %s", e.what()); + } + } +} // onUpdate +//----------------------------------------------------------------------------- +/** Called once a frame, this now triggers the rendering of the actual + * race result gui. + */ +void RaceResultGUI::onDraw(float dt) +{ + renderGlobal(dt); +} // onDraw - //----------------------------------------------------------------------------- - /** Render all global parts of the race gui, i.e. things that are only - * displayed once even in splitscreen. - * \param dt Timestep sized. - */ - void RaceResultGUI::renderGlobal(float dt) - { +//----------------------------------------------------------------------------- +/** Render all global parts of the race gui, i.e. things that are only + * displayed once even in splitscreen. + * \param dt Timestep sized. + */ +void RaceResultGUI::renderGlobal(float dt) +{ #ifndef SERVER_ONLY - m_timer += dt; - assert(World::getWorld()->getPhase() == WorldStatus::RESULT_DISPLAY_PHASE); - unsigned int num_karts = (unsigned int)m_all_row_infos.size(); - float time_overall_scroll = m_time_overall_scroll; - - // First: Update the finite state machine - // ====================================== - switch (m_animation_state) + m_timer += dt; + assert(World::getWorld()->getPhase() == WorldStatus::RESULT_DISPLAY_PHASE); + unsigned int num_karts = (unsigned int)m_all_row_infos.size(); + float time_overall_scroll = m_time_overall_scroll; + + // First: Update the finite state machine + // ====================================== + switch (m_animation_state) + { + case RR_INIT: + for (unsigned int i = 0; i < num_karts; i++) + { + RowInfo *ri = &(m_all_row_infos[i]); + ri->m_start_at = m_time_between_rows * i; + ri->m_x_pos = (float)UserConfigParams::m_width; + ri->m_y_pos = (float)(m_top + i*m_distance_between_rows); + } + m_animation_state = RR_RACE_RESULT; + break; + case RR_RACE_RESULT: + // GP mode has a continue button so no extra time is needed + if (RaceManager::get()->getMajorMode() == + RaceManager::MAJOR_MODE_GRAND_PRIX) + time_overall_scroll -= 2.0f; + if (m_timer > time_overall_scroll) { - case RR_INIT: + // Make sure that all lines are aligned to the left + // (in case that the animation was skipped). for (unsigned int i = 0; i < num_karts; i++) { RowInfo *ri = &(m_all_row_infos[i]); - ri->m_start_at = m_time_between_rows * i; - ri->m_x_pos = (float)UserConfigParams::m_width; - ri->m_y_pos = (float)(m_top + i*m_distance_between_rows); + ri->m_x_pos = (float)m_leftmost_column; } - m_animation_state = RR_RACE_RESULT; - break; - case RR_RACE_RESULT: - // GP mode has a continue button so no extra time is needed - if (RaceManager::get()->getMajorMode() == + if (RaceManager::get()->getMajorMode() != RaceManager::MAJOR_MODE_GRAND_PRIX) - time_overall_scroll -= 2.0f; - if (m_timer > time_overall_scroll) - { - // Make sure that all lines are aligned to the left - // (in case that the animation was skipped). - for (unsigned int i = 0; i < num_karts; i++) - { - RowInfo *ri = &(m_all_row_infos[i]); - ri->m_x_pos = (float)m_leftmost_column; - } - if (RaceManager::get()->getMajorMode() != - RaceManager::MAJOR_MODE_GRAND_PRIX) - { - m_animation_state = RR_WAIT_TILL_END; - enableAllButtons(); - break; - } - - m_animation_state = RR_WAITING_GP_RESULT; - std::vector prev_infos = m_all_row_infos; - determineGPLayout(); - m_all_row_info_waiting = m_all_row_infos; - m_all_row_infos = prev_infos; - GUIEngine::IconButtonWidget *middle = getWidget("middle"); - GUIEngine::RibbonWidget *operations = getWidget("operations"); - operations->setActive(true); - operations->setFocusForPlayer(PLAYER_ID_GAME_MASTER); - middle->setLabel(_("Continue")); - middle->setImage("gui/icons/green_check.png"); - middle->setVisible(true); - operations->select("middle", PLAYER_ID_GAME_MASTER); - } - break; - case RR_WAITING_GP_RESULT: - break; - case RR_OLD_GP_RESULTS: - if (m_timer > m_time_overall_scroll) { - m_animation_state = RR_INCREASE_POINTS; - m_timer = 0; - for (unsigned int i = 0; i < num_karts; i++) - { - RowInfo *ri = &(m_all_row_infos[i]); - ri->m_x_pos = (float)m_leftmost_column; - } + m_animation_state = RR_WAIT_TILL_END; + enableAllButtons(); + break; } - break; - case RR_INCREASE_POINTS: - // Have one second delay before the resorting starts. - if (m_timer > 1 + m_time_for_points) - { - m_animation_state = RR_RESORT_TABLE; - if (m_gp_position_was_changed) - m_timer = 0; - else - // This causes the phase to go to RESORT_TABLE once, and then - // immediately wait till end. This has the advantage that any - // phase change settings will be processed properly. - m_timer = m_time_rotation + 1; - // Make the new row permanent; necessary in case - // that the animation is skipped. - for (unsigned int i = 0; i < num_karts; i++) - { - RowInfo *ri = &(m_all_row_infos[i]); - ri->m_new_points = 0; - ri->m_current_displayed_points = - (float)ri->m_new_overall_points; - } - } - break; - case RR_RESORT_TABLE: - if (m_timer > m_time_rotation) + m_animation_state = RR_WAITING_GP_RESULT; + std::vector prev_infos = m_all_row_infos; + determineGPLayout(); + m_all_row_info_waiting = m_all_row_infos; + m_all_row_infos = prev_infos; + GUIEngine::IconButtonWidget *middle = getWidget("middle"); + GUIEngine::RibbonWidget *operations = getWidget("operations"); + operations->setActive(true); + operations->setFocusForPlayer(PLAYER_ID_GAME_MASTER); + middle->setLabel(_("Continue")); + middle->setImage("gui/icons/green_check.png"); + middle->setVisible(true); + operations->select("middle", PLAYER_ID_GAME_MASTER); + } + break; + case RR_WAITING_GP_RESULT: + break; + case RR_OLD_GP_RESULTS: + if (m_timer > m_time_overall_scroll) + { + m_animation_state = RR_INCREASE_POINTS; + m_timer = 0; + for (unsigned int i = 0; i < num_karts; i++) { - m_animation_state = RR_WAIT_TILL_END; - // Make the new row permanent. - for (unsigned int i = 0; i < num_karts; i++) - { - RowInfo *ri = &(m_all_row_infos[i]); - ri->m_y_pos = ri->m_centre_point - ri->m_radius; - } - enableAllButtons(); + RowInfo *ri = &(m_all_row_infos[i]); + ri->m_x_pos = (float)m_leftmost_column; } - break; - case RR_WAIT_TILL_END: - if (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) - displayGPProgress(); - if (m_timer - m_time_rotation > 1.0f && - dynamic_cast(World::getWorld())) + } + break; + case RR_INCREASE_POINTS: + // Have one second delay before the resorting starts. + if (m_timer > 1 + m_time_for_points) + { + m_animation_state = RR_RESORT_TABLE; + if (m_gp_position_was_changed) + m_timer = 0; + else + // This causes the phase to go to RESORT_TABLE once, and then + // immediately wait till end. This has the advantage that any + // phase change settings will be processed properly. + m_timer = m_time_rotation + 1; + // Make the new row permanent; necessary in case + // that the animation is skipped. + for (unsigned int i = 0; i < num_karts; i++) { - RaceManager::get()->exitRace(); - StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance()); + RowInfo *ri = &(m_all_row_infos[i]); + ri->m_new_points = 0; + ri->m_current_displayed_points = + (float)ri->m_new_overall_points; } - break; - } // switch - // Second phase: update X and Y positions for the various animations - // ================================================================= - float v = 0.9f*UserConfigParams::m_width / m_time_single_scroll; - if (RaceManager::get()->isSoccerMode()) + } + break; + case RR_RESORT_TABLE: + if (m_timer > m_time_rotation) { - displaySoccerResults(); + m_animation_state = RR_WAIT_TILL_END; + // Make the new row permanent. + for (unsigned int i = 0; i < num_karts; i++) + { + RowInfo *ri = &(m_all_row_infos[i]); + ri->m_y_pos = ri->m_centre_point - ri->m_radius; + } + enableAllButtons(); } - else if (RaceManager::get()->isCTFMode()) + break; + case RR_WAIT_TILL_END: + if (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) + displayGPProgress(); + if (m_timer - m_time_rotation > 1.0f && + dynamic_cast(World::getWorld())) { - displayCTFResults(); + RaceManager::get()->exitRace(); + StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance()); } - else + break; + } // switch + + // Second phase: update X and Y positions for the various animations + // ================================================================= + float v = 0.9f*UserConfigParams::m_width / m_time_single_scroll; + if (RaceManager::get()->isSoccerMode()) + { + displaySoccerResults(); + } + else if (RaceManager::get()->isCTFMode()) + { + displayCTFResults(); + } + else + { + for (unsigned int i = 0; i < m_all_row_infos.size(); i++) { - for (unsigned int i = 0; i < m_all_row_infos.size(); i++) + RowInfo *ri = &(m_all_row_infos[i]); + float x = ri->m_x_pos; + float y = ri->m_y_pos; + switch (m_animation_state) + { + // Both states use the same scrolling: + case RR_INIT: break; // Remove compiler warning + case RR_RACE_RESULT: + case RR_WAITING_GP_RESULT: + case RR_OLD_GP_RESULTS: + if (m_timer > ri->m_start_at) + { // if active + ri->m_x_pos -= dt*v; + if (ri->m_x_pos < m_leftmost_column) + ri->m_x_pos = (float)m_leftmost_column; + x = ri->m_x_pos; + } + break; + case RR_INCREASE_POINTS: { - RowInfo *ri = &(m_all_row_infos[i]); - float x = ri->m_x_pos; - float y = ri->m_y_pos; - switch (m_animation_state) - { - // Both states use the same scrolling: - case RR_INIT: break; // Remove compiler warning - case RR_RACE_RESULT: - case RR_WAITING_GP_RESULT: - case RR_OLD_GP_RESULTS: - if (m_timer > ri->m_start_at) - { // if active - ri->m_x_pos -= dt*v; - if (ri->m_x_pos < m_leftmost_column) - ri->m_x_pos = (float)m_leftmost_column; - x = ri->m_x_pos; - } - break; - case RR_INCREASE_POINTS: + WorldWithRank *wwr = dynamic_cast(World::getWorld()); + assert(wwr); + int most_points; + if (RaceManager::get()->isFollowMode()) + most_points = wwr->getScoreForPosition(2); + else + most_points = wwr->getScoreForPosition(1); + ri->m_current_displayed_points += + dt*most_points / m_time_for_points; + if (ri->m_current_displayed_points > ri->m_new_overall_points) { - WorldWithRank *wwr = dynamic_cast(World::getWorld()); - assert(wwr); - int most_points; - if (RaceManager::get()->isFollowMode()) - most_points = wwr->getScoreForPosition(2); - else - most_points = wwr->getScoreForPosition(1); - ri->m_current_displayed_points += - dt*most_points / m_time_for_points; - if (ri->m_current_displayed_points > ri->m_new_overall_points) - { - ri->m_current_displayed_points = - (float)ri->m_new_overall_points; - } - ri->m_new_points -= - dt*most_points / m_time_for_points; - if (ri->m_new_points < 0) - ri->m_new_points = 0; - break; + ri->m_current_displayed_points = + (float)ri->m_new_overall_points; } - case RR_RESORT_TABLE: - x = ri->m_x_pos - - ri->m_radius*sinf(m_timer / m_time_rotation*M_PI); - y = ri->m_centre_point - + ri->m_radius*cosf(m_timer / m_time_rotation*M_PI); - break; - case RR_WAIT_TILL_END: - break; - } // switch - displayOneEntry((unsigned int)x, (unsigned int)y, i, true); - } // for i - } + ri->m_new_points -= + dt*most_points / m_time_for_points; + if (ri->m_new_points < 0) + ri->m_new_points = 0; + break; + } + case RR_RESORT_TABLE: + x = ri->m_x_pos + - ri->m_radius*sinf(m_timer / m_time_rotation*M_PI); + y = ri->m_centre_point + + ri->m_radius*cosf(m_timer / m_time_rotation*M_PI); + break; + case RR_WAIT_TILL_END: + break; + } // switch + displayOneEntry((unsigned int)x, (unsigned int)y, i, true); + } // for i + } - // Display highscores - if (RaceManager::get()->getMajorMode() != RaceManager::MAJOR_MODE_GRAND_PRIX || - m_animation_state == RR_WAITING_GP_RESULT) - { - displayPostRaceInfo(); - } + // Display highscores, lap and difficulty info, challenge status + if (RaceManager::get()->getMajorMode() != RaceManager::MAJOR_MODE_GRAND_PRIX || + m_animation_state == RR_WAITING_GP_RESULT) + { + displayPostRaceInfo(); + } #endif - } // renderGlobal +} // renderGlobal - //----------------------------------------------------------------------------- - /** Determine the layout and fields for the GP table based on the previous - * GP results. - */ - void RaceResultGUI::determineGPLayout() - { +//----------------------------------------------------------------------------- +/** Determine the layout and fields for the GP table based on the previous + * GP results. + */ +void RaceResultGUI::determineGPLayout() +{ #ifndef SERVER_ONLY - unsigned int num_karts = RaceManager::get()->getNumberOfKarts(); - std::vector old_rank(num_karts, 0); + unsigned int num_karts = RaceManager::get()->getNumberOfKarts(); + std::vector old_rank(num_karts, 0); - int time_precision = RaceManager::get()->currentModeTimePrecision(); + int time_precision = RaceManager::get()->currentModeTimePrecision(); - float max_time = 0; - /* Compute highest overall time to know if hours should be displayed */ - for (unsigned int kart_id = 0; kart_id < num_karts; kart_id++) - { - max_time = std::max(RaceManager::get()->getOverallTime(kart_id), max_time); - } + float max_time = 0; + /* Compute highest overall time to know if hours should be displayed */ + for (unsigned int kart_id = 0; kart_id < num_karts; kart_id++) + { + max_time = std::max(RaceManager::get()->getOverallTime(kart_id), max_time); + } - for (unsigned int kart_id = 0; kart_id < num_karts; kart_id++) + for (unsigned int kart_id = 0; kart_id < num_karts; kart_id++) + { + int rank = RaceManager::get()->getKartGPRank(kart_id); + // In case of FTL mode: ignore the leader + if (rank < 0) continue; + old_rank[kart_id] = rank; + const AbstractKart *kart = World::getWorld()->getKart(kart_id); + RowInfo *ri = &(m_all_row_infos[rank]); + ri->m_kart_icon = + kart->getKartProperties()->getIconMaterial()->getTexture(); + ri->m_is_player_kart = kart->getController()->isLocalPlayerController(); + ri->m_kart_name = kart->getController()->getName(); + if (RaceManager::get()->getKartGlobalPlayerId(kart->getWorldKartId()) > -1) { - int rank = RaceManager::get()->getKartGPRank(kart_id); - // In case of FTL mode: ignore the leader - if (rank < 0) continue; - old_rank[kart_id] = rank; - const AbstractKart *kart = World::getWorld()->getKart(kart_id); - RowInfo *ri = &(m_all_row_infos[rank]); - ri->m_kart_icon = - kart->getKartProperties()->getIconMaterial()->getTexture(); - ri->m_is_player_kart = kart->getController()->isLocalPlayerController(); - ri->m_kart_name = kart->getController()->getName(); - if (RaceManager::get()->getKartGlobalPlayerId(kart->getWorldKartId()) > -1) - { - const core::stringw& flag = StringUtils::getCountryFlag( - RaceManager::get()->getKartInfo(kart->getWorldKartId()).getCountryCode()); - if (!flag.empty()) - { - ri->m_kart_name += L" "; - ri->m_kart_name += flag; - } - } - ri->m_kart_color = RaceManager::get()->getKartColor(kart_id); - // In FTL karts do have a time, which is shown even when the kart - // is eliminated - if (kart->isEliminated() && !(RaceManager::get()->isFollowMode())) - { - ri->m_finish_time_string = core::stringw(_("Eliminated")); - } - else - { - float time = RaceManager::get()->getOverallTime(kart_id); - ri->m_finish_time_string - = StringUtils::timeToString(time, time_precision, true, /*display hours*/ (max_time > 3599.99f)).c_str(); - } - ri->m_start_at = m_time_between_rows * rank; - ri->m_x_pos = (float)UserConfigParams::m_width; - ri->m_y_pos = (float)(m_top + rank*m_distance_between_rows); - int p = RaceManager::get()->getKartPrevScore(kart_id); - ri->m_current_displayed_points = (float)p; - if (kart->isEliminated() && !(RaceManager::get()->isFollowMode())) - { - ri->m_new_points = 0; - } - else + const core::stringw& flag = StringUtils::getCountryFlag( + RaceManager::get()->getKartInfo(kart->getWorldKartId()).getCountryCode()); + if (!flag.empty()) { - WorldWithRank *wwr = dynamic_cast(World::getWorld()); - assert(wwr); - ri->m_new_points = - (float)wwr->getScoreForPosition(kart->getPosition()); + ri->m_kart_name += L" "; + ri->m_kart_name += flag; } } - - // Now update the GP ranks, and determine the new position - // ------------------------------------------------------- - RaceManager::get()->computeGPRanks(); - m_gp_position_was_changed = false; - for (unsigned int i = 0; i < num_karts; i++) + ri->m_kart_color = RaceManager::get()->getKartColor(kart_id); + // In FTL karts do have a time, which is shown even when the kart + // is eliminated + if (kart->isEliminated() && !(RaceManager::get()->isFollowMode())) { - int j = old_rank[i]; - int gp_position = RaceManager::get()->getKartGPRank(i); - m_gp_position_was_changed |= j != gp_position; - RowInfo *ri = &(m_all_row_infos[j]); - ri->m_radius = (j - gp_position)*(int)m_distance_between_rows*0.5f; - ri->m_centre_point = m_top + (gp_position + j)*m_distance_between_rows*0.5f; - int p = RaceManager::get()->getKartScore(i); - ri->m_new_overall_points = p; - ri->m_new_gp_rank = gp_position; - ri->m_laps = World::getWorld()->getFinishedLapsOfKart(i); - } // i < num_karts -#endif - } // determineGPLayout - - //----------------------------------------------------------------------------- - /** Displays the race results for a single kart. - * \param n Index of the kart to be displayed. - * \param display_points True if GP points should be displayed, too - */ - void RaceResultGUI::displayOneEntry(unsigned int x, unsigned int y, - unsigned int n, bool display_points) - { -#ifndef SERVER_ONLY - RowInfo *ri = &(m_all_row_infos[n]); - video::SColor color = ri->m_is_player_kart - ? video::SColor(255, 255, 0, 0) - : video::SColor(255, 255, 255, 255); - - unsigned int current_x = x; - - // Draw rank order - // (only when num. of karts >=10 ) - if (RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_FREE_FOR_ALL && - !ri->m_finish_time_string.empty() && - RaceManager::get()->getNumberOfKarts() >= 10) - { - int rankNo = ( - RaceManager::get()->getMajorMode()==RaceManager::MAJOR_MODE_GRAND_PRIX && - m_animation_state >= RR_RESORT_TABLE - ? ri->m_new_gp_rank - : n - ) + 1; - - int pos_rank_width = m_font->getDimension(core::stringw(rankNo).c_str()).Width; - core::recti pos_rank(current_x, y, pos_rank_width, m_distance_between_rows); - m_font->draw(core::stringw(rankNo), pos_rank, color); - current_x += 48; - } - - // Draw kart color circle if kart has custom color - if (m_icons_frame && ri->m_kart_color > 0.0) - { - const video::SColorHSL kart_colorHSL(ri->m_kart_color * 360.0, 80.0, 50.0); - video::SColorf kart_colorf; - kart_colorHSL.toRGB(kart_colorf); - const video::SColor kart_color = kart_colorf.toSColor(); - const video::SColor colors[4] = {kart_color, kart_color, kart_color, kart_color}; - const core::recti source_rect(core::vector2di(0, 0), m_icons_frame->getSize()); - // make frame bigger than icon to make color visible for all cases - const int extra_width = std::max((unsigned int)5, m_width_icon / 8); - core::recti dest_rect(current_x - extra_width, y - extra_width, - current_x + m_width_icon + extra_width, y + m_width_icon + extra_width); - draw2DImage(m_icons_frame, dest_rect, source_rect, NULL, colors, true); - } - // First draw the icon - // ------------------- - if (ri->m_kart_icon) + ri->m_finish_time_string = core::stringw(_("Eliminated")); + } + else { - core::recti source_rect(core::vector2di(0, 0), - ri->m_kart_icon->getSize()); - core::recti dest_rect(current_x, y, - current_x + m_width_icon, y + m_width_icon); - draw2DImage(ri->m_kart_icon, dest_rect, - source_rect, NULL, NULL, - true); + float time = RaceManager::get()->getOverallTime(kart_id); + ri->m_finish_time_string + = StringUtils::timeToString(time, time_precision, true, /*display hours*/ (max_time > 3599.99f)).c_str(); } - - current_x += m_width_icon + m_width_column_space; - - // Draw the name - // ------------- - - core::recti pos_name(current_x, y, - current_x + m_width_kart_name, y + m_distance_between_rows); - m_font->draw(ri->m_kart_name, pos_name, color, false, false, NULL, - true /* ignoreRTL */); - current_x += m_width_kart_name + m_width_column_space; - - if (RaceManager::get()->isLapTrialMode()) + ri->m_start_at = m_time_between_rows * rank; + ri->m_x_pos = (float)UserConfigParams::m_width; + ri->m_y_pos = (float)(m_top + rank*m_distance_between_rows); + int p = RaceManager::get()->getKartPrevScore(kart_id); + ri->m_current_displayed_points = (float)p; + if (kart->isEliminated() && !(RaceManager::get()->isFollowMode())) { - core::recti pos_laps = core::recti(current_x, y, current_x + 100, y + 10); - m_font->draw(irr::core::stringw(ri->m_laps), pos_laps, color, false, false, - NULL, true /* ignoreRTL */); + ri->m_new_points = 0; } else { - core::recti dest_rect = core::recti(current_x, y, current_x + 100, y + 10); - m_font->draw(ri->m_finish_time_string, dest_rect, color, false, false, - NULL, true /* ignoreRTL */); - current_x += m_width_finish_time + m_width_column_space; + WorldWithRank *wwr = dynamic_cast(World::getWorld()); + assert(wwr); + ri->m_new_points = + (float)wwr->getScoreForPosition(kart->getPosition()); } - + } + + // Now update the GP ranks, and determine the new position + // ------------------------------------------------------- + RaceManager::get()->computeGPRanks(); + m_gp_position_was_changed = false; + for (unsigned int i = 0; i < num_karts; i++) + { + int j = old_rank[i]; + int gp_position = RaceManager::get()->getKartGPRank(i); + m_gp_position_was_changed |= j != gp_position; + RowInfo *ri = &(m_all_row_infos[j]); + ri->m_radius = (j - gp_position)*(int)m_distance_between_rows*0.5f; + ri->m_centre_point = m_top + (gp_position + j)*m_distance_between_rows*0.5f; + int p = RaceManager::get()->getKartScore(i); + ri->m_new_overall_points = p; + ri->m_new_gp_rank = gp_position; + ri->m_laps = World::getWorld()->getFinishedLapsOfKart(i); + } // i < num_karts +#endif +} // determineGPLayout + +//----------------------------------------------------------------------------- +/** Displays the race results for a single kart. + * \param n Index of the kart to be displayed. + * \param display_points True if GP points should be displayed, too + */ +void RaceResultGUI::displayOneEntry(unsigned int x, unsigned int y, + unsigned int n, bool display_points) +{ +#ifndef SERVER_ONLY + RowInfo *ri = &(m_all_row_infos[n]); + video::SColor color = ri->m_is_player_kart + ? video::SColor(255, 255, 0, 0) + : video::SColor(255, 255, 255, 255); + + unsigned int current_x = x; + + // Draw rank order + // (only when num. of karts >=10 ) + if (RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_FREE_FOR_ALL && + !ri->m_finish_time_string.empty() && + RaceManager::get()->getNumberOfKarts() >= 10) + { + int rankNo = ( + RaceManager::get()->getMajorMode()==RaceManager::MAJOR_MODE_GRAND_PRIX && + m_animation_state >= RR_RESORT_TABLE + ? ri->m_new_gp_rank + : n + ) + 1; + + int pos_rank_width = m_font->getDimension(core::stringw(rankNo).c_str()).Width; + core::recti pos_rank(current_x, y, pos_rank_width, m_distance_between_rows); + m_font->draw(core::stringw(rankNo), pos_rank, color); + current_x += 48; + } + + // Draw kart color circle if kart has custom color + if (m_icons_frame && ri->m_kart_color > 0.0) + { + const video::SColorHSL kart_colorHSL(ri->m_kart_color * 360.0, 80.0, 50.0); + video::SColorf kart_colorf; + kart_colorHSL.toRGB(kart_colorf); + const video::SColor kart_color = kart_colorf.toSColor(); + const video::SColor colors[4] = {kart_color, kart_color, kart_color, kart_color}; + const core::recti source_rect(core::vector2di(0, 0), m_icons_frame->getSize()); + // make frame bigger than icon to make color visible for all cases + const int extra_width = std::max((unsigned int)5, m_width_icon / 8); + core::recti dest_rect(current_x - extra_width, y - extra_width, + current_x + m_width_icon + extra_width, y + m_width_icon + extra_width); + draw2DImage(m_icons_frame, dest_rect, source_rect, NULL, colors, true); + } + // First draw the icon + // ------------------- + if (ri->m_kart_icon) + { + core::recti source_rect(core::vector2di(0, 0), + ri->m_kart_icon->getSize()); + core::recti dest_rect(current_x, y, + current_x + m_width_icon, y + m_width_icon); + draw2DImage(ri->m_kart_icon, dest_rect, + source_rect, NULL, NULL, + true); + } + + current_x += m_width_icon + m_width_column_space; + + // Draw the name + // ------------- - current_x += 100 + m_width_column_space; + core::recti pos_name(current_x, y, + current_x + m_width_kart_name, y + m_distance_between_rows); + m_font->draw(ri->m_kart_name, pos_name, color, false, false, NULL, + true /* ignoreRTL */); + current_x += m_width_kart_name + m_width_column_space; - // Only display points in GP mode and when the GP results are displayed. - // ===================================================================== - if (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX && - m_animation_state != RR_RACE_RESULT && - m_animation_state != RR_WAITING_GP_RESULT) + if (RaceManager::get()->isLapTrialMode()) + { + core::recti pos_laps = core::recti(current_x, y, current_x + 100, y + 10); + m_font->draw(irr::core::stringw(ri->m_laps), pos_laps, color, false, false, + NULL, true /* ignoreRTL */); + } + else + { + core::recti dest_rect = core::recti(current_x, y, current_x + 100, y + 10); + m_font->draw(ri->m_finish_time_string, dest_rect, color, false, false, + NULL, true /* ignoreRTL */); + current_x += m_width_finish_time + m_width_column_space; + } + + + current_x += 100 + m_width_column_space; + + // Only display points in GP mode and when the GP results are displayed. + // ===================================================================== + if (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX && + m_animation_state != RR_RACE_RESULT && + m_animation_state != RR_WAITING_GP_RESULT) + { + // Draw the new points + // ------------------- + if (ri->m_new_points > 0) { - // Draw the new points - // ------------------- - if (ri->m_new_points > 0) - { - core::recti dest_rect = core::recti(current_x, y, - current_x + 100, y + 10); - core::stringw point_string = core::stringw("+") - + core::stringw((int)ri->m_new_points); - // With mono-space digits space has the same width as each digit, - // so we can simply fill up the string with spaces to get the - // right aligned. - while (point_string.size() < 3) - point_string = core::stringw(" ") + point_string; - m_font->draw(point_string, dest_rect, color, false, false, NULL, - true /* ignoreRTL */); - } - current_x += m_width_new_points + m_width_column_space; - - // Draw the old_points plus increase value - // --------------------------------------- - core::recti dest_rect = core::recti(current_x, y, current_x + 100, y + 10); - core::stringw point_inc_string = - core::stringw((int)(ri->m_current_displayed_points)); - while (point_inc_string.size() < 3) - point_inc_string = core::stringw(" ") + point_inc_string; - m_font->draw(point_inc_string, dest_rect, color, false, false, NULL, + core::recti dest_rect = core::recti(current_x, y, + current_x + 100, y + 10); + core::stringw point_string = core::stringw("+") + + core::stringw((int)ri->m_new_points); + // With mono-space digits space has the same width as each digit, + // so we can simply fill up the string with spaces to get the + // right aligned. + while (point_string.size() < 3) + point_string = core::stringw(" ") + point_string; + m_font->draw(point_string, dest_rect, color, false, false, NULL, true /* ignoreRTL */); } + current_x += m_width_new_points + m_width_column_space; + + // Draw the old_points plus increase value + // --------------------------------------- + core::recti dest_rect = core::recti(current_x, y, current_x + 100, y + 10); + core::stringw point_inc_string = + core::stringw((int)(ri->m_current_displayed_points)); + while (point_inc_string.size() < 3) + point_inc_string = core::stringw(" ") + point_inc_string; + m_font->draw(point_inc_string, dest_rect, color, false, false, NULL, + true /* ignoreRTL */); + } #endif - } // displayOneEntry +} // displayOneEntry + +//----------------------------------------------------------------------------- +void RaceResultGUI::displaySoccerResults() +{ +#ifndef SERVER_ONLY + //Draw win text + core::stringw result_text; + static video::SColor color = video::SColor(255, 255, 255, 255); + gui::IGUIFont* font = GUIEngine::getTitleFont(); + int team_icon_height = font->getDimension(L"A").Height * 1.5f; // the size of team icon + int current_x = UserConfigParams::m_width / 2; + RowInfo *ri = &(m_all_row_infos[0]); + int current_y = (int)ri->m_y_pos; + SoccerWorld* sw = (SoccerWorld*)World::getWorld(); + const int red_score = sw->getScore(KART_TEAM_RED); + const int blue_score = sw->getScore(KART_TEAM_BLUE); + + GUIEngine::Widget *table_area = getWidget("result-table"); + int height = table_area->m_h + table_area->m_y; + + if (red_score > blue_score) + result_text = _("Red Team Wins"); + else if (blue_score > red_score) + result_text = _("Blue Team Wins"); + else //Cannot really happen now. Only in time limited matches. + result_text = _("It's a draw"); + + core::rect pos(current_x, current_y, current_x, current_y); + font->draw(result_text.c_str(), pos, color, true, true); + + core::dimension2du rect = font->getDimension(result_text.c_str()); + + //Draw team scores: + current_y += rect.Height; + current_x /= 2; + irr::video::ITexture* red_icon = irr_driver->getTexture(FileManager::GUI_ICON, + "soccer_ball_red.png"); + irr::video::ITexture* blue_icon = irr_driver->getTexture(FileManager::GUI_ICON, + "soccer_ball_blue.png"); + + int team_icon_width = team_icon_height * (red_icon->getSize().Width / red_icon->getSize().Height); + core::recti source_rect(core::vector2di(0, 0), red_icon->getSize()); + current_x -= team_icon_width/2; + core::recti dest_rect(current_x, current_y, current_x + team_icon_width, + current_y + team_icon_height); + draw2DImage(red_icon, dest_rect, source_rect, + NULL, NULL, true); + current_x += UserConfigParams::m_width / 2; + dest_rect = core::recti(current_x, current_y, current_x + team_icon_width, + current_y + team_icon_height); + draw2DImage(blue_icon, dest_rect, source_rect, + NULL, NULL, true); + + result_text = StringUtils::toWString(blue_score); + rect = font->getDimension(result_text.c_str()); + current_x += team_icon_height / 2; + current_y += team_icon_height + rect.Height / 4; + pos = core::rect(current_x, current_y, current_x, current_y); + font->draw(result_text.c_str(), pos, color, true, false); + + current_x -= UserConfigParams::m_width / 2; + result_text = StringUtils::toWString(red_score); + pos = core::rect(current_x, current_y, current_x, current_y); + font->draw(result_text.c_str(), pos, color, true, false); + + int center_x = UserConfigParams::m_width / 2; + pos = core::rect(center_x, current_y, center_x, current_y); + font->draw("-", pos, color, true, false); + + //Draw goal scorers: + //The red scorers: + current_y += rect.Height / 2 + rect.Height / 4; + font = GUIEngine::getSmallFont(); + std::vector scorers = sw->getScorers(KART_TEAM_RED); + + // Maximum 10 scorers displayed in result screen + while (scorers.size() > 10) + { + scorers.erase(scorers.begin()); + } - //----------------------------------------------------------------------------- - void RaceResultGUI::displaySoccerResults() + int prev_y = current_y; + + for (unsigned int i = 0; i < scorers.size(); i++) { -#ifndef SERVER_ONLY - //Draw win text - core::stringw result_text; - static video::SColor color = video::SColor(255, 255, 255, 255); - gui::IGUIFont* font = GUIEngine::getTitleFont(); - int team_icon_height = font->getDimension(L"A").Height * 1.5f; // the size of team icon - int current_x = UserConfigParams::m_width / 2; - RowInfo *ri = &(m_all_row_infos[0]); - int current_y = (int)ri->m_y_pos; - SoccerWorld* sw = (SoccerWorld*)World::getWorld(); - const int red_score = sw->getScore(KART_TEAM_RED); - const int blue_score = sw->getScore(KART_TEAM_BLUE); + const bool own_goal = !(scorers.at(i).m_correct_goal); - GUIEngine::Widget *table_area = getWidget("result-table"); - int height = table_area->m_h + table_area->m_y; + result_text = scorers.at(i).m_player; + if (scorers.at(i).m_handicap_level == HANDICAP_MEDIUM) + result_text = _("%s (handicapped)", result_text); - if (red_score > blue_score) - { - result_text = _("Red Team Wins"); - } - else if (blue_score > red_score) + if (own_goal) { - result_text = _("Blue Team Wins"); + result_text.append(" "); + //I18N: indicates a player that scored in their own goal in result screen + result_text.append(_("(Own Goal)")); } - else + if (!scorers.at(i).m_country_code.empty()) { - //Cannot really happen now. Only in time limited matches. - result_text = _("It's a draw"); + result_text += " "; + result_text += StringUtils::getCountryFlag(scorers.at(i).m_country_code); } - core::rect pos(current_x, current_y, current_x, current_y); - font->draw(result_text.c_str(), pos, color, true, true); - core::dimension2du rect = font->getDimension(result_text.c_str()); - - //Draw team scores: - current_y += rect.Height; - current_x /= 2; - irr::video::ITexture* red_icon = irr_driver->getTexture(FileManager::GUI_ICON, - "soccer_ball_red.png"); - irr::video::ITexture* blue_icon = irr_driver->getTexture(FileManager::GUI_ICON, - "soccer_ball_blue.png"); - - int team_icon_width = team_icon_height * (red_icon->getSize().Width / red_icon->getSize().Height); - core::recti source_rect(core::vector2di(0, 0), red_icon->getSize()); - current_x -= team_icon_width/2; - core::recti dest_rect(current_x, current_y, current_x + team_icon_width, - current_y + team_icon_height); - draw2DImage(red_icon, dest_rect, source_rect, - NULL, NULL, true); - current_x += UserConfigParams::m_width / 2; - dest_rect = core::recti(current_x, current_y, current_x + team_icon_width, - current_y + team_icon_height); - draw2DImage(blue_icon, dest_rect, source_rect, - NULL, NULL, true); - - result_text = StringUtils::toWString(blue_score); + result_text.append(" "); + result_text.append(StringUtils::timeToString(scorers.at(i).m_time).c_str()); rect = font->getDimension(result_text.c_str()); - current_x += team_icon_height / 2; - current_y += team_icon_height + rect.Height / 4; - pos = core::rect(current_x, current_y, current_x, current_y); - font->draw(result_text.c_str(), pos, color, true, false); - - current_x -= UserConfigParams::m_width / 2; - result_text = StringUtils::toWString(red_score); - pos = core::rect(current_x, current_y, current_x, current_y); - font->draw(result_text.c_str(), pos, color, true, false); - int center_x = UserConfigParams::m_width / 2; - pos = core::rect(center_x, current_y, center_x, current_y); - font->draw("-", pos, color, true, false); + if (height - prev_y < ((short)scorers.size() + 1)*(short)rect.Height) + current_y += (height - prev_y) / ((short)scorers.size() + 1); + else + current_y += rect.Height; - //Draw goal scorers: - //The red scorers: - current_y += rect.Height / 2 + rect.Height / 4; - font = GUIEngine::getSmallFont(); - std::vector scorers = sw->getScorers(KART_TEAM_RED); + if (current_y > height) break; - // Maximum 10 scorers displayed in result screen - while (scorers.size() > 10) + pos = core::rect(current_x, current_y, current_x, current_y); + font->draw(result_text, pos, (own_goal ? + video::SColor(255, 255, 0, 0) : color), true, false); + irr::video::ITexture* scorer_icon = NULL; + const KartProperties* kp = kart_properties_manager->getKart(scorers.at(i).m_kart); + // For addon kart online + if (!kp) + kp = kart_properties_manager->getKart("tux"); + if (kp) + scorer_icon = kp->getIconMaterial()->getTexture(); + if (scorer_icon) { - scorers.erase(scorers.begin()); + source_rect = core::recti(core::vector2di(0, 0), scorer_icon->getSize()); + irr::u32 offset_x = (irr::u32)(font->getDimension(result_text.c_str()).Width / 1.5f); + core::recti r = core::recti(current_x - offset_x - m_width_icon, current_y, + current_x - offset_x, current_y + m_width_icon); + draw2DImage(scorer_icon, r, source_rect, + NULL, NULL, true); } + } - int prev_y = current_y; - - for (unsigned int i = 0; i < scorers.size(); i++) - { - const bool own_goal = !(scorers.at(i).m_correct_goal); - - result_text = scorers.at(i).m_player; - if (scorers.at(i).m_handicap_level == HANDICAP_MEDIUM) - result_text = _("%s (handicapped)", result_text); - - if (own_goal) - { - result_text.append(" "); - //I18N: indicates a player that scored in their own goal in result screen - result_text.append(_("(Own Goal)")); - } - if (!scorers.at(i).m_country_code.empty()) - { - result_text += " "; - result_text += StringUtils::getCountryFlag(scorers.at(i).m_country_code); - } + //The blue scorers: + current_y = prev_y; + current_x += UserConfigParams::m_width / 2; + scorers = sw->getScorers(KART_TEAM_BLUE); - result_text.append(" "); - result_text.append(StringUtils::timeToString(scorers.at(i).m_time).c_str()); - rect = font->getDimension(result_text.c_str()); + while (scorers.size() > 10) + { + scorers.erase(scorers.begin()); + } - if (height - prev_y < ((short)scorers.size() + 1)*(short)rect.Height) - current_y += (height - prev_y) / ((short)scorers.size() + 1); - else - current_y += rect.Height; - - if (current_y > height) break; - - pos = core::rect(current_x, current_y, current_x, current_y); - font->draw(result_text, pos, (own_goal ? - video::SColor(255, 255, 0, 0) : color), true, false); - irr::video::ITexture* scorer_icon = NULL; - const KartProperties* kp = kart_properties_manager->getKart(scorers.at(i).m_kart); - // For addon kart online - if (!kp) - kp = kart_properties_manager->getKart("tux"); - if (kp) - scorer_icon = kp->getIconMaterial()->getTexture(); - if (scorer_icon) - { - source_rect = core::recti(core::vector2di(0, 0), scorer_icon->getSize()); - irr::u32 offset_x = (irr::u32)(font->getDimension(result_text.c_str()).Width / 1.5f); - core::recti r = core::recti(current_x - offset_x - m_width_icon, current_y, - current_x - offset_x, current_y + m_width_icon); - draw2DImage(scorer_icon, r, source_rect, - NULL, NULL, true); - } - } + for (unsigned int i = 0; i < scorers.size(); i++) + { + const bool own_goal = !(scorers.at(i).m_correct_goal); - //The blue scorers: - current_y = prev_y; - current_x += UserConfigParams::m_width / 2; - scorers = sw->getScorers(KART_TEAM_BLUE); + result_text = scorers.at(i).m_player; + if (scorers.at(i).m_handicap_level == HANDICAP_MEDIUM) + result_text = _("%s (handicapped)", result_text); - while (scorers.size() > 10) + if (own_goal) { - scorers.erase(scorers.begin()); + result_text.append(" "); + //I18N: indicates a player that scored in their own goal in result screen + result_text.append(_("(Own Goal)")); } - - for (unsigned int i = 0; i < scorers.size(); i++) + if (!scorers.at(i).m_country_code.empty()) { - const bool own_goal = !(scorers.at(i).m_correct_goal); + result_text += " "; + result_text += StringUtils::getCountryFlag(scorers.at(i).m_country_code); + } - result_text = scorers.at(i).m_player; - if (scorers.at(i).m_handicap_level == HANDICAP_MEDIUM) - result_text = _("%s (handicapped)", result_text); + result_text.append(" "); + result_text.append(StringUtils::timeToString(scorers.at(i).m_time).c_str()); + rect = font->getDimension(result_text.c_str()); - if (own_goal) - { - result_text.append(" "); - //I18N: indicates a player that scored in their own goal in result screen - result_text.append(_("(Own Goal)")); - } - if (!scorers.at(i).m_country_code.empty()) - { - result_text += " "; - result_text += StringUtils::getCountryFlag(scorers.at(i).m_country_code); - } + if (height - prev_y < ((short)scorers.size() + 1)*(short)rect.Height) + current_y += (height - prev_y) / ((short)scorers.size() + 1); + else + current_y += rect.Height; - result_text.append(" "); - result_text.append(StringUtils::timeToString(scorers.at(i).m_time).c_str()); - rect = font->getDimension(result_text.c_str()); + if (current_y > height) break; - if (height - prev_y < ((short)scorers.size() + 1)*(short)rect.Height) - current_y += (height - prev_y) / ((short)scorers.size() + 1); - else - current_y += rect.Height; - - if (current_y > height) break; - - pos = core::rect(current_x, current_y, current_x, current_y); - font->draw(result_text, pos, (own_goal ? - video::SColor(255, 255, 0, 0) : color), true, false); - irr::video::ITexture* scorer_icon = NULL; - const KartProperties* kp = kart_properties_manager->getKart(scorers.at(i).m_kart); - // For addon kart online - if (!kp) - kp = kart_properties_manager->getKart("tux"); - if (kp) - scorer_icon = kp->getIconMaterial()->getTexture(); - if (scorer_icon) - { - source_rect = core::recti(core::vector2di(0, 0), scorer_icon->getSize()); - irr::u32 offset_x = (irr::u32)(font->getDimension(result_text.c_str()).Width / 1.5f); - core::recti r = core::recti(current_x - offset_x - m_width_icon, current_y, - current_x - offset_x, current_y + m_width_icon); - draw2DImage(scorer_icon, r, source_rect, - NULL, NULL, true); - } + pos = core::rect(current_x, current_y, current_x, current_y); + font->draw(result_text, pos, (own_goal ? + video::SColor(255, 255, 0, 0) : color), true, false); + irr::video::ITexture* scorer_icon = NULL; + const KartProperties* kp = kart_properties_manager->getKart(scorers.at(i).m_kart); + // For addon kart online + if (!kp) + kp = kart_properties_manager->getKart("tux"); + if (kp) + scorer_icon = kp->getIconMaterial()->getTexture(); + if (scorer_icon) + { + source_rect = core::recti(core::vector2di(0, 0), scorer_icon->getSize()); + irr::u32 offset_x = (irr::u32)(font->getDimension(result_text.c_str()).Width / 1.5f); + core::recti r = core::recti(current_x - offset_x - m_width_icon, current_y, + current_x - offset_x, current_y + m_width_icon); + draw2DImage(scorer_icon, r, source_rect, + NULL, NULL, true); } -#endif } +#endif +} // displaySoccerResults - //----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- - void RaceResultGUI::clearHighscores() - { - m_highscore_rank = 0; - } // clearHighscores +void RaceResultGUI::clearHighscores() +{ + m_highscore_rank = 0; +} // clearHighscores - //----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- - void RaceResultGUI::setHighscore(int rank) - { - m_highscore_rank = rank; - } // setHighscore +void RaceResultGUI::setHighscore(int rank) +{ + m_highscore_rank = rank; +} // setHighscore - // ---------------------------------------------------------------------------- - void RaceResultGUI::enableGPProgress() +// ---------------------------------------------------------------------------- +void RaceResultGUI::enableGPProgress() +{ + if (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) { - if (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) - { - GUIEngine::Widget* result_table = getWidget("result-table"); - assert(result_table != NULL); + GUIEngine::Widget* result_table = getWidget("result-table"); + assert(result_table != NULL); - auto wit = m_gp_progress_widgets.begin(); - bool resize = !m_gp_progress_widgets.empty(); - int currentTrack = RaceManager::get()->getTrackNumber(); - int font_height = getFontHeight(); - int w = (int)(UserConfigParams::m_width*0.17); - int x = (int)(result_table->m_x + result_table->m_w - w - 15); - int y = (m_top + font_height + 5); + auto wit = m_gp_progress_widgets.begin(); + bool resize = !m_gp_progress_widgets.empty(); + int currentTrack = RaceManager::get()->getTrackNumber(); + int font_height = getFontHeight(); + int w = (int)(UserConfigParams::m_width*0.17); + int x = (int)(result_table->m_x + result_table->m_w - w - 15); + int y = (m_top + font_height + 5); + + //Current progress + GUIEngine::LabelWidget* status_label = resize ? + static_cast(*wit++) : + new GUIEngine::LabelWidget(); + status_label->m_properties[GUIEngine::PROP_ID] = "status_label"; + status_label->m_properties[GUIEngine::PROP_TEXT_ALIGN] = "center"; + status_label->m_x = x; + status_label->m_y = y; + status_label->m_w = w; + status_label->m_h = font_height; + if (resize) + { + status_label->resize(); + } + else + { + status_label->add(); + status_label->setText(_("Track %i/%i", currentTrack + 1, + RaceManager::get()->getGrandPrix().getNumberOfTracks()), true); + addGPProgressWidget(status_label); + } + y = (status_label->m_y + status_label->m_h + 5); + + //Scroll up button + GUIEngine::IconButtonWidget* up_button = resize ? + static_cast(*wit++) : + new GUIEngine::IconButtonWidget( + GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, + false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); + up_button->m_properties[GUIEngine::PROP_ID] = "up_button"; + up_button->m_x = x; + up_button->m_y = y; + up_button->m_w = w; + up_button->m_h = font_height; + if (resize) + { + up_button->resize(); + } + else + { + up_button->add(); + up_button->setImage(file_manager->getAsset(FileManager::GUI_ICON, "scroll_up.png")); + addGPProgressWidget(up_button); + } + y = (up_button->m_y + up_button->m_h + SSHOT_SEPARATION); - //Current progress - GUIEngine::LabelWidget* status_label = resize ? - static_cast(*wit++) : - new GUIEngine::LabelWidget(); - status_label->m_properties[GUIEngine::PROP_ID] = "status_label"; - status_label->m_properties[GUIEngine::PROP_TEXT_ALIGN] = "center"; - status_label->m_x = x; - status_label->m_y = y; - status_label->m_w = w; - status_label->m_h = font_height; + //Track screenshots and labels + int n_sshot = 1; + for (int i = m_start_track; i < m_end_track; i++) + { + //Screenshot + GUIEngine::IconButtonWidget* screenshot_widget = resize ? + static_cast(*wit++) : + new GUIEngine::IconButtonWidget( + GUIEngine::IconButtonWidget:: + SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, + false, false, + GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); + screenshot_widget->setCustomAspectRatio(4.0f / 3.0f); + screenshot_widget->m_x = x; + screenshot_widget->m_y = y; + screenshot_widget->m_w = w; + screenshot_widget->m_h = m_sshot_height; + screenshot_widget->m_properties[GUIEngine::PROP_ID] = + ("sshot_" + StringUtils::toString(n_sshot)); if (resize) { - status_label->resize(); + screenshot_widget->resize(); } else { - status_label->add(); - status_label->setText(_("Track %i/%i", currentTrack + 1, - RaceManager::get()->getGrandPrix().getNumberOfTracks()), true); - addGPProgressWidget(status_label); + screenshot_widget->add(); + addGPProgressWidget(screenshot_widget); } - y = (status_label->m_y + status_label->m_h + 5); - //Scroll up button - GUIEngine::IconButtonWidget* up_button = resize ? - static_cast(*wit++) : - new GUIEngine::IconButtonWidget( - GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, - false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); - up_button->m_properties[GUIEngine::PROP_ID] = "up_button"; - up_button->m_x = x; - up_button->m_y = y; - up_button->m_w = w; - up_button->m_h = font_height; + //Label + GUIEngine::LabelWidget* sshot_label = resize ? + static_cast(*wit++) : + new GUIEngine::LabelWidget(); + sshot_label->m_properties[GUIEngine::PROP_ID] = + ("sshot_label_" + StringUtils::toString(n_sshot)); + sshot_label->m_properties[GUIEngine::PROP_TEXT_ALIGN] = "left"; + sshot_label->m_x = (x + w + 5); + sshot_label->m_y = (y + (m_sshot_height / 2) - (font_height / 2)); + sshot_label->m_w = (w / 2); + sshot_label->m_h = font_height; if (resize) { - up_button->resize(); + sshot_label->resize(); } else { - up_button->add(); - up_button->setImage(file_manager->getAsset(FileManager::GUI_ICON, "scroll_up.png")); - addGPProgressWidget(up_button); + sshot_label->add(); + addGPProgressWidget(sshot_label); } - y = (up_button->m_y + up_button->m_h + SSHOT_SEPARATION); - //Track screenshots and labels - int n_sshot = 1; - for (int i = m_start_track; i < m_end_track; i++) - { - //Screenshot - GUIEngine::IconButtonWidget* screenshot_widget = resize ? - static_cast(*wit++) : - new GUIEngine::IconButtonWidget( - GUIEngine::IconButtonWidget:: - SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, - false, false, - GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); - screenshot_widget->setCustomAspectRatio(4.0f / 3.0f); - screenshot_widget->m_x = x; - screenshot_widget->m_y = y; - screenshot_widget->m_w = w; - screenshot_widget->m_h = m_sshot_height; - screenshot_widget->m_properties[GUIEngine::PROP_ID] = - ("sshot_" + StringUtils::toString(n_sshot)); - if (resize) - { - screenshot_widget->resize(); - } - else - { - screenshot_widget->add(); - addGPProgressWidget(screenshot_widget); - } + y += (m_sshot_height + SSHOT_SEPARATION); + n_sshot++; + } // for + displayScreenShots(); + + //Scroll down button + GUIEngine::IconButtonWidget* down_button = resize ? + static_cast(*wit++) : + new GUIEngine::IconButtonWidget( + GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, + false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); + down_button->m_properties[GUIEngine::PROP_ID] = "down_button"; + down_button->m_x = x; + down_button->m_y = y; + down_button->m_w = w; + down_button->m_h = font_height; + if (resize) + { + down_button->resize(); + } + else + { + down_button->add(); + down_button->setImage(file_manager->getAsset(FileManager::GUI_ICON, "scroll_down.png")); + addGPProgressWidget(down_button); + } + } // if MAJOR_MODE_GRAND_PRIX) - //Label - GUIEngine::LabelWidget* sshot_label = resize ? - static_cast(*wit++) : - new GUIEngine::LabelWidget(); - sshot_label->m_properties[GUIEngine::PROP_ID] = - ("sshot_label_" + StringUtils::toString(n_sshot)); - sshot_label->m_properties[GUIEngine::PROP_TEXT_ALIGN] = "left"; - sshot_label->m_x = (x + w + 5); - sshot_label->m_y = (y + (m_sshot_height / 2) - (font_height / 2)); - sshot_label->m_w = (w / 2); - sshot_label->m_h = font_height; - if (resize) - { - sshot_label->resize(); - } - else - { - sshot_label->add(); - addGPProgressWidget(sshot_label); - } +} // enableGPProgress - y += (m_sshot_height + SSHOT_SEPARATION); - n_sshot++; - } // for - displayScreenShots(); +// ---------------------------------------------------------------------------- +void RaceResultGUI::addGPProgressWidget(GUIEngine::Widget* widget) +{ + m_widgets.push_back(widget); + m_gp_progress_widgets.push_back(widget); +} // addGPProgressWidget - //Scroll down button - GUIEngine::IconButtonWidget* down_button = resize ? - static_cast(*wit++) : - new GUIEngine::IconButtonWidget( - GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, - false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); - down_button->m_properties[GUIEngine::PROP_ID] = "down_button"; - down_button->m_x = x; - down_button->m_y = y; - down_button->m_w = w; - down_button->m_h = font_height; - if (resize) - { - down_button->resize(); - } - else - { - down_button->add(); - down_button->setImage(file_manager->getAsset(FileManager::GUI_ICON, "scroll_down.png")); - addGPProgressWidget(down_button); - } +// ---------------------------------------------------------------------------- +void RaceResultGUI::displayGPProgress() +{ + core::stringw msg = _("Grand Prix progress:"); - } // if MAJOR_MODE_GRAND_PRIX) + GUIEngine::Widget* result_table = getWidget("result-table"); + assert(result_table != NULL); - } // enableGPProgress + video::SColor color = video::SColor(255, 255, 0, 0); + // 0.96 from stkgui + core::recti dest_rect( + result_table->m_x + result_table->m_w - m_font->getDimension(msg.c_str()).Width - 5, + m_top, UserConfigParams::m_width * 0.96f, + m_top + GUIEngine::getFontHeight()); - // ---------------------------------------------------------------------------- - void RaceResultGUI::addGPProgressWidget(GUIEngine::Widget* widget) - { - m_widgets.push_back(widget); - m_gp_progress_widgets.push_back(widget); - } + m_font->draw(msg, dest_rect, color, false, false, NULL, true); +} // displayGPProgress - // ---------------------------------------------------------------------------- - void RaceResultGUI::displayGPProgress() - { - core::stringw msg = _("Grand Prix progress:"); +// ---------------------------------------------------------------------------- +void RaceResultGUI::cleanupGPProgress() +{ + for (unsigned int i = 0; i < m_gp_progress_widgets.size(); i++) + m_widgets.remove(m_gp_progress_widgets.get(i)); + m_gp_progress_widgets.clearAndDeleteAll(); +} // cleanupGPProgress + +// ---------------------------------------------------------------------------- +/** Manages the display of the post-race info located on the right-side of the + * screen as applicable: highscores, laps, difficulty, best lap, challenge info + * */ +void RaceResultGUI::displayPostRaceInfo() +{ +#ifndef SERVER_ONLY + // This happens in demo world + if (!World::getWorld()) + return; - GUIEngine::Widget* result_table = getWidget("result-table"); - assert(result_table != NULL); + int x = (int)(UserConfigParams::m_width*0.65f); + int y = m_top; - video::SColor color = video::SColor(255, 255, 0, 0); - // 0.96 from stkgui - core::recti dest_rect( - result_table->m_x + result_table->m_w - m_font->getDimension(msg.c_str()).Width - 5, - m_top, UserConfigParams::m_width * 0.96f, - m_top + GUIEngine::getFontHeight()); + if (RaceManager::get()->isBenchmarking()) + return; - m_font->draw(msg, dest_rect, color, false, false, NULL, true); - } // displayGPProgress + int current_y = displayHighscores(x, y); - // ---------------------------------------------------------------------------- - void RaceResultGUI::cleanupGPProgress() - { - for (unsigned int i = 0; i < m_gp_progress_widgets.size(); i++) - m_widgets.remove(m_gp_progress_widgets.get(i)); - m_gp_progress_widgets.clearAndDeleteAll(); - } // cleanupGPProgress + // Display the number of laps, difficulty, and the best lap time if applicable + if (!RaceManager::get()->isSoccerMode()) + current_y = displayLapDifficulty(x, current_y); - // ---------------------------------------------------------------------------- - void RaceResultGUI::displayPostRaceInfo() - { + // Display challenge result and goals + if (RaceManager::get()->raceWasStartedFromOverworld()) + current_y = displayChallengeInfo(x, current_y); +#endif +} // displayPostRaceInfo + +//----------------------------------------------------------------------------- +/** Displays the highscores, if applicable for this game mode. Returns the + * bottom limit of the highscore display area, so that other elements can + * be properly positioned vertically. + * \param x Left limit of the highscore display area + * \param y Top limit of the highscore display area */ +int RaceResultGUI::displayHighscores(int x, int y) +{ #ifndef SERVER_ONLY - // This happens in demo world - if (!World::getWorld()) - return; + Highscores* scores = World::getWorld()->getHighscores(); - Highscores* scores = World::getWorld()->getHighscores(); + // In some case, for example FTL, there will be no highscores + if (scores == NULL) + return y; - video::SColor white_color = video::SColor(255, 255, 255, 255); + video::SColor white_color = video::SColor(255, 255, 255, 255); + int current_y = y; + int time_precision = RaceManager::get()->currentModeTimePrecision(); - int x = (int)(UserConfigParams::m_width*0.65f); - int y = m_top; + // First draw title + GUIEngine::getFont()->draw(_("Highscores"), + // 0.96 from stkgui + core::recti(x, y, UserConfigParams::m_width * 0.96f, y + GUIEngine::getFontHeight()), + white_color, false, false, NULL, true /* ignoreRTL */); - int current_y = y; + std::string kart_name; + irr::core::stringw player_name; - int time_precision = RaceManager::get()->currentModeTimePrecision(); + // prevent excessive long name + unsigned int max_characters = 15; + unsigned int max_width = (UserConfigParams::m_width / 2 - 200) / 10; + if (max_width < 15) + max_characters = max_width; - // In some case for exemple FTL they will be no highscores - if (scores != NULL) + float time; + for (int i = 0; i < scores->getNumberEntries(); i++) + { + scores->getEntry(i, kart_name, player_name, &time); + if (player_name.size() > max_characters) { - // First draw title - GUIEngine::getFont()->draw(_("Highscores"), - // 0.96 from stkgui - core::recti(x, y, UserConfigParams::m_width * 0.96f, y + GUIEngine::getFontHeight()), - white_color, - false, false, NULL, true /* ignoreRTL */); + int begin = (int(m_timer / 0.4f)) % (player_name.size() - max_characters); + player_name = player_name.subString(begin, max_characters, false); + } + + video::SColor text_color = white_color; + if (m_highscore_rank - 1 == i) + { + text_color = video::SColor(255, 255, 0, 0); + } - std::string kart_name; - irr::core::stringw player_name; + int current_x = x; + current_y = y + (int)((i + 1) * m_distance_between_meta_rows); - // prevent excessive long name - unsigned int max_characters = 15; - unsigned int max_width = (UserConfigParams::m_width / 2 - 200) / 10; - if (max_width < 15) - max_characters = max_width; + const KartProperties* prop = kart_properties_manager->getKart(kart_name); + if (prop != NULL) + { + const std::string &icon_path = prop->getAbsoluteIconFile(); + video::ITexture* kart_icon_texture = irr_driver->getTexture(icon_path); - float time; - for (int i = 0; i < scores->getNumberEntries(); i++) + if (kart_icon_texture != NULL) { - scores->getEntry(i, kart_name, player_name, &time); - if (player_name.size() > max_characters) - { - int begin = (int(m_timer / 0.4f)) % (player_name.size() - max_characters); - player_name = player_name.subString(begin, max_characters, false); - } + core::recti source_rect(core::vector2di(0, 0), + kart_icon_texture->getSize()); - video::SColor text_color = white_color; - if (m_highscore_rank - 1 == i) - { - text_color = video::SColor(255, 255, 0, 0); - } + core::recti dest_rect(current_x, current_y, + current_x + m_width_icon, current_y + m_width_icon); - int current_x = x; - current_y = y + (int)((i + 1) * m_distance_between_meta_rows); + draw2DImage(kart_icon_texture, dest_rect, + source_rect, NULL, NULL, true); - const KartProperties* prop = kart_properties_manager->getKart(kart_name); - if (prop != NULL) - { - const std::string &icon_path = prop->getAbsoluteIconFile(); - video::ITexture* kart_icon_texture = irr_driver->getTexture(icon_path); + current_x += m_width_icon + m_width_column_space; + } + } - if (kart_icon_texture != NULL) - { - core::recti source_rect(core::vector2di(0, 0), - kart_icon_texture->getSize()); + // draw the player name + GUIEngine::getSmallFont()->draw(player_name.c_str(), + core::recti(current_x, current_y, current_x + 150, current_y + 10), + text_color, false, false, NULL, true /* ignoreRTL */); - core::recti dest_rect(current_x, current_y, - current_x + m_width_icon, current_y + m_width_icon); + current_x = (int)(UserConfigParams::m_width * 0.85f); - draw2DImage( - kart_icon_texture, dest_rect, - source_rect, NULL, NULL, - true); + // Finally draw the time + std::string highscore_string; + if (RaceManager::get()->isLapTrialMode()) + highscore_string = std::to_string(static_cast(time)); + else + highscore_string = StringUtils::timeToString(time, time_precision); + GUIEngine::getSmallFont()->draw(highscore_string.c_str(), + core::recti(current_x, current_y, current_x + 100, current_y + 10), + text_color, false, false, NULL, true /* ignoreRTL */); + } // for highscore entries - current_x += m_width_icon + m_width_column_space; - } - } + return current_y; +#endif +} // displayHighscores - // draw the player name - GUIEngine::getSmallFont()->draw(player_name.c_str(), - core::recti(current_x, current_y, current_x + 150, current_y + 10), - text_color, - false, false, NULL, true /* ignoreRTL */); +//----------------------------------------------------------------------------- +/** Displays the difficulty, the number of laps and the best lap time, + * if applicable for this game mode. Returns the bottom limit of the display area, + * so that other elements can be properly positioned vertically. + * \param x Left limit of the highscore display area + * \param y Top limit of the highscore display area */ +int RaceResultGUI::displayLapDifficulty(int x, int y) +{ +#ifndef SERVER_ONLY + video::SColor white_color = video::SColor(255, 255, 255, 255); + int current_y = y; + int time_precision = RaceManager::get()->currentModeTimePrecision(); - current_x = (int)(UserConfigParams::m_width * 0.85f); + // display lap count + if (RaceManager::get()->modeHasLaps()) + { + core::stringw laps = _("Laps: %i", RaceManager::get()->getNumLaps()); + current_y += int(m_distance_between_meta_rows * 0.8f * 2); + GUIEngine::getFont()->draw(laps, + // 0.96 from stkgui + core::recti(x, current_y, UserConfigParams::m_width * 0.96f, current_y + GUIEngine::getFontHeight()), + white_color, false, false, nullptr, true); + } - // Finally draw the time - std::string highscore_string; - if (RaceManager::get()->isLapTrialMode()) - highscore_string = std::to_string(static_cast(time)); - else - highscore_string = StringUtils::timeToString(time, time_precision); - GUIEngine::getSmallFont()->draw(highscore_string.c_str(), - core::recti(current_x, current_y, current_x + 100, current_y + 10), - text_color, - false, false, NULL, true /* ignoreRTL */); + // display difficulty + core::stringw difficulty_name = + RaceManager::get()->getDifficultyName(RaceManager::get()->getDifficulty()); + core::stringw difficulty_one; + core::stringw difficulty_two; + core::recti diff_ghost_one, diff_ghost_two; + if (RaceManager::get()->hasGhostKarts() && ReplayPlay::get()->isSecondReplayEnabled()) + { + WorldWithRank* wwr = dynamic_cast(World::getWorld()); + for (unsigned k = 0; k < wwr->getNumKarts(); k++) + { + GhostKart* gk = dynamic_cast(wwr->getKartAtPosition(k + 1)); + if (!gk) + continue; + const ReplayPlay::ReplayData& rd = gk->getReplayData(); + if (difficulty_one.empty()) + { + difficulty_one = RaceManager::get()->getDifficultyName((RaceManager::Difficulty)rd.m_difficulty); + core::dimension2d dim_1 = m_font->getDimension(difficulty_one.c_str()); + RowInfo* ri_1 = &(m_all_row_infos[k]); + diff_ghost_one.UpperLeftCorner.X = ri_1->m_x_pos + m_width_icon + m_width_kart_name + m_width_finish_time + m_width_column_space + 20; + diff_ghost_one.UpperLeftCorner.Y = ri_1->m_y_pos; + diff_ghost_one.LowerRightCorner.X = diff_ghost_one.UpperLeftCorner.X + dim_1.Width; + diff_ghost_one.LowerRightCorner.Y = diff_ghost_one.UpperLeftCorner.Y + dim_1.Height; + } + else if (difficulty_two.empty()) + { + difficulty_two = RaceManager::get()->getDifficultyName((RaceManager::Difficulty)rd.m_difficulty); + core::dimension2d dim_2 = m_font->getDimension(difficulty_two.c_str()); + RowInfo* ri_2 = &(m_all_row_infos[k]); + diff_ghost_two.UpperLeftCorner.X = ri_2->m_x_pos + m_width_icon + m_width_kart_name + m_width_finish_time + m_width_column_space + 20; + diff_ghost_two.UpperLeftCorner.Y = ri_2->m_y_pos; + diff_ghost_two.LowerRightCorner.X = diff_ghost_two.UpperLeftCorner.X + dim_2.Width; + diff_ghost_two.LowerRightCorner.Y = diff_ghost_two.UpperLeftCorner.Y + dim_2.Height; } } + if (difficulty_one != difficulty_two) + difficulty_name = difficulty_one + L" / " + difficulty_two; + else + difficulty_name = difficulty_one; - if (!RaceManager::get()->isSoccerMode()) - { - // display lap count - if (RaceManager::get()->modeHasLaps()) - { - core::stringw laps = _("Laps: %i", RaceManager::get()->getNumLaps()); - current_y += int(m_distance_between_meta_rows * 0.8f * 2); - GUIEngine::getFont()->draw(laps, - // 0.96 from stkgui - core::recti(x, current_y, UserConfigParams::m_width * 0.96f, current_y + GUIEngine::getFontHeight()), - white_color, false, false, nullptr, true); - } - // display difficulty - core::stringw difficulty_name = - RaceManager::get()->getDifficultyName(RaceManager::get()->getDifficulty()); - core::stringw difficulty_one; - core::stringw difficulty_two; - core::recti diff_ghost_one, diff_ghost_two; - if (RaceManager::get()->hasGhostKarts() && ReplayPlay::get()->isSecondReplayEnabled()) - { - WorldWithRank* wwr = dynamic_cast(World::getWorld()); - for (unsigned k = 0; k < wwr->getNumKarts(); k++) - { - GhostKart* gk = dynamic_cast(wwr->getKartAtPosition(k + 1)); - if (!gk) - continue; - const ReplayPlay::ReplayData& rd = gk->getReplayData(); - if (difficulty_one.empty()) - { - difficulty_one = RaceManager::get()->getDifficultyName((RaceManager::Difficulty)rd.m_difficulty); - core::dimension2d dim_1 = m_font->getDimension(difficulty_one.c_str()); - RowInfo* ri_1 = &(m_all_row_infos[k]); - diff_ghost_one.UpperLeftCorner.X = ri_1->m_x_pos + m_width_icon + m_width_kart_name + m_width_finish_time + m_width_column_space + 20; - diff_ghost_one.UpperLeftCorner.Y = ri_1->m_y_pos; - diff_ghost_one.LowerRightCorner.X = diff_ghost_one.UpperLeftCorner.X + dim_1.Width; - diff_ghost_one.LowerRightCorner.Y = diff_ghost_one.UpperLeftCorner.Y + dim_1.Height; - } - else if (difficulty_two.empty()) - { - difficulty_two = RaceManager::get()->getDifficultyName((RaceManager::Difficulty)rd.m_difficulty); - core::dimension2d dim_2 = m_font->getDimension(difficulty_two.c_str()); - RowInfo* ri_2 = &(m_all_row_infos[k]); - diff_ghost_two.UpperLeftCorner.X = ri_2->m_x_pos + m_width_icon + m_width_kart_name + m_width_finish_time + m_width_column_space + 20; - diff_ghost_two.UpperLeftCorner.Y = ri_2->m_y_pos; - diff_ghost_two.LowerRightCorner.X = diff_ghost_two.UpperLeftCorner.X + dim_2.Width; - diff_ghost_two.LowerRightCorner.Y = diff_ghost_two.UpperLeftCorner.Y + dim_2.Height; - } - } - if (difficulty_one != difficulty_two) - difficulty_name = difficulty_one + L" / " + difficulty_two; - else - difficulty_name = difficulty_one; + // Left side difficulty display + m_font->draw(difficulty_one, diff_ghost_one, video::SColor(255, 255, 255, 255), false, false, nullptr, true); + m_font->draw(difficulty_two, diff_ghost_two, video::SColor(255, 255, 255, 255), false, false, nullptr, true); + } + core::stringw difficulty_string = _("Difficulty: %s", difficulty_name); + current_y += int(m_distance_between_meta_rows * 0.8f); + GUIEngine::getFont()->draw(difficulty_string, + // 0.96 from stkgui + core::recti(x, current_y, UserConfigParams::m_width * 0.96f, current_y + GUIEngine::getFontHeight()), + white_color, false, false, nullptr, true); - // Left side difficulty display - m_font->draw(difficulty_one, diff_ghost_one, video::SColor(255, 255, 255, 255), false, false, nullptr, true); - m_font->draw(difficulty_two, diff_ghost_two, video::SColor(255, 255, 255, 255), false, false, nullptr, true); - } - core::stringw difficulty_string = _("Difficulty: %s", difficulty_name); + // show fastest lap + if (RaceManager::get()->modeHasLaps()) + { + float best_lap_time = static_cast(World::getWorld())->getFastestLap(); + // The fastest lap ticks is set to INT_MAX, so the best_lap_time will be + // very high when none has been set yet. + if (best_lap_time <= 3600.0) + { + core::stringw best_lap_string = _("Best lap time: %s", + StringUtils::timeToString(best_lap_time, time_precision).c_str()); current_y += int(m_distance_between_meta_rows * 0.8f); - GUIEngine::getFont()->draw(difficulty_string, + GUIEngine::getFont()->draw(best_lap_string, // 0.96 from stkgui core::recti(x, current_y, UserConfigParams::m_width * 0.96f, current_y + GUIEngine::getFontHeight()), white_color, false, false, nullptr, true); - // show fastest lap - if (RaceManager::get()->modeHasLaps()) - { - float best_lap_time = static_cast(World::getWorld())->getFastestLap(); - // The fastest lap ticks is set to INT_MAX, so the best_lap_time will be - // very high when none has been set yet. - if (best_lap_time <= 3600.0) - { - core::stringw best_lap_string = _("Best lap time: %s", - StringUtils::timeToString(best_lap_time, time_precision).c_str()); - current_y += int(m_distance_between_meta_rows * 0.8f); - GUIEngine::getFont()->draw(best_lap_string, - // 0.96 from stkgui - core::recti(x, current_y, UserConfigParams::m_width * 0.96f, current_y + GUIEngine::getFontHeight()), - white_color, false, false, - nullptr, true); - - core::stringw best_lap_by = dynamic_cast(World::getWorld())->getFastestLapKartName(); - - if (best_lap_by != "") - { - //I18N: is used to indicate who has the bast laptime (best laptime "by kart_name") - core::stringw best_lap_by_string = _("by %s", best_lap_by); - // Make it closer to the above line - current_y += int(GUIEngine::getFontHeight() * 0.8f); - GUIEngine::getFont()->draw(best_lap_by_string, - // 0.96 from stkgui - core::recti(x, current_y, UserConfigParams::m_width * 0.96f, current_y + GUIEngine::getFontHeight()), - white_color, false, false, - nullptr, true); - } - } - } // if mode has laps - } // if not soccer mode - // Display challenge result and goals - bool is_gp = RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX; - if(RaceManager::get()->raceWasStartedFromOverworld() && - (!is_gp || - RaceManager::get()->getTrackNumber() + 1 == RaceManager::get()->getNumOfTracks())) - { - current_y += int(m_distance_between_meta_rows * 0.4f); + core::stringw best_lap_by = dynamic_cast(World::getWorld())->getFastestLapKartName(); - const ChallengeStatus* c_stat = PlayerManager::getCurrentPlayer()->getCurrentChallengeStatus(); - if (!c_stat) - return; - const ChallengeData* c_data = c_stat->getData(); - if (!c_data) - return; - RaceManager::Difficulty difficulty = RaceManager::get()->getDifficulty(); - video::SColor win_color = video::SColor(255, 0, 255, 0); - video::SColor lose_color = video::SColor(255, 255, 0, 0); - video::SColor special_color = video::SColor(255, 0, 255, 255); - AbstractKart* kart = World::getWorld()->getPlayerKart(0); - bool lose_all = false; - bool position_passed = false; - bool time_passed = false; - bool energy_passed = false; - - if (is_gp) - { - // GP has no best while slower - lose_all = true; - if (c_data->isGPFulfilled()) - { - position_passed = true; - time_passed = true; - energy_passed = true; - } - } - else + if (best_lap_by != "") { - if (kart->isEliminated()) - lose_all = true; - position_passed = (kart->getPosition() <= c_data->getMaxPosition(difficulty) && lose_all == false) - || c_data->getMaxPosition(difficulty) == -1; - time_passed = (kart->getFinishTime() <= c_data->getTimeRequirement(difficulty) && lose_all == false) - || c_data->getTimeRequirement(difficulty) <= 0.0f; - energy_passed = (kart->getEnergy() >= c_data->getEnergy(difficulty) && lose_all == false) - || c_data->getEnergy(difficulty) <= 0; + //I18N: is used to indicate who has the bast laptime (best laptime "by kart_name") + core::stringw best_lap_by_string = _("by %s", best_lap_by); + // Make it closer to the above line + current_y += int(GUIEngine::getFontHeight() * 0.8f); + GUIEngine::getFont()->draw(best_lap_by_string, + // 0.96 from stkgui + core::recti(x, current_y, UserConfigParams::m_width * 0.96f, current_y + GUIEngine::getFontHeight()), + white_color, false, false, + nullptr, true); } + } + } // if mode has laps - bool all_passed = position_passed && time_passed && energy_passed; + return current_y; +#endif +} // displayLapDifficulty - core::stringw text_string = all_passed ? _("You completed the challenge!") : _("You failed the challenge!"); - video::SColor text_color = all_passed ? win_color : lose_color; - current_y += int(m_distance_between_meta_rows * 0.8f); - GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, - y + GUIEngine::getFontHeight()), text_color, false, false, nullptr, true); +//----------------------------------------------------------------------------- +/** Displays the result of the challenge and the status of the different + * goals associated with the challenge. Also notify the user if the + * "best while slower" requirements have been met. + * \param x Left limit of the highscore display area + * \param y Top limit of the highscore display area */ +int RaceResultGUI::displayChallengeInfo(int x, int y) +{ +#ifndef SERVER_ONLY + int current_y = y; + bool is_gp = (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX); + + // If this is a GP challenge, challenge info is only displayed after the last race + if (is_gp && RaceManager::get()->getTrackNumber() + 1 != RaceManager::get()->getNumOfTracks()) + return current_y; + + // Display challenge result and goals + current_y += int(m_distance_between_meta_rows * 0.4f); + + const ChallengeStatus* c_stat = PlayerManager::getCurrentPlayer()->getCurrentChallengeStatus(); + if (!c_stat) + return current_y; + const ChallengeData* c_data = c_stat->getData(); + if (!c_data) + return current_y; + RaceManager::Difficulty difficulty = RaceManager::get()->getDifficulty(); + video::SColor win_color = video::SColor(255, 0, 255, 0); + video::SColor lose_color = video::SColor(255, 255, 0, 0); + video::SColor special_color = video::SColor(255, 0, 255, 255); + AbstractKart* kart = World::getWorld()->getPlayerKart(0); + bool lose_all = false; + bool position_passed = false; + bool time_passed = false; + bool energy_passed = false; + + if (is_gp) + { + // GP has no best while slower + lose_all = true; + if (c_data->isGPFulfilled()) + { + position_passed = true; + time_passed = true; + energy_passed = true; + } + } + else + { + if (kart->isEliminated()) + lose_all = true; + position_passed = (kart->getPosition() <= c_data->getMaxPosition(difficulty) && lose_all == false) + || c_data->getMaxPosition(difficulty) == -1; + time_passed = (kart->getFinishTime() <= c_data->getTimeRequirement(difficulty) && lose_all == false) + || c_data->getTimeRequirement(difficulty) <= 0.0f; + energy_passed = (kart->getEnergy() >= c_data->getEnergy(difficulty) && lose_all == false) + || c_data->getEnergy(difficulty) <= 0; + } - current_y += int(m_distance_between_meta_rows * 0.2f); + bool all_passed = position_passed && time_passed && energy_passed; - // Display goals - if (c_data->getMaxPosition(difficulty) != -1) - { - int r = c_data->getMaxPosition(difficulty); - if (c_data->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER) - r --; - - text_string = _("Required Rank: %i", r); - text_color = position_passed ? win_color : lose_color; - current_y += int(m_distance_between_meta_rows * 0.7f); - GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, - y + GUIEngine::getSmallFontHeight()), text_color, false, false, nullptr, true); - } - if (c_data->getTimeRequirement(difficulty) > 0) - { - text_string = _("Required Time: %i", - StringUtils::timeToString(c_data->getTimeRequirement(difficulty)).c_str()); - text_color = time_passed ? win_color : lose_color; - current_y += int(m_distance_between_meta_rows * 0.7f); - GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, - y + GUIEngine::getSmallFontHeight()), text_color, false, false, nullptr, true); - } - if (c_data->getEnergy(difficulty) > 0) - { - int energy = c_data->getEnergy(difficulty); + core::stringw text_string = all_passed ? _("You completed the challenge!") : _("You failed the challenge!"); + video::SColor text_color = all_passed ? win_color : lose_color; + current_y += int(m_distance_between_meta_rows * 0.8f); + GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, + y + GUIEngine::getFontHeight()), text_color, false, false, nullptr, true); - text_string = _("Required Nitro Points: %i", energy); - text_color = energy_passed ? win_color : lose_color; - current_y += int(m_distance_between_meta_rows * 0.7f); - GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, - y + GUIEngine::getSmallFontHeight()), text_color, false, false, nullptr, true); - } + current_y += int(m_distance_between_meta_rows * 0.2f); - if (c_data->isChallengeFulfilled(true) && RaceManager::get()->getDifficulty() != RaceManager::DIFFICULTY_BEST) - { - text_string = _("Reached Requirements of SuperTux"); - text_color = special_color; - current_y += int(m_distance_between_meta_rows * 0.7f); - GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, + // Display goals + if (c_data->getMaxPosition(difficulty) != -1) + { + int r = c_data->getMaxPosition(difficulty); + if (c_data->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER) + r --; + + text_string = _("Required Rank: %i", r); + text_color = position_passed ? win_color : lose_color; + current_y += int(m_distance_between_meta_rows * 0.7f); + GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, y + GUIEngine::getSmallFontHeight()), text_color, false, false, nullptr, true); - } + } + if (c_data->getTimeRequirement(difficulty) > 0) + { + text_string = _("Required Time: %i", + StringUtils::timeToString(c_data->getTimeRequirement(difficulty)).c_str()); + text_color = time_passed ? win_color : lose_color; + current_y += int(m_distance_between_meta_rows * 0.7f); + GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, + y + GUIEngine::getSmallFontHeight()), text_color, false, false, nullptr, true); + } + if (c_data->getEnergy(difficulty) > 0) + { + int energy = c_data->getEnergy(difficulty); - } // if it's a challenge -#endif + text_string = _("Required Nitro Points: %i", energy); + text_color = energy_passed ? win_color : lose_color; + current_y += int(m_distance_between_meta_rows * 0.7f); + GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, + y + GUIEngine::getSmallFontHeight()), text_color, false, false, nullptr, true); } - // ---------------------------------------------------------------------------- - void RaceResultGUI::displayScreenShots() + if (c_data->isChallengeFulfilled(true /*best*/) && RaceManager::get()->getDifficulty() != RaceManager::DIFFICULTY_BEST) { - const std::vector tracks = - RaceManager::get()->getGrandPrix().getTrackNames(); - int currentTrack = RaceManager::get()->getTrackNumber(); - - int n_sshot = 1; - for (int i = m_start_track; i < m_end_track; i++) - { - Track* track = track_manager->getTrack(tracks[i]); - GUIEngine::IconButtonWidget* sshot = getWidget( - ("sshot_" + StringUtils::toString(n_sshot)).c_str()); - GUIEngine::LabelWidget* label = getWidget( - ("sshot_label_" + StringUtils::toString(n_sshot)).c_str()); - assert(sshot != NULL && label != NULL); + text_string = _("Reached Requirements of SuperTux"); + text_color = special_color; + current_y += int(m_distance_between_meta_rows * 0.7f); + GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, + y + GUIEngine::getSmallFontHeight()), text_color, false, false, nullptr, true); + } - // Network grand prix chooses each track 1 by 1 - if (track == NULL) - { - sshot->setImage(file_manager->getAsset(FileManager::GUI_ICON, - "main_help.png")); - } - else - sshot->setImage(track->getScreenshotFile()); - if (i <= currentTrack) - sshot->setBadge(GUIEngine::OK_BADGE); - else - sshot->resetAllBadges(); + return current_y; +#endif +} // displayChallengeInfo - label->setText(StringUtils::toWString(i + 1), true); +// ---------------------------------------------------------------------------- +void RaceResultGUI::displayScreenShots() +{ + const std::vector tracks = RaceManager::get()->getGrandPrix().getTrackNames(); + int currentTrack = RaceManager::get()->getTrackNumber(); - n_sshot++; + int n_sshot = 1; + for (int i = m_start_track; i < m_end_track; i++) + { + Track* track = track_manager->getTrack(tracks[i]); + GUIEngine::IconButtonWidget* sshot = getWidget( + ("sshot_" + StringUtils::toString(n_sshot)).c_str()); + GUIEngine::LabelWidget* label = getWidget( + ("sshot_label_" + StringUtils::toString(n_sshot)).c_str()); + assert(sshot != NULL && label != NULL); + + // Network grand prix chooses each track 1 by 1 + if (track == NULL) + { + sshot->setImage(file_manager->getAsset(FileManager::GUI_ICON, + "main_help.png")); } - } + else + sshot->setImage(track->getScreenshotFile()); + if (i <= currentTrack) + sshot->setBadge(GUIEngine::OK_BADGE); + else + sshot->resetAllBadges(); - // ---------------------------------------------------------------------------- - int RaceResultGUI::getFontHeight() const - { - assert(m_font != NULL); - return m_font->getDimension(L"A").Height; //Could be any capital letter - } + label->setText(StringUtils::toWString(i + 1), true); - // ---------------------------------------------------------------------------- - void RaceResultGUI::onResize() - { - Screen::onResize(); - if (!m_gp_progress_widgets.empty()) - enableGPProgress(); + n_sshot++; } +} // displayScreenShots + +// ---------------------------------------------------------------------------- +int RaceResultGUI::getFontHeight() const +{ + assert(m_font != NULL); + return m_font->getDimension(L"A").Height; //Could be any capital letter +} // getFontHeight + +// ---------------------------------------------------------------------------- +void RaceResultGUI::onResize() +{ + Screen::onResize(); + if (!m_gp_progress_widgets.empty()) + enableGPProgress(); +} // onResize diff --git a/src/states_screens/race_result_gui.hpp b/src/states_screens/race_result_gui.hpp index d6704b1a681..d1ffb5da481 100644 --- a/src/states_screens/race_result_gui.hpp +++ b/src/states_screens/race_result_gui.hpp @@ -206,6 +206,9 @@ class RaceResultGUI : public RaceGUIBase, void addGPProgressWidget(GUIEngine::Widget* widget); void displayGPProgress(); void displayPostRaceInfo(); + int displayHighscores(int x, int y); + int displayLapDifficulty(int x, int y); + int displayChallengeInfo(int x, int y); void displayCTFResults(); void displaySoccerResults(); void displayScreenShots(); From 8fd0a0a09df44fdebecb949bf5f39e8555d639ca Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sat, 4 May 2024 20:19:54 +0200 Subject: [PATCH 360/830] Split the displaySoccerResults function Use a 'drawTeamScorers' function to reduce code duplication and make it easier to understand what's going on. Some minor clean-up has also been done, but more could be done, especially regarding variables that had to be recreated in the new separate function. --- src/states_screens/race_result_gui.cpp | 129 ++++++++----------------- src/states_screens/race_result_gui.hpp | 1 + 2 files changed, 43 insertions(+), 87 deletions(-) diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 0ed9a550844..def432fb619 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -1587,10 +1587,8 @@ void RaceResultGUI::displaySoccerResults() //Draw team scores: current_y += rect.Height; current_x /= 2; - irr::video::ITexture* red_icon = irr_driver->getTexture(FileManager::GUI_ICON, - "soccer_ball_red.png"); - irr::video::ITexture* blue_icon = irr_driver->getTexture(FileManager::GUI_ICON, - "soccer_ball_blue.png"); + irr::video::ITexture* red_icon = irr_driver->getTexture(FileManager::GUI_ICON, "soccer_ball_red.png"); + irr::video::ITexture* blue_icon = irr_driver->getTexture(FileManager::GUI_ICON, "soccer_ball_blue.png"); int team_icon_width = team_icon_height * (red_icon->getSize().Width / red_icon->getSize().Height); core::recti source_rect(core::vector2di(0, 0), red_icon->getSize()); @@ -1621,77 +1619,34 @@ void RaceResultGUI::displaySoccerResults() pos = core::rect(center_x, current_y, center_x, current_y); font->draw("-", pos, color, true, false); - //Draw goal scorers: - //The red scorers: - current_y += rect.Height / 2 + rect.Height / 4; - font = GUIEngine::getSmallFont(); - std::vector scorers = sw->getScorers(KART_TEAM_RED); - - // Maximum 10 scorers displayed in result screen - while (scorers.size() > 10) - { - scorers.erase(scorers.begin()); - } - - int prev_y = current_y; - - for (unsigned int i = 0; i < scorers.size(); i++) - { - const bool own_goal = !(scorers.at(i).m_correct_goal); - - result_text = scorers.at(i).m_player; - if (scorers.at(i).m_handicap_level == HANDICAP_MEDIUM) - result_text = _("%s (handicapped)", result_text); - - if (own_goal) - { - result_text.append(" "); - //I18N: indicates a player that scored in their own goal in result screen - result_text.append(_("(Own Goal)")); - } - if (!scorers.at(i).m_country_code.empty()) - { - result_text += " "; - result_text += StringUtils::getCountryFlag(scorers.at(i).m_country_code); - } - - result_text.append(" "); - result_text.append(StringUtils::timeToString(scorers.at(i).m_time).c_str()); - rect = font->getDimension(result_text.c_str()); - - if (height - prev_y < ((short)scorers.size() + 1)*(short)rect.Height) - current_y += (height - prev_y) / ((short)scorers.size() + 1); - else - current_y += rect.Height; - - if (current_y > height) break; - - pos = core::rect(current_x, current_y, current_x, current_y); - font->draw(result_text, pos, (own_goal ? - video::SColor(255, 255, 0, 0) : color), true, false); - irr::video::ITexture* scorer_icon = NULL; - const KartProperties* kp = kart_properties_manager->getKart(scorers.at(i).m_kart); - // For addon kart online - if (!kp) - kp = kart_properties_manager->getKart("tux"); - if (kp) - scorer_icon = kp->getIconMaterial()->getTexture(); - if (scorer_icon) - { - source_rect = core::recti(core::vector2di(0, 0), scorer_icon->getSize()); - irr::u32 offset_x = (irr::u32)(font->getDimension(result_text.c_str()).Width / 1.5f); - core::recti r = core::recti(current_x - offset_x - m_width_icon, current_y, - current_x - offset_x, current_y + m_width_icon); - draw2DImage(scorer_icon, r, source_rect, - NULL, NULL, true); - } - } + // Draw the scorers for each team + current_y += (3 * rect.Height) / 4; + drawTeamScorers(KART_TEAM_RED, current_x, current_y, height); + drawTeamScorers(KART_TEAM_BLUE, current_x, current_y, height); +#endif +} // displaySoccerResults - //The blue scorers: - current_y = prev_y; - current_x += UserConfigParams::m_width / 2; - scorers = sw->getScorers(KART_TEAM_BLUE); +//----------------------------------------------------------------------------- +/** Displays the goal scorers for a team + * \param team The team for which to draw goal scorers + * \param x Left limit of the scorers lists (both blue and red) + * \param y Top limit of the scorers lists + * \param height Maximum y of the table area (??) */ +void RaceResultGUI::drawTeamScorers(KartTeam team, int x, int y, int height) +{ +#ifndef SERVER_ONLY + int current_x = (team == KART_TEAM_RED) ? x : x + UserConfigParams::m_width / 2; + int current_y = y; + core::rect pos(current_x, current_y, current_x, current_y); + int prev_y = y; + gui::IGUIFont* font = GUIEngine::getSmallFont(); + core::dimension2du rect; // Filled later + core::stringw scorer_text; + static video::SColor color = video::SColor(255, 255, 255, 255); + SoccerWorld* sw = (SoccerWorld*)World::getWorld(); + std::vector scorers = sw->getScorers(team); + // Display a maximum of 10 scorers while (scorers.size() > 10) { scorers.erase(scorers.begin()); @@ -1701,25 +1656,25 @@ void RaceResultGUI::displaySoccerResults() { const bool own_goal = !(scorers.at(i).m_correct_goal); - result_text = scorers.at(i).m_player; + scorer_text = scorers.at(i).m_player; if (scorers.at(i).m_handicap_level == HANDICAP_MEDIUM) - result_text = _("%s (handicapped)", result_text); + scorer_text = _("%s (handicapped)", scorer_text); if (own_goal) { - result_text.append(" "); + scorer_text.append(" "); //I18N: indicates a player that scored in their own goal in result screen - result_text.append(_("(Own Goal)")); + scorer_text.append(_("(Own Goal)")); } if (!scorers.at(i).m_country_code.empty()) { - result_text += " "; - result_text += StringUtils::getCountryFlag(scorers.at(i).m_country_code); + scorer_text += " "; + scorer_text += StringUtils::getCountryFlag(scorers.at(i).m_country_code); } - result_text.append(" "); - result_text.append(StringUtils::timeToString(scorers.at(i).m_time).c_str()); - rect = font->getDimension(result_text.c_str()); + scorer_text.append(" "); + scorer_text.append(StringUtils::timeToString(scorers.at(i).m_time).c_str()); + rect = font->getDimension(scorer_text.c_str()); if (height - prev_y < ((short)scorers.size() + 1)*(short)rect.Height) current_y += (height - prev_y) / ((short)scorers.size() + 1); @@ -1729,7 +1684,7 @@ void RaceResultGUI::displaySoccerResults() if (current_y > height) break; pos = core::rect(current_x, current_y, current_x, current_y); - font->draw(result_text, pos, (own_goal ? + font->draw(scorer_text, pos, (own_goal ? video::SColor(255, 255, 0, 0) : color), true, false); irr::video::ITexture* scorer_icon = NULL; const KartProperties* kp = kart_properties_manager->getKart(scorers.at(i).m_kart); @@ -1740,16 +1695,16 @@ void RaceResultGUI::displaySoccerResults() scorer_icon = kp->getIconMaterial()->getTexture(); if (scorer_icon) { - source_rect = core::recti(core::vector2di(0, 0), scorer_icon->getSize()); - irr::u32 offset_x = (irr::u32)(font->getDimension(result_text.c_str()).Width / 1.5f); + core::recti source_rect = core::recti(core::vector2di(0, 0), scorer_icon->getSize()); + irr::u32 offset_x = (irr::u32)(font->getDimension(scorer_text.c_str()).Width / 1.5f); core::recti r = core::recti(current_x - offset_x - m_width_icon, current_y, current_x - offset_x, current_y + m_width_icon); draw2DImage(scorer_icon, r, source_rect, NULL, NULL, true); } - } + } // for scorers.size() #endif -} // displaySoccerResults +} // drawTeamScorers //----------------------------------------------------------------------------- diff --git a/src/states_screens/race_result_gui.hpp b/src/states_screens/race_result_gui.hpp index d1ffb5da481..e6e0f564212 100644 --- a/src/states_screens/race_result_gui.hpp +++ b/src/states_screens/race_result_gui.hpp @@ -211,6 +211,7 @@ class RaceResultGUI : public RaceGUIBase, int displayChallengeInfo(int x, int y); void displayCTFResults(); void displaySoccerResults(); + void drawTeamScorers(KartTeam team, int x, int y, int height); void displayScreenShots(); int getFontHeight () const; From 0969a173c742dc5562fe01e5bb50c6bbd4c22676 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sat, 4 May 2024 20:26:24 +0200 Subject: [PATCH 361/830] Fix #5069 --- src/states_screens/options/options_screen_video.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/states_screens/options/options_screen_video.cpp b/src/states_screens/options/options_screen_video.cpp index e05d07b153a..6863b4bbefe 100644 --- a/src/states_screens/options/options_screen_video.cpp +++ b/src/states_screens/options/options_screen_video.cpp @@ -354,6 +354,7 @@ void OptionsScreenVideo::init() getWidget("scale_rtts")->setActive(!in_game || GE::getDriver()->getDriverType() == video::EDT_VULKAN); } + getWidget("benchmarkCurrent")->setActive(!in_game); #endif #if defined(MOBILE_STK) || defined(__SWITCH__) From 7d02e57a194f41c0dacdec615074017097166c6a Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 5 May 2024 13:08:35 +0800 Subject: [PATCH 362/830] Avoid resetting FOV which caused issue after resizing cutscene --- src/graphics/camera.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/graphics/camera.cpp b/src/graphics/camera.cpp index 7330c3b7442..2c37711be24 100644 --- a/src/graphics/camera.cpp +++ b/src/graphics/camera.cpp @@ -129,6 +129,16 @@ Camera::Camera(CameraType type, int camera_index, AbstractKart* kart) m_camera = irr_driver->addCameraSceneNode(); m_previous_pv_matrix = core::matrix4(); + if (RaceManager::get()->getNumLocalPlayers() > 1) + { + m_fov = DEGREE_TO_RAD * stk_config->m_camera_fov + [RaceManager::get()->getNumLocalPlayers() - 1]; + } + else + { + m_fov = DEGREE_TO_RAD * UserConfigParams::m_camera_fov; + } + m_camera->setFOV(m_fov); setupCamera(); setKart(kart); m_ambient_light = Track::getCurrentTrack()->getDefaultAmbientColor(); @@ -170,22 +180,10 @@ void Camera::setupCamera() { m_viewport = irr_driver->getSplitscreenWindow(m_index); m_aspect = (float)((float)(m_viewport.getWidth()) / (float)(m_viewport.getHeight())); - m_scaling = core::vector2df( float(irr_driver->getActualScreenSize().Width) / m_viewport.getWidth() , float(irr_driver->getActualScreenSize().Height) / m_viewport.getHeight()); - if (RaceManager::get()->getNumLocalPlayers() > 1) - { - m_fov = DEGREE_TO_RAD * stk_config->m_camera_fov - [RaceManager::get()->getNumLocalPlayers() - 1]; - } - else - { - m_fov = DEGREE_TO_RAD * UserConfigParams::m_camera_fov; - } - - m_camera->setFOV(m_fov); m_camera->setAspectRatio(m_aspect); m_camera->setFarValue(Track::getCurrentTrack()->getCameraFar()); } // setupCamera From 6e2d528b91e167e680754a91089b404293cb5e01 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 5 May 2024 13:18:59 +0800 Subject: [PATCH 363/830] Remove static variable in cutscenes --- src/states_screens/feature_unlocked.cpp | 4 ++-- src/states_screens/grand_prix_win.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/states_screens/feature_unlocked.cpp b/src/states_screens/feature_unlocked.cpp index fafa38ab765..c8ec3260d45 100644 --- a/src/states_screens/feature_unlocked.cpp +++ b/src/states_screens/feature_unlocked.cpp @@ -638,8 +638,8 @@ void FeatureUnlockedCutScene::onUpdate(float dt) assert(m_unlocked_stuff.size() > 0); - static const int w = irr_driver->getFrameSize().Width; - static const int h = irr_driver->getFrameSize().Height; + const int w = irr_driver->getFrameSize().Width; + const int h = irr_driver->getFrameSize().Height; const irr::video::SColor color(255, 255, 255, 255); GUIEngine::getTitleFont()->draw(_("Challenge Completed"), diff --git a/src/states_screens/grand_prix_win.cpp b/src/states_screens/grand_prix_win.cpp index 4301154af51..b14c0db8c89 100644 --- a/src/states_screens/grand_prix_win.cpp +++ b/src/states_screens/grand_prix_win.cpp @@ -316,8 +316,8 @@ void GrandPrixWin::onUpdate(float dt) // ---- title - static const int w = irr_driver->getFrameSize().Width; - static const int h = irr_driver->getFrameSize().Height; + const int w = irr_driver->getFrameSize().Width; + const int h = irr_driver->getFrameSize().Height; const irr::video::SColor color(255, 255, 255, 255); static int test_y = 0; From aba99c22b68ac1fa53b229b600025c71a7dfd26b Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 5 May 2024 13:45:23 +0800 Subject: [PATCH 364/830] Enable new screen resizing code --- .../source/Irrlicht/CIrrDeviceSDL.cpp | 2 +- src/graphics/irr_driver.cpp | 16 ++------ src/guiengine/abstract_state_manager.cpp | 37 ----------------- src/guiengine/abstract_state_manager.hpp | 5 --- src/guiengine/engine.cpp | 16 +++++++- src/guiengine/modaldialog.cpp | 3 -- src/guiengine/modaldialog.hpp | 1 - src/guiengine/screen.cpp | 1 - src/guiengine/screen.hpp | 15 ------- src/modes/world.cpp | 3 -- src/states_screens/main_menu_screen.cpp | 3 -- .../options/options_screen_general.cpp | 4 -- .../options/options_screen_video.cpp | 40 ++++--------------- 13 files changed, 27 insertions(+), 119 deletions(-) diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp b/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp index dd71d0cc54f..d71fce1fcd6 100644 --- a/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp +++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp @@ -437,7 +437,7 @@ bool CIrrDeviceSDL::createWindow() } } - u32 flags = SDL_WINDOW_SHOWN; + u32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; #if !defined(ANDROID) && !defined(__SWITCH__) if (CreationParams.DriverType == video::EDT_OPENGL || CreationParams.DriverType == video::EDT_OGLES2 || diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 0c29bbc2336..7a6d1c20abf 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -805,7 +805,7 @@ void IrrDriver::initDevice() } // This remaps the window, so it has to be done before the clear to avoid flicker - m_device->setResizable(false); + //m_device->setResizable(false); // Immediate clear to black for a nicer user loading experience m_video_driver->beginScene(/*backBuffer clear*/true, /* Z */ false); @@ -2078,14 +2078,11 @@ void IrrDriver::doScreenShot() // ---------------------------------------------------------------------------- void IrrDriver::handleWindowResize() { - bool dialog_exists = GUIEngine::ModalDialog::isADialogActive() || - GUIEngine::ScreenKeyboard::isActive(); - // This will allow main menu auto resize if missed a resize event core::dimension2du current_screen_size = m_video_driver->getCurrentRenderTargetSize(); GUIEngine::Screen* screen = GUIEngine::getCurrentScreen(); - if (screen && screen->isResizable()) + if (screen) { current_screen_size.Width = screen->getWidth(); current_screen_size.Height = screen->getHeight(); @@ -2102,8 +2099,8 @@ void IrrDriver::handleWindowResize() current_screen_size != new_size || screen_orientation_changed) { - // Don't update when dialog is opened or minimized - if (dialog_exists || new_size.getArea() == 0) + // Don't update when minimized + if (new_size.getArea() == 0) return; m_screen_orientation = new_orientation; @@ -2114,11 +2111,6 @@ void IrrDriver::handleWindowResize() UserConfigParams::m_real_height = (unsigned)((float)m_actual_screen_size.Height / m_device->getNativeScaleY()); resizeWindow(); } - // In case reset by opening options in game - if (!dialog_exists && - StateManager::get()->getGameState() == GUIEngine::GAME && - !m_device->isResizable()) - m_device->setResizable(true); } // handleWindowResize // ---------------------------------------------------------------------------- diff --git a/src/guiengine/abstract_state_manager.cpp b/src/guiengine/abstract_state_manager.cpp index 4bf050e5eae..32904d27009 100644 --- a/src/guiengine/abstract_state_manager.cpp +++ b/src/guiengine/abstract_state_manager.cpp @@ -311,40 +311,3 @@ void AbstractStateManager::resetAndSetStack(Screen* screens[]) onTopMostScreenChanged(); } // resetAndSetStack - -// ---------------------------------------------------------------------------- - -void AbstractStateManager::onResize() -{ - // Happens in the first resize in main.cpp - if (m_menu_stack.empty()) - return; - - // In game resizing - if (m_menu_stack[0].first == RACE_STATE_NAME) - { - if (m_menu_stack.size() == 1) - { - clearScreenCache(); - m_menu_stack.emplace_back(RACE_STATE_NAME, (Screen*)NULL); - } - return; - } - - // For some window manager it sends resize event when STK is not focus - // even if the screen is not resizable, prevent it from resizing if wrong - // screen - if (!m_menu_stack.back().second || - !m_menu_stack.back().second->isResizable()) - return; - - std::vector > screen_function; - for (auto& p : m_menu_stack) - screen_function.push_back(p.second->getNewScreenPointer()); - clearScreenCache(); - std::vector new_screen; - for (auto& screen : screen_function) - new_screen.push_back(screen()); - new_screen.push_back(NULL); - resetAndSetStack(new_screen.data()); -} // onResize diff --git a/src/guiengine/abstract_state_manager.hpp b/src/guiengine/abstract_state_manager.hpp index 2a18d2e6170..7952ab4ad36 100644 --- a/src/guiengine/abstract_state_manager.hpp +++ b/src/guiengine/abstract_state_manager.hpp @@ -111,11 +111,6 @@ namespace GUIEngine */ void resetAndSetStack(Screen* screens[]); - /** - * \brief Called when resizing of stk window - */ - void onResize(); - /** * \brief Used in no graphics STK to enter menu screen (when server is * idle state) diff --git a/src/guiengine/engine.cpp b/src/guiengine/engine.cpp index d3818835245..76907f06fac 100644 --- a/src/guiengine/engine.cpp +++ b/src/guiengine/engine.cpp @@ -1240,7 +1240,10 @@ namespace GUIEngine g_small_title_font->getDimension( L"X" ).Height; Private::tiny_title_font_height = g_tiny_title_font->getDimension( L"X" ).Height; - StateManager::get()->onResize(); + if (ScreenKeyboard::isActive()) + ScreenKeyboard::getCurrent()->onResize(); + if (ModalDialog::isADialogActive()) + ModalDialog::getCurrent()->onResize(); } // reloadForNewSize // ----------------------------------------------------------------------- @@ -1283,6 +1286,16 @@ namespace GUIEngine GameState gamestate = g_state_manager->getGameState(); + core::dimension2d screen_size = irr_driver->getFrameSize(); + core::dimension2d cur_screen_size; + if (getCurrentScreen()) + { + cur_screen_size.Width = getCurrentScreen()->getWidth(); + cur_screen_size.Height = getCurrentScreen()->getHeight(); + if (screen_size != cur_screen_size) + getCurrentScreen()->onResize(); + } + // ---- some menus may need updating bool dialog_opened = false; @@ -1372,7 +1385,6 @@ namespace GUIEngine if (gamestate != GAME && !gui_messages.empty()) { - core::dimension2d screen_size = irr_driver->getFrameSize(); const int text_height = getFontHeight() + 20; const int y_from = screen_size.Height - text_height; diff --git a/src/guiengine/modaldialog.cpp b/src/guiengine/modaldialog.cpp index b6560014182..6e9d479eccd 100644 --- a/src/guiengine/modaldialog.cpp +++ b/src/guiengine/modaldialog.cpp @@ -60,8 +60,6 @@ ModalDialog::ModalDialog(const float percentWidth, const float percentHeight, m_percent_width = percentWidth; m_percent_height = percentHeight; m_irrlicht_window = NULL; - m_was_resizable = irr_driver->getDevice()->isResizable(); - irr_driver->getDevice()->setResizable(false); } // ModalDialog // ---------------------------------------------------------------------------- @@ -191,7 +189,6 @@ ModalDialog::~ModalDialog() // to the deleted widgets will be gone, but some widgets // may want to perform additional cleanup at this time elementsWereDeleted(); - GUIEngine::getDevice()->setResizable(m_was_resizable); } // ~ModalDialog // ---------------------------------------------------------------------------- diff --git a/src/guiengine/modaldialog.hpp b/src/guiengine/modaldialog.hpp index e3b1c4da682..a6789085c47 100644 --- a/src/guiengine/modaldialog.hpp +++ b/src/guiengine/modaldialog.hpp @@ -60,7 +60,6 @@ namespace GUIEngine float m_percent_width, m_percent_height; bool m_init; - bool m_was_resizable; protected: irr::gui::IGUIWindow* m_irrlicht_window; irr::core::rect< irr::s32 > m_area; diff --git a/src/guiengine/screen.cpp b/src/guiengine/screen.cpp index 1ca7af10644..7bc5e414204 100644 --- a/src/guiengine/screen.cpp +++ b/src/guiengine/screen.cpp @@ -58,7 +58,6 @@ Screen::Screen(const char* file, bool pause_race) m_update_in_background = false; m_width = irr_driver->getActualScreenSize().Width; m_height = irr_driver->getActualScreenSize().Height; - m_resizable = false; } // Screen // ----------------------------------------------------------------------------- diff --git a/src/guiengine/screen.hpp b/src/guiengine/screen.hpp index b9900f8f6df..e26acfab0b3 100644 --- a/src/guiengine/screen.hpp +++ b/src/guiengine/screen.hpp @@ -71,9 +71,6 @@ namespace GUIEngine if (singleton == NULL) { singleton = new SCREEN(); - std::function new_screen_function = []() - { return ScreenSingleton::getInstance(); }; - singleton->setScreenPointerFunction(new_screen_function); GUIEngine::addScreenToList(singleton); } @@ -95,10 +92,6 @@ namespace GUIEngine */ class Screen : public AbstractTopLevelContainer { -protected: - /** True if this screen is resizable - */ - bool m_resizable; private: /** True if the race (if it is running) should be paused when this * screen is shown. The RaceResultGUI uses this to leave the race @@ -143,13 +136,6 @@ namespace GUIEngine PtrVector& append_to, irr::gui::IGUIElement* parent = NULL); - /** Save the function before GUIEngine::clearScreenCache, call it after - * to get the new screen instance pointer - */ - std::function getNewScreenPointer() const { return m_screen_func; } - - void setScreenPointerFunction(const std::function& f) { m_screen_func = f; } - Screen(bool pause_race=true); Screen(const char* filename, bool pause_race=true); @@ -308,7 +294,6 @@ namespace GUIEngine virtual int getHeight() { return m_height; } - virtual bool isResizable() const { return m_resizable; } /** * \brief Override this if you need to be notified of player actions * in subclasses. diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 36717ffd849..e3e124a11a1 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -129,8 +129,6 @@ World* World::m_world[PT_COUNT]; */ World::World() : WorldStatus() { - if (m_process_type == PT_MAIN) - GUIEngine::getDevice()->setResizable(true); RewindManager::setEnable(NetworkConfig::get()->isNetworking()); #ifdef DEBUG m_magic_number = 0xB01D6543; @@ -614,7 +612,6 @@ World::~World() { if (m_process_type == PT_MAIN) { - GUIEngine::getDevice()->setResizable(false); material_manager->unloadAllTextures(); } diff --git a/src/states_screens/main_menu_screen.cpp b/src/states_screens/main_menu_screen.cpp index 91c4964fb34..a28dc264591 100644 --- a/src/states_screens/main_menu_screen.cpp +++ b/src/states_screens/main_menu_screen.cpp @@ -78,7 +78,6 @@ using namespace Online; MainMenuScreen::MainMenuScreen() : Screen("main_menu.stkgui") { - m_resizable = true; } // MainMenuScreen // ---------------------------------------------------------------------------- @@ -125,7 +124,6 @@ void MainMenuScreen::beforeAddingWidget() // void MainMenuScreen::init() { - GUIEngine::getDevice()->setResizable(true); Screen::init(); m_user_id = getWidget("user-id"); @@ -612,7 +610,6 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name, void MainMenuScreen::tearDown() { - GUIEngine::getDevice()->setResizable(false); } // tearDown // ---------------------------------------------------------------------------- diff --git a/src/states_screens/options/options_screen_general.cpp b/src/states_screens/options/options_screen_general.cpp index afc538260b5..e4c161bf17c 100644 --- a/src/states_screens/options/options_screen_general.cpp +++ b/src/states_screens/options/options_screen_general.cpp @@ -66,7 +66,6 @@ using namespace Online; OptionsScreenGeneral::OptionsScreenGeneral() : Screen("options/options_general.stkgui") { - m_resizable = true; m_inited = false; } // OptionsScreenVideo @@ -81,8 +80,6 @@ void OptionsScreenGeneral::loadedFromFile() void OptionsScreenGeneral::init() { - GUIEngine::getDevice()->setResizable( - StateManager::get()->getGameState() == GUIEngine::MENU); Screen::init(); RibbonWidget* ribbon = getWidget("options_choice"); assert(ribbon != NULL); @@ -283,7 +280,6 @@ void OptionsScreenGeneral::setInternetCheckboxes(bool activate) void OptionsScreenGeneral::tearDown() { - GUIEngine::getDevice()->setResizable(false); Screen::tearDown(); // save changes when leaving screen user_config->saveConfig(); diff --git a/src/states_screens/options/options_screen_video.cpp b/src/states_screens/options/options_screen_video.cpp index 6863b4bbefe..58952f7e51b 100644 --- a/src/states_screens/options/options_screen_video.cpp +++ b/src/states_screens/options/options_screen_video.cpp @@ -205,7 +205,6 @@ OptionsScreenVideo::OptionsScreenVideo() : Screen("options/options_video.stkgui" m_prev_adv_pipline(false), m_prev_img_quality(-1) { - m_resizable = true; m_inited = false; initPresets(); } // OptionsScreenVideo @@ -235,8 +234,6 @@ void OptionsScreenVideo::loadedFromFile() void OptionsScreenVideo::init() { - GUIEngine::getDevice()->setResizable( - StateManager::get()->getGameState() == GUIEngine::MENU); Screen::init(); m_prev_adv_pipline = UserConfigParams::m_dynamic_lights; m_prev_img_quality = getImageQuality(); @@ -367,12 +364,6 @@ void OptionsScreenVideo::init() updateResolutionsList(); - if (m_fullscreen_checkbox_focus) - { - m_fullscreen_checkbox_focus = false; - getWidget("fullscreen")->setFocusForPlayer(PLAYER_ID_GAME_MASTER); - } - // If a benchmark was requested and the game had to reload // the graphics engine, start the benchmark when the // video settings screen is loaded back afterwards. @@ -386,6 +377,13 @@ void OptionsScreenVideo::onResize() { Screen::onResize(); configResolutionsList(); + if (m_fullscreen_checkbox_focus) + { + m_fullscreen_checkbox_focus = false; + Widget* full = getWidget("fullscreen"); + if (full->isActivated() && full->isVisible()) + full->setFocusForPlayer(PLAYER_ID_GAME_MASTER); + } } // onResize // -------------------------------------------------------------------------------------------- @@ -987,24 +985,7 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name, { UserConfigParams::m_fullscreen = fullscreen->getState(); update_fullscreen_desktop(UserConfigParams::m_fullscreen); - if (StateManager::get()->getGameState() == GUIEngine::INGAME_MENU) - { - StateManager::get()->popMenu(); - std::function screen_function = - getNewScreenPointer(); - int new_width = 0; - int new_height = 0; - SDL_GetWindowSize(gevk->getSDLWindow(), &new_width, - &new_height); - static_cast(gevk->getIrrlichtDevice()) - ->handleNewSize(new_width, new_height); - irr_driver->handleWindowResize(); - Screen* new_screen = screen_function(); - OptionsScreenVideo::m_fullscreen_checkbox_focus = true; - new_screen->push(); - } - else - OptionsScreenVideo::m_fullscreen_checkbox_focus = true; + OptionsScreenVideo::m_fullscreen_checkbox_focus = true; } else updateResolutionsList(); @@ -1034,11 +1015,6 @@ void OptionsScreenVideo::startBenchmark() void OptionsScreenVideo::tearDown() { - if (getWidget("fullscreen")->isVisible() && - getWidget("fullscreen")->isFocusedForPlayer(PLAYER_ID_GAME_MASTER)) - OptionsScreenVideo::m_fullscreen_checkbox_focus = true; - - GUIEngine::getDevice()->setResizable(false); #ifndef SERVER_ONLY if (m_prev_adv_pipline != UserConfigParams::m_dynamic_lights && CVS->isGLSL()) From 7ad4040b2db3137ce6042489f0aa4ba3b93285bc Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sun, 5 May 2024 14:24:56 +0200 Subject: [PATCH 365/830] Add a new 'Display' option tab The video settings were getting crowded with the benchmark mode, and with large font size the benchmark buttons ended off-screen. --- data/gui/icons/options_display.png | Bin 0 -> 13147 bytes data/gui/screens/options/options_audio.stkgui | 2 + .../gui/screens/options/options_device.stkgui | 2 + .../screens/options/options_display.stkgui | 70 +++ .../screens/options/options_general.stkgui | 2 + data/gui/screens/options/options_input.stkgui | 2 + .../screens/options/options_language.stkgui | 2 + data/gui/screens/options/options_ui.stkgui | 2 + data/gui/screens/options/options_video.stkgui | 39 +- .../{ => options}/user_screen_tab.stkgui | 2 + .../options/options_screen_audio.cpp | 7 +- .../options/options_screen_device.cpp | 5 +- .../options/options_screen_display.cpp | 460 ++++++++++++++++++ .../options/options_screen_display.hpp | 97 ++++ .../options/options_screen_general.cpp | 5 +- .../options/options_screen_input.cpp | 5 +- .../options/options_screen_language.cpp | 5 +- .../options/options_screen_ui.cpp | 5 +- .../options/options_screen_video.cpp | 300 +----------- .../options/options_screen_video.hpp | 33 -- src/states_screens/options/user_screen.cpp | 3 + src/states_screens/options/user_screen.hpp | 2 +- 22 files changed, 676 insertions(+), 374 deletions(-) create mode 100644 data/gui/icons/options_display.png create mode 100644 data/gui/screens/options/options_display.stkgui rename data/gui/screens/{ => options}/user_screen_tab.stkgui (97%) create mode 100644 src/states_screens/options/options_screen_display.cpp create mode 100644 src/states_screens/options/options_screen_display.hpp diff --git a/data/gui/icons/options_display.png b/data/gui/icons/options_display.png new file mode 100644 index 0000000000000000000000000000000000000000..7bdd37b5c810f7aa7b136e5efabee9348216fd34 GIT binary patch literal 13147 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 IvUTYH0v + + + + +
+
+ + +
+ + + + + + + + + + + + + + + + + + +
+
+
diff --git a/data/gui/screens/options/options_general.stkgui b/data/gui/screens/options/options_general.stkgui index 7cb1f1b03b5..3d726a66de1 100644 --- a/data/gui/screens/options/options_general.stkgui +++ b/data/gui/screens/options/options_general.stkgui @@ -10,6 +10,8 @@ + + + + + - - - -
+
diff --git a/data/gui/dialogs/custom_video_settings.stkgui b/data/gui/dialogs/custom_video_settings.stkgui index 6d6100fcbb3..814ea699c2a 100644 --- a/data/gui/dialogs/custom_video_settings.stkgui +++ b/data/gui/dialogs/custom_video_settings.stkgui @@ -1,6 +1,6 @@ -
+
diff --git a/data/gui/dialogs/online/achievement_progress_dialog.stkgui b/data/gui/dialogs/online/achievement_progress_dialog.stkgui index d88e7832a08..acb80650a59 100644 --- a/data/gui/dialogs/online/achievement_progress_dialog.stkgui +++ b/data/gui/dialogs/online/achievement_progress_dialog.stkgui @@ -1,6 +1,6 @@ -
+
diff --git a/data/gui/dialogs/recommend_video_settings.stkgui b/data/gui/dialogs/recommend_video_settings.stkgui index 4f3d1856386..48462e0a67b 100644 --- a/data/gui/dialogs/recommend_video_settings.stkgui +++ b/data/gui/dialogs/recommend_video_settings.stkgui @@ -1,8 +1,6 @@ -
- - +
From 5bfb9aa05473c3f280c452c045fdc67f5ca2d4e4 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Tue, 21 May 2024 15:12:59 +0200 Subject: [PATCH 406/830] Fix an error detected by CI - Update MSVC cmakelist to properly add DEBUG --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bd4820ee23..e48bcb874ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -519,7 +519,7 @@ endif() if(MSVC) # VS will automatically add NDEBUG for release mode, but only _DEBUG in debug mode. # Since STK uses DEBUG, this is added for debug compilation only: - set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUG) + set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS $<$:DEBUG>) else() # All non VS generators used create only a single compile mode, so # compile flags can be simplye be added From e165a5680bb5f0e41b9809214c6f208f348c452e Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Tue, 21 May 2024 15:31:46 +0200 Subject: [PATCH 407/830] Fix #4742 --- src/modes/follow_the_leader.cpp | 10 +++++++--- src/modes/follow_the_leader.hpp | 7 ++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/modes/follow_the_leader.cpp b/src/modes/follow_the_leader.cpp index 48990c30f44..0a69448c5c2 100644 --- a/src/modes/follow_the_leader.cpp +++ b/src/modes/follow_the_leader.cpp @@ -47,6 +47,7 @@ FollowTheLeaderRace::FollowTheLeaderRace() : LinearWorld() m_use_highscores = false; // disable high scores setClockMode(WorldStatus::CLOCK_COUNTDOWN, m_leader_intervals[0]); m_is_over_delay = 5.0f; + m_leader_hit_count = 0; } //----------------------------------------------------------------------------- @@ -89,6 +90,7 @@ void FollowTheLeaderRace::reset(bool restart) m_leader_intervals[0]); m_is_over_delay = 2.0f; + m_leader_hit_count = 0; } // reset //----------------------------------------------------------------------------- @@ -122,7 +124,8 @@ const btTransform &FollowTheLeaderRace::getStartTransform(int index) */ void FollowTheLeaderRace::countdownReachedZero() { - m_last_eliminated_time += m_leader_intervals[0]; + m_last_eliminated_time += m_leader_intervals[0] + m_leader_hit_count * LEADER_HIT_TIME; + m_leader_hit_count = 0; // Reset the hit counter if(m_leader_intervals.size()>1) m_leader_intervals.erase(m_leader_intervals.begin()); WorldStatus::setTime(m_leader_intervals[0]); @@ -146,7 +149,7 @@ void FollowTheLeaderRace::countdownReachedZero() { if(UserConfigParams::m_ftl_debug) { - Log::debug("[FTL", "Eliminiating kart '%s' at position %d.", + Log::debug("[FTL", "Eliminating kart '%s' at position %d.", kart->getIdent().c_str(), position_to_remove); } eliminateKart(kart->getWorldKartId()); @@ -227,8 +230,9 @@ bool FollowTheLeaderRace::isRaceOver() void FollowTheLeaderRace::leaderHit() { int countdown = getTimeTicks(); - countdown += stk_config->time2Ticks(5.0f); + countdown += stk_config->time2Ticks(LEADER_HIT_TIME); setTicks(countdown); + m_leader_hit_count++; } // leaderHit //----------------------------------------------------------------------------- diff --git a/src/modes/follow_the_leader.hpp b/src/modes/follow_the_leader.hpp index 498521a730f..3eef8c7bba9 100644 --- a/src/modes/follow_the_leader.hpp +++ b/src/modes/follow_the_leader.hpp @@ -18,6 +18,8 @@ #ifndef _follow_the_leader_hpp_ #define _follow_the_leader_hpp_ +#define LEADER_HIT_TIME 5.0f + #include "modes/linear_world.hpp" /** @@ -27,9 +29,12 @@ class FollowTheLeaderRace : public LinearWorld { private: - // time till elimination in follow leader + // time till elimination in follow leader std::vector m_leader_intervals; + // Number of rescue/hit endured by the leader since the previous kart elimination + unsigned int m_leader_hit_count; + /** A timer used before terminating the race. */ float m_is_over_delay; From 2923a86cd61fc441c853d5937baa831391b41fa1 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Tue, 21 May 2024 21:35:41 +0200 Subject: [PATCH 408/830] Minor fixes - The code starting a tutorial race was duplicated in three places. Consolidate it in one place. - When launching the tutorial from the overworld, use the last used input device instead of the keyboard - Restore the old cmake policy. The new way to replace that code suggested by the cmake manual fails CI, and debugging MSVC fantasies without a local install is a nightmare. - Restrict this policy setting to MSVC as that's the only compile path that needs it, avoiding the warning for non-MSVC builds. - Add missing define guards - Remove some extraneous includes --- CMakeLists.txt | 4 ++ src/config/player_profile.hpp | 2 + src/modes/tutorial_utils.cpp | 62 +++++++++++++++++++++++ src/modes/tutorial_utils.hpp | 27 ++++++++++ src/modes/world.cpp | 44 ++-------------- src/states_screens/help/help_screen_1.cpp | 40 +-------------- src/states_screens/main_menu_screen.cpp | 42 ++------------- src/states_screens/main_menu_screen.hpp | 2 - 8 files changed, 104 insertions(+), 119 deletions(-) create mode 100644 src/modes/tutorial_utils.cpp create mode 100644 src/modes/tutorial_utils.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e48bcb874ea..64fcec66f3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,10 @@ add_definitions( -DSUPERTUXKART_VERSION="${PROJECT_VERSION}" ) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") include(CMakeDependentOption) +if(MSVC) + cmake_policy(SET CMP0043 OLD) +endif() + include(BuildTypeSTKRelease) if(NOT CMAKE_BUILD_TYPE) message(STATUS "No build type selected, default to STKRelease") diff --git a/src/config/player_profile.hpp b/src/config/player_profile.hpp index ed73334653a..f70c5fe99e6 100644 --- a/src/config/player_profile.hpp +++ b/src/config/player_profile.hpp @@ -160,7 +160,9 @@ class PlayerProfile : public NoCopy /** Returns the name of this player. */ const core::stringw& getName() const { + #ifdef DEBUG assert(m_magic_number == 0xABCD1234); + #endif return m_local_name; } // getName diff --git a/src/modes/tutorial_utils.cpp b/src/modes/tutorial_utils.cpp new file mode 100644 index 00000000000..b727edd385f --- /dev/null +++ b/src/modes/tutorial_utils.cpp @@ -0,0 +1,62 @@ +// SuperTuxKart - a fun racing game with go-kart +// +// Copyright (C) 2024 Alayan +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "modes/tutorial_utils.hpp" + +#include "config/player_manager.hpp" +#include "config/user_config.hpp" +#include "karts/kart_properties_manager.hpp" +#include "input/device_manager.hpp" +#include "input/input_manager.hpp" +#include "race/race_manager.hpp" + +namespace TutorialUtils +{ + void startTutorial(bool from_overworld) + { + RaceManager::get()->setNumPlayers(1); + RaceManager::get()->setMajorMode (RaceManager::MAJOR_MODE_SINGLE); + RaceManager::get()->setMinorMode (RaceManager::MINOR_MODE_TUTORIAL); + RaceManager::get()->setNumKarts( 1 ); + RaceManager::get()->setTrack( "tutorial" ); + RaceManager::get()->setDifficulty(RaceManager::DIFFICULTY_EASY); + RaceManager::get()->setReverseTrack(false); + + // Use the last used device + InputDevice* device = input_manager->getDeviceManager()->getLatestUsedDevice(); + + // Create player and associate player with device + StateManager::get()->createActivePlayer(PlayerManager::getCurrentPlayer(), device); + + if (kart_properties_manager->getKart(UserConfigParams::m_default_kart) == NULL) + { + Log::warn("HelpScreen1", "Cannot find kart '%s', will revert to default", + UserConfigParams::m_default_kart.c_str()); + UserConfigParams::m_default_kart.revertToDefaults(); + } + RaceManager::get()->setPlayerKart(0, UserConfigParams::m_default_kart); + + // ASSIGN should make sure that only input from assigned devices is read. + input_manager->getDeviceManager()->setAssignMode(ASSIGN); + input_manager->getDeviceManager()->setSinglePlayer( StateManager::get()->getActivePlayer(0) ); + + StateManager::get()->enterGameState(); + RaceManager::get()->setupPlayerKartInfo(); + RaceManager::get()->startNew(from_overworld); + } +} \ No newline at end of file diff --git a/src/modes/tutorial_utils.hpp b/src/modes/tutorial_utils.hpp new file mode 100644 index 00000000000..2c5f6745ed7 --- /dev/null +++ b/src/modes/tutorial_utils.hpp @@ -0,0 +1,27 @@ +// SuperTuxKart - a fun racing game with go-kart +// +// Copyright (C) 2024 Alayan +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef __HEADER_TUTORIAL_UTILS_HPP__ +#define __HEADER_TUTORIAL_UTILS_HPP__ + +namespace TutorialUtils +{ + void startTutorial(bool from_overworld = false); +} + +#endif \ No newline at end of file diff --git a/src/modes/world.cpp b/src/modes/world.cpp index a4a85fe6d26..decf04c5d15 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -52,6 +52,7 @@ #include "karts/kart_rewinder.hpp" #include "main_loop.hpp" #include "modes/overworld.hpp" +#include "modes/tutorial_utils.hpp" #include "network/child_loop.hpp" #include "network/protocols/client_lobby.hpp" #include "network/network_config.hpp" @@ -82,12 +83,6 @@ #include "utils/translation.hpp" #include "utils/string_utils.hpp" -#include -#include -#include -#include -#include - #include #include @@ -1016,7 +1011,6 @@ void World::updateWorld(int ticks) assert(m_magic_number == 0xB01D6543); #endif - if (m_schedule_pause) { pause(m_scheduled_pause_phase); @@ -1067,41 +1061,8 @@ void World::updateWorld(int ticks) if (m_schedule_tutorial) { m_schedule_tutorial = false; - RaceManager::get()->setNumPlayers(1); - RaceManager::get()->setMajorMode (RaceManager::MAJOR_MODE_SINGLE); - RaceManager::get()->setMinorMode (RaceManager::MINOR_MODE_TUTORIAL); - RaceManager::get()->setNumKarts( 1 ); - RaceManager::get()->setTrack( "tutorial" ); - RaceManager::get()->setDifficulty(RaceManager::DIFFICULTY_EASY); - RaceManager::get()->setReverseTrack(false); - - // Use keyboard 0 by default (FIXME: let player choose?) - InputDevice* device = input_manager->getDeviceManager()->getKeyboard(0); - - // Create player and associate player with keyboard - StateManager::get()->createActivePlayer(PlayerManager::getCurrentPlayer(), - device); - - if (!kart_properties_manager->getKart(UserConfigParams::m_default_kart)) - { - Log::warn("[World]", - "Cannot find kart '%s', will revert to default.", - UserConfigParams::m_default_kart.c_str()); - UserConfigParams::m_default_kart.revertToDefaults(); - } - RaceManager::get()->setPlayerKart(0, UserConfigParams::m_default_kart); - - // ASSIGN should make sure that only input from assigned devices - // is read. - input_manager->getDeviceManager()->setAssignMode(ASSIGN); - input_manager->getDeviceManager() - ->setSinglePlayer( StateManager::get()->getActivePlayer(0) ); - delete this; - - StateManager::get()->enterGameState(); - RaceManager::get()->setupPlayerKartInfo(); - RaceManager::get()->startNew(true); + TutorialUtils::startTutorial(true /*from overworld*/); } else { @@ -1123,6 +1084,7 @@ void World::updateWorld(int ticks) void World::scheduleTutorial() { + printf("Tutorial scheduled\n"); m_schedule_exit_race = true; m_schedule_tutorial = true; } // scheduleTutorial diff --git a/src/states_screens/help/help_screen_1.cpp b/src/states_screens/help/help_screen_1.cpp index 18d8e5ecff7..bb6c6d5ba75 100644 --- a/src/states_screens/help/help_screen_1.cpp +++ b/src/states_screens/help/help_screen_1.cpp @@ -18,13 +18,8 @@ // Manages includes common to all help screens #include "states_screens/help/help_common.hpp" -#include "config/player_manager.hpp" -#include "config/user_config.hpp" #include "guiengine/widgets/button_widget.hpp" -#include "input/device_manager.hpp" -#include "input/input_manager.hpp" -#include "karts/kart_properties_manager.hpp" -#include "race/race_manager.hpp" +#include "modes/tutorial_utils.hpp" using namespace GUIEngine; @@ -46,38 +41,7 @@ void HelpScreen1::eventCallback(Widget* widget, const std::string& name, const i { if (name == "startTutorial") { - RaceManager::get()->setNumPlayers(1); - RaceManager::get()->setMajorMode (RaceManager::MAJOR_MODE_SINGLE); - RaceManager::get()->setMinorMode (RaceManager::MINOR_MODE_TUTORIAL); - RaceManager::get()->setNumKarts( 1 ); - RaceManager::get()->setTrack( "tutorial" ); - RaceManager::get()->setDifficulty(RaceManager::DIFFICULTY_EASY); - RaceManager::get()->setReverseTrack(false); - - // Use the last used device - InputDevice* device = input_manager->getDeviceManager()->getLatestUsedDevice(); - - // Create player and associate player with keyboard - StateManager::get()->createActivePlayer(PlayerManager::getCurrentPlayer(), - device); - - if (kart_properties_manager->getKart(UserConfigParams::m_default_kart) == NULL) - { - Log::warn("HelpScreen1", "Cannot find kart '%s', will revert to default", - UserConfigParams::m_default_kart.c_str()); - UserConfigParams::m_default_kart.revertToDefaults(); - } - RaceManager::get()->setPlayerKart(0, UserConfigParams::m_default_kart); - - // ASSIGN should make sure that only input from assigned devices - // is read. - input_manager->getDeviceManager()->setAssignMode(ASSIGN); - input_manager->getDeviceManager() - ->setSinglePlayer( StateManager::get()->getActivePlayer(0) ); - - StateManager::get()->enterGameState(); - RaceManager::get()->setupPlayerKartInfo(); - RaceManager::get()->startNew(false); + TutorialUtils::startTutorial(); } else if (name == "category") { diff --git a/src/states_screens/main_menu_screen.cpp b/src/states_screens/main_menu_screen.cpp index a28dc264591..e52995cd652 100644 --- a/src/states_screens/main_menu_screen.cpp +++ b/src/states_screens/main_menu_screen.cpp @@ -38,8 +38,9 @@ #include "karts/kart_properties_manager.hpp" #include "main_loop.hpp" #include "modes/cutscene_world.hpp" -#include "modes/overworld.hpp" #include "modes/demo_world.hpp" +#include "modes/overworld.hpp" +#include "modes/tutorial_utils.hpp" #include "network/network_config.hpp" #include "online/request_manager.hpp" #include "states_screens/addons_screen.hpp" @@ -258,7 +259,7 @@ void MainMenuScreen::onUpdate(float delta) virtual void onConfirm() { GUIEngine::ModalDialog::dismiss(); - MainMenuScreen::getInstance()->startTutorial(); + TutorialUtils::startTutorial(); } // onConfirm }; // PlayTutorial @@ -271,41 +272,6 @@ void MainMenuScreen::onUpdate(float delta) #endif } // onUpdate -// ---------------------------------------------------------------------------- -void MainMenuScreen::startTutorial() -{ - RaceManager::get()->setNumPlayers(1); - RaceManager::get()->setMajorMode (RaceManager::MAJOR_MODE_SINGLE); - RaceManager::get()->setMinorMode (RaceManager::MINOR_MODE_TUTORIAL); - RaceManager::get()->setNumKarts( 1 ); - RaceManager::get()->setTrack("tutorial"); - RaceManager::get()->setDifficulty(RaceManager::DIFFICULTY_EASY); - RaceManager::get()->setReverseTrack(false); - - // Use the last used device - InputDevice* device = input_manager->getDeviceManager()->getLatestUsedDevice(); - - // Create player and associate player with device - StateManager::get()->createActivePlayer(PlayerManager::getCurrentPlayer(), device); - - if (kart_properties_manager->getKart(UserConfigParams::m_default_kart) == NULL) - { - Log::warn("MainMenuScreen", "Cannot find kart '%s', will revert to default", - UserConfigParams::m_default_kart.c_str()); - UserConfigParams::m_default_kart.revertToDefaults(); - } - RaceManager::get()->setPlayerKart(0, UserConfigParams::m_default_kart); - - // ASSIGN should make sure that only input from assigned devices is read - input_manager->getDeviceManager()->setAssignMode(ASSIGN); - input_manager->getDeviceManager() - ->setSinglePlayer( StateManager::get()->getActivePlayer(0) ); - - StateManager::get()->enterGameState(); - RaceManager::get()->setupPlayerKartInfo(); - RaceManager::get()->startNew(false); -} // startTutorial - // ---------------------------------------------------------------------------- void MainMenuScreen::eventCallback(Widget* widget, const std::string& name, @@ -509,7 +475,7 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name, } else if (selection == "startTutorial") { - startTutorial(); + TutorialUtils::startTutorial(); } else if (selection == "story") { diff --git a/src/states_screens/main_menu_screen.hpp b/src/states_screens/main_menu_screen.hpp index ce495e3b84c..4967d262d7e 100644 --- a/src/states_screens/main_menu_screen.hpp +++ b/src/states_screens/main_menu_screen.hpp @@ -38,8 +38,6 @@ class MainMenuScreen : public GUIEngine::Screen, public GUIEngine::ScreenSinglet core::stringw m_news_text; MainMenuScreen(); - - void startTutorial(); public: virtual void onUpdate(float delta) OVERRIDE; From c086a6774dba68583953d2e5e3f3e8805c5a9444 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Wed, 22 May 2024 23:24:50 +0200 Subject: [PATCH 409/830] Misc. improvements - Fix MSVC compilation - Improve some repetitive code --- CMakeLists.txt | 7 ++---- src/states_screens/race_gui_base.cpp | 32 ++++++++-------------------- src/tracks/track.cpp | 2 +- 3 files changed, 12 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 64fcec66f3b..d85449a5f58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,10 +9,6 @@ add_definitions( -DSUPERTUXKART_VERSION="${PROJECT_VERSION}" ) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") include(CMakeDependentOption) -if(MSVC) - cmake_policy(SET CMP0043 OLD) -endif() - include(BuildTypeSTKRelease) if(NOT CMAKE_BUILD_TYPE) message(STATUS "No build type selected, default to STKRelease") @@ -523,7 +519,8 @@ endif() if(MSVC) # VS will automatically add NDEBUG for release mode, but only _DEBUG in debug mode. # Since STK uses DEBUG, this is added for debug compilation only: - set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS $<$:DEBUG>) + cmake_policy(SET CMP0043 OLD) + set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUG) else() # All non VS generators used create only a single compile mode, so # compile flags can be simplye be added diff --git a/src/states_screens/race_gui_base.cpp b/src/states_screens/race_gui_base.cpp index b1c59e0ae29..bb3a19adcc4 100644 --- a/src/states_screens/race_gui_base.cpp +++ b/src/states_screens/race_gui_base.cpp @@ -1034,35 +1034,21 @@ void RaceGUIBase::drawPlayerIcon(AbstractKart *kart, int x, int y, int w, bool is_local) { #ifndef SERVER_ONLY - video::ITexture *icon = - kart->getKartProperties()->getIconMaterial()->getTexture(); + video::ITexture *icon = kart->getKartProperties()->getIconMaterial()->getTexture(); CaptureTheFlag* ctf = dynamic_cast(World::getWorld()); unsigned int kart_id = kart->getWorldKartId(); // CTF - if (ctf) + if (ctf && (ctf->getRedHolder() == (int)kart_id || + ctf->getBlueHolder() == (int)kart_id)) { - if (ctf->getRedHolder() == (int)kart_id) - { - video::ITexture* red = - irr_driver->getTexture(FileManager::GUI_ICON, "red_flag.png"); - const core::rect rect(core::position2d(0, 0), - red->getSize()); - const core::rect pos1 - (x - 20, y - 10, x + w - 20, y + w - 30); - draw2DImage(red, pos1, rect, NULL, NULL, true); - } - else if (ctf->getBlueHolder() == (int)kart_id) - { - video::ITexture* blue = - irr_driver->getTexture(FileManager::GUI_ICON, "blue_flag.png"); - const core::rect rect(core::position2d(0, 0), - blue->getSize()); - const core::rect pos1 - (x - 20, y - 10, x + w - 20, y + w - 30); - draw2DImage(blue, pos1, rect, NULL, NULL, true); - } + video::ITexture* flag = irr_driver->getTexture(FileManager::GUI_ICON, + (ctf->getRedHolder() == (int)kart_id) ? "red_flag.png" : "blue_flag.png"); + + const core::rect rect(core::position2d(0, 0), flag->getSize()); + const core::rect pos1(x - 20, y - 10, x + w - 20, y + w - 30); + draw2DImage(flag, pos1, rect, NULL, NULL, true); } const core::rect pos(x, y, x+w, y+w); diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index ce13b321ed0..e2219c50812 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -936,7 +936,7 @@ void Track::createPhysicsModel(unsigned int main_track_count, // ----------------------------------------------------------------------------- -/** Convert the graohics track into its physics equivalents. +/** Convert the graphics track into its physics equivalents. * \param mesh The mesh to convert. * \param node The scene node. */ From af18315c738227ff84df664da7748513e7fad4c2 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Thu, 23 May 2024 00:10:25 +0200 Subject: [PATCH 410/830] Clean up repetitive CTF code --- src/modes/capture_the_flag.cpp | 108 ++++++++++++++------------------- src/modes/capture_the_flag.hpp | 7 ++- 2 files changed, 50 insertions(+), 65 deletions(-) diff --git a/src/modes/capture_the_flag.cpp b/src/modes/capture_the_flag.cpp index 65365f8723a..4115336695e 100644 --- a/src/modes/capture_the_flag.cpp +++ b/src/modes/capture_the_flag.cpp @@ -109,8 +109,7 @@ void CaptureTheFlag::init() return; m_red_flag_node = irr_driver->addAnimatedMesh(m_red_flag_mesh, "red_flag"); - m_blue_flag_node = irr_driver->addAnimatedMesh(m_blue_flag_mesh, - "blue_flag"); + m_blue_flag_node = irr_driver->addAnimatedMesh(m_blue_flag_mesh, "blue_flag"); assert(m_red_flag_node); assert(m_blue_flag_node); m_red_flag_node->grab(); @@ -262,66 +261,9 @@ void CaptureTheFlag::update(int ticks) m_red_flag->update(ticks); m_blue_flag->update(ticks); - if (m_red_flag->getHolder() != -1 && m_blue_flag->isInBase() && - (m_blue_flag->getBaseOrigin() - m_red_flag->getOrigin()).length() < - g_capture_length) - { - // Blue team scored - if (!NetworkConfig::get()->isNetworking() || - NetworkConfig::get()->isServer()) - { - int red_holder = m_red_flag->getHolder(); - int new_kart_scores = m_scores.at(red_holder) + g_captured_score; - int new_blue_scores = m_blue_scores + 1; - m_scores.at(red_holder) = new_kart_scores; - if (NetworkConfig::get()->isServer()) - { - NetworkString p(PROTOCOL_GAME_EVENTS); - p.setSynchronous(true); - p.addUInt8(GameEventsProtocol::GE_CTF_SCORED) - .addUInt8((int8_t)red_holder) - .addUInt8(0/*red_team_scored*/) - .addUInt16((int16_t)new_kart_scores) - .addUInt8((uint8_t)m_red_scores) - .addUInt8((uint8_t)new_blue_scores); - STKHost::get()->sendPacketToAllPeers(&p, true); - } - ctfScored(red_holder, false/*red_team_scored*/, new_kart_scores, - m_red_scores, new_blue_scores); - } - m_last_captured_flag_ticks = World::getWorld()->getTicksSinceStart(); - m_red_flag->resetToBase(RaceManager::get()->getFlagDeactivatedTicks()); - } - else if (m_blue_flag->getHolder() != -1 && m_red_flag->isInBase() && - (m_red_flag->getBaseOrigin() - m_blue_flag->getOrigin()).length() < - g_capture_length) - { - // Red team scored - if (!NetworkConfig::get()->isNetworking() || - NetworkConfig::get()->isServer()) - { - int blue_holder = m_blue_flag->getHolder(); - int new_kart_scores = m_scores.at(blue_holder) + g_captured_score; - int new_red_scores = m_red_scores + 1; - m_scores.at(blue_holder) = new_kart_scores; - if (NetworkConfig::get()->isServer()) - { - NetworkString p(PROTOCOL_GAME_EVENTS); - p.setSynchronous(true); - p.addUInt8(GameEventsProtocol::GE_CTF_SCORED) - .addUInt8((int8_t)blue_holder) - .addUInt8(1/*red_team_scored*/) - .addUInt16((int16_t)new_kart_scores) - .addUInt8((uint8_t)new_red_scores) - .addUInt8((uint8_t)m_blue_scores); - STKHost::get()->sendPacketToAllPeers(&p, true); - } - ctfScored(blue_holder, true/*red_team_scored*/, new_kart_scores, - new_red_scores, m_blue_scores); - } - m_last_captured_flag_ticks = World::getWorld()->getTicksSinceStart(); - m_blue_flag->resetToBase(RaceManager::get()->getFlagDeactivatedTicks()); - } + // Test if points have been scored + checkScoring(FC_RED); + checkScoring(FC_BLUE); // Test if red or blue flag is touched for (auto& k : m_karts) @@ -372,6 +314,48 @@ void CaptureTheFlag::update(int ticks) } } // update +// ---------------------------------------------------------------------------- +void CaptureTheFlag::checkScoring(FlagColor color) +{ + bool red_active = (color == FC_RED); + std::shared_ptr active_flag = (red_active) ? m_red_flag : m_blue_flag; + std::shared_ptr other_flag = (red_active) ? m_blue_flag : m_red_flag; + + // If a flag is held close enough to the base of the other flag, + // while the other flag is in base, the flag has been successfully captured. + // If the active flag is red (blue), the scoring team is blue (red). + if (active_flag->getHolder() != -1 && other_flag->isInBase() && + (other_flag->getBaseOrigin() - active_flag->getOrigin()).length() < + g_capture_length) + { + if (!NetworkConfig::get()->isNetworking() || + NetworkConfig::get()->isServer()) + { + int active_holder = active_flag->getHolder(); + int new_kart_score = m_scores.at(active_holder) + g_captured_score; + int new_red_score = (red_active) ? m_red_scores : m_red_scores + 1; + int new_blue_score = (red_active) ? m_blue_scores + 1 : m_blue_scores; + m_scores.at(active_holder) = new_kart_score; + if (NetworkConfig::get()->isServer()) + { + NetworkString p(PROTOCOL_GAME_EVENTS); + p.setSynchronous(true); + p.addUInt8(GameEventsProtocol::GE_CTF_SCORED) + .addUInt8((int8_t)active_holder) + .addUInt8((red_active) ? 0 : 1 /*red_team_scored*/) + .addUInt16((int16_t)new_kart_score) + .addUInt8((uint8_t)new_red_score) + .addUInt8((uint8_t)new_blue_score); + STKHost::get()->sendPacketToAllPeers(&p, true); + } + ctfScored(active_holder, (red_active) ? false : true /*red_team_scored*/, + new_kart_score, new_red_score, new_blue_score); + } + m_last_captured_flag_ticks = World::getWorld()->getTicksSinceStart(); + active_flag->resetToBase(RaceManager::get()->getFlagDeactivatedTicks()); + } +} // checkScoring + // ---------------------------------------------------------------------------- int CaptureTheFlag::getRedHolder() const { diff --git a/src/modes/capture_the_flag.hpp b/src/modes/capture_the_flag.hpp index 9d1af4579b9..89e8d880ac9 100644 --- a/src/modes/capture_the_flag.hpp +++ b/src/modes/capture_the_flag.hpp @@ -20,6 +20,8 @@ #include "modes/free_for_all.hpp" +#include "modes/ctf_flag.hpp" + #include #include @@ -37,15 +39,12 @@ class CaptureTheFlag : public FreeForAll { private: scene::IAnimatedMeshSceneNode* m_red_flag_node; - scene::IAnimatedMeshSceneNode* m_blue_flag_node; scene::IAnimatedMesh* m_red_flag_mesh; - scene::IAnimatedMesh* m_blue_flag_mesh; scene::ISceneNode* m_red_flag_indicator; - scene::ISceneNode* m_blue_flag_indicator; SFXBase* m_scored_sound; @@ -71,6 +70,8 @@ class CaptureTheFlag : public FreeForAll // ------------------------------------------------------------------------ virtual video::SColor getColor(unsigned int kart_id) const OVERRIDE; + void checkScoring(FlagColor color); + public: // ------------------------------------------------------------------------ CaptureTheFlag(); From 57a80c209a12a5a54b5632053ba6e1a443fda143 Mon Sep 17 00:00:00 2001 From: Benau Date: Thu, 23 May 2024 08:43:52 +0000 Subject: [PATCH 411/830] Fix possibly missed dynamic spm buffer rendering --- .../src/ge_vulkan_draw_call.cpp | 95 +++++++++++++------ .../src/ge_vulkan_draw_call.hpp | 16 +++- 2 files changed, 82 insertions(+), 29 deletions(-) diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index 0e2b90d1e7d..3eb37616772 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -252,7 +252,8 @@ void GEVulkanDrawCall::addNode(irr::scene::ISceneNode* node) { GEVulkanDynamicSPMBuffer* dbuffer = static_cast< GEVulkanDynamicSPMBuffer*>(buffer); - m_dynamic_spm_buffers[shader].emplace_back(dbuffer, node); + m_dynamic_spm_buffers[getDynamicBufferKey(shader)] + .emplace_back(dbuffer, node); continue; } m_visible_nodes[buffer][shader].emplace_back(node, i); @@ -1378,19 +1379,20 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, const size_t dynamic_spm_size = sizeof(ObjectData) + getPadding( sizeof(ObjectData), sbo_alignment); size_t dynamic_spm_offset = 0; + + int cur_mid = -1; + std::vector dynamic_offsets = + { + 0u, + 0u, + 0u, + 0u, + }; if (bind_mesh_textures) { vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, 1, m_texture_descriptor->getDescriptorSet(), 0, NULL); - - std::array dynamic_offsets = - {{ - 0u, - 0u, - 0u, - 0u, - }}; size_t indirect_offset = sizeof(GEVulkanCameraUBO); const size_t indirect_size = sizeof(VkDrawIndexedIndirectCommand); unsigned draw_count = 0; @@ -1404,12 +1406,13 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, if (m_cmds[i].m_shader != cur_pipeline) { bindPipeline(cmd, cur_pipeline); - auto it = m_dynamic_spm_buffers.find(cur_pipeline); - if (it != m_dynamic_spm_buffers.end() && !it->second.empty()) + auto it = m_dynamic_spm_buffers.find( + getDynamicBufferKey(cur_pipeline)); + if (it != m_dynamic_spm_buffers.end()) { - rebind_base_vertex = true; for (auto& buf : it->second) { + rebind_base_vertex = true; dynamic_offsets[1] = dynamic_spm_offset; vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, @@ -1419,6 +1422,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, current_buffer_idx); dynamic_spm_offset += dynamic_spm_size; } + m_dynamic_spm_buffers.erase(it); } if (rebind_base_vertex) { @@ -1451,12 +1455,13 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, draw_count++; } bindPipeline(cmd, m_cmds.back().m_shader); - auto it = m_dynamic_spm_buffers.find(m_cmds.back().m_shader); - if (it != m_dynamic_spm_buffers.end() && !it->second.empty()) + auto it = m_dynamic_spm_buffers.find( + getDynamicBufferKey(m_cmds.back().m_shader)); + if (it != m_dynamic_spm_buffers.end()) { - rebind_base_vertex = true; for (auto& buf : it->second) { + rebind_base_vertex = true; dynamic_offsets[1] = dynamic_spm_offset; vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 1, 1, @@ -1466,6 +1471,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, current_buffer_idx); dynamic_spm_offset += dynamic_spm_size; } + m_dynamic_spm_buffers.erase(it); } if (rebind_base_vertex) bindBaseVertex(vk, cmd); @@ -1480,21 +1486,16 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, } else { - std::array dynamic_offsets = - {{ - 0u, - 0u, - 0u, - }}; + dynamic_offsets.resize(3); bool rebind_base_vertex = true; - int cur_mid = -1; bindPipeline(cmd, cur_pipeline); - auto it = m_dynamic_spm_buffers.find(cur_pipeline); - if (it != m_dynamic_spm_buffers.end() && !it->second.empty()) + auto it = m_dynamic_spm_buffers.find( + getDynamicBufferKey(cur_pipeline)); + if (it != m_dynamic_spm_buffers.end()) { - rebind_base_vertex = true; for (auto& buf : it->second) { + rebind_base_vertex = true; dynamic_offsets[1] = dynamic_spm_offset; vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, @@ -1514,6 +1515,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, current_buffer_idx); dynamic_spm_offset += dynamic_spm_size; } + m_dynamic_spm_buffers.erase(it); } if (cur_mid != m_materials[m_cmds[0].m_mb]) { @@ -1541,12 +1543,13 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, { cur_pipeline = m_cmds[i].m_shader; bindPipeline(cmd, cur_pipeline); - auto it = m_dynamic_spm_buffers.find(cur_pipeline); - if (it != m_dynamic_spm_buffers.end() && !it->second.empty()) + auto it = m_dynamic_spm_buffers.find( + getDynamicBufferKey(cur_pipeline)); + if (it != m_dynamic_spm_buffers.end()) { - rebind_base_vertex = true; for (auto& buf : it->second) { + rebind_base_vertex = true; dynamic_offsets[1] = dynamic_spm_offset; vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, @@ -1566,6 +1569,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, current_buffer_idx); dynamic_spm_offset += dynamic_spm_size; } + m_dynamic_spm_buffers.erase(it); } } int mid = m_materials[m_cmds[i].m_mb]; @@ -1604,6 +1608,41 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, } if (!drawn_skybox) GEVulkanSkyBoxRenderer::render(cmd, cam); + for (auto& p : m_dynamic_spm_buffers) + { + bindPipeline(cmd, getShaderFromKey(p.first)); + for (auto& buf : p.second) + { + dynamic_offsets[1] = dynamic_spm_offset; + vkCmdBindDescriptorSets(cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, + 1, 1, &m_data_descriptor_sets[current_buffer_idx], + dynamic_offsets.size(), dynamic_offsets.data()); + if (bind_mesh_textures) + { + if (!drawn_skybox) + { + vkCmdBindDescriptorSets(cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, + 1, m_texture_descriptor->getDescriptorSet(), 0, NULL); + } + } + else + { + int dy_mat = m_materials[buf.first]; + if (dy_mat != cur_mid) + { + cur_mid = dy_mat; + vkCmdBindDescriptorSets(cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, + 1, &m_texture_descriptor->getDescriptorSet()[cur_mid], + 0, NULL); + } + } + buf.first->drawDynamicVertexIndexBuffer(cmd, current_buffer_idx); + dynamic_spm_offset += dynamic_spm_size; + } + } } // render // ---------------------------------------------------------------------------- diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp index fba35fdb95c..f6be7ba0ccf 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp @@ -115,7 +115,7 @@ class GEVulkanDrawCall std::unordered_map m_mb_map; - std::unordered_map > > m_dynamic_spm_buffers; @@ -199,6 +199,20 @@ class GEVulkanDrawCall void updateDataDescriptorSets(GEVulkanDriver* vk); // ------------------------------------------------------------------------ void bindBaseVertex(GEVulkanDriver* vk, VkCommandBuffer cmd); + // ------------------------------------------------------------------------ + std::string getDynamicBufferKey(const std::string& shader) const + { + static PipelineSettings default_settings = {}; + const PipelineSettings* settings = &default_settings; + auto it = m_graphics_pipelines.find(shader); + if (it != m_graphics_pipelines.end()) + settings = &it->second.second; + return std::string(1, settings->isTransparent() ? (char)1 : (char)0) + + std::string(1, settings->m_drawing_priority) + shader; + } + // ------------------------------------------------------------------------ + std::string getShaderFromKey(const std::string& key) const + { return key.substr(2); } public: // ------------------------------------------------------------------------ GEVulkanDrawCall(); From 3d86d937695bd8d1056d14d05bd867ba876a0614 Mon Sep 17 00:00:00 2001 From: Benau Date: Thu, 23 May 2024 08:55:08 +0000 Subject: [PATCH 412/830] Use forward enum declaration --- src/modes/capture_the_flag.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modes/capture_the_flag.hpp b/src/modes/capture_the_flag.hpp index 89e8d880ac9..1a830b6c9e7 100644 --- a/src/modes/capture_the_flag.hpp +++ b/src/modes/capture_the_flag.hpp @@ -20,8 +20,6 @@ #include "modes/free_for_all.hpp" -#include "modes/ctf_flag.hpp" - #include #include @@ -34,6 +32,7 @@ namespace irr } class CTFFlag; +enum FlagColor : unsigned int; class CaptureTheFlag : public FreeForAll { From 8b4741133d7c732f4deeb893aade0316c1d39821 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 27 May 2024 11:30:17 +0200 Subject: [PATCH 413/830] Add new Desert skin Variation of the standard theme using a yellow accent color, by CrystalDaEevee --- data/skins/desert/License.txt | 8 + data/skins/desert/achievement.png | Bin 0 -> 17735 bytes data/skins/desert/bubble.png | Bin 0 -> 39491 bytes data/skins/desert/error.png | Bin 0 -> 16419 bytes data/skins/desert/friend.png | Bin 0 -> 16912 bytes data/skins/desert/generic.png | Bin 0 -> 18043 bytes .../desert/glass_iconhighlight_focus.png | Bin 0 -> 25921 bytes data/skins/desert/glassbutton.png | Bin 0 -> 12284 bytes data/skins/desert/glassbutton_focused.png | Bin 0 -> 11653 bytes data/skins/desert/glasscheckbox.png | Bin 0 -> 2334 bytes data/skins/desert/glasscheckbox_checked.png | Bin 0 -> 2428 bytes .../desert/glasscheckbox_checked_focus.png | Bin 0 -> 2915 bytes data/skins/desert/glasscheckbox_focus.png | Bin 0 -> 2635 bytes data/skins/desert/glasssgauge_fill.png | Bin 0 -> 4991 bytes data/skins/desert/glassspinner_down.png | Bin 0 -> 11409 bytes data/skins/desert/glassspinner_focus.png | Bin 0 -> 9280 bytes data/skins/desert/glassspinner_halo.png | Bin 0 -> 9965 bytes data/skins/desert/glasstab.png | Bin 0 -> 4615 bytes data/skins/desert/glasstab_down.png | Bin 0 -> 2626 bytes data/skins/desert/glasstab_focus.png | Bin 0 -> 2947 bytes data/skins/desert/glasstab_vert.png | Bin 0 -> 3489 bytes data/skins/desert/glasstab_vert_down.png | Bin 0 -> 2599 bytes data/skins/desert/glasstab_vert_focus.png | Bin 0 -> 2676 bytes data/skins/desert/left_arrow_focus.png | Bin 0 -> 2447 bytes data/skins/desert/right_arrow_focus.png | Bin 0 -> 2556 bytes data/skins/desert/scrollbar_btn_down.png | Bin 0 -> 5201 bytes data/skins/desert/scrollbar_thumb.png | Bin 0 -> 3461 bytes data/skins/desert/select.png | Bin 0 -> 1862 bytes data/skins/desert/stkskin.xml | 340 ++++++++++++++++++ data/skins/desert/table_header_down.png | Bin 0 -> 1862 bytes data/skins/desert/textbubble.png | Bin 0 -> 2607 bytes data/skins/desert/textbubble2.png | Bin 0 -> 2635 bytes 32 files changed, 348 insertions(+) create mode 100644 data/skins/desert/License.txt create mode 100644 data/skins/desert/achievement.png create mode 100644 data/skins/desert/bubble.png create mode 100644 data/skins/desert/error.png create mode 100644 data/skins/desert/friend.png create mode 100644 data/skins/desert/generic.png create mode 100644 data/skins/desert/glass_iconhighlight_focus.png create mode 100644 data/skins/desert/glassbutton.png create mode 100644 data/skins/desert/glassbutton_focused.png create mode 100644 data/skins/desert/glasscheckbox.png create mode 100644 data/skins/desert/glasscheckbox_checked.png create mode 100644 data/skins/desert/glasscheckbox_checked_focus.png create mode 100644 data/skins/desert/glasscheckbox_focus.png create mode 100644 data/skins/desert/glasssgauge_fill.png create mode 100644 data/skins/desert/glassspinner_down.png create mode 100644 data/skins/desert/glassspinner_focus.png create mode 100644 data/skins/desert/glassspinner_halo.png create mode 100644 data/skins/desert/glasstab.png create mode 100644 data/skins/desert/glasstab_down.png create mode 100644 data/skins/desert/glasstab_focus.png create mode 100644 data/skins/desert/glasstab_vert.png create mode 100644 data/skins/desert/glasstab_vert_down.png create mode 100644 data/skins/desert/glasstab_vert_focus.png create mode 100644 data/skins/desert/left_arrow_focus.png create mode 100644 data/skins/desert/right_arrow_focus.png create mode 100644 data/skins/desert/scrollbar_btn_down.png create mode 100644 data/skins/desert/scrollbar_thumb.png create mode 100644 data/skins/desert/select.png create mode 100644 data/skins/desert/stkskin.xml create mode 100644 data/skins/desert/table_header_down.png create mode 100644 data/skins/desert/textbubble.png create mode 100644 data/skins/desert/textbubble2.png diff --git a/data/skins/desert/License.txt b/data/skins/desert/License.txt new file mode 100644 index 00000000000..4f64d57dbdd --- /dev/null +++ b/data/skins/desert/License.txt @@ -0,0 +1,8 @@ +friend.png, error.png, achievement.png - Licensed under CC-BY-SA 3.0 by Magne Djupvik (notification_backgrounds.xcf), + based on cup_gold.png licensed under CC-BY-SA 3+ from Open Game Art (art by onyum.com, comissionned by Bart Kelsey) + glass_section.png licensed under CC-BY-SA 3.0 Unported and main_about.png licensed under Creative-Commons BY-SA 3, By yeKcim (Anthony Carré) + +This work is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License. +To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send +a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. + diff --git a/data/skins/desert/achievement.png b/data/skins/desert/achievement.png new file mode 100644 index 0000000000000000000000000000000000000000..367182d6b7729757329700ec41077bc04e73c8e4 GIT binary patch literal 17735 zcmYhicUaQz_Xqq2QE}x;#f>ZLlLJ$8q=MxtQ?vS%=GIKj+?rc)rn$2mIj}UfuRG0c z;7Bb^92Mr?dv6foq0jGmuIu>&E_ica+~+>`+2?iQ?-=W|F$*vQ0Kj(BK<6$1fM_29 zG?an%zVNx>?+*|sZ6j>}s7YZV+tJg$!yOFn8UaAi1=_l303iKczXAY$2mn~K1pxId z0O0e?Z8p`Q{lMgDVD19|=Q{tsKs_F%k7*AXeQz4+GR}j~u|O__$Q$&~9>IKd&3x~9 zJn{9n^L7M0?Ofb_<=h>8;YxA{xvS(vhiL%NiM^?#eLui@GcUB<{h`%zli0{g1xHdV z+xzpwk1pR4e2G9OE02iH_!hL@e~iky`*qOJA?^0uim1BclYYcir8i8E4OS*@s)O5+ zrOKZ(hdXzMJ9MklzeDr}wHdh1Yok0I>T=C7p+`>B+qDB@`0>Djrsbw%wQnl;sdcxi z&qv#*R@l!+W2YJ$|9gntEx%4Y)t@HjO%qSHPm;GAZFvf0zCW{ajbi&P`~&Bwov^V; z*6-WS!6T_F6=i^9p8r&!wCihE54Y-eyY4gz_Leg87e>Lblg^Y@uF8$MJHno$rWA(Z zhHqgMH+pI2dYpvFZd}DSWovsXX8UYvdvoxmL<;fr)2;0E_nt$#e3R4#X(TZ`vPA3f zqeZ55&}zi&r#?B?Sd44wsTe+Uwa{;!P;*2bl;WFa%ReY$nX-9y98g2ZX-|{TPj1gH zoc5a{(qUd%zTlZJLK;2)#`010xUt7gbC$_uG-!?+(@3u^-@4Nw>$&@t&m?BG_lEWN zg7WjsmA`Cix#`#TK4rFTu-hE|@8Kj%*eqX|-TG*a!)fw*Re0!&2NO+@(|3B8-B|jT zuE~_HvsbolIhnNXy`er`my!?s_PZ8ymgsL+5{&20gCcol4+ZvH;sh&5P<+&GW3{lVj)pczo^~9mb z-#2rIq6Mo?06p?-kFU*&b99%Xc@;OGBdNhX zYDE5)rganFD>EzAqEkZW8Gh%>dS#3I`f@mB`I^*EWqp1N_<-+%n7rd1UdMk}Uq(iv ztnRWt#iQ#7FBJ1Y^#}f3H52AodT`P@>Pk^$TTd}s138q8%05rDx(qg^H-kNUwF_5B zI!P?&kiLm`mYFqG`*zO7hDsu^M}L`(6>PTYcs2U!nqA|nOwSdW7fLU|ga;g@_g;eh zD%-$gOC9f2oU6?KRa-wt5*xau$QJx97?ygd4?R!Ea0#7c-w*)4%^1Y~*@Cvs9(+)o zA|Xob{nS zUX8)^#ObGq=)$j#+J3+-!Q$#}=m5b_)X{BQGOYRGt)nx+Zx<#^>f&q$IWhG0LYrbz z(Y{3{!*onG+#K}LAsP&Uf3V~)n-5!0c7?4EhkJYjzWz#ii{qFokzfz}$l_@FL>6T^ z9(0i*h~Z~;bIC*0xU+=YhaZ<9iw)dSY#EFx?%J2#MK+YF*?PY*HX3(yaUZX^f=4ge zqeJ~qA&(>{w^o7O^dZ5eSY&hU_a2^OvFh8`+gwP zOZKt){*&BUT-{-fOT?g?@F{||n1 zu{RQJMJ3vuD^uJDd{x2yN7tzP+!qWeX~$YFrwga~t)bLBK6mQwsr&>5Dcb6JYJxn7 z8V}!lm%!+GE>42Y<=YMG0@XWL2{4^^0nGn*^1t^m68i|6E3hB{3cWrZvUu6%PtZ;~ zV?%vI15IsQCcOJR{H-tN19Zvj;D8d1x7~U*<8+)ruT5eIp|q-{stnUb_}pzJ#+oUx zC%MZ1j=w@mqp0HMRN86bqW?`Z2FGHAr%`1^CMvH~(66YHw%>U2BdD{Yn}-q0R`Ysg ziUcJ5j1Ybn!FJW`eE8wR@L%yjK6(VyY61b+0T9kmlLG|ZV=oMAJ}o^T{mx!_m&xJr z=08(#O`Yi1Tw(Cji>vbH9NE&}nY3ZtbZfUKU2e!iqKBT0<&Q)jFkBU{ZvS-Bt@34v z3AiWvJA(sgHKs?i-OykgeF#FIeD0eTIP}XI`IULH;h1sK|IGvI*CUmAFrt4VJV*J{ zhSU&Br;J!+-u~*OMSd-YK~N=0>#x`ERobJ3KVD{e`7`h8MTnZRr@G=2+n^KnI2d~z zf4YsON(hRL+H!`hTTHJ(WTO#+R=21;b zoA4acJ1wCw|bPIq9uO4AWc|e=Ol!;YdTj%xZ zpU4W(C!5YajOL@eDYemq83T#m2-AD=y=VhNT2AqpTjSFRGBY5LZf^(BWhjEGh9uVQ zCUeDqUdIW5+$zRxg6VQDwKMe1c~F)--hzQye$OK}W<&y6O?rTnqtgk*=6xO2tFBFE z8s6pzw^usX;lsKrCZ9@fT*SA`4UJP5%rl>1cVgs6DcP8&C*Ww!WwlHX8_L1xPRSrol(B3bTe@gJmwkh|P$;xo0ihRL&$qGhv=YaNCGy^tZXjTFsw zQ(<^3?sNEIna!`Hy;SNpm9lL}y-f){9iQIPnf>cTj%pkTNS%BcI*qeW3D@ijLMrJw z=pou-gNi6tb?p^hcuc_&!wL&2`pdhNmCFQrXop_*8?$l)@mAHvLZNZM)h0L?t z!D&{@Axt~_^$+DnUh#MEi;y_3&B&R!_UMO*I9xKv3|neO{m##*zq^-N3Qfe}7!qbs z5L=Nw#Rk8K1fMxLR*s4yN03Y6+3h5?B<+fN&Mr_>kjtm)!;1gRSJuWcYEM&+8vGVy z*|zn(ErWKy%7@kX9P+RBQ2v@s#j2Ch9xrliHzWk0-A zyr}pFXJN~k=112W74ixd>f)hgRLaNfrYIP{!c8jXI8_aOlMwY8y3heXM*p}jdt-EF zLdR7UcZ(i9gb@x)G;11@Cwf^46Vu7hGTrdUCh4M?e@sO)$8{d>wVh0~$LDM~1oFgK~gKv08HuY%fuL+@<;F zCc2Z`llZD5PDljo6ccI-Vwnxle6?@hI^JCwvriDTd__*2fjvL{Ls_^ks^jIw>i?Eg zbWU;X20|}LZ~9(Lz<%=DDX|20N3;uSdObHQ8KG?FCazl`fpv}pLUqO-K`gmva=$#s z0LQk9JfrX$4-wQWEO~0NrCY|Dn2X_g##%!-2!^6I44tMOE~;l2O|N%=siK6NTQyCwJTT^7kMU`r6an%kSZWF;~|?g6GS_ zm~ksM_|r?TWh+7+1M`p&a1Oi8QmuDt@D^LA@{`Ap>4h2y`XOBkB*n<#H^Xjb}6YgX3exCVs8*4$v;3&S64yq92G9pD8O82!hm zv5hBEq)6W*_E25SkpGsV0cSzgstx~8KtQ3*I z9r2Vk`|GudfcihoaqZ;MAIdP~e(0WdYVE%O%_$zlGq{zohva65>R>qk+Q$V$&I0^u z@D}Je(!WjRUIbfExjS=eA-0UtOc~IxYMgtS{z{baCP@KSrT0S~|6Rei0G_L^OcXy? zIJItl?9-`8tc)eU{AIpdn5c-=@3)eo|{`#xpWl{7)Ye?)2Uj0S*~5@y z!sS7YWP7ofX{DA6l3-kG1}A$V!?X0o4+8lyr+ciPl)itEdUD^yV&2cjiW+>X4Cl(N zH+X_^9(>ZV5;dX6x^kJ6_@$72(}a}ad!QU@Jnh5Y$Va>n=Y^7{F^ensVqyK~dRlriHm|?+M7Ao;Ux!JE=&1f{X%`2ApIcr(IgzKHS01~b z^GtNPF1vn&@gPQ?i#VF1Rk*!!xcYnMsAC` z6;=G-Ho8abr;rszQnFT&{OY~Ep`HW3ZF=8hTt&x3&H`)IA=s!jjD5*GZPZ|3SO?M&_+RF>*G;HM8Y z=wN%9(pl2N1MoIwE$@}3UHQc3(Q!8GD6DlH@8qkOJiGtF($e-p?+@&NJ9Si)CTAMU zC4Wz47)DxPIi{{0@oD)5`roE$h(l=K{fIC6sNz7-qKJDd+J}{aNig3#$hf}cmpCthL zeP$rEPjkllr#0@0?99a1{NI50!E*Me%hbn-Z>U?RXB$q-AKp9y%*yRwceeE;Eq>s$ z92W*PhA_6h+rQhtUU^25lXXO>ESam8Ejaaw!`Cs=_<5ybb z+*S=qb-Vy6KN#0G$TB0cO7FRS^%Ojyxv}bov%kodosZ4QHdzzkf%@(xl(1{5^bAsTL#2kfb|J$*Zkf3x#9?oijY8~ z6ho`}TQ){QIhj@Ck73wcr!bT%Ja;-#qWoV5M+@U66Ar@D9+}jVH}dNXHGX{#`*I^; zcW!%nft+P2vyVQ_Cp!H|lqpACBkk+jSbHqy>dNMuE8=B&_(kZKLK-YsSu+V~CY*!Z zGn{EZcH>)NRpeZF%6}Mw{H61nTtle}t2!{^h9EdPT%y3A0o(L09%5z{UNb|8KeKvH>qu;emn3rS;d@BCS z(TP&dzU()u0Z$>!Wvz1zsFjW+xcEti|=pK>arBJyvy&GVlj3NuU%?r578@v3TcYJ!cvWhnA0;dDtv-7ubi%P_KU7|4ZI z?MMfr1(&_Ja6WTtB^m=Duit9g*5N-q_?ILGs+)!8pnSy*t%f!Ka_)$92^EVUl z*T>XIgv$ef*lY5E{9mt_Ss680k~`8vv(E!7_y$N5;{^BKl0E#`eM||Sq`;P9!^U2C zMYu;`4R)n1@Czj=Pjx^vWT#zDrf(_BRlr>nAeI_t^zF)|_JoM{(OFB6p#40Mj_0{8 zZv)*E;e1rjOW)Az+0zF-(Ch^Dr?c-#R|Y?Z^)fI=@DdME&+A3hHTWGbk-{Zdkvl1ix~Pl=|hs5l+hb(tWnPZy$2!ygd3pX})N~ z_1y*4)WAIgurWuq_ad$)rr2~SJxWU64@5oMcMK4?x|ma`<<41fj!_`kdZgMnPm$ea zeHE35@##~>%_8LvEX<%1No6ya zz{|P7dC&fIv?MZA$7aasNHp{&W>~st)*?dY{Bu#*CiY@$zY^duWUC`k9!tNrV-D+c zQY8$hs$J-J81YITx&as%HUh!_<*al>K;3a^Ac70dgy1ZSrzaezp6 z5YGu1ya!PEv{*$F8F~D_ha2T5>B+PdqSugSnhvBw#||x49Z1aG}Yckz9 z+oM&;9-4b=dbnqDu+BB1%WY0_WA3;!43~mn_oEwZAE8YNv*rvvhfRT{ zIg1>XcHB;?@K7tgj5oAgBfDwoVcl;&jXltxw$vGt5qwyHkf zvS-M^1SUB-pn{0ZxuyEV{o6!3)pCRjVCCerb-$&)T>IIu%x>8i#c8XK+x`Ow>UgfV zNRe!?q;KQ?QxpfErn5i#%pdl{dbfjlh#uXI>=S~+HG|(Z=ckM;7;#xoC1eO9iMs`9 zI)&$Mg6G(3r(DQOeFt26Sy;V13}W3k)$HHXoA+*e27+)gkHx-Ch9|bPD#s0pcSSUtb?o(s{BsWloHkgK>daeOuT^CDjowE%qxZi~Wi{ z7ua1OcCRz-ia+lEeq3|TFI#zyT(tbwPc7F;utaR%Y(V=nrqMomxlX)kvT2%Z^|QC;$GW)l0E7(`&@&$H3&(~Id!KG{ zf5Qltj^4@>A3O~Gd=96C4qj46Z87%7;IQOAY%T)Ms{gR*oZ);$l2sO?Bq**{sLwf~ zahTCcYhQA$&bm`QoskPB*Pr7k^@zByzWzIG?j@7l0w_@q*jw*I!U$P_Z=vb-+hV9~ zV!~}kgT8w60RmCMmKoT*KFXom3L3jwA^(aj^Xl9JHhei4#Egq(95kUbW1O+}!taUH z^MXYKW+H+|N~2@n#3rS^Q8$hz48lNxYbUMUN~*8Cav=q*9iX0@kqW7?dy;x=l|$bd zKTWOw4C_evYbTljgN`5&2f=F$Z0m$>Gkj^cH-Ka)gEqFXb&BMitA;Wtz>(8~PO}M4 z(;LwiJynoPK){tcra{KKn$I&2Th5y7p2BHv;b40Pv_cQ>qGv|AilqjRdqBsO*$gDg z@QR5xoloobk|OHjm4fCpmq)K8aTk5_F->m|$#BRj-RFMNtX}@c`u|q^+knlQA&Wvx z0W+y53o{j0kQ9Y_5EQhM=&l1GekyRaE}DOz<&#&c7L9bP}@Cz9Qu@Ga;uWE zF2KNEfB{z<^d(%Ms13wGY+rLlIV2hTKbL7`@DfnNnXyUB+XV`z#4i)-91OUAR?7_C zqHAPe$&-8j$bHG`_~@RoLi<+;ToiQ0yE>8;rUu{YI)^g`1VnIf0JfS8*fzqvU!oIi z6Jsxd!<1iGd2ld*(1>*zpe};e9Kt?-y+GLXNDDtPM#+Oq=xsy9Ql&x9c;92rw1AoX zdPsqz0n9=GQQBz%H}*8nXFZD_oe?L~7D!g+R<&sIRa$6lTtYFcE~2h+$lOMOAXv`UODd(Qy8?t;WJr z=2VNqP-JAI?`b;OJ#NkV)!KAME(h8eGA05XNA*-sstA17+&3)%-$62yXqRabDon zGA!3_KT^YC@iVFwGK4d97Vxk)oAOT@ zTY()gQ-VH>9iO65yd;71q~?J)peXGdfX-H|j~$|f?p1W?0S9AdU>>DZzH0lrw_YG7 zXjE=8j8^u&or^pZp$WnTFWFN1o^LSJn=4oruMGd`mS}=En83rw@No>|^^_&^c%`&F9>A_Bn00 zL8>GSFM5(DT;Q+OUS5BAjxSS}7_V_5^qikz02G=2Vu)9WPt4)VFwJzcyj*@^RjFv! zB+4a0mhCY6L9(AY;mGHQeJm|db>*{_1@@nT1-OB4c#j}}qn#ev3tAOxHR~}#Re}b2 zznNHAPJ7yM$ZUY>ASm{NIGhH!x>j&!r9zA0yvq)ZOYft$Y}5mOmlbley1PJ!hNwh2 z{D+3~;ymd!-Xkxpd@JGozunq(7>%#2CCtD`M;iw)=HpltHTj=x>9T0tX9Ke|3ffpa`DJxeq%d zA7S0SjRYvHWu5HnqKCe0Q6+q-Q^;{`jsK&^>xZHI3Q14iHiOYNe0gP>>+gY>(Xm;$ zEG0Aix>D`nKN4&Nhq-db;-54)`mE<96EBQriGPH6&3zvNSY{X zwk&W>+%TNo6@a4J#Zy3&&?2uT1%?&HWyxCt(@M^buhS$;=i}28tusB7V*(%b`eskr zd@s{hCE(Y8!zY{TF`p9Rjd*~g*bOdplM2|#oNkme;tv?-fUrJFljOMme#b)neS*Vf z1dRJ-=aIg!-)`R6V8$~+7iUE;8VL$1fUo#q6E!IhT>#y?A{gLx`Xo~XIBFR?fS@L*jzN34MX3zH}O1hQ^VTtG#kuw&$SX% z1nf-V~Cmp$bH`c+Ur7cgN--Q;1hOGIl3zFv_5(+m5e0=nbj{0wiSUTi$RZGF-3w-rP^0aP;CvL>OVF{^=aG+In z|7*I}O%k!=XmiL$F9tlAfO;kBTNrK(`hI4%`l;*EkJEsab3S)@0{LH*) z=xwr1XJSKtvvIsknQj28@qH@c)d~t74cs!8%C?wz9M(7 zAa4LG%Nc-Y${Lj&*S3&v4^*&6$9-Y53Mf?Hw2vx>ytP!S4W&uQM}VtDZC?Y={eVxf6i!S`?7d6mKxE+_dh`Uw$oW6LFGMxXcp zUErtrcR}!`)n$LLBSa2?zK0knJMuq8i>iGj*QGU2V{ZFLs8?E*kA z{1iC6hR^it;9Aq5qENqaXyN8$?zAk9#hq@8!xgv$(4rb7Q*7Ge^*6CyUXh657Gv9h z*rY|pkVK%^5d2smtfbvF?ty@!{bK&9>EIY*Usd}NYiJ_i*9g0uQ&+sKG7m>D<7g2U82#Wa z#PL<76kwemBx%raZnMYd;srH7PS5MWUhPa1ADUj$l72$p(pO8ZZQa!N2Ef3%lJq>2 zFBLq~OW>Y0#Dq^BWl|4_<2Iz)@FC$F@Hoi3EM$xS3__C=O^)Nb_d3U&R1x13#6jt^ zY5d;}LUCke=m$6M1^f_}5771DKtDa$CRwl-OfYW!sKZARf&s)8bYI+%odzZ7wg$t8 zYj3^cS*w=2`7>SO@SZ6@N@jhY1+cAW9QIW|5b3M!R}Z(!e9%hNjm4}Uaa;F$tATb* zZOhPr8sbG{n9W2l!WpHT~W%3J+?i=l1krQR%L5>s_cANK?vvJ zU)^$z$%hi`tBU1sdR*hwv3{T;n}(zG`mDt{n&vsIhO_-X0D?d;9ox4wp@OS1$QKmk zGyfF#yih{dOwk}Xz3gx>oD5%^ObZ)ZsiKik69@bZ1}4D$w7hu{3_q?50~c`Gp#-eh zl2{WzxY!ARE;@07VGQN9)$V8wW_0O@lll7r4=a>)R2{zxn{^A1zS`*@T6W`dl^!iS zJNh*m*f_*Q8Rsz+@u9UZgJI3$9N>+8?CEB7D}#%oyFlyn%gNs7 zq5zKHOekW``gBz7xxooe*a-R~&6=SlCg8wJTpZAU8O*rIkGM2bVo4xq12G}e3eXU4-cvOO0t zdSUdqqhH_x*nlF5ePNp(J{i7cYCPHaV#081^=~KNmx@HwPUX;@wF}FNRbwj>+thHZ zpHuctb_J(?i6z_uKQ_yo`t-@jFKiv$o9?1mNk1GAx>rAJ_T=&u$*c9*DUDS71@dV` z)(!`=F)2Scn%Uo!=~12i4D1%+tJT{AU;Qjr#uD~|%pY`rMqEDA{*2Aqxeu}pK8Xg< zizT4U+X0|F#=&4v6i`I78#LLwc{d)2ei{!z4)VZykF~!3um}k8>}+5aQ&@)-ED9Su zAAyT3^r;+kz-(qBPB@a~i9db9zEuJJh7@f;ueS0?k_4MZ^bO*rsh$-hBYm_|12;>}xL%h0G&H;Kb5x7yzfsnPe9v}gNJ|`;ksW8GM zyWi_%5goM60F!jSZyaNxCh<}a-|LGQ*)Lqvd11=L7o;PaNaKz^0FpFis;(+#MsZqB zgm39qQhaFTY{d!c0386c7NJWtehfnte?R%?vIy5t(! zPksMFA~JDP^i&d-az?{Ubr#dE9o|5n{>>_)_1|tK+vD~2T3$LnOBN`n0oN~aoQEM4 z_AXmsrdaXmJP#sr{>w6UWiG`gE`@;7ST(51F;Q!##s7ZZ3EMDQcUkY74GT_gF9nK1 zlKyrX10=ps@igOOV9Swt#j)}RoY_U zz@eMIc%S>CbcoeBUQ-X)Dy3+ug3&Kj{{i47pb$}@0o3WOkeb4Lm%~Mmk4|5gR^B3U zdWdiu(6FoqiGh&R%ppNMaQ%j-ULgI<{cI7$oZ@i$K$=MP2bFjeqVlTL7lS$W1rw0L z-Z9wLreB#ff<0T=UdA?>ObGH(L(VdTN4=>ah7Uu)fP!;px<>Xn=ZXC;0>LFhX#^Fh z{3!&Af*q<@{v@KT!j_hE)g39#U!s2qdIXN7`ng2xJ$+0x4^QSq{}w>)7ZzNi>3gq{ z_TzFsI^s^(ZFyUJ*@8`aR`Ee@dwxy>@nVi@Js{9)JP;{LtHm7uvZu#|FMONVU^20u zAiH$Y0_Z{tjK~ODiSfuKr;Ab{R#;wmeHb|^I4vQ3qU=&mxX@XS2s-xbcGhn8Rc*84 zkMqT1BfsI+^Yzvu4jWwg2t3=q%Dz;qUf#6Nydt~vuk7mE_j-(O6jx}I-)~N*)2_b2 znzhT#HrmdQ_(HDfWGk>0z4Qom10vZe!)f5n7QLTm{Db|T{Nc6 z;o;%3Kzbq7WpBB6`p}hglzfm`h`pz@#dDk(+_Qpjdwj5+6vP1}F-eTGBQT3Re-yZi zv@O_qKM&6+IEOJ6whBa>+{nv!mGqLimgYCX(m0jvj9lEf2@JE?LhK~%Vw#S?7XkSK zqE5kEW|}+Va>#(96*ysW<_6zal34JR5Z?V!rLGXs;nSY`XeV+{vK5u%9)zZEE=gqN z)fU&I!z?)VFfX0v91j*A0vjzs2POEtQ$iv2bp=+9#12NM*(m{OgEOkjqiIr|PVEN* z9~XBFTd_s8Ap`r(XwN?Jkhs%sm1|~UTpb7Tw4!LFI@YfEZ^TfXbx5*# zFDs9e25ST_@!ZeXH3^o<5-*6jHunLLxeSKi{KHwx!NavrFQRvg_jrwn4A-DK&2zLc znM?Nj6Qx2DP9~M-NG$2dcw}n$@d`2k(7nHEK^h~3H8DCAhHH^Jdtcho>|poTR@10` zn8aLW$bhW!-I02f2HYn6hnPvm*{`b2qLSMp7HPk)bf+F}?j1{>=!LV{g;qo%!ZW^l z(aPZA-<$%AR6T?1&X@Ei^>D=SkpZ(Oc0%*~3%16}ds5=%AjL&62`1O9$36(|s{2)%bNHdzSUL+Ld zFvY&oGmPofN0OE)TSI1^ThrQ|-L~DV4+ zi+7?BsuWYe74`OYh(G(4eS;JtQc^xowVz7#k>Fs7Am&lr1@1r|C!PdO#*@%$H0scy zh^u?Y3;wfstMG$1k25cmrM%MwC3qS`|E@Kf(;|bR!Yf!7&mDNCv8>v8TRze7%1`*z zC*8d1b;q}ksg90Bbn`->cok+@$SG?z#_P3JfAb|^lt~m~SJitPWFQa6KpW+8lM%4| zoT%83C~2TY7uBgH3$#HG3TH~8(H#9;paC(t1*d~$PFwvo!kMKC6;F?%W^tWpoBRgl z`+qHz)*?)jlQF$PKf5rxH18QnZUb1~o0F2i_>QpC+N{f(Gx@5dWBgf3G6hv=*EPe3 z66!DvVeDk}PyPe;D!K_4aB3v%zKtdnHF`3Fyzc%R)EnhFquI!Zt2#LsISAK+Nl|has;t6EcL>;t z7xM?7S;8miwsb$Qd#p{^ID0z8mbPcq8Ah~nm2{6P)9+eev$DO3%I&$Snxa@v-^ZAp zVY7~_@iSw{$lK)V`rHxYSD5QKW^=o_i6Iq?2;nT%4KWP{g*^D*XL!~<(1TJ}&Xs6* zEBZVL5r>k6Xy-F=Uc{!Fo`f@;Oh^HA260>v zu+9i&vPTgu^%XeiR(pD@3O2>5MS$6*^K7rmaSj-Bx&^Z9iX_N>#1;IY{tKxzSh`ee9-4L+W_m7{lL^k&n-Vy zyn4fMPI1=3Q^?vaiih2PVvm5x3l$Vh^!(dChbTs}MSItpy2oOMiF z79t1HPYs0d3jcIM>^>y6BP@0u7LDkLk5UaHs}+t_)XvEj-`1^c3?r}<@022RTxw{`CU(KnqjZO1j zVGCUIF8&b=@=_ii^^0PwYFBQGjW#r6Ah;~j7hMw^qZLjD%D90$lmWpU<~tY5URLTU zirZCh+|T)ZQ8f-HbRB4i3v~Iv?rFoP<%jouHAY@NG9cZH`Pq0j(z`9{Vqhq;moc!_ z3bvLmw*0=VZke*~9a_x1p%^f3#Fx(-@%E%Zo1AXJIb!ama=;T?FQhJjNq-ZPSjT?7x@s0E2I7XK}wIk>35SH`*@4 zw}*I_Emq@S2plc969*01;>M3sqNbYyP9EB|V(_JjWdjE6YCc8C&j1a4+iSrRIRzr@ z+n`U)5z$QB(ai&jYbxJtNHJP8^bieRAgGJ^=hJ^UHTiiGOOoFFL1PzNSAk4N^sFpL zrpq^1RY$H2!YtuLgIBAPjT0 z*w;gV^}JuZZKz!w^&#>egjuo+m8uPuo2G1pX1ZZd-T0o_oJH#U`*>@0{-A_DI23bS zt#&_$eK>4#YN#+16u=N5K%7RK@u7f63;5?h1c?3*$SG5|Xs|;XEOWhedh<&qNuK5= z*=|LRcc6q5mrX#WMAirTv?pc)c z2T+CT{-|7X+w)lY@v!d~m(*$Xl1m_9aa%(d=hpEOC>xQx;{_VX5l5_Z+DSoD89}OH zed*0_LiNHQ9+*_v7TGMBC|u0b+<+Ik|4eI6P9h1f>T)3UY1w$Fflc#DPt!ulb`xV? zs;KS7>k?prT)nUIF072%PLC#F2I({EFu(j@x9|NLMd^*POjYs*4y5xy--1B)RAb_? zI=|DO+PQAj+pd4cO#&2#&Nykqi9gptjW9Xpf57f0UsL}`pbf`EoKT#lF$L0WgLJm9 z53{ujJzRYCyP_!f01mM(=N*6nR621MS!ooPpS zdRRH%>l9MPx(Ad0MDxg)wt8BJ`u(XifICDN>ZeS-Nr-%j64-JvnIX^1JpHln3$W&+ zh%xsoLDegzmr3C^udCP=&lgmK2yiV z&UG_JR6qwg;|)S%pVlj)^{VgO{(K1t;|ain?@%uMrZbD1+rMWS_sfNbhA`(`&X}D% zg*<_36Ey?phTT8p`2jjWLr!>q1k1o9luLmA?dpHDQ+HnLH#KqeO82JxElp3uH;UCh zBy&$0#*GdZhb?514`QYd3u$nD8sIaXTzN9mBS-SubhHeAr|_BeUexelbocM;mn#_5 zp64YpE`aiLx<9R}&Km}+o3VHNkWl3d{GpDtBQN>YvW{C6zR9@K%4=smGXMWuT1(00 z8_Bx_M9azo1!T5$(1;G&v_D2$l=D-~SK+8s8epC~GL~inrb?cLZyd|7#uYPo$JS{NX6yOfX&IRKP_H(etCfYZs&Du77X17vZ`8$&mB` z8x7jC*ozfiV01w_fnBB?C(!T&#-_wUiVRr-z z3?!_i9uaP(#x}|8CBAdm5t0U7DX)8X6G)wX9aHu!?E5R{Tmo@DsEYZ|Z(f7imq+&o zBA9?IDR93N4`{~c87sC3x%Jw1?<^vg=uKi#Fp8Pw0pEc)qSjV~h z0Ll;&qCTSqO3dYy<74!>g;-)^y$*lJ3>VzGdK~}-UdJ(Otkg4M4;1oTzx;DYWHE@X zvd6C}Z28ELBuN{^$TP*%4|V$zeQHu@LmMFj+fS)ssiMxRBQud1u^RIIgnw%3*)-TD zP2c*&8Jc}O2Iin8$Z`og>+zv0Bh23=6J382YppZhxaBY|^?fS-?>_6#$OBx!GxrZ* z;3?dxRxqXny-u%bG{})nUAU>jUkcKB(Z909gdAdi(<|Z%<=WEv>A|9}5q>PLz zJh|x#L$rBuu@CB_J%=9$eec!i`bEnDvPy(y`_u92X>uta*?0TuMP&}F+8;z@KpV~D zIPqV#kC_20Yu0dmX!6weR)L3s4ICS^ffkOq{J2ZZWnGXz={xVWL&i`RJMh1AUAJCu z{*^87boS7m^N*3e>`My6XF39!dO47phMzSo%M(Md5&NKy_+_*CDtZ*n&p{cBq{;^{ zeiJ5URsS|%_Q&W@K)}We0P$l&1q6tJTU9&-TYimx`u@dF?)wCEyu3+H>rQNwiN6GW~5P;@ftd%58>IuM_DpWd+Ic|>^n zP8UG&yO6m6XEF)|Z#6dI&(MEVX}XM8uj2B%)>HlRNCNPe*{3mqUWYcBvH>e6&_9|2 z-n=^B-0>{V6ng7M7{AKfKqZOGI^RxNP8)H+id?-K7dMcd=VpS56%3Bqk7j z(kWhOpRh|KzQs}=EPj;oLdVC#P7!rZpU#TZ3h$u>#K4`e3l`ZBD&10*F({Qk%8?2R zxWlQonu}?Y`HUs|cP}{lB)vUoUB=02EuZ{+qfY3OPP|&L7fPGRntd~M=1p|9RV}#M z9~DU;tn4@btTL1UvCgY>K7FkExIk2j#V$j;`GHz4;c!BJ9s9)TOccBOf74|Xs<@iv3A0qMT;##v z4es6S3!Uh|PZJQw3V}eQs&qnwJAaQ_prY2uV;I6De_S*o8*mp^Lna!4*h&E=q^C5$y zQLo@3&i<`EDoF2MZ{xkCWH_Mb%sUUO2z*}EFi1;1#bg78CP6+y-xqlg>^}*&9=9Ehg>}F+7M`Hnt<{$Kg5Mx>MN0vw4!kvjNzC&R zV4f>5b63$n&6$Js6G)S8=~pV-UG;`yA!tG{~?$jTYUAz`h^m%&sT5)w@of#*pa#p8)&< z1O4nt@?(Pv0QRdVjeQ?E^02#_B;9Y6zs?(|g~0UzJp$YmD&HbtiUA`pu8o2K5lKfw z$pazD4=E|D1>#6UTJn&WGAK*J`v@;dPh2fPx?DNpJI|-B62HE28*H#wFz3hZm;8W1 zjDhH?tFHPe_WbN;KjU2`?eSuR?`abBpfDx`1t)Tiz>%27KrqEX&p<(dppMECRbc?6 z0l4T1!%b&7mSH)hQDC@slHQJ{uGBf___T?(U3Ae!_p`U3GzbJY1?2I5gKN!my;aod zFt%$9b^cY|p9rkM`7=y3+=T49653fo;8Vh zrjbHWh;+f27%4h!n~3#P7kvpWlZ-FEsdMt;eE^t;YGzvEab=NS(y4 zVgA0Xj_iVKI|uXbduTSqCFa*&;h*H!37WrL0A=XUjG-#=c~&C^W>I`jjneS;iV# z5M>*?kz^k`Gv+sae}Bw1%XQ85+|PO4ulwBRyv~z!)ykX$CIkZjfWrc9at#1LjE^7y z%EEZN^XQE`;|=0rXlV!l)#+?h7iPwHR)6%ZKma)1`R@hl@q2TR@uOgn>CGTpKlh+e zmq+&je-}^RAVuH%K?pTPWkq#rs@n_zylA&DF}(iRajhk)H`x5e@8c^C6S<{HiM4|e zQ!Xwe9`I1DtO976|4~;V#0S!C0Fe^45%Me;0}01$<(d_rv34ah2P&(vob6=Ihqf1| z!i2c8utTqv!`V|`Xo)W`tNwj3ABZ991dlq@*_F49V)Uoe@6iL+ZojiDzkMTgYV?Nq zikmpqdgEkJY=E2UmvD;i9^09~iP?}9T$DB&onDylQht=qCZNE@X3@Pt|2o&ceX`LR zvlJsh&FPFmIn(3joj5ra4~eHaPd16-V$@6*-}FH-jh)GFJ-XjXUXK+jm+Q)mROGkC z1Qg>lBkl-hT(x*)A#<2DX<=8d6!%8y1k1^JazGRnqp}|7RMRe`wSb%dCUwS)Li?Mj zeT-|+DicoGd*eN?g2+t+oiou zC$VOOYkZHG`{;zun4Aw$FJhnObMp_iJg1FvIWnIlA2i^-+MVe0o3nbe+MD`&Gu8(h z9Qta8dUivtoR8O=zNL6IKiMpIj9F=|zO!8iW7(=Kima^leqPOYYKUt1_NybWq5-?q zzGf71PQsjhMjF-?&>JO(3{TSYxx9n?hB>Tin!tv$c(+m6Ftwj-Q3`D15A zpVAb%?%uzppt>w#*xd0+7G|aJUdmIXTlNu=C=k1y;zAaaN$+ehc$}fvjC{aq{rJq| zx-O94Y-7t|UB-kX)ekAs)yzEEU)|Jh&t@ZzoYFuXhDvO4!o=>=32Y~}Y?Pz!vsZ>= zdK0{KB^#&rE%tpFizatWdmgvxyQ$^R7E6~6{%GT308D>AaXP^!oT@YjDyq^(>VA%A zTJpsTO7QAD@owzta})g7(|#Vp^2JhnlE! zTYH}jgIMho_t9C`@Rx2IzQmrHZIHn!TK}e7|Gvn)NYe^FP}xe47XLu^=}3TX$ecL- zJupRM&XF{@rZ>I*CJNqpB1?@69%Y#@%6lMO@ARg;b{uoh|47hmJwW%01*c;09Q!G( zR%~lC`%=v2tRLcN#uzui6>2vBbb9yLB4i$;IDYn?Nan>Kr8?@3CrYa4Nkr+$PljFR zPJ>-h?HE{R@y}xyG#w81N6o!(5*3T&&zofTg-Aft;F_3^>O*!D?5o|gPgPPU-9pc2 zPHQROYwZwAZ}dWR@2=8C8+|T49zvZBKsK3VUC;8tBmVP@Eye{he|_#E`89L#KMc{+ zr5U$ljq5oB(k(^c{Qg7WNcrmitKmK+<(e4g9w&=eijnJ#3otnCCW_zTBoquU)T%V+ z>}V^eMe$ihDl|r`Y4A+9S7Y&TPQ$bfu6`)zYx`%bpD!ZQ!y31brE}eJXEH-gatQb9 zMHCVv)H?A!Z)U99dAxNb4>-tJSOoQw!OjZ=oDM(U$1CZ^m19!Ak71hBe?FgGoUjx2 z^73hQGSJm$Y*_Djt5bK{v7nMx$YavVg^sUlEkSoI(zh}A$4hNaF_4*9b`+8tz+DX2 zx1fJD+CzMj0`C#^n0rXwtv5F>*P1Ax!PXWn9K(?(N`&|-~#RNJI#qHz#AO!3>#AXB!GP`jE(Ta%Rc|}sSBvyO=*{|kM^k+z!$qP zSSE6x85MsxPFgt7hi_l1cS)BaH6*M5lV_Qc9^jkQ`E1}u5@s_o#v^!y7+Xq&yF3_^9Jn@J{i>g znegLxeuPgN%$tXjUI(rsh`s-()>>Nu9|V6dBr5))Nn0I=MIc4CQf5!eI5}Hm0w;=t ztyb$#vx8dSb!PYIfn6sZ{KfBmbfQ%90iZJ)$p(^1ks|0v+ZXa*OA~XmoUWLGIGvk# z@s%!0ethwk$cBK4OL>-SH@%ND%D`k%rzAIlz4Hxp!~WMm2wdk)CL$^%&qhN+NR){rK1;b^65Y*|2eys=I2^|k8VnAE5y$25W5=cc5)w|K9zB-d8pjBA z`QI??)$(dD(5|(*q+ho`x-3o1pmv2y0TxU@)YHHaNI|lJtJ$AoqYj>vwyU)z*0toB zv%q&~ArIg)oD9^{T_=91t@fxzyHzK?fj3(JDTwu}F2C!ycqEQc62B}4YsWm9Js+Pr zaM7gFiGM$czksEgzbE`%SC0!y>aFN+nJww&E+z1$lsQw$$FH@Tf7bHpru*$vZDR7h zO1D96w_>1Op#v&fU3i2|L`I~Xx4n${I`Jbn`&^0GAV|wHf@43(Ep8qFTD~B% ze<^?IA-d_wL0yA}sMVfay`Rkb>G-#McS1jilVynVz<)WgGJ6230~%9q@%GlA>H|$IQZtV${?P^CphxK6if5u_p6iX(Z`^jzUkXP@u5fP^ zkaU zWwEO6t3V02tzG1?phg2%`ka`7N1s0>?nzkk;XZ_LOBx6tUg;JUq3bT|f8A4De4{a;9)LeAEK-Zw_(rN_* z+;^BAJ5Mf;?U!GfF^lYf!onbyS(l`f>OjK1%C;XTBF#Kmm@6MHZOUzNVk0(dI?Fi4 zp3aKUPnjCc2TprvErkq04rRa@fXk?c zzO2tEG@{5LJo!LFlehd&g`_Uy5K|sn19I&OvHDtnWZRd{8$ofLj@`!gu~wG-@M*}j z;ke@|$9Ao1{lawJ9Dde>%mMW`t1)vYzuTUG^U6Hx;^qh29Pub ze(nNBg!_V*`O~VPa-^I%;G0s9UbrSfg$& zM;J8CfR|@3>rJC4>;o%WDIH545B_nct#-7msIsei`m{t@XH=43CEcqV=N9@T(Qja& z8qtcL*B}#iPm=1u8M)kNw+`mUtwR(Huem?wtqnu3sz3b}|FPisV}anayS2gI?OJq` zMolo>76k9Y+Bg%7pawzaOgEsq37V+e+#9aE5}S+fbNMs&&E>w5#)#JlVT!2?x(Mi; z4W!wRuNZf%u)Pq^_yhmsFq{3xB60}xK^hf1rA8Ld#GVB%OX6y7s5m!efrmJ@0yB`4 z@mEN%YTP3fbjzd<-Zb0R20uNprLduOd2uG^z+*luPYtfN=JG?g-DWtSQ{$D(m|F>3 zxFvu%KAT|eWcn)D$C>OUpu@QQx$6%%kJTomP1`GRkNxf+OJ#A-|Ne^+T{k}PLsO90 z%Ty$4Ns;5wf#S!9dkdX?aPbOK?)DW6B+@Cq?8#nulk@c)6Ne=^9T%$V@Ca*)qq4IQH&2+2_P0Gt zE=!zz4d6$q1dEag_^N&5R`ZvRPE_clX^v$-#jgDkM-6fg6(7`;g|z{=xd|Wa4BHO1 z2UjA4g$4iDV~@4wDfY5j7G_))KQ@nRHB!}uqsQESr!&6z&B#qdhg zCpr)?y-ggil5Q2`!m=Hjg9npvXbM}t+@Nnm;nH}r+%0Riu=3^I^cYV)(kE+)Egl%I zh@8`WS+Xs}>QuZJQ+`AW;>3NPmnnfB(12SA_5pJD6L#dHE{hM3zEZHoyO6u_%Nd0D zPg!eTo^R4g?~EpH&LuP+@{dcwf0S+O>;K(l?(wsx@O(~@<;EJETm)Y&TJSZ}e#|D~ zBZXMZQPov^N#}k;8qV;VDsXu|*C_Zag5wdS5Xzf%+8m5un|ojY7cT~x^m5i{3q5{H zyD1EyJZ362wT!m1eMditvc+1l?&wANlk)`F7=d6?i>#mwqm^PzRLC;T9Fn9?lwCYk zWmKkL0IlD*l`gD(5pEG_LFf_~U#LXV?YPjdl_W&93vL@^oaPQNr#3wsdmi#~1D+wP ztgsKQ9nToEtyTZhSZnQdE^#~wXyuYbj5&#L7?2&9!zQnpwAn;kJAIx2Jm*1@LtS8( zt?E&p{R>gn;yWCjndy$~f@Y3?6798Lr2IfAy*8vGNAn)k3VRAVNj#B2C2DkwfU4Hy zDLw5nrCo$9r+FFm46FrU*ZJY>8}s1FplSXLFOx5A3r`R4FujhHP?5J~V|HP+aAcNf zD0>hWkgR@pqN?t{`c5VFG!|L&RF-Ry#FQVvX8HHWSyvgGjuDrOQE7pW-FyGtS$cg} zfPtlVa8UEgW=SS{gip*^nul8y0|@qo?1J3?dcC^KW_ znuDWGeXcPLo9 zw(Cowsz%w0|FT!&=VB}}8ci7%)K3gJQxc}fLY#iZgAd-0>M(~@f095QKRW=w4k25= zPL?YgMGRQxmPsXlo4LUCxsK;~Lb%DtSg^Ez)#IM2s_v(etQOkLfg4zoD{liE(jcC7 zTjZI{kLP-QwHCY(&vyvud{&{c;REKvsp;6g$h}Z*PQcc*eH!JIdW6@vm>69y zjurTBY~0z)#%xO|uEKyPP?P>!=k@t5atV`rY|0IAUnGk3jLOZZlD~cLP9)o2v6$h0 zweYcYkjqh%rhKJC;QEJI^j70TZn=WW?x%&U=)=rm$mpKZcX08F$04_mDEF-aWX?@) z=ArK1whY=OyC2*iGs4gZT%}7{Sn`YE>_;tD(DSOt0Xe{dPjvXZ!Km&3FdH(FO!J!; z`ajB=FqB-Pt)WT{K~5z_W{DePaf9i`L1dW%tU8x%MTt2F)=>|)%<5;}3=EB&khYi= zz@5F@Po7iTdcrG*s$wy{a}gQm^l4oum523Jgg)3jjM+{R< z3@=C{Z@OBrYx0wMSM7(aSns0skXYA@*59Ld+|Gh6!=hOK#{>EsWk!NK2CJk(;xm_c zq$n#7x)yy}KMh$6T0gKTMPgwFS($5d8BTC}3&qkdYxF@@YjSVm4(m`ziNJFen=jOW zK3~~6Hhsz4+?Hr{DT%Z(u3K<=>u}qj+nOh*G)JDjRS0y*S$^Ompn|(XIBUrVZm$;P zgYF4*;~I+qWa)CB#)#;*QLha5v*4d9rS7Z89+d$JxT6z%W25C84o$jz8WDV_N>Vvh z*9lGWQtlnj6qlmIUoVb2(Y`7qIBcCKnt1hDN5Y-p0u2*r9^~)bhBb>q~u ze!X=ynEY!4It(^amaao!WC7O{&U!uyiz8(P16)uyGCk?XIyqFu;`xcDCi zLSKq_kjuT5F40(3nr4x;+o5;J=nC6>3^kUJbHKV6b0C$mBzc(huBG*mTag>fvn&_L zzLveix*{t}n5p8NMT^c!-;6F+-9Pjc&TXDap#ufV3J{s6?|-39x^s} zw&Rx+c-|NSb4foBww$;j=`8d`NV2V3o4X1V8xV@y5%`uD+u0k)nz|X0(YEoSCkn&9 z4@%{IM=Q)CJa!`giKlf9^jb%bu6Q)EN?VGm7>wLR>_fYu<-{;y-S%gZ3 znJ6jAMr6EN(=PEKW;tHC_$Ib9x->RFGso+2=CM5i^35ygiJ?~fYv;SLzqQe8@+>81 zEP32rXCF9gOTx3#R|dq?=9>}koQZp6%ME?x2`>!ie2kWC!%T`+VZ4c;2uHI#r+K%| zrQ_ma2HrS|N4`?*c`Vo>vS6Pjm8?4TjJis{vruz4fd=g=8~5vTiim0tiTW5%lbDn7 zls_D&>)vOj@Yu}@Onz{GGk}rSKlDNBk)Caqa17PZPq*)-Zm!ycvoJ|yY#oQ@eBSNU zq4R}J&+jv;Ejh2J#Gm)ivb^SsDKKLu#o`VSWwXsM;IhEcuiFw2hEAKdt-!vvVXmCo zxjUHLHZ}4jsB(CzdWvme|6LaYD<}fPK5rlCm|PuM@8o(AxxcR_;u87lZI=%c)iYnu zK{9;sLzBq$t zH^C8g0&ECKepQ~Th6++)$78Si|-6791@w)nQgS)|F1}nE@)PrNv14`<>>bHf2if+~g^yW`L;~^5||66Iy>SYWG4f z=Z~m4N#9+r2DQ~na)ZklA(K$M%TcZCu00p_+vaML67S1LmX&u2BU0ak8i~&iyhB^` z!oH!EEMPWxH4(pv{WNb)o6Dc&TxJ?^8moymVtyib{IZq5K_pf@3&sV4?-lw$J&M5- zZ(GW5#vusjZk_|??HSWGu1ukD?jr z?xidltIzV7D>m#&+STx2RQ)XBBDw74f`oXzK%bIY>64DVkyof;)&U-ALOFTqv2OV& zx0C;S#nsFZv&i-k=@w_=%5qW@OW9qdUfKmIU6O)|2jr|1o$|L!`4dYnD--E59=`h_ zZRAGAhWAUrrD+%3VFiVHNP#Qr0*W$%I)4D98;~Is3=?8fQF7lVCH1thFMVsAiu-{tYcPn$F0 z59GmJqolay%L<8vOl*d`EchsMR7%kVrz|dP2gO{OqHP$JW!Y!1-*{x?o2nW3Qqb%b z|DD~EOr>_sY0h7A$Smv>Rd93n%S?$&?C0SOZ+i+)S&{w4v7N`SWO~o_62c-x+pE(K z@M{R7)pN2;>vU(Cl_ADLY0S|yQkbBtGgPxi9PyRb-F=H3sA3*%egva5x^kE;S#A4O zDolLH?70Ge&$Da{H**DS%vYG#I$UHRT?6Yv83Ug^L16=>5VDP_f&Y_!kHnS8OYB45 zBCO8DM*V=J5Gy}g@zC*(%twZHi0O_x@d=r|V!7Jz=}&@cvm*uA*hT%%P>sDO^7|vH z!<3@Xv)EVmSB1Ycx1@2HPX2Wy)K2M9k@`LH+Y$2*{Rmw-(5G{j+Q6~uke5vV8dM3b zBc;8Z(@QP0^`BmpN*zk0@QUQI8asSG-w=$5l3^(+mtv|9Pr{mP96PE7M>fhosy6qWTpsw@TH*_$07D4e1L~q#K0E!=1T&3(<{CG^KQfWx60e*)yA>?E*W^f` zjf2H|_>-)~?5&dq_UwkT-Or6DIUv>3_Fw)hZXErtrWMKFi&9UDR(ENFMXN6ysY>9; zox7m4@3FYZCWrWvTfCrltrSL$bK^@=7jE@y9kr-JrZ zu9tqpOIbVgC4J}UR)xi_cY^m?da>p3SV8|aD`;=c-Sg}ch>A28?_xU$Nd}IEqbxI)zKsqMTEun(ZZ8Yj=}I}H5AOo$riR{bq`RvrNXpQyN50${JA&vi+rO;=s=!5Nv?USPjjTJyMs$l75*yeVa=tS(4UG$H626*2SWUHS^QS*7*Zbf=SP#C&Sod-miQkM+I_!HPP!sjPfm7^K*5K1l zZ>~;ml=WcWJ#(i!WT5nyOiiQy^t_r5!)7=MCfI0qYIMCiqnGJ<>C>6R09+%p$@IJ4 z%5C`P4DLTyEA&HKFad3mCK|uX$#t0rB6(Z{+JtS^%r&K%OvS!2d|KP|U+n}JcUG|gLK#;r!@Wm=a5(zK?MmYA#pAv+CozF#M!@AhH?O{;I6S9or)p{KY8&s5jr*qGavH}-LKa_mX=VX5{UO`r}8r?l2 z+lo&Xwf1i}#p%uK%=7ezM^IK0)4%`q7dsA$mAY&G1?hwT)VhOI`Hl^b`te-p>)pRs z;|#dqBN{7}3dxr4Mui-8(xX&1hGm72{@u(M^>aP~k_MuWkb{=2nvSNpHEnK$B_C-1 ze<)aAfiv+4xioMRgA4Sq&T}R3Mt>4R$iOr(lJ;*Z2UHIpQtvJSeRFHUE?WUkE{1=W?x27zWMf4~)9#9iBEd$S`jX zHKKizvHl)Y<-iHZfidIS+U6f6J>AY90#a}Y6g^k6My_Pif_w8_#S*r zGI54GK}~hYw*QiW;V0zpj6sE<5{5A8mH0E zTHmUT~)|4eWS@apz zc_oA3Keoby%3sJfXOFVT=@-{4M&tdTJSma+Zr0&8D)H7DR_v8rdPlgsO*^@M-T5qJ z;@n!9LfzYX>8a8mZSzmt)EB9_-0%iX?%BwQg~oHHFXh1^gd`l&&+z3RnjC$VxmGt} z%~uZ>Bmw?O(zrrInnOu%+sqfU)JyVZF!qc{U%y(tWK%6rWLNz+9k`NkGQIbPurmY* z8O1!f$$pdJEM@1owJ8GcB~e@AbB{Be{=j25imO+pCya@K`s}nG1>hde# z9xIIvzKc5uPr%V$K;a`7L0@ibv%j|4aLpN2Q1|dprJ;)N#WyAH*s*N}Zmc1VsM~QM zAeuJN%gG;s5tT1UxxkS?6>(VIeY@bDrUZiYq?v|SeB|l#*1olQYp^BrWnpsx09~*U z_X2eUI&dKr^|g&BgXA|gw`M50`SZC0E(c4+GU_nKpa3l4diH8P;5)*T*Vi)>?-{hxO|cNTkk9eJ{r58&2;deLNQv9 zQr?$PpGvE)3_nV)7qg_r8yTFaNX|CH!Sm@lLWy#q9{UtvaZ86&{C*(4eo;%hp>ZUs^&Df+gzw{~hp|m>D3~6%clL9!Os440kAq)2Q;{)0; zGGG`Ep>Nu@i%TGn_Rsow1;L)gD?XKu=4Bwm+B~2>WKsIKi(0x1qLvI(HTk z<2%Q6z8^~jW}zU6KF*|-WcC;MIo&Rj~E@XPNSWY>g=t%8Z8^!A8>{l zqZ&s=KHTMa_H}y3$brkH`@OSU?ZB{R@Osx?5(mv9G)oT)cdA0=Z3J3{dZmY-j)*FX z5ip;5aX{8WHcKoX#KayCH)glVI_;A_B%WWYWgM6Z#}$q-9MRQ51@3EUzIP4$oAob! z!<+*LBin-ir2!Agw!@k@LuP|2C)$gHa$C?`KzoQNa|ra&SrLY#*|@0A8)dK zloCuol`F7*@eLdf@D7% zG|}V)j^jFH_O$jMBlLHjc()E{O=XC`|GQgv3*RiiRTe8jOxwW+y<<)Daq{ODT+}mt z{`G?UiyG>1_$_;vDT@YK$b@1XV(k(}0^Frw#VQ+^3W@dU-FgAVc{RGrfLD8R;-P*B zMTmhcIM!j5DKTXkc#v>p40_P<0!k)Y^Kl(;ld;@fiOhy3vyLA>U$iE(G8iCqZ^PP< zrbK*qxu|7LfIhpT&Kxv0!$C8=aS4Wsm{77wbm~(=?7rVm=vCP{WiE-b`p`IA#68|`Ma};j%Dh#ttzUXf*}H5xAS~+8foAV|lX~l<-pc1LhnAyHkq^4&p${(5 z$!g-J0KA^{xHA|;9o%1`<2U8|*|?mW(jYs`Lw!xkhp*FMvUgiZJ`XnoLQENz-O1v9B@d_??M7H#4oG>r?<~0B_s) zB0zaQgKBXQA}r$hhqF(bejPy4BgRnNhvOCd`@_oy8f0skUoJ_ciIqT%bPU2$x@9(8 zv`E%g`p&TG0Q$>E!`1B1e{Nf9$(Jtvp1duylDq5U(^hQ-;hv}*d$jTtAf#mCs=j;c z)Y~TkqcAQ&M+tT>>1pcNp|VEgx1z+x;Pn3!I-TEKXy@KTr8D zE!yd@Z<-#kSKcc#q+C*|hvHDp+t-LCxK{7WOomMp@zl;|nEIxKh#*Z-rGkvcC&n1c z+lHN>JxJJlp}&{qtCM!{feBrDo~acIrLM~5r60(+kWZ@pFN-~MVB=VDp|9R+? zGQ>NBj1Qxu1UJ^&LU;|1+|vKSo;7W}xpNYW+3%mbv_?zXuKWCBkQm{b%rbTsNNGXc z)Big-!%V!n(<$e!hk64x_}H*V{pnRdXx>;oDv(c9-D1`GkcmNCP4o~8#PE@JELC z(5eo9_`5=FL1_s9bf0JOG0Y&*V9qWTLjE}_)@7JvxU8h9fqIHl?S%H_x z!)-QQzYqLjtCQPqgjajii;w)ZGaKdYeEama_^d=+qBH$V?EB@JGV zhvSNYaB9fh-YY%>ip?X!@a^YqcI;8^EN&plj`_kUB`@b%F5_f+POn!77hwq>cuW~it!(p4eMsc&=|ek7+cl& zXEckT-F%HP%yy+u39X7mZFM?2$q01Md609E7B3+I9u~hce2qFJT&#t&FZ_J87_vIB zGR$f?5$)z8{9__jtwt^y;kyuoTc~k}T^(>l%!dc-8GtiG8^qeG%R`ybsN3-TC*U!s zd=~$c98=+(e{-JBblYhV`b3VURAR=f-HMZiL#nKBaJOANUR3;^j{c5?%e<`Nuid7d9Yc|5O}8zKnj*OxTA~c+VfVx1-kLJ)vdT9 z0vdQiPmSiW0!wEP2h>QrjZ2T&s`#Qmh`|Y`vr|NfPQJIrDOi=!JG)D-JA3)nA9}_% z?wbFe4mqg!Vk|gwppoVu(v-e^n?mp$WW|v+qKp|nj<1ED8GoX#dCagx4g$2GHw#(f zWt@~iZ@w)DNxlmltfL*jW!hvFHZ zIQa*ZTOg$y}l$?;y$Yi;vX$dXZ zEb&t}^)|}5te#Tw3yiZ8!>(9OW4v@$hQ&`C;a5nC_FA2W%e9=E;MEmJQ^cAHH7OZb zc5gV<7Z{+2qcNPo7rPA@{I^%9gE=U6iV;~0%B2&2@)@IyWjXsa$hQGcqsWVBD|`fc z0qbAk$Sz`5U!|h<#%vBRUbe{@Zc~pn?QZp0Y;-oq40&wmOJZEl0{IT~vEnsa8Q6gO zW}k7mRo!b&X=tH)|FPDL81lPxg142znkT{h#oL1Rni67nSkr#J#pxU8TC@7zg(Dfe3HlCN z)zT=~t0l~guo;SjK5jj%UMoJR7DOM4tNVR?sHfGs+t=oDuY*N`M|66F_G{_nZ7SAd z74`CSK4C45s-R5POX{nJ1M@4J1ll@^b`2OyN9{6N=Es4wqnxSP>+vT)b;2<=tJUu9 zN+LJ?BQvQy*VvP?8wV3n-2t)Au6b4vm|c=VeYTG~Nr90O`Y|o%3e#7FV^#PNw9m|j zRa^HZ_R^8S(+&0>YTEBB0PHWiEi$%+G4J%TuQik$iJFB`K3 zw~w~Y@YFr**{f9k+t4oX=4OVtRR8Z|!OASu4-r3e;0Aym&U8X!<^>o@>>K|{Th+ct z#IM1baGnaGqwLX#l(No*;e8XqEYmxGx(KfJ63)l(Ekk%gq_+Crkm@Ji=Sb&Cm9>lW z*9}kzA{^A=YnVavm2cA$HV2igtwa6qfO1=;03#r=DP`vdkht$ulhCUs9mNN#C$dqD zb!Q~Yz2Nq@JhYnoLgO<#SR{)D9?B|m@1MNw;_TbWi9Jo<=)USytGw#Ra03>jtUynE zCw6|tDVz(nLX$H;KJ_Z4h4|#sgv|y@IZJ53OX=T?!2N{)eh3%6Z5S#uByXVn~ zt@_`7S@TJlN5lXzVlsy&#X+kx))rXaC(nQc@X&u|$wRV`vub9F52&#**m_%F4sxy) zyymUSOkBC+6r;{QP(Y zZelm`t_&bJ;E-?wK z^u+N>Vz&e%TKHjp5b3k}m%R^b-ksjoq!IP{axHZc<_twKp5N4PhpSHWLMkv>u(B{S z?nVP-{4}UgWQz`3Re}LM>vxUvthf+XR-e^yn+bQm%6-20b7679{5Wmm9>0WIGYi>- z?}tWV^Plu~KiSm*m9C5(!9_x8uiJM9Z2?;l5PV?WOkbYGGYAJ=Ifb;8aWyAbEcP&qB9CU?M{ukjY4=z_2ZuRu@nPEKs<0d?AH}2czQvmzJ zb_6+oX9g;9XqGBW=l%>en7OZ03hL?+h#h~W0LcnbXGTn=?p*E-?4>WQ>X_!d6Ki@! z`D|=B@#rUi4b;$mK&mF^X)^XHzI$`#+xSV*i|nn8P1{^6=hPwqhafs1tM`Ar*ypz~ z5QOlh*^~+=rB6G#)i_1aouq)LyAQwoeOUgkUIHjNR+XRGJt=8es%$}ddXNRkGf^!$ zjpKvjWx8AxR9*y4+FOWYRTBIUbfULCX{^3}Do(#p3Af1>6&o}qTew*`%{4f>qct>Y z11uW>nhj0T=$mDrJB+(oO#rII8-B1haRH<25ZnqRXRKAJ;VZ^cO4G?#9-k?1U5J9RXa48#_o_?5 z)kU5x>d%{A;GQBKlQF$w6gC$7Es5ram%QCT|`5o`73XFdFLL?sinVF-ZJqVw| z$?U96m026wr28e?6z_YW!s)J5ulLB$b}twE9TAT0 z5Im`w+C5R{-m2S|VFw}ZGRpJ7fbFpsRKQ&9>wx}WWUS&I)z({xIZ>J`ckCoT6}(w} zFzOOzNsyWv={7LMRpqh3L%;?%{mQZ%MBYky53!`PTiAbmuG|_YBK=J!ctdG1<7+1= zdMXX!@{KNiO>RfS@Eg5-|NIpP9M_fX-sGEddm1ocN%1tD_2PTu_v4%5^TZcs|4YFV zwRH~yg*m#Su=B2qgg{46W4DsrW43w^2C4b`l#)9|-|f$2)6b`=^1&JVaHu|$kxIwo z$6s}o-)2MHjZy?qj7;C__3K^7k>XNFDAP_r#jYn!G!}qQTTEUB#+;C-Q5d;?8D~tt zc?t;7$e7t7{)iRRUs-204n#WfSI(~Iybfq~ zYzZw6ZmZ|~%)xBn?`V#pV4Pu;P{=Gk>OB)qoO=Ubd`GN;Y3B(pGi7+-H~sp$0591P z#_;^}Tb(iVjJR(dJVaTbgaMW>aSr9ePM6EZCQO!}41XmStW6w~WYw>dj4~9M z_7T{AHjr~f*)(A#lq~Q>b-fRJh4C=n2T||rA$5l`@c49ni+%>U(C?2_$%eiVUg@)} z!OT$4&c*ppHaL9?hDuo78c+8$*jmin@rlZ(`u$qkjryX)0}Oqp64uTfCRN^%qI2DW zic~N$nv`P`&0YY<<&MYH9CrPyinliuxW&QFnx+m_kEZQFz!Vk5*jA>I49M0{AeV#g ziF@Y*5iXGpgaXTdCkc(d2aLmUngeJy|3(WjE#x|AEE}uy+{F0_042$izSi^9->*M+ z{O%Q-bHoA7AnJ;fROPzre7*c@owxE8DL_@bF+``1&6%n5q;e<$Qjx(ZBeL?9;&> zV4MpIc1QQcce)|zIJA?_5QAY>AWUicsHW9u0a_4Sdpu3ool`Rh;c4T6AjYt@A$4`x zfbxf-O`|AYxz^B&7zY9?AOXPXQQe`&fTm0-=t$FZ1qytF;FL=N#^g~AG3h|`jq$!N zFlYI6d$)U_X$hp=>1Dv-(yjS}#1}xH`6l~qKl%mgXGbIdt-r0?``Cp~J}2Zo(0TxHZPi@$8rejcy9ky`B|ijhok{x(3Y&$BgmVHin`ltUYr zMbPkWyU!7%DOsHV$`o#yF(ZUEerW~l1lJn_P-B2Ge+k_2xU`d&(($-Llr4I-XB&tm zl=^PIdCyAu)!AQ(DQBsA#) ziioHrbVLOdMU)bX3P_ixw1nQ2W_eM;prY957*I;60v13}TBM2s(t8WZ-G0w~?stFi zo0D_)o>{YI&6?QZHRQPw@rGGp!C*zCO~WT!CF(S$j?rJSG`K_J3Ku}Ho__7a+ z-L^1n{w=rh2dT?jf*CV9CUs@c8Z%cGzjkSGd%leZzj$s*fDi)m?|oPMBdO25uh9oS z&J;alPiLODM&O3C*o#>vYemS&5SbTDe&$8+ekE9RE>pF)-9 z^b;k}#eLEAz7 z2g*~gx+``qhS7Le9H_tOlG&`~%$9|y+-qLEO~~APjhIz5&LZ-mw=cRKMaaWke)5ta ziS|2&BG@Xam_D>+EAEO7LZo{}L?77TUA9;zb?x=o@O41n-12RKR|whUk&5iY_h^x4 zBaU*ehm;$xu@2`7wnlfsdLFsg~<^Uet;j zZ92L|wB_$d*|>UY@YJ>W$^_~-iU3Xr?hWm@>(UF`aLCHwJW8kbJitsJ1mp02i=}OB zZK%i1`>-zBbj5?>n&rRvse}~L-5}3-3bI&%HRW;}qcvL+BG0I; zcB^1Z3K6tI1N+nV7~m&3vaWmqo?jf%6>Krs64w^?k0d*-Gv3NQ&!}lj=@!lSXDi69w zF}qe~if;HC(UN`?h@%PV!P8oR?JJ60T+3D$B#b6=H8DtcKzi`v8ihx>HDG!c|EWTR z%)QGKMR>~xAOvp@?&VnFcmnh47T03RG>DZ3O(D}DTVOXTgKCHQ{+|%&YRVxClE=1F zkc0=X!AN)G5X`7>@DC)?cn+##iCk3Xz)8BEtJAI);@o4l(9iUU=!yU-&fFFrCf7Kp54HpZ)Mrhq0q z`<^Y!hCG&r2hlU<-JM{bU;N){*g$nNwgS|j16LvYuFJDvpZdcC_zz;pt_KlLq+ky6 z(ocf?2L-?x;t1r5tRJxE!&m_+<YI&i+&m&c6FAwU_#mz|`SXS(+yNqg<%{*=3izfYyTOIb@n6GGk=Hz~)yl|o$E z&i6XWG!g>(=vv>XXx*=vHt zYEv-eR){XS}E;SF&lnio`t>N*;?C>Q0 z%#~%0T63iB-Mg2e_yk~I00uc+&rr{o>a$fr6+h0luxT*ojkJP9Pd~&uM0p_iHjEwI zG65-R;7+XoSlS!Oh&krAOwzYMg$TSqrgfB)uy$5?L(Z4Bu9NIg{BuZH?7 zuobWOw5S|O7-)_oP(x~kFgBc^CPWCd(d2+Wqlq0s7O%KNT300qfnB5jSq)v)e;HVf zR#d#zA;`+A%)op<13an@f&B*rfXW5sixgzu(?vmC;!z;D)F`q3{`YfV@HP~gK0C(? z=x;>8dDEQuNo;nog=E8gk(au1-$XpB6y(Ow#!JW2vBAhwdKVH zUREGaTtJgOZ?3EOpsyD=pq*ql*=Wb%)HimdGiNDLx0l4tg-~QqN+7@V+u0@h3SxjK(<#fx-*<0A~UM z!=*v`YHbeMNf{}C(C}Rf-QBzNh_YBQDhQhXtN!SJ7`iD4N=0B8f>156@hE7L^h8+A zphs3T`N_pQnrOnL)D|aGToyzmZ1gKM{F}wC{%{ll4L__XXdIs6H4ABv=V0Th1qSHN zXheh{uqTlVMI5vs`mxcB>JL9dFCfw}f-~27n_TMzubly?#TwU*9_R7+w&Vv=i+8cmjR0x2zsvr=-)79}94Ga;uh;>VScxZDaVBN8zVvW!V-x{eG zBsa1m7o?@lgb#O4%OjK!n$XD#Z!t(#ZbD)BDkJvVzN zYJjaYSCFjGl6w4DO!T?%eIRG`Y#e2aj|+k^;bAuLMhaP~S#Jdr-;9gsp3vR3 z_{JBJoKZICza-jU>+#=tBrcc_MEq4mj)(!hiaUU?0)1v|5aiZHIj6%&GlbcauNXo! zv%>^YOcqpSUczKk!A8?){vjkCCN5eeC+7P)P@Ha0Lj>f^3F8*S5S59Vr8_6M$$DjP z0JbL|(aQxYg=jUBF72o~=`aI4g%QP+60$s;-k-$ZzAmJ&F z{@A*vAPu$>`iwy$T?gHnu=+d204RQcZ;$$^gCsAAiy%0sy$LEt4|ilnpq&YwQVu2$ zZt*U@K@*1MAYiJoEb5_gE6^T5gi%W&iRa;uAhMDPDq#GbA`twWJO^JH}(chdcwwLK%sPm0+=~kP=L(sNJD{A$_HQ@Ib8s~I;<8xzxuiTs`5BB zmZ%0G-7P2zQIMa-UbJu%B^k^}q4gr{Thovt!}fw8;*r)?RnjeO1k-0xXvJ;X{uf>d>If(h?`zNE^PBijekKX!}Sq!u%kFz#q4 zb7l?<-=i`({}POuEewJE>!2@^W0V;*a(w^G-l#Tp6oGgOfxAul`62$-*4v!_vM;HD zR8V&z?Ksj*deRgSgU+d0z9k94p3&>cGkTb_6RhZf;5~>yDbzPbv4mM;1n~XViVb1u zr%x#MZ~=(@o}U)!1uLBJ$SKv9uF??jRiy76&P>yLe+HP@<%5+a78(5fU=D&E*vw$B z`&bM~+ZSCIN-mQ^`6nRvZr*W{pnISQKXc%@Ajo>Cj_D$D5knu>n0K5y{JjLoFLH#@ zguXxh%)I^$Z09*(c2pdZp4O3H{XlE=j+0jcxa%B(fl4dUaoT$!&`RQ$C6{1UkQz+6 zEcPczQ>LO~OAI4=7Gm(mKq6|aZ{}I<{o5Pxm#kXqd#O^_rO*+=W3X0M-t_kTmr8eX zP)@qYPLb6U5qGrCgSx7=gC<~zG_m1@TBvG_A)P|#Fb3=Yv*E1U|BPIQTuAICfIm`b zHIx3;vXRCiB9?ZI2N-_m1KTMSG)GwxQUKm!C00*DRNoLRc`98YkjW0?(>b0O;TEhu zF7mIw=})D4EH3+Os3+RVgDv5k-`zlKnFWFnE|4BD^t9-2+1CD>jvPK_2tO3zh8ChP zNU)QO?D0M|r2FlE)Xrd-Mq9aJa#*5GK&}8en9FZJx^DVRJTpySOEu1s;i-`e%r^FHqFX|QftV`>z_W{htV3hNMqw33*iSj*ObBbnY#Ce13_2k%Vvue!E-e?ByNT6iRGje zx-o&gqSj71j(({wOnF-Y7C(plt@5H20@ai{S!pnYumUJ-12(qG2K$K-+*ZRf-ZgChzRb7)H`z%M%yghY*YI^0WU(Al3B+eluPRM5 z=IakV{aAcmSlH~+1(qb@Sd_H#lt2^5=Bt$u%|7=HNK1GPHy@gFf~rgZ!5jcDom1GN z1^M;I#r_;1p2oOPBV;xpdzuY1VR13^O;6Oij&9duLpw_-1^Kanr#nb>O2yVbNt;w@ z+ARX0Esfd)s{qDERgifB1Dt;%C2j+lN((UMNDcmI8_@dsx>e5&KC}O+c;mk-+H@IM z*WVCJ-y!lTgT}{1r(*NSdg$7yt`j+iBp5R8nfRi~JFYaL*2u$12o(gQAmA1E;s;i3 z#DOc%{*?ql9`m=CNfD+}E@4z)_PEiG%mr?^sestSW|0xwMrbEFWCs=>hZ6x+`JiC? z6i^I@XfS$fw|rX0#s%!ki3P>Q;b%{GyS0|g@9SgTcdB~Cx7+Bc-+=o%p~6t707KgsD5oO>Pl^Zb)E1 zS0?SZ@+vG1%DqMVa$It62$LJO?sX;bMJe<%g+^s#`FEU0gW-5HUdShmr3}yzL(q>R zWD%2((N1BI!n#;hf%NFS%^lTXBFPChXUloX1#8ebGO_$u=SO4ka7`y;lUCcX_IX7- z-18UGX|Wy)ZY=fKfSDa@09&$2Ty>e)6AucFFbPP384{%G3GDwQqpcgM5r6 z&$+G&Ttx3S_x@5FFlK}6<$?FSN}#TI8VD`s~0v1p<&MDuzYl#3|JK&QAYF`qkcwSRkrd)DC^w+p?ghyHb3Ic zlS2>Va~qWDrms2;(^*M^08Ypr98)-@-kRUeYV+L(@-D)>T;zx;KhrntAxTJ|cy*es z$q|*BdI*Nqz5ROqj#P(}k^j>a?w=23MfWcd5v`ke|NXh%*{nN0`F3PeVX{1**|B9@ z=SMs8Q!zWkYl0IxvAneTiP)ADz=%x_j`fW~T&?4EnF;~}5jM#!d@Mq@OQEu^7tQY32IIz`-S>UaKJX?`pbjrB@TgV#dV4pRc_)R= zmPzg27Lf>pt(CXTGD#%C@!h(*-o&<|ChGz)tMK0-qHw|>O%-f8?%f{p`tsG7{c+E*(=HpLt)qD^>mR&|t8S!o%uT*U^SV!>eT$ zL?@{`qdO!9iO#^!L0b&UO?D>{gxRfDU&g_dC{30EiDh10i;9gHlg}*=a=W2?c9;{? zmTvHHZE|yMXbFYpNpJE;GYk-lGFJaY060CENqLA|F0?{6zwni7euuft5V)^iVjwtD z8H%Vq5mV$J(j99St`mbPbv9nIP!*1;Xy5VvEC|-78}SBGogyooV{UI)c~d^DDc7w_ zi|<950ggf-93RiJL*){|Ph;>xCf%TOjy^4dNN;p}biHuk>lps4%H^Sc4E&2@BM zA%=2>kdMH7nCZzv$4k6Ot)){|m@$Oj#C#wM%eDr{n0D6e!AL|0b%U-zNTIl@vnLCZ zpC!ZdN_9N}OyHH_?cWc**DoI)ynM88-*fNaON?%g zOH0#I5@A;sA588fJt|-dTu5L!{Sqe^0K$e3lZYPKvs5HPR(dQ=o08yT{D%dVDhX;L zSIPydjp*;R=fwzyB8?6vzYAY9P@a?Vxy6o<8q<&%5AxfRP%zX24%az{>z zR_{lZ;^AAPZJTR2Gn^IagIeTj8=8ciS=BYo^o{0MVDa1bWa4e>Ib$bNi3COi)xAyK z>mc3d^gNM)`@@u&wqZr=j}NGV0wj?H*1swR%r1~rfh?abSwam7r)H*u)XG+WSXk4h z#SGl-dC+?b%aQtl^YV`+&;G19mn#>}&E;3*jwWv?1JQZj)E{_G>D#2NzKDI(SErSqe$w7b*2&=(OF|kys>0*M#Kd||JMIjUX9re){xNP?H*>@UT{erB%ur2 z4mL^@#ALCoE3#Og9Ns$bNENbL)h6FHY`PlGPD-IRYu+t0a~i`5~imEy3+zszGE%uyFHQ zV;r7-su*82PkR9$ukP)-!mVa}gvBr$Yz3#|W6#41>;#6KeXai8Jg1KgxI4w!OfKCz zJ3L)*aCK&mrErzc;Mw$sSc7@9aSnTS1hvl~7@Z?*R=ya=fTX7`@iHDoHXz0CSo#k( zp8@09YU~4|5=8r5aO)OGT2a!n$OzH2Vyd-g%$#kh#|Qhv?52xuOB+xs$% z_Iwq8YiWA*Oqcm0%Mz$!lCaxe=v3H4ds?ha8)=UgfVrLMt1!9R`-G)(70_}@OO3mfsV&4 zU(FP(_Fa?xhR-V{TLtUfZc{FDEL@4X8C7MVun+yUAy^jdx;T%*tR1#sOD^TfM>s9s z$9aV8MPpJsULa+1EZtOj--|?{v$bJ-auw%Xb6aMPbp%cN(x=(BklUtzclsTVGw`oL zIj)0`GPiGj-YoLd3hK(LP{h&BEh%tP?@)@F`;FUXS1w&P<{nl&gXF3PP6kMc{KkS`Gcr?BcG2wH+BuB8=I=hALWt&$2`We6!sxI z*ri)TZ~e{E;f2rR{HRa6--3EkMA6tD4`@V! z0FBKAu_HZ5Rat*1hmKy>-jDgKs03Wpk*1At1X$tS*SS=T=Z}Z}LnRH$iok&$atjHtmTj|=q zI0pLYI>QBuXnL}(Cz!J*@v$dWSVvcxE_VQGGem@Zf8zvGJ$>D8!#C&m!oJ}>Ci}cF zJg=QA``pEfwbD3kZ5tG!5zl6oc{(X#FS$4ssWIoLX=NDjHWlfGX%|mLVh-y`zGN$w zM2-|&aeO1KylJB`UV65becq zNyqKHenn70irv$CV+0Yc1xNBTiafzGS=ygpOuo${ zL&xVWt9qW`dj~eUc2A`ZZWm$6Tuav~^2b@K^pY)gMONe8DPFH7?FBCHya-e8`=U_j z&ZqUlWYlHQP(NAUy2KH+Pw3ZAB}g?b1c~7)hd#a|Pbrc$hWJ%^%KZhcimxgE`@>x_ z{o$X&c7YEoknq2f@d<0pz=2zz`drRdlm+>CWvrbDw^~W(5SY7x*Nw-xmvbd3(hS5lFH0&vd$)7UBj)sIy|^IW z`{k^u_kaH$*IBFhW9gV+YyO?TBBoFMP6`P;=NF9J2LyF`0IK)pJi3@@iV!`5BD2$V zxNx`L0db5Ml&J6cDdQ6HOQB?UNgIy+sXvndkF_K*FmJN$fZREmw*QPI-i@AkDjy#I zNaNM#e%-Yoy#K$!Bzn0#&D-MfU?*|-pRR0e^#M#m6)PprR+t3f|`R9kDt2p~_3LouzMJ60&+4Me1zpGWnyHmA0a?(yEj3r36Yc5_N-UmAT z{>+7DuPA}0?G6XZQ`N{^)1?;EFs1*7ne>ermSAJ6Qme)gPp6el7Lpm(%KG9mLX%)D zKjgafAR6|LT*REvocZ(Y-xb)DOb>JAE{@qD8rVzx&C1~W{pq2M3zYHam$B-+jf$1a zN*_~o{$nJ@KW9*%TkSU8)$4Dy8pv2ZrboRW89oT{_tAeJ>W!Go7k zcrH5H@`O}ft7e7t@CROk{b8<=538Q~GrecXLNA^|xhneuHB9sm>nIykU)mWm9A+Sc zH?g_c->Ok!2GDv@?w5z_+4zflTuF`;>BS@Wk?#*~HYdUgW~91b4NqKE^OkzUY=5-M zvu3wMi*xmr9Xtxnep5VyYVcEfUv91vN%AB<@&G)*=Pb0UU-l80;{v^v4t_h9{K09= zv-@eqK?SRF)lI>o{x_4I#|5=69TUinI+S@YXi`d@{a$n3+qXhFHuqObu3s!Z1DejE zURu@2T4`i+^=ZVKKH&PE0Tzq+n$r#WI{VL}0vj?QE=s_b^Qr|djV&DH!)6-EdBk28 zb2ezeJsh?9Et?1(f&(h zp1aS0IPb1}>1cHD}hsYv&qqvs$)hC>ldadWmZa5Bs+|Im1!314nKH5HR- zrIvZa`j%N3zo^4W)w|xVY3gsczwga^#It!&F4BY=a1z@T61j;>DZ>}1D}$a z9-_F*_Ky@=W2<~$u{PPHNu#%WdRwoqe;#FZgInjkUevc*#WwMCe14BUy%j_I4Z^U| zS-@dS?Q$CAFw&18Bv$M4IngZ8Iz_dIT92%@lbuNUhY(NL0=^u&TVRkb$Co#ak$dG8 zqm-F=QZ(ZxkIBtQ`)3*uP)G5QU# z8Ig}1F9|(PFqNM1*_}E6ajH%mo-pn4jh=4={n;aEj|8Kb@^8z@a=$&E)bzYmb-CnI zY+Xc=ZVBE;bE0Ju<>2Gnt;pWGiJw4i9@%S1qPiK9#(c)Jl{TNPw-o6mk#;9A4O}>I zA8ILiMRb8B0jX-uA{bqzC2H2}e0RR>KYDx{uGc{c#dH5CLc=cSF$r{@X6XT&FXn!Q z%i*R#8YNmPj=&UtgMU%vEQx8>n|gtA%yJuG0)8)9(tw?8_SbqK@#6)|6Hr@(Dh_*{MM${B5mXY({A1S z?zCDDoN^t4pz5%+DMCBhB*^TXBiF;*$Sz#w1yRclG!$H8#iEkKlNc_7PJJW1`qf09 z)KwssmrRaVi1ZhPw|XSBWG~^yH5n@n0fhcQ{{R{H^_sL|)8E$nBR{2&Sc*OKOnDJ* zDpNbMQQWJJ*}mr4Rj?1=`?z4^WF$3UNNRjSqBr^KaT?CySY-PVIA5IjC+DRcDQElF z(c0WHXzf|m%0~!O?G7s(w?rsPzRvy|O8OKk8+7dYygIafDE1d58ytE@&JwtJjK^>T z4aXASkI@v7_Od2W{I_*sEU#Zz$SO-`=(v0z92#;6;FlTsc@kUUZ;oqy1E=$s#jjTj zAT;Hz_)mKAv$ad|uUCpXc$$Z5svVx_(Y*rw>&35o^-M!K_}W%D`nS*D(KYX)E(WULBz%E4U#BEG?J(9O$2#IB_+iCbN2l`3Q11rjbXq;OxS7YRd|7 z+H%hY{Kmm%jqBnsV6_(%tOnwg<8GY+&N*D}61QxO$pLI)ag{hybhRPsn1v{ED1oAV1v11bRYB7mCOwyz9kc)1CH`xv#ZLmiE?z*!RY-_;T4%- zY*%~t-uqUnQ0n;4t-=PnRg`C#JyOdcKJpCHu%E5?s%U5$IaUQ@(qVWD-qzrIci>W% z(jDpcSK|tWygO~a84Ug^Lw-^e-FUFZ`+>_eY)}XJ;?={p3Eu|Trb%! z21|P!p&fQM15pP0>Ljbhrir_FwhU}gy-6=V}z{@e8i+@qR;GBhrTzLZ z?AO075JK%G;_&nmcg0P#|B_ND$$&Lqw8nJoUJ}@QbB-cvQm7wh3hYnF`{ov}pY4SH zA|B23Gj-=s8cfM^E{e$a>Xq%#|6sfE6&YGfB4Y>NG)hS6$=0o%LM6xW7y||3Au*hH zQ1H@2HU52>I??5CnsMLw*L42Jz(wV=Qt8b9^=~;W%cMeQOS?ATNBzOic@Fb#_dou+ zo#feuhj^YSkKeBFuNmzm^8TaiU$|ARF$~&UCEIK4_WM^4tt(g%YcsFcX07#awX^o^ zlI@i-Mbur08}^FQXFe)^MwWseUPupB4MCs}Ym+&VH8*SYw`m)ViMY zrFv))7-#Qs;}>nmXkNXdTDvzQV6mux$moxU-a`vL*pEs1Y??zs=T>&bg~uWju9dKa zRJz1Y$8b^`-J7;MEftVz$87$w4fa)q9OSL_vGE8Az6I~%(T5xSw~x<|xPlEZVjnuy8b!miE5uMSDTn~hN}S42LQ zuta1*Q)&U92tBAOw|d;)fJ@8(eHT%v3111G$w?Pz_7?COd)H)da+G`0e@24YQsc)w z%6r{EYZ}}?JYByj4gm$vgzDOs2l1b84V+3;_70Lcj-P06wVdn@f!>Qf<@Z}D>Cm$p zzu0|~G_<_FM*RGw$WAy{{o_Ga%Y$u&_>8Kth5tIjwQn`lup3sFom=3zBDfGJy!Yvk zGvv-2u@$bJP;q4b&;sRN>~p+s8Y%(J$i@42mC|m60EJM=sjDe5yrymQ*W1%zyVpev zXIAEasaOsbU0snJmBrt^!`E6SyL{H(<)K^Eu*~OszrCk%16%To-MrBOZcP)R-=?|O zei`l^c&K%cK}AnpEm|$DxmKSB`};>&^L@2RI;(tJh3mE?Uxli_MRJDEiiO-KVM90ls>nRHVHU)mdqr;u^dA?9>`HmpeMdPLqo$ zq;=a&6jpxct)ntu6mr}>rpt%bmhgulj>nTNfY~zzJcLc5DdrlD{WUiI!g@8iGbt&> z*g(=AOEbryCW4K|E*;b~vx?uNDPJHeDei2&_3cpH75?s0>Z<$S3bXL~o6u0fubQ9O z$4*6WUasmh;ipA@XPYsK#0Er;X=hS2Op2pRRo9q)PG*s*r^8q{{9@4P?hQO^y-lfb zd1By9p=8J;3_yF)f-fTvwGIiyRGM$8Df4qjHyvjm3(jfj%JOK{dJ*5WAa08MeZyh5 z;sneA)%SVKCOcoHqP*P2v$dp=GaW|cojGUeiF94z-*$)OTfYI1zc3N|yul{MtJ*aa z(p%EA)D-ErI%RLQ=g1TtRZGjd|Ni?k-erODgL1XOW41Zdo+ndV-c;KkY%TiwuEv|- zs2@Hy9ZuP~QSe_l^hwhHfTQ7tb6VBqY9Z;rZ@h?`BvJP3EjMXz*?xQCw!KWRiNrCk z_zctfapNcb(YTMBhZ?gvG=BELh*?x1lRN4SI)s{nWJZEeEimejx$4%{QfxyXeVq6y z$~ozzD+cYGjgrYDKe0&33x3t&Jc3OrD*OaL)mTFMd`1(&Zx(lzdr2bmhPcVi+l5Lm zuBiN$%yhJM^Ac?8>^Hj}3i(56#HwA0Z7EtwX7y zWDudS_G5|-$Yem*#&8FG82OjxwS99O*AqQk8l*;3-ZPiS2NGjU>ot~MX6?tE-AKDA zE%r-66vzCKcw>HELNjv-J;C?sajm1(7sUg}{|)EJ9iu)tki`Wp?1iTZ6(>zvxolwwqm|4t961e>GDt zwdmoi@{+Huix`9r%-$$6_L9Xf zKD$Y)p&7EO64Mlzb!j^Dkz?VDX85BeaWvt^)?YXglxEKx%~rY+!~2}ZW9;Q&^(?*2 zJh?$XWx~&eO)_64w2U)%3_6V~x=#M|5(v98sqS{l@NuDO%|p-Zz6K&(AL>7{fSMrbnOxTieQwg?rzr%E2u;p$8b z&o35xSXuB4E}9E!UH)qMFJ$HFBoEuZc?O@DKfSQZFqdtBZS-a1w>mLtTu1+Rg4siq zhw_6;6Z!tT6Bwd85+4T zY0xD%kL1_>Y%F=yH}A6^r8@(EV7rq39^IvsR{(yI#5g=L_tCB$nt>z(+m>`}u>#gM z{-YXbjv{LW&uz^)xMx-fw^AP;rlre%3zhBD!vz?Dzz<* zjE4LvuGUV(i6+jYh}4y*^PU*SgmV>eMadMKU}8~9qRCM>2lshYE!6k)EM)Z!l+-BUkFLWzpoll~9Op-FWNsxb2h|1==8y_Oy!x6;D8vQk* zq|7|1tT^?Lj93y)CbJ(_ZSf545Rorxj?lD+Ql!3(<<4QD?Cz}Wo#@N)9sY6Qx<%1?&+%w%7LmymX=A8GI7=_pS zqix1Q3?sWZHaV*vlguOAAJlYPGRC4QBO9F}N}tmiGHtu-J?AYMZXAZJM}uke9tT$b z6UZ&x3dpe*-+~!W0g<4hb@debrO{8Jx^$w;w)3q;)Q#i_+BN=9C&PunlX{G+GES=! z_qB8KW_4cD?z9_`ZL&s$8$8(C-i-pir#Vn?W7bNf6wX1C2f|bx37(NY|0-eFAH~mNlW}@^ap}-d<$C=;>j=x zd>}*75kCg5JOmeq%_D@OTN&Z+-QD7{~@jhN5Rz;7sjR>uXPH8ru{+jHIXNwcYnFKp0L!SAXUXy z4zK<4%?^68T&V?akI~S-*r-sp?shbu89N#Vr*xL++r4&?ygNx%6?ZQj&HnWIA76SW zwoxRzDgP70hs?8QUDqS8KNL78lH*-y$>fiMV(-!ZWhPk?Y0F%~#^g#YLJXhJCXJdQ znfa-juzB?=MLAV*A;#Z6i+Y76xX%l|eJF-mnrYJIhqJrLBKF&LEjPB`N zVccMMb-+n>3O(U1%e1Jeb*kD9KisrM?|Ko`ZpkQ~nCSCs?}$vNp|50Z4r(vOR1SA6 z7Ja{ow+5;BTt!>rlE3n5LjI8zOXxB!CfZTdZg2iOFw>KB=Of8sw}xE%=$7A^;#>g) zG-g&TuS{qsHSkx{bztX{8P55%^w5LVlWK=|_n zi)p{8#vbi@9$R_!m{%T7^lT3AO*6Z$o z#-GotPZw+M_x5PUUcpINa5ikCRh{RNjnbm*7X zD(-=5{+q{VY})oGrYw~lm#x9kF8ZpQ9hUg3u!!y*eAO#L6~COKz9D>WDd4Nm*QDw5 zOWdhJ;~jperAvlP+m&Z;ySH~V=PP&zQW=h_7c2sXhFwH&iY;ifw_ogK^HNlf*!{AD z<7I5WnRdFF>@}-<2XDWv7m7mp8}cpm<@v|6^k&{+T;*`?3kBB5#GObpmfn~FrY~|g zeSV)KpRF1y8eUsMIcyJkD`29_&kMdhdGeDomh|GPy_X+G|2o*f?Nyb$5<-H-T>Wil16WKlmC(>!P8da;ReS0(Y&Opza9J{5k(_?u3_t(G8Ke&lE zAnc)?{S?vuX9vd5eDs8t=yYc3NZwyk>`sw$Zt$7TgxCgK?Q>#h-TQ1%av|KQKUy@7 z=m{V)CaxOt#S36Qb)DvP|9RuUtyx`p>+=}hz%MTTcT&tMPydjH$#iW^4?M>x{%nE9@>7kG z3djbNXQ$rp#~L{G`!)2tgUp=*@}x9MfNwGuRG);Fd{MU87%UPoI^9ZuQxT|7qPxX8 z|MJOs#f{2kY${Z*3GzD@53a5>eKkvScvhkC_RW?|lI4caK(#Eq!-WgnOAlAKPK4JV zfmrXt7&rA!W{-lk6d@uGd zJLGe!BnIeFK1T4}gWCv_ZX;^r^vBY6pEIM*|L_xAkTc3X-u~{YHBzixd+(LkGPwYg z+WQTRZy!ZyTBAPjA)JMxqhDcnnWCeQi8MpwShRH8zP>bt-TAqZk{)T%XKJ6;=xs}m z{@c>UJrLAGFOwuStC=+AOC~f;=%&=v=BhSI({Qz!S<~#B=xqgq$ThW&n&-V~McZUw zK|FQNqQ+59q5aTiGh7UF#t0{j*8DD{t^IMKo)a&>*V5QSLu~cd?N`$IFbmu$KVVEK zmz(Ij#@EU&*q^9%N(k}kh@Ch#eLoB`bIPb^eELxa#n;Z^T0{1+%fP3ViY7czx#U6} z=}T{wRm~oD;1IVd=Xy@4SF}1-Qoz z4bp!<=e^+Vb>elDhV4%oO)U$PSoq44?Q)_ zjdDFC+A6{+{_U1P)^&7jOy+F32x z%g|UMo2V-x=fr(Creb<5DZT3+jR7Af55t#lkNA<&k=&i@?*`aD6bBrRUkZy})q9oq zE-ERFT(sG6y3d*RdKvl&%Tu+ zwZ1@NcWtID6DOYzzposoK`{E>XlPHJXl>n+h?tq7N3jfYG4F2E<75ICc_e$IGkU6t zGqLUz1~*dRatE6ydMvffBGySn6Qhs&dTN)E3g&LdI+p*upqxxBMaynCmN z2?!0ZHg)%`&`1BqhP@}LC6b(qNS8-gMP$;wXVDKt{l4C)GfUTQB3Cl{j3Y$!6*1o@ zX7`+(+X${dQO96^c|0t-T>r*DtJxiMhSHSBgzZndNx1%_AC8m_<0ZH4%ogRPgQw=9 z3jNRSrjYT&l2=}jyU{1?=ag2flzrEymM0!DU>+(gIgR>6<4wSr{c(U$F%@oD)pCq~ zvi4Lfw09x>mHT$zGq3)H+Hvu{(?W@XYocA&LNa>ySCd(yj>c7jEB8?wSUr?*GNq0o# zdeh*}P&wLc2lMnF%l981QzC`~N_-0QH?E&Q_9sj_9a8!o99oI-a6g=ROh5NVN$icl zQlY3}$#9Pge0ASk3L@Lbq+RLdw2eVpXJ$2;`nPrezt!iAOI;#?0pU?3Xs|!^!I4tAXHFQ>HijZpGKzVs*diGfgY}rh0W(ssPVa2LNV?9F4RPV=!n%p{Z=c#V@){eQN@6j z4{Db(_lh{mHY&ZiEMiZ}SfRejQy6RsmafU&br6QDs!_dO;-OvkRT-}Y-UFv=za=8O?Fpn*784)I;7TogL+>A%w+{U~W<1u5R+AkR6D(v!e zC4NYknv!Rt;96lWeHC`>(O5zr7PID>j61ulFSQC&Ac|?u#Wj&jzl&t@-+d>3DIX^x zlBv_^U3~jR`na08I?;EObKtO_E z{|RRlnCto_`LTI@RGjc$;+`b@4XEU2`$LrJf+oKhMxJkM5P>t0|NB)0{^j7m5%=$L zE=6GVlz_ad2ndOv;99f4C(quY1!NtH0R;X>;uc2*q7?%{+MyUEQVfKSH3hZ`QD{NA zheSOtY=*BBAyy*D_Y3~QWWIM2u5Nc zT0!uRf(|C8f-n^Y$`FqsCvdu0IGbQ54%lT#+Fc;2GaP|qN%D^DhGL2E5UW1oP5Q09 zy|B#$+cR>LHb`%KiRp2Csghq{_aXUh7s;RPL;TI9oxaU+iLU_swCsDG8?g0XTns&b zViJ*SL1Ym?56|^9}8yPGKf*1)x3$7nS&lWnRpuFuO+6*mG*FYO)xDr9~1h$QT zX%=qV2H3YQ;B6wjAZ~aYuWh3ir0+=IqD_abHV*lPZ6Wbn@)P&>gr6hsQS$r^q4WM9 zgKwG#;q|0_9p_)BuM%GHlJXsw4N;;*E zm(by+B9IQYAE1(ECB0w05qYl>v()o530j?baARuiANIn&TK-r%OK??;ykZ%R?@u{lf zWF2%+%9i({D=2>*T8mQmil#^26_waiNNR1`lDxHX3+)X-yWTya?ORZvIxQ1P?3UlN5I}O&C1X< zmlnizBty_kasKm$C9r>F@*KWv9+F0zf zZ8-Nv!Z$H8cop$}%)|Hj&)X}#$H6f2Vn7jr=R^K{R^auJ`RuwtJ0*B#UEo2Sv%5=> z0?>*8`2=}%nBp|)Kve{Age3ux{5t~&GpzZv`HQ@63(Kn{2bD?S|xUi7zC62_Ka7Z0C^wG2_5(_}qI5-#}cf z^y`BcTd&_@7d8s~4fv$x#Xvz`EE1U(L{!w5^qvc7GdQy8etPE>~V4V{9 z5k^M=D0+m=0%3bkI)y+-5p36c&pMUR!CDc}X$odU#%b=^1>}EhP@f?n(pSzUMrGI) znHTM_C;)8F$ltWtVy~ZfRfvy!`!4ix{0X*m$p2#q{|(y3_Wls<`B&_}hT}2c*XKsQ zc(Gv^c`*Vd{yiGy1rEzVof6o?GyMPebxPn!;2HQ?=DQUE(suttz~PKZ04 z1|-p25I-Zm!^;uK-`h+>P`yzeD+Tj6?`2g1YXs4^#_YYQI%yta<^{tW5UCbCpJ{#ba0FuUC0u`KwzY<4#I}YTd zu6|448#x-lY5g-2|Ec&99g8sj$|*+!I+D<-a29))SR7OYQV4L8ZWNHjPY^dGKgWX9 z878<+5IMu#=GqVBzS|=(qB(C!F<64cpQ0uINB~IVTEJ58AH)~beb(y}U*FyXcM=?s+w(H}(Y)7w8o4k$vE6L|FeMcYCmqtGJY``$`*@C6f0NdBOHlXtn{s5=@SxyUZ zxF>1&Z-Fn8Hbw-+iK++)oM<)@V84z86ahi}q5u$Ii7&YY*Xqc=5)V!R8NZ(4DL}Gk zxD{)JU@8K{#ae(NZIHcx+<`#IyHB@K&v^cUup>WV5TAIbY?55UC-Hv@z6b6zE$#ST zeS@^GCQp6kynnIxTwoaaY{PUkKp1NSIN}EpfIDzf|C;O(rv=3Q8V8FnyWkKH>0m_! zZYfSR6oC{1_E!nOi2Moi-b(Ol z{?Ea-v5jmiwr#UJ*nf!aSltKq{P8Gnv7f@=_Y~fuPZZyH*7y1?hLO)kxIoyB2EZ$E zApiR6oj8zh%f+++=X

|5t= z-0eQj>&WHQkk@FhIRa!~B?Q=fC;)=}A^B;Ke9$T1A*jRtmiXEVd)9eA@$oP zeVzIpw1xkx_zHc3_KCT^zB2NmXCsD@&t|xai*v-C0vzKdIIPbN#IykNe-ekfS0`uN zue(+uz*&B(a})XuK)!|Nv*JEv(oF~0?xq4G0pQ%308p+W`6c=kocm3Yb zznAb9+9`(n;5FFtkM#xY?CZPFiC(|OF!I?B=XEwVY9G%HV+Wd31|?m{nn}A~nk*9FMa}>W8qiZENzD5KVrvVG(uS5Ta{6T#3jkaO?VdCtJjecyIv@dX!_5tkq7PhY}ZTuqJ{JA#VA7L2zTtiL^zzcDz7vofZ&+WDJ{{9D_ z-*^jW!;$PwLI~LQ{&D>{1myPP5Wc8$8_xB)b|k>@ZY_W`KE1b503>~abQ{Sp36?+| z9%;ANqRnFp%AxQD24z_#0xJceCI4qR&!;rMWImMfG4Q0M=eP^E{tM4zmch27Y_8Mz zfz)fT`D-c9%WYfsUkILc5A+-r!^r0%>@h#%h)FpVP^_8%{Ve~L0G0FM(s=C#@ogNqxSD!H_wAYVOKsy!ieDax%06133@A)|Qko+x48%#-kBv_{s zKH6YW1T3eZTw4Vo$xr_66My#f-|;o>Dd~Mq!?Jk12#61B`G=g>*(O}?3d-{`+X@@j zq5huu%NR!PaTZe{z{y|a3Ni$~95TNVXSyD#}tC007!h1q)$MIUCIBGCLEzn6QC@K)gqAPri@hts8>A3oa7g7D+~_rCp~>Y z(i8ru9QQemdr1Eo&ikOYr!D+T`O9q+uJ?l{|LwbV}|mt zVl?n)#9f`E0tn#zUsAhP5K{z@BZGYHwBD)${-cZp3Gye5sNfAa=G%z7fw-Gp1cV5!7{thcZPy7} zF{px&WRggt5Z|7(69EWxB;rf1HrxiwWJtM2A}}L=i!3weTh4fT~y*AXA+O+NMM{Tgj?ifbyadfm(1jOJ4I<5{33GBUI?lb|Xe?7RG_;&#xR`Kt> zK1-T2IQ{*EIYM|;0v3|{pv#j&5fH>xVQ7cdWk|gfGVdjLJ;}U8@+7(-&h-w(!BK;M zq7iEx){T689>N!RZlD>gj-vZvnu@4Y;6J+px1izzyFFoV~5X6=AoJ+?LpJUPcgD0kh&PBBW zp56onBn5@*h0r9D;6joYI2y?5fgjuOc4(~l6YqmLce3wm)Gm(tfR3W~7JGT(eC+zw z;4*EZZP<tk@VhM_gX);t~3Uc0G z7bgk7Nm+d5)+vl{+4*fm--Ymj9G{Q45hB0WI#?I$WZkSIxUAIqQf-iPdTpbP_C5W% z!!UA>(?^U9boMejXa#}r#gN7iQN9A=yvClA?bkt|H*wsTTHc{B0AE=8F!(qm{iJj0 z-yR;^jxhL7JU&t9pQQSPUEFUkf)NkmC>#@Hd_1H>-d|H>$Tz;n$G+d*`+Vum{nC!_ z(|-uUe?X#JCd#>Pp<9I-QL`5*`vSKGWflGiEh~}qh+ zsShb#0(t$jl%0|1n^!~d7bMBOc9fy?>QSzJ&wf#17`eyAha_N&m{K$#ZWRXS&GH_V gVULRqA3FH|0bygBxa-G4)Bpeg07*qoM6N<$g7$Kj82|tP literal 0 HcmV?d00001 diff --git a/data/skins/desert/error.png b/data/skins/desert/error.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf598256bb71eff501a0d50b8f8c092c8bb6ad4 GIT binary patch literal 16419 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 Uf8!suBOfp`x?xzOk9hk30mWU0`2YX_ literal 0 HcmV?d00001 diff --git a/data/skins/desert/friend.png b/data/skins/desert/friend.png new file mode 100644 index 0000000000000000000000000000000000000000..66609ba9ba3b7048d7b776f05109ceb361282f3e GIT binary patch literal 16912 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 literal 0 HcmV?d00001 diff --git a/data/skins/desert/glass_iconhighlight_focus.png b/data/skins/desert/glass_iconhighlight_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..13f47e8a22dbf51a3cf77579caa50d323cb94a77 GIT binary patch literal 25921 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 V!Q-Su^8h9RIXk-Vd}<#M`#(Romihny literal 0 HcmV?d00001 diff --git a/data/skins/desert/glassbutton.png b/data/skins/desert/glassbutton.png new file mode 100644 index 0000000000000000000000000000000000000000..1481be86b75185b1a67fd8d5b2daed7970c2311d GIT binary patch literal 12284 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 literal 0 HcmV?d00001 diff --git a/data/skins/desert/glassbutton_focused.png b/data/skins/desert/glassbutton_focused.png new file mode 100644 index 0000000000000000000000000000000000000000..f80c28b33272048e61bbbb70b9f38a98ac293121 GIT binary patch literal 11653 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 literal 0 HcmV?d00001 diff --git a/data/skins/desert/glasscheckbox.png b/data/skins/desert/glasscheckbox.png new file mode 100644 index 0000000000000000000000000000000000000000..f09123196184d9619e2b34c6b00bd7758eb5033b GIT binary patch literal 2334 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 literal 0 HcmV?d00001 diff --git a/data/skins/desert/glasscheckbox_checked.png b/data/skins/desert/glasscheckbox_checked.png new file mode 100644 index 0000000000000000000000000000000000000000..4da8300752cac9ed60aa73b8cd57a90cdaaedf5e GIT binary patch literal 2428 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 N002ovPDHLkV1hoAamD}u literal 0 HcmV?d00001 diff --git a/data/skins/desert/glasscheckbox_focus.png b/data/skins/desert/glasscheckbox_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..e028df01201e36501543082986d733ce0721141c GIT binary patch literal 2635 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 literal 0 HcmV?d00001 diff --git a/data/skins/desert/glasssgauge_fill.png b/data/skins/desert/glasssgauge_fill.png new file mode 100644 index 0000000000000000000000000000000000000000..98ed4a87ec391d4d53c30b86536265b6c446d6eb GIT binary patch literal 4991 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 F{{bqjbE5zN literal 0 HcmV?d00001 diff --git a/data/skins/desert/glassspinner_focus.png b/data/skins/desert/glassspinner_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..5b78f4e4ac3b0d06b509434ca6539b4b430287fd GIT binary patch literal 9280 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 F{{fdeNt^%x literal 0 HcmV?d00001 diff --git a/data/skins/desert/glasstab_down.png b/data/skins/desert/glasstab_down.png new file mode 100644 index 0000000000000000000000000000000000000000..e59baa7146e704bb8bbf726f09446646a0f92855 GIT binary patch literal 2626 zcmd^A`9GWa7Jfr4b*-(Ut*T*4qH1hyr?x?@t!gBeAVeauq;|1ah0^KV=@=c?7%fG& z+fCKdj&8Kt(sFg7Bn%-$f`sIKzi+4+!_`0H{&b(ubDqyR&-v|q&iR}l2!Xy@8ap*0 z2-5QR^CChJW;2D{)s;83`%L(G2vUX!0m0szrLwZpb^{$84u{9%t*xzXZEfxB?CkCB zU0q$>+}vVaEj;}keEb~3qCCPQgQKWqDwRr$jf#zpWiS}=@$pGXNhv8Qsi~J zPK_B(Ek&*mi=5jzE>DXOHSukFmVD56HqP@<&pr807i*mj0pY+MaF}`1PS325Izy+2LpZxm<&Zn2`G<*@=;cro~W3J zQH;}3evE=oL-}+CKUTqKAXCA}RG54w1f2>)rpSmO90($j=?Fv+4Q8ScAsH4$z_S!s z6s-_Y(P;`iM}Zfpu#_qiu*5S-VqwahAXPk_J||?)3$x~Ca_43W=0$mnAaw~zmw^l! znlD2OWN0BgO#{LhM6^jd5Hf)<4iPg@0bMZ_tC)#VOw-YsSjE()!$dc`vk7391w<+6 zYyvu)h|JLu2@RfOfH@{I9|z{*VM#o)NQb4du#|x;G7)JUvKWudCm{2QV4ejQPJ)Fb zu#gNSDPSQLSxi8d62W3JkftKCWJHz3~n(QFvah0#+8T8PSXQ6vuq1t?meP!uhp97M6nVpvfE zD@wnt?Ee_GqnB*H90!{iNZR=S21Hs>+q*gLEopw?nGj@S_9Za4rzd{dG}YMt$Gz2r z7!All|L^1H;Ywl|qgN{wUZ&@z}%8Z9w}ZIi-en>yOq+8kUvA3F&_D%btJJc4th z7cZ@b5fhC#LFxE?LxhNS=EY^oSkxdPjr%mAgiCm-l+kdET!FE*(lebu8_#Q08pTwT4z?B)M%+tK!a0Xh0&?k)o}QHfjyd zyr8GclG|FUFYneoa?bf~Jc{z?{dUw4Pgbh(COmdn`KaS{C+n|gxNL2<8T8W<7GvLg zr_<6l;KchiciXOSyE;Bw;>p;mytYsOLEB&44L@*s3#N9?(d@a8uhnaZOleg%o!)vo zpVb$0%GJTy)%l6-p$#?sZ}pMCsWjGbeO`VF&KefJDqS8X->@uO=zu37%TKXaV`rLs zdMzz1efc}%IHN27komvp{wut@SDwwt$eR;hA0rtV(RRNj-D7OLGrw`8N`H>3simd8ysxS>^3K!a z78lOF_I(zL?I02@e*M?mv53e>=gV$|w~aq&vMzU-s=W7Lx^E%wHsxCEt320#^xj>~ zv}=T5BGF9$$CE4}vYh={QXH?WbNVY49e0(|u|H;!i#uD$>Q}CGoBxV=xVw{Vy0waO z7Hfa2y|eS#J<{l4(Z&vZ$K>P{>D`mf&DBSl4MmT zztQ9C^~&4Z$46~-@uB9_u8e=arF-vf8LcL!*HSN@w)y?5FnAlD!0CI065Y!G9Zhem zyh64X-O{D@Lj|XlJWFZa#{ zElr_7sIrVE_0lc}gM&kD88#KAwRcg}(WE?c>!^{c8fS;G?o=Dso^z-cqO02Co(ra2 zqE)ePqSiUz)Kb(dUd#xLwLfpelnAi7k*YlLqHNEb7~Ae{TkFF$FK2IDV=$QUMMpGR z+uH1j#12YehW**Hvf{XguCA5N_e$9MxXXcl&v{7)tNUm4%q!Ylj!?fn{7PM(OR>30 z+p?u$$666a>4d#eVV00rl6{{$DUImeFNgZfV_Y#K z-w7PB znHH~Y-yzwH|J3~UtD>O6{15|0|KJ;HwQoMHgj@rAr80ZKP~Z8yMAo+aW28%N`;XUf zMYSIzFJ-RBCzq3JuYH@!Z{5vnDO8gW`*vDr^?R1?!YM@_bSAm&4}9FwoN;Z8n1u7A z9cj7lbT1>P7&@7FPrH0M*xA|2lhgF<>Y07X`?0o7nK@C(GU1f)oNmL(uCd|5x*ybI zB78GfJ!0zsg1Q6@BWQ6b?zdGt}YdthMTHB(EFqRp|f7@C|@(Rj#MYWn=; O*ZO-0dfoGkDfut!@tR-& literal 0 HcmV?d00001 diff --git a/data/skins/desert/glasstab_focus.png b/data/skins/desert/glasstab_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..245d3edbfd5c41d4f1861ffe359dac7aeff01474 GIT binary patch literal 2947 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 Z?6hFANSY$CJoNWZYj5jBd}JMX{=XEeDf0jT literal 0 HcmV?d00001 diff --git a/data/skins/desert/glasstab_vert_down.png b/data/skins/desert/glasstab_vert_down.png new file mode 100644 index 0000000000000000000000000000000000000000..6c538925736e52b9aacf516095e634d95750dbfa GIT binary patch literal 2599 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 literal 0 HcmV?d00001 diff --git a/data/skins/desert/glasstab_vert_focus.png b/data/skins/desert/glasstab_vert_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..db33eb0e8056059fa2b576c8f5d7953ed757fa3b GIT binary patch literal 2676 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 literal 0 HcmV?d00001 diff --git a/data/skins/desert/left_arrow_focus.png b/data/skins/desert/left_arrow_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..983dd66d0ee8ec87d12227fa7f418bca9b08f30e GIT binary patch literal 2447 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 N002ovPDHLkV1jjAPk;ab literal 0 HcmV?d00001 diff --git a/data/skins/desert/right_arrow_focus.png b/data/skins/desert/right_arrow_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..0c72b0b2b2446a000518da4ab5c48b58a648736f GIT binary patch literal 2556 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/skins/desert/table_header_down.png b/data/skins/desert/table_header_down.png new file mode 100644 index 0000000000000000000000000000000000000000..585b4c9523161a473da510c0af065d184e236dae GIT binary patch literal 1862 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 literal 0 HcmV?d00001 diff --git a/data/skins/desert/textbubble2.png b/data/skins/desert/textbubble2.png new file mode 100644 index 0000000000000000000000000000000000000000..e028df01201e36501543082986d733ce0721141c GIT binary patch literal 2635 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 literal 0 HcmV?d00001 From fa0bb71c3ab3fc5eba83704f007a78a2aee459e7 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 27 May 2024 11:37:48 +0200 Subject: [PATCH 414/830] Add new variants of the cartoon skin The variants use the same accent colors as variants of the standard skin : blue (ocean), green (forest), black (coal), pink (ruby), yellow (desert). Made by CrystalDaEevee with help from QwertyChouskie (base theme advice, original cartoon theme) and myself (forest screenshot, advice regarding screenshots, initiative to get it merged) --- data/skins/cartoon-coal/achievement.png | Bin 0 -> 6842 bytes data/skins/cartoon-coal/background.jpg | Bin 0 -> 159999 bytes data/skins/cartoon-coal/bottom_bar.png | Bin 0 -> 23037 bytes data/skins/cartoon-coal/bubble.png | Bin 0 -> 49620 bytes data/skins/cartoon-coal/button.png | Bin 0 -> 6591 bytes data/skins/cartoon-coal/button_focused.png | Bin 0 -> 5988 bytes data/skins/cartoon-coal/checkbox.png | Bin 0 -> 1740 bytes data/skins/cartoon-coal/checkbox_checked.png | Bin 0 -> 2482 bytes .../cartoon-coal/checkbox_checked_focus.png | Bin 0 -> 2423 bytes data/skins/cartoon-coal/checkbox_focus.png | Bin 0 -> 1605 bytes data/skins/cartoon-coal/dialog.png | Bin 0 -> 5764 bytes data/skins/cartoon-coal/down_arrow.png | Bin 0 -> 3247 bytes data/skins/cartoon-coal/error.png | Bin 0 -> 5961 bytes .../cartoon-coal/error_red_with_orange_bg.png | Bin 0 -> 6338 bytes .../cartoon-coal/error_white_with_red_bg.png | Bin 0 -> 5785 bytes data/skins/cartoon-coal/friend.png | Bin 0 -> 5760 bytes data/skins/cartoon-coal/gauge_fill.png | Bin 0 -> 333 bytes data/skins/cartoon-coal/generic.png | Bin 0 -> 3658 bytes .../glass_iconhighlight_focus.png | Bin 0 -> 34607 bytes data/skins/cartoon-coal/glass_rsection.png | Bin 0 -> 1266 bytes data/skins/cartoon-coal/left_arrow.png | Bin 0 -> 4948 bytes data/skins/cartoon-coal/left_arrow_focus.png | Bin 0 -> 4686 bytes data/skins/cartoon-coal/licenses.txt | 30 ++ data/skins/cartoon-coal/right_arrow.png | Bin 0 -> 4867 bytes data/skins/cartoon-coal/right_arrow_focus.png | Bin 0 -> 4649 bytes data/skins/cartoon-coal/rsection.png | Bin 0 -> 350 bytes data/skins/cartoon-coal/scrollbar_bg.png | Bin 0 -> 250 bytes data/skins/cartoon-coal/scrollbar_button.png | Bin 0 -> 656 bytes data/skins/cartoon-coal/scrollbar_thumb.png | Bin 0 -> 217 bytes data/skins/cartoon-coal/section.png | Bin 0 -> 366 bytes data/skins/cartoon-coal/select.png | Bin 0 -> 175 bytes data/skins/cartoon-coal/spinner.png | Bin 0 -> 4120 bytes data/skins/cartoon-coal/spinner_down.png | Bin 0 -> 4120 bytes data/skins/cartoon-coal/spinner_fill.png | Bin 0 -> 200 bytes data/skins/cartoon-coal/spinner_focus.png | Bin 0 -> 3991 bytes data/skins/cartoon-coal/stkskin.xml | 376 ++++++++++++++++++ data/skins/cartoon-coal/tab.png | Bin 0 -> 4835 bytes data/skins/cartoon-coal/tab_focus.png | Bin 0 -> 4455 bytes data/skins/cartoon-coal/tab_vert.png | Bin 0 -> 5195 bytes data/skins/cartoon-coal/tab_vert_focus.png | Bin 0 -> 4971 bytes data/skins/cartoon-coal/table_header_down.png | Bin 0 -> 204 bytes data/skins/cartoon-coal/textbubble.png | Bin 0 -> 420 bytes data/skins/cartoon-coal/textbubble2.png | Bin 0 -> 420 bytes data/skins/cartoon-coal/tooltip.png | Bin 0 -> 299 bytes data/skins/cartoon-coal/up_arrow.png | Bin 0 -> 3199 bytes data/skins/cartoon-desert/achievement.png | Bin 0 -> 9500 bytes data/skins/cartoon-desert/background.jpg | Bin 0 -> 243666 bytes data/skins/cartoon-desert/bottom_bar.png | Bin 0 -> 153048 bytes data/skins/cartoon-desert/bubble.png | Bin 0 -> 50405 bytes data/skins/cartoon-desert/button.png | Bin 0 -> 7314 bytes data/skins/cartoon-desert/button_focused.png | Bin 0 -> 7194 bytes data/skins/cartoon-desert/checkbox.png | Bin 0 -> 1910 bytes .../skins/cartoon-desert/checkbox_checked.png | Bin 0 -> 2740 bytes .../cartoon-desert/checkbox_checked_focus.png | Bin 0 -> 2676 bytes data/skins/cartoon-desert/checkbox_focus.png | Bin 0 -> 1932 bytes data/skins/cartoon-desert/down_arrow.png | Bin 0 -> 3633 bytes data/skins/cartoon-desert/friend.png | Bin 0 -> 7796 bytes data/skins/cartoon-desert/gauge_fill.png | Bin 0 -> 236 bytes data/skins/cartoon-desert/generic.png | Bin 0 -> 4618 bytes .../glass_iconhighlight_focus.png | Bin 0 -> 37430 bytes data/skins/cartoon-desert/left_arrow.png | Bin 0 -> 5299 bytes .../skins/cartoon-desert/left_arrow_focus.png | Bin 0 -> 5198 bytes data/skins/cartoon-desert/licenses.txt | 30 ++ data/skins/cartoon-desert/readme.txt | 10 + data/skins/cartoon-desert/right_arrow.png | Bin 0 -> 4884 bytes .../cartoon-desert/right_arrow_focus.png | Bin 0 -> 5015 bytes .../skins/cartoon-desert/scrollbar_button.png | Bin 0 -> 684 bytes data/skins/cartoon-desert/scrollbar_thumb.png | Bin 0 -> 215 bytes data/skins/cartoon-desert/select.png | Bin 0 -> 172 bytes data/skins/cartoon-desert/spinner.png | Bin 0 -> 4383 bytes data/skins/cartoon-desert/spinner_down.png | Bin 0 -> 4383 bytes data/skins/cartoon-desert/spinner_fill.png | Bin 0 -> 184 bytes data/skins/cartoon-desert/spinner_focus.png | Bin 0 -> 4585 bytes data/skins/cartoon-desert/stkskin.xml | 376 ++++++++++++++++++ data/skins/cartoon-desert/tab.png | Bin 0 -> 5035 bytes data/skins/cartoon-desert/tab_focus.png | Bin 0 -> 5064 bytes data/skins/cartoon-desert/tab_vert.png | Bin 0 -> 5448 bytes data/skins/cartoon-desert/tab_vert_focus.png | Bin 0 -> 5456 bytes .../cartoon-desert/table_header_down.png | Bin 0 -> 454 bytes data/skins/cartoon-desert/up_arrow.png | Bin 0 -> 3528 bytes data/skins/cartoon-forest/achievement.png | Bin 0 -> 8806 bytes data/skins/cartoon-forest/background.jpg | Bin 0 -> 324965 bytes data/skins/cartoon-forest/bottom_bar.png | Bin 0 -> 44820 bytes data/skins/cartoon-forest/bubble.png | Bin 0 -> 24975 bytes data/skins/cartoon-forest/button.png | Bin 0 -> 3005 bytes data/skins/cartoon-forest/button_focused.png | Bin 0 -> 2928 bytes data/skins/cartoon-forest/checkbox.png | Bin 0 -> 1834 bytes .../skins/cartoon-forest/checkbox_checked.png | Bin 0 -> 2115 bytes .../cartoon-forest/checkbox_checked_focus.png | Bin 0 -> 2103 bytes data/skins/cartoon-forest/checkbox_focus.png | Bin 0 -> 1813 bytes data/skins/cartoon-forest/down_arrow.png | Bin 0 -> 2429 bytes data/skins/cartoon-forest/friend.png | Bin 0 -> 7180 bytes data/skins/cartoon-forest/gauge_fill.png | Bin 0 -> 5039 bytes data/skins/cartoon-forest/generic.png | Bin 0 -> 2881 bytes .../glass_iconhighlight_focus.png | Bin 0 -> 15502 bytes data/skins/cartoon-forest/left_arrow.png | Bin 0 -> 2969 bytes .../skins/cartoon-forest/left_arrow_focus.png | Bin 0 -> 3014 bytes data/skins/cartoon-forest/licenses.txt | 30 ++ data/skins/cartoon-forest/readme.txt | 10 + data/skins/cartoon-forest/right_arrow.png | Bin 0 -> 2946 bytes .../cartoon-forest/right_arrow_focus.png | Bin 0 -> 2982 bytes .../skins/cartoon-forest/scrollbar_button.png | Bin 0 -> 802 bytes data/skins/cartoon-forest/scrollbar_thumb.png | Bin 0 -> 339 bytes data/skins/cartoon-forest/select.png | Bin 0 -> 302 bytes data/skins/cartoon-forest/spinner.png | Bin 0 -> 2822 bytes data/skins/cartoon-forest/spinner_down.png | Bin 0 -> 2822 bytes data/skins/cartoon-forest/spinner_fill.png | Bin 0 -> 4954 bytes data/skins/cartoon-forest/spinner_focus.png | Bin 0 -> 2761 bytes data/skins/cartoon-forest/stkskin.xml | 376 ++++++++++++++++++ data/skins/cartoon-forest/tab.png | Bin 0 -> 3400 bytes data/skins/cartoon-forest/tab_focus.png | Bin 0 -> 3337 bytes data/skins/cartoon-forest/tab_vert.png | Bin 0 -> 3137 bytes data/skins/cartoon-forest/tab_vert_focus.png | Bin 0 -> 3080 bytes .../cartoon-forest/table_header_down.png | Bin 0 -> 1056 bytes data/skins/cartoon-forest/up_arrow.png | Bin 0 -> 2372 bytes data/skins/cartoon-ocean/achievement.png | Bin 0 -> 9456 bytes data/skins/cartoon-ocean/background.jpg | Bin 0 -> 266252 bytes data/skins/cartoon-ocean/bottom_bar.png | Bin 0 -> 45444 bytes data/skins/cartoon-ocean/bubble.png | Bin 0 -> 24143 bytes data/skins/cartoon-ocean/button.png | Bin 0 -> 3150 bytes data/skins/cartoon-ocean/button_focused.png | Bin 0 -> 2991 bytes data/skins/cartoon-ocean/checkbox.png | Bin 0 -> 1884 bytes data/skins/cartoon-ocean/checkbox_checked.png | Bin 0 -> 2168 bytes .../cartoon-ocean/checkbox_checked_focus.png | Bin 0 -> 2120 bytes data/skins/cartoon-ocean/checkbox_focus.png | Bin 0 -> 1848 bytes data/skins/cartoon-ocean/down_arrow.png | Bin 0 -> 2481 bytes data/skins/cartoon-ocean/friend.png | Bin 0 -> 7710 bytes data/skins/cartoon-ocean/gauge_fill.png | Bin 0 -> 5182 bytes data/skins/cartoon-ocean/generic.png | Bin 0 -> 2912 bytes .../glass_iconhighlight_focus.png | Bin 0 -> 15161 bytes data/skins/cartoon-ocean/left_arrow.png | Bin 0 -> 3013 bytes data/skins/cartoon-ocean/left_arrow_focus.png | Bin 0 -> 3038 bytes data/skins/cartoon-ocean/licenses.txt | 30 ++ data/skins/cartoon-ocean/readme.txt | 10 + data/skins/cartoon-ocean/right_arrow.png | Bin 0 -> 2983 bytes .../skins/cartoon-ocean/right_arrow_focus.png | Bin 0 -> 2994 bytes data/skins/cartoon-ocean/scrollbar_button.png | Bin 0 -> 798 bytes data/skins/cartoon-ocean/scrollbar_thumb.png | Bin 0 -> 339 bytes data/skins/cartoon-ocean/select.png | Bin 0 -> 302 bytes data/skins/cartoon-ocean/spinner.png | Bin 0 -> 2888 bytes data/skins/cartoon-ocean/spinner_down.png | Bin 0 -> 2888 bytes data/skins/cartoon-ocean/spinner_fill.png | Bin 0 -> 5123 bytes data/skins/cartoon-ocean/spinner_focus.png | Bin 0 -> 2787 bytes .../cartoon-ocean/spinner_rainbow_focus.png | Bin 0 -> 5693 bytes data/skins/cartoon-ocean/stkskin.xml | 376 ++++++++++++++++++ data/skins/cartoon-ocean/tab.png | Bin 0 -> 3507 bytes data/skins/cartoon-ocean/tab_focus.png | Bin 0 -> 3381 bytes data/skins/cartoon-ocean/tab_vert.png | Bin 0 -> 3249 bytes data/skins/cartoon-ocean/tab_vert_focus.png | Bin 0 -> 3134 bytes .../skins/cartoon-ocean/table_header_down.png | Bin 0 -> 1056 bytes data/skins/cartoon-ocean/up_arrow.png | Bin 0 -> 2435 bytes data/skins/cartoon-ruby/achievement.png | Bin 0 -> 10251 bytes data/skins/cartoon-ruby/background.jpg | Bin 0 -> 175989 bytes data/skins/cartoon-ruby/bottom_bar.png | Bin 0 -> 111330 bytes data/skins/cartoon-ruby/bubble.png | Bin 0 -> 47489 bytes data/skins/cartoon-ruby/button.png | Bin 0 -> 6741 bytes data/skins/cartoon-ruby/button_focused.png | Bin 0 -> 6717 bytes data/skins/cartoon-ruby/checkbox.png | Bin 0 -> 1846 bytes data/skins/cartoon-ruby/checkbox_checked.png | Bin 0 -> 2700 bytes .../cartoon-ruby/checkbox_checked_focus.png | Bin 0 -> 2697 bytes data/skins/cartoon-ruby/checkbox_focus.png | Bin 0 -> 1897 bytes data/skins/cartoon-ruby/down_arrow.png | Bin 0 -> 3330 bytes data/skins/cartoon-ruby/friend.png | Bin 0 -> 8344 bytes data/skins/cartoon-ruby/gauge_fill.png | Bin 0 -> 1882 bytes data/skins/cartoon-ruby/generic.png | Bin 0 -> 4836 bytes .../glass_iconhighlight_focus.png | Bin 0 -> 32457 bytes data/skins/cartoon-ruby/left_arrow.png | Bin 0 -> 5206 bytes data/skins/cartoon-ruby/left_arrow_focus.png | Bin 0 -> 5199 bytes data/skins/cartoon-ruby/licenses.txt | 30 ++ data/skins/cartoon-ruby/readme.txt | 10 + data/skins/cartoon-ruby/right_arrow.png | Bin 0 -> 4930 bytes data/skins/cartoon-ruby/right_arrow_focus.png | Bin 0 -> 4905 bytes data/skins/cartoon-ruby/scrollbar_button.png | Bin 0 -> 675 bytes data/skins/cartoon-ruby/scrollbar_thumb.png | Bin 0 -> 218 bytes data/skins/cartoon-ruby/select.png | Bin 0 -> 172 bytes data/skins/cartoon-ruby/spinner.png | Bin 0 -> 4382 bytes data/skins/cartoon-ruby/spinner_down.png | Bin 0 -> 4382 bytes data/skins/cartoon-ruby/spinner_fill.png | Bin 0 -> 2030 bytes data/skins/cartoon-ruby/spinner_focus.png | Bin 0 -> 4322 bytes data/skins/cartoon-ruby/stkskin.xml | 312 +++++++++++++++ data/skins/cartoon-ruby/tab.png | Bin 0 -> 4886 bytes data/skins/cartoon-ruby/tab_focus.png | Bin 0 -> 4624 bytes data/skins/cartoon-ruby/tab_vert.png | Bin 0 -> 5310 bytes data/skins/cartoon-ruby/tab_vert_focus.png | Bin 0 -> 5333 bytes data/skins/cartoon-ruby/table_header_down.png | Bin 0 -> 829 bytes data/skins/cartoon-ruby/up_arrow.png | Bin 0 -> 3294 bytes 186 files changed, 2006 insertions(+) create mode 100644 data/skins/cartoon-coal/achievement.png create mode 100644 data/skins/cartoon-coal/background.jpg create mode 100644 data/skins/cartoon-coal/bottom_bar.png create mode 100644 data/skins/cartoon-coal/bubble.png create mode 100644 data/skins/cartoon-coal/button.png create mode 100644 data/skins/cartoon-coal/button_focused.png create mode 100644 data/skins/cartoon-coal/checkbox.png create mode 100644 data/skins/cartoon-coal/checkbox_checked.png create mode 100644 data/skins/cartoon-coal/checkbox_checked_focus.png create mode 100644 data/skins/cartoon-coal/checkbox_focus.png create mode 100644 data/skins/cartoon-coal/dialog.png create mode 100644 data/skins/cartoon-coal/down_arrow.png create mode 100644 data/skins/cartoon-coal/error.png create mode 100644 data/skins/cartoon-coal/error_red_with_orange_bg.png create mode 100644 data/skins/cartoon-coal/error_white_with_red_bg.png create mode 100644 data/skins/cartoon-coal/friend.png create mode 100644 data/skins/cartoon-coal/gauge_fill.png create mode 100644 data/skins/cartoon-coal/generic.png create mode 100644 data/skins/cartoon-coal/glass_iconhighlight_focus.png create mode 100644 data/skins/cartoon-coal/glass_rsection.png create mode 100644 data/skins/cartoon-coal/left_arrow.png create mode 100644 data/skins/cartoon-coal/left_arrow_focus.png create mode 100644 data/skins/cartoon-coal/licenses.txt create mode 100644 data/skins/cartoon-coal/right_arrow.png create mode 100644 data/skins/cartoon-coal/right_arrow_focus.png create mode 100644 data/skins/cartoon-coal/rsection.png create mode 100644 data/skins/cartoon-coal/scrollbar_bg.png create mode 100644 data/skins/cartoon-coal/scrollbar_button.png create mode 100644 data/skins/cartoon-coal/scrollbar_thumb.png create mode 100644 data/skins/cartoon-coal/section.png create mode 100644 data/skins/cartoon-coal/select.png create mode 100644 data/skins/cartoon-coal/spinner.png create mode 100644 data/skins/cartoon-coal/spinner_down.png create mode 100644 data/skins/cartoon-coal/spinner_fill.png create mode 100644 data/skins/cartoon-coal/spinner_focus.png create mode 100644 data/skins/cartoon-coal/stkskin.xml create mode 100644 data/skins/cartoon-coal/tab.png create mode 100644 data/skins/cartoon-coal/tab_focus.png create mode 100644 data/skins/cartoon-coal/tab_vert.png create mode 100644 data/skins/cartoon-coal/tab_vert_focus.png create mode 100644 data/skins/cartoon-coal/table_header_down.png create mode 100644 data/skins/cartoon-coal/textbubble.png create mode 100644 data/skins/cartoon-coal/textbubble2.png create mode 100644 data/skins/cartoon-coal/tooltip.png create mode 100644 data/skins/cartoon-coal/up_arrow.png create mode 100644 data/skins/cartoon-desert/achievement.png create mode 100644 data/skins/cartoon-desert/background.jpg create mode 100644 data/skins/cartoon-desert/bottom_bar.png create mode 100644 data/skins/cartoon-desert/bubble.png create mode 100644 data/skins/cartoon-desert/button.png create mode 100644 data/skins/cartoon-desert/button_focused.png create mode 100644 data/skins/cartoon-desert/checkbox.png create mode 100644 data/skins/cartoon-desert/checkbox_checked.png create mode 100644 data/skins/cartoon-desert/checkbox_checked_focus.png create mode 100644 data/skins/cartoon-desert/checkbox_focus.png create mode 100644 data/skins/cartoon-desert/down_arrow.png create mode 100644 data/skins/cartoon-desert/friend.png create mode 100644 data/skins/cartoon-desert/gauge_fill.png create mode 100644 data/skins/cartoon-desert/generic.png create mode 100644 data/skins/cartoon-desert/glass_iconhighlight_focus.png create mode 100644 data/skins/cartoon-desert/left_arrow.png create mode 100644 data/skins/cartoon-desert/left_arrow_focus.png create mode 100644 data/skins/cartoon-desert/licenses.txt create mode 100644 data/skins/cartoon-desert/readme.txt create mode 100644 data/skins/cartoon-desert/right_arrow.png create mode 100644 data/skins/cartoon-desert/right_arrow_focus.png create mode 100644 data/skins/cartoon-desert/scrollbar_button.png create mode 100644 data/skins/cartoon-desert/scrollbar_thumb.png create mode 100644 data/skins/cartoon-desert/select.png create mode 100644 data/skins/cartoon-desert/spinner.png create mode 100644 data/skins/cartoon-desert/spinner_down.png create mode 100644 data/skins/cartoon-desert/spinner_fill.png create mode 100644 data/skins/cartoon-desert/spinner_focus.png create mode 100644 data/skins/cartoon-desert/stkskin.xml create mode 100644 data/skins/cartoon-desert/tab.png create mode 100644 data/skins/cartoon-desert/tab_focus.png create mode 100644 data/skins/cartoon-desert/tab_vert.png create mode 100644 data/skins/cartoon-desert/tab_vert_focus.png create mode 100644 data/skins/cartoon-desert/table_header_down.png create mode 100644 data/skins/cartoon-desert/up_arrow.png create mode 100644 data/skins/cartoon-forest/achievement.png create mode 100644 data/skins/cartoon-forest/background.jpg create mode 100644 data/skins/cartoon-forest/bottom_bar.png create mode 100644 data/skins/cartoon-forest/bubble.png create mode 100644 data/skins/cartoon-forest/button.png create mode 100644 data/skins/cartoon-forest/button_focused.png create mode 100644 data/skins/cartoon-forest/checkbox.png create mode 100644 data/skins/cartoon-forest/checkbox_checked.png create mode 100644 data/skins/cartoon-forest/checkbox_checked_focus.png create mode 100644 data/skins/cartoon-forest/checkbox_focus.png create mode 100644 data/skins/cartoon-forest/down_arrow.png create mode 100644 data/skins/cartoon-forest/friend.png create mode 100644 data/skins/cartoon-forest/gauge_fill.png create mode 100644 data/skins/cartoon-forest/generic.png create mode 100644 data/skins/cartoon-forest/glass_iconhighlight_focus.png create mode 100644 data/skins/cartoon-forest/left_arrow.png create mode 100644 data/skins/cartoon-forest/left_arrow_focus.png create mode 100644 data/skins/cartoon-forest/licenses.txt create mode 100644 data/skins/cartoon-forest/readme.txt create mode 100644 data/skins/cartoon-forest/right_arrow.png create mode 100644 data/skins/cartoon-forest/right_arrow_focus.png create mode 100644 data/skins/cartoon-forest/scrollbar_button.png create mode 100644 data/skins/cartoon-forest/scrollbar_thumb.png create mode 100644 data/skins/cartoon-forest/select.png create mode 100644 data/skins/cartoon-forest/spinner.png create mode 100644 data/skins/cartoon-forest/spinner_down.png create mode 100644 data/skins/cartoon-forest/spinner_fill.png create mode 100644 data/skins/cartoon-forest/spinner_focus.png create mode 100644 data/skins/cartoon-forest/stkskin.xml create mode 100644 data/skins/cartoon-forest/tab.png create mode 100644 data/skins/cartoon-forest/tab_focus.png create mode 100644 data/skins/cartoon-forest/tab_vert.png create mode 100644 data/skins/cartoon-forest/tab_vert_focus.png create mode 100644 data/skins/cartoon-forest/table_header_down.png create mode 100644 data/skins/cartoon-forest/up_arrow.png create mode 100644 data/skins/cartoon-ocean/achievement.png create mode 100644 data/skins/cartoon-ocean/background.jpg create mode 100644 data/skins/cartoon-ocean/bottom_bar.png create mode 100644 data/skins/cartoon-ocean/bubble.png create mode 100644 data/skins/cartoon-ocean/button.png create mode 100644 data/skins/cartoon-ocean/button_focused.png create mode 100644 data/skins/cartoon-ocean/checkbox.png create mode 100644 data/skins/cartoon-ocean/checkbox_checked.png create mode 100644 data/skins/cartoon-ocean/checkbox_checked_focus.png create mode 100644 data/skins/cartoon-ocean/checkbox_focus.png create mode 100644 data/skins/cartoon-ocean/down_arrow.png create mode 100644 data/skins/cartoon-ocean/friend.png create mode 100644 data/skins/cartoon-ocean/gauge_fill.png create mode 100644 data/skins/cartoon-ocean/generic.png create mode 100644 data/skins/cartoon-ocean/glass_iconhighlight_focus.png create mode 100644 data/skins/cartoon-ocean/left_arrow.png create mode 100644 data/skins/cartoon-ocean/left_arrow_focus.png create mode 100644 data/skins/cartoon-ocean/licenses.txt create mode 100644 data/skins/cartoon-ocean/readme.txt create mode 100644 data/skins/cartoon-ocean/right_arrow.png create mode 100644 data/skins/cartoon-ocean/right_arrow_focus.png create mode 100644 data/skins/cartoon-ocean/scrollbar_button.png create mode 100644 data/skins/cartoon-ocean/scrollbar_thumb.png create mode 100644 data/skins/cartoon-ocean/select.png create mode 100644 data/skins/cartoon-ocean/spinner.png create mode 100644 data/skins/cartoon-ocean/spinner_down.png create mode 100644 data/skins/cartoon-ocean/spinner_fill.png create mode 100644 data/skins/cartoon-ocean/spinner_focus.png create mode 100644 data/skins/cartoon-ocean/spinner_rainbow_focus.png create mode 100644 data/skins/cartoon-ocean/stkskin.xml create mode 100644 data/skins/cartoon-ocean/tab.png create mode 100644 data/skins/cartoon-ocean/tab_focus.png create mode 100644 data/skins/cartoon-ocean/tab_vert.png create mode 100644 data/skins/cartoon-ocean/tab_vert_focus.png create mode 100644 data/skins/cartoon-ocean/table_header_down.png create mode 100644 data/skins/cartoon-ocean/up_arrow.png create mode 100644 data/skins/cartoon-ruby/achievement.png create mode 100644 data/skins/cartoon-ruby/background.jpg create mode 100644 data/skins/cartoon-ruby/bottom_bar.png create mode 100644 data/skins/cartoon-ruby/bubble.png create mode 100644 data/skins/cartoon-ruby/button.png create mode 100644 data/skins/cartoon-ruby/button_focused.png create mode 100644 data/skins/cartoon-ruby/checkbox.png create mode 100644 data/skins/cartoon-ruby/checkbox_checked.png create mode 100644 data/skins/cartoon-ruby/checkbox_checked_focus.png create mode 100644 data/skins/cartoon-ruby/checkbox_focus.png create mode 100644 data/skins/cartoon-ruby/down_arrow.png create mode 100644 data/skins/cartoon-ruby/friend.png create mode 100644 data/skins/cartoon-ruby/gauge_fill.png create mode 100644 data/skins/cartoon-ruby/generic.png create mode 100644 data/skins/cartoon-ruby/glass_iconhighlight_focus.png create mode 100644 data/skins/cartoon-ruby/left_arrow.png create mode 100644 data/skins/cartoon-ruby/left_arrow_focus.png create mode 100644 data/skins/cartoon-ruby/licenses.txt create mode 100644 data/skins/cartoon-ruby/readme.txt create mode 100644 data/skins/cartoon-ruby/right_arrow.png create mode 100644 data/skins/cartoon-ruby/right_arrow_focus.png create mode 100644 data/skins/cartoon-ruby/scrollbar_button.png create mode 100644 data/skins/cartoon-ruby/scrollbar_thumb.png create mode 100644 data/skins/cartoon-ruby/select.png create mode 100644 data/skins/cartoon-ruby/spinner.png create mode 100644 data/skins/cartoon-ruby/spinner_down.png create mode 100644 data/skins/cartoon-ruby/spinner_fill.png create mode 100644 data/skins/cartoon-ruby/spinner_focus.png create mode 100644 data/skins/cartoon-ruby/stkskin.xml create mode 100644 data/skins/cartoon-ruby/tab.png create mode 100644 data/skins/cartoon-ruby/tab_focus.png create mode 100644 data/skins/cartoon-ruby/tab_vert.png create mode 100644 data/skins/cartoon-ruby/tab_vert_focus.png create mode 100644 data/skins/cartoon-ruby/table_header_down.png create mode 100644 data/skins/cartoon-ruby/up_arrow.png diff --git a/data/skins/cartoon-coal/achievement.png b/data/skins/cartoon-coal/achievement.png new file mode 100644 index 0000000000000000000000000000000000000000..3d3ee76adc9247bafb1f98265e7fe387ba4303a0 GIT binary patch literal 6842 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

!dt(B5t3kCN6lyJ3I1dmOedtD2BU6_-Cq;JxY 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 I6U@*5*~`InJpcdz literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/bottom_bar.png b/data/skins/cartoon-coal/bottom_bar.png new file mode 100644 index 0000000000000000000000000000000000000000..27398c55ab86fbac037129993fe31075b8ce0e83 GIT binary patch literal 23037 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 Hu0mjfyu|j; literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/bubble.png b/data/skins/cartoon-coal/bubble.png new file mode 100644 index 0000000000000000000000000000000000000000..0ce1b0a2da5a540866a65593e482bcd86b0cd60b GIT binary patch literal 49620 zcmWifbySmIAHYXShln&o5r!hA2uO{P5_BK}Dlz#X0!m89HX3P_66q3@Qb9rnBcz73 zfaIvrv5neb@$#PYJm0Ni&696$a5s~>a)p)dqQqkZqEfu1}v^%WrkeRN;;s)l{L??+a^f+v(Q(0Rv<%gzrO{P{{@ckjc6Ufel+bLsezSX0vK01H&UU`Yw1ZoVLUqeXWmo$|pE z4bR5Os^{pCrOrnLvwf1VGEZ%~kD4-@fWrTmj%@w`1jET=+chm*lwUhzkKTAQq5WgD z(SaN@N@Q7FGSo!L$OrqHQ8H=tKL9e1oge8!g^{uz=oR0=-LlJtYybwxgIpWrSn_3QP($mwAy%N zR^h)Jcp*Y-676E}(7PH!3qSf_qL63TVjnBhz)Z)HfA>Y)YDJmZ0nuVe&Sv z*0b&5jIAQq*lH`Y!6W>g%Qjp30!9`{wqBM?eXmKcb+d0AvSipq@jzoH1sAh443He{ z?CM);y0*#}Plw;11dlxkZOfotbyH$l1=})rh;^=OpEL{7C#@9e261}30^}9#Huqch z+f2QhmSRnLi31iX1H3^tJ2IMk!s&WgIQt&+n3qnrmyS|R)H<{4)YpxXJ8UGvk$E{*Cytx?$}zbnD5&8G31Gv2%F@UZt+b?h+0lts3%8j#8~vJUO&0#HY^|`t+LIAth;Mi z-xrkqq$Nu93a-wyP(e5{&Eo_os+`<;yA*7M%8&RQ$|gy;Nv*@Zx|t8!Ep^s8c(^no zXs2_2APk-AWk%t38Ahx%AUNNWt@&ExmI#nP|63*5_Hh8QuFPh7QH&QGt7_{Xv~GLM z&df22HA)qSnV{ZRfp;s98`=VOOhfJGkGyNh!z(RYU_qk~)@deOo?qkwi0&WLib_Gn z`n1J#I3f0z@&ixxY4{@me&tjU7fqnBT<4mdg?Z zCs~s4u^!3ohD^}N`>Ah8uY6K~hyDiNE4-@dM#@`XAo?5Dwdmc5OIHTxJFGnZc*d0K z`is(c4i_H|cdf%Z#);s_{kW$6vHV^~rK3;kIP?-?(3`l<$#=XYj@(_n^bW%v> zuWLKKDv9*Z6r$RWC!huOo`BeIhdzz(B%`$b5UGo>j!+iN!=V0(Q^t;!&cG#n5Kd+# z-=1#B^j>mz(UpJUZ6{=tI2SVFsFuoq%XiaR6%$scFt_TSN|V2|C!c;C_50ir89CCf zcY+OwTG94jlmR!&hUS|4=~KS^i<&p?sX2w?FUIA*pz+i~PgtS7 zyS_hDxWa5ub2H6Sshju#DM#j+oDkPUh?HHmr8I21f*ctHe`-99*F6y$;Lz=+NP^kS z_-liHD;1#b9hP0?KZO&u)JdTXnEbyIuY-Jx5<*4l8$X=9oY_fyEZ$mEI@ngLgX?>5 z>)DL8LZsp1Az__A6iAbeZ3YecqI-bwO1S;r6~!qDZ`H@4Zp(UEj~?4N=E&80|}?Usmhg>^5aZQOiWwg?3`}nnfY@ z!5qQ3kv~|I+e$r~8YALG9^%}Zw=`291TCd#?0uW- z3S@1E)YA#_1B-k^g}RNN&#kp|V@iqI`KRK07Gip*7lVzNy`HL#Gv zVsO}q7v_q&i-zzJoQ-691zyNUIaG#Rhj&{|&M_>;F}FBC1WNs5j?Gdepb>yG%ehsl z;b%_f-#BKLE~`6RJppsrKF?bo9{70hej#HTtUu??0dTq~3_~+H3IR4a6xJg<%IB4s z4{i0mg`R9u5~YR_Z=uYYbPk39iO`+1b||)0dfdhiWzS+3g>;Y zGn*p@_F-cBniEe)QVGDpQrf~1Y|gt`AT&d7vd$#14_dPWoE@fUJ%2Or(E{ST>Q&@XOY~E2e z3E3@szqYXj_47Iy-?r%`DGZR@0VMvaaq&f1oLDzBdW!AqD#C?N>YBJ$v;l*4SPdSw zKxT(k7;6XVBDIl69)VxeptffQchS&Vqa)Hse zrlghsyE)P>hPrE-kD!tYKALuR^REsv+rS#m9B|3Al)x*)fme9;djnhc2Q-6yxtIEc z3Wzp~N7k6YQU1Ql#Um9jBjKk>iwfARmrY^cf1I+%)G#q@m(*M~4g0_qk}J1^W-~yg zeE$%9dtWOywU5x`4lb9A@KI!XLL~U5Ya3#vBS8Eu9iqq_6^z>jeX>}Q%8?d(Cx(s z9ss)|#7Q8c5wmxDTJ`qm!WJrvcmZcc)_6YX8x}T9VC$Rmp>fFB!n`jn$rubDgms-u z3u=S89lYwF3%bwgAwJ9(ahbEKlF5j81GjzS<4*2X)rOMJ=f(Asg5@Tk*k&RnPn`>U z0jU7FEwv_IpQQVnb?ilR29k@w?P!No**iqA0l8#^^5a9Q0PMx~8NE2W-5xM{PpgBk zl$6rZztWppKX=L$EVFu{l7Xh<2L$dZV zTkJ+c>T@2=@J`?q( z11%2D2nbUfgvjfPDF$H3^7wC|dV>4+hlS4R)?>nNu_&6xht0{Eq0f}2zy_r}_=?fCO z=5<71+WF9Vt9*~n*-p(Qk9|J80TZyJsloj8W1ktRyO_>Zx7Q>_0c+EtD$dIBPo<|B z9i-q)7REO=;sdAFTNt#Z!vKL`4__M`ENON;iNvmbi=2lc<@qKf(iR^$pGyH=9)|0< z&`N2Gi1&YuxR6GoON#K?YXyF4Jo5szHk_SYVLZ{T<$ir=1%21%HUKqN7j)Ay3tmwR zjOkFD2xzn@zGOA|_WPWUzD~h1)b+8}Y3T1~F;C4;d1aZym0T)@#26Us<9Q{jWwm{+ zWdnr5i6h(oPN~u0sQr}1X9>8Nny@GUO_$ilI&TUs5Z3G$)iTO~pr-RLA>BB_hmR;Q zs{fSzx_qYVzVp@jy&UN*#XVQ zZ4(g2Q1bc5LqP!P@QT0W^W5NJgCf76IWhPL<<#hhdJETnYcW%7iI`H<9&?*fn@j3> z(o7gUTxief1pLh`U`1y36BG~fIXDJMV&i?HM9;YGp!0ZXo@eoqbaxQ=x#V6qMbmdxAoque1QnKxrajmq zNmEM%+ksua%Y$#O1?h`~lQIiT{9{mwCao7}QD!sqBb1A&ws3wN-58atgTxiNDwWNL zv4QDorvlId4xz+3I3t5Pw9AvZ&`C9BA(gjcf+!I{pOi6tHvX1v7`7!0e-0BqAZZsI(yoKt!wk$-i^=ItAWa2h8O7TfdGogQ&;AXN_R%}~dMb0vXa)L#ZUdQDnj3M0rGBG_K%ky)@*hg!^ zvk$@pD{tB3*`2Rl2lHDPwi&p749*dx+sM1;x9bULdkjcziR@!0?Mac@)i6T%_l3}F zrz%Iy;bCI=7hDGd-DYnK{sw9sEg7##9r!l(Lm4 ztGDuhgIefM0Up z9`cv1hD>6gsyOPZ+Xpv8Gx=R#SKHAAOXK}NuFuK}HkMHXM<%-u{YjIfZZ19OwsF;e zDpM_ty+4>VM29b5N>kjq)05U4GZ+}UU)fdAegfAaZYn`J5dcY|l{KxFkE()2I_@(q zm@~HzXj{XEH>Ml`3laNHTKpJpKP2!nf^}_Jk3#dKrTKx;OLelSL124hFB}3Dh8k9V{8FW@C51IIC`E;h$fpnTvVJmd?T}9&sb`pkgP_{?W8n2NgQ#G;ca0qLh9v;#QA@xj zzOE;mk@e9<6HQ0>sI}S~$!EtKwM&@TeSt)n^FO10Xn9KQ2=xq4;T@|B#K0OMmlt>p z7mHN^W#m*%LSF_4F1hJMaRc}Q2mVS}IXTcC3MA6#F*&ns*bBk7%+Hp6v015aY~7&= zU<=`d&rQApkJB-j$Fe#DHHBMJkZ7(?!T8S!Pd0u3kQn_R1bvZZn<@@9{Aq-GkIce_ zUU=R6>M{9KoG?MEM8b6?+JRIkvUgxpC_0;=^jQvuRE@ZGs;PECPDabo_0B^Wvap+F zk?ix{i|0n*0z0vLIS!A~r9g||`^;^LG!ClBa#>O0%z0(1AmX@$n~OTEN8@QLi2bV2 zL6%HAST{?d*?3kH^aBTgCZa)R`^*uy8icaqm*0bj%Q(}(dWNCa(aF~oisn9~un9Ry z7;}qt+_y77z8Ab?ZxNy^77DlWQut_3eUNUUXv8PH`_#hkRA5H!ILV+qwGcxo|0Ri% z@Nls4n)URqdG>8F0CVeA3I~LPF8I`vz8J+e+&e3Jy2J}+T3e5l=S|YQHv; z+YMd=$WoYn8g;*A$1dj9Twmeo{e7diq2dQW7i!2OH2TvlD-Keb5?z`cN_#`kaG_bp zAiS?`_G6U{&_B4S-g=X%p8~3tObz#Xj9V>I`1ylmB0u~+Ekr2IM2N6ylXo0kMJrTH za@NtHB=jZ_bh&}MpJcc0jlND{bd%hVP7Se1>Ojgx)>ohZ?7HtrFWS4(Wt3%c&Vtm| zUaNQfP z7!ROAI|%Cq!LXQ~1DJrgYjA!lhAE18&-+Gl7)(>95h8dP|BYo#QZYm2#vLqa;0~v` zO$gn5hC_&JgHY1_XXvwAYzy1vttAm3S+>JjhdsX~%L$sV-CJttn67i7*sRNC-dbN# zzn(_j^9xdBb81a8H`UNL{SX!^1L$s8fE zSfFoxGR*ly;ktzw*WL$+{r5jlJ9x z!tP{$fpzPd#jUsqxLJ>nGKZ5mX|0!Ky~e=f*_qC9CulMc7F@!_xrbZ}N++hig{GhD=dE-7Y^TNVcRSd? znTh%=nX)MK{=q-6^q@lPDMbD>EAS%#I4koc`|zUhMts^TV~DAXA8)!UFH0~#bJyo& zdi^F@2~Dl4cN<+`>%YSr47F_eHX%!Sxl2W7_DBbT;E*6|&!Q=C*XfXF&%O7T6>I+F z1qyBxw>jvS@(bW=`XHi7IfD8KtqtMOWl#9N$FHwAX(>VD8mC_@_!FGGuQr5JYfHN; zJuevnRzBnKz=4G*AK_8&Ai6r=ZLQQ-f~X&=9# zFag^c@z(ewx$uYpD}t>rtn<3l8xBD_1bd9vRhHGw_|Lo$b+|zEqqXIjeY=PUn{M3w ztySOuJUV??f{eynPE{fQ8stdcOV@Do()XH`ehigCRR8y91i}6Mw+|P;+Jaouq)hwm zNxrt_j(yUi?VQkGQ9fWsXqA@~%suMg=UVGph{)-`4+_fY%I~|r4?ihzlJ@^-N9~tm z^Y1+bx=_RJ2}*|3JX{6l&xObl&@)RdJGVK>gcb7hE<^{ZHIN2@N(VlM!=hF<`F2Z1 z;-LA4_RP*1k%48BG-5|Qm3dkv0jl}@rdRPH?zfT7qrLA=y<}Q2Yl*w^85TMD3h7w9 zIMKjlMjT?W?>AJdk$bWcR)5#k@5=Tp!<}s z?7I0v?m`CSox_Tly3<7`9yFI;En%sa%%=`l$hvh}KAKp7j|aboWbhW?MF(=~LtWRe z=0es$yRoWHPqdxogz1dEN~#NDsGfwAJiy)nj&ggCw-aK26Ll?@qi;I`bJmJE-~`ho zt7vii51B`Shh)(`@mvA81)O=8y_6=nj(tAE>BVY%RALSP5MT`pyAV`eRAQH1*EvvW ziGQ0IPw3h%jWhhjw>RZXh+tiL`R>9e&Am(HKbcuE!ATc@rDDS01Zh5bOQlx--Y5!c zn~a$ExdN3h#(Gpb&R&~WnU!B@xDInYn!dc*-)Q6FAoeXaMIS9K=ReAYtS{P9@pM=* z)boO|B>&L-hjW6+H?qfeoP8sF+aG8HKVTxPKC)5#LPqO@LVzZHPTf0w@gX&6uv zbs9k@{+EqWL*6Lc{h+{x3Hxp-V>r14az*_VT>9=FbR*dn9Ur-6yp8r!cbok3bMWj^ za-dvaR>Lc`Kc+$5EE^&qQOWRw3_sfVUk%qvn)3|J;<@%&$cJALXfQUz#S4k=$wCpk z6+RDWB zk5ApF)m@8EuyD-8<>FPXbbi#b&QcQhk1fj@dM9mA>sXzKs+JOQsnYwFq+&N8^b#1U z(DHLVNmQMsb*AKs;MR>pLWdw%pT>IXfAx!Pib?(#oNGpOgkC7cTK0Ur5cO`jT6cgP z1Zi)&mgj?y*Ilc_R{mJF3B?`M_bTd(p@QVPPGxQ{DLqJn6~C=7LjPk7^1TKS8Yf(@ zT`OK2X&&g7z*4z(aSpQktcx_sdQ{voe-u^97(d&R*oJB-!VOQmq=}q9wx&Z=l980wy&=y2Vzytf@RSVA+Z~Xi`kO2_HD*V z^gD0T$RRfHR&on$;1!lpU%@%QiuiYXE1e&xI=$SLHcziuVEYudNh<%i7BRd&aM|*N zF>@Qd#NxFw_3GbbJv+3mzAmO~%8ux*Maz`0Tu8E(_1zjDy}a_Jv8><4Uj4n5DC%Gq za_LJCSQeEczb?iS);rxMRiLk{-7Bg5?tXGk9RAT}?*6k~G0B6@A4m~JPM5YF=9`uH zY6DZ~G^=sr!<8l<&|(ZGHQOb%ffTQf`~EX_Q`x@_fZ24(4_@2p1yk`h(9}Ggmpec2 zS;A46K+d#vNC>4?4m_+AmiwZS(#RV);g3C`bpoRl(8KKy(lLO|a9i@w6NF-w$+p z=UNt4$;f?d*tDU>e&6Z5xEp599CWXIv?l59uCSX^{vZ2lYAjYRzu4w(d&HN4u2rc$ zg!$Gc^*e`MnS#S5JyWsRBUumk?W%dJ-m5b5PTR=MG*utML~eH$*I-_F)-=kQ(ichd zTAWSCb03ntiVzH+AnXo7T2xwlPl|(t9r`OmilNXT49IZE%e)j7jp>&_R$m`Lbj_!V zfTYrxOP#S(LN9d!t>D3ak*7&#F2&@(yr6j#=^c1&`qacghL+Dp&EAb)Wa_|m8*k_X zZPO>8WHam0wYAG7 zKhNj4{_ju_%3gT0q{vDbp8Q<~OelIi%34~|1TR4X4Zdh-<3CsksP!2sKcoiramSGx zrPxtm6J4HI_p?AmSJGIG)T#;`yjFONBy_fkVS+n37p$dAf1 zE6pPwFD{`*d(KnKn!Wc1D-w3Ol zjPe>gPrX4=epEm;%T#yoUbz9Oo3cyi*YI}tp&lpB^@H5mnLGYv_|#4Pr$xMt zDg7xr+S}3&9-M*N2gM~^R>`vjP(g4&a8(wKk3dP@%L-$%6Q6n zQo$w=M0OjaG_JuR?Lcl)(8vj6o55`UvYPkSPx9B1*DnD*rr>Cb{93OOOndu;FkJiH zVGy7uC>;J1&HZLlRs0phVgJ33x?3i41si_ST#9MP_)*ygF(&lGaO6G1mKxlhcuW z6>4(-iu8UiGNy~DJ0Ar<=TKL0;{TNZ0p1_dlazB=y<9^sOE0T>%}F=3tLLEjDoo2O zBN18~ZKJhRl)S=z&&nnPdiWO;X|>N-3hCj=|HE*;?-t&7pWOlLd*k&T1`x?bnmFzj zZr`=Mpf)sGTkGhV16!LkbKww$v9|ocfk3&LM`2pNfe=4Yk~mpu)A^JoNt&7+5&NcH zRBF=%NeS1^mKYNN83{_aN*le1k}V(Ff3^xnhx=E}aVxh)>vGV^`w;(Qxsj(*ElB71i}cJ7^M+Zg_XE!++Y#@e zk`#uo9d>y=R9+iP2&AWm5xufsqulWGE(Ne-;yH&=$=kGeLYKznz(Qmw;0{}4c-V8t z>}%s0*Z@T7E6zgfN5F5ld7V&fa-mP}GDD=9LT09xZL7(gutnp2w&x#jo&H|D-(M}e zZXD)Sw5{T>j?LA4dKCELy33dhiu5dd((Oris>OTx+j@x0*kL}#fpVmJE0(Z5% zV3%p=qrmMbw@cY?wo~-_*;)x1w}HES&D$eZcU$g$a>v|&>X5GOra${ZmQgR8J$>etE|b?gO0S{H)I?S_l_U8*lYpMQ2992la0?s119cg})43)*MS z3PKn3dnw%2+IyjIb@62q7kxtVWxZ=|sKEza)T*bs*!u za!7g^;rE!go{7$WckeotR7ijc^~gJJv58TMgsv7RG3$NKL%!ICCdrYw&sV2XuKKy! z$jBBRd;*GhX{A)Y8Een8Q!|DNmlPs(z`?0VhIIB z2z>I7hQ|H(QosVcyXGzctDZn+Ikl<}^kS#)`fa0Mc{#XdHO=A$C5O#xd@nl;6uJ-Z z-#feEj<`oO4h(yY+hH;L<}mPnfl#WwSwBS#Q+@smn}w`Eep9=o;YC>5sr4Cmhla7X zhhXDV`J94v6U&o13Bue8gEG`;Dc)nt|InlJzwbQRiqtSKh-~6JKchw@_HdX+9)^yb zFi4BtHU8UN(9w3eEJ&5_(AST^#}Qt8y1+Ha9Y)nkI|32(4`Qv0X5Rl=`lIkx!}tzs zVqp~vFIK(%q1p0k@=F%;P}aQ zoe$dlM}uK?x`}TDNU%Cx{`XEh#kYVRZ9RDr1QqfQq)Ty@XJS3QGTQ5!b^<`?pTZ8u zxs&pn-tAvF_ROsW=TRdm{>&LCBdTsNu48mTR^i{%~UqOh83a#v6pZdi`xzZT)k= zgg)cN&Z8@>9I<;w}@Y^eb{MX;oh{)P)0xaB*Y9K_&!AZo88D*JrK~> z)$}Rf3Zu3eq@h8FHaX+8HB2mr5_tBsANJ)Wu*>D+>8=k0ocRlaKX88%3s52{9R^yi zSO3o7^B)V8$S>ao3D%9@{H#Ffr4fOZa|{OlYdTA*VV=J>r89`n8Vaa4#}44<@Md1s za4JH1jmKQ{1I#>@jiFB35rk z%=ip#VdHRrY~snzM6z>|^YHfA-OCM?b0g&oKrv+7`n&ofTBZx8+Oli_Z;~&p-+L*f z=SP_oG$#sa_Cgfw`$9xUwngb6B1vj#yvJt<5fHo@|J{r7gJS>E?6!lV7yG9Gc{=mU z{b_j}VG+A6Jm@Kwpml%IldQu7MiOR7kO)>Fp9D}#astPCwkM>3B{}C@YS`$hV|E}E43>L4l$-n)^G**k#-VDDg51m7K0{s@V7^2u^!`nd{|z-AXg zSi-V-&~E{jfz}V*h}ZVXT^#6q8I&^Fz2EFMSa;LD;?fHnzE0lXnGV<(Y2fH92;H{EfSnoIS*9|F04cwJH^1ZEd0r1eXD zSr_X%1cx0CPJsOg0lU2R0vDzdsFfv) zM%Q7w>(@z*81A>NB$pb5KU1!haQ-#;m{shMMMLvjjSaj{HVf87T$=zviG!*oLh>%Q zRkvrKJh9YvjFG%=8`j{Iq-ui}iW#x`s1jHvFtP(3!>yFEo?ZORq?~C#`cFVtv02ua>O8x zE47t+qdlU|%|xk|AJVL1_NUph=*Z*z@G1*jF|Uhw@!wNfbgj4UhkRv{ZGP@}Sr-(3 z{a4!3eM~A{a<6jNXVc*l^{q$GlPV5m!))KsI`5Ic&v+r$YI+N5_>H`g? zjq*F>MjL#jn&w9xW>x7tuDOBc1EO3@JiK;OAKd{h*L5Y_YEY}vV9tB<#<5S+svs{H z_bBsbN?n`c^nK2xTO*vzPC%vxj+M9}=bFgha{rEJaDV4JO$`gldP1%3Kc3O# zG{~`EP#mT`6=k89s7h{JYkAj5Dpi_P!5uY6TGvtk|53L;mgkkLEnS#Fh3awGl2lB= z@l_(1`VwM?V$g{)F2R5}Pb3(K2wj^mZ}4$ItSZOlVG7qN{rz~+CK;s-G)FPH$l*_R)pV zZ(eeO9GgoR&I7WqIZb9HhiAGdn~xeyy1p|1-JOfr6V5Sio#2|i<};+wTIO8t1l+Ae9*g{5RF_sK^(aMQrYhvXD>EBP zO{;Zg>-St1>SPdFx_!ve*xwUJhNfB#`cJrOwjRvOA#!)epQ`$t3DlNNG{wodL)in~ z#oc&wY4emB3JtpsQjZvyc$%ewU1!CZ+5Rm$;k7PbFl?)wxa02$Iw3h)bRDx5kf6SU zcWg$DZBFgTqe2SQg{YPUB9xDIBk#*TvG-G?J4Kf{*5px?>UC6KVH${!ewlCh8pk25 znp}Td_VnFka>Qn`swVE`4_2c-*Sged_fUcV%)=}I&zsH&j{?x6y=91`s7S#}Ff#$k zR2|}#UGl8^(ri#VhQ#T$A{@F79H{3y&E&eY0Ufgy@n zkvg=^oc|MpNvk{$a~c%b);8fKp?3G8j3r^6%=y*+vq6zuSCSlL%>Jzo|ECq5*9G?kznWlCwPs zAJ-Dad`cT5gW-W=Zs5};l{FNf^?3r8>ec(2J!1eYUBoQ8PQCL{w%OZTuY5>`1uj3R zLoA$lwHp3KIT4LH55EXP3l(IR7h^YDsufLMM`rVz>0Wgp;eX7O!&dWT+OT~R3D%l1 z@5|rQXV@3~cyQlg%gSeH_Gf_W^G8|!BPsH$Zhyj6YBLntMl*8{4NaRZ9qN6E?Z@0 zMQ`Y+$A2wLy03CX3hbs;5-xtZD_K>yxA7-*=SjSnX0l~LO z!TH__*ewKm@*xa?@i@j7Y~x}7wpyt0v#Oy-uL8j*+{z%wG~I*`!y}w@!F3@~?n>9| z(lG*$FGC4Rwk2OQE#SHT?vuWNV$0H@F!>%XX3^W{Z9H+0SWCf`EeWj85( ze~!0a4x*!iwTE7e&eah%1Y_9 zwVS1aH&&FyN_SFG02 z9(Xrg`s_$u?1g{z=?i)x2DGxcLs$l8MHhYRHXaA)H5Xr>I-F~|tzhJulW6sV11|e> zr>Y0X^QQ?CK>yh`)#G;SsB;auc-c)-(On|==8VUya|*`W3MV}CwFH-|X5Ta^)>+PFqSEEoQtv0C z`@bRyE)!V~|Cxx}7!6dbJhToS@3G2Pm#%DKOVOFaTF2pwN4fYnk@Lv8Nc=1Pp93nN zUgoT~L=|}v)O$>1LlS$9)nBIA-+ebR<9F~@W$)?x%YqZr{<3vKv`}qEV z_uq}%-mqEnt;)33%*-xN&htZm$#h%r_~W`We*8QInd1yk4#y#=)15l`iyF2#iu%B} zs$f#-1M}S<$;aKt)@LXGu^c9AyiA$@aOK_4P3FK{k!JL+BY~WaF{yUFmo3vI+K3-YQYp z+_aYuQ7=fvBYDwY#=a_OPRJUHJ4mS1$Otnd=kEpBft#UF%gkT4R56AD(Aqwl9>XJ9d?%zG!gC9+AVD3j}hgk#)^2pP5Z{>wBRp@j(_cc za}ru{zWGYYxE*8EePVQ{mMt!?;Ev#5cuK~$@4puwxVQQEH;E0(1}1pCAtaR5OM&)XIs7J4 z?iN%Wr^0@uIx|K)Ek3EQ&=jil`6D{;$*K2=QL}LRqrM%+!YQ9pd5+t0RfVLo|I)Gq z={lzeh2p&CSpEJ@qV==yvOS6O5$iT1>O$(~i~az#Tt}-1*s^pZCAC*Tqqo@$Li(rRI<bNYMR}nX6^97N zUOz!hQX|*BrCd9q8-C5{u{;}f?*n|Id5a^gJI!;bfH7frMR^Y-_g*s zjUV8`v?+-xS(KNv1dVYf%gv6~1R4PxenS}BDgzj9_2G^pm@HgDgC=yrH}&T&;6j2t zlx9M2oOKpViBa9PjGTR5ryZ~ek3F@7#F*4-W^YWU#4m3*1~C@9N)g$zv^DXjCTxFs zf8GCCx+AC7VIMgE(^%kSJ`l?8(bIZzIQI*g#nQ1H{Vb3`}3ZDmUlyZVWocb1=&E1O)=z8&AKvX5||GIiBKXnnxB*TrOPW^15yh z1!W6>`}Iij%f+4PIug9hM{IL1;B~L8USqY!DD}8<_vh{%X{p;|eA20Jgh(GIf_qO; z5R$^-IYxb=Ofd{M+68yhZtY#^9F}BP*vID3rLj(P)=*QmPd6->2YTV~ahi>H4HdpZ zu2v=tyS?2fpY0y_cvpcK^q+CQT@tQprZfI{_^6%u+p69GTdpN^)0i;1qC=@66D@+e z2Ak(qA3XEG-}J>c6u_naEEZvIy=^aoWwWt*_2i+;WH=Q?wTqeyTT~vAKo6dUzt%HQpJXw_KW33*+dTbCY58Kr`9(j*bI#PUs z(@}!lD-sDBs`Ny{3;%NW;G0HR8+-{;PBc5y2-qgbHD1(@No`f1b^CjR&LXHS+Z}k;8rN~E#&_b@2Q0gyO&7#A zBj5uW?L!_wqU12TKlE2J6j+I2!sO~(`k?I zZm6V&RVq|7MfuB8JQFDAE#O5l$IJm?a`j2gMHTZMVJ;)95)~yK#(X8bBU3zolEU9! zsc3TS@r4+Md#Brf()`P7pduDRIT*b~Z{fKy%`_rCyfSaRVRJXx+9)og1Tdob7@RvR zE=~t|(YH1duzn{5VBZ`dusBFV{T`MNpHJ+>m6tZN6S;1^(PL=O^-7QLd~s2w$Qse0 zP5rgsrMzeP_;f(|vo#G>Jc@{cf{DB(yvA{O*=mOTc*5C*wsWd%gi8-f5#wPf-EBA; zE?dyq?*V|B+nX3XbK&Q3vV+G4x;Cx-xz}U(xtPmiL2`UQ9^$)y@k6_zGYhqrWXcV) z=Mxv6%m5DIDF4{P0LB)f$XoPxG9TOxyhE?fgN<591|XmIr;2GzCWo`lZ{c&HhR=6l z0P2{$1m2JxTu)THqP08LxMv7u)D%eu>}8F1L1S0t7e(qP3fRuFTWcM8$W#BhG-xqb zna!y`2gt(~BQDgOTW`0&y{>b$qlHk3y)A?&EwxB1VjoPrWP2SIuE4gSSVP6fTVjW{ zAb!KPh`C?BwB=-!YJaRh&iyfbJL{#O7sM8h&R76_{U1?Z6&BU^{XIiBA`Ma^Azex{ z11KR<2Au)|(%sBZqNGaqARzdq5owsAVQ7%uiA&>seg;6rwPH3jtkT7oCP`p7_ssxs)YUxn zw)b&l%Jc&9zaq{}S06fPaRP7=u;Q#9MN1sQ2+lmrxo8IHrakQ_VlAQ-)vM>2ITcw6 zM5~`*sg|%hS@)qUHli&j9kKHm)$iRzgR6TZ8x|h-m(zD7YwQcfoOeJ~L#&@zIu?90 z;`riN>~zkvsI!aBDnbydBo4rES<=--y>IB>qZam+po0s}? zESqU+!KE&cr_I($f=Y%Mo^Fo%yPl-cs=}Lj{#Il~M{ebKrD}>IOO#7oyX$AGiE2bX zZp4TnUljAQmPrdAm%>|50*>>gg?Dvo1upN^pCx?HEdYc<1YlelmLxy;97kVqB(n|B zI!42?YrRNM{AM4Uq4Xsx1~Ek5*sW`dgw13;@BQ=S6treQV9i0x%D zn;qT8(0_?Zx^|WesCE1K%0Cpr1Eu8F_^D+&P#CKM38A;&rIDKZm z{z@}Stp9rF7WvKE|J)Yfz4=#UYrW(J`Vqc++x$Wz-lz?Md$T#o)>Ech3A{1#`2yXg z+DfY&6t1)*4A1P0GU$<*r*qzn#w`@@s5pLFLev+qW%tw#995>Eze9E_ww_a~y4VZd z#ipBPTgaCa%{onZ0@nIR@I~<&Rvdp)-kA1-y$98t$tI((E8iVzG7rVe22skkhK%(3*ZnyzrQcfM% zqqH5;Y3nh+oQRhy>M|q(;~*4LwLlmA8X(s7Ml`J^)q`lNLO&J7yPgTB)VDoe%YPd?HyWwxBGcaV)r%QoT3o_b_)g3rJ7ogr(g?d0oMaNiaK!u zE%opSDLesbsg!q^mM%#a;FiOpzSY?~z_cGQ*;GBO+Z^E2P*7r{l>pq(4lB5{_fF#JJvF@g2TTxjk=+Sxm;FGnl1ROlG?MV^kGBvUiRWYpSqR=ghB4=r zVQ!Mj;Yi(#)TEZKKbO+4TNz*63RZv&G4~ZWMc;^vPMWQyNamR$#vUZoJiy_{;sNJu zSXew%>D+d1@; z5_ah=-+lI)KA&KT`XSX=l3IB0HTPr7@U}@iD~<)9n{yD>OFl#~{#tSw(+Ss=pyBv+ zR{s!VKaSx`nf2IP(hptpT{?)(T>kdC-H@^{hOPV8LfKM}HZd(eSU%MNB1+6wXman= zt5=FePH{BdzCcbDJ9nDj`u*^mo1624At6dJmJOq?;8b=LUAHXZ2ju*o7;fS6cA}*h}kK zBcC#3-*>cq-7mgA>b-t^B3d$R`9SH~4SNU=aZCy>D}UE;UtBS;`|lY=ItYFG=Y`Vw zbq+)jDMn@Y)^Po^ri6Tu}A0Vk6tNcSve$M5Ub-& zHZI|>+InXYO21rxP4((FXJ%UKw%Z8n@GVvB%JIM{KFnrqMn)|mMXGmLysV)_+;@;I zXdB_5m4v&f|68E%+t&@x`SYqWv7u*%ds|;! zZ7rMfpHK;)o)orR>u$0WvlmO)zacLk?@eFPrpp5!nr1!cjH390f3(8-D?1q6`L*Z~ zXb?OpYG0J5gGrg>NH4b7{fow5M!i)pM?c1^&N^H7S(R*a9RLY*TF`;QVk!P|&y2Xj zeDQwz;tyi^^O9t2I0C$4nC?9I^aNde@lb+Thu5WCQr9**o->2y&}PYelWzyC}f>?)fhuU06xvjo=)b zU+wZ%yBGSmv^J^#g<0rkieXz+&uzeQ;>sBampk|=FZtjgha5(-K$m-b`SEZ<`6c>( zkklI-2I=Wz?(r1(ssE87*ZU6v@B5hWZr&N)e!A2RT>qYXwkb|&m}>ka0e-r$-0?K} zW8}x?{sR5^q_fhS`lUU?i8{kjdTgvE`U4#nhT$HJg1Ss7-mFBZJ0H7Yex>~@^~c^V za}XcX+)~Q(Hu2^9uaO-6pbptlO;fo1_cp=JFz{D?Z-!s*vO5L-`J0Q;7%GVneE6or zqYf>ldw%xPEt+G(vfi^nzC83J!aht4k!n+5!7=)mvzg-2lyUWYQXj;Hjzfr^{-9ug zizeSwIhz14L_s!l?UI0crk}T)B!`S<7KGq9(P3Y*SSLsB9(_InuhDUxVu6BglR&a( z9ps`n;&_m-4bbh47~#^_AU;a>?t5Z^%RI(UG=J~`{aTqhGWMiI2vg+4Fuo=F0kO>_ z#Szf@`a91~sy-sR($kWe_qW>5~vh(%7i~KJwd53t5fH0i1D~AZp|m{ zd2DJB_c8Ind>~A0-KM(59s3ga@n24j0Me?@O_Fj_ni;9zA$N?C3u$ z+x5(1R=^_Um3*pICTwu2SnV21+?ICMLKhr%BN++NxasX%BbQ$CU!S9nt|+I-e>UV2 zhbbLNOq%_B4*t-f0X#+0^*(1MWfH`EosT}3#JVE$5O^Y2hnVLjb#6@@CE_LGG|vnY z7N7g!4M%ycEoeA-O~yC4>&!2F%nh>-bo`E=0Jv`sk6*qE`xi0xm10%hcV)lEPIl<_ z2DU?(m?fN!<7iUxPq?_!m90qp`0N^BzJ{IXkal}Ry^qmz@SCzVm&7j^TlT5MWI z3&4hZ>_suiC373=H&#u(ssvt`T&BkY7v8>GLt2)G#F1WvPK_(?CGo%}3%`YIqmN;< zzgp9^0K%dea49+BHLpk>x~Kkiz)_j^^xk03xiRAJO_9@X5D z&KGVVH85U0OI(2#7-4msw2bzUc7Grb^fNrq0j%fX#A9?20eHyVU8h96!J-$2kb<86 zCNC+(v|SoNcYMWkjju{#A@P~9MbXcsg z4CB-Pj?;}d^0DZbv-+JZqN`n%LxN8tWWy<5YGOUX&-2)ZvHbW*GP|h+P7go&RLf>) z4^HXCS-qq0gXn;KL>Q>#ifkkJ@wF2yG$rA^e_?zxaJgSr8+31!*z5}$^GlLDkY<`P z9~5B$tZaVC(>)stH~m`w#!5-~bv|FoMIlmG=2fL6t%3>StClru96|=D1!D_&F#lw$ zIz|m(yP2xyIgB~`K2`5_(ll=Rns>Q>(oqJ1+!IZN4U*_>n$}-3;;{E=XNfavw;@jZ zLnUa!ySm+>S{`n_67h2J3UN^xzTtSU+UWvljh-i0;_ZgMZ=9f(_Adph7d;!|p!Tj5 zO*6<768JSyowx^b!pFEGbcP*iB0*%{KMiBWM^1t?L6h2-MO3DTw ze=9iSiabU(93Iy%Q&d&%`{H|Xiygr}IXjgpW3bBP#KZc`VG;zK3ffc25nVY!_df{j z@aK>s2&q*OF!P^B`+8RP;Ngy!?NDmXvm1#V9o8Bx2A6R!!^;;&tLzHLo0 zI#rYt*9+b_uH`}4&-w&$=>5{$l{6aP$af*_WQ{6PbR9d>fhT=zO44oPuU9yuW#@ZR z3XYwQ;ds|@7GFgba;D3x-JtE#uJ{zID{y5)&?7GL&+Oj<-RA-X5-q^^IR$w0TC2sj zEBK6G75U?A+_rQeQ-MeI*Z#MWHgeoSuRD)xcVpx~=L{5H=x)d*U#=gmcaPx0TASB{ z0xK4m+wV&E@@hsomwD$);8Vl#rEV-|?FRspx2T#kVv?>5*g#tR(u1z$7Lw~ND9Si< z!fZg|^{tpXnW@JbPsoUfCYB|y;TDCEV47tX`>q2<7RE2lnMAM48{ZS2Dh1roa1M+S zf1MWi`Mww%YYK^-63)5vdm9QI$qJl@Q#D@(<B&BB2t6LQmf!jc$?ILfS-%p=!@5 zoq{iZ+iWrcTp#bMtch>qftw(0#k~T?8;qbhXmz_3 zohIqp%nE>?ylQWoIF{^UefpYw4UVlFT|Zk96}W%sBFgC|azin(OOc9Cu5B|`kHK3C zwXk>EDut~kMf>w2y!nux@urcqhkz{0OyIo$`9a{R^b#tz$Ys}6??k#B3VP~Jab-i& zEAA(fofPi1nJw!#oL~FAIH|Fs(U2jTw3E=G5u!qMCjyw&%s^&J@a5TMfHI(G(T}cd z0P+zB{6A*E^Jf<16}_}ZP^2!KK1OZto6f8_0c!lDpa7in-p{QtZhxgQ+@p!EKu#Qw z7GEqE>-g{Tn`@V!;P-P-n>v8?fM?~WWGl-=RSha)$@u>BIoGI}X9ll4tZ@(u2<7)$~9w6X9^vU$> z@=5*~2gQ{WL8O9K*LQ9PYz-+Ez= zlT%&WoVxwKQh9;RBKfiUS3Cs(H005q!x8Xg(%i>L)%|Z%c>?WGIun3sj;!T(SGEpzq4S<3|`S@ybFz zv8Ix0&^kbP#z!OPr?!5u`9nkfmcK^L-_+Ac;ZZf{0BjA=3VLoKp*%tsid~*2JxAx^ z)qcC}pjyqAMQXBE>93M+#OltT5^e^KO@ClZQtsJ5{oH>AqFag7_Z7i@daSrilbA#d zr3)0f$3g)Qj4`wk5WR@ z@Og31ZT%H92Gh?$!)};cRzUgahVT=|CI))aB>Qr4SSCfC_01y~#X}!Ip2%Dsu?A)h zdNX`$r5mgLG{`K^jvM(Ls1eP&+GUWVQ>ElnnJvDL_o)pfx~g}3{aITL{Lg55W*S$T zWDMymWW9Bw*$`yOUm1jqv&@JXzQGkJ#o{P<5`Fj+QOM%kqO@R!9yyKk?s|s#v9F6@ zjO*(y)XUa@hnzVz=!F~*$s4~(>%1Lv-8-{EKJ^O=!H7&o=uWmJ%4dGX2@!xv%$wwB zf+xIU@02@diiVVTxRKN2h^(W}U{)$_B=Nqsce+`;3SE+<-bzW&J2bfych4E+eP5b` z<7F05mi|KVr{iYMDp~uLjr!-K{h)2o@*@0lp=!i-)ZWv`LzG`t%()^VpYGP!;U-^-7)^54dW^rN>8b+ zkMYe;@6zI0ReqvBHU7j` z=Jc8P&yM}NFXw--t9w|~hb(hM(_JR+dW|PhLZY1jEQm|=Y=-uUOQfLGBY?uUu**ZZ znu_Ijmwv+K-hL2)WBLxAi$=D0d0gO*G*v+&Li&O38aksYk)s9B^0{qe`6`hyY!NWZ z2@+T#eqeXuhrP%9w$b$NKCR zO8)lA18zcX#iGCl)e8)M-5i~G7|meOstAf1TfL_sqG%#Nt@rqed76$rT(w+~~CXx0h=1|8zTSXe|ByZv4Ib( z2)utqT}8b?HJ-7G&N0tr^?s9yhk}mY)}J%Od%RqU!F-B%C4HD!Q4qloKES9@iQtF! zT80A{UcAQge+WqsnfE^{ecv^FUIOI42cMNu&Olz_{>0X;6GAYBPGID@sj9x|kX(>! z2X31%Gao6OMCw{87JMsMU-_;H8oHeB>MfbLQ*2MJFdUs()O>l=YZxb}9ftxdCh<8J z-lkMAn6^7mJp3h$dHaZiFp%Ix6WSYu9a{bm=z!ec%*E;<5l!k<0G2ecBun##;PY3`YfqII&1vG0z5J zMSwy-%OLrtTeHcIDDc?fVGY0N%MIp&oeUj=hZki1nAy&oC5~x}b_B`b&>fMJP(;-I zr??+-^LYfxK#fQOa%4GIMJ~XZKw-ZQ+q`Ax?yJa3TF&lbs((dueqlYHUeKMjNROzm znUL*b#h*Xudod)g-idkhjj5A6Igi1t2Pi{N1xUis%JX(#7l z8l8^iG-c%CmCRn=Rmg>)yfM~Kd)~VB0;+tF(f}wNb-sqy&Qq6_(LCZeHSA4U}Pn`UaLt7Kea;hkwdTjJOcA6oG zd0;V@NT%0oHhhZyEwizSbKgV&NwfT+$5}MTZ8pEZ^#=Vrnt-T^K^HRuzxk)h!TWEI zg2j(AG~qGcmvf6?>~k;$G?DPY?+;ag-Gj~9h8j_3;JM!L&#)O=&DA_=6{2J{c@4#Q zeDw!fnUx!vn4e_jfzdTgcQRUn0t%F|s}uLLvUUulD!fBpvL_8Btc zpC_J?JnpTqLh($$xX=C7hFvKz?%+pz!18b zV}R8O4=4HXfRcA1JCLELyr)q4#Mh>Jn2g~OC$iGB_smf2EG)&d_bNj~isVn&G3==p!JIZ!dOMlVCavGr<%koDxLeJ|{i2U4|SY{dQGzGqY4DwN5pi>SX3(122(&7Y2zdv&YMJt`me z#^uxC=e6vjii5Rc~#Ae!&Vf* zBzK>R!(a*Jc7}r~a6&`y+}J9< ztW#L#9RVkHaR$Qh(Busuhfmmz^!E%q5cNDfApzM|L(XYg*}~FPcrosNYoGA%ZD{~y z1+&Idb$H?R(uf}*{Nf#0ei{SN7`mOy8j;IQPQks?|51TW;!7=;=5Rj+;2xM}tGy2@`(W+@C2T$#9Z9 zsB(`C&$s+J?ux*4)-d|fu)obj0&e+UP)PYp?s(qIp6e_$kCokYs%qABfwG-8roNZF$P;4dS5NNJq?+%4M0EfD6by<8R%iS+Dbi~*cZ;{~^(yB|1FXnG&Uiae z!hL!9%KBZqBHrsz3z-kFw3^CiWCi0B*7Ec`pWF1?1#&cBnSsyGqCOai;_c2v61ias zt+;t0ULysoS+;F*B^CMZsg7A!fkDaS+@}h6SGO%2b6lLg{ z?!P-=0Uex<1;xTz_v)^L^+kNOZ;x9A>W+c9wzbq(y1JhWwhMn8e=abX#Ku!R^JB-ch1D&y=AJ zqf9!);w0N2s{5HAdXe_w&HA0z&aXGghxk2`S9d7~OvU)Joo+`9w0`{5mZO{fT2RfJ zt;DwAY^0p8#Zm9pYjhUhIAne!*UxxA7w~B9Z!d7@r6|7aadUekjZwr)W$8-tx3Rda z+y&!M6l3|)YBjM3L0#;k{$c5FZtdIlS{!#v5>=}r8Q!EpovLjKcKUMppiP0fJgQ+G zT9%sWtO=@*)>Jwzlh?{a;I>qB2iYJ0%+;+_fcX}>U0eGSN+vn%t|K`2=XSLMjR*H> z9NZp}ZC?YzygyICF=syc1r%Ew$Gq>6> z{5yj-p3+u=^2fAG%fK1R^X;MN2LGzGMvq}rcR^0RW`XU8S2b_>;{w}bI5-G(Wsd+V zOjU*G4+}up1g67p(_g&$0fMz7BuDuQDEfHH1Tb#WcPe9_UvIwKOWNshIREX@8XxW5 zcjg*ri!lc1n~&Mw+V#ZT0`HBq-S{?@^^XlRqnQXbXYuk1L-ruP=FK2kIZc&59J4tt8z%l(|+{ zOB=@C5vn;Kk}E%wHt=qit`eDZra=C^Qh|E>R{2%=?2v8uS-gq72E|$%eOmjnfavFr zN-nlpml`r9dE6KI+Bz8TwG_@s*DU<54~}JkjQCMYI-@C};7Ut}_ODAik-49pC0_RT zAr5!PRU$s{nR?TlWKTawvV}X0;dlSf?VusZKjOoDBdcHfhx!79Yi#%U8otX<{C!*Y zHijm57<_T%BBAQxmZW+EifnYs3Nh>_y#j6Fjj6-M2DMQbReU#Lk86fzqZC`2eGcT8xb;65ZGBR5_6Ev|YzJyQMFK21+JtE-1AJkg1b$|$MNfl9SyC&_j_$T{C~ZaX5&K0wA)4j0;=m<| zA3&=aFz3yHV$SB6)nuET$>|$5)zm*@$c4svo!6!)BdVPDMyIwR#D)>pqcXTm^>^4N zm})N6QG3|6gqoM(2*(X)kn3V4JeSQHaSY2jj(N>5h$`xmol0aPG5Yf>anqt8$fjXk!o_7~W+8LcL^Jv#i5Hq{xDWM7G!X9z7O zV#gPhsNnf$*!GCeP|`8IxE||6a2nv7{d9ryy=0WCSdNe+sRMJNo0mv>*^Tz<_DNnwle|X6!oAx`wQX}=q@ z?09wI2mFY%jA3U9Ha|68GFJ}xZPv~BkFBy1TEhzpwu*hG|9ZT0zRoI%JX5@-pCk^( zac>TYdYOzE3HV#q%&n9WX+EXEC(xfNcE|z=Gd6g*UYlZbne+ z9!)DooV3Un9$KDr@{kDanlYWjEWL^|p$H~tTT`*l5?}JRmmIDJ6LD+x1;e>B2Vy)6 z&$uH*Wa8z_@1F_rhb9Mon|%3C<=h1SudL>@6hWoJ{l$didQtsyXfqbu=TdJu9m)I7^s%`zsl+nZgeCkJ{ zo1qcCP2!7NqzE}1i^PsPV9zT3rn8wtFhx1VZ~`#Y)ATyC4~OmwkBaH#yB7%Y9&UKG zroU2z()i>igTy>!)2|+3Qq$ZbtmFqNvcr%!*}SKGpj>_c$fd&U7q%8@kV+U6oI;;dS!^u$q~4dCmN?8 zwvhW=gsSi1tjMK#a$i|Z(IE2_(-+KJ${Oy@EmGwrf{#@R3}y=KdX?9nwBPJ2 z^0;{&Yq4~8|Bf()sQ94CZV;thD7wM2J0K$=ea!E3P?YL=9nq`0eX20eI~Z-QU(0mk zJ5anIo(f0#v6az*cgN^d9Xw7sMO;U35x*?Lez<6I`-I7TwMwdPILu4@!-OE>S?{0s zL4-SGdr@0pQ5B{CujIb(&T+H)^IvAsKDFe8xrwhV-!?N=_JE)VRr)JmaFdpRKV zyd3t~zqnz zVvb3|Z1a+$B+pz;Tm~!!nNBvde6&5BsRgq(c_N|;Z^8@1#V zhC^tos6AsU#h03|RF^GXw4YONl%ZR~0?ijbj^V$uIqzSF+wTqt?zLQaceo^Pb3J_b zsh(T_9_M2!BW_)U#?$(8l=l{s|A%;bpLynYnRBb-9x@3qw-#XQw3@$c>at6{Ox)m) z1CP{sz40n*DXroP7dPX-)lXg6D!5qfgqnTC^wi)V*5O2`0=3~``kpadP@z`R&1x*8ze~%l{iU9zFAeI&wxBYEPD5P1F5r>BKZUA5Q8|jHtGyk86<0RwWKGH2;#;4jp1fq?K0p6hc-rgGpdNWZbTT;M z2jE*OEjCDzLm>+y5LC1daxJ{y{(#(+}S=P=?XuzMGs36WT^A$%25Exa#7(5kT z$I;tJ>(1z|X1=WHNCZe)aB40Kl zz*@{e$`Jk1X4DsuWR4(7u8;Cnrxc1GwvrY9`@s-58y@NZH1_(@WqB*HLlTJb3%)E7 z3E{OnV--ZkcRv|2aR?cjY&wKHcqaSz|NElvx`(b*cxq#v-Y&6XsTnb)LLBR(2A=*Y z+hhaXqk+kzwjJR_oQVMKV>UR>&qx8UVF*HFsWs*Ygw+WbU3hg{iW39@Dfd7AXmWbs z_xD?^_%+~jZ+ZF!gIQz@NGC9=S3=GCT*@kkMy9LX#<9$=`JNGpY?3wLH4$@=SEpCH z`0@KA#Y46421~Dm@xxvp3cv~XmNNY!V-~}4AxZ?@YCQD2Ua4O40}M}bgU47$U~>+6 zG$?*Ot<{WGI&1BjzYX1g$Qdf&hRzsa3pO5s@I0a5mgiLYAodraW0`Z>aXvtDfvaSc_%1L`aTh`x=5S5?|1Tuh)~C=~YasOud z<~HAL;ZEj8E?g@@Jb#ENh=v6Z*}S0XT!{EOQ9LAw$7#aKF!6lVo$&-^l{E>GF6r}s zS{%ivXW)(0=}!dz5`Ej#V@}|?+*w}MmlvBB3e5RWE3$RrdpT5&;qq1Y^xu+@h97lJ zUqI6oQ29VVe9_q)ui@ z3LK4x_6Yy%=&0z~<0Inr`yk8P7yTwl ztzTaY_?--IdM6YPWX-TcMSQ!9GhIn~PUsEI#4#YSAJNEa>BQcdpbwBgusD)23|xNs zz5T6BJyjcvQ28)j!4Fn;a{%PokLsX)ju$)9<5WGQ>4|9(OX1bE4gJhy7^RcKOV7c2 zsS=&S!_jANtXPFg{}!>YUTEdg4El_iuHu4E1QX2Y?oTJ<|1bTh4mC1@L49~$tjVzz zinsY9Y|}3JnVma7=t4ZFX-my2XW`IM8q9W?>SD&d{nv6XxIk&G z@<=HHn=PkpI$UF8;s!{E8qO+}#4C{nPsPcMJSgr9#;2dnc&8TpbEjv!)&<;Y7O)-h zVPR4sLOKtTS@^kM99n0w70aSCSaOrhHDAc?|2CoJACH@;pPBe8lD@o)(>P<(Q5Qd8 zw3-!jRx)I9&(h}D?B5i8t7z->KQp-ze@(Yl5qy1HL2#N5T*(+CN7N=al^_i)kER?9(da-M}#Y}+V#_{fDt0^ zo^n-*iQo2|%~2)2)B!ArS*7?<(Qj@-Gd*R`h^Rg`s{N=N#`_f2TO&E@f=BDRc|q#l zu}v$%67g!nEoNCioJ&ff&<{u>z34sh#)w znW13phk)^iNR$wiN<=$^G0%hZm@Y$HA{U~ z0jFy$F47{jk#N%W^pScD4tKP*;PMBRCPZTQg2Ut}DLLzjRGh>V@~P~hw;jFP?k&7; zc&f$}-2x6Oc#V?VOGp?G6~&&RIkw-n{)w9qWcqh04_MX013RtRL~yM42B!BQmP*F; z_3Q552eeC>$NGxt3D;7vr2Fb6BBgac62)pBNXd;850kprP_C&Mwm%i^1yFvi?Fg2L zQutS`vK%=_IJ5KsVc`e-01C%`?EEE;YdDBzM-)xM5&tbM2XSoAp73)ZDJ|A`_zv;J zY6@RJW6v+UybG(&mhCf~hg7G!N$d5@an}WEnD_$z`L!wq{x}DP=tWzC4J|$_7%&{t zx7$~FQG>&lSd_GsS)jDuQ#ge}a>LbPPG3ybp_H@txHez5T6?9mqeAU#qm;j-QcC#h zrYP`uF26z!2Va{dQ9`PvOxQmhw>9!l>^EYNU7uD~(P0yL3Au9Y)ZsQiry0;k7)2Yg zh-w|0TJ~6Wxt#vnNMSkTG}I^o6JlaOlGKvKTRZY-Y1i?-T0joCh6QKUVFd-1-oHj> zMx6ZwahDYDXT&T!*gHnMomyz!5TPHf<|}G*1mmsb!m^BtQJ@(BNh{Ew|CeZ&$0wa+4S$B}k0 z>%G`DR)#si4Xw_5Cu0G)ss7@hn*O=gtoGBUVR{74?3vs zu9fCK*snu^e)ddNyRI+h_0VN=Z~te2Rin}!D)(Z0>{a|Os)&`wCS8I2IF_A$oB_j4a)vijOaAj$a{@

brHK&xTPmc2=%Kw0H4%IK%Qi-mcRE$<9>`pXp#7fOB_^iJ!_0)rdYc-XEAwMoUJ!-pd7M1xl18= z9WvZsEPiZL?yR?Ed&%Jo*ot+2A7W$7U9t_XyNw#>VRI2G5-o{Xnq7?1G1EK`IbP0! zj9^E8ca9peW9fPE4Xq?B?7p4nh4(py>ApFUq)WFXRtaMC;Gq2P!V&5{N~s*yzDFiQ zyt#3(D7Qsm2hQiCXyw2!q|Ht4p6baXPU8^)RXK0}@O1i7!3oi=bYJiPWEFCAUI6ZG zAa^K46oAdiSc(Vn#qr#TRQ2u~^pKYBI@wtnsD%||?*z4e zea$Gd3*&0}K+@M-bI-B%y_vx*`YZd`Fizd0z`OOlmF?b7lfV@ViM#`@7XLo4Z7S0_ zexh3~p%+zWchY;+rhTD`x}l5k495#8!l{rUeahEVo@pd=efcw{+9}U38Se>u>g8fe z;PdkK^0$01pdHqwm#)T^L1!lPS4w$y(VeMIiH`-R3uR~OV8ju~STR*$o`_ewkBEo* zbF+qhx{G=jx{YXb*Lih1Z&vPnpT&{sRZ;n9XNK2J;cor$+h^N6qAJGkcu7UfF+Q`j zg}Q5$T2j?NRWIHK?q;+F2C^L<%|n`2XO~~ja{zLfAy|<5an~birJI%S|HGK8SG1u% z$zLX%G#bPk#_ti@D)SOkb73g8R z?eCgVVs)<}K)#uPQq&k}b_}YRgFt$ekNphU;`0u0f@FOkZztG@SfPD-yL+ zf2wG&x@CaFnPWE3^eq@T26%GQ0!ZvnJAM;;ywgv_kDt%=q-PYT+v*m~Wa{*4m=kmo z2)&4Eu)J-JJ~@nBEQcgY!1Ha)*da%a+ZJeD>@KLaMaLIqC9;b1QA!l~pO4s*3ZdVM zQa|8c?#Sjzkv_Si=V=6mm7B@b$ZEj(0}9?dYU`pWafu zULWC!$+%RsAFr3NxT>_Q(MzozjXM3`GTuiv>px!6R40AN$geW;CsMAre15ofY35@$ zh<-p$4GJ5&f_yRd0JqP)>O?sG5qEH zvL;%84f_RapNuseWmgPE-<-qG<>5&ZsbW+oWG&Tpk1Gnp>-AT9^)R~PdT_8&Y{5gc zp+N9Y%8r?xfao47y8rY|#0i^3o}X35!hR=@kBrjDKh3LcNu|)me0}OM@v8BB$ZIcV zdEDm7M#17LchH`MP<-$riH3Au+vQr+$AA<0lOuox5SM!E%9M(AGEZ?A@0RbB?YI1G zGll5=x_i{%EE302^qlF4Md}*&oM(!L){)xw7ub(r`T{KE?T25VH)OoeYf-;kecS#A zHDDumYXjgHErnYTbot<0u}=tPo$%t1<}c~FMWuA>-?kQ+OSk0+ zXdr?);WGa&@t?(QNs#`nHlr|3l4kb~c-iBm^K$s-iwxshcfV005MYfvC=sB$a`$hz z8F21w_GBxj8n2F;#-B_{&2IY5i9D%g{IM3X;loe@`S`kR*skY1(QY@%mDwa7hdD9eC2eG_YW-FJ zd?(9L>HGzMJZ>1T1Pd&1Eq} zRNAngf$oR6;R=J6H(#4GgT}HZIRfbx(K4Cz?V~UIeX88#?qX{xyExN9)yldI56C%7 zBw}>+0d@%`x*n$ zj{ONFMfr|L01Y^0b?mbgtHOf2FLg<_=Chz`@$=bjrktRI-Q=pbvJvZyiIwtAKGI6K zy>e6f3~*5(%l=$({M_Qr5g~;<^z83hVYwpNs9E^HHBeZW_vcz%yFo9oGyZ@zEr~nK zsEPFfzwSsq6+7j-zS9iR&4Wxg+D}o8@2^}-Thos}e46Ai4AwWrFvNFo)Sm74!Sl-D zc51s%C*<+(ZAKXkA;?D@_fL=SWuUQWQ>E3N&vrY~aVW0fgJK{O{ayE#XFtJplmHts zJ@ODs=k2$#jKFF+U?XZPzg_psA2qBGj_<>{d6TNCAgE%^41KF@ilM^($VnK=$jZWBR^?Q9O<%>Z|Z3qQwmN(#8eDNFcrfY zR~dx%EJ6P5sw<@!*Wc1^);nZ7(ghjQEu8foL(u(+p+XT2E?P}eHw6bNhSO`~1svVe zdl{;^KL)7g=#8ILdY05YVJ8 z1fLH*2VR;=qg7zFMp_8^me0gJ$ezNGX zgWBS}(7A#RWHtEuw{FNMPbv317iNJu*WO6-cw^Rak@=Ew!z`!LN=aRp>%%`Dy*jlv zZ;E$gU6Pmmvm(BpX-QYC{a88<93-zqrn)H9KElryT{90WS~WulqtliPG^D6S^dLarcITec~2&Vpaq1(4yFq#{HBfJlL zzKBJ*sBr9PpD-a_{2x`^xGJbB93FRxmP%RDzIkqhp$WSh>s&L4KAD-->}As>dcGYZ z_k%tuSg;we_g4~g{-)ZW4x!CXt}?y6#m`wo`|YFc0;y4g%Xe2MQH5m3yH6>32Lu=W z9NeFwbh_XSL0ys`qbmtu$YO<6SA(j%AMA}qiMdKj`Lae5eP~zkU&i$q(e&u9v^uoP zru{;}O%Kk(&Z9HVC)tukd7X~A=sZ^GyB38DWTSZPhiD>t!-lV%|4?M!MRAgP+`p?hLA*LSjDO%;t-(GmpJ9s;Q02EgD98eHrN?X{($JO_m3sI{s4sso6#0& zq2`+JLwkZY7pN1Y@T(gx>w|GdUZtSb0qvw|&+|BZtXkU z+`8MH8xMvV*}%T6bp!9d=jpfnnb139-P*7_i~W*9Y8u@{QTV5g2(3(n@WTs@kMUyG zP{pJIFPJ9+-R=RNY|Vd3%ACS6T8sLxs)nLq7cI1a z<+(dRN=j(|A2)88+x+PV0-?A0lf~4m@z7>qwWGRw+vgQd_y5VuT3X2uRn)=!T)R#7I$TMVgIHr9@C_z!)84)COaF_I>ul{($Yg z&iTZ3U2pTGgQPm7*PmI}f{SeAzz0PTrG$x23E@rhv40-!HsZKP?b|K&MBnSgjnNk< z4j+gD%c>76Ua@fc{Y!6AQ8H5zi8txQz4HF!UhrC=+hnL<&8VEK~E3SF=XM?6RCs@ zy9mdrg6anJBBOcHUCY9>sJ|;SgyGu}O3qv*CS$SU{_e8gDO9%&seWtQ-}ri*Z7AXR zAiLdH#;s7d%@I8MSeO#qIrq0m@m03muRHcArUWJGIAhrOjZ=Te0Ca=4kw>>fU0iWJ zD7xNsh2`Sqp{nQEiHPatr_74wid_rRm24}zf@)%%;K7j4N-c3Z2OQIm8!cPi$!C86 zBc?oSvI*-QEUtTdx$>PTcVaVdl?l=s`S*L9!`q64TYwrF)dIAIK^1fReY~M(drPIr_+&7zcAEA4iY*HnrM4b zO?791{<)gb(sI0Mk@A%#+mY@{U1ONSRKXKA|L0Pf)T1 zP9F4gJ&7!+`(YE_TORb$alprdATwS*jMh35V2}+&;N5q5mcH%m+io-tq6FV}PmT_j7a;oH@eKIBW8wTQS0Yr`1!xiZNDDulT0KSpJmu#MN|N)J{xnz+Fc^!tIkNs z$7(QAdThTLw5Ip9Zd3OLkW4T+Xx%7s_MbvAfHMc6NlC!&;@Vy6-HvFgHm-=-#9uK} zU#87EBwK|6c#3+kt`PQ3(fVAr#f+^y$mOP}i&vunm91s4PRP{k62lM!IZ}WMT~l;S zqrmf2na&p8z#>va0ef{5-Na=*(vk*<^PDL}B1Bz^R{j*kzCxWAR z2TX@|!C?{(9s9-_WA$DeL=c9`R94lyUUV!D;`0WTw!dgMk+A_73cDK6@?*qo{(D<< z%Oi%cu1=2yEe1H#7blRiyk)}yn9qiv8IguWVy5PSyL^~KB26|}-w|(2v5C~pm z1Z4eb?6->u!5T`W8%B5e-cF#zcO2S0aG~uRS&Y!q<&2C_AW7l8`caJE{(^fb{BtWH%zt(WDP;WFaW1 z3c1NPe+99*lC0Cbuxc062JVYIl<9iXSNEnKr4xOb8BFR1Y_Xg3)8AFoKBqr&-RKvz z4om^8_)~+%l^&Z|OK}Xf(`dU)7RQL?;0k!BP5vJFC#TOd8WFN40c%|IMg)v{3l3LhnEtDiB?>$_di5~)mLUTuRj+FsUH5ibC|Uv2e7m>kge{)KRdB}By0trB7HImHVf5#9S3&Gtd}G;aT+O_% zsti!`ybKpcYR17hNzyJM9i-chbt~k%N-N30al-1jH*vswH)QqqP-oPDJuVrEPo4}f z4J67&H80mn?B+*?=Myb@6sC+AhU9HBhi|D1iO^kRHIe)?VE8_P=SfFObPOYN$Row+ zT6L;P%s zn7#pV`b_V*|7hWI0?f7955mWSf-xxa1(d_x+eq&$iEul@;No*1)M%5;+9Fh`Sib^O zo5Zufv3$f(e9dR-n^0rgS+|lM3LM;qZG4x7w$#3PJMvzUQbN1RI3#)t*G+Nt1;`ek z|K~y9Nst+RCnx1Is&i*GTH4RVit({T%lC5|oj**;)YpdlMk?#K4SjyPz8NvH*1Lm! zlrKQ-7%8#L)VeUm?)Y$YW^zbQz$&;DGlk%qVovc`9}MJqVd02WPVyGROuF6*q8Ahm z7WrGw=0Dg3Ka*P+xSr%8GSP<1pKSpT7-C!p9fLD)`IT}&a9nShx5!MqpJBS1zf0Ho z#f+H1tbTa)?|VO#2fg$O!&LympW7(#?;E7+`!v`$CzT51hZl=fnz}E?eNLh7z$&B> z!zqo%#_b6D&D{=iCYD|Z^RgfNWCBUEc$R%ve4?~?;(COCDeo;IYVMfvc==1-Q`xPohkrbqd51Hk;GbB}|Z{FdZ0mHGuU(Ndf!yV|BitG@FMlI`4@otMIPMQfFUBl$X>Q31aQ5K6DAJDvUX zEd3tUW!jXgj+uSdSX29-W}qW&3db5^F-SYZ(%g19^*p?_TVLC#E+mOla7Jn_3)Gbzasy8N z!2}qb^61P7Z5f4(^K%^1AZMPuz$0|#U|2Ik2I{h!IW+8oYaUOmqo08_W~(@#!ZnP`?q#UA!MatVRdgWhi>CzkmV8cv`pL5Ua*brg&GF6y z$ie(}Avs_(<2y+6^sjTygX0Ok5RG&L(p4IgoHEuPjJk6CWr zEq{lNyN~?Riy|c;hR#8&F2*Xie|Ub4EWbYrqj%{U&!GApiP^-Z0WuEIgB{#&ud0Tq zFaLV*=s-|DU^ydZy;+J@eIzsU)I!u)1I2g8ON%M43Y1-@Ampi3lI67+;Ou1$Z~J;H z`4?Dd2I!W8v9flVtPA|512qhlvApxixRT zTrg4|___VJhcBV%y%7+>Eko0|N_{!?n~B6*=#-XwDMtSI&au{DPwlo|nwe%5G)^==;75v(9tboYI|*e&db zdiCnW$1Te(-8nU35>K>W2_`jkswp7N>fthK+S0;YPxC4kpt>dB?J$)HdslSW5EK zmKlx@e&|BJTq1wp3&PBclex72Mic(K+kG5OlzonmYy4SrW3Vjs*X!#4t|o%^|Edqf zRGcVgcxT{vPT3GN&%)E~(jZZWYABB^Q0`I`52kWg8rpvnsT;tDfsQb4jdPu9khinj zBc$ASjK@fI1u$Il(&x(_`u}MuZ-<0OFMw#YjQ)C(Gn9$EK1gvQm+ca|@^Gs~=Yj^yrc_3@Q2Nsa#IV{;9W8_-sjwU0gVtV%m?pGq@Dc)DS} zb~LbG-j8dl_|?>TuJ}pVt5NG78bAG4EpS>v-Y*WC=e%3o^X#^tMFXJ!>9=5XTlY`a@Dx!lSwG#wuu0~g{Xr_?^yt@K zcX8x(f9hV3!hxDP$rtc%i!vdz>BK)I+%InlHrOR^4V#EOWD++XqA$WfBeQ=sAMd`= zrgYuJ-|>SM&Pr(Szy_kDoHQ;_!Rk^n`F*wdom=Ll)oXMuG2l0)c75^k$O~v;JuZU` z;9Pn^II)4~%iS~+rJ1dw!jS{hGl zjZ>N{eD*(&M)fp$&4k;0wO>644^-A+%iBNBZnQsba(O$4%g9C@KU2`h7&Urh2LF-P z?!MJpwUI-Ln+=E{?r^1=fuDz40M8E>p!_;kB=2Ri$R)|6Aa0p~LM1qp$%Iz5F0jd^ zE-ILlOv1Nv!eutX=m$(Gf!t)5_jRlnkLt;m3ot>=bpUtZl!#HO2LFs{thxF=dY}8(Oq-LOG@4v zs?H~M&*4NK@ zECU_+w$A)VzEfJ@9objQ3#kN8pr>*EChQSU?E5!{%g@{&k5;xl@vFWC_jxYpLZOTj zCZ3wsoNM$y&Vtv|UmrQ}>2AYFJb3hW;SQ-u4jGcFL3Ka-FTGva&D546Mo0upBBeB; ztt(8%{Z_!3wIN@hTx5%tJvsYOTdSFLapm%)0`ARy3MF;oy-B~2A^nx_7$UVI86y7~ z>JiO{6s8=I;$RLRa%3b*o+89fY9G*?kkp`Jux@jNY#veVMY!Ukueq~JQw9_1`|`GV z8^fj%n(bO5;){tTxrJpBT3e!AwkuMG)IrqK7q}K-^N24%Of=SVUi*g};ly|+8^UT+ zq}9my9x^L7ITzfmV{>IA=97La+wbh3&Q!iKk3okoz`e3sM4wct5W)G0>T%q96+$y* zp4b^a+BF~2jQk;Srde(niIG4U6MlyWJ1b*HvHfm&OXouNz2{L%hK1WlEN1I*n!JbK zNWnV_&+$RrWMuD7nSV10)pr&|g6av27L&~&dmbQ-Fiux;PoxlF#Za%db^T+N`*F?V z2*XHF&l!@b6Q*-k5m|>uENd?-h|r^6U4kP|W>T?akCD zZ?6V@eWHG1`Z__qlsBr}KF;x6z<%JS=CSJ5T4HH0kNTF~;mYA`=uD35g%IHAuBnBQ zM2tMcso#iMc-E^mPwC(`9ECND`LvKa;=Ry;)z^~IX#Z~MYM9D!ECkasD|cBK78BC+ z!fl2nV55v()-eYX`**K7I=@E#our8JhZ$knsYTO2fOeJ9rT1==xP`dT zUY22XsX?mW)hu&sY7@cNTT1(%nAoo}Kc$@^V(+)sa<@KE6+v)6O&+p{`pjn&XKww1 ze*S}R#nuoUk)X`0{nU5ripXb@Y{V36kn0sv9yb05(wf(lD`19=llG&e{(OA6R zlJ%|N$1*C=*ySD7?^5g5ECcG(`_PS*v{|M>t?Elw{bV zaI{$_TzS;zs*(=wp4iiYwgGABkKM$7c7ziKKFlx`qSjWAgWi)tcY~rk)+1_w-ze&{k^|pENN2+=b zFVAO`abT=!T-RxYbe*`FDy{g*qi8ECR*_em>Z831$1Ozl(SF#sESl37OAw8n;$7*< z58vf+jN8e&Rzi?w&lSbg`n{jOv>d;`e!({(m2?m&hFCTGhf7~ig<8H25u6oZnER?L z45QAF^7(yZMGAhB_a;}9GBOCkexjrUPwg3QM&Yi)6LBoTZBs1U_ZHB+8FpftW2qz1 zkD)+HR1T93>Wt~ahFrHyzKemxHw5qhul_V)@Y$hg1txTQ4&IYby~%;3lY1k}*?*}{ zuVX{i*D|8=Hye?B^<@ZPvB8)0Ky#fm8kH80Q~)N^N#GZN>$Z#8eT{NI1HeN!V;e>4 z0UI@gh~j?*^-j;QrEg>YC>^zY+@je0#5Z*a5H>5sOszDMg(*A}emw2if*bY_2;IJ$^1TknIQj!{hqZkAtrJ|zXI+6uU5mFSM^x78Dw|*lqNi9g#9L7>oX&Pe0lQn+Y*Ibwh z*PuqPtHK@2evMy7XqLAN8{28fY&f(pkAmmMN|tD-AX~0@>OHG&dyy?{*6P|@RMgZU zfu%EZratL_5U#mlQVBX2GGKemI}M(84+cw#KS~j!KYH)-4O3Ttt6ZvXWyJL_P*3dZ zLW9_Q;}MU{7v@bYEVt|x_rO#66snx@*OZf5a;5PF9eDf_)%yhxW!V!OIh<#_w?=|Ig6fs9*Z8E_#?k!URPyXUqZQ+4!)FZ-?B834xNV%G;7#F&x-77HX zrKhTm0vM4&QuA`@(A@F{$I_RHIzSlhL(;-&7>>n@jobCy0X zo5+rBwj|8w#xdmh7yQlZDm>LE)Fi#*rgI<3VzFjb@ZnLRbxA;H7`BZZ1j#|uzJ&|g zBlB0@<9Ax1eS~QE!QFe~kjotq>dXw%tiyz%i#DV4qF}-08n(5l@G=YIcMagh87FQN zRwCrPhu(^eq~?{!=@~j5lHwV!UpcXrYZ!}^&pI%a!``T05fGL4?GfLa-sn$R36J&` zSlVT0%@|}!wcZ;s(+qh>;CdgT<8@RqTn2J^rMmK;Gv5U5PQCbT^J|hn%%So4~>O4M$UI|a{jm{Yq5u#OsK^^$Xd`%5{Em= z>X4k)sL*}%WEB{`p66;Ra$G~c%D(_$B)3X0srb*4-Bv487jWQ|F(e0yMF*;R3|$4v zh?&0bS^mP5ClE<^%{ws6X-a*PO=sspTO4xrPRsFjeF9g#Car9Ue6O*7aoOK=73%v} ztPOqlrUglsZ?<#BDI8He&e~8qLdhy6lH|r|{%OtmV%OxZA~p7p&q{~mOZmS#V*lAw z&s{BgpF`wR}qY8nLI)ZYZ0==NHR-z~v>^c)78sThrj^K{bzF(UKK%$MC)=;kn!!7aHAKZ4jNrWWF`sj> z*@gPAz$OP(W}%oU7YgrPTi9b)!|mBXVVe}X4zZM?EqI$N#CMnk(FEdUiqxit9(oxd-a_wa?#?|?Q~M~4(0q;Gp-aw_*xCTt6h_j z)^IQDVVP^ono>mu^ECeqNb+9zR^n-U^2@CAy%_pjd~5B@{`v-F#7HDHJB+huE8{S` zsfkRD7~=LUuvJG-NpHVn$l;%K%Q-)Fchfom>K6@KE0dT$A`i%6bH|K_G|+i(9{amA z;vF0`~f8t029l!H1 z)3(!sxHWun6mYb$dFL^aQwvyw!+Trv0lcK37N1$6h~=(#>(sR6 z6?$uXGK>;av78^uFRWNGFthpE$tP8F24TYL$FV+p16SSL=ahh^+PC+^ev6V}alj1n zwI}}VP%%=Ddzk`B^W;^*g<;1hdhL3imfc7OQS7fS8-c3|bil}iiscI|DmMLo9vQR% zykq_9Fm&gWq?AEdqQ@cOMyys;N5fe5;wqC-71NCc7%iJ=X;o;CdT<5@2IiE{U{)cP z8nGGIRUcz%rhxipK+1#rU#@-$j2e-!KULauyCB@Q8D+HVS7AM8pqs0={KukVmSR`Y zACD+KPBF6#i$NlI3;ah?SF2i%yDRB4lw@Qdag5KsKxPSt&n;$&9T!F*0)7Ms0-SB3 z>{D5J>fFbN6`udPb?OL-DcX9x_NSof%UdM!$4ryk1a^O55xR-&y)~{nOkQKq!bb8N zYaGD9yOapBI>GRRv+!}U`$pG&2Q4W-EO-HZL4EGs4dr(aw-|znzOjjWmRQJ}Rl}Nd zsOdeINYB3X8u#-*in8X;s-P-7O+nq7!i_iYiZCKzqt9a|iPlgkF!$Rcn(N=(nf9hZZ% zTFlHiytb5u{L#KX_BQe3QaY26&UsOm*qqE1Gzm+l9wrev=Yrhe-si1*P{uQfRVfOU zdf@21V>Y~gYIv4<@8&frwEC?MWW>32H16o}`MB;g!e!C~6a6}wlD>YlUDap7?q>Qm zTG#^yZz)dkq1J$CgC5A-<$0Y8&M1t~I+^}&S8&XD|8V_Q?{~Y+ERI|Ij30rC&FXSB zw4Z_>Rs@Jz>|Nv44JxVgPG4EzQyG&O0#-g*T@$nldGCMn6x820s(B@~;e(X- zZfk&R5N6bJr9o>8Z(+*^f_KQ|Y=2u+cqOAn!e4ol661(hp&n*gTt7V(ma54N+to8a zUaxx*KJpX7oq*G8%eY56z$2K+4~PeoP0$;c2g{dI1qv6M(2c?%gk(;*-!WCN{G>g1 z=*gZpv|T~3W%ej1Q1X5^LUuRu)PR2L-qa;8?l-Hwx&y!*KW*Q)+;|6ujIE_d4ZgO=*>?8qvg?**BislqrH{aKyn6txMfv-R^4Se;K( zr*RqNhtupck)uz$190a;)*&7HwQGMzpC8(gs?pTGy|B(RAq1sEoc3^5&6#b$Cos zDQuK&E1GS{KS#w-&qvJ{r;H^G2TwKKEHZrtbVub%Rkdjic=#f6(%>)bC-zCqb$8Mz zHq8TK<4uE!cNH0~dtW(V^nKtkOVW+~lz>k~z84ucmdUvG)cfbGA(`mVg|ipu_@Ide z5>S^YnAYn`!g7$`?T|O16TxLpjL zFxAw0PbtX#F!5lPG2!VaJmcuYYb$lZ;3++;>uz;9X=p|5$N2chzU~-)#L_);&CYN~ z5qW9#MZWjAu%aWXlU8*713N*6$8IS)nF)b^a%aK*TEV)`_M>MsBJ?89kfeFG==3)=Ix5XxSqAs6CI5sq21HcCfDPM;u4hS{36H3f$!hdRrlB4Br7hKXwP|pMFL71amxU2~_q^(mJJ4I*kfE z(X5#Gsc+`G5E?$0XVP&cl}e-SXg+DA`7{1J1+-D}bLcpIhOZM}{mE?yPA!#X7e@ zrw8{{2Zqe9j|f!=YER)&^9IR7mE5D_hPfD_`TLt54?=gvwJ2Ds+fbG{ zxPFDVz=q0J%3utP=)s2!t}#`2&c|}^MrmPQedHQ z2V2xM2swKO$`t!|d2ef6yWK4lbPLwE1E5?Nl!*Gea9jrbxFIQeXOMeA(#7}XA$ZO2 zW;Fhu+d=mO<2IXH3{!U^P+0pmx zxnpyT$KLBXdNjU$f{}XrFD)!hYQi^Mf2cfcW{gec^7vmc?ML4a|NKYkTMs^;myf~@ ztcUYmH`^?0HT|T>o7usVX*jTMS=U8gb7T9}y+ftuBCWpGxo1e`0uu9}{=`z~>!4|^ z?v0$1ufPW|%(6`og1S0d)r?DfpwEBdA;FU;!6*H;vARzuU)OvVDBab9P=Wp|Y35FJ zgu$Er`pNRaS-%o-epfFH!N6UgNf~5|8*2pC&&k9fg6ia-`n_f5*uL@93z*?$c9+l8 zC7mPN=kJTD5$vR&R~%jKfl&?uLvTi(%yJ9ugtNr!1w=K-(ak4qY2OTDALlZ`u5mVo zII$*dd`s%MSInv{3KhJ^ap=YQ`mPvrM%IkKTLqYDv`%7pc6=&(^&d=voMl;N)|%EC z&a57)uvYtwOD|M!00mD1G(k z_gk75K9%is)4ql zn(otZy-o29mx$1BrJQ@Z55ss7wzmWsWRV*|-}^Y1O_-%+IRTMT_z%oOBo zUYq6GDx0C3lk>(v)K-=KMZ8Z)K%eKu5VA@F2K@O=Gs~tzp}9}23wU3MajwtYb|3gC zv6Kf!#fh~p@_ZtY<8uc_A+p0(RYmQz1Lt!QkwQDW)ke_}!>#z^MBG1RH{5is_j9Z? zWb)RP4ZrZC;9DxagG?8rT7&rb=_9*^+2Z!?3&DfrzVJ=b`W`@$dWePrHwc8@*`DWz=pO4a7RSF+GF# zd=L&IW+v}csS?_iMw~yUHO*}2_`5Ot(Ee))(9IBKD3GABaKh74w^6qU*M5muaiy``2lzKaoy0d?NmLB<^Q2EAHDXOwa+>}Z7y*Ii>e}N} zs||tN>=tL!k4Idhy*+Nf;#UgSWQ=wwOkqC^KS59dfiapbl-$*jLmFHVGjj|XfNyv( zgCQ#$3=hOgs*~*r`uyj~d}s+>+O1I9evSli3?D|K4`@V$uy%+EbTaE5K9SrU_pxV} z^(S;jL>R8H8Y$2{KP@dV29)bN@m~L}d$sfzp4EFT&q8;4^#<`GKoRbSk?KjDVqoF zy`~=7Zm;=R#`TGcFHHZFOeIWlSg_La;Xq7BR#D3ljl3iNXYJ&XREKx}rTUm35_Nb) z8XgaZvXSc2$8#XyX0jmhH-9@WIe7^{(T-AlT*a>PAm%oI4^CMB>f_)v}8?8a^e(wuC!;b+vA)m&x3N!Rl#THobW@F zuq`uqvd~$Sdojn@kQ`-vV3G$ZDCur$!SE04#Dk3eY?&@JTn1OXlFn6#^Vl8G$_116 zI1w?oQ-g$kf_Gl*w=c#b_7wa zS<2_iUwRup6>kG2=Q3PYFhIj-1b;c~>E;3HU z&|&LmNWXJ8Pbc&09{zS6 zE12ZOgAy*O;;4_C4Pl~}8j?S~S^Omc544V}A7;|H8|LTjrZBlD%6*REXN$QkXr|`XCXfuQy6iMm!S?eA17q zI1Z9NG&^XA4z#U1rme=;2@AWQqSRAtU~Vg8%r*lFEgPX*Dq6A-!3b#}BFJ?1*-t6# zK^8rD;K1fH$DMVMOC&*E=}h|QOm9TPXHX<4nCWs`Sf9|pDh}Gk6E}d+Ee0T7hwk7% z$xTV3Mjr9(t_(1FbYq}owzCV3hsKI)YFozo``(z4>WonhXA(OOXTP~Hm;|}T zQ4+Y-461Df{ZtU-Wz@(*RF6rYk1cnT^Yp*L*K0nHk446rqqmPovf&+~m6lD!7FXjV zeh8>i6zH(CO_p8}(}Ol#9;MkI2-A5mkem$fQj^N32cILe_li+2;i=yI2E|&1)OSqQ{Mc*K_hbjuCk*I1J)AOj*jMGE z^uuOqm2mS*6=1p#V;=j1iht?kz{h_?x?c|hYGTK_eFQBupLb5xZCAOVpC~C^Ngm;- zkqbZS+&nt0v>}1I>g374r}K`qwm=dj@#Det@2=JkrglT*1;3I*3Ixz;%Qu}Vlp_jl zmIO?p)ZjeFfyDVV5smdcf=%CLvx(O2=YXuw0@StxQH`4a>88tyQf1TgDu+nvE|y+A zCEff<2NiKMi4hu?e98k|*Zxa>nsikv-e6 zMGm-Pd(3splp*$|b6(lphGh6IdlXeNnr=db z0U(Iu5&0fb_z=Ym%Q$!GX%&CHdh~eScPM{jdV;%>l~2ww__~D zg_r8vDtx{+(8i7V{PZKU4BB_;+Y8S(>X!6zI4OD#(EuRD+4j*9LLsa-#tbX8C+j|# zC%X@jH<(bYi}K_Q>DKWxv6yh6V>1!;zx{S1#Y1ymF^k*jPD z28^GDj8a}f&*$N^Ui}Wm9UFJW{zCwn=Mp`;bOb&I2n;$f9ks2%m2(wOqr8;Zr+(Vi+&DkEZyg zsZ7Js!l>Y_ALm}=*n#{3K*G7PV#X(>up2G0SP{IKuT&T9f3#k2bT6Gof3)z#T-Mz> z(*YW{RfWl1q^;9HqNn5@w;6{dCcI0DI4-B&wo?S)nj9Fw$wFm1?%jOmD9b8Bh)^aC z17r^v8)$8kH!96(-)MiD(>UqtuQkwFcbW)u&1!9y6Q=dlzKyy_D1=?=N;teU@q*1`dQ0n7vNNC2RXqQI?+#&6FC`T)GJdg7Jc z&mHp)_NUyNVJw}WhHjS=+M~kD-=|p#Qt5zi0?`{9TufHywgkBptJo*E&vQrDB#=t! z!r=uuJ!V|cI2_S`mPQtM$l!z0e^a#Hf{(Hx%^uA|C?`Rk#vE&erL6BZWT<$yrSec? zug~)%Ins9}M4Q0}nWk-K+`Q5?q#WZ53!bYW_3MAdcxLvCi+D4shQ_X4#p2_S^=SZ* z+D*j6@1?ZU87LymzgOtSNP;-W-pA#Dr=;S!CMvnDwLInAaMR#Tzox@ev18={BbNi8 zfwB>qit*8>c-huq21hHf7~e&HB1v6g#jpU{gL3MyV=U@}vSZG&QC6WSC1#&Z+DJ`kwkQYL4Ulp$OFE<%BEh3oZBOAutQlR9o;DWz}j;{ynHz_tKkwrGQ@gIUMjl_ z1%ogr!rZmTh^Y%sG+sc{>?7$7=){otPynz(w*om^oDHH$_i~sz8sdy>$*+gsfO16n z%QfZ~+Zisr*k_QA2A&Y_H40G2lp`&xIez&(zFMTte!~>;gWiD!1G3n+SaF{vHlUi2 z3-bz1uLxVcZoKydqkgml2C69JPuGs^Cgdi`SrB3c22S$z4?@K{NG$sWNBOH4{h~-2 z0wV%=B`lqAxA>+O6Vc;h3`pKbYJP(3LhJ=jD-ia=M51F>8>R zgB!an`joFl9abvc(+8Oc*KnFC4wu%Lo4?5Z)yDx9aoKhN|17@KLKdA(9vX*_;iF>J z&%$wO$6ZP%GOo?{Z^bVDQ7fh;89I;3k@zr+5qwJlaS=_hB>0_1Xj)zmD;-WUbqipqJGA&-P&Tu6}fM(@BS!Pqp zK6r(Wd_R8t1O&MYKbc*TngZ|+I8#-jUN9zBUD_DqZk7hgnNNT%)(RO@>3eb#ydHiA zpOT$>YOf>2SHo7l9$YjZ4q0hLdI65Pbj9S(J&FS89jq|%NOG||+Z8ry$WQ*1SN=fj zN-V{>f=+oM<5@WgSE3MZwBgB>xJ}rISpVSJVT~X9L0TPF-FsE$Jh(tH^n=f70a*k` z2)W&SPRboL3?E#%PsnIm1ofCTQb|uYL==-#aI!J|e5mA}pzG44rsW6B!Yek$M>nq{ z0dg>S&)DF#1So@6>@F>Mi3gwL6G%OwLb+Jcve&z%zxYpCv37By3<$IPfFTc!vFB=i z^5!Ag5l$zbN_#T;@+ol+HC)B=^8yhT1haewa_C5#h*s9pg%G*0!yk&<11^K^Sn zSlEu79}k|H!nO8X*E$)n^B-JMZxxPr`Qzz}yB7gPM5_Tc2 zI;guBsxd}B-+mA|Ag++fc{(W3YTYCAxAr)k@h<9I%64QI+4D4V?J(H<7|*Br1awQ9 zT)LX!>YiiOo+vBR0 zPUM8+LF2RU3$X4Z0Rj$QVGPaoM~Ys4Xujw}nIr!p)76v#cikA(SVX@h>l%^TzwI)< z^EPZD=3o%U>)U9uBo_Yhe0rIlSd}Q(r?9#ph(9R4#H@TT#~c<%vB*2pHj2?4e=!6) z1}p2@5$K3zPL%XeVm>cQ+3LhIh0;O>Qk79jo4Z;Cs{EkSp9~AVOP!ceCmbOgt+g{+ zcJvA5GrN2aVE~S;m<8-LGn23Sl{f*JE}43?#-TBiEqiB#a7!>4cq43pkNh2exm&V2 z{>}|BiZ%z)tF}$NO??S9ZLov zG8n&9#t_K}%hOeM?NI3mq86gs70-i-_cs30Y;kNCIkoXimsmSgoT*w&DxxGfP=vA3 zMNJNXQeuknh=d*HSVEy$>E1z?-|GZoY|?)gt$-Nbz@Oh;bj5c5Ik36Z z>j%N~XzE$k;{Y42z9P`>&q#Wnw zIuY6X9U=00zLNBS5`|bT5JnaGNKM97yCR_f52Lcb&|f#&O~WboW~FT9%s(7n9pySy zSs?UAXL3$(hy+iLB4>GPSZJD(3SdyCSC|NnhX=a+klLLb{Z3Bqdypg|OUkDF%{Ha1 zkuXj%$noT;8C(mJ`Def`(v02q#9Jo;6&EJuh`N8~@sNbOv&DO@&Y+~}{5tIGyIMDr zkZ0-h2`5^548NVQalYL7hgJA*drOy0$-%V6JG9$oqOU>S=i_?lRk@v`UMmIgH(BSh&9KS|2f*xu0Lb+X_1@+!I!o77reC=r^WwY;i zsc@lo;79R+-V_3?#{cDxr(f2*Bg$d^VRV77_=ap?Ch=$9UCOg9Ji*!0dD5~RTe1>5 zI#J1nh^}|yOh6`37k=8!sP#?lI6b^-{ZA%kM0ERht}uNTkSXGH`jM6ej&5y?7I=9b ztg?6Z-VMhU6hOh7Rel~MSCOgF=;Zsdons*9(8LXo_7X0w$S{Ou7%_*VnXo}QZSS-v z1X|=M!f#=sQ0${!v&2iOPqW1jXRp`KO8gY1dmbJ{qn_HGioLL-1}U}u_xvg@`2FV| ze@yH?bSIH|&pa^medzX-XH=&&G97+;?v#1(HwbytOq&dTEmYtF-@ee4cMsS$8h=n6A*fsfsV0+lPm|ZQ&9H`5wyXb%NgUX#m9JLk%nwojGrr zh!xfTUEA5%{d6a+M@ZzL-ZW6vLVW~e;S1sGB!s&jr0j{Kj8~-&%{ZZ=l~Wf}V|RDc z!Ro7K-k0vRu;UJFSW#21Ax%)+aSj}E`ma}>MAuV7)e`Z}su;M>YK^&lmaA=DVcA-z zbFDUdpS`P+9syqCp@(sioD|RKCwk5P`ZZS7j(~DpNrP(wlu+MGCr{c(O+KpH50)OR z!66g1iQh_cf9xbsW(T6p7PSW2`e)6jMH?!*OD=dVglizgDlF?#?QmoHq=QVouRmoP zvQRPx&KIkI>Q_kZedzr|>RFipbQrvI#paDuwBU?6|JyCL-ql{d{1tJ~7-nkurOsgG z0d)u6P4mgl=g$d?T=;(Ujz#)axr7VmYC}4)l0W<627n?tX$tcWcXo#$8RtaniTiFt zU~)d%sfIS$0oGd|VE)J>fdlvT|2FSFUsGGPpZJ26k{;M2`As|yD^gMsKuBjfM`A2a zM+NG0E>%S3h&Q3cK`4=j&|5G|Lpk9Ax_07Af%Be*3nB?hjMA}#adH+z&TlhdCCXMS zwKsOXbZC53m@6V%xb3rSq8(aTjrZ8WXmc88&H2Ed9}xHf?W2Dx+(j2A!$&@BAA<}k z`dc52=Uv^v6q1skY=Pb~lcUk_TeC`sLLzB=Jc^|{oU@dJOycHq+W$2{?J#QsD*8Z5o;9&b!L z-2u;j`vGE3Q7s3vF;7Wo>yciw^d|o*>6|c}EbDmE&9))t-BOC8Y%q&vJ#B*7txi?1 zQ0~Qi+V3KI#qZs^wWAx@o^NthEJ(0h9jnsZZe1gDFn=?p$IJ^A04N`0eba}vx(-qQ E2XfVOp#T5? literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/button.png b/data/skins/cartoon-coal/button.png new file mode 100644 index 0000000000000000000000000000000000000000..d6e4a4e77189649c2f4b33193f31cdc358c9744c GIT binary patch literal 6591 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/checkbox.png b/data/skins/cartoon-coal/checkbox.png new file mode 100644 index 0000000000000000000000000000000000000000..df90c40641903dfb88d64eb293b8812cfacabe63 GIT binary patch literal 1740 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/checkbox_focus.png b/data/skins/cartoon-coal/checkbox_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..868b9deaaf814c4220c57f74bf1cc598c31b7cc0 GIT binary patch literal 1605 zcmV-L2DPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!TkOK~#8N?VDRm zbwwD*mnSrpJWGnF@Eml2=!isDUDXHhB5$N`(AVfQ1l6h#Gv8N5W)g`#+T z6~*&eo8OulU3;yWS!=85Z1V?y=UE%sd(VHKIj*&X2OfCfe@&4puR^=ffKY9C|6Hgpyt+TorJqo_G@cWBR)+VE_p%u9wkq!}18FhZn*meomV`F2%_V%`VCBfsgrmGjSE*vnRtgI}ktgKY8+#FO$x8lLU zL9oBSAMEVxgq7Ld-3_k~4-bRm3}`LcULx`s;Vj{ z_2~)~6%}D+_V)ISmBfUbtfUJvYIb&3T^adBXwzi?ssD-$lMD>75zIwb($*($3qBju zG26i-{Z*Fh29DjgC3NAC%>Zlq1B)IFBQA5U4>0)A|0x}Wqrb*xfOP<*?^joI zmLOrh?L+!A4xtRw-&d*($=iUwzP_BDpD*c8--o%mxv;dr&gf?uN=ybY!FR|oNly>! zBMGUmKlm;o1L=yexVRXW7AAz`KPpTHIOl(+K#fm>A12WEQ@Z2D^ry+&fX2o~75SI` zDZ4+oo&hyAH9>iKc^I?UNZD-M3JiSud!#IX{}D?3L)-waSpygu92``UKdrC(KB=E_ z`ja#IYvKlQ1pc%PlXP`;g=K~hyA`5?Uxo%rq(8(B$g~6Gkb~5_Ye;<-J}^H&AC?wa z8T}x`T;c{;SAfj@i~+#n#|NTQaLVb=k3z=7insx@S*!YtgUgr;l$YgA!-1vZ@pRC-p&IdevJM!Ks5bRrax{A z@j!=>r~%F$APXQ;&WD2!2H;WJfchJ!xl6gqREi~Hg{+mJW> zc!2rE^rnR(77A|(T^W8x!o+HNbKk{IEw5jI*xoX>qMBo8dFz~znp zTzCYO4HA!nSRa+SLuep&Li`lYkH=FUc;JBoBnbWmRI$Ro_)4x^00000NkvXXu0mjf DS?UBG literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/dialog.png b/data/skins/cartoon-coal/dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..760fb7e3ab99cdecb7cc7bb38305142bc233ecae GIT binary patch literal 5764 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/down_arrow.png b/data/skins/cartoon-coal/down_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..be54a4a9cb6f80d6b33cf1977b566b06bd2a1022 GIT binary patch literal 3247 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 urr2GAHc%2C9Oq0!lvI6;>1s;*b z3=Dh+K$tP>S|=w^P@=>&q9iy!t)x7$D3zfgF*C13FE6!3!9>qM&+Jc6@_nG1)1EGl zAr*0NPb&iT3bY*f{eO9MWFX6|H!2=^X=(rFWk{WEHJQboX(E0pLvP8&7>~s}C%6?W k_C9kOOcEJsX?ErMTFsG8C02i8fZk&8boFyt=akR{06PPE>Hq)$ literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/generic.png b/data/skins/cartoon-coal/generic.png new file mode 100644 index 0000000000000000000000000000000000000000..d871314e18d7f98637ed9456aeb9ba227cd5723b GIT binary patch literal 3658 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 Tqo+tG?Uw~2Bcj==aBjhWm@ynV literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/left_arrow.png b/data/skins/cartoon-coal/left_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..7229ff9965ef63f7754d439e878fbf712952043a GIT binary patch literal 4948 zcmW+)c{o(>7awD631OrxV`(g7ttfr1!wd%5DNFVtwAe-l$(Sfc_MI5X8d(yh#x862 zY?17SQpT3u@B01m-uHQ*d+vEYpL0IXx#vAmCPun!XZX&5Kp-|f4B8CX38#yh5qP$$ zJM{n?ou8Sm7O1>WUiJmM%CnJ6mwXXW#|{i0oG(PJ434z|V_Rs>H*{LK zh3k<4n0}L>f7HRJoY-);7+HbmTv4!DYJ!|q>0hyx;kULQzW@30nd6&JcD~M#Ex7WS z2y5aNwyPv{44FQON!Gx03k9tV72NYzM-MrS1?k)PvvCYa(O|h};!6+JegEm~DZ}Kn zf68Q(&i}%#<;8x!cYo+^rkp*c)539{E-tx6szFCzP-Zc95MM2Gl9d?x>y!Uxr>WgR zgSvw4)mzIqSuZFI{a8O4|$1V#x$Oqop@aw|p$zb=WsXuS0 zOU_bF0~e$kE2aXn%Xaw?zJ+DSJTX5<{cWjH5uL+ty?!>#T0g;qEnp9z6?F}bPz{SS z9TD<9*sG1BH!RJ#fH&tQg#;ZZtd2m|2ba5UYZKB64*#wO3F&psu$Ww2kjlw3%2wTR zM1+JdXmZZ{`}CwVe_CEeFF`?gTf?N9AoEJJ1nicw0xu+gYKG3YNKm0T|%VJ`KO_47x z%F|6Y7P%XE@7^zYMP(lUrlWs9g;bBWhBZ%)kLZtL*F9+fUbeEij9&-(G=DR`u<4t1 zhd;X(Re1dwIbZ^+2fwSEr|SHkwzs#hdoDL~=WZta+Bis<Qg-K}o5NYSiAfU1jJ>^O3#sfmpf4h~ zX%nQJr9FP!u|bzql)35i;^UH{oHMY%17{XRkI-sj#5HwFdf+ zSpFZcf2ypln+zHG7YIRfiFuLowchBb5=|-1Hfr7dZ>ha$lcBfAfDnA8-5V=sbL-7? z?Q7hfW4*NaOoE{D-Aau|Ee7g)tJB%KIzVn!#-4J+s?OK-viA(qWv$4Ve0|h`1rPoh zb`XvY-h$@#CN4J0zAB!_3F*GLz*%NpEpAomNT(L;mLoCL=sl~o8@18OoqO4Pc_J?s z>J_wwt@$~;$IlnFlkNTQM?e;7`r6nXm%gZV(}p=lKYIioyr9d!*t0n7sb)xWp<@Ey zc-wxKPf^mU#?#XKXUIQ>eZeKZgeP@FlpA<34qZN1&7;=!`rU2-d>F_<@z42SHIuMo+&B|UizBR zCMkpm-_iNM!#ZkkL0N!U^&XJbujx)CWu+fDbNu4F4b#UZ=W(Pk38YGC+T4MG)9b~J zu~h*dsa3}nV^tb@eRn>NpTkiz-`KSxnN|5qZYek6ua|EyNjX12xdEkr5G58DM^#Fp=E(7!+S-w=Le4gx%{hRG)dKV~t%^Qn7h6p8INi{^m z6A_#?*fH;8u z{>NAE28s%HKfwF61@|{Q*F45NsZ@71#pV=N7-%g;1G6EB`0d5DoX36?*su2QWy$gfrtXRbqS2LNH}Hbgw8a)& z5!+BwH&IvYamkQZX! zV%}vwd_(6UL8u8z24tw%m-0E(c>ZakJNHATNpir!+K1(uAje^fr>Qzdf$qCiJyhwY z<^+fTAye0dDDLqPfY%0Hg!z=7OD6C0_gsV%{;KYi%;YT&!Rn*#l2h7$D4Tuk+Szx; zF&b|HUPC&dL%-T$l%T`BiNNKpSORCP@>AKA{iq^S2p)RJMM$ylytz?YFaiqpJ#-e#v!R%5)xd1 z=3*Jp*&_|;b}v>W5$%)CF4Fs)a}oszh6Sp3of-@=H=QK)u8D1;N>5VTShkjde|0(P z6q}-aFCc7T1f=qoS8@e&cF2y#2+bDAYG0z5!PmzQ#mQOGo~L@&69#qn+tfo({1FRk zbqB7>0sANSL#HW$n=i{?7Q?5~QKT!|2#mGYh%v^{EVh7x6ag?0d2k9qjK%SXdNZus z0sgAk{Kjoo(_(++!%3f1b9Z8jx5 zzH)ilDJ%uN(E20k*XCKfGpbeMAq$z9{;-h@Cy-Tyr@yqFZ}Ndr;7ebnx5O*Z~T zK8}WdGBa-x*)(UmKVB(<2P(+djknV2?CK|nn{p2Hpp+dD$jv@+!&aQl;b@HbbA{*LJS+FWCJtD`fIK!qX^a{1kWN_k-!v1b@0&H4 zGOn{T8Dai%O2wQm3_eU}u9s=@00N57wH)nC9>`B9sGHvx6>`U}g;LqG}*o3WuMdA&; z{aDzOZW2Akk#fReQEa~TVGEVeI_pdFR!bA=RgT+UleG_;cWLu65xm5QnI*jN|4>vZ zi2GkQ_W`e=v`Z^q@xHZ@%)iIeWuj!a=BESxOnE$nsX-zrbRMEUnq~^&$8qPN7TH~mBiZj?tdIygm=ei1erRP%Lck=p|1;+#< zl)rme=%Z^-s$&y@j=`Wy&jz!)3IXk~>N%tVamUjq$&taS^WC(IiSJ=*36GiAe7`LdgMtU z74N4yc6Yur!VDBA@OxV*xn}iwsQ9glM}XQGUD{tnP2G1MZqt{62Z9%#ALU_L+WEuL z!glwW^_sS3EL4Z?K8;h~@BDh;(h<8h!*-*hO)F6X>9p?3InS04@9r#y^w;XxQKLdXR>Iw@KS?rNCqc;= zC-Q1KqPc`4Vb0V-DDTN_Jzl^M>A4uOmkYyd?WQiyHN(cJABBT`33~cCBoZHCCJTfF z$Nmw4Wf7N)pX=h16iY&w=&P6eIX{(NMPZ!~yywu3Ju5!f%GV)Of$=P7N|+-NT?k<* zjV9lldNo*wNB^2=kKtF@5_$Bf@s$K}x#gTNw2+=cH%tc$GrMZnwRLHZ?WO(`(~!vQ z4DldvGUF5+^=yE@@{_yG@M25c>f@q^WqvftHyoyCR+1G5xpQ%sAQI{PQQKj*w|q7QB@wZ?2fBst2II_>PRrcs&A9tqB+I)6kaN1c!U`$I-( zlCFeA#?N>Tqk&6H^Yo3+pD+aXNMVMYF&Z7`e0*PawCC>AhsME_$ z)^j9?5{7`SjHf345}U-m)p>1Bi$uoHCCG{;iQDU)Mr6^kQ#jq#O-0syLC3*|*102M zruy#ancS&v7ai+?nj#$b@On$P=x~c(@5-cqHk0ip-@cWfIJ+aabV#IP)~7B0ATXT1 z4t;qMi&&#zyl=sGt;VP*_;qj6`h6i$fBLHsXX0a4y&O;%lHW`CiceVbBh5N>#H9l4 zBLxQuC);2dz^nlK4uZIH6$RWPVZwA;v|`I{2{}i@Sp&OCaWfOuys@S_j)Zha>cFdn z|GRp+4RPzqZ2!HQ7h57IF#5hycX=NE+dT3MZN9^hCqZ}aD$jx(ARjpIlsk%1WHPhd zkEDx(&9VhaF8WEqCe+c;z8+a?r*H^>OQ&2(SPr=k#=)u*QsxFV1>sXCx^} z0u4PDEGGO6WX5GpoG2FkVvfv9zDbM3RTYQ00Wc%P!nPq>e8T6NpmDgb3UTa_quUs_M6Z(|pZ^>6FPbwA21Xb3w-7JHG0Ag!JT%7lxgk0=cQ-FMI_ZpRSIkgvD}% z!y{#3E7d}7S2H-!lEwt+s~9B$gpUS^C*TRoB7c%~iwAwC6yl~w?*;^d^LYV9tgVrBVbP&jxfTI($xw=l29S+P-@CY+3qll)C{naE6i?&(EKvUDTL}!Z#xE3Q;3+4mN z?6t_)2b;MQBQnj~C<5hlu2bI`!zK)tpQ{yfxft3Gi25U1iprH3)laH1`_KU%|KuGfm$lJ&dk(n$v2Ta01dfG?4JBA^2#Lv=Q`K(oOAB`KF{+z@x8(55-H^cmvY@*IZJyTWfJA%}81iqe4=qV6sFEBwzkW)42zgZ|Q;@+#&6J6>3 z(gk7v@st!i<7^ZLbYV?rp}38v5RF*o-Io8_*A4cx!CziQCp-o6()VxWZxNE^sa5nuNHa<;WCQDuiz@7n+V%sQ=`@7QG+S;_0qw`#%)z*%D&mWl9Z+!7*s7txq)L@}$Qo_b!}Se<7jpl({cV2fsrdYaT81P4{sd zAN`xagIs`x9zN*ZVBXa`DswFfrMdm6xWjZX6%#WwJj@Xk6!iGcRaRMSpRlP$y})dl zXSdZzxb2vhY@p;S@^9+_nXl5ZoeXtM&GnmMFu#P14_7v@#5DX~E;_~SB(M&$JkHF@Bf}Q5IeAIS_JhRo>MG06U%#&MuDpoj z=@{yWs<&vXT9zJq8g-MX`QDpGM}4!YYanvCrT>NOSXSgTgPh8^4djrLOxACvE(L#W ze%r-6Sn2+iiAUCfO~$?`qM~67=Y2 zq%AXVR#||ue}UYMHa99)^YK9n!QGWB_|@iI))lKbe)W)?69+OpeGDvP*W@%x#dNY3 zUiV+JurMIL6wu5#RmGp#!N0X}j=s0|mc%?4pHl&G&OBfIAu=q>Ad8)q5OO5epM5m0 z&t|_&-?3*sz1aBhx0lyp2?l#EDnH#8jEN`(ZRzBvyUw;f(v<4+{OB-^6H^{NK)q% z3x)xAg-s)^zdcVm&FR57G~^3D>dZu-Z(({M?*fgI-s-#e9eos-o9rZ?-kR$l1VGYjSI$xC9sE8b|A zC<^I)m7+GkJHO83xT`UQ`7;d;TJmdkw zar#}wq;M@$&G&un12Kiqib(dMzg>@ZB-X@)Wj!5ud5r)J^K;vZzm)q=O9IL7=IDPF zG=@=Ti8he!ti{sT7W5rUxMB6L)6F7F_v*@mqJ6K*FlhLD9`7W_UYGUeQ(F-F1FESP z*fvSa?`D70A2ZrypRJK_+_}Fb?bt?Gu4GdB>dm#Slh0r-w}zTzV{mmGrO3LBHOyLe zd{=JJuKq{pm6L254av47Alh#rv;DRxRp*OF^n&$BEj3)395#n7GQF&Kw72=ILTphIMv{zYZ%FiVT}+I_HRz18E-ef^Da)|#d{h3i zB2!D+(8#ch$LDsI4i1`<8ev8;0)M(gqtz|{Z@hhOlwv8Q{XVqs$ecxpEPGyZOwD8| zIy#?NXn63^l!Ic1B5>td z(tXOo1oWcaNb}z4y?E(+4OvnP-QOh6Wo89oPdsRO5uEi%aYt~p`THODJ`A+KJ&iN*_?c`S})%g)x7*% zd5yHFh#z{bn%Ds9qhAEW0QafVprHb$LnCVVXTV|j2Ce7h#er1-#bR{9LMp%ctb%0K zAB27(qv%a_(oxH~efpIXy8Ygs*wZ^yg3;~Vn&ao^FAM%DhCX4Lz>s0Yq?X3t>Re%q zTTG??o0F;v&uu_W%6(|Db?NTQgl^8!weo59C^6 zchlPYGdrffUgiBvXCC|ddt43SR{O3W7pF!!1sby)7j?YPAlvqLwvbop?LmQd47n^; z_hOOA-6qN5cb|(!0_)n*;9?ZiZ^;nbCWxWvAw`RI9acY$?A;oB{{I)4{nz^Nx^bpz44k0inS z`+uhV>gZqa>)r=x=nBX`*5^Trf+o15a%95e`$du=E(+tyZ-Gy=?K<_JFn}n# z3+JTWY@Ad|VFm+~NkpzzXOgeyS>I`CV4IUF{#NX&a4ty1FmUIir&xAR9XJmKptb@< z3Qr8u$HgLUeQK)QIq0#3t4ylj(t9YNNneUgOkcQOYeNrB+G8w95i=aYDXYAtm`v=c zg-9}UTozCdk;+kUH|^~a?1Wx+3xL17#Nea})GznAPnQ~o-BCL&19v%EX&B?{CXvRy z(0g9@F2SJMLRpsg-znx<04_#C;fxvIs~{MZ%u({QE8>5C9BQRXF`Evu*R&Y+8B*S6 zRk*7TwQr2L+Ob}*2hjNE!eaF`K$K3K)UzQ&ZjTHp#bo%lcG#AaT*&%(X6d|?uc%@R z082&Yo!o&7j|W+Ni3p0kJ9Y)}{eC`6Ur$w4m6(!*e$B(TFt*?XOmYWnA%r0xzj%r>$m;K5Z9nW4gKUHcGc>P z>g7jAN2AZh&GHsu1Rajm){J?Ebhej>9Qit&FuL&R0DEE9$w&QvOnf!zz}Ru8qurIn z<a@WBG1q_&?(lvlvS1IbbZ2XZp4-BgUQPRZC+icb(X()45qxd1L+$w{wzW zooLpNq_;7}<>z=8;M^q z2q@1qy9ANLwxCEq5Uqpwu17mSc96N|*r9O`Uu`HhmF#fxPK`7NQr_Mb6mif! zbNH;3NdQQ)!m&elFZ6KSz0ee}@iBMOQz>VQ(e%5@J4kJ&XAuuFxWgow5UU@;oS=aMcA^z8gxtXw6n3VQ>#v7 zC=8a4_>kN*cKs0~+($ZCa_-cIL+F*3o}S#uZyK?mon)1k7Q>GogxK{=y#S>0ar!fS ziovdMzE+f)qyT&A)DUZ7!}OvvxMPG}*AICBBV%9OBfNiLJIHuTqpsA2^n~5+T%n^* zoK8)tOTCoGyguY(n9DJg!YBoMPfeuVWa9T2Eqt6%*p(AsX_((~4$nO+j+=NA5y+Lc zeB*KCi}T3y5#op&@KNaR;rNM&JM$`mWQ=!s1~f+DBHy8Y>SyvGmCUEvUEES^6b|Y} z0|~&=`Np8Aw#wZuoUo6eNT~~zT68In2f2?0%e53B?U1U6aouBG1F;VAI(x!(U2og9 zo#4H!LJ>9j9oZShzft@T41(JXma;O#O@+A|AQ{z753b z3LWDJu>);m9dAtk#h7JljZduR#$qNVSp;{8-!M9n2N?nlr?dI+`KduV7}^z$ zFBqu}q~I*;>@OyF(vadF3)PwQNzB546krt2Z#A-#k*~N3- z2OH9#WoIa=aHk#7;0o51$mI!HkO9LKMk1p@kSPUsAp9}rO58LjFrR#~0fkfyuM^*^Usv3^9jq5GZp4N3`rKQ*iG_!- z=TzvY0T!vI(qBpq_s%)F*W;#yF$ zf1I9tLcN++@f!3Q{@Z^_)JrR(!E<^L8gW@<5%-PA&o4NGH(f*gsy=x)tCDh|64H}OXk zN!P{F$-6WVV%XS^nq6md0HgxLJ}?SRW;$d=roAzMo(TF`JxS~KBmbto0RfCqrh4yn Ho#OrnUoOoS literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/licenses.txt b/data/skins/cartoon-coal/licenses.txt new file mode 100644 index 00000000000..086c7eeaa02 --- /dev/null +++ b/data/skins/cartoon-coal/licenses.txt @@ -0,0 +1,30 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: SuperTuxKart +Upstream-Contact: + Marianne Gagnon + Jean-Manuel Clémençon +Source: https://supertuxkart.net + +Files: + glass_iconhighlight_focus.png + bubble.png +Copyright: ??? +License: CC-BY-SA 3.0 +Comment: From peach skin + +Files: + src/Inter-UI-Black.ttf +Copyright: Copyright 2018 The Inter UI project authors +License: OFL 1.1 (SIL Open Font License, Version 1.1) +Comment: Specifically using version 2.5 of the font, later versions have a different look + +Files: + src/NotoSans* +Copyright: Copyright 2015-2016 Google Inc. All Rights Reserved. +License: This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software. +Comment: Bold/Black versions of the language-specific fonts used in the other skins + +Files: * +Copyright: Copyright 2018-2020 LCP and QwertyChouskie +License: CC-BY-SA 4.0 +Comment: Original style, most icons, and some elements by LCP, skin finished by QwertyChouskie diff --git a/data/skins/cartoon-coal/right_arrow.png b/data/skins/cartoon-coal/right_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..48b90444dbe68a790e22ea2c09e8e649fd242eed GIT binary patch literal 4867 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/right_arrow_focus.png b/data/skins/cartoon-coal/right_arrow_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..40096b37a5b39dd8774d1b0584fd64735dadd5e8 GIT binary patch literal 4649 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 HN@xNAWFvRc literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/scrollbar_bg.png b/data/skins/cartoon-coal/scrollbar_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..6e97588361eed48d9e9745fdfe3e7359f3e4ecf2 GIT binary patch literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^3P3Et!3HGD8EPYe6k~CayA#8@b22Z19F}xPUq=Rp zjs4tz5?O(K&H|6fVg?4j!ywFfJby(BP*9@8HKHUqKdq!Zu_%?HATcwqL@zJ3M8QPQ zK+o(?Px5`Bnru%O#}E(ionvvfX3F{XlGPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0wqaAK~zXf?UcQb z5>XVzFCUxm5d(w(g^3XpvjtfRNK8x!*kH2-;iI#KSgi#CIxVy_Ru(p93lj?ywepWJ zv7xY&7^tXr0~A02VLa!}yadtN>?(G9l3(WDGn0Ggz58b5QkT+lf#+ak!I<98^b8nV z(A$abf*-(eyWNJ%<;2{H#$0PN6T^tUF7=|I)Y*u-e_{^ah{w}))L2wKlOq$K6 zc)ebkOePWx24%foOSxR;EsD>)24R(L$?mAV0cwExd|nELg3M+!8IQ-R5gTwNT+v`K z;A5P_b?|}7rvB960eH+H6bebJ)sn?xA;aO2mXgosQ(iP0m2S5y^ZA@M2h#;#nP_cq z(N*x$3`G^^+m1&3wtf|ha}K3a$#Rrlfoo=HYI6nL%Xi=wlVY(b>2zAXIk#h5+#bK* zFU#dpZCk(Jr_IS9fVWJj%?3x{5rbGPCbe2k?KxLqC*6b%dcB@Zr&HQIx+mZZ6Ww4R zya#(s+U>R~d{%KS-6Rr;NT<`WT)786f>Yh#6JTelR;v<^$In$<%jtAVAP`V7R|4@x zZ-ZkFnbTKCl3SBXrDU~QF};xRpORcIr-pBdHPt82p=|zNb_r{%)AQLfb_r`@LZ!lvI6;>1s;*b3=DjSL74G){)!Z!V4kOoV@QPi+i4d$8w_|{7Js%3a67S}jPIOaA4#rP(H=7VQ=4~!0%tS&iTVRQFvO7kHd;1PZWVRGkCiC KxvX0#LT=By}Z;C1rt33 zJ+nVO$@hV3?t8j8hE&A8oqdq^kOL3P`(jN6(WOo+M4~vhJz>9;$K1!BX~!Kg>*xKh z^MZSt@(cJCV=r6Yy>4A#Kg(g)`t$b6l?o2?&H;;42_;lD teC%J=mU!IrLrK}6$1e|_e}4TV^WuMu6Ak|r$O65};OXk;vd$@?2>>@AfH?pF literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/select.png b/data/skins/cartoon-coal/select.png new file mode 100644 index 0000000000000000000000000000000000000000..6fd5a98d927c06ce51a99cec2b30c921db30f8fc GIT binary patch literal 175 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/spinner_down.png b/data/skins/cartoon-coal/spinner_down.png new file mode 100644 index 0000000000000000000000000000000000000000..6cee4dd4c91e976f27383798e78f754b68e64f58 GIT binary patch literal 4120 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/spinner_fill.png b/data/skins/cartoon-coal/spinner_fill.png new file mode 100644 index 0000000000000000000000000000000000000000..4a208f64969bd8a63088370d3c41508f5cb50c6a GIT binary patch literal 200 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/stkskin.xml b/data/skins/cartoon-coal/stkskin.xml new file mode 100644 index 00000000000..c34ca63210b --- /dev/null +++ b/data/skins/cartoon-coal/stkskin.xml @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/skins/cartoon-coal/tab.png b/data/skins/cartoon-coal/tab.png new file mode 100644 index 0000000000000000000000000000000000000000..0c5ce0280d303f272c82fdda4d76f9abdf101f1b GIT binary patch literal 4835 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/tab_vert.png b/data/skins/cartoon-coal/tab_vert.png new file mode 100644 index 0000000000000000000000000000000000000000..593c80263ec472b92169e8c9d2f659ecac4aa000 GIT binary patch literal 5195 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 vy3Ec%}CQ!mhl)D zF1*Q^@c)WwWcy!uRP_G@^Tw6C_yX*WRg*EHZhojrfuhE)nqu-GD)O6i#P?L0m8_Cu zw5Zs^3$VaTO^$@R5{C*I%C2QSjB>+u>awCzUbX4)SQh2nykCp@BbPX>e0JNk^fMZ& zhd%v^wB5tZ z037n^F#wa;MlN0v2*_t7Wn~|9qsHrBx`aBv(Yn(VHGYWQ0}h-S{p&7KOHDE>-Zo3z zD0916w%L$F8U15plCGI-MVUK}+uPfVLVlB-mL6u`Xd(*ewjo%?{5=1;&AC&Fd-ecf zj3Z2%23Dp!HI-E4!LyLrJ~?1Vn&~Ub_T}%`C9m8prlz_&tApflf9247Z>SW0V5PPs)b>1VV*t(i2$OY*PevQgLFDz_YZg62t)0O#ee0g?w2l7=_@t#-{55=Rk^OkYUFlZ%CU(LyegrIciQnPPSqWilpV*W@!8d<-Xb98Ieh`kSX-r8 z#Qg=9RfK^mYDs{$Gs<8lyy7UY-8NfoP8sS}Fu?S4nC0jUY8~k6?iNzcvN#&K*mCmy ziPuo}GycWfgvanheLzgt$cXrtOvu)r^v1?hsEEx6$rp#+&o;g^PC3AmkUSG8eTf=X z>!oFkkcr#-RPj*Z4VbhBDT73FUoQR6C2SO-%)^NbHf8AOyGoS3gMU2fKk^n@_8#3@ zIk-NPkI(90cG_&EV5+=DK}=QfeNJx(WvoF9<_D?!S!M842s6(EVk{$> zYFQ0SWBDu2ZoS%TbaZ9L+D4q;$)t)GER7>?%%~53xX*j{NC4$zRPF(}PN0lsh>Z766i+MY<8R^>V4C)W& zQ3QT%t#oqd-u~_Nb?uiXA`IHS-~n3Q6VPS?RP>hj^Bu?L-TCGP^wqG8-o*vEvXJR7 zm%q2AUis0TPlqGQPsErDgJqwu`FgGw105?pF9yz6{q1_~0^$TVhy7e3-yj6b|Eb@D z+*=I!kO8I);#=lsl_l7lN%>_;kV)yommgA{$K87oAC__8*wEo&o!@2@La546qALva zU9aIwYe>(Hn95Xinr7XNf0f*867X9I!Nf9dcAj15q!pN-Dj5=9P(8uGGw2AYNIRA*FDHpl`T37&8?^8Zr6la;P>)Cn^f>7=+uLLPQ1`pe9wlMl7 z+jWpPnT{1zAwtUW-+U3lMuN})&3UeRZcdVRK~_Wnq`AqxbnOrp>FP6{ey9c{;WvG- zrQ5!U2CJpfH&FR+yIvnZPHK_|M`aP)=%xntew3xMZYry&4~{kxf_A*5ijv+vf`P`F zmMdr#<7I5bD5ik(huxAr@Zr LbD>o4@}2(!c^!yO literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/tab_vert_focus.png b/data/skins/cartoon-coal/tab_vert_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..61bdbdbdf16c16baf182796dcb0a506bda393ee6 GIT binary patch literal 4971 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 WKVtv0kLma%kXlbyKbLh*2~7aNK|MkM literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/textbubble.png b/data/skins/cartoon-coal/textbubble.png new file mode 100644 index 0000000000000000000000000000000000000000..fb805bd24d6ade7a99a21c1433c5e7ab33b5c03d GIT binary patch literal 420 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucL5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt33 zJ+nVO$@hVVih8;@hE&A8oxPFwkb?k=y;6bXx+9XDM*}!RxO5xzooDGj_&Gaa($s6u z=iZRJ{(G&d;TsnoYr(^Q1`>~pK3P=GuMu0g?aDIlZ%Pu6D<{cqV)B3EYH;lJ@(oh@ zZ(JvIpKjR8;gqSmLEKRz_x87&-~X;(QSKKF;$CI$fBZxH)!fTsZ(IeuxB?oO9!;DX z*uW&xAj|qqi9?lD!-4VRi8DZw>p&ka@A<`dI}+8CZgfg~duX+q9?Qd0R|$2r>mdKI;Vst0HZjZTmS$7 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/textbubble2.png b/data/skins/cartoon-coal/textbubble2.png new file mode 100644 index 0000000000000000000000000000000000000000..9c9fcb1741779a5e8a40075e75a76b05b95b0ea7 GIT binary patch literal 420 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucL5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt33 zJ+nVO$@hVVih8;@hE&A8oxPFwkb?k=y&>xkrF0b$XVn1BEe!j3GPgB6&u{V!i<)1a zR2}nv`?Vt*gbm-g@K_&A=sA7z@srw5kuA4^X6xPPPUv~=S#^TTW~2B)iS_djW$oD@ z?x?57{7s2t>C^*pEDN{f-cG;&egC3+mbnLk+z@`7zQ^lVl>0>k)oExtFmiRcr@1k5 z1u&F}+~`)ABC>#i^@y_ZVg^OU zAjx&0kEvR)WfGIff`*EeG?3;5_r|>(PM$y$9c+w@L7F!#2D#%(oWt+_rQsmum%I}6 wnd)bLT)y(&{Nn{1`ISV`@iy0XB4ude`@%$AjKtYKT*NBqf{Irtt#G+J&g2c?c61}|C5(N`I z13j}pJ<0chYUX&lIEG|6zn!^}_pkvE%heOi8A`qq{;$?Nn9#t@{6}r+7xf3Trn^2^ zZxTI6`3KAW2WE=9)1JS%cg~^qi9=cbb?pM>-KV+LQ(n06R=@u)k*vLG@++w;2J&Yt zw<}q%T<6Fu*ucPYLQ%V!fkk1#mzoudOacuImMN(~l4Z&~ep43)CIN-^H9SoJ1QY%T oU*VCoI+%5)&N6F{T>f$XYzJw-wD|Y=KzA~Dy85}Sb4q9e0KxWVs{jB1 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-coal/up_arrow.png b/data/skins/cartoon-coal/up_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..14a3fdcb94eec4c3f237ba830713c6ae3d56ef81 GIT binary patch literal 3199 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

&spBG$nWG08lpeeKA4r_8Zc z2u?P*+=T?%e01JbUe{=?rOaU2Yuk%R-_vqKk0*9r8QrxCs;Ft(^u@I#0>gNwD)}eH z94LZtW(Bjm-(mT(xGRwkxp$JS&fdCB&lm$OL@4JMZr*>5^)~Yr*I|+GEZW`8)qhdJ zdx-_Pe(Ock;GWb{m7sffot96J1Dlz?(L8vo%QgX(&8Lm3xLuzE{|XO%fDaa2pWof}FOXHkTQuda78+B6V>JN}p_)b2Gphoh&Bk1zvNNRC#;GC`rFVOA z?r%Ei$&PRl2N6V$izqI3_<(jpZ_6O?j5paBTGUCxMua6q~=#bqYm0qG|$Gm9-rjZvm zgUVy*?#p}|?mI!Vj!yj_@xY*M`s)h{X-|OO-dQSLZ{p;~RXFs90|fMnhX9rs9`Py9 z7*{<7L}hnXwYNRFQrs$1%TuAhcT;{ngG}toDgj9Vf&;65)PcQhnJOF4deAE8VJFw7 zY}vx`*w+Og2;^mT7L*dbAbgjh{Y+zize1G$)#*~pqg(W7t-qIcHZ}H4qByszvF&op^gxW@0)1m+h1p>WQ5u&2fx*ow7%bUjG#^f=LJbcFmB}Y zb+K>m-wLL&${b!c(XxryeamZjhr)A+Ge>8|`G2#h)E9)dcLMueN6tYSh&7Q;zxz(S zlH;BTx5cd^)FkWbSRLkU;QyYfNYz>ajK)&p*ns9A5Vp4pz4aXdiLev4!eSb+Hk%t! zXlzO0&Q%(sne2LgLvDqaO1K|nj?r8g%WSSx9|H_nt8E|4PJWZQG#iLbL$V*9DSOR4 zbu!kr8(6C$jmC~FssyKRqHBBke3ny6M`(2_51`M=1>iXETH61j+tk@9TMODoh! zH?L`BiIq939``upSCin(LH>D*<)@P%@$&U@^2yK#XNl0t*k4V=dZ`s{!}$2YVXDu& zkG}k*o;tHpqS?>#o+wJV8@qJyjoZEH$b`)*%z2d{YM=un4W7zgLgZI-Xi|c%Ch0Pk z*0{FnB1b!O)D$?#L9q(kEzb~(OMR+Qi*H}mhjIx2#8Y*JKQtURC|O+D zZfM$n_1)w#E%Ktv*cJVTNqhYdGSj2Cbi4vAaQT+Ix}85S)^j!&pL^=_I$6$@R&rp+ zi08H25^h62W|qTv5~Z%pX^m6jo>k~*t;QMW9%TO$bQ>u>aTTotxft)*iWjSV4u zgJXC7%Y4AZg7fmmZ@M}o!K8n4w78aqW=p&do5tH`E{oOVbAXQnKIZm5R~zkHw1;|!aBs>m^$Ms^Tc^aqNv7dx3|8IB+IqUERSJDH?sv@O>Ee~&dmQoLL0nr z8{3S|=%j1F)=O05$Zw@bM=JO62Fkg7ia5322zZG+0RX_ZEC>~A@*2XV1P`tLL&_{c zzWph?lw;MeKo%?m1#do!Y6}#}kY-+_wc=a zOV_hWxy>Gy=59;&kj(@YS~M`Gs~tukkeGzr+>_@RaRq4;mDNLKc|(m`;?NP>gf?No z%t*|kDKkYYKPS}e2^$0X5vh%=u2Qy7vsh1D*-dfE+!~ONwDc025PshRlMZC=pA`P) zFcn_7nINAMfk%w!f?@p$Y@1b<)()(>Ikv-k`js5Fd!Y@tHQ@;*8l4$oN{Qg9EHIls zB%#8E53F!g9m0g&bgbx{=$m7Ozx!EV7C;0AD=A!EYy{co5;-DnK}DF*N3e9u8@A}o zr}~xLn|5Hfa6l6&D!5ryZp{Tsb-~|W)z*_qYB5O-U8-U$F>d7Z9_Uoz3$~Lq;>+hQ zcD1~GjZrrLxz5XNuJe`bK){&V=pck?4jz}oXs>#CHLBiTspTh^Id-fRu>!@hQa=<92!R*T6Zyr%8!4jOF-YP!$fFGw9J} zwfTh`czrkYafOqndtS<&lNGyEzp_yMXxbM6>SEvPS;BM$ns=hIHl3{L!=S9ra1bhx z>8q)L8e{n?U#DWC@>KE!1?lE{-Z05VFS~qh1+~N7WzULH)un&Aie#E!?dWFi{Cu2$ zhVqU}gB;1QTTr?EOg+H)77_f)Q`q>{P$tTb$a`*G{gIm!DvCSY8G=Y7c#unmbfT1# zR-14_jxYB*c`5=kz@lm&*A>R=M~k#4zzj~#2XGmuLW~@XyUUq>44~e}7++F+>3uBg zL~`?T_Rn&-`@S=Mo7|kB?37asaVFQ<@D;e#uBF&b`c&Y|jB7c_jbla*8u>|zVXzTq zr5TN&#jHSa_m3gE-kPwBMz8gBut6HJ5T3agfJ?HhwxaXG`{YnCcO2i^T*Av(>j^GkR_Qg#IHft69lW|2~LPI6fE3trXJY=RR>9;3zNF#guT z!Cnn+qNG4%C!Xrs@^d5hNNKq10QcHpLJP;Yr@5JpG%2Y?yZPjR8zcKMEw9%I3dJhq4FHP*Zz>b#L?j z@9Z294PPO>)c$|`l*?nL0r;21`&nJLM?V`xJ-^}5Mx}Aet%0RSo?sL6&-EWa1$g>J z5f@z-3(|6iV+)53pJExy$0kkT9tB(sV4l`ws9HfcJNs`1brpLLP;^4^Rtid5pZc7- z!wY;yV$3jFer5_Wkmo;}Zd<(13R40gWWsNNd_XhHLDfHjtrxy6o;k4v$;y)2=eK={ ztPXx)K(}!92Ot-IXRP$)qI4s(@zz4JG?OPFPC5N&UnG0M658z<}pj?ePq?AI7~_%vFh?d>VdTkAF%)VcR#~FO%n-yuGS?N`NsS~ zz1s;3X?8&^R%*EjS<>$tnbV`pXj--I4K8_GJ$%#4)+f=iO4jAqW=(`Sb0f#4a~5nb6uXj;y+2 zv`f8xix#FyHUKJ5{F~RscT9IqSUjLp$a2$NvqqWPFh1c>K$Z zg(a&Y$|XUp8M(I#XP7%iHQ~7nhS6UX$LOHkb8rcBdKcL7E)nh**R#CitiMEX zZY*8cRl`}SrP<@|UhqgzuoU}FmPwW(wV-Xsw|SNVrrdn~yX%+Bu~xv{3xxR!0PYUV zyraunQJNBG2Alph1hGUi$JIR|79ZMQbzuDiCp!Rd8&G7v*Cq7vyfGyzvlfBtM zy5{Zv*9>^6u;TQ}O9VIv9?`B}#dqMgF#2`@ zGJ})8WNt)_MjU8X{#8Iz32zRPIxc$h54tb#n7NzV?Q~?K=<~eY@U0AWC0F#2BNac{ zxs3tKyqMp*Ro)frZkEny>wj;`8zN;=XC4z<{1;tuBH_;+c&M%4?1Qcj(h9^+#w}<5 z{fD=P%etfvg>OKu5Sdd-iMAx0Nc?lSHS=QI(>O$m4F_ndB*>E`>p9|(#s@~~R` z7&DLCG>Rl_wWxo1ozt3g5TIQ84 z{iUB?JivSp3V8=C+?N`w@Isb?$Bnx^zk=T7iX-5dLZ72s79mq9QmA+`AE1F0ms@*B zyDjx)w?n+j?*g8tI}_4*fkBkxb{N+5a=NxyZ!V%G|8F%AK?O>T3Rlr(g@@2O@7|1e zs^dn)Zt&v+3yz^S4jn7k-12=E8>{4==11M#RM1_WLFuFG>f*173F@@)90rAx6WBCZ zyd|Y=kARFZ@+DGh^mo;vp!%1Y{fJ3XNx307vcEL&2zfy*07+on?KXV@;H%%w>>k;) zhR|RVx@`bon{>$u%X!yDhAAj_wn7_5>{d!1B+I!ELoQ*=z=4q~K^iJ!VK7S7xLBR1 z%0z_4D6Y*rDB-ytRK6z4XQ5cgJbVT$=3_{SgV8%f=!J^!06z}fT#eLXQh6_>&ETnp zhtd@)(=NNs_r{+UZxXIMj==i~4lFxGEL3y_Fmz)_8x$!ZX8R865>Q_Y~~>qAwESJ^T_ zHW{k~dK&wug>)w5PBF1VwaS?MK4p4;JLeA7^{u!E>_LQg+|Cy_yU%lNVMJgo1#hri8hfNwdWn`9S;l$;E zqNrqEGGgYJF^(wFu0@yI1{iK7_4lw(j5f0c?*Y#5nxRn`h1su6i4t*-c2&1o-AQAj z`K5WbuC@i=tC??B84}Zre)qj|N?sMoedWb;0b3%P z1%(NmQ+x<|SkM9FuQ?bi175dy9l~LLeWCrlIsCq}59C)`Tig!7m8oCDlk~*HuVmT6 zq@rk2)hfUhxY|XV4lH}{z)gLIrMdNz<h_LOZhP`as037_nLj#pCb`gV(5o|#Jm*8 z-PXA+sBPcvIZ?KFy{*`ftS~5EH_4fSxq6D@DCNyqP<(w)VF2|4z%4ODuH#=+<$5|& z9f&dZd8m_J$!9uj0&98%YWR(ycNaph4~?LEiWEp_B_VV9En@1*t(W3e!XCHQA7_U& zU4*C-GkrmG+P9Uy8Z4Rqu}&7SkCFdGdam-`qYLJLD61gsQ8tIwyyrbJ-lTUipv%(A z4ARE)o!qje3@9|_Eo%2QEoCR9tRjE#Zc`u86WQB6tKXDC`~Wvh%r6|dQx~M# zsybM^4Z+UMH8Ei#<2}VNy#Dv>%&qG}FH~~1)vjhXdBA$Xm z->BLQmPGiV>65Gi@D`*uA!GOe4f-&m<_Ye+yc9SxW_5oMd1~vbd6r|YanbZK-VwZ6 zJ{WLyp?ke{;*hC0rtzoL9;6~g@K;4OiO&oN%N8Iw`EK|p$fz<5|dkT$1z_#X6-M$Pi4dV^5OR9|DB2k4Ixts`!)9~(rr z5TjJA%`5)Q9s45C)wL628VB_oRIJ~~mF3_aSDzmc-dhr5Y3*C=D+tlE*7%C5ciaaO3Kj9!A*Ex?m=o{ar*Mup% zqT3FE#|MLDjeI`;+YX!c1Ko=6N21KE%xpy%5r%a2{9~;1bZ0jQgQ8MQ-eLZ;=SG*U zpA0~0Nf|O?0aUAXlWg29_#6R#(CuM1bA~z6uKwEDR&NG(j&29 z)UyiEB2&sY)=g0Ev?G8FBBAlo;AitUS-x{MlGk*o>){AN$2;wvlYypk@j)fy>EY5$ z-In?{^gX^O(@{A`E>{S>`E<$p!zU?Mp!7$<+Yf&479m6T&dI-9<4x-RT>ySy@9Sgj ze}3O+xfvMq;&=3789F^KcwvD1vZ%&*mGh{k#Ue-_!jD+!K_sL6i^4bNGz#yMo`k99 zAqS(iN0sUwz%Y{jpbpoX)ExU`KZh_}zuN3zC1-8PGZ4KME4nBAnU$MmI#%R)kT-{6 zAi(TKu3D*1h;)hcRsJW`dwU5RVZPF$93l<88GF;(RlJ-2sR2l*dAIyQQ55CyRS4f` z(hRs3AHTqSWIu*&^pit!3w8c`j@UNVMxxShM8_{hX8)ekiYb*o?92^k)N)?l&N>H9 z{v(zag|78R{!Izab6U>t%gJBWz<1e-WyR_;zd6bHqNE&AXG6eH!t^OL#5K*!C_s8mib)KCrUlYsij<>VNiFISSJn;vV#CcJDIC>&;OB#U z?^aiGPY=*Q`#2yBtzS}26FbTrSkmNnv&<1N(9c>G4lJ69*8OJ?hcTNnh=G=G$P$c` z$rgw+Yq|dFgn2%aO(DHkgv^(J`o~L`$^YtlGpTyB%zcvTd>sN-Xsx$!k@4xN;5fN0 z5r*@hk?LR3f}?6F@!FTCEOSjJm%V&yz){$}Ld`;Q@ec#0Q7a5eq!y8t)LTa^RdqBA z$;yzGq6Rma4Ja#MYm^IkU$mP_D*+)E_?AvySuH9ZVOr@U;$iq*+SXpKRNu5XN2Gmm*BlxV|I7bQaQi=p?Rgo?reX7Dp*0GEWoHh*ijT0P z`3R}cZM#xYl-V#gRCbG{-1<3cZ~U^f1E`5kPn0tyKBGyqp%S{J z3WRx_>50BcTOtsp9J@hOAy=CLND~m0PWHJuEejMHD+!mBc7CCG5NB0$J0qTza0akk zUV6BGQ4AOXcICR019$VMfgYBgiV`OZy9cPmEfr-NCt?x-aF}TkpCO6XM>k|aI(X9cE`sGVXT@k*|~$0ZvQS$lhAKjDbgGrNN5GJ0afLb%vSKzdSxcqQ-t7cEWF zIPs^{NhMnM{>Gz!q6(vo_&V7#<$FL-XMf$DL%!=#lfQ}w3CTK?eVXE@nFg^ zOdgR(jGpE*Sh^5~+J~F@f(_=h-g+@nnzRFe`5W7pID+aZ$YdoYw)cn#+eGg+nrzp1 z07ri&$&77e2g@9CM{HVOI*8sZdbPApr4}%18;aDv1Qr(ywqG1<>;l_ND<1M=pTi{3 zdA_H(^8OLqtNw2^WU4xg9x6HKPA1t}^TekDU;_W)WSW+Cdt)9JnuDSGm%b6DYD(~i zRep03yrXfGkp1~?GjWSF>hA6kLFdn(8}LOPIg?U*UWQ2|>|7@yUMD+0asH^li=;ta z7Mxp7;Fx)}{y`{N2(3pwJ{A9MW^nWu8&w~V5F4K_XxTOB7Ua$7g^rk3^H%))J`*<_s=1Je7cLwR*+%`$ zP#j_IEmAF>wd&HtW`kE(GMBvgBofq}M?u1?K|j7jn8@60A|BAQb*hXl>mOYxqCLTv zba4V@I>^__^uUj0z~L{n;Sy8jSw>Xzdv*OI3(l64H(6apabeC;brH=bjdy&%2H!XV z%vLV>%y_x-pcgqs5A%8Ey3=D1Fe<9;U2fIN6Cqhk4+BN-0jmJKwvW11=bZ0%pd{UH z7$BlNh#^5?x#F!*O1qWMX0Zh4jg!>Il^K`5MUhPB2_vE_Qan&DJc3Q|xj1v8$le3` zdwm>7#7k4|NOBH40pWGV-|?6{1C9lWSjqH8e7ND}NL_PmO)Hf8K|UVT(PARA8#=Xr z!suj_DhW(};=ne=Df>TNlYZJ#%Q1k?DL$uGr^)8pNThxmZ(`~e74zt_+cW{pjHT4s z(=v&4M|2o2G|+P@67A7BH5H8kvWfL25A~fnNp;0 zvU{j;kaKNXaiKVSiE!n-H}U5MbE`Hmd%bf0ClxB16(mImbeJk{RdrE=6z;6QEIFts zEde^uT&njN)!bW;XUUYCx3`cg2dWF2^!NS1%&+7B@5hWpb47XvIj~34*3wUMyqn9F zTm*dH!52h~9H0BLRs0TaYppjv|(!U+%I6d8rXEt+P zs*|sEJohEiBp>3w1%H}p9RJR3-Fh_9JYaAZkxV)Zup6ByMG73DYI@e7&A;xlsbc30 zx;F(C8Sv;}omhYw9-hr2|KMND%3s#5sAJF2u$mJJv-mlz% z={VZ;tX22_dONS}!Y?9)^o?qX5loY-7nP=QIHQ8nr^0Q-!jRro+Y=;t2=UuF{s|-7B1s56naB zip&Uw8YkBxMuGwm;CK>tUdh@0%qlrnS}E7QAN2_GKTw_xx8%tGPncAyh$_@!g#P-s zQ_vRZ#D9Sa7Oo=hagZxHeoaWF8 zFrx2)!drRW9u?tQzDJcur5{{Vpu$=Fv!~iLWs09C!qO%GY~)#sqA(+2M-C;Njh>eM zzn$cA<7!3a;`nVAqm#7i(}i`j%teeUp%+H9AJK>^Y{fL)OXt;t&UOH3&>W~Rlw6U< zmCgWyED6LKlM5NBGMEErOuwG*&EI>ss8Vkrm%m6K>00OF%yPoN0Ij-s%_G<^Teczq zt??PQo1ogb7F0T0$NW;>2^mhjd-v^pCC<9-fzr1TxpInI_08CnWh1WFe5BLM1^E=y z7IZ)}&sg2Pl|a8878l0Wd#wg(-Tb=j6I@e$_M*2g z^8xpd0OQ~)&F#7 zg2BOm^K~Y?R^6BKZ}X*JfT|)5CBta_TRJ5ThfJm7mG>Jg0|yQzm9wW96gg7(t0l@C zPh6VH%g{zNj35ERn+;et?v}DpnHp=Wm&8wI!bx0emXX4q64UXy1X5{Y$jO9pFz|Q@{8V5-rM7UYzvo@Ou zR@bm^DY1byWmb6gDhC!cm!t*f)EX@hdY9$Z?Fn9TJ!-uLT4Dphr6?1A-12~@s* z$N9C;$sw*YhADn7p;wv5pF9jwx@`??xxA%E%Lg;7Y1oSy-sy>! zTP%&_P|=X9%IfPi`uFFw{wXW|;;`DqtfyKp3C`CR=)CY+Zjfu1v=68b+r0m4v)(O| ztLWq#NiThF;v|>fO<))L(7PW5MA#kJ414RmCK^1ziMJ5oLE7$VP@7hBKfOJxX?S|b z4EHK6Ha(FPSR(D$*>j7A>gvNhOLodwf!tWks_&@ly?WkIC12dj2JEykrr$`O62)5n zWqXgXcLQ$5_^-CZaqe$=jL?2(Vj=7+6&v^8F()Wrh``0l%F)-D4c#&}pTqg578-dD zJV)Gm(n+8i;eaS?7E1*iAXO@)y{Kqyl~#&)+AT83OfFPnG{O(A^B6426@RC($Oryh z{1g_*EW{*DnTHJ%-70Shge)1DCodE!rd^{!A9^G;ntsb8TCB z5<3pyj4>LAqdK=Bg0$4Uh;s_#^o#JkOyBlqZQuj|k%MJ&=r_~`K;&5Rvt!AEH^2$^ zRcJf|2=Tp<))<<^@H%J}!(?ZrhYqNZ)kX7OZ<^@05# zbs&E?W__}nfCIbxN~kpW?Khw`j?qkx3;8G#{aZu$8vu|iMw+A^pr<7(a@>Yhy*#xs zo+(a|waPgnVc;0l0g=_o@CPxN%z0)xIirW7cQfFY%|SC_*!!@UWjiAE|1E!A!Ye`2DbUQ%)~+#!n9G7ni5t-vq3=kl@-KKMaR8F zOd38bv{{NNS_c||(Asky_idnS@hi;+fMhhE#xLwhPu&R|BUJm!l56sLS$lp`WF8UR z>fGkf#;6W|VFmydSfJc+47Nsk*%%k+f-#U*L%gOU7EVr&XkJL!wDo<#NYK(9-ZkGw zTAcIKa)AIJ(6kZqUH05^se*r~-%-wvB(aSO&o@Hn*OAMrM~4Ufz;9vsDAsR9ZU<`9qAz^RP8^`Sz`4ktMs1 zG@zKb-dnqo_o7ca^sR=1$ie*EVylwfpFeCe9%A1!?!L%7U2d@J)|^!=Yo5Tf%+#y_JfD@n~U^$rB_TYWm z&hITx$ETZe4IE3jmV~~5@V3=M(}s^4>$O9U9VZQ|0lz&Wu7Vyx+y}_xjWI;1vs+H7 z5sNMB<$Rn%m;wvrvKctRD*{TB-=c_;lDJ>{A9Z%2!YqN^rz8=y zAoz{ZB=_%kL6Kk*J?&BZSDfjE8f8yLNt{wW1_>%=@&N13k0iv;Q& zv;VTBHZ2GS!=fg~&b7{jIME9@)ih-I3Y-qPnkMR|9UI}qsvJqZP%~lx%jNAQ;g;pGi{CWD2|1C`_3F9JlCi;rZG-FF_VPP>ZCG3ng{D3G!n_xYrP<0wgNqd z&E1^KOLUynzG3NJD&Ew3&`kRoxZ~&M|HtkLdzUI?BN>o3_okz@MSudhnSO(}bvpi| z4!T&h@Qj5T(4jBoz&7!PNeXC0p*iwkLQ^;5Xo%dc^;*9tJtF}VVYZfNl_`LwTK$tl zI#66$dJNiF4IC5UmyS1S1}nFYY;xB$6QGTx2Q^fXwMx#|dWZTwyI2TQoVwFZ>_qCP z5&)UbH)b15;M$O&wdMa_y6`UejX67|DO8NcdiwY$&z^7v+Rm1Zzk6tVfj`@UtuqQS z;t1reK^|uVhsD6t4#?hUSQ?iyvWx?%x##7`&)7o=6Y+ z8Q{puR=Y zTjt`x4!vHQ*ot!aWi4b^cO-X56!5OU^WUj*bZUNXyw4JHfzxSZf0dCGrJ}*J#3Oob zl?rl8Wm*=w{*t%1X-8yqoYI6?r*+w~z~j?I^(jK`LJIPg)hoFl*mUQINub`l&9=^+ z&q&d7Bt=fQr5>MOxX+dddgW$aj}?fTSGM>WAnZDVqOvJ*?)1orlOu@Ml)E7`u-hXjNRvZ@Ln^dnm* zWIz3;E9uK;pX+?C8*@adp6D)BIj@)l6SQG)`I{2?B%TVK;?7SB42wuar~r@naycJE zOyo+wAm2jkb}8d~jM}Ec$4$iQP>U_diOiN|p3|%O!=N>8wSQ=6?d0{Oq?j>6mQPQ( zxuQs@{BGq-Gz(R#(!_Xn0NIyM9;&?XJYbga-0(!?`n7b$4>U~3CkmH(^RO5@xwe@D zlF+&E7XbO(Oi&w+6g~}x20)Ksk~tnMqrqyNvw#UTuBwm>hblA38f_|{c}-*m1DTBpL0T30{x_!>`{Lh>uxOurJM*_1r(+^McN|cegh+Y(q=FFn z8U}Lg12`iGp#Nb3_Cg7CyZ?c7qGaW7M*OC`&U)FH4kpjhW$c39aZ+w-T&Di#KezFp zs2(&DAV_4DC*Ya+f(Ez!OJr{o7AbcJGnX?Q%VO#+ImLzd+#-|`Ik%{SSv{5PMGAGg z2~t-Wr7%Hu<4hesGeu^UTm}gqo*{u|-pLqorQQ-QwKe^}nbiEXa#pZ{eg8XiondrZ zC&0%I`LUr9%x^(AxWBZ!G+a7b_1<+_EDV?WM@$c2@NBt!rW4JrEUNzPrzhBogMd~mbtyz345Ov^nD0g#BSZ8Z(NU6i!a zY0Bj13!4=Ou&0vxn`K8Ig$Ey3d~XK2lRSbxT|DI@m_C+5dqP&0gFOEsSm1380Or%2 zn#CsGfjIMK-Z%>8!=*F>zq^m38{aDY)xjCs>{+Y{KdJvWJ+pfD_QE|T1kL9_w1FE~ zpax08%M1E9h_mf|Yc=dWJ1i!aU(KzOXU30^EDErAq~&!Gillj9A7Ow_Ko)>4&0?t+ z^^`0M{0&<61&d88=s^JLNpBoGU%30ll9IxMEL>1t(Esb`yyKGE|38kncPh@b z9B2q;4lr?DQ*osRh&a-&IT6cL%u>7esx3uBaf@b%ThJUhNbOpQGfhk_XXUI+8*0|= z-oC%n?>`;~9&pZw&w+DZpZELue0Nq+5C~+$&T=qlcDmK`S38r!FeW&+1p?Y0-}2bC zt(T^aAeUCVnZ^j?_t;Z!Ny@`>DGGQWokM1Yb=_KqX-XE>__j^z`M92Oi}W+`q!}0Y zo6V24$Yx_Qs?e>kanw@Vuh(Vso!mdr8YKex8#4gN2lTavG zRjvNw%k2?n-V+NeLc|$&5Hy#zfB3;_zWspN(SY=`H@s)-3RwMRm(ZNKOFhDPv%MEg znTWQ4E4i<+VtMECUL`lq4}73_*K5qS=T893Rhoc<4q6AvQ~(rK`idILw)H~&ig9Oh zAabiKIr9}X7?f^;t_F_F%{4UA25XuwZ)5=kv z^n0tHF-mwqmsan5K>3@z#X*98OK-cHQ8;>j?rrwaVMKeo0B2PbZiGLIFg4?uJ;piC(LKtHl}e_9RYO)#$i!qEqAxTTLGY8RAB6G$fm{m z%uI4e{1uIM(>Ls^zbJ23Zm8FP4+Um3@+_+@%j-7}~dnCUzXN0F4VC#;x= z0o4@I>7kb(uX{*B*f#(-&|_M^ACRA!e^u6KJ;ng3m$lR>rR95%npO^P;YMIy`+5ex zpiPwX*`+>N(C^V1(-gn_S6v5y<e|CCGV%^5fZ(t&iAa+@<^^lV{!AW zc#PhXp{54&;ASM@wU2Lc+}iXVl_Jl<%FNI1PmGFG64kxkD zRdyMd{sA`e9yI5IMVSBa05E--#*6NtEg*--&YvGzzHBNS4SzK&Q$jzNt6oi2!a z`Pg-You~j7wN_j^t!XzC{6^GYFC<5tai`e<=mAW&oTe3usGi#ceSeKL>{2~?A^^m; z^g)R}DMD%MSx!)}?YYU**$H{UK1pHF%goj;Rlmkvz19hsklobj%k@Pn;x!;rz+y7v z){-B^UW2~)dA6|%pj4|CZEC&G8VAM%wBJZ z-G1bdsU}tr7vuJkuv(1d=v>CQ1f6DOSS; zU{9Y+8vyp~%j}5CPLb)f%CHXsS(ggDTMeqc-&oE3W=&#)PtRRBfx@rgF~S(Pm*2~= z0`tGY?dmC~MLOYs7|Sx_2)ThX+(5ag$v3`Y+;wwaRMf9N4D@HRAxni z^N>1I`p}?Z>qweMS&kgXPxbtAs30b%GdjUouDBr~x147qoHS(a7qBZ%p?;(IKSR_BY z$$4rM7@oV2TVvppH{7Q2>xK|LIeGU!{Wd0GFS+6r+X|Wb;boXsNm`q>hzD*!4v`1E z7M}-SpeE|%C*7VZ!}LhtH)mN9J5hdM;!0JLthG$2W(PceacceODGLkpGur^Ykax}{ z+?K@q%6ifbeN7{?A3i6T9(YLDOe?w-0_vXejby9KaRM4z;YAIlOL(GMY7jUYGYQ z%_*fmozl-BwA2O2)YqmvhGkJ(b>sTkQ06-t{PfKscVFoOe*`@#THnn|Js^jwp2(yLTxmu#46t$@^jfxepwNEY1*<(7- zz=|5~#D*c?-GUh&D&o5!f+vH9k}788&NK=0f-QgUJJso?8V9)DR+jBKe=`z_{E&F$ zaQBnr_)q^1SnZyR(G~ZACOc=v72p^(m1n-3K&`x}Yk01H_{+o4`U5eK>w$@_HG8J0 zXAfqKo68Ejn@7#2CtM_(!^{Z}b#tOZ&rKZh1q9uRZYE1)X`Tgdqff1TYO&y{EjbHd zT779%6?t9mqkr#MlQ9-ayg=(9qWj*01;EUdKe>n%dGmRh{r%ydP+S;j7NsLU3pukKoQ!=lPNDV2vgbo>sJ~7oVcIX#B?Uh&dy$@@dHX z*@fboz=s)Tdrj}g3S5L&4lC`(oz++`+K)j@RR#R2TK%Wm;N&soy8C`_N>=)k|G$sR zM}pYF1>H`1gLB(C1C`Iz=H-*__*<@ zkM@V!fPBl$++KOk7ETPD@ss+%YtRBpM}dp;Mjgn4y&}M=iPwZ9aZq^X&*>R_1 z5v0)Pr7jSD z-=TSGGTkd%@SO(nB*#@$- zq!T5dA8>7!y<`6HrfIYeJpJ#j9DeOVKCd5jPVE55omewHBZ#o+uO{`s?#dKRTpKR> zX#;L3iNyQL#M8Ye#M0d&d6E;+X7AVURWjL1f$z^=mGy5!@R*6vVr*oLtV7Y7#=Way zlSKu)-T_apPgP5+bk3ns@l!|4Fut&6&*Xl+4a{rSw7yWUTIG6iEkW!7eY-Kw0>8GWp_#N$T?M1}WTN27_dpuyd2od9!n6LR*JM2LO`-U%Gtyl}l$BH%`oxU`yiom2%52`rM|_}>x2+1yxKja7Uu|d} zs%&U^R4rWN;AT)QDNzY`QS5BnTSHFeA~EZs5wBFGyE6E3>;|9h3j8q7@Mt_ zD1*^_Ybu`~R{COY z>g>2BQ!@OX)_cx`Yd^EHZ6fd!*>W`^rb8oJ-T%9C{NX>*zuMp;Z5#CHzMFRl2@P>_ zp+-Y%ous~4pl;4ntda|WrAlA^765vy`*3M`*5;&#c)%55%62rZBj;;7^@?!tE76aB zgWEakRVA|M4zTz#r_?wWjqHFAykO)P|gmv1(KqAaS{ z{(D~)Bh8=}Yiuv{Ss_B4Nnq`r?Q#FpG2fV>x{kEMaP8F^Fi&24`q>e2q(n9kDT1!4 z49K4MZ+vP|(}U~2U^n<%8Qu5z#l&*pf7=&%!CCL!X`#m}^|yv5zNta7d)_Me7tR4r zNV#v!YfrR+ioA`-*#K(uLKB^Dx|lo#qxyVwLwvSBR|mDu@cb!E zakq@A|285bRiF1Hp|&<`%U*${H4}sQ^BYqPZgLJjoFPO7Raxwmusttz?=hv~&K6%- z;WlkQuD}Szt6iX35zFK1&lQN91|Wcb;Mqrjuc0Y_zPbx5?;cng{}iX#5iuhy<5TS> zpSyH33PYB+tSay||8sbI0^zp+rxnEKl#E~Zg6=hubOSdbJWO0?;#qO`K8>5_L<0b) zxR!}2m4Okvo5>3_JVwVWBV4aNNjy;l%}JY03yijq7h~oDGQ3hubv~`bC&mP5(vfV| zUtxP%kW(+TMKF`lYg4UG-ij3WA%kL=Y}P+htX-fsQORYh$PNwAY)hQIqFTEl{Vm;+ z<48>!Om~eU_pNf!O)NcM5$2fKaPhV!>k%NLPGFBxeHlh)OpEo~g@2t$Am%l`h^UyS zYCJpvDR*#~V#&uA#gFraRb2GDkxo710Bs_|PlGY9NueeRJG}htnb}DrXO9sE@;mIX ziuU$=MGI%rI=J@+^+F%nKH*|MgB%GF((4q(n7_saA4Wv53F-OYB1su+1xk=am-9RwcLbgVZx6{kb=|=p7PsXwtmUZz@w@pm#?w*h^?n0M zF5j_CrsItBJvnqUTwsx9t8}XS@qN@i=3;DZZ?eFuQt$q)Yjpt)(Z=}RcP`%NQ3j(Z zv%UPoe<0jbu3NrR{7cz-px%zW-}2#cq-s4+Q6q-^g?B%MJ_hxUqLDdyZ(12|aoSvf zn0v}l>)jWrjcm&6%Z$_$~*_I;9l zciU#4eOnkV_&Dd`zV8H3h!-RypWN7WWZyy|!E#Wd@oy5uPg)l6jST?Rg7Uff9>;9* z3BvvvmXO&C6!(7XB%o(=r9|-(NlmUlEcx0an?lV?4Rb0s>lSX{bscNF`5pFG;iOoD1Q8W| zHkEx+c}q}F88v|17FX69JAWt9#oP2z|J#}0CmLILS*MSES0;D@3iS1Lz$}jS{0Ial znSEry=$s`KYl-rS0Puyp?&O)vWwvjjrNg$e&QP&5VcMR#p%zI&`aU^Dh6+mk>;=d( zM9dD&LHfJV5Wg!HTy|eIg{z(eQhScW{FOVo@j8LH?vNWUQF91 z67MF)n$7U7A{y@MKI@LCe-uYApVh27fh_&#b8YIc{}SR;zaL>G*}hMWZk>RmH5iA? z6P2a={BD#0$@?IA#SQ9QWg8=|0fYRnLj7)~MJ} zdUw{@`J%ciXruPQ4H_oF*}-gM7^VO8>Kd_r!nJlt+#vHNDFVr}g`W&9mkPFQ*&*xp zV}<8_NaZAbFnlTQEuGJ|1~tb=apO~eEdvY>0)jBv#bqvTRH*x(Df5slQ|a!1o}cV$ zI`S!HC|b;oMeh%~d6iY7q6;`u?1MUsAz0vNupD;^nl`r2%DpXdl7bP6(>TP%;t#h( zP^FCK2h4$IODp9d6b#5_G+7D;lJnbU)jAr_Eqv@}@zxCjFQb}}`#_yf{3xEsLLNVk zJFCX3DlMRQosX$;fe@80uvM?!#PzdUyJd_Nsi14#<*#x0mntlJ#ssMW?3`P_g#r0K z=nYd7qt2T;wZnh-Tz*Sxeh`}}TdEq+%ZXzk8clLSj7KSCvy((t2QE_|eP8W>l?8D+ zcC7FJgJBE^E>kYBSE&rd*_YacQsJ3L*7jHhx3#mHAU6U4uP(+eUAX+Uz*X#n`Zz>G z=m?f)PjIC&nIfH*7r%1tAORZ-dHlQBLlANNFz>aAckWZ1rSqNcx zk}UJ@Ak{-O-hPE@Z$jZigpdkgU{L&juz|~n7|06QlO6j0#Ri97LZDm=?<=UBv_TtcCOHX4Z)9eyQ^5y{%;@A1y8-@O@lRnd#4mIZa5wPcoLHp2FeC@+CxkfqNLlmk`7~5*||PK z5?WbJ1A#ca|L-HB^-M`-suT=7H3)hH@o_2@dxTMh=2@me2&vmWSAkK5#sGW6j-ay1 zBA=vS!Vcs0jbc&u@my>K`k5LlRmA{!O*qt!>%&S8#1HJVN}cen5JC%lT!&RHl{Yp) zVsbH?bc{~M^UXd;|1YB{7SvQB3lW0<0o18K8dhVahoGToJ_O=_GZTW1a2I^e$CzkI zy%xBop$i%XoG`UrVp-fj42CI>{N-MxR-FDOQ=0gUIyfs&- zB*`mlVZd0K?9Ng}o&YEptgiGeKBPoI7(T_SuGFB=NR8m8>1u&1=^4YZ2SO;aGL(d1 zJu;yXEY!lpXBQ*NAm-(9u^t)wV*1H~Q^%|uT!{{_8a)Tb=xH35;MP z(=$VWF$O#Hm4Qyp7y|@GMr!bL;R694k3=qXUI3FCPeG&g@(PFxQ}6wgm&>KvnvTL6V3OkKSSYUHx8F zz$()kYS40ZNZ;c@cXSggj#4^2l~-3zT1DOUq$RFUzr5FyK7WvP14-zQG+ZH!w(^zV zy?GiI8?Y%eNc~#>finE4!ag`d;ypcBCJ&KLJ}+W zxW9)Zjl@}_W(r6zWckXQv(5sm)9NqlS>4bMi_B#71dQYC(XIg(Q`Fj`B1}v#XE++J zP~X+@%4sJCEMCW~Q1?l0B_6B$rX88AK5`^7`zwWkU_Qkihk!oo02a44rDbXm}JyxT(=`C4^ljQMCSxlt1MZycTFw$4qo7B#H zUZV%`6?G()sWivUQrGE~QC`j@PJeVKa6SoX-tK@%+{jB71W0~x9xa;e6@9W%i&OPVcbKkFQt*s;uC>{_I5s|oc z^Ts_9kv;#qBG31U{j1;2DBb+m>ae{t=F z`-Q_v7oYupDXq9mOy-2>CBu5YGQNJ36KQ{Qoj<6M}YsEb%|JfH%=j zZvu;oz~8t2FSg(k*i#5ak;qlI|4qXYh-aK|HByB8e<2X${3(;1)cJ%lAo3lqBY;I1 z>;ErGjS_DPgnzbH)ctnKIhQUe*|G%(JEH^h7_jZ#!AdnYk%i~N9NzTe9ez<)XcuQsI1Zs9R zIhMa zhO@k7OdAK4VogldaA8|pBRk6sGAfxG_Q51Ed11Id)`_pj3=_7j(9x+XBa82N-0*UK zm>|U!Z$qF@+HU9@3qM0bLW6t3AQ8K4Iae%l-yTJvEV zoBljlIQ>bt`@V#|zz|}xG{#t$X*K{6Q#0{J3oMocd20(U!{MN0PNg7|y_>(7EPYtZ z8ftNEr2h(W@dAamH-?SHt~Q}8{MvYk{UcG&lLw|dw?lNf%Nt+61)--;M5QH5EYmpD zu*U@Sg!xwV7TAkR;8(wcL9NgF({Kz*RA?g%mQO4m%(d^P$4SrGz+{9klD&_nB!PRr zl#z)(d>+jkCa)STIT3{Jsm&nvRe%`>;IgXGEhd0%Frb)u7`IGY+WC{><;_#UyczN4eJeNowL_vQT zs?Ho7>C-ZNG1(o7rGS7$lpo$46w$p6C_WhWAEFRyF-Z3rg;ish)uVCy7n&pTR}B%R zYuoVq`COW5ase<56{{{D^>Wf&7y7d7I>S>4F^AzKFkv6$Fl)VyQ^?zEA?m8av&^dS zb5q>b1t$FhmnEnY&d(&n*+K6C0f*pGC}xk*ZbS!Fo^lp;QCV5lIe(n8_B$7(2o-W# zH9(OsRX;29)`Jat93`#C}b#iOfQZyUr@Y1_QSFQ!GQw1&d0+gfs|jr_u*irj!X_M%H1ALCGw>b&mp~Qgn2t7-+>vquv2`BoIN1&Wx?_@;TAowKexjiiX_s^1Ocw9uD=6- zQP^Igvy0#?lLsbmp*umzljb~PbA=I4FU+~jo*&OoE?8Sb){U$!M=c_&03Gu_bks37O?VK0r z_zOFz5N5}-Q(K;!p%;0ZaEKnyNytLLuW)I?ZGe_wYj}8lb$DWZo7rCjZ@Rcb?@yjc z7+YWMcOge$*I9zWfL03rTYimc{B6?-Y`?MW^A)jaa+g*}!m{HE@L5sq7~7V6 zM8Q-h4Bpfvh$4&Q<-zKlPC(PhvNOoK@zr(+B|BHCuLaqc2_-IWgNp}NSFET`9d-`g8DTH&I1`m z-_zYxevADphuF*16mWG@D6UCcxz)%aoumBZsmH?-;|_D@DhWg7v8?7YNLfKa%s->I zxh{~aJ?_mt4=IJ%2eijdDVv%cJ>VBsCj>7xagCjz-zYtYx`12upB!mxRJYX4V$DFWPh<$D<9gTS&hK<>3DgRF$yFP(-vXM$TTd;(sgkqNl z`^q7CuJXnd1k%u)A!Y$cS>>Rt-~(8WT(m+Jg*bE$8-uB8F`EEw4Qe%C6%SKQaW$Jr zL7p%39*#YeSKy`2>D5tqNS5u7P7(@{f)Xh(j)p|~sR->?aJVv(WV)dc?JkTp;cgTX z?P(*=<~g8lK@p9LZiLT`FpH&DtGtM;n1Tbt1!4GzF*pNdT~;=MHU|YT;)N|lgMa$Z zV)BKllpRL)lEbz9q6Jwkyxd!mZU`1q?`maC{^u?(1LBuE&EMU3DzA(FXfndI-Lb9H z7K|)DRJvwDUUvDnB)Y{G>{=dNNUC`*i2hG%wG3#xCD0MlAd`GQA-&t?QwQMjb61Ar z7AKqmWr*1)#S||29yFQw5v|n0xwvD-u;UT{$UY=#Hv!rfsn>?UxS${=PU;+sR-{*^ zp#$_G)*f$W(+%sKi&aUr#J$J@*@!MR%{H%!e~PGH+F#Au&^W3^M&P1NdFyj|^F}G+ zyw{+2)5lU=2bai?xB_t@KD(5k%CAH|FR%nbc&Y+o^3WJwUPzkZ^v_|WpXnIydv0uSgR+!g&!BD5nlhLEpP0sqSTT5Z2Y65s zHfj3ws^NhO+qvIK6Vv>>yltq713CO@vXvSB5=BWn3Ek0^b=I|ry}Dyg^S^mc3vX;YvGmh*m=C?^yt(qOPF-1$@fk84v3= zj3@mYFPfZo8s$WiSJ#51k5H6?_uN$gc(!(ImT<@-x zG2Xf)$rNu{IkPv`#bJuh2vG9<$7y(cKoWI|`t*~=<4jcjR~t)3k}Se|Edy+OHT{xP zkmQxp?EQVsigPLt{}kLuRMu9zQ814ck>2WW4w*zy2Bc2xtUMZ@ZsTS`D3SoZ%%?hY z^93_nJHPZ=ByPQa=Iv_~p4c__D?2;^@aEWpTz86ZdX^9U6F(TD46$_1tgO*0XWH@d2Mt z7Ox2COH&GnRj+KcnFDtvgNreJ-ArSYrJX0&`W2LAo)Kqa(_^-uN}ajZ9kr2I2cL@? z3F}5uDVU}LPP5FJPYtba@q!9vLq*l|f;pSp`1((VC{T+t)Hk(Y(r2L{=$EVas@wDhe;N@w%RFeBhwiN&iH}fV1rs4cLE4sl1uN;KEKz4 zCJ+^VJ*bRCdGzWOCVM@L3;xdh^R(@CqgD!yfs8iKc}+yT;N!-OeYYxI?udoncVufD z#2y+8=u)sUIw3C1ksSJ`8_!};>sL8KtN;($DU~eYgH}r|nQdQ<6jZ{uL3$4YZF+WR zN{!)S2#LOk4ZBhn?L@wnowZprDezJ+=deTMPh1M0XizGLzdGAGdYsdlV2C6G$Npp& z@8#L{Shi+q#5#Nlk5uO6>WIu0-dcSQ*jQh&SSeG1`U)|V4}j0rLIb~xQIaJib98jL z2yxts_41omfp(Z2y>EVuVb4tPrA%6`R-dvs*|LMncER6*DSp(H1ADlynZ}o@B!Q>x^A%dPlZll1W&?wH zYjpBh_N)5B8FWh3&pX{_NdNmrUtk44T{nt`f5ykG=_GHauPc~s-d$I(PD~j)(AvEf zp|+BjEH4CIRvcimnXO(_*B|F!Qt7P*q?y3xp#dg+eIceuN;;TX2M{ZKDPMuN_!kPz^UqA29j%=JF&s0tsM^mTkBsh@(_(q=88=b3X%X)R@jvtpYbF$v#?Zn1lBOgTQCFvN; z{UvV3R+DJQJC}JDBcf9LO@6KVg7F4=rer~`zZcY)&69u^xZv-vSynqvn$rh2#WMhy zV{3lGu4eWSD$_hwLq7a2Y>f5>)k*8>UVn>@=-}t|P4~f-qm?g~nL2Z4WE-p+U+{ay z=bXWNzq=fcOITZz$SwQ&pfy>#_b1FHM$obFYy0HrxKuZ9JK&LWsrz~5Pq?N6i8VOm z>zgPTH8SEBa*E9W+=z$QwFrHUd;*eBS0_YRGM8~TIm_xTjlu-sNXay3m>Gy`9`rWl zOpgRMUxaYk6`!H`xG-!5R!88C9Nr&(GCkj9QrUX-q#e0QNgJnNG}$B=wt*zqgIq4V zE{&<$v(!Lo4Kp7qHy64rN$ZTe>s+I0*Mxv!7Q^#u@q~TyxG0Xo<)^!I=V4cGJybM- z{+K!6g2?^)dJWqG4(l>6TH?+|oN{k7h3Fb#vBv@=J9@-bZk=}J#Dc5&^75(EGunpy zz6Fj{?}HAz?q*E-XFp*dz{2WsFDN!M-IbnnyCP;iO2~L}H6NlM&HOEJKkWq4N-6`L zMY8KYOH7pH+eY%j!amV&IKi0#kDxoB2gT^quq~0hp|@=gvYT6^O71Y`Z5huK&;M6*tcZe48%b0#>0VC zqV#$!BXZO*efH!4U=k#?sk7~5;7>N`51$!RYh7Gf-Aa^X zU#VmM2hXIvb)Y-4W*jj7$$f8gy~aUw`;E`QO)4hbMZx>4hT&#}^rIUSztDrJbzCpA z57mCu0{w>QDGWHFY^W-**Imd${;8Fl_>&y+e3tzl924XmuqeOVG?_@_1G{`PF7f0$>$?S=e(tHX$c9NZ#l~+giJIJb+HugT) zeP(m!E7Ha!)q3%H$SRAMyf1!q>mIgU=5j1e!>vKBTyG?4_+eqy8bVnIvBvC#QO#R3 z8^#@4Y9{CVIGNG$@`d+Hmm9TOES_R`XVKCge{#vh+S%So;}V@~INOE>T)4L3?5`wa zE+Gmv2(@TX0o;^^OB`5NY7(yb37e2BgdD_+y7sQ_at%TsniL%c zBAjA-t0>iOO>G%pbgKlVGiZyavax(kxXHp~1RQdeCl&C2z zgt9`}49m!HXw6+!@5Xp%*K?U6-uApxu5l?^(fNV!POUp8X@=gke1OFU;G)sx)|jJ< zlgT$(Pc*cvHf3$D530ASf1o<%VWQX zbf6&LyW=J+m6$7il3H@@p%!Sd?#C*pIDo1cmo{EjAFJQ^Ur-NoZw%ZgDd3Nm|@I7tTsq%i^-2v!nfJ%pq0G5 zV%wsCZNj0UQcN%Mdk9|8K7E19#PP&a(Lzm7W?=Erx=D>6B2UgYwd(9hw7=M(o2E;$ zbPeadPm?Ex>ZdC~nh#S(&qW|!$9b>^H#-BPR9QE&*paYHQ1;<=`oj3JysoT6OnlDa z)7^!d-n`Cw<;el#J-%|QdFtGg+qhBi+)BWN1V|WN8!Cb#tZAf%#PCWInt(^?XAQrX za7Vi~GmDGlr;mA>4ZZZ68V23?enB!(B!Sx0>+|jqY|A)nrz0>xdc4p`*}^Jb?eZYW z28J`-uXZV8-ups>3B~A9D158q^@L^UBfGLLCvYSF5wS9T-^TSpIh>>yX1=`dV(^GZ z8qOVJptoXK$Mw9pqGG9HttH`n z2*fXQ=(j6z=((>_09Hl{y6V$(N1$Naa}+MOVJoSw5z5Nm)-riTeQ3ifQBgOLK%V-p4pZcNn}=4Y zKIPxRO4zZ^c88k~CMdlJahSJW*(dhoPqmVEW-2S!(-%(_l1krgda&+eLSeI&E>f2< zso^dofcS^meUAd@I%^W&NE!?2-SG#(gQQT5w)@bT5}PIEIoE*IvP0b{Uqg8oG5i*! zN~_l^wm3C?U@nlknJqV^6((l_9&WVg`2tQ@3(v25eFpnuJ_rA9W%nJ0T+QxHiJ-Q> z4AqGpCPyD5m>#Ti?Tb$2O96#v!=~0=3=rr9qn5U)nk&x2&czBrkgyI`5|A^H3(m>( zf!f+_(0eO6=x9GD)0=sT*nidq+!N2fgvX|E5F%oHE-l+EQZo{MbHleMwr{l0<8Gps}YbrYYCq~U1>4=40 zQK8$oxAz%ks&`C@Ti$H~aI{pzhwx)NuIS+}qDxnL(Y)xz+m)HzZWMCckyv#eH`}-( z&fPGAbso$NU(Io%yT2^BzbqppCy?y%g5@6CJZE_}Ms-#m(`p%f5`UTrZg22c+eP`IAoiHq2 zhR<`!1{jRaLvbKtvjh3 z_Kj4zRiA0onR)zc#d}3X$eV-ol|A(v31or><7p?{C8kfl@CjM(qQTkd8HV1k!`+~j zB-}pOM=6OGt?D%AxVH7-Eow~tbeYhfaf|2js)ULuYyM+xTHK!pdjtQ;GOrnI&v2!Mx;K5yK{yS#lEJ-!+NbgD3Tn@l zw|@H)0{lK*6Z%v14&B@Uxm~UqorD~C#7*T^PWQ<>4*I_TGW)I}^Ht-9D}N|Z*Y1sO zhVNAANjVH~pFlJ2%S&&|lcUcm7m_S5v3VRFD^eypnG0{$yT_U{yQIvX>4^jwQtKs_ zZb=@dNt`X*+c-{Ha8qhO^c#yF8ldVl{j*87^pcR6w&9F3dFkT3BK?h_-eXoTeofB- z?svVBDxd2Lv&QJ0bQCrkuz^Q$FQTo_vrbc$d#<6!_Ztg(=a;PpUU1e#1C- z$v*}FNu`xK(cB;%S};H*WYM}3vgfDt)yHPRkwq{u5LOkUs15P?rSi2^Nbp_=!M{AB|qPtwtVsG z192k54qHX&@lrTyhPUb2>r9kOFH`={N8NDP8Z(|^otc#ob9)=~Q%=fuuE_=y%~yYL z+(B2p;GI-yD)YZVMe^)wYKc4bED3LbZ^A(|%3IRfocY}#^tIMA!z%zwP6T&41Sc6) zE(NP}ex*l{r7?QovXJWfci}dtZ9v9=ZD2L;_dT1GGOTJ14C_()X+6kcbKe%EI=Qu~ ze_i_Fmpuq~@jH33s&-v>d-2-(lY{2+d#wXzel;{UMacPG<14hIP2GY#FsvX zloCA>5x$^>xz28$@$7@>&1++K9QS+#@yC`+`RK$RH^+&Rf#=r94mX6c5u)vz!#js) zVqZO}#Dmtf#Br#FFOc`#wzjBTQf8-bBaQLHa)bz-E#BLI4sIc>rQCc`MxE-Sw( z=~JX1Fmi(brH=Ae4fAZRhQIV(G6F;hU;$pQ}^R(p&1<`-897qo!e z3rY6`1$JU&^{A2NYxS5+X+V~YO7W@CN5b>ixHoGfUabzzX1FuiHt}mqej*bK9c!>P zN6sh38#{s$J#|n}*WI5~vTR6r6Spt>Keu)Kz}7R2W`(O5c3@tiBsA#GVD7%STgf?X zgUE$kV68+$=gw2fAZbR3#C1*S2H(IU&o@qg9)cZ%&TwQYeni5F9^A32ssqQUC{sJl z6~TJV*iSXlSe!ilIkFh=?3J)^hLCbsL)HJ~DDNO8NP2Bo0U<8sLxbPX7a*bIuM?~2 zissB1Cnz9r^7*wsuk(oCsfVhYSRT%Mn%+*+9(B zroHupX3*UxIWT*JHRIU*u5ue1b{zLmt`#XVDDZqu^bshpS_jB*MLy&7M z!_HVXMV~f3S8wO={7|=EQwyor_>rS~4051r_`<34^4bbVCv@~nG&x3Cv2okj6M6e5 zt>?KNJILaI6ZNWRS!5BBndMVJ&!YasOTYBuCCr-A;}aP=*$MxGYa95-+lQ`fxUY-s z`|~{BE=5P!H`w$Evdo)l>3z6vE2g^pjkCUchJ;z9$!6kIwBHIg$chRMJurP7%jwH2 z-CaUFSX(x+u>_PD z)wzZ_m5E2D`^DB}%y0MEfcBnybmouun^#`DOp?5fHXODpMAfNUABRsE&p22AaQjtt zBn+CPT=nSX_Lax`3Yw!D$T_zbUmwVczEwy5b^7fgb7BB`HTf>ma=(9Z2VwtYp#M{^ zF$hF5;&FG|e*#436_up#CA5Ppe%UpEg#A*xR4${fI}8-ZXtwcXBhnO|B%@RDadU1W zj%jgrd1Ja)kIZR%WsGKB`>waruvf95>V`$&eKV&C2iif8`@1ZhL6VmHJpN|8nC(3w zI~t|E`)f{(Jnl-MncfkR?nbFjhrMC8X6f7C0i@l=<-r8?Zw&GjcAv;&!ttr)gc~de zg(*kQt?E@X@vf=b9aCE()_EaeWTtP#TQ6Ue6bcx32n0+$`?&*+7{$Gu_4cP)+UyJ) zh(z1c)}3x$D3}1XZST5Nuuu^KjYb@n1KGp3M1-ZR z>UqzM%odBbe}Evur@K=33yEU9G0-6}i{qyj7Ntx0H9owb)cjtw2nsa6{9;oC-E^)K^fRB{=sY z3wA*>c(N%r^f7e(CJ3st+Tq#*gJKCDfk8v;Wf^8gL{(e$s{u=7@Cj@wS_nVF^(P1CA-AQ#MVtiZ2wry zSZv==$5~u7|Lf}4N@Gw4mH`pqL4uxE(1cXCO~_%9Hn|Pn8eNh_xuJGg(o^F-Ds6H5 z{*qQ<66}39w5>W~Qo=~;2NUiRJa`5JM z^JbR{5-dyJp6q>eR+u%NKh>#!Y5ewnLWT5gP+VFtE?RcKCt=g-b^XF|#Q+RaR;o~e zrx)!;l_M9zmCQzYPr~TSxZf_5Q={>R)1QIzB6d{!2cU!7 z%lMS|{v9wGbXI7~^MQ++MVxrP?EhX0WL2louv%=QU-GRra(;ECn$Gebcx_TB)26TT zl^PX#TFH*mN-w0{n9=T?JE~b`CezDMRs1hfN!B;?3C?uiQ;z}I>*g4Ncatja!;k5N zVmb@v$g?1+9bw9Tz>&|1M2DjObnY}G+r@v@iM&zk~G(h+*I2rXC| zrSP)^`r=0Y6>p(U)?!uuh1$R+NP_1cYjl;$d^)q8b^Fl3V5KABKwiPnTCGZM`|V$z zH5Jph_AEjAA0=u6tftJNgI_%F=p#BAZ``!lAk9)vie)mmF&{b=prkHbA<5UR3zG>ayqU zUDZ`Hj!YHvVYT1cb_ zOJmv4nQt z*3;p%N@HkT2o8oY{kpV^^m(W1DofMDw&i}<*A@+(6(C48J*J{6#mjK^Y2L~%6JiPY z^pg;k1r-+w*m{a5fl{o`e#sp;W&0j~l6`>ta&m6S@Y?W2(yaFG)#mSg^$4T2e<2Xu zOXx1}5iY&7G1iXH)gNSJD=D3lI_y^O)qtK+WlEAEriCtmo$JXNwQ$3S+i=+zwL&4W z()|+Da|k)L9AE_fZck{KIgq(xLJ9%hrV-l zmvp~m7KEjhRp^X%%X1+xtyPVJYh!d;o|R&+FKs4i(CRWs0j!(Zh5d(WXggp!?z9cU z=N$Tb;*lc>s7i1|!*zX`DVt|Bye}KOEkpBDW9jacXLO0)>g7lsE@%(maIIj*?&R1C zaH+9Dc$Ly80jY9%+DB8D%B)&Dlvejaczy-Mb2M&6t^f;gF+1uNcOv5DqT_a4oQa;Z zarl~qFZkhy_5gLzH_6ETTy73uXYN=~n3vF@Rr<~gEq(4`UddPZsZ-AgLB@khq6Z@x znp}v+&J!i*WTL538zn7zBAx$TU>)$)@DetaMskC139FFD=x~?{0~=W$>!sN%#RUo@ zDNj^`EQe^N)|FPrw}J%o9W{P#X;|pgsd^-fxPkzBXJ6Z#?vMJsS=HZT{84|#u2yy& zuJY=S^)G$ZiRh!@vWBMwkd1xwwED>JBG(#YbW&g zPmdpeHh0>NC521T-M!2xr;-!AOBm3+PX`PpH_~?@S_9}qTjvA~j&JRIaFH9@9^+4Z zxJ4m?oUNbu?Z&bu$mLv5JT#m)VIjHAv^n|ppumLqaBJY?YAUd~+xWjn#j$`E&ek(y zMIVl5ec9BS!?ea-Tg7!B&e6FWu{c3$UXEA8D-(nNX0{(*c@!(7b;^b$ zvlFt34l?oZKHC;tqIVy#CFkC{dGox+U^r&ZinI%|QPhRMnQYQ^j^_KNK=rcetJA^S zwf>p8zyWGbxA#H%tFwj4EJCh>P?v3`@uV-OrteZWM=~=rfi^2FUBjl3^R29m>G}Ni zIjw@>m3Cnzun$_7CG4F@`h}VOT6H&`XqhRHwP~OHatr{G#)Fb3*H!~0D4%*GIxO|% zJ9_j}r`1PWB`A?f+t+8;e*BffjVh~}OuU?dbm06O*usJ1rU;pfukC-Lr~BsiQ&Pxb~1kiUzem53M{&-K; z^(na(gw1LE`zPb$*W@FKV5JX(qlyNW$A7<}V-h+=-8P9NubH8}l;LR{j< z9dUf)nd^gg!*wOmX9_JhmZF%KE^YOwJNx5Q#buVFF0?!;d?lwPGoA%mAq10Qt+ky8LU_WY&H56D;wP%fR`44`#*}=cfa` zN6xU}Ar}GR#UWp%Svd{K(+Z2)$MPwYw|30)8hy<6cB^c4Ozxqh^dUMS9!N`eSG(wz zQhu%S+AL~nKhTN1QzU;$EMDxwrmFW^j$9_N=vn1r~1RfNwLZG8H*(jNuN}Q6HLK!_A2cwmcJ^s&LBSw?%o;JwW*``n#n8X&wM4E{P_9~ z!=Za(MYUnWFuISE%cJh-RZ_87fjy9G*1GuKaT+TTJ@qs_IccV~l4!q>S2|B~5^v@d zdP?;etygVd+?+4?7^GY~t3+7cLVGskIrqGW6^UYC*Nul(LBv^%Pwp9P@2-OdVYKw6oB}q&tj8KX(0-Mud#C)}4a|WXglb|e6UuOeevkMB zp|>Mmy9`e}W-*jK?XK>o#iEbO@rtx zHq8Eh`<1!0M@yC_4&|ubEC-W>%u;?#b);)+S!3T;(x!2 zdTwE!JOACEvi(RX7Q7Ueq{&7!p)uhXw}p3{2*MxUPF2YAx{(_HR8@NrG&Qdh<7f2a zx8X67b^c4S1XHh~T4{3^EI0Jo6nbf&ix5OP{OIJ7f|R(znamPoaentZ83$?Mb5OHm z^~vL@FUi`J>LuRY)5-W2$hZ#Z+`gB$dIe6cH!x1)aye=bulSwMFpZ@IK*}SLs3%R^ z)#3h5lR<5d&p2K5Nezi}eF6Q=W9=k4ZkbN*-O7y5`BvD8e~Kl{*mIIc$|tjg^jtFC zJo(B#!V&s48y3TT{XvTg+XIC)f(c|g4&vmX%Q_G8K=794Va%<+5@Y%C76g2Qv zi>2u)optj1HlPV?d>4%1w> zRHlguCBp3vT{LY1y}M8-x9c}-V@=5T(ak))F19-*GFG`F8JUQRcw6%H(#9^PS$uNN zgYWVJB&sSfFj@Guqcs}coGtfIU2rjv5qp^!2< z3n}wg_pK-N>4!TUYAqr%Qps}sZS|4u?=4wIg7$1pxX;hH+cjsZVAw9$86j-42o_)a zwzXSur%P@>_kH9|LE~#gu2~gqB>B>;$hrtDc=tr`<^G@>@qLeaU+;2pBMcB3!+2!! z&;+I(|L*8O04k}YFLhp--cc_fQ3b_cbO)YsU}`mm@4&(i@e4B${!zSC{SGEeGP&f! zaUhRM1OFmy=m2N#hp8P@r{Pa@=#EJx>nv(1t5WasAI_Bw!Azx!tN0#&*BM{zVoL8C7JBP>~vdQ7FR2Gt}Fw?1HbL-(6 z@VWyNn5j!)r$1TRt}ZgmKjY|DYO&x4dTxo7?;i(e&RSUq9U^?>?{%R=BXSH0p1Xe^ zf7FF6k!*P0WAs9no!P{hu{-FgU6Q73dcbrIoiwyBcs}T?=JA0q+BXgN00Z@1PqD1@ z-F4Wn3QHI=rd@?9JN7?_IWA%o&rZ63zaDr6RT&(yX1)~i_P*(rmqYBNeaC@`S`S*e z1wVZD$R@Yv(sEcO%k#$ixv}|I-Z3-VVk3?4<1vZ*g>}b^3DokkD7j7x(_Yaf3=oqz5lF+ zIwUw#vUaaSkaHYE_gaRe?@oxG^yh<~MEZN>o>U!;8c}@Xa=x*t!q1A}J=g)OWVNQv zw3Zd&iUasnR8Py9{UyreO~xm`sy4zaIqyu}Gp!@xoXW_gyC`l&`V%MPx2p%vk~cbQ z4)*lM-ppQXs4LObJx!h|TZ|?E(}O37kr}9P|L0Zg@{J0KoL9vgdwzQU_=lF%dZTRG z1Zv5Mb0>is~SR+}@rt)JI#fmz(E^q7?52L5ZJZn8Jrp6R#oa(j!% zKYRWhB>274^3XR8vYIFRYZDCbQSPPdt3M9O-0>(5#JHIs=;e^lm`Uahw zy_Lbc_#>X~L%cRv1BaRwwRp4S{>Hv2_&6{CxQoa>23D-Ou>)kwJdSi!lAUgk~PIeG9f022g^xeU!I@ElEv5cQg&y3q|4yWy z6}h8xJ^4E2X=U)9jnJp;CEz{>>8{4Bl0{k@vd>X_&g}76G`vd8vD+hI9clfQq!~jv z0aZEp^Ad=%2Z$al|K!Y*_K$fdQWbb3XOD!@rk?IokHJ4D(OVvu!`~?W!$f|2a12f+>R%25)e*OJnB!TK@i{8;gD0%Mnb zK;Lmu_L!t%1Or)pb6?Po>4Vt6bQ7F@>!>dd0dZ>)tn)FHewu;o<%-MP*UWq=Ty%XH z9M^0>{q}M5V?UX)$_u}m+BH7e1c7H3SRCnom7$n!!~E%IaHyMh3Z7RaijJ{UjBdRZ zp~{?;RB4vt$MF8t`^tq$m~5nClVl0M9$fVk3Z9PZ_e!N#Nl6!4#*F;Nl;W#_v2W>e z_gpvjvVG}L*$l9nA+4SqX`K5MgBxy7f-VnASL;Y#r<7E;qH{Yu8)}Co|Fd4oTpO{T zKD4Giqt3>qhhs?7Y1bWA6B7ETz8}BlA6DFLI+RgEr%9YefG_;lxSxVa6jqh~~Lf&5Yr{qxeQNo)Ew&G@GLo8Q(> zUa0wrzt>@u(RBp5eW{4yfE0N&FZb$uzJslte8;>jqGsapGgY%Upk@h&Bf3peUI5-f zNp_ri!1CE6mFouwP7LK-1zD6SwV~R-t4FA+2xHkVqo}}@01eW)r9c%$>=}`o8<{pK z!CKjE1)Vz*k2tR6ybVg|1jUay7-*JjFHNSabU$@hf}4vkC(w%tp3jR!9v4nr;tUwv{7XQ2`;pY>iR9(V_9340rHRB@r{ zmg$l;L>VETnQZ5Ir`X&Td?keayQ(I$GM|4odt@L78epMNl}^<`rLN1s0Fjq?PGbkl z^JoEJ7=wbJ8zkn!H#v!r-If8k*P>4-x|PO7cgP~XzY zeka{K?&?$R;Ih0J6`F5ex+U4lWpR|ZVXXdQO3UiAyt~Zf4&jpPE#+p2rSQ*^->YbU zaZTi#hAkrEJuOd!4#sn6c$)AwfK*9+E3wR{J|Gk9rA%6#F#V4e%+4~ z2hAo|Zn$XwP#d=Zw4B-1|8v7|>6d8Yy3*ZU3Q<0kguI)7uB&Ya{6Jf98-jI;aZ)Bq zhs5-_ncGx6DVX-!fSdUQufLrDTM8T^RxT(#p4V6!!S3B6>gmi_&jTw3zC zz)ej<9(^!9&h=wz=4+|wpp{(m;@^>|zt8l;kShp`e%>M-p_3XjU!?!|b>@&*uN^je zOq@Q+gMDJrCacyF3l?&d{#pF`=3nTN!b0)`a|CoO)JDNIYzX~zXff*ou&s|;H*WQ>T45iqi#;3N1E?c%_=NP->?XOnMfhW`mkIMkXkg6zn7ZMBkJr$i)>?qY6$EOLxeKcm z>Z2B#Z3?mcuO|R0U$3lOC{Ti(G&+LvMh_7NJ%zQ;tY%}&ga;H>l0X>Am|9IrTJf=d zjU*-FU~ub+)SAWyQB*bXX8z&s*YP3S`X{kRT3;gl`?q7}2$dpPzTK|b>-H{Ga|2t0WPu!7EesZ5Gw$n?ulNTx-dK5b%PM8Y13}KH+5i8RMsqY+ib* zOl5__4l_cOWzyffrD^z4My7rkuUchBnB(ie?XB(*+roMU8K<&^=Z|PJym#eW{94U` zQN&*SSC+&thgjx`9S%sa4pl5doU;nG$eoU-SYbZic_gv>m%{cc(kr9A(F-qMC2ZM; zd9|;cdG2u5tB0fDs82L*M zf2VduZ+sB6&2n^mbrc2L3Eg1Pr!nq993nYyI*)jwjF8%!Jo^}J@ScQsx!o9H5FlbdkGOWypQi@cg>ijv*sSHkmQdYnL|eAZ0E`GxR@MRJDa4;nNsvFYY?lcIYHdUQs(qd&gD%KLC0_ zg};V=jS~W2|9SWh{m%F-8*RMe?;>=8KL}L*>lKd8z1Rkg;UaV+_{7&~_|(lf{^`FA zZQKsMf6Q(c!~XXk4Yy+LfNsz0`5XJuzR$x?`3Rty*vF59sQ`nl(F9-Mte^QYJLqRU z{7xfatZi$_%vm_6apvB!*9h9Iq9qxY7=@E)BiwPl&4f4~s1I5|J=-sz;LtSE%ioFn z#*x6*;Ng52N}Jty8jTbQmGkw12dEJvFj@pPqV(*?A*7KGb>`Sl>s{JQ?3z4s8Pm((Z(7nD?{$LP@`o=%BVL!Mt{+eb0k9>eS^2J zb%^u(okjHEfs^PQBNSO47tGYJq=C0EoN%BNzRnxffBWX{K0229(IVX1&SLl&Jt$f= za%t4k{^sKdaN?MxFXLaGbMe%dbNMm&A7|&wnc5cWnvu(rxs;l_ahI#PO_%fPWOH~F zfke?+rw45&e;lc;D`Z*if@Z6K=+B#ve!?Yn(Tu-mBTS5rBl$YozH1}bMv}vf+jEkS z8vQMuG5UKD?)Ty<+p&j^OTuqO0PIBoy0>FopA2`~b4`~+*R@BrJG!@TQyNt~)3p>q)?EXx)ITcuH}SD?BSc8G7s_yBER zQZ2s8-#I~(LA*A56a3YTr2Dkja)xY_N0ozi&G@<3j781xgMDbTt>Y>IRJ1)Aq0?q3 z173HjwIA-+vUOdVRmYN%vRyBo>~#};vomeB?DjkY_a|{Kg0494nVMBmch4z{e8|#P zn?W0>itE*u;Mu%y)c?`{)oh+;ix)Feo~57V*XU@ic&TR~w6Af(9%@Dos-D^un(vOf zmCUtI^eRCqeKT2=-qmUn^#gk5$Th2F$hKwytIdmdv`aq4Lv6u5j$KcgDkF6)?FH{C zKPXUswK@B@#FISelDbqqJjG{0 z=|;(?bVFNJJJBkXT(7>U*UxHe$Mvck9poz>vVZkN%l%FF!~VS@#+H%7Us}t5f_-*Lt7p*^(#V!!yb(+bbE?IrfsRon?8x>`k5ATeM4_C0qA7uIE;~ zkV*1Q22lR9XhH3l{uOUf?Oi@H%guJFnZ!5IGC06{J;#2Ihxb7|>|hqpM4SM{b890Q zpD!CyUah(*kX^}uOvzi{?q}`QW{OgmkZ6YBqIu#EU9OvXp#$>5yDW8mIR{fhC1jK3Ei_otRm+eE%bzJbvMODX= z3Dh0vl9BkYf3}Y&>%4OnpBC4=ig*`ov*9LdVDo+0$@qL9qk`O~R@I81vu>ZF^uF5P zN@1uRp^xQQtRt%r9;0ex=?g#TQl|LSI|VK$^i0fuMv!^1!^mg zYm>rbZV8WmO!qSG<|o+lVf0P4YRDGaYZKS!IdIU;{I}e&JO1P~bsrElfo26AU(mq^ z*6Wpln)SEs^J@6=4?|L39S{$UxpT{<^|KJ{$=Q8Cu;tI)Ps#W2I)K*-zWCj+F&_vqN$>c1Kg^9jIu=;|p5nX9;iqqQ+7g0wCVS=yVEF+&7=xFV{F|}29KtAN zl;@`oYS}|I3VQvr3XQbq(_mgLplf@Q+C?bNjavZSFg@L zORq;I|FsOL21_a^MM1Z4`ugURB}&kga8x46KV$#F^VwYenvn!ea)Xi~xZWrKmSdHZ zvZZ?K>S4QzXCg;82YXK5Z@DgeWqgjxdL&d0xW+R~nW zxn19B7F@eKIE-3F5+2W?MUM1MU;} zoCQ|_Gf@gZ3yc>Le{Is2KHpQ;TS6k{nSjv4f zBplaToumIWc+~R-#m8@B|Fw0kmL@~#qHC>P0@Wt&wPgpr{p0aGg3Wrx0jf;2dLEr? zZTA`bcU&@N|80r-=%dT78b*Ck_9ylq_i9VW-(~-G|9W{%zen`;-{{5l2koEk!WbW| z^Z8x&U-r<;$vtf9H`zbn+kS8V--Tse{ub?jDL?jKG2#REUv+msEO{UG48F_$%Rdy# z{@v5sc|4|zJ^$)kynf66wRzYUU0T||W$?c6y=MPV`dcVo+bdt4{(~|N8yITxOx3@Y z`;h$y=x*soOE`k7ifNbE*6hFNS~b+Zr!&5KvTlpT1HQ;dlCPzYZ^F((CRHl~6^+Me zPrnGX9&7kzq2;TLW3q1WLb(+$iwBfx&`sQ1uO(J2)F=K$54^&N586#f)zh{HLkeD7 zwCrEZ)-V4TgVk%F760{vG?mba*OZ~nE1oof&?iZK!fxO7jUSTxY9PJoO#Iu&y=2h8 z=IU9m4VXkLdIib9SUv|eRxpuffTzxV7?bsfAP%qP|MeO{<_GxvbWp1XPtIRO3FCJI zDj$+_w3`Bz#G8BsZAwS09Ws&*9f>`IPgk!)eq&zr5Gq+m&yWOEd(>b#R4&%PmeA)} zeU5`(KbQcxIt|MGYZKb)tJjNmf7P|%80uX6Cc)3bH-`P+ezCJ0fUN;F{MvdAyk1AB zJhLW;3(ocVVD<3^_q?9&HHT*3k%#$d^@cIuh01yRUnFSXsPihW*9SoED+dNE3dVtf zpZ=$dmfZKbI9lFHtzQvve(y(-&j$V7r{Tx`_y5~xe=_(2>uo6US#0j-?avnkcMp<5 zORnDjGKA?%zq{MHGfSW$c@EtvroXD!X$42O2LozDB+@FdC@ooqZ~`89Hu zidp(-Iq&66ClzfR{>PF|^1IvGZ}s(zzp864VXd_lMvub|W(N_F#x{aBwpFi1)N=yX zR%WYN*g^QR_6rknt}XYB5}Qn8zn&A|wy$}>47E&BZ^y?L(c%ll#ct)^XZ@@ELw? z7Jp>ptJ9W{A4Xv5)dKZauB~P4mc+Vmcpu4D1ZoDrEo(&wJ@X$C3I=}>Fh=l24*WM? z-3RQ-a6cQljP}Pdc!l9+BkFt`^h5tzy~DrY*E6jh$94sEQ9p;5Q8qr8w1RK@^iNr2 zL#{VrQ+%amaGot$ozElj3?7x)QNH-b{<{4u-zzW9d4{amY_osu z7JAzxuX%%jgpdp^uTE*l^YK^m^=|$w?n8&4u-uxSsvq91l>%i^0a}OmtYg}L$#32M z3v`M8{U-ZA-;Mr1o-g}%FIl6f9Z0I#|F0uad=d#z1f1;O9e6#DHdDG-rk3@u+rK)n zhO&SCLc1^iJr6nDTguMzo`&Dqln0IWPrsE|?T7c?{=HUkH%mFwN!NS(7k})958b?qJ~#AB zf8KuCN1fK~KlHpk7uQZ_`>~hzx39^EEbX5LPm8esz7Ew+cWq!J=tf&zZZ3xH^U%Mo z?6dqy)aWR0M#gF*|9eMa2;}q=UJ$D$g^kR(8NXPqh}D{;K*cI#J;UYSD~Z0*2jt!Sh`*@ z+UhD|c)#Wl@H(c~2d+bJ+HtUOy$GoX@5hg{8_y*^iZ+?&An!?=8OJ9XMm#&llOfiY ztoLzby#`>r`;vE|1D?#tS9^>9)Dy2t^v*vz_1XYlcG~MF(N@YC&+k79x^YfxsC61h&2WBzH#OB)%!Bsk@a9d_Vzy{G6+SB; zvQz~XU4bN|e4MOp#?i*IzM56!lcXH66y@GZebqjs*x(Kim$cu;wP>@`;NzR0M7w)UB>vj3 zIE1hA{Omk@ihMfk177}a+(QH=BhjEP{xIcL9pC5)-|@BlJXE25c>mdM%gx&_IBbTj z!nZZw9PGT5U&@Q0hxdw9X12KguY`3*c6S-ha{O{=oA?aJ(_RDEx@#i~?R^470yVM# zmHfkUrrwB$_doYT;1YHtxkf;&0NC5f-{r3ve;s|dbOM}%=Rb}{^n7$uZPwaoiuqre&6k<$Ibr zt|jrxrF|ixHuG0O5HIV6HhGXb{h zh6hUo@lf{{k7O#uN{6cx)U9*t?n}PWaUXfm1vUK`f2DJ12|mmk;H_lmIh}td4S0!w zr)g}`bWQNmFJE*|Ej@hOKA=Xo-I4Y4OuZ7oSA4bkyz!AqM#9}X3UriRODoAsJ@H5; z0ucN3hz_|QoKqg4tIjvUq3#H(PVR6W-__Rko!9jVBf;|}@04CzS@DOSIl}uWBk!T# z!bkzqb>qKA**(p_sRyL|9yQ*Qj^HDg`=&;E+c;%bD`qVDt~L`wkSbZA3m@Y6S@2U! ztbrbAJ94rQ>Hr4u$QG0(f!Ge(WP>gq$wl2W_y`{!`^BsK0R4O>WeMtucIlO}$%9O_ z8(GhTCoNif2juUC6=maroLR|}crxj^hlGVtX)|~)-9W#1a4mHwZ3#~$EB8TCa;G-Q z=T=BvD0@O{KctKX*%innx!q{`Z|2i+(R&y6a2)5Wtg1gK8GnGs@`vg~2EDvWchoi$ zqFl}lc&d6-{XwgjKd*LxD$}gbdFUa1g}S$7sSa$L9+zzaT`1p@by(TI4=4&Ck3v>t zR`#Df#+8U;-fli?)LaAmBuID3p!5aMz+a}f>Fc65Yxg{gGWahbb3B$zwa15eN`G5R z@Jp7ZyS<(#R`y@#++TWygLm=7%J-fHrToBMYGJmQdY1irPC2D}o-6y8BI6A|>Rs)b zJmre6_WD-bQ}%DUKaeWE)PS9s>|p=efOM2cM((kkyvlEF5R|>jK(^|Kr-$qx?3X{T z^LVw?-Fd!1JEG%>-0Ju8RW~3L_w#4^Y!c#=%0H4(mX>vPoV|y72krd z1$??Lb`hymdlXjJGY06dmEEh0^u}PDRXxz#KX{g8T*rUu3ux!w7Ho@Wbt}K;{VTq{ zIac6zK;)z?3hMmzn?-xA*Ks{7w(qyD?MD7Vn(Q+_BxpaOmq(i{Z*CZgK@1V^>uG&h6bsFouxi0yqvvfG4{%m8YC`1WG4~k|_-@fGi<&SG} zb+ytM{paDGPTO(X-G|68i(a86|ND`w$F@+f5wzD|CF@;II~Z^|T2ZIclFr z+qWv<<+Jhio?7zXzIm6sEyo^zX{NpQZsk0@cs^Ww^>(=u!0MLD)qRkk?zdn5Qk}@f zXBTh&VbkX2`~JQPj!{Yb#Z~({|9Z0D-kb0R#6UZa^DlpYR61W0m+X&&01b}e%9+4k}yakK0UQ!3&Yb=(iV)2?&i zIN$kK$K*-7)Sw4&8an3pA6L9ohoUo){5$p?00RU0PW{T6>gWU%>WxQ^LO{6w&VRqm ztw&F<0s!C~wF6n8ba|bfC7$}ux8C))3ZS6AUS}`}R?y)KK7})63v^pYT1%S*7nT6p zuRu+G3beO^vvRl-GyD4t4=?kV{w zr_KYuQC#P%Q2Z5d;9hc5T9sAj(LfU)#e=r6t>g<$*GiUN`N12xS5PiM6f{{o;Mpp> zmLpdi6-q8-QK-5WU$*^qsOJiwlT%x&9R6N%3+TAVEUx<>l7nOP`!WT?z>`#+Yw36e z!BF)@13i3I64}=^WtGpkR`P)=+w}}9*!qee=c}Ab-k@wlLWEDH;iKwU&-D5R=%W0P z{TE6`kOQjt+-)}fY_u`_qtidf{!3=gD?3w;v;oib@>VzJTCg7dOC6^y9=8ADt#nI! zRMKDe50x09hZoOP3p;N1zqdV{fAM@-CY0Rk8RbLW<6PCbcq~-CT<_~pD4Kme!MIeNBqwrJEn_Iuu3U$=kv6%DogF8hb#j|Vki+S|V;UH3eAw#ug8;JJtF zzsiKFhiz~F{rRGsT9g9`J@19KM1Rl6Opn|7;;s6kk^|5WgF)5a1tqX4_^a5z6<2=M zX5Ic>tNXyUb^8bRea`-i9zB4vDMy##tJdvbg0F6#EBmkVie4?5cMQd2yB0?UdQk(p zW&eGf_H}y~k3EUQ+0}U_+7WwHUGVB&^0bfNzW?{l0kKrQ^IvfcnDMV~85vB-y5@Is z#0?b#vHu!WG8s}a+4^ghUtjMG-}}W^!)#}JSp5F8;Ab@u3SvQY>m1r|b4=xvm=f0G zNy)!Dt>}p>GnUTtImmN5zUJCbcvXDbpU>n!fiG=9VoA5K-IDdn51gri0CehmT+WN{ z@j+(Qf2)B~RyE0FxN-v9uWk2tI6B?bMmcsasN@!!C%QP>$}Qv>NSGCZk1=r z2it^mKD;ZM(zv!B>1o$ws?K9%!?)K^~^GVt^t5Fr-rZolZ*DMK%rh|@veXW#s44u za4}roY_?wx@QWZ`dG>1a#y|OAKl_ur?dW)X3G*@<`p&34{%6Bizm9}|*Y8T4lX8P4 z`m>KK$Kw3UKMtMT2__<;XzzoahTLP{GUNGeC_yCtSC5Z}w_k@izKP)OAUY_OKFx}? zuN=nyVmr2ryWz<{IEw3=?Q7wdLS4-d+7h((RnyRaOW!Ov`tT}f?;bRImSOm_oWe5w zde6gBjb|^@8Q;#RicV<}>O8c7QqW=9n6BZ&>l9wUgoWbN(iU(&->J6@F8FaS+yVN& z0$M=#{8e;LaepadAbKb-CC^nQEz;zjRN?!u7og2(JQ_Cwt*ujl-)KL+Qw;oO6lt<72RG9S+GH`?gq z`CTZ>W|SIi?6qY^Sw!&tFTAZ)1 zQ$bI=c?&N2I=&kw8+eS^FjQp zvlMLJ#*;f2r^6zAM7ZEqf)=|Cs^PAK5=q=e*yCe@f?VZq4kxo*4u~G$*?9rc`Qu2O z;?MFve>9z5=03Rqon_}Zz@>WxGmf;XrJhB>-);O^oToNAt_-MOA3Vv&C=Rd4N)?eLz<fLg9Q9KN@=A|}6Th-SukM<@u|27cb2LVnRsH}_D`dIqgocD7 zQ?DEj^xXh+!r5+;1ro|s&68>Wf+N0Rr3(VW^ux}nKm8{I((()*@lp1Vq9wS7pxD2k zNXYilo^(NJsHnNsCu#p#Lj#rq?zDgO@%V}TM*xHu&(fx{|MdN-qgihYI@6cs96C#} z{Ptn{2lh{fT1+~u-RL3B!dH4r-Ye}tEtplgFYRAlm7Qgz^_2ZPk2m~#<~P|t`(zov z$^Lnv>igLLb!Y#$x(F>~_gTMut%q%t{U?Rw|8w@A%llXMPZy*jP%^CN$S3c?UrK>S z;k~zi%lq{Y^iG}7rXTd=A^Yc7a=xCfrXMC{=hyAuus91w)ARUpADvK!Yx#;s+FWn{ zw6l6Sa?(De(A$4%*0=2+Me;4#v48g~JGsE$O;||w&uRJAr|^-f3tF46Q@2dG)i3mT zE&?NKI+Wfd+vnT%?}`>xPjTjb#Mc{}v?{-qfL}4gQ6vTi0WQ>K=OE6XL|J(DFaF6O z;aEM$;BuV#7f*>{PJ-X#pbl0v-bXC&=N)&B*dG4#8Z8z7@uzB_|ChMW#%~CGb02mV zyISA&K7vxQrHJD4cz@Xb(sQJY9*Jc%o!pQ;9=C^+lW4z)A@%qmengXJ5Es^;c(T?D zX!)e6t!C}K_)STt5%0QR%xjCMP49;V9Q&oB_FBQQfxXl{TxuDfN?W#jqpmn!&eYE$ z;V8sIV*9JR`J%<;5ud+&aXVu(hA1C}tUUHSAI*nl6qWK6*XLI< zBA$J7)1LQifzJ zzx$xm7HWsL+hoo2miz-6?H2>kiTy^$v7f5n+Z$efKki#7Ao#P5T)a)D%dy#n?*T-U zz50uIZad063(qsYGH`hjp6m8-*xtV$F8tC_;L9(=??m401E1$N;ZwBslo4q&s(SC>VVqAdnbtDPje-xG)3TPz&rY(hV z=`X_d1anZ!66#fgT3GP1H%C!sbwSJnYQx)82gLoIm)insG6W% zBV7z-JN7LLa({F{jb6VG&2a=CJ=aO4!-syU4f@V{RpI>2#r@gFi}}`_akWor+A=I| z{rU4O;v!tlUW8_abQIa1=Gv~p8FHrQSI$R}5z76=W{v=YYj6;4uVaErB+VEc4(}Up zHM%GH2TtCzC%2o!(fD3aeWBlZ^guW-L@%f_6rbL5&-h8y?W1hN zlAAU)%BuUTV=y+=xbsTG7of{Kf1T?@N~r`2f#emGOfY0WsSgS)MgccbmmwDjBO6oon< zQM2S&9n5;YiGNe}$L$`^pT}Om1W#GY_l&mILHGO@@0Qe)kvaex=W#CUl5*{5IndpS z`%5N(uJicFkWt%?Z4+14>y59vZrNykMco-sD;FPij~Ym$R<@A$Dofew=3e0&-NE&G zJGd{YWf|&k_D9>8Nh;kThms?{i)Qgss5%tSj*Z6i0#*~fA6~|_llbpNw9@;=tF};< zXS6$18^dk1>)v?pdU@oCXYEYa$V1EQM+wZ=u>j{c9h{j(-$96ps&~f1Zpj z)ukVRMzy8;$UwhD9;N?ehfmk?_|q9KD0)T5mVEoRgr1kr*}vxs?B6}?z3iV1c@g%H zjulbtpN{sg!?>@O#e;jvwvM5%16>lpSG%|$@M%@Yy8ZWc))&zfD8Ev5E4kKj)jO$Y zTf3)pfG@G+ejS-uXBiL47SIO1zPI6Czo7WXSLs{U|0JGW*?-w*Uk7{uTVNw)1MVrA zf&29T{9eo;_3Y$iCxa<4syCy+yCr zsgj#>>|d|0&g_8Bqp$qluQ=DY5%j!(0&RNF)z2~$$`)kO$(>eOC-{k{l!>`}?l`Av5$w#|+ zM9<&ebFFb6?U<{zi=P}IrnCAu$-ne__1x3Dvt`}|^{T_8=Qne_iO2B*OPP&4L#>Qf z$66%;{jq$`YXmIJaF+pO?NGnq1vPl)gY7-==J{GhP$A0+__oA?9OSAs+X+Od1BY$9J{%P_l`EQB;IQ!r4 zL#@nz{D)~zernTCc@}o>ZrX}~R@*p3~i9-7sg`nFiJ__KAAMUiDN@!p7 z-Ae~%p8)Ht;ND5AWf_)o5M=#nB!ABPll%iZ)I;OuyC{rL8lUtuw#J2C3GGv!QlP!( zvpI)V0R}_im@DyQNDRnG9>psIcC9y>)7i${F=KAdDd=&0wgt!OXlKLgH=_cK@GJ*W z`wZEBItPoYGT3HxI^l8-=<8r#zdLNt-9?zq$n5)b&+d*P%P4>2ZZJ5JZ-$~qK>^NJMJTpkiKqHSODCUbio5M5O%qNU;Am}1m4i)tvH^IMz zK>d`7p0`%DOC>Q9JLi>e4yuB2^4VrXUwuCRwrw(RvRW_v!Gl}!gb>7F8>418GIC~Cj@s$lE zUvv*0aFz{Mu#-BTZQ>7qG|}5;iKb7JD2S$&$0X82QAN+K6ox|A@xo2gV#!ws=lBceDH;y19eT`utMno4%k1Q zNK4{Tx~z?>F1`I{|CY&Q_JjOZ+P~}IdEUSg+4Iq5|7Lwl*3}L?2tDIH$b|i6>%DLP zuIxVt2b5FxU;fZ}_OI?_Y0Lfr4WN@HE8nbn-z+rcs13vkS>Lk%^dD6(d;(eW0VPv+ zJc)bNM;qs$L7p$&cZ`1N6kfHJa%p_FF&}Z$j*EV^L$(k7@;#eO7OP)W4mo(Q7Rh_eVED{aACZ2BkZzm=Hf{`}$jLpVvrA83Sh|Lb}5nPV)|C;zryU(7f~JXO9g zLEp8%a?tCOf7?pZEBW8t-e}3Xm{#4zk7#MK=@zexTojEoC9m|ASIt9~sF{5*BRz=Gso{46Gi$`8PK_z-oL{QE$*PbI3UpW{& zl>E!*{M9kkuMyyn{m?>#_W6o6`_Jq0!Nu*T1HWkX6U*|=y+4S1B5(GJDjKb4@x8i{ zw`PM;WxpQKjw5HTythqW$G&`6?h9=ty}bE0?)P>7AB5C=4>ddkE-J&`Pv@AcMF)$*I%`SDw{5Smc&7_3cEUj0MVIoU?B* z!EygQexM9dITzgrJPMv?bewNN@?Si8mf=9rMbmX7Z`ZSE%f()tFQZ!VW-EceA3uO+ zSfcn@rwKI@${Fr|GCQ3xb8j$U7LO{wlK(Pj=V~PYL!U>oUe38kIqh=T=zTg;$tC10 zBDvv@V?3*sD}mne7jz^#n2l|nF*?at4eDe9o%J&M?SnZwB_HTJ+PL`Eh&MRa!4^K{ zQMXdFJE1?O^7tKAmXM!%I1PKo5;xpFtoa2+3iBgf^^MdElG?y{zNPX%$?n ze_LOxE}p}4(do-Anw~Gdi#KId9g9Erqw9Lrr|1;wdXKudWF%?T zegY_gIE|}WF+i_$q1vGMN?JJ+v|cxXe$5&|m05BFx}{8Y?%TWWgSwV{WFn_s`nD*n zXsl+Z$V-A(e1K<4HYE=z`Bfb~E06~P;W|8LSi!a8Bk8ig4AZKtf@AWmRVsA7W)|77 zK)qJHkb`IYHZPQXz_s4~SF&5R^;OUW=`duQrtKEpk}n$7=H=(t+YZn#-k{{@-kyKw zdtRW)e{a?lYJp<~J3HjD=8tNq0@Kyby z11YDK9y%`BoL#N>@htSQP+`84@up{rS16idB&gRai#g)}QwRK*6YT^v)!-0j5S6(;BMEUXa>YGtDIQ%$hdyRlEDu1>+yno|mhkT}d z?)ouoJ>PG(hL`dq;%0EpQ*iypdhU9hRRh9KJy0#vGgxxr!8MKm=L*d<-nHu_p9LH%ij&2$9MkytS>BoD%GsN zJUg!Y;9sFuBAAfxAy04l`MdPHX8K|G$>wl*G3r>G?7tm0{>eZ2{-4}!&4{OyZyKVch3WAqBzfja+(T{^s@TS)4x@ zZug=QV!JWBST?qw#i)1nfA7VWA75$>Y9_@PX}zzn(Yf7&IREC&?A~+r4obZjLvhfI zdl%k8*?uvf`4~%%qoc-Ic(22|Y@9lyxf?#d$>%6zaJcju6!g@r|7P^(lK!ktQlgl(9aTNdV zN9TmEe8%@9P8XTHJEz0S_p0N$=%?GBt(CWSz&H3VYCyw1kU(wGQJl)qt*o3)`EH4L&?&DcjksUhu zc?VPN%}#OLe&~=?HbN4{=;>y@pX<$BolnjdJ5QSV-kmuruODb%{IX{4BYah|@Qq$w z2bTsWyaC23=l2h?TwJQ9F8Lt-<*aiJ25OGI?})CJs!rQXC#xV|?MW&;i5jb;k2IP0 z(ke+uvXbv&I-3r+>cNKyI>|yA$rFobUrB@f>K<}PpO^_B{!ZfG>}I5qbkV!E`8IE8 zPHR8%CTGu{gv|1K@*}XZR>)csVV#$xvcu2!WAhgS*gbD_5c~X*Hp?f^;$E6VkMN5^ zgfeYkdD-f#cj}a(KI&C<-jDk&#Pc?!bu9c8D;CN=jcZ=bQh)UmY-$_z#)W+v=32f< zN!!`P)5eoh*qNubojC;bGyKdCeBq50$&}ocCAcuhp7TvS4k_U6pv}~fZ7ynF3~yU9 zWVW6E)~;T$P?E2$=nZf|)3QBNue9RZI0kZK3p|-$%t9n?MN<}rl<=KBN$6Q*tND`tF%Qxgx`GcoJ~h>73cVJYwySw z@1D!#2e-Tmji4L(9DbFMAAqw`g}Nmn@9O1Py;vl9W>}vb zTKbvu=kz`4Y(%|$m4e*ZAQT<;PYd`=Ww6P7&Yzeg>z$sa%Xw@aa$5h`&X_tbl!~?rKJ6PVNw)T_OCzSztvHl zQwA&hx6c+lMGMkTi!Y=DIl)8A=q4Xb5Ajbk{fKF{G5%7&di(bzTgjI6vXt7)!bYFO zx#az6*qLNct#~xr=~o)qE_ysJUD1|?7sx52P&#VZCfn^esCi>DYvc-&h(l3!;+N6&c^0GNBz|-qf*+1*L41MPz3|f#6FN{BB zTt@<^b$p-4z4TN6Pq$8k7gT5>n`G+N69c_#mfl07HBKufG9K0@dH z-CkP-o$-}ifql?KNi{v8FMP>qoC$eH0xiy~n9tuv~Ck{xr|vOK27Rq(XO;~E=IEzKt z=v~zPF5=w#sC%?S#pZj@GY&Y3CzC%uFZGqSRxa`8ZRP}L8#^Uu(Hh?!{Ygdu{yAuy`qW#5fBzKGUs{yC;-IjlZeJ)Ji@~dPe-%wBAA<-7NReu(1 zaugr_(0ez3JUg5354S;Q|6^F;jDn`6}~Cd7y6@$PF#i z_w#(iEd1a+_P6J4CBfx9VyXx!(P=fly=^}sC{xnvtnQmXmorC8-978%KW z{e*s7{T_Mnm%ksrXk)i6nD^a0HVGf2R{M+4pWUc$=aMokPTyw6_M zfP$aYZ^^&>JfzZ6$FS+moyBk#Y5MMVP`(Lou^-+jlK-!M9x=?~!{1+Ap3H|2<1z|g z4cxtqyANN)#g9o?vfe&WFcRO)(T&EjrT z@pDF&BRj^7s0tc2(q-E^xi>l3Q0Qq<)&hFERL=o!fSI6|hI2Q36V3r@=HC*KS`N~~ zNFGOJba0&~bR^dABhemC!dS-lpEytW`gV7@RKG?@H;;4`nLf0INwKw96Ka$Y-kk_I z#}ThJ^rN;#uLs)IKIoy_&;0izz?JlaPV0Jn=S@997^O4q%Rs+eG*E zkM`^c-#OsC=#DSj)^nEq^ELBr0sjykYlLe%Pll_T2gYbGZ|QJ4Z+ev-z~k1&zUH0J(^vPPAqdE@Q#nb`LP$$W zYlPqRw2e<^Z~9pgsAM^jvp0BBrcj%{m_4fJ*df#+evS`HF3*E&ulSI0ErKn1qlr5K zQ9iQ~B@30(CxHFpTdb-3v_ z=+ejGd+mBb{ej)6bLmC#<2mIfzY=MQ|ElfaCTf9ZwT0)&Mc_~}Lj&+%bk}9=o@yUJ zuiCiU*ERR4OAdTwStSeC=xrtlscV^jWg9x@7~E4bl9tqLF8)DV(PgmsTCiK?l-}?c z{7!vG0P_8JzBh;Tl#H*cJ81i|f9;vcWj>#6EXmK=@GA2mRQvVz?>jM|O#D|JORhaU zk9X~{nyp;v-MW1M-bjYdq>LZ7e>8iP{Gr;p+H~Fib9js_Q-A4oZ~wgx7tmU_fBVqe zKe(^z*ZVg#=%hZR_ygzG?cej@_#yjOmgma;-A_J%uS}J)t(8@}QF80sp)ZrZNQry< zDEs#^lWXhtPeb+p=ff9E`cV3_-Y?)sLQBqgF8eQihT^;K^DNZ!cVkXIs5lS z`Q_dx0D1KFtYzp`cG)T5L;37qJuKgT6Bbnd7w}%ZqGh!}K^*fw;!3U4$3k!z#nLRa zE8eJ>vg{xBuCp!sXIa+c*~KU4ysDrD+J4(hTEK5%i~S!)yyhd%dclhMK3=crfS7XU zh);MpW)oM7pZSXOld$RW3-9YOF3(acOZ#tJt%DS_2fnXPg1_}gu;_?nLgml zv&CP*xqf9YEJAL5zCcG@fBGzCAWsnEgL+r|TlKwp6Lnw9Ina=3_bUOcJTBcqr*yqw zz{gq3{tNYN5A^YT7^#J!tc%e6+NQm&avZ$Y%)euKSM9IEHw5Sd9@mjWYKArMhmBWZ zLt`FU=vNR_p84nnX|s9Rq*zPo2N zf!y5wyYNqy?;S;TV&kX%VYWE?R~BFWr|AfW!>Cl3I7#^L->e$z%YQYTl8+N;V@nbw z`&NiNKMXAj#f)TS6p$j8p+IkV49UnF!xMz~0JK0$zkHkSCHL`}A)^t)kMELiFCjqh5EzML z+r2Pm_X9I5EW(8w(_?tL?6Y^tk1rk+7Wdzbd!c_}KJcW?)EoWGkxGybLv|#I+Y|58 z-L{0^^8Pp1^G1U+JG;Ig4z^RYMpg?PLDjXE@l*%CI9W9Xr&!q7G*c+3Or6|0x{eU< zS>vgk0~GCLfEUicoc-~3$TRlWw>#Tb2Al;aIY3e!iLKc}VHluk=AU`DQO$V-tmD%B zTB^So-_6U&2qXYFUJl#1T-rYPKjt2k3+LbKTO=s`v5m>()j( z7tdKeQ9RRk0ZP$uzAp=^Gxn@R6LMxF>k8zc-0G|{OiOw9G^q~&_A=z3w`QAC)BF~ z0{5?Inx(~|gmk6rJxy?5f6cadu&ufj?VO9qM9j0LYwE;{duyDI^zBsiduStmMcqrz z?kl@cr^~P%^efRKYvs6(C$??BuX6z>B!nJ#w(5=-bc(Oiv0k@(xqxS@ean{VxPGs6 zo4h2ARVVGGjdq8(%V&y*s%KAsT}FWBZ?b>#;g3?*zuEr5ammfO_3J(An)|EGz`bSX z=+wDF$))zq3|IVsX5a4it6tfbDVu7WUI**GI#=|do+*CVzht`Fq|W~)`zJ+1DutdW z_mHz#t^EGqhW(en|J$*niPQhYac%*6qLg+mc;x z&!3jH>dQUb_y2Xj{zp8j%<7AvY*I{8@k`G)c>sGXek{`$3&FFUcf;GOCv9I$^K|Q1 z?bvxJ`}bUL8&KzK*?++xf^Q)GYNT73?MSg!ey95Xb}iZf=x|T3V!qlhRPv7p@+cjA zD1m(_`8O%GeonmW{^F(fD^|iA8JxWPvqmUon;~g|B9W*)GeacCy4wbuJFU+upc&|t?u z3LAa};PgBP0ZfKlzVG9IH;dubt5L_h_x=xd+FwiljV2gXko<3i@f=5@kLYC@0JP*E z;`!mrps_Yup%UN&fS>(8+LbCxQcG%SN6Bn&vICBLfM30Uah= zThN)L!_U_+&@&>>#qFJ|;n5-oQ49{~JTusne4WPg>BO?r zN6$xaEvm85r&PTat!;8ib2zFQeTECcBKS9#iBd*%J~+}Ci;C1!irLeaC8h^P-b{^&}{ z5M0xa+Vz{DZx+_}I@;Vhyc&Q_o3cdkdda&I>Ad^!oPoWBMF5}rM>aXSF8NiK+0CRU zP(TM?_yD?&KeA@q+CYFF78~W~BKz#eEU45^SPYy2Z|Y*M?f|rlPJU)eFmBMu2fTjJ z?(wwbAGax^cR@etkrKYr=4e#Tzp|C<#*Y%x*0Ox7LsG7JU)Gn7xpO5a$wcaa`epr7 z&KGf(>{oPhAcO8`Z}(+AwB3tF*PwtlqnqiQy|$3;MILm@b7fD;O#NX8Y5#chho0wH z1bp76HZvW~GeOs3flnl`*`(OFBw14#Sdh)?;%l;38clOWj zwW0ewr?x04C%5hv&*eZ1umyF^g#WwkKkrYO7CqbE{(VT&^Xii_^cqO^z1qI)pFWgs zrOdOxcHhbt^t)bel4xby(;-*XF8Qa$THNFyRBW$|D(n1B@V^>L6Au|fTQQph2nDimT=|Tg#q+kqM)bGQ#^^Nq@wXB5#1xQp zbL9)rqp#y0zMxh{%hST6L=A86{W*t60|Sl?Ch!0}n?J~3h+tp7XQIE|9^SsWYdN2s z(jb7}_pki0&j-!?%i7TJdIVplmy&^0@-JU~|8?Zak*~Jz28w*9ZS>5~x0=4v}DR+lDXIV>u zVl!aMt~=o(YQ)P(S%L9V@x#U4{l|^Hx&4CVUr7u$U3wZHN09+kv_a5k%w@C(Td7=^ zi)fGWYyAbzp=SKKDs;IQU0V$XaK7)}rRd6eaf1CmSP>vu&(1_=%>8FOrctj(>AOW#E@VQ}GFxCw^T%>2dtkf#?kE*Y-NpyZ9)eTl}gmr(rOm zo-6dnIzUPM-42)XB+hd}8N5A-zjxsxI9(ljlj}H`0PA%3+kixreG_3qB=Z7H5Kut| zq}AGj!W{kgRxCMKUd*Z0sJQ3ps?Jg;Z?L46+f}{E&0EWvoMzC|j|>AxF7Odb(5;>i zs9?sRiNwosav@oj#HCFLWSn;$O1E-9yGM5x9nY&z21$9oX3!-&Y_j+%6kq7&8`U{$ zTe_odT`S-vwLN7C+5UMBblz1j^{o2UefSbwIqwyk$AS(i?_zsjv) zi+91jIgnh$?W*-=IT(m<<>5!2*L5rRGl61B1{KO?>56g+=#=~cf9UC(3|{yRePI8r zFm3m3aLLz7cGN1rd|^+!RXuGZ{BCCoWjAUhfTvq|Oot7Fr<}_M@MeGspYBr+<*H{s zzw$M7k4(#sKWG2F9+WR~O})vvw;kmw2Mz6Jh&Fu-zp=7w@El$5`Qex76?ydS<9yv` z3wSQxlv}n^zREfLL+Pb$$pcD8)CcykCptYZPh=&w?UI?K!ir_1; z`;nJg$!Id8#Z~q3;w@i9*ALRGOg2*=%(v#iBH1mjvVQ>27uMq~@mj?P*{|U&eHJ-8 z!tcq|IQbap=|MmHe{giZw87FpkYwxWX|^HnH}5ieeJI`)XVz*}lV{pTy|j+HYHhM} z41D=7-tDyb*yPzdD!#XR*5HKt@!|AR;;WuHNR_cZd-rQzHF!|Te{Box8(hyt8V35w zjP>b{b2UW`SeWatmBNJ@1gLG%mM`Q$0t>8MA^FEAw1K1XwFEiL>1<;zA1ZqCBFBI~ zbc&~<)kD3{-ef*i&#j{-m~wC;^R*t8yVYud`n8015Rmv+epvgqz9Asms6Mw=l7j&O zUgREe8(x6}>hv5Xt zwp_a{`#&Aqu6{Dm3Ie|%V6xu+MZ}Tg%JQ21ha3R7j4DOa@BM#Y{|CuGJlTzo@DCqF zt)ucqu;3K{cD1uVy!u%_SHPHLzqW;!KMY30X|(qq3?u~Fs{`ZD{K0uB>&Y*}*?HH0 zq05s@kH7sFXg{G4bPXy<{;7@eLGMfSUpED*nK_bL_TLWxtivFHuWeS)SnoXnXHmfo z#d`B5olUQhH2}~XBIf|*2zsYb`?eS3JNjk3>jvGH@84Yvna8ICF>n1jT)sOBy15Jp z8jWyXoS1Xld(Vc;tCP0OC`a(p2qDAcPe=65!Wll~2%%^yqn0hLKd)=md88Yctmie) zLh;tqh20}`I0yH8HUl{wNFqA}Bdh&r@6~mmgZpKYE3ttMd~;)0@T3qIHzjVYb18=qP*WP&apSX^M%^+b0iRI%G}$gxnI)&b6NlbTYFjcZp0p_*NWAKyURq{0e#4}% zPd%@l>0ikezv_^m<1uTR@9|4Ma&RDR3-B!X$l1LFK7^T|E$9KBpnRhHdmYry1+vZU zYKc0yUmKSGxz@|A^rPC=mW3+2l9NKop|)uE?Yu7AYVWcG=d%1vsy*B58g796&AIu2 zRVE^STPBly&lcU@{`0xC5BHRQd8S9%ZrQ(m&s05D^-Vw6qv};OppqOsXs22pPG8l- zxnBOgK9>Dk$s=%*P?QW3>C5qgR@D!R&*G_2dQtMN_I17ziEp>LD2f2g`b$sC+3 zoq7nxW3^lAUM6>vH;^>Jy8V-nXTQt-dtEA?;k)dgf2_pyH`%{uO5XMSZ)5+iE5|B; zl<#-jzcePf%q8zaX_yZ=bD>>(zI)y7W!uC3+I-#q$+dLeInS3Km;FPvHDtp2{njX@~^>^^=I(`z5TEIs;c8d_RkL3Ta~*N<<_%RAO5$eSN!6k z>>usospMCB0j}YlKCIh+C31Mo)i|z({om9Qg}e}<2T!C0AM{gbZlE65QLm^SmlA>z9I0#E+4O1e}e(_^MT{5`mf$bZ}!c3`@p}gNq=Yq0Cp~e*~goatk>-S(dO{w zQ80Kh8cMxCqJS#MHt^MJ%Ynw{g2^7AB>&z~P|1SIJ07?FPX}6xQ6n%$PWqqz1HwIM z!Zbpw12za?WZLqW)xJT2597#8-@voQ)A?fdO*<|{sGpuFW#RBLX{C^>kw#yiY$pS! zvyJvlDP}*ywf*cR~fb0Z4=NY=0OZBR?@|jA2luc&gZrffzkdTtifZ0BH#f^2IDyRYbo~s}WP3N+Pxf(}s zuI{!K=&<`LzXBdxIwG~`(Fa1+F{07KF>hASmOOQuWp6sqs)PG0Ina*o^hE8i=;XF9 z&$&9T_9q{*a$Jc{-;U%D&R5&j7W(9(R$Inn{lo9cd4VH{B?YXF#ixBtS!(lq`zplxfbMWiRFX zA~Z8+6x&k7&rOC^ue+rGZgUn3Fx1HNj&px0^jRYqS&=d1m}HFkkF!A`z5 zkgvz2MP#U+sdLu0~L-x-`N?(%aEW=$Xqm@kpTPpi+aYWps9XwmQ zs4PIU_<_2I51}W}U+c>%8t`5ApVw2~C70U&T;gu6p{r2#r7cQ|Wn=E~Z(mN?zv~4u zOCNwY3-!}eiiO+uW`8+xQ8e42z*hctMaiI`j-@B*pHAE4idbxY5TGAOu)o;yn%cMR zpHJbN*o*V%L3?J5&uZVG0Eh`I`G>U4{(C7E%WMueC#xCWhah&9#Czx8GX>9z4T>*u z0E_<|y*>uEFCIsu{6j%I7nEl*4*FaH)^mvUB2U>ziYrL(#2#0m?u3c3!+! zvJO3Oee&*lpUUH(;eg7Wb`Bz^uGzcIg zYP0=a?rTus>%R!!5D9+e(k+J$dREi>Mqm3de{5g=ey}IOw=y5bRrw8Fj_%j}Oz2T=9Gl}Bivk*^69v&#m~3-~HvbyJTA_eji-YWLc2#5}!tgJ!ufYmxBd4M&Grtb~i|dPfK;p z-qCNJDjnmNBt!I9AS1;v%Y6~0_yz-Bik=q{JV&-VS4)@aCATPn@PRN#`Eyiks>vkU zkF2s?xzy1HVxL>gW6M6h@6A;TT*$}0IxiiscEh*&r*v}hyC5TdfUO|!o2 zFm2o2`8>+bf#4^c1B<&d?X(eqpB zN^@HcbKm7UQ)egcIPQu4{KIsUS zef%%wq@F0CBREW*@-I!&=4``kD1P#r*?dK>TbZ1u{iDPFab|&g`hGK^IgmnY(ni%g z+ld^LF5g7T1}!AcdS*{517%v2Nk!SeHZ6Inv-`7slh5=pWqVc!nz6*YCCzwBuP;iV zCnQ)t%5&|aV3NHpz~&&nES zLQ5COC;LOkUf}8bfAsK&&unw0`HAP(v9F!c%6d8Po@`U)WdEP?Oka|Eg!_7d>eK$; z_0lWyNMDitzbUrUn~1%)Or@y5e#T0uonbp-dc${~OIy)r<1_pJ^mV*39SENh$@qLT zO1%qzA?Y7uwTiJE-*4l{z>YHTmUMHFOuvL~(6|ZTGsa|}OwNqwq$=XVt$nm}#Uy>C zPgzfzguh2|9QJb_eMgjEap*%33-3NsBl=@~Xa14TsVDwy9jA4WrTimb6KQ{&!FkYL zkN45Dl7PJ>t&}AlFWSZX#k;6`<=Z=1mUWi4josa%)F2Z8H3Lp7!tMS>z z@ak3AY2?wvN%+m(@Ihn#ytp~bfq>&j!|dJZ@bZtse(ytz_apAQh_d#T70-=%hHL)X zIUE!_HX*RyX0=x57AU6~JC7 zm3Is*{SSQglbo?@zaHRy|2N}(j)Pf0Phj5%|CV1ij7s^^VGHXsj}C!FMYcAFH@~Fh ziTbHO0&L4DW-r5gowwt?A6r7G^AW7%=rCv~(8aiZ`s!pjn}08!{pSAQ{&6JzKBkiI z!aG;10y6ne=rSp0y?0iip7p`MnvJRbb$F)*O0ji>99ODjf>ZC`xv5dMO!_#P{J@-Z zwTy@1G1MAelrRdKYP8r)z32Nc{1<8@&h`B#xojPO0$1r;eFO!sh59BzJ!{m{drwPV zCE9_Usn0}5rvuL5OUG95j{a|h1gu2ZwLTqEo`gzylVE}= z7+UDj4c~)?wR5_w-T9m@h9!~EApwgg2eoIA59jVt-fL{+1?yyC{p8BHsacS(5o3M z%g^eX=L??8t|@hf26%^(gtd`!Q)|)F)#kIFt9{pNW`*ol{AwMuyE#)_GasHUxd@GX zD9h4TAyetH>ov2lZP0McT8o}Cpnq?+WUAiY2Unh2SN%YJl~e8ECDwJ#iy{cE$A5HsJH&Bm)d&mb25S8zMvV-EyHTTwgxsK@*-N32yC3E_- zI(`!6n;lGDt9sRpp8C-+^a^OW$9y$x4X@%@TamLQ87DO}jl)%&mkz71k^nCmcIovb za%lr}E}y5fIRnjKuKN@`m#)C4WgNv>iHHF#el+!>W>a_wIwIjHU9Yyplk!TJ_#4N) z{b!PuAE%lPzY|X=v-<07yJ|CVPP_0!sk_H<#+=Kl+^Q?A>kVkXyJ$ByUG~q9C^zM3 zAR=X2HrdNQ+dXL&Z73O%ebKWI%E2dk=qj~dvnk$tx}}3z-_>h1H9P5imDj&!;#$^k zRo_qLva)}0O<83(Y)*N#%1i%`j(g}^t$0)li}Mt#p#!{ep8vM}<4yb17Ue6KK9NcG zYiXPQN1R_n=~rHN+}9TkWw9h&JEwf%xxKRgvQKo;V@u#zd$SYgb5=j~ zsq8=bNqg&|UL*oNef-(d4PgK2gWfHDxM%hMlJ@cg?5Eng>WGK(#eE;5ero7@E~T$P zKH0`;a}Vh)pp$V=_H%X3w)%ha>}OL+nLKXBNtdIYjE#JAptpZCsvp!oc-7zfI)O;| z^d@6)_#|ns7;DF>nv|dZpUl)TV;TJ^-x)F7+6sbt)w5m&5EEY99Y^w?t1Z}+XCVhV z%N|occjwWbcNgDUi3&Ao1&<@%rL&3D7yN3olCOxPX8!wE2|j^u0c?g(I}*2Nj!?Yt zO$FE3UCsO##Nkl!If(CfpXB$W3iZ6LxKmG0j_4H)K&OsuwLr6LB>`U2xsF}OyZ=Wo z4CdSq`;o-glK=BLe`4_HH25_^a6f$f^Y_cVdHI3A@dJPjKFlB2zWl?GqX~HM)qg+1 zUmxOc-vW3v3?Y-R{*#DvecXS9kNcmm7G^eV{EzDhjN08sn9tsZv!6YRbe@?muNBeo8jUlX{>`|?N!2}gL^o#TKpZa?QKR^4&U{b#G$aGI>5Y`yk$5qNyFp+7w&}MNPoqN!^^(z~( zJqkZ9l(@JFrxN^nhw~;l(8;PZJ~Q0Ivk<|T!a4U0%s3=V{Cc+f;zX=W5 zVA%$la(*lm4FAzQGbm;Xw6OZ7ybbggj@wHu+Yz^Q3`JhUTPU_E%RSRq+i2 zyrh+ZvHi3YGY^7?>@H1-8p^e@}fEQDpp{DWiT*Y>MJ z$a>QS^Ay@&J#|pomE>%s@<`mcewJz9{Z>;5#tnH`M?piCkqIV_GiXb?YIxr6ai=kK z@C1I;tJ=sP4(Y#uDrK6o*pKqGX)Yipc{Sm8aj7dMJI4lsXpYf!{HR9``1#7lUi{_P zHXM_qnKSiEoyqn{Z>U^#H`k{1Dzy=WY9rT@Z^vlR53<&s*EO7^PN^-qs^e|Yp$}%& z9DyyWB&a0TbNIWPk^4#y-$B zP%S_~hn&fUh4?I|*?e}!a?}UZQ|O#tj~?R_EkULkTQxF!mq}YnP@wF!BeGySe!rgf z;D*0AZrq}-CC!Osy(L=DJ@pA$ zFJ8*WA$<-lhp|`oFHNTd=&*MQtU8L&@MCNEAU_56sr{2d*?HMN-6!p|SA$}}!)R}V z_ddv$ZAhopv}9yxf;@7SPujmS^gR3@c_}5Or5DzwA`tu9i;jCD^-BHHDpEJIKeUd( zmj3X2{J51W^fYxr+p%@>^=UpS8!nWQf4oELR<1rVIATQ)8Xwy=HLQB^Eq+@kR~WE? zJj+9o96G+$5$R6+XOnxk$!-E&_JvB=(M=O)*$_E)G6Aj z`)O-w&(2opmM^i-Lx(Enjr~6P_uUP{UD-;x(g=K#@pSwEcaMtmd+a~aZmCWFa=M8> zpj-SnzYsmo_}X!g%oD;kA~vmd@Wa;fN^Wr`=Ev{F+t`kIhUX>z^Jv$>E8Fp> zcXa*mss4;rh)L10nu7(?9(jb;59@rB@+)t__V{)3Zo{p!{6>sr|JjawFD|u4)>t3Q zlKfqcE5R%8llb2c&t~Vd(5>0oy`ct!0*5d5BGc9T^5Oc)Tvg7C=)Kve9P{eyNZu{C zzYh()%lxs;`j4yE+baN($A0mHu;aLA%e(#KtL|5u>Em~APTGe7cS2@w|EXs}m(Bcl z$$$G`pS(J176Je8hNxM-X~=9{r06`<2xel(v5^T^anJ4M2_=|G{Jrx( z%r3$uJPSW}vDjQZo*lo~ndw9*ryp^nnq0iVo_SLs?(*#$Uw6H{KN}9`hl@~vNUDR6 ziY}I*jM)KDh~%AP(0yb8lN_JD*%*w#np=?Emb)O?$V6@V)?d&#^%)MvB#<77F3V@#HeKB6gg=e$IsmPZn;pC#Nygp!C z0|0kM2;;cU)v_gBK1XvuJPiuz1es46ALq)kZiFN7SB}xj!Ee}Sx^!nOV8 z6f?ln?$Kg5A(3#RMtgMtz8$GE*xnhP|ArMPVRUWTmo5#D(siEj+OFQ;;n%mE4df%GuVsm^SzkH0L|}O$3|UC&PWH@J%p! zcN50E6#>poIMNNv7rB4S_i0|z;r?~B-cVF~3A`>_>m5hXb~QYUd&1F0y}6~uh7RBF z0KAX0`K*?4TuV~9&I}&~WVxIWzdAn>%5=t0H@=S29>o>+Ww7E;$00ElPUx=i$xYeQ zwRjJ*)jRGq&MY*i2ihxFQP5qo4@VSyWr9Pa=^d^!_!l@h561g-+n!=Y5-$OMe!W*( zktwR#taQ(O5WUIy0%P}NG$ z@Kb#(L#5x=x3CoTqE~|RTp}vCtDltgLX3AnEd7uJYL6cnh3%Zmq(2xl|Lz@=TEd2XD3m%>}@qLz?YbEwa zqqG@0XA;Q91)=#PXf)KeY*m|N8{=7@lFQ|3m<}Ib%I6tzr4`cR&0IMv!O_#;Q(GU$ z_M(-loNSBmBf$gS^D|P)%U64na`uzxNTw~tR*ss^LPt^uBqFSau1e9&MDVbNW4>wj z$x~!lB|#$z%j6{*+BBC!=ds|yj8)boUu!Vzm_d?qS!miQ4&TQa-=3#?+91=pT82+r zbPM-1-+lPX`+2GS5HI~EDYaMItRG1VLd`B_D#iY3hdQKQrOyF8<5$0oz6323F=1Ki zJX?8oKn@Z;KG5nNzT0&+^EZ9(|1GwPUXJ(qic&R`#zS^7%Kss2iQ+KQl?jOZ8Z!NCrwI`%D|@ zjCsa~?4Ne9$y{qd=V*tskJ|k?%v6hAX)xW;nI%HNYg>R#%G zJH=LMTXd0*p`b?DPf281H~3yY$+KyFiy7Q}^+);IRt>WsLJ$4)JK8vHUwiq>!4wlk zY%cvt`Vl=rt`nhu8k7S5}`e#r0Ur~jqXbU1su z>}}27E2nJBeYB%=!4wjM0|9wz=7d9kbAURZX_+>NN@;2Jm`Sfw*XKo&4wt@Rk z`+qi>)~RJZr`M++_z4}o2`|5aQ*p*YJf$VVH~CO_kY8-j7U^_q1b)i?*$I7UFW%jt z5PE$(8!i_SBaZP9Nd60VTN(e2mtqh1EJXX!Bf5An+>Ebjiq~4K7W?4Xcc85LwB6jp z%_<%x7fGY7gqwe&2UZg3r?*pDQDvUs|2qP`7Q@&!fEV zSuyVJ;&iyaJ#R6!n7qZmhb&lIqztq>&C51Xe;)PzTgiXL^p!g}p5O1cmA$M%Y_Ep? z%1?X60q6AT^j*dip6~zKxyVD>Hjce^j0YN2gAv&ukXQccuO#cUjr=)L6OMA2miUh_ zDe2t76TX7qripZn^wb!A=Xr@}k$2(!=3xs9F|N9JQTZ-XO4(P-u!ZNc>n4&Y;D$F?U&!*2cLImN5l2?Ra^1@^7q4@|BZkB$A7XBg?|5cPKL!9 zhaKU2G`*0FQS-uKHs{eg6X8V2yTpfl|o&< zj=*_lwtYU^U+fR3eg<(w4F-T^{}hGV;I6tI2B!;SltRMOw;`u6maF>+w8l{~hRHw} z5ZE#ndz=AN!lfEJrtoHCfU&s0PyT^J@J>$~Z8Y}O|^%h}YO zYY}?nv5rKTCiypb!0{VQ({b3s=Iu94I-I~>bXwUlCta@VaCj5{N>Osu+_l@A(A}_; zwqjuXX^-mc_QLqt(BVdux#8!&1T~UPvy9osLOil02ML5u_;5o|e%HEq+ID(#FziRY z^T)gnL*l|%VO(~?+?o11w#644(Y@z+VUn7WD0yU%n*5NqD;Zd^5&CSVUP8j|+>uaw zuQ3QPd>l%EC%k$c_djm?q-B&?FfItq5Ysul2uzKbXN~cu!^(sxLw=TN*3)~Eo^j4S z_{tzrJ6bxM!DiNr4hdn|u$IYsOOa7bDdRmGMs4XHt8yQW2lsoL1oK~aN>_8yBRMDy zJrJcgB5Zfg@CM0c*r-g} zPoF`0SF;Y$$t<|(2UblvCVxP?=Ra<3QBgJc`Z%8?5zZ?v7#)=trBV%-M{W_j8 zJ5HBKfE@gue-3bw2(5E(S}840-pc+n9n@;tNMe~Q6Y?G$3TD}${!`z927Yo7m2GGV z`plL*!)|C^>LlCGVHsSK8a`4Bg;%&hOaGR7l(rz@5mVq(`D`JF#?;aLkUjLXF8OK+ zUT~t${Gj&B-YtD1kVr-`_~Wy(CTOF8D%qc?F zn*I!rYUuk8nJT6}d2K-g%O90z#4F#jvVY~chBwcVB^f%hOdDV7j81BmnylTa^fhE{Xn}1S%uSB9b^25KqW|Mo@ z`Z{8e?TrsXInq^K1$Esbck(pYi%)IOgZcM$l=r0V-`r@+u=(-zNvL=TmXj^xN6>Je z?V;^RU;Fqt8($pSISwYYq(A;VUw;|9oex)$SnVEWES|{NlTSrGBM|no7|u?}LEjqW zA_gpoO~sNGt4eM3966w;PU@eL7S6R7+y5ZmjWp7;{%&qAhr>1{99j_cy+(U;dpH~( zi`P)em=b6si&f_ufWABlZXV|)J+*m*OB~(Z#@s) z_RYKT6##jw*VJXEko}mQpcZ+k5B*(6J+^MHhgZLj{>ZEHHHq%^`B_-O$IPu4*HNqM z^Wn?iiB@@YHS9c(d*se${C%TuKlnM1XU|U}@7);Q{3=??w*p`@Y%&sl`Taqpa@TiH zBQJ`W_G)K%{^NYLVD``d?LS)l=2t0rAEG#&ew;K%TVVTDl2o!d=BK!*nR{Mq7A?Ga2 zPQ@-h8IEqC;HUWvK%lv`vueYeNYuUi1g;-GNgj$$h7fTr_LPHn=dME0CHnnux*ADc z2POB6l8csO$Pr-y!@+QI9v#KT;c$7E$(WI2sQ1z`1POk2bex>68O3}jFlh?|%gCc! z553;oIvOr+BB2i&yE{*!!wj7nzX4Ft*?F#iK9fR0GIz!aTUxa@Tttt1w3Ei_-8tVM zsBd#{(B_W{=$Tc>b~XoP2_d@al%*Is$H@U}KZ$t`l0eRZ2#`{KfEVa>yZG*P(mC%m z7P1_Cuf7dXcoTV5I1L3a2no2+(n zzSqH$GnA}Tr_v7V*{U1)=xSkg?$bKde%9r6l!wZvc3<~``>QTR%W+;yIj(5epiI^! z>m_M3_z@jkz`#J+gY(+H*X2UWLU+$!(OeXA?ufIUQnm9|HQ|*pPW|q4`!p!-*Pu&S?fJ?+9um$Qw^ z{x?D=SM^x8qwHIL8~ab)^nUcpj$w6eW&iZ)FxrdeWKBPB|Eu;~*}uB@efYBfl26qy zk>x$%7f!_X;N4nwF1hq^$>vgDo_ppCnzS^}=_d?$v6syZ9&7SDdp{!7OT_*l1p<*in@mfrkk`!C+e zK>v{6I{0?~5A098R&k;JxXtKB98=#pg5)@&GfUVVk8x7+u(G+{{>fR)BOW@x`nug; z0|12@6i9m64pl$Tqb>fR`>oBc$RuK?yH#9X=zr?(@W{aF%4X{M;@7eLi}Ui6;p4{` z9K@9E_0ci5+>GMrJ>S~Llj3l4t8X8Ocb6F7@3#gFd^@Xt{?FI%Yu3NweEgX7@Dr#w zq(`UkGO6#;$LIB}uSd_Mng-AexY6ybFQAhH;CI9MyD`@S^^5y2YnAl~^m8Ra@`e}F z4K=^2?BYiX&YwqpMI_NU*_^R@rT zv#kJl`TaQOJA5y~-cP$W+zB1qiWnu%U55U@|3&zzxZiV^wN`K z7w*Q0O5o^sw}!2I2EWr@CoqD-Wf{XWUPHjtVfhUK&j;UNiH2n!ma%zXV?I9~9=!+| zHT6i-tyw_IP93>lCA@lLUUQ=*{#6{w3_U_mPl3LCO5nd8->&uKPCXXjItD7ME?AQSV&9DuuR+z^epX!O0?O zbeI7yry#MwUyiEl#3WdxyEUA6=Rcg_&Q6$URApl`0+mSo+cpwz??f40-92W)oHMS{ zDcBm@FGr}`x;T$JLYKUoRj&`!=xmRjeM-kYX-9#Edly?{wH51?-2|;Q^&Y7?&bX>7O{5}E?t;0eDB{g%ConW>BTQq0r zFFV9sZGt29wQL;^&e0X!oiGU>#)a8)(!`(NE6?={W>V7CYd6ayb!`TdgsjniaR)st z>oAJTg3=Ci#>#!VR(r}u$J`97$nZ?EEh(gXxn=cgU%+v7s;=Y9%MTW2=Fmm!Um9?h zibMr={*?)2>*xv~oH;XloWG!cMedvw- zN(Az!z64_=fR36cKa#Xu;Y2=`({4vVoo|gQkELb(Nk@Pv%`s?ZI7#~qO$+F&w)97D z=#g((NK*5?@T6}*(7*OkN;|T}m-fhSACM)T%b8TqWUHmz$v6M?^?P;Ha{O3oKAoh^ zy3Y&<=)cy>*~6SEldL_8BV1S?CBEWIH-%mWkBVLqM){e0>pnIgddGY>xD_fOQ&lM{1TWryPMY z8zE=fuP?OJnU1nnt)J4!nx=-pL-y}!5>1^VlSDp89(~`-dU#WFocStB@l4nFBYH#n zYUg=!&0a={*{+_!XZafEQofE;zntUiGWkjS&w!S%%WpK`7dN|coZiNJ+Ao%Tsjn8v z{)&F;Z>)fF2fcP53DZIM^B+DcYE|N+IR4cB)hF#(GRFVpJZ;&(`?Lv}nSJyffb_%Z zUr{SR&(F9om*0DJfn{0cvvW(o_W`NZWKiU7gulhBX$ENHlpMLWcU&p-}>y>SmU&IG_tEu{W7Ke^} z7*Vgw%CwalmXBl~UMcY;S@8>Wnx9ku?03^zVu7|$5oas&WfCZHKzUJ zpPcwq?VWu%NnXY?VkpnF6`)&-wyoDa3p@Kb(q8nLz3Z`Zja&LqUN<7AtLPKD8UKnW zE2gw<@#-#&_j`a{2GZ5xUH{l??jViEpeu`@fL(YU?Y%NOz`GNWZ^i?trNTJrukvy6^fe(9_J zl6?8)dh!pKABVl)4O^T?>qef)<5r?5O#zwCB((vNHJRdG2|GvKe-f(>yI_amv4?~__mw}t$ zIsTsh;9xkr`8e$EM1Oz#V%YdM{)a#KliT}Xbi+@4oVQVd%eTS&c9?Y}>epNI;g^3J zOvJ!86Hj*>~wX`^cevU5;J_P*w*Fn$Bzl2M} zw8SgJ-PTC4f4;dh?0%75A(&UOpQ=c)bzJC1cluhAlbu*?&G@_DYXIQ<{tHHo6LbW! zR51ep-HFaqXLkNJg5yXC!&GMXA?JqC(G<4kkB9jaM#7zN)Cuk-$1^!E&itm$)O$yV zLC+NNLl#`Usd602lA}hr`YD;pSeWhOUiE zcN(qG4dralBgi=YZB>-x}U=Hqp*La>9|`&o0~cVCN{3>QKsYiPUkB zN1GH$RA-b4shXmyo7$&l4UNXulSbnqWb&Upsh_>1gD*>s%?w26d!C(0`-@IsbN(!N z42RY&|2I0lwPSX~C@i{kF_TyhD1!x^=gDw=6`gBzOlJCTZbDCMjoan8s*lvQUn4)j_$br)(($ab1LaSOlv5B}L!>bHBeZzkmeVj-YVAZ^1Sm#dynu1M3rYGNM4 zaV|>~=<<@dG_$EZP97IJAChpCwapGHWu!CJOEzGkWM?%l{Pu@o|YS$rHI59zDw**f#t9w*99bt0(%l>_3Bf+Hf6P79bvB zclOKv{fyeW{ae*i_AmKo|E{tB955w|_pPKF*l-=M=#>5Q{WxSx>XQ~g<~T_^Voxdi z#C=ODNjv3I_OC6Pf3Bwu;V@-S?r2uqmi@azsyQ!;Y7S80$>4$KI4j*V6v8ys{B}zl73&Q4JR4t2o(GW&d;~dFt(dyRCM6(aLcZ|8&6X4B4|~ zB9ro<8+0k{Uo9Z@m-eUJ^P`tqoF4ng9~l@t$`vIB15okWO4eJM$!*Hj{j2_;uBQwl zrn!kSHf|!3k9IKu6wRpr$GKMqQIIU@Vd+QeXMTU=+Q*3k;vun+#JzAB3Gv)J`d$l- zEh_4m0~YBoQZMKLdh9=JbzGIXb$=A`TG;HZd%|x;{N~RffL{+VEJByEe>!C}R z@pUs?L_E2^+`kh49y`Y*LbKEUwJrMMBE3!ez{rJ=h0dCe1`zt;p=+xbEk^=7#Au72Rzi}Tj=7?jQUlfNRgazX5>lkl8o@V5NSWte+hYzTfwYUtNZ+9uHfytI)m35T)OXkHhRHXa5V9 z{crDwF5g8RBKbd?MO*xD{>>+C0AOSOArhca_3Ln|k@z1x-)yh#zxl~Qo9Vw<91M>h zT`iM+OAXHFKWqiwZX66h{DWZbBr0iHf<)3!h4}jaW}G()aTI~U?D6o`KMf)Gl|6{g z@hlvaFCUJt0nBdqhL?YEJ#0mzZ-=672Y*|O=z!yI`|eGsz(L!;pI;7d-$Wy5l-)hg+$FTyKALgJM# zz&i!igKkYte_uF=3#{W0Rn%nGbKOT{F3lPKI&a%C1tvSaW{TOquxr9rW z@lX;U_q8_C=4PuN>Z#5>IjnHnNa3Od%gltOj64S-4Drm;&icV{d0WB-B>yUwtE-Ri zR{^Z=!@xN8&7cXI@e942i;m{+GaC|)dk>i92OGKeItB(s+ET0At>H0tHLAOhi#B4; zjKT3tyl0&^hqKeuPmFU<{@Y#z<9Ck*Y;Bv}M@wxogM#AXIGUEDN!!y$&4J8TKHfV4 z-)FZ;9n_7Xy+#YGG)fa)<0BA( ztCYRK{jl!mJfB#>ie7}OFf%%VKj-aS1vtesV}+aFD)E7_79?;ugjQ><02P}%QikN= z6ujx8;vx#bq-J<4Q9!2(nPG=p5($Bjkx4*|0aePj;6ep)71Y#hB-wCf@kc3YAy1YG zS8%R9%V&)Mb$ikY^ig_T-}I+Fwj5{uQoJf%A_YYYM|>$cf?dr*maXXD(XNUcl?Zqa zTB21qP=8lYZ06hU9oohrey8+bK-p!rcv9_DxUo z;8X3;&1L$2(e5G7WlP8>Us-d(`Xr-WewXzht;v)gwNS-XGEs?;-rzzmd@KIovR4W6 zISc*gKiC=bb6S8g>iB4@^9bGQyut>%QbiS*^yEfc<z-^sC{pOx!xkH=MSvbQ6&+06GY$f(X&z-~^D~Yd+qxeNK z_)jvPgeK?kz3dBLm;4~Hj+uY)kRrg^YPgq}erscIIJr0*cGqLG68q~5?TnBu)izAZ zkKsXDyfE>XBrh>ko1~c^Cx$GG0K{zKx6Mr}9~ZJ$x@@H4j~ZvQgVW$P#*IDk_jyOi24nHSId5S% z({A!{^ND-QZ;^HP+ZV_L7kkPZ>hCt~+3xs0@elNN@AHx5ZHG_AFl;${LYCz>G9oq` z?Z``P`cX7LIfjD5axtMn;(6}1@$b9a;n^?B2DDe( zClPOC-pFsB(cjA_$-Y(bul|$B_n7~tk+|BzSHj=+(aZVy_1W;nznan5-Cy!=+5f(T zDV#|@y=HYplK)})dU*FHGS?rYKR+4Xzd9e*w&G`(if%yif3p&HQvZPD|LXY7a2XzGbbTu~C1+_X0k#j4{FkHq`soiv zB$W^e|M;HJ2F`h=afSKi47?uRJ zF-HXk6D0i|RA!c7^M%&~Vl*)kQV8P9-1PYYpR2bQgI5Hq7~O?HlKqiA-lfguD8FVvE0w?t?MwRp7FdP#| zeo&!X6b||kET7vuh|vH<*=Ou{qi<}YubOj71!Ppb^(UupPZDl zL#t*4TOVdeIe+}V9WHNTELS75F$iRn^Sz4US&tmLz9)kffC&W1qfjS$m|tDbQ8B(7 z;hWb03G7QgD+GjtfZSM75C}vB9Tj}s#sz$rzqkWs_u^;^w^E@+NJQmJY~i!e13$v<6jU8NLN{4l1vLXuEp zt>xM!cYdjM0N!x!k%D|jHvt8?uk;Qb>-C^8H71S(?~J#S8d67&eY9I?2b#FQ5**{w zuW?lI!VC~#ohl)$wOz4o0W_%qOZ$>Nc7i<7gQ87cCnyt+>Q!JWbv1irWfGj|oMg&X zD&|&=^gRrU7d>pHhnD>JM4^8sZPUB5B*s`c2w-d0UU7yDu-9BXn}Awq#8$YcXr`ae zBbv!h`Bs6EdbR1l$c*Xct$?3i)0q3DF(RqS(@Yh7uRPJL*vL)ja8SJ#>e^SgE{ zh@w~UAr}&9*HuEM{{nqWxGYfrHs`g(=fI{`v-sc&-uo2&>0Zf=S8o-M*g<-r2xHt` zw%Id@EuHpQ1s)vd?@I9MVV9!eUFcrpq^D+>;Lq-nK6{pUz2ttr)7_qcRk%l{jg4GZ znuWf2P*^<9`1CFTaJApjsFoU&Ij ze}7v4%T9~87W&_zXjJ;YF}!L$pmXU*$!HZjyNs6pJC;4OySV*((4>kiwd5ZC`G0ak zdhoCkW%5*h9&g!Pg%Lgl9qm{x+ktnh3WowZBQs z;l4>?kh|fRDGtu!PCO13Z zllL}LzkZpxGQKRPykw>qQHy_M9#6`S#2%b&44Z3JP*|Pi@0ICreI32F{6F^sa({TJ z6%V4YTlhhD@QBS&e8%nISZ^$E39;q>;_n`tD+D;FFtGKAtkQkHuI|B?va!{chaj%s z#kS9bhlD!g>^VY9s+}8ilAXirkwWB;e$jt=N?%Jy{eAiF!+inazKwjG+fHl_Z-0B{ zpN|9br_ys0C$SdKT74A@^dUT%L>ne!QD)>t`@1ndeFVpYrxp1bFP@fk*Molm?quue zokC*eYm)uV*|F!XThiZ`{R1=q+F_f$o25fdKX_;eO?QXWH)-qPq;g;OzcJqT_TBLE zm!XeIy1V_LSUFJ`@gsSe%Rdoq9y#pG&$yM zE%{yWOwPUfAO0_Y^&3g}T?PO=8*p>FH=LXt4ma2DhxwFXgs(YoxxvBX2>Nt03VqU6 z1HAb8#jv*dxDfLJl71@z`tfu&y!vAZsKQ~R!136ZI`pLwDkCp{7Qx=g;4Lq?dL5#t z?Iix~b%JEivk>#E;qBkX(0PslQM)Dhq&(6g$VQNms+W2_|q zTumkZs;q(u23T-a4vLYu{6J|wEgWR)U5wr4I`$o1nH{z9OC7BOxQ?-2Tean5WNV%g zZS6N~IM6a(KImc`RV1tP0-tK%6TefzdfM7(Z3*Jb2&<~Et*Ta%Kvh-F4o(%y;4QwF zW5zWc(!Vze+u)~?$XfqVbn1bPpoB@Rz}0y(4z(GQ{y5T_rS+UTjyprQY)~e7ai6pF zs&@RYyEp=)D2H5OS2=op^wVK+K(m@Jam9paTj(Hw{m1f8P)_ZBqWuT(|!2RHSOT9 z`wJ@hx1xmp;B^&|1eM0`RgLF(kA`V^1Bzg#NQta7DYrd@~mMEC3M9D>l#p z?X#7*i9Y2lX|CTFe_OUG*s6kHokQO$d{k1QUn9kzY5~;V2*OvmJS*%i4p15W^k}f~EI4%eLY#IWkt^NMCL)VM~zH#?2bKrk=UI zZNYp`6Y#jkUIi`7c_oHcU}&dgM0#B^P^*Y4$XeJcxZ??#=rT$&;Od>@aI15yx1P1* zOwoW{Kt&dz(0jEyu5}|CQW-s{i!X zY_M_xI!jN>9?=&%Tl!yPvOF9e;G@Nb{+Axwd7ezTw=k|T{%QTMnQF2M?}h$X?4W(C zdt6)kUq@6_a1k58xMH=g|HVOmON(e#c$Ex^YxY*W+i`f3O()yZmnU@O@gLGo}CTK_fP}>_DA!B#VWE-_W<@5e4fvHmJ^* z{u`}Ww&N>ygRPlVzddPxm0x6^$)@{DLdcMD84qjb#Kz`-=Ql}&#W3^J#4_u{Sbg5IS4#JlY|`nyQd?5xfFYge4x z6ZPAbv*F+of6soi-soJ9u)qu_%7!P3J1e_m)*m;Q6Mu>I>TEy#TqgOa(>`JjD+2Hr zzv+4R8Rto^!&jRw$_?@n*NYHZfkYxTp4&Yv-{TD?$^dlO_^m<_FTxUEExu3;S=dkyZE> zC$Xwl5%%v217~jvuTLhHeecWu&y$~?ydGZuWh7%0W^6v-kMdd1wQ^P8le@IZZ>vHi z|0m(!Wn{_U)6iQUoMR>bX;hYpapYmw&lC?DW^+L+mcsb;MOG#^b9W7K(OX1nA)J+c@43;pIOKQK#uZ0bm}SLb!qi zY*EgO)fk~9zOVk%7{uCuzW_lM13)hb+$aBLN{Z>2TrQacm0_F`m?Zz;c5>7N223XJ zbM0767-9c8^Zg;>X31qGa9xc#UPfH)?c_rQbP|_fY0bRGeqYgwk`QR$_nwwxEHkCD z%PE-=5};P)%(;sXs>DotDKKaXDEU{#8-emwkO?P&nYkOzjMEaNl)F0(;~5x6YO-RM z>DjP44^@(&U*8-x92p@q^^5`MBQV$=zRq88WY8E#V~%pg7@ps#wwK{z1ZOkGvVeh{ zgm<3NSGi-}QNNaRn+^9Jew;#rjOk7sQIhv0<-NMvlmF$VT8uT*jE`Ii+W1yHVc-Sn z3GAkfdl_@U_+Q0vgP!>NtZY_goe{+m#)jH4hD>7d$cBU~!~Xika2An!ym>ra-X#FI z&HWjcB7h}ul6U$8D!?FDW=a{b3YxTsM-mE7SJFSvxFsnbt%1MqRh4HbjEiL0b(+B` z)8!fg7pnT3`|C-PR)A%QXpbu#1{})amSJ%uy=AzaBNv>pR*T*>>sLF}lXcpFDrCe= z7B0GPy(NKM9^52+uA~E%;hA zwww+f6bAY-`$|ZR5guF#9VCrKp9c#OH^1YOZyd8qqGT z`(OmIy8+{OH#w`LJA|-CVAg}Ixz0TT0zBtXOODA!;h~&UcFPE~2GGCyX4!p8|DC7* zbq)Qm8NYe#i{6aYbv17GrxLCT!C_}CMk4{S;>K!&;!%G#zKV^Nc+@yi#TAMY9xZ@p z>AzWh*A$LE?jw&l!hf)b##CBV`p?$*y%#e|zFl8@LSwH0)kU{qJp* z+*YtxW2qu%$qW9nji2g&^#?a2(O=o~O{u=`sBQx44-&XXkYtX_tTqiEU=fbeAFa58_*gn;Ncc9O*{*x-Y zUquq_qKSYV5Aoy2`VT+UA!F!{&JXp!^j0tAp{~c1)%M7T`y_F71YQ5jvi{@r-?-}; zc|o#Ys@P+6>=?POLZlHJExMN7r2j?_H*}SZmw(2?0{Y+OQ}Mw4rAO{7{fC8P$qQZd zjooC^%O*M69lvxMJ?JC)Dz<*A|6R_zuDb)TQAHB!9Q`kEx(Vec6 zSXPIOkuG+VeOvhd@=3)Dqc3^x^6k9DjJ^0&|Ir1&Q2WNdxr#Cui4W;Iiz+T)L#lY` z*YY#;u}UAOH)n0r<91B)PrJlH^xtX#agp=vUGasS(qvec4j8-k#A~xVayiDmOA|HM z!<*chQLa24);5f`=t+L*JpR^)EIT(#ymo#+Q~$XYq#e9H3T;T-R^u-ouqQ?+1|cmU zhP$)C} zT?)-t#(YLQtq|at_Dx9cJvDB38n=}VHFj;18Is37oW2VW62sfkf4UN1Yrllx zYNGUVQuwYVf!%zIj=xlSm(9j_$WM@ZG^MY+a&+FFu&|HQ_x=j9+3QR zzo?w8@;{kijj@WuC2QO9FDGw`j(xU&ew93BjV%i(0?2XKro+p>%6QN6w~6oMQC6jk zf0{jL8?@)QBnd6~KZv}^QRS)u$$nq%F9-H%GymbkeX>8!_J0an!>hlG4_bRX%p=zx z$Cs10UH)zK7m)m01@Pz>v3@JZ$;r~r!J}dF;j9$_hIzQ*RfEa*SO0hai^JaxH)BFR zjeAY3lR@R|nbt)z?Rys<&y(yvf7IR{P-dHoRDe;2xhk$q;nfjEk6_ufBQOi0 zRivAckBKYA@%8{pTL!QkDOKqp@%Q)D_^J&G+>`&CyLY)bv|3934-etO*=muxRok2n zbIlQfvv-S1o@Cu;J%T%*rAHgBAOnGxar22EE#-rP-91 z;rUrUd&6yHv9~4hXZU^kci^~D`-Eg%mbM8e6pMr;o?5cZT`!XV1QP3U*|YRNi7AO( zG4FjNLC>n8CyWHRuw>{tHfakftCbFBt0R*)oa1Ue=kKwToU`<9V^yWw-JYQnh-k3_ z)hbNY%m?X#7wXpacuTe!>f&Jqpq##dzyD@d@Y{S7R2o5X*lchG0yM&?1umqD3<#o( zg5(RT1WVNio>p+g`3P!UW9$_e0|8wXCiGZ1E!rWa3}_|K1$|jQ9LqV^?7C<1=pP5+ zPPi);2$cjqqVHpOczw}%jOA)YpfM)k|lwsapO~$3A15llSr?zYFqKfn5sR& z2g>RRuJz2MzlsXRE95OoXtRPSlz=a}S4KF8`y zX-+?Er3An1Fd43~Rghc3g;fbwk>G13O|T&+t`W#qa1D$>Uyii`LfZn<=eeKm3f}R9 z{8Z7*xO_@>taQ?QA4{hfA6B|yhRYRoU&*6;*e|n{iW!oxJ{B#b6KVCm>=gauC#uCt z0BgMDpd^05O9?$07xEaT^YHb37Fl!^Stz`#pOU$fIDJ$=Ts~6Y^@=~Vz#C)mym0*u z+*iD;zw5~7)CUb&3V4Eh|H8NI1s&{aySosybJ6EV|;*PwBraAL{?|r|W;+PZzXibOKqw|Fr&_eKxj|?N9Z;=5T+k z|HW%DNa=rFUtpZY8+wN;pV$AQ?Lz-S*Z-33l52$ZCtpKX;pZF5vh|A1rT_K3G=Ju|Dol3$ zC*MYoP7B$$(#?4s)vhafW^HKw#dwx(p*yczG6SEIY4q+Gp|m^2K8~FS^_{M;C;e}- zx;lK5@2>H;{_(+@DPzM&*!dl|T@MFxQa+&y3MHR5A#=Z({)?ONL0p-5#=Xwv!dzGK zLDCBcT%cDaw~Z1>{((mZ?(TBO%4sVAh~dO(W`)-`pCqI-Uh)f1Qdvb?*x?;G+^{VZ`DKGG1B4A+FDyujom3jwqSAH|Xdo?@4~;bT&l zp0{jH_A4&}!O1FVMF2U|&XbyaqcfzaCVz~c+__(ix5MSzaA{nfEy#jgaEG?xpXd5}!v8c0{dM^Fpa@_x-BN$Wsb31?Dj-SAo{M)JU_4f}5H$q$fZxz7w`}TKxd%#05z1qR!0QM00f7SI3-iIiX z{{HCKe_%=`Sl1~RqTPP*iJgj%b*7M+kRR*4EB#b2#(#7eA znDv$YreKuU@hU-EgXNk3L&nKs7)#nHaW^25}0+_$qiUA- z`$_&87OxbO0+)fN)KpPYTTXkLIIC||0{ZbDZnxUG!q4m^BVCCPa|KVw4&L*xXmHbJ zycaUjzdQQPlAFyI2&gD?B^*n=!iYm&Yt?ZOnvGSlcNBmL)V|mIkhwvp^kXa#wM5h9|syK5V zq>T)teeb)Rx1+J>-}phlAJp&8RAB}mLE%ts>A(Iq`-ZPVoVTrCFiBF5&zwAoH(J;2 z4c<9i1(Msr=0*MbS{>s9Z;3*e6Zg@_yOuO|8e8R4>d z?-;nAPLg@o(3f&O6*_C*QgpZ!r-X|NL#1oLQ|udUCM&WUxzt|G(3L!*XW>V;YD35l z=x$6k7sX!Tm2Wlc-0wp_y~7Y4wIK-7zBY?zo)eX5DN4cF70OqFBzM+~&qaRgP$Ok8 zN>9B;tEa&gX7qW68UsMplA8|=uR162hbKL%<+HAr;CET9S!M}H6{*mzU_ndcFWOeS zZ~%B~gr$3ARp3~OYR3!I^T|as*VbbMdj2YHm9OYH15|N6x&XMk&o0EqtzUf5jxiZE znvkusjS5yCCNeWa&WpEQCe5(m5zub&!Prax;pU7Zyd3>jJSH1fH9fg+*Y9|?pvxlY z0M4TcdBrC(quug1MdzYlwPg&we{JED`>UP8uiIKQ1^qW|qHJAL@~Ka>>-vv2=z^}D z)_`3s-KSTzXF`qF67#ZUy-jk`$L;s7lg{}Y^l`hUbhP9G%|YQ>e5U`}2ClaOXzAO6 zmVJ!+f~T=B>%V(CEbBj7>Faa)Pq*kQ-0L@~0-Cd7DT$9c zmEfWNcijTo9Zaz_aYA_G-lj==xvu_3V7nXOdvP%Z+>3WwV&2 zTVJ;G03FcW_^;c&g=6tuzv2eij`3rT)mO<`j|-~cKsP&HCCfL%&vSf|Px%AA*ZGo3 z{kumG&hr1p-gOr~Ft0a7cxXerX!5b$kKXICb*?M=6yD^Z;|PlW@U4|QCBvWh|61t& zzsphiwHh00_LvWpzbpSuUV6W!OC{UJV9Y>FA6sYxIQ7>9^(7H#J=SoiT$_J-oatXdf`)J>|m^w<@ zlK<5gB7w)jpmu`m&?jDj0`d8q@Jt@rb4jpN2mq6dC&RO^ruDo(c$(OMbCD}9!|T7z zKjVx)XtVvvdE0RWd2pNgx6z+>`geH0$R%4bAh5iW-gEyQiW;{9U~BK` zaCRD3wLcp!-@h5Q_lo!(S#JwaWN;idD^cpuX8!-;0TU1E{$Z8@^&-ID>hS76KC7aE zr4#^R`}Yplm&40nhM4n%mhkUglro*|d=Y^WNG+6B^8XMBOD_U+uKy7rVZ0qzN)STd9W8I!JLDLO*6uH7z-d$suN%p0m7@{d*A*EwC5bX>S24kIP~h39 z-bMvS0+QEpr++?06N;^JbuX60h=F8}t?Jy0HQ9S~z!s(`@)~ zcHHji2459<`8z|ty~jLz?ze)V4rN>gWhG;m)1CX31faL`5Z2pMR>0nqP;O4J+}kNAXRrTCzL&4%63~h9bWI;) z%`j9O@Z=a6SvW|lZbDbr^`OS}=&wzWB2?mm=HKMosJ|mD+9p3Q+d0?Qm@3Fvv|B+r z5CnEQRuEanu{Jq_yC)t$P14W~E#a&Et>F*t{MGQw{9TDwhlhWIPB-_$(U?1+t9yXp zZ27uM8jF6*^f#7%ZNH||!5=P$sw(gA_)4>>Q%8l7pb zaet>-r%Ao4jGn|njo0W~P`cIZ6+K)yZ(ux&{`c_%H0iS6ajYWLr}!+>tILApvR=cn&it|AwyJk3PXxD!UVCT8N z|39Vw53lR(d`|y+GSshiKU#OZdb^!A;Ky=jbp_bVon`}nTK_i^15Ag1J-;sWzt8;R zO}FjKa@TD>Jb-aO)PHz)JUf2QgZ>*RU8Xx$PyK2A2fqK5{x93mhx*^~0>vl%`l0<@ z_kMcKGJTh!U)%eAsI$w^>9GubEGWC1W9d)ViO;pQh$YDY`@5F-$WfBm>9`sHe-(Q4 zcuBtt-70|3GQC{WkNw(Zo-gYt=xudfi18v^<`Y1-#XczR=-GaKXdxhuiBU-y2`I z^UH93wL5HVoeygf6)~;?9DJ7J%JPo|muI0t5^^wEEx*#C$H3y>?LDKec1o5Paq}{0 z514!tfA=CnOVk5BMmJMmNq&J?RkBaUwab4fR*3IG&o{*SD|hdP+u7S;W&K}naX*k; z18uT@H3_MpMP_OuQ|a*hg97COdb{xIID)-HD{A^gM~#WB@HGly#t$U_a1jN|T|m!^ zdb@I*jVEMS;n8^NktVdO7=3|b&$s%Z(8C%pM@{u8v>S-f5m`r{&}5W{onkLfA*Vy_TKBEw{e`=t{21X=G`#4J{{IqSBLeDYV?z5{=-}Z zXq&H%%O38R{TqDWI8frhnfoRFrmMSpT-!^7j-Y?;2+Sb;*TRy?sxa1%BZSRH6?o`_-3&G@6 zR5lqSk9OhaaRqHYI&}BJ zh!>nx8Ea9ge#|u(>FI~?Vy3r8Z396-c_(-7kJDbMYUuu>T98JyZ2n>Cm~W`V^`O31 zFP2w(1h%&*_kMd6peO&}saHmZZdJJ}L(6p6_nxrNhV!!+itx`q1eRoJ2Y7UVBk9kR z?d;$yKA9mi&f>1NI8yEym9C~G*Zn@9&q3emwtbI5W31*4*E++g)FN_!>5+j%6^Q^7 zSGaI$HpYXSD}jPc$snARXt*rDaa8rJtJfK6ujpM%9reO(3l^(K3)L+Lh7V_6=L8Dc zHAh6gg#hHpZ?!CNkBiS=C;69Q=0a-rqL#>^<)?bU0Sar(Z)gi;)}xDcpA`;prBg8z zt<7b+Y7tLeCFo&91-^Tghwfu{` z-L-bh{c~tVzYY}=ku}$HO61vx?$zS}XjwSdH`f>+TVajK~#CF(BI~f zMGsEMEN0=3a*m+zw8_nz;BSL8Gig2W7Fe)jj*_D~NB^}!0#O?N0;2iwm+dUPi+8XS z+|ys1;ne0!^?bKbh;yz4PfM^eZuBz_pg#alZIUjdDBhsAlXh?=?217e!Snoxv zejWLfcxcDo^Y%6*I*jAst-O~5svt@~8Q;ehVw>pE4vUq4#AvqeO$7XAzbiZh& zeH`>w5O$zw-2*lKmFCt)YxcP5_}8n+N|zM}%3pb6-8jwMYrUvad@$Mt{{4GdC;gIP z_M-IP=+~M|+JC@k%)nX3>~|94S@Y5_M{R1S>p!m3Es}x{HO|^l*7K`BrT_3UmSz2i zS0x~H1x335Tb^8Ww)lKFM`wm$Q;ebT_8btv;R~>p#4@{=&(3t@#ev z*{<6gO;60!`K#mxJ!^@-QPrn-LLX7%C|CSg|NU2S#HadiEZQ!KkwDP*h5pYXA2l1t zFNqaO|Fvc5eDxv8As;0x;B)%l@udGX_R@d<7G4Ye2k41=v9efddxUbOCQbp7dllKL8J`SG$X zr5D;HyG0xRORFV$?kFGb9pr3t#|3@-GHq8bU*oB`37-0*7mL1~D_wJr z?eV+4vg*4%kn~&nZ-0kLvw_xlS#4D@4Z3XR9x_ld(*CfqR?-h6954N^qkhQ&-%|Fe zibmHFU5WpO*Qy01|DeZOVm3v9{cXI3A^C#8VwG5>Yycj%$D_P)Dskh=>f?MKweLL! z?6A6)-#5t*il7ajSCJo@(hl|>eI)B9qV8@-`!qMJS~0HW`~71wNejK5TGgXp1rv$2 z@vRS6XOStZZtrd?p4U&}X~zz}KRK-Uf&Obl;RhYb0_}57>@htK{^Rm|?Sa+A`fW44 z^}lX^i~qMD;}z*)!^nXBMm)k|<%%}xUifiDzGJ_~wt(+)g~rA4{MI4cMxSb|q|F#{ zNLxOBnI=Di3u{jT)`JVsPS2C%AnQ+zim%+y88}8J@{Qh?^-k=bv)=PRUkTmDDjC%(^Bm*8{Be}knZ z|KL9P2bTFSKkwfksrMND?=R~)|8beWPk-*;M*aP<{Jn$N`}ukD#MlZ6|8?YTx-wjy zpAYMgGsf|igWvvsNzVTJ|MnNZ@kQbfcE^n-fJXr|ZZCjm&mz`mZ->eAM}v0=u8i+f z^bYcQl=J#71fG2y-o1%x-vGHlM!!U`R&VZ)ec&n{k=YqOIleS z4w6uRcvnQ1>~mP)GJ?Ha3|L=DAo{Ef7D3?#BxKAxg;SBz8+M%@ReOYyP(FmFEUSmZ zc7(f@ZFW^*XsFKOLp;xt{8KbaaS`LXIf+qA8(jhWarcQG?kkP-P(lb4W#JgyYpHNK z#)}UznWKO(67HQR*=Hb@+x5(i4KQjkFvWDgB%&PptOaa4!^aP0q9YQpSM^ zVaya007G3y5DsJpZnYdy0)KHN7LJn>#G4ApwD%D9lIUOGE%4^NEYNVhpbjM~Fg?t< zYKwCsJsjowngWnOn8UJckwl(Jzi8_|?b$@rDvFZ7 zPVE9T>H#a-S^kU`6*v_gB{pXGil%)Rcw?}GuW{lv`RK_c3K&br8@Af0`yAn>b%jAA zeiP~nOciJ(kv&->JAy#LNMTucT498HRRBQ=AzEEg{-k8Hf=V(Cw;oXAG1+l14!Em| z8iGU?gI*i2FhJ06oE5U^#X0vBp2jR`#(Vga_2P$X;E$I2>pJ0DT=cg-KqW8kfL9d} z98t-q`ZbbD_ViwKlU)F!^7CrT3nL3)3{*zg<-sNUD{>SWO*MIlnv1|U6{`bTWbbb|$=|8&F zYNt>2U*e_zvd@ca%^sEhYlj_#-{t;MkPPS#^-h!AvI?5Kh=MHfsuk^Jy%~v)h;Jp z|104vO8%7oyS{o>boH(Dzj(IL|Kd;09J|WMYn*6NwDey4>g~_#zwvkduT6Z}W3v3G z^&f8aceTl=F)!~oI2O_AN~7SP*Bem7Zs+)43Dn= z_}KNIF2f0J{Gy#@{|~RO|Ev~2rp3ir*_gVokC%NF0oB;?qIlWmvFpFK$s~T9Oq`ApYNbxvnkgJTys8**-n#??;cQ_hTyr=5T$nR76nN8hO=L=1*^;i=q0> z*0A?FMV1`a`Vf@%8f5ij?1e6E^lI@^ZEMA z+iLJILGg#U?=wcQf~E#c4S{(G*U-$pY-SOk9gS4%_znBjvlBg5?8{rXk7g1KSxx}rqBTk=nE zCN{tWD{&AJMuKQ=!@@!De61HwNbrJh#GBc;cpJwU;qxJMiU9p@#Q?$$b{}J~Ac6BP zm1DrD3*%eo%&bRPqimor^LLcYDg^Y^1Y1uy1$Qyd6h{D5s-vn`jy9&5@~tjjm%tEA z(iWpY6)3k21s^}v7B}x%-N*UuQ5(HBs2%E29>od3VBOumZHlZ7`v){*Xy^JEHY*dh zhi@D8EC%d}x(|hPMB(Z9Ow~_;HftpTT1jjf`U(Kbc?x#4=ee|mWz%Y}C;uFPjdr%y zKE&utCQfrM3HJ_%#-UW;B9sFR_98iXJxr(XhmFm@9PaM)vw)4r-_F|Uy@Q&mCN~4^ z{t9e3cDOpn;o`q#ZX6}rUraZL?Kn)|rO^83Q0sY4>q8i6-x&I8ixYNT8E!OjE#p=W zz4|5_yjBJD^&!7+@(bFTfi45*==aVWp9(50{i}Xm<(EoaUgo>sd$4A_#?~bmpKJW^ z6eKXZ#%`=6xn{houfngKk6+A4l+G0Wv{mv-_ls7A z56;5de`sC~plH<-k!n|e=z+qe*JV@7YM@62{rZO|`jn1UUu1-i6wn_5qEK;os zD*5r)(6jtig$4NPqXNA?yNUKTSVIRkxl$z8b-D8U&hTCPMpE$IeXfC7J5}(v{LdxJn8-&>`b+wE)&PG_4>Jud5hX@>hSm->+t51^#Fz z5OYpaRr)Wfb*9esJz&W8vi@5KX%7i9VSQKesghdSLv{e0Q-wl$((PB*|C=TKcTbJC zS~H@D`oEBgDscTN{YP^T9W3krqKzNxKk4Xl^i%qe+C_7``Sbc;$!eG3(tiog|3B-0 z;q`g_FPuKrf8+Tn{kOAx*MFE*QoYds!dshvUjMg;di?TF>A%DnUEGg0WUmALFIxSJ z=|5fg7t#MZ_o@EV(`D%Tue?_DaBt~))7ag+cMqYLxXP;#z@C(K)!@<&Jz-lg!jO zx(!iqkr0-iR7_KGSILMd@M<`k?hV_UE5k`*qK(bHw0C_UTY=lO+wrT3BY4q+N|BY- zN#@yEP3ZL`zkmF_vHrHjfK~;pZHnjE(xSP!Wh-VC7Oef@IXo_ObsW2!L|-f^rff6+ zs~>}7^f+yHF!Nuu<|oAOHOW=_NNVZa?eO+P60h~hm<|8NL?1~0dlBGz{-I5tiRO(? zp?Gyr7$y7oR{BprFOQRtr43OQ=qrSM`h=YLzmk7(yZ($DepQ&Y0)R)SA7@8<;o(

=!}*x}caZD@`I|}G%e#6s-ogKqS^wDTRuCv!n@n%X|86Y&)%tLKOs@;f{#y}X1wh~M zZ`j&s$-n&pEBJD z0?6_8gAD{*RYk(zlm8JuN&b5!rYHU*oUKfT4{y^?XY_UYfq7d~^B9BLfot$?$fTz^L~}KW6RK9JviU7@Mi@ z$v@~-ILH2-!aR!ddGsO!C_EajaMTC$DCym6?NK!U^%Vd>0iY|R&;C)^5)0gmC_-Q%u|Q41=XwPU=IGWwNxCInoNt{MH)i_=y>Xs>3O?Kb1T zJxPeU&FR%Yv5XpN>U^Ww^eJsf(!Y#2Io<1c_xSXC$G=AkjwChfoqK>491g?m1w*rR#kb>?r?MAfz2_;EI5!@D&US=Dp*iW{OCuD|-OtgXR@z zaxPVPDvNTGF=^*CXZ&^+>^|fSJ*Xm@fUAN<-)pw4f}RSt^jVKG;8)oLeIGRYz!g@p zqsGo+;Ob8Pa}VbuP~q_V>{89M3q(xyk_!#_bYexd~_ zB8Rt0D5@WrdM38dHp9&lQnF2FO7^q}H$aAp5|zy1P(4#h=IUJ0&-Y5G*a(ZOYc?4U zlKRc`L^m(THY!mCTf@6tZ?=rgRuK;rjVhhfwh*U+FaTq+Me?d0VU0C2aMBiBY6VpV zrFEUw3U^?9zLWR5r_Q^YY{x~XJv=#Y{omzW(TSWhcqNN$1)UX+SHO6dzio8qT{d|5 zDm}3t=)2H=ZS+11JJd8Xvvl9O(M*8U^Co{k?!Lc+3qqeX78NwnkX`&!%jLh80=VZ2q6q ze-vFE^&gE($#Erze@g#rh98gEB77}g&>fF?{W<-o=bh)v`d@az z9xNWi^5_Zd(X8~pY<=l}w}W`>sK4?gr5{C!I$w67QZ(&3U-T>emx7=`$;eT@!IM7v z?L2?+sZ~Vka_I53l0)UG5OWn@9243|yIqmje`*f^) zp;o($!?WmIW1%IAI)#I4EOlqKF48mEUig0;f=5k)pod7nN;_jjv-1Dq4n1}M?^<`T z7W(cV{n3Bd(f{ony#|pMv4V;dyG>3H(}F}geq=4F5+ccn8|NR z6rAV`E#7MP?yX%8r&qC+je{ zGow2w$X<$F=nT2Azl!N9m{pW?b(W;hE5Y-bPvr;U{kS{7$mwXhsixxcdzdsGX^a$S&h9< ze|v{)T6sT5mJAnh)@wa$-O%PReY-x~P4aDpoD^P;9r`)>jMb3(^!toOfH%L5FBoU~`(*X~%zvOyVt?^3=QsBOxkLZ-mGB_nfBQG_ zU&$ds#Q1)bKhSdQfOB5;CnulGBO`0!Q@)?Si4JYq<0ALw)cMhe;nk}uNcPG7p5w3d zS%0v6{N0;3!xvvH67BQvFWYMaz_XWM3}=7%efti6|A#L>LCSZ_|AAv$w!bm%cK8Xz zu=LFjfK>qb`*o84mhdmZY~0XK^53f|FaJq9EC7=__&$Cv{%&MQhpR_n+;$jox%fm7 zc3+eWlx#5wp2B5hIxwn2rVnqgezaMj+5gRC!Co2YLuq!Olu-4m9igtOI_Jrd7rkxZ z;rhN}pjF3KpS4dv2kM#s45=AlZAQUcqQc;swYR%@1pGJ-FNVSW?Ru*S#t%?!)b7?3 z0h5&R7dfX&3@1t_csPyHNH-6Mi{pCRgZs4$HdnqFHgDsY=C2y=3IUUS)$&Rb+eR$I z&)eS$0zmuV?36VBC@p3d%|Gvuo`h3=Kaleg(1Y&kt2kzslK`py|oa-3!Z`)bMyn<(mbM4xFGW>N~ z{ifj!;M>PpbbxQ+V@&YHKLLl|T?h7?9D4@1{$3up`?Uj#em1nyeo z%^(u;WxyxU@%48fH~#g0(9^ik0l$nN-R$I1^5Lie=RMFkqu?Nrk-U4>)Z+`$|JJ_% zL_6q(Z<62h_E(o1eDfwRDDKQvlN(hJDT#_;!PuXqjLJ|2A0##S%{b>5EVWfS3z zZ=}Vnyl-~70Y9bx0KRn}nXd$*HZ#*7pH;Hk>A9e5(M((2R`PF>nVPX9@0B!_ZdNdT zIm!;cmaJC7OD@o_o+~Xpimu*JU<<<1{ocRcN=~KIkMb8?RV0)~|9SnVuch~;x26AN zot-iZf7aT;10S+g@aOfv>|yCY8R<0q$LjxXD>VOD|ADd6|N6Ul-}Rr}ciuSM=l(8( z@TcdW)Bk08=(>ZpT}S;*CrU=lx>lRTTXw*euB!9;HBaiOJ-*qIPUxR5_4EENS!Z{} zIOtfvgN~0QJoN$RF2|1byB^D5c3mjEjl1)%^Z>ZN%Pt`6-PU#4CqdeSADd;IWcx{U zSnK@%_2~b7XQRk4o8ms>0r0_Zy4L+at~;73u89Ov_w!u$_ikx;iD$$`;x%~H_^M66 zYmbI?U9=vN&ahEu)3xE*=F0GKy47O8zPYl*->Lvma#;3?T#_`!PA#`{)5J`9q1HjC` z&*5{AS$UL`)D_L~+IL!ew=!uP_njS$alPb!Jv#S3@^w7g7Uu$X`+xbf!w`1NDNQOb zf0wJ;x6XV1J@dabDcwO1yPU_q{MlW*{vNCV=quru@?d-DnLxME-*Vz_BYxnV&+;UD z2YI%Q`(69~oAUp5`(J*vUw+?n{nh`~zyI^L0suJv{rBGu?>?Rn|K`6|#%Mm}s0&s$ z;|R_Cp9QJw81226!-wzAhYfW2;g#^k>z`l=?qfY1_uGxqu3+UpgVKJ(vU>HF*VX?H9AE?0WyNq*q6`;;d7L)8=Affz~^dyIvlJ`hm(1X=_44` zcq<^1v~e^&NEBQ}7^495Neo<)@|C*;n|HI8@K57lJR9X%tE;=!;n9Ki(1nxN2EItt zy&o6-8KPVQ|d&FnweS$mfj1ca6T*NPG5TVkq3JU$+-qd(hg!bz{EfrOcQn3TIVGIHVis(%W4 z%%jvZl46 z=B@gFZ0(tiFe=hPR;plReC{o|xobvU^&7o7e*x8k-aR;@Q%2G8@ORB78uNLs@mwEQ zV7}iRmKjaG!P$QtkAPpWBFKU>`g%RrPQx2GFNF~Pn_I4#VKU$JKfjvosA@f{;eI*> z5ByV>z;Af^om|^7{<1k$Jn)P zSxykwy-mWqvW?RfeQps=$eNJTj13AE_N6yg3D6DtB6#CKj)U=eB+YKsg0y;fNWCvy z_#+t?K$71IqG5~Id+j%)aP{+?K?BlUvZ8&XHE&JNjDx+p8oo*!9HC;WyUlMD{aL}H zlDU^BxsFXlFZx9$YpHqJUbD5@pkruGnrfCx5DQlngf|Iei^$e>b*zioe(GKE3q&;77{@Xa264QP{KcUIR%B;i?Vo;~sjN@ziGV zhpauz-$GL|`aJ)#Zyw1KOwzG>)B(7sl2hEb*5r@5{@b)tuU;f4rO`&a9jqki9y^eX zK5rP6yb7XSDU9>qL3*nhOUwFUYZU{)-M!ct@{J}iHx@dxtp9oi_53!v;v2h4HqloY zE1acKs7F^z=K$Vy8sT@%ZrT>~GQZGBDUU)w`N3^Lwq%r@vo!T=A`>n1+-NXxj#$|AqDFLLQB%EQVtFLjSMQA6bS^ z*Z-2pq9vMl-V~)u|7*EAKbANw*a3b6UfMS{I$!qhZ9Z&|Nd^9({2;2jZlSyArnqvL zqXHSgGdfMC0XmicFHI^RP&1hwUvq|)WYh0HKDvh1wfc-dC9frA{CMdA|G=&$*2-V# zusghK{+NX>e_M72y~_XN(U1Lq$(w14_xbLgvKple<^S;$C&@S4G>`tfDk(zlsl7nf zqtomt`WQXjt8G`7|EFWSi4!FMd<4x`9@6Xib?CE7#%%zqfW-zYDi|?&tl~GFEWY9? zpQKn~=YDo4F~c-gY|Y9W#fjjPq}nJh?&x(*u-FU`mAW69kF;R7l}X5PMF5eSqy%R8 zCHhvAiUa*E=|8@$M?uAbkJ^UM6({h|B?q-qOaVvL=mvjP7 zwL*o>FTK1Qjz7c?>38)vlwDIKSyl+7ka;_RnIkMefkO;vLyX?Jc4$BR@MLZ`DrE zHSFot+SG62d@;YrnDJKDq0mV$Xo%w{AN>$b2|pY3 zS$}U9>p3FG`InaI1G!}X0IL8_BKvaB&CTJ>x3Tw2GyTipQ2;_9Z*9-~%W)MB99G@>K%VB>P?ixC|Oxo0qektlteEj!xSKf!pg; zAm?^!SHjuqlO#UrFiNQy(4Kh!y#V029>nZ)*ax4_>o;+zlKkqTmQ5%SjDO!J|7QL> z5glzH*oy&REC{^$hurJkp%@+G&^L4#ZsKgL0JzF;>G$O?5_C?4DvyR~Q>?<1884?( zGb-=j=KF)^PK3A8jJ`Al96qO7wQDM)z>y1%1^JR{sxFbTfk#(l)vUXfO0FrQ^Ps(T z`H5t@oPT{da$%ta!0Z6$7DM-exr`z%6#yuAS3GU5ue}_04z;b!!KoOd88d-H1!R3` z^~HybO9gOD{y{G&Xv@9?m-DB?leEXN)NY*;OF>;Nwewvd!5n_fcq_?I;Ia|{4R6+0 z&xSKe_v%WkuuA?JuX4u5AuY3XQ1B+;sh#ebqm8T3c`|E8nep$B6!^O*{~Q40e;GJDZM00p>ZX7p!;LG{z3B}dqCI8?u zoUA3HX7or^@rv_zJvUx1%{RYG(gYlW&6+7ul(w^?hLv{&Q`dg?RzHIvAfyKCUv)r5m=V;qu8PS@M{N z3UmcQ{wq97BR@G8RboH7cbP}pmqM#pT1!lhF7&avz6%-20 z^~){wWz!Wd2@WG2Ia_lhHodDwivoly+EwsYpx>HFs^S6+o$3A1ZBivjm5x@DUGp#6 z!EuhM+!I~hYv+YB_-mY%B*M5J{-D`{tfC(`jI;H`9gbOdY? zBNz(Gr^DCzyZZB-o?@Rz69j8)i!{8JyK|#>CP6IOs&V366+tw2wko3%hqodBC6=O(A}~%+KE?dRB(;o z@4_dNRJ1cgr)S(MI+TW>=t+7Jl-C0d0&N~~@nPRU)-p!C1&JGm|WH;$q|TPf^hL+CZC(>QcP9rt)@lrFQ-{+67S ze7U}4^EgbkD`+pLl9dAIW_w2J>5?FygTB2L=y|ffI?1g8yjoo+^ zA@$$&pKieuHpW>=qAT53_7o0fCs3jEpMGh->wkw{%z{Btc%lDgH9KBL`E@>^p40Va z0y5^Y4x?h<$wl!254BtRUpzVvzMtxU`JaXUTk=ik$(#Gh@#pkk@>{!dqfVD%Hlg$% z#$)&0LR z%XG>Am%h+G*q0o7giCVT`{DmlwO+xjU|af+&!8-*B*F4}pK>#R~@ZNLeJ79 z_6+S&+o%-7lk(;YD;%q+==e-vo=jkxHW3Z1jb# zk&qJQGj#T5_fR(|f0g*oQT%5cG0@{e@tkG)MyZX`MFlx_=rrfqO|Uk6IExHyZ4Xx$ z;d=6$7LO*`m;8&#E#FrJu#$jGRE%4CwQQqs>UMaZWH{|7PVTXMOR&cYK5?}p*neV# z;;FL!%7`?rxL^KEq+(C6+l-61dDw2BAt%ebhmyXs4e(0Lw^ z^m`1sPY&mM+wFfj>0h2;9`~n{x4!;1db1LJTi)nz3Hs!9+w-m``j=_P_hs;R^3Yd* zyh#pT6X<>Ue_sJG-;6F!;}xdo!{e`C4!hgQ07Db|@eQ{b{mMzM9mkwJSrOoe?-xEo ze&6@`+k3X3bSqkyzuO)FF7OBVFa67347X<=KbiRlmKE&n9JCDvwzf8hZ(r@UR|Nta z1u6oZ-E9v$I|;CYw919g^OwiN)pT#TzK&76ivs1d;njU((%)cns|~(CCjr{>iSb#W zPGG;a zqbQ{2Fa!l}-&Sx1B>x>&GRE~;R97)z`fhmqg+zcl*Gw-EL=klfu>ebAcy@Hz6vBtX z?0a>?-Ek9ef^K^O3gqnplGIj>iweVvQJ^H0NEqSy?%TH?TLHm649j5>>Z^I~P1}_3 z@%moIvYq6bg6-!U6K4627Pt<}HU%QJrr_*|+j3`c9F0{sH2P@9Eb!=wF~P;s9ZT1Q z*p>#q%AGIMUM(U&IWD}s`lO8DvteWMX1KWdV%S-KHQe6p4Ci6V)5n5bD;yY|!hw11 z&)UI_wE9=A6O@h<4gvwE1fA`PkmMU`1`EtDFP;2%8J*zY$tPGuQ>;Bc* z&KMBaC{&`*LS@hMkbI5J<%cSI|n%V{|}&P~4zWI28&%jmpPM{p5x zq(vcu0L6d)W>f_R9I%v_d*PC8)F|)~VibK!N8IJS!if+7&4f0!Y*Qa)zPXnIA(24S zEC~ta&fsh2&T>|PgTSw5t7}JN$>O`TRnlYpLIn64v-Zur9<-pRk|N_KS9M+0?JF>; z!Uur4K+6nc$#%JWPvXJ=y&8=2CdMYt2=#Go76JTzJ_X0;x-kE7!iT(=? z$sP^}ycM%nbKYtPwh-;tTTr2B<0XV-Qcl+?Q1fcMua|%C_8(u(i zs0hY>kn_Xz)~}U}2*vTfWEwrocH-q}dZ|(e35BmdYn(>4ncw+xvJ2-=_21wB82zvE z$3p-4-md>8_Y3{M%r9O4`?7M$!Lt6N^s@dNojYJmd#VWgkJtZ$=G*>p`VVK%>sBEh zz0lE&uk~`J|FFe_qB_|}@$v^oWh@fgk_4kGf7xw+0WU<((Z6g2-KmJexQe$piXJew zPQ^X?&`Q}Kf8&s6zTIa`JSRSgiK-vhDNNH~GEs>=SyV);1Vw)(8)WOx`~R;0`ok54 z8(ybV#lLuhPu(Ut+mChM!vEJAzgk}fe{Jw3o6X0g0z7L~Q__-PtElikf6+^vmv&V_ zhm|m9>ubn(tpP#P^8aVaFAkG8oQu0}lY)n!X6aYgu7~TZV3PRC-;*t?a7bc}2sij& z6huFK;7?~)u|M7(Ao1Tw8k*1Q+Q;GIF1nj`wCBFn9nzoxqL77GC`NAK&u*gh#_;xR zuf==f$-~X<7CQoQr5O6rcC7e%e9%tWlDp8Q;;n=Hi^dXvlNtQ_-SGZ+Kka$_-RLEKk1Pr4Q$}o|KF#kU5IIaM(BU=@)SQdT&?>4|piBo_z0a z9dFaexDvo)059#P-$CNvpa1V*k~yE(e>CoZ#Q&#O07(A(o_9W0zAw-C=W}*RE-x3) z{NE(Eh#8SPHyBseukAh=PNqA|77i&7I+|f4(}re-}r(m%#R{DyVL>7r@5um+f!K z{kK0<X{pm4lpDFXh!e)UcJ-YPR7_g$?%8MdNOS5fwU413zogr^;2 z04BFb!+fot&jbnpvzuyr?}^QG6b))Ap(A5eGdO}T*TtzE#d(bkKDm*!d2sPo{Y!! zsX$}6Z-??8-Co@%{r#Ds!$VgW&4mTp;23~@I7Gq1(Q)DT5EzH^t2g)0A3Ymi9jH~X z2u!QGS#&&z@h>6&I4!z7-uzSnPcBZ{V+AW)QrI%D9T#B6s%Thzk8kn4j_`J$88eBi zcI<-yD)rz5%BA^Uj(I_Ee^>BXP|F@`(_cn9}7FLBszbTcCX&k9mLz0UU<6JAyjjt<~%+=~G$ z^M9GAofaLx-d>%n-wG_tgVXg$F!l4sI>SbS6RMUec2SL^Q7wz z@EhKMle8t>2A!tpD;%nI0^J5o(?0rGu-f~s_TZ-9)#1Cy8RsuSE8fEaIQJ0xcsoBI z;t1T|b-T;E>p{nj?DT8ELptO4vMlzt0p4_71b)|kmve2`d$X<9S;(gL(9Sc;U|Cmv zH`?AG=ws}-bsY2${I)FX{r8S{hu$9O^Z;an{Q14>|8?8F{h+mFp0WGDe~kWjy4Cl> z_jCHMPv__HJDtbN;{(e$lXn_$mEg#t=UH_NqYfPWh|J9+E;)8C3`gb;y{-b~OS@v&P|CeQXdAwaWmZ8(~q5k*r zEd$xX^A5{&?(KANe)(KoSG-=vskgDL|9z4Ip*%ov>K)=_y&Udoe$J1pU zEZdn*vt{2^e=qbObUDS3vwR~P{&wD*Lpt0IUwzWP(sGxR4ke$pR-unu|C6gwYHOp# zSdQIxDkfZ9)&5c!lbhjD61370P`uFwelGihcV|~ESwGmiY;o34f%vZj+&b9HsMZ*i ze!M!`yx(`~6SxTtlPm%IRf%_v4{lu-(X)z5ie43$D^9rn$#!UyHpI?A{475Aw|M-? zBW?59Y&lD^D8}}fAAI-_X&z&6(Bp6*ZtlN*ap++`Hl1#v8{UZJyuNvH?&9ce-5e0h zi^F?--)Gw^9=Ce8`m8*pVq^tD@qT?@9Zo-FtieGZ)bkqP?~jvN`wiUg<2@QFFWJwB z9uzJnF|En64!|@203Pt^6Rw`~U!Hv3d{VRd%4|TE#$TDlmA?UHvg_ABj_q%bj)wIo z3;!=aeDPOHHexyH2TS>-mF4!NTh39J;Vk&?Jx{*+G;PRFCH&)YzWL>Fe)?(7_xc|` z?aNB~)94K7dANM~<^D-~JiuE4&d;L}Im(UuetR9h`R!uG_AHtfmgU4(mndD)VG4fV$d9>P~& z);Wj{^BC*v$*{4o6(Pc8Slihf{`lQONpEH`RS_UZg^vwy9SEpweEk>Yh#E0l6(veA zE~S`XKaN1<{Pn!OIHH&w0XzN#|nn;>8H_b$o*T0}IabF~!44AjOlcBNEALCic_vvwrb(Bn7DrVaC_vYPfm}dM3cL@X5 z8M<01sTqGC z2|xEZ%z{Ij@O@|38Vp9B^Hx!3u2l!s!7ZSykmdI3rp^3=r%Bi^Bjd|(lfPAxCG)VW zEyAjbs!k0n=FL2*^ZM*g>0nJlP1zV5gyfyiQT5Z%DLLL z9zBE|W)Lbk@En^Z^?T{XGneo~H&;5=NYQ{>w&cpV&1ahT-5&mVuK6P0wN-|fgRA`; zym|F7_nDpP{5c3-4A>XB_kFGrV5r;*7X|fbU=~w}$@&V8(!FR#H&n>$dYF}is$kCM zLFV?IsWgYnvY?frC!Y#KHEXCn@~UK2bF*dz>pV`lzvhgKR#kXV85i`Jcj4Rw%VtzK zEjy;0J2QjL=vsBaA=!Oczc&A?nP^zMiq%kO_mNJMSEDc)?RB+|x zl=ve&Dqi@w+Zbx8CEhC_!dPt^$Vec zdlnwHMp9(}t{9iiYgiIk6yHyOFsreuspHdT&MU~&IAE-O!6EseA2l;2tcN*1)-#-_ z3{TpiZ|83Yw!3B@CCiWJo|{A2n(Ie@a)ftg>6I@@nm&DC&aUFwH2>lu&G0wbELxRL z7mnyHOroQBTeK=%*<&0qyI89{NRs~QcNpN0|6o`+)h}ksJOyqEy^XXgaH>ZI>@~uI zp||_H%+hE}7i&cW&<~x(dwO~}|9b2KLah7a)BZrON@CFU>noLLu%%7EP zb(*{WVDN?qDRxknO9HuPhIL-vAhz|(lm zoOe3W5swbAG3bff_~KtUNdjEg#{|dPJPghBTl!z^Xu0eUdg6Sw=UZtCewXam48D7f zrfjGcSbFbvkTgEd9roN1%-8kRn|?^SBimKWSJ_fH!L9sng|Nr~i1~bp}=X-<=1>Ezs}!UsQz~jJ1OnrT_K# zMcrEuy8)Cedrp_TuG2*_CsryyaFG^@2Sy3suJb%TF2cu0AN(o$l@8)%6* zEL)S(ZB}nzOhx{*P#a4c1^-_(#jlc?qEd0aw1ONt)^}?=yX?NswO<9(3hLSI1wjqUmJri{J#i?TpI(-n=Zr*imUAKZv}u@_A1|Jx6!;LhT^Tgtw`>g$X60>Uj+U4 zeI(dI@`YRFlb(bY^yhXe37f31Q*dl zG{$`r{v2l)p~8B`G)0ZrrW_wVA>DMI4XSpu%lo5~6&yHscN)v#U0`O^#iQ%g@$bzD6$@}eu_D7!Q^Wp3bi7b%hTLs`KH|*c#gf01(^!FM6 zrDgx~Gk$52U-s4L4?(W$wS#8zTfW+7`;+{8#p?NGa=Gh8@dotd|LDRBlUX~;!{y+> zOuZa@-(+I)Vo5)cAGc4=fxESX;r!xuc>RYeC;5Oll*VY1-vD=gy861RfsAKj7;2Y zhq>=t5ny%YaeK`L*ncdfsM+2U>PlBT)KiIZKS};ou`Fr1xjk>n)+=URVZiPo1?KF^ zIZ!~$1Eq}GXSS)<`P(ETI3r`M5SFv4qEhL8I*knn}bH&gSB@XaJwnStKL|>*H-4|5yy@u(vN9 zWKIQ=-wxZecf-X5?WGu%sBmag?Jc3y6MyZtN^K18i=B_dYUD#=SOG*2xNGw_<98I! za74?nz7}J2TQpmSK9diV?qJs&KgdOmgUP9&G=bJy9B10uSwk0w%@S8mTPs|K%Cl$f z82Qfw%1J7A?~aDe$;EJ$B*23UB!VlFI_lluOlfTjB%sAz$wM8D)$ctZsYg95Ak>bM z(y!Bxz(LT(Rd7i7D(KMzigCyZ5a&O%A{pZ?uyfRj6U&hD>8XU5#ytZ!&nAdp8t z*BPht$_=jMUQ3REu*znJZt;S-YX5PG8Zb5E#nmA=@;I;Ut_PN zs`^KX-oDm4ok^$XZCxY00<^a@STM|8o{qgsIx4vvCIaBv*VLQK1S53!s7@~gpodYHtO+_50W9^a$0CF_B?}4+wM2P=8@pMOu{C=$ ztj#n272&bhomB!>{plAzW(EbEiy2pVXnlYFc4&`Jk=NIQGdUSlYH_%pJswQh?` zSMaH5gdXcFT9$CbA1@?Ci$$`=P%`s4-|@C&ulGZT^yNAQ6?E#nx=iwKCYEf&R^OG_ zlbG@?ojyZsv&HeaiFT|>6(0z`&9pdA_rX9 zOmr$7=t{{29>GsLz4$0$)T1;`(X*^`^{;I`qP)UQ*|)B{H5NPOdqkuPA28LLrLU#0 ziy1@uU;N~Ml>@X|_!pgFCJ0O*Jpb6_lP&1_&o%?Hsjp@IhfmpIw(qC)zi@{W2`Sn7 zDgB2BUHEhQ@AqZ>@7L3YqWI_aUuzHbzlv+D{Ue(RTy*!oNFv_mWY=H>i(=BNgvt8k!Al6+tR6$Wm4fZmR15qhkl*!Rg}}7yKE#_cB}j6YHxQQd7F@h9`&FkTlcB|*JsH`WZ^b3M&f&L zb(_(TlPwZn1O^pT$|{m1>%tKf1J3pBeJ)^E;-i?!sFOSAow{(dy` zUopG_RHQEnKfi{CThSNs!))czaP;?)+9dg)uK@qiWN_fcuM#({5DFbaHD)s{}TaV*ttjt9P+4YoTmDa&sTK`lFSr;ryoP z@Wt-d{mT8LtMK)o{cr#3H-Gs zKY-vAon=^)eH(`5p>PMZM> zS{K@u8g^m$tJUYMwYD7^+|j3yE^#B8lHyj9cZM~ahu*G2>p{_k)bP~pfaihGn*Ep` z;)UzaK;gCIDaT*<>#0zn; z4E=|(b|U4u0@n8p>uq}B-2yuBrbd2d+}@Wus$2%*_aB~DYCqYokIg5o=^gxz%ChALS&+YXs^`ykH`=s0thj?hFgw&nNpC3QHGh`s+-y$9(XCgh_ zsi4lGT}h|zbZr!F>psf1@Lo&jO*li51w&GG&y9`ToReQa8TG`oqBA>r{roS(1_|AI zJ}Fty0!+!pPo}xm;sXA*^yzyF-^HDplsT$JvJAak&#Bzqx|sVs`6|wGgm~!!J8WYzktXsd~EG?}h&MV#(VIf>uzjDv%gdmeiI;`a4c6Y zf&N$b9&UYGcU?5%NnORI(yvu3pi=~OUu?uf*g1{zgbAnpS6iJlT*9wS&RcRWVR{F4 zMg8}rdQB{aH0^l?gN8cTtqwmU27}oD9J0T%eH^s7uY2P*!|xq2kPUQ|{`k#$sa3OY z;600%*Qi|nCNv#@8ypSnHLZYCj01W?3%!QG1JRETX6uKHw$mMVm4dj7-q{+<7A6Oy zADEid{=*&loXJ@RPc_TQK_Bd5YltSPIp;H2ezMjJHTO10Sk56!7r?7e70-fwV8;63 zHrkruNf0`5{JW8P)w`f459c!ypS_vd&gHx7)T>FLdt$5`umJXnc`>l?xe`L)IGX5A zxFV;&GdMU#b1h1qaEspkc=L9hZgDiWn3N%Bvew-Xj*dULsBpZ}hZCP)6acB5ES^>$ zi~4qak;8^_=s{j+XT)B!ngv_-1m~((T=bfT@F(GTh#k(}W-Cx)@abIL@Oc4m>VH_H zj6K1F3dz=$BUZ*U+INp6dB_KPj}G6?6p;Hp6-^V`*L4IRQ8PKZrM6E=ketgmQ)t+c z7h2bRHVzc6H?7xxEEYS+{2-y#GcS@?cIODN#`tZYI%A3-1`S>LDWTQO7j!Bz%f?G%(#IAcW+^fpM-nx$;d{Dd&-bKPrvIng)Z6jTC=vAqPQO{>nD(sv z_(jaI&DlnE4e_3C>E;X89h)qzn9%CDDh7)ZMs3NBo?l4VEi^5;FfS=VhN z@aC;aJlf~}2}%Hif_SBYgG3`{lirD?`A%4UFBj@X3C15uYxizChkal)3GcPGS-iipRfOG$(?}>7OB52x>h!56eRW}`!9y$G&&dXW;hjSpj^mVY`gK> z-M;7!DvCNR-E;xTRrFFUE|F_vgmXTSsmIiSj8j++8*>xER25H*T>B(#==@Z^>1+=- zRF^FEC4E)K{A(noquuAdz<(37!5rFBxn%NnD2=SEnp7n}#jW3>q)(Irn;KEwg<{jW z3`HS+Z#Cus+J#OB{tS^092Er%L2p%dgyxVR7%$U2m?1qOXZR$pn4PZdeW5@VJ)3&2 z$i@!2KZx8Li#!aRws!R=Ubg;O{qv7h9QJ?L;1XJR(eK`Lm{IX;#42vAt`NB@5it%I zhjo5IT^gQLVcj^TvqQ{5m*TY{v?@L!|(XxQB>*Sn7 zY2KGLp}Ov_nX=uG;zSu7K;89nl>e=o%d`BUvRH-VHv)bs!1ukLZ%zMzk5)sMEf|Ed z>E#K_H)-cq^Dna;ly^A{x2DA8VL3W9RWUbyGS8}D9nR4Yq`nAx937kh@*Gmq23A4fO8)G_|+|5~uJyAj~bgTQ;X&Ukq ztn$HrH`+hAPKywlEA2)S$`0ynx2ZrbBH4TsfR^U~#abg#Mx%kQ$=bzQ0{lo#Wc8uc zFTpY)CT13qn_g>5eD`xcGBr1*_G++}ziE6Nmp}cot%q7SPAd2^J7gvyV`Z&$Fy^-1 zGr$-Z?Di|Ik9R|=3UjUgt6wXpNcs8n_E+XmKF znv5{fS2OvqG9UW2HG~(y9X9k-Pk4=#I6&X3=KOS#pY8_mj$@$$iGYyuJ@=@a) zi3bGj97fUyi&=w$;^6eLwKqL7loe`Z%rQ{*$2oAkx@&LWL{TXP)goOhXK?7N*}BhR z;s@u^%mi#iyX=MOY8KaTMj754zO^DOS4k#1Fo&U*`W-8?;xfbTKjf~vf?!O zfNzPvagVQNczqV0EBj)!#nIKVIZcx@H2v5nBPKf7BCZNLZ$|l zoM2>?_z9}tkg@{=73^aNm%4>uc|U^VRxnUlRIAs~v}J?4PXQY%a&E}00r)a@Xlb_i zMceb$-_EOb;KF0VM0zc^%5J&N`{zPdzV7_(1H$5ry1&vPjOrqQrSQs7o2~A@K}3+k zaB+=j>cS#_(%8qo(kz0~$xe~PhPq=-gH%TDKiIJ7Fa8!~7UBMxnyW|sY0Uj7U1zwm z{dL?Xwe@*-Uc14zoAmF2k)ZweQ-AF;17<)#-h7t1xGpQfhZO;4HTmOHPx)^g&4i4c z)Zu_aj^StU=Z8pn9&2%i3CJ~b5L|*^GT8awX^Clg5qi{fuWcZH?I*o}qp8{N8l<5$ zQ_eV$2{&}p;byr=nX5^8>&pgQWWz_$-w);;QY6#zAC5JNg6^v)H_=PQqv))J946=Z zsI!%ems&!*_spdm=e+M!=Zfw*;uNeitf)3y+Z$}1jcDF)gKINF9E5AS~iZ zu434!@>R;zFN6t4_~Cb&L2lw2Pdhr+pe!E<#OV*V%Hde`w5;NETKcIq-K}_uRBg51 zHwxGgv0q8qPDcX6!Yf1{nX|DcG!R;6$rSNT67lf_Af_{4RuILw!_a=%xuEX7 zyjo>_1DZN=Hi$x&ypOucO8<}Pg~FcKwhG}&PvbD3Z@5w_$U#j$Vd)^RVy`HIMv47T zbJfqj2H(nGla@fH^Zzgv&ju5;*b8Ps`j}XDaVkT2s7kJEq}3BbVD-Bw8*bq$`&FHA z{c$R1Eb2n<{bv1L&sO=+b`cQp3oM@`!MziS8uM! zC!}hM1)3LV^N2X4y=ynJDDsFSrsU1DubmJooKS4GFmXSMoRsC-Pr|V6%plYAxKYL(eM=(3L*`;{> z*`I)+%g1ri!gZAkhE&%JW}s2GtWTyNW!QO{3mJ0mh9{( z{JW4*AYHz@F2BJi{XOuLe&u9CC1k>x`RK@c`S5v99~+qRneb5h_HCF;+=p7a+2qz_R+Q!*XUHT-WP4|srCIFBv>LpHwXCzrRq48=HcRD78>eo<%|(Mc0+ zErxkRX2|K$k2J38zDn5a68`6m1qOU){U!TlrDKCxh0~us)$&D^SPk8i%Kd>S*3vOM zNZ>4KfidY8YIWNm3w+-7!;FO2A>HKJ8vyk)E}<+37OwixdZhGQX0i4J{})3(doV;| z;TX9a*TeyUya4jBT!3YWzQSQ&A3|wwZ?2b~!w}cWw-)pQdcv7%EzoEMf;I&C=HuaH z1?Hgl75+kl6s(%GNsrw8uX%dF^-sn`(-+}>Af6T;DY_u&SS-FJ6Ji-V^2OnxY0V04 zFuSB#a_jY=Q;(E377@z5AS!B?KqA#IpQaZpM!N}5Z;`?gpH48Vtu~3Uj0*$^4{O?5 zc%MQxjg~vjULbt&uz&wah`nl<`h|xb+zxt6yl$l@cT1!yXVmH&y7;_IsCMx;<1e#Y zc>G&ZMa!3W**H1>=lN_mq9u>2X1~bqJ#d@QAi_MFT6J;8cK^a|;FWor)92B6Y~$!D zsvr1yv^PY1+MLxlERRNdhkxNeiBofV-_R1^J+ja%Feuy9$$;3GZsEeNeF>{-`=}(f zJ=-xP%Af)mi8*0C=o0mu`srg*bAJA7-L1we`2|jB#yU-RsAiH^g+bZ7pe8-!^UlTw7iAJN>ZWjH;L245A8pK*}s2L*VeQx*|^fNMxn6-WlT*s~}% z8IE3_hD?9xv3QUMyo__5C};;`%0=S{lBdD_A#W5WF5FMEop1RW2i)VvUxExHwHK<+ z6m829?l)0YxeHlulf0fNk-GQ41$>gq^gA2^OY#nWdoeZwd(kT?itRuI)h(fQ&N5XI zE(&2JAE#@d!fY_HkTV3cYMTmY;{#`|HPeeDSz24y0N>yyKGOO@MNEoV%nbE=M@d+p zK)H1;fUl{$6Y6O;;ueKkAB|nxf2?IIqy?KBj)b8Dsbc=4si`WJVrRp8YLT{OY4q5T z=uv-#hwrpS{7ow8J-ohccK>njJUJ-fU{xt z!l4h?IQwV+@C$^zOBAF2&gRH9yst;Esw?0@2*^qt84afFj7zx@Y-$s%-0h*? zKEPTepZUxue{W`#;JVYlJ-N~0oVCxflU^-xWa@6Q(azK800XR8;#-%gg-8iZyE_z- zp6I_1q$0Z;eCZtg>YWCiyCgMTbYU!-p@E?*$7>XZ4jf1HewWAaG?}q7nhySv_wU7D z*$E^If|lnaITl@dFh2PkWTccXQF4r}Ua1?wXuoVEzB<(PO?bEN%K&Stc6ma-y`5wb zD;F>aWY0U*kYL!E@7)ylad`LoJ$VX}G|nN~=GQ>s>&|T`m&g?^SQ;}=^kJ6-V5v9V4rDKF@xePtQ0!T{q-LTj z?N0qoDRzM#5(kHS1|t^=VHtpt+$d_MNwKv^_I=L zmUaoXlGc;`{Q;p0=f92E!UsB;oW2UsW7|dP@`$#nt##c_CmoLryI}zrf1Dg;+f+G% zCfNq_zusr`BLG{1|53TP`4c!Sr^73DD}_p?f7rohr@j(%1|ASlkHzyP&Vk_b9~sf z8dj98eJpoXb1|e?Y?W&BZGL+QIZOCWGS6ZVzjF>yvG>;XV{a15C0;s{Vvy4l6=w?s zVI$R9@Q(iuVta8b`5Zu2Lkwxf&X#C1s}_;0WTE8G5_`%INJ{v}F)M(l`-#LeQu|Aq zR$|e3EeX{pwQ4P39UctnNl&A!O@wzy9;ot7+*asTgq;b>-86YtnP&gRcG&&9zn#$% zCjp2Cdp=Z2i_Jd%bTu$7L?}0rkhRD=V%C-uE-L8v_>OG!6!&=`;#RgfVr5`VAkSVQ%{kg0qwV!Bj-_WaqXF%Er)>1^BL8GEuM0%SgeqGFeK-o1@txvz))ChOWS%3TCD z-hX#0X_AtAWdu!>z_T3?ix*AM6AKs}47VosJ_0yN!{Aol)IW+u(36m&gh@p2mC*&rs zGH^J=s0C5pzQ-{=UJo4#syj*5Z#f#z*CJI-@3^XB*@EKoAm;@zC^@pUv-wlCt$sh%2*&q)JQcMl(E+I1`^SXAVb6QQX{8h8f>WQ53&*K7`3f`=bc}gQvBy z^y&NbSrb>O8#%jIgyoz;H0g+hMdX(ApMMKojeudGBWshFR{B^zMI9{a;lNMn!dj2& zb~QCB7~Y?b=ay4bWI8QN7Ye9Uwa;yu$f|K1IXX=S^sN$zRm97IP>SeSd-UnTP&HJw zBj|b$Wd0IWNFr?GIIGWV9^B)@Dh!muEN?x-)(LiYP`U ziW%~_3^nL?cq`-fs&mcnWSC&qjP}5SQu&>ugS@`qJ%AbM<^u^jbn(|eCG{6 zM@LiW%13cF&V_{+T<9C+$r9oae3sOG(Uq|s#YYDpes9kBNU2mWjSV-S+?k)3AUc;S z41L0ZX3GdSOaPhaMjH5(pQ^h`<)<4?)1|_q>UB-xx~;X&OdCz?LH^egQuCgxR*r*W zDn>b{EbCfxHtj0)0{y|RnO?7@4C>-Oy?Uao9%CmElk_J2&^xQgs=2W-2l25lo;a6; zV1_K8H(b^?Ou|(Zc^rbr2V}ibX6@GYm?dc^Ba4Xpl3i1oE=ppQa=#a6L)2vgj3ZKm zr>!GbxB1H2kI3YID-Kf?7Gs;^gB9nFfv6_tXGM;CfIRMmBLslDpHX#jqZLKGnhYq? zjZHEFSg6t=Nio{1?h;*dZoDBy7u_9Q<;W^OmGCXAAmf3WJpAaR!?1Lm%J{g^u_?C+ zKoeHQ=O_sY_-f!!loJ4LKCDi;*?fzb7?V1QRYvzvhha?v`E3h-y~Q_|UY(jw5nUz2 zgW$@#t6uN7@66?x*<8=YFGLD#@QPGTZ3E{*or}&5?-Xy+7r>1s1qlz(d`~4$)~$`7 z@^@W*w|o*-N-Bxem-ed5_$dlT2v2rv&iy0w)s+BtC+)WCon(hCPwY02=C71rgo5N# z8dzb)eyZ9skB@9y^aPfDeGx)$=SVFo>DY)4QQx0gvNp?XS@fnFHSM-(X)Wwh| z8w4%C^Hg%T{w}M)#;#wLe&UU2+nvBBGrp(Dk$@{4ay)h{+W&;v2YYq)eiC+fP=kaT zpw=RwqmnBSV~{D*C2kP#SRwxT6Vcg|-!6;;TbGLgDBpG;mK#@YbgS>Kl`YBb?<-p& zF@TO_^5G#WNOftmc}&(#VluebR@X0nhm5vcGm}M<{R;LZ>nf!E?)ZV~Zuv-dfg-Mk z$Rh(hc}d#Y;po|1-5T7W`5iYmm{p#60kkL#xUeOF+RRJ#jCR3w(;IelyS0<6)=h$Y zaTqeoo`=M`QVN0MU%8K^X{*lH)U~uvxy_NMR#23W#*jVZ1O8xaPUsha` zO#gp^iHiKzlw#YgI0{7YgU{ATtE7<(Ta}58u8M*5XJoA=m;%*BnOQP`}X2a3fk@gDTBsp477)8*mf`n@fj>jt}{YKOGR6} zD?zm6h5F7CayrPhCyHynmAPZcrQS*ya1+8I0W`G&bIEq_yU&Gj#$0_zK}0W}wsU}I zkTcuJksuw~8w4kb*ap3%y!Zi>c)@|Z@?XtWB!2eIn`B04I!CA5Qw7(0>Lbfl0>B29 zdD=L>>_Y-T6fZ|8{K zx}ETLth0yLl%FU`@Et{7%^WKi_${?6x;+1M1t7Wy;E+2#5K)V(7BowhXiugjhdlTU zieNra1S{aD!L7%LkqK|&5NV5aj`)UpuJaVFZp-I)!x(v;qMdWXn2ILsq;7~{OAS<7 zL<*eR3 zCZ$r1)0~SR<0&(luKa>(Z#-qjVfF^RI+k~3;2DnLVU-HeoCn+U-pPgb^UPL}<36Ka z3yZ-^sIhpu)$cN9eiXTJ0^xO$`u?A{{@osi$KPb6u*wi3^;q@S<9;brUE)Nv4I6JK zo$+Tx4$!g-_3IgT&QlG9@xPszij2Um3LnSybg(#hwK1w3!wn|naI&f;FLE*x%6)=7 zP8l{kaH~29Wu4t43$u+dwB)t_B#zA(#nfP>bSy+9EZoQgxd9mPVYwnC&Yc&QuC-LN zE0awgbKftfBYMPcgup@Xf6j$gF9k@`ZaD7AD7ihl3qjPI-GoLxP3 z4J{eXw;QNtSus%p^KK#@R@%>7tgoIPTYYjqG?DAUxB4`RhQHr>dXzL?_oNdi0pn0! z^=AuB;gr~Tb)}u3a5Ka!`KLE|?r7-r!uG6&HoibEUVP8Nowauj_VDLQp24O|&&ma^ zxOuE4lkW_Dp>YZao%q{lgqgF+44V~s>)hj7NK|&kTOLDuLKOwW3fG!{>hmENt@oj8 z3+EnR!_QxZa{Fg~EB+aBc+gRC{424&>G#5xJI{)tvFdfsJqQAcqh(n{9bMK4-FH$- zJx{GrgCUfY3WV;l*gG9wK`zyMq#j*{R*}9WO{R}qkq4vL;JnF|dsSD>s!_8$)Czlq z1IJ!nRlXoF;flCOz{L35kyiv8Sx9Hns{H!GfG5jQ$LiOp(jEeu>@TCs4mF!1({T=B z^am>5Pr7G@x5PS77wm#TI7(&IK<;HL5y7D~b*XAj(&i`qBqr;+6m8LuU|}I0>P6I? zxF@n6V3p&WSa1e?>6f&;l9T5(siPdAXQat9z;{x?M4-~#T7E2&vI5+kghlvl*?lM3 ze%~?L2dlEI8pwJLJ*YVq?fYC)5HUuICXwuT6;{p;x-jEd65WPt>*IdvBmQORPrl54 zXjJgRUwr6z-Ir^~qZbEYanILV?CSzMW&hQEZf_;d_}7)UxOM>QBd4i%J>g#XCSpMQ zLZz72+Y_45LG4U$0b(%cRruCCOBS9r{<68__;=Ksw1;DFnVK=5<)igM{w)$<{iVL~ z!hy!ZzA{@U#Kym(jdpbXKu^t_Q=>O7>a-`@SE+lu*27Lnv8bK+ z-~qf^FdKS7kDa@h^o2nVk{SJ`pJ9^;9#s`52|WR}17SuJpk(U?|JAC)fJB>Y;IKZ{ z&LP%%)#EUb*$I-&(qEEje~cR&alBAQH+aUn+XOY=pW+m6sZj@{lwZ(VjVW##2PvFO~3(V<6)-=~hN!Wx1}N|c)=O_0Vv6cHU)<0vqg-(iVq z&Lp#f5J;omjrwKd75pYbfJ_2VLC>pIN7{3KW(d3bsPe~E3oUBVvxRXE&VBFbralqB zc(3pL=(tbP1TOvG$ffY#3`cZWpbSr?bW9i?xd@$A=~93-w;*H+8K(7!oCtwqyyPiC zHgxf^rrJt}_Q_nrZ#H-Rd6h7j%2Hk%k8z{mXNa(RE7WC2xqylvCiE+VeZ~tF^`6yf zgi-?JSs+o7&otd+B>4V=IW{|>$}Z{5*@H3cEN6x@hjT7B82^v$G^f#ymtWS&7#mGZSj;a7|kpq%E4sT)w z*xE$OYQCr2$4A7)ZP}KKS0sMW2;n}j@PHzBE9 z$G=ByZ$#JbfW;n}T|aVQxPExGny#+0skL?^FOe?K-Ae`hnzQy_fX&U=hL8kJpxgLo z8tX1w=|w#tgO3v9&-rwONT&9yqT?=?FXrLG@*jDa8{}B{dVsZ3e`5Q^n>_zIy>)9` z_2Rd#7zlsCzlD|um%7PUsWKi(8z)OF_gZf*g(w@!Z@51m0D&BxK~8Z>X&bwg*ovLj z3?-wU>$VBGFS;8sdb_o3VcMe8ru`79(Xs9kv5HK}IIEt!1SJ{q-})JOe24|)8^RBqPOX4gnlD}fwT!7t`>_4>ya zKP4%>?0N^@zw?B+Ni2bdyg!WlbZAW)QfyJXPS7GPFsXG6^*oRcsv@~`F@Q9xv@$D6 zlZi&>s%~SAjoCyVM@amv_8!b{$bEYHxNxDrgyb>ra!FVDZguH_5|7(jhNt8n7&msC zZhY#ZKGT7RIpSp=&sGK>U;HveXczpNWE-E|{=sol$ZH;XfF0*Avf6Cl`#K&b%o9k&@ z*T}xk%2xgyv}a8|M-c-Uy5C|{;!f+u%omj^%pLi>S7<@P-1vpK`c-it;Y#6P{1dF} zig4gqR-ecE^vKA@DtmCvKapeqWYVph1_jQd$P#r$k+59XzXRHeG9^-AS|rSXse?Q4 zKk5VOUDS}w<)U6@x`WH$8XWJ2{dDHAF!Ttu5i9i}&r*1lIkDSh=&7kyeA2?>M+H4Q zu73tnZ)gm!{;s$eG2o%p@z3ULK7%D~wD(vdX-8C(S}H8^VliRQb7|tL2U6Oi#rni; zSiPQF(stH5*j3yU(}$bST%Goc>U`k!zV5g|6j;xzy_n{E)Z*{qwpU)vPFC}P+$<#5KWCzx8VIDi8O;?ypzOft(W?oLk~`F&Eh;* zIDAFVu9oj?%|U{2wY(_Wf%bavU!_*b5p`3V!FKI#NVX6TD=W>L!lHK>%)c*KYME!W z;h*17q;#^-u_U({e{_vdL(#f3d6kbR^`KPii!aN|>(&m%i2Z^*`m3JUM0803-xxff z!pq?rRq#H>eF)YDS7^EPM@S$u<8c87Fj3Nh^#~xx*2}s>qDoc&&)pN?*jf0Go_*K_ zh;S;$y^yFu=s^I<0JuVMCK`vNx9-q+tvtpVX;0($p#wE`QAT~d+j(&W_kalXdMY!K z0)iH4t3Fk?`FDDqvOMb5ihvQee>8~iT~RXL5R=aO@u*PxY)k+7CpHmX*s~Tesw(;z zgUp$}WEwEWwryomAAL&>Awz%Q(rM)wYq;&tss2+h&_o0yZRE>}8vyI{@NWT$V_KCK zY`bgH!%a7Zzu54HwD6D@fbLz!$HQ`E>t;OZZBdj8F(s%Xk2GI#p&vqgLWF+1qVC1y zs@MToKrYmlY!?0+HD6l_fqrN`d(5by;?E%pK2-_*SS7xybq!EKxY33BZLe;73gRjc zR(L-wXF)LA-F+82=eEFB4r|ef`#--K_$<;AeS1+@+`Ei5`5QR z$PE;Jk@h2=zTLup<+XQp<2j8oMP2z)*E z6Wn=T-#0&nt<=je6cUeGlOpG|u6tbYV7MU#x9L3`auwSM zqaKY_-yyxQYwFH21-EG|G-hEgZ)|c(;D=O7Gz<)5=C!#sqq7@-|9bW4KH$XsK8qNy zxD38NF<~%413uaVuHQjB9cjEIVfep&+zF--`Og>D8J*Gs<}S|O*5CAR#&GW3wp!4k z2oiT1LbksLFpAc8P<7~sMW1%m9@7-%4P9=3~=>MH+EYv?4Y2fHrUXdHS z+vG97f1N@WSawv(`PIRj?o4&!2D~;VJTY~ zk8-25j$Qgo+S3oWXw-wZM6 zH&=C~{Puj@o?zrfiX%c1PtF0Vnsu{=;=G%dSZ6$I`EK&Kuks2v-P2mDbJbc=1%Hbo z;2h~Fl3Q-JWWj+tEg&%0r8ZwxV_@o{Mmfc^=||kb$zyb36`>}uV0)Xe3AuZBjK@C59VSBv=6JXFQ?hDw-XX04}m-ZZ(q0{j~wScsQ zt@>|5ZYz=bA+faTn>N2biHGlzn;EGo!laIL=wkOWBKC5Z6Y(}|GI8zInP*FZyD;lJ z-oZ{U#67_xNw=f#P`gaxv~x5IW6^z;h=fFlxtcnB)iZ`&qZ+qujic9ZWLHhmtruktQF51W+N&YA%_pTOZQRn?-RLhTpwN0-FGyr& zC`*|TtcgRyNI;N{M9X!SvUEuBcTR4j6~aJz-^fZgoP$*YxlZbn$IM0$=3S3H!cN2F zjSL;BnyJ63<3J>&?TE54q0^u(mrVyB+PU^!IUym?8+|Mi7nT&-qXM{648w(PDhiN& z;10vi3w*QS#mY8l#}EeFWgO8?=KS-canSlbg@ac*gfPx+os*AeP25n}J5EOky!Z1IFBtgcd;8kcQ1cfP z>B4ci-geB&PTwCJ%Fg8ahboy2d^5u^rla}oVR7~1OpH5I6wk0NxN}-<9 zxxYW!TX1tyJIFxGY8gd7W~`%e^g6c!!gxg66<8QFnsUOhTu#tyH}7kOgemie8Wg1ArKISHvn7kf2=MMb8IuJ$cyY zHwF~43Xg0dC*1pkL1Qh#KaZJ#l_kYSEwCek6s-8R@lKyls10Bin&;?r27!-lkl+nQW!U8>WnoUS&qMe;MJ zBzK|9_1$TJnXrpp(V2DUyhECoA;kfGcVq_M-&}UkbUYHQ50^2P4!n3efX}C>5$-)| z@7_x`;I!Q^f(z?AWm;GOzF*IC#)3I4=ReWNFk2!Zlnf3@%pB)>ImR@P$>&xABPgfT zk{sd`gO8N84+Un0>SNzyx9*YViO+wy^1VAlKZW@a#(l4R+^)7&qWKwkvl$Qn2KCa7 zHg3qs*OPIWfVM%D6^RFQB65Yvt1L{1-860Rl!LOiTK6^XT@U+i0tvh#*Wp9VBj_Y$ zW0}5To}0LpNZ8U={@>UaJ4+j;tu_B02|F%O`g?Q2NSgpsBERp3VspmBNzK;kKO~9y zzleY;zL6HeAY2=W4U zFs;nj-+hgM8fx(jpAAcTF}n}<`w7tR*c``@w#!da3DYrBkCkuSAeXAFbR5Iz`kN0) zxG&*C9E?t*e)G$`D&gf&y;J4v#{3h@UQzd|Tv3MXImS#xG?Y*6eqt zx8buzYuNom6X5o2U7km)S1J_j+l356*#w!e5htZf+a zU*L##Fe4Q|C}{~mG>FKZM_;zGv%_t&5-i3%p|x`Jg|EZB3dR#AJTCkT{&Jh>^HhzB zE;2G)TU8sV31=`JBDoCLP{ehN4vk`s9D{pihUA72#xagSz7qc`-iq$;T`0$|(KcmAEZJNWsFw*8p=qX}tYH`now^q*NHP=`_c;elp^t4mN6YF zX?h-;5c&KY!HVUH zcRmxbM?YEJy^rqB9XS!j{&dQr=Vl65n>c>*9-?*}!uxUm{OU0qw zB4XKxEIP*79yFMNb^TS+4&u@o-TdzD1<@>*S|4mQEvR(vM+D&Xk8{BGKS>92G7824Qf< zXF7lV^@xw7)}t21en)qk17HdT1tYJdM&~7V8a)S&@93n)d5WhKCKJX6+W?`VY zn>fl9uIsUE890-`u=||y9V(q*76BfYVCcx*boJh(AN)%{4N3U0oO3f`de0f19Y09( zdemQI{WwG}#+T`V1=VPccKD92vBd;@Q9tFesv(RgwQh9Pt6v?|&ovMyrc?ipoRm&=*G@9_tb_OZlUF^~+`r)- zj5P~GFwA+YBEOuvNKWvrcM^N)OTfj@4e&^9N-sDj`+64gv)j)}w!4}^Qy_|jldO1xR)$m)g*+U!itH=tWB=l6r4!3*{JNViF zyw(ndSJlfoh|bxa#a-PeVl0cMCn3e@;Wgw%%9<~As*$BLRI0W z{*c>R+wZvT#lr2sk|fhh8&r8cM-Zk$m^+oS?w#_lXX9qa^TQaSgQM19!l17$tE=Bv za=x`XCpseeVC`uKPqQ#%Ka3xnRvtKZoobR3Sa~e6q~$zI#gYQPP|-RW}}W;BG% zwwPq|!RY16##x&tPP#&bTQ=#zLuQMjHk)JuI)d}lgMf<3h0Ev zLafvyZ^_~dB(HZg>l$cqqIg* zBek{ms8O5RRXXeuMUC2{#EiYS)~FGRYHQWrVkXq4wFyG;TCpQCULT(i=lA^1^W}c- zbN|nET{sn|Ca1)#xw$UiNI0?F41BQPORX6;%R2j5;Fuk4NN+3z^AgB2cVmEW%zfQ zuvSp=Zs^aCDgxk6aVn`Q8%J#>SpyYkh{gGFuL#W2}OzZ#j zzSNm;gYM2Zz0Vpg)3Qh0eu$fYs7rc5(Qq#r!*B_UbOKzwLI0BP=o-IOC;OqUddu=q za%OOCJdhG?l^wsNim^G+WpMRU>g+~~dCWJWYr2c8chKim=Yg1>#K`TFZ1sXn=V!Tv zedUn9?K*Y7lL-cs?^42!d?>Ojmd3nJ%P!3gH#aZQA7Lph^BaXG!yY`cLEHPP0>D?h z?0pA>rE&&vJD2(D3V=)5NN!{KqkG$D)1Fr5jY|>ZKb#wYaJN>%)KfkD4YIRu|2T5~ zWHBF%oJJ<#=TN76|Gb$wZ{1XaDT?PKjw4WK{C1^4^^LRNa?d?2x0?+;{5Dh&U}SmJ zL7RoI6fbT?M1*2a%KmQUSET#;q;E$TV?(S7^H59I+p#GYQHb+guugR!OOJ2%A-{&t zS{UH_awp~D{}M3JlOZoOKR}OgIz~9Xf)KP~cuTT;SYSWx%x6mO{CY4@XT0Gx993}p z8##oBnHbUSvKKJ2z&tw>kD`U3&z8Q*El_0q@(BAPzH!pUb+j0E})26I36=U5Heoy;{ z6ef@AY4&~y33$X?`oX*ZZV)?I7gkIDf++tIc}XWH|KjkWJA+e}J^4hS_o5R&$D{by zi+Yk%?~c#n1xHj98dh!idcVA6;C=oMX0LUd-ZXF)SB*QNjkh>Oy^)wmh)=s3^<;f; zXiEu6Wj&HlSvdTQmqIsnw4c2gxcSKgjR&2%YThk7Gqpd9)tAL379V|p zeUzUEM?co_0Wy;>TvglhB#H6AM{0Lo^gq=C==EOj`Jn3&g)kAiAbuG7%jr;G#`)p} z=2w1%YXczoPWAe1p$lf8ih?z|a_?m6S9_33wN_4z5OIyAh&;oBj3qgtz-$ldUrQb$ zn*Um2WGL!NzIJh$3>Z}*m?_xzP0g}I#>n`Klch0p-WYH6-8z&vE!~p^8n30ZzU#-4 zx-=b3V#=O&rp70(SusGhJJ4P%j}(lX#(QPbnC2A4e8*JD=!r$jMDzaJDsrRY$iXe0 ztbZyEo{SHE>U^{3V^5EiB-;rpbSk@_QD|N(^lIayRY{Q_iMP7?056WZhtEjAZFhRN zV4pl3TOA7!*)6Rao>;s+zY4dnb@~IO;8R%Y7L6gnfC1oP&}iWIdC}F z>knejkD`BeLzKvbrTvvE2(F9$=0byFS8<|FkO^%j6)XV*ra-iU{rL!fx-H%QhdYXj zdUjt<#wL*wR*$4EV_8Hq=CtwoT2S&h7ZM|N0n5zH)nTn2n=JGQ-&Ltzfh!x_kpm~a zst?@LnG)`e26X;wx4!Bv!uFD`Em73&`<8^Yx+}R(fK?1QB}PmM%BI5cW6uIWKg_89u$(1ifDo zR6-C1rPofVbfvOx1&`#GC(&QDr{UVPA?sO^HM;A=Y%AlQeaqBOw8p4R z8%CTQMeyPUWFioET133B#i&!%PmG80?fH3S=daTQc9esqWFL&|(wJYf$9Zng8zsYP>c3+Qvrqe{r|zNL}{J^`P)SBgIq-=fDl zoI_Hal?Xz(WAey2P0UQ-Ji*CG6L3|{XA9zhydYQ+bK^2%{X>o`I{{J2H-;*@47EBd zx4|K(n>X~L$mmRXgQlo~_-VoX1)w{m69rB7ZsX$Q=)?!!7~nJG391G!rX8Qm_ub-6 zmfSI_i?`u@b{&CXiuOdPpJAmc!7FM*WkUDn>RhePS`pgyn2;{eeH*oYPf*P_jnwN* zrAyrPlFh2#S(8rP@xSd6F(!ug8Qg~!f2YtnH`W2{R*~N#_g)=%IQshLUd~G&4LU2E zGCDM~VX-~ZwQ99IFSqWB)cs_I8mYdGf@Up@JelrHolUxCXubA4-NF3xTxcbhD_oyJ zGb_D-4GFaDv{i=g;=M7j6r5-BE&HD!IB>Y-`gZ#kH2Vx-dd$QHxEpAen+S={)^Qx` zns(N@^T<@PbJ|GFGz(l^arO0Lr;Mn62N;yywx|c)dS75GosrMOCM+ zHlDRkPd6_d6%WW*tEU}$xCn@D#tSNrywMnKQ8ij}6&7kLx?F=&;gt#AOvkC-ETK+v zdYAKo@q)k*ku9G?SKq3LdkUUi=mk^dVRogX)Biege2sgGr^`pJFuMoKEF$WYS9}Cn z{@j7bM7Kwx|_spNVGoJaLwTuyDo7(a6*0uzm>#KJ+%eM@E->~(yzu+6_ z&4rizVQ1mRK-rYdCKS6GD+ut4BV~V|61_X3Dxn7Pf*LhIO@C9lmdy6h_NkC&5rBlR zd4JW1kgvBZEjq}%^rR?*A!@3eOeFVi>hSi>lG|Gj$^+Ak;ZtU0=&s-a7v}0F>Nltq z$v3z?0CPDI7hFYkcVmw|M2O7VMwv^N9?I&uB;Y!L`Y%2xJo0!IX@OgIBit zDe(-2981zphe4C68@TwC$bolvIN-NrAm139Mm6s1xOeMTjX-(Ub`!e11t2`TWRB-2)XiwN8zCuxq4!_nYZ)m zXiBd4M_a8Tt4F`vT_76^-de(;nuMV*c75=g%zbwB@SUHWj?Z()E6)dCVu#%dH}qjV zy-CFGu|(`iz4hdj3UwdAY!*R$-|09vGfu*0eh%zO`{yI;w}baa<8-59M@*xh(CJAC zyTqg%NBNGvP@ZHiTyFdjWfW&-yq4n(XSK@Okv5F_RYX=}@?{|Ksw}@37C1ttGe^45 zl{WzY7-i-=wYQSqI1KWy*$|5G+>r{GnM#isW1X(xw@@$&Tt%Erwc`1}xWGtm6nl_? z#6py+JjP}d`6Wb2em4~E)@Kz}EIW7e{75OXx9r{aqi5S(hpD*MEh5h-YpM(~UgB`_ z4@lhYaoo2@k^;nyjq;sS&EpYYt?1EK(>$S5T$MkdFldAWY>K28hOnMRzaFXT^=de= z5qlA3N3I?2F`cc&JeMi(5*ep7v3p%{-L0_9pTQ{v(z+( z9&z026Z!3^s1$g&@Z?CTOPXfZo2oeLXDz{yMXI)z(5};Gq%n5^y>Li@9ff1+?1UnH zieGxfwd^`t?>cqa5NwV^2NZE^>;Ux6IRt-xhW^Hhh^(LTX}Q~tT|Kdj-8%0^Lyu|NZMn)qNj`< z-~`q~a}H%mYMQlgGQtrq4lHy%KYPH42&hXjhwQFoH$KOa7jdG{OvR}Kjh+JB+n5LJ z3M`Pv7L@y~UX(`n3)+Ztgj-pKgO3}-^3HfWf0}=}JTY?rV=o9<^gcOiu|f1I#1Eb) z-RaJFq_P4ouGhm4rHAp~Q#eeo%QNm!;7T)M7~Sdke9rILMRnW~*tIFWstEB*O9$+z zw3#2;Jq1`Zt353DxW}cBZ8$X#x70oT5XEFHk8^GT3cWpWEZtq=z^~ zYKntj3N8%SilA-$oSO)chHX)ulCy7&A5AR51BDYHcoC_u@};bqq2HKu_8K2J#rr;PB1wKpH1U& zReOda;w;2`1huvAAQb%gKRG=p8@`z3rgP_)(=Dt^IP|vWZufSx+Fe8#o+(!%!n2!z zd`9EWJ9e#{%tRRE#3Zn~8NN?I<9w{%)rrIRJ8>I}4pd-|6~awhOfi-eVMZ7yz~-Tu zST8P-BqB~FUerF&t2K$#m}u9IKO&8ZWDIY$M$d;&B2wwOvZ0FP>7BHln+YR58b#C7 z(OVJQwKLq7+_5MXjv9`I72SSih6j%h#Gz_Usiv`#*~bZz%6rGOjUr{HEYH!T3}CH@ zct~A#h`zpuzYk;dR_D%gUm9hoHu~sFQh@5oz9!n?hxFWu=f}H8qnd z3bmgeBqVwi8dh}2_ahlcqj>TPm-61e$)b=vz%g@9s1lw)vlU@MaudC1*n4BzjG}nu z=u5oEr${8*arWCuhDR&06il5LpU={PfA~@PD^ge#4J7-{q?Zcqp+ey@YkYS1JLM#} z+GCCtO_axuM&$)7LRpxKZ#$1TzBAEbD_emJ2NmD4mkQ@aL*5Nl&R;Hm*^z%%y=w@XA2 zq^NQaXe{I^P5L+LQ%d_}#!m^jy5Xd$gLPm5ZwDogJY7+p`uGb}&Mex1hUm%<9PZVp zd$eIp7F@#vW~sQv#VD}Xj`#Y9-~O~!`g5+{(P0E`tH@jQ^}cE?`K2P7**@Mmwa8IR)^e_cP z6c3$qP!}g8Kuk$D!!fRL`p-fU5H_nrwCxaDszsCVOrE8CTi)_!`uL?FeDOzqoxG`3 zpwxqRWL6A26IgWe!`#(h(>=3K zkREL*U7eNjez=E2Dd>1vI%Eamuw#lF>4ts4nyJuN-ZQQyC|ShuoI<3N>w3A?qaojF z-E;0QC3x0MIJmjT!C;9xaTlO)X0@x`%8nbvo7Qk0F8vihgp88y8TJ6Z90p)WQ4wn* z!Tg7b0z`)3uJ)uNVcx#rB@YakZAqJOoc;Tj6uj@RCP#Hk_`>Zry_kQGqeR{Mvu_8J zLxxEH+a>qEa7?kSb0J6SQz^k#fIdpE5l49X%gmFhL;O-Lp$P0k)O751@7e={U>uXJ zo!nI&uHXBJ@0us9BPSMv&JizsN%W}92R3fG9~%Jnzgyy`H9;QVYHA4{A}FosVei`u zQ+8Na&6%Hwk)zvmjzc6E<94`>q1e?UTtiS1Dw_nO|5VZN|G)+^)>mw}+ypJLrQcGR zV>$V(`FITYMp8h+U&^V}5QBM67-735knGN$18>zWioJ~^L8!4SZ6Ho&Q8b_I3PjT6 z2T=LQ_UBkII0t%7s72Hsw!m;`14`8Bv6__&V;8f|!`g{dU#ad@5ANBIn;B0}eBAuH z=!-eUWvpfhdnf*d=0abRRZWo&J90>K_HkdxO(%Y!W)<)yCXgOSNWltvz6-(9RdS6s zZK=Y?i%`9M39MCyMDAL(JkAuQy@C|9O(t001x>x`IR*m1ZDM0fp!8aaKfS5G-qLJ~ z2@OazP9@BFp!Eq+)5BStO&NpD?B{N+%tR!jD$F|l@0G*)nnyGyuHZ5}*>JcX4`ci# zNkn;=nbZqg(#qTzu*(Bv#vf$#dvplYjy>Tz_O(M+r=2 zT@1oKJ}3BO87VR5xX@3SRSnz#l#YRV!QhmjfE!s6L%Mq^Zp$CmoPo}T-cu@Bsf;}y zkX+LQUtc#6A%0!yA0X`88k{0;=}XWU_Xr^ysI9V{yBE^J9=0a`0x``<1i%U4!MH=4 zEm7IWJ|o*f_SlLQVbb9p2?+hbtoZR)OBRpKxh!xz?MSe zG>`&VsoJPEZu!D_U|#&U#&6+yf!Q0Z@3jjuDE$Yif-7(n;b#J$J^Ng)<}7-BwQvK^ zlggeCWA5BS#B{Whfx7TlU~~75;{`wO5!Kz>IrwqV$tm)}*C`RI7btv85V(E}7RWt79n(arm_vkS@F6%A+?6Tt_N{Iy-CLSWJ$-+2O|jI~F?@W>Y(bLaq8^ z+7jH^hU&s`)h4!1^#Yf4@||rS22Z)7wh#^^fj(`^+@^Jxx@e2NSYUzX}3fN5szN)ta1YC?e0ICOE9&(aI;}rz z+#R_5^{~BzKDg;!K{$vlhGdldH6g4)wiZUnXf z&Q`^`Aq_XPPGl?uXm%w|%bOSB$8uNlfZ&!MDZDl*lDX?^)g$S|wS#k$@X@Q9rZ9`c z4yWx?LvQ-JCg%2bqd77xYPP4oH6WRO{_OCbhoVO_p4Y*FXBG74T{*C`ZghvCXF_f% zZD;A0c;h3-mT;2)`phXto1+8UHW?VoVC*&!C^N8JU-wPg37HZ-!LN42ULac(?FDD7 zfjNHsVmHbogKmmZ!pg;9oV(^(eLeQeW~*^IZqFvy8M{=c32_d!@3NV)v_oc--V>ir zGsJPIPJ{j7Z~Q4?cY}eqTd?cOtlN{RkFp8EaTea7k1q&8S#z}n7r;ZAFYHb`t9Mc# zoP&>lfpTOElw_B*xN`k}t_o89{+L=@|0dPBXW#7)!Bow|OLnB2O$XU&qOl}b3z;EI zbv7&ib}Sne65KkuJ%yD%t{N%*iHv-wqn$@ZGQan7TwLV=*Gzf6whD*oL(<@QS zged*i&Q5>jwU6mxVQw&hpn7)KX~@h7PM2kunGM~ehq zY&PKKdXhQOg2D3#rW*@bP5Z1L`4@w%Ig15KE>uBi#ORsp`1TRooqt6F%e-FDC*Vg0N=p%v>;w;4edS9CTz4KU^dn-ub*JA}URK}fe-LR_l zMf3s#Y&dj+Jza$#EjrOrWl|8BD=5nKfl)-EWefZucs6<1w%*n<{1fR~^o!va;#0A+pg!zr&lrKIwCbQo+Px8}KbOy82kpJ4A9lA0ER?dgznU zB+cerJ@n^{Z!{bARF(EvMX6(waf@6)eEF2X;jCBPTrti9{D$aREDz&lB5`+LGIefV zo<+bnaDjToeqcleembCcuJLDd>Jkt9^4ytLWea-*u~a?_T_Rwrp7Som^}PnRP$H z8JnI~%gg&&aKg*e(igv9*B@=iJwoY(>4T?dU7{li+b_|zu`I|ut_XK=xg-Y(`zaQe@WmdrdrUHjw@5s?LM&-o#T*_~(|G8auGCHhRj>(}d0Q zB{$eB*qTq6uU=7Frcj=VaBuH|ge4^LN_p+xOqqKe;q%X$M%HSe4#M zu!<|4NrHx|RaPaY2F7HRP5%Bk`^non7koyzrbfse{V1?7S@mFTvnZ5Tj1dR+Sl2P% zXDxkg2y?^V`(T#Z>-S-O!`5X>ZgkSyyD3t$Ag#lxi3oT^zE0K)u*L!Zg$AEX}N61zYW%?fH?Qe~l!2Lg%=zaXMH^F5pd` z5ncG*b48_p>A>Up)8*}{$umV_H^FhiBH;fu=6Z8 zuKbW5UHDDCw=H06^cLf5urn?J?Mc7VJVVwSPQQl|2(^UXvJgT7Ap-gFUKm&$XQbJ& z3U3%VCc^{&f^Cw$J`z-cGWgp%kd9Nm!jla z850qiQ#=*u)0ETP zqc64?blHtP4AaqVfILK+Xxz(z0xwT@S4GM2XFI4uvUQGY5*Zv* zDiJg!P-HaSx7os$vghYNV;7}*zt7k?l=^(()qTFOE%0PEQJN-X@(7BMe$3$zCg2&F zyHn8XJk2@08nI-de7?3~0eH+M!A6^LmC4Taul2HE@<8%Tb&uZt5<7C%VKe(v--m2v zr``S`*AcQU1L!NR79KpGe3;!TbpsBv{1wVrGE4*#)9>qz+$sv4KXWyR^HvfR&8_xvps$KoNrmXs>AtEyo_Ogj?bTsKyTnZHY2($0 z6jG{Si@1Zs&cvw6AI+L3l z(3V4Px5MXlDCCm}XNcsD$*=KTu0zK`^!U#_{m-o?PW`LRDM{VaN-gcH&YIkv^fV`X z_kMGaDw15DdGl=iTl1}`@X34lGF%bFzHUWFxJTE{*qOWI@GaX`Xy;Vw(HNcVn77Qt zTmXH6C{!O$Y5eSs`$@3W1KhRgg7cr;)!(#6kzRT&(Vg3Dkig54t`2hmxJWwJ-bGh$qh-us`0O;wfy` zb^qqDH2(TT!O^J(fha3a;GUI5$K0xMRkR98xcj?msY z=XBlbx$W>tcc(#96zT39a0m<8UhA~x#g~vS0xIgpm4zckaEE-3FxW?;)ar8X!-XMo zA&(irlq2WDPw{s;FYkxJRlfE4NX?C2bJ{{b$U?H%YFVxE8bIGbOzfk+=X20 z9D4ftWbe&&R^x*6Q6R^P4vPAo{B3x!x3e6o4Lv&3@k}Go6xLy7JG1{oWLD|{Lz~B6 zU1s^bdwNp?Q5U$DS{}n1Gh|=}uaG00uz38tqIP$?&io;lzNd4(>@PF*09dMMX z3WphzEi{0g&zr3@b!by;th8X!dxW*CUY4OSWv?Sw|3e>5(YiW}4>F;Op}~H_FN6A= zm*OW2uX=pjXZ6@ua#6h(qqaOW00wq)6~~qLy9q3)fObHrYY&MY0E_koD*newHTw#l zeYwYoHl&l^0lhwt+!6l^&b~iy;PEYmqB!}9PQ__O64a5OLiS|1)^08;Qur=&)_ zV%dcr8Qp-726QHwfD(;v9og&tL6KKF?EQJu@#RJ7*I@UO6PEQ39ZWjmqh+6A!Q~y^ zfTuP4X-Egm@v{$!{=94A7!+YaZkIg6&v5_;9dWmxS1GXxf%#U*|M))WUVk6Fk?T@% zCjw7uHT1UMvkQDcn2*L!6BN4#M&_LC%#u3uuLWuwET)niQ=K~#QwIsYVwWa`L8`Vy z*jXoGE=@y)NV1$fBlc{)(d#D@->bZWh8Cm(9yrV;&qOz11RiZZT&Z)J@W3D>*af~|9=cx}mz&~X)5#DN5wDYDWY8tJbXj7gY!a~Efuj%~! zO~dm-bg|!RL2Uo5--y~6Gtucid#B>6N*5z8-^&+1bw@wumgC^W98-tryfHrD2G^rp zub3AnB24>6B7)omqE=)XaLudCC~W1o=_1IbGpy`Zs=5bHycDCfhBmRZWn;6`>wOC< za9b`Bf`neD9@%`}Yv(9XLr!-@&-j89a)ffxoO6OqvVGH8e3NGP`WdG7DU?6MjbCxft~q<+tsx6|%$G0IYJV9`>Gl#h|)u(b;1e5dcO9 zd<~&%8G~R8{+{ujMAQ+jw}Z35CDx)G&bXjfF7|e*MtrXsSnk=xxgrYc#YE~$I0a)X zlu6drPU%6ndI#P0y*uy)+b}um=#6*-D)Tjyxe}6l2KOVBA#`NB<*FJ)C`Fs=wnJFJ ztlILF8l33TY)7%GB%@7Q=&g_WQc>JziXEp%@o$A|hM2rq>(X<_@dA@%hn}VQ)XT1T_`y}QO zMFyxXAVM2c!m__IS8=kD^J8CYBoXyGCHl^3A~|@iX_5PGxV6~rT1R;n)>qR~z|-x> zM(@Cod#dYyUq|`ySR(zTglNqQ45vKj}wbCo6$= zDB=I!27Qdfxmx{BZ*V{}v)+qv1RZHblH9y#d0bJbAIXOb;b$H3H2{8#DTRG+m^Lky z$>e1SG^qKtF!VgAk3mkM;3Gfd>H8d^)&bwd`p@^Dtt>W_YREETn9|$4ev}k%YwT<7 z`cDibRXFrF=0x(gEgXH0Ft__=__Z)@E=`oSEmw9$oP^Q!t~Zq!sNyg0 z0yRi*jGnlp_~b177)Tw6Ws4sL+Tvp2&^14g*){DXE{dbJ%+OR{%K}-k;pa*N&p> z3J8~zvvvGjcz^2NIp`HxVE}Zit_1AfB{|1r`3G+gxKURd@ailkir=rOUmw|IWkREt z)Alv1w2A~%WhI&E8JT6&QuI){$)NQq_L zT56N*r;dY+ECY|14C9!s$Fv#iZRnJ!8cM^Svg^W;(g^|u`n{>zM{m6Mz0}r(eHuxM zvnWA{V<%}0u&v=Yn3(FMO8%2IegtaX!Y{QsbN9(%lxj5}H0wUQ6^XfrzztdTZp@{2{KQ%HcFP}yw9Lgv zFnI;9c|rKV?p;j~ZJ5DpnSs%h#O+aA)g?e0egy-C)mX;8?+{VmlRmvOP zkt}a3jO_wqpTB76c-O`k1K1<@xX)n3ABKi{xUavOkvm6(3xYPd{WVkriUNKCQ|d>e z(A($(aF+E+0gvLLr0uTiWfFdwRo}F}tY?Ki;#l^L%{op;Ut~MGp4enjFI#ih5c_j6 zXiMtEOTgjWYw_;;o<9*v$iUBbTp511YaRi?T95*8o@#qjggsGjJVg(uHC1_M_ZN5h+eY;sb@b`#Q%z&l6$9T~x&g zzWC+__t@Hx&uYMX_z%1)mZDG7I#(nU1-RZvQ9s(dwR|ybJv68pingz>0A;sLh)sL* zK}T zh*H#ZXMuh198t2!_n9e)90cyaZKw{Bwi;?~kRGbY(%g90@6w&&VLGFG)cc~1$0<2z zgpKKrFyG|jplyA?hZ7l`NAZ~E50r+|+pe~)b`@D#dxQ;bXuEkMX!Ni_{C$2%Xp+6=HhXd4z5VQAMgpSSB)s)?A)htTHO&=iiZHaa z{RcMnMtOuX-7xJ?weS!26KMQu*1h-n&cm;-5T1x`;7{_1?+M#E z_t!q$Tg)5k!JJ!jrs;)0yQV}Reoj~I$~v1EjFG=9kzqpqQAJPCj!o-0oatv}rT)r9 z#h3`C+3!zJh#oNowo+qWC-#WqjKXgS2b0gFto6twzBpH)Ssxd({8&EznL?W6b0ZC$-2}QaVblmFiC!f?APl<2UM#=}{>YnAd_fRr}`qx@M60?&u+N z@9*z+Ox2su3io=Vr*lS&NAh22623Vrsg<7jMidPFp>=mZ>$ac&&_%CCK&@nw|6_nf z7up%mSeXlz4B>@!w_}4}Kann%vJ92ZR$*bMetXWoLc?EHB*;YZ$LPniO&JryTtU8f zgQbIjLT7H{M)pJg3%#)E?zfsjDlU~Fy&EA(T;xvQsHvsi@9I(faVZQFfBf#Vrq$@i z(MNbxuGg?cdS%x2-N~9FVedNO#~t_Z(J9%5)<+_rD$vVWOU6+5r$iK_5C1@D#W}f4 z#YWzZIsKc8d3#!e@O|r9Qbw8}6;I0dW0EELozpSYs{n?``mx@J0-5o9aLS)vTxFSqior19-5U&w?iJ$$Q$GS$p=3{(%aSo zpFI0^%(d&if(c8&+<`3k0p|PO{6tq1aZ~Y0*jty3Gy3+vk37SA;Y?K5x3#G<1fM-H ze=HQEV&^mp_b--h_5t9UHBwz1ZdqGK17{a$EaF63)?D=AR1P8J30|GcDWCi}~H0Lz_8DP0&X6nyV4)72bL?W?Q|8%mVesw$T3O&B{qo1i=ccp9gM z-yU>r%s(Y^m=m(m0SR$e`j~#j9)8c)*!}6vW8171bM{SAoNRbPZf%upZIU&r(dW7 zRiEO-zayrSUlQrySSF|aFfq7T+sag=Uk?K}Bne+IR(=i$PDM-!h4VDl640Exm^YY7 z!Z3wWo>Ot0li^99H3owE?I^^iIM1A`b*?I`A|WQ=(BFEO@kXB^RI2-tPmV`f-Gcb8 zRFN*Kp`9Stu7)4v$$|JGUWcj^>dUO*=mXOvs`3I^mH+4+yv~!n@a#QH3suJg?3?r$ zi0B_fvGxi7M8A&o8^8_NRFlU5b)Nuvvl&s?R@-L%OK$Z({R*Ma3^il6m0Dk(zN;#G zhf72Cga%lm0Y`iIk|NkD9Ybl;Yttox+M$*53=XgDdQ9!B7k({HnNx%2z>SG`1odOK zLw@l^jX%-TFC_m2k zT-8&?>|aM22s~A_td&1EekTYrZ{JPF5uQyZ_1c@)biRW!h__ZuaUPWm>W?wC-WO(6 zWiXIt(@CKM%fqDq-C!k9sUh~h$rp)}%m``AL1@+XbERC5nQr$NT^1w;ufMF5EyyiD z6;>13F@WVsItnULT_Fe` zh2+Xd*Lqcd4YDk*Ocp=?ALlZlfr^S)TkL)r<ZEWel<5hV&DU zN?l2E1v4@>!f=l^R&ob?3z{$Qr5%9;L-pqx4}YW}GhX*_K$6vSv+W zpsL~+x9z)*_&L9{Myf`Hys5^>bE$q0V+-JalWP>0V;*0WF#WG>2I`C}3QNk^5ACVxQ3fH!^>Q4!-O8k^sBBj+3C@mR{h)3`XA z!64_8SN{yHo&`+yXxW+X_lGx1k8>x>zkkjUhVS^$J#54^+4V8NzEmWzzLKW4)-H8Dmih zj<9|fj1?0i|8XQ8j088iGr`PP%%-|QGeiP{%lD}+y+6h@-s|~L<{-O(7JKHsSr`wj zu!O^iLT||Xf@z=6Uo(z)K4xn4Q=}K8d9AhVE_%I_$=Pg#SR}gXpzibKNp4bKZ&ehs zEAjep>-|t~O|RHXgE4$@P@Jj%I1;5bVX^+b-p*YfSSPHIb=azs?BwV(@LGMENX7ro zTK&$$OBFGA00Wz&K;n%&%X^XEk_G!;M`}U)4tD2)BYihFGN!{VSZNub8uC|J;4)4B zGQ!K;)X49#Moj8O^efRX^z&ZO7lzlyQ?NT+J#6M%z?~;J8f}ptwyxz`vDxz8`H{h;(Kyk@1n)UvUhFu z>M1bkFE2Y7sXqI^IgbPs>sVE9l`cwLYsl?%`r7-!^q)L?r?eXPbCY+;>ZMmYGNo3^ zAg^_^3{-Zu%SS~W7FoAu=1<&li^D!!PUqaFRd$B#5^Q^D6oRV>mwHm1H);e%&H;S* z3qtZKF80gj!|7r3T4p4Zlv}nkNVjugAN(CZkbI#|HEaLDzwc}qnUck{$imN4OQ1tV zhv$hT(Yc8?y=X!GKws~@_9?;sT(&`dN&6AD>l>lcdUw54hyu8tf6Y5Rb|L1FQj?mD z-fS2yMrgP0sym@mIXaIvSbhy~1QsPoRV@sYx01pud(R%Qfin4|*=XBdvJxW`1%`zlT|e>yvqq{mal; zWlC1TH0gl}(Ce|`Ic7MOc#D9aPyznUlolM_)ecWB{zU?J=qLa4Sykk(cByeoUaPrD zcsV*~Y5yk3Xuvw-Xe@KicKXG=L?Au}Xel4*+O7UPau#&qm zi~jqtDHQ;8BZnRs@cGIRp^cJee5o>|V9I3`{>b|8oOr*#g!IF1-M;7Cs8utA>NK3u z*9r3s#b2vkIG8V+sWi~q-Ceu;t!vy2E&3#?CGXGh$` z>|a|5S66C|RDynTJW_%6ra=84@rIONZj5%?mKP1G-mNBkBzd((7;>KEcUhcrd0TTA zvQk0R>p;4d>y8MM%PiEv*IyAL4O_$%a;u7^eoSx*N;43S+IO(%V#~$b($QIzyp5Qgu_hB+~=mq^St`Us?AIU&A zzsYYu{Y(NPIH{~`_MfDiguGFSGu6DzZ=$3DBLQM=?u`{7r(Z--I6YP!co`sq$u`@` zSZFW~&WfhDLsDZOtVZ>+yXU_NU>qPvao7oFAatV+ns^?D&7XT7;gG!=)4y z;bEibKqZO)S#~y)0J6N}*+t8i;fSpo3q<>XtTRUXU8Uxf8=A!U}a=Ixy_Dj08+$O0G{;_qXEw;UsWjcugMNSUg zot8OET@PLytT|yhld1TCL57~pLWU?Y(0i68F2+G--sr593+8ATHSmE4eu0P842Oe^ zLb)wt7UhZAXN)|$V-7_|)`C{;0Up%=+~GqXkls@$SR5n+jEx*3{HN%_Z#$Ma5{|Rs zQ2DY1?ux!K9?*sZf^M8Gbkm>ZxMvR3W>Ul#cfx+36#|5BC;7}OXc#{9&B<={8~hv> zv(>k_5~w#8u8acA#+6RS!T{}nAAF1h)nVG%7dv4m*=Fp5`p>qJGb5;VIbzTK^a&Zr zS5J%%Xd+OcAM_2J%-&cZ7+=3%=RFAGIvX#YpHB%e)IZ4-cs4TV@QyKkj2Ar6>U6;q z^xHsz8|T5t7#qIo6IoN~=|W?tAP0WUWy4H{Wu&>E!V9oiNMTTLEK~gpVE)&d6Wgtsjsx_w6ULzsIbd7NdMDgNiyhi z4UPOC$27{1C5w^)@RF3l17yp`&}W5g9JnXZ8DyJtrFz4TgP%8KGi%^9BMV$dzZf5Y z`vIpP@P7EX8|}hj^g(w*Gh3utHdDu4{~0rQ3s^tY2dCTHr9bEZ8)NR*J9uG=F+@k< z6=R;|P3Hv#I9$XdVbcG>coE)zaGKEti{I7je# zlxyga|40Af7w4hh#}S^=SM;AEvGFm{e`_a^b!hlY^xygXSpN@d>o3)R+TeQEe|!Z+ z66c}oKRS!Q`TOcWI)?sd_cO_;?$tQBtU?#`(QoGoo9R+L`ZxeTgxtVC>y!2*nS5f} z{lDwKjg@?+`CHM44S{a}xM#8(u|GVX5%nKBd<@+-!C%@kTLG?wPTJu&u;Dpy^`G$| zAwd?5---VF_`%c1dzV@6b-!UY1^(+kew#e%H`loCv$roxsa+;5n7jZN{vRLZbkiSn z09xRO;TQdY^)s3HFy2T$my%^-L~tMz#98IKCCy;zz~`T|*}57extHKf<%YOtvOS7bFuTmAO*QaAuPkQzn&&iHNVb zp7A%{K!^C1_W!goAIDgQWSZD$)WDX_`^6MOT12x4doF!5XTC!yXx z3D-)#*79deDCVU{#Jo%<5=%q#N_6O^P*Gyf*hQNnnG`NI@IrT?yp>%!vrnOu$O4YX zX#{A4_`iMHwz%8#0t#s3{*6sU9`aXVHR@UX|LS}Ba`lb-4X<=(R$r&`wb^y};m0KDRxUK=5f9~95*Up|w4K|o1XME>KY0EY^6L5cJ8NPr93FlqqYJb1s{w?HmM8TD^DWX zpDnkx2go;XZ<+X!oGZciJ#aVNg%V$QOW?(G<;OGZu;h3uADyp-v2enZC97|e{P!F6 z7dY(W7y~>;PttD*d{ulDJWl=r^szgIM#W9Z#67vPC;k8le{s{ZJlzWcz7l}zSY43& zU;gK(zokKdnSV#P94Y~lapyPZfBaz^hC_@@E#%fSt1_fl0ib-9+{%)F0H%=8JF~)S zYQ=!NyHRMi%HjHU9omgT7)~~3WMBeqv0v({Ts!`*c#RG(V^xW6o;)E~*Q zNHMocwo&rUE*IM8&%&HwLcVixsLSw3X=Lpv3iwPszaNG&6nvLo0mEb-ldPSbP*KKe zt#MV#6=oWPv!;@D$p-hcYN1jonKNU9$5g+Wy&g?6;?F|IBpBz4mfF_$&IMoemov3L-d1KV0V+=kYxL-Y8(BJu8qT ze5Kz`6aBQHLH{#;oJU><6WJ);3lAzaKI^l!z<8-+=-d6ZXl_x-=4GTxs?;upCYGla zsx6}j-fRyIU8lfCMxOrAZ`!m(hrVg-ia8nHB9ClTC9fJcUB~^<4Q~2FFi8>#?RMQN z7P(yi2g8Y-1Lt_G06L)uS_ZtuR?2j8^+lNKI1|3`t(aG^&oiyf7Yghb(Q)cH{(HJQ zgi5t0oxKnBj_jENv88mh+B`8HKpR0tuRoQnD=FH>@nQuJbg+uY=pPNOuMgMXgz0o5 z2h+9y4Vi=&^pCNGCj@OP*>?g$^xt&^e9(qGa}Q(XdSOA7_zXU9u;)Cqxt-t|f+XYt z-9Y9P!X4#{jeFsxZ*%D`?IYXBA^|D9qEA*F6irJ4N%=veL&w2^Z2^C^eP;TPZ7~}o zzRWio9|gGh2xz1)&U1c42QoMj@4?40@2j`#x=jBF#z|mD(p!wpt5=M_T*LXCVgz*GZ2-UFZ>3r^ z8_Src$BW<22il+y+?)2ToM%JFathd1nUgS)udhh%;Tdwxv#BhVrLYa}!H4bTe)NOQ zVjA_ENBiId?epnm}AO5lQA6(#gtp8@`)Mi+A?Ge47 z(tmu=KSci-m)%bBVddnH^dElM@50HEKiCWW5clmHWVkTj>a27=Q@?l|L+B*G*ImWTy1vmm z592BNudxvhl52Yhka&Bq+~L!g=T;2F*P#Ebs3GR1;KdjcqnC^M@a^ldbc&Z)N;cN= z13@-!#>(t`czE-J73*s4OC_6%*<~-hSVd8diP6!l7%F-3q;Mf#kHh`L#*%jMFga>8 z@qDRZmn@YJ`IeIOz43|-8^oBp&Kpq7P(H^>@Opz4K)i6B$sO@=GPZsW#@G<)op`{? zaEb#!tHpalipu$TltW6K0#E({a!lW|RVwcj^iQ5e`2sK7l2zP-oZ2NPEfkdt?MLCq zw{a!FN;wsYIM5v_UKcI=CP5!AE8(*%>0q+5pgSN|mJBAF0~7bm{NMDIzi*16R@_+f z4`9349A5mgY52X(+<*H&eED05puy27HV*h6cyp5tS1l2&RzWJ1P$ZtAn}z4kzi+6EwttoRuu#r%+%zw_GAckzdbV~NL;etRJuyg8@C6U6#c*w-rImQ~ii~~Wh@ks#v@Sk(w^1cJ~Kk7x>XmlKt zVONMHiv%>uW{~jR0w~>wj#?#Myvyb!m!gT_$1CInC*UTyg%0pAj;xL;H=0M@fD?Yx zuk2xN{ATqGg++o&?u8cwiCiNT7Mu~7Z}$oo)i3ax{OWpi%k&?;*VwxL^L=3GJr;u! zuoXmB!H?_P`6ttADyLR)bN75rE%V*I&=pziwB??dbKsdVAQuBpq8^t%r+ zAWG=wI@`L(Z*9VJ=;B;ONeUbH!4vizr#vxGMsN8V@``Q;w^<@B(J?`i$7 zDrrQv2)NMy$uI`}+>4$A+~Z>oJl22fm-qv%Y5h0))F*TT+UO_r!bkK0fPc2^Tgh*w zrKCdri+zy|l{}!oj2CUNcbxzqIMAo*Y!LR_L$r<3Luf+RNeW2t`Au@nF?$3G`KK?! zP20{NaDw0a<@#?kTH*=)XI!kGo5LUJKmDSQkM-YdifA>S{Uho>G@9(n&bB+Jf298; ziRk}M$w-dm@gJc74r%>|Uq7Y)@BzJWnSgHk0ZE!yA|9$+^ z`cL5(7>}d=Q*bxl%T940_aKk-Kk7zYRp9!++YA%A%oyFs0g%>z!2LgX*sxKL{XZLh z^f5O56|dcH0;cz(lluYM<`}@e)~|&3AJcyd-dqQ**i2TYt`;L(J<2RKqjS z)j#NC6+3hg^V$0zhyz9Yaq_I%4xMI<%itdc2y_&EGCqq}@CUhIGKpA?`+VjXJULc8 zC@*00Yc!pO(^f@%SDc*qfAo?6bCL( zkwcdAt9{{OqljkXhPs`2^i_XA7r=c}x2YSdYh|Fc${mFIts^A0-lY4TX|S0=_UntV<_ z&ip%k{f6R(Y=XuFAUC&FO8R{e|8nAGK{+_dzvueL6#)PBzqtA>OZxc%QOxf1zh6jI z0U+t$%18h^4a{kE5$k0zu%porw3moekG-M#ezElmEAGn2D$QG_^KPP9&^iHvjXS8^>YX7r&@~ zFsKaDUdD@61sq>0kpU0NHyA|2N88}qi}?&Biia?rcN*czljtxg807gpQu2RB*CL=O zB7wzp9k1JLsuDsTC(xjf6iNXo0sza!*n}JKK+XZfK3ioJC@{bUQx?G9P|ZG3j;s>* z@qA?khpmJi<3+$gaE6jW6O}tFCa7(GqkxmunG7-tekHml%O^gYNRv@ZWjV@`mW zk#QAItsoH%EDiwYiXpVV$}r#v-(0gSR{hYJXR=g1V{*P)twcY@Jr*uV);IfVsFf7F z&smZ-);T5n3dl-I$l(F)bO$(JK39eDSsZckc3zTqjze#|9{Yr0z~N!^`R)AlJ;^^{ ziivR*eLPzvdoSb8y9fGqyqr%Qw2TW*kz|~4paN?z&ELU?!$0k>)fnF)7h_X*{fXXY6lHjz! zOJBhSp0x}pUz#9rTdWTer*x6~>}68P{W#(+=k(hP72B191NE2vQceZO$o=42u9zv8 zQ{|;bVjtI2?WXDtKKdW4-by?~7uP=A-^I5B=XQqoF|PDx?Tcaa)M$avtXe6Q6jUlHxVZGy*1f`fV@z)3p?_kWpV9gB{}k;drS4=JMD-5><;K zg&Ub~pPiZhQC(+T>=7F6zyA8G@ZuN$#F7=p3OZ)!sp#}EM9xOMG$;=*)E|vodOZF2 zcswwA2((w??|wTsSvGl;tiy-NLUJX1!-rmIH0!3Tj5|DrZv_Pnj17ghy#fXJPaimM z<3P1m{HXFGokVuPPw?sdWPI4rC3Kn9M9>3Y7zYxvhljph&p7(H(r54>53c{_zs#=`!Tkrg`QYeRi41X5RCe%B{>QGQ^&eSftXu@ig(DKc)YEpWAJCVDt;8_mR!@pUvrTIdfdd zh3h}pagE{sGxZ4lHKPF3TNc_h=_Z}gH4(fiz zZ}7+C=4P`UmV4z&vX^g_TuZnmle8!O)4kv+^7zn-M{jwtYc;f6G2sOVg-qm)A|OC< z$KjhFMSD`XA+`r6FHtNj7va%kVrcl(tfEh{Gopu$;y1a1CH}sdg?|n1@e3IkOpkl7E0zJZCTdqrj&rp_Sqc^k3gfwsc=MM}L>b zL+IL4_}ocOb&l=qghI&9`~$@&3MmqLi>W;}2YP+U=SDHfau`@3G@p#ZHrxDw2b1|Y zynGfXkfwuc^^?^_(y?TW@#U;!K<93Hvbj3W4FCSn7XG>PJL)^f0CGBJ>d`T_IO8w+ zB$qcgV@uxY7dhg$Kdz1mKY3}VUA6y#OiuP+I>Po$^pTTx)xPD8$}iY9lZoZ593!9o z-Pf|e;(bx^%x<@_Bp;v{z{YR(1DpU@M&L*tkyjOXJ{jQmizj3_{OZgpOrYHXnB>xmDwhK83wKJHr zoQD@8NC`DKJYqm0;OUhNM4@3y2xp*RFp9SJFKHVvU%?MQ%S z{PjP}ea<^nxh7#DXUyl1NFZ$)zJBjAG7?)VL^6_s?npe*V6zn^L?{W$F`N=;O?2N> z1G^7T&sbs~tKK6%#g~bOhNQJGV+UTAQ-A&KU1*5y>EwSReir3`Ypsq9rdleL!sS`P zl%iBSwIGC-_@FE(BmiFU-whNv4ZhM5C6RdT=^?tkcY6*N3i3{LgABtDAA$vptq zZKQ-K9|@T`T^U`B1O3Dh02m1j4lk+`bY0>=`_dZ>G!DQE6acF_wsMdd z>S`rXMByNaz?tCyY3J^)Z$=jYpC$b=h7>tCk5OU|ZYzf6app?;l9y{Dd&O+5{Npfj z)C2$&5ZGc6Q?%=8bGejEsXxdwxB!lGA2{Z-vGEB<%Tg|AbzB4$ejRk~GRWJ^?&m&V zk-=&a=sz5`;oYqqpmeU;RI(%4qhieQN+m9_a@^cU5ygKSzXkSNyrx~+C#VMa%{eOV zqhU{c&@qiAG6DbK3k4j4hUg5K?TO2dxeuNc3K(iRJ;^JpQv6;o=70krIj~hL8sk>0 zZNXx{-;IgA8g@Fkhq2-1G5)q##&)@`Nhh+BckyXK#r+ zFC1q~8L#{McM2L}a0G^T3&(O(Q(NNKVPk!()~WtS`2;UC)@y}u ze|v2KDuAr9(Z7?^D@I_l0>6$u_fb@#uK=<@ z|47zJenw*@l(K0&Rt2zns?s<&IYeH#*5!}?NrYTxXao5}SKv2v@SE!x8}>dv4#)*O zCZLBl?x8<((ZY4eH1|5t2K-{oxvo~P+a4gnaM`tFLwLE4V3{#rtz~PZf9t)1%Mk6h z>wmA?HJZ5&8wehFx|0ln$K?PW0RK^kWm^c&8|Ag})yKtYX3vJ4KzkZ!i^30qE&xsk zY|vabmiFO|^AH^H$j8*iU9!q=?)N>{au4H+45IJM=Ai$KL0bPAcc=4X`cFTh(dmcZ zC#R>j=NN5*Gp+v=8eM;!cdq~N2mrs?YROxruH;|Wa2}h*y~rrXxF5hjVAsb=q-h`h zf9TGw{{XZ*pW^sL-GV-Jj<(Qi!27k^&Q0c-jdT5nKFi*IxvV}Z;~C%1}2i=kfc7_B$=Gugs*=yck$LGgva6oZis;uz;6_70fLBySWg zk_jLZSojBUjCPo~lch2{lM^`7h+{~ zud8c|${YLB&^c{}H@744Z5m!aiK~L3fmwbY1;!pzRAP)=4qo4&SBG$``$)JmnWf}1 z=5IckOCIOT^Z^Pqj34)J7gJ0A{rvzW|8|XHM7B)nTrxhhywX=flh=~`1KCi_@VbS$Qz*%hl_Ltbt0f`HHbLomzt zSrYN)mQVaq5iEp@CuhdIufN|I4qi$y75ywxC`c)Q(VV3)8lY7+eEC_;n3ZNCOE>J9 zjf9cxANm_h@>u}|trR4{LA%gFo4}`^oY*pudQ}Rm`$+h=#daw35}pJuPRbH!CD9Uk z6m}?Kt=DRy+b2n%*isuJCRYQ@4U@XNddxVAjvA_Bs^KFhTHJwhUY7(_8x3G zJ4^jMF)mm6#6(@mZ8lWe!ID&;3AV&SMz1$lP|PP{4sq-E)JG}JWHu7>J7y4owUizM zQLooz;HHMJT#_-CbL{9C2C;SW#45HVq!{T|vlf1Qbscu=epu}< z>n2i4!4-3YoITJB}Mp9jA#g8Vn*{j2}*gv8CYQ zt2@|u#<^C_9)o&-zA`qOxq^K3A*n8N4fk5oCZp?x6OK`Yv7!sXLvdq)7XcxTpJ2w5 z5CDgaBgbKKy+3NgqaVBgr>L=ZTx@LH zqlLzFZ*5UT$(MLR6SE*A3!JN!O1Qk_8BYQtwJT@IGB$e&k@VGRAUJS(+32$uP~g1> zE%3am@nK(3$ryLDVoysvw+E{MJd4g~HM&X0iEa1!)S*ohNcw9op5EB&t5D^|cDV6h5(nHTWz`8;L>E1}mTNK*nh6V9E2K;eh4+&7tQjUQ~ZLE8k< z6D8>M?ev5d4LqOL)V*?4!dEWigmMawlw2mq=aPwhZfg7%rZ8EQt>{8h15ZfgCRC<% zuGOxGt`ZaQgAZEhr#!d?>2*H+X`d-t8;yfr*Ag-El>ikgpi9GT7JI0BC7asfAnat!{c8tE{j>{KFCY^XffVOu;2px<1>eeel7yy%BK zZZ@(VxtP3J-*ld_hwgorLa+kETs`VX(l6*>EE#)b8#w4%`UOt-0DbLt&18&KR1|Ho zU&vlj{iS~&(|_)z5A12n^k2BkCE=DWg71tcGDxBbzoD0VDBf+hO3GGzwl>a0nN5}c zn+~L8C9VJHpY=C6kKM}@&OXq8?C@PzK9Lo83-r2k)PHzC8Y#p zMzV$eqq~eP?SdEnQ1E9}B0O}RM#o$iU6&~o;Ge1YrmuC`p`UKQ=m&uRb-866u{m*E zq+g1qT>s~ym6)SgT$(P7hkR;{Szra@kBWnwrwumOW7?$+>^d93dADt8dhrSHn)}lF z&w009W()Ki9Pkl41pV-}P^_B_xZHu0BBmD$;1O}36+C2wusvp<M=Z_c9`Q3VBomHI zHe~}VD1--|*&`*n(4XTJrN87k zh5F{0BNX=WQIdP!Bcqs~A`vk;1%TUo5_gvHOUBhd3JJT_edzaDQCJA~L;0}PG@M_a z+ho*O?Lb$|9b_If#=cyi$DY6bZYmvJhVHm%xtlm?+j6cp1SI}T>Dluq70U%BDh&05K%7%rs+5lFp}^#64w&LrGE`_Iff$v?mn28f4I zUws=Z7Bybbwk{g(`BZoh5|#=EJ~E4EAn5#P5Z}BH<6tBM!fZeId4b?JuNVNCOl?$8 zc=IO32yoHvc&UzQ(4If#&HTKjQw$ca;h32?CFHxvM4kr$_wC&>OjjgQ@fi=GTqK~Y znUGvwJqy*wX?XcW0wse)^6$^6uqWuS-%317;=`+JmSQQeC@mzsa!%WY83UArjbN4S z^G{o0D$j&b!03<|@_RW}l8>>KVzc$Tx__0oWO{$7$ysH>eQz!!LJ-GGU7pIoPr{2Q z3W{WG28%d5RmdpVOA>UBQ>g{|QMA`~BH#%+z{&)Gesc~ZOC=OKta>VAOusU6)btU<(30~EQsOtSy5aQl zsrX+GXPt91ETtlENflkR-$-L%4Z8hH;b3prwF z#eraS4WH!h;xsx10)~?%Be-d3O`nHElaWJYw;eyz@ zc&uH4w@Gm!>Zt+)##lOUvMpJJ&ji^%#@q`p854e|@#o4N8{4X6gL9_O0>9S+c|k#Z z;d$L`HWmPFnRYy70PWC0|E6;V_wqmR>EYp4tYVC#EWkIX1G?bPv2XB6zwMl^p|9+b z3Ha(V%s6tL-LGrmE3#ye=prl3IL?@$7uJT_hYtV&_GqSKyMb)zPl_ z3%%sLJu0X3of94>*o3PmPd}>v*k3Ouqo45KSrbMzmb`*ZXk`u|-0H+j+Z$iq+RKe7!iuKyGvzynXve;4w>pl&;bz`s;cIo%WS0$rds~Ohn>pW62mO(cym1J1(~c_*rl`f78eK z&HvB?&FC6(3%?of{@~vDas=@W{&KzB5}#CHgEr*Ce~$^*73TmP2PXvzl6))Zta$#L zS?ef^Mz?rNOu!_RMlvR{iq$-J0UDyy3-+_wB=pBo|D*j;VlCUjq#A{H;sEY9y2Kx3 zWjyJHTDftI<0_Rn*~82&U`btFHeGgwIFlkdlQuS4L)<9-TimAq0gwB@M-sa$D1K4g z=<#T!cp~{xtb6iBc>3&I_lZ9W_wH`j7B>?s6E`!_chZm?2~T{4fqoRi#mO!-t96T! ziR;M?z|H@}(g5ucKl?;pQE|%k-6*u`Mf*)V;3wvPcBRm`r@kH7OkbijW4Un+=|KKE#0B^6)iwp4!eesh%(bs*LtYq6I2YlA9 z+||KzMd zx)8w3KRK>HLeC095`WKoc@%(i&z@jsqyAg2BVe|l|I-D5*YBb}rIUXDpQ6IMHw)R# z+%fs*K32zjp6|&&g@D{Y{VzWIEiVn=<$e%x^JZ&_|4CZ|loSBc6$NjI)eYL{oVP>0$qVl!ybAtc1`N13Q}EtqIV4Fv%evwV7Q6^BUC42X z32*PCp|93hM#$$$is9-aYmXH)T5TCRDTW5_SL*z5j02*w&5SNHE=$`}ee{<>{QjGR z2D@rAp+Gr1u?iBvbr~r}Z?p>MR}~pX-ux{i$Y&HJlp-wjCYi8Ql2K6L!simZ!(zDW zX~1(-Sw~^1xa42~sxFrjFC=I@Gk1BivgBGFjVlKzCTQ=;EPIRx#->!^TbD|JgM>yn z0B|ys!#SSY`SR1UEhD9B*-`T6ipYlY{BSpubImGcn8}!;Y@I~W&PeIiA!Dw5`(4xpjSL;d0 zZO3sng>ViRc?)Dhp=OU;Q1qx(XrJXg1m5CJu@vqe=Hg!n!)+zhi#o3H+h{l#i;#=* zi6O&L&F2`GxZHWcbHBVzMj%&d8%`7Ym~mqE*eZ)V1+YA)pkU)oZyJgRmQa<$gA#=~ zuZERz$B~fq<4joj0Bw#FUUoW7b6n&8w^m)Y;F;iyJ%I(mkj|5Qa6c7VFHGQ=s4f%m z@tdH7wl?Y-!LK`N0vm#UWT@T}1k+Zn)-(f0b)I4X#Q_h(NE9hp5!evOkdzQ?6cn7W zng)EW&ZQ-i)oQd6#uo);6g>7DW_M!nMjHhG06_uHA080+2Qh-a9^m zJv*1k2sjBQha;U6J@Ch??L3x4yIy#KU*NaEPUAluc5SRH#hL7d5*y(nm?fBkSKz0w z6fm5&$k$jj;hZHV0s_@^@JA3Hc9Gt}aAvYZKk3i8;xhs*t_26j7#|8w)-Iou5}yg+ zEJ+a_f=Ga`s8k9uiQ;+>svS7a5O~1Mi+@;I#CT=Jw}ONMT=nLu^>erBtD6dqW&4Mt zQMkI)xGP8jNF2b&Jpl3!9uETJG3kVYYWRzMa;XK!N}y_0Ia0OBeY82-@Gh8)@zd^= zd_f-pSf!|r7Nk3pk3y0>6U6&UCi;TBkffrk6$M#*6TTwf0soNkbRZ7jet7k@>>SG} zV^PlnYS97y0iU5#pbhQZ>%l#GiTqfB1$osNSm8o6+n6e0L{`xqlR=HuRCGbl?d^lv z^SpG3>u(>%k>{8k(L|eE#~z)aAK;-Mt|L|uBcWA4*rWgKkq_rBHVawCCUD;CZ55exopEk9D#s#3tI6l^ zTH*Zs+;ob58i+6S6TNX+#9pI|ye|WA{rCQY8~&Jlh;Q{uEYg|&3(zBb(Qcyu(2l)? zZkDs6|JVU=(gz;#)V7KfqX-+$H0|1|D>u z&GiZzSn7@bb3OJQ{ipAM6)*I=fL?<~^gt`n!=6aC*b1fgQUBoycwFac%acg@#aN)P z<}ZW~S!HbC3F9(b?!%kcUs=)$a38cHEBGjMF0KD=JG?MT-@!$@Y5ha@(YacyV=`!C zmyQ0P;!()6S~cgzuPr-;`smCzBtFs}3i zzz1<3_LvPIZmZYI$M^xAqeua-n5>xYYl>~-3PJS04^KrS69gOS8Hq0wTqMEh3p3CZ z=~k<0DA$w}Za3lN>@?iUZkJ1nnbohd>^A;?s|2#5xPny=gZaSXXXql~Bzz@VJ^rTP z#G?p`V;X0|qqYiRWpOt#DmbwF6n5vbbFBV(dn4H^i(k4YFCH;oj5Bd6G?yhOl{Jo$M?T^A>N_SOSaqj7Li=nsep+;YP+pM4<=D2*U&szA@wL1| zV0l84BPyM(Pnvv@Bu+jK2SW)|F#pImOy6exDWUwzpOcf^z88vt%LevgLh<6{zk^9_ENl}hTZl4te+ ztGM}1L0~80IejX>&cttqV5nG09Cw6L_t(skvyElpM)Rq-w(Gt#n<_8{xnYLGnv0RL>{ujzc&cd9efoN z;IfPV`G5BOx4h7gm;8a4MBkHrF95JluLfWypV|7yNq-vX0F?@_dib71m;YDlJjDRu z7cYx8ST=wdb8RI5054o<)JcT0wz>eu0VMxCOTpmqEJaR<;9kiKs{(%UiIjq5FB6|B z1#GZNEg5MluiL=#a#j)mwXz&G-#HdgMRFk`@rR~QK4YdPj_jEXH%dGl$0cD7WjV;< zG~!?-LD-JMWF^C|Jw*hB5aUph0c&=6hB_xjYgtmYLpdLfO{4f=c);iVMDh6F6%zbE{J@O344@JohKr@cP)`EgePa&FtB7_ zyjIXutVm{M^rtd*^<2^V-Bgl^qvU(0I37MZ7@rv;K~S>J(mX{reC6S=my$L+kw@xl zR*E;CDR>h;fa9&I5<9h-k;8NcK#>ZAh{IeTq$C4}bL8`iI9VK-J9`{6 zff>Oj#SMx&I60s|!rdc^{f*OJpobZ&$OXG@s07WsB zYVT0NU$Jtg;8=+cFJDu#13l19a6#Zi`?V6wQX_r>3h2d&<1qTetpe?6gm5Y~1<6)m zm`e5)023I|F8x6cCUeQV^q9ni>j+rDh1~L+<)7e~tq8n%DVO+`(VYtZp}_(Nj^ryQE14}k!(Layb{f#U5<)24obS=FMI}v@j(U@yv|GR^VKf!I;#M& zSFVlPMqV^PWSdL7>PH;-#Ob|wJ4jmMBno6h$=%LB^4xguT{w_-- zqzwgL)1~yScx4HQy#PzR1?cPT%_|G?!AJk;AM(K%l8_Tzg5Ts{Jmg&_1n>mF7W~Ub z(noMv605)w83I`LXD?P$z>MtD-@AciPXQD%$t=Ni(@_$}XVGHefH5;(Ya@ApUi!nh zv5|C<_2XiK1-wJlbb`M0^||2KdZqu+oSbMT&$bx8f&w00MXP7Tnk( zf?D`xg)v1F$fgyY6vRR!2_Uiv{iRa4+=S1Fi~hyc(_pV4XjY^NE6 z6zJkwWEe17mGn~-v~QM6|F_aX_vy%?|L^+G7ZVQoOB)w>VS1zEkM*B1fWI8GWxJ9W zXh;7U7wq2k?JM0!LM2&XJj4@l(tiWlv5)D$2kgjDny;29iUnRI*J@-9Q{!LA58zHW z$(Ya<_dy%_&mR3pPU#PNf{im?i(vL?1*S$!*9c50R829`se-9eEO{xF6^98Awuz0zmDm+{ zez6VHZ8J2~?yd3-CXpxrurh=~J*#XUG_LC;76lgiAAWi=OF;pDPX8}Y;$s8I8%bxo z9OGMyQ}e9sSy*g6n{-6S#N>_S7d}xu;D3+p;p>yLOt`u0h1Gnm|9L#KWyKHj1y78L z{}&VNvw9~QSsG8jDRA)eZu$z|-+%oooIYtuW|ix)!eKrLw^Q|@5N)L;|IGL*{_pl; z3=STELOIF4AA^U$)d`b!MVn}Z76*zG6glWClYGq7lkDGib&c{I@($=4O!J{$WfBY< zP_ty+`leXiH_tnW^C!9wzJB#8`Yq4bjy^_Pq0mwL+mKbx*F1^$D&f$5YMSs^xdQ;O zKu^Com`su-~18!(s73^3ROFzW^{j>(B8YzFQbRHWL2y z=Bw&~m!C%&1t>mD`^)h3Dn9#9`y~GW!<_kF|F{3{0AW-P&aX63O3*>Z3V@G+&-^=Z zFSGj&6b5LB<7ogdKmmdO*>fK={~rThv;g=U7pZ)-Iz0cUWF|@c0sd!jZ26FY!Qr_N zULe??)Wb=GS;9**>}mMBZwE(Q+z(W%?V#Km;W<1OI>n~qMfe~1Os%!1jUMa|| zlz@$8P;tyu?^X&<^gnGd%Lt+EAF9On(t z&n{z|H*(sH2V(>7c0qwR%K!xD)qLoVnIVneCnh)ncwUQVx;e(4Hp)#oVBHU#%OO2X zW=Fo2v+A=@Lia++1mi)!xDR8s%QQpoFg7FYJj@iAN4mJ5M;CC!%l-SY;Jn`hE$fBG zA?dT@ao{CF;F!r7??K*D1AD{>Ur2FYOyiaLpH>1*lgLB|~d>zLK zo(YoXD^^bkujr#(98i<|_sI8aJ0K#`V0-rzhK?UEkPj8TY(?b8qi3;CL}R z4Fj14wC)@P4~2fZy+Xdet!fPlKNaoE``6aa-s> zy8w2FzBw?KT*rB*&-v&5ak~s~4xRO}aC%(^z5jq;i_G~wX&(7`03T2-McGRG8?I05 zzg@fNn$Eer0C{G61wW_%@W}b@`VTGHL*LH-l>T!K`+scx$4|jm{&&0pymXo!{u2H7 z|DDf&U;X!M(sIGEkLf?-gZ-s%?nhkK+`l2`T!$|EcsaODNb8fufXRL7_(T>X{;IzSC z`cGS|5+p7Il;2t$RAYsM&H>)f#{i!kH|>zDvr35n0q>{BN5n-;s=d8knjbDC{PBL$ zNALk0BffeJt#Z@iBM0I);%A36&xlC@VqfC%PoHXh_@Y%3M-l@PTN3B8qBmDRvv~6Q zVQu%Gw0Pts+E3`Bzvu~ot~@<2hMUpYa1pQZI6yky<*`-ZwqLfD!pu-Vj-x&99WP6v zSxT}sK{{7B#{Aj?ti<*Epo>0_`E;QG{G0H8i0n5|4u9%YYm2posg>i-iz zr-6RgD@)5i*nn2R2Oqe6Px22e zmfP@)Un(t6pMHfJLZ18j&y?4b4kw&hmr>XJHgC9s|5gZO#k1(^HpZ? z0q$`h20YG-KY7Xf=XhcL#*%!W>38sRp#pwr&ErP z0Du^vg5Wd$>_OIpT9qSTya?R~Uf2-7PY6)?@Mjzx zNc@?BxgS*n&+*sGTYL7RTqzkNVJJW)h9&=0W!O0P?D?rxgYt!nRh59jV5&a6FIu1= zy|I*IJPJH|03Iqn@%bZ`8nXPRB)Zq(7r#0W6TYKA%ZGAJn+9jYY&y?&WYpi-4F#ht z&(=Lb0=tWeK92wZ&@)~aWmvc2@|ld^ViTW1Nd(bxAl%G6^G4LkxTM2dIibAG*no>Z zfrnXxt@=vkjJ|L`6*BH$3m^Ay_q?O9ijn8^ubQaBo6M0nIYh zno$n8A6oY6;**neDKqaI;FBZFmMWPV^1_vT=#PsEVs#xeKB9?Z;HHgSp(f)ow`WdR zJz@73)kkfIrIbW;m-%+AX!!BnBCMx3)<CUUfS z@jahssUa`HiSjM0BAJXlvCl%5JEApX2`%?-HD;`?So6I8j#&`#d9|~)sOEEyl@nYC z&{y#78S8w-_{Iv7dU+RkwiH{y>?WVyvp{sQ4bAph7!4Fqt6yG42R~JA`UT)rxgVOL z6CBW2D)G`RR)K7-UyLiqviYj`T@JH3Z}C>ph9eiBIq$Tx^evk#CkI$zVsG+S@Qkjm zcP%-9*dMCW@Bkd}f%i%9J>kP1T`UJ)1k@WWx|9n#X7017ot=v4V*pDrdnOD^-~Bf=9ed#Aa7>jj&n8uNJ^} z`aGLX?2YF8gE*-Bc{Y;~og#tH?FZL2A2%Wp|{civrMp#tT_v)z5mv;~;zE^LUzkHcC3c?@G0){z&I`yh%83Ho|0A_+Gsm zN_QJ}o|RX11*7zbz9ED3bGv57k!KDS2xcU!;=7QWtU?F;XPj8^lU1Al}CKU7dH67xS-Ey zFSJ3EuRdBWm$u4ks%GNnJ7u3|(n~YrH)Ez)e~$V6&;af54SH9bs2lW+J!4R+@CjUA z^ceNu^_=@nM%71jk>m6meDP&ox^dFog zle5{>zAB^9G`_)eXoAPiH^$G4AIPrtS-!w#b`?9I{|`MSWeT9v`cGf5nOqOg%?4F6 zYU_{nA9+Ovm@R!6@)+KU{N!H!5A&-_-Q;~Kk^#{eSN=)f6aA+x`1qIT zKlJ=5{l|vEr=Qb*WRPS9Uy3f>^%o!LKm1}W(f`#(yp&FwjLEOjCT-)Z7xSUf%}NPu z1U3L*%(9Z@%wZa?ue+xIjMX8d@#K?!;wLK}HXGhvulP&yj6RYOvkVwLKxWZ1`fs*W zJnlX`*tPV@br5=(8O4v2D`NxT5j4^V^d3EN{$U%2Gm0Ow6~rPs-tP@UrKYw;3)gf< zk~iIpUngz>FS-X`kS~CuHa@19Z$*D3`mh^}<$O)iTDB$|{UR~}@Ax154*BdVuwXo^ zL#(_zNQQ}9kj1=WF~${0C;!An#4W_8=n}RKI_WcU0JGxs>-?-89=d$hLUFWYmRJZN z9%6MNKup9WPp%-Ju5p2{a1=RN?W&S0u;AM2cd)er-}tV&Lvi5^5>ziij0`!}{ zE;VlC5PUN4=JnX_pRcg1k{R`}*H^!lljMX;2EgL~_GQcR1M-EHoE40VW&C0&3&zwZqKx7P%kkx-KV{XWiMQv^61s&hF51i`RD5ae4>H3_VYq8 ze<6fYCrcn_ycJr5aobx;=nA^O5xVzO%65hWe5?SN%ZXIV8=JM4oeBHgnG8=99#3>g zo=Fz!?WPIiW;0Mfmw{)=4+$%#i&{7o;xfNdAs0?Ac`2HVf`mD*AS5cbep3jLa-&2* z_f7_v1RSFxBRQP&42J@ZO(m3N5c4vQ898*8wSdQPYCPu?1(DTaxNNs=`8t3S-SbEo zpAK4$Ea1tCPL#Tooh!-iSQ5nXzxv`_MkOlQ=>AQ3`SiKbL-a<&Pd_Y#dG30bSMvVsW-HQ@cT!bB7wGr9z|TbAT0(7@>I6;Lgtw^JE`!@e3` zK0lMfRzjtfH##<(TG-6`#yf|@nwM~8EcxHanf8?2<@Pgk8oZze8Ygolf_nvoYYGZ{ zEkZ_%q)ZNp0E?w%1ftm;75#%5KN9a@cVGq?z#-w7aKM(h2R`>DMOEN*+Ex&#;BBMd zjJZ8?rR%`I+eT+gAVdHFP&AonY^fvhKY$aV8j67=QRaH?v*0J$6Q~np5Red@bq6D( zg&8j7#oov*8Yy@b3OqZv53|L}D%aincNSO>AYlWTtsyWXpkb9nUqRtQL5KA(ahOAv zLGfMPB>3RC1?mJy3f9nn0#<%Q6YUWU0R&3~YaAoE+RDgsod@}Bmc-M(0(t@=iWKNG z0mNXuv;KJC;lUo)B4-46;3t8qi07=NSWBOl8gtr#U(gMH0)MXcps-f0hP&ZX@(4?L zhOcBi07w>SlMOq;{rpej->6l>Z2Vw-`Sdw2ualEgFa{0CT|)so{9xRDjNmcJ3V}3Z z%`#pRA`%Pa1jmn!u%uKpz&HA539R(h6D0aWKd{jRc@`*XYzZ2c^NG>QdBztxVI%kl zpb_378}0U~^Z=XJHlCA+LMI6bef{S9>u_;#X=BFLk>0^O02;yT2^hzjAty*9 z^cA^ufCpS__v=c4XZPP z@&W}w`>|*i^&gy!4+#VMzuac64d_K~8I!b+!!OtQq@eU4nT&}jc~q2Z!06F&bf0@| zhF$Hz-+Dtyh>k@)&YLeTDtM;jeyC z36p7@s3iX5{>07NiU*1yY{PlmVmw~-JseTAC;94$2X*O4$8-n3e|D^E^fdtfqGEG1r^Kdl_|0$b_eyi?3ij6WO2$vE<(#g0cIC67hLcw-8Jk~KEvB<&Wf zx)0%t-&`7xeB$y*>%~*+FX!0EkBtAy;Q$H%0Qpuy`U7x`<^L7@r^v>2GLgt*2D}WA zN3sFp>{mD9yK)>h5`NDovHARee9zn!pOI&RCHf)$C%4>gq)Xa(gq#8ZFT7{6n|v1_ zU(P5FjKNRe19@ z&i1FF(TW4k;Pkr+=p>|1uQVtH3FAr(WJXX1%|36I3>JH;eN>33@*pTA`WL)OP7>mk zo{bC*P;a-ann{(2q>PzPDp(kFOa28^?tXYhfP#~W_fdU9_!{*K1sw>p0>aTIJbziV ziWmxpvY~V+2SPp?>}++x;BF#5Rl;H|rOol|lN^^ea9CMWfbr?}rs3+z))dWgf@{4H zPqlr2y$E$F8b*?3G6y9QD<#@g0`n4lUeL1IEy7ql@5s5XFp$}altc-)c#0wy3Qxmq zJuqX2p|x4h2R<9b3?}a$*xQD9QCz52n+iIXW*A7|&rT|#P}3OZaO&!Z0&Eg=migyo z*rzi&ht)QWXS^_JWw`hh4F(MS^cP%%5#JhDK&k{yE>ucSWm!QrhEdK5JcVow&P&;S zxV>e@4QIkE2eUOxqmgQ8A&V1Q+Y6(pVp`HFnPoPDgr90U&X(%@gNzi<_x8s!2*RB? zFq^LgP_*)S7W%kc!h<-2dvQ{-iNl04RWPJ&urI5r++4J~zZ?4{@*rtGyuw1kuP_c$Lxf?7F>`muIHRG7f4N zIvJy^x)@Fo9Ej;{}Dxj+1Qg|J+`rsYF3C2R#$~ zOr{!8RAC@xkJe$iWh<4`SaOgW3e_otLfKSyKNB{M=Z#1sb!(HDh z_7+%)H&)zGzv&k=q)!2jh{8GZ-F-k~mzR zpGseOYdr5^P~a!}p@;kUO}o6Xi{tPMgMBZXX2m!K43k+=`n9sa0$@A|^wzs}Xf&%f zQ#hN;!S4yoaWrKMK$u0?OE2LYPLRS^Pl;TqD0xx8*r0=LD(^=hY!h8`RuJhp^gsiN zj0HDJbl~@3K;bD9PVGCoJ=6cOD|p+1yXVh;yJQ`KJ%iv z&9-XK0S`yAoo{}SzMRWmXdH##_#`^3)q>6JffHGPc5E;ecEfR7CY5jVF}os(0Q z-cmFx6x+rh+PuH#rLS4j5dukySNy+REAbjgwl#k91$~xAA7Y@5Orbkm%NQZ!K2`+o z^k+1Yy(7qx&eC?a5OoqDLG1Q%w5-lhAR^gCMk!=IJSgxl@w{+TwxVMFrq5i1Om_RC zLwb06!lzc1tPW=C7j~H?n0)7*XIUkKx@S0>NzQopOq4C?8_#)zxpad)x+ps6H`gP> z;Gr#Mtc>T$_`7V%6D!DO#z8tSo{uLi-Q-iIaeO$Bo=j)*PvF(Dhh9&3dES%XRq18_ zsH@1R$)nnVpSF}fX`itiPnao=i8Vp~OhGjKaQ$Zwo#-0)7#qfoRc?Nq`x!5EYC2co zZ~PR$Wv5*K_v;6n$pS~TjZM48<<4xAeseGM&o$nRt=Sdbf!*gf{KL+m+l zqsaR3FgMw?#C-9d9{9ai5{~}UU-Unpi+xS&|8eYpLjOsM(SKz9vHsIG2{`)SYH7SB zYyVjK@4S4h|3_XW`p-4o! zR(fc5-De-iYH2z}|9hjc`Br>ktKBe}Vde}wja(xyBu?gEq+9C+xK1L?8HK>`X$$L;}S|Vo2Hic`Wom zkF8Dr5 z-iQ96p%|C=68(?yW?6E_DxHjUeXk^~P!=x5_awsGZ6#bOCVs7Cm_8AY7MYmPSdlxR zD<1#SPE$G4N_qs45HrEWWEir{XS`XNLHs}LD-Kk@^I1M$niXAL^^sL_1?fNUe!4MU zo-1ea$wGixbS5R0gT_Po!P!YUOk^X-Io5Oe5A~g#1o{|9kLSr0@)(kTfIN~%v6)mw5`S$xE>7~# zZ@*c7kmEmS+;hM9;>EE508ka!k_aZi%sLWikxY<4mv!m(b+aVqhK2~J0l0d8Zr4*mWW@j# zL@J2@Gut`+&(BW*7MMsgeZ7oSSjRv4Fv|EVM(wan{m(?WXuYH$}#1`7AZ`)pAsx4yMf2 z+PQFOY!x)I%p81F1sC&yDGe{ZsaE4s$eNru%6`!Jk$93=FJz3Pfs}%ThAD7fjuL!q zB+)GIWWzWXWdKeuWGur}j`BQg4ns@&nQ4$NT7?^9iV=V4%h2xm&8ms21y}H`F5|P4 z!NK_OGQjgwrT%hk&}2!Wg8#{=C%NKLj>u<%&Aa<(uxh&h=5}ny!3&K9>d-qL-^s}E z^1)hBLt~PBS}4#&nq*=I19#K0fo-t1b9J9LCTMTB`2Z(%@)g0cWRd;IXZN3;wU{a z=YIlsFK{r%@RfoQ4wHQ*D<`M(73w40CkMDt&_d-Ic=zs&0ypWG93lY)K_z&eTvo$C zv@)h4!;4s0W>gNvqGUrdNPt4Zy`_3tR`Mg~4p^|QfR?t5u1rly9bcJf=^Szrmuqql zFG}JXrzV>9V$>(vSjp*Tq?;V)S}M!*FUmT4EV+QD z6h8=r77D1tVth-jyMUV0XxqJVm2Reb_#=%7f@uqC%7mr7vO zPo$LVzymygc4h?^#*cn+U0bqBauACfIr~jgYL2#}fKum3?yMN4_U&G^VSCAghS$a! zUNR%e7{MFkn|P4E9z4|jn1OryZk*`N-gv^;p+gioY4?X$N+u-Nd~KpwWQ-~Bk!Z5S zH_lA+Kemi>7iTS_pSL`tqora~2}=wZOA2P-2l_x81iBAm&iYTp&jHBTY!vwO#jz%mW=5?RR7_dj~zUZ@bmf)xQub#j+F+& z@mT-C^D+G=F-z+|__>E;X?-rZpbG3?#b)RiyfHa@r2p{FWJQ0_9rPc$!JfhwYyf!L zEd|ckT^(1y6I)JO;JAMn>YnJsu{CZN;6Ln-D3QZ!>G3u zMR+_QKC*yL09Mpe=#Bpd%x7ARp!i8irN!8ZJ>fp+U9ZPVEHuvIGsz(drwq34saWBJ zI0OEn|HK*KjP|Xfq(@0#lFUIL|06@@i&Oo^2HIpswr&N-43DgEPO%X{L4kq=1z&K` zU*aCIMsj^>aj3_I(4Lh)fi4Os#6zrvpb$Xp#%~HTtUh_@QCzepj$@&jby!0s94dE$-47X3WdAS<(c(NF4W6y zoA6-5iddQzpA=($|E=Qe>CEUTSDN-ebdoRd!qeBU--(}>O3I06Ga)Ov-z!KZ@u$Bw zfufDoK6M3kOm-2E@8v}99_~dGE4%p0nc@cRYZYRd6bq zg!GliCZufSl_dYbC!ba=xAc6H$I?C5^xP8o;fJi~d!MHkiW5ux!QYflu_^<3Z*?g8 zWQ0RHDxbGe{>x-GiN7cR0QofF6Xy%X4b1eDTa%yr_Vk6FJ|_E~r?XE#Zop&yOUaSv z`nK9%@Ie89gLw%&dye@F1-zO7@ce)y^*8$S=|G4f>4#8?2mrHS0LM80=`Z7PmfO>L zfP|lS2KW~NfQN^QF%O2p0E{6FjLw;tl_>DgK#}|d38-#izdrbZvSb7g2+_Uk}gb0Cp^GX6Cfjh7SM8+*Aql`gnx2Vc) ztqQeT^~3W^9hbvE`AA>^o+GEqIOq#sv0}f!`gW)Uf=3W|7Ds_jK}Kc6TgQ3)A{tKM z*I%5-=ubjPj!X7BK4T=|W?2`r%m77;yFRnI{m^K%Wh4~%NZEEqrwoz|4@L*$^UKfV z6qWSSCyWb*ipngBHpZ2Non_Vk_HSOv;8pD&lIVqw-QO)0G-QO2C0>#jIn3L4zmuSK zL+^eRZg1X(&1@9r2fmZKuqE;sMiTGd0Ov_zh{~-Le#`U7Nk66J9OJvg)#}3f<%S*L zH%sing8{>N-QQDXjYi-3M)IFI=(zgLl2Q!MvuDll;>m^Ghl9jnvb+(Xn$BYf0IM?K zA4Zi#04EZiGGCWq<%1Me&Jp_H6+sG>J(k&Fy!kXHj+g|Dr1`ra-pMKRjBKQfmuoP8&uwOI>GzLcEHp%SDM%n*zzE;Ae$=C~q*q*umEjuW}0=<(*w zt8jI7ZulIS*@+2C{GWh^K%F3&jY0>N0S17C3kACxC%oPyPw$7)K4B(aScOjD#mHoAhHz zEM_>sMe<6L5EB~7tHlqK|L{8{4dcygV z0_0Zn;>dps07akk2bn-e;mODJpSEJ37^h(WGiK;NQ-9$$bTnM4n_TO|(isfcylDoBWgD!saR(|x~>kp&;2f!j4wqQbOOJP4A6f|{zaS7qGQPZ?!YW@ z&HO)Ylc*uf$N=X})(*UUk`+V9B66=|$)0{ApYY1s(El#`R>YF;=9ud$dkU6}BR(Df z-|1W!J_nw8#&*TkkFBuU$)}1=W?zA~*EqgXXf&Dm5?^?ROZ(|W{o59#tW@0da$IFgpjpD& z9j`*aKb3OyWb6slYhlpu8I6DQ?__LcoGR5b-G_0~A31@X92v9zqan-5E8+Y+WAsBG zV9$uj=fsL{G`JWsRyv%Xc8&>psdOr*q+otB7k~L&W6hTFlTzHh{v&3Y(WS<1aKzUA|Bv`S=gDy>%0uE#i0MRy0n@-thCo-E71 zdtf=4cr7Q&EG&J)XuW$oH2QM6=n&ec3?(m28dyOhvu9-oOQ$yBw%av6u!MWLWHrYs zG@GXif|$)<$tf=pquR}LuvA!A3LM&Ie0|o0V3DMq6$1~0epsw#lKq&J^Z7vdL=ncF z2eOQlnNAhxtKU`#QSg8xw}3+`z@r)j5I&Ou5U9)*1abd(!VE@Y=;W;UHZcI+7tgOO zXeEdMFHRot|8c?=(8xI~rOVJkkVb$2F8az$C3JJ1fCnHr!P(*vaWWJ(NG!0O;D#pd zBhZEpHUbB>`CN${qpQx*Ur&fB`n-8P4y|^4*McqW-;~VhSOBAqKxDh)xk5P|$sV|D zrHl;iTmdHMjK<_zFCzJ#^N|K*kC)6TI03hSU=jWjq|*=jTfhJulITES!I=Pl)vIy@ z3X-Kk78qH-go{E6K)<{QLDE7H$Mr`V1&v1g*giaBIV{gxTA?n>3J=*q$viLm-0Z}M zES2ZE^tvtjCZ==aA^MZCBG!+u_?(dJu>uR^p4D0KioSr8b_wzpD+&s{8$wP{_;-6M z`q;asaK&dwxppwvYK)Z-XRG1rs%`Q@BEqVivVvBEuC0PTej^Jc1#^23LDfE=!=4xF z@S?oWKmXhk5l@_1-GCg^A7~s62@GO^h`{&2qXeRb!Vz|dU9TiyJ+i<9*}@JH1R@s$=>!QyyboGsgWrxrxuC#SwvCr)PL#MXOF^Iv%`V3jXW0YD z2XesJz*mw0#u%LRizJi80zIWbYO^1r*JMRw_Q(-I=W<;L2iX8- z(XcP@jcqWb9qFp+C97-bPaI=p9iBe9JPmhuvJ*=BXa`wFcGG*uOOiX3ELCdfhST{9 zKKcWgPU!z!F4Bm-xPRE{x9n5t#QKlyI2~pSOyC*${_{*!n~hmH;g8G5}|JeUY{mlW;}Zo6NM0D1v%iHLtBX;vgw5u3PU9D6k@mv-;A!{ zujw=K1&JGp9J)_Z#e_y%d?Wb>h+P2q>#>X#1aftY*ZKqc&q_j8;}8!~5Nd|EZyuD4 zb*!Bp#oCq<(kiPdDOSZoJnpNO5*FATYMvNRosJ@4SWE{Yc)TxL>~6(}+3e+-;EJuL{=+Lrdu=S$E{RJLvKbvzS=3^&W=di{J2a=s!;Q9XLm>nNI$FlGje)F8~1ie|DibXtJ^#Jq;xN4##%@@Pp*vs{_xT zC=^K&{WM|+|D>P2h(Omnv1}mq>V+r&R6f$n8|Wwwf<%|ZpEo7)O~meftYA4f6JaWw z!{t*se6d=U@peh4=Y$=vnKUiWxtz5P};+!xFMa^-MuD0WY7aiNTHqDuu}7Mxz=AeH>*y zoSa2@*e1pmKv}#HfT38)2(RWm<4@5cj^$#pmvL#DQQ(;?j3Gv%QfC=1j#WXL446Md z#PV~JcFr*dBoO%!PI++^%K{YA$smG_Q~WEQ!j_%fNsF=NJ$iaSY( zB_om>Y{q=fr+(u55zx`oGYWsa>wpy zlcafKiOwN&&_;41Q>b>898}^x@PvEdQC<4Rp8FT`zQ%*k1hUMnX1<`&Jh3)B(1ia4 zgUAXpNI!YYIJ{;B4K&1Hp4r$Kpu7AqR`3oTgtxS536&BJ=;b{0_&6aa_(${{T%3b$ zu0=1pJ%V?Nv#~H{L8XAU;ywoM@SO1(E5V{5gsxfgqp<=H@R+oN&7iSo_HsnJ$SA8zZ$#-|$c9sUJ_@N5TOu z@QgmC&(SvW2F?*Lg_3`$%XYJ(@MHRKJdsVbgkAD)GAh|-JZ<(&HXsK6QKw^JCdxH* z!GHeeJ`z2~g6nD(UJe)gh5mc8WAvlD!k5;6^cj90^p21bPw4;ISzN{N zQ~Hlig6HS--@aS}52gEFd`70}BY2TDd_3S|X$2D9hm2u|;h7i1O?TBsTK|E~h8Ke} z%NF(DY_RTQ4Dp#1+`vt{;Gj4}f7vru$Q%4b7OP5584J@(;bChwiAQpwR;92{@q;(g zPt_Mz!=4=V$n;0{ilPSN!Ef)2`^&nL@%cO^Wbhun_stT0jg`xs>ld5b1jd@al1#(@ zaycnf+c-x5PZ5UV2jhn<6Mw|G2){}4BR$YDXo3#k7!Qkc75`Qh|67q!*AWL<(O@^V zN9EG1g@D_8#yiGT@Yf!dQB1{Fmi#Z5JNy6aRQ6T+Y!f|-fmqQ%?2C*7tS(@3WLACSzF3fnD@do39VRk4&SM1MeT{F6c_S}Z=l@#cTyl8D5$hXMT9EhcvU}eUh{*rh7<~MwDau^B~ z9_5kkDe*~I$!3GZTKPmd=8E5Z6_@y@lWGb9fFB2*JV(FVmO~OpkjqfaB*$b=zR6bu z$S>1LKgmA8Z*++Km*k&hoiEmLKlusCKC9lD@b={2pZRxymUIyST>jgWe}Me_V>vp> zKVJ**$$d}!)4#!Mj{tDOf;0g$|GdO6J=5?1JMcSQSs=-WFn~S30UF>11?l7;!s$3w zUtStWTYNHsCI1dyKyZMWUH~BZ2Vf=}gF(^@Fi;E_iO_f7#O0iT<6^Kq`R9Kg1$h3l zB_WsaFdM8r%V@yCi!@}@>^R%ajg&$6ASf;@2&XIFH^2KPoL`+wxy6rqR5CV%I#w7v zmRO@ORJnMJ073Q*A__!b37>MoR5N_V}6l7eOQa}&j z#R&Gj`>yeb-=DmYW07G6s8q6?iVE=l!1H5L9vQ{qbgaaX1b1f!9s|q0tbCv{n3M5j zOb7y=K9M3P2`?|yU`*0LF@_iL4F=G^m%*A#_;|q$&)ccbqPKg0uj|z3Y&E=i9t|o6 zL9CFwQjat1SiM~k2%^yCuvqaNA2U!n1!)BFRFpCLGUjq5#gb^9EW*Wk(VPcM@^W%S zI3{K?NZ4_1I2v%{OfXWg52MGYoibdnV8IgiU8J4ywdIUTqPd>Lf!P=eN31^ZnG2jh zKv9C_l#@w(R06svcJSgPX6PwWh&-c**$YqD2}a_KK@8Xk=((5Ri?>Qs_yNp;ZdfkQ zCx45}*^L za2&Z|EWNl>EXHHtVx z7XcK2lRq37OPsrwV&n&=C?xjB@ZsjsbU!3XSIAdL@c0@CdavUx$uPm8eE*825+d_b& zG1C~{-#$nV5*{UiCOoH)*cyUXcmqz_0}r%91LJ6g4@**bS&hym$z;0|AD`hKWTtm7 z{b;w2HjzDnT?~TqmYBk0g6Hv=VhYL3-o}C?1={F4^w9=j0VvCGMK2q45%9uK_`&tO z{h3ujdxAyrh8YlKlQx*4CgF4b6Uc33+etRTZEXmzOsCO+ywKN1gC&r0hKLQE*cEI* zt9_y|q&Q7-w6x+Q#a5PV@+c7f!Ioi*_%<~9K%zlV?tNs;p&Plg^OA}6rYJkfQd5bb z#s=P_KO{xy2KVwC*)kp_Kn#OD&hdtOT}OYg5y%q>7<_TrLeA(1pMgVuV=ym2C7HKC zUp9y_Di&k={LfpI;p1XSqQ|uqJ7Pi8>0uA=!NGmVEBto)xgUFk+-LDI>N|Fum2?!S z@d+Q(fB0klR~ufyU{Bj@6o_2^{TvA2bO!BDvzZ6oqV(&qY4 z0>O3Q&*qxO1MJnu^uHuq`PJ|Kt@PpQsQ>s4+BE%_j-fl?GyNA`$QZ%)-$(zspMud} zqW=`^fuGa=m^jN9rSzZce@_3Q2O57$|49=6QvEl*R2$&se@~)ZcA%LtbvZCSN>(_g z^`GJ#$9Nk)*A)tN(*>?UXBca2up#FAoaj2dW3tTjS+;_N2H%VR=aYDk z0ucI740n2_K9S5m(tmuHJ?5hX2(Va2eV}c89<~7gi){eV9mX7g>&3O`mtql&{%{}q zV=GC8i~mXFh&SLJGKn7I|0!Zo7^EPYUSYwEImJs>-~sdx`vA`OTb!ICMu0vmP)SGQ zd#3V=OXKPqFX}=wg+A_cpHA}6){9MA>dv2Vm__(S9cJ3>3p zp798VbZ|Sg{J`EZq>azk+3E@99>C4*`!PTknKYy5vDua_zCXK+@juBwc?=0KtCyuJ zHi=oSMLevkAo(ZWMP?a8zoqX^Fm_Y$F{)qskeQcebB*pJ4>f%^d}Dliye-)vKP zXAq-6vAmyW_q{p;Pz31rWZ05HWiYaeAHeAX3GjcZETNSq#zF!!xV&{VzEu(>vVj-e z-NqSD$C-Y70I=nDQk<(NQTSN~&dXYuO(%fi4b2EUOQ1-;r(19 zmS-u=7)n`4u1PjAfL3MQE4aW&2tP{5Quyn4GAJ^n0M)W~=fv=1V60N6K6C8pWzOE_ ziSa_$NvN4AW_cxshS}_pnVa$v#8^NfgNWjdc?MF>ibNYh25+Omiw}9*G68v64yqD* z-LCP|0Ul0gG7=VaP&FnHiitXVHZN8{9}c9D@5m`_HLh`48b%gl#tb{j|L^~Br}2u( zKcC}qW5s8!FtY5|>$Q}aDpyqjMpraXjYfc%nUKU2@UcvAIw@Iy7)R)Y#yjze0Bj~h z!3IAu)>PaH7@18V$S4$9x`m^S&nz)gIAeIv1|La$;aTi=ta#V!RnZxjGDas6@shAp z`6rOZ>BrzihKdSa5+H*oJ}M#^Q4q$r>KPXTN`ln!=#>)dUAVt_kUS6&BteFP01P|< zZL8H39s=En$Da9=TyYHA77K!BURcHZC|JT519<2nh{5o~9}DVbOwdbs4-lAeKVNGA zze6??^@m{b?7Xe%k@D;2P0?-L~S963Jhl?aH( z+{-=Cf~*4E>%8JR=gDV z;*DbrPILnv`M5wk$u)2;+lB6@^?xoO?S)48M^fZ7?5_V_e4+2)h9~Ghv;u#w{xfcW zO8?T&{ z!6?7+x-QMkx*hb{c0UX$B zA5Sk%kf0L>P)xAN0paqM5sVMXKY-5!NPsDfBD2Jb7AvX$Ox6&K7D^}5f9zEAh}+_- zWO8Jvc#Z4f4|~QA8v?yiC!;SX{*xBOeiWti^SBy`M}8=_@$La#W-B!<1`r)yh=>K2 zM1R3Azh5klbPY?xd6}JbS}f(!4sdS7H%q$nqHk0&S%nVh!!|;X$AI9Xol7N~Jbvgi z{ydgIjL$f-v4VmLuXoqc2BvcZ#sE11593@alc*NL)dgeAsyx~D{nC-}IC5g@53ry;esFFFC?IzO|n(c>(E_1tjeE4-^{sCPf+ zd;2_|fJgs+{~zSbEk}&9>=VJ{bLl*hXa310nJh);d8ElV`WO3H3*Y>KxG@%%*mz8v zy{`t~9KgzV2cHCIZ~td56`SLG;^mO9yz+?1}XZ(rpne7KC0Faws-za{S z9Rz$2`2SuM_|-qDye|Nd{PVd!K08424|wvQt}f7kFC*{`$B+gH_ZJ9~q*Ac}c$o>r z^V^p|@WO+i0%s(Q@k$Ed)s#Yk?DDfMVbv4Q2A^gjlk zo_uor{^rhTzq;h{1Sv7k*-5!cE)gy&su&!SZi)aXU-#}lJbC^+5l|((_xIWpOi@MR zSlNsr&%$B6T;Z7gX7-wDFEeA%_rni7*T?KSFWbYx$ymy`nPN*ZP(b=ysW5}QRC1kB zz!8H0lJ{ooOgw2R5WUg)jT8~1s`h2@F*XD#Z1mY@3IHl@B;y!(t3ay6p#K1E#W9HijyYrTilhbFX_s>`c=E&{Ch7p^ z#-pLN!T*k*@rw}qgS^5c0zOYp2r^@!MSxE75ZmN9eIsyY+)3!c%`xsJao`@Vi}&a* zjkn7e@_{@9;3rT;PXPGq?UAH<;sIXpn`0JUc*<|C!;yoB|F7S^m7d`+V{+lw#XiL( zhrSU+vj^zM#pSu$h3>p;)}8RxjSd2IjzbIY38AHhp2RVx@R1-3`9xP3Q~Jm3G<(L{`2a1* z9kc9QhfYzL^FD(U{OB9k&=-;gW_pojk|KDBY=aMZ@xJiC$*A;=-y}C@=V#V7?J(9Z zJG8|f;JO&(F~c2`Vea>9xX1g;aR6SBxNt4kFedcFX226bC*TkC&^~Rr41m+ypiSg} zF`|t@zi;{vxUXVKXynOz{iI*sKK&+GjeL&%KnJ-Fo^zZwX`gfahKKkq;XkU+NStH z97LbN&saE3(S}67=``RcIgbt_JNS8cjDPkbCg-^pobX}L>l@Gb%?57t3)^V=FFOEU zWQfES++H+{h0vJ1F(ypZq=A?XKGTO-RF5m5mJ8xja75lpqU?Ikx&KB!yr29Z+mZf@ zX2#8mCkIw6Deh}xgJhS4-x78COJFdJkF**d^@aWs3#F4;0RF@zKR(W5E4&nE0mL=_ zxTL~H!voKlbOVR;i9R~LmzRpq6}N(iNgCeO;e`Z_^Ek@&+llg-k@3jybz6x)=YQyf zW>#|04q!39VoLf=fde{E+T!z`cny7Mn2q9o2mYrG?=$f@k8&`%x18%9(L+qn%Yk_x z2QfbJH1D$EKI518=KOLx0SW-W{>@X1A-R{wmdHVvD6~m0@r^i|c7~%^C;&XUW}|Q5 zgOAWytI0-|Pc#1Hs|`yt=al| zvu3}azqn9;i1`&0hPl0OjhT9QNzH>*!mLQ)>uALH#NyBgxXjQ`aA9}IKWHD@#!F1e z9oXh`VnyXX%Ej17{>i62UrXnKX*j#2Siz);^i#Ry+4)o9g2p)G4=~|8?D1$_O!C?I z-@$*gPbdGr#NTKC*|wXW`n3r^d^5MN>nWU_hJCKIg|CQ%IA9E wum9B_{{6ET=U4XQ5svoRWJNl{8t$)6x4FiKid=?-Za zBeucf_5I^M_nyD*z2`aSJonu1C*I6NpP7N10RR9n8ye_50stufEhzwWH2)@R?~2#| zw|pMyYXNFTd3XOARL+{lngGCmDU1XM>VG!9r-7vp0Kn4o|3T3Yt8fGWdV>vhG@k_8 z9ujGPIQ9GGCmfjoxRq%ssWc-DZ;R5%8e}}wUFiQ7*6jmEn=X=9`!5Qb$w;;B%gfoU zlwzGnFEcp1cv<5_ooRPoL4im&F1V!!Gx+z;2> zBc=0}a^1&h!MWwISZPR|pFcVo{WI+JOug;AP6^QVbDXCoCMoS*nBA(%cbBoS@|K## z`FR)>`GRk|mHRlYx>|nnY~N&}e_y}Pl1|p&@sn~Lx(&E;u2BNP`wB;{Z26j_T(?XF&)D&w^zu&(m6+I^V<^@iGP8t4c5fxLQ>@B${hmEu z4W_x8vL7Be0e5$@?7ob$(E7nPtP&MM_o|IS)`B&8c+0+UAL=84!1qU@yIdAy>qfo)q_Yz8wB2H zuJ*WqTdi+xBuw!pUC_Qt)f#ureoKz^hApVJ!A(}w6=NGIXhXl$)!kLZbj2Vij-WwO z7KdXjB9Oo8)- zfJ`SRCm^ul$V_J`80sa#{911sX^-CE4nE& zEQI{~%IOmR0Px)Y!k+Bp;pW30HJ)!Og%8=~kGzJC7`l+FqURdPR}2cY z(b>(m$P?k`?Y4!Z(iD1>xhe9s zZS?5A$gbxoAu;m9IUf@*m2EFstulVwA($oq#oabN;U;#1*GAdrqnM`8n+rQ5O%rpl*yCr;Auik@S)}$Zp_{O(OD4JHaPqAE zrt(9fwr{`UWQgo(0sI2PK84B7ccl^A(6TFmPk;CfV$sbnlpp4KhZ_pEsT)2uW0xxu z|L625J59)#W(e}ymU8!)1A2@VdrM7P3&FM2u?Fql@uCbWKMsuRvOfl#w3#tC#_~aX z`n~!f1}T1hKi(w=EAm~@EL!b!aufJumJCHYm@lha&nEYaY-mw2$6vy@s`P?+g@SJ| z23czNb9&D<#%a*5V*_?|PKADyCk*f{=Gi-*MQDKonTxGt0iXQ+r%i3LhaTFnI5b;0 zbh1!+AgoUU_b07lt~{5-0?WfCykpm#Xest`k>UHUn;Nfje5DIHXc;YT_In7~J)`>D zuEcsk>A$J|7GQdUB9vB3X5&*F&PFeu4?0wlU#OHDU8%O2?JW7Os(Qi7(}P>aP%)zj zzP!ue$&z%ffYreG&V(~t(15L^&>m9a_^`iD5ze$LFii1YDKQcLnl(ooA~VwR8B6Qa zCoTGLqc~YZ-N0NM8x--lHJ%r0Q~d+@*SI%?#=Ga%YYOHz8X%_~r|+2pNn~)xbv^&& zB~{>uhT2Et#Wf5^!r&%a5d50@!IJJQ-HsP%e_Z;Mp8vCjP5kzonvXj>Qd`G`z>Wl# zV2*|#^eZN`9dm(!wUPZ-7tGK53_mJ>owv~B$Q^VK7`)iSTNX2h>hb+nxx1P_?RF*` z7(DYM9+fb-HE5*8)I#t(kc%5!;01v@;C`!o|D z!pzs9gR>0GkGQza5R#~+_Vb*Hl-+L)S=gxu~6@+*4lM0t)~kXh{JRT}MC3 z{3>&NI9S&)#R{{(t<$V!5lSmIl=8B8+%CG``8+J2EI{MuS;yU%j_&F3+~Ohp@+?Y9 z3@nfAWM^S0Id{m{Na6GVG3R@GIN~BM6}fu*D-1cCy6qc;3z;nGQ>Q7qL|Bs2X>V+{ zt*YaWg*{x&e)>%#sL3!x^6g%Ivz>Ib2JleXF{rayiM5KNbv|++J(&Dv8NFK+VDsxC z=urKPzcE)f6nlAOllR}J^Dxp<$Xv>XhL$uu_x>7F?MUSK%SAMA@2mTlA{x>d7y3R! zd44xJ8$dgk8#CZ@xoO>meI0!aa`m$a{8`3Tw<7Imy;*R+Z?i3|XJ6AS-4y=us&5!2b9n*Ef*DyI}_zrW&6J9GcN4Gm^^X@4bgTEp~9N4tBst-w`)IV zJdmAk%d~i=oqG?^c|3*WqPnDjLV37kz38z(Xwmv~XJAqTZfIpHYR$5c=bZx0IRipE z924|$wEi7uOJV0$ij~8e0yp3c8yW5(cV2YMVC~%Du7y2IZ@}7RXNIXz$2*Av5znV+ zDpJ1zK~xP?Y}Z6P_WsCE52@7gJ@p4xf+A2K1ZZEI+WnN%ri9?(`)lLtl8xJET3LAf z;jsOnuH@9y>=o9}8cgR6xL+8(ItU0~jO_h6up50+*C^fy@l~oO`;3irPH#E1qSJe@BTRJV}*~utXABuc>rmWHo z`(vXY>yuJjg!;%rf~))@`ql{dl)q9p!Pspe*yrodmLH>=U)DYD$C-cCJ05HS4e*Kz zi5M?(1ES>o289%=i*O9Rijl7i_VWp>e9e-BGt4y9j;&(KMQ+W6R)<+YB@;p{l1VR= zy@sov-0H~#5QzGFa4Zl`$);z4?*mY7a8H}^YlN)U187qNRK1t`{UB?q#<6hQ&Y&B% z$82iGHVADzSg@;h?xvdY{Pw`c_m2+e%9J$7xz_e2Zx>o4Viu(qn1@yaULB~5>T|iR0t&sPvaQ2K@*?3W-!s%R>% z7C5FXS4^P5EA(gxJtD5|if~1@t)Vf5W*uk2yi(}{6*+wY5gAnU6LS?l;LlHCqc~k2 z070Li;rRZ5w=k)DV2lqb$oa5GOW7x~^CP`)HvEZQ%#UGihn-t^_?!)3=2LEd;U8%?kM|e*={t^Fg7R-9S~pts^ZgY z+$f<}De|`Q1>tf{JW@$b4oxZ**e2F z{11h0O7|m3&z5wm|7fShq@aph`XS{L@A#BJW)(Gp5!Y%$!eSKz`c7iaN2AtyDmm70 z)uOQ6{hpGOB5_*EV+J)O*+J}tktV+&{jbA%*jKbWihH(EyZwgO#lbYvqZT25^uu)# z``9vx+@nw>y}zg})CAO6tc9L-{MRlGUhg&TFLO@2P5zrjp#H44_BU23_)f~eU8oWW zTVJ#RD%feFQkS{^!P*?gh&c@(IefU7-#Ci8`)~@u6MiYdb;KSA#!KZ&mVQXrKdrJP+r3yN8?1Ij>9cmD>Vw{&z2$zdNA^5WJX-R zJvt;!Q@|N`bs_24o(JVy(eRw^pCgNmJXhFE^5xFHz{-9_#A&Vupb@Do8@nB_L#LJ$ z@{fkSfTF2UbAylP)F=B{gy`PL{AmJONj=?Jp0ivy`-h@BJx0osxny^XhJ{MX%2)cH z7d|Or*7OJETu^KVq?dv!E78_W)7ix?>jA+(G8|6F1=ySt?m_Q- zKB#Z_u}vE^k`ouOK@#-p@UgerG}Nl;FCph0R1#i3YZ?X?aiai{@Sx@_< zgM%G(gu67^;i(Dw;TW#6E{Lq%?)Vj=eU&7sS?a z;XlXLc9(DGr9%T=8_@YUlq9K}@gwMO}!mOz@X-z(;DT2)j#tK|dIKs$W7RM2@7-OO~rV}TG0 zfz#g~?x`3FHC$?gtEt|_IJ+v!G%NEI!k6!zRric}x4hKx1Da|w$pi09=ih5yR&en*0e5+<3nK8? zwHB7k)8-DxGq=s4*wy~C=mH^f)5BZRLD{QEv5h9jSFT7meYPqF2 z*o}%#Ya);6{#yb=dv%7sa2=Gr6(ACF01`_G@Yu14vI4;*$M>0 zDu1*o=ImSqL!aX}UXY>yUME80R+N*$P{Lg~f{MNu6UQ@3CtFY~; z=mr^>g%-u#2_6Y?8BZDKELaT=*K@fF;|z--i$@g*)kxywg?3w5q7&0jt{;c93J9sG zQtVD48K_L;_ZmW$Gm6!}JgWn~*}Tgs@X3Vsmt;7ETI0Q8v)>RutA1!in_k<%#r99< zDHx^i6io_pv!%B~Lyg)`G&2{0`wF0XVV!a}@11ZSxytdo9Wp%lUGkuGOn#i=&O+Bc z&bFa<1&F(Mh=se1FK8$NJp@xAg0-}9SnE|M38GRjk!l`fusYWXTMMGcN}i0f`Zb5j zD#9t@MfzI^woCn!6(gbPZ2OK_GOUoVwCEW(#5bEj5SCIvj*L^ads?-pHu~`+3+0{A zB_bcs3Y#fSaq*|Wl#XqhSZL%p=@_oHJ~k+Fp{6WuV;qo><)CJIW2~Q1v|9sR(o-0c zmvhm46{Tmr@!gv$E3lNynd%1rV41*F+l#qIU}9YXFzL`6^?f(h&ez1+da~gM6%`7K ztEZD41*NDxSWKZufG<-F$ea#{wViKZs>Z{eY=(|O>_~PaOJQ%%@?Y%}Y|&v#ku~;} z#`HoW_|l>f!80>=TBpEm->^ADO`oug(`5$8RQ(zJji!#ekYjXm$zwF#5MG{gR!!{f z6M83gkl3o2V+Mu{ZULo@vjpI`wKbN8rc|(aJ5k?OCQh#lEKnQC5S`+kg1dXY#HVmk z@}c!cDMm=+Ru)a9t0k3O){q=+j=g%UtwrNWs_DFw3f*&BLV@t9H1zd${rT;)a)Z-X zJ1fQRp#vlOaduh|ed%q@)o;9j;0=+Tri&GQMi)YXP7zr1KdGzZ5$Eh9DMszPqw zj2W)+dekp$IoLK8CkqM*SFVw1{8vb1Tvp6w@-s&E#ro`X~1EzGq)K7bHlm z4STZ|60$)AnSwPByJgL_pqhf1o*z4E ztpp>^pkTtw;|Hn771~UB0(lW}6G(p2zf1AyLP3a99{UT;{z~L_nr&2LAjML4^b1>^ zdt?S77~WK-{|CKZj6!6YUdBowAG@!c{c}Zu)Uwi<)!1s2^)D56Z<5`fufklvAd0oE zx#=!L8A?op{z7%8ss&i{&V%**;g$Auxp%B61DB0diNdY~;o@yq5j$~&5fkO_ZA>^V z9A0&O%f@hcDME|b{7N2fokYH)^0Qtdh5WAW7`CAQwQEYyC9n18_M?v|>bC@q#p3hZ z(BVWCN_+zgR7W1ZIDO4N4*VhzKQkH5sYu3@Sc=-Hb+fH(Ki-WuuniNT8cZ0?FnOYO zz2RFmFer;)**;R(4ze#~vN1~@hdvgGdL4x^dB(67$;uySrNRLDAqUm7?v_mc*5u2& zp>HYKvB_cZ!`)^Oa;f)x%KbaVR-(tS?sFQ7Hd0Kl-FnAxCV+1WeD~z00}aKZo%WA| zQL3*KQg<(>NG%`0N_}Hn0ZU~06H_QQ;BvBAL5q7ixtLLn)`i)b;d*@?YNo;_WYLb%wc4a-0dsNT9*%7gwwj+WYVJ?$yeF^v6`#q)G>xVd8L zRR8&GP3y;7mw6GC_xM0Ap&3CCr;DG0s9QSMPHVY@Tthyb2uYlvzuy-drvZw6c!~@# zNIe$suEz-Ur983<9h6G-e{pebK*>F#u*?cWmxR%+r6S}Q&4W>p(7neMA;Kh>m6Hrtd{nCMV;Ai*rM_O(e88B+M4vzgpR?`KW(Q0|Y-Z&sTX!j1M6zQLE2 zb7rTbuuOQ`frrKE733ppZZN4dQoTFAe(Fi=ZlKBIS$W_21H7==be3LmtSm5MXVNka zeV=aUz0@~Vg=MYMT?&WzM*7sJDtr_UkAvq6p~6NhMa45rG({4u!QZ(EnHo~@+9Dl; zx-oV}$<`TW-WzNlTX!v4*S{7Hm2ciOu-N)U?Ru&f3lA*T-t3R&T)NK5Oc@9(wm9~_AyHTdg0!_1jIGQ&n~e#ev9=u+g5XyvCpH)Sy`-DKdi})3lT$>|%It@? zQ)6_}Tpa@|9TrAl8+-kJ7cA~KX!t)-qlHvFT>fR(OswXlJqF6Ol&q!M%_zvHE#0=& zRG;skvM`12MH?=d5aUxGCglfzmqTXN1Ts8L<{xR}@{L&yqKLj4I(g4>m-e47A$aLI zuV?n(gZ;{%CjmgMutZ@Xwcb=9QD49dz4=xja?R_Dbs#Stx~ZHso+&TXimO%Q^R0CK z!8sNg{S-n%ei{$Qhr#!q^P1rg`GtO^tev?32Fq0736C{|I7x)ysleR&Op__MX*gTL|+ zPXb4m^HXV=8UZpAb7WnZ5YNQKfj#%CJfbzZr)lm$;y;`Vw(9OAA*$DULUP->fwDEC z@IZB9$^;`uJa`D%)o?=(`QRSD5KG&ef{Q-qZ2O_L+e#~!?P5Q@N;T4GZuA&P8R`li zqZi9ZEXx{%*zP8>hl^oKwuckUG zlOU@SI`VS2sXS4%lHwFN;w~;5rAxLKPxVLCYjQ1zHXoDK4t4%^{0UHs!FUl0H1BGx z?>EgIL0d>i3#guB5X?4yauSN0N=5T{^npO$D@Y!EAy6#TyMu4wHf**sqys;p|ue6|%M;wQ$n z57?M|07Z%_xkoKFqn%gFIj${3G;#=sHiKR>|pDt>pLQHtS> zf7%mB{3J!uzH+=qOrM6friM|&FeyOuRNk1(KR;%+{$K;_0{1~o<3h$=%sr?8lP4U4 zx9xBz3LG7J+jduZ!8`D<=_)oom&CRapP`Ej45$+{A8>~?$U4` zS9GJmx*oZ}3 z6s9T+Mk0#R^cOp-hPc|ws?}a=_UJUx8SYx?6YhL)p6-J3^JS;zG4@)wKK79cC3WrutKf)8T~v zw5<)4NIRX;DGy*$jCfZXbD>>gxUWm=S7&x{mnr=7-<$TE!PhPjWWe&%>MSl^61KwqfVi}%&^yYOl^ljmIF34cIj1+m~ z4v-1n#Gug?cw-H$O{$IhHA6c`FgVmV+(tGXH!prQhU#yAWW*p&S83JrU)42rC*r`p z=Ne>Z^Kt$7i}B4jHDp8F0_OTQy_c%+w65#@1es7TMsy1MeRmzUM!h?NgB&sL%|54T z2E?B*UIpxdh-<0Ze->T@AG;i@AntYrf@C}9EZr^(@B3FQJr6U&qpjvWrgHT$+fLdc zXc0#f@Ps6Vpp{2_cX?u=N?djC$too>#DPk zp_50Ucp|!`ngROrL%)k|A#YDcuxO@)T}aj_qbSynyK z5|diaEgc!@KnUc3tBsmq`g7=2ty;SW5@CU><4x@sE0L6|a_8nxEQQ=!Pw}SpvtZgC#;HE*UMw{(Mt< zAx2T1eW=TKD*@BOP%kl>yC)gk%LDPN(+En9mq8?q1?|h)YS@2r7_M%b*S*bW;j24~ zdzj6VLoYGE+=!-@Fr5AqK%0nueAL&{?t(opif^fkT-(VEbQ*HL@5&HU3epr3 zx7id0AvUjP%bl7MgGGi5Yw87o z|55@OJO^Z6sJdzF6rb3cx+C;(sB7h#_(6|(xvbSh@%a(xV#Q)_`T;K;li^K)RF*G# z=No;gv@hh~wrAH|-xiOVA*PV=-z)q8&c|D2=broZ6&FkNv-{n4g zwX=|t$a@ubIiOEIpXQ=LCa_?BG*@thqHQDBkF~_X#h-tB?PJkb`)wqRkEU26xlrA7 z*69ToYWKJIGs=nIQ1R4fOUVGiA&$TS4~ofo^8?T`HL13EaH67uvwsg-brV7RYSt2$@* zmBSE~JtyCrw?o5?;mwOG3dB_BbsWds_&)W2QRWf5ll^E568*lIK1!5}a`|@=ZB&|x zp&P_7WEDo#;m9RMuEUlX))4(+92W30-kEJ+M?6{oHpYLAC*a7c1eH^m$icxBP0L>n zd8BNIKB+sF7v1#n^+!~ks*7&XWs*QRMD!z<6(8m@6pR(O{;s7@H1!?>$7UwY9*@qB zJ~X6>2k~~LpsvIWj1Y%2e!*bvE82=_Sp9W&_Pdj2mv7K<^PQ8CQz^viPEr+4Zh3Lyz1+UB^yBs(=SIX&_!lA^1 z(iP0+tK#+}E^BI}*1$6XcXmB~SN6?&)VD;+ zFMIDgIugnv`E7aLxb(IqyOmp*aG{tJs@nR*Q(WUBB_(+{5}ClH4B8QH((fI~o>jg- z4sXzWCdIFG%9w5|(>C3BJnwIIGtaYRKc3K_Uj$|)$nEc2%P8>^zN%Mrg%6ZyKF85C z5&o$|oO-m;n9tec0yWmmPq-9<&$j&wqfab4B*8XYJGr(Nogcli;WBSPlXI_KmDpN^ zJppwobFppd4vWr(#OqT1#vp1`%9Z=jsrxN(8Nc-6)%f&a0zMR4`8!(g@X9sE&HQ5N z$>LZ5;u8}h)&;T~rhel*z5*q5AXmeMpjz#Q73+0B#sQn&A&?OpIj%{= zBSk#=k!c>3D>X(du+sAnIO%emyFO#1r99oG?(`$h*DWpVpe%c<>nX%I`CEIcKH7Sj z^ULs^)8+D&2JN6f$O_CBAzWql&X?;aSI?E%?YNR_=8R00$2C=jpnW@`P}}pv(iMWR z760izhJ9MIxVC3_&Ijq;G9rH!V$(e&%QvdbnWaJ16DfpprW|?@thVg0{kk03<5336ctMr zi4P}3Ek9%LvNr0J%S<)8I-I>YEEoLlPPrA~>!Dj%fLNP=G;fW)D_jqkCm+0lT6|z# zcmuUPo9Abcg9Xk%fTDZ}^(n04+8k?{GgbTo3O4C?+;u2>B`%}06{1uM`2|DOyT}}H zJHdO z$cgf9`3P}DBli!z2)WfDTb0jtX#UsJ-Sz>9{9Af8#(s3 zTnhdxlNk4gk}ZmQ>gn|o_pOHO0~VdqMgY6dscFKBK}|qaYy7(YzR*T?jM0CS@gGlo z?rxX3(iVHfh=V;!2M20Y$KBuJc{wGtFK}7kCx>6<$^{d%<|y<@x@mfPD@^?4_y2vI zPSBBkzO!pM#h7t0$C%IAe|F1TA!nytYWHAC7Vj5 zK^SHbeqBAbqdm^ed*D8t;kavAV{d+4G~3SYjS*sRXNd;E_I9_uMT9=!Y~CU z`n#Tvc0q@yljL6ie62D0l{wRi7pO&OZ1JVt5tN>KFtd8P%3)#kWdbg1KPehOKW)sx z1*fTQDz7A+{Kx_8fCG9$@)|Sk`Z~g!3%dyw zA~zrpkwjw>RtqDN<+}+5a@h>m8aY|Dls%Aux-la~BsQ;czZ)h7 zQr7p?$_@crCV$>P6rj>Bm$>JW_((ZwVORzCY5-`eB7g~#li~YgqB!8InkGqo)kF<%Rzd5MsTBn@s(%eO{H_{iL<+kB5qQq!;_hnnN35mw)2y( z!7rT03=)BB=FaGkV}ovmg3_1iH738nTod1Gb~ETr=fgci=Hj3{RO6~It*nCmr)Vgq z?uHDMHzFwTj;!O5vyT%3GMjTUzlU*vmeiZ!2EQo>hPbjhsCxtj{k2Ic@1Z=`nm#XJ z-w%M>!)ovO1-k9$I`i9?_TCFwRfaWa9vCu~mV0DI{AVxl33J(1*gi{3%Ipt<7kq4RE){i%;g(5S{F~ol9$#4W{d3D{Ut{ zf8X0J2QNeT#u#6!+@)_HktPh)Y<2jm*fAN-?G&vn^b1Q}1x<3@%=+2Z_VTRcI}5!y zV+yIc?1QcP<(Uu1hwrx^E8G5EQ)Cyrn*DH=CBlK^-Ln*t4t$IKZKXR@#qa3<%rh#} zw3We8V4z2TD0&i1C4)iX9BImoodsu@)Y*H6d7@W7y?E`WfNKr+<@kh; z{3!Vu_=%OYO(u2~z^-TLQ=}1@_RIAf?YZ46$>UdMlUH70?Mje!^6d_%J?UL~Bthfx(`j9jd%S90b#DeDnECCV z6#kjAMEcoXghfimAC(s~nlXHkW2K7g()iz*DvtwL?^!a>N|mV(-jrXUBkajpQEp9M zo4nV@6;o7Ag?47Os0k99B53s#==T~YJlrq;mT6Z>vF~udP{3H9+Jf@V9ZGXX);n{Q zti*Ufkhprf=Q*ZHrz1HO;SA;R<_Rlk)D5bgo^EIn#0RZK&^h2nyTJ3!A0yzD?@^^B zWdgYK+@o{FY_0a19_qu|7b7`XJ<1_ajY*6w)|roR(A2ZW(B-L(o7cVCh^5(YI~i8( zEq@i*_3F80$FEFnjjZohFxD9!4Qj8ym6)fw&5nfuVKmTDb#C_Itj$2_-=e3a$u zo3E`k*$C9y5p_%5Vznjd-Lb9a+c}uW!Fm zd0(?kJgGq3^m0&s+=3e=PeXc5z-WShT{;mmN`K)n0&4ZFYZBP@jK|rS_NtF+wwndP zznz-R`f7|?nd~=@vo_jl-_L9pS?vsOKHd6$Fx^$TJp~K%`V912)6LzXTXM>J7O)An z$)#E5z5L>~WzfW&VLIQC@OCH-Mi(L_KsFr8OZksA+g}lMDgpulADiwv{&iS$5w<5q zbU1~4m&t$oCC2{sy~*-6^-E2pLDTh?)v+eVlIs^zF`?`M`?S`k*P9<$brS)*ZQ7n3 z1danJx{VqD>6B5y^@J%!w`uB5K1VPgGK-aYyu{gx*8C!{-;!eTvM9XU9?tvCvXg~E zn}sOwdiTzfoWO4%z|;cTEvcY#)5DG64?UIKknY)DhqWz&H(!5A;QMn&Yj4Tf4Q+Y9=Py$ z>FX=M_H@l~1raVPlbmTeAx~G<)R<5IucxZ>EKr3{8k@SopQ2RZY zdgO=0-GZ;tKuMj98BgZ$y^6UunaRcfuYu~@W1z@Y8IUJu+@(z(iuv%e?4gN*GH=vMcFfDU zhR6BCvC{Yf3DJOjUY(fk>!$q!4&|Y?<4bx>5=FaXSv07&p~j1OZcOzTFzL{5gET&U;$lfacm{!<;O==ZT}eXz(i_NDK~9?rdB5#ask{2G-8PJce*bXq ze0um-!lM=aue0VKrbCG%8#uUH4iPuP}zjYD(O;a^$OAEmTtHOx%w&ruv`!Zx8Re#1;hF?|0&>C?AE}tl0@q zX|rFbaF0pjUxl z-R83INDFQV^*e&*Yn8~hKA$ak{ml4(dRIibP(3QzXy02H(^y6Ii29j+a1Zt?hONmF zH>t}t`g>=1wvA?*2E)&F*lxXypmzLmWyCdb4$%@&tu%q zcTab@FXbPC~*AhS~n^bmpW6U4Q<#>;qYGC*}?k%mSv0H0+TczE< z3{`@<&-6VGmX(yF999hEF&JJ^w%CdFYPiw4A-Glluq3~T?=xswhlK6MYV3JQduezE zpu1vkUNrDDP##bb4@}3~Q7ag%^6LUy%wZWvGhFMrx(k|%ii#u}rSL`cnpa2$COB2f z@eMbJ;9(Y6PD>uLv&-4H@z#w{26i0fhMer0`AeLNZ^UM)@0#h0n;Vg=Su=rdj%B0T zK_AyRsuQ(mFb|ngiAMR9cu6it7}}I+CPD$ES~tV`NmoQT9DwwWntqDOGIY_YfWwXRrjKDY#cA^^b_myOpBAmGi4WVXZ5$Dq!81egVXoVI-frVVJsPQ+ODAf+t9G3zkyau3z1oPkpZmp ziAU6oRU~$8p52oA)0kza=tk1SFA^Pk#&kKhJCDc={`?5?t+Tmh8^%WJ%I_*fRZn7O z-nHF{dxTedcgtpCgN>^x+>__+JG2?gdzc4dlt5=hyPITZ`H#d=s@55fgw%I9sFr49 zN;rP8l-jwlwoil@GZ%#BcFkS3cZFnjO*y=rU9iEtYiVvVT87J@zj~iJ32{E8rIg-( z9vN;%yQhU}HPm-MDQT}3=RL*h<{Nx% zLXyb}DirZn3h{qF7E0e<%pw)BWg%QLN`xMgpSuyHc$||~&M>nRXOSZ}g9lXmK#wIY z_4{fiq<8=Pmvr3;=R}ws^6Ul-I1ldp_|Q_M^g98mjJHwFq5*E`+JX0psAy=^Y=SuG~6|c z$YOiNe!#eDx+G~wCk|CZ$e#UEo(b9yNqFAK*kaV}ss5s-rvR?YeCtHCyi?Gd4O4`*PD{w9Vb()Kc8ZJ!=v*jQ2pJ|S1#I5T?+nyfk z_@bF7*Rjl94o?jGgHe)owFqe(IB{VN_V345GAsVDkRVcn9)I5!YclSFrR8l+@V$He!Ti_l~Wm z-0`>wiU8nEy@(yC6%|CT7XDR!Evu=jNaP49FguHcen7{Z|D;j7n~-iyVJvvNtb-y< zWQ_?x_r7BY_cU?sRF<@vf>;oSB%T;4RZT2(`6(%ent6=-C0`rbQBp*oYC`V6RpAVe zni!1JP-4wU_Ej_x%ewFTz79@TTuyh=Kag4=gC6dYeGb&;pvlz)%*DnrN~c}?YLj|s z8D~qVqw`)62w&;a6hdjiU718_pVPPUf|)7HWZ&jTR#umc0L&RHXorAC-1#Wo+urLU zx2)*c{yUVcF~>Lz&}6=$65H8JrOiO#HXd zwSMp!K|hrY!1gpZna!e#Wb8z+m4)Ba#u+MaJ9R#0_%EY~J`m>?SAdX(ZuUOqx_u|X z-jTrl;Usm_cyaaKhDiOyWWjJ(XESGqH~Qnsq$}jw+GCoay=>UR2UNHJ8=E9B=-{rk zi@KT@xXpdK2^b|q(QcpB!N7T}M_{_m9_FJ~9|2y9I(j2Og`Q=CL0JC*Fvk`^_Ta+@ zoicFn(x1+xF;#N!;Ks-zKVO**i{VEW%Ar_L)=vqLWD1k^6#80b-L8Z;x15VUU0Y47E-bp` zK@sJ6q3^0{dwIRA;`9n`J=KeA7jS9#A5C8!*5v!Xy)nvBQ$Xo~sFVnjg2V_3K`8+d zkZwjOAidF`lu{x!N>Ea|WR!G+)aa1@0HYb(-hF?^@&2J=pmK0#nE&g|da|}V zLCKsa1TKg;^-MzKnY!85nTy5uX1YdVaziQE>xICyLt+6(IT;szZfeSfA^5Yx#l~q+ z9&Bz%w^|W=*h2@kgk0E&;d#kz&-m)m`J-f*Sm~S$cbGa_i;zF@1%Gstz*LGKoO~3P5C{37WX?-oZ=5q0V0B0D9HVs>% zFQE)?WDW~!{~3ZZBFE5?OHwC4q5>`YKw#~)oFpjHy|w|_^nd!15?8-O2p4v%EQ($W zDVxCFw{Iw5rflTP?igU_;ZzWz?$&FHyVLY!y_dX3qOBgASyBk|3-*)QiZ(2yB;-!( zvz#R_c2RwTtSDfQcwAQI(tG&U8Sf;9XLLTtF^$g>4Yv?~HXP!eN-RmVr^BP^QF{dV zPTC3lj87v#I2jm}U#K{}*P7#U*0q#m`!&rzcmiUiD;|8D_MO&=xo%>|&Efh<45NyT z^qyCDj(A|KPwEGQ!G*VTUfeUb&j4y4qPn~wqXz&KhJlPZ(kfqRneMu#dK>F)Y4;?5 zAZm&5?HDP`6z-W{hP3ik10e$o%9OZCluTe(Tpdu}QbSQGI|w|5yn8R?;BU*PHjCA( z)}hXZrFJ}Yt3xMRzAj0c!huFKqFOO7VC%;p;b?~U_{X*u#$IRVj7x;lv85B{x;*~I zETpoRlLXE9X+&HOB7N+XR|QlMtYnXHyuoWM-NHXu^L-4~7u<5PDf@`wQQw;V(h@uR zDB}@MT9P2sd60(7U?DtEtN7(ox#@CJqFaSivPx>VY!0zpr~@n<_(Iy~vd$baKn99J z8S0Y{l+jR5@GT$HL|~iOy532t;*@>L#1-z93AdiF*Swn*5aJ?zlsu zG#feh95L|0ipcWiy_*T|@v-ml!v7hcEY;SYipeTA_6Y(^FrC0<9g>X11mxiEnvQfPTHO|r?kwrKH2sWof@?XZJLi!W z-Q{C1=n#jkKfbb4KQvb4A1ni3g#fa;Ey9qnBH=|PSQ-MZW%)Y4Xk4fsL<(EiW6zPS zi|xubLs`Jps-kl-k@2@m>2rR7Dh4If0Apk*AK z#XOoo`XKnA#r2v(98Nlbjx~vPTqaj zKQ9#PPnK+#a^5YwYax!i<=xk)Jb&m!NJ|BJ{)i1S7^DMRPlN!vp4AKg7f12Af*hgx-< z{deR1s3N_i8ctZRJt?-2-}`hO-I+B0NRXMPibjN2{$8)>n|R-_lz8#?MX*_N&FQRIBeV*v3JJp>>zH*i%np^ zDtJ4AHs^S_)nYN`=+jv1(z})Hw4>=#9eGBPDb`^36Klp!#NnsIpzTZxSAVt^umUa@ zGayWqJpqL{3WaOtWUy2Jt0TYj4&w0?AkRmvgn9{)s8_w;7QoyNUdC;eE#q4%v*6_% za|-S*r5+%!-*f17cTX*S6WKQ%nK}j4ER9waCaSknCo<^P6_imy?V?9CFl<0+nQHR5 z@dZ67Bh)w~6Wb{A{GCYqh#pe0&?rak=K!&&Z>s{bDsuf3b+%uvPsV({@==CckhuD& zGcR06Uk=adhC*EfUtE zONr*Z0{-t>CNV21QlkzU?)XD0q2n*RwE1g7z8TB zQM2M7vtIMm1|ezPl>`*SH{5egkL<6*ciR{ao)=hNmykJcrN?|O`CQ&|kf8fI)gFQH zOxgOgm(UZ^4xZXW*PKLUTeIn~;kCNmTfB(ov}=mcP7yQLe2WM++OA7_@;f#V0D1oT ztP-*}&}LK#z-J1)c;}MX;A4!GlRT_rZbP5JAP6I1uWtEv$ET$(TTT{-C#Ga~Q=ZbS zVw{nPqx{4Z&v_A#pfCJO?U$_OR3R2Tic8#q8~=$|^SNC0^lL{9AcUS5mgi2^e{Roe zP&nEYC$i1BA3X)Dc{1JmSY0I;z+?A;8~^2KZ3HD+`C91p?MQaAV6mZbbO%`e{E4a3&R0kpx|^dX4`s!W>N2mFY&IJrCrjdNVd#_h;%!Lo|ky$i|< zemwOqenj_a{Fkipd0mJV#BZ-#S&Axdc2xw3M-!&Bs_kIOMK@k&r~Oe#gXY< zMay}8JyD-8)h{$g-<|m8I9{P)#+VZN5@52jFKarU%&k~{{rL7JAvEoQOb#OsnVb}pY8<4 zCKUbljNL_^_q912q2q&J?h;pN=e#q@h%CRnCKHH ze^1q~rAXmuS45jQ5`yIs!ZTBvg-@D?k3!B^(oEl=dpw^W1s81EoBiyuoP_`V z{+e|Ko1=Fj2=?Xscp;I37Z)VTkR!gT4p$M=Y2S8pmsi3LB_YNU=49JHv|v@&6NaDR zM4h+$hY4W2vmSR9-SDG5cV3u8z(#o{{&zBsl`L)`f92&l;jPKbRZTv@wF3tP)-5h3 zcGeEzejRph*0a=o_-DiQWVf>KBgzO=dka#_2D8XdY5OS-oP%%p!6H20iBic|i-=)) z3oo+Z>N+>31Oba@t^klq0G#D}Aqfm>pF<<6b1X`GFfM4hY#fQTzG&J7gfZUh%csUq zPoxo9%h3<7X}pfS!#C0aU$ftwhw6%Df#NJP2fpt1b>WF+4XyEx_pk46yEN#jKBR_7 zxnaO3{PuJ=WK0MQ1(d!V@{)T1#o0&pM6qB&uCOT`R_B^p?Z?4nCObks4eb~COcVMQ zV|yY&BNrnKhG+Xmpr-u4qo|VY=azrdk#MVw8L4qsAqJqX?eY^LVN41ebx{lc6{UUHpQ){xsp!=Pq^c#lA=u>inK@pBYF?0 zd_PAKjA#2DlY(n6ojc}s;0@DCP1d_1&$!;BXa_vj)n?;$jq_&Mi~qu3tv|@4S2?~% z@GRfUdPwUg9tcj>t9;~C0{gZ{)GS^-4j_yh-m8(qMfrsc62dGb&`$ng;W~(MtOymt zuFLLvQkb)yo(Ju>@<6!z5;J>&DZPMuw>zW(;^Ku_G6AF0lSHSI<9EmOcQFKDGGZkG(p< z&1nsE*dgj>dI7?N#fgT;gl8X_-c2oUI?9U<>b1X`T4}d{MTW(Hq;Z63e5#~#4wqySum|ZL*3cU29;3IiwL+~#;i}B zRW08juL1_)+;Vmk*I%nLqXfIG1;6&lHl>K(K}d$&u(zg4@8)Pb8|0>?kb7a?TDiTlG`4c`o0))6#ntTue%pHwT-S69{(Nk^*_`U$6=#oN znHnZwsV7*=z3_XA`yRhZMD(NcnXZc<=iPnBYl_{v|N3egl~B5}!klTtG<7j>8+H;( zrLLL|J|GJ0R57hDLk6`gSS=;?c-4YMT`hhZwpG$mCj=!Z-=nQ4`Rl_%O$?^Gv&yK} zYJ449BY=M7o%h5BG8-F6-#z`TwY)81bz15-CxVmp(vN_tv7!{$whV4lq8hj$^HQr6 z`cY}Y@!L=-5x-odpPi3=98A}Oj$INcwu|+r{yz08PnhTwEqB`U6ZH~qr6V)$5#J>Z zsq>88wd-5caFacLT)Omx-C>zk7(cK~xBJmhi@35YpUb1@Moh_;3WM8R565P-qVYaR zZ}VEVuk>Vi@J}z(Cdx~ESUYq^O_F*NrVDq%toETqN7aMcTY+#VX3IX6`jm{<*Jl47YV|OZUvJDim3-P@l9EUY=fZys~&UK(b>d!g14Llh;j;JJC z{|vQ5q6Mha(;J1O`@cM32wm-oYu8^Cj~{HJC+}|dI&P;|$BH@kbKO}#jBF8fz5E7U zIWlhI`j@Na|0Q-s%=_@a-ixIlGeg{?yA8TUr_*ExMj;7B0+h{mwn=ed&cS&(apd~;!w{tLw<>LZa_OK zA5l`QU7VLb!s7Wyys3Yupehb6p7}W-l=yE1piZv&fr}+K19>~lo(~Y&eZev?P z4fdbE;fpv2?f9$S5AEaX#e-L>F7{jYEF$)Iemg_9MnElf7_jebdCA<20t~%H=Tif& zWMGvVZhe+l2Tpu|%Bs@&@%A#sSMmKeat>fW;S`Cc>J>KGC zZs9(smJ>`au^Y5puSw2r54l;?dM%TeIk1B8^vLjBJA&MuhB@;qP{l%Ii@8&^v?y*J z){_0S;m}!hpYG1YxCbC}yIZNw)SLHkP$`t43!| z`m~vD^jYt?6p7d!2TPoE}q?L;yeT_J^e6OnSh0= zx@(GPJfy~m0YPv^Z(~+l}Mb+0mBJx_2 za`|DZ>otm%r{HXUGqQ zhYU_+)P3($LJ}VYu|MeAu&{aN7#rlK%ROe8JjU!b4D<-{&|&xCZg_*4>OPW=r35g+ zDT8;mL?ccBqs(o!qL;tjGm^}!*+L?Q9zFNf>h|9xxni85p*-Eq))L9SjBNUTBc`2?z-KNZ2;? zHOwe{8O5`xN-5oOVCms_^;$G=bNRP2bud^n|NKzr9DM6a;Qmfd{|T$)iPy#20g0-) z>cHANku;V3!Y;p9YWauuc<~;8JmLy8!Kz5k&JhQHT@k_rdF{7^ID9lj2)$mbz>Q}N z69Q)BjmpUEv*{e+hHyUD3Fm2N7Yvuqn!t?Cp7=?7mm&0~H;YD-eFKYM_6_9JRrb-@ z!kb41t%pzhA^>~1xi%(RS%DmW_B=rPsbrvtlQ?x&m!t{wLG_H7gt^5*4iq5Aft+=} zYBX-3oK8c&BU*H>=Ee85*B8yDbb*#RBaCyuexnTW6UD~E2yuVZwmU&;14Lcq03urE zI{)SDbR(KKVUU1b)}N=)V0p7N>iec;#_Md!^eP7`H4857{Aq}M6l8hUh}@w$qr+)L zgQ6XyLW0<+7)b&=l#?(XIjYf!+v(vM?RWNe!|MH{9%ueoNpgBhRjeg@>QPz=@Z$nZ ztH9t_f?)A0W~=@xWE4pBvhXJ3<*kq#)x=HN(2y*czrwd=$$R2GV=#dGwc%Hp;?MdL zesy;OIjnw$T%9E>(&X#kPCnG%xfY!B;YdR@IPraL3c?&s5$YGuO{G+RA)0nW0x z5v!4l50U$IWTdWk?X%iAQVz9UAyxANm$JZg7SnDT1ovWjjjE{Y8N5uB_-BRwdtbrf z#dy&+PVVqR*Iebmf?{1#iacTOQ=mC^8n#>yjQ4PAeuNK-+N6YMs4^XJeB%jt0$X0T z`fAy7yPRD!SzOu-K2aEBVW7!|e{1jj6_HQ2Psw(H{LUY;9Imw@|4}WsiacMNH`|$9 z5O%^M#WpCz@-xK2U=sK$;ddeNPfuq2=A1RBs|%*(+BbEs^-4>zIe;FuD+O?v9GR!2 zT_jbRWdCl8Y^!fkMao!ydW6G(0e(YMHRviOyo zlvwQs`e>3jzq-HMd`FeS0UTb3BNV{3o@2F|e$NtD*8+`!b?NY;rMj9IaMMl-*%x!K zXZRvp#~dkcZFs)pOVa#yBHnUOewtz6;)Mf(<9a0*`VVeQ7g3Yj9`=E?HwjK2F3A@2 z4Q=a~)_IRJBVvi+%%8=Vb3;-4x}CsXNeA!-Xbk=}oA#&$!N7`~HKD-}YAe8XekkMj zM>L7wpQUz$e`K8>?M44718Hjo_Ciw}!2J{SMAb`U;hRMPMAA!+liXO_&*N|27$jMc zXi{X7dKq`tt6MkfwllVSPJXOgY*XOHwo$dD|IBq_oKpifiOgK8x?0&9B=cC&LAlbd zg4aaPG%}&$@;fjToy&mPbYcH&l?-CK|o`B#j7C2~2=o){`VCb+hgfgfSmH3IGg zHeu&%nNb#_2Ws#HhaWmar|hx;S1eBIL2(|lHH7U;rB9|5;gWt~dQ^{FZb&@wYvEu1 za)WtDcI`X_Rl+~vJtu|5g6?}mSn?%d|6RV6rTve!{1MNjawj&+`Iychjr3$%yivL= z+WY#jVLjdd0|V}>(yBA7I;r9H<0KFIgR@;8-*b9CC;f&%0?HeT_xZf84_xRRt~50t zu3e~!+gCqXI$_0ikE;8x!8ZYarrX~aO`RV~po^aZ-?O~fd`iCY34T}3P09aH2%|4{ zk#^%ybFqX9Q+~ioITU7HWd^q%HJbN(_(W9-Csu1V&*0~t9hk* zbhlXqZUTj475U0GrVEvYv&kaVtkfBZx<{V}xz?erFH$4(Qoq%nn?;e%_WD;0J;p>^ z8Dle1$CcQsLg~4!mH!@KgPgry2X6EzH4^{B5r%Zr8%zEZ< zF{CrMM(x9VaJ!B9w>!lYtJ0|4tA`*!`o(*dY~Vc`v;L;uc`XERMd2<-;+pI16*yXZ zAK_MpSIyo4ZX29j2hR^KAOmMKTb#vP>kngPI$2s$ytUvE; zBaj<-mnqpmrMwALd7Iy9>aZ^mQ^Vw_>GU3TbFQ}$%>RMOA}*40E(3uHxl&^Y@ZGga zVoooX`VR`e^&1_9cQ||mRLWPFUJ&Cr-F=h(^0*B)b>uNRp;bXB_~$aH~k zX=DI!cE{6O)Qj>_jUX=`W?|_7vAq_!Q_Sk*{le3Xf0BKs$XPysH1Ph%RbgS{>(O3k zV2Y;IH|1zk{T8*C-FkOF$K4_B!Ss0>f~g>KLhOvKg$_jHEW&{>amj2?H4U>sR~ZN2 zo zU?KwRvSMN0bVdcSbAyoe6o(g`RJ|s0Vo!KWA!|A8(b{(Fzx=OZZUOIg5Ya-gbT%mKqdxCQXv=L> z(A6ieYCG8Q-hg6+;L~^YK^N+i3eF5^^g-;}#`b@G@G`K37bC#KfA8OQ4Yl5>q_f^K z7-g_gDR=h1bU>R6=C{2|yJD>|Sp*Jo2@nM+sS!(^pl4J-#M!*ajZGuVx3r?L0yHQw zAo7)5_e;86-YmOoJhvsC{*CBeu=uA&N>B8&?5z*9+hOd5N!#E1bNE-@Q}%fZ3=0!9MOlon`hzwO^{!{; znR=hD!{1+2tj<*k{f;BQr~ag``j28S>T63L;Q4OFCtsP}0Gzw+mXN4vqKxZZ?NWWO zF+;#hgAhY^Oc%PsH41=)_M zUSz);XaUc~$p{2Q!^@cP*?t z2LgNP7!iDmf+sDdU|n`WepaPy!ZG-%2JP>kJ{vrCbpc+x3}`fswTQ&$G3PPn)3 zKjz4SYERcbGw1N}4?ZSu7H$B8d@2uNqG*5DzyT&Tx_RNYt?8>mq=dTw!< zo@my)(`+nZ&sL)*MvxL*t%F?TT-l?`aCZQGK>@Tyt2hj$-z)3tU*Six!;Bie+S8_| zz}+itU}WKmWP>&p>lHD*RflFT)U63HxFWLFV=l8@M%K~mBgucDB>10A`!7=l-F#|7 znpEx4PVOdUu zwKXcWwdQFd*#5{gW6t-~Sx$;8G@&gnK#OXg2hDNgrJ)0t?IkE7hOF1&kIfu#51)MH z#+cC#?KcSp8FR2&Vl}usBi)((6!r6`?TdUeLQ1h=| zb_Vt>x7d}Dd})+4^iH1el|qOjV}4t8U%_LS-dW~Uc{MI^nXj~tUfK50!9q;GHHIkLDOu>3Qp)+BlO9dc zs`pX+%Bj&Cl~5O~1$7JS^J#l9-&9_UHY}bc{xmQ(=8%)Lcu70#0JL`Vrm10$pA23V z8UZD;IlO;TMY{-B+84uW>je<&#m@c%m<5_Sa_Zzzpm;@C8LBt*voq)^L;GAYVrf7t zU#*shYwY{qs!birWqx}{yCf6)gw%T66t>^n%R*ksytXbFF3s#t;XC$@%n`e5rLM)q zR4WW=keG0%0?&<$`qmy)TR4^mlzK6wNlU?-e~cwL!Y!~ZPKW=ouvodqn~36#^YacO z)fBU{I09OJ9b^uP?dF`aU7G+;o_KrowFXfxCnn)xvYYL?YtxoT4{r#0nIhS0eB$=W zIpi7EGT3W3muJb!X0w4a^t+^=&cZ)0=enh!E$mj(MObS-p$KL7JHcO7%*1;=DIm&G zGHZA6V8GgWPjG78o&1|*aU9&o_rHG%2gMc$IS`ucl+)GfiT+yR7T0~tzg@HKs^!4?0`j7eEXo{M}%m?RRy+z}^&79u;;AS_? z>~QLtvD^sI#}u>he@fSH?!&3nO7M8W73EbLcYXEQ&WN7xaP=OpQ_fpu`&xrDE^FzR zY1sQiy_80$eh>0K#S>&Ajc&&9cj$2bHAYHN*2*vaMS}ihSUc_-act5ctb-2!Te-WU zyz6@DT=)B(@;rOXlXW2c8JR2Uzfpe0pWiC_L z-BJ2r;Mh2^-x0q8wzOwPjwUhvBTs|QYH|tOOVLJl0?C zQR5T7ay7-+rN7&?>?do%+lsWb?59CkOz*JTmNBrXKAs+=yna}LSJp3~=Hg9ox#$|S zpBckx2AC!~76fA7=)2|`>nG^TvauIt1>YLnV3Hi_c|rN5Cgo!}J&f&VE7z$FIG`c$ zmnOTR=?E*r$~-4Gp{`Y#cue!^@%NpKiJ0$hPBfIX=vMiU>Wgn6idnv!sF0k_Yne7D zaB$|JO;0(&0K%-ia%>tXN{cy|{JD^4CdtpFQJ=4r8wKX}OfLR(R0mcun}x_S1nMHdj71rvs~e%o4ZE+~H%77RGmL5%FQ3 z(65qM!^0@$4aFa2#;kAtz3SKD^rJ`RHZwbpkZH$4r?@391WPMx!&E~ull¥2;PP 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 A=Kufz literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/button_focused.png b/data/skins/cartoon-desert/button_focused.png new file mode 100644 index 0000000000000000000000000000000000000000..e26ddf6b362ebdc9dfd2c1094c58bd25fe3c1bf7 GIT binary patch literal 7194 zcmZ8`c|25Y_`X47EQ1MQ$R4t1FIi^nWi3h886sOT$eLvsOZFmbmQj{u&8|ZBEE&8p zWXqDN#uo1&+xMvV`}uu8zdvR<=X0KOKhO2t_jO(8K99{z^q~xJ1}Z8lsG)(*4Js;7 z2k;*Q0R!L2ZeLE|2jqK0A4yg9iT68jKzk2ijG&^bO<_Dlp8<~Py$$a8Qc*E?oqj-l zUS)TwsCcRkbr2ST_G@`iZ{B;My(a;U%PfW&(t`z$h5H^S(5U)5k-Jl05=^s@*i=0G zwd+_kgEsd7!6fZsH2r;T?LwKCP`U98Zc;iv9R%i@UJxWcUK1hGi;9Rgk_URPc@8?% z{`*jD_TM0i|HF{C8&xJ_vmYDt=Z6%U4(38aUJK8~o}7fvpXAn_^~FmQLhzM@Yp#6k z?__bTNTYNizq7xocQ{Dmiqy5C)7fW~5Q^;w_%DSQ%oIen*^rP+93NJOpm@BhJ*;ZgN|_AJsx-)B2_CM;c6|6fD3q$gw5zgmVn{r9wg~H zd=CK}Xa04ZK&5zJ)PUwtA#N$mmnZ+WKu6aI7h!)I`HnvonPG~XQb3w|AXMayC5t;<6#^Z{0>Rj)f@vv=D$3UKqWEzl7z5i$`i6Q!z$k2xm zd#+Y8%eMQE<}^FE4EDqH^#&%n&Y$0TPz~W9S{Y(K|8Y7z>;>u|{A)lN?!gq}Ed5&a zfCGWbH9{(iB1!_qc_>PtX!j^;IcwO12`di|PWZR487;xUPLyDWbdq{XRh7oeavZOg z=R9-%nzqmu#9ti3T?xSt^q9Yy8dGA3HuzP`+U~EMtN(I^x!O}vuyfF&>MGay;pvJy z&)QA#BubHEX8;Fm?N;hVA!|i7%mBG6WTPTp61tfBdk!b$rIWqi_U4aMP64q3YJ2`4u}UIBQ@Q~a)BPOXKLM7OilQZ@shA8mZ(c*wrx;M<0IhBm5Ku2_emjk=W>!vQ`5EhQKu|lcTBLvCD ztV^Pc7Hq(2!*YpfrGij68ztryY}b4ImF@Oa&gV*Hk8`b@HbX9$6`axLub!<4H{7dK z%v;4S2c| zqMa#}$=wRB=;_Bhvm~(WfhPvXO7je9?35;~Nqdp%TYQfU<>V1`$#g>;XbD_3A>BB7 zZ}Jzjc7ZUP5{En`tloh%%_h&WIA3j~8+Y-;$6}TvBKdeEckNN9R|W2*pQ7!BOGZHV z^*NNasxX24I&}8^F>GARAwWn9NPVuS6lcae6e1|h1ek?9UROBeMUvR2! zYZ%VS75;7lH{4=pX6TBu16>QCunxP7Zsoxk@Cy45O{R!o=VG@WK_>zHC*sqe(8Y zg?nNq%wIZCbMb~w-iq*%{w~Mmm4pID3$#2I;BZ?*?`}^SWO&e zJ%`=fFEKY66oGmf-ux3)1{(V;gG@ngm6t7`0!AA*`lq}t??+dko&Y5w~q#bZp^k>mbK;32I$61Yg|0>7t*^9Ax9%Jyuxp+-~_u zl7SsirWiLu(Du+YDl+f9t_S+4R#h>@pQK#2ZjO2i@<9kq-tF$Zx?VIonc38(epw&R zemA?d@-2o@5Z9bo2vSzc9*$A27@3wZY4W4V-C;@{wXnln=CDf|R|(Lr?TLF-w`w)& zPi{fIIPQ%_$Lqoig|vVfJG(~sqTG1tX6o^%!OWK>2(L)1yo#z(i?N=|jDB>>ymZU! zZKj&zUM+-@_zQ0`J_=QRRxJd?1j2hEH(~DqTCE-e!+((=B?L}3YCTM%PGd@43Qy5a zq|I|9+$^p0e-{8TM=h^09SbGVFbLw}7Id-3#TF!}hr&cpj?;rI@cZ-SKUIMxj(s*k z9u#`Nzr-S{5t734WxasON~1uIS^NZ$Z5W!Fj0HD4-~5nK7g@q%@??tP(%FjK+?Ol2 zxzG40mnlGh+o~YDL%Wop`_AMx@d{br)q@Cj8;Nq!JwFptxZlw9Y^;cxcrD}|to%#S zo+1rXd1sBdo7B)x{zX31AT?iqfv4b}3yg90O3dOoRw0}U8#|bo$mOPNv^o9R`*LsK z1J#V)slsu`2tTC@g!WQR?2$O6x{a*Os$ z6KB17H*cBEUP~c5DENjjO@awY$PnMi$yGhLK;X8WfWZB{DS z8D7h1y~;oNe2XbHVbLu@D&^eusC-??1g8QuP4;Srw68vKTQWe^JBofyqLJ5#R4348 zN_o7|P28ICKIb}H-kG>+W=jfS{So7s`@L3`@|aU^t;2V8k=X2sb+d_%0MvN^Ank25 zd?&*==%@9q;1SSx;X}z}^?YC>vcSet$)U}qu4?{Cy$MdfqGk6Yfe|{~pQ!IYkl_|c zaFR8yV(9uPVuY3Fh@We4zDgs4z<93mVf#$d%?jAOn~)TmPx<#7 zA0|w}0rY=Za+JUWie6*R4$1W2;XUYo0z25M`T&d&+PDonO-Okx=&T7YXsY!eMe#|R z2RQdOeN+P{s*Jgw_|9SlGyqd<{XrwrU1==tR6f=9u)&G-9pz3*aLvkPIta*3G4x>e4MTSK>qRUu?tKl*{;$n zX;4QdJqN5l<3w3LX53PzzQtv8dbuogI`MWhYo@NBjLaI0NH&QYd+i#Qi_a-Wh&e`l z;KP0@mjia@_fFhx?h;$x+)VxMa?EKN3%W+w(s6b8k#eevDySihS%~Yr4X3B!p@8r7W>i}Mfs?shU1+~yQ%2M3)KX6 z`LMA={_Bs~`z-%1-j&53&faGfW$)WCRYbY*mZs6?Vs~(vXu_hHdjtYQ4inD+tEX75 z!?+}qD?5n*!a{-O0z#T?XZ4~6Zz~tC!TNXZ4O1Y`%OqFuP6Uv+C2wvt9ZQH4TGX!gLL8Sg5QB3V>@pcZ|Uae0N2sFV{t-Mml%8ceF0qU6y$b2H=U zJqM73AQv4|VjOH?`e(B~%JCN0r!pNDo1grqk3RyISbI~c_ilQ|U%;@-ebtpxeSeuvgcXF-svyAG;)>z8*rV{{99H3|5$!| z!}#yw3qkT{;L0M&jAMt>U#?Ajji{{e zYmfH)Gd=OHXFgva%i)SgtL&he*JYB2x7rOk`|`_y`8De=D5UzPbj;1cz8qMjf_o-8 zvKl%5u-V=>K@A4cPSz4c(}Ng#`y~Kwpk&I&1}vbdv^}+X35x}47WMjkjBBtgZ1LZO zW3`8;!%+Rt-njmZ+4NvB;jD?tihx_hO8p(}Ec_&9|2jjF#}iq;{$y)M_E6f*BkphmL* z2pUCw(obyiMz~`<*ZKCYxgyz&+}$EHqf~|eVc8yFANBcV@qzgv%d@e<`k?>n)fyJ# zozhWhGc+OB>#OjpT&_W0s|0bG-i31+ptt4zxTC;HREuikxo*JTKwyb9dP$Gj(Dsco zO3;BgcVR`mI<<#$goqXU1}`1?yOLU9^E?==hjb(KyOsh4&Yhsbmd=LG0{{C3BHVfA zzRP{HYZy-xnQSuv0l2^J%QljO#T1Wr%1O-p<@o$l zj(^tld5p@?9lqn8GL?29n+{0gxo%J1S%lrN`OLR)WZ^_Pq8*IQ9ETIR#P?3;OoIJf9r+hv#1vfLByeb`P`x zbGBkIro+`KzBwTsWD{*52TG;^ZVE@c``waV1<3jT5Ph*?S(D0Nzk0zn!U)^S6#xIo z-b4yzmOlg*VAZ@)UjOQm>XN;#;ZLDY~1V|r*hqp0~o&q8NU!uRL1htl>S?0qU zVJUlk96&a*;gAGYaIdK@fbWC@!oOd;Jo%?a3HmM4+tdV+l@^gH(n!`Y2Cz0W?q} zuq+Ax=9^Og(AUN2#T^inq=EU#7n-$-a5p{d7-pDS$7< z@QS@}Mq$X%pLLBtB-#Z{%s6633)6z(0^^0iRC#>P^{rpFtUn(jLqsKm`$LQ%E`Ul5 zsWua5m0&S7p-Y2|jaNfcI&uq(Q^$Y)aElOWkT42JnHnG25vJzt$rJeBEG^Q~*X05- zWij~%hMcZW-D0bON$CjYL7DO9J~@@)AAS?byUbIrpxx5HF6601C#znZO2u$ulm5b5 zsxNQN98f)K^lMR8f+f@?i2r;&k-!QyTRJtN*Jzg_4E1^p1({3xX+vmx z7yE;G0K?orRk*%LoQ1%4pE3 zGoL+nseSx9_mzc!-NP}mYs!@Fy{whbFEyaGSH*6NC61PPC)9bjF&$lD_x)O_;!GCi zw{rCgJI~ufAAbK`4B$g-M+tX3aU+t+N4Hs?zYLWTnC{ll&9Ut6kVqaKQCq$Adpj$p z*EcMTT&KF5d?ZWHB-?CRSeQh+%QoXdZrG9c?@%NSa1>vFIc@B3wrYk?kg>AaYr$hc zF9X39`*l4c7+-r`ae(Sh=9)Ia0Rgd;yz{Pu%rZaW7#^_e=#f2guyn*AsIx@R*9rQ% zO$<4HO=mKu!NYprvA})EmG;Ta%EY+MtUuxQ^82Q*$<86H+r>Wwq~c_5eNYPDUVWzA znPd|8)oXWAw=P7}iEu^d;sFPX#39Nmr-b_3gZbYfb!+3h z74;l>rJfU>0lbp9tUEgV6>coE@i(6*?nWdl*N*t<=;HcBnoAeLUW9iMFQ%~lZiZBu zo^7@LMWFq{dQIBK8h*g2AcvwXWag69<_EvHiNcm_BQzL~g#GfNFU`UIKvOpKeCwHb zm}y=K5=-(g#8^x6OZ@?s^@_J$6BmEj*0MM7nafEB^r^bW&6p8{F1VBfWS zb;2@ui+Sv~E`3{+h#$<6$ujItYquxDV~RE#d_>mF4c!eNmTBc=dmg1hA4KmPv^92*kn=iTNA4SLjKY-P z^hAsm-uxTF^7*33S{-Oql#(6K9aMcBlId=tbGG%gf!*SJZBUpCCJznXXiN;F1aDLJGlr8T?_CO)lx z1dPkwJ1&NEJgIF2_I_cu?uBXk!fz3L0;?k!!Iqmqh!^c&{T#qAfAC{+h*^Fjq3Z(p z1RBb9W!#lU#3*Wx?g*6r6f7O6c03V9>Uv1V^4{NdQ1^bi(;^4V+6~8DJ7ngq-syC9 z#?-s|YY3l*Xg$Z7|&dN8J-SD$oy4&*5^jR4;@gA?OL9QMu5`8wz z4^Y*IF(dQUVd_q5tRT@u8hPlz^gsN$%%`jDe6c2NCIuZ3-)xnsi(ca%bos$QE++xB z#xVN|k*h(wusQ`Qpb%3ANlB^W&~P zb!K!?T?ymP5r;lGD9(Dm_%#?{s)1KL!46;iWRzC5L;_+_;^pS5z^sx)RP0~^`0t~% zmjy-RsGl(acQ*I3^4QKDcZPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2Mb9=K~#8N?VI0k zR7DiWr==}z`B8)lrBb3ImWpUmE58&p4TUJ0m=uj9`e0(>qYoMr-~0o7)fW?^0e|6( zU=&0^Flf*K25bx5OiVYDG>3Vqvu zjNsOm7lb%_US05WD%TX43o!-`Pd>UxhzbOPHH+1i34$GAr$z>ZNL?0U_<|7eKM=>A z5h9B580tp57uONsrTTGi+}C;1^{2J-H z{DMxNb9J&0%826rl={E3e35C71?F)LtU{d7@1bDnAePKBxkvXeuukz^;?=>$eN zd38cNY2ylJ#zzNLL(lh+ewzYl`fal6XWQmRe0m&T>Wb{-^~vd^i4g?4=kX{JM*U{? z^24TpJ0Pwh&Sukkm-&-498nZbDg^XH|Hol?IrxenHU+FvrIr=V9tCht2RQ0(`ruc0 z98e8C@VeqSD>emK9pL;1wE{RqepZ!W8G`d0#$s{A{x~#$?g*_4SglGQ54Fw_MqmIip&cd{zcDPSSQxV?LPgKPc|!}K`?0>*KE<%nIs_)%Td zvmcTbtmqVAUH>1r+cp0~cE)#R{(=|-7PkVdJHXp-g$0Zt z;)wsQt^`LEv(RyVu{yUt= zefW{L0@kY1M{DyeQIW>3F9eAXXWQ%Wf&J{S4`TNafC^xKt2NWo@XRKffAFC%cY6_+ z^JCz9kojFR9DUDmwI3?rUPw)*rD1(rBg{Ye#0N*;y#in0_}a?>X%8yAXRZ=jY~tee{WS`E#Hp8DE0p4luI6S=6TZn$Y;52`7^B z+%5)Fj>Cg9jh!jc;W&hCW_Wa=Rz(H2v-ilV9V&qK%|wWg zE$ilr-EYwLvJ$CTFfbYI3~pn|j(R)Be;Y5;;jLPr1ct&ZUs4zKya{i+<&2tn}5Oz9K$7oJ=WLyO$obD0g<+s%ZJsl8xhEPETFuXHHfkgOWA9}1iBS77f#_zSi%!DUcKErc7S w`4Ho)G6BK?`Uk?F!nw9cB}$YiQ3yi(3)N}d#VJqSbN~PV07*qoM6N<$fPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D3Q0*sK~#8N?VAly z71tHVk34uVM2o}}QIwXkidCZoB^ql=I*BA`tJ4g$X{KZBryXnu+vzlRqSI!kU*oi$ zj5BKM*lB@SLrpsqsMS!7kfvz08Z?3t4aP(f5Pg6=h&agq zh4P7RcktlBgF%gkh6cqThVufD&qE^S+YsYL#+<>C27~$e`Nq$_0SU`@ zA;u4m8Nsp?+`W6ZP}83F_I9IFY>OlgsDOM`Er#Mwm_S!w%clF>gQDf$Bd>R;3?%5NG0WLu1sKro<9-m74cYcMa^B^JwmuMYjf`0r#Y!iS2SzC!R z*grdC=gyr3pTNa)?BMLUA7U9etohswqId*?NgNc$m>_~Se-CuMNi^7s814#D-$e-e zqYpkgqa-Tj1Azb`Mi4dnS2zPKg;%+O{JxxHq7h%$Ibwsf=p41W(q$m=D!9j>}?j67?V~6<$36a8?a`otE=g2 z>(?ubzJVJ4V|T?z#8JxpY=h_bo{N32Gihsy9^8kXj~5M*Q&(3<#YIKrhvzo{heW5j zU}u13;wUA3nqdU=@)kjix&H|S;+0V;f9A{?TDx|w7VsEB;G$%Nwg#|V0aoO|;khP? z8u0fb%f2isF@lxPsm2{9iiXJP^IW2Wf&%L9?iMX3{wa=@21tT%5+tQ)rEd9Syp0(C zl35lllQH`i{S9}=x8V$5Un{+|WhHfVbchxce4}9vums{(i)J3pGYtRRXGI|fOj?AV zKY$SyQK}w_&qE))zKVYHGL~IycyI8!TC_HRZ2&ZTmTm<2L=+bbSoy_A5mTg!1_uQC zsrB$0>h3s0w-8*~pm=``D+A<-qlrYfnAu@k-e zrgE_2HiRRT21b$>adSi`Kvo%fEShGEgsn5&G3uS@bahO$N;l4 z5-1^w_eek@X3E1DZ=9EB{!nd;lmrA)xrbE87Y%K%5MB75QtTf<;KR>+K>1;vZ!*J) ziYZz%8i4DI)uNeaSA7zSBMZ#{=#!3c&#h$FT+5#;Hv`-m1+;TtSh zS$ld;BFO(Dv{k#DZO{$p$25Pa9&L!o0HzHP&c4^JTSv{!&6F|kY3qDE4L9~cp{Ph; zKaulyqSQx4gF|`|ZomDMns*4;`T0bmS9MH1TEH36TWT>BqX9zZe{OCr)gL=XWo2cQ zmKMPpJ!iYzA#&WX5V3vgW1_(!1L)ocC~sJDyS?g>m%qw7+l`Vsh;Wsm7!B~SI4Zq< z^5jWcw#+sw4uu06qeEon7yXrJ$|}*|kU=Chryf`L4s{IrpwS(*+yz4n4%se%A>pqc zy#YA;__SKYggJDGdV1`GYAJe$$kSzhIi|)J)Vfpr=(L8_>i(huZSFHC&WnOI()rKm z4Zz-i_~{0xlUuex8K-CtQBywM@uPSZBsbIm!}a`EG>pK`k9%FC0^x)WJaphdPdH7q-54{0~=f4K; zrInPFz~Z*^OHQ;7kH72ucQ6EB6Afmx$d9=^oY`AqIs6&D0i@opzP_H0*S;!h_kc@3 zB5M7EsF?Bl)e)d^$UH;zC=Wl>q8!Zt9FQY8mvg(NOr4XX&E;PbUHP@B$l>1S#E0SK zZ{Jb1Y{3bLZMv!$z~yq;CP4GDl8LVUUerd3>u{JYFNlgYdgsR@!O8BA48;I`zn}L2 zElHn_6!`Mb5sfv7mKf7nt!!#&@x2wjSoihLufgH&j|^=JSUv;H$(}^<0hoF42GP4E zVQ8V(B$T zLD*qAdaB9~3uG6HNJ>jfg__pzIkL}=lJHyYj^G!DWfzJ__&r^ICEbdxTenI-H;TeP z=x_w@1Vud!Se7qe9t;EmLgf*5?AReae-wp1w)2+?0RMP^qbAu!BNBcmUk|^%&7(th z?kEX|lTp603B=DxIM|e3Jgn#)Vognr^5X^Bd7~tp6FT|@h{o_9Anu!khrd90|C?Wq zcJ%hM*XyPJ{(eeLO{K!ZLZy5U;4gU@f^3THw?-`BI6wx^BTkTblf?Fcn;wiJ*W9^t ulNuWv4S{RS;nXo^KZP4-oN+#?5d9B&1a6;^9KpE&0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D3JFO>K~#8N?VAg5 zR96|tzdT3+h7cr>I!1?TF&(g#M$$|jXkiAOVUQ6EL>*~?nG~%LS{WZB>cpwoTBnb( zltH0RTeOIF3QRNFs+}T*iDO9wD$huOJnZJ3-DJaVvdJF*-@Rv-dw0)$W}}&Del!2v zb58c&z2CX#@qOpqr75PE;yq24Jo@27P&qVP%S~QlP#1It8sdWSz!i2s^e;$EW-VR1 zRBYeA-B>mP{SI0H`Qm+09b~-dq*O&kg=lVW7U6JMY}~jp_5Ts*i;yR>p+7^Z7n^ii zv}lpIbm@{v5C{ac3Q76g7_lhsxpUI=8#FXDs6O8T&4L`^r+)=f zU1ZXztgK9&K7Cr6oX&v*2UO>M3v%S+km}?~BR0OVu~C|;W^8Os)YjIfp8F=`$Ty(W z6DN&|i;G2leZ4f(9v&3euU~IGKj6j>_zkpCPns#exs)2;_#EZs^1%9kAS;VCRP#}(*Pwfg? zb7fbYy-+mStN|Dpa%ZF!k>8_TR?Cbx4jno~>(;H4IW0z*>r?^k{e4DHnpwMQAsv3{ zXD}*9mVn{6@#ii5N#^tuO~0&{XNsZciRNs=ce)w6%p5y*jFvB7E^`{VQM$)&4B&5B zq9@b&^1T&i;~9aVtLP|E;mOP!AAZia@$eC7?b@|6mxLd#=H*#&3&ewaD_5>ib#*meyLL^MB*FAT4V;jnsag6Wqi}{^0lK}?4k0<|KU&hB{gY@R%ZB$psYd4lS zRse>0nx-eyS@2O_4m2RN?vxoq+lWejggeWZ1?~}JQ3^KyfPS(6fGknMeKnvbtt-HG z0Gv~DlT3jzI5)+IWM-VO@pIu@YQRr=;wQ3P4Ld&^10+#ZfMxS%=6~2Q0FL<#XcC0( zh4H^6%JsRo68s~auP&Zn!lj`Y=%g z^a#;?o9QMsag!aoAV1^-?s9<*Y1a(~bmO~PNi1AwGB{PP=j!CPH$QdD=59ydtL7W+ zy+!XHei=o}3v4!D6B-NOc>1kPX$Gh2+mI6DEWk}98Ri{1a)cs0!Fr__T`hE5E-UzUYHmeL7V1AEpf5>W4W=LAW;F9 zOW+SZfPZ1$p(0!>=yO1{BYFkx`b%i~X`2^m7zaP*b!~6QlH}%x9b5st`g@0#Q?Pm^ zoS4zGdZy?xJgr7Ooe4(JqCz!rl-L2ahr`}s(^?Ku?ISXwhGTzi^TQ6V05;yR%VDN` z!F=@16EX*eYPIF(aTCM*)%O*BGt~vg!H*f>pxqu<{y$g1oqAGD;S4nYLLN*d=n7fE zBQoO?UP|xXhQTF$^MY;Uz8*mx4~B{Q`-!@`^)e&pF35y6_8mmRE~4d2Q1i=*si}TF zO)Gg$mPpvgpZ+#cKChp8WGq5MEf3R3!Cq}8XA~NSaWOf-#USksnG|w!F&oX(y8_?! zS5be5t)Bz;S<9U*BisUb7f8w1w=AJ)GYri?L4Lcx0TIE?<;F+pa?f6B#U%nAh;@3< zoY5foiI1R$^y8xY?^Mx-MhTZu&RT zg?AsLP^X72F*s7KXP%_t+@0Ff^dp8{U;cgvT)V%Fr3>t&)vH&FNF*YCSR3MTv3vJ! zMHnkQPqW9$xX<7@Zdq^xf3MYZDAE0cBwApN=_kjU0t2>yb07M$P@g^ zIKMisx|l2N*s(*oe0Kc!apmVHQ2bWAr{&0h#wd)d8NFv;vTETLS7;M1jMg`S-vWhN>x==PDMpU!Ja*P#{Kg&2RJNx7kUTE iKwvV(6jQu6A^I<{gz%PmJt3+90000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2O&vBK~#8N?VD+A zRYerXr|n~>ElUFwE3$(aR>1|MHL(#T?#z9+i@kldzvOhz-1qYO=FH4l=H90| z>7b8xvh3o=Zr z9gf*y3{WX;N94>fdBE$Co3xtAm|+9embF)^uCY3~5-rJey-Fl%RWfx_B~m9;JatSh ze}9j<{{eY}pJQPRunRI;tC=i&Y__`V_8XOI_!PY`?xZzH!iB-$1r$cK6ZqH1l!_tO z>2^rJMM%NdFSt{wmtT_$ezxT@KtITz5aatcuenc6opuRQjPLQKewC}OKpIY(17zan z3=&evfgV<>$1l!X!f+7wC=d2t&*w70Ovp!C^>cXVQdKsP*)XVErQ6Uj5;dT~APY}I zmq8ZRDAkjTuH|gms?^jAq+{l)Tn2a;vRJEr;s=+jST~7|slWYO!I?=85?Lr`vHy}g+&3QZXM=g8_%okFac?F zRyG5`#j7q_^)qS&j{`lVz7Zu_YBBpX!b@++1vA{Me`wWifb*p_(!XqwXdsECrtiDb zi55D)L;?Hw!qs8HRyd!l0k866i@#L)3^@CSaE3wD^?HPU1Q+%X?7 z6?oI#uSAKKTFgG#!2He*QdE`kg-r%1hYZoGpQ)3Fiv|)X6icJ`{;u<5V*1pha?#9Z z5Z)(f#AJZL_&=ngLNt)rDN3}|i}O2y^!E^}Xgj{yYO(=J`nU-Y{$s%xqDKp3KiQeP zz-*ZT=FOd?iekmO6GtQ|LFE@QbbbxU{mF{pV1#5vAz#lV+W_pJtyMqQ&YJvh1(@8f z+lZ-`CC>`*)#X~ZU<{7g2H+8RiB|oL8+(RU(lC3B{v=u$eQU)4)jYThCX@jJE5JeJ z3=klJTC>+Stw#u#K4+e63aZU-yD@yIRDj9o4?dXmxXzEPvL4(!9DrCume&A*4zOQ8 zIDynD%zpIeeho-wUFS!hepVDST>cCgM!W{F?*FO_N2)G7|BwINE)G7t%l`;Z_ksy5 zR=fr{M_M2AuS0Ic3NZb(T!{|Oe7&cf*%};>c=KbeR?WBu;2F2)lp~WV6Gq^pj-&E> zPp(9V6Z&L9GberF6|Gy~j2+dg8P@>T8z7|OG$cUr_EGt{g%61*lv=+*I%aalYu5nQ zh6b1j>EZMYj2?*us3`cL ztu1i&z9*X3@N_Sj!0_in0|X{O#l7&Kdk2?VtqI4-+gqoQ>G6o`C>C;cH4Na%{K)p7 zM6nZU&oYu&AA%ZM(MRpxc#Y~(_M%*AK3u{qVCcD%5a%8qS_+*T`+SWjJZVps=Ta0y zoE{(pWhCd^5i_LtK8pte2i{Ybj{9%!s zc(!-pufTXBkoCw)co+sv^n^@;@J^`pQJDzgfjH0R_*1y7B)OALI_V@VO8o=7frcX^ ShJ!Q!0000o8+btA$n42Q)>&r%NnsLui&p;;L|C)UIX2LNz)|EIt{OtmK?Q?IF^ z-pxqY^%78?y%%2}Z3w0$J75qy$85utV?E)8{4ro+bH@=`^gjA_t-a|AynOt{b`G_{ z{(HlunPWb^!{UO9#S>F;_bW`yvfTz9IenXKOP#QY;M3Enp1Fg#rKcJ+#U-A5O<49Hz@YeDVKerD`B1y<0JxvQd_c{Q+H_>F%O)cyda<$-PoGQr%+x z;%bLA>5_?M~BDkV;Wku>{iVZKSgjQYg z#99PtnW&@x>8F8IvUS8nS-uc;49V*W@Jv^-9q+|J6GFhlJ^jqEzit5a&k(1A-H-n2 zF-bycA+Ur(l2%p}vj#?gBnc*ik_x`Ge3lezQlbRM{=rYeBg{&6Yr)4cW_JTAPG!#$9peU*6KjnR7}M^EnZ3&;N;Om07b!xFz-2YU5X#Vw((pC3_N; z;Dj)TClgcN3&eMseEpm2W@W^^OwzMcsqNhaMnJ3>d{8UhI6}ehWJm`ppe_L#6w@|+ zAU1thMOMPJvW3Wn`9VO=+eYtUOYd9DTxI$EvL(Ez5`C+%6F!SO|Wwee7^L!)&8klGPzzh{n1Ed}J=yt;Igd{GYWhd| zmcKFgyv!dfQos^nnRQcpl#YPT+|pjz5EAD|&lhH;XETZ$I_#=0V4hcYKdZw{^Fmse zJVovy*dy*`#0QVC$<*Xotpu7YVTYX~O^em0W-y049?Bx8t<(yeY|=c`TZxdB(S2t! z?N8-Pu1Op(=DBL$E$y}`F~yqHk+z}C@%Uk~O*Lq~k z9a4;u6Z>a7y2_W{dB2=Y9u0O8j0YWq8!(Sbs-z)C3r;hBbuZ*L zKfjFjT>90TsKA1!SYc@(`cre*s{oLkVDG`uc8~{Lq;W1;9(giI8NYXe_12KDR%Tzjl!)hZ1P`I?(aQUjFEp{nxV}`=Bs#FUOnZ0hvlHP`gFE zSp3;PNVf1M&&t+X%iauiVF^KrZy?`C*XiZ??B*?0wh+`;pES);FBdfjz0Hwv>nj30 zN$RzOKMj<)60~fPTt4uzauL;r`?#tQlpn2DH;t{fV*wGvtg%b~2C5d!^I#GNI-OPj z0f7j9e{1$lN9FdPKS#cR)x;(~N*C;y(AeTT*~XLgGNH@Tz9GzKIXb0S)^YjrO1|}L z6FjvDXX?0-91}7Iz-C-pjeMr+0~+tM8`#lC%8T_Qv8jN7JI|j20V4 zh(@HuLV+~U?0dM|I4wwn35E8E5k?ni+(6uIO99hVD}0W+*2CG&61j}WA%Y&j_>>s)I` z7q+Wo99^SByo^@6?L205^(lpl&Y2fO3lQ7Sy-;(qylnvu&V=XPCB#l_*5>PWo;N2P z-@{LBOqw%f&uRVF&%YNk-QOy^FCI~AAJ~=%%N0<Z^=?QA9_=?(5i2cMH4>r|z%u(l z@={q&9;dEoiXoy{p})Uje^>h)FI48XEO0s;fAvFkumREAD!$K=M!n2#`VUZhtJpH8 z_)|vx6}dT8+~e@$-eG6o10DMZ-XrdhBtg3FD#h^&0-deQdYfTpjl)lkgeg^h6|uMK zs0wyUKJ_arurDlwW$E;qVX46*@2~&*!9w;=RdK;>X}h26QO$jy;@?Qoo0$}#NF^D} zmhxvU3vN>!P`i;zoFVs*kN`ApB9&hfrAqc1x04d0&kHxmLAOYq67JBhg`r1^W|BH^G#jEReL4VoU+*NTW=eH3wSd`=>>%O6Caqgne zk+&Ua=DYXExPnrgD!6OOLm9UiHZ@Wz{z{=EMMj~)s_iX#LZ1q)Gf(9-Z^6{PlY0i8 zRcU9;IUS`B9a6XGlKqU0lcEPV7Kbwk<&+z?!m{5ckbDbQOltdsH2iiedh8*||4 zj!y3pK}29F3pzt$Omc?7us9^8B(&Yzj@QW-F>mE{^B^E&Ly~arUEvNZNsYstf|p)l z-`? z@RyZW(|B;Ue1WjT&)-~YdBnnZ-z)xM>IqOSQD-o%gg;Zvw}FGbi=OH&eEO)arFRIU z+o=u8IR4_s8sNQ6!xaAXr`}&R0$Ixed-qE$+ypHo8_FaGv;h3kww1BDy_~uQ2`#f) z%1Y~nGjLj%0;DT3Tw;-QyLxx*G?H24Xetm7rdw2mG4Y&4oaJY(agKF))Yyca@HKcU zen@ZAkQz5{i0&WFH5=Ci76_jSQVsGO9q>Y6Gv~!}Z0HD`UniM7`)Mng=be`E21PP} zD9E-P<4sgU4}#;uPo}8_yphm@6Ro3Zsg{Hr>Lwl+vdwA5mYr$1CG&46@yPDQRA-&j ztUjmg2HFnaqsBXcuAd^9(m;C_zNmgM4_`qrJg3~V=w!9NBF$zQouM;1Ad?RRa>Seo z4h0VriJn;&CFf=|U@?kA{UI1sNWZs((S;cqfiBw(RcProVax^(X`oL&;;iDX5BiUy+$63VF``_Zg!^)~* z1GRQDLb};9i};%Kfs1%&5c;8wsoD*_$e=rw3?3q{$$2zf`zcTE!@%2Rj0@swB%e5q z5l}trPo<5n!+lZqO*jgKOl}X)vZQiyBskEEz=I}5f0^f*ciJ0w92jF{ZDsaji>0f6 z=;nEkRO~X%EexEm+<98-@#)1*&Wqy&(aIyN9E>^^WE&`qu5aFz?=v%17waMnSNwvZ z9sOqTH5F;Ix)x^KyeH|lP%P#q%*E5kZ{)V==!ndsQe literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/friend.png b/data/skins/cartoon-desert/friend.png new file mode 100644 index 0000000000000000000000000000000000000000..55dbf1624c0bef440db97a5cef6df462b8f21ecc GIT binary patch literal 7796 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/generic.png b/data/skins/cartoon-desert/generic.png new file mode 100644 index 0000000000000000000000000000000000000000..378f0b0da8786f05909e1bf3f0fac9362e0696c6 GIT binary patch literal 4618 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/glass_iconhighlight_focus.png b/data/skins/cartoon-desert/glass_iconhighlight_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..bbbfa8af7054f704ea91d07df518eb4451410cb8 GIT binary patch literal 37430 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
cWArhu2MhV7^M2DH|&I{QAD)*gQ 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/left_arrow.png b/data/skins/cartoon-desert/left_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..23b92a682e81a4f558526c84318b988e1362a6d0 GIT binary patch literal 5299 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 u=Yl{Uhssswb{J) + Jean-Manuel Clémençon +Source: https://supertuxkart.net + +Files: + glass_iconhighlight_focus.png + bubble.png +Copyright: 2010 Dakal and/or Marianne Gagnon (Auria) +License: CC-BY-SA 3.0 +Comment: From peach skin, first found in commit 5cddb8ffb61001407ce97ee5a8c63faa18a08c2c. It is unclear which author made these particular files. + +Files: + src/Inter-UI-Black.ttf +Copyright: Copyright 2018 The Inter UI project authors +License: OFL 1.1 (SIL Open Font License, Version 1.1) +Comment: Specifically using version 2.5 of the font, later versions have a different look + +Files: + src/NotoSans* +Copyright: Copyright 2015-2016 Google Inc. All Rights Reserved. +License: This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software. +Comment: Bold/Black versions of the language-specific fonts used in the other skins + +Files: * +Copyright: Copyright 2018-2020 LCP and QwertyChouskie +License: CC-BY-SA 4.0 +Comment: Original style, most icons, and some elements by LCP, skin finished by QwertyChouskie diff --git a/data/skins/cartoon-desert/readme.txt b/data/skins/cartoon-desert/readme.txt new file mode 100644 index 00000000000..f39612d027d --- /dev/null +++ b/data/skins/cartoon-desert/readme.txt @@ -0,0 +1,10 @@ +# This color variation was made using the following commands: + +for i in *.png ; do convert "$i" -colorspace gray -fill "#00ff00" -tint 100 "$i" ; done +for i in *focus.png ; do convert "$i" -colorspace gray -fill "#00dd00" -tint 100 "$i" ; done +for i in *focused.png ; do convert "$i" -colorspace gray -fill "#00dd00" -tint 100 "$i" ; done +convert bottom_bar.png -colorspace gray -fill "#006900" -tint 100 bottom_bar.png + +# table_header_down manually re-colored +# gauge_fill and spinner_fill were manually colored to #77ff77 +# achievement and friend were manually re-created from the source SVG with the background color changed. \ No newline at end of file diff --git a/data/skins/cartoon-desert/right_arrow.png b/data/skins/cartoon-desert/right_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..bf72bbd5a30fea9260bc1a3674035055fe1b2121 GIT binary patch literal 4884 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 al#i!vHG{l($B_A%23VTfnv@#3VgC=M(yOKb literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/scrollbar_button.png b/data/skins/cartoon-desert/scrollbar_button.png new file mode 100644 index 0000000000000000000000000000000000000000..06c779410ca581438232be9e434cf9d6b565567d GIT binary patch literal 684 zcmV;d0#p5oP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0zpYcK~zXf?UX-g zQ&AMgzvPiNnEpvxTEUtqEm(`%L5o!^P9j24$S95u4pId-K|54%P*fB}L^3Ev1l=55 zBw8#KJ6N$IMk{I;MJu!gElG^G-*@v~Ohbz$#;qUxl6%g(ob%2(_dcv>MV=gTj!e5~ zEnmfShL{rMtB7`zU&I8fe5N{3NFbk{{gXoEEwMq9SJs-ui9!PLp45`Eb)DE?2ls@G zdDd+nUx11CEJ&g~Woa+@O-x)u4( zk#TFevMnf53wcQzWK7&^L))4vMoZCBtN%z9jDG|szXJPDxlUk)bdpJHQNF{0aABj*wFl$!Lu^|sw{_|d;#n`={i^#*-BDg z1rLZa<5FK3y!lvI6;>1s;*b3=DjSL74G){)!Z!V2-DYV@QPi+i8wm2NZZ%lK)?euD|pCO8E^I zrnLeaM2@p}7A8Ce7z7(hfruZGZux1}QeyOyti`a#{r@1=*gL+iQzN}#zopr E0P0~%I{*Lx literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/select.png b/data/skins/cartoon-desert/select.png new file mode 100644 index 0000000000000000000000000000000000000000..9d730ede0582a19b8c14f8c413aebf64bc6eb6b8 GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^3P9|@!3-pQ0$S$)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheYymzYuK#xfSqy4hwAp|ZQ%R6t@PCG<+YP*cJkA1-$YKTtzQZ8Qcszea z3Q$nd)5S5w!#g=ag+apYpoRqN;slYNra*&B3|mASm<^1W7zF$o9J_njz~*|o`njxg HN@xNA!qO>W literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/spinner.png b/data/skins/cartoon-desert/spinner.png new file mode 100644 index 0000000000000000000000000000000000000000..64124c9b15fb3013d850ae5c2f18eaef5f858eb9 GIT binary patch literal 4383 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/spinner_down.png b/data/skins/cartoon-desert/spinner_down.png new file mode 100644 index 0000000000000000000000000000000000000000..64124c9b15fb3013d850ae5c2f18eaef5f858eb9 GIT binary patch literal 4383 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/spinner_fill.png b/data/skins/cartoon-desert/spinner_fill.png new file mode 100644 index 0000000000000000000000000000000000000000..dc7f4e02e3d166a0fa0f35d89bc02a0faa3004ef GIT binary patch literal 184 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`1M1^9%xzWEPiG4Qo6-36qWN`m}?|1&(@Zr}yvaTa()76auDgD~Uq{1quc zL0wN5$B+p3x7RlEG8k~M7}ot?Dj1~3uyix~j$c~tOiYUz7#jTVm8|FF=t)+{v^mXk U@W4uuV?d1zp00i_>zopr0G(4a^8f$< literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/spinner_focus.png b/data/skins/cartoon-desert/spinner_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..d019c47a96581b9f7dbdfcd7f0b8bf5b84d15486 GIT binary patch literal 4585 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/stkskin.xml b/data/skins/cartoon-desert/stkskin.xml new file mode 100644 index 00000000000..33cf9f83752 --- /dev/null +++ b/data/skins/cartoon-desert/stkskin.xml @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/skins/cartoon-desert/tab.png b/data/skins/cartoon-desert/tab.png new file mode 100644 index 0000000000000000000000000000000000000000..e4304e12d424a5a8b0a5bfc5fb41ffd7765bb750 GIT binary patch literal 5035 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 D2G1>f literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/tab_vert.png b/data/skins/cartoon-desert/tab_vert.png new file mode 100644 index 0000000000000000000000000000000000000000..b36bb60e1fff0459cf972f021f3dfafd52594319 GIT binary patch literal 5448 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/tab_vert_focus.png b/data/skins/cartoon-desert/tab_vert_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..fd49bd68316d8da1d64ffa31312b3c1720a9efd2 GIT binary patch literal 5456 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-desert/up_arrow.png b/data/skins/cartoon-desert/up_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..cd1d6330243670eb5983f743f4540c3661c6c09b GIT binary patch literal 3528 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-forest/background.jpg b/data/skins/cartoon-forest/background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3972567e53ee2af351b5bd0eb9691a0eae1b65fb GIT binary patch literal 324965 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

b9+J@|W5XvLn(GHBPOTsMJ^Ur8 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-forest/bubble.png b/data/skins/cartoon-forest/bubble.png new file mode 100644 index 0000000000000000000000000000000000000000..9a48b1bbaa7194b4011bbe483b51a21aa404aa14 GIT binary patch literal 24975 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 z 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-forest/button.png b/data/skins/cartoon-forest/button.png new file mode 100644 index 0000000000000000000000000000000000000000..5e66865d686e4fdcf227690eae095a74ffef4b71 GIT binary patch literal 3005 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 T{GQNSE&#)En?vPR_Rs$Y@Mljr literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-forest/checkbox_checked_focus.png b/data/skins/cartoon-forest/checkbox_checked_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..9b6d80716664a06e96233181e37e337d72465fb4 GIT binary patch literal 2103 zcmdT_`8yPP7eBJzM99)4p)zHu8Cw`8dt-?^RE#_^vR_+D_Qo2Q>~iS}H?PX&ZIsuW zXe=WU#kca`4ze01&aX zFtg{P(GL;g<=#cLaf@8w^ES3I26&YzyywQx)fL<=>}>!dkpQuY06Sb$EFIu38epCX zfGGfwx%If-&H&)RE&S!H=J1C57JPF_(H%G`}2zOd^Yw<-&B)`mTkdqf};9PJTNnJ1NWek-6&n=`-3-MpVAbjBkP2a&VbBM-W!#<3J7;Ik`mFna9o%5v*ye0Q20#tSPsuwm zod!9BPz(o04qjQk!sIX~Ig>C5)+^SFoW*6%a^OZ_>{jgY$>SzVCg2WE3@18=?z-lB z=*uDK1?Yeo&W!k&xXf3X@XhcE&IE|Uk?|w^ANlik@;-Aum+qE|j*7wufZw5?)Bkes zC1L^r58&L~IU1WrWmAPe3)k+|wz1n(XH`YMh`<0KXONQPl28X@oH67ylES8dH3)tZ zghCkSjN7c(yx4mIMF7o!rlY|ZpaS6ij}A3hFgP%L0Jzm@0H}xDom}V!flmT}<@P1W zo8@nFi)IvJZ+ivg%&y@v!aObmJI|H=wM95k$F}jJA07`@YxJM{$I^&IzGW;m@%H{8ftEMImiz<`G0_ zdXUQlxg!#8X=Z$t@NOx8*HrSFWV;|ApBX+nx74?^K-sIT;f(l*G2ZU%PeNH;Q=-h5 zN>-KH_9qIx4pUO{$f?S{Zg^j}zIUnPZ0oU+sO5$`Uf%xu(1Ut=XLgsh+~B>84RaV+ zPC6wa@%%l)vO`&YeSJ_1`&W461M>5p56#h?wD8~tA3w&0&Fn{>bKcz{QLM}AR53MU zXx29pj;T# zUd~k@g;kQO&;(HdK_O$GLi5*!VsgK(7?dwqwh;M`Qj9D@B<==K=g*rn%grg`#4aZ? zFChsPDrQn~{qgC{W!qMH;?C~$#m*T4lzK76zrIb8mhY&+wsOnj(bT1Fi+(K8aivC& zRQ`7H=c8ruR6p7uEqPT!iX^`jrJf?CLk@9qnTWx+jP3#yRw56T-Q}Y_=ju(VYQG=D zyN1gQzE?4^HV{#okI;I%dXN39ywJPYk3tC^7JQG4@2c(32Dg^bRi>Cjw*|HmsLqLx zqj&eWd-WR>TvbI*Or(U3Xhfots$^UDly@#3{b#PgLd29-p>ck0kZgBvgg2wi@70DU_&+44XVl%bJL&$zsc( zWBRm`zbj=0JrvM0V5lpmCtONS52{OJsbXh^o|fEV*$?#zha*RQhE&UbV-EQh>_1E= zr;r4A2{Vgy+%MZCS*bnFLP67}o^?iFFq)9jQ)YEtE%CYT{{4g|B6bp`%uZc9{O3Sj z?|hrKRm8Vv?`vbySx*F1qq6#g-cbGTs#Kd6l?J*Ey}Bp4mJlG_W2MWZ8BUN}7^x>M zIM-ZX=x&yxZNV!v9|@R%6onn_<8^C1;kTsIc5SvSPk zv8k&i{PaD5>~JRawPNn`lm1UHw=r?fr-SnF2CcY3U@FXbJ9o#lbbMW{oF(SHlp4%b z;bq*Gs?j5Cj&=xg_W)taPKcm3d zrn^;VKhz?obpt!^VW&D4Gy^EFdxNhmE>w(K{FsoC8w&xGXyQO9LzZjFz_t%>tK`{d)|SL2KdbRfD?%{I@>!k&uB3nfom%g_sjUJlsM&G48iLxd0ky4fS*C>gUkvSJ65c4Q-6(1ywW} kgGMW(1MB{a5D?_y>lN|8350;*ADbU6&27!dCdBx^0WXbqjQ{`u literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-forest/checkbox_focus.png b/data/skins/cartoon-forest/checkbox_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..86b9bc8ffea3f6314d797dc0041b7484cd729fde GIT binary patch literal 1813 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-forest/generic.png b/data/skins/cartoon-forest/generic.png new file mode 100644 index 0000000000000000000000000000000000000000..9c0e635b19b5cb94b200716c5fae2d19f3ad4510 GIT binary patch literal 2881 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
Q1jGTXE$q!p_mi&v1KV|a^#A|>

literal 0
HcmV?d00001

diff --git a/data/skins/cartoon-forest/glass_iconhighlight_focus.png b/data/skins/cartoon-forest/glass_iconhighlight_focus.png
new file mode 100644
index 0000000000000000000000000000000000000000..bbb8a9c314f33217bc54224c294aa8229637f49d
GIT binary patch
literal 15502
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
H^^ExsULS95

literal 0
HcmV?d00001

diff --git a/data/skins/cartoon-forest/left_arrow_focus.png b/data/skins/cartoon-forest/left_arrow_focus.png
new file mode 100644
index 0000000000000000000000000000000000000000..455bb99e880197fed9197906760da76bd14a2021
GIT binary patch
literal 3014
zcmb_ec{r478^6cc_kAg4qCrtJ8nR^>LkuHBloZJ>TOYboGlNq@k&imYk*kohr8s0s
zIU|u$+Lg78EQuJh@4h!K=exc?&VS!r@4WZ&``!2Rd+z7G-s?@E9dBpJg6YYrrWho*{C-{&U<89+)4{%N$;V}Uge(}EpoW=tTdjc3;
z15h}1ao6lW`_MkxP}A05E&pZkOWcmlWsX#X<@K@c>4gJ81eI09I#IY=0^
z0bKw%3E;L7{%tMSJWl}fnzMdC1fUCG_BUz6LCXK`u)fv?@?X2Imb%dp0g#OA+D?&%
z>z$D#;vhN^2)Pi)bB(_q9soeDO#mtzG(}GJknvk58|xr
zT;B__*44GzcOd;m8ZtqtM@h9$6+VLQkgiIv%I2?|ArW>A>@XZQgg3B%bidAb9S8^I
zuga7$iuN~cXax0sb>tvqyJe~4RBNs^wjT?RfH*>Q9Cx%BwGinPG5KKvcY(K!7xx_p
z??J6k&2rQdUVtsv7V3TpllmeBl_1bA0Qq1rYyfF%6MhMx36Kt3zHWgE;A`UpWK%65
z{#hK@AlfAgXF<3_7#cu+wAZO2|2j51amwU*diDNP7TQ`mQN@!F=N?dqz!a}IAOYodxZy|buoHm_sZrw(>C
z=p4WOduT;(E2BBxzuWXk1vZgu<@?;=
zn;LgH6(?V`Wcb+AW+D)2C@(u}%YK}f@eU*qh$P!v2@Hs!1e6FqC553#<}BHg=p5BK
zaDAC{&_(h2!wVsGo+Fuu1-hI)#pO=t9tW9=m0CLF!D_h`Oj
zfx3h_R{cl${fO|%_>M^t
z5)-9aobOZ7NbuYKI>w4CeG85)JU6m?F83iPjJ}r)&UBgkY~M4?z80DCgD+4wryRoV
zYg73-PirorZuZ*M)XUg2}0dZ6Gy_yBP<(6Gnf2IV@h#%2cpk#c-3sj1);QwypLEm6rUVOl8bh5GmAB2z;9WU2pI{h)S8jw;Hd5
zJtYv@(ddK*J+yW_=~}^-Bj2xW{OeAPt$kjFZqMhzfzn;xpo?Ap;s`36@Yj
zC(mEE~O}EvWeVZfknGcj^UCxSi8dtNa
z@5uJyzd1)5Og!-}ewB{3I5n+s7R8ieHvVDEv!oESyvv}%OVLT+lBC$s`zjIZaDMwS
z^g#PALM%T1zP5XnvgD1R1kAB?B~0WByIx=FTs`N)1>Ey(Gz(K9y-yL@JiIZH;*XU3
z!W)N^$Z4$$9n>_{56a#;Ps?#PoddQWHKJpk^UNAP(5K@+L%o$`ThR*#lFK6{Ws2dm
zhx$(yay}2Z5VBFcF>!f@@!hhkTmy0{H?m{oV9&#*9M4yclB@LC7ON7&{<*BUqR1b%
z_Zl%zn9O=>0$OZ;?GXC*a_x1pT`u@8g_
zNr}#6e3E0c4;GGo)g?j<~Ud
zNh%HPF^0C$0aka$jlX?o&x2txC%#_q$&>5GduZ@TKC19;&J=SIvWwt&
zT^Sv54RgKGcYQ$>Qy2d;SWOC|uQZ&tS?o+dM~)Z^XHBk{CwQ~ZO#5Bq&9!~98F^K>
zgttcJrwoNCZf*j>Gp>|YE8Jrq!42T^0^uLnpn8IZOPQ>UU=|6=4N8oTT@uxtmF@ekzA93u3e6?PcU!
zalaKs&U>jnp*0p_zGTcBTNXu@UsQxJnd;YeTx25YLOe|Mqj&X3nPiM0h9c8?cEmSG
zmZvAB<^heN#c>jZ$6=d(Xpg^AxFh}EdUqkoh|*oG>Y^$ndCo8OF}g^a47wkQ4km|)
zf9huSlM2R3W}JIsIom1Ng^ybM>`Om|_NC%++2h{&#I)+y&H0%(f;_1HYRjJ;zF%q5
z3fWDoc~eq%!Mc{@=c{n|ukuEZoTsU8uh^GrPianl*CWnpXwHtLJDk5Iku4(|vyd5E
zV3cSYJ+{0o;3uE$Na*$Y_0flov~rE~IT7h=
+ Jean-Manuel Clémençon 
+Source: https://supertuxkart.net
+
+Files:
+ glass_iconhighlight_focus.png
+ bubble.png
+Copyright: 2010 Dakal and/or Marianne Gagnon (Auria)
+License: CC-BY-SA 3.0
+Comment: From peach skin, first found in commit 5cddb8ffb61001407ce97ee5a8c63faa18a08c2c.  It is unclear which author made these particular files.
+
+Files:
+ src/Inter-UI-Black.ttf
+Copyright: Copyright 2018 The Inter UI project authors
+License: OFL 1.1 (SIL Open Font License, Version 1.1)
+Comment: Specifically using version 2.5 of the font, later versions have a different look
+
+Files:
+ src/NotoSans*
+Copyright: Copyright 2015-2016 Google Inc. All Rights Reserved.
+License: This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software.
+Comment: Bold/Black versions of the language-specific fonts used in the other skins
+
+Files: *
+Copyright: Copyright 2018-2020 LCP and QwertyChouskie
+License: CC-BY-SA 4.0
+Comment: Original style, most icons, and some elements by LCP, skin finished by QwertyChouskie
diff --git a/data/skins/cartoon-forest/readme.txt b/data/skins/cartoon-forest/readme.txt
new file mode 100644
index 00000000000..f39612d027d
--- /dev/null
+++ b/data/skins/cartoon-forest/readme.txt
@@ -0,0 +1,10 @@
+# This color variation was made using the following commands:
+
+for i in *.png ; do convert "$i" -colorspace gray -fill "#00ff00" -tint 100 "$i" ; done
+for i in *focus.png ; do convert "$i" -colorspace gray -fill "#00dd00" -tint 100 "$i" ; done
+for i in *focused.png ; do convert "$i" -colorspace gray -fill "#00dd00" -tint 100 "$i" ; done
+convert bottom_bar.png -colorspace gray -fill "#006900" -tint 100 bottom_bar.png
+
+# table_header_down manually re-colored
+# gauge_fill and spinner_fill were manually colored to #77ff77
+# achievement and friend were manually re-created from the source SVG with the background color changed.
\ No newline at end of file
diff --git a/data/skins/cartoon-forest/right_arrow.png b/data/skins/cartoon-forest/right_arrow.png
new file mode 100644
index 0000000000000000000000000000000000000000..4c4baa834ec5f556ee5b1be943d77d197f975592
GIT binary patch
literal 2946
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

literal 0
HcmV?d00001

diff --git a/data/skins/cartoon-forest/right_arrow_focus.png b/data/skins/cartoon-forest/right_arrow_focus.png
new file mode 100644
index 0000000000000000000000000000000000000000..bfbf9646c40d8db08dbdbaa958911a1e7072efe1
GIT binary patch
literal 2982
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
V-wiH-?LU9C!IElYUSj4I_b*w5ZI=K5

literal 0
HcmV?d00001

diff --git a/data/skins/cartoon-forest/scrollbar_button.png b/data/skins/cartoon-forest/scrollbar_button.png
new file mode 100644
index 0000000000000000000000000000000000000000..f3891e60426ea60ca5101a497684e530c2a79c7c
GIT binary patch
literal 802
zcmc&x`%9An6g^|c)U`4)OAGDggXZGfH;nDe3~N)TxpXe`fjD(Df<%)QX)jrd+QSm*
ztwyQAOqZ$jaG<8P+05)gP0c5jils>959(}v(og*bUAXsf5BL0V&Ml0P1#=wT9072o
zA!0d=>z3M{Nl%Ne+f0Mqp}_D!;L&BaHE9{WZ%hf1hXdJOKu#_&Pg6M)z%c@tR07lu
zU~NWeQ=~t@SP`*LAwe~L@;}M}U;z!l1t1X^1}cF4z$%~*7y<49RX{WF5oiQTfOMc2
z=mbna0!;iqj}2)@yl0JEp6P1W
ztG7-kXa`^dS8I+_}iiUSosJ>9P@^0o-)piw5n
zx4^Sk8)~XjKDUcZipLt?-pC=F)L+Tw4;i+%oK5YCo=kMMcMBp$1i5eW&YTps8NG_@
zEGFaK7;T}n$0@INsw|Ic
z{nF^w)DX&aX+Cw-p)%HEdF@X&ac%cNXsg<=r9JMTr7oG1f8gn}MNRSa;I0~u|4nUv
z@SJ|ZPFLyvZpOM9kZeq`*ym-Q+Ne*iP}?63d;

literal 0
HcmV?d00001

diff --git a/data/skins/cartoon-forest/scrollbar_thumb.png b/data/skins/cartoon-forest/scrollbar_thumb.png
new file mode 100644
index 0000000000000000000000000000000000000000..6230264ad9030407c4f891199734fb9f2cecf969
GIT binary patch
literal 339
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvmUKs7M+SzC{oH>NSwWJ?9znhg
z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fgAsXNl;>xfJ$U*|g8UFwO
zpFe3)3Q&xtB*-tA!RP4{zgpvOKt5xVx4R2lV%m;cAcwug)7O>#DK{g#q{{PJ-IYKg
zZBG}+5RLQ62@ALciW-?+H#BfM9gx&{(8N-}+2V9?1w)}?o8SqFiw=ei47I)?rd^Rg
z)&RAsmbgZgq$HN4S|t~y0x1R~10zFSLqlBy!w>^gD)78&qol`;+0MdzA;{X5v

literal 0
HcmV?d00001

diff --git a/data/skins/cartoon-forest/select.png b/data/skins/cartoon-forest/select.png
new file mode 100644
index 0000000000000000000000000000000000000000..c018de590cd05e475f08c8dc19eb9518d5de641e
GIT binary patch
literal 302
zcmeAS@N?(olHy`uVBq!ia0vp^3P9|@#0(_a9?Z1`QY`6?zK#qG8~eHcB(ehe3dtTp
zz6=aiY77hwEes65fIfBfoh3sL`h0wNvc(HQ7VvPFfuSQ)HO8J
zH82b@FtswWurjvLHZZUfv$mtu8~=Yk+GGLk(Hq(M8m2>
S`>cQ(7(8A5T-G@yGywn)o=v*|

literal 0
HcmV?d00001

diff --git a/data/skins/cartoon-forest/spinner.png b/data/skins/cartoon-forest/spinner.png
new file mode 100644
index 0000000000000000000000000000000000000000..622249b0273374a69d9d44a5f9578815ad08c7f6
GIT binary patch
literal 2822
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

;pUbE@?^fRv&-ryIw?KF5(?YJKkbeA9 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 V?*i|r;eUTouqU|K+_UmO_YV;TAtC?( literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-forest/stkskin.xml b/data/skins/cartoon-forest/stkskin.xml new file mode 100644 index 00000000000..401bf313706 --- /dev/null +++ b/data/skins/cartoon-forest/stkskin.xml @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/skins/cartoon-forest/tab.png b/data/skins/cartoon-forest/tab.png new file mode 100644 index 0000000000000000000000000000000000000000..afafda47361def902cf68143d069f32c25d162b5 GIT binary patch literal 3400 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-forest/tab_focus.png b/data/skins/cartoon-forest/tab_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..728e750a6fe02ca61188fd6ded6a9757b2cc0e35 GIT binary patch literal 3337 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-forest/tab_vert_focus.png b/data/skins/cartoon-forest/tab_vert_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..2c2ba56158eb9bc8b4aca228822e2425590527d6 GIT binary patch literal 3080 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 a9sB~D1?)uWhHkz90000{2d8 zC2j58ySp@UOFQgr?A=xBY%`iTU+b)M*7@c92j{ca`+nBD*5~=W@B2K@df#JiuGzWxs& zmI}P#0E}~hdSqceYcn7n?Y7gy9_2*I|Koo%5DWMK+Q6^CPrw6U1P}n{0fOK#zyNp! ztOh!PBA@^`2rz*mfDSwdN-<9|4{!s9fvtc%FaX>JP68nSp{yD(2-E{hffk@2cnH)2 zd4!fgHLwpLG<^(I0xN+hz>xj8qlVB(4hh;esiL(5FKc2f3nN3zMx*M)uA z+rG{2PS=n6VL?7r(KkHo|R`heC_W@!nslCqI?Vc(2brEbqF2>Qt zUT%ycC8xQ1BFXqFKnirUv-OA{d|x0=?6K2%u->hpuuj@wwZZr*_F(Z~2jHa?8)SS9nyb-KT8a>^6xxeRKXtD}H)M+<_0HpWDAa zkBAG}!p*rL?&Pm+JxcyheCzUbJLM&r-0EncbCH?MsyX8x#cB}g=kEyh^T}B&qqn*{ zQ!=^zWLoOesVQ>}YlppBn;1$9ob+>@N++^^Jg<PIO%ybAa6XaS8z^#^NG^v)^V?r1=jgg?Ndc%tu_3Xv97!4 zZSMN0-jwnjvS+pzsh6jc?(~Eo?@g)KZZuk$%S_f``4?*!uii&1ZdfQsX&v3wa6}_< zFiNUmx+O*8F7gajalIiU$)~?pwHU|<;3}MG)JXS=k{PT$9q8iWfJAQh!?c;N! zFg-cll2_dv@l$0x=4H)+Lp@tm=aqvkqqO`P}TmcImeUjgsE+73J#`{05Z? z)SBv{iR>b>VAygac5BuqtevU)r0(6nx6mPx6nB=z=aDP*3`5SuD7zf)YAqWynzQlS zZv45kjwI9-iwgc?AKD*TFf$XMRj(*f8%+CLKD^kwKVfV*d&NvNyKhlpAZ=DKoE~sB z@tqX+u$tX-eoDP-@|NBpO<$gP$!1OOZ0CU>0%qXHKNy()4}TFw__a=USeldP&mT3a zJ`|r7Miv}fUU%5VD!062YPnY1HcqXqQ164-A$)dO=^e#N?PqKyL6X17Av`EGmS;8V z^n1hS2ICbkK1`a*!Ig- zs|mG2uf#FR6(>vS{o{K=x&ujZyR|8m*%oqr#vwPW=*47CHz<|9g`!QD*(cs7HGgL3 zo+j1i^@t7o-0&YRz93AZ^rtJ` zwSr?;FG|WSf3i-T_u_ULsX~vPJe;n&_}_8k4O3-(P;FDoFDb+etRG|V9kXvw%=e7I z1K$$~G%C%+*u=z`YT`kqGiVl!O%{e!DuYUWS7k{2CjSKp=k5y)N|*;wjj0yKG&2v{ bCI*ehFtPj>puDAlK>*-r?`n5#D<|!rDJfCd literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/achievement.png b/data/skins/cartoon-ocean/achievement.png new file mode 100644 index 0000000000000000000000000000000000000000..9a76be1dfc9529dd9ea083ffb0f628693aa31afb GIT binary patch literal 9456 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 AApigX literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/background.jpg b/data/skins/cartoon-ocean/background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b3cf5bf55cbf6aea60f621270230282dc9facd52 GIT binary patch literal 266252 zcmbTdc{p3$7Y1sosfJQfAymZ}w5A}Y){ux0-RHUYpZmwXcjwtVCpqWj>~+r0UhiJ-yZ(Lg?;C*wt_T-| zfS{nDz#0Ba;NQ0b5%7z|FaZG%4*`gPfPlDwh@i5-KK_;bW_+KmZ zUl9@huiYmiA}k`hPgL}ORZK!$R7^rlR8)MwxP;_?g})`WUsCG75C8qh|9Ps=K4IZ~ zl47D_|2yRWQ}b`PfSkC9rPwuL!6O1fa)QEgg8%jj9On0a-~YPzpAr8nf9`@+KfPVeLQn1A$T{(b=wxqb3SjO|4aq5{PQ!7TSr$9Vg@z0u!LDTI>8anNEcTO7Kiuo^&)p2Yd-pp!yPo#;^$!dV4UbIE@Mh

2B}?4K(2G5qE9Pxl*Dbqs)ciaJCqYr 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%0DHZCA%3oDQpkzZMXr|zTW@s&BG z$y(WxFsl_wT2n35m8P6LhztvSrO1~fw)twA(nr%E}ZD8^SIHVrt)6xl3V zF_LRDqCJQ=tVay=t8pLq>0K4b*)rUr{wjBztTUQ-Cz3))cZ>>1#>3Wu+e;4f4|T2Y z1#4eoyHH086(;=V3Easd&CswN=``qk07ZUw30b#d_j9|apyHlVdER*lLFzZs8&-ZezKD0hF?ylH=*2k z6UC8TI;+e2*RS|0_6wk+%oX|$TZ@f&EltH)q7+DaxHoBhB@%2Ss6Zx)}S_JIe%$9jq(DuYrnA$2+GfYI1t}-rBJc z$koi1Fx2Vka-(>r;$9rL=TJ|mOD`d_UpFaK_L`orBvfod z(iRvsR_0BgH?3>BFo(M$jJL%fC}~$%l#Qk8@H43yG>vOvy}WN>jd3imoz&z>T;jCF zVP#nB!eM0?*$;acbGVAPrDz^}*eg|m!O2R@x{#GQb9OsT8^9Ktgg#WZ;e!wE)_;mW zXUhwynoE0L-j(z(DUEtNYC1eYQwLEi=y{)sz6o9FEX{0;J&3MHP|$TvIf~5_e6{iz z%pFWEPb2g!uQbEssHfDTbqOtH#DvzKo8o(LFw+eG0KHRAyt!=7xl@XfsTYc&BV==O zf7-7>_lqGf!l# zh36IZSd0v*(dLQy-dmqjmMhuK=+0gIb8)3eVZ2sWUOsB4eeojRbpHTbUq39v+5584 z`{-d+X!FBV%%<^!%Pvw%(bK$A#Qe?r)2Enuhtz%TQKX(GMjdL^zlmVoi5|83#w0)AhxWV|9ACRT&;lTt!G| zZ)tk5iPePPt#lS%D3aL*E*tZ&cMl~S9(`GJM^j@?@pho!>Vvg(x)+FbTb5OpHrroM zfy75kpA(zYjhUmX+0T6k2y)9_cjFHOTwey=3w~93g-FU8A0rsrM;6}<@1U5xVY=1p z9}eDHGKphjUnciD6m7B9cy~lwmQ^tRmD_2551_q>1&g1hD_qhml(PQ-2K?s3TXp{c zW|ck%!lNx`pTecnI;mFW*ayKoefTzi`0YARgb`YfEwTRq0i_yeTyawFW@>*9QUp7p z{{Y7;lh?c<9BRNv`c=w4>9ldOIDKQoN{+*4f9}*)J{S-3gsdY+nnyM(8Ot5bYflIi z`MkQl7lz2_pRIOB4tW0n+FoSP=tW!;6?EPjf?FvS!t|rq8b>hmJtIZ&QHIrHb6LJA z)qdRzbDEERR-^*1?tqeKawzrKwV-KxznX>p-5^hwhR$d-tq_zg(ASE4ab(u(<~}o8_Au>SnsMBBHErZr z(>Sa8Rr-lX&s|t~a@Ix|rOid1UXwaVpc>RLd5MuxVLN~&1mzb`*@6hy%@RY)RgnUNChpveH$+2c_LO;kvi#8q|! znupB<)bke)gnVQZRwGbXnxRzaSGkLxl*obIk}6~I5~c2%kvUlNidiKED`TJS88?G* zVO16*zcq}$BeEX}Xc9V8)?8H+K7tt-oYT?1ZVd)xfddXrK_nn@1pqh6AKajz91%fW z!=r$>+N)P0f+QGfsESf0jUgSW`;kWisK{$f8?`x95tBhJ5+oz8Da`<0sakt7d9@nR zs2Kv90XzX&mG($4H!VeO3-W1wqebwVHld2}X=aG$Ij*>TCmg;aGJ_ln8L%)-S3j6? zvNJL;`Khed=c?3m#L+1ViyIt@vjh1@IHH}1o#af{i?lv(pw$~v7e zm%DPrFc5NTcrIElDaS%8d&QWqlQ=DklkMdOH&(Hc&nS`0eV%tzChVT|K^WX)+=uG) z&$N);Dr9NONgFc`l`2fhR7{ZexMII@s@_S?+L;A4sZL@ta4Nix2Q|+lx|t@Mmylq0 zuFph_`C#I(h;ptoDosarmTyNwOj5~Whk>Y`$EVhC1uH@$s2vz##GMgHMy0B{fvQvDXnP3 zy-z8&qJ5toT9Cj;Mx&Gzg!?w`f|(>7bfc8DBAlT1rlDeb)+VIGJ?I3Em0Z9%WM!v$ z+*K0L!p-YIEKdff?G#(J1y5SF87G|9kuY)|6D@$%xu98`gSNXcwE3zdlNCN%XJw>9 zsEQeDWg0YIE9@|_<)(a|B2tuyZ*JG5X0tD@Sra9z3|(tPygW9!&T98e;jq<&>?D^p z^3|o!Q2H!1d15+H0&psn=WsZzrMcBlas`X#$*VT;4C56sk3(5|sIek>X}r~WCvc0`m?zS)wZ@bQ?2#4f?qWnlyMxgxnEb2 z+IUam4$!eY!#`T@G;bCCsd6Q+p~2%-N_I7)PEn|te&R&Dj}Fzxc*DV~dKyTFU*WGe zG{MIeO{RW_lVhC=GmX3OEO4E&TjryS;klIViZHeEbuu{e*+lxtXB}Gy@MBwijT=zD z5y}4mSi-#8*(zEc_c_Bfj@OSRM!3yzx&BESCvyKsTZR?%6ZImM5jg8?fBeS zd($Pi)g$UTsg4g3PFFfVwJ`N*>T393Ue>hBrNj~yuUzm)#Vea58J}|F*1nr7$4?H_ zWO!J*bg^-Kto5%A{AabE1xYSDcQvD^{6nysEz3Ip0N+*ibaOg#hOGE}W=~R8bVoIP z;;lCBMlCAlu{C@9Sq9XZe>%>kcvRV${{UsmG399H^+;iz8|Thz8cz+i%k2xC{{XXD z#)NBV(dFW>-&easX836&qs;P({uPy}cq0D9Hqr9e&gR)N_~4ET7|(l_M?0uNb7tjT zHr8d`;XGH!^2(f?Bzm#;tkFGU_iLZ==fjIjsN_*@4Su6u zge8YR1j1vd9A)p+@Q;X}1}$Z0CfIlFUNhpqh1YsqjMm}0*X8-<1C~xuKYrmH;Z&xn z&D`bY)2}SwYpX3jDQ;urGgrsPy-3Q(>0ec+QYuj{L#W8S84XG`Nf+i>zwzqYIGJ}N z>ap0h2Z?2kcDc<(Ka1`ewxn!p(8J^9vF76Nyr`1f#F~k2EoA(wr10hTv#2_(VSulD z1&ggID<3b5g&5xFeW2(XtjMn0iLT4To)Xk&kwmCXeO?l^Mzua$8D5-Y?w*<9ABS%0 zq2T>1&@?}WsFAA(E8W9aluwJs)aH{ko4{K~%$1#}{6C6Jsf<@;O0ID}dS2|VV_p0< zw_dPgKGlXXS$eOALc~v(Qc`CN;=L@ytfm_C9~DRBZvE9vjbhFo z{b0I~uF5QQ_enBRs+4`>gBd9(o7S3o>=|0Tnoi-7iuEbePAAG%uPDfP(l(96RhxTZ z4QS|)v65X&OLMefH|tH3Z!}?#{ykCbOZxPRvskRBII7K}BYzDqV#W2z4Sg66F-$r+ z#zIo|0{YahM<$c~?Z-G%q5oVd!)G9PUs2HH(q`!Yy3V!awv`W{VeUYEHOS^U@wR&DIz z1C<|*b;g%-&8>=ZWrVhgd#zZH$%uX2)|{s-s!Bn7Jbq6LTrZ37nlxrw;m3Ql&g{8! zR98H+#5%l>a=@|cSkm1Y8|G^GEKNr$j_2rDdU1_3G|!Io<+;at<~s|P6RA0^yBAWK z2C5}Qo_nDZ{LN5W>tZ{F3f0j^_=v`~uxDrCtzBg*3s-4jG;+c|YWr*qm$OIb`ILWq za$^E8>rl%YuL8XT$z8~#+O-u=F{Dp|>S%x*SLP?~RXPrtKpYCECo^XhRQN(Y3GAc= zgpmXtwA!LD&w&e37BUz#bwTMOw6C{TUP?3 zYofxdm{ze}!DF0KY;Q`FNVKD_mjA1J2-k(#1pG|0fv8-drjkFCA#0@LAo2?iO(2a&K~u_CF;@8rHC_y%#bW*=q8|x*+EI*?Qb_yy8rCwj zPI)hQjpJtiDq%!H%jUDYA1W!`T&j)ZvC&Q%YF@H-Wym#kTPvK^DOk#J z_l8L(1{Bm1uQ(=-V1z~pK{W3x{hB$8@JPO986QZ6X#qA@*rYSPQx}7gg+6NW39-k@2jIGXT3vH`R zYi~;G5_?vf@`u_OcaPzwNiYKhR$#Ru^A(%#Rf}@0FlyGr zm%=_sBamQxH$JAC*jgI>tDM}OBN(Pj8BT_)l#7tjxcbw&EP8|7RPn|Tbf!#;QGA02 zq)AW=R)!`0D%9M{4R#tHo3Jk7UbbIP-nryv6*+y=qJrHck2PBA`^ezEeH5ka>7EoL z?IdQ;tN!x<)Hk>Oc*2_TF?fz^qtK^MmdwS~Bt(xntY0}p5G%&0+3aECcn)dzj4`N5 z$<0e<@m!z>psB6bYi6!HvB;UjNV_UAXDc1pr8RRn$wX_|I9%vP)hgg&TdQ+cMe08n; zriT;5`@}D(=Z*BA+J%3OzbZYXi~77tt+l&|CEk*9E2;3u#M_$*78{PA-pzGkF_NQE zT*_E`YL7$E{B*a`DM^0t^{vSDA#yiJYwD;3 zT|Ofo2&~T%==RM662HS<{d^y^rhaEuw=HcCEb*<3DY-(|1$S)CF;!ap*E+!R;uDHK zrzw=H#Uk#Xq?Z7)*2T7n3jNCVa=bS!G|$np{4`@t6DE=)Jc^k#{yyz{e6j3$QA*>Q zz;p{lHt8E~HO*cz_H5+F#d{WZ9tzg3tesFucGs|YPgYCl7B|IdmDTsTS^WP1#Z+VU zrzn?o{T?YIEgDytc;~~#!wsLM8Lbt{&PfUU*_qe|H^zUyh2WQs?wOLt0qMDk!Yp z5x$YWP~U*7`d`DnV(Ev-)yqOvE9nG#)v(dSE@`u@(EbM9-R*h9HtyBe=|2E1kyN#q z{8qlFEy~=Qaz8%e4C*xE;|6NS@FLr2*=PR%j@H(P@NO#>S6g0x-LJ30PhN%9v|=$qNA)x|wb$E0VFCc5 zdRJ^?%6Ro>%tw1Ql8&HOCZlr+ISjSDWO?$Z?-XU8-b||jSz48)oWP7wUIDoh#uxZwz>g%iF$B*1L@_#HdwsFY8ocBVIjr7hIVIGV@Y~ zc=5PaW|26b6(YzOWOc7E@pZMS3?8OMMV@o3S;8l0kJg)SH`#e%N}Rb}&U{3DriPV< zq$b5~SeIzvxACx}qR`)$$p|K38+?GI?`F6=Nxk zgHlH@A1F1B2Dk3freQ`-p*&=PkZS#`?YCAS9jH#_cr}M{e9=#k-Rq(;FV-sQSTC!btdw?I83N z^FZSwHE>5Jq)8R}8eT;{c`h!x5Bj&M96jjwzEN1*s!Apjm=B6{K#=B_>hSEQSkWui;+Vf+$hCLwrWoxepRn2&ne2} z_SOm?ek)SiBvF7V#d4Tba%7Dfu<22>Y`sNN)XFa7N|V)SSjS|g%M!2V0YV%amtwf8 zeniSv)KhM8#X~ijBRgsuxT7MY*%8{G1WtyOO?kc2#YZ~s;}vX+m8P}@a7AZc*<=t` z=}E-sqf_27?ycQR0xLFeF%MH*)7h4rE<-ZMJi z4O&KlcXqDA#UVuCiu!B}V;X4rylkZ^jEhj!R@iOdT;{FfA4w{)SdLhR7KbsD{kP{o z$t_q-Q0@EQop>^8B23%*9sac0_uPfQX+e{*}+_T1!T8 zQ&O3DTt_jNC9zYCQ(7_?0=Z91n1!twx{9}_LeMxkthsE-sVB>3bUJOu00h@TrZS#} zy$UCfi8PXRPK{M>CQh}{CU8@Zw=?FrQ^x9Qd2DjkmW=D=lu#oN3=>IEx=llEnP-&O(HH&5Ri?ysg~FQmNl$nZ4r#5Iidra zjPu&FsnCKtl~|6Im>WJG@omPFGNV4_uIotg^ixEjJ$(iT9qi-E%B4q|MdRaFUzud$ zu2^`|+Tn)j_P3>PQ!-0-d-!Y@w6&49ZK}1>jg3>6kw#=0uP(M_%`Fe7!sS1^yG6|+ z>?81^x?2rkM4&p?ql3mNMB&6`t}@VOvEn-cA3bXpFBa+PHW|R?x2am3k3Oavq)v-S z@fMphjk7Iu8g0&>azd-EMHt4Ujy_tH<$D`ex)z;wpXyb&R(FWJ5ny6wjureXvRGKi z>!*&D9;XSZ_&OJ#V#oYgt&b0UG_{pO7=KFe@z@G#TOHBP>T;x+sd@00c3j%VSN+;; zhlKTg3AakE^4E4#Ml|GkIi_vxsaV>y@hjRU*ZvyM)_h+D(llYK>*G`0vpz;Uux6id9qZ*YIuWT-==;2nFO@x7H#D6)axPZ3t@O~T$g0Cq_H@s_ z!^f5awwxD|w8pl;`?b{;R7S~c`$+<`FM&X7pBEq9GYnLDskA@Co+wKz#k9F@{55+w zfOV^BQZ|lJUUpSlF0)T`eig--SyRMG+eUg6cW~TV?JOIL$ElQo4&x6Ctl}n?|b?M@oMg%QlCA?D0*S&lmVIOHy$o<=bYg(GQ z)%ah+R`(@KMmeuY@ZZC2K4n)}SN{30b0y2-;>dY_+8>DLS*NzXrSst16il+MRGUuItcNPK>?(1m9Z!jMrz(UktLgS*_j_tM z{9|gZk216N(T<4djAbb5Xjyzij@5w^{rdJuJ($DeyK=luRPOw5ka0CHXg_3(o1Yg%@AFE(om7{^7P7a=B_7b3Q)Rm^ z7DZ|SGS;o9#8rS~T>iCQ(H!nA8n!9`O1{#PF4-#mnwVJ5SX;=py(=jiW*J^ zO-AkC6(vNib9RwuBD1bF*yG?D9Jx`nX}K9Xmx$Ny`IU#LYij#}difmcUh8MrWOVdJ zShX&4tyUtw3~;Sp9tyW9?qewPM&^Z`&IVZ3_^+Z~hQ5;xi1$yI#o=3!=G7dXXFQw# z`@XyAFj^({=*QkF#HK~XrXf}YC1&hZTU%&N0y#W8%`IS*GXyp zbeOI3UDdeF>A4F(@29XV`=J@dD#{aW%656}RD@P{=G`&Z zvihSt*bc7gPi02X5t15+3eiVT`=UHM)bgpEIFWdkV@}Gvbzoc3mqwosy4@$xQCP+W zv->x$Vmo_EO3X!FHU5If)Agkq-D5Zf6oZu}`J(}fC-9#9T zUa@njHoG#m_hprQA5`xuE|burQ6ZL!=Pndd`uaDIMwcV44r1b{hkcCu!1Yzf{moqU zy3~0jP4=&huymqu5HIKVRJWo3yFsBTDo`$Ty!F8PkVwO3SGvYBDwt%M80!AD(wZ`b zwNR~OKf{{kKRec%?UmcL8hl4g5;5w~AP28%6HjQvUZ0D^`;Cetq{FDofASs~&kIzS zFyEGsX2L|_`WjIGihPZbmR*?8YpL_#6z$57EIPJ?@;4bqZDL^VlEyrG}e zb<>2nT-m{mLYKR5g>k)8^v6&glHd+shm_V2d7PrIUsMqGy>^v&LSf)9VOigTX0Z47 zxY>dXLbCT&B4y-+Ov|nO=d_+}G{Px8nERQ%D6m|Go10@(Lg!S0M#$%Yx?2ske*M0A zrc%k06Z*%+H;eCEviX{>9!~Ox3_-Dulepm`(*yk%a0cwB*R5HkJ&WT%)50M6B45~o zp|~7CXo}_T-BVnKA28$Z%HbR{eyJKFcsm0N%<7Pz^7>L~y`Yq;H+EeL#JB8YYG)p+ z!@Vt$>S#iou@_xyQLn{fGu+Dnt?I&}hPtI|g zP-2W2MC(h~yp?v`?WIs6U(-sid}Tr+AD7=`^fSdYVeP#e1|kk@y=y)f2@CJ%=cpiW znLgBvRbKPPF_H$Q`wb-`kiTS9l_Ec21M&qk`=%}va<>RSr`<=({}D%Do>mS`2#!0w zOKH{}whwO}R36*${oY=o2HzjG{v(IiS?0Q*P*7qm>LZ*tv6&*6@*+uYP!8Z?_dpVp z-P)T?;5-T9uG1fc@H zP(`#lz4;N3cAm2Dd~}hw*AJm*E7sOhk2iiLYf`DIDWojGJKh8m`v{hv58>YEq?|r@ zv^J}HrZo7zlF7YBR*WV!Ytt>~)Y;XhnqRuq0GtrcAb64l{ul39|48fijQWicWO4iU zHhoX8&M{l)1aBac&YuC^NnIt@R9j|KLQ(qBXc#azrQDYN4-?uek zJ|hPYQ;t3f+>(UB9D3>?R&>FOq{`M0t~p;~_^RoRiPpg9Ab(!pmF*L)kz7lmVUWT@ zx^gobbK%PUbBT<$wsjxzRbp244wa0F2DEHHiWQhJ5@49ipU>*9ERuJsGU)Pr;jM75 z_miKfNzBtq{CmiEqv>eHl#xxxo0V%dShrE8Zxqp98j4TkQ4w9GI9OKZZSAx0qHq>G-m4|IYOSJP`df=92+l1240fBlu9 zQUjLPyySc$W9(sUW`?h?c_a0|8zV7hq_ZGPzMdH%=7!iU04%j6^ z(*917abM=kV>?SOC(TQ3{ue;9e)sbSd+$iGZfzINDo}4oX}T3}`9BbSaCGEq`|CI> z@vMKptLIzdpIE-Oku+Sh(U0j5X)lzG`+7W#NGAgs(*_T`jwP0B*S^8f`Ta|^&6&bA zNW}sTbFvt83!`S<*$}N!Vl>&bTgj}Xdu9A}5NxKDpqtU8^rOGcDzjix>4{hnS)_}F z15>ThaI?15b9Sk$er!8f@3`|>>IeqRHas=W5icyzaA!_sb~X)DFk`-NF<+i6K!(%wcLbH#IkD&nNMM~$O0I@e z%*y<%DUZs=FvE8y0V4RxE-SFPo0+Wd%IA2IBp%wOW=*U!*Q1VEA}_glIA0g*Ub`~3 za^d>D*RHj4C)`r^zOY<=k_eo*X2HCVWmH%MyDbhTGc4A6{mfnq2Lk3`u2p>jxFy zMOCm#xm>G0wYIPI?ES}!hGaCqUftE5EAZf?JCC`I4MeF*i64*^^@zHAn`WNvnB&7! zQf!s)DJMrCo=V(w9DHaKUlXgbWL>`^!DyM%u2uIP82YTSd7M7}#L37&QkkbGI1S!k z>uR?_nr81Mp8I`3D?h}0Ggs-fbc{K{juP5J8V1gWTnp(||LYEarf@82US~h=e{=XW1~8*N}A)!S8szqgWUxHJA9! z*SegIWslo?y6D%)pYDVPKdJC$Ypw(XOUl>RyLI#I15GLtD?a405FU%0=~oM+pFA&H z$YHtQ0+i=8o=5j--|h2e8r~%TzX_e?MZXRn6KntpxF+&fNH(sxET5=gvcbWywt_pF zcl)Z|4gUXA(7FvHpY5MvY~{#CRgot2vXc2xBW82`sGtaI*g%OG6;g4eLl*~g^(gai zzI2}7@~`tgEPVgu7#aoJDNevjm1KQ`NWTH%Y_tO^cXR}2h2Mi#VbNOA z_o^IT3=&e_5=VA=i{#wQK}%Za+0vIuUkW2TKgn;B z3s{G-u$LFCuC=UQ)ow&?)DLD~;rz9XgV&uSo~f|` zpXOTF)q2&4*?-@;kj|^=8Tzh;5~pZohFtT93G@8ljiyzezYe#4^KVLzhOKVJhve2a!}z@ysr8^>&2I2m~Bpf=4{1Puj>DPyR!&y8YbV^ruk}gf3l= z;{M|!6oyMenoiu6agFZgs1~()xroD%?ZN$xzR3*WO>{|iDkRb*d-b`>9yDxC9`(w2 zI>oYb*JQ}>=@I9|$%BY}pvtSJu7TCRs~J@Vf}5UzNCgD}{rE^lKN{cdK2KPN5S6Rf{x-{J9 zhNoMwg_Meg*Z(~)i@vgVA94{wx(t>Le}qS|CBo=40UfX9d((%NydnSAz58DNT?s9H z_SMi*E1A!k9v!#(>GmbksFeCUVnl;C`$|Jv(iZiA4FmWR%6bziUv~4O(3f?`NL4(a zCc}?B9|}sJi#Vl~Bn^oI%eUqEb4o=qo;vFH1@~CYkvmV)+60qKCSzv!)ZS!HC`=2jgZhom;tYksP0k|Z4l>0y^3_}wo z>O_!g5F6l<{?^4tT_+^XV&Q}0JDecXty*$rFE&q)`%lwK<>xg(o#fDp&j@RZlIQi# zm$o}jfKn%47UOz0>%#Vzqk+%+UE~3*4&e5T0vdgUw?MWm>liS!e-cHKJ>7kmz}hZ4 z0r(19xF1rHZlrRQ8sdXpGzmO-zWyMK2m2_rG(No4*Tloq$4j5RPuQ)(w=#nn+koV@ zS*zJJn&)8HIujoFGv=%RC@vVYx#6~RX$N#AkLVn&%xQkSZp_^Ho&}jsk$z!svd+Se zn!j;I84EHkSP2N)Mzly74o@ymQEa=1gluYy|I^m6*l zqYM;G-w!lCW`Fgdo+h$;g!~{nVIB)D+ocif7;(cb=*w~Y)nXt@BN`rd>o2cvKY{+3 zFTUC5Iy&U-^9Ss>!`hq1?pS|N`^D&&E6Z^9UWs8Ag7J8d6nYzi_d@K#eX@)v62cZ( z8G#W%SaT}6WDr!ULXT?c)okA!oA0h@lcj?7?Kl}DG>3tjUu$rt183EFp7iAMM~$7e zInw}lWumZux-hIYNO_G|VZ0<()|4tfc}DY1;h0!TOj+Z7-V?x$4&QV1I2VZfO9Ml_ z>OoCDEP6l4kOp)~7GI`tc3|Ey4SXX32&AI{l-F ztF`$V>Nj&s)*JLPq>0AR5*XCNQbgsu%8 zlM>lT!Z%$$Jbzc;8HK>SV*9(Zm)xf>W2ryr)gADMxNGZuchq#)VGNzDa~at_Wjqb9?1dZtwxfE(zfDeb2U zb%0LS(jJAdp)>9&MS$E8Z}N&DKMC29l`Z3-@Vm6zB& z&hJe~R=*9MK%~n7#&%dm=AY$r1euRK1GXu3m~w)+r}#b|Q4kB+a!D6B!47xvMa6&3 zKkYUJjq9)apNX6YW=;ank{PZ(6iRKJ)ePIvH~IYR4!#OpPy8hHH zNQ9{ubG#_x20As7w4S03KJ%WbKqUTAb?sa(Z?mDw;Y+oHUBSG&gomq@bSD2UIQcrQ z%sG8p)I^f516EvzU0x5LTgq2 zSUb(WBK_$dRpt*_V3DH#B+`AT8DEFUf2=7t8s^XXuU{KZT75uQrJ3&$a?vwR$2RQT z0}7~@%v|tIUa9-^g^&o-E{u14j8+)=8U6%jurlImEwc7vT5KIb)i5)BM8ld_`%)!2 zrXGSOLt8rtAeyVsXtJdxW`Ey<-`t0I)#PBcD*C4|gwJqxiKDqTQRLeLRNs+GWS|{_ za_3J64NC|JvF`0(vPa8!qB)(=EeryR@xXs2UYXV38^jwARS7VCIG+S0r9_^C9?i^_R3-Nrd0N zsmjA6Y9~>y}xlVNJW?HAHvTLD8d{2m!?w(@wPnWuY zQW;#E@%XZ_bMz!qUo8qjC8GL=lVa^(AVwcmyAh5Gw1rm_CMP{Xu-*wT)w9j2dqA5kQm^#gYjvtrRkKO zdw%nTpgvEe6g)(ALU z@&R;N)pz_B-4__GS!JElX|!^WA43mM!D%fjAt;(=ZrylNi21rWs{`5!Q2;-`O4MP| zRE53hf8o>0KE<6EP1?4x%&@Q|X#6>yCIFIY46~CAY;8L&SPS`!Q?J`Ajp!@BW2jPo zK62IRHyX5@LXQPcH1HQC(ZXsg)bnoN{!TFSxOEfS^|<7SAus7vgnxw2ygPQwOl0JX zOn`CJH}|i|abv3q>f?QQIy99Z=y|JL1HU5P@3;^_ASFm{8xo8bF>-_wa`NjL0GB~RpYBsvmeasF9(uJIwt<<-|~mi+@;Fk&*NAB{@qY; zJ(L}%U=h8H4kcrwx{i{uIre0*l3S5OSnrJNLMyR}##x-sjHN2{%VN6K15^1$f4Z`R zmmQaiNKNKsZ7SNPcIJet4G$h!x0h=}dJcAZ(|>3s^^*hT zK&AF>?TmM*d$>z7=f)wLlERRU|770h{i@*4n;R3>*{~me<(($fKaiSW;>+>}l31Q# zk5d)T?&~tC5(lzk)H#c5R7)O(@7+clefcPv+-|Z@5Iz)cwMtkMcVWKpkX?s*tz*Xb zI8rZlQ}d_^6KM|tV4%eIQ4=oR@{>%EJZMU9wO6;O&goT28anLBomUUGlkllVWQ;OX zW@}A*8R9#HyE0?{iQ^_9H^|L^4A0OE<*P~!d6?0QLCsTsPM52-X-0HOEVVX!+9BfK z8HNAf4dw@~Wty2Xat`7yNO0)&PvWS!BTds((u$a!8$J-=MWY&^FgR>FN&an_VP;^f zS@rM4!1LRqj{Y<`-~B*pzny0tXq+HhevnpE#vW*M4)H%IqZ}ZZfoi(>U845GSw+?g zrCdXp4|k49x%_Hg-7fsPe?4|I&#~mQSR^V%NO@S~C#ry|d><)3%C7sp>m<^Yhs|)< zKsI%JWP509OGz>y9&M()O9*|&U}RYxLau1bgWBY=VLK?MR)4+E)=j;94=$w;<7#0+V!_I@^i5oP2r;86FNc{fG1)iGdQ10thoW zGNdBWs8CFo^%0}@VEH0HlUL<=+J-_HdV2@ub3f7^WauJYl=XV&w9<}`4SsmUEJw(U z(O(&b?eRgVN4obhd$>?TY~KyTPqKywW<-a}LKk{`6}r}OUaC1i`1gvJ2Xi3~p{YFe zDZs3JeVt+DR~W&jp##Hx6S*brN#9u$pIMuyv}iF0E?GS2;8~q|ZK7SLeR#Gz$XXBB zx83o5aay%nRV^eHPE~5s^B`&UnB9jsH@crc20<&9FuiPj7wND|1!+q>el!iVJ{uRV z>vhyAi*|kXvN_3r4%J`k;jL?2NN8$KXv9t{&!ve*fmYW(&crK?IMRYZ^|^lhxtG|M zx&22@fWz4ur4q%GFMY2_%uD~7?whAaLJvTi4hwDMKpecI=7=;}4}LVM-wv9)q#90# znD~MpKikvp+En4T`E_iq*&2vYx6IXW@9xn%YKbh$)k}%RFP+v+RjnY5@3*L*1fbAL zb~9Bc$-Rd6hi$_rEsOg1k4JFVlMMDX z%nY3kITF|hJtxdNVXqaA9#}}*meyHMbeOpKyVW<+7Brs)@jG!j7SCNp2V@QzZD>`j z{^#yX4_xi2#w)JW5m}wtR~>QJSwKlhl8|`4+G8aIX7k zzR=N=Wy_`Kuy`&#_Sw-q+s|KjH(Wg@lkJ~5qs*S&dv%wR?5>j@`1kmE#WN>{kf;9g z@u}Am?(?khloeSHHT!=-a*$%vPXV6da)&+mbTd!=`oX; zWXBgwSav z_*e`ym@;1quKIP)Xz)&SXSORn$$=}lCw$~`3@QI4hFxj!4F5V&;sV&MYa^Xyp z$mpGJG84o*c(?7vq_+!Mi#w1#mMZCdy*>o3{)j!>Lc}K#(<$TIiDyUucY`|TLfcnE z+B)WC;-$2~z;*_x$s#8P3k%ANw2&y3$Vm~lhjQz3X59TxxEF??EiUKptMprkOqRJi zXI4Idr9>fkQ0vXa_l)0ALq!G(%;)apHEmNY*jgiKa&e5`qr$EAL~Wwnuw|V;>v?iJ z_vzk-CVVDVlvTqC0-MUL(CnknE?BnrVK&ijsYZYZPIldSbEASCwiDHg1M-?QVB0Uj zUPK4HII=Y|qYg4KF~e5B^`e?b=$T-V&M9}}g${45;GVH*Dm{JhCQDgKZNwRO4hJ4! z`Rn+M`i*do21et9h@i3to6R4hOln03oo8|$A%IC>WL7ZvMK&G-j(WckQS0i{cV158 zXXL~Ym}#o9-!zkgNVT-K8nZT%P!e%0YR?VYH4Y;`6aMtc3#>hGsg|RPt_f;ZkoT)+ zpLvpZ^X1hf{V`6YM61{9vFtK{yX0nqv7pbl-aS~otNWOCvC4^LMk~bI=w4PpvuRsv zVleBZX-D;s**Vh+nUkf3jMHO2kgSxv!}4 z`4vW^QGf1MvzH|KFhY<8NNG^t&m)GE`=opHQ4P+xj5-(w#e8uy6VvAKD+YUJ%iOF| znc$(-E@NRkHb>f&z6siKZl?aET5a@V2qTUU59S!db=(uln`d&_vPOo^JPo?DdHLRaEgj%&TESa}|9J0h>{$6x-AXX~^^ z$k*I~*x(PY89p^}|6Ey_=)By6vlSUabyL^GYsj1XgV>#(Y)VhN_n@Y-hcj^A_vCq@ zlB$`50HH0nPvRPked|Wr59q$&#P+lOnaP(zmb->mj`>zOYtr*0L^C)yz^@o`5y3Yg zT7vdPrMRFd*I>ulLuL8VWUOyLt)Q!5hP^R~)(1C67`5GLkO{0=A47>O1J_MouNxP~ zRt?ttn^=0|mm`I$r;qT4B6twmdQrS)+7*3?r86cx!@Z$;gtt{!NCI{BAYg)iIAspi zx@&QPMg0(iqRL9@3w|O%g>OV(A^d&Mlph2)QvSW3>oTdHSFRi)xfV!nRK7M`sz8)Z z`8BuQxCwK5{wYbtw7o>%XYptg_7a_17*^7s^Ph08MeLQ%7^HsUK@x=7gH@sfiQ7B! z%m9gOxf&F9IF44L51^aV*Ntyog`o963{a`2?jD+4QYOZ4c#{WfgP>%ts%A#ByNo8R zd81soK5mX zri>h7*eQy2)ig!4#tV&b{dxBX0C3ADCkI2JCS=GbaaflesEA6$$5qD>6rb6`saxIe zr3qRL)Wv(NKAvC7lhx_rh)Uv4#wd?5jX9v#jM68;WL`L`DF11iDaF~&qV9B;LKhX< z8oxKIv@aLW+h2uWs`RM%d1NgsAzCwDw6PI25mQBdtnXCH$Gb@3hhI?&KKe@<717Nm z%6u$eT3RT85{}7@?uigZ2ENa1$I&(OavrY5!1_Km9Vg9|cKtsNx7t97M9H?UMxpp~ z=Z)T;rB>=APi3L+v+PcQ)4TD4zEFOd7hV(!f)8XCrw>g5XOF||F!7EwGjUFi zR~wa6@Wd;p8e1cv3MOBRNN}4UdF4Yi)ratTG+i~5^*X}K25I8v)8b_ePQF65a6M?T zP$(>?o4e~?xgj@Tur3{Mdl16TjFmih1eXb_=1sqtVoIlIv=M=+j1?Vy#)dXJV~A$* zfbW;EJ)Hl&^}CnYDgva6C8%Vy+7Lq%#PvK>>4>8p22NNj^TV7ibrR!+L@r#-~CW<49-?Y%O|or62NJ6j#Kl{pA~%P(A! zHuCYcq@q(l(pZg~bJvp)Gb7%<0CFN~0gR>ofpgD9@PUg7C*GIlgm_sSeC))lak9F3 zmF$}KsrjaA<9fCqEaNozS2MGDQcmCIWwdtgM%5{KCPFe@TJACg#FBd9zu{tBOXjB> zOz>z${|6za|Dq}_m$h^5)nSLcttW*zX`j&yLmC?n|CXiaFWjt+wV3M&q{ESCEuj;w z>$*$d)%MhW*(rh4`Tz5nFYL|~HR5*kPkMl3<ZpAFNY6Y7mZ%Yo?zcNL?I$#3sjhGM<(7ANI!I|C)vS7ryemmM==@mx8`*0*D= z1osUVvl@4Uf4m3JTNB8Z=|{=vUB*AXpYL21;+%vS?UpYGi#^W@FVF0e*1Svu_^=mP zKS`3@9#Y$}?dn;lRmEFwwU><-6*2$*+uR^;bS!(0Br>`|t_*Jvb!NH^S5#z5l~-g` zr%0twEji1Of2TMhrprGnMRZ<8GAklcBnQg{Dwkr1fm+$#E_T$bSpXh|s?s|J{!Riw zHdS~JNqsf#tDr0n(q4&sswL_&&*Z*wm0x&jWF2cpn!~Vrpe)7CyRbmEB-pt zc=Q=Amqtqub+b;PUV6H8M%Z3&wQ=3_Q`Qs0l&z6cTh^Yy<9^zp@+FI!-EY&Wi&(c! z|1g%6eUlm*wcfV|BDKp~EKk3QnWm*YU{(xuCWW zE3Vej!Z7mtosSP=X=CHvjo>7kz-i+qFp{n`=)MI#<%y50LUfb97|7y0-SVY&vph~P z?@W1B)gMm->HI2yb00$tfgM=>oDOn%tyC)xS5*kzNomZBE`8ca%~(Z}xryu?RkV{( z*Zg*?c49fp=l8@2f32K0^R}U7NJ*aV47JfH$4Id|>_F=~NDL=||ip;vU^-3i&@4}+J9(jYmK9+8M;El16h)80MG%#x1;r&DbuXo7sHD>YEB0o9l zji?;#2LTGRmH!^>BzSn~*cVTjZIlnQn|}eckn`O#Lq4+yZ--U z!Cy^hJWpL|F%5YT+1I|$3dD%7uCal{H%YNvhwUJf9Dc^kGv2fT>I z96_g6TWNhLZhL?C-4ECKp1LRhLF2uWU7Fg>U9)q&@b5jq+X+)EpVd@g5Huj!(6lZclem;?r2Td^T=QSpGNS0kx3gpZo?djrjgLs6#fO4KP-DR$6 zo87NCT#V2Kb_z2kRKQ9MJYIpn_UXF;ufIQ@-ImUHS#6ow!9Js*oGd`s>a?fJG9dlN z#r-GiRzlJ<$915U9$ng*&Ze=2LbH%=5l$gE=K|9PE~Tt-#X-vL9=Bo*i?&{tE&7+` zHOidZbXv}<#7i|?ckb#)U&Z#CLK2gDv?eJ!o;RC!CIWn5ofMqrT+f7tOsK7Nb~u*J zZ7tIDB3kXwlvyQ1%RMT5ihRl&c-wgE`CE6iPPa6dTEWL^OFQvZ-l%>}H);Df4zHC6 zagM6wig@^8oa;MrZpzNK zO+PW!mc}X`uTWaV)+*?`0VUIdL&IEej>qb#I^{}b4JSeLeL6ht@|oRz8FnK}vS|<3@KqR4UU?OG}fjhA&-0?NP4$vE_yB78qW*r@5J#EZ}IP) znOY&dzalSxpUOMj1T-KJ!!efsMY+}uc`Rn$|WR>Jwcq-59xyFb=X zq^VJ40|&DKh!n!6GDsz+kb(-Ql_fP$)brEYB&ueI9F2f8Uezjl$zn_84?M3MbcSQq#Y}Vvd2(OebfSkGBNQCvA7e8o^0qksSIug}*dY<| zKTF(SQ7187ned4WN9%bE!Q}{Bc;)`vSTmvVOYkWmaNvT^INSTk2)I5VY2p$3oGYDA zp0E)IOuaG9?NMIHU&JOb;yQ+-b;ekOgeKSmbKS+f zx~gZ=S_{=(Wfl+MI2%|*PSnIucD<4571D299u}0F(n@UR_v|>OiZC$ka$T+xDcJ0x z8xB6o@52&QL|kprWP3!L-<7{)m5MtR*J0jZBjuav${&~C_vFbEP>7wF!Hk?r-Ka>m zSvbFo{XlR_>1F(II=|s`M=+7k$V^!QdS&-ofe97*y|V6fqx}ud@~Dt$;_fdw$BbQV zu4lQLX|l>}-!7(#6Z_lUANzOs57x~HuE@LatRbNnNohYcqsz@12EgA+xx9xVD2^@_F@8 zHOq@_R6NjAMb`KKZg7dcT)1`xs%Z52_7@o?*tw`4rRldy{cGZiUs(`)wrlCj+(1h1 zC1lvc!<%dZ|J{GN;XO5tm6Al)6^*!ZDn)5SBuM6FUD7ACkJ4Yxl{yp^fGiF+@SrNs z@=@NPVW^G$QRd&xPOtOn|DR_wke#KrtQGl<9U3aEJQ8ZOYEz1Hhez_XEw!8B`WVA+37 zA!=c$n`_EF2mgz1X&N8h$k%>sgf?)V#rg#~_-0P~>yuhSiR0Gex9Q2kPm6ZH*Halq=O1qI*p zI<<#O!r(jS-7*>)=K`liy+w77n$XJmah`ol%p-ou$HB&&i`_aTk`uY>8zM>+`Zdc= zXQ9JCk$S)JrjLe`jV4J>)Kxh3!T@Eof%xU|t~X@YS3irivOQ^UnwY3-zMk5JZ01XF z@X-%YQ`z2xqD!5uc(tTZH697>DXuKe?uN@6Az6zeJ-weUrHx?^D1#M>wCJV^=#@ruET)E^hE5Kg7BvVI`D&Zb*Wy&<2NI`v{W zqMM3BpzcB*L>}fT^tv(UugYDWtx9}$opk!hQ(?Y_VGm@yFDoAHY+Xf_cSjI&P`EY{_K!-L0 zZQ+YS48S6I>aEx5ze5G#?1Uzy9b&QEgB za@R^q8 z6=Z~QlZ*^nShs4v>K5)IS9#SMa$6a=6RT00TMzqf@{!pH>4IP8uj!ofm_sDo(zmeq zkLR^(SAMcMd^83AqmOkBl>M8$!5$@G^;wO}FQjpN(a&WF4M5>_vdXK??y42#V-R-@ z6&rD1ZrqR|+2v&Bc5u4LdY9SiEqd#+w@2%%*!m=En;7T=cl;LepgO9|T?n?9`EUD0 z_$|sFqHE=~7f-ADe0H7$<(-)R`kAKQmgg}lFwC44RWW#chRp&81`5G+m*mMi59)Vm z>Y3Fax!+}!aiB8twACV>4y#kMztii5A4@`p?7uSH2@uv5N|>O*kERf12|vo>g?D)a z9ZSb(p(ZS$e6f6f&p>)JNj)SSL+2C|SKzAxHS+mPX|h$mWR(`0V;WfMJNo>SJaS|n z*uXyT+Hlv*F29JHhirI5HH5`jduD?5=ZNl+$Xh9YGRslk^)RU~Ob zfI&oZneuHljpRSY+1pJ&QAP~!A9#PMqV$e5(v}vv1_eK*^Pzy7mV-D;;)N5x_+e$u zp3C?ed@z0?6sqn+v=ceVIxuy?4BhE=U&Bc+dCHBNNpg<3_;ct#T?8wzrX&QXtEw2n zGPP9H=qfRPOt8cN}#RnH9)@LY<_b{pMB|CB(ON=oEQEbtvU3;3WiqA%bi+u)l zjQAPncJ(A<7ckt=syViQob5cw%=6mXZ_aZ!jBQ-d|C>shlpKh2GLhEK=Hy<5?i^YEpNPSr%hWgW_s?m{gxTv&l&}%+DKG#It%C z$@9BUW*(H)Hz3(LrR@`t~ib>{&g=hHIA<^!EqPBn%@HXIi@Tbi`O7v5@^-hH?y%##bSOv`mrWqQBT5yNSP zxQzTFoB4Ctz14L`Aickw3nO?nA5_8TVd3W8mccrfFPUU+nRLccTlgmYM~5RPaRq)WTNiAssSJVFl<4yleN119ri0flfWTv$G%z2&t09xz^Ex{bLAqUc@L}+Wb9mr zI2?cH`K!b%lT7H30{*belKe@gv1`u@SU6QIsy-6-MlBxpV>4TH(gv5i4f7BNaYs$t zLp5W+XDpi;S33H(Enw&E?!095 zxv^C&dZ&npEOGqpweFiZtds^9V7-g~@WqrALsGdMIa;wvtPu8*8#P|}J0>V$i0NhpyKUqV+{yG)y^9mt;UZ0n;rK$s-uUL#IPZ&Fcg?55kF)aKx5e^HHb zo4IF5Wu4JQKcLe9s=Ior94`*=TxSM~^8Dax@m<_aUsiSKyunhQFOk?E_T^l=1fskx3c^ z&HlM#7?ZoayFcFA69l^=O_cyhVY591U{mI2Hl-7#MX-r^KO= z1=}Tzm{feXyQ3@PfaOi(4tPSolHgP6J9Yn6p+_K2OvZi96|-3}d&+mXNQju=gIE0( zYFJ=!1Jo8+iF*r$O!G*}1eONca0rXKj2N{xy*BPMOPZV1n})aL(}i#Qh}fBBR%FX0 zvDWsBp?Fg`N}-Vjg2}JKh8YhjS*mqev3q@f8tliZrW<@>$2cIHsbjxzP}pwP=ziwp z?4AA}lPTLph2CU}O_qF>yM31dg=trd5Su41d~o!B2wniYI0)!*+kUyQOOqc}9iO|b z>^!wm?hN}u$xLHPeefSX$BHg9M!IT8aV(JsAB+=;lQY(_xu>SAV+_8NM{MWHAZV_F zPc98&3e!1jJUF*C5q-^dj2R| zX(-007TA zncy})bmI0&61$$NZaULD@w3x=o;2apryn?rEjSzT^81?;BQ|*Z4pC@Xn@w1x?ye;U zKV{3iV9Ln6;hWf8;bf~+C@ELxBYGiZoRP@psu{bUZff5iXm((lnhwiHagOm@msDvB zP*e+AOJ?1e8Q*}M$GpqYRacwbw7Y4hviNy@hJ)35`@|@rbRVc}Hk8iS4f{CXI25i4 z>b&w(*5gp72${Km(kY|(mB9KFcf_*#cg}*5n@H^*aW)qy0*f$%I>PpbotS5|3pf>k z=(`AFhlE>;b4_z|$jaqLyvNXA0V?Jpl;$RLTUsI_<>+Aq&SJKSXBYL2lRkP{|C_i- zbS-Nh5`J;K2rtv;hwF2KtQqs2iY!Niu>&I5MDoL91Q}KuED-7Uc`rw&Zn9HCOJ

vwgk>XE_uY!FZz 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

8b-unyT3H!TN zxP@KKs!^J|lI9>Yby5^O!I3oT1~co$v-GA7DI#!rejLw>IA6=y~wH zg%*QaamWi)&AU3_q2#Tz9pXlM45EN`dKa{-?7onOv2dNhZb_gvSWdE6k6K+*Y{ zYrMm6eb}O5^w&*r3nt)Il-m-x#9G{u*>f^x#Cm6aKLxP&3KhkWNdA?!eS6Z4@jsI%~>w!P6U&YgtQ)S;;bi2O+* zyLBi&_a{e6irAXdNqRI)KP2R6uQLWbFAJe)JEqx}_UnFF=XUew2W zRt6$&Fy6M@G#GNz8SrIiNxUzBjKOBlGRL-76!RiN^u*oY&h{8 zk*RB&0wT6RZsXKS{KtXKTSt1i%c<$$tlXpy{j+=psj3N?{IA7k9VqSNy5fk z9`e6e7=sg^^#A{Q<^<6E zU2l0=de_UaK7c!ePtA2h0SO;?5}QQ$7apMN7sU-9ZbC1y?8*)~zCMW-QpM zr~LVb9m-VfO>Dy8ZG43`dn6pBa`mTpFG$XeQ*$NUSHwnCIoe6kW&k&QR>xSsdnN2N1V| zkH_l9wvId_mXS{>(ti6)mV*>N1k~<0_zMvG4Gjia6NMPiF^?6b&j-LHEB6i4L4_EQ*PTPM(bT0;70 zoWVzYYD&AQg00_BY2<)wwmU7qs>5~}rbSowyW|Z~QXP&pt>?+4$jYnGVNL(?cSx3O z8`doN)T^$N>torPi)Mdqd^v@VC`uj+ zwl`-GwLGzXSyQhXia#Kcd@q=hEAq^BoDxDB7nY$7hl5+}E;%_4xlCf)K!v`XlIXts z(BMYiV~H(R`i*c^**mFFAL`*>Pqjp7DP=cj!j9^qf5@Q0ZnVXmrQ0~=(?9P z<~0HOy5zVlmdSkI{?!MW=(NS$bYYC?6+qjxo5lo!>mM?Ob~M1T8~SHav$oCDtMsy* zooXHWs|(WL8h91OdiIEX{mU|ufbBs|k^S|Ei1|s9-mSADyRZi6`fxce1xDWbkHp+e zyH1X8ZOBv!U?g>gFcB8^$QDcQ^%+7*)XCfF%=hi%>!#@A>!vem=GyyX7sM{~o$(j3 zrcmAE+(md=Cu@EML>$G(1g1(3p~0C=cLhJOn4j&>YT<#!e`XTGL$V%oqTm(OKhWdrD+B=-k3jUXlYpk73om_Uopfz9Tn~ z7x?^9CyOZ^Xtch^)^Dz@F&<;2Q@R`}8Mm!9S>r876OwEiau+|D$WV; zKZ?%%k;(V}6ZC}EiM%rK*zZ4PD5hxD!-*PM+kl*6zw8s>bcoX@8X zIaSW5lyg#jzWe?Q_Ye1VU9Z>k`FJEm(c8V9U(`x<*wr^yNrDFvqGbl8f1|j-e()Az7lg zk_`pYX`iNA%mS~f%Nx0_)3f|}$zh3^L6tlHZvC0zR%;LNJT+IEu#!7itu)GkL-)6n ziQ5coJE8L1I_v=Rnj7%R``R>@`7KC~P&t;UPwyCyA_hE@h%e}wtaMbxg-ixyWN3Nt zazhr>*!oCEd5xe6kz^Cj_J!gSW3I~xRN%~u^jkUVZwYx9B!tiEnXfx0oamn`L46cc zVFaSw@_H74rZ>~7FRHH5yoyw(GJPqrWwyohrr!nm#6Ji~6{E(Ccs(Q2K#OU|Wa4CD z!!1N1bhNBvL1nEW+;K%47IIV={vO^)85|yolOndI^Lu2KWZ%aczaN|YH=>_xOBC?- zeE7@I@pYFAT1%?PrGE#AoG6uMelB(_uJ!ZvX;YN}>Yh${$@ur{-!DuQ{qW~6H*$kH zTuh0efG2uO(bx^<*pxW{12v|Nfc#uX(10JD@+{ENhGj;AZ%f;K%94=qc$tNwMwfBi zgC{=r`@(xtxU}&K0QX1A8198FE~Oc^5uu!c6D6AQ!tMww5NM;A# zlk0Xqo;ImU50K{Ei`Bm@@+6Yjbo4_JE!xcqM}&=-##?>_?!hah-1WwXx zjy%)KN3q^9K27Dcx%g#v=z$jC$91X##t2fSeIW?Z52hag-$dneNW%z#NoGo_wMUY^ zixWk6YQ;D57Q4I2dh}LV=%T6Y{e;i_{gRm;M5e5T^=kB(5E9fbRS?6Wo5Zc7hxNZejVNke>*;qGULf{x&Pm2Y0!)yMY)0#)L9 zvoPB+?PCSOz2fhK<+(0FS+P5|0Bg~Ej1>!n@Cvhv`z~GowEa&=S>M;Y;o*DbDcmnh zp?5`ilxyhL8^Y?X4faD|-8~oT19OuQgtVLUCU+|Z%~d zbb3@{M>Ha0JaIJF^F^mhg!S5~)!DUE8~5zLWY$DyX2jxNts8FA<8uC$EpxBSgdAS( zZ`6pS52~LP)J170NjuR!0}?j*Zn-tKp?*Vz!Fg{j4Yotj?diUC8RC=7m)m~xD31KK zTw4qmnN@Z2yaX(D<7DaWr(9GFneS`0NSA}LTLOG6ad2(W?0siA=w_VKAKr=(<%aK6 zjuL`d&L+6HOQ;cf}}GCejdN?VsT&Q;7h3QtlMGi$Zj1*L>6fF&;s z3{HkZY>r*Sc@MMV{F@`MB)<0<`r{Ju&iG^bD}g&fKL${3?%~Oe8ibVuke+SsH^Zo9 zT88f4i z!=Kug)efc*>TwnU7TID@88@n-HpNax`&cS@&W-RatF7?my|8mPx6C}vR^YLi^hfO~ zPiOE}906u5E>KPJ;=XR6_l}#mrm!brDDAm1m%F;em6Hk`y<=`9LzkP3J;r8Xhi(H} z(X(H#60n{O7VXLJ77i&9liQsEsT>R;;~|q?Ekw zRUjcbvSHMnP#H6`Co@oXQ{z&RpP49MHPhwl5q>+%nFnV67`WFtMzW47`bG`WmPeS2 z4G9xrE`w&9d#Uqb&(O<~E}QwnZh0gJM)BkLPE7wQ`%X^aqtg$ndKBmTY8Ci3U9_?e zUN8(B>b}&e-tns)fnjDS|82jeASeJ$7gWZ_fU+;bk3p!Q6Q%tc&)O6fM(&|bo(`vk zpo7;(#QeA_{c;Rt!)QTci+*eoH)VcS4``#4Yk&cc;hs+PWd0CWn|~W6MV_3IQT1!-Pe&!7&hrGt9|aLG%RcX?Y;^& zGZljDpeJKx`t9>+(Yq3HIvo^Ujr#(H()a@9?la{5PD@$YnJf6&hCI|H55C{%p(<*k8nmtIuMD8D`N_Cx ziZ_uaG-Pe%_|-US@dena0P;H=!978*mxsr|x~7jfyZ8OwsG7V9D=SOtk=5mM1%c0N zK^MSUsduXhwrR1RX!e^we$zcyt_PUkJuCDjW)t1=yYhw*SyH*^yzWz|=e;H!lw0!7 zV*;Qk;DS&?ggHZ|%r$ZuvZz4#=f#w>u}-)S*(rml6kX(Oa{4Fb z#&b2n^0JzG>>`@_^HNDh0?4(>7EQsSRU@$#xSyZDd|UuBEnY6gguaGt41RpYse*o( zER%!+h{aIZtM17%8XkRI&2@FtyzwYDV90*2cf;w)^kN2g|9RqV3nkbCSJFq)*n3?> zS;j5X-Ir#{H#LT=INOZB!k~J>MQILr0ZeuAZ-^ojHoAb47wE@+3L2gP(dZ>beHt#< zM!&E=2cvm)lBoCG=!@NJSJ5V(^&Tflj|BkuZU`7&RFg*|AkSkzm3D?q{4#)^C0+G? z7MHa?X{UGOGFg;9rDLPo_&^yrhxjgV{wFy(mIF@BG+&ax+z}vtRhTglS>pMzRN%r= z5E^0H@`&)7+9Or3QQW$y`DBR+a17aP%6yf`pO)Qf{usma=a4gt*smrPo_R;!VJZUq z;n&EP!(?rtUo1%)X3oO<%U|C%Gq-7pcX6`R=WXQku0TVsp3oXnd6w3a<3NK>0NCPo zvw#seXvQ)*%?e0E-%D~!dm?m5adXIzku}OpYO%rvwiW5#G7?tbas-ob6}Byt9i+c2 zu5;)wEsKyz-e#4NPMbR@#Q2MMt-%QOM3+~ON1P4=i`Pgb=*+kK;iqQGh!@^PYyLON) zcq3;Gf^vMl+3760ALbqVWPoki&ystH?$`4|ceJ_CvY*ucB3Q^KR@hF*Of(xz-R4vX!8hYBuqnnvNZ7v8A@4?96|p+l9kihftdEsrT_;!b+%^ju27rfl(=q}a1Scn^d;R| zWJCj0u+;x1(M9S4^zK@!w?rbbN5Tg2E#QTW6K_9w>P%3{(|0c?nKZ)`hxQg(!wen4 zyDo>fL&& zJdyH7qHANtEBFy4{x$`fJgM}NIq%OePSkENg7`?7j>2Sss2D{kNNFY^n%iAsD`XX_lrJ}vc>X+F#IF2=-SK^3-5`ebj`P%VUt(JYSg!! zLl>X%3)Oiqf|gy&-x}e+eo^*a?Tbv*MYnpmtOoP0*`%nZ6qMib5&}Fn8-*jeXk#1y zL}1qVDvKnA(%8hR(Xm%1#=j{tHHKg1gD{v}-HF%dD%>93Py-blYIE0=pXYtl-?5J#3#Q9%u>VX(Bg0pldUj)+jQ@ibZhE%Cm4h=d*QAiiqVT{n?(^-jJ;(-4~t#K<=d?^9aJon5~C$$H-p zPnT@{{6)nTeL6B$$Rkyy3K7!dHIt(A&*yx6EOzDc)M&xhdJIzn9Y$fXe?n zW0h{f2A?1eCL>fE-EHoV>jonD5U6Y)#fopDZV}@vV0>Ld=Q2F0GVS?3>vpWlFv)(b zzS@3j6%o~Z=EN{4N_uH^H4PGO5r}HLkpt6DIqflb=| zB5@W8X;hzv&SrR$iEYj>J81NI99c#DQ5m{+e|z0W(|D95|I=o`HZtkH^eN+2&X}Nw z0F5p2+76vQ2~VF>+o*AbQ@YZuXuD9*HWT7)O$E|H1GLz^CeR3>@5<)-v5#wrLi&D!Dc0mZNo?D8!Cx-;+9#I zO$N>c$$VK~iTf4DZgpvOXjk?hDAssyGZEu{YT8<|tnx8lCQWeHZNK^>tPlBh;||Mk|r;g z;U~Db+S3mtzwcrpXr5qUawPH8TkuwwJ=YmsH%ES^%JW;?S@Q7}l&MRPYi1_dWD_Xh z|M(~liR6znsc?F5z&E_vjZrTWb(y^J=9g5R{A#}&Xh>rpyjK5`vV9-{z$~eLk^DFm zekfhD{{B~QtHL=GS4|-@gYu^$+znZcD~#lk1&2@z*gMiXCJ2l7b^p437a7sdmuT<|oCgqb%1o-fx{=Tt!c`s;Z(e_u#t zQy9rW(o!!y%B)eua?9jKXO2T%V#?n`r`p|gqijTOcm*28j6y5S?U>B&SC;Gl!asQv zHCg4zMu2Fkg&*!sPfc$g{749yg76lvEfhEI3J2cqyS?RnbVCu>l+OW>$y2B1DU@Z@ zOI6I=Cg@e6^TJ?>i;Ief(rCZwUud?2S-G1NJJDA+ey97}M?WS$S@iy7#H;;@B7j(x zD*vgxI{M>c*D}mBtzGZ_KRCg0=(@l2g;=R<=<-^iq->`RuwuuR)SFrig;*MB>R+NRk7ta-} zL2oa4=LrVw4g=pf;2AgBf?EIl-vD@at ztz;h8@v}(vMCL>Xq2Yc~9?$(S>oz6(nSY7ao@H$&U9f}_ zb(g~u>W5+Ar62=}HYJ(ePI3SySZHsg*@Z|7se-tsE(T0ygq22jCbs9-eoI@(FWyU5 zeiT%eZ@qP2LS;~M$Vl$Bz!3X%!;W=x!`+b8>K#enT_i(b%8=#pUEpe^+zJ^0FzF!+ zJ5kda7wQwm^v!#Rl`tNmjQiT4^LGCK{ljZ_FASo;nBTr~?VH|>q`yD9Q^GTLI$^ar zDR;?#^NM4u4Uytr&|-59-?w7Yq-Qm3R|#7@VN$KF$!AX9kO%e6Nr*&7oVlAopo)o6rbkEjrL*K43TJv%*G9=6L2h&O|6Zmu z(&}e~Bz*GmY;(m(S^B`dT1tz)&b;=KgCkt{{z6AU5vFkcG z@>hu#hm*xj;zm=fVY46m#>`)k1yTNEVR?&egU;6qAQBf3{eR*GtVxSDcXTZ1C?v)g11t zC3%{ra35#@&i7To#(7N{IAz-{#*KGOFsf9J9LTrycbYUA>~H8D*k_WYoXvkOwhq`| zzX4v}HsenAmRUzP21)%+`}1eDIJQ_g19BHHpCn}Z9{gGMK&eOi>y#Nt1Koq4i)sq+ z*l_qAhfS9`k?GItD{{;-(u^$a^N?C+#*njmY#+@!QIQWj@F_OGGKU64?n8=JDOXtA zH7olgI`_#vnQ0l`Lk53+Oau&Eq*os2**kbf<8{!Kn8fhGysPps%h-LDJuS9sP#%Fu#!6@-M2pebAt535Ts*~Cenx2k{^AJFP{NA`>5c1Jdyrlvx{CluoWJuzTTo3IU&sq>LiLqqy z2AA@_)LFR%mY2!FZpU1>st$Td&*d-JdVT=;OI~otA}3W#McwZ{(qT8!mdrj!2AzZ9 zW_vx@@nwL0-Uh@*lKC|?qFC6(#9Ee0s*jH)ef5DNdI@1Xna3S5V3+N0fG>DlHTUks z^YL)g`jV^-egZ^_jWymx)K4wLuXZ zQ%n`)UiZ@P{Elro=SB!7s`BM-a63KLUoifm7a7A}BG@Pt#$eFy24KhYg?gFuK<8o=6!y;|sjqZ|I|}FH{f)Vu z?aHe7?r$WI;7ie#Q#6m@kKjs57MxD#oqVwxYBfy~Z+DOK7jGqSuFUNQ2-kqSQ%C|F z^NhL-UID2l@`K&R{nrHGYf@RifW=H#`ftaO{?;&B>t|6X$c3W?iQp5b&27dcsC?h|`)6OL;b2^f zIzEcV$+_J0QCkXWm*qk*Psp;}n%B1Q2cG0t7Wa)*x$G0J=Z-h~Ay=!mGmc^fcBD1G z8?^|3G*n#Sk z_EI>)P4PFrSMY-EZC~`Uu9W~ib~=|bi84GphcPc-e4zw3t>G4*J07=F0w*a0+%;@* znajy{oOhGDzIiWZyhQ#Ty>ba!Ve4f?uVL-;6#a?_x3Z$5bm zta0U__G7o9F4L^rfdz;P*>~8_To;jxtxdYymiWpOGOxnQ2&ByBwkA=&zjUY5=&TXq zg`KmHrjS9*e_(c%KEyD%FWrb{DW30jz{923xZ~{*IFs!9chQ)No9OFOxjh|++O;lU z#Se+c+lD7@Kpd0r@|0XmmQ9+G1`VlHzU_RFOc_S49)UD&A5;uc20@3H(xM;sms?B> z&?j7Y`EjN)$Uh97wroJ15=2p$Tp35nPw&Lg3PjV-bg*uhTIvs%!|v6j3STVeJL(fy zLDPM`WEu@x&&Ed3lLD{vTRRB~Q|=~l$DJ0wxph@*f&*I7*Kkn${9NuLbx*Cm$ut9J z8`<+HOx4(GuC>VR%w+Mlc8i_iy_jXvADfrE&3HL=yBj>@DG{ce(%0ti?!o7Xzg@#y z%omDPgIGlCd4o~A{>vT_{8~|CjbB%7HQmR`f~bNkP}02PbGltrQGd81e%U&YmuVR< zoz?*5)@v30;MsY6Dno`2F*6@4nN1>@OZ`UY6`v7m<*-WvOrVv$OX9BY(U89&??=v#hD*MlmGEFJTp zqyZtpI=*$a7eHr*tMz2F%=A~v(9P!bn=NVfTDbo*YGIS2qN`?QA9i@QBKvOoPRX`7 zjp*YcQn7Un+!U0<7ByqQ&QL2}1g$(bSwnwWb%~<7b@L-=Rv-{Cg4cE6^#=&GAxIiC zS1O3RLN=aJ%h{{1!apOq?RyrrG=mx`=T}q+@0$bm?aVl|VnV@+tw15GJaHW#*}=)U z65p8?^c**Ahc*tL9twaItWOkL`wW!FeE>!G&n+ovR%|Rl)kr(w-YII$~YZ5kTjwL`{8w*!=ZC8q;xrARHqt?v5s-PTI1|F!^ACjL-HO>|MYywf& z2=@@+kD!p57xCeRS^l>`WU!kXp@ zZ2C#PAo>b@f9b}ME2tUz#1K+hp_G(cz|(5xk_99Cj)38a_ECV6hY{ zGQZK|DuFb)85__<+RRSdmPAn6gSwUcLp4S?=PzG9Tj8V*33p%ESZE=<$}c#u564(H zj&BfL3_n7~`3AU_r))Jao!^+HW_`0_wX-CE>k^?Xt-rgqN%5;~_;-vZ4<=bzX2|_6 zYn3F)CKrAi=5DaP(aX!dDVOV6lR+ihosYKvO0#5Nh#**}5=EEWBI+gRa=RP>wlXZd z{t8SVYfdCdHYI0^1=3?E>-(f}P5>qR&?Y&4^y|uZ@mDgBDl~WjsCPJ- z%4j!6ve@hL;9}vZ0od|HRLR^$Kf!oD0Q&$*fL)-R?|9bSPe51+Sv@*h$M}3n1zt4u z;wQuFL3R`36(TYIj)m5Hn??y2JEmLL=D5&#{NF9~i~)JnN#){U<&RHaYR&52xVB() zFh0{AZbTs&m1Py*eEyh~i=_3YYd!L}VM#_a+4p|H%YXfwbf3#+{gU(){xEsgWj`mC{!OOT5>PBIaREfA2A?v?iahWpcKL>xGWb_>pIi<-f;@iOw`Z99IZc%y)VP!Fg zJO(+Cj+T@NjQ)3+r*YOmO0&hO^uHhbl*=KSF8%{hiKwrmW_5Dnej>8=**cqrE_amw z=9OVIC_YYik~-}SHRkrWU@H=h&*h8efO(UL#r5z37(81Rc zVsp=YT(jytr$ay7X!_9;YN=&Ts_asR1+&WANTkj;3P|Km6kTYTkxuDyB?3im#Qo9K zS&~c6weu@pH}U;1rpk-WXuerDR4jpcTTcM&89}7lSQXhr9W!@N!i#Og2kK0UhM47w zn*Z;*@eef5e)<{;P_4Qa#DP&igIlyI(L81?e?Xp&k*sT8+ z2~T=%o_iG!&@3f>98o==D2I7QvrrB|1m<9pB-90n1|lj@ng@Hjc{z@8H#Y;~h&Q7V zof5*NDxJ~2fO{Z6ff*^4(jlv_e|$&+`qH4@p1YDCeE)ZbH|%weGxcDaHL6xF!tOr> z3^l`<`fW6YH8-Tn=lsvNfHw*VTx(bYHQnb8!~dMh8K0(-o;UHwI3J2(1YgBg^ZwkF zh)I5{tcPLqgA+8oN#c>6{BWBylsokOADT`{(eU{(flaP>RnsD?x#m!qNspV&C{?Lj;Zl+6rELW=H@3O7*kTRh@l~I5Gfrqy~ zE0}G(NXUM*@F8b_M}nyI2?%|6dP&3wjZq}sxHayhL|zKEYMn}ZhRuV-OcdP)i0^mG z{89ES>x-B|-mH|xYv!eGOq31?RjYW899PR4SEyZet+t{w=uyPi+qw^%AwPZjFVS$} zX5ln}IA^rIzr@2uvV`B@&Jx8YLqU;|+qwjCmy!hF$@`zk(-kY+h04I*SPrylh{wru zQgXuQEv~cfc5BAbG>DI#Soz>|xkb^ynTgIBC2r>l4+*1NO1o^K|4 z(bp~KsS%T&moG3f0%#aStx_fg!K_`DM;#9M2(H=}+JPc+OFj8gRIz+V6Z7q_2N}`w za^$}=D>0h1yRtA`kU^1!buVv3KLZx^sY#|M%Shg&Q4qe@#r2hDmhF<#?^C%ZOls{p zcTL~4cKo(W72iT8w$kFksPH_S64zxAM*1Ufg_>q*L$ZYu^g+(1Y;Rjk+-LisvV}RB z)kK4QmxkGHSzC6xl~tdo`#R&s5%E(Lv0T$Mvuwg<4&0pe)lavwL#`}gFpXZcm7 z%|1c53%~6wsl_$o(BKZjcIlUrzf>{YB-K-Qge2Y;y+LxTA6Y0*8eG{)CtsQR0aMxJ z{J6lRc#aM$t$GNxU+)szg{ze>u766c4n)$Z!es}Fzfch4!TPMH@TXnTOpr{TjO`^T zwLmmHP{>tsd#OLkqmGjZZ;rZZ=gZt>u|6gknlEXP7V(CU9!sak+l)@I^bL7?g1*1J zihbc@q3c4(5nmEdViau4#!O1a57I`Y^MY1w8j`&qKDktMiu!L6T=^_!)5L^Z;hjLV zjdkC%=ebbKMN6BzRt!9BrCqi&|8J$#%(aNs+~1;cqDlDA#1g}166KVqGqT1>HAFMu z+Jf9Ad3={sJ?{i}oJX0u+bXZ5cVVFBW#=m;udSFAHtRsnKJS$A@)7h#KOLezw^@X+ z%EA=|a0iJO?H%P#@uIavhlNBWB{5yi7yW?`7S=B=Prbwzk$!X7;ZkJjjgKR{*=)BW zV?$P38jUi4Z_9hrC9|&E0bvS$_%;`4&R9a}5EpLpL#`jQ_;hy2Pe4?z?6d=?pe5G- zTsUXTRv@PzmuMHEaJIx;wHyI{S4`wjeOhAKBuKcUffhyup63?z|JuC;1B>uC<8#7nIe``2+BD;NI3l{TD-x zL0%)S)oA9)Z5bbZXN1!>EAV8>ukepc+!K=Afb+J}!KUxXr8;ZiJRm?jz$+w&ivnw( zT=MAGsIp;yl@d5a%I;U59?)vJCMB}<;M3|%z+UxKso+>zpW~H{>`7oqiUu!Yb3t-F zys{~(TDxz*8ywu1AWD0y@ZqF~w-DzbTk(pIYxc+4^5SvrmKVC;Q5XA}hJdcEOi}nU z`XfDujVG9wGUx`-N&kH5E5l+9?xXjw2D?nM(!EvJrphLDwVi^xjlG$t=-jXg#}#_X zdRjD-I(IXg8pJrAith48>?(07C>@)*Jk{_`L=UyKhMyhYM_Ol?L2>SA`(NGe--gV?S7}o!m`TWOw#k{2M5VM>HtWXJq`mxFFUhWecfQe$db#^rgqwGfWq8xS51Rf(r0F?DnBm9@0Ne< zD2qnXcU~^{`1h{4DaK=dKfwQ~2!(Y?Ls31hZGEz0HrD;KgyiC+y}o72 zU2ogf*E`)ROrqHNsCggd-rFf4$m+SCn{Z4bMbkc6N7qPuwQ^>|>z?wMMSc;ehz-s_d^95t6izO?zFfmg8a zQ+d6smZP3Eco73FlAB9DTv-%fg08hbe+yD+`YHPERuYVGSjDzEuw1!T<#_f^u$X+V z&EF-}ABU3Zx-6BZPHoHILF;zRnDlEz^lrTN;P)Xtm2{0NT_YNQ>P4abd>YV?t+%Wm zbIRjy%G6f62bu`g~ga{bK(?yE@Zc*X=#ih#o7P`9?p zYgcH_-w0+5lhZ<`m1*vCA`?l6L^)pT#g7bxgo2S&Iejm+9Xv)zr+i-!Ez$2&Af>j8 z%~8p}h%{T)d?~$QJvs*XW*4mlA6L9_!4@oqNwYYzUmRxl93cDpi&9An@W&>B23|)W z{h1V;6qwCcl9(jX=rL70rt~pi^0Gl0;F+2jKq7RD~D}EF@ArqMuya98HYr zAO?3M``6w|_G^Am%jPH7t2Jw$E2qCUnR|XMYaZpfFZnQ&zAyO2G3R#-M%z8m{)QUI z#Ey8wX5{$Y^?}UxlKa=UL5&xiwERId-kn_9%8$9^Mf&r-30G)Qn(a}-tA?-BXo4D4 zgUr(=ZkU>UsEV14!-xr7Y(uAlS-LI(7M*&eDBb;hb;;ez{A>AmIpsT$wwR3YcN{eC z!Q!t3$wnE@J}v2PG|Qcz)9ltV7y?+k<10I6nm0sVN~bwLq33lDeR+(xs=(3Zw7|Y8 z>m9H07kgN?%-93%BQKSTO&QvM=rzxrnC7(dzN$Ns`s?p&Pf*#le=Yt*kt-O~($=lL zU78OBipK@;Z1lMKe;9u4Mwolw4DgnBqK}AHL+=#!D0Xiq)h=4Vrp%KSqMiEQ)q6Xx zmWxKnGGk~vuSXW}WAJ?&W2^rT2e$G7d&hq0?p9~}yatHyxMt)RPNz8tkNSYA%c_$x zake#FdyfQII0_(I>ev6A%;D&g^eKzC=yaspQRAF9_U)TeW_W(Ac~>hr)EEzj3X*Zs zJ@buh8qV~Cj5?nyHN~kAqg`0p$)=C9n~eCQu*Db3is*z}Sq%Osvb9G(8x9Qwuo*G* zQG-8_@7Q7?OzbaHKXtw-=>d5o!|>Rg%VE&wM>K7yf4DL%C-k=&C99&2N?=i`Yg{wm zM;=Hsk+^QqPyUKP*ZvKY3vZ9h3)6ZMQd)-YS`{;#t*xI?+yB=Bz@JD8^1pa zG_gj@r}mKfXNAfk9dP*C(=h&ud%%18{ejYSEPc9`4u5b7-IFc6RJu?lW%o*V_}k%^@uvOTZ61n4^Z*t?xnK`_PFybHZ7aB^lvh zVG}s_ zAXMFV?42BP>Q!t9bo{>g7BjxP1eouH^Y=f=3{oxHjY()%&HNnYp7b%RwMnB&Wkrdn zqJR8Xp{9iciBviJex+y4X{^g&pKO$wB@Y$^mwTn~TN)$|_J&ZA@|8UBkrk@Xe|~!!QC|O2h2;0wX4G$~JDK^yiDjgUP>4ewnz^E5%Q%83T{G zoIXW+f~?C73IzPo_F>)Ly}EvW_F=o3d;dFw59+QD#1hZDj`VmNaX(vPMBEcfo`CO? zF#{Y?Z3FAlwl|ljI*i;7LV95M0G@1TpLO^}E+!{X@XUe>KAI9pVd_ zbNGCFXOwr~?_;ccp1r|Jc@ll4G4FGJ%bd9hOs9gKe|&BrO+bj?EfG|u#kAKcuO%b8Y z(+;7un)ceNe|DkR`0rN2fv!k=g5EN#dwKo4(tb!pW@*S}Hj}Fqhc`X0!OSzX;B~ze ziKWnEShKKnG+hh$piq&j4LxJh1$i{4T&bzrH+LSZl@7~)tZ!YM&yaed`eyjtMAkgZ z3Aqu>NOVoUb<9;EtDr$v%zSgh^*2=6Elp3t?CiQm8Nn&{tX{359lk*-vnm9Axe$)B>F+VhJXR(o zm7v2s|9skP-kQ+9L%!SDuH(#Vq~>E866CU+CBjG|KN$Rct`(hsV0kXS86X;TmTJyf z@B>*|%H(f)dY;ynyILa7&o~B1zE1+1d(CwTs>yorpe&G`=YBnyMubg<{3*tEyv_VP zj*&MivkcffYbXCLL@2+mG+ej_=UOX&%Yz^Gt_N_f*-6ZOEv2cOP0<25@#pnu5D90R zSqVP2zSWJoIOjz)&2}x~s0euUYX)uKcljplgM?gizzY=CN{mn|CGiTAMz_;?eLkMq z@d8-vDILng{N~%JrF4Ojg(_VNvwb!Oa3l#4A=KJZd50dSB!abQ7J$@cB2tX{$Xo2{ zC6iSUbLTF4FmM~mI-^7#x|Kf2{AtAGeV?p3j^{7iw7kmEu|w}We}tG(QhD5SJFX?p2FJxbKlWuK{F%`?k%WR z47FNP0i#}7FYnBCSFd^*xE7*NQz(7`Q1P8Y&b6mOpAe!?(T`vE zOa|LuT149MR{40^dBhODcEYwJ8d%k{N_fgcG1DD^2!vRi=OG+t)%oUP@IG<7x&az$ws zX5mIRmaxfCA&ON|qqFow{3e{V6WH78^p%$=ou4YA@nUh?zwD|+VhZkSo zq>VsxS_N~9IXAe$p*PFfE{sO?(=uHbgDeWuJSTs3tKEZ)*VC(&ft9(*TB!<%FWrCH zk%{=mOHBZva4=v%+z5Uin+$%WL?8*I_1zl2XyAC6&^aTnW-=pl)r*8+<%Mx(SUHDB zau{;`f+U?JN5XUUZUuv!M;>})cnvu#$P!4@Ljkz5z0X6pveCoy8c13&A|jE~0nvi^ z70P{(TdG=$=u_?!J-j%6raig=V7j22WgoMV>5+P?Loj{(8_yaKQ2-zqm;xGjv8e5a z6|@ie{=YNg*Z{vgmE3TM-B`~}Ng%gX!pl6`hE)l(IL4$?N4?J&uz|`klTCRd*D@%$ z<9IUFnH_M)75Lb7*unKrci}TWG^665L$~>3i=5R(CAeD9ck|4v+>XEftCjY3B6(y^ zOJCV2uHfIOULqGi-Sj2&SD66YaycSCbpIV3%14DL;x<%+eJ&wzJiSXDO#?x5=9TI@Ewt`<)p(gUSS1 z*Si<4Jo_fqlorxBWShTf`Z626LQ23JPmiTBFGgT~ZPpd3BY?~X_>-0(E3ciOj$I=U zt0PC@bNg$mSC3V>&U{_A>D;TDM_0O1f*?)A!G}FIRS9d(_HTztFz=Ccxqa*t{e?E< z?}N&_{OdBa>HE{cj1e&W$=Vq45shF)W~`U%IT+DzV||HF$mRagXpr{JLO~>4ujk>octs)ZkE&B_3_o?j2phkV8Zc zMtexbin@A87woNfWy|4H%27W2!?Ng!(H5PDVXHqDIiqM+)XQwn9+nA5>!)Lq^|8dL zvyKRG!oD#vy}pP8#lI*Usgbu97j#F`PR7Zj%-;3FRC|1i+_ls$`ca0*QyUwY)4NIb z&LNc@H$zn9q$nR#Go&RRFl3Bt*s{;#lHj@u3*^jYn7RUXdHiqO7AGVGj#ITvpvo5J z5YoDAp;^4hrq+Z56QTlg1;^`j35~cw3=RA=uhTeLLL}X2XyV*kg+SAH28BEJ6NO-O zLZ-2vh~b&kKt$kKR~hhvx$zYpcI(`tvgHe`ske5#RRBTAK&$F9=A<1w9`lto&a}j> z>rz_6SM>nw)!PDHXY|E=*Hn$Bh@R(h;mZ`zl!&y9Nr78R;5pgto6lcv*oh=$brnAX zU)1<7VzT|w>Zw5%>U0MP>m`YrP)L7n>-f2278F|8xF1asHY-I}UK4irFaNOreYHd_ zVP0!#An(4;)&vtPlcjMin9KHe1v^x9+MNHq6cL^p`@=RkNisXYw(42duCA`iN?D** zR-WoZH6SQ7{v&!hy*9-)vq(Cd%fR+4GennsYm$(rU7d-|Sg7q;0a=8V<~%8RpV^p9 z4uBm4*+m_MB9+SFGq-x?E0&DMi9Ui^5&9`j_yUfc=cgS`N+~jHbkg7e8xQ9lbX92N z1vm6!Ee7Wns6jHx*+XmpM7JC#5A;={U|LIT0`-LWOpLkOhy$0};FLP;xFWbaWoO54 zdN@}7u5F^ig#TB@lt5&uFmn&DK(oay1>5+!Q+rb*}c6y_K(x^j}~?ZxMJ$ z#NVAN?+nWz#ue^7@Je;~lR8@X>=U~Q~pYrJW?7csEu%|g4c#N}CrwFsnV<`&^mPtHX~IB=y$$nq?T{P>0$Yo) zrOu-dFe1&d8aZ_RmYo1>l&fw9deG0s%|hC|#aN=} z7vqHp+k&FXkw#lV_x=L#|IUCl0Uj>S>&YCp#uexZt)GX9szcyYQ@=`!nGHE@SjL^- z{Xt}n(~1FJJ=pQ04`OrR<|)JF|2R4qcc%aU|9f{P6j?cioDY%HFo(h%hLOXZmBO3}8*(aQ&g7g_pWnW}zhJwr?RveQkLTllzul@`bL7p! zD2}~Z(*BCl{ny=k4E8V#no-Aav9O9$J4!gG9`#aJAE_o@0+Q&kw#OD}GEip`uemGR zggh5FEiJ&pMb@~_N9EDmB`Lo%Dm1RH%Ak3DQ1`WD?w23wVWvS6!f*ekp|!o&toyJf zocTL1Knkc5Aa1z%`y}#Z5=p&%Mxk-)KzG)iRR-2;<9H2Uop1hwXp!T@%kj7pEklj( zN|C9|&3%*r4iZV{G_X9dRBTrD0OlHCGUMA!AYHg3I$JTx_Fk*k@Gj3&+qk&{`=_m) zPjtz_*2KZWd4nvK(woI0o-yyJc+dQfljfQSOF8S0zfRPCv3q#j$vx~hy{R-){Z+}q zx{E?E?)1dThci*mJ@u%WLJF{1MzKeCok6&>T~SRzwcy3)B0{#!D7Sy|nO z*C*SbSeiJY%$z{$l0E zFxwyN6rJ^lq9e-Z!p{+E@{^7*qIw#URyA8DuZFFILRJ&1R))XK zyuAlOm}$-Jc#;qr9Ng=+=HkE#-mu7^XihTGudLju)7D)$f-KG2!2#kqjYmEcYDLL^ z12VLtvsWWbe;o0>Rng_Fob8;@W~vcc$~mk(k;)f%UG#c(e+u#LSBx#9A#~Hldn;UZ z<1Ak`KP~Cf&CDHS(hJ&Vw1Vb6l!5Hwum}?VQQ}>-TGY^?)LCt|D~#TW8c?KcK7119UOF7n_hPSax`^Kq)eVN6ZG(n1>%Rz}!h+lYMktw3hBH#(Djoyf!)koD~a9c)TA&!%~_}j1p>KZH?E0r7xC?|9>7T1ehVZ8id@N~6C z8e5S|aO^N}H)!Fdw(h;gga?thk_(nTgRULj6%oU>XXfzl1!%PG9y>Q8`lyuwkt%D7B*5-zQKKP!=bqc#x}=Wp3@hp;aT8y8eXAdkz>glODm4wa$K3Ydk?_2S4xcgDsc3=N)MoTM= ze;Uku=b3hlwSfNoSIAeCcSw?HZ1N5+K&-F#8%ul|QACeCe$2r(4e0;&P1NFKlVPP7 znf%n#j9a3bc8C&>b0QBM|IGD(8iv=O_MR~UM1Q!;H?oKpp(4DVw00}KcB*Ytoo=)aysU!rRj_CzaKC4XV;s(Om*A(-YR2%M)jMe-y;d zpXW;HX3el(*-5kd=y~;pjQEOOqdp_Uu=bUi)zmx)dXw6`Zchs&3Bg20yke*#{Ij@f!H_P%d3|uAlr2MU-S|wQWx&% zoW63d*mfomR+~|;f}$rLAXC&LhiLAmuBF9a#?dfLtk!{!+zPO5aoe|_e0!4@_#ncq zp2Gy6?q%b;q}NB3^A*mQ*N-FycmIsYS5NRghCB@CqH>*iQkj zih{&zNmkgk&lCOzQi!&G#Uc1gb(+P{(I9sVeAJlm!(2tb&o_>h!&Y`1i{@Q>Wo~5n zUbYB4UfP(g7kJT+@i4Vbzo$<$F6JZlmyZa(CTS5;0=zgG2_3-?a3~Fs!2B0s9xUj# z3n*z$>b+;F%!DRZ5n7Uq!!g-_5Bpz~rgjNN<%#=h^2!ExPoe4PbLf zELP+D_#HU9b@XLB-Xg3EQ!TW7!%Cl6$L|jSXUTp4!E^Hm^(m`Ovv~5Tcq2LmhMhCx zhOxbs0)VXYU7=5o2!~0@%5z&t-koyv3ZRl5QRWtVV4DgpQ%)`FvRa92aqTk0dmZpY z=W#DVO)C{80#zgJlayEB#3?++{n|dpNkbq)*-}nX%7e_VZi6g5Ff0yr4{msAQD@|; zYFpKj=YFJ;9GRBdI!G{6eA3^xX+y8QEfe6yRfYC|5mt5;^C@X!f{HYr2Dkr)JZrIR zK9f<3%J=2-s}cwfbbb}Mn~0IVAzq{7TR3$9W2kr$(Zb(eY*u}(k2)Ervrzc1c@m_P zE>-t9;?WA+ajpb;z$F*`NK`YRyl~Hl)7PtvK@YAPepWWjR~%rzCv130pmFP{J+;HR zK#*f7m5(DH&gg=cimHl}L>H%oref6ddNJzJb+?eeC$9R@84fB1ZZ5X!;_`QX$v#Z$W{Q}FxCpzLcb1Lh>-qX!Pbur>zW0LP@s zK%+}B#JPf*ix%0aFSRd&&!fii3Pc%v=HBA7ZS|$axYf{*zZtKWFtODeOJaVbj@m7i z9o~_d!5fB0HAU+X3*kjX!7DXFstJcxX3qSt;73=uaMg7Kld8SK zA6{Ow$du??+6XqRz1#Pa1tIqjxyl0HP|8HdEWMHZcSpB;gsIxCEjwKQ_C+NGJ5~76 z~Q5_I$WSvV$@`q3Pu?4DH{tY4&1j-^YZDId9yJ zIHT@rF_ujSywP3T#b-1=C$AkMkF>^{G?exsFSMG{$*0g?vZ?LpS*jCH8T;jZ1&=c5i-tVKEc*r6E4O5 zMt6$Dfuwiea(SpbJ!VqKkri7M(X9B(pZiO+6yPQE1#;`cJp+p)^6ps8j-X)Tr;pyj zAB6W_aZtXdJqx8chbPxaXgfTu)-;P+i_GTd1Gg!MBn|z#SXnXt4m#sFQ7Gr8Y1>w$ zB5WvP9#`D_u_>YLwB@O036HTpUkwLHa2}W&y!6oA6c=yY>%o6NSo=ArT%Z7P4pAe) zf^{LoT;PJzpSsUBq0|J*gjQWT4bhdl=poO+Vb{kGzsp9 zE!6+~DV6>f7dDovK%c5u0)-Zy>S63!OL6V4)g=!?B%vQlHD`>H>TXv1^byGnyh!TZ zlntC3F&8>|-O+j)$^&TWxtCa0?r`@_nheXoL5VvEp6-o88J_x?@9s1;YXc-3axi$j z?9QI!c`Ef&7dxA^$JnbPBmN8fa2@|;chnenKc+wL54JqKYhto%yl2)Sp;L&qCU?7c zfJRp1uSdQ&Wo(4uy$|3x1n&WO-{Ga*Bx9BPnlZy3)v3x_?;P>$Xg?&6O6Rk0gt+lI;hufE z+Z$|CsSzP-Z!gIRa5;{b81C=q8zfc9>nG1N7PoV<3v?LUXico{arwz!8kIJ(%%0L@ zA+l(1@V|edgimuQW@o!|z;5C;0pvgKW~CF1VOY5$m%gg?8n3t(iSYV56n)OGku3dj z*9@*xnIm!?r>}#?Qap&P#2LX;yDT{-{PDmGiym3mwN27cm4jt{e$#KTmzHCr+TS0c^(8S zDdsOO6dtGx)Q2^`I0h1;@(!ZQTUOZerSq3Xc3E1uC!XzrJtPCEf7iN5Iy8TRVmCSh zV7$}Am-qiuAKWwXnM$$toTI?1wokyG2cZSY0``=lxi93Nz>00B+nJ>*`$rQ7C1dm@ z$^AaO!}L77J=Sp*&|Z)r|0c<)2xlHSp+_o!vlSUSeO~ctaXTr$)*#?-z+BO!hwD`4 z1ueL zn4Bk#o98BnfEgeGo4s1zIv?}yYC_Al5XI*XMwsi2M!2N|NMes zL#Stx*SEyCu%5B3#Dj6iDwa!G?ecG|J-A(Lg+8F1nHjj7V%m)>V+mnYB+TINMHQE) zH*K0H_5+J528$C`{Xlox;jFwSDcOWGz>tJ+Sr)d*DmPFzi2G9t#=lQBNPi%;>)l|^ z50`ve4sl+H=Tco>!~No0LukI-xb0YzOS!;L^yU^1DS;-%vKwxu6XI_$t&Lml(+M&k zQkAcXa7a=yl|Erio3NWFtK9R>`MkXtSdv1=>aJCMpNmsadEh`IGoWoEcGP%GBX2)B zo>l)|&bIB4VQ%hZI)U(lQ{6gAOu3tubYU)(;A8aNiY|gp8Vns)czYRd>zP*+Q9upg za!SQrZHe&-HgqgBzCyY3E+ZksN+Q;#glczKlZ)MndF8VKMKsCgeW|~>#^$;lBFX;W z^mkdUCzuMd*nT%&2DBwjg%0GAAqEg!5{<)WW8j*swVTZQGk180PwMjmrs6#ErM}6P zWnXuzjAv1hlQ{5-?2LmlDIPY}(6B$nOz9DY{eKw)!7%hW98RASeJHIabu{_UH^DR((?>rhr)HS7=h>#H*A{vIt- zq-0|6ro8lC`?U7oD2}YV7WwIPjPuf;CMH@~)>CNJiiqJOtWp6s2fR?P%*B6LveGK+ z7{;{!!51I-Ssm|wz!rE}xN;O(iN6a3Dz z1BS+ntjgs@W9A2{cR|n}cq#<~!Z(hc*W1b-U;3O-IV>sD6Q*mMv^t`KG2d=uDYNe@ z928+mo4+nkvf*Kq!SpNmo7v!FR!LGy#@;XbNB%4M_Akgjn0G&c&Yw_b!+9u*62~qV zNDp*>dS+9J5{6ulV`nou7dMA0-+7eP>YVa5C!FhRRV=p))U}KVbv4}t@wfDBNgmj~5xHED?m{L}^xZ7nh;CQ1+Ipasz$% zDhV>C9!PB|O$pN-|8S!Ggk8beybd?|v?QS}9eL4+)zo3xO3$?)Ta|3WQ~ktod19yi z(NkVOTlhw@k%5F@T^Xb>IU*|b=^aId(uXDHOES0t2=41wZi>Q+!9prg^upz8d~Y|0 zaNyAz1K${-TEU5}esd!n%h8=sw;OG+`x!rDbH;xd`0u#XX`wzy;tFs5N_$(_r)r}S zh?aDS3!wZ?_R+A6;SbbMt!6L78IRCr=bre2Oo{K?X{`B1B>BVabuqR>IgF(1>v$Ts z)Ntq|o$F=nOo!%!&(S+dzvB5$tTODCW(g#W14F2l+6w+K@ks6*G|H}>4daNrLmK%t zIxmX)-rHr1HxDIG8QK8CboO6sWr^s%v%qs1~jm_emoO?F53kX4uB}VVb~4MT|S2& zuqCl;ueH<&i-%o{qyGF?R06nz8;#f$z%X{3#m;lS4PI?M-Ggc>M&Mti3uv{4di zX5Pfi`^36rz~Lk(x8fU9)p=WB406Iy7r#uBDM(=Fbu>X3d7japu}S5gA1p6B52r@Rmw|}lyB)BoM}qFKgrlfDYHA1}w1R$O8sSdxayB*(lo4Kp zJxZun&&{8XVIlc`s>inkoK^o08`xExM@2tlpLyC;;t{{_6`tArY<B^ah~HsU-&$D2%ME!Y`G%&O;~l^?j#f3#!qsA+}DsC#FkIiz-NmqRsIR5Py1o% zwe)3mF*B(C+8@L8ADlLWem0MPZF*B%dLgfhoKfpyT))N~ml}VicD^h4*tb6;dJD<0axDv-PMgUSIV;OR5r@Ia z8n{L}X=Y(dHF8pM1((w=d7#%W-h@Gt`M-dKdP4qy6zOjy=Y1+7dOQ}qPetEV!?8PI zVrl!m$8@>iGKV!WYU8D z6CTgFMD2;x=-zuab`>VS2ET9nCeNA+bo|=+zE$Std6ND#TU7p!3sl96k@}D3h0?el zgy9R*mVp+ZeJ$7y#|j*2&1C(6qqqh%+QWP$zCi6kO36dgBspn>T6Ad&$Y)2}uZy7M zJ~R+bVE~~F4ZsKa}1*U_pt)NILW4y z&j*~GtN>{+8#ED$w5h3mp>7-P8ouLvL}~S1H*?5JEv%rgToiCM43)T?0bOdJA3?xF z+qlg!>T_Pj)^XoorX#BJ5qUO}DGs%pkg7FWyVp?AK>q8vYsNBU&9|4jPlCo-FwEl)Ap(i9V+C{Y|ipy>A z#;O7*9TPIQwFXxT+y{mjgZN!&sJ6BV8bfs^Okn%`-OA`ZNglSt@H?YwdHuiR$1jCy zjk$*}t=p`AuwEvc5~PEWl5-n-<(=^U4^x(hk#r)Y*H7BqbSSr*I{>%dU#*iH!ZZ+~w+A(X9Jr4e(FXtkQr zjk~5FyUb0Z_x0`b2(UPQT8&iLHn1T~EsrcS6!#VmHdoMlCbS^-i@@E(sVZFFi^DCO z9#!l+M1n;TJOGa-o@MI?-YkKYc7MdjPLeqH9*!#0sh8$ng5;w#>e}%y=F>nwEc?sz z0*9>_eveXHd_<`#tm3y`6I-i(mDnxInY>~>WVmmNsb}iexo=_j#*4q=V-VRP&u;HP zNDga;Wji(on7qAP;u%Jt{}AmXQwpq+*a|&KYCAf|@2kVk1oY#!i_oL~|y)hb>9sXGmb#Z+!2E zFM0td-b9lu%fckObYo6aIlLyyqaL+_HD69_m-$0e=vC$10sj9S%gSL5t-j0n>DpFSX41Oh4-)5hHEym# zC917+rs_YgJKU=8&PB4M9Tz-mJ`6dVkzi{a;OBh zF}VXNt&u#Sgc^U$ocBybJu0~_*z8uhI?!z>WWSK@7k>)eZuf;F2BdgPvND20&9l6E zht~WEq+qPQr%OKqBVqLtlLp)6v{491pEtUPXCW%%g_K_day5$NT0AULGZUryl{d2$ zI$}KeioqH+tWKP$?SYi^C%49Ta(%16L6Nbpb``}N2Bnd+%GaV|yF&p|YY1a9!PT)# z>x~!Jo2t4%TG!C}KyMlMnfE-aUkr6cAn^|f*}F5geFiwPJ5sI!&L*51a!N zQIvyj%QU^RY1!{mhDNS%2wi{=tQO^%l8&J$9d#Jr;Jz@Fk2yrVGZdn<+@C z0Sunx@N<}Bw4JEewgK}xT2fc8_5*Sn!npSjdbD|h7h*Gd0{h1*KF?LXiIcJGTg67k zzJ4w(&GRHs2?a@s<$;6SQP!szc*X|%Ys8-8ewNgf`M6N}=F>gvsHQyms?(O_(+JD2 z-|cT*fZ80D(q~bWAeCYnF1C_xP$VPX5ZT_?>t0%yyc9a1K;jc|9qs0j@6CZ_s@JK_ zIJd4-TUMaOl6*I9*9>^#y$xK_ynyrOwweQ&An}{m2NY07A>nRjJ&x$$W2 z9vlHSfYbJIoV@|IN=_-D02)nM+Wx-7^d>|e{@CgMxgzKzgY}?_L_80psXPA3k+nZ? z)_1^NJ2Mgts_+If-`XYn@i+vlS+(Ak{cR|(uiC@fCEWOIZ**_~B$vzorkQ1!s;Qk$ z910zU#1zYMPxT%5H}>wj7@Sf|qyv0u7Auy#y@Cc~p^f)QquZfXC~gO3=c zS7Sx(qfo2zJahGiQ+LOd9kt8ic?(v1_%FS7IIjjs@NM16amoIwQ)6!H8klj~CCjc$ z@529K)qLd#GA(qdw%<7xDi7%aNik5!M@_o?~k-=5-sTY@7b zpQguN8lH}}cSW|ou8$B9R$pf7sj-i770b45t>jPxTg{oY6;TiS%dq(Ev-40|pLw?n zuTo#xU33SV4&nC=vB9HxNN;514F`i_1*~-vbXh>j+ys3HoG>R2tBdYAzJ=w>1uwMz z5J8o2>ZJiSrTlT^o#25rD;_S&U3C^_Qw#YMF2*>_b@8th`N8#zJVd6V7piaT%9l|H zVX^41$LF8MezC^Xd%obWdfs8a(men0Ty+Fc^a*<$!&lOH+p-TtQezQye}7nFx&3*G zQ1mzcjmA=A)i%Q~MjkVlV2jLW_Q)4@8bVxk+GEj0pSOXQ7jsJLP|H&UVUs0o7_63O zwcQTz2V=gij?v(nPk>LL=tFntp(}DptR#6`jVHGR0cvIysxg22IXqPR z&id7imI~{KIJ2Bs%q?Omd4OHIB^x>C_D!#2qpB6Zvr?&M*xYRg6uZ1@L!gPwo@^8= zdYtQ^*HyG@J=u6B$`UAeP#sCW8}PbtSVUm+ak_J|wMR#D_Rpg(^%RH}D#VQ`WhNqG znuh#l(RzMo9PJK}*1uUiUi~|>xzy--L0qOa>vIJ8!yUqj@>cy%MqgB<*^#A8({#8QlCB))mw)k9UVgMqleUflUja|hqhvH|y5_c6JNal)`;7zbBdBuO8an(h#(!SW6it?cW}&_`a48cB5>LWYJJ?a^DRwW`rtU$}u-Q zQ%^^#dvNz6y&JxMtDt3vK)U3V^xUMljT_u*{l6L7@QcCBfX~~UI2b+YVplSXV?52C zQpv!==NvFEgZ|EBUiBV@zir_3eLsm2P_W)r=1}WQ$txU+=gmuRu@09sjz}rc1n`U8 z#XYc93GesK{-vpmQ3+$A)sDHD*G@L9BkNgcE0Xx*$Pl5_baK_+$S4Rl>1+Yy*AQbD1sJhq=QZ@{29{hf_5GH-loln0j$|Q z^5-v0{g#xA0Sq9KqIx|`g#z8vjwso^9n##*At$}pCaHZCd3daiBt#IPnV#6?agn?q zz#7Y@R;T(bEx3`Z>=!Gwm7P9fu&V>c{)E?3HV+CZWpFOl2dJNa^&oURCB&=We%ALI z8v1Lv>wFRUyCb*n>(%l1-6AzCr=}6#y=Q%3X#KXLse(hymH~|24po5jWS)^DgTus& z=(0WKuLL8j#MaYd7M;L3z0&SUA%y79rO?YbV3oVqoj@%gW~Lv?r*Yly=MvTFCFy^p zmwDA16tP-Av{$Y7XT>V~9)P_9I_xX5FvzmAw%lV@o=egWiP^-Z|ND3C8YgJ|ZOE;Y z&OtdhR~sETZoeuX;5)|qX5CS5lvYcQh*-92q3JyetVj<}j$}#o_Tzt`QX=!FGGFJo z>?*V>#8V>p4~>J7gc>f994i}0cJR9s^a2+qdsm7wvz4qgO085P94%9qB)rm-Nh@c#+B{YO!O`i=LX&=_M^y1 z`TKF+bY6-*c?LF|S`ZKwil#}Mt$8b9O`sWRf$;A-Lc<~Y3ld@$p>qi__l8#iSry@- z1auvWQljm;HnozjmU|}CCT0F-yA0;&&n@eyPJw#W4D)!xd47#b9K?-SWX~db>{b=h*DN2kMKV z$w4J~ul$ebu9X7E4mvwS|6|(bvA8e}63t@0ZhN@_+n`mgf1~fZK`K3P31#{QEw@==}W9c%9S|s`ZlK0xhM{C~=UbgE>$Qc>RqsF6nZ% zw4Ue@uqAPAz8(V=YQaRZz#U7Gsfza;zDe=H%Ct=fKan)Y1|^&8;&27oHUq-qDcOV5lSsL1 z4jgsQ!>t)Wn4)?N@wSR0$XL4{!oS<#?`8s+^%6E#YtiY-xmif{L^F_CY}N$=;gTrhk`w^?5US3S0EoqfQa9`E>Ua z7AEze#&}V|wuje@47tS%M6DKxiZBsRx6jmjl9yTF#)j5!hE>lsR4Lc}!Ps6oP?Dyp zx%xWH^!lrEZN6z=|jp7{H+;!%TDf2s;P&6h;W$LasgKrAeGTmn&I_Jg3yy!5uB}25OOQFU;Io z(WG=5?TKw*dA64uTu~9!TE7E4at0&^8<$DVnx`s2ouX?`VHJaZc#;l4xQGD+<5A%$A0=OVn9{8%Z-FPyIbT=}^^$P2 z1L5^88Z&(};kba#)fl%CzpdWeE|xL>V;U&TeQc@ym$Tf|+i|pY66VZBFN~W+^xxNV zU0xNbQ?PamhV+^y>;54V5l@s(5Z;}Om09+^q8M1g z14VSI0(eKpd58PP71ojfb|^fJ{htqLNer*TU|3KZgyZhoIw_~{jz7ICR_BItpM*z{ zPR*Yo3@eUni6c^j`yo{V=!x7MPW^}m#udkVDzoZvh%N&UXY4`D9v0B5%%8ez#A;Yk zDd3$EpLI9I`7i9IaP5)W$tBp{W>l--qelz%YG)L&q~6G?UJ2BJcvMK{tK%n1a)_#* z8|S#rJ1qVadBgp8qPzk9Uxty|pbKL1G4oE+pVFM@0o%z4xr%7 z!aGby0B47XbG#CKa6J##2X#X9;%u((kbNM8?je=d7f2yG+a>S_zt8gzvkH?ZJMc$u zkh9+#cO{%dPZinCG@a6(ZTptE zUFP^U!wS0Vll-jvrMRBHa?!qpIKhE z2LMNvnUy$IkHO4>n9a#+6zBCHlW*u!=7141FDG?zM!w6lVW@48$_U;A^FxWfzcrkSK@=h!eW`|;;js+<2vTy!|NLHQ`I z0J);G?O-6+t65O&`GVtsr7|!#xCPEz8-y{SYesiY*ckb`7J+R3jvv)>1KgB<)S^EK zt6kc`(vn*-rdO}C{&z%t4V&cS?yJ2T2E4=b9Yvn*c4I5!>SaP+yr_o|(v&Y3O%33w zS`kRV2w_<8-rV0=hSn0No`iF)eX<(9kSQF^`qEam`p?G?GIm?R)Kmqc$KCs?{Q%b( zEuQ=TIY|YBtVVH*GW?^7A%r{GvdDS|*@iYt+nl7-yVX&4#wpfY+EP;`_9#8g40{8R zzTu!t)2%D&lj1efAC{!7J+ni1xyO66)*&-K!y0aYZpO_86?^LHxBh`Q?7zmzbZ;}x zMMP`s@g|ZI~lk~i5em-!ERxo6@Je3Ra zN49K%%Xow8n3z==we9tiWvFm_{RzsOdBa|K!b+ zm5L;QKVPU_%8uTyx#G%Y0araLmLbh998&r_VLLqJHP~m{{N9#d)@xxcXy7BV9tRYG zhvu2yw)ialO&LM16pu2qGVx6ii`g6{np^)}j^dJ`R7H4dPjo{lvtmo+tmycF|Y~=Grxy73xYVIwdEf7C1 z%Ff&aqN=~n^3)^(9gA9kXT_y zPR85asO_bb0%lNJlQ3ZO`dk_X#JDG2;?ttvv^)AB-V49O!_v}Df9tXsrjj{ z$y!&OBObrRd*9*|#0q|Xf5K=a;;-_oXdsM7b>^Cdn@T_}qp&8q#EzTEydkh!f%KQj zWZKqNpmD7y8<6XX*kf{?{xWKYLv2;twbNQ>JXf~cP#)G0rjYyJmqnSIe(@K^k+ar$(hc9zilL z!(Nph65QQi8paiMdf*Or7tSi3xEP%Ba>qE}8+c=<$w~UAp|9&y# ze&Ohq{UJuGSLA?qg)I6cP(S=v_F3=Pla-y~o5%7b>&^bkJ%N=6uhN-W-gj0PcRhU@ z0-b)IxIzKVdD$cGc<-~_9bsruzNUT(Uj0Wy(T{YBw<~&Ig2Vj!9P6`dd4MJU-IIqS z>SMKXL6gO}1bG>&D?9T1=fTE>%~jvJ5u9yhCl&2|EKBt{W7iUUsNeaQp|`2$B>I4# zpc2H_86uE#``)gEAp6^oc>YrxzPD&~{r?E|uY$+m@kIiSR(*k7v~1b|qyw^q7* zgsb)pKiAx3D4WyRi*Em_fZ+FsG7H`AO3cs2EyQ7qvB2(($+B^8>YRIKDau}aS6>~&&CRpNx}iUsWL^SP6V6K1!y;yVrZAZ8H? zf-<&6A8vfc251?V?&v;`fXXhLWR~eyp#GoeS0`;%?sqsdB7A&MizvLa9+e z0Zp^?!$b?;!@-#%_g)PdZOG1r=;m`pVIr{*M_qZH0qPqiV%hD_`sHPeX%o(O%&$gr z6DcTB9J((hae-PYxqNoi;5!ll!q#XN9rjqYj6?KCW^&|Q84?x|@E03w8aX~hPMN-o zTB;N<18*!=NEdA0{MN0{J{d4l^A+(aJDSF|@lAKrr6m+dA_Fi;-l~$Bk5*1#41M6O z-_0HG2|wI)4B)pC(4kJ6Uh! zg-T|+G>@uPUR6D+?i*P<*Z@1h&eOJTh@}#JV`&SYSBb*ABSJ@m_UKD|1rJ7{?PUa;C;>i zzBSEa>5|AUjfc!!ZGP)PvS|rp6__fwEaMRz7(vW3U|LD`;*FlE2RUTv*`mK4$}|;do1?D9>CPclEr5Ba*79mw(Yuzv5K@1J04xcI$avk0Cx%YSRIkXI=>B zwlUzcek*;r>7Z}VKb|GOU_^Y^G>4=z56;yhC5^TrihxZUPGP;-kEo(FfhBCywFaP@ zC?gD3X!9My{9js1X=&3OrTTvJ8!%=5A@Sz?Ow)=2Hp#V7WTC3}=BHsFMhPkS0#1&0 zNRrw@6C{~JxX^|GLW8L9Q?W?uhsc3^DFa(}=MpyaX=75XV`fL$sRLuWa4p^`NMVnh zUI`WdFWZKTBGW@`Ib@u-6EsAjy9wV`&jYQWDcuEihPC?o?!{U;+ZkJ7oQG_dq7Mnh zmc7k!?qOgsh5tS<<5x=dfShET$ zbU>vZ@FCv_zdV7rr)BhT^4sSUb@u7+L&cc*@rzZF;bC55j_HxN_vSq5qp-{?;@IdS ztejL-E%hU#eMP0sngKxKts>^Dw~Z&Ko9~Jw!FhO9dyQx2%2&~Zfu>vFii~Ec+4fiL zioP2JGZwy z80Rk&U3mi^5^ocH(&W*937l%fw#_e~iYjHYrj=`t2`BIolaJsjp+TqnOD3RhKnHYj03`E%xb>vX^#Pt%mMe_X8Ihi~+`ZjTn^>Qm;vB7aS<5 zOQHLmi?6l|4)%_Otf21>Z?duYOxunA`_QWam9Ws$-64EBR$k!cGmF{n{ivoH3E=)GoJm~E&|)1Mmv zuZW+?W8Gzq0O)eXi+%&H8xFeG$!SkeQ7MOL%0%>1!|-M1iI&oSRe!8g2KV%tp&ZE9S8(?d$>TxDYCOXl z@;s5Tf*gLq#M4#gH%I1h`XO2b9z)&egp9%A2?7C>m_taLn`$t@a70dvtgwyVR z332Np*~fX8a$h1vQ54GtiEP_-?NPDSR^2N9V+vn-Px?8x_Sxhlam7CzyJsF}U#teI zk-qu_(s~Z_D%m8&3dF zJ)x7!$T%xhLXp89;1Zo89WJZcbrP)S7G&;N{*m=6?+Vego#P&Cc2V`8xXY%1h#^<} zb9{@Ri5-4N_x^2iS7POu0EIoC>>Hneex_Pf(CsSN4y4tO<3!T(VqyFzU+Vq*myz%U*0X__hfYJ z2t^L%neiV(40%rIj2u`-&4I3&;$82|qv~0t^ZtWT#1*p?RNyKuZ6pWJu&~=5M(jKlN9_?y3x_--A(9(sUH}w5)m6vHgzBfqqzeYs z!fBI+AJ=-EBgiU?8jk6nkV)sL;8~ivZ0&i)F|~= zYE|j3nOz{aFuDCfAQ4%?#`RCsEOgkc;LYN=XtG&|h{=slX&sddU6tLx{^+&9xqoM3 z-8?lA?DTV~oh4AsI`#KQYDGry*(?1dnfnsx@v;^h46?BKxHQG?kG_4(X7bo2S%3gL@)jVB2Ez*Q7^|AUvfGTAN;Aeo30T~qe|a01lI7oc&`J2{a%kbKnq7%DEDK&sRrK$ zNKaO#pKZWrgh^HOkLobiggi%fWTz}?sW{&vUGH9bzqjC#K=rpf9H~u1f48cAIak-1 z?DJKREbQZRwhi3|&CB{B{G6gD0$tFvmpQ)oR$PQ`+VsP+qa#bM4RTreD`Ddl5q%9Q zUIPIs>>Ow!ejuaEoHmb4Q^ntu46X#?ry7+-Tbjd@mofTK;TLggA0?BRy`@?fuVZTi z)L*}>?Y5Fc%z6HN3z#@lR5n_F?8SRn<@*?wEb%ZF$J$a^UVjBLeDrIV=;nTNN?x*| z@1?<1yHHMMYUPKXnF;3H*dIB?;g7-9`R3nVfX@g}n__QJb#{=drRr5bLgFz1wOJpB zAlwhY-Ny#KS;!Rx;hl>PXH4v(h4C#pN{)*B0<~|PeDW-|L96T=j@n#OnV5jN0kpPZ zrYl-7|18z$|Hn`LNSNZ)+_GsRx%FOZN4l*N`o{j_#Kluo8dN>%(r*-LDee(t(Wc&6 z)kxNkPNwbH8(P|!_MsX>*6R9f8l{d$r}K2ol}E0Uu$OC@`QZuS5y*VNCcLBtL8H3X|H$cN&0q{8XS z)%LMx;EZ5-WoG}In2LEW=)Yd2lZ$pHL83plA~dF(eJkqKA+(E6bshE)-O>R0AguY( z`GIlrf?d0DAWn)`OfMSKlFe7Qwc4@%8oTrx7qEkFV%CjOR#5R0ghdt2)zi*8uq2S$ zEO=dBzFat6dFKd+Gke5(a+WDUi%fZXD{|i#d6@;CEQuvpD0TfH+QsN{Nl%HAP9YxX zAm;cVsu;mp5yO``DTZizppz87HjLC6$@*O^Nn{oHWdM;1Us1+q0Bc4O>#eJvqDmPR zXRc^a|Ht-FR)zja;CE#LtWvG8cP&gpSB@N9{3ZJpC_0BA6+a>fCQG!2Yxuu#;zp5=YTlh2gs9Ip$hZc+!%GJl27? zeEQrTJTa8f?M(rtgh4gm6$BZzr9o&i z*@ZpB-ue7z-X~w@dMdF(`tl9ZF~1_)bXR@#Sm~y23KZ zDe_fEXaxQk+d5Vwp zR%IKd7}TUo=)};eh}4UyY}CC+7ZpQn;*|SPm2%G%MYR=8)zUg7{sPNkbsxUwCcE4I z^kNIvm9sAilHb9i`b8tHIG2AxMOKrxJ1}JW8r8Tw3d| zhGGa_H$y-w>Pf*8>7Qj!uvNzox#<#h6yD90nDvUZ`8_UV8+)A;!SLy zC;SvAuiZoz5Dy}{1kZ511*i!(9B>Zb!8A8Qf0q_J}T{1PFYIk0pJ z@xDL^>7s>9`)ShL&S9;E^R}4gEMC3I@Z+*pdT)+f_ps1S1_nAQC{upXDUB9*l$jk~ zR9@owchGZtJBqFP7UpS1yN;n1>D>T<06?F@5xQ62sSwsvJ5v(C-#yBn+=B9f%Rn2b zhxQKzMX4LL&wfC^hrJBL@*n2k{t$p#Ino=Ww5pacS^vIK(LN^{J@zx@ zSJ4kM&$%46^ksig&5Wk$-c-IlWP`0USnWV3CN!ITOrHjN0TuT-x3U+KBQwoCamdoX`p z6{S@$d-lMdx3oDIld!vYUR434F%Q7Fe2&uerxRhZF); zZ6@%O&mW98XX;K6vMlWjs+)-dx%G-JR(vVSP8OcCtgHQ2kUpTjp~zDcy))S6??VJ=cuLy z5zKhHKuversS3aHcg03QGU^v%;M&P^ngj!+wB%#QVDTy9N6y;1hU)a~f*%SF8H@28 zzAv}=AbRH)ZMjKo!bl?rMA zut-bw+7=QY#th3Ypx(^j!3^;ZN-)zUvI8}q+2246xGqneSdTJA0W8o|)$3VK2+1j! zwp?1fafd#rR+lQ8yexj^`iEZ9JWsbQNW!{iDlImqS+2NzI_s9JK^y=plM>J(q*?6& zd!Prm+#Rvc#_xc?W)stu z?jXv1V&^&%09z>KyU>KONEC(UxDv$&cxW}o!_+U-8PipsU*

NHVUUs*|%KhVr%CS#;T@l@7-RH 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/button.png b/data/skins/cartoon-ocean/button.png new file mode 100644 index 0000000000000000000000000000000000000000..8fff3b662388537d4fe7e7480cba09ab4d811a8b GIT binary patch literal 3150 zcmdT``9IX%7eA&E4YDr{MMy)DJw)~`*~X|;kL*U-O=SxWO?JtWHAC6=(1V0*F~|@t zLs6PSS_l>O_~-gDpgyx-^Cd(ICx&c@1=3xmY~0GGL$5gvf06R`u> zw;}UIZ1g^4L3`?3>I2lLaQt#+MfMV|W_U}0P#J)z7=U#Iikd^b6#*8U0JO3Ig#Ghc zZM6YVc$?z{V@PO0eExq13kdH8!*gKf4mu}6(-u^Z!68F9a1{1y09FRj+kuS(tbL*U zCER-h^>3hd8fsp{-Ep}61afGQ*$b(ikk|^>?m=WFgxmqwSP++oV?=0TV)|Ek2G@4d z);I=M*&na4_I*S3E<^VcbbWdvI+>{|a<|hPIFJ_j_oZg{mp2oP^Tn zP&f*XWC$&W`%DNgh5ee)wg5LDftDQVbkMklFz@{*d?pc(D*u583^2i3(mf;Cw1X*Fr=E5H7;yBDm2G*PGzZQ=l}!)f$Mb zfGcGXRtmv)ASiEhb92?}iZ9Ynnk2lH9k3rQn*9FHT$B_mi}t|s#_z>CLvEqfi9poM z``BH{d=}*yOxx%^Bi$OOzHs8)52?3>ir)9mb8I;*#Fc`Gu((*58uhwz9Jq{Z*huD< z#%xRu7B)^H5%C-y0QN?6BYi?J<5S-J89P&fK79!}9M!uB7ypbaU|LRy#TbWGlJu>9 zi{Tv?)${R@r?Q_P#|Q;fS`e#wXPZxA6o?zwSDy?$WS5y5*qti2`s?V2?km9snjeP3 z-tWWVf^E!*SirAWLPD_X#Lx z#zl7}vF532(5GWXcz@bg)kme38a0S3n4eqcQl=ktcXM+)Xg6@z&GueH!>!tW=T;-j z-4_lz1!6kbYKDe4gys(~YgUHVGZNa`v@0iCJ%)40a~pRh!)&bBi4= z`fQ~2bf34uJt~C~Q!nmY<)^X!6F1i(S8?!lMfwjL_tlLGv2TU(^*E2Z+uFUPxSf_N zmt4u7%h;T>GeOv9atYz(iN$J6M)7sI%5{SKrYXJ`9siB9wos}>behTU>E%0D*id}c z=4;)pgQnpFW7QZx`7h=8PqS5v+sfj1v5fqtT_A?XQz?B(@6=YpT@CFbWpQ_CR(|&C zVfh)>X9ZQp^M~H6k!WtNDjt1hgtcytjtSLWa=22Of_TOF51ZbySCOe2IfoRSyEuh@ z6uxQLe_o9s>yE*$W!z5cJtL@MDB_Yhb~7w4SIHcu;;|^^OY}VFOT-KQVm3Zo4BIW} zXMglF4+VF!#_{Q}2vVaXF`|rH5hpJY?VheK{|+Vqb*edg;5S_fWq3rJBFeDvop3Bg zWinaUCwb#1E`CJS76v5^XT^qehj0xyzATTLz)7%+RY&H1P$Na;1@I?Mytco)IdGmh zU#}ObWnhc(-R$N1G}?gn7?Sqw6Ps#`e?}jhc=26=Iu&qoDIdRp(&w7s`sB`9MajGq z#bdK@R`kRVFXEwh7LNok&l|rD6;;>g(a1}3Xro}bJ{h+b=3D1duS8OHcNgNmYqu6Y zG;<=BUPB5La6euB5#!&OHL4#eYX-Jl`P5yERjwE4N7SkP2vL#XL_9P@S);M31!u5D zF2xjcSr8Ywr-iR-@~4KVr(klm?V>I$H|!~qXNibpTA;qJ==NkGdp!hGxah1`V1Hxl80j&(r{FkUy&&+B3_EJQip+zc z>n|m!BXaDBtGiMg-6(4!!z4$j|1s_f*DmuojmX`_EBI*i>P6{PO8nu>{EG!=T!+XL zNO-Sq8Fu)m%0P~JGsRL-52xeb_RcO5dF$F`@zmQ`uTyG{&t5f0Zcb&8$zd7t@>Zo! z`*NxC>4V=+dy~bDruiJsohXxhWosN-6hB^Z?A`fGVZM$LOABkWA8JJ(v@#|qr){h% zNG(}p~1s@B=%f(#5!| z{|pWi-Ojs+G`p_ow_SO2)4ZiB2z^>;ns2o_wZ)adZ6?XG|IlTmR~Aq;qfyqJHX*a~ zq=)Lcf#soNU)08jdL(p$BQx6q(sDiQ6dbNS`)8tms^@F5x!ZBuu!c=pVISG7_Cl+> zsc~^EDWlhI$3L$fVcs*VE&MK5_1ZsaXy@w!dJm)*)tt=PC3U>zu9q5VmQoZtP3M0) zI=Yk|WdA|;omAkeuSasEtgw!3R)fpW^7d27oEp!YvrX(2`cMmM0xYx{^FEZ!&WX>< z?8hbT5?L1`W)eE3<@6<-el*%>lcVBtBzY8Znz9pobG1h6(t&wqojr}cOJx#-gLhnw zP}{GKIOfIM3*eUa1{knJcRjsnFl%cNe5y$DI>(9D(}I@CJ06*^@3aUf_Sel&H(6q8 zF~QsO*2Iu6%|4RxDUzEr$z97e&>dMoSy5R@UP(z_QHh{_qErbB(##Tl(22SMv0IjqiS^xk5 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/button_focused.png b/data/skins/cartoon-ocean/button_focused.png new file mode 100644 index 0000000000000000000000000000000000000000..a707bef58403bd7b9d3b29ef37bb678311359bee GIT binary patch literal 2991 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 B>cap4 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/checkbox.png b/data/skins/cartoon-ocean/checkbox.png new file mode 100644 index 0000000000000000000000000000000000000000..be5b31c90ce7660ce297ba73f79dd6040c2a6257 GIT binary patch literal 1884 zcmd^;`9IYO7so&M+HRIfDq9qy)P(OPjBChtv#)bgd6Xqv^U@UemMwMTdQ2G0AV$`S z)UAY+LWWA4vS;6l9u(>l#mQPqTu~f=l&y`G zn?TLJB}GV3^QzBH3q&~3+|eAUNRe3f5fONmBQ|c1K;$-n%>fn#E%qdEk^tU$1GH>F z?nG{l>yH3A(Zzv5N8&xf%>QqQP*6UKTW?S{j4Qn;YD3O5{N4zf8=Q|5y{o91LhUo@HpC}A;^F!rvY$ZwJN%r6x_7wTjq}wg?lKCx`3Tw; zdcAxYxf=HKk@Fnq$`D(==IK24g`x5ds>V^!iggNdEnl^JR*_r>@wFy{e4(Z}r2U1^ zi|~ln=voGejQVLjm_^*J9j{h!p$T5G*s81Cz6fR>E;b|M0U|C*Jo}8oHth99Nf#3D zBKHLXlc7mdYFpgh$45~+WE63R3!i_(V9ws>Sha=vbKJ+o!W=*ysS z%ttS+@%GC%?56r7Xt(dz4Q$f4nH?Lbo9!{Tzi+#$oVntZcYEQty_Rfp8$D_yXj)NI zr|_aNj)aL$zIGpxe*}{uAz?i;9pZO~fHK*GvN{#oai=LloS2H>h`EHbJB>76)rDp@ zZQFTFe>}>5g%FZIRrz=y^B6Z`Xi>`G;HD6XXmvBM-3IGAuICJQ4F)qiWM8~jH`}xO zj?7%x`e#!L0qNJaX)-rG`aG>PN*&CnQ=S>TUA}ex`4H*r>a>v}9y?VypXv+m&x@D% zE(`TR$$&MYw4@48pud$^AO>M1e0jO zjP;=x_E>nt@_3R2IgiQN^@iNiDIuQ{z*Zr&WkPM6C_4`CEt>nyl$6`dVK7Piudoyx zSvBoi#l9QEIQysclbk~%w;$T>KPWO-SS8z$z9O$8n#)zIjFEU+(yjihbJ|G4PmNbK zL^g%5T+Fb`a?M!wND-O1kZ^6>pd?JXEtYh-DBZ%1k(4?dH_y@$rC2xIUm6tSkxDjn zQs*ciACCKUD{kCcoFXl~T_~n8!r?{TnVigy?WxI9M^=KYOrtLca26&~le6TcXS@B1?<344+&{(jXyf z7-H;8h`OOLw(LwZ!K7rk3NAc` z->-HE#gCeR>9i0D9JNB^RizK%qg&Fx>wD zDRd}hLD6@JD}k_Vh{%OaxN$xLGf#*wh1k~+{R*O9S`G@6*Xw^lM~9JquS=ou(2YYJ z?VMnnxr@D_l*oxL-g6DvHypP$0vn(4fuP^${@F91H>6od@hccp;k#RvjDq7#h8M&O zRpwKvA@zwpOPQXlnAdf}Mj|H5s}0wDB>O&3m+E6+RW71 zt#SUcHm>n!6`OcEh~=n@>hQm(d*5$*G-Us{mv=1DwT%F;u28>r$BW7DZ8|q!!#0oc1_3QX1 zrAF4&PgLH3rCBJtC%E)HNV&<&s#UG)nbNqVorAM(ym&2aB%+OI+uZuh!_o1agqrHu z;_l7O1vKA-EU>U>8l!a_$U272j$w@7r%a)wp znr>AzvXd<>UpR)ZQfJ;dqTD81PchxNXUD~1l2J7G>&ujgL^q2rMWoJpd_5pSZ>TKb z)UrVvbJ^`_>}DfYO<8~?KZ$CSL8NYJiBg(+Dp6U>Gd_1SP-g1%g6~NQQZ%FMMyE1g zm;UyrQcAnL#6Jpqx;tFt>#?ER>GSRjTNPV2NW6AGiKCiE-=z&Cb8py6HZ0og`$K0e zmvSoCYs8Ru2YX&r{^A6=VJu$6?4VDwR|%Qhzn0!+WOYJ}C*_6TNYqubI9I2#cQ#UK zk(NH1Ke8vK9V;>MTTpr1j_D3R{|I-|XtG#qcFb0vg`x|VRS!>}&^1;FKXhk*5|1=K zKA;}RfPkQxareO2*Y-1b)qB(TE8|;rsLs(0G3LYW;u|tv1ROb@cd0-tA|=Hsk<)n4 zSLA&}Ak{fzZBG&ZY71^xQ8CrbqZy;w=#;8FseS)qfeUj%FMalTDR-R|PtNCjzR@Q= zm(VTYUrUl0YUzV?^6r9UDV`$6LWbi0DJN+}>w2aq{oxy{qw7>MiPwJ0dEqreyhl~5 z9jYw)M)#@3RD(jph87u(eatI50e^;v6;flKh*KCJx8FWZpVL3HM)1V0;eid+&~9## zQT*<60`1$bgf#oO)-zdKO^Avm*I0~9>=k)!FWu)_hbZPLepMaQO_}S*5?yL&rrXqH z6^dI(Y@f3fnMlV{PFeT2z0ca@v~Cee@j3L|U91R$!Q+}?`7wMI%?1&hSm&tHFR}Vs zkzaI4aS8WkowjM+;s>)SIlhqT6g(g}HXY{I`{MJTmuTcJ8=Htw}FAUTOjJO}%Bc)myA(r=sHWU#$ zOGy0s$J6CxvFDkoR|K)EtE9n==~| zfD`@>Y%xayxqg!XIt$b?KvfS5HvYs_?4Ajmk&VD-Ivc2}-CTe`=QL=VxVH!~#8Ac( z1X?+uvKw5>?iN91tB`WfETE0*FqT?HP@Mn*?cc#i*6TH>NeF@Z5s*v!Du$4s7v8~7 z7RN#JB%tODiy`c!uo(W{ggj9EQ6J8f6tcdL4_esZ!OLDag^CVfY7IUxLH#g*D^=J8 z@;)RjK%;O}CRV^NmXh$)0j`}j+11Gn=;Ga-%@J~5{i5fF)oY&ewNl4(Tn%RAFSM|4 zg|kDO(uvf@*h6WZDw>yXmmi&4Qmix(r&;ZtMEr zuDgcI$sPJ-Mql1|-;;pQ$JF4HlkPQ#&OCALQFBDx^E&0L!84ieVqWIwm|6IXm1E+E za?HlMukfudcfYSrx`YkexD~sXZfEC^RIq#Z^HMauI*W8L>bMpst%RQRLNN>RwkKs- zZ9g_Vwj(Z;(4U0hrgvx}6Eo3Er|l1D6>|oEuVw?zzn`#c^~k%XOMb6V8C%V~yJEtJ zqhp^Ks_ETHt&G7@ff`NGIA ziHP5rJb&;#GjsXi0g<{5LGs2Z3XSoUSF(uG&F?g-ZKnp~;zF~^jUp0@edhmpMKE$1 z)tP@||HyXB z(=R6;$iVGppVqm?jL}{)6gysBkFirqyi$s*-RZ4|mvDBtt^f)e2TLO-d1&uA z{T<%=PkWEkKiE@Fq$@yroH1uwqWdT;Hg?Mg~FWM z8?P0;r?z<{XIYU z7*~SwRL|UW6%~PuddAn`bZgT$2z6Mzn>eI>9J+LHCDa&6n~>+2L~AzRm^rt2^Ae%k zKQq<5+6!0v*yJo-l1?Ujw0fYZTUK?Y)`q;dE?pR}j}rE=Kh;u0eX7>w5w{dQM5LI} z`ssOQc@dfh-e$6m6!ULcb&K;v<>1+GIyzSnxnZF#^vHO zy2c45U1xR)R(ynRJ@>Kg9!O(fZcqtRU-@C<>4ka(R))a5vsD>OetJCd{=@Rcvk@$U zG#g{ziYe3ysk$C`;mS5Er>Oc^n`NZ2L2c*2BHraoaWyI9)#HU=*`QKmmLW@H0eyt3 zVDlzi$Qk>qx}e>?VL<2a1qHbbX{MV^z#T1#()8gFVB+zCP!xZr zrI~5ar<=>Ii*89y-JmLM9N7EFBiE-4J9P5SG-H^e{IS(owgGcWZM<``^7ZS8cOeD* zi}nh_V`1n<3pCRYATnDz>k8zW%1^V{r_}xm!`OOj)Gbbv5S1N&kFu^_ZOiemjHpvb?mvF^{H7Z!PIkNr|=_LkY1o)K2= z&&}Qb{4n0tFM+*%w7>hEY_Pq}eU3nqDCZ=#;)|%AC*bj9NVfGP2l$c$&HXP0!T?NB zrf6d{+8BiLZhFht zEe8NSD#h6g!TtXfMgzIC$}Wy0uMNRXyQS^`%L*ar+cJ`vCEG zg2t9W*bRS;K!un&w7?!&MAeT$wh+v>!5$jiufBlzzU}ovV!UjIgdFbZQWU}jM1xQQ zC9UwF2G=BykgCBu#I;|AMiwknB*I2`a_F9{qiNO8RQ^KMc(mn? zn|bw^`L$=RJlgwZO7mIprpffI*F3##@j`tzJ0-4id$r(aXjS(|OFEoeWP z73J54-7qQ+cFq6pU?E1osenf*vZ$`LRb?CY`b8>)GvY$(P{V>)(Wi*YK0Q>?9n-Mk zQULjWAZIuA;SHZQ*Hgw_b)g1<$K`|~`EVdD_Gp9c<=A$shsxH_o3~N^k49okI=c_B z`1!k`WQ_)W`{QTIApXc8>H^+h3%|$9tGx4G`IkG4qm-S-`8rjL8rpORw7 zR8#5RTGh2hSdE{{^M4Y=38Q&NB)fW9g>fEYFwXZ=()3%Wz6{2trsMqCR_KIA2TJW5 zM&L~o+Ee^vokxz?Nq^<~9_~>l15;>4iuB$t3>7%V8N~?5l@7Mkbvk;7I!V6a1(?iK z5%q5T)tRB4zs@&jt}sBA2H(+#NYjR`h{OX9c(xV|$TTtl2F>h9;v zcbYqPnpgUayS>-A?*fJsZUwI)f|-YTP7ZhslmS5+JMl+{uBr>me9iJ~vi4OQrMM9* z(FEHvgUCx=^4uf(E9*hG>XqeqZo)ot^oCyIi-3Krk~buZ(}?75M$)$dx*le^8EHTG z?$?r5&jx5Ek%#Qdo9i_Ln_lAuTsTdTF*8(lu9U~7vMpJ|2P;1sc!@L}b9*_(EyK=o zOKFHN|GLuOv2oZvnzAuMC9sM`hwO3FO41$*F|WIYcx+GlHY3cXq9rF|jYWmGbcvouqFGP<4>C`)l(Ya6dtKGKa7l?m z@Dq#n+1%6#JWx@6`%Hae|qK3Ya6uuWUB9 z;Lk?1lGtTM!os`W_)Uu!Lv(fcCP((AqB{M^sij!#Xw2oy586GuPg7I}W0lrdP0Txm z3#8R~%2ze%IK$!!KtoS?gfJ$)0-K-WV$C!C~$6YIYEm;?a&` zhAhSvk2VamHc*}Wcr`sT!oJYtC6ma)DbE#+)pcz%V#@TI<(8r6 z&zE{mBLB~V=W>)6$l)C$aU+i*0CogBq79K~Lm+w+c9Dp7Bs;rr2m}&=5IVMt{x89) a(}5vDQU5J4E)`550-(CMJO4)ZPxu?m#@3|( literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/down_arrow.png b/data/skins/cartoon-ocean/down_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..62d13159f05139feae5b21211dfbd8ed7faedaba GIT binary patch literal 2481 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/friend.png b/data/skins/cartoon-ocean/friend.png new file mode 100644 index 0000000000000000000000000000000000000000..4d562d386e297283bdd6ee43b12c567177eb39c9 GIT binary patch literal 7710 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/glass_iconhighlight_focus.png b/data/skins/cartoon-ocean/glass_iconhighlight_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..ea1cfb23a28760069110230c4bb25ab45564aeb4 GIT binary patch literal 15161 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/left_arrow.png b/data/skins/cartoon-ocean/left_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..9bc82a44c2668974221a2ae965bb7b1de507af52 GIT binary patch literal 3013 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/left_arrow_focus.png b/data/skins/cartoon-ocean/left_arrow_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..c3d32dba37afd38a156db6be13559949da5a3494 GIT binary patch literal 3038 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 AH~;_u literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/licenses.txt b/data/skins/cartoon-ocean/licenses.txt new file mode 100644 index 00000000000..d0cbfe1df7d --- /dev/null +++ b/data/skins/cartoon-ocean/licenses.txt @@ -0,0 +1,30 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: SuperTuxKart +Upstream-Contact: + Marianne Gagnon + Jean-Manuel Clémençon +Source: https://supertuxkart.net + +Files: + glass_iconhighlight_focus.png + bubble.png +Copyright: 2010 Dakal and/or Marianne Gagnon (Auria) +License: CC-BY-SA 3.0 +Comment: From peach skin, first found in commit 5cddb8ffb61001407ce97ee5a8c63faa18a08c2c. It is unclear which author made these particular files. + +Files: + src/Inter-UI-Black.ttf +Copyright: Copyright 2018 The Inter UI project authors +License: OFL 1.1 (SIL Open Font License, Version 1.1) +Comment: Specifically using version 2.5 of the font, later versions have a different look + +Files: + src/NotoSans* +Copyright: Copyright 2015-2016 Google Inc. All Rights Reserved. +License: This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software. +Comment: Bold/Black versions of the language-specific fonts used in the other skins + +Files: * +Copyright: Copyright 2018-2020 LCP and QwertyChouskie +License: CC-BY-SA 4.0 +Comment: Original style, most icons, and some elements by LCP, skin finished by QwertyChouskie diff --git a/data/skins/cartoon-ocean/readme.txt b/data/skins/cartoon-ocean/readme.txt new file mode 100644 index 00000000000..491ceb43fad --- /dev/null +++ b/data/skins/cartoon-ocean/readme.txt @@ -0,0 +1,10 @@ +# This color variation was made using the following commands: + +for i in *.png ; do convert "$i" -colorspace gray -fill "#00cfff" -tint 100 "$i" ; done +for i in *focus.png ; do convert "$i" -colorspace gray -fill "#00dfff" -tint 100 "$i" ; done +for i in *focused.png ; do convert "$i" -colorspace gray -fill "#00dfff" -tint 100 "$i" ; done +convert bottom_bar.png -colorspace gray -fill "#006999" -tint 100 bottom_bar.png + +# table_header_down manually re-colored +# gauge_fill and spinner_fill were manually colored to #00ffff +# achievement and friend were manually re-created from the source SVG with the background color changed. \ No newline at end of file diff --git a/data/skins/cartoon-ocean/right_arrow.png b/data/skins/cartoon-ocean/right_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..c3ce631d43b3b058b627d417ac03eb8c13320789 GIT binary patch literal 2983 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 PNdQZNoq4{gPt1P+d?L@O literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/scrollbar_button.png b/data/skins/cartoon-ocean/scrollbar_button.png new file mode 100644 index 0000000000000000000000000000000000000000..c9de25b920a2a85c822c8065c442caa4c0e39a52 GIT binary patch literal 798 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM3?#3wJbMaAv7|ftIx;Y9?C1WI$O_~uBzpw; zGB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZk1_nm%0G|+7hVGp}H3I*SM%dRo>?_;Q2#gIFdVb3dul{XoB zcQZs(GbkA{EWOImvx`AqmtpZ`hE=y18rL!u&1P7An_ui3p! z7Z?!gB|(0{49s00nl1lu-@3~?-R+;Zz~g7aE2E>N-^wv=+nt-E{`Hu)?(wOo&s-F! z=mu(GO!9VjiFmv9NFR{HUgGKN%Kns_k)20OLVlJlQ0T6wi(`n!`LpM)2OSC!aeK(j z=pyL7!F39s_eMu1jZLB=yKe;E|L<#)z-@SMv)=ytwDVzEI$SKg$`T(WonAQA+sY&+ zPxiR+S~yT6|KO7;=^Y2ZoqH#D#I4rKZ)ukGR<4hd+s~hKyqovNn%y9OR~w7T+r!hQ z%vJXI^NUGl`|3rnulOZ=yghxIqhECM!s;@UftDnm{ Hr-UW|wBh~9 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/scrollbar_thumb.png b/data/skins/cartoon-ocean/scrollbar_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..cf40666f803ead1f6a929df3e398d4dffce301e8 GIT binary patch literal 339 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvmUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fgAsXNl;>ysy6Uan><=6lJ z|L?40ejO;pQWE4B%;59%iC?YpHz1!e$=lt9Eir9JEs(=r;_2(k{*;@MokvVUewHmz zNZZrJF+}5ha>4>Gfucrc*9{GvP6s4)9yGBOaJD!dT)|MN*d};F;-Z5g14FHEh-p{k zk2OGTswJ)wB`Jv|saDBFsX&Us$iT=@*U(Vcz%azX+{)0<%G6NXz`)ADVAsd_r%^QI t=BH$)Rf04a=o(n)8kvO{8Cw|{Ss7YFG^{$b&kCr4!PC{xWt~$(69D-}S&9Gv literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/select.png b/data/skins/cartoon-ocean/select.png new file mode 100644 index 0000000000000000000000000000000000000000..bd6c20cb2f8deed1247cc322cb3b9684e3e5b147 GIT binary patch literal 302 zcmeAS@N?(olHy`uVBq!ia0vp^3P9|@#0(_a9?Z1`QY`6?zK#qG8~eHcB(ehe3dtTp zz6=aiY77hwEes65fI#@^N2~v&jQ&l>gnPb zqH#Vsp`kHALn5`uh{HI6fgxCY$;N_*89RXrR7+eVN>UO_QmvAUQh^kMk%5t+uA!l> zfnkV&xs{=zm8qe&fq|8Q!LE<cps|0B<&^55oH8Kk^GPW`@vNE)UXjpY< RpA}F8gQu&X%Q~loCIB3?PnG}x literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/spinner.png b/data/skins/cartoon-ocean/spinner.png new file mode 100644 index 0000000000000000000000000000000000000000..0d0fbe75ced3df39ec44dc068651fc547d421708 GIT binary patch literal 2888 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 I!o)M~-#;sZqW}N^ literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/spinner_down.png b/data/skins/cartoon-ocean/spinner_down.png new file mode 100644 index 0000000000000000000000000000000000000000..0d0fbe75ced3df39ec44dc068651fc547d421708 GIT binary patch literal 2888 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 I!o)M~-#;sZqW}N^ literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/spinner_fill.png b/data/skins/cartoon-ocean/spinner_fill.png new file mode 100644 index 0000000000000000000000000000000000000000..44ffe46da7ea18317ebbfa997f7cf1862a5872fa GIT binary patch literal 5123 zcmeHLX;>528V&*?tI8%SY77*inte|R2!tg{Fa;EpN|{V1Fqn;GNCLPZip7ekAO!^x zD{j}aSiLT|v`>)=q9PTAQbbg?f`wkR0-|y!0TrLyKR(axKPS&5bIy6c_dDNvzBx;_ z3qt~}E#_EYFc@oo5HA${U8=vQ7^B}!X8Qyfj0ut)9*KkkTC7r~kib$1izF!_ETn@a z7>usvkBF%34tJ}U-S#Oa%YCP1RZ&Iqifa!{F1D_{Th?E;@8GW)XAfIBCKm@AK}}wILwa#1Nl@PEwW(kJC)=NC-&0h{M; zhmQ?7S0`KT9o>xZ+K1aSh61`WC1VxZ-+QJF7$dBjz~qJgDF=Po&(>|~cJgK}@M>Ez zT6NLr@=>8f7lChElrS}K#HH3(PS1DW+hx5+=jlJJG$ECdIOS(#hwEpLEI;yDz^(b* zJ;shhMIM{x?lw!U`ZfAGUy&s@R{i|&VvBifN6Lj8S8eV+|2AoKXTzg>e*Kc~r>C-= z`S(Ltb9-_-Z59xc6ZuI2eh?Dg^6Y2TV_ORi$2=EF6xR_NiUr%;1fEnsWDD7M>ANTw`J^T|+!>OKt?1U|ptN&*$vuo-#EkcdlD)v}vnzXHj>2vm|i4SG-k& zDAS|sYGj8OY*8B;?9rK-Kf8$f9o1e%_@ZR^+fVG(pL`Rp@*fHR^55Iy>G#6bkKL?O z0xfT@k)G%bnRlddL(}}qzna79jgK(I!-wQs0hcV=U~P*}-&doi_j+P>&I$`_2)T!) zU%XI!;XqG^RpzNh)xGEVMi%=Q#YVXfBvF{`-)zB^?qD{j7N*TM-g3pRuQ=y3t4jVn z;Y+ZsFg=I)+ODg$q~Em5Yfw|Yrmn9ryLtv=i)pW0)l|&4)h<@c@`OIX=0xj1&6}3pzuftHc4SbW?IXL2C;g|# z=9HymO#hJt4duV;R&vV;+O^T;5qT-uqjh&XJ687-SLKby`)oW{*_xPiIeKk><)vr? z=E2Fb4RfEe?kku28h7^uKdf(A5a^w?(fJkY#RJYy-eA?3c74E5yvy)~oLl!>N(F`Z zuL^8duHSvmRoz$CoN}%)Y%tz~J~;gIZ>3EkyLOG;Y2>zuj%|#;eC>+OAJMxu%xk$k zf0T13h5I})ZYcRl-|hZ8%?S-zVdtegHr+2e+rKz{;OwSDF72i`Z+fRlM$Q zLDW;{W7C&zljK$!+1PB}gM-RPE?qpmK|c1J);(lg>!kvF98cDv3xy+$E(no=U=FB| z5dg751QB#HCAwf>FrMBzB>=925UdD_h2>n_z{MYMSXj)(MbHH#fzl6(gM*S)P*`$E zIGDT+WQ%d$UKXA@4oV<{5CE%_N#$yej*Bz!a?odeH4%q3K#+A@T%B$Lcu&ks=Y{;&5m?_D%m}N`c@ly<9z^0;&g52PlbT z0*NS-5hq)y5q}LzGSQ*GwNQtn>nbr6QY#WwAmp!s!SAhE#*YB$~l#sTtJ2z|3B zQt3@S{5QiyVKYc<5|f0N05o)%L?9c_qBGcd5=a%ZM4$*28hD>wt&kvEKn3~4qCt)a zf*n@?>u!+I<9)m~4$^BxqLA@qGM+>ZCy_X08iz{3lb9S52}hg=nW%rG-^A=m{2x_3 z4S-2g0BSd0hfXc%OhtS-3MvWql}}{*BU(rSqX!~{q^Ue%u39d{yKC_n1&XOkkF7Y z%+juA^sh6Fk!X1!50ha!F9(d5Ygu Z492yljr97U>^O?S@cl!0Wxg?K{{<%$wN(HB literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/spinner_focus.png b/data/skins/cartoon-ocean/spinner_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..69bfd419a5f44e4ed5f4875eeed6ee66997ef0d2 GIT binary patch literal 2787 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 R`4~%mV}qNJl55bY{{eL?FgXAK literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/stkskin.xml b/data/skins/cartoon-ocean/stkskin.xml new file mode 100644 index 00000000000..c56c1507eea --- /dev/null +++ b/data/skins/cartoon-ocean/stkskin.xml @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/skins/cartoon-ocean/tab.png b/data/skins/cartoon-ocean/tab.png new file mode 100644 index 0000000000000000000000000000000000000000..c779114522b0f4bbe5166931bb3284ab84649718 GIT binary patch literal 3507 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 Iti2Qd2Q(OJqyPW_ literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/tab_focus.png b/data/skins/cartoon-ocean/tab_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..17be11a5aae40ed655b03af18595a8035244d1fd GIT binary patch literal 3381 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 H*|Gly=dx)o literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/tab_vert.png b/data/skins/cartoon-ocean/tab_vert.png new file mode 100644 index 0000000000000000000000000000000000000000..7dfb601be7555e3d463f3a811d29a8c49e2e82f1 GIT binary patch literal 3249 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 GG5-PQ!QFoV literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/tab_vert_focus.png b/data/skins/cartoon-ocean/tab_vert_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..1c1bfdb820c8193620218c05f62bd6857c9455f7 GIT binary patch literal 3134 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/achievement.png b/data/skins/cartoon-ruby/achievement.png new file mode 100644 index 0000000000000000000000000000000000000000..c41eff986a5b144a27abf484a1289554dba65def GIT binary patch literal 10251 zcmV+mDD>BfP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!T)8Ltx{JCfC6!zXYv6Pab_Mvj8?$)(CRo+|R#sM+K7D$^ zk|j%G?d(Cb-4$ksb^SG3ejFYK}u(q~Fd$;E3&bAF|K$gJDONa5z zxdTWopyVslp)J9*Y10xu`|PtA8Vdxx)U^U2dweC6$ z3n{pxs7nRl#$*!{%G5InTKKPrjK<`ko~oMp`k-2R`DRa_un(Po5SCoH;mB3ik4 z$XCpRwg+pOB3K-`11V-$1U-86NZ+twLzIVyN2z>CAkax&DS#GCwlnD=&5XpFnYj}K zd*J=vdBYfU>D^T}jegC(az@#BRcjp6_uXBU!#u z9cybVtonQyTDo4r><_Qw>}CB&?o-K$jyb*iiWB9ae&KCbg z>6)Fb6<&P2DK2bnhe@Nzpi$eRc+%SF_% zz%(A~&^*k*D1>$VgaW{QzLPs3i^D&&=eA%t{0J~Cs;rKSU z#kysF_~XB=(Z+{T7pfDJl`4C!&3R4xp zSSA$V#|;JYtQa-}liT%@uc!}s{I@5ZQFN>=o;w7qzJCWccJ4q)8oT?SlfP1(lv@R8 z;*bqb_H8w}lz9U?64|!FLOjA=n;+S0WNgsW%9ShItXZ?BnLHH;xG}{C(1uAQ6Yki4 zcY7zS8vcw$oPC9*#Znypp9xXeb@iN-&Z|V^&S!CVNOyMAF9C9o0eSQksQp?$&@6Lx~*{M+OOuSudAH(pG6M)p^Kv9x>wGvVQ ziAlNmc!d=%C+JV;p%-pkKzC{H9^k6}%{L+?9uJ3pEoB|@5*!?ywQt|PNCyW8;S^}( z@G1af!`x`!|EOkY7~0SNICKUEwo<>M_xxjrX6n-!KQDp4 zc6e~8D;^l^iXpw7VQZuO6tbBDXyRgrip0D4q+-1D#Z9c-k_khOcB)T6&zEuu)a2L8 z$MEu@wVWz|z3x_47JzPTv}xx4bkk9vCA|GqzH9IwOOTM0 zCSOseb2|r28tH}yhPa|E6{jRI}U(6{@jayWb4j&z6;mSH=55*?^ay=Htd-U=;4gd-}FJk z?)HfKy)EWH?``(tCwg~vLfDD`?E2OpUD{J?LS^Xm;mxC)q)=Zqd721 z@uxNvHA$~6B~S5CSXgND#v5<6m8SxMB8C(Ib?kXaGc?RQ_l&d1SwFEcCPJ#lTN5u2 z8+`O)b9q*K6ciSsQ=4ow_0WC^ujW|B2_Mp|jdbkD%f5a4yti!G;weuB0xb+FfO+zx zLGEtW8qWk%Yd`g&gqaVHQ_hh#OJ8k)W}fO4?ckyuICVY^8~=<$Mph9z`fFD#O3JgG z1Dzt>bBhcH`&8iV<%qm|&A*jj?2OkwtsWoXU}K98?k#X8 zjUo;!>FD8u|MY)Ul@jE1D$xJ;Mck#wH*em2V&K4m+459yhhuIa(CFlEqy=l=7Jue(wjo)HU$TJNT&fCAc1KS3a!N$4_)=cV(tI1{fdOd&E9zl&s zsR+pZt-HuqOoNU@`)vFe*EyVy6e4`&$dRKWE}(H>jskdx$$Ofiem?H=5T3eAJFmKV~zr#61p8VL)}ojuHzHus?vq`WNHFFII#_fk}u0w?i_4vtRx4cl7E3b z`Jb{alsO4glpE1&!$(}c0IDV&6&1zh+YvNuOjQ8=m>kj!_49U*vG~8PCO7|)pvt}P zo!Bas@G>TAW&XeVpU_{FHIHw1;^79@QSYg?}9WYZ~Q zTV*O8R+i2lGuUG`dt^fM;#8&tDhqWCm==dak<}f6OWq!WIWNtCm9+zK{e7(3nu#ap zCZVKMTMPKRdg0K7*G=w1MD+-|t$Po}92#!Yq)FG7FJG=5QYpBj;8g%sZ+DdD##Q)! zq+chq7JpoJDxM2lY4qYJW=!s^&f=#9PE~;lE&+KbfUI3W+Haa_LDv@m$qO}Ox<+5i zIl{j8tmf}jS^UJ46Dos|TD5S&#Y3;+)mNTp+Lf6h`4Q6f#~*OVFN=I71y&R43veRE z^sPC)7x!^m5IcA7Y+g`Mz!ya%xZ|n%K^Vw{D{g#JyL;r3X?zv6UkdNl#gmgeVfN$A z6&K6&NxVP1g#E|v)KZwy4H6^Y!jH?w;EOk#;q;~;j2%?{Zr`JaLSB5yO(1gz zTXbuI6t;_@#hvsaTY#UlMgFt)0;jvbinukg#+I)-;G6j^;Fz;g^Yh5EP>B2+*i4COT6r#Wz%6;5-cLWew{R zDm1F!otc%RywJ^kP3iAH=-*wQ>F4m_!y-daAW@+JT$%LL4D~arjd{T$*+K* zPMSSE-SNrHF5?futqm?G6ye%U{ib|Yt_}sDLNw*QK0#cag-S|Ftak0%B{BpBw-o@_ z{-1jIJF5`*W33Q>R910FuFrhWIjq^!)1JQ`lAB)!zhRfqWx^G_viJse9?H==`_I*- z093F5Tx=brq9HsSIB-Dt0R*=dKwtS$F9TGnc59_z0hCol?v!gQfa2mZ6jCxzG3~MI zFWoyjqE{Cusnz(WKi|UrGZWYyzxwthH{UWofC>h*`IBO`?cAdnOQtwyemy(JaE z?HeVt08T{R!n$oS_-^e*tlSife=keGuiG0&@Y>V=sD5KDD6Fmk@(Xk*02M3%g13En zOiYZ6=qfCrPaS3d89W!JkX0)Cr3Okq0E(BFoO$KN$j&K3PHqWS?Xbo4dHMLy>O71Z zVByF=m6$Td9WGVEiSr7oFEU*Uz}7|`pB!z|lwRMOzQ0nR=H*vf092pg zwy&cGc2?>;a0zXG7LWZ@ARh)=4_%ByApF3(DYr6ZK2^s~o%D8Ur)bdL$bRGj%*#cNuSO1>yh&;tq+WN%) zqt_93yn0G*RSST+59@Ng+pA~+wB}US>FMd}^)nYVNJs&2*^5*GNG%j20cl%6vHc9% z0$A19CgkLm;p7F4f~b#BDeguZ>AdH#*d4(ldvqSq1 zU-cMJ-xffvNI=5fj?cGOP*9+r*&%3q)t8nN~Zv&RZjuzY}i~HYEhs300+qQXLojrT>N>nvSO;R0Lc6&bSVHe zEi7J?-UmVBf)qgY3YR)4HnU_^RTLuuX~oM5fWBN>s;rw1M$``l5R;IN=(sG{*;=Ed z+!-0!${MS}2T&0Nq-zVKrUk%TUd+zUPRDN}Xe`hwdBjIZcSczO5JjcR zcc=3)#ueyXb$ill3yM)nNXo&@TlvgVDaWCc+RncUDtrLh6&8Sk zu26IF6PcXvm6MZ`Zp|fV6p#W)(+u^KUZ|ewtrQ1P)dxW2>rem`SaUr^J!`}i$n2*U z;e>;O4NhLv{rgm;16TS0w4WE1T2qrW&X(bBZf?3Ym!MHV3LsT8)DLeTdLEQ4fRa*n zGb*qAJm%`TiN##ya$8sw-xiu+8*6LjLzJGK9P#;^K3M*)CNr->0Vp{))mH%3i>m5E zC;$Ps0=Sl&A&<;Q$@`p>Lm%2o+dem6*#aQ0B-XtGXw^a!8F?#{UP29RTH4|Dr<);q zdpjIo7laodZwfCDo7*t}1nIe&sI34JbJOLKemp%rg#u{g(5E*+Gt|#j&JPt2N(vx1 zySjxjq*oIR?d<|b2kq~@l34ej+g8n;B}*nD8TjWTp7?83AmVqm$HIR#N4qxFt%8iq zqTA`swP67yiWGF0 z+D^c@EH0xCty{Mi3ZRig3Ls81)X%weO~jiTDER<1TL5jy0w7D^{r~eu_{spJAMS{M zKgCz_%F=Xd?*V5g<;9zpUWg4lViA7)21?j%zpUH_TMm@rqwlnzr?(UJWl@jwobOd& zV4zR{jT}+{XEj6p#In0eL5VtdUPTKahtJ7K1vjbuc732@kamp(DsCDPm5O!SW7u;l zMMj-lMpjTk=dl-MV$FpV?J{TBE`OFj#ZD zw7d)vsa);?gE-h~XQ3WEo{kN>vXGUdut~0`)GS+;oRW`q+hTF-Og8o$v&U2K72)kK zauIV)_c0+=TYmbk0rJdzsLi;p!lPAjad9bW*RGwg02(=@0O->aCCv~PsfAki;4XeRER5{IEr-@rTn%RzD~UvOP37Y}?hXeyrX!qt_H z8{YRQBqT(;MYEvMQK10#$&Y%WEdcE?&1GCbckUi`iOI!S{#!a8dMOcJ{V!tpGx1oq z;#R#-2B*%aVbS+DC56QUIX{QC>WFU#Psh=R-o*I85cwqjCf8`fNIuPsNl$r7{%7>HLJX#=MBHnHfy|?0DK*SLM%x>V+m7%f*;X>^q#qtPtHL^(eUK z0sn4TGyGW`n>ZJ*-aQI_oaMSrB{cDzJkn2aaB#Mpo0~`k65Lh*1lKlTQ*0!6x~U<^ z13rP7!5c>X6X&OVfbWMqfvFwtMN4PHjca!t%Bhp`U{nWS@1Z2gIr(>#_AlUO=ZJTE zJ&2Q&-obb5`3&{FOR{(@4b^Md5`Rjb>8EeszUqZ_3K}#ZeN{3A?z?|*-r zE|}G6Fn4KgwIIukH)C_ikRf9KFOaCJ01hzWiXd5k<%B%49R99ecs6(-){UHn{SUq> zU#-rL@Y>r3Q2zh6eTh>3KVfUX)V z_x?J~P(Ptp&vECRt3g}$<_L1t?q5<{et-*?Gq7!M<>Dt|uW6s5)0SpPs}Az4_DC-wgqoYvmGYxr=rmw;^xyKVb{OUtERQPr`%FG=WmwRc zMf?0yDcJK@k`&@wm2KhL-hb-NPtMKS=BJB?rT2t~sZ*yW%R_-cO932aa#1tX&)4U| zkgrm101v}jb(BYyP|#55UzV`~=x)F3&@~)m3ZN>q_b)AXM&t!;1u(1*%zui@`1U-V z;u^-!&o6J_z=3spek!O})Kmb(YWYzwR3T_p^ig?cdHVUZg`+|afhGI^g+-;B4v36)!m}R~W64hi z$j#TSV8|UfzvnpiSi8wJYoh-~az39!pPBx*I&|nDvi}6t(DjM!!Gt0M4Su4%9h)G0 z!s~EXv3syCuIFZ;*M^U{!d-ou*}rz-vSS1GD0)d z&y2hJV*y(PwZXp+ub1|{#$dzjoL*g>5W3tSt}fa}55@JzT+PGF3$t%|ybgW(^hw*XW5;QEDrf}oDgdP|Km{Mkj|Tba;$MhVsaS|1KIlCj zLljN~^g*Wu{w?hk7k^Q48QS@~Vf3I@DALi6tSX+&(s`LJ`r{Ml;@i4SAKb-qNQv2PsRC{+!zG!8a)QYPV&z7L}dXDKaf_AKYl z)Gk6oP$yz4@JZh@ZJh2L1PVkVQ$OP2d3YmaG@3iP$zQ2m%Ghg6uQgBAA0i|qBxA&g z5hC+XpopP8{%|I{G(*G8zh@l&*_q4oP>tlgOdLqMgs|(Eur>a)Vh_V9W8ATNv0-Hq z9bbfw4_wx&LPST9>qpM2m82d+(8n4h>g1R)V?^wKBSVcX0I{3N2F=hg zAD!5SV<}ukhE>DI*&RcCJF+KYrMUQM|37aQpPAm?-yVItYdbUlO1^?eb}h%{%$xF+ zx*;MZ9t$J?lxKz+K79C1vG@i0;JKx}%!JF;Oy2pKVJoHB^xB}D{aJVU7zY2bL}xM# z-Ti}u9ORi{o*1vZ4LEo`8bdcP#fK5wr1SUMhP?hW5B$O%@=J|B7cX9{P7z1J9Se^F zxXR>x&CoDOxfysde66%NEy<;fWK8(;e|YiGTAgXIboYOImh#?T7mti~hm%4#B7zp* z7iacL3TN+C^;4pCL9gXY?0F_~cKjh`&z>C{7#LXhz0?Ku8s3&P6zxOje9fhq0jP_R zgN-fvw9t;+Q-iP0?#HuXKkIFQMNYl9XL{q|k;Xae9PMfG7a{CKq0WlL8AbWn7#kre zgn=#F%U3POXQy{d2|v691qJ2&_~VZkZEV!-I3#E|ELyZEKpyIa#{wY8=6#+C_icSa z#CH73%yYG&fA_uPTlAX39RlpJ`#XQUH`}05|z-gZWtmb&kxi`e3% zqd7~k>*_hYc6dF%)@96?F(W|~{1otFi~=CuW)iL$8iwKmW{0oF(Hk-H74ukk<+#pR z0}A_%_$>(YnF4T-%y{DoJ9-^?1(hcWv;`;f%!9?p=420KE&CyBzdMDL%J%Url{VeKBn2pTlTDgas?k1^qEKF261DaQ1@Kd5p%cs@hBmW8LA4Sx8b z6~a~o80GD+$(8slTxOyKr3d?X=Hty7%J~i{`Raz)Q|a|7yT3K62ZOu2d+~}DE6xei zUtkQzDgc5yPfTaR{Xxqt%E!c=U#Yqss30?^6hCarz<*b#Nrgg9flU9fqsoPHs186; znKQmvXM+#FQ$B5I>7v~v)Ko$f&q^@|^qTQPExr~kSa4Bz{RPHiiUJ_EGg+b;@QAmGNd&9Vkk9&4CP zmS&vL4}7!77`)JR7#kb+3p5JUvI^qs?fq8*}4|L z)gNul?D0oOnO~m`lY*LzIp(Xt*Vi{cG&D4#RjXFDpOheI5Y)B;Am}zuRfJ56jipY( zi~3ANcOyFn69sJXAGjVZB?RqY%78avhKIIp-qNC{#qVruFJCnsDxC5<+rpf_MJX1> zLyLdo#*L>$eLsOd>Ouh!UQ8%i{a$HiB-B5DVqg!v*XuzvHLIalMAPi+0PdL8KwkkuOWk=K~h%=fFPg1 zCMNeuGZSdW7XNE^kHVC8y`|cFrb3yC+Y-)5DZ^*dG@gEaP=nG(+V#S7Y&&AEnO^}N zf3A)`DlLBA0-j3r?AbG&E&eF6=NIr$mkNL&Tlps@k4iHWp^C#ZI}OIu!2{rAruls_ zBNS9w_m_TT`K^BJbDY5 zyvD?=pF^#->8?Dz!@Xwr-lN1F+JB!-zb-i-J9)N5S1&*LtL8&ZQ&+Nuzx><*v+no= zo$XVQ&nKUJ5+ly}1;$Vx6hH-3SMV1mW{1ns5nO+tws<(GC&mSIH`^*u3o`TfCtXz4 z3CT?T;-yQMUYIm#lJRGqf<{k$QUChVg5Y9ndLoc1 z?IP zuI8po5qfc1sW_K@9q~E0xNGs70+sQiNSLvjQN<8ko(5ijCGyhYf*1z+Dtn zZOC>$%7j{xQy6h~CIW$=mZ|Hqu~bTjf`+ICSs)XCCIW$=mZ+;OfG+5i;0-2Ynbf!6 zO(3}AsIQBRQj6y@8PCMjszm~UzyS6AE=wVL6Pe6lBK!mbfx2WhBs04+lW9yy8E|zd z5(or(+1C*F*%aZ^kI67udNZNYWCDS}IL6%xjy5VBK*2>+oUbpFu1u6${0anu3O;5s z_fAj%O3-m)Fca!dN|lPJo;YnA=%}$J6S5-i)aNb`=z`KysV@H~Otu2R{{w9+WQfM) RokRct002ovPDHLkV1k6s$1VT> literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/background.jpg b/data/skins/cartoon-ruby/background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b1cf44354f8509a183af78d09a2cf0f4be4b9500 GIT binary patch literal 175989 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�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

_@Z4&(adyF0Ej2K*9zq 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 W`4j2tqpymrc4Px(v`^{3Z~q4b6yDtc literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/bottom_bar.png b/data/skins/cartoon-ruby/bottom_bar.png new file mode 100644 index 0000000000000000000000000000000000000000..ae4e0d35e5b5b7431197ecd0bdca227df063ed95 GIT binary patch literal 111330 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

xL<0LP3=gsbkul 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 IT+sdh15Gb9hyVZp literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/bubble.png b/data/skins/cartoon-ruby/bubble.png new file mode 100644 index 0000000000000000000000000000000000000000..bb9676304157c52454081e29397f747b99966c88 GIT binary patch literal 47489 zcmV)*K#9MJP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>DxfV%8K~#8N?fu!a zCC8QSiJiUo88Q=zOpHl@05KB-XMh7(EEZYCvaVaVZs|&8)-6*%^n;%6t4wWrkXh?R z)+Uolf5A1=Tbrp(*IK4l_r0aM?5<*w#VP_E02WCQ13^s0#6)7qL?ZJ{dvATewR}Z* zctq^sRh-B1(<%Hit5fdaUK0ojA(n@>JBgvis~@o*rBj3XoT zXvp5S1t||z!icHvJYv=6VXQ^*6Pao z>YCi^y0=1i>WliVF^so_qx^h^xby(L& zMW{o%f1QrQI*xD_VK=7Z@gY5{^JGm*f-r#lqV&YCrBLkL2M8;Oz}tEsr1xVm*i`x; z_m0xAqj2Y>kk0G+oR0G=JL65I^CKN+mDclm_PoNmVi-@(D?M8%1ydx0!T8YE9@;(k zH$Pq3dG+Mv~kJ=XD~^F%kA? zI$t*!4UZE>1V5x_uOEy?M?|U(k^Zm|dpf1{SL{+4QUdZDR(@bQ4W%#}kUcP&LUM-) zE<&d+f)RgP$EJ~eckhP@6j{g}QXO)MuO2=7QEgvc^=GK|}o67Tf<#|VG+6jdq z|LM-lZ<``GPzaX>2MXXK1LE&I|N3xr;s#9mkqEnHt+bPoR{T1V{yGuu1`+HAkpYrl zFJjyz_feg1NJPJ0wRJ=-DOSRD6}f9tdrO~V+Tphs42 z+#Db2I47cipuC<@xHGzcT7K`Z?2b_oA1HtLnFXP6n|gLjWkWpU@yQP+YY*KyIZy-_ z7Y7R9A|NNdTFf;O7PI~kt-J_)z5I^LWIrYo|3(qx776@~BGHX{^tedN`50u!?ALSj z`>$7+jltR|Yt3hnyCCd-Kz;r7!Qu67J0DuF#t^2P+sM$4xxI@3wv@l^q!>^N=j8rK zgvSy%tvsKWvU^Y0@9O^h>OQ=$vN$cp@WIOJ=&V@>C=zuSR9-s=%HZPRKmqI%I$HX5 zBmHD@R0;qB-zZ^*=(oy!v%=ge0oQdR{B(Lu_m8y5UJ|_~cTMu#WWNXy=~qR58z97O zo&lwmla$)Jh>M%S#=uUc6c{5|8*S=Lx*03LLU>=td+GeX{7$N@PASg!RX$vQC`ED> zWuUU$mj8ieu+KP902hE5$lLhReM1TAssz={dkOkc5#_i9_C{UbBL7=Oj!%dTx9YJI zI*j!4J1X)T;e$YV>k8R1x79`XNW`f7;-jIpxGhA#KSw?Wuov)N;v7$6?w-=;)-d6YKth{6$telpzJ0bu}eRs_I z+a$b@{dNid&ALVjK>Q;LOE@Ej&H&Qv$o&0K!hOmJ#=x2&64d=|LFABiu$t!dZ5q&t z4@&X}mQ?~il~*Gpf1sfR7{~*R@K2^p0or8+SwsqhGB_%dAJzG|!geVH@{eUe8N6=_ zV0HL=Sw$z6=eHGyDF~I*8B+$6$)@~wHy(Rnm%+mWMX)>$6u^Rj^qevChc{inDxt>2 zKWrxccyf~j`-I%L%kMS?yIsd8blfVTy+P-r658u^&PlIZQv~^pEQWXW{0GT9hY?(H zjv&7I2rUH=n5PH;$^e3gQV4f>rsW?Fn0Bl!kAw#KK_~!0_a;j3c2WZMG-6

=w>o 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

eoN&Jci#d3Up+X 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%0Dq_LA!R{bhgL<3e!B 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�LX0Pz z`X((kNA< zM(v_@DetY%@ArA%_m3p^oqW%I&Uancbxxib=&94wAZW!QiXs*`9>>?nbIYIhBDPckxw_vbHA_d~*6GBVCp zO%=4sW9yA*i|9JFBPM)Df5dk!Q95|-$f7Mu;kKzpB4V{=!{ zNe5UVEKVe=Qci}bz&5aXnN)02J}v)(4;hi1Nye91`nBL|-YPcR(8>hM4Y!S3l_Xga zkBH7}ACq7h4atyPX=24~w{Gf1FsX`I@RXkpX0yB|0!JpC|6Cnf|CyLhs4zu}oD{7# z5$y$`;1gxihDiJo69$SbB3FyinZL87vA{!$d1n!n{Ikh4aw`>B++`UQdO*h4BvSJ^ z8*PhiNCfaO`OpI~<3Bk>P3+U}*8-lLVeL>U=cXJnCqE6!P3;1z*4xNzuy*|a`Sv$E z;isXUkdGT9hoBzD0Uc$YFwxgSzIaNV|dZ(B@RqQprRF=a@d(txzIt_%xH%qH4 z!Sz4BEapu5Xgzw*y(tF7O-@kI{@y{iRh)oD78{raH$R=jJe~`e8Pbn;%q~~94Yt4G z{&4n@{K1-k;Z-N!lSBOl(m?lgFZUL>{gBt_5kW^?9Enm&Mf)4H%H5QU81A z*KEac;k^}139-G88Urms`M%I7LteVn>wj2(7p#`oC3AFyk_^6epFP%7e>ltCWh)SK zpwEoz$~txvWWU>(D^&7bZK`-Pm#2k)X7X6-=;db@5B!C#T3x(eB>%cEiC-_3_K<5N zr_|(12@391h;IF7?t$;_pq0_PfF~y6_fv_DcMj4blKaC~ay&;Bg#(#qmfW7rHW%X< z60?*8msgdi{I`B&&{lCT!TAS|)tG{kdduHYBQotSejnPV4oXj2Ox?SAY3bb$<l#P;J9wkO&W1yag17T^u zI&@nvdDdBqlRUW!om*lBH8gIFD!QiJT=>sQ90!&8-gRDO%j;H^VS}CAuzlOvAf$xu zVm^35KK)=Uzjda1aP*hZu}vypmjBT8Ozj(1nfV* zPQD&5O#AA0A(rP;r}Uwwz(OlviS58?S?Xzj#B1^!xXV!`Aw5G|G16?a!MBrV zAN4P0ts(D=Tx9=a<#-&ukXe6b(K7lcjvy^eb2nIbuYl;9W*2ab`RZ9qQ;U`q{ahsj z1lg;5snFZJRzp`tcgy2KFIcEoSt6IpZp5PbAYO_s87I~rnAh$5GPV|bNs{f%vxDLm zOTIZJtC2+zK4O{u0bfL4{=`7!hkuHfg@H)1(HeQc_t*u%N#>FZFt^{d~sb zvzaOqEU)rb7u9Q{nG$Vzld+?)-fz=9xrB^+El5&_asjS=sQ8|u65KD|rN~Q}NfYB| z75Y#e`ZnT| z*G@z!5>sy3y)XTW4=7q?Py19b_ia38-PKG&dy+&Zv)YdiZd)IYdG&<$m2sooJ?GD9 zxb$a6QoEG6H@#1$Uo+8(8Xe~N#=lBpST=NU)^IRgla|-`4;AaT{gu(v~h6n06hE&O^*LyM5^^-$8x7 zNBMEWF2rGlfyrC!F}HK|A4`V~rUpm;OIF$0&Pn;5@fmdBXvRb;W&qdQUZUh%OElBJ zyrNBEi!Zk-4pUCQQBV`uM#(mkXB;R=e&Vt4X8rn?mD}|7h3M~Fmuwi&P~?Is@TDzaNDSx(d8F~` z+TDq)qpQUtP0T|eCX?FL+gQz4ZNl{(hcgx;Dq(5}*76PgEPZWnr9ftFE^_{+Y|C@s zA}HJol=hxXvR9_+(u+@76BpnHibfT zGY$yl2dYv^6N@{O4meyP$e!Chn&zo(@3)H*CgIz5vV=$6?)rk4-o2al6nzunenBY_ z41}LLj4q!Aw3^%H=M<+G-tjWMq>i9fCwy~|><}gsh4W+HJs>e*g@;x~B!@4}D>^1f3v+y6 z!9c6Y9~!Vk=zp84)2mY%f^^EwZiu9+i$2NM;UFSuPHv?&iww+Op737{bU~!j&QT*H z#@*BVOQ>%Txg?9Oa;TV7-tMb3DL>ec8}x$2sBWW_cAWt1ZN@48`sABHX2^X#0}}bp z-)bHhnXEZWd+H&-N5k4}&2GibRjZ_Zo9&(g_yeYOp2#91Ku^F0v42g<+7M0nHj2*bYlLJP)ylSl zl#4n$ak%$T`a~;@{_XbB{kd^&s*4dY<}TV4?qEW>cP#FjsfCdL9D_=5eM#(1F6j~w zuaTV^L2{BZ-RE)Dmvtt>&%v7e!1QH@r+N1pO5MW0NmqVUlx;6KOabJ~oWYjdE;PW( z!G`r#a*9;;YEnLLs93x%kZH1(Sx)|_zH~9mi>0d^^4;vPBR4Etv%2lbwH=O5i*C>- zfvvW;64%IgNAp7YfDVOHGiO1KWs1ixC-RI6z+6Ca*4)=il=H>DP7;@SLxmFq{rH9G zS6REf3zRk~kP$HQSz5S==YHwJXt~RrABBCk%BSbb7iE+h5DLm(gtE@+gK<9!4{qSm zG4vD~G7mx`Y@Mw7Jtp8*Y>=ljx+1LI5-&;?cGQ9pUOn zk3#l~td1%7F+29tNZt`VZ$<#dVvkwl`8GG6Eu6@+&IFyG4|@z)+s!hz)8+F%cxcUJ z%FPuw7xx14u{%2%psyIPh*$#Zar3Q9^MOkqu{clk4PfD1L7tWed0KViR&0QMKeCFq z>V9YS4*gIvBv9AEieY=qpx(h`8|cfsUq}04?gr7$z!rDI*}p%GkqE_{FzK34p*!u z6xPKr@c4C%&H4fKO}eTwem!tWq1cbY&kleDSc>vEpSz{${4O;9a$*AMmy|W@Ef(+% zLaaohVph7Vf>b6Xvb6R*e90)aUY)7dQin&DcvrF5XwV=*>`p!;Mp`%)*9t&z>Jx% zZrfTDpNHpoIBjK@^|0;pAySe`8P>VZxqS+puLVXg&0DSX5>b{gpjd#;gI!fR>`Wi? zo*0Kag}|x4C(y2L0Pu&5b-SR0#WlZC zEk=L0S!QZb#SRx7W+L)z*k0Q#e)P^HS0p!HW?JUxuGrsc@;Y}MWJ~+q?yBOqZ=cz} z2*BopDLJ}xNs+*rxZlAc(Ekgux@_HD za{PapHtaEz4XhBobWKLrl-oa?res(lOG8VN4tCgCZ5ILQmMC02oOP;~tLymdgzPuS z+i6gU>HXn|x$%#rvEG~pu1_;=#HM@U?4x9iB`5*us^uX{2JKD|AMn%7CEJJ z*t@T?J-Rzzn^+)bthqke40}%g8w`r%Hl`CCos5MGI>o;QM)IKe_u<(9I^VnI?Dc>m zgNp}=Yqesj>#x=M$H;$Rx!+|#VruR`EG_V-D3IG<0ezw11f7#Gc!yRu0zbTy`@o6?NcP&r zUw0S`bvVLS@}*Rw`|fc2>*uNSWA5lh0DZ>XHFkq1sJg=8t!sP*O?c0yAX_X>=vSS6 zwB5f@yS>vs2zdK%Q9#KBETUj&jD(Q~dz0=hAgKW={y#FxKG>0TZ zgWC%6+?pYDFXTxq?s-S({|8(5|AI5P@OrlJ@b!K78@LC7K>I&Nq+?uf>%J3iVTAzI zAH{@l8qTRk$}5a7?Lt-lBL(0p<*dU!?vov*h0PK*(uk4VCw>&^9c1d*%Ot}zLvAka z+h7$e+)-AT1}8-WFz_5$Kjx}Zvv>Chsm5*EV>2QYU>7yGi$oDhDP;Ldjr#1*0ZsX_ zMa$8(jSAPN=Ee=*S_2JJ%V9x5;CC6XA()RzOY9HA z0r-DJ9G@F6^5Sh(&-+IV5sTXd1o1BP-v*O^T%sr1aQlCuw>oZ4+bx6&3-oC8Xo{|5 zlN3;pJ*;{z7j>el^93K9_OJd;Eh9KyEbg|}d2&0eXAI0aIyV{Ex`A^Jj9}=M4~6JS zj{3gW%S6<_g4b!U(Fno6RoY?J4PwmN1gHcjPw{WTe3$LnV+bRF3gl${DAZWHyGn;S zFVv{pmYj3wU)(K_s~Z(?pAGQZHa_?8If0eX?G|U+_d05PBJVnO4BuwN#jjJT|Bt>y zHr?pcm6Yv@H&fpMF*jfhTa;(Yo8pJbxjDH#Px#c2L@_idM`{c|eg+H)`TxpxB=0=p z$>tQR=@7N3Bkz1(N83VgJ&V%|_uS!bP z55B|HS^FkfaIoG&0TlHMJo@BM_!8y?oX;nB+w3giE#Elie#%XSpVHd74RRtZ z997r^ORvQ2FY5VUqN1V}hHWdeIP3MUePT?O5=mVea2hpb0Drg^ZII=a))%AjvUGK^ zR=2e9b+4!k%T6sbuo2{6&EL$_EM$g16_B~$NM7(z18wXPuOWj#71E9q)lN24dl^d6 z?S)ZS2wwiy^-Jn^?V%Q=;h4Kr(U;cTgdlj`#cv!i>$O&n>6r=Q$^(gEe8{ns$%`p*p$$u&w4WT$<-}dAZps6 z3{_VA7o`#P%$B54UWP*mq>6-FdLgix)yn7<{OcdhO?=(YuC`X*4}OD_U3UIf$hJf0 z(xS%dX=(JIcxsuAhnvUxN5|96hBmZopMupRvDC|E3kHc$*z9%mK`9-WyDzbC-`BLS z%bOln{o|EJup@9j6yHE4QlYxSoEU5A`_$0Hi#0wTaKvY;CHfgALfXhOmH+0DJsr+m?cYU zCDxV3f0eO$@YXtK{50?L8|k+~BHJ7~P)!JLtl# zRx13De~wMT55I()4f#&WxmF7F8q}7)FkUM=qkX}DH9FjJu+N73sJiL%S&NS>)qv_m zxt|ItfhErp0!4v-NRs#n@xohQe|P>`|9!mJ`0}AUmDbV2h~&E;6b*{~#{~myIXYvS z{-_+tS@_^)Z5Ztpm)u@eHAh+gZlfTP*+o1PB(!R)Eb0FYHqY6Z+|22xY;}dtD2u3s z>SdT!unMs;C}veQ9D?;cj+!YoY7@U6~mQ`ARk$kqJV9ek{gVx-9+tCjVNd{5w+ z`O5-iaI*HU5==~ZuS&nL7UFk37d{ZFP=FxO!6sQ_WF76mcJmcqamuYW>UB!ZUXtysHy?61u?ukY&@L8k& zAzY=JXIpIL_ z!va^bLuk@ec;L%N#0_cs$K0GTxgR#qD~{9FA4 z>Tk^Ww5`ayfD*pi7${m(gDEt^Zj-Po735)gU0`_&u9v;<3O#C4$?G%#8t|anI8o<)X8KwMV zM${>UEP>h>*ri%mboBYW;0LUYLXi!;B;zz$rGTeFBtsGc8%ML}dOz&^>FrgkY@}9` zuVf&j{QJ7wuW2H+Dh=#1DO$J^0BPK#gRY_sMz8L~&{#duv!sDQZNr?{6!tJN1WX{7vp@cX;o_r2af7SFY(&N=tF&wW0N)xWDrM-8I}fk1THT55(M5V#%q?hd5{ z-jQ9N?7#=u(@+x$svO|{2@J>|A@mR+P)#z;i7f>%zTl>1<_QAPcb>n%MAuRb2*f$8 zt%fl2v);(Vx>+q^du9khZ|lXsy-B%RbDH%-uPyROs6NC$GHJXUi$<> z6BhgQI>SNkCihf;eJ9p$X7hOZhJaL@(HbhbtkR_aJ{zHYErJoL^-{O=F8)k?FAlFK zi|_Co>qRXRY@XgW46;TM;QC)qp!^X+kicTKI*mF*Z{%nh%-EiX!zOXH34aaWXLJ*u zeThE;X9T*9&~Q&#RiG86GJ1qEOC+}qIYiDFqX-Uxz#)co&BFKCP*$&yMvXe&8tJku z5#XoyBe88rT1F(4-;qosMt5F%UKi7}YPl}C!#9N`Q2!9)k6?V}ViRWiWIF~<_`pt! z1LpP${mxeyRmFRtj7w&I3qO6`fe|{NCszG^_AQZ{f$Qo8QjsRyl3l6zH5s_cYQ>p0weQjfhe>ZJQ9%+3#9vmS?=|NlTd@ zSqN=H!S0(7X0Z}5GxB3?mX@1$u)sm`ua^gi$(B{@#>gN8KEQ87-n@gm(F+-HjLSt}^y*^de-_ zibG18C0kaY0l`Xd(aOPmq0rl!CwEy+A1z**4pg@$ox13=l8TUw`_CSOAkWF#q=xfJ zg@1L}L#j<1GgJ@fQE=IO1+5-5zn_ z+jl=!oshox9oOk}!n?A+*60-AN*pxrv<;@W9iQyNwk4cmU*lp6nZ7l;7oE%&HM}Zg zNFP$-8;^5rtRlRZ#ED&DSB33f##faoISySLznZx@!qeU~$IiEId-7-ZQABDKIyde29Rwfao82+dH&;Nx ze=6{bMpu`x8r9sijzd(a!SfT$u#wv>gD0U%`ztTBiq!<$Pn5FxdT(7&YJB4YZI3e_{r zZnyO!E!|ey-p&IdG0B-uX`9(!E07VbpKB@iH%zaQDV=)vkRW*ho74Apa%cY?Vd0y_ zC0x|n_?==#p0wR)$FLE>(C9Jj6L`CH9I*TBn?KVsY)An`#1`}2^6n8F}d;TKH5RS7x13O*Pyg7T-X>}*cfjBJNDJQcaNajeqA z&5)wa2s_}n4PD<^*>U?-g-n-I9_1SIn%KwwHnap{gk^VzhZLwmimc-zZA}8 zGD+4XvVQLdUWx1MS5BL8e#@zCnN?GuG~FtHej%xHP=1esS(a^f=Q^+*RQvi-Znx5G z>r}wP^O@78lU2V|?1#`6xNbCjgW=IGq&9r#lhHU{X(uGSNOc%@TgSMf)ldNY>(Z!e zJe+J<17pVl%NvfNY|hYljZt&+`M^l`bCc(uWTl!qlwU}3MX=F9K(n6baf-85*3wQ$ zcUDaK^!-AGglvTW2daq=cXDTPs(2>`cR&8fzc1}RW+6cgV`2m7iz+3CNrsJ;^<&s} zX-$a`s9gO|E?m(2#uQ}?qgT~xHFjNPUe0lI^VtWv#JfRvw$(gZ4ETX{0ymj@`#+@) zUNsjUS6j{r=dJEwrp!wD#pnW2JB%`Sx>On%K>l+zv`xrkFeuJKpimDM&=Xr}g%OVwk+q+b) zD;JiQ`l62PJ?yc0H&+TxDImEMZuuf7lhls-PQwmHe_S*sN4<^eZ*2JNresHm=>yAL zaAc#P3p*i%i&rwb7weWN7$jQ>sM5O`V=?fR{u*kpw|&06j8j1kwRMNrA`pd6053!^ z-ne;F16EsGthU5D_$-WjCNfnL2OsrEnHRP5LAp+6h;X&AR>vWh@D}N@Z296XI5vig$+3T-=4hGK`j*hu>F-eaT;m$d8owhPDv`P&kwMXDZN1r|L4R6!#Jxl}?x zxIi?v`Wp9(RI+CKvOi&-#=ic8qgeV|4U-Y4gqkQ;B1a8pltcTcc!s}BEa`ujub-t5nEpp6wG>2WuhWGbdc$%h8d|}rolmPX~rSvMWT)u+nCAm!%u)b#( zdAyB0gBB1nx^jRZCoRheW$EvP*$|HUUP6!cDndd;TiyoYA@D(ud#ps44aKWL&cv1g zvgc&NfMGq^R7TZ2c0rvUX7?j`*IW7Mvg_waTeOS@mxc>MyKDYd5v*=Ge%r{S`U=Gn z5I{-yYe#CY10%-n8m_*V04&_@6sx3A)2(#e@+_IxH+FZL;SKE%x{U6wnNlW`V))1h zsD>CW43tUer?@}4M*OFaICLi7MgLWx?1~qi+iPlZq;k$#0&i$go^)XINDk$q(my1{ zB+HQ1E`ePwy&}sA)ay)H^?1nWn*5VL4a`Sl>^`Do`@Q@CJYblwL?A*i zy6Ni0#f_%;_&c3(X!LW3zIgP#agfx9gIIXA=4|2gh_nxW+>DK~jav=yGwB18Llz-V zj_)YfOm6=@M-rQ%m$HIH5DKq%8K=9#yj<@^%QPIa5|{on*pK* z`Hsx8+>1TB=`GzLBT1(ACrcP_zvOQC`6~z#k8XJJQ_7!Q0f;Cs4si}CMN=pQqK3od zqwmcEJg>F`VGpolqBR#1&ZEqW1;5nfGc1ViM^kCIub)Y9I<2|=y0GwH2s18Zw}Zw< zucbeE2_!`ggQT!B*`v8T#_sFwyrEj*a&peTPSG(d*MK4vA+NIXC`Tk5EJ1L^VY}IS z-Z4nFqwvM?=)v9S3f|DxWAFh(Zqgoo5q`iOB2YAx6%YVEG^_2x<6&}+(5Ci@Q}iIkdSQGOwK$xmzSeRJF9o?VcH&BvooqX~(^oSM`X z)NkvSW1JkHxC2NuhMtE{QaK9Ln=LXjF5g|_E(m~QR8W#r^GzIDka<@xJfCAdy=LI7 zY>wpSx5f@oBr;?oj0rq(0w$XDJH|AKozdVq2O%Qp|D|se@k5S({Qb}*Sq1hlzgOrS zAdW+I@e&Mc^tPK!@`7k>xy!MllGU1gap>T$?;pX*F#nL`A|vT>FXcz`` zivZhQ%pOz?D{~LF`*kS9fIHxgCf_pnoTGkBFeW=NzWQ>}_^XyPf0)vPYHBYHl&#?p zwNl^ud)_Mc7QZ+l-8B}+cXb|o-zrlMy+DNr?2&l5UQRygHF;@Rv1_)oF@0f1VX^Ln=xA|^eKuPD>%C zUyR(5lC&~RkFSkGQ|&`#;?Ne#WL8+~b7Z;QDn@La6%Z*XD44HG(1<5l;ol?DhaL|Z z!DjEW8AoL2oRvuWlka=?{oWcdg|YHW{O61x)=&tbbmw1+W2{g%$?cq|NbPj609~BA zBHuzZ4hE95lf3F^WgRQDB)Sl-V)SiITE$2){R>)AcV?~-ae(viL^{U0gAY1FucML!d+H!T=9?cN&_RF_DDEt+@ltr!!WSFb*&;9p5IIdbw{GJBp9y z&$nJt+ip>}vWao`C-2a=c{+|SNvG7SgYeVE0hx}n)#pAYsWc>buPxTNU+fV93a$_z z1vQS+iZ_paOhBwq#sSX*1vFUXq0yoRSM96i2<~sek{OhvqPTy$h`XJu`fis}or?Rq zcf85RI1ewxHie`9I#n(}JzfzuTH!9n6#LN0$!29^ZZ0wXf0?EDn*sy1It!6mSzj&v zEC%EkQw&O)fO5al{kjuWF-HoA--Fe9F6fq@XIdxub4ox7*lD)($AE&!g#IsIFW35$ zmvjbIf2p#nGqIOA@EV@*G*qzoo+u;w56pflt}2&2JUkbVx(Rd6(JDZ>Ds;_qNRc=| zz*r3mTw%NO1D)Gvznp8JxPOw;=PP?y+^Yh4pVM50=N2#yaL3Ke(v0WC(Bcu0YCO6~ zv%r9x>sZ+#3_$!k`IU&!n|A*nQAd^_M(jgYm||F0Y9t;S!L!lL^R2H7s@>bO8HM1lgV{;UXP=uc~x01 z4Y+Vp%IkjMdpfshc(uHb#e>%gdFxUG|5z8pyho1CRB31BtXFjcLb%;NQDBV9YJcPK zQ%0p20o>kT(Skd`WZdA}bgg1NEbU*+*Gqfm(uS{fY&`@ znQIv}5HPQem!CS{tC9l9{b@y5u$pS2p~_?i+{b{tuBp<12u0xH*~<^0BaJ2+>RBPO z0*%I224Y`czNrQTDo>5ZqL~EDsiF+R^#f3E;_xdv-hn#Bh${ShT^CdTS8CKd{RRLj zI8v3ckV|}{Q1!?fZR{+?eD>kyL(kk83#3hqNl57JddGwo=f;O|5|?-PKI0MyA_KXp zv53)c{5y)Xm#js019Dea(@H9fhOf^xO*6}uDWXINW2Y{pV&DrM@Z3z)4T6%yN&1oO z_HM<2&gn$@k>b(cXMl|cEc@$kA9&0x-@Nf)9yBj0`C07Y!_>hCS*-2vWLnN zTkuQgSHQ+HzbpEYxkiNNlSu`+eu};bPQ7K)U3`LQPCL0yT->WSFFQuW?ED z?&;DRu$2b#Q^hy-@7CD zOrsU!Gy_Q2qeAS+cldhm?{!2V=8Hde>6hlKTI*A(7Y2OVA=Ol+$Ip(f2jBgHMK?Z- zm}li+N_zfMuuJ=?b-q!$iI%PH6&n~APx?KJ{f|3|f5kTQCS0c%L6wJGqw{c9hu%_f z*kd;CL#FiCGX0~dz3l~W-(GgtFDfaHLo}KHHb1pK7}VRj$vqwe8o2JHffz>ssDd%^ z|7a(#VQMYlGhTh$^jb6j`(bu-AS0W+^6c$Wxlt?ldM3wUEl|(>8&=g(tPmglq1~#g zX7&8W1O8qylVA)?=H~w*N_lzd3HLK8!A`ebrBMy?uwP&V(Z@j}BKHOB!m^GYs%`<# zDL{AB;cA`9o^yjs-8is4%CB47K3~H*c-L(;Pc)+mN^Og6_7(?BJ9vnf=n=yx3%=4R z!c;5#R@IRp$_BREljC}4CcnKPx-@_k^kR83Fi}gqdbjTt#IPt(B@K7`-~3MT<3;bc#Cfp8RB^IXRqP zkCZ~3w8w`-PD7kF6Y!MmnqSG^-TB1r_)d%PC2$I*y7TJgw{?Bwjzcd>TT8Z!5lj@; z_sy<(3$t;WmGrH|0t%5{V|2IPtBxvN4WiY*p+A*=6+)|bu2cCP$-8UX@+<5!+-ykK zMFhUU#Vj;*fvPbKacm29;^e!ieiS3Adm>iHr#WcDfyi1>^ zIYYYG5x&#P_*Zxs8$SEL-@@O*y&?}AoVfT@;H(v5w+wB^=PcRkwP%~YK!LSFG+|c{ zX$)WJ!M%hZD_^2zY$tCrTKP)DPi$HI84YN{?$&e?;@j~cxM6WlfMuqW3!YI T^-SO|ACR{CUA0Q2P1yecmuy%; literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/checkbox.png b/data/skins/cartoon-ruby/checkbox.png new file mode 100644 index 0000000000000000000000000000000000000000..fedc6db6e3a8795c99a0672d1656c67e0eac2f61 GIT binary patch literal 1846 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≠vkNy|)4o6RN#*DLAZRdb2T9$t=K!m{XILSAgas>_S?^f*(ZkEU zD=Qu^sQly4dj0dX3?LD>!NNH-IbXUSWRO7y5fJ?cvNnTg1f~?R00000NkvXXu0mjf D$801m literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/checkbox_focus.png b/data/skins/cartoon-ruby/checkbox_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..e2ccf8a1d45705a2354da0b23372416847d2a0bc GIT binary patch literal 1897 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/generic.png b/data/skins/cartoon-ruby/generic.png new file mode 100644 index 0000000000000000000000000000000000000000..a8f53b59c7d734b349c21f46f30390e7944bbd14 GIT binary patch literal 4836 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 DiHSQ? literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/glass_iconhighlight_focus.png b/data/skins/cartoon-ruby/glass_iconhighlight_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..6f2bd52d56c1b2eed051b453e85202745ca48a6a GIT binary patch literal 32457 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 Bba(&& literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/left_arrow.png b/data/skins/cartoon-ruby/left_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..43af58fecc15a40e225f74f70d68b4536aa1f42c GIT binary patch literal 5206 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/left_arrow_focus.png b/data/skins/cartoon-ruby/left_arrow_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..1cce63915ea6373892ca42922eef81297c1a79a2 GIT binary patch literal 5199 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/licenses.txt b/data/skins/cartoon-ruby/licenses.txt new file mode 100644 index 00000000000..d0cbfe1df7d --- /dev/null +++ b/data/skins/cartoon-ruby/licenses.txt @@ -0,0 +1,30 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: SuperTuxKart +Upstream-Contact: + Marianne Gagnon + Jean-Manuel Clémençon +Source: https://supertuxkart.net + +Files: + glass_iconhighlight_focus.png + bubble.png +Copyright: 2010 Dakal and/or Marianne Gagnon (Auria) +License: CC-BY-SA 3.0 +Comment: From peach skin, first found in commit 5cddb8ffb61001407ce97ee5a8c63faa18a08c2c. It is unclear which author made these particular files. + +Files: + src/Inter-UI-Black.ttf +Copyright: Copyright 2018 The Inter UI project authors +License: OFL 1.1 (SIL Open Font License, Version 1.1) +Comment: Specifically using version 2.5 of the font, later versions have a different look + +Files: + src/NotoSans* +Copyright: Copyright 2015-2016 Google Inc. All Rights Reserved. +License: This Font Software is licensed under the SIL Open Font License, Version 1.1. This Font Software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the SIL Open Font License for the specific language, permissions and limitations governing your use of this Font Software. +Comment: Bold/Black versions of the language-specific fonts used in the other skins + +Files: * +Copyright: Copyright 2018-2020 LCP and QwertyChouskie +License: CC-BY-SA 4.0 +Comment: Original style, most icons, and some elements by LCP, skin finished by QwertyChouskie diff --git a/data/skins/cartoon-ruby/readme.txt b/data/skins/cartoon-ruby/readme.txt new file mode 100644 index 00000000000..7388b7efd32 --- /dev/null +++ b/data/skins/cartoon-ruby/readme.txt @@ -0,0 +1,10 @@ +# This color variation was made using the following commands: + +for i in *.png ; do convert "$i" -colorspace gray -fill "#ff0000" -tint 100 "$i" ; done +for i in *focus.png ; do convert "$i" -colorspace gray -fill "#990000" -tint 100 "$i" ; done +for i in *focused.png ; do convert "$i" -colorspace gray -fill "#990000" -tint 100 "$i" ; done +convert bottom_bar.png -colorspace gray -fill "#690000" -tint 100 bottom_bar.png + +# table_header_down manually re-colored +# gauge_fill and spinner_fill were manually colored to #ffa6b3 +# achievement and friend were manually re-created from the source SVG with the background color changed. \ No newline at end of file diff --git a/data/skins/cartoon-ruby/right_arrow.png b/data/skins/cartoon-ruby/right_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..7da0ef0d105958a73a6c816f4d16662c8b8def37 GIT binary patch literal 4930 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 b1Y`dLUl>t9gF8=*00000NkvXXu0mjfU;7-9 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/scrollbar_button.png b/data/skins/cartoon-ruby/scrollbar_button.png new file mode 100644 index 0000000000000000000000000000000000000000..ebd76ac257cd6b79a0b0b8e32452b5a48699a220 GIT binary patch literal 675 zcmV;U0$lxxP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0ys%TK~zXf?Uc)F z6Hye#zq!*qnlwq%3bh)1q>76)MJm`vK?IABluAJmv>S1wpn|v+TvSjH+_(^>i2sCL zh=?l@6kNCwML}IiHnBFQ(LyuhckbLtVoiLeyZ+!u&OMoYXXegiu*xbvHoZna8>NBe`hdQR%(3lg3$DG((xsX6&b@q(}u~n4CBaSe7htGP4I8*fYp6<6ikQ ztp;?{J5(n=J8}_LBm}4Y6;?FN&2jNKcUry@g4G$sEVt2+ptXA^G!8gR4@r@ar_no-LA6-oX|_lg_*B^( zvVGH5jKwyZCdTL)udGknMxWD&EDBS6)dV|!9o~rJV5u;N)PpOgfeIa_uly^xOLh3W z-4|em0)HMZD20x`B<>H&^P!O}$<$kvq57R7TN6(A!>u~9{5x!gp==fhF7E&U literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/scrollbar_thumb.png b/data/skins/cartoon-ruby/scrollbar_thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..54816e01435e0679db3d9cb292ff1d7a28ee266c GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjSL74G){)!Z!V7{k|V@QO1vIOg52JR1xkCr?9nSV+mMeRgR z(*sU{Wa9=Yi4-%ggqBMu7?w!A%SC0$NSbzCzyq}yBF$MNW>@_ylMz! z@3Bg_!nl}EqV&KDX18dU8!`-8doOVbq<(8KKka_dgNcWSVQGzz1JnKT7@*Y*p00i_ I>zopr0CyfkD*ylh literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/select.png b/data/skins/cartoon-ruby/select.png new file mode 100644 index 0000000000000000000000000000000000000000..29737bad205f448a6fefc86799fa578ad55c793f GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^3P9|@!3-pQ0$S$)DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheYymzYt}o(yfy`eFVt0TPQ%R6t@PCG<+YP*cJkA1-$YKTtzQZ8Qcszea z3Q$nd)5S5w!#g=ag+apYpoRqN;slYNra*&B3|mASm<^1W7zF$o9J_njb^{eNc)I$z JtaD0e0stR7DqH{n literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/spinner.png b/data/skins/cartoon-ruby/spinner.png new file mode 100644 index 0000000000000000000000000000000000000000..ec9f248f4ec64460d34f2a358d35fd8283f176ce GIT binary patch literal 4382 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 ZDi`)^FqKJ@$EJL#86IsH<42`j5D^ixI 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/stkskin.xml b/data/skins/cartoon-ruby/stkskin.xml new file mode 100644 index 00000000000..aa9e01791cd --- /dev/null +++ b/data/skins/cartoon-ruby/stkskin.xml @@ -0,0 +1,312 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/skins/cartoon-ruby/tab.png b/data/skins/cartoon-ruby/tab.png new file mode 100644 index 0000000000000000000000000000000000000000..b9e80f94a811e4cfd3c64d347f9c3ca9412a10fe GIT binary patch literal 4886 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 VdLtf@w+LYc+UojhWvX^z{{wVe0~r7S literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/tab_focus.png b/data/skins/cartoon-ruby/tab_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..fa78b00fa02f101cc5703e3850085f91df76d28f GIT binary patch literal 4624 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/tab_vert_focus.png b/data/skins/cartoon-ruby/tab_vert_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..fce37730c1cbb37a625621e5fd16eaf5c1487cf3 GIT binary patch literal 5333 zcmYLNc{tSF`#xhCQI>b2g-~{qO16{?S+b8(WQhpLz7F$RMnYt(?8@F)8*A3F)!0%Y zChH*C#$?};Wqu#t?{)qDnB{X_=X0Lt+~>aU=Q$?=rLW1#!p#BzVAZ;%b{haX=r6z? zfkWQ`#=S?OADHKDO;v#Zc7_5yFxac;sQ^$Gdvy09BlOJdcI&<;0BoNQKCpJz{6_$A zKG9NBG4g$|KxU4+OG;^8S*xRjh1s>|T5zEL;c{0I&7OEAe!4T?okv#c=8@M0b3_lj zCsB%>QR2t-9Eydww1^jaC6W-Lm!F<}?8fPBj=Cgbjj{&!IkWEPhQc2-$&aJE{nn{7 zE_;8SH}`0TjdkO-WJ!tDfTeWLZmpCUd|Zw0q)CKG!~+BXXNO-PjCBaq=tA>A`sMQx z6genu#zEl~n+P)@A8PcI1V*IGyuqgN5X6gCX{Fi z-3%~yEm8&oI6g6OuCWJ~kk@qDJB`RH$67U6n2{P52A8J;nX}q?eRkdHN)H-!@RX{` zr0T_C+szvP*+mPFrmtN~{x-q)msdP4vab+`{_h!K$4T$;0$v$wm@e z(8kTBI^D~7b}fZKxL{MBLQr3=UFuuvoW{7(HH)Iz326~vQ562lGC#!Hw8J;YvvA@&39M&GehC9Z5NsUUN5^ThRp^O1$O z)V(vF7OplXWwTULKgu+VBT9xVr4@}AHHDbMn2guVFpU(_xAam_G+#!%3%3gX?VS^ zZr9a7JaI^F1Kpi_{)_E+>Y|1p26=qK40ZQqDp2ru`7>mCkcp~en;1HoA)j=C z&`oBpG*OkGEIQHzw+f2zMg&@p6m8FF>XOgtx%5YHj#bSVkReB!>i9iqYkI>$PH>UX zMrO|C*V4SDhCe0A*kr%Kucg+Qy8L-^z+xsx1H<$K@-W1$jF>GRh305g3e!T5_||Qf z!tb7=vOTqHi!wuA%exwdjo)km5PH4?uK#)zP$qS|RiEkD6A(Cy&l;9v$gqtoT)WQ? zNs>L!al$Kv(D`d0in?JNp(1yoBojUn5Me9Fy4i9q$R~xpiSa2kQ*eLtL(6`0py0-< z{0TcryX%y(S>RV-Y1c|qbKRA@KcG2dg`5{}tGJIYL?d#`U zuJhN#9Lc~liWQZ@k>dtY{yY=7ZT2OyTV91xgT6BWahGJp>rbI3BVUTvrDc6X50pc* z8BHl-+Xr@A9#t)Q<-`!gK@1BV2)*n_k|Q>U?^wTI>GKALvbFiyfn_I!Qk}Vrr$Z)E zo*MBQzyRocod!Q8yK4ol-~}RYu=08~H~>U5v7Bu#~Gi!K3u`cmY_rn*_J zl6|5r?=)X9l)g;uz|VGGxwd)@1>H%pw8RH*=0^p}dT=d#0fCKOioGGhzPubDPHpj~ z+frb_*XNBP4c9+1E}D9{E2k?{@WJ>1@5IikMfaST|Hjpd0!3E0_FNspb=4s@rpOU6 zN5wj%!F5Wuf*xYMp}f>Sr@@se&)ubtdK1)&xkAWX)v!UavO!$SgZsO6U5eH^R?rIl z(qOfFZrn_)>-c}x)4EpWkfU&<(ocNwx3}oLPTa_-SS+62>hf7|HewYA3%qgehfH(r zqUmjQXJ9lE_FjrAcGq%N8h}@VH0K)6w)SDFW;f%hM}6NZ+VrKjtyAq^Qpw zAUp-8Nln2w!)qktrQW>w5afpT+NkxPx`QoImhF2qBJC0%&I^M9=6*lrH`MlYN;yh6 zh$pj%6*)!4E`4y4N%=ZL&VRdgvDx{>5rDL=c@6W#=_mg#N8J(Pb~5F*c;BHTd=DxM zb++fte;B%$sX_V?cID12DCo4!`m0Tx=VZCtp}Bf>k$bMrkNwo^&N@TB9}pD~VhJ<` zf`~0H`tK{AXA+bl5Gn)e#8LT-{1@d@7Os)=d3oqy08!AVh%GYMkL*%)phw+$8}lwM z&HFo0Z)tfYd&x?k#XGqE#9efu`_u>+XjJTagkEqL3=e_G3b_*2 zQ82

    Kh>erru# zVGP_Nc3GS#oTGxe5uldNmOm`#=S%6&i8soTS;q}o$>Zq)Gb_6zV^)DE7 zw-z@Z74m^haFN7gZubsTagGC=y}z#eW)~7$jG|X%muhtUDf_;UTotfE@dN(~+}j!Y zK2sAsp?4tg?dz}-$2l8~b>80^S#?URsNb_oFJ0+JYaUf~E)M_FcnY41=abNG1JezepJudMnLxt#nBf_X40bGM`e)9R24gFw|czddL&LPrfl?hI8@wR=JFOW!VBOJc*GW|G#) z+@+i4YzGBMg$m$oyp!dqy0hGT_M+FFrj8r;8bLEfMIc7S}j5_MJ;ZLsPfd8fj9As)9O{N=Y zo0#u?4dJQM2i_Ie{FOuIpOg!<8m~Sv?pdykFtW{hP@^c~YA4^boV;%-67l z8>chAdp+X`RqVE~Id4m!DZqneGM18qtm`7X87nhD#&V%(UfdJP2GO#uB_nh@=zn0^ z7Vbe8d-w5{*dGb}L%AA(ONYtnbudj_7G!t7pC2L=Q|)m5oeS{Meteu`em}Hg%Z2Yv zp*=SQo8-e66IAZM$(N(ce0G(_Eo{WwuWX4z-B8elfX|S9t#}-|x#$!#R-bKwt7^q z*BeN}8Gz71RyU&e%ui6v(a}bDZ5}_l=IL&-YdJ;kq5)~Z<i>U|z3=>09zlIjT&b zV_l7#W!J&28)w^=^K_#CU;Y%0T8x9jIq*gg+42fgo^!|YkTMm)0~KaQmOhfFMxTf@`TFRDZ57ziOb1S8KAx^?>j06eHg|+eP%-Jypr#8__DYE{_o&I&7$S`mg zXMWkI_Qde6e@2PJ6z$YfdV}4S(@TL;($e=ZU!y%O&qo@4K6Xk`p_2Kr^Y)iB>lH<0 zvHnvLTh7Dy+pJj3J?nD4y}kMMf*JnCl~|FAs~(-uLEkhW{ir)51&`eeKgQxj=ap(j zGsC5jPyZVq_?$=BrP`rhTMig&eW`RPb!NZrm;uzTv%mlmg}gjwh9#6Wh!k)b-?p%L z>u_pNxs=&={vAzr-1n!7JWKAs%es|^Z(|;;C`R;*f0{Alzao2cia#A{Eitd?Slq+; ze~~K&6j~L~>>0`rj$cB~XLbjDS}?0hHEgQ+5lu(Qh^H4`f4tuyF$D4lgc~2-3F=O# z@z3N|h^BqW1I0g&xHdAwP;;p#Ay}v2LV;eiWwGBc0$7kB)1-Ay%MBQWb-fPPPO|7}} zELn2nn>AV+1=X}q^kNNoPV29-b%s%%Ti}_alamb8c#YAnT}_kow~ndVQiN8#Hup)$ zl<+d&i#{_^2YNqvtY+2j3g)BlYjQ(78HULI5~{Ez3rIz@=3t*3!kO(LpTP^3=n$0U z>tx%$`NzQJbxjLyU;mVUoZn*j6$gO2|G#X3b}r3|te;2LizPcQny!@dFk+0LqvD#; zO?tQTXN}n$h1*QAsi|!@T%M^>wa@)9&*3?M6%=X(9xt`~%I&!uQdcY$?^2l42kL}_ z?#h6_|Nbdbo9l!x?e;CqH0Q8a2l?eF#@BMpHo`$E{MczH+5@Mql5gH0X6P9II=;KXJJabMQ#Kn~VR!37Dt9v6}49PTNfu_sCO87-l6A z1+xpRSUw$s#w2j%oTxooBL7QN&n@SOtrW4g1O`wp7#C#8@Ni8yy~DYH22*apb(Qtf zJIawOd&zwb1ayhwlBwAps>KGsIqe~aw7J>_^?+JBR5s7Cz9zRE6y{P-G^roFIk!SM zxU`DcRk!w%m4(hjrKYO0B2fQ8i7M;vE(+1lr0zuIVFUp{Nl*(Z%veQp)oM7tY8#?1BHY)>J+Ee%MGCWO7GMIT_OVFq&v_p)b;7RLan(`2Xr z8!eKNG_c^MZB#N~a Ht)BiLo}uJ< literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/table_header_down.png b/data/skins/cartoon-ruby/table_header_down.png new file mode 100644 index 0000000000000000000000000000000000000000..6f3e79476c4349e8fddc418c6bf4450c306fde71 GIT binary patch literal 829 zcmV-D1H$}?P)4Tx04UFukv&MmP!xqvQ>CI62P=p;1guULL`57m3Pq?8YK2xEOkVmUG-*gu zTpR`0f`dPcRR<1N7MX6hjRCsh zSjo5~rZX#I=oMWEAc7(EDat5osqSJt3;(NbEo(C%AQI0o({hN{iKjLl zlk+}tgcTHx_?&puq6Uc{xvu*B#yRh?z%wIODmh0SAr|vZtTr(#SUT|}aa7X{$`{f; zYn-<@>%}sw_sL%v&Kk>0T&FdNI2N!786s4av4J8S#Ar82v5};6sfB;Q^ULH?$+ZDS zj(L=zL-G9JfAD*@c5Y(aPYO#w`-|&-30Yqi@Opy|+N;sz0~-IZhvd6wNAe0~{Oz zBYDbRYw_-m=DGcO$D1FdA4rmNmeKKt0ssI232;bRa{vGf6951U69E94oEQKA0bWT& zK~!i%?U_Ap!!QhmDen#70O?Zqj@|65e|RTImhEJjN0!{^_$b(vFrg z&vVu<6-*XWk$I+%~vgzH|+hpVU zYy*=iQIEpr&hS4ku|k_Uz5{Nzv1ck)VB+k3Sb?7DiVZHt238@kNBEZ5cMFXO#W&e6 zXntl6`njDgkbzkE5W@zI#dP;Y11sMj*9;#c{soQ|0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<0A*R0_V|7DvF)eppZh(-%}P#DVW}V`)P%4;ypx zFQ6w9!psWS0hLFnJ~D>ECokZOM9#m&F#EzOVO^s4v10ZI)%Tz&NS{r%00000NkvXX Hu0mjfw*q9j literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ruby/up_arrow.png b/data/skins/cartoon-ruby/up_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..1e4a46b92819451dd5a9b8b47afc0f1a48d5d1ac GIT binary patch literal 3294 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 K(5}$3d--3r#x9Nk literal 0 HcmV?d00001 From d79cca3667af277469eb61740805b1193baa1b44 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 27 May 2024 12:08:08 +0200 Subject: [PATCH 415/830] Add a SKIN_MAKING.md file Instead of duplicating the general skin-making advice in all 12 stkskin.xml files, centralize it in one place. Also correct header comments regarding the theme names. --- data/skins/SKIN_MAKING.md | 79 ++++++++++++++++++++++++++ data/skins/cartoon-coal/stkskin.xml | 80 ++------------------------- data/skins/cartoon-desert/stkskin.xml | 76 +------------------------ data/skins/cartoon-forest/stkskin.xml | 69 ++--------------------- data/skins/cartoon-ocean/stkskin.xml | 78 ++------------------------ data/skins/cartoon-ruby/stkskin.xml | 16 ++---- data/skins/cartoon/stkskin.xml | 74 +------------------------ data/skins/coal/stkskin.xml | 76 +------------------------ data/skins/forest/stkskin.xml | 76 +------------------------ data/skins/ocean/stkskin.xml | 74 +------------------------ data/skins/peach/stkskin.xml | 74 +------------------------ data/skins/ruby/stkskin.xml | 77 +------------------------- 12 files changed, 110 insertions(+), 739 deletions(-) create mode 100644 data/skins/SKIN_MAKING.md diff --git a/data/skins/SKIN_MAKING.md b/data/skins/SKIN_MAKING.md new file mode 100644 index 00000000000..6a7a3b494f3 --- /dev/null +++ b/data/skins/SKIN_MAKING.md @@ -0,0 +1,79 @@ +# Making a skin + +To make your own skin, the easiest way is to start with the files from a standard skin +and modifying them as needed. + +There are two types of images : some will be simply stretched as a whole, others will +have non-stretchable borders (you cannot choose which one you must use, it's hardcoded +for each element type; though, as you will see below, for all "advanced stretching" images +you can easily fake "simple stretch") + +All elements will have at least 2 properties : + type="X" sets what you're skinning with this entry + image="skinDirectory/imageName.png" sets which image is used for this element + +Most elements also support states : + state="neutral" + state="focused" + state="down" +You can thus give different looks for different states. Not all widgets support all states, +see entries and comments below to know what's supported. +Note that checkboxes are an exception and have the following styles : + "neutral+unchecked" + "neutral+checked" + "focused+unchecked" + "focused+checked" + "deactivated+unchecked" + "deactivated+checked" + +"Advanced stretching" images are split this way : + + +----+--------------------+----+ + | | | | + +----+--------------------+----+ + | | | | + | | | | + | | | | + +----+--------------------+----+ + | | | | + +----+--------------------+----+ + +The center border will be stretched in all directions. The 4 corners will not stretch at all. +Horizontal borders will stretch horizontally, verticallt borders will stretch vertically. +Use properties left_border="X" right_border="X" top_border="X" bottom_border="X" to specify +the size of each border in pixels (setting all borders to '0' makes the whole image scaled). + +In some cases, you may not want vertical stretching to occur (like if the left and right sides +of the image must not be stretched vertically, e.g. for the spinner). In this case, pass +parameter preserve_h_aspect_ratios="true" to make the left and right areas stretch by keeping +their aspect ratio. + +Some components may fill the full inner area with stuff; others will only take a smaller +area at the center. To adjust for this, there are properties "hborder_out_portion" and "vborder_out_portion" +that take a float from 0 to 1, representing the percentage of each border that goes out of the widget's +area (this might include stuff like shadows, etc.). The 'h' one is for horizontal borders, +the 'v' one is for vertical borders. + +Finnally : the image is split, as shown above, into 9 areas. In some cases, you may not want +all areas to be rendered. Then you can pass parameter areas="body+left+right+top+bottom" +and explicitely specify which parts you want to see. The 4 corner areas are only visible +when the border that intersect at this corner are enabled. + +When there is a common="y" with image tag, the image will be loaded only from data/skins/common in stk-code. + +Any information not specified in the stkskin.xml file of a theme will be inherited from the specified +base theme, if any. To specify a base theme, add base_theme="themename" to the `` tag. + +To use an icon theme, place the replacement icons (PNG or SVG) into [skin folder]/data/gui/icons +STK will prefer these icons first, if not found it will fallback to icons from the base theme(s). + +For TTF specify the list like the following, for normal and digit ttf it will be added at the beginning of the +font list in STK, so those TTF will be used first, and any missing characters will be rendered from the base +theme font list. For color emoji ttf it will replace the base theme color emoji directly. You are not required +to specify all types of ttf. + +``` + +``` \ No newline at end of file diff --git a/data/skins/cartoon-coal/stkskin.xml b/data/skins/cartoon-coal/stkskin.xml index c34ca63210b..89f876d9398 100644 --- a/data/skins/cartoon-coal/stkskin.xml +++ b/data/skins/cartoon-coal/stkskin.xml @@ -1,87 +1,17 @@ diff --git a/data/skins/cartoon-desert/stkskin.xml b/data/skins/cartoon-desert/stkskin.xml index 33cf9f83752..29c17b7c41c 100644 --- a/data/skins/cartoon-desert/stkskin.xml +++ b/data/skins/cartoon-desert/stkskin.xml @@ -1,87 +1,17 @@ diff --git a/data/skins/cartoon-forest/stkskin.xml b/data/skins/cartoon-forest/stkskin.xml index 401bf313706..420730b4295 100644 --- a/data/skins/cartoon-forest/stkskin.xml +++ b/data/skins/cartoon-forest/stkskin.xml @@ -1,75 +1,14 @@ - + - + diff --git a/data/skins/cartoon-ruby/stkskin.xml b/data/skins/cartoon-ruby/stkskin.xml index aa9e01791cd..a47c24d1275 100644 --- a/data/skins/cartoon-ruby/stkskin.xml +++ b/data/skins/cartoon-ruby/stkskin.xml @@ -1,23 +1,17 @@ diff --git a/data/skins/cartoon/stkskin.xml b/data/skins/cartoon/stkskin.xml index 921076a23b3..d4f755353cd 100644 --- a/data/skins/cartoon/stkskin.xml +++ b/data/skins/cartoon/stkskin.xml @@ -3,85 +3,13 @@ Cartoon skin by LCP and QwertyChouskie, released under CC-BY-SA 4.0+ -To make your own skin, I suggest simply duplicating this file and modifying it as needed. -There are two types of images : some will be simply stretched as a whole, others will -have non-stretchable borders (you cannot choose which one you must use, it's hardcoded -for each element type; though, as you will see below, for all "advanced stretching" images -you can easily fake "simple stretch") - -All elements will have at least 2 properties : - type="X" sets what you're skinning with this entry - image="skinDirectory/imageName.png" sets which image is used for this element - -Most elements also support states : - state="neutral" - state="focused" - state="down" -You can thus give different looks for different states. Not all widgets support all states, -see entries and comments below to know what's supported. -Note that checkboxes are an exception and have the following styles : - "neutral+unchecked" - "neutral+checked" - "focused+unchecked" - "focused+checked" - "deactivated+unchecked" - "deactivated+checked" - -"Advanced stretching" images are split this way : - - +----+--------------------+----+ - | | | | - +----+--------------------+----+ - | | | | - | | | | - | | | | - +----+--------------------+----+ - | | | | - +----+--------------------+----+ - -The center border will be stretched in all directions. The 4 corners will not stretch at all. -Horizontal borders will stretch horizontally, verticallt borders will stretch vertically. -Use properties left_border="X" right_border="X" top_border="X" bottom_border="X" to specify -the size of each border in pixels (setting all borders to '0' makes the whole image scaled). - -In some cases, you may not want vertical stretching to occur (like if the left and right sides -of the image must not be stretched vertically, e.g. for the spinner). In this case, pass -parameter preserve_h_aspect_ratios="true" to make the left and right areas stretch by keeping -their aspect ratio. - -Some components may fill the full inner area with stuff; others will only take a smaller -area at the center. To adjust for this, there are properties "hborder_out_portion" and "vborder_out_portion" -that take a float from 0 to 1, representing the percentage of each border that goes out of the widget's -area (this might include stuff like shadows, etc.). The 'h' one is for horizontal borders, -the 'v' one is for vertical borders. - -Finnally : the image is split, as shown above, into 9 areas. In some cases, you may not want -all areas to be rendered. Then you can pass parameter areas="body+left+right+top+bottom" -and explicitely specify which parts you want to see. The 4 corner areas are only visible -when the border that intersect at this corner are enabled. - -When there is a common="y" with image tag, the image will be loaded only from data/skins/common in stk-code. - -Any information not specified in this theme will be inherited from the specified base theme, -if any. To specify a base theme, add base_theme="themename" to the tag. - -To use an icon theme, place the replacement icons (PNG or SVG) into [skin folder]/data/gui/icons -STK will prefer these icons first, if not found it will fallback to icons from the base theme(s). +See SKIN_MAKING.md for more details on how the skin elements work. --> diff --git a/data/skins/coal/stkskin.xml b/data/skins/coal/stkskin.xml index f31397dcdd1..7ace1643b65 100644 --- a/data/skins/coal/stkskin.xml +++ b/data/skins/coal/stkskin.xml @@ -1,90 +1,18 @@ diff --git a/data/skins/forest/stkskin.xml b/data/skins/forest/stkskin.xml index 161df29a3e0..393646f12ba 100644 --- a/data/skins/forest/stkskin.xml +++ b/data/skins/forest/stkskin.xml @@ -1,90 +1,18 @@ diff --git a/data/skins/ocean/stkskin.xml b/data/skins/ocean/stkskin.xml index c9e0ee36616..23c59605675 100644 --- a/data/skins/ocean/stkskin.xml +++ b/data/skins/ocean/stkskin.xml @@ -5,85 +5,13 @@ Ocean skin by Dakal and Marianne Gagnon, released under creative-commons BY-SA 3 Except background.jpg, by elisee Except stars, by s@f -To make your own skin, I suggest simply duplicating this file and modifying it as needed. -There are two types of images : some will be simply stretched as a whole, others will -have non-stretchable borders (you cannot choose which one you must use, it's hardcoded -for each element type; though, as you will see below, for all "advanced stretching" images -you can easily fake "simple stretch") - -All elements will have at least 2 properties : - type="X" sets what you're skinning with this entry - image="skinDirectory/imageName.png" sets which image is used for this element - -Most elements also support states : - state="neutral" - state="focused" - state="down" -You can thus give different looks for different states. Not all widgets support all states, -see entries and comments below to know what's supported. -Note that checkboxes are an exception and have the following styles : - "neutral+unchecked" - "neutral+checked" - "focused+unchecked" - "focused+checked" - "deactivated+unchecked" - "deactivated+checked" - -"Advanced stretching" images are split this way : - - +----+--------------------+----+ - | | | | - +----+--------------------+----+ - | | | | - | | | | - | | | | - +----+--------------------+----+ - | | | | - +----+--------------------+----+ - -The center border will be stretched in all directions. The 4 corners will not stretch at all. -Horizontal borders will stretch horizontally, verticallt borders will stretch vertically. -Use properties left_border="X" right_border="X" top_border="X" bottom_border="X" to specify -the size of each border in pixels (setting all borders to '0' makes the whole image scaled). - -In some cases, you may not want vertical stretching to occur (like if the left and right sides -of the image must not be stretched vertically, e.g. for the spinner). In this case, pass -parameter preserve_h_aspect_ratios="true" to make the left and right areas stretch by keeping -their aspect ratio. - -Some components may fill the full inner area with stuff; others will only take a smaller -area at the center. To adjust for this, there are properties "hborder_out_portion" and "vborder_out_portion" -that take a float from 0 to 1, representing the percentage of each border that goes out of the widget's -area (this might include stuff like shadows, etc.). The 'h' one is for horizontal borders, -the 'v' one is for vertical borders. - -Finnally : the image is split, as shown above, into 9 areas. In some cases, you may not want -all areas to be rendered. Then you can pass parameter areas="body+left+right+top+bottom" -and explicitely specify which parts you want to see. The 4 corner areas are only visible -when the border that intersect at this corner are enabled. - -When there is a common="y" with image tag, the image will be loaded only from data/skins/common in stk-code. - -Any information not specified in this theme will be inherited from the specified base theme, -if any. To specify a base theme, add base_theme="themename" to the tag. - -To use an icon theme, place the replacement icons (PNG or SVG) into [skin folder]/data/gui/icons -STK will prefer these icons first, if not found it will fallback to icons from the base theme(s). +See SKIN_MAKING.md for more details on how the skin elements work. --> diff --git a/data/skins/peach/stkskin.xml b/data/skins/peach/stkskin.xml index 4b63c08dd01..f39ded2b40e 100644 --- a/data/skins/peach/stkskin.xml +++ b/data/skins/peach/stkskin.xml @@ -5,85 +5,13 @@ Peach skin by Dakal and Marianne Gagnon, released under creative-commons BY-SA 3 Except background.jpg, by elisee Except stars, by s@f -To make your own skin, I suggest simply duplicating this file and modifying it as needed. -There are two types of images : some will be simply stretched as a whole, others will -have non-stretchable borders (you cannot choose which one you must use, it's hardcoded -for each element type; though, as you will see below, for all "advanced stretching" images -you can easily fake "simple stretch") - -All elements will have at least 2 properties : - type="X" sets what you're skinning with this entry - image="skinDirectory/imageName.png" sets which image is used for this element - -Most elements also support states : - state="neutral" - state="focused" - state="down" -You can thus give different looks for different states. Not all widgets support all states, -see entries and comments below to know what's supported. -Note that checkboxes are an exception and have the following styles : - "neutral+unchecked" - "neutral+checked" - "focused+unchecked" - "focused+checked" - "deactivated+unchecked" - "deactivated+checked" - -"Advanced stretching" images are split this way : - - +----+--------------------+----+ - | | | | - +----+--------------------+----+ - | | | | - | | | | - | | | | - +----+--------------------+----+ - | | | | - +----+--------------------+----+ - -The center border will be stretched in all directions. The 4 corners will not stretch at all. -Horizontal borders will stretch horizontally, verticallt borders will stretch vertically. -Use properties left_border="X" right_border="X" top_border="X" bottom_border="X" to specify -the size of each border in pixels (setting all borders to '0' makes the whole image scaled). - -In some cases, you may not want vertical stretching to occur (like if the left and right sides -of the image must not be stretched vertically, e.g. for the spinner). In this case, pass -parameter preserve_h_aspect_ratios="true" to make the left and right areas stretch by keeping -their aspect ratio. - -Some components may fill the full inner area with stuff; others will only take a smaller -area at the center. To adjust for this, there are properties "hborder_out_portion" and "vborder_out_portion" -that take a float from 0 to 1, representing the percentage of each border that goes out of the widget's -area (this might include stuff like shadows, etc.). The 'h' one is for horizontal borders, -the 'v' one is for vertical borders. - -Finnally : the image is split, as shown above, into 9 areas. In some cases, you may not want -all areas to be rendered. Then you can pass parameter areas="body+left+right+top+bottom" -and explicitely specify which parts you want to see. The 4 corner areas are only visible -when the border that intersect at this corner are enabled. - -When there is a common="y" with image tag, the image will be loaded only from data/skins/common in stk-code. - -Any information not specified in this theme will be inherited from the specified base theme, -if any. To specify a base theme, add base_theme="themename" to the tag. - -To use an icon theme, place the replacement icons (PNG or SVG) into [skin folder]/data/gui/icons -STK will prefer these icons first, if not found it will fallback to icons from the base theme(s). +See SKIN_MAKING.md for more details on how the skin elements work. --> diff --git a/data/skins/ruby/stkskin.xml b/data/skins/ruby/stkskin.xml index 6a265262e43..ec32beb3199 100644 --- a/data/skins/ruby/stkskin.xml +++ b/data/skins/ruby/stkskin.xml @@ -1,90 +1,19 @@ From 06d503a54b583bd885bdcd29f9cc6c90b3782329 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 27 May 2024 18:12:20 +0200 Subject: [PATCH 416/830] Use two distinct spinners to select skins - Use new 'base theme name' and 'variant name' values for skins to determine spinner values - Ensure the skin is correctly set based on the values of both spinners - Keep the options in the 'variant' spinners correct when updating the base spinner, as different base themes may have different variants (or no variants) - Many other small changes to make it all work smoothly. - Rename the folders of the classic skins, as the order of variants is determined by folder name alphabetic order. Using the same structure as with the cartoon skins ensure the variant order is the same. - Also remove some redundant comments that were missed in the previous commit. Remaining: - Tidying up the code - Ensure that if a variant exists in both the previous 'base theme' and the new 'base theme', switching the base theme while this variant is active doesn't reset to the default variant. --- data/gui/screens/options/options_ui.stkgui | 12 +- data/skins/cartoon-coal/stkskin.xml | 2 +- data/skins/cartoon-desert/stkskin.xml | 2 +- data/skins/cartoon-forest/stkskin.xml | 11 +- data/skins/cartoon-ocean/stkskin.xml | 2 +- data/skins/cartoon-ruby/stkskin.xml | 2 +- data/skins/cartoon/stkskin.xml | 2 +- data/skins/{coal => classic-coal}/License.txt | 0 .../{coal => classic-coal}/achievement.png | Bin .../{coal => classic-coal}/background.jpg | Bin .../{coal => classic-coal}/bottom_bar.png | Bin data/skins/{coal => classic-coal}/bubble.png | Bin data/skins/{coal => classic-coal}/dialog.png | Bin data/skins/{coal => classic-coal}/error.png | Bin data/skins/{coal => classic-coal}/friend.png | Bin data/skins/{coal => classic-coal}/generic.png | Bin .../glass_iconhighlight_focus.png | Bin .../{coal => classic-coal}/glass_rsection.png | Bin .../{coal => classic-coal}/glass_section.png | Bin .../{coal => classic-coal}/glassbutton.png | Bin .../glassbutton_focused.png | Bin .../{coal => classic-coal}/glasscheckbox.png | Bin .../glasscheckbox_checked.png | Bin .../glasscheckbox_checked_focus.png | Bin .../glasscheckbox_focus.png | Bin .../glasssgauge_fill.png | Bin .../glassspinner_down.png | Bin .../glassspinner_focus.png | Bin .../glassspinner_halo.png | Bin .../skins/{coal => classic-coal}/glasstab.png | Bin .../{coal => classic-coal}/glasstab_focus.png | Bin .../{coal => classic-coal}/glasstab_vert.png | Bin .../glasstab_vert_focus.png | Bin .../left_arrow_focus.png | Bin .../right_arrow_focus.png | Bin .../scrollbar_btn_down.png | Bin .../scrollbar_thumb.png | Bin data/skins/{coal => classic-coal}/select.png | Bin data/skins/{coal => classic-coal}/stkskin.xml | 2 +- .../{coal => classic-coal}/table_header.png | Bin .../table_header_down.png | Bin .../{coal => classic-coal}/textbubble.png | Bin .../{coal => classic-coal}/textbubble2.png | Bin data/skins/{coal => classic-coal}/tooltip.png | Bin .../{desert => classic-desert}/License.txt | 0 .../achievement.png | Bin .../{desert => classic-desert}/bubble.png | Bin .../{desert => classic-desert}/error.png | Bin .../{desert => classic-desert}/friend.png | Bin .../{desert => classic-desert}/generic.png | Bin .../glass_iconhighlight_focus.png | Bin .../glassbutton.png | Bin .../glassbutton_focused.png | Bin .../glasscheckbox.png | Bin .../glasscheckbox_checked.png | Bin .../glasscheckbox_checked_focus.png | Bin .../glasscheckbox_focus.png | Bin .../glasssgauge_fill.png | Bin .../glassspinner_down.png | Bin .../glassspinner_focus.png | Bin .../glassspinner_halo.png | Bin .../{desert => classic-desert}/glasstab.png | Bin .../glasstab_down.png | Bin .../glasstab_focus.png | Bin .../glasstab_vert.png | Bin .../glasstab_vert_down.png | Bin .../glasstab_vert_focus.png | Bin .../left_arrow_focus.png | Bin .../right_arrow_focus.png | Bin .../scrollbar_btn_down.png | Bin .../scrollbar_thumb.png | Bin .../{desert => classic-desert}/select.png | Bin data/skins/classic-desert/stkskin.xml | 269 ++++++++++++++ .../table_header_down.png | Bin .../{desert => classic-desert}/textbubble.png | Bin .../textbubble2.png | Bin .../{forest => classic-forest}/License.txt | 0 .../achievement.png | Bin .../{forest => classic-forest}/bubble.png | Bin .../{forest => classic-forest}/error.png | Bin .../{forest => classic-forest}/friend.png | Bin .../{forest => classic-forest}/generic.png | Bin .../glass_iconhighlight_focus.png | Bin .../glassbutton.png | Bin .../glassbutton_focused.png | Bin .../glasscheckbox.png | Bin .../glasscheckbox_checked.png | Bin .../glasscheckbox_checked_focus.png | Bin .../glasscheckbox_focus.png | Bin .../glasssgauge_fill.png | Bin .../glassspinner_down.png | Bin .../glassspinner_focus.png | Bin .../glassspinner_halo.png | Bin .../{forest => classic-forest}/glasstab.png | Bin .../glasstab_focus.png | Bin .../glasstab_vert.png | Bin .../glasstab_vert_focus.png | Bin .../left_arrow_focus.png | Bin .../right_arrow_focus.png | Bin .../scrollbar_btn_down.png | Bin .../scrollbar_thumb.png | Bin .../{forest => classic-forest}/select.png | Bin .../{forest => classic-forest}/stkskin.xml | 2 +- .../table_header_down.png | Bin .../{forest => classic-forest}/textbubble.png | Bin .../textbubble2.png | Bin .../{ocean => classic-ocean}/License.txt | 0 .../{ocean => classic-ocean}/achievement.png | Bin .../skins/{ocean => classic-ocean}/bubble.png | Bin data/skins/{ocean => classic-ocean}/error.png | Bin .../skins/{ocean => classic-ocean}/friend.png | Bin .../{ocean => classic-ocean}/generic.png | Bin .../glass_iconhighlight_focus.png | Bin .../{ocean => classic-ocean}/glassbutton.png | Bin .../glassbutton_focused.png | Bin .../glasscheckbox.png | Bin .../glasscheckbox_checked.png | Bin .../glasscheckbox_checked_focus.png | Bin .../glasscheckbox_focus.png | Bin .../glasssgauge_fill.png | Bin .../glassspinner_down.png | Bin .../glassspinner_focus.png | Bin .../glassspinner_halo.png | Bin .../{ocean => classic-ocean}/glasstab.png | Bin .../glasstab_focus.png | Bin .../glasstab_vert.png | Bin .../glasstab_vert_focus.png | Bin .../left_arrow_focus.png | Bin .../right_arrow_focus.png | Bin .../scrollbar_btn_down.png | Bin .../scrollbar_thumb.png | Bin .../skins/{ocean => classic-ocean}/select.png | Bin .../{ocean => classic-ocean}/stkskin.xml | 2 +- .../table_header_down.png | Bin .../{ocean => classic-ocean}/textbubble.png | Bin .../{ocean => classic-ocean}/textbubble2.png | Bin .../skins/{peach => classic-ruby}/License.txt | 0 .../{ruby => classic-ruby}/achievement.png | Bin data/skins/{ruby => classic-ruby}/bubble.png | Bin data/skins/{ruby => classic-ruby}/error.png | Bin data/skins/{ruby => classic-ruby}/friend.png | Bin data/skins/{ruby => classic-ruby}/generic.png | Bin .../glass_iconhighlight_focus.png | Bin .../{ruby => classic-ruby}/glassbutton.png | Bin .../glassbutton_focused.png | Bin .../{ruby => classic-ruby}/glasscheckbox.png | Bin .../glasscheckbox_checked.png | Bin .../glasscheckbox_checked_focus.png | Bin .../glasscheckbox_focus.png | Bin .../glasssgauge_fill.png | Bin .../glassspinner_down.png | Bin .../glassspinner_focus.png | Bin .../glassspinner_halo.png | Bin .../skins/{ruby => classic-ruby}/glasstab.png | Bin .../{ruby => classic-ruby}/glasstab_down.png | Bin .../{ruby => classic-ruby}/glasstab_focus.png | Bin .../{ruby => classic-ruby}/glasstab_vert.png | Bin .../glasstab_vert_down.png | Bin .../glasstab_vert_focus.png | Bin .../left_arrow_focus.png | Bin .../right_arrow_focus.png | Bin .../scrollbar_btn_down.png | Bin .../scrollbar_thumb.png | Bin data/skins/{ruby => classic-ruby}/select.png | Bin data/skins/{ruby => classic-ruby}/stkskin.xml | 2 +- .../table_header_down.png | Bin .../{ruby => classic-ruby}/textbubble.png | Bin .../{ruby => classic-ruby}/textbubble2.png | Bin data/skins/{ruby => classic}/License.txt | 0 data/skins/{peach => classic}/achievement.png | Bin data/skins/{peach => classic}/bubble.png | Bin data/skins/{peach => classic}/error.png | Bin data/skins/{peach => classic}/friend.png | Bin data/skins/{peach => classic}/generic.png | Bin .../glass_iconhighlight_focus.png | Bin data/skins/{peach => classic}/glassbutton.png | Bin .../glassbutton_focused.png | Bin .../{peach => classic}/glasscheckbox.png | Bin .../glasscheckbox_checked.png | Bin .../glasscheckbox_checked_focus.png | Bin .../glasscheckbox_focus.png | Bin .../{peach => classic}/glasssgauge_fill.png | Bin .../{peach => classic}/glassspinner_down.png | Bin .../{peach => classic}/glassspinner_focus.png | Bin .../{peach => classic}/glassspinner_halo.png | Bin data/skins/{peach => classic}/glasstab.png | Bin .../{peach => classic}/glasstab_down.png | Bin .../{peach => classic}/glasstab_focus.png | Bin .../{peach => classic}/glasstab_vert.png | Bin .../{peach => classic}/glasstab_vert_down.png | Bin .../glasstab_vert_focus.png | Bin .../{peach => classic}/left_arrow_focus.png | Bin .../{peach => classic}/right_arrow_focus.png | Bin .../{peach => classic}/scrollbar_btn_down.png | Bin .../{peach => classic}/scrollbar_thumb.png | Bin data/skins/{peach => classic}/select.png | Bin data/skins/{peach => classic}/stkskin.xml | 2 +- .../{peach => classic}/table_header_down.png | Bin data/skins/{peach => classic}/textbubble.png | Bin data/skins/{peach => classic}/textbubble2.png | Bin data/skins/desert/stkskin.xml | 340 ------------------ src/config/user_config.hpp | 2 +- .../options/options_screen_ui.cpp | 289 ++++++++++----- .../options/options_screen_ui.hpp | 19 +- 204 files changed, 515 insertions(+), 447 deletions(-) rename data/skins/{coal => classic-coal}/License.txt (100%) rename data/skins/{coal => classic-coal}/achievement.png (100%) rename data/skins/{coal => classic-coal}/background.jpg (100%) rename data/skins/{coal => classic-coal}/bottom_bar.png (100%) rename data/skins/{coal => classic-coal}/bubble.png (100%) rename data/skins/{coal => classic-coal}/dialog.png (100%) rename data/skins/{coal => classic-coal}/error.png (100%) rename data/skins/{coal => classic-coal}/friend.png (100%) rename data/skins/{coal => classic-coal}/generic.png (100%) rename data/skins/{coal => classic-coal}/glass_iconhighlight_focus.png (100%) rename data/skins/{coal => classic-coal}/glass_rsection.png (100%) rename data/skins/{coal => classic-coal}/glass_section.png (100%) rename data/skins/{coal => classic-coal}/glassbutton.png (100%) rename data/skins/{coal => classic-coal}/glassbutton_focused.png (100%) rename data/skins/{coal => classic-coal}/glasscheckbox.png (100%) rename data/skins/{coal => classic-coal}/glasscheckbox_checked.png (100%) rename data/skins/{coal => classic-coal}/glasscheckbox_checked_focus.png (100%) rename data/skins/{coal => classic-coal}/glasscheckbox_focus.png (100%) rename data/skins/{coal => classic-coal}/glasssgauge_fill.png (100%) rename data/skins/{coal => classic-coal}/glassspinner_down.png (100%) rename data/skins/{coal => classic-coal}/glassspinner_focus.png (100%) rename data/skins/{coal => classic-coal}/glassspinner_halo.png (100%) rename data/skins/{coal => classic-coal}/glasstab.png (100%) rename data/skins/{coal => classic-coal}/glasstab_focus.png (100%) rename data/skins/{coal => classic-coal}/glasstab_vert.png (100%) rename data/skins/{coal => classic-coal}/glasstab_vert_focus.png (100%) rename data/skins/{coal => classic-coal}/left_arrow_focus.png (100%) rename data/skins/{coal => classic-coal}/right_arrow_focus.png (100%) rename data/skins/{coal => classic-coal}/scrollbar_btn_down.png (100%) rename data/skins/{coal => classic-coal}/scrollbar_thumb.png (100%) rename data/skins/{coal => classic-coal}/select.png (100%) rename data/skins/{coal => classic-coal}/stkskin.xml (99%) rename data/skins/{coal => classic-coal}/table_header.png (100%) rename data/skins/{coal => classic-coal}/table_header_down.png (100%) rename data/skins/{coal => classic-coal}/textbubble.png (100%) rename data/skins/{coal => classic-coal}/textbubble2.png (100%) rename data/skins/{coal => classic-coal}/tooltip.png (100%) rename data/skins/{desert => classic-desert}/License.txt (100%) rename data/skins/{desert => classic-desert}/achievement.png (100%) rename data/skins/{desert => classic-desert}/bubble.png (100%) rename data/skins/{desert => classic-desert}/error.png (100%) rename data/skins/{desert => classic-desert}/friend.png (100%) rename data/skins/{desert => classic-desert}/generic.png (100%) rename data/skins/{desert => classic-desert}/glass_iconhighlight_focus.png (100%) rename data/skins/{desert => classic-desert}/glassbutton.png (100%) rename data/skins/{desert => classic-desert}/glassbutton_focused.png (100%) rename data/skins/{desert => classic-desert}/glasscheckbox.png (100%) rename data/skins/{desert => classic-desert}/glasscheckbox_checked.png (100%) rename data/skins/{desert => classic-desert}/glasscheckbox_checked_focus.png (100%) rename data/skins/{desert => classic-desert}/glasscheckbox_focus.png (100%) rename data/skins/{desert => classic-desert}/glasssgauge_fill.png (100%) rename data/skins/{desert => classic-desert}/glassspinner_down.png (100%) rename data/skins/{desert => classic-desert}/glassspinner_focus.png (100%) rename data/skins/{desert => classic-desert}/glassspinner_halo.png (100%) rename data/skins/{desert => classic-desert}/glasstab.png (100%) rename data/skins/{desert => classic-desert}/glasstab_down.png (100%) rename data/skins/{desert => classic-desert}/glasstab_focus.png (100%) rename data/skins/{desert => classic-desert}/glasstab_vert.png (100%) rename data/skins/{desert => classic-desert}/glasstab_vert_down.png (100%) rename data/skins/{desert => classic-desert}/glasstab_vert_focus.png (100%) rename data/skins/{desert => classic-desert}/left_arrow_focus.png (100%) rename data/skins/{desert => classic-desert}/right_arrow_focus.png (100%) rename data/skins/{desert => classic-desert}/scrollbar_btn_down.png (100%) rename data/skins/{desert => classic-desert}/scrollbar_thumb.png (100%) rename data/skins/{desert => classic-desert}/select.png (100%) create mode 100644 data/skins/classic-desert/stkskin.xml rename data/skins/{desert => classic-desert}/table_header_down.png (100%) rename data/skins/{desert => classic-desert}/textbubble.png (100%) rename data/skins/{desert => classic-desert}/textbubble2.png (100%) rename data/skins/{forest => classic-forest}/License.txt (100%) rename data/skins/{forest => classic-forest}/achievement.png (100%) rename data/skins/{forest => classic-forest}/bubble.png (100%) rename data/skins/{forest => classic-forest}/error.png (100%) rename data/skins/{forest => classic-forest}/friend.png (100%) rename data/skins/{forest => classic-forest}/generic.png (100%) rename data/skins/{forest => classic-forest}/glass_iconhighlight_focus.png (100%) rename data/skins/{forest => classic-forest}/glassbutton.png (100%) rename data/skins/{forest => classic-forest}/glassbutton_focused.png (100%) rename data/skins/{forest => classic-forest}/glasscheckbox.png (100%) rename data/skins/{forest => classic-forest}/glasscheckbox_checked.png (100%) rename data/skins/{forest => classic-forest}/glasscheckbox_checked_focus.png (100%) rename data/skins/{forest => classic-forest}/glasscheckbox_focus.png (100%) rename data/skins/{forest => classic-forest}/glasssgauge_fill.png (100%) rename data/skins/{forest => classic-forest}/glassspinner_down.png (100%) rename data/skins/{forest => classic-forest}/glassspinner_focus.png (100%) rename data/skins/{forest => classic-forest}/glassspinner_halo.png (100%) rename data/skins/{forest => classic-forest}/glasstab.png (100%) rename data/skins/{forest => classic-forest}/glasstab_focus.png (100%) rename data/skins/{forest => classic-forest}/glasstab_vert.png (100%) rename data/skins/{forest => classic-forest}/glasstab_vert_focus.png (100%) rename data/skins/{forest => classic-forest}/left_arrow_focus.png (100%) rename data/skins/{forest => classic-forest}/right_arrow_focus.png (100%) rename data/skins/{forest => classic-forest}/scrollbar_btn_down.png (100%) rename data/skins/{forest => classic-forest}/scrollbar_thumb.png (100%) rename data/skins/{forest => classic-forest}/select.png (100%) rename data/skins/{forest => classic-forest}/stkskin.xml (99%) rename data/skins/{forest => classic-forest}/table_header_down.png (100%) rename data/skins/{forest => classic-forest}/textbubble.png (100%) rename data/skins/{forest => classic-forest}/textbubble2.png (100%) rename data/skins/{ocean => classic-ocean}/License.txt (100%) rename data/skins/{ocean => classic-ocean}/achievement.png (100%) rename data/skins/{ocean => classic-ocean}/bubble.png (100%) rename data/skins/{ocean => classic-ocean}/error.png (100%) rename data/skins/{ocean => classic-ocean}/friend.png (100%) rename data/skins/{ocean => classic-ocean}/generic.png (100%) rename data/skins/{ocean => classic-ocean}/glass_iconhighlight_focus.png (100%) rename data/skins/{ocean => classic-ocean}/glassbutton.png (100%) rename data/skins/{ocean => classic-ocean}/glassbutton_focused.png (100%) rename data/skins/{ocean => classic-ocean}/glasscheckbox.png (100%) rename data/skins/{ocean => classic-ocean}/glasscheckbox_checked.png (100%) rename data/skins/{ocean => classic-ocean}/glasscheckbox_checked_focus.png (100%) rename data/skins/{ocean => classic-ocean}/glasscheckbox_focus.png (100%) rename data/skins/{ocean => classic-ocean}/glasssgauge_fill.png (100%) rename data/skins/{ocean => classic-ocean}/glassspinner_down.png (100%) rename data/skins/{ocean => classic-ocean}/glassspinner_focus.png (100%) rename data/skins/{ocean => classic-ocean}/glassspinner_halo.png (100%) rename data/skins/{ocean => classic-ocean}/glasstab.png (100%) rename data/skins/{ocean => classic-ocean}/glasstab_focus.png (100%) rename data/skins/{ocean => classic-ocean}/glasstab_vert.png (100%) rename data/skins/{ocean => classic-ocean}/glasstab_vert_focus.png (100%) rename data/skins/{ocean => classic-ocean}/left_arrow_focus.png (100%) rename data/skins/{ocean => classic-ocean}/right_arrow_focus.png (100%) rename data/skins/{ocean => classic-ocean}/scrollbar_btn_down.png (100%) rename data/skins/{ocean => classic-ocean}/scrollbar_thumb.png (100%) rename data/skins/{ocean => classic-ocean}/select.png (100%) rename data/skins/{ocean => classic-ocean}/stkskin.xml (99%) rename data/skins/{ocean => classic-ocean}/table_header_down.png (100%) rename data/skins/{ocean => classic-ocean}/textbubble.png (100%) rename data/skins/{ocean => classic-ocean}/textbubble2.png (100%) rename data/skins/{peach => classic-ruby}/License.txt (100%) rename data/skins/{ruby => classic-ruby}/achievement.png (100%) rename data/skins/{ruby => classic-ruby}/bubble.png (100%) rename data/skins/{ruby => classic-ruby}/error.png (100%) rename data/skins/{ruby => classic-ruby}/friend.png (100%) rename data/skins/{ruby => classic-ruby}/generic.png (100%) rename data/skins/{ruby => classic-ruby}/glass_iconhighlight_focus.png (100%) rename data/skins/{ruby => classic-ruby}/glassbutton.png (100%) rename data/skins/{ruby => classic-ruby}/glassbutton_focused.png (100%) rename data/skins/{ruby => classic-ruby}/glasscheckbox.png (100%) rename data/skins/{ruby => classic-ruby}/glasscheckbox_checked.png (100%) rename data/skins/{ruby => classic-ruby}/glasscheckbox_checked_focus.png (100%) rename data/skins/{ruby => classic-ruby}/glasscheckbox_focus.png (100%) rename data/skins/{ruby => classic-ruby}/glasssgauge_fill.png (100%) rename data/skins/{ruby => classic-ruby}/glassspinner_down.png (100%) rename data/skins/{ruby => classic-ruby}/glassspinner_focus.png (100%) rename data/skins/{ruby => classic-ruby}/glassspinner_halo.png (100%) rename data/skins/{ruby => classic-ruby}/glasstab.png (100%) rename data/skins/{ruby => classic-ruby}/glasstab_down.png (100%) rename data/skins/{ruby => classic-ruby}/glasstab_focus.png (100%) rename data/skins/{ruby => classic-ruby}/glasstab_vert.png (100%) rename data/skins/{ruby => classic-ruby}/glasstab_vert_down.png (100%) rename data/skins/{ruby => classic-ruby}/glasstab_vert_focus.png (100%) rename data/skins/{ruby => classic-ruby}/left_arrow_focus.png (100%) rename data/skins/{ruby => classic-ruby}/right_arrow_focus.png (100%) rename data/skins/{ruby => classic-ruby}/scrollbar_btn_down.png (100%) rename data/skins/{ruby => classic-ruby}/scrollbar_thumb.png (100%) rename data/skins/{ruby => classic-ruby}/select.png (100%) rename data/skins/{ruby => classic-ruby}/stkskin.xml (99%) rename data/skins/{ruby => classic-ruby}/table_header_down.png (100%) rename data/skins/{ruby => classic-ruby}/textbubble.png (100%) rename data/skins/{ruby => classic-ruby}/textbubble2.png (100%) rename data/skins/{ruby => classic}/License.txt (100%) rename data/skins/{peach => classic}/achievement.png (100%) rename data/skins/{peach => classic}/bubble.png (100%) rename data/skins/{peach => classic}/error.png (100%) rename data/skins/{peach => classic}/friend.png (100%) rename data/skins/{peach => classic}/generic.png (100%) rename data/skins/{peach => classic}/glass_iconhighlight_focus.png (100%) rename data/skins/{peach => classic}/glassbutton.png (100%) rename data/skins/{peach => classic}/glassbutton_focused.png (100%) rename data/skins/{peach => classic}/glasscheckbox.png (100%) rename data/skins/{peach => classic}/glasscheckbox_checked.png (100%) rename data/skins/{peach => classic}/glasscheckbox_checked_focus.png (100%) rename data/skins/{peach => classic}/glasscheckbox_focus.png (100%) rename data/skins/{peach => classic}/glasssgauge_fill.png (100%) rename data/skins/{peach => classic}/glassspinner_down.png (100%) rename data/skins/{peach => classic}/glassspinner_focus.png (100%) rename data/skins/{peach => classic}/glassspinner_halo.png (100%) rename data/skins/{peach => classic}/glasstab.png (100%) rename data/skins/{peach => classic}/glasstab_down.png (100%) rename data/skins/{peach => classic}/glasstab_focus.png (100%) rename data/skins/{peach => classic}/glasstab_vert.png (100%) rename data/skins/{peach => classic}/glasstab_vert_down.png (100%) rename data/skins/{peach => classic}/glasstab_vert_focus.png (100%) rename data/skins/{peach => classic}/left_arrow_focus.png (100%) rename data/skins/{peach => classic}/right_arrow_focus.png (100%) rename data/skins/{peach => classic}/scrollbar_btn_down.png (100%) rename data/skins/{peach => classic}/scrollbar_thumb.png (100%) rename data/skins/{peach => classic}/select.png (100%) rename data/skins/{peach => classic}/stkskin.xml (99%) rename data/skins/{peach => classic}/table_header_down.png (100%) rename data/skins/{peach => classic}/textbubble.png (100%) rename data/skins/{peach => classic}/textbubble2.png (100%) delete mode 100644 data/skins/desert/stkskin.xml diff --git a/data/gui/screens/options/options_ui.stkgui b/data/gui/screens/options/options_ui.stkgui index cbab4d55bfb..9685dbc8279 100644 --- a/data/gui/screens/options/options_ui.stkgui +++ b/data/gui/screens/options/options_ui.stkgui @@ -34,12 +34,20 @@
    - +
    +
    + +
    + + + +
    diff --git a/src/states_screens/options/options_screen_video.cpp b/src/states_screens/options/options_screen_video.cpp index 55a45f611c9..98807468938 100644 --- a/src/states_screens/options/options_screen_video.cpp +++ b/src/states_screens/options/options_screen_video.cpp @@ -673,10 +673,10 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name, RaceManager::get()->scheduleBenchmark(); #endif } // benchmarkCurrent - else if (name == "benchmarkRecommend") + /*else if (name == "benchmarkRecommend") { new RecommendVideoSettingsDialog(0.8f, 0.9f); - } // benchmarkRecommend + }*/ // benchmarkRecommend } // eventCallback // -------------------------------------------------------------------------------------------- diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 48e76eff8c7..35e1ffdb256 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -1013,7 +1013,7 @@ void RaceResultGUI::determineTableLayout() r = m_font->getDimension(L"Y"); m_distance_between_rows = (int)(1.5f*r.Height); m_distance_between_meta_rows = m_distance_between_rows; - + // If there are too many highscores, reduce size between rows Highscores* scores = World::getWorld()->getHighscores(); if (scores != NULL && @@ -1926,15 +1926,28 @@ void RaceResultGUI::displayPostRaceInfo() if (RaceManager::get()->isBenchmarking()) return; - int current_y = displayHighscores(x, y); + int size_esti = 1 + World::getWorld()->getHighscores()->getNumberEntries(); + + if (!RaceManager::get()->isSoccerMode()) + size_esti += RaceManager::get()->modeHasLaps() ? 4 : 2; + + if (RaceManager::get()->raceWasStartedFromOverworld()) + size_esti += 3; + + int size_esti_real = size_esti * m_distance_between_meta_rows; + + int current_y = displayHighscores(x, y, + size_esti_real > UserConfigParams::m_height * 0.7f); // Display the number of laps, difficulty, and the best lap time if applicable if (!RaceManager::get()->isSoccerMode()) - current_y = displayLapDifficulty(x, current_y); + current_y = displayLapDifficulty(x, current_y, + size_esti_real > UserConfigParams::m_height * 0.8f); // Display challenge result and goals if (RaceManager::get()->raceWasStartedFromOverworld()) - current_y = displayChallengeInfo(x, current_y); + current_y = displayChallengeInfo(x, current_y, + size_esti_real > UserConfigParams::m_height * 0.85f); #endif } // displayPostRaceInfo @@ -1944,7 +1957,7 @@ void RaceResultGUI::displayPostRaceInfo() * be properly positioned vertically. * \param x Left limit of the highscore display area * \param y Top limit of the highscore display area */ -int RaceResultGUI::displayHighscores(int x, int y) +int RaceResultGUI::displayHighscores(int x, int y, bool increase_density) { #ifndef SERVER_ONLY Highscores* scores = World::getWorld()->getHighscores(); @@ -1972,6 +1985,8 @@ int RaceResultGUI::displayHighscores(int x, int y) if (max_width < 15) max_characters = max_width; + int width_icon_adjusted = increase_density ? m_width_icon * 0.8f : m_width_icon; + float time; for (int i = 0; i < scores->getNumberEntries(); i++) { @@ -1989,7 +2004,9 @@ int RaceResultGUI::displayHighscores(int x, int y) } int current_x = x; - current_y = y + (int)((i + 1) * m_distance_between_meta_rows); + current_y = y + m_distance_between_meta_rows + + (int)(i * m_distance_between_meta_rows + * (increase_density ? 0.8f : 1.0f)); const KartProperties* prop = kart_properties_manager->getKart(kart_name); if (prop != NULL) @@ -2003,12 +2020,12 @@ int RaceResultGUI::displayHighscores(int x, int y) kart_icon_texture->getSize()); core::recti dest_rect(current_x, current_y, - current_x + m_width_icon, current_y + m_width_icon); + current_x + width_icon_adjusted, current_y + width_icon_adjusted); draw2DImage(kart_icon_texture, dest_rect, source_rect, NULL, NULL, true); - current_x += m_width_icon + m_width_column_space; + current_x += width_icon_adjusted + m_width_column_space; } } @@ -2040,19 +2057,22 @@ int RaceResultGUI::displayHighscores(int x, int y) * so that other elements can be properly positioned vertically. * \param x Left limit of the highscore display area * \param y Top limit of the highscore display area */ -int RaceResultGUI::displayLapDifficulty(int x, int y) +int RaceResultGUI::displayLapDifficulty(int x, int y, bool increase_density) { #ifndef SERVER_ONLY video::SColor white_color = video::SColor(255, 255, 255, 255); int current_y = y; int time_precision = RaceManager::get()->currentModeTimePrecision(); + irr::gui::ScalableFont *the_font = increase_density ? GUIEngine::getSmallFont() : GUIEngine::getFont(); + const int line_height = m_distance_between_meta_rows * 0.8f * (increase_density ? 0.8f : 1.0f); + // display lap count if (RaceManager::get()->modeHasLaps()) { core::stringw laps = _("Laps: %i", RaceManager::get()->getNumLaps()); - current_y += int(m_distance_between_meta_rows * 0.8f * 2); - GUIEngine::getFont()->draw(laps, + current_y += int(line_height * 1.6f); + the_font->draw(laps, // 0.96 from stkgui core::recti(x, current_y, UserConfigParams::m_width * 0.96f, current_y + GUIEngine::getFontHeight()), white_color, false, false, nullptr, true); @@ -2076,7 +2096,7 @@ int RaceResultGUI::displayLapDifficulty(int x, int y) if (difficulty_one.empty()) { difficulty_one = RaceManager::get()->getDifficultyName((RaceManager::Difficulty)rd.m_difficulty); - core::dimension2d dim_1 = m_font->getDimension(difficulty_one.c_str()); + core::dimension2d dim_1 = the_font->getDimension(difficulty_one.c_str()); RowInfo* ri_1 = &(m_all_row_infos[k]); diff_ghost_one.UpperLeftCorner.X = ri_1->m_x_pos + m_width_icon + m_width_kart_name + m_width_finish_time + m_width_column_space + 20; diff_ghost_one.UpperLeftCorner.Y = ri_1->m_y_pos; @@ -2086,7 +2106,7 @@ int RaceResultGUI::displayLapDifficulty(int x, int y) else if (difficulty_two.empty()) { difficulty_two = RaceManager::get()->getDifficultyName((RaceManager::Difficulty)rd.m_difficulty); - core::dimension2d dim_2 = m_font->getDimension(difficulty_two.c_str()); + core::dimension2d dim_2 = the_font->getDimension(difficulty_two.c_str()); RowInfo* ri_2 = &(m_all_row_infos[k]); diff_ghost_two.UpperLeftCorner.X = ri_2->m_x_pos + m_width_icon + m_width_kart_name + m_width_finish_time + m_width_column_space + 20; diff_ghost_two.UpperLeftCorner.Y = ri_2->m_y_pos; @@ -2100,12 +2120,12 @@ int RaceResultGUI::displayLapDifficulty(int x, int y) difficulty_name = difficulty_one; // Left side difficulty display - m_font->draw(difficulty_one, diff_ghost_one, video::SColor(255, 255, 255, 255), false, false, nullptr, true); - m_font->draw(difficulty_two, diff_ghost_two, video::SColor(255, 255, 255, 255), false, false, nullptr, true); + the_font->draw(difficulty_one, diff_ghost_one, video::SColor(255, 255, 255, 255), false, false, nullptr, true); + the_font->draw(difficulty_two, diff_ghost_two, video::SColor(255, 255, 255, 255), false, false, nullptr, true); } core::stringw difficulty_string = _("Difficulty: %s", difficulty_name); - current_y += int(m_distance_between_meta_rows * 0.8f); - GUIEngine::getFont()->draw(difficulty_string, + current_y += line_height; + the_font->draw(difficulty_string, // 0.96 from stkgui core::recti(x, current_y, UserConfigParams::m_width * 0.96f, current_y + GUIEngine::getFontHeight()), white_color, false, false, nullptr, true); @@ -2120,8 +2140,8 @@ int RaceResultGUI::displayLapDifficulty(int x, int y) { core::stringw best_lap_string = _("Best lap time: %s", StringUtils::timeToString(best_lap_time, time_precision).c_str()); - current_y += int(m_distance_between_meta_rows * 0.8f); - GUIEngine::getFont()->draw(best_lap_string, + current_y += line_height; + the_font->draw(best_lap_string, // 0.96 from stkgui core::recti(x, current_y, UserConfigParams::m_width * 0.96f, current_y + GUIEngine::getFontHeight()), white_color, false, false, nullptr, true); @@ -2133,8 +2153,8 @@ int RaceResultGUI::displayLapDifficulty(int x, int y) //I18N: is used to indicate who has the bast laptime (best laptime "by kart_name") core::stringw best_lap_by_string = _("by %s", best_lap_by); // Make it closer to the above line - current_y += int(GUIEngine::getFontHeight() * 0.8f); - GUIEngine::getFont()->draw(best_lap_by_string, + current_y += int(line_height * 0.8f); + the_font->draw(best_lap_by_string, // 0.96 from stkgui core::recti(x, current_y, UserConfigParams::m_width * 0.96f, current_y + GUIEngine::getFontHeight()), white_color, false, false, @@ -2153,7 +2173,7 @@ int RaceResultGUI::displayLapDifficulty(int x, int y) * "best while slower" requirements have been met. * \param x Left limit of the highscore display area * \param y Top limit of the highscore display area */ -int RaceResultGUI::displayChallengeInfo(int x, int y) +int RaceResultGUI::displayChallengeInfo(int x, int y, bool increase_density) { #ifndef SERVER_ONLY int current_y = y; @@ -2164,8 +2184,6 @@ int RaceResultGUI::displayChallengeInfo(int x, int y) return current_y; // Display challenge result and goals - current_y += int(m_distance_between_meta_rows * 0.4f); - const ChallengeStatus* c_stat = PlayerManager::getCurrentPlayer()->getCurrentChallengeStatus(); if (!c_stat) return current_y; @@ -2209,11 +2227,16 @@ int RaceResultGUI::displayChallengeInfo(int x, int y) core::stringw text_string = all_passed ? _("You completed the challenge!") : _("You failed the challenge!"); video::SColor text_color = all_passed ? win_color : lose_color; - current_y += int(m_distance_between_meta_rows * 0.8f); + + current_y += int(m_distance_between_meta_rows); + GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, y + GUIEngine::getFontHeight()), text_color, false, false, nullptr, true); - current_y += int(m_distance_between_meta_rows * 0.2f); + current_y += int(m_distance_between_meta_rows); + + irr::gui::ScalableFont *the_font = increase_density ? GUIEngine::getSmallFont() : GUIEngine::getFont(); + const int line_height = m_distance_between_meta_rows * 0.8f * (increase_density ? 0.8f : 1.0f); // Display goals if (c_data->getMaxPosition(difficulty) != -1) @@ -2224,18 +2247,20 @@ int RaceResultGUI::displayChallengeInfo(int x, int y) text_string = _("Required Rank: %i", r); text_color = position_passed ? win_color : lose_color; - current_y += int(m_distance_between_meta_rows * 0.7f); - GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, - y + GUIEngine::getSmallFontHeight()), text_color, false, false, nullptr, true); + + the_font->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, + y + line_height), text_color, false, false, nullptr, true); + current_y += line_height; } if (c_data->getTimeRequirement(difficulty) > 0) { text_string = _("Required Time: %i", StringUtils::timeToString(c_data->getTimeRequirement(difficulty)).c_str()); text_color = time_passed ? win_color : lose_color; - current_y += int(m_distance_between_meta_rows * 0.7f); - GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, - y + GUIEngine::getSmallFontHeight()), text_color, false, false, nullptr, true); + + the_font->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, + y + line_height), text_color, false, false, nullptr, true); + current_y += line_height; } if (c_data->getEnergy(difficulty) > 0) { @@ -2243,18 +2268,33 @@ int RaceResultGUI::displayChallengeInfo(int x, int y) text_string = _("Required Nitro Points: %i", energy); text_color = energy_passed ? win_color : lose_color; - current_y += int(m_distance_between_meta_rows * 0.7f); - GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, - y + GUIEngine::getSmallFontHeight()), text_color, false, false, nullptr, true); + + the_font->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, + y + line_height), text_color, false, false, nullptr, true); + current_y += line_height; } if (c_data->isChallengeFulfilled(true /*best*/) && RaceManager::get()->getDifficulty() != RaceManager::DIFFICULTY_BEST) { + // The translated string might be too long, implement word wrap + std::vector best_while_slower_layout; text_string = _("Reached Requirements of SuperTux"); + the_font->initGlyphLayouts(text_string, + best_while_slower_layout); + irr::gui::breakGlyphLayouts(best_while_slower_layout, + UserConfigParams::m_width * 0.93f - x, + the_font->getInverseShaping(), + the_font->getScale()); + irr::core::dimension2du dim = + irr::gui::getGlyphLayoutsDimension(best_while_slower_layout, + line_height, + the_font->getInverseShaping(), + the_font->getScale()); text_color = special_color; - current_y += int(m_distance_between_meta_rows * 0.7f); - GUIEngine::getFont()->draw(text_string, core::recti(x, current_y, UserConfigParams::m_width * 0.96f, - y + GUIEngine::getSmallFontHeight()), text_color, false, false, nullptr, true); + + the_font->draw(best_while_slower_layout, core::recti(x, current_y, x + dim.Width, + current_y + dim.Height), text_color, false, false, nullptr); + current_y += line_height; } return current_y; diff --git a/src/states_screens/race_result_gui.hpp b/src/states_screens/race_result_gui.hpp index 54c6248da48..5aba04c346d 100644 --- a/src/states_screens/race_result_gui.hpp +++ b/src/states_screens/race_result_gui.hpp @@ -206,9 +206,9 @@ class RaceResultGUI : public RaceGUIBase, void addGPProgressWidget(GUIEngine::Widget* widget); void displayGPProgress(); void displayPostRaceInfo(); - int displayHighscores(int x, int y); - int displayLapDifficulty(int x, int y); - int displayChallengeInfo(int x, int y); + int displayHighscores(int x, int y, bool increase_density); + int displayLapDifficulty(int x, int y, bool increase_density); + int displayChallengeInfo(int x, int y, bool increase_density); void displayCTFResults(); void displaySoccerResults(); void drawTeamScorers(KartTeam team, int x, int y, int height); From 73271db08a48383fa64461eb592aa3a4c4b10265 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Tue, 29 Oct 2024 23:41:47 +0800 Subject: [PATCH 488/830] Fix crash race result screen on networking --- src/states_screens/race_result_gui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 35e1ffdb256..49a317c611d 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -1926,7 +1926,8 @@ void RaceResultGUI::displayPostRaceInfo() if (RaceManager::get()->isBenchmarking()) return; - int size_esti = 1 + World::getWorld()->getHighscores()->getNumberEntries(); + Highscores *highscore = World::getWorld()->getHighscores(); + int size_esti = highscore ? highscore->getNumberEntries() + 1 : 1; if (!RaceManager::get()->isSoccerMode()) size_esti += RaceManager::get()->modeHasLaps() ? 4 : 2; From 7d8b963e504968cf4bd2b8d2c3046b9964920223 Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 29 Oct 2024 22:08:01 +0100 Subject: [PATCH 489/830] Small fixes in stkgui files --- data/gui/screens/online/online.stkgui | 2 +- data/gui/screens/tracks_and_gp.stkgui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/gui/screens/online/online.stkgui b/data/gui/screens/online/online.stkgui index e3a9f4fbf78..cc80df1a07c 100644 --- a/data/gui/screens/online/online.stkgui +++ b/data/gui/screens/online/online.stkgui @@ -18,7 +18,7 @@

|1P32gc7vS$n6 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 literal 0 HcmV?d00001 diff --git a/data/skins/cartoon-ocean/bottom_bar.png b/data/skins/cartoon-ocean/bottom_bar.png new file mode 100644 index 0000000000000000000000000000000000000000..2145f3e3b7ea162fd768ab0bd1313fd381141f81 GIT binary patch literal 45444 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 ^u$XCKi!l3j`wT{<>$hSbUrG7u(lnxArP*f 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

p!~$1%&@kv-s`*qg`@*yM+FG24er&B`B1@ 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

diff --git a/data/gui/screens/tracks_and_gp.stkgui b/data/gui/screens/tracks_and_gp.stkgui index 2a870c36caf..495ebe9803c 100644 --- a/data/gui/screens/tracks_and_gp.stkgui +++ b/data/gui/screens/tracks_and_gp.stkgui @@ -25,7 +25,7 @@
- +
From 0b1a8d09b175670fe4afba1944d8c6415338b5e6 Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 29 Oct 2024 22:11:13 +0100 Subject: [PATCH 490/830] Fixed running update_pot script. Probably needed because of new python. --- data/po/extract_strings_from_XML.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/data/po/extract_strings_from_XML.py b/data/po/extract_strings_from_XML.py index a560e7dd711..f56f0b9cc3e 100755 --- a/data/po/extract_strings_from_XML.py +++ b/data/po/extract_strings_from_XML.py @@ -3,7 +3,7 @@ import codecs f = open('./data/po/gui_strings.h', 'w') -f.write( codecs.BOM_UTF8 ) +f.write(codecs.BOM_UTF8.decode('utf-8')) def traverse(file, node, isChallenge, isGP, isKart, isTrack, isAchievements, level=0): @@ -25,7 +25,7 @@ def traverse(file, node, isChallenge, isGP, isKart, isTrack, isAchievements, lev else: line += "//I18N: Cutscene subtitle from " + file + "\n//I18N: " + comment + "\n_(\"" + e.getAttribute("text") + "\");\n\n" - f.write( line.encode( "utf-8" ) ) + f.write(line) if isChallenge or isGP or isKart or isTrack or isAchievements: if isTrack and e.hasAttribute("internal") and e.getAttribute("internal") == "Y": continue @@ -37,7 +37,7 @@ def traverse(file, node, isChallenge, isGP, isKart, isTrack, isAchievements, lev else: line += "//I18N: File : " + file + "\n//I18N: " + comment + "\n_(\"" + e.getAttribute("name") + "\");\n\n" - f.write( line.encode( "utf-8" ) ) + f.write(line) # challenges and GPs can have a description file; karts don't if e.hasAttribute("description") and len(e.getAttribute("description")) > 0: @@ -48,11 +48,11 @@ def traverse(file, node, isChallenge, isGP, isKart, isTrack, isAchievements, lev else: line += "//I18N: File : " + file + "\n//I18N: " + comment + "\n_(\"" + e.getAttribute("description") + "\");\n\n" - f.write( line.encode( "utf-8" ) ) + f.write(line) else: if e.nodeName == "string" and e.hasAttribute("name") and e.getAttribute("name").startswith("po_") and e.firstChild is not None: line = "//I18N: In Android UI, " + e.getAttribute("name") + "\n_(\"" + e.firstChild.nodeValue + "\")\n\n" - f.write( line.encode( "utf-8" ) ) + f.write(line) elif e.hasAttribute("text") and len(e.getAttribute("text")) > 0: # print "Label=", e.getAttribute("text"), " Comment=", comment line = "" @@ -60,7 +60,7 @@ def traverse(file, node, isChallenge, isGP, isKart, isTrack, isAchievements, lev line += "//I18N: " + file + "\n_(\"" + e.getAttribute("text").replace("\"", "\\\"") + "\")\n\n" else: line += "//I18N: " + file + "\n//I18N: " + comment + "\n_(\"" + e.getAttribute("text") + "\");\n\n" - f.write( line.encode( "utf-8" ) ) + f.write(line) # don't recurse in children nodes for karts, they can contain sounds, etc. that should not be translated if not isKart: From 3fcdaa9f51efd999053fc1f586adc29b353d91ad Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 29 Oct 2024 22:12:44 +0100 Subject: [PATCH 491/830] Update pot file --- ...net.supertuxkart.SuperTuxKart.metainfo.xml | 21 + data/po/supertuxkart.pot | 2034 ++++++++++------- data/supertuxkart.desktop | 2 + 3 files changed, 1224 insertions(+), 833 deletions(-) diff --git a/data/net.supertuxkart.SuperTuxKart.metainfo.xml b/data/net.supertuxkart.SuperTuxKart.metainfo.xml index 9cc0f298695..baea4df3098 100644 --- a/data/net.supertuxkart.SuperTuxKart.metainfo.xml +++ b/data/net.supertuxkart.SuperTuxKart.metainfo.xml @@ -43,6 +43,7 @@ Ενα 3D ανοιχτού κώδικα παιχνίδι αγώνων με κάρτ Ein Open-Source 3D-Kart-Rennspiel Et 3D-kartracerspil i open source + Gêm rasio cart cod agored 3D 3D open source závodní hra motokár Un joc de curses de karts en 3D de codi obert. 3-измерна състезателна игра с колички, с отворен код @@ -84,6 +85,7 @@

Καρτ. Nitro. Πάμε! To SuperTuxKart είναι ένα τρισδιάστατο, ανοικτού λογισμικού ηλεκτρονικό παιχνίδι αγώνων δρόμου, με ποικιλία χαρακτήρων, πιστών και κατηγοριών για να παίξετε. Στόχος μας είναι να φτιάξουμε ένα παιχνίδι το οποίο είναι περισσότερο διασκεδαστικό παρά ρεαλιστικό και να παρέχει μια ευχάριστη εμπειρία για όλες τις ηλικίες.

Karts. Nitro. Action! SuperTuxKart ist ein Open-Source 3D-Arcade-Rennspiel mit einer Vielzahl von Charakteren, Strecken und Spielmodi. Unser Ziel ist es, ein Spiel zu schaffen, das mehr Spaß macht als realistisch ist, und eine unterhaltsame Erfahrung für alle Altersgruppen bietet.

Karts. nitro. action! SuperTuxKart er en 3D-arkaderacer i open source med et udvalg af karakterer, spor og tilstande som kan spilles. Vores mål er at skabe et spil som er mere sjovt end det er realistisk og give alle aldersgrupper en god oplevelse.

+

Cartiau. Nitro. Antur! Mae SuperTuxKart yn gêm rasio arcêd cod agored 3D gydag amrywiaeth o gymeriadau, traciau a moddau i'w chwarae. Ein nod yw creu gêm sy'n fwy o hwyl na realistig, ac yn cynnig profiad pleserus i bob oed.

Motokáry. Nitro. Akce! SuperTuxKart je 3D arkádová závodní hra s otevřeným zdrojovým kódem, která nabízí různé postavy, tratě a režimy. Naším cílem je vytvořit hru, která je spíš zábavnější než realistická a poskytne příjemný zážitek všem věkovým skupinám.

Karts. Nitro. Acció! El SuperTuxKart és un joc de curses 3D de codi obert amb una gran varietat de personatges, circuits i maneres de jugar. El nostre objectiu és crear un joc que sigui més divertit que realista, i proporcionar una experiència agradable per a totes les edats.

Колички. Азот. Екшън! Супер Тъкс Карт е 3-измерна състезателна игра с отворен код, която включва множество персонажи, писти и режими на игра. Целта ни е да създадем игра, която е повече забавна, отколкото реалистична – такава, която предоставя приятно изживяване за хора от всички възрасти.

@@ -123,6 +125,7 @@

Υπάρχουν διάφορες πίστες με διάφορα θέματα ώστε όλοι οι παίκτες να παιρνάνε καλά, από οδήγηση κάτω απο το νερό, αγροτικές περιοχές, ζούγκλες η ακόμα και στο διάστημα! Προσπάθησε όσο μπορείς να αποφύγεις άλλα karts όπου μπορούν να σε προσπεράσουν, όμως μην πέσεις πάνω στις μπανάνες! Να έχεις το νου σου για μπάλες του bowling, βεντούζες, φούσκες και cakes όπου θα έρθουν απο τους αντιπάλους σου.

Wir haben mehrere Strecken mit verschiedenen Themen für Spieler, die sie genießen können: Fahrten unter Wasser, über ländliches Ackerland, durch den Dschungel oder sogar im Weltraum! Versuche dein Bestes und vermeide dabei andere Karts, da diese möglicherweise überholen, aber esse keine Bananen! Achte auf Bowlingkugeln, Pömpel, Kaugummi und Kuchen, die von deinen Gegnern geworfen werden.

Vi har baner med diverse temaer, som spillere kan fornøje sig med fra kørsel under vandet, landbrug, jungler og endda i rummet! Gør dit bedste, mens du undviger andre karts, der overhaler dig, men spis ikke bananerne! Pas på bowlingkugler, svuppere, tyggegummi og kager som kastes af dine modstandere.

+

Mae gennym ni sawl trac gyda themâu amrywiol i chwaraewyr eu mwynhau, o yrru o dan y dŵr, tiroedd ffermydd gwledig, jyngl neu yn y gofod! Gwna dy orau wrth osgoi cartiau eraill oherwydd efallai y byddan nhw'n dy basio, ond paid â bwyta'r bananas! Gwylia am beli bowlio, plymwyr, gwm swigen, a chacennau wedi'u taflu gan dy wrthwynebwyr.

Máme několik tratí s různými tématy, které si hráči mohou užít, od tratí pod vodou, venkovských a zemědělských tratí, džunglí nebo dokonce trať ve vesmíru! Snažte se ze všech sil vyhýbat se ostatním motokárám, protože vás mohou předjet, ale nejezte banány! Dávejte pozor na bowlingové koule, zvony, žvýkačky a dorty hozené vašimi protivníky.

Tenim varis circuits amb diferents ambientacions per disfrutar, des de conduir sota l'aigua, terres de cultiu rurals, selves o fins i tot l'espai! Dona-ho tot mentre evites que els altres karts t'avancin, però no et mengis els plàtans! Vigila amb les boles de bitlles, desembussadors, xiclets i pastissos llançats pels teus oponents.

Разполагаме с разнообразни писти с най-различни тематики – карай под водата, из полята, джунглите и дори в космоса! Дай най-доброто от себе си, избягвай другите колички и в никакъв случай не яж бананите! Пази се от топките за боулинг, буталата, дъвките и кексчетата, които противниците ти ще се опитат да хвърлят по теб.

@@ -163,6 +166,7 @@

Μπορείς να κάνεις μονο 'εναν αγώνα ενάντιον άλλων karts, να ανταγωνιστείς σε ενα από τα διάφορους μαραθώνιους απο αγώνες, προσπάθησε να ξεπεράσεις το καλύτερο χρονο στους αγώνες ταχύτητας από μόνο σου, δοκίμασε αγώνες αναμέτρησεις εναντίον του υπολογιστή η των φίλλων σου, και πολλά άλλα! Για μια πιο δύσκολη πρόσκληση, μπες online και συνάντησε άλλους παίκτες απο όλες τις γωνιές του κόσμου και απέδιξε τους, τις ικανότητες σου!

Du kannst ein einzelnes Rennen gegen andere Karts fahren, an einem von mehreren Grands Prix teilnehmen, versuchen, den Rekord im Zeitfahren zu schlagen, im Kampfmodus gegen den Computer oder deine Freunde spielen und vieles mehr! Für eine noch größere Herausforderung kannst du dich online mit Spielern aus der ganzen Welt messen und deine Rennkünste unter Beweis stellen!

Du kan tage et enkelt race mod andre karts, dyste i en af mange grandprixer, prøve at slå highscore i tidskørsel på egen hånd, spille i kamptilstand mod computeren eller dine venner og mere! For en større udfordring kan du tilslutte dig online, møde og bevise dine køreevner med og for spillere fra hele verden!

+

Gelli wneud ras unigol yn erbyn cartiau eraill, cystadlu mewn un o nifer o Grand Prix, ceisio curo'r sgôr uchel mewn treialon amser ar dy ben dy hun, chwarae modd brwydr yn erbyn y cyfrifiadur neu dy ffrindiau, a mwy! Am her fwy, ymuna ar-lein a chwrdd â chwaraewyr o bob cwr o'r byd a phrofi dy sgiliau rasio!

Můžete absolvovat samostatný závod s jinými motokáry, soutěžit v jedné z několika Velkých cen, pokusit se porazit vysoké skóre v závodech na čas, hrát bojový režim proti počítači nebo svým přátelům a další! Pro ještě větší výzvu se připojte on-line a potkejte se s hráči z celého světa a prokažte své závodní schopnosti!

Pots córrer una sola cursa contra altres karts, competir en un o varis campionats, intentar superar les puntuacions màximes en les teves pròpies curses contra rellotge, jugar en mode batalla contra l'ordinador o els teus amics, i més! Per a un desafiament encara més gran, competeix en línia contra jugadors de tot el món i demostra les teves habilitats al volant!

Можеш да изиграеш единично състезание срещу други колички, да се съревноваваш в някой от турнирите за Голямата награда, да се опиташ да победиш най-доброто време сам, да играеш бойния режим срещу компютъра или приятелите си, и още! Ако имаш нужда от по-голямо предизвикателство, можеш да се състезаваш по Интернет срещу други играчи от целия свят и да им докажеш, че си най-добрият!

@@ -211,6 +215,7 @@ Balapan Biasa Normál verseny Normalna utrka + साधारण रेस מרוץ רגיל Carreira normal Rèis àbhaisteach @@ -226,10 +231,12 @@ Κανονικός αγώνας Normales Rennen Normalt løb + Ras Arferol Normální závod Cursa normal Obična trka Redadeg normal + সাধারণ রেস Обикновено състезание Звычайная гонка سباق عاديّ @@ -269,6 +276,7 @@ Perang Csata Borba + लड़ाई קרב Batalla Còmhrag @@ -284,6 +292,7 @@ Μονομαχία Kampf Kamp + Brwydr Bitva Batalla Borba @@ -333,6 +342,7 @@ Sepak Bola Foci Footbalica + फ़ुटबॉल כדורגל Fútbol Ball-coise @@ -349,6 +359,7 @@ Ποδόσφαιρο Fußball Fodbold + Pêl-droed Fotbal Futbol Nogomet @@ -387,10 +398,12 @@ Il team di SuperTuxKart Tim SuperTuxKart A SuperTuxKart csapat + SuperTuxKart टीम צוות SuperTuxKart Equipo SuperTuxKart Sgioba SuperTuxKart Foireann SuperTuxKart + SuperTuxKart Team L'équipe SuperTuxKart SuperTuxKart Team SuperTuxKart-tiimi @@ -401,6 +414,7 @@ Ομάδα SuperTuxKart SuperTuxKart-Team SuperTuxKart-teamet + Tîm SuperTuxKart Tým SuperTuxKart L'equip del SuperTuxKart Екипът на Супар Тъкс Карт @@ -434,10 +448,12 @@ ar be bg + bn br bs ca cs + cy da de el @@ -450,12 +466,15 @@ fil fr fr_CA + fy ga gd gl he + hi hr hu + hy id is it @@ -481,6 +500,8 @@ ro ru rue + sc + sco sk sl sq diff --git a/data/po/supertuxkart.pot b/data/po/supertuxkart.pot index c333d0f3285..c1d4fa46f1a 100644 --- a/data/po/supertuxkart.pot +++ b/data/po/supertuxkart.pot @@ -8,13 +8,13 @@ msgid "" msgstr "" "Project-Id-Version: supertuxkart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" @@ -166,7 +166,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "" @@ -188,7 +188,7 @@ msgstr "" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "" @@ -202,13 +202,13 @@ msgstr "" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "" @@ -239,35 +239,37 @@ msgstr "" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "" @@ -335,30 +337,33 @@ msgstr "" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "" @@ -534,9 +539,9 @@ msgstr "" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -597,7 +602,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "" @@ -632,7 +637,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "" @@ -648,7 +653,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "" @@ -712,12 +717,12 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "" @@ -758,7 +763,7 @@ msgstr "" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "" @@ -770,7 +775,7 @@ msgstr "" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "" @@ -782,7 +787,7 @@ msgstr "" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "" @@ -794,7 +799,7 @@ msgstr "" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "" @@ -802,8 +807,8 @@ msgstr "" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "" @@ -814,8 +819,8 @@ msgstr "" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "" @@ -828,7 +833,7 @@ msgstr "" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "" @@ -836,7 +841,8 @@ msgstr "" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "" @@ -845,24 +851,24 @@ msgstr "" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "" @@ -873,7 +879,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "" @@ -967,6 +973,50 @@ msgstr "" msgid "Assign nothing" msgstr "" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -981,11 +1031,11 @@ msgstr "" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "" @@ -1024,10 +1074,15 @@ msgstr "" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1037,20 +1092,20 @@ msgstr "" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "" @@ -1061,12 +1116,12 @@ msgstr "" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "" @@ -1080,27 +1135,28 @@ msgstr "" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "" @@ -1139,9 +1195,9 @@ msgstr "" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "" @@ -1178,7 +1234,7 @@ msgstr "" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "" @@ -1225,10 +1281,10 @@ msgstr "" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "" @@ -1260,9 +1316,9 @@ msgstr "" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1273,80 +1329,80 @@ msgstr "" msgid "Save Grand Prix" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1354,56 +1410,57 @@ msgstr "" msgid "Story Mode" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1411,14 +1468,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1427,34 +1484,34 @@ msgid "" "carefully before!" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1462,7 +1519,7 @@ msgid "" "leader will get you eliminated too!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1472,29 +1529,29 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and " "record your own!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1503,93 +1560,93 @@ msgid "" "wins the cup." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights. " "It also affects other karts close to the explosion." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts " "down on the way." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to " "remove parachutes and bombs." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air. " "Bump into another kart to transfer the bomb to it." msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1598,7 +1655,7 @@ msgid "" "accept to race against you. Win to liberate Gnu!" msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1606,20 +1663,20 @@ msgid "" "the cup and the more points it is worth." msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1627,7 +1684,7 @@ msgid "" "resistant to explosions." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1635,7 +1692,7 @@ msgid "" "especially at low speeds." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1643,14 +1700,14 @@ msgid "" "top speed." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1658,12 +1715,12 @@ msgid "" "easier it is." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1673,7 +1730,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1683,12 +1740,12 @@ msgid "" "players and the server." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1698,7 +1755,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon " @@ -1717,7 +1774,7 @@ msgstr "" #. I18N: In the high score selection screen #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "" @@ -1725,9 +1782,9 @@ msgstr "" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "" @@ -1738,6 +1795,20 @@ msgstr "" msgid "Choose a Kart" msgstr "" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1751,11 +1822,11 @@ msgstr "" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "" @@ -1772,7 +1843,7 @@ msgstr "" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "" @@ -1780,7 +1851,7 @@ msgstr "" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "" @@ -1834,30 +1905,30 @@ msgstr "" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "" @@ -1883,9 +1954,9 @@ msgstr "" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "" @@ -1903,7 +1974,7 @@ msgstr "" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "" @@ -1928,7 +1999,7 @@ msgstr "" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "" @@ -1978,8 +2049,8 @@ msgid "Online Username" msgstr "" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "" @@ -1992,7 +2063,7 @@ msgid "" msgstr "" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "" @@ -2010,338 +2081,408 @@ msgstr "" msgid "User search" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" +msgid "Enable chatting in online lobbies" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" +msgid "Enable chatting in online matches" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to " "join the game." msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" +msgid "Skin variant" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" +msgid "Minimap" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" +msgid "Performance tests" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" +msgid "Performance test of the current settings" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" msgstr "" #. I18N: ./data/gui/screens/race_setup.stkgui @@ -2369,15 +2510,15 @@ msgstr "" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "" @@ -2392,31 +2533,15 @@ msgstr "" msgid "Random Grand Prix" msgstr "" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 -msgid "Login" -msgstr "" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" msgstr "" #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" +#. I18N: Used as a verb, appears on the main networking menu (login button) +#: src/states_screens/online/online_screen.cpp:69 +msgid "Login" msgstr "" #. I18N: ./data/tips.xml @@ -2537,238 +2662,301 @@ msgid "" msgstr "" #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart-assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart-assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart-assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart-assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart-assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "" @@ -2777,11 +2965,11 @@ msgstr "" msgid "Completed achievement \"%s\"." msgstr "" -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "" -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "" @@ -2846,7 +3034,7 @@ msgid "New kart '%s' now available" msgstr "" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been " "closed since the launch of the story mode.\n" @@ -2879,32 +3067,32 @@ msgid "" "created." msgstr "" -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "" -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "" -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "" @@ -2926,19 +3114,18 @@ msgstr "" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "" @@ -3412,19 +3599,19 @@ msgid "Axis %d" msgstr "" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "" #. I18N: to appear in input configuration screen, for mouse (might not be used at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "" #. I18N: to appear in input configuration screen, for mouse (might not be used at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "" @@ -3596,26 +3783,30 @@ msgstr "" msgid "+1 life." msgstr "" -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "" -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy. " @@ -3624,16 +3815,16 @@ msgid "" "Internet\")." msgstr "" -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "" -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "" -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3641,38 +3832,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "" -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "" #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "" @@ -3682,7 +3873,7 @@ msgstr "" msgid "Eggs: %d / %d" msgstr "" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "" @@ -3690,22 +3881,22 @@ msgstr "" msgid "Final lap!" msgstr "" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "" @@ -3719,194 +3910,194 @@ msgstr "" msgid "Oops, %s made an own goal!" msgstr "" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "" msgstr[1] "" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "" -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "" -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "" -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "" -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "" -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "" #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "" #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "" #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "" -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "" -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "" -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "" -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "" -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "" -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "" -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "" #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "" #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "" #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "" -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "" #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "" #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "" #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "" #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "" #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3914,15 +4105,15 @@ msgid "" msgstr "" #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "" #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3953,38 +4144,38 @@ msgstr "" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "" -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "" -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "" #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -3992,19 +4183,19 @@ msgstr[0] "" msgstr[1] "" #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "" -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "" msgstr[1] "" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "" @@ -4033,12 +4224,12 @@ msgid "" msgstr "" #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "" @@ -4051,91 +4242,88 @@ msgstr "" msgid "Replay saved in \"%s\"." msgstr "" -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you " "are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "" -msgstr[1] "" - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "" @@ -4383,7 +4571,7 @@ msgstr "" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "" @@ -4474,7 +4662,7 @@ msgstr "" msgid " (official tracks matching the goal)" msgstr "" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you " "connect them to this device.\n" @@ -4487,91 +4675,95 @@ msgid "" msgstr "" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "" @@ -4591,67 +4783,91 @@ msgstr "" #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4659,7 +4875,7 @@ msgid "" msgstr "" #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4676,101 +4892,102 @@ msgstr "" msgid "Invalid server address: %s." msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "" @@ -4858,33 +5075,41 @@ msgid "Press any key..." msgstr "" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 -msgid "Back to Battle" +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" msgstr "" #: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +msgid "Back to Battle" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "" @@ -4900,11 +5125,11 @@ msgstr "" msgid "%s is number %d in the rankings with a score of %f." msgstr "" -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "" -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4926,7 +5151,7 @@ msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "" @@ -4939,21 +5164,21 @@ msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "" @@ -4966,54 +5191,54 @@ msgstr "" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "" @@ -5026,74 +5251,74 @@ msgid "No player available for connecting to server." msgstr "" #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5122,7 +5347,7 @@ msgstr "" msgid "An error occurred while trying to save your grand prix." msgstr "" -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "" @@ -5166,12 +5391,12 @@ msgstr "" msgid "You unlocked grand prix %0" msgstr "" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5192,19 +5417,19 @@ msgstr "" msgid "Please select a Grand Prix" msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "" @@ -5213,19 +5438,19 @@ msgstr "" msgid "Better luck next time!" msgstr "" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "" @@ -5238,44 +5463,59 @@ msgstr "" msgid "Are you sure you want to remove all of your high scores?" msgstr "" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online, " "go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download " "addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download " "addons, go in the options menu, and check \"Connect to the Internet\".\n" @@ -5283,66 +5523,66 @@ msgid "" "You can however delete already downloaded addons." msgstr "" -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5350,7 +5590,7 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "" @@ -5358,24 +5598,24 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "" -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5384,7 +5624,7 @@ msgstr[1] "" #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5393,96 +5633,108 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "" -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "" @@ -5560,34 +5812,34 @@ msgid "Distance (km)" msgstr "" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "" #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "" -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "" -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting " "will end early." @@ -5595,149 +5847,149 @@ msgstr "" #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down, " "all keys that contain a character that is different in upper-case will stop " @@ -5745,16 +5997,26 @@ msgid "" msgstr "" #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "" +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5762,89 +6024,74 @@ msgstr "" #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the " "launch of the story mode.\n" @@ -5855,127 +6102,132 @@ msgid "" msgstr "" #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "" #. I18N: in graphical options. The \n is a newline character, place it where appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "" #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "" -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "" #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "" @@ -6003,7 +6255,7 @@ msgstr "" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "" @@ -6037,7 +6289,7 @@ msgstr "" msgid "Top %i" msgstr "" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "" @@ -6061,101 +6313,198 @@ msgstr "" msgid "Press fire to start the challenge" msgstr "" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "" #. I18N: is used to indicate who has the bast laptime (best laptime "by kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "" @@ -6196,28 +6545,28 @@ msgstr "" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "" @@ -6237,10 +6586,12 @@ msgid "%d/%m/%Y" msgstr "" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6249,41 +6600,48 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left " "or right." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these " "boxes!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6291,6 +6649,7 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the " @@ -6298,28 +6657,34 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6327,23 +6692,26 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "" #. I18N: Generic name in desktop file entry, summary in AppData and short description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "" @@ -6352,7 +6720,7 @@ msgstr "" msgid "tux;game;race;" msgstr "" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6360,7 +6728,7 @@ msgid "" "for all ages." msgstr "" -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best " @@ -6369,7 +6737,7 @@ msgid "" "your opponents." msgstr "" -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6378,27 +6746,27 @@ msgid "" "your racing skills!" msgstr "" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "" -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "" -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "" -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "" diff --git a/data/supertuxkart.desktop b/data/supertuxkart.desktop index 3c333c74934..4b99be47cdc 100644 --- a/data/supertuxkart.desktop +++ b/data/supertuxkart.desktop @@ -7,6 +7,7 @@ GenericName[be]=3D-гульня для гонак на картах з адкр GenericName[bg]=3-измерна състезателна игра с колички, с отворен код GenericName[ca]=Un joc de curses de karts en 3D de codi obert. GenericName[cs]=3D open source závodní hra motokár +GenericName[cy]=Gêm rasio cart cod agored 3D GenericName[da]=Et 3D-kartracerspil i open source GenericName[de]=Ein Open-Source 3D-Kart-Rennspiel GenericName[el]=Ενα 3D ανοιχτού κώδικα παιχνίδι αγώνων με κάρτ @@ -56,6 +57,7 @@ Keywords[be]=tux;game;race;тукс;такс;гульня;гонка;футбо Keywords[bg]=тъкс;кола;коли;количка;колички;състезание;състезания Keywords[ca]=tux;joc;cursa; Keywords[cs]=tux;hra;závod; +Keywords[cy]=tux;gêm;rasio; Keywords[da]=tux;spil;racerløb; Keywords[de]=tux;spiel;rennen; Keywords[el]=tux;παιχνίδι;αγώνας; From 3e71e248f206291d07d2ef7b7c136f9e561b17d1 Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 29 Oct 2024 22:27:40 +0100 Subject: [PATCH 492/830] Update translations --- data/po/ar.po | 35 +-- data/po/be.po | 88 +++---- data/po/da.po | 12 +- data/po/de.po | 17 +- data/po/el.po | 2 +- data/po/eo.po | 27 ++- data/po/es.po | 6 +- data/po/fil.po | 12 +- data/po/fr.po | 91 +++---- data/po/gl.po | 545 ++++++++++++++++++++--------------------- data/po/he.po | 620 +++++++++++++++++++++++------------------------ data/po/hr.po | 2 +- data/po/id.po | 12 +- data/po/is.po | 127 +++++----- data/po/it.po | 119 ++++----- data/po/ja.po | 31 +-- data/po/mk.po | 20 +- data/po/ml.po | 240 +++++++++--------- data/po/nb.po | 21 +- data/po/oc.po | 441 ++++++++++++++++----------------- data/po/pl.po | 14 +- data/po/pt.po | 411 +++++++++++++++---------------- data/po/pt_BR.po | 14 +- data/po/ro.po | 90 +++---- data/po/ru.po | 87 +++---- data/po/rue.po | 20 +- data/po/sl.po | 5 +- data/po/sr.po | 24 +- data/po/sv.po | 14 +- data/po/th.po | 38 +-- data/po/tr.po | 57 ++--- data/po/tt.po | 194 +++++++-------- data/po/zh_CN.po | 18 +- 33 files changed, 1731 insertions(+), 1723 deletions(-) diff --git a/data/po/ar.po b/data/po/ar.po index 7c26e4dc326..6e5320881fe 100644 --- a/data/po/ar.po +++ b/data/po/ar.po @@ -3,6 +3,7 @@ # This file is distributed under the same license as the supertuxkart package. # # Translators: +# Ahmed Mohammed, 2024 # A.Karim S., 2018 # Benamara Mohamed , 2015 # FIRST AUTHOR , 2011 @@ -22,7 +23,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Hasan Nahleh , 2019,2022\n" +"Last-Translator: Ahmed Mohammed, 2024\n" "Language-Team: Arabic (http://app.transifex.com/supertuxkart/supertuxkart/language/ar/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -921,7 +922,7 @@ msgstr "معلومات المستخدم" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "أزِل صديقًا" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -931,17 +932,17 @@ msgstr "أضف صديقًا" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "اقبل الدعوة" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "ارفض الدعوة" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "اعرض الملفّ الشّخصيّ" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1129,7 +1130,7 @@ msgstr "إشادات" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "تخطى" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1511,7 +1512,7 @@ msgstr "شبح الإعادة: تسابق ضد شبح الإعادة في ضدّ #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "" +msgstr "لفّة تجريبية: أكمل أكبر عدد ممكن من اللفّات في فترة زمنية المحددة." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1739,7 +1740,7 @@ msgstr "اختيار نتيجة عالية" #. time. #: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" -msgstr "جولة تجريبية" +msgstr "لفّة تجريبية" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen @@ -2009,7 +2010,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "يمكنك اللعب دون إنشاء حساب شبكيّ من خلال تحديد حساب بلا اتّصال. لكنك لن تتمكن من الاتّصال بالأصدقاء، أو التصويت على الإضافات، أو إلخ. من فضلك طالع بيان الخصوصية الخاص بنا على https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2522,7 +2523,7 @@ msgstr "يمكن تدمير كرات السلة باستخدام تسديدات msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "" +msgstr "حاول تجنب الاصطدام بدعائم العربات الأخرى، لأن ذلك سيبطئك." #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." @@ -2566,7 +2567,7 @@ msgstr "اماندا" #. I18N: ../stk-assets/karts/beastie/kart.xml msgid "Godette" -msgstr "" +msgstr "غوديت" #. I18N: ../stk-assets/karts/emule/kart.xml msgid "Emule" @@ -2590,7 +2591,7 @@ msgstr "كيكي" #. I18N: ../stk-assets/karts/konqi/kart.xml msgid "Konqi" -msgstr "كونقي" +msgstr "كونكي" #. I18N: ../stk-assets/karts/nolok/kart.xml msgid "Nolok" @@ -2679,7 +2680,7 @@ msgstr "المزرعة" #. I18N: ../stk-assets/tracks/hole_drop/track.xml msgid "Hole Drop" -msgstr "" +msgstr "سقوط الحفرة" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" @@ -2734,7 +2735,7 @@ msgstr "الغولف المصغّر" #. I18N: ../stk-assets/tracks/oasis/track.xml msgid "Oasis" -msgstr "" +msgstr "الواحة" #. I18N: ../stk-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" @@ -3612,7 +3613,7 @@ msgstr "وقت جزاء!!" #: src/karts/controller/local_player_controller.cpp:332 msgid "Don't accelerate before 'Set!'" -msgstr "لا تتسارع قبل \"تعيين!\"" +msgstr "لا تتسارع قبل «استعدّ!»" #: src/karts/controller/spare_tire_ai.cpp:150 msgid "You can have at most 3 lives!" @@ -4180,7 +4181,7 @@ msgstr[5] "%d حلبة غير متوفرة عند اللعب الإنفرادي. #: src/states_screens/credits.cpp:184 msgid "translator-credits" -msgstr "Launchpad Contributions:\nA.Karim S., 2018\nBenamara Mohamed, 2015\nHasan Nahleh, 2022\nHasan Nahleh, 2019\nIbrahim Al-Darra, 2017\nmahmoudtark25, 2020\nMoaaz Mohamed, 2017\nخليل مراطلة, 2021\nصفا الفليج, 2015,2019\nHasan Nahleh, 2019,2022\nصفا الفليج,\nالمترجمون السابقون (منصّة لنشباد):\nBenjamin Kerensa - Dawid Gan - Hichem Razgallah - Majid Al-Dharrab\nSAKOUM Yassine - STK-team - abdXelrhman - محمد الحرقان" +msgstr "فريق عرب‌آيز للتّرجمة http://www.arabeyes.org (سابقًا)\nصفا الفليج، 2015–2019\nBenamara Mohamed, 2015\nMoaaz Mohamed, 2017\nIbrahim Al-Darra, 2017\nA.Karim S., 2018\nHasan Nahleh, 2019–2022\nmahmoudtark25, 2020\nخليل مراطلة، 2021\nأحمد محمد، 2024\nالمترجمون السابقون (منصّة لنشباد):\nBenjamin Kerensa - Dawid Gan - Hichem Razgallah - Majid Al-Dharrab\nSAKOUM Yassine - STK-team - abdXelrhman - محمد الحرقان" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:65 msgctxt "achievement_info" @@ -5609,7 +5610,7 @@ msgstr "البُرد الإلكترونيّة لا تتطابق!" msgid "" "Online username can only contain alphanumeric (ASCII) characters, periods, " "dashes and underscores!" -msgstr "" +msgstr "يمكن لأسماء المستخدم الشّبكيّة أن تحوي محارف أبجديّة عدديّة (ASCII)، ونقاط، وشرطات، وشرطات سفلية حصرًا!" #: src/states_screens/online/register_screen.cpp:374 msgid "Online username has to be between 3 and 30 characters long!" diff --git a/data/po/be.po b/data/po/be.po index d5c198f5157..3d30c7fd1e2 100644 --- a/data/po/be.po +++ b/data/po/be.po @@ -9,14 +9,14 @@ # Źmicier Turok , 2018 # Zmicer Turok , 2018 # Źmicier Turok , 2018 -# Денис Ким , 2019-2023 +# Денис Ким , 2019-2024 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Денис Ким , 2019-2023\n" +"Last-Translator: Денис Ким , 2019-2024\n" "Language-Team: Belarusian (http://app.transifex.com/supertuxkart/supertuxkart/language/be/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -197,7 +197,7 @@ msgstr "Абярыце пераважны тып кіравання" #. I18N: In the multitouch settings screen #: src/states_screens/dialogs/race_paused_dialog.cpp:549 msgid "Accelerometer" -msgstr "Паскарэнне" +msgstr "Акселерометр" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type @@ -435,7 +435,7 @@ msgstr "Налады графікі" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Advanced pipeline (lights, etc.)" -msgstr "Свой ланцужок (святло і г.д.)" +msgstr "Палепшаная графіка (святло і інш.)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -558,7 +558,7 @@ msgstr "Добра" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen msgid "Record the race for ghost replay" -msgstr "Запісаць гонку для паўтору з прывідам" +msgstr "Запісаць паўтор з прывідам падчас гонкі" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info action @@ -694,7 +694,7 @@ msgstr "Даведка" #. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui #. I18N: In player rankings dialog msgid "Top 10 players" -msgstr "10 найлепшых гульцоў" +msgstr "10 найлепшых гульцоў у рэйтынгу" #. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui msgid "Refresh" @@ -885,7 +885,7 @@ msgstr "Дадаць гульца" #. I18N: Splitscreen player in network #: src/states_screens/online/online_profile_achievements.cpp:76 msgid "Name" -msgstr "Назва" +msgstr "Імя" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network @@ -915,7 +915,7 @@ msgstr "Інфармацыя аб карыстальніку" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Выдаліць сябра" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -925,17 +925,17 @@ msgstr "Дадаць сябра" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Прыняць заяўку" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Адхіліць заяўку" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Праглядзець профіль" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -945,7 +945,7 @@ msgstr "Галасаваць" #. I18N: ./data/gui/dialogs/overworld_dialog.stkgui #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui msgid "Paused" -msgstr "Прыпынена" +msgstr "Паўза" #. I18N: ./data/gui/dialogs/overworld_dialog.stkgui #. I18N: In the in-game dialog @@ -965,7 +965,7 @@ msgstr "Абраць карт" #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When changing input configurations msgid "Press fully and release..." -msgstr "Моцна націсніце і адпусціце" +msgstr "Моцна націсніце і адпусціце..." #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input @@ -975,7 +975,7 @@ msgstr "Прызначыць да кнопкі ESC" #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input msgid "Assign nothing" -msgstr "Нічога не прызначана" +msgstr "Не прызначаць нічога" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui @@ -1123,7 +1123,7 @@ msgstr "Стваральнікі" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Прапусціць" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1178,7 +1178,7 @@ msgstr "Колькасць кругоў:" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: In the edit track screen msgid "Reverse:" -msgstr "Адвернута:" +msgstr "У адваротным напрамку:" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen @@ -1207,27 +1207,27 @@ msgstr "Параўнаць паўторы" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Only show replays matching the current difficulty" -msgstr "Паказваць толькі паўторы, што адпавядаюць бягучаму ўзроўню складанасці" +msgstr "Паказваць толькі паўторы з бягучым ўзроўнем складанасці" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Only show replays matching the current version" -msgstr "Паказваць толькі паўторы, што адпавядаюць бягучай версіі" +msgstr "Паказваць толькі паўторы з бягучай версіяй" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Hide multiplayer replays" -msgstr "Схаваць шматкарыстальніцкія прайграванні" +msgstr "Схаваць шматкарыстальніцкія паўторы" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Record a ghost replay" -msgstr "Запісваць паўторы з прывідам" +msgstr "Запісаць паўтор з прывідам" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen msgid "AI karts" -msgstr "Карты са штучным інтэлектам" +msgstr "Боты" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen @@ -1482,7 +1482,7 @@ msgid "" "player who hits others the most will win in a given hit or time limit. In " "Capture The Flag, your team needs to bring the flag of the other team to " "your own flag base, as long as your flag is not captured by the other team." -msgstr "Ёсць тры тыпы рэжымаў бітвы. У Бітве трох удараў вам неабходна выкарыстоўваць зброю супраць іншых гульцоў, пакуль яны не страцяць усе свае жыцці. У рэжыме свабоднай гульні той гулец, які стукне іншых больш разоў, пераможа, калі набярэ некаторую колькасць удараў або скончыцца час гульні. У гульні \"Захоп сцяга\" вашай камандзе трэба прынесці сцяг іншай каманды на сваю базу, пры гэтым ваш сцяг павінны быць на вашай базе." +msgstr "Ёсць 3 тыпы рэжымаў бітвы. У \"Бітве трох удараў\" вам неабходна выкарыстоўваць зброю супраць іншых гульцоў, пакуль яны не страцяць усе свае жыцці. У \"Бітве супраць усіх\" той гулец, які стукне іншых больш разоў, пераможа, калі набярэ некаторую колькасць удараў або скончыцца час гульні. У гульні \"Захоп сцяга\" вашай камандзе трэба прынесці сцяг іншай каманды на сваю базу, пры гэтым ваш сцяг павінны быць на вашай базе." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -2003,7 +2003,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Вы можаце гуляць без стварэння сеціўнага рахунка, абраўшы пазасеціўны рахунак. Але пры гэтым вы не зможаце злучыцца з сябрамі, галасаваць за дадаткі і інш. Азнаёмцеся з нашымі ўмовамі канфідэнцыйнасці на https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2301,7 +2301,7 @@ msgstr "Паказваць FPS" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" -msgstr "Паказваць зброю іншых картаў" +msgstr "Паказваць бонусы іншых картаў" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings @@ -2360,7 +2360,7 @@ msgstr "Ужыць новую раздзяляльную здольнасць" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" -msgstr "Абярыце цяжкасць" +msgstr "Абярыце складанасць" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a game mode" @@ -2393,7 +2393,7 @@ msgstr "Колькасць кругоў" #: src/states_screens/online/create_server_screen.cpp:196 #: src/states_screens/track_info_screen.cpp:195 msgid "Number of AI karts" -msgstr "Колькасць картаў-кампутараў" +msgstr "Колькасць ботаў" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen @@ -2439,7 +2439,7 @@ msgstr "Афармленне інтэрфейсу можна памяняць у #. I18N: ./data/tips.xml msgid "You can see other karts' powerups by enabling it in the UI options." -msgstr "Вы зможаце бачыць зброю іншых картаў, калі ўключыце гэта ў наладах інтэрфейсу." +msgstr "Вы зможаце бачыць бонусы іншых картаў, калі ўключыце гэта ў наладах інтэрфейсу." #. I18N: ./data/tips.xml msgid "The font size can be changed in the UI options." @@ -2516,7 +2516,7 @@ msgstr "Баскетбольны мяч можна знішчыць, калі д msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "" +msgstr "Не сутыкайцеся з іншымі картамі, бо гэта запавольвае вас." #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." @@ -2692,7 +2692,7 @@ msgstr "О так, глядзі, ён цяпер у маім замку і бу #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." -msgstr "Але я сумленнае стварэнне, таму прапаную ўгоду." +msgstr "Але я сумленная істота, таму прапаную ўгоду." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml @@ -2704,15 +2704,15 @@ msgstr "Калі ты зможаш перамагчы мяне ў гонцы, я msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" -msgstr " Але ты, гаротны валацуга, ніколі не зможаш адолець мяне — караля картаў!" +msgstr "Але ты, гаротны валацуга, ніколі не зможаш адолець мяне — караля картаў!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "Лас-Дунас-Арэна" +msgstr "Арэна Лас-Дунас" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" -msgstr "Футбольны стадыён Лас-Дзюнас" +msgstr "Футбольны стадыён Лас-Дунас" #. I18N: ../stk-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" @@ -2833,7 +2833,7 @@ msgstr "Руш за лідарам (адна гонка)" #: src/challenges/challenge_data.cpp:324 #: src/states_screens/dialogs/select_challenge.cpp:78 msgid "Mode: Reverse" -msgstr "Рэжым: адваротны" +msgstr "Рэжым: адваротны напрамак" #: src/challenges/challenge_data.cpp:601 #, c-format @@ -3978,7 +3978,7 @@ msgstr "Часовая гонка (Гран-пры)" #: src/states_screens/online/create_server_screen.cpp:237 #: src/states_screens/track_info_screen.cpp:252 msgid "Free-For-All" -msgstr "Свабодная гульня" +msgstr "Бітва супраць усіх" #. I18N: Game mode #. I18N: In the create server screen for battle server @@ -4382,13 +4382,13 @@ msgstr "Скончана гульняў \"Захоп сцяга\"" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:230 msgid "Free-for-All matches started" -msgstr "Пачата свабодных гульняў" +msgstr "Пачата бітваў супраць усіх" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:232 msgid "Free-for-All matches finished" -msgstr "Скончана свабодных гульняў" +msgstr "Скончана бітваў супраць усіх" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4407,7 +4407,7 @@ msgstr "Бонусаў выкарыстана" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:254 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:262 msgid " (1 race)" -msgstr "(1 гонка)" +msgstr " (1 гонка)" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4457,7 +4457,7 @@ msgstr "Слізганне" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:269 msgid " (1 lap)" -msgstr "(1 круг)" +msgstr " (1 круг)" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4479,7 +4479,7 @@ msgstr "Гонак пачата" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:288 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:294 msgid " (maximum on one official track)" -msgstr "(не больш, чым на адной афіцыйнай трасе)" +msgstr " (не больш, чым на адной афіцыйнай трасе)" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4550,7 +4550,7 @@ msgstr "Скончана паляванняў на яйкі" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:313 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:319 msgid " (official tracks matching the goal)" -msgstr "(афіцыйныя трасы, што адпавядаюць мэце)" +msgstr " (афіцыйныя трасы, што адпавядаюць мэце)" #: src/states_screens/dialogs/add_device_dialog.cpp:64 msgid "" @@ -5038,7 +5038,7 @@ msgstr "Неабходная колькасць нітра: %i" #: src/states_screens/dialogs/select_challenge.cpp:109 #, c-format msgid "Number of AI Karts: %i" -msgstr "Колькасць картаў са штучным інтэлектам: %i" +msgstr "Колькасць ботаў: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 @@ -5646,12 +5646,12 @@ msgstr "Невядома" #. I18N: Message shown to user if no IPv4 detected by STK #: src/states_screens/online/server_selection.cpp:363 msgid "No IPv4 detected, you may not be able to join any servers." -msgstr "Не ўдалося выявіць IPv4, магчыма, вы не зможаце далучацца да сервераў." +msgstr "Не ўдалося выявіць IPv4, магчыма, вы не зможаце далучацца да сервераў па гэтаму пратаколу." #. I18N: Message shown to user if no IPv6 detected by STK #: src/states_screens/online/server_selection.cpp:365 msgid "No IPv6 detected, you may not be able to join any servers." -msgstr "Не ўдалося выявіць IPv6, магчыма, вы не зможаце далучацца да сервераў. " +msgstr "Не ўдалося выявіць IPv6, магчыма, вы не зможаце далучацца да сервераў па гэтаму пратаколу." #: src/states_screens/online/server_selection.cpp:504 msgid "No server is available." @@ -6188,7 +6188,7 @@ msgstr "Гэта нічыя" #: src/states_screens/race_result_gui.cpp:881 #, c-format msgid "Eliminated after %s" -msgstr "Ліквідацыя праз %s" +msgstr "Выбыў праз %s" #: src/states_screens/race_result_gui.cpp:886 #: src/states_screens/race_result_gui.cpp:1334 diff --git a/data/po/da.po b/data/po/da.po index f965bba6af5..d555ccf6d1e 100644 --- a/data/po/da.po +++ b/data/po/da.po @@ -914,7 +914,7 @@ msgstr "Brugerinformation" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Fjern ven" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -924,17 +924,17 @@ msgstr "Tilføj ven" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Acceptér invitation" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Afvis invitation" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Vis profil" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1122,7 +1122,7 @@ msgstr "Anerkendelser" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Spring over" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -2002,7 +2002,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Du kan spille uden en online konto ved at vælge offlinekonto. Men så kan du ikke forbinde dig til venner, stemme for udvidelser osv. Læs venligst vores privatlivserklæring på https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 diff --git a/data/po/de.po b/data/po/de.po index 1644f610a6b..00dd1aa0885 100644 --- a/data/po/de.po +++ b/data/po/de.po @@ -14,6 +14,7 @@ # Flakebi, 2015 # Flakebi, 2015 # hiker , 2015 +# Iwan Gabovitch, 2023 # hiker , 2015 # Juli X, 2022 # Juli X, 2022 @@ -37,7 +38,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: FabianF, 2020-2023\n" +"Last-Translator: Iwan Gabovitch, 2023\n" "Language-Team: German (http://app.transifex.com/supertuxkart/supertuxkart/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -936,7 +937,7 @@ msgstr "Benutzerinformation" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Freund entfernen" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -946,17 +947,17 @@ msgstr "Freund hinzufügen" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Einladung annehmen" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Einladung ablehnen" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Profil anzeigen" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1144,7 +1145,7 @@ msgstr "Mitwirkende" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Überspringen" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -2024,7 +2025,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Du kannst spielen, ohne ein Online-Konto zu erstellen, indem du ein Offline-Konto auswählst. Allerdings kannst du dich dann nicht mit Freunden verbinden, für Add-ons abstimmen usw. Bitte lies unsere Datenschutzerklärung unter https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2537,7 +2538,7 @@ msgstr "Basketbälle können mit präzisen Rückwärtsschüssen mit einer Bowlin msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "" +msgstr "Krache anderen Karts nicht ins Heck, das verlangsamt dich." #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." diff --git a/data/po/el.po b/data/po/el.po index be2b05ffbe6..0ba9e93a030 100644 --- a/data/po/el.po +++ b/data/po/el.po @@ -17,7 +17,7 @@ # Nick Tsakalidis , 2021 # othon alexandros stamataras , 2022 # Savvas Adamtziloglou , 2021 -# Vangelis Skarmoutsos , 2015-2017 +# Vangelis Skarmoutsos (SkarmoutsosV) , 2015-2017 # 79353a696ad19dc202b261b3067b7640_bec941e, 2015 # Χριστόφορος Δρόσος , 2019 msgid "" diff --git a/data/po/eo.po b/data/po/eo.po index c8dc8172965..ba6ad2286fa 100644 --- a/data/po/eo.po +++ b/data/po/eo.po @@ -6,15 +6,16 @@ # FIRST AUTHOR , 2011 # Hendur Saga , 2020 # Lagash, 2022 -# Jakub Fabijan , 2021 +# Jakub Fabijan (Felidae) , 2021 +# Jakub Fabijan (Felidae) , 2023 # Jonas Marx , 2017 -# Jorge Maldonado Ventura , 2021 +# Jorge , 2021 # Kevin G , 2021 # Lagash, 2022 # Lagash, 2022 # Lagash, 2022 # Nicolas G, 2022 -# Nicolas G, 2022 +# Nicolas G, 2022-2023 # Przemysław Wierzbowski, 2023 # Rachel Singh , 2018 # Robin van der Vliet , 2015 @@ -28,7 +29,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Przemysław Wierzbowski, 2023\n" +"Last-Translator: Nicolas G, 2022-2023\n" "Language-Team: Esperanto (http://app.transifex.com/supertuxkart/supertuxkart/language/eo/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -467,7 +468,7 @@ msgstr "Lumŝafto (diaj radioj)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Ambient occlusion" -msgstr "" +msgstr "Ambianta okludo" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -497,7 +498,7 @@ msgstr "Bildbazita lumigo" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Light Scattering" -msgstr "" +msgstr "Lumdisvastigo" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -927,7 +928,7 @@ msgstr "Uzantinformo" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Forigi amikon" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -937,17 +938,17 @@ msgstr "Aldoni amikon" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Akcepti peton" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Malakcepti peton" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Vidi profilon" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1135,7 +1136,7 @@ msgstr "Agnoskoj" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Salti" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1433,7 +1434,7 @@ msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " "pressing the appropriate key or button. You can see your current level of " "nitro in the gauge at the bottom-right of the race screen." -msgstr "" +msgstr "Kolekti nitron permesas al vi obteni rapidajn akcelojn kiam ajn vi deziras premante la taŭgan butonon. Vi povas vidi vian aktualan nivelon de nitron en la mezurilo ĉe la malsupre-dekstre de la ekrano de la vetkuro." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu @@ -2740,7 +2741,7 @@ msgstr "Minigolfo" #. I18N: ../stk-assets/tracks/oasis/track.xml msgid "Oasis" -msgstr "" +msgstr "Oazo" #. I18N: ../stk-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" diff --git a/data/po/es.po b/data/po/es.po index 322e16ba394..3fc68fbd2d7 100644 --- a/data/po/es.po +++ b/data/po/es.po @@ -4,7 +4,7 @@ # # Translators: # Benau, 2018 -# Benau, 2018 +# Benau, 2018,2024 # Marc Coll Carrillo , 2015-2023 # MxtApps , 2022 # MxtApps , 2022 @@ -19,7 +19,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Tagomago , 2020-2021,2023\n" +"Last-Translator: Benau, 2018,2024\n" "Language-Team: Spanish (http://app.transifex.com/supertuxkart/supertuxkart/language/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -2690,7 +2690,7 @@ msgstr "¿Qué pasa, pequeños hippies? ¿Vuestro gran líder Gnu ha desaparecid #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." -msgstr "¡Oh,sí! Ahora está en mi castillo, y será servido como cena..." +msgstr "¡Oh, sí! Ahora está en mi castillo, y será servido como cena..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml diff --git a/data/po/fil.po b/data/po/fil.po index 99cd7507c0d..0e1e23e0b8e 100644 --- a/data/po/fil.po +++ b/data/po/fil.po @@ -910,7 +910,7 @@ msgstr "Info ng User" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Tanggalin ang Kaibigan" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -920,17 +920,17 @@ msgstr "Idagdag ang kaibigan" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Tanggapin ang Imbita" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Tanggihan ang Imbita" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Itignan ang Profile" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1118,7 +1118,7 @@ msgstr "Mga Kredito" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "I-skip" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1998,7 +1998,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Maari kang maglaro nang hindi gumawa ng online na account sa pamamagitan ng pagpili ng offline na account. Bagaman ay hindi ka makakakonekta sa mga kaibigan, bumoto sa mga addon atbp. Mangyaring basahin ang aming pribadong pahayag sa https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 diff --git a/data/po/fr.po b/data/po/fr.po index 87a15309d02..5ee7f4744c5 100644 --- a/data/po/fr.po +++ b/data/po/fr.po @@ -4,7 +4,7 @@ # # Translators: # adrien vigneron , 2015 -# Alayan , 2018-2019 +# Alayan, 2018-2019,2024 # alfu5, 2022 # Anard0 , 2020 # Anard0 , 2020 @@ -13,8 +13,9 @@ # Benau, 2020-2021 # Clément Escude--Cotinat, 2022 # Clément Escude--Cotinat, 2022 +# Cwpute BipBoup, 2024 # devnoname120 , 2015 -# Alayan , 2018 +# Alayan, 2018 # Éfrit, 2015 # Éfrit, 2015 # Éfrit, 2015 @@ -37,7 +38,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Jérôme HERBINET, 2023\n" +"Last-Translator: Alayan, 2018-2019,2024\n" "Language-Team: French (http://app.transifex.com/supertuxkart/supertuxkart/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -111,7 +112,7 @@ msgstr "Un vrai pilote de Formule 1 !" msgid "" "Win against at least 3 AIs in normal race, time-trial, and follow the " "leader." -msgstr "Gagne contre au moins 3 intelligences artificielles dans une Course normale, Course contre la montre et Suis le meneur." +msgstr "Gagne contre au moins 3 IA dans les modes Course normale, Course contre la montre et Suivez-le-Chef." #. I18N: ./data/achievements.xml msgid "Powerup Love" @@ -936,7 +937,7 @@ msgstr "Informations sur l’utilisateur" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Retirer un ami" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -946,17 +947,17 @@ msgstr "Ajouter un ami" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Accepter l'invitation" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Refuser l'invitation" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Voir le profil" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1144,7 +1145,7 @@ msgstr "Générique" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Passer" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1428,7 +1429,7 @@ msgstr "Débuter le tutoriel" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." -msgstr "Ramasse les boîtes bleues : elles contiennent des armes et divers bonus." +msgstr "Ramasse les cadeaux bleus, ils te donneront des bonus." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu @@ -1493,7 +1494,7 @@ msgid "" "Follow the leader: Run for second place, as the last kart will be " "disqualified every time the counter hits zero. Beware: going in front of the" " leader will get you eliminated too!" -msgstr "Suis le meneur de course : vise le second rang, car le dernier kart sera éliminé à chaque fois que le décompte atteint zéro. Attention : dépasser le meneur de cours va aussi conduire à l'élimination !" +msgstr "Suivez-le-Chef : vise la deuxième place, car le dernier kart sera éliminé à chaque fois que le décompte atteint zéro. Attention : dépasser le chef (le meneur) vous éliminera également !" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1526,7 +1527,7 @@ msgstr "Course contre un enregistrement : Faites la course contre des enregistre #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "" +msgstr "Tours contre-la-montre : terminer autant de tours que possible en un temps donné" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1535,12 +1536,12 @@ msgid "" "instead of playing a single race, you play many in a row. The better you " "rank, the more points you get. In the end, the player with the most points " "wins the cup." -msgstr "* Plusieurs de ces modes de jeu sont disponibles en mode Grand Prix: plusieurs courses sont disputées au lieu d’une seule. Plus votre position est bonne, plus vous gagnez de points. À la fin, le joueur ayant le plus de points remporte la coupe." +msgstr "* Beaucoup de ces modes de jeux peuvent être joués à la manière du Grand Prix: au lieu d’une seule course, vous en disputez plusieurs à la suite. Plus vous atteignez une place élevée du classement, et plus vous gagnez de points. À la fin, le joueur ayant le plus de points remporte la coupe." #. I18N: ./data/gui/screens/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" -msgstr "Afin de vous aider à obtenir la victoire, des bonus peuvent être collectés :" +msgstr "Pour t'aider à gagner, il y a des bonus que tu peux ramasser :" #. I18N: ./data/gui/screens/help3.stkgui msgid "" @@ -1580,13 +1581,13 @@ msgstr "Parachute - ralentit tous les karts en meilleure position." msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." -msgstr "Échangeur - pour une courte durée, les coffrets cadeaux sont transformés en bananes et vice-versa, et les nitros, en chewing-gums." +msgstr "Échangeur - pour une courte durée, les cadeaux sont transformés en bananes, les nitros sont transformées en chewing-gums, et vice-versa." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." -msgstr "Balle de basket - poursuit le premier joueur, et peut écraser et ralentir les karts sur son passage." +msgstr "Balle de basket - poursuit le meneur en rebondissant, et peut écraser et ralentir les karts sur son passage." #. I18N: ./data/gui/screens/help3.stkgui msgid "" @@ -1645,7 +1646,7 @@ msgstr "Quand vous complétez un défi, vous obtenez une coupe. Chaque coupe vau msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." -msgstr "Quand vous obtenez le nombre de points indiqué sous cette icône, vous recevrez une surprise. Il y en a plusieurs à collecter." +msgstr "Quand tu obtiendras le nombre de points indiqué sous cette icône, tu recevras une surprise. Il y en a plusieurs à collectionner." #. I18N: ./data/gui/screens/help6.stkgui msgid "" @@ -1945,7 +1946,7 @@ msgstr "Amis" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: In the profile screen msgid "Look for more friends:" -msgstr "Chercher des amis :" +msgstr "Chercher plus d'amis :" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: ./data/gui/screens/online/user_search.stkgui @@ -2024,7 +2025,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Tu peux jouer sans créer de compte en ligne en sélectionnant un compte hors-ligne. Toutefois, tu ne pourras pas communiquer avec tes amis, noter les extensions, etc. Merci de lire notre déclaration de confidentialité sur https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2460,7 +2461,7 @@ msgstr "L´interface graphique peut être modifiée dans le menu des options d'i #. I18N: ./data/tips.xml msgid "You can see other karts' powerups by enabling it in the UI options." -msgstr "Vous pouvez voir les bonus des autres karts en l´activant dans les options de l´interface." +msgstr "Tu peux voir les bonus des autres karts en l´activant dans les options de l´interface." #. I18N: ./data/tips.xml msgid "The font size can be changed in the UI options." @@ -2537,7 +2538,7 @@ msgstr "Les ballons de basket peuvent être détruits avec un tir précis vers l msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "" +msgstr "Essaies de ne pas percuter l'arrière des autres karts pour ne pas être ralenti." #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." @@ -2551,7 +2552,7 @@ msgstr "Dans le football, travaillez en équipe pour réussir." msgid "" "If you miss the ball and an opponent is approaching, try hitting them with a" " powerup or block their way." -msgstr "Si vous ratez la balle et qu´un adversaire approche, essayez de le toucher avec un bonus ou bloquer leur la voie." +msgstr "Si tu rates la balle et qu´un adversaire approche, essaies de le toucher avec un bonus ou mets-toi en travers de son chemin." #. I18N: ./data/tips.xml msgid "Good rotation of positions (attack and defense) is essential." @@ -2625,7 +2626,7 @@ msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml msgid "Sara" -msgstr "Sata" +msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml msgid "Suzanne" @@ -2694,7 +2695,7 @@ msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml msgid "Hole Drop" -msgstr "" +msgstr "Trou de Chute" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" @@ -2703,7 +2704,7 @@ msgstr "Terrain de football glacé" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" -msgstr "Qu’y a-t-il, petits hippies ? Votre chef le grand gnu est absent ?" +msgstr "Qu’est-ce qui se passe les petits hippies ? Votre grand chef gnou a disparu ?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml @@ -2749,7 +2750,7 @@ msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml msgid "Oasis" -msgstr "" +msgstr "Oasis" #. I18N: ../stk-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" @@ -2847,7 +2848,7 @@ msgstr "Contre la montre (course simple)" #: src/challenges/challenge_data.cpp:318 msgid "Follow the Leader (single race)" -msgstr "Suivre le meneur de course (course simple)" +msgstr "Suivez-le-Chef (course simple)" #. I18N: In the Select challenge dialog, tell user this challenge has reversed #. laps @@ -4041,13 +4042,13 @@ msgstr "%s est sur le serveur \"%s\"." #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" -msgstr[0] "Tu as %d nouvelle demande d'amitié !" -msgstr[1] "Tu as %d nouvelles demandes d’amitié !" -msgstr[2] "Tu as %d nouvelles demandes d’amitié !" +msgstr[0] "Tu as %d nouvelle demande d'ami !" +msgstr[1] "Tu as %d nouvelles demandes d’ami !" +msgstr[2] "Tu as %d nouvelles demandes d’ami !" #: src/online/online_player_profile.cpp:556 msgid "You have a new friend request!" -msgstr "Tu as une nouvelle demande d'amitié !" +msgstr "Tu as une nouvelle demande d'ami !" #: src/online/xml_request.cpp:83 msgid "" @@ -4076,7 +4077,7 @@ msgstr "Le fichier des meilleurs scores était trop vieux,\n il a donc été sup #. I18N: Game mode #: src/race/race_manager.cpp:1286 msgid "Follow the Leader" -msgstr "Suis le meneur" +msgstr "Suivez-le-Chef" #. I18N: Game mode #: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 @@ -4236,7 +4237,7 @@ msgstr "Courses contre-la-montre remportées" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:176 msgid "Follow-the-Leader races won" -msgstr "Courses Suis le meneur gagnées" +msgstr "Courses Suivez-le-Chef gagnées" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4326,13 +4327,13 @@ msgstr "Courses contre-la-montre complétées" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:206 msgid "Follow-the-Leader races started" -msgstr "Courses Suis le meneur commencées" +msgstr "Courses Suivez-le-Chef commencées" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:208 msgid "Follow-the-Leader races finished" -msgstr "Courses Suis le meneur complétées" +msgstr "Courses Suivez-le-Chef complétées" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -5133,15 +5134,15 @@ msgstr "Aujourd’hui" #: src/states_screens/dialogs/user_info_dialog.cpp:164 msgid "Friend request sent!" -msgstr "Requête d’amitié envoyée !" +msgstr "Demande d'ami envoyée !" #: src/states_screens/dialogs/user_info_dialog.cpp:221 msgid "Friend request accepted!" -msgstr "Requête d’amitié acceptée !" +msgstr "Demande d'ami acceptée !" #: src/states_screens/dialogs/user_info_dialog.cpp:273 msgid "Friend request declined!" -msgstr "Requête d’amitié déclinée !" +msgstr "Demande d'ami refusée !" #: src/states_screens/dialogs/user_info_dialog.cpp:319 msgid "Friend removed!" @@ -5149,7 +5150,7 @@ msgstr "Ami retiré !" #: src/states_screens/dialogs/user_info_dialog.cpp:370 msgid "Friend request cancelled!" -msgstr "Requête d’amitié annulée !" +msgstr "Demande d'ami annulée !" #: src/states_screens/dialogs/user_info_dialog.cpp:480 msgid "Processing" @@ -6123,7 +6124,7 @@ msgstr "Ramasse de la nitro !" #: src/states_screens/race_gui_base.cpp:771 msgid "Follow the leader!" -msgstr "Suis le meneur !" +msgstr "Suivez le chef !" #. I18N: When some GlobalPlayerIcons are hidden, write "Top 10" to show it #: src/states_screens/race_gui_base.cpp:954 @@ -6212,7 +6213,7 @@ msgstr "Éliminé" #: src/states_screens/race_result_gui.cpp:1608 #: src/states_screens/race_result_gui.cpp:1670 msgid "(Own Goal)" -msgstr "(dans son propre but)" +msgstr "(contre son camp)" #: src/states_screens/race_result_gui.cpp:1749 #, c-format @@ -6257,12 +6258,12 @@ msgstr "Tous les coups sont permis, alors collecte des armes et utilise-les judi #: src/states_screens/race_setup_screen.cpp:96 msgid "Contains no powerups, so only your driving skills matter!" -msgstr "Pas de bonus - seuls tes talents de conduite comptent !" +msgstr "Ne contiens aucun bonus, alors seuls tes talents de conduite comptent !" #. I18N: short definition for follow-the-leader game mode #: src/states_screens/race_setup_screen.cpp:109 msgid "Keep up with the leader kart but don't overtake it!" -msgstr "Talonne le meneur, mais sans le dépasser !" +msgstr "Talonne le meneur de course, mais sans le dépasser !" #: src/states_screens/race_setup_screen.cpp:115 msgid "Hit others with weapons until they lose all their lives." @@ -6372,7 +6373,7 @@ msgstr "Accélère en déplaçant l'accélérateur vers le haut, et dirige le ka #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" -msgstr "Récolte les coffrets cadeaux, et utilise l’arme grâce à la touche <%s> pour détruire ces boîtes !" +msgstr "Ramasse des cadeaux, et utilise ton arme avec la touche <%s> pour détruire ces caisses !" #: ../stk-assets/tracks/tutorial/scripting.as:67 msgid "" @@ -6474,7 +6475,7 @@ msgid "" "battle mode against the computer or your friends, and more! For a greater " "challenge, join online and meet players from all over the world and prove " "your racing skills!" -msgstr "Vous pouvez faire une simple course contre d'autres karts, compétitionner dans un de nos Grands Prix, tenter de battre le score au contre la montre, faire la bataille contre l'ordinateur ou vous amis, et plus ! Pour un plus grand défi, rejoignez le jeu en ligne et rencontrez des joueurs des quatre coins du monde et prouvez vos talents de conducteur !" +msgstr "Vous pouvez faire une simple course contre d'autres karts, faire la compétition sur l'un de nos Grands Prix, essayer de battre le record au contre la montre, faire une bataille contre l'ordinateur ou vous amis, et plus encore ! Si vous cherchez le défi, rejoignez le mode en ligne, rencontrez des joueurs des quatre coins du monde et prouvez vos talents de pilote !" #: supertuxkart.appdata.xml:17 msgid "This game has no ads." diff --git a/data/po/gl.po b/data/po/gl.po index ebb5cc571b1..3fd2e168ab6 100644 --- a/data/po/gl.po +++ b/data/po/gl.po @@ -3,18 +3,21 @@ # This file is distributed under the same license as the supertuxkart package. # # Translators: -# abloosy Freksy Woopy, 2021-2022 +# Taitow, 2021-2023 # Adrián Chaves Fernández , 2010,2015 # Adrián Chaves Fernández , 2015-2016 # Adrián Chaves Fernández , 2010 # Adrián Chaves Fernández , 2010-2011,2013 +# nin hum , 2024 +# Taitow, 2023 +# Toño Calo , 2023 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Adrián Chaves Fernández , 2010,2015\n" +"Last-Translator: nin hum , 2024\n" "Language-Team: Galician (http://app.transifex.com/supertuxkart/supertuxkart/language/gl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -54,7 +57,7 @@ msgstr "Pleno!" #. I18N: ./data/achievements.xml msgid "Hit 10 karts with a bowling-ball." -msgstr "Golpea 10 karts cunha bola dos birlos." +msgstr "Golpea 10 karts cunha bóla dos birlos." #. I18N: ./data/achievements.xml msgid "Arch Enemy" @@ -88,7 +91,7 @@ msgstr "Condutor dourado" msgid "" "Win against at least 3 AIs in normal race, time-trial, and follow the " "leader." -msgstr "" +msgstr "Vence contra polo menos 3 IAs nunha carreira normal, contra-reloxo e seguir ao lider." #. I18N: ./data/achievements.xml msgid "Powerup Love" @@ -106,7 +109,7 @@ msgstr "Imparábel" msgid "" "Win 5 single races in a row against at least 3 AIs. Beware, restarting a " "race counts as a loss." -msgstr "" +msgstr "Gaña 5 carreiras individuais seguidas con polo menos 3 IAs. Coidado, reiniciar unha carreira conta como perdida." #. I18N: ./data/achievements.xml msgid "Banana Lover" @@ -132,7 +135,7 @@ msgstr "Matamoscas" msgid "" "Take your opponents for mosquitos! With the swatter, squash them at least 5 " "times in a race." -msgstr "" +msgstr "Fai dos teus oponentes mosquitos! Co matamoscas esmagaos polo menos 5 veces nunha carreira." #. I18N: ./data/achievements.xml msgid "Beyond Luck" @@ -142,7 +145,7 @@ msgstr "Alén da sorte" msgid "" "Win 10 single races in a row in Expert or SuperTux against at least 5 AIs. " "Beware, restarting a race counts as a loss." -msgstr "" +msgstr "Gaña 10 carreiras individuais seguidas con polo menos 5 IAs. Coidado, reiniciar unha carreira conta como perdida." #. I18N: ./data/grandprix/1_penguinplayground.grandprix msgid "Penguin Playground" @@ -419,7 +422,7 @@ msgstr "Cámara trasera" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "Follow ball in soccer mode" -msgstr "Seguir a bola no modo Fútbol" +msgstr "Seguir a bóla no modo Fútbol" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -652,7 +655,7 @@ msgstr "Saír do Servidor" #. I18N: Show in network ingame dialog to allow user to go back to lobby to #. end spectating (for example) msgid "Back to lobby" -msgstr "" +msgstr "Voltar a sala de espera" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button @@ -893,7 +896,7 @@ msgstr "Desvantaxe" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "Press the 'All players ready' button after the player list is ready." -msgstr "" +msgstr "Pulsa o botón 'Todos listos' cando a lista de xogadores estea preparada." #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network @@ -903,7 +906,7 @@ msgstr "Limpar xogadores" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "All players ready" -msgstr "" +msgstr "Todos listos" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -913,7 +916,7 @@ msgstr "Información do usuario" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Eliminar Amigo" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -923,17 +926,17 @@ msgstr "Engadir como amigo" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Aceptar Invitación" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Rexeitar Invitación" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Ver Perfil" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -963,7 +966,7 @@ msgstr "Escolle un kart:" #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When changing input configurations msgid "Press fully and release..." -msgstr "" +msgstr "Preme a fondo e solta..." #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input @@ -1121,7 +1124,7 @@ msgstr "Contribuidores" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Saltar" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1325,7 +1328,7 @@ msgstr "Modos de xogo" #. I18N: ./data/gui/screens/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" -msgstr "" +msgstr "Potenciadores" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: Tab in help menu @@ -1405,7 +1408,7 @@ msgstr "Comezar o titorial" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." -msgstr "" +msgstr "Apaña os agasallos azuis, eles vante dar potenciadores." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu @@ -1419,7 +1422,7 @@ msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " "pressing the appropriate key or button. You can see your current level of " "nitro in the gauge at the bottom-right of the race screen." -msgstr "" +msgstr "Recolleitar nitro permíteche obter máis velocidade cando queiras premendo a tecla ou botón correspondente. Podes ver o teu nivel actual de nitro no indicador na parte inferior dereita da pantalla da carreira." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu @@ -1435,14 +1438,14 @@ msgid "" "help to take sharp turns; while medium skids will boost your speed, long " "skids more so. You can't stop turning while skidding, so orient your kart " "carefully before!" -msgstr "" +msgstr "Podes derrapar premendo unha tecla ou botón especial. Derrapaxes curtas sucesivas axudan a tomar curvas pechadas; mentres que derrapaxes medias aumentarán a túa velocidade, e as derrapaxes longas aínda máis. Non podes deixar de xirar mentres derrapas, así que orienta o teu kart con coidado antes!" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." -msgstr "" +msgstr "Podes obter un impulso de saída premendo o botón de acelerar en 'Listos!', antes de que comece a carreira." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: in the help screen @@ -1451,18 +1454,18 @@ msgstr "Os atallos de teclado poden ser vistos e alterados no menú de Opcións" #. I18N: ./data/gui/screens/help2.stkgui msgid "SuperTuxKart features several game modes:" -msgstr "" +msgstr "O SuperTuxKart ten varios modos de xogo:" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" -msgstr "" +msgstr "Carreira normal: Todos os golpes están permitidos, por iso recolle os potenciadores e úsaos con cabeza!" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" -msgstr "" +msgstr "Contra-Reloxo: Non hai melloras, só o teu talento ao volante conta!" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1480,7 +1483,7 @@ msgid "" "player who hits others the most will win in a given hit or time limit. In " "Capture The Flag, your team needs to bring the flag of the other team to " "your own flag base, as long as your flag is not captured by the other team." -msgstr "" +msgstr "Hai 3 tipos de modo de batalla: En Batalla de 3 golpes, tes que golpear aos demais con armas ata que perdan todas as súas vidas. En Todos contra todos, o xogador que máis golpee aos demais gañará nun límite de golpes ou de tempo determinado. En Captura a bandeira, o teu equipo debe levar a bandeira do outro equipo á túa propia base de bandeira, sempre que a túa bandeira non sexa capturada polo outro equipo." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1503,7 +1506,7 @@ msgstr "Repetición fantasma: Corre contra repeticións fantasma no modo Contra- #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "" +msgstr "Proba de voltas: Completa tantas voltas como sexa posible nun tempo determinado." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1512,7 +1515,7 @@ msgid "" "instead of playing a single race, you play many in a row. The better you " "rank, the more points you get. In the end, the player with the most points " "wins the cup." -msgstr "" +msgstr "* Moitos destes modos de xogo tamén se poden xogar de xeito Gran Premio: en lugar de xogar unha única carreira, xogas a moitas seguidas. Canto mellor clasifiques, máis puntos conseguirás. Ao final, o xogador con máis puntos gaña a copa." #. I18N: ./data/gui/screens/help3.stkgui #. I18N: In the help menu @@ -1529,13 +1532,13 @@ msgstr "Goma de mascar — Protéxete cun escudo, ou úsaa mentres miras cara at msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" -msgstr "" +msgstr "Turbo - darache un forte impulso de velocidade. Pero ten coidado de non perder o control do teu kart!" #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." -msgstr "" +msgstr "Torta - lanzada ao rival máis próximo, ideal a curtas distancias e en rectas longas. Tamén afecta a outros karts próximos á explosión." #. I18N: ./data/gui/screens/help3.stkgui msgid "" @@ -1547,7 +1550,7 @@ msgstr "Chupón — Lánzao cara adiante para ralentizar a un opoñente, ou lán msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." -msgstr "" +msgstr "Bóla de birlos - vai en liña recta até golpear, pode rebotar nas paredes. Se estás mirando cara atrás, será lanzada cara atrás." #. I18N: ./data/gui/screens/help3.stkgui msgid "Parachute - slows down all karts in a better position." @@ -1557,48 +1560,48 @@ msgstr "Paracaídas — Ralentiza todos os karts por diante de ti." msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." -msgstr "" +msgstr "Intercambiador - as caixas de agasallos transfórmase en plátanos, as latas de nitro en gomas de mascar, e viceversa durante un curto período de tempo." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." -msgstr "Bóla de baloncesto — Vai saltando en dirección ao líder, e ralentiza os karts que se atope polo camiño." +msgstr "Balón de baloncesto — Vai saltando en dirección ao líder, e ralentiza os karts que se atope polo camiño." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." -msgstr "" +msgstr "Matamoscas - esmagará os karts próximos, abrandándoos. Tamén pode usarse para eliminar paracaídas e bombas." #. I18N: ./data/gui/screens/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" -msgstr "" +msgstr "Ao golpear un plátano, podes acabar cun dos seguintes enganchado ao kart:" #. I18N: ./data/gui/screens/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." -msgstr "" +msgstr "Áncora - fai diminuír a velocidade do kart de forma súbita." #. I18N: ./data/gui/screens/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." -msgstr "" +msgstr "Paracaídas - fai diminuír a velocidade do kart de forma máis progresiva ca áncora. Canto máis rápido vas, máis forte é o freo." #. I18N: ./data/gui/screens/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." -msgstr "" +msgstr "Bomba - detona despois dun certo tempo, lanzando o kart ao aire. Colide co outro kart para transferir a bomba a el." #. I18N: ./data/gui/screens/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" -msgstr "" +msgstr "O malvado Nolok capturou a Gnu! Aquí tes algúns consellos para axudarche:" #. I18N: ./data/gui/screens/help5.stkgui #. I18N: In the help menu @@ -1607,7 +1610,7 @@ msgid "" "completed. In the top-right of the screen, it also tells you how many points" " you currently have. Complete as many challenges as possible, and Nolok will" " accept to race against you. Win to liberate Gnu!" -msgstr "" +msgstr "Esta icona no minimapa amosa os desafíos dispoñibles que non completaches. No canto superior dereito da pantalla, tamén te indica cantos puntos tes actualmente. Completa tantos desafíos como sexa posible, e Nolok aceptará correr contra ti. Gaña para liberar a Gnu!" #. I18N: ./data/gui/screens/help5.stkgui #. I18N: In the help menu @@ -1615,20 +1618,20 @@ msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " "points. The higher the difficulty you completed the challenge in, the better" " the cup and the more points it is worth." -msgstr "" +msgstr "Cando completas un desafío, recibes unha copa. Cada copa ten varios puntos de valor. Canto máis difícil sexa o desafío completado, mellor será a copa e máis puntos valerá." #. I18N: ./data/gui/screens/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." -msgstr "" +msgstr "Cando consigas o número de puntos indicado baixo esta icona, recibirás unha sorpresa de agasallo. Hai varias para coleccionar." #. I18N: ./data/gui/screens/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" -msgstr "" +msgstr "Non todos os karts conducen igual! Pertencen a clases con varias diferenzas:" #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu @@ -1636,7 +1639,7 @@ msgid "" "Mass - there are three classes of karts, depending on their mass: light, " "medium and heavy. Heavier karts are less affected by parachutes and are more" " resistant to explosions." -msgstr "" +msgstr "Masa - hai tres clases de karts, dependendo da súa masa: lixeiro, medio e pesado. Os karts máis pesados ​​son menos afectados polos paracaídas e son máis resistentes ás explosións." #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu @@ -1644,7 +1647,7 @@ msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " "with a lot of sharp curves. The lighter the kart, the faster it accelerates," " especially at low speeds." -msgstr "" +msgstr "Aceleración - especialmente útil ao comezar, despois dun accidente ou en circuitos con moitas curvas pechadas. Canto máis lixeiro sexa o kart, máis rápido acelera, especialmente a baixas velocidades." #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu @@ -1652,14 +1655,14 @@ msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " "in tracks with straight lines and gentle curves. Heavier karts have a higher" " top speed." -msgstr "" +msgstr "Velocidade máxima - canto máis alta sexa, máis rápido pode ir o kart. Especialmente útil en circuitos con liñas rectas e curvas suaves. Os karts máis pesados teñen unha velocidade máxima maior." #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." -msgstr "" +msgstr "Eficiencia do nitro - Canto maior sexa, máis velocidade obtés do nitro. Un kart máis lixeiro terá unha maior eficiencia de nitro." #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu @@ -1667,12 +1670,12 @@ msgid "" "If you follow closely another kart for a few seconds, you'll get a " "slipstream speed bonus when you overtake it. The lighter your kart, the " "easier it is." -msgstr "" +msgstr "Se segues de cerca outro kart durante uns segundos, obterás un bono de velocidade na estela cando o adiantes. Canto máis lixeiro sexa o teu kart, máis sinxelo será." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" -msgstr "" +msgstr "SuperTuxKart pode ser xogado no modo multixogador online...:" #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1682,7 +1685,7 @@ msgid "" "options). Then, you can either create your own server with custom options, " "or search among a list of existing servers to join. Some of them are " "recommended servers with optionally ranked races." -msgstr "" +msgstr "Primeiro, selecciona a icona 'en liña' no menú principal. Escolle entre rede local ou rede global (require conexión a internet activada nas opcións). Logo, podes crear o teu propio servidor con opcións personalizadas, ou buscar entre unha lista de servidores existentes para unirte a eles. Algúns deles son servidores recomendados con carreiras clasificadas opcionalmente." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1692,12 +1695,12 @@ msgid "" " enough players. Then, you can choose your kart and vote for the next track " "to race on. An addon track is allowed only if it exists on all joined " "players and the server." -msgstr "" +msgstr "Unha vez dentro dun servidor, unha carreira comezará cando o seu dono (simbolizado coa coroa) así o decida. Os servidores oficiais poden iniciar as carreiras automaticamente cando hai suficientes xogadores. Entón, podes elixir o teu kart e votar polo circuito seguinte no que correr. Un circuito adicional está permitida só se existe en todos os xogadores unidos e no servidor." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" -msgstr "" +msgstr "... ou no mesmo dispositivo:" #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1707,7 +1710,7 @@ msgid "" "keyboard(s), each player will need a different set of keys, and most " "keyboards are not appropriate for multiplayer because they don't support " "multiple simultaneous keypresses." -msgstr "" +msgstr "Primeiro, precisarás varios dispositivos de entrada. Usa a pantalla de configuración de entrada para configuralos. Múltiples mandos ou joysticks son ideais: en teclado(s), cada xogador necesitará un conxunto diferente de teclas, e a maioría dos teclados non son apropiados para multixogador porque non admiten pulsacións simultáneas múltiples." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1717,12 +1720,12 @@ msgid "" "keyboard to join the game, and use their input device to select their kart. " "The game continues when everyone selected their kart. Note that the mouse " "may not be used for this operation." -msgstr "" +msgstr "Cando os dispositivos de entrada estean configurados, selecciona a icona de 'Multixogador a pantalla partida' no menú principal. Cada xogador pode premer a tecla de 'disparo' do seu mando ou teclado para unirse ao xogo, e usar o seu dispositivo de entrada para seleccionar o seu kart. O xogo continúa cando todos seleccionaron o seu kart. Ten en conta que non se pode usar o rato para esta operación." #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen msgid "High Score Selection" -msgstr "" +msgstr "Selección de Récords" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen @@ -1731,7 +1734,7 @@ msgstr "" #. time. #: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" -msgstr "" +msgstr "Proba de Voltas" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen @@ -1758,7 +1761,7 @@ msgstr "Un xogador" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Splitscreen Multiplayer" -msgstr "" +msgstr "Multixogador en pantalla dividida" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1786,7 +1789,7 @@ msgstr "Aprendizaxe" #. I18N: In the main screen #: src/states_screens/track_info_screen.cpp:341 msgid "High Scores" -msgstr "" +msgstr "Récords" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen @@ -1824,7 +1827,7 @@ msgstr "Número máximo de xogadores" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen msgid "Password for private server (optional)" -msgstr "" +msgstr "Contrasinal para servidor privado (opcional)" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen @@ -1865,33 +1868,33 @@ msgstr "Sala de espera" #. I18N: In networking lobby to configuration server settings #: src/states_screens/online/networking_lobby.cpp:200 msgid "Configuration" -msgstr "" +msgstr "Configuración" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #: src/states_screens/online/networking_lobby.cpp:192 msgid "Start race" -msgstr "" +msgstr "Comezar carreira" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: In the networking menu msgid "Enable splitscreen or player handicaps" -msgstr "" +msgstr "Activar pantalla dividida ou desvantaxe en xogadores" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button msgid "Local networking" -msgstr "" +msgstr "Rede local" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button msgid "Global networking" -msgstr "" +msgstr "Rede global" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button msgid "Enter server address" -msgstr "" +msgstr "Introducir enderezo do servidor" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button @@ -1911,7 +1914,7 @@ msgstr "…" #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: In the achievements screen msgid "Player rankings" -msgstr "" +msgstr "Clasificacións dos xogadores" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen @@ -1956,7 +1959,7 @@ msgstr "Mudar" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: In the online account settings screen msgid "E-mail:" -msgstr "" +msgstr "E-mail:" #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog @@ -1993,7 +1996,7 @@ msgstr "Nome de usuario por internet" #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" -msgstr "" +msgstr "Reiniciar contrasinal" #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog @@ -2001,7 +2004,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Podes xogar sen crear unha conta en liña seleccionando unha conta fora de liña. Aínda que entón non podes conectarte con amigos, votar por complementos, etc. Por favor, lea a nosa declaración de privacidade en https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2011,12 +2014,12 @@ msgstr "Escolla de servidor" #. I18N: ./data/gui/screens/online/server_selection.stkgui #. I18N: In the server selection screen msgid "Show private server(s)" -msgstr "" +msgstr "Amosa servidor(es) privado(s)." #. I18N: ./data/gui/screens/online/server_selection.stkgui #. I18N: In the server selection screen msgid "Use IPv6 connection" -msgstr "" +msgstr "Usa a conexión IPv6" #. I18N: ./data/gui/screens/online/user_search.stkgui msgid "User search" @@ -2090,7 +2093,7 @@ msgstr "Son" #. I18N: ./data/gui/screens/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" -msgstr "" +msgstr "Interface" #. I18N: ./data/gui/screens/options_audio.stkgui #. I18N: Section in the settings menu @@ -2147,7 +2150,7 @@ msgstr "Controis" #. I18N: ./data/gui/screens/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" -msgstr "" +msgstr "Lingua" #. I18N: ./data/gui/screens/options_audio.stkgui #. I18N: In the audio options screen @@ -2185,7 +2188,7 @@ msgstr "Eliminar a configuración" #: src/states_screens/options/options_screen_device.cpp:125 #: src/states_screens/options/options_screen_device.cpp:632 msgid "Disable Configuration" -msgstr "" +msgstr "Desactivar Configuración" #. I18N: ./data/gui/screens/options_device.stkgui #. I18N: In the input configuration screen @@ -2195,17 +2198,17 @@ msgstr "Volver á lista de dispositivos" #. I18N: ./data/gui/screens/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" -msgstr "" +msgstr "Renomear Configuración" #. I18N: ./data/gui/screens/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" -msgstr "" +msgstr "Activar a retroalimentación de forza (se está soportada)." #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings msgid "Internet options" -msgstr "" +msgstr "Opcións da Internet" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings @@ -2220,17 +2223,17 @@ msgstr "Conectar a internet." #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings msgid "Enable chatting online" -msgstr "" +msgstr "Activar o chat online" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings msgid "Enable chatting in online games" -msgstr "" +msgstr "Activar o chat en xogos online" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" -msgstr "" +msgstr "Opcións diversas" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings @@ -2241,7 +2244,7 @@ msgstr "Activar limitacións por xogador." #. I18N: For mobile version for STK, uninstall the downloaded assets #: src/states_screens/options/options_screen_general.cpp:113 msgid "Uninstall full game assets" -msgstr "" +msgstr "Desinstalar o paquete completo de recursos" #. I18N: ./data/gui/screens/options_input.stkgui #. I18N: In the input configuration screen @@ -2269,27 +2272,27 @@ msgstr "Aparencia:" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Minimap" -msgstr "" +msgstr "Minimapa" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Splitscreen Multiplayer layout" -msgstr "" +msgstr "Distribución do multixogador en pantalla dividida" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" -msgstr "" +msgstr "Tamaño da fonte" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" -msgstr "" +msgstr "Cámara" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." -msgstr "" +msgstr "Personalizada..." #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings @@ -2299,22 +2302,22 @@ msgstr "Amosar os fotogramas por segundo (FPS)." #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" -msgstr "" +msgstr "Mostrar potenciadores dos outros karts" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" -msgstr "" +msgstr "Activar temporizador no modo historia" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" -msgstr "" +msgstr "Activar temporizador en carreira rápida" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" -msgstr "" +msgstr "Resolución da renderización" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings @@ -2324,12 +2327,12 @@ msgstr "Nivel dos efectos gráficos:" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" -msgstr "" +msgstr "Nivel de efectos de desenfoque" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" -msgstr "" +msgstr "Límite de FPS" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings @@ -2396,7 +2399,7 @@ msgstr "Número de opoñentes:" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen msgid "Number of blue team AI karts" -msgstr "" +msgstr "Número de karts IA na equipa azul" #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen @@ -2429,124 +2432,124 @@ msgstr "Eliminar" #. I18N: ./data/gui/screens/user_screen_tab.stkgui #. I18N: In the user screen msgid "Kart color" -msgstr "" +msgstr "Cor do Kart" #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." -msgstr "" +msgstr "O tema da interface pode ser cambiado nas opcións de UI." #. I18N: ./data/tips.xml msgid "You can see other karts' powerups by enabling it in the UI options." -msgstr "" +msgstr "Podes ver os potenciadores doutros karts se activas esta opción nas opcións de UI." #. I18N: ./data/tips.xml msgid "The font size can be changed in the UI options." -msgstr "" +msgstr "O tamaño da fonte pode ser cambiado nas opcións de UI." #. I18N: ./data/tips.xml msgid "The help menu has lots of useful information." -msgstr "" +msgstr "O menú Axuda ten moita información útil." #. I18N: ./data/tips.xml msgid "In single-player, you can watch and challenge recorded time-trials." -msgstr "" +msgstr "No modo un xogador, poderás ver e desafiar as repeticións de contra-reloxo." #. I18N: ./data/tips.xml msgid "" "You can visit https://supertuxkart.net/ for more information about the game." -msgstr "" +msgstr "Podes visitar https://supertuxkart.net/ para máis información sobre o xogo." #. I18N: ./data/tips.xml msgid "Short nitro boosts are more efficient." -msgstr "" +msgstr "Impulsos de nitro curtos son máis eficientes." #. I18N: ./data/tips.xml msgid "Only use zippers when it is safe. Long straight lines are ideal." -msgstr "" +msgstr "Usa os turbos só cando sexa seguro. As rectas longas son ideais." #. I18N: ./data/tips.xml msgid "" "Don't use multiple zippers quickly in row, instead, wait until the speed " "boost wears off." -msgstr "" +msgstr "Non uses varios turbos seguidos rapidamente, espera a que o impulso de velocidade desapareza." #. I18N: ./data/tips.xml msgid "Skidding makes you much faster, do it whenever safe." -msgstr "" +msgstr "Derrapar faite moito máis rápido, por iso derrapa sempre que sexa seguro facelo." #. I18N: ./data/tips.xml msgid "The swatter can be used to remove bombs or parachutes." -msgstr "" +msgstr "O matamoscas pode ser usado para eliminar bombas e paracaídas." #. I18N: ./data/tips.xml msgid "" "You can't stop turning while skidding. Good kart orientation at the skid's " "start is paramount." -msgstr "" +msgstr "Non podes deixar de virar mentres derrapas. A orientación adecuada do kart ao comezo do derrape é fundamental." #. I18N: ./data/tips.xml msgid "You get a startup boost if you start accelerating during \"Set\"." -msgstr "" +msgstr "Obtes un impulso inicial se comezas a acelerar durante \"Preparados\"." #. I18N: ./data/tips.xml msgid "Braking allows to get rid of parachutes quicker." -msgstr "" +msgstr "Frear axuda a desfacerse dos paracaidas máis rapido." #. I18N: ./data/tips.xml msgid "First and foremost, focus on where your kart is going." -msgstr "" +msgstr "En primeiro lugar, concéntrate en a onde vai o teu kart." #. I18N: ./data/tips.xml msgid "The rescue key (button) is very useful." -msgstr "" +msgstr "A tecla (ou botón) de rescate é moi útil." #. I18N: ./data/tips.xml msgid "Be careful when close to other karts, they may attack you!" -msgstr "" +msgstr "Ten coidado cando esteas preto doutros karts, poden atacarte!" #. I18N: ./data/tips.xml msgid "" "Basketballs can be destroyed using precise backward shots with a bowling " "ball, cake, or plunger." -msgstr "" +msgstr "Os balóns de baloncesto poden ser destruídas lanzando tiros precisos cara atrás cunha bóla de birlos, unha torta ou un chupón." #. I18N: ./data/tips.xml msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "" +msgstr "Tenta evitar colidir contra as costas doutros karts xa que isto vai ralentizarte." #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." -msgstr "" +msgstr "Podes usar as bólas de birlos para empurrar e bloquear o balón." #. I18N: ./data/tips.xml msgid "In soccer, always work as a team for good results." -msgstr "" +msgstr "No modo fútbol, traballa sempre coa túa equipa para obter bos resultados." #. I18N: ./data/tips.xml msgid "" "If you miss the ball and an opponent is approaching, try hitting them with a" " powerup or block their way." -msgstr "" +msgstr "Se erras o balón e un rival se achega, intenta golpealo cun potenciador ou bloquea o seu camiño." #. I18N: ./data/tips.xml msgid "Good rotation of positions (attack and defense) is essential." -msgstr "" +msgstr "É esencial unha boa rotación das posicións (ataque e defensa)." #. I18N: ./data/tips.xml msgid "Make sure to store at least 2 big cans worth of nitro." -msgstr "" +msgstr "Asegúrate de almacenar polo menos 2 garrafas enteiras de nitro. " #. I18N: ./data/tips.xml msgid "Never use the three bowling balls all at the same time." -msgstr "" +msgstr "Xamais uses as tres bólas de birlos ao mesmo tempo." #. I18N: ./data/tips.xml msgid "" "Don't get in the way of a teammate carrying the ball, though you can try to " "hit opponents attempting to stop them from scoring." -msgstr "" +msgstr "Non te poñas no camiño dun compañeiro de equipo que leva o balón, aínda que podes intentar golpear aos rivais que intenten evitar que marquen." #. I18N: ../stk-assets/karts/adiumy/kart.xml msgid "Adiumy" @@ -2655,7 +2658,7 @@ msgstr "Templo do cacao" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" -msgstr "" +msgstr "Travesia do Milleiral" #. I18N: ../stk-assets/tracks/fortmagma/track.xml msgid "Fort Magma" @@ -2671,11 +2674,11 @@ msgstr "Facenda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml msgid "Hole Drop" -msgstr "" +msgstr "Caída polo burato" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" -msgstr "" +msgstr "Campo de Fútbol Xeado" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml @@ -2706,11 +2709,11 @@ msgstr " Pero xa vos aviso, ningún de vós —patéticos ananos— conseguirá #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "" +msgstr "Las Dunas Area" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" -msgstr "" +msgstr "Estadio de Fútbol Las Dunas" #. I18N: ../stk-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" @@ -2726,7 +2729,7 @@ msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml msgid "Oasis" -msgstr "" +msgstr "Oasis" #. I18N: ../stk-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" @@ -2791,7 +2794,7 @@ msgstr "Conseguiches o logro «%s»." #: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 msgid "Failed to connect to the SuperTuxKart add-ons server." -msgstr "" +msgstr "Non foi posible conectar ao servidor de extensións do SuperTuxKart." #: src/addons/news_manager.cpp:180 #, c-format @@ -2808,11 +2811,11 @@ msgstr "Contra-Reloxo (Campionato)" #: src/challenges/challenge_data.cpp:310 msgid "Time-Trial - beat the replay" -msgstr "" +msgstr "Proba contra o tempo - supera a repetición" #: src/challenges/challenge_data.cpp:312 msgid "Time-Trial - nitro challenge" -msgstr "" +msgstr "Proba contra o tempo - desafío de nitro" #: src/challenges/challenge_data.cpp:314 msgid "Normal Race (single race)" @@ -2866,7 +2869,7 @@ msgid "" "Closing the game before the story mode's completion invalidates the timer.\n" "\n" "To use the speedrun mode, please use a new profile." -msgstr "" +msgstr "O modo carreira rápida desactivado. Só se pode activar se o xogo non foi pechado desde o lanzamento do modo historia.\n\nPechar o xogo antes de completar o modo historia invalida o cronómetro.\n\nPara usar o modo carreira rápida, por favor, utiliza un novo perfil." #. I18N: Name of first guest player (without number) #: src/config/player_manager.cpp:396 @@ -3505,42 +3508,42 @@ msgstr "Control de dirección á dereita" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:181 msgid "Left thumbstick right" -msgstr "" +msgstr "Botón analóxico esquerdo dereita" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:183 msgid "Left thumbstick left" -msgstr "" +msgstr "Botón analóxico esquerdo esquerda" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:185 msgid "Left thumbstick down" -msgstr "" +msgstr "Botón analóxico esquerdo abaixo" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:187 msgid "Left thumbstick up" -msgstr "" +msgstr "Botón analóxico esquerdo arriba" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:189 msgid "Right thumbstick right" -msgstr "" +msgstr "Botón analóxico dereito dereita" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:191 msgid "Right thumbstick left" -msgstr "" +msgstr "Botón analóxico dereito esquerda" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:193 msgid "Right thumbstick down" -msgstr "" +msgstr "Botón analóxico dereito abaixo" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:195 msgid "Right thumbstick up" -msgstr "" +msgstr "Botón analóxico dereito arriba" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:197 @@ -3570,14 +3573,14 @@ msgstr "%s está con pouca batería." msgid "" "Connect your wiimote to the Bluetooth manager, then click on Ok. Detailed " "instructions at https://supertuxkart.net/Wiimote" -msgstr "" +msgstr "Conecta o teu wiimote ao xestor de Bluetooth e fai clic en Aceptar. Instrucións detalladas en https://supertuxkart.net/Wiimote" #: src/input/wiimote_manager.cpp:382 msgid "" "Press the buttons 1+2 simultaneously on your wiimote to put it in discovery " "mode, then click on Ok. Detailed instructions at " "https://supertuxkart.net/Wiimote" -msgstr "" +msgstr "Preme os botóns 1+2 simultaneamente no teu wiimote para poñelo en modo de descubrimento e, a continuación, fai clic en Aceptar. Instrucións detalladas en https://supertuxkart.net/Wiimote" #: src/input/wiimote_manager.cpp:405 #, c-format @@ -3600,7 +3603,7 @@ msgstr "Penalización de tempo!" #: src/karts/controller/local_player_controller.cpp:332 msgid "Don't accelerate before 'Set!'" -msgstr "" +msgstr "Non aceleres antes de 'Listos!'" #: src/karts/controller/spare_tire_ai.cpp:150 msgid "You can have at most 3 lives!" @@ -3612,7 +3615,7 @@ msgstr "+1 vida" #: src/karts/kart.cpp:1024 msgid "You were too slow!" -msgstr "" +msgstr "Fuches moi amodo!" #: src/karts/kart.cpp:1025 msgid "You won the race!" @@ -3621,7 +3624,7 @@ msgstr "Gañaches a carreira!" #: src/karts/kart.cpp:1026 #, c-format msgid "You finished the race in rank %d!" -msgstr "" +msgstr "Remataches a carreira no %dº lugar!" #. I18N: Message shown in game to tell player left the game in network #: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 @@ -3636,11 +3639,11 @@ msgid "" " Would you like this feature to be enabled? (To change this setting at a " "later time, go to options, select tab 'General', and edit \"Connect to the " "Internet\")." -msgstr "" +msgstr "SuperTuxKart pode conectarse a un servidor para descargar complementos e notificarche as actualizacións. Lea a nosa política de privacidade en https://supertuxkart.net/Privacy. Queres que se habilite esta función? (Para cambiar esta configuración máis tarde, vai a opcións, selecciona a lapela \"Xeral\" e edita \"Conectar a Internet\")." #: src/main.cpp:2386 msgid "Your screen resolution is too low to run STK." -msgstr "" +msgstr "A túa resolución de pantalla é demasiado baixa para correr o STK." #: src/main.cpp:2437 msgid "" @@ -3653,7 +3656,7 @@ msgid "" "Your graphics driver appears to be very old. Please check if an update is " "available. SuperTuxKart recommends a driver supporting %s or better. The " "game will likely still run, but in a reduced-graphics mode." -msgstr "" +msgstr "O teu controlador de gráficos parece ser moi antigo. Comproba se hai unha actualización dispoñible. SuperTuxKart recomenda un controlador compatible %s ou mellor. É probable que o xogo aínda funcione, pero nun modo de gráficos reducidos." #: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 msgid "Server connection timed out." @@ -3737,8 +3740,8 @@ msgstr "Ups, %s marcou en propia!" #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Xurdiu %i o kart con neumático de reposto!" +msgstr[1] "Xurdiron %i os karts con neumático de reposto!" #: src/modes/world.cpp:1427 msgid "You have been eliminated!" @@ -3751,20 +3754,20 @@ msgstr "%s quedou eliminado." #: src/network/protocols/client_lobby.cpp:129 msgid "Server has been shut down." -msgstr "" +msgstr "O servidor foi desconectado." #: src/network/protocols/client_lobby.cpp:130 msgid "You were kicked from the server." -msgstr "" +msgstr "Fuches expulsado do servidor." #: src/network/protocols/client_lobby.cpp:132 msgid "You were kicked: Ping too high." -msgstr "" +msgstr "Fuches expulsado: Ping demasiado alto." #: src/network/protocols/client_lobby.cpp:297 #: src/network/protocols/client_lobby.cpp:911 msgid "Bad network connection is detected." -msgstr "" +msgstr "Foi detectado unha mala conexión da rede." #: src/network/protocols/client_lobby.cpp:463 #: src/network/protocols/server_lobby.cpp:3848 @@ -3781,7 +3784,7 @@ msgstr "%s desconectouse." #: src/network/protocols/client_lobby.cpp:672 msgid "" "Press player name in the list for player management and ranking information." -msgstr "" +msgstr "Preme no nome do xogador na lista para a xestión do xogador e ver a súa clasificación." #. I18N: In the networking lobby #. I18N: In server info dialog @@ -3839,7 +3842,7 @@ msgstr "Progreso do Campionato: %d / %d" #. will not be allowed to start #: src/network/protocols/client_lobby.cpp:903 msgid "All players joined red or blue team." -msgstr "" +msgstr "Todos os xogadores uníronse a equipa vermella ou azul." #. I18N: Display when a player is allow to control the server #: src/network/protocols/client_lobby.cpp:923 @@ -3848,46 +3851,46 @@ msgstr "Agora es o dono do servidor." #: src/network/protocols/client_lobby.cpp:966 msgid "Connection refused: Server is busy." -msgstr "" +msgstr "Conexión rexeitada: O servidor está ocupado." #: src/network/protocols/client_lobby.cpp:971 msgid "Connection refused: You are banned from the server." -msgstr "" +msgstr "Conexión rexeitada: Estás baneado do servidor." #: src/network/protocols/client_lobby.cpp:986 msgid "Connection refused: Server password is incorrect." -msgstr "" +msgstr "Conexión rexeitada: Contrasinal do servidor incorrecto." #: src/network/protocols/client_lobby.cpp:990 msgid "Connection refused: Game data is incompatible." -msgstr "" +msgstr "Conexión rexeitada: Os datos do xogo son incompatibles." #: src/network/protocols/client_lobby.cpp:994 msgid "Connection refused: Server is full." -msgstr "" +msgstr "Conexión rexeitada: O servidor está cheo." #: src/network/protocols/client_lobby.cpp:998 msgid "Connection refused: Invalid player connecting." -msgstr "" +msgstr "Conexión rexeitada: A conexión do xogador non é válida." #: src/network/protocols/client_lobby.cpp:1026 msgid "Failed to start the network game." -msgstr "" +msgstr "Non foi posible iniciar ao xogo online." #. I18N: Error message shown if live join or spectate failed in network #: src/network/protocols/client_lobby.cpp:1241 msgid "The game has ended, you can't live join or spectate anymore." -msgstr "" +msgstr "O xogo rematou, xa non podes unirte en directo nin como espectador." #. I18N: Error message shown if live join failed in network #: src/network/protocols/client_lobby.cpp:1245 msgid "No remaining place in the arena - live join disabled." -msgstr "" +msgstr "Non queda ningún lugar na area: unión en directo está desactivada." #. I18N: Error message shown if only 1 player remains in network #: src/network/protocols/client_lobby.cpp:1249 msgid "Only 1 player remaining, returning to lobby." -msgstr "" +msgstr "Queda só 1 xogador, volvendo a sala de espera." #: src/network/protocols/client_lobby.cpp:1255 msgid "Server owner quit the game." @@ -3896,7 +3899,7 @@ msgstr "O dono do servidor saíu do xogo." #. I18N: Status shown to player when he will be spectating the next game #: src/network/protocols/client_lobby.cpp:1259 msgid "You will be spectating the next game." -msgstr "" +msgstr "Estarás mirando o próximo partido." #. I18N: Show when player join red team of the started game in #. network @@ -3925,13 +3928,13 @@ msgstr "%s entrou no xogo." msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " "camera position." -msgstr "" +msgstr "Preme <%s> ou <%s> para cambiar o xogador, <%s> ou <%s> para cambiar a cámara." #. I18N: Tell player he has successfully report this named player #: src/network/protocols/client_lobby.cpp:1654 #, c-format msgid "Successfully reported %s." -msgstr "" +msgstr "%s Reportado con éxito." #. I18N: Shown when there is download error for assets download #. in the first run @@ -3940,7 +3943,7 @@ msgstr "" msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." -msgstr "" +msgstr "Erro ao descargar os recursos, verifica o teu espazo de almacenamento máis a conexión a internet e tentao de novo." #: src/network/protocols/connect_to_server.cpp:230 msgid "No quick play server available." @@ -3955,11 +3958,11 @@ msgstr "Non foi posible conectarse ao servidor %s." #: src/network/protocols/connect_to_server.cpp:883 #, c-format msgid "Failed to detect port number for server %s." -msgstr "" +msgstr "Erro ao detectar o número do porto para o servidor %s." #: src/network/protocols/lobby_protocol.cpp:294 msgid "Network grand prix has been finished." -msgstr "" +msgstr "O gran premio en rede rematou." #: src/network/server_config.cpp:263 msgid "Time Trial (Grand Prix)" @@ -4182,7 +4185,7 @@ msgstr "Cumprir polo menos un obxectivo secundario" #. I18N: For achievements, a parent goal linking logically several subgoals #: src/states_screens/dialogs/achievement_progress_dialog.cpp:168 msgid "The sum of the subgoals must reach the indicated value" -msgstr "" +msgstr "A suma dos subobxectivos debe acadar o valor indicado." #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4220,55 +4223,55 @@ msgstr "Carreiras consecutivas gañadas" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:180 msgid "Consecutive won races in Expert or SuperTux" -msgstr "" +msgstr "Carreras gañadas consecutivamente en Experto ou SuperTux" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:182 msgid "Novice races started" -msgstr "" +msgstr "Carreiras iniciadas na dificultade Principiante" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:184 msgid "Novice races finished" -msgstr "" +msgstr "Carreiras rematadas na dificultade Principiante" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:186 msgid "Intermediate races started" -msgstr "" +msgstr "Carreiras iniciadas na dificultade Intermedio" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:188 msgid "Intermediate races finished" -msgstr "" +msgstr "Carreiras rematadas na dificultade Intermedio" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:190 msgid "Expert races started" -msgstr "" +msgstr "Carreiras de expertos comezadas" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:192 msgid "Expert races finished" -msgstr "" +msgstr "Carreiras de expertos rematadas" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:194 msgid "SuperTux races started" -msgstr "" +msgstr "Carreiras de SuperTux comezadas" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:196 msgid "SuperTux races finished" -msgstr "" +msgstr "Carreiras de SuperTux rematadas" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4370,20 +4373,20 @@ msgstr "Partidas de Capturar a Bandeira rematadas" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:230 msgid "Free-for-All matches started" -msgstr "" +msgstr "Comezaron as partidas de todos contra todos" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:232 msgid "Free-for-All matches finished" -msgstr "" +msgstr "Remataron as partidas de todos contra todos" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:234 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:236 msgid "Powerups used" -msgstr "" +msgstr "Potenciadores usados" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4395,34 +4398,34 @@ msgstr "" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:254 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:262 msgid " (1 race)" -msgstr "" +msgstr "(1 carreira)" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:238 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:240 msgid "Bowling ball hits" -msgstr "" +msgstr "Golpes de bólas de birlos" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:242 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:244 msgid "Swatter hits" -msgstr "" +msgstr "Golpes do Matamoscas" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:246 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:248 msgid "All hits" -msgstr "" +msgstr "Todos os golpes" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:250 msgid "Hits against the same kart" -msgstr "" +msgstr "Golpes contra o mesmo kart" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4445,7 +4448,7 @@ msgstr "Derrapar" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:269 msgid " (1 lap)" -msgstr "" +msgstr "(1 volta)" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4495,21 +4498,21 @@ msgstr "Carreeiras rematadas só" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:282 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:307 msgid "Races with less than the default lap number" -msgstr "" +msgstr "Carreiras con menos voltas que o número por defecto" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:284 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:309 msgid "Races with more than the default lap number" -msgstr "" +msgstr "Carreiras con máis voltas que o número por defecto" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:286 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:311 msgid "Races with at least twice as much as the default lap number" -msgstr "" +msgstr "Carreiras con polo menos o dobre de voltas que o número por defecto" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4538,14 +4541,14 @@ msgstr "Caza dos ovos rematadas" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:313 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:319 msgid " (official tracks matching the goal)" -msgstr "" +msgstr "(circuítos oficiais que corresponden co obxectivo)" #: src/states_screens/dialogs/add_device_dialog.cpp:64 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" "To add a keyboard config, you can use the button below, HOWEVER please note that most keyboards only support a limited amount of simultaneous keypresses and are thus inappropriate for multiplayer gameplay. (You can, however, connect multiple keyboards to this device. Remember that everyone still needs different keybindings in this case.)" -msgstr "" +msgstr "Os novos mandos e joysticks aparecerán automaticamente na lista cando os conectes a este dispositivo.\n\nPara engadir unha configuración de teclado, podes usar o botón de abaixo, CON TODO, ten en conta que a maioría dos teclados só admiten un número limitado de pulsacións simultáneas e, polo tanto, non son apropiados para xogos multixogador. (Con todo, podes conectar varios teclados a este dispositivo. Lembra que cada un aínda precisa diferentes combinacións de teclas neste caso.)" #. I18N: In the 'add new input device' dialog #: src/states_screens/dialogs/add_device_dialog.cpp:87 @@ -4602,15 +4605,15 @@ msgstr "Non se puido eliminar o complemento «%s»." #: src/states_screens/dialogs/addons_pack.cpp:66 msgid "Background download completed." -msgstr "" +msgstr "Descarga en segundo plano completada." #: src/states_screens/dialogs/addons_pack.cpp:127 msgid "Background download" -msgstr "" +msgstr "Descarga en segundo plano" #: src/states_screens/dialogs/addons_pack.cpp:136 msgid "Background download has already started." -msgstr "" +msgstr "A descarga en segundo plano xa foi iniciada" #: src/states_screens/dialogs/change_password_dialog.cpp:137 msgid "Current password invalid." @@ -4649,13 +4652,13 @@ msgstr[1] "Confirma a resolución antes de %i segundos" msgid "" "Resolutions smaller than 1024x768 or 1280x720 are unsupported. Some parts of" " the UI may not work correctly." -msgstr "" +msgstr "As resolucións menores a 1024x768 ou 1280x720 non son soportadas. Algunhas partes da interface poden non funcionar correctamente" #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 #: src/states_screens/options/options_screen_ui.cpp:166 msgid "Drone chase" -msgstr "" +msgstr "Cámara de dron" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings @@ -4681,7 +4684,7 @@ msgstr "Desactivado" #: src/states_screens/dialogs/custom_video_settings.cpp:70 #: src/states_screens/options/options_screen_video.cpp:668 msgid "Important only" -msgstr "" +msgstr "Só importantes" #. I18N: Geometry level disabled : lowest level, no details #. I18N: in the graphical options tooltip; @@ -4690,7 +4693,7 @@ msgstr "" #: src/states_screens/dialogs/custom_video_settings.cpp:86 #: src/states_screens/options/options_screen_video.cpp:672 msgid "Very Low" -msgstr "" +msgstr "Moi Baixo" #. I18N: Geometry level low : few details are displayed #. I18N: in the graphical options tooltip; @@ -4700,7 +4703,7 @@ msgstr "" #: src/states_screens/dialogs/custom_video_settings.cpp:93 #: src/states_screens/options/options_screen_video.cpp:675 msgid "Low" -msgstr "" +msgstr "Baixo" #. I18N: Geometry level high : everything is displayed #. I18N: in the graphical options tooltip; @@ -4710,7 +4713,7 @@ msgstr "" #: src/states_screens/dialogs/custom_video_settings.cpp:94 #: src/states_screens/options/options_screen_video.cpp:678 msgid "High" -msgstr "" +msgstr "Alto" #. I18N: In download assets dialog #: src/states_screens/dialogs/download_assets.cpp:108 @@ -4718,20 +4721,20 @@ msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " "don't have a wifi connection." -msgstr "" +msgstr "SuperTuxKart descargará todos os recursos (incluíndo texturas e música de alta calidade) para proporcionar unha mellor experiencia do xogo. Isto utilizará os teus datos móviles se non tes unha conexión sen fios dispoñíbel." #. I18N: In download assets dialog #: src/states_screens/dialogs/download_assets.cpp:116 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." -msgstr "" +msgstr "SuperTuxKart descargará todos os recursos completos (incluíndo texturas de alta calidade e música) para unha mellor experiencia de xogo." #: src/states_screens/dialogs/enter_address_dialog.cpp:42 msgid "" "Enter the server address optionally followed by : and then port or select " "address from list." -msgstr "" +msgstr "Introduce o enderezo do servidor, opcionalmente seguido de : e o porto, ou selecciona o enderezo da lista." #: src/states_screens/dialogs/enter_address_dialog.cpp:124 #, c-format @@ -4844,7 +4847,7 @@ msgstr "Usar a cor orixinal" #. I18N: In kart color choosing dialog #: src/states_screens/dialogs/kart_color_slider_dialog.cpp:49 msgid "Pick a color from slider" -msgstr "" +msgstr "Escoller unha cor da barra deslizante" #: src/states_screens/dialogs/message_dialog.cpp:145 msgid "Don't show again" @@ -4876,7 +4879,7 @@ msgstr "Botar" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:124 msgid "Change team" -msgstr "" +msgstr "Mudar equipa" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:139 @@ -4900,13 +4903,13 @@ msgstr "Denunciar xogador" #: src/states_screens/dialogs/player_rankings_dialog.cpp:141 #, c-format msgid "Fetching ranking info for %s" -msgstr "" +msgstr "Obtendo información de clasificación de %s" #. I18N: In the network player dialog, instruction for reporting player #: src/states_screens/dialogs/network_player_dialog.cpp:194 #, c-format msgid "Tell server administrator about this player (%s):" -msgstr "" +msgstr "Informe ao administrador do servidor sobre este xogador (%s):" #. I18N: In press a key dialog, tell user to press a key to bind configuration #: src/states_screens/dialogs/press_a_key_dialog.cpp:43 @@ -4927,19 +4930,19 @@ msgstr "O chat está desactivado, actívao no menú de Opcións." #: src/states_screens/dialogs/race_paused_dialog.cpp:132 msgid "Back to Battle" -msgstr "" +msgstr "Voltar á Batalla" #: src/states_screens/dialogs/race_paused_dialog.cpp:135 msgid "Setup New Game" -msgstr "" +msgstr "Configurar Novo Xogo" #: src/states_screens/dialogs/race_paused_dialog.cpp:137 msgid "Restart Battle" -msgstr "" +msgstr "Reiniciar Batalla" #: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Exit Battle" -msgstr "" +msgstr "Saír da Batalla" #: src/states_screens/dialogs/race_paused_dialog.cpp:146 #: src/states_screens/race_result_gui.cpp:350 @@ -4955,12 +4958,12 @@ msgstr "Saír da carreira" #: src/states_screens/dialogs/ranking_callback.hpp:44 #, c-format msgid "%s has no ranking yet." -msgstr "" +msgstr "%s aínda non ten clasificación." #: src/states_screens/dialogs/ranking_callback.hpp:56 #, c-format msgid "%s is number %d in the rankings with a score of %f." -msgstr "" +msgstr "%s é o número %d da clasificación cunha puntuación de %f." #: src/states_screens/dialogs/recovery_dialog.cpp:120 msgid "Username and/or email address invalid." @@ -4973,7 +4976,7 @@ msgid "" "agree to these terms in order to register an account for STK. If you have " "any questions or comments regarding these terms, one of the members of the " "development team would gladly assist you." -msgstr "" +msgstr "Lea os termos e condicións de SuperTuxKart en '%s'. Debes aceptar estes termos para rexistrar unha conta en STK. Se tes algunha pregunta ou comentario sobre estes termos, un dos membros do equipo de desenvolvemento estará encantado de axudarche." #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:60 @@ -5091,7 +5094,7 @@ msgstr "Non existe ningún xogador dispoñible para se conectar ao servidor." #: src/states_screens/dialogs/user_info_dialog.cpp:56 #, c-format msgid "Username: %s" -msgstr "" +msgstr "Nome de usuario: %s" #: src/states_screens/dialogs/user_info_dialog.cpp:60 msgid "Cancel Request" @@ -5209,12 +5212,12 @@ msgstr "Superaches o desafío difícil! Puntos conseguidos neste nivel: %i/%i" #, c-format msgid "" "You completed the SuperTux challenge! Points earned on this level: %i/%i" -msgstr "" +msgstr "Completaches o desafío SuperTux!\nPuntos gañados neste nivel: %i/%i" #: src/states_screens/feature_unlocked.cpp:315 #, c-format msgid "You unlocked %s!" -msgstr "" +msgstr "Desbloqueaches %s!" #: src/states_screens/feature_unlocked.cpp:645 msgid "Challenge Completed" @@ -5231,7 +5234,7 @@ msgstr "Desbloqueaches o campionato «%0»." #: src/states_screens/ghost_replay_selection.cpp:153 msgctxt "column_name" msgid "Track" -msgstr "Pista" +msgstr "Circuíto" #: src/states_screens/ghost_replay_selection.cpp:164 #: src/states_screens/online/server_selection.cpp:134 @@ -5281,7 +5284,7 @@ msgstr "Superaches un desafío!" #: src/states_screens/grand_prix_win.cpp:324 msgid "You won the Grand Prix!" -msgstr "" +msgstr "Gañaches o Gran Premio!" #: src/states_screens/grand_prix_win.cpp:325 msgid "You completed the Grand Prix!" @@ -5294,15 +5297,15 @@ msgstr "Número de karts" #: src/states_screens/high_score_selection.cpp:352 msgid "Are you sure you want to remove this high score entry?" -msgstr "" +msgstr "Estás certo de que queres eliminar esta entrada de alta puntuación?" #: src/states_screens/high_score_selection.cpp:360 msgid "Are you sure you want to remove all of your high scores?" -msgstr "" +msgstr "Estás certo de que queres eliminar todas as túas puntuacións máis altas?" #: src/states_screens/kart_selection.cpp:447 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" -msgstr "" +msgstr "Conecta un teclado ou un mando para xogar ao modo multixogador en pantalla dividida" #: src/states_screens/kart_selection.cpp:933 #: src/states_screens/kart_selection.cpp:1616 @@ -5322,27 +5325,27 @@ msgstr "Todos:\nPremede o botón de seleccionar para unirvos á partida." #: src/states_screens/main_menu_screen.cpp:267 msgid "Would you like to play the tutorial of the game?" -msgstr "" +msgstr "Queres xogar o titorial do xogo?" #: src/states_screens/main_menu_screen.cpp:563 #: src/states_screens/online/online_screen.cpp:211 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." -msgstr "" +msgstr "Non podes xogar en liña sen acceso a internet. Se queres xogar en liña, vai ao menú de opcións e marca \"Conectar á internet\"." #: src/states_screens/main_menu_screen.cpp:578 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." -msgstr "" +msgstr "Non podes descargar complementos sen acceso a Internet. Se queres descargar complementos, vai no menú de opcións e marca \"Conectar a Internet\"." #: src/states_screens/main_menu_screen.cpp:586 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." -msgstr "" +msgstr "Non podes descargar complementos sen acceso a Internet. Se queres descargar complementos, vai no menú de opcións e marca \"Conectar a Internet\".\n\nNon obstante, pode eliminar os complementos xa descargados." #: src/states_screens/main_menu_screen.cpp:626 msgid "The add-ons module is currently disabled in the Options screen" @@ -5354,7 +5357,7 @@ msgstr "Cargando os complementos…" #: src/states_screens/main_menu_screen.cpp:659 msgid "Are you sure you want to quit STK?" -msgstr "" +msgstr "Estás seguro de querer saír do STK?" #: src/states_screens/online/create_server_screen.cpp:102 msgid "Create LAN Server" @@ -5368,7 +5371,7 @@ msgstr "Servidor de %s" #. I18N: In the create server screen #: src/states_screens/online/create_server_screen.cpp:215 msgid "No. of grand prix track(s)" -msgstr "" +msgstr "Número de circuíto(s) do Gran Premio" #: src/states_screens/online/create_server_screen.cpp:298 msgid "Name has to be between 4 and 30 characters long!" @@ -5382,19 +5385,19 @@ msgstr "Caracteres incorrectos no contrasinal!" #. server that he is ready for next game for owner less server #: src/states_screens/online/networking_lobby.cpp:195 msgid "Ready" -msgstr "" +msgstr "Preparado" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game #: src/states_screens/online/networking_lobby.cpp:198 msgid "Live join" -msgstr "" +msgstr "Unirse en directo" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game #: src/states_screens/online/networking_lobby.cpp:203 msgid "Spectate" -msgstr "" +msgstr "Observar" #: src/states_screens/online/networking_lobby.cpp:204 msgid "Install addon" @@ -5421,27 +5424,27 @@ msgstr "Por favor, agarda a que o xogo actual remate, tempo restante estimado: % #. percent, showing the current track name inside bracket #: src/states_screens/online/networking_lobby.cpp:563 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." -msgstr "" +msgstr "Agarda a que finalice (%s) o xogo actual, progreso estimado: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent #: src/states_screens/online/networking_lobby.cpp:572 msgid "Please wait for the current game's end, estimated progress: %d%." -msgstr "" +msgstr "Agarda ata que remate o xogo actual, progreso estimado: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish #: src/states_screens/online/networking_lobby.cpp:580 msgid "Please wait for the current game's end." -msgstr "" +msgstr "Por favor, agarda a que o xogo actual remate." #: src/states_screens/online/networking_lobby.cpp:647 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "O xogo comezará se hai máis de %d xogador." +msgstr[1] "O xogo comezará se hai máis de %d xogadores." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game @@ -5451,8 +5454,8 @@ msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." msgid_plural "" "Starting after %d seconds, or once everyone has pressed the 'Ready' button." -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Comezando despois de %d segundo, ou unha vez que todos premeron o botón \"Listo\"." +msgstr[1] "Comezando despois de %d segundos, ou unha vez que todos premeron o botón \"Listo\"." #: src/states_screens/online/networking_lobby.cpp:698 #, c-format @@ -5535,7 +5538,7 @@ msgstr "Non foi posible mudar o Email: %s" #: src/states_screens/online/online_screen.cpp:201 msgid "" "You must be logged in to play Global networking. Click your username above." -msgstr "" +msgstr "Tes que estar autenticado para xogar na rede Global. Fai clic no teu nome de usuario arriba." #: src/states_screens/online/online_user_search.cpp:179 #: src/states_screens/online/online_user_search.cpp:242 @@ -5569,7 +5572,7 @@ msgstr "Os enderezos de correo electrónico non coinciden!" msgid "" "Online username can only contain alphanumeric (ASCII) characters, periods, " "dashes and underscores!" -msgstr "" +msgstr "O nome de usuario online só pode conter caracteres alfanuméricos (ASCII), puntos, guións e guións baixos!" #: src/states_screens/online/register_screen.cpp:374 msgid "Online username has to be between 3 and 30 characters long!" @@ -5645,14 +5648,14 @@ msgstr "Obtendo os servidores" #: src/states_screens/online/server_selection.cpp:578 msgid "Server Bookmarks" -msgstr "" +msgstr "Marcadores de servidor" #. I18N: In track screen for networking, clarify voting phase #: src/states_screens/online/tracks_screen.cpp:318 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." -msgstr "" +msgstr "Se a maioría dos xogadores escollen o mesmo circuíto e configuracións de carreira, a votación rematará cedo." #. I18N: In track screen #. I18N: In the track info screen @@ -5820,7 +5823,7 @@ msgstr "Escribe o nome da configuración, deixa en branco para tornar ao nome pr msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" -msgstr "" +msgstr "No modo multixogador, os xogadores poden seleccionar perfís con \ndesvantaxe (máis difíciles) na pantalla de selección de karts" #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server @@ -5913,12 +5916,12 @@ msgid "" "Closing the game before the story mode's completion invalidates the timer.\n" "\n" "To use the speedrun mode, please use a new profile." -msgstr "" +msgstr "O modo carreira rápida só se pode activar se o xogo non se pechou desde o lanzamento do modo historia.\n\nPechar o xogo antes de completar o modo historia invalida o temporizador.\n\nPara usar o modo carreira rápida, utiliza un novo perfil." #. I18N: In the video options #: src/states_screens/options/options_screen_video.cpp:259 msgid "Vertical Sync" -msgstr "" +msgstr "Sincronización vertical" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. @@ -5926,12 +5929,12 @@ msgstr "" msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." -msgstr "" +msgstr "A Sincronización vertical forza a tarxeta gráfica a fornecer un novo fotograma só cando o monitor está pronto para mostralo." #. I18N: in graphical options. #: src/states_screens/options/options_screen_video.cpp:279 msgid "Vsync will not work if your drivers don't support it." -msgstr "" +msgstr "Sincronización vertical non funcionará se os teus controladores non o admiten." #. I18N: in graphical options #: src/states_screens/options/options_screen_video.cpp:681 @@ -6060,7 +6063,7 @@ msgstr "Xa!" #. I18N: Shown when a goal is scored #: src/states_screens/race_gui_base.cpp:79 msgid "GOAL!" -msgstr "Gol!" +msgstr "GOL!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting @@ -6108,17 +6111,17 @@ msgstr "Desafío non superado" #. and press the podium (2, 1, 3 like) icon instead of fire button #: src/states_screens/race_gui_overworld.cpp:541 msgid "Press podium icon to start tutorial" -msgstr "" +msgstr "Toca na icona do podio para iniciar o titorial " #: src/states_screens/race_gui_overworld.cpp:547 msgid "Press fire to start the tutorial" -msgstr "" +msgstr "Preme Disparar para iniciar o titorial" #. I18N: Shown when multitouch GUI exists #. and press the podium (2, 1, 3 like) icon instead of fire button #: src/states_screens/race_gui_overworld.cpp:623 msgid "Press podium icon to start the challenge" -msgstr "" +msgstr "Preme na icona do podio para iniciar o desafio" #: src/states_screens/race_gui_overworld.cpp:629 msgid "Press fire to start the challenge" @@ -6170,7 +6173,7 @@ msgstr "Empate" #: src/states_screens/race_result_gui.cpp:881 #, c-format msgid "Eliminated after %s" -msgstr "" +msgstr "Eliminado despois de %s" #: src/states_screens/race_result_gui.cpp:886 #: src/states_screens/race_result_gui.cpp:1334 @@ -6239,7 +6242,7 @@ msgstr "Golpea outros karts con armas ata que perdan todas as vidas." #: src/states_screens/race_setup_screen.cpp:120 msgid "Push the ball into the opposite cage to score goals." -msgstr "" +msgstr "Empurra o balón na portería contraria para marcar goles." #: src/states_screens/race_setup_screen.cpp:130 msgid "Explore tracks to find all hidden eggs" @@ -6256,7 +6259,7 @@ msgstr "Complete o maior número de voltas posible nun determinado período de t #. I18N: In soccer setup screen #: src/states_screens/soccer_setup_screen.cpp:120 msgid "Press red or blue soccer icon to change team" -msgstr "" +msgstr "Toca nas iconas de fútbol vermella ou azul para mudar a equipa" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) @@ -6279,7 +6282,7 @@ msgstr "Número de karts AI no equipo vermello" msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" -msgstr "" +msgstr "Non podes xogar este Campeonato porque contén circuítos aínda por desbloquear!" #: src/states_screens/tracks_and_gp_screen.cpp:217 msgid "Locked!" @@ -6323,19 +6326,19 @@ msgstr "Acelera con <%s>, e xira con <%s> e <%s>." msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." -msgstr "" +msgstr "Acelera tocando a parte superior do volante e vira movendo cara á esquerda ou á dereita." #: ../stk-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." -msgstr "" +msgstr "Acelera movendo o acelerador cara arriba e xira inclinando o teu dispositivo." #: ../stk-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." -msgstr "" +msgstr "Acelera movendo o acelerador cara arriba e xira rotando o teu dispositivo." #: ../stk-assets/tracks/tutorial/scripting.as:59 #, c-format @@ -6347,20 +6350,20 @@ msgstr "Recolle caixas de agasallos, e dispara con <%s> para estoupar estas caix msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" -msgstr "" +msgstr "Recolle caixas de agasallos e dispara premendo na icona de birlos para facelas explotar!" #: ../stk-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" "Fire the weapon with <%s> while pressing <%s> to fire behind!" -msgstr "" +msgstr "Preme <%s> para mirar atrás.\nDispara a arma con <%s> mentres premes <%s> para disparar de costas!" #: ../stk-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" -msgstr "" +msgstr "Preme na ícona do espello para mirar atrás. Dispara a arma que está detrás mantendo premido o ícono do espello e logo deslizando cara á icona de birlos!" #: ../stk-assets/tracks/tutorial/scripting.as:98 #, c-format @@ -6369,7 +6372,7 @@ msgstr "Preme <%s> para usar o nitro que recolliches!" #: ../stk-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" -msgstr "" +msgstr "Usa o nitro que collas premendo a icona do nitro" #: ../stk-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." @@ -6389,13 +6392,13 @@ msgstr "Ups! Cando esteas en problemas, preme na icona do paxaro para ser rescat msgid "" "Accelerate and press the <%s> key while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." -msgstr "" +msgstr "Acelere e prema a tecla <%s> mentres xira para derrapar.\nDerrapar un pouco pode axudarche a virar máis rápido para dar curvas pronunciadas." #: ../stk-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." -msgstr "" +msgstr "Acelera e preme na icona de derrape mentres estás a virar para derrapar.\nDerrapar durante un curto período de tempo pode axudarte a virar máis rápido para tomar curvas pechadas." #: ../stk-assets/tracks/tutorial/scripting.as:156 msgid "" @@ -6425,7 +6428,7 @@ msgid "" "variety of characters, tracks, and modes to play. Our aim is to create a " "game that is more fun than realistic, and provide an enjoyable experience " "for all ages." -msgstr "" +msgstr "Karts. Nitro. Action! SuperTuxKart é un xogo de carreiras arcade en 3D de código aberto con varios personaxes, circuítos e modos para xogar. O noso obxectivo é crear un xogo que sexa máis divertido que realista e ofrecer unha experiencia agradable para todas as idades." #: supertuxkart.appdata.xml:11 msgid "" @@ -6434,7 +6437,7 @@ msgid "" " while avoiding other karts as they may overtake you, but don't eat the " "bananas! Watch for bowling balls, plungers, bubble gum, and cakes thrown by " "your opponents." -msgstr "" +msgstr "Temos varios circuítos con diferentes temas para que os xogadores gocen, desde conducir baixo a auga, terras agrícolas rurais, xunglas ou incluso no espazo! Tenta ser o mellor mentres evitas cos outros karts che adianten, pero non comas os plátanos! Ollo ás bolas de birlos, chupóns, gomas de mascar e tortas lanzadas polos teus opoñentes." #: supertuxkart.appdata.xml:14 msgid "" @@ -6443,7 +6446,7 @@ msgid "" "battle mode against the computer or your friends, and more! For a greater " "challenge, join online and meet players from all over the world and prove " "your racing skills!" -msgstr "" +msgstr "Podes facer unha carreira individual contra outros karts, competir nun dos varios Grand Prix, intentar superar a puntuación máis alta en probas de tempo por ti mesmo, xogar en modo de batalla contra o ordenador ou os teus amigos e moito máis! Para un maior desafío, únete en liña e conéctate con xogadores de todo o mundo para demostrar as túas habilidades como piloto!" #: supertuxkart.appdata.xml:17 msgid "This game has no ads." @@ -6454,7 +6457,7 @@ msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." -msgstr "" +msgstr "Esta é unha versión inestable do SuperTuxKart que contén as últimas melloras. Publícase principalmente para probar o xogo e facer unha versión estable do STK tan boa como sexa posible." #: supertuxkart.appdata.xml:23 msgid "" diff --git a/data/po/he.po b/data/po/he.po index 6e3eeb110d8..d6138713bc9 100644 --- a/data/po/he.po +++ b/data/po/he.po @@ -7,8 +7,8 @@ # Capri , 2015 # FIRST AUTHOR , 2010 # gk , 2015-2016 -# Liran , 2016-2017 -# 63f334ffc0709ba0fc2361b80bf3c0f0_00ffd1e , 2020-2022 +# Liran Vaknin , 2016-2017 +# Omer I.S., 2020-2022,2024 # 63f334ffc0709ba0fc2361b80bf3c0f0_00ffd1e , 2020-2021 # 63f334ffc0709ba0fc2361b80bf3c0f0_00ffd1e , 2020 # עומר רוזנר, 2018 @@ -26,13 +26,13 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: רואי לוי , 2016\n" +"Last-Translator: Omer I.S., 2020-2022,2024\n" "Language-Team: Hebrew (http://app.transifex.com/supertuxkart/supertuxkart/language/he/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: he\n" -"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;\n" +"Plural-Forms: nplurals=3; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: 2;\n" #. I18N: In Android UI, po_extract_game_data msgid "Extracting game data..." @@ -44,7 +44,7 @@ msgstr "שגיאה בחילוץ נתוני המשחק" #. I18N: In Android UI, po_extract_error_msg msgid "Check remaining device space or reinstall SuperTuxKart." -msgstr "נא לבדוק את השטח הפנוי בהתקן או להתקין את SuperTuxKart מחדש." +msgstr "נא לבדוק את השטח הפנוי במכשיר או להתקין מחדש את SuperTuxKart." #. I18N: In Android UI, po_quit #. I18N: ./data/gui/screens/main_menu.stkgui @@ -54,11 +54,11 @@ msgstr "יציאה" #. I18N: ./data/achievements.xml msgid "Christoffel Columbus" -msgstr "כּריסטוֹפֶל קולומבוס" +msgstr "כּריסטוֹפֵל קולומבוס" #. I18N: ./data/achievements.xml msgid "Play every official track at least once." -msgstr "לשחק בכל מסלול רשמי פעם אחת לפחות." +msgstr "סיבוב אחד לפחות בכל מסלול רשמי." #. I18N: ./data/achievements.xml msgid "Strike!" @@ -66,15 +66,15 @@ msgstr "בול פגיעה!" #. I18N: ./data/achievements.xml msgid "Hit 10 karts with a bowling-ball." -msgstr "לפגוע ב־10 מכוניות באמצעות כדור כדורת." +msgstr "פגיעה ב־10 מכוניות עם כדור באולינג" #. I18N: ./data/achievements.xml msgid "Arch Enemy" -msgstr "תחרות אכזרית" +msgstr "מהלך ערמומי" #. I18N: ./data/achievements.xml msgid "Hit the same kart at least 5 times in one race." -msgstr "לפגוע באותה המכונית 5 פעמים לפחות במרוץ אחד." +msgstr "פגיעה באותה המכונית לפחות 5 פעמים במרוץ אחד." #. I18N: ./data/achievements.xml msgid "Marathoner" @@ -82,7 +82,7 @@ msgstr "מרתון מכוניות" #. I18N: ./data/achievements.xml msgid "Finish a race with at least twice the track's default lap number." -msgstr "לסיים מרוץ עם מספר הקפות הגדול לפחות פי שניים מברירת המחדל של המסלול." +msgstr "השלמה של מסלול אחד עם מספר הקפות הגדול פי שניים לפחות ממספר ההקפות המקורי." #. I18N: ./data/achievements.xml msgid "Skid-row" @@ -90,17 +90,17 @@ msgstr "רצפה חלקה" #. I18N: ./data/achievements.xml msgid "Skid 5 times in a single lap." -msgstr "להחליק 5 פעמים בהקפה אחת." +msgstr "ביצוע 5 החלקות בהקפה אחת." #. I18N: ./data/achievements.xml msgid "Gold driver" -msgstr "מקום ראשון" +msgstr "הצטיינות במרוצים" #. I18N: ./data/achievements.xml msgid "" "Win against at least 3 AIs in normal race, time-trial, and follow the " "leader." -msgstr "לנצח 3 מתחרים מדומים לפחות במרוץ רגיל, במרוץ נגד השעון ובמרוץ בעקבות המכונית המובילה." +msgstr "ניצחון על 3 מתחרים לפחות במרוץ רגיל, מרוץ נגד השעון ומרוץ בעקבות המכונית המובילה." #. I18N: ./data/achievements.xml msgid "Powerup Love" @@ -108,7 +108,7 @@ msgstr "חיזוקים זה החיים" #. I18N: ./data/achievements.xml msgid "Use 10 or more powerups in a race." -msgstr "להשתמש ב־10 חיזוקים או יותר במרוץ." +msgstr "שימוש ב־10 חיזוקים או יותר במרוץ." #. I18N: ./data/achievements.xml msgid "Unstoppable" @@ -118,7 +118,7 @@ msgstr "בלי מעצורים" msgid "" "Win 5 single races in a row against at least 3 AIs. Beware, restarting a " "race counts as a loss." -msgstr "לנצח ב־5 מרוצים יחידים ברצף נגד 3 מתחרים מדומים לפחות. זהירות, התחלת מרוץ מחדש תיחשב כהפסד." +msgstr "ניצחון ב־5 מרוצים בודדים ברצף, נגד 3 מתחרים מדומים לפחות. זהירות, התחלת מרוץ מחדש נחשבת כהפסד." #. I18N: ./data/achievements.xml msgid "Banana Lover" @@ -126,7 +126,7 @@ msgstr "אי אפשר בלי בננות" #. I18N: ./data/achievements.xml msgid "Collect at least 5 bananas in one race." -msgstr "לאסוף 5 בננות לפחות במרוץ אחד." +msgstr "איסוף של 5 בננות לפחות במרוץ אחד." #. I18N: ./data/achievements.xml msgid "It's secret" @@ -144,7 +144,7 @@ msgstr "צֵיד יתושים" msgid "" "Take your opponents for mosquitos! With the swatter, squash them at least 5 " "times in a race." -msgstr "לתפוס את היריבים כמו יתושים! באמצעות מחבט היתושים, יש למעוך אותם 5 פעמים לפחות במרוץ." +msgstr "מוחצים את היריבים כמו יתושים! מוחצים אותם לפחות 5 פעמים במרוץ, בעזרת מחבט היתושים." #. I18N: ./data/achievements.xml msgid "Beyond Luck" @@ -154,7 +154,7 @@ msgstr "מעבר למזל" msgid "" "Win 10 single races in a row in Expert or SuperTux against at least 5 AIs. " "Beware, restarting a race counts as a loss." -msgstr "לנצח ב־10 מרוצים יחידים ברצף נגד 5 מתחרים מדומים לפחות ברמה למומחים או ברמת סופר־טַקס. זהירות, התחלת מרוץ מחדש תיחשב כהפסד." +msgstr "ניצחון ב־10 מרוצים בודדים ברצף, נגד 5 מתחרים מדומים לפחות, ברמה „למומחים” או „סופר־טַקס”. זהירות, התחלת מרוץ מחדש נחשבת כהפסד." #. I18N: ./data/grandprix/1_penguinplayground.grandprix msgid "Penguin Playground" @@ -302,7 +302,7 @@ msgstr "לחצנים הפוכים" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Buttons scale" -msgstr "קנה מידה לחצנים" +msgstr "גודל הלחצנים" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -392,7 +392,7 @@ msgstr "שחזור" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog msgid "Accept" -msgstr "קבלה" +msgstr "אישור" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui msgid "Camera Settings" @@ -401,7 +401,7 @@ msgstr "הגדרות מצלמה" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera settings msgid "Player camera" -msgstr "מצלמת שחקן/ית" +msgstr "מצלמת שחקן" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -490,7 +490,7 @@ msgstr "טשטוש תנועה" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Image-based lighting" -msgstr "הארה מבוססת תמונות" +msgstr "תאורה על סמך תמונות" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -708,7 +708,7 @@ msgstr "10 השחקנים הטובים ביותר" #. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui msgid "Refresh" -msgstr "ריענון" +msgstr "רענון" #. I18N: ./data/gui/dialogs/online/recovery_info.stkgui #. I18N: In the recovery dialog @@ -728,7 +728,7 @@ msgstr "יישלח אליך דואר אלקטרוני עם הוראות לאיפ msgid "" "Fill in the username and email address you supplied at registration to be " "able to reset your password." -msgstr "נא למלא כאן את שם המשתמש ואת כתובת הדוא״ל שסיפקת בעת ההרשמה כדי להמשיך באיפוס הסיסמה שלך." +msgstr "נא למלא את שם המשתמש וכתובת הדוא״ל שסיפקת בעת ההרשמה לצורך איפוס הסיסמה שלך." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog @@ -756,7 +756,7 @@ msgstr "תנאים והסכמה" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog msgid "I agree to the above terms and am 13 years or older. " -msgstr "התנאים לעיל מוסכמים מבחינתי וגילי 13 שנים או יותר." +msgstr "אני מקבל/ת את התנאים האמורים לעיל, וגילי 13 שנים ומעלה." #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: In the server configuration screen @@ -884,7 +884,7 @@ msgstr "סיסמה" #. I18N: In the server info dialog #: src/states_screens/dialogs/server_info_dialog.cpp:291 msgid "Bookmark this server" -msgstr "הוספת השרת הזה לסימניות" +msgstr "הוספת השרת לסימניות" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network @@ -905,7 +905,7 @@ msgstr "הגבלה" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "Press the 'All players ready' button after the player list is ready." -msgstr "יש ללחוץ על כפתור \"כל השחקנים מוכנים\" לאחר שרשימת השחקנים מוכנה." +msgstr "יש ללחוץ על „כל השחקנים מוכנים” לאחר שכולם בפנים." #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network @@ -925,7 +925,7 @@ msgstr "מידע על המשתמש/ת" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "הסרה מהחברים" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -935,17 +935,17 @@ msgstr "הוספה לחברים" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "קבלת ההזמנה" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "סירוב להזמנה" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "הצגת הפרופיל" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -985,7 +985,7 @@ msgstr "שיוך למקש ESC" #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input msgid "Assign nothing" -msgstr "לא לשייך לדבר" +msgstr "לא לשייך דבר" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui @@ -1133,7 +1133,7 @@ msgstr "תודות" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "דילוג" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1147,7 +1147,7 @@ msgstr "כל המסלולים" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Title in edit grand prix screen msgid "Edit Grand Prix" -msgstr "עריכת הגרנד־פרי" +msgstr "עריכת סבב מרוצים" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item @@ -1268,7 +1268,7 @@ msgstr "להמשיך גרנד פרי שמור" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Title in grand prix editor screen msgid "Grand Prix editor" -msgstr "עריכת גרנד־פרי" +msgstr "הכלי לעריכת סבבי מרוצים" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item @@ -1293,7 +1293,7 @@ msgstr "שינוי שם" #. I18N: ./data/gui/screens/grand_prix_lose.stkgui #. I18N: ./data/gui/screens/grand_prix_win.stkgui msgid "Save Grand Prix" -msgstr "שמירת הגרנד־פרי" +msgstr "שמירת סבב מרוצים" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: ./data/gui/screens/help2.stkgui @@ -1303,7 +1303,7 @@ msgstr "שמירת הגרנד־פרי" #. I18N: ./data/gui/screens/help6.stkgui #. I18N: ./data/gui/screens/help7.stkgui msgid "SuperTuxKart Help" -msgstr "עזרה עבור SuperTuxKart" +msgstr "עזרה בנוגע ל־SuperTuxKart" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: Tab in help menu @@ -1423,7 +1423,7 @@ msgstr "יש לאסוף את קופסאות המתנה הכחולות, הן יע #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" -msgstr "יש להיזהר מבננות!" +msgstr "זהירות מבננות!" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu @@ -1431,7 +1431,7 @@ msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " "pressing the appropriate key or button. You can see your current level of " "nitro in the gauge at the bottom-right of the race screen." -msgstr "איסוף גז־טורבו מאפשר להאיץ את המהירות מתי שרוצים בלחיצה על המקש או הכפתור המתאים. אפשר לראות את רמת הגז־טורבו הנוכחית שלך בפס שנמצא למטה בצדו הימני של מסך המרוץ." +msgstr "צבירת גז טורבו מאפשרת לקבל האצת מהירות מתי שרוצים בלחיצה על המקש או הכפתור המתאים. אפשר לראות את הרמה הנוכחית של גז הטורבו בפס שנמצא למטה בצדו הימני של מסך המרוץ." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu @@ -1447,14 +1447,14 @@ msgid "" "help to take sharp turns; while medium skids will boost your speed, long " "skids more so. You can't stop turning while skidding, so orient your kart " "carefully before!" -msgstr "אפשר להחליק בעזרת לחיצה על מקש או כפתור מיוחדים. החלקות קצרות ורצופות עוזרות בפניות חדות. החלקות בינוניות יאיצו את המהירות שלך, אבל החלקות ארוכות יאיצו יותר. אי אפשר להפסיק להסתובב בזמן החלקה, אז חשוב לכוון את המכונית בזהירות לפני כן!" +msgstr "אפשר להחליק בעזרת לחיצה על מקש או כפתור מיוחדים. החלקות קצרות ורצופות מועילות כשיש פנייה חדה. החלקות בינוניות נותנות האצת מהירות, אבל החלקות ארוכות נותנות האצה גדולה יותר. אי אפשר להסתובב בזמן שמחליקים, אז חשוב להטות את המכונית לכיוון הנכון לפני כן!" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." -msgstr "אפשר לקבל האצה בהזנקה באמצעות לחיצה על כפתור ההאצה ב\"היכון!\", לפני שהמרוץ מתחיל." +msgstr "אפשר לקבל האצה בהזנקה באמצעות לחיצה על כפתור ההאצה ב„היכון!”, לפני שהמרוץ מתחיל." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: in the help screen @@ -1497,12 +1497,12 @@ msgstr "יש 3 סוגים למצב הקרב: בקרב 3 פגיעות, יש לת #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." -msgstr "כדורגל: להשתמש במכונית שלך כדי לדחוף את הכדור לשער." +msgstr "כדורגל: משתמשים במכונית כדי לדחוף את הכדור לעבר השער." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." -msgstr "ציד ביצים: סיירו במסלולים למציאת כל הביצים המוסתרות." +msgstr "ציד ביצים: מסיירים במסלולים ומוצאים את כל הביצים הנסתרות." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1515,7 +1515,7 @@ msgstr "שידור רפאים: להתחרות נגד שידורי רפאים ב #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "" +msgstr "שיא הקפות: השלמה של כמה שיותר הקפות בזמן נתון." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1524,18 +1524,18 @@ msgid "" "instead of playing a single race, you play many in a row. The better you " "rank, the more points you get. In the end, the player with the most points " "wins the cup." -msgstr "* ברוב מצבי המשחק האלה אפשר לשחק גם בסגנון גרנד־פרי: במקום לשחק במרוץ יחיד, משחקים בכמה ברצף. ככל שהדירוג טוב יותר, מקבלים יותר נקודות. בסוף, השחקן/ית עם הניקוד הגבוה ביותר זוכה בגביע." +msgstr "* ברוב מצבי המשחק האלה אפשר לשחק גם בתור סבב מרוצים: במקום לשחק במרוץ בודד, משחקים בכמה ברצף. ככל שהדירוג טוב יותר, מקבלים יותר נקודות. בסוף, השחקן/ית עם הניקוד הכי גבוה זוכה בגביע." #. I18N: ./data/gui/screens/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" -msgstr "כדי לעזור לך לנצח, יש חיזוקים שאפשר לאסוף:" +msgstr "אפשר לאסוף את החיזוקים הבאים שיעזרו לך לנצח:" #. I18N: ./data/gui/screens/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." -msgstr "גומי לעיסה – מאפשרת להגן על עצמך בעזרת מגן, או להשתמש במהלך מבט לאחור כדי להותיר שלולית ורודה ודביקה מאחור." +msgstr "גומי לעיסה - עוזר לך ליצור מגן חסינות, או לחלופין באמצעות מבט לאחור, להשאיר מאחוריך שלולית ורודה דביקה." #. I18N: ./data/gui/screens/help3.stkgui msgid "" @@ -1547,7 +1547,7 @@ msgstr "מאיצן - נותן לך האצת מהירות חזקה. אך יש ל msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." -msgstr "עוגה - נזרקת על היריבים הקרובים ביותר, טובה ביותר לטווחים קצרים ולמרחקים ארוכים בקווים ישרים. היא משפיעה גם על מכוניות אחרות אשר סמוכות לפיצוץ." +msgstr "עוגה - נזרקת על המתחרה הכי קרוב, מועילה במיוחד בטווחים קצרים ולמרחקים ארוכים בקווים ישרים. היא משפיעה גם על המכוניות האחרות שסמוכות לפיצוץ." #. I18N: ./data/gui/screens/help3.stkgui msgid "" @@ -1559,7 +1559,7 @@ msgstr "פומפה - נזרקת קדימה למשיכת יריבים לאחור, msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." -msgstr "כדור כדורת - נע ישר עד שהוא פוגע, הוא יכול לנתר מקירות. במבט לאחור, הוא יכול להיזרק לאחור." +msgstr "כדור באולינג - נע ישר עד שהוא פוגע, הוא יכול לנתר מקירות. במבט לאחור, הוא יכול להיזרק לאחור." #. I18N: ./data/gui/screens/help3.stkgui msgid "Parachute - slows down all karts in a better position." @@ -1569,13 +1569,13 @@ msgstr "מצנח – מאט את כל המכוניות מלפנים." msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." -msgstr "החלפה - קופסאות המתנה הופכות לבננות, פחיות גז־טורבו לגומי לעיסה, ולהיפך לזמן קצר." +msgstr "מחליפן - מחליף את כל קופסאות המתנה בבננות, פחיות של גז טורבו בגומי לעיסה ולהפך, למשך זמן קצר." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." -msgstr "כדורסל - מקפץ אחרי המכונית המובילה, ועשוי למעוך ולהאט מכוניות בדרך." +msgstr "כדורסל - מקפץ בעקבות המכונית המובילה, ועשוי למעוך ולהאט מכוניות בדרך." #. I18N: ./data/gui/screens/help3.stkgui msgid "" @@ -1587,7 +1587,7 @@ msgstr "מחבט יתושים - מוחץ מכוניות סמוכות ומאט א msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" -msgstr "פגיעה בבננה תגרום להצמדת אחד מהדברים הבאים למכוני:" +msgstr "היתקלות בבננה תצמיד למכונית את אחד מהדברים הבאים:" #. I18N: ./data/gui/screens/help4.stkgui #. I18N: In the help menu @@ -1606,7 +1606,7 @@ msgstr "מצנח - מאט את המכונית, בהדרגה גבוהה משל ה msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." -msgstr "פצצה מתפוצצת לאחר זמן מה ומעיפה את המכונית. אפשר להתנגש במכונית אחרת כדי להעביר אליה את הפצצה." +msgstr "פצצה - מתפוצצת לאחר זמן מה ומעיפה את המכונית. אפשר להתנגש במכונית אחרת כדי להעביר אליה את הפצצה." #. I18N: ./data/gui/screens/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" @@ -1619,7 +1619,7 @@ msgid "" "completed. In the top-right of the screen, it also tells you how many points" " you currently have. Complete as many challenges as possible, and Nolok will" " accept to race against you. Win to liberate Gnu!" -msgstr "הסמל הזה במפה הממוזערת מסמל את האתגרים הזמינים שלא השלמת. בחלק העליון בצד ימין של המסך גם מראה כמה נקודות יש לך. יש להשלים כמה שיותר שלבים, ונולוק יענה למרוץ נגדך. הגורל של גנו תלוי בך!" +msgstr "הסמל הזה במפה הממוזערת מסמל את האתגרים הזמינים שלא הושלמו. בפינה הימנית־עליונה של המסך ניתן לראות גם כמה נקודות צברת עד כה. יש להשלים כמה שיותר שלבים, ואז נוֹלוֹק יהיה מוכן להתחרות נגדך. הגורל של גנו תלוי בך!" #. I18N: ./data/gui/screens/help5.stkgui #. I18N: In the help menu @@ -1634,13 +1634,13 @@ msgstr "כשמשלימים אתגר, מקבלים גביע. כל גביע שוו msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." -msgstr "כשצוברים את מספר הנקודות המופיעות מתחת לסמל הזה, מקבלים הפתעה. יש מספר הפתעות לאסוף." +msgstr "לאחר שצוברים את כמות הנקודות המופיעה מתחת לסמל הזה, מקבלים הפתעה. יש כל מיני הפתעות שאפשר לקבל." #. I18N: ./data/gui/screens/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" -msgstr "לא כל המכוניות זהות! הן שייכות לדרגות עם מספר הבדלים:" +msgstr "לא כל המכוניות זהות! יש להן דרגות שונות עם מספר הבדלים:" #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu @@ -1648,7 +1648,7 @@ msgid "" "Mass - there are three classes of karts, depending on their mass: light, " "medium and heavy. Heavier karts are less affected by parachutes and are more" " resistant to explosions." -msgstr "מסה - יש שלושה סוגים של מכוניות, תלוי במסה שלהן: קלילות, בינוניות, וכבדות. מכוניות כבדות יותר מושפעות פחות ממצנחים וחסינות יותר לפיצוצים." +msgstr "מסה - יש שלושה סוגים של מכוניות, תלוי במסה שלהן: קלילות, בינוניות, וכבדות. המכוניות הכבדות יותר מושפעות פחות ממצנחים וחסינות יותר לפיצוצים." #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu @@ -1664,14 +1664,14 @@ msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " "in tracks with straight lines and gentle curves. Heavier karts have a higher" " top speed." -msgstr "מהירות מרבית - ככל שהיא גבוהה יותר, כך גם מהירות המכונית. שימושית במיוחד במסלולים ישרים עם עקומות עדינות. למכוניות הכבדות יש המהירות הטובה ביותר." +msgstr "מהירות מרבית - ככל שהיא גבוהה יותר, כך גם מהירות המכונית. שימושית במיוחד במסלולים ישרים עם עקומות עדינות. המהירות הטובה ביותר היא אצל המכוניות הכבדות." #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." -msgstr "יעילות גז־טורבו - ככל שהיא גבוהה יותר, כך גם המהירות שמקבלים ממכל גז־טורבו. למכוניות קלות יעילות יש גז־טורבו גבוהה יותר." +msgstr "יעילות גז טורבו - ככל שהיא גבוהה יותר, כך גם המהירות שמקבלים מפחית של גז טורבו. למכוניות קלות יש יעילות גז טורבו גבוהה יותר." #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu @@ -1679,7 +1679,7 @@ msgid "" "If you follow closely another kart for a few seconds, you'll get a " "slipstream speed bonus when you overtake it. The lighter your kart, the " "easier it is." -msgstr "אם נצמדים למכונית אחרת למשך כמה שניות, מקבלים בונוס האצת מהירות כשעוקפים אותה. ככל שהמכונית קלה יותר, קל יותר לעקוף." +msgstr "כאשר נצמדים למכונית אחרת למשך כמה שניות, מקבלים בונוס של האצת מהירות אם עוקפים אותה. ככל שהמכונית קלה יותר, יותר קל לעקוף אותה." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1694,7 +1694,7 @@ msgid "" "options). Then, you can either create your own server with custom options, " "or search among a list of existing servers to join. Some of them are " "recommended servers with optionally ranked races." -msgstr "ראשית, יש לבחור בסמל \"משחק ברשת\" בתפריט הראשי. אפשר לבחור ברשת המקומית או ברשת העולמית (נחוץ חיבור לאינטרנט). לאחר מכן, אפשר ליצור שרת משלך עם אפשרויות מותאמות אישית, או לחפש ברשימת השרתים הקיימים להצטרפות. חלקם שרתים מומלצים עם מרוֹצים בדרגות משתנות." +msgstr "תחילה, יש לבחור בסמל „משחק ברשת” שנמצא בתפריט הראשי. אפשר לבחור בין משחק ברשת המקומית או העולמית (יש צורך בחיבור לאינטרנט). לאחר מכן אפשר ליצור שרת מותאם אישית משלך, או לבחור להצטרף לשרת קיים מתוך הרשימה. חלק מהשרתים הם שרתים מומלצים, עם דירוגי מרוץ שונים." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1704,7 +1704,7 @@ msgid "" " enough players. Then, you can choose your kart and vote for the next track " "to race on. An addon track is allowed only if it exists on all joined " "players and the server." -msgstr "כשמחוברים לשרת, המרוצים מתחילים כשבעלי השרת (מסומנים בכתר) מחליטים להתחיל אותם. בשרתים רשמיים המרוצים עשויים להתחיל אוטומטית כשיש מספיק שחקנים. אז, יהיה אפשר לבחור את המכונית שלך ולהצביע למסלול הבא. מכוניות מִתּוֹספים מורשות רק אם הן קיימות אצל כל השחקנים שהצטרפו ובשרת." +msgstr "לאחר שהתחברת לשרת, המרוץ יתחיל לפי ההחלטה של המנהל/ת (עם הסימן של הכתר). בשרתים רשמיים המרוץ עשוי להתחיל אוטומטית כאשר יש מספיק שחקנים. אז, תהיה לך אפשרות לבחור מכונית ולהצביע בנוגע למסלול שיהיה בסיבוב הבא. ניתן לבחור מכוניות מהתוספים אך ורק אם הן מותקנות אצל כל השחקנים שהצטרפו וגם בשרת." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1719,7 +1719,7 @@ msgid "" "keyboard(s), each player will need a different set of keys, and most " "keyboards are not appropriate for multiplayer because they don't support " "multiple simultaneous keypresses." -msgstr "ראשית, נחוצים מספר התקני קלט. אפשר להשתמש במסך הגדרת הקלט ולהגדירם. מומלצים בקרי משחק וג׳ויסטיקים מרובים: במקלד(ו)ת, לכל השחקנים נחוץ מערך מקשים שונה, ורוב המקלדות לא תומכות במשחק מרובה משתתפים מכיוון שאינן תומכות בלחיצה על מספר מקשים בו־זמנית." +msgstr "ראשית, נחוצים כמה התקני קלט. אפשר להגדיר אותם דרך מסך תצורת הקלט. יש עדיפות לשימוש בבקרי משחק או ג׳ויסטיקים מרובים: כשמשחקים עם המקלד(ו)ת, לכל שחקן/ית יוקצה מערך מקשים אחר, וגם רוב המקלדות לא תומכות במשחק מרובה משתתפים, מכיוון שאין בהן תמיכה בלחיצה על מקשים מרובים בבת אחת." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1729,7 +1729,7 @@ msgid "" "keyboard to join the game, and use their input device to select their kart. " "The game continues when everyone selected their kart. Note that the mouse " "may not be used for this operation." -msgstr "כשמוגדרים התקני קלט, אפשר לבחור בסמל \"משחק מרובה משתתפים במסך מפוצל\" בתפריט הראשי. כל השחקנים יכולים ללחוץ על מקש \"ירייה\" של בקר המשחק או המקלדת כדי להצטרף למשחק, ולהשתמש בהתקן הקלט שלהם לבחירת המכונית המשחק נמשך לאחר שכולם בחרו מכוניות. נא לשים לב שייתכן שאי אפשר להשתמש בעכבר לצורך פעולה זו." +msgstr "לאחר הגדרת התקני הקלט, בוחרים בסמל „משחק מרובה משתתפים במסך מפוצל” שבתפריט הראשי. כל השחקנים יכולים ללחוץ על מקש „ירייה” בבקר המשחק שלהם כדי להצטרף למשחק, ואז לבחור מכונית בעזרת התקן הקלט איתו הצטרפו. המשחק ממשיך לאחר שכולם בחרו מכונית. לתשומת ליבך, לא ניתן להשתמש בעכבר לצורך פעולה זו." #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen @@ -1743,7 +1743,7 @@ msgstr "בחירת שיאים" #. time. #: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" -msgstr "כמה שיותר הקפות" +msgstr "שיא הקפות" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen @@ -1753,7 +1753,7 @@ msgstr "כמה שיותר הקפות" #: src/states_screens/dialogs/select_challenge.cpp:51 #: src/states_screens/high_score_selection.cpp:136 msgid "Grand Prix" -msgstr "גרנד־פרי" +msgstr "סבב מרוצים" #. I18N: ./data/gui/screens/karts.stkgui #. I18N: In the kart selection (player setup) screen @@ -1765,7 +1765,7 @@ msgstr "נא לבחור מכונית" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" -msgstr "משחק לבד" +msgstr "משחק יחידי" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1811,7 +1811,7 @@ msgstr "הישגים" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen msgid "Grand Prix Editor" -msgstr "עריכת גרנד־פרי" +msgstr "עריכת סבב מרוצים" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen @@ -1852,7 +1852,7 @@ msgstr "רשת מקומית" #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen msgid "Find Server" -msgstr "חיפוש שרת" +msgstr "איתור שרת" #. I18N: ./data/gui/screens/online/lan.stkgui #. I18N: In the online multiplayer screen @@ -2013,7 +2013,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "אפשר לשחק גם דרך חשבון מקומי, מבלי ליצור חשבון ברשת. אולם אז, לא יהיה ניתן להתחבר לחברים, לדרג תוספים וכו׳. מומלץ לקרוא את הצהרת הפרטיות שלנו בכתובת https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2271,7 +2271,7 @@ msgstr "הוספת התקן" msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." -msgstr "* התצורה לשימוש תקבע על פי מקש \"בחירה\" שנלחץ כדי להצטרף למשחק." +msgstr "* מקש הבחירה שאיתו מצטרפים למשחק יקבע באיזו תצורה ייעשה שימוש." #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings @@ -2286,7 +2286,7 @@ msgstr "מפה מוקטנת" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Splitscreen Multiplayer layout" -msgstr "פריסת המסך המפוצל\nלמשחק מרובה משתתפים" +msgstr "פריסת מסך מפוצל למשחק מרובה משתתפים" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings @@ -2370,7 +2370,7 @@ msgstr "החלת הרזולוציה החדשה" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" -msgstr "נא לבחור רמה" +msgstr "נא לבחור רמת קושי" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a game mode" @@ -2379,7 +2379,7 @@ msgstr "נא לבחור מצב משחק" #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen msgid "Use left/right to choose your team and press fire" -msgstr "יש להשתמש במקשי ימין/שמאל לבחירת הקבוצה שלך וללחוץ על \"ירייה\"" +msgstr "יש להשתמש במקשים ימינה/שמאלה לבחירת הקבוצה שלך וללחוץ על \"ירייה\"" #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen @@ -2414,7 +2414,7 @@ msgstr "מספר המתחרים המדומים בקבוצה הכחולה" #. I18N: In the track and grand prix selection screen #: src/race/grand_prix_data.cpp:623 msgid "Random Grand Prix" -msgstr "גרנד־פרי אקראי" +msgstr "סבב מרוצים אקראי" #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) @@ -2445,23 +2445,23 @@ msgstr "צבע המכונית" #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." -msgstr "את ערכת הנושא אפשר לשנות באפשרויות הממשק." +msgstr "אפשר לשנות את ערכת הנושא באפשרויות הממשק." #. I18N: ./data/tips.xml msgid "You can see other karts' powerups by enabling it in the UI options." -msgstr "אפשר לראות את החיזוקים של המכוניות האחרות בעזרת הפעלת האפשרות באפשרויות הממשק." +msgstr "אפשר לראות חיזוקים של מכוניות אחרות אם מפעילים זאת באפשרויות הממשק." #. I18N: ./data/tips.xml msgid "The font size can be changed in the UI options." -msgstr "את גודל הגופן אפשר לשנות באפשרויות הממשק." +msgstr "אפשר לשנות את גודל הגופן באפשרויות הממשק." #. I18N: ./data/tips.xml msgid "The help menu has lots of useful information." -msgstr "תפריט העזרה מכיל מידע שימושי בכמויות." +msgstr "תפריט העזרה מכיל המון מידע שימושי." #. I18N: ./data/tips.xml msgid "In single-player, you can watch and challenge recorded time-trials." -msgstr "במשחק לבד, אפשר לצפות ולהתחרות בהקלטות של מרוצים נגד השעון." +msgstr "במשחקים יחידיים, אפשר לצפות ולהתחרות בהקלטות של מרוצים נגד השעון." #. I18N: ./data/tips.xml msgid "" @@ -2470,7 +2470,7 @@ msgstr "אפשר לבקר באתר https://supertuxkart.net/ למידע נוסף #. I18N: ./data/tips.xml msgid "Short nitro boosts are more efficient." -msgstr "האצות גז־טורבו קצרות הן יעילות יותר." +msgstr "האצות קצרות של גז טורבו הן יותר יעילות." #. I18N: ./data/tips.xml msgid "Only use zippers when it is safe. Long straight lines are ideal." @@ -2480,25 +2480,25 @@ msgstr "יש להשתמש במאיצנים רק כאשר בטוח להשתמש msgid "" "Don't use multiple zippers quickly in row, instead, wait until the speed " "boost wears off." -msgstr "אין להשתמש במאיצנים מרובים במהירות ברצף, יש להמתין עד שהאצת המהירות מפסיקה." +msgstr "לא משתמשים במאיצנים מרובים בבת אחת, אלא ממתינים עד שהאצת המהירות מתפוגגת." #. I18N: ./data/tips.xml msgid "Skidding makes you much faster, do it whenever safe." -msgstr "ההחלקה מגבירה מאוד את המהירות, יש לעשות זאת רק כשבטוח." +msgstr "ההחלקה מגבירה מאוד את המהירות, מומלץ להשתמש בה כשאין סיכון." #. I18N: ./data/tips.xml msgid "The swatter can be used to remove bombs or parachutes." -msgstr "אפשר להשתמש במחבט היתושים להסרת פצצות או מצנחים." +msgstr "מחבט היתושים מסוגל להסיר מהמכונית שלך פצצות ומצנחים." #. I18N: ./data/tips.xml msgid "" "You can't stop turning while skidding. Good kart orientation at the skid's " "start is paramount." -msgstr "אי אפשר להסתובב במהלך החלקה. נטייה טובה של מכוניות בתחילת ההחלקה היא מועילה באופן משמעותי." +msgstr "אי אפשר להסתובב בזמן שמחליקים. מומלץ בחום להטות את המכונית לכיוון טוב בתחילת ההחלקה." #. I18N: ./data/tips.xml msgid "You get a startup boost if you start accelerating during \"Set\"." -msgstr "מקבלים האצה בהזנקה אם מתחילים להאיץ במהלך \"היכון\"." +msgstr "כאשר מתחילים להאיץ ב\"היכון\", מקבלים האצה בהזנקה." #. I18N: ./data/tips.xml msgid "Braking allows to get rid of parachutes quicker." @@ -2506,7 +2506,7 @@ msgstr "בלימה מאפשרת להיפטר מהמצנחים במהירות." #. I18N: ./data/tips.xml msgid "First and foremost, focus on where your kart is going." -msgstr "בראש ובראשונה, יש להתרכז בלאן המכונית נוסעת." +msgstr "בראש ובראשונה, יש להתמקד במקום שאליו המכונית נוסעת." #. I18N: ./data/tips.xml msgid "The rescue key (button) is very useful." @@ -2514,23 +2514,23 @@ msgstr "מקש (כפתור) החילוץ שימושי מאוד." #. I18N: ./data/tips.xml msgid "Be careful when close to other karts, they may attack you!" -msgstr "יש להיזהר כשקרובים למכוניות אחרות, הן עלולות לתקוף אותך!" +msgstr "כשמתקרבים למכוניות אחרות יש להיזהר, הן עלולות לתקוף!" #. I18N: ./data/tips.xml msgid "" "Basketballs can be destroyed using precise backward shots with a bowling " "ball, cake, or plunger." -msgstr "אפשר להשמיד כדורי סל בעזרת זריקות מדויקות לאחור של כדור כדורת, עוגה או פומפה." +msgstr "אפשר להשמיד כדורסל בעזרת זריקה מדויקת לאחור של כדורי באולינג, עוגות, או פומפה." #. I18N: ./data/tips.xml msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "" +msgstr "מומלץ להימנע מהתנגשות בפגושים של מכוניות אחרות כי זה יאט אותך." #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." -msgstr "אפשר להשתמש בכדורי כדורת כדי לדחוף ולחסום את הכדור." +msgstr "אפשר להשתמש בכדורי באולינג כדי לדחוף ולחסום את הכדור." #. I18N: ./data/tips.xml msgid "In soccer, always work as a team for good results." @@ -2540,25 +2540,25 @@ msgstr "בכדורגל, יש לעבוד כקבוצה תמיד בשביל תוצ msgid "" "If you miss the ball and an opponent is approaching, try hitting them with a" " powerup or block their way." -msgstr "אם הכדור לא נמצא אצלך ויריב מתקרב, אפשר לנסות לפגוע בו באמצעות חיזוק או לחסום את דרכו." +msgstr "אם החטאת את השער כשזרקת את הכדור ויריב מתקרב, אפשר לנסות לפגוע בו עם חיזוק או לחסום לו את הדרך." #. I18N: ./data/tips.xml msgid "Good rotation of positions (attack and defense) is essential." -msgstr "בחירת המקומות הטובים (להתקפה ולהגנה) חיונית." +msgstr "חשוב ביותר לבחור ולהתמקם בעמדות טובות (להתקפה ולהגנה)." #. I18N: ./data/tips.xml msgid "Make sure to store at least 2 big cans worth of nitro." -msgstr "כדאי לדאוג לאחסן לפחות 2 פחיות גדולות של גז־טורבו." +msgstr "מומלץ לשמור גז טורבו בכמות של 2 פחיות גדולות לפחות." #. I18N: ./data/tips.xml msgid "Never use the three bowling balls all at the same time." -msgstr "אין להשתמש בשלושה כדורי כדורת בו־זמנית." +msgstr "לא משתמשים בשלושה כדורי באולינג בבת אחת." #. I18N: ./data/tips.xml msgid "" "Don't get in the way of a teammate carrying the ball, though you can try to " "hit opponents attempting to stop them from scoring." -msgstr "אין להפריע לחברי הקבוצה להחזיק את הכדור, כן יש לנסות לירות בשחקנים שמנסים למנוע מהקבוצה שלך להבקיע לשער." +msgstr "לא חוסמים את הדרך לחברי הקבוצה כשהם מחזיקים את הכדור, אלא מנסים לירות על שחקני הקבוצה היריבה שמנסים למנוע מהם להבקיע גול." #. I18N: ../stk-assets/karts/adiumy/kart.xml msgid "Adiumy" @@ -2570,7 +2570,7 @@ msgstr "אמנדה" #. I18N: ../stk-assets/karts/beastie/kart.xml msgid "Godette" -msgstr "" +msgstr "גוֹדֵט" #. I18N: ../stk-assets/karts/emule/kart.xml msgid "Emule" @@ -2602,7 +2602,7 @@ msgstr "נוֹלוֹק" #. I18N: ../stk-assets/karts/pidgin/kart.xml msgid "Pidgin" -msgstr "פּידג׳ין" +msgstr "פּידג׳ן" #. I18N: ../stk-assets/karts/puffy/kart.xml msgid "Puffy" @@ -2638,7 +2638,7 @@ msgstr "מצולות עתיקות" #. I18N: ../stk-assets/tracks/alien_signal/track.xml msgid "Alien Signal" -msgstr "אות חייזרים" +msgstr "אותות מהחלל החיצון" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" @@ -2647,7 +2647,7 @@ msgstr "מבוך הקולוסאום העתיק" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml msgid "Candela City" -msgstr "העיר קנדלה" +msgstr "העיר קַנַדֶלָה" #. I18N: ../stk-assets/tracks/battleisland/track.xml msgid "Battle Island" @@ -2675,15 +2675,15 @@ msgstr "מבצר המגמה" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" -msgstr "אי גראן פראדיסו" +msgstr "האי גְרַאן פָּרָדיסוֹ" #. I18N: ../stk-assets/tracks/hacienda/track.xml msgid "Hacienda" -msgstr "אַסְיֶינדַה" +msgstr "המערב הפרוע" #. I18N: ../stk-assets/tracks/hole_drop/track.xml msgid "Hole Drop" -msgstr "" +msgstr "גומות בקרקע" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" @@ -2692,37 +2692,37 @@ msgstr "מגרש הכדורגל הקפוא" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" -msgstr "מה קרה, ילדי פרחים קטנטנים? מנהיגכם הדגול גנו נעלם?" +msgstr "מה קרה, היפים קטנים? המנהיג הדגול שלכם, גנו, נעלם?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." -msgstr "אה כן, תראו, הוא נמצא בטירה שלי ויוגש לארוחת ערב..." +msgstr "אה כן, תראו, הוא בטירה שלי עכשיו והוא יוגש בתור ארוחת ערב..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." -msgstr "אבל אני יצור הוגן, אז אעשה איתכם עסקה." +msgstr "אבל אני יצור הגון, אז אעשה איתכם עסקה." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." -msgstr "אם תנצחו אותי במרוץ, אשחרר את הברנש הזקן." +msgstr "אם ינצחו אותי במרוץ, אשחרר את הברנש הזקן." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" -msgstr " אבל טיפשים קטנים ועלובים שכמותכם לעולם לא יביסו אותי - מלך המכוניות!" +msgstr " אבל טיפשים קטנים ועלובים שכמותכם לעולם לא ינצחו אותי - מלך המכוניות!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "זירת לאס דונאס" +msgstr "הזירה של לאס דוּנַאס" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" -msgstr "אצטדיון הכדורגל של לאס דונאס" +msgstr "אצטדיון הכדורגל של לאס דוּנַאס" #. I18N: ../stk-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" @@ -2730,7 +2730,7 @@ msgstr "מסביב למגדלור" #. I18N: ../stk-assets/tracks/mines/track.xml msgid "Old Mine" -msgstr "מכרה ישן" +msgstr "המכרה הישן" #. I18N: ../stk-assets/tracks/minigolf/track.xml msgid "Minigolf" @@ -2738,19 +2738,19 @@ msgstr "מיני גולף" #. I18N: ../stk-assets/tracks/oasis/track.xml msgid "Oasis" -msgstr "" +msgstr "נווה מדבר" #. I18N: ../stk-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" -msgstr "כיתת החשבון של אוליבר" +msgstr "הכיתה של אוליבר" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" -msgstr "חלקת הדלעות" +msgstr "חלקת הדלועים" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" -msgstr "אחוזת רייבנברידג׳" +msgstr "אחוזת רֶיְיבֶנבּרידג׳" #. I18N: ../stk-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" @@ -2758,7 +2758,7 @@ msgstr "חולות נודדים" #. I18N: ../stk-assets/tracks/scotland/track.xml msgid "Nessie's Pond" -msgstr "האגם של נסי" +msgstr "האגם של נֶסי" #. I18N: ../stk-assets/tracks/snowmountain/track.xml msgid "Northern Resort" @@ -2778,11 +2778,11 @@ msgstr "האצטדיון" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" -msgstr "‏SuperTuxKart ארגונים" +msgstr "המטה של SuperTuxKart" #. I18N: ../stk-assets/tracks/temple/track.xml msgid "Temple" -msgstr "מקדש" +msgstr "המקדש" #. I18N: ../stk-assets/tracks/volcano_island/track.xml msgid "Volcan Island" @@ -2794,7 +2794,7 @@ msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml msgid "Zen Garden" -msgstr "גן זן" +msgstr "גן יפני עתיק" #: src/achievements/achievement.cpp:387 #, c-format @@ -2808,15 +2808,15 @@ msgstr "ההתחברות לשרת התוספים של SuperTuxKart נכשלה." #: src/addons/news_manager.cpp:180 #, c-format msgid "Error downloading news: '%s'." -msgstr "שגיאה בהורדת החדשות: \"%s\"." +msgstr "שגיאה בהורדת החדשות: „%s”." #: src/challenges/challenge_data.cpp:303 src/network/server_config.cpp:261 msgid "Normal Race (Grand Prix)" -msgstr "מרוץ רגיל (גרנד־פרי)" +msgstr "מרוץ רגיל (סבב מרוצים)" #: src/challenges/challenge_data.cpp:305 msgid "Time-Trial (Grand Prix)" -msgstr "נגד השעון (גרנד־פרי)" +msgstr "נגד השעון (סבב מרוצים)" #: src/challenges/challenge_data.cpp:310 msgid "Time-Trial - beat the replay" @@ -2824,51 +2824,51 @@ msgstr "נגד השעון - השידור הטוב ביותר" #: src/challenges/challenge_data.cpp:312 msgid "Time-Trial - nitro challenge" -msgstr "נגד השעון - אתגר גז־טורבו" +msgstr "נגד השעון - אתגר גז טורבו" #: src/challenges/challenge_data.cpp:314 msgid "Normal Race (single race)" -msgstr "מרוץ רגיל (מרוץ יחיד)" +msgstr "מרוץ רגיל (מרוץ בודד)" #: src/challenges/challenge_data.cpp:316 msgid "Time-Trial (single race)" -msgstr "נגד השעון (מרוץ יחיד)" +msgstr "נגד השעון (מרוץ בודד)" #: src/challenges/challenge_data.cpp:318 msgid "Follow the Leader (single race)" -msgstr "בעקבות המכונית המובילה (מרוץ יחיד)" +msgstr "בעקבות המכונית המובילה (מרוץ בודד)" #. I18N: In the Select challenge dialog, tell user this challenge has reversed #. laps #: src/challenges/challenge_data.cpp:324 #: src/states_screens/dialogs/select_challenge.cpp:78 msgid "Mode: Reverse" -msgstr "מצב: נסיעה לאחור" +msgstr "מצב: נסיעה ברוורס" #: src/challenges/challenge_data.cpp:601 #, c-format msgid "New track '%s' now available" -msgstr "המסלול החדש \"%s\" זמין כעת" +msgstr "המסלול החדש „%s” זמין כעת" #: src/challenges/challenge_data.cpp:605 #, c-format msgid "New game mode '%s' now available" -msgstr "מצב המשחק החדש \"%s\" זמין כעת" +msgstr "מצב המשחק החדש „%s” זמין כעת" #: src/challenges/challenge_data.cpp:615 #, c-format msgid "New Grand Prix '%s' now available" -msgstr "הגרנד פרי־החדש \"%s\" זמין כעת" +msgstr "סבב המרוצים החדש „%s” זמין כעת" #: src/challenges/challenge_data.cpp:619 #, c-format msgid "New difficulty '%s' now available" -msgstr "הרמה החדשה \"%s\" זמינה כעת" +msgstr "הרמה החדשה „%s” זמינה כעת" #: src/challenges/challenge_data.cpp:629 #, c-format msgid "New kart '%s' now available" -msgstr "המכונית החדשה \"%s\" זמינה כעת" +msgstr "המכונית החדשה „%s” זמינה כעת" #: src/challenges/story_mode_timer.cpp:281 #: src/states_screens/options/options_screen_ui.cpp:318 @@ -2930,7 +2930,7 @@ msgstr "עצה: %s" #: src/guiengine/engine.cpp:1496 msgid "Loading" -msgstr "בהליכי טעינה" +msgstr "בטעינה" #: src/guiengine/widgets/kart_stats_widget.cpp:104 msgid "Mass" @@ -2946,7 +2946,7 @@ msgstr "האצה" #: src/guiengine/widgets/kart_stats_widget.cpp:123 msgid "Nitro efficiency" -msgstr "יעילות גז־טורבו" +msgstr "יעילות גז טורבו" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) @@ -3012,13 +3012,13 @@ msgstr "לחצן עכבר X2" #: src/input/binding.cpp:104 msgctxt "input_key" msgid "Backspace" -msgstr "מקש Backspace" +msgstr "מקש מחיקה (Backspace)" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:106 msgctxt "input_key" msgid "Tab" -msgstr "טאב" +msgstr "Tab" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:108 @@ -3030,7 +3030,7 @@ msgstr "ניקוי" #: src/input/binding.cpp:110 msgctxt "input_key" msgid "Return" -msgstr "מקש Enter" +msgstr "Enter" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:112 @@ -3048,7 +3048,7 @@ msgstr "Ctrl" #: src/input/binding.cpp:116 msgctxt "input_key" msgid "Alt/Menu" -msgstr "Alt/תפריט" +msgstr "" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:118 @@ -3079,7 +3079,7 @@ msgstr "Junja" #: src/input/binding.cpp:127 msgctxt "input_key" msgid "Final" -msgstr "סופי" +msgstr "" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:129 @@ -3091,7 +3091,7 @@ msgstr "Esc" #: src/input/binding.cpp:131 msgctxt "input_key" msgid "Convert" -msgstr "המרה" +msgstr "" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:133 @@ -3139,7 +3139,7 @@ msgstr "End" #: src/input/binding.cpp:147 msgctxt "input_key" msgid "Home" -msgstr "בית (Home)" +msgstr "Home" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:149 @@ -3169,19 +3169,19 @@ msgstr "למטה" #: src/input/binding.cpp:157 msgctxt "input_key" msgid "Select" -msgstr "בחירה (Select)" +msgstr "Select" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:159 msgctxt "input_key" msgid "Print" -msgstr "הדפסה (Print)" +msgstr "Print" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:161 msgctxt "input_key" msgid "Exec" -msgstr "ביצוע (Exec)" +msgstr "הרצה (Exec)" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:163 @@ -3223,7 +3223,7 @@ msgstr "סמליל ימני" #: src/input/binding.cpp:211 msgctxt "input_key" msgid "Apps" -msgstr "יישומים" +msgstr "" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:213 @@ -3367,25 +3367,25 @@ msgstr "תפריט ימני" #: src/input/binding.cpp:289 msgctxt "input_key" msgid "Attn" -msgstr "Attn" +msgstr "" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:291 msgctxt "input_key" msgid "Crsel" -msgstr "Crsel" +msgstr "" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:293 msgctxt "input_key" msgid "Exsel" -msgstr "Exsel" +msgstr "" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:295 msgctxt "input_key" msgid "Ereof" -msgstr "Ereof" +msgstr "" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:297 @@ -3409,7 +3409,7 @@ msgstr "Pa1" #: src/input/binding.cpp:303 msgctxt "input_key" msgid "Oem Clear" -msgstr "Oem Clear" +msgstr "" #. I18N: to appear in input configuration screen, for gamepad hats #: src/input/binding.cpp:343 src/input/binding.cpp:348 @@ -3462,12 +3462,12 @@ msgstr "נא להגדיר מחדש את המקשים." #: src/input/device_manager.cpp:497 msgid "Your input config file is not compatible with this version of STK." -msgstr "קובץ הגדרת הקלט שלך לא מתאים לגרסה הזאת של SuperTuxKart." +msgstr "קובץ הגדרת הקלט שלך לא מתאים לגרסה זו של SuperTuxKart." #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:159 msgid "Guide" -msgstr "הכפתור הראשי" +msgstr "כפתור Xbox" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:161 @@ -3477,22 +3477,22 @@ msgstr "התחלה (Start)" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:163 msgid "Left thumbstick press" -msgstr "Left thumbstick press" +msgstr "לחיצה עם מוט ההיגוי השמאלי" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:165 msgid "Right thumbstick press" -msgstr "Right thumbstick press" +msgstr "לחיצה עם מוט ההיגוי הימני" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:167 msgid "Left shoulder" -msgstr "Left shoulder" +msgstr "" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:169 msgid "Right shoulder" -msgstr "Right shoulder" +msgstr "" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:171 @@ -3517,42 +3517,42 @@ msgstr "DPad ימינה" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:181 msgid "Left thumbstick right" -msgstr "Left thumbstick right" +msgstr "מוט היגוי שמאלי כלפי ימינה" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:183 msgid "Left thumbstick left" -msgstr "Left thumbstick left" +msgstr "מוט היגוי שמאלי כלפי שמאלה" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:185 msgid "Left thumbstick down" -msgstr "Left thumbstick down" +msgstr "מוט היגוי שמאלי כלפי מטה" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:187 msgid "Left thumbstick up" -msgstr "Left thumbstick up" +msgstr "מוט היגוי שמאלי כלפי מעלה" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:189 msgid "Right thumbstick right" -msgstr "Right thumbstick right" +msgstr "מוט היגוי ימני כלפי ימינה" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:191 msgid "Right thumbstick left" -msgstr "Right thumbstick left" +msgstr "מוט היגוי ימני כלפי שמאלה" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:193 msgid "Right thumbstick down" -msgstr "Right thumbstick down" +msgstr "מוט היגוי ימני כלפי מטה" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:195 msgid "Right thumbstick up" -msgstr "Right thumbstick up" +msgstr "מוט היגוי ימני כלפי מעלה" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:197 @@ -3567,11 +3567,11 @@ msgstr "הדק ימני (RT)" #: src/input/input_manager.cpp:867 #, c-format msgid "Ignoring '%s'. You needed to join earlier to play!" -msgstr "בהתעלמות מ־\"%s\". היה צריך להצטרף מוקדם יותר כדי לשחק!" +msgstr "מתעלמים מ־„%s”. בשביל לשחק היה צריך להצטרף קודם." #: src/input/input_manager.cpp:903 msgid "Only the Game Master may act at this point!" -msgstr "רק מנהל המשחק יכול לפעול בנקודה זו!" +msgstr "רק מנהל המשחק יכול לפעול בנקודה זו." #: src/input/sdl_controller.cpp:253 #, c-format @@ -3582,14 +3582,14 @@ msgstr "הסוללה של %s חלשה." msgid "" "Connect your wiimote to the Bluetooth manager, then click on Ok. Detailed " "instructions at https://supertuxkart.net/Wiimote" -msgstr "יש לחבר את שלט Wii שלך אל מנהל Bluetooth, ולאחר מכן ללחוץ על אישור. הוראות מפורטות נמצאות בכתובת https://supertuxkart.net/Wiimote" +msgstr "יש לחבר את שלט ה־Wii דרך מנהל הבלוטות׳ ואז ללחוץ על „אישור”. ניתן למצוא הוראות מפורטות בכתובת https://supertuxkart.net/Wiimote" #: src/input/wiimote_manager.cpp:382 msgid "" "Press the buttons 1+2 simultaneously on your wiimote to put it in discovery " "mode, then click on Ok. Detailed instructions at " "https://supertuxkart.net/Wiimote" -msgstr "יש ללחוץ על כפתורי 1+2 בו־זמנית בשלט Wii שלך כדי לשים אותו במצב גילוי, ולאחר מכן ללחוץ על אישור. הוראות מפורטות נמצאות בכתובת https://supertuxkart.net/Wiimote" +msgstr "יש ללחוץ בבת אחת על המקשים 1 ו־2 בשלט ה־Wii בשביל להעביר אותו למצב איתור התקנים בקרבת מקום ואז ללחוץ על „אישור”. ניתן למצוא הוראות מפורטות בכתובת https://supertuxkart.net/Wiimote" #: src/input/wiimote_manager.cpp:405 #, c-format @@ -3598,7 +3598,6 @@ msgid_plural "Found %d wiimotes" msgstr[0] "נמצא שלט Wii‏ %d" msgstr[1] "נמצאו %d שלטי Wii" msgstr[2] "נמצאו %d שלטי Wii" -msgstr[3] "נמצאו %d שלטי Wii" #: src/input/wiimote_manager.cpp:410 msgid "Could not detect any wiimote :/" @@ -3614,7 +3613,7 @@ msgstr "זמן עונשין!!" #: src/karts/controller/local_player_controller.cpp:332 msgid "Don't accelerate before 'Set!'" -msgstr "אין להאיץ לפני \"היכון!\"" +msgstr "לא מאיצים לפני „היכון!”" #: src/karts/controller/spare_tire_ai.cpp:150 msgid "You can have at most 3 lives!" @@ -3635,7 +3634,7 @@ msgstr "ניצחת במרוץ!" #: src/karts/kart.cpp:1026 #, c-format msgid "You finished the race in rank %d!" -msgstr "סיימת את המרוץ במקום ה־%d!" +msgstr "סיימת את המרוץ במקום מספר %d!" #. I18N: Message shown in game to tell player left the game in network #: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 @@ -3740,12 +3739,12 @@ msgstr "טעות בדרך!" #: src/modes/soccer_world.cpp:533 src/modes/soccer_world.cpp:660 #, c-format msgid "%s scored a goal!" -msgstr "שער הובקע על ידי %s!" +msgstr "‏%s הבקיע/ה גול!" #: src/modes/soccer_world.cpp:535 src/modes/soccer_world.cpp:662 #, c-format msgid "Oops, %s made an own goal!" -msgstr "אופס, שער עצמי הובקע על ידי %s!" +msgstr "אופס, %s הבקיע/ה גול עצמי!" #: src/modes/three_strikes_battle.cpp:641 #, c-format @@ -3754,7 +3753,6 @@ msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "הופיעה מכונית צמיגים חלופיים %i!" msgstr[1] "הופיעו %i מכוניות צמיגים חלופיים!" msgstr[2] "הופיעו %i מכוניות צמיגים חלופיים!" -msgstr[3] "הופיעו %i מכוניות צמיגים חלופיים!" #: src/modes/world.cpp:1427 msgid "You have been eliminated!" @@ -3763,7 +3761,7 @@ msgstr "נפסלת!" #: src/modes/world.cpp:1434 #, c-format msgid "'%s' has been eliminated." -msgstr "\"%s\" נפסל/ה." +msgstr "„%s” נפסל/ה." #: src/network/protocols/client_lobby.cpp:129 msgid "Server has been shut down." @@ -3797,7 +3795,7 @@ msgstr "‏%s התנתק/ה." #: src/network/protocols/client_lobby.cpp:672 msgid "" "Press player name in the list for player management and ranking information." -msgstr "יש ללחוץ על שם השחקן/ית ברשימה לניהול ולפרטי דירוג השחקן/ית." +msgstr "אפשר ללחוץ על שם של שחקן ברשימה לצורך ניהול ופרטי דירוג השחקן." #. I18N: In the networking lobby #. I18N: In server info dialog @@ -3838,7 +3836,7 @@ msgstr "הגבלת זמן" #: src/states_screens/online/create_server_screen.cpp:255 #: src/states_screens/track_info_screen.cpp:377 msgid "Goals limit" -msgstr "הגבלת שערים" +msgstr "מגבלת כמות גולים" #. I18N: In the networking lobby #: src/network/protocols/client_lobby.cpp:774 @@ -3849,7 +3847,7 @@ msgstr "סוג משחק כדורגל: %s" #: src/network/protocols/client_lobby.cpp:784 #, c-format msgid "Grand prix progress: %d / %d" -msgstr "התקדמות בגרנד־פרי: %d / %d" +msgstr "התקדמות בסבב המרוצים: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start @@ -3860,7 +3858,7 @@ msgstr "כל השחקנים הצטרפו לקבוצה האדומה או הכחו #. I18N: Display when a player is allow to control the server #: src/network/protocols/client_lobby.cpp:923 msgid "You are now the owner of server." -msgstr "השרת בבעלותך כעת." +msgstr "השרת בניהולך כעת." #: src/network/protocols/client_lobby.cpp:966 msgid "Connection refused: Server is busy." @@ -3884,7 +3882,7 @@ msgstr "החיבור נדחה: השרת מלא." #: src/network/protocols/client_lobby.cpp:998 msgid "Connection refused: Invalid player connecting." -msgstr "החיבור נדחה: התחברות שחקן/ית בלתי־תקינה." +msgstr "החיבור נדחה: התחברות שחקן/ית שאינה תקינה." #: src/network/protocols/client_lobby.cpp:1026 msgid "Failed to start the network game." @@ -3903,11 +3901,11 @@ msgstr "לא נותר מקום בזירה - ההצטרפות בזמן־אמת ה #. I18N: Error message shown if only 1 player remains in network #: src/network/protocols/client_lobby.cpp:1249 msgid "Only 1 player remaining, returning to lobby." -msgstr "נותר/ה שחקן/ית 1, חוזרים למבואה." +msgstr "לא נותרו עוד שחקנים, חוזרים למבואה." #: src/network/protocols/client_lobby.cpp:1255 msgid "Server owner quit the game." -msgstr "בעלי השרת יצאו מהמשחק." +msgstr "מנהל/ת השרת יצא/ה מהמשחק." #. I18N: Status shown to player when he will be spectating the next game #: src/network/protocols/client_lobby.cpp:1259 @@ -3975,11 +3973,11 @@ msgstr "כשל בזיהוי מספר הפִּתחה של השרת %s." #: src/network/protocols/lobby_protocol.cpp:294 msgid "Network grand prix has been finished." -msgstr "הגרנד־פרי ברשת הסתיים." +msgstr "סבב המרוצים ברשת הסתיים." #: src/network/server_config.cpp:263 msgid "Time Trial (Grand Prix)" -msgstr "נגד השעון (גרנד־פרי)" +msgstr "נגד השעון (סבב מרוצים)" #. I18N: Game mode #. I18N: In the create server screen for battle server @@ -4021,7 +4019,6 @@ msgid_plural "%d friends are now online." msgstr[0] "חבר %d מחובר כעת." msgstr[1] "%d חברים מחוברים כעת." msgstr[2] "%d חברים מחוברים כעת." -msgstr[3] "%d חברים מחוברים כעת." #. I18N: Tell your friend if he is on any server in game #: src/online/online_player_profile.cpp:519 @@ -4036,7 +4033,6 @@ msgid_plural "You have %d new friend requests!" msgstr[0] "יש לך %d בקשת חברות חדשה!" msgstr[1] "יש לך %d בקשות חברות חדשות!" msgstr[2] "יש לך %d בקשות חברות חדשות!" -msgstr[3] "יש לך %d בקשות חברות חדשות!" #: src/online/online_player_profile.cpp:556 msgid "You have a new friend request!" @@ -4103,7 +4099,7 @@ msgstr "3 חודשים" #: src/states_screens/addons_screen.cpp:53 msgid "6 months" -msgstr "6 חודשים" +msgstr "חצי שנה" #: src/states_screens/addons_screen.cpp:54 msgid "9 months" @@ -4167,14 +4163,13 @@ msgstr "זירה אקראית" #, c-format msgid "%d arena unavailable in single player." msgid_plural "%d arenas unavailable in single player." -msgstr[0] " זירה %d אינה זמינה במשחק לבד." -msgstr[1] "%d זירות אינן זמינות במשחק לבד." -msgstr[2] "%d זירות אינן זמינות במשחק לבד." -msgstr[3] "%d זירות אינן זמינות במשחק לבד." +msgstr[0] " זירה %d אינה זמינה במשחק יחידי." +msgstr[1] "%d זירות אינן זמינות במשחק יחידי." +msgstr[2] "%d זירות אינן זמינות במשחק יחידי." #: src/states_screens/credits.cpp:184 msgid "translator-credits" -msgstr "Launchpad Contributions:\nNiv Baehr, 2016-2017\nCapri, 2015\ngk, 2015-2016\nLiran, 2016-2017\nOmer I.S., 2020-2022\nOmer I.S., 2020-2021\nOmer I.S., 2020\nעומר רוזנר, 2018\nYaroslav Serhieiev, 2018\nYevgney Sliosarenko, 2015\nעומר רוזנר, 2018-2019\nרואי לוי, 2016\nGenghisKhan, 2015-2016\n‫רואי לוי‬‎, 2016\nAsael\nAuria\nDdorda\nGenghisKhan\nJorge Mariano\nLeo Juszkiewicz\nNiv Baehr\nReuma Mordechai\nSTK-team\nShai Shapira\nShimi Chen\nYaron" +msgstr "Launchpad Contributions:\nNiv Baehr, 2016-2017\nCapri, 2015\ngk, 2015-2016\nLiran, 2016-2017\nOmer I.S., 2020-2024\nעומר רוזנר, 2018\nYaroslav Serhieiev, 2018\nYevgney Sliosarenko, 2015\nעומר רוזנר, 2018-2019\nרואי לוי, 2016\nGenghisKhan, 2015-2016\n‫רואי לוי‬‎, 2016\nAsael\nAuria\nDdorda\nGenghisKhan\nJorge Mariano\nLeo Juszkiewicz\nNiv Baehr\nReuma Mordechai\nSTK-team\nShai Shapira\nShimi Chen\nYaron" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:65 msgctxt "achievement_info" @@ -4189,22 +4184,22 @@ msgstr "התקדמות" #. I18N: For achievements, a parent goal linking logically several subgoals #: src/states_screens/dialogs/achievement_progress_dialog.cpp:162 msgid "Fulfill all the subgoals" -msgstr "השלמת כל התת־מטרות" +msgstr "השגת כל המטרות המשניות" #. I18N: For achievements, a parent goal linking logically several subgoals #: src/states_screens/dialogs/achievement_progress_dialog.cpp:164 msgid "Fulfill all the subgoals at the same time" -msgstr "השלמת כל התת־מטרות בבת־אחת" +msgstr "השגת כל המטרות המשניות במכה" #. I18N: For achievements, a parent goal linking logically several subgoals #: src/states_screens/dialogs/achievement_progress_dialog.cpp:166 msgid "Fulfill at least one subgoal" -msgstr "הגעה לתת־מטרת אחת לפחות" +msgstr "השגת מטרה משנית אחת לפחות" #. I18N: For achievements, a parent goal linking logically several subgoals #: src/states_screens/dialogs/achievement_progress_dialog.cpp:168 msgid "The sum of the subgoals must reach the indicated value" -msgstr "סכום התת־מטרות צריך להגיע לערך שצוין" +msgstr "על סכום המטרות המשניות להגיע לערך שצוין" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4230,7 +4225,7 @@ msgstr "ניצחונות במרוצים נגד השעון" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:176 msgid "Follow-the-Leader races won" -msgstr "ניצחונות במרוצים בעקבות המכונית המובילה" +msgstr "ניצחונות במרוצי בעקבות המכונית המובילה" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4417,14 +4412,14 @@ msgstr "חיזוקים בשימוש" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:254 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:262 msgid " (1 race)" -msgstr "(מרוץ 1)" +msgstr "(מרוץ אחד)" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:238 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:240 msgid "Bowling ball hits" -msgstr "פגיעות מכדור כדורת" +msgstr "פגיעות מכדור באולינג" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4467,7 +4462,7 @@ msgstr "החלקה" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:269 msgid " (1 lap)" -msgstr "(הקפה 1)" +msgstr "(הקפה אחת)" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4510,7 +4505,7 @@ msgstr "מרוצים הפוכים שהסתיימו" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:280 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:305 msgid "Races finished alone" -msgstr "מרוצים ללא יריבים" +msgstr "מרוצים במשחק יחידי שהסתיימו" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4567,7 +4562,7 @@ msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" "To add a keyboard config, you can use the button below, HOWEVER please note that most keyboards only support a limited amount of simultaneous keypresses and are thus inappropriate for multiplayer gameplay. (You can, however, connect multiple keyboards to this device. Remember that everyone still needs different keybindings in this case.)" -msgstr "בקרי משחק חדשים וג׳ויסטיקים יופיעו ברשימה באופן אוטומטי בעת התחברות להתקן הזה.\n\nכדי להוסיף תצורת מקלדת, אפשר להשתמש בלחצן שלמטה. עם זאת, יש לשים לב שרוב המקלדות תומכות בהקשה על מספר מוגבל של מקשים בו־זמנית, ולכן אינן מתאימות למשחק מרובה משתתפים. (אפשר, עם זאת, לחבר כמה מקלדות למחשב. יש לזכור שגם במקרה הזה כל אחת צריכה מערך מקשים שונה.)" +msgstr "בקרי משחק חדשים וג׳ויסטיקים יופיעו ברשימה באופן אוטומטי בעת התחברות למכשיר הזה.\n\nכדי להוסיף תצורת מקלדת, אפשר להשתמש בלחצן שלמטה. עם זאת, יש לשים לב כי רוב המקלדות תומכות בהקשה על מספר מוגבל של מקשים בו־זמנית, ולכן אינן מתאימות למשחק מרובה משתתפים. (אפשר, עם זאת, לחבר כמה מקלדות למחשב. יש לזכור שגם במקרה הזה כל אחת צריכה מערך מקשים שונה.)" #. I18N: In the 'add new input device' dialog #: src/states_screens/dialogs/add_device_dialog.cpp:87 @@ -4609,7 +4604,7 @@ msgstr "הורדת התוסף נכשלה, עימך הסליחה" #: src/states_screens/dialogs/addons_loading.cpp:374 #, c-format msgid "Problems installing the addon '%s'." -msgstr "בעיות בהתקנת התוסף \"%s\"." +msgstr "התקנת התוסף „%s” נתקלה בבעיות." #: src/states_screens/dialogs/addons_loading.cpp:385 #: src/states_screens/dialogs/addons_loading.cpp:436 @@ -4620,7 +4615,7 @@ msgstr "ניסיון חוזר" #: src/states_screens/dialogs/addons_loading.cpp:425 #, c-format msgid "Problems removing the addon '%s'." -msgstr "בעיות בהסרת התוסף \"%s\"." +msgstr "הסרת התוסף „%s” נתקלה בבעיות." #: src/states_screens/dialogs/addons_pack.cpp:66 msgid "Background download completed." @@ -4641,12 +4636,12 @@ msgstr "הסיסמה הנוכחית שגויה." #: src/states_screens/dialogs/change_password_dialog.cpp:143 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" -msgstr "הסיסמה צריכה להיות בין 8 ל־30 תווים!" +msgstr "על אורך הסיסמה להיות בין 8 ל־30 תווים." #: src/states_screens/dialogs/change_password_dialog.cpp:150 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" -msgstr "הסיסמות אינן תואמות!" +msgstr "הסיסמות אינן תואמות." #: src/states_screens/dialogs/change_password_dialog.cpp:235 #: src/states_screens/dialogs/recovery_dialog.cpp:207 @@ -4667,19 +4662,18 @@ msgid_plural "Confirm resolution within %i seconds" msgstr[0] "יש לאשר את הרזולוציה תוך שנייה %i" msgstr[1] "יש לאשר את הרזולוציה תוך %i שניות" msgstr[2] "יש לאשר את הרזולוציה תוך %i שניות" -msgstr[3] "יש לאשר את הרזולוציה תוך %i שניות" #: src/states_screens/dialogs/confirm_resolution_dialog.cpp:93 msgid "" "Resolutions smaller than 1024x768 or 1280x720 are unsupported. Some parts of" " the UI may not work correctly." -msgstr "רזולוציות נמוכות מ־1024x768 או מ־1280x720 אינן נתמכות. חלקים מסוימים של ממשק המשתמש לא יעבדו באופן תקין." +msgstr "אין תמיכה ברזולוציות נמוכות מ־1024x768 או מ־1280x720. חלקים מסוימים מתוך ממשק המשתמש עשויים שלא לעבוד כראוי." #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 #: src/states_screens/options/options_screen_ui.cpp:166 msgid "Drone chase" -msgstr "מרדף מזל״טים" +msgstr "מרדף רחפנים" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings @@ -4689,7 +4683,7 @@ msgstr "מרדף מזל״טים" #: src/states_screens/options/options_screen_video.cpp:620 #: src/states_screens/options/options_screen_video.cpp:648 msgid "Custom" -msgstr "מותאמת" +msgstr "בהתאמה אישית" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled @@ -4742,20 +4736,20 @@ msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " "don't have a wifi connection." -msgstr "משאבי המשחק המלאים של SuperTuxKart (כולל מרקמים ומוזיקה באיכות גבוהה) יורדו בשביל חוויית משחק טובה יותר, יהיה שימוש בנתונים הניידים שלך אם אין לך חיבור אלחוטי לרשת." +msgstr "תתבצע הורדה של משאבי המשחק המלאים של SuperTuxKart (לרבות מרקמים ומוזיקה באיכות גבוהה) בשביל לספק חוויית משחק מיטבית, ייעשה שימוש בחבילת הנתונים הניידים אם אין חיבור פעיל לרשת אלחוטית." #. I18N: In download assets dialog #: src/states_screens/dialogs/download_assets.cpp:116 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." -msgstr "משאבי המשחק המלאים של SuperTuxKart (כולל מרקמים ומוזיקה באיכות גבוהה) יורדו בשביל חוויית משחק טובה יותר." +msgstr "תתבצע הורדה של משאבי המשחק המלאים של SuperTuxKart (כולל מרקמים ומוזיקה באיכות גבוהה) בשביל לספק חוויית משחק מיטבית." #: src/states_screens/dialogs/enter_address_dialog.cpp:42 msgid "" "Enter the server address optionally followed by : and then port or select " "address from list." -msgstr "נא לספק את כתובת השרת אליה אפשר להוסיף \":\" ואז את הפִּתחה, או לבחור כתובת שרת מהרשימה." +msgstr "נא לספק את כתובת השרת אליה אפשר להוסיף „:” ואז את הפִּתחה, או לבחור כתובת שרת מהרשימה." #: src/states_screens/dialogs/enter_address_dialog.cpp:124 #, c-format @@ -4851,7 +4845,7 @@ msgstr "הקפות: %d" #: src/states_screens/dialogs/high_score_info_dialog.cpp:143 #, c-format msgid "Reverse: %s" -msgstr "נסיעה לאחור: %s" +msgstr "נסיעה ברוורס: %s" #. I18N: for empty highscores entries #: src/states_screens/dialogs/high_score_info_dialog.cpp:226 @@ -4877,7 +4871,7 @@ msgstr "לא להציג שוב" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:50 msgid "Player info" -msgstr "פרטי השחקן/ית" +msgstr "מידע על השחקן/ית" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:55 @@ -4900,7 +4894,7 @@ msgstr "סילוק" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:124 msgid "Change team" -msgstr "שנה קבוצה" +msgstr "החלפת קבוצה" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:139 @@ -4941,7 +4935,7 @@ msgstr "נא ללחוץ על מקש כרצונך\n(לחיצה על ESC לביט #: src/states_screens/dialogs/press_a_key_dialog.cpp:49 msgid "Press any key..." -msgstr "נא ללחוץ על מקש כרצונך..." +msgstr "נא ללחוץ על מקש כלשהו..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 #: src/states_screens/online/networking_lobby.cpp:249 @@ -4984,11 +4978,11 @@ msgstr "ל־%s עדיין אין דירוג." #: src/states_screens/dialogs/ranking_callback.hpp:56 #, c-format msgid "%s is number %d in the rankings with a score of %f." -msgstr "%s במקום ה־%d עם ניקוד %f." +msgstr "‏%s במקום מספר %d עם ניקוד %f." #: src/states_screens/dialogs/recovery_dialog.cpp:120 msgid "Username and/or email address invalid." -msgstr "שם המשתמש ו/או כתובת הדוא״ל בלתי־תקינים." +msgstr "שם המשתמש ו/או כתובת הדוא״ל אינם תקינים." #: src/states_screens/dialogs/registration_dialog.cpp:42 #, c-format @@ -4997,12 +4991,12 @@ msgid "" "agree to these terms in order to register an account for STK. If you have " "any questions or comments regarding these terms, one of the members of the " "development team would gladly assist you." -msgstr "נא לקרוא את תנאי השימוש של SuperTuxKart בכתובת \"%s\". חובה להסכים לתנאים אלו כדי להירשם לחשבון SuperTuxKart. חברי צוות הפיתוח ישמחו לסייע בעניין שאלות או הערות בנוגע לתנאים אלו." +msgstr "נא לקרוא את התנאים וההגבלות של SuperTuxKart בכתובת „%s”. חובה לאשר את התנאים הללו על מנת להירשם לחשבון SuperTuxKart. אם יש לך שאלות או הערות כלשהן בנוגע לפרטים, אחד מחברי צוות הפיתוח של SuperTuxKart ישמח לסייע לך." #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:60 msgid "Nitro challenge" -msgstr "אתגר גז־טורבו" +msgstr "אתגר גז טורבו" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:65 @@ -5042,7 +5036,7 @@ msgstr "זמן נדרש: %i" #: src/states_screens/race_result_gui.cpp:2138 #, c-format msgid "Required Nitro Points: %i" -msgstr "נקודות גז־טורבו נדרשות: %i" +msgstr "נקודות נדרשות של גז טורבו: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:109 @@ -5136,15 +5130,15 @@ msgstr "בקשת חברות אושרה!" #: src/states_screens/dialogs/user_info_dialog.cpp:273 msgid "Friend request declined!" -msgstr "בקשת החברות נדחתה!" +msgstr "בקשת החברות נדחתה." #: src/states_screens/dialogs/user_info_dialog.cpp:319 msgid "Friend removed!" -msgstr "הסרת את החבר/ה!" +msgstr "הסרת את החבר/ה." #: src/states_screens/dialogs/user_info_dialog.cpp:370 msgid "Friend request cancelled!" -msgstr "בקשת החברות בוטלה!" +msgstr "בקשת החברות בוטלה." #: src/states_screens/dialogs/user_info_dialog.cpp:480 msgid "Processing" @@ -5183,7 +5177,7 @@ msgstr "מסלול אקראי" #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" -msgstr "להסיר את \"%s\"?" +msgstr "להסיר את „%s”?" #: src/states_screens/edit_gp_screen.cpp:134 #: src/states_screens/edit_gp_screen.cpp:382 @@ -5206,11 +5200,11 @@ msgstr "%s (+)" #: src/states_screens/edit_gp_screen.cpp:330 msgid "An error occurred while trying to save your grand prix." -msgstr "אירעה שגיאה במהלך שמירת הגרנד־פרי." +msgstr "אירעה שגיאה במהלך שמירת סבב המרוצים." #: src/states_screens/edit_track_screen.cpp:255 msgid "Select a track" -msgstr "בחירת מסלול" +msgstr "נא לבחור מסלול" #: src/states_screens/feature_unlocked.cpp:254 #, c-format @@ -5233,7 +5227,7 @@ msgstr "השלמת את האתגר הקשה! הנקודות שצברת בשלב #, c-format msgid "" "You completed the SuperTux challenge! Points earned on this level: %i/%i" -msgstr "סיימת את אתגר SuperTux! הנקודות שצברת בשלב הזה: %i/%i" +msgstr "סיימת את אתגר הסופּר־טַקס! הנקודות שצברת בשלב הזה: %i/%i" #: src/states_screens/feature_unlocked.cpp:315 #, c-format @@ -5246,11 +5240,11 @@ msgstr "האתגר הושלם" #: src/states_screens/feature_unlocked.cpp:684 msgid "You unlocked track %0" -msgstr "שחררת את המסלול %0" +msgstr "פתחת את המסלול %0" #: src/states_screens/feature_unlocked.cpp:730 msgid "You unlocked grand prix %0" -msgstr "שחררת את הגרנד־פרי %0" +msgstr "נפתח סבב המרוצים %0" #: src/states_screens/ghost_replay_selection.cpp:153 msgctxt "column_name" @@ -5272,11 +5266,11 @@ msgstr "טעינה מחדש" #: src/states_screens/grand_prix_editor_screen.cpp:100 #: src/states_screens/grand_prix_editor_screen.cpp:117 msgid "Please enter the name of the grand prix" -msgstr "נא להזין את שם הגרנד־פרי" +msgstr "נא לתת שם לסבב המרוצים" #: src/states_screens/grand_prix_editor_screen.cpp:168 msgid "Please select a Grand Prix" -msgstr "נא לבחור גרנד־פרי" +msgstr "נא לבחור סבב מרוצים" #: src/states_screens/grand_prix_editor_screen.cpp:336 msgid "User defined" @@ -5288,11 +5282,11 @@ msgstr "נא להקליד שם." #: src/states_screens/grand_prix_editor_screen.cpp:357 msgid "Another grand prix with this name already exists." -msgstr "כבר קיים גרנד־פרי בשם הזה." +msgstr "כבר קיים סבב מרוצים בשם הזה." #: src/states_screens/grand_prix_editor_screen.cpp:363 msgid "Name is too long." -msgstr "שם ארוך מדי." +msgstr "השם ארוך מדי." #. I18N: when failing a GP #: src/states_screens/grand_prix_lose.cpp:157 @@ -5305,11 +5299,11 @@ msgstr "השלמת אתגר!" #: src/states_screens/grand_prix_win.cpp:324 msgid "You won the Grand Prix!" -msgstr "ניצחת בגרנד־פרי!" +msgstr "ניצחת בסבב המרוצים!" #: src/states_screens/grand_prix_win.cpp:325 msgid "You completed the Grand Prix!" -msgstr "השלמת את הגרנד־פרי!" +msgstr "השלמת את סבב המרוצים!" #: src/states_screens/high_score_selection.cpp:144 msgctxt "column_name" @@ -5322,11 +5316,11 @@ msgstr "להסיר את הערך הזה מטבלת השיאים?" #: src/states_screens/high_score_selection.cpp:360 msgid "Are you sure you want to remove all of your high scores?" -msgstr "להסיר את כל השיאים שלך?" +msgstr "להסיר את כל השיאים?" #: src/states_screens/kart_selection.cpp:447 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" -msgstr "למשחק מרובה משתתפים במסך מפוצל יש לחבר מקלדת או בקר משחק" +msgstr "לצורך משחק מרובה משתתפים במסך מפוצל, יש לחבר מקלדת או בקר משחק" #: src/states_screens/kart_selection.cpp:933 #: src/states_screens/kart_selection.cpp:1616 @@ -5342,7 +5336,7 @@ msgstr "נעול" msgid "" "Everyone:\n" "Press the 'Select' button to join the game" -msgstr "כולם:\nלחצו על כפתור \"בחירה\" כדי להצטרף למשחק" +msgstr "כולם:\nלחצו על כפתור הבחירה כדי להצטרף למשחק" #: src/states_screens/main_menu_screen.cpp:267 msgid "Would you like to play the tutorial of the game?" @@ -5353,7 +5347,7 @@ msgstr "להפעיל את ההדרכה של המשחק?" msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." -msgstr "אי אפשר לשחק ברשת ללא גישה לאינטרנט. אם ברצונך לשחק ברשת, נא להיכנס לתפריט האפשרויות, ולסמן את \"התחברות לאינטרנט\"." +msgstr "אי אפשר לשחק ברשת ללא גישה לאינטרנט. אם רוצים לשחק ברשת, יש לגשת לתפריט האפשרויות ולסמן את האפשרות „התחברות לאינטרנט”." #: src/states_screens/main_menu_screen.cpp:578 msgid "" @@ -5392,15 +5386,15 @@ msgstr "השרת של %s" #. I18N: In the create server screen #: src/states_screens/online/create_server_screen.cpp:215 msgid "No. of grand prix track(s)" -msgstr "כמות המסלול(ים) בגרנד־פרי" +msgstr "כמות המסלול(ים) בסבב המרוצים" #: src/states_screens/online/create_server_screen.cpp:298 msgid "Name has to be between 4 and 30 characters long!" -msgstr "אורך השם צריך להיות בין 4 ל־30 תווים!" +msgstr "על אורך השם להיות בין 4 ל־30 תווים!" #: src/states_screens/online/create_server_screen.cpp:315 msgid "Incorrect characters in password!" -msgstr "תווים שגויים בסיסמה!" +msgstr "ישנם תווים לא תקינים בסיסמה." #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server @@ -5412,7 +5406,7 @@ msgstr "מוכנים" #. to join the current started in-progress game #: src/states_screens/online/networking_lobby.cpp:198 msgid "Live join" -msgstr "הצטרפות בזמן־אמת" +msgstr "הצטרפות בזמן אמת" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game @@ -5438,7 +5432,7 @@ msgstr "נא להמתין עד סוף המשחק הנוכחי (%s), זמן נו #: src/states_screens/online/networking_lobby.cpp:551 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." -msgstr "נא להמתין עד הסוף המשחק הנוכחי, זמן נותר משוער: %s." +msgstr "נא להמתין עד הסוף המשחק הנוכחי, הזמן המשוער שנותר: %s." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in @@ -5467,7 +5461,6 @@ msgid_plural "Game will start if there are more than %d players." msgstr[0] "המשחק יתחיל אם יש יותר משחקן %d." msgstr[1] "המשחק יתחיל אם יש יותר מ־%d שחקנים." msgstr[2] "המשחק יתחיל אם יש יותר מ־%d שחקנים." -msgstr[3] "המשחק יתחיל אם יש יותר מ־%d שחקנים." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game @@ -5480,7 +5473,6 @@ msgid_plural "" msgstr[0] "מתחילים לאחר שנייה %d, או לאחר שכולם לחצו על כפתור \"מוכנים\"." msgstr[1] "מתחילים לאחר %d שניות, או לאחר שכולם לחצו על כפתור \"מוכנים\"." msgstr[2] "מתחילים לאחר %d שניות, או לאחר שכולם לחצו על כפתור \"מוכנים\"." -msgstr[3] "מתחילים לאחר %d שניות, או לאחר שכולם לחצו על כפתור \"מוכנים\"." #: src/states_screens/online/networking_lobby.cpp:698 #, c-format @@ -5548,11 +5540,11 @@ msgstr "על אורך כתובת הדוא״ל החדשה להיות בין 5 ל #: src/states_screens/online/online_profile_settings.cpp:93 msgid "New Email is invalid!" -msgstr "כתובת הדוא״ל החדשה בלתי־תקינה!" +msgstr "כתובת הדוא״ל החדשה אינה תקינה." #: src/states_screens/online/online_profile_settings.cpp:118 msgid "E-mail changed!" -msgstr "שונתה כתובת הדוא״ל!" +msgstr "כתובת הדוא״ל שונתה." #: src/states_screens/online/online_profile_settings.cpp:120 #, c-format @@ -5579,7 +5571,7 @@ msgstr "יציאה מהמשחק" #: src/states_screens/online/register_screen.cpp:289 #, c-format msgid "Could not create player '%s'." -msgstr "אי אפשר ליצור את השחקן/ית \"%s\"." +msgstr "אי אפשר ליצור את השחקן/ית „%s”." #: src/states_screens/online/register_screen.cpp:306 msgid "User name cannot be empty." @@ -5587,33 +5579,33 @@ msgstr "שדה שם המשתמש לא יכול להיות ריק." #: src/states_screens/online/register_screen.cpp:362 msgid "Online username and password must not be the same!" -msgstr "על שם המשתמש המקוון והסיסמה להיות שונים זה מזה!" +msgstr "על שם המשתמש המקוון והסיסמה להיות שונים זה מזה." #: src/states_screens/online/register_screen.cpp:366 msgid "Emails don't match!" -msgstr "כתובות הדוא״ל אינן תואמות!" +msgstr "כתובות הדוא״ל אינן תואמות." #: src/states_screens/online/register_screen.cpp:370 msgid "" "Online username can only contain alphanumeric (ASCII) characters, periods, " "dashes and underscores!" -msgstr "שם המשתמש המקוון יכול להכיל רק אותיות ומספרים (תווי ASCII), נקודות, קווים מפרידים ומקפים תחתונים!" +msgstr "שם המשתמש המקוון יכול להכיל רק אותיות ומספרים (תווי ASCII), נקודות, קווים מפרידים ומקפים תחתונים." #: src/states_screens/online/register_screen.cpp:374 msgid "Online username has to be between 3 and 30 characters long!" -msgstr "שם המשתמש המקוון צריך להיות בין 3 ל־30 תווים!" +msgstr "על אורך שם המשתמש המקוון להיות בין 3 ל־30 תווים." #: src/states_screens/online/register_screen.cpp:378 msgid "Online username must not start with a number!" -msgstr "שם משתמש מקוון אינו יכול להתחיל במספר!" +msgstr "שם המשתמש ברשת אינו יכול להתחיל במספר." #: src/states_screens/online/register_screen.cpp:386 msgid "Email has to be between 5 and 254 characters long!" -msgstr "על אורך כתובת הדוא״ל להיות בין 5 ל־254 תווים!" +msgstr "על אורך כתובת הדוא״ל להיות בין 5 ל־254 תווים." #: src/states_screens/online/register_screen.cpp:392 msgid "Email is invalid!" -msgstr "כתובת דוא״ל לא תקפה!" +msgstr "כתובת הדוא״ל אינה תקינה." #: src/states_screens/online/register_screen.cpp:456 msgid "" @@ -5623,7 +5615,7 @@ msgstr "יישלח אליך דואר אלקטרוני עם הוראות להפע #: src/states_screens/online/register_screen.cpp:495 msgid "Internet access is disabled, please enable it in the options" -msgstr "הגישה לאינטרנט מושבתת, נא להפעילה בתפריט האפשרויות" +msgstr "הגישה לאינטרנט מושבתת, נא להפעיל אותה בתפריט האפשרויות" #: src/states_screens/online/server_selection.cpp:132 msgctxt "column_name" @@ -5640,7 +5632,7 @@ msgstr "מצב משחק" #: src/states_screens/online/server_selection.cpp:140 msgctxt "column_name" msgid "Owner" -msgstr "בעלים" +msgstr "מנהל/ת" #. I18N: In server selection screen, distance to server #: src/states_screens/online/server_selection.cpp:142 @@ -5656,12 +5648,12 @@ msgstr "לא ידוע" #. I18N: Message shown to user if no IPv4 detected by STK #: src/states_screens/online/server_selection.cpp:363 msgid "No IPv4 detected, you may not be able to join any servers." -msgstr "לא זוהה IPv4, ייתכן שבכלל לא תהיה לך אפשרות להיכנס לשרתים." +msgstr "לא זוהה IPv4, ייתכן שלא יהיה אפשר כלל להתחבר לשרתים." #. I18N: Message shown to user if no IPv6 detected by STK #: src/states_screens/online/server_selection.cpp:365 msgid "No IPv6 detected, you may not be able to join any servers." -msgstr "לא זוהה IPv6, ייתכן שלא תהיה לך אפשרות להתחבר לשרתים כלל." +msgstr "לא זוהה IPv6, ייתכן שלא יהיה אפשר כלל להתחבר לשרתים." #: src/states_screens/online/server_selection.cpp:504 msgid "No server is available." @@ -5694,13 +5686,13 @@ msgstr "מיקום חפצים אקראי" #: src/states_screens/online/tracks_screen.cpp:504 #: src/states_screens/track_info_screen.cpp:455 msgid "Number of goals to win" -msgstr "מספר שערים לניצחון" +msgstr "מספר גולים עד לניצחון" #. I18N: In the track info screen #: src/states_screens/online/tracks_screen.cpp:552 #: src/states_screens/track_info_screen.cpp:298 msgid "Drive in reverse" -msgstr "נסיעה לאחור" +msgstr "נהיגה ברוורס" #: src/states_screens/online/tracks_screen.cpp:626 #: src/states_screens/tracks_and_gp_screen.cpp:296 @@ -5731,7 +5723,7 @@ msgstr "הפעלת ההתקן" #: src/states_screens/options/options_screen_device.cpp:127 #: src/states_screens/options/options_screen_device.cpp:633 msgid "Enable Configuration" -msgstr "אפשר הגדרה" +msgstr "לאפשר הגדרה" #. I18N: Key binding section #: src/states_screens/options/options_screen_device.cpp:176 @@ -5761,7 +5753,7 @@ msgstr "האצה" #. I18N: Key binding name #: src/states_screens/options/options_screen_device.cpp:275 msgid "Brake / Reverse" -msgstr "בלמים / נסיעה לאחור" +msgstr "בלמים / רוורס" #. I18N: Key binding name #: src/states_screens/options/options_screen_device.cpp:278 @@ -5771,7 +5763,7 @@ msgstr "ירייה" #. I18N: Key binding name #: src/states_screens/options/options_screen_device.cpp:281 msgid "Nitro" -msgstr "גז־טורבו" +msgstr "גז טורבו" #. I18N: Key binding name #: src/states_screens/options/options_screen_device.cpp:287 @@ -5786,7 +5778,7 @@ msgstr "חילוץ" #. I18N: Key binding name #: src/states_screens/options/options_screen_device.cpp:293 msgid "Pause Game" -msgstr "השהיית משחק" +msgstr "השהיית המשחק" #. I18N: Key binding name #: src/states_screens/options/options_screen_device.cpp:298 @@ -5820,23 +5812,23 @@ msgstr "ביטול/חזרה" #: src/states_screens/options/options_screen_device.cpp:404 msgid "* A blue item means a conflict with another configuration" -msgstr "* פריט כחול פירושו התנגשות עם תצורה אחרת" +msgstr "* פריט בצבע כחול מסמל סתירה של תצורה אחרת" #: src/states_screens/options/options_screen_device.cpp:409 msgid "* A red item means a conflict in the current configuration" -msgstr "* פריט אדום פירושו התנגשות עם התצורה הנוכחית" +msgstr "* פריט אדום מסמל סתירה בתצורה הנוכחית" #: src/states_screens/options/options_screen_device.cpp:514 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" " working." -msgstr "אזהרה: המקש \"Shift\" אינו מקש מומלץ. כאשר \"Shift\" לחוץ, כל המקשים הדו־מצביים יפסיקו לעבוד." +msgstr "אזהרה: לא מומלץ לבחור במקש „Shift”. כאשר „Shift” לחוץ, כל המקשים הדו־מצביים יפסיקו לעבוד." #. I18N: shown before deleting an input configuration #: src/states_screens/options/options_screen_device.cpp:613 msgid "Are you sure you want to permanently delete this configuration?" -msgstr "למחוק את ההגדרה הזאת לצמיתות?" +msgstr "למחוק הגדרה זו לצמיתות?" #: src/states_screens/options/options_screen_device.cpp:641 msgid "Enter new configuration name, leave empty to revert default value." @@ -5872,7 +5864,7 @@ msgstr "התקן מגע" #. I18N: In the input configuration screen, help for touch device #: src/states_screens/options/options_screen_input.cpp:207 msgid "Tap on a device to configure it" -msgstr "יש להקיש על התקן להגדרתו" +msgstr "יש להקיש על התקן כדי להגדירו" #. I18N: in the language choice, to select the same language as the OS #: src/states_screens/options/options_screen_language.cpp:90 @@ -5892,7 +5884,7 @@ msgstr "בצד ימין" #. I18N: In the UI options, minimap position in the race UI #: src/states_screens/options/options_screen_ui.cpp:99 msgid "Hidden" -msgstr "חבוי" +msgstr "מוסתר" #. I18N: In the UI options, minimap position in the race UI #: src/states_screens/options/options_screen_ui.cpp:101 @@ -5941,12 +5933,12 @@ msgid "" "Closing the game before the story mode's completion invalidates the timer.\n" "\n" "To use the speedrun mode, please use a new profile." -msgstr "אפשר להפעיל את מצב המשחק המהיר רק אם המשחק לא נסגר מאז הפעלת מצב העלילה לראשונה.\n\nסגירת מצב העלילה לפני השלמת מצב העלילה תבטל את קוצב הזמן.\n\nכדי להשתמש במצב המשחק המהיר, נא להשתמש בפרופיל חדש." +msgstr "אפשר להפעיל את מצב המשחק המהיר רק אם המשחק לא נסגר מאז הפעלת מצב העלילה לראשונה.\n\nסגירת המשחק לפני סיום מצב העלילה תבטל את קוצב הזמן.\n\nכדי להשתמש במצב המשחק המהיר, נא להשתמש בפרופיל חדש." #. I18N: In the video options #: src/states_screens/options/options_screen_video.cpp:259 msgid "Vertical Sync" -msgstr "סנכרון אנכי" +msgstr "סנכרון אנכי (Vsync)" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. @@ -5954,12 +5946,12 @@ msgstr "סנכרון אנכי" msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." -msgstr "Vsync מכריח את כרטיס המסך לספק מסגרת חדשה\nרק כאשר הצג מוכן להציגה." +msgstr "הסנכרון האנכי (Vsync) מכריח את כרטיס המסך\nלספק מסגרת חדשה רק כאשר הצג מוכן להציגה." #. I18N: in graphical options. #: src/states_screens/options/options_screen_video.cpp:279 msgid "Vsync will not work if your drivers don't support it." -msgstr "Vsync לא יעבוד אם מנהלי ההתקנים שלך לא תומכים בו." +msgstr "הסנכרון האנכי (Vsync) לא יפעל אם למנהלי ההתקנים שלך אין תמיכה בו." #. I18N: in graphical options #: src/states_screens/options/options_screen_video.cpp:681 @@ -5977,7 +5969,7 @@ msgstr "דמויות מונפשות: %s" #: src/states_screens/options/options_screen_video.cpp:690 #, c-format msgid "Dynamic lights: %s" -msgstr "אורות דינאמיים: %s" +msgstr "אורות דינמיים: %s" #. I18N: in graphical options #: src/states_screens/options/options_screen_video.cpp:693 @@ -5989,7 +5981,7 @@ msgstr "פיר אור: %s" #: src/states_screens/options/options_screen_video.cpp:696 #, c-format msgid "Anti-aliasing: %s" -msgstr "הפחתת מדרג עקומות: %s" +msgstr "החלקת עקומות: %s" #. I18N: in graphical options #: src/states_screens/options/options_screen_video.cpp:699 @@ -6040,11 +6032,11 @@ msgstr "טשטוש תנועה: %s" #: src/states_screens/options/options_screen_video.cpp:744 #, c-format msgid "Depth of field: %s" -msgstr "עומק שדה : %s" +msgstr "עומק שדה: %s" #: src/states_screens/options/user_screen.cpp:366 msgid "Internet access is disabled. Do you want to enable it?" -msgstr "הגישה לאינטרנט מושבתת. להפעילה?" +msgstr "הגישה לאינטרנט מושבתת. להפעיל אותה?" #: src/states_screens/options/user_screen.cpp:554 msgid "You need to enter a password." @@ -6053,12 +6045,12 @@ msgstr "יש להזין סיסמה." #: src/states_screens/options/user_screen.cpp:575 #, c-format msgid "Logging out '%s'" -msgstr "מתבצעת יציאה מחשבון \"%s\"" +msgstr "מתבצעת יציאה מחשבון „%s”" #: src/states_screens/options/user_screen.cpp:576 #, c-format msgid "Logging in '%s'" -msgstr "מתבצעת התחברות לחשבון \"%s\"" +msgstr "מתבצעת התחברות לחשבון „%s”" #: src/states_screens/options/user_screen.cpp:659 msgid "You can't delete the only player." @@ -6068,7 +6060,7 @@ msgstr "אי אפשר למחוק את השחקן/ית היחיד/ה." #: src/states_screens/options/user_screen.cpp:667 #, c-format msgid "Do you really want to delete player '%s'?" -msgstr "למחוק את \"%s\"?" +msgstr "למחוק את „%s”?" #. I18N: as in "ready, set, go", shown at the beginning of the race #: src/states_screens/race_gui_base.cpp:73 @@ -6088,7 +6080,7 @@ msgstr "צאו!" #. I18N: Shown when a goal is scored #: src/states_screens/race_gui_base.cpp:79 msgid "GOAL!" -msgstr "שער!" +msgstr "גול!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting @@ -6116,7 +6108,7 @@ msgstr "מאת" #: src/states_screens/race_gui_base.cpp:769 msgid "Collect nitro!" -msgstr "צאו לאסוף גז־טורבו!" +msgstr "צאו לאסוף גז טורבו!" #: src/states_screens/race_gui_base.cpp:771 msgid "Follow the leader!" @@ -6158,7 +6150,7 @@ msgstr "יציאה מהשרת" #: src/states_screens/race_result_gui.cpp:310 msgid "Abort Grand Prix" -msgstr "נטישת הגרנד־פרי" +msgstr "נטישת סבב המרוצים" #: src/states_screens/race_result_gui.cpp:330 msgid "Restart" @@ -6178,7 +6170,7 @@ msgstr "חזרה לתפריט" #: src/states_screens/race_result_gui.cpp:536 msgid "Do you really want to abort the Grand Prix?" -msgstr "לנטוש את הגרנד־פרי?" +msgstr "לנטוש את סבב המרוצים?" #: src/states_screens/race_result_gui.cpp:636 #: src/states_screens/race_result_gui.cpp:1529 @@ -6193,7 +6185,7 @@ msgstr "הניצחון בידי הקבוצה הכחולה" #: src/states_screens/race_result_gui.cpp:640 #: src/states_screens/race_result_gui.cpp:1538 msgid "It's a draw" -msgstr "זה תיקו" +msgstr "זהו תיקו" #: src/states_screens/race_result_gui.cpp:881 #, c-format @@ -6209,7 +6201,7 @@ msgstr "נפסל/ה" #: src/states_screens/race_result_gui.cpp:1608 #: src/states_screens/race_result_gui.cpp:1670 msgid "(Own Goal)" -msgstr "(שער עצמי)" +msgstr "(גול עצמי)" #: src/states_screens/race_result_gui.cpp:1749 #, c-format @@ -6218,7 +6210,7 @@ msgstr "מסלול %i/%i" #: src/states_screens/race_result_gui.cpp:1833 msgid "Grand Prix progress:" -msgstr "התקדמות בגרנד־פרי:" +msgstr "התקדמות בסבב המרוצים:" #: src/states_screens/race_result_gui.cpp:1879 msgid "Highscores" @@ -6246,7 +6238,7 @@ msgstr "נכשלת באתגר!" #: src/states_screens/race_result_gui.cpp:2155 msgid "Reached Requirements of SuperTux" -msgstr "הגעת לדרישות של סופר־טַקס" +msgstr "הגעת ליכולות הנחוצות לרמת סופר־טַקס" #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" @@ -6267,11 +6259,11 @@ msgstr "יש לתקוף אחרים בעזרת הנשקים עד שייגמרו #: src/states_screens/race_setup_screen.cpp:120 msgid "Push the ball into the opposite cage to score goals." -msgstr "יש לדחוף את הכדור לכלוב הנגדי כדי להבקיע לשער." +msgstr "יש לדחוף את הכדור לעבר השער הנגדי בשביל להבקיע גול." #: src/states_screens/race_setup_screen.cpp:130 msgid "Explore tracks to find all hidden eggs" -msgstr "יש לסיירו במסלולים ומצאו את כל הביצים הנסתרות" +msgstr "יש לסייר במסלולים ולמצוא את כל הביצים הנסתרות" #: src/states_screens/race_setup_screen.cpp:138 msgid "Race against ghost karts and try to beat them!" @@ -6279,7 +6271,7 @@ msgstr "יש להתחרות נגד מכוניות רפאים ולנסות לעק #: src/states_screens/race_setup_screen.cpp:143 msgid "Complete as many laps as possible in a given amount of time." -msgstr "יש להשלים כמה שיותר הקפות בזמן שנקבע." +msgstr "השלמה של כמה שיותר הקפות בזמן נתון." #. I18N: In soccer setup screen #: src/states_screens/soccer_setup_screen.cpp:120 @@ -6291,7 +6283,7 @@ msgstr "לחצו על סמל כדורגל אדום או כחול כדי לשנו #: src/states_screens/track_info_screen.cpp:149 #, c-format msgid "Track by %s" -msgstr "המסלול מאת %s" +msgstr "מסלול מאת %s" #. I18N: the max players supported by an arena. #: src/states_screens/track_info_screen.cpp:157 @@ -6307,7 +6299,7 @@ msgstr "מספר המתחרים המדומים בקבוצה האדומה" msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" -msgstr "אין לך אפשרות לשחק בגרנד־פרי הזה בגלל שהוא מכיל מסלולים שעדיין לא שחררת." +msgstr "אי אפשר לשחק בסבב המרוצים הזה מכיוון שהוא מכיל מסלולים שלא נפתחו עדיין." #: src/states_screens/tracks_and_gp_screen.cpp:217 msgid "Locked!" @@ -6357,7 +6349,7 @@ msgstr "יש להאיץ בעזרת לחיצה על החלק העליון של ה msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." -msgstr "יש להאיץ בעזרת הרמת דוושת ההאצה, ואפשר להטות את ההתקן כדי לִפנות." +msgstr "יש להאיץ בעזרת הרמת דוושת ההאצה, ואפשר להטות את המכשיר לצדדים בשביל לפנות." #: ../stk-assets/tracks/tutorial/scripting.as:27 msgid "" @@ -6375,7 +6367,7 @@ msgstr "אפשר לאסוף קופסאות מתנה, ולירות את כלי ה msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" -msgstr "אפשר לאסוף קופסאות מתנה, ולירות את כלי הנשק באמצעות סמל כדור הכדורת כדי להעיף את הארגזים מכאן!" +msgstr "אפשר לאסוף קופסאות מתנה, ולירות את כלי הנשק באמצעות סמל כדור הבאולינג כדי להעיף את הארגזים מכאן!" #: ../stk-assets/tracks/tutorial/scripting.as:78 #, c-format @@ -6388,29 +6380,29 @@ msgstr "אפשר ללחוץ על <%s> כדי להסתכל לאחור.\nאפשר msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" -msgstr "אפשר ללחוץ על סמל המראה כדי להסתכל לאחור.\nאפשר לירות את כלי הנשק לאחור באמצעות החזקת סמל המראה לחוץ ואז לחיצה על סמל כדור הכדורת!" +msgstr "אפשר ללחוץ על סמל המראה כדי להסתכל לאחור.\nאפשר לירות את כלי הנשק לאחור באמצעות החזקת סמל המראה לחוץ ואז לחיצה על סמל כדור הבאולינג!" #: ../stk-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" -msgstr "אפשר להשתמש בגז־טורבו שצברת בלחיצה על <%s>!" +msgstr "אפשר להשתמש בגז הטורבו שצברת בלחיצה על <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" -msgstr "אפשר להשתמש בגז־טורבו שצברת בלחיצה על סמל הגז־טורבו" +msgstr "אפשר להשתמש בגז הטורבו שצברת בעזרת לחיצה על סמל של גז הטורבו" #: ../stk-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." -msgstr "יש לאסוף בקבוקי גז־טורבו (נשתמש בהם לאחר העקומה)." +msgstr "כעת יש לאסוף בקבוקי גז טורבו (נשתמש בהם לאחר העקומה)." #: ../stk-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." -msgstr "אופס! בעת צרה, לחיצה על <%s> תחלץ אותך." +msgstr "אופס! אם נקלעת לצרה, לחיצה על <%s> תחלץ אותך." #: ../stk-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." -msgstr "אופס! בעת צרה, לחיצה על סמל הציפור תחלץ אותך." +msgstr "אופס! אם נקלעת לצרה, לחיצה על סמל הציפור תחלץ אותך." #: ../stk-assets/tracks/tutorial/scripting.as:137 #, c-format @@ -6429,7 +6421,7 @@ msgstr "יש להאיץ וללחוץ על סמל ההחלקה תוך כדי סי msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" -msgstr "שימו לב שאם תצליחו להחליק למשך מספר שניות, תקבלו האצה נוספת כפרס!" +msgstr "לתשומת ליבך, אם מצליחים להחליק למשך כמה שניות, מקבלים האצה נוספת בתור פרס!" #: ../stk-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" @@ -6439,7 +6431,7 @@ msgstr "עברת בהצלחה את ההכשרה למרוץ. בהצלחה!" #. description in Google Play #: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 msgid "A 3D open-source kart racing game" -msgstr "משחק מֵרוצי מכוניות בתלת־ממד ובקוד פתוח" +msgstr "משחק תלת־ממדי בקוד פתוח של מֵרוצי מכוניות" #. I18N: Keywords in desktop entry, translators please keep it separated with #. semicolons @@ -6453,7 +6445,7 @@ msgid "" "variety of characters, tracks, and modes to play. Our aim is to create a " "game that is more fun than realistic, and provide an enjoyable experience " "for all ages." -msgstr "מכוניות. גז־טורבו. אקשן! SuperTuxKart הוא משחק ארקייד של תחרויות מרוץ בתלת־ממד ובקוד פתוח עם מגוון דמויות, מסלולים, ומצבים למשחק. מטרתנו ליצור משחק מהנה יותר מהמציאות, ולספק חוויה מהנה לכל הגילים." +msgstr "מכוניות. גז טורבו. אקשן! SuperTuxKart הוא משחק ארקייד תלת־ממדי בקוד פתוח של תחרויות מרוץ עם מגוון דמויות, מסלולים, ומצבים למשחק. מטרתנו ליצור משחק מהנה יותר מהמציאות, ולספק חוויה מהנה לכל הגילאים." #: supertuxkart.appdata.xml:11 msgid "" @@ -6462,7 +6454,7 @@ msgid "" " while avoiding other karts as they may overtake you, but don't eat the " "bananas! Watch for bowling balls, plungers, bubble gum, and cakes thrown by " "your opponents." -msgstr "יש לנו כמה מסלולים במגוון נושאים שהשחקנים יכולים ליהנות מהם, החל מצלילה במצולות, חוות חקלאיות, ג׳ונגלים, ועד לחלל! במשחק יש לנסוע במיטב יכולתך תוך הימנעות ממכוניות אחרות שעלולות לעקוף אותך, ולא לאכול את הבננות! אפשר לצפות בכדורי כדורת, פומפות, גומי לעיסה, ועוגות שזורקים היריבים שלך." +msgstr "יש לנו כמה מסלולים במגוון נושאים שהשחקנים יכולים ליהנות מהם, החל מצלילה במצולות, חוות חקלאיות, ג׳ונגלים, ועד לחלל! במשחק יש לנסוע במיטב יכולתך תוך הימנעות ממכוניות אחרות שעלולות לעקוף אותך, ולא לאכול את הבננות! אפשר לצפות בכדורי באולינג, פומפות, גומי לעיסה, ועוגות שזורקים היריבים שלך." #: supertuxkart.appdata.xml:14 msgid "" @@ -6471,7 +6463,7 @@ msgid "" "battle mode against the computer or your friends, and more! For a greater " "challenge, join online and meet players from all over the world and prove " "your racing skills!" -msgstr "אפשר להתחרות במרוץ בודד נגד מכוניות אחרות, להתמודד באחד מכמה גרנד־פרי, לנסות לשבור את השיא שלך לבד בְּמרוץ נגד השעון, לשחק במצב קרב מול המחשב או החברים, ועוד! אתגר גדול יותר: להצטרף לְמרוץ ברשת ולפגוש שחקנים מכל רחבי העולם ולהוכיח את כישורי המרוץ שלך!" +msgstr "אפשר להתחרות במרוץ בודד נגד מכוניות אחרות, להתחרות באחד מסבבי המרוצים, לנסות לשבור את השיא שלך לבד במרוץ נגד השעון, לשחק במצב קרב מול המחשב או החברים, ועוד! אתגר גדול יותר: להצטרף למרוץ ברשת, לפגוש שחקנים מכל רחבי העולם ולהוכיח את כישורי המרוץ שלך!" #: supertuxkart.appdata.xml:17 msgid "This game has no ads." @@ -6482,13 +6474,13 @@ msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." -msgstr "זוהי גרסה בלתי־יציבה של SuperTuxKart שמכילה את השיפורים החדשים. היא פורסמה בעיקר למטרת בדיקה, כדי לשפר את SuperTuxKart ככל שאפשר." +msgstr "זוהי גרסה לא יציבה של SuperTuxKart, המכילה את השיפורים החדשים ביותר. היא פורסמה בעיקר למטרות בדיקה, בשביל לוודא שהגרסה היציבה של SuperTuxKart תהיה טובה ככל האפשר." #: supertuxkart.appdata.xml:23 msgid "" "This version can be installed in parallel with the stable version on the " "device." -msgstr "אפשר להתקין את הגרסה הזאת במקביל לגרסה שמותקנת על ההתקן." +msgstr "ניתן להתקין גרסה זו על המכשיר במקביל לגרסה היציבה." #: supertuxkart.appdata.xml:26 msgid "If you need more stability, consider using the stable version: %s" diff --git a/data/po/hr.po b/data/po/hr.po index b58fdad80b9..4fb4f411ab0 100644 --- a/data/po/hr.po +++ b/data/po/hr.po @@ -4,7 +4,7 @@ # # Translators: # Aleksandra Kurda, 2022 -# Aleksandra Kurda, 2022 +# f54d4d2f4a87a54e50d75d6c658a5020_cea22be <13d8e250d37cead4c2a433f71830c9a5_1045958>, 2022 # Ivan Putnik , 2010 # vjeran fistric , 2020 msgid "" diff --git a/data/po/id.po b/data/po/id.po index dd098021544..f33b7b2cd7b 100644 --- a/data/po/id.po +++ b/data/po/id.po @@ -5,17 +5,17 @@ # Translators: # Adzka - <4dzka.m.ivi@gmail.com>, 2021 # Ai_ZAQraven , 2021-2022 -# liimee , 2021 -# Christian Elbrianno , 2017 +# liimee , 2021 +# Chris , 2017 # Christian Elbrianno, 2017 -# Christian Elbrianno , 2023 -# Christian Elbrianno , 2017 +# Chris , 2023 +# Chris , 2017 # Christian Elbrianno Yoga, 2017 # Dito Kurnia Pratama , 2019 # FIRST AUTHOR , 2011 # Icho Yulian Chandra , 2016 # Iwan Rahardi Putra , 2017 -# liimee , 2021 +# liimee , 2021 # Raja Sulaiman , 2017 # Triyan W. Nugroho , 2020 # Ai_ZAQraven , 2020-2021 @@ -25,7 +25,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Christian Elbrianno , 2023\n" +"Last-Translator: Chris , 2023\n" "Language-Team: Indonesian (http://app.transifex.com/supertuxkart/supertuxkart/language/id/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/data/po/is.po b/data/po/is.po index 82f67d6d2b9..f3550d4373a 100644 --- a/data/po/is.po +++ b/data/po/is.po @@ -6,13 +6,14 @@ # 111more1, 2022 # FIRST AUTHOR , 2010 # IAN RODRÍGUEZ Lorenzo, 2022 +# Tómas Helgason, 2024 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: 111more1, 2022\n" +"Last-Translator: Tómas Helgason, 2024\n" "Language-Team: Icelandic (http://app.transifex.com/supertuxkart/supertuxkart/language/is/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -22,53 +23,53 @@ msgstr "" #. I18N: In Android UI, po_extract_game_data msgid "Extracting game data..." -msgstr "" +msgstr "Vinnur úr leikjagögnum..." #. I18N: In Android UI, po_extract_error msgid "Game data extraction error" -msgstr "" +msgstr "Villa kom upp við útdrátt á leikjagögnum" #. I18N: In Android UI, po_extract_error_msg msgid "Check remaining device space or reinstall SuperTuxKart." -msgstr "" +msgstr "Skoðaðu laust Geymslurými eftir eða endursettu SuperTuxKart." #. I18N: In Android UI, po_quit #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen msgid "Quit" -msgstr "" +msgstr "Hætta" #. I18N: ./data/achievements.xml msgid "Christoffel Columbus" -msgstr "" +msgstr "Kristófer Kólumbus" #. I18N: ./data/achievements.xml msgid "Play every official track at least once." -msgstr "" +msgstr "Spilaðu allar opinbera brautir að minnsta kosti einu sinni." #. I18N: ./data/achievements.xml msgid "Strike!" -msgstr "" +msgstr "Slag!" #. I18N: ./data/achievements.xml msgid "Hit 10 karts with a bowling-ball." -msgstr "" +msgstr "hittu 10 karts með keilukúlu." #. I18N: ./data/achievements.xml msgid "Arch Enemy" -msgstr "" +msgstr "Erkióvinur" #. I18N: ./data/achievements.xml msgid "Hit the same kart at least 5 times in one race." -msgstr "" +msgstr "Hittu sama kartinn að minnsta kosti 5 sinnum í röð í einni keppni." #. I18N: ./data/achievements.xml msgid "Marathoner" -msgstr "" +msgstr "Maraþonari" #. I18N: ./data/achievements.xml msgid "Finish a race with at least twice the track's default lap number." -msgstr "" +msgstr "Kláraðu keppni með að minnsta kosti tvöfald sjálgefna hringfjölda brautarinnar." #. I18N: ./data/achievements.xml msgid "Skid-row" @@ -76,7 +77,7 @@ msgstr "" #. I18N: ./data/achievements.xml msgid "Skid 5 times in a single lap." -msgstr "" +msgstr "Skransaðu 5 sinnum í einum hring." #. I18N: ./data/achievements.xml msgid "Gold driver" @@ -86,77 +87,77 @@ msgstr "" msgid "" "Win against at least 3 AIs in normal race, time-trial, and follow the " "leader." -msgstr "" +msgstr "Sigraðu á móti að minnsta kosti 3 gervigreindum í venjulegum kappakstri, tímatöku og fylgdu leiðtogan." #. I18N: ./data/achievements.xml msgid "Powerup Love" -msgstr "" +msgstr "Powerup Ást" #. I18N: ./data/achievements.xml msgid "Use 10 or more powerups in a race." -msgstr "" +msgstr "Notaðu 10 eða fleiri powerups í keppni." #. I18N: ./data/achievements.xml msgid "Unstoppable" -msgstr "" +msgstr "Óstöðvandi" #. I18N: ./data/achievements.xml msgid "" "Win 5 single races in a row against at least 3 AIs. Beware, restarting a " "race counts as a loss." -msgstr "" +msgstr "Sigraðu 5 stakar keppnir í röð á móti að minnsta kosti 3 Gervigreindum. Hafðu í huga að endurtökur á keppnum tells sem tap. " #. I18N: ./data/achievements.xml msgid "Banana Lover" -msgstr "" +msgstr "Banana elskhugi" #. I18N: ./data/achievements.xml msgid "Collect at least 5 bananas in one race." -msgstr "" +msgstr "Safnaðu að minnsta kosti 5 bönunum í einni keppni." #. I18N: ./data/achievements.xml msgid "It's secret" -msgstr "" +msgstr "Það er leyndarmál" #. I18N: ./data/achievements.xml msgid "Really ... a secret." -msgstr "" +msgstr "Virkilega ... leyndarmál." #. I18N: ./data/achievements.xml msgid "Mosquito Hunter" -msgstr "" +msgstr "Moskító veiðimaður" #. I18N: ./data/achievements.xml msgid "" "Take your opponents for mosquitos! With the swatter, squash them at least 5 " "times in a race." -msgstr "" +msgstr "Taktu andstæðinga þína fyrir moskítóflugur! Krembdu þá að minnsta kosti 5 sinnum með flugnaspaða í keppni." #. I18N: ./data/achievements.xml msgid "Beyond Luck" -msgstr "" +msgstr "Handan heppni" #. I18N: ./data/achievements.xml msgid "" "Win 10 single races in a row in Expert or SuperTux against at least 5 AIs. " "Beware, restarting a race counts as a loss." -msgstr "" +msgstr "Sigraðu 10 stakar keppnir í röð á móti að minnsta kosti 5 Gervigreindum á Erfitt eða SuperTux Erfiðleikastigi. Hafðu í huga að endurtökur á keppnum tells sem tap. " #. I18N: ./data/grandprix/1_penguinplayground.grandprix msgid "Penguin Playground" -msgstr "" +msgstr "Mörgæsa Leikvöllur" #. I18N: ./data/grandprix/2_offthebeatentrack.grandprix msgid "Off the Beaten Track" -msgstr "" +msgstr "Utan alfaraleið" #. I18N: ./data/grandprix/3_tothemoonandback.grandprix msgid "To the Moon and Back" -msgstr "" +msgstr "Til tunglsins og til baka" #. I18N: ./data/grandprix/4_atworldsend.grandprix msgid "At World's End" -msgstr "" +msgstr "Á enda heimsins" #. I18N: ./data/gui/dialogs/addons_loading.stkgui #. I18N: Add-on screen action @@ -171,21 +172,21 @@ msgstr "" #: src/input/gamepad_config.cpp:157 #: src/states_screens/dialogs/addons_loading.cpp:303 msgid "Back" -msgstr "" +msgstr "Til baka" #. I18N: ./data/gui/dialogs/addons_loading.stkgui #. I18N: Add-on screen action msgid "Install" -msgstr "" +msgstr "Uppsettu" #. I18N: ./data/gui/dialogs/addons_loading.stkgui #. I18N: Add-on screen action msgid "Uninstall" -msgstr "" +msgstr "Fjarlægðu" #. I18N: ./data/gui/dialogs/android/init_android.stkgui msgid "Select a type of control that you prefer" -msgstr "" +msgstr "Veldu tengund af fjarstýringu sem þú hyggist" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type @@ -193,7 +194,7 @@ msgstr "" #. I18N: In the multitouch settings screen #: src/states_screens/dialogs/race_paused_dialog.cpp:549 msgid "Accelerometer" -msgstr "" +msgstr "Hröðunarmælir" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type @@ -207,23 +208,23 @@ msgstr "" #. I18N: Race paused button #: src/states_screens/dialogs/race_paused_dialog.cpp:554 msgid "Gyroscope" -msgstr "" +msgstr "Gyroscope" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type #: src/states_screens/dialogs/race_paused_dialog.cpp:544 msgid "Steering wheel" -msgstr "" +msgstr "Stýrihjól" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Auto acceleration" -msgstr "" +msgstr "Sjálfvirk hröðun" #. I18N: ./data/gui/dialogs/android/init_android.stkgui msgid "You can change it later in touch device settings." -msgstr "" +msgstr "Þú getur breytt því seinna í snertitækja stillingum." #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui @@ -234,11 +235,11 @@ msgstr "" #. I18N: ./data/gui/dialogs/kart_color_slider.stkgui #. I18N: In the kart color slider dialog msgid "Apply" -msgstr "" +msgstr "Nota" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui msgid "Touch Device Settings" -msgstr "" +msgstr "Snertitækja Stillingar" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -273,46 +274,46 @@ msgstr "" #. I18N: ./data/gui/screens/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" -msgstr "" +msgstr "Almennt" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Device enabled" -msgstr "" +msgstr "Tækið er virkt" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Inverted buttons" -msgstr "" +msgstr "Öfugir hnappar" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Buttons scale" -msgstr "" +msgstr "Hnappa kvarði" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Advanced" -msgstr "" +msgstr "Ítarleg" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Deadzone" -msgstr "" +msgstr "Deadzone" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Sensitivity X" -msgstr "" +msgstr "Næmi X ás" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Sensitivity Y" -msgstr "" +msgstr "Næmi Y ás" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui msgid "Restore defaults" -msgstr "" +msgstr "Endurheimtu sjálgefnar breytur" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog @@ -354,7 +355,7 @@ msgstr "" #: src/states_screens/online/register_screen.cpp:168 #: src/states_screens/options/user_screen.cpp:128 msgid "Cancel" -msgstr "" +msgstr "Hætta við" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog @@ -364,13 +365,13 @@ msgstr "" #: src/states_screens/ghost_replay_selection.cpp:388 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" -msgstr "" +msgstr "Já" #. I18N: ./data/gui/dialogs/confirm_resolution_dialog.stkgui #. I18N: In the 'confirm resolution' dialog, that's shown when switching #. resoluton msgid "Revert" -msgstr "" +msgstr "Afturkalla" #. I18N: ./data/gui/dialogs/confirm_resolution_dialog.stkgui #. I18N: In the 'confirm resolution' dialog, that's shown when switching @@ -378,31 +379,31 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog msgid "Accept" -msgstr "" +msgstr "Samþykkja" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui msgid "Camera Settings" -msgstr "" +msgstr "Myndavéla stillingar" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera settings msgid "Player camera" -msgstr "" +msgstr "Myndarvél leikmans" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "FOV" -msgstr "" +msgstr "Sjónsvið" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "Distance" -msgstr "" +msgstr "Fjarlægð" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "Angle" -msgstr "" +msgstr "Horn" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -766,7 +767,7 @@ msgstr "" #. I18N: Difficulty #: src/race/race_manager.cpp:1309 msgid "Novice" -msgstr "" +msgstr "Létt" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: Difficulty @@ -778,7 +779,7 @@ msgstr "" #. I18N: Difficulty #: src/race/race_manager.cpp:1310 msgid "Intermediate" -msgstr "" +msgstr "Venjulegt" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: Difficulty @@ -790,7 +791,7 @@ msgstr "" #. I18N: Difficulty #: src/race/race_manager.cpp:1311 msgid "Expert" -msgstr "" +msgstr "Erfitt" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: Difficulty diff --git a/data/po/it.po b/data/po/it.po index a4b10e1aa7b..b9f560fdc81 100644 --- a/data/po/it.po +++ b/data/po/it.po @@ -8,7 +8,7 @@ # Davide Depau , 2015 # Enrico B. , 2015 # Enrico B. , 2015 -# Giuseppe Pignataro , 2015 +# Giuseppe Pignataro (Fastbyte01) , 2015 # Ioma Taani, 2016,2018 # Ioma Taani, 2019-2023 # Ioma Taani, 2016,2018 @@ -16,8 +16,9 @@ # Lorenzo , 2015 # Luca Argentieri , 2015 # Luca Argentieri , 2015 +# Machinari Utens, 2023 # Massimo Gismondi , 2021 -# mattia_b89 , 2017,2019-2020 +# mattia_b89 , 2017,2019-2020,2023 # mimiz skindoor, 2020-2023 # Massimo Gismondi , 2019-2020 # Ioma Taani, 2018-2021 @@ -32,7 +33,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: mimiz skindoor, 2020-2023\n" +"Last-Translator: Machinari Utens, 2023\n" "Language-Team: Italian (http://app.transifex.com/supertuxkart/supertuxkart/language/it/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -106,7 +107,7 @@ msgstr "Pilota d'oro" msgid "" "Win against at least 3 AIs in normal race, time-trial, and follow the " "leader." -msgstr "Vinci contro almeno 3 IA in gare \"prova a tempo\" e/o \"segui il leader\"." +msgstr "Vinci contro almeno 3 IA in gare normali, \"prova a tempo\" e/o \"segui il leader\"." #. I18N: ./data/achievements.xml msgid "Powerup Love" @@ -132,7 +133,7 @@ msgstr "Amante delle banane" #. I18N: ./data/achievements.xml msgid "Collect at least 5 bananas in one race." -msgstr "Raccogli almeno 5 banane in una gara" +msgstr "Raccogli almeno 5 banane in una gara." #. I18N: ./data/achievements.xml msgid "It's secret" @@ -140,7 +141,7 @@ msgstr "È un segreto" #. I18N: ./data/achievements.xml msgid "Really ... a secret." -msgstr "Davvero... un segreto" +msgstr "Davvero... un segreto." #. I18N: ./data/achievements.xml msgid "Mosquito Hunter" @@ -150,7 +151,7 @@ msgstr "Cacciatore di zanzare" msgid "" "Take your opponents for mosquitos! With the swatter, squash them at least 5 " "times in a race." -msgstr "I tuoi avversari sono zanzare! Schiaccia almeno 5 avversari in una gara con l'acchiappamosche. " +msgstr "Tratta i tuoi avversari come fossero zanzare! Schiacciali almeno 5 volte in una gara con l'acchiappamosche." #. I18N: ./data/achievements.xml msgid "Beyond Luck" @@ -160,7 +161,7 @@ msgstr "Oltre la fortuna" msgid "" "Win 10 single races in a row in Expert or SuperTux against at least 5 AIs. " "Beware, restarting a race counts as a loss." -msgstr "Vinci 10 gare singole in serie in difficoltà Esperto o SuperTux contro almeno 5 IA. Attenzione: ricominciare la gara conta come una sconfitta." +msgstr "Vinci 10 gare singole di fila in difficoltà Esperto o SuperTux contro almeno 5 IA. Attenzione, ricominciare la gara conta come una sconfitta." #. I18N: ./data/grandprix/1_penguinplayground.grandprix msgid "Penguin Playground" @@ -332,7 +333,7 @@ msgstr "Sensitività Y" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui msgid "Restore defaults" -msgstr "Ripristina impostazione " +msgstr "Ripristina impostazioni" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog @@ -384,7 +385,7 @@ msgstr "Annulla" #: src/states_screens/ghost_replay_selection.cpp:388 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" -msgstr "Si" +msgstr "Sì" #. I18N: ./data/gui/dialogs/confirm_resolution_dialog.stkgui #. I18N: In the 'confirm resolution' dialog, that's shown when switching @@ -653,7 +654,7 @@ msgstr "Conferma" #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog msgid "Submit" -msgstr "Manda" +msgstr "Invia" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button @@ -670,7 +671,7 @@ msgstr "Esci dal server" #. I18N: Show in network ingame dialog to allow user to go back to lobby to #. end spectating (for example) msgid "Back to lobby" -msgstr "Torna alla sala d'attesa." +msgstr "Torna alla sala d'attesa" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button @@ -762,7 +763,7 @@ msgstr "Termini e condizioni" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog msgid "I agree to the above terms and am 13 years or older. " -msgstr "Accetto i termini e dichiaro di avere più di 13 anni." +msgstr "Accetto i termini e dichiaro di avere almeno 13 anni." #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: In the server configuration screen @@ -931,7 +932,7 @@ msgstr "Informazioni utente" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Rimuovi amicizia" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -941,17 +942,17 @@ msgstr "Aggiungi amico" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Accetta l'invito" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Rifiuta l'invito" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Visualizza il profilo" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1139,7 +1140,7 @@ msgstr "Riconoscimenti" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Salta" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1153,7 +1154,7 @@ msgstr "Tutte le piste" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Title in edit grand prix screen msgid "Edit Grand Prix" -msgstr "Modifica Gran premio" +msgstr "Modifica Gran Premio" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item @@ -1269,12 +1270,12 @@ msgstr "Gruppo di piste" #. I18N: In the grand prix info screen #: src/states_screens/gp_info_screen.cpp:164 msgid "Continue saved GP" -msgstr "Continua il Gran premio salvato" +msgstr "Continua il Gran Premio salvato" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Title in grand prix editor screen msgid "Grand Prix editor" -msgstr "Editor gran premio" +msgstr "Editor Gran Premio" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item @@ -1299,7 +1300,7 @@ msgstr "Rinomina" #. I18N: ./data/gui/screens/grand_prix_lose.stkgui #. I18N: ./data/gui/screens/grand_prix_win.stkgui msgid "Save Grand Prix" -msgstr "Salva Gran premio" +msgstr "Salva Gran Premio" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: ./data/gui/screens/help2.stkgui @@ -1465,7 +1466,7 @@ msgstr "Puoi avere un bonus velocità alla partenza premendo il pulsante per acc #. I18N: ./data/gui/screens/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" -msgstr "La configurazione dei tasti può essere controllata o personalizzata nel menu Opzioni" +msgstr "* La configurazione dei tasti può essere controllata o personalizzata nel menu Opzioni" #. I18N: ./data/gui/screens/help2.stkgui msgid "SuperTuxKart features several game modes:" @@ -1475,7 +1476,7 @@ msgstr "SuperTuxKart ha differenti modalità di gioco:" #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" -msgstr "Gara: tutte le armi presenti possono essere utilizzate, quindi usale con intelligenza!" +msgstr "Gara normale: tutte le armi presenti possono essere utilizzate, quindi usale con intelligenza!" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1488,7 +1489,7 @@ msgid "" "Follow the leader: Run for second place, as the last kart will be " "disqualified every time the counter hits zero. Beware: going in front of the" " leader will get you eliminated too!" -msgstr "Insegui il leader: gareggia per il secondo posto, l'ultimo kart verrà squalificato ogni volta che il contatore raggiunge lo zero. Attenzione: anche superando il leader verrai eliminato! " +msgstr "Segui il Leader: gareggia per il secondo posto, l'ultimo kart verrà squalificato ogni volta che il contatore raggiunge lo zero. Attenzione: anche superando il leader verrai eliminato!" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1503,7 +1504,7 @@ msgstr "Per la battaglia ci sono tre tipi di modalità: In \"Battaglia a tre col #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." -msgstr "Calcio: usa il kart per spingere la palla in rete." +msgstr "Calcio: usa il kart per spingere la palla nella rete." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1530,7 +1531,7 @@ msgid "" "instead of playing a single race, you play many in a row. The better you " "rank, the more points you get. In the end, the player with the most points " "wins the cup." -msgstr "* Molte di queste modalità di gioco possono essere anche giocate in stile Grand Prix: invece di gareggiare in gara singola è possibile giocarne diverse in serie. Migliore è il tuo posto in classifica, maggiori saranno i punti ricevuti. Alla fine il giocatore con più punti vincerà la coppa." +msgstr "* Molte di queste modalità di gioco possono essere anche giocate in stile Gran Premio: invece di gareggiare in gara singola è possibile giocarne diverse in serie. Migliore è il tuo posto in classifica, maggiori saranno i punti ricevuti. Alla fine il giocatore con più punti vincerà la coppa." #. I18N: ./data/gui/screens/help3.stkgui #. I18N: In the help menu @@ -1593,7 +1594,7 @@ msgstr "Acchiappamosche - schiaccia i kart vicini rallentandoli. Può essere uti msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" -msgstr "Colpire una banana potraà agganciare al tuo kart uno di questi oggetti:" +msgstr "Colpire una banana potrà agganciare al tuo kart uno di questi oggetti:" #. I18N: ./data/gui/screens/help4.stkgui #. I18N: In the help menu @@ -1759,7 +1760,7 @@ msgstr "Giro di prova" #: src/states_screens/dialogs/select_challenge.cpp:51 #: src/states_screens/high_score_selection.cpp:136 msgid "Grand Prix" -msgstr "Gran premio" +msgstr "Gran Premio" #. I18N: ./data/gui/screens/karts.stkgui #. I18N: In the kart selection (player setup) screen @@ -1817,7 +1818,7 @@ msgstr "Obiettivi raggiunti" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen msgid "Grand Prix Editor" -msgstr "Editor gran premio" +msgstr "Editor Gran Premio" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen @@ -2019,7 +2020,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Puoi giocare senza creare un account in rete scegliendo un account non in rete. Tuttavia non potrai connetterti con i tuoi amici, votare i componenti aggiuntivi, ecc. Leggi la nostra informativa privacy all'indirizzo https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2223,7 +2224,7 @@ msgstr "Abilita la vibrazione (se supportato)" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings msgid "Internet options" -msgstr "Opzioni internet" +msgstr "Opzioni Internet" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings @@ -2233,7 +2234,7 @@ msgstr "Mostra sempre la schermata di accesso" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" -msgstr "Connetti ad internet" +msgstr "Connetti ad Internet" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings @@ -2277,7 +2278,7 @@ msgstr "Aggiungi un dispositivo" msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." -msgstr "* Quale configurazione usare verrà dedotta da quale pulsante 'Seleziona' verrà premuto per unirsi al gioco." +msgstr "* La configurazione da usare verrà dedotta da quale pulsante 'Seleziona' verrà premuto per unirsi al gioco." #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings @@ -2347,7 +2348,7 @@ msgstr "Livello di sfocatura" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" -msgstr "FPS massimo" +msgstr "FPS massimi" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings @@ -2420,7 +2421,7 @@ msgstr "Numero di kart gestiti dall'IA della squadra blu." #. I18N: In the track and grand prix selection screen #: src/race/grand_prix_data.cpp:623 msgid "Random Grand Prix" -msgstr "Gran premio casuale" +msgstr "Gran Premio casuale" #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) @@ -2818,7 +2819,7 @@ msgstr "Errore durante il caricamento delle notizie: '%s'" #: src/challenges/challenge_data.cpp:303 src/network/server_config.cpp:261 msgid "Normal Race (Grand Prix)" -msgstr "Gara Normale (Gran Premio)" +msgstr "Gara normale (Gran Premio)" #: src/challenges/challenge_data.cpp:305 msgid "Time-Trial (Grand Prix)" @@ -3853,7 +3854,7 @@ msgstr "Modalità gioco calcio: %s" #: src/network/protocols/client_lobby.cpp:784 #, c-format msgid "Grand prix progress: %d / %d" -msgstr "Progresso del Grand Prix: %d / %d" +msgstr "Progresso del Gran Premio: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start @@ -3979,11 +3980,11 @@ msgstr "Impossibile determinare il numero della porta per il server %s." #: src/network/protocols/lobby_protocol.cpp:294 msgid "Network grand prix has been finished." -msgstr "Il Gran premio in rete è stato completato." +msgstr "Il Gran Premio in rete è stato completato." #: src/network/server_config.cpp:263 msgid "Time Trial (Grand Prix)" -msgstr "Prova a tempo (Grand premio)" +msgstr "Prova a tempo (Gran Premio)" #. I18N: Game mode #. I18N: In the create server screen for battle server @@ -4231,7 +4232,7 @@ msgstr "Prove a tempo vinte" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:176 msgid "Follow-the-Leader races won" -msgstr "Gare \"segui il capo\" vinte" +msgstr "Gare \"Segui il Leader\" vinte" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4321,13 +4322,13 @@ msgstr "Prove a tempo completate" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:206 msgid "Follow-the-Leader races started" -msgstr "Gare \"segui il capo\" iniziate" +msgstr "Gare \"Segui il Leader\" iniziate" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:208 msgid "Follow-the-Leader races finished" -msgstr "Gare \"segui il capo\" completate" +msgstr "Gare \"Segui il Leader\" completate" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -5206,7 +5207,7 @@ msgstr "%s (+)" #: src/states_screens/edit_gp_screen.cpp:330 msgid "An error occurred while trying to save your grand prix." -msgstr "Si è verificato un errore durante il salvataggio del tuo gran premio" +msgstr "Si è verificato un errore durante il salvataggio del tuo Gran Premio." #: src/states_screens/edit_track_screen.cpp:255 msgid "Select a track" @@ -5272,11 +5273,11 @@ msgstr "Ricarica" #: src/states_screens/grand_prix_editor_screen.cpp:100 #: src/states_screens/grand_prix_editor_screen.cpp:117 msgid "Please enter the name of the grand prix" -msgstr "Inserisci il nome del gran premio" +msgstr "Inserisci il nome del Gran Premio" #: src/states_screens/grand_prix_editor_screen.cpp:168 msgid "Please select a Grand Prix" -msgstr "Inserisci il nome del gran premio" +msgstr "Scegli un Gran Premio" #: src/states_screens/grand_prix_editor_screen.cpp:336 msgid "User defined" @@ -5288,7 +5289,7 @@ msgstr "Il nome è vuoto." #: src/states_screens/grand_prix_editor_screen.cpp:357 msgid "Another grand prix with this name already exists." -msgstr "Un altro gran premio è già salvato con questo nome" +msgstr "Esiste già un altro Gran Premio con questo nome." #: src/states_screens/grand_prix_editor_screen.cpp:363 msgid "Name is too long." @@ -5305,11 +5306,11 @@ msgstr "Hai completato una sfida!" #: src/states_screens/grand_prix_win.cpp:324 msgid "You won the Grand Prix!" -msgstr "Hai vinto il Gran premio!" +msgstr "Hai vinto il Gran Premio!" #: src/states_screens/grand_prix_win.cpp:325 msgid "You completed the Grand Prix!" -msgstr "Hai completato il Gran premio!" +msgstr "Hai completato il Gran Premio!" #: src/states_screens/high_score_selection.cpp:144 msgctxt "column_name" @@ -5392,7 +5393,7 @@ msgstr "Server di %s" #. I18N: In the create server screen #: src/states_screens/online/create_server_screen.cpp:215 msgid "No. of grand prix track(s)" -msgstr "Numero di piste per il Gran premio" +msgstr "Numero di piste per il Gran Premio" #: src/states_screens/online/create_server_screen.cpp:298 msgid "Name has to be between 4 and 30 characters long!" @@ -5759,7 +5760,7 @@ msgstr "Accelera" #. I18N: Key binding name #: src/states_screens/options/options_screen_device.cpp:275 msgid "Brake / Reverse" -msgstr "Frena / Retromarcia" +msgstr "Freno / Retromarcia" #. I18N: Key binding name #: src/states_screens/options/options_screen_device.cpp:278 @@ -6118,7 +6119,7 @@ msgstr "Raccogli nitro!" #: src/states_screens/race_gui_base.cpp:771 msgid "Follow the leader!" -msgstr "Segui il capo!" +msgstr "Segui il leader!" #. I18N: When some GlobalPlayerIcons are hidden, write "Top 10" to show it #: src/states_screens/race_gui_base.cpp:954 @@ -6156,7 +6157,7 @@ msgstr "Esci dal server" #: src/states_screens/race_result_gui.cpp:310 msgid "Abort Grand Prix" -msgstr "Abbandona Gran premio" +msgstr "Abbandona Gran Premio" #: src/states_screens/race_result_gui.cpp:330 msgid "Restart" @@ -6176,7 +6177,7 @@ msgstr "Torna al menu" #: src/states_screens/race_result_gui.cpp:536 msgid "Do you really want to abort the Grand Prix?" -msgstr "Vuoi davvero abbandonare il Gran premio?" +msgstr "Vuoi davvero abbandonare il Gran Premio?" #: src/states_screens/race_result_gui.cpp:636 #: src/states_screens/race_result_gui.cpp:1529 @@ -6216,7 +6217,7 @@ msgstr "Pista %i/%i" #: src/states_screens/race_result_gui.cpp:1833 msgid "Grand Prix progress:" -msgstr "Progressi Gran premio:" +msgstr "Progressi Gran Premio:" #: src/states_screens/race_result_gui.cpp:1879 msgid "Highscores" @@ -6305,7 +6306,7 @@ msgstr "Numero di kart gestiti dall'IA della squadra rossa." msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" -msgstr "Non puoi gareggiare in questo grand prix perché contiene tracciati che non sono ancora stati sbloccati!" +msgstr "Non puoi gareggiare in questo Gran Premio perché contiene piste che non sono ancora state sbloccate!" #: src/states_screens/tracks_and_gp_screen.cpp:217 msgid "Locked!" @@ -6469,7 +6470,7 @@ msgid "" "battle mode against the computer or your friends, and more! For a greater " "challenge, join online and meet players from all over the world and prove " "your racing skills!" -msgstr "Puoi fare una gara singola contro altri kart, competere in uno dei numerosi Gran Prix, provare a battere i punteggi più alti nelle prove a tempo, sfidare amici e IA in modalità battaglia e altro ancora! Per una sfida ancora più stimolante, gioca in rete e mettiti alla prova gareggiando contro giocatori da tutto il mondo!" +msgstr "Puoi fare una gara singola contro altri kart, competere in uno dei numerosi Gran Premi, provare a battere i punteggi più alti nelle prove a tempo, sfidare amici e IA in modalità battaglia e altro ancora! Per una sfida ancora più stimolante, gioca in rete e mettiti alla prova gareggiando contro giocatori da tutto il mondo!" #: supertuxkart.appdata.xml:17 msgid "This game has no ads." @@ -6480,13 +6481,13 @@ msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." -msgstr "Questa è una versione instabile di SuperTuxKart che contiene gli ultimi miglioramenti. Praticamente è rilasciata per fare test, in modo che la prossima versione stabile sia al meglio." +msgstr "Questa è una versione instabile di SuperTuxKart che contiene gli ultimi miglioramenti. È stata rilasciata principalmente per fare test, in modo da rendere la versione stabile il meglio possibile." #: supertuxkart.appdata.xml:23 msgid "" "This version can be installed in parallel with the stable version on the " "device." -msgstr "Questa versione può essere installata in parallelo con la versione stabile nel dispositivo" +msgstr "Questa versione può essere installata in parallelo con la versione stabile nel dispositivo." #: supertuxkart.appdata.xml:26 msgid "If you need more stability, consider using the stable version: %s" diff --git a/data/po/ja.po b/data/po/ja.po index a6e0641592f..bf1ec0a26d7 100644 --- a/data/po/ja.po +++ b/data/po/ja.po @@ -8,15 +8,16 @@ # Bobby Youstra, 2022 # Bobby Youstra, 2022 # David Blaszyk , 2017 -# Happymc! , 2019-2020,2022-2023 +# Happymc , 2024 +# Happymc , 2019-2020,2022-2023 # lindwurm, 2015 -# Kazma , 2023 +# Kazma Otsubo , 2023 # 5605c392824fda3ac2df0bdbd59ff35b_058bab5 <4437a8e713388fd5aa2ba28f526ee201_779197>, 2019-2020 -# Kazma , 2020-2021 +# Kazma Otsubo , 2020-2021 # lindwurm, 2015 # lip_of_cygnus , 2015 # Masayuki Sugahara , 2015 -# Kazma , 2020 +# Kazma Otsubo , 2020 # Otsubo Kazma, 2022 # ec688d94bb12b1f70fb8e51df58a9b21_e09dba8, 2022-2023 # paontv , 2020 @@ -25,8 +26,8 @@ # Masayuki Sugahara , 2015 # Ubuntu Jackson , 2018-2020 # Ubuntu Jackson , 2020 -# 加瀬義悠, 2023 -# 加瀬義悠, 2023 +# よっちゃん, 2023 +# よっちゃん, 2023 # David Blaszyk , 2017 msgid "" msgstr "" @@ -34,7 +35,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Happymc! , 2019-2020,2022-2023\n" +"Last-Translator: Happymc , 2024\n" "Language-Team: Japanese (http://app.transifex.com/supertuxkart/supertuxkart/language/ja/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -933,7 +934,7 @@ msgstr "ユーザー情報" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "フレンドを削除" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -943,17 +944,17 @@ msgstr "フレンドを追加" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "招待を受け入れる" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "招待を断る" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "プロフィールを見る" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1141,7 +1142,7 @@ msgstr "クレジット" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "スキップ" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1523,7 +1524,7 @@ msgstr "ゴーストプレイ: タイムトライアルや卵狩りモードで #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "" +msgstr "ラップトライアル: 一定時間内にできるだけ多く周回する。" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -2021,7 +2022,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "オフラインアカウントを選択すれば、オンラインアカウントを作成せずにプレイできます。ただし、フレンドとの接続やアドオンへの投票などはできません。プライバシーに関する声明は、 https://privacy.supertuxkart.net をお読みください。" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2534,7 +2535,7 @@ msgstr "バスケットボールはカップケーキ、きゅうばん、ボー msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "" +msgstr "他のカートの後部に衝突しないようにして、速度が低下するのを防ごう。" #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." diff --git a/data/po/mk.po b/data/po/mk.po index 3f277b5f7ef..83a1e44b917 100644 --- a/data/po/mk.po +++ b/data/po/mk.po @@ -910,7 +910,7 @@ msgstr "Информации за Корисникот" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Отстрани пријател" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -920,17 +920,17 @@ msgstr "Додади Пријател" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Прифати покана" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Одби покана" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Погледни профил" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1118,7 +1118,7 @@ msgstr "Заслуги" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Прескокни" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1500,7 +1500,7 @@ msgstr "Дух снимка: Тркајте се против дух снимк #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "" +msgstr "Пробен круг: Завршете колку што е можно повеќе кругови во одредено дадено време." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1998,7 +1998,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Можете да играте без да создадете онлајн акаунт така што ќе селектирате офлајн акаунт. Меѓутоа тогаш не можете да се конектирате со пријатели, да гласате за додатоци итн. Ве молиме прочитајте ја нашата приватна изјава на https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2511,7 +2511,7 @@ msgstr "Кошаркаските топки можат да се уништат msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "" +msgstr "Пробајте да избегнувате да се судирате позади други возила бидејќи ова ќе ве успори." #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." @@ -2668,7 +2668,7 @@ msgstr "Хациенда" #. I18N: ../stk-assets/tracks/hole_drop/track.xml msgid "Hole Drop" -msgstr "" +msgstr "Испуштање Дупка" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" @@ -3794,7 +3794,7 @@ msgstr "Тежина: %s" #: src/network/protocols/client_lobby.cpp:743 #, c-format msgid "Max players: %d" -msgstr "Максиумум играчи: %d" +msgstr "Максимум играчи: %d" #. I18N: In server info dialog #: src/network/protocols/client_lobby.cpp:756 diff --git a/data/po/ml.po b/data/po/ml.po index 975d82bc686..7b6749bb272 100644 --- a/data/po/ml.po +++ b/data/po/ml.po @@ -5,7 +5,7 @@ # Translators: # Adithyan S S , 2020 # Adithyan S S , 2020 -# Adithyan S S , 2020-2022 +# Adithyan S S , 2020-2022,2024 # Kevin 008, 2021 # Kevin 008, 2021 msgid "" @@ -14,7 +14,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Kevin 008, 2021\n" +"Last-Translator: Adithyan S S , 2020-2022,2024\n" "Language-Team: Malayalam (http://app.transifex.com/supertuxkart/supertuxkart/language/ml/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -24,7 +24,7 @@ msgstr "" #. I18N: In Android UI, po_extract_game_data msgid "Extracting game data..." -msgstr " ഗെയിം വിവരങ്ങൾ സ്വാംശീകരിക്കുന്നു..." +msgstr "ഗെയിം വിവരങ്ങൾ സ്വാംശീകരിക്കുന്നു..." #. I18N: In Android UI, po_extract_error msgid "Game data extraction error" @@ -46,7 +46,7 @@ msgstr "ക്രിസ്റ്റോഫെൽ കൊളമ്പസ്" #. I18N: ./data/achievements.xml msgid "Play every official track at least once." -msgstr " ഔദ്യോഗിക ട്രാക്കുകളെല്ലാം കുറഞ്ഞത് ഒരുതവണയെങ്കിലും കളിക്കുക." +msgstr "ഔദ്യോഗിക പാതകൾ സർവ്വവും കുറഞ്ഞത് ഒരുതവണയെങ്കിലും കളിക്കുക." #. I18N: ./data/achievements.xml msgid "Strike!" @@ -70,7 +70,7 @@ msgstr "മാരത്തോണർ" #. I18N: ./data/achievements.xml msgid "Finish a race with at least twice the track's default lap number." -msgstr "ട്രാക്കിൻ്റെ സ്വതേയുള്ള ലാപ്പ് നമ്പറിൽനിന്നും കുറഞ്ഞത് ഇരട്ടിത്തവണയെങ്കിലും കളിച്ച് റേസ് പൂർത്തിയാക്കുക." +msgstr "പാതയുടെ സ്വതേയുള്ള ലാപ്പ് നമ്പറിൽനിന്നും കുറഞ്ഞത് ഇരട്ടിത്തവണയെങ്കിലും കളിച്ച് റേസ് പൂർത്തിയാക്കുക." #. I18N: ./data/achievements.xml msgid "Skid-row" @@ -88,7 +88,7 @@ msgstr "സുവർണ്ണ ഡ്രൈവർ" msgid "" "Win against at least 3 AIs in normal race, time-trial, and follow the " "leader." -msgstr "സാധാരണ റേസ്, ടൈം ട്രയൽ, നേതാവിനെ പിന്തുടരൂ എന്നിവയിൽ കുറഞ്ഞത് 3 AIകൾക്കെതിരേ ജയിക്കുക." +msgstr "സാധാരണ റേസ്, സമയസാമർഥ്യം, നേതാവിനെ പിന്തുടരൂ എന്നിവയിൽ കുറഞ്ഞത് 3 AIകൾക്കെതിരേ ജയിക്കുക." #. I18N: ./data/achievements.xml msgid "Powerup Love" @@ -114,7 +114,7 @@ msgstr "പഴത്തൊലിപ്രിയൻ" #. I18N: ./data/achievements.xml msgid "Collect at least 5 bananas in one race." -msgstr "കുറഞ്ഞത് 5 പഴത്തൊലികളങ്കിലും ഒരൊറ്റ റേസിൽ ശേഖരിക്കുക." +msgstr "കുറഞ്ഞത് 5 പഴത്തൊലികളെങ്കിലും ഒരൊറ്റ റേസിൽ ശേഖരിക്കുക." #. I18N: ./data/achievements.xml msgid "It's secret" @@ -132,7 +132,7 @@ msgstr "കൊതുകു വേട്ടക്കാരൻ" msgid "" "Take your opponents for mosquitos! With the swatter, squash them at least 5 " "times in a race." -msgstr "നിങ്ങളുടെ എതിരാളികളെ വെറും കൊതുകുകളായി കാണൂ! സ്വാറ്ററുപയോഗിച്ച്, അവരെ കുറഞ്ഞത് 5 തവണയെങ്കിലും അടിച്ചുപരത്തുക." +msgstr "നിങ്ങളുടെ ദൃഷ്ടിയിൽ എതിരാളികളെല്ലാം വെറും കൊതുകുകൾ! സ്വാറ്ററുപയോഗിച്ച്, അവരെ കുറഞ്ഞത് 5 തവണയെങ്കിലും അടിച്ചുപരത്തുക." #. I18N: ./data/achievements.xml msgid "Beyond Luck" @@ -183,7 +183,7 @@ msgstr "ഇൻസ്റ്റാൾ ചെയ്യുക" #. I18N: ./data/gui/dialogs/addons_loading.stkgui #. I18N: Add-on screen action msgid "Uninstall" -msgstr "അൺ ഇൻസ്റ്റാൾ ചെയ്യുക" +msgstr "അണിൻസ്റ്റാൾ ചെയ്യുക" #. I18N: ./data/gui/dialogs/android/init_android.stkgui msgid "Select a type of control that you prefer" @@ -195,7 +195,7 @@ msgstr "നിങ്ങൾ ഇഷ്ടപ്പെടുന്ന നിയന #. I18N: In the multitouch settings screen #: src/states_screens/dialogs/race_paused_dialog.cpp:549 msgid "Accelerometer" -msgstr "ആക്സിലറോമിറ്റർ" +msgstr "ത്വരണമാപകം" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type @@ -209,7 +209,7 @@ msgstr "ആക്സിലറോമിറ്റർ" #. I18N: Race paused button #: src/states_screens/dialogs/race_paused_dialog.cpp:554 msgid "Gyroscope" -msgstr "ഗൈറോസ്കോപ്പ്" +msgstr "ജൈറോസ്കോപ്പ്" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type @@ -275,12 +275,12 @@ msgstr "ടച്ച്-ഉപകരണ ക്രമീകരണങ്ങൾ" #. I18N: ./data/gui/screens/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" -msgstr "സാധാരണം" +msgstr "പൊതുവസ്തുതകൾ" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Device enabled" -msgstr "ഉപകരണം പ്രായോഗികമാണ്" +msgstr "ഉപകരണം ലഭ്യമാക്കണം" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -394,12 +394,12 @@ msgstr "കളിക്കാരന്റെ ക്യാമറ" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "FOV" -msgstr "എഫ്.ഓ.വി" +msgstr "കാഴ്ചപരിധി" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "Distance" -msgstr "അകലം" +msgstr "ദൂരം" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -453,12 +453,12 @@ msgstr "പ്രകാശരശ്മികൾ (അർക്കകിരണങ #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Ambient occlusion" -msgstr "ആംബിയന്റ് ഒക്ലൂഷൻ" +msgstr "പരിസ്ഥിതി ഗൂഹനം" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Depth of field" -msgstr "ഡെപ്ത് ഓഫ് ഫീൽഡ്" +msgstr "പരിസരവ്യാപ്തി" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -468,7 +468,7 @@ msgstr "തിളക്കം (ഔട്ട്ലൈനുകൾ)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Anti-aliasing" -msgstr "ആന്റി-എലീസിംഗ്" +msgstr "ആകാരമൃദുവൽകരണം" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -665,7 +665,7 @@ msgstr "റേസ് പുനരാരംഭിക്കുക" #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button msgid "Give Up Race" -msgstr "റേസ് വിട്ടുകളയുക" +msgstr "റേസ് പരിത്യജിക്കുക" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button @@ -710,7 +710,7 @@ msgstr "അക്കൗണ്ട് വീണ്ടെടുക്കൽ" msgid "" "You will receive an email with further instructions on how to reset your " "password. Please be patient and be sure to check your spam folder." -msgstr "താങ്കളുടെ പാസ് വേഡ് വീണ്ടെടുക്കുന്നതിനെക്കുറിച്ച് ഇനിയുള്ള നിർദ്ദേശങ്ങൾ അടങ്ങിയ ഒരു ഇമെയിൽ താങ്കൾക്ക് ലഭിക്കുന്നതായിരിക്കും. ദയവായി ക്ഷമയോടെ കാത്തിരിക്കുക. ഒപ്പം താങ്കളുടെ സ്പാം ഫോൾഡർ പരിശോധിച്ചെന്ന് ഉറപ്പാക്കുക." +msgstr "താങ്കളുടെ രഹസ്യവാക്ക് വീണ്ടെടുക്കുന്നതുമായി സംബന്ധിച്ച് ഇനിയുള്ള നിർദ്ദേശങ്ങൾ അടങ്ങിയ ഒരു ഇമെയിൽ താങ്കൾക്ക് ലഭിക്കുന്നതായിരിക്കും. ദയവായി ക്ഷമയോടെ കാത്തിരിക്കുക. ഒപ്പം താങ്കളുടെ സ്പാം ഫോൾഡർ പരിശോധിച്ചെന്നും ഉറപ്പാക്കുക." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui msgid "" @@ -739,7 +739,7 @@ msgstr "ഇമെയിൽ" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog msgid "Terms and Agreement" -msgstr "നിബന്ധനകളും വ്യവസ്ഥയും" +msgstr "നിബന്ധനകളും വാഗ്ദാനവും" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog @@ -838,7 +838,7 @@ msgstr "സാധാരണ റേസ്" #. I18N: Game mode #: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 msgid "Time Trial" -msgstr "ടൈം ട്രയൽ" +msgstr "സമയസാമർഥ്യം" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: Multiplayer game mode @@ -898,7 +898,7 @@ msgstr "കളിക്കാർ തയ്യാറാണെന്നുറപ #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "Clear players" -msgstr "കളിക്കാരെ ഒഴിവാക്കുക" +msgstr "കളിക്കാരെ കലശംചെയ്യുക" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network @@ -913,7 +913,7 @@ msgstr "ഉപയോക്തൃവിവരം" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "സുഹൃത്തിനെ നീക്കംചെയ്യുക" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -923,22 +923,22 @@ msgstr "സുഹൃത്തിനെ ചേർക്കാം" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "ക്ഷണം സ്വീകരിക്കുക" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "ക്ഷണം നിഷേധിക്കുക" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "പ്രൊഫൈൽ കാണുക" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog msgid "Vote" -msgstr "വോട്ട്" +msgstr "വോട്ട് ചെയ്യാം" #. I18N: ./data/gui/dialogs/overworld_dialog.stkgui #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui @@ -1023,7 +1023,7 @@ msgstr "കാർട്ടുകൾ" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen msgid "Tracks" -msgstr "ട്രാക്കുകൾ" +msgstr "പാതകൾ" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In the addons screen @@ -1121,7 +1121,7 @@ msgstr "കടപ്പാടുകൾ" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "പോക്കുക" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1130,7 +1130,7 @@ msgstr "" #. I18N: ./data/gui/screens/tracks.stkgui #. I18N: In the track selection screen msgid "All Tracks" -msgstr "എല്ലാ ട്രാക്കുകളും" +msgstr "എല്ലാ പാതകളും" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Title in edit grand prix screen @@ -1245,7 +1245,7 @@ msgstr "പരമാവധി സമയം (മിനി.)" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen msgid "Track group" -msgstr "ട്രാക്ക് ഗ്രൂപ്പ്" +msgstr "പാതയിനം" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen @@ -1419,7 +1419,7 @@ msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " "pressing the appropriate key or button. You can see your current level of " "nitro in the gauge at the bottom-right of the race screen." -msgstr "നൈട്രോ ശേഖരിക്കുന്നതിലൂടെ നിങ്ങളുടെ ഇഷ്ടാനുസൃതം ഉചിതമായ കിയോ ബട്ടണോ അമർത്തി സ്പീഡ് ബൂസ്റ്റുകൾ നേടാൻ അനുവദിക്കുന്നു. നിങ്ങളുടെ തത്സമയ നൈട്രോ നിരക്ക് നിങ്ങൾക്കു റേസ് സ്ക്രീനിന്റെ താഴെ-ഇടതുവശത്തെ ഗേജിൽ കാണാൻ സാധിക്കും." +msgstr "നൈട്രോ ശേഖരിക്കുന്നത് ഇഷ്ടാനുസൃതം ഉചിതമായ കീയോ ബട്ടണോ അമർത്തി സ്പീഡ് ബൂസ്റ്റുകൾ നേടാൻ നിങ്ങളെ അനുവദിക്കുന്നു. നിങ്ങളുടെ തത്സമയ നൈട്രോ നിരക്ക് റേസ് സ്ക്രീനിന്റെ താഴെ-ഇടതുവശത്തെ ഗേജിൽ നിങ്ങൾക്ക് കാണാൻ സാധിക്കും." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu @@ -1435,14 +1435,14 @@ msgid "" "help to take sharp turns; while medium skids will boost your speed, long " "skids more so. You can't stop turning while skidding, so orient your kart " "carefully before!" -msgstr "ഒരു പ്രത്യേക കിയോ ബട്ടണോ അമർത്തുന്നതിലുടെ നിങ്ങൾ സ്കിഡ്ഡ് ചെയ്യുന്നു. അനുസ്യൂതമായ ചെറിയ സ്കിഡ്ഡുകൾ കൂർത്ത തിരിവുകൾ എടുക്കാൻ സഹായിക്കും; മിതമായ സ്കിഡ്ഡുകൾ നിങ്ങളുടെ വേഗത വർദ്ധിപ്പിക്കുമ്പോൾ, ദൈർഘ്യമേറിയ സ്കിഡ്ഡുകൾ അതിനും മേലെയാണ്. സ്കിഡ്ഡിങ്ങിനിടെയുള്ള തിരിയൽ അനിയന്ത്രിതമാണ്, അതിനാൽ നിങ്ങളുടെ കാർട്ടിനെ ശ്രദ്ധാപൂർവ്വം വിന്യസിക്കേണേ!" +msgstr "ഒരു സവിശേഷ കിയോ ബട്ടണോ അമർത്തുന്നതിലുടെ നിങ്ങൾ സ്കിഡ്ഡ് ചെയ്യുന്നു. അനുസ്യൂതമായ ചെറിയ സ്കിഡ്ഡുകൾ കൂർത്ത തിരിവുകൾ എടുക്കാൻ സഹായിക്കും; മിതമായ സ്കിഡ്ഡുകൾ നിങ്ങളുടെ വേഗത വർദ്ധിപ്പിക്കുമ്പോൾ, ദൈർഘ്യമേറിയ സ്കിഡ്ഡുകൾ അതിനും മേലെയാണ്. സ്കിഡ്ഡിങ്ങിനിടെയുള്ള തിരിയൽ അനിയന്ത്രിതമാണ്, അതിനാൽ നിങ്ങളുടെ കാർട്ടിനെ ശ്രദ്ധാപൂർവ്വം വിന്യസിക്കേണേ!" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." -msgstr "റേസ് ആരംഭിക്കുന്നതിന് മുൻപായി 'ഒരുങ്ങിക്കോ!' കാണിക്കുമ്പോൾ 'ത്വരിപ്പിക്കാം' ബട്ടൺ അമർത്തുന്നതിലൂടെ ഒരു പ്രാരംഭ ബൂസ്റ്റ് നിങ്ങൾക്ക് ലഭിക്കുന്നു." +msgstr "റേസ് ആരംഭിക്കുന്നതിന് മുൻപായി 'ഒരുങ്ങിക്കോ!' കാണിക്കുമ്പോൾ 'ത്വരണ' ബട്ടൺ അമർത്തുന്നതിലൂടെ ഒരു പ്രാരംഭ ബൂസ്റ്റ് നിങ്ങൾക്ക് ലഭിക്കുന്നു." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: in the help screen @@ -1462,7 +1462,7 @@ msgstr "സാധാരണ റേസ്: എല്ലാ പ്രഹരങ് #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" -msgstr "ടൈം ട്രയൽ: ആയുധങ്ങൾ ഒന്നുമില്ല, അതിനാൽ നിങ്ങളുടെ ഡ്രെെവിങ്ങ് മിടുക്കുകൾക്കാണ് ഇവിടെ കാര്യം!" +msgstr "സമയസാമർഥ്യം: ആയുധങ്ങൾ ഒന്നുമില്ല, അതിനാൽ നിങ്ങളുടെ ഡ്രെെവിംഗ് മിടുക്കുകൾക്കാണ് ഇവിടെ കാര്യം!" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1470,7 +1470,7 @@ msgid "" "Follow the leader: Run for second place, as the last kart will be " "disqualified every time the counter hits zero. Beware: going in front of the" " leader will get you eliminated too!" -msgstr "നേതാവിനെ പിന്തുടരൂ: രണ്ടാം സ്ഥാനത്തിനായി മത്സരിക്കുക, കൗണ്ടർ പൂജ്യമടിക്കുന്ന ഓരോ സമയത്തും അവസാനത്തെ കാർട്ട് അയോഗ്യരായിക്കൊണ്ടിരിക്കും. സൂക്ഷിക്കണേ: നേതാവിന് മുന്നിൽകൂടി പോകുന്നത് നിങ്ങളെയും സ്ഥാനഭ്രംശം ചെയ്യാൻ ഇടയാക്കും." +msgstr "നേതാവിനെ പിന്തുടരൂ: രണ്ടാം സ്ഥാനത്തിനായി മത്സരിക്കുക, കൗണ്ടർ പൂജ്യമടിക്കുന്ന ഓരോ സമയത്തും അവസാനത്തെ കാർട്ട് അയോഗ്യമായിക്കൊണ്ടിരിക്കും. സൂക്ഷിക്കണേ: നേതാവിന് മുന്നിൽകൂടി പോകുന്നത് നിങ്ങളെയും സ്ഥാനഭ്രംശം ചെയ്യാൻ ഇടയാക്കും!" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1490,20 +1490,20 @@ msgstr "സോക്കർ: നിങ്ങളുടെ കാർട്ടുപ #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." -msgstr "മുട്ട വേട്ട: ട്രാക്കുകൾ സന്ദർശിച്ച് ഒളിഞ്ഞിരിക്കുന്ന എല്ലാ മുട്ടകളും കണ്ടെത്തുക." +msgstr "മുട്ട വേട്ട: വിവിധ സ്ഥലങ്ങൾ സന്ദർശിച്ച് ഒളിഞ്ഞിരിക്കുന്ന എല്ലാ മുട്ടകളും കണ്ടെത്തുക." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" -msgstr "പ്രേത റീപ്ലേ: ടൈം ട്രയലിലോ മുട്ട വേട്ടരീതിയിലോ പ്രേത റീപ്ലേകൾക്കെതിരെ മത്സരിക്കുക, സ്വയം നേട്ടംകൊയ്യുക!" +msgstr "പ്രേത റീപ്ലേ: സമയസാമർഥ്യത്തിലോ മുട്ട വേട്ടരീതിയിലോ പ്രേത റീപ്ലേകൾക്കെതിരെ മത്സരിക്കുക, സ്വയം നേട്ടംകൊയ്യുക!" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "" +msgstr "ലാപ്പ് മത്സരം: തന്നിരിക്കുന്ന സമയത്തിനകം കഴിയുന്നത്ര ലാപ്പുകൾ പൂർത്തീകരിക്കുക." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1547,7 +1547,7 @@ msgstr "പ്ലഞ്ചർ - നേരെയെറിഞ്ഞാൽ ഒര msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." -msgstr "ബൗളിംങ് ബോൾ - നേരെപോയി ഇത് ആഘാതമുണ്ടാക്കുന്നു, ഇതിന് ഭിത്തികൾ തട്ടിത്തെറിപ്പിക്കാൻ കഴിയും, നിങ്ങൾ തിരിഞ്ഞുനോക്കുകയാണെങ്കിൽ, പിന്നിലേക്കിത് എറിയെപ്പെടും." +msgstr "ബൗളിംഗ് ബോൾ - ആഘാതമുണ്ടാക്കുന്നതുവരെ ഇത് രേഖീയമായി സഞ്ചരിക്കുന്നു, ഇതിന് ഭിത്തികൾ തട്ടിത്തെറിപ്പിക്കാൻ കഴിയും. നിങ്ങൾ തിരിഞ്ഞുനോക്കുന്നുവെങ്കിൽ, പിന്നിലേക്കിത് എറിയെപ്പെടും." #. I18N: ./data/gui/screens/help3.stkgui msgid "Parachute - slows down all karts in a better position." @@ -1563,7 +1563,7 @@ msgstr "പകരംമാറ്റി - കുറച്ചുസമയത്ത msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." -msgstr "ബാസ്ക്കറ്റ് ബോൾ: നേതാവിന്റെ പുറേകേ തട്ടിത്തെറിക്കുന്നു, പിന്നെ വഴിക്കുള്ള കാർട്ടുകളെ അടിച്ചുപരത്തുകയും വേഗം കുറയ്ക്കുകയും ചെയ്തേക്കാം." +msgstr "ബാസ്ക്കറ്റ് ബോൾ: ഒന്നാംസ്ഥാനക്കാരന്റെ പിന്നാലെ തട്ടിത്തെറിച്ചുപോകുന്നു, പിന്നെ വഴിക്കുള്ള കാർട്ടുകളെ അടിച്ചുപരത്തുകയും വേഗം കുറയ്ക്കുകയും ചെയ്തേക്കാം." #. I18N: ./data/gui/screens/help3.stkgui msgid "" @@ -1607,7 +1607,7 @@ msgid "" "completed. In the top-right of the screen, it also tells you how many points" " you currently have. Complete as many challenges as possible, and Nolok will" " accept to race against you. Win to liberate Gnu!" -msgstr "മിനിമാപ്പിലെ ഈ ഐകൺ നിങ്ങൾ പൂർത്തികരിക്കാത്ത ലഭ്യമായ വെല്ലുവിളികൾ കാണിക്കുന്നു. സ്ക്രീനിന്റെ മുകളിൽ-വലത്തായി, അത് നിങ്ങൾക്ക് എത്ര പോയിന്റുകൾ നിലവിലുണ്ടെന്ന് പറയുന്നു. കഴിയുന്നത്ര വെല്ലുവിളികൾ പൂർത്തിയാക്കുക, ശേഷം നോലോക്ക് നിങ്ങൾക്കെതിരെ പന്തയത്തിനായി സമ്മതിക്കും. വിജയിച്ച് ഗ്നുവിനെ മോചിപ്പിക്കു!" +msgstr "മിനിമാപ്പിലെ ഈ ഐകൺ നിങ്ങൾ പൂർത്തികരിക്കാത്ത ലഭ്യമായ വെല്ലുവിളികൾ കാണിക്കുന്നു. സ്ക്രീനിന്റെ മുകളിൽ-വലത്തായി, അത് നിങ്ങൾക്ക് എത്ര പോയിന്റുകൾ നിലവിലുണ്ടെന്നുകൂടി പറയുന്നു. കഴിയുന്നത്ര വെല്ലുവിളികൾ പൂർത്തിയാക്കുക, ശേഷം നോലോക്കിന് നിങ്ങൾ പന്തയത്തിനു യോഗ്യനെന്ന് ബോധ്യപ്പെടും. വിജയിച്ച് ഗ്നുവിനെ മോചിപ്പിക്കൂ!" #. I18N: ./data/gui/screens/help5.stkgui #. I18N: In the help menu @@ -1644,7 +1644,7 @@ msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " "with a lot of sharp curves. The lighter the kart, the faster it accelerates," " especially at low speeds." -msgstr "ത്വരണം - പ്രത്യേകിച്ച് തുടക്കത്തിൽ, ഒരുപകടത്തിനുശേഷം, അല്ലെങ്കിൽ അനേകം കൂർത്ത വളവുകള്ളുള്ള ട്രാക്കുകളിൽ ഉപയോഗപ്രദം. കാർട്ടെത്ര ലഘുവാണോ, അത്ര വേഗത്തിൽ അത് ത്വരണംചെയ്യുന്നു, പ്രത്യേകിച്ചും കുറഞ്ഞ വേഗതകളിൽ." +msgstr "ത്വരണം - പ്രത്യേകിച്ച് തുടക്കത്തിൽ, ഒരുപകടത്തിനുശേഷം, അല്ലെങ്കിൽ അനേകം കൂർത്ത വളവുകള്ളുള്ള പാതകളിൽ ഉപയോഗപ്രദം. കാർട്ടെത്ര ലഘുവാണോ, അത്ര വേഗത്തിൽ അത് ത്വരണംചെയ്യുന്നു, പ്രത്യേകിച്ചും കുറഞ്ഞ വേഗതകളിൽ." #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu @@ -1652,7 +1652,7 @@ msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " "in tracks with straight lines and gentle curves. Heavier karts have a higher" " top speed." -msgstr "പരമ. വേഗം - എത്ര ഉയർന്നതോ അത്, അത്ര വേഗത്തിൽ കാർട്ടിനുപോകാൻ സാധിക്കും. പ്രത്യേകിച്ച് നേർരേഖകളും നേർത്ത വളവുകളുമുള്ള ട്രാക്കുകളിൽ ഉപകരിക്കുന്നു. ഭാരേമേറിയ കാർട്ടുകൾക്ക് ഒരുയർന്ന വേഗപരിധി ഉണ്ട്." +msgstr "പരമ. വേഗം - എത്ര ഉയർന്നതോ അത്, അത്ര വേഗത്തിൽ കാർട്ടിനുപോകാൻ സാധിക്കും. പ്രത്യേകിച്ച് നേർരേഖകളും നേർത്ത വളവുകളുമുള്ള പാതകളിൽ ഉപകരിക്കുന്നു. ഭാരേമേറിയ കാർട്ടുകൾക്ക് വിശാലമായ വേഗപരിധി ഉണ്ട്." #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu @@ -1682,7 +1682,7 @@ msgid "" "options). Then, you can either create your own server with custom options, " "or search among a list of existing servers to join. Some of them are " "recommended servers with optionally ranked races." -msgstr "ആദ്യം, പ്രധാന മെനുവിലെ 'ഓൺലൈൻ' ഐകൺ തിരഞ്ഞെടുക്കുക. പ്രാദേശിക നെറ്റ്‌വർക്കിംഗോ അല്ലെങ്കിൽ ആഗോള നെറ്റ്‌വർക്കിംഗോ (ഐച്ഛികങ്ങളിൽ ഇന്റർനെറ്റ് ലഭ്യമാക്കിയിടേണ്ടത് അനിവാര്യമാണ്) വേണ്ടത് നിർണ്ണയിക്കുക. ശേഷം, നിങ്ങൾക്ക് ഒന്നുകിൽ സ്വന്തമായൊരു സെർവർ കൃത്രിമ ഐച്ഛികങ്ങൾ ഉപയോഗിച്ചു സൃഷ്ടിക്കാം, അല്ലെങ്കിൽ നിലവിലെ സെർവറുകളുടെ ഒരു ലിസ്റ്റിൽനിന്ന് കണ്ടുപിടിച്ചു ചേരാം. അവയിൽ ചിലത് കൃത്രിമമായി റാങ്കുചെയ്ത റേസുകളാൽ ശുപാർശ ചെയ്ത സെർവറുകളാണ്." +msgstr "ആദ്യം, പ്രധാന മെനുവിലെ 'ഓൺലൈൻ' ഐകൺ തിരഞ്ഞെടുക്കുക. പ്രാദേശിക നെറ്റ്‌വർക്കിംഗോ അല്ലെങ്കിൽ ആഗോള നെറ്റ്‌വർക്കിംഗോ (ഐച്ഛികങ്ങളിൽ ഇന്റർനെറ്റ് ലഭ്യമാക്കിയിടേണ്ടത് അനിവാര്യമാണ്) വേണ്ടത് നിർണ്ണയിക്കുക. ശേഷം, നിങ്ങൾക്ക് ഒന്നുകിൽ സ്വന്തമായൊരു സെർവർ കൃത്രിമ ഐച്ഛികങ്ങൾ ഉപയോഗിച്ചു സൃഷ്ടിക്കാം, അല്ലെങ്കിൽ നിലവിലെ സെർവറുകളുടെ ഒരു ലിസ്റ്റിൽനിന്ന് കണ്ടുപിടിച്ചു ചേരാം. അവയിൽ ചിലത് സവിശേഷമായി റാങ്കുചെയ്ത റേസുകളാൽ ശുപാർശ ചെയ്ത സെർവറുകളാണ്." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1692,7 +1692,7 @@ msgid "" " enough players. Then, you can choose your kart and vote for the next track " "to race on. An addon track is allowed only if it exists on all joined " "players and the server." -msgstr "സെർവറിലൊരിക്കൽ, ഒരു റേസ് ആരംഭിക്കണമെങ്കിൽ അതിന്റെ ഉടമ (കിരീടംകൊണ്ട് പ്രധിനിധീകരിച്ചത്) അതു നിശ്ചയിക്കണം. ഔദ്യോഗിക സെർവറുകൾ മതിയായ കളിക്കാരുള്ളപ്പോൾ മാത്രം റേസുകൾ സ്വയം ആരംഭിച്ചേക്കാം. ശേഷം, നിങ്ങൾക്ക് റേസുചെയ്യാൻ നിങ്ങളുടെ കാർട്ട് തിരഞ്ഞെടുത്ത് അടുത്ത ട്രാക്കിനായി വോട്ടുചെയ്യാം. ഒരു ആഡോൺ ട്രാക്ക് അനുവദനിയം എല്ലാ ചേർന്നിരിക്കുന്ന കളിക്കാരിലും സെർവറിലും അത് നിലനിൽക്കുന്നെങ്കിൽ മാത്രമാണ്." +msgstr "ഒരു സെർവറിൽ, അതിൻ്റെ ഉടമ (കിരീടംകൊണ്ട് പ്രധിനിധീകരിച്ചത്) താൽപര്യപ്പെടുന്ന പക്ഷം ഒരു റേസ് ആരംഭിക്കുന്നതാണ്. ഔദ്യോഗിക സെർവറുകൾ മതിയായ കളിക്കാരുള്ളപ്പോൾ മാത്രം റേസുകൾ സ്വയം ആരംഭിച്ചേക്കാം. ശേഷം, നിങ്ങൾക്ക് റേസിനുവേണ്ട കാർട്ട് തിരഞ്ഞെടുത്ത് തുടർന്നുള്ള പാതയ്ക്കായി വോട്ടുചെയ്യാം. ഒരു ആഡോൺപഥം ചേർന്നിരിക്കുന്ന എല്ലാ കളിക്കാരിലും സെർവറിലുമെല്ലാം നിലനിൽക്കുന്നെങ്കിൽ മാത്രമാണ് അനുവദനീയം." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1707,7 +1707,7 @@ msgid "" "keyboard(s), each player will need a different set of keys, and most " "keyboards are not appropriate for multiplayer because they don't support " "multiple simultaneous keypresses." -msgstr "ആദ്യം, നിങ്ങൾക്ക് ഒരുപാട് ഇൻപുട്ട് ഉപകരണങ്ങൾ വേണ്ടതാണ്. അവയെ സജ്ജമാക്കിയെടുക്കുന്നതിനായി ഇൻപുട്ട് ക്രമീകരണങ്ങൾ എന്ന തിരശ്ശീല ഉപയോഗിക്കുക. ഒന്നിലധികം ഗെയിംപാഡുകളോ ജോയ്സ്റ്റിക്കുകളോ ആണ് അനുേയോജ്യം: കീബോർഡിൽ, ഓരോ കളിക്കാരനും വ്യത്യസ്തതരം കീകൾ വേണം, മാത്രവുമല്ല മിക്ക കീബോർഡുകളും ഒരേസമയം ഒരുപാട് കീ പ്രസ്സുകൾ അനുവദിക്കുന്നതല്ല എന്നതുകൊണ്ടു തന്നെ സംഘറേസുകളിൽ ഇവ അനുയോജ്യമല്ല." +msgstr "ആദ്യം, നിങ്ങൾക്ക് അനവധി ഇൻപുട്ട് ഉപകരണങ്ങൾ വേണ്ടതാണ്. അവയെ പ്രാപ്തമാക്കിയെടുക്കുവാൻ ഇൻപുട്ട് ക്രമീകരണങ്ങൾ എന്ന തിരശ്ശീല ഉപയോഗിക്കുക. ഒന്നിലധികം ഗെയിംപാഡുകളോ ജോയ്സ്റ്റിക്കുകളോ ആണ് അനുേയോജ്യം: കീബോർഡിൽ, ഓരോ കളിക്കാരനും വ്യത്യസ്തതരം കീകൾ വേണം, മാത്രവുമല്ല മിക്ക കീബോർഡുകളും ഒരേസമയം ഒരുപാട് കീ പ്രസ്സുകൾ അനുവദിക്കുന്നതല്ല എന്നതുകൊണ്ടു തന്നെ സംഘറേസുകളിൽ ഇവ അനുയോജ്യമല്ല." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -2001,7 +2001,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "ഒരു ഓഫ്‌ലൈൻ അക്കൗണ്ട് തിരഞ്ഞെടുക്കുന്നതു വഴി ഓൺലൈൻ അക്കൗണ്ട് ഇല്ലാതെയും നിങ്ങൾക്ക് കളിക്കാൻ സാധിക്കും. അങ്ങനെയെങ്കിൽ നിങ്ങൾക്ക് സുഹൃത്തുക്കളുമായി ബന്ധപ്പെടൽ, ആഡോണുകൾക്ക് വോട്ട് ചെയ്യൽ, മുതലായവ സാധിക്കുന്നതല്ല. ദയവായി ഞങ്ങളുടെ സ്വകാര്യതാനയം https://privacy.supertuxkart.net -ൽ വായിക്കുക." #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2314,17 +2314,17 @@ msgstr "സ്പീഡ്റൺ ടൈമർ ലഭ്യമാക്കാം" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" -msgstr "മിഴിവ് അവതരിപ്പിക്കാം" +msgstr "അവതരണമിഴിവ്" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" -msgstr "ഗ്രാഫിക്കൽ എഫക്ടുകൾ നിരക്ക്" +msgstr "ഗ്രാഫിക്കൽ ഇഫക്ടുകൾ നിരക്ക്" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" -msgstr "മങ്ങൽ എഫക്ടുകൾ നിരക്ക്" +msgstr "മങ്ങൽ ഇഫക്ടുകൾ നിരക്ക്" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video options, maximum frame per second @@ -2334,7 +2334,7 @@ msgstr "പരമാവധി FPS" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." -msgstr "കൃത്രിമ ക്രമീകരണങ്ങൾ" +msgstr "കൃത്രിമ ക്രമീകരണങ്ങൾ..." #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings @@ -2449,7 +2449,7 @@ msgstr "സഹായമെനുവിൽ ധാരാളം ഉപകാരപ #. I18N: ./data/tips.xml msgid "In single-player, you can watch and challenge recorded time-trials." -msgstr "ഒറ്റയാളിൽ, നിങ്ങൾക്ക് റെക്കോർഡ് ചെയ്ത ടൈം-ട്രയലുകളെ കാണാനും പന്തയം വയ്ക്കാനും സാധിക്കും." +msgstr "ഒറ്റയാളിൽ, നിങ്ങൾക്ക് റെക്കോർഡ് ചെയ്ത സമയ-സമർഥരെ കാണാനും പന്തയം വയ്ക്കാനും സാധിക്കും." #. I18N: ./data/tips.xml msgid "" @@ -2468,7 +2468,7 @@ msgstr "സുരക്ഷിതെമെന്ന് ഉറച്ചശേഷ msgid "" "Don't use multiple zippers quickly in row, instead, wait until the speed " "boost wears off." -msgstr "ഒന്നിലധികം സിപ്പറുകൾ പൊടുന്നനെ ഒരുനിരയിൽ ഉപയോഗിക്കരുത്, പകരം, വേഗതാ ബൂസ്റ്റ് വിട്ടുമാറുതുവരെ കാക്കുക." +msgstr "ഒന്നിലധികം സിപ്പറുകൾ പൊടുന്നനെ ഒരുനിരയിൽ ഉപയോഗിക്കരുത്, പകരം, ആ വേഗതാ ബൂസ്റ്റ് വിട്ടുമാറുതുവരെ കാക്കുക." #. I18N: ./data/tips.xml msgid "Skidding makes you much faster, do it whenever safe." @@ -2476,7 +2476,7 @@ msgstr "സ്കിഡുചെയ്യുന്നത് നിങ്ങള #. I18N: ./data/tips.xml msgid "The swatter can be used to remove bombs or parachutes." -msgstr "ബോംബുകളെയും പാരഷ്യൂട്ടുകളെയും നീക്കാൻ പാരഷ്യൂട്ട് ഉപയോഗിക്കാവുന്നതാണ്." +msgstr "ബോംബുകളെയും പാരഷ്യൂട്ടുകളെയും നീക്കാൻ സ്വാറ്റർ ഉപയോഗിക്കാവുന്നതാണ്." #. I18N: ./data/tips.xml msgid "" @@ -2486,7 +2486,7 @@ msgstr "സ്കിഡ്ഡിങ്ങിനിടെയുള്ള തി #. I18N: ./data/tips.xml msgid "You get a startup boost if you start accelerating during \"Set\"." -msgstr "\"ഒരുങ്ങിക്കോ\"യുടെ സമയത്ത് നിങ്ങൾ തുടങ്ങിയാൽ ഒരു പ്രാരംഭ ബൂസ്റ്റ് നിങ്ങൾക്ക് ലഭിക്കുന്നു." +msgstr "\"ഒരുങ്ങിക്കോ\"യുടെ സമയത്ത് നിങ്ങൾ ത്വരണമാരംഭിച്ചാൽ ഒരു പ്രാരംഭ ബൂസ്റ്റ് നിങ്ങൾക്ക് ലഭിക്കുന്നു." #. I18N: ./data/tips.xml msgid "Braking allows to get rid of parachutes quicker." @@ -2514,7 +2514,7 @@ msgstr "കൃത്യമായ ബൗളിംങ് ബോൾ, കേക് msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "" +msgstr "മറ്റു കാർട്ടുകളുടെ പിറകുകളിൽ ചെന്നിടിക്കുന്നത് കഴിയുന്നതും ഒഴിവാക്കുക, ഇതു നിങ്ങളുടെ വേഗം കുറയ്ക്കുമെന്നതിനാൽ." #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." @@ -2574,7 +2574,7 @@ msgstr "ഗ്നു" #. I18N: ../stk-assets/karts/hexley/kart.xml msgid "Hexley" -msgstr "ഹെക്സ് ലി" +msgstr "ഹെക്സ്​ലി" #. I18N: ../stk-assets/karts/kiki/kart.xml msgid "Kiki" @@ -2622,7 +2622,7 @@ msgstr "സ്യൂ" #. I18N: ../stk-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" -msgstr "ആന്റെഡിലൂവിയൻ തുരങ്കപ്പാത" +msgstr "അത്യാദിമകാല തുരങ്കപ്പാത" #. I18N: ../stk-assets/tracks/alien_signal/track.xml msgid "Alien Signal" @@ -2671,7 +2671,7 @@ msgstr "ഹസിയെൻഡ" #. I18N: ../stk-assets/tracks/hole_drop/track.xml msgid "Hole Drop" -msgstr "" +msgstr "ന്യൂജെൻ ഗോലികളി" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" @@ -2702,7 +2702,7 @@ msgstr "നിനക്കെന്നെ റേസിംഗിൽ തോല് msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" -msgstr " പക്ഷേ നിങ്ങൾ പരിതാപകരായ കുഞ്ഞുവങ്കന്മാർക്ക് ഒരിക്കലും എന്നെ തോല്പിക്കാൻ ആകില്ല - കാർട്ടുകളുടെ രാജാവേ!" +msgstr "പക്ഷേ നിങ്ങൾ പരിതാപകരായ കുഞ്ഞുവങ്കന്മാർക്ക് ഒരിക്കലും എന്നെ തോല്പിക്കാൻ ആകില്ല - ഈ കാർട്ടുകളുടെ രാജാവിനെ!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" @@ -2726,7 +2726,7 @@ msgstr "മിനിഗോൾഫ്" #. I18N: ../stk-assets/tracks/oasis/track.xml msgid "Oasis" -msgstr "" +msgstr "മരുപ്പച്ച" #. I18N: ../stk-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" @@ -2787,7 +2787,7 @@ msgstr "സെൻ ഉദ്യാനം" #: src/achievements/achievement.cpp:387 #, c-format msgid "Completed achievement \"%s\"." -msgstr "പുരസ്ക്കാരം നേടിയിരിക്കുന്നു \"%s\"." +msgstr "പുരസ്കാരം നേടിയിരിക്കുന്നു \"%s\"." #: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 msgid "Failed to connect to the SuperTuxKart add-ons server." @@ -2804,15 +2804,15 @@ msgstr "സാധാരണ റേസ് (ഗ്രാന്റ് പ്രീ)" #: src/challenges/challenge_data.cpp:305 msgid "Time-Trial (Grand Prix)" -msgstr "ടൈം-ട്രയൽ (ഗ്രാന്റ് പ്രീ)" +msgstr "സമയ-സാമർഥ്യം (ഗ്രാന്റ് പ്രീ)" #: src/challenges/challenge_data.cpp:310 msgid "Time-Trial - beat the replay" -msgstr "ടൈം-ട്രയൽ - റീപ്ലെയെ പരാജയപ്പെടുത്തുക" +msgstr "സമയ-സാമർഥ്യം - റീപ്ലെയെ പരാജയപ്പെടുത്തുക" #: src/challenges/challenge_data.cpp:312 msgid "Time-Trial - nitro challenge" -msgstr "ടൈം-ട്രയൽ - നൈട്രോ വെല്ലുവിളി" +msgstr "സമയ-സാമർഥ്യം - നൈട്രോ വെല്ലുവിളി" #: src/challenges/challenge_data.cpp:314 msgid "Normal Race (single race)" @@ -2820,7 +2820,7 @@ msgstr "സാധാരണ റേസ് (ഒറ്റയാൾ റേസ്)" #: src/challenges/challenge_data.cpp:316 msgid "Time-Trial (single race)" -msgstr "ടൈം-ട്രയൽ (ഒറ്റയാൾ റേസ്)" +msgstr "സമയ-സാമർഥ്യം (ഒറ്റയാൾ റേസ്)" #: src/challenges/challenge_data.cpp:318 msgid "Follow the Leader (single race)" @@ -2836,7 +2836,7 @@ msgstr "മോഡ്: എതിർദിശ" #: src/challenges/challenge_data.cpp:601 #, c-format msgid "New track '%s' now available" -msgstr "പുതിയ ട്രാക്ക് '%s' ഇപ്പോൾ ലഭ്യമാണ്" +msgstr "പുതിയ പാത '%s' ഇപ്പോൾ ലഭ്യമാണ്" #: src/challenges/challenge_data.cpp:605 #, c-format @@ -2866,7 +2866,7 @@ msgid "" "Closing the game before the story mode's completion invalidates the timer.\n" "\n" "To use the speedrun mode, please use a new profile." -msgstr "സ്പീഡ്റൺ മോഡ് ഇനി ലഭ്യമല്ല. കഥാ മോഡിന്റെ വിക്ഷേപണം മുതൽക്കേ ഗെയിം അടച്ചിട്ടില്ലെങ്കിൽ മാത്രമേ അത് ലഭ്യമാക്കാനാവൂ.\n\nകഥ മോഡിന്റെ പൂർത്തീകരണത്തിനു മുൻപേ ഗെയിം അടയ്ക്കുന്നത് ടൈമർ അസാധുവാക്കുന്നു.\n\nസ്പീഡ്റൺ മോഡ് ഉപയോഗിക്കുന്നതിനായി, ദയവായി ഒരു പുതിയ പ്രൊഫൈൽ ഉപയോഗിക്കുക." +msgstr "സ്പീഡ്റൺ മോഡ് ഇപ്പോൾ ലഭ്യമല്ല. കഥാ മോഡിന്റെ വിക്ഷേപണം മുതൽക്കേ ഗെയിം അടച്ചിട്ടില്ലെങ്കിൽ മാത്രമേ അത് ലഭ്യമാക്കാനാവൂ.\n\nകഥ മോഡിന്റെ പൂർത്തീകരണത്തിനു മുൻപേ ഗെയിം അടയ്ക്കുന്നത് ടൈമർ അസാധുവാക്കുന്നു.\n\nസ്പീഡ്റൺ മോഡ് ഉപയോഗിക്കുന്നതിനായി, ദയവായി ഒരു പുതിയ പ്രൊഫൈൽ ഉപയോഗിക്കുക." #. I18N: Name of first guest player (without number) #: src/config/player_manager.cpp:396 @@ -3391,13 +3391,13 @@ msgstr "വലിപ്പംകൂട്ടൽ" #: src/input/binding.cpp:301 msgctxt "input_key" msgid "Pa1" -msgstr "Pa1" +msgstr "പാ1" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:303 msgctxt "input_key" msgid "Oem Clear" -msgstr "ഓഎം ക്ലിയർ" +msgstr "ഓഇഎം ക്ലിയർ" #. I18N: to appear in input configuration screen, for gamepad hats #: src/input/binding.cpp:343 src/input/binding.cpp:348 @@ -3446,7 +3446,7 @@ msgstr "മൗസ് അച്ചുതണ്ട് %d%s" #. I18N: shown when config file is too old #: src/input/device_manager.cpp:496 msgid "Please re-configure your key bindings." -msgstr "ദയവായി നിങ്ങളുടെ കീ അനുക്രമണങ്ങൾ പുനർ- ക്രമീകരിക്കുക." +msgstr "ദയവായി നിങ്ങളുടെ കീ അനുക്രമണങ്ങൾ പുനർ-ക്രമീകരിക്കുക." #: src/input/device_manager.cpp:497 msgid "Your input config file is not compatible with this version of STK." @@ -3570,25 +3570,25 @@ msgstr "%s-ന്റെ ബാറ്ററി നിരക്ക് കുറവ msgid "" "Connect your wiimote to the Bluetooth manager, then click on Ok. Detailed " "instructions at https://supertuxkart.net/Wiimote" -msgstr "താങ്കളുടെ വിമോട്ട് ബ്ലുടൂത്ത് മാനേജറുമായി ബന്ധിപ്പിക്കുക, ശേഷം ശരി അമർത്തുക. വിശദ നിർദ്ദേശങ്ങൾ https://supertuxkart.net/Wiimote -ൽ." +msgstr "താങ്കളുടെ വീമോട്ട് ബ്ലുടൂത്ത് മാനേജറുമായി ബന്ധിപ്പിക്കുക, ശേഷം ശരി അമർത്തുക. വിശദ നിർദ്ദേശങ്ങൾ https://supertuxkart.net/Wiimote -ൽ." #: src/input/wiimote_manager.cpp:382 msgid "" "Press the buttons 1+2 simultaneously on your wiimote to put it in discovery " "mode, then click on Ok. Detailed instructions at " "https://supertuxkart.net/Wiimote" -msgstr "താങ്കളുടെ വിമോട്ട് ഡിസ്കവറി മോഡിലിടാൻ 1+2 ബട്ടണുകൾ ഒരേവേളയിൽ അമർത്തുക, ശേഷം ശരിയിൽ അമർത്തുക. വിശദ നിർദ്ദേശങ്ങൾ https://supertuxkart.net/Wiimote -ൽ." +msgstr "താങ്കളുടെ വീമോട്ട് ഡിസ്കവറി മോഡിലിടാൻ 1+2 ബട്ടണുകൾ ഒരേവേളയിൽ അമർത്തുക, ശേഷം ശരിയിൽ അമർത്തുക. വിശദ നിർദ്ദേശങ്ങൾ https://supertuxkart.net/Wiimote -ൽ." #: src/input/wiimote_manager.cpp:405 #, c-format msgid "Found %d wiimote" msgid_plural "Found %d wiimotes" -msgstr[0] "%d വിമോട്ട് കണ്ടെത്തി." -msgstr[1] "%d വിമോട്ടുകൾ കണ്ടെത്തി." +msgstr[0] "%d വീമോട്ട് കണ്ടെത്തി." +msgstr[1] "%d വീമോട്ടുകൾ കണ്ടെത്തി." #: src/input/wiimote_manager.cpp:410 msgid "Could not detect any wiimote :/" -msgstr "ഒരു വിമോട്ടും കണ്ടെത്താനായില്ല :/" +msgstr "ഒരു വീമോട്ടും കണ്ടെത്താനായില്ല :/" #: src/io/rich_presence.cpp:477 msgid "Getting ready to race" @@ -3627,7 +3627,7 @@ msgstr "റാങ്ക് %d-ൽ നിങ്ങൾ റേസ് പൂർത #: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 #, c-format msgid "%s left the game." -msgstr "%s ഗെയിം വിട്ടു" +msgstr "%s ഗെയിം വിട്ടു." #: src/main.cpp:2034 msgid "" @@ -3636,7 +3636,7 @@ msgid "" " Would you like this feature to be enabled? (To change this setting at a " "later time, go to options, select tab 'General', and edit \"Connect to the " "Internet\")." -msgstr "സൂപ്പർടക്സ്കാർട്ട് ആഡ്-ഓണുകൾ ഡൗൺലോഡ് ചെയ്യുന്നതിനും പുതുമകളപ്പറ്റി താങ്കളെ അറിയിക്കുന്നതിനുമായി ഒരു സെർവറുമായി ബന്ധപ്പെട്ടേക്കാം. ദയവായി ഞങ്ങളുടെ സ്വകാര്യതാനയം https://supertuxkart.net/Privacy -ൽ വായിക്കുക. താങ്കൾ ഈ പ്രത്യേകത ലഭ്യമാക്കാൻ ആഗ്രഹിക്കുന്നുവോ? (ഈ ക്രമീകരണം പിൽക്കാലത്ത് മാറ്റുന്നതിനായി, ഐച്ഛികങ്ങളിലേക്കു പോകുക, 'സാധാരണം' ടാബ് തിരഞ്ഞെടുക്കുക, ശേഷം \"ഇന്റർനെറ്റുമായി ബന്ധപ്പെടുക\" തിരുത്തുക)." +msgstr "സൂപ്പർടക്സ്കാർട്ട് ആഡ്-ഓണുകൾ ഡൗൺലോഡ് ചെയ്യുന്നതിനും പുതുമകളപ്പറ്റി താങ്കളെ അറിയിക്കുന്നതിനുമായി ഒരു സെർവറുമായി ബന്ധപ്പെട്ടേക്കാം. ദയവായി ഞങ്ങളുടെ സ്വകാര്യതാനയം https://supertuxkart.net/Privacy -ൽ വായിക്കുക. താങ്കൾ ഈ പ്രത്യേകത ലഭ്യമാക്കാൻ ആഗ്രഹിക്കുന്നുവോ? (ഈ ക്രമീകരണം പിൽക്കാലത്ത് മാറ്റുന്നതിനായി, ഐച്ഛികങ്ങളിലേക്കു പോകുക, 'പൊതുവസ്തുതകൾ' ടാബ് തിരഞ്ഞെടുക്കുക, ശേഷം \"ഇന്റർനെറ്റുമായി ബന്ധപ്പെടുക\" തിരുത്തുക)." #: src/main.cpp:2386 msgid "Your screen resolution is too low to run STK." @@ -3963,7 +3963,7 @@ msgstr "നെറ്റ്‌വർക്ക് ഗ്രാന്റ് പ് #: src/network/server_config.cpp:263 msgid "Time Trial (Grand Prix)" -msgstr "ടൈം ട്രയൽ (ഗ്രാന്റ് പ്രീ)" +msgstr "സമയസാമർഥ്യം (ഗ്രാന്റ് പ്രീ)" #. I18N: Game mode #. I18N: In the create server screen for battle server @@ -4137,7 +4137,7 @@ msgstr "ക്ഷമിക്കണം, ആഡ്-ഓണുകളുടെ വ #: src/states_screens/kart_selection.cpp:1598 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" -msgstr "പൂട്ടിയിരിക്കുന്നു: കൂടുതൽ യോഗ്യതകൾ പ്രാപ്തമാക്കാൻ സജീവ വെല്ലുവിളികൾ പരിഹരിക്കൂ!" +msgstr "പൂട്ടിയിരിക്കുന്നു: അധികയോഗ്യതകൾ നേടാൻ സജീവ വെല്ലുവിളികൾ പരിഹരിക്കൂ!" #: src/states_screens/arenas_screen.cpp:342 msgid "Random Arena" @@ -4152,7 +4152,7 @@ msgstr[1] "%d മേഖലകൾ ഒറ്റയാളിൽ അലഭ്യമ #: src/states_screens/credits.cpp:184 msgid "translator-credits" -msgstr "Launchpad Contributions:\nAdithyan S S, 2020\nAdithyan S S, 2020-2022\nKevin 008, 2021\nAdithyan S S, 2020-2021\nAdithyan SS ആദിത്യൻ എസ് എസ് (aka Alphacelestius)\nLaunchpad:\nGitHub:\nInstagram: @alphacelestius_activated925" +msgstr "Launchpad Contributions:\nAdithyan S S, 2020\nAdithyan S S, 2020-2024\nAdithyan S S, 2020-2022\nAdithyan S S, 2020-2021\nAdithyan SS ആദിത്യൻ എസ് എസ് (aka Alphacelestius)\nLaunchpad: ~thestrawberryandkiwi-2\nGitHub: The-Legendary-Psycho" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:65 msgctxt "achievement_info" @@ -4202,7 +4202,7 @@ msgstr "വിജയിച്ച സാധാരണ റേസുകൾ" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:174 msgid "Time-trial races won" -msgstr "വിജയിച്ച ടൈം-ട്രയൽ റേസുകൾ" +msgstr "വിജയിച്ച സമയ-സാമർഥ്യ റേസുകൾ" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4286,13 +4286,13 @@ msgstr "പൂർത്തീകരിച്ച സാധാരണ റേസു #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:202 msgid "Time-trial races started" -msgstr "ആരംഭിച്ച ടൈം-ട്രയൽ റേസുകൾ" +msgstr "ആരംഭിച്ച സമയ-സാമർഥ്യ റേസുകൾ" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:204 msgid "Time-trial races finished" -msgstr "പൂർത്തീകരിച്ച ടൈം-ട്രയൽ റേസുകൾ" +msgstr "പൂർത്തീകരിച്ച സമയ-സാമർഥ്യ റേസുകൾ" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4467,7 +4467,7 @@ msgstr "ആരംഭിച്ച റേസുകൾ" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:288 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:294 msgid " (maximum on one official track)" -msgstr "(ഔദ്യോഗിക ട്രാക്കുകളിലൊന്നിലെ പരമാവധി)" +msgstr "(ഔദ്യോഗിക പാതയിലൊന്നിലെ പരമാവധി)" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4538,7 +4538,7 @@ msgstr "പൂർത്തീകരിച്ച മുട്ട വേട്ട #: src/states_screens/dialogs/achievement_progress_dialog.cpp:313 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:319 msgid " (official tracks matching the goal)" -msgstr "(ലക്ഷ്യവുമായി ചേരുന്ന ഔദ്യോഗിക ട്രാക്കുകൾ)" +msgstr "(ലക്ഷ്യവുമായി ചേരുന്ന ഔദ്യോഗിക പാതകൾ)" #: src/states_screens/dialogs/add_device_dialog.cpp:64 msgid "" @@ -4550,7 +4550,7 @@ msgstr "പുതിയ ഗെയിംപാഡുകളും ജോയിസ #. I18N: In the 'add new input device' dialog #: src/states_screens/dialogs/add_device_dialog.cpp:87 msgid "Add Wiimote" -msgstr "വിമോട്ട് ചേർക്കാം" +msgstr "വീമോട്ട് ചേർക്കാം" #. I18N: In the 'add new input device' dialog #: src/states_screens/dialogs/add_device_dialog.cpp:108 @@ -4797,7 +4797,7 @@ msgstr "ഇല്ല" #: src/states_screens/edit_gp_screen.cpp:151 #: src/states_screens/high_score_selection.cpp:138 msgid "Track" -msgstr "ട്രാക്ക്" +msgstr "പാത" #: src/states_screens/dialogs/high_score_info_dialog.cpp:110 #, c-format @@ -4939,7 +4939,7 @@ msgstr "യുദ്ധം പുനരാരംഭിക്കുക" #: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Exit Battle" -msgstr "യുദ്ധം വിടുക" +msgstr "യുദ്ധം ഉപേക്ഷിക്കുക" #: src/states_screens/dialogs/race_paused_dialog.cpp:146 #: src/states_screens/race_result_gui.cpp:350 @@ -4948,7 +4948,7 @@ msgstr "പുതിയ റേസ് രൂപീകരിക്കുക" #: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Exit Race" -msgstr "റേസ് വിടുക" +msgstr "റേസ് ഉപേക്ഷിക്കുക" #. I18N: In the network player dialog, indiciating a network #. player has no ranking @@ -5050,7 +5050,7 @@ msgstr "സെർവർ സ്ഥലം: %s" #: src/states_screens/dialogs/server_info_dialog.cpp:119 #, c-format msgid "Current track: %s" -msgstr "ഇപ്പോഴത്തെ ട്രാക്ക്: %s" +msgstr "ഇപ്പോഴത്തെ പാത: %s" #: src/states_screens/dialogs/server_info_dialog.cpp:129 msgid "Rank" @@ -5128,7 +5128,7 @@ msgstr "സ്വീകരിക്കുന്നു" #: src/states_screens/dialogs/vote_dialog.cpp:169 msgid "Fetching last vote" -msgstr "അവനാന വോട്ട് കണ്ടെടുക്കുന്നു" +msgstr "അവസാന വോട്ട് സമാഹരിക്കുന്നു" #: src/states_screens/dialogs/vote_dialog.cpp:188 msgid "You can adapt your previous rating by clicking the stars beneath." @@ -5152,7 +5152,7 @@ msgstr "വോട്ട് പ്രകടിപ്പിക്കുന്ന #: src/states_screens/online/tracks_screen.cpp:640 #: src/states_screens/tracks_and_gp_screen.cpp:310 msgid "Random Track" -msgstr "ആകസ്മിക ട്രാക്ക്" +msgstr "ആകസ്മിക പാത" #: src/states_screens/edit_gp_screen.cpp:117 #: src/states_screens/ghost_replay_selection.cpp:507 @@ -5164,7 +5164,7 @@ msgstr "നിങ്ങൾക്ക് '%s' നീക്കംചെയ്യണ #: src/states_screens/edit_gp_screen.cpp:134 #: src/states_screens/edit_gp_screen.cpp:382 msgid "Do you want to save your changes?" -msgstr "നിങ്ങളുടെ മാറ്റങ്ങൾ നിങ്ങൾക്കു സൂക്ഷിക്കണോ?" +msgstr "നിങ്ങളുടെ മാറ്റങ്ങൾ സൂക്ഷിക്കണമോ?" #: src/states_screens/edit_gp_screen.cpp:152 msgid "Laps" @@ -5186,7 +5186,7 @@ msgstr "നിങ്ങളുടെ ഗ്രാന്റ് പ്രീ സൂ #: src/states_screens/edit_track_screen.cpp:255 msgid "Select a track" -msgstr "ഒരു ട്രാക്ക് തിരഞ്ഞെടുക്കുക" +msgstr "ഒരു പാത തിരഞ്ഞെടുക്കുക" #: src/states_screens/feature_unlocked.cpp:254 #, c-format @@ -5222,7 +5222,7 @@ msgstr "വെല്ലുവിളി പൂർത്തീകരിച്ച #: src/states_screens/feature_unlocked.cpp:684 msgid "You unlocked track %0" -msgstr "നിങ്ങൾ തുറന്നു ട്രാക്ക് %0" +msgstr "നിങ്ങൾ തുറന്നു പാത %0" #: src/states_screens/feature_unlocked.cpp:730 msgid "You unlocked grand prix %0" @@ -5231,7 +5231,7 @@ msgstr "നിങ്ങൾ തുറന്നു ഗ്രാന്റ് പ് #: src/states_screens/ghost_replay_selection.cpp:153 msgctxt "column_name" msgid "Track" -msgstr "ട്രാക്ക്" +msgstr "പാത" #: src/states_screens/ghost_replay_selection.cpp:164 #: src/states_screens/online/server_selection.cpp:134 @@ -5368,7 +5368,7 @@ msgstr "%s-ന്റെ സെർവർ" #. I18N: In the create server screen #: src/states_screens/online/create_server_screen.cpp:215 msgid "No. of grand prix track(s)" -msgstr "ഗ്രാന്റ് പ്രീ ട്രാക്കുകളുടെ എണ്ണം" +msgstr "ഗ്രാന്റ് പ്രീ പഥങ്ങളുടെ എണ്ണം" #: src/states_screens/online/create_server_screen.cpp:298 msgid "Name has to be between 4 and 30 characters long!" @@ -5545,7 +5545,7 @@ msgstr "തിരയുന്നു" #: src/states_screens/online/register_screen.cpp:169 #: src/states_screens/options/user_screen.cpp:127 msgid "Exit game" -msgstr "ഗെയിം വിടുക" +msgstr "ഗെയിം ഉപേക്ഷിക്കുക" #: src/states_screens/online/register_screen.cpp:282 #: src/states_screens/online/register_screen.cpp:289 @@ -5569,7 +5569,7 @@ msgstr "ഇമെയിലുകൾ തമ്മിൽ യോജിക്കു msgid "" "Online username can only contain alphanumeric (ASCII) characters, periods, " "dashes and underscores!" -msgstr "" +msgstr "ഓൺലൈൻ ഉപയോക്തൃനാമത്തിൽ ആൽഫാന്യൂമെറിക്ക് (ASCII) പ്രതീകങ്ങളും, മാത്രകളും, വരകളും, പിന്നെ അടിവരകളും മാത്രമേ ഉണ്ടാകുവാൻ പാടുള്ളൂ." #: src/states_screens/online/register_screen.cpp:374 msgid "Online username has to be between 3 and 30 characters long!" @@ -5618,7 +5618,7 @@ msgstr "ഉടമ" #: src/states_screens/online/server_selection.cpp:142 msgctxt "column_name" msgid "Distance (km)" -msgstr "അകലം (കി.മി.)" +msgstr "ദൂരം (കി.മി.)" #. I18N: In server selection screen, unknown distance to server #: src/states_screens/online/server_selection.cpp:318 @@ -5652,7 +5652,7 @@ msgstr "സെർവർ ബുക്ക്മാർക്കുകൾ" msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." -msgstr "ഒരു ഭൂരിപക്ഷം കളിക്കാർ എല്ലാം സമാന ട്രാക്ക്, റേസ് ക്രമീകരണങ്ങൾ എന്നിവ തിരഞ്ഞെടുത്താൽ, വോട്ടിംഗ് വേഗം തീരും." +msgstr "ഒരു ഭൂരിപക്ഷം കളിക്കാർ എല്ലാം സമാന പാത, റേസ് ക്രമീകരണങ്ങൾ എന്നിവ തിരഞ്ഞെടുത്താൽ, വോട്ടിംഗ് വേഗം തീരും." #. I18N: In track screen #. I18N: In the track info screen @@ -5812,7 +5812,7 @@ msgstr "നിങ്ങൾക്ക് ഈ ക്രമീകരണം എന് #: src/states_screens/options/options_screen_device.cpp:641 msgid "Enter new configuration name, leave empty to revert default value." -msgstr "പുതിയ ക്രമീകരണനാമം എഴുതുക, സ്വതേയുള്ള മൂല്യം നിലനിർത്താൻ ശൂന്യമായി ഇടുക." +msgstr "പുതിയ ക്രമീകരണനാമം എഴുതുക, സ്വതേയുള്ള മൂല്യം പ്രതിഗമിക്കുവാൻ ശൂന്യമായി ഇടുക." #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. @@ -5820,7 +5820,7 @@ msgstr "പുതിയ ക്രമീകരണനാമം എഴുതുക, msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" -msgstr "സംഘറേസ് മോഡിൽ, കളിക്കാർക്ക് ദൗർഭല്യ\n(കൂടുതൽ പ്രയാസമുള്ള) പ്രൊഫൈലുകൾ കാർട്ട്\nതിരഞ്ഞെടുക്കൽ സ്ക്രീനിൽ തിരഞ്ഞെടുക്കാൻ\nകഴിയും" +msgstr "സംഘറേസ് മോഡിൽ, കളിക്കാർക്ക് കാർട്ട് തിരഞ്ഞെ-\nടുക്കൽ സ്ക്രീനിൽ ദൗർഭല്യ (കൂടുതൽ പ്രയാസമുള്ള)\nപ്രൊഫൈലുകൾ കൈകൊള്ളാൻ കഴിയും" #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server @@ -6034,13 +6034,13 @@ msgstr "'%s' ലോഗിൻ ചെയ്യുന്നു" #: src/states_screens/options/user_screen.cpp:659 msgid "You can't delete the only player." -msgstr "ശേഷിക്കുന്ന കളിക്കാരനെ ഇല്ലാതാക്കാനാനില്ല." +msgstr "ശേഷിക്കുന്ന കളിക്കാരനെ ഇല്ലാതാക്കാനാകില്ല." #. I18N: In the player info dialog (when deleting) #: src/states_screens/options/user_screen.cpp:667 #, c-format msgid "Do you really want to delete player '%s'?" -msgstr "നിങ്ങൾക്ക് ശരിക്കും '%s' എന്നയാളെ നീക്കംചെയ്യണോ?" +msgstr "നിങ്ങൾക്ക് ശരിക്കും '%s' എന്നയാളെ നീക്കംചെയ്യണമോ?" #. I18N: as in "ready, set, go", shown at the beginning of the race #: src/states_screens/race_gui_base.cpp:73 @@ -6150,7 +6150,7 @@ msgstr "തിരികെ മെനുവിലേക്ക്" #: src/states_screens/race_result_gui.cpp:536 msgid "Do you really want to abort the Grand Prix?" -msgstr "നിങ്ങൾക്ക് ശരിക്കും ഗ്രാന്റ് പ്രീ നിഷ്ഫലമാക്കണോ?" +msgstr "നിങ്ങൾക്ക് ശരിക്കും ഗ്രാന്റ് പ്രീ നിഷ്ഫലമാക്കണമോ?" #: src/states_screens/race_result_gui.cpp:636 #: src/states_screens/race_result_gui.cpp:1529 @@ -6186,7 +6186,7 @@ msgstr "(സ്വയം ഗോൾ)" #: src/states_screens/race_result_gui.cpp:1749 #, c-format msgid "Track %i/%i" -msgstr "ട്രാക്ക്: %i/%i" +msgstr "പാത: %i/%i" #: src/states_screens/race_result_gui.cpp:1833 msgid "Grand Prix progress:" @@ -6210,7 +6210,7 @@ msgstr "%s കൈവരിച്ചു" #: src/states_screens/race_result_gui.cpp:2104 msgid "You completed the challenge!" -msgstr "നിങ്ങൾ വെല്ലുവിളി പൂർത്തീകരിച്ചിരിക്കുന്നു!" +msgstr "നിങ്ങൾ വെല്ലുവിളി\n പൂർത്തീകരിച്ചിരിക്കുന്നു!" #: src/states_screens/race_result_gui.cpp:2104 msgid "You failed the challenge!" @@ -6243,7 +6243,7 @@ msgstr "ഗോളുകൾ കൊയ്യാൻ എതിർക്കൂട് #: src/states_screens/race_setup_screen.cpp:130 msgid "Explore tracks to find all hidden eggs" -msgstr "ട്രാക്കുകൾ സന്ദർശിച്ച് ഒളിഞ്ഞിരിക്കുന്ന എല്ലാ മുട്ടകളും കണ്ടെത്തുക." +msgstr "വിവിധ സ്ഥലങ്ങൾ സന്ദർശിച്ച് ഒളിഞ്ഞിരിക്കുന്ന എല്ലാ മുട്ടകളും കണ്ടെത്തുക." #: src/states_screens/race_setup_screen.cpp:138 msgid "Race against ghost karts and try to beat them!" @@ -6263,7 +6263,7 @@ msgstr "ടീം മാറ്റുവാൻ സോക്കർ ഐകൺ ച #: src/states_screens/track_info_screen.cpp:149 #, c-format msgid "Track by %s" -msgstr "ട്രാക്ക് നിർമ്മിച്ചത്: %s" +msgstr "പാത നിർമ്മിച്ചത്: %s" #. I18N: the max players supported by an arena. #: src/states_screens/track_info_screen.cpp:157 @@ -6279,7 +6279,7 @@ msgstr "ചുവപ്പ് ടീം AI കാർട്ടുകളുടെ msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" -msgstr "ഈ ഗ്രാന്റ് പ്രീയിൽ അടങ്ങിയിരിക്കുന്ന ചില ട്രാക്കുകൾ തുറക്കപ്പെടാത്തതിനാൽ കളിക്കാൻ സാധിക്കുന്നതല്ല." +msgstr "ഈ ഗ്രാന്റ് പ്രീയിൽ അടങ്ങിയിരിക്കുന്ന ചില പാതകൾ തുറക്കപ്പെടാത്തതിനാൽ കളിക്കാൻ സാധിക്കുന്നതല്ല." #: src/states_screens/tracks_and_gp_screen.cpp:217 msgid "Locked!" @@ -6317,7 +6317,7 @@ msgstr "ഈ വെല്ലുവിളിയിൽ പ്രവേശി\n-ക #: ../stk-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." -msgstr "<%s> ത്വരിപ്പിക്കുവാൻ, പിന്നെ വളയ്ക്കുവാൻ <%s> പിന്നെ <%s>" +msgstr "<%s> ത്വരിപ്പിക്കുവാൻ, കൂടാതെ വളയ്ക്കുവാൻ <%s> പിന്നെ <%s>" #: ../stk-assets/tracks/tutorial/scripting.as:17 msgid "" @@ -6401,7 +6401,7 @@ msgstr "സ്കിഡ്ഡ് ചെയ്യാൻ ത്വരണംചെ msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" -msgstr "കുറേനിമിഷത്തേക്ക് നിങ്ങൾ സ്കിഡ്ഡ് കൈകാര്യം ചെയ്താൽ, ഒരു പ്രതിഫലമായി നിങ്ങൾക്കൊരു വേഗോന്നതി ബോണസ് ലഭിക്കുമെന്ന് ഓർക്കുക!" +msgstr "കുറേനിമിഷത്തേക്ക് നിങ്ങൾ സ്കിഡ്ഡ് കൈകാര്യം ചെയ്താൽ, പ്രതിഫലമെന്നോണം നിങ്ങൾക്കൊരു വേഗോന്നതി ബോണസ് ലഭിക്കുമെന്ന് ഓർക്കുക!" #: ../stk-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" @@ -6425,7 +6425,7 @@ msgid "" "variety of characters, tracks, and modes to play. Our aim is to create a " "game that is more fun than realistic, and provide an enjoyable experience " "for all ages." -msgstr "കാർട്ടുകൾ. നൈട്രോ. ആക്ഷൻ! സൂപ്പർടക്സ്കാർട്ട് വൈവിധ്യമാർന്ന കഥാപാത്രങ്ങളും, ട്രാക്കുകളും, കളിക്കുവാൻ പല മോഡുകളും അണിനിരക്കുന്ന ഒരു സ്വതന്ത്ര 3D ആർക്കേഡ് റേസറാണ്. യാഥാർത്ഥ്യം എന്നതിലുപരി രസകരമായ, എല്ലാ പ്രായക്കാരിലും ആസ്വാദ്യാനുഭവം ഉളവാക്കുന്ന ഒരു ഗെയിം സൃഷ്ടിക്കുക എന്നതാണ് ഞങ്ങളുടെ ലക്ഷ്യം." +msgstr "കാർട്ടുകൾ. നൈട്രോ. ആക്ഷൻ! സൂപ്പർടക്സ്കാർട്ട് വൈവിധ്യമാർന്ന കഥാപാത്രങ്ങളും, സ്ഥലങ്ങളും, കളിക്കുവാൻ പല മോഡുകളും അണിനിരക്കുന്ന ഒരു സ്വതന്ത്ര 3D ആർക്കേഡ് റേസറാണ്. യാഥാർത്ഥ്യം എന്നതിലുപരി രസകരമായ, എല്ലാ പ്രായക്കാരിലും ആസ്വാദ്യാനുഭവം ഉളവാക്കുന്ന ഒരു ഗെയിം സൃഷ്ടിക്കുക എന്നതാണ് ഞങ്ങളുടെ ലക്ഷ്യം." #: supertuxkart.appdata.xml:11 msgid "" @@ -6434,7 +6434,7 @@ msgid "" " while avoiding other karts as they may overtake you, but don't eat the " "bananas! Watch for bowling balls, plungers, bubble gum, and cakes thrown by " "your opponents." -msgstr "കളിക്കാരുടെ ആസ്വാദനത്തിനായി ഞങ്ങൾ അവതരിപ്പിക്കുന്നു വിവിധ ആശയങ്ങൾ ഉൾക്കൊള്ളിച്ച ട്രാക്കുകൾ, പന്തയം ആഴക്കടൽ, ഗ്രാമീണ കൃഷിയിടങ്ങൾ, വനങ്ങൾ എന്നിവയിൽ തുടങ്ങി ശൂന്യകാശം വരെയെത്തുന്നു! മറ്റു കാർട്ടുകൾ നിങ്ങളെ എതിരിടുമെന്നതിനാൽ അവരെ പരമാവധി ഒഴിവാക്കാൻ ശ്രമിക്കുക, പക്ഷേ പഴത്തൊലികൾ തിന്നരുത്! നിങ്ങളുടെ എതിരാളികൾ എറിയുന്ന ബൗളിംഗ് ബോളുകൾ, പ്ലഞ്ചറുകൾ, ബബിൾ ഗം, പിന്നെ കേക്കുകൾ എന്നിവയ്ക്കുമേൽ ഒരു കണ്ണു വേണം." +msgstr "കളിക്കാരുടെ ആസ്വാദനത്തിനായി ഞങ്ങൾ അവതരിപ്പിക്കുന്നു വിവിധ ആശയങ്ങൾ ഉൾക്കൊള്ളിച്ച പാതകൾ, പന്തയം ആഴക്കടലിൽ തുടങ്ങി, ഗ്രാമീണ കൃഷിയിടങ്ങളും, വനങ്ങളും കടന്ന് ശൂന്യകാശം വരെയെത്തുന്നു! മറ്റു കാർട്ടുകൾ നിങ്ങളെ എതിരിടുമെന്നതിനാൽ അവരെ പരമാവധി ഒഴിവാക്കാൻ ശ്രമിക്കുക, പക്ഷേ പഴത്തൊലികൾ തിന്നരുത്! നിങ്ങളുടെ എതിരാളികൾ എറിയുന്ന ബൗളിംഗ് ബോളുകൾ, പ്ലഞ്ചറുകൾ, ബബിൾ ഗം, പിന്നെ കേക്കുകൾ എന്നിവയ്ക്കുമേൽ ഒരു കണ്ണു വേണം." #: supertuxkart.appdata.xml:14 msgid "" @@ -6443,11 +6443,11 @@ msgid "" "battle mode against the computer or your friends, and more! For a greater " "challenge, join online and meet players from all over the world and prove " "your racing skills!" -msgstr "മറ്റു കാർട്ടുകൾക്കെതിരെ നിങ്ങൾക്ക് ഒരു ഒറ്റയാൾ റേസ് നടത്താൻ സാധിക്കും, ഒരുപാട് ഗ്രാന്റ് പ്രീകളിലൊന്നിൽ മത്സരിക്കാനും, നിങ്ങൾക്ക് സ്വന്തമായി ടൈം ട്രയലുകളിലെ ഉയർന്ന സ്കോർ പരാജയപ്പെടുത്താനും, കമ്പ്യൂട്ടറിനോ നിങ്ങളുടെ സുഹൃത്തുക്കൾക്കോ എതിരെ യുദ്ധമോഡിൽ കളിക്കാനും കൂടാതെ ധാരാളം! വിപുലമായ ഒരു വെല്ലുവിളിക്കായി, ഓൺലൈനിൽ ചേർന്ന് ലോകത്താകമാനമുള്ള കളിക്കാരെ കണ്ടുമുട്ടി നിങ്ങളുടെ റേസിംഗ് മിടുക്കുകൾ തെളിയിക്കു!" +msgstr "മറ്റു കാർട്ടുകൾക്കെതിരെ നിങ്ങൾക്ക് ഒരു ഒറ്റയാൾ റേസ് നടത്താൻ സാധിക്കും, ഒരുപാട് ഗ്രാന്റ് പ്രീകളിലൊന്നിൽ മത്സരിക്കാനും, നിങ്ങൾക്ക് സ്വന്തമായി സമയ-സാമർഥ്യ കളികളിലെ ഉയർന്ന സ്കോർ പരാജയപ്പെടുത്താനും, കമ്പ്യൂട്ടറിനോ നിങ്ങളുടെ സുഹൃത്തുക്കൾക്കോ എതിരെ യുദ്ധമോഡിൽ കളിക്കാനും കൂടാതെ ധാരാളം! വിപുലമായ ഒരു വെല്ലുവിളിക്കായി, ഓൺലൈനിൽ ചേർന്ന് ലോകത്താകമാനമുള്ള കളിക്കാരെ കണ്ടുമുട്ടി നിങ്ങളുടെ റേസിംഗ് മിടുക്കുകൾ തെളിയിക്കു!" #: supertuxkart.appdata.xml:17 msgid "This game has no ads." -msgstr "ഈ ഗെയിം പരസ്യരഹിതമാണ്" +msgstr "ഈ ഗെയിം പരസ്യരഹിതമാണ്." #: supertuxkart.appdata.xml:20 msgid "" diff --git a/data/po/nb.po b/data/po/nb.po index 13169657f41..d19da837119 100644 --- a/data/po/nb.po +++ b/data/po/nb.po @@ -12,13 +12,14 @@ # IAN RODRÍGUEZ Lorenzo, 2022 # Karl Ove Hufthammer , 2015 # Magne Djupvik , 2017-2018 +# Stian Onarheim, 2023 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Karl Ove Hufthammer , 2015\n" +"Last-Translator: Stian Onarheim, 2023\n" "Language-Team: Norwegian Bokmål (http://app.transifex.com/supertuxkart/supertuxkart/language/nb/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -376,7 +377,7 @@ msgstr "Ja" #. I18N: In the 'confirm resolution' dialog, that's shown when switching #. resoluton msgid "Revert" -msgstr "" +msgstr "Tilbakestill" #. I18N: ./data/gui/dialogs/confirm_resolution_dialog.stkgui #. I18N: In the 'confirm resolution' dialog, that's shown when switching @@ -917,7 +918,7 @@ msgstr "Brukerinfo" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Fjern venn" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -927,17 +928,17 @@ msgstr "Legg til venn" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Godta invitasjon" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Avslå invitasjon" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Vis profil" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1125,7 +1126,7 @@ msgstr "Bidragsytere" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Hopp over" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -2333,7 +2334,7 @@ msgstr "" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" -msgstr "" +msgstr "Maksimal FPS" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings @@ -3625,7 +3626,7 @@ msgstr "Du vant løpet!" #: src/karts/kart.cpp:1026 #, c-format msgid "You finished the race in rank %d!" -msgstr "" +msgstr "Du fullførte løpet på %d. plass!" #. I18N: Message shown in game to tell player left the game in network #: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 @@ -3773,7 +3774,7 @@ msgstr "" #: src/network/protocols/client_lobby.cpp:463 #: src/network/protocols/server_lobby.cpp:3848 msgid "Bot" -msgstr "" +msgstr "Bot" #: src/network/protocols/client_lobby.cpp:641 #, c-format diff --git a/data/po/oc.po b/data/po/oc.po index 26ae72bb47b..635a05e9f06 100644 --- a/data/po/oc.po +++ b/data/po/oc.po @@ -3,16 +3,17 @@ # This file is distributed under the same license as the supertuxkart package. # # Translators: +# Arturo Chacho Corte, 2024 # Quentin PAGÈS, 2020 -# Quentin PAGÈS, 2020-2023 -# Quentin PAGÈS, 2020 +# Quentin PAGÈS, 2020-2024 +# Quentin PAGÈS, 2020,2024 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Quentin PAGÈS, 2020-2023\n" +"Last-Translator: Arturo Chacho Corte, 2024\n" "Language-Team: Occitan (post 1500) (http://app.transifex.com/supertuxkart/supertuxkart/language/oc/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -44,39 +45,39 @@ msgstr "Christoffel Columbus" #. I18N: ./data/achievements.xml msgid "Play every official track at least once." -msgstr "" +msgstr "Jogar totas las pistas almens un còp" #. I18N: ./data/achievements.xml msgid "Strike!" -msgstr "" +msgstr "En lo blanc !" #. I18N: ./data/achievements.xml msgid "Hit 10 karts with a bowling-ball." -msgstr "" +msgstr "Tustar 10 karts amb una bòla de quilhas." #. I18N: ./data/achievements.xml msgid "Arch Enemy" -msgstr "" +msgstr "Enemigàs" #. I18N: ./data/achievements.xml msgid "Hit the same kart at least 5 times in one race." -msgstr "" +msgstr "Tustar lo meteis kart 5 còps dins una corsa." #. I18N: ./data/achievements.xml msgid "Marathoner" -msgstr "" +msgstr "Corredor de maratons" #. I18N: ./data/achievements.xml msgid "Finish a race with at least twice the track's default lap number." -msgstr "" +msgstr "Acabar una corsa amb almens dos còps lo nombre de torns per defaut." #. I18N: ./data/achievements.xml msgid "Skid-row" -msgstr "" +msgstr "Escarta compulsiva" #. I18N: ./data/achievements.xml msgid "Skid 5 times in a single lap." -msgstr "" +msgstr "S'escampa 5 còps en un sol torn." #. I18N: ./data/achievements.xml msgid "Gold driver" @@ -86,25 +87,25 @@ msgstr "Conductor en aur" msgid "" "Win against at least 3 AIs in normal race, time-trial, and follow the " "leader." -msgstr "" +msgstr "Gana contra un minimum de 3 oponents contrarotlats per l'ordinator en carrièra normala, contracloc o seguent lo líder." #. I18N: ./data/achievements.xml msgid "Powerup Love" -msgstr "" +msgstr "Amant de las melhoracions" #. I18N: ./data/achievements.xml msgid "Use 10 or more powerups in a race." -msgstr "" +msgstr "Utiliza 10 o mai melhoracions dins una corsa." #. I18N: ./data/achievements.xml msgid "Unstoppable" -msgstr "" +msgstr "Imparabla" #. I18N: ./data/achievements.xml msgid "" "Win 5 single races in a row against at least 3 AIs. Beware, restarting a " "race counts as a loss." -msgstr "" +msgstr "Ganha 5 carrièras de seguida amb al mens 3 oponents. Atencion, reiniciar una carrièra compta coma perduda." #. I18N: ./data/achievements.xml msgid "Banana Lover" @@ -124,39 +125,39 @@ msgstr "Vertadièrament ... un secrèt." #. I18N: ./data/achievements.xml msgid "Mosquito Hunter" -msgstr "Caçador de moscas" +msgstr "Caçador de moissals" #. I18N: ./data/achievements.xml msgid "" "Take your opponents for mosquitos! With the swatter, squash them at least 5 " "times in a race." -msgstr "" +msgstr "Prenètz vòstre adversaris per de moissals ! Amb la grelha de fageda, esclafatz-las almens 5 còps dins una corsa." #. I18N: ./data/achievements.xml msgid "Beyond Luck" -msgstr "" +msgstr "Al delà de la fortuna" #. I18N: ./data/achievements.xml msgid "" "Win 10 single races in a row in Expert or SuperTux against at least 5 AIs. " "Beware, restarting a race counts as a loss." -msgstr "" +msgstr "Ganha 10 carrièras normalas seguidas en mòde Expert o SuperTux contra al mens 5 oponents. Atencion, reiniciar una carrièra compta coma perduda." #. I18N: ./data/grandprix/1_penguinplayground.grandprix msgid "Penguin Playground" -msgstr "" +msgstr "Lo pati del Penguin" #. I18N: ./data/grandprix/2_offthebeatentrack.grandprix msgid "Off the Beaten Track" -msgstr "" +msgstr "Fòra del circuit habitual" #. I18N: ./data/grandprix/3_tothemoonandback.grandprix msgid "To the Moon and Back" -msgstr "" +msgstr "Fins a la luna e tornar" #. I18N: ./data/grandprix/4_atworldsend.grandprix msgid "At World's End" -msgstr "" +msgstr "A la fin del monde" #. I18N: ./data/gui/dialogs/addons_loading.stkgui #. I18N: Add-on screen action @@ -185,7 +186,7 @@ msgstr "Desinstallar" #. I18N: ./data/gui/dialogs/android/init_android.stkgui msgid "Select a type of control that you prefer" -msgstr "" +msgstr "Seleccionatz vòstre tipe de contraròtle preferit" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type @@ -193,7 +194,7 @@ msgstr "" #. I18N: In the multitouch settings screen #: src/states_screens/dialogs/race_paused_dialog.cpp:549 msgid "Accelerometer" -msgstr "" +msgstr "Acceleromètre" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type @@ -213,7 +214,7 @@ msgstr "Giroscòpi" #. I18N: Control type #: src/states_screens/dialogs/race_paused_dialog.cpp:544 msgid "Steering wheel" -msgstr "" +msgstr "Volant" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui @@ -288,7 +289,7 @@ msgstr "Botons inversats" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Buttons scale" -msgstr "" +msgstr "Escala dels botons" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -370,7 +371,7 @@ msgstr "Òc" #. I18N: In the 'confirm resolution' dialog, that's shown when switching #. resoluton msgid "Revert" -msgstr "" +msgstr "Reversar" #. I18N: ./data/gui/dialogs/confirm_resolution_dialog.stkgui #. I18N: In the 'confirm resolution' dialog, that's shown when switching @@ -392,7 +393,7 @@ msgstr "Camèra jogaire" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "FOV" -msgstr "" +msgstr "Camp de vision" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -417,7 +418,7 @@ msgstr "Camèra arrièra" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "Follow ball in soccer mode" -msgstr "" +msgstr "Seguís la bala en mòde balonpè" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -431,7 +432,7 @@ msgstr "Paramètres grafics" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Advanced pipeline (lights, etc.)" -msgstr "" +msgstr "Efèctes avançats (luces, etc.)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -441,17 +442,17 @@ msgstr "Ombras" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Bloom" -msgstr "" +msgstr "Resplendor" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Light shaft (God rays)" -msgstr "" +msgstr "Rais de Dieu" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Ambient occlusion" -msgstr "" +msgstr "Occlusion environamentala" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -461,27 +462,27 @@ msgstr "Prigondor de camp" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Glow (Outlines)" -msgstr "" +msgstr "Brilhatge (conurbas)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Anti-aliasing" -msgstr "" +msgstr "Suavitat" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Motion blur" -msgstr "" +msgstr "Difusion de movement" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Image-based lighting" -msgstr "" +msgstr "Iluminacion basada en imatges" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Light Scattering" -msgstr "" +msgstr "Dispersion luminosa" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -496,22 +497,22 @@ msgstr "Compression textura" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Particle effects" -msgstr "" +msgstr "Efectes de particulas" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Rendered image quality" -msgstr "" +msgstr "Qualitat de l'imatge processat" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Geometry detail" -msgstr "" +msgstr "Detalh geometric" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "* Restart STK to apply new settings" -msgstr "" +msgstr "* Reset STK per aplicar la novèla configuracion" #. I18N: ./data/gui/dialogs/debug_slider.stkgui #. I18N: ./data/gui/dialogs/online/recovery_info.stkgui @@ -554,17 +555,17 @@ msgstr "D’acordi" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen msgid "Record the race for ghost replay" -msgstr "" +msgstr "Regardar la corsa per una repeticion fantasma" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info action msgid "Watch replay only" -msgstr "" +msgstr "Veire sonque la repeticion" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info action msgid "Compare to another ghost" -msgstr "" +msgstr "Comparar amb un autre fantasma" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info action @@ -580,7 +581,7 @@ msgstr "Suprimir" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info screen action msgid "Compare ghost" -msgstr "" +msgstr "Comparar fantasma" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info screen action @@ -708,13 +709,13 @@ msgstr "Recuperacion de compte" msgid "" "You will receive an email with further instructions on how to reset your " "password. Please be patient and be sure to check your spam folder." -msgstr "" +msgstr "Recebràs un mail amb mai d'instruccions per restablir ton senhal. Per favor, siatz pacient e asseguratz-vos de verificar la carpeta de corrièr indesit." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui msgid "" "Fill in the username and email address you supplied at registration to be " "able to reset your password." -msgstr "" +msgstr "Escrivètz lo nom d'utilizaire e l'adreça de corrièr electronic qu'avètz utilizat a l'enregistrament per poder recuperar lo senhal." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog @@ -737,7 +738,7 @@ msgstr "Corrièl" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog msgid "Terms and Agreement" -msgstr "" +msgstr "Termes e Condicions" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog @@ -836,7 +837,7 @@ msgstr "Corsa normala" #. I18N: Game mode #: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 msgid "Time Trial" -msgstr "" +msgstr "Contraròtle del temps" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: Multiplayer game mode @@ -891,7 +892,7 @@ msgstr "Desavantatge" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "Press the 'All players ready' button after the player list is ready." -msgstr "" +msgstr "Premètz lo boton \"Totes los jogaires son prèstes\" quand es atal." #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network @@ -911,7 +912,7 @@ msgstr "Info jogaire" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Levar amic" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -921,17 +922,17 @@ msgstr "Ajustar amic" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Acceptar invitacion" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Refusar invitacion" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Veire perfil" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -961,17 +962,17 @@ msgstr "Causir kart" #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When changing input configurations msgid "Press fully and release..." -msgstr "" +msgstr "Puls prigond e desliura" #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input msgid "Assign to ESC key" -msgstr "" +msgstr "Assignar a la clau ESC" #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input msgid "Assign nothing" -msgstr "" +msgstr "Assignar pas res" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui @@ -1119,7 +1120,7 @@ msgstr "Crèdits" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Omitir" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1133,7 +1134,7 @@ msgstr "Totas las pistas" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Title in edit grand prix screen msgid "Edit Grand Prix" -msgstr "" +msgstr "Modificar campionat" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item @@ -1174,12 +1175,12 @@ msgstr "Nombre de torns :" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: In the edit track screen msgid "Reverse:" -msgstr "" +msgstr "Al revèrs" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Ghost Replay Selection" -msgstr "" +msgstr "Seleccion de repeticion fantasma" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen @@ -1193,32 +1194,32 @@ msgstr "Cèrca d’uòus" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Only show the best times" -msgstr "" +msgstr "Mostrar sonque los melhors temps" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Compare replay" -msgstr "" +msgstr "Comparar repeticion" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Only show replays matching the current difficulty" -msgstr "" +msgstr "Mostrar solament las repeticions que coincidisson amb la dificultat actuala" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Only show replays matching the current version" -msgstr "" +msgstr "Mostrar solament las repeticions que coincidisson amb la version actuala" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Hide multiplayer replays" -msgstr "" +msgstr "Amagar las repeticions multijugador" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Record a ghost replay" -msgstr "" +msgstr "Gravar una repeticion fantasma" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen @@ -1238,23 +1239,23 @@ msgstr "Sens invèrse" #: src/states_screens/track_info_screen.cpp:284 #: src/states_screens/track_info_screen.cpp:450 msgid "Maximum time (min.)" -msgstr "" +msgstr "Durada maximala (min.)" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen msgid "Track group" -msgstr "" +msgstr "Grop de circuits" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #: src/states_screens/gp_info_screen.cpp:164 msgid "Continue saved GP" -msgstr "" +msgstr "Contunhar un campionat gardat" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Title in grand prix editor screen msgid "Grand Prix editor" -msgstr "" +msgstr "Editor de campionats" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item @@ -1279,7 +1280,7 @@ msgstr "Renomenar" #. I18N: ./data/gui/screens/grand_prix_lose.stkgui #. I18N: ./data/gui/screens/grand_prix_win.stkgui msgid "Save Grand Prix" -msgstr "" +msgstr "Gardar lo campionat" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: ./data/gui/screens/help2.stkgui @@ -1323,7 +1324,7 @@ msgstr "Mòdes de jòcs" #. I18N: ./data/gui/screens/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" -msgstr "" +msgstr "Melhoraments" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: Tab in help menu @@ -1377,7 +1378,7 @@ msgstr "Mòde istòria" #. I18N: ./data/gui/screens/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" -msgstr "" +msgstr "Clasas de karts" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: Tab in help menu @@ -1403,7 +1404,7 @@ msgstr "Començar lo tutorial" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." -msgstr "" +msgstr "Pren las caissas blavas, vos balharàn de melhoraments." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu @@ -1417,14 +1418,14 @@ msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " "pressing the appropriate key or button. You can see your current level of " "nitro in the gauge at the bottom-right of the race screen." -msgstr "" +msgstr "Prenent de nitròs vos permet d'aténher mai de velocitat quand volètz en pressionant la clau o boton correspondent. Podètz veire vòstre nivèl actual de nitro dins l'indicador situat en bas drech de l'ecran de jòc." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." -msgstr "" +msgstr "Se vesètz un boton amb un blocatge coma aqueste, vos cal completar un desfís per lo desblocar." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu @@ -1433,34 +1434,34 @@ msgid "" "help to take sharp turns; while medium skids will boost your speed, long " "skids more so. You can't stop turning while skidding, so orient your kart " "carefully before!" -msgstr "" +msgstr "Podètz desliurar en pressionant una tecla o boton especial. Las desliuras cortas e seguidas vos ajudan a prene de corbas tancadas. Los mèdias aumentan ta velocitat, e los longs encara mai. Podètz pas daissar de virar quand desliratz, doncas orienta ben vòstre kart abans!" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." -msgstr "" +msgstr "Podètz obténer un melhorament del començament en quichant lo boton d'acceleracion al « Fuòc ! », abans de començar la corsa." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" -msgstr "" +msgstr "* L'assignacion de teclas actuala se pòt veire/canbiar dins lo menú Opcions." #. I18N: ./data/gui/screens/help2.stkgui msgid "SuperTuxKart features several game modes:" -msgstr "" +msgstr "SuperTuxKart a diferents mòdes de jòc:" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" -msgstr "" +msgstr "Carrièra normala: Tot es permés, pren de melhoracions e fa bona utilizacion d'elas!" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" -msgstr "" +msgstr "Controla-temps: I a pas de melhoracions, donc importa sonque vòstra habilitat al volant!" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1468,7 +1469,7 @@ msgid "" "Follow the leader: Run for second place, as the last kart will be " "disqualified every time the counter hits zero. Beware: going in front of the" " leader will get you eliminated too!" -msgstr "" +msgstr "Seguir lo menaire : corrètz per la segonda plaça, perque lo darrièr kart serà desqualificat cada còp que lo comptador arriba a zèro. Atencion : anar davant lo menaire vos eliminarà tanben !" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1478,30 +1479,30 @@ msgid "" "player who hits others the most will win in a given hit or time limit. In " "Capture The Flag, your team needs to bring the flag of the other team to " "your own flag base, as long as your flag is not captured by the other team." -msgstr "" +msgstr "I a 3 tipes de mòde de batalha : dins 3 Strikes Battle, cal tustar los autres amb d'armas fins que pèrdan tota lor vida. Dins Free-For-All, lo jogaire que mai tusta los autres ganharà dins un còp o un limit de temps donat. Dins Capture The Flag, vòstra equipa a besonh de portar la bandièra de l'autra equipa a vòstra pròpria basa de bandièra, tan que vòstra bandièra es pas capturada per l'autra equipa." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." -msgstr "" +msgstr "Fotbòl : utilizatz vòstre kart per possar la pelòta dins la gàbia." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." -msgstr "" +msgstr "Cèrca als uòus : exploratz las pistas per trobar totes los uòus amagats." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" -msgstr "" +msgstr "Reproduccion fantasma: Afrontatz de correires fantaumas contra lo relòtge o a la recèrca dels uòus perduts, e establissètz un recòrd novèl !" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "" +msgstr "Competicion de torns: Completatz ​​tant de torns que podètz dins un temps fixat." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1510,89 +1511,89 @@ msgid "" "instead of playing a single race, you play many in a row. The better you " "rank, the more points you get. In the end, the player with the most points " "wins the cup." -msgstr "" +msgstr " * La màger part d'aqueles mòdes de jòc pòdon tanben èsser jogats a l'estil del Grand Prèmi: en luòc de concórrer dins una sola corsa, concorretz dins divèrsas de seguida. Coma mai naut classatz, mai de punts obtenètz. A la fin, lo jogaire amb lo mai de punts ganha la copa." #. I18N: ./data/gui/screens/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" -msgstr "" +msgstr "Per vos ajudar a ganhar, i a qualques bonus que podètz collectar:" #. I18N: ./data/gui/screens/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." -msgstr "" +msgstr "Bombolha de Goma - protegissètz-vos amb un escut, o l'utilizatz en agachant enrè per daissar una flaca ròsa pegajosa darrièr vos." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" -msgstr "" +msgstr "Turbo - aumentarà fòrça vòstra velocitat, mas fasètz atencion que vòstre kart se descontrole pas!" #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." -msgstr "" +msgstr "Pastís - lançat a l'adversari mai pròche, melhor a distància pròcha e en linha drecha. Afecta tanben los karts pròches de l'explosion." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." -msgstr "" +msgstr "Plonger - botatz-lo endavant per tirar un adversari enrè, o botatz-lo en agachant darrièr per lo far pèrdre la vision." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." -msgstr "" +msgstr "Bola de bòla - va drecha fins que tusta quicòm, rebomba de las parets. Se fasètz cap a l'arrièr, la pelòta serà lançada cap a l'arrièr." #. I18N: ./data/gui/screens/help3.stkgui msgid "Parachute - slows down all karts in a better position." -msgstr "" +msgstr "Paracasuda - arrèsta totes los karts davant tu." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." -msgstr "" +msgstr "Escambiaire - las bóstias de present se convertisson en pèls de banana, las botelhas de nitro en goma de goma, e vice versa pendent aperaquí cinc segondas." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." -msgstr "" +msgstr "Basquetbòl - rebota après lo cap, e pòt esclafar o alentir los karts sus son camin." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." -msgstr "" +msgstr "Escrachaire de moscas - esclafarà los karts pròches, en los ralentissent. Pòt tanben èsser utilizat per eliminar de paracasuda e de bombas." #. I18N: ./data/gui/screens/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" -msgstr "" +msgstr "Tombar sus una banana pòt desencadenar çò seguent dins lo kart:" #. I18N: ./data/gui/screens/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." -msgstr "" +msgstr "Ancra - frena lo kart subte." #. I18N: ./data/gui/screens/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." -msgstr "" +msgstr "Paracasuda - frena lo kart, mai progressivament que l'ancra. Coma mai vite vas, mai dur te ralentirà." #. I18N: ./data/gui/screens/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." -msgstr "" +msgstr "Bomba - detona après un moment, lançant lo kart dins l'aire. Tustatz amb un autre kart per li passar la bomba." #. I18N: ./data/gui/screens/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" @@ -1670,7 +1671,7 @@ msgstr "" #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" -msgstr "" +msgstr "Se pòt jogar a SuperTuxKart en multijogaire en mòde en linha...:" #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1729,7 +1730,7 @@ msgstr "" #. time. #: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" -msgstr "" +msgstr "Torn d’ensag" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen @@ -1904,12 +1905,12 @@ msgstr "Vòstre perfil" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: ./data/gui/screens/online/profile_settings.stkgui msgid "..." -msgstr "" +msgstr "..." #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: In the achievements screen msgid "Player rankings" -msgstr "" +msgstr "Classament jogaires" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen @@ -2018,7 +2019,7 @@ msgstr "Utilizaire una connexion IPv6" #. I18N: ./data/gui/screens/online/user_search.stkgui msgid "User search" -msgstr "" +msgstr "Recèrca d’utilizaire" #. I18N: ./data/gui/screens/options_audio.stkgui #. I18N: ./data/gui/screens/options_device.stkgui @@ -2188,7 +2189,7 @@ msgstr "Desactivar la configuracion" #. I18N: ./data/gui/screens/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" -msgstr "" +msgstr "Tornar a la lista d’aparelhs" #. I18N: ./data/gui/screens/options_device.stkgui #. I18N: In the input configuration screen @@ -2208,7 +2209,7 @@ msgstr "Opcions Internet" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" -msgstr "" +msgstr "Mostrar totjorn la pantalha d'inici de session" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings @@ -2245,7 +2246,7 @@ msgstr "" #. I18N: In the input configuration screen #: src/states_screens/options/options_screen_input.cpp:212 msgid "Press enter or double-click on a device to configure it" -msgstr "" +msgstr "Quichar entrada o doble clicar sus un periferic per lo configurar" #. I18N: ./data/gui/screens/options_input.stkgui #. I18N: In the input configuration screen @@ -2287,12 +2288,12 @@ msgstr "Camèra" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." -msgstr "" +msgstr "Personalizar..." #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" -msgstr "" +msgstr "Afichar los FPS" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings @@ -2312,12 +2313,12 @@ msgstr "" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" -msgstr "" +msgstr "Resolucion de rendut" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" -msgstr "" +msgstr "Nivèl d’efièch grafic" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings @@ -2327,7 +2328,7 @@ msgstr "" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" -msgstr "" +msgstr "FPS maximals" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings @@ -2347,12 +2348,12 @@ msgstr "Ecran complet" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings msgid "Remember window location" -msgstr "" +msgstr "Memorizar l’emplaçament de la fenèstra" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings msgid "Apply new resolution" -msgstr "" +msgstr "Aplicar la resolucion novèla" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2568,7 +2569,7 @@ msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml msgid "Gnu" -msgstr "" +msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml msgid "Hexley" @@ -2596,11 +2597,11 @@ msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml msgid "Pepper" -msgstr "" +msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml msgid "Sara" -msgstr "" +msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml msgid "Suzanne" @@ -2620,15 +2621,15 @@ msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" -msgstr "" +msgstr "Avenc antediluvian" #. I18N: ../stk-assets/tracks/alien_signal/track.xml msgid "Alien Signal" -msgstr "" +msgstr "Senhal estrangièr" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" -msgstr "" +msgstr "Laberint del Colisèu ancian" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml @@ -2637,7 +2638,7 @@ msgstr "Ciutat de Candela" #. I18N: ../stk-assets/tracks/battleisland/track.xml msgid "Battle Island" -msgstr "" +msgstr "Illa de la batalha" #. I18N: ../stk-assets/tracks/black_forest/track.xml msgid "Black Forest" @@ -2653,11 +2654,11 @@ msgstr "Temple Cacau" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" -msgstr "" +msgstr "Passejada per la milhièra" #. I18N: ../stk-assets/tracks/fortmagma/track.xml msgid "Fort Magma" -msgstr "" +msgstr "Fòrt Magma" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" @@ -2704,7 +2705,7 @@ msgstr "" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "" +msgstr "Las dunas arena" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" @@ -2720,11 +2721,11 @@ msgstr "Mina anciana" #. I18N: ../stk-assets/tracks/minigolf/track.xml msgid "Minigolf" -msgstr "" +msgstr "Minigòlf" #. I18N: ../stk-assets/tracks/oasis/track.xml msgid "Oasis" -msgstr "" +msgstr "Oasis" #. I18N: ../stk-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" @@ -2736,19 +2737,19 @@ msgstr "Pargue de cojas" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" -msgstr "" +msgstr "Castelet Ravenbridge" #. I18N: ../stk-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" -msgstr "" +msgstr "Sablas movedissas" #. I18N: ../stk-assets/tracks/scotland/track.xml msgid "Nessie's Pond" -msgstr "" +msgstr "L’estanh de Nessie" #. I18N: ../stk-assets/tracks/snowmountain/track.xml msgid "Northern Resort" -msgstr "" +msgstr "Estacion balneària del nòrd" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" @@ -2756,7 +2757,7 @@ msgstr "" #. I18N: ../stk-assets/tracks/soccer_field/track.xml msgid "Soccer Field" -msgstr "" +msgstr "Estadi de fotbòl " #. I18N: ../stk-assets/tracks/stadium/track.xml msgid "The Stadium" @@ -2772,7 +2773,7 @@ msgstr "Temple" #. I18N: ../stk-assets/tracks/volcano_island/track.xml msgid "Volcan Island" -msgstr "" +msgstr "Illa volcanica" #. I18N: ../stk-assets/tracks/xr591/track.xml msgid "XR591" @@ -2789,7 +2790,7 @@ msgstr "" #: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 msgid "Failed to connect to the SuperTuxKart add-ons server." -msgstr "" +msgstr "Fracàs de la connexion al servidor de modul complementari de SuperTuxKart." #: src/addons/news_manager.cpp:180 #, c-format @@ -2829,7 +2830,7 @@ msgstr "" #: src/challenges/challenge_data.cpp:324 #: src/states_screens/dialogs/select_challenge.cpp:78 msgid "Mode: Reverse" -msgstr "" +msgstr "Mòde : inversat" #: src/challenges/challenge_data.cpp:601 #, c-format @@ -3034,7 +3035,7 @@ msgstr "Contraròtle" #: src/input/binding.cpp:116 msgctxt "input_key" msgid "Alt/Menu" -msgstr "" +msgstr "Alt/Menut" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:118 @@ -3107,13 +3108,13 @@ msgstr "Espaci" #: src/input/binding.cpp:141 msgctxt "input_key" msgid "Page Up" -msgstr "" +msgstr "Sageta amont" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:143 msgctxt "input_key" msgid "Page Down" -msgstr "" +msgstr "Sageta aval" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:145 @@ -3221,61 +3222,61 @@ msgstr "Mesa en velha" #: src/input/binding.cpp:215 msgctxt "input_key" msgid "Numpad 0" -msgstr "" +msgstr "Pavat numeric 0" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:217 msgctxt "input_key" msgid "Numpad 1" -msgstr "" +msgstr "Pavat numeric 1" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:219 msgctxt "input_key" msgid "Numpad 2" -msgstr "" +msgstr "Pavat numeric 2" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:221 msgctxt "input_key" msgid "Numpad 3" -msgstr "" +msgstr "Pavat numeric 3" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:223 msgctxt "input_key" msgid "Numpad 4" -msgstr "" +msgstr "Pavat numeric 4" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:225 msgctxt "input_key" msgid "Numpad 5" -msgstr "" +msgstr "Pavat numeric 5" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:227 msgctxt "input_key" msgid "Numpad 6" -msgstr "" +msgstr "Pavat numeric 6" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:229 msgctxt "input_key" msgid "Numpad 7" -msgstr "" +msgstr "Pavat numeric 7" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:231 msgctxt "input_key" msgid "Numpad 8" -msgstr "" +msgstr "Pavat numeric 8" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:233 msgctxt "input_key" msgid "Numpad 9" -msgstr "" +msgstr "Pavat numeric 9" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:237 @@ -3305,7 +3306,7 @@ msgstr "" #: src/input/binding.cpp:269 msgctxt "input_key" msgid "Num Lock" -msgstr "" +msgstr "Verr. num." #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:271 @@ -3453,7 +3454,7 @@ msgstr "" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:159 msgid "Guide" -msgstr "" +msgstr "Guida" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:161 @@ -3598,7 +3599,7 @@ msgstr "" #: src/karts/controller/local_player_controller.cpp:332 msgid "Don't accelerate before 'Set!'" -msgstr "" +msgstr "Acceleretz pas abans « Fuòc ! »" #: src/karts/controller/spare_tire_ai.cpp:150 msgid "You can have at most 3 lives!" @@ -3655,39 +3656,39 @@ msgstr "" #: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 msgid "Server connection timed out." -msgstr "" +msgstr "Relambi de connexion al servidor expirat." #. I18N: Show when a player gets the red flag in CTF #: src/modes/capture_the_flag.cpp:191 #, c-format msgid "%s has the red flag!" -msgstr "" +msgstr "%s a un drapèl roge !" #. I18N: Show when the red flag is returned to its base in CTF #: src/modes/capture_the_flag.cpp:198 msgid "The red flag has returned!" -msgstr "" +msgstr "Lo drapèl roge es tornat !" #. I18N: Show when a player gets the blue flag in CTF #: src/modes/capture_the_flag.cpp:209 #, c-format msgid "%s has the blue flag!" -msgstr "" +msgstr "%sa un drapèl blau !" #. I18N: Show when the blue flag is returned to its base in CTF #: src/modes/capture_the_flag.cpp:216 msgid "The blue flag has returned!" -msgstr "" +msgstr "Lo drapèl blau es tornat !" #: src/modes/capture_the_flag.cpp:424 #, c-format msgid "%s captured the blue flag!" -msgstr "" +msgstr "%s a capturat lo drapèl blau !" #: src/modes/capture_the_flag.cpp:428 #, c-format msgid "%s captured the red flag!" -msgstr "" +msgstr "%s a capturat lo drapèl roge !" #: src/modes/easter_egg_hunt.cpp:222 #, c-format @@ -3795,7 +3796,7 @@ msgstr "Dificultat : %s" #: src/network/protocols/client_lobby.cpp:743 #, c-format msgid "Max players: %d" -msgstr "" +msgstr "Max. jogaire : %d" #. I18N: In server info dialog #: src/network/protocols/client_lobby.cpp:756 @@ -3803,7 +3804,7 @@ msgstr "" #: src/states_screens/dialogs/server_info_dialog.cpp:101 #, c-format msgid "Game mode: %s" -msgstr "" +msgstr "Mòde de jòc : %s" #. I18N: In the create server screen for soccer server #: src/network/protocols/client_lobby.cpp:769 @@ -3812,7 +3813,7 @@ msgstr "" #: src/states_screens/online/create_server_screen.cpp:253 #: src/states_screens/track_info_screen.cpp:376 msgid "Time limit" -msgstr "" +msgstr "Limit de temps" #. I18N: In the create server screen for soccer server #: src/network/protocols/client_lobby.cpp:770 @@ -3820,7 +3821,7 @@ msgstr "" #: src/states_screens/online/create_server_screen.cpp:255 #: src/states_screens/track_info_screen.cpp:377 msgid "Goals limit" -msgstr "" +msgstr "Limit dels objectius" #. I18N: In the networking lobby #: src/network/protocols/client_lobby.cpp:774 @@ -3837,7 +3838,7 @@ msgstr "" #. will not be allowed to start #: src/network/protocols/client_lobby.cpp:903 msgid "All players joined red or blue team." -msgstr "" +msgstr "Totes los jogaires an rejonch una còla roja o blava." #. I18N: Display when a player is allow to control the server #: src/network/protocols/client_lobby.cpp:923 @@ -3850,15 +3851,15 @@ msgstr "Connexion refusada : lo servidor es ocupat." #: src/network/protocols/client_lobby.cpp:971 msgid "Connection refused: You are banned from the server." -msgstr "" +msgstr "Connexion refusada : sètz fòrabandit del servidor." #: src/network/protocols/client_lobby.cpp:986 msgid "Connection refused: Server password is incorrect." -msgstr "" +msgstr "Connexion refusada : lo senhal del servidor es incorrècte." #: src/network/protocols/client_lobby.cpp:990 msgid "Connection refused: Game data is incompatible." -msgstr "" +msgstr "Connexion refusada : las donadas de jòc son incompatiblas." #: src/network/protocols/client_lobby.cpp:994 msgid "Connection refused: Server is full." @@ -3889,7 +3890,7 @@ msgstr "" #: src/network/protocols/client_lobby.cpp:1255 msgid "Server owner quit the game." -msgstr "" +msgstr "Lo proprietari del servidor a quitat la partida." #. I18N: Status shown to player when he will be spectating the next game #: src/network/protocols/client_lobby.cpp:1259 @@ -3901,20 +3902,20 @@ msgstr "" #: src/network/protocols/client_lobby.cpp:1435 #, c-format msgid "%s joined the red team." -msgstr "" +msgstr "%s a rejonch la còla roja." #. I18N: Show when player join blue team of the started game in #. network #: src/network/protocols/client_lobby.cpp:1441 #, c-format msgid "%s joined the blue team." -msgstr "" +msgstr "%s a rejonch la còla blava." #. I18N: Show when player join the started game in network #: src/network/protocols/client_lobby.cpp:1447 #, c-format msgid "%s joined the game." -msgstr "" +msgstr "%s a rejonch la partida." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network @@ -3978,7 +3979,7 @@ msgstr "" #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 #: src/states_screens/online/create_server_screen.cpp:239 msgid "Capture The Flag" -msgstr "Trapar lo drapèu" +msgstr "Trapar lo drapèl" #: src/online/online_player_profile.cpp:455 #, c-format @@ -4097,7 +4098,7 @@ msgstr "2 ans" #: src/states_screens/addons_screen.cpp:107 msgid "Add-on name" -msgstr "" +msgstr "Nom del modul complementari" #: src/states_screens/addons_screen.cpp:108 msgid "Updated date" @@ -4580,7 +4581,7 @@ msgstr "Talha : %s" #: src/states_screens/dialogs/addons_pack.cpp:220 #: src/states_screens/dialogs/download_assets.cpp:201 msgid "Sorry, downloading the add-on failed" -msgstr "" +msgstr "Lo telecargament del modul complementari a fracassat" #: src/states_screens/dialogs/addons_loading.cpp:374 #, c-format @@ -4805,7 +4806,7 @@ msgstr "" #: src/states_screens/dialogs/high_score_info_dialog.cpp:112 #, c-format msgid "%s: %s" -msgstr "" +msgstr "%s : %s" #: src/states_screens/dialogs/high_score_info_dialog.cpp:125 #, c-format @@ -4820,7 +4821,7 @@ msgstr "" #: src/states_screens/dialogs/high_score_info_dialog.cpp:139 #, c-format msgid "Laps: %d" -msgstr "" +msgstr "Torn : %d" #: src/states_screens/dialogs/high_score_info_dialog.cpp:143 #, c-format @@ -4846,7 +4847,7 @@ msgstr "" #: src/states_screens/dialogs/message_dialog.cpp:145 msgid "Don't show again" -msgstr "" +msgstr "Mostrar pas mai" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:50 @@ -4874,7 +4875,7 @@ msgstr "Forabandir" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:124 msgid "Change team" -msgstr "" +msgstr "Cambiar de còla" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:139 @@ -4925,24 +4926,24 @@ msgstr "" #: src/states_screens/dialogs/race_paused_dialog.cpp:132 msgid "Back to Battle" -msgstr "" +msgstr "Tornar a la batalha" #: src/states_screens/dialogs/race_paused_dialog.cpp:135 msgid "Setup New Game" -msgstr "" +msgstr "Configurar partida novèla" #: src/states_screens/dialogs/race_paused_dialog.cpp:137 msgid "Restart Battle" -msgstr "" +msgstr "Recomençar la batalha" #: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Exit Battle" -msgstr "" +msgstr "Sortir la batalha" #: src/states_screens/dialogs/race_paused_dialog.cpp:146 #: src/states_screens/race_result_gui.cpp:350 msgid "Setup New Race" -msgstr "" +msgstr "Configurar una corsa novèla" #: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Exit Race" @@ -5028,7 +5029,7 @@ msgstr "" #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 #: src/states_screens/online/create_server_screen.cpp:233 msgid "Battle mode" -msgstr "" +msgstr "Mòde batalha" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 @@ -5048,7 +5049,7 @@ msgstr "Emplaçament del servidor : %s" #: src/states_screens/dialogs/server_info_dialog.cpp:119 #, c-format msgid "Current track: %s" -msgstr "" +msgstr "Pista actuala : %s" #: src/states_screens/dialogs/server_info_dialog.cpp:129 msgid "Rank" @@ -5064,22 +5065,22 @@ msgstr "Jogaire" #. the scores of user calculated by player rankings #: src/states_screens/dialogs/server_info_dialog.cpp:135 msgid "Scores" -msgstr "" +msgstr "Marcas" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server #: src/states_screens/dialogs/server_info_dialog.cpp:138 msgid "Time played" -msgstr "" +msgstr "Durada de jòc" #: src/states_screens/dialogs/server_info_dialog.cpp:281 #: src/states_screens/dialogs/server_info_dialog.cpp:296 msgid "Remove from bookmarks" -msgstr "" +msgstr "Tirar dels marcapaginas" #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:130 msgid "Input device already exists." -msgstr "" +msgstr "Lo periferic d’entrada existís ja." #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:147 msgid "No player available for connecting to server." @@ -5288,7 +5289,7 @@ msgstr "" #: src/states_screens/high_score_selection.cpp:144 msgctxt "column_name" msgid "Number of karts" -msgstr "" +msgstr "Nombre de karts" #: src/states_screens/high_score_selection.cpp:352 msgid "Are you sure you want to remove this high score entry?" @@ -5348,7 +5349,7 @@ msgstr "" #: src/states_screens/main_menu_screen.cpp:638 msgid "Please wait while the add-ons are loading" -msgstr "" +msgstr "Mercés d’esperar mentre que lo modul complementari es a cargar" #: src/states_screens/main_menu_screen.cpp:659 msgid "Are you sure you want to quit STK?" @@ -5455,7 +5456,7 @@ msgstr[1] "" #: src/states_screens/online/networking_lobby.cpp:698 #, c-format msgid "Connecting to server %s" -msgstr "" +msgstr "Connexion al servidor %s" #: src/states_screens/online/networking_lobby.cpp:703 msgid "Finding a quick play server" @@ -5603,7 +5604,7 @@ msgstr "Nom" #: src/states_screens/online/server_selection.cpp:133 msgctxt "column_name" msgid "Game mode" -msgstr "" +msgstr "Mòde de jòc" #. I18N: In server selection screen, owner of server, only displayed #. if it's localhost or friends' @@ -5689,13 +5690,13 @@ msgstr "" #: src/states_screens/options/options_screen_device.cpp:108 #: src/states_screens/options/options_screen_device.cpp:627 msgid "Disable Device" -msgstr "" +msgstr "Desactivar lo periferic" #. I18N: button to enable a gamepad configuration #: src/states_screens/options/options_screen_device.cpp:110 #: src/states_screens/options/options_screen_device.cpp:628 msgid "Enable Device" -msgstr "" +msgstr "Activar lo periferic" #. I18N: button to enable a keyboard configuration #: src/states_screens/options/options_screen_device.cpp:127 @@ -5726,7 +5727,7 @@ msgstr "" #. I18N: Key binding name #: src/states_screens/options/options_screen_device.cpp:272 msgid "Accelerate" -msgstr "" +msgstr "Accelerar" #. I18N: Key binding name #: src/states_screens/options/options_screen_device.cpp:275 @@ -5736,12 +5737,12 @@ msgstr "" #. I18N: Key binding name #: src/states_screens/options/options_screen_device.cpp:278 msgid "Fire" -msgstr "" +msgstr "Fuòc" #. I18N: Key binding name #: src/states_screens/options/options_screen_device.cpp:281 msgid "Nitro" -msgstr "" +msgstr "Nitrogèn" #. I18N: Key binding name #: src/states_screens/options/options_screen_device.cpp:287 @@ -5833,7 +5834,7 @@ msgstr "" #: src/states_screens/options/options_screen_input.cpp:119 #, c-format msgid "Keyboard %i" -msgstr "" +msgstr "Clavièr %i" #: src/states_screens/options/options_screen_input.cpp:170 msgid "Touch Device" @@ -5842,7 +5843,7 @@ msgstr "" #. I18N: In the input configuration screen, help for touch device #: src/states_screens/options/options_screen_input.cpp:207 msgid "Tap on a device to configure it" -msgstr "" +msgstr "Tocar un periferic per lo configurar" #. I18N: in the language choice, to select the same language as the OS #: src/states_screens/options/options_screen_language.cpp:90 @@ -5882,7 +5883,7 @@ msgstr "Orizontal" #. I18N: In the UI options, Very small font size #: src/states_screens/options/options_screen_ui.cpp:132 msgid "Very small" -msgstr "" +msgstr "Plan pichona" #. I18N: In the UI options, Small font size #: src/states_screens/options/options_screen_ui.cpp:134 @@ -5902,7 +5903,7 @@ msgstr "Granda" #. I18N: In the UI options, Very large font size #: src/states_screens/options/options_screen_ui.cpp:140 msgid "Very large" -msgstr "" +msgstr "Plan granda" #: src/states_screens/options/options_screen_ui.cpp:502 msgid "" @@ -6065,12 +6066,12 @@ msgstr "" #: src/states_screens/race_gui_base.cpp:82 #: src/states_screens/race_result_gui.cpp:409 msgid "Waiting for others" -msgstr "" +msgstr "En espèra dels autres" #. I18N: Shown waiting for the server in network if live join or spectate #: src/states_screens/race_gui_base.cpp:84 msgid "Waiting for the server" -msgstr "" +msgstr "En espèra del servidor" #. I18N: string used to show the song title (e.g. "Sunny Song") #: src/states_screens/race_gui_base.cpp:646 @@ -6124,7 +6125,7 @@ msgstr "" #: src/states_screens/race_result_gui.cpp:269 msgid "Quit the server" -msgstr "" +msgstr "Quitar lo servidor" #: src/states_screens/race_result_gui.cpp:310 msgid "Abort Grand Prix" @@ -6144,7 +6145,7 @@ msgstr "" #: src/states_screens/race_result_gui.cpp:353 msgid "Back to the menu" -msgstr "" +msgstr "Tornar al menú" #: src/states_screens/race_result_gui.cpp:536 msgid "Do you really want to abort the Grand Prix?" @@ -6153,12 +6154,12 @@ msgstr "" #: src/states_screens/race_result_gui.cpp:636 #: src/states_screens/race_result_gui.cpp:1529 msgid "Red Team Wins" -msgstr "" +msgstr "La còla roja a ganhat" #: src/states_screens/race_result_gui.cpp:638 #: src/states_screens/race_result_gui.cpp:1533 msgid "Blue Team Wins" -msgstr "" +msgstr "La còla blava a ganhat" #: src/states_screens/race_result_gui.cpp:640 #: src/states_screens/race_result_gui.cpp:1538 @@ -6184,7 +6185,7 @@ msgstr "" #: src/states_screens/race_result_gui.cpp:1749 #, c-format msgid "Track %i/%i" -msgstr "" +msgstr "Pista %i/%i" #: src/states_screens/race_result_gui.cpp:1833 msgid "Grand Prix progress:" @@ -6261,7 +6262,7 @@ msgstr "" #: src/states_screens/track_info_screen.cpp:149 #, c-format msgid "Track by %s" -msgstr "" +msgstr "Pista de %s" #. I18N: the max players supported by an arena. #: src/states_screens/track_info_screen.cpp:157 @@ -6403,7 +6404,7 @@ msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" -msgstr "" +msgstr "Es prèst per córrer. Bona fortuna!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play @@ -6423,7 +6424,7 @@ msgid "" "variety of characters, tracks, and modes to play. Our aim is to create a " "game that is more fun than realistic, and provide an enjoyable experience " "for all ages." -msgstr "" +msgstr "Karts. Nitròs. Accion ! SuperTuxKart es un jòc de corsa 3D de còde dobèrt amb una granda varietat de personatges, traces, e mòdes de jòc. La nòstra tòca es de crear un jòc qu'es mai amusant que los reals, e de provesir una bona experiéncia per totas las edats." #: supertuxkart.appdata.xml:11 msgid "" @@ -6462,7 +6463,7 @@ msgstr "" #: supertuxkart.appdata.xml:26 msgid "If you need more stability, consider using the stable version: %s" -msgstr "" +msgstr "Comparar repeticion" #: supertuxkart.appdata.xml:44 msgid "SuperTuxKart Team" diff --git a/data/po/pl.po b/data/po/pl.po index 83c81b66a8c..9a5658a09e1 100644 --- a/data/po/pl.po +++ b/data/po/pl.po @@ -5,7 +5,7 @@ # Translators: # Deve , 2015 # Deve , 2015-2021 -# Jakub Fabijan , 2021 +# Jakub Fabijan (Felidae) , 2021 # Jakub Wojtkowiak , 2016,2021 # Marcin Węclewski, 2022 # Marcin Węclewski, 2022-2023 @@ -917,7 +917,7 @@ msgstr "Informacje o użytkowniku" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Usuń znajomego" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -927,17 +927,17 @@ msgstr "Dodaj Przyjaciela" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Zaakceptuj zaproszenie" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Odrzuć zaproszenie" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Wyświetl profil" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1125,7 +1125,7 @@ msgstr "Autorzy" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Pomiń" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -2005,7 +2005,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Możesz grać bez tworzenia konta online, wybierając konto offline. Jednak w takim przypadku nie będziesz mógł połączyć się ze znajomymi, oceniać dodatków, itp. Prosimy zapoznać się z naszą polityką prywatności na stronie https://privacy.supertuxkart.net." #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 diff --git a/data/po/pt.po b/data/po/pt.po index c331c2f838b..679651c09fe 100644 --- a/data/po/pt.po +++ b/data/po/pt.po @@ -9,7 +9,8 @@ # Crystal Da Eevee , 2019-2023 # Daniel Luiz Lorenzi , 2022 # FIRST AUTHOR , 2010 -# João Frade <100nome.portugal@gmail.com>, 2023 +# Hugo Carvalho , 2024 +# João Frade <100nome.portugal@gmail.com>, 2023-2024 # Pedroxz , 2017 # Pedroxz , 2017 # Pedroxz , 2017 @@ -21,7 +22,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: João Frade <100nome.portugal@gmail.com>, 2023\n" +"Last-Translator: João Frade <100nome.portugal@gmail.com>, 2023-2024\n" "Language-Team: Portuguese (http://app.transifex.com/supertuxkart/supertuxkart/language/pt/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -57,7 +58,7 @@ msgstr "Joga cada pista oficial pelo menos uma vez." #. I18N: ./data/achievements.xml msgid "Strike!" -msgstr "Atingidos!" +msgstr "Strike!" #. I18N: ./data/achievements.xml msgid "Hit 10 karts with a bowling-ball." @@ -81,7 +82,7 @@ msgstr "Termina uma corrida com pelo menos o dobro do número padrão de voltas #. I18N: ./data/achievements.xml msgid "Skid-row" -msgstr "Derrapador em série" +msgstr "Derrapagens em Série" #. I18N: ./data/achievements.xml msgid "Skid 5 times in a single lap." @@ -89,7 +90,7 @@ msgstr "Derrapa 5 vezes numa única volta." #. I18N: ./data/achievements.xml msgid "Gold driver" -msgstr "Piloto de ouro" +msgstr "Piloto de Ouro" #. I18N: ./data/achievements.xml msgid "" @@ -121,7 +122,7 @@ msgstr "Amante de Bananas" #. I18N: ./data/achievements.xml msgid "Collect at least 5 bananas in one race." -msgstr "Apanha no mínimo de 5 bananas numa corrida." +msgstr "Apanha pelo menos 5 bananas numa corrida." #. I18N: ./data/achievements.xml msgid "It's secret" @@ -143,7 +144,7 @@ msgstr "Faz dos teus oponentes pequenos mosquitos! Com o mata-moscas, esmaga-os #. I18N: ./data/achievements.xml msgid "Beyond Luck" -msgstr "Mais do que sorte" +msgstr "Além da Sorte" #. I18N: ./data/achievements.xml msgid "" @@ -465,7 +466,7 @@ msgstr "Oclusão do ambiente" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Depth of field" -msgstr "Campo de visão" +msgstr "Profundidade de campo" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -520,7 +521,7 @@ msgstr "Detalhes da geometria" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "* Restart STK to apply new settings" -msgstr "* Reinicia o STK para aplicar as alterações." +msgstr "* Reinicia o STK para aplicar as alterações" #. I18N: ./data/gui/dialogs/debug_slider.stkgui #. I18N: ./data/gui/dialogs/online/recovery_info.stkgui @@ -717,13 +718,13 @@ msgstr "Recuperação da Conta" msgid "" "You will receive an email with further instructions on how to reset your " "password. Please be patient and be sure to check your spam folder." -msgstr "Vais receber um email com informações detalhadas sobre como alterar a palavra-passe. Por favor, sê paciente e lembra-te de verificar a pasta de spam." +msgstr "Vais receber um e-mail com informações detalhadas sobre como alterar a palavra-passe. Por favor, sê paciente e lembra-te de verificar a pasta de spam." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui msgid "" "Fill in the username and email address you supplied at registration to be " "able to reset your password." -msgstr "Preenche o nome de utilizador e o endereço de e-mail que introduziste ao criar a conta para poderes alterar a tua palavra-passe." +msgstr "Preenche com o nome de utilizador e endereço de e-mail que introduziste ao criar a conta para poderes alterar a tua palavra-passe." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog @@ -900,7 +901,7 @@ msgstr "Desvantagem" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "Press the 'All players ready' button after the player list is ready." -msgstr "Clica no botão 'Todos os jogadores prontos' quando a lista de jogadores estiver pronta." +msgstr "Clica no botão 'Todos Prontos' quando a lista de jogadores estiver pronta." #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network @@ -910,7 +911,7 @@ msgstr "Limpar jogadores" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "All players ready" -msgstr "Todos os jogadores prontos" +msgstr "Todos Prontos" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -1128,7 +1129,7 @@ msgstr "Créditos" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "Saltar" +msgstr "Passar à frente" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1142,7 +1143,7 @@ msgstr "Todas as Pistas" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Title in edit grand prix screen msgid "Edit Grand Prix" -msgstr "Editar campeonato" +msgstr "Editar Campeonato" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item @@ -1487,7 +1488,7 @@ msgid "" "player who hits others the most will win in a given hit or time limit. In " "Capture The Flag, your team needs to bring the flag of the other team to " "your own flag base, as long as your flag is not captured by the other team." -msgstr "Existem 3 tipos de Batalha: em Batalha de 3 Golpes, tens de atingir os outros com armas até ficarem sem vidas. Em Todos Contra Todos, o jogador que golpear mais os outros vence, num dado limite de golpes ou tempo. Em Capturar a Bandeira, tu e a tua equipa têm de trazer a bandeira da equipa adversária até à vossa base, desde que a vossa bandeira não seja capturada por eles." +msgstr "Existem 3 tipos de Batalha: em Batalha de 3 Vidas, tens de atingir os outros com armas até ficarem sem vidas. Em Todos Contra Todos, o jogador que golpear mais os outros vence, num dado limite de golpes ou tempo. Em Capturar a Bandeira, tu e a tua equipa têm de trazer a bandeira da equipa adversária até à vossa base, desde que a vossa bandeira não seja capturada pela outra equipa." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1504,13 +1505,13 @@ msgstr "Caça aos Ovos: explora as pistas e encontra todos os ovos escondidos." msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" -msgstr "Desafiar Fantasma: corre contra repetições fantasma de Contrarrelógio ou Caça aos Ovos e grava as tuas próprias!" +msgstr "Corrida Contra Fantasma: corre contra repetições fantasma de Contrarrelógio ou Caça aos Ovos e grava as tuas próprias!" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "Conta-voltas: completa o máximo de voltas possível num dado tempo." +msgstr "Resistência: completa o máximo de voltas possível num dado tempo." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1530,53 +1531,53 @@ msgstr "Para te ajudar a ganhar, aqui estão alguns potenciadores que podes apan msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." -msgstr "Pastilha Elástica: protege-te com um escudo ou utiliza-a enquanto olhas à retaguarda para deixares uma poça rosa pegajosa atrás de ti." +msgstr "Pastilha Elástica - protege-te com um escudo ou utiliza-a enquanto olhas à retaguarda para deixares uma poça rosa pegajosa atrás de ti." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" -msgstr "Propulsor: dá-te um grande impulso de velocidade. Mas cuidado para não perderes o controlo do teu kart!" +msgstr "Zarpador - dá-te um grande impulso de velocidade. Mas cuidado para não perderes o controlo do teu kart!" #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." -msgstr "Bolo: dispara contra o rival mais próximo; é melhor em distâncias curtas e retas compridas. Também afeta outros karts próximos da explosão." +msgstr "Bolo - dispara contra o rival mais próximo; é melhor em distâncias curtas e retas compridas. Também afeta outros karts próximos da explosão." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." -msgstr "Desentupidor: dispara-o em frente para puxares um adversário para trás, ou dispara à retaguarda para cegares alguém." +msgstr "Desentupidor - dispara-o em frente para puxares um adversário para trás ou dispara à retaguarda para cegares alguém." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." -msgstr "Bola de Bólingue: vai em linha reta até atingir alguém. A bola faz ricochete nas paredes. Se estiveres a olhar à retaguarda, ela será lançada para trás." +msgstr "Bola de Bólingue - vai em linha reta até atingir alguém. A bola faz ricochete nas paredes. Se estiveres a olhar à retaguarda, ela será lançada para trás." #. I18N: ./data/gui/screens/help3.stkgui msgid "Parachute - slows down all karts in a better position." -msgstr "Paraquedas: abranda todos os karts à tua frente." +msgstr "Paraquedas - abranda todos os karts à tua frente." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." -msgstr "Alternador: presentes são transformados em bananas e garrafas de nitro em pastilhas elásticas, e vice-versa, por um curto período de tempo." +msgstr "Alternador - presentes são transformados em bananas e garrafas de nitro em pastilhas elásticas, e vice-versa, por um curto período de tempo." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." -msgstr "Bola de Basquete: saltita atrás do líder e pode esmagar e abrandar karts pelo caminho." +msgstr "Bola de Basquete - saltita atrás do líder e pode esmagar e abrandar karts pelo caminho." #. I18N: ./data/gui/screens/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." -msgstr "Mata-moscas: esmaga os karts próximos, abrandando-os. Também pode ser usado para remover paraquedas e bombas." +msgstr "Mata-Moscas - esmaga os karts próximos, abrandando-os. Também pode ser usado para remover paraquedas e bombas." #. I18N: ./data/gui/screens/help4.stkgui msgid "" @@ -1587,21 +1588,21 @@ msgstr "Apanhar uma banana pode resultar num dos seguintes efeitos no kart:" #. I18N: ./data/gui/screens/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." -msgstr "Âncora: abranda repentinamente o kart." +msgstr "Âncora - abranda repentinamente o kart." #. I18N: ./data/gui/screens/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." -msgstr "Paraquedas: abranda o kart, mas menos que a âncora. Quanto mais rápido fores, mais te abrandará." +msgstr "Paraquedas - abranda o kart de forma mais progressiva que a âncora. Quanto mais rápido fores, mais te abrandará." #. I18N: ./data/gui/screens/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." -msgstr "Bomba: detona após algum tempo, atirando o kart ao ar. Embate noutro kart para transferires a bomba para ele." +msgstr "Bomba - explode após algum tempo, atirando o kart ao ar. Bate contra outro kart para transferires a bomba para ele." #. I18N: ./data/gui/screens/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" @@ -1622,20 +1623,20 @@ msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " "points. The higher the difficulty you completed the challenge in, the better" " the cup and the more points it is worth." -msgstr "Quando completas um desafio, ganhas uma taça. Cada taça vale vários pontos. Quanto maior a dificuldade do desafio concluído, melhor será a taça e mais pontos valerá." +msgstr "Quando completas um desafio, ganhas uma taça. Cada taça vale vários pontos. Quanto maior for a dificuldade do desafio concluído, melhor será a taça e mais pontos valerá." #. I18N: ./data/gui/screens/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." -msgstr "Quando consegues o número de pontos indicado abaixo deste ícone, receberás de presente uma surpresa. Existem várias para colecionar." +msgstr "Quando consegues o número de pontos indicado abaixo deste ícone, és presenteado com uma surpresa. Existem várias para colecionar." #. I18N: ./data/gui/screens/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" -msgstr "Nem todos os karts se pilotam igual. Eles pertencem a classes com várias diferenças:" +msgstr "Nem todos os karts se pilotam igual! Eles pertencem a classes com várias diferenças:" #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu @@ -1643,7 +1644,7 @@ msgid "" "Mass - there are three classes of karts, depending on their mass: light, " "medium and heavy. Heavier karts are less affected by parachutes and are more" " resistant to explosions." -msgstr "Peso: existem três classes de karts, dependendo do seu peso: leve, médio e pesado. Os karts mais pesados são menos afetados por paraquedas e são mais resistentes a explosões." +msgstr "Peso - existem três classes de karts tendo em conta o seu peso: leve, médio e pesado. Os karts mais pesados são menos afetados por paraquedas e são mais resistentes a explosões." #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu @@ -1651,7 +1652,7 @@ msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " "with a lot of sharp curves. The lighter the kart, the faster it accelerates," " especially at low speeds." -msgstr "Aceleração: particularmente útil na partida, após um acidente ou em pistas com muitas curvas apertadas. Quanto mais leve for o kart, mais rápido ele acelera, especialmente a baixas velocidades." +msgstr "Aceleração - particularmente útil no momento de Partida, após um acidente ou em pistas com muitas curvas apertadas. Quanto mais leve for o kart, mais rápido ele acelera, especialmente a baixas velocidades." #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu @@ -1659,14 +1660,14 @@ msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " "in tracks with straight lines and gentle curves. Heavier karts have a higher" " top speed." -msgstr "Velocidade máxima: quanto maior, mais rápido o kart pode ir. É útil em pistas com linhas retas e curvas suaves. Os karts mais pesados têm uma velocidade máxima superior." +msgstr "Velocidade máxima - quanto maior, mais rápido o kart pode ir. É útil em pistas com linhas retas e curvas suaves. Os karts mais pesados têm maior velocidade máxima." #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." -msgstr "Eficiência do nitro: quanto mais, maior será o impulso que obterás de uma garrafa de nitro. Um kart mais leve terá uma eficiência de nitro maior." +msgstr "Eficiência do nitro - quanto maior for, maior será o impulso que obterás de uma garrafa de nitro. Um kart mais leve terá uma eficiência de nitro maior." #. I18N: ./data/gui/screens/help6.stkgui #. I18N: In the help menu @@ -1674,7 +1675,7 @@ msgid "" "If you follow closely another kart for a few seconds, you'll get a " "slipstream speed bonus when you overtake it. The lighter your kart, the " "easier it is." -msgstr "Se seguires de perto outro kart por alguns segundos, receberás um impulso bónus pelo efeito de cone de aspiração ao ultrapassá-lo. Quanto mais leve for o teu kart, mais fácil será fazê-lo." +msgstr "Se seguires de perto outro kart por alguns segundos, receberás um impulso de cone de ar bónus ao ultrapassá-lo. Quanto mais leve for o teu kart, mais fácil será fazê-lo." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1699,7 +1700,7 @@ msgid "" " enough players. Then, you can choose your kart and vote for the next track " "to race on. An addon track is allowed only if it exists on all joined " "players and the server." -msgstr "Num servidor, uma corrida iniciará quando o dono (indicado por uma coroa) o decidir. Servidores oficiais apenas poderão autoiniciá-la assim que houver jogadores suficientes. A seguir, poderás escolher o teu kart e votar na próxima pista a correr. Uma pista de extensão só é permitida se todos os jogadores no servidor a tiverem." +msgstr "Entrando num servidor, uma corrida iniciará quando o dono (indicado por uma coroa) o decidir. Servidores oficiais apenas poderão autoiniciá-la assim que houver jogadores suficientes. A seguir, poderás escolher o teu kart e votar na próxima pista a correr. Uma pista de extensão só é permitida se todos os jogadores no servidor a tiverem." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1714,7 +1715,7 @@ msgid "" "keyboard(s), each player will need a different set of keys, and most " "keyboards are not appropriate for multiplayer because they don't support " "multiple simultaneous keypresses." -msgstr "Primeiro necessitarás de vários dispositivos de entrada. Usa a tecla de configuração de entrada para configurá-los. Vários controladores de jogo ou joysticks é o ideal: com teclado(s), cada jogador necessita de um conjunto diferente de teclas, e a maioria dos teclados não é apropriada para o multijogador porque não suportam o uso de várias teclas em simultâneo." +msgstr "Primeiro necessitarás de vários dispositivos de entrada. Usa o menu Controlos, nas Opções, para os configurares. Múltiplos comandos de jogo ou joysticks é o ideal: com teclado(s), cada jogador necessitará de um conjunto diferente de teclas, e a maioria dos teclados não é apropriada para multijogador porque não suporta o uso de várias teclas em simultâneo." #. I18N: ./data/gui/screens/help7.stkgui #. I18N: In the help menu @@ -1724,7 +1725,7 @@ msgid "" "keyboard to join the game, and use their input device to select their kart. " "The game continues when everyone selected their kart. Note that the mouse " "may not be used for this operation." -msgstr "Quando dispositivos de entrada estiverem configurados, seleciona 'Multijogador em Ecrã Dividido' no menu principal. Cada jogador poderá premir o botão 'Disparar' no seu controlador de jogo ou teclado para entrar no jogo e usar o seu dispositivo de entrada para escolher o seu kart. O jogo continuará quando todos tiverem selecionado um kart. Nota que o rato não poderá ser usado nesta operação." +msgstr "Quando os dispositivos de entrada estiverem configurados, seleciona 'Multijogador em Ecrã Dividido' no menu principal. Cada jogador poderá premir o botão 'Disparar' no seu comando de jogo ou teclado para entrar no jogo e usar o seu dispositivo de entrada para escolher o seu kart. O jogo continuará quando todos tiverem selecionado um kart. Nota que o rato não poderá ser usado nesta operação." #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen @@ -1738,7 +1739,7 @@ msgstr "Seleção de Recordes" #. time. #: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" -msgstr "Conta-voltas" +msgstr "Resistência" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen @@ -2000,7 +2001,7 @@ msgstr "Nome de utilizador online" #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" -msgstr "Limpar palavra-passe" +msgstr "Repor palavra-passe" #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog @@ -2197,22 +2198,22 @@ msgstr "Desativar Configuração" #. I18N: ./data/gui/screens/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" -msgstr "<- voltar à lista de dispositivos" +msgstr "<= voltar à lista de dispositivos" #. I18N: ./data/gui/screens/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" -msgstr "Renomear Configuração " +msgstr "Renomear Configuração" #. I18N: ./data/gui/screens/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" -msgstr "Ativar vibração (Força Reativa, se for suportado)" +msgstr "Ativar vibração (Force Feedback, se for suportado)" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings msgid "Internet options" -msgstr "Opções de Internet" +msgstr "Opções da Internet" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings @@ -2237,7 +2238,7 @@ msgstr "Ativar conversação em jogos online" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" -msgstr "Opções extra" +msgstr "Opções diversas" #. I18N: ./data/gui/screens/options_general.stkgui #. I18N: In the general settings @@ -2248,13 +2249,13 @@ msgstr "Ativar desvantagem em jogadores" #. I18N: For mobile version for STK, uninstall the downloaded assets #: src/states_screens/options/options_screen_general.cpp:113 msgid "Uninstall full game assets" -msgstr "Desinstalar recursos integrais do jogo" +msgstr "Desinstalar recursos completos do jogo" #. I18N: ./data/gui/screens/options_input.stkgui #. I18N: In the input configuration screen #: src/states_screens/options/options_screen_input.cpp:212 msgid "Press enter or double-click on a device to configure it" -msgstr "Prime Enter ou faz duplo clique num dispositivo para o configurar" +msgstr "Prime Enter ou faz duplo clique num dispositivo para configurá-lo" #. I18N: ./data/gui/screens/options_input.stkgui #. I18N: In the input configuration screen @@ -2296,7 +2297,7 @@ msgstr "Câmara" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." -msgstr "personalizada..." +msgstr "Personalizada..." #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings @@ -2311,12 +2312,12 @@ msgstr "Mostrar potenciadores dos outros karts" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" -msgstr "Ativar temporizador no Modo História" +msgstr "Mostrar cronometragem do Modo História" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" -msgstr "Ativar temporizador em Speedrun" +msgstr "Ativar cronómetro para Speedrun" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings @@ -2444,7 +2445,7 @@ msgstr "O tema da interface pode ser mudado nas opções de IU." #. I18N: ./data/tips.xml msgid "You can see other karts' powerups by enabling it in the UI options." -msgstr "Poderás ver os potenciadores de outros karts se ativares esta opção nas opções de IU." +msgstr "Poderás ver os potenciadores de outros karts se ativares essa opção nas opções de IU." #. I18N: ./data/tips.xml msgid "The font size can be changed in the UI options." @@ -2465,21 +2466,21 @@ msgstr "Podes visitar https://supertuxkart.net/ para mais informações sobre o #. I18N: ./data/tips.xml msgid "Short nitro boosts are more efficient." -msgstr "Impulsos de nitro curtos são mais eficientes." +msgstr "Curtos impulsos de nitro são mais eficientes." #. I18N: ./data/tips.xml msgid "Only use zippers when it is safe. Long straight lines are ideal." -msgstr "Usa propulsores apenas quando for seguro. Longas linhas retas é o ideal." +msgstr "Usa zarpadores apenas quando for seguro. Longas linhas retas é o ideal." #. I18N: ./data/tips.xml msgid "" "Don't use multiple zippers quickly in row, instead, wait until the speed " "boost wears off." -msgstr "Não uses múltiplos propulsores de seguida, espera que o impulso de um desapareça primeiro." +msgstr "Não uses múltiplos zarpadores de seguida, espera que o seu efeito desapareça primeiro." #. I18N: ./data/tips.xml msgid "Skidding makes you much faster, do it whenever safe." -msgstr "Derrapar faz-te muito mais rápido, por isso derrapa sempre que for seguro fazê-lo." +msgstr "Derrapar faz-te muito mais rápido, por isso derrapa sempre que seguro." #. I18N: ./data/tips.xml msgid "The swatter can be used to remove bombs or parachutes." @@ -2489,7 +2490,7 @@ msgstr "O mata-moscas pode ser usado para remover bombas ou paraquedas." msgid "" "You can't stop turning while skidding. Good kart orientation at the skid's " "start is paramount." -msgstr "Não consegues parar de virar enquanto derrapas. Uma boa orientação do teu kart no começo de uma derrapagem é primordial." +msgstr "Não podes parar de virar durante uma derrapagem. Orientar bem o kart no começo de uma é crucial." #. I18N: ./data/tips.xml msgid "You get a startup boost if you start accelerating during \"Set\"." @@ -2497,11 +2498,11 @@ msgstr "Ganharás um impulso inicial se começares a acelerar em \"Preparar!\"." #. I18N: ./data/tips.xml msgid "Braking allows to get rid of parachutes quicker." -msgstr "Travar permite-te livrar-te dos paraquedas mais rápido." +msgstr "Travar permite-te livrares-te dos paraquedas mais rápido." #. I18N: ./data/tips.xml msgid "First and foremost, focus on where your kart is going." -msgstr "Antes de mais nada, concentra-te aonde o teu kart está a ir." +msgstr "Acima de tudo, concentra-te para onde o teu kart está a ir." #. I18N: ./data/tips.xml msgid "The rescue key (button) is very useful." @@ -2509,7 +2510,7 @@ msgstr "A tecla (ou botão) de resgate é bastante útil." #. I18N: ./data/tips.xml msgid "Be careful when close to other karts, they may attack you!" -msgstr "Tem cuidado quando estiveres perto de outros karts, eles podem-te atacar!" +msgstr "Tem cuidado quando perto de outros karts, eles podem-te atacar!" #. I18N: ./data/tips.xml msgid "" @@ -2525,35 +2526,35 @@ msgstr "Evita chocar com as traseiras dos outros karts, pois isso vai abrandar-t #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." -msgstr "Podes usar bolas de bólingue para chutar ou bloquear a bola." +msgstr "Podes usar bolas de bólingue para empurrar ou bloquear a bola." #. I18N: ./data/tips.xml msgid "In soccer, always work as a team for good results." -msgstr "No modo futebol, trabalha sempre com a tua equipa para obter bons resultados." +msgstr "No modo Futebol, trabalha sempre em equipa para bons resultados." #. I18N: ./data/tips.xml msgid "" "If you miss the ball and an opponent is approaching, try hitting them with a" " powerup or block their way." -msgstr "Se falhares a bola e um adversário estiver a aproximar-se, tenta acertar-lhe com um potenciador ou bloqueia o seu caminho." +msgstr "Se falhares a bola e um adversário estiver a aproximar-se, tenta acertar-lhe com um potenciador ou bloqueia-lhe o caminho." #. I18N: ./data/tips.xml msgid "Good rotation of positions (attack and defense) is essential." -msgstr "Uma boa rotação de posições entre a equipa (ataque e defesa) é essencial." +msgstr "Uma boa alternância de posições (ataque e defesa) é essencial." #. I18N: ./data/tips.xml msgid "Make sure to store at least 2 big cans worth of nitro." -msgstr "Tenta sempre apanhar e guardar pelo menos dois barris de nitro." +msgstr "Certifica-te de armazenar pelo menos 2 garrafas grandes de nitro." #. I18N: ./data/tips.xml msgid "Never use the three bowling balls all at the same time." -msgstr "Nunca dispares as três bolas de bólingue de uma vez só." +msgstr "Nunca dispares as três bolas de bólingue de seguida." #. I18N: ./data/tips.xml msgid "" "Don't get in the way of a teammate carrying the ball, though you can try to " "hit opponents attempting to stop them from scoring." -msgstr "Não atrapalhes o teu colega de equipa se este estiver com a bola, poderás sempre atingir adversários a tentar pará-lo de marcar." +msgstr "Não atrapalhes o teu colega de equipa se este estiver com a bola, mas poderás sempre atingir adversários que o tentam impedir de marcar." #. I18N: ../stk-assets/karts/adiumy/kart.xml msgid "Adiumy" @@ -2613,7 +2614,7 @@ msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml msgid "Suzanne" -msgstr "Suzana" +msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml msgid "Tux" @@ -2687,29 +2688,29 @@ msgstr "Campo de Futebol Gelado" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" -msgstr "Qual é agora, seus hippiezinhos? O vosso grande líder gnu está desaparecido?" +msgstr "Que é agora, seus hippiezinhos? O vosso grande líder gnu desapareceu?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." -msgstr "Oh sim, vê, ele está no meu castelo agora e será servido ao jantar..." +msgstr "Oh, sim. Vejam, ele está no meu castelo agora e será servido ao jantar..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." -msgstr "Mas como sou uma criatura justa, vamos fazer um acordo." +msgstr "Mas sou uma criatura justa, por isso proponho-vos um acordo." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." -msgstr "Se me conseguires vencer na corrida, eu liberto o velho ranzinza." +msgstr "Se me conseguirem vencer em corridas, eu liberto o velho ranzinza." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" -msgstr "Mas vocês, patéticos insignificantes, nunca serão capazes de me vencer - Rei dos Karts!" +msgstr "Mas vocês, patéticos insignificantes, nunca me conseguirão vencer - Rei dos Karts!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" @@ -2721,7 +2722,7 @@ msgstr "Estádio de Futebol Las Dunas" #. I18N: ../stk-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" -msgstr "À Volta do Farol " +msgstr "À Volta do Farol" #. I18N: ../stk-assets/tracks/mines/track.xml msgid "Old Mine" @@ -2761,7 +2762,7 @@ msgstr "Resort do Norte" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" -msgstr "Pico da Neve" +msgstr "Pico de Neve" #. I18N: ../stk-assets/tracks/soccer_field/track.xml msgid "Soccer Field" @@ -2831,14 +2832,14 @@ msgstr "Contrarrelógio (corrida única)" #: src/challenges/challenge_data.cpp:318 msgid "Follow the Leader (single race)" -msgstr "Seguir o líder (corrida única)" +msgstr "Seguir o Líder (corrida única)" #. I18N: In the Select challenge dialog, tell user this challenge has reversed #. laps #: src/challenges/challenge_data.cpp:324 #: src/states_screens/dialogs/select_challenge.cpp:78 msgid "Mode: Reverse" -msgstr "Modo: sentido inverso" +msgstr "Modo: Sentido Inverso" #: src/challenges/challenge_data.cpp:601 #, c-format @@ -2873,7 +2874,7 @@ msgid "" "Closing the game before the story mode's completion invalidates the timer.\n" "\n" "To use the speedrun mode, please use a new profile." -msgstr "Modo Speedrun desativado. Só pode ser ativado se o jogo não tiver sido fechado desde o começo do modo História.\n\nFechar o jogo antes de completado o modo História invalida o temporizador.\n\nPara usares o modo modo Speedrun, usa um perfil novo." +msgstr "Modo Speedrun desativado. Só pode ser ativado se o jogo não tiver sido fechado depois de iniciado o modo História.\n\nFechar o jogo antes de completado o modo História invalida o cronómetro.\n\nPara ativares o modo Speedrun, por favor usa um perfil novo." #. I18N: Name of first guest player (without number) #: src/config/player_manager.cpp:396 @@ -2890,7 +2891,7 @@ msgstr "Convidado %d" msgid "" "Your config file was malformed, so it was deleted and a new one will be " "created." -msgstr "O ficheiro de configurações está danificado por isso foi eliminado. Vai ser criado um novo." +msgstr "O ficheiro de configurações está danificado e por isso foi eliminado. Vai ser criado um novo." #: src/config/user_config.cpp:699 msgid "" @@ -2960,12 +2961,12 @@ msgstr "%s (em desvantagem)" #: src/guiengine/widgets/player_kart_widget.cpp:444 #, c-format msgid "%s is ready" -msgstr "%s está pronto." +msgstr "%s está pronto" #. I18N: Unbound key binding #: src/input/binding.cpp:85 msgid "[none]" -msgstr "[nenhum]" +msgstr "[nenhuma]" #. I18N: input configuration screen: mouse button #: src/input/binding.cpp:92 @@ -3188,7 +3189,7 @@ msgstr "Print Screen" #: src/input/binding.cpp:165 msgctxt "input_key" msgid "Insert" -msgstr "Insert/Inserir" +msgstr "Insert" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:167 @@ -3206,25 +3207,25 @@ msgstr "Ajuda" #: src/input/binding.cpp:207 msgctxt "input_key" msgid "Left Logo" -msgstr "Logotipo Esquerdo" +msgstr "Logo Esquerdo" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:209 msgctxt "input_key" msgid "Right Logo" -msgstr "Logotipo Direito" +msgstr "Logo Direito" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:211 msgctxt "input_key" msgid "Apps" -msgstr "Apps" +msgstr "Aplicações" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:213 msgctxt "input_key" msgid "Sleep" -msgstr "Sleep (suspender)" +msgstr "Suspender" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:215 @@ -3302,7 +3303,7 @@ msgstr "- (subtrair)" #: src/input/binding.cpp:241 msgctxt "input_key" msgid "Decimal" -msgstr "Decimal" +msgstr "Ponto numérico" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:243 @@ -3386,13 +3387,13 @@ msgstr "Ereof" #: src/input/binding.cpp:297 msgctxt "input_key" msgid "Play" -msgstr "Play" +msgstr "Reproduzir" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:299 msgctxt "input_key" msgid "Zoom" -msgstr "Zoom" +msgstr "Aproximar" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:301 @@ -3410,7 +3411,7 @@ msgstr "Oem Clear" #: src/input/binding.cpp:343 src/input/binding.cpp:348 #, c-format msgid "Gamepad hat %d" -msgstr "Hat %d do controlador de jogo" +msgstr "Direcional %d do comando de jogo" #. I18N: to appear in input configuration screen, for gamepad axes #: src/input/binding.cpp:355 @@ -3434,7 +3435,7 @@ msgstr "Eixo %d" #: src/input/binding.cpp:375 #, c-format msgid "Gamepad button %d" -msgstr "Botão %d do controlador de jogo" +msgstr "Botão %d do comando de jogo" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) @@ -3457,7 +3458,7 @@ msgstr "Por favor, reconfigura as tuas atribuições de teclas." #: src/input/device_manager.cpp:497 msgid "Your input config file is not compatible with this version of STK." -msgstr "O teu ficheiro de configuração não é compatível com esta versão do SuperTuxKart." +msgstr "O teu ficheiro de configuração não é compatível com esta versão do STK." #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:159 @@ -3482,12 +3483,12 @@ msgstr "Botão analógico direito" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:167 msgid "Left shoulder" -msgstr "Ombro superior esquerdo (L1)" +msgstr "Ombro esquerdo (L1/LB)" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:169 msgid "Right shoulder" -msgstr "Ombro superior direito (R1)" +msgstr "Ombro direito (R1/RB)" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:171 @@ -3512,42 +3513,42 @@ msgstr "DPad direita" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:181 msgid "Left thumbstick right" -msgstr "Manipulo esquerdo (Direita)" +msgstr "Manípulo esquerdo (Direita)" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:183 msgid "Left thumbstick left" -msgstr "Manipulo esquerdo (Esquerda)" +msgstr "Manípulo esquerdo (Esquerda)" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:185 msgid "Left thumbstick down" -msgstr "Manipulo esquerdo (Baixo)" +msgstr "Manípulo esquerdo (Baixo)" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:187 msgid "Left thumbstick up" -msgstr "Manipulo esquerdo (Cima)" +msgstr "Manípulo esquerdo (Cima)" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:189 msgid "Right thumbstick right" -msgstr "Manipulo direito (Direita)" +msgstr "Manípulo direito (Direita)" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:191 msgid "Right thumbstick left" -msgstr "Manipulo direito (Esquerda)" +msgstr "Manípulo direito (Esquerda)" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:193 msgid "Right thumbstick down" -msgstr "Manipulo direito (Baixo)" +msgstr "Manípulo direito (Baixo)" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:195 msgid "Right thumbstick up" -msgstr "Manipulo direito (Cima)" +msgstr "Manípulo direito (Cima)" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:197 @@ -3566,12 +3567,12 @@ msgstr "A ignorar '%s'. Tinhas de ter entrado mais cedo para jogar!" #: src/input/input_manager.cpp:903 msgid "Only the Game Master may act at this point!" -msgstr "Só o primeiro jogador pode atuar agora!" +msgstr "Só o jogador do perfil atual pode atuar!" #: src/input/sdl_controller.cpp:253 #, c-format msgid "%s has low battery level." -msgstr "%s tem pouca bateria." +msgstr "%s está com pouca bateria." #: src/input/wiimote_manager.cpp:379 msgid "" @@ -3592,7 +3593,7 @@ msgid "Found %d wiimote" msgid_plural "Found %d wiimotes" msgstr[0] "Foi encontrado %d wiimote" msgstr[1] "Foram encontrados %d wiimotes" -msgstr[2] "Encontrados %d wiimotes" +msgstr[2] "Foram encontrados %d wiimotes" #: src/input/wiimote_manager.cpp:410 msgid "Could not detect any wiimote :/" @@ -3608,7 +3609,7 @@ msgstr "Penalidade!!" #: src/karts/controller/local_player_controller.cpp:332 msgid "Don't accelerate before 'Set!'" -msgstr "Não aceleres antes de 'Preparar!' " +msgstr "Não aceleres antes de 'Preparar!'" #: src/karts/controller/spare_tire_ai.cpp:150 msgid "You can have at most 3 lives!" @@ -3620,7 +3621,7 @@ msgstr "+1 vida." #: src/karts/kart.cpp:1024 msgid "You were too slow!" -msgstr "Foste demasiado lento! " +msgstr "Foste demasiado lento!" #: src/karts/kart.cpp:1025 msgid "You won the race!" @@ -3644,11 +3645,11 @@ msgid "" " Would you like this feature to be enabled? (To change this setting at a " "later time, go to options, select tab 'General', and edit \"Connect to the " "Internet\")." -msgstr "O SuperTuxKart poderá ligar ao servidor para descarregar extensões e notificar-te de atualizações. Lê a nossa política de privacidade em https://supertuxkart.net/Privacy. Gostarias de ativar esta função? (Podes mudar esta opção mais tarde, vai a Opções, no separador 'Geral', e marca \"Ligar à Internet\".)" +msgstr "O SuperTuxKart poderá ligar ao servidor para descarregar extensões e notificar-te de atualizações. Lê a nossa política de privacidade em https://supertuxkart.net/Privacy. Gostarias de ativar esta função? (Para mudar esta opção mais tarde, vai a Opções, no separador 'Geral', e marca \"Ligar à Internet\".)" #: src/main.cpp:2386 msgid "Your screen resolution is too low to run STK." -msgstr "A tua resolução do ecrã é demasiado baixa para o jogo." +msgstr "A tua resolução do ecrã é demasiado baixa para correr o STK." #: src/main.cpp:2437 msgid "" @@ -3739,7 +3740,7 @@ msgstr "%s marcou um golo!" #: src/modes/soccer_world.cpp:535 src/modes/soccer_world.cpp:662 #, c-format msgid "Oops, %s made an own goal!" -msgstr "Oops, %s marcou na própria!" +msgstr "Ups, %s marcou autogolo!" #: src/modes/three_strikes_battle.cpp:641 #, c-format @@ -3768,7 +3769,7 @@ msgstr "Foste expulso do servidor." #: src/network/protocols/client_lobby.cpp:132 msgid "You were kicked: Ping too high." -msgstr "Foste expulso: o teu ping é demasiado alto (tempo de resposta com o servidor)." +msgstr "Foste expulso: o teu ping é demasiado alto." #: src/network/protocols/client_lobby.cpp:297 #: src/network/protocols/client_lobby.cpp:911 @@ -3783,7 +3784,7 @@ msgstr "Bot" #: src/network/protocols/client_lobby.cpp:641 #, c-format msgid "%s disconnected." -msgstr "%s desligado." +msgstr "%s desligou-se." #. I18N: Message shown in network lobby to tell user that #. player name is clickable @@ -3886,7 +3887,7 @@ msgstr "Não foi possível iniciar o jogo online." #. I18N: Error message shown if live join or spectate failed in network #: src/network/protocols/client_lobby.cpp:1241 msgid "The game has ended, you can't live join or spectate anymore." -msgstr "O jogo terminou. Já não podes participar nele nem assistir." +msgstr "O jogo terminou. Já não podes participar ao vivo nem assistir." #. I18N: Error message shown if live join failed in network #: src/network/protocols/client_lobby.cpp:1245 @@ -3934,7 +3935,7 @@ msgstr "%s entrou no jogo." msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " "camera position." -msgstr "Prime <%s> ou <%s> para mudar o jogador alvo; <%s> ou <%s> para a posição da câmara. " +msgstr "Prime <%s> ou <%s> para mudar o jogador alvo; <%s> ou <%s> para a posição da câmara." #. I18N: Tell player he has successfully report this named player #: src/network/protocols/client_lobby.cpp:1654 @@ -3964,7 +3965,7 @@ msgstr "Não foi possível ligar ao servidor %s." #: src/network/protocols/connect_to_server.cpp:883 #, c-format msgid "Failed to detect port number for server %s." -msgstr "Falha ao detetar o número da porta do servidor %s" +msgstr "Falha ao detetar o número da porta do servidor %s." #: src/network/protocols/lobby_protocol.cpp:294 msgid "Network grand prix has been finished." @@ -4045,7 +4046,7 @@ msgstr "Padrão" #: src/race/grand_prix_data.cpp:641 src/states_screens/gp_info_screen.cpp:78 msgid "None" -msgstr "Nenhum" +msgstr "Nenhuma" #: src/race/grand_prix_data.cpp:645 src/states_screens/gp_info_screen.cpp:80 msgid "Random" @@ -4065,7 +4066,7 @@ msgstr "Seguir o Líder" #. I18N: Game mode #: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 msgid "3 Strikes Battle" -msgstr "Batalha de 3 Golpes" +msgstr "Batalha de 3 Vidas" #: src/replay/replay_recorder.cpp:358 msgid "Incomplete replay file will not be saved." @@ -4138,7 +4139,7 @@ msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" -msgstr "Ocorreu um erro na ligação ao site de extensões. Certifica-te de que estás ligado à Internet e que o SuperTuxKart não está a ser bloqueado pela firewall." +msgstr "Ocorreu um erro na ligação ao site de extensões. Certifica-te de que estás ligado à Internet e que o SuperTuxKart não está a ser bloqueado pela firewall" #: src/states_screens/arenas_screen.cpp:278 #: src/states_screens/arenas_screen.cpp:330 @@ -4164,7 +4165,7 @@ msgstr[2] "%d arenas indisponíveis para o modo Um Jogador." #: src/states_screens/credits.cpp:184 msgid "translator-credits" -msgstr "Contribuições no Launchpad/Transifex:\nJoão Frade / WWW.100NOME.ML\n274fb1bc2f045587a5bbfc0549580229_c79ef42 , 2015\nBenau, 2018-2020\nCrystal Da Eevee, 2019-2021\nDaniel Luiz Lorenzi, 2022\nPedroxz, 2017\nRui, 2016-2019\nRui, 2016\nAuria\nDawid Gan\nBruno Ramalhete\nDouglas Moura\nEvandro P. Alves\nFátima de Menezes Dantas\nRicardo Conde\nSTK-team\nSérgio Marques" +msgstr "Contribuições no Launchpad/Transifex:\nJoão Frade / 100Nome.blogs.sapo.pt\n274fb1bc2f045587a5bbfc0549580229_c79ef42 , 2015\nBenau, 2018-2020\nCrystalDaEevee, 2019-2023\nDaniel Luiz Lorenzi, 2022\nPedroxz, 2017\nRui, 2016-2019\nAuria\nDawid Gan\nBruno Ramalhete\nDouglas Moura\nEvandro P. Alves\nFátima de Menezes Dantas\nRicardo Conde\nSTK-team\nSérgio Marques\nHugo Carvalho" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:65 msgctxt "achievement_info" @@ -4250,25 +4251,25 @@ msgstr "Corridas finalizadas na dificuldade Principiante" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:186 msgid "Intermediate races started" -msgstr "Corridas iniciadas na dificuldade Intermédio " +msgstr "Corridas iniciadas na dificuldade Intermédio" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:188 msgid "Intermediate races finished" -msgstr "Corridas finalizadas na dificuldade Intermédio " +msgstr "Corridas finalizadas na dificuldade Intermédio" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:190 msgid "Expert races started" -msgstr "Corridas iniciadas na dificuldade Perito " +msgstr "Corridas iniciadas na dificuldade Perito" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:192 msgid "Expert races finished" -msgstr "Corridas finalizadas na dificuldade Perito " +msgstr "Corridas finalizadas na dificuldade Perito" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4280,7 +4281,7 @@ msgstr "Corridas iniciadas na dificuldade SuperTux" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:196 msgid "SuperTux races finished" -msgstr "Corridas finalizadas na dificuldade SuperTux " +msgstr "Corridas finalizadas na dificuldade SuperTux" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4322,13 +4323,13 @@ msgstr "Corridas Seguir o Líder finalizadas" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:210 msgid "3 Strikes battles started" -msgstr "Batalhas de 3 Golpes iniciadas" +msgstr "Batalhas de 3 Vidas iniciadas" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:212 msgid "3 Strikes battles finished" -msgstr "Batalhas de 3 Golpes terminadas" +msgstr "Batalhas de 3 Vidas finalizadas" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4407,7 +4408,7 @@ msgstr "Potenciadores utilizados" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:254 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:262 msgid " (1 race)" -msgstr " (1 corrida)" +msgstr " (numa corrida)" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4457,7 +4458,7 @@ msgstr "Derrapagens" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:269 msgid " (1 lap)" -msgstr " (1 volta)" +msgstr " (numa volta)" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4557,7 +4558,7 @@ msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" "To add a keyboard config, you can use the button below, HOWEVER please note that most keyboards only support a limited amount of simultaneous keypresses and are thus inappropriate for multiplayer gameplay. (You can, however, connect multiple keyboards to this device. Remember that everyone still needs different keybindings in this case.)" -msgstr "Novos controladores de jogo vão aparecer automaticamente na lista quando os ligares a este dispositivo.\n\nPara adicionar uma configuração de teclado, usa o botão abaixo, CONTUDO tem em atenção que a maioria dos teclados só regista um número limitado de teclas premidas ao mesmo tempo, sendo assim inapropriados para multijogador. (No entanto, poderás ligar vários teclados a este dispositivo. Lembra-te de que ainda assim todos os teclados terão de ter diferentes atribuições de teclas.)" +msgstr "Novos comandos de jogo aparecerão automaticamente na lista quando os ligares a este dispositivo.\n\nPara adicionar uma configuração de teclado, usa o botão abaixo, CONTUDO tem em atenção que a maioria dos teclados só regista um número limitado de teclas premidas ao mesmo tempo, sendo assim inapropriados para multijogador. (No entanto, poderás ligar vários teclados a este dispositivo. Lembra-te de que ainda assim todos os teclados terão de ter atribuições de teclas diferentes.)" #. I18N: In the 'add new input device' dialog #: src/states_screens/dialogs/add_device_dialog.cpp:87 @@ -4594,7 +4595,7 @@ msgstr "Tamanho: %s" #: src/states_screens/dialogs/addons_pack.cpp:220 #: src/states_screens/dialogs/download_assets.cpp:201 msgid "Sorry, downloading the add-on failed" -msgstr "Ocorreu um erro ao descarregar a extensão." +msgstr "Infelizmente, ocorreu um erro ao descarregar a extensão" #: src/states_screens/dialogs/addons_loading.cpp:374 #, c-format @@ -4614,15 +4615,15 @@ msgstr "Ocorreu um erro ao remover a extensão %s." #: src/states_screens/dialogs/addons_pack.cpp:66 msgid "Background download completed." -msgstr "Download em segundo plano completo." +msgstr "Descarga em segundo plano completa." #: src/states_screens/dialogs/addons_pack.cpp:127 msgid "Background download" -msgstr "Download em segundo plano" +msgstr "Descarga em segundo plano" #: src/states_screens/dialogs/addons_pack.cpp:136 msgid "Background download has already started." -msgstr "O download em segundo plano já foi iniciado." +msgstr "A descarga em segundo plano já foi iniciada." #: src/states_screens/dialogs/change_password_dialog.cpp:137 msgid "Current password invalid." @@ -4731,14 +4732,14 @@ msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " "don't have a wifi connection." -msgstr "O SuperTuxKart vai descarregar recursos integrais (incluindo texturas de alta qualidade e música) para uma melhor experiência de jogo; isto usará os teus dados móveis se não tiveres uma ligação wifi." +msgstr "O SuperTuxKart vai descarregar recursos completos (incluindo texturas de alta qualidade e música) para uma melhor experiência de jogo; isto usará os teus dados móveis se não tiveres uma ligação wifi." #. I18N: In download assets dialog #: src/states_screens/dialogs/download_assets.cpp:116 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." -msgstr "O SuperTuxKart vai descarregar recursos integrais (incluindo texturas de alta qualidade e música) para uma melhor experiência de jogo." +msgstr "O SuperTuxKart vai descarregar recursos completos (inclui texturas de alta qualidade e música) para uma melhor experiência." #: src/states_screens/dialogs/enter_address_dialog.cpp:42 msgid "" @@ -4830,7 +4831,7 @@ msgstr "Número de karts: %d" #: src/states_screens/dialogs/high_score_info_dialog.cpp:137 #, c-format msgid "Time target: %s" -msgstr "Meta de tempo: 1 %s" +msgstr "Tempo alvo: 1 %s" #: src/states_screens/dialogs/high_score_info_dialog.cpp:139 #, c-format @@ -4940,7 +4941,7 @@ msgstr "A conversação está desativada, ativa-a no menu Opções." #: src/states_screens/dialogs/race_paused_dialog.cpp:132 msgid "Back to Battle" -msgstr "Voltar à partida de Batalha" +msgstr "Voltar à Batalha" #: src/states_screens/dialogs/race_paused_dialog.cpp:135 msgid "Setup New Game" @@ -4948,11 +4949,11 @@ msgstr "Configurar Novo Jogo" #: src/states_screens/dialogs/race_paused_dialog.cpp:137 msgid "Restart Battle" -msgstr "Reiniciar partida de Batalha" +msgstr "Reiniciar Batalha" #: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Exit Battle" -msgstr "Sair da partida de Batalha" +msgstr "Sair da Batalha" #: src/states_screens/dialogs/race_paused_dialog.cpp:146 #: src/states_screens/race_result_gui.cpp:350 @@ -4991,13 +4992,13 @@ msgstr "Por favor, lê os termos e condições do SuperTuxKart em '%s'. Tens de #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:60 msgid "Nitro challenge" -msgstr "Desafio de coleta de nitro" +msgstr "Desafio de nitro" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:65 #: src/states_screens/race_setup_screen.cpp:137 msgid "Ghost replay race" -msgstr "Desafiar Fantasma" +msgstr "Corrida Contra Fantasma" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 @@ -5017,21 +5018,21 @@ msgstr "Tipo: %s" #: src/states_screens/race_result_gui.cpp:2119 #, c-format msgid "Required Rank: %i" -msgstr "Posição mínima exigida: %iº lugar" +msgstr "Posição alvo: %iº lugar" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 #: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Required Time: %i" -msgstr "Tempo máximo exigido: %i" +msgstr "Tempo alvo: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 #: src/states_screens/race_result_gui.cpp:2138 #, c-format msgid "Required Nitro Points: %i" -msgstr "Pontos de nitro mínimos exigidos: %i" +msgstr "Pontos de nitro alvo: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:109 @@ -5231,7 +5232,7 @@ msgstr "Desbloqueaste %s!" #: src/states_screens/feature_unlocked.cpp:645 msgid "Challenge Completed" -msgstr "Desafio Terminado" +msgstr "Desafio Concluído" #: src/states_screens/feature_unlocked.cpp:684 msgid "You unlocked track %0" @@ -5255,13 +5256,13 @@ msgstr "Jogadores" #: src/states_screens/gp_info_screen.cpp:172 #: src/states_screens/gp_info_screen.cpp:230 msgid "Reload" -msgstr "Recarregar" +msgstr "Regerar" #: src/states_screens/grand_prix_cutscene.cpp:77 #: src/states_screens/grand_prix_editor_screen.cpp:100 #: src/states_screens/grand_prix_editor_screen.cpp:117 msgid "Please enter the name of the grand prix" -msgstr "Introduz o nome do campeonato" +msgstr "Introduz um nome para o campeonato" #: src/states_screens/grand_prix_editor_screen.cpp:168 msgid "Please select a Grand Prix" @@ -5286,7 +5287,7 @@ msgstr "O nome é demasiado longo." #. I18N: when failing a GP #: src/states_screens/grand_prix_lose.cpp:157 msgid "Better luck next time!" -msgstr "Pode ser que tenhas mais sorte na próxima vez!" +msgstr "Pode ser que tenhas mais sorte da próxima!" #: src/states_screens/grand_prix_win.cpp:168 msgid "You completed a challenge!" @@ -5307,15 +5308,15 @@ msgstr "Número de karts" #: src/states_screens/high_score_selection.cpp:352 msgid "Are you sure you want to remove this high score entry?" -msgstr "Tens a certeza de que queres remover este recorde?" +msgstr "Tens a certeza de que queres remover este tempo recorde?" #: src/states_screens/high_score_selection.cpp:360 msgid "Are you sure you want to remove all of your high scores?" -msgstr "Tens a certeza de que queres remover todos os teus recordes?" +msgstr "Tens a certeza de que queres remover todos os tempos recorde?" #: src/states_screens/kart_selection.cpp:447 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" -msgstr "Liga um teclado ou controlador de jogo para jogares Multijogador em Ecrã Dividido" +msgstr "Liga um teclado ou comando de jogo para jogares Multijogador em Ecrã Dividido" #: src/states_screens/kart_selection.cpp:933 #: src/states_screens/kart_selection.cpp:1616 @@ -5359,11 +5360,11 @@ msgstr "Não podes descarregar extensões sem acesso à Internet. Se quiseres de #: src/states_screens/main_menu_screen.cpp:626 msgid "The add-ons module is currently disabled in the Options screen" -msgstr "De momento o módulo de extensões está desativado no ecrã de Opções." +msgstr "De momento, o módulo de extensões está desativado no ecrã de Opções" #: src/states_screens/main_menu_screen.cpp:638 msgid "Please wait while the add-ons are loading" -msgstr "Aguarda enquanto as extensões são carregadas" +msgstr "Por favor, aguarda enquanto as extensões são carregadas" #: src/states_screens/main_menu_screen.cpp:659 msgid "Are you sure you want to quit STK?" @@ -5411,7 +5412,7 @@ msgstr "Assistir" #: src/states_screens/online/networking_lobby.cpp:204 msgid "Install addon" -msgstr "Instalar addon" +msgstr "Instalar extensão" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, @@ -5527,24 +5528,24 @@ msgstr "Offline" #: src/states_screens/online/online_profile_settings.cpp:79 msgid "Enter new E-mail below" -msgstr "Introduz o novo E-mail em baixo" +msgstr "Introduz o novo e-mail em baixo" #: src/states_screens/online/online_profile_settings.cpp:84 msgid "New Email has to be between 5 and 254 characters long!" -msgstr "O novo E-Mail deverá ter entre 5 e 254 caracteres!" +msgstr "O novo e-mail deverá ter entre 5 e 254 caracteres!" #: src/states_screens/online/online_profile_settings.cpp:93 msgid "New Email is invalid!" -msgstr "Novo E-Mail inválido!" +msgstr "O novo e-mail é inválido!" #: src/states_screens/online/online_profile_settings.cpp:118 msgid "E-mail changed!" -msgstr "O E-Mail foi alterado!" +msgstr "O e-mail foi alterado!" #: src/states_screens/online/online_profile_settings.cpp:120 #, c-format msgid "Failed to change E-mail: %s" -msgstr "Não foi possivel mudar o E-Mail: %s" +msgstr "Falha ao alterar o e-mail: %s" #. I18N: Shown to players when he is not is not logged in #: src/states_screens/online/online_screen.cpp:201 @@ -5574,17 +5575,17 @@ msgstr "O nome de utilizador não pode estar em branco." #: src/states_screens/online/register_screen.cpp:362 msgid "Online username and password must not be the same!" -msgstr "O nome de usuário e a senha online não podem ser iguais!" +msgstr "O nome de utilizador online e a palavra-passe não podem ser iguais!" #: src/states_screens/online/register_screen.cpp:366 msgid "Emails don't match!" -msgstr "Os e-mails não são iguais!" +msgstr "Os e-mails não se correspondem!" #: src/states_screens/online/register_screen.cpp:370 msgid "" "Online username can only contain alphanumeric (ASCII) characters, periods, " "dashes and underscores!" -msgstr "Nomes de utilizador online apenas podem conter caracteres alfanuméricos (ASCII), pontos, traços e sublinhados! " +msgstr "Nomes de utilizador online apenas podem conter caracteres alfanuméricos (ASCII), pontos, traços e sublinhados!" #: src/states_screens/online/register_screen.cpp:374 msgid "Online username has to be between 3 and 30 characters long!" @@ -5596,7 +5597,7 @@ msgstr "O nome de utilizador online não pode começar com um número!" #: src/states_screens/online/register_screen.cpp:386 msgid "Email has to be between 5 and 254 characters long!" -msgstr "O e-mail tem de ter entre 5 e 254 caracteres!" +msgstr "O e-mail deverá ter entre 5 e 254 caracteres!" #: src/states_screens/online/register_screen.cpp:392 msgid "Email is invalid!" @@ -5606,7 +5607,7 @@ msgstr "O e-mail é inválido!" msgid "" "You will receive an email with further instructions regarding account " "activation. Please be patient and be sure to check your spam folder." -msgstr "Vais receber um email com informações detalhadas sobre a ativação da conta. Por favor, sê paciente e lembra-te de verificar a pasta de spam." +msgstr "Vais receber um e-mail com informações detalhadas sobre a ativação da conta. Por favor, sê paciente e lembra-te de verificar a pasta de spam." #: src/states_screens/online/register_screen.cpp:495 msgid "Internet access is disabled, please enable it in the options" @@ -5827,7 +5828,7 @@ msgstr "Tens a certeza de que queres eliminar permanentemente esta configuraçã #: src/states_screens/options/options_screen_device.cpp:641 msgid "Enter new configuration name, leave empty to revert default value." -msgstr "Introduz o nome da nova configuração; deixa em branco para reverter para o nome padrão." +msgstr "Introduz o novo nome da configuração; deixa em branco para reverter para o nome padrão." #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. @@ -5835,17 +5836,17 @@ msgstr "Introduz o nome da nova configuração; deixa em branco para reverter pa msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" -msgstr "No modo multijogador, os jogadores podem selecionar perfis em\ndesvantagem (mais difícil) no ecrã de seleção de kart" +msgstr "No modo multijogador, os jogadores poderão selecionar perfis em\ndesvantagem (mais difícil) no ecrã de seleção de kart" #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server #: src/states_screens/options/options_screen_general.cpp:119 msgid "Install full game assets" -msgstr "Instalar recursos integrais do jogo" +msgstr "Instalar recursos completos do jogo" #: src/states_screens/options/options_screen_general.cpp:238 msgid "Are you sure to uninstall full game assets?" -msgstr "Tens a certeza de que queres desinstalar os recursos integrais do jogo?" +msgstr "Tens a certeza de que queres desinstalar o pacote completo dos recursos do jogo?" #: src/states_screens/options/options_screen_input.cpp:119 #, c-format @@ -5928,7 +5929,7 @@ msgid "" "Closing the game before the story mode's completion invalidates the timer.\n" "\n" "To use the speedrun mode, please use a new profile." -msgstr "O modo Speedrun só pode ser ativado se o jogo não tiver sido fechado desde o começo do modo História.\n\nFechar o jogo antes de completado o modo História invalida o temporizador.\n\nPara usares o modo Speedrun, usa um perfil novo." +msgstr "O modo Speedrun só pode ser ativado se o jogo não tiver sido fechado depois de iniciado o modo História.\n\nFechar o jogo antes de completado o modo História invalida o cronómetro.\n\nPara ativares o modo Speedrun, por favor usa um perfil novo." #. I18N: In the video options #: src/states_screens/options/options_screen_video.cpp:259 @@ -5946,7 +5947,7 @@ msgstr "A sincronização vertical força a placa gráfica a só fornecer\num no #. I18N: in graphical options. #: src/states_screens/options/options_screen_video.cpp:279 msgid "Vsync will not work if your drivers don't support it." -msgstr "A sincronização vertical não vai funcionar se os controladores instalados não a suportarem." +msgstr "A sincronização vertical não funcionará se os controladores\ninstalados não a suportarem." #. I18N: in graphical options #: src/states_screens/options/options_screen_video.cpp:681 @@ -5976,7 +5977,7 @@ msgstr "Dispersão da luz: %s" #: src/states_screens/options/options_screen_video.cpp:696 #, c-format msgid "Anti-aliasing: %s" -msgstr "Suavização: %s" +msgstr "Antisserrilhado: %s" #. I18N: in graphical options #: src/states_screens/options/options_screen_video.cpp:699 @@ -6004,7 +6005,7 @@ msgstr "Florescência: %s" #: src/states_screens/options/options_screen_video.cpp:712 #, c-format msgid "Glow (outlines): %s" -msgstr "Brilho (esboços) : %s" +msgstr "Aura (contornos): %s" #. I18N: in graphical options #: src/states_screens/options/options_screen_video.cpp:716 @@ -6040,7 +6041,7 @@ msgstr "Tens de introduzir a palavra-passe." #: src/states_screens/options/user_screen.cpp:575 #, c-format msgid "Logging out '%s'" -msgstr "Terminar sessão '%s'" +msgstr "A terminar sessão de '%s'" #: src/states_screens/options/user_screen.cpp:576 #, c-format @@ -6103,7 +6104,7 @@ msgstr "por" #: src/states_screens/race_gui_base.cpp:769 msgid "Collect nitro!" -msgstr "Apanha garrafas de nitro!" +msgstr "Apanha nitro!" #: src/states_screens/race_gui_base.cpp:771 msgid "Follow the leader!" @@ -6117,7 +6118,7 @@ msgstr "Top %i" #: src/states_screens/race_gui.cpp:447 msgid "Challenge Failed" -msgstr "Desafio falhado" +msgstr "Desafio Falhado" #. I18N: Shown when multitouch GUI exists #. and press the podium (2, 1, 3 like) icon instead of fire button @@ -6157,7 +6158,7 @@ msgstr "Voltar à Seleção de Desafio" #: src/states_screens/race_result_gui.cpp:345 msgid "Race against the new ghost replay" -msgstr "Desafiar o Novo Fantasma" +msgstr "Correr contra o novo fantasma" #: src/states_screens/race_result_gui.cpp:353 msgid "Back to the menu" @@ -6170,12 +6171,12 @@ msgstr "Queres mesmo abortar o Campeonato?" #: src/states_screens/race_result_gui.cpp:636 #: src/states_screens/race_result_gui.cpp:1529 msgid "Red Team Wins" -msgstr "A equipa vermelha vence" +msgstr "Vence a Equipa Vermelha!" #: src/states_screens/race_result_gui.cpp:638 #: src/states_screens/race_result_gui.cpp:1533 msgid "Blue Team Wins" -msgstr "A equipa azul vence" +msgstr "Vence a Equipa Azul!" #: src/states_screens/race_result_gui.cpp:640 #: src/states_screens/race_result_gui.cpp:1538 @@ -6196,7 +6197,7 @@ msgstr "Eliminado" #: src/states_screens/race_result_gui.cpp:1608 #: src/states_screens/race_result_gui.cpp:1670 msgid "(Own Goal)" -msgstr "(Própria Baliza)" +msgstr "(Autogolo)" #: src/states_screens/race_result_gui.cpp:1749 #, c-format @@ -6233,7 +6234,7 @@ msgstr "Falhaste o desafio!" #: src/states_screens/race_result_gui.cpp:2155 msgid "Reached Requirements of SuperTux" -msgstr "Requisitos da dificuldade SuperTux atingidos" +msgstr "Requisitos para SuperTux atingidos" #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" @@ -6246,7 +6247,7 @@ msgstr "Não há potenciadores, só o teu talento ao volante conta!" #. I18N: short definition for follow-the-leader game mode #: src/states_screens/race_setup_screen.cpp:109 msgid "Keep up with the leader kart but don't overtake it!" -msgstr "Fica perto do líder mas não o ultrapasses." +msgstr "Fica perto do líder mas não o ultrapasses!" #: src/states_screens/race_setup_screen.cpp:115 msgid "Hit others with weapons until they lose all their lives." @@ -6254,11 +6255,11 @@ msgstr "Atinge os outros com armas até ficarem sem vidas." #: src/states_screens/race_setup_screen.cpp:120 msgid "Push the ball into the opposite cage to score goals." -msgstr "Empurra a bola para a baliza adversária e marca golos." +msgstr "Empurra a bola para a baliza adversária para marcar golos." #: src/states_screens/race_setup_screen.cpp:130 msgid "Explore tracks to find all hidden eggs" -msgstr "Explora as pistas e encontra todos os ovos escondidos." +msgstr "Explora as pistas para encontrar todos os ovos escondidos" #: src/states_screens/race_setup_screen.cpp:138 msgid "Race against ghost karts and try to beat them!" @@ -6271,7 +6272,7 @@ msgstr "Completa o máximo de voltas possível num dado tempo." #. I18N: In soccer setup screen #: src/states_screens/soccer_setup_screen.cpp:120 msgid "Press red or blue soccer icon to change team" -msgstr "Toca nos ícones de futebol vermelho ou azul para mudares de equipa" +msgstr "Toca nos ícones vermelho ou azul para mudares de equipa" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) @@ -6332,50 +6333,50 @@ msgstr "Precisas de mais pontos\npara entrar neste desafio!\nProcura no minimapa #: ../stk-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." -msgstr "Acelera com <%s> e vira com <%s> e <%s>" +msgstr "Acelera com <%s> e vira com <%s> e <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." -msgstr "Acelera tocando na parte de cima do volante, e vira movendo para a esquerda ou direita." +msgstr "Acelera tocando na parte de cima do volante e vira movendo para a esquerda ou direita." #: ../stk-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." -msgstr "Acelera movendo o acelerador para cima, e vira inclinando o teu dispositivo." +msgstr "Acelera movendo o acelerador para cima e vira inclinando o teu dispositivo." #: ../stk-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." -msgstr "Acelera movendo o acelerador para cima, e vira rodando o teu dispositivo." +msgstr "Acelera movendo o acelerador para cima e vira rodando o teu dispositivo." #: ../stk-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" -msgstr "Apanha presentes e dispara uma arma com <%s> para atirares estas caixas ao ar!" +msgstr "Apanha presentes e dispara com <%s> para para derrubares estas caixas!" #: ../stk-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" -msgstr "Apanha presentes e dispara tocando no ícone de bólingue para atirares estas caixas ao ar!" +msgstr "Apanha presentes e dispara tocando no ícone de bólingue para derrubares estas caixas!" #: ../stk-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" "Fire the weapon with <%s> while pressing <%s> to fire behind!" -msgstr "Prime <%s> para olhares à retaguarda.\nDispara uma arma com <%s> ou enquanto primes <%s> para disparar atrás!" +msgstr "Prime <%s> para olhares à retaguarda.\nDispara com <%s> ou enquanto primes <%s> para disparar atrás!" #: ../stk-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" -msgstr "Toca no ícone do espelho para olhares à retaguarda.\nDispara uma arma para trás segurando o ícone do espelho e depois deslizando para o ícone da bola de bólingue!" +msgstr "Toca no ícone do espelho para olhares à retaguarda.\nDispara para trás segurando o ícone do espelho e depois deslizando para o ícone de bólingue!" #: ../stk-assets/tracks/tutorial/scripting.as:98 #, c-format @@ -6393,30 +6394,30 @@ msgstr "Apanha garrafas de nitro (vamos usá-las após a curva)." #: ../stk-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." -msgstr "Oh não! Quando estiveres em apuros, prime <%s> para chamar o resgate." +msgstr "Oh, não! Quando estiveres em apuros, prime <%s> para chamar o resgate." #: ../stk-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." -msgstr "Oh não! Quando estiveres em apuros, toca no ícone do pássaro para chamar o resgate." +msgstr "Oh, não! Quando estiveres em apuros, toca no ícone do pássaro para chamar o resgate." #: ../stk-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." -msgstr "Acelera e prime <%s> enquanto viras para derrapar.\nDerrapar por um curto período de tempo ajuda-te a virar mais rápido durante curvas apertadas." +msgstr "Acelera e prime <%s> ao virar para derrapar.\nDerrapar por pouco tempo ajuda-te a virar mais rápido em curvas apertadas." #: ../stk-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." -msgstr "Acelera e toca no ícone de derrapagem enquanto viras para derrapar.\nDerrapar por um curto período de tempo ajuda-te a virar mais rápido durante curvas apertadas." +msgstr "Acelera e toca no ícone de derrapar ao virar para derrapar.\nDerrapar por pouco tempo ajuda-te a virar mais rápido em curvas apertadas." #: ../stk-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" -msgstr "Nota que se derrapares durante vários segundos, terás um impulso extra como recompensa!" +msgstr "Nota que, se derrapares por vários segundos, receberás um impulso extra!" #: ../stk-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" @@ -6426,13 +6427,13 @@ msgstr "Estás pronto para correr. Boa sorte!" #. description in Google Play #: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 msgid "A 3D open-source kart racing game" -msgstr "Um jogo 3D de karting com mascotes de aplicativos open source." +msgstr "Um jogo de karting de código aberto em 3D" #. I18N: Keywords in desktop entry, translators please keep it separated with #. semicolons #: supertuxkart.desktop:11 msgid "tux;game;race;" -msgstr "tux;jogo;corrida" +msgstr "tux;jogo;corrida;" #: supertuxkart.appdata.xml:8 msgid "" @@ -6440,7 +6441,7 @@ msgid "" "variety of characters, tracks, and modes to play. Our aim is to create a " "game that is more fun than realistic, and provide an enjoyable experience " "for all ages." -msgstr "Karts. Nitro. Ação! SuperTuxKart é um jogo 3D de karting arcade com uma variedade de personagens, pistas e vários modos de jogo. O nosso objectivo é criar um jogo que se foque mais na diversão do que no realismo, e dar uma experiência disfrutante aos jogadores de todas as idades." +msgstr "Karts. Nitro. Ação! SuperTuxKart é um arcada de corrida 3D em código aberto com uma variedade de personagens, pistas e modos para jogar. O nosso objetivo é criar um jogo que seja mais divertido do que realista, e propiciar uma experiência agradável para todas as idades." #: supertuxkart.appdata.xml:11 msgid "" @@ -6469,17 +6470,17 @@ msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." -msgstr "Esta é uma versão de teste. Contém as mais recentes modificações e improvisos. É usada para manter o jogo o mais estavel e optimizado possivel" +msgstr "Esta é uma versão instável do SuperTuxKart que contém as mais recentes melhorias. Ela é lançada sobretudo para testes ao jogo, possibilitando uma versão estável no seu melhor." #: supertuxkart.appdata.xml:23 msgid "" "This version can be installed in parallel with the stable version on the " "device." -msgstr "Esta versão pode ser instalada separadamente com a versão oficial." +msgstr "Esta versão pode ser instalada no dispositivo em paralelo com a versão estável." #: supertuxkart.appdata.xml:26 msgid "If you need more stability, consider using the stable version: %s" -msgstr "Se precisares de estabilidade, ou de melhor performance, tenta usar a versão oficial: %s" +msgstr "Se desejas mais estabilidade, considera usar a versão estável: %s" #: supertuxkart.appdata.xml:44 msgid "SuperTuxKart Team" diff --git a/data/po/pt_BR.po b/data/po/pt_BR.po index f949a1f4851..bf3a3831a43 100644 --- a/data/po/pt_BR.po +++ b/data/po/pt_BR.po @@ -43,7 +43,7 @@ msgstr "Erro ao extrair os dados do jogo" #. I18N: In Android UI, po_extract_error_msg msgid "Check remaining device space or reinstall SuperTuxKart." -msgstr "Verifique se há espaço suficiente no dispositivo ou reinicie o SuperTuxKart." +msgstr "Verifique se há espaço suficiente no dispositivo ou reinstale o SuperTuxKart." #. I18N: In Android UI, po_quit #. I18N: ./data/gui/screens/main_menu.stkgui @@ -924,7 +924,7 @@ msgstr "Dados do usuário" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Remover Amizade" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -934,17 +934,17 @@ msgstr "Adicionar como amigo" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Aceitar Convite" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Recusar Convite" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Ver Perfil" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1132,7 +1132,7 @@ msgstr "Créditos" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Pular" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -2012,7 +2012,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Você pode jogar sem criar uma conta online selecionando uma conta offline. Porém você não poderá se conectar aos amigos, dar votos aos complementos, etc. Por favor, leia nossa Declaração de Privacidade em https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 diff --git a/data/po/ro.po b/data/po/ro.po index 8d89f9324e5..9d352e530b0 100644 --- a/data/po/ro.po +++ b/data/po/ro.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the supertuxkart package. # # Translators: -# Dominik Jastrzębski, 2022-2023 +# Dominik Jastrzębski, 2022-2024 # Har Gosmos , 2019 # Nicolae Crefelean, 2015,2017-2018 # Sorin Ingeaua , 2020 @@ -13,7 +13,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Dominik Jastrzębski, 2022-2023\n" +"Last-Translator: Dominik Jastrzębski, 2022-2024\n" "Language-Team: Romanian (http://app.transifex.com/supertuxkart/supertuxkart/language/ro/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -379,16 +379,16 @@ msgstr "Reveni" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog msgid "Accept" -msgstr "Acepta" +msgstr "Acceptați" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui msgid "Camera Settings" -msgstr "Setări cameră" +msgstr "Setările camerei" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera settings msgid "Player camera" -msgstr "Camera de la jucator" +msgstr "Cameră de la jucător" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -398,7 +398,7 @@ msgstr "FOV" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "Distance" -msgstr "Distanta" +msgstr "Distanță" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -413,7 +413,7 @@ msgstr "Cameră netedă" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera settings msgid "Backward camera" -msgstr "Camera pe spate" +msgstr "Cameră pe spate" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -610,24 +610,24 @@ msgstr "Progres" #. I18N: ./data/gui/dialogs/online/change_password.stkgui #. I18N: In the change password dialog msgid "Password Change" -msgstr "Schimba parola" +msgstr "Schimbă parola" #. I18N: ./data/gui/dialogs/online/change_password.stkgui #. I18N: In the change password dialog msgid "Current Password" -msgstr "Parola curenta" +msgstr "Parola curentă" #. I18N: ./data/gui/dialogs/online/change_password.stkgui #. I18N: In the change password dialog msgid "New Password" -msgstr "Parola Noua" +msgstr "Parola nouă" #. I18N: ./data/gui/dialogs/online/change_password.stkgui #. I18N: In the change password dialog #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog msgid "Confirm" -msgstr "Confirma" +msgstr "Confirmă" #. I18N: ./data/gui/dialogs/online/change_password.stkgui #. I18N: In the change password dialog @@ -640,12 +640,12 @@ msgstr "Trimite" #. I18N: Race paused button #: src/states_screens/dialogs/race_paused_dialog.cpp:143 msgid "Back to Race" -msgstr "Înapoi la Cursă" +msgstr "Înapoi la cursă" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button msgid "Quit Server" -msgstr "Iesi din server" +msgstr "Ieși din server" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Show in network ingame dialog to allow user to go back to lobby to @@ -657,14 +657,14 @@ msgstr "Înapoi la lobby" #. I18N: Race paused button #: src/states_screens/dialogs/race_paused_dialog.cpp:148 msgid "Restart Race" -msgstr "Reincepe cursa" +msgstr "Reîncepe cursa" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button msgid "Give Up Race" -msgstr "Iesi din Cursa" +msgstr "Ieși din cursă" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button @@ -702,7 +702,7 @@ msgstr "Reîncarca" #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog msgid "Account Recovery" -msgstr "Recuperaza contul" +msgstr "Recuperarea contului" #. I18N: ./data/gui/dialogs/online/recovery_info.stkgui #. I18N: In the recovery dialog @@ -715,7 +715,7 @@ msgstr "Veți primi un e-mail cu instrucțiuni suplimentare despre cum să vă r msgid "" "Fill in the username and email address you supplied at registration to be " "able to reset your password." -msgstr "Ca sa poti reseta parola ta" +msgstr "Completați numele de utilizator și adresa de e-mail pe care le-ați furnizat la înregistrare pentru a vă putea reseta parola." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog @@ -871,12 +871,12 @@ msgstr "Parola" #. I18N: In the server info dialog #: src/states_screens/dialogs/server_info_dialog.cpp:291 msgid "Bookmark this server" -msgstr "Marcă acest server" +msgstr "Marcați acest server" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "Add player" -msgstr "Adaugă jucător" +msgstr "Adăugați jucător" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network @@ -897,12 +897,12 @@ msgstr "Apăsați butonul „Toți jucătorii gata” după ce lista de jucător #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "Clear players" -msgstr "Jucatori limpezi" +msgstr "Jucători limpezi" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "All players ready" -msgstr "Toti jucatorii pregatiti" +msgstr "Toți jucătorii pregătiți" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -912,32 +912,32 @@ msgstr "Informații despre utilizator" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Ștergeți prietenul" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Add Friend" -msgstr "Adaugă prieten" +msgstr "Adăugați prieten" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Acceptați invitația" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Respingeți invitația" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Afișați profilul" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog msgid "Vote" -msgstr "Votează" +msgstr "Votați" #. I18N: ./data/gui/dialogs/overworld_dialog.stkgui #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui @@ -957,7 +957,7 @@ msgstr "Înapoi in meniu" #. I18N: ./data/gui/dialogs/overworld_dialog.stkgui #. I18N: In the in-game dialog msgid "Select kart" -msgstr "Selectează kart" +msgstr "Selectați kartul" #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When changing input configurations @@ -994,7 +994,7 @@ msgstr "Configurarea cursei" #: src/states_screens/race_result_gui.cpp:304 #: src/states_screens/race_result_gui.cpp:1142 msgid "Continue" -msgstr "Continuă" +msgstr "Continuați" #. I18N: ./data/gui/screens/addons_screen.stkgui msgid "SuperTuxKart Addons" @@ -1120,7 +1120,7 @@ msgstr "Autori" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Omite" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1139,12 +1139,12 @@ msgstr "Editați Marele Premiu" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item msgid "Move up" -msgstr "Mișcă în sus" +msgstr "Mișcați în sus" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item msgid "Move down" -msgstr "Mișcă în jos" +msgstr "Mișcați în jos" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item @@ -1160,12 +1160,12 @@ msgstr "Adaugă" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item msgid "Edit" -msgstr "Editează" +msgstr "Editați" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item msgid "Save" -msgstr "Salvează" +msgstr "Salvați" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: In the edit track screen @@ -1180,7 +1180,7 @@ msgstr "Cu spatele" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Ghost Replay Selection" -msgstr "Selecția Reluarea Fantoma" +msgstr "Selecția reluării fantomei" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen @@ -1189,12 +1189,12 @@ msgstr "Selecția Reluarea Fantoma" #. I18N: Game mode #: src/race/race_manager.cpp:1296 msgid "Egg Hunt" -msgstr "" +msgstr "Vânătoare de ouă" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Only show the best times" -msgstr "Arată doar cele mai bune timpuri" +msgstr "Arătați doar cele mai bune timpuri" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen @@ -1239,7 +1239,7 @@ msgstr "Înapoi" #: src/states_screens/track_info_screen.cpp:284 #: src/states_screens/track_info_screen.cpp:450 msgid "Maximum time (min.)" -msgstr "" +msgstr "Timp maxim (min.)" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen @@ -1404,7 +1404,7 @@ msgstr "Începe tutorialul" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." -msgstr "Colectează cadourile albastre ca să primești powerup" +msgstr "Colectați cadourile albastre ca să primiți powerup" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu @@ -1446,7 +1446,7 @@ msgstr "" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" -msgstr "" +msgstr "* Tastele de control se pot vedea/modifica în meniul Opțiuni" #. I18N: ./data/gui/screens/help2.stkgui msgid "SuperTuxKart features several game modes:" @@ -1528,7 +1528,7 @@ msgstr "" msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" -msgstr "Controleaza kartul" +msgstr "Controlați kartul" #. I18N: ./data/gui/screens/help3.stkgui msgid "" @@ -1597,7 +1597,7 @@ msgstr "" #. I18N: ./data/gui/screens/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" -msgstr "" +msgstr "Maleficul Nolok l-a capturat pe Gnu! Iată câteva sfaturi pentru a vă ajuta:" #. I18N: ./data/gui/screens/help5.stkgui #. I18N: In the help menu @@ -1606,7 +1606,7 @@ msgid "" "completed. In the top-right of the screen, it also tells you how many points" " you currently have. Complete as many challenges as possible, and Nolok will" " accept to race against you. Win to liberate Gnu!" -msgstr "" +msgstr "Această pictogramă de pe minimap arată provocările disponibile pe care nu le-ați finalizat. În partea dreaptă sus a ecranului, vă spune, de asemenea, câte puncte aveți în prezent. Finalizează cât mai multe provocări posibil, iar Nolok va accepta să concureze împotriva ta. Victorie pentru eliberarea lui Gnu!" #. I18N: ./data/gui/screens/help5.stkgui #. I18N: In the help menu @@ -3616,7 +3616,7 @@ msgstr "" #: src/karts/kart.cpp:1025 msgid "You won the race!" -msgstr "Ai castigat cursa!" +msgstr "Ați câștigat cursa!" #: src/karts/kart.cpp:1026 #, c-format @@ -3653,7 +3653,7 @@ msgid "" "Your graphics driver appears to be very old. Please check if an update is " "available. SuperTuxKart recommends a driver supporting %s or better. The " "game will likely still run, but in a reduced-graphics mode." -msgstr "" +msgstr "Driverul grafic pare să fie foarte vechi. Vă rugăm să verificați dacă este disponibilă o actualizare. SuperTuxKart recomandă un driver care să suporte %s sau mai bine. Probabil că jocul va rula în continuare, dar într-un mod cu grafică redusă." #: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 msgid "Server connection timed out." diff --git a/data/po/ru.po b/data/po/ru.po index 0fa5b4c025c..b639de81d08 100644 --- a/data/po/ru.po +++ b/data/po/ru.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the supertuxkart package. # # Translators: -# Andrei Stepanov, 2015-2023 +# Andrei Stepanov, 2015-2024 # Benau, 2018-2020 # cda3b49fcd26cff178434c994782573e_67b0153 , 2018 # Dmitry Dubrov , 2015 @@ -14,7 +14,8 @@ # Valeri , 2016,2018 # Valeri , 2016,2018 # cda3b49fcd26cff178434c994782573e_67b0153 , 2018 -# Артём Котлубай , 2022-2023 +# Темак, 2022-2023 +# Денис Ким , 2024 # Олег Лазарев , 2017,2019 msgid "" msgstr "" @@ -22,7 +23,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Andrei Stepanov, 2015-2023\n" +"Last-Translator: Andrei Stepanov, 2015-2024\n" "Language-Team: Russian (http://app.transifex.com/supertuxkart/supertuxkart/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -564,7 +565,7 @@ msgstr "Хорошо" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen msgid "Record the race for ghost replay" -msgstr "Записать гонку для повтора с призраком" +msgstr "Записать повтор с призраком во время гонки" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info action @@ -700,7 +701,7 @@ msgstr "Справка" #. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui #. I18N: In player rankings dialog msgid "Top 10 players" -msgstr "Топ-10 игроков" +msgstr "Топ-10 рейтинга игроков" #. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui msgid "Refresh" @@ -1427,7 +1428,7 @@ msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " "pressing the appropriate key or button. You can see your current level of " "nitro in the gauge at the bottom-right of the race screen." -msgstr "Собрав нитро-заряды, вы можете получить временный прирост скорости по нажатию соответствующей кнопки в нужный момент. Текущий уровень нитро показан в виде шкалы в правом нижнем углу экрана." +msgstr "Собрав нитро-заряды, вы можете получить временный прирост скорости по нажатии соответствующей кнопки в нужный момент. Текущий уровень нитро показан в виде шкалы в правом нижнем углу экрана." #. I18N: ./data/gui/screens/help1.stkgui #. I18N: In the help menu @@ -1488,7 +1489,7 @@ msgid "" "player who hits others the most will win in a given hit or time limit. In " "Capture The Flag, your team needs to bring the flag of the other team to " "your own flag base, as long as your flag is not captured by the other team." -msgstr "Есть 3 режима сражений: в «Битве трёх ударов» вам нужно поразить других оружием, пока они не потеряют все свои жизни. В «Свободном заезде» побеждает игрок, который поразит других больше всего по достижению нужного количества очков или по истечению времени. В «Захвате флага» ваша команда должна доставить флаг вражеской команды на собственную базу и не дать захватить свой флаг." +msgstr "Есть 3 режима сражений: в «Битве трёх ударов» вам нужно поразить других оружием, пока они не потеряют все свои жизни. В «Битве против всех» побеждает игрок, который поразит других больше всего по достижению нужного количества очков или по истечению времени. В «Захвате флага» ваша команда должна доставить флаг вражеской команды на собственную базу и не дать захватить свой флаг." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1511,7 +1512,7 @@ msgstr "Повтор с призраком: сразитесь против пр #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "Круговой заезд: пройдите как можно больше кругов за отведённое времени." +msgstr "Круговой заезд: пройдите как можно больше кругов за отведённое время." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1520,7 +1521,7 @@ msgid "" "instead of playing a single race, you play many in a row. The better you " "rank, the more points you get. In the end, the player with the most points " "wins the cup." -msgstr "* В бо́льшую часть этих режимов игры можно сыграть в Гран-при: вместо одной трассы, вы можете проехать сразу несколько. Чем лучше ваш ранг, тем больше очков вы получите. По окончании игрок с бо́льшим количеством очков выигрывает кубок." +msgstr "* В бо́льшую часть этих режимов игры можно сыграть в Гран-при: вместо одной трассы, вы можете проехать сразу несколько. Чем лучше ваш ранг, тем больше очков вы получите. По окончании игрок с наибольшим числом очков выигрывает кубок." #. I18N: ./data/gui/screens/help3.stkgui #. I18N: In the help menu @@ -1615,7 +1616,7 @@ msgid "" "completed. In the top-right of the screen, it also tells you how many points" " you currently have. Complete as many challenges as possible, and Nolok will" " accept to race against you. Win to liberate Gnu!" -msgstr "Этот значкок на мини-карте обозначает доступные для прохождения испытания. Он также показывает количество ваших очков в верхнем правом углу экрана. Завершите как можно больше испытаний, и Нолок посоревнуется с вами в гонке. Победите его, чтобы освободить Гну!" +msgstr "Этот значок на мини-карте обозначает доступные для прохождения испытания. Он также показывает количество ваших очков в верхнем правом углу экрана. Завершите как можно больше испытаний, и Нолок посоревнуется с вами в гонке. Победите его, чтобы освободить Гну!" #. I18N: ./data/gui/screens/help5.stkgui #. I18N: In the help menu @@ -1873,7 +1874,7 @@ msgstr "Лобби" #. I18N: In networking lobby to configuration server settings #: src/states_screens/online/networking_lobby.cpp:200 msgid "Configuration" -msgstr "Схема" +msgstr "Настройки" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby @@ -1919,7 +1920,7 @@ msgstr "…" #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: In the achievements screen msgid "Player rankings" -msgstr "Таблица лидеров" +msgstr "Рейтинг игроков" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen @@ -2009,7 +2010,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "Вы можете играть без создания сетевой учётной записи, выбрав автономную учётку. Но тогда вы не сможете подключаться к друзьям, голосовать за дополнения и прочее. Пожалуйста, ознакомься с нашим заявление о защите персональных данных по адресу: https://privacy.supertuxkart.net" +msgstr "Вы можете играть без создания сетевой учётной записи, выбрав автономный аккаунт. Но тогда вы не сможете подключаться к друзьям, голосовать за дополнения и прочее. Пожалуйста, ознакомьтесь с нашим заявлением о защите персональных данных по адресу: https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2307,7 +2308,7 @@ msgstr "Показывать счётчик кадров" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" -msgstr "Показывать другие карты с усилителями" +msgstr "Показывать усилители других картов" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings @@ -2322,7 +2323,7 @@ msgstr "Включить таймер скоростного прохожден #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" -msgstr "Разрешение рендеринга" +msgstr "Разрешение отрисовки" #. I18N: ./data/gui/screens/options_video.stkgui #. I18N: In the video settings @@ -3646,7 +3647,7 @@ msgid "" " Would you like this feature to be enabled? (To change this setting at a " "later time, go to options, select tab 'General', and edit \"Connect to the " "Internet\")." -msgstr "SuperTuxKart может подключаться к серверу для загрузки дополнений и уведомлять вас об обновлениях. Пожалуйста, прочтите нашу политику конфиденциальности на https://supertuxkart.net/Privacy. Вам нужна такая возможность? (Для изменения этой настройки перейдите в «Настройки» > «Основные» > «Подключаться к интернету»)." +msgstr "SuperTuxKart может подключаться к серверу для загрузки дополнений и уведомлять вас об обновлениях. Пожалуйста, прочтите нашу политику конфиденциальности на https://supertuxkart.net/Privacy. Хотите включить эту возможность? (Для правки этой настройки перейдите в «Настройки» > «Основные» > «Подключаться к интернету»)." #: src/main.cpp:2386 msgid "Your screen resolution is too low to run STK." @@ -3673,7 +3674,7 @@ msgstr "Истекло время ожидания соединения с се #: src/modes/capture_the_flag.cpp:191 #, c-format msgid "%s has the red flag!" -msgstr "%s захватил(а) красный флаг!" +msgstr "%s взял(а) красный флаг!" #. I18N: Show when the red flag is returned to its base in CTF #: src/modes/capture_the_flag.cpp:198 @@ -3684,7 +3685,7 @@ msgstr "Красный флаг был возвращён!" #: src/modes/capture_the_flag.cpp:209 #, c-format msgid "%s has the blue flag!" -msgstr "%s захватил(а) синий флаг!" +msgstr "%s взял(а) синий флаг!" #. I18N: Show when the blue flag is returned to its base in CTF #: src/modes/capture_the_flag.cpp:216 @@ -3723,15 +3724,15 @@ msgstr "Круг %i" #, c-format msgctxt "fastest_lap" msgid "%s by %s" -msgstr "лучший круг: %s, %s" +msgstr " %s от %s" #: src/modes/linear_world.cpp:555 msgid "New fastest lap" -msgstr "Новый рекорд круга" +msgstr "Новый лучший круг" #: src/modes/linear_world.cpp:1097 msgid "WRONG WAY!" -msgstr "В ОБРАТНУЮ СТОРОНУ!" +msgstr "НЕВЕРНОЕ НАПРАВЛЕНИЕ!" #: src/modes/soccer_world.cpp:533 src/modes/soccer_world.cpp:660 #, c-format @@ -3809,7 +3810,7 @@ msgstr "Сложность: %s" #: src/network/protocols/client_lobby.cpp:743 #, c-format msgid "Max players: %d" -msgstr "Максимальное число игроков: %d" +msgstr "Максимум игроков: %d" #. I18N: In server info dialog #: src/network/protocols/client_lobby.cpp:756 @@ -3984,7 +3985,7 @@ msgstr "Гонка на время (Гран-при)" #: src/states_screens/online/create_server_screen.cpp:237 #: src/states_screens/track_info_screen.cpp:252 msgid "Free-For-All" -msgstr "Свободный заезд" +msgstr "Битва против всех" #. I18N: Game mode #. I18N: In the create server screen for battle server @@ -4050,7 +4051,7 @@ msgstr "По умолчанию" #: src/race/grand_prix_data.cpp:641 src/states_screens/gp_info_screen.cpp:78 msgid "None" -msgstr "Ничего" +msgstr "Нет" #: src/race/grand_prix_data.cpp:645 src/states_screens/gp_info_screen.cpp:80 msgid "Random" @@ -4388,13 +4389,13 @@ msgstr "Матчей Захвата флага закончено" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:230 msgid "Free-for-All matches started" -msgstr "Матчей Свободного заезда начато" +msgstr "Матчей Битвы против всех начато" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:232 msgid "Free-for-All matches finished" -msgstr "Матчей Свободного заезда закончено" +msgstr "Матчей Битвы против всех закончено" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4563,7 +4564,7 @@ msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" "To add a keyboard config, you can use the button below, HOWEVER please note that most keyboards only support a limited amount of simultaneous keypresses and are thus inappropriate for multiplayer gameplay. (You can, however, connect multiple keyboards to this device. Remember that everyone still needs different keybindings in this case.)" -msgstr "Новые контроллеры автоматически появятся в списке после того, как вы подключите их к этому устройству.\n\nЧтобы добавить настройки клавиатуры, вы можете нажать на кнопку, находящуюся ниже. Но учтите, что большинство клавиатур поддерживают ограниченное количество одновременных нажатий клавиш и поэтому не подходят для многопользовательской игры. (Однако вы можете решить эту проблему подключением нескольких клавиатур к компьютеру. Но даже в этом случае нужно назначать различные сочетания клавиш для разных игроков.)" +msgstr "Новые контроллеры автоматически появятся в списке после того, как вы подключите их к этому устройству.\n\nЧтобы добавить настройки клавиатуры, вы можете нажать на кнопку, находящуюся ниже. Но учтите, что большинство клавиатур поддерживают ограниченное число одновременных нажатий клавиш и поэтому не подходят для многопользовательской игры. (Однако вы можете решить эту проблему подключением нескольких клавиатур к компьютеру. Но даже в этом случае нужно назначать различные сочетания клавиш для разных игроков.)" #. I18N: In the 'add new input device' dialog #: src/states_screens/dialogs/add_device_dialog.cpp:87 @@ -4663,19 +4664,19 @@ msgid_plural "Confirm resolution within %i seconds" msgstr[0] "Подтвердите сохранение разрешения в течение %i секунды" msgstr[1] "Подтвердите сохранение разрешения в течение %i секунд" msgstr[2] "Подтвердите сохранение разрешения в течение %i секунд" -msgstr[3] "Подтвердите сохранение разрешения в течение %i секунды" +msgstr[3] "Подтвердите сохранение разрешения в течение %i секунд" #: src/states_screens/dialogs/confirm_resolution_dialog.cpp:93 msgid "" "Resolutions smaller than 1024x768 or 1280x720 are unsupported. Some parts of" " the UI may not work correctly." -msgstr "Разрешения меньше 1024×768 или 1280×720 не поддерживаются. Некоторые части интерфейса могут работать некорректно." +msgstr "Разрешения меньше 1024×768 или 1280×720 не поддерживаются. Некоторые части интерфейса могут сломаться." #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 #: src/states_screens/options/options_screen_ui.cpp:166 msgid "Drone chase" -msgstr "Следование за дроном" +msgstr "Погоня за дроном" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings @@ -4756,7 +4757,7 @@ msgstr "Введите адрес сервера, по желанию допиш #: src/states_screens/dialogs/enter_address_dialog.cpp:124 #, c-format msgid "Invalid server address: %s." -msgstr "Недействительный адрес сервера: %s." +msgstr "Неверный адрес сервера: %s." #: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 #: src/states_screens/ghost_replay_selection.cpp:155 @@ -4859,7 +4860,7 @@ msgstr "(Пусто)" #. I18N: In kart color choosing dialog #: src/states_screens/dialogs/kart_color_slider_dialog.cpp:47 msgid "Use original color" -msgstr "Использовать оригинальный цвет" +msgstr "Использовать исходный цвет" #. I18N: In kart color choosing dialog #: src/states_screens/dialogs/kart_color_slider_dialog.cpp:49 @@ -4926,7 +4927,7 @@ msgstr "Получение информации о рейтинге %s" #: src/states_screens/dialogs/network_player_dialog.cpp:194 #, c-format msgid "Tell server administrator about this player (%s):" -msgstr "Скажите администратору об этом игроке (%s):" +msgstr "Скажите администратору сервера об этом игроке (%s):" #. I18N: In press a key dialog, tell user to press a key to bind configuration #: src/states_screens/dialogs/press_a_key_dialog.cpp:43 @@ -5148,7 +5149,7 @@ msgstr "Обработка" #: src/states_screens/dialogs/vote_dialog.cpp:169 msgid "Fetching last vote" -msgstr "Получение последнего голосования" +msgstr "Получение последнего голоса" #: src/states_screens/dialogs/vote_dialog.cpp:188 msgid "You can adapt your previous rating by clicking the stars beneath." @@ -5184,7 +5185,7 @@ msgstr "Вы действительно хотите удалить «%s»?" #: src/states_screens/edit_gp_screen.cpp:134 #: src/states_screens/edit_gp_screen.cpp:382 msgid "Do you want to save your changes?" -msgstr "Хотите сохранить изменения?" +msgstr "Хотите сохранить ваши изменения?" #: src/states_screens/edit_gp_screen.cpp:152 msgid "Laps" @@ -5229,7 +5230,7 @@ msgstr "Вы закончили сложное испытание! Получе #, c-format msgid "" "You completed the SuperTux challenge! Points earned on this level: %i/%i" -msgstr "Вы закончили SuperTux-испытание! Полученные очки на данном уровне: %i/%i" +msgstr "Вы закончили испытание SuperTux! Полученные очки на этом уровне: %i/%i" #: src/states_screens/feature_unlocked.cpp:315 #, c-format @@ -5544,7 +5545,7 @@ msgstr "Адрес новой почты должен быть в предела #: src/states_screens/online/online_profile_settings.cpp:93 msgid "New Email is invalid!" -msgstr "Новая почта является недопустимой!" +msgstr "Новая эл. почта является неверной!" #: src/states_screens/online/online_profile_settings.cpp:118 msgid "E-mail changed!" @@ -5575,7 +5576,7 @@ msgstr "Выйти из игры" #: src/states_screens/online/register_screen.cpp:289 #, c-format msgid "Could not create player '%s'." -msgstr "Невозможно создать игрока «%s»." +msgstr "Не удалось создать игрока «%s»." #: src/states_screens/online/register_screen.cpp:306 msgid "User name cannot be empty." @@ -5652,12 +5653,12 @@ msgstr "Неизвестно" #. I18N: Message shown to user if no IPv4 detected by STK #: src/states_screens/online/server_selection.cpp:363 msgid "No IPv4 detected, you may not be able to join any servers." -msgstr "Не удалось распознать IPv4, скорее всего вы не сможете подключаться к серверам." +msgstr "Не удалось распознать IPv4, скорее всего, вы не сможете подключаться к серверам по этому протоколу." #. I18N: Message shown to user if no IPv6 detected by STK #: src/states_screens/online/server_selection.cpp:365 msgid "No IPv6 detected, you may not be able to join any servers." -msgstr "Не удалось распознать IPv6, скорее всего вы не сможете подключаться к серверам." +msgstr "Не удалось распознать IPv6, скорее всего, вы не сможете подключаться к серверам по этому протоколу." #: src/states_screens/online/server_selection.cpp:504 msgid "No server is available." @@ -5684,13 +5685,13 @@ msgstr "Если большинство игроков выберет одни #: src/states_screens/online/tracks_screen.cpp:522 #: src/states_screens/track_info_screen.cpp:303 msgid "Random item location" -msgstr "Случайное расположение предметов" +msgstr "Случайное размещение усилителей" #. I18N: In track screen #: src/states_screens/online/tracks_screen.cpp:504 #: src/states_screens/track_info_screen.cpp:455 msgid "Number of goals to win" -msgstr "Количество голов для победы" +msgstr "Число голов для победы" #. I18N: In the track info screen #: src/states_screens/online/tracks_screen.cpp:552 @@ -6378,7 +6379,7 @@ msgstr "Собирайте голубые коробки и используйт msgid "" "Press <%s> to look behind.\n" "Fire the weapon with <%s> while pressing <%s> to fire behind!" -msgstr "Нажмите «%s», чтобы обернуться.\nНажмите кнопку огня «%s» с удерживанием «%s» для стрельбы назад!" +msgstr "Нажмите «%s», чтобы обернуться.\nНажмите кнопку огня «%s» при зажатии «%s» для стрельбы назад!" #: ../stk-assets/tracks/tutorial/scripting.as:88 msgid "" diff --git a/data/po/rue.po b/data/po/rue.po index e0f03cf06fc..111309b0739 100644 --- a/data/po/rue.po +++ b/data/po/rue.po @@ -6,14 +6,14 @@ # Гондрош Руснак, 2022 # Ондрош Руснак, 2022 # Ондрош Руснак, 2022 -# Ондрош Руснак, 2022-2023 +# Ондрош Руснак, 2022-2024 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Ондрош Руснак, 2022-2023\n" +"Last-Translator: Ондрош Руснак, 2022-2024\n" "Language-Team: Rusyn (http://app.transifex.com/supertuxkart/supertuxkart/language/rue/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -912,7 +912,7 @@ msgstr "Інфо хосновача" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Удалити цімбору" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -922,17 +922,17 @@ msgstr "Придати цімбору" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Прияти закликаня" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Не прияти закликаня" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Увідіти профіл" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1120,7 +1120,7 @@ msgstr "Вшыткі причастні" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Лишити" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -2000,7 +2000,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Можете бавити без учиненя онлайн акаунта, просто уберавучи офлайн акаунт. Айбо не будете скапчовати ся з цімборами, голосовати за придаткы тай дале. Будьте добрі, почитайте наш устав на https://privacy.superuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -6410,7 +6410,7 @@ msgstr "Вы тепирь прилажені од перебігови. Сере #. description in Google Play #: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 msgid "A 3D open-source kart racing game" -msgstr "3х-мірна возикова перебігова бавка" +msgstr "3х-мірна возикова перебігова бавка из одкрытым зачаточным кодом" #. I18N: Keywords in desktop entry, translators please keep it separated with #. semicolons @@ -6424,7 +6424,7 @@ msgid "" "variety of characters, tracks, and modes to play. Our aim is to create a " "game that is more fun than realistic, and provide an enjoyable experience " "for all ages." -msgstr "Моторвозикы. Нітро. Екшен! SuperTuxKart се 3ьохмірна аркадна гонитва из одкрытым зачаточным кодом рузными особами, автомапами и режімув для бавкы. Наша цїль учинити бавку яка май весела, чим реалістічна и натїшит вшыткі рокы." +msgstr "Моторвозикы. Нітро. Екшен! SuperTuxKart се 3ьохмірна аркадна гонитва яка має одкрытый зачаточный код, тай рузні особы, автомапы и режімы для бавкы. Наша цїль учинити бавку яка май весела, чим реалістічна и натїшит бавлячув усьых рокув." #: supertuxkart.appdata.xml:11 msgid "" diff --git a/data/po/sl.po b/data/po/sl.po index 07cbeda0f03..bc4a4393cb1 100644 --- a/data/po/sl.po +++ b/data/po/sl.po @@ -4,6 +4,7 @@ # # Translators: # Andrej Znidarsic , 2015-2016,2021 +# Gorzy Gorup , 2023 # Gorzy Gorup , 2018,2023 # Luka116, 2023 # Sasa Batistic , 2018 @@ -15,7 +16,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Gorzy Gorup , 2018,2023\n" +"Last-Translator: Gorzy Gorup , 2023\n" "Language-Team: Slovenian (http://app.transifex.com/supertuxkart/supertuxkart/language/sl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -2599,7 +2600,7 @@ msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml msgid "Pepper" -msgstr "Pepper" +msgstr "Paprika" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml msgid "Sara" diff --git a/data/po/sr.po b/data/po/sr.po index 867509aa8cd..7c9ab802a74 100644 --- a/data/po/sr.po +++ b/data/po/sr.po @@ -10,7 +10,7 @@ # SUABNINISAN alalalala , 2020 # SUABNINISAN alalalala , 2020 # Мирослав Николић , 2011 -# Саша Петровић , 2012-2014,2016,2018,2020-2023 +# Саша Петровић , 2012-2014,2016,2018,2020-2024 # Саша Петровић , 2015-2016 # Саша Петровић , 2016 # Саша Петровић , 2016-2017 @@ -22,7 +22,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Саша Петровић , 2012-2014,2016,2018,2020-2023\n" +"Last-Translator: Саша Петровић , 2012-2014,2016,2018,2020-2024\n" "Language-Team: Serbian (http://app.transifex.com/supertuxkart/supertuxkart/language/sr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -223,7 +223,7 @@ msgstr "Чигра" #. I18N: Control type #: src/states_screens/dialogs/race_paused_dialog.cpp:544 msgid "Steering wheel" -msgstr "Управљач" +msgstr "Точак управљача" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui @@ -921,7 +921,7 @@ msgstr "Подаци о кориснику" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Уклони пријатеља" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -931,17 +931,17 @@ msgstr "Додај пријатеља" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Прихвати позив" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Одбаци позив" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Прегледај податке о налогу" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1129,7 +1129,7 @@ msgstr "Заслуге" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Прескочи" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1511,7 +1511,7 @@ msgstr "Приказ снимка са духом. Тркајте се прот #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "" +msgstr "Трка кругова; завршите што више кругова можете у датом времену." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -2009,7 +2009,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Можете играти без стварања налога на мрежи одабиром налога ван мреже. Али, тада се не можете повезати са пријатељима, гласати за додатке итд. Молимо вас да прочитајте нашу објаву о заштити личности на http://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2522,7 +2522,7 @@ msgstr "Кошаркашке лопте се могу уништити прец msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "" +msgstr "Покушај да избегнеш сударе у леђа осталих колица јер ће те то успорити." #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." @@ -6450,7 +6450,7 @@ msgid "" " while avoiding other karts as they may overtake you, but don't eat the " "bananas! Watch for bowling balls, plungers, bubble gum, and cakes thrown by " "your opponents." -msgstr "Имамо неколико стаза са разним темама за играчко уживање, од вожње под водом, сеоских предела, прашума, чак и свемира! Покушајте да избегавате остала колица јер Вас могу претећи, али не једите банане! Пазите се кугли, гума за отчепљивање цеви, жвакаћих гума, и колача које бацају Ваши противници!" +msgstr "Имамо неколико стаза са разним темама за играчко уживање, од вожње под водом, сеоских предела, прашума, чак и свемира! Покушајте да избегавате остала колица јер Вас могу претећи, али не једите банане! Пазите се кугли, гума за отчепљивање цеви, жвакаћих гума, и колача које бацају Ваши противници." #: supertuxkart.appdata.xml:14 msgid "" diff --git a/data/po/sv.po b/data/po/sv.po index c262995297f..fcf334d5cda 100644 --- a/data/po/sv.po +++ b/data/po/sv.po @@ -14,7 +14,7 @@ # Kjell Rilbe , 2016 # Kristoffer Grundström , 2016 # Kristoffer Grundström , 2016,2022 -# Luna Jernberg , 2020 +# Luna Jernberg , 2020 # Marcus Larborg, 2017 # Marcus Larborg, 2017 # Mikael Elm , 2021 @@ -926,7 +926,7 @@ msgstr "Användarinformation" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Ta bort vän" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -936,17 +936,17 @@ msgstr "Lägg till vän" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Acceptera inbjudan" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Avvisa inbjudan" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Visa profil" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1134,7 +1134,7 @@ msgstr "Tack till" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Hoppa över" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -2014,7 +2014,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Du kan spela utan att skapa ett nätkonto genom att välja ett frånkopplat konto. Men då kan du inte ansluta till vänner, rösta på tillägg o.s.v. Läs vår integritetspolicy på https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 diff --git a/data/po/th.po b/data/po/th.po index 1eb16f1d2cf..e93d7f355cf 100644 --- a/data/po/th.po +++ b/data/po/th.po @@ -5,7 +5,7 @@ # Translators: # Annop Chawwalitsitthikun , 2019 # Annop Chawwalitsitthikun , 2019 -# Annop Chawwalitsitthikun , 2019-2022 +# Annop Chawwalitsitthikun , 2019-2022,2024 # Benau, 2020 # Benau, 2020 msgid "" @@ -14,7 +14,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Benau, 2020\n" +"Last-Translator: Annop Chawwalitsitthikun , 2019-2022,2024\n" "Language-Team: Thai (http://app.transifex.com/supertuxkart/supertuxkart/language/th/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -913,7 +913,7 @@ msgstr "ข้อมูลผู้ใช้" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "ลบเพื่อน" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -923,17 +923,17 @@ msgstr "เพิ่มเพื่อน" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "ยอมรับคำเชิญ" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "ปฏิเสธคำเชิญ" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "ดูโปรไฟล์" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1121,7 +1121,7 @@ msgstr "เครดิต" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "ข้าม" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1503,7 +1503,7 @@ msgstr "โกสรีเพลย์: แข่งกับกับรีเ #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "" +msgstr "รอบทดลอง:เสร็จสิ้นรอบให้ได้มากที่สุดเท่าที่จะเป็นไปได้ในระยะเวลาที่กำหนด" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1731,7 +1731,7 @@ msgstr "การเลือกคะแนนสูง" #. time. #: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" -msgstr "" +msgstr "รอบทดลอง" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen @@ -2001,7 +2001,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "คุณสามารถเล่นได้โดยไม่ต้องสร้างบัญชีออนไลน์โดยเลือกบัญชีออฟไลน์ แม้ว่าคุณจะไม่สามารถเชื่อมต่อกับเพื่อนได้ โหวตให้ส่วนเสริม ฯลฯ โปรดอ่านคำชี้แจงสิทธิ์ส่วนบุคคลของเราที่ https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2514,7 +2514,7 @@ msgstr "บาสเก็ตบอลสามารถถูกทำลาย msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "" +msgstr "พยายามหลีกเลี่ยงการชนท้ายรถแข่งคันอื่น เพราะจะทำให้คุณช้าลง" #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." @@ -2558,7 +2558,7 @@ msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml msgid "Godette" -msgstr "" +msgstr "โกเด็ตต์" #. I18N: ../stk-assets/karts/emule/kart.xml msgid "Emule" @@ -2671,7 +2671,7 @@ msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml msgid "Hole Drop" -msgstr "" +msgstr "หลุมหล่น" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" @@ -2726,7 +2726,7 @@ msgstr "Old Mine" #. I18N: ../stk-assets/tracks/oasis/track.xml msgid "Oasis" -msgstr "" +msgstr "โอเอซิส" #. I18N: ../stk-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" @@ -4811,7 +4811,7 @@ msgstr "จำนวนรถแข่ง %d" #: src/states_screens/dialogs/high_score_info_dialog.cpp:137 #, c-format msgid "Time target: %s" -msgstr "" +msgstr "เวลาเป้าหมาย: %s" #: src/states_screens/dialogs/high_score_info_dialog.cpp:139 #, c-format @@ -4842,7 +4842,7 @@ msgstr "เลือกสีจากแถบเลื่อน" #: src/states_screens/dialogs/message_dialog.cpp:145 msgid "Don't show again" -msgstr "" +msgstr "อย่าแสดงอีก" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:50 @@ -5551,7 +5551,7 @@ msgstr "ต้องระบุชื่อผู้ใช้" #: src/states_screens/online/register_screen.cpp:362 msgid "Online username and password must not be the same!" -msgstr "" +msgstr "ชื่อผู้ใช้และรหัสผ่านออนไลน์จะต้องไม่เหมือนกัน!" #: src/states_screens/online/register_screen.cpp:366 msgid "Emails don't match!" @@ -5561,7 +5561,7 @@ msgstr "อีเมลไม่ตรงกัน!" msgid "" "Online username can only contain alphanumeric (ASCII) characters, periods, " "dashes and underscores!" -msgstr "" +msgstr "ชื่อผู้ใช้ออนไลน์ต้องประกอบด้วยอักขระตัวอักษรและตัวเลข (ASCII) จุด ขีดกลาง และขีดล่างเท่านั้น!" #: src/states_screens/online/register_screen.cpp:374 msgid "Online username has to be between 3 and 30 characters long!" @@ -6243,7 +6243,7 @@ msgstr "แข่งกับโกสต์และพยายามเอา #: src/states_screens/race_setup_screen.cpp:143 msgid "Complete as many laps as possible in a given amount of time." -msgstr "" +msgstr "เสร็จสิ้นรอบให้ได้มากที่สุดเท่าที่จะเป็นไปได้ในระยะเวลาที่กำหนด" #. I18N: In soccer setup screen #: src/states_screens/soccer_setup_screen.cpp:120 diff --git a/data/po/tr.po b/data/po/tr.po index 87f9e1ed837..96c5c07c06d 100644 --- a/data/po/tr.po +++ b/data/po/tr.po @@ -3,20 +3,21 @@ # This file is distributed under the same license as the supertuxkart package. # # Translators: +# A. Cem Hanoğlu , 2024 # FIRST AUTHOR , 2010 # Rover, 2022 # Rover, 2022 -# Serdar Sağlam , 2019-2022 +# Serdar Sağlam , 2019-2023 # U. Ozan Basar , 2015 # Volkan Gezer , 2015 -# yakup , 2015-2017 +# 9d4282795e87ad099e39d98812f1a822_ade2f01 , 2015-2017 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Volkan Gezer , 2015\n" +"Last-Translator: A. Cem Hanoğlu , 2024\n" "Language-Team: Turkish (http://app.transifex.com/supertuxkart/supertuxkart/language/tr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -34,7 +35,7 @@ msgstr "Oyun verisi ayıklama hatası" #. I18N: In Android UI, po_extract_error_msg msgid "Check remaining device space or reinstall SuperTuxKart." -msgstr "Cihazda kalan alanını kontrol edin veya SuperTuxKart'ı yeniden kurun." +msgstr "Cihazda kalan alanı kontrol edin veya SuperTuxKart'ı yeniden kurun." #. I18N: In Android UI, po_quit #. I18N: ./data/gui/screens/main_menu.stkgui @@ -52,7 +53,7 @@ msgstr "Her bölümü en az bir kez oyna." #. I18N: ./data/achievements.xml msgid "Strike!" -msgstr "Vurgun!" +msgstr "Strike!" #. I18N: ./data/achievements.xml msgid "Hit 10 karts with a bowling-ball." @@ -64,7 +65,7 @@ msgstr "Baş Düşman" #. I18N: ./data/achievements.xml msgid "Hit the same kart at least 5 times in one race." -msgstr "Aynı araca bir yarışta en az 5 kez vurun." +msgstr "Aynı araca bir yarışta en az 5 kez vur." #. I18N: ./data/achievements.xml msgid "Marathoner" @@ -72,7 +73,7 @@ msgstr "Maratoncu" #. I18N: ./data/achievements.xml msgid "Finish a race with at least twice the track's default lap number." -msgstr "Bir yarışı pistin varsayılan tur sayısının en az iki katı ile bitirin." +msgstr "Bir yarışı pistin varsayılan tur sayısının en az iki katı ile bitir." #. I18N: ./data/achievements.xml msgid "Skid-row" @@ -80,7 +81,7 @@ msgstr "Patinajcı" #. I18N: ./data/achievements.xml msgid "Skid 5 times in a single lap." -msgstr "Tek bir turda 5 kez kaydırın." +msgstr "Tek bir turda 5 kez kaydır." #. I18N: ./data/achievements.xml msgid "Gold driver" @@ -90,7 +91,7 @@ msgstr "Altın Sürücü" msgid "" "Win against at least 3 AIs in normal race, time-trial, and follow the " "leader." -msgstr "Normal yarışta en az 3 Yapay zekaya karşı kazanın, deneme yapın ve lideri takip edin." +msgstr "Normal yarış, zamana karşı ve lideri takip et modlarında en az 3 yapay zekaya karşı kazan. " #. I18N: ./data/achievements.xml msgid "Powerup Love" @@ -98,7 +99,7 @@ msgstr "Güçartışı Sever" #. I18N: ./data/achievements.xml msgid "Use 10 or more powerups in a race." -msgstr "Bir yarışta 10 veya daha fazla güç artışları kullanın." +msgstr "Bir yarışta 10 veya daha fazla güç artışı kullan." #. I18N: ./data/achievements.xml msgid "Unstoppable" @@ -120,7 +121,7 @@ msgstr "Bir yarışta en az 5 muz topla." #. I18N: ./data/achievements.xml msgid "It's secret" -msgstr "O gizli" +msgstr "Sır" #. I18N: ./data/achievements.xml msgid "Really ... a secret." @@ -128,13 +129,13 @@ msgstr "Gerçekten ... bir sır." #. I18N: ./data/achievements.xml msgid "Mosquito Hunter" -msgstr "Sivri Sinek Avcısı" +msgstr "Sivrisinek Avcısı" #. I18N: ./data/achievements.xml msgid "" "Take your opponents for mosquitos! With the swatter, squash them at least 5 " "times in a race." -msgstr "Rakiplerini sivrisineklere götür! Renk örneği ile, yarışta en az 5 kez ezin." +msgstr "Rakiplerini sivrisineklermiş gibi gör! Onları bir yarışta sinek raketiyle en az 5 kere ez." #. I18N: ./data/achievements.xml msgid "Beyond Luck" @@ -144,7 +145,7 @@ msgstr "Şansın Ötesinde" msgid "" "Win 10 single races in a row in Expert or SuperTux against at least 5 AIs. " "Beware, restarting a race counts as a loss." -msgstr "En az 5 Yapay zekaya karşı Uzman veya SuperTux'ta arka arkaya 10 yarış kazanın. Dikkat edin, bir yarışı yeniden başlatmak bir kayıp olarak sayılır." +msgstr "Expert ya da SuperTux zorluklarında en az 5 yapay zekaya karşı art arda 10 kere tek yarış kazan. Dikkat et, bir yarışı yeniden başlatırsan kaybetmiş sayılırsın. " #. I18N: ./data/grandprix/1_penguinplayground.grandprix msgid "Penguin Playground" @@ -292,7 +293,7 @@ msgstr "Ters çevrilmiş düğmeler" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Buttons scale" -msgstr "Düğmeler ölçeği" +msgstr "Düğme ölçeği" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -667,7 +668,7 @@ msgstr "Yarışı Yeniden Başlat" #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button msgid "Give Up Race" -msgstr "Yarışı Bırak" +msgstr "Yarıştan Çekil" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button @@ -736,7 +737,7 @@ msgstr "Kullanıcı adı" #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog msgid "Email" -msgstr "Eposta" +msgstr "E-posta" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog @@ -915,7 +916,7 @@ msgstr "Kullanıcı Bilgisi" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Arkadaşı Kaldır" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -925,17 +926,17 @@ msgstr "Arkadaş Ekle" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Daveti Kabul Et" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Daveti Reddet" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Profili Görüntüle" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1123,7 +1124,7 @@ msgstr "Hazırlayanlar" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Atla" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1505,7 +1506,7 @@ msgstr "Hayaletin: Zamana karşı veya yumurta avı kipinde hayaletine karşı y #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "" +msgstr "Tur Denemesi: Belirli bir süre içinde mümkün olduğunca çok tur tamamlayın." #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -2003,7 +2004,7 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Bir çevrimdışı hesap seçerek çevrimiçi bir hesap oluşturmadan oynayabilirsiniz. Ancak o zaman arkadaşlara bağlanamaz, eklentiler için oy kullanamazsınız vb. Lütfen https://privacy.supertuxkart.net adresindeki gizlilik bildirimimizi okuyun." #. I18N: ./data/gui/screens/online/server_selection.stkgui #: src/states_screens/online/server_selection.cpp:580 @@ -2516,7 +2517,7 @@ msgstr "Basket topları bir bowling topu, kek veya dalgıç ile hassas geri atı msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "" +msgstr "Sizi yavaşlatacağı için diğer araçlara arkadan çarpmaktan kaçının." #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." @@ -2560,7 +2561,7 @@ msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml msgid "Godette" -msgstr "" +msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml msgid "Emule" @@ -2673,7 +2674,7 @@ msgstr "Çiftlik" #. I18N: ../stk-assets/tracks/hole_drop/track.xml msgid "Hole Drop" -msgstr "" +msgstr "Hole Drop" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" @@ -2728,7 +2729,7 @@ msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml msgid "Oasis" -msgstr "" +msgstr "Vaha" #. I18N: ../stk-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" diff --git a/data/po/tt.po b/data/po/tt.po index 2f60c847c3a..231e42f7a31 100644 --- a/data/po/tt.po +++ b/data/po/tt.po @@ -4,7 +4,7 @@ # # Translators: # FIRST AUTHOR , 2012 -# Timur Seber , 2021 +# Timur Seber , 2021,2023-2024 # Булат Ибраһим , 2015-2017,2021 msgid "" msgstr "" @@ -12,7 +12,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Timur Seber , 2021\n" +"Last-Translator: Timur Seber , 2021,2023-2024\n" "Language-Team: Tatar (http://app.transifex.com/supertuxkart/supertuxkart/language/tt/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -219,7 +219,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Auto acceleration" -msgstr "" +msgstr "Автоматик тизләнеш" #. I18N: ./data/gui/dialogs/android/init_android.stkgui msgid "You can change it later in touch device settings." @@ -298,7 +298,7 @@ msgstr "Өстәмә" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Deadzone" -msgstr "" +msgstr "Үле зона" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -690,7 +690,7 @@ msgstr "Ярдәм" #. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui #. I18N: In player rankings dialog msgid "Top 10 players" -msgstr "" +msgstr "Иң яхшы 10 уенчы" #. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui msgid "Refresh" @@ -747,7 +747,7 @@ msgstr "Мин шартлар белән риза, һәм миңа 13 яшьтә #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: In the server configuration screen msgid "Server Configuration" -msgstr "" +msgstr "Серверне көйләү" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: In the server configuration screen @@ -870,12 +870,12 @@ msgstr "Серсүз" #. I18N: In the server info dialog #: src/states_screens/dialogs/server_info_dialog.cpp:291 msgid "Bookmark this server" -msgstr "" +msgstr "Бу серверны кыстыргычларга кую" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "Add player" -msgstr "" +msgstr "Уенчы өстәү" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network @@ -896,7 +896,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "Clear players" -msgstr "" +msgstr "Уенчыларны чистарту" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network @@ -921,17 +921,17 @@ msgstr "Дусны өстәргә" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Чакыруны кабул итү" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Чакырудан баш тарту" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Профильне карау" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -1119,7 +1119,7 @@ msgstr "Ясаучылар" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Калдырып тору" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1323,7 +1323,7 @@ msgstr "Уен төре" #. I18N: ./data/gui/screens/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" -msgstr "" +msgstr "Ташламалар" #. I18N: ./data/gui/screens/help1.stkgui #. I18N: Tab in help menu @@ -1863,7 +1863,7 @@ msgstr "Лобби" #. I18N: In networking lobby to configuration server settings #: src/states_screens/online/networking_lobby.cpp:200 msgid "Configuration" -msgstr "" +msgstr "Көйләү" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby @@ -1889,7 +1889,7 @@ msgstr "" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button msgid "Enter server address" -msgstr "" +msgstr "Сервер адресын кертү" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button @@ -1954,7 +1954,7 @@ msgstr "Үзгәртергә" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: In the online account settings screen msgid "E-mail:" -msgstr "" +msgstr "Эл. почта:" #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog @@ -1991,7 +1991,7 @@ msgstr "Челтәр исеме" #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" -msgstr "" +msgstr "Серсүзне алыштыру" #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog @@ -2014,7 +2014,7 @@ msgstr "" #. I18N: ./data/gui/screens/online/server_selection.stkgui #. I18N: In the server selection screen msgid "Use IPv6 connection" -msgstr "" +msgstr "IPv6 тоташуын куллану" #. I18N: ./data/gui/screens/online/user_search.stkgui msgid "User search" @@ -2145,7 +2145,7 @@ msgstr "Идарә итү" #. I18N: ./data/gui/screens/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" -msgstr "" +msgstr "Тел" #. I18N: ./data/gui/screens/options_audio.stkgui #. I18N: In the audio options screen @@ -2267,7 +2267,7 @@ msgstr "Тема" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Minimap" -msgstr "" +msgstr "Кечкенә карта" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings @@ -2277,17 +2277,17 @@ msgstr "" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" -msgstr "" +msgstr "Шрифт үлчәме" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" -msgstr "" +msgstr "Камера" #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." -msgstr "" +msgstr "Үзгә..." #. I18N: ./data/gui/screens/options_ui.stkgui #. I18N: In the ui settings @@ -2427,7 +2427,7 @@ msgstr "Бетерергә" #. I18N: ./data/gui/screens/user_screen_tab.stkgui #. I18N: In the user screen msgid "Kart color" -msgstr "" +msgstr "Картинг төсе" #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." @@ -2568,7 +2568,7 @@ msgstr "Гаврош" #. I18N: ../stk-assets/karts/gnu/kart.xml msgid "Gnu" -msgstr "" +msgstr "Гну" #. I18N: ../stk-assets/karts/hexley/kart.xml msgid "Hexley" @@ -2576,7 +2576,7 @@ msgstr "Хекслей" #. I18N: ../stk-assets/karts/kiki/kart.xml msgid "Kiki" -msgstr "" +msgstr "Кики" #. I18N: ../stk-assets/karts/konqi/kart.xml msgid "Konqi" @@ -2596,11 +2596,11 @@ msgstr "Пуфи" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml msgid "Pepper" -msgstr "" +msgstr "Борыч" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml msgid "Sara" -msgstr "" +msgstr "Сара" #. I18N: ../stk-assets/karts/suzanne/kart.xml msgid "Suzanne" @@ -2641,7 +2641,7 @@ msgstr "Сугыш утравы" #. I18N: ../stk-assets/tracks/black_forest/track.xml msgid "Black Forest" -msgstr "" +msgstr "Кара урман" #. I18N: ../stk-assets/tracks/cave/track.xml msgid "Cave X" @@ -2724,7 +2724,7 @@ msgstr "Минигольф" #. I18N: ../stk-assets/tracks/oasis/track.xml msgid "Oasis" -msgstr "" +msgstr "Оазис" #. I18N: ../stk-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" @@ -2732,7 +2732,7 @@ msgstr "Оливерның математика бүлмәсе" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" -msgstr "" +msgstr "Кабак паркы" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" @@ -2744,7 +2744,7 @@ msgstr "Шуучан Комнар" #. I18N: ../stk-assets/tracks/scotland/track.xml msgid "Nessie's Pond" -msgstr "" +msgstr "Лох-Несс албастысы күле" #. I18N: ../stk-assets/tracks/snowmountain/track.xml msgid "Northern Resort" @@ -2891,12 +2891,12 @@ msgstr "Сезнең көйләүләрегез искергәнгә күрә б #: src/graphics/irr_driver.cpp:730 msgid "Video recording started." -msgstr "" +msgstr "Видеоны яздыру башланды." #: src/graphics/irr_driver.cpp:737 #, c-format msgid "Video saved in \"%s\"." -msgstr "" +msgstr "Видео монда \"%s\" сакланылды." #: src/graphics/irr_driver.cpp:741 msgid "Encoding progress:" @@ -2906,13 +2906,13 @@ msgstr "" #: src/graphics/irr_driver.cpp:1961 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" -msgstr "" +msgstr "Кадр/с: %d/%d/%d - %d КТр, Пинг: %d мс " #. I18N: Tip shown in gui for giving player hints #: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 #, c-format msgid "Tip: %s" -msgstr "" +msgstr "Киңәш: %s" #: src/guiengine/engine.cpp:1496 msgid "Loading" @@ -2920,15 +2920,15 @@ msgstr "Йөкләнү" #: src/guiengine/widgets/kart_stats_widget.cpp:104 msgid "Mass" -msgstr "" +msgstr "Масса" #: src/guiengine/widgets/kart_stats_widget.cpp:110 msgid "Maximum speed" -msgstr "" +msgstr "Максималь тизлек" #: src/guiengine/widgets/kart_stats_widget.cpp:117 msgid "Acceleration" -msgstr "" +msgstr "Тизләнеш" #: src/guiengine/widgets/kart_stats_widget.cpp:123 msgid "Nitro efficiency" @@ -3453,7 +3453,7 @@ msgstr "Сезнең көйләүләр файлы уенның бу верси #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:159 msgid "Guide" -msgstr "" +msgstr "Кулланма" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:161 @@ -3589,7 +3589,7 @@ msgstr "Wiimote-ны табып булмый" #: src/io/rich_presence.cpp:477 msgid "Getting ready to race" -msgstr "" +msgstr "Ярышка әзерләнү" #: src/karts/controller/local_player_controller.cpp:329 msgid "Penalty time!!" @@ -3597,7 +3597,7 @@ msgstr "Җаза вакыты!!" #: src/karts/controller/local_player_controller.cpp:332 msgid "Don't accelerate before 'Set!'" -msgstr "" +msgstr "'Игътибар' сүзенә кадәр кузгалмагыз!" #: src/karts/controller/spare_tire_ai.cpp:150 msgid "You can have at most 3 lives!" @@ -3624,7 +3624,7 @@ msgstr "" #: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 #, c-format msgid "%s left the game." -msgstr "" +msgstr "%s уеннан китте." #: src/main.cpp:2034 msgid "" @@ -3681,12 +3681,12 @@ msgstr "" #: src/modes/capture_the_flag.cpp:424 #, c-format msgid "%s captured the blue flag!" -msgstr "" +msgstr "%s зәңгәр байракны яулап алды!" #: src/modes/capture_the_flag.cpp:428 #, c-format msgid "%s captured the red flag!" -msgstr "" +msgstr "%s кызыл байракны яулап алды!" #: src/modes/easter_egg_hunt.cpp:222 #, c-format @@ -3770,7 +3770,7 @@ msgstr "Бот" #: src/network/protocols/client_lobby.cpp:641 #, c-format msgid "%s disconnected." -msgstr "" +msgstr "%s тоташмаган." #. I18N: Message shown in network lobby to tell user that #. player name is clickable @@ -3801,7 +3801,7 @@ msgstr "" #: src/states_screens/dialogs/server_info_dialog.cpp:101 #, c-format msgid "Game mode: %s" -msgstr "" +msgstr "Уен төре: %s" #. I18N: In the create server screen for soccer server #: src/network/protocols/client_lobby.cpp:769 @@ -3868,7 +3868,7 @@ msgstr "" #: src/network/protocols/client_lobby.cpp:1026 msgid "Failed to start the network game." -msgstr "" +msgstr "Челтәр уенын башлый алмады." #. I18N: Error message shown if live join or spectate failed in network #: src/network/protocols/client_lobby.cpp:1241 @@ -3945,7 +3945,7 @@ msgstr "" #: src/network/protocols/connect_to_server.cpp:380 #, c-format msgid "Cannot connect to server %s." -msgstr "" +msgstr "%s серверына тоташып булмый" #. I18N: Show the failed detect port server name #: src/network/protocols/connect_to_server.cpp:883 @@ -3976,7 +3976,7 @@ msgstr "" #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 #: src/states_screens/online/create_server_screen.cpp:239 msgid "Capture The Flag" -msgstr "" +msgstr "Байракны яулап алу" #: src/online/online_player_profile.cpp:455 #, c-format @@ -4150,7 +4150,7 @@ msgstr "Launchpad Contributions:\nTimur Seber, 2021\nБулат Ибраһим, #: src/states_screens/dialogs/achievement_progress_dialog.cpp:65 msgctxt "achievement_info" msgid "Subgoals" -msgstr "" +msgstr "Эчке максатлар" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:67 msgctxt "achievement_info" @@ -4219,13 +4219,13 @@ msgstr "" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:182 msgid "Novice races started" -msgstr "" +msgstr "Өйрәнчек ярышлары башланды" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:184 msgid "Novice races finished" -msgstr "" +msgstr "Өйрәнчек ярышлары тәмамланды" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4243,13 +4243,13 @@ msgstr "" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:190 msgid "Expert races started" -msgstr "" +msgstr "Эксперт узышлары башланды" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:192 msgid "Expert races finished" -msgstr "" +msgstr "Эксперт узышлары тәмамланды" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4267,13 +4267,13 @@ msgstr "" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:198 msgid "Normal races started" -msgstr "" +msgstr "Нормаль узышлар башланды" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:200 msgid "Normal races finished" -msgstr "" +msgstr "Нормаль узышлар тәмамланды" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4351,13 +4351,13 @@ msgstr "" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:226 msgid "Capture-the-Flag matches started" -msgstr "" +msgstr "\"Байракны яулап алу\" матчлары башланды" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:228 msgid "Capture-the-Flag matches finished" -msgstr "" +msgstr "\"Байракны яулап алу\" матчлары тәмамланды" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4376,7 +4376,7 @@ msgstr "" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:234 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:236 msgid "Powerups used" -msgstr "" +msgstr "Ташламалар кулланды" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4445,7 +4445,7 @@ msgstr "(1 әйләнә)" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:272 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:297 msgid "Races started" -msgstr "" +msgstr "Узышлар башланды" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4467,7 +4467,7 @@ msgstr "" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:274 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:299 msgid "Races finished" -msgstr "" +msgstr "Узышлар тәмамланды" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4682,7 +4682,7 @@ msgstr "" #: src/states_screens/dialogs/custom_video_settings.cpp:86 #: src/states_screens/options/options_screen_video.cpp:672 msgid "Very Low" -msgstr "" +msgstr "Бик түбән" #. I18N: Geometry level low : few details are displayed #. I18N: in the graphical options tooltip; @@ -4799,7 +4799,7 @@ msgstr "" #: src/states_screens/dialogs/high_score_info_dialog.cpp:112 #, c-format msgid "%s: %s" -msgstr "" +msgstr "%s: %s" #: src/states_screens/dialogs/high_score_info_dialog.cpp:125 #, c-format @@ -4831,7 +4831,7 @@ msgstr "(Буш)" #. I18N: In kart color choosing dialog #: src/states_screens/dialogs/kart_color_slider_dialog.cpp:47 msgid "Use original color" -msgstr "" +msgstr "Оригиналь төс куллану" #. I18N: In kart color choosing dialog #: src/states_screens/dialogs/kart_color_slider_dialog.cpp:49 @@ -4840,18 +4840,18 @@ msgstr "" #: src/states_screens/dialogs/message_dialog.cpp:145 msgid "Don't show again" -msgstr "" +msgstr "Кабат күрсәтмә" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:50 msgid "Player info" -msgstr "" +msgstr "Уенчы турында мәгълүмат" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:55 #, c-format msgid "Player name: %s" -msgstr "" +msgstr "Уенчы исеме: %s" #. I18N: In the network player dialog, show the player location with #. country name (based on IP geolocation) @@ -4868,7 +4868,7 @@ msgstr "" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:124 msgid "Change team" -msgstr "" +msgstr "Команданы үзгәртү" #. I18N: In the network player dialog #: src/states_screens/dialogs/network_player_dialog.cpp:139 @@ -4905,11 +4905,11 @@ msgstr "" msgid "" "Press any key...\n" "(Press ESC to cancel)" -msgstr "" +msgstr "Теләсә нинди төймәгә басыгыз...\n(Баш тарту өчен ESC басыгыз)" #: src/states_screens/dialogs/press_a_key_dialog.cpp:49 msgid "Press any key..." -msgstr "" +msgstr "Теләсә нинди төймәгә басыгыз..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 #: src/states_screens/online/networking_lobby.cpp:249 @@ -4919,7 +4919,7 @@ msgstr "" #: src/states_screens/dialogs/race_paused_dialog.cpp:132 msgid "Back to Battle" -msgstr "" +msgstr "Сугышка кире кайту" #: src/states_screens/dialogs/race_paused_dialog.cpp:135 msgid "Setup New Game" @@ -4927,11 +4927,11 @@ msgstr "Яңа уен урнаштыру" #: src/states_screens/dialogs/race_paused_dialog.cpp:137 msgid "Restart Battle" -msgstr "" +msgstr "Сугышны яңадан башлау" #: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Exit Battle" -msgstr "" +msgstr "Сугыштан чыгу" #: src/states_screens/dialogs/race_paused_dialog.cpp:146 #: src/states_screens/race_result_gui.cpp:350 @@ -5022,7 +5022,7 @@ msgstr "Ботлар саны: %i" #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 #: src/states_screens/online/create_server_screen.cpp:233 msgid "Battle mode" -msgstr "" +msgstr "Сугыш төре" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 @@ -5052,7 +5052,7 @@ msgstr "Урын" #. the user name on server #: src/states_screens/dialogs/server_info_dialog.cpp:132 msgid "Player" -msgstr "" +msgstr "Уенчы" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings @@ -5069,7 +5069,7 @@ msgstr "" #: src/states_screens/dialogs/server_info_dialog.cpp:281 #: src/states_screens/dialogs/server_info_dialog.cpp:296 msgid "Remove from bookmarks" -msgstr "" +msgstr "Кыстыргычлардан бетерү" #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:130 msgid "Input device already exists." @@ -5206,7 +5206,7 @@ msgstr "" #: src/states_screens/feature_unlocked.cpp:315 #, c-format msgid "You unlocked %s!" -msgstr "" +msgstr "Сез %s ачтыгыз!" #: src/states_screens/feature_unlocked.cpp:645 msgid "Challenge Completed" @@ -5282,7 +5282,7 @@ msgstr "Сез Гран-Прины тәмамладыгыз!" #: src/states_screens/high_score_selection.cpp:144 msgctxt "column_name" msgid "Number of karts" -msgstr "" +msgstr "Картлар саны" #: src/states_screens/high_score_selection.cpp:352 msgid "Are you sure you want to remove this high score entry?" @@ -5386,11 +5386,11 @@ msgstr "" #. to join the current started in-progress game #: src/states_screens/online/networking_lobby.cpp:203 msgid "Spectate" -msgstr "" +msgstr "Күзәтү" #: src/states_screens/online/networking_lobby.cpp:204 msgid "Install addon" -msgstr "" +msgstr "Кушымча урнаштыру" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, @@ -5447,7 +5447,7 @@ msgstr[0] "" #: src/states_screens/online/networking_lobby.cpp:698 #, c-format msgid "Connecting to server %s" -msgstr "" +msgstr "%s серверына тоташу" #: src/states_screens/online/networking_lobby.cpp:703 msgid "Finding a quick play server" @@ -5463,7 +5463,7 @@ msgstr "" #. I18N: Goals in achievement #: src/states_screens/online/online_profile_achievements.cpp:83 msgid "Goals" -msgstr "" +msgstr "Максатлар" #: src/states_screens/online/online_profile_achievements.cpp:116 #: src/states_screens/online/online_profile_achievements.cpp:315 @@ -5502,11 +5502,11 @@ msgstr "Челтәрдә түгел" #: src/states_screens/online/online_profile_settings.cpp:79 msgid "Enter new E-mail below" -msgstr "" +msgstr "Түбәндә яңа эл. почта кертегез" #: src/states_screens/online/online_profile_settings.cpp:84 msgid "New Email has to be between 5 and 254 characters long!" -msgstr "" +msgstr "Яңа эл. почта кимендә 5, ә иң күбе 254 билгедән торырга тиеш!" #: src/states_screens/online/online_profile_settings.cpp:93 msgid "New Email is invalid!" @@ -5519,7 +5519,7 @@ msgstr "Эл. почта үзгәрде!" #: src/states_screens/online/online_profile_settings.cpp:120 #, c-format msgid "Failed to change E-mail: %s" -msgstr "" +msgstr "Эл. почтаны үзгәртә алмады: %s" #. I18N: Shown to players when he is not is not logged in #: src/states_screens/online/online_screen.cpp:201 @@ -5545,11 +5545,11 @@ msgstr "'%s' уенчысын ясап булмый." #: src/states_screens/online/register_screen.cpp:306 msgid "User name cannot be empty." -msgstr "" +msgstr "Кулланучының исеме буш була алмый." #: src/states_screens/online/register_screen.cpp:362 msgid "Online username and password must not be the same!" -msgstr "" +msgstr "Онлайн кулланучы исеме һәм серсүз бер үк булырга тиеш түгел!" #: src/states_screens/online/register_screen.cpp:366 msgid "Emails don't match!" @@ -5627,7 +5627,7 @@ msgstr "" #: src/states_screens/online/server_selection.cpp:504 msgid "No server is available." -msgstr "" +msgstr "Бер сервер да юк." #: src/states_screens/online/server_selection.cpp:512 msgid "Fetching servers" @@ -5829,7 +5829,7 @@ msgstr "Төймәсар %i" #: src/states_screens/options/options_screen_input.cpp:170 msgid "Touch Device" -msgstr "" +msgstr "Сизгер җиһаз" #. I18N: In the input configuration screen, help for touch device #: src/states_screens/options/options_screen_input.cpp:207 @@ -6024,13 +6024,13 @@ msgstr "Керү '%s'" #: src/states_screens/options/user_screen.cpp:659 msgid "You can't delete the only player." -msgstr "" +msgstr "Сез бердәнбер уенчыны бетерә алмыйсыз." #. I18N: In the player info dialog (when deleting) #: src/states_screens/options/user_screen.cpp:667 #, c-format msgid "Do you really want to delete player '%s'?" -msgstr "" +msgstr "Чыннан да '%s' уенчысын бетерергәме?" #. I18N: as in "ready, set, go", shown at the beginning of the race #: src/states_screens/race_gui_base.cpp:73 @@ -6057,12 +6057,12 @@ msgstr "ГОЛ!" #: src/states_screens/race_gui_base.cpp:82 #: src/states_screens/race_result_gui.cpp:409 msgid "Waiting for others" -msgstr "" +msgstr "Башкаларны көтү" #. I18N: Shown waiting for the server in network if live join or spectate #: src/states_screens/race_gui_base.cpp:84 msgid "Waiting for the server" -msgstr "" +msgstr "Серверны көтү" #. I18N: string used to show the song title (e.g. "Sunny Song") #: src/states_screens/race_gui_base.cpp:646 @@ -6098,11 +6098,11 @@ msgstr "Ярыш уңышсыз тәмамланды" #. and press the podium (2, 1, 3 like) icon instead of fire button #: src/states_screens/race_gui_overworld.cpp:541 msgid "Press podium icon to start tutorial" -msgstr "" +msgstr "Өйрәтүне башлау өчен, \"подиум тамгачыгы\"-на басыгыз" #: src/states_screens/race_gui_overworld.cpp:547 msgid "Press fire to start the tutorial" -msgstr "" +msgstr "Өйрәтүне башлау өчен, \"ут\"-ка басыгыз" #. I18N: Shown when multitouch GUI exists #. and press the podium (2, 1, 3 like) icon instead of fire button diff --git a/data/po/zh_CN.po b/data/po/zh_CN.po index 2299b13556f..68e03c985f6 100644 --- a/data/po/zh_CN.po +++ b/data/po/zh_CN.po @@ -6,7 +6,7 @@ # Ben Au, 2015 # Benau, 2016,2019-2020 # Benau, 2015-2016 -# CodingJellyfish , 2018,2021-2023 +# CodingJellyfish , 2018,2021-2024 # Jiawei Sun, 2022 # 92373a9a734415f33212259453a6274d_77ab48e, 2022 # Jin Zhang , 2015,2019-2021,2023 @@ -19,7 +19,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-06-16 01:41+0800\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: CodingJellyfish , 2018,2021-2023\n" +"Last-Translator: CodingJellyfish , 2018,2021-2024\n" "Language-Team: Chinese (China) (http://app.transifex.com/supertuxkart/supertuxkart/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -141,7 +141,7 @@ msgstr "把您的对手当成蚊子打!在一场比赛中用苍蝇拍打扁对 #. I18N: ./data/achievements.xml msgid "Beyond Luck" -msgstr "东方不败" +msgstr "不败传说" #. I18N: ./data/achievements.xml msgid "" @@ -1508,7 +1508,7 @@ msgstr "重播录像:在竞速模式或收集彩蛋中与重播录像比赛, #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "圈数赛:在指定的时间内达到尽可能多的圈数。" +msgstr "圈数模式:在指定的时间内达到尽可能多的圈数。" #. I18N: ./data/gui/screens/help2.stkgui #. I18N: In the help menu @@ -1736,7 +1736,7 @@ msgstr "高分选择" #. time. #: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" -msgstr "竞速模式" +msgstr "圈数模式" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen @@ -2635,7 +2635,7 @@ msgstr "外星讯号" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" -msgstr " 上古迷宫" +msgstr "上古迷宫" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml @@ -2676,7 +2676,7 @@ msgstr "大庄园" #. I18N: ../stk-assets/tracks/hole_drop/track.xml msgid "Hole Drop" -msgstr "纽扣球馆" +msgstr "纽扣球场" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" @@ -2731,7 +2731,7 @@ msgstr "迷你高尔夫球场" #. I18N: ../stk-assets/tracks/oasis/track.xml msgid "Oasis" -msgstr "沙中绿茵" +msgstr "绿洲球场" #. I18N: ../stk-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" @@ -2763,7 +2763,7 @@ msgstr "积雪顶峰" #. I18N: ../stk-assets/tracks/soccer_field/track.xml msgid "Soccer Field" -msgstr "足球场" +msgstr "经典球场" #. I18N: ../stk-assets/tracks/stadium/track.xml msgid "The Stadium" From d37558ff0f2eee869916933fa4bc845ab2f2adfd Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Thu, 31 Oct 2024 16:50:42 +0800 Subject: [PATCH 493/830] Update Changelog (#5199) * Update CHANGELOG * Update CHANGELOG again --- CHANGELOG.md | 50 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79fc90fddf0..611d4866785 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,44 +5,68 @@ It should be kept in mind that some versions have a less complete changelog than For similar reasons, and because some features are vastly more complex than others, attributions of main changes should not be taken as a shortcut for overall contribution. -## SuperTuxKart 1.5 (TBD, still unfinished) +## SuperTuxKart 1.5 Beta1 ### Networking * Improve track-voting logic when no majority is achieved, by kimden +* Prevent selectable addons to be removed by spectators, by kimden +* Make bot indices start from one, by JipFr +* Various bugfixes and code-quality improvements, by kimden ### General -* Make the game's window resizable in all the screens, by CodingJellyfish (previously, most UI screens did not support resizing) * New benchmark mode, by Alayan: - Can be run with a few clicks, allowing to easily test the performance of various settings or to compare different systems - Robust performance metrics that better reflect the impact of varying frametimes than Average FPS and 1% Lows. -* Fix incorrect unlock information in Story Mode after a Grand Prix, by CodingJellyfish +* Add benchmark mode to commandline options, by ektor5 +* Implement blog announcement system in Online screen, by CodingJellyfish * Make the progression of audio levels geometrical and increase default steps, allowing to set lower audio levels and better accuracy for low audio levels (especially useful for headphone users), by Alayan * Fix drive-on sound from materials being played when the game is paused, by Alayan * Fix a crash trying to read replays when the random starting position setting is enabled, by Alayan +* Enable smooth scrolling for Irrlicht, by CodingJellyfish * Handle track names with spaces in the replay reader, by Alayan +* Add launchable tag and use rDNS format for AppData file, by AsciiWolf +* Various build system updates, by deveee, tobbi, ognevny and others +* Various compiler fixes, by heirecka, limburgher, nyllet and others * Various tweaks, bugfixes and code-quality improvements ### Graphics * Improve the accuracy of the framerate limiter, by Benau -* Add more maximum framerate options to the built-in framerate limiter, by Benau (this does not affect physics, which run at 120FPs independetly of graphical FPS) +* Add more maximum framerate options to the built-in framerate limiter, by Benau * Add some graphical effects for legacy video drivers, by Benau -* Ensure fragment shaders use high precision, to avoid rendering issues with some drivers, by zmike -* Fix a related precision issue causing black artifacts with GL_ES, by CodingJellyfish -* Fix other shader issues that could produce black artifacts in specific situations, by CodingJellyfish +* Replace inaccurate normal compression algorithm with Octahedron Normal Vector, by CodingJellyfish +* Guarantee 2048 overall bone limit for skinned mesh, by CodingJellyfish +* Improve Cascaded Shadow Mapping, by CodingJellyfish +* Fix incorrect Screen-Space Reflection shader, by CodingJellyfish * Various improvements to the automatic computations of Level of Detail (LoD) distances, by Alayan -* Improve draw call performance in some situations, by CodingJellyfish +* Improve the performance of scene node iteration, by CodingJellyfish * Enable new higher LoD and shadows settings, by Alayan * Integrate LoD (Geometry Detail) settings in the graphics presets, by Alayan * Prefer displaying a lower quality LoD model over switching to a higher quality one when too close, by Alayan +* Various bugfixes and improvements, by zmike, Icenowy and others ### User Interface +* Make the game window resizable in all UI screens, by Benau and CodingJellyfish +* Use separated "base theme" and "skin variant" values for skin configuration, by Alayan +* Add some skin variants for Classic and Cartoon base theme, by Alayan * Add a new Display tab in the Settings, by Alayan -* Allow to rate addons with a keyboard or a controller, and notify when trying to rate an addon while not logged in, by CodingJellyfish -* Fix an issue that prevented to go up with a scrollbar using a trackpad, by CodingJellyfish +* Add help information for Lap Trial mode, by searinminecraft +* Allow to rate addons with a keyboard or a controller, by CodingJellyfish +* Allow users to select favorite karts/tracks/arenas, by Alayan and CodingJellyfish +* Allow users to search karts/arenas, by CodingJellyfish +* Allow users to group karts by kart classes, by CodingJellyfish * Improve the typing bars, especially for the coal theme, by Alayan -* Greatly improve UI layout for 'tall' resolutions (greater height than width), by CodingJellyfish -* Improve font scaling, by CodingJellyfish -* Various enhancements, by Qwertychouskie and others +* Various UI layout improvements, by CodingJellyfish +* Generate higher resolution texture for scalable fonts, by CodingJellyfish +* Show score with color on the center of speedometer in battles, by CodingJellyfish +* Various enhancements, by QwertyChouskie, Nomagno, Nstelt and others + +### Tracks and modeling +* Fix start positions for negative sidewards distance, by kimden +* Make the rescue bird place the kart towards the ball in soccer mode, by Snoker101 +* New music for Las Dunas Arena/Las Dunas Soccer, by ALBatross +* Update Godette face texture, by ZAQraven99 +* Fix Northern Resort skybox, by Alayan +* Various cut/checkline fixes, by Benau ### Mobile * Don't keep the rescue button active after it stops being touched, when the finger keeps touching the screen (e. g. to handle the steering wheel), by S0nter From 721018c64a68642985205f08ed423b33889f39c4 Mon Sep 17 00:00:00 2001 From: Deve Date: Sat, 2 Nov 2024 10:02:55 +0100 Subject: [PATCH 494/830] Try disable tutorial on android TV to make google happy --- src/modes/overworld.cpp | 9 +++++++++ src/states_screens/help/help_screen_1.cpp | 20 ++++++++++++++++++++ src/states_screens/help/help_screen_1.hpp | 3 +++ src/states_screens/main_menu_screen.cpp | 19 +++++++++++++++++++ src/states_screens/race_gui_overworld.cpp | 10 ++++++++++ 5 files changed, 61 insertions(+) diff --git a/src/modes/overworld.cpp b/src/modes/overworld.cpp index 1f060ecbf69..0fed626666e 100644 --- a/src/modes/overworld.cpp +++ b/src/modes/overworld.cpp @@ -38,6 +38,10 @@ #include "tracks/track.hpp" #include "tracks/track_object_manager.hpp" +#ifdef ANDROID +#include +#endif + //----------------------------------------------------------------------------- OverWorld::OverWorld() : World() { @@ -242,6 +246,11 @@ void OverWorld::onFirePressed(Controller* who) { if (challenges[n].m_challenge_id == "tutorial") { +#ifdef ANDROID + if (SDL_IsAndroidTV()) + return; +#endif + scheduleTutorial(); return; } diff --git a/src/states_screens/help/help_screen_1.cpp b/src/states_screens/help/help_screen_1.cpp index bb6c6d5ba75..eda76f31db2 100644 --- a/src/states_screens/help/help_screen_1.cpp +++ b/src/states_screens/help/help_screen_1.cpp @@ -21,6 +21,10 @@ #include "guiengine/widgets/button_widget.hpp" #include "modes/tutorial_utils.hpp" +#ifdef ANDROID +#include +#endif + using namespace GUIEngine; // ----------------------------------------------------------------------------- @@ -37,6 +41,22 @@ void HelpScreen1::loadedFromFile() // ----------------------------------------------------------------------------- +void HelpScreen1::beforeAddingWidget() +{ +#ifdef ANDROID + if (SDL_IsAndroidTV()) + { + Widget* tutorial = getWidget("startTutorial"); + if (tutorial) + tutorial->setVisible(false); + + Widget* tutorial_icon = getWidget("tutorialIcon"); + if (tutorial_icon) + tutorial_icon->setVisible(false); + } +#endif +} + void HelpScreen1::eventCallback(Widget* widget, const std::string& name, const int playerID) { if (name == "startTutorial") diff --git a/src/states_screens/help/help_screen_1.hpp b/src/states_screens/help/help_screen_1.hpp index e517f721c73..2676718e49e 100644 --- a/src/states_screens/help/help_screen_1.hpp +++ b/src/states_screens/help/help_screen_1.hpp @@ -35,6 +35,9 @@ class HelpScreen1 : public GUIEngine::Screen, public GUIEngine::ScreenSingleton< /** \brief implement callback from parent class GUIEngine::Screen */ virtual void loadedFromFile() OVERRIDE; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void beforeAddingWidget() OVERRIDE; /** \brief implement callback from parent class GUIEngine::Screen */ virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name, diff --git a/src/states_screens/main_menu_screen.cpp b/src/states_screens/main_menu_screen.cpp index bb35a2d8d4d..ccd4a461383 100644 --- a/src/states_screens/main_menu_screen.cpp +++ b/src/states_screens/main_menu_screen.cpp @@ -72,6 +72,10 @@ #include +#ifdef ANDROID +#include +#endif + using namespace GUIEngine; using namespace Online; @@ -119,6 +123,15 @@ void MainMenuScreen::beforeAddingWidget() if (w) w->setVisible(false); #endif + +#ifdef ANDROID + if (SDL_IsAndroidTV()) + { + Widget* tutorial = getWidget("startTutorial"); + if (tutorial) + tutorial->setVisible(false); + } +#endif } // ---------------------------------------------------------------------------- @@ -327,6 +340,12 @@ void MainMenuScreen::onUpdate(float delta) if (player->getUseFrequency() != 0) return; +#ifdef ANDROID + // Don't show tutorial dialog on Android TV + if (SDL_IsAndroidTV()) + return; +#endif + player->incrementUseFrequency(); class PlayTutorial : public MessageDialog::IConfirmDialogListener diff --git a/src/states_screens/race_gui_overworld.cpp b/src/states_screens/race_gui_overworld.cpp index a82c5dd95fa..f72d6a39635 100644 --- a/src/states_screens/race_gui_overworld.cpp +++ b/src/states_screens/race_gui_overworld.cpp @@ -58,6 +58,11 @@ #include #include #include + +#ifdef ANDROID +#include +#endif + using namespace irr; #include @@ -526,6 +531,11 @@ void RaceGUIOverworld::drawGlobalMiniMap() if (challenges[n].m_challenge_id == "tutorial") { +#ifdef ANDROID + if (SDL_IsAndroidTV()) + continue; +#endif + gui::ScalableFont* font = GUIEngine::getTitleFont(); font->draw(_("Tutorial"), pos, video::SColor(255,255,255,255), false, true /* vcenter */, NULL); From 3f7958b9f4ecd90fcde76a8d48ce9571c8e59216 Mon Sep 17 00:00:00 2001 From: QwertyChouskie Date: Sat, 2 Nov 2024 02:13:53 -0700 Subject: [PATCH 495/830] graphical_restrictions.xml: Remove restrictions for Android Emulator (#5170) Android Emulator supports proper hardware acceleration nowadays, we shouldn't be forcing the legacy pipeline if it's not needed. --- data/graphical_restrictions.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/data/graphical_restrictions.xml b/data/graphical_restrictions.xml index 01b268b7e79..b3ade708cd8 100644 --- a/data/graphical_restrictions.xml +++ b/data/graphical_restrictions.xml @@ -34,8 +34,6 @@ - - From 4c231063086895c54ae1896a9074e351b273519a Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sat, 2 Nov 2024 20:19:59 +0800 Subject: [PATCH 496/830] Fix missed credit --- CHANGELOG.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 611d4866785..85b66143275 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,8 +65,8 @@ For similar reasons, and because some features are vastly more complex than othe * Make the rescue bird place the kart towards the ball in soccer mode, by Snoker101 * New music for Las Dunas Arena/Las Dunas Soccer, by ALBatross * Update Godette face texture, by ZAQraven99 -* Fix Northern Resort skybox, by Alayan -* Various cut/checkline fixes, by Benau +* Fix Northern Resort skybox, by CrystalDaEevee +* Various cut/checkline fixes, by CrystalDaEevee ### Mobile * Don't keep the rescue button active after it stops being touched, when the finger keeps touching the screen (e. g. to handle the steering wheel), by S0nter @@ -90,10 +90,12 @@ For similar reasons, and because some features are vastly more complex than othe ### Tracks and modeling * Updated Konqi, by ZAQraven99 * New Godette kart, by ZAQraven99 +* New Hole Drop Soccer Field, by CrystalDaEevee, music by DernisNW +* New Oasis Soccer Field, by CrystalDaEevee * Updated Battle Island and Cave X, by Typhon306 * Fix broken invisible wall in Antediluvian Abyss, by Benau * New textures in Shifting Sands, by KartOym -* Balanced starting positions in all official soccer fields, by Crystal +* Balanced starting positions in all official soccer fields, by CrystalDaEevee ### Networking * Add track searching to network track screen, by Benau @@ -202,7 +204,7 @@ For similar reasons, and because some features are vastly more complex than othe ### Tracks and modeling #### Karts * New version of Kiki, by Typhon306 and ZAQraven99 -* Improved karts, by Crystal +* Improved karts, by CrystalDaEevee * Pidgin, Puffy * Improved beastie animation, by D_ft Kid From 64d36b2769b2546c081a2d95a49b47ee6775d093 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sat, 2 Nov 2024 20:36:35 +0800 Subject: [PATCH 497/830] Fix memory leak --- src/config/favorite_status.cpp | 8 +------- src/config/favorite_status.hpp | 2 -- src/config/player_profile.cpp | 19 ++++++++++++++++--- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/config/favorite_status.cpp b/src/config/favorite_status.cpp index 85240cb2027..3426f2c5808 100644 --- a/src/config/favorite_status.cpp +++ b/src/config/favorite_status.cpp @@ -59,13 +59,7 @@ FavoriteStatus::FavoriteStatus(const XMLNode* node, std::string parse_type) m_favorite[temp_group_string].insert(temp_string); } } -} // FavoriteStatus - -//------------------------------------------------------------------------------ -FavoriteStatus::~FavoriteStatus() -{ - -} // ~FavoriteStatus +} // FavoriteStatu //------------------------------------------------------------------------------ /** Adds a new favorite track to this player profile and to the group diff --git a/src/config/favorite_status.hpp b/src/config/favorite_status.hpp index 522ae3dd550..cde113b1bc9 100644 --- a/src/config/favorite_status.hpp +++ b/src/config/favorite_status.hpp @@ -55,8 +55,6 @@ class FavoriteStatus /** Parse all <(parse_type)/> in in xml node */ FavoriteStatus(const XMLNode *node, std::string parse_type); - virtual ~FavoriteStatus(); - void save(UTFWriter &out); bool isFavorite(std::string ident); diff --git a/src/config/player_profile.cpp b/src/config/player_profile.cpp index e2d1aa9f739..8a4a8ee13a2 100644 --- a/src/config/player_profile.cpp +++ b/src/config/player_profile.cpp @@ -105,9 +105,22 @@ PlayerProfile::PlayerProfile(const XMLNode* node) //------------------------------------------------------------------------------ PlayerProfile::~PlayerProfile() { - delete m_story_mode_status; - delete m_achievements_status; - delete m_favorite_track_status; + if (m_story_mode_status) + { + delete m_story_mode_status; + } + if (m_achievements_status) + { + delete m_achievements_status; + } + if (m_favorite_track_status) + { + delete m_favorite_track_status; + } + if (m_favorite_kart_status) + { + delete m_favorite_kart_status; + } #ifdef DEBUG m_magic_number = 0xDEADBEEF; #endif From 26caafac5e2766a89280b85e65a083b430cebbd0 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 4 Nov 2024 19:08:04 +0800 Subject: [PATCH 498/830] Avoid iterating appear animation node when it's invisible (#5200) --- src/items/item.cpp | 90 +++++++++++++++++++++++----------------------- src/items/item.hpp | 3 ++ 2 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/items/item.cpp b/src/items/item.cpp index 7514d5e79aa..ea4d4413292 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -223,7 +223,8 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal, { m_icon_node = NULL; m_was_available_previously = true; - m_animation_start_ticks = 0; + // Prevent appear animation at start + m_animation_start_ticks = -9999; m_distance_2 = 1.2f; initItem(type, xyz, normal); m_graphical_type = getGrahpicalType(); @@ -251,6 +252,7 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal, // when already quite far. lodnode->autoComputeLevel(24); // The distance grows with the square root of the scaling factor m_node = lodnode; + m_appear_anime_node = irr_driver->getSceneManager()->addEmptySceneNode(m_node); } setType(type); handleNewMesh(getGrahpicalType()); @@ -273,7 +275,7 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal, { scene::ISceneNode* billboard = irr_driver->addBillboard(core::dimension2df(SPARK_SIZE, SPARK_SIZE), - "item_spark.png", m_node); + "item_spark.png", m_appear_anime_node); #ifdef DEBUG billboard->setName("spark"); #endif @@ -361,9 +363,11 @@ Item::~Item() if (m_node != NULL) { for (auto* node : m_spark_nodes) - m_node->removeChild(node); + m_appear_anime_node->removeChild(node); if (m_icon_node) - m_node->removeChild(m_icon_node); + m_appear_anime_node->removeChild(m_icon_node); + + m_node->removeChild(m_appear_anime_node); irr_driver->removeNode(m_node); m_node->drop(); @@ -380,7 +384,7 @@ Item::~Item() void Item::reset() { m_was_available_previously = true; - m_animation_start_ticks = 0; + m_animation_start_ticks = -9999; ItemState::reset(); if (m_node != NULL) @@ -417,7 +421,7 @@ void Item::handleNewMesh(ItemType type) if (!icon.empty()) { m_icon_node = irr_driver->addBillboard(core::dimension2df(1.0f, 1.0f), - icon, m_node); + icon, m_appear_anime_node); m_icon_node->setPosition(core::vector3df(0.0f, 0.5f, 0.0f)); m_icon_node->setVisible(false); @@ -503,60 +507,54 @@ void Item::updateGraphics(float dt) m_node->setRotation(hpr.toIrrHPR()); } // if item is available - for (size_t i = 0; i < SPARK_AMOUNT; i++) + bool is_in_appear_anime = time_since_return < 1.0f + || (!isAvailable() && time_till_return < 1.0f); + m_appear_anime_node->setVisible(is_in_appear_anime); + + if (is_in_appear_anime) { - if (time_since_return >= 1.0f) + for (size_t i = 0; i < SPARK_AMOUNT; i++) { - m_spark_nodes[i]->setVisible(false); - continue; - } + float t = time_since_return + 0.5f; + float t2 = time_since_return + 1.0f; - float t = time_since_return + 0.5f; - float t2 = time_since_return + 1.0f; + float node_angle = !rotating() ? 0.0f : + fmodf((float)World::getWorld()->getTicksSinceStart() / 40.0f, + M_PI * 2); - float node_angle = !rotating() ? 0.0f : - fmodf((float)World::getWorld()->getTicksSinceStart() / 40.0f, - M_PI * 2); + float x = sin(float(i) / float(SPARK_AMOUNT) * 2.0f * M_PI - node_angle) + * t * SPARK_SPEED_H; + float y = 2.0f * t2 - t2 * t2 - 0.5f; + float z = cos(float(i) / float(SPARK_AMOUNT) * 2.0f * M_PI - node_angle) + * t * SPARK_SPEED_H; - float x = sin(float(i) / float(SPARK_AMOUNT) * 2.0f * M_PI - node_angle) - * t * SPARK_SPEED_H; - float y = 2.0f * t2 - t2 * t2 - 0.5f; - float z = cos(float(i) / float(SPARK_AMOUNT) * 2.0f * M_PI - node_angle) - * t * SPARK_SPEED_H; + m_spark_nodes[i]->setPosition(core::vector3df(x, y, z)); - m_spark_nodes[i]->setPosition(core::vector3df(x, y, z)); + float factor = std::max(0.0f, 1.0f - t / 2.0f); - float factor = std::max(0.0f, 1.0f - t / 2.0f); - - if (factor < 0.001f) - { - m_spark_nodes[i]->setVisible(false); - } - else - { m_spark_nodes[i]->setVisible(true); ((scene::IBillboardSceneNode*)m_spark_nodes[i]) ->setSize(core::dimension2df(factor * SPARK_SIZE, - factor * SPARK_SIZE)); + factor * SPARK_SIZE)); } - } - if (m_icon_node) - { - if (!isAvailable() && time_till_return <= 1.0f) - { - m_icon_node->setVisible(true); - float size = 1.0f / (pow(6.0f, -time_till_return - 0.2f) * - (-time_till_return - 0.2f)) + 7.0f; - - ((scene::IBillboardSceneNode*)m_icon_node) - ->setSize(core::dimension2df(size * ICON_SIZE, - size * ICON_SIZE)); - } - else + if (m_icon_node) { - m_icon_node->setVisible(false); + if (!isAvailable()) + { + m_icon_node->setVisible(true); + float size = 1.0f / (pow(6.0f, -time_till_return - 0.2f) * + (-time_till_return - 0.2f)) + 7.0f; + + ((scene::IBillboardSceneNode*)m_icon_node) + ->setSize(core::dimension2df(size * ICON_SIZE, + size * ICON_SIZE)); + } + else + { + m_icon_node->setVisible(false); + } } } diff --git a/src/items/item.hpp b/src/items/item.hpp index 4f218513b7b..6e319cf4fd4 100644 --- a/src/items/item.hpp +++ b/src/items/item.hpp @@ -330,6 +330,9 @@ class Item : public ItemState, public NoCopy /** Graphical type of the mesh. */ ItemType m_graphical_type; + /** The parent of m_spark_nodes and m_icon_node */ + scene::ISceneNode* m_appear_anime_node; + /** Vector containing the sparks */ std::vector m_spark_nodes; From 6c8cbcf0b7e3494befccc453079d0c3e0d378f1e Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Fri, 8 Nov 2024 22:23:11 +0800 Subject: [PATCH 499/830] Add favorite to network track & Fix Android favorite kart (#5202) --- data/gui/screens/arenas.stkgui | 2 +- data/gui/screens/karts.stkgui | 55 ++++++++++--------- data/gui/screens/online/network_karts.stkgui | 57 ++++++++++---------- data/gui/screens/tracks.stkgui | 14 +++-- src/states_screens/kart_selection.cpp | 9 ++-- src/states_screens/online/tracks_screen.cpp | 23 +++++++- 6 files changed, 92 insertions(+), 68 deletions(-) diff --git a/data/gui/screens/arenas.stkgui b/data/gui/screens/arenas.stkgui index ef416f501ea..e4ecb37b455 100644 --- a/data/gui/screens/arenas.stkgui +++ b/data/gui/screens/arenas.stkgui @@ -11,7 +11,7 @@
- +
diff --git a/data/gui/screens/karts.stkgui b/data/gui/screens/karts.stkgui index f6998767625..2351e815c37 100644 --- a/data/gui/screens/karts.stkgui +++ b/data/gui/screens/karts.stkgui @@ -7,38 +7,37 @@ align="center" text_align="center" /> - + -
-
- - -
-
- - -
- - - - -
- - - +
+ + +
+
+ +
+ + + +
+
+ + + +
diff --git a/data/gui/screens/online/network_karts.stkgui b/data/gui/screens/online/network_karts.stkgui index ade06ac4f82..494d6a58615 100644 --- a/data/gui/screens/online/network_karts.stkgui +++ b/data/gui/screens/online/network_karts.stkgui @@ -4,38 +4,37 @@
- + - -
-
- - -
-
- - -
- - - - -
- - - + +
+ + +
+
+ +
+ + + +
+
+ + + +
diff --git a/data/gui/screens/tracks.stkgui b/data/gui/screens/tracks.stkgui index 4d5212534ab..dd01abbda88 100644 --- a/data/gui/screens/tracks.stkgui +++ b/data/gui/screens/tracks.stkgui @@ -3,10 +3,18 @@
-
- + +
+
+
+ + + +
+
+ m_properties[GUIEngine::PROP_WIDTH] = "85%"; + getWidget("karts")->m_properties[GUIEngine::PROP_WIDTH] = "85%"; getWidget("continue")->setVisible(true); } else { - getWidget("kartlist")->m_properties[GUIEngine::PROP_WIDTH] = "100%"; + getWidget("karts")->m_properties[GUIEngine::PROP_WIDTH] = "100%"; getWidget("continue")->setVisible(false); } // Remove dispatcher from m_widgets before calculateLayout otherwise a @@ -418,9 +418,6 @@ void KartSelectionScreen::init() DynamicRibbonWidget* w = getWidget("karts"); assert( w != NULL ); - // Only allow keyboard and gamepad to choose kart without continue button in - // multitouch GUI, so mouse (touch) clicking can be used as previewing karts - w->setEventCallbackActive(Input::IT_MOUSEBUTTON, !useContinueButton()); KartHoverListener* karthoverListener = new KartHoverListener(this); w->registerHoverListener(karthoverListener); @@ -1233,7 +1230,7 @@ void KartSelectionScreen::eventCallback(Widget* widget, } setKartsFromCurrentGroup(); } - else if (m_kart_widgets.size() > unsigned(player_id)) + else if (m_kart_widgets.size() > unsigned(player_id) && !useContinueButton()) playerConfirm(player_id); } else if (name == "kart_class") diff --git a/src/states_screens/online/tracks_screen.cpp b/src/states_screens/online/tracks_screen.cpp index b6d2ec407d2..752c4f609bb 100644 --- a/src/states_screens/online/tracks_screen.cpp +++ b/src/states_screens/online/tracks_screen.cpp @@ -91,6 +91,14 @@ void TracksScreen::eventCallback(Widget* widget, const std::string& name, m_laps->setValue(host_vote->m_num_laps); m_reversed->setState(host_vote->m_reverse); voteForPlayer(); + + // If editing favorite, also favorite that track + if (getWidget("favorite")->getState() + && !PlayerManager::getCurrentPlayer()->isFavoriteTrack(host_vote->m_track_name)) + { + PlayerManager::getCurrentPlayer()->addFavoriteTrack(host_vote->m_track_name); + buildTrackList(); + } } } } @@ -130,7 +138,16 @@ void TracksScreen::eventCallback(Widget* widget, const std::string& name, if (m_selected_track) { - if (STKHost::existHost()) + if (getWidget("favorite")->getState()) + { + if(PlayerManager::getCurrentPlayer()->isFavoriteTrack(m_selected_track->getIdent())) + PlayerManager::getCurrentPlayer()->removeFavoriteTrack(m_selected_track->getIdent()); + else + PlayerManager::getCurrentPlayer()->addFavoriteTrack(m_selected_track->getIdent()); + + buildTrackList(); + } + else if (STKHost::existHost()) { w2->setBadge(selection, OK_BADGE); voteForPlayer(); @@ -343,6 +360,10 @@ void TracksScreen::beforeAddingWidget() RibbonWidget* tabs = getWidget("trackgroups"); tabs->clearAllChildren(); + + CheckBoxWidget* favorite_cb = getWidget("favorite"); + assert( favorite_cb != NULL ); + favorite_cb->setState(false); RaceManager::MinorRaceModeType minor_mode = RaceManager::get()->getMinorMode(); bool is_soccer = minor_mode == RaceManager::MINOR_MODE_SOCCER; From 7027212b2f268281b9b532e42abbd30bf0f6dae7 Mon Sep 17 00:00:00 2001 From: Deve Date: Wed, 13 Nov 2024 00:47:07 +0100 Subject: [PATCH 500/830] Fixed a crash when trying to edit favorites in multiplayer screen. Also fixed some compiler warnings. --- src/states_screens/kart_selection.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index 611edf993f5..3ce44630e9e 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -354,7 +354,7 @@ void KartSelectionScreen::beforeAddingWidget() kart_class->m_properties[GUIEngine::PROP_MIN_VALUE] = "0"; kart_class->m_properties[GUIEngine::PROP_MAX_VALUE] = StringUtils::toString(classes.size()); - for (int i = 0; i < classes.size(); i++) + for (unsigned int i = 0; i < classes.size(); i++) { // Make the first letter upper-case std::string class_str = classes[i]; @@ -1214,9 +1214,9 @@ void KartSelectionScreen::eventCallback(Widget* widget, assert(w != NULL); const std::string selection = w->getSelectionIDString(player_id); - if (getWidget("favorite")->getState() - && player_id == PLAYER_ID_GAME_MASTER - && selection != RANDOM_KART_ID) + if (getWidget("favorite")->getState() && + player_id == PLAYER_ID_GAME_MASTER && + selection != RANDOM_KART_ID && !selection.empty()) { const KartProperties *kp = kart_properties_manager->getKart(selection); @@ -1632,7 +1632,7 @@ PtrVector KartSelectionScreen::getUsableKarts( prop->getName().make_lower().find(search_text.c_str()) == -1) continue; - if (kart_class->getValue() != classes.size() && + if (kart_class->getValue() != (int)classes.size() && classes[kart_class->getValue()] != prop->getKartType()) continue; From 80b91236231c5d3a598d0248d4501134450dffb2 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 10 Dec 2024 01:57:33 +0400 Subject: [PATCH 501/830] Remove old PR branch from readme [skip ci] --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d8d4e84b4c0..709132ddb76 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,9 @@ This repository contains a **modified** version of SuperTuxKart (STK), mainly in ## Important branches -* [master](https://github.com/kimden/stk-code/): contains an old but stable version, which cannot be suddenly broken by recent commits (as almost all of them are currently in `command-manager-prototype` branch). +* [master](https://github.com/kimden/stk-code/): contains the latest version. For a few years, it contained old commits, while new commits were on `command-manager-prototype` branch. Use this branch if you want to deploy your own server. -* [command-manager-prototype](https://github.com/kimden/stk-code/tree/command-manager-prototype): contains all the latest commits, starting from introduction of command manager. As there are too many commits already, it will be merged into `master` branch soon, but not before the long-term database structure and similar important things are defined. - -* [command-manager-2x](https://github.com/kimden/stk-code/tree/command-manager-2x): the branch combining `command-manager-prototype` and [BalanceSTK2](https://github.com/Alayan-stk-2/stk-code/tree/BalanceSTK2), which is currently the source code of 2.X development version. This branch might not have the latest commits, its purpose is to store game results while testing 2.X version. +* [command-manager-2x](https://github.com/kimden/stk-code/tree/command-manager-2x): the branch combining `command-manager-prototype` and [BalanceSTK2](https://github.com/Alayan-stk-2/stk-code/tree/BalanceSTK2), which is currently the source code of 2.X development version. This branch might not have the latest commits, its purpose is to store game results while testing 2.X version. It will be changed to have commits from `master` instead of `command-manager-prototype`, which is now deprecated. * [local-client](https://github.com/kimden/stk-code/tree/local-client): the version of client with some optimizations and edits, used by kimden. For now, this is the only branch of this repo that is really intended for client-side usage. From 54642f6871ec8bc039a4780cc1ed6b7fdeac8df1 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 11 Dec 2024 02:02:17 +0400 Subject: [PATCH 502/830] Fix filters preventing playing Moved kart/map filters below checks for number of assets. Before, applying filters could cause hourglass while citing the reason of "having not enough standard tracks"?? --- src/network/protocols/server_lobby.cpp | 29 +++++++++++++------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 71174cd7f96..75600cffa81 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -6318,20 +6318,6 @@ bool ServerLobby::canRace(STKPeer* peer) std::set maps = peer->getClientAssets().second; std::set karts = peer->getClientAssets().first; - applyAllFilters(maps, true); - applyAllKartFilters(username, karts, false); - - if (karts.empty()) - { - m_why_peer_cannot_play[peer] = HR_NO_KARTS_AFTER_FILTER; - return false; - } - if (maps.empty()) - { - m_why_peer_cannot_play[peer] = HR_NO_MAPS_AFTER_FILTER; - return false; - } - if (!m_play_requirement_tracks.empty()) for (const std::string& track: m_play_requirement_tracks) if (peer->getClientAssets().second.count(track) == 0) @@ -6388,6 +6374,21 @@ bool ServerLobby::canRace(STKPeer* peer) m_why_peer_cannot_play[peer] = HR_OFFICIAL_TRACKS_PLAY_THRESHOLD; return false; } + + applyAllFilters(maps, true); + applyAllKartFilters(username, karts, false); + + if (karts.empty()) + { + m_why_peer_cannot_play[peer] = HR_NO_KARTS_AFTER_FILTER; + return false; + } + if (maps.empty()) + { + m_why_peer_cannot_play[peer] = HR_NO_MAPS_AFTER_FILTER; + return false; + } + m_why_peer_cannot_play[peer] = 0; return true; } // canRace From 724a28cbb09ca01eb0e81c6cfaee52bc12fdaf32 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Wed, 18 Dec 2024 22:50:51 +0800 Subject: [PATCH 503/830] Maybe fix 5226 --- src/items/item.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/items/item.cpp b/src/items/item.cpp index ea4d4413292..79f1b6f2781 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -414,7 +414,7 @@ void Item::handleNewMesh(ItemType type) m_node->setRotation(hpr.toIrrHPR()); if (m_icon_node) - m_node->removeChild(m_icon_node); + m_appear_anime_node->removeChild(m_icon_node); m_icon_node = NULL; auto icon = ItemManager::getIcon(type); From f72d62ce8795f16ee4a73b35e956378a93982cce Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Thu, 19 Dec 2024 18:26:47 +0800 Subject: [PATCH 504/830] Fix invalid memory access --- src/graphics/sp/sp_base.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/graphics/sp/sp_base.cpp b/src/graphics/sp/sp_base.cpp index cc9265b33ee..f05fd30cec0 100644 --- a/src/graphics/sp/sp_base.cpp +++ b/src/graphics/sp/sp_base.cpp @@ -123,7 +123,7 @@ unsigned g_skinning_offset = 0; // ---------------------------------------------------------------------------- std::vector g_skinning_mesh; // ---------------------------------------------------------------------------- -int g_skinning_tbo_limit = 0; +bool g_skinning_use_tbo = false; // ---------------------------------------------------------------------------- int sp_cur_shadow_cascade = 0; // ---------------------------------------------------------------------------- @@ -319,12 +319,13 @@ void initSkinning() else { #ifndef USE_GLES2 - glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &g_skinning_tbo_limit); - if (stk_config->m_max_skinning_bones << 6 > (unsigned)g_skinning_tbo_limit) + int skinning_tbo_limit; + glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &skinning_tbo_limit); + if (stk_config->m_max_skinning_bones << 6 > (unsigned)skinning_tbo_limit) { Log::warn("SharedGPUObjects", "Too many bones for skinning, max: %d", - g_skinning_tbo_limit >> 6); - stk_config->m_max_skinning_bones = g_skinning_tbo_limit >> 6; + skinning_tbo_limit >> 6); + stk_config->m_max_skinning_bones = skinning_tbo_limit >> 6; } Log::info("SharedGPUObjects", "Hardware Skinning enabled, method: TBO, " "max bones: %u", stk_config->m_max_skinning_bones); @@ -444,7 +445,14 @@ void init() if (CVS->isARBTextureBufferObjectUsable()) { - glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE_ARB, &g_skinning_tbo_limit); + int skinning_tbo_limit; + glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE_ARB, &skinning_tbo_limit); + + g_skinning_use_tbo = skinning_tbo_limit >= stk_config->m_max_skinning_bones << 6; + } + else + { + g_skinning_use_tbo = false; } initSkinning(); @@ -655,8 +663,7 @@ SPShader* getNormalVisualizer() // ---------------------------------------------------------------------------- bool skinningUseTBO() { - return CVS->isARBTextureBufferObjectUsable() - && g_skinning_tbo_limit >= 64 * stk_config->m_max_skinning_bones; + return g_skinning_use_tbo; } From fe08205c65b81f864149b222198c262a0bc758c0 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Thu, 19 Dec 2024 20:07:48 +0800 Subject: [PATCH 505/830] Fix Windows armv7 build (#5224) Since latest Windows SDK dropped armv7 support, we skip the MSVC windows armv7 build on GitHub actions. There's still armv7 in llvm-mingw. --- .github/workflows/windows.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 28f1113702b..d53b33edc2d 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -15,6 +15,9 @@ jobs: matrix: arch: [i686, x86_64, armv7, aarch64] os: [windows-latest, ubuntu-latest] + exclude: + - arch: armv7 + os: windows-latest runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 From 3dbf3606839302e49964dd0956541b900ecc2752 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 19 Dec 2024 17:49:31 +0400 Subject: [PATCH 506/830] Move ranking related stuff out of server_lobby.cpp (#5223) --- src/network/protocols/ranking.cpp | 482 +++++++++++++++++++++++++ src/network/protocols/ranking.hpp | 82 +++++ src/network/protocols/server_lobby.cpp | 469 ++---------------------- src/network/protocols/server_lobby.hpp | 45 +-- 4 files changed, 605 insertions(+), 473 deletions(-) create mode 100644 src/network/protocols/ranking.cpp create mode 100644 src/network/protocols/ranking.hpp diff --git a/src/network/protocols/ranking.cpp b/src/network/protocols/ranking.cpp new file mode 100644 index 00000000000..af93b1473e5 --- /dev/null +++ b/src/network/protocols/ranking.cpp @@ -0,0 +1,482 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2024 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "network/protocols/ranking.hpp" +#include "io/xml_node.hpp" +#include "utils/log.hpp" +#include "utils/time.hpp" +#include +#include +#include + +namespace +{ + /* Ranking related variables */ + // If updating the base points, update the base points distribution in DB + const double BASE_RANKING_POINTS = 4000.0; // Given to a new player on 1st connection to a ranked server + const double BASE_RATING_DEVIATION = 1000.0; // Given to a new player on 1st connection to a ranked server + const double MIN_RATING_DEVIATION = 100.0; // A server cron job makes RD go up if a player is inactive + const double BASE_RD_PER_DISCONNECT = 15.0; + const double VAR_RD_PER_DISCONNECT = 3.0; + const double MAX_SCALING_TIME = 360.0; + const double BASE_POINTS_PER_SECOND = 0.18; + const double HANDICAP_OFFSET = 2000.0; +} + + +//----------------------------------------------------------------------------- +RankingEntry::RankingEntry(uint32_t online_id): online_id(online_id) +{ + raw_score = BASE_RANKING_POINTS; + score = BASE_RANKING_POINTS - 3*BASE_RATING_DEVIATION + 3*MIN_RATING_DEVIATION; + max_score = BASE_RANKING_POINTS - 3*BASE_RATING_DEVIATION + 3*MIN_RATING_DEVIATION; + deviation = BASE_RATING_DEVIATION; + disconnects = 0; + races = 0; +} + +//----------------------------------------------------------------------------- +/** Compute the new player's rankings used in ranked servers + */ +void Ranking::computeNewRankings(std::vector& data, bool time_trial) +{ + // TODO : go over the variables and look + // for things that can be simplified away. + // e.g. can new/prev be simplified ? + + std::vector ranking_data; + for (const auto& result: data) + { + auto it = m_entries.find(result.online_id); + if (it == m_entries.end()) + { + Log::fatal("Ranking", "Failed to obtain the saved ranking for online id %u", result.online_id); + return; + } + auto it2 = m_old_entries.find(result.online_id); + if (it2 == m_old_entries.end()) + m_old_entries[result.online_id] = it->second.entry; + ranking_data.push_back(&(it->second.entry)); + } + + std::vector raw_scores_change; + std::vector new_raw_scores; + std::vector prev_raw_scores; + std::vector prev_scores; + std::vector new_rating_deviations; + std::vector prev_rating_deviations; + std::vector prev_disconnects; //bitflag + std::vector disconnects; + + unsigned player_count = data.size(); + + // Initialize data vectors + for (unsigned i = 0; i < player_count; i++) + { + double prev_raw_score = ranking_data[i]->raw_score; + new_raw_scores.push_back(prev_raw_score); + prev_raw_scores.push_back(prev_raw_score); + + prev_scores.push_back(ranking_data[i]->score); + + double prev_deviation = ranking_data[i]->deviation; + new_rating_deviations.push_back(prev_deviation); + prev_rating_deviations.push_back(prev_deviation); + + prev_disconnects.push_back(ranking_data[i]->disconnects); + } + + // Update some variables + for (unsigned i = 0; i < player_count; i++) + { + //First, update the number of ranked races + ranking_data[i]->races++; + + // Update the number of disconnects + // We store the last 64 results as bit flags in a 64-bit int. + // This way, shifting flushes the oldest result. + ranking_data[i]->disconnects <<= 1; + + if (data[i].is_eliminated) + ranking_data[i]->disconnects++; + + // std::popcount is C++20 only + std::bitset<64> b(ranking_data[i]->disconnects); + disconnects.push_back(b.count()); + } + + // In this loop, considering the race as a set + // of head to head minimatches, we compute : + // I - Point changes for each ordered player pair. + // In a (p1, p2) pair, only p1's rating is changed. + // However, the loop will also go over (p2, p1). + // Point changes can be assymetric. + // II - Rating deviation changes + for (unsigned i = 0; i < player_count; i++) + { + raw_scores_change.push_back(0.0); + + double player1_raw_scores = new_raw_scores[i]; + if (data[i].handicap) + player1_raw_scores -= HANDICAP_OFFSET; + + // If the player has quitted before the race end, + // the time value will be incorrect, but it will not be used + double player1_time = data[i].time; + double player1_rd = prev_rating_deviations[i]; + + // On a disconnect, increase RD once, + // no matter how many opponents + if (data[i].is_eliminated && disconnects[i] >= 3) + new_rating_deviations[i] = prev_rating_deviations[i] + + BASE_RD_PER_DISCONNECT + + VAR_RD_PER_DISCONNECT * (disconnects[i] - 3); + + // Loop over all opponents + for (unsigned j = 0; j < player_count; j++) + { + // Don't compare a player with himself + if (i == j) + continue; + + // No change between two quitting players + if (data[i].is_eliminated && data[j].is_eliminated) + continue; + + double diff, result, expected_result, ranking_importance, max_time; + diff = result = expected_result = ranking_importance = max_time = 0.0; + + double player2_raw_scores = new_raw_scores[j]; + if (data[j].handicap) + player2_raw_scores -= HANDICAP_OFFSET; + + double player2_time = data[j].time; + double player2_rd = prev_rating_deviations[j]; + + // Each result can be viewed as new data helping to refine our previous + // estimates. But first, we need to assess how reliable this new data is + // compared to existing estimates. + + bool handicap_used = (data[i].handicap || data[j].handicap); + double accuracy = computeDataAccuracy(player1_rd, player2_rd, player1_raw_scores, player2_raw_scores, player_count, handicap_used); + + // Now that we've computed the reliability value, + // we can proceed with computing the points gained or lost + + // Compute the result and race ranking importance + + double mode_factor = getModeFactor(time_trial); + + if (data[i].is_eliminated) + { + // Recurring disconnects are punished through + // increased RD and higher RD floor, + // not through higher raw score loss + result = 0.0; + player1_time = player2_time * 1.2; // for getTimeSpread + } + else if (data[j].is_eliminated) + { + result = 1.0; + player2_time = player1_time * 1.2; + } + else + { + result = computeH2HResult(player1_time, player2_time); + } + + max_time = std::min(MAX_SCALING_TIME, std::max(player1_time, player2_time)); + + ranking_importance = accuracy * mode_factor * scalingValueForTime(max_time); + + // Compute the expected result using an ELO-like function + diff = player2_raw_scores - player1_raw_scores; + + expected_result = 1.0/ (1.0 + std::pow(10.0, + diff / ( BASE_RANKING_POINTS / 2.0 + * getModeSpread(time_trial) + * getTimeSpread(std::min(player1_time, player2_time))))); + + // Compute the ranking change + raw_scores_change[i] += ranking_importance * (result - expected_result); + + // We now update the rating deviation. The change + // depends on the current RD, on the result's accuracy, + // on how expected the result was (upsets can increase RD) + + // If there was a disconnect in this race, RD was handled once already + if (!data[i].is_eliminated) { + // First the RD reduction based on accuracy and current RD + double rd_change_factor = accuracy * 0.0016; + double rd_change = (-1) * prev_rating_deviations[i] * rd_change_factor; + + // If the unexpected result happened, we add a RD increase + // TODO : more reliable would be accumulating an expected_result/result + // differential over time, weighted through relative RDs. + // If that differential goes high, then increase RD while decaying + // the differential. Some work needed to ensure sensible maths. + double upset = std::abs(result - expected_result); + if (upset > 0.5) + { + // Renormalize so expected result 50% is 1.0 and expected result 100% is 0.0 + upset = 2.0 - 2 * upset; + upset = std::max(0.02, upset); + + // If upsets happen at the rate predicted by expected score, + // this won't prevent the rating deviation from going down. + // However, if upsets are at least twice more frequent than expected, RD will go up. + rd_change += MIN_RATING_DEVIATION * rd_change_factor / upset; + } + + // Minimum RD will be handled after all iterative RD change have been done, + // so as to avoid the order in which player pairs are computed changing results. + new_rating_deviations[i] += rd_change; + } + } + } + + // Don't merge it in the main loop as new_scores value are used there + for (unsigned i = 0; i < player_count; i++) + { + new_raw_scores[i] += raw_scores_change[i]; + ranking_data[i]->raw_score = new_raw_scores[i]; + + // Ensure RD doesn't go below the RD floor. + // The minimum RD is increased in case of repeated disconnects + double disconnects_floor = 0; + if (disconnects[i] >= 3) + { + int n = disconnects[i] - 3; + disconnects_floor = (disconnects[i] - 2) * BASE_RD_PER_DISCONNECT + + VAR_RD_PER_DISCONNECT * (n * (n + 1)) / 2; + } + new_rating_deviations[i] = std::max(new_rating_deviations[i], MIN_RATING_DEVIATION + disconnects_floor); + ranking_data[i]->deviation = new_rating_deviations[i]; + + // Update the main public rating. At min RD, it is equal to the raw score. + ranking_data[i]->score = ranking_data[i]->raw_score - 3 * new_rating_deviations[i] + 3 * MIN_RATING_DEVIATION; + if (ranking_data[i]->score > ranking_data[i]->max_score) + ranking_data[i]->max_score = ranking_data[i]->score; + } +} // computeNewRankings + + +//----------------------------------------------------------------------------- +/** Returns the mode race importance factor, + * used to make ranking move slower in more random modes. + */ +double Ranking::getModeFactor(bool time_trial) +{ + if (time_trial) + return 1.0; + return 0.75; +} // getModeFactor + +//----------------------------------------------------------------------------- +/** Returns the mode spread factor, used so that a similar difference in + * skill will result in a similar ranking difference in more random modes. + */ +double Ranking::getModeSpread(bool time_trial) +{ + if (time_trial) + return 1.0; + + //TODO: the value used here for normal races is a wild guess. + // When hard data to the spread tendencies of time-trial + // and normal mode becomes available, update this to make + // the spreads more comparable + return 1.25; +} // getModeSpread + +//----------------------------------------------------------------------------- +/** Returns the time spread factor. + * Short races are more random, so the expected result changes depending + * on race duration. + */ +double Ranking::getTimeSpread(double time) +{ + return sqrt(120.0 / time); +} // getTimeSpread + +//----------------------------------------------------------------------------- +/** Compute the scaling value of a given time + * This is linear to race duration, getTimeSpread takes care + * of expecting a more random result in shorter races. + */ +double Ranking::scalingValueForTime(double time) +{ + return time * BASE_POINTS_PER_SECOND; +} // scalingValueForTime + +//----------------------------------------------------------------------------- +/** Computes the score of a head-to-head minimatch. + * If time difference > 2,5% ; the result is 1 (complete win of player 1) + * or 0 (complete loss of player 1) + * Otherwise, it is averaged between 0 and 1. + */ +double Ranking::computeH2HResult(double player1_time, double player2_time) +{ + double max_time = std::max(player1_time, player2_time); + double min_time = std::min(player1_time, player2_time); + + double result = (max_time - min_time) / (min_time / 20.0); + result = std::min(1.0, 0.5 + result); + + if (player2_time <= player1_time) + result = 1.0 - result; + + return result; +} // computeH2HResult + +//----------------------------------------------------------------------------- +/** Computes a relative factor indicating how much informative value + * the new race result gives us. + * + * For a player with a high own rating deviation, the current rating is unreliable + * so any new data holds more importance. This is crucial to allow reasonably + * fast rating convergence of new players, provided they play accurately rated opponents. + * + * When the opponent has a high rating deviation, the expected scores are likely off. + * Therefore, the information from such a result is much less valuable. + * + * We also reduce rating changes when the player ratings are very different, even + * after considering the uncertainties from rating deviation. + * This is multi-purpose : + * - With a very high rating difference, random race events (very poor luck, disconnects) + * are very likely to be the cause of any upset, so the rate of legitimate upsets is + * unreliable. No rating method is safe. + * - Attempting to "farm" much lower rated players against which a practical 100% winrate + * may be reached (outside of random events) becomes very ineffective. Instead, + * to gain rating points, the player has incentive to play well-rated opponents. + * - The primary goal is to ensure that two players of equal rating would be about + * evenly matched in head-to-head. If two strong players each beat a much weaker third + * player, very little information is gained on how a direct head-to-head between the + * strong players would go. + * For the purposes of this rating computation, we assume that the informational value + * of a race is roughly proportional to the likelihood of the weaker player winning. + * We cap the effect so that losing to a much weaker player still costs rating points. + * + * In a race with many players, a single event can have a significant impact on the + * results of all the H2H. To avoid races with high players count having too strong + * rating swings, we apply a modifier scaling down accuracy. + * + * Finally, while handicap is allowed in ranked races and a rating offset is applied + * to keep expected results realistic (without incentivizing playing handicap-only), + * the results of such races are much less reliable. + */ +double Ranking::computeDataAccuracy(double player1_rd, double player2_rd, double player1_scores, double player2_scores, int player_count, bool handicap_used) +{ + double accuracy = player1_rd / (sqrt(player2_rd) * sqrt(MIN_RATING_DEVIATION)); + + double strong_lowerbound = (player1_scores > player2_scores) ? player1_scores - 3 * player1_rd + : player2_scores - 3 * player2_rd; + double weak_upperbound = (player1_scores > player2_scores) ? player2_scores + 3 * player2_rd + : player1_scores + 3 * player1_rd; + + if (weak_upperbound < strong_lowerbound) + { + double diff = strong_lowerbound - weak_upperbound; + diff = diff / (BASE_RANKING_POINTS / 2.0); + + // The expected result is that of the weaker player and is between 0 and 0.5 + double expected_result = 1.0/ (1.0 + std::pow(10.0, diff)); + expected_result = std::max(0.2, sqrt(2*expected_result)); + + accuracy *= expected_result; + } + + // Reduce the importance of single h2h in a race with many players. + // The overall impact of a race with more players is still always bigger. + double player_count_modifier = 2.0 / sqrt((double) player_count); + accuracy *= player_count_modifier; + + // Races with handicap are unreliable for ranking + if (handicap_used) + accuracy *= 0.25; + + return accuracy; +} + +//----------------------------------------------------------------------------- +void Ranking::cleanup() +{ + std::map new_entries; + for (const auto& pair: m_entries) + { + auto profile = pair.second.profile; + if (!profile.expired()) + new_entries.insert(pair); + } + std::swap(new_entries, m_entries); +} + +//----------------------------------------------------------------------------- +void Ranking::fill(uint32_t online_id, const XMLNode* result, std::shared_ptr npp) +{ + RankingEntry entry(online_id); + result->get("scores", &entry.score); + result->get("max-scores", &entry.max_score); + result->get("num-races-done", &entry.races); + result->get("raw-scores", &entry.raw_score); + result->get("rating-deviation", &entry.deviation); + result->get("disconnects", &entry.disconnects); + m_entries[online_id] = {entry, npp}; +} + +//----------------------------------------------------------------------------- +bool Ranking::has(uint32_t online_id) +{ + auto it = m_entries.find(online_id); + if (it == m_entries.end()) + return false; + if (it->second.profile.expired()) + return false; + return true; +} + +//----------------------------------------------------------------------------- +double Ranking::getDelta(uint32_t online_id) +{ + auto it = m_old_entries.find(online_id); + if (it == m_old_entries.end()) + return 0.; + auto it2 = m_entries.find(online_id); + if (it2 == m_entries.end()) + return 0.; + double result = it2->second.entry.score - it->second.score; + m_old_entries.erase(it); + return result; +} + +//----------------------------------------------------------------------------- +const RankingEntry Ranking::getScores(uint32_t online_id) const +{ + return m_entries.at(online_id).entry; +} + +//----------------------------------------------------------------------------- +const RankingEntry Ranking::getTemporaryPenalizedScores(uint32_t online_id) const +{ + RankingEntry entry = m_entries.at(online_id).entry; + entry.score -= 200.0; + entry.raw_score -= 200.0; + entry.races += 1; + entry.disconnects <<= 1; + entry.disconnects += 1; + return entry; +} \ No newline at end of file diff --git a/src/network/protocols/ranking.hpp b/src/network/protocols/ranking.hpp new file mode 100644 index 00000000000..0812045823e --- /dev/null +++ b/src/network/protocols/ranking.hpp @@ -0,0 +1,82 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2024 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef RANKING_HPP +#define RANKING_HPP + +#include +#include +#include + +class XMLNode; +class NetworkPlayerProfile; + +struct RankingEntry +{ + uint32_t online_id; + double raw_score; + double score; + double max_score; + double deviation; + uint64_t disconnects; + unsigned races; + + RankingEntry(uint32_t online_id = -1); +}; + +struct RaceResultData { + uint32_t online_id; + bool is_eliminated; + double time; + bool handicap; +}; + +struct RankingEntryAndProfile +{ + RankingEntry entry; + std::weak_ptr profile; +}; + +class Ranking +{ +private: + // A map that stores the actual scores. + std::map m_entries; + + // A map that stores the score before the last series of computeNewRankings calls has started. + std::map m_old_entries; + + static double getModeFactor(bool time_trial); + static double getModeSpread(bool time_trial); + static double getTimeSpread(double time); + static double scalingValueForTime(double time); + static double computeH2HResult(double player1_time, double player2_time); + static double computeDataAccuracy(double player1_rd, double player2_rd, + double player1_scores, double player2_scores, + int player_count, bool handicap_used); +public: + void computeNewRankings(std::vector& data, bool time_trial); + void cleanup(); + void fill(uint32_t online_id, const XMLNode* result, std::shared_ptr npp); + bool has(uint32_t online_id); + double getDelta(uint32_t online_id); + const RankingEntry getScores(uint32_t online_id) const; + const RankingEntry getTemporaryPenalizedScores(uint32_t online_id) const; +}; + +#endif \ No newline at end of file diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 447eb4c9fd6..624534b1282 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -41,6 +41,7 @@ #include "network/protocols/connect_to_peer.hpp" #include "network/protocols/game_protocol.hpp" #include "network/protocols/game_events_protocol.hpp" +#include "network/protocols/ranking.hpp" #include "network/race_event_manager.hpp" #include "network/server_config.hpp" #include "network/socket_address.hpp" @@ -70,20 +71,17 @@ int ServerLobby::m_fixed_laps = -1; class SubmitRankingRequest : public Online::XMLRequest { public: - SubmitRankingRequest(uint32_t online_id, double scores, - double max_scores, unsigned num_races, - double raw_scores, double rating_deviation, - uint64_t disconnects, + SubmitRankingRequest(const RankingEntry& entry, const std::string& country_code) : XMLRequest(Online::RequestManager::HTTP_MAX_PRIORITY) { - addParameter("id", online_id); - addParameter("scores", scores); - addParameter("max-scores", max_scores); - addParameter("num-races-done", num_races); - addParameter("raw-scores", raw_scores); - addParameter("rating-deviation", rating_deviation); - addParameter("disconnects", disconnects); + addParameter("id", entry.online_id); + addParameter("scores", entry.score); + addParameter("max-scores", entry.max_score); + addParameter("num-races-done", entry.races); + addParameter("raw-scores", entry.raw_score); + addParameter("rating-deviation", entry.deviation); + addParameter("disconnects", entry.disconnects); addParameter("country-code", country_code); } virtual void afterOperation() @@ -178,6 +176,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() Log::info("ServerLobby", "This server will submit ranking scores to " "the STK addons server. Don't bother hosting one without the " "corresponding permissions, as they would be rejected."); + + m_ranking = std::make_shared(); } m_result_ns = getNetworkString(); m_result_ns->setSynchronous(true); @@ -782,7 +782,7 @@ void ServerLobby::asynchronousUpdate() updateServerOwner(); if (ServerConfig::m_ranked && m_state.load() == WAITING_FOR_START_GAME) - clearDisconnectedRankedPlayer(); + m_ranking->cleanup(); if (allowJoinedPlayersWaiting() || (m_game_setup->isGrandPrix() && m_state.load() == WAITING_FOR_START_GAME)) @@ -2341,28 +2341,14 @@ void ServerLobby::checkRaceFinished() */ void ServerLobby::computeNewRankings() { - // TODO : go over the variables and look - // for things that can be simplified away. - // e.g. can new/prev be simplified ? - // No ranking for battle mode if (!RaceManager::get()->modeHasLaps()) return; - std::vector raw_scores_change; - std::vector new_raw_scores; - std::vector prev_raw_scores; - std::vector prev_scores; - std::vector new_rating_deviations; - std::vector prev_rating_deviations; - std::vector prev_disconnects; //bitflag - std::vector disconnects; - World* w = World::getWorld(); assert(w); unsigned player_count = RaceManager::get()->getNumPlayers(); - m_result_ns->addUInt8((uint8_t)player_count); // If all players quitted the race, we assume something went wrong // and skip entirely rating and statistics updates. @@ -2373,347 +2359,32 @@ void ServerLobby::computeNewRankings() if ((i + 1) == player_count) return; } - - // Initialize data vectors - for (unsigned i = 0; i < player_count; i++) - { - const uint32_t id = RaceManager::get()->getKartInfo(i).getOnlineId(); - double prev_raw_score = m_raw_scores.at(id); - new_raw_scores.push_back(prev_raw_score); - prev_raw_scores.push_back(prev_raw_score); - - prev_scores.push_back(m_scores.at(id)); - - double prev_deviation = m_rating_deviations.at(id); - new_rating_deviations.push_back(prev_deviation); - prev_rating_deviations.push_back(prev_deviation); - - prev_disconnects.push_back(m_num_ranked_disconnects.at(id)); - } - - // Update some variables - for (unsigned i = 0; i < player_count; i++) - { - const uint32_t id = RaceManager::get()->getKartInfo(i).getOnlineId(); - - //First, update the number of ranked races - m_num_ranked_races.at(id)++; - - // Update the number of disconnects - // We store the last 64 results as bit flags in a 64-bit int. - // This way, shifting flushes the oldest result. - m_num_ranked_disconnects.at(id) <<= 1; - - if (w->getKart(i)->isEliminated()) - m_num_ranked_disconnects.at(id)++; - - // std::popcount is C++20 only - std::bitset<64> b(m_num_ranked_disconnects.at(id)); - disconnects.push_back(b.count()); - } - - // In this loop, considering the race as a set - // of head to head minimatches, we compute : - // I - Point changes for each ordered player pair. - // In a (p1, p2) pair, only p1's rating is changed. - // However, the loop will also go over (p2, p1). - // Point changes can be assymetric. - // II - Rating deviation changes + + // Fill the results for the rankings to process + std::vector data; for (unsigned i = 0; i < player_count; i++) { - raw_scores_change.push_back(0.0); - - double player1_raw_scores = new_raw_scores[i]; - if (w->getKart(i)->getHandicap()) - player1_raw_scores -= HANDICAP_OFFSET; - - // If the player has quitted before the race end, - // the time value will be incorrect, but it will not be used - double player1_time = RaceManager::get()->getKartRaceTime(i); - double player1_rd = prev_rating_deviations[i]; - - // On a disconnect, increase RD once, - // no matter how many opponents - if (w->getKart(i)->isEliminated() && disconnects[i] >= 3) - new_rating_deviations[i] = prev_rating_deviations[i] - + BASE_RD_PER_DISCONNECT - + VAR_RD_PER_DISCONNECT * (disconnects[i] - 3); - - // Loop over all opponents - for (unsigned j = 0; j < player_count; j++) - { - // Don't compare a player with himself - if (i == j) - continue; - - // No change between two quitting players - if ( w->getKart(i)->isEliminated() - && w->getKart(j)->isEliminated()) - continue; - - double diff, result, expected_result, ranking_importance, max_time; - diff = result = expected_result = ranking_importance = max_time = 0.0; - - double player2_raw_scores = new_raw_scores[j]; - if (w->getKart(j)->getHandicap()) - player2_raw_scores -= HANDICAP_OFFSET; - - double player2_time = RaceManager::get()->getKartRaceTime(j); - double player2_rd = prev_rating_deviations[j]; - - // Each result can be viewed as new data helping to refine our previous - // estimates. But first, we need to assess how reliable this new data is - // compared to existing estimates. - - bool handicap_used = w->getKart(i)->getHandicap() || w->getKart(j)->getHandicap(); - double accuracy = computeDataAccuracy(player1_rd, player2_rd, player1_raw_scores, player2_raw_scores, player_count, handicap_used); - - // Now that we've computed the reliability value, - // we can proceed with computing the points gained or lost - - // Compute the result and race ranking importance - - double mode_factor = getModeFactor(); - - if (w->getKart(i)->isEliminated()) - { - // Recurring disconnects are punished through - // increased RD and higher RD floor, - // not through higher raw score loss - result = 0.0; - player1_time = player2_time * 1.2; // for getTimeSpread - } - else if (w->getKart(j)->isEliminated()) - { - result = 1.0; - player2_time = player1_time * 1.2; - } - else - { - result = computeH2HResult(player1_time, player2_time); - } - - max_time = std::min(MAX_SCALING_TIME, std::max(player1_time, player2_time)); - - ranking_importance = accuracy * mode_factor * scalingValueForTime(max_time); - - // Compute the expected result using an ELO-like function - diff = player2_raw_scores - player1_raw_scores; - - expected_result = 1.0/ (1.0 + std::pow(10.0, - diff / ( BASE_RANKING_POINTS / 2.0 - * getModeSpread() - * getTimeSpread(std::min(player1_time, player2_time))))); - - // Compute the ranking change - raw_scores_change[i] += ranking_importance * (result - expected_result); - - // We now update the rating deviation. The change - // depends on the current RD, on the result's accuracy, - // on how expected the result was (upsets can increase RD) - - // If there was a disconnect in this race, RD was handled once already - if (!w->getKart(i)->isEliminated()) { - // First the RD reduction based on accuracy and current RD - double rd_change_factor = accuracy * 0.0016; - double rd_change = (-1) * prev_rating_deviations[i] * rd_change_factor; - - // If the unexpected result happened, we add a RD increase - // TODO : more reliable would be accumulating an expected_result/result - // differential over time, weighted through relative RDs. - // If that differential goes high, then increase RD while decaying - // the differential. Some work needed to ensure sensible maths. - double upset = std::abs(result - expected_result); - if (upset > 0.5) - { - // Renormalize so expected result 50% is 1.0 and expected result 100% is 0.0 - upset = 2.0 - 2 * upset; - upset = std::max(0.02, upset); - - // If upsets happen at the rate predicted by expected score, - // this won't prevent the rating deviation from going down. - // However, if upsets are at least twice more frequent than expected, RD will go up. - rd_change += MIN_RATING_DEVIATION * rd_change_factor / upset; - } - - // Minimum RD will be handled after all iterative RD change have been done, - // so as to avoid the order in which player pairs are computed changing results. - new_rating_deviations[i] += rd_change; - } - } + RaceResultData entry; + entry.online_id = RaceManager::get()->getKartInfo(i).getOnlineId(); + entry.is_eliminated = w->getKart(i)->isEliminated(); + entry.time = RaceManager::get()->getKartRaceTime(i); + entry.handicap = w->getKart(i)->getHandicap(); + data.push_back(entry); } - // Don't merge it in the main loop as new_scores value are used there - for (unsigned i = 0; i < player_count; i++) - { - new_raw_scores[i] += raw_scores_change[i]; - const uint32_t id = RaceManager::get()->getKartInfo(i).getOnlineId(); - m_raw_scores.at(id) = new_raw_scores[i]; - - // Ensure RD doesn't go below the RD floor. - // The minimum RD is increased in case of repeated disconnects - double disconnects_floor = 0; - if (disconnects[i] >= 3) - { - int n = disconnects[i] - 3; - disconnects_floor = (disconnects[i]-2) * BASE_RD_PER_DISCONNECT - + VAR_RD_PER_DISCONNECT * (n * (n+1)) / 2; - } - new_rating_deviations[i] = std::max(new_rating_deviations[i], MIN_RATING_DEVIATION + disconnects_floor); - m_rating_deviations.at(id) = new_rating_deviations[i]; - - // Update the main public rating. At min RD, it is equal to the raw score. - m_scores.at(id) = m_raw_scores.at(id) - 3*new_rating_deviations[i] + 3*MIN_RATING_DEVIATION; - if (m_scores.at(id) > m_max_scores.at(id)) - m_max_scores.at(id) = m_scores.at(id); + for (int i = 0; i < 64; ++i) { + m_ranking->computeNewRankings(data, RaceManager::get()->isTimeTrialMode()); } // Used to display rating change at the end of a race + m_result_ns->addUInt8((uint8_t)player_count); for (unsigned i = 0; i < player_count; i++) { const uint32_t id = RaceManager::get()->getKartInfo(i).getOnlineId(); - double change = m_scores.at(id) - prev_scores[i]; + double change = m_ranking->getDelta(id); m_result_ns->addFloat((float)change); } } // computeNewRankings - - -//----------------------------------------------------------------------------- -/** Returns the mode race importance factor, - * used to make ranking move slower in more random modes. - */ -double ServerLobby::getModeFactor() -{ - if (RaceManager::get()->isTimeTrialMode()) - return 1.0; - return 0.75; -} // getModeFactor - -//----------------------------------------------------------------------------- -/** Returns the mode spread factor, used so that a similar difference in - * skill will result in a similar ranking difference in more random modes. - */ -double ServerLobby::getModeSpread() -{ - if (RaceManager::get()->isTimeTrialMode()) - return 1.0; - - //TODO: the value used here for normal races is a wild guess. - // When hard data to the spread tendencies of time-trial - // and normal mode becomes available, update this to make - // the spreads more comparable - return 1.25; -} // getModeSpread - -//----------------------------------------------------------------------------- -/** Returns the time spread factor. - * Short races are more random, so the expected result changes depending - * on race duration. - */ -double ServerLobby::getTimeSpread(double time) -{ - return sqrt(120.0 / time); -} // getTimeSpread - -//----------------------------------------------------------------------------- -/** Compute the scaling value of a given time - * This is linear to race duration, getTimeSpread takes care - * of expecting a more random result in shorter races. - */ -double ServerLobby::scalingValueForTime(double time) -{ - return time * BASE_POINTS_PER_SECOND; -} // scalingValueForTime - -//----------------------------------------------------------------------------- -/** Computes the score of a head-to-head minimatch. - * If time difference > 2,5% ; the result is 1 (complete win of player 1) - * or 0 (complete loss of player 1) - * Otherwise, it is averaged between 0 and 1. - */ -double ServerLobby::computeH2HResult(double player1_time, double player2_time) -{ - double max_time = std::max(player1_time, player2_time); - double min_time = std::min(player1_time, player2_time); - - double result = (max_time - min_time) / (min_time / 20.0); - result = std::min(1.0, 0.5 + result); - - if (player2_time <= player1_time) - result = 1.0 - result; - - return result; -} // computeH2HResult - -//----------------------------------------------------------------------------- -/** Computes a relative factor indicating how much informative value - * the new race result gives us. - * - * For a player with a high own rating deviation, the current rating is unreliable - * so any new data holds more importance. This is crucial to allow reasonably - * fast rating convergence of new players, provided they play accurately rated opponents. - * - * When the opponent has a high rating deviation, the expected scores are likely off. - * Therefore, the information from such a result is much less valuable. - * - * We also reduce rating changes when the player ratings are very different, even - * after considering the uncertainties from rating deviation. - * This is multi-purpose : - * - With a very high rating difference, random race events (very poor luck, disconnects) - * are very likely to be the cause of any upset, so the rate of legitimate upsets is - * unreliable. No rating method is safe. - * - Attempting to "farm" much lower rated players against which a practical 100% winrate - * may be reached (outside of random events) becomes very ineffective. Instead, - * to gain rating points, the player has incentive to play well-rated opponents. - * - The primary goal is to ensure that two players of equal rating would be about - * evenly matched in head-to-head. If two strong players each beat a much weaker third - * player, very little information is gained on how a direct head-to-head between the - * strong players would go. - * For the purposes of this rating computation, we assume that the informational value - * of a race is roughly proportional to the likelihood of the weaker player winning. - * We cap the effect so that losing to a much weaker player still costs rating points. - * - * In a race with many players, a single event can have a significant impact on the - * results of all the H2H. To avoid races with high players count having too strong - * rating swings, we apply a modifier scaling down accuracy. - * - * Finally, while handicap is allowed in ranked races and a rating offset is applied - * to keep expected results realistic (without incentivizing playing handicap-only), - * the results of such races are much less reliable. - */ -double ServerLobby::computeDataAccuracy(double player1_rd, double player2_rd, double player1_scores, double player2_scores, int player_count, bool handicap_used) -{ - double accuracy = player1_rd / (sqrt(player2_rd) * sqrt(MIN_RATING_DEVIATION)); - - double strong_lowerbound = (player1_scores > player2_scores) ? player1_scores - 3 * player1_rd - : player2_scores - 3 * player2_rd; - double weak_upperbound = (player1_scores > player2_scores) ? player2_scores + 3 * player2_rd - : player1_scores + 3 * player1_rd; - - if (weak_upperbound < strong_lowerbound) - { - double diff = strong_lowerbound - weak_upperbound; - diff = diff / (BASE_RANKING_POINTS / 2.0); - - // The expected result is that of the weaker player and is between 0 and 0.5 - double expected_result = 1.0/ (1.0 + std::pow(10.0, diff)); - expected_result = std::max(0.2, sqrt(2*expected_result)); - - accuracy *= expected_result; - } - - // Reduce the importance of single h2h in a race with many players. - // The overall impact of a race with more players is still always bigger. - double player_count_modifier = 2.0 / sqrt((double) player_count); - accuracy *= player_count_modifier; - - // Races with handicap are unreliable for ranking - if (handicap_used) - accuracy *= 0.25; - - return accuracy; -} - //----------------------------------------------------------------------------- /** Called when a client disconnects. * \param event The disconnect event. @@ -2756,29 +2427,6 @@ void ServerLobby::clientDisconnected(Event* event) #endif } // clientDisconnected -//----------------------------------------------------------------------------- -void ServerLobby::clearDisconnectedRankedPlayer() -{ - for (auto it = m_ranked_players.begin(); it != m_ranked_players.end();) - { - if (it->second.expired()) - { - const uint32_t id = it->first; - m_scores.erase(id); - m_max_scores.erase(id); - m_num_ranked_races.erase(id); - m_raw_scores.erase(id); - m_rating_deviations.erase(id); - m_num_ranked_disconnects.erase(id); - it = m_ranked_players.erase(it); - } - else - { - it++; - } - } -} // clearDisconnectedRankedPlayer - //----------------------------------------------------------------------------- void ServerLobby::kickPlayerWithReason(STKPeer* peer, const char* reason) const { @@ -3904,42 +3552,17 @@ void ServerLobby::getRankingForPlayer(std::shared_ptr p) const XMLNode* result = request->getXMLData(); std::string rec_success; - // Default result - double raw_score = BASE_RANKING_POINTS; - double score = BASE_RANKING_POINTS - 3*BASE_RATING_DEVIATION + 3*MIN_RATING_DEVIATION; - double max_score = BASE_RANKING_POINTS - 3*BASE_RATING_DEVIATION + 3*MIN_RATING_DEVIATION; - unsigned num_races = 0; - double rating_deviation = BASE_RATING_DEVIATION; - uint64_t disconnects = 0; + bool success = false; if (result->get("success", &rec_success)) - { if (rec_success == "yes") - { - result->get("scores", &score); - result->get("max-scores", &max_score); - result->get("num-races-done", &num_races); - result->get("raw-scores", &raw_score); - result->get("rating-deviation", &rating_deviation); - result->get("disconnects", &disconnects); - } - else - { - Log::error("ServerLobby", "No ranking info found for player %s.", - StringUtils::wideToUtf8(p->getName()).c_str()); - // Kick the player to avoid his score being reset in case - // connection to stk addons is broken - auto peer = p->getPeer(); - if (peer) - { - peer->kick(); - return; - } - } - } - else + success = true; + + if (!success) { Log::error("ServerLobby", "No ranking info found for player %s.", StringUtils::wideToUtf8(p->getName()).c_str()); + // Kick the player to avoid his score being reset in case + // connection to stk addons is broken auto peer = p->getPeer(); if (peer) { @@ -3947,13 +3570,7 @@ void ServerLobby::getRankingForPlayer(std::shared_ptr p) return; } } - m_ranked_players[id] = p; - m_scores[id] = score; - m_max_scores[id] = max_score; - m_num_ranked_races[id] = num_races; - m_raw_scores[id] = raw_score; - m_rating_deviations[id] = rating_deviation; - m_num_ranked_disconnects[id] = disconnects; + m_ranking->fill(id, result, p); } // getRankingForPlayer //----------------------------------------------------------------------------- @@ -3966,16 +3583,14 @@ void ServerLobby::submitRankingsToAddons() for (unsigned i = 0; i < RaceManager::get()->getNumPlayers(); i++) { const uint32_t id = RaceManager::get()->getKartInfo(i).getOnlineId(); + const RankingEntry& scores = m_ranking->getScores(id); auto request = std::make_shared - (id, m_scores.at(id), m_max_scores.at(id), - m_num_ranked_races.at(id), m_raw_scores.at(id), - m_rating_deviations.at(id), m_num_ranked_disconnects.at(id), - RaceManager::get()->getKartInfo(i).getCountryCode()); + (scores, RaceManager::get()->getKartInfo(i).getCountryCode()); NetworkConfig::get()->setUserDetails(request, "submit-ranking"); - Log::info("ServerLobby", "Submiting ranking for %s (%d) : %lf, %lf %d", + Log::info("ServerLobby", "Submitting ranking for %s (%d) : %lf, %lf %d", StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(i).getPlayerName()).c_str(), id, - m_scores.at(id), m_max_scores.at(id), m_num_ranked_races.at(id)); + scores.score, scores.max_score, scores.races); request->queue(); } } // submitRankingsToAddons @@ -4086,10 +3701,7 @@ void ServerLobby::addWaitingPlayersToGame() } } uint32_t online_id = profile->getOnlineId(); - if (ServerConfig::m_ranked && - (m_ranked_players.find(online_id) == m_ranked_players.end() || - (m_ranked_players.find(online_id) != m_ranked_players.end() && - m_ranked_players.at(online_id).expired()))) + if (ServerConfig::m_ranked && !m_ranking->has(online_id)) { getRankingForPlayer(peer->getPlayerProfiles()[0]); } @@ -4441,12 +4053,9 @@ void ServerLobby::handlePlayerDisconnection() const // Real score will be submitted later in computeNewRankings const uint32_t id = RaceManager::get()->getKartInfo(i).getOnlineId(); - unsigned num_races = m_num_ranked_races.at(id); - uint64_t disconnects = m_num_ranked_disconnects.at(id) << 1; + RankingEntry penalized = m_ranking->getTemporaryPenalizedScores(id); auto request = std::make_shared - (id, m_scores.at(id) - 200.0, m_max_scores.at(id), - ++num_races, m_raw_scores.at(id) - 200.0, - m_rating_deviations.at(id), ++disconnects, + (penalized, RaceManager::get()->getKartInfo(i).getCountryCode()); NetworkConfig::get()->setUserDetails(request, "submit-ranking"); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index fc18cfeca43..0c5998eeb9b 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -41,6 +41,7 @@ class NetworkString; class NetworkPlayerProfile; class STKPeer; class SocketAddress; +class Ranking; namespace Online { @@ -154,39 +155,7 @@ class ServerLobby : public LobbyProtocol std::map m_pending_peer_connection; - /* Ranking related variables */ - // If updating the base points, update the base points distribution in DB - const double BASE_RANKING_POINTS = 4000.0; // Given to a new player on 1st connection to a ranked server - const double BASE_RATING_DEVIATION = 1000.0; // Given to a new player on 1st connection to a ranked server - const double MIN_RATING_DEVIATION = 100.0; // A server cron job makes RD go up if a player is inactive - const double BASE_RD_PER_DISCONNECT = 15.0; - const double VAR_RD_PER_DISCONNECT = 3.0; - const double MAX_SCALING_TIME = 360.0; - const double BASE_POINTS_PER_SECOND = 0.18; - const double HANDICAP_OFFSET = 2000.0; - - /** Online id to profile map, handling disconnection in ranked server */ - std::map > m_ranked_players; - - /** Multi-session rating for each current player */ - std::map m_raw_scores; - - /** The rating uncertainty for each current player */ - std::map m_rating_deviations; - - /** A single number compounding "raw score" and RD, - * for rating display to players and rankings */ - std::map m_scores; - - /** The maximum rating obtained for each current player. - * This is based on m_scores, not m_raw_scores */ - std::map m_max_scores; - - /** Number of disconnects in the previous 64 ranked races for each current players */ - std::map m_num_ranked_disconnects; - - /** Number of ranked races done for each current players */ - std::map m_num_ranked_races; + std::shared_ptr m_ranking; /* Saved the last game result */ NetworkString* m_result_ns; @@ -306,16 +275,6 @@ class ServerLobby : public LobbyProtocol void getRankingForPlayer(std::shared_ptr p); void submitRankingsToAddons(); void computeNewRankings(); - void clearDisconnectedRankedPlayer(); - double getModeFactor(); - double getModeSpread(); - double getTimeSpread(double time); - double getUncertaintySpread(uint32_t online_id); - double scalingValueForTime(double time); - double computeH2HResult(double player1_time, double player2_time); - double computeDataAccuracy(double player1_rd, double player2_rd, - double player1_scores, double player2_scores, - int player_count, bool handicap_used); void checkRaceFinished(); void getHitCaptureLimit(); void configPeersStartTime(); From 800c4421148855ba50aad7b53ba5851d6dc797f7 Mon Sep 17 00:00:00 2001 From: FifthTundraG <117035030+FifthTundraG@users.noreply.github.com> Date: Thu, 19 Dec 2024 08:51:35 -0500 Subject: [PATCH 507/830] Add Arch install instructions and fix typos in INSTALL.md (#5217) --- INSTALL.md | 58 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 6e8c4be8d11..abad7088c56 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -26,6 +26,15 @@ To build SuperTuxKart from source, you'll need to install the following packages * jpeg (libjpeg-turbo-devel) * SDL2 (libsdl2-devel) +Debian-based Distributions command: + +```bash +sudo apt-get install build-essential cmake libbluetooth-dev libsdl2-dev \ +libcurl4-openssl-dev libenet-dev libfreetype6-dev libharfbuzz-dev \ +libjpeg-dev libogg-dev libopenal-dev libpng-dev \ +libssl-dev libvorbis-dev libmbedtls-dev pkg-config zlib1g-dev +``` + Fedora command: ```bash @@ -39,13 +48,12 @@ libogg-devel openssl-devel pkgconf \ wiiuse-devel zlib-devel ``` -Mageia 6 command: +Arch-based Distributions command: ```bash -su -c 'urpmi gcc-c++ cmake openssl-devel libcurl-devel freetype-devel harfbuzz-devel \ -libjpeg-turbo-devel libogg-devel openal-soft-devel SDL2-devel \ -libpng-devel libvorbis-devel nettle-devel zlib-devel git subversion \ -libbluez-devel libfreetype6-devel +sudo pacman -S openal libogg libvorbis freetype2 harfbuzz curl \ +bluez-libs openssl libpng zlib libjpeg-turbo sdl2 gcc cmake \ +pkgconf make git subversion ``` openSUSE command: @@ -57,13 +65,13 @@ libvorbis-devel pkgconf zlib-devel enet-devel \ libjpeg-devel bluez-devel freetype2-devel ``` -Debian-based Distributions command: +Mageia 6 command: ```bash -sudo apt-get install build-essential cmake libbluetooth-dev libsdl2-dev \ -libcurl4-openssl-dev libenet-dev libfreetype6-dev libharfbuzz-dev \ -libjpeg-dev libogg-dev libopenal-dev libpng-dev \ -libssl-dev libvorbis-dev libmbedtls-dev pkg-config zlib1g-dev +su -c 'urpmi gcc-c++ cmake openssl-devel libcurl-devel freetype-devel harfbuzz-devel \ +libjpeg-turbo-devel libogg-devel openal-soft-devel SDL2-devel \ +libpng-devel libvorbis-devel nettle-devel zlib-devel git subversion \ +libbluez-devel libfreetype6-devel ``` Solus command: @@ -73,19 +81,19 @@ harfbuzz-devel curl-devel bluez-devel openssl-devel libpng-devel zlib-devel \ libjpeg-turbo-devel sdl2-devel enet-devel libjpeg-turbo-devel bluez-devel curl-devel ``` -### In-game recorder +#### In-game recorder To build the in-game recorder for STK, you have to install `libopenglrecorder` from your distribution, or compile it yourself from [here](https://github.com/Benau/libopenglrecorder). Compilation instruction is explained there. If you don't need this feature, pass `-DBUILD_RECORDER=off` to CMake. -### Shaderc for Vulkan support +#### Shaderc for Vulkan support You need to compile [Shaderc](https://github.com/google/shaderc) for Vulkan support in SuperTuxKart if you are not building for Windows or macOS. If you don't need this feature, pass `-DNO_SHADERC=on` to CMake. ### Compiling -To compile SuperTuxKart, run the following commands inside the `stk-code` directory +To compile SuperTuxKart, run the following commands inside the `stk-code` directory: ```bash # go into the stk-code directory @@ -102,7 +110,7 @@ cmake .. make -j$(nproc) ``` -STK can then be run from the build directory with `bin/supertuxkart` +STK can then be run from the build directory with `bin/supertuxkart`. #### Keeping your build up to date @@ -115,11 +123,11 @@ cmake .. make -j$(nproc) ``` -##### Build Speed Optimization +#### Build Speed Optimization -"-j$(nproc)" is an example, for a faster build, use "-jx" instead, where "x" is the amount of CPU threads you have, minus one. +The `-j$(nproc)` option is an example. For a faster build, use `-jx` instead, where "x" is the amount of CPU threads you have, minus one. -### Further options +#### Further options To create a debug version of STK, run: @@ -134,21 +142,21 @@ sudo make install ``` The default install location is `/usr/local`, i.e. the data files will -be written to `/usr/local/share/games/supertuxkart`, the executable +be written to `/usr/local/share/games/supertuxkart` and the executable will be copied to `/usr/local/bin`. To change the default installation location, specify `CMAKE_INSTALL_PREFIX` when running CMake, e.g.: -`cmake .. -DCMAKE_INSTALL_PREFIX=/opt/stk` +`cmake .. -DCMAKE_INSTALL_PREFIX=/opt/stk`. ## Building SuperTuxKart on Windows -To Build SuperTuxKart on Windows follow these instructions: +To Build SuperTuxKart on Windows, follow these instructions: 1. Download and install Visual Studio from here: [Visual Studio - Download](https://www.visualstudio.com/downloads/). The free Visual Studio Community edition works fine. Remember to select "Desktop development with C++" in the installer. -2. If you want the stable version, download the SuperTuxKart source package from the latest stable version [SuperTuxKart on GitHub](https://github.com/supertuxkart/stk-code/releases) and unpack it. +2. If you want the stable version, download the SuperTuxKart source package from the latest stable version of [SuperTuxKart on GitHub](https://github.com/supertuxkart/stk-code/releases) and unpack it. 3. If you want the development version, you will need a Git client and an SVN client. More information can be found here: [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control). -Open your file browser and find somewhere you want to put the development version of SuperTuxKart. For example in C:\Users\ as the Git and SVN clients will have write permissions there, and you should create its own directory, for example SuperTuxKart-dev. Enter that directory, and create a directory inside called stk-assets, and enter it. If you installed TortoiseSVN, right-click, select TortoiseSVN -> Checkout... and paste the corresponding URL found in [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control). While it is downloading the game assets, go back to your file browser and one level up. Right-click again somewhere empty and select "Git clone..." and paste the corresponding link found in [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control). +Open your file browser and find somewhere you want to put the development version of SuperTuxKart. For example in C:\\Users\\\ as the Git and SVN clients will have write permissions there, and you should create its own directory, for example "SuperTuxKart-dev". Enter that directory, and create a directory inside called "stk-assets", and enter it. If you installed TortoiseSVN, right-click, select TortoiseSVN -> Checkout... and paste the corresponding URL found in [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control). While it is downloading the game assets, go back to your file browser and move one level up (if you followed the example that directory would be named "SuperTuxKart-dev"). Right-click again somewhere empty and select "Git clone..." and paste the corresponding link found in [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control). *Note: Both `stk-code` and `stk-assets` **must** be in the same directory, otherwise the build will likely fail!* 4. If you got the stable version, download the Windows dependencies package from [SuperTuxKart on GitHub - Dependencies Releases](https://github.com/supertuxkart/dependencies/releases), find the stk-code version there and download the `dependencies(arch).zip` as needed and unpack the archive into the `stk-code` directory. @@ -204,7 +212,7 @@ and unpack the archive into the `stk-code` directory. Download `i686` if you use msbuild.exe SuperTuxKart.sln ``` -SuperTuxKart can now be run as `bin\Debug\supertuxkart.exe` or `bin\Release\supertuxkart.exe` +SuperTuxKart can now be run as `bin\Debug\supertuxkart.exe` or `bin\Release\supertuxkart.exe`. ## Building SuperTuxKart on Windows using LLVM MinGW @@ -250,7 +258,7 @@ Install the developer tools, either from the OS X Install DVD or from Apple's we Download `dependencies-macosx.tar.xz` from the `Assets` section [here](https://github.com/supertuxkart/dependencies/releases) and extract it inside the `stk-code` directory, use the `preview` version for git stk-code. -Build STK +Build STK: ```bash cd /path/to/stk-code @@ -270,6 +278,6 @@ By default, the executable that is produced is not ready for distribution. Insta dylibbundler -od -b -x ./bin/SuperTuxKart.app/Contents/MacOS/supertuxkart -d ./bin/SuperTuxKart.app/Contents/libs/ -p @executable_path/../libs/ -s ../dependencies-macosx/lib ``` -Add `-ns` to disable ad-hoc codesigning +Add `-ns` to disable ad-hoc codesigning. Afterwards, copy the contents of `stk-assets` into `/SuperTuxKart.app/Contents/Resources/data`. From 252058cc78fb0f8e3ed7b03402adcc90565443e0 Mon Sep 17 00:00:00 2001 From: Alayan-stk-2 Date: Fri, 20 Dec 2024 17:14:36 +0100 Subject: [PATCH 508/830] Fully update the Changelog - Add the items that were missing in the 1.4 changelog - Update the 1.5 changelog with recent changes and a few that were missing - Try to improve clarity for multiple 1.5 entries --- CHANGELOG.md | 82 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85b66143275..bc0997b1264 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,28 +5,37 @@ It should be kept in mind that some versions have a less complete changelog than For similar reasons, and because some features are vastly more complex than others, attributions of main changes should not be taken as a shortcut for overall contribution. -## SuperTuxKart 1.5 Beta1 +## SuperTuxKart 1.5 ### Networking -* Improve track-voting logic when no majority is achieved, by kimden -* Prevent selectable addons to be removed by spectators, by kimden +* Improve the track-voting logic when no majority is achieved, by kimden +* Prevent tracks missed by spectators from limiting the choice of active players, by kimden * Make bot indices start from one, by JipFr -* Various bugfixes and code-quality improvements, by kimden +* Various bugfixes, by kimden + +### Gameplay +* Fix start positions for negative sideward distances, by kimden +* Make the rescue bird place the kart towards the ball in soccer mode, by Snoker101 ### General +* Make the game's window resizable in all menu screens, by Benau and CodingJellyfish * New benchmark mode, by Alayan: - Can be run with a few clicks, allowing to easily test the performance of various settings or to compare different systems - Robust performance metrics that better reflect the impact of varying frametimes than Average FPS and 1% Lows. -* Add benchmark mode to commandline options, by ektor5 -* Implement blog announcement system in Online screen, by CodingJellyfish +- Results are displayed along the active graphics settings, and detailed results can be saved to file +* Add the benchmark mode to commandline options, by ektor5 +* Fix incorrect unlock information in Story Mode after a Grand Prix, by CodingJellyfish * Make the progression of audio levels geometrical and increase default steps, allowing to set lower audio levels and better accuracy for low audio levels (especially useful for headphone users), by Alayan * Fix drive-on sound from materials being played when the game is paused, by Alayan +* Fix incorrect unlock information in Story Mode after a Grand Prix, by CodingJellyfish * Fix a crash trying to read replays when the random starting position setting is enabled, by Alayan -* Enable smooth scrolling for Irrlicht, by CodingJellyfish * Handle track names with spaces in the replay reader, by Alayan +* Enable smooth scrolling for Irrlicht, by CodingJellyfish * Add launchable tag and use rDNS format for AppData file, by AsciiWolf * Various build system updates, by deveee, tobbi, ognevny and others * Various compiler fixes, by heirecka, limburgher, nyllet and others +* Substantial changes improving code quality, by Alayan and kimden +* Update Wiiuse library to 0.15.6, SIMD-e to 0.8.2, MojoAL to latest (a9e2f30) * Various tweaks, bugfixes and code-quality improvements ### Graphics @@ -34,35 +43,39 @@ For similar reasons, and because some features are vastly more complex than othe * Add more maximum framerate options to the built-in framerate limiter, by Benau * Add some graphical effects for legacy video drivers, by Benau * Replace inaccurate normal compression algorithm with Octahedron Normal Vector, by CodingJellyfish -* Guarantee 2048 overall bone limit for skinned mesh, by CodingJellyfish -* Improve Cascaded Shadow Mapping, by CodingJellyfish * Fix incorrect Screen-Space Reflection shader, by CodingJellyfish -* Various improvements to the automatic computations of Level of Detail (LoD) distances, by Alayan +* Guarantee an overall bone limit of 2048 for skinned mesh (up from 1024), by CodingJellyfish +* Improve Cascaded Shadow Mapping, by CodingJellyfish * Improve the performance of scene node iteration, by CodingJellyfish +* Various improvements to the automatic computations of Level of Detail (LoD) distances, by Alayan * Enable new higher LoD and shadows settings, by Alayan -* Integrate LoD (Geometry Detail) settings in the graphics presets, by Alayan +* Integrate LoD (Geometry Detail) settings in the graphics presets, and add a 7th graphics preset, by Alayan * Prefer displaying a lower quality LoD model over switching to a higher quality one when too close, by Alayan +* Remove the distance limit on the display of on-track items (such as gift boxes), by Alayan +* Improve image quality on low and medium presets with better anisotropic filtering, by Alayan * Various bugfixes and improvements, by zmike, Icenowy and others ### User Interface -* Make the game window resizable in all UI screens, by Benau and CodingJellyfish -* Use separated "base theme" and "skin variant" values for skin configuration, by Alayan -* Add some skin variants for Classic and Cartoon base theme, by Alayan -* Add a new Display tab in the Settings, by Alayan -* Add help information for Lap Trial mode, by searinminecraft -* Allow to rate addons with a keyboard or a controller, by CodingJellyfish * Allow users to select favorite karts/tracks/arenas, by Alayan and CodingJellyfish +* Five new skin variants for Cartoon, and a new Desert skin variant for Classic, by Alayan and CrystalDaEevee +* Improve the skin selection UX by separating "base theme" and "skin variant" selection, by Alayan +* Add a new Display tab in the Settings, by Alayan * Allow users to search karts/arenas, by CodingJellyfish * Allow users to group karts by kart classes, by CodingJellyfish +* Allow to rate addons with a keyboard or a controller, and notify when trying to rate an addon while not logged in, by CodingJellyfish * Improve the typing bars, especially for the coal theme, by Alayan -* Various UI layout improvements, by CodingJellyfish +* Implement a blog announcement system in the Online screen, by CodingJellyfish +* Various UI layout improvements (especially for 'tall' resolutions), by CodingJellyfish * Generate higher resolution texture for scalable fonts, by CodingJellyfish -* Show score with color on the center of speedometer in battles, by CodingJellyfish * Various enhancements, by QwertyChouskie, Nomagno, Nstelt and others +#### In-race UI +* Add color and sound indicators when an elimination is about to happen in Follow-The-Leader, by Alayan +* Correctly display the remaining time in FtL when extra-time is added, by Alayan +* Show score with color on the center of speedometer in battles, by CodingJellyfish +* Display correctly themed attachment icons if the base theme has been changed before the last restart, by CodingJellyfish + ### Tracks and modeling -* Fix start positions for negative sidewards distance, by kimden -* Make the rescue bird place the kart towards the ball in soccer mode, by Snoker101 * New music for Las Dunas Arena/Las Dunas Soccer, by ALBatross * Update Godette face texture, by ZAQraven99 * Fix Northern Resort skybox, by CrystalDaEevee @@ -73,19 +86,26 @@ For similar reasons, and because some features are vastly more complex than othe ## SuperTuxKart 1.4 (31. October 2022) ### General -* Lap trial mode, by mrkubax10 -* Fix parachute powerup, by heuchi -* Fix gyroscope on walldriving surface, by Benau * Enable ARMv7 build for Windows, by Benau * Restore macOS <= 10.14 support, by Benau +* Allow setting the auto-center behavior of steering wheels, by Mstrodl +* Simplify making derivative UI skins by allowing to specify a base theme, by qwertychouskie +* Make sure old save data is only removed after new save data is written, to avoid data losses on full drives, by Benau +* Fixed camera rotation when using the gyroscope and driving on vertical surfaces, by Benau +* Lap trial mode, by mrkubax10 +* Fix a parachute powerup bug, whereby karts behind the user would still lose their shield, by heuchi +* Add an option to randomize the player starting position, by Iwoithe * Avoid triggering other goal lines when the goal is already scored, by kimden +* And some other minor bugfixes and enhancements too small or specific to be detailed ### Graphics -* Items and stars animation, by Semphris +* Beta Vulkan renderer, by Benau +* Add an animation to the stars displayed after a kart gets hit, by Semphris +* Add intuitive animations for the respawn of on-track items (such as gift boxes), by Semphris * LOD optimization, by Benau * Implement HiDPI support in SDL2 properly, by Benau -* Beta Vulkan renderer, by Benau -* Make sky particle always fall vertically, by Benau +* Increase the use of on-demand loading for textures, by Benau +* Make sky particle always fall vertically (instead of perpendicularly to the player camera), by Benau ### Tracks and modeling * Updated Konqi, by ZAQraven99 @@ -98,12 +118,14 @@ For similar reasons, and because some features are vastly more complex than othe * Balanced starting positions in all official soccer fields, by CrystalDaEevee ### Networking -* Add track searching to network track screen, by Benau -* Make limit of players in game configurable, by Waldlaubsaengernest +* Make the in-server and in-game player limits independent, allowing extra slots for spectators, by Waldlaubsaengernest * Allow using real addon karts (same hitbox and kart type as in local game), by Benau +* Sort the server list by number of real players in servers (ignoring AIs), by Benau ### User Interface -* Add left side ghost replay difficulties, by ldoyenard +* Display per-kart difficulty in the end-screen for replays, by ldoyenard +* Add track searching to the network track screen, by Benau +* Minor enhancements and fixes in the end race screen ## SuperTuxKart 1.3 (28. September 2021) ### Networking From 7e34f604f805348ae2b82c992b2b299ee6d616e4 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sat, 21 Dec 2024 17:08:16 +0100 Subject: [PATCH 509/830] Fix #5173 Do not modify the max-players-in-game parameter to interpret it in server_config.cpp, instead do the interpretation in server_lobby.cpp The issue was caused by the modified parameter being then saved in the XML, causing issues later on. This commit also addresses a similar issue with the min-start-game-players parameter --- src/network/protocols/server_lobby.cpp | 18 ++++++++++++++---- src/network/server_config.cpp | 8 ++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 624534b1282..30659b051a1 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -874,9 +874,14 @@ void ServerLobby::asynchronousUpdate() { if (ServerConfig::m_owner_less) { + // Ensure that a game can auto-start if the server meets the config's starting limit or if it's already full. + int starting_limit = std::min((int)ServerConfig::m_min_start_game_players, (int)ServerConfig::m_server_max_players); + if (ServerConfig::m_max_players_in_game > 0) // 0 here means it's not the limit + starting_limit = std::min(starting_limit, (int)ServerConfig::m_max_players_in_game); + unsigned players = 0; STKHost::get()->updatePlayers(&players); - if (((int)players >= ServerConfig::m_min_start_game_players || + if (((int)players >= starting_limit || m_game_setup->isGrandPrixStarted()) && m_timeout.load() == std::numeric_limits::max()) { @@ -884,7 +889,7 @@ void ServerLobby::asynchronousUpdate() (int64_t) (ServerConfig::m_start_game_counter * 1000.0f)); } - else if ((int)players < ServerConfig::m_min_start_game_players && + else if ((int)players < starting_limit && !m_game_setup->isGrandPrixStarted()) { resetPeersReady(); @@ -894,7 +899,7 @@ void ServerLobby::asynchronousUpdate() } if (m_timeout.load() < (int64_t)StkTime::getMonoTimeMs() || (checkPeersReady(true/*ignore_ai_peer*/) && - (int)players >= ServerConfig::m_min_start_game_players)) + (int)players >= starting_limit)) { resetPeersReady(); startSelection(); @@ -4355,7 +4360,12 @@ std::set> ServerLobby::getSpectatorsByLimit() auto peers = STKHost::get()->getPeers(); std::set> always_spectate_peers; - unsigned player_limit = ServerConfig::m_max_players_in_game; + unsigned player_limit = ServerConfig::m_server_max_players; + // If the server has an in-game player limit lower than the lobby limit, apply it, + // A value of 0 for this parameter means no limit. + if (ServerConfig::m_max_players_in_game > 0) + player_limit = std::min(player_limit, (unsigned)ServerConfig::m_max_players_in_game); + // only 10 players allowed for battle or soccer if (RaceManager::get()->isBattleMode() || RaceManager::get()->isSoccerMode()) player_limit = std::min(player_limit, 10u); diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 5d22927a1ff..c58bfe63905 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -341,8 +341,10 @@ void loadServerLobbyFromConfig() m_server_max_players > 10) m_server_max_players = 10; - m_max_players_in_game = (m_max_players_in_game <= 0) ? m_server_max_players : - std::min(m_max_players_in_game, m_server_max_players); + // Parameters should only be sanity checked, not modified for interpretation (see #5173). + // A parameter of 0 here means no limit is to be applied. + if (m_max_players_in_game < 0) + m_max_players_in_game = 0; if (m_ipv6_connection) { @@ -360,8 +362,6 @@ void loadServerLobbyFromConfig() } if (m_owner_less) { - if (m_min_start_game_players > m_max_players_in_game) - m_min_start_game_players = 1; if (!m_live_players) m_team_choosing = false; m_server_configurable = false; From 9f4a190245f94df7feb322059672e501b48a5ce1 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sat, 21 Dec 2024 18:40:56 +0100 Subject: [PATCH 510/830] Disable unusable in-game option tabs (fix #5163) --- src/states_screens/options/options_common.cpp | 15 +++++++++++++++ src/states_screens/options/options_common.hpp | 1 + .../options/options_screen_audio.cpp | 3 ++- .../options/options_screen_device.cpp | 6 +++--- .../options/options_screen_display.cpp | 2 ++ .../options/options_screen_general.cpp | 2 ++ .../options/options_screen_input.cpp | 2 ++ src/states_screens/options/options_screen_ui.cpp | 1 + .../options/options_screen_video.cpp | 2 ++ 9 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/states_screens/options/options_common.cpp b/src/states_screens/options/options_common.cpp index d134301ba26..104fedc09ed 100644 --- a/src/states_screens/options/options_common.cpp +++ b/src/states_screens/options/options_common.cpp @@ -43,4 +43,19 @@ namespace OptionsCommon if(screen) StateManager::get()->replaceTopMostScreen(screen); } + + // In the in-game pause options, disable the players and language tabs + void setTabStatus() + { + if (StateManager::get()->getGameState() == GUIEngine::INGAME_MENU) + { + GUIEngine::getWidget("tab_players")->setActive(false); + GUIEngine::getWidget("tab_language")->setActive(false); + } + else + { + GUIEngine::getWidget("tab_players")->setActive(true); + GUIEngine::getWidget("tab_language")->setActive(true); + } + } // setTabStatus } \ No newline at end of file diff --git a/src/states_screens/options/options_common.hpp b/src/states_screens/options/options_common.hpp index 9bafe3e26c3..9a618f06070 100644 --- a/src/states_screens/options/options_common.hpp +++ b/src/states_screens/options/options_common.hpp @@ -52,6 +52,7 @@ namespace OptionsCommon { void switchTab(std::string selected_tab); + void setTabStatus(); } #endif \ No newline at end of file diff --git a/src/states_screens/options/options_screen_audio.cpp b/src/states_screens/options/options_screen_audio.cpp index 0bcad71bfc4..97174de5d00 100644 --- a/src/states_screens/options/options_screen_audio.cpp +++ b/src/states_screens/options/options_screen_audio.cpp @@ -41,6 +41,8 @@ void OptionsScreenAudio::loadedFromFile() void OptionsScreenAudio::init() { Screen::init(); + OptionsCommon::setTabStatus(); + RibbonWidget* ribbon = this->getWidget("options_choice"); assert(ribbon != NULL); ribbon->setFocusForPlayer(PLAYER_ID_GAME_MASTER); @@ -70,7 +72,6 @@ void OptionsScreenAudio::init() getWidget("sfx_volume")->setActive(false); if(!UserConfigParams::m_music) getWidget("music_volume")->setActive(false); - } // init // ----------------------------------------------------------------------------- diff --git a/src/states_screens/options/options_screen_device.cpp b/src/states_screens/options/options_screen_device.cpp index 209f21113be..7f0fbd32cab 100644 --- a/src/states_screens/options/options_screen_device.cpp +++ b/src/states_screens/options/options_screen_device.cpp @@ -63,6 +63,8 @@ void OptionsScreenDevice::beforeAddingWidget() void OptionsScreenDevice::init() { Screen::init(); + OptionsCommon::setTabStatus(); + RibbonWidget* tabBar = getWidget("options_choice"); assert(tabBar != NULL); // Focus is set to the actions list later in the init @@ -182,9 +184,7 @@ void OptionsScreenDevice::init() actions->setSelectionID(0); // Disable deleting or disabling configuration mid-race - bool in_game = StateManager::get()->getGameState() == GUIEngine::INGAME_MENU; - - if (in_game) + if (StateManager::get()->getGameState() == GUIEngine::INGAME_MENU) { delete_button->setActive(false); disable_toggle->setActive(false); diff --git a/src/states_screens/options/options_screen_display.cpp b/src/states_screens/options/options_screen_display.cpp index 68f1bc81434..09148348eda 100644 --- a/src/states_screens/options/options_screen_display.cpp +++ b/src/states_screens/options/options_screen_display.cpp @@ -66,6 +66,8 @@ void OptionsScreenDisplay::loadedFromFile() void OptionsScreenDisplay::init() { Screen::init(); + OptionsCommon::setTabStatus(); + RibbonWidget* ribbon = getWidget("options_choice"); assert(ribbon != NULL); ribbon->setFocusForPlayer(PLAYER_ID_GAME_MASTER); diff --git a/src/states_screens/options/options_screen_general.cpp b/src/states_screens/options/options_screen_general.cpp index 1dca1dc2cb5..b83e7c4b1cf 100644 --- a/src/states_screens/options/options_screen_general.cpp +++ b/src/states_screens/options/options_screen_general.cpp @@ -72,6 +72,8 @@ void OptionsScreenGeneral::init() assert( show_login!= NULL ); show_login->setState( UserConfigParams::m_always_show_login_screen); + OptionsCommon::setTabStatus(); + #ifdef MOBILE_STK if (ExtractMobileAssets::hasFullAssets()) { diff --git a/src/states_screens/options/options_screen_input.cpp b/src/states_screens/options/options_screen_input.cpp index 15289a5ea67..b58a50744ff 100644 --- a/src/states_screens/options/options_screen_input.cpp +++ b/src/states_screens/options/options_screen_input.cpp @@ -154,6 +154,8 @@ void OptionsScreenInput::buildDeviceList() void OptionsScreenInput::init() { Screen::init(); + OptionsCommon::setTabStatus(); + RibbonWidget* tabBar = this->getWidget("options_choice"); assert(tabBar != NULL); tabBar->setFocusForPlayer(PLAYER_ID_GAME_MASTER); diff --git a/src/states_screens/options/options_screen_ui.cpp b/src/states_screens/options/options_screen_ui.cpp index de9ee66b39e..6caa85f3df8 100644 --- a/src/states_screens/options/options_screen_ui.cpp +++ b/src/states_screens/options/options_screen_ui.cpp @@ -148,6 +148,7 @@ void OptionsScreenUI::loadedFromFile() void OptionsScreenUI::init() { Screen::init(); + OptionsCommon::setTabStatus(); bool in_game = StateManager::get()->getGameState() == GUIEngine::INGAME_MENU; diff --git a/src/states_screens/options/options_screen_video.cpp b/src/states_screens/options/options_screen_video.cpp index 98807468938..3cfa5db2910 100644 --- a/src/states_screens/options/options_screen_video.cpp +++ b/src/states_screens/options/options_screen_video.cpp @@ -230,6 +230,8 @@ void OptionsScreenVideo::loadedFromFile() void OptionsScreenVideo::init() { Screen::init(); + OptionsCommon::setTabStatus(); + m_prev_adv_pipline = UserConfigParams::m_dynamic_lights; m_prev_img_quality = getImageQuality(); RibbonWidget* ribbon = getWidget("options_choice"); From 4a479ed6f507dd06e2a995df19f4aaf8debe5d5b Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sun, 22 Dec 2024 17:53:47 +0100 Subject: [PATCH 511/830] Improvements in the last lap music transition - Group up the code to trigger the fast music and the last lap SFX in the same area - Remove all the code meant to play a music at higher pitch, it was unused and would have been annoying if it was. - Apply the 'last lap SFX' reduced music volume when switching between a normal music and a fast music too - Increase the switch duration between normal and fast music from 1.0s to 1.5s --- src/audio/music.hpp | 1 - src/audio/music_information.cpp | 40 ++++++++++----------------------- src/audio/music_information.hpp | 16 ++++++------- src/audio/music_ogg.cpp | 7 ------ src/audio/music_ogg.hpp | 1 - src/modes/linear_world.cpp | 19 +++++++--------- 6 files changed, 27 insertions(+), 57 deletions(-) diff --git a/src/audio/music.hpp b/src/audio/music.hpp index a848fb6e50f..120b46f42b1 100644 --- a/src/audio/music.hpp +++ b/src/audio/music.hpp @@ -35,7 +35,6 @@ class Music : public NoCopy virtual bool pauseMusic () = 0; virtual bool resumeMusic () = 0; virtual void setVolume (float volume) = 0; - virtual void updateFaster(float percent, float pitch) = 0; virtual void update () = 0; virtual bool isPlaying () = 0; diff --git a/src/audio/music_information.cpp b/src/audio/music_information.cpp index e211664d4ff..511768b4be6 100644 --- a/src/audio/music_information.cpp +++ b/src/audio/music_information.cpp @@ -84,8 +84,7 @@ MusicInformation::MusicInformation(const XMLNode *root, m_fast_loop_end = -1.0f; m_enable_fast = false; m_music_waiting = false; - m_faster_time = 1.0f; - m_max_pitch = 0.1f; + m_faster_time = 1.5f; m_gain = 1.0f; @@ -107,6 +106,8 @@ MusicInformation::MusicInformation(const XMLNode *root, root->get("fast-loop-start", &m_fast_loop_start ); root->get("fast-loop-end", &m_fast_loop_end ); + m_temporary_volume = m_gain; + // Get the path from the filename and add it to the ogg filename std::string path = StringUtils::getPath(filename); m_normal_filename = path + "/" + m_normal_filename; @@ -273,31 +274,15 @@ void MusicInformation::update(float dt) { m_mode=SOUND_FAST; m_normal_music->stopMusic(); + m_fast_music->setVolume(m_temporary_volume); m_fast_music->update(); return; } float fraction=m_time_since_faster/m_faster_time; - m_normal_music->setVolume(1-fraction); - m_fast_music->setVolume(fraction); + m_normal_music->setVolume(m_temporary_volume * (1-fraction)); + m_fast_music->setVolume(m_temporary_volume * fraction); m_normal_music->update(); m_fast_music->update(); - break; - } - case SOUND_FASTER: { - if ( m_normal_music == NULL ) break; - - m_time_since_faster +=dt; - if(m_time_since_faster>=m_faster_time) - { - // Once the pitch is adjusted, just switch back to normal - // mode. We can't switch to fast music mode, since this would - // play m_fast_music, which isn't available. - m_mode=SOUND_NORMAL; - return; - } - float fraction=m_time_since_faster/m_faster_time; - m_normal_music->updateFaster(fraction, m_max_pitch); - break; } case SOUND_NORMAL: @@ -354,6 +339,7 @@ void MusicInformation::resumeMusic() //----------------------------------------------------------------------------- void MusicInformation::setDefaultVolume() { + m_temporary_volume = m_gain; if (m_normal_music && m_normal_music->isPlaying()) m_normal_music->setVolume(m_gain); if (m_fast_music && m_fast_music->isPlaying()) @@ -366,11 +352,14 @@ void MusicInformation::setDefaultVolume() */ void MusicInformation::setTemporaryVolume(float volume) { - if (m_normal_music != NULL) m_normal_music->setVolume(volume); - if (m_fast_music != NULL) m_fast_music->setVolume(volume); + m_temporary_volume = m_gain * volume; + if (m_normal_music != NULL) m_normal_music->setVolume(m_temporary_volume); + if (m_fast_music != NULL) m_fast_music->setVolume(m_temporary_volume); } //----------------------------------------------------------------------------- +/** If there is a fast music available, switch to it. + * */ void MusicInformation::switchToFastMusic() { if(!m_enable_fast) return; @@ -381,11 +370,6 @@ void MusicInformation::switchToFastMusic() m_fast_music->playMusic(); m_fast_music->setVolume(0); } - else - { - // FIXME: for now this music is too annoying, - m_mode = SOUND_FASTER; - } } // switchToFastMusic //----------------------------------------------------------------------------- diff --git a/src/audio/music_information.hpp b/src/audio/music_information.hpp index fd2406f3a9c..183a9e2ef64 100644 --- a/src/audio/music_information.hpp +++ b/src/audio/music_information.hpp @@ -53,8 +53,7 @@ class MusicInformation : public NoCopy * was told not to start right away). */ bool m_music_waiting; - /** If faster music is enabled at all (either separate file or using - * the pitch shift approach). */ + /** If faster music is enabled at all. */ bool m_enable_fast; float m_gain; @@ -64,18 +63,19 @@ class MusicInformation : public NoCopy float m_normal_loop_end; float m_fast_loop_end; - /** Either time for fading faster music in, or time to change pitch. */ + /** Time for fading faster music in. */ float m_faster_time; - /** Maximum pitch for faster music. */ - float m_max_pitch; + + /* Avoid the temporary volume being forgotten */ + float m_temporary_volume; + static const int LOOP_FOREVER=-1; mutable std::mutex m_music_mutex; Music *m_normal_music, *m_fast_music; enum {SOUND_NORMAL, //!< normal music is played SOUND_FADING, //!< normal music fading out, faster fading in - SOUND_FASTER, //!< change pitch of normal music - SOUND_FAST} //!< playing faster music or max pitch reached + SOUND_FAST} //!< playing faster music m_mode; float m_time_since_faster; @@ -127,8 +127,6 @@ class MusicInformation : public NoCopy // ------------------------------------------------------------------------ /** If available, returns the file name of the faster/last-lap music. */ const std::string& getFastFilename() const { return m_fast_filename; } - // ------------------------------------------------------------------------ - float getMaxPitch() const { return m_max_pitch; } }; // MusicInformation #endif diff --git a/src/audio/music_ogg.cpp b/src/audio/music_ogg.cpp index 8b8c421d6b8..805a90a3f67 100644 --- a/src/audio/music_ogg.cpp +++ b/src/audio/music_ogg.cpp @@ -255,13 +255,6 @@ void MusicOggStream::setVolume(float volume) check("volume music"); // clear errors } // setVolume -//----------------------------------------------------------------------------- -void MusicOggStream::updateFaster(float percent, float max_pitch) -{ - alSourcef(m_soundSource,AL_PITCH,1+max_pitch*percent); - update(); -} // updateFaster - //----------------------------------------------------------------------------- void MusicOggStream::update() { diff --git a/src/audio/music_ogg.hpp b/src/audio/music_ogg.hpp index 37c2c352c1e..c1b7fa63917 100644 --- a/src/audio/music_ogg.hpp +++ b/src/audio/music_ogg.hpp @@ -49,7 +49,6 @@ class MusicOggStream : public Music virtual ~MusicOggStream(); virtual void update(); - virtual void updateFaster(float percent, float max_pitch); virtual bool load(const std::string& filename); diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index 148a8f97932..ad770659630 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -443,6 +443,14 @@ void LinearWorld::newLap(unsigned int kart_index) m_last_lap_sfx_playing = false; } } + // Switch on faster music if not already done so, if the + // first kart is doing its last lap. + if(!m_faster_music_active && + useFastMusicNearEnd()) + { + music_manager->switchToFastMusic(); + m_faster_music_active=true; + } } else if (raceHasLaps() && kart_info.m_finished_laps > 0 && kart_info.m_finished_laps+1 < lap_count && !isLiveJoinWorld() && m_race_gui) @@ -955,17 +963,6 @@ void LinearWorld::updateRacePosition() assert(false); } #endif - - // Switch on faster music if not already done so, if the - // first kart is doing its last lap. - if(!m_faster_music_active && - p == 1 && - kart_info.m_finished_laps == RaceManager::get()->getNumLaps() - 1 && - useFastMusicNearEnd() ) - { - music_manager->switchToFastMusic(); - m_faster_music_active=true; - } } // for i Date: Mon, 23 Dec 2024 12:01:37 +0100 Subject: [PATCH 512/830] Miscellaneous improvements - Add more colors to indicate the time difference with a ghost kart, with new thresholds at +- 0.3s and +-2.5s, while keeping noticeable contrast between colors - Confirm in the networking documentation that STK's networking uses UDP --- NETWORKING.md | 4 ++-- src/states_screens/race_gui.cpp | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index 97ad3dc34ee..91a4ce6516a 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -200,11 +200,11 @@ The current server configuration xml looks like this: ``` At the moment STK has a list of STUN servers for NAT penetration which allows players or servers behind a firewall or router to be able to connect to each other, but in case it doesn't work, you have to manually disable the firewall or port forward the port(s) used by STK. -By default STK servers use port `2759`. For example, in Ubuntu based distributions, run the following command to disable the firewall on that port: +By default STK servers use port `2759` (UDP). For example, in Ubuntu based distributions, run the following command to disable the firewall on that port: `sudo ufw allow 2759` -You may also need to handle the server discovery port `2757` for connecting your WAN server in LAN / localhost. +You may also need to handle the server discovery port `2757` (UDP) for connecting your WAN server in LAN / localhost. Notice: You don't need to make any firewall or router configuration changes if you connect to the recommended servers (marked with ☆★STK★☆). diff --git a/src/states_screens/race_gui.cpp b/src/states_screens/race_gui.cpp index cf6940d0b31..0f692d78283 100644 --- a/src/states_screens/race_gui.cpp +++ b/src/states_screens/race_gui.cpp @@ -519,14 +519,22 @@ void RaceGUI::drawLiveDifference() video::SColor time_color; // Change color depending on value - if (live_difference > 1.0f) + if (live_difference > 2.5f) time_color = video::SColor(255, 255, 0, 0); + else if (live_difference > 1.0f) + time_color = video::SColor(255, 255, 60, 0); + else if (live_difference > 0.3f) + time_color = video::SColor(255, 255, 120, 0); else if (live_difference > 0.0f) - time_color = video::SColor(255, 255, 160, 0); + time_color = video::SColor(255, 255, 180, 0); + else if (live_difference > -0.3f) + time_color = video::SColor(255, 210, 230, 0); else if (live_difference > -1.0f) - time_color = video::SColor(255, 160, 255, 0); + time_color = video::SColor(255, 105, 255, 0); + else if (live_difference > -2.5f) + time_color = video::SColor(255, 0, 210, 30); else - time_color = video::SColor(255, 0, 255, 0); + time_color = video::SColor(255, 0, 160, 60); int dist_from_right = 10 + timer_width; From 2c30427d92da3cb9852998cb62fac8bfc65429bb Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 23 Dec 2024 20:37:55 +0100 Subject: [PATCH 513/830] Fix #5096 - Move the GP higshcore update from race_result_gui.cpp to world.cpp ; GUI code should not be doing this sort of operation - Update the GP hishcore for any number of eligible local human players. - Various simplifications of the highscore logic in world.cpp - Drop support for lap-trial GP highscore - the code for it was extremely hacky and a fix would require a complete rewrite of how lap totals are tracked in lap-trial GPs --- src/config/saved_grand_prix.hpp | 4 -- src/modes/world.cpp | 70 ++++++++++++++------------ src/race/race_manager.cpp | 6 +-- src/race/race_manager.hpp | 4 -- src/states_screens/race_result_gui.cpp | 21 -------- 5 files changed, 40 insertions(+), 65 deletions(-) diff --git a/src/config/saved_grand_prix.hpp b/src/config/saved_grand_prix.hpp index a5c8eb70433..8d12d7d26a8 100644 --- a/src/config/saved_grand_prix.hpp +++ b/src/config/saved_grand_prix.hpp @@ -158,10 +158,6 @@ class SavedGrandPrix /** Returns time target used in Lap Trial mode */ float getTimeTarget() const { return m_time_target; } - // ------------------------------------------------------------------------ - /** Returns total laps in GP */ - int getPlayerTotalLaps() const { return m_player_total_laps; } - // ------------------------------------------------------------------------ /** Sets the index of the last track finished. */ void setNextTrack(int next_track) { m_next_track = next_track; } diff --git a/src/modes/world.cpp b/src/modes/world.cpp index d84f68796ba..eae6672c9ba 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -1256,14 +1256,13 @@ Highscores* World::getGPHighscores() const } // ---------------------------------------------------------------------------- -/** Called at the end of a race. Checks if the current times are worth a new - * score, if so it notifies the HighscoreManager so the new score is added - * and saved. +/** Called at the end of a race. + * Submits the valid new times through the addHighscore functions, which then handles + * checking if the new times are worth of a highscore and saving them. + * The best highscore rank is transmitted to highlight the best new highscore in the GUI. */ void World::updateHighscores(int* best_highscore_rank) { - *best_highscore_rank = -1; - if(!m_use_highscores) return; // Add times to highscore list. First compute the order of karts, @@ -1291,7 +1290,6 @@ void World::updateHighscores(int* best_highscore_rank) { // no kart claimed to be in this position, most likely means // the kart location data is wrong - #ifdef DEBUG Log::error("[World]", "Incorrect kart positions:"); for (unsigned int i=0; iisLapTrialMode() ? static_cast(getFinishedLapsOfKart(index[pos])) + : k->getFinishTime(); // The player is a local player, so there is a name: - if (RaceManager::get()->isLapTrialMode()) - { - highscore_rank = highscores->addData(k->getIdent(), - k->getController()->getName(), - static_cast(getFinishedLapsOfKart(index[pos]))); - } - else + int highscore_rank = highscores->addData(k->getIdent(), k->getController()->getName(), highscore_value); + + if (highscore_rank > 0 && (*best_highscore_rank == -1 || + highscore_rank < *best_highscore_rank)) { - highscore_rank = highscores->addData(k->getIdent(), - k->getController()->getName(), - k->getFinishTime() ); + *best_highscore_rank = highscore_rank; } - + } // next position + + // Handle GP highscores + if (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX && + RaceManager::get()->getNumOfTracks() == RaceManager::get()->getTrackNumber() + 1 && + !RaceManager::get()->getGrandPrix().isRandomGP() && + RaceManager::get()->getSkippedTracksInGP() == 0) + { + std::string gp_name = RaceManager::get()->getGrandPrix().getId(); - if (highscore_rank > 0) + for (unsigned int kart_id = 0; kart_id < RaceManager::get()->getNumberOfKarts(); kart_id++) { - if (*best_highscore_rank == -1 || - highscore_rank < *best_highscore_rank) - { - *best_highscore_rank = highscore_rank; - } + // Only record times for local player karts and only if + // they finished the race + if (!m_karts[kart_id]->getController()->isLocalPlayerController() || + !m_karts[kart_id]->hasFinishedRace() || + m_karts[kart_id]->isEliminated()) + continue; - Highscores::setSortOrder(Highscores::SO_DEFAULT); - highscore_manager->sortHighscores(false); + // The original lap trial GP code was a mess. I'm not fixing it... + if (RaceManager::get()->isLapTrialMode()) + continue; - highscore_manager->saveHighscores(); - } - } // next position - delete []index; + Kart *k = (Kart*)m_karts[kart_id].get(); + float full_time = RaceManager::get()->getOverallTime(kart_id); + Highscores* highscores = World::getWorld()->getGPHighscores(); + // The player is a local player, so there is a name: + highscores->addGPData(k->getIdent(), k->getController()->getName(), gp_name, full_time); + } // for kart_id + } // Handle GP highscores + + delete []index; } // updateHighscores //----------------------------------------------------------------------------- diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index 823ddf60680..f58d51985c3 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -138,7 +138,6 @@ RaceManager::RaceManager() m_flag_deactivated_ticks = stk_config->time2Ticks(3.0f); m_skipped_tracks_in_gp = 0; m_gp_time_target = 0.0f; - m_gp_total_laps = 0; setMaxGoal(0); setTimeTarget(0.0f); setReverseTrack(false); @@ -432,10 +431,7 @@ void RaceManager::startNew(bool from_overworld) m_skipped_tracks_in_gp = m_saved_gp->getSkippedTracks(); Log::info("RaceManager","%d",isLapTrialMode()); if (isLapTrialMode()) - { m_gp_time_target = m_saved_gp->getTimeTarget(); - m_gp_total_laps = m_saved_gp->getPlayerTotalLaps(); - } } // if m_saved_gp==NULL } // if m_continue_saved_gp } // if !network_world @@ -795,7 +791,7 @@ void RaceManager::saveGP() m_grand_prix.getReverseType(), m_skipped_tracks_in_gp, isLapTrialMode() ? m_gp_time_target : 0.0f, - isLapTrialMode() ? m_gp_total_laps : 0, + 0, m_kart_status); // If a new GP is saved, delete any other saved data for this diff --git a/src/race/race_manager.hpp b/src/race/race_manager.hpp index 69356f51004..18870138048 100644 --- a/src/race/race_manager.hpp +++ b/src/race/race_manager.hpp @@ -936,10 +936,6 @@ class RaceManager // ---------------------------------------------------------------------------------------- void setGPTimeTarget(float time_target) { m_gp_time_target = time_target; } // ---------------------------------------------------------------------------------------- - int getGPTotalLaps() const { return m_gp_total_laps; } - // ---------------------------------------------------------------------------------------- - void addGPTotalLaps(int laps) { m_gp_total_laps += laps; } - // ---------------------------------------------------------------------------------------- /** Whether the current game mode allow live joining even the current game *. started in network*/ bool supportsLiveJoining() const diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 49a317c611d..43d4ec2bad2 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -207,27 +207,6 @@ void RaceResultGUI::init() MessageQueue::add(MessageQueue::MT_GENERIC, tips_string); } #endif - - if (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX && - !NetworkConfig::get()->isNetworking() && - (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE || RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL || - RaceManager::get()->isLapTrialMode())) - { - const AbstractKart* k = RaceManager::get()->getKartWithGPRank(RaceManager::get()->getLocalPlayerGPRank(PLAYER_ID_GAME_MASTER)); - RaceManager::get()->addGPTotalLaps(World::getWorld()->getFinishedLapsOfKart(k->getWorldKartId())); - if (RaceManager::get()->getNumOfTracks() == RaceManager::get()->getTrackNumber() + 1 - && !RaceManager::get()->getGrandPrix().isRandomGP() && RaceManager::get()->getSkippedTracksInGP() == 0) - { - Highscores* highscores = World::getWorld()->getGPHighscores(); - float full_time; - if (RaceManager::get()->isLapTrialMode()) - full_time = static_cast(RaceManager::get()->getGPTotalLaps()); - else - full_time = RaceManager::get()->getOverallTime(RaceManager::get()->getLocalPlayerGPRank(PLAYER_ID_GAME_MASTER)); - std::string gp_name = RaceManager::get()->getGrandPrix().getId(); - highscores->addGPData(k->getIdent(), k->getController()->getName(), gp_name, full_time); - } - } } // init //----------------------------------------------------------------------------- From 2fac72bd05af89640f14d7be7c1f4b2e3388b0e1 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Tue, 24 Dec 2024 13:35:16 +0100 Subject: [PATCH 514/830] Fix #5204 When music was resumed, its status was switched to 'playing' without regard to the music play initialization steps having been done or not. --- src/audio/music_ogg.cpp | 15 +++++---------- src/audio/music_ogg.hpp | 1 + src/audio/sfx_manager.cpp | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/audio/music_ogg.cpp b/src/audio/music_ogg.cpp index 805a90a3f67..72db0e122b8 100644 --- a/src/audio/music_ogg.cpp +++ b/src/audio/music_ogg.cpp @@ -35,6 +35,7 @@ MusicOggStream::MusicOggStream(float loop_start, float loop_end) m_soundSource = -1; m_pausedMusic = true; m_playing.store(false); + m_play_initialized.store(false); m_loop_start = loop_start; m_loop_end = loop_end; } // MusicOggStream @@ -166,6 +167,7 @@ bool MusicOggStream::release() m_soundSource = -1; m_playing.store(false); + m_play_initialized.store(false); return true; } // release @@ -187,6 +189,7 @@ bool MusicOggStream::playMusic() alSourcePlay(m_soundSource); m_pausedMusic = false; m_playing.store(true); + m_play_initialized.store(true); check("playMusic"); return true; } // playMusic @@ -195,15 +198,6 @@ bool MusicOggStream::playMusic() bool MusicOggStream::isPlaying() { return m_playing.load(); - - /* - if (m_soundSource == -1) return false; - - ALenum state; - alGetSourcei(m_soundSource, AL_SOURCE_STATE, &state); - - return (state == AL_PLAYING); - */ } // isPlaying //----------------------------------------------------------------------------- @@ -237,7 +231,8 @@ bool MusicOggStream::resumeMusic() return true; } - m_playing.store(true); + if(m_play_initialized.load()) // Avoid #5204 + m_playing.store(true); alSourcePlay(m_soundSource); m_pausedMusic= false; diff --git a/src/audio/music_ogg.hpp b/src/audio/music_ogg.hpp index c1b7fa63917..7f7a80a7c25 100644 --- a/src/audio/music_ogg.hpp +++ b/src/audio/music_ogg.hpp @@ -77,6 +77,7 @@ class MusicOggStream : public Music bool m_error; std::atomic_bool m_playing; + std::atomic_bool m_play_initialized; ALuint m_soundBuffers[2]; ALuint m_soundSource; diff --git a/src/audio/sfx_manager.cpp b/src/audio/sfx_manager.cpp index 66aeb38b69f..ce6b6623640 100644 --- a/src/audio/sfx_manager.cpp +++ b/src/audio/sfx_manager.cpp @@ -438,7 +438,7 @@ void SFXManager::mainLoop(void *obj) current->m_music_information->pauseMusic(); break; case SFX_MUSIC_RESUME: current->m_music_information->resumeMusic(); - // This might be necessasary if the volume was changed + // This might be necessary if the volume was changed // in the in-game menu current->m_music_information->setDefaultVolume(); break; case SFX_MUSIC_SWITCH_FAST: From 4ea1a28ca26d34ae6a5b516c9eff5773226c0a7a Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sun, 29 Dec 2024 02:51:53 +0100 Subject: [PATCH 515/830] Fix #5232 - Don't clear the favorites data of the kart properties manager when leaving the kart selection screen - this was the cause of the bug. - Remove a block of code that was never accessed because the condition was always false - Use getIdent() behind the scenes for more robustness - Prevent a crash when uninstalling an addon that's registered as a favorite kart --- src/config/favorite_status.cpp | 2 +- src/karts/kart_properties.cpp | 4 +-- src/karts/kart_properties_manager.cpp | 39 ++++++++------------------- src/karts/kart_properties_manager.hpp | 1 - src/states_screens/kart_selection.cpp | 10 +++---- 5 files changed, 18 insertions(+), 38 deletions(-) diff --git a/src/config/favorite_status.cpp b/src/config/favorite_status.cpp index 3426f2c5808..968e506d94c 100644 --- a/src/config/favorite_status.cpp +++ b/src/config/favorite_status.cpp @@ -59,7 +59,7 @@ FavoriteStatus::FavoriteStatus(const XMLNode* node, std::string parse_type) m_favorite[temp_group_string].insert(temp_string); } } -} // FavoriteStatu +} // FavoriteStatus //------------------------------------------------------------------------------ /** Adds a new favorite track to this player profile and to the group diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index 2ef98446a14..5852abf89cc 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -658,8 +658,8 @@ bool KartProperties::operator<(const KartProperties &other) const PlayerProfile *p = PlayerManager::getCurrentPlayer(); bool this_is_locked = p->isLocked(getIdent()); bool other_is_locked = p->isLocked(other.getIdent()); - bool this_is_favorite = p->isFavoriteKart(getNonTranslatedName()); - bool other_is_favorite = p->isFavoriteKart(other.getNonTranslatedName()); + bool this_is_favorite = p->isFavoriteKart(getIdent()); + bool other_is_favorite = p->isFavoriteKart(other.getIdent()); if (this_is_locked != other_is_locked) { diff --git a/src/karts/kart_properties_manager.cpp b/src/karts/kart_properties_manager.cpp index adce7c117f1..833542f8e02 100644 --- a/src/karts/kart_properties_manager.cpp +++ b/src/karts/kart_properties_manager.cpp @@ -116,7 +116,7 @@ void KartPropertiesManager::removeKart(const std::string &ident) for (auto it = m_current_favorite_status->getAllFavorites().begin(); it != m_current_favorite_status->getAllFavorites().end(); it++) { // User-defined groups - if (it->second.find(kp->getNonTranslatedName()) != it->second.end()) + if (it->second.find(kp->getIdent()) != it->second.end()) { groups.push_back(it->first); } @@ -129,13 +129,14 @@ void KartPropertiesManager::removeKart(const std::string &ident) it = std::find(m_groups_2_indices_no_custom[groups[i]].begin(), m_groups_2_indices_no_custom[groups[i]].end(), index); // Handle no custom group first - assert(it!=m_groups_2_indices_no_custom[groups[i]].end()); - - m_groups_2_indices_no_custom[groups[i]].erase(it); - - if(m_groups_2_indices_no_custom[groups[i]].size()==0) + if(it!=m_groups_2_indices_no_custom[groups[i]].end()) { - m_groups_2_indices_no_custom.erase(groups[i]); + m_groups_2_indices_no_custom[groups[i]].erase(it); + + if(m_groups_2_indices_no_custom[groups[i]].size()==0) + { + m_groups_2_indices_no_custom.erase(groups[i]); + } } it = std::find(m_groups_2_indices[groups[i]].begin(), @@ -317,17 +318,6 @@ bool KartPropertiesManager::loadKart(const std::string &dir) m_kart_available.push_back(true); std::vector groups=kart_properties->getGroups(); - if (m_current_favorite_status) - { - for (auto it = m_current_favorite_status->getAllFavorites().begin(); - it != m_current_favorite_status->getAllFavorites().end(); it++) - { // User-defined groups - if (it->second.find(kart_properties->getNonTranslatedName()) != it->second.end()) - { - groups.push_back(it->first); - } - } - } for(unsigned int g=0; gfirst].push_back(i); break; @@ -544,13 +534,7 @@ void KartPropertiesManager::setFavoriteKartStatus(FavoriteStatus *status) int x = g2i.find(a)->second[0], y = g2i.find(b)->second[0]; return x == y ? a < b : x < y; }); -} // addFavorite - -//----------------------------------------------------------------------------- -void KartPropertiesManager::clearFavoriteKartStatus() -{ - setFavoriteKartStatus(NULL); -} // addFavorite +} // setFavoriteKartStatus //----------------------------------------------------------------------------- /** Returns true if a kart is available to be selected. A kart is available to @@ -588,8 +572,7 @@ void KartPropertiesManager::selectKartName(const std::string &kart_name) * determined * \return A vector of indices with the karts in the given group. */ -const std::vector KartPropertiesManager::getKartsInGroup( - const std::string& g) +const std::vector KartPropertiesManager::getKartsInGroup(const std::string& g) { if (g == ALL_KART_GROUPS_ID) { diff --git a/src/karts/kart_properties_manager.hpp b/src/karts/kart_properties_manager.hpp index a45c8daea6c..0aa852ead29 100644 --- a/src/karts/kart_properties_manager.hpp +++ b/src/karts/kart_properties_manager.hpp @@ -104,7 +104,6 @@ class KartPropertiesManager: public NoCopy * We need to treat it specially, because the list of tracks in this group * depends on the player-profile, not on the track data. */ void setFavoriteKartStatus(FavoriteStatus *status); - void clearFavoriteKartStatus(); bool kartAvailable(int kartid); std::vector getAllAvailableKarts() const; void setUnavailableKarts(std::vector); diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index 3ce44630e9e..f730732a0ae 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -494,8 +494,6 @@ void KartSelectionScreen::init() void KartSelectionScreen::tearDown() { - kart_properties_manager->clearFavoriteKartStatus(); - #ifndef SERVER_ONLY GE::getGEConfig()->m_enable_draw_call_cache = false; GE::GEVulkanDriver* gevk = GE::getVKDriver(); @@ -1220,13 +1218,13 @@ void KartSelectionScreen::eventCallback(Widget* widget, { const KartProperties *kp = kart_properties_manager->getKart(selection); - if (PlayerManager::getCurrentPlayer()->isFavoriteKart(kp->getNonTranslatedName())) + if (PlayerManager::getCurrentPlayer()->isFavoriteKart(kp->getIdent())) { - PlayerManager::getCurrentPlayer()->removeFavoriteKart(kp->getNonTranslatedName()); + PlayerManager::getCurrentPlayer()->removeFavoriteKart(kp->getIdent()); } else { - PlayerManager::getCurrentPlayer()->addFavoriteKart(kp->getNonTranslatedName()); + PlayerManager::getCurrentPlayer()->addFavoriteKart(kp->getIdent()); } setKartsFromCurrentGroup(); } @@ -1674,7 +1672,7 @@ void KartSelectionScreen::setKartsFromCurrentGroup() prop->getAbsoluteIconFile(), LOCKED_BADGE, IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); } - else if (PlayerManager::getCurrentPlayer()->isFavoriteKart(prop->getNonTranslatedName())) + else if (PlayerManager::getCurrentPlayer()->isFavoriteKart(prop->getIdent())) { w->addItem(prop->getName(), prop->getIdent(), From 53ff6e69fcc1a0b33ffda596ff2a58fb23fb6be1 Mon Sep 17 00:00:00 2001 From: "Tej A. Shah" Date: Sun, 29 Dec 2024 12:39:02 -0500 Subject: [PATCH 516/830] Command line parameters to assign keyboard or gamepad with the -N or -R option (#5230) Authored-by: Tej A. Shah (DesiOtaku) --- src/config/user_config.hpp | 4 ++++ src/main.cpp | 33 ++++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index 92b9c54985e..ecdca1be72b 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -834,6 +834,10 @@ namespace UserConfigParams PARAM_PREFIX bool m_race_now PARAM_DEFAULT( false ); + PARAM_PREFIX int m_default_keyboard PARAM_DEFAULT( -1 ); + + PARAM_PREFIX int m_default_gamepad PARAM_DEFAULT( -1 ); + PARAM_PREFIX bool m_enforce_current_player PARAM_DEFAULT( false ); PARAM_PREFIX bool m_enable_sound PARAM_DEFAULT( true ); diff --git a/src/main.cpp b/src/main.cpp index 9d143f78884..7fa0f567615 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -516,10 +516,21 @@ void setupRaceStart() InputDevice *device; - // Use keyboard 0 by default in --no-start-screen - device = input_manager->getDeviceManager()->getKeyboard(0); + // Assign the player a device; check the command line params for preferences; by default use keyboard 0 - // Create player and associate player with keyboard + if(UserConfigParams::m_default_keyboard > -1) { + device = input_manager->getDeviceManager()->getKeyboard(UserConfigParams::m_default_keyboard); + } + else if(UserConfigParams::m_default_gamepad > -1) { + // getGamePad(int) returns a GamePadDevice which is a subclass of InputDevice + // However, the compiler doesn't like it so it has to be manually casted in + device = (InputDevice *) input_manager->getDeviceManager()->getGamePad(UserConfigParams::m_default_gamepad); + } + else { + device = input_manager->getDeviceManager()->getKeyboard(0); + } + + // Create player and associate player with device StateManager::get()->createActivePlayer( PlayerManager::get()->getPlayer(0), device); @@ -557,10 +568,14 @@ void cmdLineHelp() "menu.\n" " -R, --race-now Same as -N but also skip the ready-set-go phase" " and the music.\n" + " --use-keyboard=N Used in conjunction with the -N or -R option, will assign the player to the specified" + " keyboard. Is zero indexed.\n" + " --use-gamepad=N Used in conjunction with the -N or -R option, will assign the player to the specified" + " gamepad. Is zero indexed.\n" " -t, --track=NAME Start track NAME.\n" " --gp=NAME Start the specified Grand Prix.\n" - " --add-gp-dir=DIR Load Grand Prix files in DIR. Setting will be saved\n" - "in config.xml under additional_gp_directory. Use\n" + " --add-gp-dir=DIR Load Grand Prix files in DIR. Setting will be saved" + "in config.xml under additional_gp_directory. Use" "--add-gp-dir=\"\" to unset.\n" " --stk-config=FILE use ./data/FILE instead of " "./data/stk_config.xml\n" @@ -1675,6 +1690,14 @@ int handleCmdLine(bool has_server_config, bool has_parent_process) UserConfigParams::m_race_now = true; } // --race-now + if(CommandLine::has( "--use-keyboard",&n)) { + UserConfigParams::m_default_keyboard = n; + } //--use-keyboard + + if(CommandLine::has( "--use-gamepad",&n)) { + UserConfigParams::m_default_gamepad = n; + } //--use-gamepad + if(CommandLine::has("--laps", &s)) { int laps = atoi(s.c_str()); From 31d3596995316bf2b7209fd2494ab2ef40b7f13b Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sun, 29 Dec 2024 19:21:52 +0100 Subject: [PATCH 517/830] Improve command-line input device handling - Fallback to the first keyboard config instead of crashing if the requested device doesn't exist - Automatically enable the requested config if it's available but disabled --- src/input/device_manager.cpp | 18 ++++++++++++++++++ src/input/device_manager.hpp | 6 ++---- src/main.cpp | 21 +++++++++++++++++---- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/input/device_manager.cpp b/src/input/device_manager.cpp index 6a423b516cc..189172c9fa2 100644 --- a/src/input/device_manager.cpp +++ b/src/input/device_manager.cpp @@ -611,6 +611,24 @@ KeyboardDevice* DeviceManager::getKeyboardFromBtnID(const int button_id) return NULL; } // getKeyboardFromButtonID +// ----------------------------------------------------------------------------- +GamePadDevice* DeviceManager::getGamePad(const int i) +{ + if (i>= 0 && i < (int)m_gamepads.size()) + return m_gamepads.get(i); + else + return NULL; +} + +// ----------------------------------------------------------------------------- +KeyboardDevice* DeviceManager::getKeyboard(const int i) +{ + if (i >= 0 && i < (int)m_keyboards.size()) + return m_keyboards.get(i); + else + return NULL; +} + // ----------------------------------------------------------------------------- void DeviceManager::shutdown() diff --git a/src/input/device_manager.hpp b/src/input/device_manager.hpp index 126718679d6..b6ca0366b3e 100644 --- a/src/input/device_manager.hpp +++ b/src/input/device_manager.hpp @@ -98,8 +98,6 @@ class DeviceManager: public NoCopy void shutdown(); public: - - DeviceManager(); ~DeviceManager(); @@ -111,7 +109,7 @@ class DeviceManager: public NoCopy void addGamepad(GamePadDevice* d); int getGamePadAmount() const { return m_gamepads.size(); } int getGamePadConfigAmount() const { return m_gamepad_configs.size(); } - GamePadDevice* getGamePad(const int i) { return m_gamepads.get(i); } + GamePadDevice* getGamePad(const int i); GamepadConfig* getGamepadConfig(const int i) { return m_gamepad_configs.get(i); } GamePadDevice* getGamePadFromIrrID(const int i); void clearGamepads(); @@ -135,7 +133,7 @@ class DeviceManager: public NoCopy return active; } int getKeyboardConfigAmount() const { return m_keyboard_configs.size(); } - KeyboardDevice* getKeyboard(const int i) { return m_keyboards.get(i); } + KeyboardDevice* getKeyboard(const int i); KeyboardConfig* getKeyboardConfig(const int i) { return m_keyboard_configs.get(i); } KeyboardDevice* getKeyboardFromBtnID(const int btnID); diff --git a/src/main.cpp b/src/main.cpp index 7fa0f567615..c52e014cfc7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -514,22 +514,35 @@ void setupRaceStart() // a current player PlayerManager::get()->enforceCurrentPlayer(); - InputDevice *device; + InputDevice *device = NULL; // Assign the player a device; check the command line params for preferences; by default use keyboard 0 - if(UserConfigParams::m_default_keyboard > -1) { + if(UserConfigParams::m_default_keyboard > -1) + { device = input_manager->getDeviceManager()->getKeyboard(UserConfigParams::m_default_keyboard); } - else if(UserConfigParams::m_default_gamepad > -1) { + else if(UserConfigParams::m_default_gamepad > -1) + { // getGamePad(int) returns a GamePadDevice which is a subclass of InputDevice // However, the compiler doesn't like it so it has to be manually casted in device = (InputDevice *) input_manager->getDeviceManager()->getGamePad(UserConfigParams::m_default_gamepad); } - else { + // If no config requested or if the requested config doesn't exist + if (device == NULL) + { + if (UserConfigParams::m_default_keyboard > -1 || + UserConfigParams::m_default_gamepad > -1) + { + Log::error("main", "Requested input device unavailable, fallback to the default keyboard"); + } device = input_manager->getDeviceManager()->getKeyboard(0); } + // In case the requested config was disabled, enable it. + if (!device->getConfiguration()->isEnabled()) + device->getConfiguration()->setEnabled(true); + // Create player and associate player with device StateManager::get()->createActivePlayer( PlayerManager::get()->getPlayer(0), device); From 6a9dbc23c14ea9260af3b518e23c666ab197b84b Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 29 Dec 2024 23:10:45 +0400 Subject: [PATCH 518/830] Make all deltas in GP online result screen dependent on server points (#5235) --- src/states_screens/race_result_gui.cpp | 23 +++++------------------ src/states_screens/race_result_gui.hpp | 3 +++ 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 43d4ec2bad2..4e6934adce4 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -1286,20 +1286,15 @@ void RaceResultGUI::renderGlobal(float dt) { WorldWithRank *wwr = dynamic_cast(World::getWorld()); assert(wwr); - int most_points; - if (RaceManager::get()->isFollowMode()) - most_points = wwr->getScoreForPosition(2); - else - most_points = wwr->getScoreForPosition(1); ri->m_current_displayed_points += - dt*most_points / m_time_for_points; + dt * m_most_points / m_time_for_points; if (ri->m_current_displayed_points > ri->m_new_overall_points) { ri->m_current_displayed_points = (float)ri->m_new_overall_points; } ri->m_new_points -= - dt*most_points / m_time_for_points; + dt * m_most_points / m_time_for_points; if (ri->m_new_points < 0) ri->m_new_points = 0; break; @@ -1345,6 +1340,7 @@ void RaceResultGUI::determineGPLayout() max_time = std::max(RaceManager::get()->getOverallTime(kart_id), max_time); } + m_most_points = 0.; for (unsigned int kart_id = 0; kart_id < num_karts; kart_id++) { int rank = RaceManager::get()->getKartGPRank(kart_id); @@ -1385,17 +1381,6 @@ void RaceResultGUI::determineGPLayout() ri->m_y_pos = (float)(m_top + rank*m_distance_between_rows); int p = RaceManager::get()->getKartPrevScore(kart_id); ri->m_current_displayed_points = (float)p; - if (kart->isEliminated() && !(RaceManager::get()->isFollowMode())) - { - ri->m_new_points = 0; - } - else - { - WorldWithRank *wwr = dynamic_cast(World::getWorld()); - assert(wwr); - ri->m_new_points = - (float)wwr->getScoreForPosition(kart->getPosition()); - } } // Now update the GP ranks, and determine the new position @@ -1412,6 +1397,8 @@ void RaceResultGUI::determineGPLayout() ri->m_centre_point = m_top + (gp_position + j)*m_distance_between_rows*0.5f; int p = RaceManager::get()->getKartScore(i); ri->m_new_overall_points = p; + ri->m_new_points = ri->m_new_overall_points - ri->m_current_displayed_points; + m_most_points = std::max(m_most_points, ri->m_new_points); ri->m_new_gp_rank = gp_position; ri->m_laps = World::getWorld()->getFinishedLapsOfKart(i); } // i < num_karts diff --git a/src/states_screens/race_result_gui.hpp b/src/states_screens/race_result_gui.hpp index 5aba04c346d..3f85a7012c2 100644 --- a/src/states_screens/race_result_gui.hpp +++ b/src/states_screens/race_result_gui.hpp @@ -186,6 +186,9 @@ class RaceResultGUI : public RaceGUIBase, /** For highscores */ int m_highscore_rank; + /** Maximum number of points earned by a player in this game (used in animation). */ + float m_most_points; + unsigned int m_width_all_points; int m_max_tracks; From 05f34527455b6d35baf34bccf4faa8eb71405944 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 30 Dec 2024 01:09:35 +0100 Subject: [PATCH 519/830] Race Result GUI improvements - Consolidate duplicated per-team code in the CTF player score drawing - Don't assume the value of the extra wait time after race results have been displayed - Tweak timings for the GP UI, in particular increase the duration of points transfer from new to total from 1.0s to 2.0s - Use a lambda for a minor code quality improvement --- src/states_screens/race_result_gui.cpp | 130 +++++++++++-------------- src/states_screens/race_result_gui.hpp | 4 + 2 files changed, 61 insertions(+), 73 deletions(-) diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 4e6934adce4..a487a73dc47 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -235,6 +235,15 @@ void RaceResultGUI::enableAllButtons() operations->setActive(true); operations->setFocusForPlayer(PLAYER_ID_GAME_MASTER); + auto makeContinueButton + { + [](GUIEngine::IconButtonWidget *button) + { + button->setLabel(_("Continue")); + button->setImage("gui/icons/green_check.png"); + } + }; + if (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) { enableGPProgress(); @@ -260,8 +269,7 @@ void RaceResultGUI::enableAllButtons() // If we're in a network world, change the buttons text if (World::getWorld()->isNetworkWorld()) { - right->setLabel(_("Continue")); - right->setImage("gui/icons/green_check.png"); + makeContinueButton(right); right->setVisible(true); operations->select("right", PLAYER_ID_GAME_MASTER); middle->setVisible(false); @@ -283,8 +291,7 @@ void RaceResultGUI::enableAllButtons() (RaceManager::get()->getMajorMode() != RaceManager::MAJOR_MODE_GRAND_PRIX || RaceManager::get()->getTrackNumber() + 1 == RaceManager::get()->getNumOfTracks() ) ) { - middle->setLabel(_("Continue")); - middle->setImage("gui/icons/green_check.png"); + makeContinueButton(middle); middle->setVisible(true); operations->select("middle", PLAYER_ID_GAME_MASTER); } @@ -292,16 +299,14 @@ void RaceResultGUI::enableAllButtons() { // In case of a GP: // ---------------- - middle->setLabel(_("Continue")); - middle->setImage("gui/icons/green_check.png"); + makeContinueButton(middle); middle->setVisible(false); middle->setFocusable(false); left->setVisible(false); left->setFocusable(false); // Two continue buttons to make sure the buttons in the bar is balanced - right->setLabel(_("Continue")); - right->setImage("gui/icons/green_check.png"); + makeContinueButton(right); right->setVisible(true); if (RaceManager::get()->getTrackNumber() + 1 < RaceManager::get()->getNumOfTracks()) @@ -652,7 +657,6 @@ void RaceResultGUI::displayCTFResults() //Draw win text core::stringw result_text; video::SColor color = video::SColor(255, 255, 255, 255); - video::SColor red_color = video::SColor(255, 255, 0, 0); gui::IGUIFont* font = GUIEngine::getTitleFont(); int team_icon_height = font->getDimension(L"A").Height; int current_x = UserConfigParams::m_width / 2; @@ -718,18 +722,44 @@ void RaceResultGUI::displayCTFResults() // The red team player scores: current_y += rect.Height / 2 + rect.Height / 4; - font = GUIEngine::getSmallFont(); + drawCTFScorers(KART_TEAM_RED, current_x, current_y, height); + current_x += UserConfigParams::m_width / 2; + drawCTFScorers(KART_TEAM_BLUE, current_x, current_y, height); +#endif +} // displayCTFResults + +//----------------------------------------------------------------------------- +/** Displays the CTF scorers for a team + * \param team The team for which to draw the scorers + * \param x Left limit of the scorers lists (both blue and red) + * \param y Top limit of the scorers lists + * \param height Maximum y of the table area (??) */ +void RaceResultGUI::drawCTFScorers(KartTeam team, int x, int y, int height) +{ +#ifndef SERVER_ONLY + CaptureTheFlag* ctf = dynamic_cast(World::getWorld()); + gui::IGUIFont* font = GUIEngine::getSmallFont(); irr::video::ITexture* kart_icon; - int prev_y = current_y; + core::stringw result_text; + video::SColor color = video::SColor(255, 255, 255, 255); + video::SColor red_color = video::SColor(255, 255, 0, 0); + + int current_x = x; + int current_y = y; + core::dimension2du rect; + core::rect pos(current_x, current_y, current_x, current_y); + const unsigned num_karts = ctf->getNumKarts(); for (unsigned int i = 0; i < num_karts; i++) { AbstractKart* kart = ctf->getKartAtPosition(i + 1); unsigned kart_id = kart->getWorldKartId(); - if (ctf->getKartTeam(kart_id) != KART_TEAM_RED) + if (ctf->getKartTeam(kart_id) != team) continue; result_text = kart->getController()->getName(); + + // add the country flag if available if (RaceManager::get()->getKartGlobalPlayerId(kart_id) > -1) { const core::stringw& flag = StringUtils::getCountryFlag( @@ -747,9 +777,9 @@ void RaceResultGUI::displayCTFResults() } else { - result_text.append( - StringUtils::toWString(ctf->getKartScore(kart_id))); + result_text.append(StringUtils::toWString(ctf->getKartScore(kart_id))); } + rect = font->getDimension(result_text.c_str()); current_y += rect.Height; @@ -760,63 +790,15 @@ void RaceResultGUI::displayCTFResults() kart->getController()->isLocalPlayerController() ? red_color : color, true, false); kart_icon = kart->getKartProperties()->getIconMaterial()->getTexture(); - source_rect = core::recti(core::vector2di(0, 0), kart_icon->getSize()); + core::recti source_rect = core::recti(core::vector2di(0, 0), kart_icon->getSize()); irr::u32 offset_x = (irr::u32)(font->getDimension(result_text.c_str()).Width / 1.5f); - dest_rect = core::recti(current_x - offset_x - m_width_icon, current_y, - current_x - offset_x, current_y + m_width_icon); - draw2DImage(kart_icon, dest_rect, source_rect, NULL, NULL, true); - } - - // The blue team player scores: - current_y = prev_y; - current_x += UserConfigParams::m_width / 2; - for (unsigned int i = 0; i < num_karts; i++) - { - AbstractKart* kart = ctf->getKartAtPosition(i + 1); - unsigned kart_id = kart->getWorldKartId(); - if (ctf->getKartTeam(kart_id) != KART_TEAM_BLUE) - continue; - result_text = kart->getController()->getName(); - if (RaceManager::get()->getKartGlobalPlayerId(kart_id) > -1) - { - const core::stringw& flag = StringUtils::getCountryFlag( - RaceManager::get()->getKartInfo(kart_id).getCountryCode()); - if (!flag.empty()) - { - result_text += L" "; - result_text += flag; - } - } - result_text.append(" "); - if (kart->isEliminated()) - { - continue; - } - else - { - result_text.append( - StringUtils::toWString(ctf->getKartScore(kart_id))); - } - rect = font->getDimension(result_text.c_str()); - current_y += rect.Height; - - if (current_y > height) break; - - pos = core::rect(current_x, current_y, current_x, current_y); - font->draw(result_text, pos, - kart->getController()->isLocalPlayerController() ? - red_color : color, true, false); - kart_icon = kart->getKartProperties()->getIconMaterial()->getTexture(); - source_rect = core::recti(core::vector2di(0, 0), kart_icon->getSize()); - irr::u32 offset_x = (irr::u32) - (font->getDimension(result_text.c_str()).Width / 1.5f); - dest_rect = core::recti(current_x - offset_x - m_width_icon, current_y, + core::recti dest_rect = core::recti(current_x - offset_x - m_width_icon, current_y, current_x - offset_x, current_y + m_width_icon); draw2DImage(kart_icon, dest_rect, source_rect, NULL, NULL, true); } #endif -} // displayCTFResults +} // drawCTFScorers //----------------------------------------------------------------------------- void RaceResultGUI::unload() @@ -982,11 +964,12 @@ void RaceResultGUI::determineTableLayout() // The time the first phase is being displayed: add the start time // of the last kart to the duration of the scroll plus some time // of rest before the next phase starts + m_extra_scroll_time = 1.0f; m_time_overall_scroll = (num_karts - 1)*m_time_between_rows - + m_time_single_scroll + 2.0f; + + m_time_single_scroll + m_extra_scroll_time; // The time to increase the number of points. - m_time_for_points = 1.0f; + m_time_for_points = 2.0f; // Determine text height r = m_font->getDimension(L"Y"); @@ -1121,6 +1104,9 @@ void RaceResultGUI::renderGlobal(float dt) assert(World::getWorld()->getPhase() == WorldStatus::RESULT_DISPLAY_PHASE); unsigned int num_karts = (unsigned int)m_all_row_infos.size(); float time_overall_scroll = m_time_overall_scroll; + // TODO after 1.5: Avoid the point increase being too slow for low point amounts + // float time_for_points = std::min(0.3f + 0.2f*m_most_points, m_time_for_points); + float time_for_points = m_time_for_points; // First: Update the finite state machine // ====================================== @@ -1140,7 +1126,7 @@ void RaceResultGUI::renderGlobal(float dt) // GP mode has a continue button so no extra time is needed if (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX) - time_overall_scroll -= 2.0f; + time_overall_scroll -= m_extra_scroll_time; if (m_timer > time_overall_scroll) { // Make sure that all lines are aligned to the left @@ -1189,7 +1175,7 @@ void RaceResultGUI::renderGlobal(float dt) break; case RR_INCREASE_POINTS: // Have one second delay before the resorting starts. - if (m_timer > 1 + m_time_for_points) + if (m_timer > 1 + time_for_points) { m_animation_state = RR_RESORT_TABLE; if (m_gp_position_was_changed) @@ -1286,15 +1272,13 @@ void RaceResultGUI::renderGlobal(float dt) { WorldWithRank *wwr = dynamic_cast(World::getWorld()); assert(wwr); - ri->m_current_displayed_points += - dt * m_most_points / m_time_for_points; + ri->m_current_displayed_points += dt * m_most_points / time_for_points; if (ri->m_current_displayed_points > ri->m_new_overall_points) { ri->m_current_displayed_points = (float)ri->m_new_overall_points; } - ri->m_new_points -= - dt * m_most_points / m_time_for_points; + ri->m_new_points -= dt * m_most_points / time_for_points; if (ri->m_new_points < 0) ri->m_new_points = 0; break; diff --git a/src/states_screens/race_result_gui.hpp b/src/states_screens/race_result_gui.hpp index 3f85a7012c2..e6b3b2831df 100644 --- a/src/states_screens/race_result_gui.hpp +++ b/src/states_screens/race_result_gui.hpp @@ -134,6 +134,9 @@ class RaceResultGUI : public RaceGUIBase, This includes a small waiting time at the end. */ float m_time_overall_scroll; + /** The small waiting time for the above. */ + float m_extra_scroll_time; + /** Distance between each row of the race results */ unsigned int m_distance_between_rows; @@ -213,6 +216,7 @@ class RaceResultGUI : public RaceGUIBase, int displayLapDifficulty(int x, int y, bool increase_density); int displayChallengeInfo(int x, int y, bool increase_density); void displayCTFResults(); + void drawCTFScorers(KartTeam team, int x, int y, int height); void displaySoccerResults(); void drawTeamScorers(KartTeam team, int x, int y, int height); void displayBenchmarkSummary(); From ac3bf83bc33fc5550562fd7e89a61189ccd0072c Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Wed, 8 Jan 2025 14:37:20 +0100 Subject: [PATCH 520/830] Fix #5226 and some other GUI issues - Ensure the back button will always work when clicked in the arena screen - Fix the back button not working in the online track selection screen by removing the ability to edit favorites in the network track selection screen (it was poor UX anyway). The ability to see previously picked favorites remains. - Avoid the spinners of the random GP screen overflowing with big fonts in non-lap-trial mode --- data/gui/screens/arenas.stkgui | 23 ++++++++++----------- data/gui/screens/gp_info.stkgui | 16 +++++++------- data/gui/screens/tracks.stkgui | 12 ++--------- src/states_screens/online/tracks_screen.cpp | 23 +-------------------- 4 files changed, 22 insertions(+), 52 deletions(-) diff --git a/data/gui/screens/arenas.stkgui b/data/gui/screens/arenas.stkgui index e4ecb37b455..d9446266476 100644 --- a/data/gui/screens/arenas.stkgui +++ b/data/gui/screens/arenas.stkgui @@ -1,20 +1,19 @@ - - -
-
-
- +
+ +
+ + +
+ -
- - - -
+
+
+
diff --git a/data/gui/screens/gp_info.stkgui b/data/gui/screens/gp_info.stkgui index 46584d4db6e..7941daba731 100644 --- a/data/gui/screens/gp_info.stkgui +++ b/data/gui/screens/gp_info.stkgui @@ -31,14 +31,6 @@
-
-
- -
- -
-
@@ -54,6 +46,14 @@
+ +
+
+ +
+ +
diff --git a/data/gui/screens/tracks.stkgui b/data/gui/screens/tracks.stkgui index dd01abbda88..11046e7b0ce 100644 --- a/data/gui/screens/tracks.stkgui +++ b/data/gui/screens/tracks.stkgui @@ -4,16 +4,8 @@
-
-
-
- - - -
-
- +
setValue(host_vote->m_num_laps); m_reversed->setState(host_vote->m_reverse); voteForPlayer(); - - // If editing favorite, also favorite that track - if (getWidget("favorite")->getState() - && !PlayerManager::getCurrentPlayer()->isFavoriteTrack(host_vote->m_track_name)) - { - PlayerManager::getCurrentPlayer()->addFavoriteTrack(host_vote->m_track_name); - buildTrackList(); - } } } } @@ -138,16 +130,7 @@ void TracksScreen::eventCallback(Widget* widget, const std::string& name, if (m_selected_track) { - if (getWidget("favorite")->getState()) - { - if(PlayerManager::getCurrentPlayer()->isFavoriteTrack(m_selected_track->getIdent())) - PlayerManager::getCurrentPlayer()->removeFavoriteTrack(m_selected_track->getIdent()); - else - PlayerManager::getCurrentPlayer()->addFavoriteTrack(m_selected_track->getIdent()); - - buildTrackList(); - } - else if (STKHost::existHost()) + if (STKHost::existHost()) { w2->setBadge(selection, OK_BADGE); voteForPlayer(); @@ -361,10 +344,6 @@ void TracksScreen::beforeAddingWidget() RibbonWidget* tabs = getWidget("trackgroups"); tabs->clearAllChildren(); - CheckBoxWidget* favorite_cb = getWidget("favorite"); - assert( favorite_cb != NULL ); - favorite_cb->setState(false); - RaceManager::MinorRaceModeType minor_mode = RaceManager::get()->getMinorMode(); bool is_soccer = minor_mode == RaceManager::MINOR_MODE_SOCCER; bool is_arena = is_soccer || RaceManager::get()->isBattleMode(); From e2b2a1c65841a79708cb3f67523d8d6071660f54 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Wed, 8 Jan 2025 15:41:02 +0100 Subject: [PATCH 521/830] Fix #5014 The TextBoxWidget relies under the hood on IGUIEditBox and behaves in a peculiar way. How exactly both the 'send' button and the chat box could be simultaneously active is unclear beyond involving use of both keyboard and mouse, and the underlying issue will likely remain until a deeper overhaul. In the meantime, simply selecting back the chatbox after the send box has been triggered ensures that at most one line will be affected, and is convenient in other situations where the send box is used. --- src/states_screens/online/networking_lobby.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/states_screens/online/networking_lobby.cpp b/src/states_screens/online/networking_lobby.cpp index 217653c33fa..94caa412429 100644 --- a/src/states_screens/online/networking_lobby.cpp +++ b/src/states_screens/online/networking_lobby.cpp @@ -841,6 +841,7 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name, { onEnterPressed(m_chat_box->getText()); m_chat_box->setText(""); + m_chat_box->setFocusForPlayer(PLAYER_ID_GAME_MASTER); } // send chat message else if (name == m_emoji_button->m_properties[PROP_ID] && !ScreenKeyboard::isActive()) From 8a46f5a6a9f289453d87b11b3cda13608fcbb24d Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 10 Jan 2025 20:01:37 +0100 Subject: [PATCH 522/830] Introduce super-sampling options Allow to set the render scale over 100%, with presets at 125%, 150% and 200%. Users with powerful GPUs can therefore get a higher quality image at the cost of performance. Render scale increase the vertical resolution and horizontal resolution by the scaling factor, 125% is therefore 1.56x more pixels than native, 150% is 2.25x more and 200% is 4x more pixels. --- src/states_screens/options/options_screen_video.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/states_screens/options/options_screen_video.cpp b/src/states_screens/options/options_screen_video.cpp index 3cfa5db2910..5c6423bea21 100644 --- a/src/states_screens/options/options_screen_video.cpp +++ b/src/states_screens/options/options_screen_video.cpp @@ -124,6 +124,9 @@ void OptionsScreenVideo::initPresets() m_scale_rtts_custom_presets.push_back({ 0.9f }); m_scale_rtts_custom_presets.push_back({ 0.95f }); m_scale_rtts_custom_presets.push_back({ 1.0f }); + m_scale_rtts_custom_presets.push_back({ 1.25f }); + m_scale_rtts_custom_presets.push_back({ 1.5f }); + m_scale_rtts_custom_presets.push_back({ 2.0f }); } // initPresets @@ -292,6 +295,9 @@ void OptionsScreenVideo::init() scale_rtts->addLabel("90%"); scale_rtts->addLabel("95%"); scale_rtts->addLabel("100%"); + scale_rtts->addLabel("125%"); + scale_rtts->addLabel("150%"); + scale_rtts->addLabel("200%"); // --- set gfx settings values updateGfxSlider(); From d7981c0714b3550eda50d7319ea41908bacc6784 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 11 Jan 2025 23:31:59 +0400 Subject: [PATCH 523/830] Remove unused variables, fix #5161 (#5241) Previously some of them were commented in one file without realizing they are extern in another file. --- .../BroadphaseCollision/btAxisSweep3.h | 3 --- .../BroadphaseCollision/btMultiSapBroadphase.cpp | 2 -- .../btOverlappingPairCache.cpp | 15 --------------- .../BroadphaseCollision/btOverlappingPairCache.h | 5 ----- .../BroadphaseCollision/btSimpleBroadphase.cpp | 3 --- 5 files changed, 28 deletions(-) diff --git a/lib/bullet/src/BulletCollision/BroadphaseCollision/btAxisSweep3.h b/lib/bullet/src/BulletCollision/BroadphaseCollision/btAxisSweep3.h index c47c20784b4..7b7293e15e0 100644 --- a/lib/bullet/src/BulletCollision/BroadphaseCollision/btAxisSweep3.h +++ b/lib/bullet/src/BulletCollision/BroadphaseCollision/btAxisSweep3.h @@ -628,8 +628,6 @@ void btAxisSweep3Internal::resetPool(btDispatcher* dispatcher) } } - -extern int gOverlappingPairs; //#include template @@ -696,7 +694,6 @@ void btAxisSweep3Internal::calculateOverlappingPairs(btDispatche pair.m_pProxy0 = 0; pair.m_pProxy1 = 0; m_invalidPair++; - //gOverlappingPairs--; } } diff --git a/lib/bullet/src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.cpp b/lib/bullet/src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.cpp index 6712f528e97..43fdc39fac3 100644 --- a/lib/bullet/src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.cpp +++ b/lib/bullet/src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.cpp @@ -22,7 +22,6 @@ subject to the following restrictions: /// btSapBroadphaseArray m_sapBroadphases; /// btOverlappingPairCache* m_overlappingPairs; -extern int gOverlappingPairs; /* class btMultiSapSortedOverlappingPairCache : public btSortedOverlappingPairCache @@ -429,7 +428,6 @@ void btMultiSapBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher pair.m_pProxy0 = 0; pair.m_pProxy1 = 0; m_invalidPair++; - gOverlappingPairs--; } } diff --git a/lib/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp b/lib/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp index 7ed226fd463..7fece0e3ac0 100644 --- a/lib/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp +++ b/lib/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp @@ -23,11 +23,6 @@ subject to the following restrictions: #include -//int gOverlappingPairs = 0; - -//int gRemovePairs =0; -//int gAddedPairs =0; -//int gFindPairs =0; @@ -135,7 +130,6 @@ void btHashedOverlappingPairCache::removeOverlappingPairsContainingProxy(btBroad btBroadphasePair* btHashedOverlappingPairCache::findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) { - //gFindPairs++; if(proxy0->m_uniqueId>proxy1->m_uniqueId) btSwap(proxy0,proxy1); int proxyId1 = proxy0->getUid(); @@ -272,7 +266,6 @@ btBroadphasePair* btHashedOverlappingPairCache::internalAddPair(btBroadphaseProx void* btHashedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1,btDispatcher* dispatcher) { - //gRemovePairs++; if(proxy0->m_uniqueId>proxy1->m_uniqueId) btSwap(proxy0,proxy1); int proxyId1 = proxy0->getUid(); @@ -387,8 +380,6 @@ void btHashedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* if (callback->processOverlap(*pair)) { removeOverlappingPair(pair->m_pProxy0,pair->m_pProxy1,dispatcher); - - //gOverlappingPairs--; } else { i++; @@ -436,7 +427,6 @@ void* btSortedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* pro int findIndex = m_overlappingPairArray.findLinearSearch(findPair); if (findIndex < m_overlappingPairArray.size()) { - //gOverlappingPairs--; btBroadphasePair& pair = m_overlappingPairArray[findIndex]; void* userData = pair.m_internalInfo1; cleanOverlappingPair(pair,dispatcher); @@ -470,9 +460,6 @@ btBroadphasePair* btSortedOverlappingPairCache::addOverlappingPair(btBroadphaseP void* mem = &m_overlappingPairArray.expandNonInitializing(); btBroadphasePair* pair = new (mem) btBroadphasePair(*proxy0,*proxy1); - //gOverlappingPairs++; - //gAddedPairs++; - if (m_ghostPairCallback) m_ghostPairCallback->addOverlappingPair(proxy0, proxy1); return pair; @@ -527,7 +514,6 @@ void btSortedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* pair->m_pProxy1 = 0; m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); m_overlappingPairArray.pop_back(); - //gOverlappingPairs--; } else { i++; @@ -560,7 +546,6 @@ void btSortedOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair,b pair.m_algorithm->~btCollisionAlgorithm(); dispatcher->freeCollisionAlgorithm(pair.m_algorithm); pair.m_algorithm=0; - //gRemovePairs--; } } } diff --git a/lib/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h b/lib/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h index a1cafb762eb..aed8e745a6f 100644 --- a/lib/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h +++ b/lib/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h @@ -49,9 +49,6 @@ struct btOverlapFilterCallback -extern int gRemovePairs; -extern int gAddedPairs; -extern int gFindPairs; const int BT_NULL_PAIR=0xffffffff; @@ -121,8 +118,6 @@ class btHashedOverlappingPairCache : public btOverlappingPairCache // no new pair is created and the old one is returned. virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) { - //gAddedPairs++; - if (!needsBroadphaseCollision(proxy0,proxy1)) return 0; diff --git a/lib/bullet/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp b/lib/bullet/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp index 752fcd0fef2..d15b3d1a25d 100644 --- a/lib/bullet/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp +++ b/lib/bullet/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp @@ -24,8 +24,6 @@ subject to the following restrictions: #include -extern int gOverlappingPairs; - void btSimpleBroadphase::validate() { for (int i=0;i Date: Sat, 11 Jan 2025 22:09:14 +0100 Subject: [PATCH 524/830] Add shaderc deps initialization to the android build script. --- android/make_deps.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/android/make_deps.sh b/android/make_deps.sh index 6d89eb07a25..445ac74c361 100755 --- a/android/make_deps.sh +++ b/android/make_deps.sh @@ -291,6 +291,13 @@ build_deps() cp -a -f "$DIRNAME/../lib/shaderc/"* "$DIRNAME/deps-$ARCH_OPTION/shaderc" cd "$DIRNAME/deps-$ARCH_OPTION/shaderc" + + if [ ! -f "$DIRNAME/deps-$ARCH_OPTION/shaderc-deps.stamp" ]; then + ./utils/git-sync-deps + check_error + touch "$DIRNAME/deps-$ARCH_OPTION/shaderc-deps.stamp" + fi + cmake . -DCMAKE_TOOLCHAIN_FILE=../../../cmake/Toolchain-android.cmake \ -DHOST=$HOST -DARCH=$ARCH -DCMAKE_C_FLAGS="-fpic -O3" \ -DCMAKE_CXX_FLAGS="-fpic -O3" -DSHADERC_SKIP_INSTALL=1 \ From 86bbcd15cbf20c739211bbc4023a21824b36526c Mon Sep 17 00:00:00 2001 From: Deve Date: Sat, 11 Jan 2025 22:19:57 +0100 Subject: [PATCH 525/830] Initialize shaderc deps for linux build script in the same way as for android. --- tools/linux_builder.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/linux_builder.sh b/tools/linux_builder.sh index c71ddb21d62..9c511fdf247 100755 --- a/tools/linux_builder.sh +++ b/tools/linux_builder.sh @@ -395,13 +395,17 @@ build_stk() # Shaderc if [ ! -f "$DEPENDENCIES_DIR/shaderc.stamp" ]; then echo "Compiling shaderc" - - "$DEPENDENCIES_DIR/../lib/shaderc/utils/git-sync-deps" - mkdir -p "$DEPENDENCIES_DIR/shaderc" cp -a -f "$DEPENDENCIES_DIR/../lib/shaderc/"* "$DEPENDENCIES_DIR/shaderc" - + cd "$DEPENDENCIES_DIR/shaderc" + + if [ ! -f "$DEPENDENCIES_DIR/shaderc-deps.stamp" ]; then + ./utils/git-sync-deps + check_error + touch "$DEPENDENCIES_DIR/shaderc-deps.stamp" + fi + cmake . -DCMAKE_FIND_ROOT_PATH="$INSTALL_DIR" \ -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" \ -DCMAKE_C_FLAGS="-fpic -O3" \ From f8c6c66d157adc18fa87cfd0ddd8a692c4f75846 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 12 Jan 2025 15:27:25 +0800 Subject: [PATCH 526/830] Fix memory corruption with shared wheel and headlight, see #5240 --- src/karts/kart_model.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index 933cd13a1c4..ccc4632ad1f 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -267,7 +267,8 @@ KartModel::~KartModel() if(m_is_master && m_wheel_model[i]) { irr_driver->dropAllTextures(m_wheel_model[i]); - irr_driver->removeMeshFromCache(m_wheel_model[i]); + if (m_wheel_model[i]->getReferenceCount() == 1) + irr_driver->removeMeshFromCache(m_wheel_model[i]); } } From 097fa70658c2efe8d80c091146b188aa42f401a3 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 13 Jan 2025 23:38:28 +0400 Subject: [PATCH 527/830] Apply different conditions in checkPeersReady based on when it's called --- src/network/protocols/server_lobby.cpp | 14 ++++++++------ src/network/protocols/server_lobby.hpp | 9 ++++++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 36d2e058b80..b2813408f6e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1123,7 +1123,7 @@ void ServerLobby::asynchronousUpdate() } if ((!ServerConfig::m_soccer_tournament && m_timeout.load() < (int64_t)StkTime::getMonoTimeMs()) || - (checkPeersReady(true/*ignore_ai_peer*/, true/*before_start*/) && + (checkPeersReady(true/*ignore_ai_peer*/, BEFORE_SELECTION) && (int)players >= starting_limit)) { resetPeersReady(); @@ -1166,7 +1166,7 @@ void ServerLobby::asynchronousUpdate() if (m_server_has_loaded_world.load() == false) return; if (!checkPeersReady( - ServerConfig::m_ai_handling && m_ai_count == 0/*ignore_ai_peer*/)) + ServerConfig::m_ai_handling && m_ai_count == 0/*ignore_ai_peer*/, LOADING_WORLD)) return; // Reset for next state usage resetPeersReady(); @@ -2083,7 +2083,7 @@ void ServerLobby::update(int ticks) Log::info("ServerLobby", "End of game message sent"); break; case RESULT_DISPLAY: - if (checkPeersReady(true/*ignore_ai_peer*/) || + if (checkPeersReady(true/*ignore_ai_peer*/, AFTER_GAME) || (int64_t)StkTime::getMonoTimeMs() > m_timeout.load()) { // Send a notification to all clients to exit @@ -5304,7 +5304,7 @@ bool ServerLobby::supportsAI() } // supportsAI //----------------------------------------------------------------------------- -bool ServerLobby::checkPeersReady(bool ignore_ai_peer, bool before_start) +bool ServerLobby::checkPeersReady(bool ignore_ai_peer, SelectionPhase phase) { bool all_ready = true; bool someone_races = false; @@ -5313,11 +5313,13 @@ bool ServerLobby::checkPeersReady(bool ignore_ai_peer, bool before_start) auto peer = p.first.lock(); if (!peer) continue; - if (peer->alwaysSpectate()) + if (phase == BEFORE_SELECTION && peer->alwaysSpectate()) + continue; + if (phase == AFTER_GAME && peer->isSpectator()) continue; if (ignore_ai_peer && peer->isAIPeer()) continue; - if (before_start && !canRace(peer)) + if (phase == BEFORE_SELECTION && !canRace(peer)) continue; someone_races = true; all_ready = all_ready && p.second; diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 53804fe245d..3c991eec8b6 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -94,6 +94,13 @@ class ServerLobby : public LobbyProtocol ERROR_LEAVE, // shutting down server EXITING }; + + enum SelectionPhase: unsigned int + { + BEFORE_SELECTION = 0, + LOADING_WORLD = 1, + AFTER_GAME = 2, + }; private: struct KeyData { @@ -408,7 +415,7 @@ class ServerLobby : public LobbyProtocol void handleServerConfiguration(std::shared_ptr peer, int difficulty, int mode, bool soccer_goal_target); void updateTracksForMode(); - bool checkPeersReady(bool ignore_ai_peer, bool before_start = false); + bool checkPeersReady(bool ignore_ai_peer, SelectionPhase phase); void resetPeersReady() { for (auto it = m_peers_ready.begin(); it != m_peers_ready.end();) From 74b82ca0bb34ba31cfb5fa26f20e6e5d624f9d99 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 14 Jan 2025 19:42:31 +0400 Subject: [PATCH 528/830] Minor fixes for command manager --- src/network/protocols/command_manager.cpp | 132 ++++++++++------------ src/network/protocols/command_manager.hpp | 16 --- 2 files changed, 60 insertions(+), 88 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 21e9a6f5269..942af04fdc0 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -19,44 +19,17 @@ #include "network/protocols/command_manager.hpp" #include "addons/addon.hpp" -// #include "config/user_config.hpp" #include "io/file_manager.hpp" -// #include "items/network_item_manager.hpp" -// #include "items/powerup_manager.hpp" -// #include "items/attachment.hpp" -// #include "karts/controller/player_controller.hpp" -// #include "karts/kart_properties.hpp" -// #include "karts/kart_properties_manager.hpp" -// #include "karts/official_karts.hpp" -// #include "modes/capture_the_flag.hpp" #include "modes/soccer_world.hpp" -// #include "modes/linear_world.hpp" #include "network/crypto.hpp" #include "network/database_connector.hpp" #include "network/event.hpp" #include "network/game_setup.hpp" -// #include "network/network.hpp" -// #include "network/network_config.hpp" #include "network/network_player_profile.hpp" -// #include "network/peer_vote.hpp" -// #include "network/protocol_manager.hpp" -// #include "network/protocols/connect_to_peer.hpp" -#include "network/protocols/command_permissions.hpp" -// #include "network/protocols/command_voting.hpp" -// #include "network/protocols/game_protocol.hpp" -// #include "network/protocols/game_events_protocol.hpp" #include "network/protocols/server_lobby.hpp" -// #include "network/race_event_manager.hpp" #include "network/server_config.hpp" -// #include "network/socket_address.hpp" #include "network/stk_host.hpp" -// #include "network/stk_ipv6.hpp" #include "network/stk_peer.hpp" -// #include "online/online_profile.hpp" -// #include "online/request_manager.hpp" -// #include "online/xml_request.hpp" -// #include "race/race_manager.hpp" -// #include "tracks/check_manager.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/file_utils.hpp" @@ -64,8 +37,6 @@ #include "utils/log.hpp" #include "utils/random_generator.hpp" #include "utils/string_utils.hpp" -// #include "utils/time.hpp" -// #include "utils/translation.hpp" #include #include @@ -75,23 +46,74 @@ #include #include -std::vector CommandManager::QUEUE_NAMES = { - "", "mqueue", "mcyclic", "mboth", - "kqueue", "qregular", "", "", - "kcyclic", "", "qcyclic", "", - "kboth", "", "", "qboth" -}; +namespace +{ + const std::vector g_queue_names = { + "", "mqueue", "mcyclic", "mboth", + "kqueue", "qregular", "", "", + "kcyclic", "", "qcyclic", "", + "kboth", "", "", "qboth" + }; + + enum QueueMask: int { + QM_NONE = -1, + QM_MAP_ONETIME = 1, + QM_MAP_CYCLIC = 2, + QM_KART_ONETIME = 4, + QM_KART_CYCLIC = 8, + QM_ALL_MAP_QUEUES = QM_MAP_ONETIME | QM_MAP_CYCLIC, + QM_ALL_KART_QUEUES = QM_KART_ONETIME | QM_KART_CYCLIC, + QM_START = 1, + QM_END = 16 + }; // enum QueueMask + + int get_queue_mask(std::string a) + { + for (int i = 0; i < (int)g_queue_names.size(); i++) + if (a == g_queue_names[i]) + return i; + return QueueMask::QM_NONE; + } // get_queue_mask + // ==================================================================== + + std::string get_queue_name(int x) + { + if (x == QM_MAP_ONETIME) + return "regular map queue"; + if (x == QM_MAP_CYCLIC) + return "cyclic map queue"; + if (x == QM_KART_ONETIME) + return "regular kart queue"; + if (x == QM_KART_CYCLIC) + return "cyclic kart queue"; + return StringUtils::insertValues( + "[Error QN%d: please report with /tell about it] queue", x); + } // get_queue_name + // ==================================================================== + + int another_cyclic_queue(int x) + { + if (x == QM_MAP_ONETIME) + return QM_MAP_CYCLIC; + // if (x == QM_KART_ONETIME) + // return QM_KART_CYCLIC; + return QM_NONE; + } // another_cyclic_queue + // ==================================================================== + +} // namespace -// ======================================================================== EnumExtendedReader CommandManager::mode_scope_reader({ {"MS_DEFAULT", MS_DEFAULT}, {"MS_SOCCER_TOURNAMENT", MS_SOCCER_TOURNAMENT} }); + EnumExtendedReader CommandManager::state_scope_reader({ {"SS_LOBBY", SS_LOBBY}, {"SS_INGAME", SS_INGAME}, {"SS_ALWAYS", SS_ALWAYS} }); + EnumExtendedReader CommandManager::permission_reader({ {"PE_NONE", PE_NONE}, {"PE_SPECTATOR", PE_SPECTATOR}, @@ -427,9 +449,9 @@ void CommandManager::initCommands() applyFunctionIfPossible("length x", &CM::process_length_multi); applyFunctionIfPossible("direction", &CM::process_direction); applyFunctionIfPossible("direction =", &CM::process_direction_assign); - for (int i = 0; i < (int)QUEUE_NAMES.size(); i++) + for (int i = 0; i < (int)g_queue_names.size(); i++) { - const std::string& name = QUEUE_NAMES[i]; + const std::string& name = g_queue_names[i]; if (name.empty()) continue; applyFunctionIfPossible(name + "", &CM::process_queue); @@ -4446,15 +4468,6 @@ std::string CommandManager::getAddonPreferredType() const } // getAddonPreferredType // ======================================================================== -int CommandManager::get_queue_mask(std::string a) -{ - for (int i = 0; i < (int)QUEUE_NAMES.size(); i++) - if (a == QUEUE_NAMES[i]) - return i; - return QM_NONE; -} // getAddonPreferredType -// ======================================================================== - std::deque>& CommandManager::get_queue(int x) const { if (x == QM_MAP_ONETIME) @@ -4472,31 +4485,6 @@ std::deque>& CommandManager::get_queue(int x) const } // get_queue // ======================================================================== -std::string CommandManager::get_queue_name(int x) -{ - if (x == QM_MAP_ONETIME) - return "regular map queue"; - if (x == QM_MAP_CYCLIC) - return "cyclic map queue"; - if (x == QM_KART_ONETIME) - return "regular kart queue"; - if (x == QM_KART_CYCLIC) - return "cyclic kart queue"; - return StringUtils::insertValues( - "[Error QN%d: please report with /tell about it] queue", x); -} // get_queue_name -// ======================================================================== - -int CommandManager::another_cyclic_queue(int x) -{ - if (x == QM_MAP_ONETIME) - return QM_MAP_CYCLIC; - // if (x == QM_KART_ONETIME) - // return QM_KART_CYCLIC; - return QM_NONE; -} // get_queue_name -// ======================================================================== - template void CommandManager::add_to_queue(int x, int mask, bool to_front, std::string& s) const { diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 25ae6d07929..dafda8ac842 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -82,23 +82,7 @@ class CommandManager static EnumExtendedReader mode_scope_reader; static EnumExtendedReader state_scope_reader; - enum QueueMask: int { - QM_NONE = -1, - QM_MAP_ONETIME = 1, - QM_MAP_CYCLIC = 2, - QM_KART_ONETIME = 4, - QM_KART_CYCLIC = 8, - QM_ALL_MAP_QUEUES = QM_MAP_ONETIME | QM_MAP_CYCLIC, - QM_ALL_KART_QUEUES = QM_KART_ONETIME | QM_KART_CYCLIC, - QM_START = 1, - QM_END = 16 - }; - - static std::vector QUEUE_NAMES; - static int get_queue_mask(std::string a); std::deque>& get_queue(int x) const; - static std::string get_queue_name(int x); - static int another_cyclic_queue(int x); template void add_to_queue(int x, int mask, bool to_front, std::string& s) const; From 13ba4b38e7b30f77252f0e238cc4ed0c460b5b17 Mon Sep 17 00:00:00 2001 From: "Molly M.B. Maclachlan" Date: Fri, 17 Jan 2025 17:01:18 +0000 Subject: [PATCH 529/830] Removed glow under main menu options, see #5109 (#5245) --- src/guiengine/skin.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index 9a674c75b16..e4e1569d6eb 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -1424,10 +1424,11 @@ void Skin::drawRibbonChild(const core::recti &rect, Widget* widget, } const bool mark_focused = - focused || (parent_focused && parentRibbonWidget != NULL && + (focused || (parent_focused && parentRibbonWidget != NULL && parentRibbonWidget->m_mouse_focus == widget) || (mark_selected && !always_show_selection && - parent_focused); + parent_focused)) && + widget->m_properties[PROP_FOCUS_ICON].size() == 0; /* draw "selection bubble" if relevant */ if (always_show_selection && mark_selected) From 84830a726cdb0e0471c6931c43443f50f5e41fe6 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 18 Jan 2025 10:12:45 +0400 Subject: [PATCH 530/830] Minor fixes for database initialization scripts (#5248) --- NETWORKING.md | 2 +- tools/generate-countries-table.py | 2 +- tools/generate-ip-mappings.py | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index 91a4ce6516a..a86c27956de 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -360,7 +360,7 @@ CREATE TABLE ipv6_mapping latitude REAL NOT NULL, -- Latitude of this IP range longitude REAL NOT NULL, -- Longitude of this IP range country_code TEXT NOT NULL -- 2-letter country code -) +); ``` For initialization of `ip_mapping` table, check [this script](tools/generate-ip-mappings.py). diff --git a/tools/generate-countries-table.py b/tools/generate-countries-table.py index a953704d30a..a7a714d4d42 100755 --- a/tools/generate-countries-table.py +++ b/tools/generate-countries-table.py @@ -6,7 +6,7 @@ # .mode csv # .headers off # .separator ";" -# .import `full path to countries.csv` `v(database_version)_countries` +# .import 'full path to countries.csv' 'v(database_version)_countries' # import csv diff --git a/tools/generate-ip-mappings.py b/tools/generate-ip-mappings.py index 5f3fd86d904..0967ba6bdd2 100755 --- a/tools/generate-ip-mappings.py +++ b/tools/generate-ip-mappings.py @@ -4,8 +4,8 @@ # in sqlite3 terminal: # # .mode csv -# .import `full path to ipv4.csv` ip_mapping -# .import `full path to ipv6.csv` ipv6_mapping +# .import 'full path to ipv4.csv' ip_mapping +# .import 'full path to ipv6.csv' ipv6_mapping # # For query by ip: @@ -27,8 +27,8 @@ def ipv62int64(addr): hi, lo = struct.unpack('!QQ', socket.inet_pton(socket.AF_INET6, addr)) return hi -CSV_WEB_LINK = 'https://download.db-ip.com/free/dbip-city-lite-2020-01.csv.gz' -CSV_FILE = 'dbip-city-lite-2020-01.csv' +CSV_WEB_LINK = 'https://download.db-ip.com/free/dbip-city-lite-2025-01.csv.gz' +CSV_FILE = 'dbip-city-lite-2025-01.csv' if not os.path.exists(CSV_FILE): print("File = {} does not exist. Download it from = {} ".format(CSV_FILE, CSV_WEB_LINK)) @@ -42,7 +42,7 @@ def ipv62int64(addr): if row[3] == "ZZ": continue # Skip empty latitude and longitude - if row[6] is "" or row[7] is "": + if row[6] == "" or row[7] == "": continue if row[0].find(':') == -1: From b180a49600ea530bbc1f455bfd56889919992043 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sat, 18 Jan 2025 15:09:54 +0800 Subject: [PATCH 531/830] Make SSAO correct (#5249) * Removed glow under main menu options, see #5109 * Much better SSAO * Fix shader bug * Increase kernel size * Increase kernel size & bring back pute shader * Reduce sample to 4 * Fix black line * Stronger bias when resolution is lower --- data/shaders/IBL.frag | 28 +++++++++++-- data/shaders/bilateralH.comp | 34 ++++++++-------- data/shaders/bilateralH.frag | 4 +- data/shaders/bilateralV.comp | 34 ++++++++-------- data/shaders/bilateralV.frag | 4 +- data/shaders/combine_diffuse_color.frag | 4 +- data/shaders/degraded_ibl.frag | 7 +++- data/shaders/ssao.frag | 44 ++++++++++++++------- src/graphics/lighting_passes.cpp | 27 +++++++++---- src/graphics/lighting_passes.hpp | 6 ++- src/graphics/post_processing.cpp | 52 ++++++++++++------------- src/graphics/post_processing.hpp | 2 +- src/graphics/shader_based_renderer.cpp | 38 +++++++++--------- src/tracks/track.cpp | 4 +- 14 files changed, 170 insertions(+), 118 deletions(-) diff --git a/data/shaders/IBL.frag b/data/shaders/IBL.frag index d1e3b2964f4..9292a9c9967 100644 --- a/data/shaders/IBL.frag +++ b/data/shaders/IBL.frag @@ -1,6 +1,8 @@ uniform sampler2D ntex; uniform sampler2D dtex; uniform sampler2D albedo; +uniform sampler2D ssao; +uniform sampler2D ctex; #ifdef GL_ES layout (location = 0) out vec4 Diff; @@ -70,6 +72,16 @@ vec2 RayCast(vec3 dir, vec3 hitCoord) } } +vec3 gtaoMultiBounce(float visibility, vec3 albedo) +{ + // Jimenez et al. 2016, "Practical Realtime Strategies for Accurate Indirect Occlusion" + vec3 a = 2.0404 * albedo - 0.3324; + vec3 b = -4.7951 * albedo + 0.6417; + vec3 c = 2.7552 * albedo + 0.6903; + + return max(vec3(visibility), ((visibility * a + b) * visibility + c) * visibility); +} + // Main =================================================================== void main(void) @@ -77,8 +89,6 @@ void main(void) vec2 uv = gl_FragCoord.xy / u_screen; vec3 normal = DecodeNormal(texture(ntex, uv).xy); - Diff = vec4(0.25 * DiffuseIBL(normal), 1.); - float z = texture(dtex, uv).x; vec4 xpos = getPosFromUVDepth(vec3(uv, z), u_inverse_projection_matrix); @@ -86,9 +96,18 @@ void main(void) // Extract roughness float specval = texture(ntex, uv).z; + float ao = texture(ssao, uv).x; + // Lagarde and de Rousiers 2014, "Moving Frostbite to PBR" + float ao_spec = clamp(pow(max(dot(normal, eyedir), 0.) + ao, exp2(-16.0 * (1.0 - specval) - 1.0)) - 1.0 + ao, 0.0, 1.0); + #ifdef GL_ES - Spec = vec4(.25 * SpecularIBL(normal, eyedir, specval), 1.); + Diff = vec4(0.25 * DiffuseIBL(normal) * ao, 1.); + Spec = vec4(.25 * SpecularIBL(normal, eyedir, specval) * ao_spec, 1.); #else + vec3 surface_color = texture(ctex, uv).xyz; + vec3 ao_multi = gtaoMultiBounce(ao, surface_color); + vec3 ao_spec_multi = gtaoMultiBounce(ao_spec, surface_color); + // :::::::: Compute Space Screen Reflection :::::::::::::::::::::::::::::::::::: // Output color @@ -123,7 +142,8 @@ void main(void) outColor = fallback; } - Spec = vec4(outColor.rgb, 1.0); + Diff = vec4(0.25 * DiffuseIBL(normal) * ao_multi, 1.); + Spec = vec4(outColor.rgb * ao_spec_multi, 1.0); #endif } diff --git a/data/shaders/bilateralH.comp b/data/shaders/bilateralH.comp index e1e8435f130..523b83933b8 100644 --- a/data/shaders/bilateralH.comp +++ b/data/shaders/bilateralH.comp @@ -4,27 +4,27 @@ uniform sampler2D source; uniform sampler2D depth; uniform vec2 pixel; layout(r16f) volatile restrict writeonly uniform image2D dest; -uniform float sigma = 5.; +uniform float sigma = 2.; -layout (local_size_x = 8, local_size_y = 8) in; +layout (local_size_x = 4, local_size_y = 4) in; -shared float local_src[8 + 2 * 8][8]; -shared float local_depth[8 + 2 * 8][8]; +shared float local_src[4 + 2 * 4][4]; +shared float local_depth[4 + 2 * 4][4]; void main() { int x = int(gl_LocalInvocationID.x), y = int(gl_LocalInvocationID.y); ivec2 iuv = ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y); - vec2 uv_m = (iuv - ivec2(8, 0)) * pixel; + vec2 uv_m = (iuv - ivec2(4, 0)) * pixel; vec2 uv = iuv * pixel; - vec2 uv_p = (iuv + ivec2(8, 0)) * pixel; + vec2 uv_p = (iuv + ivec2(4, 0)) * pixel; local_src[x][y] = texture(source, uv_m).x; local_depth[x][y] = texture(depth, uv_m).x; - local_src[x + 8][y] = texture(source, uv).x; - local_depth[x + 8][y] = texture(depth, uv).x; - local_src[x + 16][y] = texture(source, uv_p).x; - local_depth[x + 16][y] = texture(depth, uv_p).x; + local_src[x + 4][y] = texture(source, uv).x; + local_depth[x + 4][y] = texture(depth, uv).x; + local_src[x + 8][y] = texture(source, uv_p).x; + local_depth[x + 8][y] = texture(depth, uv_p).x; barrier(); @@ -32,18 +32,18 @@ void main() g0 = 1.0 / (sqrt(2.0 * 3.14) * sigma); g1 = exp(-0.5 / (sigma * sigma)); g2 = g1 * g1; - float sum = local_src[x + 8][y] * g0; - float pixel_depth = local_depth[x + 8][y]; + float sum = local_src[x + 4][y] * g0; + float pixel_depth = local_depth[x + 4][y]; g0 *= g1; g1 *= g2; float tmp_weight, total_weight = g0; - for (int j = 1; j < 8; j++) { - tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[8 + x - j][y] - pixel_depth)); + for (int j = 1; j < 5; j++) { + tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[4 + x - j][y] - pixel_depth)); total_weight += g0 * tmp_weight; - sum += local_src[8 + x - j][y] * g0 * tmp_weight; - tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[8 + x + j][y] - pixel_depth)); + sum += local_src[4 + x - j][y] * g0 * tmp_weight; + tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[4 + x + j][y] - pixel_depth)); total_weight += g0 * tmp_weight; - sum += local_src[8 + x + j][y] * g0 * tmp_weight; + sum += local_src[4 + x + j][y] * g0 * tmp_weight; g0 *= g1; g1 *= g2; } diff --git a/data/shaders/bilateralH.frag b/data/shaders/bilateralH.frag index 61c7565362d..87ba1bc1dc4 100644 --- a/data/shaders/bilateralH.frag +++ b/data/shaders/bilateralH.frag @@ -8,7 +8,7 @@ out vec4 FragColor; void main() { - float sigma = 5.; + float sigma = 2.; vec2 uv = gl_FragCoord.xy * pixel; float X = uv.x; @@ -23,7 +23,7 @@ void main() g0 *= g1; g1 *= g2; float tmp_weight, total_weight = g0; - for (int i = 1; i < 9; i++) { + for (int i = 1; i < 5; i++) { tmp_weight = max(0.0, 1.0 - .001 * abs(texture(depth, vec2(X - float(i) * pixel.x, Y)).x - pixel_depth)); sum += texture(tex, vec2(X - float(i) * pixel.x, Y)) * g0 * tmp_weight; total_weight += g0 * tmp_weight; diff --git a/data/shaders/bilateralV.comp b/data/shaders/bilateralV.comp index a9cff8a6f6b..e51b3b386b8 100644 --- a/data/shaders/bilateralV.comp +++ b/data/shaders/bilateralV.comp @@ -4,27 +4,27 @@ uniform sampler2D source; uniform sampler2D depth; uniform vec2 pixel; layout(r16f) volatile restrict writeonly uniform image2D dest; -uniform float sigma = 5.; +uniform float sigma = 2.; -layout (local_size_x = 8, local_size_y = 8) in; +layout (local_size_x = 4, local_size_y = 4) in; -shared float local_src[8][8 + 2 * 8]; -shared float local_depth[8][8 + 2 * 8]; +shared float local_src[4][4 + 2 * 4]; +shared float local_depth[4][4 + 2 * 4]; void main() { int x = int(gl_LocalInvocationID.x), y = int(gl_LocalInvocationID.y); ivec2 iuv = ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y); - vec2 uv_m = (iuv - ivec2(0, 8)) * pixel; + vec2 uv_m = (iuv - ivec2(0, 4)) * pixel; vec2 uv = iuv * pixel; - vec2 uv_p = (iuv + ivec2(0, 8)) * pixel; + vec2 uv_p = (iuv + ivec2(0, 4)) * pixel; local_src[x][y] = texture(source, uv_m).x; local_depth[x][y] = texture(depth, uv_m).x; - local_src[x][y + 8] = texture(source, uv).x; - local_depth[x][y + 8] = texture(depth, uv).x; - local_src[x][y + 16] = texture(source, uv_p).x; - local_depth[x][y + 16] = texture(depth, uv_p).x; + local_src[x][y + 4] = texture(source, uv).x; + local_depth[x][y + 4] = texture(depth, uv).x; + local_src[x][y + 8] = texture(source, uv_p).x; + local_depth[x][y + 8] = texture(depth, uv_p).x; barrier(); @@ -32,17 +32,17 @@ void main() g0 = 1.0 / (sqrt(2.0 * 3.14) * sigma); g1 = exp(-0.5 / (sigma * sigma)); g2 = g1 * g1; - float sum = local_src[x][y + 8] * g0; - float pixel_depth = local_depth[x][y + 8]; + float sum = local_src[x][y + 4] * g0; + float pixel_depth = local_depth[x][y + 4]; g0 *= g1; g1 *= g2; float tmp_weight, total_weight = g0; - for (int j = 1; j < 8; j++) { - tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[x][y + 8 + j] - pixel_depth)); - sum += local_src[x][y + 8 + j] * g0 * tmp_weight; + for (int j = 1; j < 5; j++) { + tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[x][y + 4 + j] - pixel_depth)); + sum += local_src[x][y + 4 + j] * g0 * tmp_weight; total_weight += g0 * tmp_weight; - tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[x][y + 8 - j] - pixel_depth)); - sum += local_src[x][y + 8 - j] * g0 * tmp_weight; + tmp_weight = max(0.0, 1.0 - .001 * abs(local_depth[x][y + 4 - j] - pixel_depth)); + sum += local_src[x][y + 4 - j] * g0 * tmp_weight; total_weight += g0 * tmp_weight; g0 *= g1; g1 *= g2; diff --git a/data/shaders/bilateralV.frag b/data/shaders/bilateralV.frag index 1779eb34e8d..d490e7dd9b3 100644 --- a/data/shaders/bilateralV.frag +++ b/data/shaders/bilateralV.frag @@ -8,7 +8,7 @@ out vec4 FragColor; void main() { - float sigma = 5.; + float sigma = 2.; vec2 uv = gl_FragCoord.xy * pixel; float X = uv.x; @@ -23,7 +23,7 @@ void main() g0 *= g1; g1 *= g2; float tmp_weight, total_weight = g0; - for (int i = 1; i < 9; i++) { + for (int i = 1; i < 5; i++) { tmp_weight = max(0.0, 1.0 - .001 * abs(texture(depth, vec2(X, Y - float(i) * pixel.y)).x - pixel_depth)); sum += texture(tex, vec2(X, Y - float(i) * pixel.y)) * g0 * tmp_weight; total_weight += g0 * tmp_weight; diff --git a/data/shaders/combine_diffuse_color.frag b/data/shaders/combine_diffuse_color.frag index af71349cf78..5b037751ceb 100644 --- a/data/shaders/combine_diffuse_color.frag +++ b/data/shaders/combine_diffuse_color.frag @@ -1,6 +1,5 @@ uniform sampler2D diffuse_map; uniform sampler2D specular_map; -uniform sampler2D ssao_tex; uniform sampler2D normal_color; uniform sampler2D diffuse_color; #if defined(GL_ES) && defined(GL_FRAGMENT_PRECISION_HIGH) @@ -28,7 +27,6 @@ void main() float specMapValue = texture(normal_color, tc).z; float emitMapValue = diffuseMatColor.w; - float ao = texture(ssao_tex, tc).x; vec3 DiffuseComponent = texture(diffuse_map, tc).xyz; vec3 SpecularComponent = texture(specular_map, tc).xyz; @@ -42,7 +40,7 @@ void main() vec3 tmp = DiffuseComponent * mix(diffuseMatColor.xyz, vec3(0.0), metallicMapValue) + (metallicMatColor * SpecularComponent); vec3 emitCol = diffuseMatColor.xyz + (diffuseMatColor.xyz * diffuseMatColor.xyz * emitMapValue * emitMapValue * 10.0); - vec4 color_1 = vec4(tmp * ao + (emitMapValue * emitCol), 1.0); + vec4 color_1 = vec4(tmp + (emitMapValue * emitCol), 1.0); // Fog float depth = texture(depth_stencil, tc).x; diff --git a/data/shaders/degraded_ibl.frag b/data/shaders/degraded_ibl.frag index af53a3a850f..ce712b1c857 100644 --- a/data/shaders/degraded_ibl.frag +++ b/data/shaders/degraded_ibl.frag @@ -1,4 +1,5 @@ uniform sampler2D ntex; +uniform sampler2D ssao; #ifdef GL_ES layout (location = 0) out vec4 Diff; @@ -17,7 +18,9 @@ void main(void) { vec2 uv = gl_FragCoord.xy / u_screen; vec3 normal = DecodeNormal(texture(ntex, uv).xy); + vec3 spec_color = vec3(0.031, 0.106, 0.173); + float ao = texture(ssao, uv).x; - Diff = vec4(0.25 * DiffuseIBL(normal), 1.); - Spec = vec4(0.031, 0.106, 0.173, 1.); + Diff = vec4(0.25 * DiffuseIBL(normal) * ao, 1.); + Spec = vec4(spec_color * ao, 1.); } diff --git a/data/shaders/ssao.frag b/data/shaders/ssao.frag index 3dee1176853..6b3b3b86f37 100644 --- a/data/shaders/ssao.frag +++ b/data/shaders/ssao.frag @@ -1,5 +1,6 @@ // From paper http://graphics.cs.williams.edu/papers/AlchemyHPG11/ // and improvements here http://graphics.cs.williams.edu/papers/SAOHPG12/ +// and implementations here https://github.com/google/filament/blob/026b985c07b7eec4f678e0e5130d0a4e742e9c61/filament/src/materials/ssao/saoImpl.fs uniform sampler2D dtex; uniform float radius; @@ -7,12 +8,10 @@ uniform float k; uniform float sigma; out float AO; -const float tau = 7.; -const float beta = 0.002; -const float epsilon = .00001; +const float thickness = 10.0; -#define SAMPLES 16 -const float invSamples = 0.0625; // 1. / SAMPLES +#define SAMPLES 4 +const float invSamples = 0.25; // 1. / SAMPLES vec3 getXcYcZc(int x, int y, float zC) { @@ -22,6 +21,12 @@ vec3 getXcYcZc(int x, int y, float zC) return vec3(xC, yC, zC); } +float interleavedGradientNoise(highp vec2 w) +{ + const vec3 m = vec3(0.06711056, 0.00583715, 52.9829189); + return fract(m.z * fract(dot(w, m.xy))); +} + void main(void) { vec2 uv = gl_FragCoord.xy / u_screen; @@ -35,31 +40,42 @@ void main(void) vec3 norm = normalize(cross(ddy, ddx)); float r = radius / FragPos.z; - float phi = 3. * float((x ^ y) + x * y); + float phi = interleavedGradientNoise(vec2(gl_FragCoord.x, gl_FragCoord.y)); float bl = 0.0; float m = log2(r) + 6. + log2(invSamples); - float theta = mod(2. * 3.14 * tau * .5 * invSamples + phi, 6.283185307179586); + float peak = 0.1 * radius; + float peak2 = peak * peak; + float intensity = 2.0 * 3.14159 * sigma * peak * invSamples; + + // Apply stronger bias when the resolution is lower. + float horizon = min(100. / min(u_screen.x, u_screen.y), 0.3); + float bias = min(1. / min(u_screen.x, u_screen.y), 0.003); + + float theta = phi * 2.0 * 2.4 * 3.14159; vec2 rotations = vec2(cos(theta), sin(theta)) * u_screen; vec2 offset = vec2(cos(invSamples), sin(invSamples)); - for(int i = 0; i < SAMPLES; ++i) { + for(int i = 0; i < SAMPLES; ++i) + { float alpha = (float(i) + .5) * invSamples; rotations = vec2(rotations.x * offset.x - rotations.y * offset.y, rotations.x * offset.y + rotations.y * offset.x); float h = r * alpha; vec2 localoffset = h * rotations; - m = m + .5; - ivec2 ioccluder_uv = ivec2(x, y) + ivec2(localoffset); - - if (ioccluder_uv.x < 0 || ioccluder_uv.x > int(u_screen.x) || ioccluder_uv.y < 0 || ioccluder_uv.y > int(u_screen.y)) continue; + ivec2 ioccluder_uv = clamp(ivec2(x, y) + ivec2(localoffset), ivec2(0), ivec2(u_screen)); float LinearoccluderFragmentDepth = textureLod(dtex, vec2(ioccluder_uv) / u_screen, max(m, 0.)).x; vec3 OccluderPos = getXcYcZc(ioccluder_uv.x, ioccluder_uv.y, LinearoccluderFragmentDepth); vec3 vi = OccluderPos - FragPos; - bl += max(0., dot(vi, norm) - FragPos.z * beta) / (dot(vi, vi) + epsilon); + float vv = dot(vi, vi); + float vn = dot(vi, norm); + float w = max(0.0, 1.0 - vv / thickness / thickness); + w = w * w; + w *= step(vv * horizon * horizon, vn * vn); + bl += w * max(0., vn - FragPos.z * bias) / (vv + peak); } - AO = max(pow(1.0 - min(2. * sigma * bl * invSamples, 0.99), k), 0.); + AO = pow(max(1.0 - sqrt(bl * intensity), 0.), k); } diff --git a/src/graphics/lighting_passes.cpp b/src/graphics/lighting_passes.cpp index d30c6cf4c7e..76459bb8954 100644 --- a/src/graphics/lighting_passes.cpp +++ b/src/graphics/lighting_passes.cpp @@ -170,7 +170,7 @@ class PointLightScatterShader : public TextureShader +class IBLShader : public TextureShader { public: IBLShader() @@ -181,12 +181,14 @@ class IBLShader : public TextureShader assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED, 1, "dtex", ST_NEAREST_FILTERED, 2, "probe", ST_TRILINEAR_CUBEMAP, - 3, "albedo",ST_NEAREST_FILTERED); + 3, "albedo",ST_NEAREST_FILTERED, + 4, "ssao", ST_NEAREST_FILTERED, + 5, "ctex", ST_NEAREST_FILTERED); } // IBLShader }; // IBLShader // ============================================================================ -class DegradedIBLShader : public TextureShader +class DegradedIBLShader : public TextureShader { public: DegradedIBLShader() @@ -194,7 +196,8 @@ class DegradedIBLShader : public TextureShader loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert", GL_FRAGMENT_SHADER, "degraded_ibl.frag"); assignUniforms(); - assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED); + assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED, + 1, "ssao", ST_NEAREST_FILTERED); } // DegradedIBLShader }; // DegradedIBLShader @@ -298,7 +301,9 @@ static void renderPointLights(unsigned count, void LightingPasses::renderEnvMap(GLuint normal_depth_texture, GLuint depth_stencil_texture, GLuint specular_probe, - GLuint albedo_buffer) + GLuint albedo_buffer, + GLuint ssao_texture, + GLuint diffuse_color_texture) { glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); @@ -311,7 +316,7 @@ void LightingPasses::renderEnvMap(GLuint normal_depth_texture, glBindVertexArray(SharedGPUObjects::getFullScreenQuadVAO()); DegradedIBLShader::getInstance() - ->setTextureUnits(normal_depth_texture); + ->setTextureUnits(normal_depth_texture, ssao_texture); DegradedIBLShader::getInstance()->setUniforms(); } else @@ -323,7 +328,9 @@ void LightingPasses::renderEnvMap(GLuint normal_depth_texture, normal_depth_texture, depth_stencil_texture, specular_probe, - albedo_buffer); + albedo_buffer, + ssao_texture, + diffuse_color_texture); IBLShader::getInstance()->setUniforms(); } @@ -434,6 +441,8 @@ void LightingPasses::renderLights( bool has_shadow, GLuint depth_stencil_texture, GLuint albedo_texture, const FrameBuffer* shadow_framebuffer, + GLuint ssao_texture, + GLuint diffuse_color_texture, GLuint specular_probe) { { @@ -441,7 +450,9 @@ void LightingPasses::renderLights( bool has_shadow, renderEnvMap(normal_depth_texture, depth_stencil_texture, specular_probe, - albedo_texture); + albedo_texture, + ssao_texture, + diffuse_color_texture); } // Render sunlight if and only if track supports shadow diff --git a/src/graphics/lighting_passes.hpp b/src/graphics/lighting_passes.hpp index 2655a4f50d8..aef150a52bc 100644 --- a/src/graphics/lighting_passes.hpp +++ b/src/graphics/lighting_passes.hpp @@ -47,7 +47,9 @@ class LightingPasses void renderEnvMap(GLuint normal_depth_texture, GLuint depth_stencil_texture, GLuint specular_probe, - GLuint albedo_buffer); + GLuint albedo_buffer, + GLuint ssao_buffer, + GLuint diffuse_color_texture); /** Generate diffuse and specular map */ void renderSunlight(const core::vector3df &direction, @@ -65,6 +67,8 @@ class LightingPasses GLuint depth_stencil_texture, GLuint albedo_texture, const FrameBuffer* shadow_framebuffer, + GLuint ssao_texture, + GLuint diffuse_color_texture, GLuint specular_probe); void renderLightsScatter(GLuint depth_stencil_texture, const FrameBuffer& half1_framebuffer, diff --git a/src/graphics/post_processing.cpp b/src/graphics/post_processing.cpp index 092dfeaf1e7..98b2f6831b4 100644 --- a/src/graphics/post_processing.cpp +++ b/src/graphics/post_processing.cpp @@ -181,18 +181,18 @@ class Gaussian6HBlurShader : public TextureShader { public: - Gaussian17TapHShader() + Gaussian9TapHShader() { loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert", GL_FRAGMENT_SHADER, "bilateralH.frag"); assignUniforms("pixel"); assignSamplerNames(0, "tex", ST_BILINEAR_CLAMPED_FILTERED, 1, "depth", ST_BILINEAR_CLAMPED_FILTERED); - } // Gaussian17TapHShader + } // Gaussian9TapHShader // ------------------------------------------------------------------------ void render(const FrameBuffer &fb, const FrameBuffer &linear_depth, int width, int height) @@ -202,15 +202,15 @@ class Gaussian17TapHShader : public TextureShader { public: GLuint m_dest_tu; - ComputeGaussian17TapHShader() + ComputeGaussian9TapHShader() { #if !defined(USE_GLES2) loadProgram(OBJECT, GL_COMPUTE_SHADER, "bilateralH.comp"); @@ -220,7 +220,7 @@ class ComputeGaussian17TapHShader : public TextureShader { public: - Gaussian17TapVShader() + Gaussian9TapVShader() { loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert", GL_FRAGMENT_SHADER, "bilateralV.frag"); @@ -253,7 +253,7 @@ class Gaussian17TapVShader : public TextureShader { public: GLuint m_dest_tu; - ComputeGaussian17TapVShader() + ComputeGaussian9TapVShader() { #if !defined(USE_GLES2) loadProgram(OBJECT, GL_COMPUTE_SHADER, "bilateralV.comp"); @@ -282,7 +282,7 @@ class ComputeGaussian17TapVShader : public TextureShader @@ -896,13 +896,13 @@ void PostProcessing::renderHorizontalBlur(const FrameBuffer &in_fbo, // ---------------------------------------------------------------------------- -void PostProcessing::renderGaussian17TapBlur(const FrameBuffer &in_fbo, +void PostProcessing::renderGaussian9TapBlur(const FrameBuffer &in_fbo, const FrameBuffer &auxiliary, const FrameBuffer &linear_depth) const { assert(in_fbo.getWidth() == auxiliary.getWidth() && in_fbo.getHeight() == auxiliary.getHeight()); - + #if !defined(USE_GLES2) if (CVS->supportsComputeShadersFiltering()) glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT); @@ -912,14 +912,14 @@ void PostProcessing::renderGaussian17TapBlur(const FrameBuffer &in_fbo, if (!CVS->supportsComputeShadersFiltering()) { auxiliary.bind(); - Gaussian17TapHShader::getInstance()->render(in_fbo, + Gaussian9TapHShader::getInstance()->render(in_fbo, linear_depth, in_fbo.getWidth(), in_fbo.getHeight()); } else { - ComputeGaussian17TapHShader::getInstance()->render(in_fbo, + ComputeGaussian9TapHShader::getInstance()->render(in_fbo, auxiliary, linear_depth, in_fbo.getWidth(), @@ -936,14 +936,14 @@ void PostProcessing::renderGaussian17TapBlur(const FrameBuffer &in_fbo, if (!CVS->supportsComputeShadersFiltering()) { in_fbo.bind(); - Gaussian17TapVShader::getInstance()->render(auxiliary, + Gaussian9TapVShader::getInstance()->render(auxiliary, linear_depth, in_fbo.getWidth(), in_fbo.getHeight()); } else { - ComputeGaussian17TapVShader::getInstance()->render(auxiliary, + ComputeGaussian9TapVShader::getInstance()->render(auxiliary, in_fbo, linear_depth, in_fbo.getWidth(), @@ -955,7 +955,7 @@ void PostProcessing::renderGaussian17TapBlur(const FrameBuffer &in_fbo, if (CVS->supportsComputeShadersFiltering()) glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); #endif -} // renderGaussian17TapBlur +} // renderGaussian9TapBlur // ---------------------------------------------------------------------------- void PostProcessing::renderPassThrough(GLuint tex, unsigned width, diff --git a/src/graphics/post_processing.hpp b/src/graphics/post_processing.hpp index fa2fc4cbd37..264d6540f5c 100644 --- a/src/graphics/post_processing.hpp +++ b/src/graphics/post_processing.hpp @@ -65,7 +65,7 @@ class PostProcessing float sigmaV, float sigmaH) const; void renderHorizontalBlur(const FrameBuffer &in_fbo, const FrameBuffer &auxiliary) const; - void renderGaussian17TapBlur(const FrameBuffer &in_fbo, + void renderGaussian9TapBlur(const FrameBuffer &in_fbo, const FrameBuffer &auxiliary, const FrameBuffer &linear_depth) const; diff --git a/src/graphics/shader_based_renderer.cpp b/src/graphics/shader_based_renderer.cpp index 943b8348fff..6f1f17e7c8c 100644 --- a/src/graphics/shader_based_renderer.cpp +++ b/src/graphics/shader_based_renderer.cpp @@ -138,7 +138,7 @@ void ShaderBasedRenderer::renderSSAO() const FrameBuffer::blit(m_rtts->getFBO(FBO_SSAO), m_rtts->getFBO(FBO_HALF1_R), GL_COLOR_BUFFER_BIT, GL_LINEAR); - m_post_processing->renderGaussian17TapBlur(m_rtts->getFBO(FBO_HALF1_R), + m_post_processing->renderGaussian9TapBlur(m_rtts->getFBO(FBO_HALF1_R), m_rtts->getFBO(FBO_HALF2_R), m_rtts->getFBO(FBO_LINEAR_DEPTH)); @@ -195,7 +195,7 @@ void ShaderBasedRenderer::renderShadows() } // ============================================================================ -class CombineDiffuseColor : public TextureShader > { public: @@ -206,17 +206,16 @@ class CombineDiffuseColor : public TextureShader & bg_color) { - setTextureUnits(dm, sm, st, nt, dc, ds, lt); + setTextureUnits(dm, sm, nt, dc, ds, lt); drawFullScreenEffect(bg_color); } // render }; // CombineDiffuseColor @@ -266,6 +265,15 @@ void ShaderBasedRenderer::renderSceneDeferred(scene::ICameraSceneNode * const ca SP::draw(SP::RP_1ST, SP::DCT_NORMAL); } + // Handle SSAO + { + PROFILER_PUSH_CPU_MARKER("- SSAO", 0xFF, 0xFF, 0x00); + ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_SSAO)); + if (UserConfigParams::m_ssao) + renderSSAO(); + PROFILER_POP_CPU_MARKER(); + } + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Lights { @@ -282,19 +290,12 @@ void ShaderBasedRenderer::renderSceneDeferred(scene::ICameraSceneNode * const ca m_rtts->getDepthStencilTexture(), m_rtts->getRenderTarget(RTT_COLOR), m_rtts->getShadowFrameBuffer(), + m_rtts->getRenderTarget(RTT_HALF1_R), + m_rtts->getRenderTarget(RTT_SP_DIFF_COLOR), specular_probe); PROFILER_POP_CPU_MARKER(); } - // Handle SSAO - { - PROFILER_PUSH_CPU_MARKER("- SSAO", 0xFF, 0xFF, 0x00); - ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_SSAO)); - if (UserConfigParams::m_ssao) - renderSSAO(); - PROFILER_POP_CPU_MARKER(); - } - const Track * const track = Track::getCurrentTrack(); // Render discrete lights scattering if (UserConfigParams::m_light_scatter && track && track->isFogEnabled()) @@ -349,7 +350,6 @@ void ShaderBasedRenderer::renderSceneDeferred(scene::ICameraSceneNode * const ca CombineDiffuseColor::getInstance()->render( m_rtts->getRenderTarget(RTT_DIFFUSE), m_rtts->getRenderTarget(RTT_SPECULAR), - m_rtts->getRenderTarget(RTT_HALF1_R), m_rtts->getRenderTarget(RTT_NORMAL_AND_DEPTH), m_rtts->getRenderTarget(RTT_SP_DIFF_COLOR), m_rtts->getDepthStencilTexture(), diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 738037c2124..66a595c0c30 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -541,8 +541,8 @@ void Track::loadTrackInfo() m_sun_specular_color = video::SColor(255, 255, 255, 255); m_sun_diffuse_color = video::SColor(255, 255, 255, 255); m_sun_position = core::vector3df(0, 10, 10); - irr_driver->setSSAORadius(1.); - irr_driver->setSSAOK(1.5); + irr_driver->setSSAORadius(0.5); + irr_driver->setSSAOK(3.); irr_driver->setSSAOSigma(1.); XMLNode *root = file_manager->createXMLTree(m_filename); From 70c2ba09ddedbb971709d7a3406bb7675dab2ee8 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 24 Jan 2025 01:20:12 +0100 Subject: [PATCH 532/830] Reorganize graphics settings, add 4096 shadows - Add 4096 resolution shadows. This helps noticeably in some places to reduce shadow aliasing, nonetheless, for most users, the significant performance hit will not be worth the small quality gains. - Add an 8th graphics preset, with max resolution shadows. - Enable Light Shaft (God Rays) only on level 5, instead of level 4 - Enable SSAO only on level 7 instead of level 6 - Changed the location of specific settings in the custom settings dialog, to group the blur options at the end and to have less performance-intensive options towards the top. The options activated on each preset level are now 'connected'. - Remove the text saying the game needs to be restarted to apply new settings - the player doesn't need to manually restart the game, STK takes care of it when needed - Remove unused variables and fix typo --- data/gui/dialogs/custom_video_settings.stkgui | 60 +++++++++---------- src/graphics/irr_driver.cpp | 2 +- src/graphics/shadow_matrices.cpp | 14 ++--- src/graphics/shadow_matrices.hpp | 11 +--- .../dialogs/custom_video_settings.cpp | 7 ++- .../options/options_screen_video.cpp | 18 ++++-- 6 files changed, 53 insertions(+), 59 deletions(-) diff --git a/data/gui/dialogs/custom_video_settings.stkgui b/data/gui/dialogs/custom_video_settings.stkgui index 814ea699c2a..840890f479a 100644 --- a/data/gui/dialogs/custom_video_settings.stkgui +++ b/data/gui/dialogs/custom_video_settings.stkgui @@ -29,7 +29,7 @@
@@ -39,17 +39,17 @@
- + -
- + -
@@ -59,17 +59,17 @@
- + -
- + -
@@ -77,19 +77,19 @@
- +
- + -
- + -
@@ -97,19 +97,11 @@
- -
- - -
- -
- + -
@@ -117,11 +109,19 @@
- +
- + -
+ + + +
+ + +
@@ -167,11 +167,7 @@
- - -
diff --git a/data/gui/dialogs/ghost_replay_info_dialog.stkgui b/data/gui/dialogs/ghost_replay_info_dialog.stkgui index 5836f779c1c..f6f71c1ccd9 100644 --- a/data/gui/dialogs/ghost_replay_info_dialog.stkgui +++ b/data/gui/dialogs/ghost_replay_info_dialog.stkgui @@ -34,6 +34,7 @@
+
diff --git a/data/shaders/sunlightshadow.frag b/data/shaders/sunlightshadow.frag index 6641cb25f44..30ca5197985 100644 --- a/data/shaders/sunlightshadow.frag +++ b/data/shaders/sunlightshadow.frag @@ -13,6 +13,11 @@ uniform float splitmax; uniform float shadow_res; uniform float overlap_proportion; +uniform vec3 box0; +uniform vec3 box1; +uniform vec3 box2; +uniform vec3 box3; + uniform vec3 sundirection; uniform vec3 sun_color; @@ -32,12 +37,12 @@ out vec4 Spec; #stk_include "utils/SunMRP.frag" // https://web.archive.org/web/20230210095515/http://the-witness.net/news/2013/09/shadow-mapping-summary-part-1 -float getShadowFactor(vec3 pos, int index, float bias) +float getShadowFactor(vec3 pos, int index) { vec4 shadowcoord = (u_shadow_projection_view_matrices[index] * u_inverse_view_matrix * vec4(pos, 1.0)); shadowcoord.xy /= shadowcoord.w; vec2 shadowtexcoord = shadowcoord.xy * 0.5 + 0.5; - float d = .5 * shadowcoord.z + .5 - bias; + float d = .5 * shadowcoord.z + .5; vec2 uv = shadowtexcoord * shadow_res; vec2 base_uv = floor(uv + 0.5); @@ -83,13 +88,26 @@ float blend_start(float x) { return x * (1.0 - overlap_proportion); } +vec3 getXcYcZc(int x, int y, float zC) +{ + // We use perspective symetric projection matrix hence P(0,2) = P(1, 2) = 0 + float xC= (2. * (float(x)) / u_screen.x - 1.) * zC / u_projection_matrix[0][0]; + float yC= (2. * (float(y)) / u_screen.y - 1.) * zC / u_projection_matrix[1][1]; + return vec3(xC, yC, zC); +} + void main() { vec2 uv = gl_FragCoord.xy / u_screen; float z = texture(dtex, uv).x; vec4 xpos = getPosFromUVDepth(vec3(uv, z), u_inverse_projection_matrix); + // get the normal of current fragment + vec3 ddx = dFdx(xpos.xyz); + vec3 ddy = dFdy(xpos.xyz); + vec3 geo_norm = normalize(cross(ddy, ddx)); + vec3 norm = DecodeNormal(texture(ntex, uv).xy); - float roughness =texture(ntex, uv).z; + float roughness = texture(ntex, uv).z; vec3 eyedir = -normalize(xpos.xyz); vec3 Lightdir = SunMRP(norm, eyedir); @@ -100,24 +118,30 @@ void main() { // Shadows float factor; - float bias = max(1.0 - NdotL, .2) / shadow_res; + vec3 lbias = 40. * Lightdir / shadow_res; // Scale with blur kernel size + vec3 nbias = geo_norm * (1.0 - max(dot(-geo_norm, Lightdir), 0.)) / shadow_res; + nbias -= Lightdir * dot(nbias, Lightdir); // Slope-scaled normal bias + if (xpos.z < split0) { - factor = getShadowFactor(xpos.xyz, 0, bias); + factor = getShadowFactor(xpos.xyz + lbias + nbias * max(box0.x, box0.y), 0); if (xpos.z > blend_start(split0)) { - factor = mix(factor, getShadowFactor(xpos.xyz, 1, bias), (xpos.z - blend_start(split0)) / split0 / overlap_proportion); + factor = mix(factor, getShadowFactor(xpos.xyz + lbias + nbias * max(box1.x, box1.y), 1), + (xpos.z - blend_start(split0)) / split0 / overlap_proportion); } } else if (xpos.z < split1) { - factor = getShadowFactor(xpos.xyz, 1, bias); + factor = getShadowFactor(xpos.xyz + lbias + nbias * max(box1.x, box1.y), 1); if (xpos.z > blend_start(split1)) { - factor = mix(factor, getShadowFactor(xpos.xyz, 2, bias), (xpos.z - blend_start(split1)) / split1 / overlap_proportion); + factor = mix(factor, getShadowFactor(xpos.xyz + lbias + nbias * max(box2.x, box2.y), 2), + (xpos.z - blend_start(split1)) / split1 / overlap_proportion); } } else if (xpos.z < split2) { - factor = getShadowFactor(xpos.xyz, 2, bias); + factor = getShadowFactor(xpos.xyz + lbias + nbias * max(box2.x, box2.y), 2); if (xpos.z > blend_start(split2)) { - factor = mix(factor, getShadowFactor(xpos.xyz, 3, bias), (xpos.z - blend_start(split2)) / split2 / overlap_proportion); + factor = mix(factor, getShadowFactor(xpos.xyz + lbias + nbias * max(box3.x, box3.y), 3), + (xpos.z - blend_start(split2)) / split2 / overlap_proportion); } } else if (xpos.z < splitmax) { - factor = getShadowFactor(xpos.xyz, 3, bias); + factor = getShadowFactor(xpos.xyz + lbias + nbias * max(box3.x, box3.y), 3); if (xpos.z > blend_start(splitmax)) { factor = mix(factor, 1.0, (xpos.z - blend_start(splitmax)) / splitmax / overlap_proportion); } diff --git a/data/shaders/sunlightshadowpcss.frag b/data/shaders/sunlightshadowpcss.frag new file mode 100644 index 00000000000..b702aa42161 --- /dev/null +++ b/data/shaders/sunlightshadowpcss.frag @@ -0,0 +1,247 @@ +// Implementation from https://github.com/google/filament/blob/main/shaders/src/surface_shadowing.fs +uniform sampler2D ntex; +#if defined(GL_ES) && defined(GL_FRAGMENT_PRECISION_HIGH) +uniform highp sampler2D dtex; +#else +uniform sampler2D dtex; +#endif +uniform sampler2DArray shadowtexdepth; +uniform sampler2DArrayShadow shadowtex; + +uniform float split0; +uniform float split1; +uniform float split2; +uniform float splitmax; +uniform float shadow_res; +uniform float overlap_proportion; + +uniform vec3 box0; +uniform vec3 box1; +uniform vec3 box2; +uniform vec3 box3; + +uniform vec3 sundirection; +uniform vec3 sun_color; + +in vec2 uv; +#ifdef GL_ES +layout (location = 0) out vec4 Diff; +layout (location = 1) out vec4 Spec; +#else +out vec4 Diff; +out vec4 Spec; +#endif + +#stk_include "utils/decodeNormal.frag" +#stk_include "utils/SpecularBRDF.frag" +#stk_include "utils/DiffuseBRDF.frag" +#stk_include "utils/getPosFromUVDepth.frag" +#stk_include "utils/SunMRP.frag" + +// PCF with Vogel Disk Sampling +// From https://drdesten.github.io/web/tools/vogel_disk/ +vec2 vogel_disk_16[16] = vec2[]( + vec2(0.18993645671348536, 0.027087114076591513), + vec2(-0.21261242652069953, 0.23391293246949066), + vec2(0.04771781344140756, -0.3666840644525993), + vec2(0.297730981239584, 0.398259878229082), + vec2(-0.509063425827436, -0.06528681462854097), + vec2(0.507855152944665, -0.2875976005206389), + vec2(-0.15230616564632418, 0.6426121151781916), + vec2(-0.30240170651828074, -0.5805072900736001), + vec2(0.6978019230005561, 0.2771173334141519), + vec2(-0.6990963248129052, 0.3210960724922725), + vec2(0.3565142601623699, -0.7066415061851589), + vec2(0.266890002328106, 0.8360191043249159), + vec2(-0.7515861305520581, -0.41609876195815027), + vec2(0.9102937449894895, -0.17014527555321657), + vec2(-0.5343471434373126, 0.8058593459499529), + vec2(-0.1133270115046468, -0.9490025827627441) +); + +// https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_standard_multisample_quality_levels?redirectedfrom=MSDN +vec2 sample_point_pos[8] = vec2[]( + vec2( 0.125, -0.375), + vec2(-0.125, 0.375), + vec2( 0.625, 0.125), + vec2(-0.375, -0.625), + vec2(-0.625, 0.625), + vec2(-0.875, -0.125), + vec2( 0.375, 0.875), + vec2( 0.875, -0.875) +); + +float interleavedGradientNoise(vec2 w) +{ + vec3 m = vec3(0.06711056, 0.00583715, 52.9829189); + return fract(m.z * fract(dot(w, m.xy))); +} + +vec2 computeReceiverPlaneDepthBias(vec3 position) +{ + // see: GDC '06: Shadow Mapping: GPU-based Tips and Techniques + // Chain rule to compute dz/du and dz/dv + // |dz/du| |du/dx du/dy|^-T |dz/dx| + // |dz/dv| = |dv/dx dv/dy| * |dz/dy| + vec3 duvz_dx = dFdx(position); + vec3 duvz_dy = dFdy(position); + vec2 dz_duv = inverse(transpose(mat2(duvz_dx.xy, duvz_dy.xy))) * vec2(duvz_dx.z, duvz_dy.z); + return dz_duv; +} + +mat2 getRandomRotationMatrix(vec2 fragCoord) +{ + // rotate the vogel disk randomly + float randomAngle = interleavedGradientNoise(fragCoord) * 2.0 * 3.14159; + vec2 randomBase = vec2(cos(randomAngle), sin(randomAngle)); + mat2 R = mat2(randomBase.x, randomBase.y, -randomBase.y, randomBase.x); + return R; +} + +void blockerSearchAndFilter(out float occludedCount, out float z_occSum, + vec2 uv, float z_rec, uint layer, vec2 filterRadii, vec2 dz_duv) +{ + // Make sure no light leaking + float z_occ = texture(shadowtexdepth, vec3(uv, float(layer))).r; + float dz = z_rec - z_occ; + float occluded = 0.01 * step(0.5 / shadow_res, dz); + occludedCount = occluded; + z_occSum = z_occ * occluded; + + for (uint i = 0u; i < 8u; i++) + { + vec2 duv = sample_point_pos[i] * filterRadii; + vec2 tc = clamp(uv + duv, vec2(0.), vec2(1.)); + // receiver plane depth bias + float z_bias = dot(dz_duv, duv); + + float z_occ = texture(shadowtexdepth, vec3(tc, float(layer))).r; + float dz = z_rec - z_occ; // dz>0 when blocker is between receiver and light + float occluded = step(z_bias, dz); + occludedCount += occluded; + z_occSum += z_occ * occluded; + } +} + +float filterPCSS(vec2 uv, float z_rec, uint layer, + vec2 filterRadii, mat2 R, vec2 dz_duv) +{ + float occludedCount = 0.0; // must be to workaround a spirv-tools issue + for (uint i = 0u; i < 16u; i++) + { + vec2 duv = R * (vogel_disk_16[i] * filterRadii); + vec2 tc = clamp(uv + duv, vec2(0.), vec2(1.)); + + // receiver plane depth bias + float z_bias = dot(dz_duv, duv); + occludedCount += texture(shadowtex, vec4(tc, float(layer), z_rec + z_bias)); + } + return occludedCount * (1.0 / 16.0); +} + +float getShadowFactor(vec3 position, vec3 bbox, vec2 dz_duv, uint layer) +{ + float penumbra = tan(3.14 * sun_angle / 360.) * bbox.z * position.z; + + // rotate the poisson disk randomly + mat2 R = getRandomRotationMatrix(gl_FragCoord.xy); + + float occludedCount = 0.0; + float z_occSum = 0.0; + + blockerSearchAndFilter(occludedCount, z_occSum, position.xy, position.z, layer, penumbra / bbox.xy, dz_duv); + + // early exit if there is no occluders at all, also avoids a divide-by-zero below. + if (z_occSum == 0.0) { + return 1.0; + } + + float penumbraRatio = 1.0 - z_occSum / occludedCount / position.z; + vec2 radius = max(penumbra / bbox.xy * penumbraRatio, vec2(0.5 / shadow_res)); + + float percentageOccluded = filterPCSS(position.xy, position.z, layer, radius, R, dz_duv); + + return percentageOccluded; +} + +float blend_start(float x) { + return x * (1.0 - overlap_proportion); +} + +void main() { + vec2 uv = gl_FragCoord.xy / u_screen; + float z = texture(dtex, uv).x; + vec4 xpos = getPosFromUVDepth(vec3(uv, z), u_inverse_projection_matrix); + + vec3 norm = DecodeNormal(texture(ntex, uv).xy); + float roughness =texture(ntex, uv).z; + vec3 eyedir = -normalize(xpos.xyz); + + vec3 Lightdir = SunMRP(norm, eyedir); + float NdotL = clamp(dot(norm, Lightdir), 0., 1.); + + vec3 Specular = SpecularBRDF(norm, eyedir, Lightdir, vec3(1.), roughness); + vec3 Diffuse = DiffuseBRDF(norm, eyedir, Lightdir, vec3(1.), roughness); + + // Shadows + // Calculate all shadow positions to prevent bug of dFdx + vec4 position = (u_shadow_projection_view_matrices[0] * u_inverse_view_matrix * vec4(xpos.xyz, 1.0)); + vec3 position1 = position.xyz * (1.0 / position.w) * 0.5 + 0.5; + + position = (u_shadow_projection_view_matrices[1] * u_inverse_view_matrix * vec4(xpos.xyz, 1.0)); + vec3 position2 = position.xyz * (1.0 / position.w) * 0.5 + 0.5; + + position = (u_shadow_projection_view_matrices[2] * u_inverse_view_matrix * vec4(xpos.xyz, 1.0)); + vec3 position3 = position.xyz * (1.0 / position.w) * 0.5 + 0.5; + + position = (u_shadow_projection_view_matrices[3] * u_inverse_view_matrix * vec4(xpos.xyz, 1.0)); + vec3 position4 = position.xyz * (1.0 / position.w) * 0.5 + 0.5; + + // We need to use the shadow receiver plane depth bias to combat shadow acne due to the + // large kernel. + vec2 dz_duv1 = computeReceiverPlaneDepthBias(position1); + vec2 dz_duv2 = computeReceiverPlaneDepthBias(position2); + vec2 dz_duv3 = computeReceiverPlaneDepthBias(position3); + vec2 dz_duv4 = computeReceiverPlaneDepthBias(position4); + + float factor; + if (xpos.z < split0) { + float factor2 = getShadowFactor(position1, box0, dz_duv1, 0); + factor = factor2; + } + if (blend_start(split0) < xpos.z && xpos.z < split1) { + float factor2 = getShadowFactor(position2, box1, dz_duv2, 1); + if (xpos.z < split0) { + factor = mix(factor, factor2, (xpos.z - blend_start(split0)) / split0 / overlap_proportion); + } else { + factor = factor2; + } + } + if (blend_start(split1) < xpos.z && xpos.z < split2) { + float factor2 = getShadowFactor(position3, box2, dz_duv3, 2); + if (xpos.z < split1) { + factor = mix(factor, factor2, (xpos.z - blend_start(split1)) / split1 / overlap_proportion); + } else { + factor = factor2; + } + } + if (blend_start(split2) < xpos.z && xpos.z < splitmax) { + float factor2 = getShadowFactor(position4, box3, dz_duv4, 3); + if (xpos.z < split2) { + factor = mix(factor, factor2, (xpos.z - blend_start(split2)) / split2 / overlap_proportion); + } else { + factor = factor2; + } + } + if (blend_start(splitmax) < xpos.z) { + float factor2 = 1.; + if (xpos.z < splitmax) { + factor = mix(factor, factor2, (xpos.z - blend_start(splitmax)) / splitmax / overlap_proportion); + } else { + factor = factor2; + } + } + + Diff = vec4(factor * NdotL * Diffuse * sun_color, 1.); + Spec = vec4(factor * NdotL * Specular * sun_color, 1.); +} diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index e61441e8207..f312d52410e 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -1017,6 +1017,10 @@ namespace UserConfigParams PARAM_DEFAULT( IntUserConfigParam(0, "shadows_resolution", &m_graphics_quality, "Shadow resolution (0 = disabled") ); + PARAM_PREFIX IntUserConfigParam m_pcss_threshold + PARAM_DEFAULT( IntUserConfigParam(2048, + "pcss_threshold", &m_graphics_quality, + "Enable Percentage Closer Soft Shadows when shadow resolution is higher than this value") ); PARAM_PREFIX BoolUserConfigParam m_degraded_IBL PARAM_DEFAULT(BoolUserConfigParam(true, "Degraded_IBL", &m_graphics_quality, diff --git a/src/graphics/lighting_passes.cpp b/src/graphics/lighting_passes.cpp index 76459bb8954..c7e79c5cb5d 100644 --- a/src/graphics/lighting_passes.cpp +++ b/src/graphics/lighting_passes.cpp @@ -205,6 +205,8 @@ class DegradedIBLShader : public TextureShader class ShadowedSunLightShaderPCF : public TextureShader { public: @@ -218,14 +220,15 @@ class ShadowedSunLightShaderPCF : public TextureShader +{ +public: + ShadowedSunLightShaderPCSS() + { + loadProgram(OBJECT, GL_VERTEX_SHADER, "screenquad.vert", + GL_FRAGMENT_SHADER, "sunlightshadowpcss.frag"); + + // Use 8 to circumvent a catalyst bug when binding sampler + assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED, + 1, "dtex", ST_NEAREST_FILTERED, + 8, "shadowtexdepth", ST_NEAREST_FILTERED_ARRAY2D, + 16, "shadowtex", ST_SHADOW_SAMPLER); + assignUniforms("split0", "split1", "split2", "splitmax", "shadow_res", + "overlap_proportion", "box0", "box1", "box2", "box3", "sundirection", "sun_color"); + } // ShadowedSunLightShaderPCF + // ------------------------------------------------------------------------ + void render(GLuint normal_depth_texture, + GLuint depth_stencil_texture, + const FrameBuffer* shadow_framebuffer, + const core::vector3df &direction, + const video::SColorf &col, + const core::vector3df* shadow_box_extents) + { + setTextureUnits(normal_depth_texture, + depth_stencil_texture, + shadow_framebuffer->getDepthTexture(), + shadow_framebuffer->getDepthTexture() ); + drawFullScreenEffect(ShadowMatrices::m_shadow_split[1], + ShadowMatrices::m_shadow_split[2], + ShadowMatrices::m_shadow_split[3], + ShadowMatrices::m_shadow_split[4], + float(UserConfigParams::m_shadows_resolution), + ShadowMatrices::m_shadow_overlap_proportion, + shadow_box_extents[0], shadow_box_extents[1], + shadow_box_extents[2], shadow_box_extents[3], + direction, col); + + } // render +}; // ShadowedSunLightShaderPCSS + // ============================================================================ class SunLightShader : public TextureShader @@ -443,7 +495,8 @@ void LightingPasses::renderLights( bool has_shadow, const FrameBuffer* shadow_framebuffer, GLuint ssao_texture, GLuint diffuse_color_texture, - GLuint specular_probe) + GLuint specular_probe, + const core::vector3df* shadow_box_extents) { { ScopedGPUTimer timer(irr_driver->getGPUTimer(Q_ENVMAP)); @@ -466,11 +519,24 @@ void LightingPasses::renderLights( bool has_shadow, glDisable(GL_DEPTH_TEST); glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); - ShadowedSunLightShaderPCF::getInstance()->render(normal_depth_texture, - depth_stencil_texture, - shadow_framebuffer, - irr_driver->getSunDirection(), - irr_driver->getSunColor()); + if (UserConfigParams::m_pcss_threshold <= UserConfigParams::m_shadows_resolution) + { + ShadowedSunLightShaderPCSS::getInstance()->render(normal_depth_texture, + depth_stencil_texture, + shadow_framebuffer, + irr_driver->getSunDirection(), + irr_driver->getSunColor(), + shadow_box_extents); + } + else + { + ShadowedSunLightShaderPCF::getInstance()->render(normal_depth_texture, + depth_stencil_texture, + shadow_framebuffer, + irr_driver->getSunDirection(), + irr_driver->getSunColor(), + shadow_box_extents); + } } else renderSunlight(irr_driver->getSunDirection(), diff --git a/src/graphics/lighting_passes.hpp b/src/graphics/lighting_passes.hpp index aef150a52bc..19e82cb5016 100644 --- a/src/graphics/lighting_passes.hpp +++ b/src/graphics/lighting_passes.hpp @@ -69,7 +69,8 @@ class LightingPasses const FrameBuffer* shadow_framebuffer, GLuint ssao_texture, GLuint diffuse_color_texture, - GLuint specular_probe); + GLuint specular_probe, + const core::vector3df* shadow_box_extents); void renderLightsScatter(GLuint depth_stencil_texture, const FrameBuffer& half1_framebuffer, const FrameBuffer& half2_framebuffer, diff --git a/src/graphics/shader_based_renderer.cpp b/src/graphics/shader_based_renderer.cpp index 6f1f17e7c8c..12e126bcbf2 100644 --- a/src/graphics/shader_based_renderer.cpp +++ b/src/graphics/shader_based_renderer.cpp @@ -292,7 +292,8 @@ void ShaderBasedRenderer::renderSceneDeferred(scene::ICameraSceneNode * const ca m_rtts->getShadowFrameBuffer(), m_rtts->getRenderTarget(RTT_HALF1_R), m_rtts->getRenderTarget(RTT_SP_DIFF_COLOR), - specular_probe); + specular_probe, + m_shadow_matrices.getShadowFrustumBoxExtent()); PROFILER_POP_CPU_MARKER(); } diff --git a/src/graphics/shadow_matrices.cpp b/src/graphics/shadow_matrices.cpp index c655e1b0c74..27c2931b826 100644 --- a/src/graphics/shadow_matrices.cpp +++ b/src/graphics/shadow_matrices.cpp @@ -145,7 +145,8 @@ static std::vector getFrustrumVertex(const scene::SViewFrustum &frust * \param pointsInside a vector of point in 3d space. */ core::matrix4 ShadowMatrices::getTightestFitOrthoProj(const core::matrix4 &transform, - const std::vector &pointsInside) + const std::vector &pointsInside, + core::vector3df& bounding_box_extent) { float xmin = std::numeric_limits::infinity(); float xmax = -std::numeric_limits::infinity(); @@ -175,9 +176,14 @@ core::matrix4 ShadowMatrices::getTightestFitOrthoProj(const core::matrix4 &trans // Prevent Matrix without extend if (left == right || up == down) return tmp_matrix; + + float vnear = std::min((zmax + zmin) / 2 - 250, zmin); // 250m above karts tmp_matrix.buildProjectionMatrixOrthoLH(left, right, down, up, - zmin - 100, zmax); + vnear, zmax); + bounding_box_extent.X = right - left; + bounding_box_extent.Y = down - up; + bounding_box_extent.Z = zmax - vnear; return tmp_matrix; } // getTightestFitOrthoProj @@ -275,7 +281,7 @@ void ShadowMatrices::computeMatrixesAndCameras(scene::ICameraSceneNode *const ca memcpy(m_shadows_cam[i], tmp, 24 * sizeof(float)); std::vector vectors = getFrustrumVertex(*frustrum); - tmp_matrix = getTightestFitOrthoProj(sun_cam_view_matrix, vectors); + tmp_matrix = getTightestFitOrthoProj(sun_cam_view_matrix, vectors, m_frustum_box_extent[i]); m_shadow_cam_nodes[i]->setProjectionMatrix(tmp_matrix, true); diff --git a/src/graphics/shadow_matrices.hpp b/src/graphics/shadow_matrices.hpp index 183438f9226..60054a20666 100644 --- a/src/graphics/shadow_matrices.hpp +++ b/src/graphics/shadow_matrices.hpp @@ -51,9 +51,11 @@ class ShadowMatrices float m_shadows_cam[4][24]; bool m_rsm_map_available; float m_mat_ubo[16 * 9 + 2]; + core::vector3df m_frustum_box_extent[4]; core::matrix4 getTightestFitOrthoProj(const core::matrix4 &transform, - const std::vector &pointsInside); + const std::vector &pointsInside, + core::vector3df& bounding_box_extent); void renderWireFrameFrustrum(float *tmp, unsigned i); public: @@ -75,6 +77,11 @@ class ShadowMatrices return m_shadow_cam_nodes; } // getShadowCamNodes // ------------------------------------------------------------------------ + core::vector3df* getShadowFrustumBoxExtent() + { + return m_frustum_box_extent; + } // getShadowCamNodes + // ------------------------------------------------------------------------ scene::ICameraSceneNode* getSunCam() { return m_sun_cam; } // ------------------------------------------------------------------------ std::vector& getSunOrthoMatrices() diff --git a/src/graphics/texture_shader.cpp b/src/graphics/texture_shader.cpp index a6026a0d055..443844cd28e 100644 --- a/src/graphics/texture_shader.cpp +++ b/src/graphics/texture_shader.cpp @@ -28,6 +28,7 @@ TextureShaderBase::BindFunction TextureShaderBase::m_all_bind_functions[] = /* ST_TRILINEAR_ANISOTROPIC_FILTERED */ &TextureShaderBase::bindTextureTrilinearAnisotropic, /* ST_TRILINEAR_CUBEMAP */ &TextureShaderBase::bindCubemapTrilinear, /* ST_BILINEAR_FILTERED */ &TextureShaderBase::bindTextureBilinear, + /* ST_NEAREST_FILTERED_ARRAY2D */ &TextureShaderBase::bindTextureNearestArrayTexture, /* ST_SHADOW_SAMPLER */ &TextureShaderBase::bindTextureShadow, /* ST_TRILINEAR_CLAMPED_ARRAY2D */ &TextureShaderBase::bindTrilinearClampedArrayTexture, /* ST_VOLUME_LINEAR_FILTERED */ &TextureShaderBase::bindTextureVolume, @@ -42,6 +43,7 @@ GLuint TextureShaderBase::m_all_texture_types[] = /* ST_TRILINEAR_ANISOTROPIC_FILTERED */ GL_TEXTURE_2D, /* ST_TRILINEAR_CUBEMAP */ GL_TEXTURE_CUBE_MAP, /* ST_BILINEAR_FILTERED */ GL_TEXTURE_2D , + /* ST_NEAREST_FILTERED_ARRAY2D */ GL_TEXTURE_2D_ARRAY, /* ST_SHADOW_SAMPLER */ GL_TEXTURE_2D_ARRAY, /* ST_TRILINEAR_CLAMPED_ARRAY2D */ GL_TEXTURE_2D_ARRAY, /* ST_VOLUME_LINEAR_FILTERED */ GL_TEXTURE_3D, @@ -168,6 +170,17 @@ void TextureShaderBase::bindTextureSemiTrilinear(GLuint tex_unit, GLuint tex_id) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.); } // bindTextureSemiTrilinear +// ---------------------------------------------------------------------------- +void TextureShaderBase::bindTextureNearestArrayTexture(GLuint tex_unit, GLuint tex_id) +{ + glActiveTexture(GL_TEXTURE0 + tex_unit); + glBindTexture(GL_TEXTURE_2D_ARRAY, tex_id); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} // bindTextureShadow + // ---------------------------------------------------------------------------- void TextureShaderBase::bindTextureShadow(GLuint tex_unit, GLuint tex_id) { diff --git a/src/graphics/texture_shader.hpp b/src/graphics/texture_shader.hpp index d05ba7af0d3..9e7dd059f19 100644 --- a/src/graphics/texture_shader.hpp +++ b/src/graphics/texture_shader.hpp @@ -37,6 +37,7 @@ enum SamplerTypeNew ST_TRILINEAR_ANISOTROPIC_FILTERED, ST_TRILINEAR_CUBEMAP, ST_BILINEAR_FILTERED, + ST_NEAREST_FILTERED_ARRAY2D, ST_SHADOW_SAMPLER, ST_TRILINEAR_CLAMPED_ARRAY2D, ST_VOLUME_LINEAR_FILTERED, @@ -70,6 +71,7 @@ class TextureShaderBase static void bindTextureTrilinearAnisotropic(GLuint tex_unit, GLuint tex_id); static void bindTextureSemiTrilinear(GLuint tex_unit, GLuint tex_id); static void bindCubemapTrilinear(GLuint tex_unit, GLuint tex_id); + static void bindTextureNearestArrayTexture(GLuint tex_unit, GLuint tex_id); static void bindTextureShadow(GLuint tex_unit, GLuint tex_id); static void bindTrilinearClampedArrayTexture(GLuint tex_unit, GLuint tex_id); static void bindTextureVolume(GLuint tex_unit, GLuint tex_id); diff --git a/src/replay/replay_play.cpp b/src/replay/replay_play.cpp index adb95709695..9dbda4256e0 100644 --- a/src/replay/replay_play.cpp +++ b/src/replay/replay_play.cpp @@ -284,6 +284,15 @@ bool ReplayPlay::addReplayFile(const std::string& fn, bool custom_replay, int ca rd.m_track = t; fgets(s, 1023, fd); + if (sscanf(s, "info: %1023s", s1) == 1) + { + int last = strlen(s); + if (s[last - 1] == '\n') + s[last - 1] = '\0'; + + rd.m_info = s + 6; + fgets(s, 1023, fd); + } if (sscanf(s, "laps: %u", &rd.m_laps) != 1) { Log::warn("Replay", "No number of laps found in replay file, '%s'.", fn.c_str()); diff --git a/src/replay/replay_play.hpp b/src/replay/replay_play.hpp index 2c6f57415b2..53b30985975 100644 --- a/src/replay/replay_play.hpp +++ b/src/replay/replay_play.hpp @@ -62,6 +62,7 @@ class ReplayPlay : public ReplayBase std::string m_minor_mode; core::stringw m_stk_version; core::stringw m_user_name; + core::stringw m_info; std::vector m_kart_list; std::vector m_name_list; std::vector m_kart_color; //no sorting for this diff --git a/src/states_screens/dialogs/custom_video_settings.cpp b/src/states_screens/dialogs/custom_video_settings.cpp index 738f9b0a79f..3197e122481 100644 --- a/src/states_screens/dialogs/custom_video_settings.cpp +++ b/src/states_screens/dialogs/custom_video_settings.cpp @@ -103,9 +103,7 @@ void CustomVideoSettingsDialog::beforeAddingWidgets() shadows->addLabel(_("Low")); // 1 shadows->addLabel(_("Medium")); // 2 shadows->addLabel(_("High")); // 3 - shadows->addLabel(_("Very High")); // 4 - shadows->setValue(UserConfigParams::m_shadows_resolution == 4096 ? 4 : - UserConfigParams::m_shadows_resolution == 2048 ? 3 : + shadows->setValue(UserConfigParams::m_shadows_resolution == 2048 ? 3 : UserConfigParams::m_shadows_resolution == 1024 ? 2 : UserConfigParams::m_shadows_resolution == 512 ? 1 : 0); @@ -163,8 +161,7 @@ GUIEngine::EventPropagation CustomVideoSettingsDialog::processEvent(const std::s UserConfigParams::m_shadows_resolution = getWidget("shadows")->getValue() == 1 ? 512 : getWidget("shadows")->getValue() == 2 ? 1024 : - getWidget("shadows")->getValue() == 3 ? 2048 : - getWidget("shadows")->getValue() == 4 ? 4096 : 0; + getWidget("shadows")->getValue() == 3 ? 2048 : 0; } else { @@ -263,4 +260,3 @@ void CustomVideoSettingsDialog::updateActivation() getWidget("lightscattering")->setActive(light); #endif } // updateActivation - diff --git a/src/states_screens/dialogs/ghost_replay_info_dialog.cpp b/src/states_screens/dialogs/ghost_replay_info_dialog.cpp index d94ed930707..d70f3bf9ae8 100644 --- a/src/states_screens/dialogs/ghost_replay_info_dialog.cpp +++ b/src/states_screens/dialogs/ghost_replay_info_dialog.cpp @@ -21,6 +21,7 @@ #include "config/player_manager.hpp" #include "guiengine/CGUISpriteBank.hpp" #include "graphics/stk_tex_manager.hpp" +#include "guiengine/widgets/bubble_widget.hpp" #include "guiengine/widgets/check_box_widget.hpp" #include "guiengine/widgets/icon_button_widget.hpp" #include "guiengine/widgets/label_widget.hpp" @@ -43,7 +44,7 @@ using namespace irr::core; // ----------------------------------------------------------------------------- GhostReplayInfoDialog::GhostReplayInfoDialog(unsigned int replay_id, uint64_t compare_replay_uid, bool compare_ghost) - : ModalDialog(0.95f,0.75f), m_replay_id(replay_id) + : ModalDialog(0.95f,0.9f), m_replay_id(replay_id) { m_self_destroy = false; m_record_race = false; @@ -56,6 +57,9 @@ GhostReplayInfoDialog::GhostReplayInfoDialog(unsigned int replay_id, loadFromFile("ghost_replay_info_dialog.stkgui"); + m_info_widget = getWidget("info"); + m_info_widget->setText(m_rd.m_info); + Track* track = track_manager->getTrack(m_rd.m_track_name); m_track_screenshot_widget = getWidget("track_screenshot"); diff --git a/src/states_screens/dialogs/ghost_replay_info_dialog.hpp b/src/states_screens/dialogs/ghost_replay_info_dialog.hpp index f8306934852..9fc24db9ae7 100644 --- a/src/states_screens/dialogs/ghost_replay_info_dialog.hpp +++ b/src/states_screens/dialogs/ghost_replay_info_dialog.hpp @@ -24,6 +24,7 @@ namespace GUIEngine { + class BubbleWidget; class CheckBoxWidget; class IconButtonWidget; class ListWidget; class RibbonWidget; } @@ -48,6 +49,7 @@ class GhostReplayInfoDialog : public GUIEngine::ModalDialog ReplayPlay::ReplayData m_rd; + GUIEngine::BubbleWidget* m_info_widget; GUIEngine::RibbonWidget* m_action_widget; GUIEngine::IconButtonWidget* m_back_widget; GUIEngine::CheckBoxWidget* m_record_widget; diff --git a/src/states_screens/options/options_screen_video.cpp b/src/states_screens/options/options_screen_video.cpp index 8bed1953014..a970fb72a4e 100644 --- a/src/states_screens/options/options_screen_video.cpp +++ b/src/states_screens/options/options_screen_video.cpp @@ -64,7 +64,7 @@ void OptionsScreenVideo::initPresets() m_presets.push_back // Level 4 ({ - true /* light */, 0 /* shadow */, false /* bloom */, false /* lightshaft */, + true /* light */, 0 /* shadow */, false /* bloom */, true /* lightshaft */, true /* glow */, true /* mlaa */, false /* ssao */, true /* light scatter */, true /* animatedCharacters */, 2 /* particles */, 2 /* image_quality */, false /* degraded IBL */, 3 /* Geometry Detail */ @@ -81,7 +81,7 @@ void OptionsScreenVideo::initPresets() m_presets.push_back // Level 6 ({ true /* light */, 1024 /* shadow */, true /* bloom */, true /* lightshaft */, - true /* glow */, true /* mlaa */, false /* ssao */, true /* light scatter */, + true /* glow */, true /* mlaa */, true /* ssao */, true /* light scatter */, true /* animatedCharacters */, 2 /* particles */, 3 /* image_quality */, false /* degraded IBL */, 4 /* Geometry Detail */ }); @@ -94,25 +94,17 @@ void OptionsScreenVideo::initPresets() false /* degraded IBL */, 5 /* Geometry Detail */ }); - m_presets.push_back // Level 8 - ({ - true /* light */, 4096 /* shadow */, true /* bloom */, true /* lightshaft */, - true /* glow */, true /* mlaa */, true /* ssao */, true /* light scatter */, - true /* animatedCharacters */, 2 /* particles */, 3 /* image_quality */, - false /* degraded IBL */, 5 /* Geometry Detail */ - }); - - m_blur_presets.push_back // Level 0 + m_blur_presets.push_back ({ false /* motionblur */, false /* depth of field */ }); - m_blur_presets.push_back // Level 1 + m_blur_presets.push_back ({ true /* motionblur */, false /* depth of field */ }); - m_blur_presets.push_back // Level 2 + m_blur_presets.push_back ({ true /* motionblur */, true /* depth of field */ }); @@ -220,7 +212,7 @@ OptionsScreenVideo::OptionsScreenVideo() : Screen("options/options_video.stkgui" void OptionsScreenVideo::loadedFromFile() { m_inited = false; - assert(m_presets.size() == 8); + assert(m_presets.size() == 7); assert(m_blur_presets.size() == 3); GUIEngine::SpinnerWidget* gfx = @@ -477,45 +469,43 @@ void OptionsScreenVideo::updateTooltip() const core::stringw very_high = _("Very High"); //I18N: in the graphical options tooltip; const core::stringw ultra = _("Ultra"); - + //I18N: in graphical options - tooltip = _("Particles Effects: %s", - UserConfigParams::m_particles_effects == 2 ? enabled : - UserConfigParams::m_particles_effects == 1 ? important_only : - disabled); + tooltip = _("Dynamic lights: %s", + UserConfigParams::m_dynamic_lights ? enabled : disabled); //I18N: in graphical options - tooltip = tooltip + L"\n" + _("Animated Characters: %s", - UserConfigParams::m_animated_characters ? enabled : disabled); + if (UserConfigParams::m_shadows_resolution == 0) + tooltip = tooltip + L"\n" + _("Shadows: %s", disabled); + else + tooltip = tooltip + L"\n" + _("Shadows: %i", UserConfigParams::m_shadows_resolution); //I18N: in graphical options - tooltip = tooltip + L"\n" + _("Dynamic lights: %s", - UserConfigParams::m_dynamic_lights ? enabled : disabled); + tooltip = tooltip + L"\n" + _("Anti-aliasing: %s", + UserConfigParams::m_mlaa ? enabled : disabled); //I18N: in graphical options tooltip = tooltip + L"\n" + _("Light scattering: %s", UserConfigParams::m_light_scatter ? enabled : disabled); //I18N: in graphical options - tooltip = tooltip + L"\n" + _("Anti-aliasing: %s", - UserConfigParams::m_mlaa ? enabled : disabled); - //I18N: in graphical options - tooltip = tooltip + L"\n" + _("Ambient occlusion: %s", - UserConfigParams::m_ssao ? enabled : disabled); + tooltip = tooltip + L"\n" + _("Glow (outlines): %s", + UserConfigParams::m_glow ? enabled : disabled); //I18N: in graphical options - if (UserConfigParams::m_shadows_resolution == 0) - tooltip = tooltip + L"\n" + _("Shadows: %s", disabled); - else - tooltip = tooltip + L"\n" + _("Shadows: %i", UserConfigParams::m_shadows_resolution); - + tooltip = tooltip + L"\n" + _("Light shaft (God rays): %s", + UserConfigParams::m_light_shaft ? enabled : disabled); //I18N: in graphical options tooltip = tooltip + L"\n" + _("Bloom: %s", UserConfigParams::m_bloom ? enabled : disabled); - //I18N: in graphical options - tooltip = tooltip + L"\n" + _("Glow (outlines): %s", - UserConfigParams::m_glow ? enabled : disabled); + tooltip = tooltip + L"\n" + _("Ambient occlusion: %s", + UserConfigParams::m_ssao ? enabled : disabled); //I18N: in graphical options - tooltip = tooltip + L"\n" + _("Light shaft (God rays): %s", - UserConfigParams::m_light_shaft ? enabled : disabled); + tooltip = tooltip + L"\n" + _("Animated Characters: %s", + UserConfigParams::m_animated_characters ? enabled : disabled); + //I18N: in graphical options + tooltip = tooltip + L"\n" + _("Particles Effects: %s", + UserConfigParams::m_particles_effects == 2 ? enabled : + UserConfigParams::m_particles_effects == 1 ? important_only : + disabled); //I18N: in graphical options int quality = getImageQuality(); @@ -749,4 +739,4 @@ void OptionsScreenVideo::unloaded() m_inited = false; } // unloaded -// -------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------- \ No newline at end of file From 78665b82b9f9832514bd36c4f46415218437e25b Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 17 Feb 2025 12:29:50 +0100 Subject: [PATCH 549/830] Add a separate Camera tab The User Interface tab was crowded, display didn't fit very well either, and a new tab allows to lay out camera options more directly. The graphics settings icon is now used for the camera tab. The cartoon theme has a new icon for the graphics tab, the standard theme is using the old icon as a placeholder. --- data/gui/icons/options_camera.png | Bin 0 -> 3977 bytes data/gui/screens/options/options_audio.stkgui | 2 + .../gui/screens/options/options_camera.stkgui | 49 +++++ .../gui/screens/options/options_device.stkgui | 2 + .../screens/options/options_display.stkgui | 2 + .../screens/options/options_general.stkgui | 2 + data/gui/screens/options/options_input.stkgui | 2 + .../screens/options/options_language.stkgui | 2 + data/gui/screens/options/options_ui.stkgui | 10 +- data/gui/screens/options/options_video.stkgui | 2 + .../screens/options/user_screen_tab.stkgui | 2 + .../cartoon/data/gui/icons/options_camera.png | Bin 0 -> 3462 bytes .../cartoon/data/gui/icons/options_video.png | Bin 3462 -> 9475 bytes .../dialogs/custom_camera_settings.cpp | 4 +- src/states_screens/options/options_common.cpp | 2 + src/states_screens/options/options_common.hpp | 1 + .../options/options_screen_camera.cpp | 180 ++++++++++++++++++ .../options/options_screen_camera.hpp | 63 ++++++ .../options/options_screen_ui.cpp | 89 --------- .../options/options_screen_ui.hpp | 4 - 20 files changed, 315 insertions(+), 103 deletions(-) create mode 100644 data/gui/icons/options_camera.png create mode 100644 data/gui/screens/options/options_camera.stkgui create mode 100644 data/skins/cartoon/data/gui/icons/options_camera.png create mode 100644 src/states_screens/options/options_screen_camera.cpp create mode 100644 src/states_screens/options/options_screen_camera.hpp diff --git a/data/gui/icons/options_camera.png b/data/gui/icons/options_camera.png new file mode 100644 index 0000000000000000000000000000000000000000..8fa50ea5b42d4da02a97484fce9685e926c61c04 GIT binary patch literal 3977 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 + + + +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+
+
+
diff --git a/data/gui/screens/options/options_device.stkgui b/data/gui/screens/options/options_device.stkgui index 51171a6cd42..51dedb685c0 100644 --- a/data/gui/screens/options/options_device.stkgui +++ b/data/gui/screens/options/options_device.stkgui @@ -18,6 +18,8 @@ I18N="Section in the settings menu" text="Audio"/> + + + + + + -
- -
- -
diff --git a/data/gui/screens/options/options_video.stkgui b/data/gui/screens/options/options_video.stkgui index 7e5d77f09c7..4e987bc7894 100644 --- a/data/gui/screens/options/options_video.stkgui +++ b/data/gui/screens/options/options_video.stkgui @@ -18,6 +18,8 @@ I18N="Section in the settings menu" text="Audio"/> + + 2#e!TBFO%D;X> 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 LH_&XSV{ru7Lbqz2}ucI5u`(28Vr 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 YEDav4oZb5^rhy4iRn}ChR2#e!TBFO%D;X> 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 LH_&XupdateCameraPresetSpinner(); + OptionsScreenCamera::getInstance()->updateCameraPresetSpinner(); m_self_destroy = true; return GUIEngine::EVENT_BLOCK; } diff --git a/src/states_screens/options/options_common.cpp b/src/states_screens/options/options_common.cpp index 104fedc09ed..3217e59a29e 100644 --- a/src/states_screens/options/options_common.cpp +++ b/src/states_screens/options/options_common.cpp @@ -36,6 +36,8 @@ namespace OptionsCommon screen = OptionsScreenInput::getInstance(); else if (selected_tab == "tab_ui") screen = OptionsScreenUI::getInstance(); + else if (selected_tab == "tab_camera") + screen = OptionsScreenCamera::getInstance(); else if (selected_tab == "tab_general") screen = OptionsScreenGeneral::getInstance(); else if (selected_tab == "tab_language") diff --git a/src/states_screens/options/options_common.hpp b/src/states_screens/options/options_common.hpp index 9a618f06070..3d0e74a582b 100644 --- a/src/states_screens/options/options_common.hpp +++ b/src/states_screens/options/options_common.hpp @@ -34,6 +34,7 @@ // Other option screens, for navigation between them #include "states_screens/options/options_screen_audio.hpp" +#include "states_screens/options/options_screen_camera.hpp" #include "states_screens/options/options_screen_display.hpp" #include "states_screens/options/options_screen_general.hpp" #include "states_screens/options/options_screen_input.hpp" diff --git a/src/states_screens/options/options_screen_camera.cpp b/src/states_screens/options/options_screen_camera.cpp new file mode 100644 index 00000000000..17099fc6e5e --- /dev/null +++ b/src/states_screens/options/options_screen_camera.cpp @@ -0,0 +1,180 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2009-2025 Marianne Gagnon, Alayan et al. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +// Manages includes common to all options screens +#include "states_screens/options/options_common.hpp" + +#include "graphics/camera/camera.hpp" +#include "graphics/camera/camera_normal.hpp" +#include "config/player_manager.hpp" +#include "states_screens/dialogs/custom_camera_settings.hpp" +#include "states_screens/dialogs/message_dialog.hpp" +#include "states_screens/main_menu_screen.hpp" + +#include + +using namespace GUIEngine; +using namespace Online; + +// ----------------------------------------------------------------------------- + +OptionsScreenCamera::OptionsScreenCamera() : Screen("options/options_camera.stkgui") +{ + m_inited = false; +} // OptionsScreenCamera + +// ----------------------------------------------------------------------------- + +void OptionsScreenCamera::loadedFromFile() +{ + m_inited = false; + + // Setup the camera spinner + GUIEngine::SpinnerWidget* camera_preset = getWidget("camera_preset"); + assert( camera_preset != NULL ); + + camera_preset->m_properties[PROP_WRAP_AROUND] = "true"; + camera_preset->clearLabels(); + //I18N: In the UI options, Camera setting: Custom + camera_preset->addLabel( core::stringw(_("Custom"))); + //I18N: In the UI options, Camera setting: Standard + camera_preset->addLabel( core::stringw(_("Standard"))); + //I18N: In the UI options, Camera setting: Drone chase + camera_preset->addLabel( core::stringw(_("Drone chase"))); + camera_preset->m_properties[GUIEngine::PROP_MIN_VALUE] = "0"; + camera_preset->m_properties[GUIEngine::PROP_MAX_VALUE] = "2"; + updateCameraPresetSpinner(); +} // loadedFromFile + +// ----------------------------------------------------------------------------- + +void OptionsScreenCamera::init() +{ + Screen::init(); + OptionsCommon::setTabStatus(); + + RibbonWidget* ribbon = getWidget("options_choice"); + assert(ribbon != NULL); + ribbon->setFocusForPlayer(PLAYER_ID_GAME_MASTER); + ribbon->select( "tab_camera", PLAYER_ID_GAME_MASTER ); + + // --- select the right camera in the spinner + GUIEngine::SpinnerWidget* camera_preset = getWidget("camera_preset"); + assert( camera_preset != NULL ); + + camera_preset->setValue(UserConfigParams::m_camera_present); // use the saved camera + updateCameraPresetSpinner(); +} // init + +// ----------------------------------------------------------------------------- +void OptionsScreenCamera::updateCamera() +{ + bool in_game = StateManager::get()->getGameState() == GUIEngine::INGAME_MENU; + if (in_game) + { + (Camera::getActiveCamera()->getCameraSceneNode())->setFOV(DEGREE_TO_RAD * UserConfigParams::m_camera_fov); + CameraNormal *camera = dynamic_cast(Camera::getActiveCamera()); + if (camera) + { + camera->setDistanceToKart(UserConfigParams::m_camera_distance); + } + } +} // updateCamera + +// ----------------------------------------------------------------------------- +void OptionsScreenCamera::updateCameraPresetSpinner() +{ + updateCamera(); +} // updateCameraPresetSpinner + +// ----------------------------------------------------------------------------- +void OptionsScreenCamera::eventCallback(Widget* widget, const std::string& name, const int playerID) +{ +#ifndef SERVER_ONLY + if (name == "options_choice") + { + std::string selection = ((RibbonWidget*)widget)->getSelectionIDString(PLAYER_ID_GAME_MASTER); + + if (selection != "tab_camera") + OptionsCommon::switchTab(selection); + } + else if(name == "back") + { + StateManager::get()->escapePressed(); + } + else if (name == "camera_preset") + { + GUIEngine::SpinnerWidget* camera_preset = getWidget("camera_preset"); + assert( camera_preset != NULL ); + unsigned int i = camera_preset->getValue(); + UserConfigParams::m_camera_present = i; + if (i == 1) //Standard + { + UserConfigParams::m_camera_fov = UserConfigParams::m_standard_camera_fov; + UserConfigParams::m_camera_distance = UserConfigParams::m_standard_camera_distance; + UserConfigParams::m_camera_forward_up_angle = UserConfigParams::m_standard_camera_forward_up_angle; + UserConfigParams::m_camera_forward_smoothing = UserConfigParams::m_standard_camera_forward_smoothing; + UserConfigParams::m_camera_backward_distance = UserConfigParams::m_standard_camera_backward_distance; + UserConfigParams::m_camera_backward_up_angle = UserConfigParams::m_standard_camera_backward_up_angle; + UserConfigParams::m_reverse_look_use_soccer_cam = UserConfigParams::m_standard_reverse_look_use_soccer_cam; + } + else if (i == 2) //Drone chase + { + UserConfigParams::m_camera_fov = UserConfigParams::m_drone_camera_fov; + UserConfigParams::m_camera_distance = UserConfigParams::m_drone_camera_distance; + UserConfigParams::m_camera_forward_up_angle = UserConfigParams::m_drone_camera_forward_up_angle; + UserConfigParams::m_camera_forward_smoothing = UserConfigParams::m_drone_camera_forward_smoothing; + UserConfigParams::m_camera_backward_distance = UserConfigParams::m_drone_camera_backward_distance; + UserConfigParams::m_camera_backward_up_angle = UserConfigParams::m_drone_camera_backward_up_angle; + UserConfigParams::m_reverse_look_use_soccer_cam = UserConfigParams::m_drone_reverse_look_use_soccer_cam; + } + else //Custom + { + UserConfigParams::m_camera_fov = UserConfigParams::m_saved_camera_fov; + UserConfigParams::m_camera_distance = UserConfigParams::m_saved_camera_distance; + UserConfigParams::m_camera_forward_up_angle = UserConfigParams::m_saved_camera_forward_up_angle; + UserConfigParams::m_camera_forward_smoothing = UserConfigParams::m_saved_camera_forward_smoothing; + UserConfigParams::m_camera_backward_distance = UserConfigParams::m_saved_camera_backward_distance; + UserConfigParams::m_camera_backward_up_angle = UserConfigParams::m_saved_camera_backward_up_angle; + UserConfigParams::m_reverse_look_use_soccer_cam = UserConfigParams::m_saved_reverse_look_use_soccer_cam; + } + updateCamera(); + } + else if(name == "custom_camera") + { + new CustomCameraSettingsDialog(0.8f, 0.95f); + } +#endif +} // eventCallback + +// ----------------------------------------------------------------------------- + +void OptionsScreenCamera::tearDown() +{ + Screen::tearDown(); + // save changes when leaving screen + user_config->saveConfig(); +} // tearDown + +// ----------------------------------------------------------------------------- + +void OptionsScreenCamera::unloaded() +{ + m_inited = false; +} // unloaded + +// ----------------------------------------------------------------------------- diff --git a/src/states_screens/options/options_screen_camera.hpp b/src/states_screens/options/options_screen_camera.hpp new file mode 100644 index 00000000000..0d94c363618 --- /dev/null +++ b/src/states_screens/options/options_screen_camera.hpp @@ -0,0 +1,63 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2009-2025 Marianne Gagnon, Alayan et al. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifndef __HEADER_OPTIONS_SCREEN_CAMERA_HPP__ +#define __HEADER_OPTIONS_SCREEN_CAMERA_HPP__ + +#include +#include + +#include "guiengine/screen.hpp" + +namespace GUIEngine { class Widget; } + +/** + * \brief Graphics options screen + * \ingroup states_screens + */ +class OptionsScreenCamera : public GUIEngine::Screen, public GUIEngine::ScreenSingleton +{ + OptionsScreenCamera(); + bool m_inited; + + void updateCamera(); +public: + friend class GUIEngine::ScreenSingleton; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void loadedFromFile() OVERRIDE; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name, + const int playerID) OVERRIDE; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void init() OVERRIDE; + + /** \brief implement callback from parent class GUIEngine::Screen */ + virtual void tearDown() OVERRIDE; + + /** \brief implement optional callback from parent class GUIEngine::Screen */ + virtual void unloaded() OVERRIDE; + + void updateCameraPresetSpinner(); + + void reloadGUIEngine(); +}; + +#endif diff --git a/src/states_screens/options/options_screen_ui.cpp b/src/states_screens/options/options_screen_ui.cpp index 6caa85f3df8..93397cb8e14 100644 --- a/src/states_screens/options/options_screen_ui.cpp +++ b/src/states_screens/options/options_screen_ui.cpp @@ -18,8 +18,6 @@ // Manages includes common to all options screens #include "states_screens/options/options_common.hpp" -#include "graphics/camera/camera.hpp" -#include "graphics/camera/camera_normal.hpp" #include "challenges/story_mode_timer.hpp" #include "config/player_manager.hpp" #include "font/font_manager.hpp" @@ -27,7 +25,6 @@ #include "items/attachment_manager.hpp" #include "items/powerup_manager.hpp" #include "modes/world.hpp" -#include "states_screens/dialogs/custom_camera_settings.hpp" #include "states_screens/dialogs/message_dialog.hpp" #include "states_screens/main_menu_screen.hpp" @@ -112,22 +109,6 @@ void OptionsScreenUI::loadedFromFile() font_size->m_properties[GUIEngine::PROP_MAX_VALUE] = "5"; } - // Setup camera spinner - GUIEngine::SpinnerWidget* camera_preset = getWidget("camera_preset"); - assert( camera_preset != NULL ); - - camera_preset->m_properties[PROP_WRAP_AROUND] = "true"; - camera_preset->clearLabels(); - //I18N: In the UI options, Camera setting: Custom - camera_preset->addLabel( core::stringw(_("Custom"))); - //I18N: In the UI options, Camera setting: Standard - camera_preset->addLabel( core::stringw(_("Standard"))); - //I18N: In the UI options, Camera setting: Drone chase - camera_preset->addLabel( core::stringw(_("Drone chase"))); - camera_preset->m_properties[GUIEngine::PROP_MIN_VALUE] = "0"; - camera_preset->m_properties[GUIEngine::PROP_MAX_VALUE] = "2"; - updateCameraPresetSpinner(); - font_size->setValueUpdatedCallback([this](SpinnerWidget* spinner) { // Add a special value updated callback so font size is updated when @@ -288,13 +269,6 @@ void OptionsScreenUI::init() } } speedrun_timer->setState( UserConfigParams::m_speedrun_mode ); - - // --- select the right camera in the spinner - GUIEngine::SpinnerWidget* camera_preset = getWidget("camera_preset"); - assert( camera_preset != NULL ); - - camera_preset->setValue(UserConfigParams::m_camera_present); // use the saved camera - updateCameraPresetSpinner(); } // init // ----------------------------------------------------------------------------- @@ -421,27 +395,6 @@ std::string OptionsScreenUI::getCurrentSpinnerSkin() return "classic"; // Default if nothing is found } // getCurrentSpinnerSkin -// ----------------------------------------------------------------------------- -void OptionsScreenUI::updateCamera() -{ - bool in_game = StateManager::get()->getGameState() == GUIEngine::INGAME_MENU; - if (in_game) - { - (Camera::getActiveCamera()->getCameraSceneNode())->setFOV(DEGREE_TO_RAD * UserConfigParams::m_camera_fov); - CameraNormal *camera = dynamic_cast(Camera::getActiveCamera()); - if (camera) - { - camera->setDistanceToKart(UserConfigParams::m_camera_distance); - } - } -} // updateCamera - -// ----------------------------------------------------------------------------- -void OptionsScreenUI::updateCameraPresetSpinner() -{ - updateCamera(); -} // updateCameraPresetSpinner - // ----------------------------------------------------------------------------- void OptionsScreenUI::eventCallback(Widget* widget, const std::string& name, const int playerID) { @@ -546,48 +499,6 @@ void OptionsScreenUI::eventCallback(Widget* widget, const std::string& name, con } UserConfigParams::m_speedrun_mode = speedrun_timer->getState(); } - else if (name == "camera_preset") - { - GUIEngine::SpinnerWidget* camera_preset = getWidget("camera_preset"); - assert( camera_preset != NULL ); - unsigned int i = camera_preset->getValue(); - UserConfigParams::m_camera_present = i; - if (i == 1) //Standard - { - UserConfigParams::m_camera_fov = UserConfigParams::m_standard_camera_fov; - UserConfigParams::m_camera_distance = UserConfigParams::m_standard_camera_distance; - UserConfigParams::m_camera_forward_up_angle = UserConfigParams::m_standard_camera_forward_up_angle; - UserConfigParams::m_camera_forward_smoothing = UserConfigParams::m_standard_camera_forward_smoothing; - UserConfigParams::m_camera_backward_distance = UserConfigParams::m_standard_camera_backward_distance; - UserConfigParams::m_camera_backward_up_angle = UserConfigParams::m_standard_camera_backward_up_angle; - UserConfigParams::m_reverse_look_use_soccer_cam = UserConfigParams::m_standard_reverse_look_use_soccer_cam; - } - else if (i == 2) //Drone chase - { - UserConfigParams::m_camera_fov = UserConfigParams::m_drone_camera_fov; - UserConfigParams::m_camera_distance = UserConfigParams::m_drone_camera_distance; - UserConfigParams::m_camera_forward_up_angle = UserConfigParams::m_drone_camera_forward_up_angle; - UserConfigParams::m_camera_forward_smoothing = UserConfigParams::m_drone_camera_forward_smoothing; - UserConfigParams::m_camera_backward_distance = UserConfigParams::m_drone_camera_backward_distance; - UserConfigParams::m_camera_backward_up_angle = UserConfigParams::m_drone_camera_backward_up_angle; - UserConfigParams::m_reverse_look_use_soccer_cam = UserConfigParams::m_drone_reverse_look_use_soccer_cam; - } - else //Custom - { - UserConfigParams::m_camera_fov = UserConfigParams::m_saved_camera_fov; - UserConfigParams::m_camera_distance = UserConfigParams::m_saved_camera_distance; - UserConfigParams::m_camera_forward_up_angle = UserConfigParams::m_saved_camera_forward_up_angle; - UserConfigParams::m_camera_forward_smoothing = UserConfigParams::m_saved_camera_forward_smoothing; - UserConfigParams::m_camera_backward_distance = UserConfigParams::m_saved_camera_backward_distance; - UserConfigParams::m_camera_backward_up_angle = UserConfigParams::m_saved_camera_backward_up_angle; - UserConfigParams::m_reverse_look_use_soccer_cam = UserConfigParams::m_saved_reverse_look_use_soccer_cam; - } - updateCamera(); - } - else if(name == "custom_camera") - { - new CustomCameraSettingsDialog(0.8f, 0.95f); - } #endif } // eventCallback diff --git a/src/states_screens/options/options_screen_ui.hpp b/src/states_screens/options/options_screen_ui.hpp index a8d23694bf7..c17fd90cc38 100644 --- a/src/states_screens/options/options_screen_ui.hpp +++ b/src/states_screens/options/options_screen_ui.hpp @@ -58,8 +58,6 @@ class OptionsScreenUI : public GUIEngine::Screen, public GUIEngine::ScreenSingle GUIEngine::SpinnerWidget* m_base_skin_selector; GUIEngine::SpinnerWidget* m_variant_skin_selector; - void updateCamera(); - void loadSkins(const std::set& files, bool addon); void loadCurrentSkinVariants(); int getBaseID(SkinID skin); @@ -85,8 +83,6 @@ class OptionsScreenUI : public GUIEngine::Screen, public GUIEngine::ScreenSingle /** \brief implement optional callback from parent class GUIEngine::Screen */ virtual void unloaded() OVERRIDE; - void updateCameraPresetSpinner(); - virtual void onUpdate(float delta) OVERRIDE; void reloadGUIEngine(); From 5dced9c22512103df0b1e086e40a1ecf40e7af5a Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 17 Feb 2025 14:06:15 +0100 Subject: [PATCH 550/830] Move the content of the camera dialog into the camera tab --- .../gui/dialogs/custom_camera_settings.stkgui | 87 -------- .../gui/screens/options/options_camera.stkgui | 68 ++++++- .../dialogs/custom_camera_settings.cpp | 190 ------------------ .../dialogs/custom_camera_settings.hpp | 63 ------ .../options/options_screen_camera.cpp | 165 ++++++++++++--- .../options/options_screen_camera.hpp | 8 + 6 files changed, 214 insertions(+), 367 deletions(-) delete mode 100644 data/gui/dialogs/custom_camera_settings.stkgui delete mode 100644 src/states_screens/dialogs/custom_camera_settings.cpp delete mode 100644 src/states_screens/dialogs/custom_camera_settings.hpp diff --git a/data/gui/dialogs/custom_camera_settings.stkgui b/data/gui/dialogs/custom_camera_settings.stkgui deleted file mode 100644 index e0e12f1cbac..00000000000 --- a/data/gui/dialogs/custom_camera_settings.stkgui +++ /dev/null @@ -1,87 +0,0 @@ - - -
-
- -
- -
-
-
diff --git a/data/gui/screens/options/options_camera.stkgui b/data/gui/screens/options/options_camera.stkgui index a4aa5d9d473..0b233999331 100644 --- a/data/gui/screens/options/options_camera.stkgui +++ b/data/gui/screens/options/options_camera.stkgui @@ -34,15 +34,77 @@ -
-
+ + + +
+ +
+
+
+ + + +
+ +
+
+
+ + + +
+ +
+
+
+ + + +
+ +
+ + +
+
+ + + +
diff --git a/src/states_screens/dialogs/custom_camera_settings.cpp b/src/states_screens/dialogs/custom_camera_settings.cpp deleted file mode 100644 index fbe0e40e888..00000000000 --- a/src/states_screens/dialogs/custom_camera_settings.cpp +++ /dev/null @@ -1,190 +0,0 @@ -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2009-2015 Marianne Gagnon -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 3 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include "states_screens/dialogs/custom_camera_settings.hpp" - -#include "config/user_config.hpp" -#include "guiengine/widgets/check_box_widget.hpp" -#include "guiengine/widgets/label_widget.hpp" -#include "guiengine/widgets/ribbon_widget.hpp" -#include "guiengine/widgets/spinner_widget.hpp" -#include "states_screens/options/options_screen_camera.hpp" -#include "states_screens/state_manager.hpp" -#include "utils/translation.hpp" -#include "graphics/central_settings.hpp" -#include "graphics/irr_driver.hpp" -#include "utils/string_utils.hpp" -#include "utils/translation.hpp" - -#include - - -using namespace GUIEngine; -using namespace irr; -using namespace irr::core; -using namespace irr::gui; - -// ----------------------------------------------------------------------------- - -CustomCameraSettingsDialog::CustomCameraSettingsDialog(const float w, const float h) : - ModalDialog(w, h) -{ - m_self_destroy = false; - loadFromFile("custom_camera_settings.stkgui"); -} - -// ----------------------------------------------------------------------------- - -CustomCameraSettingsDialog::~CustomCameraSettingsDialog() -{ -} - - -// ----------------------------------------------------------------------------- - -void CustomCameraSettingsDialog::beforeAddingWidgets() -{ -#ifndef SERVER_ONLY - getWidget("fov")->setRange(75, 115); - getWidget("camera_distance")->setRange(0.05f, 20, 0.05f); - getWidget("camera_angle")->setRange(0, 80); - getWidget("backward_camera_distance")->setRange(0.05f, 20, 0.05f); - getWidget("backward_camera_angle")->setRange(0, 80); - if (UserConfigParams::m_camera_present == 1) // Standard camera - { - getWidget("camera_name")->setText(_("Standard"), false); - getWidget("fov")->setValue(UserConfigParams::m_standard_camera_fov); - getWidget("camera_distance")->setFloatValue(UserConfigParams::m_standard_camera_distance); - getWidget("camera_angle")->setValue(UserConfigParams::m_standard_camera_forward_up_angle); - getWidget("backward_camera_distance")->setFloatValue(UserConfigParams::m_standard_camera_backward_distance); - getWidget("backward_camera_angle")->setValue(UserConfigParams::m_standard_camera_backward_up_angle); - getWidget("camera_smoothing")->setState(UserConfigParams::m_standard_camera_forward_smoothing); - getWidget("use_soccer_camera")->setState(UserConfigParams::m_standard_reverse_look_use_soccer_cam); - // Not allowed to change fov, distance, and angles. Only allow to change smoothing and follow soccer - getWidget("fov")->setActive(false); - getWidget("camera_distance")->setActive(false); - getWidget("camera_angle")->setActive(false); - getWidget("backward_camera_distance")->setActive(false); - getWidget("backward_camera_angle")->setActive(false); - } - else if (UserConfigParams::m_camera_present == 2) // Drone chase camera - { - getWidget("camera_name")->setText(_("Drone chase"), false); - getWidget("fov")->setValue(UserConfigParams::m_drone_camera_fov); - getWidget("camera_distance")->setFloatValue(UserConfigParams::m_drone_camera_distance); - getWidget("camera_angle")->setValue(UserConfigParams::m_drone_camera_forward_up_angle); - getWidget("backward_camera_distance")->setFloatValue(UserConfigParams::m_drone_camera_backward_distance); - getWidget("backward_camera_angle")->setValue(UserConfigParams::m_drone_camera_backward_up_angle); - getWidget("camera_smoothing")->setState(UserConfigParams::m_drone_camera_forward_smoothing); - getWidget("use_soccer_camera")->setState(UserConfigParams::m_drone_reverse_look_use_soccer_cam); - // Not allowed to change fov, distance, and angles. Only allow to change smoothing and follow soccer - getWidget("fov")->setActive(false); - getWidget("camera_distance")->setActive(false); - getWidget("camera_angle")->setActive(false); - getWidget("backward_camera_distance")->setActive(false); - getWidget("backward_camera_angle")->setActive(false); - } - else // Custom camera - { - getWidget("camera_name")->setText(_("Custom"), false); - getWidget("fov")->setValue(UserConfigParams::m_saved_camera_fov); - getWidget("camera_distance")->setFloatValue(UserConfigParams::m_saved_camera_distance); - getWidget("camera_angle")->setValue(UserConfigParams::m_saved_camera_forward_up_angle); - getWidget("camera_smoothing")->setState(UserConfigParams::m_saved_camera_forward_smoothing); - getWidget("backward_camera_distance")->setFloatValue(UserConfigParams::m_saved_camera_backward_distance); - getWidget("backward_camera_angle")->setValue(UserConfigParams::m_saved_camera_backward_up_angle); - getWidget("use_soccer_camera")->setState(UserConfigParams::m_saved_reverse_look_use_soccer_cam); - } -#endif -} - -// ----------------------------------------------------------------------------- - -GUIEngine::EventPropagation CustomCameraSettingsDialog::processEvent(const std::string& eventSource) -{ -#ifndef SERVER_ONLY - if (eventSource == "buttons") - { - const std::string& selection = getWidget("buttons")-> - getSelectionIDString(PLAYER_ID_GAME_MASTER); - - if (selection == "apply") - { - UserConfigParams::m_camera_forward_smoothing = getWidget("camera_smoothing")->getState(); - UserConfigParams::m_reverse_look_use_soccer_cam = getWidget("use_soccer_camera")->getState(); - if (UserConfigParams::m_camera_present == 1) // Standard camera, only smoothing and follow soccer is customizable - { - UserConfigParams::m_saved_camera_forward_smoothing = UserConfigParams::m_camera_forward_smoothing; - UserConfigParams::m_standard_reverse_look_use_soccer_cam = UserConfigParams::m_reverse_look_use_soccer_cam; - - } - else if (UserConfigParams::m_camera_present == 2) // Drone chase camera, only smoothing and follow soccer is customizable - { - UserConfigParams::m_drone_camera_forward_smoothing = UserConfigParams::m_camera_forward_smoothing; - UserConfigParams::m_drone_reverse_look_use_soccer_cam = UserConfigParams::m_reverse_look_use_soccer_cam; - } - else // Custom camera, everything is customizable - { - UserConfigParams::m_camera_fov = getWidget("fov")->getValue(); - UserConfigParams::m_camera_distance = getWidget("camera_distance")->getFloatValue(); - UserConfigParams::m_camera_forward_up_angle = getWidget("camera_angle")->getValue(); - UserConfigParams::m_camera_backward_distance = getWidget("backward_camera_distance")->getFloatValue(); - UserConfigParams::m_camera_backward_up_angle = getWidget("backward_camera_angle")->getValue(); - UserConfigParams::m_saved_camera_fov = UserConfigParams::m_camera_fov; - UserConfigParams::m_saved_camera_distance = UserConfigParams::m_camera_distance; - UserConfigParams::m_saved_camera_forward_up_angle = UserConfigParams::m_camera_forward_up_angle; - UserConfigParams::m_saved_camera_forward_smoothing = UserConfigParams::m_camera_forward_smoothing; - UserConfigParams::m_saved_camera_backward_distance = UserConfigParams::m_camera_backward_distance; - UserConfigParams::m_saved_camera_backward_up_angle = UserConfigParams::m_camera_backward_up_angle; - UserConfigParams::m_saved_reverse_look_use_soccer_cam = UserConfigParams::m_reverse_look_use_soccer_cam; - } - OptionsScreenCamera::getInstance()->updateCameraPresetSpinner(); - m_self_destroy = true; - return GUIEngine::EVENT_BLOCK; - } - else if (selection == "reset") // discard all the changes - { - if (UserConfigParams::m_camera_present == 1) // Standard camera - { - getWidget("camera_smoothing")->setState(UserConfigParams::m_standard_camera_forward_smoothing); - getWidget("use_soccer_camera")->setState(UserConfigParams::m_standard_reverse_look_use_soccer_cam); - } - else if (UserConfigParams::m_camera_present == 2) // Drone chase camera - { - getWidget("camera_smoothing")->setState(UserConfigParams::m_drone_camera_forward_smoothing); - getWidget("use_soccer_camera")->setState(UserConfigParams::m_drone_reverse_look_use_soccer_cam); - } - else // Custom camera - { - getWidget("fov")->setValue(UserConfigParams::m_saved_camera_fov); - getWidget("camera_distance")->setFloatValue(UserConfigParams::m_saved_camera_distance); - getWidget("camera_angle")->setValue(UserConfigParams::m_saved_camera_forward_up_angle); - getWidget("camera_smoothing")->setState(UserConfigParams::m_saved_camera_forward_smoothing); - getWidget("backward_camera_distance")->setFloatValue(UserConfigParams::m_saved_camera_backward_distance); - getWidget("backward_camera_angle")->setValue(UserConfigParams::m_saved_camera_backward_up_angle); - getWidget("use_soccer_camera")->setState(UserConfigParams::m_saved_reverse_look_use_soccer_cam); - } - } - else if (selection == "cancel") - { - ModalDialog::dismiss(); - return GUIEngine::EVENT_BLOCK; - } - } -#endif - return GUIEngine::EVENT_LET; -} // processEvent diff --git a/src/states_screens/dialogs/custom_camera_settings.hpp b/src/states_screens/dialogs/custom_camera_settings.hpp deleted file mode 100644 index cb9a084a410..00000000000 --- a/src/states_screens/dialogs/custom_camera_settings.hpp +++ /dev/null @@ -1,63 +0,0 @@ -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2009-2015 Marianne Gagnon -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 3 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - -#ifndef HEADER_CUSTOM_CAMERA_SETTINGS_HPP -#define HEADER_CUSTOM_CAMERA_SETTINGS_HPP - -#include "guiengine/modaldialog.hpp" - -/** - * \brief Dialog that allows the player to select custom video settings - * \ingroup states_screens - */ -class CustomCameraSettingsDialog : public GUIEngine::ModalDialog -{ -private: - bool m_self_destroy; -public: - /** - * Creates a modal dialog with given percentage of screen width and height - */ - CustomCameraSettingsDialog(const float percentWidth, const float percentHeight); - ~CustomCameraSettingsDialog(); - - virtual void beforeAddingWidgets(); - - void updateActivation(); - - GUIEngine::EventPropagation processEvent(const std::string& eventSource); - - virtual bool onEscapePressed() - { - m_self_destroy = true; - return false; - } - - virtual void onUpdate(float dt) - { - // It's unsafe to delete from inside the event handler so we do it here - if (m_self_destroy) - { - ModalDialog::dismiss(); - return; - } - } - -}; - -#endif diff --git a/src/states_screens/options/options_screen_camera.cpp b/src/states_screens/options/options_screen_camera.cpp index 17099fc6e5e..d1b602891d9 100644 --- a/src/states_screens/options/options_screen_camera.cpp +++ b/src/states_screens/options/options_screen_camera.cpp @@ -21,7 +21,6 @@ #include "graphics/camera/camera.hpp" #include "graphics/camera/camera_normal.hpp" #include "config/player_manager.hpp" -#include "states_screens/dialogs/custom_camera_settings.hpp" #include "states_screens/dialogs/message_dialog.hpp" #include "states_screens/main_menu_screen.hpp" @@ -58,6 +57,14 @@ void OptionsScreenCamera::loadedFromFile() camera_preset->m_properties[GUIEngine::PROP_MIN_VALUE] = "0"; camera_preset->m_properties[GUIEngine::PROP_MAX_VALUE] = "2"; updateCameraPresetSpinner(); + +#ifndef SERVER_ONLY + getWidget("fov")->setRange(75, 115); + getWidget("camera_distance")->setRange(0.05f, 20, 0.05f); + getWidget("camera_angle")->setRange(0, 80); + getWidget("backward_camera_distance")->setRange(0.05f, 20, 0.05f); + getWidget("backward_camera_angle")->setRange(0, 80); +#endif } // loadedFromFile // ----------------------------------------------------------------------------- @@ -78,6 +85,40 @@ void OptionsScreenCamera::init() camera_preset->setValue(UserConfigParams::m_camera_present); // use the saved camera updateCameraPresetSpinner(); + +#ifndef SERVER_ONLY + getWidget("fov")->setRange(75, 115); + getWidget("camera_distance")->setRange(0.05f, 20, 0.05f); + getWidget("camera_angle")->setRange(0, 80); + getWidget("backward_camera_distance")->setRange(0.05f, 20, 0.05f); + getWidget("backward_camera_angle")->setRange(0, 80); + if (UserConfigParams::m_camera_present == 1) // Standard camera + { + setCameraParameters (UserConfigParams::m_standard_camera_fov, UserConfigParams::m_standard_camera_distance, + UserConfigParams::m_standard_camera_forward_up_angle, UserConfigParams::m_standard_camera_backward_distance, + UserConfigParams::m_standard_camera_backward_up_angle, UserConfigParams::m_standard_camera_forward_smoothing, + UserConfigParams::m_standard_reverse_look_use_soccer_cam); + // Not allowed to change fov, distance, and angles. Only allow to change smoothing and follow soccer + setSpinnersActive(false); + } + else if (UserConfigParams::m_camera_present == 2) // Drone chase camera + { + setCameraParameters (UserConfigParams::m_drone_camera_fov, UserConfigParams::m_drone_camera_distance, + UserConfigParams::m_drone_camera_forward_up_angle, UserConfigParams::m_drone_camera_backward_distance, + UserConfigParams::m_drone_camera_backward_up_angle, UserConfigParams::m_drone_camera_forward_smoothing, + UserConfigParams::m_drone_reverse_look_use_soccer_cam); + // Not allowed to change fov, distance, and angles. Only allow to change smoothing and follow soccer + setSpinnersActive(false); + } + else // Custom camera + { + setCameraParameters (UserConfigParams::m_saved_camera_fov, UserConfigParams::m_saved_camera_distance, + UserConfigParams::m_saved_camera_forward_up_angle, UserConfigParams::m_saved_camera_backward_distance, + UserConfigParams::m_saved_camera_backward_up_angle, UserConfigParams::m_saved_camera_forward_smoothing, + UserConfigParams::m_saved_reverse_look_use_soccer_cam); + setSpinnersActive(true); + } +#endif } // init // ----------------------------------------------------------------------------- @@ -101,6 +142,38 @@ void OptionsScreenCamera::updateCameraPresetSpinner() updateCamera(); } // updateCameraPresetSpinner +// ----------------------------------------------------------------------------- +void OptionsScreenCamera::setSpinnersActive(bool spinner_status) +{ + getWidget("fov")->setActive(spinner_status); + getWidget("camera_distance")->setActive(spinner_status); + getWidget("camera_angle")->setActive(spinner_status); + getWidget("backward_camera_distance")->setActive(spinner_status); + getWidget("backward_camera_angle")->setActive(spinner_status); +} // setSpinnersActive + +// ----------------------------------------------------------------------------- +void OptionsScreenCamera::setCameraParameters(int fov, float distance, float angle, float bw_distance, + float bw_angle, bool forward_smoothing, bool soccer_follow) +{ + UserConfigParams::m_camera_fov = fov; + UserConfigParams::m_camera_distance = distance; + UserConfigParams::m_camera_forward_up_angle = angle; + UserConfigParams::m_camera_backward_distance = bw_distance; + UserConfigParams::m_camera_backward_up_angle = bw_angle; + UserConfigParams::m_camera_forward_smoothing = forward_smoothing; + UserConfigParams::m_reverse_look_use_soccer_cam = soccer_follow; + + // Update the widget values alongside + getWidget("fov")->setValue(fov); + getWidget("camera_distance")->setFloatValue(distance); + getWidget("camera_angle")->setValue(angle); + getWidget("backward_camera_distance")->setFloatValue(bw_distance); + getWidget("backward_camera_angle")->setValue(bw_angle); + getWidget("camera_smoothing")->setState(forward_smoothing); + getWidget("use_soccer_camera")->setState(soccer_follow); +} // setCameraParameters + // ----------------------------------------------------------------------------- void OptionsScreenCamera::eventCallback(Widget* widget, const std::string& name, const int playerID) { @@ -124,39 +197,83 @@ void OptionsScreenCamera::eventCallback(Widget* widget, const std::string& name, UserConfigParams::m_camera_present = i; if (i == 1) //Standard { - UserConfigParams::m_camera_fov = UserConfigParams::m_standard_camera_fov; - UserConfigParams::m_camera_distance = UserConfigParams::m_standard_camera_distance; - UserConfigParams::m_camera_forward_up_angle = UserConfigParams::m_standard_camera_forward_up_angle; - UserConfigParams::m_camera_forward_smoothing = UserConfigParams::m_standard_camera_forward_smoothing; - UserConfigParams::m_camera_backward_distance = UserConfigParams::m_standard_camera_backward_distance; - UserConfigParams::m_camera_backward_up_angle = UserConfigParams::m_standard_camera_backward_up_angle; - UserConfigParams::m_reverse_look_use_soccer_cam = UserConfigParams::m_standard_reverse_look_use_soccer_cam; + setCameraParameters (UserConfigParams::m_standard_camera_fov, UserConfigParams::m_standard_camera_distance, + UserConfigParams::m_standard_camera_forward_up_angle, UserConfigParams::m_standard_camera_backward_distance, + UserConfigParams::m_standard_camera_backward_up_angle, UserConfigParams::m_standard_camera_forward_smoothing, + UserConfigParams::m_standard_reverse_look_use_soccer_cam); + setSpinnersActive(false); } else if (i == 2) //Drone chase { - UserConfigParams::m_camera_fov = UserConfigParams::m_drone_camera_fov; - UserConfigParams::m_camera_distance = UserConfigParams::m_drone_camera_distance; - UserConfigParams::m_camera_forward_up_angle = UserConfigParams::m_drone_camera_forward_up_angle; - UserConfigParams::m_camera_forward_smoothing = UserConfigParams::m_drone_camera_forward_smoothing; - UserConfigParams::m_camera_backward_distance = UserConfigParams::m_drone_camera_backward_distance; - UserConfigParams::m_camera_backward_up_angle = UserConfigParams::m_drone_camera_backward_up_angle; - UserConfigParams::m_reverse_look_use_soccer_cam = UserConfigParams::m_drone_reverse_look_use_soccer_cam; + setCameraParameters (UserConfigParams::m_drone_camera_fov, UserConfigParams::m_drone_camera_distance, + UserConfigParams::m_drone_camera_forward_up_angle, UserConfigParams::m_drone_camera_backward_distance, + UserConfigParams::m_drone_camera_backward_up_angle, UserConfigParams::m_drone_camera_forward_smoothing, + UserConfigParams::m_drone_reverse_look_use_soccer_cam); + setSpinnersActive(false); } else //Custom { - UserConfigParams::m_camera_fov = UserConfigParams::m_saved_camera_fov; - UserConfigParams::m_camera_distance = UserConfigParams::m_saved_camera_distance; - UserConfigParams::m_camera_forward_up_angle = UserConfigParams::m_saved_camera_forward_up_angle; - UserConfigParams::m_camera_forward_smoothing = UserConfigParams::m_saved_camera_forward_smoothing; - UserConfigParams::m_camera_backward_distance = UserConfigParams::m_saved_camera_backward_distance; - UserConfigParams::m_camera_backward_up_angle = UserConfigParams::m_saved_camera_backward_up_angle; - UserConfigParams::m_reverse_look_use_soccer_cam = UserConfigParams::m_saved_reverse_look_use_soccer_cam; + setCameraParameters (UserConfigParams::m_saved_camera_fov, UserConfigParams::m_saved_camera_distance, + UserConfigParams::m_saved_camera_forward_up_angle, UserConfigParams::m_saved_camera_backward_distance, + UserConfigParams::m_saved_camera_backward_up_angle, UserConfigParams::m_saved_camera_forward_smoothing, + UserConfigParams::m_saved_reverse_look_use_soccer_cam); + setSpinnersActive(true); } updateCamera(); } - else if(name == "custom_camera") + else if (name == "camera_smoothing") { - new CustomCameraSettingsDialog(0.8f, 0.95f); + UserConfigParams::m_camera_forward_smoothing = getWidget("camera_smoothing")->getState(); + if (UserConfigParams::m_camera_present == 1) // Standard camera + UserConfigParams::m_standard_camera_forward_smoothing = UserConfigParams::m_camera_forward_smoothing; + else if (UserConfigParams::m_camera_present == 2) // Drone chase camera + UserConfigParams::m_drone_camera_forward_smoothing = UserConfigParams::m_camera_forward_smoothing; + else // Custom camera + UserConfigParams::m_saved_camera_forward_smoothing = UserConfigParams::m_camera_forward_smoothing; + updateCamera(); + } + else if (name == "use_soccer_camera") + { + UserConfigParams::m_reverse_look_use_soccer_cam = getWidget("use_soccer_camera")->getState(); + if (UserConfigParams::m_camera_present == 1) // Standard camera + UserConfigParams::m_standard_reverse_look_use_soccer_cam = UserConfigParams::m_reverse_look_use_soccer_cam; + else if (UserConfigParams::m_camera_present == 2) // Drone chase camera + UserConfigParams::m_drone_reverse_look_use_soccer_cam = UserConfigParams::m_reverse_look_use_soccer_cam; + else // Custom camera + UserConfigParams::m_saved_reverse_look_use_soccer_cam = UserConfigParams::m_reverse_look_use_soccer_cam; + updateCamera(); + } + // Only the custom camera can update the following widgets, so we don't test the active camera preset + else if (name == "fov") + { + UserConfigParams::m_camera_fov = getWidget("fov")->getValue(); + UserConfigParams::m_saved_camera_fov = UserConfigParams::m_camera_fov; + updateCamera(); + } + else if (name == "camera_distance") + { + UserConfigParams::m_camera_distance = getWidget("camera_distance")->getFloatValue(); + UserConfigParams::m_saved_camera_distance = UserConfigParams::m_camera_distance; + updateCamera(); + } + else if (name == "camera_angle") + { + UserConfigParams::m_camera_forward_up_angle = getWidget("camera_angle")->getValue(); + UserConfigParams::m_saved_camera_forward_up_angle = UserConfigParams::m_camera_forward_up_angle; + updateCamera(); + } + + else if (name == "backward_camera_distance") + { + UserConfigParams::m_camera_backward_distance = getWidget("backward_camera_distance")->getFloatValue(); + UserConfigParams::m_saved_camera_backward_distance = UserConfigParams::m_camera_backward_distance; + updateCamera(); + } + else if (name == "backward_camera_angle") + { + UserConfigParams::m_camera_backward_up_angle = getWidget("backward_camera_angle")->getValue(); + UserConfigParams::m_saved_camera_backward_up_angle = UserConfigParams::m_camera_backward_up_angle; + updateCamera(); } #endif } // eventCallback diff --git a/src/states_screens/options/options_screen_camera.hpp b/src/states_screens/options/options_screen_camera.hpp index 0d94c363618..ba0ec1309b9 100644 --- a/src/states_screens/options/options_screen_camera.hpp +++ b/src/states_screens/options/options_screen_camera.hpp @@ -57,6 +57,14 @@ class OptionsScreenCamera : public GUIEngine::Screen, public GUIEngine::ScreenSi void updateCameraPresetSpinner(); + /** Enables or disables the spinners allowing to customize a camera values */ + void setSpinnersActive(bool spinner_status); + + /** Update the active camera parameters and the status of the parameters widgets, + * used when switching the active camera */ + void setCameraParameters(int fov, float distance, float angle, float bw_distance, + float bw_angle, bool forward_smoothing, bool soccer_follow); + void reloadGUIEngine(); }; From 864d8c13fc8db9c6edca67e86880565698a57172 Mon Sep 17 00:00:00 2001 From: Maxim Leshchenko Date: Mon, 17 Feb 2025 14:16:32 +0100 Subject: [PATCH 551/830] Put the macOS icon in a rounded rectangle (#5299) --- data/supertuxkart.icns | Bin 35149 -> 950595 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/supertuxkart.icns b/data/supertuxkart.icns index d33c8a656c44a113167b46ea9cac7fe0c13c0146..07ffdee3675741b9b2033e67a6e330b916364e8d 100644 GIT binary patch literal 950595 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

Zh!TDnCGXou0|C$v;u5r8Wa$)`Ya1atKyIMIG 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%0DdP+7g}|)t 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

^QEr#MxbqeX0Z$h-h=)4ROGKZp7R_aMkf}mn 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

`_UP}mm&H>z?6SRodL(yO;I^=Qz2bxc9e#)~ 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 psyNRc|j#fBw(M_b(QJ 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 H*gpC{=yd8M literal 35149 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 Zfu9lh8G)Y>_!)tp5%?K_|5Fk8{{Z4Rm4pBQ From 50c5afa2ef281485d0912a5988e5bb987c7f0fa4 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 17 Feb 2025 22:31:54 +0800 Subject: [PATCH 552/830] Reduce uniform size --- data/shaders/sunlightshadow.frag | 28 +++++++------- data/shaders/sunlightshadowpcss.frag | 34 ++++++++-------- src/graphics/lighting_passes.cpp | 58 ++++++++++++++++------------ 3 files changed, 64 insertions(+), 56 deletions(-) diff --git a/data/shaders/sunlightshadow.frag b/data/shaders/sunlightshadow.frag index 30ca5197985..55a8ae252b1 100644 --- a/data/shaders/sunlightshadow.frag +++ b/data/shaders/sunlightshadow.frag @@ -10,16 +10,16 @@ uniform float split0; uniform float split1; uniform float split2; uniform float splitmax; + +uniform vec3 sundirection; uniform float shadow_res; +uniform vec3 sun_color; uniform float overlap_proportion; -uniform vec3 box0; -uniform vec3 box1; -uniform vec3 box2; -uniform vec3 box3; - -uniform vec3 sundirection; -uniform vec3 sun_color; +uniform float texel0; +uniform float texel1; +uniform float texel2; +uniform float texel3; in vec2 uv; #ifdef GL_ES @@ -123,25 +123,25 @@ void main() { nbias -= Lightdir * dot(nbias, Lightdir); // Slope-scaled normal bias if (xpos.z < split0) { - factor = getShadowFactor(xpos.xyz + lbias + nbias * max(box0.x, box0.y), 0); + factor = getShadowFactor(xpos.xyz + lbias + nbias * texel0, 0); if (xpos.z > blend_start(split0)) { - factor = mix(factor, getShadowFactor(xpos.xyz + lbias + nbias * max(box1.x, box1.y), 1), + factor = mix(factor, getShadowFactor(xpos.xyz + lbias + nbias * texel1, 1), (xpos.z - blend_start(split0)) / split0 / overlap_proportion); } } else if (xpos.z < split1) { - factor = getShadowFactor(xpos.xyz + lbias + nbias * max(box1.x, box1.y), 1); + factor = getShadowFactor(xpos.xyz + lbias + nbias * texel1, 1); if (xpos.z > blend_start(split1)) { - factor = mix(factor, getShadowFactor(xpos.xyz + lbias + nbias * max(box2.x, box2.y), 2), + factor = mix(factor, getShadowFactor(xpos.xyz + lbias + nbias * texel2, 2), (xpos.z - blend_start(split1)) / split1 / overlap_proportion); } } else if (xpos.z < split2) { - factor = getShadowFactor(xpos.xyz + lbias + nbias * max(box2.x, box2.y), 2); + factor = getShadowFactor(xpos.xyz + lbias + nbias * texel2, 2); if (xpos.z > blend_start(split2)) { - factor = mix(factor, getShadowFactor(xpos.xyz + lbias + nbias * max(box3.x, box3.y), 3), + factor = mix(factor, getShadowFactor(xpos.xyz + lbias + nbias * texel3, 3), (xpos.z - blend_start(split2)) / split2 / overlap_proportion); } } else if (xpos.z < splitmax) { - factor = getShadowFactor(xpos.xyz + lbias + nbias * max(box3.x, box3.y), 3); + factor = getShadowFactor(xpos.xyz + lbias + nbias * texel3, 3); if (xpos.z > blend_start(splitmax)) { factor = mix(factor, 1.0, (xpos.z - blend_start(splitmax)) / splitmax / overlap_proportion); } diff --git a/data/shaders/sunlightshadowpcss.frag b/data/shaders/sunlightshadowpcss.frag index b702aa42161..ef104008f0f 100644 --- a/data/shaders/sunlightshadowpcss.frag +++ b/data/shaders/sunlightshadowpcss.frag @@ -12,16 +12,16 @@ uniform float split0; uniform float split1; uniform float split2; uniform float splitmax; + +uniform vec3 sundirection; uniform float shadow_res; +uniform vec3 sun_color; uniform float overlap_proportion; -uniform vec3 box0; -uniform vec3 box1; -uniform vec3 box2; -uniform vec3 box3; - -uniform vec3 sundirection; -uniform vec3 sun_color; +uniform vec2 penumbra0; +uniform vec2 penumbra1; +uniform vec2 penumbra2; +uniform vec2 penumbra3; in vec2 uv; #ifdef GL_ES @@ -139,25 +139,23 @@ float filterPCSS(vec2 uv, float z_rec, uint layer, return occludedCount * (1.0 / 16.0); } -float getShadowFactor(vec3 position, vec3 bbox, vec2 dz_duv, uint layer) +float getShadowFactor(vec3 position, vec2 penumbra, vec2 dz_duv, uint layer) { - float penumbra = tan(3.14 * sun_angle / 360.) * bbox.z * position.z; - // rotate the poisson disk randomly mat2 R = getRandomRotationMatrix(gl_FragCoord.xy); float occludedCount = 0.0; float z_occSum = 0.0; - blockerSearchAndFilter(occludedCount, z_occSum, position.xy, position.z, layer, penumbra / bbox.xy, dz_duv); + blockerSearchAndFilter(occludedCount, z_occSum, position.xy, position.z, layer, penumbra * position.z, dz_duv); // early exit if there is no occluders at all, also avoids a divide-by-zero below. if (z_occSum == 0.0) { return 1.0; } - float penumbraRatio = 1.0 - z_occSum / occludedCount / position.z; - vec2 radius = max(penumbra / bbox.xy * penumbraRatio, vec2(0.5 / shadow_res)); + float penumbraRatio = position.z - z_occSum / occludedCount; + vec2 radius = max(penumbra * penumbraRatio, vec2(0.5 / shadow_res)); float percentageOccluded = filterPCSS(position.xy, position.z, layer, radius, R, dz_duv); @@ -174,7 +172,7 @@ void main() { vec4 xpos = getPosFromUVDepth(vec3(uv, z), u_inverse_projection_matrix); vec3 norm = DecodeNormal(texture(ntex, uv).xy); - float roughness =texture(ntex, uv).z; + float roughness = texture(ntex, uv).z; vec3 eyedir = -normalize(xpos.xyz); vec3 Lightdir = SunMRP(norm, eyedir); @@ -206,11 +204,11 @@ void main() { float factor; if (xpos.z < split0) { - float factor2 = getShadowFactor(position1, box0, dz_duv1, 0); + float factor2 = getShadowFactor(position1, penumbra0, dz_duv1, 0); factor = factor2; } if (blend_start(split0) < xpos.z && xpos.z < split1) { - float factor2 = getShadowFactor(position2, box1, dz_duv2, 1); + float factor2 = getShadowFactor(position2, penumbra1, dz_duv2, 1); if (xpos.z < split0) { factor = mix(factor, factor2, (xpos.z - blend_start(split0)) / split0 / overlap_proportion); } else { @@ -218,7 +216,7 @@ void main() { } } if (blend_start(split1) < xpos.z && xpos.z < split2) { - float factor2 = getShadowFactor(position3, box2, dz_duv3, 2); + float factor2 = getShadowFactor(position3, penumbra2, dz_duv3, 2); if (xpos.z < split1) { factor = mix(factor, factor2, (xpos.z - blend_start(split1)) / split1 / overlap_proportion); } else { @@ -226,7 +224,7 @@ void main() { } } if (blend_start(split2) < xpos.z && xpos.z < splitmax) { - float factor2 = getShadowFactor(position4, box3, dz_duv4, 3); + float factor2 = getShadowFactor(position4, penumbra3, dz_duv4, 3); if (xpos.z < split2) { factor = mix(factor, factor2, (xpos.z - blend_start(split2)) / split2 / overlap_proportion); } else { diff --git a/src/graphics/lighting_passes.cpp b/src/graphics/lighting_passes.cpp index c7e79c5cb5d..76588df5c56 100644 --- a/src/graphics/lighting_passes.cpp +++ b/src/graphics/lighting_passes.cpp @@ -205,8 +205,7 @@ class DegradedIBLShader : public TextureShader class ShadowedSunLightShaderPCF : public TextureShader { public: @@ -220,7 +219,8 @@ class ShadowedSunLightShaderPCF : public TextureShadergetDepthTexture() ); - drawFullScreenEffect(ShadowMatrices::m_shadow_split[1], - ShadowMatrices::m_shadow_split[2], - ShadowMatrices::m_shadow_split[3], - ShadowMatrices::m_shadow_split[4], - float(UserConfigParams::m_shadows_resolution), - ShadowMatrices::m_shadow_overlap_proportion, - shadow_box_extents[0], shadow_box_extents[1], - shadow_box_extents[2], shadow_box_extents[3], - direction, col); + std::array texel; + for (int i = 0; i < 4; i++) + { + texel[i] = std::max(shadow_box_extents[i].X, shadow_box_extents[i].Y); + } + drawFullScreenEffect(ShadowMatrices::m_shadow_split[1], + ShadowMatrices::m_shadow_split[2], + ShadowMatrices::m_shadow_split[3], + ShadowMatrices::m_shadow_split[4], + float(UserConfigParams::m_shadows_resolution), + ShadowMatrices::m_shadow_overlap_proportion, + texel[0], texel[1], texel[2], texel[3], + direction, col); } // render }; // ShadowedSunLightShaderPCF @@ -250,8 +254,8 @@ class ShadowedSunLightShaderPCF : public TextureShader { public: @@ -266,7 +270,8 @@ class ShadowedSunLightShaderPCSS : public TextureShadergetDepthTexture(), shadow_framebuffer->getDepthTexture() ); - drawFullScreenEffect(ShadowMatrices::m_shadow_split[1], - ShadowMatrices::m_shadow_split[2], - ShadowMatrices::m_shadow_split[3], - ShadowMatrices::m_shadow_split[4], - float(UserConfigParams::m_shadows_resolution), - ShadowMatrices::m_shadow_overlap_proportion, - shadow_box_extents[0], shadow_box_extents[1], - shadow_box_extents[2], shadow_box_extents[3], - direction, col); + std::array penumbra; + for (int i = 0; i < 4; i++) + { + float size = tan(core::PI64 * 0.54 / 360.) * shadow_box_extents[i].Z; + penumbra[i] = core::vector2df(size / shadow_box_extents[i].X, size / shadow_box_extents[i].Y); + } + drawFullScreenEffect(ShadowMatrices::m_shadow_split[1], + ShadowMatrices::m_shadow_split[2], + ShadowMatrices::m_shadow_split[3], + ShadowMatrices::m_shadow_split[4], + float(UserConfigParams::m_shadows_resolution), + ShadowMatrices::m_shadow_overlap_proportion, + penumbra[0], penumbra[1], penumbra[2], penumbra[3], + direction, col); } // render }; // ShadowedSunLightShaderPCSS From b42f4df182680a8c65f80b4bb72f6f82e386e87c Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 17 Feb 2025 23:46:23 +0800 Subject: [PATCH 553/830] Slow down new animation a bit for low fps --- src/items/attachment.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/items/attachment.cpp b/src/items/attachment.cpp index 78da8a2986f..87d2b3fdfaa 100644 --- a/src/items/attachment.cpp +++ b/src/items/attachment.cpp @@ -621,9 +621,9 @@ void Attachment::updateGraphics(float dt) { const float progress = 1.0f - scale_ratio; - const float x = 0.2f * atan(25.0f * progress - 5.0f) + 0.69f; + const float x = 0.2f * atan(20.0f * progress - 5.0f) + 0.7f; const float y = x; - const float z = 1.0f - pow(2.0f, -20.f * progress); + const float z = 1.0f - pow(2.0f, -15.f * progress); m_node->setScale(core::vector3df(x * wanted_node_scale, y * wanted_node_scale, @@ -638,7 +638,7 @@ void Attachment::updateGraphics(float dt) const float x = scale_ratio; scale_ratio = x <= 0 ? 0 : x >= 1 ? 1 - : -pow(2, 10 * x - 10) * sin((x * 10 - 10.75) * c4); + : -pow(2, 8 * x - 8) * sin((x * 8 - 8.75) * c4); } float scale = 0.3f * scale_ratio + From c46e1ce457529cc575543eb9186702216913fccd Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Wed, 19 Feb 2025 17:20:15 +0800 Subject: [PATCH 554/830] Fix #5301 --- lib/mcpp/system.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/mcpp/system.c b/lib/mcpp/system.c index a5b0d85c742..9b8ffeec6c3 100644 --- a/lib/mcpp/system.c +++ b/lib/mcpp/system.c @@ -3435,7 +3435,7 @@ static int open_file( if (! fullname) /* Non-existent or directory */ return FALSE; if (standard && included( fullname)) /* Once included */ - goto true; + goto case_true; if ((max_open != 0 && max_open <= include_nest) /* Exceed the known limit of open files */ @@ -3462,12 +3462,12 @@ static int open_file( if ((fp = fopen( fullname, "r")) == NULL) { file->fp = fopen( cur_fullname, "r"); fseek( file->fp, file->pos, SEEK_SET); - goto false; + goto case_false; } if (max_open == 0) /* Remember the limit of the system */ max_open = include_nest; } else if (fp == NULL) /* No read permission */ - goto false; + goto case_false; /* Truncate buffer of the includer to save memory */ len = (int) (file->bptr - file->buffer); if (len) { @@ -3514,9 +3514,9 @@ static int open_file( if (mkdep && ((mkdep & MD_SYSHEADER) || ! infile->sys_header)) put_depend( fullname); /* Output dependency line */ -true: +case_true: return TRUE; -false: +case_false: free( fullname); return FALSE; } From 83e029cc123176a77a239edf90ee461e46f9f8a2 Mon Sep 17 00:00:00 2001 From: Gwyn Ciesla Date: Wed, 19 Feb 2025 09:34:58 -0600 Subject: [PATCH 555/830] Add include to work with gcc15. (#5310) --- src/network/remote_kart_info.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/remote_kart_info.hpp b/src/network/remote_kart_info.hpp index 80a6339187c..9865dcda8c3 100644 --- a/src/network/remote_kart_info.hpp +++ b/src/network/remote_kart_info.hpp @@ -29,6 +29,7 @@ #include #include #include +#include enum KartTeam : int8_t { From 43448e0555a2b92a6e05e239e2d0b008429430f5 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 24 Feb 2025 12:29:28 +0400 Subject: [PATCH 556/830] Use the addon date format for news screen (#5312) Also add a function that converts day/month/year, and not TimeType, to date string --- src/states_screens/online/online_screen.cpp | 4 +-- src/utils/time.cpp | 34 +++++++++++++++++++-- src/utils/time.hpp | 7 +++++ 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/states_screens/online/online_screen.cpp b/src/states_screens/online/online_screen.cpp index 18384a44f86..24b24f27588 100644 --- a/src/states_screens/online/online_screen.cpp +++ b/src/states_screens/online/online_screen.cpp @@ -195,9 +195,7 @@ void OnlineScreen::loadList() // Date format int yyyy, mm, dd; sscanf(date.c_str(), "%d-%d-%d", &yyyy, &mm, &dd); - date = StringUtils::toString(yyyy) + "-" - + StringUtils::toString(mm) + "-" - + StringUtils::toString(dd); + date = StkTime::toString(yyyy, mm, dd); std::vector row; row.push_back(GUIEngine::ListWidget::ListCell(str.c_str(), icon, 4, false)); diff --git a/src/utils/time.cpp b/src/utils/time.cpp index 2865556c758..8f87cde7d8a 100644 --- a/src/utils/time.cpp +++ b/src/utils/time.cpp @@ -70,6 +70,36 @@ std::string StkTime::toString(const TimeType &tt) { const struct tm *t = gmtime(&tt); + std::string date_format = getDateFormat(); + + char s[64]; + strftime(s, 64, date_format.c_str(), t); + return s; +} // toString(1) + +// ---------------------------------------------------------------------------- + +/** Converts the date represented by year, month, day + * to a human readable string. */ +std::string StkTime::toString(int year, int month, int day) +{ + struct tm *t = new tm(); + t->tm_year = year - 1900; + t->tm_mon = month - 1; + t->tm_mday = day; + + std::string date_format = getDateFormat(); + + char s[64]; + strftime(s, 64, date_format.c_str(), t); + return s; +} // toString(3) + +// ---------------------------------------------------------------------------- + +/** Obtains the translated format of the time string. */ +std::string StkTime::getDateFormat() +{ //I18N: Format for dates (%d = day, %m = month, %Y = year). See http://www.cplusplus.com/reference/ctime/strftime/ for more info about date formats. core::stringw w_date_format = translations->w_gettext(N_("%d/%m/%Y")); core::stringc c_date_format(w_date_format.c_str()); @@ -82,9 +112,7 @@ std::string StkTime::toString(const TimeType &tt) date_format = "%d/%m/%Y"; } - char s[64]; - strftime(s, 64, date_format.c_str(), t); - return s; + return date_format; } // toString // ---------------------------------------------------------------------------- diff --git a/src/utils/time.hpp b/src/utils/time.hpp index ae7d3b95a8e..7a04b6db565 100644 --- a/src/utils/time.hpp +++ b/src/utils/time.hpp @@ -62,6 +62,13 @@ class StkTime /** Converts the time in this object to a human readable string. */ static std::string toString(const TimeType &tt); // ------------------------------------------------------------------------ + /** Converts the date represented by year, month, day + * to a human readable string. */ + static std::string toString(int year, int month, int day); + // ------------------------------------------------------------------------ + /** Obtains the translated format of the time string. */ + static std::string getDateFormat(); + // ------------------------------------------------------------------------ /** Returns the number of seconds since 1.1.1970. This function is used * to compare access times of files, e.g. news, addons data etc. */ From 9030521c8cae3970cff369e2aaac5df075238905 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 24 Feb 2025 16:52:00 +0800 Subject: [PATCH 557/830] Fix PCSS Bugs --- data/shaders/sunlightshadowpcss.frag | 88 +++++++++++++++++++--------- 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/data/shaders/sunlightshadowpcss.frag b/data/shaders/sunlightshadowpcss.frag index ef104008f0f..82ebc9c3c9d 100644 --- a/data/shaders/sunlightshadowpcss.frag +++ b/data/shaders/sunlightshadowpcss.frag @@ -59,6 +59,13 @@ vec2 vogel_disk_16[16] = vec2[]( vec2(-0.1133270115046468, -0.9490025827627441) ); +vec2 vogel_disk_4[4] = vec2[]( + vec2(0.21848650099008202, -0.09211370200809937), + vec2(-0.5866112654782878, 0.32153793477769893), + vec2(-0.06595078555407359, -0.879656059066481), + vec2(0.43407555004227927, 0.6502318262968816) +); + // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_standard_multisample_quality_levels?redirectedfrom=MSDN vec2 sample_point_pos[8] = vec2[]( vec2( 0.125, -0.375), @@ -71,6 +78,17 @@ vec2 sample_point_pos[8] = vec2[]( vec2( 0.875, -0.875) ); +float sample_point_coeff[8] = float[]( + 0.157112, + 0.157112, + 0.138651, + 0.130251, + 0.114946, + 0.114946, + 0.107982, + 0.079001 +); + float interleavedGradientNoise(vec2 w) { vec3 m = vec3(0.06711056, 0.00583715, 52.9829189); @@ -98,68 +116,80 @@ mat2 getRandomRotationMatrix(vec2 fragCoord) return R; } -void blockerSearchAndFilter(out float occludedCount, out float z_occSum, - vec2 uv, float z_rec, uint layer, vec2 filterRadii, vec2 dz_duv) +void blockerSearchAndFilter(out float occludedFactor, out float z_occSum, + vec2 uv, float z_rec, float layer, vec2 filterRadii, vec2 dz_duv, float bias) { - // Make sure no light leaking - float z_occ = texture(shadowtexdepth, vec3(uv, float(layer))).r; - float dz = z_rec - z_occ; - float occluded = 0.01 * step(0.5 / shadow_res, dz); - occludedCount = occluded; - z_occSum = z_occ * occluded; + occludedFactor = 0.; + z_occSum = 0.; for (uint i = 0u; i < 8u; i++) { vec2 duv = sample_point_pos[i] * filterRadii; vec2 tc = clamp(uv + duv, vec2(0.), vec2(1.)); // receiver plane depth bias - float z_bias = dot(dz_duv, duv); + float z_bias = -dot(dz_duv, duv) + bias; - float z_occ = texture(shadowtexdepth, vec3(tc, float(layer))).r; + float z_occ = texture(shadowtexdepth, vec3(tc, layer)).r; float dz = z_rec - z_occ; // dz>0 when blocker is between receiver and light - float occluded = step(z_bias, dz); - occludedCount += occluded; + float occluded = step(z_bias, dz) * sample_point_coeff[i]; + occludedFactor += occluded; z_occSum += z_occ * occluded; } } -float filterPCSS(vec2 uv, float z_rec, uint layer, +float filterPCF(vec2 uv, float z_rec, float layer, + vec2 filterRadii, mat2 R, vec2 dz_duv) +{ + float occludedCount = 0.0; // must be to workaround a spirv-tools issue + for (uint i = 0u; i < 4u; i++) + { + vec2 duv = R * (vogel_disk_4[i] * filterRadii); + vec2 tc = uv + duv; + + // receiver plane depth bias + float z_bias = dot(dz_duv, duv); + occludedCount += texture(shadowtex, vec4(tc, layer, z_rec + z_bias)); + } + return occludedCount * (1.0 / 4.0); +} + +float filterPCSS(vec2 uv, float z_rec, float layer, vec2 filterRadii, mat2 R, vec2 dz_duv) { float occludedCount = 0.0; // must be to workaround a spirv-tools issue for (uint i = 0u; i < 16u; i++) { vec2 duv = R * (vogel_disk_16[i] * filterRadii); - vec2 tc = clamp(uv + duv, vec2(0.), vec2(1.)); + vec2 tc = uv + duv; // receiver plane depth bias float z_bias = dot(dz_duv, duv); - occludedCount += texture(shadowtex, vec4(tc, float(layer), z_rec + z_bias)); + occludedCount += texture(shadowtex, vec4(tc, layer, z_rec + z_bias)); } return occludedCount * (1.0 / 16.0); } -float getShadowFactor(vec3 position, vec2 penumbra, vec2 dz_duv, uint layer) +float getShadowFactor(vec3 position, vec2 penumbra, vec2 dz_duv, float layer) { // rotate the poisson disk randomly mat2 R = getRandomRotationMatrix(gl_FragCoord.xy); + float min_radius = 0.5 / shadow_res; - float occludedCount = 0.0; + float occludedFactor = 0.0; float z_occSum = 0.0; - blockerSearchAndFilter(occludedCount, z_occSum, position.xy, position.z, layer, penumbra * position.z, dz_duv); + blockerSearchAndFilter(occludedFactor, z_occSum, + position.xy, position.z, layer, penumbra, dz_duv, min_radius / max(penumbra.x, penumbra.y)); // early exit if there is no occluders at all, also avoids a divide-by-zero below. - if (z_occSum == 0.0) { - return 1.0; + if (occludedFactor == 0.0) { + return filterPCF(position.xy, position.z, layer, vec2(min_radius), R, dz_duv); } - float penumbraRatio = position.z - z_occSum / occludedCount; - vec2 radius = max(penumbra * penumbraRatio, vec2(0.5 / shadow_res)); - - float percentageOccluded = filterPCSS(position.xy, position.z, layer, radius, R, dz_duv); + float penumbraRatio = position.z - z_occSum / occludedFactor; + vec2 radius = max(penumbra * penumbraRatio, vec2(min_radius)); - return percentageOccluded; + return filterPCSS(position.xy, position.z, layer, radius, R, dz_duv); } float blend_start(float x) { @@ -204,11 +234,11 @@ void main() { float factor; if (xpos.z < split0) { - float factor2 = getShadowFactor(position1, penumbra0, dz_duv1, 0); + float factor2 = getShadowFactor(position1, penumbra0, dz_duv1, 0.); factor = factor2; } if (blend_start(split0) < xpos.z && xpos.z < split1) { - float factor2 = getShadowFactor(position2, penumbra1, dz_duv2, 1); + float factor2 = getShadowFactor(position2, penumbra1, dz_duv2, 1.); if (xpos.z < split0) { factor = mix(factor, factor2, (xpos.z - blend_start(split0)) / split0 / overlap_proportion); } else { @@ -216,7 +246,7 @@ void main() { } } if (blend_start(split1) < xpos.z && xpos.z < split2) { - float factor2 = getShadowFactor(position3, penumbra2, dz_duv3, 2); + float factor2 = getShadowFactor(position3, penumbra2, dz_duv3, 2.); if (xpos.z < split1) { factor = mix(factor, factor2, (xpos.z - blend_start(split1)) / split1 / overlap_proportion); } else { @@ -224,7 +254,7 @@ void main() { } } if (blend_start(split2) < xpos.z && xpos.z < splitmax) { - float factor2 = getShadowFactor(position4, penumbra3, dz_duv4, 3); + float factor2 = getShadowFactor(position4, penumbra3, dz_duv4, 3.); if (xpos.z < split2) { factor = mix(factor, factor2, (xpos.z - blend_start(split2)) / split2 / overlap_proportion); } else { From 950b932dad261446fed763ebd2edc5480ee14dbe Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Wed, 26 Feb 2025 20:38:08 +0800 Subject: [PATCH 558/830] Fix #5212 --- data/shaders/sunlightshadowpcss.frag | 4 ++-- src/states_screens/edit_gp_screen.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data/shaders/sunlightshadowpcss.frag b/data/shaders/sunlightshadowpcss.frag index 82ebc9c3c9d..5b288f5ff13 100644 --- a/data/shaders/sunlightshadowpcss.frag +++ b/data/shaders/sunlightshadowpcss.frag @@ -144,7 +144,7 @@ float filterPCF(vec2 uv, float z_rec, float layer, for (uint i = 0u; i < 4u; i++) { vec2 duv = R * (vogel_disk_4[i] * filterRadii); - vec2 tc = uv + duv; + vec2 tc = clamp(uv + duv, vec2(0.), vec2(1.)); // receiver plane depth bias float z_bias = dot(dz_duv, duv); @@ -160,7 +160,7 @@ float filterPCSS(vec2 uv, float z_rec, float layer, for (uint i = 0u; i < 16u; i++) { vec2 duv = R * (vogel_disk_16[i] * filterRadii); - vec2 tc = uv + duv; + vec2 tc = clamp(uv + duv, vec2(0.), vec2(1.)); // receiver plane depth bias float z_bias = dot(dz_duv, duv); diff --git a/src/states_screens/edit_gp_screen.cpp b/src/states_screens/edit_gp_screen.cpp index 65bf5db2171..aaffcbad333 100644 --- a/src/states_screens/edit_gp_screen.cpp +++ b/src/states_screens/edit_gp_screen.cpp @@ -174,7 +174,7 @@ void EditGPScreen::init() EditTrackScreen* edit = EditTrackScreen::getInstance(); assert(edit != NULL); - if (edit->getResult()) + if (edit->getResult() && edit->getTrack()) { bool reverse = edit->getTrack()->reverseAvailable() ? edit->getReverse() : false; From a0e309935758ca6899d1760f61ec0a278203d9d0 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Wed, 26 Feb 2025 21:14:32 +0800 Subject: [PATCH 559/830] Fix #5208 --- src/karts/kart_properties.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index 5852abf89cc..15eda0c2926 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -145,6 +145,11 @@ KartProperties::~KartProperties() void KartProperties::copyForPlayer(const KartProperties *source, HandicapLevel h) { + if (!source) + { + return; + } + *this = *source; // After the memcpy any pointers will be shared. From 6623872d8725e5a6a4372e665123455da9da14e5 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 27 Feb 2025 12:51:37 +0400 Subject: [PATCH 560/830] Add Georgian font (#5313) --- data/stk_config.xml | 2 +- data/ttf/NotoSansGeorgian-Regular.ttf | Bin 0 -> 62952 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 data/ttf/NotoSansGeorgian-Regular.ttf diff --git a/data/stk_config.xml b/data/stk_config.xml index a677bd65305..951ea047fe1 100644 --- a/data/stk_config.xml +++ b/data/stk_config.xml @@ -535,7 +535,7 @@ which leads to crash with STK), but the fonts are to blame, what's the point of not using industry standard nowadays... --> - diff --git a/data/ttf/NotoSansGeorgian-Regular.ttf b/data/ttf/NotoSansGeorgian-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ed0bb19774383cdf1dd6129c971e8ced3aa72e4e GIT binary patch literal 62952 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 i2)~jB!ip;T7Tr%Wep+~(R(2e^n@wlFCp Date: Fri, 28 Feb 2025 10:35:20 +0100 Subject: [PATCH 561/830] Change Anvil to Anchor and Bowling to Bowling ball in artist debug menu (#5327) * Change Anvil to Anchor in artist debug menu * Change "Bowling" to "Bowling ball" --- src/utils/debug.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index bc1aae7af98..de40959984b 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -1050,8 +1050,8 @@ bool handleContextMenuAction(s32 cmd_id) case DEBUG_HELP: new TutorialMessageDialog(L"Debug keyboard shortcuts (can conflict with user-defined shortcuts):\n" "* <~> - Show this help dialog | + - Adjust lights | + - Adjust visuals\n" - "* - Anvil powerup | + - Normal view | + - Bomb attachment\n" - "* - Basketball powerup | + - First person view | + - Anvil attachment\n" + "* - Anchor powerup | + - Normal view | + - Bomb attachment\n" + "* - Basketball powerup | + - First person view | + - Anchor attachment\n" "* - Bowling ball powerup | + - Top view | + - Parachute attachment\n" "* - Bubblegum powerup | + - Behind wheel view | + - Flatten kart\n" "* - Cake powerup | + - Behind kart view | + - Send plunger to kart front\n" @@ -1248,9 +1248,9 @@ bool onEvent(const SEvent &event) mnu->addItem(L"Items >",-1,true,true); sub = mnu->getSubMenu(3); - sub->addItem(L"Anvil (F1)", DEBUG_POWERUP_ANVIL ); + sub->addItem(L"Anchor (F1)", DEBUG_POWERUP_ANVIL ); sub->addItem(L"Basketball (F2)", DEBUG_POWERUP_RUBBERBALL ); - sub->addItem(L"Bowling (F3)", DEBUG_POWERUP_BOWLING ); + sub->addItem(L"Bowling ball (F3)", DEBUG_POWERUP_BOWLING ); sub->addItem(L"Bubblegum (F4)", DEBUG_POWERUP_BUBBLEGUM ); sub->addItem(L"Cake (F5)", DEBUG_POWERUP_CAKE ); sub->addItem(L"Parachute (F6)", DEBUG_POWERUP_PARACHUTE ); @@ -1263,7 +1263,7 @@ bool onEvent(const SEvent &event) mnu->addItem(L"Attachments >",-1,true, true); sub = mnu->getSubMenu(4); sub->addItem(L"Bomb (Shift + F1)", DEBUG_ATTACHMENT_BOMB); - sub->addItem(L"Anvil (Shift + F2)", DEBUG_ATTACHMENT_ANVIL); + sub->addItem(L"Anchor (Shift + F2)", DEBUG_ATTACHMENT_ANVIL); sub->addItem(L"Parachute (Shift + F3)", DEBUG_ATTACHMENT_PARACHUTE); sub->addItem(L"Flatten (Shift + F4)", DEBUG_ATTACHMENT_SQUASH); sub->addItem(L"Plunger (Shift + F5)", DEBUG_ATTACHMENT_PLUNGER); From c616a1d0263ee1932fddb090f9a02e292ab99220 Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Sat, 1 Mar 2025 12:48:33 +0000 Subject: [PATCH 562/830] src/network/protocols/ranking.hpp: add missing `` include (#5346) Without the chnage the build fails on upcoming `gcc-15` as: /build/source/src/network/protocols/ranking.hpp:31:5: error: 'uint32_t' does not name a type 31 | uint32_t online_id; | ^~~~~~~~ --- src/network/protocols/ranking.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/protocols/ranking.hpp b/src/network/protocols/ranking.hpp index 0812045823e..02de90e9517 100644 --- a/src/network/protocols/ranking.hpp +++ b/src/network/protocols/ranking.hpp @@ -22,6 +22,7 @@ #include #include #include +#include class XMLNode; class NetworkPlayerProfile; From 2ff69dbc431f58307387a17dd6634d1a58842c44 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 2 Mar 2025 21:27:46 +0800 Subject: [PATCH 563/830] Add option to disable PCSS --- data/gui/dialogs/custom_video_settings.stkgui | 2 +- src/states_screens/dialogs/custom_video_settings.cpp | 8 ++++++-- src/states_screens/options/options_screen_video.cpp | 4 +++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/data/gui/dialogs/custom_video_settings.stkgui b/data/gui/dialogs/custom_video_settings.stkgui index 48a5e4cc2f7..840890f479a 100644 --- a/data/gui/dialogs/custom_video_settings.stkgui +++ b/data/gui/dialogs/custom_video_settings.stkgui @@ -29,7 +29,7 @@

K8?LlQn&@4 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

diff --git a/src/states_screens/dialogs/custom_video_settings.cpp b/src/states_screens/dialogs/custom_video_settings.cpp index 3197e122481..0ae695fe49c 100644 --- a/src/states_screens/dialogs/custom_video_settings.cpp +++ b/src/states_screens/dialogs/custom_video_settings.cpp @@ -103,7 +103,9 @@ void CustomVideoSettingsDialog::beforeAddingWidgets() shadows->addLabel(_("Low")); // 1 shadows->addLabel(_("Medium")); // 2 shadows->addLabel(_("High")); // 3 - shadows->setValue(UserConfigParams::m_shadows_resolution == 2048 ? 3 : + shadows->addLabel(_("Very High")); // 4 + shadows->setValue(UserConfigParams::m_shadows_resolution == 2048 ? + (UserConfigParams::m_pcss_threshold == 2048 ? 4 : 3) : UserConfigParams::m_shadows_resolution == 1024 ? 2 : UserConfigParams::m_shadows_resolution == 512 ? 1 : 0); @@ -161,7 +163,9 @@ GUIEngine::EventPropagation CustomVideoSettingsDialog::processEvent(const std::s UserConfigParams::m_shadows_resolution = getWidget("shadows")->getValue() == 1 ? 512 : getWidget("shadows")->getValue() == 2 ? 1024 : - getWidget("shadows")->getValue() == 3 ? 2048 : 0; + getWidget("shadows")->getValue() >= 3 ? 2048 : 0; + UserConfigParams::m_pcss_threshold = + getWidget("shadows")->getValue() == 3 ? 4096 : 2048; } else { diff --git a/src/states_screens/options/options_screen_video.cpp b/src/states_screens/options/options_screen_video.cpp index a970fb72a4e..75db196ba72 100644 --- a/src/states_screens/options/options_screen_video.cpp +++ b/src/states_screens/options/options_screen_video.cpp @@ -358,7 +358,8 @@ void OptionsScreenVideo::updateGfxSlider() m_presets[l].degraded_ibl == UserConfigParams::m_degraded_IBL && m_presets[l].geometry_detail == (UserConfigParams::m_geometry_level == 0 ? 2 : UserConfigParams::m_geometry_level == 2 ? 0 : - UserConfigParams::m_geometry_level)) + UserConfigParams::m_geometry_level) && + UserConfigParams::m_pcss_threshold == 2048) { gfx->setValue(l + 1); found = true; @@ -605,6 +606,7 @@ void OptionsScreenVideo::eventCallback(Widget* widget, const std::string& name, UserConfigParams::m_geometry_level = (m_presets[level].geometry_detail == 0 ? 2 : m_presets[level].geometry_detail == 2 ? 0 : m_presets[level].geometry_detail); + UserConfigParams::m_pcss_threshold = 2048; updateGfxSlider(); } From c885fb76b963d43cfc233426246e4d552cbe86d2 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 3 Mar 2025 18:13:07 +0800 Subject: [PATCH 564/830] Fix #5279 --- .github/ISSUE_TEMPLATE.md | 53 --------------- .github/ISSUE_TEMPLATE/defect.yml | 90 ++++++++++++++++++++++++++ .github/ISSUE_TEMPLATE/enhancement.yml | 13 ++++ 3 files changed, 103 insertions(+), 53 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/defect.yml create mode 100644 .github/ISSUE_TEMPLATE/enhancement.yml diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 560b6abef1f..00000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,53 +0,0 @@ - -## Description - - - - -## Steps to reproduce - - - - -## Configuration - - -STK release version: - - -STK Source (PPA, distribution package, official binary, etc.): - -System: - -Graphics card: - -CPU: - -Gamepads/keyboards models if related to the issue: - -## Additional information - -stdout.log: -``` - -``` - - -input.xml: -```xml - -``` - - -Error message: -``` - -``` diff --git a/.github/ISSUE_TEMPLATE/defect.yml b/.github/ISSUE_TEMPLATE/defect.yml new file mode 100644 index 00000000000..17702acb824 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/defect.yml @@ -0,0 +1,90 @@ +name: Defect +description: Report bugs, crashes, or unintended behavior +labels: ['T: defect'] + +body: + + - type: textarea + id: description + attributes: + label: Description + description: Provide a clear and concise explanation of the problem encountered. + validations: + required: true + + - type: textarea + id: to_reproduce + attributes: + label: Steps to reproduce + description: Outline the exact sequence of actions required to reproduce the issue. + placeholder: | + 1. Launch SuperTuxKart + 2. Navigate to [specific menu/location] + 3. Perform [specific action] + 4. Observe unexpected behavior + validations: + required: true + + - type: textarea + id: config + attributes: + label: Configuration + description: | + Include the following details to help us diagnose the issue: + - SuperTuxKart version (visible in the "About" menu) + - Installation source (official website, package manager, etc.) + - Operating system and version + - CPU/GPU specifications + - Input device details (if relevant) + values: | + SuperTuxKart version: + Installation source: + OS: + CPU: + GPU: + Input device: + validations: + required: true + + - type: textarea + id: error_msg + attributes: + label: Error message + description: | + If an error message was shown, please paste the complete error message, or a screenshot of it. + values: | + ``` + [Paste error message here] + ``` + + - type: textarea + id: stdout + attributes: + label: Log File (stdout.log) + description: | + Attach the log file (stdout.log) from your latest session where the issue occurred. + File location + - Windows: %appdata%\supertuxkart\config-0.10\stdout.log + - macOS: ~/Library/Application Support/supertuxkart/config-0.10/stdout.log + - Linux and other Unix-based systems: + $XDG_CONFIG_HOME/supertuxkart/config-0.10/stdout.log + or + ~/.config/supertuxkart/config-0.10/stdout.log + values: | + ``` + [Paste contents of stdout.log here] + ``` + + - type: textarea + id: input + attributes: + label: Input Configuration (input.xml) + description: | + If your issue is related to the input config (gamepads, keyboards), + please provide your file input.xml located in the same directory as stdout.log. + values: | + ``` + [Paste contents of input.xml here] + ``` + + \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/enhancement.yml b/.github/ISSUE_TEMPLATE/enhancement.yml new file mode 100644 index 00000000000..8f1f8fd6699 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement.yml @@ -0,0 +1,13 @@ +name: Enhancement +description: Request for new features and other improvements +labels: ['T: enhancement'] + +body: + - type: textarea + id: description + attributes: + label: Description + description: | + If applicable, add screenshots or mockups to help explain your request. + validations: + required: true \ No newline at end of file From b709eb9a997e687411a6990862045eae322e1402 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 3 Mar 2025 18:30:56 +0800 Subject: [PATCH 565/830] Fix broken defect --- .github/ISSUE_TEMPLATE/defect.yml | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/defect.yml b/.github/ISSUE_TEMPLATE/defect.yml index 17702acb824..336b14010ba 100644 --- a/.github/ISSUE_TEMPLATE/defect.yml +++ b/.github/ISSUE_TEMPLATE/defect.yml @@ -35,16 +35,16 @@ body: - Installation source (official website, package manager, etc.) - Operating system and version - CPU/GPU specifications - - Input device details (if relevant) - values: | - SuperTuxKart version: - Installation source: - OS: - CPU: - GPU: - Input device: - validations: - required: true + - Controller/keyboard type (if relevant) + placeholder: | + SuperTuxKart version: 1.4 + Installation source: Official repository + OS: Ubuntu 24.04 + CPU: i5-10400 + GPU: GTX 1660 + Input device: USB keyboard + validations: + required: true - type: textarea id: error_msg @@ -52,7 +52,7 @@ body: label: Error message description: | If an error message was shown, please paste the complete error message, or a screenshot of it. - values: | + value: | ``` [Paste error message here] ``` @@ -68,9 +68,8 @@ body: - macOS: ~/Library/Application Support/supertuxkart/config-0.10/stdout.log - Linux and other Unix-based systems: $XDG_CONFIG_HOME/supertuxkart/config-0.10/stdout.log - or - ~/.config/supertuxkart/config-0.10/stdout.log - values: | + or ~/.config/supertuxkart/config-0.10/stdout.log + value: | ``` [Paste contents of stdout.log here] ``` @@ -82,7 +81,7 @@ body: description: | If your issue is related to the input config (gamepads, keyboards), please provide your file input.xml located in the same directory as stdout.log. - values: | + value: | ``` [Paste contents of input.xml here] ``` From 3e50084e232027300694a118b817498a7fa3ddee Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 3 Mar 2025 20:33:21 +0800 Subject: [PATCH 566/830] Fix build errors --- .github/ISSUE_TEMPLATE/defect.yml | 2 +- .github/workflows/apple.yml | 2 +- .github/workflows/windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/defect.yml b/.github/ISSUE_TEMPLATE/defect.yml index 336b14010ba..a8b362a2f77 100644 --- a/.github/ISSUE_TEMPLATE/defect.yml +++ b/.github/ISSUE_TEMPLATE/defect.yml @@ -41,7 +41,7 @@ body: Installation source: Official repository OS: Ubuntu 24.04 CPU: i5-10400 - GPU: GTX 1660 + GPU: RX 580 Input device: USB keyboard validations: required: true diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml index 5e3fd584c9f..7ba161194b7 100644 --- a/.github/workflows/apple.yml +++ b/.github/workflows/apple.yml @@ -49,7 +49,7 @@ jobs: echo "cache_$number=apple-${{ github.ref }}-${{ matrix.arch }}-${{ matrix.platform }}-$id" >> $GITHUB_ENV done - name: Handle build cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | build diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d53b33edc2d..1867ca11aaf 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -59,7 +59,7 @@ jobs: echo "cache_$number=windows-${{ github.ref }}-${{ matrix.arch }}-${{ matrix.os }}-$id" >> $GITHUB_ENV done - name: Handle build cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: | build From 06cd143b162e8a66ebe361081f20b91f5e56d75d Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 3 Mar 2025 21:12:24 +0800 Subject: [PATCH 567/830] Restrict max karts in arenas --- .github/ISSUE_TEMPLATE/defect.yml | 2 +- .github/workflows/switch.yml | 2 +- src/states_screens/track_info_screen.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/defect.yml b/.github/ISSUE_TEMPLATE/defect.yml index a8b362a2f77..3a712ef1f97 100644 --- a/.github/ISSUE_TEMPLATE/defect.yml +++ b/.github/ISSUE_TEMPLATE/defect.yml @@ -63,7 +63,7 @@ body: label: Log File (stdout.log) description: | Attach the log file (stdout.log) from your latest session where the issue occurred. - File location + File locations: - Windows: %appdata%\supertuxkart\config-0.10\stdout.log - macOS: ~/Library/Application Support/supertuxkart/config-0.10/stdout.log - Linux and other Unix-based systems: diff --git a/.github/workflows/switch.yml b/.github/workflows/switch.yml index 311d6c86b97..0d79d845d08 100644 --- a/.github/workflows/switch.yml +++ b/.github/workflows/switch.yml @@ -72,7 +72,7 @@ jobs: echo "cache_$number=switch-${{ github.ref }}-$id" >> $GITHUB_ENV done - name: Handle build cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: # This is unnecessarily verbose and might break, but again ! seems broken # See: https://github.com/Mstrodl/stk-code/runs/2333673736?check_suite_focus=true#step:16:34 diff --git a/src/states_screens/track_info_screen.cpp b/src/states_screens/track_info_screen.cpp index aca3e167c44..f5d699def2d 100644 --- a/src/states_screens/track_info_screen.cpp +++ b/src/states_screens/track_info_screen.cpp @@ -139,7 +139,7 @@ void TrackInfoScreen::init() { m_record_this_race = false; - const int max_arena_players = m_track->getMaxArenaPlayers(); + const int max_arena_players = std::min(m_track->getMaxArenaPlayers(), unsigned(stk_config->m_max_karts)); const int local_players = RaceManager::get()->getNumLocalPlayers(); const bool has_laps = RaceManager::get()->modeHasLaps(); const bool has_highscores = RaceManager::get()->modeHasHighscores(); From 9ff14038cebd4266284831f39900b95761f32472 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 3 Mar 2025 20:44:37 +0400 Subject: [PATCH 568/830] CI and issue template changes for this repo [skip ci] --- .github/ISSUE_TEMPLATE/defect.yml | 2 +- .github/ISSUE_TEMPLATE/enhancement.yml | 4 ++-- .github/workflows/switch.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/defect.yml b/.github/ISSUE_TEMPLATE/defect.yml index a8b362a2f77..a01c7d7444c 100644 --- a/.github/ISSUE_TEMPLATE/defect.yml +++ b/.github/ISSUE_TEMPLATE/defect.yml @@ -1,6 +1,6 @@ name: Defect description: Report bugs, crashes, or unintended behavior -labels: ['T: defect'] +labels: ['T: bug'] body: diff --git a/.github/ISSUE_TEMPLATE/enhancement.yml b/.github/ISSUE_TEMPLATE/enhancement.yml index 8f1f8fd6699..c54790cf7f7 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yml +++ b/.github/ISSUE_TEMPLATE/enhancement.yml @@ -1,6 +1,6 @@ name: Enhancement -description: Request for new features and other improvements -labels: ['T: enhancement'] +description: Request for new features +labels: ['T: Suggestion'] body: - type: textarea diff --git a/.github/workflows/switch.yml b/.github/workflows/switch.yml index 311d6c86b97..0d79d845d08 100644 --- a/.github/workflows/switch.yml +++ b/.github/workflows/switch.yml @@ -72,7 +72,7 @@ jobs: echo "cache_$number=switch-${{ github.ref }}-$id" >> $GITHUB_ENV done - name: Handle build cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: # This is unnecessarily verbose and might break, but again ! seems broken # See: https://github.com/Mstrodl/stk-code/runs/2333673736?check_suite_focus=true#step:16:34 From 1960072ca1b88de05808d80241e1c0503209a299 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 15 Feb 2025 20:40:59 +0400 Subject: [PATCH 569/830] Less includes, remove true/*reliable*/ and false/*encrypted*/ --- src/modes/capture_the_flag.cpp | 2 +- src/modes/free_for_all.cpp | 4 +- src/modes/linear_world.cpp | 2 +- src/modes/soccer_world.cpp | 10 +- src/network/crypto_mbedtls.cpp | 2 +- src/network/crypto_mbedtls.hpp | 2 +- src/network/crypto_openssl.cpp | 2 +- src/network/crypto_openssl.hpp | 3 +- src/network/network.cpp | 2 +- src/network/network.hpp | 4 +- src/network/protocol.cpp | 6 +- src/network/protocol.hpp | 8 +- src/network/protocols/client_lobby.cpp | 14 +-- .../protocols/game_events_protocol.cpp | 6 +- src/network/protocols/game_protocol.cpp | 8 +- src/network/protocols/server_lobby.cpp | 110 +++++++++--------- src/network/stk_host.cpp | 12 +- src/network/stk_host.hpp | 11 +- src/network/stk_peer.cpp | 2 +- src/network/stk_peer.hpp | 5 +- .../dialogs/network_player_dialog.cpp | 8 +- .../dialogs/race_paused_dialog.cpp | 2 +- .../dialogs/server_configuration_dialog.cpp | 2 +- .../online/network_kart_selection.cpp | 4 +- .../online/networking_lobby.cpp | 4 +- src/states_screens/online/tracks_screen.cpp | 2 +- src/utils/constants.hpp | 14 +++ 27 files changed, 134 insertions(+), 117 deletions(-) diff --git a/src/modes/capture_the_flag.cpp b/src/modes/capture_the_flag.cpp index f40aa915a56..c26d7618c42 100644 --- a/src/modes/capture_the_flag.cpp +++ b/src/modes/capture_the_flag.cpp @@ -348,7 +348,7 @@ void CaptureTheFlag::checkScoring(FlagColor color) .addUInt16((int16_t)new_kart_score) .addUInt8((uint8_t)new_red_score) .addUInt8((uint8_t)new_blue_score); - STKHost::get()->sendPacketToAllPeers(&p, true); + STKHost::get()->sendPacketToAllPeers(&p, PRM_RELIABLE); } ctfScored(active_holder, (red_active) ? false : true /*red_team_scored*/, new_kart_score, new_red_score, new_blue_score); diff --git a/src/modes/free_for_all.cpp b/src/modes/free_for_all.cpp index 9ba7bd872f1..d28997d7e66 100644 --- a/src/modes/free_for_all.cpp +++ b/src/modes/free_for_all.cpp @@ -130,7 +130,7 @@ void FreeForAll::handleScoreInServer(int kart_id, int hitter) p.addUInt8((uint8_t)kart_id).addUInt16((int16_t)new_score); else p.addUInt8((uint8_t)hitter).addUInt16((int16_t)new_score); - STKHost::get()->sendPacketToAllPeers(&p, true); + STKHost::get()->sendPacketToAllPeers(&p, PRM_RELIABLE); } } // handleScoreInServer @@ -345,6 +345,6 @@ void FreeForAll::notifyAboutScoreIfNonzero(int id) p.setSynchronous(true); p.addUInt8(GameEventsProtocol::GE_BATTLE_KART_SCORE); p.addUInt8((uint8_t)id).addUInt16((int16_t)m_scores[id]); - STKHost::get()->sendPacketToAllPeers(&p, true); + STKHost::get()->sendPacketToAllPeers(&p, PRM_RELIABLE); } } // notifyAboutScoreIfNonzero diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index 96225bf8e6b..40c46e50efd 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -1326,7 +1326,7 @@ void LinearWorld::updateCheckLinesServer(int check_id, int kart_id) for (unsigned i = 0; i < cc; i++) cm->getCheckStructure(i)->saveIsActive(kart_id, &cl); - STKHost::get()->sendPacketToAllPeers(&cl, true); + STKHost::get()->sendPacketToAllPeers(&cl, PRM_RELIABLE); } // updateCheckLinesServer // ---------------------------------------------------------------------------- diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp index f5934ad6a61..4bbf30903d8 100644 --- a/src/modes/soccer_world.cpp +++ b/src/modes/soccer_world.cpp @@ -699,11 +699,11 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) if (peer->getClientCapabilities().find("soccer_fixes") != peer->getClientCapabilities().end()) { - peer->sendPacket(&p_1_1, true/*reliable*/); + peer->sendPacket(&p_1_1, PRM_RELIABLE); } else { - peer->sendPacket(&p, true/*reliable*/); + peer->sendPacket(&p, PRM_RELIABLE); } } } @@ -965,7 +965,7 @@ void SoccerWorld::updateBallPosition(int ticks) p.setSynchronous(true); p.addUInt8(GameEventsProtocol::GE_RESET_BALL) .addTime(m_reset_ball_ticks); - STKHost::get()->sendPacketToAllPeers(&p, true); + STKHost::get()->sendPacketToAllPeers(&p, PRM_RELIABLE); } else if (!NetworkConfig::get()->isNetworking()) { @@ -1393,7 +1393,7 @@ void SoccerWorld::tellCountToEveryoneInGame() const chat->encodeString16(StringUtils::utf8ToWide(real_count)); for (auto& peer : peers) if (peer->isValidated() && !peer->isWaitingForGame()) - peer->sendPacket(chat, true/*reliable*/); + peer->sendPacket(chat, PRM_RELIABLE); delete chat; } // tellCountToEveryoneInGame @@ -1411,7 +1411,7 @@ void SoccerWorld::tellCount(std::shared_ptr peer) const std::string real_count = std::to_string(real_red) + " : " + std::to_string(real_blue); chat->encodeString16(StringUtils::utf8ToWide(real_count)); - peer->sendPacket(chat, true/*reliable*/); + peer->sendPacket(chat, PRM_RELIABLE); delete chat; } // tellCount // ---------------------------------------------------------------------------- diff --git a/src/network/crypto_mbedtls.cpp b/src/network/crypto_mbedtls.cpp index 42184d22c4b..cc1a0ca8ef9 100644 --- a/src/network/crypto_mbedtls.cpp +++ b/src/network/crypto_mbedtls.cpp @@ -121,7 +121,7 @@ bool Crypto::decryptConnectionRequest(BareNetworkString& ns) } // decryptConnectionRequest // ---------------------------------------------------------------------------- -ENetPacket* Crypto::encryptSend(BareNetworkString& ns, bool reliable) +ENetPacket* Crypto::encryptSend(BareNetworkString& ns, PacketReliabilityMode reliable) { // 4 bytes counter and 4 bytes tag ENetPacket* p = enet_packet_create(NULL, ns.m_buffer.size() + 8, diff --git a/src/network/crypto_mbedtls.hpp b/src/network/crypto_mbedtls.hpp index 381c6487770..3be2136dad7 100644 --- a/src/network/crypto_mbedtls.hpp +++ b/src/network/crypto_mbedtls.hpp @@ -134,7 +134,7 @@ class Crypto // ------------------------------------------------------------------------ bool decryptConnectionRequest(BareNetworkString& ns); // ------------------------------------------------------------------------ - ENetPacket* encryptSend(BareNetworkString& ns, bool reliable); + ENetPacket* encryptSend(BareNetworkString& ns, PacketReliabilityMode reliable); // ------------------------------------------------------------------------ NetworkString* decryptRecieve(ENetPacket* p); diff --git a/src/network/crypto_openssl.cpp b/src/network/crypto_openssl.cpp index a15f7180832..682aeeef073 100644 --- a/src/network/crypto_openssl.cpp +++ b/src/network/crypto_openssl.cpp @@ -178,7 +178,7 @@ bool Crypto::decryptConnectionRequest(BareNetworkString& ns) } // decryptConnectionRequest // ---------------------------------------------------------------------------- -ENetPacket* Crypto::encryptSend(BareNetworkString& ns, bool reliable) +ENetPacket* Crypto::encryptSend(BareNetworkString& ns, PacketReliabilityMode reliable) { // 4 bytes counter and 4 bytes tag ENetPacket* p = enet_packet_create(NULL, ns.m_buffer.size() + 8, diff --git a/src/network/crypto_openssl.hpp b/src/network/crypto_openssl.hpp index 5cb75038ed2..864e239ffa1 100644 --- a/src/network/crypto_openssl.hpp +++ b/src/network/crypto_openssl.hpp @@ -22,6 +22,7 @@ #define HEADER_CRYPTO_OPENSSL_HPP #include "utils/log.hpp" +#include "utils/constants.hpp" #include @@ -156,7 +157,7 @@ class Crypto // ------------------------------------------------------------------------ bool decryptConnectionRequest(BareNetworkString& ns); // ------------------------------------------------------------------------ - ENetPacket* encryptSend(BareNetworkString& ns, bool reliable); + ENetPacket* encryptSend(BareNetworkString& ns, PacketReliabilityMode reliable); // ------------------------------------------------------------------------ NetworkString* decryptRecieve(ENetPacket* p); diff --git a/src/network/network.cpp b/src/network/network.cpp index 32b99a145b0..12544eb54a5 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -211,7 +211,7 @@ int Network::receiveRawPacket(char *buffer, int buf_len, /** \brief Broadcasts a packet to all peers. * \param data : Data to send. */ -void Network::broadcastPacket(NetworkString *data, bool reliable) +void Network::broadcastPacket(NetworkString *data, PacketReliabilityMode reliable) { ENetPacket* packet = enet_packet_create(data->getData(), data->size() + 1, (reliable ? ENET_PACKET_FLAG_RELIABLE : diff --git a/src/network/network.hpp b/src/network/network.hpp index 3802f389159..fb26db432ae 100644 --- a/src/network/network.hpp +++ b/src/network/network.hpp @@ -23,7 +23,7 @@ #define HEADER_NETWORK_HPP #include "utils/synchronised.hpp" -#include "utils/types.hpp" +#include "utils/constants.hpp" // enet.h includes win32.h, which without lean_and_mean includes // winspool.h, which defines MAX_PRIORITY as a macro, which then @@ -72,7 +72,7 @@ class Network int receiveRawPacket(char *buffer, int buf_len, SocketAddress* sender, int max_tries = -1); void broadcastPacket(NetworkString *data, - bool reliable = true); + PacketReliabilityMode reliable = PRM_RELIABLE); // ------------------------------------------------------------------------ uint16_t getPort() const { return m_port; } // ------------------------------------------------------------------------ diff --git a/src/network/protocol.cpp b/src/network/protocol.cpp index 9cd4e7afbac..c9dc91a3871 100644 --- a/src/network/protocol.cpp +++ b/src/network/protocol.cpp @@ -96,7 +96,7 @@ void Protocol::requestTerminate() * type) followed by the actual message. * \param message The actual message content. */ -void Protocol::sendMessageToPeers(NetworkString *message, bool reliable) +void Protocol::sendMessageToPeers(NetworkString *message, PacketReliabilityMode reliable) { STKHost::get()->sendPacketToAllPeers(message, reliable); } // sendMessageToPeers @@ -108,7 +108,7 @@ void Protocol::sendMessageToPeers(NetworkString *message, bool reliable) * \param message The actual message content. */ void Protocol::sendMessageToPeersInServer(NetworkString* message, - bool reliable) + PacketReliabilityMode reliable) { STKHost::get()->sendPacketToAllPeersInServer(message, reliable); } // sendMessageToPeersInServer @@ -116,7 +116,7 @@ void Protocol::sendMessageToPeersInServer(NetworkString* message, // ---------------------------------------------------------------------------- /** Sends a message from a client to the server. */ -void Protocol::sendToServer(NetworkString *message, bool reliable) +void Protocol::sendToServer(NetworkString *message, PacketReliabilityMode reliable) { STKHost::get()->sendToServer(message, reliable); } // sendMessage diff --git a/src/network/protocol.hpp b/src/network/protocol.hpp index bb4950beac8..335fd80b7af 100644 --- a/src/network/protocol.hpp +++ b/src/network/protocol.hpp @@ -24,7 +24,7 @@ #define PROTOCOL_HPP #include "utils/no_copy.hpp" -#include "utils/types.hpp" +#include "utils/constants.hpp" #include #include @@ -119,10 +119,10 @@ class Protocol : public std::enable_shared_from_this, /// functions to check incoming data easily NetworkString* getNetworkString(size_t capacity = 16) const; bool checkDataSize(Event* event, unsigned int minimum_size); - void sendMessageToPeers(NetworkString *message, bool reliable = true); + void sendMessageToPeers(NetworkString *message, PacketReliabilityMode reliable = PRM_RELIABLE); void sendMessageToPeersInServer(NetworkString *message, - bool reliable = true); - void sendToServer(NetworkString *message, bool reliable = true); + PacketReliabilityMode reliable = PRM_RELIABLE); + void sendToServer(NetworkString *message, PacketReliabilityMode reliable = PRM_RELIABLE); virtual void requestStart(); virtual void requestTerminate(); // ------------------------------------------------------------------------ diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp index b7709dd5435..930e0d0ea25 100644 --- a/src/network/protocols/client_lobby.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -178,7 +178,7 @@ void ClientLobby::doneWithResults() NetworkString* done = getNetworkString(1); done->setSynchronous(true); done->addUInt8(LE_RACE_FINISHED_ACK); - sendToServer(done, /*reliable*/true); + sendToServer(done, PRM_RELIABLE); delete done; } // doneWithResults @@ -514,7 +514,7 @@ void ClientLobby::update(int ticks) m_auto_started = true; NetworkString start(PROTOCOL_LOBBY_ROOM); start.addUInt8(LobbyProtocol::LE_REQUEST_BEGIN); - STKHost::get()->sendToServer(&start, true); + STKHost::get()->sendToServer(&start, PRM_RELIABLE); } if (m_background_download.joinable()) { @@ -1282,7 +1282,7 @@ void ClientLobby::finishedLoadingWorld() NetworkString* ns = getNetworkString(1); ns->setSynchronous(m_server_send_live_load_world); ns->addUInt8(LE_CLIENT_LOADED_WORLD); - sendToServer(ns, true); + sendToServer(ns, PRM_RELIABLE); delete ns; } // finishedLoadingWorld @@ -1381,7 +1381,7 @@ void ClientLobby::requestKartInfo(uint8_t kart_id) NetworkString* ns = getNetworkString(1); ns->setSynchronous(true); ns->addUInt8(LE_KART_INFO).addUInt8(kart_id); - sendToServer(ns, true/*reliable*/); + sendToServer(ns, PRM_RELIABLE); delete ns; } // requestKartInfo @@ -1525,7 +1525,7 @@ void ClientLobby::sendChat(irr::core::stringw text, KartTeam team) if (team != KART_TEAM_NONE) chat->addUInt8(team); - STKHost::get()->sendToServer(chat, true); + STKHost::get()->sendToServer(chat, PRM_RELIABLE); delete chat; } } // sendChat @@ -1870,7 +1870,7 @@ void ClientLobby::handleClientCommand(const std::string& cmd) NetworkString* cmd_ns = getNetworkString(1); const std::string& language = UserConfigParams::m_language; cmd_ns->addUInt8(LE_COMMAND).encodeString(language).encodeString(cmd); - sendToServer(cmd_ns, /*reliable*/true); + sendToServer(cmd_ns, PRM_RELIABLE); delete cmd_ns; } #endif @@ -1912,7 +1912,7 @@ void ClientLobby::updateAssetsToServer() NetworkString* ns = getNetworkString(1); ns->addUInt8(LE_ASSETS_UPDATE); getKartsTracksNetworkString(ns); - sendToServer(ns, /*reliable*/true); + sendToServer(ns, PRM_RELIABLE); delete ns; } // updateAssetsToServer diff --git a/src/network/protocols/game_events_protocol.cpp b/src/network/protocols/game_events_protocol.cpp index 87279d66565..7a6eccc920e 100644 --- a/src/network/protocols/game_events_protocol.cpp +++ b/src/network/protocols/game_events_protocol.cpp @@ -118,7 +118,7 @@ bool GameEventsProtocol::notifyEvent(Event* event) NetworkString *ns = getNetworkString(); ns->setSynchronous(true); ns->addUInt8(GE_STARTUP_BOOST).addUInt8(kart_id).addFloat(f); - sendMessageToPeers(ns, true); + sendMessageToPeers(ns, PRM_RELIABLE); delete ns; } else @@ -164,7 +164,7 @@ void GameEventsProtocol::kartFinishedRace(AbstractKart *kart, float time) ns->setSynchronous(true); ns->addUInt8(GE_KART_FINISHED_RACE).addUInt8(kart->getWorldKartId()) .addFloat(time); - sendMessageToPeers(ns, /*reliable*/true); + sendMessageToPeers(ns, PRM_RELIABLE); delete ns; } // kartFinishedRace @@ -198,6 +198,6 @@ void GameEventsProtocol::sendStartupBoost(uint8_t kart_id) NetworkString *ns = getNetworkString(); ns->setSynchronous(true); ns->addUInt8(GE_STARTUP_BOOST).addUInt8(kart_id); - sendToServer(ns, /*reliable*/true); + sendToServer(ns, PRM_RELIABLE); delete ns; } // sendStartupBoost diff --git a/src/network/protocols/game_protocol.cpp b/src/network/protocols/game_protocol.cpp index 2d09d10c342..f7c2e274d10 100644 --- a/src/network/protocols/game_protocol.cpp +++ b/src/network/protocols/game_protocol.cpp @@ -109,7 +109,7 @@ void GameProtocol::sendActions() } // for a in m_all_actions // FIXME: for now send reliable - sendToServer(m_data_to_send, /*reliable*/ true); + sendToServer(m_data_to_send, PRM_RELIABLE); m_all_actions.clear(); } // sendActions @@ -244,7 +244,7 @@ void GameProtocol::handleControllerAction(Event *event) // is after the server time peer->updateLastActivity(); if (!will_trigger_rewind) - STKHost::get()->sendPacketExcept(peer, &data, false); + STKHost::get()->sendPacketExcept(peer, &data, PRM_UNRELIABLE); } // if server } // handleControllerAction @@ -261,7 +261,7 @@ void GameProtocol::sendItemEventConfirmation(int ticks) ns->addUInt8(GP_ITEM_CONFIRMATION).addUInt32(ticks); // This message can be sent unreliable, it's not critical if it doesn't // get delivered, a future update will come through - sendToServer(ns, /*reliable*/false); + sendToServer(ns, PRM_UNRELIABLE); delete ns; } // sendItemEventConfirmation @@ -333,7 +333,7 @@ void GameProtocol::finalizeState(std::vector& cur_rewinder) void GameProtocol::sendState() { assert(NetworkConfig::get()->isServer()); - sendMessageToPeers(m_data_to_send, /*reliable*/false); + sendMessageToPeers(m_data_to_send, PRM_UNRELIABLE); } // sendState // ---------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index b0d478b7dd4..0b29fcd5a2a 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -18,12 +18,12 @@ #include "network/protocols/server_lobby.hpp" -#include "addons/addon.hpp" -#include "config/user_config.hpp" +// #include "addons/addon.hpp" +// #include "config/user_config.hpp" #include "items/network_item_manager.hpp" -#include "items/powerup_manager.hpp" +// #include "items/powerup_manager.hpp" #include "items/attachment.hpp" -#include "karts/controller/player_controller.hpp" +// #include "karts/controller/player_controller.hpp" #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" #include "karts/official_karts.hpp" @@ -34,35 +34,35 @@ #include "network/database_connector.hpp" #include "network/event.hpp" #include "network/game_setup.hpp" -#include "network/network.hpp" +// #include "network/network.hpp" #include "network/network_config.hpp" #include "network/network_player_profile.hpp" -#include "network/peer_vote.hpp" +// #include "network/peer_vote.hpp" #include "network/protocol_manager.hpp" #include "network/protocols/connect_to_peer.hpp" -#include "network/protocols/command_permissions.hpp" +// #include "network/protocols/command_permissions.hpp" #include "network/protocols/game_protocol.hpp" #include "network/protocols/game_events_protocol.hpp" #include "network/protocols/ranking.hpp" #include "network/race_event_manager.hpp" #include "network/server_config.hpp" -#include "network/socket_address.hpp" +// #include "network/socket_address.hpp" #include "network/stk_host.hpp" #include "network/stk_ipv6.hpp" #include "network/stk_peer.hpp" -#include "online/online_profile.hpp" +// #include "online/online_profile.hpp" #include "online/request_manager.hpp" #include "online/xml_request.hpp" -#include "race/race_manager.hpp" +// #include "race/race_manager.hpp" #include "tracks/check_manager.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/game_info.hpp" -#include "utils/log.hpp" -#include "utils/random_generator.hpp" -#include "utils/string_utils.hpp" -#include "utils/time.hpp" -#include "utils/translation.hpp" +// #include "utils/log.hpp" +// #include "utils/random_generator.hpp" +// #include "utils/string_utils.hpp" +// #include "utils/time.hpp" +// #include "utils/translation.hpp" #include #include @@ -532,7 +532,7 @@ void ServerLobby::handleChat(Event* event) chat->setSynchronous(true); core::stringw warn = "Spam detected"; chat->addUInt8(LE_CHAT).encodeString16(warn); - event->getPeer()->sendPacket(chat, true/*reliable*/); + event->getPeer()->sendPacket(chat, PRM_RELIABLE); delete chat; return; } @@ -552,7 +552,7 @@ void ServerLobby::handleChat(Event* event) chat->setSynchronous(true); core::stringw warn = "Don't try to impersonate others!"; chat->addUInt8(LE_CHAT).encodeString16(warn); - event->getPeer()->sendPacket(chat, true/*reliable*/); + event->getPeer()->sendPacket(chat, PRM_RELIABLE); delete chat; return; } @@ -981,7 +981,7 @@ void ServerLobby::writePlayerReport(Event* event) success->setSynchronous(true); success->addUInt8(LE_REPORT_PLAYER).addUInt8(1) .encodeString(reporting_npp->getName()); - event->getPeer()->sendPacket(success, true/*reliable*/); + event->getPeer()->sendPacket(success, PRM_RELIABLE); delete success; } #endif @@ -1519,14 +1519,14 @@ void ServerLobby::rejectLiveJoin(STKPeer* peer, BackLobbyReason blr) NetworkString* reset = getNetworkString(2); reset->setSynchronous(true); reset->addUInt8(LE_BACK_LOBBY).addUInt8(blr); - peer->sendPacket(reset, /*reliable*/true); + peer->sendPacket(reset, PRM_RELIABLE); delete reset; updatePlayerList(); NetworkString* server_info = getNetworkString(); server_info->setSynchronous(true); server_info->addUInt8(LE_SERVER_INFO); m_game_setup->addServerInfo(server_info); - peer->sendPacket(server_info, /*reliable*/true); + peer->sendPacket(server_info, PRM_RELIABLE); delete server_info; } // rejectLiveJoin @@ -1599,7 +1599,7 @@ void ServerLobby::liveJoinRequest(Event* event) getLivePlayers(); NetworkString* load_world_message = getLoadWorldMessage(players, true/*live_join*/); - peer->sendPacket(load_world_message, true/*reliable*/); + peer->sendPacket(load_world_message, PRM_RELIABLE); delete load_world_message; peer->updateLastActivity(); } // liveJoinRequest @@ -1840,7 +1840,7 @@ void ServerLobby::finishedLoadingLiveJoinClient(Event* event) peer->setWaitingForGame(false); peer->setSpectator(spectator); - peer->sendPacket(ns, true/*reliable*/); + peer->sendPacket(ns, PRM_RELIABLE); delete ns; updatePlayerList(); peer->updateLastActivity(); @@ -2007,7 +2007,7 @@ void ServerLobby::update(int ticks) NetworkString* back_to_lobby = getNetworkString(2); back_to_lobby->setSynchronous(true); back_to_lobby->addUInt8(LE_BACK_LOBBY).addUInt8(BLR_NONE); - sendMessageToPeersInServer(back_to_lobby, /*reliable*/true); + sendMessageToPeersInServer(back_to_lobby, PRM_RELIABLE); delete back_to_lobby; RaceEventManager::get()->stop(); @@ -2020,7 +2020,7 @@ void ServerLobby::update(int ticks) NetworkString* back_to_lobby = getNetworkString(2); back_to_lobby->setSynchronous(true); back_to_lobby->addUInt8(LE_BACK_LOBBY).addUInt8(BLR_NONE); - ai->sendPacket(back_to_lobby, /*reliable*/true); + ai->sendPacket(back_to_lobby, PRM_RELIABLE); delete back_to_lobby; } if (all_players_in_world_disconnected) @@ -2044,7 +2044,7 @@ void ServerLobby::update(int ticks) back_lobby->setSynchronous(true); back_lobby->addUInt8(LE_BACK_LOBBY) .addUInt8(BLR_ONE_PLAYER_IN_RANKED_MATCH); - sendMessageToPeers(back_lobby, /*reliable*/true); + sendMessageToPeers(back_lobby, PRM_RELIABLE); delete back_lobby; resetVotingTime(); // m_game_setup->cancelOneRace(); @@ -2096,7 +2096,7 @@ void ServerLobby::update(int ticks) // result screen and go back to the lobby m_timeout.store((int64_t)StkTime::getMonoTimeMs() + 15000); m_state = RESULT_DISPLAY; - sendMessageToPeers(m_result_ns, /*reliable*/ true); + sendMessageToPeers(m_result_ns, PRM_RELIABLE); Log::info("ServerLobby", "End of game message sent"); break; case RESULT_DISPLAY: @@ -2108,7 +2108,7 @@ void ServerLobby::update(int ticks) NetworkString* back_to_lobby = getNetworkString(2); back_to_lobby->setSynchronous(true); back_to_lobby->addUInt8(LE_BACK_LOBBY).addUInt8(BLR_NONE); - sendMessageToPeersInServer(back_to_lobby, /*reliable*/true); + sendMessageToPeersInServer(back_to_lobby, PRM_RELIABLE); delete back_to_lobby; m_rs_state.store(RS_ASYNC_RESET); } @@ -2361,7 +2361,7 @@ void ServerLobby::startSelection(const Event *event) NetworkString* bt = getNetworkString(); bt->setSynchronous(true); bt->addUInt8(LE_BAD_TEAM); - event->getPeer()->sendPacket(bt, true/*reliable*/); + event->getPeer()->sendPacket(bt, PRM_RELIABLE); delete bt; } return; @@ -2625,7 +2625,7 @@ void ServerLobby::startSelection(const Event *event) for (const std::string& track : all_t) ns->encodeString(track); - peer->sendPacket(ns, /*reliable*/true); + peer->sendPacket(ns, PRM_RELIABLE); delete ns; if (areKartFiltersIgnoringKarts()) @@ -2643,7 +2643,7 @@ void ServerLobby::startSelection(const Event *event) { return always_spectate_peers.find(peer) != always_spectate_peers.end(); - }, back_lobby, /*reliable*/true); + }, back_lobby, PRM_RELIABLE); delete back_lobby; updatePlayerList(); } @@ -3094,7 +3094,7 @@ void ServerLobby::kickPlayerWithReason(STKPeer* peer, const char* reason) const message->addUInt8(LE_CONNECTION_REFUSED).addUInt8(RR_BANNED); message->encodeString(std::string(reason)); peer->cleanPlayerProfiles(); - peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); + peer->sendPacket(message, PRM_RELIABLE, PEM_UNENCRYPTED); peer->reset(); delete message; } // kickPlayerWithReason @@ -3254,13 +3254,13 @@ bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) incompatible_reason->encodeString16( StringUtils::utf8ToWide(advice)); peer->sendPacket(incompatible_reason, - true/*reliable*/, false/*encrypted*/); + PRM_RELIABLE, PEM_UNENCRYPTED); Log::info("ServerLobby", "Sent advice"); delete incompatible_reason; } peer->cleanPlayerProfiles(); - peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); + peer->sendPacket(message, PRM_RELIABLE, PEM_UNENCRYPTED); peer->reset(); delete message; } @@ -3349,7 +3349,7 @@ void ServerLobby::connectionRequested(Event* event) message->setSynchronous(true); message->addUInt8(LE_CONNECTION_REFUSED).addUInt8(RR_BUSY); // send only to the peer that made the request and disconnect it now - peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); + peer->sendPacket(message, PRM_RELIABLE, PEM_UNENCRYPTED); peer->reset(); delete message; Log::verbose("ServerLobby", "Player refused: selection started"); @@ -3365,7 +3365,7 @@ void ServerLobby::connectionRequested(Event* event) message->setSynchronous(true); message->addUInt8(LE_CONNECTION_REFUSED) .addUInt8(RR_INCOMPATIBLE_DATA); - peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); + peer->sendPacket(message, PRM_RELIABLE, PEM_UNENCRYPTED); peer->reset(); delete message; Log::verbose("ServerLobby", "Player refused: wrong server version"); @@ -3416,7 +3416,7 @@ void ServerLobby::connectionRequested(Event* event) NetworkString *message = getNetworkString(2); message->setSynchronous(true); message->addUInt8(LE_CONNECTION_REFUSED).addUInt8(RR_TOO_MANY_PLAYERS); - peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); + peer->sendPacket(message, PRM_RELIABLE, PEM_UNENCRYPTED); peer->reset(); delete message; Log::verbose("ServerLobby", "Player refused: too many players"); @@ -3446,7 +3446,7 @@ void ServerLobby::connectionRequested(Event* event) NetworkString* message = getNetworkString(2); message->setSynchronous(true); message->addUInt8(LE_CONNECTION_REFUSED).addUInt8(RR_INVALID_PLAYER); - peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); + peer->sendPacket(message, PRM_RELIABLE, PEM_UNENCRYPTED); peer->reset(); delete message; Log::verbose("ServerLobby", "Player refused: invalid player"); @@ -3494,7 +3494,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, .addUInt8(RR_BANNED); std::string tempban = "Please behave well next time."; message->encodeString(tempban); - peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); + peer->sendPacket(message, PRM_RELIABLE, PEM_UNENCRYPTED); peer->reset(); delete message; Log::verbose("ServerLobby", "Player refused: invalid player"); @@ -3509,7 +3509,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, message->setSynchronous(true); message->addUInt8(LE_CONNECTION_REFUSED) .addUInt8(RR_INCORRECT_PASSWORD); - peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); + peer->sendPacket(message, PRM_RELIABLE, PEM_UNENCRYPTED); peer->reset(); delete message; Log::verbose("ServerLobby", "Player refused: incorrect password"); @@ -3531,7 +3531,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, message->setSynchronous(true); message->addUInt8(LE_CONNECTION_REFUSED) .addUInt8(RR_TOO_MANY_PLAYERS); - peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); + peer->sendPacket(message, PRM_RELIABLE, PEM_UNENCRYPTED); peer->reset(); delete message; Log::verbose("ServerLobby", "Player refused: too many players"); @@ -3548,7 +3548,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, message->setSynchronous(true); message->addUInt8(LE_CONNECTION_REFUSED) .addUInt8(RR_INVALID_PLAYER); - peer->sendPacket(message, true/*reliable*/, false/*encrypted*/); + peer->sendPacket(message, PRM_RELIABLE, PEM_UNENCRYPTED); peer->reset(); delete message; Log::verbose("ServerLobby", "Player refused: invalid player"); @@ -3768,7 +3768,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, chat->setSynchronous(true); std::string warning = m_kart_elimination.getWarningMessage(hasEliminatedPlayer); chat->encodeString16(StringUtils::utf8ToWide(warning)); - peer->sendPacket(chat, true/*reliable*/); + peer->sendPacket(chat, PRM_RELIABLE); delete chat; } if (ServerConfig::m_record_replays) @@ -4410,7 +4410,7 @@ void ServerLobby::configPeersStartTime() ns->addUInt8(cc); *ns += *m_items_complete_state; m_client_starting_time = start_time; - sendMessageToPeers(ns, /*reliable*/true); + sendMessageToPeers(ns, PRM_RELIABLE); const unsigned jitter_tolerance = ServerConfig::m_jitter_tolerance; Log::info("ServerLobby", "Max ping from peers: %d, jitter tolerance: %d", @@ -4742,7 +4742,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, message->addUInt8(LE_CONNECTION_REFUSED) .addUInt8(RR_INCOMPATIBLE_DATA); peer->cleanPlayerProfiles(); - peer->sendPacket(message, true/*reliable*/); + peer->sendPacket(message, PRM_RELIABLE); peer->reset(); delete message; Log::verbose("ServerLobby", @@ -5069,7 +5069,7 @@ void ServerLobby::handleKartInfo(Event* event) if (peer->getClientCapabilities().find("real_addon_karts") != peer->getClientCapabilities().end()) rki.getKartData().encode(ns); - peer->sendPacket(ns, true/*reliable*/); + peer->sendPacket(ns, PRM_RELIABLE); delete ns; @@ -5119,7 +5119,7 @@ void ServerLobby::clientInGameWantsToBackLobby(Event* event) back_to_lobby->setSynchronous(true); back_to_lobby->addUInt8(LE_BACK_LOBBY) .addUInt8(BLR_SERVER_ONWER_QUITED_THE_GAME); - sendMessageToPeersInServer(back_to_lobby, /*reliable*/true); + sendMessageToPeersInServer(back_to_lobby, PRM_RELIABLE); delete back_to_lobby; m_rs_state.store(RS_ASYNC_RESET); return; @@ -5157,14 +5157,14 @@ void ServerLobby::clientInGameWantsToBackLobby(Event* event) NetworkString* reset = getNetworkString(2); reset->setSynchronous(true); reset->addUInt8(LE_BACK_LOBBY).addUInt8(BLR_NONE); - peer->sendPacket(reset, /*reliable*/true); + peer->sendPacket(reset, PRM_RELIABLE); delete reset; updatePlayerList(); NetworkString* server_info = getNetworkString(); server_info->setSynchronous(true); server_info->addUInt8(LE_SERVER_INFO); m_game_setup->addServerInfo(server_info); - peer->sendPacket(server_info, /*relsiable*/true); + peer->sendPacket(server_info, PRM_RELIABLE); delete server_info; } // clientInGameWantsToBackLobby @@ -5190,7 +5190,7 @@ void ServerLobby::clientSelectingAssetsWantsToBackLobby(Event* event) back_to_lobby->setSynchronous(true); back_to_lobby->addUInt8(LE_BACK_LOBBY) .addUInt8(BLR_SERVER_ONWER_QUITED_THE_GAME); - sendMessageToPeersInServer(back_to_lobby, /*reliable*/true); + sendMessageToPeersInServer(back_to_lobby, PRM_RELIABLE); delete back_to_lobby; resetVotingTime(); resetServer(); @@ -5205,14 +5205,14 @@ void ServerLobby::clientSelectingAssetsWantsToBackLobby(Event* event) NetworkString* reset = getNetworkString(2); reset->setSynchronous(true); reset->addUInt8(LE_BACK_LOBBY).addUInt8(BLR_NONE); - peer->sendPacket(reset, /*reliable*/true); + peer->sendPacket(reset, PRM_RELIABLE); delete reset; updatePlayerList(); NetworkString* server_info = getNetworkString(); server_info->setSynchronous(true); server_info->addUInt8(LE_SERVER_INFO); m_game_setup->addServerInfo(server_info); - peer->sendPacket(server_info, /*reliable*/true); + peer->sendPacket(server_info, PRM_RELIABLE); delete server_info; } // clientSelectingAssetsWantsToBackLobby @@ -5708,7 +5708,7 @@ void ServerLobby::writeOwnReport(STKPeer* reporter, STKPeer* reporting, const st else success->addUInt8(LE_REPORT_PLAYER).addUInt8(1) .encodeString(reporting_npp->getName()); - reporter->sendPacket(success, true/*reliable*/); + reporter->sendPacket(success, PRM_RELIABLE); delete success; } #endif @@ -5893,7 +5893,7 @@ void ServerLobby::sendStringToPeer(std::string& s, std::shared_ptr& pee chat->addUInt8(LE_CHAT); chat->setSynchronous(true); chat->encodeString16(StringUtils::utf8ToWide(s)); - peer->sendPacket(chat, true/*reliable*/); + peer->sendPacket(chat, PRM_RELIABLE); delete chat; } // sendStringToPeer //----------------------------------------------------------------------------- @@ -5908,7 +5908,7 @@ void ServerLobby::sendStringToPeer(std::string& s, STKPeer* peer) chat->addUInt8(LE_CHAT); chat->setSynchronous(true); chat->encodeString16(StringUtils::utf8ToWide(s)); - peer->sendPacket(chat, true/*reliable*/); + peer->sendPacket(chat, PRM_RELIABLE); delete chat; } // sendStringToPeer //----------------------------------------------------------------------------- @@ -5918,7 +5918,7 @@ void ServerLobby::sendStringToAllPeers(std::string& s) chat->addUInt8(LE_CHAT); chat->setSynchronous(true); chat->encodeString16(StringUtils::utf8ToWide(s)); - sendMessageToPeers(chat, true/*reliable*/); + sendMessageToPeers(chat, PRM_RELIABLE); delete chat; } // sendStringToAllPeers //----------------------------------------------------------------------------- diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index 5b8cc5a18c4..ecccdc09211 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -926,7 +926,7 @@ void STKHost::mainLoop(ProcessType pt) NetworkString msg(PROTOCOL_LOBBY_ROOM); msg.setSynchronous(true); msg.addUInt8(LobbyProtocol::LE_BAD_CONNECTION); - p.second->sendPacket(&msg, /*reliable*/true); + p.second->sendPacket(&msg, PRM_RELIABLE); } } } @@ -1339,7 +1339,7 @@ std::shared_ptr STKHost::getServerPeerForClient() const * \param data Data to sent. * \param reliable If the data should be sent reliable or now. */ -void STKHost::sendPacketToAllPeersInServer(NetworkString *data, bool reliable) +void STKHost::sendPacketToAllPeersInServer(NetworkString *data, PacketReliabilityMode reliable) { std::lock_guard lock(m_peers_mutex); for (auto p : m_peers) @@ -1354,7 +1354,7 @@ void STKHost::sendPacketToAllPeersInServer(NetworkString *data, bool reliable) * \param data Data to sent. * \param reliable If the data should be sent reliable or now. */ -void STKHost::sendPacketToAllPeers(NetworkString *data, bool reliable) +void STKHost::sendPacketToAllPeers(NetworkString *data, PacketReliabilityMode reliable) { std::lock_guard lock(m_peers_mutex); for (auto p : m_peers) @@ -1371,7 +1371,7 @@ void STKHost::sendPacketToAllPeers(NetworkString *data, bool reliable) * \param reliable If the data should be sent reliable or now. */ void STKHost::sendPacketExcept(STKPeer* peer, NetworkString *data, - bool reliable) + PacketReliabilityMode reliable) { std::lock_guard lock(m_peers_mutex); for (auto p : m_peers) @@ -1392,7 +1392,7 @@ void STKHost::sendPacketExcept(STKPeer* peer, NetworkString *data, * \param reliable If the data should be sent reliable or now. */ void STKHost::sendPacketToAllPeersWith(std::function predicate, - NetworkString* data, bool reliable) + NetworkString* data, PacketReliabilityMode reliable) { std::lock_guard lock(m_peers_mutex); for (auto p : m_peers) @@ -1407,7 +1407,7 @@ void STKHost::sendPacketToAllPeersWith(std::function predicate, //----------------------------------------------------------------------------- /** Sends a message from a client to the server. */ -void STKHost::sendToServer(NetworkString *data, bool reliable) +void STKHost::sendToServer(NetworkString *data, PacketReliabilityMode reliable) { std::lock_guard lock(m_peers_mutex); if (m_peers.empty()) diff --git a/src/network/stk_host.hpp b/src/network/stk_host.hpp index 3f7829dddea..f7395ad3449 100644 --- a/src/network/stk_host.hpp +++ b/src/network/stk_host.hpp @@ -25,6 +25,7 @@ #include "utils/stk_process.hpp" #include "utils/synchronised.hpp" #include "utils/time.hpp" +#include "utils/constants.hpp" #include "irrString.h" @@ -244,12 +245,12 @@ class STKHost void shutdown(); //------------------------------------------------------------------------- void sendPacketToAllPeersInServer(NetworkString *data, - bool reliable = true); + PacketReliabilityMode reliable = PRM_RELIABLE); // ------------------------------------------------------------------------ - void sendPacketToAllPeers(NetworkString *data, bool reliable = true); + void sendPacketToAllPeers(NetworkString *data, PacketReliabilityMode reliable = PRM_RELIABLE); // ------------------------------------------------------------------------ void sendPacketToAllPeersWith(std::function predicate, - NetworkString* data, bool reliable = true); + NetworkString* data, PacketReliabilityMode reliable = PRM_RELIABLE); // ------------------------------------------------------------------------ /** Returns true if this client instance is allowed to control the server. * It will auto transfer ownership if previous server owner disconnected. @@ -271,7 +272,7 @@ class STKHost std::shared_ptr findPeerByWildcard(const core::stringw& name_pattern, std::string &name_found) const; // ------------------------------------------------------------------------ void sendPacketExcept(STKPeer* peer, NetworkString *data, - bool reliable = true); + PacketReliabilityMode reliable = PRM_RELIABLE); // ------------------------------------------------------------------------ void setupClient(int peer_count, int channel_limit, uint32_t max_incoming_bandwidth, @@ -344,7 +345,7 @@ class STKHost /** Returns the host id of this host. */ uint32_t getMyHostId() const { return m_host_id; } // ------------------------------------------------------------------------ - void sendToServer(NetworkString *data, bool reliable = true); + void sendToServer(NetworkString *data, PacketReliabilityMode reliable = PRM_RELIABLE); // ------------------------------------------------------------------------ bool isClientServer() const; // ------------------------------------------------------------------------ diff --git a/src/network/stk_peer.cpp b/src/network/stk_peer.cpp index bca21c598a1..146fe8bfa03 100644 --- a/src/network/stk_peer.cpp +++ b/src/network/stk_peer.cpp @@ -103,7 +103,7 @@ void STKPeer::reset() * \param reliable If the data is sent reliable or not. * \param encrypted If the data is sent encrypted or not. */ -void STKPeer::sendPacket(NetworkString *data, bool reliable, bool encrypted) +void STKPeer::sendPacket(NetworkString *data, PacketReliabilityMode reliable, PacketEncryptionMode encrypted) { if (m_disconnected.load()) return; diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index 00f75290eab..aabe28aaf5f 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -26,6 +26,7 @@ #include "utils/no_copy.hpp" #include "utils/time.hpp" #include "utils/types.hpp" +#include "utils/constants.hpp" #include @@ -144,8 +145,8 @@ class STKPeer : public NoCopy // ------------------------------------------------------------------------ ~STKPeer(); // ------------------------------------------------------------------------ - void sendPacket(NetworkString *data, bool reliable = true, - bool encrypted = true); + void sendPacket(NetworkString *data, PacketReliabilityMode reliable = PRM_RELIABLE, + PacketEncryptionMode encrypted = PEM_ENCRYPTED); // ------------------------------------------------------------------------ void disconnect(); // ------------------------------------------------------------------------ diff --git a/src/states_screens/dialogs/network_player_dialog.cpp b/src/states_screens/dialogs/network_player_dialog.cpp index a488d456204..7bbbdcb4836 100644 --- a/src/states_screens/dialogs/network_player_dialog.cpp +++ b/src/states_screens/dialogs/network_player_dialog.cpp @@ -205,7 +205,7 @@ void NetworkPlayerDialog::onUpdate(float dt) NetworkString report(PROTOCOL_LOBBY_ROOM); report.addUInt8(LobbyProtocol::LE_REPORT_PLAYER) .addUInt32(host_id).encodeString16(info); - STKHost::get()->sendToServer(&report, true/*reliable*/); + STKHost::get()->sendToServer(&report, PRM_RELIABLE); return true; }); return; @@ -248,7 +248,7 @@ GUIEngine::EventPropagation { NetworkString kick(PROTOCOL_LOBBY_ROOM); kick.addUInt8(LobbyProtocol::LE_KICK_HOST).addUInt32(m_host_id); - STKHost::get()->sendToServer(&kick, true/*reliable*/); + STKHost::get()->sendToServer(&kick, PRM_RELIABLE); m_self_destroy = true; return GUIEngine::EVENT_BLOCK; } @@ -258,7 +258,7 @@ GUIEngine::EventPropagation NetworkString change_team(PROTOCOL_LOBBY_ROOM); change_team.addUInt8(LobbyProtocol::LE_CHANGE_TEAM) .addUInt8(m_local_id); - STKHost::get()->sendToServer(&change_team, true/*reliable*/); + STKHost::get()->sendToServer(&change_team, PRM_RELIABLE); m_self_destroy = true; return GUIEngine::EVENT_BLOCK; } @@ -273,7 +273,7 @@ GUIEngine::EventPropagation NetworkString change_handicap(PROTOCOL_LOBBY_ROOM); change_handicap.addUInt8(LobbyProtocol::LE_CHANGE_HANDICAP) .addUInt8(m_local_id).addUInt8(new_handicap); - STKHost::get()->sendToServer(&change_handicap, true/*reliable*/); + STKHost::get()->sendToServer(&change_handicap, PRM_RELIABLE); m_self_destroy = true; return GUIEngine::EVENT_BLOCK; } diff --git a/src/states_screens/dialogs/race_paused_dialog.cpp b/src/states_screens/dialogs/race_paused_dialog.cpp index 572fca5794a..1171077c15f 100644 --- a/src/states_screens/dialogs/race_paused_dialog.cpp +++ b/src/states_screens/dialogs/race_paused_dialog.cpp @@ -388,7 +388,7 @@ GUIEngine::EventPropagation NetworkString back(PROTOCOL_LOBBY_ROOM); back.setSynchronous(true); back.addUInt8(LobbyProtocol::LE_CLIENT_BACK_LOBBY); - STKHost::get()->sendToServer(&back, true); + STKHost::get()->sendToServer(&back, PRM_RELIABLE); } else { diff --git a/src/states_screens/dialogs/server_configuration_dialog.cpp b/src/states_screens/dialogs/server_configuration_dialog.cpp index f775acc06b5..c2c28187363 100644 --- a/src/states_screens/dialogs/server_configuration_dialog.cpp +++ b/src/states_screens/dialogs/server_configuration_dialog.cpp @@ -122,7 +122,7 @@ GUIEngine::EventPropagation break; } } - STKHost::get()->sendToServer(&change, true); + STKHost::get()->sendToServer(&change, PRM_RELIABLE); return GUIEngine::EVENT_BLOCK; } } diff --git a/src/states_screens/online/network_kart_selection.cpp b/src/states_screens/online/network_kart_selection.cpp index 8539caa567d..8f8cc6bb0d8 100644 --- a/src/states_screens/online/network_kart_selection.cpp +++ b/src/states_screens/online/network_kart_selection.cpp @@ -157,7 +157,7 @@ void NetworkKartSelectionScreen::allPlayersDone() kart_data.encode(&kart); } } - STKHost::get()->sendToServer(&kart, true); + STKHost::get()->sendToServer(&kart, PRM_RELIABLE); // ---- Switch to assign mode input_manager->getDeviceManager()->setAssignMode(ASSIGN); @@ -188,7 +188,7 @@ bool NetworkKartSelectionScreen::onEscapePressed() m_exit_timeout = StkTime::getMonoTimeMs() + 5000; NetworkString back(PROTOCOL_LOBBY_ROOM); back.addUInt8(LobbyProtocol::LE_CLIENT_BACK_LOBBY); - STKHost::get()->sendToServer(&back, true); + STKHost::get()->sendToServer(&back, PRM_RELIABLE); } return false; } diff --git a/src/states_screens/online/networking_lobby.cpp b/src/states_screens/online/networking_lobby.cpp index 94caa412429..a2bc4284cf1 100644 --- a/src/states_screens/online/networking_lobby.cpp +++ b/src/states_screens/online/networking_lobby.cpp @@ -863,7 +863,7 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name, // Send a message to the server to start NetworkString start(PROTOCOL_LOBBY_ROOM); start.addUInt8(LobbyProtocol::LE_REQUEST_BEGIN); - STKHost::get()->sendToServer(&start, true); + STKHost::get()->sendToServer(&start, PRM_RELIABLE); } } else if (name == m_config_button->m_properties[PROP_ID]) @@ -883,7 +883,7 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name, start.addUInt8(LobbyProtocol::LE_LIVE_JOIN) // is spectating .addUInt8(1); - STKHost::get()->sendToServer(&start, true); + STKHost::get()->sendToServer(&start, PRM_RELIABLE); return; } if (cl) diff --git a/src/states_screens/online/tracks_screen.cpp b/src/states_screens/online/tracks_screen.cpp index f0d9c5e33fe..f9aa94d7ab5 100644 --- a/src/states_screens/online/tracks_screen.cpp +++ b/src/states_screens/online/tracks_screen.cpp @@ -757,7 +757,7 @@ void TracksScreen::voteForPlayer() PeerVote pvote(vote); lp->addVote(STKHost::get()->getMyHostId(), pvote); } - STKHost::get()->sendToServer(&vote, true); + STKHost::get()->sendToServer(&vote, PRM_RELIABLE); } // voteForPlayer // ----------------------------------------------------------------------------- diff --git a/src/utils/constants.hpp b/src/utils/constants.hpp index 7e50df8e683..12dfb372681 100644 --- a/src/utils/constants.hpp +++ b/src/utils/constants.hpp @@ -20,11 +20,25 @@ #ifndef HEADER_CONSTANTS_HPP #define HEADER_CONSTANTS_HPP +#include "utils/types.hpp" + /* All final units are in meters (or meters/sec or meters/sec^2) and degrees (or degrees/sec). */ +enum PacketReliabilityMode : uint8_t +{ + PRM_UNRELIABLE = 0, + PRM_RELIABLE = 1, +}; + +enum PacketEncryptionMode : uint8_t +{ + PEM_UNENCRYPTED = 0, + PEM_ENCRYPTED = 1, +}; + /* Handy constants */ #define KILOMETER 1000.000f #define HOUR (60.0f * 60.0f) From 0bb92985effba921fc2a662bb7037fbca24e8c60 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 16 Feb 2025 01:04:48 +0400 Subject: [PATCH 570/830] Use shared_ptr for STKPeer in most cases Still has some bugs --- src/modes/capture_the_flag.cpp | 2 +- src/modes/capture_the_flag.hpp | 2 +- src/modes/free_for_all.cpp | 2 +- src/modes/free_for_all.hpp | 2 +- src/modes/linear_world.cpp | 2 +- src/modes/linear_world.hpp | 2 +- src/modes/soccer_world.cpp | 2 +- src/modes/soccer_world.hpp | 2 +- src/modes/world.hpp | 2 +- src/network/database_connector.cpp | 8 +- src/network/database_connector.hpp | 6 +- src/network/protocols/command_manager.cpp | 18 +-- src/network/protocols/game_protocol.cpp | 2 +- src/network/protocols/server_lobby.cpp | 156 ++++++++-------------- src/network/protocols/server_lobby.hpp | 52 ++++---- src/network/stk_host.cpp | 10 +- src/network/stk_host.hpp | 4 +- 17 files changed, 114 insertions(+), 160 deletions(-) diff --git a/src/modes/capture_the_flag.cpp b/src/modes/capture_the_flag.cpp index c26d7618c42..256c5ce65fb 100644 --- a/src/modes/capture_the_flag.cpp +++ b/src/modes/capture_the_flag.cpp @@ -571,7 +571,7 @@ const std::string& CaptureTheFlag::getIdent() const } // getIdent // ---------------------------------------------------------------------------- -void CaptureTheFlag::saveCompleteState(BareNetworkString* bns, STKPeer* peer) +void CaptureTheFlag::saveCompleteState(BareNetworkString* bns, std::shared_ptr peer) { FreeForAll::saveCompleteState(bns, peer); bns->addUInt32(m_red_scores).addUInt32(m_blue_scores); diff --git a/src/modes/capture_the_flag.hpp b/src/modes/capture_the_flag.hpp index 1a830b6c9e7..da6f090bf5d 100644 --- a/src/modes/capture_the_flag.hpp +++ b/src/modes/capture_the_flag.hpp @@ -158,7 +158,7 @@ class CaptureTheFlag : public FreeForAll } // ------------------------------------------------------------------------ virtual void saveCompleteState(BareNetworkString* bns, - STKPeer* peer) OVERRIDE; + std::shared_ptr peer) OVERRIDE; // ------------------------------------------------------------------------ virtual void restoreCompleteState(const BareNetworkString& b) OVERRIDE; }; // CaptureTheFlag diff --git a/src/modes/free_for_all.cpp b/src/modes/free_for_all.cpp index d28997d7e66..3869d2407b4 100644 --- a/src/modes/free_for_all.cpp +++ b/src/modes/free_for_all.cpp @@ -295,7 +295,7 @@ bool FreeForAll::getKartFFAResult(int kart_id) const } // getKartFFAResult // ---------------------------------------------------------------------------- -void FreeForAll::saveCompleteState(BareNetworkString* bns, STKPeer* peer) +void FreeForAll::saveCompleteState(BareNetworkString* bns, std::shared_ptr peer) { for (unsigned i = 0; i < m_scores.size(); i++) bns->addUInt32(m_scores[i]); diff --git a/src/modes/free_for_all.hpp b/src/modes/free_for_all.hpp index b1d8649f816..e74c36e6c36 100644 --- a/src/modes/free_for_all.hpp +++ b/src/modes/free_for_all.hpp @@ -86,7 +86,7 @@ class FreeForAll : public WorldWithRank } // ------------------------------------------------------------------------ virtual void saveCompleteState(BareNetworkString* bns, - STKPeer* peer) OVERRIDE; + std::shared_ptr peer) OVERRIDE; // ------------------------------------------------------------------------ virtual void restoreCompleteState(const BareNetworkString& b) OVERRIDE; // ------------------------------------------------------------------------ diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index 40c46e50efd..d4de352c294 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -1238,7 +1238,7 @@ void LinearWorld::KartInfo::restoreCompleteState(const BareNetworkString& b) } // restoreCompleteState // ---------------------------------------------------------------------------- -void LinearWorld::saveCompleteState(BareNetworkString* bns, STKPeer* peer) +void LinearWorld::saveCompleteState(BareNetworkString* bns, std::shared_ptr peer) { bns->addUInt32(m_fastest_lap_ticks); bns->addFloat(m_distance_increase); diff --git a/src/modes/linear_world.hpp b/src/modes/linear_world.hpp index b170f608cd3..3b93bccc0af 100644 --- a/src/modes/linear_world.hpp +++ b/src/modes/linear_world.hpp @@ -277,7 +277,7 @@ class LinearWorld : public WorldWithRank OVERRIDE; // ------------------------------------------------------------------------ virtual void saveCompleteState(BareNetworkString* bns, - STKPeer* peer) OVERRIDE; + std::shared_ptr peer) OVERRIDE; // ------------------------------------------------------------------------ virtual void restoreCompleteState(const BareNetworkString& b) OVERRIDE; // ------------------------------------------------------------------------ diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp index 4bbf30903d8..25b9b5560af 100644 --- a/src/modes/soccer_world.cpp +++ b/src/modes/soccer_world.cpp @@ -1203,7 +1203,7 @@ void SoccerWorld::enterRaceOverState() } // enterRaceOverState // ---------------------------------------------------------------------------- -void SoccerWorld::saveCompleteState(BareNetworkString* bns, STKPeer* peer) +void SoccerWorld::saveCompleteState(BareNetworkString* bns, std::shared_ptr peer) { const unsigned red_scorers = (unsigned)m_red_scorers.size(); bns->addUInt32(red_scorers); diff --git a/src/modes/soccer_world.hpp b/src/modes/soccer_world.hpp index b4f820f16ba..881e79eb753 100644 --- a/src/modes/soccer_world.hpp +++ b/src/modes/soccer_world.hpp @@ -264,7 +264,7 @@ class SoccerWorld : public WorldWithRank } // ------------------------------------------------------------------------ virtual void saveCompleteState(BareNetworkString* bns, - STKPeer* peer) OVERRIDE; + std::shared_ptr peer) OVERRIDE; // ------------------------------------------------------------------------ virtual void restoreCompleteState(const BareNetworkString& b) OVERRIDE; // ------------------------------------------------------------------------ diff --git a/src/modes/world.hpp b/src/modes/world.hpp index 96c0bb2c143..342c82f1b09 100644 --- a/src/modes/world.hpp +++ b/src/modes/world.hpp @@ -376,7 +376,7 @@ class World : public WorldStatus m_eliminated_karts--; } // ------------------------------------------------------------------------ - virtual void saveCompleteState(BareNetworkString* bns, STKPeer* peer) {} + virtual void saveCompleteState(BareNetworkString* bns, std::shared_ptr peer) {} // ------------------------------------------------------------------------ virtual void restoreCompleteState(const BareNetworkString& buffer) {} // ------------------------------------------------------------------------ diff --git a/src/network/database_connector.cpp b/src/network/database_connector.cpp index f820e1d19c2..769b21e0a90 100644 --- a/src/network/database_connector.cpp +++ b/src/network/database_connector.cpp @@ -151,7 +151,7 @@ void DatabaseConnector::destroyDatabase() { auto peers = STKHost::get()->getPeers(); for (auto& peer : peers) - writeDisconnectInfoTable(peer.get()); + writeDisconnectInfoTable(peer); if (m_db != NULL) sqlite3_close(m_db); } // destroyDatabase @@ -380,7 +380,7 @@ sqlite3_extension_init(sqlite3* db, char** pzErrMsg, * database peer's disconnection time and statistics (ping and packet loss). * \param peer Disconnecting peer. */ -void DatabaseConnector::writeDisconnectInfoTable(STKPeer* peer) +void DatabaseConnector::writeDisconnectInfoTable(std::shared_ptr peer) { if (m_server_stats_table.empty()) return; @@ -676,8 +676,8 @@ void DatabaseConnector::initServerStatsTable() * \return True if the database query succeeded. */ bool DatabaseConnector::writeReport( - STKPeer* reporter, std::shared_ptr reporter_npp, - STKPeer* reporting, std::shared_ptr reporting_npp, + std::shared_ptr reporter, std::shared_ptr reporter_npp, + std::shared_ptr reporting, std::shared_ptr reporting_npp, irr::core::stringw& info) { std::string query; diff --git a/src/network/database_connector.hpp b/src/network/database_connector.hpp index 4e6593be072..81080680461 100644 --- a/src/network/database_connector.hpp +++ b/src/network/database_connector.hpp @@ -174,11 +174,11 @@ class DatabaseConnector sqlite3_value** argv); static void insideIPv6CIDRSQL(sqlite3_context* context, int argc, sqlite3_value** argv); - void writeDisconnectInfoTable(STKPeer* peer); + void writeDisconnectInfoTable(std::shared_ptr peer); void initServerStatsTable(); bool writeReport( - STKPeer* reporter, std::shared_ptr reporter_npp, - STKPeer* reporting, std::shared_ptr reporting_npp, + std::shared_ptr reporter, std::shared_ptr reporter_npp, + std::shared_ptr reporting, std::shared_ptr reporting_npp, irr::core::stringw& info); bool hasDatabase() const { return m_db != nullptr; } bool hasServerStatsTable() const { return !m_server_stats_table.empty(); } diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 942af04fdc0..db1ed49d3a0 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -1762,7 +1762,7 @@ void CommandManager::process_kick(Context& context) if (ServerConfig::m_track_kicks) { std::string auto_report = "[ Auto report caused by kick ]"; - m_lobby->writeOwnReport(player_peer.get(), peer.get(), auto_report); + m_lobby->writeOwnReport(player_peer, peer, auto_report); } if (argv[0] == "kickban") { @@ -2219,7 +2219,7 @@ void CommandManager::process_tell(Context& context) ans.push_back(' '); ans += argv[i]; } - m_lobby->writeOwnReport(peer.get(), peer.get(), ans); + m_lobby->writeOwnReport(peer, peer, ans); } // process_tell // ======================================================================== @@ -2277,7 +2277,7 @@ void CommandManager::process_teamchat(Context& context) error(context, true); return; } - m_lobby->m_team_speakers.insert(peer.get()); + m_lobby->m_team_speakers.insert(peer); std::string msg = "Your messages are now addressed to team only"; m_lobby->sendStringToPeer(msg, peer); } // process_teamchat @@ -2297,13 +2297,13 @@ void CommandManager::process_to(Context& context) error(context); return; } - m_lobby->m_message_receivers[peer.get()].clear(); + m_lobby->m_message_receivers[peer].clear(); for (unsigned i = 1; i < argv.size(); ++i) { if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, i, m_stf_present_users, 3, false, true)) return; - m_lobby->m_message_receivers[peer.get()].insert( + m_lobby->m_message_receivers[peer].insert( StringUtils::utf8ToWide(argv[i])); } std::string msg = "Successfully changed chat settings"; @@ -2319,8 +2319,8 @@ void CommandManager::process_public(Context& context) error(context, true); return; } - m_lobby->m_message_receivers[peer.get()].clear(); - m_lobby->m_team_speakers.erase(peer.get()); + m_lobby->m_message_receivers[peer].clear(); + m_lobby->m_team_speakers.erase(peer); std::string s = "Your messages are now public"; m_lobby->sendStringToPeer(s, peer); } // process_public @@ -3285,7 +3285,7 @@ void CommandManager::process_register(Context& context) } std::string message_ok = "Your registration request is being processed"; std::string message_wrong = "Sorry, an error occurred. Please try again."; - if (m_lobby->writeOnePlayerReport(peer.get(), ServerConfig::m_register_table_name, + if (m_lobby->writeOnePlayerReport(peer, ServerConfig::m_register_table_name, ans)) m_lobby->sendStringToPeer(message_ok, peer); else @@ -4036,7 +4036,7 @@ void CommandManager::process_why_hourglass(Context& context) error(context); return; } - auto it = m_lobby->m_why_peer_cannot_play.find(player_peer.get()); + auto it = m_lobby->m_why_peer_cannot_play.find(player_peer); if (it == m_lobby->m_why_peer_cannot_play.end()) { response = "For some reason, server doesn't know about the hourglass status of this player."; diff --git a/src/network/protocols/game_protocol.cpp b/src/network/protocols/game_protocol.cpp index f7c2e274d10..564a536549a 100644 --- a/src/network/protocols/game_protocol.cpp +++ b/src/network/protocols/game_protocol.cpp @@ -184,7 +184,7 @@ void GameProtocol::controllerAction(int kart_id, PlayerAction action, */ void GameProtocol::handleControllerAction(Event *event) { - STKPeer* peer = event->getPeer(); + std::shared_ptr peer = event->getPeerSP(); if (NetworkConfig::get()->isServer() && (peer->isWaitingForGame() || peer->getAvailableKartIDs().empty())) return; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 0b29fcd5a2a..f7d103abc73 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -62,7 +62,7 @@ // #include "utils/random_generator.hpp" // #include "utils/string_utils.hpp" // #include "utils/time.hpp" -// #include "utils/translation.hpp" +#include "utils/translation.hpp" #include #include @@ -574,7 +574,7 @@ void ServerLobby::handleChat(Event* event) NetworkString* chat = getNetworkString(); chat->setSynchronous(true); const bool game_started = m_state.load() != WAITING_FOR_START_GAME; - STKPeer* sender = event->getPeer(); + std::shared_ptr sender = event->getPeerSP(); auto can_receive = m_message_receivers[sender]; if (!can_receive.empty()) message = StringUtils::utf32ToWide({0x1f512, 0x20}) + message; @@ -641,7 +641,7 @@ void ServerLobby::handleChat(Event* event) STKHost::get()->sendPacketToAllPeersWith( [game_started, sender_in_game, target_team, can_receive, sender, team_speak, teams, tournament_limit, - important_players, sender_name, sees_teamchats, this](STKPeer* p) + important_players, sender_name, sees_teamchats, this](std::shared_ptr p) { if (sender == p) return true; @@ -689,7 +689,7 @@ void ServerLobby::handleChat(Event* event) { if (auto peer_sp = peer.first.lock()) { - if (peer_sp.get() == p && + if (peer_sp == p && peer.second.find(sender_name) != peer.second.end()) return false; } @@ -802,7 +802,7 @@ void ServerLobby::kickHost(Event* event) if (ServerConfig::m_track_kicks) { std::string auto_report = "[ Auto report caused by kick ]"; - writeOwnReport(peer.get(), event->getPeerSP().get(), auto_report); + writeOwnReport(peer, event->getPeerSP(), auto_report); } } } // kickHost @@ -835,7 +835,7 @@ bool ServerLobby::notifyEventAsynchronous(Event* event) clientSelectingAssetsWantsToBackLobby(event); break; case LE_REPORT_PLAYER: writePlayerReport(event); break; case LE_ASSETS_UPDATE: - handleAssets(event->data(), event->getPeer()); break; + handleAssets(event->data(), event->getPeerSP()); break; case LE_COMMAND: handleServerCommand(event, event->getPeerSP()); break; default: break; @@ -872,7 +872,7 @@ void ServerLobby::pollDatabase() std::vector online_id_ban_list = m_db_connector->getOnlineIdBanTableData(); - for (std::shared_ptr& p : STKHost::get()->getPeers()) + for (std::shared_ptr p : STKHost::get()->getPeers()) { if (p->isAIPeer()) continue; @@ -957,7 +957,7 @@ void ServerLobby::writePlayerReport(Event* event) #ifdef ENABLE_SQLITE3 if (!m_db_connector->hasDatabase() || !m_db_connector->hasPlayerReportsTable()) return; - STKPeer* reporter = event->getPeer(); + std::shared_ptr reporter = event->getPeerSP(); if (!reporter->hasPlayerProfiles()) return; auto reporter_npp = reporter->getPlayerProfiles()[0]; @@ -974,7 +974,7 @@ void ServerLobby::writePlayerReport(Event* event) auto reporting_npp = reporting_peer->getPlayerProfiles()[0]; bool written = m_db_connector->writeReport(reporter, reporter_npp, - reporting_peer.get(), reporting_npp, info); + reporting_peer, reporting_npp, info); if (written) { NetworkString* success = getNetworkString(); @@ -1314,7 +1314,7 @@ void ServerLobby::asynchronousUpdate() // code will also have to provide kart data (or setKartName has to // set the correct hitbox itself). std::string new_kart = getKartForBadKartChoice( - players[i]->getPeer().get(), name, current_kart); + players[i]->getPeer(), name, current_kart); if (new_kart != current_kart) { // Filters only support standard karts for now, but when they @@ -1514,7 +1514,7 @@ bool ServerLobby::worldIsActive() const /** \ref STKPeer peer will be reset back to the lobby with reason * \ref BackLobbyReason blr */ -void ServerLobby::rejectLiveJoin(STKPeer* peer, BackLobbyReason blr) +void ServerLobby::rejectLiveJoin(std::shared_ptr peer, BackLobbyReason blr) { NetworkString* reset = getNetworkString(2); reset->setSynchronous(true); @@ -1536,7 +1536,7 @@ void ServerLobby::rejectLiveJoin(STKPeer* peer, BackLobbyReason blr) */ void ServerLobby::liveJoinRequest(Event* event) { - STKPeer* peer = event->getPeer(); + std::shared_ptr peer = event->getPeerSP(); const NetworkString& data = event->data(); if (!canLiveJoinNow()) @@ -1567,7 +1567,7 @@ void ServerLobby::liveJoinRequest(Event* event) used_id.push_back(id); } if ((used_id.size() != peer->getPlayerProfiles().size()) || - (spectators_by_limit.find(event->getPeerSP().get()) != spectators_by_limit.end())) + (spectators_by_limit.find(event->getPeerSP()) != spectators_by_limit.end())) { for (unsigned i = 0; i < peer->getPlayerProfiles().size(); i++) peer->getPlayerProfiles()[i]->setKartName(""); @@ -1714,7 +1714,7 @@ void ServerLobby::finishedLoadingLiveJoinClient(Event* event) std::shared_ptr peer = event->getPeerSP(); if (!canLiveJoinNow()) { - rejectLiveJoin(peer.get(), BLR_NO_GAME_FOR_LIVE_JOIN); + rejectLiveJoin(peer, BLR_NO_GAME_FOR_LIVE_JOIN); return; } bool live_joined_in_time = true; @@ -1731,7 +1731,7 @@ void ServerLobby::finishedLoadingLiveJoinClient(Event* event) { Log::warn("ServerLobby", "%s can't live-join in time.", peer->getAddress().toString().c_str()); - rejectLiveJoin(peer.get(), BLR_NO_GAME_FOR_LIVE_JOIN); + rejectLiveJoin(peer, BLR_NO_GAME_FOR_LIVE_JOIN); return; } World* w = World::getWorld(); @@ -1824,7 +1824,7 @@ void ServerLobby::finishedLoadingLiveJoinClient(Event* event) nim->saveCompleteState(ns); nim->addLiveJoinPeer(peer); - w->saveCompleteState(ns, peer.get()); + w->saveCompleteState(ns, peer); if (RaceManager::get()->supportsLiveJoining()) { // Only needed in non-racing mode as no need players can added after @@ -2371,7 +2371,7 @@ void ServerLobby::startSelection(const Event *event) unsigned max_player = 0; STKHost::get()->updatePlayers(&max_player); auto peers = STKHost::get()->getPeers(); - std::set always_spectate_peers; + std::set> always_spectate_peers; // Set late coming player to spectate if too many players auto& spectators_by_limit = getSpectatorsByLimit(); @@ -2402,12 +2402,12 @@ void ServerLobby::startSelection(const Event *event) peer->setWaitingForGame(true); m_peers_ready.erase(peer); need_to_update = true; - always_spectate_peers.insert(peer.get()); + always_spectate_peers.insert(peer); continue; } else if (peer->alwaysSpectate()) { - always_spectate_peers.insert(peer.get()); + always_spectate_peers.insert(peer); continue; } peer->eraseServerKarts(m_available_kts.first, karts_erase); @@ -2426,11 +2426,11 @@ void ServerLobby::startSelection(const Event *event) Log::warn("ServerLobby", "An attempt to start a game while no one can play."); std::string msg = "No one can play!"; - sendStringToPeer(msg, event->getPeer()); + sendStringToPeer(msg, event->getPeerSP()); } addWaitingPlayersToGame(); return; - // for (STKPeer* peer : always_spectate_peers) + // for (std::shared_ptr peer : always_spectate_peers) // peer->setAlwaysSpectate(ASM_NONE); // always_spectate_peers.clear(); } @@ -2440,7 +2440,7 @@ void ServerLobby::startSelection(const Event *event) // be able to vote, this will be reset in STKHost::getPlayersForNewGame // This will also allow a correct number of in game players for max // arena players handling - for (STKPeer* peer : always_spectate_peers) + for (std::shared_ptr peer : always_spectate_peers) peer->setWaitingForGame(true); } @@ -2639,7 +2639,7 @@ void ServerLobby::startSelection(const Event *event) back_lobby->setSynchronous(true); back_lobby->addUInt8(LE_BACK_LOBBY).addUInt8(BLR_SPECTATING_NEXT_GAME); STKHost::get()->sendPacketToAllPeersWith( - [always_spectate_peers](STKPeer* peer) + [always_spectate_peers](std::shared_ptr peer) { return always_spectate_peers.find(peer) != always_spectate_peers.end(); @@ -3070,7 +3070,7 @@ void ServerLobby::clientDisconnected(Event* event) // Don't show waiting peer disconnect message to in game player STKHost::get()->sendPacketToAllPeersWith([waiting_peer_disconnected] - (STKPeer* p) + (std::shared_ptr p) { if (!p->isValidated()) return false; @@ -3082,12 +3082,12 @@ void ServerLobby::clientDisconnected(Event* event) delete msg; #ifdef ENABLE_SQLITE3 - m_db_connector->writeDisconnectInfoTable(event->getPeer()); + m_db_connector->writeDisconnectInfoTable(event->getPeerSP()); #endif } // clientDisconnected //----------------------------------------------------------------------------- -void ServerLobby::kickPlayerWithReason(STKPeer* peer, const char* reason) const +void ServerLobby::kickPlayerWithReason(std::shared_ptr peer, const char* reason) const { NetworkString *message = getNetworkString(2); message->setSynchronous(true); @@ -3108,7 +3108,7 @@ void ServerLobby::saveIPBanTable(const SocketAddress& addr) } // saveIPBanTable //----------------------------------------------------------------------------- -bool ServerLobby::handleAssets(const NetworkString& ns, STKPeer* peer) +bool ServerLobby::handleAssets(const NetworkString& ns, std::shared_ptr peer) { std::set client_karts, client_tracks; const unsigned kart_num = ns.getUInt16(); @@ -3384,7 +3384,7 @@ void ServerLobby::connectionRequested(Event* event) caps.insert(cap); } event->getPeer()->setClientCapabilities(caps); - if (!handleAssets(data, event->getPeer())) + if (!handleAssets(data, event->getPeerSP())) return; unsigned player_count = data.getUInt8(); @@ -3394,16 +3394,16 @@ void ServerLobby::connectionRequested(Event* event) encrypted_size = data.getUInt32(); // Will be disconnected if banned by IP - testBannedForIP(peer.get()); + testBannedForIP(peer); if (peer->isDisconnected()) return; - testBannedForIPv6(peer.get()); + testBannedForIPv6(peer); if (peer->isDisconnected()) return; if (online_id != 0) - testBannedForOnlineId(peer.get(), online_id); + testBannedForOnlineId(peer, online_id); // Will be disconnected if banned by online id if (peer->isDisconnected()) return; @@ -3785,10 +3785,10 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, "using /replay 0 (to disable) or /replay 1 (to enable). "; sendStringToPeer(msg, peer); } - getMessagesFromHost(peer.get(), online_id); + getMessagesFromHost(peer, online_id); if (ServerConfig::m_soccer_tournament) - updateTournamentRole(peer.get()); + updateTournamentRole(peer); } // handleUnencryptedConnection //----------------------------------------------------------------------------- @@ -3877,7 +3877,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) profile_name = StringUtils::utf32ToWide({0x1F4F1}) + profile_name; // Add an hourglass emoji for players waiting because of the player limit - if (spectators_by_limit.find(profile->getPeer().get()) != spectators_by_limit.end()) + if (spectators_by_limit.find(profile->getPeer()) != spectators_by_limit.end()) profile_name = StringUtils::utf32ToWide({ 0x231B }) + profile_name; // Add a hammer emoji for angry host @@ -3933,7 +3933,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) // Don't send this message to in-game players STKHost::get()->sendPacketToAllPeersWith([game_started] - (STKPeer* p) + (std::shared_ptr p) { if (!p->isValidated()) return false; @@ -4011,7 +4011,7 @@ void ServerLobby::kartSelectionRequested(Event* event) return; const NetworkString& data = event->data(); - STKPeer* peer = event->getPeer(); + std::shared_ptr peer = event->getPeerSP(); setPlayerKarts(data, peer); } // kartSelectionRequested @@ -4036,7 +4036,7 @@ void ServerLobby::handlePlayerVote(Event* event) if (isVotingOver()) return; - if (!canVote(event->getPeer())) return; + if (!canVote(event->getPeerSP())) return; NetworkString& data = event->data(); PeerVote vote(data); @@ -4500,7 +4500,7 @@ void ServerLobby::resetServer() } // resetServer //----------------------------------------------------------------------------- -void ServerLobby::testBannedForIP(STKPeer* peer) const +void ServerLobby::testBannedForIP(std::shared_ptr peer) const { #ifdef ENABLE_SQLITE3 if (!m_db_connector->hasDatabase() || !m_db_connector->hasIpBanTable()) @@ -4535,7 +4535,7 @@ void ServerLobby::testBannedForIP(STKPeer* peer) const } // testBannedForIP //----------------------------------------------------------------------------- -void ServerLobby::getMessagesFromHost(STKPeer* peer, int online_id) +void ServerLobby::getMessagesFromHost(std::shared_ptr peer, int online_id) { #ifdef ENABLE_SQLITE3 std::vector messages = @@ -4553,7 +4553,7 @@ void ServerLobby::getMessagesFromHost(STKPeer* peer, int online_id) } // getMessagesFromHost //----------------------------------------------------------------------------- -void ServerLobby::testBannedForIPv6(STKPeer* peer) const +void ServerLobby::testBannedForIPv6(std::shared_ptr peer) const { #ifdef ENABLE_SQLITE3 if (!m_db_connector->hasDatabase() || !m_db_connector->hasIpv6BanTable()) @@ -4587,7 +4587,7 @@ void ServerLobby::testBannedForIPv6(STKPeer* peer) const } // testBannedForIPv6 //----------------------------------------------------------------------------- -void ServerLobby::testBannedForOnlineId(STKPeer* peer, +void ServerLobby::testBannedForOnlineId(std::shared_ptr peer, uint32_t online_id) const { #ifdef ENABLE_SQLITE3 @@ -4997,7 +4997,7 @@ void ServerLobby::addLiveJoinPlaceholder( } // addLiveJoinPlaceholder //----------------------------------------------------------------------------- -void ServerLobby::setPlayerKarts(const NetworkString& ns, STKPeer* peer) const +void ServerLobby::setPlayerKarts(const NetworkString& ns, std::shared_ptr peer) const { unsigned player_count = ns.getUInt8(); player_count = std::min(player_count, (unsigned)peer->getPlayerProfiles().size()); @@ -5047,7 +5047,7 @@ void ServerLobby::handleKartInfo(Event* event) if (!w) return; - STKPeer* peer = event->getPeer(); + std::shared_ptr peer = event->getPeerSP(); const NetworkString& data = event->data(); uint8_t kart_id = data.getUInt8(); if (kart_id > RaceManager::get()->getNumPlayers()) @@ -5217,7 +5217,7 @@ void ServerLobby::clientSelectingAssetsWantsToBackLobby(Event* event) } // clientSelectingAssetsWantsToBackLobby //----------------------------------------------------------------------------- -std::set& ServerLobby::getSpectatorsByLimit(bool update) +std::set>& ServerLobby::getSpectatorsByLimit(bool update) { if (!update) return m_spectators_by_limit; @@ -5287,7 +5287,7 @@ std::set& ServerLobby::getSpectatorsByLimit(bool update) ignore = true; else if (!canRace(peer)) { - m_spectators_by_limit.insert(peer.get()); + m_spectators_by_limit.insert(peer); ignore = true; } } @@ -5300,7 +5300,7 @@ std::set& ServerLobby::getSpectatorsByLimit(bool update) { player_count += (unsigned)peer->getPlayerProfiles().size(); if (player_count > player_limit) - m_spectators_by_limit.insert(peer.get()); + m_spectators_by_limit.insert(peer); } } return m_spectators_by_limit; @@ -5677,7 +5677,7 @@ void ServerLobby::resetToDefaultSettings() setConsentOnReplays(false); } // resetToDefaultSettings //----------------------------------------------------------------------------- -void ServerLobby::writeOwnReport(STKPeer* reporter, STKPeer* reporting, const std::string& info) +void ServerLobby::writeOwnReport(std::shared_ptr reporter, std::shared_ptr reporting, const std::string& info) { #ifdef ENABLE_SQLITE3 if (!m_db_connector->hasDatabase() || !m_db_connector->hasPlayerReportsTable()) @@ -5882,22 +5882,7 @@ void ServerLobby::changeColors() updatePlayerList(); } // changeColors //----------------------------------------------------------------------------- -void ServerLobby::sendStringToPeer(std::string& s, std::shared_ptr& peer) -{ - if (!peer) - { - sendStringToAllPeers(s); - return; - } - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16(StringUtils::utf8ToWide(s)); - peer->sendPacket(chat, PRM_RELIABLE); - delete chat; -} // sendStringToPeer -//----------------------------------------------------------------------------- -void ServerLobby::sendStringToPeer(std::string& s, STKPeer* peer) +void ServerLobby::sendStringToPeer(std::string& s, std::shared_ptr peer) { if (!peer) { @@ -5922,12 +5907,7 @@ void ServerLobby::sendStringToAllPeers(std::string& s) delete chat; } // sendStringToAllPeers //----------------------------------------------------------------------------- -bool ServerLobby::canRace(std::shared_ptr& peer) -{ - return canRace(peer.get()); -} // canRace -//----------------------------------------------------------------------------- -bool ServerLobby::canRace(STKPeer* peer) +bool ServerLobby::canRace(std::shared_ptr peer) { auto it = m_why_peer_cannot_play.find(peer); if (it != m_why_peer_cannot_play.end()) @@ -6033,12 +6013,7 @@ bool ServerLobby::canRace(STKPeer* peer) return true; } // canRace //----------------------------------------------------------------------------- -bool ServerLobby::canVote(std::shared_ptr& peer) const -{ - return canVote(peer.get()); -} // canVote -//----------------------------------------------------------------------------- -bool ServerLobby::canVote(STKPeer* peer) const +bool ServerLobby::canVote(std::shared_ptr peer) const { if (!peer || peer->getPlayerProfiles().empty()) return false; @@ -6057,16 +6032,11 @@ bool ServerLobby::canVote(STKPeer* peer) const return true; } // canVote //----------------------------------------------------------------------------- -bool ServerLobby::hasHostRights(std::shared_ptr& peer) const -{ - return hasHostRights(peer.get()); -} // hasHostRights -//----------------------------------------------------------------------------- -bool ServerLobby::hasHostRights(STKPeer* peer) const +bool ServerLobby::hasHostRights(std::shared_ptr peer) const { if (!peer || peer->getPlayerProfiles().empty()) return false; - if (peer == m_server_owner.lock().get()) + if (peer == m_server_owner.lock()) return true; if (peer->isAngryHost()) return true; @@ -6079,12 +6049,7 @@ bool ServerLobby::hasHostRights(STKPeer* peer) const return false; } // hasHostRights //----------------------------------------------------------------------------- -int ServerLobby::getPermissions(std::shared_ptr& peer) const -{ - return getPermissions(peer.get()); -} // getPermissions -//----------------------------------------------------------------------------- -int ServerLobby::getPermissions(STKPeer* peer) const +int ServerLobby::getPermissions(std::shared_ptr peer) const { int mask = 0; if (!peer) @@ -6100,7 +6065,7 @@ int ServerLobby::getPermissions(STKPeer* peer) const mask |= CommandPermissions::PE_USUAL; mask |= CommandPermissions::PE_VOTED_NORMAL; } - if (peer == m_server_owner.lock().get()) + if (peer == m_server_owner.lock()) { mask |= CommandPermissions::PE_CROWNED; if (ServerConfig::m_only_host_riding) @@ -6291,7 +6256,7 @@ void ServerLobby::loadPreservedSettings() m_preserve.insert(str); } // loadWhiteList //----------------------------------------------------------------------------- -bool ServerLobby::writeOnePlayerReport(STKPeer* reporter, +bool ServerLobby::writeOnePlayerReport(std::shared_ptr reporter, const std::string& table, const std::string& info) { #ifdef ENABLE_SQLITE3 @@ -6342,12 +6307,7 @@ void ServerLobby::initAvailableTracks() ServerConfig::m_play_requirement_tracks_string, ' ', false); } // initAvailableTracks //----------------------------------------------------------------------------- -std::vector ServerLobby::getMissingAssets(std::shared_ptr& peer) const -{ - return getMissingAssets(peer.get()); -} // getMissingAssets -//----------------------------------------------------------------------------- -std::vector ServerLobby::getMissingAssets(STKPeer* peer) const +std::vector ServerLobby::getMissingAssets(std::shared_ptr peer) const { std::vector ans; for (const std::string& required_track : m_play_requirement_tracks) @@ -6356,7 +6316,7 @@ std::vector ServerLobby::getMissingAssets(STKPeer* peer) const return ans; } // getMissingAssets //----------------------------------------------------------------------------- -void ServerLobby::updateTournamentRole(STKPeer* peer) +void ServerLobby::updateTournamentRole(std::shared_ptr peer) { if (!ServerConfig::m_soccer_tournament) return; @@ -6939,7 +6899,7 @@ bool ServerLobby::areKartFiltersIgnoringKarts() const return false; } // applyAllKartFilters //----------------------------------------------------------------------------- -std::string ServerLobby::getKartForBadKartChoice(STKPeer* peer, const std::string& username, const std::string& check_choice) const +std::string ServerLobby::getKartForBadKartChoice(std::shared_ptr peer, const std::string& username, const std::string& check_choice) const { std::set karts = (peer->isAIPeer() ? m_available_kts.first : peer->getClientAssets().first); applyAllKartFilters(username, karts, true); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 3c991eec8b6..67c0cf4d7f3 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -234,7 +234,7 @@ class ServerLobby : public LobbyProtocol // Calculated before each game started unsigned m_ai_count; - std::set m_spectators_by_limit; + std::set> m_spectators_by_limit; std::vector m_must_have_tracks; @@ -252,11 +252,11 @@ class ServerLobby : public LobbyProtocol irr::core::stringw m_help_message; - std::map> m_message_receivers; + std::map, std::set> m_message_receivers; - std::set m_team_speakers; + std::set> m_team_speakers; - std::map m_why_peer_cannot_play; + std::map, int> m_why_peer_cannot_play; KartElimination m_kart_elimination; @@ -486,11 +486,11 @@ class ServerLobby : public LobbyProtocol void encodePlayers(BareNetworkString* bns, std::vector >& players) const; std::vector > getLivePlayers() const; - void setPlayerKarts(const NetworkString& ns, STKPeer* peer) const; - bool handleAssets(const NetworkString& ns, STKPeer* peer); + void setPlayerKarts(const NetworkString& ns, std::shared_ptr peer) const; + bool handleAssets(const NetworkString& ns, std::shared_ptr peer); void handleServerCommand(Event* event, std::shared_ptr peer); void liveJoinRequest(Event* event); - void rejectLiveJoin(STKPeer* peer, BackLobbyReason blr); + void rejectLiveJoin(std::shared_ptr peer, BackLobbyReason blr); bool canLiveJoinNow() const; bool worldIsActive() const; int getReservedId(std::shared_ptr& p, @@ -498,26 +498,22 @@ class ServerLobby : public LobbyProtocol void handleKartInfo(Event* event); void clientInGameWantsToBackLobby(Event* event); void clientSelectingAssetsWantsToBackLobby(Event* event); - std::set& getSpectatorsByLimit(bool update = false); - void kickPlayerWithReason(STKPeer* peer, const char* reason) const; - void testBannedForIP(STKPeer* peer) const; - void testBannedForIPv6(STKPeer* peer) const; - void testBannedForOnlineId(STKPeer* peer, uint32_t online_id) const; - void getMessagesFromHost(STKPeer* peer, int online_id); + std::set>& getSpectatorsByLimit(bool update = false); + void kickPlayerWithReason(std::shared_ptr peer, const char* reason) const; + void testBannedForIP(std::shared_ptr peer) const; + void testBannedForIPv6(std::shared_ptr peer) const; + void testBannedForOnlineId(std::shared_ptr peer, uint32_t online_id) const; + void getMessagesFromHost(std::shared_ptr peer, int online_id); void writePlayerReport(Event* event); bool supportsAI(); void updateAddons(); void initCategories(); void initTournamentPlayers(); void changeColors(); - bool canRace(std::shared_ptr& peer); - bool canRace(STKPeer* peer); - bool canVote(std::shared_ptr& peer) const; - bool canVote(STKPeer* peer) const; - bool hasHostRights(std::shared_ptr& peer) const; - bool hasHostRights(STKPeer* peer) const; - std::vector getMissingAssets(std::shared_ptr& peer) const; - std::vector getMissingAssets(STKPeer* peer) const; + bool canRace(std::shared_ptr peer); + bool canVote(std::shared_ptr peer) const; + bool hasHostRights(std::shared_ptr peer) const; + std::vector getMissingAssets(std::shared_ptr peer) const; void loadTracksQueueFromConfig(); std::string getGrandPrixStandings(bool showIndividual = false, bool showTeam = true) const; bool loadCustomScoring(std::string& scoring); @@ -527,7 +523,7 @@ class ServerLobby : public LobbyProtocol void changeLimitForTournament(bool goal_target); bool tournamentGoalsLimit(int game) const; bool tournamentColorsSwapped(int game) const; - void updateTournamentRole(STKPeer* peer); + void updateTournamentRole(std::shared_ptr peer); CommandManager& getCommandManager(); // bool tournamentHasIcy(int game) const; @@ -575,17 +571,15 @@ class ServerLobby : public LobbyProtocol void initAvailableTracks(); void initAvailableModes(); void resetToDefaultSettings(); - void writeOwnReport(STKPeer* reporter, STKPeer* reporting, + void writeOwnReport(std::shared_ptr reporter, std::shared_ptr reporting, const std::string& info); - bool writeOnePlayerReport(STKPeer* reporter, const std::string& table, + bool writeOnePlayerReport(std::shared_ptr reporter, const std::string& table, const std::string& info); // int getTrackMaxPlayers(std::string& name) const; void updateGnuElimination(); - void sendStringToPeer(std::string& s, std::shared_ptr& peer); - void sendStringToPeer(std::string& s, STKPeer* peer); + void sendStringToPeer(std::string& s, std::shared_ptr peer); void sendStringToAllPeers(std::string& s); - int getPermissions(std::shared_ptr& peer) const; - int getPermissions(STKPeer* peer) const; + int getPermissions(std::shared_ptr peer) const; bool hasConsentOnReplays() const { return m_consent_on_replays; } void setConsentOnReplays(bool value) { m_consent_on_replays = value; } bool isSoccerGoalTarget() const; @@ -622,7 +616,7 @@ class ServerLobby : public LobbyProtocol void applyAllFilters(std::set& maps, bool use_history) const; void applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection = false) const; bool areKartFiltersIgnoringKarts() const; - std::string getKartForBadKartChoice(STKPeer* peer, const std::string& username, const std::string& check_choice) const; + std::string getKartForBadKartChoice(std::shared_ptr peer, const std::string& username, const std::string& check_choice) const; void setKartDataProperly(KartData& kart_data, const std::string& kart_name, std::shared_ptr player, const std::string& type) const; diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index ecccdc09211..9808b10deee 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -1370,14 +1370,14 @@ void STKHost::sendPacketToAllPeers(NetworkString *data, PacketReliabilityMode re * \param data Data to sent. * \param reliable If the data should be sent reliable or now. */ -void STKHost::sendPacketExcept(STKPeer* peer, NetworkString *data, +void STKHost::sendPacketExcept(std::shared_ptr peer, NetworkString *data, PacketReliabilityMode reliable) { std::lock_guard lock(m_peers_mutex); - for (auto p : m_peers) + for (const auto& p : m_peers) { STKPeer* stk_peer = p.second.get(); - if (!stk_peer->isSamePeer(peer) && p.second->isValidated() && + if (!stk_peer->isSamePeer(peer.get()) && p.second->isValidated() && !p.second->isWaitingForGame()) { stk_peer->sendPacket(data, reliable); @@ -1391,13 +1391,13 @@ void STKHost::sendPacketExcept(STKPeer* peer, NetworkString *data, * \param data Data to sent. * \param reliable If the data should be sent reliable or now. */ -void STKHost::sendPacketToAllPeersWith(std::function predicate, +void STKHost::sendPacketToAllPeersWith(std::function)> predicate, NetworkString* data, PacketReliabilityMode reliable) { std::lock_guard lock(m_peers_mutex); for (auto p : m_peers) { - STKPeer* stk_peer = p.second.get(); + std::shared_ptr stk_peer = p.second; if (!stk_peer->isValidated()) continue; if (predicate(stk_peer)) diff --git a/src/network/stk_host.hpp b/src/network/stk_host.hpp index f7395ad3449..8191568533c 100644 --- a/src/network/stk_host.hpp +++ b/src/network/stk_host.hpp @@ -249,7 +249,7 @@ class STKHost // ------------------------------------------------------------------------ void sendPacketToAllPeers(NetworkString *data, PacketReliabilityMode reliable = PRM_RELIABLE); // ------------------------------------------------------------------------ - void sendPacketToAllPeersWith(std::function predicate, + void sendPacketToAllPeersWith(std::function)> predicate, NetworkString* data, PacketReliabilityMode reliable = PRM_RELIABLE); // ------------------------------------------------------------------------ /** Returns true if this client instance is allowed to control the server. @@ -271,7 +271,7 @@ class STKHost std::shared_ptr findPeerByName(const core::stringw& name) const; std::shared_ptr findPeerByWildcard(const core::stringw& name_pattern, std::string &name_found) const; // ------------------------------------------------------------------------ - void sendPacketExcept(STKPeer* peer, NetworkString *data, + void sendPacketExcept(std::shared_ptr peer, NetworkString *data, PacketReliabilityMode reliable = PRM_RELIABLE); // ------------------------------------------------------------------------ void setupClient(int peer_count, int channel_limit, From db2e0d20c6eeefafb8b2c87f202669cdb7161f91 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 16 Feb 2025 14:47:32 +0400 Subject: [PATCH 571/830] Small fixes --- src/network/crypto_mbedtls.hpp | 1 + src/network/protocols/server_lobby.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/network/crypto_mbedtls.hpp b/src/network/crypto_mbedtls.hpp index 3be2136dad7..49429a40893 100644 --- a/src/network/crypto_mbedtls.hpp +++ b/src/network/crypto_mbedtls.hpp @@ -22,6 +22,7 @@ #define HEADER_CRYPTO_MBEDTLS_HPP #include "utils/log.hpp" +#include "utils/constants.hpp" #include #include diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index f7d103abc73..72e69349a62 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3044,6 +3044,7 @@ void ServerLobby::clientDisconnected(Event* event) World* w = World::getWorld(); std::shared_ptr peer = event->getPeerSP(); + m_message_receivers.erase(peer); // No warnings otherwise, as it could happen during lobby period if (w && m_game_info) saveDisconnectingPeerInfo(peer); From 1040a1ea557e12cca29ad123cf27a97717893d45 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 16 Feb 2025 23:58:46 +0400 Subject: [PATCH 572/830] Move the teamhit logic away from server lobby I would like items to not refer to server lobby too, but the structure of classes interaction was written by very nice people who didn't think I would ever need to pass one pointer from ServerLobby to Bowling, and so it's pretty difficult and it's not happening now. Very sad, because I just want to not include SL in many other files. --- src/items/bowling.cpp | 11 +- src/items/cake.cpp | 9 +- src/items/powerup.cpp | 3 +- src/items/swatter.cpp | 3 +- src/karts/explosion_animation.cpp | 5 +- src/network/protocols/command_manager.cpp | 13 +- src/network/protocols/server_lobby.cpp | 295 +------------------- src/network/protocols/server_lobby.hpp | 44 +-- src/utils/hit_processor.cpp | 312 ++++++++++++++++++++++ src/utils/hit_processor.hpp | 82 ++++++ 10 files changed, 436 insertions(+), 341 deletions(-) create mode 100644 src/utils/hit_processor.cpp create mode 100644 src/utils/hit_processor.hpp diff --git a/src/items/bowling.cpp b/src/items/bowling.cpp index 64ccbe047e9..9d7a1a926c8 100644 --- a/src/items/bowling.cpp +++ b/src/items/bowling.cpp @@ -24,10 +24,11 @@ #include "graphics/material.hpp" #include "io/xml_node.hpp" #include "karts/abstract_kart.hpp" -#include "modes/linear_world.hpp" +// #include "modes/linear_world.hpp" #include "network/protocols/server_lobby.hpp" +#include "utils/hit_processor.hpp" #include "utils/log.hpp" //TODO: remove after debugging is done float Bowling::m_st_max_distance; // maximum distance for a bowling ball to be attracted @@ -158,7 +159,7 @@ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) { auto sl = LobbyProtocol::get(); if (sl) - sl->setTeamMateHitOwner(getOwnerId(),m_ticks_since_thrown); + sl->getHitProcessor()->setTeamMateHitOwner(getOwnerId(),m_ticks_since_thrown); bool was_real_hit = Flyable::hit(kart, obj); if (was_real_hit) @@ -168,8 +169,8 @@ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) kart->decreaseShieldTime(); if (sl) { - sl->registerTeamMateHit(kart->getWorldKartId()); - sl->handleTeamMateHits(); + sl->getHitProcessor()->registerTeamMateHit(kart->getWorldKartId()); + sl->getHitProcessor()->handleTeamMateHits(); } return true; } @@ -180,7 +181,7 @@ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) } } if (sl) - sl->handleTeamMateHits(); + sl->getHitProcessor()->handleTeamMateHits(); return was_real_hit; } // hit diff --git a/src/items/cake.cpp b/src/items/cake.cpp index ba10bfb14d5..62fd2c425ce 100644 --- a/src/items/cake.cpp +++ b/src/items/cake.cpp @@ -24,6 +24,7 @@ #include "io/xml_node.hpp" #include "karts/abstract_kart.hpp" #include "utils/constants.hpp" +#include "utils/hit_processor.hpp" #include "utils/random_generator.hpp" #include "network/protocols/server_lobby.hpp" @@ -65,7 +66,7 @@ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj) { auto sl = LobbyProtocol::get(); if (sl) - sl->setTeamMateHitOwner(getOwnerId()); + sl->getHitProcessor()->setTeamMateHitOwner(getOwnerId()); bool was_real_hit = Flyable::hit(kart, obj); if (was_real_hit) @@ -75,8 +76,8 @@ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj) kart->decreaseShieldTime(); if (sl) { - sl->registerTeamMateHit(kart->getWorldKartId()); - sl->handleTeamMateHits(); + sl->getHitProcessor()->registerTeamMateHit(kart->getWorldKartId()); + sl->getHitProcessor()->handleTeamMateHits(); } return false; //Not sure if a shield hit is a real hit. } @@ -84,7 +85,7 @@ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj) } if (sl) - sl->handleTeamMateHits(); + sl->getHitProcessor()->handleTeamMateHits(); return was_real_hit; } // hit diff --git a/src/items/powerup.cpp b/src/items/powerup.cpp index d84fb834fb4..253fe2af95d 100644 --- a/src/items/powerup.cpp +++ b/src/items/powerup.cpp @@ -35,6 +35,7 @@ #include "network/rewind_manager.hpp" #include "physics/triangle_mesh.hpp" #include "tracks/track.hpp" +#include "utils/hit_processor.hpp" #include "utils/string_utils.hpp" #include "utils/log.hpp" //TODO: remove after debugging is done @@ -405,7 +406,7 @@ void Powerup::use() // check if we are in team gp and hit a teammate and should punish the attacker auto sl = LobbyProtocol::get(); if(sl && !kart->hasFinishedRace()) - sl->handleAnvilHit(m_kart->getWorldKartId(), kart->getWorldKartId()); + sl->getHitProcessor()->handleAnvilHit(m_kart->getWorldKartId(), kart->getWorldKartId()); kart->getAttachment()->set(Attachment::ATTACH_ANVIL, stk_config-> diff --git a/src/items/swatter.cpp b/src/items/swatter.cpp index 7aa8910f633..9f15af56d63 100644 --- a/src/items/swatter.cpp +++ b/src/items/swatter.cpp @@ -43,6 +43,7 @@ #include "network/network_string.hpp" #include "network/rewind_manager.hpp" #include "network/protocols/server_lobby.hpp" +#include "utils/hit_processor.hpp" #include #define SWAT_POS_OFFSET core::vector3df(0.0, 0.2f, -0.4f) @@ -412,7 +413,7 @@ void Swatter::squashThingsAround() // check if we are in team gp and hit a teammate and should punish attacker auto sl = LobbyProtocol::get(); if (sl && !m_closest_kart->hasFinishedRace()) - sl->handleSwatterHit(m_kart->getWorldKartId(), + sl->getHitProcessor()->handleSwatterHit(m_kart->getWorldKartId(), m_closest_kart->getWorldKartId(), success, m_has_hit_kart, World::getWorld()->getTicksSinceStart() - m_created_ticks); } diff --git a/src/karts/explosion_animation.cpp b/src/karts/explosion_animation.cpp index 320121b079c..513d38d8851 100644 --- a/src/karts/explosion_animation.cpp +++ b/src/karts/explosion_animation.cpp @@ -31,6 +31,7 @@ #include "network/protocols/server_lobby.hpp" #include "race/race_manager.hpp" #include "tracks/track.hpp" +#include "utils/hit_processor.hpp" #include "mini_glm.hpp" #include @@ -62,7 +63,7 @@ ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart, { kart->decreaseShieldTime(); if (sl) - sl->registerTeamMateHit(kart->getWorldKartId()); + sl->getHitProcessor()->registerTeamMateHit(kart->getWorldKartId()); return NULL; } @@ -75,7 +76,7 @@ ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart, } if (sl) - sl->registerTeamMateExplode(kart->getWorldKartId()); + sl->getHitProcessor()->registerTeamMateExplode(kart->getWorldKartId()); return new ExplosionAnimation(kart, direct_hit); } // create diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index db1ed49d3a0..c89dbdb1f1a 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -33,6 +33,7 @@ #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/file_utils.hpp" +#include "utils/hit_processor.hpp" #include "utils/hourglass_reason.hpp" #include "utils/log.hpp" #include "utils/random_generator.hpp" @@ -3148,7 +3149,7 @@ void CommandManager::process_hitmsg(Context& context) error(context, true); return; } - if (m_lobby->m_show_teammate_hits) + if (m_lobby->getHitProcessor()->m_show_teammate_hits) msg = "Teammate hits are sent to all players"; else msg = "Teammate hits are not sent"; @@ -3167,10 +3168,10 @@ void CommandManager::process_hitmsg_assign(Context& context) } if (argv[1] == "0") { - m_lobby->m_show_teammate_hits = false; + m_lobby->getHitProcessor()->m_show_teammate_hits = false; msg = "Teammate hits will not be sent"; } else { - m_lobby->m_show_teammate_hits = true; + m_lobby->getHitProcessor()->m_show_teammate_hits = true; msg = "Teammate hits will be sent to all players"; } m_lobby->sendStringToAllPeers(msg); @@ -3186,7 +3187,7 @@ void CommandManager::process_teamhit(Context& context) error(context, true); return; } - if (m_lobby->m_teammate_hit_mode) + if (m_lobby->getHitProcessor()->m_teammate_hit_mode) msg = "Teammate hits are punished"; else msg = "Teammate hits are not punished"; @@ -3205,12 +3206,12 @@ void CommandManager::process_teamhit_assign(Context& context) } if (argv[1] == "0") { - m_lobby->m_teammate_hit_mode = false; + m_lobby->getHitProcessor()->m_teammate_hit_mode = false; msg = "Teammate hits are not punished now"; } else { - m_lobby->m_teammate_hit_mode = true; + m_lobby->getHitProcessor()->m_teammate_hit_mode = true; msg = "Teammate hits are punished now"; } m_lobby->sendStringToAllPeers(msg); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 72e69349a62..ae2e73ac5fe 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -58,6 +58,7 @@ #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/game_info.hpp" +#include "utils/hit_processor.hpp" // #include "utils/log.hpp" // #include "utils/random_generator.hpp" // #include "utils/string_utils.hpp" @@ -169,11 +170,9 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_troll_active = ServerConfig::m_troll_active; - m_show_teammate_hits = ServerConfig::m_show_teammate_hits; - m_teammate_hit_mode = ServerConfig::m_teammate_hit_mode; - m_last_teammate_hit_msg = 0; - m_teammate_swatter_punish.clear(); - m_collecting_teammate_hit_info = false; + m_hit_processor = std::make_shared(this); + // feb16 remove this + m_available_teams = ServerConfig::m_init_available_teams; m_map_vote_handler.setAlgorithm(ServerConfig::m_map_vote_handling); @@ -432,7 +431,7 @@ void ServerLobby::setup() m_winner_peer_id = 0; m_client_starting_time = 0; m_ai_count = 0; - m_collecting_teammate_hit_info = false; + getHitProcessor()->m_collecting_teammate_hit_info = false; auto players = STKHost::get()->getPlayersForNewGame(); if (m_game_setup->isGrandPrix() && !m_game_setup->isGrandPrixStarted()) { @@ -1164,7 +1163,7 @@ void ServerLobby::asynchronousUpdate() // reset // maybe this is not the best place for this? - m_last_teammate_hit_msg = 0; + getHitProcessor()->m_last_teammate_hit_msg = 0; if (m_end_voting_period.load() == 0) return; @@ -1911,9 +1910,9 @@ void ServerLobby::update(int ticks) // check warn level for each player switch(lin_world->getWarnLevel(i)) { - case 0: // fine + case 0: break; - case 1: // print WARNING + case 1: { std::string msg = ServerConfig::m_troll_warn_msg; sendStringToPeer(msg, peer); @@ -1921,7 +1920,7 @@ void ServerLobby::update(int ticks) Log::info("ServerLobby-AntiTroll", "Sent WARNING to %s", player_name.c_str()); break; } - default: // kick !! + default: { std::string player_name = StringUtils::wideToUtf8(peer->getPlayerProfiles()[0]->getName()); Log::info("ServerLobby-AntiTroll", "KICKING %s", player_name.c_str()); @@ -1931,16 +1930,16 @@ void ServerLobby::update(int ticks) } } } - if (m_teammate_swatter_punish.size() > 0) + if (getHitProcessor()->m_teammate_swatter_punish.size() > 0) { // punish players who swattered teammates - for (auto& kart : m_teammate_swatter_punish) + for (auto& kart : getHitProcessor()->m_teammate_swatter_punish) { kart->getAttachment()->set(Attachment::ATTACH_ANVIL, stk_config->time2Ticks(kart->getKartProperties()->getAnvilDuration())); kart->adjustSpeed(kart->getKartProperties()->getAnvilSpeedFactor()); } - m_teammate_swatter_punish.clear(); + getHitProcessor()->m_teammate_swatter_punish.clear(); } } } @@ -6460,276 +6459,6 @@ std::string ServerLobby::getToken() //----------------------------------------------------------------------------- #endif // ENABLE_WEB_SUPPORT -// this is called when collisions of an item are handled -// so we keep track of hits caused by that item -void ServerLobby::setTeamMateHitOwner(unsigned int ownerID, uint16_t ticks_since_thrown) -{ - m_teammate_current_item_ownerID = ownerID; - m_teammate_ticks_since_thrown = ticks_since_thrown; - m_teammate_karts_hit.clear(); - m_teammate_karts_exploded.clear(); - m_collecting_teammate_hit_info = true; -} // setTeamMateHitOwner -//----------------------------------------------------------------------------- - -void ServerLobby::registerTeamMateHit(unsigned int kartID) -{ - // only register if we know the item owner and victim is still racing - if (m_collecting_teammate_hit_info && !World::getWorld()->getKart(kartID)->hasFinishedRace()) - m_teammate_karts_hit.push_back(kartID); -} // registerTeamMateHit -//----------------------------------------------------------------------------- - -void ServerLobby::registerTeamMateExplode(unsigned int kartID) -{ - // only register if we know the item owner and victim is still racing - if (m_collecting_teammate_hit_info && !World::getWorld()->getKart(kartID)->hasFinishedRace()) - m_teammate_karts_exploded.push_back(kartID); -} // registerTeamMateExplode -//----------------------------------------------------------------------------- - -void ServerLobby::sendTeamMateHitMsg(std::string& s) -{ - if (World* w = World::getWorld()) - { - int ticks = w->getTicksSinceStart(); - if (ticks - m_last_teammate_hit_msg > stk_config->time2Ticks(1.5f)) - { - m_last_teammate_hit_msg = ticks; - sendStringToAllPeers(s); - } - } -} // sendTeamMateHitMsg -//----------------------------------------------------------------------------- - -void ServerLobby::handleTeamMateHits() -{ - m_collecting_teammate_hit_info = false; - // get team of owner of item - const std::string ownername = StringUtils::wideToUtf8( - RaceManager::get()->getKartInfo(m_teammate_current_item_ownerID).getPlayerName()); - const int ownerTeam = m_team_for_player[ownername]; - - if (ownerTeam == 0) // no team, no punishment - return; - - AbstractKart *owner = World::getWorld()->getKart(m_teammate_current_item_ownerID); - - // if item is too old, it doesn't count - // currently only bowling balls have their creation time registered - // so cakes will always count - - if (m_teammate_ticks_since_thrown > stk_config->time2Ticks(MAX_BOWL_TEAMMATE_HIT_TIME)) - return; - - // Show message? - if (showTeamMateHits()) - { - // prepare string - int num_victims = 0; - std::string msg = ServerConfig::m_teammate_hit_msg_prefix; - std::string victims; - msg += ownername; - msg += " just shot "; - - for (unsigned int i = 0; i < m_teammate_karts_exploded.size(); i++) - { - const std::string playername = StringUtils::wideToUtf8( - RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); - const int playerTeam = m_team_for_player[playername]; - if (ownerTeam == playerTeam) - { - // hit teammate - if (num_victims > 0) - victims += " and "; - victims += StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); - num_victims++; - } - } - if (num_victims > 0) // we found victims, so send message - { - msg += (num_victims > 1) ? "teammates " : "teammate "; - msg += victims; - sendTeamMateHitMsg(msg); - } - } - - if (useTeamMateHitMode()) - { - bool punished = false; - // first check if we exploded at least one teammate - for (unsigned int i=0; i < m_teammate_karts_exploded.size() && !punished; i++) - { - const std::string playername = StringUtils::wideToUtf8( - RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); - const int playerTeam = m_team_for_player[playername]; - if (ownerTeam == playerTeam) - { - // we did, so punish - punished = true; - if(owner->getAttachment()->getType() == Attachment::ATTACH_BOMB) - { - // make bomb explode - owner->getAttachment()->update(10000); - } - else if (owner->isShielded()) - { - // if owner is shielded, take away shield - owner->decreaseShieldTime(); - } - else - { - int left_over_ticks = 0; - // if owner already has an anvil or a parachute, make new anvil last longer - if (owner->getAttachment()->getType() == Attachment::ATTACH_ANVIL - || owner->getAttachment()->getType() == Attachment::ATTACH_PARACHUTE) - { - left_over_ticks = owner->getAttachment()->getTicksLeft(); - } - owner->getAttachment()->set(Attachment::ATTACH_ANVIL, - stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) + left_over_ticks); - owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor()); - } - } - } - - // now check for deshielding teammates - for (unsigned int i = 0; i < m_teammate_karts_hit.size() && !punished; i++) - { - const std::string playername = StringUtils::wideToUtf8( - RaceManager::get()->getKartInfo(m_teammate_karts_hit[i]).getPlayerName()); - const int playerTeam = m_team_for_player[playername]; - if (ownerTeam == playerTeam) - { - // we did, so punish - punished = true; - if (owner->getAttachment()->getType() == Attachment::ATTACH_BOMB) - { - // make bomb explode - owner->getAttachment()->update(10000); - } - else if (owner->isShielded()) - { - // if owner is shielded, take away shield - owner->decreaseShieldTime(); - } - else - { - // since teammate didn't explode, make anvil less severe - int left_over_ticks = 0; - // if owner already has an anvil or a parachute, make new anvil last longer - if (owner->getAttachment()->getType() == Attachment::ATTACH_ANVIL - || owner->getAttachment()->getType() == Attachment::ATTACH_PARACHUTE) - { - left_over_ticks = owner->getAttachment()->getTicksLeft(); - } - owner->getAttachment()->set(Attachment::ATTACH_ANVIL, - stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) / 2 + left_over_ticks); - owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor() * 2.0f); - } - } - } - } -} // handleTeamMateHits -//----------------------------------------------------------------------------- - -void ServerLobby::handleSwatterHit(unsigned int ownerID, unsigned int victimID, - bool success, bool has_hit_kart, uint16_t ticks_active) -{ - const std::string ownername = StringUtils::wideToUtf8( - RaceManager::get()->getKartInfo(ownerID).getPlayerName()); - const int ownerTeam = m_team_for_player[ownername]; - if (ownerTeam == 0) - return; - - const std::string victimname = StringUtils::wideToUtf8( - RaceManager::get()->getKartInfo(victimID).getPlayerName()); - const int victimTeam = m_team_for_player[victimname]; - if (victimTeam != ownerTeam) - return; - - // should we tell the world? - if (showTeamMateHits() && success) - { - std::string msg = ServerConfig::m_teammate_hit_msg_prefix; - msg += ownername; - msg += " just swattered teammate "; - msg += victimname; - sendTeamMateHitMsg(msg); - } - if (useTeamMateHitMode()) - { - // remove swatter - AbstractKart *owner = World::getWorld()->getKart(ownerID); - owner->getAttachment()->setTicksLeft(0); - // if this is the first kart hit and the swatter is in use for less than 3s - // the attacker also gets an anvil - if (!has_hit_kart && ticks_active < stk_config->time2Ticks(3.0f) && success) - // we cannot do this here, will be done in update() - m_teammate_swatter_punish.push_back(owner); - } -} // handleSwatterHit -//----------------------------------------------------------------------------- - -void ServerLobby::handleAnvilHit(unsigned int ownerID, unsigned int victimID) -{ - const std::string ownername = StringUtils::wideToUtf8( - RaceManager::get()->getKartInfo(ownerID).getPlayerName()); - const int ownerTeam = m_team_for_player[ownername]; - if (ownerTeam == 0) - return; - - const std::string victimname = StringUtils::wideToUtf8( - RaceManager::get()->getKartInfo(victimID).getPlayerName()); - const int victimTeam = m_team_for_player[victimname]; - if (victimTeam != ownerTeam) - return; - - AbstractKart *owner = World::getWorld()->getKart(ownerID); - - // should we tell the world? - if (showTeamMateHits()) - { - std::string msg = ServerConfig::m_teammate_hit_msg_prefix; - msg += ownername; - msg += " just gave an anchor to teammate "; - msg += victimname; - sendTeamMateHitMsg(msg); - } - if (useTeamMateHitMode()) - { - if (owner->getAttachment()->getType() == Attachment::ATTACH_BOMB) - { - // make bomb explode - owner->getAttachment()->update(10000); - } - else - { - if (owner->isShielded()) - { - // if owner is shielded, take away shield - // since the anvil will also destroy the shield of the victim - // we also punish this severely - owner->decreaseShieldTime(); - } - - // now give anvil to owner - int left_over_ticks = 0; - // if owner already has an anvil or a parachute, make new anvil last longer - if (owner->getAttachment()->getType() == Attachment::ATTACH_ANVIL - || owner->getAttachment()->getType() == Attachment::ATTACH_PARACHUTE) - { - left_over_ticks = owner->getAttachment()->getTicksLeft(); - } - owner->getAttachment()->set(Attachment::ATTACH_ANVIL, - stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) + left_over_ticks); - // the powerup anvil is very strong, copy these values (from powerup.cpp) - owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor() * 0.5f); - } - } -} // handleAnvilHit -//----------------------------------------------------------------------------- - bool ServerLobby::isSoccerGoalTarget() const { return m_game_setup->isSoccerGoalTarget(); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 67c0cf4d7f3..9718ae5f280 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -52,6 +52,7 @@ class STKPeer; class SocketAddress; enum AlwaysSpectateMode: uint8_t; class Ranking; +class HitProcessor; namespace Online { @@ -195,6 +196,8 @@ class ServerLobby : public LobbyProtocol std::shared_ptr m_ranking; + std::shared_ptr m_hit_processor; + /* Saved the last game result */ NetworkString* m_result_ns; @@ -365,31 +368,6 @@ class ServerLobby : public LobbyProtocol // config for troll system bool m_troll_active; - // teammate hits - // show messages about team hits? - bool m_show_teammate_hits; - // give anvils to attackers? - bool m_teammate_hit_mode; - // time index of last team mate hit - // make sure not to send too many of them - int m_last_teammate_hit_msg; - // we have to keep track of the karts affected by a hit - // we store IDs, because we need to find the team by name (by ID) - // m_collecting_teammate_hit_info is set to true if we are processing a - // cake or bowl hit, so we make sure we never fill the vectors with - // unneeded data. - bool m_collecting_teammate_hit_info; - unsigned int m_teammate_current_item_ownerID; - uint16_t m_teammate_ticks_since_thrown; - std::vector m_teammate_karts_hit; - std::vector m_teammate_karts_exploded; - // store karts to punish for swattering a teammate - std::vector m_teammate_swatter_punish; - - // after a certain time a bowl can be avoided and doesn't - // trigger teammate hits anymore - const float MAX_BOWL_TEAMMATE_HIT_TIME = 2.0f; - friend CommandManager; CommandManager m_command_manager; @@ -589,20 +567,6 @@ class ServerLobby : public LobbyProtocol std::string& direction, int laps); #endif - // handle cakes and bowls - void setTeamMateHitOwner(unsigned int ownerID, uint16_t ticks_since_thrown = 0); - void registerTeamMateHit(unsigned int kartID); - void registerTeamMateExplode(unsigned int kartID); - void handleTeamMateHits(); - - // handle swatters - void handleSwatterHit(unsigned int ownerID, unsigned int victimID, bool success, bool has_hit_kart, uint16_t ticks_active); - // handle anvil - void handleAnvilHit(unsigned int ownerID, unsigned int victimID); - - void sendTeamMateHitMsg(std::string& s); - bool showTeamMateHits() const { return m_show_teammate_hits; } - bool useTeamMateHitMode() const { return m_teammate_hit_mode; } bool isDifficultyAvailable(int difficulty) const { return m_available_difficulties.count(difficulty) > 0; } bool isModeAvailable(int mode) const @@ -637,6 +601,8 @@ class ServerLobby : public LobbyProtocol void setTemporaryTeamInLobby(std::shared_ptr profile, int team); void checkNoTeamSpectator(std::shared_ptr peer); void setSpectateModeProperly(std::shared_ptr peer, AlwaysSpectateMode mode); + int getTeamForUsername(const std::string& name) { return m_team_for_player[name]; } + std::shared_ptr getHitProcessor() const { return m_hit_processor; } }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/utils/hit_processor.cpp b/src/utils/hit_processor.cpp new file mode 100644 index 00000000000..5b69f987072 --- /dev/null +++ b/src/utils/hit_processor.cpp @@ -0,0 +1,312 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2024 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/hit_processor.hpp" +#include "network/server_config.hpp" +#include "karts/abstract_kart.hpp" +#include "modes/world.hpp" +#include "items/attachment.hpp" +#include "utils/string_utils.hpp" +#include "karts/kart_properties.hpp" +#include "network/protocols/server_lobby.hpp" + + +HitProcessor::HitProcessor(ServerLobby* lobby): m_lobby(lobby) +{ + m_show_teammate_hits = ServerConfig::m_show_teammate_hits; + m_teammate_hit_mode = ServerConfig::m_teammate_hit_mode; + m_last_teammate_hit_msg = 0; + m_teammate_swatter_punish.clear(); + m_collecting_teammate_hit_info = false; +} // HitProcessor +// ======================================================================== + + +// this is called when collisions of an item are handled +// so we keep track of hits caused by that item +void HitProcessor::setTeamMateHitOwner(unsigned int ownerID, uint16_t ticks_since_thrown) +{ + m_teammate_current_item_ownerID = ownerID; + m_teammate_ticks_since_thrown = ticks_since_thrown; + m_teammate_karts_hit.clear(); + m_teammate_karts_exploded.clear(); + m_collecting_teammate_hit_info = true; +} // setTeamMateHitOwner +//----------------------------------------------------------------------------- + +void HitProcessor::registerTeamMateHit(unsigned int kartID) +{ + // only register if we know the item owner and victim is still racing + if (m_collecting_teammate_hit_info && !World::getWorld()->getKart(kartID)->hasFinishedRace()) + m_teammate_karts_hit.push_back(kartID); +} // registerTeamMateHit +//----------------------------------------------------------------------------- + +void HitProcessor::registerTeamMateExplode(unsigned int kartID) +{ + // only register if we know the item owner and victim is still racing + if (m_collecting_teammate_hit_info && !World::getWorld()->getKart(kartID)->hasFinishedRace()) + m_teammate_karts_exploded.push_back(kartID); +} // registerTeamMateExplode +//----------------------------------------------------------------------------- + +void HitProcessor::sendTeamMateHitMsg(std::string& s) +{ + if (World* w = World::getWorld()) + { + int ticks = w->getTicksSinceStart(); + if (ticks - m_last_teammate_hit_msg > stk_config->time2Ticks(1.5f)) + { + m_last_teammate_hit_msg = ticks; + m_lobby->sendStringToAllPeers(s); + } + } +} // sendTeamMateHitMsg +//----------------------------------------------------------------------------- + +void HitProcessor::handleTeamMateHits() +{ + m_collecting_teammate_hit_info = false; + // get team of owner of item + const std::string owner_name = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(m_teammate_current_item_ownerID).getPlayerName()); + const int owner_team = m_lobby->getTeamForUsername(owner_name); + + if (owner_team == 0) // no team, no punishment + return; + + AbstractKart *owner = World::getWorld()->getKart(m_teammate_current_item_ownerID); + + // if item is too old, it doesn't count + // currently only bowling balls have their creation time registered + // so cakes will always count + + if (m_teammate_ticks_since_thrown > stk_config->time2Ticks(MAX_BOWL_TEAMMATE_HIT_TIME)) + return; + + // Show message? + if (showTeamMateHits()) + { + // prepare string + int num_victims = 0; + std::string msg = ServerConfig::m_teammate_hit_msg_prefix; + std::string victims; + msg += owner_name; + msg += " just shot "; + + for (unsigned int i = 0; i < m_teammate_karts_exploded.size(); i++) + { + const std::string playername = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); + const int playerTeam = m_lobby->getTeamForUsername(playername); + if (owner_team == playerTeam) + { + // hit teammate + if (num_victims > 0) + victims += " and "; + victims += StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); + num_victims++; + } + } + if (num_victims > 0) // we found victims, so send message + { + msg += (num_victims > 1) ? "teammates " : "teammate "; + msg += victims; + sendTeamMateHitMsg(msg); + } + } + + if (useTeamMateHitMode()) + { + bool punished = false; + // first check if we exploded at least one teammate + for (unsigned int i = 0; i < m_teammate_karts_exploded.size() && !punished; i++) + { + const std::string playername = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); + const int playerTeam = m_lobby->getTeamForUsername(playername); + if (owner_team == playerTeam) + { + // we did, so punish + punished = true; + if(owner->getAttachment()->getType() == Attachment::ATTACH_BOMB) + { + // make bomb explode + owner->getAttachment()->update(10000); + } + else if (owner->isShielded()) + { + // if owner is shielded, take away shield + owner->decreaseShieldTime(); + } + else + { + int left_over_ticks = 0; + // if owner already has an anvil or a parachute, make new anvil last longer + if (owner->getAttachment()->getType() == Attachment::ATTACH_ANVIL + || owner->getAttachment()->getType() == Attachment::ATTACH_PARACHUTE) + { + left_over_ticks = owner->getAttachment()->getTicksLeft(); + } + owner->getAttachment()->set(Attachment::ATTACH_ANVIL, + stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) + left_over_ticks); + owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor()); + } + } + } + + // now check for deshielding teammates + for (unsigned int i = 0; i < m_teammate_karts_hit.size() && !punished; i++) + { + const std::string playername = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(m_teammate_karts_hit[i]).getPlayerName()); + const int playerTeam = m_lobby->getTeamForUsername(playername); + if (owner_team == playerTeam) + { + // we did, so punish + punished = true; + if (owner->getAttachment()->getType() == Attachment::ATTACH_BOMB) + { + // make bomb explode + owner->getAttachment()->update(10000); + } + else if (owner->isShielded()) + { + // if owner is shielded, take away shield + owner->decreaseShieldTime(); + } + else + { + // since teammate didn't explode, make anvil less severe + int left_over_ticks = 0; + // if owner already has an anvil or a parachute, make new anvil last longer + if (owner->getAttachment()->getType() == Attachment::ATTACH_ANVIL + || owner->getAttachment()->getType() == Attachment::ATTACH_PARACHUTE) + { + left_over_ticks = owner->getAttachment()->getTicksLeft(); + } + owner->getAttachment()->set(Attachment::ATTACH_ANVIL, + stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) / 2 + left_over_ticks); + owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor() * 2.0f); + } + } + } + } +} // handleTeamMateHits +//----------------------------------------------------------------------------- + +void HitProcessor::handleSwatterHit(unsigned int ownerID, unsigned int victimID, + bool success, bool has_hit_kart, uint16_t ticks_active) +{ + const std::string owner_name = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(ownerID).getPlayerName()); + const int owner_team = m_lobby->getTeamForUsername(owner_name); + if (owner_team == 0) + return; + + const std::string victim_name = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(victimID).getPlayerName()); + const int victim_team = m_lobby->getTeamForUsername(victim_name); + if (victim_team != owner_team) + return; + + // should we tell the world? + if (showTeamMateHits() && success) + { + std::string msg = StringUtils::insertValues( + "%s%s just swattered teammate %s", + std::string(ServerConfig::m_teammate_hit_msg_prefix).c_str(), + owner_name.c_str(), + victim_name.c_str() + ); + sendTeamMateHitMsg(msg); + } + if (useTeamMateHitMode()) + { + // remove swatter + AbstractKart *owner = World::getWorld()->getKart(ownerID); + owner->getAttachment()->setTicksLeft(0); + // if this is the first kart hit and the swatter is in use for less than 3s + // the attacker also gets an anvil + if (!has_hit_kart && ticks_active < stk_config->time2Ticks(3.0f) && success) + // we cannot do this here, will be done in update() + m_teammate_swatter_punish.push_back(owner); + } +} // handleSwatterHit +//----------------------------------------------------------------------------- + +void HitProcessor::handleAnvilHit(unsigned int ownerID, unsigned int victimID) +{ + const std::string owner_name = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(ownerID).getPlayerName()); + const int owner_team = m_lobby->getTeamForUsername(owner_name); + if (owner_team == 0) + return; + + const std::string victim_name = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(victimID).getPlayerName()); + const int victim_team = m_lobby->getTeamForUsername(victim_name); + if (victim_team != owner_team) + return; + + AbstractKart *owner = World::getWorld()->getKart(ownerID); + + // should we tell the world? + if (showTeamMateHits()) + { + std::string msg = StringUtils::insertValues( + "%s%s just gave an anchor to teammate %s", + std::string(ServerConfig::m_teammate_hit_msg_prefix).c_str(), + owner_name.c_str(), + victim_name.c_str() + ); + sendTeamMateHitMsg(msg); + } + if (useTeamMateHitMode()) + { + if (owner->getAttachment()->getType() == Attachment::ATTACH_BOMB) + { + // make bomb explode + owner->getAttachment()->update(10000); + } + else + { + if (owner->isShielded()) + { + // if owner is shielded, take away shield + // since the anvil will also destroy the shield of the victim + // we also punish this severely + owner->decreaseShieldTime(); + } + + // now give anvil to owner + int left_over_ticks = 0; + // if owner already has an anvil or a parachute, make new anvil last longer + if (owner->getAttachment()->getType() == Attachment::ATTACH_ANVIL + || owner->getAttachment()->getType() == Attachment::ATTACH_PARACHUTE) + { + left_over_ticks = owner->getAttachment()->getTicksLeft(); + } + owner->getAttachment()->set(Attachment::ATTACH_ANVIL, + stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) + left_over_ticks); + // the powerup anvil is very strong, copy these values (from powerup.cpp) + owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor() * 0.5f); + } + } +} // handleAnvilHit +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/hit_processor.hpp b/src/utils/hit_processor.hpp new file mode 100644 index 00000000000..61486f858f8 --- /dev/null +++ b/src/utils/hit_processor.hpp @@ -0,0 +1,82 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HIT_PROCESSOR_HPP +#define HIT_PROCESSOR_HPP + +#include "utils/types.hpp" + +#include +#include +class AbstractKart; +class ServerLobby; + +// A class that incapsulates most of the logic for processing kart hits. +// Contains the code originally written by Heuchi1, but it's moved to a +// separate file to not include ServerLobby from item source files. + +class HitProcessor +{ +public: + HitProcessor(ServerLobby* lobby); + +public: // feb16 remove todo revert to private + // feb16 remove + ServerLobby* m_lobby = nullptr; + + bool m_show_teammate_hits; // Whether to show messages about team hits. + bool m_teammate_hit_mode; // Whether to anvil the team hitters. + // time index of last team mate hit + // make sure not to send too many of them + int m_last_teammate_hit_msg; + // we have to keep track of the karts affected by a hit + // we store IDs, because we need to find the team by name (by ID) + // m_collecting_teammate_hit_info is set to true if we are processing a + // cake or bowl hit, so we make sure we never fill the vectors with + // unneeded data. + bool m_collecting_teammate_hit_info; + unsigned int m_teammate_current_item_ownerID; + uint16_t m_teammate_ticks_since_thrown; + std::vector m_teammate_karts_hit; + std::vector m_teammate_karts_exploded; + + std::vector m_teammate_swatter_punish; // store karts to punish for swattering a teammate + + // after a certain time a bowl can be avoided and doesn't + // trigger teammate hits anymore + const float MAX_BOWL_TEAMMATE_HIT_TIME = 2.0f; + +public: + // handle cakes and bowls + void setTeamMateHitOwner(unsigned int ownerID, uint16_t ticks_since_thrown = 0); + void registerTeamMateHit(unsigned int kartID); + void registerTeamMateExplode(unsigned int kartID); + void handleTeamMateHits(); + + // handle swatters + void handleSwatterHit(unsigned int ownerID, unsigned int victimID, bool success, bool has_hit_kart, uint16_t ticks_active); + // handle anvil + void handleAnvilHit(unsigned int ownerID, unsigned int victimID); + + void sendTeamMateHitMsg(std::string& s); + bool showTeamMateHits() const { return m_show_teammate_hits; } + bool useTeamMateHitMode() const { return m_teammate_hit_mode; } +}; + + +#endif // HIT_PROCESSOR_HPP From d4ca128efbf6038b670695193f1da5b55e9e3ccf Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 23 Feb 2025 01:05:22 +0400 Subject: [PATCH 573/830] Old slight cleanups --- src/network/protocols/command_manager.cpp | 12 +++--- src/network/protocols/server_lobby.cpp | 46 +++-------------------- src/utils/hit_processor.cpp | 31 ++++++++++++--- src/utils/hit_processor.hpp | 11 ++++-- 4 files changed, 44 insertions(+), 56 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index c89dbdb1f1a..8db2702b2f3 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -3149,7 +3149,7 @@ void CommandManager::process_hitmsg(Context& context) error(context, true); return; } - if (m_lobby->getHitProcessor()->m_show_teammate_hits) + if (m_lobby->getHitProcessor()->showTeammateHits()) msg = "Teammate hits are sent to all players"; else msg = "Teammate hits are not sent"; @@ -3168,10 +3168,10 @@ void CommandManager::process_hitmsg_assign(Context& context) } if (argv[1] == "0") { - m_lobby->getHitProcessor()->m_show_teammate_hits = false; + m_lobby->getHitProcessor()->setShowTeammateHits(false); msg = "Teammate hits will not be sent"; } else { - m_lobby->getHitProcessor()->m_show_teammate_hits = true; + m_lobby->getHitProcessor()->setShowTeammateHits(true); msg = "Teammate hits will be sent to all players"; } m_lobby->sendStringToAllPeers(msg); @@ -3187,7 +3187,7 @@ void CommandManager::process_teamhit(Context& context) error(context, true); return; } - if (m_lobby->getHitProcessor()->m_teammate_hit_mode) + if (m_lobby->getHitProcessor()->isTeammateHitMode()) msg = "Teammate hits are punished"; else msg = "Teammate hits are not punished"; @@ -3206,12 +3206,12 @@ void CommandManager::process_teamhit_assign(Context& context) } if (argv[1] == "0") { - m_lobby->getHitProcessor()->m_teammate_hit_mode = false; + m_lobby->getHitProcessor()->setTeammateHitMode(false); msg = "Teammate hits are not punished now"; } else { - m_lobby->getHitProcessor()->m_teammate_hit_mode = true; + m_lobby->getHitProcessor()->setTeammateHitMode(true); msg = "Teammate hits are punished now"; } m_lobby->sendStringToAllPeers(msg); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index ae2e73ac5fe..077fe942081 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -18,12 +18,8 @@ #include "network/protocols/server_lobby.hpp" -// #include "addons/addon.hpp" -// #include "config/user_config.hpp" #include "items/network_item_manager.hpp" -// #include "items/powerup_manager.hpp" #include "items/attachment.hpp" -// #include "karts/controller/player_controller.hpp" #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" #include "karts/official_karts.hpp" @@ -34,35 +30,25 @@ #include "network/database_connector.hpp" #include "network/event.hpp" #include "network/game_setup.hpp" -// #include "network/network.hpp" #include "network/network_config.hpp" #include "network/network_player_profile.hpp" -// #include "network/peer_vote.hpp" #include "network/protocol_manager.hpp" #include "network/protocols/connect_to_peer.hpp" -// #include "network/protocols/command_permissions.hpp" #include "network/protocols/game_protocol.hpp" #include "network/protocols/game_events_protocol.hpp" #include "network/protocols/ranking.hpp" #include "network/race_event_manager.hpp" #include "network/server_config.hpp" -// #include "network/socket_address.hpp" #include "network/stk_host.hpp" #include "network/stk_ipv6.hpp" #include "network/stk_peer.hpp" -// #include "online/online_profile.hpp" #include "online/request_manager.hpp" #include "online/xml_request.hpp" -// #include "race/race_manager.hpp" #include "tracks/check_manager.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/game_info.hpp" #include "utils/hit_processor.hpp" -// #include "utils/log.hpp" -// #include "utils/random_generator.hpp" -// #include "utils/string_utils.hpp" -// #include "utils/time.hpp" #include "utils/translation.hpp" #include @@ -171,7 +157,6 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_troll_active = ServerConfig::m_troll_active; m_hit_processor = std::make_shared(this); - // feb16 remove this m_available_teams = ServerConfig::m_init_available_teams; @@ -431,7 +416,6 @@ void ServerLobby::setup() m_winner_peer_id = 0; m_client_starting_time = 0; m_ai_count = 0; - getHitProcessor()->m_collecting_teammate_hit_info = false; auto players = STKHost::get()->getPlayersForNewGame(); if (m_game_setup->isGrandPrix() && !m_game_setup->isGrandPrixStarted()) { @@ -527,12 +511,8 @@ void ServerLobby::handleChat(Event* event) event->getPeer()->getConsecutiveMessages() > ServerConfig::m_chat_consecutive_interval / 2) { - NetworkString* chat = getNetworkString(); - chat->setSynchronous(true); - core::stringw warn = "Spam detected"; - chat->addUInt8(LE_CHAT).encodeString16(warn); - event->getPeer()->sendPacket(chat, PRM_RELIABLE); - delete chat; + std::string msg = "Spam detected"; + sendStringToPeer(msg, event->getPeerSP()); return; } @@ -547,12 +527,8 @@ void ServerLobby::handleChat(Event* event) if (!StringUtils::startsWith(message_utf8, prefix)) { - NetworkString* chat = getNetworkString(); - chat->setSynchronous(true); - core::stringw warn = "Don't try to impersonate others!"; - chat->addUInt8(LE_CHAT).encodeString16(warn); - event->getPeer()->sendPacket(chat, PRM_RELIABLE); - delete chat; + std::string warn = "Don't try to impersonate others!"; + sendStringToPeer(warn, event->getPeerSP()); return; } @@ -1163,7 +1139,7 @@ void ServerLobby::asynchronousUpdate() // reset // maybe this is not the best place for this? - getHitProcessor()->m_last_teammate_hit_msg = 0; + getHitProcessor()->resetLastHits(); if (m_end_voting_period.load() == 0) return; @@ -1930,17 +1906,7 @@ void ServerLobby::update(int ticks) } } } - if (getHitProcessor()->m_teammate_swatter_punish.size() > 0) - { - // punish players who swattered teammates - for (auto& kart : getHitProcessor()->m_teammate_swatter_punish) - { - kart->getAttachment()->set(Attachment::ATTACH_ANVIL, - stk_config->time2Ticks(kart->getKartProperties()->getAnvilDuration())); - kart->adjustSpeed(kart->getKartProperties()->getAnvilSpeedFactor()); - } - getHitProcessor()->m_teammate_swatter_punish.clear(); - } + getHitProcessor()->punishSwatterHits(); } } if (m_state.load() == WAITING_FOR_START_GAME) { diff --git a/src/utils/hit_processor.cpp b/src/utils/hit_processor.cpp index 5b69f987072..d14076f152c 100644 --- a/src/utils/hit_processor.cpp +++ b/src/utils/hit_processor.cpp @@ -32,6 +32,9 @@ HitProcessor::HitProcessor(ServerLobby* lobby): m_lobby(lobby) m_teammate_hit_mode = ServerConfig::m_teammate_hit_mode; m_last_teammate_hit_msg = 0; m_teammate_swatter_punish.clear(); + + // This was also present in ServerLobby::setup(), I'm not sure why. + // Return back if there are problems. m_collecting_teammate_hit_info = false; } // HitProcessor // ======================================================================== @@ -100,7 +103,7 @@ void HitProcessor::handleTeamMateHits() return; // Show message? - if (showTeamMateHits()) + if (showTeammateHits()) { // prepare string int num_victims = 0; @@ -131,7 +134,7 @@ void HitProcessor::handleTeamMateHits() } } - if (useTeamMateHitMode()) + if (isTeammateHitMode()) { bool punished = false; // first check if we exploded at least one teammate @@ -226,7 +229,7 @@ void HitProcessor::handleSwatterHit(unsigned int ownerID, unsigned int victimID, return; // should we tell the world? - if (showTeamMateHits() && success) + if (showTeammateHits() && success) { std::string msg = StringUtils::insertValues( "%s%s just swattered teammate %s", @@ -236,7 +239,7 @@ void HitProcessor::handleSwatterHit(unsigned int ownerID, unsigned int victimID, ); sendTeamMateHitMsg(msg); } - if (useTeamMateHitMode()) + if (isTeammateHitMode()) { // remove swatter AbstractKart *owner = World::getWorld()->getKart(ownerID); @@ -267,7 +270,7 @@ void HitProcessor::handleAnvilHit(unsigned int ownerID, unsigned int victimID) AbstractKart *owner = World::getWorld()->getKart(ownerID); // should we tell the world? - if (showTeamMateHits()) + if (showTeammateHits()) { std::string msg = StringUtils::insertValues( "%s%s just gave an anchor to teammate %s", @@ -277,7 +280,7 @@ void HitProcessor::handleAnvilHit(unsigned int ownerID, unsigned int victimID) ); sendTeamMateHitMsg(msg); } - if (useTeamMateHitMode()) + if (isTeammateHitMode()) { if (owner->getAttachment()->getType() == Attachment::ATTACH_BOMB) { @@ -309,4 +312,20 @@ void HitProcessor::handleAnvilHit(unsigned int ownerID, unsigned int victimID) } } } // handleAnvilHit +//----------------------------------------------------------------------------- + +void HitProcessor::punishSwatterHits() +{ + if (m_teammate_swatter_punish.size() > 0) + { + // punish players who swattered teammates + for (auto& kart : m_teammate_swatter_punish) + { + kart->getAttachment()->set(Attachment::ATTACH_ANVIL, + stk_config->time2Ticks(kart->getKartProperties()->getAnvilDuration())); + kart->adjustSpeed(kart->getKartProperties()->getAnvilSpeedFactor()); + } + m_teammate_swatter_punish.clear(); + } +} // punishSwatterHits //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/hit_processor.hpp b/src/utils/hit_processor.hpp index 61486f858f8..a98da95f4ec 100644 --- a/src/utils/hit_processor.hpp +++ b/src/utils/hit_processor.hpp @@ -35,8 +35,7 @@ class HitProcessor public: HitProcessor(ServerLobby* lobby); -public: // feb16 remove todo revert to private - // feb16 remove +private: ServerLobby* m_lobby = nullptr; bool m_show_teammate_hits; // Whether to show messages about team hits. @@ -63,6 +62,10 @@ class HitProcessor public: // handle cakes and bowls + bool isTeammateHitMode() const { return m_teammate_hit_mode; } + bool showTeammateHits() const { return m_show_teammate_hits; } + void setTeammateHitMode(bool value) { m_teammate_hit_mode = value; } + void setShowTeammateHits(bool value) { m_show_teammate_hits = value; } void setTeamMateHitOwner(unsigned int ownerID, uint16_t ticks_since_thrown = 0); void registerTeamMateHit(unsigned int kartID); void registerTeamMateExplode(unsigned int kartID); @@ -74,8 +77,8 @@ class HitProcessor void handleAnvilHit(unsigned int ownerID, unsigned int victimID); void sendTeamMateHitMsg(std::string& s); - bool showTeamMateHits() const { return m_show_teammate_hits; } - bool useTeamMateHitMode() const { return m_teammate_hit_mode; } + void punishSwatterHits(); + void resetLastHits() { m_last_teammate_hit_msg = 0; } }; From 469ea17343c831c527a9d8602e54f9558772ef76 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 23 Feb 2025 18:15:53 +0400 Subject: [PATCH 574/830] Move kart and map handling into another unit, kinda Only slightly tested for now, and no optimizations were applied. --- src/network/protocols/command_manager.cpp | 84 ++-- src/network/protocols/command_manager.hpp | 6 +- src/network/protocols/ranking.cpp | 26 + src/network/protocols/ranking.hpp | 10 + src/network/protocols/server_lobby.cpp | 456 ++--------------- src/network/protocols/server_lobby.hpp | 29 +- src/utils/lobby_asset_manager.cpp | 574 ++++++++++++++++++++++ src/utils/lobby_asset_manager.hpp | 108 ++++ 8 files changed, 794 insertions(+), 499 deletions(-) create mode 100644 src/utils/lobby_asset_manager.cpp create mode 100644 src/utils/lobby_asset_manager.hpp diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 8db2702b2f3..15c0967eef5 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -35,6 +35,7 @@ #include "utils/file_utils.hpp" #include "utils/hit_processor.hpp" #include "utils/hourglass_reason.hpp" +#include "utils/lobby_asset_manager.hpp" #include "utils/log.hpp" #include "utils/random_generator.hpp" #include "utils/string_utils.hpp" @@ -608,6 +609,8 @@ CommandManager::CommandManager(ServerLobby* lobby): initCommands(); initAssets(); + m_asset_manager = lobby->getLobbyAssetManager(); + m_aux_mode_aliases = { {"m0"}, {"m1"}, @@ -1313,10 +1316,10 @@ void CommandManager::process_addons(Context& context) // removed const reference so that I can modify `from` // without changing the original container, we copy everything anyway std::set from = - (argv[1] == "kart" ? m_lobby->m_addon_kts.first : - (argv[1] == "track" ? m_lobby->m_addon_kts.second : - (argv[1] == "arena" ? m_lobby->m_addon_arenas : - /*argv[1] == "soccer" ?*/ m_lobby->m_addon_soccers + (argv[1] == "kart" ? m_asset_manager->getAddonKarts() : + (argv[1] == "track" ? m_asset_manager->getAddonTracks() : + (argv[1] == "arena" ? m_asset_manager->getAddonArenas() : + /*argv[1] == "soccer" ?*/ m_asset_manager->getAddonSoccers() ))); if (apply_filters) m_lobby->applyAllFilters(from, false); // happily the type is never karts in this line @@ -1457,13 +1460,13 @@ void CommandManager::process_checkaddon(Context& context) unsigned server_status = 0; std::vector players[4]; - if (m_lobby->m_addon_kts.first.count(id)) + if (m_asset_manager->hasAddonKart(id)) server_status |= HAS_KART; - if (m_lobby->m_addon_kts.second.count(id)) + if (m_asset_manager->hasAddonTrack(id)) server_status |= HAS_MAP; - if (m_lobby->m_addon_arenas.count(id)) + if (m_asset_manager->hasAddonArena(id)) server_status |= HAS_MAP; - if (m_lobby->m_addon_soccers.count(id)) + if (m_asset_manager->hasAddonSoccer(id)) server_status |= HAS_MAP; auto peers = STKHost::get()->getPeers(); @@ -1616,22 +1619,26 @@ void CommandManager::process_lsa(Context& context) if (type.empty() || // not specify addon type (!type.empty() && type.compare("kart") == 0)) // list kart addon { - total_addons.insert(m_lobby->m_addon_kts.first.begin(), m_lobby->m_addon_kts.first.end()); + const auto& collection = m_asset_manager->getAddonKarts(); + total_addons.insert(collection.begin(), collection.end()); } if (type.empty() || // not specify addon type (!type.empty() && type.compare("track") == 0)) { - total_addons.insert(m_lobby->m_addon_kts.second.begin(), m_lobby->m_addon_kts.second.end()); + const auto& collection = m_asset_manager->getAddonTracks(); + total_addons.insert(collection.begin(), collection.end()); } if (type.empty() || // not specify addon type (!type.empty() && type.compare("arena") == 0)) { - total_addons.insert(m_lobby->m_addon_arenas.begin(), m_lobby->m_addon_arenas.end()); + const auto& collection = m_asset_manager->getAddonArenas(); + total_addons.insert(collection.begin(), collection.end()); } if (type.empty() || // not specify addon type (!type.empty() && type.compare("soccer") == 0)) { - total_addons.insert(m_lobby->m_addon_soccers.begin(), m_lobby->m_addon_soccers.end()); + const auto& collection = m_asset_manager->getAddonSoccers(); + total_addons.insert(collection.begin(), collection.end()); } std::string msg = ""; for (auto& addon : total_addons) @@ -1992,10 +1999,15 @@ void CommandManager::process_sha(Context& context) return; } std::set total_addons; - total_addons.insert(m_lobby->m_addon_kts.first.begin(), m_lobby->m_addon_kts.first.end()); - total_addons.insert(m_lobby->m_addon_kts.second.begin(), m_lobby->m_addon_kts.second.end()); - total_addons.insert(m_lobby->m_addon_arenas.begin(), m_lobby->m_addon_arenas.end()); - total_addons.insert(m_lobby->m_addon_soccers.begin(), m_lobby->m_addon_soccers.end()); + + const auto all_karts = m_asset_manager->getAddonKarts(); + const auto all_tracks = m_asset_manager->getAddonTracks(); + const auto all_arenas = m_asset_manager->getAddonArenas(); + const auto all_soccers = m_asset_manager->getAddonSoccers(); + total_addons.insert(all_karts.begin(), all_karts.end()); + total_addons.insert(all_tracks.begin(), all_tracks.end()); + total_addons.insert(all_arenas.begin(), all_arenas.end()); + total_addons.insert(all_soccers.begin(), all_soccers.end()); std::string addon_id_test = Addon::createAddonId(argv[1]); bool found = total_addons.find(addon_id_test) != total_addons.end(); if (found) @@ -2160,7 +2172,7 @@ void CommandManager::process_gnu(Context& context) if (peer) { kart = "gnu"; - if (argv.size() > 1 && m_lobby->m_available_kts.first.count(argv[1]) > 0) + if (argv.size() > 1 && m_asset_manager->isKartAvailable(argv[1])) { kart = argv[1]; } @@ -2569,9 +2581,9 @@ void CommandManager::process_queue_push(Context& context) bool to_front = (argv[1] == "push_front"); if (argv.size() == 3 && argv[2] == "-") // kept until there's filter-type replacement - argv[2] = getRandomMap(); + argv[2] = m_asset_manager->getRandomMap(); else if (argv.size() == 3 && argv[2] == "-addon") // kept until there's filter-type replacement - argv[2] = getRandomAddonMap(); + argv[2] = m_asset_manager->getRandomAddonMap(); std::string filter_text = ""; CommandManager::restoreCmdByArgv(filter_text, argv, ' ', '"', '"', '\\', 2); @@ -4251,40 +4263,6 @@ bool CommandManager::assignRandomTeams(int intended_number, } // assignRandomTeams // ======================================================================== -std::string CommandManager::getRandomMap() const -{ - std::set items; - for (const std::string& s: m_lobby->m_entering_kts.second) { - items.insert(s); - } - m_lobby->applyAllFilters(items, false); - if (items.empty()) - return ""; - RandomGenerator rg; - std::set::iterator it = items.begin(); - std::advance(it, rg.get((int)items.size())); - return *it; -} // getRandomMap -// ======================================================================== - -std::string CommandManager::getRandomAddonMap() const -{ - std::set items; - for (const std::string& s: m_lobby->m_entering_kts.second) { - Track* t = track_manager->getTrack(s); - if (t->isAddon()) - items.insert(s); - } - m_lobby->applyAllFilters(items, false); - if (items.empty()) - return ""; - RandomGenerator rg; - std::set::iterator it = items.begin(); - std::advance(it, rg.get((int)items.size())); - return *it; -} // getRandomAddonMap -// ======================================================================== - void CommandManager::addUser(std::string& s) { m_users.insert(s); diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index dafda8ac842..e7f8754eef5 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -49,6 +49,7 @@ class ServerLobby; class Event; class STKPeer; +class LobbyAssetManager; class CommandManager { @@ -197,6 +198,8 @@ class CommandManager ServerLobby* m_lobby; + std::shared_ptr m_asset_manager; + std::vector> m_all_commands; std::map> m_full_name_to_command; @@ -349,9 +352,6 @@ class CommandManager void process_available_teams_assign(Context& context); void special(Context& context); - std::string getRandomMap() const; - std::string getRandomAddonMap() const; - public: CommandManager(ServerLobby* lobby = nullptr); diff --git a/src/network/protocols/ranking.cpp b/src/network/protocols/ranking.cpp index 1662faa6bcb..452bc9f7d72 100644 --- a/src/network/protocols/ranking.cpp +++ b/src/network/protocols/ranking.cpp @@ -17,6 +17,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "network/protocols/ranking.hpp" +#include "online/request_manager.hpp" #include "io/xml_node.hpp" #include "utils/log.hpp" #include "utils/time.hpp" @@ -38,6 +39,31 @@ namespace const double HANDICAP_OFFSET = 2000.0; } +SubmitRankingRequest::SubmitRankingRequest(const RankingEntry& entry, + const std::string& country_code) + : XMLRequest(Online::RequestManager::HTTP_MAX_PRIORITY) +{ + addParameter("id", entry.online_id); + addParameter("scores", entry.score); + addParameter("max-scores", entry.max_score); + addParameter("num-races-done", entry.races); + addParameter("raw-scores", entry.raw_score); + addParameter("rating-deviation", entry.deviation); + addParameter("disconnects", entry.disconnects); + addParameter("country-code", country_code); +} + +void SubmitRankingRequest::afterOperation() +{ + Online::XMLRequest::afterOperation(); + const XMLNode* result = getXMLData(); + std::string rec_success; + if (!(result->get("success", &rec_success) && + rec_success == "yes")) + { + Log::error("ServerLobby", "Failed to submit scores."); + } +} //----------------------------------------------------------------------------- RankingEntry::RankingEntry(uint32_t online_id): online_id(online_id) diff --git a/src/network/protocols/ranking.hpp b/src/network/protocols/ranking.hpp index 02de90e9517..8709125a7f8 100644 --- a/src/network/protocols/ranking.hpp +++ b/src/network/protocols/ranking.hpp @@ -19,6 +19,7 @@ #ifndef RANKING_HPP #define RANKING_HPP +#include "online/xml_request.hpp" #include #include #include @@ -27,6 +28,7 @@ class XMLNode; class NetworkPlayerProfile; + struct RankingEntry { uint32_t online_id; @@ -53,6 +55,14 @@ struct RankingEntryAndProfile std::weak_ptr profile; }; +class SubmitRankingRequest : public Online::XMLRequest +{ +public: + SubmitRankingRequest(const RankingEntry& entry, + const std::string& country_code); + virtual void afterOperation(); +}; + class Ranking { private: diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 077fe942081..7f7d3e776ae 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -43,12 +43,13 @@ #include "network/stk_ipv6.hpp" #include "network/stk_peer.hpp" #include "online/request_manager.hpp" -#include "online/xml_request.hpp" +// #include "online/xml_request.hpp" #include "tracks/check_manager.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/game_info.hpp" #include "utils/hit_processor.hpp" +#include "utils/lobby_asset_manager.hpp" #include "utils/translation.hpp" #include @@ -60,35 +61,6 @@ int ServerLobby::m_default_fixed_laps = -1; // ======================================================================== -class SubmitRankingRequest : public Online::XMLRequest -{ -public: - SubmitRankingRequest(const RankingEntry& entry, - const std::string& country_code) - : XMLRequest(Online::RequestManager::HTTP_MAX_PRIORITY) - { - addParameter("id", entry.online_id); - addParameter("scores", entry.score); - addParameter("max-scores", entry.max_score); - addParameter("num-races-done", entry.races); - addParameter("raw-scores", entry.raw_score); - addParameter("rating-deviation", entry.deviation); - addParameter("disconnects", entry.disconnects); - addParameter("country-code", country_code); - } - virtual void afterOperation() - { - Online::XMLRequest::afterOperation(); - const XMLNode* result = getXMLData(); - std::string rec_success; - if (!(result->get("success", &rec_success) && - rec_success == "yes")) - { - Log::error("ServerLobby", "Failed to submit scores."); - } - } -}; // UpdatePlayerRankingRequest -// ======================================================================== // We use max priority for all server requests to avoid downloading of addons // icons blocking the poll request in all-in-one graphical client server @@ -158,6 +130,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_hit_processor = std::make_shared(this); + m_asset_manager = std::make_shared(this); + m_available_teams = ServerConfig::m_init_available_teams; m_map_vote_handler.setAlgorithm(ServerConfig::m_map_vote_handling); @@ -165,25 +139,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() initAvailableModes(); m_current_ai_count.store(0); - std::vector all_k = - kart_properties_manager->getKartsInGroup("standard"); - std::vector all_t = - track_manager->getTracksInGroup("standard"); - std::vector all_arenas = - track_manager->getArenasInGroup("standard", false); - std::vector all_soccers = - track_manager->getArenasInGroup("standard", true); - all_t.insert(all_t.end(), all_arenas.begin(), all_arenas.end()); - all_t.insert(all_t.end(), all_soccers.begin(), all_soccers.end()); - - m_official_kts.first = OfficialKarts::getOfficialKarts(); - for (int track : all_t) - { - Track* t = track_manager->getTrack(track); - if (!t->isAddon()) - m_official_kts.second.insert(t->getIdent()); - } - updateAddons(); + m_asset_manager->init(); + m_asset_manager->updateAddons(); initAvailableTracks(); @@ -265,146 +222,14 @@ void ServerLobby::initServerStatsTable() } // initServerStatsTable //----------------------------------------------------------------------------- -void ServerLobby::updateAddons() +/** Calls the corresponding method from LobbyAssetManager + * whenever server is reset or game mode is changed. */ +void ServerLobby::updateMapsForMode() { - m_addon_kts.first.clear(); - m_addon_kts.second.clear(); - m_addon_arenas.clear(); - m_addon_soccers.clear(); - - std::set total_addons; - for (unsigned i = 0; i < kart_properties_manager->getNumberOfKarts(); i++) - { - const KartProperties* kp = - kart_properties_manager->getKartById(i); - if (kp->isAddon()) - total_addons.insert(kp->getIdent()); - } - for (unsigned i = 0; i < track_manager->getNumberOfTracks(); i++) - { - const Track* track = track_manager->getTrack(i); - if (track->isAddon()) - total_addons.insert(track->getIdent()); - } - - for (auto& addon : total_addons) - { - const KartProperties* kp = kart_properties_manager->getKart(addon); - if (kp && kp->isAddon()) - { - m_addon_kts.first.insert(kp->getIdent()); - continue; - } - Track* t = track_manager->getTrack(addon); - if (!t || !t->isAddon() || t->isInternal()) - continue; - if (t->isArena()) - m_addon_arenas.insert(t->getIdent()); - if (t->isSoccer()) - m_addon_soccers.insert(t->getIdent()); - if (!t->isArena() && !t->isSoccer()) - m_addon_kts.second.insert(t->getIdent()); - } - - std::vector all_k; - for (unsigned i = 0; i < kart_properties_manager->getNumberOfKarts(); i++) - { - const KartProperties* kp = kart_properties_manager->getKartById(i); - if (kp->isAddon()) - all_k.push_back(kp->getIdent()); - } - std::set oks = OfficialKarts::getOfficialKarts(); - if (all_k.size() >= 65536 - (unsigned)oks.size()) - all_k.resize(65535 - (unsigned)oks.size()); - for (const std::string& k : oks) - all_k.push_back(k); - if (ServerConfig::m_live_players) - m_available_kts.first = m_official_kts.first; - else - m_available_kts.first = { all_k.begin(), all_k.end() }; - m_entering_kts = m_available_kts; -} // updateAddons - -//----------------------------------------------------------------------------- -/** Called whenever server is reset or game mode is changed. - */ -void ServerLobby::updateTracksForMode() -{ - auto all_t = track_manager->getAllTrackIdentifiers(); - if (all_t.size() >= 65536) - all_t.resize(65535); - m_available_kts.second = { all_t.begin(), all_t.end() }; RaceManager::MinorRaceModeType m = ServerConfig::getLocalGameMode(m_game_mode.load()).first; - switch (m) - { - case RaceManager::MINOR_MODE_NORMAL_RACE: - case RaceManager::MINOR_MODE_TIME_TRIAL: - case RaceManager::MINOR_MODE_FOLLOW_LEADER: - { - auto it = m_available_kts.second.begin(); - while (it != m_available_kts.second.end()) - { - Track* t = track_manager->getTrack(*it); - if (t->isArena() || t->isSoccer() || t->isInternal()) - { - it = m_available_kts.second.erase(it); - } - else - it++; - } - break; - } - case RaceManager::MINOR_MODE_FREE_FOR_ALL: - case RaceManager::MINOR_MODE_CAPTURE_THE_FLAG: - { - auto it = m_available_kts.second.begin(); - while (it != m_available_kts.second.end()) - { - Track* t = track_manager->getTrack(*it); - if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) - { - if (!t->isCTF() || t->isInternal()) - { - it = m_available_kts.second.erase(it); - } - else - it++; - } - else - { - if (!t->isArena() || t->isInternal()) - { - it = m_available_kts.second.erase(it); - } - else - it++; - } - } - break; - } - case RaceManager::MINOR_MODE_SOCCER: - { - auto it = m_available_kts.second.begin(); - while (it != m_available_kts.second.end()) - { - Track* t = track_manager->getTrack(*it); - if (!t->isSoccer() || t->isInternal()) - { - it = m_available_kts.second.erase(it); - } - else - it++; - } - break; - } - default: - assert(false); - break; - } - m_entering_kts = m_available_kts; -} // updateTracksForMode + m_asset_manager->updateMapsForMode(m); +} // updateMapsForMode //----------------------------------------------------------------------------- void ServerLobby::setup() @@ -436,16 +261,9 @@ void ServerLobby::setup() ai->setKartName(""); StateManager::get()->resetActivePlayers(); - // We use maximum 16bit unsigned limit - auto all_k = kart_properties_manager->getAllAvailableKarts(); - if (all_k.size() >= 65536) - all_k.resize(65535); - if (ServerConfig::m_live_players) - m_available_kts.first = m_official_kts.first; - else - m_available_kts.first = { all_k.begin(), all_k.end() }; + m_asset_manager->onServerSetup(); NetworkConfig::get()->setTuxHitboxAddon(ServerConfig::m_live_players); - updateTracksForMode(); + updateMapsForMode(); m_server_has_loaded_world.store(false); @@ -2354,7 +2172,7 @@ void ServerLobby::startSelection(const Event *event) } // Remove karts / tracks from server that are not supported on all clients - std::set karts_erase, tracks_erase; + std::vector> erasingPeers; bool has_peer_plays_game = false; for (auto peer : peers) { @@ -2375,8 +2193,8 @@ void ServerLobby::startSelection(const Event *event) always_spectate_peers.insert(peer); continue; } - peer->eraseServerKarts(m_available_kts.first, karts_erase); - peer->eraseServerTracks(m_available_kts.second, tracks_erase); + // I might introduce an extra use for a peer that leaves at the same moment. Please investigate later. + erasingPeers.push_back(peer); if (!peer->isAIPeer()) has_peer_plays_game = true; } @@ -2409,14 +2227,7 @@ void ServerLobby::startSelection(const Event *event) peer->setWaitingForGame(true); } - for (const std::string& kart_erase : karts_erase) - { - m_available_kts.first.erase(kart_erase); - } - for (const std::string& track_erase : tracks_erase) - { - m_available_kts.second.erase(track_erase); - } + m_asset_manager->eraseAssetsWithPeers(erasingPeers); max_player = 0; STKHost::get()->updatePlayers(&max_player); @@ -2443,38 +2254,21 @@ void ServerLobby::startSelection(const Event *event) else m_ai_count = 0; - std::set available_tracks_fallback = m_available_kts.second; - applyAllFilters(m_available_kts.second, true); - - /* auto iter = m_available_kts.second.begin(); - while (iter != m_available_kts.second.end()) - { - // Initial version which will be brought into a separate fuction - std::string track = *iter; - if (getTrackMaxPlayers(track) < max_player) - iter = m_available_kts.second.erase(iter); - else - iter++; - }*/ - - if (m_available_kts.second.empty()) + if (!m_asset_manager->tryApplyingMapFilters()) { Log::error("ServerLobby", "No tracks for playing!"); - m_available_kts.second = available_tracks_fallback; return; } + m_default_vote->m_track_name = m_asset_manager->getRandomAvailableMap(); RandomGenerator rg; - std::set::iterator it = m_available_kts.second.begin(); - std::advance(it, rg.get((int)m_available_kts.second.size())); - m_default_vote->m_track_name = *it; switch (RaceManager::get()->getMinorMode()) { case RaceManager::MINOR_MODE_NORMAL_RACE: case RaceManager::MINOR_MODE_TIME_TRIAL: case RaceManager::MINOR_MODE_FOLLOW_LEADER: { - Track* t = track_manager->getTrack(*it); + Track* t = track_manager->getTrack(m_default_vote->m_track_name); assert(t); m_default_vote->m_num_laps = t->getDefaultNumberOfLaps(); if (ServerConfig::m_auto_game_time_ratio > 0.0f) @@ -2581,14 +2375,7 @@ void ServerLobby::startSelection(const Event *event) all_k = {}; } - - const auto& all_t = m_available_kts.second; - - ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size()); - for (const std::string& kart : all_k) - ns->encodeString(kart); - for (const std::string& track : all_t) - ns->encodeString(track); + m_asset_manager->encodePlayerKartsAndCommonMaps(ns, all_k); peer->sendPacket(ns, PRM_RELIABLE); delete ns; @@ -3092,112 +2879,7 @@ bool ServerLobby::handleAssets(const NetworkString& ns, std::shared_ptr client_tracks.insert(track); } - // Drop this player if he doesn't have at least 1 kart / track the same - // as server - float okt = 0.0f; - float ott = 0.0f; - int addon_karts = 0; - int addon_tracks = 0; - int addon_arenas = 0; - int addon_soccers = 0; - for (auto& client_kart : client_karts) - { - if (m_official_kts.first.find(client_kart) != - m_official_kts.first.end()) - okt += 1.0f; - if (m_addon_kts.first.find(client_kart) != - m_addon_kts.first.end()) - ++addon_karts; - } - okt = okt / (float)m_official_kts.first.size(); - for (auto& client_track : client_tracks) - { - if (m_official_kts.second.find(client_track) != - m_official_kts.second.end()) - ott += 1.0f; - if (m_addon_kts.second.find(client_track) != - m_addon_kts.second.end()) - ++addon_tracks; - if (m_addon_arenas.find(client_track) != - m_addon_arenas.end()) - ++addon_arenas; - if (m_addon_soccers.find(client_track) != - m_addon_soccers.end()) - ++addon_soccers; - } - ott = ott / (float)m_official_kts.second.size(); - - std::set karts_erase, tracks_erase; - for (const std::string& server_kart : m_entering_kts.first) - { - if (client_karts.find(server_kart) == client_karts.end()) - { - karts_erase.insert(server_kart); - } - } - for (const std::string& server_track : m_entering_kts.second) - { - if (client_tracks.find(server_track) == client_tracks.end()) - { - tracks_erase.insert(server_track); - } - } - - bool has_required_tracks = true; - for (const std::string& required_track : m_must_have_tracks) - { - if (client_tracks.find(required_track) == client_tracks.end()) - { - has_required_tracks = false; - Log::info("ServerLobby", "Player does not have a required track '%s'.", required_track.c_str()); - break; - } - } - - Log::info("ServerLobby", "Player has the following addons: %d/%d(%d) karts," - " %d/%d(%d) tracks, %d/%d(%d) arenas, %d/%d(%d) soccer fields.", - addon_karts, (int)ServerConfig::m_addon_karts_join_threshold, - (int)ServerConfig::m_addon_karts_play_threshold, - addon_tracks, (int)ServerConfig::m_addon_tracks_join_threshold, - (int)ServerConfig::m_addon_tracks_play_threshold, - addon_arenas, (int)ServerConfig::m_addon_arenas_join_threshold, - (int)ServerConfig::m_addon_arenas_play_threshold, - addon_soccers, (int)ServerConfig::m_addon_soccers_join_threshold, - (int)ServerConfig::m_addon_soccers_play_threshold); - - peer->addon_karts_count = addon_karts; - peer->addon_tracks_count = addon_tracks; - peer->addon_arenas_count = addon_arenas; - peer->addon_soccers_count = addon_soccers; - - if (karts_erase.size() == m_entering_kts.first.size()) - Log::verbose("ServerLobby", "Bad player: no common karts with server"); - if (tracks_erase.size() == m_entering_kts.second.size()) - Log::verbose("ServerLobby", "Bad player: no common tracks with server"); - if (okt < ServerConfig::m_official_karts_threshold) - Log::verbose("ServerLobby", "Bad player: bad official kart threshold"); - if (ott < ServerConfig::m_official_tracks_threshold) - Log::verbose("ServerLobby", "Bad player: bad official track threshold"); - if (addon_karts < (int)ServerConfig::m_addon_karts_join_threshold) - Log::verbose("ServerLobby", "Bad player: too little addon karts"); - if (addon_tracks < (int)ServerConfig::m_addon_tracks_join_threshold) - Log::verbose("ServerLobby", "Bad player: too little addon tracks"); - if (addon_arenas < (int)ServerConfig::m_addon_arenas_join_threshold) - Log::verbose("ServerLobby", "Bad player: too little addon arenas"); - if (addon_soccers < (int)ServerConfig::m_addon_soccers_join_threshold) - Log::verbose("ServerLobby", "Bad player: too little addon soccers"); - if (!has_required_tracks) - Log::verbose("ServerLobby", "Bad player: no required tracks"); - - if (karts_erase.size() == m_entering_kts.first.size() || - tracks_erase.size() == m_entering_kts.second.size() || - okt < ServerConfig::m_official_karts_threshold || - ott < ServerConfig::m_official_tracks_threshold || - addon_karts < (int)ServerConfig::m_addon_karts_join_threshold || - addon_tracks < (int)ServerConfig::m_addon_tracks_join_threshold || - addon_arenas < (int)ServerConfig::m_addon_arenas_join_threshold || - addon_soccers < (int)ServerConfig::m_addon_soccers_join_threshold || - !has_required_tracks) + if (!m_asset_manager->handleAssetsForPeer(peer, client_karts, client_tracks)) { if (peer->isValidated()) { @@ -3234,49 +2916,8 @@ bool ServerLobby::handleAssets(const NetworkString& ns, std::shared_ptr return false; } - std::array addons_scores = {{ -1, -1, -1, -1 }}; - size_t addon_kart = 0; - size_t addon_track = 0; - size_t addon_arena = 0; - size_t addon_soccer = 0; - - for (auto& kart : m_addon_kts.first) - { - if (client_karts.find(kart) != client_karts.end()) - addon_kart++; - } - for (auto& track : m_addon_kts.second) - { - if (client_tracks.find(track) != client_tracks.end()) - addon_track++; - } - for (auto& arena : m_addon_arenas) - { - if (client_tracks.find(arena) != client_tracks.end()) - addon_arena++; - } - for (auto& soccer : m_addon_soccers) - { - if (client_tracks.find(soccer) != client_tracks.end()) - addon_soccer++; - } - if (!m_addon_kts.first.empty()) - { - addons_scores[AS_KART] = addon_kart; - } - if (!m_addon_kts.second.empty()) - { - addons_scores[AS_TRACK] = addon_track; - } - if (!m_addon_arenas.empty()) - { - addons_scores[AS_ARENA] = addon_arena; - } - if (!m_addon_soccers.empty()) - { - addons_scores[AS_SOCCER] = addon_soccer; - } + std::array addons_scores = m_asset_manager->getAddonScores(client_karts, client_tracks); // Save available karts and tracks from clients in STKPeer so if this peer // disconnects later in lobby it won't affect current players @@ -3287,8 +2928,8 @@ bool ServerLobby::handleAssets(const NetworkString& ns, std::shared_ptr peer->getHostId() == m_client_server_host_id.load()) { // Update child process addons list too so player can choose later - updateAddons(); - updateTracksForMode(); + m_asset_manager->updateAddons(); + updateMapsForMode(); } if (ServerConfig::m_soccer_tournament) @@ -4014,7 +3655,7 @@ void ServerLobby::handlePlayerVote(Event* event) Track* t = track_manager->getTrack(vote.m_track_name); if (!t) { - vote.m_track_name = *m_available_kts.second.begin(); + vote.m_track_name = m_asset_manager->getAnyMapForVote(); t = track_manager->getTrack(vote.m_track_name); assert(t); } @@ -4685,23 +4326,15 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, } m_difficulty.store(difficulty); m_game_mode.store(mode); - updateTracksForMode(); + updateMapsForMode(); auto peers = STKHost::get()->getPeers(); for (auto& peer : peers) { auto assets = peer->getClientAssets(); - if (!peer->isValidated() || assets.second.empty()) + if (!peer->isValidated() || assets.second.empty()) // this check will fail hard when I introduce vavriable limits continue; - std::set tracks_erase; - for (const std::string& server_track : m_available_kts.second) - { - if (assets.second.find(server_track) == assets.second.end()) - { - tracks_erase.insert(server_track); - } - } - if (tracks_erase.size() == m_available_kts.second.size()) + if (m_asset_manager->checkIfNoCommonMaps(assets)) { NetworkString *message = getNetworkString(2); message->setSynchronous(true); @@ -4981,7 +4614,7 @@ void ServerLobby::setPlayerKarts(const NetworkString& ns, std::shared_ptrisKartAvailable(kart))) { current_kart = ""; } @@ -5901,9 +5534,6 @@ bool ServerLobby::canRace(std::shared_ptr peer) return false; } - std::set maps = peer->getClientAssets().second; - std::set karts = peer->getClientAssets().first; - if (!m_play_requirement_tracks.empty()) for (const std::string& track: m_play_requirement_tracks) if (peer->getClientAssets().second.count(track) == 0) @@ -5933,22 +5563,11 @@ bool ServerLobby::canRace(std::shared_ptr peer) return false; } - float karts_fraction = 0.0f; - float maps_fraction = 0.0f; - for (auto& kart : karts) - { - if (m_official_kts.first.find(kart) != - m_official_kts.first.end()) - karts_fraction += 1.0f; - } - for (auto& map : maps) - { - if (m_official_kts.second.find(map) != - m_official_kts.second.end()) - maps_fraction += 1.0f; - } - karts_fraction /= (float)m_official_kts.first.size(); - maps_fraction /= (float)m_official_kts.second.size(); + std::set maps = peer->getClientAssets().second; + std::set karts = peer->getClientAssets().first; + + float karts_fraction = m_asset_manager->officialKartsFraction(karts); + float maps_fraction = m_asset_manager->officialMapsFraction(maps); if (karts_fraction < ServerConfig::m_official_karts_play_threshold) { @@ -6267,8 +5886,7 @@ void ServerLobby::initAvailableTracks() { m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); m_global_karts_filter = KartFilter(ServerConfig::m_only_played_karts_string); - m_must_have_tracks = StringUtils::split( - ServerConfig::m_must_have_tracks_string, ' ', false); + m_asset_manager->setMustHaveMaps(ServerConfig::m_must_have_tracks_string); m_play_requirement_tracks = StringUtils::split( ServerConfig::m_play_requirement_tracks_string, ' ', false); } // initAvailableTracks @@ -6597,7 +6215,7 @@ bool ServerLobby::areKartFiltersIgnoringKarts() const //----------------------------------------------------------------------------- std::string ServerLobby::getKartForBadKartChoice(std::shared_ptr peer, const std::string& username, const std::string& check_choice) const { - std::set karts = (peer->isAIPeer() ? m_available_kts.first : peer->getClientAssets().first); + std::set karts = (peer->isAIPeer() ? m_asset_manager->getAvailableKarts() : peer->getClientAssets().first); applyAllKartFilters(username, karts, true); if (m_kart_elimination.isEliminated(username) && karts.count(m_kart_elimination.getKart())) diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 9718ae5f280..20f10950f10 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -53,6 +53,7 @@ class SocketAddress; enum AlwaysSpectateMode: uint8_t; class Ranking; class HitProcessor; +class LobbyAssetManager; namespace Online { @@ -145,26 +146,6 @@ class ServerLobby : public LobbyProtocol std::atomic m_server_owner_id; - /** Official karts and tracks available in server. */ - std::pair, std::set > m_official_kts; - - /** Addon karts and tracks available in server. */ - std::pair, std::set > m_addon_kts; - - /** Addon arenas available in server. */ - std::set m_addon_arenas; - - /** Addon soccers available in server. */ - std::set m_addon_soccers; - - /** Available karts and tracks for all clients, this will be initialized - * with data in server first. */ - std::pair, std::set > m_available_kts; - - /** Available karts and tracks for all clients, this will be initialized - * with data in server first. */ - std::pair, std::set > m_entering_kts; - /** Keeps track of the server state. */ std::atomic_bool m_server_has_loaded_world; @@ -198,6 +179,8 @@ class ServerLobby : public LobbyProtocol std::shared_ptr m_hit_processor; + std::shared_ptr m_asset_manager; + /* Saved the last game result */ NetworkString* m_result_ns; @@ -239,8 +222,6 @@ class ServerLobby : public LobbyProtocol std::set> m_spectators_by_limit; - std::vector m_must_have_tracks; - std::vector m_play_requirement_tracks; std::vector m_tournament_must_have_tracks; @@ -392,7 +373,7 @@ class ServerLobby : public LobbyProtocol void handleServerConfiguration(Event* event); void handleServerConfiguration(std::shared_ptr peer, int difficulty, int mode, bool soccer_goal_target); - void updateTracksForMode(); + void updateMapsForMode(); bool checkPeersReady(bool ignore_ai_peer, SelectionPhase phase); void resetPeersReady() { @@ -484,7 +465,6 @@ class ServerLobby : public LobbyProtocol void getMessagesFromHost(std::shared_ptr peer, int online_id); void writePlayerReport(Event* event); bool supportsAI(); - void updateAddons(); void initCategories(); void initTournamentPlayers(); void changeColors(); @@ -603,6 +583,7 @@ class ServerLobby : public LobbyProtocol void setSpectateModeProperly(std::shared_ptr peer, AlwaysSpectateMode mode); int getTeamForUsername(const std::string& name) { return m_team_for_player[name]; } std::shared_ptr getHitProcessor() const { return m_hit_processor; } + std::shared_ptr getLobbyAssetManager() const { return m_asset_manager; } }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp new file mode 100644 index 00000000000..5f316432325 --- /dev/null +++ b/src/utils/lobby_asset_manager.cpp @@ -0,0 +1,574 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2024 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "karts/kart_properties.hpp" +#include "karts/kart_properties_manager.hpp" +#include "karts/official_karts.hpp" +#include "network/network_string.hpp" +#include "network/server_config.hpp" +#include "network/stk_peer.hpp" +#include "network/protocols/server_lobby.hpp" +#include "tracks/track.hpp" +#include "tracks/track_manager.hpp" +#include "utils/lobby_asset_manager.hpp" +#include "utils/random_generator.hpp" + +LobbyAssetManager::LobbyAssetManager(ServerLobby* lobby): m_lobby(lobby) +{ + +} // LobbyAssetManager +// ======================================================================== + +void LobbyAssetManager::init() +{ + + std::vector all_k = + kart_properties_manager->getKartsInGroup("standard"); + std::vector all_t = + track_manager->getTracksInGroup("standard"); + std::vector all_arenas = + track_manager->getArenasInGroup("standard", false); + std::vector all_soccers = + track_manager->getArenasInGroup("standard", true); + all_t.insert(all_t.end(), all_arenas.begin(), all_arenas.end()); + all_t.insert(all_t.end(), all_soccers.begin(), all_soccers.end()); + + k_official_kts.first = OfficialKarts::getOfficialKarts(); + for (int track : all_t) + { + Track* t = track_manager->getTrack(track); + if (!t->isAddon()) + k_official_kts.second.insert(t->getIdent()); + } +} // init +// ======================================================================== + +void LobbyAssetManager::updateAddons() +{ + k_addon_kts.first.clear(); + k_addon_kts.second.clear(); + k_addon_arenas.clear(); + k_addon_soccers.clear(); + + std::set total_addons; + for (unsigned i = 0; i < kart_properties_manager->getNumberOfKarts(); i++) + { + const KartProperties* kp = + kart_properties_manager->getKartById(i); + if (kp->isAddon()) + total_addons.insert(kp->getIdent()); + } + for (unsigned i = 0; i < track_manager->getNumberOfTracks(); i++) + { + const Track* track = track_manager->getTrack(i); + if (track->isAddon()) + total_addons.insert(track->getIdent()); + } + + for (auto& addon : total_addons) + { + const KartProperties* kp = kart_properties_manager->getKart(addon); + if (kp && kp->isAddon()) + { + k_addon_kts.first.insert(kp->getIdent()); + continue; + } + Track* t = track_manager->getTrack(addon); + if (!t || !t->isAddon() || t->isInternal()) + continue; + if (t->isArena()) + k_addon_arenas.insert(t->getIdent()); + if (t->isSoccer()) + k_addon_soccers.insert(t->getIdent()); + if (!t->isArena() && !t->isSoccer()) + k_addon_kts.second.insert(t->getIdent()); + } + + std::vector all_k; + for (unsigned i = 0; i < kart_properties_manager->getNumberOfKarts(); i++) + { + const KartProperties* kp = kart_properties_manager->getKartById(i); + if (kp->isAddon()) + all_k.push_back(kp->getIdent()); + } + std::set oks = OfficialKarts::getOfficialKarts(); + if (all_k.size() >= 65536 - (unsigned)oks.size()) + all_k.resize(65535 - (unsigned)oks.size()); + for (const std::string& k : oks) + all_k.push_back(k); + if (ServerConfig::m_live_players) + k_available_kts.first = k_official_kts.first; + else + k_available_kts.first = { all_k.begin(), all_k.end() }; + k_entering_kts = k_available_kts; +} // updateAddons + +//----------------------------------------------------------------------------- +/** Called whenever server is reset or game mode is changed. + */ +void LobbyAssetManager::updateMapsForMode(RaceManager::MinorRaceModeType mode) +{ + auto all_t = track_manager->getAllTrackIdentifiers(); + if (all_t.size() >= 65536) + all_t.resize(65535); + k_available_kts.second = { all_t.begin(), all_t.end() }; + switch (mode) + { + case RaceManager::MINOR_MODE_NORMAL_RACE: + case RaceManager::MINOR_MODE_TIME_TRIAL: + case RaceManager::MINOR_MODE_FOLLOW_LEADER: + { + auto it = k_available_kts.second.begin(); + while (it != k_available_kts.second.end()) + { + Track* t = track_manager->getTrack(*it); + if (t->isArena() || t->isSoccer() || t->isInternal()) + { + it = k_available_kts.second.erase(it); + } + else + it++; + } + break; + } + case RaceManager::MINOR_MODE_FREE_FOR_ALL: + case RaceManager::MINOR_MODE_CAPTURE_THE_FLAG: + { + auto it = k_available_kts.second.begin(); + while (it != k_available_kts.second.end()) + { + Track* t = track_manager->getTrack(*it); + if (RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) + { + if (!t->isCTF() || t->isInternal()) + { + it = k_available_kts.second.erase(it); + } + else + it++; + } + else + { + if (!t->isArena() || t->isInternal()) + { + it = k_available_kts.second.erase(it); + } + else + it++; + } + } + break; + } + case RaceManager::MINOR_MODE_SOCCER: + { + auto it = k_available_kts.second.begin(); + while (it != k_available_kts.second.end()) + { + Track* t = track_manager->getTrack(*it); + if (!t->isSoccer() || t->isInternal()) + { + it = k_available_kts.second.erase(it); + } + else + it++; + } + break; + } + default: + assert(false); + break; + } + k_entering_kts = k_available_kts; +} // updateMapsForMode + +//----------------------------------------------------------------------------- + +void LobbyAssetManager::onServerSetup() +{ + // We use maximum 16bit unsigned limit + auto all_k = kart_properties_manager->getAllAvailableKarts(); + if (all_k.size() >= 65536) + all_k.resize(65535); + if (ServerConfig::m_live_players) + k_available_kts.first = k_official_kts.first; + else + k_available_kts.first = { all_k.begin(), all_k.end() }; +} // onServerSetup + +//----------------------------------------------------------------------------- + +void LobbyAssetManager::eraseAssetsWithPeers(const std::vector>& peers) +{ + std::set karts_erase, tracks_erase; + for (const auto& peer: peers) + { + if (peer) + { + peer->eraseServerKarts(k_available_kts.first, karts_erase); + peer->eraseServerTracks(k_available_kts.second, tracks_erase); + } + } + for (const std::string& kart_erase : karts_erase) + { + k_available_kts.first.erase(kart_erase); + } + for (const std::string& track_erase : tracks_erase) + { + k_available_kts.second.erase(track_erase); + } +} // eraseAssetsWithPeers + +//----------------------------------------------------------------------------- + +bool LobbyAssetManager::tryApplyingMapFilters() +{ + std::set available_tracks_fallback = k_available_kts.second; + m_lobby->applyAllFilters(k_available_kts.second, true); + + /* auto iter = k_available_kts.second.begin(); + while (iter != k_available_kts.second.end()) + { + // Initial version which will be brought into a separate fuction + std::string track = *iter; + if (getTrackMaxPlayers(track) < max_player) + iter = k_available_kts.second.erase(iter); + else + iter++; + }*/ + + if (k_available_kts.second.empty()) + { + k_available_kts.second = available_tracks_fallback; + return false; + } + return true; +} // tryApplyingMapFilters +//----------------------------------------------------------------------------- + +std::string LobbyAssetManager::getRandomAvailableMap() +{ + RandomGenerator rg; + std::set::iterator it = k_available_kts.second.begin(); + std::advance(it, rg.get((int)k_available_kts.second.size())); + return *it; +} // getRandomAvailableMap + +//----------------------------------------------------------------------------- + +void LobbyAssetManager::encodePlayerKartsAndCommonMaps(NetworkString* ns, const std::set& all_k) +{ + const auto& all_t = k_available_kts.second; + + ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size()); + for (const std::string& kart : all_k) + ns->encodeString(kart); + for (const std::string& track : all_t) + ns->encodeString(track); +} // encodePlayerKartsAndCommonMaps + +//----------------------------------------------------------------------------- + +bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer, + const std::set& client_karts, + const std::set& client_tracks) +{ + // Drop this player if he doesn't have at least 1 kart / track the same + // as server + float okt = 0.0f; + float ott = 0.0f; + int addon_karts = 0; + int addon_tracks = 0; + int addon_arenas = 0; + int addon_soccers = 0; + for (auto& client_kart : client_karts) + { + if (k_official_kts.first.find(client_kart) != + k_official_kts.first.end()) + okt += 1.0f; + if (k_addon_kts.first.find(client_kart) != + k_addon_kts.first.end()) + ++addon_karts; + } + okt = okt / (float)k_official_kts.first.size(); + for (auto& client_track : client_tracks) + { + if (k_official_kts.second.find(client_track) != + k_official_kts.second.end()) + ott += 1.0f; + if (k_addon_kts.second.find(client_track) != + k_addon_kts.second.end()) + ++addon_tracks; + if (k_addon_arenas.find(client_track) != + k_addon_arenas.end()) + ++addon_arenas; + if (k_addon_soccers.find(client_track) != + k_addon_soccers.end()) + ++addon_soccers; + } + ott = ott / (float)k_official_kts.second.size(); + + std::set karts_erase, tracks_erase; + for (const std::string& server_kart : k_entering_kts.first) + { + if (client_karts.find(server_kart) == client_karts.end()) + { + karts_erase.insert(server_kart); + } + } + for (const std::string& server_track : k_entering_kts.second) + { + if (client_tracks.find(server_track) == client_tracks.end()) + { + tracks_erase.insert(server_track); + } + } + + Log::info("LobbyAssetManager", "Player has the following addons: %d/%d(%d) karts," + " %d/%d(%d) tracks, %d/%d(%d) arenas, %d/%d(%d) soccer fields.", + addon_karts, (int)ServerConfig::m_addon_karts_join_threshold, + (int)ServerConfig::m_addon_karts_play_threshold, + addon_tracks, (int)ServerConfig::m_addon_tracks_join_threshold, + (int)ServerConfig::m_addon_tracks_play_threshold, + addon_arenas, (int)ServerConfig::m_addon_arenas_join_threshold, + (int)ServerConfig::m_addon_arenas_play_threshold, + addon_soccers, (int)ServerConfig::m_addon_soccers_join_threshold, + (int)ServerConfig::m_addon_soccers_play_threshold); + + bool bad = false; + + bool has_required_tracks = true; + for (const std::string& required_track : m_must_have_maps) + { + if (client_tracks.find(required_track) == client_tracks.end()) + { + has_required_tracks = false; + bad = true; + Log::verbose("LobbyAssetManager", "Player does not have a required track '%s'.", required_track.c_str()); + break; + } + } + + peer->addon_karts_count = addon_karts; + peer->addon_tracks_count = addon_tracks; + peer->addon_arenas_count = addon_arenas; + peer->addon_soccers_count = addon_soccers; + + if (karts_erase.size() == k_entering_kts.first.size()) + { + Log::verbose("LobbyAssetManager", "Bad player: no common karts with server"); + bad = true; + } + + if (tracks_erase.size() == k_entering_kts.second.size()) + { + Log::verbose("LobbyAssetManager", "Bad player: no common tracks with server"); + bad = true; + } + + if (okt < ServerConfig::m_official_karts_threshold) + { + Log::verbose("LobbyAssetManager", "Bad player: bad official kart threshold"); + bad = true; + } + + if (ott < ServerConfig::m_official_tracks_threshold) + { + Log::verbose("LobbyAssetManager", "Bad player: bad official track threshold"); + bad = true; + } + + if (addon_karts < (int)ServerConfig::m_addon_karts_join_threshold) + { + Log::verbose("LobbyAssetManager", "Bad player: too little addon karts"); + bad = true; + } + + if (addon_tracks < (int)ServerConfig::m_addon_tracks_join_threshold) + { + Log::verbose("LobbyAssetManager", "Bad player: too little addon tracks"); + bad = true; + } + + if (addon_arenas < (int)ServerConfig::m_addon_arenas_join_threshold) + { + Log::verbose("LobbyAssetManager", "Bad player: too little addon arenas"); + bad = true; + } + + if (addon_soccers < (int)ServerConfig::m_addon_soccers_join_threshold) + { + Log::verbose("LobbyAssetManager", "Bad player: too little addon soccers"); + bad = true; + } + + if (!has_required_tracks) + { + Log::verbose("LobbyAssetManager", "Bad player: no required tracks"); + bad = true; + } + + return !bad; +} // handleAssetsForPeer + +//----------------------------------------------------------------------------- + +std::array LobbyAssetManager::getAddonScores( + const std::set& client_karts, + const std::set& client_tracks) +{ + + std::array addons_scores = {{ -1, -1, -1, -1 }}; + size_t addon_kart = 0; + size_t addon_track = 0; + size_t addon_arena = 0; + size_t addon_soccer = 0; + + for (auto& kart : k_addon_kts.first) + { + if (client_karts.find(kart) != client_karts.end()) + addon_kart++; + } + for (auto& track : k_addon_kts.second) + { + if (client_tracks.find(track) != client_tracks.end()) + addon_track++; + } + for (auto& arena : k_addon_arenas) + { + if (client_tracks.find(arena) != client_tracks.end()) + addon_arena++; + } + for (auto& soccer : k_addon_soccers) + { + if (client_tracks.find(soccer) != client_tracks.end()) + addon_soccer++; + } + + if (!k_addon_kts.first.empty()) + { + addons_scores[AS_KART] = addon_kart; + } + if (!k_addon_kts.second.empty()) + { + addons_scores[AS_TRACK] = addon_track; + } + if (!k_addon_arenas.empty()) + { + addons_scores[AS_ARENA] = addon_arena; + } + if (!k_addon_soccers.empty()) + { + addons_scores[AS_SOCCER] = addon_soccer; + } + return addons_scores; +} // getAddonScores + +//----------------------------------------------------------------------------- + +std::string LobbyAssetManager::getAnyMapForVote() +{ + return *k_available_kts.second.begin(); +} // getAnyMapForVote + +//----------------------------------------------------------------------------- + +bool LobbyAssetManager::checkIfNoCommonMaps( + const std::pair, std::set>& assets) +{ + std::set tracks_erase; + for (const std::string& server_track : k_available_kts.second) + { + if (assets.second.find(server_track) == assets.second.end()) + { + tracks_erase.insert(server_track); + } + } + return tracks_erase.size() == k_available_kts.second.size(); +} // getAnyMapForVote + +//----------------------------------------------------------------------------- + +bool LobbyAssetManager::isKartAvailable(const std::string& kart) const +{ + return k_available_kts.first.find(kart) != k_available_kts.first.end(); +} // getAnyMapForVote + +//----------------------------------------------------------------------------- + +float LobbyAssetManager::officialKartsFraction(const std::set& clientKarts) const +{ + int karts_count = 0; + for (auto& kart : clientKarts) + { + if (k_official_kts.first.find(kart) != k_official_kts.first.end()) + karts_count += 1; + } + return karts_count / (float)k_official_kts.first.size(); +} // officialKartsFraction + +//----------------------------------------------------------------------------- + +float LobbyAssetManager::officialMapsFraction(const std::set& clientMaps) const +{ + int maps_count = 0; + for (auto& map : clientMaps) + { + if (k_official_kts.second.find(map) != k_official_kts.second.end()) + maps_count += 1; + } + return maps_count / (float)k_official_kts.second.size(); +} // officialMapsFraction + +//----------------------------------------------------------------------------- + +std::string LobbyAssetManager::getRandomMap() const +{ + std::set items; + for (const std::string& s: k_entering_kts.second) { + items.insert(s); + } + m_lobby->applyAllFilters(items, false); + if (items.empty()) + return ""; + RandomGenerator rg; + std::set::iterator it = items.begin(); + std::advance(it, rg.get((int)items.size())); + return *it; +} // getRandomMap + +// ======================================================================== + +std::string LobbyAssetManager::getRandomAddonMap() const +{ + std::set items; + for (const std::string& s: k_entering_kts.second) { + Track* t = track_manager->getTrack(s); + if (t->isAddon()) + items.insert(s); + } + m_lobby->applyAllFilters(items, false); + if (items.empty()) + return ""; + RandomGenerator rg; + std::set::iterator it = items.begin(); + std::advance(it, rg.get((int)items.size())); + return *it; +} // getRandomAddonMap + +// ======================================================================== \ No newline at end of file diff --git a/src/utils/lobby_asset_manager.hpp b/src/utils/lobby_asset_manager.hpp new file mode 100644 index 00000000000..980746df5c7 --- /dev/null +++ b/src/utils/lobby_asset_manager.hpp @@ -0,0 +1,108 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef LOBBY_ASSET_MANAGER_HPP +#define LOBBY_ASSET_MANAGER_HPP + +#include "utils/types.hpp" + +#include +#include +#include +#include +class ServerLobby; +class STKPeer; + +class LobbyAssetManager +{ +public: + LobbyAssetManager(ServerLobby* lobby); + + void init(); + + void updateAddons(); + void updateMapsForMode(RaceManager::MinorRaceModeType mode); + void onServerSetup(); + void eraseAssetsWithPeers(const std::vector>& peers); + bool tryApplyingMapFilters(); + std::string getRandomAvailableMap(); + void encodePlayerKartsAndCommonMaps(NetworkString* ns, const std::set& all_k); + bool handleAssetsForPeer(std::shared_ptr peer, + const std::set& client_karts, + const std::set& client_maps); + std::array getAddonScores( + const std::set& client_karts, + const std::set& client_maps); + std::string getAnyMapForVote(); + bool checkIfNoCommonMaps( + const std::pair, std::set>& assets); + bool isKartAvailable(const std::string& kart) const; + float officialKartsFraction(const std::set& clientKarts) const; + float officialMapsFraction(const std::set& clientMaps) const; + + + std::string getRandomMap() const; + std::string getRandomAddonMap() const; + + std::set getAvailableKarts() const + { return k_available_kts.first; } + void setMustHaveMaps(const std::string& input) + { m_must_have_maps = StringUtils::split(input, ' ', false); } + + std::set getAddonKarts() const { return k_addon_kts.first; } + std::set getAddonTracks() const { return k_addon_kts.second; } + std::set getAddonArenas() const { return k_addon_arenas; } + std::set getAddonSoccers() const { return k_addon_soccers; } + + bool hasAddonKart(const std::string& id) const + { return k_addon_kts.first.find(id) != k_addon_kts.first.end(); } + bool hasAddonTrack(const std::string& id) const + { return k_addon_kts.second.find(id) != k_addon_kts.second.end(); } + bool hasAddonArena(const std::string& id) const + { return k_addon_arenas.find(id) != k_addon_arenas.end(); } + bool hasAddonSoccer(const std::string& id) const + { return k_addon_soccers.find(id) != k_addon_soccers.end(); } + +private: + ServerLobby* m_lobby; + +public: + /** Official karts and maps available in server. */ + std::pair, std::set > k_official_kts; + + /** Addon karts and maps available in server. */ + std::pair, std::set > k_addon_kts; + + /** Addon arenas available in server. */ + std::set k_addon_arenas; + + /** Addon soccers available in server. */ + std::set k_addon_soccers; + + /** Available karts and maps for all clients, this will be initialized + * with data in server first. */ + std::pair, std::set > k_available_kts; + + /** Available karts and maps for all clients, this will be initialized + * with data in server first. */ + std::pair, std::set > k_entering_kts; + + std::vector m_must_have_maps; +}; + +#endif From 77979c227967f044e63e8b6d3233f3ff5d48627c Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 23 Feb 2025 20:29:58 +0400 Subject: [PATCH 575/830] Less includes, more shared_ptrs, and a few renames --- src/network/protocols/command_manager.cpp | 18 +-- src/network/protocols/server_lobby.cpp | 64 +++++---- src/network/protocols/server_lobby.hpp | 14 +- src/utils/lobby_asset_manager.cpp | 166 ++++++++++++---------- src/utils/lobby_asset_manager.hpp | 33 +++-- 5 files changed, 155 insertions(+), 140 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 15c0967eef5..b4b880d212a 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -35,8 +35,10 @@ #include "utils/file_utils.hpp" #include "utils/hit_processor.hpp" #include "utils/hourglass_reason.hpp" +#include "utils/kart_elimination.hpp" #include "utils/lobby_asset_manager.hpp" #include "utils/log.hpp" +#include "utils/map_vote_handler.hpp" #include "utils/random_generator.hpp" #include "utils/string_utils.hpp" @@ -2142,13 +2144,13 @@ void CommandManager::process_gnu(Context& context) } // "nognu" and "gnu off" are equivalent bool turn_on = (argv.size() < 2 || argv[1] != "off"); - if (turn_on && m_lobby->m_kart_elimination.isEnabled()) + if (turn_on && m_lobby->m_kart_elimination->isEnabled()) { std::string msg = "Gnu Elimination mode was already enabled!"; m_lobby->sendStringToPeer(msg, peer); return; } - if (!turn_on && !m_lobby->m_kart_elimination.isEnabled()) + if (!turn_on && !m_lobby->m_kart_elimination->isEnabled()) { std::string msg = "Gnu Elimination mode was already off!"; m_lobby->sendStringToPeer(msg, peer); @@ -2198,14 +2200,14 @@ void CommandManager::process_gnu(Context& context) m_votables["gnu"].reset("gnu kart"); if (kart == "off") { - m_lobby->m_kart_elimination.disable(); + m_lobby->m_kart_elimination->disable(); std::string msg = "Gnu Elimination is now off"; m_lobby->sendStringToAllPeers(msg); } else { - m_lobby->m_kart_elimination.enable(kart); - std::string msg = m_lobby->m_kart_elimination.getStartingMessage(); + m_lobby->m_kart_elimination->enable(kart); + std::string msg = m_lobby->m_kart_elimination->getStartingMessage(); m_lobby->sendStringToAllPeers(msg); } } // process_gnu @@ -2277,7 +2279,7 @@ void CommandManager::process_standings(Context& context) msg = m_lobby->getGrandPrixStandings(isGPPlayers, isGPTeams); } else if (isGnu) - msg = m_lobby->m_kart_elimination.getStandings(); + msg = m_lobby->m_kart_elimination->getStandings(); m_lobby->sendStringToPeer(msg, peer); } // process_standings // ======================================================================== @@ -3981,7 +3983,7 @@ void CommandManager::process_voting(Context& context) return; } std::string msg = StringUtils::insertValues("Voting method: %d", - m_lobby->m_map_vote_handler.getAlgorithm()); + m_lobby->m_map_vote_handler->getAlgorithm()); m_lobby->sendStringToPeer(msg, peer); } // process_voting // ======================================================================== @@ -4007,7 +4009,7 @@ void CommandManager::process_voting_assign(Context& context) error(context); return; } - m_lobby->m_map_vote_handler.setAlgorithm(value); + m_lobby->m_map_vote_handler->setAlgorithm(value); msg = StringUtils::insertValues("Set voting method to %s", value); m_lobby->sendStringToPeer(msg, peer); } // process_voting_assign diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 7f7d3e776ae..c8ac3fdd9c4 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -34,6 +34,7 @@ #include "network/network_player_profile.hpp" #include "network/protocol_manager.hpp" #include "network/protocols/connect_to_peer.hpp" +#include "network/protocols/command_manager.hpp" #include "network/protocols/game_protocol.hpp" #include "network/protocols/game_events_protocol.hpp" #include "network/protocols/ranking.hpp" @@ -47,9 +48,11 @@ #include "tracks/check_manager.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" +#include "utils/kart_elimination.hpp" #include "utils/game_info.hpp" #include "utils/hit_processor.hpp" #include "utils/lobby_asset_manager.hpp" +#include "utils/map_vote_handler.hpp" #include "utils/translation.hpp" #include @@ -111,11 +114,14 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_help_message = getGameSetup()->readOrLoadFromFile ((std::string) ServerConfig::m_help); - m_command_manager = CommandManager(nullptr); + m_command_manager = std::make_shared(nullptr); m_shuffle_gp = ServerConfig::m_shuffle_gp; m_current_max_players_in_game.store(ServerConfig::m_max_players_in_game); m_consent_on_replays = false; + m_kart_elimination = std::make_shared(); + m_map_vote_handler = std::make_shared(); + m_fixed_lap = ServerConfig::m_fixed_lap_count; // Server config has better priority than --laps // as it is more flexible and was introduced earlier @@ -134,7 +140,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_available_teams = ServerConfig::m_init_available_teams; - m_map_vote_handler.setAlgorithm(ServerConfig::m_map_vote_handling); + m_map_vote_handler->setAlgorithm(ServerConfig::m_map_vote_handling); initAvailableModes(); @@ -272,7 +278,7 @@ void ServerLobby::setup() resetPeersReady(); m_timeout.store(std::numeric_limits::max()); m_server_started_at = m_server_delay = 0; - getCommandManager().onResetServer(); + getCommandManager()->onResetServer(); if (m_game_info) delete m_game_info; m_game_info = nullptr; @@ -2115,7 +2121,7 @@ void ServerLobby::startSelection(const Event *event) } if (!hasHostRights(peer)) { - auto argv = getCommandManager().getCurrentArgv(); + auto argv = getCommandManager()->getCurrentArgv(); if (argv.empty() || argv[0] != "start") { Log::warn("ServerLobby", "Client %d is not authorised to start selection.", @@ -2367,10 +2373,10 @@ void ServerLobby::startSelection(const Event *event) // std::string username = StringUtils::wideToUtf8(profile->getName()); applyAllKartFilters(username, all_k); - if (!m_kart_elimination.getRemainingParticipants().empty() && m_kart_elimination.getRemainingParticipants().count(username) == 0) + if (!m_kart_elimination->getRemainingParticipants().empty() && m_kart_elimination->getRemainingParticipants().count(username) == 0) { - if (all_k.count(m_kart_elimination.getKart())) - all_k = {m_kart_elimination.getKart()}; + if (all_k.count(m_kart_elimination->getKart())) + all_k = {m_kart_elimination->getKart()}; else all_k = {}; } @@ -2422,7 +2428,7 @@ void ServerLobby::startSelection(const Event *event) m_gp_team_scores.clear(); } - getCommandManager().onStartSelection(); + getCommandManager()->onStartSelection(); } // startSelection //----------------------------------------------------------------------------- @@ -2678,7 +2684,7 @@ void ServerLobby::checkRaceFinished() ranking_changes_indication = 1; m_result_ns->addUInt8(ranking_changes_indication); - if (m_kart_elimination.isEnabled()) + if (m_kart_elimination->isEnabled()) { // ServerLobby's function because we need to take // the list of players from somewhere @@ -2813,7 +2819,7 @@ void ServerLobby::clientDisconnected(Event* event) std::string name = StringUtils::wideToUtf8(p->getName()); msg->encodeString(name); Log::info("ServerLobby", "%s disconnected", name.c_str()); - getCommandManager().deleteUser(name); + getCommandManager()->deleteUser(name); } unsigned players_number; @@ -3232,7 +3238,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, setTeamInLobby(player, KART_TEAM_BLUE); } } - getCommandManager().addUser(username); + getCommandManager()->addUser(username); if (m_game_setup->isGrandPrix()) { auto it = m_gp_scores.find(username); @@ -3357,14 +3363,14 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, #ifdef ENABLE_SQLITE3 m_db_connector->onPlayerJoinQueries(peer, online_id, player_count, country_code); #endif - if (m_kart_elimination.isEnabled()) + if (m_kart_elimination->isEnabled()) { bool hasEliminatedPlayer = false; for (unsigned i = 0; i < peer->getPlayerProfiles().size(); ++i) { std::string name = StringUtils::wideToUtf8( peer->getPlayerProfiles()[i]->getName()); - if (m_kart_elimination.isEliminated(name)) + if (m_kart_elimination->isEliminated(name)) { hasEliminatedPlayer = true; break; @@ -3373,7 +3379,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); - std::string warning = m_kart_elimination.getWarningMessage(hasEliminatedPlayer); + std::string warning = m_kart_elimination->getWarningMessage(hasEliminatedPlayer); chat->encodeString16(StringUtils::utf8ToWide(warning)); peer->sendPacket(chat, PRM_RELIABLE); delete chat; @@ -3768,7 +3774,7 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote, cur_players++; } - return m_map_vote_handler.handleAllVotes( + return m_map_vote_handler->handleAllVotes( m_peers_votes, getRemainingVotingTime(), getMaxVotingTime(), @@ -4355,7 +4361,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, { int final_number, players_number; m_team_for_player.clear(); - m_command_manager.assignRandomTeams(2, &final_number, &players_number); + m_command_manager->assignRandomTeams(2, &final_number, &players_number); } else { @@ -4381,11 +4387,11 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, delete server_info; updatePlayerList(); - if (m_kart_elimination.isEnabled() && + if (m_kart_elimination->isEnabled() && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_NORMAL_RACE && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) { - m_kart_elimination.disable(); + m_kart_elimination->disable(); NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); @@ -4606,9 +4612,9 @@ void ServerLobby::setPlayerKarts(const NetworkString& ns, std::shared_ptrgetPlayerProfiles()[i]->getName()); - if (m_kart_elimination.isEliminated(username)) + if (m_kart_elimination->isEliminated(username)) { - peer->getPlayerProfiles()[i]->setKartName(m_kart_elimination.getKart()); + peer->getPlayerProfiles()[i]->setKartName(m_kart_elimination->getKart()); continue; } std::string current_kart = kart; @@ -4951,7 +4957,7 @@ void ServerLobby::handleServerCommand(Event* event, { if (peer.get()) peer->updateLastActivity(); - getCommandManager().handleCommand(event, peer); + getCommandManager()->handleCommand(event, peer); } // handleServerCommand //----------------------------------------------------------------------------- void ServerLobby::updateGnuElimination() @@ -4968,7 +4974,7 @@ void ServerLobby::updateGnuElimination() else order[username] = RaceManager::get()->getKartRaceTime(i); } - std::string msg = m_kart_elimination.update(order); + std::string msg = m_kart_elimination->update(order); if (!msg.empty()) sendStringToAllPeers(msg); } // updateGnuElimination @@ -5249,7 +5255,7 @@ void ServerLobby::resetToDefaultSettings() handleServerConfiguration(NULL); if (!m_preserve.count("elim")) - m_kart_elimination.disable(); + m_kart_elimination->disable(); if (!m_preserve.count("laps")) { @@ -5954,11 +5960,11 @@ void ServerLobby::updateTournamentRole(std::shared_ptr peer) } // updateTournamentRole //----------------------------------------------------------------------------- -CommandManager& ServerLobby::getCommandManager() +std::shared_ptr ServerLobby::getCommandManager() { - if (!m_command_manager.isInitialized()) + if (!m_command_manager->isInitialized()) { - m_command_manager = CommandManager(this); + m_command_manager = std::make_shared(this); } return m_command_manager; } // getCommandManager @@ -6217,10 +6223,10 @@ std::string ServerLobby::getKartForBadKartChoice(std::shared_ptr peer, { std::set karts = (peer->isAIPeer() ? m_asset_manager->getAvailableKarts() : peer->getClientAssets().first); applyAllKartFilters(username, karts, true); - if (m_kart_elimination.isEliminated(username) - && karts.count(m_kart_elimination.getKart())) + if (m_kart_elimination->isEliminated(username) + && karts.count(m_kart_elimination->getKart())) { - return m_kart_elimination.getKart(); + return m_kart_elimination->getKart(); } if (!check_choice.empty() && karts.count(check_choice)) // valid choice return check_choice; diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 20f10950f10..2cdb7f55df0 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -21,14 +21,11 @@ #include "network/protocols/lobby_protocol.hpp" #include "utils/cpp2011.hpp" -#include "utils/kart_elimination.hpp" #include "utils/team_utils.hpp" #include "utils/time.hpp" #include "utils/track_filter.hpp" -#include "utils/map_vote_handler.hpp" #include "utils/hourglass_reason.hpp" #include "karts/controller/player_controller.hpp" -#include "network/protocols/command_manager.hpp" #include "irrString.h" @@ -54,6 +51,9 @@ enum AlwaysSpectateMode: uint8_t; class Ranking; class HitProcessor; class LobbyAssetManager; +class CommandManager; +class KartElimination; +class MapVoteHandler; namespace Online { @@ -242,9 +242,9 @@ class ServerLobby : public LobbyProtocol std::map, int> m_why_peer_cannot_play; - KartElimination m_kart_elimination; + std::shared_ptr m_kart_elimination; - MapVoteHandler m_map_vote_handler; + std::shared_ptr m_map_vote_handler; std::set m_available_difficulties; @@ -350,7 +350,7 @@ class ServerLobby : public LobbyProtocol bool m_troll_active; friend CommandManager; - CommandManager m_command_manager; + std::shared_ptr m_command_manager; // connection management void clientDisconnected(Event* event); @@ -482,7 +482,7 @@ class ServerLobby : public LobbyProtocol bool tournamentGoalsLimit(int game) const; bool tournamentColorsSwapped(int game) const; void updateTournamentRole(std::shared_ptr peer); - CommandManager& getCommandManager(); + std::shared_ptr getCommandManager(); // bool tournamentHasIcy(int game) const; #ifdef ENABLE_WEB_SUPPORT diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp index 5f316432325..919947bb7d7 100644 --- a/src/utils/lobby_asset_manager.cpp +++ b/src/utils/lobby_asset_manager.cpp @@ -27,6 +27,7 @@ #include "tracks/track_manager.hpp" #include "utils/lobby_asset_manager.hpp" #include "utils/random_generator.hpp" +#include "utils/string_utils.hpp" LobbyAssetManager::LobbyAssetManager(ServerLobby* lobby): m_lobby(lobby) { @@ -48,22 +49,22 @@ void LobbyAssetManager::init() all_t.insert(all_t.end(), all_arenas.begin(), all_arenas.end()); all_t.insert(all_t.end(), all_soccers.begin(), all_soccers.end()); - k_official_kts.first = OfficialKarts::getOfficialKarts(); + m_official_kts.first = OfficialKarts::getOfficialKarts(); for (int track : all_t) { Track* t = track_manager->getTrack(track); if (!t->isAddon()) - k_official_kts.second.insert(t->getIdent()); + m_official_kts.second.insert(t->getIdent()); } } // init // ======================================================================== void LobbyAssetManager::updateAddons() { - k_addon_kts.first.clear(); - k_addon_kts.second.clear(); - k_addon_arenas.clear(); - k_addon_soccers.clear(); + m_addon_kts.first.clear(); + m_addon_kts.second.clear(); + m_addon_arenas.clear(); + m_addon_soccers.clear(); std::set total_addons; for (unsigned i = 0; i < kart_properties_manager->getNumberOfKarts(); i++) @@ -85,18 +86,18 @@ void LobbyAssetManager::updateAddons() const KartProperties* kp = kart_properties_manager->getKart(addon); if (kp && kp->isAddon()) { - k_addon_kts.first.insert(kp->getIdent()); + m_addon_kts.first.insert(kp->getIdent()); continue; } Track* t = track_manager->getTrack(addon); if (!t || !t->isAddon() || t->isInternal()) continue; if (t->isArena()) - k_addon_arenas.insert(t->getIdent()); + m_addon_arenas.insert(t->getIdent()); if (t->isSoccer()) - k_addon_soccers.insert(t->getIdent()); + m_addon_soccers.insert(t->getIdent()); if (!t->isArena() && !t->isSoccer()) - k_addon_kts.second.insert(t->getIdent()); + m_addon_kts.second.insert(t->getIdent()); } std::vector all_k; @@ -112,10 +113,10 @@ void LobbyAssetManager::updateAddons() for (const std::string& k : oks) all_k.push_back(k); if (ServerConfig::m_live_players) - k_available_kts.first = k_official_kts.first; + m_available_kts.first = m_official_kts.first; else - k_available_kts.first = { all_k.begin(), all_k.end() }; - k_entering_kts = k_available_kts; + m_available_kts.first = { all_k.begin(), all_k.end() }; + m_entering_kts = m_available_kts; } // updateAddons //----------------------------------------------------------------------------- @@ -126,20 +127,20 @@ void LobbyAssetManager::updateMapsForMode(RaceManager::MinorRaceModeType mode) auto all_t = track_manager->getAllTrackIdentifiers(); if (all_t.size() >= 65536) all_t.resize(65535); - k_available_kts.second = { all_t.begin(), all_t.end() }; + m_available_kts.second = { all_t.begin(), all_t.end() }; switch (mode) { case RaceManager::MINOR_MODE_NORMAL_RACE: case RaceManager::MINOR_MODE_TIME_TRIAL: case RaceManager::MINOR_MODE_FOLLOW_LEADER: { - auto it = k_available_kts.second.begin(); - while (it != k_available_kts.second.end()) + auto it = m_available_kts.second.begin(); + while (it != m_available_kts.second.end()) { Track* t = track_manager->getTrack(*it); if (t->isArena() || t->isSoccer() || t->isInternal()) { - it = k_available_kts.second.erase(it); + it = m_available_kts.second.erase(it); } else it++; @@ -149,8 +150,8 @@ void LobbyAssetManager::updateMapsForMode(RaceManager::MinorRaceModeType mode) case RaceManager::MINOR_MODE_FREE_FOR_ALL: case RaceManager::MINOR_MODE_CAPTURE_THE_FLAG: { - auto it = k_available_kts.second.begin(); - while (it != k_available_kts.second.end()) + auto it = m_available_kts.second.begin(); + while (it != m_available_kts.second.end()) { Track* t = track_manager->getTrack(*it); if (RaceManager::get()->getMinorMode() == @@ -158,7 +159,7 @@ void LobbyAssetManager::updateMapsForMode(RaceManager::MinorRaceModeType mode) { if (!t->isCTF() || t->isInternal()) { - it = k_available_kts.second.erase(it); + it = m_available_kts.second.erase(it); } else it++; @@ -167,7 +168,7 @@ void LobbyAssetManager::updateMapsForMode(RaceManager::MinorRaceModeType mode) { if (!t->isArena() || t->isInternal()) { - it = k_available_kts.second.erase(it); + it = m_available_kts.second.erase(it); } else it++; @@ -177,13 +178,13 @@ void LobbyAssetManager::updateMapsForMode(RaceManager::MinorRaceModeType mode) } case RaceManager::MINOR_MODE_SOCCER: { - auto it = k_available_kts.second.begin(); - while (it != k_available_kts.second.end()) + auto it = m_available_kts.second.begin(); + while (it != m_available_kts.second.end()) { Track* t = track_manager->getTrack(*it); if (!t->isSoccer() || t->isInternal()) { - it = k_available_kts.second.erase(it); + it = m_available_kts.second.erase(it); } else it++; @@ -194,7 +195,7 @@ void LobbyAssetManager::updateMapsForMode(RaceManager::MinorRaceModeType mode) assert(false); break; } - k_entering_kts = k_available_kts; + m_entering_kts = m_available_kts; } // updateMapsForMode //----------------------------------------------------------------------------- @@ -206,9 +207,9 @@ void LobbyAssetManager::onServerSetup() if (all_k.size() >= 65536) all_k.resize(65535); if (ServerConfig::m_live_players) - k_available_kts.first = k_official_kts.first; + m_available_kts.first = m_official_kts.first; else - k_available_kts.first = { all_k.begin(), all_k.end() }; + m_available_kts.first = { all_k.begin(), all_k.end() }; } // onServerSetup //----------------------------------------------------------------------------- @@ -220,17 +221,17 @@ void LobbyAssetManager::eraseAssetsWithPeers(const std::vectoreraseServerKarts(k_available_kts.first, karts_erase); - peer->eraseServerTracks(k_available_kts.second, tracks_erase); + peer->eraseServerKarts(m_available_kts.first, karts_erase); + peer->eraseServerTracks(m_available_kts.second, tracks_erase); } } for (const std::string& kart_erase : karts_erase) { - k_available_kts.first.erase(kart_erase); + m_available_kts.first.erase(kart_erase); } for (const std::string& track_erase : tracks_erase) { - k_available_kts.second.erase(track_erase); + m_available_kts.second.erase(track_erase); } } // eraseAssetsWithPeers @@ -238,23 +239,23 @@ void LobbyAssetManager::eraseAssetsWithPeers(const std::vector available_tracks_fallback = k_available_kts.second; - m_lobby->applyAllFilters(k_available_kts.second, true); + std::set available_tracks_fallback = m_available_kts.second; + m_lobby->applyAllFilters(m_available_kts.second, true); - /* auto iter = k_available_kts.second.begin(); - while (iter != k_available_kts.second.end()) + /* auto iter = m_available_kts.second.begin(); + while (iter != m_available_kts.second.end()) { // Initial version which will be brought into a separate fuction std::string track = *iter; if (getTrackMaxPlayers(track) < max_player) - iter = k_available_kts.second.erase(iter); + iter = m_available_kts.second.erase(iter); else iter++; }*/ - if (k_available_kts.second.empty()) + if (m_available_kts.second.empty()) { - k_available_kts.second = available_tracks_fallback; + m_available_kts.second = available_tracks_fallback; return false; } return true; @@ -264,8 +265,8 @@ bool LobbyAssetManager::tryApplyingMapFilters() std::string LobbyAssetManager::getRandomAvailableMap() { RandomGenerator rg; - std::set::iterator it = k_available_kts.second.begin(); - std::advance(it, rg.get((int)k_available_kts.second.size())); + std::set::iterator it = m_available_kts.second.begin(); + std::advance(it, rg.get((int)m_available_kts.second.size())); return *it; } // getRandomAvailableMap @@ -273,7 +274,7 @@ std::string LobbyAssetManager::getRandomAvailableMap() void LobbyAssetManager::encodePlayerKartsAndCommonMaps(NetworkString* ns, const std::set& all_k) { - const auto& all_t = k_available_kts.second; + const auto& all_t = m_available_kts.second; ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size()); for (const std::string& kart : all_k) @@ -298,40 +299,40 @@ bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer, int addon_soccers = 0; for (auto& client_kart : client_karts) { - if (k_official_kts.first.find(client_kart) != - k_official_kts.first.end()) + if (m_official_kts.first.find(client_kart) != + m_official_kts.first.end()) okt += 1.0f; - if (k_addon_kts.first.find(client_kart) != - k_addon_kts.first.end()) + if (m_addon_kts.first.find(client_kart) != + m_addon_kts.first.end()) ++addon_karts; } - okt = okt / (float)k_official_kts.first.size(); + okt = okt / (float)m_official_kts.first.size(); for (auto& client_track : client_tracks) { - if (k_official_kts.second.find(client_track) != - k_official_kts.second.end()) + if (m_official_kts.second.find(client_track) != + m_official_kts.second.end()) ott += 1.0f; - if (k_addon_kts.second.find(client_track) != - k_addon_kts.second.end()) + if (m_addon_kts.second.find(client_track) != + m_addon_kts.second.end()) ++addon_tracks; - if (k_addon_arenas.find(client_track) != - k_addon_arenas.end()) + if (m_addon_arenas.find(client_track) != + m_addon_arenas.end()) ++addon_arenas; - if (k_addon_soccers.find(client_track) != - k_addon_soccers.end()) + if (m_addon_soccers.find(client_track) != + m_addon_soccers.end()) ++addon_soccers; } - ott = ott / (float)k_official_kts.second.size(); + ott = ott / (float)m_official_kts.second.size(); std::set karts_erase, tracks_erase; - for (const std::string& server_kart : k_entering_kts.first) + for (const std::string& server_kart : m_entering_kts.first) { if (client_karts.find(server_kart) == client_karts.end()) { karts_erase.insert(server_kart); } } - for (const std::string& server_track : k_entering_kts.second) + for (const std::string& server_track : m_entering_kts.second) { if (client_tracks.find(server_track) == client_tracks.end()) { @@ -369,13 +370,13 @@ bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer, peer->addon_arenas_count = addon_arenas; peer->addon_soccers_count = addon_soccers; - if (karts_erase.size() == k_entering_kts.first.size()) + if (karts_erase.size() == m_entering_kts.first.size()) { Log::verbose("LobbyAssetManager", "Bad player: no common karts with server"); bad = true; } - if (tracks_erase.size() == k_entering_kts.second.size()) + if (tracks_erase.size() == m_entering_kts.second.size()) { Log::verbose("LobbyAssetManager", "Bad player: no common tracks with server"); bad = true; @@ -439,40 +440,40 @@ std::array LobbyAssetManager::getAddonScores( size_t addon_arena = 0; size_t addon_soccer = 0; - for (auto& kart : k_addon_kts.first) + for (auto& kart : m_addon_kts.first) { if (client_karts.find(kart) != client_karts.end()) addon_kart++; } - for (auto& track : k_addon_kts.second) + for (auto& track : m_addon_kts.second) { if (client_tracks.find(track) != client_tracks.end()) addon_track++; } - for (auto& arena : k_addon_arenas) + for (auto& arena : m_addon_arenas) { if (client_tracks.find(arena) != client_tracks.end()) addon_arena++; } - for (auto& soccer : k_addon_soccers) + for (auto& soccer : m_addon_soccers) { if (client_tracks.find(soccer) != client_tracks.end()) addon_soccer++; } - if (!k_addon_kts.first.empty()) + if (!m_addon_kts.first.empty()) { addons_scores[AS_KART] = addon_kart; } - if (!k_addon_kts.second.empty()) + if (!m_addon_kts.second.empty()) { addons_scores[AS_TRACK] = addon_track; } - if (!k_addon_arenas.empty()) + if (!m_addon_arenas.empty()) { addons_scores[AS_ARENA] = addon_arena; } - if (!k_addon_soccers.empty()) + if (!m_addon_soccers.empty()) { addons_scores[AS_SOCCER] = addon_soccer; } @@ -483,7 +484,7 @@ std::array LobbyAssetManager::getAddonScores( std::string LobbyAssetManager::getAnyMapForVote() { - return *k_available_kts.second.begin(); + return *m_available_kts.second.begin(); } // getAnyMapForVote //----------------------------------------------------------------------------- @@ -492,22 +493,22 @@ bool LobbyAssetManager::checkIfNoCommonMaps( const std::pair, std::set>& assets) { std::set tracks_erase; - for (const std::string& server_track : k_available_kts.second) + for (const std::string& server_track : m_available_kts.second) { if (assets.second.find(server_track) == assets.second.end()) { tracks_erase.insert(server_track); } } - return tracks_erase.size() == k_available_kts.second.size(); -} // getAnyMapForVote + return tracks_erase.size() == m_available_kts.second.size(); +} // checkIfNoCommonMaps //----------------------------------------------------------------------------- bool LobbyAssetManager::isKartAvailable(const std::string& kart) const { - return k_available_kts.first.find(kart) != k_available_kts.first.end(); -} // getAnyMapForVote + return m_available_kts.first.find(kart) != m_available_kts.first.end(); +} // isKartAvailable //----------------------------------------------------------------------------- @@ -516,10 +517,10 @@ float LobbyAssetManager::officialKartsFraction(const std::set& clie int karts_count = 0; for (auto& kart : clientKarts) { - if (k_official_kts.first.find(kart) != k_official_kts.first.end()) + if (m_official_kts.first.find(kart) != m_official_kts.first.end()) karts_count += 1; } - return karts_count / (float)k_official_kts.first.size(); + return karts_count / (float)m_official_kts.first.size(); } // officialKartsFraction //----------------------------------------------------------------------------- @@ -529,10 +530,10 @@ float LobbyAssetManager::officialMapsFraction(const std::set& clien int maps_count = 0; for (auto& map : clientMaps) { - if (k_official_kts.second.find(map) != k_official_kts.second.end()) + if (m_official_kts.second.find(map) != m_official_kts.second.end()) maps_count += 1; } - return maps_count / (float)k_official_kts.second.size(); + return maps_count / (float)m_official_kts.second.size(); } // officialMapsFraction //----------------------------------------------------------------------------- @@ -540,7 +541,7 @@ float LobbyAssetManager::officialMapsFraction(const std::set& clien std::string LobbyAssetManager::getRandomMap() const { std::set items; - for (const std::string& s: k_entering_kts.second) { + for (const std::string& s: m_entering_kts.second) { items.insert(s); } m_lobby->applyAllFilters(items, false); @@ -557,7 +558,7 @@ std::string LobbyAssetManager::getRandomMap() const std::string LobbyAssetManager::getRandomAddonMap() const { std::set items; - for (const std::string& s: k_entering_kts.second) { + for (const std::string& s: m_entering_kts.second) { Track* t = track_manager->getTrack(s); if (t->isAddon()) items.insert(s); @@ -571,4 +572,11 @@ std::string LobbyAssetManager::getRandomAddonMap() const return *it; } // getRandomAddonMap +// ======================================================================== + +void LobbyAssetManager::setMustHaveMaps(const std::string& input) +{ + m_must_have_maps = StringUtils::split(input, ' ', false); +} // setMustHaveMaps + // ======================================================================== \ No newline at end of file diff --git a/src/utils/lobby_asset_manager.hpp b/src/utils/lobby_asset_manager.hpp index 980746df5c7..107b6e4bc6a 100644 --- a/src/utils/lobby_asset_manager.hpp +++ b/src/utils/lobby_asset_manager.hpp @@ -60,47 +60,46 @@ class LobbyAssetManager std::string getRandomAddonMap() const; std::set getAvailableKarts() const - { return k_available_kts.first; } - void setMustHaveMaps(const std::string& input) - { m_must_have_maps = StringUtils::split(input, ' ', false); } + { return m_available_kts.first; } + void setMustHaveMaps(const std::string& input); - std::set getAddonKarts() const { return k_addon_kts.first; } - std::set getAddonTracks() const { return k_addon_kts.second; } - std::set getAddonArenas() const { return k_addon_arenas; } - std::set getAddonSoccers() const { return k_addon_soccers; } + std::set getAddonKarts() const { return m_addon_kts.first; } + std::set getAddonTracks() const { return m_addon_kts.second; } + std::set getAddonArenas() const { return m_addon_arenas; } + std::set getAddonSoccers() const { return m_addon_soccers; } bool hasAddonKart(const std::string& id) const - { return k_addon_kts.first.find(id) != k_addon_kts.first.end(); } + { return m_addon_kts.first.find(id) != m_addon_kts.first.end(); } bool hasAddonTrack(const std::string& id) const - { return k_addon_kts.second.find(id) != k_addon_kts.second.end(); } + { return m_addon_kts.second.find(id) != m_addon_kts.second.end(); } bool hasAddonArena(const std::string& id) const - { return k_addon_arenas.find(id) != k_addon_arenas.end(); } + { return m_addon_arenas.find(id) != m_addon_arenas.end(); } bool hasAddonSoccer(const std::string& id) const - { return k_addon_soccers.find(id) != k_addon_soccers.end(); } + { return m_addon_soccers.find(id) != m_addon_soccers.end(); } private: ServerLobby* m_lobby; public: /** Official karts and maps available in server. */ - std::pair, std::set > k_official_kts; + std::pair, std::set > m_official_kts; /** Addon karts and maps available in server. */ - std::pair, std::set > k_addon_kts; + std::pair, std::set > m_addon_kts; /** Addon arenas available in server. */ - std::set k_addon_arenas; + std::set m_addon_arenas; /** Addon soccers available in server. */ - std::set k_addon_soccers; + std::set m_addon_soccers; /** Available karts and maps for all clients, this will be initialized * with data in server first. */ - std::pair, std::set > k_available_kts; + std::pair, std::set > m_available_kts; /** Available karts and maps for all clients, this will be initialized * with data in server first. */ - std::pair, std::set > k_entering_kts; + std::pair, std::set > m_entering_kts; std::vector m_must_have_maps; }; From 34e535547bd5bb4352ccaf2271b75353f479a995 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 25 Feb 2025 03:01:11 +0400 Subject: [PATCH 576/830] Tournament stuff moved out (initial commit) Barely compilable version, haven't been run even. That goes to next commits --- src/network/protocols/command_manager.cpp | 247 +++++------ src/network/protocols/command_manager.hpp | 2 + src/network/protocols/server_lobby.cpp | 345 +++------------ src/network/protocols/server_lobby.hpp | 52 +-- src/utils/lobby_asset_manager.cpp | 3 +- src/utils/lobby_asset_manager.hpp | 4 + src/utils/set_with_flip.hpp | 72 ++++ src/utils/tournament.cpp | 495 ++++++++++++++++++++++ src/utils/tournament.hpp | 142 +++++++ 9 files changed, 900 insertions(+), 462 deletions(-) create mode 100644 src/utils/set_with_flip.hpp create mode 100644 src/utils/tournament.cpp create mode 100644 src/utils/tournament.hpp diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index b4b880d212a..b8620ef3c97 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -41,6 +41,7 @@ #include "utils/map_vote_handler.hpp" #include "utils/random_generator.hpp" #include "utils/string_utils.hpp" +#include "utils/tournament.hpp" #include #include @@ -612,6 +613,7 @@ CommandManager::CommandManager(ServerLobby* lobby): initAssets(); m_asset_manager = lobby->getLobbyAssetManager(); + m_tournament = lobby->getTournament(); m_aux_mode_aliases = { {"m0"}, @@ -3350,7 +3352,7 @@ void CommandManager::process_muteall(Context& context) { auto& argv = context.m_argv; auto peer = context.m_peer.lock(); - if (!peer) + if (!peer || !m_tournament) { error(context, true); return; @@ -3359,23 +3361,17 @@ void CommandManager::process_muteall(Context& context) return; std::string peer_username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); + + int op = SWF_OP_FLIP; if (argv.size() >= 2 && argv[1] == "0") - { - m_lobby->m_tournament_mutealls.erase(peer_username); - } + op = SWF_OP_REMOVE; else if (argv.size() >= 2 && argv[1] == "1") - { - m_lobby->m_tournament_mutealls.insert(peer_username); - } - else - { - if (m_lobby->m_tournament_mutealls.count(peer_username)) - m_lobby->m_tournament_mutealls.erase(peer_username); - else - m_lobby->m_tournament_mutealls.insert(peer_username); - } + op = SWF_OP_ADD; + + int status = m_tournament->editMuteall(peer_username, op); + std::string msg; - if (m_lobby->m_tournament_mutealls.count(peer_username)) + if (status) msg = "You are now receiving messages only from players and referees"; else msg = "You are now receiving messages from spectators too"; @@ -3387,7 +3383,7 @@ void CommandManager::process_game(Context& context) { auto& argv = context.m_argv; auto peer = context.m_peer.lock(); - if (!peer) + if (!peer || !m_tournament) { error(context, true); return; @@ -3396,73 +3392,67 @@ void CommandManager::process_game(Context& context) return; std::string peer_username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); - int old_game = m_lobby->m_tournament_game; - int addition = 0; - if (argv.size() < 2) - { - ++m_lobby->m_tournament_game; - if (m_lobby->m_tournament_game == m_lobby->m_tournament_max_games) - m_lobby->m_tournament_game = 0; - m_lobby->m_fixed_lap = ServerConfig::m_fixed_lap_count; - } else { - int new_game_number; - int new_length = m_lobby->m_tournament_length; - if (!StringUtils::parseString(argv[1], &new_game_number) - || new_game_number < 0 - || new_game_number >= m_lobby->m_tournament_max_games) - { - std::string msg = "Please specify a correct number. " - "Format: /game [number 0.." - + std::to_string(m_lobby->m_tournament_max_games - 1) + "] [length]"; - m_lobby->sendStringToPeer(msg, peer); - return; - } - if (argv.size() >= 3) + + int old_game_number; + int old_duration; + int old_addition; + m_tournament->getGameCmdInput(old_game_number, old_duration, old_addition); + int new_game_number = m_tournament->getNextGameNumber(); + int new_duration = m_tournament->getDefaultDuration(); // Was m_tournament_length for argv.size >= 2 + int new_addition = 0; + + if (1 < argv.size()) + { + // What's the difference between m_tournament_length and ServerConfig::fixedlap ?? + bool bad = false; + + if (!StringUtils::parseString(argv[1], &new_game_number)) + bad = true; + + if (!bad && argv.size() >= 3 && !StringUtils::parseString(argv[2], &new_duration)) + bad = true; + + if (!bad && argv.size() >= 4 && !StringUtils::parseString(argv[3], &new_addition)) + bad = true; + + if (!bad && !m_tournament->isValidGameCmdInput(new_game_number, new_duration, new_addition)) { - bool ok = StringUtils::parseString(argv[2], &new_length); - if (!ok || new_length < 0) - { - error(context); - return; - } + bad = true; } - if (argv.size() >= 4) + + if (bad) { - bool ok = StringUtils::parseString(argv[3], &addition); - if (!ok || addition < 0 || addition > 59) - { - std::string msg = "Please specify a correct number. " - "Format: /game [number] [length] [0..59 additional seconds]"; - m_lobby->sendStringToPeer(msg, peer); - return; - } - m_lobby->m_extra_seconds = 0.0f; - if (addition > 0) { - m_lobby->m_extra_seconds = 60.0f - addition; - } - } else { - m_lobby->m_extra_seconds = 0.0f; + std::string msg = StringUtils::insertValues( + "Please specify a correct number. " + "Format: /game [number %d..%d] [length in minutes] [0..59 additional seconds]", + m_tournament->minGameNumber(), + m_tournament->maxGameNumber()); + // error(context) ? + m_lobby->sendStringToPeer(msg, peer); + return; } - m_lobby->m_tournament_game = new_game_number; - m_lobby->m_fixed_lap = new_length; } - if (m_lobby->tournamentColorsSwapped(m_lobby->m_tournament_game) - ^ m_lobby->tournamentColorsSwapped(old_game)) + m_tournament->setGameCmdInput(new_game_number, new_duration, new_addition); + m_lobby->m_fixed_lap = new_duration; + + if (m_tournament->hasColorsSwapped(new_game_number) ^ m_tournament->hasColorsSwapped(old_game_number)) m_lobby->changeColors(); - if (m_lobby->tournamentGoalsLimit(m_lobby->m_tournament_game) - ^ m_lobby->tournamentGoalsLimit(old_game)) - m_lobby->changeLimitForTournament(m_lobby->tournamentGoalsLimit(m_lobby->m_tournament_game)); + + if (m_tournament->hasGoalsLimit(new_game_number) ^ m_tournament->hasGoalsLimit(old_game_number)) + m_lobby->changeLimitForTournament(m_tournament->hasGoalsLimit()); + std::string msg = StringUtils::insertValues( - "Ready to start game %d for %d ", m_lobby->m_tournament_game, m_lobby->m_fixed_lap) - + (m_lobby->tournamentGoalsLimit(m_lobby->m_tournament_game) ? "goals" : "minutes"); - if (!m_lobby->tournamentGoalsLimit(m_lobby->m_tournament_game) && addition > 0) + "Ready to start game %d for %d %s", new_game_number, new_duration, + (m_tournament->hasGoalsLimit() ? "goals" : "minutes")); + + if (!m_tournament->hasGoalsLimit() && new_addition > 0) { - msg += " " + std::to_string(addition) + " seconds"; + msg += StringUtils::insertValues(" %d seconds", new_addition); ++m_lobby->m_fixed_lap; } m_lobby->sendStringToAllPeers(msg); Log::info("CommandManager", "SoccerMatchLog: Game number changed from %d to %d", - old_game, m_lobby->m_tournament_game); + old_game_number, new_game_number); } // process_game // ======================================================================== @@ -3470,7 +3460,7 @@ void CommandManager::process_role(Context& context) { auto& argv = context.m_argv; auto peer = context.m_peer.lock(); - if (!peer) + if (!peer || !m_tournament) { error(context, true); return; @@ -3500,8 +3490,9 @@ void CommandManager::process_role(Context& context) error(context); return; } - if (role[0] >= 'A' && role[0] <= 'Z') - role[0] += 'a' - 'A'; + char role_char = role[0]; + if (role_char >= 'A' && role_char <= 'Z') + role_char += 'a' - 'A'; std::vector changed_usernames; if (!username.empty()) { @@ -3524,15 +3515,7 @@ void CommandManager::process_role(Context& context) } for (const std::string& u: changed_usernames) { - m_lobby->m_tournament_red_players.erase(u); - m_lobby->m_tournament_blue_players.erase(u); - m_lobby->m_tournament_referees.erase(u); - if (permanent) - { - m_lobby->m_tournament_init_red.erase(u); - m_lobby->m_tournament_init_blue.erase(u); - m_lobby->m_tournament_init_ref.erase(u); - } + m_tournament->eraseFromAllTournamentCategories(u, permanent); std::string role_changed = "The referee has updated your role - you are now %s"; std::shared_ptr player_peer = STKHost::get()->findPeerByName( StringUtils::utf8ToWide(u)); @@ -3540,102 +3523,68 @@ void CommandManager::process_role(Context& context) if (player_peer) missing_assets = m_lobby->getMissingAssets(player_peer); bool fail = false; - switch (role[0]) + switch (role_char) { - case 'R': case 'r': { - if (!missing_assets.empty()) - { - fail = true; -// break; - } - if (m_lobby->tournamentColorsSwapped(m_lobby->m_tournament_game)) + fail = !missing_assets.empty(); + if (m_tournament->hasColorsSwapped()) { - m_lobby->m_tournament_blue_players.insert(u); - if (permanent) - m_lobby->m_tournament_init_blue.insert(u); + m_tournament->setTeam(KART_TEAM_BLUE, u, permanent); } else { - m_lobby->m_tournament_red_players.insert(u); - if (permanent) - m_lobby->m_tournament_init_red.insert(u); + m_tournament->setTeam(KART_TEAM_RED, u, permanent); } if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, "red player"); + role_changed = StringUtils::insertValues(role_changed, Tournament::charToString(role_char)); if (player_peer->hasPlayerProfiles()) - { m_lobby->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_RED); - } m_lobby->sendStringToPeer(role_changed, player_peer); } break; } - case 'B': case 'b': { - if (!missing_assets.empty()) - { - fail = true; -// break; - } - if (m_lobby->tournamentColorsSwapped(m_lobby->m_tournament_game)) + fail = !missing_assets.empty(); + if (m_tournament->hasColorsSwapped()) { - m_lobby->m_tournament_red_players.insert(u); - if (permanent) - m_lobby->m_tournament_init_red.insert(u); + m_tournament->setTeam(KART_TEAM_RED, u, permanent); } else { - m_lobby->m_tournament_blue_players.insert(u); - if (permanent) - m_lobby->m_tournament_init_blue.insert(u); + m_tournament->setTeam(KART_TEAM_BLUE, u, permanent); } if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, "blue player"); + role_changed = StringUtils::insertValues(role_changed, Tournament::charToString(role_char)); if (player_peer->hasPlayerProfiles()) - { m_lobby->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_BLUE); - } m_lobby->sendStringToPeer(role_changed, player_peer); } break; } - case 'J': case 'j': { - if (!missing_assets.empty()) - { - fail = true; -// break; - } - m_lobby->m_tournament_referees.insert(u); - if (permanent) - m_lobby->m_tournament_init_ref.insert(u); + fail = !missing_assets.empty(); + m_tournament->setReferee(u, permanent); if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, "referee"); + role_changed = StringUtils::insertValues(role_changed, Tournament::charToString(role_char)); if (player_peer->hasPlayerProfiles()) - { m_lobby->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); - } m_lobby->sendStringToPeer(role_changed, player_peer); } break; } - case 'S': case 's': { if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, "spectator"); + role_changed = StringUtils::insertValues(role_changed, Tournament::charToString(role_char)); if (player_peer->hasPlayerProfiles()) - { m_lobby->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); - } m_lobby->sendStringToPeer(role_changed, player_peer); } break; @@ -3669,6 +3618,11 @@ void CommandManager::process_role(Context& context) void CommandManager::process_stop(Context& context) { + if (!m_tournament) + { + error(context, true); + return; + } World* w = World::getWorld(); if (!w) return; @@ -3682,6 +3636,11 @@ void CommandManager::process_stop(Context& context) void CommandManager::process_go(Context& context) { + if (!m_tournament) + { + error(context, true); + return; + } World* w = World::getWorld(); if (!w) return; @@ -3695,6 +3654,11 @@ void CommandManager::process_go(Context& context) void CommandManager::process_lobby(Context& context) { + if (!m_tournament) + { + error(context, true); + return; + } World* w = World::getWorld(); if (!w) return; @@ -3709,7 +3673,7 @@ void CommandManager::process_init(Context& context) { auto& argv = context.m_argv; auto peer = context.m_peer.lock(); - if (!peer) + if (!peer || !m_tournament) { error(context, true); return; @@ -3928,14 +3892,15 @@ void CommandManager::process_preserve_assign(Context& context) void CommandManager::process_history(Context& context) { auto peer = context.m_peer.lock(); - if (!peer) + if (!peer || !m_tournament) { error(context, true); return; } std::string msg = "Map history:"; - for (unsigned i = 0; i < m_lobby->m_tournament_arenas.size(); i++) - msg += StringUtils::insertValues(" [%d]: ", i) + m_lobby->m_tournament_arenas[i]; + std::vector arenas = m_tournament->getMapHistory(); + for (unsigned i = 0; i < arenas.size(); i++) + msg += StringUtils::insertValues(" [%d]: %s", i, arenas[i].c_str()); m_lobby->sendStringToPeer(msg, peer); } // process_history // ======================================================================== @@ -3944,7 +3909,7 @@ void CommandManager::process_history_assign(Context& context) { auto& argv = context.m_argv; auto peer = context.m_peer.lock(); - if (!peer) + if (!peer || !m_tournament) { error(context, true); return; @@ -3965,9 +3930,11 @@ void CommandManager::process_history_assign(Context& context) 2, m_stf_all_maps, 3, false, false)) return; std::string id = argv[2]; - if (index >= (int)m_lobby->m_tournament_arenas.size()) - m_lobby->m_tournament_arenas.resize(index + 1, ""); - m_lobby->m_tournament_arenas[index] = id; + if (!m_tournament->assignToHistory(index, id)) + { + error(context); + return; + } msg = StringUtils::insertValues("Assigned [%d] to %s in the map history", index, id.c_str()); m_lobby->sendStringToPeer(msg, peer); diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index e7f8754eef5..b3f752fe11f 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -50,6 +50,7 @@ class ServerLobby; class Event; class STKPeer; class LobbyAssetManager; +class Tournament; class CommandManager { @@ -199,6 +200,7 @@ class CommandManager ServerLobby* m_lobby; std::shared_ptr m_asset_manager; + std::shared_ptr m_tournament; std::vector> m_all_commands; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index c8ac3fdd9c4..ab76010ced8 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -53,6 +53,7 @@ #include "utils/hit_processor.hpp" #include "utils/lobby_asset_manager.hpp" #include "utils/map_vote_handler.hpp" +#include "utils/tournament.hpp" #include "utils/translation.hpp" #include @@ -129,7 +130,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_fixed_lap = m_default_fixed_laps; } m_fixed_direction = ServerConfig::m_fixed_direction; - m_extra_seconds = 0.0f; + m_default_lap_multiplier = ServerConfig::m_auto_game_time_ratio; m_troll_active = ServerConfig::m_troll_active; @@ -180,8 +181,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() initCategories(); if (ServerConfig::m_soccer_tournament) { - initTournamentPlayers(); - m_tournament_game = 0; + m_tournament = std::make_shared(this); } m_allowed_to_start = ServerConfig::m_allowed_to_start; m_game_info = nullptr; @@ -400,38 +400,17 @@ void ServerLobby::handleChat(Event* event) if (add_red_emoji) message = StringUtils::utf32ToWide({0x1f7e5, 0x20}) + message; bool tournament_limit = false; - std::set important_players; + if (m_tournament) + tournament_limit = !m_tournament->checkSenderInRefsOrPlayers(sender); std::set sees_teamchats; - if (ServerConfig::m_soccer_tournament) - { - for (const std::string& s: m_tournament_referees) { - sees_teamchats.insert(s); - } - tournament_limit = true; - for (auto& profile: sender->getPlayerProfiles()) - { - std::string name = StringUtils::wideToUtf8( - profile->getName()); - if (m_tournament_referees.count(name) > 0 || - m_tournament_red_players.count(name) > 0 || - m_tournament_blue_players.count(name) > 0) - tournament_limit = false; - } - } + if (m_tournament) + sees_teamchats = m_tournament->getThoseWhoSeeTeamchats(); + // Note that mutealls are still spectators - if (tournament_limit) + std::set important_players; + if (m_tournament && tournament_limit) { - if (m_tournament_limited_chat) - { - for (const std::string& s: m_tournament_referees) - important_players.insert(s); - for (const std::string& s: m_tournament_red_players) - important_players.insert(s); - for (const std::string& s: m_tournament_blue_players) - important_players.insert(s); - } - for (const std::string& s: m_tournament_mutealls) - important_players.insert(s); + important_players = m_tournament->getImportantChatPlayers(); } chat->addUInt8(LE_CHAT).encodeString16(message); core::stringw sender_name = @@ -536,8 +515,11 @@ void ServerLobby::changeTeam(Event* event) uint8_t local_id = data.getUInt8(); auto& player = event->getPeer()->getPlayerProfiles().at(local_id); auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); - if (ServerConfig::m_soccer_tournament) - return; // message here? + if (m_tournament && !m_tournament->canChangeTeam()) + { + Log::info("ServerLobby", "Team change requested by %s, but tournament forbids it.", player->getName().c_str()); + return; + } // For now, the change team button will still only work in soccer + CTF. // Further logic might be added later, but now it seems to be complicated @@ -937,10 +919,14 @@ void ServerLobby::asynchronousUpdate() updatePlayerList(); m_timeout.store(std::numeric_limits::max()); } - if ((!ServerConfig::m_soccer_tournament && - m_timeout.load() < (int64_t)StkTime::getMonoTimeMs()) || - (checkPeersReady(true/*ignore_ai_peer*/, BEFORE_SELECTION) && - (int)players >= starting_limit)) + bool forbid_starting = false; + if (m_tournament && m_tournament->forbidStarting()) + forbid_starting = true; + + bool timer_finished = (!forbid_starting && m_timeout.load() < (int64_t)StkTime::getMonoTimeMs()); + bool players_ready = (checkPeersReady(true/*ignore_ai_peer*/, BEFORE_SELECTION) && (int)players >= starting_limit); + + if (timer_finished || players_ready) { resetPeersReady(); startSelection(); @@ -1027,17 +1013,17 @@ void ServerLobby::asynchronousUpdate() *m_default_vote = winner_vote; m_item_seed = (uint32_t)StkTime::getTimeSinceEpoch(); ItemManager::updateRandomSeed(m_item_seed); - m_game_setup->setRace(winner_vote, m_extra_seconds); + float extra_seconds = 0.0f; + if (m_tournament) + extra_seconds = m_tournament->getExtraSeconds(); + m_game_setup->setRace(winner_vote, extra_seconds); // For spectators that don't have the track, remember their // spectate mode and don't load the track std::string track_name = winner_vote.m_track_name; - if (ServerConfig::m_soccer_tournament) - { - if (m_tournament_game >= (int)m_tournament_arenas.size()) - m_tournament_arenas.resize(m_tournament_game + 1, ""); - m_tournament_arenas[m_tournament_game] = track_name; - } + if (m_tournament) + m_tournament->fillNextArena(track_name); + auto peers = STKHost::get()->getPeers(); std::map, AlwaysSpectateMode> previous_spectate_mode; @@ -2304,10 +2290,9 @@ void ServerLobby::startSelection(const Event *event) } case RaceManager::MINOR_MODE_SOCCER: { - if (ServerConfig::m_soccer_tournament) + if (m_tournament) { - m_default_vote->m_num_laps = m_tournament_length; - m_default_vote->m_reverse = false; + m_tournament->applyRestrictionsOnDefaultVote(m_default_vote); } else { @@ -2572,15 +2557,9 @@ void ServerLobby::checkRaceFinished() assert(World::getWorld()); if (!RaceEventManager::get()->isRaceOver()) return; - if (ServerConfig::m_soccer_tournament) - { - World* w = World::getWorld(); - if (w) - { - SoccerWorld *sw = dynamic_cast(w); - sw->tellCountIfDiffers(); - } - } + if (m_tournament) + m_tournament->onRaceFinished(); + if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) Log::info("ServerLobby", "SoccerMatchLog: The game is considered finished."); @@ -2938,8 +2917,8 @@ bool ServerLobby::handleAssets(const NetworkString& ns, std::shared_ptr updateMapsForMode(); } - if (ServerConfig::m_soccer_tournament) - updateTournamentRole(peer); + if (m_tournament) + m_tournament->updateTournamentRole(peer); updatePlayerList(); return true; } // handleAssets @@ -3204,7 +3183,10 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, if (it2 != m_team_for_player.end()) previous_team = it2->second; - if (ServerConfig::m_team_choosing && !ServerConfig::m_soccer_tournament) + bool can_change_teams = true; + if (m_tournament && !m_tournament->canChangeTeam()) + can_change_teams = false; + if (ServerConfig::m_team_choosing && can_change_teams) { KartTeam cur_team = KART_TEAM_NONE; @@ -3224,19 +3206,11 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, if (cur_team != KART_TEAM_NONE) setTeamInLobby(player, cur_team); } - if (ServerConfig::m_soccer_tournament) + if (m_tournament) { - if (m_tournament_red_players.count(utf8_online_name)) - setTeamInLobby(player, KART_TEAM_RED); - else if (m_tournament_blue_players.count(utf8_online_name)) - setTeamInLobby(player, KART_TEAM_BLUE); - if (tournamentColorsSwapped(m_tournament_game)) - { - if (player->getTeam() == KART_TEAM_BLUE) - setTeamInLobby(player, KART_TEAM_RED); - else if (player->getTeam() == KART_TEAM_RED) - setTeamInLobby(player, KART_TEAM_BLUE); - } + KartTeam team = m_tournament->getTeam(utf8_online_name); + if (team != KART_TEAM_NONE) + setTeamInLobby(player, team); } getCommandManager()->addUser(username); if (m_game_setup->isGrandPrix()) @@ -3400,8 +3374,8 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, } getMessagesFromHost(peer, online_id); - if (ServerConfig::m_soccer_tournament) - updateTournamentRole(peer); + if (m_tournament) + m_tournament->updateTournamentRole(peer); } // handleUnencryptedConnection //----------------------------------------------------------------------------- @@ -3667,9 +3641,9 @@ void ServerLobby::handlePlayerVote(Event* event) } // Remove / adjust any invalid settings - if (ServerConfig::m_soccer_tournament) + if (m_tournament) { - vote.m_reverse = false; + m_tournament->applyRestrictionsOnVote(&vote); } else if (RaceManager::get()->modeHasLaps()) { @@ -5359,111 +5333,6 @@ void ServerLobby::initCategories() } } // initCategories //----------------------------------------------------------------------------- -void ServerLobby::initTournamentPlayers() -{ - // Init playing teams - std::vector tokens = StringUtils::split( - ServerConfig::m_soccer_tournament_match, ' '); - std::string type = ""; - for (std::string& s: tokens) - { - if (s.length() == 1) - type = s; - else if (s.empty()) - continue; - else if (s[0] == '#') - { - std::string cat_name = s.substr(1); - std::set& dest = ( - type == "R" ? m_tournament_red_players : - type == "B" ? m_tournament_blue_players : - m_tournament_referees); - for (const std::string& member: - m_player_categories[cat_name]) - dest.insert(member); - } - else if (type == "R") - m_tournament_red_players.insert(s); - else if (type == "B") - m_tournament_blue_players.insert(s); - else if (type == "J") - m_tournament_referees.insert(s); - } - for (const std::string& s: m_tournament_red_players) - { - Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to r", - s.c_str()); - } - for (const std::string& s: m_tournament_blue_players) - { - Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to b", - s.c_str()); - } - for (const std::string& s: m_tournament_referees) - { - Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to j", - s.c_str()); - } - m_tournament_init_red = m_tournament_red_players; - m_tournament_init_blue = m_tournament_blue_players; - m_tournament_init_ref = m_tournament_referees; - - // Init tournament format - tokens = StringUtils::split( - ServerConfig::m_soccer_tournament_rules, ';'); - bool fallback = tokens.size() < 2; - std::vector general; - if (!fallback) - { - general = StringUtils::split(tokens[0], ' '); - if (general.size() < 5) - fallback = true; - } - if (fallback) - { - Log::warn("ServerLobby", "Tournament rules are not complete, fallback to default"); - general.clear(); - general.push_back("nochat"); - general.push_back("10"); - general.push_back("GGGGT"); - general.push_back("RRBBR"); - general.push_back("+++++"); - tokens.clear(); - tokens.push_back("nochat 10 GGGT RRBBR"); - tokens.push_back(""); - tokens.push_back(""); - tokens.push_back("not %0"); - tokens.push_back("not %0" " %1"); - tokens.push_back(""); - ServerConfig::m_soccer_tournament_rules = "nochat 10 TTTTG RRBBR +++++;" - ";;not %1;" - "not %1 " - "%2;;;"; - } - Log::info("ServerLobby", "SoccerMatchLog: Tournament rules are set to \"%s\"", - ServerConfig::m_soccer_tournament_rules.c_str()); - m_tournament_limited_chat = false; - m_tournament_length = 10; - if (general[0] == "nochat") - m_tournament_limited_chat = true; - if (StringUtils::parseString(general[1], &m_tournament_length)) - { - if (m_tournament_length <= 0) - m_tournament_length = 10; - } - else - m_tournament_length = 10; - ServerConfig::m_fixed_lap_count = m_tournament_length; - - m_tournament_game_limits = general[2]; - m_tournament_colors = general[3]; - m_tournament_max_games = std::min(general[2].length(), general[3].length()); - m_tournament_max_games = std::min(m_tournament_max_games, (int)tokens.size() - 1); - m_tournament_votability = general[4]; - for (int i = 0; i < m_tournament_max_games; i++) - m_tournament_track_filters.emplace_back(tokens[i + 1]); -} // initTournamentPlayers -//----------------------------------------------------------------------------- void ServerLobby::changeColors() { // We assume here that it's soccer, as it's only called @@ -5525,14 +5394,10 @@ bool ServerLobby::canRace(std::shared_ptr peer) } std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); - if (ServerConfig::m_soccer_tournament) + if (m_tournament && !m_tournament->canPlay(username)) { - if (m_tournament_red_players.count(username) == 0 && - m_tournament_blue_players.count(username) == 0) - { - m_why_peer_cannot_play[peer] = HR_NOT_A_TOURNAMENT_PLAYER; - return false; - } + m_why_peer_cannot_play[peer] = HR_NOT_A_TOURNAMENT_PLAYER; + return false; } else if (m_spectators_by_limit.find(peer) != m_spectators_by_limit.end()) { @@ -5608,19 +5473,11 @@ bool ServerLobby::canVote(std::shared_ptr peer) const { if (!peer || peer->getPlayerProfiles().empty()) return false; - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - if (ServerConfig::m_soccer_tournament) { - bool first = m_tournament_red_players.count(username) > 0; - bool second = m_tournament_blue_players.count(username) > 0; - if (!first && !second) - return false; - char votable = m_tournament_votability[m_tournament_game]; - if (votable == '+') - return true; - return (votable == 'F' && first) || (votable == 'S' && second); - } - return true; + + if (!m_tournament) + return true; + + return m_tournament->canVote(peer); } // canVote //----------------------------------------------------------------------------- bool ServerLobby::hasHostRights(std::shared_ptr peer) const @@ -5631,12 +5488,9 @@ bool ServerLobby::hasHostRights(std::shared_ptr peer) const return true; if (peer->isAngryHost()) return true; - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - if (ServerConfig::m_soccer_tournament) - { - return m_tournament_referees.count(username) > 0; - } + if (m_tournament) + return m_tournament->hasHostRights(peer); + return false; } // hasHostRights //----------------------------------------------------------------------------- @@ -5666,12 +5520,9 @@ int ServerLobby::getPermissions(std::shared_ptr peer) const { mask |= CommandPermissions::PE_HAMMER; } - else if (ServerConfig::m_soccer_tournament) + else if (m_tournament && m_tournament->hasHammerRights(peer)) { - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - if (m_tournament_referees.count(username) > 0) - mask |= CommandPermissions::PE_HAMMER; + mask |= CommandPermissions::PE_HAMMER; } return mask; } // getPermissions @@ -5878,16 +5729,6 @@ void ServerLobby::changeLimitForTournament(bool goal_target) updatePlayerList(); } // changeLimitForTournament //----------------------------------------------------------------------------- -bool ServerLobby::tournamentGoalsLimit(int game) const -{ - return m_tournament_game_limits[game] == 'G'; -} // tournamentGoalsLimit -//----------------------------------------------------------------------------- -bool ServerLobby::tournamentColorsSwapped(int game) const -{ - return m_tournament_colors[game] == 'B'; -} // tournamentColorsSwapped -//----------------------------------------------------------------------------- void ServerLobby::initAvailableTracks() { m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); @@ -5906,59 +5747,6 @@ std::vector ServerLobby::getMissingAssets(std::shared_ptr return ans; } // getMissingAssets //----------------------------------------------------------------------------- -void ServerLobby::updateTournamentRole(std::shared_ptr peer) -{ - if (!ServerConfig::m_soccer_tournament) - return; - if (peer->getPlayerProfiles().empty()) - return; - std::string utf8_online_name = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - bool erased_from_tournament_roles = false; - std::vector missing_assets; - missing_assets = getMissingAssets(peer); -// if (!missing_assets.empty()) -// { -// erased_from_tournament_roles |= m_tournament_red_players.count(utf8_online_name) > 0; -// erased_from_tournament_roles |= m_tournament_blue_players.count(utf8_online_name) > 0; -// erased_from_tournament_roles |= m_tournament_referees.count(utf8_online_name) > 0; -// m_tournament_red_players.erase(utf8_online_name); -// m_tournament_blue_players.erase(utf8_online_name); -// m_tournament_referees.erase(utf8_online_name); -// } - for (unsigned i = 0; i < peer->getPlayerProfiles().size(); i++) - { - auto player = peer->getPlayerProfiles()[i]; - core::stringw name = player->getName(); - std::string utf8_name = StringUtils::wideToUtf8(name); - if (m_tournament_red_players.count(utf8_online_name)) - setTeamInLobby(player, KART_TEAM_RED); - else if (m_tournament_blue_players.count(utf8_online_name)) - setTeamInLobby(player, KART_TEAM_BLUE); - else - setTeamInLobby(player, KART_TEAM_NONE); - if (tournamentColorsSwapped(m_tournament_game)) - { - if (player->getTeam() == KART_TEAM_BLUE) - setTeamInLobby(player, KART_TEAM_RED); - else if (player->getTeam() == KART_TEAM_RED) - setTeamInLobby(player, KART_TEAM_BLUE); - } - } - if (erased_from_tournament_roles) - { - std::string msg = "You lack the following assets:"; - for (unsigned i = 0; i < missing_assets.size(); i++) - { - if (i) - msg.push_back(','); - msg += " " + missing_assets[i]; - } - sendStringToPeer(msg, peer); - updatePlayerList(); - } -} // updateTournamentRole -//----------------------------------------------------------------------------- std::shared_ptr ServerLobby::getCommandManager() { @@ -6169,11 +5957,8 @@ void ServerLobby::applyAllFilters(std::set& maps, bool use_history) m_global_filter.apply(track_context); if (use_history) { - track_context.wildcards = m_tournament_arenas; - if (ServerConfig::m_soccer_tournament) - { - m_tournament_track_filters[m_tournament_game].apply(track_context); - } + if (m_tournament) + m_tournament->applyFiltersForThisGame(track_context); track_context.wildcards = m_map_history; if (!m_onetime_tracks_queue.empty()) { diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 2cdb7f55df0..78a79190333 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -54,6 +54,7 @@ class LobbyAssetManager; class CommandManager; class KartElimination; class MapVoteHandler; +class Tournament; namespace Online { @@ -224,8 +225,6 @@ class ServerLobby : public LobbyProtocol std::vector m_play_requirement_tracks; - std::vector m_tournament_must_have_tracks; - bool m_restricting_config; bool m_inverted_config_restriction; @@ -260,35 +259,7 @@ class ServerLobby : public LobbyProtocol std::map m_team_for_player; - std::set m_tournament_red_players; - - std::set m_tournament_blue_players; - - std::set m_tournament_referees; - - std::set m_tournament_mutealls; - - std::set m_tournament_init_red; - - std::set m_tournament_init_blue; - - std::set m_tournament_init_ref; - - bool m_tournament_limited_chat; - - int m_tournament_length; - - int m_tournament_max_games; - - std::string m_tournament_game_limits; - - std::string m_tournament_colors; - - std::string m_tournament_votability; - - std::vector m_tournament_arenas; - - std::vector m_tournament_track_filters; + std::shared_ptr m_tournament; TrackFilter m_global_filter; @@ -310,14 +281,10 @@ class ServerLobby : public LobbyProtocol std::map m_gp_team_scores; - int m_tournament_game; - int m_fixed_lap; int m_fixed_direction; - float m_extra_seconds; - double m_default_lap_multiplier; std::vector m_scoring_int_params; @@ -479,9 +446,6 @@ class ServerLobby : public LobbyProtocol void loadWhiteList(); void loadPreservedSettings(); void changeLimitForTournament(bool goal_target); - bool tournamentGoalsLimit(int game) const; - bool tournamentColorsSwapped(int game) const; - void updateTournamentRole(std::shared_ptr peer); std::shared_ptr getCommandManager(); // bool tournamentHasIcy(int game) const; @@ -581,9 +545,15 @@ class ServerLobby : public LobbyProtocol void setTemporaryTeamInLobby(std::shared_ptr profile, int team); void checkNoTeamSpectator(std::shared_ptr peer); void setSpectateModeProperly(std::shared_ptr peer, AlwaysSpectateMode mode); - int getTeamForUsername(const std::string& name) { return m_team_for_player[name]; } - std::shared_ptr getHitProcessor() const { return m_hit_processor; } - std::shared_ptr getLobbyAssetManager() const { return m_asset_manager; } + int getTeamForUsername(const std::string& name) + { return m_team_for_player[name]; } + std::shared_ptr getHitProcessor() const + { return m_hit_processor; } + std::shared_ptr getLobbyAssetManager() const + { return m_asset_manager; } + std::shared_ptr getTournament() const { return m_tournament; } + std::map> getCategories() const + { return m_player_categories; } }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp index 919947bb7d7..c002d5020cf 100644 --- a/src/utils/lobby_asset_manager.cpp +++ b/src/utils/lobby_asset_manager.cpp @@ -16,6 +16,8 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include "utils/lobby_asset_manager.hpp" + #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" #include "karts/official_karts.hpp" @@ -25,7 +27,6 @@ #include "network/protocols/server_lobby.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" -#include "utils/lobby_asset_manager.hpp" #include "utils/random_generator.hpp" #include "utils/string_utils.hpp" diff --git a/src/utils/lobby_asset_manager.hpp b/src/utils/lobby_asset_manager.hpp index 107b6e4bc6a..fd96265fb01 100644 --- a/src/utils/lobby_asset_manager.hpp +++ b/src/utils/lobby_asset_manager.hpp @@ -20,6 +20,9 @@ #define LOBBY_ASSET_MANAGER_HPP #include "utils/types.hpp" +#include "race/race_manager.hpp" +#include "network/stk_peer.hpp" + #include #include @@ -27,6 +30,7 @@ #include class ServerLobby; class STKPeer; +class NetworkString; class LobbyAssetManager { diff --git a/src/utils/set_with_flip.hpp b/src/utils/set_with_flip.hpp new file mode 100644 index 00000000000..ef7f4fa451b --- /dev/null +++ b/src/utils/set_with_flip.hpp @@ -0,0 +1,72 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef SET_WITH_FLIP_HPP +#define SET_WITH_FLIP_HPP + +#include "utils/log.hpp" +#include + +enum Op: int +{ + SWF_OP_ADD = 1, + SWF_OP_REMOVE = 0, + SWF_OP_FLIP = -1, +}; + +template +class SetWithFlip: public std::set +{ +public: + int add(const T& element) + { + this->insert(element); + return SWF_OP_ADD; + } + + int remove(const T& element) + { + this->erase(element); + return SWF_OP_REMOVE; + } + + int flip(const T& element) + { + auto it = this->find(element); + if (it != this->end()) + { + return remove(element); + } + return add(element); + } + + int set(const T& element, int type) + { + switch (type) + { + case SWF_OP_ADD: return add(element); + case SWF_OP_REMOVE: return remove(element); + case SWF_OP_FLIP: return flip(element); + } + + Log::warn("SetWithFlip", "Invalid type = %d encountered, defaulting to flip (%d).", type, SWF_OP_FLIP); + return flip(element); + } +}; + +#endif \ No newline at end of file diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp new file mode 100644 index 00000000000..33a62b80b20 --- /dev/null +++ b/src/utils/tournament.cpp @@ -0,0 +1,495 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2024 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/tournament.hpp" + +#include "utils/track_filter.hpp" +#include "network/stk_peer.hpp" +#include "network/network_player_profile.hpp" +#include "network/server_config.hpp" +#include "network/protocols/server_lobby.hpp" +#include "network/peer_vote.hpp" +#include "modes/world.hpp" +#include "modes/soccer_world.hpp" +// #include "karts/kart_properties.hpp" +// #include "karts/kart_properties_manager.hpp" +// #include "karts/official_karts.hpp" +// #include "network/network_string.hpp" +// #include "network/server_config.hpp" +// #include "network/stk_peer.hpp" +// #include "network/protocols/server_lobby.hpp" +// #include "tracks/track.hpp" +// #include "tracks/track_manager.hpp" +// #include "utils/random_generator.hpp" +#include "utils/string_utils.hpp" + +namespace +{ + using T = Tournament::TournamentRole; + + static std::unordered_map g_roleToTeam = { + {T::TR_RED_PLAYER, KART_TEAM_RED}, + {T::TR_BLUE_PLAYER, KART_TEAM_BLUE}, + {T::TR_JUDGE, KART_TEAM_NONE}, + {T::TR_SPECTATOR, KART_TEAM_NONE}, + }; + + static std::unordered_map g_roleToString = { + {T::TR_RED_PLAYER, "red player"}, + {T::TR_BLUE_PLAYER, "blue player"}, + {T::TR_JUDGE, "referee"}, + {T::TR_SPECTATOR, "spectator"}, + }; + + static std::unordered_map g_roleToChar = { + {T::TR_RED_PLAYER, 'r'}, + {T::TR_BLUE_PLAYER, 'b'}, + {T::TR_JUDGE, 'j'}, + {T::TR_SPECTATOR, 's'}, + }; + + static std::unordered_map g_charToRole = { + {'r', T::TR_RED_PLAYER}, + {'b', T::TR_BLUE_PLAYER}, + {'j', T::TR_JUDGE}, + {'s', T::TR_SPECTATOR}, + }; + + static int g_history_limit = 100; +} + + +KartTeam Tournament::roleToTeam(TournamentRole role) +{ + return g_roleToTeam[role]; +} + +std::string Tournament::roleToString(TournamentRole role) +{ + return g_roleToString[role]; +} + +char Tournament::roleToCbar(TournamentRole role) +{ + return g_roleToChar[role]; +} + +Tournament::TournamentRole Tournament::charToRole(char c) +{ + auto it = g_charToRole.find(c); + if (it != g_charToRole.end()) + return it->second; + return TR_SPECTATOR; +} + +std::string Tournament::charToString(char c) +{ + return roleToString(charToRole(c)); +} + + +Tournament::Tournament(ServerLobby* lobby): m_lobby(lobby) +{ + initTournamentPlayers(); + m_tournament_game = 0; + m_extra_seconds = 0.0f; +} // Tournament +// ======================================================================== + +void Tournament::applyFiltersForThisGame(FilterContext& track_context) +{ + track_context.wildcards = m_tournament_arenas; + m_tournament_track_filters[m_tournament_game].apply(track_context); +} + +std::set Tournament::getThoseWhoSeeTeamchats() const +{ + std::set sees_teamchats; + for (const std::string& s: m_tournament_referees) { + sees_teamchats.insert(s); + } + return sees_teamchats; +} + +bool Tournament::checkSenderInRefsOrPlayers(std::shared_ptr sender) const +{ + if (!sender) + return false; + for (auto& profile: sender->getPlayerProfiles()) + { + std::string name = StringUtils::wideToUtf8( + profile->getName()); + if (m_tournament_referees.count(name) > 0 || + m_tournament_red_players.count(name) > 0 || + m_tournament_blue_players.count(name) > 0) + { + return true; + } + } + return false; +} + +std::set Tournament::getImportantChatPlayers() const +{ + std::set important_players; + if (m_tournament_limited_chat) + { + for (const std::string& s: m_tournament_referees) + important_players.insert(s); + for (const std::string& s: m_tournament_red_players) + important_players.insert(s); + for (const std::string& s: m_tournament_blue_players) + important_players.insert(s); + } + for (const std::string& s: m_tournament_mutealls) + important_players.insert(s); + return important_players; +} + +void Tournament::fillNextArena(const std::string& track_name) +{ + if (m_tournament_game >= (int)m_tournament_arenas.size()) + m_tournament_arenas.resize(m_tournament_game + 1, ""); + m_tournament_arenas[m_tournament_game] = track_name; +} + +void Tournament::applyRestrictionsOnDefaultVote(PeerVote* default_vote) const +{ + default_vote->m_num_laps = m_tournament_length; + default_vote->m_reverse = false; +} + +void Tournament::applyRestrictionsOnVote(PeerVote* vote) const +{ + vote->m_reverse = false; +} + +void Tournament::onRaceFinished() const +{ + World* w = World::getWorld(); + if (w) + { + SoccerWorld *sw = dynamic_cast(w); + sw->tellCountIfDiffers(); + } +} + +void Tournament::updateTournamentRole(std::shared_ptr peer) +{ + if (peer->getPlayerProfiles().empty()) + return; + std::string utf8_online_name = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + for (auto& player: peer->getPlayerProfiles()) + { + core::stringw name = player->getName(); + std::string utf8_name = StringUtils::wideToUtf8(name); + if (m_tournament_red_players.count(utf8_online_name)) + m_lobby->setTeamInLobby(player, KART_TEAM_RED); + else if (m_tournament_blue_players.count(utf8_online_name)) + m_lobby->setTeamInLobby(player, KART_TEAM_BLUE); + else + m_lobby->setTeamInLobby(player, KART_TEAM_NONE); + if (hasColorsSwapped()) + { + if (player->getTeam() == KART_TEAM_BLUE) + m_lobby->setTeamInLobby(player, KART_TEAM_RED); + else if (player->getTeam() == KART_TEAM_RED) + m_lobby->setTeamInLobby(player, KART_TEAM_BLUE); + } + } +} // updateTournamentRole +//----------------------------------------------------------------------------- + +KartTeam Tournament::getTeam(std::string utf8_online_name) const +{ + bool swapped = hasColorsSwapped(); + + if (m_tournament_red_players.count(utf8_online_name)) + { + if (swapped) + return KART_TEAM_BLUE; + return KART_TEAM_RED; + } + + if (m_tournament_blue_players.count(utf8_online_name)) + { + if (swapped) + return KART_TEAM_RED; + return KART_TEAM_BLUE; + } + + return KART_TEAM_NONE; +} + +bool Tournament::hasGoalsLimit() const +{ + return m_tournament_game_limits[m_tournament_game] == 'G'; +} // hasGoalsLimit +//----------------------------------------------------------------------------- +bool Tournament::hasGoalsLimit(int game) const +{ + return m_tournament_game_limits[game] == 'G'; +} // hasGoalsLimit +//----------------------------------------------------------------------------- +bool Tournament::hasColorsSwapped() const +{ + return m_tournament_colors[m_tournament_game] == 'B'; +} // hasColorsSwapped +//----------------------------------------------------------------------------- +bool Tournament::hasColorsSwapped(int game) const +{ + return m_tournament_colors[game] == 'B'; +} // hasColorsSwapped +//----------------------------------------------------------------------------- + +void Tournament::initTournamentPlayers() +{ + // Init playing teams + std::vector tokens = StringUtils::split( + ServerConfig::m_soccer_tournament_match, ' '); + std::string type = ""; + for (std::string& s: tokens) + { + if (s.length() == 1) + type = s; + else if (s.empty()) + continue; + else if (s[0] == '#') + { + std::string cat_name = s.substr(1); + std::set& dest = ( + type == "R" ? m_tournament_red_players : + type == "B" ? m_tournament_blue_players : + m_tournament_referees); + for (const std::string& member: m_lobby->getCategories()[cat_name]) + dest.insert(member); + } + else if (type == "R") + m_tournament_red_players.insert(s); + else if (type == "B") + m_tournament_blue_players.insert(s); + else if (type == "J") + m_tournament_referees.insert(s); + } + for (const std::string& s: m_tournament_red_players) + { + Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to r", + s.c_str()); + } + for (const std::string& s: m_tournament_blue_players) + { + Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to b", + s.c_str()); + } + for (const std::string& s: m_tournament_referees) + { + Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to j", + s.c_str()); + } + m_tournament_init_red = m_tournament_red_players; + m_tournament_init_blue = m_tournament_blue_players; + m_tournament_init_ref = m_tournament_referees; + + // Init tournament format + tokens = StringUtils::split( + ServerConfig::m_soccer_tournament_rules, ';'); + bool fallback = tokens.size() < 2; + std::vector general; + if (!fallback) + { + general = StringUtils::split(tokens[0], ' '); + if (general.size() < 5) + fallback = true; + } + if (fallback) + { + Log::warn("ServerLobby", "Tournament rules are not complete, fallback to default"); + general.clear(); + general.push_back("nochat"); + general.push_back("10"); + general.push_back("GGGGT"); + general.push_back("RRBBR"); + general.push_back("+++++"); + tokens.clear(); + tokens.push_back("nochat 10 GGGT RRBBR"); + tokens.push_back(""); + tokens.push_back(""); + tokens.push_back("not %0"); + tokens.push_back("not %0" " %1"); + tokens.push_back(""); + ServerConfig::m_soccer_tournament_rules = "nochat 10 TTTTG RRBBR +++++;" + ";;not %1;" + "not %1 " + "%2;;;"; + } + Log::info("ServerLobby", "SoccerMatchLog: Tournament rules are set to \"%s\"", + ServerConfig::m_soccer_tournament_rules.c_str()); + m_tournament_limited_chat = false; + m_tournament_length = 10; + if (general[0] == "nochat") + m_tournament_limited_chat = true; + if (StringUtils::parseString(general[1], &m_tournament_length)) + { + if (m_tournament_length <= 0) + m_tournament_length = 10; + } + else + m_tournament_length = 10; + ServerConfig::m_fixed_lap_count = m_tournament_length; + + m_tournament_game_limits = general[2]; + m_tournament_colors = general[3]; + m_tournament_max_games = std::min(general[2].length(), general[3].length()); + m_tournament_max_games = std::min(m_tournament_max_games, (int)tokens.size() - 1); + m_tournament_votability = general[4]; + for (int i = 0; i < m_tournament_max_games; i++) + m_tournament_track_filters.emplace_back(tokens[i + 1]); +} // initTournamentPlayers +//----------------------------------------------------------------------------- + +bool Tournament::canPlay(const std::string& username) const +{ + return m_tournament_red_players.count(username) > 0 || + m_tournament_blue_players.count(username) > 0; +} + +bool Tournament::canVote(std::shared_ptr peer) const +{ + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + + bool first = m_tournament_red_players.count(username) > 0; + bool second = m_tournament_blue_players.count(username) > 0; + if (!first && !second) + return false; + char votable = m_tournament_votability[m_tournament_game]; + if (votable == '+') + return true; + return (votable == 'F' && first) || (votable == 'S' && second); +} + +bool Tournament::hasHostRights(std::shared_ptr peer) +{ + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + return m_tournament_referees.count(username) > 0; +} + +bool Tournament::hasHammerRights(std::shared_ptr peer) +{ + std::string username = StringUtils::wideToUtf8( + peer->getPlayerProfiles()[0]->getName()); + return m_tournament_referees.count(username) > 0; +} + +int Tournament::editMuteall(const std::string& username, int type) +{ + return m_tournament_mutealls.set(username, type); +} + + +int Tournament::getNextGameNumber() const +{ + int res = m_tournament_game + 1; + if (res == m_tournament_max_games) + res = 0; + return res; +} + +int Tournament::getDefaultDuration() const +{ + return ServerConfig::m_fixed_lap_count; +} + +bool Tournament::isValidGameCmdInput(int new_game_number, int new_duration, int addition) const +{ + return new_game_number >= 0 + && new_game_number < m_tournament_max_games + && new_duration >= 0 + && addition >= 0 + && addition <= 59; +} + +void Tournament::getGameCmdInput(int& game_number, int& duration, int& addition) const +{ + game_number = m_tournament_game; + duration = m_tournament_length; + addition = m_extra_seconds; +} + +void Tournament::setGameCmdInput(int new_game_number, int new_duration, int addition) +{ + m_tournament_game = new_game_number; + m_tournament_length = new_duration; + m_extra_seconds = 0.0f; + if (addition > 0) { + m_extra_seconds = 60.0f - addition; + } +} + +void Tournament::setTeam(KartTeam team, const std::string& username, bool permanent) +{ + if (team == KART_TEAM_RED) + { + m_tournament_red_players.insert(username); + if (permanent) + m_tournament_init_red.insert(username); + } + else if (team == KART_TEAM_BLUE) + { + m_tournament_blue_players.insert(username); + if (permanent) + m_tournament_init_blue.insert(username); + } +} + +void Tournament::setReferee(const std::string& username, bool permanent) +{ + m_tournament_referees.insert(username); + if (permanent) + m_tournament_init_ref.insert(username); +} + +void Tournament::eraseFromAllTournamentCategories(const std::string& username, bool permanent) +{ + m_tournament_red_players.erase(username); + m_tournament_blue_players.erase(username); + m_tournament_referees.erase(username); + if (permanent) + { + m_tournament_init_red.erase(username); + m_tournament_init_blue.erase(username); + m_tournament_init_ref.erase(username); + } +} + +std::vector Tournament::getMapHistory() const +{ + return m_tournament_arenas; +} + +bool Tournament::assignToHistory(int index, const std::string& map_id) +{ + if (index >= g_history_limit) + return false; + if (index >= (int)m_tournament_arenas.size()) + m_tournament_arenas.resize(index + 1, ""); + m_tournament_arenas[index] = map_id; + return true; +} \ No newline at end of file diff --git a/src/utils/tournament.hpp b/src/utils/tournament.hpp new file mode 100644 index 00000000000..dece32f13ab --- /dev/null +++ b/src/utils/tournament.hpp @@ -0,0 +1,142 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef TOURNAMENT_HPP +#define TOURNAMENT_HPP + +#include "network/remote_kart_info.hpp" +#include "utils/types.hpp" +#include "utils/set_with_flip.hpp" + +#include +#include +#include +#include +class FilterContext; +class PeerVote; +class TrackFilter; +class ServerLobby; +class STKPeer; + +/** This class combines things that were previously located in server lobby + * (m_tournament_*) and were related to Soccer Tournaments. + * The current plan is to make it contain generic tournament things, while + * specific things like format, modes, etc would be in other new classes. + */ +class Tournament +{ +public: + enum TournamentRole: int8_t + { + TR_RED_PLAYER = 0, + TR_BLUE_PLAYER = 1, + TR_JUDGE = 2, + TR_SPECTATOR = -1, + }; + + static KartTeam roleToTeam(TournamentRole role); + static std::string roleToString(TournamentRole role); + static char roleToCbar(TournamentRole role); + static TournamentRole charToRole(char c); + static std::string charToString(char c); + + + Tournament(ServerLobby* lobby); + void initTournamentPlayers(); + void applyFiltersForThisGame(FilterContext& track_context); + std::set getThoseWhoSeeTeamchats() const; + bool checkSenderInRefsOrPlayers(std::shared_ptr sender) const; + std::set getImportantChatPlayers() const; + void fillNextArena(const std::string& track_name); + void applyRestrictionsOnDefaultVote(PeerVote* default_vote) const; + void applyRestrictionsOnVote(PeerVote* vote) const; + void onRaceFinished() const; + void updateTournamentRole(std::shared_ptr peer); + + KartTeam getTeam(std::string utf8_online_name) const; + bool canPlay(const std::string& username) const; + bool canVote(std::shared_ptr peer) const; + + bool hasHostRights(std::shared_ptr peer); + bool hasHammerRights(std::shared_ptr peer); + + int editMuteall(const std::string& username, int type); + + bool hasGoalsLimit() const; + bool hasGoalsLimit(int game) const; + bool hasColorsSwapped() const; + bool hasColorsSwapped(int game) const; + bool canChangeTeam() const { return false; } + bool forbidStarting() const { return true; } + int getNextGameNumber() const; + int getDefaultDuration() const; + bool isValidGameNumber(int number) const; + int minGameNumber() const { return 0; } + int maxGameNumber() const { return m_tournament_max_games - 1; } + bool isValidGameCmdInput(int new_game_number, int new_duration, int addition) const; + void getGameCmdInput(int& game_number, int& duration, int& addition) const; + void setGameCmdInput(int new_game_number, int new_duration, int addition); + void setTeam(KartTeam team, const std::string& username, bool permanent); + void setReferee(const std::string& username, bool permanent); + void eraseFromAllTournamentCategories(const std::string& username, bool permanent); + std::vector getMapHistory() const; + bool assignToHistory(int index, const std::string& map_id); + + float getExtraSeconds() const { return m_extra_seconds; } + +private: + ServerLobby* m_lobby; + + std::set m_tournament_red_players; + + std::set m_tournament_blue_players; + + std::set m_tournament_referees; + + SetWithFlip m_tournament_mutealls; + + std::set m_tournament_init_red; + + std::set m_tournament_init_blue; + + std::set m_tournament_init_ref; + + bool m_tournament_limited_chat; + + int m_tournament_length; + + int m_tournament_max_games; + + std::string m_tournament_game_limits; + + std::string m_tournament_colors; + + std::string m_tournament_votability; + + std::vector m_tournament_arenas; + + std::vector m_tournament_track_filters; + + int m_tournament_game; + + std::vector m_tournament_must_have_tracks; + + float m_extra_seconds; +}; + +#endif \ No newline at end of file From 5f0f0a3df02c268d0c747c6bab5c9a8b7da6d7e8 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 25 Feb 2025 22:52:54 +0400 Subject: [PATCH 577/830] Compilation and warning fixes Some modes still don't run normally --- src/modes/soccer_world.cpp | 7 +- src/modes/world.hpp | 2 +- src/network/database_connector.hpp | 2 +- src/network/game_setup.cpp | 2 +- src/network/game_setup.hpp | 6 +- src/network/protocols/command_manager.cpp | 14 ++-- src/network/protocols/server_lobby.cpp | 2 + src/network/protocols/server_lobby.hpp | 2 +- src/utils/tournament.cpp | 60 ---------------- src/utils/tournament.hpp | 19 +---- src/utils/tournament_role.cpp | 86 +++++++++++++++++++++++ src/utils/tournament_role.hpp | 43 ++++++++++++ src/utils/track_filter.hpp | 1 + 13 files changed, 150 insertions(+), 96 deletions(-) create mode 100644 src/utils/tournament_role.cpp create mode 100644 src/utils/tournament_role.hpp diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp index 25b9b5560af..f34ce73a214 100644 --- a/src/modes/soccer_world.cpp +++ b/src/modes/soccer_world.cpp @@ -662,8 +662,7 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) sd.m_time = getTime(); // Notice: true first_goal means it's blue goal being shoot, // so red team can score - // if (!stopped) - m_red_scorers.push_back(sd); + m_red_scorers.push_back(sd); } else { @@ -673,8 +672,8 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) } else sd.m_time = getTime(); - // if (!stopped) - m_blue_scorers.push_back(sd); + + m_blue_scorers.push_back(sd); } if (NetworkConfig::get()->isNetworking() && NetworkConfig::get()->isServer()) diff --git a/src/modes/world.hpp b/src/modes/world.hpp index 342c82f1b09..d8bc751e982 100644 --- a/src/modes/world.hpp +++ b/src/modes/world.hpp @@ -46,7 +46,7 @@ class AbstractKart; class BareNetworkString; class btRigidBody; class Controller; -class GameInfo; +struct GameInfo; class ItemState; class PhysicalObject; class STKPeer; diff --git a/src/network/database_connector.hpp b/src/network/database_connector.hpp index 81080680461..a4dff734e49 100644 --- a/src/network/database_connector.hpp +++ b/src/network/database_connector.hpp @@ -31,7 +31,7 @@ #include #include -class GameInfo; +struct GameInfo; class SocketAddress; class STKPeer; class NetworkPlayerProfile; diff --git a/src/network/game_setup.cpp b/src/network/game_setup.cpp index dbd2d6464a0..d86a62721d1 100644 --- a/src/network/game_setup.cpp +++ b/src/network/game_setup.cpp @@ -114,7 +114,7 @@ void GameSetup::addServerInfo(NetworkString* ns) // Reserve for extra spectators .addUInt8(0) .addUInt8((uint8_t)sl->getGameMode()); - if (hasExtraSeverInfo()) + if (hasExtraServerInfo()) { if (isGrandPrix()) { diff --git a/src/network/game_setup.hpp b/src/network/game_setup.hpp index a539acb50d3..36811d51b16 100644 --- a/src/network/game_setup.hpp +++ b/src/network/game_setup.hpp @@ -99,11 +99,11 @@ class GameSetup // ------------------------------------------------------------------------ bool isGrandPrix() const { return m_is_grand_prix.load(); } // ------------------------------------------------------------------------ - bool hasExtraSeverInfo() const { return m_extra_server_info != -1; } + bool hasExtraServerInfo() const { return m_extra_server_info != -1; } // ------------------------------------------------------------------------ uint8_t getExtraServerInfo() const { - assert(hasExtraSeverInfo()); + assert(hasExtraServerInfo()); return (uint8_t)m_extra_server_info; } // ------------------------------------------------------------------------ @@ -117,7 +117,7 @@ class GameSetup // ------------------------------------------------------------------------ bool isSoccerGoalTarget() const { - assert(hasExtraSeverInfo()); + assert(hasExtraServerInfo()); return m_extra_server_info != 0; } // ------------------------------------------------------------------------ diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index b8620ef3c97..d1d82119ec6 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -1149,7 +1149,7 @@ void CommandManager::process_config(Context& context) } int difficulty = m_lobby->getDifficulty(); int mode = m_lobby->getGameMode(); - bool goal_target = (m_lobby->m_game_setup->hasExtraSeverInfo() ? m_lobby->isSoccerGoalTarget() : false); + bool goal_target = (m_lobby->m_game_setup->hasExtraServerInfo() ? m_lobby->isSoccerGoalTarget() : false); // m_aux_goal_aliases[goal_target ? 1 : 0][0] std::string msg = "Current config: "; auto get_first_if_exists = [&](std::vector& v) -> std::string { @@ -1181,7 +1181,7 @@ void CommandManager::process_config_assign(Context& context) const auto& argv = context.m_argv; int difficulty = m_lobby->getDifficulty(); int mode = m_lobby->getGameMode(); - bool goal_target = (m_lobby->m_game_setup->hasExtraSeverInfo() ? m_lobby->isSoccerGoalTarget() : false); + bool goal_target = (m_lobby->m_game_setup->hasExtraServerInfo() ? m_lobby->isSoccerGoalTarget() : false); bool user_chose_difficulty = false; bool user_chose_mode = false; bool user_chose_target = false; @@ -1474,7 +1474,6 @@ void CommandManager::process_checkaddon(Context& context) server_status |= HAS_MAP; auto peers = STKHost::get()->getPeers(); - unsigned total_players = 0; for (auto p : peers) { if (!p || !p->isValidated() || p->isWaitingForGame() @@ -1490,7 +1489,6 @@ void CommandManager::process_checkaddon(Context& context) if (kt.second.find(id) != kt.second.end()) status |= HAS_MAP; players[status].push_back(username); - ++total_players; } std::string response = ""; @@ -3538,7 +3536,7 @@ void CommandManager::process_role(Context& context) } if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, Tournament::charToString(role_char)); + role_changed = StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char)); if (player_peer->hasPlayerProfiles()) m_lobby->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_RED); m_lobby->sendStringToPeer(role_changed, player_peer); @@ -3558,7 +3556,7 @@ void CommandManager::process_role(Context& context) } if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, Tournament::charToString(role_char)); + role_changed = StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char)); if (player_peer->hasPlayerProfiles()) m_lobby->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_BLUE); m_lobby->sendStringToPeer(role_changed, player_peer); @@ -3571,7 +3569,7 @@ void CommandManager::process_role(Context& context) m_tournament->setReferee(u, permanent); if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, Tournament::charToString(role_char)); + role_changed = StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char)); if (player_peer->hasPlayerProfiles()) m_lobby->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); m_lobby->sendStringToPeer(role_changed, player_peer); @@ -3582,7 +3580,7 @@ void CommandManager::process_role(Context& context) { if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, Tournament::charToString(role_char)); + role_changed = StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char)); if (player_peer->hasPlayerProfiles()) m_lobby->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); m_lobby->sendStringToPeer(role_changed, player_peer); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index ab76010ced8..bec89393839 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -5714,6 +5714,8 @@ bool ServerLobby::writeOnePlayerReport(std::shared_ptr reporter, bool written = m_db_connector->writeReport(reporter, reporter_npp, reporter, reporter_npp, info_w); return written; +#else + return false; #endif } // writeOnePlayerReport //----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 78a79190333..543f71c7eba 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -41,7 +41,7 @@ class BareNetworkString; class DatabaseConnector; -class GameInfo; +struct GameInfo; class NetworkItemManager; class NetworkString; class NetworkPlayerProfile; diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp index 33a62b80b20..c94535cceeb 100644 --- a/src/utils/tournament.cpp +++ b/src/utils/tournament.cpp @@ -40,69 +40,9 @@ namespace { - using T = Tournament::TournamentRole; - - static std::unordered_map g_roleToTeam = { - {T::TR_RED_PLAYER, KART_TEAM_RED}, - {T::TR_BLUE_PLAYER, KART_TEAM_BLUE}, - {T::TR_JUDGE, KART_TEAM_NONE}, - {T::TR_SPECTATOR, KART_TEAM_NONE}, - }; - - static std::unordered_map g_roleToString = { - {T::TR_RED_PLAYER, "red player"}, - {T::TR_BLUE_PLAYER, "blue player"}, - {T::TR_JUDGE, "referee"}, - {T::TR_SPECTATOR, "spectator"}, - }; - - static std::unordered_map g_roleToChar = { - {T::TR_RED_PLAYER, 'r'}, - {T::TR_BLUE_PLAYER, 'b'}, - {T::TR_JUDGE, 'j'}, - {T::TR_SPECTATOR, 's'}, - }; - - static std::unordered_map g_charToRole = { - {'r', T::TR_RED_PLAYER}, - {'b', T::TR_BLUE_PLAYER}, - {'j', T::TR_JUDGE}, - {'s', T::TR_SPECTATOR}, - }; - static int g_history_limit = 100; } - -KartTeam Tournament::roleToTeam(TournamentRole role) -{ - return g_roleToTeam[role]; -} - -std::string Tournament::roleToString(TournamentRole role) -{ - return g_roleToString[role]; -} - -char Tournament::roleToCbar(TournamentRole role) -{ - return g_roleToChar[role]; -} - -Tournament::TournamentRole Tournament::charToRole(char c) -{ - auto it = g_charToRole.find(c); - if (it != g_charToRole.end()) - return it->second; - return TR_SPECTATOR; -} - -std::string Tournament::charToString(char c) -{ - return roleToString(charToRole(c)); -} - - Tournament::Tournament(ServerLobby* lobby): m_lobby(lobby) { initTournamentPlayers(); diff --git a/src/utils/tournament.hpp b/src/utils/tournament.hpp index dece32f13ab..7dbae34d1c1 100644 --- a/src/utils/tournament.hpp +++ b/src/utils/tournament.hpp @@ -19,15 +19,15 @@ #ifndef TOURNAMENT_HPP #define TOURNAMENT_HPP -#include "network/remote_kart_info.hpp" #include "utils/types.hpp" #include "utils/set_with_flip.hpp" +#include "utils/tournament_role.hpp" #include #include #include #include -class FilterContext; +struct FilterContext; class PeerVote; class TrackFilter; class ServerLobby; @@ -41,21 +41,6 @@ class STKPeer; class Tournament { public: - enum TournamentRole: int8_t - { - TR_RED_PLAYER = 0, - TR_BLUE_PLAYER = 1, - TR_JUDGE = 2, - TR_SPECTATOR = -1, - }; - - static KartTeam roleToTeam(TournamentRole role); - static std::string roleToString(TournamentRole role); - static char roleToCbar(TournamentRole role); - static TournamentRole charToRole(char c); - static std::string charToString(char c); - - Tournament(ServerLobby* lobby); void initTournamentPlayers(); void applyFiltersForThisGame(FilterContext& track_context); diff --git a/src/utils/tournament_role.cpp b/src/utils/tournament_role.cpp new file mode 100644 index 00000000000..c0a4d22c3db --- /dev/null +++ b/src/utils/tournament_role.cpp @@ -0,0 +1,86 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2024 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/tournament_role.hpp" + +KartTeam Conversions::roleToTeam(TournamentRole role) +{ + switch (role) + { + case TR_RED_PLAYER: + return KART_TEAM_RED; + case TR_BLUE_PLAYER: + return KART_TEAM_BLUE; + case TR_JUDGE: + return KART_TEAM_NONE; + case TR_SPECTATOR: + return KART_TEAM_NONE; + } +} // roleToTeam + +std::string Conversions::roleToString(TournamentRole role) +{ + switch (role) + { + case TR_RED_PLAYER: + return "red player"; + case TR_BLUE_PLAYER: + return "blue player"; + case TR_JUDGE: + return "referee"; + case TR_SPECTATOR: + return "spectator"; + } +} // roleToString + +char Conversions::roleToChar(TournamentRole role) +{ + switch (role) + { + case TR_RED_PLAYER: + return 'r'; + case TR_BLUE_PLAYER: + return 'b'; + case TR_JUDGE: + return 'j'; + case TR_SPECTATOR: + return 's'; + } +} // roleToChar + +TournamentRole Conversions::charToRole(char c) +{ + switch (c) + { + case 'r': + return TR_RED_PLAYER; + case 'b': + return TR_BLUE_PLAYER; + case 'j': + return TR_JUDGE; + case 's': + return TR_SPECTATOR; + default: + return TR_SPECTATOR; + } +} // charToRole + +std::string Conversions::roleCharToString(char c) +{ + return roleToString(charToRole(c)); +} // roleCharToString diff --git a/src/utils/tournament_role.hpp b/src/utils/tournament_role.hpp new file mode 100644 index 00000000000..34480b48176 --- /dev/null +++ b/src/utils/tournament_role.hpp @@ -0,0 +1,43 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef TOURNAMENT_ROLE_HPP +#define TOURNAMENT_ROLE_HPP + +#include "utils/types.hpp" +#include "network/remote_kart_info.hpp" +#include + +enum TournamentRole: int8_t +{ + TR_RED_PLAYER = 0, + TR_BLUE_PLAYER = 1, + TR_JUDGE = 2, + TR_SPECTATOR = -1, +}; + +namespace Conversions +{ + KartTeam roleToTeam(TournamentRole role); + std::string roleToString(TournamentRole role); + char roleToChar(TournamentRole role); + TournamentRole charToRole(char c); + std::string roleCharToString(char c); +} + +#endif \ No newline at end of file diff --git a/src/utils/track_filter.hpp b/src/utils/track_filter.hpp index 2222e8874cc..f6ecd736b7c 100644 --- a/src/utils/track_filter.hpp +++ b/src/utils/track_filter.hpp @@ -61,6 +61,7 @@ class Filter { bool isPlaceholder() const { return m_placeholder; } Filter() {} + virtual ~Filter() {} Filter(std::string input) {} std::string getInitialString() const { return m_initial_string; } virtual void apply(FilterContext& context) const = 0; From 09f393d98896fbac3d4a23cb08c426d2ca3b1ba6 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 1 Mar 2025 02:45:23 +0400 Subject: [PATCH 578/830] Initial work on separating queues from SL and CM I planned to completely remove them from CM, but got confused, so I reverted some changes, hopefully I did it correctly. Small tests seem to work. Also apparently there was a message bug. --- src/network/protocols/command_manager.cpp | 14 ++- src/network/protocols/command_manager.hpp | 2 + src/network/protocols/server_lobby.cpp | 126 +++---------------- src/network/protocols/server_lobby.hpp | 12 +- src/utils/lobby_queues.cpp | 142 ++++++++++++++++++++++ src/utils/lobby_queues.hpp | 66 ++++++++++ src/utils/tournament_role.cpp | 4 + 7 files changed, 246 insertions(+), 120 deletions(-) create mode 100644 src/utils/lobby_queues.cpp create mode 100644 src/utils/lobby_queues.hpp diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index d1d82119ec6..495b3f0ba7d 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -37,6 +37,7 @@ #include "utils/hourglass_reason.hpp" #include "utils/kart_elimination.hpp" #include "utils/lobby_asset_manager.hpp" +#include "utils/lobby_queues.hpp" #include "utils/log.hpp" #include "utils/map_vote_handler.hpp" #include "utils/random_generator.hpp" @@ -614,6 +615,7 @@ CommandManager::CommandManager(ServerLobby* lobby): m_asset_manager = lobby->getLobbyAssetManager(); m_tournament = lobby->getTournament(); + m_lobby_queues = lobby->getLobbyQueues(); m_aux_mode_aliases = { {"m0"}, @@ -2674,7 +2676,7 @@ void CommandManager::process_queue_pop(Context& context) { int another = another_cyclic_queue(x); if (get_queue(x).empty()) { - msg = "The " + get_queue_name(x) + " was empty before."; + msg += "The " + get_queue_name(x) + " was empty before.\n"; } else { @@ -4417,16 +4419,16 @@ std::string CommandManager::getAddonPreferredType() const std::deque>& CommandManager::get_queue(int x) const { if (x == QM_MAP_ONETIME) - return m_lobby->m_onetime_tracks_queue; + return m_lobby_queues->getOnetimeTracksQueue(); if (x == QM_MAP_CYCLIC) - return m_lobby->m_cyclic_tracks_queue; + return m_lobby_queues->getCyclicTracksQueue(); if (x == QM_KART_ONETIME) - return m_lobby->m_onetime_karts_queue; + return m_lobby_queues->getOnetimeKartsQueue(); if (x == QM_KART_CYCLIC) - return m_lobby->m_cyclic_karts_queue; + return m_lobby_queues->getCyclicKartsQueue(); Log::error("CommandManager", "Unknown queue mask %d, revert to map onetime", x); - return m_lobby->m_onetime_tracks_queue; + return m_lobby_queues->getOnetimeTracksQueue(); } // get_queue // ======================================================================== diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index b3f752fe11f..7fc264ad5f0 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -51,6 +51,7 @@ class Event; class STKPeer; class LobbyAssetManager; class Tournament; +class LobbyQueues; class CommandManager { @@ -201,6 +202,7 @@ class CommandManager std::shared_ptr m_asset_manager; std::shared_ptr m_tournament; + std::shared_ptr m_lobby_queues; std::vector> m_all_commands; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index bec89393839..450be644e80 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -52,6 +52,7 @@ #include "utils/game_info.hpp" #include "utils/hit_processor.hpp" #include "utils/lobby_asset_manager.hpp" +#include "utils/lobby_queues.hpp" #include "utils/map_vote_handler.hpp" #include "utils/tournament.hpp" #include "utils/translation.hpp" @@ -123,6 +124,8 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_kart_elimination = std::make_shared(); m_map_vote_handler = std::make_shared(); + m_lobby_queues = std::make_shared(this); + m_fixed_lap = ServerConfig::m_fixed_lap_count; // Server config has better priority than --laps // as it is more flexible and was introduced earlier @@ -185,7 +188,6 @@ ServerLobby::ServerLobby() : LobbyProtocol() } m_allowed_to_start = ServerConfig::m_allowed_to_start; m_game_info = nullptr; - loadTracksQueueFromConfig(); std::string scoring = ServerConfig::m_gp_scoring; loadCustomScoring(scoring); loadWhiteList(); @@ -1089,7 +1091,7 @@ void ServerLobby::asynchronousUpdate() std::string current_kart = players[i]->getKartName(); if (!players[i]->getPeer().get()) continue; - if (areKartFiltersIgnoringKarts()) + if (m_lobby_queues->areKartFiltersIgnoringKarts()) current_kart = ""; std::string name = StringUtils::wideToUtf8(players[i]->getName()); // Note 1: setKartName also resets KartData, and should be called @@ -2371,7 +2373,7 @@ void ServerLobby::startSelection(const Event *event) peer->sendPacket(ns, PRM_RELIABLE); delete ns; - if (areKartFiltersIgnoringKarts()) + if (m_lobby_queues->areKartFiltersIgnoringKarts()) sendStringToPeer(ignored_choice_string, peer); } @@ -2693,30 +2695,7 @@ void ServerLobby::checkRaceFinished() m_map_history.push_back(RaceManager::get()->getTrackName()); - if (!m_onetime_tracks_queue.empty()) - { - m_onetime_tracks_queue.pop_front(); - } - if (!m_cyclic_tracks_queue.empty()) - { - auto item = m_cyclic_tracks_queue.front().get()->getInitialString(); - bool is_placeholder = m_cyclic_tracks_queue.front()->isPlaceholder(); - m_cyclic_tracks_queue.pop_front(); - if (!is_placeholder) - m_cyclic_tracks_queue.push_back(std::make_shared(item)); - } - if (!m_onetime_karts_queue.empty()) - { - m_onetime_karts_queue.pop_front(); - } - if (!m_cyclic_karts_queue.empty()) - { - auto item = m_cyclic_karts_queue.front().get()->getInitialString(); - bool is_placeholder = m_cyclic_karts_queue.front()->isPlaceholder(); - m_cyclic_karts_queue.pop_front(); - if (!is_placeholder) - m_cyclic_karts_queue.push_back(std::make_shared(item)); - } + m_lobby_queues->popOnRaceFinished(); } // checkRaceFinished //----------------------------------------------------------------------------- @@ -4598,7 +4577,7 @@ void ServerLobby::setPlayerKarts(const NetworkString& ns, std::shared_ptrareKartFiltersIgnoringKarts()) current_kart = ""; std::string name = StringUtils::wideToUtf8(peer->getPlayerProfiles()[i]->getName()); peer->getPlayerProfiles()[i]->setKartName(getKartForBadKartChoice(peer, name, current_kart)); @@ -5240,17 +5219,7 @@ void ServerLobby::resetToDefaultSettings() if (!m_preserve.count("direction")) m_fixed_direction = ServerConfig::m_fixed_direction; - if (!m_preserve.count("queue")) - m_onetime_tracks_queue.clear(); - - if (!m_preserve.count("qcyclic")) - m_cyclic_tracks_queue.clear(); - - if (!m_preserve.count("kqueue")) - m_onetime_karts_queue.clear(); - - if (!m_preserve.count("kcyclic")) - m_cyclic_karts_queue.clear(); + m_lobby_queues->resetToDefaultSettings(m_preserve); if (!m_preserve.count("replay")) setConsentOnReplays(false); @@ -5527,38 +5496,6 @@ int ServerLobby::getPermissions(std::shared_ptr peer) const return mask; } // getPermissions //----------------------------------------------------------------------------- -void ServerLobby::loadTracksQueueFromConfig() -{ - std::vector tokens; - m_onetime_tracks_queue.clear(); - m_cyclic_tracks_queue.clear(); - m_onetime_karts_queue.clear(); - m_cyclic_karts_queue.clear(); - - tokens = StringUtils::splitQuoted(ServerConfig::m_tracks_order, ' ', '{', '}', '\\'); - for (std::string& s: tokens) - { - m_onetime_tracks_queue.push_back(std::make_shared(s)); - m_cyclic_tracks_queue.push_back(std::make_shared(TrackFilter::PLACEHOLDER_STRING)); - } - - tokens = StringUtils::splitQuoted(ServerConfig::m_cyclic_tracks_order, ' ', '{', '}', '\\'); - for (std::string& s: tokens) - m_cyclic_tracks_queue.push_back(std::make_shared(s)); - - - tokens = StringUtils::splitQuoted(ServerConfig::m_karts_order, ' ', '{', '}', '\\'); - for (std::string& s: tokens) - { - m_onetime_karts_queue.push_back(std::make_shared(s)); - m_cyclic_karts_queue.push_back(std::make_shared(KartFilter::PLACEHOLDER_STRING)); - } - - tokens = StringUtils::splitQuoted(ServerConfig::m_cyclic_karts_order, ' ', '{', '}', '\\'); - for (std::string& s: tokens) - m_cyclic_karts_queue.push_back(std::make_shared(s)); -} // loadTracksQueueFromConfig -//----------------------------------------------------------------------------- std::string ServerLobby::getGrandPrixStandings(bool showIndividual, bool showTeam) const { std::stringstream response; @@ -5950,28 +5887,21 @@ void ServerLobby::applyAllFilters(std::set& maps, bool use_history) // Please note that use_history refers to using queue filters too - // calls with false only get map sets, etc - FilterContext track_context; - track_context.username = ""; // unused - track_context.num_players = max_player; - track_context.wildcards = m_map_history; - track_context.applied_at_selection_start = true; - track_context.elements = maps; - m_global_filter.apply(track_context); + FilterContext map_context; + map_context.username = ""; // unused + map_context.num_players = max_player; + map_context.wildcards = m_map_history; + map_context.applied_at_selection_start = true; + map_context.elements = maps; + m_global_filter.apply(map_context); if (use_history) { if (m_tournament) - m_tournament->applyFiltersForThisGame(track_context); - track_context.wildcards = m_map_history; - if (!m_onetime_tracks_queue.empty()) - { - m_onetime_tracks_queue.front()->apply(track_context); - } - if (!m_cyclic_tracks_queue.empty()) - { - m_cyclic_tracks_queue.front()->apply(track_context); - } + m_tournament->applyFiltersForThisGame(map_context); + map_context.wildcards = m_map_history; + m_lobby_queues->applyFrontMapFilters(map_context); } - swap(maps, track_context.elements); + swap(maps, map_context.elements); } // applyAllFilters //----------------------------------------------------------------------------- @@ -5986,26 +5916,10 @@ void ServerLobby::applyAllKartFilters(const std::string& username, std::setapply(kart_context); - } - if (!m_cyclic_karts_queue.empty()) - { - m_cyclic_karts_queue.front()->apply(kart_context); - } + m_lobby_queues->applyFrontKartFilters(kart_context); swap(karts, kart_context.elements); } // applyAllKartFilters //----------------------------------------------------------------------------- -bool ServerLobby::areKartFiltersIgnoringKarts() const -{ - if (!m_onetime_karts_queue.empty() && m_onetime_karts_queue.front()->ignoresPlayersInput()) - return true; - if (!m_cyclic_karts_queue.empty() && m_cyclic_karts_queue.front()->ignoresPlayersInput()) - return true; - return false; -} // applyAllKartFilters -//----------------------------------------------------------------------------- std::string ServerLobby::getKartForBadKartChoice(std::shared_ptr peer, const std::string& username, const std::string& check_choice) const { std::set karts = (peer->isAIPeer() ? m_asset_manager->getAvailableKarts() : peer->getClientAssets().first); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 543f71c7eba..a3e84080e9c 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -55,6 +55,7 @@ class CommandManager; class KartElimination; class MapVoteHandler; class Tournament; +class LobbyQueues; namespace Online { @@ -267,13 +268,7 @@ class ServerLobby : public LobbyProtocol std::set m_temp_banned; - std::deque> m_onetime_tracks_queue; - - std::deque> m_cyclic_tracks_queue; - - std::deque> m_onetime_karts_queue; - - std::deque> m_cyclic_karts_queue; + std::shared_ptr m_lobby_queues; std::vector m_map_history; @@ -439,7 +434,6 @@ class ServerLobby : public LobbyProtocol bool canVote(std::shared_ptr peer) const; bool hasHostRights(std::shared_ptr peer) const; std::vector getMissingAssets(std::shared_ptr peer) const; - void loadTracksQueueFromConfig(); std::string getGrandPrixStandings(bool showIndividual = false, bool showTeam = true) const; bool loadCustomScoring(std::string& scoring); void updateWorldSettings(); @@ -554,6 +548,8 @@ class ServerLobby : public LobbyProtocol std::shared_ptr getTournament() const { return m_tournament; } std::map> getCategories() const { return m_player_categories; } + std::shared_ptr getLobbyQueues() const + { return m_lobby_queues; } }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/utils/lobby_queues.cpp b/src/utils/lobby_queues.cpp new file mode 100644 index 00000000000..f18e24a6280 --- /dev/null +++ b/src/utils/lobby_queues.cpp @@ -0,0 +1,142 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/lobby_queues.hpp" +#include "network/protocols/server_lobby.hpp" +#include "network/server_config.hpp" +#include "utils/string_utils.hpp" + +LobbyQueues::LobbyQueues(ServerLobby* lobby): m_lobby(lobby) +{ + loadTracksQueueFromConfig(); +} // LobbyQueues +// ======================================================================== + +void LobbyQueues::loadTracksQueueFromConfig() +{ + std::vector tokens; + m_onetime_tracks_queue.clear(); + m_cyclic_tracks_queue.clear(); + m_onetime_karts_queue.clear(); + m_cyclic_karts_queue.clear(); + + tokens = StringUtils::splitQuoted(ServerConfig::m_tracks_order, ' ', '{', '}', '\\'); + for (std::string& s: tokens) + { + m_onetime_tracks_queue.push_back(std::make_shared(s)); + m_cyclic_tracks_queue.push_back(std::make_shared(TrackFilter::PLACEHOLDER_STRING)); + } + + tokens = StringUtils::splitQuoted(ServerConfig::m_cyclic_tracks_order, ' ', '{', '}', '\\'); + for (std::string& s: tokens) + m_cyclic_tracks_queue.push_back(std::make_shared(s)); + + + tokens = StringUtils::splitQuoted(ServerConfig::m_karts_order, ' ', '{', '}', '\\'); + for (std::string& s: tokens) + { + m_onetime_karts_queue.push_back(std::make_shared(s)); + m_cyclic_karts_queue.push_back(std::make_shared(KartFilter::PLACEHOLDER_STRING)); + } + + tokens = StringUtils::splitQuoted(ServerConfig::m_cyclic_karts_order, ' ', '{', '}', '\\'); + for (std::string& s: tokens) + m_cyclic_karts_queue.push_back(std::make_shared(s)); +} // loadTracksQueueFromConfig +//----------------------------------------------------------------------------- + +void LobbyQueues::popOnRaceFinished() +{ + if (!m_onetime_tracks_queue.empty()) + { + m_onetime_tracks_queue.pop_front(); + } + if (!m_cyclic_tracks_queue.empty()) + { + auto item = m_cyclic_tracks_queue.front().get()->getInitialString(); + bool is_placeholder = m_cyclic_tracks_queue.front()->isPlaceholder(); + m_cyclic_tracks_queue.pop_front(); + if (!is_placeholder) + m_cyclic_tracks_queue.push_back(std::make_shared(item)); + } + if (!m_onetime_karts_queue.empty()) + { + m_onetime_karts_queue.pop_front(); + } + if (!m_cyclic_karts_queue.empty()) + { + auto item = m_cyclic_karts_queue.front().get()->getInitialString(); + bool is_placeholder = m_cyclic_karts_queue.front()->isPlaceholder(); + m_cyclic_karts_queue.pop_front(); + if (!is_placeholder) + m_cyclic_karts_queue.push_back(std::make_shared(item)); + } +} // popOnRaceFinished +//----------------------------------------------------------------------------- + +void LobbyQueues::resetToDefaultSettings(const std::set& preserved_settings) +{ + if (!preserved_settings.count("queue")) + m_onetime_tracks_queue.clear(); + + if (!preserved_settings.count("qcyclic")) + m_cyclic_tracks_queue.clear(); + + if (!preserved_settings.count("kqueue")) + m_onetime_karts_queue.clear(); + + if (!preserved_settings.count("kcyclic")) + m_cyclic_karts_queue.clear(); +} // resetToDefaultSettings +//----------------------------------------------------------------------------- + +void LobbyQueues::applyFrontMapFilters(FilterContext& context) +{ + if (!m_onetime_tracks_queue.empty()) + { + m_onetime_tracks_queue.front()->apply(context); + } + if (!m_cyclic_tracks_queue.empty()) + { + m_cyclic_tracks_queue.front()->apply(context); + } +} // applyFrontMapFilters +//----------------------------------------------------------------------------- + +void LobbyQueues::applyFrontKartFilters(FilterContext& context) +{ + if (!m_onetime_karts_queue.empty()) + { + m_onetime_karts_queue.front()->apply(context); + } + if (!m_cyclic_karts_queue.empty()) + { + m_cyclic_karts_queue.front()->apply(context); + } +} // applyFrontKartFilters +//----------------------------------------------------------------------------- + +bool LobbyQueues::areKartFiltersIgnoringKarts() const +{ + if (!m_onetime_karts_queue.empty() && m_onetime_karts_queue.front()->ignoresPlayersInput()) + return true; + if (!m_cyclic_karts_queue.empty() && m_cyclic_karts_queue.front()->ignoresPlayersInput()) + return true; + return false; +} // applyAllKartFilters +//----------------------------------------------------------------------------- diff --git a/src/utils/lobby_queues.hpp b/src/utils/lobby_queues.hpp new file mode 100644 index 00000000000..e7deb0faacf --- /dev/null +++ b/src/utils/lobby_queues.hpp @@ -0,0 +1,66 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef LOBBY_QUEUES_HPP +#define LOBBY_QUEUES_HPP + +#include "irrString.h" + +#include +#include +#include "utils/track_filter.hpp" +class ServerLobby; + +class LobbyQueues +{ +public: + LobbyQueues(ServerLobby* lobby); + + void loadTracksQueueFromConfig(); + + void popOnRaceFinished(); + + void resetToDefaultSettings(const std::set& preserved_settings); + + void applyFrontMapFilters(FilterContext& context); + + void applyFrontKartFilters(FilterContext& context); + + bool areKartFiltersIgnoringKarts() const; + +private: + ServerLobby* m_lobby; + + std::deque> m_onetime_tracks_queue; + + std::deque> m_cyclic_tracks_queue; + + std::deque> m_onetime_karts_queue; + + std::deque> m_cyclic_karts_queue; + +// Temporary reference getters +public: + std::deque>& getOnetimeTracksQueue() { return m_onetime_tracks_queue; } + std::deque>& getCyclicTracksQueue() { return m_cyclic_tracks_queue; } + std::deque>& getOnetimeKartsQueue() { return m_onetime_karts_queue; } + std::deque>& getCyclicKartsQueue() { return m_cyclic_karts_queue; } + +}; + +#endif \ No newline at end of file diff --git a/src/utils/tournament_role.cpp b/src/utils/tournament_role.cpp index c0a4d22c3db..c40ca220690 100644 --- a/src/utils/tournament_role.cpp +++ b/src/utils/tournament_role.cpp @@ -31,6 +31,7 @@ KartTeam Conversions::roleToTeam(TournamentRole role) case TR_SPECTATOR: return KART_TEAM_NONE; } + return KART_TEAM_NONE; } // roleToTeam std::string Conversions::roleToString(TournamentRole role) @@ -46,6 +47,7 @@ std::string Conversions::roleToString(TournamentRole role) case TR_SPECTATOR: return "spectator"; } + return ""; } // roleToString char Conversions::roleToChar(TournamentRole role) @@ -61,6 +63,7 @@ char Conversions::roleToChar(TournamentRole role) case TR_SPECTATOR: return 's'; } + return ' '; } // roleToChar TournamentRole Conversions::charToRole(char c) @@ -78,6 +81,7 @@ TournamentRole Conversions::charToRole(char c) default: return TR_SPECTATOR; } + return TR_SPECTATOR; } // charToRole std::string Conversions::roleCharToString(char c) From 25311820841f2848dfd0f6a5bc654903d2d390b3 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 1 Mar 2025 03:10:14 +0400 Subject: [PATCH 579/830] Remove WEB_SUPPORT option and its tokens And some minor changes --- src/network/database_connector.cpp | 47 ------------------- src/network/database_connector.hpp | 9 ---- src/network/protocols/command_manager.cpp | 41 ---------------- src/network/protocols/command_manager.hpp | 3 -- src/network/protocols/server_lobby.cpp | 57 +++-------------------- src/network/protocols/server_lobby.hpp | 13 +----- src/network/server_config.hpp | 9 ---- src/utils/lobby_queues.cpp | 2 +- src/utils/lobby_queues.hpp | 5 +- 9 files changed, 9 insertions(+), 177 deletions(-) diff --git a/src/network/database_connector.cpp b/src/network/database_connector.cpp index 769b21e0a90..95bff2c6648 100644 --- a/src/network/database_connector.cpp +++ b/src/network/database_connector.cpp @@ -139,10 +139,6 @@ void DatabaseConnector::initDatabase() m_ipv6_geolocation_table_exists); checkTableExists(ServerConfig::m_records_table_name, m_records_table_exists, true); - -#ifdef ENABLE_WEB_SUPPORT - checkTableExists(ServerConfig::m_tokens_table, m_tokens_table_exists); -#endif } // initDatabase //----------------------------------------------------------------------------- @@ -1263,49 +1259,6 @@ void DatabaseConnector::insertManyResults(const GameInfo& game_info) } } // insertManyResults -//----------------------------------------------------------------------------- -#ifdef ENABLE_WEB_SUPPORT - -bool DatabaseConnector::getAllTokens(std::vector& result) -{ - if (!m_tokens_table_exists) - return false; - std::vector> output; - std::string query = StringUtils::insertValues( - "SELECT distinct token FROM %s;", - ServerConfig::m_tokens_table.c_str()); - if (!easySQLQuery(query, &output)) - return false; - result.clear(); - for (const auto& row: output) - if (!row.empty()) - result.push_back(row[0]); - return true; -} // getAllTokens - -//----------------------------------------------------------------------------- -/** Inserts a generated token into the database. - * \param username The name of user whose token it is. - * \param token The token itself. - * \return True in case of success. - */ -bool DatabaseConnector::insertToken(std::string& username, std::string& token) -{ - if (!m_tokens_table_exists) - return false; - std::shared_ptr coll = std::make_shared(); - std::string query = StringUtils::insertValues( - "INSERT INTO %s (username, token) " - "VALUES (%s, %s);", - ServerConfig::m_tokens_table.c_str(), - Binder(coll, username, "username"), - Binder(coll, token, "token") - ); - return easySQLQuery(query, nullptr, coll->getBindFunction()); -} // insertToken - -#endif // ENABLE_WEB_SUPPORT - //----------------------------------------------------------------------------- #endif // ENABLE_SQLITE3 diff --git a/src/network/database_connector.hpp b/src/network/database_connector.hpp index a4dff734e49..f2929d39883 100644 --- a/src/network/database_connector.hpp +++ b/src/network/database_connector.hpp @@ -120,10 +120,6 @@ class DatabaseConnector bool m_records_table_exists; uint64_t m_last_poll_db_time; -#ifdef ENABLE_WEB_SUPPORT - bool m_tokens_table_exists; -#endif - public: /** Corresponds to the row of IPv4 ban table. */ struct IpBanTableData @@ -207,11 +203,6 @@ class DatabaseConnector void deleteServerMessage(int row_id) const; bool getBestResult(const GameInfo& game_info, bool* exists, std::string* user, double* result); void insertManyResults(const GameInfo& game_info); - -#ifdef ENABLE_WEB_SUPPORT - bool getAllTokens(std::vector& result); - bool insertToken(std::string& username, std::string& token); -#endif }; #endif // ifndef DATABASE_CONNECTOR_HPP diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 495b3f0ba7d..c1c47bc550e 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -497,9 +497,6 @@ void CommandManager::initCommands() applyFunctionIfPossible("version", &CM::process_text); applyFunctionIfPossible("clear", &CM::process_text); applyFunctionIfPossible("register", &CM::process_register); -#ifdef ENABLE_WEB_SUPPORT - applyFunctionIfPossible("token", &CM::process_token); -#endif applyFunctionIfPossible("muteall", &CM::process_muteall); applyFunctionIfPossible("game", &CM::process_game); applyFunctionIfPossible("role", &CM::process_role); @@ -3310,44 +3307,6 @@ void CommandManager::process_register(Context& context) } // process_register // ======================================================================== -#ifdef ENABLE_WEB_SUPPORT -void CommandManager::process_token(Context& context) -{ - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - if (!peer->hasPlayerProfiles()) - return; - int online_id = peer->getPlayerProfiles()[0]->getOnlineId(); - if (online_id <= 0) - { - std::string msg = "Please join with a valid online STK account."; - m_lobby->sendStringToPeer(msg, peer); - return; - } - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); - std::string token = m_lobby->getToken(); - while (m_lobby->m_web_tokens.count(token)) - token = m_lobby->getToken(); - m_lobby->m_web_tokens.insert(token); - std::string msg = "Your token is " + token; -#ifdef ENABLE_SQLITE3 - if (m_lobby->m_db_connector->insertToken(username, token)) - msg += "\nRetype it on the website to connect your STK account. "; - else - msg = "An error occurred, please try again."; -#else - msg += "\nThough it is useless..."; -#endif - m_lobby->sendStringToPeer(msg, peer); -} // process_token -#endif -// ======================================================================== - void CommandManager::process_muteall(Context& context) { auto& argv = context.m_argv; diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 7fc264ad5f0..2777bada9a2 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -328,9 +328,6 @@ class CommandManager void process_scoring(Context& context); void process_scoring_assign(Context& context); void process_register(Context& context); -#ifdef ENABLE_WEB_SUPPORT - void process_token(Context& context); -#endif // soccer tournament commands void process_muteall(Context& context); void process_game(Context& context); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 450be644e80..d3be879ae35 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -124,7 +124,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_kart_elimination = std::make_shared(); m_map_vote_handler = std::make_shared(); - m_lobby_queues = std::make_shared(this); + m_lobby_queues = std::make_shared(); m_fixed_lap = ServerConfig::m_fixed_lap_count; // Server config has better priority than --laps @@ -177,25 +177,23 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_difficulty.store(ServerConfig::m_server_difficulty); m_game_mode.store(ServerConfig::m_server_mode); m_default_vote = new PeerVote(); + #ifdef ENABLE_SQLITE3 - m_db_connector = new DatabaseConnector(); + m_db_connector = std::make_shared(); m_db_connector->initDatabase(); #endif + initCategories(); + if (ServerConfig::m_soccer_tournament) - { m_tournament = std::make_shared(this); - } + m_allowed_to_start = ServerConfig::m_allowed_to_start; m_game_info = nullptr; std::string scoring = ServerConfig::m_gp_scoring; loadCustomScoring(scoring); loadWhiteList(); loadPreservedSettings(); -#ifdef ENABLE_WEB_SUPPORT - m_token_generation_tries.store(0); - loadAllTokens(); -#endif } // ServerLobby //----------------------------------------------------------------------------- @@ -216,7 +214,6 @@ ServerLobby::~ServerLobby() #ifdef ENABLE_SQLITE3 m_db_connector->destroyDatabase(); - delete m_db_connector; #endif } // ~ServerLobby @@ -5734,48 +5731,6 @@ std::string ServerLobby::getRecord(std::string& track, std::string& mode, #endif //----------------------------------------------------------------------------- -#ifdef ENABLE_WEB_SUPPORT - -void ServerLobby::loadAllTokens() -{ -#ifdef ENABLE_SQLITE3 - std::vector tokens; - if (!m_db_connector->getAllTokens(tokens)) - { - Log::warn("ServerLobby", "Could not make a query to retrieve tokens."); - } - else - { - Log::info("ServerLobby", "Successfully loaded %d tokens.", (int)tokens.size()); - for (std::string& s: tokens) - m_web_tokens.insert(s); - } -#endif -} // loadAllTokens -//----------------------------------------------------------------------------- - -std::string ServerLobby::getToken() -{ - int tries = m_token_generation_tries.load(); - m_token_generation_tries.store(tries + 1); - std::mt19937 mt(time(nullptr) + tries); - std::string token; - for (int i = 0; i < 16; ++i) - { - int z = mt() % 36; - if (z < 26) - token.push_back('a' + z); - else - token.push_back('0' + z - 26); - if ((i & 3) == 3) - token.push_back(' '); - } - token.pop_back(); - return token; -} // getToken -//----------------------------------------------------------------------------- -#endif // ENABLE_WEB_SUPPORT - bool ServerLobby::isSoccerGoalTarget() const { return m_game_setup->isSoccerGoalTarget(); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index a3e84080e9c..3515e5a081c 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -116,7 +116,7 @@ class ServerLobby : public LobbyProtocol }; #ifdef ENABLE_SQLITE3 - DatabaseConnector* m_db_connector; + std::shared_ptr m_db_connector; void pollDatabase(); #endif @@ -302,12 +302,6 @@ class ServerLobby : public LobbyProtocol GameInfo* m_game_info; -#ifdef ENABLE_WEB_SUPPORT - std::set m_web_tokens; - - std::atomic m_token_generation_tries; -#endif - // config for troll system bool m_troll_active; @@ -442,11 +436,6 @@ class ServerLobby : public LobbyProtocol void changeLimitForTournament(bool goal_target); std::shared_ptr getCommandManager(); - // bool tournamentHasIcy(int game) const; -#ifdef ENABLE_WEB_SUPPORT - void loadAllTokens(); - std::string getToken(); -#endif public: ServerLobby(); virtual ~ServerLobby(); diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index ea7dcc76168..fe4f8d3b4f3 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -733,15 +733,6 @@ namespace ServerConfig "is counted, no-own-goals - last touching player of scoring team " "is counted if existing, advanced - as standard for now.")); -#ifdef ENABLE_WEB_SUPPORT - - SERVER_CFG_PREFIX StringServerConfigParam m_tokens_table - SERVER_CFG_DEFAULT(StringServerConfigParam("", - "tokens-table", - "A table containing tokens for website authentication using " - "STK account only.")); -#endif - SERVER_CFG_PREFIX StringServerConfigParam m_power_password SERVER_CFG_DEFAULT(StringServerConfigParam("", "power-password", diff --git a/src/utils/lobby_queues.cpp b/src/utils/lobby_queues.cpp index f18e24a6280..7ce15757adc 100644 --- a/src/utils/lobby_queues.cpp +++ b/src/utils/lobby_queues.cpp @@ -21,7 +21,7 @@ #include "network/server_config.hpp" #include "utils/string_utils.hpp" -LobbyQueues::LobbyQueues(ServerLobby* lobby): m_lobby(lobby) +LobbyQueues::LobbyQueues() { loadTracksQueueFromConfig(); } // LobbyQueues diff --git a/src/utils/lobby_queues.hpp b/src/utils/lobby_queues.hpp index e7deb0faacf..61149836e52 100644 --- a/src/utils/lobby_queues.hpp +++ b/src/utils/lobby_queues.hpp @@ -24,12 +24,11 @@ #include #include #include "utils/track_filter.hpp" -class ServerLobby; class LobbyQueues { public: - LobbyQueues(ServerLobby* lobby); + LobbyQueues(); void loadTracksQueueFromConfig(); @@ -44,8 +43,6 @@ class LobbyQueues bool areKartFiltersIgnoringKarts() const; private: - ServerLobby* m_lobby; - std::deque> m_onetime_tracks_queue; std::deque> m_cyclic_tracks_queue; From 887786c860aa4bcd7b5a0dd5dc5c99352c96c168 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 2 Mar 2025 15:04:10 +0400 Subject: [PATCH 580/830] Move many things to LobbySettings, fix some bugs I got scared that I accidentally discarded changes in one of files. Very frightening. --- CMakeLists.txt | 6 - NETWORKING.md | 7 +- data/commands.xml | 5 - src/achievements/achievements_status.cpp | 4 +- src/addons/addons_manager.cpp | 4 + src/audio/music_information.cpp | 7 +- src/challenges/challenge_data.cpp | 8 +- src/challenges/challenge_status.cpp | 2 +- src/challenges/unlock_manager.cpp | 2 +- src/config/player_profile.cpp | 2 +- src/graphics/irr_driver.cpp | 6 +- src/graphics/particle_kind_manager.cpp | 2 +- src/io/file_manager.cpp | 2 +- src/io/rich_presence.cpp | 2 +- src/items/bowling.cpp | 8 +- src/items/cake.cpp | 8 +- src/karts/explosion_animation.cpp | 4 +- src/karts/kart.cpp | 2 +- src/main.cpp | 17 +- src/modes/capture_the_flag.cpp | 2 +- src/modes/demo_world.cpp | 2 + src/modes/soccer_world.cpp | 2 +- src/modes/world.cpp | 4 +- src/modes/world.hpp | 6 +- src/network/protocols/client_lobby.cpp | 8 +- src/network/protocols/command_manager.cpp | 258 ++---- src/network/protocols/command_manager.hpp | 6 + src/network/protocols/lobby_protocol.cpp | 2 +- src/network/protocols/server_lobby.cpp | 675 ++++----------- src/network/protocols/server_lobby.hpp | 143 +--- src/network/server.cpp | 2 +- src/race/grand_prix_data.cpp | 13 +- src/race/highscores.cpp | 1 + src/race/race_manager.cpp | 2 +- src/replay/replay_play.cpp | 2 +- src/states_screens/arenas_screen.cpp | 5 +- src/states_screens/dialogs/addons_loading.cpp | 2 +- src/states_screens/dialogs/addons_pack.cpp | 2 + .../dialogs/ghost_replay_info_dialog.cpp | 2 +- .../dialogs/high_score_info_dialog.cpp | 4 +- .../dialogs/select_challenge.cpp | 2 +- src/states_screens/easter_egg_screen.cpp | 10 +- src/states_screens/edit_gp_screen.cpp | 4 +- src/states_screens/edit_track_screen.cpp | 8 +- src/states_screens/feature_unlocked.cpp | 6 +- src/states_screens/ghost_replay_selection.cpp | 4 +- src/states_screens/gp_info_screen.cpp | 10 +- src/states_screens/grand_prix_cutscene.cpp | 2 +- .../grand_prix_editor_screen.cpp | 4 +- src/states_screens/high_score_selection.cpp | 2 +- src/states_screens/main_menu_screen.cpp | 4 + .../online/server_selection.cpp | 4 +- src/states_screens/online/tracks_screen.cpp | 12 +- src/states_screens/race_gui_overworld.cpp | 2 +- src/states_screens/race_result_gui.cpp | 2 +- src/states_screens/track_info_screen.cpp | 2 +- src/states_screens/tracks_and_gp_screen.cpp | 8 +- src/tracks/arena_graph.cpp | 2 +- src/tracks/terrain_info.cpp | 2 +- src/tracks/track.cpp | 2 +- src/tracks/track_manager.cpp | 9 +- src/tracks/track_manager.hpp | 5 +- src/tracks/track_object_presentation.cpp | 2 +- src/utils/debug.cpp | 2 +- src/utils/extract_mobile_assets.cpp | 2 +- src/utils/hit_processor.cpp | 47 +- src/utils/hit_processor.hpp | 30 +- src/utils/lobby_asset_manager.cpp | 16 +- src/utils/lobby_settings.cpp | 803 ++++++++++++++++++ src/utils/lobby_settings.hpp | 239 ++++++ src/utils/map_vote_handler.cpp | 37 +- src/utils/map_vote_handler.hpp | 18 +- src/utils/tournament.cpp | 16 +- src/utils/tournament.hpp | 5 +- 74 files changed, 1556 insertions(+), 1008 deletions(-) create mode 100644 src/utils/lobby_settings.cpp create mode 100644 src/utils/lobby_settings.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d22bcef35af..d3540a02b3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,6 @@ CMAKE_DEPENDENT_OPTION(USE_IPV6 "Allow create or connect to game server with IPv option(USE_SYSTEM_WIIUSE "Use system WiiUse instead of the built-in version, when available." OFF) option(USE_SQLITE3 "Use sqlite to manage server stats and ban list." ON) -option(WEB_SUPPORT "Website integration tools" OFF) option(FATAL_WHEN_OLD_RECORDS "Fatal error if the results table is old" ON) if(APPLE) @@ -516,11 +515,6 @@ if(USE_SQLITE3) endif() endif() -# Web support -if(WEB_SUPPORT) - add_definitions(-DENABLE_WEB_SUPPORT) -endif() - # Error if the records table is too old if(FATAL_WHEN_OLD_RECORDS) add_definitions(-DENABLE_FATAL_WHEN_OLD_RECORDS) diff --git a/NETWORKING.md b/NETWORKING.md index 0854779d9c2..4825e382182 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -5,11 +5,11 @@ A reminder: you are looking at NETWORKING.md of the fork, not the one of the sta ## Hosting server You **should** compile STK with `-DSERVER_ONLY=ON`. This option produces a GUI-less STK binary optimized for size and memory usage, useful for situation like in VPS. As this fork is server-side (at least for now), this option is enabled **always** during the testing. You can compile the code without this option, and most likely nothing bad will happen, but it's not an intended way to run this fork. -The other options you should consider using are `-DUSE_SQLITE3=ON`, if you want to use a database for storing data; `-DWEB_SUPPORT=ON`, if you want to use a (slightly deprecated) way to authenticate users with their STK account. +The other option(s) you should consider using are `-DUSE_SQLITE3=ON`, if you want to use a database for storing data. A typical cmake command looks like ```bash -cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSERVER_ONLY=ON -DUSE_SQLITE3=ON -DWEB_SUPPORT=ON +cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DSERVER_ONLY=ON -DUSE_SQLITE3=ON ``` The dependencies for RHEL/CentOS 7 are installed with: @@ -364,9 +364,6 @@ A typical current server configuration xml that fits the current code version is - - - diff --git a/data/commands.xml b/data/commands.xml index ccfff1090f5..d355f6a5f50 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -918,11 +918,6 @@ here later. For now, please refer to the code for the strings being used. --> permissions-verbose="everyone" description="The command is used to register to an event (if the server has a database to store the registrations). Players can provide information while registering." /> - getNumberOfTracks(); + (unsigned int)TrackManager::get()->getNumberOfTracks(); for (unsigned int n = 0; n < track_amount; n++) { - Track* curr = track_manager->getTrack(n); + Track* curr = TrackManager::get()->getTrack(n); if (curr->isArena() || curr->isSoccer()||curr->isInternal()) continue; TrackStats new_track; diff --git a/src/addons/addons_manager.cpp b/src/addons/addons_manager.cpp index c0b1280087e..e8419485bc3 100644 --- a/src/addons/addons_manager.cpp +++ b/src/addons/addons_manager.cpp @@ -364,6 +364,7 @@ void AddonsManager::checkInstalledAddons() // Then tracks // ----------- + std::shared_ptr track_manager = TrackManager::get(); for(unsigned int i=0; igetNumberOfTracks(); i++) { const Track *track = track_manager->getTrack(i); @@ -545,6 +546,7 @@ bool AddonsManager::install(const Addon &addon) assert(index>=0 && index < (int)m_addons_list.getData().size()); m_addons_list.getData()[index].setInstalled(true); + std::shared_ptr track_manager = TrackManager::get(); if(addon.getType()=="kart") { // We have to remove the mesh of the kart since otherwise it remains @@ -599,6 +601,8 @@ bool AddonsManager::uninstall(const Addon &addon) Log::info("addons", "Uninstalling '%s'.", core::stringc(addon.getName()).c_str()); + std::shared_ptr track_manager = TrackManager::get(); + // addon is a const reference, and to avoid removing the const, we // find the proper index again to modify the installed state int index = getAddonIndex(addon.getId()); diff --git a/src/audio/music_information.cpp b/src/audio/music_information.cpp index 511768b4be6..80fbdc6c5a9 100644 --- a/src/audio/music_information.cpp +++ b/src/audio/music_information.cpp @@ -135,10 +135,11 @@ MusicInformation::~MusicInformation() void MusicInformation::addMusicToTracks() { - for(int i=0; i<(int)m_all_tracks.size(); i++) + for (int i = 0; i < (int)m_all_tracks.size(); i++) { - Track* track=track_manager->getTrack(m_all_tracks[i]); - if(track) track->addMusic(this); + Track* track = TrackManager::get()->getTrack(m_all_tracks[i]); + if (track) + track->addMusic(this); } } // addMusicToTracks diff --git a/src/challenges/challenge_data.cpp b/src/challenges/challenge_data.cpp index ca8024ce58f..b9714f15b1a 100644 --- a/src/challenges/challenge_data.cpp +++ b/src/challenges/challenge_data.cpp @@ -190,7 +190,7 @@ ChallengeData::ChallengeData(const std::string& filename) { error("track"); } - if (track_manager->getTrack(m_track_id) == NULL) + if (TrackManager::get()->getTrack(m_track_id) == NULL) { error("track"); } @@ -349,7 +349,7 @@ void ChallengeData::check() const { try { - track_manager->getTrack(m_track_id); + TrackManager::get()->getTrack(m_track_id); } catch(std::exception&) { @@ -593,7 +593,7 @@ const irr::core::stringw { case UNLOCK_TRACK: { // {} avoids compiler warning - const Track* track = track_manager->getTrack(m_name); + const Track* track = TrackManager::get()->getTrack(m_name); // shouldn't happen but let's avoid crashes as much as possible... if (track == NULL) return irr::core::stringw( L"????" ); @@ -642,7 +642,7 @@ const irr::core::stringw void ChallengeData::addUnlockTrackReward(const std::string &track_name) { - if (track_manager->getTrack(track_name) == NULL) + if (TrackManager::get()->getTrack(track_name) == NULL) { throw std::runtime_error( StringUtils::insertValues("Challenge refers to unknown track <%s>", diff --git a/src/challenges/challenge_status.cpp b/src/challenges/challenge_status.cpp index 0824a1ddbfc..8062bd2e72d 100644 --- a/src/challenges/challenge_status.cpp +++ b/src/challenges/challenge_status.cpp @@ -26,7 +26,7 @@ #include "race/grand_prix_manager.hpp" #include "race/race_manager.hpp" #include "tracks/track.hpp" -#include "tracks/track_manager.hpp" +// #include "tracks/track_manager.hpp" #include "utils/translation.hpp" #include "utils/string_utils.hpp" diff --git a/src/challenges/unlock_manager.cpp b/src/challenges/unlock_manager.cpp index e1c743d4643..f65892a1922 100644 --- a/src/challenges/unlock_manager.cpp +++ b/src/challenges/unlock_manager.cpp @@ -68,7 +68,7 @@ UnlockManager::UnlockManager() // Read challenges from .../data/tracks/* // -------------------------------------- - const std::vector *all_track_dirs = track_manager->getAllTrackDirs(); + const std::vector *all_track_dirs = TrackManager::get()->getAllTrackDirs(); readAllChallengesInDirs(all_track_dirs); // Read challenges from .../data/karts/* diff --git a/src/config/player_profile.cpp b/src/config/player_profile.cpp index 8a4a8ee13a2..2451ed69f8d 100644 --- a/src/config/player_profile.cpp +++ b/src/config/player_profile.cpp @@ -27,7 +27,7 @@ #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" #include "online/online_player_profile.hpp" -#include "tracks/track_manager.hpp" +// #include "tracks/track_manager.hpp" #include "utils/string_utils.hpp" //------------------------------------------------------------------------------ diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 5b598c4f674..9ab24222671 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -1065,7 +1065,7 @@ void IrrDriver::applyResolutionSettings(bool recreate_device) s32(m_device->getNativeScaleY() * (float)UserConfigParams::m_prev_real_height)) ); m_video_driver->endScene(); } - track_manager->removeAllCachedData(); + TrackManager::get()->removeAllCachedData(); delete attachment_manager; attachment_manager = NULL; ProjectileManager::get()->removeTextures(); @@ -1180,9 +1180,9 @@ void IrrDriver::applyResolutionSettings(bool recreate_device) file_manager->popTextureSearchPath(); std::string banana = file_manager->getAsset(FileManager::GUI_ICON, "banana.png"); GUIEngine::addLoadingIcon(irr_driver->getTexture(banana) ); - // No need to reload cached track data (track_manager->cleanAllCachedData + // No need to reload cached track data (TrackManager::get()->cleanAllCachedData // above) - this happens dynamically when the tracks are loaded. - track_manager->updateScreenshotCache(); + TrackManager::get()->updateScreenshotCache(); GUIEngine::reshowCurrentScreen(); MessageQueue::updatePosition(); // Preload the explosion effects (explode.png) diff --git a/src/graphics/particle_kind_manager.cpp b/src/graphics/particle_kind_manager.cpp index b7bd0e2b902..cd0846baf68 100644 --- a/src/graphics/particle_kind_manager.cpp +++ b/src/graphics/particle_kind_manager.cpp @@ -86,7 +86,7 @@ ParticleKind* ParticleKindManager::getParticles(const std::string &name) { try { - Track* t = track_manager->getTrack(RaceManager::get()->getTrackName()); + Track* t = TrackManager::get()->getTrack(RaceManager::get()->getTrackName()); if (t) { ParticleKind* newkind = new ParticleKind(t->getTrackFile(name)); diff --git a/src/io/file_manager.cpp b/src/io/file_manager.cpp index ece404d2385..77ccf5c886f 100644 --- a/src/io/file_manager.cpp +++ b/src/io/file_manager.cpp @@ -510,7 +510,7 @@ void FileManager::reinitAfterDownloadAssets() // Add back addons search path KartPropertiesManager::addKartSearchDir( file_manager->getAddonsFile("karts/")); - track_manager->addTrackSearchDir( + TrackManager::get()->addTrackSearchDir( file_manager->getAddonsFile("tracks/")); } // reinitAfterDownloadAssets diff --git a/src/io/rich_presence.cpp b/src/io/rich_presence.cpp index 0466558e0cf..694e3bac4c6 100644 --- a/src/io/rich_presence.cpp +++ b/src/io/rich_presence.cpp @@ -478,7 +478,7 @@ void RichPresence::update(bool force) Track* track = nullptr; if (world) { - track = track_manager->getTrack(trackId); + track = TrackManager::get()->getTrack(trackId); if (track) trackName = StringUtils::wideToUtf8(track->getName()); } diff --git a/src/items/bowling.cpp b/src/items/bowling.cpp index 9d7a1a926c8..6c44d003bbe 100644 --- a/src/items/bowling.cpp +++ b/src/items/bowling.cpp @@ -159,7 +159,7 @@ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) { auto sl = LobbyProtocol::get(); if (sl) - sl->getHitProcessor()->setTeamMateHitOwner(getOwnerId(),m_ticks_since_thrown); + sl->getHitProcessor()->setTeammateHitOwner(getOwnerId(),m_ticks_since_thrown); bool was_real_hit = Flyable::hit(kart, obj); if (was_real_hit) @@ -169,8 +169,8 @@ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) kart->decreaseShieldTime(); if (sl) { - sl->getHitProcessor()->registerTeamMateHit(kart->getWorldKartId()); - sl->getHitProcessor()->handleTeamMateHits(); + sl->getHitProcessor()->registerTeammateHit(kart->getWorldKartId()); + sl->getHitProcessor()->handleTeammateHits(); } return true; } @@ -181,7 +181,7 @@ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) } } if (sl) - sl->getHitProcessor()->handleTeamMateHits(); + sl->getHitProcessor()->handleTeammateHits(); return was_real_hit; } // hit diff --git a/src/items/cake.cpp b/src/items/cake.cpp index 62fd2c425ce..dd3f2de6b2f 100644 --- a/src/items/cake.cpp +++ b/src/items/cake.cpp @@ -66,7 +66,7 @@ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj) { auto sl = LobbyProtocol::get(); if (sl) - sl->getHitProcessor()->setTeamMateHitOwner(getOwnerId()); + sl->getHitProcessor()->setTeammateHitOwner(getOwnerId()); bool was_real_hit = Flyable::hit(kart, obj); if (was_real_hit) @@ -76,8 +76,8 @@ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj) kart->decreaseShieldTime(); if (sl) { - sl->getHitProcessor()->registerTeamMateHit(kart->getWorldKartId()); - sl->getHitProcessor()->handleTeamMateHits(); + sl->getHitProcessor()->registerTeammateHit(kart->getWorldKartId()); + sl->getHitProcessor()->handleTeammateHits(); } return false; //Not sure if a shield hit is a real hit. } @@ -85,7 +85,7 @@ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj) } if (sl) - sl->getHitProcessor()->handleTeamMateHits(); + sl->getHitProcessor()->handleTeammateHits(); return was_real_hit; } // hit diff --git a/src/karts/explosion_animation.cpp b/src/karts/explosion_animation.cpp index 513d38d8851..799cf8e8e46 100644 --- a/src/karts/explosion_animation.cpp +++ b/src/karts/explosion_animation.cpp @@ -63,7 +63,7 @@ ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart, { kart->decreaseShieldTime(); if (sl) - sl->getHitProcessor()->registerTeamMateHit(kart->getWorldKartId()); + sl->getHitProcessor()->registerTeammateHit(kart->getWorldKartId()); return NULL; } @@ -76,7 +76,7 @@ ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart, } if (sl) - sl->getHitProcessor()->registerTeamMateExplode(kart->getWorldKartId()); + sl->getHitProcessor()->registerTeammateExplode(kart->getWorldKartId()); return new ExplosionAnimation(kart, direct_hit); } // create diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 1efa7fe2e58..aab994acd9e 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -80,7 +80,7 @@ #include "tracks/drive_graph.hpp" #include "tracks/drive_node.hpp" #include "tracks/track.hpp" -#include "tracks/track_manager.hpp" +// #include "tracks/track_manager.hpp" #include "tracks/track_sector.hpp" #include "utils/constants.hpp" #include "utils/helpers.hpp" diff --git a/src/main.cpp b/src/main.cpp index d54ec585dd9..db1d31a03f9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1622,7 +1622,7 @@ int handleCmdLine(bool has_server_config, bool has_parent_process) Log::verbose("main", "You chose to start in track '%s'.", s.c_str()); - Track* t = track_manager->getTrack(s); + Track* t = TrackManager::get()->getTrack(s); if (!t) { Log::warn("main", "Can't find track named '%s'.", s.c_str()); @@ -1722,9 +1722,10 @@ int handleCmdLine(bool has_server_config, bool has_parent_process) else { Log::verbose("main", "You chose to have %d laps.", laps); - if (NetworkConfig::get()->isServer()) - ServerLobby::m_default_fixed_laps = laps; - else + + // Note that --laps doesn't work with ServerLobby anymore, as it was removed + // during refactoring. Will probably be returned later. + if (!NetworkConfig::get()->isServer()) RaceManager::get()->setNumLaps(laps); } } // --laps @@ -1980,7 +1981,6 @@ void initRest() ReplayPlay::create(); ReplayRecorder::create(); material_manager = new MaterialManager (); - track_manager = new TrackManager (); kart_properties_manager = new KartPropertiesManager(); ProjectileManager::create(); powerup_manager = new PowerupManager (); @@ -1997,7 +1997,7 @@ void initRest() } if (!UserConfigParams::m_disable_addon_tracks) { - track_manager->addTrackSearchDir( + TrackManager::get()->addTrackSearchDir( file_manager->getAddonsFile("tracks/")); } @@ -2008,7 +2008,7 @@ void initRest() XMLNode characteristicsNode(file_manager->getAsset(char_file)); kart_properties_manager->loadCharacteristics(&characteristicsNode); - track_manager->loadTrackList(); + TrackManager::get()->loadTrackList(); music_manager->addMusicToTracks(); GUIEngine::addLoadingIcon(irr_driver->getTexture(FileManager::GUI_ICON, @@ -2030,7 +2030,7 @@ void initRest() RaceManager::get()->setDifficulty( (RaceManager::Difficulty)(int)UserConfigParams::m_difficulty); - if (!track_manager->getTrack(UserConfigParams::m_last_track)) + if (!TrackManager::get()->getTrack(UserConfigParams::m_last_track)) UserConfigParams::m_last_track.revertToDefaults(); RaceManager::get()->setTrack(UserConfigParams::m_last_track); @@ -2760,7 +2760,6 @@ static void cleanSuperTuxKart() if(powerup_manager) delete powerup_manager; ProjectileManager::destroy(); if(kart_properties_manager) delete kart_properties_manager; - if(track_manager) delete track_manager; if(material_manager) delete material_manager; if(history) delete history; ReplayPlay::destroy(); diff --git a/src/modes/capture_the_flag.cpp b/src/modes/capture_the_flag.cpp index 256c5ce65fb..f12d1f32d8b 100644 --- a/src/modes/capture_the_flag.cpp +++ b/src/modes/capture_the_flag.cpp @@ -413,7 +413,7 @@ void CaptureTheFlag::ctfScored(int kart_id, bool red_team_scored, { scored_msg = _("%s captured the red flag!", name); } - GameInfo* game_info = getGameInfo(); + std::shared_ptr game_info = getGameInfo(); if (game_info) { game_info->m_player_info.emplace_back(false/* reserved */, diff --git a/src/modes/demo_world.cpp b/src/modes/demo_world.cpp index d032eb9a205..d4a0c0f0d03 100644 --- a/src/modes/demo_world.cpp +++ b/src/modes/demo_world.cpp @@ -144,6 +144,8 @@ bool DemoWorld::updateIdleTimeAndStartDemo(float dt) if(m_current_idle_time <= m_max_idle_time) return false; + std::shared_ptr track_manager = TrackManager::get(); + if(m_demo_tracks.size()==0) m_demo_tracks = track_manager->getAllTrackIdentifiers(); Track *track = track_manager->getTrack(m_demo_tracks[0]); diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp index f34ce73a214..0c088dff8a8 100644 --- a/src/modes/soccer_world.cpp +++ b/src/modes/soccer_world.cpp @@ -585,7 +585,7 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) m_karts[sd.m_id]->getKartModel() ->setAnimation(KartModel::AF_LOSE_START, true/* play_non_loop*/); } - GameInfo* game_info = getGameInfo(); + std::shared_ptr game_info = getGameInfo(); if (game_info) { int sz = game_info->m_player_info.size(); diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 7635900c1e5..510f19c4615 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -176,7 +176,7 @@ void World::init() RewindManager::create(); main_loop->renderGUI(1100); // Grab the track file - Track *track = track_manager->getTrack(RaceManager::get()->getTrackName()); + Track *track = TrackManager::get()->getTrack(RaceManager::get()->getTrackName()); if (m_process_type == PT_MAIN) { Scripting::ScriptEngine::getInstance(); @@ -1727,7 +1727,7 @@ void World::updateAchievementDataEndRace() if (RaceManager::get()->modeHasLaps()) { - Track* track = track_manager->getTrack(RaceManager::get()->getTrackName()); + Track* track = TrackManager::get()->getTrack(RaceManager::get()->getTrackName()); int default_lap_num = track->getDefaultNumberOfLaps(); if (RaceManager::get()->getNumLaps() < default_lap_num) { diff --git a/src/modes/world.hpp b/src/modes/world.hpp index d8bc751e982..af9a2359206 100644 --- a/src/modes/world.hpp +++ b/src/modes/world.hpp @@ -133,7 +133,7 @@ class World : public WorldStatus bool m_unfair_team; - GameInfo* m_game_info; + std::shared_ptr m_game_info; /** Whether highscores should be used for this kind of race. * True by default, change to false in a child class to disable. @@ -211,7 +211,7 @@ class World : public WorldStatus void updateAchievementDataEndRace(); void updateAchievementModeCounters(bool start); // ------------------------------------------------------------------------ - GameInfo* getGameInfo() { return m_game_info; } + std::shared_ptr getGameInfo() { return m_game_info; } public: World(); @@ -439,7 +439,7 @@ class World : public WorldStatus unsigned getStartPosition(int index) const { return m_kart_position_map.at(index); } // ------------------------------------------------------------------------ - void setGameInfo(GameInfo* ptr) { m_game_info = ptr; } + void setGameInfo(std::shared_ptr ptr) { m_game_info = ptr; } }; // World #endif diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp index 930e0d0ea25..ddae89bb156 100644 --- a/src/network/protocols/client_lobby.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -590,7 +590,7 @@ void ClientLobby::receivePlayerVote(Event* event) "Vote from server: host %d, track %s, laps %d, reverse %d.", host_id, vote.m_track_name.c_str(), vote.m_num_laps, vote.m_reverse); - Track* track = track_manager->getTrack(vote.m_track_name); + Track* track = TrackManager::get()->getTrack(vote.m_track_name); if (!track) { Log::fatal("ClientLobby", "Missing track %s", @@ -1807,6 +1807,8 @@ void ClientLobby::handleClientCommand(const std::string& cmd) total_addons.insert(kp->getIdent()); } } + + std::shared_ptr track_manager = TrackManager::get(); if(type.empty() || // not specify addon type (!type.empty() && (type.compare("track") == 0 || type.compare("arena") == 0))) { @@ -1892,7 +1894,7 @@ void ClientLobby::getKartsTracksNetworkString(BareNetworkString* ns) for (const std::string& k : oks) all_k.push_back(k); - auto all_t = track_manager->getAllTrackIdentifiers(); + auto all_t = TrackManager::get()->getAllTrackIdentifiers(); if (all_t.size() >= 65536) all_t.resize(65535); ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size()); @@ -2017,7 +2019,7 @@ void ClientLobby::doInstallAddonsPack() addons_manager->saveInstalled(); if (track_installed) { - track_manager->loadTrackList(); + TrackManager::get()->loadTrackList(); // Update the replay file list to use latest track pointer ReplayPlay::get()->loadAllReplayFile(); delete grand_prix_manager; diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index c1c47bc550e..e18e4f452c3 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -37,6 +37,7 @@ #include "utils/hourglass_reason.hpp" #include "utils/kart_elimination.hpp" #include "utils/lobby_asset_manager.hpp" +#include "utils/lobby_settings.hpp" #include "utils/lobby_queues.hpp" #include "utils/log.hpp" #include "utils/map_vote_handler.hpp" @@ -540,9 +541,8 @@ void CommandManager::initCommands() applyFunctionIfPossible("liststkaddon", &CM::special); applyFunctionIfPossible("listlocaladdon", &CM::special); - addTextResponse("description", StringUtils::wideToUtf8(m_lobby->getGameSetup()->readOrLoadFromFile - ((std::string)ServerConfig::m_motd))); - addTextResponse("moreinfo", StringUtils::wideToUtf8(m_lobby->m_help_message)); + addTextResponse("description", m_lobby_settings->getMotd()); + addTextResponse("moreinfo", m_lobby_settings->getHelpMessage()); std::string version = "1.3 k 210fff beta"; #ifdef GIT_VERSION version = std::string(GIT_VERSION); @@ -568,7 +568,7 @@ void CommandManager::initCommands() void CommandManager::initAssets() { - auto all_t = track_manager->getAllTrackIdentifiers(); + auto all_t = TrackManager::get()->getAllTrackIdentifiers(); std::map what_exists; for (std::string& s: all_t) { @@ -607,12 +607,16 @@ CommandManager::CommandManager(ServerLobby* lobby): { if (!lobby) return; - initCommands(); - initAssets(); + m_hit_processor = lobby->getHitProcessor(); m_asset_manager = lobby->getLobbyAssetManager(); m_tournament = lobby->getTournament(); m_lobby_queues = lobby->getLobbyQueues(); + m_lobby_settings = lobby->getLobbySettings(); + m_kart_elimination = lobby->getKartElimination(); + + initCommands(); + initAssets(); m_aux_mode_aliases = { {"m0"}, @@ -1102,7 +1106,7 @@ void CommandManager::process_replay(Context& context) } if (ServerConfig::m_record_replays) { - bool current_state = m_lobby->hasConsentOnReplays(); + bool current_state = m_lobby_settings->hasConsentOnReplays(); if (argv.size() >= 2 && argv[1] == "0") current_state = false; else if (argv.size() >= 2 && argv[1] == "1") @@ -1110,7 +1114,7 @@ void CommandManager::process_replay(Context& context) else current_state ^= 1; - m_lobby->setConsentOnReplays(current_state); + m_lobby_settings->setConsentOnReplays(current_state); std::string msg = "Recording ghost replays is now "; msg += (current_state ? "on" : "off"); m_lobby->sendStringToAllPeers(msg); @@ -1219,8 +1223,8 @@ void CommandManager::process_config_assign(Context& context) // if (mode != 6) { // goal_target = false; // } - if (!m_lobby->isDifficultyAvailable(difficulty) - || !m_lobby->isModeAvailable(mode)) + if (!m_lobby_settings->isDifficultyAvailable(difficulty) + || !m_lobby_settings->isModeAvailable(mode)) { std::string response = "Mode or difficulty are not permitted on this server"; m_lobby->sendStringToPeer(response, peer); @@ -2055,7 +2059,7 @@ void CommandManager::process_mute(Context& context) return; } - m_lobby->m_peers_muted_players[peer].insert(player_name); + m_lobby_settings->addMutedPlayerFor(peer, player_name); result_msg = "Muted player " + argv[1]; m_lobby->sendStringToPeer(result_msg, peer); } // process_mute @@ -2071,7 +2075,6 @@ void CommandManager::process_unmute(Context& context) error(context, true); return; } - std::string result_msg; core::stringw player_name; if (argv.size() != 2 || argv[1].empty()) @@ -2081,23 +2084,13 @@ void CommandManager::process_unmute(Context& context) } player_name = StringUtils::utf8ToWide(argv[1]); - for (auto it = m_lobby->m_peers_muted_players[peer].begin(); - it != m_lobby->m_peers_muted_players[peer].end();) - { - if (*it == player_name) - { - it = m_lobby->m_peers_muted_players[peer].erase(it); - result_msg = "Unmuted player " + argv[1]; - m_lobby->sendStringToPeer(result_msg, peer); - return; - } - else - { - it++; - } - } - error(context); + if (!m_lobby_settings->removeMutedPlayerFor(peer, player_name)) + error(context); + + std::string result_msg = "Unmuted player " + StringUtils::wideToUtf8(player_name); + m_lobby->sendStringToPeer(result_msg, peer); + } // process_unmute // ======================================================================== @@ -2109,23 +2102,9 @@ void CommandManager::process_listmute(Context& context) error(context, true); return; } - std::string response; - int num_players = 0; - for (auto& name : m_lobby->m_peers_muted_players[peer]) - { - response += StringUtils::wideToUtf8(name); - response += " "; - ++num_players; - } - if (num_players == 0) - response = "No player has been muted by you"; - else - { - response += (num_players == 1 ? "is" : "are"); - response += " muted (total: " + std::to_string(num_players) + ")"; - } - m_lobby->sendStringToPeer(response, peer); + std::string muted_players = m_lobby_settings->getMutedPlayersAsString(peer); + m_lobby->sendStringToPeer(muted_players, peer); } // process_listmute // ======================================================================== @@ -2143,13 +2122,13 @@ void CommandManager::process_gnu(Context& context) } // "nognu" and "gnu off" are equivalent bool turn_on = (argv.size() < 2 || argv[1] != "off"); - if (turn_on && m_lobby->m_kart_elimination->isEnabled()) + if (turn_on && m_kart_elimination->isEnabled()) { std::string msg = "Gnu Elimination mode was already enabled!"; m_lobby->sendStringToPeer(msg, peer); return; } - if (!turn_on && !m_lobby->m_kart_elimination->isEnabled()) + if (!turn_on && !m_kart_elimination->isEnabled()) { std::string msg = "Gnu Elimination mode was already off!"; m_lobby->sendStringToPeer(msg, peer); @@ -2199,14 +2178,14 @@ void CommandManager::process_gnu(Context& context) m_votables["gnu"].reset("gnu kart"); if (kart == "off") { - m_lobby->m_kart_elimination->disable(); + m_kart_elimination->disable(); std::string msg = "Gnu Elimination is now off"; m_lobby->sendStringToAllPeers(msg); } else { - m_lobby->m_kart_elimination->enable(kart); - std::string msg = m_lobby->m_kart_elimination->getStartingMessage(); + m_kart_elimination->enable(kart); + std::string msg = m_kart_elimination->getStartingMessage(); m_lobby->sendStringToAllPeers(msg); } } // process_gnu @@ -2278,7 +2257,7 @@ void CommandManager::process_standings(Context& context) msg = m_lobby->getGrandPrixStandings(isGPPlayers, isGPTeams); } else if (isGnu) - msg = m_lobby->m_kart_elimination->getStandings(); + msg = m_kart_elimination->getStandings(); m_lobby->sendStringToPeer(msg, peer); } // process_standings // ======================================================================== @@ -2291,7 +2270,7 @@ void CommandManager::process_teamchat(Context& context) error(context, true); return; } - m_lobby->m_team_speakers.insert(peer); + m_lobby_settings->addTeamSpeaker(peer); std::string msg = "Your messages are now addressed to team only"; m_lobby->sendStringToPeer(msg, peer); } // process_teamchat @@ -2311,15 +2290,15 @@ void CommandManager::process_to(Context& context) error(context); return; } - m_lobby->m_message_receivers[peer].clear(); + std::vector receivers; for (unsigned i = 1; i < argv.size(); ++i) { if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, i, m_stf_present_users, 3, false, true)) return; - m_lobby->m_message_receivers[peer].insert( - StringUtils::utf8ToWide(argv[i])); + receivers.push_back(argv[i]); } + m_lobby_settings->setMessageReceiversFor(peer, receivers); std::string msg = "Successfully changed chat settings"; m_lobby->sendStringToPeer(msg, peer); } // process_to @@ -2333,8 +2312,7 @@ void CommandManager::process_public(Context& context) error(context, true); return; } - m_lobby->m_message_receivers[peer].clear(); - m_lobby->m_team_speakers.erase(peer); + m_lobby_settings->makeChatPublicFor(peer); std::string s = "Your messages are now public"; m_lobby->sendStringToPeer(s, peer); } // process_public @@ -2426,20 +2404,7 @@ void CommandManager::process_length(Context& context) error(context, true); return; } - std::string msg; - if (m_lobby->m_default_lap_multiplier < 0 && m_lobby->m_fixed_lap < 0) - msg = "Game length is currently chosen by players"; - else if (m_lobby->m_default_lap_multiplier > 0) - msg = StringUtils::insertValues( - "Game length is %f x default", - m_lobby->m_default_lap_multiplier); - else if (m_lobby->m_fixed_lap > 0) - msg = StringUtils::insertValues( - "Game length is %d", m_lobby->m_fixed_lap); - else - msg = StringUtils::insertValues( - "An error: game length is both %f x default and %d", - m_lobby->m_default_lap_multiplier, m_lobby->m_fixed_lap); + std::string msg = m_lobby_settings->getLapRestrictionsAsString(); m_lobby->sendStringToPeer(msg, peer); } // process_length // ======================================================================== @@ -2453,11 +2418,9 @@ void CommandManager::process_length_multi(Context& context) error(context); return; } - m_lobby->m_default_lap_multiplier = std::max(0.0, temp_double); - m_lobby->m_fixed_lap = -1; - std::string msg = StringUtils::insertValues( - "Game length is now %f x default", - m_lobby->m_default_lap_multiplier); + double value = std::max(0.0, temp_double); + m_lobby_settings->setMultiplier(value); + std::string msg = StringUtils::insertValues("Game length is now %f x default", value); m_lobby->sendStringToAllPeers(msg); } // process_length_multi // ======================================================================== @@ -2471,17 +2434,15 @@ void CommandManager::process_length_fixed(Context& context) error(context); return; } - m_lobby->m_fixed_lap = std::max(0, temp_int); - m_lobby->m_default_lap_multiplier = -1.0; - std::string msg = StringUtils::insertValues( - "Game length is now %d", m_lobby->m_fixed_lap); + int value = std::max(0, temp_int); + m_lobby_settings->setFixedLapCount(value); + std::string msg = StringUtils::insertValues("Game length is now %d", value); m_lobby->sendStringToAllPeers(msg); } // process_length_fixed // ======================================================================== void CommandManager::process_length_clear(Context& context) { - m_lobby->m_default_lap_multiplier = -1.0; - m_lobby->m_fixed_lap = -1; + m_lobby_settings->resetLapRestrictions(); std::string msg = "Game length will be chosen by players"; m_lobby->sendStringToAllPeers(msg); } // process_length_clear @@ -2489,15 +2450,7 @@ void CommandManager::process_length_clear(Context& context) void CommandManager::process_direction(Context& context) { - std::string msg = "Direction is "; - if (m_lobby->m_fixed_direction == -1) - { - msg += "chosen ingame"; - } else - { - msg += "set to "; - msg += (m_lobby->m_fixed_direction == 0 ? "forward" : "reverse"); - } + std::string msg = m_lobby_settings->getDirectionAsString(); m_lobby->sendStringToAllPeers(msg); } // process_direction // ======================================================================== @@ -2512,26 +2465,12 @@ void CommandManager::process_direction_assign(Context& context) return; } int temp_int = -1; - if (!StringUtils::parseString(argv[1], &temp_int)) + if (!StringUtils::parseString(argv[1], &temp_int) || !m_lobby_settings->setDirection(temp_int)) { error(context); return; } - if (temp_int < -1 || temp_int > 1) - { - error(context); - return; - } - m_lobby->m_fixed_direction = temp_int; - msg = "Direction is now "; - if (temp_int == -1) - { - msg += "chosen ingame"; - } else - { - msg += "set to "; - msg += (temp_int == 0 ? "forward" : "reverse"); - } + msg = m_lobby_settings->getDirectionAsString(true); m_lobby->sendStringToAllPeers(msg); } // process_direction_assign // ======================================================================== @@ -2779,40 +2718,31 @@ void CommandManager::process_queue_shuffle(Context& context) void CommandManager::process_allowstart(Context& context) { - std::string msg; auto peer = context.m_peer.lock(); if (!peer) { error(context, true); return; } - if (m_lobby->m_allowed_to_start) - msg = "Starting the game is allowed"; - else - msg = "Starting the game is forbidden"; + + std::string msg = m_lobby_settings->getAllowedToStartAsString(); m_lobby->sendStringToPeer(msg, peer); } // process_allowstart // ======================================================================== void CommandManager::process_allowstart_assign(Context& context) { - std::string msg; auto& argv = context.m_argv; + // kimden thinks the parts 2-3 should be moved into validation part + // of the settings. Please do it later. In this function it's not done + // because of an extra cast. if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) { error(context); return; } - if (argv[1] == "0") - { - m_lobby->m_allowed_to_start = false; - msg = "Now starting a game is forbidden"; - } - else - { - m_lobby->m_allowed_to_start = true; - msg = "Now starting a game is allowed"; - } + m_lobby_settings->setAllowedToStart(argv[1] != "0"); + std::string msg = m_lobby_settings->getAllowedToStartAsString(true); m_lobby->sendStringToAllPeers(msg); } // process_allowstart_assign // ======================================================================== @@ -2825,32 +2755,22 @@ void CommandManager::process_shuffle(Context& context) error(context, true); return; } - std::string msg; - if (m_lobby->m_shuffle_gp) - msg = "The GP grid is sorted by score"; - else - msg = "The GP grid is shuffled"; + std::string msg = m_lobby_settings->getWhetherShuffledGPGridAsString(); m_lobby->sendStringToPeer(msg, peer); } // process_shuffle // ======================================================================== void CommandManager::process_shuffle_assign(Context& context) { - std::string msg; auto& argv = context.m_argv; + // Move validation to lobby settings. if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) { error(context); return; } - if (argv[1] == "0") - { - m_lobby->m_shuffle_gp = false; - msg = "Now the GP grid is sorted by score"; - } else { - m_lobby->m_shuffle_gp = true; - msg = "Now the GP grid is shuffled"; - } + m_lobby_settings->setGPGridShuffled(argv[1] != "0"); + std::string msg = m_lobby_settings->getWhetherShuffledGPGridAsString(true); m_lobby->sendStringToAllPeers(msg); } // process_shuffle_assign // ======================================================================== @@ -2903,7 +2823,7 @@ void CommandManager::process_team(Context& context) if (!argv[1].empty()) { std::string temp(1, argv[1][0]); - if (m_lobby->getAvailableTeams().find(temp) != std::string::npos) + if (m_lobby_settings->getAvailableTeams().find(temp) != std::string::npos) allowed_color = true; } int team = TeamUtils::getIndexByCode(argv[1]); @@ -3071,8 +2991,7 @@ void CommandManager::process_cat(Context& context) 2, m_stf_present_users, 3, false, true)) return; std::string player = argv[2]; - m_lobby->m_player_categories[category].insert(player); - m_lobby->m_categories_for_player[player].insert(category); + m_lobby_settings->addPlayerToCategory(player, category); m_lobby->updatePlayerList(); return; } @@ -3089,14 +3008,14 @@ void CommandManager::process_cat(Context& context) 2, m_stf_present_users, 3, false, true)) return; player = argv[2]; - m_lobby->m_player_categories[category].erase(player); - m_lobby->m_categories_for_player[player].erase(category); + m_lobby_settings->erasePlayerFromCategory(player, category); m_lobby->updatePlayerList(); return; } if (argv[0] == "catshow") { int displayed; + // Validation should happen in LS if (argv.size() != 3 || !StringUtils::parseString(argv[2], &displayed) || displayed < 0 || displayed > 1) { @@ -3104,11 +3023,7 @@ void CommandManager::process_cat(Context& context) return; } std::string category = argv[1]; - if (displayed) { - m_lobby->m_hidden_categories.erase(category); - } else { - m_lobby->m_hidden_categories.insert(category); - } + m_lobby_settings->makeCategoryVisible(category, displayed); m_lobby->updatePlayerList(); return; } @@ -3124,7 +3039,7 @@ void CommandManager::process_troll(Context& context) error(context, true); return; } - if (m_lobby->m_troll_active) + if (m_hit_processor->isAntiTrollActive()) msg = "Trolls will be kicked"; else msg = "Trolls can stay"; @@ -3143,10 +3058,10 @@ void CommandManager::process_troll_assign(Context& context) } if (argv[1] == "0") { - m_lobby->m_troll_active = false; + m_hit_processor->setAntiTroll(false); msg = "Trolls can stay"; } else { - m_lobby->m_troll_active = true; + m_hit_processor->setAntiTroll(true); msg = "Trolls will be kicked"; } m_lobby->sendStringToAllPeers(msg); @@ -3239,10 +3154,7 @@ void CommandManager::process_scoring(Context& context) error(context, true); return; } - std::string msg = "Current scoring is \"" + m_lobby->m_scoring_type; - for (int param: m_lobby->m_scoring_int_params) - msg += StringUtils::insertValues(" %d", param); - msg += "\""; + std::string msg = m_lobby_settings->getScoringAsString(); m_lobby->sendStringToPeer(msg, peer); } // process_scoring // ======================================================================== @@ -3259,7 +3171,7 @@ void CommandManager::process_scoring_assign(Context& context) } std::string cmd2; CommandManager::restoreCmdByArgv(cmd2, argv, ' ', '"', '"', '\\', 1); - if (m_lobby->loadCustomScoring(cmd2)) + if (m_lobby_settings->loadCustomScoring(cmd2)) { msg = "Scoring set to \"" + cmd2 + "\""; m_lobby->sendStringToAllPeers(msg); @@ -3392,7 +3304,7 @@ void CommandManager::process_game(Context& context) } } m_tournament->setGameCmdInput(new_game_number, new_duration, new_addition); - m_lobby->m_fixed_lap = new_duration; + m_lobby_settings->setFixedLapCount(new_duration); if (m_tournament->hasColorsSwapped(new_game_number) ^ m_tournament->hasColorsSwapped(old_game_number)) m_lobby->changeColors(); @@ -3407,7 +3319,7 @@ void CommandManager::process_game(Context& context) if (!m_tournament->hasGoalsLimit() && new_addition > 0) { msg += StringUtils::insertValues(" %d seconds", new_addition); - ++m_lobby->m_fixed_lap; + m_lobby_settings->setFixedLapCount(m_lobby_settings->getFixedLapCount() + 1); } m_lobby->sendStringToAllPeers(msg); Log::info("CommandManager", "SoccerMatchLog: Game number changed from %d to %d", @@ -3452,25 +3364,13 @@ void CommandManager::process_role(Context& context) char role_char = role[0]; if (role_char >= 'A' && role_char <= 'Z') role_char += 'a' - 'A'; - std::vector changed_usernames; + std::set changed_usernames; if (!username.empty()) { if (username[0] == '#') - { - std::string category = username.substr(1); - auto it = m_lobby->m_player_categories.find(category); - if (it != m_lobby->m_player_categories.end()) - { - for (const std::string& s: it->second) - { - changed_usernames.push_back(s); - } - } - } + changed_usernames = m_lobby_settings->getPlayersInCategory(username.substr(1)); else - { - changed_usernames.push_back(username); - } + changed_usernames.insert(username); } for (const std::string& u: changed_usernames) { @@ -3480,7 +3380,7 @@ void CommandManager::process_role(Context& context) StringUtils::utf8ToWide(u)); std::vector missing_assets; if (player_peer) - missing_assets = m_lobby->getMissingAssets(player_peer); + missing_assets = m_lobby_settings->getMissingAssets(player_peer); bool fail = false; switch (role_char) { @@ -3810,9 +3710,7 @@ void CommandManager::process_preserve(Context& context) error(context, true); return; } - std::string msg = "Preserved settings:"; - for (const std::string& str: m_lobby->m_preserve) - msg += " " + str; + std::string msg = m_lobby_settings->getPreservedSettingsAsString(); m_lobby->sendStringToPeer(msg, peer); } // process_preserve // ======================================================================== @@ -3836,13 +3734,13 @@ void CommandManager::process_preserve_assign(Context& context) { msg = StringUtils::insertValues( "'%s' isn't preserved on server reset anymore", argv[1].c_str()); - m_lobby->m_preserve.erase(argv[1]); + m_lobby_settings->eraseFromPreserved(argv[1]); } else { msg = StringUtils::insertValues( "'%s' is now preserved on server reset", argv[1].c_str()); - m_lobby->m_preserve.insert(argv[1]); + m_lobby_settings->insertIntoPreserved(argv[1]); } m_lobby->sendStringToAllPeers(msg); } // process_preserve_assign @@ -4044,7 +3942,7 @@ void CommandManager::process_available_teams(Context& context) return; } std::string msg = StringUtils::insertValues("Currently available teams: \"%s\"", - m_lobby->getInternalAvailableTeams().c_str()); + m_lobby_settings->getInternalAvailableTeams().c_str()); m_lobby->sendStringToPeer(msg, peer); } // process_available_teams // ======================================================================== @@ -4088,7 +3986,7 @@ void CommandManager::process_available_teams_assign(Context& context) ignored.push_back(c); for (char c: value_set) value.push_back(c); - m_lobby->setInternalAvailableTeams(value); + m_lobby_settings->setInternalAvailableTeams(value); msg = StringUtils::insertValues("Set available teams to \"%s\"", value); if (!ignored.empty()) msg += StringUtils::insertValues( @@ -4143,7 +4041,7 @@ bool CommandManager::assignRandomTeams(int intended_number, return false; } int max_number_of_teams = TeamUtils::getNumberOfTeams(); - std::string available_colors_string = m_lobby->getAvailableTeams(); + std::string available_colors_string = m_lobby_settings->getAvailableTeams(); if (available_colors_string.empty()) return false; if (max_number_of_teams > (int)available_colors_string.length()) diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 2777bada9a2..dcc519fdd52 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -49,9 +49,12 @@ class ServerLobby; class Event; class STKPeer; +class HitProcessor; class LobbyAssetManager; class Tournament; class LobbyQueues; +class LobbySettings; +class KartElimination; class CommandManager { @@ -200,9 +203,12 @@ class CommandManager ServerLobby* m_lobby; + std::shared_ptr m_hit_processor; std::shared_ptr m_asset_manager; std::shared_ptr m_tournament; std::shared_ptr m_lobby_queues; + std::shared_ptr m_lobby_settings; + std::shared_ptr m_kart_elimination; std::vector> m_all_commands; diff --git a/src/network/protocols/lobby_protocol.cpp b/src/network/protocols/lobby_protocol.cpp index 7e30c040069..90e4d6d4784 100644 --- a/src/network/protocols/lobby_protocol.cpp +++ b/src/network/protocols/lobby_protocol.cpp @@ -262,7 +262,7 @@ Track* LobbyProtocol::getPlayingTrack() const std::unique_lock ul(m_current_track_mutex); std::string track_ident = m_current_track; ul.unlock(); - return track_manager->getTrack(track_ident); + return TrackManager::get()->getTrack(track_ident); } // getPlayingTrack //----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index d3be879ae35..518fa77ac26 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -52,6 +52,7 @@ #include "utils/game_info.hpp" #include "utils/hit_processor.hpp" #include "utils/lobby_asset_manager.hpp" +#include "utils/lobby_settings.hpp" #include "utils/lobby_queues.hpp" #include "utils/map_vote_handler.hpp" #include "utils/tournament.hpp" @@ -62,9 +63,81 @@ #include #include #include -#include +#include + +// ======================================================================== + +// Helper functions. +namespace +{ + void encodePlayers(BareNetworkString* bns, + std::vector >& players) + { + bns->addUInt8((uint8_t)players.size()); + for (unsigned i = 0; i < players.size(); i++) + { + std::shared_ptr& player = players[i]; + bns->encodeString(player->getName()) + .addUInt32(player->getHostId()) + .addFloat(player->getDefaultKartColor()) + .addUInt32(player->getOnlineId()) + .addUInt8(player->getHandicap()) + .addUInt8(player->getLocalPlayerId()) + .addUInt8(player->getTeam()) + .encodeString(player->getCountryCode()); + bns->encodeString(player->getKartName()); + } + } // encodePlayers + //--------------------------------------------------------------------- + /** Returns true if world is active for clients to live join, spectate or + * going back to lobby live + */ + bool worldIsActive() + { + return World::getWorld() && RaceEventManager::get()->isRunning() && + !RaceEventManager::get()->isRaceOver() && + World::getWorld()->getPhase() == WorldStatus::RACE_PHASE; + } // worldIsActive + + //----------------------------------------------------------------------------- + /** Get a list of current ingame players for live join or spectate. + */ + std::vector > getLivePlayers() + { + std::vector > players; + for (unsigned i = 0; i < RaceManager::get()->getNumPlayers(); i++) + { + const RemoteKartInfo& rki = RaceManager::get()->getKartInfo(i); + std::shared_ptr player = + rki.getNetworkPlayerProfile().lock(); + if (!player) + { + if (RaceManager::get()->modeHasLaps()) + { + player = std::make_shared( + nullptr, rki.getPlayerName(), + std::numeric_limits::max(), + rki.getDefaultKartColor(), + rki.getOnlineId(), rki.getHandicap(), + rki.getLocalPlayerId(), KART_TEAM_NONE, + rki.getCountryCode()); + player->setKartName(rki.getKartName()); + } + else + { + player = NetworkPlayerProfile::getReservedProfile( + RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_FREE_FOR_ALL ? + KART_TEAM_NONE : rki.getKartTeam()); + } + } + players.push_back(player); + } + return players; + } // getLivePlayers + //----------------------------------------------------------------------------- +} // anonymous namespace -int ServerLobby::m_default_fixed_laps = -1; // ======================================================================== // We use max priority for all server requests to avoid downloading of addons @@ -113,46 +186,26 @@ ServerLobby::ServerLobby() : LobbyProtocol() { m_client_server_host_id.store(0); m_lobby_players.store(0); - m_help_message = getGameSetup()->readOrLoadFromFile - ((std::string) ServerConfig::m_help); - m_command_manager = std::make_shared(nullptr); - m_shuffle_gp = ServerConfig::m_shuffle_gp; m_current_max_players_in_game.store(ServerConfig::m_max_players_in_game); - m_consent_on_replays = false; m_kart_elimination = std::make_shared(); - m_map_vote_handler = std::make_shared(); - m_lobby_queues = std::make_shared(); + m_asset_manager = std::make_shared(this); + if (ServerConfig::m_soccer_tournament) + m_tournament = std::make_shared(this, m_lobby_settings); - m_fixed_lap = ServerConfig::m_fixed_lap_count; - // Server config has better priority than --laps - // as it is more flexible and was introduced earlier - if (m_default_fixed_laps != -1) { - m_fixed_lap = m_default_fixed_laps; - } - m_fixed_direction = ServerConfig::m_fixed_direction; - - m_default_lap_multiplier = ServerConfig::m_auto_game_time_ratio; - - m_troll_active = ServerConfig::m_troll_active; - - m_hit_processor = std::make_shared(this); + m_lobby_settings = std::make_shared( + getGameSetup(), m_lobby_queues, m_kart_elimination, m_asset_manager, m_tournament + ); - m_asset_manager = std::make_shared(this); + m_map_vote_handler = std::make_shared(m_lobby_settings); + m_hit_processor = std::make_shared(this, m_lobby_settings); - m_available_teams = ServerConfig::m_init_available_teams; m_map_vote_handler->setAlgorithm(ServerConfig::m_map_vote_handling); - initAvailableModes(); - m_current_ai_count.store(0); - m_asset_manager->init(); - m_asset_manager->updateAddons(); - - initAvailableTracks(); m_rs_state.store(RS_NONE); m_last_success_poll_time.store(StkTime::getMonoTimeMs() + 30000); @@ -176,24 +229,16 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_server_id_online.store(0); m_difficulty.store(ServerConfig::m_server_difficulty); m_game_mode.store(ServerConfig::m_server_mode); - m_default_vote = new PeerVote(); #ifdef ENABLE_SQLITE3 m_db_connector = std::make_shared(); m_db_connector->initDatabase(); #endif - initCategories(); + m_game_info = {}; - if (ServerConfig::m_soccer_tournament) - m_tournament = std::make_shared(this); - - m_allowed_to_start = ServerConfig::m_allowed_to_start; - m_game_info = nullptr; - std::string scoring = ServerConfig::m_gp_scoring; - loadCustomScoring(scoring); - loadWhiteList(); - loadPreservedSettings(); + // Init CM later than all the above shared_ptrs + m_command_manager = std::make_shared(nullptr); } // ServerLobby //----------------------------------------------------------------------------- @@ -210,7 +255,6 @@ ServerLobby::~ServerLobby() delete m_items_complete_state; if (m_save_server_config) ServerConfig::writeServerConfigToDisk(); - delete m_default_vote; #ifdef ENABLE_SQLITE3 m_db_connector->destroyDatabase(); @@ -240,10 +284,7 @@ void ServerLobby::updateMapsForMode() void ServerLobby::setup() { LobbyProtocol::setup(); - m_battle_hit_capture_limit = 0; - m_battle_time_limit = 0.0f; m_item_seed = 0; - m_winner_peer_id = 0; m_client_starting_time = 0; m_ai_count = 0; auto players = STKHost::get()->getPlayersForNewGame(); @@ -278,9 +319,7 @@ void ServerLobby::setup() m_timeout.store(std::numeric_limits::max()); m_server_started_at = m_server_delay = 0; getCommandManager()->onResetServer(); - if (m_game_info) - delete m_game_info; - m_game_info = nullptr; + m_game_info = {}; Log::info("ServerLobby", "Resetting the server to its initial state."); } // setup @@ -373,10 +412,10 @@ void ServerLobby::handleChat(Event* event) chat->setSynchronous(true); const bool game_started = m_state.load() != WAITING_FOR_START_GAME; std::shared_ptr sender = event->getPeerSP(); - auto can_receive = m_message_receivers[sender]; + auto can_receive = m_lobby_settings->getMessageReceiversFor(sender); if (!can_receive.empty()) message = StringUtils::utf32ToWide({0x1f512, 0x20}) + message; - bool team_speak = m_team_speakers.find(sender) != m_team_speakers.end(); + bool team_speak = m_lobby_settings->isTeamSpeaker(sender); team_speak &= ( RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER || RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG @@ -462,15 +501,8 @@ void ServerLobby::handleChat(Event* event) return false; } } - for (auto& peer : m_peers_muted_players) - { - if (auto peer_sp = peer.first.lock()) - { - if (peer_sp == p && - peer.second.find(sender_name) != peer.second.end()) - return false; - } - } + if (m_lobby_settings->isMuting(p, sender_name)) + return false; if (team_speak) { bool someone_good = false; @@ -778,14 +810,7 @@ void ServerLobby::asynchronousUpdate() m_rs_state.store(RS_NONE); } - for (auto it = m_peers_muted_players.begin(); - it != m_peers_muted_players.end();) - { - if (it->first.expired()) - it = m_peers_muted_players.erase(it); - else - it++; - } + m_lobby_settings->clearAllExpiredWeakPtrs(); #ifdef ENABLE_SQLITE3 pollDatabase(); @@ -988,28 +1013,28 @@ void ServerLobby::asynchronousUpdate() } PeerVote winner_vote; - m_winner_peer_id = std::numeric_limits::max(); + m_lobby_settings->resetWinnerPeerId(); bool go_on_race = false; if (ServerConfig::m_track_voting) - go_on_race = handleAllVotes(&winner_vote, &m_winner_peer_id); + go_on_race = handleAllVotes(&winner_vote); else if (/*m_game_setup->isGrandPrixStarted() || */isVotingOver()) { - winner_vote = *m_default_vote; + winner_vote = m_lobby_settings->getDefaultVote(); go_on_race = true; } if (go_on_race) { - if (m_fixed_lap >= 0) + if (m_lobby_settings->hasFixedLapCount()) { - winner_vote.m_num_laps = m_fixed_lap; - Log::info("ServerLobby", "Enforcing %d lap race", (int)m_fixed_lap); + winner_vote.m_num_laps = m_lobby_settings->getFixedLapCount(); + Log::info("ServerLobby", "Enforcing %d lap race", m_lobby_settings->getFixedLapCount()); } - if (m_fixed_direction >= 0) + if (m_lobby_settings->hasFixedDirection()) { - winner_vote.m_reverse = (m_fixed_direction == 1); - Log::info("ServerLobby", "Enforcing direction %d", (int)m_fixed_direction); + winner_vote.m_reverse = (m_lobby_settings->getDirection() == 1); + Log::info("ServerLobby", "Enforcing direction %d", (int)m_lobby_settings->getDirection()); } - *m_default_vote = winner_vote; + m_lobby_settings->setDefaultVote(winner_vote); m_item_seed = (uint32_t)StkTime::getTimeSinceEpoch(); ItemManager::updateRandomSeed(m_item_seed); float extra_seconds = 0.0f; @@ -1062,7 +1087,7 @@ void ServerLobby::asynchronousUpdate() m_ai_profiles.end()); } } - m_game_setup->sortPlayersForGrandPrix(players, m_shuffle_gp); + m_game_setup->sortPlayersForGrandPrix(players, m_lobby_settings->isGPGridShuffled()); m_game_setup->sortPlayersForGame(players); for (unsigned i = 0; i < players.size(); i++) { @@ -1112,12 +1137,12 @@ void ServerLobby::asynchronousUpdate() NetworkString* load_world_message = getLoadWorldMessage(players, false/*live_join*/); - m_game_setup->setHitCaptureTime(m_battle_hit_capture_limit, - m_battle_time_limit); + m_game_setup->setHitCaptureTime(m_lobby_settings->getBattleHitCaptureLimit(), + m_lobby_settings->getBattleTimeLimit()); uint16_t flag_return_time = (uint16_t)stk_config->time2Ticks( ServerConfig::m_flag_return_timeout); RaceManager::get()->setFlagReturnTicks(flag_return_time); - if (ServerConfig::m_record_replays && m_consent_on_replays && + if (ServerConfig::m_record_replays && m_lobby_settings->hasConsentOnReplays() && (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL || RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE)) RaceManager::get()->setRecordRace(true); @@ -1153,7 +1178,7 @@ void ServerLobby::asynchronousUpdate() } } } - m_game_info = new GameInfo(); + m_game_info = std::make_shared(); for (int i = 0; i < (int)RaceManager::get()->getNumPlayers(); i++) { GameInfo::PlayerInfo info; @@ -1196,26 +1221,6 @@ void ServerLobby::asynchronousUpdate() } // asynchronousUpdate -//----------------------------------------------------------------------------- -void ServerLobby::encodePlayers(BareNetworkString* bns, - std::vector >& players) const -{ - bns->addUInt8((uint8_t)players.size()); - for (unsigned i = 0; i < players.size(); i++) - { - std::shared_ptr& player = players[i]; - bns->encodeString(player->getName()) - .addUInt32(player->getHostId()) - .addFloat(player->getDefaultKartColor()) - .addUInt32(player->getOnlineId()) - .addUInt8(player->getHandicap()) - .addUInt8(player->getLocalPlayerId()) - .addUInt8(player->getTeam()) - .encodeString(player->getCountryCode()); - bns->encodeString(player->getKartName()); - } -} // encodePlayers - //----------------------------------------------------------------------------- NetworkString* ServerLobby::getLoadWorldMessage( std::vector >& players, @@ -1224,15 +1229,14 @@ NetworkString* ServerLobby::getLoadWorldMessage( NetworkString* load_world_message = getNetworkString(); load_world_message->setSynchronous(true); load_world_message->addUInt8(LE_LOAD_WORLD); - load_world_message->addUInt32(m_winner_peer_id); - m_default_vote->encode(load_world_message); + m_lobby_settings->encodeDefaultVote(load_world_message); load_world_message->addUInt8(live_join ? 1 : 0); encodePlayers(load_world_message, players); load_world_message->addUInt32(m_item_seed); if (RaceManager::get()->isBattleMode()) { - load_world_message->addUInt32(m_battle_hit_capture_limit) - .addFloat(m_battle_time_limit); + load_world_message->addUInt32(m_lobby_settings->getBattleHitCaptureLimit()) + .addFloat(m_lobby_settings->getBattleTimeLimit()); uint16_t flag_return_time = (uint16_t)stk_config->time2Ticks( ServerConfig::m_flag_return_timeout); load_world_message->addUInt16(flag_return_time); @@ -1283,17 +1287,6 @@ bool ServerLobby::canLiveJoinNow() const return live_join; } // canLiveJoinNow -//----------------------------------------------------------------------------- -/** Returns true if world is active for clients to live join, spectate or - * going back to lobby live - */ -bool ServerLobby::worldIsActive() const -{ - return World::getWorld() && RaceEventManager::get()->isRunning() && - !RaceEventManager::get()->isRaceOver() && - World::getWorld()->getPhase() == WorldStatus::RACE_PHASE; -} // worldIsActive - //----------------------------------------------------------------------------- /** \ref STKPeer peer will be reset back to the lobby with reason * \ref BackLobbyReason blr @@ -1388,44 +1381,6 @@ void ServerLobby::liveJoinRequest(Event* event) peer->updateLastActivity(); } // liveJoinRequest -//----------------------------------------------------------------------------- -/** Get a list of current ingame players for live join or spectate. - */ -std::vector > - ServerLobby::getLivePlayers() const -{ - std::vector > players; - for (unsigned i = 0; i < RaceManager::get()->getNumPlayers(); i++) - { - const RemoteKartInfo& rki = RaceManager::get()->getKartInfo(i); - std::shared_ptr player = - rki.getNetworkPlayerProfile().lock(); - if (!player) - { - if (RaceManager::get()->modeHasLaps()) - { - player = std::make_shared( - nullptr, rki.getPlayerName(), - std::numeric_limits::max(), - rki.getDefaultKartColor(), - rki.getOnlineId(), rki.getHandicap(), - rki.getLocalPlayerId(), KART_TEAM_NONE, - rki.getCountryCode()); - player->setKartName(rki.getKartName()); - } - else - { - player = NetworkPlayerProfile::getReservedProfile( - RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_FREE_FOR_ALL ? - KART_TEAM_NONE : rki.getKartTeam()); - } - } - players.push_back(player); - } - return players; -} // getLivePlayers - //----------------------------------------------------------------------------- /** Decide where to put the live join player depends on his team and game mode. */ @@ -1686,7 +1641,7 @@ void ServerLobby::update(int ticks) StringUtils::wideToUtf8(rki.getPlayerName()).c_str(), sec); peer->kick(); } - if (m_troll_active && !peer->isAIPeer()) + if (m_hit_processor->isAntiTrollActive() && !peer->isAIPeer()) { // for all human players // if they troll, kick them @@ -1847,7 +1802,7 @@ void ServerLobby::update(int ticks) Log::info("ServerLobbyRoom", "Starting the race loading."); // This will create the world instance, i.e. load track and karts loadWorld(); - updateWorldSettings(); + m_lobby_settings->updateWorldSettings(m_game_info); m_state = WAIT_FOR_WORLD_LOADED; break; case RACING: @@ -2072,13 +2027,13 @@ void ServerLobby::startSelection(const Event *event) if (ServerConfig::m_sleeping_server) { Log::warn("ServerLobby", - "An attempt to start a race on a sleeping server. Lol."); + "An attempt to start a race on a sleeping server."); return; } auto peer = event->getPeerSP(); if (ServerConfig::m_owner_less) { - if (!m_allowed_to_start) + if (!m_lobby_settings->isAllowedToStart()) { std::string msg = "Starting the game is forbidden by server owner"; sendStringToPeer(msg, peer); @@ -2098,7 +2053,7 @@ void ServerLobby::startSelection(const Event *event) return; } } - if (!m_allowed_to_start) + if (!m_lobby_settings->isAllowedToStart()) { std::string msg = "Starting the game is forbidden by server owner"; sendStringToPeer(msg, peer); @@ -2115,7 +2070,7 @@ void ServerLobby::startSelection(const Event *event) } } } else { - if (!m_allowed_to_start) + if (!m_lobby_settings->isAllowedToStart()) { // Produce no log spam return; @@ -2251,72 +2206,7 @@ void ServerLobby::startSelection(const Event *event) return; } - m_default_vote->m_track_name = m_asset_manager->getRandomAvailableMap(); - RandomGenerator rg; - switch (RaceManager::get()->getMinorMode()) - { - case RaceManager::MINOR_MODE_NORMAL_RACE: - case RaceManager::MINOR_MODE_TIME_TRIAL: - case RaceManager::MINOR_MODE_FOLLOW_LEADER: - { - Track* t = track_manager->getTrack(m_default_vote->m_track_name); - assert(t); - m_default_vote->m_num_laps = t->getDefaultNumberOfLaps(); - if (ServerConfig::m_auto_game_time_ratio > 0.0f) - { - m_default_vote->m_num_laps = - (uint8_t)(fmaxf(1.0f, (float)t->getDefaultNumberOfLaps() * - ServerConfig::m_auto_game_time_ratio)); - } - else if (m_fixed_lap >= 0) - m_default_vote->m_num_laps = m_fixed_lap; - m_default_vote->m_reverse = rg.get(2) == 0; - if (m_fixed_direction >= 0) - m_default_vote->m_reverse = (m_fixed_direction == 1); - break; - } - case RaceManager::MINOR_MODE_FREE_FOR_ALL: - { - m_default_vote->m_num_laps = 0; - m_default_vote->m_reverse = rg.get(2) == 0; - break; - } - case RaceManager::MINOR_MODE_CAPTURE_THE_FLAG: - { - m_default_vote->m_num_laps = 0; - m_default_vote->m_reverse = 0; - break; - } - case RaceManager::MINOR_MODE_SOCCER: - { - if (m_tournament) - { - m_tournament->applyRestrictionsOnDefaultVote(m_default_vote); - } - else - { - if (m_game_setup->isSoccerGoalTarget()) - { - m_default_vote->m_num_laps = - (uint8_t)(UserConfigParams::m_num_goals); - if (m_default_vote->m_num_laps > 10) - m_default_vote->m_num_laps = (uint8_t)5; - } - else - { - m_default_vote->m_num_laps = - (uint8_t)(UserConfigParams::m_soccer_time_limit); - if (m_default_vote->m_num_laps > 15) - m_default_vote->m_num_laps = (uint8_t)7; - } - m_default_vote->m_reverse = rg.get(2) == 0; - } - break; - } - default: - assert(false); - break; - } + m_lobby_settings->initializeDefaultVote(); if (!allowJoinedPlayersWaiting()) { @@ -2347,8 +2237,7 @@ void ServerLobby::startSelection(const Event *event) ns->addUInt8(LE_START_SELECTION) .addFloat(ServerConfig::m_voting_timeout) .addUInt8(/*m_game_setup->isGrandPrixStarted() ? 1 : */0) - .addUInt8((m_fixed_lap >= 0 - || m_default_lap_multiplier > 0.0f) ? 1 : 0) + .addUInt8((!m_lobby_settings->hasNoLapRestrictions() ? 1 : 0)) .addUInt8(ServerConfig::m_track_voting ? 1 : 0); @@ -2625,7 +2514,7 @@ void ServerLobby::checkRaceFinished() gp_changes.back() += points_fl; cur_score += points_fl; } - int team = m_team_for_player[username]; + int team = m_lobby_settings->getTeamForUsername(username); if (team > 0) { m_gp_team_scores[team].score += cur_score; @@ -2757,7 +2646,7 @@ void ServerLobby::clientDisconnected(Event* event) World* w = World::getWorld(); std::shared_ptr peer = event->getPeerSP(); - m_message_receivers.erase(peer); + m_lobby_settings->onPeerDisconnect(peer); // No warnings otherwise, as it could happen during lobby period if (w && m_game_info) saveDisconnectingPeerInfo(peer); @@ -2801,6 +2690,7 @@ void ServerLobby::clientDisconnected(Event* event) } // clientDisconnected //----------------------------------------------------------------------------- + void ServerLobby::kickPlayerWithReason(std::shared_ptr peer, const char* reason) const { NetworkString *message = getNetworkString(2); @@ -3068,7 +2958,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, Log::verbose("ServerLobby", "Player refused: invalid player"); return; } - if (m_usernames_white_list.count(username) > 0) + if (m_lobby_settings->isInWhitelist(username)) password = server_pw; } if (password != server_pw) @@ -3155,9 +3045,10 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, int previous_team = -1; std::string username = StringUtils::wideToUtf8(player->getName()); - auto it2 = m_team_for_player.find(username); - if (it2 != m_team_for_player.end()) - previous_team = it2->second; + + // kimden: I'm not sure why the check is double + if (m_lobby_settings->hasTeam(username)) + previous_team = m_lobby_settings->getTeamForUsername(username); bool can_change_teams = true; if (m_tournament && !m_tournament->canChangeTeam()) @@ -3337,7 +3228,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, if (ServerConfig::m_record_replays) { std::string msg; - if (m_consent_on_replays) + if (m_lobby_settings->hasConsentOnReplays()) msg = "Recording ghost replays is enabled. " "The crowned player can change that " "using /replay 0 (to disable) or /replay 1 (to enable). " @@ -3448,10 +3339,9 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) profile_name = StringUtils::utf32ToWide({0x1F528}) + profile_name; std::string prefix = ""; - for (const std::string& category: m_categories_for_player[utf8_profile_name]) + for (const std::string& category: m_lobby_settings->getVisibleCategoriesForPlayer(utf8_profile_name)) { - if (!m_hidden_categories.count(category)) - prefix += category + ", "; + prefix += category + ", "; } if (!prefix.empty()) { @@ -3608,11 +3498,11 @@ void ServerLobby::handlePlayerVote(Event* event) event->getPeer()->getHostId(), vote.m_track_name.c_str(), vote.m_num_laps, vote.m_reverse); - Track* t = track_manager->getTrack(vote.m_track_name); + Track* t = TrackManager::get()->getTrack(vote.m_track_name); if (!t) { vote.m_track_name = m_asset_manager->getAnyMapForVote(); - t = track_manager->getTrack(vote.m_track_name); + t = TrackManager::get()->getTrack(vote.m_track_name); assert(t); } @@ -3621,59 +3511,10 @@ void ServerLobby::handlePlayerVote(Event* event) { m_tournament->applyRestrictionsOnVote(&vote); } - else if (RaceManager::get()->modeHasLaps()) - { - if (m_default_lap_multiplier > 0.0f) - { - vote.m_num_laps = - (uint8_t)(fmaxf(1.0f, (float)t->getDefaultNumberOfLaps() * - m_default_lap_multiplier)); - } - else if (vote.m_num_laps == 0 || vote.m_num_laps > 20) - vote.m_num_laps = (uint8_t)3; - if (!t->reverseAvailable() && vote.m_reverse) - vote.m_reverse = false; - } - else if (RaceManager::get()->isSoccerMode()) - { - if (m_game_setup->isSoccerGoalTarget()) - { - if (m_default_lap_multiplier > 0.0f) - { - vote.m_num_laps = (uint8_t)(m_default_lap_multiplier * - UserConfigParams::m_num_goals); - } - else if (vote.m_num_laps > 10) - vote.m_num_laps = (uint8_t)5; - } - else - { - if (m_default_lap_multiplier > 0.0f) - { - vote.m_num_laps = (uint8_t)(m_default_lap_multiplier * - UserConfigParams::m_soccer_time_limit); - } - else if (vote.m_num_laps > 15) - vote.m_num_laps = (uint8_t)7; - } - } - else if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_FREE_FOR_ALL) - { - vote.m_num_laps = 0; - } - else if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) - { - vote.m_num_laps = 0; - vote.m_reverse = false; - } - if (m_fixed_lap >= 0) + else { - vote.m_num_laps = m_fixed_lap; + m_lobby_settings->applyRestrictionsOnVote(&vote, t); } - if (m_fixed_direction >= 0) - vote.m_reverse = (m_fixed_direction == 1); // Store vote: vote.m_player_name = event->getPeer()->getPlayerProfiles()[0]->getName(); @@ -3695,8 +3536,7 @@ void ServerLobby::handlePlayerVote(Event* event) * \param winner_peer_id The host id of winner (unchanged if no vote). * \return True if race can go on, otherwise wait. */ -bool ServerLobby::handleAllVotes(PeerVote* winner_vote, - uint32_t* winner_peer_id) +bool ServerLobby::handleAllVotes(PeerVote* winner_vote) { // First remove all votes from disconnected hosts auto it = m_peers_votes.begin(); @@ -3730,8 +3570,7 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote, getMaxVotingTime(), isVotingOver(), cur_players, - m_default_vote, - winner_vote, winner_peer_id + winner_vote ); } // handleAllVotes @@ -3755,8 +3594,8 @@ void ServerLobby::getHitCaptureLimit() if (ServerConfig::m_time_limit_ffa > 0.0f) time_limit = (float)ServerConfig::m_time_limit_ffa; } - m_battle_hit_capture_limit = hit_capture_limit; - m_battle_time_limit = time_limit; + m_lobby_settings->setBattleHitCaptureLimit(hit_capture_limit); + m_lobby_settings->setBattleTimeLimit(time_limit); } // getHitCaptureLimit // ---------------------------------------------------------------------------- @@ -4229,8 +4068,8 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, bool teams_before = RaceManager::get()->teamEnabled(); unsigned total_players = 0; STKHost::get()->updatePlayers(NULL, NULL, &total_players); - bool bad_mode = (m_available_modes.count(mode) == 0); - bool bad_difficulty = (m_available_difficulties.count(difficulty) == 0); + bool bad_mode = !m_lobby_settings->isModeAvailable(mode); + bool bad_difficulty = m_lobby_settings->isDifficultyAvailable(difficulty); if (bad_mode || bad_difficulty) { // It remains just in case, but kimden thinks that @@ -4310,7 +4149,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, if (teams_after) { int final_number, players_number; - m_team_for_player.clear(); + m_lobby_settings->clearTeams(); m_command_manager->assignRandomTeams(2, &final_number, &players_number); } else @@ -4512,7 +4351,7 @@ void ServerLobby::addLiveJoinPlaceholder( return; if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) { - Track* t = track_manager->getTrack(m_game_setup->getCurrentTrack()); + Track* t = TrackManager::get()->getTrack(m_game_setup->getCurrentTrack()); assert(t); int max_players = std::min((int)ServerConfig::m_server_max_players, (int)t->getMaxArenaPlayers()); @@ -5172,54 +5011,12 @@ void ServerLobby::storeResults() #endif } // storeResults //----------------------------------------------------------------------------- -void ServerLobby::initAvailableModes() -{ - std::vector statements = - StringUtils::split(ServerConfig::m_available_modes, ' ', false); - - for (const std::string& s: statements) - { - if (s.length() <= 1) - continue; - bool difficulty = s[0] == 'd'; - if (difficulty) - { - for (unsigned i = 1; i < s.length(); i++) - { - m_available_difficulties.insert(s[i] - '0'); - } - } - else - { - for (unsigned i = 1; i < s.length(); i++) - { - m_available_modes.insert(s[i] - '0'); - } - } - } -} // initAvailableModes -//----------------------------------------------------------------------------- void ServerLobby::resetToDefaultSettings() { - if (ServerConfig::m_server_configurable && !m_preserve.count("mode")) + if (ServerConfig::m_server_configurable && !m_lobby_settings->isPreservingMode()) handleServerConfiguration(NULL); - if (!m_preserve.count("elim")) - m_kart_elimination->disable(); - - if (!m_preserve.count("laps")) - { - m_default_lap_multiplier = -1.0; - m_fixed_lap = -1; - } - - if (!m_preserve.count("direction")) - m_fixed_direction = ServerConfig::m_fixed_direction; - - m_lobby_queues->resetToDefaultSettings(m_preserve); - - if (!m_preserve.count("replay")) - setConsentOnReplays(false); + m_lobby_settings->onResetToDefaultSettings(); } // resetToDefaultSettings //----------------------------------------------------------------------------- void ServerLobby::writeOwnReport(std::shared_ptr reporter, std::shared_ptr reporting, const std::string& info) @@ -5259,46 +5056,6 @@ void ServerLobby::writeOwnReport(std::shared_ptr reporter, std::shared_ #endif } // writeOwnReport //----------------------------------------------------------------------------- -void ServerLobby::initCategories() -{ - std::vector tokens = StringUtils::split( - ServerConfig::m_categories, ' '); - std::string category = ""; - bool isTeam = false; - for (std::string& s: tokens) - { - if (s.empty()) - continue; - else if (s[0] == '#') - { - isTeam = false; - if (s.length() > 1 && s[1] == '#') - { - category = s.substr(2); - m_hidden_categories.insert(category); - } - else - category = s.substr(1); - } - else if (s[0] == '$') - { - isTeam = true; - category = s.substr(1); - } - else - { - if (!isTeam) { - m_player_categories[category].insert(s); - m_categories_for_player[s].insert(category); - } - else - { - m_team_for_player[s] = category[0] - '0' + 1; - } - } - } -} // initCategories -//----------------------------------------------------------------------------- void ServerLobby::changeColors() { // We assume here that it's soccer, as it's only called @@ -5371,13 +5128,11 @@ bool ServerLobby::canRace(std::shared_ptr peer) return false; } - if (!m_play_requirement_tracks.empty()) - for (const std::string& track: m_play_requirement_tracks) - if (peer->getClientAssets().second.count(track) == 0) - { - m_why_peer_cannot_play[peer] = HR_LACKING_REQUIRED_MAPS; - return false; - } + if (!m_lobby_settings->getMissingAssets(peer).empty()) + { + m_why_peer_cannot_play[peer] = HR_LACKING_REQUIRED_MAPS; + return false; + } if (peer->addon_karts_count < ServerConfig::m_addon_karts_play_threshold) { @@ -5552,86 +5307,6 @@ std::string ServerLobby::getGrandPrixStandings(bool showIndividual, bool showTea return response.str(); } // getGrandPrixStandings //----------------------------------------------------------------------------- -bool ServerLobby::loadCustomScoring(std::string& scoring) -{ - std::set available_scoring_types = { - "standard", "default", "", "inc", "fixed", "linear-gap", "exp-gap" - }; - auto previous_params = m_scoring_int_params; - auto previous_type = m_scoring_type; - m_scoring_int_params.clear(); - m_scoring_type = ""; - if (!scoring.empty()) - { - std::vector params = StringUtils::split(scoring, ' '); - if (params.empty()) - { - m_scoring_type = ""; - return true; - } - m_scoring_type = params[0]; - if (available_scoring_types.count(m_scoring_type) == 0) - { - Log::warn("ServerLobby", "Unknown scoring type %s, fallback.", m_scoring_type.c_str()); - m_scoring_int_params = previous_params; - m_scoring_type = previous_type; - return false; - } - for (unsigned i = 1; i < params.size(); i++) - { - int param; - if (!StringUtils::fromString(params[i], param)) - { - Log::warn("ServerLobby", "Unable to parse integer from custom scoring data, fallback."); - m_scoring_int_params = previous_params; - m_scoring_type = previous_type; - return false; - } - m_scoring_int_params.push_back(param); - } - } - return true; -} // loadCustomScoring -//----------------------------------------------------------------------------- -void ServerLobby::updateWorldSettings() -{ - World::getWorld()->setGameInfo(m_game_info); - WorldWithRank *wwr = dynamic_cast(World::getWorld()); - if (wwr) - { - wwr->setCustomScoringSystem(m_scoring_type, m_scoring_int_params); - } - SoccerWorld *sw = dynamic_cast(World::getWorld()); - if (sw) - { - std::string policy = ServerConfig::m_soccer_goals_policy; - if (policy == "standard") - sw->setGoalScoringPolicy(0); - else if (policy == "no-own-goals") - sw->setGoalScoringPolicy(1); - else if (policy == "advanced") - sw->setGoalScoringPolicy(2); - else - Log::warn("ServerLobby", "Soccer goals policy %s does not exist", policy.c_str()); - } -} // updateWorldSettings -//----------------------------------------------------------------------------- -void ServerLobby::loadWhiteList() -{ - std::vector tokens = StringUtils::split( - ServerConfig::m_white_list, ' '); - for (std::string& s: tokens) - m_usernames_white_list.insert(s); -} // loadWhiteList -//----------------------------------------------------------------------------- -void ServerLobby::loadPreservedSettings() -{ - std::vector what_to_preserve = - StringUtils::split(std::string(ServerConfig::m_preserve_on_reset), ' '); - for (std::string& str: what_to_preserve) - m_preserve.insert(str); -} // loadWhiteList -//----------------------------------------------------------------------------- bool ServerLobby::writeOnePlayerReport(std::shared_ptr reporter, const std::string& table, const std::string& info) { @@ -5665,24 +5340,6 @@ void ServerLobby::changeLimitForTournament(bool goal_target) updatePlayerList(); } // changeLimitForTournament //----------------------------------------------------------------------------- -void ServerLobby::initAvailableTracks() -{ - m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); - m_global_karts_filter = KartFilter(ServerConfig::m_only_played_karts_string); - m_asset_manager->setMustHaveMaps(ServerConfig::m_must_have_tracks_string); - m_play_requirement_tracks = StringUtils::split( - ServerConfig::m_play_requirement_tracks_string, ' ', false); -} // initAvailableTracks -//----------------------------------------------------------------------------- -std::vector ServerLobby::getMissingAssets(std::shared_ptr peer) const -{ - std::vector ans; - for (const std::string& required_track : m_play_requirement_tracks) - if (peer->getClientAssets().second.count(required_track) == 0) - ans.push_back(required_track); - return ans; -} // getMissingAssets -//----------------------------------------------------------------------------- std::shared_ptr ServerLobby::getCommandManager() { @@ -5760,7 +5417,7 @@ void ServerLobby::setTemporaryTeamInLobby(const std::string& username, int team) // todo This should be moved later to another unit. void ServerLobby::clearTemporaryTeams() { - m_team_for_player.clear(); + m_lobby_settings->clearTeams(); for (auto& peer : STKHost::get()->getPeers()) { @@ -5775,12 +5432,7 @@ void ServerLobby::clearTemporaryTeams() // todo This should be moved later to another unit. void ServerLobby::shuffleTemporaryTeams(const std::map& permutation) { - for (auto& p: m_team_for_player) - { - auto it = permutation.find(p.second); - if (it != permutation.end()) - p.second = it->second; - } + m_lobby_settings->applyPermutationToTeams(permutation); for (auto& peer : STKHost::get()->getPeers()) { for (auto &profile: peer->getPlayerProfiles()) @@ -5830,7 +5482,7 @@ void ServerLobby::applyAllFilters(std::set& maps, bool use_history) auto it = maps.begin(); while (it != maps.end()) { - Track* t = track_manager->getTrack(*it); + Track* t = TrackManager::get()->getTrack(*it); if (t && t->getMaxArenaPlayers() < max_player) { it = maps.erase(it); @@ -5848,7 +5500,8 @@ void ServerLobby::applyAllFilters(std::set& maps, bool use_history) map_context.wildcards = m_map_history; map_context.applied_at_selection_start = true; map_context.elements = maps; - m_global_filter.apply(map_context); + m_lobby_settings->applyGlobalFilter(map_context); + if (use_history) { if (m_tournament) @@ -5862,7 +5515,6 @@ void ServerLobby::applyAllFilters(std::set& maps, bool use_history) void ServerLobby::applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection) const { - FilterContext kart_context; kart_context.username = username; kart_context.num_players = 0; // unused @@ -5870,7 +5522,7 @@ void ServerLobby::applyAllKartFilters(const std::string& username, std::setapplyGlobalKartsFilter(kart_context); m_lobby_queues->applyFrontKartFilters(kart_context); swap(karts, kart_context.elements); } // applyAllKartFilters @@ -5993,22 +5645,16 @@ void ServerLobby::saveDisconnectingIdInfo(int id) const } } // saveDisconnectingIdInfo -//----------------------------------------------------------------------------- -std::string ServerLobby::getAvailableTeams() const -{ - if (RaceManager::get()->teamEnabled()) - return "rb"; - - return m_available_teams; -} // getAvailableTeams - //----------------------------------------------------------------------------- void ServerLobby::setTeamInLobby(std::shared_ptr profile, KartTeam team) { // Used for soccer+CTF, where everything can be defined by KartTeam profile->setTeam(team); profile->setTemporaryTeam(TeamUtils::getIndexFromKartTeam(team)); - m_team_for_player[StringUtils::wideToUtf8(profile->getName())] = profile->getTemporaryTeam(); + m_lobby_settings->setTeamForUsername( + StringUtils::wideToUtf8(profile->getName()), + profile->getTemporaryTeam() + ); checkNoTeamSpectator(profile->getPeer()); } // setTeamInLobby @@ -6022,7 +5668,10 @@ void ServerLobby::setTemporaryTeamInLobby(std::shared_ptr profile->setTeam((KartTeam)(TeamUtils::getKartTeamFromIndex(team))); else profile->setTeam(KART_TEAM_NONE); - m_team_for_player[StringUtils::wideToUtf8(profile->getName())] = profile->getTemporaryTeam(); + m_lobby_settings->setTeamForUsername( + StringUtils::wideToUtf8(profile->getName()), + profile->getTemporaryTeam() + ); checkNoTeamSpectator(profile->getPeer()); } // setTemporaryTeamInLobby diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 3515e5a081c..6f5db69198a 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -56,6 +56,7 @@ class KartElimination; class MapVoteHandler; class Tournament; class LobbyQueues; +class LobbySettings; namespace Online { @@ -126,10 +127,9 @@ class ServerLobby : public LobbyProtocol /* The state used in multiple threads when reseting server. */ enum ResetState : unsigned int { - RS_NONE, // Default state - RS_WAITING, // Waiting for reseting finished - RS_ASYNC_RESET // Finished reseting server in main thread, now async - // thread + RS_NONE, // Default state + RS_WAITING, // Waiting for reseting finished + RS_ASYNC_RESET // Finished reseting server in main thread, now async thread }; std::atomic m_rs_state; @@ -159,9 +159,6 @@ class ServerLobby : public LobbyProtocol std::map, bool, std::owner_less > > m_peers_ready; - std::map, std::set, - std::owner_less > > m_peers_muted_players; - std::weak_ptr m_server_registering; /** Timeout counter for various state. */ @@ -177,12 +174,6 @@ class ServerLobby : public LobbyProtocol std::map m_pending_peer_connection; - std::shared_ptr m_ranking; - - std::shared_ptr m_hit_processor; - - std::shared_ptr m_asset_manager; - /* Saved the last game result */ NetworkString* m_result_ns; @@ -205,18 +196,21 @@ class ServerLobby : public LobbyProtocol uint64_t m_last_unsuccess_poll_time, m_server_started_at, m_server_delay; - // Default game settings if no one has ever vote, and save inside here for - // final vote (for live join) - PeerVote* m_default_vote; - - int m_battle_hit_capture_limit; + // Other units previously used in ServerLobby + std::shared_ptr m_ranking; + std::shared_ptr m_hit_processor; + std::shared_ptr m_asset_manager; + std::shared_ptr m_kart_elimination; + std::shared_ptr m_map_vote_handler; + std::shared_ptr m_tournament; + std::shared_ptr m_lobby_queues; + std::shared_ptr m_lobby_settings; - float m_battle_time_limit; + friend CommandManager; + std::shared_ptr m_command_manager; unsigned m_item_seed; - uint32_t m_winner_peer_id; - uint64_t m_client_starting_time; // Calculated before each game started @@ -224,89 +218,19 @@ class ServerLobby : public LobbyProtocol std::set> m_spectators_by_limit; - std::vector m_play_requirement_tracks; - - bool m_restricting_config; - - bool m_inverted_config_restriction; - - std::set m_config_available_tracks; - - std::map> m_config_track_limitations; - - irr::core::stringw m_help_message; - - std::map, std::set> m_message_receivers; - - std::set> m_team_speakers; - std::map, int> m_why_peer_cannot_play; - std::shared_ptr m_kart_elimination; - - std::shared_ptr m_map_vote_handler; - - std::set m_available_difficulties; - - std::set m_available_modes; - - std::map> m_player_categories; - - std::set m_hidden_categories; - - std::set m_special_categories; - - std::map> m_categories_for_player; - - std::map m_team_for_player; - - std::shared_ptr m_tournament; - - TrackFilter m_global_filter; - - KartFilter m_global_karts_filter; - std::set m_temp_banned; - std::shared_ptr m_lobby_queues; - std::vector m_map_history; std::map m_gp_scores; std::map m_gp_team_scores; - int m_fixed_lap; - - int m_fixed_direction; - - double m_default_lap_multiplier; - - std::vector m_scoring_int_params; - - std::string m_scoring_type; - - std::set m_usernames_white_list; - - std::set m_preserve; - - bool m_allowed_to_start; - - bool m_consent_on_replays; - - bool m_shuffle_gp; - - std::string m_available_teams; - std::atomic m_current_max_players_in_game; - GameInfo* m_game_info; - - // config for troll system - bool m_troll_active; - - friend CommandManager; - std::shared_ptr m_command_manager; + std::shared_ptr m_game_info; // connection management void clientDisconnected(Event* event); @@ -382,7 +306,7 @@ class ServerLobby : public LobbyProtocol uint32_t online_id, const irr::core::stringw& online_name, const std::string& country_code); - bool handleAllVotes(PeerVote* winner, uint32_t* winner_peer_id); + bool handleAllVotes(PeerVote* winner); void getRankingForPlayer(std::shared_ptr p); void submitRankingsToAddons(); void computeNewRankings(); @@ -398,16 +322,12 @@ class ServerLobby : public LobbyProtocol NetworkString* getLoadWorldMessage( std::vector >& players, bool live_join) const; - void encodePlayers(BareNetworkString* bns, - std::vector >& players) const; - std::vector > getLivePlayers() const; void setPlayerKarts(const NetworkString& ns, std::shared_ptr peer) const; bool handleAssets(const NetworkString& ns, std::shared_ptr peer); void handleServerCommand(Event* event, std::shared_ptr peer); void liveJoinRequest(Event* event); void rejectLiveJoin(std::shared_ptr peer, BackLobbyReason blr); bool canLiveJoinNow() const; - bool worldIsActive() const; int getReservedId(std::shared_ptr& p, unsigned local_id); void handleKartInfo(Event* event); @@ -421,18 +341,12 @@ class ServerLobby : public LobbyProtocol void getMessagesFromHost(std::shared_ptr peer, int online_id); void writePlayerReport(Event* event); bool supportsAI(); - void initCategories(); void initTournamentPlayers(); void changeColors(); bool canRace(std::shared_ptr peer); bool canVote(std::shared_ptr peer) const; bool hasHostRights(std::shared_ptr peer) const; - std::vector getMissingAssets(std::shared_ptr peer) const; std::string getGrandPrixStandings(bool showIndividual = false, bool showTeam = true) const; - bool loadCustomScoring(std::string& scoring); - void updateWorldSettings(); - void loadWhiteList(); - void loadPreservedSettings(); void changeLimitForTournament(bool goal_target); std::shared_ptr getCommandManager(); @@ -473,8 +387,6 @@ class ServerLobby : public LobbyProtocol void storeResults(); uint32_t getServerIdOnline() const { return m_server_id_online; } void setClientServerHostId(uint32_t id) { m_client_server_host_id = id; } - void initAvailableTracks(); - void initAvailableModes(); void resetToDefaultSettings(); void writeOwnReport(std::shared_ptr reporter, std::shared_ptr reporting, const std::string& info); @@ -485,8 +397,6 @@ class ServerLobby : public LobbyProtocol void sendStringToPeer(std::string& s, std::shared_ptr peer); void sendStringToAllPeers(std::string& s); int getPermissions(std::shared_ptr peer) const; - bool hasConsentOnReplays() const { return m_consent_on_replays; } - void setConsentOnReplays(bool value) { m_consent_on_replays = value; } bool isSoccerGoalTarget() const; #ifdef ENABLE_SQLITE3 @@ -494,10 +404,6 @@ class ServerLobby : public LobbyProtocol std::string& direction, int laps); #endif - bool isDifficultyAvailable(int difficulty) const - { return m_available_difficulties.count(difficulty) > 0; } - bool isModeAvailable(int mode) const - { return m_available_modes.count(mode) > 0; } void setTemporaryTeamInLobby(const std::string& username, int team); void clearTemporaryTeams(); void shuffleTemporaryTeams(const std::map& permutation); @@ -512,15 +418,10 @@ class ServerLobby : public LobbyProtocol std::shared_ptr player, const std::string& type) const; - static int m_default_fixed_laps; - static int m_fixed_laps; bool playerReportsTableExists() const; void saveDisconnectingPeerInfo(std::shared_ptr peer) const; void saveDisconnectingIdInfo(int id) const; - std::string getInternalAvailableTeams() const { return m_available_teams; } - std::string getAvailableTeams() const; - void setInternalAvailableTeams(std::string& s) { m_available_teams = s; } // The functions below set *both* KartTeam and temporary team, // depending on game mode; also reset/set ASM_NO_TEAM if needed. @@ -528,17 +429,19 @@ class ServerLobby : public LobbyProtocol void setTemporaryTeamInLobby(std::shared_ptr profile, int team); void checkNoTeamSpectator(std::shared_ptr peer); void setSpectateModeProperly(std::shared_ptr peer, AlwaysSpectateMode mode); - int getTeamForUsername(const std::string& name) - { return m_team_for_player[name]; } + std::shared_ptr getHitProcessor() const { return m_hit_processor; } std::shared_ptr getLobbyAssetManager() const { return m_asset_manager; } std::shared_ptr getTournament() const { return m_tournament; } - std::map> getCategories() const - { return m_player_categories; } std::shared_ptr getLobbyQueues() const { return m_lobby_queues; } + std::shared_ptr getLobbySettings() const + { return m_lobby_settings; } + std::shared_ptr getKartElimination() const + { return m_kart_elimination; } + std::shared_ptr getGameInfo() const { return m_game_info; } }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/network/server.cpp b/src/network/server.cpp index 2dd313cf341..0458c95f3a0 100644 --- a/src/network/server.cpp +++ b/src/network/server.cpp @@ -238,7 +238,7 @@ Server::~Server() Track* Server::getCurrentTrack() const { if (!m_current_track.empty()) - return track_manager->getTrack(m_current_track); + return TrackManager::get()->getTrack(m_current_track); return NULL; } // getCurrentTrack diff --git a/src/race/grand_prix_data.cpp b/src/race/grand_prix_data.cpp index 2447bbf4688..6b30dd1db75 100644 --- a/src/race/grand_prix_data.cpp +++ b/src/race/grand_prix_data.cpp @@ -100,9 +100,10 @@ void GrandPrixData::changeTrackNumber(const unsigned int number_of_tracks, // The problem with the track groups is that "all" isn't a track group // TODO: Add "all" to the track groups and rewrite this more elegant std::vector track_indices; + std::shared_ptr track_manager = TrackManager::get(); if (track_group == "all") { - for(unsigned int i=0; igetNumberOfTracks(); i++) + for (unsigned int i = 0; i < track_manager->getNumberOfTracks(); i++) { const Track *track = track_manager->getTrack(i); // Ignore no-racing tracks: @@ -187,11 +188,11 @@ void GrandPrixData::changeReverse(const GrandPrixData::GPReverseType use_reverse } else if (use_reverse == GP_ALL_REVERSE) // all reversed { - m_reversed[i] = track_manager->getTrack(m_tracks[i])->reverseAvailable(); + m_reversed[i] = TrackManager::get()->getTrack(m_tracks[i])->reverseAvailable(); } else if (use_reverse == GP_RANDOM_REVERSE) { - if (track_manager->getTrack(m_tracks[i])->reverseAvailable()) + if (TrackManager::get()->getTrack(m_tracks[i])->reverseAvailable()) m_reversed[i] = (rand() % 2 != 0); else m_reversed[i] = false; @@ -312,7 +313,7 @@ void GrandPrixData::reload() } // 1.1 Checking if the track exists - Track* t = track_manager->getTrack(track_id); + Track* t = TrackManager::get()->getTrack(track_id); if (t == NULL) { Log::error("GrandPrixData", @@ -402,7 +403,7 @@ bool GrandPrixData::checkConsistency(bool log_error) const { for (unsigned int i = 0; i < m_tracks.size(); i++) { - if (track_manager->getTrack(m_tracks[i]) == NULL) + if (TrackManager::get()->getTrack(m_tracks[i]) == NULL) { if (log_error) { @@ -512,7 +513,7 @@ unsigned int GrandPrixData::getNumberOfTracks(bool includeLocked) const irr::core::stringw GrandPrixData::getTrackName(const unsigned int track) const { assert(track < getNumberOfTracks(true)); - Track* t = track_manager->getTrack(m_tracks[track]); + Track* t = TrackManager::get()->getTrack(m_tracks[track]); assert(t != NULL); return t->getName(); } // getTrackName diff --git a/src/race/highscores.cpp b/src/race/highscores.cpp index ae1605bc0a3..95dafe3f195 100644 --- a/src/race/highscores.cpp +++ b/src/race/highscores.cpp @@ -322,6 +322,7 @@ void Highscores::getEntry(int number, std::string &kart_name, // ----------------------------------------------------------------------------- bool Highscores::operator < (const Highscores& hi) const { + std::shared_ptr track_manager = TrackManager::get(); switch (m_sort_order) { case SO_TRACK: diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index d20913ad0c0..a71dfa36ce3 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -1041,7 +1041,7 @@ void RaceManager::exitRace(bool delete_world) } // Reload track screenshot after delete_world (track textures are unloaded) - track_manager->onDemandLoadTrackScreenshots(); + TrackManager::get()->onDemandLoadTrackScreenshots(); m_saved_gp = NULL; m_track_number = 0; diff --git a/src/replay/replay_play.cpp b/src/replay/replay_play.cpp index 9dbda4256e0..7660664fa82 100644 --- a/src/replay/replay_play.cpp +++ b/src/replay/replay_play.cpp @@ -273,7 +273,7 @@ bool ReplayPlay::addReplayFile(const std::string& fn, bool custom_replay, int ca if (rd.m_track_name.compare("mansion") == 0) rd.m_track_name = std::string("addon_blackhill-mansion"); - Track* t = track_manager->getTrack(rd.m_track_name); + Track* t = TrackManager::get()->getTrack(rd.m_track_name); if (t == NULL) { Log::warn("Replay", "Track '%s' used in replay '%s' not found in STK!", diff --git a/src/states_screens/arenas_screen.cpp b/src/states_screens/arenas_screen.cpp index 21a915eb296..222c1a48614 100644 --- a/src/states_screens/arenas_screen.cpp +++ b/src/states_screens/arenas_screen.cpp @@ -58,6 +58,7 @@ void ArenasScreen::loadedFromFile() void ArenasScreen::beforeAddingWidget() { + std::shared_ptr track_manager = TrackManager::get(); // Add user-defined group to track groups track_manager->setFavoriteTrackStatus(PlayerManager::getCurrentPlayer()->getFavoriteTrackStatus()); @@ -179,7 +180,7 @@ void ArenasScreen::eventCallback(Widget* widget, const std::string& name, const return; } - Track* clicked_track = track_manager->getTrack(selection); + Track* clicked_track = TrackManager::get()->getTrack(selection); if (clicked_track) { // In favorite edit mode, switch the status of the selected track @@ -215,6 +216,8 @@ void ArenasScreen::eventCallback(Widget* widget, const std::string& name, const void ArenasScreen::buildTrackList() { + std::shared_ptr track_manager = TrackManager::get(); + // Add user-defined group to track groups track_manager->setFavoriteTrackStatus(PlayerManager::getCurrentPlayer()->getFavoriteTrackStatus()); diff --git a/src/states_screens/dialogs/addons_loading.cpp b/src/states_screens/dialogs/addons_loading.cpp index 5361018750b..a5b052803fa 100644 --- a/src/states_screens/dialogs/addons_loading.cpp +++ b/src/states_screens/dialogs/addons_loading.cpp @@ -412,7 +412,7 @@ void AddonsLoading::doInstall() dismiss(); } - track_manager->loadTrackList(); + TrackManager::get()->loadTrackList(); // Update the replay file list to use latest track pointer ReplayPlay::get()->loadAllReplayFile(); delete grand_prix_manager; diff --git a/src/states_screens/dialogs/addons_pack.cpp b/src/states_screens/dialogs/addons_pack.cpp index a6aedb0d859..eeaa60ee17d 100644 --- a/src/states_screens/dialogs/addons_pack.cpp +++ b/src/states_screens/dialogs/addons_pack.cpp @@ -316,6 +316,8 @@ void AddonsPack::uninstallByName(const std::string& name, cl->updateAssetsToServer(); return; } + + std::shared_ptr track_manager = TrackManager::get(); if (track_manager->getTrack(addon_id)) { track_manager->removeTrack(addon_id); diff --git a/src/states_screens/dialogs/ghost_replay_info_dialog.cpp b/src/states_screens/dialogs/ghost_replay_info_dialog.cpp index d70f3bf9ae8..8b065d6421e 100644 --- a/src/states_screens/dialogs/ghost_replay_info_dialog.cpp +++ b/src/states_screens/dialogs/ghost_replay_info_dialog.cpp @@ -60,7 +60,7 @@ GhostReplayInfoDialog::GhostReplayInfoDialog(unsigned int replay_id, m_info_widget = getWidget("info"); m_info_widget->setText(m_rd.m_info); - Track* track = track_manager->getTrack(m_rd.m_track_name); + Track* track = TrackManager::get()->getTrack(m_rd.m_track_name); m_track_screenshot_widget = getWidget("track_screenshot"); m_track_screenshot_widget->setFocusable(false); diff --git a/src/states_screens/dialogs/high_score_info_dialog.cpp b/src/states_screens/dialogs/high_score_info_dialog.cpp index bc6372a724d..b88db511e82 100644 --- a/src/states_screens/dialogs/high_score_info_dialog.cpp +++ b/src/states_screens/dialogs/high_score_info_dialog.cpp @@ -66,6 +66,8 @@ HighScoreInfoDialog::HighScoreInfoDialog(Highscores* highscore, bool is_linear, core::stringw track_name; core::stringw track_type_name; + std::shared_ptr track_manager = TrackManager::get(); + if (m_major_mode == RaceManager::MAJOR_MODE_GRAND_PRIX) { m_gp = *grand_prix_manager->getGrandPrix(m_hs->m_track); @@ -343,7 +345,7 @@ void HighScoreInfoDialog::onUpdate(float dt) m_curr_time = 0; } - Track* track = track_manager->getTrack(tracks[frame_after]); + Track* track = TrackManager::get()->getTrack(tracks[frame_after]); std::string file = track->getScreenshotFile(); m_track_screenshot_widget->setImage(file, IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); m_track_screenshot_widget->m_properties[PROP_ICON] = file; diff --git a/src/states_screens/dialogs/select_challenge.cpp b/src/states_screens/dialogs/select_challenge.cpp index 9c342a4e6b5..fe7ca43c813 100644 --- a/src/states_screens/dialogs/select_challenge.cpp +++ b/src/states_screens/dialogs/select_challenge.cpp @@ -179,7 +179,7 @@ SelectChallengeDialog::SelectChallengeDialog(const float percentWidth, else { const core::stringw track_name = - track_manager->getTrack(c->getData()->getTrackId())->getName(); + TrackManager::get()->getTrack(c->getData()->getTrackId())->getName(); getWidget("title")->setText(track_name, true); } diff --git a/src/states_screens/easter_egg_screen.cpp b/src/states_screens/easter_egg_screen.cpp index 771a21f0d3a..4ef7394ad47 100644 --- a/src/states_screens/easter_egg_screen.cpp +++ b/src/states_screens/easter_egg_screen.cpp @@ -79,7 +79,7 @@ void EasterEggScreen::eventCallback(Widget* widget, const std::string& name, con std::string track = m_random_track_list.front(); m_random_track_list.pop_front(); m_random_track_list.push_back(track); - Track* clicked_track = track_manager->getTrack( track ); + Track* clicked_track = TrackManager::get()->getTrack( track ); if (clicked_track != NULL) @@ -95,7 +95,7 @@ void EasterEggScreen::eventCallback(Widget* widget, const std::string& name, con } else if (selection != RibbonWidget::NO_ITEM_ID) { - Track* clicked_track = track_manager->getTrack(selection); + Track* clicked_track = TrackManager::get()->getTrack(selection); if (clicked_track != NULL) { TrackInfoScreen::getInstance()->setTrack(clicked_track); @@ -121,6 +121,8 @@ void EasterEggScreen::eventCallback(Widget* widget, const std::string& name, con void EasterEggScreen::beforeAddingWidget() { + std::shared_ptr track_manager = TrackManager::get(); + // Add user-defined group to track groups track_manager->setFavoriteTrackStatus(PlayerManager::getCurrentPlayer()->getFavoriteTrackStatus()); @@ -204,6 +206,8 @@ void EasterEggScreen::init() void EasterEggScreen::buildTrackList() { + std::shared_ptr track_manager = TrackManager::get(); + // Add user-defined group to track groups track_manager->setFavoriteTrackStatus(PlayerManager::getCurrentPlayer()->getFavoriteTrackStatus()); @@ -243,7 +247,7 @@ void EasterEggScreen::buildTrackList() const std::vector& curr_group = track_manager->getTracksInGroup( curr_group_name ); const int trackAmount = (int)curr_group.size(); - for (int n=0; ngetTrack( curr_group[n] ); if(RaceManager::get()->getMinorMode()==RaceManager::MINOR_MODE_EASTER_EGG diff --git a/src/states_screens/edit_gp_screen.cpp b/src/states_screens/edit_gp_screen.cpp index aaffcbad333..5aa78f4cb1f 100644 --- a/src/states_screens/edit_gp_screen.cpp +++ b/src/states_screens/edit_gp_screen.cpp @@ -241,7 +241,7 @@ void EditGPScreen::loadList(const int selected) { std::vector row; - Track* t = track_manager->getTrack(m_gp->getTrackId(i)); + Track* t = TrackManager::get()->getTrack(m_gp->getTrackId(i)); assert(t != NULL); video::ITexture* screenShot = irr_driver->getTexture(t->getScreenshotFile()); @@ -308,7 +308,7 @@ void EditGPScreen::edit() if (m_selected >= 0 && m_selected < m_list->getItemCount()) { - edit_screen->setSelection(track_manager->getTrack( + edit_screen->setSelection(TrackManager::get()->getTrack( m_gp->getTrackId(m_selected)), m_gp->getLaps((unsigned int)m_selected), m_gp->getReverse((unsigned int)m_selected)); diff --git a/src/states_screens/edit_track_screen.cpp b/src/states_screens/edit_track_screen.cpp index 356bdc77937..7a26e15999c 100644 --- a/src/states_screens/edit_track_screen.cpp +++ b/src/states_screens/edit_track_screen.cpp @@ -93,7 +93,7 @@ void EditTrackScreen::loadedFromFile() assert(tracks_widget != NULL); tracks_widget->setMaxLabelLength(MAX_LABEL_LENGTH); // Avoid too many items shown at the same time - tracks_widget->setItemCountHint(std::min((int)track_manager->getNumberOfTracks()+1, 30)); + tracks_widget->setItemCountHint(std::min((int)TrackManager::get()->getNumberOfTracks()+1, 30)); m_screenshot = getWidget("screenshot"); m_screenshot->setFocusable(false); @@ -103,6 +103,8 @@ void EditTrackScreen::loadedFromFile() // ----------------------------------------------------------------------------- void EditTrackScreen::beforeAddingWidget() { + std::shared_ptr track_manager = TrackManager::get(); + track_manager->setFavoriteTrackStatus( PlayerManager::getCurrentPlayer()->getFavoriteTrackStatus()); @@ -193,6 +195,8 @@ void EditTrackScreen::eventCallback(GUIEngine::Widget* widget, const std::string // ----------------------------------------------------------------------------- void EditTrackScreen::loadTrackList() { + std::shared_ptr track_manager = TrackManager::get(); + track_manager->setFavoriteTrackStatus( PlayerManager::getCurrentPlayer()->getFavoriteTrackStatus()); @@ -284,7 +288,7 @@ void EditTrackScreen::selectTrack(const std::string& id) ButtonWidget* ok_button = getWidget("ok"); assert(ok_button != NULL); - m_track = track_manager->getTrack(id); + m_track = TrackManager::get()->getTrack(id); ok_button->setActive(m_track!=NULL); if (m_track) { diff --git a/src/states_screens/feature_unlocked.cpp b/src/states_screens/feature_unlocked.cpp index c8ec3260d45..ced123309ac 100644 --- a/src/states_screens/feature_unlocked.cpp +++ b/src/states_screens/feature_unlocked.cpp @@ -223,7 +223,7 @@ void FeatureUnlockedCutScene:: for (unsigned int i = 0; i < tracks.size(); i++) { - addUnlockedTrack(track_manager->getTrack(tracks[i])); + addUnlockedTrack(TrackManager::get()->getTrack(tracks[i])); } for (unsigned int i = 0; i < gps.size(); i++) { @@ -714,9 +714,9 @@ void FeatureUnlockedCutScene::addUnlockedGP(const GrandPrixData* gp) images.push_back(WTF_image); } - for (int t=0; tgetTrack(gptracks[t]); + Track* track = TrackManager::get()->getTrack(gptracks[t]); const std::string t_name = track ? track->getScreenshotFile() diff --git a/src/states_screens/ghost_replay_selection.cpp b/src/states_screens/ghost_replay_selection.cpp index aae51d01f20..bf408af7b7f 100644 --- a/src/states_screens/ghost_replay_selection.cpp +++ b/src/states_screens/ghost_replay_selection.cpp @@ -223,7 +223,7 @@ void GhostReplaySelection::loadList() if (!m_multiplayer && (rd.m_kart_list.size() > 1)) continue; - Track* track = track_manager->getTrack(rd.m_track_name); + Track* track = TrackManager::get()->getTrack(rd.m_track_name); if (track == NULL) continue; @@ -362,7 +362,7 @@ void GhostReplaySelection::loadList() rd.m_minor_mode != "egg-hunt") continue; - Track* track = track_manager->getTrack(rd.m_track_name); + Track* track = TrackManager::get()->getTrack(rd.m_track_name); if (track == NULL) continue; diff --git a/src/states_screens/gp_info_screen.cpp b/src/states_screens/gp_info_screen.cpp index 679b1a121eb..71db9c06c49 100644 --- a/src/states_screens/gp_info_screen.cpp +++ b/src/states_screens/gp_info_screen.cpp @@ -232,7 +232,7 @@ void GPInfoScreen::init() // We have to recreate the group spinner, but a new group might have // been added or deleted since the last time this screen was shown. - const std::vector& groups = track_manager->getAllTrackGroups(); + const std::vector& groups = TrackManager::get()->getAllTrackGroups(); m_group_names.clear(); m_group_names.push_back("all"); // Add "all" group as first group for (unsigned int i = 0; i < groups.size(); i++) // Add rest of groups @@ -317,7 +317,7 @@ void GPInfoScreen::addTracks() list->clear(); for (unsigned int i = 0; i < (unsigned int)tracks.size(); i++) { - const Track *track = track_manager->getTrack(tracks[i]); + const Track *track = TrackManager::get()->getTrack(tracks[i]); std::string s = StringUtils::toString(i); list->addItem(s, track->getName()); } @@ -334,7 +334,7 @@ void GPInfoScreen::addScreenshot() // (but it will be shown if the given icon is not found) screenshot->m_properties[PROP_ICON] = "gui/icons/main_help.png"; - const Track *track = track_manager->getTrack(m_gp.getTrackId(0)); + const Track *track = TrackManager::get()->getTrack(m_gp.getTrackId(0)); video::ITexture* image = STKTexManager::getInstance() ->getTexture(track->getScreenshotFile(), "While loading screenshot for track '%s':", track->getFilename()); @@ -454,7 +454,7 @@ void GPInfoScreen::onUpdate(float dt) m_curr_time = 0; } - Track* track = track_manager->getTrack(tracks[frame_after]); + Track* track = TrackManager::get()->getTrack(tracks[frame_after]); std::string file = track->getScreenshotFile(); GUIEngine::IconButtonWidget* screenshot = getWidget("screenshot"); screenshot->setImage(file, IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); @@ -465,6 +465,8 @@ void GPInfoScreen::onUpdate(float dt) */ int GPInfoScreen::getMaxNumTracks(std::string group) { + std::shared_ptr track_manager = TrackManager::get(); + int max_num_tracks = 0; if (group == "all") diff --git a/src/states_screens/grand_prix_cutscene.cpp b/src/states_screens/grand_prix_cutscene.cpp index 8610bbcd0eb..6da200e4a5f 100644 --- a/src/states_screens/grand_prix_cutscene.cpp +++ b/src/states_screens/grand_prix_cutscene.cpp @@ -55,7 +55,7 @@ void GrandPrixCutscene::setNewGPWithName(const irr::core::stringw& name) std::vector laps = current_gp.getLaps(); std::vector reverse = current_gp.getReverse(); for (unsigned int i = 0; i < laps.size(); i++) - gp->addTrack(track_manager->getTrack(tracks[i]), laps[i], reverse[i]); + gp->addTrack(TrackManager::get()->getTrack(tracks[i]), laps[i], reverse[i]); gp->writeToFile(); // Avoid double-save which can have bad side-effects diff --git a/src/states_screens/grand_prix_editor_screen.cpp b/src/states_screens/grand_prix_editor_screen.cpp index 5b789b81b32..ac58ed58256 100644 --- a/src/states_screens/grand_prix_editor_screen.cpp +++ b/src/states_screens/grand_prix_editor_screen.cpp @@ -198,7 +198,7 @@ void GrandPrixEditorScreen::loadTrackList (const std::string& gpname) tracks_widget->setItemCountHint(std::min((int)tracks.size(), 15)); for (unsigned int t = 0; t < tracks.size(); t++) { - Track* curr = track_manager->getTrack(tracks[t]); + Track* curr = TrackManager::get()->getTrack(tracks[t]); if (curr == NULL) { Log::warn("GrandPrixEditor", @@ -238,7 +238,7 @@ void GrandPrixEditorScreen::loadGPList() std::vector sshot_files; for (unsigned int t=0; tgetTrack(tracks[t]); + Track* track = TrackManager::get()->getTrack(tracks[t]); sshot_files.push_back(track->getScreenshotFile()); } if (sshot_files.empty()) diff --git a/src/states_screens/high_score_selection.cpp b/src/states_screens/high_score_selection.cpp index 1c78630ba5f..b24558a7400 100644 --- a/src/states_screens/high_score_selection.cpp +++ b/src/states_screens/high_score_selection.cpp @@ -224,7 +224,7 @@ void HighScoreSelection::loadList() } else { - Track* track = track_manager->getTrack(hs->m_track); + Track* track = TrackManager::get()->getTrack(hs->m_track); if (track == NULL || hs->getNumberEntries() < 1) continue; diff --git a/src/states_screens/main_menu_screen.cpp b/src/states_screens/main_menu_screen.cpp index ccd4a461383..b60a5665be4 100644 --- a/src/states_screens/main_menu_screen.cpp +++ b/src/states_screens/main_menu_screen.cpp @@ -94,6 +94,8 @@ void MainMenuScreen::loadedFromFile() RibbonWidget* rw_top = getWidget("menu_toprow"); assert(rw_top != NULL); + + std::shared_ptr track_manager = TrackManager::get(); if (track_manager->getTrack("overworld") == NULL || track_manager->getTrack("introcutscene") == NULL || @@ -468,6 +470,8 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name, ((CutsceneWorld*)World::getWorld())->setParts(parts); scene->addTrophy(RaceManager::DIFFICULTY_EASY, false); + + std::shared_ptr track_manager = TrackManager::get(); if (selection == "test_unlocked") { diff --git a/src/states_screens/online/server_selection.cpp b/src/states_screens/online/server_selection.cpp index c83ae94dd00..d9614b3aa2c 100644 --- a/src/states_screens/online/server_selection.cpp +++ b/src/states_screens/online/server_selection.cpp @@ -183,6 +183,8 @@ void ServerSelection::init() file_manager->getAsset(FileManager::GUI_ICON, "hourglass.png")); m_icon_bank->addTextureAsSprite(icon1); m_icon_bank->addTextureAsSprite(icon2); + + std::shared_ptr track_manager = TrackManager::get(); for (unsigned i = 0; i < track_manager->getNumberOfTracks(); i++) { Track* t = track_manager->getTrack(i); @@ -276,7 +278,7 @@ void ServerSelection::loadList() int icon = server->isGameStarted() ? 1 : 0; Track* t = server->getCurrentTrack(); if (t) - icon = track_manager->getTrackIndexByIdent(t->getIdent()) + 2; + icon = TrackManager::get()->getTrackIndexByIdent(t->getIdent()) + 2; core::stringw num_players; int current_players = server->getCurrentPlayers(); int current_ai = server->getCurrentAI(); diff --git a/src/states_screens/online/tracks_screen.cpp b/src/states_screens/online/tracks_screen.cpp index f9aa94d7ab5..61c5fb1eb84 100644 --- a/src/states_screens/online/tracks_screen.cpp +++ b/src/states_screens/online/tracks_screen.cpp @@ -83,7 +83,7 @@ void TracksScreen::eventCallback(Widget* widget, const std::string& name, const PeerVote* host_vote = cl->getVote(host_id); if (host_vote) { - m_selected_track = track_manager->getTrack( + m_selected_track = TrackManager::get()->getTrack( host_vote->m_track_name); if (!m_selected_track) return; @@ -126,7 +126,7 @@ void TracksScreen::eventCallback(Widget* widget, const std::string& name, m_random_track_list.push_back(selection); } // selection=="random_track" - m_selected_track = track_manager->getTrack(selection); + m_selected_track = TrackManager::get()->getTrack(selection); if (m_selected_track) { @@ -219,6 +219,8 @@ void TracksScreen::beforeAddingWidget() { Screen::init(); + std::shared_ptr track_manager = TrackManager::get(); + // Add user-defined group to track groups track_manager->setFavoriteTrackStatus(PlayerManager::getCurrentPlayer()->getFavoriteTrackStatus()); @@ -437,7 +439,7 @@ void TracksScreen::init() assert(cl); for (const std::string& track : cl->getAvailableTracks()) { - Track* t = track_manager->getTrack(track); + Track* t = TrackManager::get()->getTrack(track); if (!t) { Log::fatal("TracksScreen", "Missing network track %s", @@ -462,7 +464,7 @@ void TracksScreen::init() if (vote) { DynamicRibbonWidget* w2 = getWidget("tracks"); - m_selected_track = track_manager->getTrack(vote->m_track_name); + m_selected_track = TrackManager::get()->getTrack(vote->m_track_name); w2->setBadge(vote->m_track_name, OK_BADGE); } @@ -570,6 +572,8 @@ void TracksScreen::init() */ void TracksScreen::buildTrackList() { + std::shared_ptr track_manager = TrackManager::get(); + // Add user-defined group to track groups track_manager->setFavoriteTrackStatus(PlayerManager::getCurrentPlayer()->getFavoriteTrackStatus()); diff --git a/src/states_screens/race_gui_overworld.cpp b/src/states_screens/race_gui_overworld.cpp index f72d6a39635..71e94399719 100644 --- a/src/states_screens/race_gui_overworld.cpp +++ b/src/states_screens/race_gui_overworld.cpp @@ -591,7 +591,7 @@ void RaceGUIOverworld::drawGlobalMiniMap() } else { - Track* track = track_manager->getTrack(challenge->getTrackId()); + Track* track = TrackManager::get()->getTrack(challenge->getTrackId()); if (track == NULL) { Log::error("RaceGUIOverworld", "Cannot find track <%s>, " diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 52efc25fd34..d51ea046213 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -2262,7 +2262,7 @@ void RaceResultGUI::displayScreenShots() int n_sshot = 1; for (int i = m_start_track; i < m_end_track; i++) { - Track* track = track_manager->getTrack(tracks[i]); + Track* track = TrackManager::get()->getTrack(tracks[i]); GUIEngine::IconButtonWidget* sshot = getWidget( ("sshot_" + StringUtils::toString(n_sshot)).c_str()); GUIEngine::LabelWidget* label = getWidget( diff --git a/src/states_screens/track_info_screen.cpp b/src/states_screens/track_info_screen.cpp index aca3e167c44..cbd720f763b 100644 --- a/src/states_screens/track_info_screen.cpp +++ b/src/states_screens/track_info_screen.cpp @@ -42,7 +42,7 @@ #include "race/race_manager.hpp" #include "states_screens/state_manager.hpp" #include "tracks/track.hpp" -#include "tracks/track_manager.hpp" +// #include "tracks/track_manager.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" diff --git a/src/states_screens/tracks_and_gp_screen.cpp b/src/states_screens/tracks_and_gp_screen.cpp index 124002d6ace..cf7e49b8855 100644 --- a/src/states_screens/tracks_and_gp_screen.cpp +++ b/src/states_screens/tracks_and_gp_screen.cpp @@ -84,7 +84,7 @@ void TracksAndGPScreen::eventCallback(Widget* widget, const std::string& name, m_random_track_list.push_back(selection); } // selection=="random_track" - Track *track = track_manager->getTrack(selection); + Track *track = TrackManager::get()->getTrack(selection); if (track) { @@ -155,6 +155,8 @@ void TracksAndGPScreen::eventCallback(Widget* widget, const std::string& name, void TracksAndGPScreen::beforeAddingWidget() { Screen::init(); + + std::shared_ptr track_manager = TrackManager::get(); // Add user-defined group to track groups track_manager->setFavoriteTrackStatus(PlayerManager::getCurrentPlayer()->getFavoriteTrackStatus()); @@ -234,7 +236,7 @@ void TracksAndGPScreen::init() std::vector screenshots; for (unsigned int t=0; tgetTrack(tracks[t]); + const Track* curr = TrackManager::get()->getTrack(tracks[t]); screenshots.push_back(curr->getScreenshotFile()); } assert(screenshots.size() > 0); @@ -281,6 +283,8 @@ void TracksAndGPScreen::init() */ void TracksAndGPScreen::buildTrackList() { + std::shared_ptr track_manager = TrackManager::get(); + // Add user-defined group to track groups track_manager->setFavoriteTrackStatus(PlayerManager::getCurrentPlayer()->getFavoriteTrackStatus()); diff --git a/src/tracks/arena_graph.cpp b/src/tracks/arena_graph.cpp index b64743a42f9..c7eaf00dd30 100644 --- a/src/tracks/arena_graph.cpp +++ b/src/tracks/arena_graph.cpp @@ -392,7 +392,7 @@ std::vector ArenaGraph::getPathFromTo(int from, int to, */ void ArenaGraph::unitTesting() { - Track *track = track_manager->getTrack("cave"); + Track *track = TrackManager::get()->getTrack("cave"); std::string navmesh_file_name=track->getTrackFile("navmesh.xml"); double s = StkTime::getRealTime(); diff --git a/src/tracks/terrain_info.cpp b/src/tracks/terrain_info.cpp index 7e49a7cf2f1..31130ce91fb 100644 --- a/src/tracks/terrain_info.cpp +++ b/src/tracks/terrain_info.cpp @@ -21,7 +21,7 @@ #include "physics/triangle_mesh.hpp" #include "race/race_manager.hpp" #include "tracks/track.hpp" -#include "tracks/track_manager.hpp" +// #include "tracks/track_manager.hpp" #include "tracks/track_object_manager.hpp" #include "utils/constants.hpp" diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 66a595c0c30..93311bf6ef9 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -1465,7 +1465,7 @@ bool Track::loadMainTrack(const XMLNode &root) { if (challenge != "tutorial") { - Track* t = track_manager->getTrack(c->getTrackId()); + Track* t = TrackManager::get()->getTrack(c->getTrackId()); if (t == NULL) { Log::error("track", "Cannot find track named <%s>\n", diff --git a/src/tracks/track_manager.cpp b/src/tracks/track_manager.cpp index 667cc7ad842..142e3e36404 100644 --- a/src/tracks/track_manager.cpp +++ b/src/tracks/track_manager.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -37,7 +38,6 @@ #include #endif -TrackManager* track_manager = 0; std::vector TrackManager::m_track_search_path; /** Constructor (currently empty). The real work happens in loadTrackList. @@ -56,6 +56,13 @@ TrackManager::~TrackManager() delete *i; } // ~TrackManager +//----------------------------------------------------------------------------- +std::shared_ptr TrackManager::get() +{ + static std::shared_ptr instance = std::make_shared(); + return instance; +} // get + //----------------------------------------------------------------------------- void TrackManager::removeTrackSearchDirs() { diff --git a/src/tracks/track_manager.hpp b/src/tracks/track_manager.hpp index cacf421a6af..43cd256ade5 100644 --- a/src/tracks/track_manager.hpp +++ b/src/tracks/track_manager.hpp @@ -24,6 +24,7 @@ #include #include #include +#include class Track; @@ -90,6 +91,8 @@ class TrackManager public: TrackManager(); ~TrackManager(); + + static std::shared_ptr get(); static void removeTrackSearchDirs(); static void addTrackSearchDir(const std::string &dir); @@ -168,6 +171,4 @@ class TrackManager void updateScreenshotCache(); }; // TrackManager -extern TrackManager* track_manager; - #endif // HEADER_TRACK_MANAGER_HPP diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index 789c0d8935b..7d77b33ab8c 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -46,7 +46,7 @@ #include "tracks/check_trigger.hpp" #include "tracks/model_definition_loader.hpp" #include "tracks/track.hpp" -#include "tracks/track_manager.hpp" +// #include "tracks/track_manager.hpp" #include "tracks/track_object_manager.hpp" #include "utils/stk_process.hpp" #include "utils/string_utils.hpp" diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index de40959984b..93b251aef52 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -975,7 +975,7 @@ bool handleContextMenuAction(s32 cmd_id) StringUtils::split(StringUtils::wideToUtf8(text), ' '); for (const std::string& track : parts) { - Track* t = track_manager->getTrack(track); + Track* t = TrackManager::get()->getTrack(track); if (t == NULL) { Log::warn("Debug", "Cutscene %s not found!", diff --git a/src/utils/extract_mobile_assets.cpp b/src/utils/extract_mobile_assets.cpp index f9edea26727..5e1d9262131 100644 --- a/src/utils/extract_mobile_assets.cpp +++ b/src/utils/extract_mobile_assets.cpp @@ -71,7 +71,7 @@ void ExtractMobileAssets::reinit() { file_manager->reinitAfterDownloadAssets(); irr_driver->sameRestart(); - track_manager->loadTrackList(); + TrackManager::get()->loadTrackList(); // Update the replay file list to use latest track pointer ReplayPlay::get()->loadAllReplayFile(); diff --git a/src/utils/hit_processor.cpp b/src/utils/hit_processor.cpp index d14076f152c..794eeec6126 100644 --- a/src/utils/hit_processor.cpp +++ b/src/utils/hit_processor.cpp @@ -24,10 +24,13 @@ #include "utils/string_utils.hpp" #include "karts/kart_properties.hpp" #include "network/protocols/server_lobby.hpp" +#include "utils/lobby_settings.hpp" -HitProcessor::HitProcessor(ServerLobby* lobby): m_lobby(lobby) +HitProcessor::HitProcessor(ServerLobby* lobby, std::shared_ptr settings) + : m_lobby(lobby), m_lobby_settings(settings) { + m_troll_active = ServerConfig::m_troll_active; m_show_teammate_hits = ServerConfig::m_show_teammate_hits; m_teammate_hit_mode = ServerConfig::m_teammate_hit_mode; m_last_teammate_hit_msg = 0; @@ -42,33 +45,33 @@ HitProcessor::HitProcessor(ServerLobby* lobby): m_lobby(lobby) // this is called when collisions of an item are handled // so we keep track of hits caused by that item -void HitProcessor::setTeamMateHitOwner(unsigned int ownerID, uint16_t ticks_since_thrown) +void HitProcessor::setTeammateHitOwner(unsigned int ownerID, uint16_t ticks_since_thrown) { m_teammate_current_item_ownerID = ownerID; m_teammate_ticks_since_thrown = ticks_since_thrown; m_teammate_karts_hit.clear(); m_teammate_karts_exploded.clear(); m_collecting_teammate_hit_info = true; -} // setTeamMateHitOwner +} // setTeammateHitOwner //----------------------------------------------------------------------------- -void HitProcessor::registerTeamMateHit(unsigned int kartID) +void HitProcessor::registerTeammateHit(unsigned int kartID) { // only register if we know the item owner and victim is still racing if (m_collecting_teammate_hit_info && !World::getWorld()->getKart(kartID)->hasFinishedRace()) m_teammate_karts_hit.push_back(kartID); -} // registerTeamMateHit +} // registerTeammateHit //----------------------------------------------------------------------------- -void HitProcessor::registerTeamMateExplode(unsigned int kartID) +void HitProcessor::registerTeammateExplode(unsigned int kartID) { // only register if we know the item owner and victim is still racing if (m_collecting_teammate_hit_info && !World::getWorld()->getKart(kartID)->hasFinishedRace()) m_teammate_karts_exploded.push_back(kartID); -} // registerTeamMateExplode +} // registerTeammateExplode //----------------------------------------------------------------------------- -void HitProcessor::sendTeamMateHitMsg(std::string& s) +void HitProcessor::sendTeammateHitMsg(std::string& s) { if (World* w = World::getWorld()) { @@ -79,16 +82,16 @@ void HitProcessor::sendTeamMateHitMsg(std::string& s) m_lobby->sendStringToAllPeers(s); } } -} // sendTeamMateHitMsg +} // sendTeammateHitMsg //----------------------------------------------------------------------------- -void HitProcessor::handleTeamMateHits() +void HitProcessor::handleTeammateHits() { m_collecting_teammate_hit_info = false; // get team of owner of item const std::string owner_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(m_teammate_current_item_ownerID).getPlayerName()); - const int owner_team = m_lobby->getTeamForUsername(owner_name); + const int owner_team = m_lobby_settings->getTeamForUsername(owner_name); if (owner_team == 0) // no team, no punishment return; @@ -116,7 +119,7 @@ void HitProcessor::handleTeamMateHits() { const std::string playername = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); - const int playerTeam = m_lobby->getTeamForUsername(playername); + const int playerTeam = m_lobby_settings->getTeamForUsername(playername); if (owner_team == playerTeam) { // hit teammate @@ -130,7 +133,7 @@ void HitProcessor::handleTeamMateHits() { msg += (num_victims > 1) ? "teammates " : "teammate "; msg += victims; - sendTeamMateHitMsg(msg); + sendTeammateHitMsg(msg); } } @@ -142,7 +145,7 @@ void HitProcessor::handleTeamMateHits() { const std::string playername = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); - const int playerTeam = m_lobby->getTeamForUsername(playername); + const int playerTeam = m_lobby_settings->getTeamForUsername(playername); if (owner_team == playerTeam) { // we did, so punish @@ -178,7 +181,7 @@ void HitProcessor::handleTeamMateHits() { const std::string playername = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(m_teammate_karts_hit[i]).getPlayerName()); - const int playerTeam = m_lobby->getTeamForUsername(playername); + const int playerTeam = m_lobby_settings->getTeamForUsername(playername); if (owner_team == playerTeam) { // we did, so punish @@ -210,7 +213,7 @@ void HitProcessor::handleTeamMateHits() } } } -} // handleTeamMateHits +} // handleTeammateHits //----------------------------------------------------------------------------- void HitProcessor::handleSwatterHit(unsigned int ownerID, unsigned int victimID, @@ -218,13 +221,13 @@ void HitProcessor::handleSwatterHit(unsigned int ownerID, unsigned int victimID, { const std::string owner_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(ownerID).getPlayerName()); - const int owner_team = m_lobby->getTeamForUsername(owner_name); + const int owner_team = m_lobby_settings->getTeamForUsername(owner_name); if (owner_team == 0) return; const std::string victim_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(victimID).getPlayerName()); - const int victim_team = m_lobby->getTeamForUsername(victim_name); + const int victim_team = m_lobby_settings->getTeamForUsername(victim_name); if (victim_team != owner_team) return; @@ -237,7 +240,7 @@ void HitProcessor::handleSwatterHit(unsigned int ownerID, unsigned int victimID, owner_name.c_str(), victim_name.c_str() ); - sendTeamMateHitMsg(msg); + sendTeammateHitMsg(msg); } if (isTeammateHitMode()) { @@ -257,13 +260,13 @@ void HitProcessor::handleAnvilHit(unsigned int ownerID, unsigned int victimID) { const std::string owner_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(ownerID).getPlayerName()); - const int owner_team = m_lobby->getTeamForUsername(owner_name); + const int owner_team = m_lobby_settings->getTeamForUsername(owner_name); if (owner_team == 0) return; const std::string victim_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(victimID).getPlayerName()); - const int victim_team = m_lobby->getTeamForUsername(victim_name); + const int victim_team = m_lobby_settings->getTeamForUsername(victim_name); if (victim_team != owner_team) return; @@ -278,7 +281,7 @@ void HitProcessor::handleAnvilHit(unsigned int ownerID, unsigned int victimID) owner_name.c_str(), victim_name.c_str() ); - sendTeamMateHitMsg(msg); + sendTeammateHitMsg(msg); } if (isTeammateHitMode()) { diff --git a/src/utils/hit_processor.hpp b/src/utils/hit_processor.hpp index a98da95f4ec..b228a52bd07 100644 --- a/src/utils/hit_processor.hpp +++ b/src/utils/hit_processor.hpp @@ -23,8 +23,10 @@ #include #include +#include class AbstractKart; class ServerLobby; +class LobbySettings; // A class that incapsulates most of the logic for processing kart hits. // Contains the code originally written by Heuchi1, but it's moved to a @@ -33,10 +35,13 @@ class ServerLobby; class HitProcessor { public: - HitProcessor(ServerLobby* lobby); + HitProcessor(ServerLobby* lobby, std::shared_ptr settings); private: ServerLobby* m_lobby = nullptr; + std::shared_ptr m_lobby_settings; + + bool m_troll_active; bool m_show_teammate_hits; // Whether to show messages about team hits. bool m_teammate_hit_mode; // Whether to anvil the team hitters. @@ -61,22 +66,21 @@ class HitProcessor const float MAX_BOWL_TEAMMATE_HIT_TIME = 2.0f; public: - // handle cakes and bowls - bool isTeammateHitMode() const { return m_teammate_hit_mode; } - bool showTeammateHits() const { return m_show_teammate_hits; } - void setTeammateHitMode(bool value) { m_teammate_hit_mode = value; } - void setShowTeammateHits(bool value) { m_show_teammate_hits = value; } - void setTeamMateHitOwner(unsigned int ownerID, uint16_t ticks_since_thrown = 0); - void registerTeamMateHit(unsigned int kartID); - void registerTeamMateExplode(unsigned int kartID); - void handleTeamMateHits(); + bool isAntiTrollActive() const { return m_troll_active; } + bool isTeammateHitMode() const { return m_teammate_hit_mode; } + bool showTeammateHits() const { return m_show_teammate_hits; } + void setAntiTroll(bool value) { m_troll_active = value; } + void setTeammateHitMode(bool value) { m_teammate_hit_mode = value; } + void setShowTeammateHits(bool value) { m_show_teammate_hits = value; } + void setTeammateHitOwner(unsigned int ownerID, uint16_t ticks_since_thrown = 0); + void registerTeammateHit(unsigned int kartID); + void registerTeammateExplode(unsigned int kartID); + void handleTeammateHits(); - // handle swatters void handleSwatterHit(unsigned int ownerID, unsigned int victimID, bool success, bool has_hit_kart, uint16_t ticks_active); - // handle anvil void handleAnvilHit(unsigned int ownerID, unsigned int victimID); - void sendTeamMateHitMsg(std::string& s); + void sendTeammateHitMsg(std::string& s); void punishSwatterHits(); void resetLastHits() { m_last_teammate_hit_msg = 0; } }; diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp index c002d5020cf..f80893b3ca8 100644 --- a/src/utils/lobby_asset_manager.cpp +++ b/src/utils/lobby_asset_manager.cpp @@ -32,12 +32,14 @@ LobbyAssetManager::LobbyAssetManager(ServerLobby* lobby): m_lobby(lobby) { - + init(); + updateAddons(); } // LobbyAssetManager // ======================================================================== void LobbyAssetManager::init() { + std::shared_ptr track_manager = TrackManager::get(); std::vector all_k = kart_properties_manager->getKartsInGroup("standard"); @@ -62,6 +64,8 @@ void LobbyAssetManager::init() void LobbyAssetManager::updateAddons() { + std::shared_ptr track_manager = TrackManager::get(); + m_addon_kts.first.clear(); m_addon_kts.second.clear(); m_addon_arenas.clear(); @@ -125,6 +129,8 @@ void LobbyAssetManager::updateAddons() */ void LobbyAssetManager::updateMapsForMode(RaceManager::MinorRaceModeType mode) { + std::shared_ptr track_manager = TrackManager::get(); + auto all_t = track_manager->getAllTrackIdentifiers(); if (all_t.size() >= 65536) all_t.resize(65535); @@ -138,7 +144,7 @@ void LobbyAssetManager::updateMapsForMode(RaceManager::MinorRaceModeType mode) auto it = m_available_kts.second.begin(); while (it != m_available_kts.second.end()) { - Track* t = track_manager->getTrack(*it); + Track* t = track_manager->getTrack(*it); if (t->isArena() || t->isSoccer() || t->isInternal()) { it = m_available_kts.second.erase(it); @@ -154,7 +160,7 @@ void LobbyAssetManager::updateMapsForMode(RaceManager::MinorRaceModeType mode) auto it = m_available_kts.second.begin(); while (it != m_available_kts.second.end()) { - Track* t = track_manager->getTrack(*it); + Track* t = track_manager->getTrack(*it); if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) { @@ -182,7 +188,7 @@ void LobbyAssetManager::updateMapsForMode(RaceManager::MinorRaceModeType mode) auto it = m_available_kts.second.begin(); while (it != m_available_kts.second.end()) { - Track* t = track_manager->getTrack(*it); + Track* t = track_manager->getTrack(*it); if (!t->isSoccer() || t->isInternal()) { it = m_available_kts.second.erase(it); @@ -560,7 +566,7 @@ std::string LobbyAssetManager::getRandomAddonMap() const { std::set items; for (const std::string& s: m_entering_kts.second) { - Track* t = track_manager->getTrack(s); + Track* t = TrackManager::get()->getTrack(s); if (t->isAddon()) items.insert(s); } diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp new file mode 100644 index 00000000000..fa23e3224b3 --- /dev/null +++ b/src/utils/lobby_settings.cpp @@ -0,0 +1,803 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/lobby_settings.hpp" + +#include "modes/soccer_world.hpp" +#include "modes/world.hpp" +#include "network/game_setup.hpp" +#include "network/game_setup.hpp" +#include "network/network_string.hpp" +#include "network/peer_vote.hpp" +#include "network/server_config.hpp" +#include "network/stk_peer.hpp" +#include "tracks/track_manager.hpp" +#include "utils/game_info.hpp" +#include "utils/kart_elimination.hpp" +#include "utils/lobby_asset_manager.hpp" +#include "utils/lobby_queues.hpp" +#include "utils/random_generator.hpp" +#include "utils/string_utils.hpp" +#include "tracks/track.hpp" +#include "utils/tournament.hpp" + +LobbySettings::LobbySettings(GameSetup* game_setup, + std::shared_ptr queues, + std::shared_ptr elim, + std::shared_ptr asset_manager, + std::shared_ptr tournament) + : m_game_setup(game_setup) + , m_lobby_queues(queues) + , m_kart_elimination(elim) + , m_asset_manager(asset_manager) + , m_tournament(tournament) +{ + m_motd = StringUtils::wideToUtf8( + m_game_setup->readOrLoadFromFile( + (std::string) ServerConfig::m_motd + ) + ); + m_help_message = StringUtils::wideToUtf8( + m_game_setup->readOrLoadFromFile( + (std::string) ServerConfig::m_help + ) + ); + m_shuffle_gp = ServerConfig::m_shuffle_gp; + m_consent_on_replays = false; + + m_fixed_direction = ServerConfig::m_fixed_direction; + + setDefaultLapRestrictions(); + + m_available_teams = ServerConfig::m_init_available_teams; + m_default_vote = new PeerVote(); + m_allowed_to_start = ServerConfig::m_allowed_to_start; + + initCategories(); + initAvailableModes(); + initAvailableTracks(); + std::string scoring = ServerConfig::m_gp_scoring; + loadCustomScoring(scoring); + loadWhiteList(); + loadPreservedSettings(); + + // The following was called in SL::setup, I doubt it's any different + // but just in case + + m_battle_hit_capture_limit = 0; + m_battle_time_limit = 0.0f; + m_winner_peer_id = 0; +} // LobbySettings +// ======================================================================== + +LobbySettings::~LobbySettings() +{ + delete m_default_vote; +} + +void LobbySettings::initCategories() +{ + std::vector tokens = StringUtils::split( + ServerConfig::m_categories, ' '); + std::string category = ""; + bool isTeam = false; + for (std::string& s: tokens) + { + if (s.empty()) + continue; + else if (s[0] == '#') + { + isTeam = false; + if (s.length() > 1 && s[1] == '#') + { + category = s.substr(2); + m_hidden_categories.insert(category); + } + else + category = s.substr(1); + } + else if (s[0] == '$') + { + isTeam = true; + category = s.substr(1); + } + else + { + if (!isTeam) { + m_player_categories[category].insert(s); + m_categories_for_player[s].insert(category); + } + else + { + m_team_for_player[s] = category[0] - '0' + 1; + } + } + } +} // initCategories +//----------------------------------------------------------------------------- +void LobbySettings::initAvailableModes() +{ + std::vector statements = + StringUtils::split(ServerConfig::m_available_modes, ' ', false); + + for (const std::string& s: statements) + { + if (s.length() <= 1) + continue; + bool difficulty = s[0] == 'd'; + if (difficulty) + { + for (unsigned i = 1; i < s.length(); i++) + { + m_available_difficulties.insert(s[i] - '0'); + } + } + else + { + for (unsigned i = 1; i < s.length(); i++) + { + m_available_modes.insert(s[i] - '0'); + } + } + } +} // initAvailableModes +//----------------------------------------------------------------------------- + +void LobbySettings::initAvailableTracks() +{ + m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); + m_global_karts_filter = KartFilter(ServerConfig::m_only_played_karts_string); + m_asset_manager->setMustHaveMaps(ServerConfig::m_must_have_tracks_string); + m_play_requirement_tracks = StringUtils::split( + ServerConfig::m_play_requirement_tracks_string, ' ', false); +} // initAvailableTracks +//----------------------------------------------------------------------------- + +bool LobbySettings::loadCustomScoring(std::string& scoring) +{ + std::set available_scoring_types = { + "standard", "default", "", "inc", "fixed", "linear-gap", "exp-gap" + }; + auto previous_params = m_scoring_int_params; + auto previous_type = m_scoring_type; + m_scoring_int_params.clear(); + m_scoring_type = ""; + if (!scoring.empty()) + { + std::vector params = StringUtils::split(scoring, ' '); + if (params.empty()) + { + m_scoring_type = ""; + return true; + } + m_scoring_type = params[0]; + if (available_scoring_types.count(m_scoring_type) == 0) + { + Log::warn("ServerLobby", "Unknown scoring type %s, fallback.", m_scoring_type.c_str()); + m_scoring_int_params = previous_params; + m_scoring_type = previous_type; + return false; + } + for (unsigned i = 1; i < params.size(); i++) + { + int param; + if (!StringUtils::fromString(params[i], param)) + { + Log::warn("ServerLobby", "Unable to parse integer from custom scoring data, fallback."); + m_scoring_int_params = previous_params; + m_scoring_type = previous_type; + return false; + } + m_scoring_int_params.push_back(param); + } + } + return true; +} // loadCustomScoring +//----------------------------------------------------------------------------- + +void LobbySettings::loadWhiteList() +{ + std::vector tokens = StringUtils::split( + ServerConfig::m_white_list, ' '); + for (std::string& s: tokens) + m_usernames_white_list.insert(s); +} // loadWhiteList +//----------------------------------------------------------------------------- +void LobbySettings::loadPreservedSettings() +{ + std::vector what_to_preserve = + StringUtils::split(std::string(ServerConfig::m_preserve_on_reset), ' '); + for (std::string& str: what_to_preserve) + m_preserve.insert(str); +} // loadWhiteList +//----------------------------------------------------------------------------- + +void LobbySettings::addMutedPlayerFor(std::shared_ptr peer, const irr::core::stringw& name) +{ + m_peers_muted_players[std::weak_ptr(peer)].insert(name); +} + +bool LobbySettings::removeMutedPlayerFor(std::shared_ptr peer, const irr::core::stringw& name) +{ + // I'm not sure why the implementation was so long + auto& collection = m_peers_muted_players[std::weak_ptr(peer)]; + for (auto it = collection.begin(); it != collection.end(); ) + { + if (*it == name) + { + it = collection.erase(it); + return true; + } + else + it++; + } + return false; +} + +bool LobbySettings::isMuting(std::shared_ptr peer, const irr::core::stringw& name) const +{ + auto it = m_peers_muted_players.find(std::weak_ptr(peer)); + if (it == m_peers_muted_players.end()) + return false; + + return it->second.find(name) != it->second.end(); +} + +std::string LobbySettings::getMutedPlayersAsString(std::shared_ptr peer) +{ + std::string response; + int num_players = 0; + for (auto& name : m_peers_muted_players[std::weak_ptr(peer)]) + { + response += StringUtils::wideToUtf8(name); + response += " "; + ++num_players; + } + if (num_players == 0) + response = "No player has been muted by you"; + else + { + response += (num_players == 1 ? "is" : "are"); + response += StringUtils::insertValues(" muted (total: %s)", num_players); + } + return response; +} + +void LobbySettings::addTeamSpeaker(std::shared_ptr peer) +{ + m_team_speakers.insert(peer); +} + +void LobbySettings::setMessageReceiversFor(std::shared_ptr peer, + const std::vector& receivers) +{ + auto& thing = m_message_receivers[peer]; + thing.clear(); + for (unsigned i = 0; i < receivers.size(); ++i) + thing.insert(StringUtils::utf8ToWide(receivers[i])); +} + +std::set LobbySettings::getMessageReceiversFor(std::shared_ptr peer) const +{ + auto it = m_message_receivers.find(peer); + if (it == m_message_receivers.end()) + return {}; + + return it->second; +} + +bool LobbySettings::isTeamSpeaker(std::shared_ptr peer) const +{ + return m_team_speakers.find(peer) != m_team_speakers.end(); +} + +void LobbySettings::makeChatPublicFor(std::shared_ptr peer) +{ + m_message_receivers[peer].clear(); + m_team_speakers.erase(peer); +} + +bool LobbySettings::hasNoLapRestrictions() const +{ + return m_default_lap_multiplier < 0. && m_fixed_lap < 0; +} + +bool LobbySettings::hasMultiplier() const +{ + return m_default_lap_multiplier >= 0.; +} + +bool LobbySettings::hasFixedLapCount() const +{ + return m_fixed_lap >= 0; +} + +int LobbySettings::getMultiplier() const +{ + return m_default_lap_multiplier; +} + +int LobbySettings::getFixedLapCount() const +{ + return m_fixed_lap; +} + +void LobbySettings::setMultiplier(int new_value) +{ + m_default_lap_multiplier = new_value; + m_fixed_lap = -1; +} + +void LobbySettings::setFixedLapCount(int new_value) +{ + m_fixed_lap = new_value; + m_default_lap_multiplier = -1; +} + +void LobbySettings::resetLapRestrictions() +{ + m_default_lap_multiplier = -1; + m_fixed_lap = -1; +} + +void LobbySettings::setDefaultLapRestrictions() +{ + m_default_lap_multiplier = ServerConfig::m_auto_game_time_ratio; + m_fixed_lap = ServerConfig::m_fixed_lap_count; +} + +std::string LobbySettings::getLapRestrictionsAsString() const +{ + if (hasNoLapRestrictions()) + return "Game length is currently chosen by players"; + + if (hasMultiplier()) + return StringUtils::insertValues( + "Game length is %f x default", + getMultiplier()); + + if (hasFixedLapCount() > 0) + return StringUtils::insertValues( + "Game length is %d", getFixedLapCount()); + + return StringUtils::insertValues( + "An error: game length is both %f x default and %d", + m_default_lap_multiplier, m_fixed_lap); +} + +std::string LobbySettings::getDirectionAsString(bool just_edited) const +{ + std::string msg = "Direction is "; + if (just_edited) + msg += "now "; + if (m_fixed_direction == -1) + msg += "chosen ingame"; + else + { + msg += "set to "; + msg += (m_fixed_direction == 0 ? "forward" : "reverse"); + } + return msg; +} + +bool LobbySettings::setDirection(int x) +{ + if (x < -1 || x > 1) + return false; + + m_fixed_direction = x; + return true; +} + +bool LobbySettings::hasFixedDirection() const +{ + return m_fixed_direction != -1; +} + +int LobbySettings::getDirection() const +{ + return m_fixed_direction; +} + +bool LobbySettings::isAllowedToStart() const +{ + return m_allowed_to_start; +} + +void LobbySettings::setAllowedToStart(bool value) +{ + m_allowed_to_start = value; +} + +std::string LobbySettings::getAllowedToStartAsString(bool just_edited) const +{ + std::string prefix = (just_edited ? "Now s" : "S"); + prefix += "tarting the game is "; + if (isAllowedToStart()) + return prefix + "allowed"; + else + return prefix + "forbidden"; +} + +bool LobbySettings::isGPGridShuffled() const +{ + return m_shuffle_gp; +} + +void LobbySettings::setGPGridShuffled(bool value) +{ + m_shuffle_gp = value; +} + +std::string LobbySettings::getWhetherShuffledGPGridAsString(bool just_edited) const +{ + std::string prefix = "The GP grid is "; + prefix += (just_edited ? "now " : ""); + if (m_shuffle_gp) + return prefix + "sorted by score"; + else + return prefix + "shuffled"; +} + +std::vector LobbySettings::getMissingAssets(std::shared_ptr peer) const +{ + if (m_play_requirement_tracks.empty()) + return {}; + + std::vector ans; + for (const std::string& required_track : m_play_requirement_tracks) + if (peer->getClientAssets().second.count(required_track) == 0) + ans.push_back(required_track); + return ans; +} // getMissingAssets +//----------------------------------------------------------------------------- + +void LobbySettings::updateWorldSettings(std::shared_ptr game_info) +{ + World::getWorld()->setGameInfo(game_info); + WorldWithRank *wwr = dynamic_cast(World::getWorld()); + if (wwr) + { + wwr->setCustomScoringSystem(m_scoring_type, m_scoring_int_params); + } + SoccerWorld *sw = dynamic_cast(World::getWorld()); + if (sw) + { + std::string policy = ServerConfig::m_soccer_goals_policy; + if (policy == "standard") + sw->setGoalScoringPolicy(0); + else if (policy == "no-own-goals") + sw->setGoalScoringPolicy(1); + else if (policy == "advanced") + sw->setGoalScoringPolicy(2); + else + Log::warn("LobbySettings", "Soccer goals policy %s does not exist", policy.c_str()); + } +} // updateWorldSettings +//----------------------------------------------------------------------------- + +void LobbySettings::onResetToDefaultSettings() +{ + m_lobby_queues->resetToDefaultSettings(m_preserve); + + if (!m_preserve.count("elim")) + m_kart_elimination->disable(); + + if (!m_preserve.count("laps")) + { + // Note that we don't reset restrictions, but set them to those in config + setDefaultLapRestrictions(); + } + + if (!m_preserve.count("direction")) + m_fixed_direction = ServerConfig::m_fixed_direction; + + if (!m_preserve.count("replay")) + setConsentOnReplays(false); +} // onResetToDefaultSettings + +bool LobbySettings::isPreservingMode() const +{ + return m_preserve.find("mode") != m_preserve.end(); +} + +std::string LobbySettings::getScoringAsString() const +{ + std::string msg = "Current scoring is \"" + m_scoring_type; + for (int param: m_scoring_int_params) + msg += StringUtils::insertValues(" %d", param); + msg += "\""; + return msg; +} + +void LobbySettings::addPlayerToCategory(const std::string& player, const std::string& category) +{ + m_player_categories[category].insert(player); + m_categories_for_player[player].insert(category); +} + +void LobbySettings::erasePlayerFromCategory(const std::string& player, const std::string& category) +{ + m_player_categories[category].erase(player); + m_categories_for_player[player].erase(category); +} + +void LobbySettings::makeCategoryVisible(const std::string category, bool value) +{ + if (value) { + m_hidden_categories.erase(category); + } else { + m_hidden_categories.insert(category); + } +} + +bool LobbySettings::isCategoryVisible(const std::string category) const +{ + return m_hidden_categories.find(category) == m_hidden_categories.end(); +} + +std::vector LobbySettings::getVisibleCategoriesForPlayer(const std::string& profile_name) const +{ + auto it = m_categories_for_player.find(profile_name); + if (it == m_categories_for_player.end()) + return {}; + + std::vector res; + for (const std::string& category: it->second) + if (isCategoryVisible(category)) + res.push_back(category); + + return res; +} + + +std::set LobbySettings::getPlayersInCategory(const std::string& category) const +{ + auto it = m_player_categories.find(category); + if (it == m_player_categories.end()) + return {}; + + return it->second; +} + +std::string LobbySettings::getPreservedSettingsAsString() const +{ + std::string msg = "Preserved settings:"; + for (const std::string& str: m_preserve) + msg += " " + str; + return msg; +} + +void LobbySettings::eraseFromPreserved(const std::string& value) +{ + m_preserve.erase(value); +} + +void LobbySettings::insertIntoPreserved(const std::string& value) +{ + m_preserve.insert(value); +} + +void LobbySettings::clearAllExpiredWeakPtrs() +{ + for (auto it = m_peers_muted_players.begin(); + it != m_peers_muted_players.end();) + { + if (it->first.expired()) + it = m_peers_muted_players.erase(it); + else + it++; + } +} + +void LobbySettings::initializeDefaultVote() +{ + m_default_vote->m_track_name = m_asset_manager->getRandomAvailableMap(); + RandomGenerator rg; + switch (RaceManager::get()->getMinorMode()) + { + case RaceManager::MINOR_MODE_NORMAL_RACE: + case RaceManager::MINOR_MODE_TIME_TRIAL: + case RaceManager::MINOR_MODE_FOLLOW_LEADER: + { + Track* t = TrackManager::get()->getTrack(m_default_vote->m_track_name); + assert(t); + m_default_vote->m_num_laps = t->getDefaultNumberOfLaps(); + if (ServerConfig::m_auto_game_time_ratio > 0.0f) + { + m_default_vote->m_num_laps = + (uint8_t)(fmaxf(1.0f, (float)t->getDefaultNumberOfLaps() * + ServerConfig::m_auto_game_time_ratio)); + } + else if (hasFixedLapCount()) + m_default_vote->m_num_laps = getFixedLapCount(); + m_default_vote->m_reverse = rg.get(2) == 0; + + if (hasFixedDirection()) + m_default_vote->m_reverse = (getDirection() == 1); + break; + } + case RaceManager::MINOR_MODE_FREE_FOR_ALL: + { + m_default_vote->m_num_laps = 0; + m_default_vote->m_reverse = rg.get(2) == 0; + break; + } + case RaceManager::MINOR_MODE_CAPTURE_THE_FLAG: + { + m_default_vote->m_num_laps = 0; + m_default_vote->m_reverse = 0; + break; + } + case RaceManager::MINOR_MODE_SOCCER: + { + if (m_tournament) + { + m_tournament->applyRestrictionsOnDefaultVote(m_default_vote); + } + else + { + if (m_game_setup->isSoccerGoalTarget()) + { + m_default_vote->m_num_laps = + (uint8_t)(UserConfigParams::m_num_goals); + if (m_default_vote->m_num_laps > 10) + m_default_vote->m_num_laps = (uint8_t)5; + } + else + { + m_default_vote->m_num_laps = + (uint8_t)(UserConfigParams::m_soccer_time_limit); + if (m_default_vote->m_num_laps > 15) + m_default_vote->m_num_laps = (uint8_t)7; + } + m_default_vote->m_reverse = rg.get(2) == 0; + } + break; + } + default: + assert(false); + break; + } +} + +void LobbySettings::applyGlobalFilter(FilterContext& map_context) const +{ + m_global_filter.apply(map_context); +} + +void LobbySettings::applyGlobalKartsFilter(FilterContext& kart_context) const +{ + m_global_karts_filter.apply(kart_context); +} + +void LobbySettings::applyRestrictionsOnVote(PeerVote* vote, Track* t) const +{ + if (RaceManager::get()->modeHasLaps()) + { + if (hasMultiplier()) + { + vote->m_num_laps = + (uint8_t)(fmaxf(1.0f, (float)t->getDefaultNumberOfLaps() * + getMultiplier())); + } + else if (vote->m_num_laps == 0 || vote->m_num_laps > 20) + vote->m_num_laps = (uint8_t)3; + if (!t->reverseAvailable() && vote->m_reverse) + vote->m_reverse = false; + } + else if (RaceManager::get()->isSoccerMode()) + { + if (m_game_setup->isSoccerGoalTarget()) + { + if (hasMultiplier()) + { + vote->m_num_laps = (uint8_t)(getMultiplier() * + UserConfigParams::m_num_goals); + } + else if (vote->m_num_laps > 10) + vote->m_num_laps = (uint8_t)5; + } + else + { + if (hasMultiplier()) + { + vote->m_num_laps = (uint8_t)(getMultiplier() * + UserConfigParams::m_soccer_time_limit); + } + else if (vote->m_num_laps > 15) + vote->m_num_laps = (uint8_t)7; + } + } + else if (RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_FREE_FOR_ALL) + { + vote->m_num_laps = 0; + } + else if (RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) + { + vote->m_num_laps = 0; + vote->m_reverse = false; + } + if (hasFixedLapCount()) + { + vote->m_num_laps = getFixedLapCount(); + } + if (hasFixedDirection()) + vote->m_reverse = (getDirection() == 1); +} + +void LobbySettings::encodeDefaultVote(NetworkString* ns) const +{ + ns->addUInt32(m_winner_peer_id); + m_default_vote->encode(ns); +} + + +void LobbySettings::setDefaultVote(PeerVote winner_vote) +{ + *m_default_vote = winner_vote; +} + +PeerVote LobbySettings::getDefaultVote() const +{ + return *m_default_vote; +} + + +void LobbySettings::onPeerDisconnect(std::shared_ptr peer) +{ + m_message_receivers.erase(peer); +} + +bool LobbySettings::isInWhitelist(const std::string& username) const +{ + return m_usernames_white_list.find(username) != m_usernames_white_list.end(); +} + + +bool LobbySettings::isModeAvailable(int mode) const +{ + return m_available_modes.find(mode) != m_available_modes.end(); +} + +bool LobbySettings::isDifficultyAvailable(int difficulty) const +{ + return m_available_difficulties.find(difficulty) != m_available_difficulties.end(); +} + +void LobbySettings::applyPermutationToTeams(const std::map& permutation) +{ + for (auto& p: m_team_for_player) + { + auto it = permutation.find(p.second); + if (it != permutation.end()) + p.second = it->second; + } +} + +std::string LobbySettings::getAvailableTeams() const +{ + if (RaceManager::get()->teamEnabled()) + return "rb"; + + return m_available_teams; +} // getAvailableTeams + +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp new file mode 100644 index 00000000000..62508ad37d4 --- /dev/null +++ b/src/utils/lobby_settings.hpp @@ -0,0 +1,239 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef LOBBY_SETTINGS_HPP +#define LOBBY_SETTINGS_HPP + +#include "irrString.h" + +// kimden: probably should be removed later +#include "utils/track_filter.hpp" +#include "utils/team_utils.hpp" + +#include +class GameSetup; +class LobbyQueues; +class KartElimination; +class STKPeer; +class PeerVote; +class NetworkString; +class LobbyAssetManager; +class GameInfo; +class Track; +class Tournament; + +/** @brief A class that manipulates server settings, such as resetting, + * scoring, goal policies, etc. Might be split into a few parts later, + * or even merged back into ServerLobby if proved useless. */ +class LobbySettings +{ +public: + LobbySettings(GameSetup* game_setup, + std::shared_ptr queues, + std::shared_ptr elim, + std::shared_ptr asset_manager, + std::shared_ptr tournament); + ~LobbySettings(); + + void initCategories(); + void initAvailableTracks(); + void initAvailableModes(); + bool loadCustomScoring(std::string& scoring); + void loadWhiteList(); + void loadPreservedSettings(); + + bool hasConsentOnReplays() const { return m_consent_on_replays; } + void setConsentOnReplays(bool value) { m_consent_on_replays = value; } + std::string getInternalAvailableTeams() const { return m_available_teams; } + void setInternalAvailableTeams(std::string& s) { m_available_teams = s; } + void setTeamForUsername(const std::string& name, int team) + { m_team_for_player[name] = team; } + int getTeamForUsername(const std::string& name) + { + auto it = m_team_for_player.find(name); + if (it == m_team_for_player.end()) + return TeamUtils::NO_TEAM; + return it->second; + } + void clearTeams() { m_team_for_player.clear(); } + bool hasTeam(const std::string& name) + { return m_team_for_player.find(name) != m_team_for_player.end(); } + std::map> getCategories() const + { return m_player_categories; } + + std::string getHelpMessage() const { return m_help_message; } + std::string getMotd() const { return m_motd; } + void addMutedPlayerFor(std::shared_ptr peer, const irr::core::stringw& name); + bool removeMutedPlayerFor(std::shared_ptr peer, const irr::core::stringw& name); + bool isMuting(std::shared_ptr peer, const irr::core::stringw& name) const; + std::string getMutedPlayersAsString(std::shared_ptr peer); + void addTeamSpeaker(std::shared_ptr peer); + void setMessageReceiversFor(std::shared_ptr peer, const std::vector& receivers); + std::set getMessageReceiversFor(std::shared_ptr peer) const; + bool isTeamSpeaker(std::shared_ptr peer) const; + void makeChatPublicFor(std::shared_ptr peer); + bool hasNoLapRestrictions() const; + bool hasMultiplier() const; + bool hasFixedLapCount() const; + int getMultiplier() const; + int getFixedLapCount() const; + void setMultiplier(int new_value); + void setFixedLapCount(int new_value); + void resetLapRestrictions(); + void setDefaultLapRestrictions(); + std::string getLapRestrictionsAsString() const; + std::string getDirectionAsString(bool just_edited = false) const; + bool setDirection(int x = -1); + bool hasFixedDirection() const; + int getDirection() const; + bool isAllowedToStart() const; + void setAllowedToStart(bool value); + std::string getAllowedToStartAsString(bool just_edited = false) const; + bool isGPGridShuffled() const; + void setGPGridShuffled(bool value); + std::string getWhetherShuffledGPGridAsString(bool just_edited = false) const; + std::vector getMissingAssets(std::shared_ptr peer) const; + void updateWorldSettings(std::shared_ptr game_info); + void onResetToDefaultSettings(); + bool isPreservingMode() const; + std::string getScoringAsString() const; + void addPlayerToCategory(const std::string& player, const std::string& category); + void erasePlayerFromCategory(const std::string& player, const std::string& category); + void makeCategoryVisible(const std::string category, bool value); + bool isCategoryVisible(const std::string category) const; + std::vector getVisibleCategoriesForPlayer(const std::string& profile_name) const; + std::set getPlayersInCategory(const std::string& category) const; + std::string getPreservedSettingsAsString() const; + void eraseFromPreserved(const std::string& value); + void insertIntoPreserved(const std::string& value); + void clearAllExpiredWeakPtrs(); + void initializeDefaultVote(); + void applyGlobalFilter(FilterContext& map_context) const; + void applyGlobalKartsFilter(FilterContext& kart_context) const; + void applyRestrictionsOnVote(PeerVote* vote, Track* t) const; + void encodeDefaultVote(NetworkString* ns) const; + void setDefaultVote(PeerVote winner_vote); + PeerVote getDefaultVote() const; + void onPeerDisconnect(std::shared_ptr peer); + bool isInWhitelist(const std::string& username) const; + bool isModeAvailable(int mode) const; + bool isDifficultyAvailable(int difficulty) const; + void applyPermutationToTeams(const std::map& permutation); + void resetWinnerPeerId() + { m_winner_peer_id = std::numeric_limits::max(); } + void setWinnerPeerId(uint32_t value) { m_winner_peer_id = value; } + + int getBattleHitCaptureLimit() const { return m_battle_hit_capture_limit; } + float getBattleTimeLimit() const { return m_battle_time_limit; } + void setBattleHitCaptureLimit(int value) + { m_battle_hit_capture_limit = value; } + void setBattleTimeLimit(float value) { m_battle_time_limit = value; } + std::string getAvailableTeams() const; + +private: + GameSetup* m_game_setup; + + std::shared_ptr m_lobby_queues; + + std::shared_ptr m_kart_elimination; + + std::shared_ptr m_asset_manager; + + std::shared_ptr m_tournament; + +// These are fine here =============================================================================== + + int m_battle_hit_capture_limit; + + float m_battle_time_limit; + + std::vector m_play_requirement_tracks; + + std::set m_config_available_tracks; + + std::map> m_config_track_limitations; + + std::string m_motd; + + std::string m_help_message; + + std::set m_available_difficulties; + + std::set m_available_modes; + + TrackFilter m_global_filter; + + KartFilter m_global_karts_filter; + + int m_fixed_lap; + + int m_fixed_direction; + + double m_default_lap_multiplier; + + std::vector m_scoring_int_params; + + std::string m_scoring_type; + + std::set m_usernames_white_list; + + std::set m_preserve; + + bool m_allowed_to_start; + + bool m_consent_on_replays; + + bool m_shuffle_gp; + + std::string m_available_teams; + + +// These should be moved to voting manager =========================================================== + + // Default game settings if no one has ever vote, and save inside here for + // final vote (for live join) + PeerVote* m_default_vote; + + uint32_t m_winner_peer_id; + + +// These should be moved to chat handler ============================================================= + + std::map, std::set, + std::owner_less > > m_peers_muted_players; + + std::map, std::set> m_message_receivers; + + std::set> m_team_speakers; + + +// These should be moved to category and team manager ================================================ + + std::map> m_player_categories; + + std::set m_hidden_categories; + + std::set m_special_categories; + + std::map> m_categories_for_player; + + std::map m_team_for_player; + +}; + +#endif \ No newline at end of file diff --git a/src/utils/map_vote_handler.cpp b/src/utils/map_vote_handler.cpp index 6402348b262..3d5c8a6b142 100644 --- a/src/utils/map_vote_handler.cpp +++ b/src/utils/map_vote_handler.cpp @@ -20,8 +20,10 @@ #include "utils/string_utils.hpp" #include "utils/log.hpp" #include "utils/random_generator.hpp" +#include "utils/lobby_settings.hpp" -MapVoteHandler::MapVoteHandler(): algorithm(0) +MapVoteHandler::MapVoteHandler(std::shared_ptr settings) + : algorithm(0), m_lobby_settings(settings) { } // MapVoteHandler @@ -66,34 +68,34 @@ void MapVoteHandler::findMajorityValue(const std::map& choices, uns bool MapVoteHandler::handleAllVotes(std::map& peers_votes, float remaining_time, float max_time, bool is_over, - unsigned cur_players, PeerVote* default_vote, - PeerVote* winner_vote, uint32_t* winner_peer_id) const + unsigned cur_players, + PeerVote* winner_vote) const { if (algorithm == 0) - return standard(peers_votes, remaining_time, max_time, is_over, cur_players, default_vote, winner_vote, winner_peer_id); + return standard(peers_votes, remaining_time, max_time, is_over, cur_players, winner_vote); else // if (algorithm == 1) - return random(peers_votes, remaining_time, max_time, is_over, cur_players, default_vote, winner_vote, winner_peer_id); + return random(peers_votes, remaining_time, max_time, is_over, cur_players, winner_vote); } // handleAllVotes // ============================================================================ bool MapVoteHandler::random(std::map& peers_votes, float remaining_time, float max_time, bool is_over, - unsigned cur_players, PeerVote* default_vote, - PeerVote* winner_vote, uint32_t* winner_peer_id) const + unsigned cur_players, + PeerVote* winner_vote) const { if (!is_over) return false; if (peers_votes.empty()) { - *winner_vote = *default_vote; + *winner_vote = m_lobby_settings->getDefaultVote(); return true; } RandomGenerator rg; std::map::iterator it = peers_votes.begin(); std::advance(it, rg.get((int)peers_votes.size())); - *winner_peer_id = it->first; + m_lobby_settings->setWinnerPeerId(it->first); *winner_vote = it->second; return true; } // random @@ -101,8 +103,8 @@ bool MapVoteHandler::random(std::map& peers_votes, bool MapVoteHandler::standard(std::map& peers_votes, float remaining_time, float max_time, bool is_over, - unsigned cur_players, PeerVote* default_vote, - PeerVote* winner_vote, uint32_t* winner_peer_id) const + unsigned cur_players, + PeerVote* winner_vote) const { // Determine majority agreement when 35% of voting time remains, // reserve some time for kart selection so it's not 50% @@ -115,15 +117,16 @@ bool MapVoteHandler::standard(std::map& peers_votes, { if (is_over) { - *winner_vote = *default_vote; + *winner_vote = m_lobby_settings->getDefaultVote(); return true; } return false; } - std::string top_track = default_vote->m_track_name; - unsigned top_laps = default_vote->m_num_laps; - bool top_reverse = default_vote->m_reverse; + PeerVote default_vote = m_lobby_settings->getDefaultVote(); + std::string top_track = default_vote.m_track_name; + unsigned top_laps = default_vote.m_num_laps; + bool top_reverse = default_vote.m_reverse; std::map tracks; std::map laps; @@ -179,7 +182,7 @@ bool MapVoteHandler::standard(std::map& peers_votes, if (!is_over) return false; } - *winner_peer_id = it->first; + m_lobby_settings->setWinnerPeerId(it->first); *winner_vote = it->second; return true; } @@ -200,7 +203,7 @@ bool MapVoteHandler::standard(std::map& peers_votes, else it++; } - *winner_peer_id = closest_lap->first; + m_lobby_settings->setWinnerPeerId(closest_lap->first); *winner_vote = closest_lap->second; return true; } diff --git a/src/utils/map_vote_handler.hpp b/src/utils/map_vote_handler.hpp index 450509d457e..b2967e0cbb7 100644 --- a/src/utils/map_vote_handler.hpp +++ b/src/utils/map_vote_handler.hpp @@ -27,6 +27,7 @@ #include #include #include +class LobbySettings; #include "network/peer_vote.hpp" @@ -42,26 +43,29 @@ class MapVoteHandler // ADVANCED = 2 private: int algorithm; + + std::shared_ptr m_lobby_settings; + template static void findMajorityValue(const std::map& choices, unsigned cur_players, T* best_choice, float* rate); bool standard(std::map& peers_votes, float remaining_time, float max_time, bool is_over, - unsigned cur_players, PeerVote* default_vote, - PeerVote* winner_vote, uint32_t* winner_peer_id) const; + unsigned cur_players, + PeerVote* winner_vote) const; bool random(std::map& peers_votes, float remaining_time, float max_time, bool is_over, - unsigned cur_players, PeerVote* default_vote, - PeerVote* winner_vote, uint32_t* winner_peer_id) const; + unsigned cur_players, + PeerVote* winner_vote) const; public: - MapVoteHandler(); + MapVoteHandler(std::shared_ptr settings); void setAlgorithm(int x) { algorithm = x; } int getAlgorithm() const { return algorithm; } bool handleAllVotes(std::map& peers_votes, float remaining_time, float max_time, bool is_over, - unsigned cur_players, PeerVote* default_vote, - PeerVote* winner_vote, uint32_t* winner_peer_id) const; + unsigned cur_players, + PeerVote* winner_vote) const; }; #endif // MAP_VOTE_HANDLER_HPP diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp index c94535cceeb..b5486ccb684 100644 --- a/src/utils/tournament.cpp +++ b/src/utils/tournament.cpp @@ -26,16 +26,7 @@ #include "network/peer_vote.hpp" #include "modes/world.hpp" #include "modes/soccer_world.hpp" -// #include "karts/kart_properties.hpp" -// #include "karts/kart_properties_manager.hpp" -// #include "karts/official_karts.hpp" -// #include "network/network_string.hpp" -// #include "network/server_config.hpp" -// #include "network/stk_peer.hpp" -// #include "network/protocols/server_lobby.hpp" -// #include "tracks/track.hpp" -// #include "tracks/track_manager.hpp" -// #include "utils/random_generator.hpp" +#include "utils/lobby_settings.hpp" #include "utils/string_utils.hpp" namespace @@ -43,7 +34,8 @@ namespace static int g_history_limit = 100; } -Tournament::Tournament(ServerLobby* lobby): m_lobby(lobby) +Tournament::Tournament(ServerLobby* lobby, std::shared_ptr settings) + : m_lobby(lobby), m_lobby_settings(settings) { initTournamentPlayers(); m_tournament_game = 0; @@ -217,7 +209,7 @@ void Tournament::initTournamentPlayers() type == "R" ? m_tournament_red_players : type == "B" ? m_tournament_blue_players : m_tournament_referees); - for (const std::string& member: m_lobby->getCategories()[cat_name]) + for (const std::string& member: m_lobby_settings->getCategories()[cat_name]) dest.insert(member); } else if (type == "R") diff --git a/src/utils/tournament.hpp b/src/utils/tournament.hpp index 7dbae34d1c1..e2ef1123a69 100644 --- a/src/utils/tournament.hpp +++ b/src/utils/tournament.hpp @@ -32,6 +32,7 @@ class PeerVote; class TrackFilter; class ServerLobby; class STKPeer; +class LobbySettings; /** This class combines things that were previously located in server lobby * (m_tournament_*) and were related to Soccer Tournaments. @@ -41,7 +42,7 @@ class STKPeer; class Tournament { public: - Tournament(ServerLobby* lobby); + Tournament(ServerLobby* lobby, std::shared_ptr settings); void initTournamentPlayers(); void applyFiltersForThisGame(FilterContext& track_context); std::set getThoseWhoSeeTeamchats() const; @@ -87,6 +88,8 @@ class Tournament private: ServerLobby* m_lobby; + std::shared_ptr m_lobby_settings; + std::set m_tournament_red_players; std::set m_tournament_blue_players; From 0ccc65e66c52e7acd8416e1b534ab72bf5681349 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 3 Mar 2025 00:01:18 +0400 Subject: [PATCH 581/830] Minor fixes --- src/config/stk_config.cpp | 2 +- src/network/protocols/command_manager.cpp | 3 +++ src/network/protocols/server_lobby.cpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp index c67804d369c..655a7dd3d48 100644 --- a/src/config/stk_config.cpp +++ b/src/config/stk_config.cpp @@ -714,7 +714,7 @@ void STKConfig::getAllScores(std::vector *all_scores, int num_karts) if (num_karts == 0) return; assert(num_karts <= m_max_karts); - all_scores->resize(num_karts); + all_scores->resize(num_karts, 0); sorted_score_increase.resize(num_karts+1); //sorting function is [begin, end[ //get increase data into sorted_score_increase diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index e18e4f452c3..87bf4d1991f 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2086,7 +2086,10 @@ void CommandManager::process_unmute(Context& context) player_name = StringUtils::utf8ToWide(argv[1]); if (!m_lobby_settings->removeMutedPlayerFor(peer, player_name)) + { error(context); + return; + } std::string result_msg = "Unmuted player " + StringUtils::wideToUtf8(player_name); m_lobby->sendStringToPeer(result_msg, peer); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 518fa77ac26..3f9286990fe 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4069,7 +4069,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, unsigned total_players = 0; STKHost::get()->updatePlayers(NULL, NULL, &total_players); bool bad_mode = !m_lobby_settings->isModeAvailable(mode); - bool bad_difficulty = m_lobby_settings->isDifficultyAvailable(difficulty); + bool bad_difficulty = !m_lobby_settings->isDifficultyAvailable(difficulty); if (bad_mode || bad_difficulty) { // It remains just in case, but kimden thinks that From 8fe5314bcdc89ffbe07e99d6f6bb111407560c15 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 4 Mar 2025 01:15:27 +0400 Subject: [PATCH 582/830] Style refactor + huge HitProcessor change + some fixes --- src/network/protocols/command_manager.cpp | 4 +- src/utils/enum_extended_reader.cpp | 11 +- src/utils/game_info.cpp | 18 +- src/utils/game_info.hpp | 54 ++-- src/utils/hit_processor.cpp | 338 +++++++++++----------- src/utils/hit_processor.hpp | 73 +++-- src/utils/hourglass_reason.hpp | 30 +- src/utils/kart_elimination.cpp | 34 ++- src/utils/kart_elimination.hpp | 26 +- src/utils/lobby_asset_manager.cpp | 73 ++--- src/utils/lobby_asset_manager.hpp | 26 +- src/utils/lobby_queues.cpp | 38 ++- src/utils/lobby_queues.hpp | 22 +- src/utils/lobby_settings.cpp | 215 +++++++++----- src/utils/lobby_settings.hpp | 51 ++-- src/utils/map_vote_handler.cpp | 36 +-- src/utils/map_vote_handler.hpp | 35 ++- src/utils/set_typo_fixer.cpp | 21 +- src/utils/set_typo_fixer.hpp | 9 +- src/utils/set_with_flip.hpp | 4 +- src/utils/team_utils.cpp | 30 +- src/utils/team_utils.hpp | 10 +- src/utils/tournament.cpp | 248 +++++++++------- src/utils/tournament.hpp | 58 ++-- src/utils/tournament_role.cpp | 17 +- src/utils/tournament_role.hpp | 3 +- src/utils/track_filter.cpp | 14 +- src/utils/track_filter.hpp | 17 +- 28 files changed, 829 insertions(+), 686 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 87bf4d1991f..a6f3cb79045 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -3272,12 +3272,12 @@ void CommandManager::process_game(Context& context) int old_addition; m_tournament->getGameCmdInput(old_game_number, old_duration, old_addition); int new_game_number = m_tournament->getNextGameNumber(); - int new_duration = m_tournament->getDefaultDuration(); // Was m_tournament_length for argv.size >= 2 + int new_duration = m_tournament->getDefaultDuration(); // Was m_length for argv.size >= 2 int new_addition = 0; if (1 < argv.size()) { - // What's the difference between m_tournament_length and ServerConfig::fixedlap ?? + // What's the difference between m_length and ServerConfig::fixedlap ?? bool bad = false; if (!StringUtils::parseString(argv[1], &new_game_number)) diff --git a/src/utils/enum_extended_reader.cpp b/src/utils/enum_extended_reader.cpp index 62815e31673..7dc9ffd8c70 100644 --- a/src/utils/enum_extended_reader.cpp +++ b/src/utils/enum_extended_reader.cpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2021 kimden +// Copyright (C) 2021, 2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -17,10 +17,10 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "utils/enum_extended_reader.hpp" + #include "utils/log.hpp" #include "utils/string_utils.hpp" -// ======================================================================== int EnumExtendedReader::parse(std::string& text) { @@ -30,10 +30,11 @@ int EnumExtendedReader::parse(std::string& text) for (const std::string& key: items) { auto it = values.find(key); if (it == values.end()) - Log::warn("EnumExtendedReader", "Key \"%s\" not found - ignored.", key.c_str()); + Log::warn("EnumExtendedReader", + "Key \"%s\" not found - ignored.", key.c_str()); else value |= it->second; } return value; -} // parse -// ======================================================================== \ No newline at end of file +} // parse +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/game_info.cpp b/src/utils/game_info.cpp index b624a4246d1..e75761b3ae6 100644 --- a/src/utils/game_info.cpp +++ b/src/utils/game_info.cpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2024 SuperTuxKart-Team +// Copyright (C) 2024-2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -18,14 +18,20 @@ #include "utils/game_info.hpp" -// TODO: don't use file names as constants -const std::string GameInfo::m_default_powerup_string = "powerup.xml"; -const std::string GameInfo::m_default_kart_char_string = "kart_characteristics.xml"; +namespace +{ + + // TODO: don't use file names as constants + const std::string g_default_powerup_string = "powerup.xml"; + const std::string g_default_kart_char_string = "kart_characteristics.xml"; + +} // namespace + //----------------------------------------------------------------------------- void GameInfo::setPowerupString(const std::string&& str) { - if (str == m_default_powerup_string) + if (str == g_default_powerup_string) m_powerup_string = ""; else m_powerup_string = str; @@ -34,7 +40,7 @@ void GameInfo::setPowerupString(const std::string&& str) //----------------------------------------------------------------------------- void GameInfo::setKartCharString(const std::string&& str) { - if (str == m_default_kart_char_string) + if (str == g_default_kart_char_string) m_kart_char_string = ""; else m_kart_char_string = str; diff --git a/src/utils/game_info.hpp b/src/utils/game_info.hpp index fe5b988d70e..2b7831b9557 100644 --- a/src/utils/game_info.hpp +++ b/src/utils/game_info.hpp @@ -19,7 +19,6 @@ #ifndef GAME_INFO_HPP #define GAME_INFO_HPP -#include #include #include #include @@ -32,27 +31,26 @@ struct GameInfo { struct PlayerInfo { - bool m_reserved; - int m_game_event; - std::string m_username = ""; - double m_result = 0.0f; - std::string m_kart = ""; - float m_kart_color = 0.0f; - std::string m_kart_class = ""; - int m_not_full = 0; - int m_online_id = 0; - int m_autofinish = 0; - int m_team = -1; - double m_when_joined = 0; - double m_when_left = 0; - double m_fastest_lap = -1.0; - double m_sog_time = -1.0; - int m_start_position = -1; - double m_game_duration = -1; - int m_handicap = 0; - std::string m_country_code = ""; - - std::string m_other_info = ""; + bool m_reserved; + int m_game_event; + std::string m_username = ""; + double m_result = 0.0f; + std::string m_kart = ""; + float m_kart_color = 0.0f; + std::string m_kart_class = ""; + int m_not_full = 0; + int m_online_id = 0; + int m_autofinish = 0; + int m_team = -1; + double m_when_joined = 0; + double m_when_left = 0; + double m_fastest_lap = -1.0; + double m_sog_time = -1.0; + int m_start_position = -1; + double m_game_duration = -1; + int m_handicap = 0; + std::string m_country_code = ""; + std::string m_other_info = ""; PlayerInfo(bool reserved = false, bool game_event = false): m_reserved(reserved), @@ -61,19 +59,17 @@ struct GameInfo bool isReserved() const { return m_reserved; } }; - static const std::string m_default_powerup_string; - static const std::string m_default_kart_char_string; std::string m_powerup_string; std::string m_kart_char_string; std::string m_venue; std::string m_reverse; std::string m_mode; std::string m_server_version; - int m_value_limit; - double m_time_limit; - int m_flag_return_timeout; - int m_flag_deactivated_time; - int m_difficulty; + int m_value_limit; + double m_time_limit; + int m_flag_return_timeout; + int m_flag_deactivated_time; + int m_difficulty; std::string m_timestamp; // First RaceManager->getNumPlayers() elements in m_player_info diff --git a/src/utils/hit_processor.cpp b/src/utils/hit_processor.cpp index 794eeec6126..b1072e3eb81 100644 --- a/src/utils/hit_processor.cpp +++ b/src/utils/hit_processor.cpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2024 kimden +// Copyright (C) 2021 Heuchi1, 2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -16,204 +16,208 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#include "utils/hit_processor.hpp" -#include "network/server_config.hpp" -#include "karts/abstract_kart.hpp" -#include "modes/world.hpp" #include "items/attachment.hpp" -#include "utils/string_utils.hpp" +#include "karts/abstract_kart.hpp" #include "karts/kart_properties.hpp" +#include "modes/world.hpp" #include "network/protocols/server_lobby.hpp" +#include "network/server_config.hpp" +#include "utils/hit_processor.hpp" #include "utils/lobby_settings.hpp" +#include "utils/string_utils.hpp" +namespace +{ + + // Time after which a bowling ball hit doesn't trigger anything + const float MAX_BOWL_TEAMMATE_HIT_TIME = 2.0f; + + Attachment::AttachmentType getAttachment(AbstractKart* kart) + { + return kart->getAttachment()->getType(); + } + +} // namespace +//----------------------------------------------------------------------------- + HitProcessor::HitProcessor(ServerLobby* lobby, std::shared_ptr settings) : m_lobby(lobby), m_lobby_settings(settings) { m_troll_active = ServerConfig::m_troll_active; - m_show_teammate_hits = ServerConfig::m_show_teammate_hits; - m_teammate_hit_mode = ServerConfig::m_teammate_hit_mode; - m_last_teammate_hit_msg = 0; - m_teammate_swatter_punish.clear(); + m_show_hits = ServerConfig::m_show_teammate_hits; + m_hit_mode = ServerConfig::m_teammate_hit_mode; + m_last_hit_msg = 0; + m_swatter_punish.clear(); // This was also present in ServerLobby::setup(), I'm not sure why. // Return back if there are problems. - m_collecting_teammate_hit_info = false; -} // HitProcessor -// ======================================================================== - + m_collecting_hit_info = false; +} // HitProcessor +//----------------------------------------------------------------------------- -// this is called when collisions of an item are handled +// This is called when collisions of an item are handled, // so we keep track of hits caused by that item -void HitProcessor::setTeammateHitOwner(unsigned int ownerID, uint16_t ticks_since_thrown) +void HitProcessor::setTeammateHitOwner(unsigned int ownerID, + uint16_t ticks_since_thrown) { - m_teammate_current_item_ownerID = ownerID; - m_teammate_ticks_since_thrown = ticks_since_thrown; - m_teammate_karts_hit.clear(); - m_teammate_karts_exploded.clear(); - m_collecting_teammate_hit_info = true; + m_current_item_owner_id = ownerID; + m_ticks_since_thrown = ticks_since_thrown; + m_karts_hit.clear(); + m_karts_exploded.clear(); + m_collecting_hit_info = true; } // setTeammateHitOwner //----------------------------------------------------------------------------- void HitProcessor::registerTeammateHit(unsigned int kartID) { // only register if we know the item owner and victim is still racing - if (m_collecting_teammate_hit_info && !World::getWorld()->getKart(kartID)->hasFinishedRace()) - m_teammate_karts_hit.push_back(kartID); + if (m_collecting_hit_info && + !World::getWorld()->getKart(kartID)->hasFinishedRace()) + m_karts_hit.push_back(kartID); } // registerTeammateHit //----------------------------------------------------------------------------- void HitProcessor::registerTeammateExplode(unsigned int kartID) { // only register if we know the item owner and victim is still racing - if (m_collecting_teammate_hit_info && !World::getWorld()->getKart(kartID)->hasFinishedRace()) - m_teammate_karts_exploded.push_back(kartID); + if (m_collecting_hit_info && + !World::getWorld()->getKart(kartID)->hasFinishedRace()) + m_karts_exploded.push_back(kartID); } // registerTeammateExplode //----------------------------------------------------------------------------- void HitProcessor::sendTeammateHitMsg(std::string& s) { - if (World* w = World::getWorld()) + World* w = World::getWorld(); + if (!w) + return; + + int ticks = w->getTicksSinceStart(); + if (ticks - m_last_hit_msg > stk_config->time2Ticks(1.5f)) { - int ticks = w->getTicksSinceStart(); - if (ticks - m_last_teammate_hit_msg > stk_config->time2Ticks(1.5f)) - { - m_last_teammate_hit_msg = ticks; - m_lobby->sendStringToAllPeers(s); - } + m_last_hit_msg = ticks; + m_lobby->sendStringToAllPeers(s); } } // sendTeammateHitMsg //----------------------------------------------------------------------------- void HitProcessor::handleTeammateHits() { - m_collecting_teammate_hit_info = false; - // get team of owner of item - const std::string owner_name = StringUtils::wideToUtf8( - RaceManager::get()->getKartInfo(m_teammate_current_item_ownerID).getPlayerName()); + m_collecting_hit_info = false; + + // Get team of item owner + auto kart_info = RaceManager::get()->getKartInfo(m_current_item_owner_id); + const std::string owner_name = StringUtils::wideToUtf8(kart_info.getPlayerName()); const int owner_team = m_lobby_settings->getTeamForUsername(owner_name); - if (owner_team == 0) // no team, no punishment + if (owner_team == TeamUtils::NO_TEAM) return; - AbstractKart *owner = World::getWorld()->getKart(m_teammate_current_item_ownerID); + AbstractKart *owner = World::getWorld()->getKart(m_current_item_owner_id); // if item is too old, it doesn't count // currently only bowling balls have their creation time registered // so cakes will always count - if (m_teammate_ticks_since_thrown > stk_config->time2Ticks(MAX_BOWL_TEAMMATE_HIT_TIME)) + if (m_ticks_since_thrown > stk_config->time2Ticks(MAX_BOWL_TEAMMATE_HIT_TIME)) return; - // Show message? if (showTeammateHits()) + processHitMessage(owner_name, owner_team); + + if (isTeammateHitMode()) + processTeammateHit(owner, owner_name, owner_team); +} // handleTeammateHits +//----------------------------------------------------------------------------- + +void HitProcessor::processHitMessage(const std::string& owner_name, int owner_team) +{ + // prepare string + int num_victims = 0; + std::string msg = ServerConfig::m_teammate_hit_msg_prefix; + std::string victims; + msg += owner_name; + msg += " just shot "; + + for (unsigned int i = 0; i < m_karts_exploded.size(); i++) + { + const std::string player_name = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(m_karts_exploded[i]).getPlayerName()); + const int playerTeam = m_lobby_settings->getTeamForUsername(player_name); + if (owner_team != playerTeam) + continue; + + if (num_victims > 0) + victims += " and "; + victims += player_name; + num_victims++; + } + if (num_victims > 0) + { + msg += (num_victims > 1) ? "teammates " : "teammate "; + msg += victims; + sendTeammateHitMsg(msg); + } +} // processHitMessage +//----------------------------------------------------------------------------- + +void HitProcessor::processTeammateHit(AbstractKart* owner, + const std::string& owner_name, int owner_team) +{ + bool punished = false; + // first check if we exploded at least one teammate + for (unsigned int i = 0; i < m_karts_exploded.size() && !punished; i++) { - // prepare string - int num_victims = 0; - std::string msg = ServerConfig::m_teammate_hit_msg_prefix; - std::string victims; - msg += owner_name; - msg += " just shot "; - - for (unsigned int i = 0; i < m_teammate_karts_exploded.size(); i++) + const std::string player_name = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(m_karts_exploded[i]).getPlayerName()); + const int playerTeam = m_lobby_settings->getTeamForUsername(player_name); + if (owner_team != playerTeam) + continue; + + punished = true; + if (getAttachment(owner) == Attachment::ATTACH_BOMB) { - const std::string playername = StringUtils::wideToUtf8( - RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); - const int playerTeam = m_lobby_settings->getTeamForUsername(playername); - if (owner_team == playerTeam) - { - // hit teammate - if (num_victims > 0) - victims += " and "; - victims += StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); - num_victims++; - } + // make bomb explode + owner->getAttachment()->update(10000); } - if (num_victims > 0) // we found victims, so send message + else if (owner->isShielded()) { - msg += (num_victims > 1) ? "teammates " : "teammate "; - msg += victims; - sendTeammateHitMsg(msg); + // if owner is shielded, take away shield + owner->decreaseShieldTime(); } + else + punishKart(owner, 1.0f, 1.0f); } - if (isTeammateHitMode()) + // now check for deshielding teammates + for (unsigned int i = 0; i < m_karts_hit.size() && !punished; i++) { - bool punished = false; - // first check if we exploded at least one teammate - for (unsigned int i = 0; i < m_teammate_karts_exploded.size() && !punished; i++) + const std::string player_name = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(m_karts_hit[i]).getPlayerName()); + const int playerTeam = m_lobby_settings->getTeamForUsername(player_name); + if (owner_team != playerTeam) + continue; + + // we did, so punish + punished = true; + if (getAttachment(owner) == Attachment::ATTACH_BOMB) { - const std::string playername = StringUtils::wideToUtf8( - RaceManager::get()->getKartInfo(m_teammate_karts_exploded[i]).getPlayerName()); - const int playerTeam = m_lobby_settings->getTeamForUsername(playername); - if (owner_team == playerTeam) - { - // we did, so punish - punished = true; - if(owner->getAttachment()->getType() == Attachment::ATTACH_BOMB) - { - // make bomb explode - owner->getAttachment()->update(10000); - } - else if (owner->isShielded()) - { - // if owner is shielded, take away shield - owner->decreaseShieldTime(); - } - else - { - int left_over_ticks = 0; - // if owner already has an anvil or a parachute, make new anvil last longer - if (owner->getAttachment()->getType() == Attachment::ATTACH_ANVIL - || owner->getAttachment()->getType() == Attachment::ATTACH_PARACHUTE) - { - left_over_ticks = owner->getAttachment()->getTicksLeft(); - } - owner->getAttachment()->set(Attachment::ATTACH_ANVIL, - stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) + left_over_ticks); - owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor()); - } - } + // make bomb explode + owner->getAttachment()->update(10000); } - - // now check for deshielding teammates - for (unsigned int i = 0; i < m_teammate_karts_hit.size() && !punished; i++) + else if (owner->isShielded()) { - const std::string playername = StringUtils::wideToUtf8( - RaceManager::get()->getKartInfo(m_teammate_karts_hit[i]).getPlayerName()); - const int playerTeam = m_lobby_settings->getTeamForUsername(playername); - if (owner_team == playerTeam) - { - // we did, so punish - punished = true; - if (owner->getAttachment()->getType() == Attachment::ATTACH_BOMB) - { - // make bomb explode - owner->getAttachment()->update(10000); - } - else if (owner->isShielded()) - { - // if owner is shielded, take away shield - owner->decreaseShieldTime(); - } - else - { - // since teammate didn't explode, make anvil less severe - int left_over_ticks = 0; - // if owner already has an anvil or a parachute, make new anvil last longer - if (owner->getAttachment()->getType() == Attachment::ATTACH_ANVIL - || owner->getAttachment()->getType() == Attachment::ATTACH_PARACHUTE) - { - left_over_ticks = owner->getAttachment()->getTicksLeft(); - } - owner->getAttachment()->set(Attachment::ATTACH_ANVIL, - stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) / 2 + left_over_ticks); - owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor() * 2.0f); - } - } + // if owner is shielded, take away shield + owner->decreaseShieldTime(); + } + else + { + // since teammate didn't explode, make anvil less severe + punishKart(owner, 0.5f, 0.5f); } } -} // handleTeammateHits +} // processTeammateHit //----------------------------------------------------------------------------- void HitProcessor::handleSwatterHit(unsigned int ownerID, unsigned int victimID, @@ -222,7 +226,7 @@ void HitProcessor::handleSwatterHit(unsigned int ownerID, unsigned int victimID, const std::string owner_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(ownerID).getPlayerName()); const int owner_team = m_lobby_settings->getTeamForUsername(owner_name); - if (owner_team == 0) + if (owner_team == TeamUtils::NO_TEAM) return; const std::string victim_name = StringUtils::wideToUtf8( @@ -247,11 +251,16 @@ void HitProcessor::handleSwatterHit(unsigned int ownerID, unsigned int victimID, // remove swatter AbstractKart *owner = World::getWorld()->getKart(ownerID); owner->getAttachment()->setTicksLeft(0); - // if this is the first kart hit and the swatter is in use for less than 3s - // the attacker also gets an anvil - if (!has_hit_kart && ticks_active < stk_config->time2Ticks(3.0f) && success) + + // if this is the first kart hit and the swatter is in use + // for less than 3s, the attacker also gets an anvil + if (!has_hit_kart + && ticks_active < stk_config->time2Ticks(3.0f) + && success) + { // we cannot do this here, will be done in update() - m_teammate_swatter_punish.push_back(owner); + m_swatter_punish.push_back(owner); + } } } // handleSwatterHit //----------------------------------------------------------------------------- @@ -261,7 +270,7 @@ void HitProcessor::handleAnvilHit(unsigned int ownerID, unsigned int victimID) const std::string owner_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(ownerID).getPlayerName()); const int owner_team = m_lobby_settings->getTeamForUsername(owner_name); - if (owner_team == 0) + if (owner_team == TeamUtils::NO_TEAM) return; const std::string victim_name = StringUtils::wideToUtf8( @@ -285,7 +294,7 @@ void HitProcessor::handleAnvilHit(unsigned int ownerID, unsigned int victimID) } if (isTeammateHitMode()) { - if (owner->getAttachment()->getType() == Attachment::ATTACH_BOMB) + if (getAttachment(owner) == Attachment::ATTACH_BOMB) { // make bomb explode owner->getAttachment()->update(10000); @@ -300,18 +309,7 @@ void HitProcessor::handleAnvilHit(unsigned int ownerID, unsigned int victimID) owner->decreaseShieldTime(); } - // now give anvil to owner - int left_over_ticks = 0; - // if owner already has an anvil or a parachute, make new anvil last longer - if (owner->getAttachment()->getType() == Attachment::ATTACH_ANVIL - || owner->getAttachment()->getType() == Attachment::ATTACH_PARACHUTE) - { - left_over_ticks = owner->getAttachment()->getTicksLeft(); - } - owner->getAttachment()->set(Attachment::ATTACH_ANVIL, - stk_config->time2Ticks(owner->getKartProperties()->getAnvilDuration()) + left_over_ticks); - // the powerup anvil is very strong, copy these values (from powerup.cpp) - owner->adjustSpeed(owner->getKartProperties()->getAnvilSpeedFactor() * 0.5f); + punishKart(owner, 1.0f, 2.0f); } } } // handleAnvilHit @@ -319,16 +317,34 @@ void HitProcessor::handleAnvilHit(unsigned int ownerID, unsigned int victimID) void HitProcessor::punishSwatterHits() { - if (m_teammate_swatter_punish.size() > 0) + if (m_swatter_punish.size() > 0) { // punish players who swattered teammates - for (auto& kart : m_teammate_swatter_punish) - { - kart->getAttachment()->set(Attachment::ATTACH_ANVIL, - stk_config->time2Ticks(kart->getKartProperties()->getAnvilDuration())); - kart->adjustSpeed(kart->getKartProperties()->getAnvilSpeedFactor()); - } - m_teammate_swatter_punish.clear(); + for (auto& kart : m_swatter_punish) + punishKart(kart, 1.0f, 1.0f); + + m_swatter_punish.clear(); } } // punishSwatterHits +//----------------------------------------------------------------------------- + +void HitProcessor::punishKart(AbstractKart* kart, float value, float value2) +{ + int leftover_ticks = 0; + + // if owner already has an anvil or a parachute, + // make new anvil last longer + if (getAttachment(kart) == Attachment::ATTACH_ANVIL || + getAttachment(kart) == Attachment::ATTACH_PARACHUTE) + { + leftover_ticks = kart->getAttachment()->getTicksLeft(); + } + + auto time_used = kart->getKartProperties()->getAnvilDuration(); + kart->getAttachment()->set(Attachment::ATTACH_ANVIL, + stk_config->time2Ticks(time_used) * value + leftover_ticks); + + auto factor = kart->getKartProperties()->getAnvilSpeedFactor(); + kart->adjustSpeed(factor / value); +} // punishKart //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/hit_processor.hpp b/src/utils/hit_processor.hpp index b228a52bd07..8bcc9f8748a 100644 --- a/src/utils/hit_processor.hpp +++ b/src/utils/hit_processor.hpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2025 kimden +// Copyright (C) 2021 Heuchi1, 2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -21,17 +21,21 @@ #include "utils/types.hpp" -#include -#include #include +#include +#include + class AbstractKart; -class ServerLobby; class LobbySettings; +class ServerLobby; // A class that incapsulates most of the logic for processing kart hits. // Contains the code originally written by Heuchi1, but it's moved to a // separate file to not include ServerLobby from item source files. +// Note that this class currently (March 2025) processes *team* hits. +// It will be modified to process all hits later. + class HitProcessor { public: @@ -41,49 +45,58 @@ class HitProcessor ServerLobby* m_lobby = nullptr; std::shared_ptr m_lobby_settings; - bool m_troll_active; + bool m_troll_active; // Whether the anti-troll system is active. + + bool m_show_hits; // Whether to show messages about team hits. - bool m_show_teammate_hits; // Whether to show messages about team hits. - bool m_teammate_hit_mode; // Whether to anvil the team hitters. - // time index of last team mate hit - // make sure not to send too many of them - int m_last_teammate_hit_msg; - // we have to keep track of the karts affected by a hit - // we store IDs, because we need to find the team by name (by ID) - // m_collecting_teammate_hit_info is set to true if we are processing a + bool m_hit_mode; // Whether to anvil the team hitters. + + int m_last_hit_msg; // Last tick when the message was shown. + + + // We have to keep track of the karts affected by a hit + // We store IDs, because we need to find the team by name (by ID) + // m_collecting_hit_info is set to true if we are processing a // cake or bowl hit, so we make sure we never fill the vectors with // unneeded data. - bool m_collecting_teammate_hit_info; - unsigned int m_teammate_current_item_ownerID; - uint16_t m_teammate_ticks_since_thrown; - std::vector m_teammate_karts_hit; - std::vector m_teammate_karts_exploded; + bool m_collecting_hit_info; + unsigned int m_current_item_owner_id; + uint16_t m_ticks_since_thrown; + std::vector m_karts_hit; + std::vector m_karts_exploded; - std::vector m_teammate_swatter_punish; // store karts to punish for swattering a teammate + // Store karts to punish for swattering a teammate + std::vector m_swatter_punish; + +private: - // after a certain time a bowl can be avoided and doesn't - // trigger teammate hits anymore - const float MAX_BOWL_TEAMMATE_HIT_TIME = 2.0f; + void processHitMessage(const std::string& owner_name, int owner_team); + void processTeammateHit(AbstractKart* owner, const std::string& owner_name, int owner_team); + void punishKart(AbstractKart* kart, float value = 1.0f, float value2 = 1.0f); public: bool isAntiTrollActive() const { return m_troll_active; } - bool isTeammateHitMode() const { return m_teammate_hit_mode; } - bool showTeammateHits() const { return m_show_teammate_hits; } + bool isTeammateHitMode() const { return m_hit_mode; } + bool showTeammateHits() const { return m_show_hits; } void setAntiTroll(bool value) { m_troll_active = value; } - void setTeammateHitMode(bool value) { m_teammate_hit_mode = value; } - void setShowTeammateHits(bool value) { m_show_teammate_hits = value; } - void setTeammateHitOwner(unsigned int ownerID, uint16_t ticks_since_thrown = 0); + void setTeammateHitMode(bool value) { m_hit_mode = value; } + void setShowTeammateHits(bool value) { m_show_hits = value; } + + void setTeammateHitOwner(unsigned int ownerID, + uint16_t ticks_since_thrown = 0); + void registerTeammateHit(unsigned int kartID); void registerTeammateExplode(unsigned int kartID); void handleTeammateHits(); - void handleSwatterHit(unsigned int ownerID, unsigned int victimID, bool success, bool has_hit_kart, uint16_t ticks_active); + void handleSwatterHit(unsigned int ownerID, unsigned int victimID, + bool success, bool has_hit_kart, uint16_t ticks_active); + void handleAnvilHit(unsigned int ownerID, unsigned int victimID); void sendTeammateHitMsg(std::string& s); void punishSwatterHits(); - void resetLastHits() { m_last_teammate_hit_msg = 0; } + void resetLastHits() { m_last_hit_msg = 0; } }; - #endif // HIT_PROCESSOR_HPP diff --git a/src/utils/hourglass_reason.hpp b/src/utils/hourglass_reason.hpp index 13de6e1a7a4..b972230e7a9 100644 --- a/src/utils/hourglass_reason.hpp +++ b/src/utils/hourglass_reason.hpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2013-2015 Lauri Kasanen +// Copyright (C) 2024-2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -16,24 +16,24 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#ifndef HOURGLASS_REASON_H -#define HOURGLASS_REASON_H +#ifndef HOURGLASS_REASON_HPP +#define HOURGLASS_REASON_HPP enum HourglassReason : int { HR_NONE = 0, - HR_ABSENT_PEER = (1 << 0), - HR_NOT_A_TOURNAMENT_PLAYER = (1 << 1), - HR_SPECTATOR_BY_LIMIT = (1 << 2), - HR_NO_KARTS_AFTER_FILTER = (1 << 3), - HR_NO_MAPS_AFTER_FILTER = (1 << 4), - HR_LACKING_REQUIRED_MAPS = (1 << 5), - HR_ADDON_KARTS_PLAY_THRESHOLD = (1 << 6), - HR_ADDON_TRACKS_PLAY_THRESHOLD = (1 << 7), - HR_ADDON_ARENAS_PLAY_THRESHOLD = (1 << 8), - HR_ADDON_FIELDS_PLAY_THRESHOLD = (1 << 9), - HR_OFFICIAL_KARTS_PLAY_THRESHOLD = (1 << 10), + HR_ABSENT_PEER = (1 << 0), + HR_NOT_A_TOURNAMENT_PLAYER = (1 << 1), + HR_SPECTATOR_BY_LIMIT = (1 << 2), + HR_NO_KARTS_AFTER_FILTER = (1 << 3), + HR_NO_MAPS_AFTER_FILTER = (1 << 4), + HR_LACKING_REQUIRED_MAPS = (1 << 5), + HR_ADDON_KARTS_PLAY_THRESHOLD = (1 << 6), + HR_ADDON_TRACKS_PLAY_THRESHOLD = (1 << 7), + HR_ADDON_ARENAS_PLAY_THRESHOLD = (1 << 8), + HR_ADDON_FIELDS_PLAY_THRESHOLD = (1 << 9), + HR_OFFICIAL_KARTS_PLAY_THRESHOLD = (1 << 10), HR_OFFICIAL_TRACKS_PLAY_THRESHOLD = (1 << 11) }; -#endif +#endif // HOURGLASS_REASON_HPP diff --git a/src/utils/kart_elimination.cpp b/src/utils/kart_elimination.cpp index c99f478bd64..b27a57eb46a 100644 --- a/src/utils/kart_elimination.cpp +++ b/src/utils/kart_elimination.cpp @@ -1,9 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2004-2020 Steve Baker , -// Copyright (C) 2004-2020 Ingo Ruhnke -// Copyright (C) 2006-2020 SuperTuxKart-Team -// Copyright (C) 2020 kimden +// Copyright (C) 2020-2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -21,18 +18,17 @@ #include "utils/kart_elimination.hpp" -#include "utils/string_utils.hpp" #include "utils/log.hpp" +#include "utils/string_utils.hpp" + #include #include #include #include #include -#include #include +#include - -//----------------------------------------------------------------------------- KartElimination::KartElimination() { m_enabled = false; @@ -40,6 +36,7 @@ KartElimination::KartElimination() m_kart = ""; } // KartElimination //----------------------------------------------------------------------------- + bool KartElimination::isEliminated(std::string username) const { if (!m_enabled || m_remained < 0) @@ -50,6 +47,7 @@ bool KartElimination::isEliminated(std::string username) const return true; } // isEliminated //----------------------------------------------------------------------------- + std::set KartElimination::getRemainingParticipants() const { std::set ans; @@ -60,6 +58,7 @@ std::set KartElimination::getRemainingParticipants() const return ans; } // getRemainingParticipants //----------------------------------------------------------------------------- + std::string KartElimination::getStandings() const { std::string result = "Gnu Elimination "; @@ -79,6 +78,7 @@ std::string KartElimination::getStandings() const return result; } // getStandings //----------------------------------------------------------------------------- + void KartElimination::disable() { m_kart = ""; @@ -87,6 +87,7 @@ void KartElimination::disable() m_participants.clear(); } // disable //----------------------------------------------------------------------------- + void KartElimination::enable(std::string kart) { m_kart = kart; @@ -95,6 +96,7 @@ void KartElimination::enable(std::string kart) m_participants.clear(); } // enable //----------------------------------------------------------------------------- + std::string KartElimination::getStartingMessage() const { if (m_kart == "gnu") @@ -106,6 +108,7 @@ std::string KartElimination::getStartingMessage() const "after each race for results.", m_kart.c_str()); } // getStartingMessage //----------------------------------------------------------------------------- + std::string KartElimination::getWarningMessage(bool isEliminated) const { std::string what = "Gnu Elimination is played right now on this server"; @@ -132,16 +135,20 @@ std::string KartElimination::update( if (order.count(m_participants[i]) == 0) order[m_participants[i]] = KartElimination::INF_TIME; } - std::stable_sort(m_participants.begin(), m_participants.begin() + m_remained, + std::stable_sort( + m_participants.begin(), + m_participants.begin() + m_remained, [order](const std::string& a, const std::string& b) -> bool { auto it1 = order.find(a); auto it2 = order.find(b); return it1->second < it2->second; - }); + } + ); std::string msg = ""; msg += m_participants[--m_remained]; bool alone = true; - while (m_remained - 1 >= 0 && order[m_participants[m_remained - 1]] == KartElimination::INF_TIME) + while (m_remained - 1 >= 0 && + order[m_participants[m_remained - 1]] == KartElimination::INF_TIME) { msg += ", " + m_participants[--m_remained]; alone = false; @@ -152,10 +159,9 @@ std::string KartElimination::update( msg += " are now eliminated."; if (m_remained <= 1) { m_enabled = false; - msg += "\nGnu Elimination has finished! Congratulations to " + m_participants[0] + " !"; + msg += "\nGnu Elimination has finished! " + "Congratulations to " + m_participants[0] + " !"; } return msg; } // update //----------------------------------------------------------------------------- - -/* EOF */ diff --git a/src/utils/kart_elimination.hpp b/src/utils/kart_elimination.hpp index daa752cec58..ba2112c3bc7 100644 --- a/src/utils/kart_elimination.hpp +++ b/src/utils/kart_elimination.hpp @@ -1,9 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2004-2020 Steve Baker , -// Copyright (C) 2004-2020 Ingo Ruhnke -// Copyright (C) 2006-2020 SuperTuxKart-Team -// Copyright (C) 2020 kimden +// Copyright (C) 2020-2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -22,13 +19,14 @@ #ifndef HEADER_KART_ELIMINATION_HPP #define HEADER_KART_ELIMINATION_HPP -#include "utils/types.hpp" #include "utils/string_utils.hpp" +#include "utils/types.hpp" + #include -#include -#include #include +#include #include +#include // A class that contains Gnu Elimination data @@ -43,14 +41,14 @@ class KartElimination { static constexpr double INF_TIME = 1e9; KartElimination(); bool isEliminated(std::string username) const; - std::string getKart() const { return m_kart; } + std::string getKart() const { return m_kart; } std::set getRemainingParticipants() const; - bool isEnabled() const { return m_enabled; } - void enable(std::string kart); // done - void disable(); // done - std::string getStandings() const; // done - std::string getStartingMessage() const; // done - std::string getWarningMessage(bool isEliminated) const; // done + bool isEnabled() const { return m_enabled; } + void enable(std::string kart); + void disable(); + std::string getStandings() const; + std::string getStartingMessage() const; + std::string getWarningMessage(bool isEliminated) const; std::string update(std::map& order); }; diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp index f80893b3ca8..d1c0061a44f 100644 --- a/src/utils/lobby_asset_manager.cpp +++ b/src/utils/lobby_asset_manager.cpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2024 kimden +// Copyright (C) 2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -22,9 +22,9 @@ #include "karts/kart_properties_manager.hpp" #include "karts/official_karts.hpp" #include "network/network_string.hpp" +#include "network/protocols/server_lobby.hpp" #include "network/server_config.hpp" #include "network/stk_peer.hpp" -#include "network/protocols/server_lobby.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/random_generator.hpp" @@ -34,8 +34,8 @@ LobbyAssetManager::LobbyAssetManager(ServerLobby* lobby): m_lobby(lobby) { init(); updateAddons(); -} // LobbyAssetManager -// ======================================================================== +} // LobbyAssetManager +//----------------------------------------------------------------------------- void LobbyAssetManager::init() { @@ -59,8 +59,8 @@ void LobbyAssetManager::init() if (!t->isAddon()) m_official_kts.second.insert(t->getIdent()); } -} // init -// ======================================================================== +} // init +//----------------------------------------------------------------------------- void LobbyAssetManager::updateAddons() { @@ -123,10 +123,9 @@ void LobbyAssetManager::updateAddons() m_available_kts.first = { all_k.begin(), all_k.end() }; m_entering_kts = m_available_kts; } // updateAddons - //----------------------------------------------------------------------------- -/** Called whenever server is reset or game mode is changed. - */ + +/** Called whenever server is reset or game mode is changed. */ void LobbyAssetManager::updateMapsForMode(RaceManager::MinorRaceModeType mode) { std::shared_ptr track_manager = TrackManager::get(); @@ -204,7 +203,6 @@ void LobbyAssetManager::updateMapsForMode(RaceManager::MinorRaceModeType mode) } m_entering_kts = m_available_kts; } // updateMapsForMode - //----------------------------------------------------------------------------- void LobbyAssetManager::onServerSetup() @@ -217,11 +215,11 @@ void LobbyAssetManager::onServerSetup() m_available_kts.first = m_official_kts.first; else m_available_kts.first = { all_k.begin(), all_k.end() }; -} // onServerSetup - +} // onServerSetup //----------------------------------------------------------------------------- -void LobbyAssetManager::eraseAssetsWithPeers(const std::vector>& peers) +void LobbyAssetManager::eraseAssetsWithPeers( + const std::vector>& peers) { std::set karts_erase, tracks_erase; for (const auto& peer: peers) @@ -241,7 +239,6 @@ void LobbyAssetManager::eraseAssetsWithPeers(const std::vector::iterator it = m_available_kts.second.begin(); std::advance(it, rg.get((int)m_available_kts.second.size())); return *it; -} // getRandomAvailableMap - +} // getRandomAvailableMap //----------------------------------------------------------------------------- -void LobbyAssetManager::encodePlayerKartsAndCommonMaps(NetworkString* ns, const std::set& all_k) +void LobbyAssetManager::encodePlayerKartsAndCommonMaps(NetworkString* ns, + const std::set& all_k) { const auto& all_t = m_available_kts.second; @@ -288,8 +285,7 @@ void LobbyAssetManager::encodePlayerKartsAndCommonMaps(NetworkString* ns, const ns->encodeString(kart); for (const std::string& track : all_t) ns->encodeString(track); -} // encodePlayerKartsAndCommonMaps - +} // encodePlayerKartsAndCommonMaps //----------------------------------------------------------------------------- bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer, @@ -432,15 +428,13 @@ bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer, } return !bad; -} // handleAssetsForPeer - +} // handleAssetsForPeer //----------------------------------------------------------------------------- std::array LobbyAssetManager::getAddonScores( const std::set& client_karts, const std::set& client_tracks) { - std::array addons_scores = {{ -1, -1, -1, -1 }}; size_t addon_kart = 0; size_t addon_track = 0; @@ -485,15 +479,13 @@ std::array LobbyAssetManager::getAddonScores( addons_scores[AS_SOCCER] = addon_soccer; } return addons_scores; -} // getAddonScores - +} // getAddonScores //----------------------------------------------------------------------------- std::string LobbyAssetManager::getAnyMapForVote() { return *m_available_kts.second.begin(); -} // getAnyMapForVote - +} // getAnyMapForVote //----------------------------------------------------------------------------- bool LobbyAssetManager::checkIfNoCommonMaps( @@ -508,15 +500,13 @@ bool LobbyAssetManager::checkIfNoCommonMaps( } } return tracks_erase.size() == m_available_kts.second.size(); -} // checkIfNoCommonMaps - +} // checkIfNoCommonMaps //----------------------------------------------------------------------------- bool LobbyAssetManager::isKartAvailable(const std::string& kart) const { return m_available_kts.first.find(kart) != m_available_kts.first.end(); -} // isKartAvailable - +} // isKartAvailable //----------------------------------------------------------------------------- float LobbyAssetManager::officialKartsFraction(const std::set& clientKarts) const @@ -528,8 +518,7 @@ float LobbyAssetManager::officialKartsFraction(const std::set& clie karts_count += 1; } return karts_count / (float)m_official_kts.first.size(); -} // officialKartsFraction - +} // officialKartsFraction //----------------------------------------------------------------------------- float LobbyAssetManager::officialMapsFraction(const std::set& clientMaps) const @@ -541,8 +530,7 @@ float LobbyAssetManager::officialMapsFraction(const std::set& clien maps_count += 1; } return maps_count / (float)m_official_kts.second.size(); -} // officialMapsFraction - +} // officialMapsFraction //----------------------------------------------------------------------------- std::string LobbyAssetManager::getRandomMap() const @@ -558,9 +546,8 @@ std::string LobbyAssetManager::getRandomMap() const std::set::iterator it = items.begin(); std::advance(it, rg.get((int)items.size())); return *it; -} // getRandomMap - -// ======================================================================== +} // getRandomMap +//----------------------------------------------------------------------------- std::string LobbyAssetManager::getRandomAddonMap() const { @@ -577,13 +564,11 @@ std::string LobbyAssetManager::getRandomAddonMap() const std::set::iterator it = items.begin(); std::advance(it, rg.get((int)items.size())); return *it; -} // getRandomAddonMap - -// ======================================================================== +} // getRandomAddonMap +//----------------------------------------------------------------------------- void LobbyAssetManager::setMustHaveMaps(const std::string& input) { m_must_have_maps = StringUtils::split(input, ' ', false); -} // setMustHaveMaps - -// ======================================================================== \ No newline at end of file +} // setMustHaveMaps +//----------------------------------------------------------------------------- diff --git a/src/utils/lobby_asset_manager.hpp b/src/utils/lobby_asset_manager.hpp index fd96265fb01..71c2b0862bf 100644 --- a/src/utils/lobby_asset_manager.hpp +++ b/src/utils/lobby_asset_manager.hpp @@ -19,18 +19,18 @@ #ifndef LOBBY_ASSET_MANAGER_HPP #define LOBBY_ASSET_MANAGER_HPP -#include "utils/types.hpp" -#include "race/race_manager.hpp" #include "network/stk_peer.hpp" - +#include "race/race_manager.hpp" +#include "utils/types.hpp" #include -#include #include +#include #include + +class NetworkString; class ServerLobby; class STKPeer; -class NetworkString; class LobbyAssetManager { @@ -38,28 +38,32 @@ class LobbyAssetManager LobbyAssetManager(ServerLobby* lobby); void init(); - void updateAddons(); void updateMapsForMode(RaceManager::MinorRaceModeType mode); void onServerSetup(); void eraseAssetsWithPeers(const std::vector>& peers); bool tryApplyingMapFilters(); std::string getRandomAvailableMap(); - void encodePlayerKartsAndCommonMaps(NetworkString* ns, const std::set& all_k); + + void encodePlayerKartsAndCommonMaps( + NetworkString* ns, const std::set& all_k); + bool handleAssetsForPeer(std::shared_ptr peer, const std::set& client_karts, const std::set& client_maps); + std::array getAddonScores( - const std::set& client_karts, - const std::set& client_maps); + const std::set& client_karts, + const std::set& client_maps); + std::string getAnyMapForVote(); bool checkIfNoCommonMaps( const std::pair, std::set>& assets); + bool isKartAvailable(const std::string& kart) const; float officialKartsFraction(const std::set& clientKarts) const; float officialMapsFraction(const std::set& clientMaps) const; - std::string getRandomMap() const; std::string getRandomAddonMap() const; @@ -108,4 +112,4 @@ class LobbyAssetManager std::vector m_must_have_maps; }; -#endif +#endif // LOBBY_ASSET_MANAGER_HPP diff --git a/src/utils/lobby_queues.cpp b/src/utils/lobby_queues.cpp index 7ce15757adc..82a5716fe37 100644 --- a/src/utils/lobby_queues.cpp +++ b/src/utils/lobby_queues.cpp @@ -17,6 +17,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "utils/lobby_queues.hpp" + #include "network/protocols/server_lobby.hpp" #include "network/server_config.hpp" #include "utils/string_utils.hpp" @@ -24,8 +25,8 @@ LobbyQueues::LobbyQueues() { loadTracksQueueFromConfig(); -} // LobbyQueues -// ======================================================================== +} // LobbyQueues +//----------------------------------------------------------------------------- void LobbyQueues::loadTracksQueueFromConfig() { @@ -35,26 +36,32 @@ void LobbyQueues::loadTracksQueueFromConfig() m_onetime_karts_queue.clear(); m_cyclic_karts_queue.clear(); - tokens = StringUtils::splitQuoted(ServerConfig::m_tracks_order, ' ', '{', '}', '\\'); + tokens = StringUtils::splitQuoted( + ServerConfig::m_tracks_order, ' ', '{', '}', '\\'); for (std::string& s: tokens) { m_onetime_tracks_queue.push_back(std::make_shared(s)); - m_cyclic_tracks_queue.push_back(std::make_shared(TrackFilter::PLACEHOLDER_STRING)); + m_cyclic_tracks_queue.push_back( + std::make_shared(TrackFilter::PLACEHOLDER_STRING)); } - tokens = StringUtils::splitQuoted(ServerConfig::m_cyclic_tracks_order, ' ', '{', '}', '\\'); + tokens = StringUtils::splitQuoted( + ServerConfig::m_cyclic_tracks_order, ' ', '{', '}', '\\'); for (std::string& s: tokens) m_cyclic_tracks_queue.push_back(std::make_shared(s)); - tokens = StringUtils::splitQuoted(ServerConfig::m_karts_order, ' ', '{', '}', '\\'); + tokens = StringUtils::splitQuoted( + ServerConfig::m_karts_order, ' ', '{', '}', '\\'); for (std::string& s: tokens) { m_onetime_karts_queue.push_back(std::make_shared(s)); - m_cyclic_karts_queue.push_back(std::make_shared(KartFilter::PLACEHOLDER_STRING)); + m_cyclic_karts_queue.push_back( + std::make_shared(KartFilter::PLACEHOLDER_STRING)); } - tokens = StringUtils::splitQuoted(ServerConfig::m_cyclic_karts_order, ' ', '{', '}', '\\'); + tokens = StringUtils::splitQuoted( + ServerConfig::m_cyclic_karts_order, ' ', '{', '}', '\\'); for (std::string& s: tokens) m_cyclic_karts_queue.push_back(std::make_shared(s)); } // loadTracksQueueFromConfig @@ -63,9 +70,8 @@ void LobbyQueues::loadTracksQueueFromConfig() void LobbyQueues::popOnRaceFinished() { if (!m_onetime_tracks_queue.empty()) - { m_onetime_tracks_queue.pop_front(); - } + if (!m_cyclic_tracks_queue.empty()) { auto item = m_cyclic_tracks_queue.front().get()->getInitialString(); @@ -74,10 +80,10 @@ void LobbyQueues::popOnRaceFinished() if (!is_placeholder) m_cyclic_tracks_queue.push_back(std::make_shared(item)); } + if (!m_onetime_karts_queue.empty()) - { m_onetime_karts_queue.pop_front(); - } + if (!m_cyclic_karts_queue.empty()) { auto item = m_cyclic_karts_queue.front().get()->getInitialString(); @@ -133,10 +139,14 @@ void LobbyQueues::applyFrontKartFilters(FilterContext& context) bool LobbyQueues::areKartFiltersIgnoringKarts() const { - if (!m_onetime_karts_queue.empty() && m_onetime_karts_queue.front()->ignoresPlayersInput()) + if (!m_onetime_karts_queue.empty() && + m_onetime_karts_queue.front()->ignoresPlayersInput()) return true; - if (!m_cyclic_karts_queue.empty() && m_cyclic_karts_queue.front()->ignoresPlayersInput()) + + if (!m_cyclic_karts_queue.empty() && + m_cyclic_karts_queue.front()->ignoresPlayersInput()) return true; + return false; } // applyAllKartFilters //----------------------------------------------------------------------------- diff --git a/src/utils/lobby_queues.hpp b/src/utils/lobby_queues.hpp index 61149836e52..f66c2b088b9 100644 --- a/src/utils/lobby_queues.hpp +++ b/src/utils/lobby_queues.hpp @@ -20,10 +20,10 @@ #define LOBBY_QUEUES_HPP #include "irrString.h" +#include "utils/track_filter.hpp" -#include #include -#include "utils/track_filter.hpp" +#include class LobbyQueues { @@ -42,21 +42,23 @@ class LobbyQueues bool areKartFiltersIgnoringKarts() const; + using Queue = std::deque>; + private: - std::deque> m_onetime_tracks_queue; + Queue m_onetime_tracks_queue; - std::deque> m_cyclic_tracks_queue; + Queue m_cyclic_tracks_queue; - std::deque> m_onetime_karts_queue; + Queue m_onetime_karts_queue; - std::deque> m_cyclic_karts_queue; + Queue m_cyclic_karts_queue; // Temporary reference getters public: - std::deque>& getOnetimeTracksQueue() { return m_onetime_tracks_queue; } - std::deque>& getCyclicTracksQueue() { return m_cyclic_tracks_queue; } - std::deque>& getOnetimeKartsQueue() { return m_onetime_karts_queue; } - std::deque>& getCyclicKartsQueue() { return m_cyclic_karts_queue; } + Queue& getOnetimeTracksQueue() { return m_onetime_tracks_queue; } + Queue& getCyclicTracksQueue() { return m_cyclic_tracks_queue; } + Queue& getOnetimeKartsQueue() { return m_onetime_karts_queue; } + Queue& getCyclicKartsQueue() { return m_cyclic_karts_queue; } }; diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index fa23e3224b3..f67308ad0f2 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -26,6 +26,7 @@ #include "network/peer_vote.hpp" #include "network/server_config.hpp" #include "network/stk_peer.hpp" +#include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/game_info.hpp" #include "utils/kart_elimination.hpp" @@ -33,7 +34,6 @@ #include "utils/lobby_queues.hpp" #include "utils/random_generator.hpp" #include "utils/string_utils.hpp" -#include "tracks/track.hpp" #include "utils/tournament.hpp" LobbySettings::LobbySettings(GameSetup* game_setup, @@ -82,8 +82,8 @@ LobbySettings::LobbySettings(GameSetup* game_setup, m_battle_hit_capture_limit = 0; m_battle_time_limit = 0.0f; m_winner_peer_id = 0; -} // LobbySettings -// ======================================================================== +} // LobbySettings +//----------------------------------------------------------------------------- LobbySettings::~LobbySettings() { @@ -130,6 +130,7 @@ void LobbySettings::initCategories() } } // initCategories //----------------------------------------------------------------------------- + void LobbySettings::initAvailableModes() { std::vector statements = @@ -188,7 +189,8 @@ bool LobbySettings::loadCustomScoring(std::string& scoring) m_scoring_type = params[0]; if (available_scoring_types.count(m_scoring_type) == 0) { - Log::warn("ServerLobby", "Unknown scoring type %s, fallback.", m_scoring_type.c_str()); + Log::warn("ServerLobby", "Unknown scoring type %s, " + "fallback.", m_scoring_type.c_str()); m_scoring_int_params = previous_params; m_scoring_type = previous_type; return false; @@ -198,7 +200,8 @@ bool LobbySettings::loadCustomScoring(std::string& scoring) int param; if (!StringUtils::fromString(params[i], param)) { - Log::warn("ServerLobby", "Unable to parse integer from custom scoring data, fallback."); + Log::warn("ServerLobby", "Unable to parse integer from custom " + "scoring data, fallback."); m_scoring_int_params = previous_params; m_scoring_type = previous_type; return false; @@ -218,21 +221,34 @@ void LobbySettings::loadWhiteList() m_usernames_white_list.insert(s); } // loadWhiteList //----------------------------------------------------------------------------- + void LobbySettings::loadPreservedSettings() { - std::vector what_to_preserve = - StringUtils::split(std::string(ServerConfig::m_preserve_on_reset), ' '); + std::vector what_to_preserve = StringUtils::split( + std::string(ServerConfig::m_preserve_on_reset), ' '); for (std::string& str: what_to_preserve) m_preserve.insert(str); -} // loadWhiteList -//----------------------------------------------------------------------------- +} // loadPreservedSettings +//----------------------------------------------------------------------------- + +int LobbySettings::getTeamForUsername(const std::string& name) +{ + auto it = m_team_for_player.find(name); + if (it == m_team_for_player.end()) + return TeamUtils::NO_TEAM; + return it->second; +} // getTeamForUsername +//----------------------------------------------------------------------------- -void LobbySettings::addMutedPlayerFor(std::shared_ptr peer, const irr::core::stringw& name) +void LobbySettings::addMutedPlayerFor(std::shared_ptr peer, + const irr::core::stringw& name) { m_peers_muted_players[std::weak_ptr(peer)].insert(name); -} +} // addMutedPlayerFor +//----------------------------------------------------------------------------- -bool LobbySettings::removeMutedPlayerFor(std::shared_ptr peer, const irr::core::stringw& name) +bool LobbySettings::removeMutedPlayerFor(std::shared_ptr peer, + const irr::core::stringw& name) { // I'm not sure why the implementation was so long auto& collection = m_peers_muted_players[std::weak_ptr(peer)]; @@ -247,16 +263,19 @@ bool LobbySettings::removeMutedPlayerFor(std::shared_ptr peer, const ir it++; } return false; -} +} // removeMutedPlayerFor +//----------------------------------------------------------------------------- -bool LobbySettings::isMuting(std::shared_ptr peer, const irr::core::stringw& name) const +bool LobbySettings::isMuting(std::shared_ptr peer, + const irr::core::stringw& name) const { auto it = m_peers_muted_players.find(std::weak_ptr(peer)); if (it == m_peers_muted_players.end()) return false; return it->second.find(name) != it->second.end(); -} +} // isMuting +//----------------------------------------------------------------------------- std::string LobbySettings::getMutedPlayersAsString(std::shared_ptr peer) { @@ -276,12 +295,14 @@ std::string LobbySettings::getMutedPlayersAsString(std::shared_ptr peer response += StringUtils::insertValues(" muted (total: %s)", num_players); } return response; -} +} // getMutedPlayersAsString +//----------------------------------------------------------------------------- void LobbySettings::addTeamSpeaker(std::shared_ptr peer) { m_team_speakers.insert(peer); -} +} // addTeamSpeaker +//----------------------------------------------------------------------------- void LobbySettings::setMessageReceiversFor(std::shared_ptr peer, const std::vector& receivers) @@ -290,76 +311,90 @@ void LobbySettings::setMessageReceiversFor(std::shared_ptr peer, thing.clear(); for (unsigned i = 0; i < receivers.size(); ++i) thing.insert(StringUtils::utf8ToWide(receivers[i])); -} +} // setMessageReceiversFor +//----------------------------------------------------------------------------- -std::set LobbySettings::getMessageReceiversFor(std::shared_ptr peer) const +std::set LobbySettings::getMessageReceiversFor( + std::shared_ptr peer) const { auto it = m_message_receivers.find(peer); if (it == m_message_receivers.end()) return {}; return it->second; -} +} // getMessageReceiversFor +//----------------------------------------------------------------------------- bool LobbySettings::isTeamSpeaker(std::shared_ptr peer) const { return m_team_speakers.find(peer) != m_team_speakers.end(); -} +} // isTeamSpeaker +//----------------------------------------------------------------------------- void LobbySettings::makeChatPublicFor(std::shared_ptr peer) { m_message_receivers[peer].clear(); m_team_speakers.erase(peer); -} +} // makeChatPublicFor +//----------------------------------------------------------------------------- bool LobbySettings::hasNoLapRestrictions() const { return m_default_lap_multiplier < 0. && m_fixed_lap < 0; -} +} // hasNoLapRestrictions +//----------------------------------------------------------------------------- bool LobbySettings::hasMultiplier() const { return m_default_lap_multiplier >= 0.; -} +} // hasMultiplier +//----------------------------------------------------------------------------- bool LobbySettings::hasFixedLapCount() const { return m_fixed_lap >= 0; -} +} // hasFixedLapCount +//----------------------------------------------------------------------------- int LobbySettings::getMultiplier() const { return m_default_lap_multiplier; -} +} // getMultiplier +//----------------------------------------------------------------------------- int LobbySettings::getFixedLapCount() const { return m_fixed_lap; -} +} // getFixedLapCount +//----------------------------------------------------------------------------- void LobbySettings::setMultiplier(int new_value) { m_default_lap_multiplier = new_value; m_fixed_lap = -1; -} +} // setMultiplier +//----------------------------------------------------------------------------- void LobbySettings::setFixedLapCount(int new_value) { m_fixed_lap = new_value; m_default_lap_multiplier = -1; -} +} // setFixedLapCount +//----------------------------------------------------------------------------- void LobbySettings::resetLapRestrictions() { m_default_lap_multiplier = -1; m_fixed_lap = -1; -} +} // resetLapRestrictions +//----------------------------------------------------------------------------- void LobbySettings::setDefaultLapRestrictions() { m_default_lap_multiplier = ServerConfig::m_auto_game_time_ratio; m_fixed_lap = ServerConfig::m_fixed_lap_count; -} +} // setDefaultLapRestrictions +//----------------------------------------------------------------------------- std::string LobbySettings::getLapRestrictionsAsString() const { @@ -378,7 +413,8 @@ std::string LobbySettings::getLapRestrictionsAsString() const return StringUtils::insertValues( "An error: game length is both %f x default and %d", m_default_lap_multiplier, m_fixed_lap); -} +} // getLapRestrictionsAsString +//----------------------------------------------------------------------------- std::string LobbySettings::getDirectionAsString(bool just_edited) const { @@ -393,7 +429,8 @@ std::string LobbySettings::getDirectionAsString(bool just_edited) const msg += (m_fixed_direction == 0 ? "forward" : "reverse"); } return msg; -} +} // getDirectionAsString +//----------------------------------------------------------------------------- bool LobbySettings::setDirection(int x) { @@ -402,27 +439,32 @@ bool LobbySettings::setDirection(int x) m_fixed_direction = x; return true; -} +} // setDirection +//----------------------------------------------------------------------------- bool LobbySettings::hasFixedDirection() const { return m_fixed_direction != -1; -} +} // hasFixedDirection +//----------------------------------------------------------------------------- int LobbySettings::getDirection() const { return m_fixed_direction; -} +} // getDirection +//----------------------------------------------------------------------------- bool LobbySettings::isAllowedToStart() const { return m_allowed_to_start; -} +} // isAllowedToStart +//----------------------------------------------------------------------------- void LobbySettings::setAllowedToStart(bool value) { m_allowed_to_start = value; -} +} // setAllowedToStart +//----------------------------------------------------------------------------- std::string LobbySettings::getAllowedToStartAsString(bool just_edited) const { @@ -432,17 +474,20 @@ std::string LobbySettings::getAllowedToStartAsString(bool just_edited) const return prefix + "allowed"; else return prefix + "forbidden"; -} +} // getAllowedToStartAsString +//----------------------------------------------------------------------------- bool LobbySettings::isGPGridShuffled() const { return m_shuffle_gp; -} +} // isGPGridShuffled +//----------------------------------------------------------------------------- void LobbySettings::setGPGridShuffled(bool value) { m_shuffle_gp = value; -} +} // setGPGridShuffled +//----------------------------------------------------------------------------- std::string LobbySettings::getWhetherShuffledGPGridAsString(bool just_edited) const { @@ -452,9 +497,11 @@ std::string LobbySettings::getWhetherShuffledGPGridAsString(bool just_edited) co return prefix + "sorted by score"; else return prefix + "shuffled"; -} +} // getWhetherShuffledGPGridAsString +//----------------------------------------------------------------------------- -std::vector LobbySettings::getMissingAssets(std::shared_ptr peer) const +std::vector LobbySettings::getMissingAssets( + std::shared_ptr peer) const { if (m_play_requirement_tracks.empty()) return {}; @@ -486,7 +533,8 @@ void LobbySettings::updateWorldSettings(std::shared_ptr game_info) else if (policy == "advanced") sw->setGoalScoringPolicy(2); else - Log::warn("LobbySettings", "Soccer goals policy %s does not exist", policy.c_str()); + Log::warn("LobbySettings", "Soccer goals policy %s " + "does not exist", policy.c_str()); } } // updateWorldSettings //----------------------------------------------------------------------------- @@ -500,7 +548,7 @@ void LobbySettings::onResetToDefaultSettings() if (!m_preserve.count("laps")) { - // Note that we don't reset restrictions, but set them to those in config + // We don't reset restrictions, but set them to those in config setDefaultLapRestrictions(); } @@ -510,11 +558,13 @@ void LobbySettings::onResetToDefaultSettings() if (!m_preserve.count("replay")) setConsentOnReplays(false); } // onResetToDefaultSettings +//----------------------------------------------------------------------------- bool LobbySettings::isPreservingMode() const { return m_preserve.find("mode") != m_preserve.end(); -} +} // isPreservingMode +//----------------------------------------------------------------------------- std::string LobbySettings::getScoringAsString() const { @@ -523,19 +573,22 @@ std::string LobbySettings::getScoringAsString() const msg += StringUtils::insertValues(" %d", param); msg += "\""; return msg; -} +} // getScoringAsString +//----------------------------------------------------------------------------- void LobbySettings::addPlayerToCategory(const std::string& player, const std::string& category) { m_player_categories[category].insert(player); m_categories_for_player[player].insert(category); -} +} // addPlayerToCategory +//----------------------------------------------------------------------------- void LobbySettings::erasePlayerFromCategory(const std::string& player, const std::string& category) { m_player_categories[category].erase(player); m_categories_for_player[player].erase(category); -} +} // erasePlayerFromCategory +//----------------------------------------------------------------------------- void LobbySettings::makeCategoryVisible(const std::string category, bool value) { @@ -544,12 +597,14 @@ void LobbySettings::makeCategoryVisible(const std::string category, bool value) } else { m_hidden_categories.insert(category); } -} +} // makeCategoryVisible +//----------------------------------------------------------------------------- bool LobbySettings::isCategoryVisible(const std::string category) const { return m_hidden_categories.find(category) == m_hidden_categories.end(); -} +} // isCategoryVisible +//----------------------------------------------------------------------------- std::vector LobbySettings::getVisibleCategoriesForPlayer(const std::string& profile_name) const { @@ -563,7 +618,8 @@ std::vector LobbySettings::getVisibleCategoriesForPlayer(const std: res.push_back(category); return res; -} +} // getVisibleCategoriesForPlayer +//----------------------------------------------------------------------------- std::set LobbySettings::getPlayersInCategory(const std::string& category) const @@ -573,7 +629,8 @@ std::set LobbySettings::getPlayersInCategory(const std::string& cat return {}; return it->second; -} +} // getPlayersInCategory +//----------------------------------------------------------------------------- std::string LobbySettings::getPreservedSettingsAsString() const { @@ -581,17 +638,20 @@ std::string LobbySettings::getPreservedSettingsAsString() const for (const std::string& str: m_preserve) msg += " " + str; return msg; -} +} // getPreservedSettingsAsString +//----------------------------------------------------------------------------- void LobbySettings::eraseFromPreserved(const std::string& value) { m_preserve.erase(value); -} +} // eraseFromPreserved +//----------------------------------------------------------------------------- void LobbySettings::insertIntoPreserved(const std::string& value) { m_preserve.insert(value); -} +} // insertIntoPreserved +//----------------------------------------------------------------------------- void LobbySettings::clearAllExpiredWeakPtrs() { @@ -603,7 +663,8 @@ void LobbySettings::clearAllExpiredWeakPtrs() else it++; } -} +} // clearAllExpiredWeakPtrs +//----------------------------------------------------------------------------- void LobbySettings::initializeDefaultVote() { @@ -674,17 +735,20 @@ void LobbySettings::initializeDefaultVote() assert(false); break; } -} +} // initializeDefaultVote +//----------------------------------------------------------------------------- void LobbySettings::applyGlobalFilter(FilterContext& map_context) const { m_global_filter.apply(map_context); -} +} // applyGlobalFilter +//----------------------------------------------------------------------------- void LobbySettings::applyGlobalKartsFilter(FilterContext& kart_context) const { m_global_karts_filter.apply(kart_context); -} +} // applyGlobalKartsFilter +//----------------------------------------------------------------------------- void LobbySettings::applyRestrictionsOnVote(PeerVote* vote, Track* t) const { @@ -741,46 +805,53 @@ void LobbySettings::applyRestrictionsOnVote(PeerVote* vote, Track* t) const } if (hasFixedDirection()) vote->m_reverse = (getDirection() == 1); -} +} // applyRestrictionsOnVote +//----------------------------------------------------------------------------- void LobbySettings::encodeDefaultVote(NetworkString* ns) const { ns->addUInt32(m_winner_peer_id); m_default_vote->encode(ns); -} +} // encodeDefaultVote +//----------------------------------------------------------------------------- void LobbySettings::setDefaultVote(PeerVote winner_vote) { *m_default_vote = winner_vote; -} +} // setDefaultVote +//----------------------------------------------------------------------------- PeerVote LobbySettings::getDefaultVote() const { return *m_default_vote; -} +} // getDefaultVote +//----------------------------------------------------------------------------- void LobbySettings::onPeerDisconnect(std::shared_ptr peer) { m_message_receivers.erase(peer); -} +} // onPeerDisconnect +//----------------------------------------------------------------------------- bool LobbySettings::isInWhitelist(const std::string& username) const { return m_usernames_white_list.find(username) != m_usernames_white_list.end(); -} - +} // isInWhitelist +//----------------------------------------------------------------------------- bool LobbySettings::isModeAvailable(int mode) const { return m_available_modes.find(mode) != m_available_modes.end(); -} +} // isModeAvailable +//----------------------------------------------------------------------------- bool LobbySettings::isDifficultyAvailable(int difficulty) const { return m_available_difficulties.find(difficulty) != m_available_difficulties.end(); -} +} // isDifficultyAvailable +//----------------------------------------------------------------------------- void LobbySettings::applyPermutationToTeams(const std::map& permutation) { @@ -790,7 +861,8 @@ void LobbySettings::applyPermutationToTeams(const std::map& permutatio if (it != permutation.end()) p.second = it->second; } -} +} // applyPermutationToTeams +//----------------------------------------------------------------------------- std::string LobbySettings::getAvailableTeams() const { @@ -799,5 +871,4 @@ std::string LobbySettings::getAvailableTeams() const return m_available_teams; } // getAvailableTeams - -//----------------------------------------------------------------------------- \ No newline at end of file +//----------------------------------------------------------------------------- diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 62508ad37d4..03553bb50fb 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -20,22 +20,21 @@ #define LOBBY_SETTINGS_HPP #include "irrString.h" - -// kimden: probably should be removed later -#include "utils/track_filter.hpp" #include "utils/team_utils.hpp" +#include "utils/track_filter.hpp" #include + class GameSetup; -class LobbyQueues; class KartElimination; -class STKPeer; -class PeerVote; -class NetworkString; class LobbyAssetManager; -class GameInfo; -class Track; +class LobbyQueues; +class NetworkString; +class PeerVote; +class STKPeer; class Tournament; +class Track; +struct GameInfo; /** @brief A class that manipulates server settings, such as resetting, * scoring, goal policies, etc. Might be split into a few parts later, @@ -56,20 +55,13 @@ class LobbySettings bool loadCustomScoring(std::string& scoring); void loadWhiteList(); void loadPreservedSettings(); - bool hasConsentOnReplays() const { return m_consent_on_replays; } void setConsentOnReplays(bool value) { m_consent_on_replays = value; } std::string getInternalAvailableTeams() const { return m_available_teams; } void setInternalAvailableTeams(std::string& s) { m_available_teams = s; } void setTeamForUsername(const std::string& name, int team) { m_team_for_player[name] = team; } - int getTeamForUsername(const std::string& name) - { - auto it = m_team_for_player.find(name); - if (it == m_team_for_player.end()) - return TeamUtils::NO_TEAM; - return it->second; - } + int getTeamForUsername(const std::string& name); void clearTeams() { m_team_for_player.clear(); } bool hasTeam(const std::string& name) { return m_team_for_player.find(name) != m_team_for_player.end(); } @@ -78,13 +70,18 @@ class LobbySettings std::string getHelpMessage() const { return m_help_message; } std::string getMotd() const { return m_motd; } - void addMutedPlayerFor(std::shared_ptr peer, const irr::core::stringw& name); - bool removeMutedPlayerFor(std::shared_ptr peer, const irr::core::stringw& name); - bool isMuting(std::shared_ptr peer, const irr::core::stringw& name) const; + void addMutedPlayerFor(std::shared_ptr peer, + const irr::core::stringw& name); + bool removeMutedPlayerFor(std::shared_ptr peer, + const irr::core::stringw& name); + bool isMuting(std::shared_ptr peer, + const irr::core::stringw& name) const; std::string getMutedPlayersAsString(std::shared_ptr peer); void addTeamSpeaker(std::shared_ptr peer); - void setMessageReceiversFor(std::shared_ptr peer, const std::vector& receivers); - std::set getMessageReceiversFor(std::shared_ptr peer) const; + void setMessageReceiversFor(std::shared_ptr peer, + const std::vector& receivers); + std::set getMessageReceiversFor( + std::shared_ptr peer) const; bool isTeamSpeaker(std::shared_ptr peer) const; void makeChatPublicFor(std::shared_ptr peer); bool hasNoLapRestrictions() const; @@ -156,7 +153,7 @@ class LobbySettings std::shared_ptr m_tournament; -// These are fine here =============================================================================== +// These are fine here ======================================================== int m_battle_hit_capture_limit; @@ -203,7 +200,7 @@ class LobbySettings std::string m_available_teams; -// These should be moved to voting manager =========================================================== +// These should be moved to voting manager ==================================== // Default game settings if no one has ever vote, and save inside here for // final vote (for live join) @@ -212,7 +209,7 @@ class LobbySettings uint32_t m_winner_peer_id; -// These should be moved to chat handler ============================================================= +// These should be moved to chat handler ====================================== std::map, std::set, std::owner_less > > m_peers_muted_players; @@ -222,7 +219,7 @@ class LobbySettings std::set> m_team_speakers; -// These should be moved to category and team manager ================================================ +// These should be moved to category and team manager ========================= std::map> m_player_categories; @@ -236,4 +233,4 @@ class LobbySettings }; -#endif \ No newline at end of file +#endif // LOBBY_SETTINGS_HPP \ No newline at end of file diff --git a/src/utils/map_vote_handler.cpp b/src/utils/map_vote_handler.cpp index 3d5c8a6b142..975412fb43b 100644 --- a/src/utils/map_vote_handler.cpp +++ b/src/utils/map_vote_handler.cpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2024 kimden +// Copyright (C) 2024-2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -16,23 +16,23 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#include "utils/map_vote_handler.hpp" -#include "utils/string_utils.hpp" +#include "utils/lobby_settings.hpp" #include "utils/log.hpp" +#include "utils/map_vote_handler.hpp" #include "utils/random_generator.hpp" -#include "utils/lobby_settings.hpp" +#include "utils/string_utils.hpp" MapVoteHandler::MapVoteHandler(std::shared_ptr settings) : algorithm(0), m_lobby_settings(settings) { } // MapVoteHandler -// ============================================================================ +//----------------------------------------------------------------------------- template -void MapVoteHandler::findMajorityValue(const std::map& choices, unsigned cur_players, - T* best_choice, float* rate) +void MapVoteHandler::findMajorityValue(const std::map& choices, + unsigned cur_players, T* best_choice, float* rate) { RandomGenerator rg; unsigned max_votes = 0; @@ -64,7 +64,7 @@ void MapVoteHandler::findMajorityValue(const std::map& choices, uns *rate = float(best_iter->second) / cur_players; } } // findMajorityValue -// ============================================================================ +//----------------------------------------------------------------------------- bool MapVoteHandler::handleAllVotes(std::map& peers_votes, float remaining_time, float max_time, bool is_over, @@ -72,11 +72,13 @@ bool MapVoteHandler::handleAllVotes(std::map& peers_votes, PeerVote* winner_vote) const { if (algorithm == 0) - return standard(peers_votes, remaining_time, max_time, is_over, cur_players, winner_vote); + return standard(peers_votes, remaining_time, max_time, + is_over, cur_players, winner_vote); else // if (algorithm == 1) - return random(peers_votes, remaining_time, max_time, is_over, cur_players, winner_vote); + return random(peers_votes, remaining_time, max_time, + is_over, cur_players, winner_vote); } // handleAllVotes -// ============================================================================ +//----------------------------------------------------------------------------- bool MapVoteHandler::random(std::map& peers_votes, float remaining_time, float max_time, bool is_over, @@ -99,7 +101,7 @@ bool MapVoteHandler::random(std::map& peers_votes, *winner_vote = it->second; return true; } // random -// ============================================================================ +//----------------------------------------------------------------------------- bool MapVoteHandler::standard(std::map& peers_votes, float remaining_time, float max_time, bool is_over, @@ -156,9 +158,9 @@ bool MapVoteHandler::standard(std::map& peers_votes, reverse_vote->second++; } - findMajorityValue(tracks, cur_players, &top_track, &tracks_rate); - findMajorityValue(laps, cur_players, &top_laps, &laps_rate); - findMajorityValue(reverses, cur_players, &top_reverse, &reverses_rate); + findMajorityValue(tracks, cur_players, &top_track, &tracks_rate); + findMajorityValue (laps, cur_players, &top_laps, &laps_rate); + findMajorityValue (reverses, cur_players, &top_reverse, &reverses_rate); // End early if there is majority agreement which is all entries rate > 0.5 auto it = peers_votes.begin(); @@ -208,5 +210,5 @@ bool MapVoteHandler::standard(std::map& peers_votes, return true; } return false; -} // standard -// ======================================================================== +} // standard +//----------------------------------------------------------------------------- diff --git a/src/utils/map_vote_handler.hpp b/src/utils/map_vote_handler.hpp index b2967e0cbb7..9d061b4b2bb 100644 --- a/src/utils/map_vote_handler.hpp +++ b/src/utils/map_vote_handler.hpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2024 kimden +// Copyright (C) 2024-2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -20,16 +20,16 @@ #define MAP_VOTE_HANDLER_HPP #include "irrString.h" +#include "network/peer_vote.hpp" #include #include +#include #include -#include #include -#include -class LobbySettings; +#include -#include "network/peer_vote.hpp" +class LobbySettings; // A class containing different implementations for handling map votes // in a server lobby. @@ -47,25 +47,24 @@ class MapVoteHandler std::shared_ptr m_lobby_settings; template - static void findMajorityValue(const std::map& choices, unsigned cur_players, - T* best_choice, float* rate); + static void findMajorityValue(const std::map& choices, + unsigned cur_players, T* best_choice, float* rate); bool standard(std::map& peers_votes, - float remaining_time, float max_time, bool is_over, - unsigned cur_players, - PeerVote* winner_vote) const; + float remaining_time, float max_time, bool is_over, + unsigned cur_players, PeerVote* winner_vote) const; + bool random(std::map& peers_votes, - float remaining_time, float max_time, bool is_over, - unsigned cur_players, - PeerVote* winner_vote) const; + float remaining_time, float max_time, bool is_over, + unsigned cur_players, PeerVote* winner_vote) const; public: MapVoteHandler(std::shared_ptr settings); - void setAlgorithm(int x) { algorithm = x; } - int getAlgorithm() const { return algorithm; } + void setAlgorithm(int x) { algorithm = x; } + int getAlgorithm() const { return algorithm; } + bool handleAllVotes(std::map& peers_votes, - float remaining_time, float max_time, bool is_over, - unsigned cur_players, - PeerVote* winner_vote) const; + float remaining_time, float max_time, bool is_over, + unsigned cur_players, PeerVote* winner_vote) const; }; #endif // MAP_VOTE_HANDLER_HPP diff --git a/src/utils/set_typo_fixer.cpp b/src/utils/set_typo_fixer.cpp index 4fa6241691b..220a15fc23a 100644 --- a/src/utils/set_typo_fixer.cpp +++ b/src/utils/set_typo_fixer.cpp @@ -23,23 +23,23 @@ void SetTypoFixer::add(const std::string& key) { m_set.insert(key); m_map[key] = key; -} // add -// ======================================================================== +} // add (1) +//----------------------------------------------------------------------------- void SetTypoFixer::add(const std::string& key, const std::string& value) { m_set.insert(key); m_map[key] = value; -} // add -// ======================================================================== +} // add (2) +//----------------------------------------------------------------------------- void SetTypoFixer::remove(const std::string& key) { m_set.erase(m_set.find(key)); if (m_set.find(key) == m_set.end()) m_map.erase(key); -} // remove -// ======================================================================== +} // remove +//----------------------------------------------------------------------------- std::vector> SetTypoFixer::getClosest( const std::string& query, int count, bool case_sensitive) const @@ -68,8 +68,9 @@ std::vector> SetTypoFixer::getClosest( } for (const auto& p: ans_map) ans.emplace_back(p.first, p.second); - std::sort(ans.begin(), ans.end(), - [](const std::pair& a, const std::pair& b) -> bool + std::sort(ans.begin(), ans.end(), [] + (const std::pair& a, + const std::pair& b) -> bool { if (a.second != b.second) return a.second < b.second; @@ -78,5 +79,5 @@ std::vector> SetTypoFixer::getClosest( if ((int)ans.size() > count) ans.resize(count); return ans; -} // getClosest -// ======================================================================== +} // getClosest +//----------------------------------------------------------------------------- diff --git a/src/utils/set_typo_fixer.hpp b/src/utils/set_typo_fixer.hpp index f44b598d235..a961124a746 100644 --- a/src/utils/set_typo_fixer.hpp +++ b/src/utils/set_typo_fixer.hpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2021-2022 kimden +// Copyright (C) 2021-2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -23,10 +23,10 @@ #include #include +#include #include -#include #include -#include +#include // A lazy class that stores a set of strings. // For a query string, it finds exactly the same string in the set @@ -45,6 +45,7 @@ class SetTypoFixer void add(const std::string& key, const std::string& value); void remove(const std::string& key); std::vector> getClosest( - const std::string& query, int count = 3, bool case_sensitive = true) const; + const std::string& query, int count = 3, + bool case_sensitive = true) const; }; #endif // SET_TYPO_FIXER_HPP diff --git a/src/utils/set_with_flip.hpp b/src/utils/set_with_flip.hpp index ef7f4fa451b..8130fbefec7 100644 --- a/src/utils/set_with_flip.hpp +++ b/src/utils/set_with_flip.hpp @@ -20,6 +20,7 @@ #define SET_WITH_FLIP_HPP #include "utils/log.hpp" + #include enum Op: int @@ -64,7 +65,8 @@ class SetWithFlip: public std::set case SWF_OP_FLIP: return flip(element); } - Log::warn("SetWithFlip", "Invalid type = %d encountered, defaulting to flip (%d).", type, SWF_OP_FLIP); + Log::warn("SetWithFlip", "Invalid type = %d encountered, " + "defaulting to flip (%d).", type, SWF_OP_FLIP); return flip(element); } }; diff --git a/src/utils/team_utils.cpp b/src/utils/team_utils.cpp index a35a2743ede..2e78fbb0f5b 100644 --- a/src/utils/team_utils.cpp +++ b/src/utils/team_utils.cpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2024 kimden +// Copyright (C) 2024-2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -29,28 +29,28 @@ void TeamManager::addTeam(std::string hardcoded_code, hardcoded_color, hardcoded_emoji); m_finder_by_code[hardcoded_code] = index; m_finder_by_name[hardcoded_name] = index; -} // addTeam -// ======================================================================== +} // addTeam +//----------------------------------------------------------------------------- void TeamManager::addCode(int idx, std::string hardcoded_code) { m_teams[idx].addCode(hardcoded_code); m_finder_by_code[hardcoded_code] = idx; -} // addCode -// ======================================================================== +} // addCode +//----------------------------------------------------------------------------- void TeamManager::addName(int idx, std::string hardcoded_name) { m_teams[idx].addName(hardcoded_name); m_finder_by_name[hardcoded_name] = idx; -} // addName -// ======================================================================== +} // addName +//----------------------------------------------------------------------------- const CustomTeam& TeamManager::operator[](int idx) const { return m_teams[idx]; -} // getTeamByIndex -// ======================================================================== +} // getTeamByIndex +//----------------------------------------------------------------------------- int TeamManager::getIndexByCode(const std::string& code) const { @@ -60,8 +60,8 @@ int TeamManager::getIndexByCode(const std::string& code) const // breaks something. Check out the neighboring comment too return 0; return it->second; -} // getIndexByCode -// ======================================================================== +} // getIndexByCode +//----------------------------------------------------------------------------- int TeamManager::getIndexByName(const std::string& name) const { @@ -71,8 +71,8 @@ int TeamManager::getIndexByName(const std::string& name) const // breaks something. Check out the neighboring comment too return 0; return it->second; -} // getIndexByName -// ======================================================================== +} // getIndexByName +//----------------------------------------------------------------------------- TeamManager::TeamManager() { @@ -89,6 +89,6 @@ TeamManager::TeamManager() addCode(6, "v"); addName(6, "violet"); addName(8, "pink"); -} // TeamManager -// ======================================================================== +} // TeamManager +//----------------------------------------------------------------------------- diff --git a/src/utils/team_utils.hpp b/src/utils/team_utils.hpp index 628a89dd986..e37be6294a1 100644 --- a/src/utils/team_utils.hpp +++ b/src/utils/team_utils.hpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2024 kimden +// Copyright (C) 2024-2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -24,10 +24,10 @@ #include #include +#include #include -#include #include -#include +#include // A set of classes that will manipulate teams, their names // and representations such as emojis, and probably something else @@ -60,8 +60,8 @@ class CustomTeam std::string getNameWithEmoji() const { return m_emoji + " " + m_names[0]; } float getColor() const { return m_color; } std::string getEmoji() const { return m_emoji; } - void addCode(const std::string& code) { m_codes.push_back(code); } - void addName(const std::string& name) { m_names.push_back(name); } + void addCode(const std::string& code) { m_codes.push_back(code); } + void addName(const std::string& name) { m_names.push_back(name); } }; class TeamManager diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp index b5486ccb684..cd93fd77ddd 100644 --- a/src/utils/tournament.cpp +++ b/src/utils/tournament.cpp @@ -34,29 +34,32 @@ namespace static int g_history_limit = 100; } -Tournament::Tournament(ServerLobby* lobby, std::shared_ptr settings) +Tournament::Tournament(ServerLobby* lobby, + std::shared_ptr settings) : m_lobby(lobby), m_lobby_settings(settings) { initTournamentPlayers(); - m_tournament_game = 0; + m_game = 0; m_extra_seconds = 0.0f; -} // Tournament -// ======================================================================== +} // Tournament +//----------------------------------------------------------------------------- void Tournament::applyFiltersForThisGame(FilterContext& track_context) { - track_context.wildcards = m_tournament_arenas; - m_tournament_track_filters[m_tournament_game].apply(track_context); -} + track_context.wildcards = m_arenas; + m_track_filters[m_game].apply(track_context); +} // applyFiltersForThisGame +//----------------------------------------------------------------------------- std::set Tournament::getThoseWhoSeeTeamchats() const { std::set sees_teamchats; - for (const std::string& s: m_tournament_referees) { + for (const std::string& s: m_referees) { sees_teamchats.insert(s); } return sees_teamchats; -} +} // getThoseWhoSeeTeamchats +//----------------------------------------------------------------------------- bool Tournament::checkSenderInRefsOrPlayers(std::shared_ptr sender) const { @@ -66,50 +69,55 @@ bool Tournament::checkSenderInRefsOrPlayers(std::shared_ptr sender) con { std::string name = StringUtils::wideToUtf8( profile->getName()); - if (m_tournament_referees.count(name) > 0 || - m_tournament_red_players.count(name) > 0 || - m_tournament_blue_players.count(name) > 0) + if (m_referees.count(name) > 0 || + m_red_players.count(name) > 0 || + m_blue_players.count(name) > 0) { return true; } } return false; -} +} // checkSenderInRefsOrPlayers +//----------------------------------------------------------------------------- std::set Tournament::getImportantChatPlayers() const { std::set important_players; - if (m_tournament_limited_chat) + if (m_limited_chat) { - for (const std::string& s: m_tournament_referees) + for (const std::string& s: m_referees) important_players.insert(s); - for (const std::string& s: m_tournament_red_players) + for (const std::string& s: m_red_players) important_players.insert(s); - for (const std::string& s: m_tournament_blue_players) + for (const std::string& s: m_blue_players) important_players.insert(s); } - for (const std::string& s: m_tournament_mutealls) + for (const std::string& s: m_mutealls) important_players.insert(s); return important_players; -} +} // getImportantChatPlayers +//----------------------------------------------------------------------------- void Tournament::fillNextArena(const std::string& track_name) { - if (m_tournament_game >= (int)m_tournament_arenas.size()) - m_tournament_arenas.resize(m_tournament_game + 1, ""); - m_tournament_arenas[m_tournament_game] = track_name; -} + if (m_game >= (int)m_arenas.size()) + m_arenas.resize(m_game + 1, ""); + m_arenas[m_game] = track_name; +} // fillNextArena +//----------------------------------------------------------------------------- void Tournament::applyRestrictionsOnDefaultVote(PeerVote* default_vote) const { - default_vote->m_num_laps = m_tournament_length; + default_vote->m_num_laps = m_length; default_vote->m_reverse = false; -} +} // applyRestrictionsOnDefaultVote +//----------------------------------------------------------------------------- void Tournament::applyRestrictionsOnVote(PeerVote* vote) const { vote->m_reverse = false; -} +} // applyRestrictionsOnVote +//----------------------------------------------------------------------------- void Tournament::onRaceFinished() const { @@ -119,7 +127,8 @@ void Tournament::onRaceFinished() const SoccerWorld *sw = dynamic_cast(w); sw->tellCountIfDiffers(); } -} +} // onRaceFinished +//----------------------------------------------------------------------------- void Tournament::updateTournamentRole(std::shared_ptr peer) { @@ -131,9 +140,9 @@ void Tournament::updateTournamentRole(std::shared_ptr peer) { core::stringw name = player->getName(); std::string utf8_name = StringUtils::wideToUtf8(name); - if (m_tournament_red_players.count(utf8_online_name)) + if (m_red_players.count(utf8_online_name)) m_lobby->setTeamInLobby(player, KART_TEAM_RED); - else if (m_tournament_blue_players.count(utf8_online_name)) + else if (m_blue_players.count(utf8_online_name)) m_lobby->setTeamInLobby(player, KART_TEAM_BLUE); else m_lobby->setTeamInLobby(player, KART_TEAM_NONE); @@ -152,14 +161,14 @@ KartTeam Tournament::getTeam(std::string utf8_online_name) const { bool swapped = hasColorsSwapped(); - if (m_tournament_red_players.count(utf8_online_name)) + if (m_red_players.count(utf8_online_name)) { if (swapped) return KART_TEAM_BLUE; return KART_TEAM_RED; } - if (m_tournament_blue_players.count(utf8_online_name)) + if (m_blue_players.count(utf8_online_name)) { if (swapped) return KART_TEAM_RED; @@ -167,26 +176,30 @@ KartTeam Tournament::getTeam(std::string utf8_online_name) const } return KART_TEAM_NONE; -} +} // getTeam +//----------------------------------------------------------------------------- bool Tournament::hasGoalsLimit() const { - return m_tournament_game_limits[m_tournament_game] == 'G'; + return m_game_limits[m_game] == 'G'; } // hasGoalsLimit //----------------------------------------------------------------------------- + bool Tournament::hasGoalsLimit(int game) const { - return m_tournament_game_limits[game] == 'G'; + return m_game_limits[game] == 'G'; } // hasGoalsLimit //----------------------------------------------------------------------------- + bool Tournament::hasColorsSwapped() const { - return m_tournament_colors[m_tournament_game] == 'B'; + return m_colors[m_game] == 'B'; } // hasColorsSwapped //----------------------------------------------------------------------------- + bool Tournament::hasColorsSwapped(int game) const { - return m_tournament_colors[game] == 'B'; + return m_colors[game] == 'B'; } // hasColorsSwapped //----------------------------------------------------------------------------- @@ -206,37 +219,37 @@ void Tournament::initTournamentPlayers() { std::string cat_name = s.substr(1); std::set& dest = ( - type == "R" ? m_tournament_red_players : - type == "B" ? m_tournament_blue_players : - m_tournament_referees); + type == "R" ? m_red_players : + type == "B" ? m_blue_players : + m_referees); for (const std::string& member: m_lobby_settings->getCategories()[cat_name]) dest.insert(member); } else if (type == "R") - m_tournament_red_players.insert(s); + m_red_players.insert(s); else if (type == "B") - m_tournament_blue_players.insert(s); + m_blue_players.insert(s); else if (type == "J") - m_tournament_referees.insert(s); + m_referees.insert(s); } - for (const std::string& s: m_tournament_red_players) + for (const std::string& s: m_red_players) { Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to r", s.c_str()); } - for (const std::string& s: m_tournament_blue_players) + for (const std::string& s: m_blue_players) { Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to b", s.c_str()); } - for (const std::string& s: m_tournament_referees) + for (const std::string& s: m_referees) { Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to j", s.c_str()); } - m_tournament_init_red = m_tournament_red_players; - m_tournament_init_blue = m_tournament_blue_players; - m_tournament_init_ref = m_tournament_referees; + m_init_red = m_red_players; + m_init_blue = m_blue_players; + m_init_ref = m_referees; // Init tournament format tokens = StringUtils::split( @@ -272,156 +285,171 @@ void Tournament::initTournamentPlayers() } Log::info("ServerLobby", "SoccerMatchLog: Tournament rules are set to \"%s\"", ServerConfig::m_soccer_tournament_rules.c_str()); - m_tournament_limited_chat = false; - m_tournament_length = 10; + m_limited_chat = false; + m_length = 10; if (general[0] == "nochat") - m_tournament_limited_chat = true; - if (StringUtils::parseString(general[1], &m_tournament_length)) + m_limited_chat = true; + if (StringUtils::parseString(general[1], &m_length)) { - if (m_tournament_length <= 0) - m_tournament_length = 10; + if (m_length <= 0) + m_length = 10; } else - m_tournament_length = 10; - ServerConfig::m_fixed_lap_count = m_tournament_length; - - m_tournament_game_limits = general[2]; - m_tournament_colors = general[3]; - m_tournament_max_games = std::min(general[2].length(), general[3].length()); - m_tournament_max_games = std::min(m_tournament_max_games, (int)tokens.size() - 1); - m_tournament_votability = general[4]; - for (int i = 0; i < m_tournament_max_games; i++) - m_tournament_track_filters.emplace_back(tokens[i + 1]); + m_length = 10; + ServerConfig::m_fixed_lap_count = m_length; + + m_game_limits = general[2]; + m_colors = general[3]; + m_max_games = std::min(general[2].length(), general[3].length()); + m_max_games = std::min(m_max_games, (int)tokens.size() - 1); + m_votability = general[4]; + for (int i = 0; i < m_max_games; i++) + m_track_filters.emplace_back(tokens[i + 1]); } // initTournamentPlayers //----------------------------------------------------------------------------- bool Tournament::canPlay(const std::string& username) const { - return m_tournament_red_players.count(username) > 0 || - m_tournament_blue_players.count(username) > 0; -} + return m_red_players.count(username) > 0 || + m_blue_players.count(username) > 0; +} // canPlay +//----------------------------------------------------------------------------- bool Tournament::canVote(std::shared_ptr peer) const { std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); - bool first = m_tournament_red_players.count(username) > 0; - bool second = m_tournament_blue_players.count(username) > 0; + bool first = m_red_players.count(username) > 0; + bool second = m_blue_players.count(username) > 0; if (!first && !second) return false; - char votable = m_tournament_votability[m_tournament_game]; + char votable = m_votability[m_game]; if (votable == '+') return true; return (votable == 'F' && first) || (votable == 'S' && second); -} +} // canVote +//----------------------------------------------------------------------------- bool Tournament::hasHostRights(std::shared_ptr peer) { std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); - return m_tournament_referees.count(username) > 0; -} + return m_referees.count(username) > 0; +} // hasHostRights +//----------------------------------------------------------------------------- bool Tournament::hasHammerRights(std::shared_ptr peer) { std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); - return m_tournament_referees.count(username) > 0; -} + return m_referees.count(username) > 0; +} // hasHammerRights +//----------------------------------------------------------------------------- int Tournament::editMuteall(const std::string& username, int type) { - return m_tournament_mutealls.set(username, type); -} + return m_mutealls.set(username, type); +} // editMuteall +//----------------------------------------------------------------------------- int Tournament::getNextGameNumber() const { - int res = m_tournament_game + 1; - if (res == m_tournament_max_games) + int res = m_game + 1; + if (res == m_max_games) res = 0; return res; -} +} // getNextGameNumber +//----------------------------------------------------------------------------- int Tournament::getDefaultDuration() const { return ServerConfig::m_fixed_lap_count; -} +} // getDefaultDuration +//----------------------------------------------------------------------------- bool Tournament::isValidGameCmdInput(int new_game_number, int new_duration, int addition) const { return new_game_number >= 0 - && new_game_number < m_tournament_max_games + && new_game_number < m_max_games && new_duration >= 0 && addition >= 0 && addition <= 59; -} +} // isValidGameCmdInput +//----------------------------------------------------------------------------- void Tournament::getGameCmdInput(int& game_number, int& duration, int& addition) const { - game_number = m_tournament_game; - duration = m_tournament_length; + game_number = m_game; + duration = m_length; addition = m_extra_seconds; -} +} // getGameCmdInput +//----------------------------------------------------------------------------- void Tournament::setGameCmdInput(int new_game_number, int new_duration, int addition) { - m_tournament_game = new_game_number; - m_tournament_length = new_duration; + m_game = new_game_number; + m_length = new_duration; m_extra_seconds = 0.0f; if (addition > 0) { m_extra_seconds = 60.0f - addition; } -} +} // setGameCmdInput +//----------------------------------------------------------------------------- void Tournament::setTeam(KartTeam team, const std::string& username, bool permanent) { if (team == KART_TEAM_RED) { - m_tournament_red_players.insert(username); + m_red_players.insert(username); if (permanent) - m_tournament_init_red.insert(username); + m_init_red.insert(username); } else if (team == KART_TEAM_BLUE) { - m_tournament_blue_players.insert(username); + m_blue_players.insert(username); if (permanent) - m_tournament_init_blue.insert(username); + m_init_blue.insert(username); } -} +} // setTeam +//----------------------------------------------------------------------------- void Tournament::setReferee(const std::string& username, bool permanent) { - m_tournament_referees.insert(username); + m_referees.insert(username); if (permanent) - m_tournament_init_ref.insert(username); -} + m_init_ref.insert(username); +} // setReferee +//----------------------------------------------------------------------------- void Tournament::eraseFromAllTournamentCategories(const std::string& username, bool permanent) { - m_tournament_red_players.erase(username); - m_tournament_blue_players.erase(username); - m_tournament_referees.erase(username); + m_red_players.erase(username); + m_blue_players.erase(username); + m_referees.erase(username); if (permanent) { - m_tournament_init_red.erase(username); - m_tournament_init_blue.erase(username); - m_tournament_init_ref.erase(username); + m_init_red.erase(username); + m_init_blue.erase(username); + m_init_ref.erase(username); } -} +} // eraseFromAllTournamentCategories +//----------------------------------------------------------------------------- std::vector Tournament::getMapHistory() const { - return m_tournament_arenas; -} + return m_arenas; +} // getMapHistory +//----------------------------------------------------------------------------- bool Tournament::assignToHistory(int index, const std::string& map_id) { if (index >= g_history_limit) return false; - if (index >= (int)m_tournament_arenas.size()) - m_tournament_arenas.resize(index + 1, ""); - m_tournament_arenas[index] = map_id; + if (index >= (int)m_arenas.size()) + m_arenas.resize(index + 1, ""); + m_arenas[index] = map_id; return true; -} \ No newline at end of file +} // assignToHistory +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/tournament.hpp b/src/utils/tournament.hpp index e2ef1123a69..1c3884b3057 100644 --- a/src/utils/tournament.hpp +++ b/src/utils/tournament.hpp @@ -19,20 +19,21 @@ #ifndef TOURNAMENT_HPP #define TOURNAMENT_HPP -#include "utils/types.hpp" #include "utils/set_with_flip.hpp" #include "utils/tournament_role.hpp" +#include "utils/types.hpp" #include -#include #include +#include #include -struct FilterContext; + +class LobbySettings; class PeerVote; -class TrackFilter; class ServerLobby; class STKPeer; -class LobbySettings; +class TrackFilter; +struct FilterContext; /** This class combines things that were previously located in server lobby * (m_tournament_*) and were related to Soccer Tournaments. @@ -53,16 +54,12 @@ class Tournament void applyRestrictionsOnVote(PeerVote* vote) const; void onRaceFinished() const; void updateTournamentRole(std::shared_ptr peer); - KartTeam getTeam(std::string utf8_online_name) const; bool canPlay(const std::string& username) const; bool canVote(std::shared_ptr peer) const; - bool hasHostRights(std::shared_ptr peer); bool hasHammerRights(std::shared_ptr peer); - int editMuteall(const std::string& username, int type); - bool hasGoalsLimit() const; bool hasGoalsLimit(int game) const; bool hasColorsSwapped() const; @@ -71,15 +68,16 @@ class Tournament bool forbidStarting() const { return true; } int getNextGameNumber() const; int getDefaultDuration() const; - bool isValidGameNumber(int number) const; int minGameNumber() const { return 0; } - int maxGameNumber() const { return m_tournament_max_games - 1; } - bool isValidGameCmdInput(int new_game_number, int new_duration, int addition) const; + int maxGameNumber() const { return m_max_games - 1; } + bool isValidGameCmdInput(int new_game_number, + int new_duration, int addition) const; void getGameCmdInput(int& game_number, int& duration, int& addition) const; void setGameCmdInput(int new_game_number, int new_duration, int addition); void setTeam(KartTeam team, const std::string& username, bool permanent); void setReferee(const std::string& username, bool permanent); - void eraseFromAllTournamentCategories(const std::string& username, bool permanent); + void eraseFromAllTournamentCategories( + const std::string& username, bool permanent); std::vector getMapHistory() const; bool assignToHistory(int index, const std::string& map_id); @@ -90,39 +88,39 @@ class Tournament std::shared_ptr m_lobby_settings; - std::set m_tournament_red_players; + std::set m_red_players; - std::set m_tournament_blue_players; + std::set m_blue_players; - std::set m_tournament_referees; + std::set m_referees; - SetWithFlip m_tournament_mutealls; + SetWithFlip m_mutealls; - std::set m_tournament_init_red; + std::set m_init_red; - std::set m_tournament_init_blue; + std::set m_init_blue; - std::set m_tournament_init_ref; + std::set m_init_ref; - bool m_tournament_limited_chat; + bool m_limited_chat; - int m_tournament_length; + int m_length; - int m_tournament_max_games; + int m_max_games; - std::string m_tournament_game_limits; + std::string m_game_limits; - std::string m_tournament_colors; + std::string m_colors; - std::string m_tournament_votability; + std::string m_votability; - std::vector m_tournament_arenas; + std::vector m_arenas; - std::vector m_tournament_track_filters; + std::vector m_track_filters; - int m_tournament_game; + int m_game; - std::vector m_tournament_must_have_tracks; + std::vector m_must_have_tracks; float m_extra_seconds; }; diff --git a/src/utils/tournament_role.cpp b/src/utils/tournament_role.cpp index c40ca220690..0b52830c736 100644 --- a/src/utils/tournament_role.cpp +++ b/src/utils/tournament_role.cpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2024 kimden +// Copyright (C) 2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -32,7 +32,8 @@ KartTeam Conversions::roleToTeam(TournamentRole role) return KART_TEAM_NONE; } return KART_TEAM_NONE; -} // roleToTeam +} // roleToTeam +//----------------------------------------------------------------------------- std::string Conversions::roleToString(TournamentRole role) { @@ -48,7 +49,8 @@ std::string Conversions::roleToString(TournamentRole role) return "spectator"; } return ""; -} // roleToString +} // roleToString +//----------------------------------------------------------------------------- char Conversions::roleToChar(TournamentRole role) { @@ -64,7 +66,8 @@ char Conversions::roleToChar(TournamentRole role) return 's'; } return ' '; -} // roleToChar +} // roleToChar +//----------------------------------------------------------------------------- TournamentRole Conversions::charToRole(char c) { @@ -82,9 +85,11 @@ TournamentRole Conversions::charToRole(char c) return TR_SPECTATOR; } return TR_SPECTATOR; -} // charToRole +} // charToRole +//----------------------------------------------------------------------------- std::string Conversions::roleCharToString(char c) { return roleToString(charToRole(c)); -} // roleCharToString +} // roleCharToString +//----------------------------------------------------------------------------- diff --git a/src/utils/tournament_role.hpp b/src/utils/tournament_role.hpp index 34480b48176..594b152d639 100644 --- a/src/utils/tournament_role.hpp +++ b/src/utils/tournament_role.hpp @@ -19,8 +19,9 @@ #ifndef TOURNAMENT_ROLE_HPP #define TOURNAMENT_ROLE_HPP -#include "utils/types.hpp" #include "network/remote_kart_info.hpp" +#include "utils/types.hpp" + #include enum TournamentRole: int8_t diff --git a/src/utils/track_filter.cpp b/src/utils/track_filter.cpp index 285a1746f0f..1c8bd94fb23 100644 --- a/src/utils/track_filter.cpp +++ b/src/utils/track_filter.cpp @@ -21,9 +21,10 @@ #include "utils/track_filter.hpp" -#include "utils/string_utils.hpp" #include "utils/log.hpp" -#include "random_generator.hpp" +#include "utils/random_generator.hpp" +#include "utils/string_utils.hpp" + #include #include #include @@ -33,6 +34,7 @@ #include std::string Filter::PLACEHOLDER_STRING = ":placeholder"; +//----------------------------------------------------------------------------- TrackFilter::TrackFilter() { @@ -182,7 +184,8 @@ std::vector prepareAssetNames(std::string& input) return {SplitArgument(input, -1, false)}; std::set keywords = { - "", " ", "random", "available", "unavailable", "official", "addon", "not", "no", "yes", "ok", "other:yes", "other:no" + "", " ", "random", "available", "unavailable", "official", "addon", + "not", "no", "yes", "ok", "other:yes", "other:no" }; for (unsigned i = 0; i < tokens.size(); i++) { @@ -296,7 +299,8 @@ void TrackFilter::apply(FilterContext& context) const for (unsigned i = 0; i < context.elements.size(); i++) std::swap(take[rg.get(i + 1)], take[i]); std::set result; - for (std::set::iterator it = context.elements.begin(); it != context.elements.end(); it++) + for (std::set::iterator it = context.elements.begin(); + it != context.elements.end(); it++) { if (take.back() == 1) result.insert(*it); @@ -513,5 +517,3 @@ void KartFilter::apply(FilterContext& context) const std::swap(result, context.elements); } // KartFilter::apply //----------------------------------------------------------------------------- - -/* EOF */ diff --git a/src/utils/track_filter.hpp b/src/utils/track_filter.hpp index f6ecd736b7c..a43205ab3e7 100644 --- a/src/utils/track_filter.hpp +++ b/src/utils/track_filter.hpp @@ -1,9 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2004-2020 Steve Baker , -// Copyright (C) 2004-2020 Ingo Ruhnke -// Copyright (C) 2006-2020 SuperTuxKart-Team -// Copyright (C) 2020 kimden +// Copyright (C) 2020-2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -23,12 +20,13 @@ #define HEADER_TRACK_FILTER_HPP #include "utils/types.hpp" + #include -#include -#include -#include #include #include +#include +#include +#include // A structure to apply requirements to the track set. allowed contains // the only tracks to be allowed, forbidden contains the only tracks to be @@ -55,7 +53,7 @@ struct FilterContext { class Filter { public: std::string m_initial_string; - std::string toString() const { return "{ " + m_initial_string + " }"; } // toString + std::string toString() const { return "{ " + m_initial_string + " }"; } bool m_placeholder = false; bool isPlaceholder() const { return m_placeholder; } @@ -122,7 +120,8 @@ class KartFilter: public Filter KartFilter(); KartFilter(std::string input); - bool ignoresPlayersInput() const override { return m_ignore_players_input; } + bool ignoresPlayersInput() const override + { return m_ignore_players_input; } // apply is called when the selection starts just like for maps, // while applyAfterwards is called when the selection ends to determine the // random kart for a player who selected nothing (or a random kart, From 5e8ca8cb940bf4cbb1fffe48956a0794aa494b45 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 5 Mar 2025 01:33:00 +0400 Subject: [PATCH 583/830] Small warning fix --- src/utils/tournament.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp index cd93fd77ddd..72f8d9a2941 100644 --- a/src/utils/tournament.cpp +++ b/src/utils/tournament.cpp @@ -222,7 +222,9 @@ void Tournament::initTournamentPlayers() type == "R" ? m_red_players : type == "B" ? m_blue_players : m_referees); - for (const std::string& member: m_lobby_settings->getCategories()[cat_name]) + + auto categories = m_lobby_settings->getCategories(); + for (const std::string& member: categories[cat_name]) dest.insert(member); } else if (type == "R") From f3d369df2667ab075dfb6eb9e7c268e9c74d0b36 Mon Sep 17 00:00:00 2001 From: lokpro <2010297+lokpro@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:18:25 +0800 Subject: [PATCH 584/830] fix supertuxkart #5345 (#5360) --- src/guiengine/widgets/kart_stats_widget.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/guiengine/widgets/kart_stats_widget.cpp b/src/guiengine/widgets/kart_stats_widget.cpp index 1fa9563db76..585548a529f 100644 --- a/src/guiengine/widgets/kart_stats_widget.cpp +++ b/src/guiengine/widgets/kart_stats_widget.cpp @@ -85,6 +85,10 @@ KartStatsWidget::KartStatsWidget(core::recti area, const int player_id, // ----------------------------------------------------------------------------- void KartStatsWidget::setValues(const KartProperties* props, HandicapLevel h) { + // If props is NULL (e.g., when kart selection is "?" (random)), + // skip this function to avoid errors. + if( props == NULL ) return; + // Use kart properties computed for best difficulty to show the user, so // that properties don't change according to the the last used difficulty RaceManager::Difficulty previous_difficulty = RaceManager::get()->getDifficulty(); From fb1c37e1805c9152da666eaee1592470238e0dad Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 6 Mar 2025 01:30:21 +0400 Subject: [PATCH 585/830] Move request classes out of server lobby (not completely) --- src/network/protocols/server_lobby.cpp | 166 +------------------------ src/network/protocols/server_lobby.hpp | 97 ++++++++------- src/network/requests.cpp | 148 ++++++++++++++++++++++ src/network/requests.hpp | 97 +++++++++++++++ 4 files changed, 300 insertions(+), 208 deletions(-) create mode 100644 src/network/requests.cpp create mode 100644 src/network/requests.hpp diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3f9286990fe..6bf50ec2b02 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -39,6 +39,7 @@ #include "network/protocols/game_events_protocol.hpp" #include "network/protocols/ranking.hpp" #include "network/race_event_manager.hpp" +#include "network/requests.hpp" #include "network/server_config.hpp" #include "network/stk_host.hpp" #include "network/stk_ipv6.hpp" @@ -1799,7 +1800,7 @@ void ServerLobby::update(int ticks) // once all track votes have been received. break; case LOAD_WORLD: - Log::info("ServerLobbyRoom", "Starting the race loading."); + Log::info("ServerLobby", "Starting the race loading."); // This will create the world instance, i.e. load track and karts loadWorld(); m_lobby_settings->updateWorldSettings(m_game_info); @@ -1857,57 +1858,6 @@ void ServerLobby::update(int ticks) */ void ServerLobby::registerServer(bool first_time) { - // ======================================================================== - class RegisterServerRequest : public Online::XMLRequest - { - private: - std::weak_ptr m_server_lobby; - bool m_first_time; - protected: - virtual void afterOperation() - { - Online::XMLRequest::afterOperation(); - const XMLNode* result = getXMLData(); - std::string rec_success; - auto sl = m_server_lobby.lock(); - if (!sl) - return; - - if (result->get("success", &rec_success) && - rec_success == "yes") - { - const XMLNode* server = result->getNode("server"); - assert(server); - const XMLNode* server_info = server->getNode("server-info"); - assert(server_info); - unsigned server_id_online = 0; - server_info->get("id", &server_id_online); - assert(server_id_online != 0); - bool is_official = false; - server_info->get("official", &is_official); - if (!is_official && ServerConfig::m_ranked) - { - Log::fatal("ServerLobby", "You don't have permission to " - "host a ranked server."); - } - Log::info("ServerLobby", - "Server %d is now online.", server_id_online); - sl->m_server_id_online.store(server_id_online); - sl->m_last_success_poll_time.store(StkTime::getMonoTimeMs()); - return; - } - Log::error("ServerLobby", "%s", - StringUtils::wideToUtf8(getInfo()).c_str()); - // Exit now if failed to register to stk addons for first time - if (m_first_time) - sl->m_state.store(ERROR_LEAVE); - } - public: - RegisterServerRequest(std::shared_ptr sl, bool first_time) - : XMLRequest(Online::RequestManager::HTTP_MAX_PRIORITY), - m_server_lobby(sl), m_first_time(first_time) {} - }; // RegisterServerRequest - auto request = std::make_shared( std::dynamic_pointer_cast(shared_from_this()), first_time); NetworkConfig::get()->setServerDetails(request, "create"); @@ -1950,36 +1900,7 @@ void ServerLobby::registerServer(bool first_time) */ void ServerLobby::unregisterServer(bool now, std::weak_ptr sl) { - // ======================================================================== - class UnRegisterServerRequest : public Online::XMLRequest - { - private: - std::weak_ptr m_server_lobby; - protected: - virtual void afterOperation() - { - Online::XMLRequest::afterOperation(); - const XMLNode* result = getXMLData(); - std::string rec_success; - - if (result->get("success", &rec_success) && - rec_success == "yes") - { - // Clear the server online for next register - // For grand prix server - if (auto sl = m_server_lobby.lock()) - sl->m_server_id_online.store(0); - return; - } - Log::error("ServerLobby", "%s", - StringUtils::wideToUtf8(getInfo()).c_str()); - } - public: - UnRegisterServerRequest(std::weak_ptr sl) - : XMLRequest(Online::RequestManager::HTTP_MAX_PRIORITY), - m_server_lobby(sl) {} - }; // UnRegisterServerRequest - auto request = std::make_shared(sl); + auto request = std::make_shared(sl); NetworkConfig::get()->setServerDetails(request, "stop"); const SocketAddress& addr = STKHost::get()->getPublicAddress(); @@ -2334,87 +2255,6 @@ void ServerLobby::checkIncomingConnectionRequests() // Now poll the stk server last_poll_time = StkTime::getMonoTimeMs(); - // ======================================================================== - class PollServerRequest : public Online::XMLRequest - { - private: - std::weak_ptr m_server_lobby; - std::weak_ptr m_protocol_manager; - protected: - virtual void afterOperation() - { - Online::XMLRequest::afterOperation(); - const XMLNode* result = getXMLData(); - std::string success; - - if (!result->get("success", &success) || success != "yes") - { - Log::error("ServerLobby", "Poll server request failed: %s", - StringUtils::wideToUtf8(getInfo()).c_str()); - return; - } - - // Now start a ConnectToPeer protocol for each connection request - const XMLNode * users_xml = result->getNode("users"); - std::map keys; - auto sl = m_server_lobby.lock(); - if (!sl) - return; - sl->m_last_success_poll_time.store(StkTime::getMonoTimeMs()); - if (sl->m_state.load() != WAITING_FOR_START_GAME && - !sl->allowJoinedPlayersWaiting()) - { - sl->replaceKeys(keys); - return; - } - - sl->removeExpiredPeerConnection(); - for (unsigned int i = 0; i < users_xml->getNumNodes(); i++) - { - uint32_t addr, id; - uint16_t port; - std::string ipv6; - users_xml->getNode(i)->get("ip", &addr); - users_xml->getNode(i)->get("ipv6", &ipv6); - users_xml->getNode(i)->get("port", &port); - users_xml->getNode(i)->get("id", &id); - users_xml->getNode(i)->get("aes-key", &keys[id].m_aes_key); - users_xml->getNode(i)->get("aes-iv", &keys[id].m_aes_iv); - users_xml->getNode(i)->get("username", &keys[id].m_name); - users_xml->getNode(i)->get("country-code", - &keys[id].m_country_code); - keys[id].m_tried = false; - if (ServerConfig::m_firewalled_server) - { - SocketAddress peer_addr(addr, port); - if (!ipv6.empty()) - peer_addr.init(ipv6, port); - peer_addr.convertForIPv6Socket(isIPv6Socket()); - std::string peer_addr_str = peer_addr.toString(); - if (sl->m_pending_peer_connection.find(peer_addr_str) != - sl->m_pending_peer_connection.end()) - { - continue; - } - auto ctp = std::make_shared(peer_addr); - if (auto pm = m_protocol_manager.lock()) - pm->requestStart(ctp); - sl->addPeerConnection(peer_addr_str); - } - } - sl->replaceKeys(keys); - } - public: - PollServerRequest(std::shared_ptr sl, - std::shared_ptr pm) - : XMLRequest(Online::RequestManager::HTTP_MAX_PRIORITY), - m_server_lobby(sl), m_protocol_manager(pm) - { - m_disable_sending_log = true; - } - }; // PollServerRequest - // ======================================================================== - auto request = std::make_shared( std::dynamic_pointer_cast(shared_from_this()), ProtocolManager::lock()); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 6f5db69198a..430bd5abffe 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -19,44 +19,45 @@ #ifndef SERVER_LOBBY_HPP #define SERVER_LOBBY_HPP +#include "karts/controller/player_controller.hpp" #include "network/protocols/lobby_protocol.hpp" +#include "network/requests.hpp" // only needed in header as long as KeyData is there #include "utils/cpp2011.hpp" +#include "utils/hourglass_reason.hpp" #include "utils/team_utils.hpp" #include "utils/time.hpp" #include "utils/track_filter.hpp" -#include "utils/hourglass_reason.hpp" -#include "karts/controller/player_controller.hpp" #include "irrString.h" #include #include #include +#include #include #include #include #include #include -#include class BareNetworkString; +class CommandManager; class DatabaseConnector; -struct GameInfo; -class NetworkItemManager; -class NetworkString; -class NetworkPlayerProfile; -class STKPeer; -class SocketAddress; -enum AlwaysSpectateMode: uint8_t; -class Ranking; class HitProcessor; -class LobbyAssetManager; -class CommandManager; class KartElimination; -class MapVoteHandler; -class Tournament; +class LobbyAssetManager; class LobbyQueues; class LobbySettings; +class MapVoteHandler; +class NetworkItemManager; +class NetworkPlayerProfile; +class NetworkString; +class Ranking; +class SocketAddress; +class STKPeer; +class Tournament; +enum AlwaysSpectateMode: uint8_t; +struct GameInfo; namespace Online { @@ -107,14 +108,6 @@ class ServerLobby : public LobbyProtocol AFTER_GAME = 2, }; private: - struct KeyData - { - std::string m_aes_key; - std::string m_aes_iv; - irr::core::stringw m_name; - std::string m_country_code; - bool m_tried = false; - }; #ifdef ENABLE_SQLITE3 std::shared_ptr m_db_connector; @@ -270,28 +263,6 @@ class ServerLobby : public LobbyProtocol } } } - void addPeerConnection(const std::string& addr_str) - { - m_pending_peer_connection[addr_str] = StkTime::getMonoTimeMs(); - } - void removeExpiredPeerConnection() - { - // Remove connect to peer protocol running more than a 45 seconds - // (from stk addons poll server request), - for (auto it = m_pending_peer_connection.begin(); - it != m_pending_peer_connection.end();) - { - if (StkTime::getMonoTimeMs() - it->second > 45000) - it = m_pending_peer_connection.erase(it); - else - it++; - } - } - void replaceKeys(std::map& new_keys) - { - std::lock_guard lock(m_keys_mutex); - std::swap(m_keys, new_keys); - } void handlePendingConnection(); void handleUnencryptedConnection(std::shared_ptr peer, BareNetworkString& data, @@ -442,6 +413,42 @@ class ServerLobby : public LobbyProtocol std::shared_ptr getKartElimination() const { return m_kart_elimination; } std::shared_ptr getGameInfo() const { return m_game_info; } + + // Functions that arose from requests separation + void setServerOnlineId(uint32_t id) { m_server_id_online.store(id); } + void resetSuccessPollTime() + { m_last_success_poll_time.store(StkTime::getMonoTimeMs()); } + void doErrorLeave() { m_state.store(ERROR_LEAVE); } + + bool hasPendingPeerConnection(const std::string& peer_addr_str) const + { return m_pending_peer_connection.find(peer_addr_str) + != m_pending_peer_connection.end(); } + bool isWaitingForStartGame() const + { return m_state.load() == WAITING_FOR_START_GAME; } + + void addPeerConnection(const std::string& addr_str) + { + m_pending_peer_connection[addr_str] = StkTime::getMonoTimeMs(); + } + void removeExpiredPeerConnection() + { + // Remove connect to peer protocol running more than a 45 seconds + // (from stk addons poll server request), + for (auto it = m_pending_peer_connection.begin(); + it != m_pending_peer_connection.end();) + { + if (StkTime::getMonoTimeMs() - it->second > 45000) + it = m_pending_peer_connection.erase(it); + else + it++; + } + } + void replaceKeys(std::map& new_keys) + { + std::lock_guard lock(m_keys_mutex); + std::swap(m_keys, new_keys); + } + // end of functions that arose from requests separation }; // class ServerLobby #endif // SERVER_LOBBY_HPP diff --git a/src/network/requests.cpp b/src/network/requests.cpp new file mode 100644 index 00000000000..2f841b83b24 --- /dev/null +++ b/src/network/requests.cpp @@ -0,0 +1,148 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "network/requests.hpp" +#include "io/xml_node.hpp" +#include "network/server_config.hpp" +#include "network/stk_ipv6.hpp" +#include "network/protocols/server_lobby.hpp" +#include "network/socket_address.hpp" +#include "network/protocols/connect_to_peer.hpp" +#include "network/protocol_manager.hpp" + +void RegisterServerRequest::afterOperation() +{ + Online::XMLRequest::afterOperation(); + const XMLNode* result = getXMLData(); + std::string rec_success; + auto sl = m_server_lobby.lock(); + if (!sl) + return; + + if (result->get("success", &rec_success) && rec_success == "yes") + { + const XMLNode* server = result->getNode("server"); + assert(server); + const XMLNode* server_info = server->getNode("server-info"); + assert(server_info); + unsigned server_id_online = 0; + server_info->get("id", &server_id_online); + assert(server_id_online != 0); + bool is_official = false; + server_info->get("official", &is_official); + if (!is_official && ServerConfig::m_ranked) + { + Log::fatal("RegisterServerRequest", + "You don't have permission to host a ranked server."); + } + Log::info("RegisterServerRequest", "Server %d is now online.", server_id_online); + sl->setServerOnlineId(server_id_online); + sl->resetSuccessPollTime(); + return; + } + Log::error("RegisterServerRequest", "%s", + StringUtils::wideToUtf8(getInfo()).c_str()); + + // Exit now if failed to register to stk addons for first time + if (m_first_time) + sl->doErrorLeave(); +} // RegisterServerRequest::afterOperation +// ======================================================================== + +void UnregisterServerRequest::afterOperation() +{ + Online::XMLRequest::afterOperation(); + const XMLNode* result = getXMLData(); + std::string rec_success; + + if (result->get("success", &rec_success) && + rec_success == "yes") + { + // Clear the server online for next register + // For grand prix server + if (auto sl = m_server_lobby.lock()) + sl->setServerOnlineId(0); + return; + } + Log::error("UnregisterServerRequest", "%s", + StringUtils::wideToUtf8(getInfo()).c_str()); +} // UnregisterServerRequest::afterOperation +// ======================================================================== + +void PollServerRequest::afterOperation() +{ + Online::XMLRequest::afterOperation(); + const XMLNode* result = getXMLData(); + std::string success; + + if (!result->get("success", &success) || success != "yes") + { + Log::error("PollServerRequest", "Poll server request failed: %s", + StringUtils::wideToUtf8(getInfo()).c_str()); + return; + } + + // Now start a ConnectToPeer protocol for each connection request + const XMLNode * users_xml = result->getNode("users"); + std::map keys; + auto sl = m_server_lobby.lock(); + if (!sl) + return; + sl->resetSuccessPollTime(); + if (!sl->isWaitingForStartGame() && + !sl->allowJoinedPlayersWaiting()) + { + sl->replaceKeys(keys); + return; + } + + sl->removeExpiredPeerConnection(); + for (unsigned int i = 0; i < users_xml->getNumNodes(); i++) + { + uint32_t addr, id; + uint16_t port; + std::string ipv6; + const XMLNode* node = users_xml->getNode(i); + node->get("ip", &addr); + node->get("ipv6", &ipv6); + node->get("port", &port); + node->get("id", &id); + node->get("aes-key", &keys[id].m_aes_key); + node->get("aes-iv", &keys[id].m_aes_iv); + node->get("username", &keys[id].m_name); + node->get("country-code", &keys[id].m_country_code); + keys[id].m_tried = false; + if (ServerConfig::m_firewalled_server) + { + SocketAddress peer_addr(addr, port); + if (!ipv6.empty()) + peer_addr.init(ipv6, port); + peer_addr.convertForIPv6Socket(isIPv6Socket()); + std::string peer_addr_str = peer_addr.toString(); + if (sl->hasPendingPeerConnection(peer_addr_str)) + continue; + + auto ctp = std::make_shared(peer_addr); + if (auto pm = m_protocol_manager.lock()) + pm->requestStart(ctp); + sl->addPeerConnection(peer_addr_str); + } + } + sl->replaceKeys(keys); +} // PollServerRequest::afterOperation +// ======================================================================== \ No newline at end of file diff --git a/src/network/requests.hpp b/src/network/requests.hpp new file mode 100644 index 00000000000..d21fdf963f2 --- /dev/null +++ b/src/network/requests.hpp @@ -0,0 +1,97 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef HEADER_REQUESTS_HPP +#define HEADER_REQUESTS_HPP + +#include "online/xml_request.hpp" +#include "online/request_manager.hpp" + +#include + +class ProtocolManager; +class ServerLobby; + + +struct KeyData +{ + std::string m_aes_key; + std::string m_aes_iv; + irr::core::stringw m_name; + std::string m_country_code; + bool m_tried = false; +}; + +// ============================================================================ +class RegisterServerRequest: public Online::XMLRequest +{ +private: + std::weak_ptr m_server_lobby; + bool m_first_time; + +protected: + virtual void afterOperation() OVERRIDE; + +public: + RegisterServerRequest(std::shared_ptr sl, bool first_time) + : XMLRequest(Online::RequestManager::HTTP_MAX_PRIORITY), + m_server_lobby(sl), + m_first_time(first_time) {} + +}; // RegisterServerRequest +// ============================================================================ + +class UnregisterServerRequest : public Online::XMLRequest +{ +private: + std::weak_ptr m_server_lobby; + +protected: + virtual void afterOperation() OVERRIDE; + +public: + UnregisterServerRequest(std::weak_ptr sl) + : XMLRequest(Online::RequestManager::HTTP_MAX_PRIORITY), + m_server_lobby(sl) {} + +}; // UnregisterServerRequest +// ============================================================================ + +class PollServerRequest : public Online::XMLRequest +{ +private: + std::weak_ptr m_server_lobby; + std::weak_ptr m_protocol_manager; + +protected: + virtual void afterOperation() OVERRIDE; + +public: + PollServerRequest(std::shared_ptr sl, + std::shared_ptr pm) + : XMLRequest(Online::RequestManager::HTTP_MAX_PRIORITY), + m_server_lobby(sl), + m_protocol_manager(pm) + { + m_disable_sending_log = true; + } + +}; // PollServerRequest +// ============================================================================ + +#endif // HEADER_REQUESTS_HPP \ No newline at end of file From 67d427fe7c837c57e8de939373540f823c748b1e Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 7 Mar 2025 01:53:49 +0400 Subject: [PATCH 586/830] Allow specifying players who can /power with any password, in categories I know it's not the best place for it, but for now I don't want to duplicate config options. I will add more power-related commands later. This one is small as I don't want many untested changes all of a sudden. --- src/network/protocols/command_manager.cpp | 26 +++++++++++++++++------ src/utils/lobby_settings.cpp | 22 +++++++++++++++---- src/utils/lobby_settings.hpp | 5 +++++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index a6f3cb79045..29f2267a766 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2386,8 +2386,20 @@ void CommandManager::process_power(Context& context) m_lobby->updatePlayerList(); return; } + std::string username = ""; + uint32_t online_id = 0; + const auto& profiles = peer->getPlayerProfiles(); + if (!profiles.empty()) + { + username = StringUtils::wideToUtf8(profiles[0]->getName()); + online_id = profiles[0]->getOnlineId(); + } + std::string password = ServerConfig::m_power_password; - if (password.empty() || argv.size() <= 1 || argv[1] != password) + bool bad_password = (password.empty() || argv.size() <= 1 || argv[1] != password); + bool good_player = (m_lobby_settings->isInHammerWhitelist(username) + && online_id != 0); + if (bad_password && !good_player) { std::string msg = "You need to provide the password to have the power"; m_lobby->sendStringToPeer(msg, peer); @@ -3080,7 +3092,7 @@ void CommandManager::process_hitmsg(Context& context) error(context, true); return; } - if (m_lobby->getHitProcessor()->showTeammateHits()) + if (m_hit_processor->showTeammateHits()) msg = "Teammate hits are sent to all players"; else msg = "Teammate hits are not sent"; @@ -3099,10 +3111,10 @@ void CommandManager::process_hitmsg_assign(Context& context) } if (argv[1] == "0") { - m_lobby->getHitProcessor()->setShowTeammateHits(false); + m_hit_processor->setShowTeammateHits(false); msg = "Teammate hits will not be sent"; } else { - m_lobby->getHitProcessor()->setShowTeammateHits(true); + m_hit_processor->setShowTeammateHits(true); msg = "Teammate hits will be sent to all players"; } m_lobby->sendStringToAllPeers(msg); @@ -3118,7 +3130,7 @@ void CommandManager::process_teamhit(Context& context) error(context, true); return; } - if (m_lobby->getHitProcessor()->isTeammateHitMode()) + if (m_hit_processor->isTeammateHitMode()) msg = "Teammate hits are punished"; else msg = "Teammate hits are not punished"; @@ -3137,12 +3149,12 @@ void CommandManager::process_teamhit_assign(Context& context) } if (argv[1] == "0") { - m_lobby->getHitProcessor()->setTeammateHitMode(false); + m_hit_processor->setTeammateHitMode(false); msg = "Teammate hits are not punished now"; } else { - m_lobby->getHitProcessor()->setTeammateHitMode(true); + m_hit_processor->setTeammateHitMode(true); msg = "Teammate hits are punished now"; } m_lobby->sendStringToAllPeers(msg); diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index f67308ad0f2..488bfa4c40e 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -96,6 +96,7 @@ void LobbySettings::initCategories() ServerConfig::m_categories, ' '); std::string category = ""; bool isTeam = false; + bool isHammerWhitelisted = false; for (std::string& s: tokens) { if (s.empty()) @@ -103,6 +104,7 @@ void LobbySettings::initCategories() else if (s[0] == '#') { isTeam = false; + isHammerWhitelisted = false; if (s.length() > 1 && s[1] == '#') { category = s.substr(2); @@ -114,17 +116,29 @@ void LobbySettings::initCategories() else if (s[0] == '$') { isTeam = true; + isHammerWhitelisted = false; category = s.substr(1); } + else if (s[0] == '^') + { + isHammerWhitelisted = true; + } else { - if (!isTeam) { - m_player_categories[category].insert(s); - m_categories_for_player[s].insert(category); + if (isHammerWhitelisted) + { + m_hammer_whitelist.insert(s); } else { - m_team_for_player[s] = category[0] - '0' + 1; + if (!isTeam) { + m_player_categories[category].insert(s); + m_categories_for_player[s].insert(category); + } + else + { + m_team_for_player[s] = category[0] - '0' + 1; + } } } } diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 03553bb50fb..1ad4ce3c2e3 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -142,6 +142,9 @@ class LobbySettings void setBattleTimeLimit(float value) { m_battle_time_limit = value; } std::string getAvailableTeams() const; + bool isInHammerWhitelist(const std::string& str) const + { return m_hammer_whitelist.find(str) != m_hammer_whitelist.end(); } + private: GameSetup* m_game_setup; @@ -231,6 +234,8 @@ class LobbySettings std::map m_team_for_player; + std::set m_hammer_whitelist; + }; #endif // LOBBY_SETTINGS_HPP \ No newline at end of file From f9ffcc6310d4e632773acfeadcb9fd03bf446371 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sat, 8 Mar 2025 15:37:05 +0800 Subject: [PATCH 587/830] Add smooth strength adjustion & Unlock modifying default camera & Fix #5270 (#5365) * Revert recent camera change & fix #5270 * I tried my best * Now the bug is properly fixed * Pull from master * add back files * Revert separate camera tab, and move it to display * Add smooth strength * Tune --- .../gui/dialogs/custom_camera_settings.stkgui | 89 ++++++ data/gui/icons/options_camera.png | Bin 3977 -> 0 bytes data/gui/screens/options/options_audio.stkgui | 2 - .../gui/screens/options/options_camera.stkgui | 111 ------- .../gui/screens/options/options_device.stkgui | 2 - .../screens/options/options_display.stkgui | 21 +- .../screens/options/options_general.stkgui | 2 - data/gui/screens/options/options_input.stkgui | 2 - .../screens/options/options_language.stkgui | 2 - data/gui/screens/options/options_ui.stkgui | 4 - data/gui/screens/options/options_video.stkgui | 2 - .../screens/options/user_screen_tab.stkgui | 2 - .../cartoon/data/gui/icons/options_camera.png | Bin 3462 -> 0 bytes .../cartoon/data/gui/icons/options_video.png | Bin 9475 -> 3462 bytes src/config/user_config.hpp | 66 ++-- src/graphics/camera/camera.hpp | 2 - src/graphics/camera/camera_normal.cpp | 166 +++++----- src/graphics/camera/camera_normal.hpp | 13 +- .../controller/local_player_controller.cpp | 1 - src/modes/world.cpp | 34 +- src/modes/world.hpp | 2 +- .../dialogs/custom_camera_settings.cpp | 218 +++++++++++++ .../dialogs/custom_camera_settings.hpp | 63 ++++ src/states_screens/options/options_common.cpp | 2 - src/states_screens/options/options_common.hpp | 1 - .../options/options_screen_camera.cpp | 297 ------------------ .../options/options_screen_camera.hpp | 71 ----- .../options/options_screen_display.cpp | 85 +++++ .../options/options_screen_display.hpp | 4 +- .../options/options_screen_ui.hpp | 4 + 30 files changed, 619 insertions(+), 649 deletions(-) create mode 100644 data/gui/dialogs/custom_camera_settings.stkgui delete mode 100644 data/gui/icons/options_camera.png delete mode 100644 data/gui/screens/options/options_camera.stkgui delete mode 100644 data/skins/cartoon/data/gui/icons/options_camera.png create mode 100644 src/states_screens/dialogs/custom_camera_settings.cpp create mode 100644 src/states_screens/dialogs/custom_camera_settings.hpp delete mode 100644 src/states_screens/options/options_screen_camera.cpp delete mode 100644 src/states_screens/options/options_screen_camera.hpp diff --git a/data/gui/dialogs/custom_camera_settings.stkgui b/data/gui/dialogs/custom_camera_settings.stkgui new file mode 100644 index 00000000000..e8ea769967f --- /dev/null +++ b/data/gui/dialogs/custom_camera_settings.stkgui @@ -0,0 +1,89 @@ + + +
+
+ +
+ +
+
+
\ No newline at end of file diff --git a/data/gui/icons/options_camera.png b/data/gui/icons/options_camera.png deleted file mode 100644 index 8fa50ea5b42d4da02a97484fce9685e926c61c04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3977 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 - - - -
-
- - -
- - - - - - - - - - - - - - - - - - - -
- - -
- - - -
- -
-
-
- - - -
- -
-
-
- - - -
- -
-
-
- - - -
- -
- - -
-
- - - -
-
-
-
diff --git a/data/gui/screens/options/options_device.stkgui b/data/gui/screens/options/options_device.stkgui index 51dedb685c0..51171a6cd42 100644 --- a/data/gui/screens/options/options_device.stkgui +++ b/data/gui/screens/options/options_device.stkgui @@ -18,8 +18,6 @@ I18N="Section in the settings menu" text="Audio"/> - -
+ +
@@ -67,15 +67,28 @@ I18N="In the display settings" text="Apply new resolution" />
- + -
diff --git a/data/gui/screens/options/options_general.stkgui b/data/gui/screens/options/options_general.stkgui index 3549ee2a1eb..3d726a66de1 100644 --- a/data/gui/screens/options/options_general.stkgui +++ b/data/gui/screens/options/options_general.stkgui @@ -18,8 +18,6 @@ I18N="Section in the settings menu" text="Audio"/> - - - - - -
diff --git a/data/gui/screens/options/options_video.stkgui b/data/gui/screens/options/options_video.stkgui index 4e987bc7894..7e5d77f09c7 100644 --- a/data/gui/screens/options/options_video.stkgui +++ b/data/gui/screens/options/options_video.stkgui @@ -18,8 +18,6 @@ I18N="Section in the settings menu" text="Audio"/> - - 2#e!TBFO%D;X> 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 LH_&X2#e!TBFO%D;X> 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 LH_&XSV{ru7Lbqz2}ucI5u`(28Vr z@9+O+zI`)q_KSIQ-?`_WbEC91pOX;M5dr`}qN<{#i<#m7UHG_|-yT`3Va!C}uJY0o z06=s9U7&wv#U7YNS}$c|FFiLqFJCJUTfo=Xm(S7F+0)v}-ImYI!#?vsnhpS1097S< z{dZaW?|rlAr>8GG4^-xt+FK_U#;N`|#}aW^TKkLf@82m9;mWFkL-@}$9Z18d@k!f@ z(x_NqZ&=8{kFfC{CyD7R64TJH*Yh~G?@s$nr%Nm|3z;}q_!`-gT%6u)bN+Hb<*+Z> zkH}mu1dKkm>-TxnN=9CV@KJxtfSFSA98GY9{h)biHLjLAv&aR1KC_RJyCBpu_h-Xm=dX75FG+iXS^5wX4uH!obT0aXiGKTM>1zh z<(JkOs7<9a2;4Vn>-(GCB-c07R4{|-KOhDGgy=0QFTbBYyhQVuoQ)usfQ;g7+?5aS{221dP31MI6e8vH4GbvlUf{i& zUADvBq!#kYpc{z&C+@U}>r_sHEKLZFw6p*Jy^r8YCwRzPQ=tK+8`k|Tu1NO7UQ+0( zP3o|BK+~CntE(%h*5kc4?b+g)2_v#C8`ys4?d>fBr-ltW%jGfp*O3B|ngr}_m(a9p z^@IUWU#*%7xs47H82y0XfhHEOFT}<+$y12H3gZ!&V*$~j!m+3R|la1LLlf-J= z76u0A-R0#^d|QT=%JIqYu@CG}cinnDTffUnmVJp4vqMK_OSk}&T?aqCBzN?Qp;isd z-VA8G4%F!&@c#0dS8io~`kFgmSSqGC;egaM(% z^n{LojeJjk)HCwrIP@3Bd>G=6_;^|KROAr1R?}cws^9e9P#(~j^sz@hwu_Hi`M@$K z;Pr0a#&X)pGUBv_MNJ*J$}V;^q0$fBWvPo=XBYQ(%17>U0qaKGKEh=#UL@ zTD;L1%VP<~@5g9wFhIo0MDKg;IN`ZaT3+rUbSgwP=x8xUS~y2@{O_AHXchQtkO|}^ zr8Bd!(H$34$Sb+=-@TC4CPw_Yz7=+30PM)dS6mh7@*L-dfdPwmfnvD#3X3cYC+{GD z^vu*$V_=&gM-tF9*-Q-I%UX^qrCVH+2?tf0lT7Uu6dnz_0^+^v$G5_X{&eBTKF?EO zTJ)fe%+W*R5-eCwv16hTYifE;j$t8B#DT0h_G+{d8^^;-@Ym!I5=yp%f^a55(V?xs1PW;w z(&U6*&$GY=1vE|{cy5k(yIvpE<=54{6#>vY{ERa+PG#Opqy$K5IJ z9mY~>d{+6QR^83acgIiTu8kD!j=!w;v^pbKD`C2aJMU+2^0C?J|OJoqRE{UduUjVt^S8Fsg*Wy zganN6vg?q@_Q=T0>;#XU{89^GOI{?N3xcW1gkZuz&`$QUDO2*P$K!KhrW;d`p_pVh zGEn1*V7S6F0!z7&QBdj5LIt^imXqePJO0NI5_(Z)Eg50(Y!(K6!5WjKDya-jM;Ey% z8|%ZtQpYODmCqzCpuFFPeArBqSjD6ugp|9J`( z!_DBt2M#-PMWtnvLt~*MlbYGgl3jlpxCyIL^XO)PeW@VNlPA%ho}T<|cg6Ad2{sb$ z%UB;Bb}6bpt6ZgcZOLt2+BjK7mX}jQ#GAfK};zfmp|9biQzEIZT5IVJC%TQN(A`}qm zASg7;TBa7Yb?hMQ@9OOA?CX(UUT$u{9+$a{UZ#39AZWcGM%&r~iJ$P3%{{!wd<+?F z9pKvBiiyj;L8Kc{I%=9&LXyHXitvibR2J8S+;XSL8+_sExHRU>|*hm&^sB;93PY!L*8Kc*f zpLeAAN+i_$%ASb{9ni(im+I`6FmRd(V>vQZ2ruBGw(#(IfQwt7du1)#t@Cew{rD;E zEVCe?4HEpw`e5P5NO3VoP0wnnHOk+vnzO(kI0rbeN^#*TF1j|@Mlp3<5d47kcgTF=A_2&<3h`;jCiXL51b{iPJj10n&328-ig zmmTfWc&STzglLXF8&oT$@{fLK>=QPB0P&&lo+p-vZ&zVI9=Dq@j1l$Dl16-J^YqSk zA$XAL6D63KCrd?z8;wAgDA`hUDTWpvu%)~=As%R9pt;6H22R$q^x+b64%DIF-i6xi z-tULG={%0y`dwUHtiy}?q`PEfY?*U&GMTBZ<5-Xvwu;##1#PLF}l-7J1aG&a5IqP55_x@f^(kN>N_DsY=21a8J^m@ur zs&2>k<%4ndoWLfRtC-h-q@_XN=us-k$Kar>(BT8#zW%%dq0_aKlM{NwN@Iv;>tZ5i zr^pam>3(vZ%joerH70tFSPVN`>_bxbm%nz9Y9raB%VbgjPMsJW+FA&K6v+51pHtmb z2lL3%ob>iBu>?FuCE?aG%=dpiDN5oQk!!a{C8LG%PAw7TXDo1v8_H}Ma10YySA*N% zkVr%5sUs$I$pH++^S^5K*`MqGIS@kdlCIcs{ueUPs*Npv#i~odNY)Z3$SfoNgG|rX zd;UXXww5{!%Ki+Qg?wH+ekZJ~v!gLtiKjh^Bm$)CaUkDF^b#|^u!tJ@XXK=RQ6RrG zTZmWmiCGz1PC_~zQlWW@+Ile2IP`1-i`)_@um+SFXU3|g~omhfmvn` ztd~(JG)kkdIFM3fq~^R4=V$i#Rg7Sx1*7QTz)wVW_wY!~)9XMUAZ(fw0fbxnc=Nvi7ZRK_pZt7nT@Yn2|?FmZ7tAy1C#eLXdZY7HXf2PT=Fk+$O z3@Z$)HdhdShObN@!wRATBZ*midw>!6^kS%~M)@(Z9A|P72h$JHNb2QZJ(QQJdo#Zk zbJe(OE^qFd1wEaDr|<{qKwpzeu)Ys-36J?G(Z}9SF_*-Xve4n|Xzj>vzWDfVD@q~j z#E!_rgC?LFM>9*VWvkGYOtYn$;V>wN90yR=aZ0DPrBp=+q!4d>4)`cw??guMC3KG|FNVf8b}eu$`l3pUBjj&_UCHlyS_ZeF|>{A zlK12yo_s{6Gxa2O7hvfWFPmwY)Ag?)F?;J_QR{xx3m0Zv$0WXU8oQt|q>%ETRhRcM zGLs)usCL^A5L{W_Zx;gGAfiDPfHehq92PQbt812$DveCyVjSBm$-mohnoP%}9~!Rs zj3BRkCtvC8>$V`HOT;&M{ugc=ScqqtKs4Ba8h8B9i>v9i0?1)hA3+yi$oVhA`-c9g zOQY{&OT6%3tXVCu>^VOkalnB^R-QGR47+Cpp9Gj;YJT_-nNhwGN6hg!Rz2oj7AE!b z#ahMxluA@8MDk{VGtAz6Xy92VIKuMm8MePdSWYd>{y{#c`dD0kj~_D2I7Fv;GM0b? zR#Q|+w$}O_LmYB|99z82#ycbWHG}lBTWk{(xJf|V-rrpBwHV*i<24{PrpOIv!vCj zviwxxfT=z%JnPkLl+)3*%0P8KBfroHXT;(C<4}KNo`^5?9d^E(2nl0P zL;PJ2sJpFEhPL$b8W9rCDJ=5}J}3<6X8fdw~W(O!BB!($Wq{bHM%5F{f5%g>g5 zBKDwES}YP}q49+@Vto^!ifgKjiUmFDIl%D}5PHEKGxQ=N5(fhC!`=22>$``4axrog z8HzjI&}?hZ?4FAP@36vlF7DmG033VI z93}>k>AZcp4OL6B)Lx4oXLG(G{@7%0v;bG=WQjj zrQu|9I-CXYtD&V4*rH9w`zG~=>*=m}erWTsrKjQ}yXObXb8}ayl%c4;*AFDKN1Stl z1m!OO=Kj`ffPW)<#Ix>6)uM=Prz!leFZGp0G>t4ODRqwCl~eSg+0WAL=}es;a0t2WO5qB4TMzQ6a_!kRLXptBxPu{7x!vWpq-CY z+_7v}I$9LRLsP9$bu?qsI7!6Nh{VyIZff)sxMP|xWV~ASRXgkW#Kc6U~)P_v0pxhX$_u$08AB)W)CYB(9rFCxqDQ7Z+J|$;RNUd6G7*9Cv6PjCEYOZ z9|YefUT`UA*wg-A&|O(du?V#84j44)}9nWW-O z6T(ZIfnMFFYM~169u!%ka?Vt9Fqhsri5L37xq zk8aW%uvPy1_iw>nyz)tO!Nbo3!Wzku(pYxf53(491cW~9eeR0rCb4Q{9?Q{v$;QU= z8vHCD)NHfYKD**v09l#TTZBp~RSaV&d&W;H-Jz0bqF>}4S6V`0!?M>R{nF>oZF9#; zVlDoCin6)aJ*gyt0ThUx%3Y-TZ zcqEnYdF02#whYA^CM(~@7Z@rO#um0zt8xLF00)@MBZ5F_01-=38xz7?Ms7=fw(ab; zp3zPX6d{iIHn(oI!Ps`G)16hWtU~1P;c&^vp zV#rwRSruhv7WQ82gQMebwvq3%29SYi%ZI_X-*+*Eyej5t+f}0Ft}-=PH^@5mTZ2yC zF6&?(2W;r#=IO^b*~{s&%FDawVy2Y?MFfcc#UvEP_sBW zVRQ`~o$9sd7~1%Q%szYlSxa_iF#fjSlRETyMnJy@+cl_>W^-95+#zczVPM^}!QdK3 zMSwsygUPZ_r6&2Ng+naKxXLWQ^AmyLP8q27pR+35)P$@ZrQY;%{{MdR0lxp4z&2@B}!zx#I_4jZV*|nmirGt0k|*ap^1DUSwp;3euA}2yP++awrrS z{<@3P38o*oveb)k9;pCC1x}3?gjZe#)8@xwe#Y(cu0J(q}wR1CM`2*oKOemkLRytuVxiDJ*l$T*l1cKKW|_QjcRM>le-{EbWW z=eL~NYJQ~f8^uY*p5hQKJPI7~ortX$6)pGdcp25zAMC$`h#fl1TivfLm(hm>q)@Jn z6e(L4KUVV6v9@0SRQNJ#xz4f^A9eV!hm=IpY1d1?g@hvI1V!)_E|SnpIipqp3fX)d z%-tK8K+yv|7J)PWySsPOH)tQ&=#{9EUH(uewQGFgF3V@G-$H=kOCKcs5*zz4ufD#1 zaKod@j?<|5=^NEy6ZmKMl@OS6_qny@wT$xC`!f8P(QU-fhznn7da)S@f1B5cjSBzz1E`1E-rmG@VYpSA%&UQ=*5?BDhQt}Ou)as+YGFDI_Pwq6 zM)ytFFD!=f;6`SAvjonw)%%}x`FQw6g3tPgdDHZr6E-ptzwMJ&KL-D8KRkYSakEvJ zAShbGSBQ=IAFjLd<$|l%;g^mew0oKiQCdz?6+Z(wCHLjW1y`J!rNwB;1WIoI`+aG% z>r7p*^EIqVVXZf=uJ=Bb^?P$S`m9P=5D~zEr2yB?6)vJOiMKtz%3|5R46^GGBEvV! zp-Gw$-mh!-jmbJGvH$arB)hK#Uuu8nnGyfN+0ES@Tk5t_KR!#*8Te{`Q0&BnstKN* zo*?#p5g{9JDYto}*408(A>cMZlhc+@62r{jAIeVwg-b~@jT)rCYuR)6#e!&vXf!0S z08A&>fp=6z9QP$gxz4{b>r8_U%sb>B*e{v&BLgcjfWo)v4^DrK&;vBL<~p(R9n&?) zlHom8*C4EcZuF@(s3j#OuN(<`(K_)Y?CLEhHipZF^bF3O*uDT5ZdIc(Y4+{ydjGlg ztKpLJoj8$+@2I;=)5=etU>>;gWy;DbHIXERa(b&(Pq=(ksjl)fe~@{NuNXkIPWd*B zu3qmNo-Fp=8eh)yUs=1hleL4Rkvf~C0AsQi)ktRf_U3n<*w(16!{~y*igKr#q!S@2 z2~;Ur!T`0{KSp}=^%`8xDBd3zA;lSGx#s#G{GFA<}wJWqh3k8gpC_$ei_>3Shv zX<9`HQ2RwS^{$Z-@FB$w<#uTR14>>;Ns^3u&b$Nl(9wDGnRq_jey3`z5QJho>v3P< z1FAQ&j+0ZSE-N`NBw4WU)YbfS%Ud|vtFY5VoKs@b-NJzupW&_OVyp3a$=k2lj?W`j zvzTxouZqfdWXlFw3qph2YN=ntMlX75%q&s9113yDy9$v!)t%q4WvZHft4H%P2#bAa zNH_q&mn+I!)~`ek6B-}p6&9{b10?N}0r{y~$f1nyq+X=tZXV+BG9x^B(yxt>Z|%%o zK{p5V`>D93fb72^9Kf0b0E9(FJKkix+b^cycVB~t?`)QMS=}RzSs^m}KCMK!sZgJ< zall1ohVxwC%k9&Iuo;LTDCIxd&J9aQ%SSSMU9FQ2AKM2@TVK!qOh|0`AEU!Q8346W zn;VBm@&)XrgB$$fCPu*kToDxHt4wBKi&AIpb?fJ0r*&ipg!sYQOYNS%LuD4aeeOXp z@HafA)hs$JxF-hH`&nOiEww7I(tVmlhw{Gy#>nxp``Z&N^zKI&+$n8? z^r#zt=Lp4oy`m)hSR+laBkk`C|8~9fYlcDu?67jm7fees$P!r!C|CJH$n)^!d$GGM z9(J72NBTZQ^5Hy-02k_obg07rFu<2)MOc9cv$M0KOxA|gp_<|xHX8)$-4RrvB`t3$ zYGs}3_h|CjWAt@%gQbsZpmzKx8T;pNSG!#oj`hdi>kesQQb);paxxW0!hQ`@S6{!f zUIM-O8qKh6Ob{n+!_*k-PCWBTz4eapp^g;3yqzoF*a))AUEC~OXXIaVVc@CnGP`K$ zT{ABt!1^CnI092{-Rchg8EMPgYcWcFqX5A*or1yenCfj;q(5EDv8{(7!1Vd27U~RKOOBT&U(!lY-|t zX6%PsVP|G$PP)cpP&FvJThq77Y6ILfKEqurx&riX1EfmQOr2HZhtj+8crntm*|P6q z7+K*lT3h|5xhUbkDAYX-LT3GQ;zNw0gu$zQCG6)VSjoZF4BIE>k7PbZMPrS*Zl2uO zR)foVp?PFI+@&>ZiN~sAplsILAoTCDEm`xlV!ttgi03fPGiR{u)dY^+7DhS`o@6a4 zDk^%e_G9Za^(nLT`Iz}s#hq#L5_EO*G8K#nu(h@Aq_4?J!pEH0H+JTINOZW1=0~#k zS~hE{Pr11rE!zFhYjyH5<;*lRmfj;Q>Pv@wVSeTpFkYdMX3l@hOY<@nECrznvJ<4U zk3~StCX1aLSeIZGoS;rL1XCj3OdE$#Hw{5D=3ZgiY_qPUke!HQ*|-wQHuFpA^u+;ur}y7`VFOXMTb!bTncw zadpld16pCr9ZeNnZ6X8%rQm1wAVQZ+Wu=##0EE$NLLmPaIzt1lWh4QaB~XY=3IG(l zps~ZLH9oYLa;A~FcP+%>QP1DYF3(WntKkq3LFvHaI6aR0T!N{%b_zq%q|$q2Qs;5; zvSJ&d{GNcNMseU5jB7;+Fx_MJ&f$=17?hP*UEhp(cWnk-$I03>#6x4U*hak&RO`ty zJ(4E${jQl2(U^(0p$UJ>3-=DUVn{UpmPGo75}QoHm@oP&AfD19|vOS zT+_?+xAc9oBaUEQR4>M8jO`-87A0pfjn8Y>cSd7fXc5}Z$+$_~(i3BYX_psR$#hvo(J)sv_M^!q za5|jlobaI;G%!KJY?yF#pvI&fVrVH*6&tkR{>LqPbJ0I|TpCDZAhbr=Fz$j0KNVl0 zl`OjnFs`_P!HaC`g{SpnT@Eq2-4G-f2&3b6g4|!N&F%Zll1rf8H_b~VM4|}f-E4G& zI0RO)OS@0g#{mF4?7v=ss;VkX9V0w{Ar}%@l*@jl{ZE9Rsfn|L3K2Q{vx6wj9ZVCh zLtw1fVJ#mLx{t&1I{`l^7rNRG@8DXYc@N0Ls;A!|F}Uex+7cuc-an%Vf9vr2Id(Qu znzKsHMGo+EgDf9l$CVHa`Wkm2 ze2Abyn3acE^49w}01!gH*u}WByZd6Ya$YoqfD`salVwbd4|e=6F!jvw+dgIsfV^mc zYdvdTKpyindUY;P4@RvQr(x!5riz{7br4hn_LsQ zrFz;Y4$Gk=ZVb2fpo?aEvqY;jI@NZ2D8vy4U|7Zg(4U-RD-J#V5f>L1tZASA2VAcS zNOhXeQ;7nA(DK&hP3qSMqzleVPWYdFSqj7M4X@QQ7|SP*`DPbN%p%#^f>&}M(haq_ ziT>Lv$?oe6GZc#}FDpxbP1FD6Ys5Q??`GBQLUqQkP5%>nt!V5^REwDrR)2Wpyki|O z5|9in%v@f+%bMNxiiYHC(ltP5wcnad*b?brA(cJv^EDEZ`;0Y=rQmVCwnKZ;$v11CnUIziNiAt6iw6h^CYn$f>|93t!*#)-eDT~h!SYTW4Z z@|}gJgA1rS5eN$iw4%cHPh0J}JjrA9>Ch4iY67kt{`!!8#S%DF<6i!(dw+>-gNI(S z*2hkR8zW$QI4d{?26EHF`}$JeyFOn*%aq_p(1>*AWZi0AOxuY1o05(yEB*HWdNmaB zkCmy;XnE+;uYD$knUTFzZ~uUM9XPyc!s}S+hhnkJ*;-!cBzb2PzcR%P(Q(4}vqxyq YEDav4oZb5^rhy4iRn}ChRsetFOV(m_fov); } // ------------------------------------------------------------------------ diff --git a/src/graphics/camera/camera_normal.cpp b/src/graphics/camera/camera_normal.cpp index 7ba5353afbb..2048361a4fa 100644 --- a/src/graphics/camera/camera_normal.cpp +++ b/src/graphics/camera/camera_normal.cpp @@ -31,7 +31,6 @@ #include "karts/kart.hpp" #include "karts/kart_properties.hpp" #include "karts/skidding.hpp" -#include "network/rewind_manager.hpp" #include "tracks/track.hpp" // ============================================================================ @@ -45,7 +44,7 @@ */ CameraNormal::CameraNormal(Camera::CameraType type, int camera_index, AbstractKart* kart) - : Camera(type, camera_index, kart), m_camera_offset(0, 0, -15.0f) + : Camera(type, camera_index, kart), m_camera_offset(0., 0., 0.) { m_distance = kart ? UserConfigParams::m_camera_distance : 1000.0f; m_ambient_light = Track::getCurrentTrack()->getDefaultAmbientColor(); @@ -61,31 +60,26 @@ CameraNormal::CameraNormal(Camera::CameraType type, int camera_index, m_rotation_range = 0.0f; m_kart_position = btVector3(0, 0, 0); m_kart_rotation = btQuaternion(0, 0, 0, 1); + m_last_smooth_mode = Mode::CM_NORMAL; reset(); m_camera->setNearValue(1.0f); - if (kart) - { - btTransform btt = kart->getSmoothedTrans(); - m_kart_position = btt.getOrigin(); - m_kart_rotation = btt.getRotation(); - } + restart(); } // Camera //----------------------------------------------------------------------------- /** Moves the camera smoothly from the current camera position (and target) * to the new position and target. * \param dt Delta time, + * \param smooth Updates the camera if true, only calculate smooth state parameter if false * \param if false, the camera instantly moves to the endpoint, or else it smoothly moves */ void CameraNormal::moveCamera(float dt, bool smooth, float cam_angle, float distance) { if(!m_kart) return; - if (RewindManager::get()->isRewinding()) return; - Kart *kart = dynamic_cast(m_kart); - if (kart->isFlying()) + if (smooth && kart->isFlying()) { Vec3 vec3 = m_kart->getSmoothedXYZ() + Vec3(sinf(m_kart->getHeading()) * -4.0f, 0.5f, @@ -105,51 +99,30 @@ void CameraNormal::moveCamera(float dt, bool smooth, float cam_angle, float dist float skid_factor = ks->getVisualSkidRotation(); float skid_angle = asinf(skid_factor); - - // Adjust the distance of the camera to the kart with speed - // Note that distance is negative (< 0) float ratio = current_speed / max_speed_without_zipper; + ratio = ratio > -0.12f ? ratio : -0.12f; - float speed_factor = ((distance - 2.0f) - 1.0f * ratio) / (distance - 2.0f); - float camera_distance = distance * speed_factor; - // Adjust the camera angle + // distance of camera from kart in x and z plane + float camera_distance = -2.8f - 5.6f * ratio; + camera_distance *= sqrtf(UserConfigParams::m_camera_forward_smooth_position); + float min_distance = (distance * 2.0f); + if (distance > 0) camera_distance += distance + 1; // note that distance < 0 + if (camera_distance > min_distance) camera_distance = min_distance; // don't get too close to the kart + float tan_up = 0; - if (cam_angle > 0) tan_up = tanf(cam_angle) * std::max(distance - 1.0f, distance * (1.0f + 0.25f * ratio)); - // Avoid a camera razing the ground (it generates a lot of terrain clipping with the current near value of 1.0) - if (tan_up > -0.5f) - tan_up = -0.5f; - - // Defines how far the camera should be from the player's kart. - float squared_x = distance * sinf(skid_angle / 2); - squared_x *= squared_x; - float squared_y = tan_up; - squared_y *= squared_y; - float squared_z = distance * cosf(skid_angle / 2); - squared_z *= squared_z; - float length = sqrt(squared_x + squared_y + squared_z); - float camera_distance_factor = -camera_distance * camera_distance / length; - - Vec3 wanted_camera_offset(camera_distance_factor * sinf(skid_angle / 2), - -tan_up, - camera_distance_factor * cosf(skid_angle / 2)); - - float delta = 1; - float delta2 = 1; - if (smooth) - { - delta = (dt*5.0f); - if (delta < 0.0f) - delta = 0.0f; - else if (delta > 1.0f) - delta = 1.0f; - - delta2 = dt * 8.0f; - if (delta2 < 0) - delta2 = 0; - else if (delta2 > 1) - delta2 = 1; - } + if (cam_angle > 0) tan_up = tanf(cam_angle) * distance; + + // Defines how far camera should be from player kart. + Vec3 wanted_camera_offset(camera_distance * sinf(skid_angle / 2), + (0.85f + ratio / 2.5f) - tan_up, + camera_distance * cosf(skid_angle / 2)); + + float delta = dt / std::max(dt, float(UserConfigParams::m_camera_forward_smooth_position)); + float delta2 = dt / std::max(dt, float(UserConfigParams::m_camera_forward_smooth_rotation)); + + delta = irr::core::clamp(delta, 0.0f, 1.0f); + delta2 = irr::core::clamp(delta2, 0.0f, 1.0f); btTransform btt = m_kart->getSmoothedTrans(); m_kart_position = btt.getOrigin(); @@ -178,10 +151,12 @@ void CameraNormal::moveCamera(float dt, bool smooth, float cam_angle, float dist // kart_camera_position_with_offset.z(), current_target.x(), current_target.y(), // current_target.z()); - if(getMode()!=CM_FALLING) - m_camera->setPosition(current_position); - m_camera->setTarget(current_target.toIrrVector());//set new target - + if (smooth) + { + if(getMode()!=CM_FALLING) + m_camera->setPosition(current_position); + m_camera->setTarget(current_target.toIrrVector());//set new target + } assert(!std::isnan(m_camera->getPosition().X)); assert(!std::isnan(m_camera->getPosition().Y)); assert(!std::isnan(m_camera->getPosition().Z)); @@ -189,10 +164,21 @@ void CameraNormal::moveCamera(float dt, bool smooth, float cam_angle, float dist } // moveCamera //----------------------------------------------------------------------------- -void CameraNormal::snapToPosition() +void CameraNormal::restart() { - float angle = UserConfigParams::m_camera_forward_up_angle * DEGREE_TO_RAD; - moveCamera(1.0f, false, angle, -m_distance); + if (m_kart) + { + btTransform btt = m_kart->getSmoothedTrans(); + const Vec3& up = btt.getBasis().getColumn(1); + + m_camera->setUpVector(up.toIrrVector()); + m_kart_position = btt.getOrigin(); + m_kart_rotation = btt.getRotation(); + + float offset_z = -33.f * sqrtf(UserConfigParams::m_camera_forward_smooth_position); + float offset_y = -offset_z * tanf(UserConfigParams::m_camera_forward_up_angle * DEGREE_TO_RAD); + m_camera_offset = irr::core::vector3df(0., offset_y + 1.0f, offset_z); + } } // snapToPosition //----------------------------------------------------------------------------- @@ -203,27 +189,12 @@ void CameraNormal::snapToPosition() * \param distance Distance from kart. * \param cam_roll_angle Roll camera for gyroscope steering effect. */ -void CameraNormal::getCameraSettings(float *above_kart, float *cam_angle, +void CameraNormal::getCameraSettings(Mode mode, + float *above_kart, float *cam_angle, float *sideway, float *distance, bool *smoothing, float *cam_roll_angle) { - // Update the standard camera for users updating to 1.5 - if(!UserConfigParams::m_camera_updated_one_five) - { - UserConfigParams::m_standard_camera_fov.revertToDefaults(); - UserConfigParams::m_standard_camera_distance.revertToDefaults(); - UserConfigParams::m_standard_camera_forward_up_angle.revertToDefaults(); - if (UserConfigParams::m_camera_present == 1) // Currently using a standard camera - { - UserConfigParams::m_camera_fov.revertToDefaults(); - UserConfigParams::m_camera_distance.revertToDefaults(); - UserConfigParams::m_camera_forward_up_angle.revertToDefaults(); - m_distance = UserConfigParams::m_camera_distance; - } - UserConfigParams::m_camera_updated_one_five = true; - } - - switch(getMode()) + switch(mode) { case CM_NORMAL: case CM_FALLING: @@ -237,7 +208,8 @@ void CameraNormal::getCameraSettings(float *above_kart, float *cam_angle, // quadratically to dampen small variations (but keep sign) float dampened_steer = fabsf(steering) * steering; *sideway = -m_rotation_range*dampened_steer*0.5f; - *smoothing = UserConfigParams::m_camera_forward_smoothing; + *smoothing = UserConfigParams::m_camera_forward_smooth_position != 0. + || UserConfigParams::m_camera_forward_smooth_rotation != 0.; *cam_roll_angle = 0.0f; if (UserConfigParams::m_multitouch_controls == MULTITOUCH_CONTROLS_GYROSCOPE) { @@ -335,16 +307,18 @@ void CameraNormal::update(float dt) m_camera->setNearValue(1.0f); + float above_kart, cam_angle, side_way, distance, cam_roll_angle; + bool smoothing; + + getCameraSettings(getMode(), &above_kart, &cam_angle, &side_way, + &distance, &smoothing, &cam_roll_angle); + // If an explosion is happening, stop moving the camera, // but keep it target on the kart. ExplosionAnimation* ea = dynamic_cast(m_kart->getKartAnimation()); if (ea && !ea->hasResetAlready()) { - float above_kart, cam_angle, side_way, distance, cam_roll_angle; - bool smoothing; - - getCameraSettings(&above_kart, &cam_angle, &side_way, &distance, &smoothing, &cam_roll_angle); // The camera target needs to be 'smooth moved', otherwise // there will be a noticable jump in the first frame @@ -352,17 +326,29 @@ void CameraNormal::update(float dt) // above the kart). // Note: this code is replicated from smoothMoveCamera so that // the camera keeps on pointing to the same spot. + smoothing = false; + core::vector3df current_target = (m_kart->getSmoothedXYZ().toIrrVector() + core::vector3df(0, above_kart, 0)); m_camera->setTarget(current_target); } else // no kart animation { - float above_kart, cam_angle, side_way, distance, cam_roll_angle; - bool smoothing; - getCameraSettings(&above_kart, &cam_angle, &side_way, &distance, &smoothing, &cam_roll_angle); + if (smoothing) + { + m_last_smooth_mode = getMode(); + moveCamera(dt, true, cam_angle, distance); + } + positionCamera(dt, above_kart, cam_angle, side_way, distance, smoothing, cam_roll_angle); } + + if (!smoothing) + { + getCameraSettings(m_last_smooth_mode, &above_kart, &cam_angle, &side_way, + &distance, &smoothing, &cam_roll_angle); + moveCamera(dt, false, cam_angle, distance); + } } // update @@ -427,12 +413,8 @@ void CameraNormal::positionCamera(float dt, float above_kart, float cam_angle, t.setBasis(t.getBasis() * btMatrix3x3(q)); } wanted_position = t(relative_position); - - if (smoothing) - { - moveCamera(dt, true, cam_angle, distance); - } - else + + if (!smoothing) { if (getMode()!=CM_FALLING) m_camera->setPosition(wanted_position.toIrrVector()); @@ -469,4 +451,4 @@ void CameraNormal::positionCamera(float dt, float above_kart, float cam_angle, btMatrix3x3 m(q); m_camera->setUpVector(((Vec3)m.getColumn(1)).toIrrVector()); } -} // positionCamera +} // positionCamera \ No newline at end of file diff --git a/src/graphics/camera/camera_normal.hpp b/src/graphics/camera/camera_normal.hpp index af1d343ba89..61906ed2bb5 100644 --- a/src/graphics/camera/camera_normal.hpp +++ b/src/graphics/camera/camera_normal.hpp @@ -51,9 +51,12 @@ class CameraNormal : public Camera Vec3 m_camera_offset; + Mode m_last_smooth_mode; + void moveCamera(float dt, bool smooth, float cam_angle, float distance); - void handleEndCamera(float dt); - void getCameraSettings(float *above_kart, float *cam_angle, + + void getCameraSettings(Mode mode, + float *above_kart, float *cam_angle, float *side_way, float *distance, bool *smoothing, float *cam_roll_angle); @@ -73,8 +76,8 @@ class CameraNormal : public Camera virtual ~CameraNormal() {} public: - void snapToPosition(); - // ------------------------------------------------------------------------ + void restart(); + // ------------------------------------------------------------------------ bool isDebug() { return false; } // ------------------------------------------------------------------------ bool isFPS() { return false; } @@ -95,4 +98,4 @@ class CameraNormal : public Camera #endif -/* EOF */ +/* EOF */ \ No newline at end of file diff --git a/src/karts/controller/local_player_controller.cpp b/src/karts/controller/local_player_controller.cpp index f1498910a77..cc0bda814c3 100644 --- a/src/karts/controller/local_player_controller.cpp +++ b/src/karts/controller/local_player_controller.cpp @@ -272,7 +272,6 @@ void LocalPlayerController::update(int ticks) if (camera->getMode() == Camera::CM_REVERSE) { camera->setMode(Camera::CM_NORMAL); - dynamic_cast(camera)->snapToPosition(); } } if (m_sky_particles_emitter) diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 82cdc3829ae..a3247f067f8 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -138,7 +138,7 @@ World::World() : WorldStatus() m_schedule_exit_race = false; m_schedule_tutorial = false; m_is_network_world = false; - m_snap_camera = false; + m_restart_camera = false; m_stop_music_when_dialog_open = true; @@ -402,6 +402,11 @@ void World::reset(bool restart) // explosion animation will be created ProjectileManager::get()->cleanup(); resetAllKarts(); + + if (restart) + { + m_restart_camera = true; + } // Note: track reset must be called after all karts exist, since check // objects need to allocate data structures depending on the number // of karts. @@ -895,9 +900,6 @@ void World::resetAllKarts() { Camera* cam = Camera::getCamera(i); cam->setInitialTransform(); - // Ensure that smoothed cameras start from a correct position - if (cam->isNormal()) - dynamic_cast(cam)->snapToPosition(); } } } // resetAllKarts @@ -944,8 +946,6 @@ void World::moveKartTo(AbstractKart* kart, const btTransform &transform) // This will set the physics transform Track::getCurrentTrack()->findGround(kart); Track::getCurrentTrack()->getCheckManager()->resetAfterKartMove(kart); - - m_snap_camera = true; } // moveKartTo // ---------------------------------------------------------------------------- @@ -1029,18 +1029,6 @@ void World::updateWorld(int ticks) m_schedule_unpause = false; } - if (m_snap_camera) - { - m_snap_camera = false; - for(unsigned int i=0; iisNormal()) - dynamic_cast(cam)->snapToPosition(); - } - } - // Don't update world if a menu is shown or the race is over. // Exceptions : - Networking (local pause doesn't affect the server or other players) // - Benchmarking (a pause would mess up measurements) @@ -1176,6 +1164,16 @@ void World::update(int ticks) } #endif + if (m_restart_camera) + { + m_restart_camera = false; + for(unsigned int i=0; i(cam)->restart(); + } + } + PROFILER_PUSH_CPU_MARKER("World::update (sub-updates)", 0x20, 0x7F, 0x00); WorldStatus::update(ticks); PROFILER_POP_CPU_MARKER(); diff --git a/src/modes/world.hpp b/src/modes/world.hpp index d259e535096..b3b2db511e0 100644 --- a/src/modes/world.hpp +++ b/src/modes/world.hpp @@ -174,7 +174,7 @@ class World : public WorldStatus Phase m_scheduled_pause_phase; - bool m_snap_camera; + bool m_restart_camera; /** Set when the world needs to be deleted but you can't do it immediately * because you are e.g. within World::update() diff --git a/src/states_screens/dialogs/custom_camera_settings.cpp b/src/states_screens/dialogs/custom_camera_settings.cpp new file mode 100644 index 00000000000..37d5a4fb8ba --- /dev/null +++ b/src/states_screens/dialogs/custom_camera_settings.cpp @@ -0,0 +1,218 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2009-2015 Marianne Gagnon +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "states_screens/dialogs/custom_camera_settings.hpp" + +#include "config/user_config.hpp" +#include "guiengine/widgets/check_box_widget.hpp" +#include "guiengine/widgets/label_widget.hpp" +#include "guiengine/widgets/ribbon_widget.hpp" +#include "guiengine/widgets/spinner_widget.hpp" +#include "states_screens/options/options_screen_display.hpp" +#include "states_screens/state_manager.hpp" +#include "utils/translation.hpp" +#include "graphics/central_settings.hpp" +#include "graphics/irr_driver.hpp" +#include "utils/string_utils.hpp" +#include "utils/translation.hpp" + +#include + + +using namespace GUIEngine; +using namespace irr; +using namespace irr::core; +using namespace irr::gui; + +// ----------------------------------------------------------------------------- + +CustomCameraSettingsDialog::CustomCameraSettingsDialog(const float w, const float h) : + ModalDialog(w, h) +{ + m_self_destroy = false; + loadFromFile("custom_camera_settings.stkgui"); +} + +// ----------------------------------------------------------------------------- + +CustomCameraSettingsDialog::~CustomCameraSettingsDialog() +{ +} + + +// ----------------------------------------------------------------------------- + +void CustomCameraSettingsDialog::beforeAddingWidgets() +{ +#ifndef SERVER_ONLY + getWidget("fov")->setRange(75, 115); + getWidget("camera_distance")->setRange(0.05f, 20, 0.05f); + getWidget("smooth_position")->setRange(0.0f, 0.5f, 0.005f); + getWidget("smooth_rotation")->setRange(0.0f, 0.5f, 0.005f); + getWidget("camera_angle")->setRange(0, 80); + getWidget("backward_camera_distance")->setRange(0.05f, 20, 0.05f); + getWidget("backward_camera_angle")->setRange(0, 80); + if (UserConfigParams::m_camera_present == 1) // Standard camera + { + getWidget("camera_name")->setText(_("Standard"), false); + getWidget("fov")->setValue(UserConfigParams::m_standard_camera_fov); + getWidget("camera_distance")->setFloatValue(UserConfigParams::m_standard_camera_distance); + getWidget("camera_angle")->setValue(UserConfigParams::m_standard_camera_forward_up_angle); + getWidget("backward_camera_distance")->setFloatValue(UserConfigParams::m_standard_camera_backward_distance); + getWidget("backward_camera_angle")->setValue(UserConfigParams::m_standard_camera_backward_up_angle); + getWidget("smooth_position")->setFloatValue(UserConfigParams::m_standard_camera_forward_smooth_position); + getWidget("smooth_rotation")->setFloatValue(UserConfigParams::m_standard_camera_forward_smooth_rotation); + getWidget("use_soccer_camera")->setState(UserConfigParams::m_standard_reverse_look_use_soccer_cam); + } + else if (UserConfigParams::m_camera_present == 2) // Drone chase camera + { + getWidget("camera_name")->setText(_("Drone chase"), false); + getWidget("fov")->setValue(UserConfigParams::m_drone_camera_fov); + getWidget("camera_distance")->setFloatValue(UserConfigParams::m_drone_camera_distance); + getWidget("camera_angle")->setValue(UserConfigParams::m_drone_camera_forward_up_angle); + getWidget("backward_camera_distance")->setFloatValue(UserConfigParams::m_drone_camera_backward_distance); + getWidget("backward_camera_angle")->setValue(UserConfigParams::m_drone_camera_backward_up_angle); + getWidget("smooth_position")->setFloatValue(UserConfigParams::m_drone_camera_forward_smooth_position); + getWidget("smooth_rotation")->setFloatValue(UserConfigParams::m_drone_camera_forward_smooth_rotation); + getWidget("use_soccer_camera")->setState(UserConfigParams::m_drone_reverse_look_use_soccer_cam); + } + else // Custom camera + { + getWidget("camera_name")->setText(_("Custom"), false); + getWidget("fov")->setValue(UserConfigParams::m_saved_camera_fov); + getWidget("camera_distance")->setFloatValue(UserConfigParams::m_saved_camera_distance); + getWidget("camera_angle")->setValue(UserConfigParams::m_saved_camera_forward_up_angle); + getWidget("backward_camera_distance")->setFloatValue(UserConfigParams::m_saved_camera_backward_distance); + getWidget("backward_camera_angle")->setValue(UserConfigParams::m_saved_camera_backward_up_angle); + getWidget("smooth_position")->setFloatValue(UserConfigParams::m_saved_camera_forward_smooth_position); + getWidget("smooth_rotation")->setFloatValue(UserConfigParams::m_saved_camera_forward_smooth_rotation); + getWidget("use_soccer_camera")->setState(UserConfigParams::m_saved_reverse_look_use_soccer_cam); + } +#endif +} + +// ----------------------------------------------------------------------------- + +GUIEngine::EventPropagation CustomCameraSettingsDialog::processEvent(const std::string& eventSource) +{ +#ifndef SERVER_ONLY + if (eventSource == "buttons") + { + const std::string& selection = getWidget("buttons")-> + getSelectionIDString(PLAYER_ID_GAME_MASTER); + + if (selection == "apply") + { + UserConfigParams::m_camera_fov = getWidget("fov")->getValue(); + UserConfigParams::m_camera_distance = getWidget("camera_distance")->getFloatValue(); + UserConfigParams::m_camera_forward_up_angle = getWidget("camera_angle")->getValue(); + UserConfigParams::m_camera_backward_distance = getWidget("backward_camera_distance")->getFloatValue(); + UserConfigParams::m_camera_backward_up_angle = getWidget("backward_camera_angle")->getValue(); + UserConfigParams::m_camera_forward_smooth_position = getWidget("smooth_position")->getFloatValue(); + UserConfigParams::m_camera_forward_smooth_rotation = getWidget("smooth_rotation")->getFloatValue(); + UserConfigParams::m_reverse_look_use_soccer_cam = getWidget("use_soccer_camera")->getState(); + + if (UserConfigParams::m_camera_present == 1) // Standard camera, only smoothing and follow soccer is customizable + { + UserConfigParams::m_standard_camera_fov = UserConfigParams::m_camera_fov; + UserConfigParams::m_standard_camera_distance = UserConfigParams::m_camera_distance; + UserConfigParams::m_standard_camera_forward_up_angle = UserConfigParams::m_camera_forward_up_angle; + UserConfigParams::m_standard_camera_forward_smooth_position = UserConfigParams::m_camera_forward_smooth_position; + UserConfigParams::m_standard_camera_forward_smooth_rotation = UserConfigParams::m_camera_forward_smooth_rotation; + UserConfigParams::m_standard_camera_backward_distance = UserConfigParams::m_camera_backward_distance; + UserConfigParams::m_standard_camera_backward_up_angle = UserConfigParams::m_camera_backward_up_angle; + UserConfigParams::m_standard_reverse_look_use_soccer_cam = UserConfigParams::m_reverse_look_use_soccer_cam; + } + else if (UserConfigParams::m_camera_present == 2) // Drone chase camera, only smoothing and follow soccer is customizable + { + UserConfigParams::m_drone_camera_fov = UserConfigParams::m_camera_fov; + UserConfigParams::m_drone_camera_distance = UserConfigParams::m_camera_distance; + UserConfigParams::m_drone_camera_forward_up_angle = UserConfigParams::m_camera_forward_up_angle; + UserConfigParams::m_drone_camera_forward_smooth_position = UserConfigParams::m_camera_forward_smooth_position; + UserConfigParams::m_drone_camera_forward_smooth_rotation = UserConfigParams::m_camera_forward_smooth_rotation; + UserConfigParams::m_drone_camera_backward_distance = UserConfigParams::m_camera_backward_distance; + UserConfigParams::m_drone_camera_backward_up_angle = UserConfigParams::m_camera_backward_up_angle; + UserConfigParams::m_drone_reverse_look_use_soccer_cam = UserConfigParams::m_reverse_look_use_soccer_cam; + } + else // Custom camera, everything is customizable + { + UserConfigParams::m_saved_camera_fov = UserConfigParams::m_camera_fov; + UserConfigParams::m_saved_camera_distance = UserConfigParams::m_camera_distance; + UserConfigParams::m_saved_camera_forward_up_angle = UserConfigParams::m_camera_forward_up_angle; + UserConfigParams::m_saved_camera_forward_smooth_position = UserConfigParams::m_camera_forward_smooth_position; + UserConfigParams::m_saved_camera_forward_smooth_rotation = UserConfigParams::m_camera_forward_smooth_rotation; + UserConfigParams::m_saved_camera_backward_distance = UserConfigParams::m_camera_backward_distance; + UserConfigParams::m_saved_camera_backward_up_angle = UserConfigParams::m_camera_backward_up_angle; + UserConfigParams::m_saved_reverse_look_use_soccer_cam = UserConfigParams::m_reverse_look_use_soccer_cam; + } + OptionsScreenDisplay::getInstance()->updateCamera(); + m_self_destroy = true; + return GUIEngine::EVENT_BLOCK; + } + else if (selection == "reset") // discard all the changes + { + if (UserConfigParams::m_camera_present == 1) // Standard camera + { + UserConfigParams::m_camera_fov = 80; + UserConfigParams::m_camera_distance = 1.0; + UserConfigParams::m_camera_forward_up_angle = 0.0; + UserConfigParams::m_camera_forward_smooth_position = 0.2; + UserConfigParams::m_camera_forward_smooth_rotation = 0.125; + UserConfigParams::m_camera_backward_distance = 2.0; + UserConfigParams::m_camera_backward_up_angle = 10; + UserConfigParams::m_reverse_look_use_soccer_cam = false; + } + else if (UserConfigParams::m_camera_present == 2) // Drone chase camera + { + UserConfigParams::m_camera_fov = 100; + UserConfigParams::m_camera_distance = 2.6; + UserConfigParams::m_camera_forward_up_angle = 33; + UserConfigParams::m_camera_forward_smooth_position = 0.0; + UserConfigParams::m_camera_forward_smooth_rotation = 0.0; + UserConfigParams::m_camera_backward_distance = 2.0; + UserConfigParams::m_camera_backward_up_angle = 10; + UserConfigParams::m_reverse_look_use_soccer_cam = false; + } + else // Custom camera + { + UserConfigParams::m_camera_fov = UserConfigParams::m_saved_camera_fov; + UserConfigParams::m_camera_distance = UserConfigParams::m_saved_camera_distance; + UserConfigParams::m_camera_forward_up_angle = UserConfigParams::m_saved_camera_forward_up_angle; + UserConfigParams::m_camera_forward_smooth_position = UserConfigParams::m_saved_camera_forward_smooth_position; + UserConfigParams::m_camera_forward_smooth_rotation = UserConfigParams::m_saved_camera_forward_smooth_rotation; + UserConfigParams::m_camera_backward_distance = UserConfigParams::m_saved_camera_backward_distance; + UserConfigParams::m_camera_backward_up_angle = UserConfigParams::m_saved_camera_backward_up_angle; + UserConfigParams::m_reverse_look_use_soccer_cam = UserConfigParams::m_saved_reverse_look_use_soccer_cam; + } + getWidget("fov")->setValue(UserConfigParams::m_camera_fov); + getWidget("camera_distance")->setFloatValue(UserConfigParams::m_camera_distance); + getWidget("camera_angle")->setValue(UserConfigParams::m_camera_forward_up_angle); + getWidget("smooth_position")->setFloatValue(UserConfigParams::m_camera_forward_smooth_position); + getWidget("smooth_rotation")->setFloatValue(UserConfigParams::m_camera_forward_smooth_rotation); + getWidget("backward_camera_distance")->setFloatValue(UserConfigParams::m_camera_backward_distance); + getWidget("backward_camera_angle")->setValue(UserConfigParams::m_camera_backward_up_angle); + getWidget("use_soccer_camera")->setState(UserConfigParams::m_reverse_look_use_soccer_cam); + } + else if (selection == "cancel") + { + ModalDialog::dismiss(); + return GUIEngine::EVENT_BLOCK; + } + } +#endif + return GUIEngine::EVENT_LET; +} // processEvent \ No newline at end of file diff --git a/src/states_screens/dialogs/custom_camera_settings.hpp b/src/states_screens/dialogs/custom_camera_settings.hpp new file mode 100644 index 00000000000..0b5b62206e9 --- /dev/null +++ b/src/states_screens/dialogs/custom_camera_settings.hpp @@ -0,0 +1,63 @@ +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2009-2015 Marianne Gagnon +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifndef HEADER_CUSTOM_CAMERA_SETTINGS_HPP +#define HEADER_CUSTOM_CAMERA_SETTINGS_HPP + +#include "guiengine/modaldialog.hpp" + +/** + * \brief Dialog that allows the player to select custom video settings + * \ingroup states_screens + */ +class CustomCameraSettingsDialog : public GUIEngine::ModalDialog +{ +private: + bool m_self_destroy; +public: + /** + * Creates a modal dialog with given percentage of screen width and height + */ + CustomCameraSettingsDialog(const float percentWidth, const float percentHeight); + ~CustomCameraSettingsDialog(); + + virtual void beforeAddingWidgets(); + + void updateActivation(); + + GUIEngine::EventPropagation processEvent(const std::string& eventSource); + + virtual bool onEscapePressed() + { + m_self_destroy = true; + return false; + } + + virtual void onUpdate(float dt) + { + // It's unsafe to delete from inside the event handler so we do it here + if (m_self_destroy) + { + ModalDialog::dismiss(); + return; + } + } + +}; + +#endif \ No newline at end of file diff --git a/src/states_screens/options/options_common.cpp b/src/states_screens/options/options_common.cpp index 3217e59a29e..104fedc09ed 100644 --- a/src/states_screens/options/options_common.cpp +++ b/src/states_screens/options/options_common.cpp @@ -36,8 +36,6 @@ namespace OptionsCommon screen = OptionsScreenInput::getInstance(); else if (selected_tab == "tab_ui") screen = OptionsScreenUI::getInstance(); - else if (selected_tab == "tab_camera") - screen = OptionsScreenCamera::getInstance(); else if (selected_tab == "tab_general") screen = OptionsScreenGeneral::getInstance(); else if (selected_tab == "tab_language") diff --git a/src/states_screens/options/options_common.hpp b/src/states_screens/options/options_common.hpp index 3d0e74a582b..9a618f06070 100644 --- a/src/states_screens/options/options_common.hpp +++ b/src/states_screens/options/options_common.hpp @@ -34,7 +34,6 @@ // Other option screens, for navigation between them #include "states_screens/options/options_screen_audio.hpp" -#include "states_screens/options/options_screen_camera.hpp" #include "states_screens/options/options_screen_display.hpp" #include "states_screens/options/options_screen_general.hpp" #include "states_screens/options/options_screen_input.hpp" diff --git a/src/states_screens/options/options_screen_camera.cpp b/src/states_screens/options/options_screen_camera.cpp deleted file mode 100644 index d1b602891d9..00000000000 --- a/src/states_screens/options/options_screen_camera.cpp +++ /dev/null @@ -1,297 +0,0 @@ -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2009-2025 Marianne Gagnon, Alayan et al. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 3 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -// Manages includes common to all options screens -#include "states_screens/options/options_common.hpp" - -#include "graphics/camera/camera.hpp" -#include "graphics/camera/camera_normal.hpp" -#include "config/player_manager.hpp" -#include "states_screens/dialogs/message_dialog.hpp" -#include "states_screens/main_menu_screen.hpp" - -#include - -using namespace GUIEngine; -using namespace Online; - -// ----------------------------------------------------------------------------- - -OptionsScreenCamera::OptionsScreenCamera() : Screen("options/options_camera.stkgui") -{ - m_inited = false; -} // OptionsScreenCamera - -// ----------------------------------------------------------------------------- - -void OptionsScreenCamera::loadedFromFile() -{ - m_inited = false; - - // Setup the camera spinner - GUIEngine::SpinnerWidget* camera_preset = getWidget("camera_preset"); - assert( camera_preset != NULL ); - - camera_preset->m_properties[PROP_WRAP_AROUND] = "true"; - camera_preset->clearLabels(); - //I18N: In the UI options, Camera setting: Custom - camera_preset->addLabel( core::stringw(_("Custom"))); - //I18N: In the UI options, Camera setting: Standard - camera_preset->addLabel( core::stringw(_("Standard"))); - //I18N: In the UI options, Camera setting: Drone chase - camera_preset->addLabel( core::stringw(_("Drone chase"))); - camera_preset->m_properties[GUIEngine::PROP_MIN_VALUE] = "0"; - camera_preset->m_properties[GUIEngine::PROP_MAX_VALUE] = "2"; - updateCameraPresetSpinner(); - -#ifndef SERVER_ONLY - getWidget("fov")->setRange(75, 115); - getWidget("camera_distance")->setRange(0.05f, 20, 0.05f); - getWidget("camera_angle")->setRange(0, 80); - getWidget("backward_camera_distance")->setRange(0.05f, 20, 0.05f); - getWidget("backward_camera_angle")->setRange(0, 80); -#endif -} // loadedFromFile - -// ----------------------------------------------------------------------------- - -void OptionsScreenCamera::init() -{ - Screen::init(); - OptionsCommon::setTabStatus(); - - RibbonWidget* ribbon = getWidget("options_choice"); - assert(ribbon != NULL); - ribbon->setFocusForPlayer(PLAYER_ID_GAME_MASTER); - ribbon->select( "tab_camera", PLAYER_ID_GAME_MASTER ); - - // --- select the right camera in the spinner - GUIEngine::SpinnerWidget* camera_preset = getWidget("camera_preset"); - assert( camera_preset != NULL ); - - camera_preset->setValue(UserConfigParams::m_camera_present); // use the saved camera - updateCameraPresetSpinner(); - -#ifndef SERVER_ONLY - getWidget("fov")->setRange(75, 115); - getWidget("camera_distance")->setRange(0.05f, 20, 0.05f); - getWidget("camera_angle")->setRange(0, 80); - getWidget("backward_camera_distance")->setRange(0.05f, 20, 0.05f); - getWidget("backward_camera_angle")->setRange(0, 80); - if (UserConfigParams::m_camera_present == 1) // Standard camera - { - setCameraParameters (UserConfigParams::m_standard_camera_fov, UserConfigParams::m_standard_camera_distance, - UserConfigParams::m_standard_camera_forward_up_angle, UserConfigParams::m_standard_camera_backward_distance, - UserConfigParams::m_standard_camera_backward_up_angle, UserConfigParams::m_standard_camera_forward_smoothing, - UserConfigParams::m_standard_reverse_look_use_soccer_cam); - // Not allowed to change fov, distance, and angles. Only allow to change smoothing and follow soccer - setSpinnersActive(false); - } - else if (UserConfigParams::m_camera_present == 2) // Drone chase camera - { - setCameraParameters (UserConfigParams::m_drone_camera_fov, UserConfigParams::m_drone_camera_distance, - UserConfigParams::m_drone_camera_forward_up_angle, UserConfigParams::m_drone_camera_backward_distance, - UserConfigParams::m_drone_camera_backward_up_angle, UserConfigParams::m_drone_camera_forward_smoothing, - UserConfigParams::m_drone_reverse_look_use_soccer_cam); - // Not allowed to change fov, distance, and angles. Only allow to change smoothing and follow soccer - setSpinnersActive(false); - } - else // Custom camera - { - setCameraParameters (UserConfigParams::m_saved_camera_fov, UserConfigParams::m_saved_camera_distance, - UserConfigParams::m_saved_camera_forward_up_angle, UserConfigParams::m_saved_camera_backward_distance, - UserConfigParams::m_saved_camera_backward_up_angle, UserConfigParams::m_saved_camera_forward_smoothing, - UserConfigParams::m_saved_reverse_look_use_soccer_cam); - setSpinnersActive(true); - } -#endif -} // init - -// ----------------------------------------------------------------------------- -void OptionsScreenCamera::updateCamera() -{ - bool in_game = StateManager::get()->getGameState() == GUIEngine::INGAME_MENU; - if (in_game) - { - (Camera::getActiveCamera()->getCameraSceneNode())->setFOV(DEGREE_TO_RAD * UserConfigParams::m_camera_fov); - CameraNormal *camera = dynamic_cast(Camera::getActiveCamera()); - if (camera) - { - camera->setDistanceToKart(UserConfigParams::m_camera_distance); - } - } -} // updateCamera - -// ----------------------------------------------------------------------------- -void OptionsScreenCamera::updateCameraPresetSpinner() -{ - updateCamera(); -} // updateCameraPresetSpinner - -// ----------------------------------------------------------------------------- -void OptionsScreenCamera::setSpinnersActive(bool spinner_status) -{ - getWidget("fov")->setActive(spinner_status); - getWidget("camera_distance")->setActive(spinner_status); - getWidget("camera_angle")->setActive(spinner_status); - getWidget("backward_camera_distance")->setActive(spinner_status); - getWidget("backward_camera_angle")->setActive(spinner_status); -} // setSpinnersActive - -// ----------------------------------------------------------------------------- -void OptionsScreenCamera::setCameraParameters(int fov, float distance, float angle, float bw_distance, - float bw_angle, bool forward_smoothing, bool soccer_follow) -{ - UserConfigParams::m_camera_fov = fov; - UserConfigParams::m_camera_distance = distance; - UserConfigParams::m_camera_forward_up_angle = angle; - UserConfigParams::m_camera_backward_distance = bw_distance; - UserConfigParams::m_camera_backward_up_angle = bw_angle; - UserConfigParams::m_camera_forward_smoothing = forward_smoothing; - UserConfigParams::m_reverse_look_use_soccer_cam = soccer_follow; - - // Update the widget values alongside - getWidget("fov")->setValue(fov); - getWidget("camera_distance")->setFloatValue(distance); - getWidget("camera_angle")->setValue(angle); - getWidget("backward_camera_distance")->setFloatValue(bw_distance); - getWidget("backward_camera_angle")->setValue(bw_angle); - getWidget("camera_smoothing")->setState(forward_smoothing); - getWidget("use_soccer_camera")->setState(soccer_follow); -} // setCameraParameters - -// ----------------------------------------------------------------------------- -void OptionsScreenCamera::eventCallback(Widget* widget, const std::string& name, const int playerID) -{ -#ifndef SERVER_ONLY - if (name == "options_choice") - { - std::string selection = ((RibbonWidget*)widget)->getSelectionIDString(PLAYER_ID_GAME_MASTER); - - if (selection != "tab_camera") - OptionsCommon::switchTab(selection); - } - else if(name == "back") - { - StateManager::get()->escapePressed(); - } - else if (name == "camera_preset") - { - GUIEngine::SpinnerWidget* camera_preset = getWidget("camera_preset"); - assert( camera_preset != NULL ); - unsigned int i = camera_preset->getValue(); - UserConfigParams::m_camera_present = i; - if (i == 1) //Standard - { - setCameraParameters (UserConfigParams::m_standard_camera_fov, UserConfigParams::m_standard_camera_distance, - UserConfigParams::m_standard_camera_forward_up_angle, UserConfigParams::m_standard_camera_backward_distance, - UserConfigParams::m_standard_camera_backward_up_angle, UserConfigParams::m_standard_camera_forward_smoothing, - UserConfigParams::m_standard_reverse_look_use_soccer_cam); - setSpinnersActive(false); - } - else if (i == 2) //Drone chase - { - setCameraParameters (UserConfigParams::m_drone_camera_fov, UserConfigParams::m_drone_camera_distance, - UserConfigParams::m_drone_camera_forward_up_angle, UserConfigParams::m_drone_camera_backward_distance, - UserConfigParams::m_drone_camera_backward_up_angle, UserConfigParams::m_drone_camera_forward_smoothing, - UserConfigParams::m_drone_reverse_look_use_soccer_cam); - setSpinnersActive(false); - } - else //Custom - { - setCameraParameters (UserConfigParams::m_saved_camera_fov, UserConfigParams::m_saved_camera_distance, - UserConfigParams::m_saved_camera_forward_up_angle, UserConfigParams::m_saved_camera_backward_distance, - UserConfigParams::m_saved_camera_backward_up_angle, UserConfigParams::m_saved_camera_forward_smoothing, - UserConfigParams::m_saved_reverse_look_use_soccer_cam); - setSpinnersActive(true); - } - updateCamera(); - } - else if (name == "camera_smoothing") - { - UserConfigParams::m_camera_forward_smoothing = getWidget("camera_smoothing")->getState(); - if (UserConfigParams::m_camera_present == 1) // Standard camera - UserConfigParams::m_standard_camera_forward_smoothing = UserConfigParams::m_camera_forward_smoothing; - else if (UserConfigParams::m_camera_present == 2) // Drone chase camera - UserConfigParams::m_drone_camera_forward_smoothing = UserConfigParams::m_camera_forward_smoothing; - else // Custom camera - UserConfigParams::m_saved_camera_forward_smoothing = UserConfigParams::m_camera_forward_smoothing; - updateCamera(); - } - else if (name == "use_soccer_camera") - { - UserConfigParams::m_reverse_look_use_soccer_cam = getWidget("use_soccer_camera")->getState(); - if (UserConfigParams::m_camera_present == 1) // Standard camera - UserConfigParams::m_standard_reverse_look_use_soccer_cam = UserConfigParams::m_reverse_look_use_soccer_cam; - else if (UserConfigParams::m_camera_present == 2) // Drone chase camera - UserConfigParams::m_drone_reverse_look_use_soccer_cam = UserConfigParams::m_reverse_look_use_soccer_cam; - else // Custom camera - UserConfigParams::m_saved_reverse_look_use_soccer_cam = UserConfigParams::m_reverse_look_use_soccer_cam; - updateCamera(); - } - // Only the custom camera can update the following widgets, so we don't test the active camera preset - else if (name == "fov") - { - UserConfigParams::m_camera_fov = getWidget("fov")->getValue(); - UserConfigParams::m_saved_camera_fov = UserConfigParams::m_camera_fov; - updateCamera(); - } - else if (name == "camera_distance") - { - UserConfigParams::m_camera_distance = getWidget("camera_distance")->getFloatValue(); - UserConfigParams::m_saved_camera_distance = UserConfigParams::m_camera_distance; - updateCamera(); - } - else if (name == "camera_angle") - { - UserConfigParams::m_camera_forward_up_angle = getWidget("camera_angle")->getValue(); - UserConfigParams::m_saved_camera_forward_up_angle = UserConfigParams::m_camera_forward_up_angle; - updateCamera(); - } - - else if (name == "backward_camera_distance") - { - UserConfigParams::m_camera_backward_distance = getWidget("backward_camera_distance")->getFloatValue(); - UserConfigParams::m_saved_camera_backward_distance = UserConfigParams::m_camera_backward_distance; - updateCamera(); - } - else if (name == "backward_camera_angle") - { - UserConfigParams::m_camera_backward_up_angle = getWidget("backward_camera_angle")->getValue(); - UserConfigParams::m_saved_camera_backward_up_angle = UserConfigParams::m_camera_backward_up_angle; - updateCamera(); - } -#endif -} // eventCallback - -// ----------------------------------------------------------------------------- - -void OptionsScreenCamera::tearDown() -{ - Screen::tearDown(); - // save changes when leaving screen - user_config->saveConfig(); -} // tearDown - -// ----------------------------------------------------------------------------- - -void OptionsScreenCamera::unloaded() -{ - m_inited = false; -} // unloaded - -// ----------------------------------------------------------------------------- diff --git a/src/states_screens/options/options_screen_camera.hpp b/src/states_screens/options/options_screen_camera.hpp deleted file mode 100644 index ba0ec1309b9..00000000000 --- a/src/states_screens/options/options_screen_camera.hpp +++ /dev/null @@ -1,71 +0,0 @@ -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2009-2025 Marianne Gagnon, Alayan et al. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 3 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - -#ifndef __HEADER_OPTIONS_SCREEN_CAMERA_HPP__ -#define __HEADER_OPTIONS_SCREEN_CAMERA_HPP__ - -#include -#include - -#include "guiengine/screen.hpp" - -namespace GUIEngine { class Widget; } - -/** - * \brief Graphics options screen - * \ingroup states_screens - */ -class OptionsScreenCamera : public GUIEngine::Screen, public GUIEngine::ScreenSingleton -{ - OptionsScreenCamera(); - bool m_inited; - - void updateCamera(); -public: - friend class GUIEngine::ScreenSingleton; - - /** \brief implement callback from parent class GUIEngine::Screen */ - virtual void loadedFromFile() OVERRIDE; - - /** \brief implement callback from parent class GUIEngine::Screen */ - virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name, - const int playerID) OVERRIDE; - - /** \brief implement callback from parent class GUIEngine::Screen */ - virtual void init() OVERRIDE; - - /** \brief implement callback from parent class GUIEngine::Screen */ - virtual void tearDown() OVERRIDE; - - /** \brief implement optional callback from parent class GUIEngine::Screen */ - virtual void unloaded() OVERRIDE; - - void updateCameraPresetSpinner(); - - /** Enables or disables the spinners allowing to customize a camera values */ - void setSpinnersActive(bool spinner_status); - - /** Update the active camera parameters and the status of the parameters widgets, - * used when switching the active camera */ - void setCameraParameters(int fov, float distance, float angle, float bw_distance, - float bw_angle, bool forward_smoothing, bool soccer_follow); - - void reloadGUIEngine(); -}; - -#endif diff --git a/src/states_screens/options/options_screen_display.cpp b/src/states_screens/options/options_screen_display.cpp index 09148348eda..db450411289 100644 --- a/src/states_screens/options/options_screen_display.cpp +++ b/src/states_screens/options/options_screen_display.cpp @@ -20,8 +20,10 @@ #include "states_screens/options/options_common.hpp" #include "graphics/camera/camera.hpp" +#include "graphics/camera/camera_normal.hpp" #include "graphics/irr_driver.hpp" #include "modes/world.hpp" +#include "states_screens/dialogs/custom_camera_settings.hpp" #ifndef SERVER_ONLY #include @@ -59,6 +61,22 @@ void OptionsScreenDisplay::loadedFromFile() splitscreen_method->addLabel( core::stringw(_("Horizontal"))); splitscreen_method->m_properties[GUIEngine::PROP_MIN_VALUE] = "0"; splitscreen_method->m_properties[GUIEngine::PROP_MAX_VALUE] = "1"; + + // Setup camera spinner + GUIEngine::SpinnerWidget* camera_preset = getWidget("camera_preset"); + assert( camera_preset != NULL ); + + camera_preset->m_properties[PROP_WRAP_AROUND] = "true"; + camera_preset->clearLabels(); + //I18N: In the UI options, Camera setting: Custom + camera_preset->addLabel( core::stringw(_("Custom"))); + //I18N: In the UI options, Camera setting: Standard + camera_preset->addLabel( core::stringw(_("Standard"))); + //I18N: In the UI options, Camera setting: Drone chase + camera_preset->addLabel( core::stringw(_("Drone chase"))); + camera_preset->m_properties[GUIEngine::PROP_MIN_VALUE] = "0"; + camera_preset->m_properties[GUIEngine::PROP_MAX_VALUE] = "2"; + updateCamera(); } // loadedFromFile // -------------------------------------------------------------------------------------------- @@ -127,6 +145,13 @@ void OptionsScreenDisplay::init() updateResolutionsList(); + // --- select the right camera in the spinner + GUIEngine::SpinnerWidget* camera_preset = getWidget("camera_preset"); + assert( camera_preset != NULL ); + + camera_preset->setValue(UserConfigParams::m_camera_present); // use the saved camera + updateCamera(); + // ---- splitscreen mode GUIEngine::SpinnerWidget* splitscreen_method = getWidget("splitscreen_method"); assert( splitscreen_method != NULL ); @@ -298,6 +323,21 @@ void OptionsScreenDisplay::configResolutionsList() } // configResolutionsList +// ----------------------------------------------------------------------------- +void OptionsScreenDisplay::updateCamera() +{ + bool in_game = StateManager::get()->getGameState() == GUIEngine::INGAME_MENU; + if (in_game) + { + (Camera::getActiveCamera()->getCameraSceneNode())->setFOV(DEGREE_TO_RAD * UserConfigParams::m_camera_fov); + CameraNormal *camera = dynamic_cast(Camera::getActiveCamera()); + if (camera) + { + camera->setDistanceToKart(UserConfigParams::m_camera_distance); + } + } +} // updateCamera + // -------------------------------------------------------------------------------------------- void OptionsScreenDisplay::updateResolutionsList() @@ -403,6 +443,51 @@ void OptionsScreenDisplay::eventCallback(Widget* widget, const std::string& name updateResolutionsList(); #endif } // fullscreen + else if (name == "camera_preset") + { + GUIEngine::SpinnerWidget* camera_preset = getWidget("camera_preset"); + assert( camera_preset != NULL ); + unsigned int i = camera_preset->getValue(); + UserConfigParams::m_camera_present = i; + if (i == 1) // Standard + { + UserConfigParams::m_camera_fov = UserConfigParams::m_standard_camera_fov; + UserConfigParams::m_camera_distance = UserConfigParams::m_standard_camera_distance; + UserConfigParams::m_camera_forward_up_angle = UserConfigParams::m_standard_camera_forward_up_angle; + UserConfigParams::m_camera_forward_smooth_position = UserConfigParams::m_standard_camera_forward_smooth_position; + UserConfigParams::m_camera_forward_smooth_rotation = UserConfigParams::m_standard_camera_forward_smooth_rotation; + UserConfigParams::m_camera_backward_distance = UserConfigParams::m_standard_camera_backward_distance; + UserConfigParams::m_camera_backward_up_angle = UserConfigParams::m_standard_camera_backward_up_angle; + UserConfigParams::m_reverse_look_use_soccer_cam = UserConfigParams::m_standard_reverse_look_use_soccer_cam; + } + else if (i == 2) // Drone chase + { + UserConfigParams::m_camera_fov = UserConfigParams::m_drone_camera_fov; + UserConfigParams::m_camera_distance = UserConfigParams::m_drone_camera_distance; + UserConfigParams::m_camera_forward_up_angle = UserConfigParams::m_drone_camera_forward_up_angle; + UserConfigParams::m_camera_forward_smooth_position = UserConfigParams::m_drone_camera_forward_smooth_position; + UserConfigParams::m_camera_forward_smooth_rotation = UserConfigParams::m_drone_camera_forward_smooth_rotation; + UserConfigParams::m_camera_backward_distance = UserConfigParams::m_drone_camera_backward_distance; + UserConfigParams::m_camera_backward_up_angle = UserConfigParams::m_drone_camera_backward_up_angle; + UserConfigParams::m_reverse_look_use_soccer_cam = UserConfigParams::m_drone_reverse_look_use_soccer_cam; + } + else // Custom + { + UserConfigParams::m_camera_fov = UserConfigParams::m_saved_camera_fov; + UserConfigParams::m_camera_distance = UserConfigParams::m_saved_camera_distance; + UserConfigParams::m_camera_forward_up_angle = UserConfigParams::m_saved_camera_forward_up_angle; + UserConfigParams::m_camera_forward_smooth_position = UserConfigParams::m_saved_camera_forward_smooth_position; + UserConfigParams::m_camera_forward_smooth_rotation = UserConfigParams::m_saved_camera_forward_smooth_rotation; + UserConfigParams::m_camera_backward_distance = UserConfigParams::m_saved_camera_backward_distance; + UserConfigParams::m_camera_backward_up_angle = UserConfigParams::m_saved_camera_backward_up_angle; + UserConfigParams::m_reverse_look_use_soccer_cam = UserConfigParams::m_saved_reverse_look_use_soccer_cam; + } + updateCamera(); + } + else if(name == "custom_camera") + { + new CustomCameraSettingsDialog(0.8f, 0.95f); + } else if (name == "splitscreen_method") { GUIEngine::SpinnerWidget* splitscreen_method = getWidget("splitscreen_method"); diff --git a/src/states_screens/options/options_screen_display.hpp b/src/states_screens/options/options_screen_display.hpp index c83bf48dea8..68accbbb804 100644 --- a/src/states_screens/options/options_screen_display.hpp +++ b/src/states_screens/options/options_screen_display.hpp @@ -68,7 +68,7 @@ class OptionsScreenDisplay : public GUIEngine::Screen, public GUIEngine::ScreenS void updateResolutionsList(); void configResolutionsList(); - void initPresets(); + static void onScrollResolutionsList(void* data); public: friend class GUIEngine::ScreenSingleton; @@ -92,6 +92,8 @@ class OptionsScreenDisplay : public GUIEngine::Screen, public GUIEngine::ScreenS virtual bool onEscapePressed() OVERRIDE; virtual void onResize() OVERRIDE; + + void updateCamera(); }; #endif diff --git a/src/states_screens/options/options_screen_ui.hpp b/src/states_screens/options/options_screen_ui.hpp index c17fd90cc38..a8d23694bf7 100644 --- a/src/states_screens/options/options_screen_ui.hpp +++ b/src/states_screens/options/options_screen_ui.hpp @@ -58,6 +58,8 @@ class OptionsScreenUI : public GUIEngine::Screen, public GUIEngine::ScreenSingle GUIEngine::SpinnerWidget* m_base_skin_selector; GUIEngine::SpinnerWidget* m_variant_skin_selector; + void updateCamera(); + void loadSkins(const std::set& files, bool addon); void loadCurrentSkinVariants(); int getBaseID(SkinID skin); @@ -83,6 +85,8 @@ class OptionsScreenUI : public GUIEngine::Screen, public GUIEngine::ScreenSingle /** \brief implement optional callback from parent class GUIEngine::Screen */ virtual void unloaded() OVERRIDE; + void updateCameraPresetSpinner(); + virtual void onUpdate(float delta) OVERRIDE; void reloadGUIEngine(); From 146f0d0f5a88b5b8af0f13491ca8f37709a6c276 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sat, 8 Mar 2025 16:08:19 +0800 Subject: [PATCH 588/830] Fix explosion camera bug --- src/graphics/camera/camera_normal.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/graphics/camera/camera_normal.cpp b/src/graphics/camera/camera_normal.cpp index 2048361a4fa..7b0fe092c3a 100644 --- a/src/graphics/camera/camera_normal.cpp +++ b/src/graphics/camera/camera_normal.cpp @@ -326,8 +326,6 @@ void CameraNormal::update(float dt) // above the kart). // Note: this code is replicated from smoothMoveCamera so that // the camera keeps on pointing to the same spot. - smoothing = false; - core::vector3df current_target = (m_kart->getSmoothedXYZ().toIrrVector() + core::vector3df(0, above_kart, 0)); m_camera->setTarget(current_target); From 6fdf215549fef57a2530413a815b1693f994061f Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 10 Mar 2025 16:30:49 +0800 Subject: [PATCH 589/830] Fix out-of-focus text box widget when alphabet characters are assigned as navigation --- src/guiengine/widgets/text_box_widget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/guiengine/widgets/text_box_widget.cpp b/src/guiengine/widgets/text_box_widget.cpp index f1b78925f7e..70eeccdca8d 100644 --- a/src/guiengine/widgets/text_box_widget.cpp +++ b/src/guiengine/widgets/text_box_widget.cpp @@ -58,6 +58,7 @@ class MyCGUIEditBox : public CGUIEditBox { for (unsigned n = 0; n < m_listeners.size(); n++) m_listeners[n].onTextUpdated(); + GUIEngine::setWithinATextBox(true); } bool handleEnterPressed() From 6c287e0a9989df40caa38d863b2460db808ebc4e Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Tue, 11 Mar 2025 19:42:11 +0800 Subject: [PATCH 590/830] Fix #5252 & #5189 (#5367) --- src/karts/ghost_kart.cpp | 57 ++++++++++++++++++++++++++++++++++++++++ src/karts/ghost_kart.hpp | 7 +++++ src/karts/kart.cpp | 13 ++++++--- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/karts/ghost_kart.cpp b/src/karts/ghost_kart.cpp index e58225c62ff..fb46ed5b191 100644 --- a/src/karts/ghost_kart.cpp +++ b/src/karts/ghost_kart.cpp @@ -16,6 +16,8 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include "audio/sfx_manager.hpp" +#include "audio/sfx_base.hpp" #include "items/attachment.hpp" #include "items/powerup.hpp" #include "karts/ghost_kart.hpp" @@ -26,6 +28,7 @@ #include "modes/linear_world.hpp" #include "modes/world.hpp" #include "replay/replay_recorder.hpp" +#include "tracks/terrain_info.hpp" #include "tracks/track.hpp" #include "LinearMath/btQuaternion.h" @@ -99,6 +102,8 @@ void GhostKart::updateGraphics(float dt) Moveable::updateGraphics(center_shift, btQuaternion(0, 0, 0, 1)); // Also update attachment's graphics m_attachment->updateGraphics(dt); + + updateSound(dt); } // updateGraphics // ---------------------------------------------------------------------------- @@ -219,6 +224,8 @@ void GhostKart::update(int ticks) m_all_replay_events[idx].m_red_skidding); getKartGFX()->update(dt); + m_speed = getSpeed(); + Vec3 front(0, 0, getKartLength()*0.5f); m_xyz_front = getTrans()(front); @@ -233,12 +240,62 @@ void GhostKart::update(int ticks) getKartModel()->setAnimation(KartModel::AF_DEFAULT); } + m_terrain_info->update(getTrans().getBasis(), + getXYZ() + getTrans().getBasis().getColumn(1) * 0.1f); } // update +// ---------------------------------------------------------------------------- +void GhostKart::updateSound(float dt) +{ + if (!getController()) return; + + GhostController* gc = dynamic_cast(getController()); + if (gc == NULL) return; + + const unsigned int idx = gc->getCurrentReplayIndex(); + + updateEngineSFX(dt); + + if (m_skid_sound) + { + if(m_all_replay_events[idx].m_skidding_effect) + { + if (m_skid_sound->getStatus()!=SFXBase::SFX_PLAYING) + { + m_skid_sound->play(getSmoothedXYZ()); + } + } + else if(m_skid_sound->getStatus()==SFXBase::SFX_PLAYING) + { + m_skid_sound->stop(); + } + } + + if (m_nitro_sound) + { + if(m_all_replay_events[idx].m_nitro_usage) + { + if (m_nitro_sound->getStatus()!=SFXBase::SFX_PLAYING) + { + m_nitro_sound->play(getSmoothedXYZ()); + } + } + else if(m_nitro_sound->getStatus()==SFXBase::SFX_PLAYING) + { + m_nitro_sound->stop(); + } + } +} + // ---------------------------------------------------------------------------- /** Returns the speed of the kart in meters/second. */ float GhostKart::getSpeed() const { + if (!getController()) + { + return 0.f; + } + const GhostController* gc = dynamic_cast(getController()); diff --git a/src/karts/ghost_kart.hpp b/src/karts/ghost_kart.hpp index 34afb2df7cc..a6d4048c4f5 100644 --- a/src/karts/ghost_kart.hpp +++ b/src/karts/ghost_kart.hpp @@ -55,6 +55,10 @@ class GhostKart : public Kart // ---------------------------------------------------------------------------- /** Compute the time at which the ghost finished the race */ void computeFinishTime(); + // ---------------------------------------------------------------------------- + /** Update sound effect upon ghost replay data */ + void updateSound(float dt); + public: GhostKart(const std::string& ident, unsigned int world_kart_id, int position, float color_hue, @@ -84,6 +88,9 @@ class GhostKart : public Kart /** Ghost can't be hunted. */ virtual bool isInvulnerable() const OVERRIDE { return true; } // ------------------------------------------------------------------------ + /** Ghost are not on the ground if flying. */ + virtual bool isOnGround() const OVERRIDE { return !m_flying; } + // ------------------------------------------------------------------------ /** Returns the speed of the kart in meters/second. */ virtual float getSpeed() const OVERRIDE; // ------------------------------------------------------------------------ diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 1efa7fe2e58..a113f3625a4 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -2679,7 +2679,15 @@ void Kart::updateEngineSFX(float dt) { // Only update SFX during the last substep (otherwise too many SFX commands // in one frame), and if sfx are enabled - if(!m_engine_sound || !SFXManager::get()->sfxAllowed() ) + if(!SFXManager::get()->sfxAllowed()) + return; + + if (m_skid_sound) + m_skid_sound->setPosition(getSmoothedXYZ()); + if (m_nitro_sound) + m_nitro_sound->setPosition(getSmoothedXYZ()); + + if (!m_engine_sound) return; // when going faster, use higher pitch for engine @@ -3265,9 +3273,6 @@ void Kart::updateGraphics(float dt) for (int i = 0; i < EMITTER_COUNT; i++) m_emitters[i]->setPosition(getXYZ()); - if (m_skid_sound) - m_skid_sound->setPosition(getSmoothedXYZ()); - m_nitro_sound->setPosition(getSmoothedXYZ()); m_attachment->updateGraphics(dt); From 414a8e955eddb1482ad03d51f6326b86daaadd47 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Wed, 12 Mar 2025 20:40:44 +0800 Subject: [PATCH 591/830] Make sure only game master controls kart filter (#5368) --- src/states_screens/kart_selection.cpp | 158 ++++++++++++++++---------- src/states_screens/kart_selection.hpp | 9 ++ 2 files changed, 110 insertions(+), 57 deletions(-) diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index ac48e611fe5..9851e5ab781 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -1144,8 +1144,6 @@ void KartSelectionScreen::eventCallback(Widget* widget, { RibbonWidget* tabs = getWidget("kartgroups"); assert(tabs != NULL); - DynamicRibbonWidget* w = getWidget("karts"); - assert(w != NULL); setKartsFromCurrentGroup(); @@ -1154,59 +1152,7 @@ void KartSelectionScreen::eventCallback(Widget* widget, UserConfigParams::m_last_used_kart_group = selected_kart_group; - RandomGenerator random; - - const int num_players = m_kart_widgets.size(); - for (int n=0; nsetSelection( selected_kart, n, - n != PLAYER_ID_GAME_MASTER)) - { - // if we get here, it means one player "lost" his kart in - // the tab switch - if (UserConfigParams::logGUI()) - Log::info("KartSelectionScreen", "Player %u" - " lost their selection when switching tabs!!!",n); - - // Select a random kart in this case - const int count = (int) w->getItems().size(); - if (count > 0) - { - // FIXME: two players may be given the same kart by - // the use of random - const int random_id = random.get( count ); - - // select kart for players > 0 (player 0 is the one - // that can change the groups, so focus for player 0 - // must remain on the tabs) - const bool success = - w->setSelection( random_id, n, - n != PLAYER_ID_GAME_MASTER ); - if (!success) - Log::warn("KartSelectionScreen", - "setting kart of player %u failed"); - } - else - { - Log::warn("KartSelectionScreen", " 0 items " - "in the ribbon"); - } - } - } - } // end for + handleKartListFocus(); } else if (name == "karts") { @@ -1215,7 +1161,7 @@ void KartSelectionScreen::eventCallback(Widget* widget, const std::string selection = w->getSelectionIDString(player_id); if (getWidget("favorite")->getState() && - player_id == PLAYER_ID_GAME_MASTER && + player_id == PLAYER_ID_GAME_MASTER && !m_game_master_confirmed && selection != RANDOM_KART_ID && !selection.empty()) { const KartProperties *kp = kart_properties_manager->getKart(selection); @@ -1229,13 +1175,17 @@ void KartSelectionScreen::eventCallback(Widget* widget, PlayerManager::getCurrentPlayer()->addFavoriteKart(kp->getIdent()); } setKartsFromCurrentGroup(); + + handleKartListFocus(); } else if (m_kart_widgets.size() > unsigned(player_id) && !useContinueButton()) playerConfirm(player_id); } - else if (name == "kart_class") + else if (name == "kart_class" && !m_game_master_confirmed) { setKartsFromCurrentGroup(); + + handleKartListFocus(); } else if (name == "continue") { @@ -1289,6 +1239,38 @@ bool KartSelectionScreen::onEscapePressed() // ---------------------------------------------------------------------------- +void KartSelectionScreen::onFocusChanged(GUIEngine::Widget* previous, + GUIEngine::Widget* focus, int playerID) +{ + if (playerID == PLAYER_ID_GAME_MASTER || !previous || !focus) + { + return; + } + GUIEngine::SpinnerWidget* kart_class = getWidget("kart_class"); + DynamicRibbonWidget* w = getWidget("karts"); + + if (GUIEngine::isFocusedForPlayer(kart_class, playerID)) + { + for (int i = 0; i < m_kart_widgets.size(); i++) + { + if (m_kart_widgets[i].getPlayerID() == playerID) + { + if (previous->getType() == WTYPE_RIBBON) + { + m_kart_widgets[i].getPlayerNameSpinner()->setFocusForPlayer(playerID); + } + else + { + w->setSelection(playerID, playerID, true); + } + break; + } + } + } +} + +// ---------------------------------------------------------------------------- + #if 0 #pragma mark - #pragma mark KartSelectionScreen (private) @@ -1429,6 +1411,68 @@ void KartSelectionScreen::allPlayersDone() // ---------------------------------------------------------------------------- +void KartSelectionScreen::handleKartListFocus() +{ + DynamicRibbonWidget* w = getWidget("karts"); + assert(w != NULL); + + RandomGenerator random; + + const int num_players = m_kart_widgets.size(); + for (int n=0; nsetSelection( selected_kart, n, + n != PLAYER_ID_GAME_MASTER)) + { + // if we get here, it means one player "lost" his kart in + // the tab switch + if (UserConfigParams::logGUI()) + Log::info("KartSelectionScreen", "Player %u" + " lost their selection when switching tabs!!!",n); + + // Select a random kart in this case + const int count = (int) w->getItems().size(); + if (count > 0) + { + // FIXME: two players may be given the same kart by + // the use of random + const int random_id = random.get( count ); + + // select kart for players > 0 (player 0 is the one + // that can change the groups, so focus for player 0 + // must remain on the tabs) + const bool success = + w->setSelection( random_id, n, + n != PLAYER_ID_GAME_MASTER ); + if (!success) + Log::warn("KartSelectionScreen", + "setting kart of player %u failed"); + } + else + { + Log::warn("KartSelectionScreen", " 0 items " + "in the ribbon"); + } + } + } + } // end for +} + +// ---------------------------------------------------------------------------- + bool KartSelectionScreen::validateIdentChoices() { bool ok = true; diff --git a/src/states_screens/kart_selection.hpp b/src/states_screens/kart_selection.hpp index f79198547c0..6b921b8a393 100644 --- a/src/states_screens/kart_selection.hpp +++ b/src/states_screens/kart_selection.hpp @@ -92,6 +92,10 @@ class KartSelectionScreen : public GUIEngine::Screen, /** Called when all players selected their kart */ virtual void allPlayersDone(); + /** When kart list has been changed, make sure all players have valid + * focus */ + void handleKartListFocus(); + /** Called when number/order of karts changed, so that all will keep * an up-to-date ID */ void renumberKarts(); @@ -182,8 +186,13 @@ class KartSelectionScreen : public GUIEngine::Screen, setKartsFromCurrentGroup(); // After setKartsFromCurrentGroup the m_search_box may be unfocused m_search_box->focused(PLAYER_ID_GAME_MASTER); + + handleKartListFocus(); } + virtual void onFocusChanged(GUIEngine::Widget* previous, + GUIEngine::Widget* focus, int playerID) OVERRIDE; + /** \brief implement optional callback from parent * class GUIEngine::Screen */ virtual void unloaded() OVERRIDE; From c7b34e9cfd552e60f75870b35becaa2493f61a2e Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Thu, 13 Mar 2025 16:35:14 +0800 Subject: [PATCH 592/830] Fix memory corruption when closing --- src/states_screens/race_gui_multitouch.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/states_screens/race_gui_multitouch.cpp b/src/states_screens/race_gui_multitouch.cpp index 0004b325266..2c412a16ba5 100644 --- a/src/states_screens/race_gui_multitouch.cpp +++ b/src/states_screens/race_gui_multitouch.cpp @@ -105,19 +105,19 @@ void RaceGUIMultitouch::recreate() */ void RaceGUIMultitouch::close() { - if (m_device != NULL) + if (m_device) { m_device->clearButtons(); - } - - if (m_device->isAccelerometerActive()) - { - m_device->deactivateAccelerometer(); - } - if (m_device->isGyroscopeActive()) - { - m_device->deactivateGyroscope(); + if (m_device->isAccelerometerActive()) + { + m_device->deactivateAccelerometer(); + } + + if (m_device->isGyroscopeActive()) + { + m_device->deactivateGyroscope(); + } } } // close From edfdb1fd993bae0ce396a77d37f3f783fa7fe65f Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Fri, 14 Mar 2025 21:37:01 +0800 Subject: [PATCH 593/830] Initial work on PBR vulkan --- data/shaders/ge_shaders/alphatest.frag | 37 ++++- data/shaders/ge_shaders/decal.frag | 2 +- data/shaders/ge_shaders/ghost.frag | 8 +- data/shaders/ge_shaders/grass.vert | 8 +- data/shaders/ge_shaders/normalmap.frag | 75 +++++++++ data/shaders/ge_shaders/solid.frag | 35 ++++- data/shaders/ge_shaders/spm.vert | 15 +- data/shaders/ge_shaders/spm_skinning.vert | 17 +- data/shaders/ge_shaders/transparent.frag | 11 +- data/shaders/ge_shaders/utils/camera.glsl | 10 ++ .../utils/get_pos_from_frag_coord.glsl | 8 + ...t_vertex_color.h => get_vertex_color.glsl} | 0 data/shaders/ge_shaders/utils/pbr_light.glsl | 148 ++++++++++++++++++ ...esh_texture.h => sample_mesh_texture.glsl} | 0 data/shaders/ge_shaders/utils/spm_data.glsl | 31 ++++ data/shaders/ge_shaders/utils/spm_layout.h | 57 ------- data/shaders/ge_shaders/utils/spm_layout.vert | 17 ++ .../ge_shaders/utils/sun_direction.glsl | 12 ++ .../src/ge_vulkan_camera_scene_node.cpp | 5 + .../src/ge_vulkan_camera_scene_node.hpp | 1 + .../src/ge_vulkan_draw_call.cpp | 10 +- src/graphics/irr_driver.cpp | 10 +- src/graphics/material.cpp | 5 + 23 files changed, 444 insertions(+), 78 deletions(-) create mode 100644 data/shaders/ge_shaders/normalmap.frag create mode 100644 data/shaders/ge_shaders/utils/camera.glsl create mode 100644 data/shaders/ge_shaders/utils/get_pos_from_frag_coord.glsl rename data/shaders/ge_shaders/utils/{get_vertex_color.h => get_vertex_color.glsl} (100%) create mode 100644 data/shaders/ge_shaders/utils/pbr_light.glsl rename data/shaders/ge_shaders/utils/{sample_mesh_texture.h => sample_mesh_texture.glsl} (100%) create mode 100644 data/shaders/ge_shaders/utils/spm_data.glsl delete mode 100644 data/shaders/ge_shaders/utils/spm_layout.h create mode 100644 data/shaders/ge_shaders/utils/spm_layout.vert create mode 100644 data/shaders/ge_shaders/utils/sun_direction.glsl diff --git a/data/shaders/ge_shaders/alphatest.frag b/data/shaders/ge_shaders/alphatest.frag index 77ec0b4cd80..90e5f1e040d 100644 --- a/data/shaders/ge_shaders/alphatest.frag +++ b/data/shaders/ge_shaders/alphatest.frag @@ -2,10 +2,17 @@ layout(location = 0) in vec4 f_vertex_color; layout(location = 1) in vec2 f_uv; layout(location = 3) flat in int f_material_id; layout(location = 4) in float f_hue_change; +#ifdef PBR_ENABLED +layout(location = 5) in vec3 f_normal; +#endif layout(location = 0) out vec4 o_color; -#include "utils/sample_mesh_texture.h" +#include "utils/camera.glsl" +#include "utils/get_pos_from_frag_coord.glsl" +#include "utils/pbr_light.glsl" +#include "utils/sample_mesh_texture.glsl" +#include "utils/sun_direction.glsl" #include "../utils/rgb_conversion.frag" void main() @@ -21,7 +28,31 @@ void main() vec3 new_color = hsvToRgb(vec3(new_xy.x, new_xy.y, old_hsv.z)); tex_color = vec4(new_color.r, new_color.g, new_color.b, tex_color.a); } +#ifndef PBR_ENABLED + vec3 mixed_color = tex_color.xyz * f_vertex_color.xyz; + o_color = vec4(mixed_color, 1.0); +#else + vec3 diffuse_color = tex_color.xyz * f_vertex_color.xyz; + vec3 normal = normalize(f_normal.xyz); - tex_color.xyz *= f_vertex_color.xyz; - o_color = vec4(tex_color.xyz, 1.0); + vec4 pbr = sampleMeshTexture2(f_material_id, f_uv); + vec3 xpos = getPosFromFragCoord(gl_FragCoord, u_camera.m_viewport, u_camera.m_inverse_projection_matrix); + vec3 eyedir = -normalize(xpos); + + vec3 sun = sunDirection(normal, eyedir, vec3(-642.22, 673.75, -219.26)); + vec3 lightdir = normalize(sun.xyz); + + vec3 mixed_color = PBRSunAmbientEmitLight( + normal, eyedir, lightdir, diffuse_color, + vec3(211./256., 235./256., 110./256.), + vec3(120./256., 120./256., 120./256.), + 1.0 - pbr.x, pbr.y, pbr.z); + + float factor = (1.0 - exp(length(xpos) * -0.0001)); + mixed_color = mixed_color + vec3(0.5) * factor; + + mixed_color = (mixed_color * (6.9 * mixed_color + 0.5)) / (mixed_color * (5.2 * mixed_color + 1.7) + 0.06); + + o_color = vec4(mixed_color, 1.0); +#endif } diff --git a/data/shaders/ge_shaders/decal.frag b/data/shaders/ge_shaders/decal.frag index 584785bb82f..2d8486b1852 100644 --- a/data/shaders/ge_shaders/decal.frag +++ b/data/shaders/ge_shaders/decal.frag @@ -4,7 +4,7 @@ layout(location = 3) flat in int f_material_id; layout(location = 0) out vec4 o_color; -#include "utils/sample_mesh_texture.h" +#include "utils/sample_mesh_texture.glsl" void main() { diff --git a/data/shaders/ge_shaders/ghost.frag b/data/shaders/ge_shaders/ghost.frag index 7f2c64b42dc..02ace7268c8 100644 --- a/data/shaders/ge_shaders/ghost.frag +++ b/data/shaders/ge_shaders/ghost.frag @@ -5,7 +5,7 @@ layout(location = 4) in float f_hue_change; layout(location = 0) out vec4 o_color; -#include "utils/sample_mesh_texture.h" +#include "utils/sample_mesh_texture.glsl" #include "../utils/rgb_conversion.frag" void main() @@ -30,5 +30,9 @@ void main() } vec3 mixed_color = tex_color.xyz * f_vertex_color.xyz; - o_color = vec4(mixed_color * 0.5, 0.5); + mixed_color *= 0.5; +#ifdef PBR_ENABLED + mixed_color = (mixed_color * (6.9 * mixed_color + 0.5)) / (mixed_color * (5.2 * mixed_color + 1.7) + 0.06); +#endif + o_color = vec4(mixed_color, 0.5); } diff --git a/data/shaders/ge_shaders/grass.vert b/data/shaders/ge_shaders/grass.vert index f507fe92e74..3337b7a43f2 100644 --- a/data/shaders/ge_shaders/grass.vert +++ b/data/shaders/ge_shaders/grass.vert @@ -1,4 +1,6 @@ -#include "utils/spm_layout.h" +#include "utils/camera.glsl" +#include "utils/spm_data.glsl" +#include "utils/spm_layout.vert" #include "../utils/get_world_location.vert" layout(push_constant) uniform Constants @@ -26,4 +28,8 @@ void main() f_material_id = u_material_ids.m_material_id[gl_DrawIDARB]; #endif f_hue_change = u_object_buffer.m_objects[gl_InstanceIndex].m_hue_change; +#ifdef PBR_ENABLED + vec3 world_normal = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, v_normal.xyz); + f_normal = (u_camera.m_view_matrix * vec4(world_normal, 0.0)).xyz; +#endif } diff --git a/data/shaders/ge_shaders/normalmap.frag b/data/shaders/ge_shaders/normalmap.frag new file mode 100644 index 00000000000..9518197996d --- /dev/null +++ b/data/shaders/ge_shaders/normalmap.frag @@ -0,0 +1,75 @@ +layout(location = 0) in vec4 f_vertex_color; +layout(location = 1) in vec2 f_uv; +layout(location = 3) flat in int f_material_id; +layout(location = 4) in float f_hue_change; +#ifdef PBR_ENABLED +layout(location = 5) in vec3 f_normal; +layout(location = 6) in vec3 f_tangent; +layout(location = 7) in vec3 f_bitangent; +#endif + +layout(location = 0) out vec4 o_color; + +#include "utils/camera.glsl" +#include "utils/get_pos_from_frag_coord.glsl" +#include "utils/pbr_light.glsl" +#include "utils/sample_mesh_texture.glsl" +#include "utils/sun_direction.glsl" +#include "../utils/rgb_conversion.frag" + +void main() +{ + vec4 tex_color = sampleMeshTexture0(f_material_id, f_uv); + + if (f_hue_change > 0.0) + { + float mask = tex_color.a; + vec3 old_hsv = rgbToHsv(tex_color.rgb); + float mask_step = step(mask, 0.5); +#ifndef PBR_ENABLED + // For similar color + float saturation = mask * 1.825; // 2.5 * 0.5 ^ (1. / 2.2) +#else + float saturation = mask * 2.5; +#endif + vec2 new_xy = mix(vec2(old_hsv.x, old_hsv.y), vec2(f_hue_change, + max(old_hsv.y, saturation)), vec2(mask_step, mask_step)); + vec3 new_color = hsvToRgb(vec3(new_xy.x, new_xy.y, old_hsv.z)); + tex_color = vec4(new_color.r, new_color.g, new_color.b, 1.0); + } +#ifndef PBR_ENABLED + vec3 mixed_color = tex_color.xyz * f_vertex_color.xyz; + o_color = vec4(mixed_color, 1.0); +#else + vec3 diffuse_color = tex_color.xyz * f_vertex_color.xyz; + + vec4 layer_3 = sampleMeshTexture3(f_material_id, f_uv); + vec3 tangent_space_normal = 2.0 * layer_3.xyz - 1.0; + vec3 frag_tangent = normalize(f_tangent); + vec3 frag_bitangent = normalize(f_bitangent); + vec3 frag_normal = normalize(f_normal); + mat3 t_b_n = mat3(frag_tangent, frag_bitangent, frag_normal); + + vec3 normal = normalize(t_b_n * tangent_space_normal); + + vec4 pbr = sampleMeshTexture2(f_material_id, f_uv); + vec3 xpos = getPosFromFragCoord(gl_FragCoord, u_camera.m_viewport, u_camera.m_inverse_projection_matrix); + vec3 eyedir = -normalize(xpos); + + vec3 sun = sunDirection(normal, eyedir, vec3(-642.22, 673.75, -219.26)); + vec3 lightdir = normalize(sun.xyz); + + vec3 mixed_color = PBRSunAmbientEmitLight( + normal, eyedir, lightdir, diffuse_color, + vec3(211./256., 235./256., 110./256.), + vec3(120./256., 120./256., 120./256.), + 1.0 - pbr.x, pbr.y, pbr.z); + + float factor = (1.0 - exp(length(xpos) * -0.0001)); + mixed_color = mixed_color + vec3(0.5) * factor; + + mixed_color = (mixed_color * (6.9 * mixed_color + 0.5)) / (mixed_color * (5.2 * mixed_color + 1.7) + 0.06); + + o_color = vec4(mixed_color, 1.0); +#endif +} diff --git a/data/shaders/ge_shaders/solid.frag b/data/shaders/ge_shaders/solid.frag index 818f5ee109a..b4e25068ad4 100644 --- a/data/shaders/ge_shaders/solid.frag +++ b/data/shaders/ge_shaders/solid.frag @@ -2,10 +2,17 @@ layout(location = 0) in vec4 f_vertex_color; layout(location = 1) in vec2 f_uv; layout(location = 3) flat in int f_material_id; layout(location = 4) in float f_hue_change; +#ifdef PBR_ENABLED +layout(location = 5) in vec3 f_normal; +#endif layout(location = 0) out vec4 o_color; -#include "utils/sample_mesh_texture.h" +#include "utils/camera.glsl" +#include "utils/get_pos_from_frag_coord.glsl" +#include "utils/pbr_light.glsl" +#include "utils/sample_mesh_texture.glsl" +#include "utils/sun_direction.glsl" #include "../utils/rgb_conversion.frag" void main() @@ -28,7 +35,31 @@ void main() vec3 new_color = hsvToRgb(vec3(new_xy.x, new_xy.y, old_hsv.z)); tex_color = vec4(new_color.r, new_color.g, new_color.b, 1.0); } - +#ifndef PBR_ENABLED vec3 mixed_color = tex_color.xyz * f_vertex_color.xyz; o_color = vec4(mixed_color, 1.0); +#else + vec3 diffuse_color = tex_color.xyz * f_vertex_color.xyz; + vec3 normal = normalize(f_normal.xyz); + + vec4 pbr = sampleMeshTexture2(f_material_id, f_uv); + vec3 xpos = getPosFromFragCoord(gl_FragCoord, u_camera.m_viewport, u_camera.m_inverse_projection_matrix); + vec3 eyedir = -normalize(xpos); + + vec3 sun = sunDirection(normal, eyedir, vec3(-642.22, 673.75, -219.26)); + vec3 lightdir = normalize(sun.xyz); + + vec3 mixed_color = PBRSunAmbientEmitLight( + normal, eyedir, lightdir, diffuse_color, + vec3(211./256., 235./256., 110./256.), + vec3(120./256., 120./256., 120./256.), + 1.0 - pbr.x, pbr.y, pbr.z); + + float factor = (1.0 - exp(length(xpos) * -0.0001)); + mixed_color = mixed_color + vec3(0.5) * factor; + + mixed_color = (mixed_color * (6.9 * mixed_color + 0.5)) / (mixed_color * (5.2 * mixed_color + 1.7) + 0.06); + + o_color = vec4(mixed_color, 1.0); +#endif } diff --git a/data/shaders/ge_shaders/spm.vert b/data/shaders/ge_shaders/spm.vert index 12e54d713ad..db092185cb7 100644 --- a/data/shaders/ge_shaders/spm.vert +++ b/data/shaders/ge_shaders/spm.vert @@ -1,5 +1,7 @@ -#include "utils/spm_layout.h" -#include "utils/get_vertex_color.h" +#include "utils/camera.glsl" +#include "utils/get_vertex_color.glsl" +#include "utils/spm_data.glsl" +#include "utils/spm_layout.vert" #include "../utils/get_world_location.vert" void main() @@ -19,4 +21,13 @@ void main() f_material_id = u_material_ids.m_material_id[gl_DrawIDARB]; #endif f_hue_change = u_object_buffer.m_objects[gl_InstanceIndex].m_hue_change; +#ifdef PBR_ENABLED + vec3 world_normal = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, v_normal.xyz); + vec3 world_tangent = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, v_tangent.xyz); + + f_tangent = (u_camera.m_view_matrix * vec4(world_tangent, 0.0)).xyz; + f_bitangent = normalize((u_camera.m_view_matrix * + vec4(cross(world_normal, world_tangent) * v_tangent.w, 0.0)).xyz); + f_normal = (u_camera.m_view_matrix * vec4(world_normal, 0.0)).xyz; +#endif } diff --git a/data/shaders/ge_shaders/spm_skinning.vert b/data/shaders/ge_shaders/spm_skinning.vert index 0763aed92a9..7be9bb4f1ff 100644 --- a/data/shaders/ge_shaders/spm_skinning.vert +++ b/data/shaders/ge_shaders/spm_skinning.vert @@ -1,5 +1,7 @@ -#include "utils/spm_layout.h" -#include "utils/get_vertex_color.h" +#include "utils/camera.glsl" +#include "utils/get_vertex_color.glsl" +#include "utils/spm_data.glsl" +#include "utils/spm_layout.vert" #include "../utils/get_world_location.vert" void main() @@ -27,4 +29,15 @@ void main() f_material_id = u_material_ids.m_material_id[gl_DrawIDARB]; #endif f_hue_change = u_object_buffer.m_objects[gl_InstanceIndex].m_hue_change; +#ifdef PBR_ENABLED + vec4 skinned_normal = joint_matrix * v_normal; + vec4 skinned_tangent = joint_matrix * v_tangent; + vec3 world_normal = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, skinned_normal.xyz); + vec3 world_tangent = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, skinned_tangent.xyz); + + f_tangent = (u_camera.m_view_matrix * vec4(world_tangent, 0.0)).xyz; + f_bitangent = (u_camera.m_view_matrix * + vec4(cross(world_normal, world_tangent) * v_tangent.w, 0.0)).xyz; + f_normal = (u_camera.m_view_matrix * vec4(world_normal, 0.0)).xyz; +#endif } diff --git a/data/shaders/ge_shaders/transparent.frag b/data/shaders/ge_shaders/transparent.frag index 2a2dcf4d73f..cc1f4a69c6b 100644 --- a/data/shaders/ge_shaders/transparent.frag +++ b/data/shaders/ge_shaders/transparent.frag @@ -4,10 +4,15 @@ layout(location = 3) flat in int f_material_id; layout(location = 0) out vec4 o_color; -#include "utils/sample_mesh_texture.h" +#include "utils/sample_mesh_texture.glsl" void main() { - vec4 mixed_color = sampleMeshTexture0(f_material_id, f_uv) * f_vertex_color; - o_color = vec4(mixed_color.rgb * mixed_color.a, mixed_color.a); + vec4 color = sampleMeshTexture0(f_material_id, f_uv) * f_vertex_color; + vec3 mixed_color = color.xyz; + float alpha = color.w; +#ifdef PBR_ENABLED + mixed_color = (mixed_color * (6.9 * mixed_color + 0.5)) / (mixed_color * (5.2 * mixed_color + 1.7) + 0.06); +#endif + o_color = vec4(mixed_color * alpha, alpha); } diff --git a/data/shaders/ge_shaders/utils/camera.glsl b/data/shaders/ge_shaders/utils/camera.glsl new file mode 100644 index 00000000000..de323408090 --- /dev/null +++ b/data/shaders/ge_shaders/utils/camera.glsl @@ -0,0 +1,10 @@ +layout(std140, set = 1, binding = 0) uniform CameraBuffer +{ + mat4 m_view_matrix; + mat4 m_projection_matrix; + mat4 m_inverse_view_matrix; + mat4 m_inverse_projection_matrix; + mat4 m_projection_view_matrix; + mat4 m_inverse_projection_view_matrix; + vec4 m_viewport; +} u_camera; diff --git a/data/shaders/ge_shaders/utils/get_pos_from_frag_coord.glsl b/data/shaders/ge_shaders/utils/get_pos_from_frag_coord.glsl new file mode 100644 index 00000000000..3153f6cadce --- /dev/null +++ b/data/shaders/ge_shaders/utils/get_pos_from_frag_coord.glsl @@ -0,0 +1,8 @@ +vec3 getPosFromFragCoord(vec4 frag_coord, vec4 viewport, mat4 inverse_projection_matrix) +{ + return vec3( + ((frag_coord.x - viewport.x) / viewport.z * 2.0 - 1.0) * inverse_projection_matrix[0][0], + ((frag_coord.y - viewport.y) / viewport.w * 2.0 - 1.0) * inverse_projection_matrix[1][1], + inverse_projection_matrix[3][2] + ) / frag_coord.w; +} diff --git a/data/shaders/ge_shaders/utils/get_vertex_color.h b/data/shaders/ge_shaders/utils/get_vertex_color.glsl similarity index 100% rename from data/shaders/ge_shaders/utils/get_vertex_color.h rename to data/shaders/ge_shaders/utils/get_vertex_color.glsl diff --git a/data/shaders/ge_shaders/utils/pbr_light.glsl b/data/shaders/ge_shaders/utils/pbr_light.glsl new file mode 100644 index 00000000000..a12eb1b1e33 --- /dev/null +++ b/data/shaders/ge_shaders/utils/pbr_light.glsl @@ -0,0 +1,148 @@ +vec2 F_AB(float perceptual_roughness, float NdotV) +{ + vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); + vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); + vec4 r = perceptual_roughness * c0 + c1; + float a004 = min(r.x * r.x, pow(2.0, -9.28 * NdotV)) * r.x + r.y; + return vec2(-1.04, 1.04) * a004 + r.zw; +} + +// Lambert model +float F_Schlick(float f0, float f90, float VdotH) +{ + return mix(f0, f90, pow(1.0 - VdotH, 5.0)); +} + +float Fd_Burley(float roughness, float NdotV, float NdotL, float LdotH) +{ + // Don't divide by Pi to avoid light being too dim. + float f90 = 0.5 + 2.0 * roughness * LdotH * LdotH; + float lightScatter = F_Schlick(1.0, f90, NdotL); + float viewScatter = F_Schlick(1.0, f90, NdotV); + return lightScatter * viewScatter; +} + +// Calculate distribution. +// Based on https://google.github.io/filament/Filament.html#citation-walter07 +// D_GGX(h,α) = α^2 / { π ((n⋅h)^2 (α2−1) + 1)^2 } +// Simple implementation, has precision problems when using fp16 instead of fp32 +// see https://google.github.io/filament/Filament.html#listing_speculardfp16 +float D_GGX(float roughness, float NdotH) +{ + // Don't divide by Pi to avoid light being too dim. + float oneMinusNdotHSquared = 1.0 - NdotH * NdotH; + float a = NdotH * roughness; + float k = roughness / (oneMinusNdotHSquared + a * a); + return k * k; +} + +// Calculate visibility. +// Hammon 2017, "PBR Diffuse Lighting for GGX+Smith Microsurfaces" +// see https://google.github.io/filament/Filament.html#listing_approximatedspecularv +float V_Smith_GGX_Correlated(float roughness, float NdotV, float NdotL) +{ + return 0.5 / mix(2.0 * NdotL * NdotV, NdotL + NdotV, roughness); +} + +// Fresnel function +// see https://google.github.io/filament/Filament.html#citation-schlick94 +// F_Schlick(v,h,f_0,f_90) = f_0 + (f_90 − f_0) (1 − v⋅h)^5 +vec3 fresnel(vec3 f0, float f90, float VdotH) +{ + return f0 + (f90 - f0) * pow(1.0 - VdotH, 5.0); +} + +vec3 envBRDFApprox(vec3 F0, vec2 F_ab) +{ + return F0 * F_ab.x + F_ab.y; +} + +float perceptualRoughnessToRoughness(float perceptual_roughness) +{ + float roughness = clamp(perceptual_roughness, 0.089, 1.0); + return roughness * roughness; +} + +vec3 PBRLight( + vec3 normal, + vec3 eyedir, + vec3 lightdir, + vec3 color, + float perceptual_roughness, + float metallic) +{ + float NdotV = max(dot(normal, eyedir), 0.0001); + float NdotL = clamp(dot(normal, lightdir), 0.0, 1.0); + + vec2 F_ab = F_AB(perceptual_roughness, NdotV); + + vec3 H = normalize(eyedir + lightdir); + float NdotH = clamp(dot(normal, H), 0.0, 1.0); + float LdotH = clamp(dot(lightdir, H), 0.0, 1.0); + + vec3 diffuse_color = color * (1.0 - metallic); + vec3 F0 = mix(vec3(0.04), color, metallic); + // No real world material has specular values under 0.02, so we use this range as a + // "pre-baked specular occlusion" that extinguishes the fresnel term, for artistic control. + // See: https://google.github.io/filament/Filament.html#specularocclusion + float F90 = clamp(dot(F0, vec3(50.0 * 0.33)), 0.0, 1.0); + + float roughness = perceptualRoughnessToRoughness(perceptual_roughness); + + vec3 diffuse = diffuse_color * Fd_Burley(roughness, NdotV, NdotL, NdotH); + + float D = D_GGX(roughness, NdotH); + float V = V_Smith_GGX_Correlated(roughness, NdotV, NdotL); + vec3 F = fresnel(F0, F90, LdotH); + vec3 specular = D * V * F * (1.0 + F0 * (1.0 / F_ab.x - 1.0)); + + return NdotL * (diffuse + specular); +} + +vec3 PBRSunAmbientEmitLight( + vec3 normal, + vec3 eyedir, + vec3 sundir, + vec3 color, + vec3 sun_color, + vec3 ambient_color, + float perceptual_roughness, + float metallic, + float emissive) +{ + // Copied from PBRLight to use F_ab and F90 again + float NdotV = max(dot(normal, eyedir), 0.0001); + float NdotL = clamp(dot(normal, sundir), 0.0, 1.0); + + vec2 F_ab = F_AB(perceptual_roughness, NdotV); + + vec3 H = normalize(eyedir + sundir); + float NdotH = clamp(dot(normal, H), 0.0, 1.0); + float LdotH = clamp(dot(sundir, H), 0.0, 1.0); + + vec3 diffuse_color = color * (1.0 - metallic); + vec3 F0 = mix(vec3(0.04), color, metallic); + // No real world material has specular values under 0.02, so we use this range as a + // "pre-baked specular occlusion" that extinguishes the fresnel term, for artistic control. + // See: https://google.github.io/filament/Filament.html#specularocclusion + float F90 = clamp(dot(F0, vec3(50.0 * 0.33)), 0.0, 1.0); + + float roughness = perceptualRoughnessToRoughness(perceptual_roughness); + + vec3 diffuse = diffuse_color * Fd_Burley(roughness, NdotV, NdotL, NdotH); + + float D = D_GGX(roughness, NdotH); + float V = V_Smith_GGX_Correlated(roughness, NdotV, NdotL); + vec3 F = fresnel(F0, F90, LdotH); + vec3 specular = D * V * F * (1.0 + F0 * (1.0 / F_ab.x - 1.0)); + + vec3 sunlight = NdotL * (diffuse + specular); + + vec3 diffuse_ambient = envBRDFApprox(diffuse_color, F_AB(1.0, NdotV)); + + vec3 specular_ambient = F90 * envBRDFApprox(F0, F_ab); + + vec3 emit = emissive * color * 4.0; + + return sun_color * sunlight + ambient_color * (diffuse_ambient + specular_ambient) + emit; +} diff --git a/data/shaders/ge_shaders/utils/sample_mesh_texture.h b/data/shaders/ge_shaders/utils/sample_mesh_texture.glsl similarity index 100% rename from data/shaders/ge_shaders/utils/sample_mesh_texture.h rename to data/shaders/ge_shaders/utils/sample_mesh_texture.glsl diff --git a/data/shaders/ge_shaders/utils/spm_data.glsl b/data/shaders/ge_shaders/utils/spm_data.glsl new file mode 100644 index 00000000000..2952206919c --- /dev/null +++ b/data/shaders/ge_shaders/utils/spm_data.glsl @@ -0,0 +1,31 @@ +#ifdef BIND_MESH_TEXTURES_AT_ONCE +#extension GL_ARB_shader_draw_parameters : enable +#endif +struct ObjectData +{ + vec3 m_translation; + float m_hue_change; + vec4 m_rotation; + vec3 m_scale; + uint m_custom_vertex_color; + int m_skinning_offset; + int m_material_id; + vec2 m_texture_trans; +}; + +layout(std140, set = 1, binding = 1) readonly buffer ObjectBuffer +{ + ObjectData m_objects[]; +} u_object_buffer; + +layout(std140, set = 1, binding = 2) readonly buffer SkinningMatrices +{ + mat4 m_mat[]; +} u_skinning_matrices; + +#ifdef BIND_MESH_TEXTURES_AT_ONCE +layout(std430, set = 1, binding = 3) readonly buffer MaterialIDs +{ + int m_material_id[]; +} u_material_ids; +#endif diff --git a/data/shaders/ge_shaders/utils/spm_layout.h b/data/shaders/ge_shaders/utils/spm_layout.h deleted file mode 100644 index 459b2011167..00000000000 --- a/data/shaders/ge_shaders/utils/spm_layout.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifdef BIND_MESH_TEXTURES_AT_ONCE -#extension GL_ARB_shader_draw_parameters : enable -#endif - -layout(std140, set = 1, binding = 0) uniform CameraBuffer -{ - mat4 m_view_matrix; - mat4 m_projection_matrix; - mat4 m_inverse_view_matrix; - mat4 m_inverse_projection_matrix; - mat4 m_projection_view_matrix; - mat4 m_inverse_projection_view_matrix; -} u_camera; - -struct ObjectData -{ - vec3 m_translation; - float m_hue_change; - vec4 m_rotation; - vec3 m_scale; - uint m_custom_vertex_color; - int m_skinning_offset; - int m_material_id; - vec2 m_texture_trans; -}; - -layout(std140, set = 1, binding = 1) readonly buffer ObjectBuffer -{ - ObjectData m_objects[]; -} u_object_buffer; - -layout(std140, set = 1, binding = 2) readonly buffer SkinningMatrices -{ - mat4 m_mat[]; -} u_skinning_matrices; - -#ifdef BIND_MESH_TEXTURES_AT_ONCE -layout(std430, set = 1, binding = 3) readonly buffer MaterialIDs -{ - int m_material_id[]; -} u_material_ids; -#endif - -layout(location = 0) in vec3 v_position; -layout(location = 1) in vec4 v_normal; -layout(location = 2) in vec4 v_color; -layout(location = 3) in vec2 v_uv; -layout(location = 4) in vec2 v_uv_two; -layout(location = 5) in vec4 v_tangent; -layout(location = 6) in ivec4 v_joint; -layout(location = 7) in vec4 v_weight; - -layout(location = 0) out vec4 f_vertex_color; -layout(location = 1) out vec2 f_uv; -layout(location = 2) out vec2 f_uv_two; -layout(location = 3) flat out int f_material_id; -layout(location = 4) out float f_hue_change; diff --git a/data/shaders/ge_shaders/utils/spm_layout.vert b/data/shaders/ge_shaders/utils/spm_layout.vert new file mode 100644 index 00000000000..1b1589cd890 --- /dev/null +++ b/data/shaders/ge_shaders/utils/spm_layout.vert @@ -0,0 +1,17 @@ +layout(location = 0) in vec3 v_position; +layout(location = 1) in vec4 v_normal; +layout(location = 2) in vec4 v_color; +layout(location = 3) in vec2 v_uv; +layout(location = 4) in vec2 v_uv_two; +layout(location = 5) in vec4 v_tangent; +layout(location = 6) in ivec4 v_joint; +layout(location = 7) in vec4 v_weight; + +layout(location = 0) out vec4 f_vertex_color; +layout(location = 1) out vec2 f_uv; +layout(location = 2) out vec2 f_uv_two; +layout(location = 3) flat out int f_material_id; +layout(location = 4) out float f_hue_change; +layout(location = 5) out vec3 f_normal; +layout(location = 6) out vec3 f_tangent; +layout(location = 7) out vec3 f_bitangent; diff --git a/data/shaders/ge_shaders/utils/sun_direction.glsl b/data/shaders/ge_shaders/utils/sun_direction.glsl new file mode 100644 index 00000000000..f52901c7ebb --- /dev/null +++ b/data/shaders/ge_shaders/utils/sun_direction.glsl @@ -0,0 +1,12 @@ +vec3 sunDirection(vec3 normal, vec3 eyedir, vec3 sundirection) +{ + vec3 local_sundir = normalize((transpose(u_camera.m_inverse_view_matrix) * vec4(sundirection, 0.)).xyz); + vec3 R = reflect(-eyedir, normal); + float angularRadius = 3.14 * 5. / 180.; + vec3 D = local_sundir; + float d = cos(angularRadius); + float r = sin(angularRadius); + float DdotR = dot(D, R); + vec3 S = R - DdotR * D; + return (DdotR < d) ? normalize(d * D + normalize (S) * r) : R; +} diff --git a/lib/graphics_engine/src/ge_vulkan_camera_scene_node.cpp b/lib/graphics_engine/src/ge_vulkan_camera_scene_node.cpp index a5b17a96921..3f38f3ebc52 100644 --- a/lib/graphics_engine/src/ge_vulkan_camera_scene_node.cpp +++ b/lib/graphics_engine/src/ge_vulkan_camera_scene_node.cpp @@ -57,6 +57,11 @@ void GEVulkanCameraSceneNode::render() m_ubo_data.m_projection_view_matrix.getInverse( m_ubo_data.m_inverse_projection_view_matrix); + + m_ubo_data.m_viewport.UpperLeftCorner.X = m_viewport.UpperLeftCorner.X; + m_ubo_data.m_viewport.UpperLeftCorner.Y = m_viewport.UpperLeftCorner.Y; + m_ubo_data.m_viewport.LowerRightCorner.X = m_viewport.getWidth(); + m_ubo_data.m_viewport.LowerRightCorner.Y = m_viewport.getHeight(); } // render // ---------------------------------------------------------------------------- diff --git a/lib/graphics_engine/src/ge_vulkan_camera_scene_node.hpp b/lib/graphics_engine/src/ge_vulkan_camera_scene_node.hpp index 5a290812ea0..cd10215b195 100644 --- a/lib/graphics_engine/src/ge_vulkan_camera_scene_node.hpp +++ b/lib/graphics_engine/src/ge_vulkan_camera_scene_node.hpp @@ -15,6 +15,7 @@ irr::core::matrix4 m_inverse_view_matrix; irr::core::matrix4 m_inverse_projection_matrix; irr::core::matrix4 m_projection_view_matrix; irr::core::matrix4 m_inverse_projection_view_matrix; +irr::core::rectf m_viewport; }; class GEVulkanCameraSceneNode : public irr::scene::CCameraSceneNode diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index 3eb37616772..c78d02d15cd 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -795,6 +795,9 @@ std::string GEVulkanDrawCall::getShader(const irr::video::SMaterial& m) case irr::video::EMT_SOLID_2_LAYER: shader = "decal"; break; + case irr::video::EMT_NORMAL_MAP_SOLID: + shader = getGEConfig()->m_pbr ? "normalmap" : "solid"; + break; case irr::video::EMT_STK_GRASS: shader = "grass"; break; @@ -834,6 +837,10 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) settings.m_shader_name = "solid"; createPipeline(vk, settings); + settings.m_fragment_shader = "normalmap.frag"; + settings.m_shader_name = "normalmap"; + createPipeline(vk, settings); + settings.m_fragment_shader = "decal.frag"; settings.m_shader_name = "decal"; createPipeline(vk, settings); @@ -1109,7 +1116,8 @@ void GEVulkanDrawCall::createVulkanData() camera_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; camera_layout_binding.pImmutableSamplers = NULL; - camera_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + camera_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT + | VK_SHADER_STAGE_FRAGMENT_BIT; VkDescriptorSetLayoutBinding object_data_layout_binding = {}; object_data_layout_binding.binding = 1; diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 5b598c4f674..214a3cb755d 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -1848,10 +1848,12 @@ void IrrDriver::setAmbientLight(const video::SColorf &light, bool force_SH_compu { #ifndef SERVER_ONLY video::SColorf color = light; - color.r = powf(color.r, 1.0f / 2.2f); - color.g = powf(color.g, 1.0f / 2.2f); - color.b = powf(color.b, 1.0f / 2.2f); - + if (CVS->isGLSL()) + { + color.r = powf(color.r, 1.0f / 2.2f); + color.g = powf(color.g, 1.0f / 2.2f); + color.b = powf(color.b, 1.0f / 2.2f); + } m_scene_manager->setAmbientLight(color); m_renderer->setAmbientLight(light, force_SH_computation); #endif diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index c50b08dff12..22274ead41f 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -941,6 +941,11 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m if (is_vk) m->MaterialType = video::EMT_SOLID_2_LAYER; } + else if (m_shader_name == "normalmap") + { + if (is_vk) + m->MaterialType = video::EMT_NORMAL_MAP_SOLID; + } if (isTransparent()) { From 9c7e342fb699f4d8c36dc3e43b122e7cbcb4b4d8 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 16 Mar 2025 12:51:06 +0800 Subject: [PATCH 594/830] Fix missing PBR textures when material is shared in vulkan engine --- src/graphics/material.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index 22274ead41f..e1ec4c5ee8a 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -589,10 +589,7 @@ void Material::install(std::function image_mani, m_sampler_path[i]); GE::getGEConfig()->m_ondemand_load_texture_paths.clear(); if (m_vk_textures[i - 2]) - { m_vk_textures[i - 2]->grab(); - m->setTexture(i, m_vk_textures[i - 2]); - } } #endif } // install @@ -1006,6 +1003,14 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m m->ColorMaterial = video::ECM_NONE; // Override one above } #endif + if (is_vk) + { + for (unsigned i = 2; i < m_sampler_path.size(); i++) + { + if (m_vk_textures[i - 2]) + m->setTexture(i, m_vk_textures[i - 2]); + } + } } // setMaterialProperties From f7b1c56b044cc7caa3c7af540364b2809d72b1a1 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 10 Mar 2025 00:14:18 +0400 Subject: [PATCH 595/830] Move everything to LobbyContext, use less ServerConfig Seems to work --- src/items/bowling.cpp | 20 +- src/items/cake.cpp | 18 +- src/items/powerup.cpp | 8 +- src/items/swatter.cpp | 9 +- src/karts/abstract_kart.cpp | 7 + src/karts/abstract_kart.hpp | 3 + src/karts/explosion_animation.cpp | 11 +- src/network/game_setup.cpp | 3 +- src/network/game_setup.hpp | 3 +- src/network/protocols/command_manager.cpp | 626 +++++++++++----------- src/network/protocols/command_manager.hpp | 27 +- src/network/protocols/server_lobby.cpp | 475 ++++++++-------- src/network/protocols/server_lobby.hpp | 25 +- src/race/race_manager.hpp | 10 + src/utils/hit_processor.cpp | 21 +- src/utils/hit_processor.hpp | 9 +- src/utils/kart_elimination.cpp | 4 +- src/utils/kart_elimination.hpp | 9 +- src/utils/lobby_asset_manager.cpp | 15 +- src/utils/lobby_asset_manager.hpp | 10 +- src/utils/lobby_context.cpp | 61 +++ src/utils/lobby_context.hpp | 97 ++++ src/utils/lobby_queues.cpp | 5 +- src/utils/lobby_queues.hpp | 7 +- src/utils/lobby_settings.cpp | 103 +++- src/utils/lobby_settings.hpp | 132 ++++- src/utils/map_vote_handler.cpp | 23 +- src/utils/map_vote_handler.hpp | 9 +- src/utils/tournament.cpp | 20 +- src/utils/tournament.hpp | 10 +- 30 files changed, 1038 insertions(+), 742 deletions(-) create mode 100644 src/utils/lobby_context.cpp create mode 100644 src/utils/lobby_context.hpp diff --git a/src/items/bowling.cpp b/src/items/bowling.cpp index 6c44d003bbe..34c3fc4303e 100644 --- a/src/items/bowling.cpp +++ b/src/items/bowling.cpp @@ -24,10 +24,10 @@ #include "graphics/material.hpp" #include "io/xml_node.hpp" #include "karts/abstract_kart.hpp" +#include "guiengine/engine.hpp" +#include "config/stk_config.hpp" // #include "modes/linear_world.hpp" -#include "network/protocols/server_lobby.hpp" - #include "utils/hit_processor.hpp" #include "utils/log.hpp" //TODO: remove after debugging is done @@ -157,9 +157,9 @@ bool Bowling::updateAndDelete(int ticks) */ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) { - auto sl = LobbyProtocol::get(); - if (sl) - sl->getHitProcessor()->setTeammateHitOwner(getOwnerId(),m_ticks_since_thrown); + auto hp = kart->getHitProcessor(); + if (hp) + hp->setTeammateHitOwner(getOwnerId(),m_ticks_since_thrown); bool was_real_hit = Flyable::hit(kart, obj); if (was_real_hit) @@ -167,10 +167,10 @@ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) if (kart && kart->isShielded()) { kart->decreaseShieldTime(); - if (sl) + if (hp) { - sl->getHitProcessor()->registerTeammateHit(kart->getWorldKartId()); - sl->getHitProcessor()->handleTeammateHits(); + hp->registerTeammateHit(kart->getWorldKartId()); + hp->handleTeammateHits(); } return true; } @@ -180,8 +180,8 @@ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) explode(kart, obj, /*hit_secondary*/false); } } - if (sl) - sl->getHitProcessor()->handleTeammateHits(); + if (hp) + hp->handleTeammateHits(); return was_real_hit; } // hit diff --git a/src/items/cake.cpp b/src/items/cake.cpp index dd3f2de6b2f..199b73d2b74 100644 --- a/src/items/cake.cpp +++ b/src/items/cake.cpp @@ -27,8 +27,6 @@ #include "utils/hit_processor.hpp" #include "utils/random_generator.hpp" -#include "network/protocols/server_lobby.hpp" - #include "utils/log.hpp" //TODO: remove after debugging is done float Cake::m_st_max_distance_squared; @@ -64,9 +62,9 @@ void Cake::init(const XMLNode &node, scene::IMesh *cake_model) */ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj) { - auto sl = LobbyProtocol::get(); - if (sl) - sl->getHitProcessor()->setTeammateHitOwner(getOwnerId()); + auto hp = kart->getHitProcessor(); + if (hp) + hp->setTeammateHitOwner(getOwnerId()); bool was_real_hit = Flyable::hit(kart, obj); if (was_real_hit) @@ -74,18 +72,18 @@ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj) if (kart && kart->isShielded()) { kart->decreaseShieldTime(); - if (sl) + if (hp) { - sl->getHitProcessor()->registerTeammateHit(kart->getWorldKartId()); - sl->getHitProcessor()->handleTeammateHits(); + hp->registerTeammateHit(kart->getWorldKartId()); + hp->handleTeammateHits(); } return false; //Not sure if a shield hit is a real hit. } explode(kart, obj); } - if (sl) - sl->getHitProcessor()->handleTeammateHits(); + if (hp) + hp->handleTeammateHits(); return was_real_hit; } // hit diff --git a/src/items/powerup.cpp b/src/items/powerup.cpp index 253fe2af95d..822f40abbe9 100644 --- a/src/items/powerup.cpp +++ b/src/items/powerup.cpp @@ -39,8 +39,6 @@ #include "utils/string_utils.hpp" #include "utils/log.hpp" //TODO: remove after debugging is done -#include "network/protocols/server_lobby.hpp" - //----------------------------------------------------------------------------- /** Constructor, stores the kart to which this powerup belongs. * \param kart The kart to which this powerup belongs. @@ -404,9 +402,9 @@ void Powerup::use() if(kart->getPosition() == 1) { // check if we are in team gp and hit a teammate and should punish the attacker - auto sl = LobbyProtocol::get(); - if(sl && !kart->hasFinishedRace()) - sl->getHitProcessor()->handleAnvilHit(m_kart->getWorldKartId(), kart->getWorldKartId()); + auto hp = kart->getHitProcessor(); + if(hp && !kart->hasFinishedRace()) + hp->handleAnvilHit(m_kart->getWorldKartId(), kart->getWorldKartId()); kart->getAttachment()->set(Attachment::ATTACH_ANVIL, stk_config-> diff --git a/src/items/swatter.cpp b/src/items/swatter.cpp index 9f15af56d63..b6674b1377b 100644 --- a/src/items/swatter.cpp +++ b/src/items/swatter.cpp @@ -42,7 +42,6 @@ #include "modes/capture_the_flag.hpp" #include "network/network_string.hpp" #include "network/rewind_manager.hpp" -#include "network/protocols/server_lobby.hpp" #include "utils/hit_processor.hpp" #include @@ -398,7 +397,7 @@ void Swatter::squashThingsAround() const KartProperties *kp = m_kart->getKartProperties(); float duration = kp->getSwatterSquashDuration(); - float slowdown = kp->getSwatterSquashSlowdown(); + float slowdown = kp->getSwatterSquashSlowdown(); // The squash attempt may fail because of invulnerability, shield, etc. // Making a bomb explode counts as a success bool wasHit = !m_closest_kart->isInvulnerable() && !m_closest_kart->getKartAnimation(); @@ -411,9 +410,9 @@ void Swatter::squashThingsAround() if (wasHit) { // check if we are in team gp and hit a teammate and should punish attacker - auto sl = LobbyProtocol::get(); - if (sl && !m_closest_kart->hasFinishedRace()) - sl->getHitProcessor()->handleSwatterHit(m_kart->getWorldKartId(), + auto hp = m_kart->getHitProcessor(); + if (hp && !m_closest_kart->hasFinishedRace()) + hp->handleSwatterHit(m_kart->getWorldKartId(), m_closest_kart->getWorldKartId(), success, m_has_hit_kart, World::getWorld()->getTicksSinceStart() - m_created_ticks); } diff --git a/src/karts/abstract_kart.cpp b/src/karts/abstract_kart.cpp index b83f2473fb3..800f9d73ebe 100644 --- a/src/karts/abstract_kart.cpp +++ b/src/karts/abstract_kart.cpp @@ -28,6 +28,7 @@ #include "karts/kart_properties_manager.hpp" #include "karts/official_karts.hpp" #include "network/network_config.hpp" +#include "utils/hit_processor.hpp" #include "physics/physics.hpp" #include "utils/log.hpp" #include "utils/string_utils.hpp" @@ -276,3 +277,9 @@ void AbstractKart::makeKartRest() body->proceedToTransform(t); setTrans(t); } // makeKartRest + +// ---------------------------------------------------------------------------- +std::shared_ptr AbstractKart::getHitProcessor() const +{ + return RaceManager::get()->getHitProcessor(); +} // getHitProcessor diff --git a/src/karts/abstract_kart.hpp b/src/karts/abstract_kart.hpp index dafd3c70a6d..8b512b0cd24 100644 --- a/src/karts/abstract_kart.hpp +++ b/src/karts/abstract_kart.hpp @@ -25,6 +25,7 @@ #include "karts/moveable.hpp" #include "karts/controller/kart_control.hpp" #include "race/race_manager.hpp" +class HitProcessor; namespace irr { @@ -550,6 +551,8 @@ class AbstractKart : public Moveable /** Return the confirmed finish ticks (sent by the server) * indicating that this kart has really finished the race. */ virtual int getNetworkConfirmedFinishTicks() const = 0; + // ------------------------------------------------------------------------ + std::shared_ptr getHitProcessor() const; }; // AbstractKart diff --git a/src/karts/explosion_animation.cpp b/src/karts/explosion_animation.cpp index 799cf8e8e46..79326e11454 100644 --- a/src/karts/explosion_animation.cpp +++ b/src/karts/explosion_animation.cpp @@ -28,7 +28,6 @@ #include "modes/follow_the_leader.hpp" #include "network/network_string.hpp" #include "network/protocols/client_lobby.hpp" -#include "network/protocols/server_lobby.hpp" #include "race/race_manager.hpp" #include "tracks/track.hpp" #include "utils/hit_processor.hpp" @@ -57,13 +56,13 @@ ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart, // Ignore explosion that are too far away. if(!direct_hit && pos.distance2(kart->getXYZ())>r*r) return NULL; - auto sl = LobbyProtocol::get(); + auto hp = kart->getHitProcessor(); if(kart->isShielded()) { kart->decreaseShieldTime(); - if (sl) - sl->getHitProcessor()->registerTeammateHit(kart->getWorldKartId()); + if (hp) + hp->registerTeammateHit(kart->getWorldKartId()); return NULL; } @@ -75,8 +74,8 @@ ExplosionAnimation *ExplosionAnimation::create(AbstractKart *kart, ftl_world->leaderHit(); } - if (sl) - sl->getHitProcessor()->registerTeammateExplode(kart->getWorldKartId()); + if (hp) + hp->registerTeammateExplode(kart->getWorldKartId()); return new ExplosionAnimation(kart, direct_hit); } // create diff --git a/src/network/game_setup.cpp b/src/network/game_setup.cpp index d86a62721d1..a09fd83369b 100644 --- a/src/network/game_setup.cpp +++ b/src/network/game_setup.cpp @@ -30,6 +30,7 @@ #include "network/stk_host.hpp" #include "race/race_manager.hpp" #include "utils/file_utils.hpp" +#include "utils/lobby_settings.hpp" #include "utils/log.hpp" #include "utils/stk_process.hpp" #include "utils/string_utils.hpp" @@ -145,7 +146,7 @@ void GameSetup::addServerInfo(NetworkString* ns) ns->encodeString16(m_message_of_today); ns->addUInt8((uint8_t)ServerConfig::m_server_configurable); - ns->addUInt8(ServerConfig::m_live_players? 1 : 0); + ns->addUInt8(getSettings()->isLivePlayers() ? 1 : 0); } // addServerInfo //----------------------------------------------------------------------------- diff --git a/src/network/game_setup.hpp b/src/network/game_setup.hpp index 36811d51b16..20c4c35c3f7 100644 --- a/src/network/game_setup.hpp +++ b/src/network/game_setup.hpp @@ -23,6 +23,7 @@ #define GAME_SETUP_HPP #include +#include "utils/lobby_context.hpp" #include #include @@ -39,7 +40,7 @@ class PeerVote; * \brief Used to store the needed data about the players that join a game. * This class stores all the possible information about players in a lobby. */ -class GameSetup +class GameSetup: public LobbyContextUser { private: std::vector m_tracks; diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 29f2267a766..3dbe978567b 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -37,6 +37,7 @@ #include "utils/hourglass_reason.hpp" #include "utils/kart_elimination.hpp" #include "utils/lobby_asset_manager.hpp" +#include "utils/lobby_context.hpp" #include "utils/lobby_settings.hpp" #include "utils/lobby_queues.hpp" #include "utils/log.hpp" @@ -244,7 +245,7 @@ CommandManager::Command::Command(std::string name, void CommandManager::initCommandsInfo() { // "commands.xml" - const std::string file_name = file_manager->getAsset(ServerConfig::m_commands_file); + const std::string file_name = file_manager->getAsset(getSettings()->getCommandsFile()); const XMLNode *root = file_manager->createXMLTree(file_name); uint32_t version = 1; root->get("version", &version); @@ -541,8 +542,8 @@ void CommandManager::initCommands() applyFunctionIfPossible("liststkaddon", &CM::special); applyFunctionIfPossible("listlocaladdon", &CM::special); - addTextResponse("description", m_lobby_settings->getMotd()); - addTextResponse("moreinfo", m_lobby_settings->getHelpMessage()); + addTextResponse("description", getSettings()->getMotd()); + addTextResponse("moreinfo", getSettings()->getHelpMessage()); std::string version = "1.3 k 210fff beta"; #ifdef GIT_VERSION version = std::string(GIT_VERSION); @@ -602,19 +603,8 @@ void CommandManager::initAssets() } // initAssets // ======================================================================== -CommandManager::CommandManager(ServerLobby* lobby): - m_lobby(lobby) +void CommandManager::setupContextUser() { - if (!lobby) - return; - - m_hit_processor = lobby->getHitProcessor(); - m_asset_manager = lobby->getLobbyAssetManager(); - m_tournament = lobby->getTournament(); - m_lobby_queues = lobby->getLobbyQueues(); - m_lobby_settings = lobby->getLobbySettings(); - m_kart_elimination = lobby->getKartElimination(); - initCommands(); initAssets(); @@ -660,7 +650,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) return; CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); - permissions = m_lobby->getPermissions(peer); + permissions = getLobby()->getPermissions(peer); voting = false; std::string action = "invoke"; std::string username = ""; @@ -673,7 +663,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) if (argv.size() == 1 || argv[1] == "vote") { std::string msg = "Usage: /vote (a command with arguments)"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } std::reverse(argv.begin(), argv.end()); @@ -704,7 +694,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) msg = "Pick one of " + std::to_string(-1 + (int)m_user_command_replacements[username].size()) + " options using /1, etc., or use /0, or type a different command"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } } @@ -737,20 +727,20 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) { // todo change message std::string msg = "There is no such command but there should be. Very strange. Please report it."; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } else if (!isAvailable(command)) { std::string msg = "You don't have permissions to " + action + " this command"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } int mask = (permissions & command->m_permissions); if (mask == 0) { std::string msg = "You don't have permissions to " + action + " this command"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } int mask_without_voting = (mask & ~PE_VOTED); @@ -790,7 +780,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) first_time = false; } } - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); auto res = response.second; if (!res.empty()) { @@ -800,7 +790,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '"', '\\'); CommandManager::restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); std::string msg2 = "Command \"/" + new_cmd + "\" has been successfully voted"; - m_lobby->sendStringToAllPeers(msg2); + getLobby()->sendStringToAllPeers(msg2); Context new_context(event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); execute(executed_command, new_context); } @@ -822,7 +812,7 @@ int CommandManager::getCurrentModeScope() int CommandManager::getCurrentStateScope() { - auto state = m_lobby->m_state.load(); + auto state = getLobby()->m_state.load(); if (state < ServerLobby::WAITING_FOR_START_GAME || state > ServerLobby::RESULT_DISPLAY) return 0; @@ -875,7 +865,7 @@ void CommandManager::update() auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '"', '\\'); CommandManager::restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); std::string msg = "Command \"/" + new_cmd + "\" has been successfully voted"; - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); // Happily the name of the votable coincides with the command full name std::shared_ptr command = m_full_name_to_command[votable_pairs.first].lock(); if (!command) @@ -913,7 +903,7 @@ void CommandManager::error(Context& context, bool is_error) msg = "An error occurred while invoking command \"" + command->getFullName() + "\"."; if (is_error) msg += "\n/!\\ Please report this error to the server owner"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // error // ======================================================================== @@ -953,7 +943,7 @@ void CommandManager::process_help(Context& context) return; } std::string msg = command->getHelp(); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_help // ======================================================================== @@ -973,7 +963,7 @@ void CommandManager::process_text(Context& context) + " is defined without text"; else response = it->second; - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); } // process_text // ======================================================================== @@ -993,7 +983,7 @@ void CommandManager::process_file(Context& context) + command->getFullName(); else response = it->second.get(); - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); } // process_text // ======================================================================== @@ -1022,7 +1012,7 @@ void CommandManager::process_auth(Context& context) else response = it->second.get(username, online_id); } - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); } // process_text // ======================================================================== @@ -1058,7 +1048,7 @@ void CommandManager::process_commands(Context& context) if (!valid_prefix) { result = "There are no available commands with such prefix"; - m_lobby->sendStringToPeer(result, peer); + getLobby()->sendStringToPeer(result, peer); return; } result = (command == m_root_command ? "Available commands" @@ -1091,7 +1081,7 @@ void CommandManager::process_commands(Context& context) } if (had_any_subcommands) result += "\n* has subcommands"; - m_lobby->sendStringToPeer(result, peer); + getLobby()->sendStringToPeer(result, peer); } // process_commands // ======================================================================== @@ -1106,7 +1096,7 @@ void CommandManager::process_replay(Context& context) } if (ServerConfig::m_record_replays) { - bool current_state = m_lobby_settings->hasConsentOnReplays(); + bool current_state = getSettings()->hasConsentOnReplays(); if (argv.size() >= 2 && argv[1] == "0") current_state = false; else if (argv.size() >= 2 && argv[1] == "1") @@ -1114,15 +1104,15 @@ void CommandManager::process_replay(Context& context) else current_state ^= 1; - m_lobby_settings->setConsentOnReplays(current_state); + getSettings()->setConsentOnReplays(current_state); std::string msg = "Recording ghost replays is now "; msg += (current_state ? "on" : "off"); - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); } else { std::string msg = "This server doesn't allow recording replays"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } } // process_replay // ======================================================================== @@ -1138,7 +1128,7 @@ void CommandManager::process_start(Context& context) vote(context, "start", ""); return; } - m_lobby->startSelection(context.m_event); + getLobby()->startSelection(context.m_event); } // process_start // ======================================================================== @@ -1150,9 +1140,9 @@ void CommandManager::process_config(Context& context) error(context, true); return; } - int difficulty = m_lobby->getDifficulty(); - int mode = m_lobby->getGameMode(); - bool goal_target = (m_lobby->m_game_setup->hasExtraServerInfo() ? m_lobby->isSoccerGoalTarget() : false); + int difficulty = getLobby()->getDifficulty(); + int mode = getLobby()->getGameMode(); + bool goal_target = (getLobby()->m_game_setup->hasExtraServerInfo() ? getLobby()->isSoccerGoalTarget() : false); // m_aux_goal_aliases[goal_target ? 1 : 0][0] std::string msg = "Current config: "; auto get_first_if_exists = [&](std::vector& v) -> std::string { @@ -1168,7 +1158,7 @@ void CommandManager::process_config(Context& context) msg += get_first_if_exists(m_aux_goal_aliases[goal_target ? 1 : 0]); if (!ServerConfig::m_server_configurable) msg += " (not configurable)"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_config // ======================================================================== @@ -1178,13 +1168,13 @@ void CommandManager::process_config_assign(Context& context) if (!ServerConfig::m_server_configurable) { std::string msg = "Server is not configurable, this command cannot be invoked."; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } const auto& argv = context.m_argv; - int difficulty = m_lobby->getDifficulty(); - int mode = m_lobby->getGameMode(); - bool goal_target = (m_lobby->m_game_setup->hasExtraServerInfo() ? m_lobby->isSoccerGoalTarget() : false); + int difficulty = getLobby()->getDifficulty(); + int mode = getLobby()->getGameMode(); + bool goal_target = (getLobby()->m_game_setup->hasExtraServerInfo() ? getLobby()->isSoccerGoalTarget() : false); bool user_chose_difficulty = false; bool user_chose_mode = false; bool user_chose_target = false; @@ -1223,11 +1213,11 @@ void CommandManager::process_config_assign(Context& context) // if (mode != 6) { // goal_target = false; // } - if (!m_lobby_settings->isDifficultyAvailable(difficulty) - || !m_lobby_settings->isModeAvailable(mode)) + if (!getSettings()->isDifficultyAvailable(difficulty) + || !getSettings()->isModeAvailable(mode)) { std::string response = "Mode or difficulty are not permitted on this server"; - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); return; } if (context.m_voting) @@ -1242,7 +1232,7 @@ void CommandManager::process_config_assign(Context& context) vote(context, "config target", m_aux_goal_aliases[goal_target ? 1 : 0][0]); return; } - m_lobby->handleServerConfiguration(peer, difficulty, mode, goal_target); + getLobby()->handleServerConfiguration(peer, difficulty, mode, goal_target); } // process_config_assign // ======================================================================== @@ -1257,12 +1247,12 @@ void CommandManager::process_spectate(Context& context) return; } - if (/*m_game_setup->isGrandPrix() || */!ServerConfig::m_live_players) + if (/*m_game_setup->isGrandPrix() || */!getSettings()->isLivePlayers()) response = "Server doesn't support spectating"; if (!response.empty()) { - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); return; } @@ -1283,22 +1273,22 @@ void CommandManager::process_spectate(Context& context) } if (value >= 1) { - if (m_lobby->m_process_type == PT_CHILD && - peer->getHostId() == m_lobby->m_client_server_host_id.load()) + if (getLobby()->m_process_type == PT_CHILD && + peer->getHostId() == getLobby()->m_client_server_host_id.load()) { std::string msg = "Graphical client server cannot spectate"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } AlwaysSpectateMode type = (value == 2 ? ASM_COMMAND_ABSENT : ASM_COMMAND); - m_lobby->setSpectateModeProperly(peer, type); + getLobby()->setSpectateModeProperly(peer, type); } else { - m_lobby->setSpectateModeProperly(peer, ASM_NONE); + getLobby()->setSpectateModeProperly(peer, ASM_NONE); } - m_lobby->updateServerOwner(true); - m_lobby->updatePlayerList(); + getLobby()->updateServerOwner(true); + getLobby()->updatePlayerList(); } // process_spectate // ======================================================================== @@ -1320,16 +1310,17 @@ void CommandManager::process_addons(Context& context) apply_filters = true; argv[1] = getAddonPreferredType(); } + auto asset_manager = getAssetManager(); // removed const reference so that I can modify `from` // without changing the original container, we copy everything anyway std::set from = - (argv[1] == "kart" ? m_asset_manager->getAddonKarts() : - (argv[1] == "track" ? m_asset_manager->getAddonTracks() : - (argv[1] == "arena" ? m_asset_manager->getAddonArenas() : - /*argv[1] == "soccer" ?*/ m_asset_manager->getAddonSoccers() + (argv[1] == "kart" ? asset_manager->getAddonKarts() : + (argv[1] == "track" ? asset_manager->getAddonTracks() : + (argv[1] == "arena" ? asset_manager->getAddonArenas() : + /*argv[1] == "soccer" ?*/ asset_manager->getAddonSoccers() ))); if (apply_filters) - m_lobby->applyAllFilters(from, false); // happily the type is never karts in this line + getLobby()->applyAllFilters(from, false); // happily the type is never karts in this line std::vector>> result; for (const std::string& s: from) result.push_back({s, {}}); @@ -1341,7 +1332,7 @@ void CommandManager::process_addons(Context& context) if (!p || !p->isValidated()) continue; if ((!more_own || p != peer) && (p->isWaitingForGame() - || !m_lobby->canRace(p) || p->isCommandSpectator())) + || !getLobby()->canRace(p) || p->isCommandSpectator())) continue; if (!p->hasPlayerProfiles()) continue; @@ -1439,7 +1430,7 @@ void CommandManager::process_addons(Context& context) response = "No one in the lobby can play. Found " + std::to_string(all_have.size()) + " assets on the server."; } - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); } // process_addons // ======================================================================== @@ -1467,20 +1458,21 @@ void CommandManager::process_checkaddon(Context& context) unsigned server_status = 0; std::vector players[4]; - if (m_asset_manager->hasAddonKart(id)) + auto asset_manager = getAssetManager(); + if (asset_manager->hasAddonKart(id)) server_status |= HAS_KART; - if (m_asset_manager->hasAddonTrack(id)) + if (asset_manager->hasAddonTrack(id)) server_status |= HAS_MAP; - if (m_asset_manager->hasAddonArena(id)) + if (asset_manager->hasAddonArena(id)) server_status |= HAS_MAP; - if (m_asset_manager->hasAddonSoccer(id)) + if (asset_manager->hasAddonSoccer(id)) server_status |= HAS_MAP; auto peers = STKHost::get()->getPeers(); for (auto p : peers) { if (!p || !p->isValidated() || p->isWaitingForGame() - || !m_lobby->canRace(p) || p->isCommandSpectator() + || !getLobby()->canRace(p) || p->isCommandSpectator() || !p->hasPlayerProfiles()) continue; std::string username = StringUtils::wideToUtf8( @@ -1558,7 +1550,7 @@ void CommandManager::process_checkaddon(Context& context) } response.pop_back(); } - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); } // process_checkaddon // ======================================================================== @@ -1581,7 +1573,7 @@ void CommandManager::process_id(Context& context) return; std::string id = argv[1]; std::string response = "Server knows this map, copy it below:\n" + id; - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); } // process_id // ======================================================================== @@ -1621,28 +1613,29 @@ void CommandManager::process_lsa(Context& context) } std::set total_addons; + auto asset_manager = getAssetManager(); if (type.empty() || // not specify addon type (!type.empty() && type.compare("kart") == 0)) // list kart addon { - const auto& collection = m_asset_manager->getAddonKarts(); + const auto& collection = asset_manager->getAddonKarts(); total_addons.insert(collection.begin(), collection.end()); } if (type.empty() || // not specify addon type (!type.empty() && type.compare("track") == 0)) { - const auto& collection = m_asset_manager->getAddonTracks(); + const auto& collection = asset_manager->getAddonTracks(); total_addons.insert(collection.begin(), collection.end()); } if (type.empty() || // not specify addon type (!type.empty() && type.compare("arena") == 0)) { - const auto& collection = m_asset_manager->getAddonArenas(); + const auto& collection = asset_manager->getAddonArenas(); total_addons.insert(collection.begin(), collection.end()); } if (type.empty() || // not specify addon type (!type.empty() && type.compare("soccer") == 0)) { - const auto& collection = m_asset_manager->getAddonSoccers(); + const auto& collection = asset_manager->getAddonSoccers(); total_addons.insert(collection.begin(), collection.end()); } std::string msg = ""; @@ -1662,7 +1655,7 @@ void CommandManager::process_lsa(Context& context) msg = msg.substr(0, msg.size() - 2); response = "Server's addons: " + msg; } - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); } // process_lsa // ======================================================================== @@ -1731,7 +1724,7 @@ void CommandManager::process_pha(Context& context) { response = player_name + " has no addon " + addon_id; } - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); } // process_pha // ======================================================================== @@ -1762,7 +1755,7 @@ void CommandManager::process_kick(Context& context) { std::string msg = "This player is the owner of this server, " "and is protected from your actions now"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } if (context.m_voting) @@ -1775,15 +1768,15 @@ void CommandManager::process_kick(Context& context) if (ServerConfig::m_track_kicks) { std::string auto_report = "[ Auto report caused by kick ]"; - m_lobby->writeOwnReport(player_peer, peer, auto_report); + getLobby()->writeOwnReport(player_peer, peer, auto_report); } if (argv[0] == "kickban") { Log::info("CommandManager", "%s is now banned", player_name.c_str()); - m_lobby->m_temp_banned.insert(player_name); + getLobby()->m_temp_banned.insert(player_name); std::string msg = StringUtils::insertValues( "%s is now banned", player_name.c_str()); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } } // process_kick // ======================================================================== @@ -1809,10 +1802,10 @@ void CommandManager::process_unban(Context& context) return; } Log::info("CommandManager", "%s is now unbanned", player_name.c_str()); - m_lobby->m_temp_banned.erase(player_name); + getLobby()->m_temp_banned.erase(player_name); std::string msg = StringUtils::insertValues( "%s is now unbanned", player_name.c_str()); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_unban // ======================================================================== @@ -1838,10 +1831,10 @@ void CommandManager::process_ban(Context& context) return; } Log::info("CommandManager", "%s is now banned", player_name.c_str()); - m_lobby->m_temp_banned.insert(player_name); + getLobby()->m_temp_banned.insert(player_name); std::string msg = StringUtils::insertValues( "%s is now banned", player_name.c_str()); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_ban // ======================================================================== @@ -1903,7 +1896,7 @@ void CommandManager::process_pas(Context& context) msg.pop_back(); response = msg; } - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); } // process_pas // ======================================================================== @@ -1984,7 +1977,7 @@ void CommandManager::process_everypas(Context& context) response += msg; } } - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); } // process_everypas // ======================================================================== @@ -2005,10 +1998,11 @@ void CommandManager::process_sha(Context& context) } std::set total_addons; - const auto all_karts = m_asset_manager->getAddonKarts(); - const auto all_tracks = m_asset_manager->getAddonTracks(); - const auto all_arenas = m_asset_manager->getAddonArenas(); - const auto all_soccers = m_asset_manager->getAddonSoccers(); + auto asset_manager = getAssetManager(); + const auto all_karts = asset_manager->getAddonKarts(); + const auto all_tracks = asset_manager->getAddonTracks(); + const auto all_arenas = asset_manager->getAddonArenas(); + const auto all_soccers = asset_manager->getAddonSoccers(); total_addons.insert(all_karts.begin(), all_karts.end()); total_addons.insert(all_tracks.begin(), all_tracks.end()); total_addons.insert(all_arenas.begin(), all_arenas.end()); @@ -2023,7 +2017,7 @@ void CommandManager::process_sha(Context& context) { response = "Server has no addon " + argv[1]; } - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); } // process_sha // ======================================================================== @@ -2059,9 +2053,9 @@ void CommandManager::process_mute(Context& context) return; } - m_lobby_settings->addMutedPlayerFor(peer, player_name); + getSettings()->addMutedPlayerFor(peer, player_name); result_msg = "Muted player " + argv[1]; - m_lobby->sendStringToPeer(result_msg, peer); + getLobby()->sendStringToPeer(result_msg, peer); } // process_mute // ======================================================================== @@ -2085,14 +2079,14 @@ void CommandManager::process_unmute(Context& context) player_name = StringUtils::utf8ToWide(argv[1]); - if (!m_lobby_settings->removeMutedPlayerFor(peer, player_name)) + if (!getSettings()->removeMutedPlayerFor(peer, player_name)) { error(context); return; } std::string result_msg = "Unmuted player " + StringUtils::wideToUtf8(player_name); - m_lobby->sendStringToPeer(result_msg, peer); + getLobby()->sendStringToPeer(result_msg, peer); } // process_unmute // ======================================================================== @@ -2106,8 +2100,8 @@ void CommandManager::process_listmute(Context& context) return; } - std::string muted_players = m_lobby_settings->getMutedPlayersAsString(peer); - m_lobby->sendStringToPeer(muted_players, peer); + std::string muted_players = getSettings()->getMutedPlayersAsString(peer); + getLobby()->sendStringToPeer(muted_players, peer); } // process_listmute // ======================================================================== @@ -2125,16 +2119,17 @@ void CommandManager::process_gnu(Context& context) } // "nognu" and "gnu off" are equivalent bool turn_on = (argv.size() < 2 || argv[1] != "off"); - if (turn_on && m_kart_elimination->isEnabled()) + auto kart_elimination = getKartElimination(); + if (turn_on && kart_elimination->isEnabled()) { std::string msg = "Gnu Elimination mode was already enabled!"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } - if (!turn_on && !m_kart_elimination->isEnabled()) + if (!turn_on && !kart_elimination->isEnabled()) { std::string msg = "Gnu Elimination mode was already off!"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } if (turn_on && @@ -2142,7 +2137,7 @@ void CommandManager::process_gnu(Context& context) RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) { std::string msg = "Gnu Elimination is available only with racing modes"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } std::string kart; @@ -2155,7 +2150,7 @@ void CommandManager::process_gnu(Context& context) if (peer) { kart = "gnu"; - if (argv.size() > 1 && m_asset_manager->isKartAvailable(argv[1])) + if (argv.size() > 1 && getAssetManager()->isKartAvailable(argv[1])) { kart = argv[1]; } @@ -2181,15 +2176,15 @@ void CommandManager::process_gnu(Context& context) m_votables["gnu"].reset("gnu kart"); if (kart == "off") { - m_kart_elimination->disable(); + kart_elimination->disable(); std::string msg = "Gnu Elimination is now off"; - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); } else { - m_kart_elimination->enable(kart); - std::string msg = m_kart_elimination->getStartingMessage(); - m_lobby->sendStringToAllPeers(msg); + kart_elimination->enable(kart); + std::string msg = kart_elimination->getStartingMessage(); + getLobby()->sendStringToAllPeers(msg); } } // process_gnu // ======================================================================== @@ -2215,7 +2210,7 @@ void CommandManager::process_tell(Context& context) ans.push_back(' '); ans += argv[i]; } - m_lobby->writeOwnReport(peer, peer, ans); + getLobby()->writeOwnReport(peer, peer, ans); } // process_tell // ======================================================================== @@ -2248,7 +2243,7 @@ void CommandManager::process_standings(Context& context) } if (!isGP && !isGnu) { - if (m_lobby->m_game_setup->isGrandPrix()) + if (getLobby()->m_game_setup->isGrandPrix()) isGP = true; else isGnu = true; @@ -2257,11 +2252,11 @@ void CommandManager::process_standings(Context& context) { // the function will decide itself what to show if nothing is specified: // if there are teams, teams will be shown, otherwise players - msg = m_lobby->getGrandPrixStandings(isGPPlayers, isGPTeams); + msg = getLobby()->getGrandPrixStandings(isGPPlayers, isGPTeams); } else if (isGnu) - msg = m_kart_elimination->getStandings(); - m_lobby->sendStringToPeer(msg, peer); + msg = getKartElimination()->getStandings(); + getLobby()->sendStringToPeer(msg, peer); } // process_standings // ======================================================================== @@ -2273,9 +2268,9 @@ void CommandManager::process_teamchat(Context& context) error(context, true); return; } - m_lobby_settings->addTeamSpeaker(peer); + getSettings()->addTeamSpeaker(peer); std::string msg = "Your messages are now addressed to team only"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_teamchat // ======================================================================== @@ -2301,9 +2296,9 @@ void CommandManager::process_to(Context& context) return; receivers.push_back(argv[i]); } - m_lobby_settings->setMessageReceiversFor(peer, receivers); + getSettings()->setMessageReceiversFor(peer, receivers); std::string msg = "Successfully changed chat settings"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_to // ======================================================================== @@ -2315,9 +2310,9 @@ void CommandManager::process_public(Context& context) error(context, true); return; } - m_lobby_settings->makeChatPublicFor(peer); + getSettings()->makeChatPublicFor(peer); std::string s = "Your messages are now public"; - m_lobby->sendStringToPeer(s, peer); + getLobby()->sendStringToPeer(s, peer); } // process_public // ======================================================================== @@ -2360,12 +2355,12 @@ void CommandManager::process_record(Context& context) } else { - response = m_lobby->getRecord(track_name, mode_name, reverse_name, laps_count); + response = getLobby()->getRecord(track_name, mode_name, reverse_name, laps_count); } #else response = "This command is not supported."; #endif - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); } // process_record // ======================================================================== @@ -2382,8 +2377,8 @@ void CommandManager::process_power(Context& context) { peer->setAngryHost(false); std::string msg = "You are now a normal player"; - m_lobby->sendStringToPeer(msg, peer); - m_lobby->updatePlayerList(); + getLobby()->sendStringToPeer(msg, peer); + getLobby()->updatePlayerList(); return; } std::string username = ""; @@ -2397,18 +2392,18 @@ void CommandManager::process_power(Context& context) std::string password = ServerConfig::m_power_password; bool bad_password = (password.empty() || argv.size() <= 1 || argv[1] != password); - bool good_player = (m_lobby_settings->isInHammerWhitelist(username) + bool good_player = (getSettings()->isInHammerWhitelist(username) && online_id != 0); if (bad_password && !good_player) { std::string msg = "You need to provide the password to have the power"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } peer->setAngryHost(true); std::string msg = "Now you finally have the power!"; - m_lobby->sendStringToPeer(msg, peer); - m_lobby->updatePlayerList(); + getLobby()->sendStringToPeer(msg, peer); + getLobby()->updatePlayerList(); } // process_power // ======================================================================== void CommandManager::process_length(Context& context) @@ -2419,8 +2414,8 @@ void CommandManager::process_length(Context& context) error(context, true); return; } - std::string msg = m_lobby_settings->getLapRestrictionsAsString(); - m_lobby->sendStringToPeer(msg, peer); + std::string msg = getSettings()->getLapRestrictionsAsString(); + getLobby()->sendStringToPeer(msg, peer); } // process_length // ======================================================================== void CommandManager::process_length_multi(Context& context) @@ -2434,9 +2429,9 @@ void CommandManager::process_length_multi(Context& context) return; } double value = std::max(0.0, temp_double); - m_lobby_settings->setMultiplier(value); + getSettings()->setMultiplier(value); std::string msg = StringUtils::insertValues("Game length is now %f x default", value); - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); } // process_length_multi // ======================================================================== void CommandManager::process_length_fixed(Context& context) @@ -2450,23 +2445,23 @@ void CommandManager::process_length_fixed(Context& context) return; } int value = std::max(0, temp_int); - m_lobby_settings->setFixedLapCount(value); + getSettings()->setFixedLapCount(value); std::string msg = StringUtils::insertValues("Game length is now %d", value); - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); } // process_length_fixed // ======================================================================== void CommandManager::process_length_clear(Context& context) { - m_lobby_settings->resetLapRestrictions(); + getSettings()->resetLapRestrictions(); std::string msg = "Game length will be chosen by players"; - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); } // process_length_clear // ======================================================================== void CommandManager::process_direction(Context& context) { - std::string msg = m_lobby_settings->getDirectionAsString(); - m_lobby->sendStringToAllPeers(msg); + std::string msg = getSettings()->getDirectionAsString(); + getLobby()->sendStringToAllPeers(msg); } // process_direction // ======================================================================== @@ -2480,13 +2475,13 @@ void CommandManager::process_direction_assign(Context& context) return; } int temp_int = -1; - if (!StringUtils::parseString(argv[1], &temp_int) || !m_lobby_settings->setDirection(temp_int)) + if (!StringUtils::parseString(argv[1], &temp_int) || !getSettings()->setDirection(temp_int)) { error(context); return; } - msg = m_lobby_settings->getDirectionAsString(true); - m_lobby->sendStringToAllPeers(msg); + msg = getSettings()->getDirectionAsString(true); + getLobby()->sendStringToAllPeers(msg); } // process_direction_assign // ======================================================================== @@ -2513,7 +2508,7 @@ void CommandManager::process_queue(Context& context) } } msg.pop_back(); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_queue // ======================================================================== @@ -2535,10 +2530,11 @@ void CommandManager::process_queue_push(Context& context) int mask = get_queue_mask(argv[0]); bool to_front = (argv[1] == "push_front"); + auto asset_manager = getAssetManager(); if (argv.size() == 3 && argv[2] == "-") // kept until there's filter-type replacement - argv[2] = m_asset_manager->getRandomMap(); + argv[2] = asset_manager->getRandomMap(); else if (argv.size() == 3 && argv[2] == "-addon") // kept until there's filter-type replacement - argv[2] = m_asset_manager->getRandomAddonMap(); + argv[2] = asset_manager->getRandomAddonMap(); std::string filter_text = ""; CommandManager::restoreCmdByArgv(filter_text, argv, ' ', '"', '"', '\\', 2); @@ -2603,8 +2599,8 @@ void CommandManager::process_queue_push(Context& context) } msg.pop_back(); - m_lobby->sendStringToAllPeers(msg); - m_lobby->updatePlayerList(); + getLobby()->sendStringToAllPeers(msg); + getLobby()->updatePlayerList(); } // process_queue_push // ======================================================================== @@ -2658,8 +2654,8 @@ void CommandManager::process_queue_pop(Context& context) } } msg.pop_back(); - m_lobby->sendStringToAllPeers(msg); - m_lobby->updatePlayerList(); + getLobby()->sendStringToAllPeers(msg); + getLobby()->updatePlayerList(); } // process_queue_pop // ======================================================================== @@ -2686,8 +2682,8 @@ void CommandManager::process_queue_clear(Context& context) } } msg.pop_back(); - m_lobby->sendStringToAllPeers(msg); - m_lobby->updatePlayerList(); + getLobby()->sendStringToAllPeers(msg); + getLobby()->updatePlayerList(); } // process_queue_clear // ======================================================================== @@ -2726,8 +2722,8 @@ void CommandManager::process_queue_shuffle(Context& context) } } msg.pop_back(); - m_lobby->sendStringToAllPeers(msg); - m_lobby->updatePlayerList(); + getLobby()->sendStringToAllPeers(msg); + getLobby()->updatePlayerList(); } // process_queue_shuffle // ======================================================================== @@ -2740,8 +2736,8 @@ void CommandManager::process_allowstart(Context& context) return; } - std::string msg = m_lobby_settings->getAllowedToStartAsString(); - m_lobby->sendStringToPeer(msg, peer); + std::string msg = getSettings()->getAllowedToStartAsString(); + getLobby()->sendStringToPeer(msg, peer); } // process_allowstart // ======================================================================== @@ -2756,9 +2752,9 @@ void CommandManager::process_allowstart_assign(Context& context) error(context); return; } - m_lobby_settings->setAllowedToStart(argv[1] != "0"); - std::string msg = m_lobby_settings->getAllowedToStartAsString(true); - m_lobby->sendStringToAllPeers(msg); + getSettings()->setAllowedToStart(argv[1] != "0"); + std::string msg = getSettings()->getAllowedToStartAsString(true); + getLobby()->sendStringToAllPeers(msg); } // process_allowstart_assign // ======================================================================== @@ -2770,8 +2766,8 @@ void CommandManager::process_shuffle(Context& context) error(context, true); return; } - std::string msg = m_lobby_settings->getWhetherShuffledGPGridAsString(); - m_lobby->sendStringToPeer(msg, peer); + std::string msg = getSettings()->getWhetherShuffledGPGridAsString(); + getLobby()->sendStringToPeer(msg, peer); } // process_shuffle // ======================================================================== @@ -2784,9 +2780,9 @@ void CommandManager::process_shuffle_assign(Context& context) error(context); return; } - m_lobby_settings->setGPGridShuffled(argv[1] != "0"); - std::string msg = m_lobby_settings->getWhetherShuffledGPGridAsString(true); - m_lobby->sendStringToAllPeers(msg); + getSettings()->setGPGridShuffled(argv[1] != "0"); + std::string msg = getSettings()->getWhetherShuffledGPGridAsString(true); + getLobby()->sendStringToAllPeers(msg); } // process_shuffle_assign // ======================================================================== @@ -2806,11 +2802,11 @@ void CommandManager::process_timeout(Context& context) error(context); return; } - m_lobby->m_timeout.store((int64_t)StkTime::getMonoTimeMs() + + getLobby()->m_timeout.store((int64_t)StkTime::getMonoTimeMs() + (int64_t)(seconds * 1000.0f)); - m_lobby->updatePlayerList(); + getLobby()->updatePlayerList(); msg = "Successfully changed timeout"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_timeout // ======================================================================== @@ -2838,7 +2834,7 @@ void CommandManager::process_team(Context& context) if (!argv[1].empty()) { std::string temp(1, argv[1][0]); - if (m_lobby_settings->getAvailableTeams().find(temp) != std::string::npos) + if (getSettings()->getAvailableTeams().find(temp) != std::string::npos) allowed_color = true; } int team = TeamUtils::getIndexByCode(argv[1]); @@ -2847,12 +2843,12 @@ void CommandManager::process_team(Context& context) { std::string msg = StringUtils::insertValues("Color %s is not allowed", argv[1].c_str()); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } - m_lobby->setTemporaryTeamInLobby(player, team); + getLobby()->setTemporaryTeamInLobby(player, team); - m_lobby->updatePlayerList(); + getLobby()->updatePlayerList(); } // process_team // ======================================================================== @@ -2910,9 +2906,9 @@ void CommandManager::process_swapteams(Context& context) int to = TeamUtils::getIndexByCode(std::string(1, p.second)); permutation_map_int[from] = to; } - m_lobby->shuffleTemporaryTeams(permutation_map_int); - m_lobby->sendStringToPeer(msg, peer); // todo make public? - m_lobby->updatePlayerList(); + getLobby()->shuffleTemporaryTeams(permutation_map_int); + getLobby()->sendStringToPeer(msg, peer); // todo make public? + getLobby()->updatePlayerList(); } // process_swapteams // ======================================================================== @@ -2925,9 +2921,9 @@ void CommandManager::process_resetteams(Context& context) return; } std::string msg = "Teams are reset now"; - m_lobby->clearTemporaryTeams(); - m_lobby->sendStringToPeer(msg, peer); - m_lobby->updatePlayerList(); + getLobby()->clearTemporaryTeams(); + getLobby()->sendStringToPeer(msg, peer); + getLobby()->updatePlayerList(); } // process_resetteams // ======================================================================== @@ -2955,13 +2951,13 @@ void CommandManager::process_randomteams(Context& context) msg = "No one can play!"; else msg = "Teams are currently not allowed"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } std::string msg = StringUtils::insertValues( "Created %d teams for %d players", final_number, players_number); - m_lobby->sendStringToPeer(msg, peer); - m_lobby->updatePlayerList(); + getLobby()->sendStringToPeer(msg, peer); + getLobby()->updatePlayerList(); } // process_randomteams // ======================================================================== @@ -2977,10 +2973,10 @@ void CommandManager::process_resetgp(Context& context) error(context); return; } - m_lobby->getGameSetup()->setGrandPrixTrack(number_of_games); + getLobby()->getGameSetup()->setGrandPrixTrack(number_of_games); } - m_lobby->resetGrandPrix(); - m_lobby->sendStringToAllPeers(msg); + getLobby()->resetGrandPrix(); + getLobby()->sendStringToAllPeers(msg); } // process_resetgp // ======================================================================== @@ -3006,8 +3002,8 @@ void CommandManager::process_cat(Context& context) 2, m_stf_present_users, 3, false, true)) return; std::string player = argv[2]; - m_lobby_settings->addPlayerToCategory(player, category); - m_lobby->updatePlayerList(); + getSettings()->addPlayerToCategory(player, category); + getLobby()->updatePlayerList(); return; } if (argv[0] == "cat-") @@ -3023,8 +3019,8 @@ void CommandManager::process_cat(Context& context) 2, m_stf_present_users, 3, false, true)) return; player = argv[2]; - m_lobby_settings->erasePlayerFromCategory(player, category); - m_lobby->updatePlayerList(); + getSettings()->erasePlayerFromCategory(player, category); + getLobby()->updatePlayerList(); return; } if (argv[0] == "catshow") @@ -3038,8 +3034,8 @@ void CommandManager::process_cat(Context& context) return; } std::string category = argv[1]; - m_lobby_settings->makeCategoryVisible(category, displayed); - m_lobby->updatePlayerList(); + getSettings()->makeCategoryVisible(category, displayed); + getLobby()->updatePlayerList(); return; } } // process_cat @@ -3054,11 +3050,12 @@ void CommandManager::process_troll(Context& context) error(context, true); return; } - if (m_hit_processor->isAntiTrollActive()) + auto hit_processor = getHitProcessor(); + if (hit_processor->isAntiTrollActive()) msg = "Trolls will be kicked"; else msg = "Trolls can stay"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_troll // ======================================================================== @@ -3071,15 +3068,16 @@ void CommandManager::process_troll_assign(Context& context) error(context); return; } + auto hit_processor = getHitProcessor(); if (argv[1] == "0") { - m_hit_processor->setAntiTroll(false); + hit_processor->setAntiTroll(false); msg = "Trolls can stay"; } else { - m_hit_processor->setAntiTroll(true); + hit_processor->setAntiTroll(true); msg = "Trolls will be kicked"; } - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); } // process_troll_assign // ======================================================================== @@ -3092,11 +3090,12 @@ void CommandManager::process_hitmsg(Context& context) error(context, true); return; } - if (m_hit_processor->showTeammateHits()) + auto hit_processor = getHitProcessor(); + if (hit_processor->showTeammateHits()) msg = "Teammate hits are sent to all players"; else msg = "Teammate hits are not sent"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_hitmsg // ======================================================================== @@ -3109,15 +3108,16 @@ void CommandManager::process_hitmsg_assign(Context& context) error(context); return; } + auto hit_processor = getHitProcessor(); if (argv[1] == "0") { - m_hit_processor->setShowTeammateHits(false); + hit_processor->setShowTeammateHits(false); msg = "Teammate hits will not be sent"; } else { - m_hit_processor->setShowTeammateHits(true); + hit_processor->setShowTeammateHits(true); msg = "Teammate hits will be sent to all players"; } - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); } // process_hitmsg_assign // ======================================================================== @@ -3130,11 +3130,12 @@ void CommandManager::process_teamhit(Context& context) error(context, true); return; } - if (m_hit_processor->isTeammateHitMode()) + auto hit_processor = getHitProcessor(); + if (hit_processor->isTeammateHitMode()) msg = "Teammate hits are punished"; else msg = "Teammate hits are not punished"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_teamhit // ======================================================================== @@ -3147,17 +3148,18 @@ void CommandManager::process_teamhit_assign(Context& context) error(context); return; } + auto hit_processor = getHitProcessor(); if (argv[1] == "0") { - m_hit_processor->setTeammateHitMode(false); + hit_processor->setTeammateHitMode(false); msg = "Teammate hits are not punished now"; } else { - m_hit_processor->setTeammateHitMode(true); + hit_processor->setTeammateHitMode(true); msg = "Teammate hits are punished now"; } - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); } // process_teamhit_assign // ======================================================================== @@ -3169,8 +3171,8 @@ void CommandManager::process_scoring(Context& context) error(context, true); return; } - std::string msg = m_lobby_settings->getScoringAsString(); - m_lobby->sendStringToPeer(msg, peer); + std::string msg = getSettings()->getScoringAsString(); + getLobby()->sendStringToPeer(msg, peer); } // process_scoring // ======================================================================== @@ -3186,15 +3188,15 @@ void CommandManager::process_scoring_assign(Context& context) } std::string cmd2; CommandManager::restoreCmdByArgv(cmd2, argv, ' ', '"', '"', '\\', 1); - if (m_lobby_settings->loadCustomScoring(cmd2)) + if (getSettings()->loadCustomScoring(cmd2)) { msg = "Scoring set to \"" + cmd2 + "\""; - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); } else { msg = "Scoring could not be parsed from \"" + cmd2 + "\""; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } } // process_scoring_assign // ======================================================================== @@ -3214,7 +3216,7 @@ void CommandManager::process_register(Context& context) if (online_id <= 0) { std::string msg = "Please join with a valid online STK account."; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } std::string ans = ""; @@ -3226,11 +3228,11 @@ void CommandManager::process_register(Context& context) } std::string message_ok = "Your registration request is being processed"; std::string message_wrong = "Sorry, an error occurred. Please try again."; - if (m_lobby->writeOnePlayerReport(peer, ServerConfig::m_register_table_name, + if (getLobby()->writeOnePlayerReport(peer, ServerConfig::m_register_table_name, ans)) - m_lobby->sendStringToPeer(message_ok, peer); + getLobby()->sendStringToPeer(message_ok, peer); else - m_lobby->sendStringToPeer(message_wrong, peer); + getLobby()->sendStringToPeer(message_wrong, peer); } // process_register // ======================================================================== @@ -3238,7 +3240,8 @@ void CommandManager::process_muteall(Context& context) { auto& argv = context.m_argv; auto peer = context.m_peer.lock(); - if (!peer || !m_tournament) + auto tournament = getTournament(); + if (!peer || !tournament) { error(context, true); return; @@ -3254,14 +3257,14 @@ void CommandManager::process_muteall(Context& context) else if (argv.size() >= 2 && argv[1] == "1") op = SWF_OP_ADD; - int status = m_tournament->editMuteall(peer_username, op); + int status = tournament->editMuteall(peer_username, op); std::string msg; if (status) msg = "You are now receiving messages only from players and referees"; else msg = "You are now receiving messages from spectators too"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_muteall // ======================================================================== @@ -3269,7 +3272,8 @@ void CommandManager::process_game(Context& context) { auto& argv = context.m_argv; auto peer = context.m_peer.lock(); - if (!peer || !m_tournament) + auto tournament = getTournament(); + if (!peer || !tournament) { error(context, true); return; @@ -3282,9 +3286,9 @@ void CommandManager::process_game(Context& context) int old_game_number; int old_duration; int old_addition; - m_tournament->getGameCmdInput(old_game_number, old_duration, old_addition); - int new_game_number = m_tournament->getNextGameNumber(); - int new_duration = m_tournament->getDefaultDuration(); // Was m_length for argv.size >= 2 + tournament->getGameCmdInput(old_game_number, old_duration, old_addition); + int new_game_number = tournament->getNextGameNumber(); + int new_duration = tournament->getDefaultDuration(); // Was m_length for argv.size >= 2 int new_addition = 0; if (1 < argv.size()) @@ -3301,7 +3305,7 @@ void CommandManager::process_game(Context& context) if (!bad && argv.size() >= 4 && !StringUtils::parseString(argv[3], &new_addition)) bad = true; - if (!bad && !m_tournament->isValidGameCmdInput(new_game_number, new_duration, new_addition)) + if (!bad && !tournament->isValidGameCmdInput(new_game_number, new_duration, new_addition)) { bad = true; } @@ -3311,32 +3315,32 @@ void CommandManager::process_game(Context& context) std::string msg = StringUtils::insertValues( "Please specify a correct number. " "Format: /game [number %d..%d] [length in minutes] [0..59 additional seconds]", - m_tournament->minGameNumber(), - m_tournament->maxGameNumber()); + tournament->minGameNumber(), + tournament->maxGameNumber()); // error(context) ? - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } } - m_tournament->setGameCmdInput(new_game_number, new_duration, new_addition); - m_lobby_settings->setFixedLapCount(new_duration); + tournament->setGameCmdInput(new_game_number, new_duration, new_addition); + getSettings()->setFixedLapCount(new_duration); - if (m_tournament->hasColorsSwapped(new_game_number) ^ m_tournament->hasColorsSwapped(old_game_number)) - m_lobby->changeColors(); + if (tournament->hasColorsSwapped(new_game_number) ^ tournament->hasColorsSwapped(old_game_number)) + getLobby()->changeColors(); - if (m_tournament->hasGoalsLimit(new_game_number) ^ m_tournament->hasGoalsLimit(old_game_number)) - m_lobby->changeLimitForTournament(m_tournament->hasGoalsLimit()); + if (tournament->hasGoalsLimit(new_game_number) ^ tournament->hasGoalsLimit(old_game_number)) + getLobby()->changeLimitForTournament(tournament->hasGoalsLimit()); std::string msg = StringUtils::insertValues( "Ready to start game %d for %d %s", new_game_number, new_duration, - (m_tournament->hasGoalsLimit() ? "goals" : "minutes")); + (tournament->hasGoalsLimit() ? "goals" : "minutes")); - if (!m_tournament->hasGoalsLimit() && new_addition > 0) + if (!tournament->hasGoalsLimit() && new_addition > 0) { msg += StringUtils::insertValues(" %d seconds", new_addition); - m_lobby_settings->setFixedLapCount(m_lobby_settings->getFixedLapCount() + 1); + getSettings()->setFixedLapCount(getSettings()->getFixedLapCount() + 1); } - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); Log::info("CommandManager", "SoccerMatchLog: Game number changed from %d to %d", old_game_number, new_game_number); } // process_game @@ -3346,7 +3350,8 @@ void CommandManager::process_role(Context& context) { auto& argv = context.m_argv; auto peer = context.m_peer.lock(); - if (!peer || !m_tournament) + auto tournament = getTournament(); + if (!peer || !tournament) { error(context, true); return; @@ -3383,72 +3388,72 @@ void CommandManager::process_role(Context& context) if (!username.empty()) { if (username[0] == '#') - changed_usernames = m_lobby_settings->getPlayersInCategory(username.substr(1)); + changed_usernames = getSettings()->getPlayersInCategory(username.substr(1)); else changed_usernames.insert(username); } for (const std::string& u: changed_usernames) { - m_tournament->eraseFromAllTournamentCategories(u, permanent); + tournament->eraseFromAllTournamentCategories(u, permanent); std::string role_changed = "The referee has updated your role - you are now %s"; std::shared_ptr player_peer = STKHost::get()->findPeerByName( StringUtils::utf8ToWide(u)); std::vector missing_assets; if (player_peer) - missing_assets = m_lobby_settings->getMissingAssets(player_peer); + missing_assets = getSettings()->getMissingAssets(player_peer); bool fail = false; switch (role_char) { case 'r': { fail = !missing_assets.empty(); - if (m_tournament->hasColorsSwapped()) + if (tournament->hasColorsSwapped()) { - m_tournament->setTeam(KART_TEAM_BLUE, u, permanent); + tournament->setTeam(KART_TEAM_BLUE, u, permanent); } else { - m_tournament->setTeam(KART_TEAM_RED, u, permanent); + tournament->setTeam(KART_TEAM_RED, u, permanent); } if (player_peer) { role_changed = StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char)); if (player_peer->hasPlayerProfiles()) - m_lobby->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_RED); - m_lobby->sendStringToPeer(role_changed, player_peer); + getLobby()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_RED); + getLobby()->sendStringToPeer(role_changed, player_peer); } break; } case 'b': { fail = !missing_assets.empty(); - if (m_tournament->hasColorsSwapped()) + if (tournament->hasColorsSwapped()) { - m_tournament->setTeam(KART_TEAM_RED, u, permanent); + tournament->setTeam(KART_TEAM_RED, u, permanent); } else { - m_tournament->setTeam(KART_TEAM_BLUE, u, permanent); + tournament->setTeam(KART_TEAM_BLUE, u, permanent); } if (player_peer) { role_changed = StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char)); if (player_peer->hasPlayerProfiles()) - m_lobby->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_BLUE); - m_lobby->sendStringToPeer(role_changed, player_peer); + getLobby()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_BLUE); + getLobby()->sendStringToPeer(role_changed, player_peer); } break; } case 'j': { fail = !missing_assets.empty(); - m_tournament->setReferee(u, permanent); + tournament->setReferee(u, permanent); if (player_peer) { role_changed = StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char)); if (player_peer->hasPlayerProfiles()) - m_lobby->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); - m_lobby->sendStringToPeer(role_changed, player_peer); + getLobby()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); + getLobby()->sendStringToPeer(role_changed, player_peer); } break; } @@ -3458,8 +3463,8 @@ void CommandManager::process_role(Context& context) { role_changed = StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char)); if (player_peer->hasPlayerProfiles()) - m_lobby->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); - m_lobby->sendStringToPeer(role_changed, player_peer); + getLobby()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); + getLobby()->sendStringToPeer(role_changed, player_peer); } break; } @@ -3484,15 +3489,15 @@ void CommandManager::process_role(Context& context) msg += " " + missing_assets[i]; } } - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } - m_lobby->updatePlayerList(); + getLobby()->updatePlayerList(); } // process_role // ======================================================================== void CommandManager::process_stop(Context& context) { - if (!m_tournament) + if (!getTournament()) { error(context, true); return; @@ -3503,14 +3508,14 @@ void CommandManager::process_stop(Context& context) SoccerWorld *sw = dynamic_cast(w); sw->stop(); std::string msg = "The game is stopped."; - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); Log::info("CommandManager", "SoccerMatchLog: The game is stopped"); } // process_stop // ======================================================================== void CommandManager::process_go(Context& context) { - if (!m_tournament) + if (!getTournament()) { error(context, true); return; @@ -3521,14 +3526,14 @@ void CommandManager::process_go(Context& context) SoccerWorld *sw = dynamic_cast(w); sw->resume(); std::string msg = "The game is resumed."; - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); Log::info("CommandManager", "SoccerMatchLog: The game is resumed"); } // process_go // ======================================================================== void CommandManager::process_lobby(Context& context) { - if (!m_tournament) + if (!getTournament()) { error(context, true); return; @@ -3539,7 +3544,7 @@ void CommandManager::process_lobby(Context& context) SoccerWorld *sw = dynamic_cast(w); sw->allToLobby(); std::string msg = "The game will be restarted."; - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); } // process_lobby // ======================================================================== @@ -3547,7 +3552,7 @@ void CommandManager::process_init(Context& context) { auto& argv = context.m_argv; auto peer = context.m_peer.lock(); - if (!peer || !m_tournament) + if (!peer || !getTournament()) { error(context, true); return; @@ -3570,7 +3575,7 @@ void CommandManager::process_init(Context& context) std::string msg = "Please set the count when the karts " "are ready. Setting the initial count in lobby is " "not implemented yet, sorry."; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } SoccerWorld *sw = dynamic_cast(w); @@ -3594,7 +3599,7 @@ void CommandManager::process_mimiz(Context& context) msg = "please provide text"; else msg = cmd.substr(argv[0].length() + 1); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_mimiz // ======================================================================== @@ -3605,7 +3610,7 @@ void CommandManager::process_test(Context& context) if (argv.size() == 1) { std::string msg = "/test is now deprecated. Use /test *2 [something] [something]"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } argv.resize(4, ""); @@ -3627,7 +3632,7 @@ void CommandManager::process_test(Context& context) } username = "{" + argv[1].substr(4) + "} " + username; std::string msg = username + ", " + argv[2] + ", " + argv[3]; - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); } // process_test // ======================================================================== @@ -3639,9 +3644,9 @@ void CommandManager::process_slots(Context& context) error(context, true); return; } - int current = m_lobby->m_current_max_players_in_game.load(); + int current = getLobby()->m_current_max_players_in_game.load(); std::string msg = "Number of slots is currently " + std::to_string(current); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_slots // ======================================================================== @@ -3651,7 +3656,7 @@ void CommandManager::process_slots_assign(Context& context) { std::string msg = "Changing slots is not possible in the singleplayer mode"; auto peer = context.m_peer.lock(); // may be nullptr, here we don't care - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return; } auto& argv = context.m_argv; @@ -3671,10 +3676,10 @@ void CommandManager::process_slots_assign(Context& context) vote(context, "slots", argv[1]); return; } - m_lobby->m_current_max_players_in_game.store((unsigned)number); - m_lobby->updatePlayerList(); + getLobby()->m_current_max_players_in_game.store((unsigned)number); + getLobby()->updatePlayerList(); std::string msg = "Number of playable slots is now " + argv[1]; - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); } // process_slots_assign // ======================================================================== @@ -3687,7 +3692,7 @@ void CommandManager::process_time(Context& context) return; } std::string msg = "Server time: " + StkTime::getLogTime(); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_time // ======================================================================== @@ -3713,7 +3718,7 @@ void CommandManager::process_result(Context& context) } else msg = "This command is not yet supported for this game mode"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_result // ======================================================================== @@ -3725,8 +3730,8 @@ void CommandManager::process_preserve(Context& context) error(context, true); return; } - std::string msg = m_lobby_settings->getPreservedSettingsAsString(); - m_lobby->sendStringToPeer(msg, peer); + std::string msg = getSettings()->getPreservedSettingsAsString(); + getLobby()->sendStringToPeer(msg, peer); } // process_preserve // ======================================================================== @@ -3749,31 +3754,32 @@ void CommandManager::process_preserve_assign(Context& context) { msg = StringUtils::insertValues( "'%s' isn't preserved on server reset anymore", argv[1].c_str()); - m_lobby_settings->eraseFromPreserved(argv[1]); + getSettings()->eraseFromPreserved(argv[1]); } else { msg = StringUtils::insertValues( "'%s' is now preserved on server reset", argv[1].c_str()); - m_lobby_settings->insertIntoPreserved(argv[1]); + getSettings()->insertIntoPreserved(argv[1]); } - m_lobby->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(msg); } // process_preserve_assign // ======================================================================== void CommandManager::process_history(Context& context) { auto peer = context.m_peer.lock(); - if (!peer || !m_tournament) + auto tournament = getTournament(); + if (!peer || !tournament) { error(context, true); return; } std::string msg = "Map history:"; - std::vector arenas = m_tournament->getMapHistory(); + std::vector arenas = tournament->getMapHistory(); for (unsigned i = 0; i < arenas.size(); i++) msg += StringUtils::insertValues(" [%d]: %s", i, arenas[i].c_str()); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_history // ======================================================================== @@ -3781,7 +3787,8 @@ void CommandManager::process_history_assign(Context& context) { auto& argv = context.m_argv; auto peer = context.m_peer.lock(); - if (!peer || !m_tournament) + auto tournament = getTournament(); + if (!peer || !tournament) { error(context, true); return; @@ -3802,14 +3809,14 @@ void CommandManager::process_history_assign(Context& context) 2, m_stf_all_maps, 3, false, false)) return; std::string id = argv[2]; - if (!m_tournament->assignToHistory(index, id)) + if (!tournament->assignToHistory(index, id)) { error(context); return; } msg = StringUtils::insertValues("Assigned [%d] to %s in the map history", index, id.c_str()); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_history_assign // ======================================================================== @@ -3822,8 +3829,8 @@ void CommandManager::process_voting(Context& context) return; } std::string msg = StringUtils::insertValues("Voting method: %d", - m_lobby->m_map_vote_handler->getAlgorithm()); - m_lobby->sendStringToPeer(msg, peer); + getMapVoteHandler()->getAlgorithm()); + getLobby()->sendStringToPeer(msg, peer); } // process_voting // ======================================================================== @@ -3848,9 +3855,9 @@ void CommandManager::process_voting_assign(Context& context) error(context); return; } - m_lobby->m_map_vote_handler->setAlgorithm(value); + getMapVoteHandler()->setAlgorithm(value); msg = StringUtils::insertValues("Set voting method to %s", value); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_voting_assign // ======================================================================== @@ -3890,8 +3897,8 @@ void CommandManager::process_why_hourglass(Context& context) error(context); return; } - auto it = m_lobby->m_why_peer_cannot_play.find(player_peer); - if (it == m_lobby->m_why_peer_cannot_play.end()) + auto it = getLobby()->m_why_peer_cannot_play.find(player_peer); + if (it == getLobby()->m_why_peer_cannot_play.end()) { response = "For some reason, server doesn't know about the hourglass status of this player."; } @@ -3944,7 +3951,7 @@ void CommandManager::process_why_hourglass(Context& context) } response = StringUtils::insertValues(response, player_name.c_str()); } - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); } // process_why_hourglass // ======================================================================== @@ -3957,8 +3964,8 @@ void CommandManager::process_available_teams(Context& context) return; } std::string msg = StringUtils::insertValues("Currently available teams: \"%s\"", - m_lobby_settings->getInternalAvailableTeams().c_str()); - m_lobby->sendStringToPeer(msg, peer); + getSettings()->getInternalAvailableTeams().c_str()); + getLobby()->sendStringToPeer(msg, peer); } // process_available_teams // ======================================================================== @@ -4001,12 +4008,12 @@ void CommandManager::process_available_teams_assign(Context& context) ignored.push_back(c); for (char c: value_set) value.push_back(c); - m_lobby_settings->setInternalAvailableTeams(value); + getSettings()->setInternalAvailableTeams(value); msg = StringUtils::insertValues("Set available teams to \"%s\"", value); if (!ignored.empty()) msg += StringUtils::insertValues( ", but teams \"%s\" were not recognized", ignored); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // process_available_teams_assign // ======================================================================== @@ -4032,7 +4039,7 @@ void CommandManager::special(Context& context) "If you believe that is a bug, please report it. Full input:\n" "/%s"; msg = StringUtils::insertValues(msg, command->getFullName(), cmd); - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); } // special // ======================================================================== @@ -4044,7 +4051,7 @@ bool CommandManager::assignRandomTeams(int intended_number, int player_number = 0; for (auto& p : STKHost::get()->getPeers()) { - if (!m_lobby->canRace(p)) + if (!getLobby()->canRace(p)) continue; if (p->alwaysSpectateButNotNeutral()) continue; @@ -4056,7 +4063,7 @@ bool CommandManager::assignRandomTeams(int intended_number, return false; } int max_number_of_teams = TeamUtils::getNumberOfTeams(); - std::string available_colors_string = m_lobby_settings->getAvailableTeams(); + std::string available_colors_string = getSettings()->getAvailableTeams(); if (available_colors_string.empty()) return false; if (max_number_of_teams > (int)available_colors_string.length()) @@ -4087,15 +4094,15 @@ bool CommandManager::assignRandomTeams(int intended_number, std::shuffle(profile_colors.begin(), profile_colors.end(), g); - m_lobby->clearTemporaryTeams(); + getLobby()->clearTemporaryTeams(); for (auto& p : STKHost::get()->getPeers()) { - if (!m_lobby->canRace(p)) + if (!getLobby()->canRace(p)) continue; if (p->alwaysSpectateButNotNeutral()) continue; for (auto& profile : p->getPlayerProfiles()) { - m_lobby->setTemporaryTeamInLobby(profile, profile_colors.back()); + getLobby()->setTemporaryTeamInLobby(profile, profile_colors.back()); if (profile_colors.size() > 1) // prevent crash just in case profile_colors.pop_back(); } @@ -4183,7 +4190,7 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, if (closest_commands.empty()) { std::string msg = "Command " + cmd + " not found"; - m_lobby->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(msg, peer); return true; } bool no_zeros = closest_commands[0].second != 0; @@ -4220,7 +4227,7 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, } argv[idx] = initial_argument; CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); - m_lobby->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(response, peer); return true; } @@ -4277,7 +4284,7 @@ void CommandManager::Command::changePermissions(int permissions, std::string CommandManager::getAddonPreferredType() const { - int mode = m_lobby->m_game_mode.load(); + int mode = getLobby()->m_game_mode.load(); if (0 <= mode && mode <= 4) return "track"; if (mode == 6) @@ -4290,17 +4297,18 @@ std::string CommandManager::getAddonPreferredType() const std::deque>& CommandManager::get_queue(int x) const { + auto queues = getQueues(); if (x == QM_MAP_ONETIME) - return m_lobby_queues->getOnetimeTracksQueue(); + return queues->getOnetimeTracksQueue(); if (x == QM_MAP_CYCLIC) - return m_lobby_queues->getCyclicTracksQueue(); + return queues->getCyclicTracksQueue(); if (x == QM_KART_ONETIME) - return m_lobby_queues->getOnetimeKartsQueue(); + return queues->getOnetimeKartsQueue(); if (x == QM_KART_CYCLIC) - return m_lobby_queues->getCyclicKartsQueue(); + return queues->getCyclicKartsQueue(); Log::error("CommandManager", "Unknown queue mask %d, revert to map onetime", x); - return m_lobby_queues->getOnetimeTracksQueue(); + return queues->getOnetimeTracksQueue(); } // get_queue // ======================================================================== diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index dcc519fdd52..f8bbd4d3015 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -41,22 +41,19 @@ #include "network/protocols/command_voting.hpp" #include "network/protocols/command_permissions.hpp" #include "utils/enum_extended_reader.hpp" +#include "utils/lobby_context.hpp" #include "utils/set_typo_fixer.hpp" #include "utils/team_utils.hpp" #include "utils/track_filter.hpp" #include "utils/types.hpp" -class ServerLobby; class Event; -class STKPeer; -class HitProcessor; -class LobbyAssetManager; -class Tournament; -class LobbyQueues; -class LobbySettings; class KartElimination; +class LobbySettings; +class ServerLobby; +class STKPeer; -class CommandManager +class CommandManager: public LobbyContextComponent { struct FileResource { @@ -201,15 +198,6 @@ class CommandManager private: - ServerLobby* m_lobby; - - std::shared_ptr m_hit_processor; - std::shared_ptr m_asset_manager; - std::shared_ptr m_tournament; - std::shared_ptr m_lobby_queues; - std::shared_ptr m_lobby_settings; - std::shared_ptr m_kart_elimination; - std::vector> m_all_commands; std::map> m_full_name_to_command; @@ -360,13 +348,12 @@ class CommandManager void special(Context& context); public: + CommandManager(LobbyContext* context): LobbyContextComponent(context) {} - CommandManager(ServerLobby* lobby = nullptr); + void setupContextUser() OVERRIDE; void handleCommand(Event* event, std::shared_ptr peer); - bool isInitialized() { return m_lobby != nullptr; } - template void addTextResponse(std::string key, T&& value) { m_text_response[key] = value; } diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 6bf50ec2b02..171c03cb73e 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -190,21 +190,10 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_current_max_players_in_game.store(ServerConfig::m_max_players_in_game); - m_kart_elimination = std::make_shared(); - m_lobby_queues = std::make_shared(); - m_asset_manager = std::make_shared(this); - if (ServerConfig::m_soccer_tournament) - m_tournament = std::make_shared(this, m_lobby_settings); - - m_lobby_settings = std::make_shared( - getGameSetup(), m_lobby_queues, m_kart_elimination, m_asset_manager, m_tournament - ); - - m_map_vote_handler = std::make_shared(m_lobby_settings); - m_hit_processor = std::make_shared(this, m_lobby_settings); - - - m_map_vote_handler->setAlgorithm(ServerConfig::m_map_vote_handling); + m_lobby_context = std::make_shared(this, (bool)ServerConfig::m_soccer_tournament); + m_lobby_context->setup(); + m_context = m_lobby_context.get(); + m_game_setup->setContext(m_context); m_current_ai_count.store(0); @@ -237,9 +226,6 @@ ServerLobby::ServerLobby() : LobbyProtocol() #endif m_game_info = {}; - - // Init CM later than all the above shared_ptrs - m_command_manager = std::make_shared(nullptr); } // ServerLobby //----------------------------------------------------------------------------- @@ -278,7 +264,7 @@ void ServerLobby::updateMapsForMode() { RaceManager::MinorRaceModeType m = ServerConfig::getLocalGameMode(m_game_mode.load()).first; - m_asset_manager->updateMapsForMode(m); + getAssetManager()->updateMapsForMode(m); } // updateMapsForMode //----------------------------------------------------------------------------- @@ -308,8 +294,8 @@ void ServerLobby::setup() ai->setKartName(""); StateManager::get()->resetActivePlayers(); - m_asset_manager->onServerSetup(); - NetworkConfig::get()->setTuxHitboxAddon(ServerConfig::m_live_players); + getAssetManager()->onServerSetup(); + getSettings()->onServerSetup(); updateMapsForMode(); m_server_has_loaded_world.store(false); @@ -354,7 +340,7 @@ bool ServerLobby::notifyEvent(Event* event) //----------------------------------------------------------------------------- void ServerLobby::handleChat(Event* event) { - if (!checkDataSize(event, 1) || !ServerConfig::m_chat) return; + if (!checkDataSize(event, 1) || !getSettings()->getChat()) return; // Update so that the peer is not kicked event->getPeer()->updateLastActivity(); @@ -364,15 +350,15 @@ void ServerLobby::handleChat(Event* event) int64_t elapsed_time = (int64_t)StkTime::getMonoTimeMs() - last_message; // Read ServerConfig for formula and details - if (ServerConfig::m_chat_consecutive_interval > 0 && - elapsed_time < ServerConfig::m_chat_consecutive_interval * 1000) + if (getSettings()->getChatConsecutiveInterval() > 0 && + elapsed_time < getSettings()->getChatConsecutiveInterval() * 1000) event->getPeer()->updateConsecutiveMessages(true); else event->getPeer()->updateConsecutiveMessages(false); - if (ServerConfig::m_chat_consecutive_interval > 0 && + if (getSettings()->getChatConsecutiveInterval() > 0 && event->getPeer()->getConsecutiveMessages() > - ServerConfig::m_chat_consecutive_interval / 2) + getSettings()->getChatConsecutiveInterval() / 2) { std::string msg = "Spam detected"; sendStringToPeer(msg, event->getPeerSP()); @@ -413,10 +399,10 @@ void ServerLobby::handleChat(Event* event) chat->setSynchronous(true); const bool game_started = m_state.load() != WAITING_FOR_START_GAME; std::shared_ptr sender = event->getPeerSP(); - auto can_receive = m_lobby_settings->getMessageReceiversFor(sender); + auto can_receive = getSettings()->getMessageReceiversFor(sender); if (!can_receive.empty()) message = StringUtils::utf32ToWide({0x1f512, 0x20}) + message; - bool team_speak = m_lobby_settings->isTeamSpeaker(sender); + bool team_speak = getSettings()->isTeamSpeaker(sender); team_speak &= ( RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER || RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG @@ -439,17 +425,17 @@ void ServerLobby::handleChat(Event* event) if (add_red_emoji) message = StringUtils::utf32ToWide({0x1f7e5, 0x20}) + message; bool tournament_limit = false; - if (m_tournament) - tournament_limit = !m_tournament->checkSenderInRefsOrPlayers(sender); + if (isTournament()) + tournament_limit = !getTournament()->checkSenderInRefsOrPlayers(sender); std::set sees_teamchats; - if (m_tournament) - sees_teamchats = m_tournament->getThoseWhoSeeTeamchats(); + if (isTournament()) + sees_teamchats = getTournament()->getThoseWhoSeeTeamchats(); // Note that mutealls are still spectators std::set important_players; - if (m_tournament && tournament_limit) + if (getTournament() && tournament_limit) { - important_players = m_tournament->getImportantChatPlayers(); + important_players = getTournament()->getImportantChatPlayers(); } chat->addUInt8(LE_CHAT).encodeString16(message); core::stringw sender_name = @@ -502,7 +488,7 @@ void ServerLobby::handleChat(Event* event) return false; } } - if (m_lobby_settings->isMuting(p, sender_name)) + if (getSettings()->isMuting(p, sender_name)) return false; if (team_speak) { @@ -539,7 +525,7 @@ void ServerLobby::handleChat(Event* event) //----------------------------------------------------------------------------- void ServerLobby::changeTeam(Event* event) { - if (!ServerConfig::m_team_choosing || + if (!getSettings()->getTeamChoosing() || !RaceManager::get()->teamEnabled()) return; if (!checkDataSize(event, 1)) return; @@ -547,7 +533,7 @@ void ServerLobby::changeTeam(Event* event) uint8_t local_id = data.getUInt8(); auto& player = event->getPeer()->getPlayerProfiles().at(local_id); auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); - if (m_tournament && !m_tournament->canChangeTeam()) + if (getTournament() && !getTournament()->canChangeTeam()) { Log::info("ServerLobby", "Team change requested by %s, but tournament forbids it.", player->getName().c_str()); return; @@ -561,13 +547,13 @@ void ServerLobby::changeTeam(Event* event) // At most 7 players on each team (for live join) if (player->getTeam() == KART_TEAM_BLUE) { - if (red_blue.first >= 7 && !ServerConfig::m_free_teams) + if (red_blue.first >= 7 && !getSettings()->getFreeTeams()) return; setTeamInLobby(player, KART_TEAM_RED); } else { - if (red_blue.second >= 7 && !ServerConfig::m_free_teams) + if (red_blue.second >= 7 && !getSettings()->getFreeTeams()) return; setTeamInLobby(player, KART_TEAM_BLUE); } @@ -579,7 +565,7 @@ void ServerLobby::kickHost(Event* event) { if (m_server_owner.lock() != event->getPeerSP()) return; - if (!ServerConfig::m_kicks_allowed) + if (!getSettings()->getKicksAllowed()) { std::string msg = "Kicking players is not allowed on this server"; auto crown = event->getPeerSP(); @@ -591,7 +577,7 @@ void ServerLobby::kickHost(Event* event) uint32_t host_id = data.getUInt32(); std::shared_ptr peer = STKHost::get()->findPeerByHostId(host_id); // Ignore kicking ai peer if ai handling is on - if (peer && (!ServerConfig::m_ai_handling || !peer->isAIPeer())) + if (peer && (!getSettings()->getAiHandling() || !peer->isAIPeer())) { if (peer->isAngryHost()) { @@ -612,7 +598,7 @@ void ServerLobby::kickHost(Event* event) Log::info("ServerLobby", "Crown player kicks %s", player_name.c_str()); } peer->kick(); - if (ServerConfig::m_track_kicks) + if (getSettings()->getTrackKicks()) { std::string auto_report = "[ Auto report caused by kick ]"; writeOwnReport(peer, event->getPeerSP(), auto_report); @@ -670,7 +656,7 @@ bool ServerLobby::notifyEventAsynchronous(Event* event) */ void ServerLobby::pollDatabase() { - if (!ServerConfig::m_sql_management || !m_db_connector->hasDatabase()) + if (!getSettings()->getSqlManagement() || !m_db_connector->hasDatabase()) return; if (!m_db_connector->isTimeToPoll()) @@ -811,7 +797,7 @@ void ServerLobby::asynchronousUpdate() m_rs_state.store(RS_NONE); } - m_lobby_settings->clearAllExpiredWeakPtrs(); + getSettings()->clearAllExpiredWeakPtrs(); #ifdef ENABLE_SQLITE3 pollDatabase(); @@ -820,7 +806,7 @@ void ServerLobby::asynchronousUpdate() // Check if server owner has left updateServerOwner(); - if (ServerConfig::m_ranked && m_state.load() == WAITING_FOR_START_GAME) + if (getSettings()->getRanked() && m_state.load() == WAITING_FOR_START_GAME) m_ranking->cleanup(); if (allowJoinedPlayersWaiting() /*|| (m_game_setup->isGrandPrix() && @@ -911,10 +897,10 @@ void ServerLobby::asynchronousUpdate() } case WAITING_FOR_START_GAME: { - if (ServerConfig::m_owner_less) + if (getSettings()->getOwnerLess()) { // Ensure that a game can auto-start if the server meets the config's starting limit or if it's already full. - int starting_limit = std::min((int)ServerConfig::m_min_start_game_players, (int)ServerConfig::m_server_max_players); + int starting_limit = std::min((int)getSettings()->getMinStartGamePlayers(), (int)getSettings()->getServerMaxPlayers()); unsigned current_max_players_in_game = m_current_max_players_in_game.load(); if (current_max_players_in_game > 0) // 0 here means it's not the limit starting_limit = std::min(starting_limit, (int)current_max_players_in_game); @@ -925,11 +911,11 @@ void ServerLobby::asynchronousUpdate() m_game_setup->isGrandPrixStarted()) && m_timeout.load() == std::numeric_limits::max()) { - if (ServerConfig::m_start_game_counter >= -1e-5) + if (getSettings()->getStartGameCounter() >= -1e-5) { m_timeout.store((int64_t)StkTime::getMonoTimeMs() + (int64_t) - (ServerConfig::m_start_game_counter * 1000.0f)); + (getSettings()->getStartGameCounter() * 1000.0f)); } else { @@ -945,7 +931,7 @@ void ServerLobby::asynchronousUpdate() m_timeout.store(std::numeric_limits::max()); } bool forbid_starting = false; - if (m_tournament && m_tournament->forbidStarting()) + if (getTournament() && getTournament()->forbidStarting()) forbid_starting = true; bool timer_finished = (!forbid_starting && m_timeout.load() < (int64_t)StkTime::getMonoTimeMs()); @@ -982,7 +968,7 @@ void ServerLobby::asynchronousUpdate() unsigned player_in_game = 0; STKHost::get()->updatePlayers(&player_in_game); // Reset lobby will be done in main thread - if ((player_in_game == 1 && ServerConfig::m_ranked) || + if ((player_in_game == 1 && getSettings()->getRanked()) || player_in_game == 0) { resetVotingTime(); @@ -993,7 +979,7 @@ void ServerLobby::asynchronousUpdate() if (m_server_has_loaded_world.load() == false) return; if (!checkPeersReady( - ServerConfig::m_ai_handling && m_ai_count == 0/*ignore_ai_peer*/, LOADING_WORLD)) + getSettings()->getAiHandling() && m_ai_count == 0/*ignore_ai_peer*/, LOADING_WORLD)) return; // Reset for next state usage resetPeersReady(); @@ -1006,7 +992,7 @@ void ServerLobby::asynchronousUpdate() return; unsigned player_in_game = 0; STKHost::get()->updatePlayers(&player_in_game); - if ((player_in_game == 1 && ServerConfig::m_ranked) || + if ((player_in_game == 1 && getSettings()->getRanked()) || player_in_game == 0) { resetVotingTime(); @@ -1014,40 +1000,40 @@ void ServerLobby::asynchronousUpdate() } PeerVote winner_vote; - m_lobby_settings->resetWinnerPeerId(); + getSettings()->resetWinnerPeerId(); bool go_on_race = false; - if (ServerConfig::m_track_voting) + if (getSettings()->getTrackVoting()) go_on_race = handleAllVotes(&winner_vote); else if (/*m_game_setup->isGrandPrixStarted() || */isVotingOver()) { - winner_vote = m_lobby_settings->getDefaultVote(); + winner_vote = getSettings()->getDefaultVote(); go_on_race = true; } if (go_on_race) { - if (m_lobby_settings->hasFixedLapCount()) + if (getSettings()->hasFixedLapCount()) { - winner_vote.m_num_laps = m_lobby_settings->getFixedLapCount(); - Log::info("ServerLobby", "Enforcing %d lap race", m_lobby_settings->getFixedLapCount()); + winner_vote.m_num_laps = getSettings()->getFixedLapCount(); + Log::info("ServerLobby", "Enforcing %d lap race", getSettings()->getFixedLapCount()); } - if (m_lobby_settings->hasFixedDirection()) + if (getSettings()->hasFixedDirection()) { - winner_vote.m_reverse = (m_lobby_settings->getDirection() == 1); - Log::info("ServerLobby", "Enforcing direction %d", (int)m_lobby_settings->getDirection()); + winner_vote.m_reverse = (getSettings()->getDirection() == 1); + Log::info("ServerLobby", "Enforcing direction %d", (int)getSettings()->getDirection()); } - m_lobby_settings->setDefaultVote(winner_vote); + getSettings()->setDefaultVote(winner_vote); m_item_seed = (uint32_t)StkTime::getTimeSinceEpoch(); ItemManager::updateRandomSeed(m_item_seed); float extra_seconds = 0.0f; - if (m_tournament) - extra_seconds = m_tournament->getExtraSeconds(); + if (isTournament()) + extra_seconds = getTournament()->getExtraSeconds(); m_game_setup->setRace(winner_vote, extra_seconds); // For spectators that don't have the track, remember their // spectate mode and don't load the track std::string track_name = winner_vote.m_track_name; - if (m_tournament) - m_tournament->fillNextArena(track_name); + if (isTournament()) + getTournament()->fillNextArena(track_name); auto peers = STKHost::get()->getPeers(); std::map, @@ -1088,7 +1074,7 @@ void ServerLobby::asynchronousUpdate() m_ai_profiles.end()); } } - m_game_setup->sortPlayersForGrandPrix(players, m_lobby_settings->isGPGridShuffled()); + m_game_setup->sortPlayersForGrandPrix(players, getSettings()->isGPGridShuffled()); m_game_setup->sortPlayersForGame(players); for (unsigned i = 0; i < players.size(); i++) { @@ -1114,7 +1100,7 @@ void ServerLobby::asynchronousUpdate() std::string current_kart = players[i]->getKartName(); if (!players[i]->getPeer().get()) continue; - if (m_lobby_queues->areKartFiltersIgnoringKarts()) + if (getQueues()->areKartFiltersIgnoringKarts()) current_kart = ""; std::string name = StringUtils::wideToUtf8(players[i]->getName()); // Note 1: setKartName also resets KartData, and should be called @@ -1138,17 +1124,18 @@ void ServerLobby::asynchronousUpdate() NetworkString* load_world_message = getLoadWorldMessage(players, false/*live_join*/); - m_game_setup->setHitCaptureTime(m_lobby_settings->getBattleHitCaptureLimit(), - m_lobby_settings->getBattleTimeLimit()); + m_game_setup->setHitCaptureTime(getSettings()->getBattleHitCaptureLimit(), + getSettings()->getBattleTimeLimit()); uint16_t flag_return_time = (uint16_t)stk_config->time2Ticks( - ServerConfig::m_flag_return_timeout); + getSettings()->getFlagReturnTimeout()); + RaceManager::get()->setHitProcessor(getHitProcessor()); RaceManager::get()->setFlagReturnTicks(flag_return_time); - if (ServerConfig::m_record_replays && m_lobby_settings->hasConsentOnReplays() && + if (getSettings()->getRecordReplays() && getSettings()->hasConsentOnReplays() && (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL || RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE)) RaceManager::get()->setRecordRace(true); uint16_t flag_deactivated_time = (uint16_t)stk_config->time2Ticks( - ServerConfig::m_flag_deactivated_time); + getSettings()->getFlagDeactivatedTime()); RaceManager::get()->setFlagDeactivatedTicks(flag_deactivated_time); configRemoteKart(players, 0); @@ -1230,19 +1217,19 @@ NetworkString* ServerLobby::getLoadWorldMessage( NetworkString* load_world_message = getNetworkString(); load_world_message->setSynchronous(true); load_world_message->addUInt8(LE_LOAD_WORLD); - m_lobby_settings->encodeDefaultVote(load_world_message); + getSettings()->encodeDefaultVote(load_world_message); load_world_message->addUInt8(live_join ? 1 : 0); encodePlayers(load_world_message, players); load_world_message->addUInt32(m_item_seed); if (RaceManager::get()->isBattleMode()) { - load_world_message->addUInt32(m_lobby_settings->getBattleHitCaptureLimit()) - .addFloat(m_lobby_settings->getBattleTimeLimit()); + load_world_message->addUInt32(getSettings()->getBattleHitCaptureLimit()) + .addFloat(getSettings()->getBattleTimeLimit()); uint16_t flag_return_time = (uint16_t)stk_config->time2Ticks( - ServerConfig::m_flag_return_timeout); + getSettings()->getFlagReturnTimeout()); load_world_message->addUInt16(flag_return_time); uint16_t flag_deactivated_time = (uint16_t)stk_config->time2Ticks( - ServerConfig::m_flag_deactivated_time); + getSettings()->getFlagDeactivatedTime()); load_world_message->addUInt16(flag_deactivated_time); } for (unsigned i = 0; i < players.size(); i++) @@ -1255,7 +1242,7 @@ NetworkString* ServerLobby::getLoadWorldMessage( */ bool ServerLobby::canLiveJoinNow() const { - bool live_join = ServerConfig::m_live_players && worldIsActive(); + bool live_join = getSettings()->isLivePlayers() && worldIsActive(); if (!live_join) return false; if (RaceManager::get()->modeHasLaps()) @@ -1420,7 +1407,7 @@ int ServerLobby::getReservedId(std::shared_ptr& p, rki.copyFrom(p, local_id); return i; } - if (ServerConfig::m_team_choosing) + if (getSettings()->getTeamChoosing()) { if ((p->getTeam() == KART_TEAM_RED && rki.getKartTeam() == KART_TEAM_RED) || @@ -1529,7 +1516,7 @@ void ServerLobby::finishedLoadingLiveJoinClient(Event* event) } if (RaceManager::get()->isBattleMode()) { - if (ServerConfig::m_preserve_battle_scores) + if (getSettings()->getPreserveBattleScores()) points = m_game_info->m_saved_ffa_points[name]; info.m_result -= points; } @@ -1597,7 +1584,7 @@ void ServerLobby::update(int ticks) bool world_started = m_state.load() >= WAIT_FOR_WORLD_LOADED && m_state.load() <= RACING && m_server_has_loaded_world.load(); bool all_players_in_world_disconnected = (w != NULL && world_started); - int sec = ServerConfig::m_kick_idle_player_seconds; + int sec = getSettings()->getKickIdlePlayerSeconds(); if (world_started) { for (unsigned i = 0; i < RaceManager::get()->getNumPlayers(); i++) @@ -1642,7 +1629,7 @@ void ServerLobby::update(int ticks) StringUtils::wideToUtf8(rki.getPlayerName()).c_str(), sec); peer->kick(); } - if (m_hit_processor->isAntiTrollActive() && !peer->isAIPeer()) + if (getHitProcessor()->isAntiTrollActive() && !peer->isAIPeer()) { // for all human players // if they troll, kick them @@ -1655,7 +1642,7 @@ void ServerLobby::update(int ticks) break; case 1: { - std::string msg = ServerConfig::m_troll_warn_msg; + std::string msg = getSettings()->getTrollWarnMsg(); sendStringToPeer(msg, peer); std::string player_name = StringUtils::wideToUtf8(peer->getPlayerProfiles()[0]->getName()); Log::info("ServerLobby-AntiTroll", "Sent WARNING to %s", player_name.c_str()); @@ -1675,7 +1662,7 @@ void ServerLobby::update(int ticks) } } if (m_state.load() == WAITING_FOR_START_GAME) { - sec = ServerConfig::m_kick_idle_lobby_player_seconds; + sec = getSettings()->getKickIdleLobbyPlayerSeconds(); auto peers = STKHost::get()->getPeers(); for (auto peer: peers) { @@ -1766,7 +1753,7 @@ void ServerLobby::update(int ticks) return; // Reset for ranked server if in kart / track selection has only 1 player - if (ServerConfig::m_ranked && + if (getSettings()->getRanked() && m_state.load() == SELECTING && STKHost::get()->getPlayersInGame() == 1) { @@ -1803,7 +1790,7 @@ void ServerLobby::update(int ticks) Log::info("ServerLobby", "Starting the race loading."); // This will create the world instance, i.e. load track and karts loadWorld(); - m_lobby_settings->updateWorldSettings(m_game_info); + getSettings()->updateWorldSettings(m_game_info); m_state = WAIT_FOR_WORLD_LOADED; break; case RACING: @@ -1867,12 +1854,12 @@ void ServerLobby::registerServer(bool first_time) request->addParameter("private_port", STKHost::get()->getPrivatePort() ); request->addParameter("name", m_game_setup->getServerNameUtf8()); - request->addParameter("max_players", ServerConfig::m_server_max_players); + request->addParameter("max_players", getSettings()->getServerMaxPlayers()); int difficulty = m_difficulty.load(); request->addParameter("difficulty", difficulty); int game_mode = m_game_mode.load(); request->addParameter("game_mode", game_mode); - const std::string& pw = ServerConfig::m_private_server_password; + const std::string& pw = getSettings()->getPrivateServerPassword(); request->addParameter("password", (unsigned)(!pw.empty())); request->addParameter("version", (unsigned)ServerConfig::m_server_version); @@ -1945,16 +1932,16 @@ void ServerLobby::startSelection(const Event *event) m_state.load()); return; } - if (ServerConfig::m_sleeping_server) + if (getSettings()->getSleepingServer()) { Log::warn("ServerLobby", "An attempt to start a race on a sleeping server."); return; } auto peer = event->getPeerSP(); - if (ServerConfig::m_owner_less) + if (getSettings()->getOwnerLess()) { - if (!m_lobby_settings->isAllowedToStart()) + if (!getSettings()->isAllowedToStart()) { std::string msg = "Starting the game is forbidden by server owner"; sendStringToPeer(msg, peer); @@ -1974,7 +1961,7 @@ void ServerLobby::startSelection(const Event *event) return; } } - if (!m_lobby_settings->isAllowedToStart()) + if (!getSettings()->isAllowedToStart()) { std::string msg = "Starting the game is forbidden by server owner"; sendStringToPeer(msg, peer); @@ -1991,15 +1978,15 @@ void ServerLobby::startSelection(const Event *event) } } } else { - if (!m_lobby_settings->isAllowedToStart()) + if (!getSettings()->isAllowedToStart()) { // Produce no log spam return; } } - if (!ServerConfig::m_owner_less && ServerConfig::m_team_choosing && - !ServerConfig::m_free_teams && RaceManager::get()->teamEnabled()) + if (!getSettings()->getOwnerLess() && getSettings()->getTeamChoosing() && + !getSettings()->getFreeTeams() && RaceManager::get()->teamEnabled()) { auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); if ((red_blue.first == 0 || red_blue.second == 0) && @@ -2094,7 +2081,7 @@ void ServerLobby::startSelection(const Event *event) peer->setWaitingForGame(true); } - m_asset_manager->eraseAssetsWithPeers(erasingPeers); + getAssetManager()->eraseAssetsWithPeers(erasingPeers); max_player = 0; STKHost::get()->updatePlayers(&max_player); @@ -2121,13 +2108,13 @@ void ServerLobby::startSelection(const Event *event) else m_ai_count = 0; - if (!m_asset_manager->tryApplyingMapFilters()) + if (!getAssetManager()->tryApplyingMapFilters()) { Log::error("ServerLobby", "No tracks for playing!"); return; } - m_lobby_settings->initializeDefaultVote(); + getSettings()->initializeDefaultVote(); if (!allowJoinedPlayersWaiting()) { @@ -2139,7 +2126,7 @@ void ServerLobby::startSelection(const Event *event) } } - startVotingPeriod(ServerConfig::m_voting_timeout); + startVotingPeriod(getSettings()->getVotingTimeout()); std::string ignored_choice_string = "The server will ignore your kart choice"; @@ -2156,10 +2143,10 @@ void ServerLobby::startSelection(const Event *event) // a new screen, which must be done from the main thread. ns->setSynchronous(true); ns->addUInt8(LE_START_SELECTION) - .addFloat(ServerConfig::m_voting_timeout) + .addFloat(getSettings()->getVotingTimeout()) .addUInt8(/*m_game_setup->isGrandPrixStarted() ? 1 : */0) - .addUInt8((!m_lobby_settings->hasNoLapRestrictions() ? 1 : 0)) - .addUInt8(ServerConfig::m_track_voting ? 1 : 0); + .addUInt8((!getSettings()->hasNoLapRestrictions() ? 1 : 0)) + .addUInt8(getSettings()->getTrackVoting() ? 1 : 0); std::set all_k = peer->getClientAssets().first; @@ -2167,20 +2154,20 @@ void ServerLobby::startSelection(const Event *event) // std::string username = StringUtils::wideToUtf8(profile->getName()); applyAllKartFilters(username, all_k); - if (!m_kart_elimination->getRemainingParticipants().empty() && m_kart_elimination->getRemainingParticipants().count(username) == 0) + if (!getKartElimination()->getRemainingParticipants().empty() && getKartElimination()->getRemainingParticipants().count(username) == 0) { - if (all_k.count(m_kart_elimination->getKart())) - all_k = {m_kart_elimination->getKart()}; + if (all_k.count(getKartElimination()->getKart())) + all_k = {getKartElimination()->getKart()}; else all_k = {}; } - m_asset_manager->encodePlayerKartsAndCommonMaps(ns, all_k); + getAssetManager()->encodePlayerKartsAndCommonMaps(ns, all_k); peer->sendPacket(ns, PRM_RELIABLE); delete ns; - if (m_lobby_queues->areKartFiltersIgnoringKarts()) + if (getQueues()->areKartFiltersIgnoringKarts()) sendStringToPeer(ignored_choice_string, peer); } @@ -2240,7 +2227,7 @@ void ServerLobby::checkIncomingConnectionRequests() // Keep the port open, it can be sent to anywhere as we will send to the // correct peer later in ConnectToPeer. - if (ServerConfig::m_firewalled_server) + if (getSettings()->getFirewalledServer()) { BareNetworkString data; data.addUInt8(0); @@ -2285,8 +2272,8 @@ void ServerLobby::checkRaceFinished() assert(World::getWorld()); if (!RaceEventManager::get()->isRaceOver()) return; - if (m_tournament) - m_tournament->onRaceFinished(); + if (isTournament()) + getTournament()->onRaceFinished(); if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) @@ -2295,6 +2282,7 @@ void ServerLobby::checkRaceFinished() Log::info("ServerLobby", "The game is considered finished."); // notify the network world that it is stopped RaceEventManager::get()->stop(); + RaceManager::get()->resetHitProcessor(); // stop race protocols before going back to lobby (end race) RaceEventManager::get()->getProtocol()->requestTerminate(); @@ -2354,7 +2342,7 @@ void ServerLobby::checkRaceFinished() gp_changes.back() += points_fl; cur_score += points_fl; } - int team = m_lobby_settings->getTeamForUsername(username); + int team = getSettings()->getTeamForUsername(username); if (team > 0) { m_gp_team_scores[team].score += cur_score; @@ -2385,25 +2373,25 @@ void ServerLobby::checkRaceFinished() } uint8_t ranking_changes_indication = 0; - if (ServerConfig::m_ranked && RaceManager::get()->modeHasLaps()) + if (getSettings()->getRanked() && RaceManager::get()->modeHasLaps()) ranking_changes_indication = 1; if (m_game_setup->isGrandPrix()) ranking_changes_indication = 1; m_result_ns->addUInt8(ranking_changes_indication); - if (m_kart_elimination->isEnabled()) + if (getKartElimination()->isEnabled()) { // ServerLobby's function because we need to take // the list of players from somewhere updateGnuElimination(); } - if (ServerConfig::m_store_results) + if (getSettings()->getStoreResults()) { storeResults(); } - if (ServerConfig::m_ranked) + if (getSettings()->getRanked()) { computeNewRankings(); submitRankingsToAddons(); @@ -2421,7 +2409,7 @@ void ServerLobby::checkRaceFinished() m_map_history.push_back(RaceManager::get()->getTrackName()); - m_lobby_queues->popOnRaceFinished(); + getQueues()->popOnRaceFinished(); } // checkRaceFinished //----------------------------------------------------------------------------- @@ -2486,7 +2474,7 @@ void ServerLobby::clientDisconnected(Event* event) World* w = World::getWorld(); std::shared_ptr peer = event->getPeerSP(); - m_lobby_settings->onPeerDisconnect(peer); + getSettings()->onPeerDisconnect(peer); // No warnings otherwise, as it could happen during lobby period if (w && m_game_info) saveDisconnectingPeerInfo(peer); @@ -2570,7 +2558,7 @@ bool ServerLobby::handleAssets(const NetworkString& ns, std::shared_ptr client_tracks.insert(track); } - if (!m_asset_manager->handleAssetsForPeer(peer, client_karts, client_tracks)) + if (!getAssetManager()->handleAssetsForPeer(peer, client_karts, client_tracks)) { if (peer->isValidated()) { @@ -2585,7 +2573,7 @@ bool ServerLobby::handleAssets(const NetworkString& ns, std::shared_ptr message->addUInt8(LE_CONNECTION_REFUSED) .addUInt8(RR_INCOMPATIBLE_DATA); - std::string advice = ServerConfig::m_incompatible_advice; + std::string advice = getSettings()->getIncompatibleAdvice(); if (!advice.empty()) { NetworkString *incompatible_reason = getNetworkString(); incompatible_reason->addUInt8(LE_CHAT); @@ -2608,7 +2596,7 @@ bool ServerLobby::handleAssets(const NetworkString& ns, std::shared_ptr } - std::array addons_scores = m_asset_manager->getAddonScores(client_karts, client_tracks); + std::array addons_scores = getAssetManager()->getAddonScores(client_karts, client_tracks); // Save available karts and tracks from clients in STKPeer so if this peer // disconnects later in lobby it won't affect current players @@ -2619,12 +2607,12 @@ bool ServerLobby::handleAssets(const NetworkString& ns, std::shared_ptr peer->getHostId() == m_client_server_host_id.load()) { // Update child process addons list too so player can choose later - m_asset_manager->updateAddons(); + getAssetManager()->updateAddons(); updateMapsForMode(); } - if (m_tournament) - m_tournament->updateTournamentRole(peer); + if (isTournament()) + getTournament()->updateTournamentRole(peer); updatePlayerList(); return true; } // handleAssets @@ -2709,7 +2697,7 @@ void ServerLobby::connectionRequested(Event* event) unsigned total_players = 0; STKHost::get()->updatePlayers(NULL, NULL, &total_players); if (total_players + player_count + m_ai_profiles.size() > - (unsigned)ServerConfig::m_server_max_players) + (unsigned)getSettings()->getServerMaxPlayers()) { NetworkString *message = getNetworkString(2); message->setSynchronous(true); @@ -2734,12 +2722,12 @@ void ServerLobby::connectionRequested(Event* event) !(peer->getAddress().isPublicAddressLocalhost() || peer->getAddress().isLAN()) && NetworkConfig::get()->isWAN() && - ServerConfig::m_validating_player) || - (ServerConfig::m_strict_players && + getSettings()->getValidatingPlayer()) || + (getSettings()->getStrictPlayers() && (player_count != 1 || online_id == 0 || duplicated_ranked_player)) || - (peer->isAIPeer() && !peer->getAddress().isLAN() &&!ServerConfig::m_ai_anywhere) || + (peer->isAIPeer() && !peer->getAddress().isLAN() && !getSettings()->canConnectAiAnywhere()) || (peer->isAIPeer() && - ServerConfig::m_ai_handling && !m_ai_peer.expired())) + getSettings()->getAiHandling() && !m_ai_peer.expired())) { NetworkString* message = getNetworkString(2); message->setSynchronous(true); @@ -2751,7 +2739,7 @@ void ServerLobby::connectionRequested(Event* event) return; } - if (ServerConfig::m_ai_handling && peer->isAIPeer()) + if (getSettings()->getAiHandling() && peer->isAIPeer()) m_ai_peer = peer; if (encrypted_size != 0) @@ -2780,7 +2768,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, // Check for password std::string password; data.decodeString(&password); - const std::string& server_pw = ServerConfig::m_private_server_password; + const std::string& server_pw = getSettings()->getPrivateServerPassword(); if (online_id > 0) { std::string username = StringUtils::wideToUtf8(online_name); @@ -2798,7 +2786,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, Log::verbose("ServerLobby", "Player refused: invalid player"); return; } - if (m_lobby_settings->isInWhitelist(username)) + if (getSettings()->isInWhitelist(username)) password = server_pw; } if (password != server_pw) @@ -2823,7 +2811,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, { STKHost::get()->updatePlayers(NULL, NULL, &total_players); if (total_players + player_count > - (unsigned)ServerConfig::m_server_max_players) + (unsigned)getSettings()->getServerMaxPlayers()) { NetworkString *message = getNetworkString(2); message->setSynchronous(true); @@ -2840,7 +2828,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, STKHost::get()->getAllPlayerOnlineIds(); bool duplicated_ranked_player = all_online_ids.find(online_id) != all_online_ids.end(); - if (ServerConfig::m_ranked && duplicated_ranked_player) + if (getSettings()->getRanked() && duplicated_ranked_player) { NetworkString* message = getNetworkString(2); message->setSynchronous(true); @@ -2887,13 +2875,13 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, std::string username = StringUtils::wideToUtf8(player->getName()); // kimden: I'm not sure why the check is double - if (m_lobby_settings->hasTeam(username)) - previous_team = m_lobby_settings->getTeamForUsername(username); + if (getSettings()->hasTeam(username)) + previous_team = getSettings()->getTeamForUsername(username); bool can_change_teams = true; - if (m_tournament && !m_tournament->canChangeTeam()) + if (getTournament() && !getTournament()->canChangeTeam()) can_change_teams = false; - if (ServerConfig::m_team_choosing && can_change_teams) + if (getSettings()->getTeamChoosing() && can_change_teams) { KartTeam cur_team = KART_TEAM_NONE; @@ -2913,9 +2901,9 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, if (cur_team != KART_TEAM_NONE) setTeamInLobby(player, cur_team); } - if (m_tournament) + if (isTournament()) { - KartTeam team = m_tournament->getTeam(utf8_online_name); + KartTeam team = getTournament()->getTeam(utf8_online_name); if (team != KART_TEAM_NONE) setTeamInLobby(player, team); } @@ -2974,8 +2962,8 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, message_ack->encodeString(cap); message_ack->addFloat(auto_start_timer) - .addUInt32(ServerConfig::m_state_frequency) - .addUInt8(ServerConfig::m_chat ? 1 : 0) + .addUInt32(getSettings()->getStateFrequency()) + .addUInt8(getSettings()->getChat() ? 1 : 0) .addUInt8(playerReportsTableExists() ? 1 : 0); peer->setSpectator(false); @@ -2984,7 +2972,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, if (m_ai_profiles.empty() && peer->getAddress().isLoopback()) { unsigned ai_add = NetworkConfig::get()->getNumFixedAI(); - unsigned max_players = ServerConfig::m_server_max_players; + unsigned max_players = getSettings()->getServerMaxPlayers(); // We need to reserve at least 1 slot for new player if (player_count + ai_add + 1 > max_players) { @@ -3019,7 +3007,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, { peer->setWaitingForGame(false); m_peers_ready[peer] = false; - if (!ServerConfig::m_sql_management) + if (!getSettings()->getSqlManagement()) { for (std::shared_ptr& npp : peer->getPlayerProfiles()) @@ -3035,7 +3023,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, peer->sendPacket(message_ack); delete message_ack; - if (ServerConfig::m_ranked) + if (getSettings()->getRanked()) { getRankingForPlayer(peer->getPlayerProfiles()[0]); } @@ -3044,14 +3032,14 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, #ifdef ENABLE_SQLITE3 m_db_connector->onPlayerJoinQueries(peer, online_id, player_count, country_code); #endif - if (m_kart_elimination->isEnabled()) + if (getKartElimination()->isEnabled()) { bool hasEliminatedPlayer = false; for (unsigned i = 0; i < peer->getPlayerProfiles().size(); ++i) { std::string name = StringUtils::wideToUtf8( peer->getPlayerProfiles()[i]->getName()); - if (m_kart_elimination->isEliminated(name)) + if (getKartElimination()->isEliminated(name)) { hasEliminatedPlayer = true; break; @@ -3060,15 +3048,15 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); - std::string warning = m_kart_elimination->getWarningMessage(hasEliminatedPlayer); + std::string warning = getKartElimination()->getWarningMessage(hasEliminatedPlayer); chat->encodeString16(StringUtils::utf8ToWide(warning)); peer->sendPacket(chat, PRM_RELIABLE); delete chat; } - if (ServerConfig::m_record_replays) + if (getSettings()->getRecordReplays()) { std::string msg; - if (m_lobby_settings->hasConsentOnReplays()) + if (getSettings()->hasConsentOnReplays()) msg = "Recording ghost replays is enabled. " "The crowned player can change that " "using /replay 0 (to disable) or /replay 1 (to enable). " @@ -3081,8 +3069,8 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, } getMessagesFromHost(peer, online_id); - if (m_tournament) - m_tournament->updateTournamentRole(peer); + if (isTournament()) + getTournament()->updateTournamentRole(peer); } // handleUnencryptedConnection //----------------------------------------------------------------------------- @@ -3166,7 +3154,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) std::string os_type_str = version_os.second; std::string utf8_profile_name = StringUtils::wideToUtf8(profile_name); // Add a Mobile emoji for mobile OS - if (ServerConfig::m_expose_mobile && + if (getSettings()->getExposeMobile() && (os_type_str == "iOS" || os_type_str == "Android")) profile_name = StringUtils::utf32ToWide({0x1F4F1}) + profile_name; @@ -3179,7 +3167,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) profile_name = StringUtils::utf32ToWide({0x1F528}) + profile_name; std::string prefix = ""; - for (const std::string& category: m_lobby_settings->getVisibleCategoriesForPlayer(utf8_profile_name)) + for (const std::string& category: getSettings()->getVisibleCategoriesForPlayer(utf8_profile_name)) { prefix += category + ", "; } @@ -3209,7 +3197,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) boolean_combine |= (1 << 1); if (p && m_server_owner_id.load() == p->getHostId()) boolean_combine |= (1 << 2); - if (ServerConfig::m_owner_less && !game_started && + if (getSettings()->getOwnerLess() && !game_started && m_peers_ready.find(p) != m_peers_ready.end() && m_peers_ready.at(p)) boolean_combine |= (1 << 3); @@ -3217,7 +3205,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) boolean_combine |= (1 << 4); pl->addUInt8(boolean_combine); pl->addUInt8(profile->getHandicap()); - if (ServerConfig::m_team_choosing) + if (getSettings()->getTeamChoosing()) pl->addUInt8(profile->getTeam()); else pl->addUInt8(KART_TEAM_NONE); @@ -3242,7 +3230,7 @@ void ServerLobby::updateServerOwner(bool force) { if (m_state.load() < WAITING_FOR_START_GAME || m_state.load() > RESULT_DISPLAY || - ServerConfig::m_owner_less) + getSettings()->getOwnerLess()) return; if (!force && !m_server_owner.expired()) return; @@ -3315,7 +3303,7 @@ void ServerLobby::kartSelectionRequested(Event* event) */ void ServerLobby::handlePlayerVote(Event* event) { - if (m_state != SELECTING || !ServerConfig::m_track_voting) + if (m_state != SELECTING || !getSettings()->getTrackVoting()) { Log::warn("ServerLobby", "Received track vote while in state %d.", m_state.load()); @@ -3341,19 +3329,19 @@ void ServerLobby::handlePlayerVote(Event* event) Track* t = TrackManager::get()->getTrack(vote.m_track_name); if (!t) { - vote.m_track_name = m_asset_manager->getAnyMapForVote(); + vote.m_track_name = getAssetManager()->getAnyMapForVote(); t = TrackManager::get()->getTrack(vote.m_track_name); assert(t); } // Remove / adjust any invalid settings - if (m_tournament) + if (isTournament()) { - m_tournament->applyRestrictionsOnVote(&vote); + getTournament()->applyRestrictionsOnVote(&vote); } else { - m_lobby_settings->applyRestrictionsOnVote(&vote, t); + getSettings()->applyRestrictionsOnVote(&vote, t); } // Store vote: @@ -3404,7 +3392,7 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote) cur_players++; } - return m_map_vote_handler->handleAllVotes( + return getMapVoteHandler()->handleAllVotes( m_peers_votes, getRemainingVotingTime(), getMaxVotingTime(), @@ -3422,20 +3410,20 @@ void ServerLobby::getHitCaptureLimit() if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) { - if (ServerConfig::m_capture_limit > 0) - hit_capture_limit = ServerConfig::m_capture_limit; - if (ServerConfig::m_time_limit_ctf > 0) - time_limit = (float)ServerConfig::m_time_limit_ctf; + if (getSettings()->getCaptureLimit() > 0) + hit_capture_limit = getSettings()->getCaptureLimit(); + if (getSettings()->getTimeLimitCtf() > 0) + time_limit = (float)getSettings()->getTimeLimitCtf(); } else { - if (ServerConfig::m_hit_limit > 0) - hit_capture_limit = ServerConfig::m_hit_limit; - if (ServerConfig::m_time_limit_ffa > 0.0f) - time_limit = (float)ServerConfig::m_time_limit_ffa; + if (getSettings()->getHitLimit() > 0) + hit_capture_limit = getSettings()->getHitLimit(); + if (getSettings()->getTimeLimitFfa() > 0.0f) + time_limit = (float)getSettings()->getTimeLimitFfa(); } - m_lobby_settings->setBattleHitCaptureLimit(hit_capture_limit); - m_lobby_settings->setBattleTimeLimit(time_limit); + getSettings()->setBattleHitCaptureLimit(hit_capture_limit); + getSettings()->setBattleTimeLimit(time_limit); } // getHitCaptureLimit // ---------------------------------------------------------------------------- @@ -3616,7 +3604,7 @@ void ServerLobby::submitRankingsToAddons() void ServerLobby::configPeersStartTime() { uint32_t max_ping = 0; - const unsigned max_ping_from_peers = ServerConfig::m_max_ping; + const unsigned max_ping_from_peers = getSettings()->getMaxPing(); bool peer_exceeded_max_ping = false; for (auto p : m_peers_ready) { @@ -3634,12 +3622,12 @@ void ServerLobby::configPeersStartTime() } max_ping = std::max(peer->getAveragePing(), max_ping); } - if ((ServerConfig::m_high_ping_workaround && peer_exceeded_max_ping) || - (ServerConfig::m_live_players && RaceManager::get()->supportsLiveJoining())) + if ((getSettings()->getHighPingWorkaround() && peer_exceeded_max_ping) || + (getSettings()->isLivePlayers() && RaceManager::get()->supportsLiveJoining())) { Log::info("ServerLobby", "Max ping to ServerConfig::m_max_ping for " "live joining or high ping workaround."); - max_ping = ServerConfig::m_max_ping; + max_ping = getSettings()->getMaxPing(); } // Start up time will be after 2500ms, so even if this packet is sent late // (due to packet loss), the start time will still ahead of current time @@ -3654,7 +3642,7 @@ void ServerLobby::configPeersStartTime() m_client_starting_time = start_time; sendMessageToPeers(ns, PRM_RELIABLE); - const unsigned jitter_tolerance = ServerConfig::m_jitter_tolerance; + const unsigned jitter_tolerance = getSettings()->getJitterTolerance(); Log::info("ServerLobby", "Max ping from peers: %d, jitter tolerance: %d", max_ping, jitter_tolerance); // Delay server for max ping / 2 from peers and jitter tolerance. @@ -3702,7 +3690,7 @@ void ServerLobby::addWaitingPlayersToGame() if (m_peers_ready.find(peer) == m_peers_ready.end()) { m_peers_ready[peer] = false; - if (!ServerConfig::m_sql_management) + if (!getSettings()->getSqlManagement()) { Log::info("ServerLobby", "New player %s with online id %u from %s with %s.", @@ -3713,7 +3701,7 @@ void ServerLobby::addWaitingPlayersToGame() } } uint32_t online_id = profile->getOnlineId(); - if (ServerConfig::m_ranked && !m_ranking->has(online_id)) + if (getSettings()->getRanked() && !m_ranking->has(online_id)) { getRankingForPlayer(peer->getPlayerProfiles()[0]); } @@ -3900,7 +3888,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, m_state.load()); return; } - if (!ServerConfig::m_server_configurable) + if (!getSettings()->getServerConfigurable()) { Log::warn("ServerLobby", "server-configurable is not enabled."); return; @@ -3908,8 +3896,8 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, bool teams_before = RaceManager::get()->teamEnabled(); unsigned total_players = 0; STKHost::get()->updatePlayers(NULL, NULL, &total_players); - bool bad_mode = !m_lobby_settings->isModeAvailable(mode); - bool bad_difficulty = !m_lobby_settings->isDifficultyAvailable(difficulty); + bool bad_mode = !getSettings()->isModeAvailable(mode); + bool bad_difficulty = !getSettings()->isDifficultyAvailable(difficulty); if (bad_mode || bad_difficulty) { // It remains just in case, but kimden thinks that @@ -3969,7 +3957,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, auto assets = peer->getClientAssets(); if (!peer->isValidated() || assets.second.empty()) // this check will fail hard when I introduce vavriable limits continue; - if (m_asset_manager->checkIfNoCommonMaps(assets)) + if (getAssetManager()->checkIfNoCommonMaps(assets)) { NetworkString *message = getNetworkString(2); message->setSynchronous(true); @@ -3989,8 +3977,8 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, if (teams_after) { int final_number, players_number; - m_lobby_settings->clearTeams(); - m_command_manager->assignRandomTeams(2, &final_number, &players_number); + getSettings()->clearTeams(); + getCommandManager()->assignRandomTeams(2, &final_number, &players_number); } else { @@ -4016,11 +4004,11 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, delete server_info; updatePlayerList(); - if (m_kart_elimination->isEnabled() && + if (getKartElimination()->isEnabled() && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_NORMAL_RACE && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) { - m_kart_elimination->disable(); + getKartElimination()->disable(); NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); chat->setSynchronous(true); @@ -4051,9 +4039,9 @@ void ServerLobby::handleServerConfiguration(Event* event) event->getPeer()->getHostId()); return; } - int new_difficulty = ServerConfig::m_server_difficulty; - int new_game_mode = ServerConfig::m_server_mode; - bool new_soccer_goal_target = ServerConfig::m_soccer_goal_target; + int new_difficulty = getSettings()->getServerDifficulty(); + int new_game_mode = getSettings()->getServerMode(); + bool new_soccer_goal_target = getSettings()->getSoccerGoalTarget(); if (event != NULL) { NetworkString& data = event->data(); @@ -4152,7 +4140,7 @@ void ServerLobby::handlePlayerDisconnection() const World::getWorld()->eliminateKart(i, false/*notify_of_elimination*/); - if (ServerConfig::m_ranked) + if (getSettings()->getRanked()) { // Handle disconnection earlier to prevent cheating by joining // another ranked server @@ -4174,7 +4162,7 @@ void ServerLobby::handlePlayerDisconnection() const } // If live players is enabled, don't end the game if unfair team - if (!ServerConfig::m_live_players && + if (!getSettings()->isLivePlayers() && total != 1 && World::getWorld()->hasTeam() && (red_count == 0 || blue_count == 0)) World::getWorld()->setUnfairTeam(true); @@ -4187,13 +4175,13 @@ void ServerLobby::handlePlayerDisconnection() const void ServerLobby::addLiveJoinPlaceholder( std::vector >& players) const { - if (!ServerConfig::m_live_players || !RaceManager::get()->supportsLiveJoining()) + if (!getSettings()->isLivePlayers() || !RaceManager::get()->supportsLiveJoining()) return; if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) { Track* t = TrackManager::get()->getTrack(m_game_setup->getCurrentTrack()); assert(t); - int max_players = std::min((int)ServerConfig::m_server_max_players, + int max_players = std::min((int)getSettings()->getServerMaxPlayers(), (int)t->getMaxArenaPlayers()); int add_size = max_players - (int)players.size(); assert(add_size >= 0); @@ -4241,19 +4229,19 @@ void ServerLobby::setPlayerKarts(const NetworkString& ns, std::shared_ptrgetPlayerProfiles()[i]->getName()); - if (m_kart_elimination->isEliminated(username)) + if (getKartElimination()->isEliminated(username)) { - peer->getPlayerProfiles()[i]->setKartName(m_kart_elimination->getKart()); + peer->getPlayerProfiles()[i]->setKartName(getKartElimination()->getKart()); continue; } std::string current_kart = kart; if (kart.find("randomkart") != std::string::npos || (kart.find("addon_") == std::string::npos && - !m_asset_manager->isKartAvailable(kart))) + !getAssetManager()->isKartAvailable(kart))) { current_kart = ""; } - if (m_lobby_queues->areKartFiltersIgnoringKarts()) + if (getQueues()->areKartFiltersIgnoringKarts()) current_kart = ""; std::string name = StringUtils::wideToUtf8(peer->getPlayerProfiles()[i]->getName()); peer->getPlayerProfiles()[i]->setKartName(getKartForBadKartChoice(peer, name, current_kart)); @@ -4461,7 +4449,7 @@ std::set>& ServerLobby::getSpectatorsByLimit(bool updat auto peers = STKHost::get()->getPeers(); - unsigned player_limit = ServerConfig::m_server_max_players; + unsigned player_limit = getSettings()->getServerMaxPlayers(); // If the server has an in-game player limit lower than the lobby limit, apply it, // A value of 0 for this parameter means no limit. unsigned current_max_players_in_game = m_current_max_players_in_game.load(); @@ -4603,7 +4591,7 @@ void ServerLobby::updateGnuElimination() else order[username] = RaceManager::get()->getKartRaceTime(i); } - std::string msg = m_kart_elimination->update(order); + std::string msg = getKartElimination()->update(order); if (!msg.empty()) sendStringToAllPeers(msg); } // updateGnuElimination @@ -4635,8 +4623,8 @@ void ServerLobby::storeResults() if (rm->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) { m_game_info->m_value_limit = rm->getHitCaptureLimit(); - m_game_info->m_flag_return_timeout = ServerConfig::m_flag_return_timeout; - m_game_info->m_flag_deactivated_time = ServerConfig::m_flag_deactivated_time; + m_game_info->m_flag_return_timeout = getSettings()->getFlagReturnTimeout(); + m_game_info->m_flag_deactivated_time = getSettings()->getFlagDeactivatedTime(); } else if (rm->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) { @@ -4853,10 +4841,10 @@ void ServerLobby::storeResults() //----------------------------------------------------------------------------- void ServerLobby::resetToDefaultSettings() { - if (ServerConfig::m_server_configurable && !m_lobby_settings->isPreservingMode()) + if (getSettings()->getServerConfigurable() && !getSettings()->isPreservingMode()) handleServerConfiguration(NULL); - m_lobby_settings->onResetToDefaultSettings(); + getSettings()->onResetToDefaultSettings(); } // resetToDefaultSettings //----------------------------------------------------------------------------- void ServerLobby::writeOwnReport(std::shared_ptr reporter, std::shared_ptr reporting, const std::string& info) @@ -4957,7 +4945,7 @@ bool ServerLobby::canRace(std::shared_ptr peer) } std::string username = StringUtils::wideToUtf8( peer->getPlayerProfiles()[0]->getName()); - if (m_tournament && !m_tournament->canPlay(username)) + if (getTournament() && !getTournament()->canPlay(username)) { m_why_peer_cannot_play[peer] = HR_NOT_A_TOURNAMENT_PLAYER; return false; @@ -4968,28 +4956,28 @@ bool ServerLobby::canRace(std::shared_ptr peer) return false; } - if (!m_lobby_settings->getMissingAssets(peer).empty()) + if (!getSettings()->getMissingAssets(peer).empty()) { m_why_peer_cannot_play[peer] = HR_LACKING_REQUIRED_MAPS; return false; } - if (peer->addon_karts_count < ServerConfig::m_addon_karts_play_threshold) + if (peer->addon_karts_count < getSettings()->getAddonKartsPlayThreshold()) { m_why_peer_cannot_play[peer] = HR_ADDON_KARTS_PLAY_THRESHOLD; return false; } - if (peer->addon_tracks_count < ServerConfig::m_addon_tracks_play_threshold) + if (peer->addon_tracks_count < getSettings()->getAddonTracksPlayThreshold()) { m_why_peer_cannot_play[peer] = HR_ADDON_TRACKS_PLAY_THRESHOLD; return false; } - if (peer->addon_arenas_count < ServerConfig::m_addon_arenas_play_threshold) + if (peer->addon_arenas_count < getSettings()->getAddonArenasPlayThreshold()) { m_why_peer_cannot_play[peer] = HR_ADDON_ARENAS_PLAY_THRESHOLD; return false; } - if (peer->addon_soccers_count < ServerConfig::m_addon_soccers_play_threshold) + if (peer->addon_soccers_count < getSettings()->getAddonSoccersPlayThreshold()) { m_why_peer_cannot_play[peer] = HR_ADDON_FIELDS_PLAY_THRESHOLD; return false; @@ -4998,15 +4986,15 @@ bool ServerLobby::canRace(std::shared_ptr peer) std::set maps = peer->getClientAssets().second; std::set karts = peer->getClientAssets().first; - float karts_fraction = m_asset_manager->officialKartsFraction(karts); - float maps_fraction = m_asset_manager->officialMapsFraction(maps); + float karts_fraction = getAssetManager()->officialKartsFraction(karts); + float maps_fraction = getAssetManager()->officialMapsFraction(maps); - if (karts_fraction < ServerConfig::m_official_karts_play_threshold) + if (karts_fraction < getSettings()->getOfficialKartsPlayThreshold()) { m_why_peer_cannot_play[peer] = HR_OFFICIAL_KARTS_PLAY_THRESHOLD; return false; } - if (maps_fraction < ServerConfig::m_official_tracks_play_threshold) + if (maps_fraction < getSettings()->getOfficialTracksPlayThreshold()) { m_why_peer_cannot_play[peer] = HR_OFFICIAL_TRACKS_PLAY_THRESHOLD; return false; @@ -5035,10 +5023,10 @@ bool ServerLobby::canVote(std::shared_ptr peer) const if (!peer || peer->getPlayerProfiles().empty()) return false; - if (!m_tournament) + if (!getTournament()) return true; - return m_tournament->canVote(peer); + return getTournament()->canVote(peer); } // canVote //----------------------------------------------------------------------------- bool ServerLobby::hasHostRights(std::shared_ptr peer) const @@ -5049,8 +5037,8 @@ bool ServerLobby::hasHostRights(std::shared_ptr peer) const return true; if (peer->isAngryHost()) return true; - if (m_tournament) - return m_tournament->hasHostRights(peer); + if (isTournament()) + return getTournament()->hasHostRights(peer); return false; } // hasHostRights @@ -5074,14 +5062,14 @@ int ServerLobby::getPermissions(std::shared_ptr peer) const if (peer == m_server_owner.lock()) { mask |= CommandPermissions::PE_CROWNED; - if (ServerConfig::m_only_host_riding) + if (getSettings()->getOnlyHostRiding()) mask |= CommandPermissions::PE_SINGLE; } if (peer->isAngryHost()) { mask |= CommandPermissions::PE_HAMMER; } - else if (m_tournament && m_tournament->hasHammerRights(peer)) + else if (getTournament() && getTournament()->hasHammerRights(peer)) { mask |= CommandPermissions::PE_HAMMER; } @@ -5181,16 +5169,6 @@ void ServerLobby::changeLimitForTournament(bool goal_target) } // changeLimitForTournament //----------------------------------------------------------------------------- -std::shared_ptr ServerLobby::getCommandManager() -{ - if (!m_command_manager->isInitialized()) - { - m_command_manager = std::make_shared(this); - } - return m_command_manager; -} // getCommandManager -//----------------------------------------------------------------------------- - #ifdef ENABLE_SQLITE3 std::string ServerLobby::getRecord(std::string& track, std::string& mode, std::string& direction, int laps) @@ -5257,7 +5235,7 @@ void ServerLobby::setTemporaryTeamInLobby(const std::string& username, int team) // todo This should be moved later to another unit. void ServerLobby::clearTemporaryTeams() { - m_lobby_settings->clearTeams(); + getSettings()->clearTeams(); for (auto& peer : STKHost::get()->getPeers()) { @@ -5272,7 +5250,7 @@ void ServerLobby::clearTemporaryTeams() // todo This should be moved later to another unit. void ServerLobby::shuffleTemporaryTeams(const std::map& permutation) { - m_lobby_settings->applyPermutationToTeams(permutation); + getSettings()->applyPermutationToTeams(permutation); for (auto& peer : STKHost::get()->getPeers()) { for (auto &profile: peer->getPlayerProfiles()) @@ -5340,14 +5318,14 @@ void ServerLobby::applyAllFilters(std::set& maps, bool use_history) map_context.wildcards = m_map_history; map_context.applied_at_selection_start = true; map_context.elements = maps; - m_lobby_settings->applyGlobalFilter(map_context); + getSettings()->applyGlobalFilter(map_context); if (use_history) { - if (m_tournament) - m_tournament->applyFiltersForThisGame(map_context); + if (isTournament()) + getTournament()->applyFiltersForThisGame(map_context); map_context.wildcards = m_map_history; - m_lobby_queues->applyFrontMapFilters(map_context); + getQueues()->applyFrontMapFilters(map_context); } swap(maps, map_context.elements); } // applyAllFilters @@ -5362,19 +5340,19 @@ void ServerLobby::applyAllKartFilters(const std::string& username, std::setapplyGlobalKartsFilter(kart_context); - m_lobby_queues->applyFrontKartFilters(kart_context); + getSettings()->applyGlobalKartsFilter(kart_context); + getQueues()->applyFrontKartFilters(kart_context); swap(karts, kart_context.elements); } // applyAllKartFilters //----------------------------------------------------------------------------- std::string ServerLobby::getKartForBadKartChoice(std::shared_ptr peer, const std::string& username, const std::string& check_choice) const { - std::set karts = (peer->isAIPeer() ? m_asset_manager->getAvailableKarts() : peer->getClientAssets().first); + std::set karts = (peer->isAIPeer() ? getAssetManager()->getAvailableKarts() : peer->getClientAssets().first); applyAllKartFilters(username, karts, true); - if (m_kart_elimination->isEliminated(username) - && karts.count(m_kart_elimination->getKart())) + if (getKartElimination()->isEliminated(username) + && karts.count(getKartElimination()->getKart())) { - return m_kart_elimination->getKart(); + return getKartElimination()->getKart(); } if (!check_choice.empty() && karts.count(check_choice)) // valid choice return check_choice; @@ -5404,7 +5382,7 @@ void ServerLobby::setKartDataProperly(KartData& kart_data, const std::string& ka { const KartProperties* real_addon = kart_properties_manager->getKart(kart_name); - if (ServerConfig::m_real_addon_karts && real_addon) + if (getSettings()->getRealAddonKarts() && real_addon) { kart_data = KartData(real_addon); } @@ -5458,7 +5436,7 @@ void ServerLobby::saveDisconnectingIdInfo(int id) const if (ffa_world) points = ffa_world->getKartScore(id); info.m_result += points; - if (ServerConfig::m_preserve_battle_scores) + if (getSettings()->getPreserveBattleScores()) m_game_info->m_saved_ffa_points[StringUtils::wideToUtf8(rki.getPlayerName())] = points; } info.m_when_left = stk_config->ticks2Time(w->getTicksSinceStart()); @@ -5491,7 +5469,7 @@ void ServerLobby::setTeamInLobby(std::shared_ptr profile, // Used for soccer+CTF, where everything can be defined by KartTeam profile->setTeam(team); profile->setTemporaryTeam(TeamUtils::getIndexFromKartTeam(team)); - m_lobby_settings->setTeamForUsername( + getSettings()->setTeamForUsername( StringUtils::wideToUtf8(profile->getName()), profile->getTemporaryTeam() ); @@ -5508,7 +5486,7 @@ void ServerLobby::setTemporaryTeamInLobby(std::shared_ptr profile->setTeam((KartTeam)(TeamUtils::getKartTeamFromIndex(team))); else profile->setTeam(KART_TEAM_NONE); - m_lobby_settings->setTeamForUsername( + getSettings()->setTeamForUsername( StringUtils::wideToUtf8(profile->getName()), profile->getTemporaryTeam() ); @@ -5564,5 +5542,4 @@ void ServerLobby::setSpectateModeProperly(std::shared_ptr peer, AlwaysS if (mode == ASM_NONE) checkNoTeamSpectator(peer); } // setSpectateModeProperly - //----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 430bd5abffe..cc697015374 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -24,6 +24,7 @@ #include "network/requests.hpp" // only needed in header as long as KeyData is there #include "utils/cpp2011.hpp" #include "utils/hourglass_reason.hpp" +#include "utils/lobby_context.hpp" #include "utils/team_utils.hpp" #include "utils/time.hpp" #include "utils/track_filter.hpp" @@ -81,7 +82,7 @@ struct GPScore } }; -class ServerLobby : public LobbyProtocol +class ServerLobby : public LobbyProtocol, public LobbyContextUser { public: /* The state for a small finite state machine. */ @@ -190,17 +191,11 @@ class ServerLobby : public LobbyProtocol uint64_t m_last_unsuccess_poll_time, m_server_started_at, m_server_delay; // Other units previously used in ServerLobby + std::shared_ptr m_lobby_context; + std::shared_ptr m_ranking; - std::shared_ptr m_hit_processor; - std::shared_ptr m_asset_manager; - std::shared_ptr m_kart_elimination; - std::shared_ptr m_map_vote_handler; - std::shared_ptr m_tournament; - std::shared_ptr m_lobby_queues; - std::shared_ptr m_lobby_settings; friend CommandManager; - std::shared_ptr m_command_manager; unsigned m_item_seed; @@ -319,7 +314,6 @@ class ServerLobby : public LobbyProtocol bool hasHostRights(std::shared_ptr peer) const; std::string getGrandPrixStandings(bool showIndividual = false, bool showTeam = true) const; void changeLimitForTournament(bool goal_target); - std::shared_ptr getCommandManager(); public: ServerLobby(); @@ -401,17 +395,6 @@ class ServerLobby : public LobbyProtocol void checkNoTeamSpectator(std::shared_ptr peer); void setSpectateModeProperly(std::shared_ptr peer, AlwaysSpectateMode mode); - std::shared_ptr getHitProcessor() const - { return m_hit_processor; } - std::shared_ptr getLobbyAssetManager() const - { return m_asset_manager; } - std::shared_ptr getTournament() const { return m_tournament; } - std::shared_ptr getLobbyQueues() const - { return m_lobby_queues; } - std::shared_ptr getLobbySettings() const - { return m_lobby_settings; } - std::shared_ptr getKartElimination() const - { return m_kart_elimination; } std::shared_ptr getGameInfo() const { return m_game_info; } // Functions that arose from requests separation diff --git a/src/race/race_manager.hpp b/src/race/race_manager.hpp index 9706e563da6..71469551ff2 100644 --- a/src/race/race_manager.hpp +++ b/src/race/race_manager.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "network/remote_kart_info.hpp" @@ -37,6 +38,7 @@ #include "utils/types.hpp" class AbstractKart; +class HitProcessor; class NetworkString; class SavedGrandPrix; class Track; @@ -388,6 +390,8 @@ class RaceManager bool m_benchmarking; bool m_scheduled_benchmark; + std::shared_ptr m_hit_processor; + public: // ---------------------------------------------------------------------------------------- static RaceManager* get(); @@ -969,6 +973,12 @@ class RaceManager void setRandomItemsIndicator(bool value) { m_random_items = value; } // ---------------------------------------------------------------------------------------- bool getRandomItemsIndicator() const { return m_random_items; } + // ---------------------------------------------------------------------------------------- + std::shared_ptr getHitProcessor() const { return m_hit_processor; } + // ---------------------------------------------------------------------------------------- + void setHitProcessor(std::shared_ptr hp) { m_hit_processor = hp; } + // ---------------------------------------------------------------------------------------- + void resetHitProcessor() { m_hit_processor = {}; } }; // RaceManager #endif diff --git a/src/utils/hit_processor.cpp b/src/utils/hit_processor.cpp index b1072e3eb81..5dfe85b2231 100644 --- a/src/utils/hit_processor.cpp +++ b/src/utils/hit_processor.cpp @@ -41,8 +41,7 @@ namespace } // namespace //----------------------------------------------------------------------------- -HitProcessor::HitProcessor(ServerLobby* lobby, std::shared_ptr settings) - : m_lobby(lobby), m_lobby_settings(settings) +void HitProcessor::setupContextUser() { m_troll_active = ServerConfig::m_troll_active; m_show_hits = ServerConfig::m_show_teammate_hits; @@ -97,7 +96,7 @@ void HitProcessor::sendTeammateHitMsg(std::string& s) if (ticks - m_last_hit_msg > stk_config->time2Ticks(1.5f)) { m_last_hit_msg = ticks; - m_lobby->sendStringToAllPeers(s); + getLobby()->sendStringToAllPeers(s); } } // sendTeammateHitMsg //----------------------------------------------------------------------------- @@ -109,7 +108,7 @@ void HitProcessor::handleTeammateHits() // Get team of item owner auto kart_info = RaceManager::get()->getKartInfo(m_current_item_owner_id); const std::string owner_name = StringUtils::wideToUtf8(kart_info.getPlayerName()); - const int owner_team = m_lobby_settings->getTeamForUsername(owner_name); + const int owner_team = getSettings()->getTeamForUsername(owner_name); if (owner_team == TeamUtils::NO_TEAM) return; @@ -144,7 +143,7 @@ void HitProcessor::processHitMessage(const std::string& owner_name, int owner_te { const std::string player_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(m_karts_exploded[i]).getPlayerName()); - const int playerTeam = m_lobby_settings->getTeamForUsername(player_name); + const int playerTeam = getSettings()->getTeamForUsername(player_name); if (owner_team != playerTeam) continue; @@ -171,7 +170,7 @@ void HitProcessor::processTeammateHit(AbstractKart* owner, { const std::string player_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(m_karts_exploded[i]).getPlayerName()); - const int playerTeam = m_lobby_settings->getTeamForUsername(player_name); + const int playerTeam = getSettings()->getTeamForUsername(player_name); if (owner_team != playerTeam) continue; @@ -195,7 +194,7 @@ void HitProcessor::processTeammateHit(AbstractKart* owner, { const std::string player_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(m_karts_hit[i]).getPlayerName()); - const int playerTeam = m_lobby_settings->getTeamForUsername(player_name); + const int playerTeam = getSettings()->getTeamForUsername(player_name); if (owner_team != playerTeam) continue; @@ -225,13 +224,13 @@ void HitProcessor::handleSwatterHit(unsigned int ownerID, unsigned int victimID, { const std::string owner_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(ownerID).getPlayerName()); - const int owner_team = m_lobby_settings->getTeamForUsername(owner_name); + const int owner_team = getSettings()->getTeamForUsername(owner_name); if (owner_team == TeamUtils::NO_TEAM) return; const std::string victim_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(victimID).getPlayerName()); - const int victim_team = m_lobby_settings->getTeamForUsername(victim_name); + const int victim_team = getSettings()->getTeamForUsername(victim_name); if (victim_team != owner_team) return; @@ -269,13 +268,13 @@ void HitProcessor::handleAnvilHit(unsigned int ownerID, unsigned int victimID) { const std::string owner_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(ownerID).getPlayerName()); - const int owner_team = m_lobby_settings->getTeamForUsername(owner_name); + const int owner_team = getSettings()->getTeamForUsername(owner_name); if (owner_team == TeamUtils::NO_TEAM) return; const std::string victim_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(victimID).getPlayerName()); - const int victim_team = m_lobby_settings->getTeamForUsername(victim_name); + const int victim_team = getSettings()->getTeamForUsername(victim_name); if (victim_team != owner_team) return; diff --git a/src/utils/hit_processor.hpp b/src/utils/hit_processor.hpp index 8bcc9f8748a..333aaa7e8aa 100644 --- a/src/utils/hit_processor.hpp +++ b/src/utils/hit_processor.hpp @@ -19,6 +19,7 @@ #ifndef HIT_PROCESSOR_HPP #define HIT_PROCESSOR_HPP +#include "utils/lobby_context.hpp" #include "utils/types.hpp" #include @@ -36,14 +37,14 @@ class ServerLobby; // Note that this class currently (March 2025) processes *team* hits. // It will be modified to process all hits later. -class HitProcessor +class HitProcessor: public LobbyContextComponent { public: - HitProcessor(ServerLobby* lobby, std::shared_ptr settings); + HitProcessor(LobbyContext* context): LobbyContextComponent(context) {} + + void setupContextUser() OVERRIDE; private: - ServerLobby* m_lobby = nullptr; - std::shared_ptr m_lobby_settings; bool m_troll_active; // Whether the anti-troll system is active. diff --git a/src/utils/kart_elimination.cpp b/src/utils/kart_elimination.cpp index b27a57eb46a..0b34e804394 100644 --- a/src/utils/kart_elimination.cpp +++ b/src/utils/kart_elimination.cpp @@ -29,12 +29,12 @@ #include #include -KartElimination::KartElimination() +void KartElimination::setupContextUser() { m_enabled = false; m_remained = 0; m_kart = ""; -} // KartElimination +} // setupContextUser //----------------------------------------------------------------------------- bool KartElimination::isEliminated(std::string username) const diff --git a/src/utils/kart_elimination.hpp b/src/utils/kart_elimination.hpp index ba2112c3bc7..82f91d1aace 100644 --- a/src/utils/kart_elimination.hpp +++ b/src/utils/kart_elimination.hpp @@ -19,6 +19,7 @@ #ifndef HEADER_KART_ELIMINATION_HPP #define HEADER_KART_ELIMINATION_HPP +#include "utils/lobby_context.hpp" #include "utils/string_utils.hpp" #include "utils/types.hpp" @@ -30,7 +31,8 @@ // A class that contains Gnu Elimination data -class KartElimination { +class KartElimination: public LobbyContextComponent +{ private: bool m_enabled; int m_remained; @@ -39,7 +41,10 @@ class KartElimination { public: static constexpr double INF_TIME = 1e9; - KartElimination(); + + KartElimination(LobbyContext* context): LobbyContextComponent(context) {} + + void setupContextUser() OVERRIDE; bool isEliminated(std::string username) const; std::string getKart() const { return m_kart; } std::set getRemainingParticipants() const; diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp index d1c0061a44f..19ec4c20897 100644 --- a/src/utils/lobby_asset_manager.cpp +++ b/src/utils/lobby_asset_manager.cpp @@ -28,13 +28,14 @@ #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/random_generator.hpp" +#include "utils/lobby_settings.hpp" #include "utils/string_utils.hpp" -LobbyAssetManager::LobbyAssetManager(ServerLobby* lobby): m_lobby(lobby) +void LobbyAssetManager::setupContextUser() { init(); updateAddons(); -} // LobbyAssetManager +} // setupContextUser //----------------------------------------------------------------------------- void LobbyAssetManager::init() @@ -117,7 +118,7 @@ void LobbyAssetManager::updateAddons() all_k.resize(65535 - (unsigned)oks.size()); for (const std::string& k : oks) all_k.push_back(k); - if (ServerConfig::m_live_players) + if (getSettings()->isLivePlayers()) m_available_kts.first = m_official_kts.first; else m_available_kts.first = { all_k.begin(), all_k.end() }; @@ -211,7 +212,7 @@ void LobbyAssetManager::onServerSetup() auto all_k = kart_properties_manager->getAllAvailableKarts(); if (all_k.size() >= 65536) all_k.resize(65535); - if (ServerConfig::m_live_players) + if (getSettings()->isLivePlayers()) m_available_kts.first = m_official_kts.first; else m_available_kts.first = { all_k.begin(), all_k.end() }; @@ -244,7 +245,7 @@ void LobbyAssetManager::eraseAssetsWithPeers( bool LobbyAssetManager::tryApplyingMapFilters() { std::set available_tracks_fallback = m_available_kts.second; - m_lobby->applyAllFilters(m_available_kts.second, true); + getLobby()->applyAllFilters(m_available_kts.second, true); /* auto iter = m_available_kts.second.begin(); while (iter != m_available_kts.second.end()) @@ -539,7 +540,7 @@ std::string LobbyAssetManager::getRandomMap() const for (const std::string& s: m_entering_kts.second) { items.insert(s); } - m_lobby->applyAllFilters(items, false); + getLobby()->applyAllFilters(items, false); if (items.empty()) return ""; RandomGenerator rg; @@ -557,7 +558,7 @@ std::string LobbyAssetManager::getRandomAddonMap() const if (t->isAddon()) items.insert(s); } - m_lobby->applyAllFilters(items, false); + getLobby()->applyAllFilters(items, false); if (items.empty()) return ""; RandomGenerator rg; diff --git a/src/utils/lobby_asset_manager.hpp b/src/utils/lobby_asset_manager.hpp index 71c2b0862bf..8839a411011 100644 --- a/src/utils/lobby_asset_manager.hpp +++ b/src/utils/lobby_asset_manager.hpp @@ -21,6 +21,7 @@ #include "network/stk_peer.hpp" #include "race/race_manager.hpp" +#include "utils/lobby_context.hpp" #include "utils/types.hpp" #include @@ -32,10 +33,12 @@ class NetworkString; class ServerLobby; class STKPeer; -class LobbyAssetManager +class LobbyAssetManager: public LobbyContextComponent { public: - LobbyAssetManager(ServerLobby* lobby); + LobbyAssetManager(LobbyContext* context): LobbyContextComponent(context) {} + + void setupContextUser() OVERRIDE; void init(); void updateAddons(); @@ -85,9 +88,6 @@ class LobbyAssetManager bool hasAddonSoccer(const std::string& id) const { return m_addon_soccers.find(id) != m_addon_soccers.end(); } -private: - ServerLobby* m_lobby; - public: /** Official karts and maps available in server. */ std::pair, std::set > m_official_kts; diff --git a/src/utils/lobby_context.cpp b/src/utils/lobby_context.cpp new file mode 100644 index 00000000000..1a826e87f47 --- /dev/null +++ b/src/utils/lobby_context.cpp @@ -0,0 +1,61 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/lobby_context.hpp" + +#include "network/protocols/command_manager.hpp" +#include "utils/hit_processor.hpp" +#include "utils/kart_elimination.hpp" +#include "utils/lobby_asset_manager.hpp" +#include "utils/lobby_queues.hpp" +#include "utils/lobby_settings.hpp" +#include "utils/map_vote_handler.hpp" +#include "utils/tournament.hpp" + +LobbyContext::LobbyContext(ServerLobby* lobby, bool make_tournament) + : m_lobby(lobby) +{ + // Nothing for ServerLobby, as we create LC inside SL + m_asset_manager = std::make_shared(this); + m_hit_processor = std::make_shared(this); + m_kart_elimination = std::make_shared(this); + m_lobby_queues = std::make_shared(this); + m_lobby_settings = std::make_shared(this); + m_map_vote_handler = std::make_shared(this); + m_command_manager = std::make_shared(this); + + if (make_tournament) + m_tournament = std::make_shared(this); +} // LobbyContext +//----------------------------------------------------------------------------- + +void LobbyContext::setup() +{ + // Nothing for ServerLobby + m_asset_manager->setupContextUser(); + m_hit_processor->setupContextUser(); + m_kart_elimination->setupContextUser(); + m_lobby_queues->setupContextUser(); + m_lobby_settings->setupContextUser(); + m_map_vote_handler->setupContextUser(); + m_command_manager->setupContextUser(); + + if (m_tournament) + m_tournament->setupContextUser(); +} // setup +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/lobby_context.hpp b/src/utils/lobby_context.hpp new file mode 100644 index 00000000000..f83db6888fe --- /dev/null +++ b/src/utils/lobby_context.hpp @@ -0,0 +1,97 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef LOBBY_CONTEXT_HPP +#define LOBBY_CONTEXT_HPP + +#include "utils/cpp2011.hpp" + +#include + +class CommandManager; +class HitProcessor; +class KartElimination; +class LobbyAssetManager; +class LobbyQueues; +class LobbySettings; +class MapVoteHandler; +class ServerLobby; +class Tournament; + +class LobbyContext +{ +private: + ServerLobby* m_lobby; + std::shared_ptr m_hit_processor; + std::shared_ptr m_asset_manager; + std::shared_ptr m_tournament; + std::shared_ptr m_lobby_queues; + std::shared_ptr m_lobby_settings; + std::shared_ptr m_kart_elimination; + std::shared_ptr m_map_vote_handler; + std::shared_ptr m_command_manager; + +public: + + LobbyContext(ServerLobby* lobby, bool make_tournament); + + void setup(); + + ServerLobby* getLobby() const { return m_lobby; } + std::shared_ptr getHitProcessor() const { return m_hit_processor; } + std::shared_ptr getAssetManager() const { return m_asset_manager; } + bool isTournament() const { return m_tournament.get() != nullptr; } + std::shared_ptr getTournament() const { return m_tournament; } + std::shared_ptr getQueues() const { return m_lobby_queues; } + std::shared_ptr getSettings() const { return m_lobby_settings; } + std::shared_ptr getKartElimination() const { return m_kart_elimination; } + std::shared_ptr getMapVoteHandler() const { return m_map_vote_handler; } + std::shared_ptr getCommandManager() const { return m_command_manager; } +}; + +class LobbyContextUser +{ +protected: + LobbyContext* m_context; + ServerLobby* getLobby() const { return m_context->getLobby(); } + std::shared_ptr getHitProcessor() const { return m_context->getHitProcessor(); } + std::shared_ptr getAssetManager() const { return m_context->getAssetManager(); } + bool isTournament() const { return m_context->isTournament(); } + std::shared_ptr getTournament() const { return m_context->getTournament(); } + std::shared_ptr getQueues() const { return m_context->getQueues(); } + std::shared_ptr getSettings() const { return m_context->getSettings(); } + std::shared_ptr getKartElimination() const { return m_context->getKartElimination(); } + std::shared_ptr getMapVoteHandler() const { return m_context->getMapVoteHandler(); } + std::shared_ptr getCommandManager() const { return m_context->getCommandManager(); } + +public: + void setContext(LobbyContext* context) { m_context = context; } +}; + +class LobbyContextComponent: public LobbyContextUser +{ +public: + + LobbyContextComponent(LobbyContext* context) + { + m_context = context; + } + virtual void setupContextUser() = 0; +}; + +#endif // LOBBY_CONTEXT_HPP diff --git a/src/utils/lobby_queues.cpp b/src/utils/lobby_queues.cpp index 82a5716fe37..e46314de2b1 100644 --- a/src/utils/lobby_queues.cpp +++ b/src/utils/lobby_queues.cpp @@ -18,14 +18,13 @@ #include "utils/lobby_queues.hpp" -#include "network/protocols/server_lobby.hpp" #include "network/server_config.hpp" #include "utils/string_utils.hpp" -LobbyQueues::LobbyQueues() +void LobbyQueues::setupContextUser() { loadTracksQueueFromConfig(); -} // LobbyQueues +} // setupContextUser //----------------------------------------------------------------------------- void LobbyQueues::loadTracksQueueFromConfig() diff --git a/src/utils/lobby_queues.hpp b/src/utils/lobby_queues.hpp index f66c2b088b9..7b88d2ba05f 100644 --- a/src/utils/lobby_queues.hpp +++ b/src/utils/lobby_queues.hpp @@ -21,14 +21,17 @@ #include "irrString.h" #include "utils/track_filter.hpp" +#include "utils/lobby_context.hpp" #include #include -class LobbyQueues +class LobbyQueues: public LobbyContextComponent { public: - LobbyQueues(); + LobbyQueues(LobbyContext* context): LobbyContextComponent(context) {} + + void setupContextUser() OVERRIDE; void loadTracksQueueFromConfig(); diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index 488bfa4c40e..10902a51a82 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -22,10 +22,13 @@ #include "modes/world.hpp" #include "network/game_setup.hpp" #include "network/game_setup.hpp" +#include "network/network_config.hpp" #include "network/network_string.hpp" #include "network/peer_vote.hpp" #include "network/server_config.hpp" #include "network/stk_peer.hpp" +#include "network/protocols/server_lobby.hpp" +#include "network/game_setup.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/game_info.hpp" @@ -36,17 +39,10 @@ #include "utils/string_utils.hpp" #include "utils/tournament.hpp" -LobbySettings::LobbySettings(GameSetup* game_setup, - std::shared_ptr queues, - std::shared_ptr elim, - std::shared_ptr asset_manager, - std::shared_ptr tournament) - : m_game_setup(game_setup) - , m_lobby_queues(queues) - , m_kart_elimination(elim) - , m_asset_manager(asset_manager) - , m_tournament(tournament) +void LobbySettings::setupContextUser() { + m_game_setup = getLobby()->getGameSetup(); + m_motd = StringUtils::wideToUtf8( m_game_setup->readOrLoadFromFile( (std::string) ServerConfig::m_motd @@ -76,19 +72,68 @@ LobbySettings::LobbySettings(GameSetup* game_setup, loadWhiteList(); loadPreservedSettings(); - // The following was called in SL::setup, I doubt it's any different - // but just in case - - m_battle_hit_capture_limit = 0; - m_battle_time_limit = 0.0f; - m_winner_peer_id = 0; -} // LobbySettings + m_live_players = ServerConfig::m_live_players; + + m_addon_arenas_play_threshold = ServerConfig::m_addon_arenas_play_threshold; + m_addon_karts_play_threshold = ServerConfig::m_addon_karts_play_threshold; + m_addon_soccers_play_threshold = ServerConfig::m_addon_soccers_play_threshold; + m_addon_tracks_play_threshold = ServerConfig::m_addon_tracks_play_threshold; + m_ai_anywhere = ServerConfig::m_ai_anywhere; + m_ai_handling = ServerConfig::m_ai_handling; + m_capture_limit = ServerConfig::m_capture_limit; + m_chat = ServerConfig::m_chat; + m_chat_consecutive_interval = ServerConfig::m_chat_consecutive_interval; + m_expose_mobile = ServerConfig::m_expose_mobile; + m_firewalled_server = ServerConfig::m_firewalled_server; + m_flag_deactivated_time = ServerConfig::m_flag_deactivated_time; + m_flag_return_timeout = ServerConfig::m_flag_return_timeout; + m_free_teams = ServerConfig::m_free_teams; + m_high_ping_workaround = ServerConfig::m_high_ping_workaround; + m_hit_limit = ServerConfig::m_hit_limit; + m_incompatible_advice = ServerConfig::m_incompatible_advice; + m_jitter_tolerance = ServerConfig::m_jitter_tolerance; + m_kick_idle_lobby_player_seconds = ServerConfig::m_kick_idle_lobby_player_seconds; + m_kick_idle_player_seconds = ServerConfig::m_kick_idle_player_seconds; + m_kicks_allowed = ServerConfig::m_kicks_allowed; + m_max_ping = ServerConfig::m_max_ping; + m_min_start_game_players = ServerConfig::m_min_start_game_players; + m_official_karts_play_threshold = ServerConfig::m_official_karts_play_threshold; + m_official_tracks_play_threshold = ServerConfig::m_official_tracks_play_threshold; + m_only_host_riding = ServerConfig::m_only_host_riding; + m_owner_less = ServerConfig::m_owner_less; + m_preserve_battle_scores = ServerConfig::m_preserve_battle_scores; + m_private_server_password = ServerConfig::m_private_server_password; + m_ranked = ServerConfig::m_ranked; + m_real_addon_karts = ServerConfig::m_real_addon_karts; + m_record_replays = ServerConfig::m_record_replays; + m_server_configurable = ServerConfig::m_server_configurable; + m_server_difficulty = ServerConfig::m_server_difficulty; + m_server_max_players = ServerConfig::m_server_max_players; + m_server_mode = ServerConfig::m_server_mode; + m_sleeping_server = ServerConfig::m_sleeping_server; + m_soccer_goal_target = ServerConfig::m_soccer_goal_target; + m_sql_management = ServerConfig::m_sql_management; + m_start_game_counter = ServerConfig::m_start_game_counter; + m_state_frequency = ServerConfig::m_state_frequency; + m_store_results = ServerConfig::m_store_results; + m_strict_players = ServerConfig::m_strict_players; + m_team_choosing = ServerConfig::m_team_choosing; + m_time_limit_ctf = ServerConfig::m_time_limit_ctf; + m_time_limit_ffa = ServerConfig::m_time_limit_ffa; + m_track_kicks = ServerConfig::m_track_kicks; + m_track_voting = ServerConfig::m_track_voting; + m_troll_warn_msg = ServerConfig::m_troll_warn_msg; + m_validating_player = ServerConfig::m_validating_player; + m_voting_timeout = ServerConfig::m_voting_timeout; + m_commands_file = ServerConfig::m_commands_file; +} // setupContextUser //----------------------------------------------------------------------------- LobbySettings::~LobbySettings() { delete m_default_vote; -} +} // ~LobbySettings +//----------------------------------------------------------------------------- void LobbySettings::initCategories() { @@ -177,7 +222,7 @@ void LobbySettings::initAvailableTracks() { m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); m_global_karts_filter = KartFilter(ServerConfig::m_only_played_karts_string); - m_asset_manager->setMustHaveMaps(ServerConfig::m_must_have_tracks_string); + getAssetManager()->setMustHaveMaps(ServerConfig::m_must_have_tracks_string); m_play_requirement_tracks = StringUtils::split( ServerConfig::m_play_requirement_tracks_string, ' ', false); } // initAvailableTracks @@ -555,10 +600,10 @@ void LobbySettings::updateWorldSettings(std::shared_ptr game_info) void LobbySettings::onResetToDefaultSettings() { - m_lobby_queues->resetToDefaultSettings(m_preserve); + getQueues()->resetToDefaultSettings(m_preserve); if (!m_preserve.count("elim")) - m_kart_elimination->disable(); + getKartElimination()->disable(); if (!m_preserve.count("laps")) { @@ -682,7 +727,7 @@ void LobbySettings::clearAllExpiredWeakPtrs() void LobbySettings::initializeDefaultVote() { - m_default_vote->m_track_name = m_asset_manager->getRandomAvailableMap(); + m_default_vote->m_track_name = getAssetManager()->getRandomAvailableMap(); RandomGenerator rg; switch (RaceManager::get()->getMinorMode()) { @@ -721,9 +766,9 @@ void LobbySettings::initializeDefaultVote() } case RaceManager::MINOR_MODE_SOCCER: { - if (m_tournament) + if (isTournament()) { - m_tournament->applyRestrictionsOnDefaultVote(m_default_vote); + getTournament()->applyRestrictionsOnDefaultVote(m_default_vote); } else { @@ -886,3 +931,13 @@ std::string LobbySettings::getAvailableTeams() const return m_available_teams; } // getAvailableTeams //----------------------------------------------------------------------------- + +void LobbySettings::onServerSetup() +{ + m_battle_hit_capture_limit = 0; + m_battle_time_limit = 0.0f; + m_winner_peer_id = 0; + + NetworkConfig::get()->setTuxHitboxAddon(m_live_players); +} // onServerSetup +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 1ad4ce3c2e3..8e5986e10fa 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -20,6 +20,7 @@ #define LOBBY_SETTINGS_HPP #include "irrString.h" +#include "utils/lobby_context.hpp" #include "utils/team_utils.hpp" #include "utils/track_filter.hpp" @@ -39,14 +40,12 @@ struct GameInfo; /** @brief A class that manipulates server settings, such as resetting, * scoring, goal policies, etc. Might be split into a few parts later, * or even merged back into ServerLobby if proved useless. */ -class LobbySettings +class LobbySettings: public LobbyContextComponent { public: - LobbySettings(GameSetup* game_setup, - std::shared_ptr queues, - std::shared_ptr elim, - std::shared_ptr asset_manager, - std::shared_ptr tournament); + LobbySettings(LobbyContext* context): LobbyContextComponent(context) {} + + void setupContextUser() OVERRIDE; ~LobbySettings(); void initCategories(); @@ -145,17 +144,66 @@ class LobbySettings bool isInHammerWhitelist(const std::string& str) const { return m_hammer_whitelist.find(str) != m_hammer_whitelist.end(); } + void onServerSetup(); + + // These were used unchanged from ServerConfig + bool isLivePlayers() const { return m_live_players; } + int getAddonArenasPlayThreshold() const { return m_addon_arenas_play_threshold; } + int getAddonKartsPlayThreshold() const { return m_addon_karts_play_threshold; } + int getAddonSoccersPlayThreshold() const { return m_addon_soccers_play_threshold; } + int getAddonTracksPlayThreshold() const { return m_addon_tracks_play_threshold; } + bool canConnectAiAnywhere() const { return m_ai_anywhere; } + bool getAiHandling() const { return m_ai_handling; } + int getCaptureLimit() const { return m_capture_limit; } + bool getChat() const { return m_chat; } + int getChatConsecutiveInterval() const { return m_chat_consecutive_interval; } + bool getExposeMobile() const { return m_expose_mobile; } + bool getFirewalledServer() const { return m_firewalled_server; } + float getFlagDeactivatedTime() const { return m_flag_deactivated_time; } + float getFlagReturnTimeout() const { return m_flag_return_timeout; } + bool getFreeTeams() const { return m_free_teams; } + bool getHighPingWorkaround() const { return m_high_ping_workaround; } + int getHitLimit() const { return m_hit_limit; } + std::string getIncompatibleAdvice() const { return m_incompatible_advice; } + int getJitterTolerance() const { return m_jitter_tolerance; } + int getKickIdleLobbyPlayerSeconds() const { return m_kick_idle_lobby_player_seconds; } + int getKickIdlePlayerSeconds() const { return m_kick_idle_player_seconds; } + bool getKicksAllowed() const { return m_kicks_allowed; } + int getMaxPing() const { return m_max_ping; } + int getMinStartGamePlayers() const { return m_min_start_game_players; } + float getOfficialKartsPlayThreshold() const { return m_official_karts_play_threshold; } + float getOfficialTracksPlayThreshold() const { return m_official_tracks_play_threshold; } + bool getOnlyHostRiding() const { return m_only_host_riding; } + bool getOwnerLess() const { return m_owner_less; } + bool getPreserveBattleScores() const { return m_preserve_battle_scores; } + std::string getPrivateServerPassword() const { return m_private_server_password; } + bool getRanked() const { return m_ranked; } + bool getRealAddonKarts() const { return m_real_addon_karts; } + bool getRecordReplays() const { return m_record_replays; } + bool getServerConfigurable() const { return m_server_configurable; } + int getServerDifficulty() const { return m_server_difficulty; } + int getServerMaxPlayers() const { return m_server_max_players; } + int getServerMode() const { return m_server_mode; } + bool getSleepingServer() const { return m_sleeping_server; } + bool getSoccerGoalTarget() const { return m_soccer_goal_target; } + bool getSqlManagement() const { return m_sql_management; } + float getStartGameCounter() const { return m_start_game_counter; } + int getStateFrequency() const { return m_state_frequency; } + bool getStoreResults() const { return m_store_results; } + bool getStrictPlayers() const { return m_strict_players; } + bool getTeamChoosing() const { return m_team_choosing; } + int getTimeLimitCtf() const { return m_time_limit_ctf; } + int getTimeLimitFfa() const { return m_time_limit_ffa; } + bool getTrackKicks() const { return m_track_kicks; } + bool getTrackVoting() const { return m_track_voting; } + std::string getTrollWarnMsg() const { return m_troll_warn_msg; } + bool getValidatingPlayer() const { return m_validating_player; } + float getVotingTimeout() const { return m_voting_timeout; } + std::string getCommandsFile() const { return m_commands_file; } + private: GameSetup* m_game_setup; - std::shared_ptr m_lobby_queues; - - std::shared_ptr m_kart_elimination; - - std::shared_ptr m_asset_manager; - - std::shared_ptr m_tournament; - // These are fine here ======================================================== int m_battle_hit_capture_limit; @@ -202,6 +250,62 @@ class LobbySettings std::string m_available_teams; + bool m_live_players; + + int m_addon_arenas_play_threshold; + int m_addon_karts_play_threshold; + int m_addon_soccers_play_threshold; + int m_addon_tracks_play_threshold; + bool m_ai_anywhere; + bool m_ai_handling; + int m_capture_limit; + bool m_chat; + int m_chat_consecutive_interval; + bool m_expose_mobile; + bool m_firewalled_server; + float m_flag_deactivated_time; + float m_flag_return_timeout; + bool m_free_teams; + bool m_high_ping_workaround; + int m_hit_limit; + std::string m_incompatible_advice; + int m_jitter_tolerance; + int m_kick_idle_lobby_player_seconds; + int m_kick_idle_player_seconds; + bool m_kicks_allowed; + int m_max_ping; + int m_min_start_game_players; + float m_official_karts_play_threshold; + float m_official_tracks_play_threshold; + bool m_only_host_riding; + bool m_owner_less; + bool m_preserve_battle_scores; + std::string m_private_server_password; + bool m_ranked; + bool m_real_addon_karts; + bool m_record_replays; + bool m_server_configurable; + int m_server_difficulty; + int m_server_max_players; + int m_server_mode; + bool m_sleeping_server; + bool m_soccer_goal_target; + bool m_sql_management; + float m_start_game_counter; + int m_state_frequency; + bool m_store_results; + bool m_strict_players; + bool m_team_choosing; + int m_time_limit_ctf; + int m_time_limit_ffa; + bool m_track_kicks; + bool m_track_voting; + std::string m_troll_warn_msg; + bool m_validating_player; + float m_voting_timeout; + std::string m_commands_file; + + // These should be moved to voting manager ==================================== diff --git a/src/utils/map_vote_handler.cpp b/src/utils/map_vote_handler.cpp index 975412fb43b..320601fbb86 100644 --- a/src/utils/map_vote_handler.cpp +++ b/src/utils/map_vote_handler.cpp @@ -16,17 +16,18 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include "utils/map_vote_handler.hpp" + +#include "network/server_config.hpp" #include "utils/lobby_settings.hpp" #include "utils/log.hpp" -#include "utils/map_vote_handler.hpp" #include "utils/random_generator.hpp" #include "utils/string_utils.hpp" -MapVoteHandler::MapVoteHandler(std::shared_ptr settings) - : algorithm(0), m_lobby_settings(settings) +void MapVoteHandler::setupContextUser() { - -} // MapVoteHandler + algorithm = ServerConfig::m_map_vote_handling; +} // setupContextUser //----------------------------------------------------------------------------- @@ -90,14 +91,14 @@ bool MapVoteHandler::random(std::map& peers_votes, if (peers_votes.empty()) { - *winner_vote = m_lobby_settings->getDefaultVote(); + *winner_vote = getSettings()->getDefaultVote(); return true; } RandomGenerator rg; std::map::iterator it = peers_votes.begin(); std::advance(it, rg.get((int)peers_votes.size())); - m_lobby_settings->setWinnerPeerId(it->first); + getSettings()->setWinnerPeerId(it->first); *winner_vote = it->second; return true; } // random @@ -119,13 +120,13 @@ bool MapVoteHandler::standard(std::map& peers_votes, { if (is_over) { - *winner_vote = m_lobby_settings->getDefaultVote(); + *winner_vote = getSettings()->getDefaultVote(); return true; } return false; } - PeerVote default_vote = m_lobby_settings->getDefaultVote(); + PeerVote default_vote = getSettings()->getDefaultVote(); std::string top_track = default_vote.m_track_name; unsigned top_laps = default_vote.m_num_laps; bool top_reverse = default_vote.m_reverse; @@ -184,7 +185,7 @@ bool MapVoteHandler::standard(std::map& peers_votes, if (!is_over) return false; } - m_lobby_settings->setWinnerPeerId(it->first); + getSettings()->setWinnerPeerId(it->first); *winner_vote = it->second; return true; } @@ -205,7 +206,7 @@ bool MapVoteHandler::standard(std::map& peers_votes, else it++; } - m_lobby_settings->setWinnerPeerId(closest_lap->first); + getSettings()->setWinnerPeerId(closest_lap->first); *winner_vote = closest_lap->second; return true; } diff --git a/src/utils/map_vote_handler.hpp b/src/utils/map_vote_handler.hpp index 9d061b4b2bb..d140ee795db 100644 --- a/src/utils/map_vote_handler.hpp +++ b/src/utils/map_vote_handler.hpp @@ -21,6 +21,7 @@ #include "irrString.h" #include "network/peer_vote.hpp" +#include "utils/lobby_context.hpp" #include #include @@ -36,7 +37,7 @@ class LobbySettings; // It can be extended to store some information about previous choices, // but currently it doesn't store or use it. -class MapVoteHandler +class MapVoteHandler: public LobbyContextComponent { // STANDARD = 0 // RANDOM = 1 @@ -44,8 +45,6 @@ class MapVoteHandler private: int algorithm; - std::shared_ptr m_lobby_settings; - template static void findMajorityValue(const std::map& choices, unsigned cur_players, T* best_choice, float* rate); @@ -58,7 +57,9 @@ class MapVoteHandler float remaining_time, float max_time, bool is_over, unsigned cur_players, PeerVote* winner_vote) const; public: - MapVoteHandler(std::shared_ptr settings); + MapVoteHandler(LobbyContext* context): LobbyContextComponent(context) {} + + void setupContextUser() OVERRIDE; void setAlgorithm(int x) { algorithm = x; } int getAlgorithm() const { return algorithm; } diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp index 72f8d9a2941..529f98f7ac3 100644 --- a/src/utils/tournament.cpp +++ b/src/utils/tournament.cpp @@ -21,8 +21,8 @@ #include "utils/track_filter.hpp" #include "network/stk_peer.hpp" #include "network/network_player_profile.hpp" -#include "network/server_config.hpp" #include "network/protocols/server_lobby.hpp" +#include "network/server_config.hpp" #include "network/peer_vote.hpp" #include "modes/world.hpp" #include "modes/soccer_world.hpp" @@ -34,14 +34,12 @@ namespace static int g_history_limit = 100; } -Tournament::Tournament(ServerLobby* lobby, - std::shared_ptr settings) - : m_lobby(lobby), m_lobby_settings(settings) +void Tournament::setupContextUser() { initTournamentPlayers(); m_game = 0; m_extra_seconds = 0.0f; -} // Tournament +} // setupContextUser //----------------------------------------------------------------------------- void Tournament::applyFiltersForThisGame(FilterContext& track_context) @@ -141,17 +139,17 @@ void Tournament::updateTournamentRole(std::shared_ptr peer) core::stringw name = player->getName(); std::string utf8_name = StringUtils::wideToUtf8(name); if (m_red_players.count(utf8_online_name)) - m_lobby->setTeamInLobby(player, KART_TEAM_RED); + getLobby()->setTeamInLobby(player, KART_TEAM_RED); else if (m_blue_players.count(utf8_online_name)) - m_lobby->setTeamInLobby(player, KART_TEAM_BLUE); + getLobby()->setTeamInLobby(player, KART_TEAM_BLUE); else - m_lobby->setTeamInLobby(player, KART_TEAM_NONE); + getLobby()->setTeamInLobby(player, KART_TEAM_NONE); if (hasColorsSwapped()) { if (player->getTeam() == KART_TEAM_BLUE) - m_lobby->setTeamInLobby(player, KART_TEAM_RED); + getLobby()->setTeamInLobby(player, KART_TEAM_RED); else if (player->getTeam() == KART_TEAM_RED) - m_lobby->setTeamInLobby(player, KART_TEAM_BLUE); + getLobby()->setTeamInLobby(player, KART_TEAM_BLUE); } } } // updateTournamentRole @@ -223,7 +221,7 @@ void Tournament::initTournamentPlayers() type == "B" ? m_blue_players : m_referees); - auto categories = m_lobby_settings->getCategories(); + auto categories = getSettings()->getCategories(); for (const std::string& member: categories[cat_name]) dest.insert(member); } diff --git a/src/utils/tournament.hpp b/src/utils/tournament.hpp index 1c3884b3057..3bc0f758cee 100644 --- a/src/utils/tournament.hpp +++ b/src/utils/tournament.hpp @@ -19,6 +19,7 @@ #ifndef TOURNAMENT_HPP #define TOURNAMENT_HPP +#include "utils/lobby_context.hpp" #include "utils/set_with_flip.hpp" #include "utils/tournament_role.hpp" #include "utils/types.hpp" @@ -40,10 +41,12 @@ struct FilterContext; * The current plan is to make it contain generic tournament things, while * specific things like format, modes, etc would be in other new classes. */ -class Tournament +class Tournament: public LobbyContextComponent { public: - Tournament(ServerLobby* lobby, std::shared_ptr settings); + Tournament(LobbyContext* context): LobbyContextComponent(context) {} + + void setupContextUser() OVERRIDE; void initTournamentPlayers(); void applyFiltersForThisGame(FilterContext& track_context); std::set getThoseWhoSeeTeamchats() const; @@ -84,9 +87,6 @@ class Tournament float getExtraSeconds() const { return m_extra_seconds; } private: - ServerLobby* m_lobby; - - std::shared_ptr m_lobby_settings; std::set m_red_players; From 767a1d8b8825191b6137c84353dfd7bce368e085 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 13 Mar 2025 03:33:43 +0400 Subject: [PATCH 596/830] Even less ServerConfig, chat stuff moved to another unit Also refactors for sendString*, getMainName, KartTeamSet, and some functions moved to asset manager. Chat manager will be heavily refactored further. --- src/network/database_connector.cpp | 4 +- src/network/game_setup.cpp | 4 +- src/network/protocols/command_manager.cpp | 442 +++++++++------------- src/network/protocols/server_lobby.cpp | 331 +++------------- src/network/protocols/server_lobby.hpp | 10 +- src/network/remote_kart_info.hpp | 12 + src/network/stk_host.cpp | 3 +- src/network/stk_peer.cpp | 17 +- src/network/stk_peer.hpp | 2 + src/utils/chat_manager.cpp | 318 ++++++++++++++++ src/utils/chat_manager.hpp | 92 +++++ src/utils/hit_processor.cpp | 11 +- src/utils/hit_processor.hpp | 2 + src/utils/lobby_asset_manager.cpp | 103 ++++- src/utils/lobby_asset_manager.hpp | 7 + src/utils/lobby_context.cpp | 5 +- src/utils/lobby_context.hpp | 4 + src/utils/lobby_queues.cpp | 2 +- src/utils/lobby_settings.cpp | 136 +------ src/utils/lobby_settings.hpp | 63 ++- src/utils/tournament.cpp | 74 +++- src/utils/tournament.hpp | 8 + 22 files changed, 893 insertions(+), 757 deletions(-) create mode 100644 src/utils/chat_manager.cpp create mode 100644 src/utils/chat_manager.hpp diff --git a/src/network/database_connector.cpp b/src/network/database_connector.cpp index 95bff2c6648..55a6776617e 100644 --- a/src/network/database_connector.cpp +++ b/src/network/database_connector.cpp @@ -1016,7 +1016,7 @@ void DatabaseConnector::onPlayerJoinQueries(std::shared_ptr peer, peer->getAddress().toString(false), peer->getAddress().getPort(), online_id, - Binder(coll, StringUtils::wideToUtf8(peer->getPlayerProfiles()[0]->getName()), "player_name"), + Binder(coll, peer->getMainName(), "player_name"), player_count, Binder(coll, country_code, "country_code", true), Binder(coll, version_os.first, "version"), @@ -1043,7 +1043,7 @@ void DatabaseConnector::onPlayerJoinQueries(std::shared_ptr peer, peer->getAddress().getIP(), peer->getAddress().getPort(), online_id, - Binder(coll, StringUtils::wideToUtf8(peer->getPlayerProfiles()[0]->getName()), "player_name"), + Binder(coll, peer->getMainName(), "player_name"), player_count, Binder(coll, country_code, "country_code", true), Binder(coll, version_os.first, "version"), diff --git a/src/network/game_setup.cpp b/src/network/game_setup.cpp index a09fd83369b..a74abed6856 100644 --- a/src/network/game_setup.cpp +++ b/src/network/game_setup.cpp @@ -139,13 +139,13 @@ void GameSetup::addServerInfo(NetworkString* ns) if (ServerConfig::m_owner_less) { ns->addUInt8(ServerConfig::m_min_start_game_players) - .addFloat(std::max(0.0f, ServerConfig::m_start_game_counter)); + .addFloat(std::max(0.0f, getSettings()->getStartGameCounter())); } else ns->addUInt8(0).addFloat(0.0f); ns->encodeString16(m_message_of_today); - ns->addUInt8((uint8_t)ServerConfig::m_server_configurable); + ns->addUInt8((uint8_t)getSettings()->getServerConfigurable()); ns->addUInt8(getSettings()->isLivePlayers() ? 1 : 0); } // addServerInfo diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 3dbe978567b..c274aa4c0e2 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -32,6 +32,7 @@ #include "network/stk_peer.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" +#include "utils/chat_manager.hpp" #include "utils/file_utils.hpp" #include "utils/hit_processor.hpp" #include "utils/hourglass_reason.hpp" @@ -411,7 +412,7 @@ void CommandManager::initCommands() // special permissions according to ServerConfig options std::shared_ptr kick_command = mp["kick"].lock(); if (kick_command) { - if (ServerConfig::m_kicks_allowed) + if (getSettings()->getKicksAllowed()) kick_command->m_permissions |= PE_CROWNED; else kick_command->m_permissions &= ~PE_CROWNED; @@ -655,15 +656,13 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) std::string action = "invoke"; std::string username = ""; if (peer->hasPlayerProfiles()) - username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + username = peer->getMainName(); if (argv[0] == "vote") { if (argv.size() == 1 || argv[1] == "vote") { - std::string msg = "Usage: /vote (a command with arguments)"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Usage: /vote (a command with arguments)"); return; } std::reverse(argv.begin(), argv.end()); @@ -694,7 +693,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) msg = "Pick one of " + std::to_string(-1 + (int)m_user_command_replacements[username].size()) + " options using /1, etc., or use /0, or type a different command"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); return; } } @@ -726,21 +725,21 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) if (!command) { // todo change message - std::string msg = "There is no such command but there should be. Very strange. Please report it."; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, + "There is no such command but there should be. Very strange. Please report it."); return; } else if (!isAvailable(command)) { - std::string msg = "You don't have permissions to " + action + " this command"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, + "You don't have permissions to " + action + " this command"); return; } int mask = (permissions & command->m_permissions); if (mask == 0) { - std::string msg = "You don't have permissions to " + action + " this command"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, + "You don't have permissions to " + action + " this command"); return; } int mask_without_voting = (mask & ~PE_VOTED); @@ -804,7 +803,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) int CommandManager::getCurrentModeScope() { int mask = MS_DEFAULT; - if (ServerConfig::m_soccer_tournament) + if (isTournament()) mask |= MS_SOCCER_TOURNAMENT; return mask; } // getCurrentModeScope @@ -840,8 +839,7 @@ void CommandManager::vote(Context& context, std::string category, std::string va } if (!peer->hasPlayerProfiles()) return; - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + std::string username = peer->getMainName(); auto& votable = m_votables[command->m_prefix_name]; bool neededCheck = votable.needsCheck(); votable.castVote(username, category, value); @@ -903,7 +901,7 @@ void CommandManager::error(Context& context, bool is_error) msg = "An error occurred while invoking command \"" + command->getFullName() + "\"."; if (is_error) msg += "\n/!\\ Please report this error to the server owner"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); } // error // ======================================================================== @@ -942,8 +940,7 @@ void CommandManager::process_help(Context& context) error(context); return; } - std::string msg = command->getHelp(); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, command->getHelp()); } // process_help // ======================================================================== @@ -963,7 +960,7 @@ void CommandManager::process_text(Context& context) + " is defined without text"; else response = it->second; - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, response); } // process_text // ======================================================================== @@ -983,7 +980,7 @@ void CommandManager::process_file(Context& context) + command->getFullName(); else response = it->second.get(); - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, response); } // process_text // ======================================================================== @@ -1012,7 +1009,7 @@ void CommandManager::process_auth(Context& context) else response = it->second.get(username, online_id); } - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, response); } // process_text // ======================================================================== @@ -1047,8 +1044,7 @@ void CommandManager::process_commands(Context& context) } if (!valid_prefix) { - result = "There are no available commands with such prefix"; - getLobby()->sendStringToPeer(result, peer); + getLobby()->sendStringToPeer(peer, "There are no available commands with such prefix"); return; } result = (command == m_root_command ? "Available commands" @@ -1081,7 +1077,7 @@ void CommandManager::process_commands(Context& context) } if (had_any_subcommands) result += "\n* has subcommands"; - getLobby()->sendStringToPeer(result, peer); + getLobby()->sendStringToPeer(peer, result); } // process_commands // ======================================================================== @@ -1094,7 +1090,7 @@ void CommandManager::process_replay(Context& context) error(context, true); return; } - if (ServerConfig::m_record_replays) + if (getSettings()->getRecordReplays()) { bool current_state = getSettings()->hasConsentOnReplays(); if (argv.size() >= 2 && argv[1] == "0") @@ -1105,21 +1101,19 @@ void CommandManager::process_replay(Context& context) current_state ^= 1; getSettings()->setConsentOnReplays(current_state); - std::string msg = "Recording ghost replays is now "; - msg += (current_state ? "on" : "off"); - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(std::string("Recording ghost replays is now ") + + (current_state ? "on" : "off")); } else { - std::string msg = "This server doesn't allow recording replays"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "This server doesn't allow recording replays"); } } // process_replay // ======================================================================== void CommandManager::process_start(Context& context) { - if (!ServerConfig::m_owner_less && (context.m_user_permissions & UP_CROWNED) == 0) + if (!getSettings()->getOwnerLess() && (context.m_user_permissions & UP_CROWNED) == 0) { context.m_voting = true; } @@ -1156,19 +1150,18 @@ void CommandManager::process_config(Context& context) msg += get_first_if_exists(m_aux_difficulty_aliases[difficulty]); msg += " "; msg += get_first_if_exists(m_aux_goal_aliases[goal_target ? 1 : 0]); - if (!ServerConfig::m_server_configurable) + if (!getSettings()->getServerConfigurable()) msg += " (not configurable)"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); } // process_config // ======================================================================== void CommandManager::process_config_assign(Context& context) { auto peer = context.m_peer.lock(); - if (!ServerConfig::m_server_configurable) + if (!getSettings()->getServerConfigurable()) { - std::string msg = "Server is not configurable, this command cannot be invoked."; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Server is not configurable, this command cannot be invoked."); return; } const auto& argv = context.m_argv; @@ -1216,8 +1209,8 @@ void CommandManager::process_config_assign(Context& context) if (!getSettings()->isDifficultyAvailable(difficulty) || !getSettings()->isModeAvailable(mode)) { - std::string response = "Mode or difficulty are not permitted on this server"; - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, + "Mode or difficulty are not permitted on this server"); return; } if (context.m_voting) @@ -1252,7 +1245,7 @@ void CommandManager::process_spectate(Context& context) if (!response.empty()) { - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, response); return; } @@ -1276,8 +1269,7 @@ void CommandManager::process_spectate(Context& context) if (getLobby()->m_process_type == PT_CHILD && peer->getHostId() == getLobby()->m_client_server_host_id.load()) { - std::string msg = "Graphical client server cannot spectate"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Graphical client server cannot spectate"); return; } AlwaysSpectateMode type = (value == 2 ? ASM_COMMAND_ABSENT : ASM_COMMAND); @@ -1320,7 +1312,7 @@ void CommandManager::process_addons(Context& context) /*argv[1] == "soccer" ?*/ asset_manager->getAddonSoccers() ))); if (apply_filters) - getLobby()->applyAllFilters(from, false); // happily the type is never karts in this line + getAssetManager()->applyAllFilters(from, false); // happily the type is never karts in this line std::vector>> result; for (const std::string& s: from) result.push_back({s, {}}); @@ -1337,8 +1329,7 @@ void CommandManager::process_addons(Context& context) if (!p->hasPlayerProfiles()) continue; ++num_players; - std::string username = StringUtils::wideToUtf8( - p->getPlayerProfiles()[0]->getName()); + std::string username = p->getMainName(); const auto& kt = p->getClientAssets(); const auto& container = (argv[1] == "kart" ? kt.first : kt.second); for (auto& pr: result) @@ -1372,8 +1363,7 @@ void CommandManager::process_addons(Context& context) result.clear(); std::string asking_username = ""; if (peer->hasPlayerProfiles()) - asking_username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + asking_username = peer->getMainName(); for (unsigned i = 0; i < result2.size(); ++i) { bool present = false; @@ -1430,7 +1420,7 @@ void CommandManager::process_addons(Context& context) response = "No one in the lobby can play. Found " + std::to_string(all_have.size()) + " assets on the server."; } - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, response); } // process_addons // ======================================================================== @@ -1475,8 +1465,7 @@ void CommandManager::process_checkaddon(Context& context) || !getLobby()->canRace(p) || p->isCommandSpectator() || !p->hasPlayerProfiles()) continue; - std::string username = StringUtils::wideToUtf8( - p->getPlayerProfiles()[0]->getName()); + std::string username = p->getMainName(); const auto& kt = p->getClientAssets(); unsigned status = 0; if (kt.first.find(id) != kt.first.end()) @@ -1550,7 +1539,7 @@ void CommandManager::process_checkaddon(Context& context) } response.pop_back(); } - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, response); } // process_checkaddon // ======================================================================== @@ -1571,9 +1560,8 @@ void CommandManager::process_id(Context& context) if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 1, m_stf_all_maps, 3, false, true)) return; - std::string id = argv[1]; - std::string response = "Server knows this map, copy it below:\n" + id; - getLobby()->sendStringToPeer(response, peer); + + getLobby()->sendStringToPeer(peer, "Server knows this map, copy it below:\n" + argv[1]); } // process_id // ======================================================================== @@ -1655,7 +1643,7 @@ void CommandManager::process_lsa(Context& context) msg = msg.substr(0, msg.size() - 2); response = "Server's addons: " + msg; } - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, response); } // process_lsa // ======================================================================== @@ -1716,17 +1704,10 @@ void CommandManager::process_pha(Context& context) } } } - if (found) - { - response = player_name + " has addon " + addon_id; - } - else - { - response = player_name + " has no addon " + addon_id; - } - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, player_name + + " has " + (found ? "" : "no ") + "addon " + addon_id); } // process_pha -// ======================================================================== +// ============================================================================ void CommandManager::process_kick(Context& context) { @@ -1753,9 +1734,8 @@ void CommandManager::process_kick(Context& context) } if (player_peer->isAngryHost()) { - std::string msg = "This player is the owner of this server, " - "and is protected from your actions now"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "This player is the owner of " + "this server, and is protected from your actions now"); return; } if (context.m_voting) @@ -1765,7 +1745,7 @@ void CommandManager::process_kick(Context& context) } Log::info("CommandManager", "%s kicks %s", (peer.get() ? "Crown player" : "Vote"), player_name.c_str()); player_peer->kick(); - if (ServerConfig::m_track_kicks) + if (getSettings()->getTrackKicks()) { std::string auto_report = "[ Auto report caused by kick ]"; getLobby()->writeOwnReport(player_peer, peer, auto_report); @@ -1774,9 +1754,8 @@ void CommandManager::process_kick(Context& context) { Log::info("CommandManager", "%s is now banned", player_name.c_str()); getLobby()->m_temp_banned.insert(player_name); - std::string msg = StringUtils::insertValues( - "%s is now banned", player_name.c_str()); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "%s is now banned", player_name.c_str())); } } // process_kick // ======================================================================== @@ -1803,9 +1782,8 @@ void CommandManager::process_unban(Context& context) } Log::info("CommandManager", "%s is now unbanned", player_name.c_str()); getLobby()->m_temp_banned.erase(player_name); - std::string msg = StringUtils::insertValues( - "%s is now unbanned", player_name.c_str()); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "%s is now unbanned", player_name.c_str())); } // process_unban // ======================================================================== @@ -1832,9 +1810,8 @@ void CommandManager::process_ban(Context& context) } Log::info("CommandManager", "%s is now banned", player_name.c_str()); getLobby()->m_temp_banned.insert(player_name); - std::string msg = StringUtils::insertValues( - "%s is now banned", player_name.c_str()); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "%s is now banned", player_name.c_str())); } // process_ban // ======================================================================== @@ -1858,8 +1835,7 @@ void CommandManager::process_pas(Context& context) error(context); return; } - player_name = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + player_name = peer->getMainName(); } else { @@ -1896,7 +1872,7 @@ void CommandManager::process_pas(Context& context) msg.pop_back(); response = msg; } - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, response); } // process_pas // ======================================================================== @@ -1924,8 +1900,7 @@ void CommandManager::process_everypas(Context& context) continue; if (!p->hasPlayerProfiles()) continue; - std::string player_name = StringUtils::wideToUtf8( - p->getPlayerProfiles()[0]->getName()); + std::string player_name = p->getMainName(); auto &scores = p->getAddonsScores(); std::vector overall; for (int item = 0; item < AS_TOTAL; item++) @@ -1977,7 +1952,7 @@ void CommandManager::process_everypas(Context& context) response += msg; } } - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, response); } // process_everypas // ======================================================================== @@ -1989,7 +1964,6 @@ void CommandManager::process_sha(Context& context) error(context, true); return; } - std::string response; auto& argv = context.m_argv; if (argv.size() != 2) { @@ -2009,15 +1983,8 @@ void CommandManager::process_sha(Context& context) total_addons.insert(all_soccers.begin(), all_soccers.end()); std::string addon_id_test = Addon::createAddonId(argv[1]); bool found = total_addons.find(addon_id_test) != total_addons.end(); - if (found) - { - response = "Server has addon " + argv[1]; - } - else - { - response = "Server has no addon " + argv[1]; - } - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, std::string("Server has ") + + (found ? "" : "no ") + "addon " + argv[1]); } // process_sha // ======================================================================== @@ -2032,7 +1999,6 @@ void CommandManager::process_mute(Context& context) return; } std::string result_msg; - core::stringw player_name; if (argv.size() != 2 || argv[1].empty()) { @@ -2044,8 +2010,9 @@ void CommandManager::process_mute(Context& context) 1, m_stf_present_users, 3, false, false)) return; - player_name = StringUtils::utf8ToWide(argv[1]); - player_peer = STKHost::get()->findPeerByName(player_name); + + std::string player_name = argv[1]; + player_peer = STKHost::get()->findPeerByName(StringUtils::utf8ToWide(player_name)); if (!player_peer || player_peer == peer) { @@ -2053,9 +2020,8 @@ void CommandManager::process_mute(Context& context) return; } - getSettings()->addMutedPlayerFor(peer, player_name); - result_msg = "Muted player " + argv[1]; - getLobby()->sendStringToPeer(result_msg, peer); + getChatManager()->addMutedPlayerFor(peer, player_name); + getLobby()->sendStringToPeer(peer, "Muted player " + player_name); } // process_mute // ======================================================================== @@ -2069,7 +2035,6 @@ void CommandManager::process_unmute(Context& context) error(context, true); return; } - core::stringw player_name; if (argv.size() != 2 || argv[1].empty()) { @@ -2077,16 +2042,15 @@ void CommandManager::process_unmute(Context& context) return; } - player_name = StringUtils::utf8ToWide(argv[1]); + std::string player_name = argv[1]; - if (!getSettings()->removeMutedPlayerFor(peer, player_name)) + if (!getChatManager()->removeMutedPlayerFor(peer, player_name)) { error(context); return; } - std::string result_msg = "Unmuted player " + StringUtils::wideToUtf8(player_name); - getLobby()->sendStringToPeer(result_msg, peer); + getLobby()->sendStringToPeer(peer, "Unmuted player " + player_name); } // process_unmute // ======================================================================== @@ -2100,8 +2064,8 @@ void CommandManager::process_listmute(Context& context) return; } - std::string muted_players = getSettings()->getMutedPlayersAsString(peer); - getLobby()->sendStringToPeer(muted_players, peer); + getLobby()->sendStringToPeer(peer, + getChatManager()->getMutedPlayersAsString(peer)); } // process_listmute // ======================================================================== @@ -2122,22 +2086,19 @@ void CommandManager::process_gnu(Context& context) auto kart_elimination = getKartElimination(); if (turn_on && kart_elimination->isEnabled()) { - std::string msg = "Gnu Elimination mode was already enabled!"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Gnu Elimination mode was already enabled!"); return; } if (!turn_on && !kart_elimination->isEnabled()) { - std::string msg = "Gnu Elimination mode was already off!"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Gnu Elimination mode was already off!"); return; } if (turn_on && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_NORMAL_RACE && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) { - std::string msg = "Gnu Elimination is available only with racing modes"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Gnu Elimination is available only with racing modes"); return; } std::string kart; @@ -2177,14 +2138,12 @@ void CommandManager::process_gnu(Context& context) if (kart == "off") { kart_elimination->disable(); - std::string msg = "Gnu Elimination is now off"; - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers("Gnu Elimination is now off"); } else { kart_elimination->enable(kart); - std::string msg = kart_elimination->getStartingMessage(); - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(kart_elimination->getStartingMessage()); } } // process_gnu // ======================================================================== @@ -2256,7 +2215,7 @@ void CommandManager::process_standings(Context& context) } else if (isGnu) msg = getKartElimination()->getStandings(); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); } // process_standings // ======================================================================== @@ -2268,9 +2227,8 @@ void CommandManager::process_teamchat(Context& context) error(context, true); return; } - getSettings()->addTeamSpeaker(peer); - std::string msg = "Your messages are now addressed to team only"; - getLobby()->sendStringToPeer(msg, peer); + getChatManager()->addTeamSpeaker(peer); + getLobby()->sendStringToPeer(peer, "Your messages are now addressed to team only"); } // process_teamchat // ======================================================================== @@ -2296,9 +2254,8 @@ void CommandManager::process_to(Context& context) return; receivers.push_back(argv[i]); } - getSettings()->setMessageReceiversFor(peer, receivers); - std::string msg = "Successfully changed chat settings"; - getLobby()->sendStringToPeer(msg, peer); + getChatManager()->setMessageReceiversFor(peer, receivers); + getLobby()->sendStringToPeer(peer, "Successfully changed chat settings"); } // process_to // ======================================================================== @@ -2310,9 +2267,8 @@ void CommandManager::process_public(Context& context) error(context, true); return; } - getSettings()->makeChatPublicFor(peer); - std::string s = "Your messages are now public"; - getLobby()->sendStringToPeer(s, peer); + getChatManager()->makeChatPublicFor(peer); + getLobby()->sendStringToPeer(peer, "Your messages are now public"); } // process_public // ======================================================================== @@ -2360,7 +2316,7 @@ void CommandManager::process_record(Context& context) #else response = "This command is not supported."; #endif - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, response); } // process_record // ======================================================================== @@ -2376,8 +2332,7 @@ void CommandManager::process_power(Context& context) if (peer->isAngryHost()) { peer->setAngryHost(false); - std::string msg = "You are now a normal player"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "You are now a normal player"); getLobby()->updatePlayerList(); return; } @@ -2390,19 +2345,17 @@ void CommandManager::process_power(Context& context) online_id = profiles[0]->getOnlineId(); } - std::string password = ServerConfig::m_power_password; + std::string password = getSettings()->getPowerPassword(); bool bad_password = (password.empty() || argv.size() <= 1 || argv[1] != password); bool good_player = (getSettings()->isInHammerWhitelist(username) && online_id != 0); if (bad_password && !good_player) { - std::string msg = "You need to provide the password to have the power"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "You need to provide the password to have the power"); return; } peer->setAngryHost(true); - std::string msg = "Now you finally have the power!"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Now you finally have the power!"); getLobby()->updatePlayerList(); } // process_power // ======================================================================== @@ -2414,8 +2367,7 @@ void CommandManager::process_length(Context& context) error(context, true); return; } - std::string msg = getSettings()->getLapRestrictionsAsString(); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, getSettings()->getLapRestrictionsAsString()); } // process_length // ======================================================================== void CommandManager::process_length_multi(Context& context) @@ -2430,8 +2382,8 @@ void CommandManager::process_length_multi(Context& context) } double value = std::max(0.0, temp_double); getSettings()->setMultiplier(value); - std::string msg = StringUtils::insertValues("Game length is now %f x default", value); - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(StringUtils::insertValues( + "Game length is now %f x default", value)); } // process_length_multi // ======================================================================== void CommandManager::process_length_fixed(Context& context) @@ -2446,29 +2398,26 @@ void CommandManager::process_length_fixed(Context& context) } int value = std::max(0, temp_int); getSettings()->setFixedLapCount(value); - std::string msg = StringUtils::insertValues("Game length is now %d", value); - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(StringUtils::insertValues( + "Game length is now %d", value)); } // process_length_fixed // ======================================================================== void CommandManager::process_length_clear(Context& context) { getSettings()->resetLapRestrictions(); - std::string msg = "Game length will be chosen by players"; - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers("Game length will be chosen by players"); } // process_length_clear // ======================================================================== void CommandManager::process_direction(Context& context) { - std::string msg = getSettings()->getDirectionAsString(); - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(getSettings()->getDirectionAsString()); } // process_direction // ======================================================================== void CommandManager::process_direction_assign(Context& context) { auto& argv = context.m_argv; - std::string msg; if (argv.size() < 2) { error(context); @@ -2480,8 +2429,7 @@ void CommandManager::process_direction_assign(Context& context) error(context); return; } - msg = getSettings()->getDirectionAsString(true); - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(getSettings()->getDirectionAsString(true)); } // process_direction_assign // ======================================================================== @@ -2508,7 +2456,7 @@ void CommandManager::process_queue(Context& context) } } msg.pop_back(); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); } // process_queue // ======================================================================== @@ -2736,8 +2684,7 @@ void CommandManager::process_allowstart(Context& context) return; } - std::string msg = getSettings()->getAllowedToStartAsString(); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, getSettings()->getAllowedToStartAsString()); } // process_allowstart // ======================================================================== @@ -2753,8 +2700,7 @@ void CommandManager::process_allowstart_assign(Context& context) return; } getSettings()->setAllowedToStart(argv[1] != "0"); - std::string msg = getSettings()->getAllowedToStartAsString(true); - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(getSettings()->getAllowedToStartAsString(true)); } // process_allowstart_assign // ======================================================================== @@ -2766,8 +2712,7 @@ void CommandManager::process_shuffle(Context& context) error(context, true); return; } - std::string msg = getSettings()->getWhetherShuffledGPGridAsString(); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, getSettings()->getWhetherShuffledGPGridAsString()); } // process_shuffle // ======================================================================== @@ -2781,8 +2726,7 @@ void CommandManager::process_shuffle_assign(Context& context) return; } getSettings()->setGPGridShuffled(argv[1] != "0"); - std::string msg = getSettings()->getWhetherShuffledGPGridAsString(true); - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(getSettings()->getWhetherShuffledGPGridAsString(true)); } // process_shuffle_assign // ======================================================================== @@ -2794,7 +2738,6 @@ void CommandManager::process_timeout(Context& context) error(context, true); return; } - std::string msg; int seconds; auto& argv = context.m_argv; if (argv.size() < 2 || !StringUtils::parseString(argv[1], &seconds) || seconds <= 0) @@ -2805,8 +2748,7 @@ void CommandManager::process_timeout(Context& context) getLobby()->m_timeout.store((int64_t)StkTime::getMonoTimeMs() + (int64_t)(seconds * 1000.0f)); getLobby()->updatePlayerList(); - msg = "Successfully changed timeout"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Successfully changed timeout"); } // process_timeout // ======================================================================== @@ -2841,9 +2783,8 @@ void CommandManager::process_team(Context& context) // Resetting should be allowed anyway if (!allowed_color && team != TeamUtils::NO_TEAM) { - std::string msg = StringUtils::insertValues("Color %s is not allowed", - argv[1].c_str()); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "Color %s is not allowed", argv[1])); return; } getLobby()->setTemporaryTeamInLobby(player, team); @@ -2907,7 +2848,7 @@ void CommandManager::process_swapteams(Context& context) permutation_map_int[from] = to; } getLobby()->shuffleTemporaryTeams(permutation_map_int); - getLobby()->sendStringToPeer(msg, peer); // todo make public? + getLobby()->sendStringToPeer(peer, msg); // todo make public? getLobby()->updatePlayerList(); } // process_swapteams // ======================================================================== @@ -2920,9 +2861,8 @@ void CommandManager::process_resetteams(Context& context) error(context, true); return; } - std::string msg = "Teams are reset now"; getLobby()->clearTemporaryTeams(); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Teams are reset now"); getLobby()->updatePlayerList(); } // process_resetteams // ======================================================================== @@ -2951,19 +2891,17 @@ void CommandManager::process_randomteams(Context& context) msg = "No one can play!"; else msg = "Teams are currently not allowed"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); return; } - std::string msg = StringUtils::insertValues( - "Created %d teams for %d players", final_number, players_number); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "Created %d teams for %d players", final_number, players_number)); getLobby()->updatePlayerList(); } // process_randomteams // ======================================================================== void CommandManager::process_resetgp(Context& context) { - std::string msg = "GP is now reset"; auto& argv = context.m_argv; if (argv.size() >= 2) { int number_of_games; @@ -2976,7 +2914,7 @@ void CommandManager::process_resetgp(Context& context) getLobby()->getGameSetup()->setGrandPrixTrack(number_of_games); } getLobby()->resetGrandPrix(); - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers("GP is now reset"); } // process_resetgp // ======================================================================== @@ -3055,7 +2993,7 @@ void CommandManager::process_troll(Context& context) msg = "Trolls will be kicked"; else msg = "Trolls can stay"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); } // process_troll // ======================================================================== @@ -3095,7 +3033,7 @@ void CommandManager::process_hitmsg(Context& context) msg = "Teammate hits are sent to all players"; else msg = "Teammate hits are not sent"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); } // process_hitmsg // ======================================================================== @@ -3135,7 +3073,7 @@ void CommandManager::process_teamhit(Context& context) msg = "Teammate hits are punished"; else msg = "Teammate hits are not punished"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); } // process_teamhit // ======================================================================== @@ -3171,8 +3109,7 @@ void CommandManager::process_scoring(Context& context) error(context, true); return; } - std::string msg = getSettings()->getScoringAsString(); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, getSettings()->getScoringAsString()); } // process_scoring // ======================================================================== @@ -3190,13 +3127,11 @@ void CommandManager::process_scoring_assign(Context& context) CommandManager::restoreCmdByArgv(cmd2, argv, ' ', '"', '"', '\\', 1); if (getSettings()->loadCustomScoring(cmd2)) { - msg = "Scoring set to \"" + cmd2 + "\""; - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers("Scoring set to \"" + cmd2 + "\""); } else { - msg = "Scoring could not be parsed from \"" + cmd2 + "\""; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Scoring could not be parsed from \"" + cmd2 + "\""); } } // process_scoring_assign // ======================================================================== @@ -3215,8 +3150,7 @@ void CommandManager::process_register(Context& context) int online_id = peer->getPlayerProfiles()[0]->getOnlineId(); if (online_id <= 0) { - std::string msg = "Please join with a valid online STK account."; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Please join with a valid online STK account."); return; } std::string ans = ""; @@ -3226,13 +3160,11 @@ void CommandManager::process_register(Context& context) ans.push_back(' '); ans += argv[i]; } - std::string message_ok = "Your registration request is being processed"; - std::string message_wrong = "Sorry, an error occurred. Please try again."; - if (getLobby()->writeOnePlayerReport(peer, ServerConfig::m_register_table_name, + if (getLobby()->writeOnePlayerReport(peer, getSettings()->getRegisterTableName(), ans)) - getLobby()->sendStringToPeer(message_ok, peer); + getLobby()->sendStringToPeer(peer, "Your registration request is being processed"); else - getLobby()->sendStringToPeer(message_wrong, peer); + getLobby()->sendStringToPeer(peer, "Sorry, an error occurred. Please try again."); } // process_register // ======================================================================== @@ -3248,8 +3180,7 @@ void CommandManager::process_muteall(Context& context) } if (!peer->hasPlayerProfiles()) return; - std::string peer_username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + std::string peer_username = peer->getMainName(); int op = SWF_OP_FLIP; if (argv.size() >= 2 && argv[1] == "0") @@ -3264,7 +3195,7 @@ void CommandManager::process_muteall(Context& context) msg = "You are now receiving messages only from players and referees"; else msg = "You are now receiving messages from spectators too"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); } // process_muteall // ======================================================================== @@ -3280,8 +3211,7 @@ void CommandManager::process_game(Context& context) } if (!peer->hasPlayerProfiles()) return; - std::string peer_username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + std::string peer_username = peer->getMainName(); int old_game_number; int old_duration; @@ -3312,13 +3242,12 @@ void CommandManager::process_game(Context& context) if (bad) { - std::string msg = StringUtils::insertValues( + // error(context) ? + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( "Please specify a correct number. " "Format: /game [number %d..%d] [length in minutes] [0..59 additional seconds]", tournament->minGameNumber(), - tournament->maxGameNumber()); - // error(context) ? - getLobby()->sendStringToPeer(msg, peer); + tournament->maxGameNumber())); return; } } @@ -3358,8 +3287,7 @@ void CommandManager::process_role(Context& context) } if (!peer->hasPlayerProfiles()) return; - std::string peer_username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + std::string peer_username = peer->getMainName(); if (argv.size() < 3) { error(context); @@ -3417,10 +3345,10 @@ void CommandManager::process_role(Context& context) } if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char)); if (player_peer->hasPlayerProfiles()) getLobby()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_RED); - getLobby()->sendStringToPeer(role_changed, player_peer); + getLobby()->sendStringToPeer(player_peer, + StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } break; } @@ -3437,10 +3365,10 @@ void CommandManager::process_role(Context& context) } if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char)); if (player_peer->hasPlayerProfiles()) getLobby()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_BLUE); - getLobby()->sendStringToPeer(role_changed, player_peer); + getLobby()->sendStringToPeer(player_peer, + StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } break; } @@ -3450,10 +3378,10 @@ void CommandManager::process_role(Context& context) tournament->setReferee(u, permanent); if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char)); if (player_peer->hasPlayerProfiles()) getLobby()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); - getLobby()->sendStringToPeer(role_changed, player_peer); + getLobby()->sendStringToPeer(player_peer, + StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } break; } @@ -3461,10 +3389,10 @@ void CommandManager::process_role(Context& context) { if (player_peer) { - role_changed = StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char)); if (player_peer->hasPlayerProfiles()) getLobby()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); - getLobby()->sendStringToPeer(role_changed, player_peer); + getLobby()->sendStringToPeer(player_peer, + StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } break; } @@ -3489,7 +3417,7 @@ void CommandManager::process_role(Context& context) msg += " " + missing_assets[i]; } } - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); } getLobby()->updatePlayerList(); } // process_role @@ -3507,8 +3435,7 @@ void CommandManager::process_stop(Context& context) return; SoccerWorld *sw = dynamic_cast(w); sw->stop(); - std::string msg = "The game is stopped."; - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers("The game is stopped."); Log::info("CommandManager", "SoccerMatchLog: The game is stopped"); } // process_stop // ======================================================================== @@ -3525,8 +3452,7 @@ void CommandManager::process_go(Context& context) return; SoccerWorld *sw = dynamic_cast(w); sw->resume(); - std::string msg = "The game is resumed."; - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers("The game is resumed."); Log::info("CommandManager", "SoccerMatchLog: The game is resumed"); } // process_go // ======================================================================== @@ -3543,8 +3469,7 @@ void CommandManager::process_lobby(Context& context) return; SoccerWorld *sw = dynamic_cast(w); sw->allToLobby(); - std::string msg = "The game will be restarted."; - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers("The game will be restarted."); } // process_lobby // ======================================================================== @@ -3559,8 +3484,7 @@ void CommandManager::process_init(Context& context) } if (!peer->hasPlayerProfiles()) return; - std::string peer_username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + std::string peer_username = peer->getMainName(); int red, blue; if (argv.size() < 3 || !StringUtils::parseString(argv[1], &red) || @@ -3572,10 +3496,9 @@ void CommandManager::process_init(Context& context) World* w = World::getWorld(); if (!w) { - std::string msg = "Please set the count when the karts " - "are ready. Setting the initial count in lobby is " - "not implemented yet, sorry."; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Please set the count " + "when the karts are ready. Setting the initial count " + "in the lobby is not implemented yet, sorry."); return; } SoccerWorld *sw = dynamic_cast(w); @@ -3599,7 +3522,7 @@ void CommandManager::process_mimiz(Context& context) msg = "please provide text"; else msg = cmd.substr(argv[0].length() + 1); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); } // process_mimiz // ======================================================================== @@ -3609,8 +3532,8 @@ void CommandManager::process_test(Context& context) auto peer = context.m_peer.lock(); if (argv.size() == 1) { - std::string msg = "/test is now deprecated. Use /test *2 [something] [something]"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, + "/test is now deprecated. Use /test *2 [something] [something]"); return; } argv.resize(4, ""); @@ -3627,12 +3550,10 @@ void CommandManager::process_test(Context& context) std::string username = "Vote"; if (peer.get() && peer->hasPlayerProfiles()) { - username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + username = peer->getMainName(); } username = "{" + argv[1].substr(4) + "} " + username; - std::string msg = username + ", " + argv[2] + ", " + argv[3]; - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers(username + ", " + argv[2] + ", " + argv[3]); } // process_test // ======================================================================== @@ -3645,18 +3566,18 @@ void CommandManager::process_slots(Context& context) return; } int current = getLobby()->m_current_max_players_in_game.load(); - std::string msg = "Number of slots is currently " + std::to_string(current); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Number of slots is currently " + + std::to_string(current)); } // process_slots // ======================================================================== void CommandManager::process_slots_assign(Context& context) { - if (ServerConfig::m_only_host_riding) + if (getSettings()->getOnlyHostRiding()) { - std::string msg = "Changing slots is not possible in the singleplayer mode"; auto peer = context.m_peer.lock(); // may be nullptr, here we don't care - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, + "Changing slots is not possible in the singleplayer mode"); return; } auto& argv = context.m_argv; @@ -3664,7 +3585,7 @@ void CommandManager::process_slots_assign(Context& context) int number = 0; if (argv.size() < 2 || !StringUtils::parseString(argv[1], &number)) fail = true; - else if (number <= 0 || number > ServerConfig::m_server_max_players) + else if (number <= 0 || number > getSettings()->getServerMaxPlayers()) fail = true; if (fail) { @@ -3678,8 +3599,7 @@ void CommandManager::process_slots_assign(Context& context) } getLobby()->m_current_max_players_in_game.store((unsigned)number); getLobby()->updatePlayerList(); - std::string msg = "Number of playable slots is now " + argv[1]; - getLobby()->sendStringToAllPeers(msg); + getLobby()->sendStringToAllPeers("Number of playable slots is now " + argv[1]); } // process_slots_assign // ======================================================================== @@ -3691,8 +3611,7 @@ void CommandManager::process_time(Context& context) error(context, true); return; } - std::string msg = "Server time: " + StkTime::getLogTime(); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Server time: " + StkTime::getLogTime()); } // process_time // ======================================================================== @@ -3718,7 +3637,7 @@ void CommandManager::process_result(Context& context) } else msg = "This command is not yet supported for this game mode"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); } // process_result // ======================================================================== @@ -3730,8 +3649,7 @@ void CommandManager::process_preserve(Context& context) error(context, true); return; } - std::string msg = getSettings()->getPreservedSettingsAsString(); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, getSettings()->getPreservedSettingsAsString()); } // process_preserve // ======================================================================== @@ -3779,7 +3697,7 @@ void CommandManager::process_history(Context& context) std::vector arenas = tournament->getMapHistory(); for (unsigned i = 0; i < arenas.size(); i++) msg += StringUtils::insertValues(" [%d]: %s", i, arenas[i].c_str()); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); } // process_history // ======================================================================== @@ -3815,8 +3733,8 @@ void CommandManager::process_history_assign(Context& context) return; } - msg = StringUtils::insertValues("Assigned [%d] to %s in the map history", index, id.c_str()); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "Assigned [%d] to %s in the map history", index, id.c_str())); } // process_history_assign // ======================================================================== @@ -3828,9 +3746,9 @@ void CommandManager::process_voting(Context& context) error(context, true); return; } - std::string msg = StringUtils::insertValues("Voting method: %d", - getMapVoteHandler()->getAlgorithm()); - getLobby()->sendStringToPeer(msg, peer); + + getLobby()->sendStringToPeer(peer, StringUtils::insertValues("Voting method: %d", + getMapVoteHandler()->getAlgorithm())); } // process_voting // ======================================================================== @@ -3856,8 +3774,8 @@ void CommandManager::process_voting_assign(Context& context) return; } getMapVoteHandler()->setAlgorithm(value); - msg = StringUtils::insertValues("Set voting method to %s", value); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "Set voting method to %s", value)); } // process_voting_assign // ======================================================================== @@ -3880,8 +3798,7 @@ void CommandManager::process_why_hourglass(Context& context) error(context); return; } - player_name = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + player_name = peer->getMainName(); } else { @@ -3900,6 +3817,7 @@ void CommandManager::process_why_hourglass(Context& context) auto it = getLobby()->m_why_peer_cannot_play.find(player_peer); if (it == getLobby()->m_why_peer_cannot_play.end()) { + Log::error("CommandManager", "Hourglass status undefined for a player!"); response = "For some reason, server doesn't know about the hourglass status of this player."; } else @@ -3951,7 +3869,7 @@ void CommandManager::process_why_hourglass(Context& context) } response = StringUtils::insertValues(response, player_name.c_str()); } - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, response); } // process_why_hourglass // ======================================================================== @@ -3963,9 +3881,9 @@ void CommandManager::process_available_teams(Context& context) error(context, true); return; } - std::string msg = StringUtils::insertValues("Currently available teams: \"%s\"", - getSettings()->getInternalAvailableTeams().c_str()); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "Currently available teams: \"%s\"", + getSettings()->getInternalAvailableTeams().c_str())); } // process_available_teams // ======================================================================== @@ -4013,7 +3931,7 @@ void CommandManager::process_available_teams_assign(Context& context) if (!ignored.empty()) msg += StringUtils::insertValues( ", but teams \"%s\" were not recognized", ignored); - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, msg); } // process_available_teams_assign // ======================================================================== @@ -4034,12 +3952,12 @@ void CommandManager::special(Context& context) Log::warn("CommandManager", "Command %s was invoked " "but not implemented or unavailable for this server", command->getFullName().c_str()); - std::string msg = "This command (%s) is not implemented, or " + + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "This command (%s) is not implemented, or " "not available for this server. " "If you believe that is a bug, please report it. Full input:\n" - "/%s"; - msg = StringUtils::insertValues(msg, command->getFullName(), cmd); - getLobby()->sendStringToPeer(msg, peer); + "/%s", command->getFullName(), cmd)); } // special // ======================================================================== @@ -4171,8 +4089,7 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, return false; std::string username = ""; if (peer->hasPlayerProfiles()) - username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + username = peer->getMainName(); auto it = m_user_last_correct_argument.find(username); if (it != m_user_last_correct_argument.end() && std::make_pair(idx, subidx) <= it->second) @@ -4189,8 +4106,7 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, auto closest_commands = stf.getClosest(text, top, case_sensitive); if (closest_commands.empty()) { - std::string msg = "Command " + cmd + " not found"; - getLobby()->sendStringToPeer(msg, peer); + getLobby()->sendStringToPeer(peer, "Command " + cmd + " not found"); return true; } bool no_zeros = closest_commands[0].second != 0; @@ -4227,7 +4143,7 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, } argv[idx] = initial_argument; CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); - getLobby()->sendStringToPeer(response, peer); + getLobby()->sendStringToPeer(peer, response); return true; } diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 171c03cb73e..967e28be04b 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -49,6 +49,7 @@ #include "tracks/check_manager.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" +#include "utils/chat_manager.hpp" #include "utils/kart_elimination.hpp" #include "utils/game_info.hpp" #include "utils/hit_processor.hpp" @@ -262,9 +263,9 @@ void ServerLobby::initServerStatsTable() * whenever server is reset or game mode is changed. */ void ServerLobby::updateMapsForMode() { - RaceManager::MinorRaceModeType m = - ServerConfig::getLocalGameMode(m_game_mode.load()).first; - getAssetManager()->updateMapsForMode(m); + getAssetManager()->updateMapsForMode( + ServerConfig::getLocalGameMode(m_game_mode.load()).first + ); } // updateMapsForMode //----------------------------------------------------------------------------- @@ -325,12 +326,13 @@ bool ServerLobby::notifyEvent(Event* event) message_type); switch (message_type) { - case LE_RACE_FINISHED_ACK: playerFinishedResult(event); break; - case LE_LIVE_JOIN: liveJoinRequest(event); break; + case LE_RACE_FINISHED_ACK: playerFinishedResult(event); break; + case LE_LIVE_JOIN: liveJoinRequest(event); break; case LE_CLIENT_LOADED_WORLD: finishedLoadingLiveJoinClient(event); break; - case LE_KART_INFO: handleKartInfo(event); break; - case LE_CLIENT_BACK_LOBBY: clientInGameWantsToBackLobby(event); break; - default: Log::error("ServerLobby", "Unknown message of type %d - ignored.", + case LE_KART_INFO: handleKartInfo(event); break; + case LE_CLIENT_BACK_LOBBY: clientInGameWantsToBackLobby(event); break; + default: + Log::error("ServerLobby", "Unknown message of type %d - ignored.", message_type); break; } // switch message_type @@ -340,186 +342,19 @@ bool ServerLobby::notifyEvent(Event* event) //----------------------------------------------------------------------------- void ServerLobby::handleChat(Event* event) { - if (!checkDataSize(event, 1) || !getSettings()->getChat()) return; - - // Update so that the peer is not kicked - event->getPeer()->updateLastActivity(); - const bool sender_in_game = event->getPeer()->isWaitingForGame(); - - int64_t last_message = event->getPeer()->getLastMessage(); - int64_t elapsed_time = (int64_t)StkTime::getMonoTimeMs() - last_message; - - // Read ServerConfig for formula and details - if (getSettings()->getChatConsecutiveInterval() > 0 && - elapsed_time < getSettings()->getChatConsecutiveInterval() * 1000) - event->getPeer()->updateConsecutiveMessages(true); - else - event->getPeer()->updateConsecutiveMessages(false); + if (!checkDataSize(event, 1) || !getChatManager()->getChat()) return; - if (getSettings()->getChatConsecutiveInterval() > 0 && - event->getPeer()->getConsecutiveMessages() > - getSettings()->getChatConsecutiveInterval() / 2) - { - std::string msg = "Spam detected"; - sendStringToPeer(msg, event->getPeerSP()); - return; - } + auto peer = event->getPeerSP(); core::stringw message; event->data().decodeString16(&message, 360/*max_len*/); - // Check if the message starts with "(the name of main profile): " to prevent - // impersonation, see #5121. - std::string message_utf8 = StringUtils::wideToUtf8(message); - std::string prefix = StringUtils::wideToUtf8( - event->getPeer()->getPlayerProfiles()[0]->getName()) + ": "; - - if (!StringUtils::startsWith(message_utf8, prefix)) - { - std::string warn = "Don't try to impersonate others!"; - sendStringToPeer(warn, event->getPeerSP()); - return; - } - KartTeam target_team = KART_TEAM_NONE; if (event->data().size() > 0) target_team = (KartTeam)event->data().getUInt8(); - if (message.size() > 0) - { - bool add_red_emoji = false; - bool add_blue_emoji = false; - // Red or blue square emoji - if (target_team == KART_TEAM_RED) - add_red_emoji = true; - else if (target_team == KART_TEAM_BLUE) - add_blue_emoji = true; - - NetworkString* chat = getNetworkString(); - chat->setSynchronous(true); - const bool game_started = m_state.load() != WAITING_FOR_START_GAME; - std::shared_ptr sender = event->getPeerSP(); - auto can_receive = getSettings()->getMessageReceiversFor(sender); - if (!can_receive.empty()) - message = StringUtils::utf32ToWide({0x1f512, 0x20}) + message; - bool team_speak = getSettings()->isTeamSpeaker(sender); - team_speak &= ( - RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER || - RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG - ); - std::set teams; - for (auto& profile: sender->getPlayerProfiles()) - teams.insert(profile->getTeam()); - if (team_speak) - { - for (auto &team: teams) - { - if (team == KART_TEAM_RED) - add_red_emoji = true; - else if (team == KART_TEAM_BLUE) - add_blue_emoji = true; - } - } - if (add_blue_emoji) - message = StringUtils::utf32ToWide({0x1f7e6, 0x20}) + message; - if (add_red_emoji) - message = StringUtils::utf32ToWide({0x1f7e5, 0x20}) + message; - bool tournament_limit = false; - if (isTournament()) - tournament_limit = !getTournament()->checkSenderInRefsOrPlayers(sender); - std::set sees_teamchats; - if (isTournament()) - sees_teamchats = getTournament()->getThoseWhoSeeTeamchats(); - - // Note that mutealls are still spectators - std::set important_players; - if (getTournament() && tournament_limit) - { - important_players = getTournament()->getImportantChatPlayers(); - } - chat->addUInt8(LE_CHAT).encodeString16(message); - core::stringw sender_name = - event->getPeer()->getPlayerProfiles()[0]->getName(); - - STKHost::get()->sendPacketToAllPeersWith( - [game_started, sender_in_game, target_team, can_receive, - sender, team_speak, teams, tournament_limit, - important_players, sender_name, sees_teamchats, this](std::shared_ptr p) - { - if (sender == p) - return true; - if (game_started) - { - if (p->isWaitingForGame() && !sender_in_game) - return false; - if (!p->isWaitingForGame() && sender_in_game) - return false; - if (tournament_limit) - { - bool all_are_important = true; - for (auto& player : p->getPlayerProfiles()) - { - std::string name = StringUtils::wideToUtf8( - player->getName()); - if (important_players.count(name) == 0) - { - all_are_important = false; - break; - } - } - if (all_are_important) - return false; - } - if (target_team != KART_TEAM_NONE) - { - if (p->isSpectator()) - return false; - bool someone_good = false; - for (auto& player : p->getPlayerProfiles()) - { - if (player->getTeam() == target_team) - someone_good = true; - std::string name = StringUtils::wideToUtf8( - player->getName()); - if (sees_teamchats.count(name)) - someone_good = true; - } - if (!someone_good) - return false; - } - } - if (getSettings()->isMuting(p, sender_name)) - return false; - if (team_speak) - { - bool someone_good = false; - for (auto& profile: p->getPlayerProfiles()) - { - if (teams.count(profile->getTeam()) > 0) - someone_good = true; - std::string name = StringUtils::wideToUtf8( - profile->getName()); - if (sees_teamchats.count(name)) - someone_good = true; - } - if (!someone_good) - return false; - } - if (can_receive.empty()) - return true; - for (auto& profile : p->getPlayerProfiles()) - { - if (can_receive.find(profile->getName()) != - can_receive.end()) - { - return true; - } - } - return false; - }, chat); - event->getPeer()->updateLastMessage(); - delete chat; - } + getChatManager()->handleNormalChatMessage(peer, + StringUtils::wideToUtf8(message), target_team); } // handleChat //----------------------------------------------------------------------------- @@ -567,9 +402,7 @@ void ServerLobby::kickHost(Event* event) return; if (!getSettings()->getKicksAllowed()) { - std::string msg = "Kicking players is not allowed on this server"; - auto crown = event->getPeerSP(); - sendStringToPeer(msg, crown); + sendStringToPeer(event->getPeerSP(), "Kicking players is not allowed on this server"); return; } if (!checkDataSize(event, 4)) return; @@ -581,10 +414,8 @@ void ServerLobby::kickHost(Event* event) { if (peer->isAngryHost()) { - std::string msg = "This player is the owner of this server, " - "and is protected from your actions now"; - auto crown = event->getPeerSP(); - sendStringToPeer(msg, crown); + sendStringToPeer(event->getPeerSP(), "This player is the owner of this server, " + "and is protected from your actions now"); return; } if (!peer->hasPlayerProfiles()) @@ -797,7 +628,7 @@ void ServerLobby::asynchronousUpdate() m_rs_state.store(RS_NONE); } - getSettings()->clearAllExpiredWeakPtrs(); + getChatManager()->clearAllExpiredWeakPtrs(); #ifdef ENABLE_SQLITE3 pollDatabase(); @@ -1642,15 +1473,14 @@ void ServerLobby::update(int ticks) break; case 1: { - std::string msg = getSettings()->getTrollWarnMsg(); - sendStringToPeer(msg, peer); - std::string player_name = StringUtils::wideToUtf8(peer->getPlayerProfiles()[0]->getName()); + sendStringToPeer(peer, getSettings()->getTrollWarnMsg()); + std::string player_name = peer->getMainName(); Log::info("ServerLobby-AntiTroll", "Sent WARNING to %s", player_name.c_str()); break; } default: { - std::string player_name = StringUtils::wideToUtf8(peer->getPlayerProfiles()[0]->getName()); + std::string player_name = peer->getMainName(); Log::info("ServerLobby-AntiTroll", "KICKING %s", player_name.c_str()); peer->kick(); break; @@ -1676,8 +1506,7 @@ void ServerLobby::update(int ticks) continue; std::string peer_name = ""; if (peer->hasPlayerProfiles()) - peer_name = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()).c_str(); + peer_name = peer->getMainName().c_str(); Log::info("ServerLobby", "%s %s has been idle on the server for " "more than %d seconds, kick.", peer->getAddress().toString().c_str(), peer_name.c_str(), sec); @@ -1943,14 +1772,12 @@ void ServerLobby::startSelection(const Event *event) { if (!getSettings()->isAllowedToStart()) { - std::string msg = "Starting the game is forbidden by server owner"; - sendStringToPeer(msg, peer); + sendStringToPeer(peer, "Starting the game is forbidden by server owner"); return; } if (!canRace(peer)) { - std::string msg = "You cannot play so pressing ready has no action"; - sendStringToPeer(msg, peer); + sendStringToPeer(peer, "You cannot play so pressing ready has no action"); return; } else @@ -1963,8 +1790,7 @@ void ServerLobby::startSelection(const Event *event) } if (!getSettings()->isAllowedToStart()) { - std::string msg = "Starting the game is forbidden by server owner"; - sendStringToPeer(msg, peer); + sendStringToPeer(peer, "Starting the game is forbidden by server owner"); return; } if (!hasHostRights(peer)) @@ -2062,8 +1888,7 @@ void ServerLobby::startSelection(const Event *event) // inside if to not produce log spam for ownerless Log::warn("ServerLobby", "An attempt to start a game while no one can play."); - std::string msg = "No one can play!"; - sendStringToPeer(msg, event->getPeerSP()); + sendStringToPeer(event->getPeerSP(), "No one can play!"); } addWaitingPlayersToGame(); return; @@ -2128,8 +1953,6 @@ void ServerLobby::startSelection(const Event *event) startVotingPeriod(getSettings()->getVotingTimeout()); - std::string ignored_choice_string = "The server will ignore your kart choice"; - peers = STKHost::get()->getPeers(); for (auto& peer: peers) { @@ -2150,9 +1973,9 @@ void ServerLobby::startSelection(const Event *event) std::set all_k = peer->getClientAssets().first; - std::string username = StringUtils::wideToUtf8(peer->getPlayerProfiles()[0]->getName()); + std::string username = peer->getMainName(); // std::string username = StringUtils::wideToUtf8(profile->getName()); - applyAllKartFilters(username, all_k); + getAssetManager()->applyAllKartFilters(username, all_k); if (!getKartElimination()->getRemainingParticipants().empty() && getKartElimination()->getRemainingParticipants().count(username) == 0) { @@ -2168,7 +1991,7 @@ void ServerLobby::startSelection(const Event *event) delete ns; if (getQueues()->areKartFiltersIgnoringKarts()) - sendStringToPeer(ignored_choice_string, peer); + sendStringToPeer(peer, "The server will ignore your kart choice"); } m_state = SELECTING; @@ -2407,7 +2230,7 @@ void ServerLobby::checkRaceFinished() } m_state.store(WAIT_FOR_RACE_STOPPED); - m_map_history.push_back(RaceManager::get()->getTrackName()); + getAssetManager()->gameFinishedOn(RaceManager::get()->getTrackName()); getQueues()->popOnRaceFinished(); } // checkRaceFinished @@ -2474,7 +2297,7 @@ void ServerLobby::clientDisconnected(Event* event) World* w = World::getWorld(); std::shared_ptr peer = event->getPeerSP(); - getSettings()->onPeerDisconnect(peer); + getChatManager()->onPeerDisconnect(peer); // No warnings otherwise, as it could happen during lobby period if (w && m_game_info) saveDisconnectingPeerInfo(peer); @@ -2562,8 +2385,7 @@ bool ServerLobby::handleAssets(const NetworkString& ns, std::shared_ptr { if (peer->isValidated()) { - std::string msg = "You deleted some assets that are required to stay on the server"; - sendStringToPeer(msg, peer); + sendStringToPeer(peer, "You deleted some assets that are required to stay on the server"); peer->kick(); } else @@ -2963,7 +2785,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, message_ack->addFloat(auto_start_timer) .addUInt32(getSettings()->getStateFrequency()) - .addUInt8(getSettings()->getChat() ? 1 : 0) + .addUInt8(getChatManager()->getChat() ? 1 : 0) .addUInt8(playerReportsTableExists() ? 1 : 0); peer->setSpectator(false); @@ -3065,7 +2887,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, msg = "Recording ghost replays is disabled. " "The crowned player can change that " "using /replay 0 (to disable) or /replay 1 (to enable). "; - sendStringToPeer(msg, peer); + sendStringToPeer(peer, msg); } getMessagesFromHost(peer, online_id); @@ -3774,9 +3596,8 @@ void ServerLobby::getMessagesFromHost(std::shared_ptr peer, int online_ for (const auto& message: messages) { Log::info("ServerLobby", "A message from server was delivered"); - std::string msg = "A message from the server (" + - std::string(message.timestamp) + "):\n" + std::string(message.message); - sendStringToPeer(msg, peer); + sendStringToPeer(peer, "A message from the server (" + + std::string(message.timestamp) + "):\n" + std::string(message.message)); m_db_connector->deleteServerMessage(message.row_id); } #endif @@ -3911,7 +3732,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, msg = "This mode is not permitted on this server"; else msg = "This difficulty is not permitted on this server"; - sendStringToPeer(msg, peer); + sendStringToPeer(peer, msg); return; } auto modes = ServerConfig::getLocalGameMode(mode); @@ -4009,13 +3830,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) { getKartElimination()->disable(); - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16( - L"Gnu Elimination is disabled because of non-racing mode"); - sendMessageToPeers(chat); - delete chat; + sendStringToAllPeers("Gnu Elimination is disabled because of non-racing mode"); } } // handleServerConfiguration //----------------------------------------------------------------------------- @@ -4907,7 +4722,8 @@ void ServerLobby::changeColors() updatePlayerList(); } // changeColors //----------------------------------------------------------------------------- -void ServerLobby::sendStringToPeer(std::string& s, std::shared_ptr peer) + +void ServerLobby::sendStringToPeer(std::shared_ptr peer, const std::string& s) { if (!peer) { @@ -4922,7 +4738,8 @@ void ServerLobby::sendStringToPeer(std::string& s, std::shared_ptr peer delete chat; } // sendStringToPeer //----------------------------------------------------------------------------- -void ServerLobby::sendStringToAllPeers(std::string& s) + +void ServerLobby::sendStringToAllPeers(const std::string& s) { NetworkString* chat = getNetworkString(); chat->addUInt8(LE_CHAT); @@ -4932,6 +4749,7 @@ void ServerLobby::sendStringToAllPeers(std::string& s) delete chat; } // sendStringToAllPeers //----------------------------------------------------------------------------- + bool ServerLobby::canRace(std::shared_ptr peer) { auto it = m_why_peer_cannot_play.find(peer); @@ -4943,8 +4761,7 @@ bool ServerLobby::canRace(std::shared_ptr peer) m_why_peer_cannot_play[peer] = HR_ABSENT_PEER; return false; } - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + std::string username = peer->getMainName(); if (getTournament() && !getTournament()->canPlay(username)) { m_why_peer_cannot_play[peer] = HR_NOT_A_TOURNAMENT_PLAYER; @@ -5000,8 +4817,8 @@ bool ServerLobby::canRace(std::shared_ptr peer) return false; } - applyAllFilters(maps, true); - applyAllKartFilters(username, karts, false); + getAssetManager()->applyAllFilters(maps, true); + getAssetManager()->applyAllKartFilters(username, karts, false); if (karts.empty()) { @@ -5291,64 +5108,10 @@ void ServerLobby::resetGrandPrix() } // resetGrandPrix //----------------------------------------------------------------------------- -void ServerLobby::applyAllFilters(std::set& maps, bool use_history) const -{ - unsigned max_player = 0; - STKHost::get()->updatePlayers(&max_player); - if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) - { - auto it = maps.begin(); - while (it != maps.end()) - { - Track* t = TrackManager::get()->getTrack(*it); - if (t && t->getMaxArenaPlayers() < max_player) - { - it = maps.erase(it); - } - else - it++; - } - } - - // Please note that use_history refers to using queue filters too - - // calls with false only get map sets, etc - FilterContext map_context; - map_context.username = ""; // unused - map_context.num_players = max_player; - map_context.wildcards = m_map_history; - map_context.applied_at_selection_start = true; - map_context.elements = maps; - getSettings()->applyGlobalFilter(map_context); - - if (use_history) - { - if (isTournament()) - getTournament()->applyFiltersForThisGame(map_context); - map_context.wildcards = m_map_history; - getQueues()->applyFrontMapFilters(map_context); - } - swap(maps, map_context.elements); -} // applyAllFilters -//----------------------------------------------------------------------------- - -void ServerLobby::applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection) const -{ - FilterContext kart_context; - kart_context.username = username; - kart_context.num_players = 0; // unused - kart_context.wildcards = {}; // unused - kart_context.applied_at_selection_start = !afterSelection; - kart_context.elements = karts; - - getSettings()->applyGlobalKartsFilter(kart_context); - getQueues()->applyFrontKartFilters(kart_context); - swap(karts, kart_context.elements); -} // applyAllKartFilters -//----------------------------------------------------------------------------- std::string ServerLobby::getKartForBadKartChoice(std::shared_ptr peer, const std::string& username, const std::string& check_choice) const { std::set karts = (peer->isAIPeer() ? getAssetManager()->getAvailableKarts() : peer->getClientAssets().first); - applyAllKartFilters(username, karts, true); + getAssetManager()->applyAllKartFilters(username, karts, true); if (getKartElimination()->isEliminated(username) && karts.count(getKartElimination()->getKart())) { diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index cc697015374..4382e0987b1 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -210,8 +210,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser std::set m_temp_banned; - std::vector m_map_history; - std::map m_gp_scores; std::map m_gp_team_scores; @@ -359,8 +357,10 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser const std::string& info); // int getTrackMaxPlayers(std::string& name) const; void updateGnuElimination(); - void sendStringToPeer(std::string& s, std::shared_ptr peer); - void sendStringToAllPeers(std::string& s); + + void sendStringToPeer(std::shared_ptr peer, const std::string& s); + void sendStringToAllPeers(const std::string& s); + int getPermissions(std::shared_ptr peer) const; bool isSoccerGoalTarget() const; @@ -375,8 +375,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser void resetGrandPrix(); void erasePeerReady(std::shared_ptr peer) { m_peers_ready.erase(peer); } - void applyAllFilters(std::set& maps, bool use_history) const; - void applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection = false) const; bool areKartFiltersIgnoringKarts() const; std::string getKartForBadKartChoice(std::shared_ptr peer, const std::string& username, const std::string& check_choice) const; void setKartDataProperly(KartData& kart_data, const std::string& kart_name, diff --git a/src/network/remote_kart_info.hpp b/src/network/remote_kart_info.hpp index 829ace8d4a2..f7c1e936c87 100644 --- a/src/network/remote_kart_info.hpp +++ b/src/network/remote_kart_info.hpp @@ -38,6 +38,18 @@ enum KartTeam : int8_t KART_TEAM_BLUE=1, }; +struct KartTeamSet +{ + int state; + KartTeamSet(int x = 0): state(x) {} + KartTeamSet add (KartTeam team) const { return KartTeamSet(state | (1 << (team + 1))); } + KartTeamSet remove (KartTeam team) const { return KartTeamSet(state & ~(1 << (team + 1))); } + KartTeamSet flip (KartTeam team) const { return KartTeamSet(state ^ (1 << (team + 1))); } + bool has (KartTeam team) const { return ((state >> (team + 1)) & 1); } + KartTeamSet intersect (KartTeamSet rhs) const { return KartTeamSet(state & rhs.state); } + bool empty () const { return state == 0; } +}; + /** Handicap per player. */ enum HandicapLevel : uint8_t { diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index 9808b10deee..60ee0b5b058 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -896,8 +896,7 @@ void STKHost::mainLoop(ProcessType pt) std::string player_name; if (!p.second->getPlayerProfiles().empty()) { - player_name = StringUtils::wideToUtf8 - (p.second->getPlayerProfiles()[0]->getName()); + player_name = p.second->getMainName(); } const bool peer_not_in_game = sl->getCurrentState() <= ServerLobby::SELECTING diff --git a/src/network/stk_peer.cpp b/src/network/stk_peer.cpp index 146fe8bfa03..5032ecde567 100644 --- a/src/network/stk_peer.cpp +++ b/src/network/stk_peer.cpp @@ -23,6 +23,7 @@ #include "network/event.hpp" #include "network/network.hpp" #include "network/network_config.hpp" +#include "network/network_player_profile.hpp" #include "network/network_string.hpp" #include "network/socket_address.hpp" #include "network/stk_ipv6.hpp" @@ -188,9 +189,23 @@ uint32_t STKPeer::getPing() } return m_enet_peer->roundTripTime; } // getPing - //----------------------------------------------------------------------------- + void STKPeer::setCrypto(std::unique_ptr&& c) { m_crypto = std::move(c); } // setCrypto +// ---------------------------------------------------------------------------- + +// A method for convenience only. +// For now, returns an empty string if there are no profiles. +// Might be better to throw an exception. I will see later. +// For now, make sure there are profiles before calling. +std::string STKPeer::getMainName() const +{ + if (m_players.empty()) + return ""; + + return StringUtils::wideToUtf8(m_players[0]->getName()); +} // getMainName +// ------------------------------------------------------------------------ \ No newline at end of file diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index aabe28aaf5f..97a0a3f4c1a 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -383,6 +383,8 @@ class STKPeer : public NoCopy // ------------------------------------------------------------------------ void setAngryHost(bool val) { m_angry_host.store(val); } // ------------------------------------------------------------------------ + std::string getMainName() const; + // ------------------------------------------------------------------------ }; // STKPeer #endif // STK_PEER_HPP diff --git a/src/utils/chat_manager.cpp b/src/utils/chat_manager.cpp new file mode 100644 index 00000000000..644f7b9728d --- /dev/null +++ b/src/utils/chat_manager.cpp @@ -0,0 +1,318 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/chat_manager.hpp" + +#include "network/server_config.hpp" +#include "utils/string_utils.hpp" +#include "utils/tournament.hpp" +#include "network/protocols/server_lobby.hpp" +#include "utils/string_utils.hpp" +#include "network/stk_peer.hpp" +#include "network/network_player_profile.hpp" +#include "network/network_string.hpp" +#include "network/stk_host.hpp" +#include "network/remote_kart_info.hpp" + +namespace +{ + const std::string g_red_team = StringUtils::utf32ToUtf8({0x1f7e5, 0x20}); + const std::string g_blue_team = StringUtils::utf32ToUtf8({0x1f7e6, 0x20}); + const std::string g_private_chat = StringUtils::utf32ToUtf8({0x1f512, 0x20}); +}; + + +void ChatManager::setupContextUser() +{ + m_chat = ServerConfig::m_chat; + m_chat_consecutive_interval = ServerConfig::m_chat_consecutive_interval; +} // setupContextUser +//----------------------------------------------------------------------------- + +void ChatManager::addMutedPlayerFor(std::shared_ptr peer, + const std::string& name) +{ + m_peers_muted_players[std::weak_ptr(peer)].insert(name); +} // addMutedPlayerFor +//----------------------------------------------------------------------------- + +bool ChatManager::removeMutedPlayerFor(std::shared_ptr peer, + const std::string& name) +{ + // I'm not sure why the implementation was so long + auto& collection = m_peers_muted_players[std::weak_ptr(peer)]; + for (auto it = collection.begin(); it != collection.end(); ) + { + if (*it == name) + { + it = collection.erase(it); + return true; + } + else + it++; + } + return false; +} // removeMutedPlayerFor +//----------------------------------------------------------------------------- + +bool ChatManager::isMuting(std::shared_ptr peer, + const std::string& name) const +{ + auto it = m_peers_muted_players.find(std::weak_ptr(peer)); + if (it == m_peers_muted_players.end()) + return false; + + return it->second.find(name) != it->second.end(); +} // isMuting +//----------------------------------------------------------------------------- + +std::string ChatManager::getMutedPlayersAsString(std::shared_ptr peer) +{ + std::string response; + int num_players = 0; + for (auto& name : m_peers_muted_players[std::weak_ptr(peer)]) + { + response += name; + response += " "; + ++num_players; + } + if (num_players == 0) + response = "No player has been muted by you"; + else + { + response += (num_players == 1 ? "is" : "are"); + response += StringUtils::insertValues(" muted (total: %s)", num_players); + } + return response; +} // getMutedPlayersAsString +//----------------------------------------------------------------------------- + +void ChatManager::addTeamSpeaker(std::shared_ptr peer) +{ + m_team_speakers.insert(peer); +} // addTeamSpeaker +//----------------------------------------------------------------------------- + +void ChatManager::setMessageReceiversFor(std::shared_ptr peer, + const std::vector& receivers) +{ + auto& thing = m_message_receivers[peer]; + thing.clear(); + for (unsigned i = 0; i < receivers.size(); ++i) + thing.insert(receivers[i]); +} // setMessageReceiversFor +//----------------------------------------------------------------------------- + +std::set ChatManager::getMessageReceiversFor( + std::shared_ptr peer) const +{ + auto it = m_message_receivers.find(peer); + if (it == m_message_receivers.end()) + return {}; + + return it->second; +} // getMessageReceiversFor +//----------------------------------------------------------------------------- + +bool ChatManager::isTeamSpeaker(std::shared_ptr peer) const +{ + return m_team_speakers.find(peer) != m_team_speakers.end(); +} // isTeamSpeaker +//----------------------------------------------------------------------------- + +void ChatManager::makeChatPublicFor(std::shared_ptr peer) +{ + m_message_receivers[peer].clear(); + m_team_speakers.erase(peer); +} // makeChatPublicFor +//----------------------------------------------------------------------------- + +void ChatManager::clearAllExpiredWeakPtrs() +{ + for (auto it = m_peers_muted_players.begin(); + it != m_peers_muted_players.end();) + { + if (it->first.expired()) + it = m_peers_muted_players.erase(it); + else + it++; + } +} // clearAllExpiredWeakPtrs +//----------------------------------------------------------------------------- + +void ChatManager::onPeerDisconnect(std::shared_ptr peer) +{ + m_message_receivers.erase(peer); +} // onPeerDisconnect +//----------------------------------------------------------------------------- + +void ChatManager::handleNormalChatMessage(std::shared_ptr peer, + std::string message, KartTeam target_team) +{ + // Update so that the peer is not kicked + peer->updateLastActivity(); + + int64_t last_message = peer->getLastMessage(); + int64_t elapsed_time = (int64_t)StkTime::getMonoTimeMs() - last_message; + + int interval = getChatConsecutiveInterval(); + + + // Read ServerConfig for formula and details + bool too_fast = interval > 0 && elapsed_time < interval * 1000; + peer->updateConsecutiveMessages(too_fast); + + if (interval > 0 && peer->getConsecutiveMessages() > interval / 2) + { + getLobby()->sendStringToPeer(peer, "Spam detected"); + return; + } + + + // Check if the message starts with "(the name of main profile): " to prevent + // impersonation, see #5121. + std::string prefix = peer->getMainName() + ": "; + + if (!StringUtils::startsWith(message, prefix)) + { + getLobby()->sendStringToPeer(peer, "Don't try to impersonate others!"); + return; + } + + if (message.size() == 0) + return; + + const bool game_started = !getLobby()->isWaitingForStartGame(); + auto can_receive = getMessageReceiversFor(peer); + if (!can_receive.empty()) + message = g_private_chat + message; + + bool team_mode = ( + RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER || + RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG + ); + + bool team_speaker = isTeamSpeaker(peer); + KartTeamSet teams = getTeamsForPeer(peer); + + // Add team emojis + if (target_team == KART_TEAM_RED || (team_speaker && team_mode && teams.has(KART_TEAM_RED))) + message = g_red_team + message; + + if (target_team == KART_TEAM_BLUE || (team_speaker && team_mode && teams.has(KART_TEAM_BLUE))) + message = g_blue_team + message; + + NetworkString* chat = getLobby()->getNetworkString(); + chat->setSynchronous(true); + chat->addUInt8(getLobby()->LE_CHAT).encodeString16(StringUtils::utf8ToWide(message)); + + STKHost::get()->sendPacketToAllPeersWith( + std::bind(&ChatManager::shouldMessageBeSent, + this, + peer, + std::placeholders::_1, + game_started, + target_team + ), chat + ); + delete chat; + + peer->updateLastMessage(); +} // handleNormalChatMessage +//----------------------------------------------------------------------------- + +bool ChatManager::shouldMessageBeSent(std::shared_ptr sender, + std::shared_ptr target, + bool game_started, + KartTeam target_team) +{ + if (sender == target) + return true; + if (game_started) + { + if (target->isWaitingForGame() ^ sender->isWaitingForGame()) + return false; + + if (target_team != KART_TEAM_NONE) + { + if (target->isSpectator()) + return false; + } + + if (isTournament()) + { + auto tournament = getTournament(); + if (tournament->cannotSendForSureDueToRoles(sender, target)) + return false; + + if (target_team != KART_TEAM_NONE) + { + if (!tournament->hasProfileThatSeesTeamchats(target) && + !tournament->hasProfileFromTeam(target, target_team)) + return false; + } + } + } + if (isMuting(target, sender->getMainName())) + return false; + + if (isTeamSpeaker(sender)) + { + // this should be moved into a new function for peer, + // unless all profiles have the same team forcibly rn + bool someone_good = !(getTeamsForPeer(sender).intersect(getTeamsForPeer(target))).empty(); + if (!someone_good && (!isTournament() || !getTournament()->hasProfileThatSeesTeamchats(target))) + return false; + } + return isInPrivateChatRecipients(sender, target); +} // lambda +//----------------------------------------------------------------------------- + +// Should be called not once per message. Fix later +KartTeamSet ChatManager::getTeamsForPeer(std::shared_ptr peer) const +{ + KartTeamSet teams; + + for (auto& profile: peer->getPlayerProfiles()) + teams.add(profile->getTeam()); + + return teams; +} // getTeamsForPeer +//----------------------------------------------------------------------------- + +bool ChatManager::isInPrivateChatRecipients(std::shared_ptr sender, + std::shared_ptr target) const +{ + // shouldn't be called every time, fix later + std::set can_receive = getMessageReceiversFor(sender); + + // If no private chat enabled, send + if (can_receive.empty()) + return true; + + for (auto& profile : target->getPlayerProfiles()) + { + if (can_receive.find(StringUtils::wideToUtf8(profile->getName())) != + can_receive.end()) + { + return true; + } + } + return false; +} // isInPrivateChatRecipients +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/chat_manager.hpp b/src/utils/chat_manager.hpp new file mode 100644 index 00000000000..77350d4c89c --- /dev/null +++ b/src/utils/chat_manager.hpp @@ -0,0 +1,92 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef CHAT_MANAGER_HPP +#define CHAT_MANAGER_HPP + +#include "irrString.h" +#include "utils/lobby_context.hpp" +#include "utils/types.hpp" + +#include +#include +#include + +class STKPeer; +enum KartTeam : int8_t; +struct KartTeamSet; + +class ChatManager: public LobbyContextComponent +{ +public: + ChatManager(LobbyContext* context): LobbyContextComponent(context) {} + + void setupContextUser() OVERRIDE; + +private: + std::map, std::set, + std::owner_less > > m_peers_muted_players; + + std::map, std::set> m_message_receivers; + + std::set> m_team_speakers; + + bool m_chat; + + int m_chat_consecutive_interval; + +public: + void addMutedPlayerFor(std::shared_ptr peer, + const std::string& name); + + bool removeMutedPlayerFor(std::shared_ptr peer, + const std::string& name); + + bool isMuting(std::shared_ptr peer, + const std::string& name) const; + + std::string getMutedPlayersAsString(std::shared_ptr peer); + void addTeamSpeaker(std::shared_ptr peer); + + void setMessageReceiversFor(std::shared_ptr peer, + const std::vector& receivers); + + std::set getMessageReceiversFor( + std::shared_ptr peer) const; + + bool isTeamSpeaker(std::shared_ptr peer) const; + void makeChatPublicFor(std::shared_ptr peer); + void clearAllExpiredWeakPtrs(); + void onPeerDisconnect(std::shared_ptr peer); + bool getChat() const { return m_chat; } + int getChatConsecutiveInterval() const { return m_chat_consecutive_interval; } + + void handleNormalChatMessage(std::shared_ptr peer, + std::string message, KartTeam target_team); + + bool shouldMessageBeSent(std::shared_ptr sender, + std::shared_ptr target, + bool game_started, + KartTeam target_team); + + KartTeamSet getTeamsForPeer(std::shared_ptr peer) const; + bool isInPrivateChatRecipients(std::shared_ptr sender, + std::shared_ptr target) const; +}; + +#endif // CHAT_MANAGER_HPP \ No newline at end of file diff --git a/src/utils/hit_processor.cpp b/src/utils/hit_processor.cpp index 5dfe85b2231..4944817c8ab 100644 --- a/src/utils/hit_processor.cpp +++ b/src/utils/hit_processor.cpp @@ -38,6 +38,8 @@ namespace return kart->getAttachment()->getType(); } + const float g_hit_message_delay = 1.5f; + } // namespace //----------------------------------------------------------------------------- @@ -46,6 +48,7 @@ void HitProcessor::setupContextUser() m_troll_active = ServerConfig::m_troll_active; m_show_hits = ServerConfig::m_show_teammate_hits; m_hit_mode = ServerConfig::m_teammate_hit_mode; + m_message_prefix = ServerConfig::m_teammate_hit_msg_prefix; m_last_hit_msg = 0; m_swatter_punish.clear(); @@ -93,7 +96,7 @@ void HitProcessor::sendTeammateHitMsg(std::string& s) return; int ticks = w->getTicksSinceStart(); - if (ticks - m_last_hit_msg > stk_config->time2Ticks(1.5f)) + if (ticks - m_last_hit_msg > stk_config->time2Ticks(g_hit_message_delay)) { m_last_hit_msg = ticks; getLobby()->sendStringToAllPeers(s); @@ -134,7 +137,7 @@ void HitProcessor::processHitMessage(const std::string& owner_name, int owner_te { // prepare string int num_victims = 0; - std::string msg = ServerConfig::m_teammate_hit_msg_prefix; + std::string msg = m_message_prefix; std::string victims; msg += owner_name; msg += " just shot "; @@ -239,7 +242,7 @@ void HitProcessor::handleSwatterHit(unsigned int ownerID, unsigned int victimID, { std::string msg = StringUtils::insertValues( "%s%s just swattered teammate %s", - std::string(ServerConfig::m_teammate_hit_msg_prefix).c_str(), + m_message_prefix.c_str(), owner_name.c_str(), victim_name.c_str() ); @@ -285,7 +288,7 @@ void HitProcessor::handleAnvilHit(unsigned int ownerID, unsigned int victimID) { std::string msg = StringUtils::insertValues( "%s%s just gave an anchor to teammate %s", - std::string(ServerConfig::m_teammate_hit_msg_prefix).c_str(), + m_message_prefix.c_str(), owner_name.c_str(), victim_name.c_str() ); diff --git a/src/utils/hit_processor.hpp b/src/utils/hit_processor.hpp index 333aaa7e8aa..5fef119c358 100644 --- a/src/utils/hit_processor.hpp +++ b/src/utils/hit_processor.hpp @@ -51,6 +51,8 @@ class HitProcessor: public LobbyContextComponent bool m_show_hits; // Whether to show messages about team hits. bool m_hit_mode; // Whether to anvil the team hitters. + + std::string m_message_prefix; int m_last_hit_msg; // Last tick when the message was shown. diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp index 19ec4c20897..dc94a1aa387 100644 --- a/src/utils/lobby_asset_manager.cpp +++ b/src/utils/lobby_asset_manager.cpp @@ -24,12 +24,16 @@ #include "network/network_string.hpp" #include "network/protocols/server_lobby.hpp" #include "network/server_config.hpp" +#include "network/stk_host.hpp" #include "network/stk_peer.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" -#include "utils/random_generator.hpp" +#include "utils/lobby_queues.hpp" #include "utils/lobby_settings.hpp" +#include "utils/random_generator.hpp" #include "utils/string_utils.hpp" +#include "utils/tournament.hpp" + void LobbyAssetManager::setupContextUser() { @@ -245,7 +249,7 @@ void LobbyAssetManager::eraseAssetsWithPeers( bool LobbyAssetManager::tryApplyingMapFilters() { std::set available_tracks_fallback = m_available_kts.second; - getLobby()->applyAllFilters(m_available_kts.second, true); + applyAllFilters(m_available_kts.second, true); /* auto iter = m_available_kts.second.begin(); while (iter != m_available_kts.second.end()) @@ -344,16 +348,18 @@ bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer, } } + auto settings = getSettings(); + Log::info("LobbyAssetManager", "Player has the following addons: %d/%d(%d) karts," " %d/%d(%d) tracks, %d/%d(%d) arenas, %d/%d(%d) soccer fields.", - addon_karts, (int)ServerConfig::m_addon_karts_join_threshold, - (int)ServerConfig::m_addon_karts_play_threshold, - addon_tracks, (int)ServerConfig::m_addon_tracks_join_threshold, - (int)ServerConfig::m_addon_tracks_play_threshold, - addon_arenas, (int)ServerConfig::m_addon_arenas_join_threshold, - (int)ServerConfig::m_addon_arenas_play_threshold, - addon_soccers, (int)ServerConfig::m_addon_soccers_join_threshold, - (int)ServerConfig::m_addon_soccers_play_threshold); + addon_karts, settings->getAddonKartsJoinThreshold(), + settings->getAddonKartsPlayThreshold(), + addon_tracks, settings->getAddonTracksJoinThreshold(), + settings->getAddonTracksPlayThreshold(), + addon_arenas, settings->getAddonArenasJoinThreshold(), + settings->getAddonArenasPlayThreshold(), + addon_soccers, settings->getAddonSoccersJoinThreshold(), + settings->getAddonSoccersPlayThreshold()); bool bad = false; @@ -386,37 +392,37 @@ bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer, bad = true; } - if (okt < ServerConfig::m_official_karts_threshold) + if (okt < getSettings()->getOfficialKartsThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: bad official kart threshold"); bad = true; } - if (ott < ServerConfig::m_official_tracks_threshold) + if (ott < getSettings()->getOfficialTracksThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: bad official track threshold"); bad = true; } - if (addon_karts < (int)ServerConfig::m_addon_karts_join_threshold) + if (addon_karts < getSettings()->getAddonKartsJoinThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: too little addon karts"); bad = true; } - if (addon_tracks < (int)ServerConfig::m_addon_tracks_join_threshold) + if (addon_tracks < getSettings()->getAddonTracksJoinThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: too little addon tracks"); bad = true; } - if (addon_arenas < (int)ServerConfig::m_addon_arenas_join_threshold) + if (addon_arenas < getSettings()->getAddonArenasJoinThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: too little addon arenas"); bad = true; } - if (addon_soccers < (int)ServerConfig::m_addon_soccers_join_threshold) + if (addon_soccers < getSettings()->getAddonSoccersJoinThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: too little addon soccers"); bad = true; @@ -540,7 +546,7 @@ std::string LobbyAssetManager::getRandomMap() const for (const std::string& s: m_entering_kts.second) { items.insert(s); } - getLobby()->applyAllFilters(items, false); + applyAllFilters(items, false); if (items.empty()) return ""; RandomGenerator rg; @@ -558,7 +564,7 @@ std::string LobbyAssetManager::getRandomAddonMap() const if (t->isAddon()) items.insert(s); } - getLobby()->applyAllFilters(items, false); + applyAllFilters(items, false); if (items.empty()) return ""; RandomGenerator rg; @@ -573,3 +579,64 @@ void LobbyAssetManager::setMustHaveMaps(const std::string& input) m_must_have_maps = StringUtils::split(input, ' ', false); } // setMustHaveMaps //----------------------------------------------------------------------------- + +void LobbyAssetManager::gameFinishedOn(const std::string& map_name) +{ + m_map_history.push_back(map_name); +} // gameFinishedOn +//----------------------------------------------------------------------------- + +void LobbyAssetManager::applyAllFilters(std::set& maps, bool use_history) const +{ + unsigned max_player = 0; + STKHost::get()->updatePlayers(&max_player); + if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) + { + auto it = maps.begin(); + while (it != maps.end()) + { + Track* t = TrackManager::get()->getTrack(*it); + if (t && t->getMaxArenaPlayers() < max_player) + { + it = maps.erase(it); + } + else + it++; + } + } + + // Please note that use_history refers to using queue filters too - + // calls with false only get map sets, etc + FilterContext map_context; + map_context.username = ""; // unused + map_context.num_players = max_player; + map_context.wildcards = m_map_history; + map_context.applied_at_selection_start = true; + map_context.elements = maps; + getSettings()->applyGlobalFilter(map_context); + + if (use_history) + { + if (isTournament()) + getTournament()->applyFiltersForThisGame(map_context); + map_context.wildcards = m_map_history; + getQueues()->applyFrontMapFilters(map_context); + } + swap(maps, map_context.elements); +} // applyAllFilters +//----------------------------------------------------------------------------- + +void LobbyAssetManager::applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection) const +{ + FilterContext kart_context; + kart_context.username = username; + kart_context.num_players = 0; // unused + kart_context.wildcards = {}; // unused + kart_context.applied_at_selection_start = !afterSelection; + kart_context.elements = karts; + + getSettings()->applyGlobalKartsFilter(kart_context); + getQueues()->applyFrontKartFilters(kart_context); + swap(karts, kart_context.elements); +} // applyAllKartFilters +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/lobby_asset_manager.hpp b/src/utils/lobby_asset_manager.hpp index 8839a411011..d2e0e7ff3b9 100644 --- a/src/utils/lobby_asset_manager.hpp +++ b/src/utils/lobby_asset_manager.hpp @@ -73,6 +73,11 @@ class LobbyAssetManager: public LobbyContextComponent std::set getAvailableKarts() const { return m_available_kts.first; } void setMustHaveMaps(const std::string& input); + void gameFinishedOn(const std::string& map_name); + + void applyAllFilters(std::set& maps, bool use_history) const; + void applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection = false) const; + std::set getAddonKarts() const { return m_addon_kts.first; } std::set getAddonTracks() const { return m_addon_kts.second; } @@ -110,6 +115,8 @@ class LobbyAssetManager: public LobbyContextComponent std::pair, std::set > m_entering_kts; std::vector m_must_have_maps; + + std::vector m_map_history; }; #endif // LOBBY_ASSET_MANAGER_HPP diff --git a/src/utils/lobby_context.cpp b/src/utils/lobby_context.cpp index 1a826e87f47..48db3bc2546 100644 --- a/src/utils/lobby_context.cpp +++ b/src/utils/lobby_context.cpp @@ -19,6 +19,7 @@ #include "utils/lobby_context.hpp" #include "network/protocols/command_manager.hpp" +#include "utils/chat_manager.hpp" #include "utils/hit_processor.hpp" #include "utils/kart_elimination.hpp" #include "utils/lobby_asset_manager.hpp" @@ -38,6 +39,7 @@ LobbyContext::LobbyContext(ServerLobby* lobby, bool make_tournament) m_lobby_settings = std::make_shared(this); m_map_vote_handler = std::make_shared(this); m_command_manager = std::make_shared(this); + m_chat_manager = std::make_shared(this); if (make_tournament) m_tournament = std::make_shared(this); @@ -53,9 +55,10 @@ void LobbyContext::setup() m_lobby_queues->setupContextUser(); m_lobby_settings->setupContextUser(); m_map_vote_handler->setupContextUser(); + m_chat_manager->setupContextUser(); m_command_manager->setupContextUser(); if (m_tournament) m_tournament->setupContextUser(); } // setup -//----------------------------------------------------------------------------- \ No newline at end of file +//----------------------------------------------------------------------------- diff --git a/src/utils/lobby_context.hpp b/src/utils/lobby_context.hpp index f83db6888fe..e6c65023d96 100644 --- a/src/utils/lobby_context.hpp +++ b/src/utils/lobby_context.hpp @@ -23,6 +23,7 @@ #include +class ChatManager; class CommandManager; class HitProcessor; class KartElimination; @@ -45,6 +46,7 @@ class LobbyContext std::shared_ptr m_kart_elimination; std::shared_ptr m_map_vote_handler; std::shared_ptr m_command_manager; + std::shared_ptr m_chat_manager; public: @@ -62,6 +64,7 @@ class LobbyContext std::shared_ptr getKartElimination() const { return m_kart_elimination; } std::shared_ptr getMapVoteHandler() const { return m_map_vote_handler; } std::shared_ptr getCommandManager() const { return m_command_manager; } + std::shared_ptr getChatManager() const { return m_chat_manager; } }; class LobbyContextUser @@ -78,6 +81,7 @@ class LobbyContextUser std::shared_ptr getKartElimination() const { return m_context->getKartElimination(); } std::shared_ptr getMapVoteHandler() const { return m_context->getMapVoteHandler(); } std::shared_ptr getCommandManager() const { return m_context->getCommandManager(); } + std::shared_ptr getChatManager() const { return m_context->getChatManager(); } public: void setContext(LobbyContext* context) { m_context = context; } diff --git a/src/utils/lobby_queues.cpp b/src/utils/lobby_queues.cpp index e46314de2b1..839f90baddb 100644 --- a/src/utils/lobby_queues.cpp +++ b/src/utils/lobby_queues.cpp @@ -147,5 +147,5 @@ bool LobbyQueues::areKartFiltersIgnoringKarts() const return true; return false; -} // applyAllKartFilters +} // areKartFiltersIgnoringKarts //----------------------------------------------------------------------------- diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index 10902a51a82..e9f5af7dbf7 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -74,15 +74,9 @@ void LobbySettings::setupContextUser() m_live_players = ServerConfig::m_live_players; - m_addon_arenas_play_threshold = ServerConfig::m_addon_arenas_play_threshold; - m_addon_karts_play_threshold = ServerConfig::m_addon_karts_play_threshold; - m_addon_soccers_play_threshold = ServerConfig::m_addon_soccers_play_threshold; - m_addon_tracks_play_threshold = ServerConfig::m_addon_tracks_play_threshold; m_ai_anywhere = ServerConfig::m_ai_anywhere; m_ai_handling = ServerConfig::m_ai_handling; m_capture_limit = ServerConfig::m_capture_limit; - m_chat = ServerConfig::m_chat; - m_chat_consecutive_interval = ServerConfig::m_chat_consecutive_interval; m_expose_mobile = ServerConfig::m_expose_mobile; m_firewalled_server = ServerConfig::m_firewalled_server; m_flag_deactivated_time = ServerConfig::m_flag_deactivated_time; @@ -126,6 +120,18 @@ void LobbySettings::setupContextUser() m_validating_player = ServerConfig::m_validating_player; m_voting_timeout = ServerConfig::m_voting_timeout; m_commands_file = ServerConfig::m_commands_file; + m_addon_karts_join_threshold = ServerConfig::m_addon_karts_join_threshold; + m_addon_tracks_join_threshold = ServerConfig::m_addon_tracks_join_threshold; + m_addon_arenas_join_threshold = ServerConfig::m_addon_arenas_join_threshold; + m_addon_soccers_join_threshold = ServerConfig::m_addon_soccers_join_threshold; + m_addon_arenas_play_threshold = ServerConfig::m_addon_arenas_play_threshold; + m_addon_karts_play_threshold = ServerConfig::m_addon_karts_play_threshold; + m_addon_soccers_play_threshold = ServerConfig::m_addon_soccers_play_threshold; + m_addon_tracks_play_threshold = ServerConfig::m_addon_tracks_play_threshold; + m_power_password = ServerConfig::m_power_password; + m_register_table_name = ServerConfig::m_register_table_name; + m_official_karts_threshold = ServerConfig::m_official_karts_threshold; + m_official_tracks_threshold = ServerConfig::m_official_tracks_threshold; } // setupContextUser //----------------------------------------------------------------------------- @@ -299,104 +305,6 @@ int LobbySettings::getTeamForUsername(const std::string& name) } // getTeamForUsername //----------------------------------------------------------------------------- -void LobbySettings::addMutedPlayerFor(std::shared_ptr peer, - const irr::core::stringw& name) -{ - m_peers_muted_players[std::weak_ptr(peer)].insert(name); -} // addMutedPlayerFor -//----------------------------------------------------------------------------- - -bool LobbySettings::removeMutedPlayerFor(std::shared_ptr peer, - const irr::core::stringw& name) -{ - // I'm not sure why the implementation was so long - auto& collection = m_peers_muted_players[std::weak_ptr(peer)]; - for (auto it = collection.begin(); it != collection.end(); ) - { - if (*it == name) - { - it = collection.erase(it); - return true; - } - else - it++; - } - return false; -} // removeMutedPlayerFor -//----------------------------------------------------------------------------- - -bool LobbySettings::isMuting(std::shared_ptr peer, - const irr::core::stringw& name) const -{ - auto it = m_peers_muted_players.find(std::weak_ptr(peer)); - if (it == m_peers_muted_players.end()) - return false; - - return it->second.find(name) != it->second.end(); -} // isMuting -//----------------------------------------------------------------------------- - -std::string LobbySettings::getMutedPlayersAsString(std::shared_ptr peer) -{ - std::string response; - int num_players = 0; - for (auto& name : m_peers_muted_players[std::weak_ptr(peer)]) - { - response += StringUtils::wideToUtf8(name); - response += " "; - ++num_players; - } - if (num_players == 0) - response = "No player has been muted by you"; - else - { - response += (num_players == 1 ? "is" : "are"); - response += StringUtils::insertValues(" muted (total: %s)", num_players); - } - return response; -} // getMutedPlayersAsString -//----------------------------------------------------------------------------- - -void LobbySettings::addTeamSpeaker(std::shared_ptr peer) -{ - m_team_speakers.insert(peer); -} // addTeamSpeaker -//----------------------------------------------------------------------------- - -void LobbySettings::setMessageReceiversFor(std::shared_ptr peer, - const std::vector& receivers) -{ - auto& thing = m_message_receivers[peer]; - thing.clear(); - for (unsigned i = 0; i < receivers.size(); ++i) - thing.insert(StringUtils::utf8ToWide(receivers[i])); -} // setMessageReceiversFor -//----------------------------------------------------------------------------- - -std::set LobbySettings::getMessageReceiversFor( - std::shared_ptr peer) const -{ - auto it = m_message_receivers.find(peer); - if (it == m_message_receivers.end()) - return {}; - - return it->second; -} // getMessageReceiversFor -//----------------------------------------------------------------------------- - -bool LobbySettings::isTeamSpeaker(std::shared_ptr peer) const -{ - return m_team_speakers.find(peer) != m_team_speakers.end(); -} // isTeamSpeaker -//----------------------------------------------------------------------------- - -void LobbySettings::makeChatPublicFor(std::shared_ptr peer) -{ - m_message_receivers[peer].clear(); - m_team_speakers.erase(peer); -} // makeChatPublicFor -//----------------------------------------------------------------------------- - bool LobbySettings::hasNoLapRestrictions() const { return m_default_lap_multiplier < 0. && m_fixed_lap < 0; @@ -712,19 +620,6 @@ void LobbySettings::insertIntoPreserved(const std::string& value) } // insertIntoPreserved //----------------------------------------------------------------------------- -void LobbySettings::clearAllExpiredWeakPtrs() -{ - for (auto it = m_peers_muted_players.begin(); - it != m_peers_muted_players.end();) - { - if (it->first.expired()) - it = m_peers_muted_players.erase(it); - else - it++; - } -} // clearAllExpiredWeakPtrs -//----------------------------------------------------------------------------- - void LobbySettings::initializeDefaultVote() { m_default_vote->m_track_name = getAssetManager()->getRandomAvailableMap(); @@ -887,13 +782,6 @@ PeerVote LobbySettings::getDefaultVote() const } // getDefaultVote //----------------------------------------------------------------------------- - -void LobbySettings::onPeerDisconnect(std::shared_ptr peer) -{ - m_message_receivers.erase(peer); -} // onPeerDisconnect -//----------------------------------------------------------------------------- - bool LobbySettings::isInWhitelist(const std::string& username) const { return m_usernames_white_list.find(username) != m_usernames_white_list.end(); diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 8e5986e10fa..b155073a01f 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -69,20 +69,6 @@ class LobbySettings: public LobbyContextComponent std::string getHelpMessage() const { return m_help_message; } std::string getMotd() const { return m_motd; } - void addMutedPlayerFor(std::shared_ptr peer, - const irr::core::stringw& name); - bool removeMutedPlayerFor(std::shared_ptr peer, - const irr::core::stringw& name); - bool isMuting(std::shared_ptr peer, - const irr::core::stringw& name) const; - std::string getMutedPlayersAsString(std::shared_ptr peer); - void addTeamSpeaker(std::shared_ptr peer); - void setMessageReceiversFor(std::shared_ptr peer, - const std::vector& receivers); - std::set getMessageReceiversFor( - std::shared_ptr peer) const; - bool isTeamSpeaker(std::shared_ptr peer) const; - void makeChatPublicFor(std::shared_ptr peer); bool hasNoLapRestrictions() const; bool hasMultiplier() const; bool hasFixedLapCount() const; @@ -117,7 +103,6 @@ class LobbySettings: public LobbyContextComponent std::string getPreservedSettingsAsString() const; void eraseFromPreserved(const std::string& value); void insertIntoPreserved(const std::string& value); - void clearAllExpiredWeakPtrs(); void initializeDefaultVote(); void applyGlobalFilter(FilterContext& map_context) const; void applyGlobalKartsFilter(FilterContext& kart_context) const; @@ -125,7 +110,6 @@ class LobbySettings: public LobbyContextComponent void encodeDefaultVote(NetworkString* ns) const; void setDefaultVote(PeerVote winner_vote); PeerVote getDefaultVote() const; - void onPeerDisconnect(std::shared_ptr peer); bool isInWhitelist(const std::string& username) const; bool isModeAvailable(int mode) const; bool isDifficultyAvailable(int difficulty) const; @@ -148,15 +132,9 @@ class LobbySettings: public LobbyContextComponent // These were used unchanged from ServerConfig bool isLivePlayers() const { return m_live_players; } - int getAddonArenasPlayThreshold() const { return m_addon_arenas_play_threshold; } - int getAddonKartsPlayThreshold() const { return m_addon_karts_play_threshold; } - int getAddonSoccersPlayThreshold() const { return m_addon_soccers_play_threshold; } - int getAddonTracksPlayThreshold() const { return m_addon_tracks_play_threshold; } bool canConnectAiAnywhere() const { return m_ai_anywhere; } bool getAiHandling() const { return m_ai_handling; } int getCaptureLimit() const { return m_capture_limit; } - bool getChat() const { return m_chat; } - int getChatConsecutiveInterval() const { return m_chat_consecutive_interval; } bool getExposeMobile() const { return m_expose_mobile; } bool getFirewalledServer() const { return m_firewalled_server; } float getFlagDeactivatedTime() const { return m_flag_deactivated_time; } @@ -200,6 +178,18 @@ class LobbySettings: public LobbyContextComponent bool getValidatingPlayer() const { return m_validating_player; } float getVotingTimeout() const { return m_voting_timeout; } std::string getCommandsFile() const { return m_commands_file; } + int getAddonKartsJoinThreshold() const { return m_addon_karts_join_threshold; } + int getAddonTracksJoinThreshold() const { return m_addon_tracks_join_threshold; } + int getAddonArenasJoinThreshold() const { return m_addon_arenas_join_threshold; } + int getAddonSoccersJoinThreshold() const { return m_addon_soccers_join_threshold; } + int getAddonKartsPlayThreshold() const { return m_addon_karts_play_threshold; } + int getAddonTracksPlayThreshold() const { return m_addon_tracks_play_threshold; } + int getAddonArenasPlayThreshold() const { return m_addon_arenas_play_threshold; } + int getAddonSoccersPlayThreshold() const { return m_addon_soccers_play_threshold; } + std::string getPowerPassword() const { return m_power_password; } + std::string getRegisterTableName() const { return m_register_table_name; } + float getOfficialKartsThreshold() const { return m_official_karts_threshold; } + float getOfficialTracksThreshold() const { return m_official_tracks_threshold; } private: GameSetup* m_game_setup; @@ -252,15 +242,9 @@ class LobbySettings: public LobbyContextComponent bool m_live_players; - int m_addon_arenas_play_threshold; - int m_addon_karts_play_threshold; - int m_addon_soccers_play_threshold; - int m_addon_tracks_play_threshold; bool m_ai_anywhere; bool m_ai_handling; int m_capture_limit; - bool m_chat; - int m_chat_consecutive_interval; bool m_expose_mobile; bool m_firewalled_server; float m_flag_deactivated_time; @@ -304,7 +288,18 @@ class LobbySettings: public LobbyContextComponent bool m_validating_player; float m_voting_timeout; std::string m_commands_file; - + int m_addon_karts_join_threshold; + int m_addon_tracks_join_threshold; + int m_addon_arenas_join_threshold; + int m_addon_soccers_join_threshold; + int m_addon_arenas_play_threshold; + int m_addon_karts_play_threshold; + int m_addon_soccers_play_threshold; + int m_addon_tracks_play_threshold; + std::string m_power_password; + std::string m_register_table_name; + float m_official_karts_threshold; + float m_official_tracks_threshold; // These should be moved to voting manager ==================================== @@ -316,16 +311,6 @@ class LobbySettings: public LobbyContextComponent uint32_t m_winner_peer_id; -// These should be moved to chat handler ====================================== - - std::map, std::set, - std::owner_less > > m_peers_muted_players; - - std::map, std::set> m_message_receivers; - - std::set> m_team_speakers; - - // These should be moved to category and team manager ========================= std::map> m_player_categories; diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp index 529f98f7ac3..6747b192fca 100644 --- a/src/utils/tournament.cpp +++ b/src/utils/tournament.cpp @@ -132,8 +132,7 @@ void Tournament::updateTournamentRole(std::shared_ptr peer) { if (peer->getPlayerProfiles().empty()) return; - std::string utf8_online_name = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + std::string utf8_online_name = peer->getMainName(); for (auto& player: peer->getPlayerProfiles()) { core::stringw name = player->getName(); @@ -296,7 +295,7 @@ void Tournament::initTournamentPlayers() } else m_length = 10; - ServerConfig::m_fixed_lap_count = m_length; + getSettings()->setFixedLapCount(m_length); m_game_limits = general[2]; m_colors = general[3]; @@ -317,8 +316,7 @@ bool Tournament::canPlay(const std::string& username) const bool Tournament::canVote(std::shared_ptr peer) const { - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + std::string username = peer->getMainName(); bool first = m_red_players.count(username) > 0; bool second = m_blue_players.count(username) > 0; @@ -333,16 +331,14 @@ bool Tournament::canVote(std::shared_ptr peer) const bool Tournament::hasHostRights(std::shared_ptr peer) { - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + std::string username = peer->getMainName(); return m_referees.count(username) > 0; } // hasHostRights //----------------------------------------------------------------------------- bool Tournament::hasHammerRights(std::shared_ptr peer) { - std::string username = StringUtils::wideToUtf8( - peer->getPlayerProfiles()[0]->getName()); + std::string username = peer->getMainName(); return m_referees.count(username) > 0; } // hasHammerRights //----------------------------------------------------------------------------- @@ -365,7 +361,7 @@ int Tournament::getNextGameNumber() const int Tournament::getDefaultDuration() const { - return ServerConfig::m_fixed_lap_count; + return getSettings()->getFixedLapCount(); } // getDefaultDuration //----------------------------------------------------------------------------- @@ -452,4 +448,62 @@ bool Tournament::assignToHistory(int index, const std::string& map_id) m_arenas[index] = map_id; return true; } // assignToHistory +//----------------------------------------------------------------------------- + +bool Tournament::peerHasOnlyImportantProfiles(std::shared_ptr peer) const +{ + // This has to be called much rarer than once per call + std::set important = getImportantChatPlayers(); + + for (auto& player : peer->getPlayerProfiles()) + { + std::string name = StringUtils::wideToUtf8( + player->getName()); + if (important.count(name) == 0) + { + return false; + } + } + return true; +} // peerHasOnlyImportantProfiles +//----------------------------------------------------------------------------- + +bool Tournament::cannotSendForSureDueToRoles(std::shared_ptr sender, + std::shared_ptr target) const +{ + if (checkSenderInRefsOrPlayers(sender)) + return false; + if (peerHasOnlyImportantProfiles(target)) + return true; + + return false; +} // cannotSendForSureDueToRoles +//----------------------------------------------------------------------------- + +bool Tournament::hasProfileThatSeesTeamchats(std::shared_ptr peer) const +{ + // shouldn't be done once per call - obviously I could just say they should be + // referees, but what if I change it? Better to rework it separately + std::set those_who_see_teamchats = getThoseWhoSeeTeamchats(); + + for (auto& player : peer->getPlayerProfiles()) + { + std::string name = StringUtils::wideToUtf8( + player->getName()); + if (those_who_see_teamchats.count(name)) + return true; + } + return false; +} // hasProfileThatSeesTeamchats +//----------------------------------------------------------------------------- + +bool Tournament::hasProfileFromTeam(std::shared_ptr peer, KartTeam target_team) const +{ + for (auto& player : peer->getPlayerProfiles()) + { + if (player->getTeam() == target_team) + return true; + } + return false; +} // hasProfileFromTeam //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/tournament.hpp b/src/utils/tournament.hpp index 3bc0f758cee..035e1c70cd3 100644 --- a/src/utils/tournament.hpp +++ b/src/utils/tournament.hpp @@ -86,6 +86,14 @@ class Tournament: public LobbyContextComponent float getExtraSeconds() const { return m_extra_seconds; } + bool peerHasOnlyImportantProfiles(std::shared_ptr peer) const; + + bool cannotSendForSureDueToRoles(std::shared_ptr sender, + std::shared_ptr target) const; + + bool hasProfileThatSeesTeamchats(std::shared_ptr peer) const; + bool hasProfileFromTeam(std::shared_ptr peer, KartTeam target_team) const; + private: std::set m_red_players; From cbec871b504d994af5583494fab9c6843442091d Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 13 Mar 2025 23:46:19 +0400 Subject: [PATCH 597/830] Team stuff moved to team manager (Not tested) --- src/network/protocols/command_manager.cpp | 35 ++-- src/network/protocols/server_lobby.cpp | 130 ++++-------- src/network/protocols/server_lobby.hpp | 9 +- src/utils/chat_manager.hpp | 1 + src/utils/hit_processor.cpp | 17 +- src/utils/lobby_context.cpp | 3 + src/utils/lobby_context.hpp | 4 + src/utils/lobby_settings.cpp | 142 ------------- src/utils/lobby_settings.hpp | 39 ---- src/utils/team_manager.cpp | 239 ++++++++++++++++++++++ src/utils/team_manager.hpp | 88 ++++++++ src/utils/team_utils.cpp | 16 +- src/utils/team_utils.hpp | 8 +- src/utils/tournament.cpp | 13 +- 14 files changed, 419 insertions(+), 325 deletions(-) create mode 100644 src/utils/team_manager.cpp create mode 100644 src/utils/team_manager.hpp diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index c274aa4c0e2..70ef8c14ffa 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -45,6 +45,7 @@ #include "utils/map_vote_handler.hpp" #include "utils/random_generator.hpp" #include "utils/string_utils.hpp" +#include "utils/team_manager.hpp" #include "utils/tournament.hpp" #include @@ -2347,7 +2348,7 @@ void CommandManager::process_power(Context& context) std::string password = getSettings()->getPowerPassword(); bool bad_password = (password.empty() || argv.size() <= 1 || argv[1] != password); - bool good_player = (getSettings()->isInHammerWhitelist(username) + bool good_player = (getTeamManager()->isInHammerWhitelist(username) && online_id != 0); if (bad_password && !good_player) { @@ -2776,7 +2777,7 @@ void CommandManager::process_team(Context& context) if (!argv[1].empty()) { std::string temp(1, argv[1][0]); - if (getSettings()->getAvailableTeams().find(temp) != std::string::npos) + if (getTeamManager()->getAvailableTeams().find(temp) != std::string::npos) allowed_color = true; } int team = TeamUtils::getIndexByCode(argv[1]); @@ -2847,7 +2848,7 @@ void CommandManager::process_swapteams(Context& context) int to = TeamUtils::getIndexByCode(std::string(1, p.second)); permutation_map_int[from] = to; } - getLobby()->shuffleTemporaryTeams(permutation_map_int); + getTeamManager()->shuffleTemporaryTeams(permutation_map_int); getLobby()->sendStringToPeer(peer, msg); // todo make public? getLobby()->updatePlayerList(); } // process_swapteams @@ -2861,7 +2862,7 @@ void CommandManager::process_resetteams(Context& context) error(context, true); return; } - getLobby()->clearTemporaryTeams(); + getTeamManager()->clearTemporaryTeams(); getLobby()->sendStringToPeer(peer, "Teams are reset now"); getLobby()->updatePlayerList(); } // process_resetteams @@ -2940,7 +2941,7 @@ void CommandManager::process_cat(Context& context) 2, m_stf_present_users, 3, false, true)) return; std::string player = argv[2]; - getSettings()->addPlayerToCategory(player, category); + getTeamManager()->addPlayerToCategory(player, category); getLobby()->updatePlayerList(); return; } @@ -2957,7 +2958,7 @@ void CommandManager::process_cat(Context& context) 2, m_stf_present_users, 3, false, true)) return; player = argv[2]; - getSettings()->erasePlayerFromCategory(player, category); + getTeamManager()->erasePlayerFromCategory(player, category); getLobby()->updatePlayerList(); return; } @@ -2972,7 +2973,7 @@ void CommandManager::process_cat(Context& context) return; } std::string category = argv[1]; - getSettings()->makeCategoryVisible(category, displayed); + getTeamManager()->makeCategoryVisible(category, displayed); getLobby()->updatePlayerList(); return; } @@ -3316,7 +3317,7 @@ void CommandManager::process_role(Context& context) if (!username.empty()) { if (username[0] == '#') - changed_usernames = getSettings()->getPlayersInCategory(username.substr(1)); + changed_usernames = getTeamManager()->getPlayersInCategory(username.substr(1)); else changed_usernames.insert(username); } @@ -3346,7 +3347,7 @@ void CommandManager::process_role(Context& context) if (player_peer) { if (player_peer->hasPlayerProfiles()) - getLobby()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_RED); + getTeamManager()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_RED); getLobby()->sendStringToPeer(player_peer, StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } @@ -3366,7 +3367,7 @@ void CommandManager::process_role(Context& context) if (player_peer) { if (player_peer->hasPlayerProfiles()) - getLobby()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_BLUE); + getTeamManager()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_BLUE); getLobby()->sendStringToPeer(player_peer, StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } @@ -3379,7 +3380,7 @@ void CommandManager::process_role(Context& context) if (player_peer) { if (player_peer->hasPlayerProfiles()) - getLobby()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); + getTeamManager()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); getLobby()->sendStringToPeer(player_peer, StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } @@ -3390,7 +3391,7 @@ void CommandManager::process_role(Context& context) if (player_peer) { if (player_peer->hasPlayerProfiles()) - getLobby()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); + getTeamManager()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); getLobby()->sendStringToPeer(player_peer, StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } @@ -3883,7 +3884,7 @@ void CommandManager::process_available_teams(Context& context) } getLobby()->sendStringToPeer(peer, StringUtils::insertValues( "Currently available teams: \"%s\"", - getSettings()->getInternalAvailableTeams().c_str())); + getTeamManager()->getInternalAvailableTeams().c_str())); } // process_available_teams // ======================================================================== @@ -3926,7 +3927,7 @@ void CommandManager::process_available_teams_assign(Context& context) ignored.push_back(c); for (char c: value_set) value.push_back(c); - getSettings()->setInternalAvailableTeams(value); + getTeamManager()->setInternalAvailableTeams(value); msg = StringUtils::insertValues("Set available teams to \"%s\"", value); if (!ignored.empty()) msg += StringUtils::insertValues( @@ -3981,7 +3982,7 @@ bool CommandManager::assignRandomTeams(int intended_number, return false; } int max_number_of_teams = TeamUtils::getNumberOfTeams(); - std::string available_colors_string = getSettings()->getAvailableTeams(); + std::string available_colors_string = getTeamManager()->getAvailableTeams(); if (available_colors_string.empty()) return false; if (max_number_of_teams > (int)available_colors_string.length()) @@ -4012,7 +4013,7 @@ bool CommandManager::assignRandomTeams(int intended_number, std::shuffle(profile_colors.begin(), profile_colors.end(), g); - getLobby()->clearTemporaryTeams(); + getTeamManager()->clearTemporaryTeams(); for (auto& p : STKHost::get()->getPeers()) { if (!getLobby()->canRace(p)) @@ -4020,7 +4021,7 @@ bool CommandManager::assignRandomTeams(int intended_number, if (p->alwaysSpectateButNotNeutral()) continue; for (auto& profile : p->getPlayerProfiles()) { - getLobby()->setTemporaryTeamInLobby(profile, profile_colors.back()); + getTeamManager()->setTemporaryTeamInLobby(profile, profile_colors.back()); if (profile_colors.size() > 1) // prevent crash just in case profile_colors.pop_back(); } diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 967e28be04b..c86cd5e0c87 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -57,6 +57,7 @@ #include "utils/lobby_settings.hpp" #include "utils/lobby_queues.hpp" #include "utils/map_vote_handler.hpp" +#include "utils/team_manager.hpp" #include "utils/tournament.hpp" #include "utils/translation.hpp" @@ -384,13 +385,13 @@ void ServerLobby::changeTeam(Event* event) { if (red_blue.first >= 7 && !getSettings()->getFreeTeams()) return; - setTeamInLobby(player, KART_TEAM_RED); + getTeamManager()->setTeamInLobby(player, KART_TEAM_RED); } else { if (red_blue.second >= 7 && !getSettings()->getFreeTeams()) return; - setTeamInLobby(player, KART_TEAM_BLUE); + getTeamManager()->setTeamInLobby(player, KART_TEAM_BLUE); } updatePlayerList(); } // changeTeam @@ -1253,7 +1254,7 @@ int ServerLobby::getReservedId(std::shared_ptr& p, { if (rki.getKartTeam() == target_team) { - setTeamInLobby(p, target_team); + getTeamManager()->setTeamInLobby(p, target_team); rki.copyFrom(p, local_id); return i; } @@ -2165,7 +2166,7 @@ void ServerLobby::checkRaceFinished() gp_changes.back() += points_fl; cur_score += points_fl; } - int team = getSettings()->getTeamForUsername(username); + int team = getTeamManager()->getTeamForUsername(username); if (team > 0) { m_gp_team_scores[team].score += cur_score; @@ -2697,8 +2698,8 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, std::string username = StringUtils::wideToUtf8(player->getName()); // kimden: I'm not sure why the check is double - if (getSettings()->hasTeam(username)) - previous_team = getSettings()->getTeamForUsername(username); + if (getTeamManager()->hasTeam(username)) + previous_team = getTeamManager()->getTeamForUsername(username); bool can_change_teams = true; if (getTournament() && !getTournament()->canChangeTeam()) @@ -2721,13 +2722,13 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, } } if (cur_team != KART_TEAM_NONE) - setTeamInLobby(player, cur_team); + getTeamManager()->setTeamInLobby(player, cur_team); } if (isTournament()) { KartTeam team = getTournament()->getTeam(utf8_online_name); if (team != KART_TEAM_NONE) - setTeamInLobby(player, team); + getTeamManager()->setTeamInLobby(player, team); } getCommandManager()->addUser(username); if (m_game_setup->isGrandPrix()) @@ -2743,14 +2744,14 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, { if (previous_team != -1) { - setTemporaryTeamInLobby(player, previous_team); + getTeamManager()->setTemporaryTeamInLobby(player, previous_team); } } peer->addPlayer(player); // As it sets spectating mode for peer based on which players it has, // we need to set the team once again to the same thing - setTemporaryTeamInLobby(player, player->getTemporaryTeam()); + getTeamManager()->setTemporaryTeamInLobby(player, player->getTemporaryTeam()); } peer->setValidated(true); @@ -2989,7 +2990,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) profile_name = StringUtils::utf32ToWide({0x1F528}) + profile_name; std::string prefix = ""; - for (const std::string& category: getSettings()->getVisibleCategoriesForPlayer(utf8_profile_name)) + for (const std::string& category: getTeamManager()->getVisibleCategoriesForPlayer(utf8_profile_name)) { prefix += category + ", "; } @@ -3798,12 +3799,12 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, if (teams_after) { int final_number, players_number; - getSettings()->clearTeams(); + getTeamManager()->clearTeams(); getCommandManager()->assignRandomTeams(2, &final_number, &players_number); } else { - clearTemporaryTeams(); + getTeamManager()->clearTemporaryTeams(); } for (auto& peer : STKHost::get()->getPeers()) { @@ -3812,7 +3813,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, for (auto &profile: peer->getPlayerProfiles()) { // updates KartTeam - setTemporaryTeamInLobby(profile, profile->getTemporaryTeam()); + getTeamManager()->setTemporaryTeamInLobby(profile, profile->getTemporaryTeam()); } } } @@ -4711,11 +4712,11 @@ void ServerLobby::changeColors() auto pp = peer->getPlayerProfiles()[0]; if (pp->getTeam() == KART_TEAM_RED) { - setTeamInLobby(pp, KART_TEAM_BLUE); + getTeamManager()->setTeamInLobby(pp, KART_TEAM_BLUE); } else if (pp->getTeam() == KART_TEAM_BLUE) { - setTeamInLobby(pp, KART_TEAM_RED); + getTeamManager()->setTeamInLobby(pp, KART_TEAM_RED); } } } @@ -5041,7 +5042,7 @@ void ServerLobby::setTemporaryTeamInLobby(const std::string& username, int team) { if (profile->getName() == wide_player_name) { - setTemporaryTeamInLobby(profile, team); + getTeamManager()->setTemporaryTeamInLobby(profile, team); break; } } @@ -5049,49 +5050,6 @@ void ServerLobby::setTemporaryTeamInLobby(const std::string& username, int team) } // setTemporaryTeamInLobby (username) //----------------------------------------------------------------------------- -// todo This should be moved later to another unit. -void ServerLobby::clearTemporaryTeams() -{ - getSettings()->clearTeams(); - - for (auto& peer : STKHost::get()->getPeers()) - { - for (auto& profile : peer->getPlayerProfiles()) - { - setTemporaryTeamInLobby(profile, TeamUtils::NO_TEAM); - } - } -} // clearTemporaryTeams -//----------------------------------------------------------------------------- - -// todo This should be moved later to another unit. -void ServerLobby::shuffleTemporaryTeams(const std::map& permutation) -{ - getSettings()->applyPermutationToTeams(permutation); - for (auto& peer : STKHost::get()->getPeers()) - { - for (auto &profile: peer->getPlayerProfiles()) - { - auto it = permutation.find(profile->getTemporaryTeam()); - if (it != permutation.end()) - { - setTemporaryTeamInLobby(profile, it->second); - } - } - } - auto old_scores = m_gp_team_scores; - m_gp_team_scores.clear(); - for (auto& p: old_scores) - { - auto it = permutation.find(p.first); - if (it != permutation.end()) - m_gp_team_scores[it->second] = p.second; - else - m_gp_team_scores[p.first] = p.second; - } -} // shuffleTemporaryTeams -//----------------------------------------------------------------------------- - void ServerLobby::resetGrandPrix() { m_gp_scores.clear(); @@ -5226,43 +5184,13 @@ void ServerLobby::saveDisconnectingIdInfo(int id) const } } // saveDisconnectingIdInfo -//----------------------------------------------------------------------------- -void ServerLobby::setTeamInLobby(std::shared_ptr profile, KartTeam team) -{ - // Used for soccer+CTF, where everything can be defined by KartTeam - profile->setTeam(team); - profile->setTemporaryTeam(TeamUtils::getIndexFromKartTeam(team)); - getSettings()->setTeamForUsername( - StringUtils::wideToUtf8(profile->getName()), - profile->getTemporaryTeam() - ); - - checkNoTeamSpectator(profile->getPeer()); -} // setTeamInLobby - -//----------------------------------------------------------------------------- -void ServerLobby::setTemporaryTeamInLobby(std::shared_ptr profile, int team) -{ - // Used for racing+FFA, where everything can be defined by a temporary team - profile->setTemporaryTeam(team); - if (RaceManager::get()->teamEnabled()) - profile->setTeam((KartTeam)(TeamUtils::getKartTeamFromIndex(team))); - else - profile->setTeam(KART_TEAM_NONE); - getSettings()->setTeamForUsername( - StringUtils::wideToUtf8(profile->getName()), - profile->getTemporaryTeam() - ); - - checkNoTeamSpectator(profile->getPeer()); -} // setTemporaryTeamInLobby - //----------------------------------------------------------------------------- void ServerLobby::checkNoTeamSpectator(std::shared_ptr peer) { if (!peer) return; + if (RaceManager::get()->teamEnabled()) { bool has_teamed = false; @@ -5276,13 +5204,10 @@ void ServerLobby::checkNoTeamSpectator(std::shared_ptr peer) } if (!has_teamed && peer->getAlwaysSpectate() == ASM_NONE) - { setSpectateModeProperly(peer, ASM_NO_TEAM); - } + if (has_teamed && peer->getAlwaysSpectate() == ASM_NO_TEAM) - { setSpectateModeProperly(peer, ASM_NONE); - } } } // checkNoTeamSpectator @@ -5306,3 +5231,18 @@ void ServerLobby::setSpectateModeProperly(std::shared_ptr peer, AlwaysS checkNoTeamSpectator(peer); } // setSpectateModeProperly //----------------------------------------------------------------------------- + +void ServerLobby::shuffleGPScoresWithPermutation(const std::map& permutation) +{ + auto old_scores = m_gp_team_scores; + m_gp_team_scores.clear(); + for (auto& p: old_scores) + { + auto it = permutation.find(p.first); + if (it != permutation.end()) + m_gp_team_scores[it->second] = p.second; + else + m_gp_team_scores[p.first] = p.second; + } +} // shuffleGPScoresWithPermutation +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 4382e0987b1..daf6bdff0a8 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -370,8 +370,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser #endif void setTemporaryTeamInLobby(const std::string& username, int team); - void clearTemporaryTeams(); - void shuffleTemporaryTeams(const std::map& permutation); void resetGrandPrix(); void erasePeerReady(std::shared_ptr peer) { m_peers_ready.erase(peer); } @@ -386,10 +384,9 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser void saveDisconnectingPeerInfo(std::shared_ptr peer) const; void saveDisconnectingIdInfo(int id) const; - // The functions below set *both* KartTeam and temporary team, - // depending on game mode; also reset/set ASM_NO_TEAM if needed. - void setTeamInLobby(std::shared_ptr profile, KartTeam team); - void setTemporaryTeamInLobby(std::shared_ptr profile, int team); + void shuffleGPScoresWithPermutation(const std::map& permutation); + + // The functions below reset/set ASM_NO_TEAM if needed by team changing procedure. void checkNoTeamSpectator(std::shared_ptr peer); void setSpectateModeProperly(std::shared_ptr peer, AlwaysSpectateMode mode); diff --git a/src/utils/chat_manager.hpp b/src/utils/chat_manager.hpp index 77350d4c89c..e3523cb5a30 100644 --- a/src/utils/chat_manager.hpp +++ b/src/utils/chat_manager.hpp @@ -26,6 +26,7 @@ #include #include #include +#include class STKPeer; enum KartTeam : int8_t; diff --git a/src/utils/hit_processor.cpp b/src/utils/hit_processor.cpp index 4944817c8ab..84cb10c58e2 100644 --- a/src/utils/hit_processor.cpp +++ b/src/utils/hit_processor.cpp @@ -25,6 +25,7 @@ #include "utils/hit_processor.hpp" #include "utils/lobby_settings.hpp" #include "utils/string_utils.hpp" +#include "utils/team_manager.hpp" namespace @@ -111,7 +112,7 @@ void HitProcessor::handleTeammateHits() // Get team of item owner auto kart_info = RaceManager::get()->getKartInfo(m_current_item_owner_id); const std::string owner_name = StringUtils::wideToUtf8(kart_info.getPlayerName()); - const int owner_team = getSettings()->getTeamForUsername(owner_name); + const int owner_team = getTeamManager()->getTeamForUsername(owner_name); if (owner_team == TeamUtils::NO_TEAM) return; @@ -146,7 +147,7 @@ void HitProcessor::processHitMessage(const std::string& owner_name, int owner_te { const std::string player_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(m_karts_exploded[i]).getPlayerName()); - const int playerTeam = getSettings()->getTeamForUsername(player_name); + const int playerTeam = getTeamManager()->getTeamForUsername(player_name); if (owner_team != playerTeam) continue; @@ -173,7 +174,7 @@ void HitProcessor::processTeammateHit(AbstractKart* owner, { const std::string player_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(m_karts_exploded[i]).getPlayerName()); - const int playerTeam = getSettings()->getTeamForUsername(player_name); + const int playerTeam = getTeamManager()->getTeamForUsername(player_name); if (owner_team != playerTeam) continue; @@ -197,7 +198,7 @@ void HitProcessor::processTeammateHit(AbstractKart* owner, { const std::string player_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(m_karts_hit[i]).getPlayerName()); - const int playerTeam = getSettings()->getTeamForUsername(player_name); + const int playerTeam = getTeamManager()->getTeamForUsername(player_name); if (owner_team != playerTeam) continue; @@ -227,13 +228,13 @@ void HitProcessor::handleSwatterHit(unsigned int ownerID, unsigned int victimID, { const std::string owner_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(ownerID).getPlayerName()); - const int owner_team = getSettings()->getTeamForUsername(owner_name); + const int owner_team = getTeamManager()->getTeamForUsername(owner_name); if (owner_team == TeamUtils::NO_TEAM) return; const std::string victim_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(victimID).getPlayerName()); - const int victim_team = getSettings()->getTeamForUsername(victim_name); + const int victim_team = getTeamManager()->getTeamForUsername(victim_name); if (victim_team != owner_team) return; @@ -271,13 +272,13 @@ void HitProcessor::handleAnvilHit(unsigned int ownerID, unsigned int victimID) { const std::string owner_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(ownerID).getPlayerName()); - const int owner_team = getSettings()->getTeamForUsername(owner_name); + const int owner_team = getTeamManager()->getTeamForUsername(owner_name); if (owner_team == TeamUtils::NO_TEAM) return; const std::string victim_name = StringUtils::wideToUtf8( RaceManager::get()->getKartInfo(victimID).getPlayerName()); - const int victim_team = getSettings()->getTeamForUsername(victim_name); + const int victim_team = getTeamManager()->getTeamForUsername(victim_name); if (victim_team != owner_team) return; diff --git a/src/utils/lobby_context.cpp b/src/utils/lobby_context.cpp index 48db3bc2546..2fa9d344861 100644 --- a/src/utils/lobby_context.cpp +++ b/src/utils/lobby_context.cpp @@ -26,6 +26,7 @@ #include "utils/lobby_queues.hpp" #include "utils/lobby_settings.hpp" #include "utils/map_vote_handler.hpp" +#include "utils/team_manager.hpp" #include "utils/tournament.hpp" LobbyContext::LobbyContext(ServerLobby* lobby, bool make_tournament) @@ -40,6 +41,7 @@ LobbyContext::LobbyContext(ServerLobby* lobby, bool make_tournament) m_map_vote_handler = std::make_shared(this); m_command_manager = std::make_shared(this); m_chat_manager = std::make_shared(this); + m_team_manager = std::make_shared(this); if (make_tournament) m_tournament = std::make_shared(this); @@ -56,6 +58,7 @@ void LobbyContext::setup() m_lobby_settings->setupContextUser(); m_map_vote_handler->setupContextUser(); m_chat_manager->setupContextUser(); + m_team_manager->setupContextUser(); m_command_manager->setupContextUser(); if (m_tournament) diff --git a/src/utils/lobby_context.hpp b/src/utils/lobby_context.hpp index e6c65023d96..11b40014537 100644 --- a/src/utils/lobby_context.hpp +++ b/src/utils/lobby_context.hpp @@ -32,6 +32,7 @@ class LobbyQueues; class LobbySettings; class MapVoteHandler; class ServerLobby; +class TeamManager; class Tournament; class LobbyContext @@ -47,6 +48,7 @@ class LobbyContext std::shared_ptr m_map_vote_handler; std::shared_ptr m_command_manager; std::shared_ptr m_chat_manager; + std::shared_ptr m_team_manager; public: @@ -65,6 +67,7 @@ class LobbyContext std::shared_ptr getMapVoteHandler() const { return m_map_vote_handler; } std::shared_ptr getCommandManager() const { return m_command_manager; } std::shared_ptr getChatManager() const { return m_chat_manager; } + std::shared_ptr getTeamManager() const { return m_team_manager; } }; class LobbyContextUser @@ -82,6 +85,7 @@ class LobbyContextUser std::shared_ptr getMapVoteHandler() const { return m_context->getMapVoteHandler(); } std::shared_ptr getCommandManager() const { return m_context->getCommandManager(); } std::shared_ptr getChatManager() const { return m_context->getChatManager(); } + std::shared_ptr getTeamManager() const { return m_context->getTeamManager(); } public: void setContext(LobbyContext* context) { m_context = context; } diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index e9f5af7dbf7..f2cc3b5b951 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -60,11 +60,9 @@ void LobbySettings::setupContextUser() setDefaultLapRestrictions(); - m_available_teams = ServerConfig::m_init_available_teams; m_default_vote = new PeerVote(); m_allowed_to_start = ServerConfig::m_allowed_to_start; - initCategories(); initAvailableModes(); initAvailableTracks(); std::string scoring = ServerConfig::m_gp_scoring; @@ -141,61 +139,6 @@ LobbySettings::~LobbySettings() } // ~LobbySettings //----------------------------------------------------------------------------- -void LobbySettings::initCategories() -{ - std::vector tokens = StringUtils::split( - ServerConfig::m_categories, ' '); - std::string category = ""; - bool isTeam = false; - bool isHammerWhitelisted = false; - for (std::string& s: tokens) - { - if (s.empty()) - continue; - else if (s[0] == '#') - { - isTeam = false; - isHammerWhitelisted = false; - if (s.length() > 1 && s[1] == '#') - { - category = s.substr(2); - m_hidden_categories.insert(category); - } - else - category = s.substr(1); - } - else if (s[0] == '$') - { - isTeam = true; - isHammerWhitelisted = false; - category = s.substr(1); - } - else if (s[0] == '^') - { - isHammerWhitelisted = true; - } - else - { - if (isHammerWhitelisted) - { - m_hammer_whitelist.insert(s); - } - else - { - if (!isTeam) { - m_player_categories[category].insert(s); - m_categories_for_player[s].insert(category); - } - else - { - m_team_for_player[s] = category[0] - '0' + 1; - } - } - } - } -} // initCategories -//----------------------------------------------------------------------------- - void LobbySettings::initAvailableModes() { std::vector statements = @@ -296,15 +239,6 @@ void LobbySettings::loadPreservedSettings() } // loadPreservedSettings //----------------------------------------------------------------------------- -int LobbySettings::getTeamForUsername(const std::string& name) -{ - auto it = m_team_for_player.find(name); - if (it == m_team_for_player.end()) - return TeamUtils::NO_TEAM; - return it->second; -} // getTeamForUsername -//----------------------------------------------------------------------------- - bool LobbySettings::hasNoLapRestrictions() const { return m_default_lap_multiplier < 0. && m_fixed_lap < 0; @@ -543,62 +477,6 @@ std::string LobbySettings::getScoringAsString() const } // getScoringAsString //----------------------------------------------------------------------------- -void LobbySettings::addPlayerToCategory(const std::string& player, const std::string& category) -{ - m_player_categories[category].insert(player); - m_categories_for_player[player].insert(category); -} // addPlayerToCategory -//----------------------------------------------------------------------------- - -void LobbySettings::erasePlayerFromCategory(const std::string& player, const std::string& category) -{ - m_player_categories[category].erase(player); - m_categories_for_player[player].erase(category); -} // erasePlayerFromCategory -//----------------------------------------------------------------------------- - -void LobbySettings::makeCategoryVisible(const std::string category, bool value) -{ - if (value) { - m_hidden_categories.erase(category); - } else { - m_hidden_categories.insert(category); - } -} // makeCategoryVisible -//----------------------------------------------------------------------------- - -bool LobbySettings::isCategoryVisible(const std::string category) const -{ - return m_hidden_categories.find(category) == m_hidden_categories.end(); -} // isCategoryVisible -//----------------------------------------------------------------------------- - -std::vector LobbySettings::getVisibleCategoriesForPlayer(const std::string& profile_name) const -{ - auto it = m_categories_for_player.find(profile_name); - if (it == m_categories_for_player.end()) - return {}; - - std::vector res; - for (const std::string& category: it->second) - if (isCategoryVisible(category)) - res.push_back(category); - - return res; -} // getVisibleCategoriesForPlayer -//----------------------------------------------------------------------------- - - -std::set LobbySettings::getPlayersInCategory(const std::string& category) const -{ - auto it = m_player_categories.find(category); - if (it == m_player_categories.end()) - return {}; - - return it->second; -} // getPlayersInCategory -//----------------------------------------------------------------------------- - std::string LobbySettings::getPreservedSettingsAsString() const { std::string msg = "Preserved settings:"; @@ -800,26 +678,6 @@ bool LobbySettings::isDifficultyAvailable(int difficulty) const } // isDifficultyAvailable //----------------------------------------------------------------------------- -void LobbySettings::applyPermutationToTeams(const std::map& permutation) -{ - for (auto& p: m_team_for_player) - { - auto it = permutation.find(p.second); - if (it != permutation.end()) - p.second = it->second; - } -} // applyPermutationToTeams -//----------------------------------------------------------------------------- - -std::string LobbySettings::getAvailableTeams() const -{ - if (RaceManager::get()->teamEnabled()) - return "rb"; - - return m_available_teams; -} // getAvailableTeams -//----------------------------------------------------------------------------- - void LobbySettings::onServerSetup() { m_battle_hit_capture_limit = 0; diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index b155073a01f..682b25068b6 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -48,7 +48,6 @@ class LobbySettings: public LobbyContextComponent void setupContextUser() OVERRIDE; ~LobbySettings(); - void initCategories(); void initAvailableTracks(); void initAvailableModes(); bool loadCustomScoring(std::string& scoring); @@ -56,16 +55,6 @@ class LobbySettings: public LobbyContextComponent void loadPreservedSettings(); bool hasConsentOnReplays() const { return m_consent_on_replays; } void setConsentOnReplays(bool value) { m_consent_on_replays = value; } - std::string getInternalAvailableTeams() const { return m_available_teams; } - void setInternalAvailableTeams(std::string& s) { m_available_teams = s; } - void setTeamForUsername(const std::string& name, int team) - { m_team_for_player[name] = team; } - int getTeamForUsername(const std::string& name); - void clearTeams() { m_team_for_player.clear(); } - bool hasTeam(const std::string& name) - { return m_team_for_player.find(name) != m_team_for_player.end(); } - std::map> getCategories() const - { return m_player_categories; } std::string getHelpMessage() const { return m_help_message; } std::string getMotd() const { return m_motd; } @@ -94,12 +83,6 @@ class LobbySettings: public LobbyContextComponent void onResetToDefaultSettings(); bool isPreservingMode() const; std::string getScoringAsString() const; - void addPlayerToCategory(const std::string& player, const std::string& category); - void erasePlayerFromCategory(const std::string& player, const std::string& category); - void makeCategoryVisible(const std::string category, bool value); - bool isCategoryVisible(const std::string category) const; - std::vector getVisibleCategoriesForPlayer(const std::string& profile_name) const; - std::set getPlayersInCategory(const std::string& category) const; std::string getPreservedSettingsAsString() const; void eraseFromPreserved(const std::string& value); void insertIntoPreserved(const std::string& value); @@ -113,7 +96,6 @@ class LobbySettings: public LobbyContextComponent bool isInWhitelist(const std::string& username) const; bool isModeAvailable(int mode) const; bool isDifficultyAvailable(int difficulty) const; - void applyPermutationToTeams(const std::map& permutation); void resetWinnerPeerId() { m_winner_peer_id = std::numeric_limits::max(); } void setWinnerPeerId(uint32_t value) { m_winner_peer_id = value; } @@ -123,10 +105,6 @@ class LobbySettings: public LobbyContextComponent void setBattleHitCaptureLimit(int value) { m_battle_hit_capture_limit = value; } void setBattleTimeLimit(float value) { m_battle_time_limit = value; } - std::string getAvailableTeams() const; - - bool isInHammerWhitelist(const std::string& str) const - { return m_hammer_whitelist.find(str) != m_hammer_whitelist.end(); } void onServerSetup(); @@ -238,8 +216,6 @@ class LobbySettings: public LobbyContextComponent bool m_shuffle_gp; - std::string m_available_teams; - bool m_live_players; bool m_ai_anywhere; @@ -310,21 +286,6 @@ class LobbySettings: public LobbyContextComponent uint32_t m_winner_peer_id; - -// These should be moved to category and team manager ========================= - - std::map> m_player_categories; - - std::set m_hidden_categories; - - std::set m_special_categories; - - std::map> m_categories_for_player; - - std::map m_team_for_player; - - std::set m_hammer_whitelist; - }; #endif // LOBBY_SETTINGS_HPP \ No newline at end of file diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp new file mode 100644 index 00000000000..5f259e6559f --- /dev/null +++ b/src/utils/team_manager.cpp @@ -0,0 +1,239 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/team_manager.hpp" + +#include "utils/team_utils.hpp" +#include "network/remote_kart_info.hpp" +#include "network/network_player_profile.hpp" +#include "network/protocols/server_lobby.hpp" +#include "utils/string_utils.hpp" +#include "network/server_config.hpp" +#include "network/stk_host.hpp" +#include "network/stk_peer.hpp" + +void TeamManager::setupContextUser() +{ + m_available_teams = ServerConfig::m_init_available_teams; + initCategories(); +} // setupContextUser +//----------------------------------------------------------------------------- + +void TeamManager::setTeamInLobby(std::shared_ptr profile, KartTeam team) +{ + // Used for soccer+CTF, where everything can be defined by KartTeam + profile->setTeam(team); + profile->setTemporaryTeam(TeamUtils::getIndexFromKartTeam(team)); + setTeamForUsername( + StringUtils::wideToUtf8(profile->getName()), + profile->getTemporaryTeam() + ); + + getLobby()->checkNoTeamSpectator(profile->getPeer()); +} // setTeamInLobby + +//----------------------------------------------------------------------------- +void TeamManager::setTemporaryTeamInLobby(std::shared_ptr profile, int team) +{ + // Used for racing+FFA, where everything can be defined by a temporary team + profile->setTemporaryTeam(team); + if (RaceManager::get()->teamEnabled()) + profile->setTeam((KartTeam)(TeamUtils::getKartTeamFromIndex(team))); + else + profile->setTeam(KART_TEAM_NONE); + setTeamForUsername( + StringUtils::wideToUtf8(profile->getName()), + profile->getTemporaryTeam() + ); + + getLobby()->checkNoTeamSpectator(profile->getPeer()); +} // setTemporaryTeamInLobby + +//----------------------------------------------------------------------------- + +void TeamManager::applyPermutationToTeams(const std::map& permutation) +{ + for (auto& p: m_team_for_player) + { + auto it = permutation.find(p.second); + if (it != permutation.end()) + p.second = it->second; + } +} // applyPermutationToTeams +//----------------------------------------------------------------------------- + +std::string TeamManager::getAvailableTeams() const +{ + if (RaceManager::get()->teamEnabled()) + return "rb"; + + return m_available_teams; +} // getAvailableTeams +//----------------------------------------------------------------------------- + +void TeamManager::initCategories() +{ + std::vector tokens = StringUtils::split( + ServerConfig::m_categories, ' '); + std::string category = ""; + bool isTeam = false; + bool isHammerWhitelisted = false; + for (std::string& s: tokens) + { + if (s.empty()) + continue; + else if (s[0] == '#') + { + isTeam = false; + isHammerWhitelisted = false; + if (s.length() > 1 && s[1] == '#') + { + category = s.substr(2); + m_hidden_categories.insert(category); + } + else + category = s.substr(1); + } + else if (s[0] == '$') + { + isTeam = true; + isHammerWhitelisted = false; + category = s.substr(1); + } + else if (s[0] == '^') + { + isHammerWhitelisted = true; + } + else + { + if (isHammerWhitelisted) + { + m_hammer_whitelist.insert(s); + } + else + { + if (!isTeam) { + m_player_categories[category].insert(s); + m_categories_for_player[s].insert(category); + } + else + { + m_team_for_player[s] = category[0] - '0' + 1; + } + } + } + } +} // initCategories +//----------------------------------------------------------------------------- + +void TeamManager::addPlayerToCategory(const std::string& player, const std::string& category) +{ + m_player_categories[category].insert(player); + m_categories_for_player[player].insert(category); +} // addPlayerToCategory +//----------------------------------------------------------------------------- + +void TeamManager::erasePlayerFromCategory(const std::string& player, const std::string& category) +{ + m_player_categories[category].erase(player); + m_categories_for_player[player].erase(category); +} // erasePlayerFromCategory +//----------------------------------------------------------------------------- + +void TeamManager::makeCategoryVisible(const std::string category, bool value) +{ + if (value) { + m_hidden_categories.erase(category); + } else { + m_hidden_categories.insert(category); + } +} // makeCategoryVisible +//----------------------------------------------------------------------------- + +bool TeamManager::isCategoryVisible(const std::string category) const +{ + return m_hidden_categories.find(category) == m_hidden_categories.end(); +} // isCategoryVisible +//----------------------------------------------------------------------------- + +std::vector TeamManager::getVisibleCategoriesForPlayer(const std::string& profile_name) const +{ + auto it = m_categories_for_player.find(profile_name); + if (it == m_categories_for_player.end()) + return {}; + + std::vector res; + for (const std::string& category: it->second) + if (isCategoryVisible(category)) + res.push_back(category); + + return res; +} // getVisibleCategoriesForPlayer +//----------------------------------------------------------------------------- + + +std::set TeamManager::getPlayersInCategory(const std::string& category) const +{ + auto it = m_player_categories.find(category); + if (it == m_player_categories.end()) + return {}; + + return it->second; +} // getPlayersInCategory +//----------------------------------------------------------------------------- + +int TeamManager::getTeamForUsername(const std::string& name) +{ + auto it = m_team_for_player.find(name); + if (it == m_team_for_player.end()) + return TeamUtils::NO_TEAM; + return it->second; +} // getTeamForUsername +//----------------------------------------------------------------------------- + +void TeamManager::clearTemporaryTeams() +{ + clearTeams(); + + for (auto& peer : STKHost::get()->getPeers()) + { + for (auto& profile : peer->getPlayerProfiles()) + { + setTemporaryTeamInLobby(profile, TeamUtils::NO_TEAM); + } + } +} // clearTemporaryTeams +//----------------------------------------------------------------------------- + +void TeamManager::shuffleTemporaryTeams(const std::map& permutation) +{ + applyPermutationToTeams(permutation); + for (auto& peer : STKHost::get()->getPeers()) + { + for (auto &profile: peer->getPlayerProfiles()) + { + auto it = permutation.find(profile->getTemporaryTeam()); + if (it != permutation.end()) + { + setTemporaryTeamInLobby(profile, it->second); + } + } + } + getLobby()->shuffleGPScoresWithPermutation(permutation); +} // shuffleTemporaryTeams +//----------------------------------------------------------------------------- diff --git a/src/utils/team_manager.hpp b/src/utils/team_manager.hpp new file mode 100644 index 00000000000..3c97b4853a7 --- /dev/null +++ b/src/utils/team_manager.hpp @@ -0,0 +1,88 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef TEAM_MANAGER_HPP +#define TEAM_MANAGER_HPP + +#include "irrString.h" +#include "utils/lobby_context.hpp" +#include "utils/types.hpp" + +#include +#include +#include +#include + +enum KartTeam: int8_t; +class NetworkPlayerProfile; + +class TeamManager: public LobbyContextComponent +{ +public: + TeamManager(LobbyContext* context): LobbyContextComponent(context) {} + + void setupContextUser() OVERRIDE; + + // The functions below set *both* KartTeam and temporary team, + // depending on game mode; also reset/set ASM_NO_TEAM if needed. + void setTeamInLobby(std::shared_ptr profile, KartTeam team); + void setTemporaryTeamInLobby(std::shared_ptr profile, int team); + void applyPermutationToTeams(const std::map& permutation); + std::string getAvailableTeams() const; + std::map> getCategories() const + { return m_player_categories; } + void initCategories(); + void addPlayerToCategory(const std::string& player, const std::string& category); + void erasePlayerFromCategory(const std::string& player, const std::string& category); + void makeCategoryVisible(const std::string category, bool value); + bool isCategoryVisible(const std::string category) const; + std::vector getVisibleCategoriesForPlayer(const std::string& profile_name) const; + std::set getPlayersInCategory(const std::string& category) const; + std::string getInternalAvailableTeams() const { return m_available_teams; } + void setInternalAvailableTeams(std::string& s) { m_available_teams = s; } + void setTeamForUsername(const std::string& name, int team) + { m_team_for_player[name] = team; } + int getTeamForUsername(const std::string& name); + void clearTeams() { m_team_for_player.clear(); } + bool hasTeam(const std::string& name) + { return m_team_for_player.find(name) != m_team_for_player.end(); } + + bool isInHammerWhitelist(const std::string& str) const + { return m_hammer_whitelist.find(str) != m_hammer_whitelist.end(); } + void clearTemporaryTeams(); + void shuffleTemporaryTeams(const std::map& permutation); + +private: + + std::string m_available_teams; + + std::map> m_player_categories; + + std::set m_hidden_categories; + + std::set m_special_categories; + + std::map> m_categories_for_player; + + std::map m_team_for_player; + + std::set m_hammer_whitelist; + +}; + +#endif // TEAM_MANAGER_HPP \ No newline at end of file diff --git a/src/utils/team_utils.cpp b/src/utils/team_utils.cpp index 2e78fbb0f5b..bc5c45e2b33 100644 --- a/src/utils/team_utils.cpp +++ b/src/utils/team_utils.cpp @@ -20,7 +20,7 @@ #include "utils/team_utils.hpp" -void TeamManager::addTeam(std::string hardcoded_code, +void TeamsStorage::addTeam(std::string hardcoded_code, std::string hardcoded_name, float hardcoded_color, std::string hardcoded_emoji) { @@ -32,27 +32,27 @@ void TeamManager::addTeam(std::string hardcoded_code, } // addTeam //----------------------------------------------------------------------------- -void TeamManager::addCode(int idx, std::string hardcoded_code) +void TeamsStorage::addCode(int idx, std::string hardcoded_code) { m_teams[idx].addCode(hardcoded_code); m_finder_by_code[hardcoded_code] = idx; } // addCode //----------------------------------------------------------------------------- -void TeamManager::addName(int idx, std::string hardcoded_name) +void TeamsStorage::addName(int idx, std::string hardcoded_name) { m_teams[idx].addName(hardcoded_name); m_finder_by_name[hardcoded_name] = idx; } // addName //----------------------------------------------------------------------------- -const CustomTeam& TeamManager::operator[](int idx) const +const CustomTeam& TeamsStorage::operator[](int idx) const { return m_teams[idx]; } // getTeamByIndex //----------------------------------------------------------------------------- -int TeamManager::getIndexByCode(const std::string& code) const +int TeamsStorage::getIndexByCode(const std::string& code) const { auto it = m_finder_by_code.find(code); if (it == m_finder_by_code.end()) @@ -63,7 +63,7 @@ int TeamManager::getIndexByCode(const std::string& code) const } // getIndexByCode //----------------------------------------------------------------------------- -int TeamManager::getIndexByName(const std::string& name) const +int TeamsStorage::getIndexByName(const std::string& name) const { auto it = m_finder_by_name.find(name); if (it == m_finder_by_name.end()) @@ -74,7 +74,7 @@ int TeamManager::getIndexByName(const std::string& name) const } // getIndexByName //----------------------------------------------------------------------------- -TeamManager::TeamManager() +TeamsStorage::TeamsStorage() { addTeam("-", "none", 0.00, ""); addTeam("r", "red", 1.00, StringUtils::utf32ToUtf8({0x1f7e5})); // 1 @@ -89,6 +89,6 @@ TeamManager::TeamManager() addCode(6, "v"); addName(6, "violet"); addName(8, "pink"); -} // TeamManager +} // TeamsStorage //----------------------------------------------------------------------------- diff --git a/src/utils/team_utils.hpp b/src/utils/team_utils.hpp index e37be6294a1..a47e2ddd7a3 100644 --- a/src/utils/team_utils.hpp +++ b/src/utils/team_utils.hpp @@ -64,7 +64,7 @@ class CustomTeam void addName(const std::string& name) { m_names.push_back(name); } }; -class TeamManager +class TeamsStorage { private: std::vector m_teams; @@ -75,10 +75,10 @@ class TeamManager void addCode(int idx, std::string hardcoded_code); void addName(int idx, std::string hardcoded_name); public: - TeamManager(); + TeamsStorage(); // Teams are indexed from 1 to N, 0 means no team set (or undefined). // Previously the code had 4-way inconsistent indexation - // but hopefully it's fixed now' + // but hopefully it's fixed now const CustomTeam& operator[](int idx) const; int getIndexByCode(const std::string& code) const; int getIndexByName(const std::string& name) const; @@ -86,7 +86,7 @@ class TeamManager { return (int)m_teams.size() - 1; } }; -class TeamUtils: public Singleton +class TeamUtils: public Singleton { public: static const int NO_TEAM = 0; diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp index 6747b192fca..891c52dbd0b 100644 --- a/src/utils/tournament.cpp +++ b/src/utils/tournament.cpp @@ -28,6 +28,7 @@ #include "modes/soccer_world.hpp" #include "utils/lobby_settings.hpp" #include "utils/string_utils.hpp" +#include "utils/team_manager.hpp" namespace { @@ -138,17 +139,17 @@ void Tournament::updateTournamentRole(std::shared_ptr peer) core::stringw name = player->getName(); std::string utf8_name = StringUtils::wideToUtf8(name); if (m_red_players.count(utf8_online_name)) - getLobby()->setTeamInLobby(player, KART_TEAM_RED); + getTeamManager()->setTeamInLobby(player, KART_TEAM_RED); else if (m_blue_players.count(utf8_online_name)) - getLobby()->setTeamInLobby(player, KART_TEAM_BLUE); + getTeamManager()->setTeamInLobby(player, KART_TEAM_BLUE); else - getLobby()->setTeamInLobby(player, KART_TEAM_NONE); + getTeamManager()->setTeamInLobby(player, KART_TEAM_NONE); if (hasColorsSwapped()) { if (player->getTeam() == KART_TEAM_BLUE) - getLobby()->setTeamInLobby(player, KART_TEAM_RED); + getTeamManager()->setTeamInLobby(player, KART_TEAM_RED); else if (player->getTeam() == KART_TEAM_RED) - getLobby()->setTeamInLobby(player, KART_TEAM_BLUE); + getTeamManager()->setTeamInLobby(player, KART_TEAM_BLUE); } } } // updateTournamentRole @@ -220,7 +221,7 @@ void Tournament::initTournamentPlayers() type == "B" ? m_blue_players : m_referees); - auto categories = getSettings()->getCategories(); + auto categories = getTeamManager()->getCategories(); for (const std::string& member: categories[cat_name]) dest.insert(member); } From aa0c98cf6d695044c60ab3f2cb02361f65cefaef Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 14 Mar 2025 02:35:48 +0400 Subject: [PATCH 598/830] Started clearing ServerLobby from event consequences, also renames in LobbySettings (Not tested) --- src/network/game_setup.cpp | 2 +- src/network/protocols/command_manager.cpp | 14 +- src/network/protocols/server_lobby.cpp | 284 ++++++++++------------ src/network/protocols/server_lobby.hpp | 15 +- src/network/stk_peer.hpp | 4 +- src/utils/lobby_settings.cpp | 42 ++++ src/utils/lobby_settings.hpp | 49 ++-- src/utils/team_manager.cpp | 37 +++ src/utils/team_manager.hpp | 1 + 9 files changed, 259 insertions(+), 189 deletions(-) diff --git a/src/network/game_setup.cpp b/src/network/game_setup.cpp index a74abed6856..326b0da6e69 100644 --- a/src/network/game_setup.cpp +++ b/src/network/game_setup.cpp @@ -145,7 +145,7 @@ void GameSetup::addServerInfo(NetworkString* ns) ns->addUInt8(0).addFloat(0.0f); ns->encodeString16(m_message_of_today); - ns->addUInt8((uint8_t)getSettings()->getServerConfigurable()); + ns->addUInt8((uint8_t)getSettings()->isServerConfigurable()); ns->addUInt8(getSettings()->isLivePlayers() ? 1 : 0); } // addServerInfo diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 70ef8c14ffa..9ad389d1846 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -413,7 +413,7 @@ void CommandManager::initCommands() // special permissions according to ServerConfig options std::shared_ptr kick_command = mp["kick"].lock(); if (kick_command) { - if (getSettings()->getKicksAllowed()) + if (getSettings()->hasKicksAllowed()) kick_command->m_permissions |= PE_CROWNED; else kick_command->m_permissions &= ~PE_CROWNED; @@ -1091,7 +1091,7 @@ void CommandManager::process_replay(Context& context) error(context, true); return; } - if (getSettings()->getRecordReplays()) + if (getSettings()->isRecordingReplays()) { bool current_state = getSettings()->hasConsentOnReplays(); if (argv.size() >= 2 && argv[1] == "0") @@ -1114,7 +1114,7 @@ void CommandManager::process_replay(Context& context) void CommandManager::process_start(Context& context) { - if (!getSettings()->getOwnerLess() && (context.m_user_permissions & UP_CROWNED) == 0) + if (!getSettings()->isOwnerLess() && (context.m_user_permissions & UP_CROWNED) == 0) { context.m_voting = true; } @@ -1151,7 +1151,7 @@ void CommandManager::process_config(Context& context) msg += get_first_if_exists(m_aux_difficulty_aliases[difficulty]); msg += " "; msg += get_first_if_exists(m_aux_goal_aliases[goal_target ? 1 : 0]); - if (!getSettings()->getServerConfigurable()) + if (!getSettings()->isServerConfigurable()) msg += " (not configurable)"; getLobby()->sendStringToPeer(peer, msg); } // process_config @@ -1160,7 +1160,7 @@ void CommandManager::process_config(Context& context) void CommandManager::process_config_assign(Context& context) { auto peer = context.m_peer.lock(); - if (!getSettings()->getServerConfigurable()) + if (!getSettings()->isServerConfigurable()) { getLobby()->sendStringToPeer(peer, "Server is not configurable, this command cannot be invoked."); return; @@ -1746,7 +1746,7 @@ void CommandManager::process_kick(Context& context) } Log::info("CommandManager", "%s kicks %s", (peer.get() ? "Crown player" : "Vote"), player_name.c_str()); player_peer->kick(); - if (getSettings()->getTrackKicks()) + if (getSettings()->isTrackingKicks()) { std::string auto_report = "[ Auto report caused by kick ]"; getLobby()->writeOwnReport(player_peer, peer, auto_report); @@ -3574,7 +3574,7 @@ void CommandManager::process_slots(Context& context) void CommandManager::process_slots_assign(Context& context) { - if (getSettings()->getOnlyHostRiding()) + if (getSettings()->hasOnlyHostRiding()) { auto peer = context.m_peer.lock(); // may be nullptr, here we don't care getLobby()->sendStringToPeer(peer, diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index c86cd5e0c87..e2276e31bef 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -68,7 +68,7 @@ #include #include -// ======================================================================== +// ============================================================================ // Helper functions. namespace @@ -91,7 +91,7 @@ namespace bns->encodeString(player->getKartName()); } } // encodePlayers - //--------------------------------------------------------------------- + //------------------------------------------------------------------------- /** Returns true if world is active for clients to live join, spectate or * going back to lobby live */ @@ -102,7 +102,7 @@ namespace World::getWorld()->getPhase() == WorldStatus::RACE_PHASE; } // worldIsActive - //----------------------------------------------------------------------------- + //------------------------------------------------------------------------- /** Get a list of current ingame players for live join or spectate. */ std::vector > getLivePlayers() @@ -138,10 +138,33 @@ namespace } return players; } // getLivePlayers - //----------------------------------------------------------------------------- + //------------------------------------------------------------------------- + + void getClientAssetsFromNetworkString(const NetworkString& ns, + std::set& client_karts, + std::set& client_maps) + { + client_karts.clear(); + client_maps.clear(); + const unsigned kart_num = ns.getUInt16(); + const unsigned maps_num = ns.getUInt16(); + for (unsigned i = 0; i < kart_num; i++) + { + std::string kart; + ns.decodeString(&kart); + client_karts.insert(kart); + } + for (unsigned i = 0; i < maps_num; i++) + { + std::string map; + ns.decodeString(&map); + client_maps.insert(map); + } + } // getClientAssetsFromNetworkString + //------------------------------------------------------------------------- } // anonymous namespace -// ======================================================================== +// ============================================================================ // We use max priority for all server requests to avoid downloading of addons // icons blocking the poll request in all-in-one graphical client server @@ -361,81 +384,28 @@ void ServerLobby::handleChat(Event* event) //----------------------------------------------------------------------------- void ServerLobby::changeTeam(Event* event) { - if (!getSettings()->getTeamChoosing() || - !RaceManager::get()->teamEnabled()) + if (!checkDataSize(event, 1)) return; - if (!checkDataSize(event, 1)) return; + NetworkString& data = event->data(); uint8_t local_id = data.getUInt8(); auto& player = event->getPeer()->getPlayerProfiles().at(local_id); - auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); - if (getTournament() && !getTournament()->canChangeTeam()) - { - Log::info("ServerLobby", "Team change requested by %s, but tournament forbids it.", player->getName().c_str()); - return; - } - - // For now, the change team button will still only work in soccer + CTF. - // Further logic might be added later, but now it seems to be complicated - // because there's a restriction of 7 for those modes, and unnecessary - // because we don't have client changes. - // At most 7 players on each team (for live join) - if (player->getTeam() == KART_TEAM_BLUE) - { - if (red_blue.first >= 7 && !getSettings()->getFreeTeams()) - return; - getTeamManager()->setTeamInLobby(player, KART_TEAM_RED); - } - else - { - if (red_blue.second >= 7 && !getSettings()->getFreeTeams()) - return; - getTeamManager()->setTeamInLobby(player, KART_TEAM_BLUE); - } - updatePlayerList(); + getTeamManager()->changeTeam(player); } // changeTeam //----------------------------------------------------------------------------- void ServerLobby::kickHost(Event* event) { - if (m_server_owner.lock() != event->getPeerSP()) - return; - if (!getSettings()->getKicksAllowed()) - { - sendStringToPeer(event->getPeerSP(), "Kicking players is not allowed on this server"); + if (!checkDataSize(event, 4)) return; - } - if (!checkDataSize(event, 4)) return; + NetworkString& data = event->data(); uint32_t host_id = data.getUInt32(); - std::shared_ptr peer = STKHost::get()->findPeerByHostId(host_id); - // Ignore kicking ai peer if ai handling is on - if (peer && (!getSettings()->getAiHandling() || !peer->isAIPeer())) - { - if (peer->isAngryHost()) - { - sendStringToPeer(event->getPeerSP(), "This player is the owner of this server, " - "and is protected from your actions now"); - return; - } - if (!peer->hasPlayerProfiles()) - { - Log::info("ServerLobby", "Crown player kicks a player"); - } - else - { - auto npp = peer->getPlayerProfiles()[0]; - std::string player_name = StringUtils::wideToUtf8(npp->getName()); - Log::info("ServerLobby", "Crown player kicks %s", player_name.c_str()); - } - peer->kick(); - if (getSettings()->getTrackKicks()) - { - std::string auto_report = "[ Auto report caused by kick ]"; - writeOwnReport(peer, event->getPeerSP(), auto_report); - } - } + std::shared_ptr target = STKHost::get()->findPeerByHostId(host_id); + auto initiator = event->getPeerSP(); + + getSettings()->tryKickingAnotherPeer(initiator, target); } // kickHost //----------------------------------------------------------------------------- @@ -452,24 +422,24 @@ bool ServerLobby::notifyEventAsynchronous(Event* event) message_type); switch(message_type) { - case LE_CONNECTION_REQUESTED: connectionRequested(event); break; - case LE_KART_SELECTION: kartSelectionRequested(event); break; - case LE_CLIENT_LOADED_WORLD: finishedLoadingWorldClient(event); break; - case LE_VOTE: handlePlayerVote(event); break; - case LE_KICK_HOST: kickHost(event); break; - case LE_CHANGE_TEAM: changeTeam(event); break; - case LE_REQUEST_BEGIN: startSelection(event); break; - case LE_CHAT: handleChat(event); break; - case LE_CONFIG_SERVER: handleServerConfiguration(event); break; - case LE_CHANGE_HANDICAP: changeHandicap(event); break; + case LE_CONNECTION_REQUESTED: connectionRequested(event); break; + case LE_KART_SELECTION: kartSelectionRequested(event); break; + case LE_CLIENT_LOADED_WORLD: finishedLoadingWorldClient(event); break; + case LE_VOTE: handlePlayerVote(event); break; + case LE_KICK_HOST: kickHost(event); break; + case LE_CHANGE_TEAM: changeTeam(event); break; + case LE_REQUEST_BEGIN: startSelection(event); break; + case LE_CHAT: handleChat(event); break; + case LE_CONFIG_SERVER: handleServerConfiguration(event); break; + case LE_CHANGE_HANDICAP: changeHandicap(event); break; case LE_CLIENT_BACK_LOBBY: - clientSelectingAssetsWantsToBackLobby(event); break; - case LE_REPORT_PLAYER: writePlayerReport(event); break; - case LE_ASSETS_UPDATE: - handleAssets(event->data(), event->getPeerSP()); break; - case LE_COMMAND: - handleServerCommand(event, event->getPeerSP()); break; - default: break; + clientSelectingAssetsWantsToBackLobby(event); break; + case LE_REPORT_PLAYER: writePlayerReport(event); break; + case LE_ASSETS_UPDATE: handleAssets(event); break; + case LE_COMMAND: handleServerCommand(event); break; + default: + Log::error("ServerLobby", "Invalid message type %d", message_type); + break; } // switch } // if (event->getType() == EVENT_TYPE_MESSAGE) else if (event->getType() == EVENT_TYPE_DISCONNECTED) @@ -488,7 +458,7 @@ bool ServerLobby::notifyEventAsynchronous(Event* event) */ void ServerLobby::pollDatabase() { - if (!getSettings()->getSqlManagement() || !m_db_connector->hasDatabase()) + if (!getSettings()->hasSqlManagement() || !m_db_connector->hasDatabase()) return; if (!m_db_connector->isTimeToPoll()) @@ -638,7 +608,7 @@ void ServerLobby::asynchronousUpdate() // Check if server owner has left updateServerOwner(); - if (getSettings()->getRanked() && m_state.load() == WAITING_FOR_START_GAME) + if (getSettings()->isRanked() && m_state.load() == WAITING_FOR_START_GAME) m_ranking->cleanup(); if (allowJoinedPlayersWaiting() /*|| (m_game_setup->isGrandPrix() && @@ -729,7 +699,7 @@ void ServerLobby::asynchronousUpdate() } case WAITING_FOR_START_GAME: { - if (getSettings()->getOwnerLess()) + if (getSettings()->isOwnerLess()) { // Ensure that a game can auto-start if the server meets the config's starting limit or if it's already full. int starting_limit = std::min((int)getSettings()->getMinStartGamePlayers(), (int)getSettings()->getServerMaxPlayers()); @@ -800,7 +770,7 @@ void ServerLobby::asynchronousUpdate() unsigned player_in_game = 0; STKHost::get()->updatePlayers(&player_in_game); // Reset lobby will be done in main thread - if ((player_in_game == 1 && getSettings()->getRanked()) || + if ((player_in_game == 1 && getSettings()->isRanked()) || player_in_game == 0) { resetVotingTime(); @@ -811,7 +781,7 @@ void ServerLobby::asynchronousUpdate() if (m_server_has_loaded_world.load() == false) return; if (!checkPeersReady( - getSettings()->getAiHandling() && m_ai_count == 0/*ignore_ai_peer*/, LOADING_WORLD)) + getSettings()->hasAiHandling() && m_ai_count == 0/*ignore_ai_peer*/, LOADING_WORLD)) return; // Reset for next state usage resetPeersReady(); @@ -824,7 +794,7 @@ void ServerLobby::asynchronousUpdate() return; unsigned player_in_game = 0; STKHost::get()->updatePlayers(&player_in_game); - if ((player_in_game == 1 && getSettings()->getRanked()) || + if ((player_in_game == 1 && getSettings()->isRanked()) || player_in_game == 0) { resetVotingTime(); @@ -834,7 +804,7 @@ void ServerLobby::asynchronousUpdate() PeerVote winner_vote; getSettings()->resetWinnerPeerId(); bool go_on_race = false; - if (getSettings()->getTrackVoting()) + if (getSettings()->hasTrackVoting()) go_on_race = handleAllVotes(&winner_vote); else if (/*m_game_setup->isGrandPrixStarted() || */isVotingOver()) { @@ -962,7 +932,7 @@ void ServerLobby::asynchronousUpdate() getSettings()->getFlagReturnTimeout()); RaceManager::get()->setHitProcessor(getHitProcessor()); RaceManager::get()->setFlagReturnTicks(flag_return_time); - if (getSettings()->getRecordReplays() && getSettings()->hasConsentOnReplays() && + if (getSettings()->isRecordingReplays() && getSettings()->hasConsentOnReplays() && (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL || RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE)) RaceManager::get()->setRecordRace(true); @@ -1133,15 +1103,18 @@ void ServerLobby::rejectLiveJoin(std::shared_ptr peer, BackLobbyReason */ void ServerLobby::liveJoinRequest(Event* event) { + // I moved some data getters ahead of some returns. This should be fine + // in general, but you know what caused it if smth goes wrong. + std::shared_ptr peer = event->getPeerSP(); const NetworkString& data = event->data(); + bool spectator = data.getUInt8() == 1; if (!canLiveJoinNow()) { rejectLiveJoin(peer, BLR_NO_GAME_FOR_LIVE_JOIN); return; } - bool spectator = data.getUInt8() == 1; if (RaceManager::get()->modeHasLaps() && !spectator) { // No live join for linear race @@ -1164,7 +1137,7 @@ void ServerLobby::liveJoinRequest(Event* event) used_id.push_back(id); } if ((used_id.size() != peer->getPlayerProfiles().size()) || - (spectators_by_limit.find(event->getPeerSP()) != spectators_by_limit.end())) + (spectators_by_limit.find(peer) != spectators_by_limit.end())) { for (unsigned i = 0; i < peer->getPlayerProfiles().size(); i++) peer->getPlayerProfiles()[i]->setKartName(""); @@ -1239,7 +1212,7 @@ int ServerLobby::getReservedId(std::shared_ptr& p, rki.copyFrom(p, local_id); return i; } - if (getSettings()->getTeamChoosing()) + if (getSettings()->hasTeamChoosing()) { if ((p->getTeam() == KART_TEAM_RED && rki.getKartTeam() == KART_TEAM_RED) || @@ -1348,7 +1321,7 @@ void ServerLobby::finishedLoadingLiveJoinClient(Event* event) } if (RaceManager::get()->isBattleMode()) { - if (getSettings()->getPreserveBattleScores()) + if (getSettings()->isPreservingBattleScores()) points = m_game_info->m_saved_ffa_points[name]; info.m_result -= points; } @@ -1583,7 +1556,7 @@ void ServerLobby::update(int ticks) return; // Reset for ranked server if in kart / track selection has only 1 player - if (getSettings()->getRanked() && + if (getSettings()->isRanked() && m_state.load() == SELECTING && STKHost::get()->getPlayersInGame() == 1) { @@ -1762,14 +1735,14 @@ void ServerLobby::startSelection(const Event *event) m_state.load()); return; } - if (getSettings()->getSleepingServer()) + if (getSettings()->isSleepingServer()) { Log::warn("ServerLobby", "An attempt to start a race on a sleeping server."); return; } auto peer = event->getPeerSP(); - if (getSettings()->getOwnerLess()) + if (getSettings()->isOwnerLess()) { if (!getSettings()->isAllowedToStart()) { @@ -1812,8 +1785,8 @@ void ServerLobby::startSelection(const Event *event) } } - if (!getSettings()->getOwnerLess() && getSettings()->getTeamChoosing() && - !getSettings()->getFreeTeams() && RaceManager::get()->teamEnabled()) + if (!getSettings()->isOwnerLess() && getSettings()->hasTeamChoosing() && + !getSettings()->hasFreeTeams() && RaceManager::get()->teamEnabled()) { auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); if ((red_blue.first == 0 || red_blue.second == 0) && @@ -1970,7 +1943,7 @@ void ServerLobby::startSelection(const Event *event) .addFloat(getSettings()->getVotingTimeout()) .addUInt8(/*m_game_setup->isGrandPrixStarted() ? 1 : */0) .addUInt8((!getSettings()->hasNoLapRestrictions() ? 1 : 0)) - .addUInt8(getSettings()->getTrackVoting() ? 1 : 0); + .addUInt8(getSettings()->hasTrackVoting() ? 1 : 0); std::set all_k = peer->getClientAssets().first; @@ -2051,7 +2024,7 @@ void ServerLobby::checkIncomingConnectionRequests() // Keep the port open, it can be sent to anywhere as we will send to the // correct peer later in ConnectToPeer. - if (getSettings()->getFirewalledServer()) + if (getSettings()->isFirewalledServer()) { BareNetworkString data; data.addUInt8(0); @@ -2197,7 +2170,7 @@ void ServerLobby::checkRaceFinished() } uint8_t ranking_changes_indication = 0; - if (getSettings()->getRanked() && RaceManager::get()->modeHasLaps()) + if (getSettings()->isRanked() && RaceManager::get()->modeHasLaps()) ranking_changes_indication = 1; if (m_game_setup->isGrandPrix()) ranking_changes_indication = 1; @@ -2210,12 +2183,12 @@ void ServerLobby::checkRaceFinished() updateGnuElimination(); } - if (getSettings()->getStoreResults()) + if (getSettings()->isStoringResults()) { storeResults(); } - if (getSettings()->getRanked()) + if (getSettings()->isRanked()) { computeNewRankings(); submitRankingsToAddons(); @@ -2362,27 +2335,25 @@ void ServerLobby::saveIPBanTable(const SocketAddress& addr) m_db_connector->saveAddressToIpBanTable(addr); #endif } // saveIPBanTable - //----------------------------------------------------------------------------- -bool ServerLobby::handleAssets(const NetworkString& ns, std::shared_ptr peer) + +bool ServerLobby::handleAssets(Event* event) { - std::set client_karts, client_tracks; - const unsigned kart_num = ns.getUInt16(); - const unsigned track_num = ns.getUInt16(); - for (unsigned i = 0; i < kart_num; i++) - { - std::string kart; - ns.decodeString(&kart); - client_karts.insert(kart); - } - for (unsigned i = 0; i < track_num; i++) - { - std::string track; - ns.decodeString(&track); - client_tracks.insert(track); - } + const NetworkString& ns = event->data(); + std::shared_ptr peer = event->getPeerSP(); + + std::set client_karts, client_maps; + getClientAssetsFromNetworkString(ns, client_karts, client_maps); + + return handleAssetsAndAddonScores(peer, client_karts, client_maps); +} // handleAssets +//----------------------------------------------------------------------------- - if (!getAssetManager()->handleAssetsForPeer(peer, client_karts, client_tracks)) +bool ServerLobby::handleAssetsAndAddonScores(std::shared_ptr peer, + const std::set& client_karts, + const std::set& client_maps) +{ + if (!getAssetManager()->handleAssetsForPeer(peer, client_karts, client_maps)) { if (peer->isValidated()) { @@ -2419,11 +2390,11 @@ bool ServerLobby::handleAssets(const NetworkString& ns, std::shared_ptr } - std::array addons_scores = getAssetManager()->getAddonScores(client_karts, client_tracks); + std::array addons_scores = getAssetManager()->getAddonScores(client_karts, client_maps); // Save available karts and tracks from clients in STKPeer so if this peer // disconnects later in lobby it won't affect current players - peer->setAvailableKartsTracks(client_karts, client_tracks); + peer->setAvailableKartsTracks(client_karts, client_maps); peer->setAddonsScores(addons_scores); if (m_process_type == PT_CHILD && @@ -2493,7 +2464,10 @@ void ServerLobby::connectionRequested(Event* event) caps.insert(cap); } event->getPeer()->setClientCapabilities(caps); - if (!handleAssets(data, event->getPeerSP())) + + std::set client_karts, client_maps; + getClientAssetsFromNetworkString(data, client_karts, client_maps); + if (!handleAssetsAndAddonScores(event->getPeerSP(), client_karts, client_maps)) return; unsigned player_count = data.getUInt8(); @@ -2545,12 +2519,12 @@ void ServerLobby::connectionRequested(Event* event) !(peer->getAddress().isPublicAddressLocalhost() || peer->getAddress().isLAN()) && NetworkConfig::get()->isWAN() && - getSettings()->getValidatingPlayer()) || - (getSettings()->getStrictPlayers() && + getSettings()->isValidatingPlayer()) || + (getSettings()->hasStrictPlayers() && (player_count != 1 || online_id == 0 || duplicated_ranked_player)) || (peer->isAIPeer() && !peer->getAddress().isLAN() && !getSettings()->canConnectAiAnywhere()) || (peer->isAIPeer() && - getSettings()->getAiHandling() && !m_ai_peer.expired())) + getSettings()->hasAiHandling() && !m_ai_peer.expired())) { NetworkString* message = getNetworkString(2); message->setSynchronous(true); @@ -2562,7 +2536,7 @@ void ServerLobby::connectionRequested(Event* event) return; } - if (getSettings()->getAiHandling() && peer->isAIPeer()) + if (getSettings()->hasAiHandling() && peer->isAIPeer()) m_ai_peer = peer; if (encrypted_size != 0) @@ -2651,7 +2625,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, STKHost::get()->getAllPlayerOnlineIds(); bool duplicated_ranked_player = all_online_ids.find(online_id) != all_online_ids.end(); - if (getSettings()->getRanked() && duplicated_ranked_player) + if (getSettings()->isRanked() && duplicated_ranked_player) { NetworkString* message = getNetworkString(2); message->setSynchronous(true); @@ -2704,7 +2678,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, bool can_change_teams = true; if (getTournament() && !getTournament()->canChangeTeam()) can_change_teams = false; - if (getSettings()->getTeamChoosing() && can_change_teams) + if (getSettings()->hasTeamChoosing() && can_change_teams) { KartTeam cur_team = KART_TEAM_NONE; @@ -2830,7 +2804,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, { peer->setWaitingForGame(false); m_peers_ready[peer] = false; - if (!getSettings()->getSqlManagement()) + if (!getSettings()->hasSqlManagement()) { for (std::shared_ptr& npp : peer->getPlayerProfiles()) @@ -2846,7 +2820,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, peer->sendPacket(message_ack); delete message_ack; - if (getSettings()->getRanked()) + if (getSettings()->isRanked()) { getRankingForPlayer(peer->getPlayerProfiles()[0]); } @@ -2876,7 +2850,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, peer->sendPacket(chat, PRM_RELIABLE); delete chat; } - if (getSettings()->getRecordReplays()) + if (getSettings()->isRecordingReplays()) { std::string msg; if (getSettings()->hasConsentOnReplays()) @@ -2977,8 +2951,8 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) std::string os_type_str = version_os.second; std::string utf8_profile_name = StringUtils::wideToUtf8(profile_name); // Add a Mobile emoji for mobile OS - if (getSettings()->getExposeMobile() && - (os_type_str == "iOS" || os_type_str == "Android")) + if (getSettings()->isExposingMobile() && + (os_type_str == "iOS" || os_type_str == "Android")) profile_name = StringUtils::utf32ToWide({0x1F4F1}) + profile_name; // Add an hourglass emoji for players waiting because of the player limit @@ -3020,7 +2994,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) boolean_combine |= (1 << 1); if (p && m_server_owner_id.load() == p->getHostId()) boolean_combine |= (1 << 2); - if (getSettings()->getOwnerLess() && !game_started && + if (getSettings()->isOwnerLess() && !game_started && m_peers_ready.find(p) != m_peers_ready.end() && m_peers_ready.at(p)) boolean_combine |= (1 << 3); @@ -3028,7 +3002,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) boolean_combine |= (1 << 4); pl->addUInt8(boolean_combine); pl->addUInt8(profile->getHandicap()); - if (getSettings()->getTeamChoosing()) + if (getSettings()->hasTeamChoosing()) pl->addUInt8(profile->getTeam()); else pl->addUInt8(KART_TEAM_NONE); @@ -3053,7 +3027,7 @@ void ServerLobby::updateServerOwner(bool force) { if (m_state.load() < WAITING_FOR_START_GAME || m_state.load() > RESULT_DISPLAY || - getSettings()->getOwnerLess()) + getSettings()->isOwnerLess()) return; if (!force && !m_server_owner.expired()) return; @@ -3126,7 +3100,7 @@ void ServerLobby::kartSelectionRequested(Event* event) */ void ServerLobby::handlePlayerVote(Event* event) { - if (m_state != SELECTING || !getSettings()->getTrackVoting()) + if (m_state != SELECTING || !getSettings()->hasTrackVoting()) { Log::warn("ServerLobby", "Received track vote while in state %d.", m_state.load()); @@ -3445,7 +3419,7 @@ void ServerLobby::configPeersStartTime() } max_ping = std::max(peer->getAveragePing(), max_ping); } - if ((getSettings()->getHighPingWorkaround() && peer_exceeded_max_ping) || + if ((getSettings()->hasHighPingWorkaround() && peer_exceeded_max_ping) || (getSettings()->isLivePlayers() && RaceManager::get()->supportsLiveJoining())) { Log::info("ServerLobby", "Max ping to ServerConfig::m_max_ping for " @@ -3513,7 +3487,7 @@ void ServerLobby::addWaitingPlayersToGame() if (m_peers_ready.find(peer) == m_peers_ready.end()) { m_peers_ready[peer] = false; - if (!getSettings()->getSqlManagement()) + if (!getSettings()->hasSqlManagement()) { Log::info("ServerLobby", "New player %s with online id %u from %s with %s.", @@ -3524,7 +3498,7 @@ void ServerLobby::addWaitingPlayersToGame() } } uint32_t online_id = profile->getOnlineId(); - if (getSettings()->getRanked() && !m_ranking->has(online_id)) + if (getSettings()->isRanked() && !m_ranking->has(online_id)) { getRankingForPlayer(peer->getPlayerProfiles()[0]); } @@ -3710,7 +3684,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, m_state.load()); return; } - if (!getSettings()->getServerConfigurable()) + if (!getSettings()->isServerConfigurable()) { Log::warn("ServerLobby", "server-configurable is not enabled."); return; @@ -3857,7 +3831,7 @@ void ServerLobby::handleServerConfiguration(Event* event) } int new_difficulty = getSettings()->getServerDifficulty(); int new_game_mode = getSettings()->getServerMode(); - bool new_soccer_goal_target = getSettings()->getSoccerGoalTarget(); + bool new_soccer_goal_target = getSettings()->isSoccerGoalTargetInConfig(); if (event != NULL) { NetworkString& data = event->data(); @@ -3956,7 +3930,7 @@ void ServerLobby::handlePlayerDisconnection() const World::getWorld()->eliminateKart(i, false/*notify_of_elimination*/); - if (getSettings()->getRanked()) + if (getSettings()->isRanked()) { // Handle disconnection earlier to prevent cheating by joining // another ranked server @@ -4385,11 +4359,13 @@ bool ServerLobby::checkPeersReady(bool ignore_ai_peer, SelectionPhase phase) } // checkPeersReady //----------------------------------------------------------------------------- -void ServerLobby::handleServerCommand(Event* event, - std::shared_ptr peer) +void ServerLobby::handleServerCommand(Event* event) { + std::shared_ptr peer = event->getPeerSP(); + if (peer.get()) peer->updateLastActivity(); + getCommandManager()->handleCommand(event, peer); } // handleServerCommand //----------------------------------------------------------------------------- @@ -4657,7 +4633,7 @@ void ServerLobby::storeResults() //----------------------------------------------------------------------------- void ServerLobby::resetToDefaultSettings() { - if (getSettings()->getServerConfigurable() && !getSettings()->isPreservingMode()) + if (getSettings()->isServerConfigurable() && !getSettings()->isPreservingMode()) handleServerConfiguration(NULL); getSettings()->onResetToDefaultSettings(); @@ -4880,7 +4856,7 @@ int ServerLobby::getPermissions(std::shared_ptr peer) const if (peer == m_server_owner.lock()) { mask |= CommandPermissions::PE_CROWNED; - if (getSettings()->getOnlyHostRiding()) + if (getSettings()->hasOnlyHostRiding()) mask |= CommandPermissions::PE_SINGLE; } if (peer->isAngryHost()) @@ -5103,7 +5079,7 @@ void ServerLobby::setKartDataProperly(KartData& kart_data, const std::string& ka { const KartProperties* real_addon = kart_properties_manager->getKart(kart_name); - if (getSettings()->getRealAddonKarts() && real_addon) + if (getSettings()->usesRealAddonKarts() && real_addon) { kart_data = KartData(real_addon); } @@ -5157,7 +5133,7 @@ void ServerLobby::saveDisconnectingIdInfo(int id) const if (ffa_world) points = ffa_world->getKartScore(id); info.m_result += points; - if (getSettings()->getPreserveBattleScores()) + if (getSettings()->isPreservingBattleScores()) m_game_info->m_saved_ffa_points[StringUtils::wideToUtf8(rki.getPlayerName())] = points; } info.m_when_left = stk_config->ticks2Time(w->getTicksSinceStart()); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index daf6bdff0a8..9c43dda9ca6 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -234,7 +234,11 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser void handleChat(Event* event); void unregisterServer(bool now, std::weak_ptr sl = std::weak_ptr()); + +public: // I'll see if it should be private later void updatePlayerList(bool update_when_reset_server = false); + +private: void updateServerOwner(bool force = false); void handleServerConfiguration(Event* event); void handleServerConfiguration(std::shared_ptr peer, @@ -287,8 +291,13 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser std::vector >& players, bool live_join) const; void setPlayerKarts(const NetworkString& ns, std::shared_ptr peer) const; - bool handleAssets(const NetworkString& ns, std::shared_ptr peer); - void handleServerCommand(Event* event, std::shared_ptr peer); + bool handleAssets(Event* event); + + bool handleAssetsAndAddonScores(std::shared_ptr peer, + const std::set& client_karts, + const std::set& client_maps); + + void handleServerCommand(Event* event); void liveJoinRequest(Event* event); void rejectLiveJoin(std::shared_ptr peer, BackLobbyReason blr); bool canLiveJoinNow() const; @@ -391,6 +400,8 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser void setSpectateModeProperly(std::shared_ptr peer, AlwaysSpectateMode mode); std::shared_ptr getGameInfo() const { return m_game_info; } + std::shared_ptr getServerOwner() const + { return m_server_owner.lock(); } // Functions that arose from requests separation void setServerOnlineId(uint32_t id) { m_server_id_online.store(id); } diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index 97a0a3f4c1a..efd0f91d556 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -180,8 +180,8 @@ class STKPeer : public NoCopy float getConnectedTime() const { return float(StkTime::getMonoTimeMs() - m_connected_time) / 1000.0f; } // ------------------------------------------------------------------------ - void setAvailableKartsTracks(std::set& k, - std::set& t) + void setAvailableKartsTracks(const std::set& k, + const std::set& t) { m_available_kts = std::make_pair(std::move(k), std::move(t)); } // ------------------------------------------------------------------------ void eraseServerKarts(const std::set& server_karts, diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index f2cc3b5b951..4c8eab672f7 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -686,4 +686,46 @@ void LobbySettings::onServerSetup() NetworkConfig::get()->setTuxHitboxAddon(m_live_players); } // onServerSetup +//----------------------------------------------------------------------------- + +void LobbySettings::tryKickingAnotherPeer(std::shared_ptr initiator, + std::shared_ptr target) const +{ + // Should probably include hammer permissions, but this function is + // originated from the ingame button press. Unify all such functions later. + if (getLobby()->getServerOwner() != initiator) + return; + + if (!hasKicksAllowed()) + { + getLobby()->sendStringToPeer(initiator, "Kicking players is not allowed on this server"); + return; + } + + // Ignore kicking ai peer if ai handling is on + if (target && (!hasAiHandling() || !target->isAIPeer())) + { + if (target->isAngryHost()) + { + getLobby()->sendStringToPeer(initiator, "This player is the owner of this server, " + "and is protected from your actions now"); + return; + } + if (!target->hasPlayerProfiles()) + { + Log::info("ServerLobby", "Crown player kicks a player"); + } + else + { + std::string player_name = target->getMainName(); + Log::info("ServerLobby", "Crown player kicks %s", player_name.c_str()); + } + target->kick(); + if (isTrackingKicks()) + { + std::string auto_report = "[ Auto report caused by kick ]"; + getLobby()->writeOwnReport(target, initiator, auto_report); + } + } +} // tryKickingAnotherPeer //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 682b25068b6..b4b75bb3c0e 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -108,52 +108,55 @@ class LobbySettings: public LobbyContextComponent void onServerSetup(); + void tryKickingAnotherPeer(std::shared_ptr initiator, + std::shared_ptr target) const; + // These were used unchanged from ServerConfig - bool isLivePlayers() const { return m_live_players; } + bool isLivePlayers() const { return m_live_players; } bool canConnectAiAnywhere() const { return m_ai_anywhere; } - bool getAiHandling() const { return m_ai_handling; } + bool hasAiHandling() const { return m_ai_handling; } int getCaptureLimit() const { return m_capture_limit; } - bool getExposeMobile() const { return m_expose_mobile; } - bool getFirewalledServer() const { return m_firewalled_server; } + bool isExposingMobile() const { return m_expose_mobile; } + bool isFirewalledServer() const { return m_firewalled_server; } float getFlagDeactivatedTime() const { return m_flag_deactivated_time; } float getFlagReturnTimeout() const { return m_flag_return_timeout; } - bool getFreeTeams() const { return m_free_teams; } - bool getHighPingWorkaround() const { return m_high_ping_workaround; } + bool hasFreeTeams() const { return m_free_teams; } + bool hasHighPingWorkaround() const { return m_high_ping_workaround; } int getHitLimit() const { return m_hit_limit; } std::string getIncompatibleAdvice() const { return m_incompatible_advice; } int getJitterTolerance() const { return m_jitter_tolerance; } int getKickIdleLobbyPlayerSeconds() const { return m_kick_idle_lobby_player_seconds; } int getKickIdlePlayerSeconds() const { return m_kick_idle_player_seconds; } - bool getKicksAllowed() const { return m_kicks_allowed; } + bool hasKicksAllowed() const { return m_kicks_allowed; } int getMaxPing() const { return m_max_ping; } int getMinStartGamePlayers() const { return m_min_start_game_players; } float getOfficialKartsPlayThreshold() const { return m_official_karts_play_threshold; } float getOfficialTracksPlayThreshold() const { return m_official_tracks_play_threshold; } - bool getOnlyHostRiding() const { return m_only_host_riding; } - bool getOwnerLess() const { return m_owner_less; } - bool getPreserveBattleScores() const { return m_preserve_battle_scores; } + bool hasOnlyHostRiding() const { return m_only_host_riding; } + bool isOwnerLess() const { return m_owner_less; } + bool isPreservingBattleScores() const { return m_preserve_battle_scores; } std::string getPrivateServerPassword() const { return m_private_server_password; } - bool getRanked() const { return m_ranked; } - bool getRealAddonKarts() const { return m_real_addon_karts; } - bool getRecordReplays() const { return m_record_replays; } - bool getServerConfigurable() const { return m_server_configurable; } + bool isRanked() const { return m_ranked; } + bool usesRealAddonKarts() const { return m_real_addon_karts; } + bool isRecordingReplays() const { return m_record_replays; } + bool isServerConfigurable() const { return m_server_configurable; } int getServerDifficulty() const { return m_server_difficulty; } int getServerMaxPlayers() const { return m_server_max_players; } int getServerMode() const { return m_server_mode; } - bool getSleepingServer() const { return m_sleeping_server; } - bool getSoccerGoalTarget() const { return m_soccer_goal_target; } - bool getSqlManagement() const { return m_sql_management; } + bool isSleepingServer() const { return m_sleeping_server; } + bool isSoccerGoalTargetInConfig() const { return m_soccer_goal_target; } + bool hasSqlManagement() const { return m_sql_management; } float getStartGameCounter() const { return m_start_game_counter; } int getStateFrequency() const { return m_state_frequency; } - bool getStoreResults() const { return m_store_results; } - bool getStrictPlayers() const { return m_strict_players; } - bool getTeamChoosing() const { return m_team_choosing; } + bool isStoringResults() const { return m_store_results; } + bool hasStrictPlayers() const { return m_strict_players; } + bool hasTeamChoosing() const { return m_team_choosing; } int getTimeLimitCtf() const { return m_time_limit_ctf; } int getTimeLimitFfa() const { return m_time_limit_ffa; } - bool getTrackKicks() const { return m_track_kicks; } - bool getTrackVoting() const { return m_track_voting; } + bool isTrackingKicks() const { return m_track_kicks; } + bool hasTrackVoting() const { return m_track_voting; } std::string getTrollWarnMsg() const { return m_troll_warn_msg; } - bool getValidatingPlayer() const { return m_validating_player; } + bool isValidatingPlayer() const { return m_validating_player; } float getVotingTimeout() const { return m_voting_timeout; } std::string getCommandsFile() const { return m_commands_file; } int getAddonKartsJoinThreshold() const { return m_addon_karts_join_threshold; } diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp index 5f259e6559f..1817286db40 100644 --- a/src/utils/team_manager.cpp +++ b/src/utils/team_manager.cpp @@ -26,6 +26,9 @@ #include "network/server_config.hpp" #include "network/stk_host.hpp" #include "network/stk_peer.hpp" +#include "utils/lobby_settings.hpp" +#include "utils/tournament.hpp" +#include "network/protocols/server_lobby.hpp" void TeamManager::setupContextUser() { @@ -237,3 +240,37 @@ void TeamManager::shuffleTemporaryTeams(const std::map& permutation) getLobby()->shuffleGPScoresWithPermutation(permutation); } // shuffleTemporaryTeams //----------------------------------------------------------------------------- + +void TeamManager::changeTeam(std::shared_ptr player) +{ + if (!getSettings()->hasTeamChoosing() || + !RaceManager::get()->teamEnabled()) + return; + + auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); + if (isTournament() && !getTournament()->canChangeTeam()) + { + Log::info("ServerLobby", "Team change requested by %s, but tournament forbids it.", player->getName().c_str()); + return; + } + + // For now, the change team button will still only work in soccer + CTF. + // Further logic might be added later, but now it seems to be complicated + // because there's a restriction of 7 for those modes, and unnecessary + // because we don't have client changes. + + // At most 7 players on each team (for live join) + if (player->getTeam() == KART_TEAM_BLUE) + { + if (red_blue.first >= 7 && !getSettings()->hasFreeTeams()) + return; + setTeamInLobby(player, KART_TEAM_RED); + } + else + { + if (red_blue.second >= 7 && !getSettings()->hasFreeTeams()) + return; + setTeamInLobby(player, KART_TEAM_BLUE); + } + getLobby()->updatePlayerList(); +} \ No newline at end of file diff --git a/src/utils/team_manager.hpp b/src/utils/team_manager.hpp index 3c97b4853a7..1b4ba127ce1 100644 --- a/src/utils/team_manager.hpp +++ b/src/utils/team_manager.hpp @@ -66,6 +66,7 @@ class TeamManager: public LobbyContextComponent { return m_hammer_whitelist.find(str) != m_hammer_whitelist.end(); } void clearTemporaryTeams(); void shuffleTemporaryTeams(const std::map& permutation); + void changeTeam(std::shared_ptr player); private: From 377e843cdb043c8447bd39c3513eb12a31a5315f Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 15 Mar 2025 03:29:07 +0400 Subject: [PATCH 599/830] GP manager, more function movements (Seems to start the game on the server) --- src/network/protocol.cpp | 4 +- src/network/protocol.hpp | 4 +- src/network/protocols/command_manager.cpp | 7 +- src/network/protocols/server_lobby.cpp | 233 ++------------------- src/network/protocols/server_lobby.hpp | 29 +-- src/utils/lobby_asset_manager.cpp | 32 +++ src/utils/lobby_asset_manager.hpp | 6 +- src/utils/lobby_context.cpp | 3 + src/utils/lobby_context.hpp | 4 + src/utils/lobby_gp_manager.cpp | 239 ++++++++++++++++++++++ src/utils/lobby_gp_manager.hpp | 72 +++++++ src/utils/team_manager.cpp | 25 ++- src/utils/team_manager.hpp | 1 + 13 files changed, 406 insertions(+), 253 deletions(-) create mode 100644 src/utils/lobby_gp_manager.cpp create mode 100644 src/utils/lobby_gp_manager.hpp diff --git a/src/network/protocol.cpp b/src/network/protocol.cpp index c9dc91a3871..a5d32ce279b 100644 --- a/src/network/protocol.cpp +++ b/src/network/protocol.cpp @@ -96,7 +96,7 @@ void Protocol::requestTerminate() * type) followed by the actual message. * \param message The actual message content. */ -void Protocol::sendMessageToPeers(NetworkString *message, PacketReliabilityMode reliable) +void Protocol::sendMessageToPeers(NetworkString *message, PacketReliabilityMode reliable) const { STKHost::get()->sendPacketToAllPeers(message, reliable); } // sendMessageToPeers @@ -108,7 +108,7 @@ void Protocol::sendMessageToPeers(NetworkString *message, PacketReliabilityMode * \param message The actual message content. */ void Protocol::sendMessageToPeersInServer(NetworkString* message, - PacketReliabilityMode reliable) + PacketReliabilityMode reliable) const { STKHost::get()->sendPacketToAllPeersInServer(message, reliable); } // sendMessageToPeersInServer diff --git a/src/network/protocol.hpp b/src/network/protocol.hpp index 335fd80b7af..6f827fd1df0 100644 --- a/src/network/protocol.hpp +++ b/src/network/protocol.hpp @@ -119,9 +119,9 @@ class Protocol : public std::enable_shared_from_this, /// functions to check incoming data easily NetworkString* getNetworkString(size_t capacity = 16) const; bool checkDataSize(Event* event, unsigned int minimum_size); - void sendMessageToPeers(NetworkString *message, PacketReliabilityMode reliable = PRM_RELIABLE); + void sendMessageToPeers(NetworkString *message, PacketReliabilityMode reliable = PRM_RELIABLE) const; void sendMessageToPeersInServer(NetworkString *message, - PacketReliabilityMode reliable = PRM_RELIABLE); + PacketReliabilityMode reliable = PRM_RELIABLE) const; void sendToServer(NetworkString *message, PacketReliabilityMode reliable = PRM_RELIABLE); virtual void requestStart(); virtual void requestTerminate(); diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 9ad389d1846..c7d4ef03a90 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -39,6 +39,7 @@ #include "utils/kart_elimination.hpp" #include "utils/lobby_asset_manager.hpp" #include "utils/lobby_context.hpp" +#include "utils/lobby_gp_manager.hpp" #include "utils/lobby_settings.hpp" #include "utils/lobby_queues.hpp" #include "utils/log.hpp" @@ -2212,7 +2213,7 @@ void CommandManager::process_standings(Context& context) { // the function will decide itself what to show if nothing is specified: // if there are teams, teams will be shown, otherwise players - msg = getLobby()->getGrandPrixStandings(isGPPlayers, isGPTeams); + msg = getGPManager()->getGrandPrixStandings(isGPPlayers, isGPTeams); } else if (isGnu) msg = getKartElimination()->getStandings(); @@ -2788,7 +2789,7 @@ void CommandManager::process_team(Context& context) "Color %s is not allowed", argv[1])); return; } - getLobby()->setTemporaryTeamInLobby(player, team); + getTeamManager()->setTemporaryTeamInLobby(player, team); getLobby()->updatePlayerList(); } // process_team @@ -2914,7 +2915,7 @@ void CommandManager::process_resetgp(Context& context) } getLobby()->getGameSetup()->setGrandPrixTrack(number_of_games); } - getLobby()->resetGrandPrix(); + getGPManager()->resetGrandPrix(); getLobby()->sendStringToAllPeers("GP is now reset"); } // process_resetgp // ======================================================================== diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index e2276e31bef..bb331d21c4f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -54,6 +54,7 @@ #include "utils/game_info.hpp" #include "utils/hit_processor.hpp" #include "utils/lobby_asset_manager.hpp" +#include "utils/lobby_gp_manager.hpp" #include "utils/lobby_settings.hpp" #include "utils/lobby_queues.hpp" #include "utils/map_vote_handler.hpp" @@ -911,7 +912,7 @@ void ServerLobby::asynchronousUpdate() // cannot return an addon; when addons are supported, this part of // code will also have to provide kart data (or setKartName has to // set the correct hitbox itself). - std::string new_kart = getKartForBadKartChoice( + std::string new_kart = getAssetManager()->getKartForBadKartChoice( players[i]->getPeer(), name, current_kart); if (new_kart != current_kart) { @@ -2000,11 +2001,8 @@ void ServerLobby::startSelection(const Event *event) // Will be changed after the first vote received m_timeout.store(std::numeric_limits::max()); - if (!m_game_setup->isGrandPrixStarted()) - { - m_gp_scores.clear(); - m_gp_team_scores.clear(); - } + + getGPManager()->onStartSelection(); getCommandManager()->onStartSelection(); } // startSelection @@ -2091,74 +2089,7 @@ void ServerLobby::checkRaceFinished() std::vector gp_changes; if (m_game_setup->isGrandPrix()) { - // fastest lap - int fastest_lap = - static_cast(World::getWorld())->getFastestLapTicks(); - m_result_ns->addUInt32(fastest_lap); - irr::core::stringw fastest_kart_wide = - static_cast(World::getWorld()) - ->getFastestLapKartName(); - m_result_ns->encodeString(fastest_kart_wide); - std::string fastest_kart = StringUtils::wideToUtf8(fastest_kart_wide); - - int points_fl = 0; - // Commented until used to remove the warning - // int points_pole = 0; - WorldWithRank *wwr = dynamic_cast(World::getWorld()); - if (wwr) - { - points_fl = wwr->getFastestLapPoints(); - // Commented until used to remove the warning - // points_pole = wwr->getPolePoints(); - } - else - { - Log::error("ServerLobby", - "World with scores that is not a WorldWithRank??"); - } - - // all gp tracks - m_result_ns->addUInt8((uint8_t)m_game_setup->getTotalGrandPrixTracks()) - .addUInt8((uint8_t)m_game_setup->getAllTracks().size()); - for (const std::string& gp_track : m_game_setup->getAllTracks()) - m_result_ns->encodeString(gp_track); - - // each kart score and total time - m_result_ns->addUInt8((uint8_t)RaceManager::get()->getNumPlayers()); - for (unsigned i = 0; i < RaceManager::get()->getNumPlayers(); i++) - { - int last_score = (World::getWorld()->getKart(i)->isEliminated() ? - 0 : RaceManager::get()->getKartScore(i)); - gp_changes.push_back((float)last_score); - int cur_score = last_score; - float overall_time = RaceManager::get()->getOverallTime(i); - std::string username = StringUtils::wideToUtf8( - RaceManager::get()->getKartInfo(i).getPlayerName()); - if (username == fastest_kart) - { - gp_changes.back() += points_fl; - cur_score += points_fl; - } - int team = getTeamManager()->getTeamForUsername(username); - if (team > 0) - { - m_gp_team_scores[team].score += cur_score; - m_gp_team_scores[team].time += overall_time; - } - last_score = m_gp_scores[username].score; - cur_score += last_score; - overall_time = overall_time + m_gp_scores[username].time; - if (auto player = - RaceManager::get()->getKartInfo(i).getNetworkPlayerProfile().lock()) - { - player->setScore(cur_score); - player->setOverallTime(overall_time); - } - m_gp_scores[username].score = cur_score; - m_gp_scores[username].time = overall_time; - m_result_ns->addUInt32(last_score).addUInt32(cur_score) - .addFloat(overall_time); - } + getGPManager()->updateGPScores(gp_changes, m_result_ns); } else if (RaceManager::get()->modeHasLaps()) { @@ -2705,15 +2636,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, getTeamManager()->setTeamInLobby(player, team); } getCommandManager()->addUser(username); - if (m_game_setup->isGrandPrix()) - { - auto it = m_gp_scores.find(username); - if (it != m_gp_scores.end()) - { - player->setScore(it->second.score); - player->setOverallTime(it->second.time); - } - } + getGPManager()->setScoresToPlayer(player); if (!RaceManager::get()->teamEnabled()) { if (previous_team != -1) @@ -4034,7 +3957,8 @@ void ServerLobby::setPlayerKarts(const NetworkString& ns, std::shared_ptrareKartFiltersIgnoringKarts()) current_kart = ""; std::string name = StringUtils::wideToUtf8(peer->getPlayerProfiles()[i]->getName()); - peer->getPlayerProfiles()[i]->setKartName(getKartForBadKartChoice(peer, name, current_kart)); + peer->getPlayerProfiles()[i]->setKartName( + getAssetManager()->getKartForBadKartChoice(peer, name, current_kart)); } if (peer->getClientCapabilities().find("real_addon_karts") == peer->getClientCapabilities().end() || ns.size() == 0) @@ -4817,7 +4741,7 @@ bool ServerLobby::canVote(std::shared_ptr peer) const if (!peer || peer->getPlayerProfiles().empty()) return false; - if (!getTournament()) + if (!isTournament()) return true; return getTournament()->canVote(peer); @@ -4870,65 +4794,7 @@ int ServerLobby::getPermissions(std::shared_ptr peer) const return mask; } // getPermissions //----------------------------------------------------------------------------- -std::string ServerLobby::getGrandPrixStandings(bool showIndividual, bool showTeam) const -{ - std::stringstream response; - response << "Grand Prix standings"; - if (!showIndividual && !showTeam) - { - if (m_gp_team_scores.empty()) - showIndividual = true; - else - showTeam = true; - } - - uint8_t passed = (uint8_t)m_game_setup->getAllTracks().size(); - uint8_t total = m_game_setup->getExtraServerInfo(); - if (passed != 0) - response << " after " << (int)passed << " of " << (int)total << " games:\n"; - else - response << ", " << (int)total << " games:\n"; - - if (showIndividual) - { - std::vector> results; - for (auto &p: m_gp_scores) - results.emplace_back(p.second, p.first); - std::stable_sort(results.rbegin(), results.rend()); - for (unsigned i = 0; i < results.size(); i++) - { - response << (i + 1) << ". "; - response << " " << results[i].second; - response << " " << results[i].first.score; - response << " " << "(" << StringUtils::timeToString(results[i].first.time) << ")"; - response << "\n"; - } - } - - if (showTeam) - { - if (!m_gp_team_scores.empty()) - { - std::vector> results2; - if (showIndividual) - response << "\n"; - for (auto &p: m_gp_team_scores) - results2.emplace_back(p.second, p.first); - std::stable_sort(results2.rbegin(), results2.rend()); - for (unsigned i = 0; i < results2.size(); i++) - { - response << (i + 1) << ". "; - response << " " << TeamUtils::getTeamByIndex(results2[i].second).getNameWithEmoji(); - response << " " << results2[i].first.score; - response << " " << "(" << StringUtils::timeToString(results2[i].first.time) << ")"; - response << "\n"; - } - } - } - return response.str(); -} // getGrandPrixStandings -//----------------------------------------------------------------------------- bool ServerLobby::writeOnePlayerReport(std::shared_ptr reporter, const std::string& table, const std::string& info) { @@ -4953,12 +4819,7 @@ bool ServerLobby::writeOnePlayerReport(std::shared_ptr reporter, void ServerLobby::changeLimitForTournament(bool goal_target) { m_game_setup->setSoccerGoalTarget(goal_target); - NetworkString* server_info = getNetworkString(); - server_info->setSynchronous(true); - server_info->addUInt8(LE_SERVER_INFO); - m_game_setup->addServerInfo(server_info); - sendMessageToPeers(server_info); - delete server_info; + sendServerInfoToEveryone(); updatePlayerList(); } // changeLimitForTournament //----------------------------------------------------------------------------- @@ -5006,60 +4867,6 @@ bool ServerLobby::isSoccerGoalTarget() const } // isSoccerGoalTarget //----------------------------------------------------------------------------- -// This should be moved later to another unit. -void ServerLobby::setTemporaryTeamInLobby(const std::string& username, int team) -{ - irr::core::stringw wide_player_name = StringUtils::utf8ToWide(username); - std::shared_ptr player_peer = STKHost::get()->findPeerByName( - wide_player_name); - if (player_peer) - { - for (auto& profile : player_peer.get()->getPlayerProfiles()) - { - if (profile->getName() == wide_player_name) - { - getTeamManager()->setTemporaryTeamInLobby(profile, team); - break; - } - } - } -} // setTemporaryTeamInLobby (username) -//----------------------------------------------------------------------------- - -void ServerLobby::resetGrandPrix() -{ - m_gp_scores.clear(); - m_gp_team_scores.clear(); - m_game_setup->stopGrandPrix(); - - NetworkString* server_info = getNetworkString(); - server_info->setSynchronous(true); - server_info->addUInt8(LE_SERVER_INFO); - m_game_setup->addServerInfo(server_info); - sendMessageToPeers(server_info); - delete server_info; - updatePlayerList(); -} // resetGrandPrix -//----------------------------------------------------------------------------- - -std::string ServerLobby::getKartForBadKartChoice(std::shared_ptr peer, const std::string& username, const std::string& check_choice) const -{ - std::set karts = (peer->isAIPeer() ? getAssetManager()->getAvailableKarts() : peer->getClientAssets().first); - getAssetManager()->applyAllKartFilters(username, karts, true); - if (getKartElimination()->isEliminated(username) - && karts.count(getKartElimination()->getKart())) - { - return getKartElimination()->getKart(); - } - if (!check_choice.empty() && karts.count(check_choice)) // valid choice - return check_choice; - // choice is invalid, roll the random - RandomGenerator rg; - std::set::iterator it = karts.begin(); - std::advance(it, rg.get((int)karts.size())); - return *it; -} // getKartForRandomKartChoice -//----------------------------------------------------------------------------- void ServerLobby::setKartDataProperly(KartData& kart_data, const std::string& kart_name, std::shared_ptr player, const std::string& type) const @@ -5208,17 +5015,13 @@ void ServerLobby::setSpectateModeProperly(std::shared_ptr peer, AlwaysS } // setSpectateModeProperly //----------------------------------------------------------------------------- -void ServerLobby::shuffleGPScoresWithPermutation(const std::map& permutation) +void ServerLobby::sendServerInfoToEveryone() const { - auto old_scores = m_gp_team_scores; - m_gp_team_scores.clear(); - for (auto& p: old_scores) - { - auto it = permutation.find(p.first); - if (it != permutation.end()) - m_gp_team_scores[it->second] = p.second; - else - m_gp_team_scores[p.first] = p.second; - } -} // shuffleGPScoresWithPermutation + NetworkString* server_info = getNetworkString(); + server_info->setSynchronous(true); + server_info->addUInt8(LE_SERVER_INFO); + m_game_setup->addServerInfo(server_info); + sendMessageToPeers(server_info); + delete server_info; +} // sendServerInfoToEveryone //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 9c43dda9ca6..dcaa3bcac31 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -65,23 +65,6 @@ namespace Online class Request; } -// I know it should be in a more suitable place, but for now I have no idea -// how to make this with the current system. Sorry. Hope to refactor later. - -struct GPScore -{ - int score = 0; - double time = 0.; - bool operator < (const GPScore& rhs) const - { - return (score < rhs.score || (score == rhs.score && time > rhs.time)); - } - bool operator > (const GPScore& rhs) const - { - return (score > rhs.score || (score == rhs.score && time < rhs.time)); - } -}; - class ServerLobby : public LobbyProtocol, public LobbyContextUser { public: @@ -210,10 +193,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser std::set m_temp_banned; - std::map m_gp_scores; - - std::map m_gp_team_scores; - std::atomic m_current_max_players_in_game; std::shared_ptr m_game_info; @@ -319,7 +298,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser bool canRace(std::shared_ptr peer); bool canVote(std::shared_ptr peer) const; bool hasHostRights(std::shared_ptr peer) const; - std::string getGrandPrixStandings(bool showIndividual = false, bool showTeam = true) const; void changeLimitForTournament(bool goal_target); public: @@ -378,12 +356,10 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser std::string& direction, int laps); #endif - void setTemporaryTeamInLobby(const std::string& username, int team); - void resetGrandPrix(); void erasePeerReady(std::shared_ptr peer) { m_peers_ready.erase(peer); } bool areKartFiltersIgnoringKarts() const; - std::string getKartForBadKartChoice(std::shared_ptr peer, const std::string& username, const std::string& check_choice) const; + void setKartDataProperly(KartData& kart_data, const std::string& kart_name, std::shared_ptr player, const std::string& type) const; @@ -392,8 +368,7 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser void saveDisconnectingPeerInfo(std::shared_ptr peer) const; void saveDisconnectingIdInfo(int id) const; - - void shuffleGPScoresWithPermutation(const std::map& permutation); + void sendServerInfoToEveryone() const; // The functions below reset/set ASM_NO_TEAM if needed by team changing procedure. void checkNoTeamSpectator(std::shared_ptr peer); diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp index dc94a1aa387..e6c4ec72791 100644 --- a/src/utils/lobby_asset_manager.cpp +++ b/src/utils/lobby_asset_manager.cpp @@ -28,6 +28,7 @@ #include "network/stk_peer.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" +#include "utils/kart_elimination.hpp" #include "utils/lobby_queues.hpp" #include "utils/lobby_settings.hpp" #include "utils/random_generator.hpp" @@ -639,4 +640,35 @@ void LobbyAssetManager::applyAllKartFilters(const std::string& username, std::se getQueues()->applyFrontKartFilters(kart_context); swap(karts, kart_context.elements); } // applyAllKartFilters +//----------------------------------------------------------------------------- + +std::string LobbyAssetManager::getKartForBadKartChoice( + std::shared_ptr peer, + const std::string& username, + const std::string& check_choice) const +{ + std::set karts; + if (peer->isAIPeer()) + karts = getAvailableKarts(); + else + karts = peer->getClientAssets().first; + + applyAllKartFilters(username, karts, true); + + auto kart_elimination = getKartElimination(); + if (kart_elimination->isEliminated(username) + && karts.count(kart_elimination->getKart())) + { + return kart_elimination->getKart(); + } + + if (!check_choice.empty() && karts.count(check_choice)) // valid choice + return check_choice; + + // choice is invalid, roll the random + RandomGenerator rg; + std::set::iterator it = karts.begin(); + std::advance(it, rg.get((int)karts.size())); + return *it; +} // getKartForRandomKartChoice //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/lobby_asset_manager.hpp b/src/utils/lobby_asset_manager.hpp index d2e0e7ff3b9..d620e7fa8a7 100644 --- a/src/utils/lobby_asset_manager.hpp +++ b/src/utils/lobby_asset_manager.hpp @@ -77,7 +77,11 @@ class LobbyAssetManager: public LobbyContextComponent void applyAllFilters(std::set& maps, bool use_history) const; void applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection = false) const; - + + std::string getKartForBadKartChoice( + std::shared_ptr peer, + const std::string& username, + const std::string& check_choice) const; std::set getAddonKarts() const { return m_addon_kts.first; } std::set getAddonTracks() const { return m_addon_kts.second; } diff --git a/src/utils/lobby_context.cpp b/src/utils/lobby_context.cpp index 2fa9d344861..7eb0e1cf02a 100644 --- a/src/utils/lobby_context.cpp +++ b/src/utils/lobby_context.cpp @@ -28,6 +28,7 @@ #include "utils/map_vote_handler.hpp" #include "utils/team_manager.hpp" #include "utils/tournament.hpp" +#include "utils/lobby_gp_manager.hpp" LobbyContext::LobbyContext(ServerLobby* lobby, bool make_tournament) : m_lobby(lobby) @@ -42,6 +43,7 @@ LobbyContext::LobbyContext(ServerLobby* lobby, bool make_tournament) m_command_manager = std::make_shared(this); m_chat_manager = std::make_shared(this); m_team_manager = std::make_shared(this); + m_gp_manager = std::make_shared(this); if (make_tournament) m_tournament = std::make_shared(this); @@ -60,6 +62,7 @@ void LobbyContext::setup() m_chat_manager->setupContextUser(); m_team_manager->setupContextUser(); m_command_manager->setupContextUser(); + m_gp_manager->setupContextUser(); if (m_tournament) m_tournament->setupContextUser(); diff --git a/src/utils/lobby_context.hpp b/src/utils/lobby_context.hpp index 11b40014537..5cc4b1fbc82 100644 --- a/src/utils/lobby_context.hpp +++ b/src/utils/lobby_context.hpp @@ -34,6 +34,7 @@ class MapVoteHandler; class ServerLobby; class TeamManager; class Tournament; +class LobbyGPManager; class LobbyContext { @@ -49,6 +50,7 @@ class LobbyContext std::shared_ptr m_command_manager; std::shared_ptr m_chat_manager; std::shared_ptr m_team_manager; + std::shared_ptr m_gp_manager; public: @@ -68,6 +70,7 @@ class LobbyContext std::shared_ptr getCommandManager() const { return m_command_manager; } std::shared_ptr getChatManager() const { return m_chat_manager; } std::shared_ptr getTeamManager() const { return m_team_manager; } + std::shared_ptr getGPManager() const { return m_gp_manager; } }; class LobbyContextUser @@ -86,6 +89,7 @@ class LobbyContextUser std::shared_ptr getCommandManager() const { return m_context->getCommandManager(); } std::shared_ptr getChatManager() const { return m_context->getChatManager(); } std::shared_ptr getTeamManager() const { return m_context->getTeamManager(); } + std::shared_ptr getGPManager() const { return m_context->getGPManager(); } public: void setContext(LobbyContext* context) { m_context = context; } diff --git a/src/utils/lobby_gp_manager.cpp b/src/utils/lobby_gp_manager.cpp new file mode 100644 index 00000000000..c0cb1a59184 --- /dev/null +++ b/src/utils/lobby_gp_manager.cpp @@ -0,0 +1,239 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/lobby_gp_manager.hpp" + +#include "network/server_config.hpp" +#include "utils/string_utils.hpp" +#include "network/game_setup.hpp" +#include "network/protocols/server_lobby.hpp" +#include "network/network_player_profile.hpp" +#include "modes/world.hpp" +#include "karts/abstract_kart.hpp" +#include "utils/team_manager.hpp" +#include "modes/world_with_rank.hpp" +#include "modes/linear_world.hpp" +#include "network/network_string.hpp" + +void LobbyGPManager::setupContextUser() +{ + +} // setupContextUser +//----------------------------------------------------------------------------- + +void LobbyGPManager::onStartSelection() +{ + if (!getLobby()->getGameSetup()->isGrandPrixStarted()) + { + m_gp_scores.clear(); + m_gp_team_scores.clear(); + } +} // onStartSelection +//----------------------------------------------------------------------------- + +void LobbyGPManager::setScoresToPlayer(std::shared_ptr player) const +{ + std::string username = StringUtils::wideToUtf8(player->getName()); + if (getLobby()->getGameSetup()->isGrandPrix()) + { + auto it = m_gp_scores.find(username); + if (it != m_gp_scores.end()) + { + player->setScore(it->second.score); + player->setOverallTime(it->second.time); + } + } +} // setScoresToPlayer +//----------------------------------------------------------------------------- + +std::string LobbyGPManager::getGrandPrixStandings(bool showIndividual, bool showTeam) const +{ + std::stringstream response; + response << "Grand Prix standings"; + + if (!showIndividual && !showTeam) + { + if (m_gp_team_scores.empty()) + showIndividual = true; + else + showTeam = true; + } + + auto game_setup = getLobby()->getGameSetup(); + uint8_t passed = (uint8_t)game_setup->getAllTracks().size(); + uint8_t total = game_setup->getExtraServerInfo(); + if (passed != 0) + response << " after " << (int)passed << " of " << (int)total << " games:\n"; + else + response << ", " << (int)total << " games:\n"; + + if (showIndividual) + { + std::vector> results; + for (auto &p: m_gp_scores) + results.emplace_back(p.second, p.first); + std::stable_sort(results.rbegin(), results.rend()); + for (unsigned i = 0; i < results.size(); i++) + { + response << (i + 1) << ". "; + response << " " << results[i].second; + response << " " << results[i].first.score; + response << " " << "(" << StringUtils::timeToString(results[i].first.time) << ")"; + response << "\n"; + } + } + + if (showTeam) + { + if (!m_gp_team_scores.empty()) + { + std::vector> results2; + if (showIndividual) + response << "\n"; + for (auto &p: m_gp_team_scores) + results2.emplace_back(p.second, p.first); + std::stable_sort(results2.rbegin(), results2.rend()); + for (unsigned i = 0; i < results2.size(); i++) + { + response << (i + 1) << ". "; + response << " " << TeamUtils::getTeamByIndex(results2[i].second).getNameWithEmoji(); + response << " " << results2[i].first.score; + response << " " << "(" << StringUtils::timeToString(results2[i].first.time) << ")"; + response << "\n"; + } + } + } + return response.str(); +} // getGrandPrixStandings +//----------------------------------------------------------------------------- + +void LobbyGPManager::resetGrandPrix() +{ + m_gp_scores.clear(); + m_gp_team_scores.clear(); + getLobby()->getGameSetup()->stopGrandPrix(); + + getLobby()->sendServerInfoToEveryone(); + getLobby()->updatePlayerList(); +} // resetGrandPrix +//----------------------------------------------------------------------------- + +void LobbyGPManager::shuffleGPScoresWithPermutation(const std::map& permutation) +{ + auto old_scores = m_gp_team_scores; + m_gp_team_scores.clear(); + for (auto& p: old_scores) + { + auto it = permutation.find(p.first); + if (it != permutation.end()) + m_gp_team_scores[it->second] = p.second; + else + m_gp_team_scores[p.first] = p.second; + } +} // shuffleGPScoresWithPermutation +//----------------------------------------------------------------------------- + +void LobbyGPManager::updateGPScores(std::vector& gp_changes, NetworkString* ns) +{ + // fastest lap + int fastest_lap = + static_cast(World::getWorld())->getFastestLapTicks(); + irr::core::stringw fastest_kart_wide = + static_cast(World::getWorld()) + ->getFastestLapKartName(); + std::string fastest_kart = StringUtils::wideToUtf8(fastest_kart_wide); + + // all gp tracks + auto game_setup = getLobby()->getGameSetup(); + + int points_fl = 0; + // Commented until used to remove the warning + // int points_pole = 0; + WorldWithRank *wwr = dynamic_cast(World::getWorld()); + if (wwr) + { + points_fl = wwr->getFastestLapPoints(); + // Commented until used to remove the warning + // points_pole = wwr->getPolePoints(); + } + else + { + Log::error("LobbyGPManager", + "World with scores that is not a WorldWithRank??"); + } + + std::vector last_scores; + std::vector cur_scores; + std::vector overall_times; + + for (unsigned i = 0; i < RaceManager::get()->getNumPlayers(); i++) + { + int last_score = (World::getWorld()->getKart(i)->isEliminated() ? + 0 : RaceManager::get()->getKartScore(i)); + gp_changes.push_back((float)last_score); + int cur_score = last_score; + float overall_time = RaceManager::get()->getOverallTime(i); + std::string username = StringUtils::wideToUtf8( + RaceManager::get()->getKartInfo(i).getPlayerName()); + if (username == fastest_kart) + { + gp_changes.back() += points_fl; + cur_score += points_fl; + } + int team = getTeamManager()->getTeamForUsername(username); + if (team > 0) + { + auto& item = m_gp_team_scores[team]; + item.score += cur_score; + item.time += overall_time; + } + last_score = m_gp_scores[username].score; + cur_score += last_score; + overall_time = overall_time + m_gp_scores[username].time; + if (auto player = + RaceManager::get()->getKartInfo(i).getNetworkPlayerProfile().lock()) + { + player->setScore(cur_score); + player->setOverallTime(overall_time); + } + auto& item = m_gp_scores[username]; + item.score = cur_score; + item.time = overall_time; + last_scores.push_back(last_score); + cur_scores.push_back(cur_score); + overall_times.push_back(overall_time); + } + + ns->addUInt32(fastest_lap); + ns->encodeString(fastest_kart_wide); + + ns->addUInt8((uint8_t)game_setup->getTotalGrandPrixTracks()) + .addUInt8((uint8_t)game_setup->getAllTracks().size()); + + for (const std::string& gp_track : game_setup->getAllTracks()) + ns->encodeString(gp_track); + + ns->addUInt8((uint8_t)RaceManager::get()->getNumPlayers()); + for (unsigned i = 0; i < RaceManager::get()->getNumPlayers(); i++) + { + ns->addUInt32(last_scores[i]) + .addUInt32(cur_scores[i]) + .addFloat(overall_times[i]); + } +} // updateGPScores +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/lobby_gp_manager.hpp b/src/utils/lobby_gp_manager.hpp new file mode 100644 index 00000000000..11502b33980 --- /dev/null +++ b/src/utils/lobby_gp_manager.hpp @@ -0,0 +1,72 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef LOBBY_GP_MANAGER_HPP +#define LOBBY_GP_MANAGER_HPP + +#include "irrString.h" +#include "utils/track_filter.hpp" +#include "utils/lobby_context.hpp" + +#include +#include + +class NetworkPlayerProfile; +class NetworkString; + +struct GPScore +{ + int score = 0; + double time = 0.; + bool operator < (const GPScore& rhs) const + { + return (score < rhs.score || (score == rhs.score && time > rhs.time)); + } + bool operator > (const GPScore& rhs) const + { + return (score > rhs.score || (score == rhs.score && time < rhs.time)); + } +}; + +class LobbyGPManager: public LobbyContextComponent +{ +public: + LobbyGPManager(LobbyContext* context): LobbyContextComponent(context) {} + + void setupContextUser() OVERRIDE; + + void onStartSelection(); + + void setScoresToPlayer(std::shared_ptr player) const; + + std::string getGrandPrixStandings(bool showIndividual = false, bool showTeam = true) const; + + void resetGrandPrix(); + + void shuffleGPScoresWithPermutation(const std::map& permutation); + + void updateGPScores(std::vector& gp_changes, NetworkString* ns); + +private: + std::map m_gp_scores; + + std::map m_gp_team_scores; + +}; + +#endif // LOBBY_GP_MANAGER_HPP \ No newline at end of file diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp index 1817286db40..dbf38475e2f 100644 --- a/src/utils/team_manager.cpp +++ b/src/utils/team_manager.cpp @@ -26,6 +26,7 @@ #include "network/server_config.hpp" #include "network/stk_host.hpp" #include "network/stk_peer.hpp" +#include "utils/lobby_gp_manager.hpp" #include "utils/lobby_settings.hpp" #include "utils/tournament.hpp" #include "network/protocols/server_lobby.hpp" @@ -37,6 +38,25 @@ void TeamManager::setupContextUser() } // setupContextUser //----------------------------------------------------------------------------- +void TeamManager::setTemporaryTeamInLobby(const std::string& username, int team) +{ + irr::core::stringw wide_player_name = StringUtils::utf8ToWide(username); + std::shared_ptr player_peer = STKHost::get()->findPeerByName( + wide_player_name); + if (player_peer) + { + for (auto& profile : player_peer.get()->getPlayerProfiles()) + { + if (profile->getName() == wide_player_name) + { + getTeamManager()->setTemporaryTeamInLobby(profile, team); + break; + } + } + } +} // setTemporaryTeamInLobby (username) +//----------------------------------------------------------------------------- + void TeamManager::setTeamInLobby(std::shared_ptr profile, KartTeam team) { // Used for soccer+CTF, where everything can be defined by KartTeam @@ -49,8 +69,8 @@ void TeamManager::setTeamInLobby(std::shared_ptr profile, getLobby()->checkNoTeamSpectator(profile->getPeer()); } // setTeamInLobby - //----------------------------------------------------------------------------- + void TeamManager::setTemporaryTeamInLobby(std::shared_ptr profile, int team) { // Used for racing+FFA, where everything can be defined by a temporary team @@ -66,7 +86,6 @@ void TeamManager::setTemporaryTeamInLobby(std::shared_ptr getLobby()->checkNoTeamSpectator(profile->getPeer()); } // setTemporaryTeamInLobby - //----------------------------------------------------------------------------- void TeamManager::applyPermutationToTeams(const std::map& permutation) @@ -237,7 +256,7 @@ void TeamManager::shuffleTemporaryTeams(const std::map& permutation) } } } - getLobby()->shuffleGPScoresWithPermutation(permutation); + getGPManager()->shuffleGPScoresWithPermutation(permutation); } // shuffleTemporaryTeams //----------------------------------------------------------------------------- diff --git a/src/utils/team_manager.hpp b/src/utils/team_manager.hpp index 1b4ba127ce1..cef177b811a 100644 --- a/src/utils/team_manager.hpp +++ b/src/utils/team_manager.hpp @@ -40,6 +40,7 @@ class TeamManager: public LobbyContextComponent // The functions below set *both* KartTeam and temporary team, // depending on game mode; also reset/set ASM_NO_TEAM if needed. + void setTemporaryTeamInLobby(const std::string& username, int team); void setTeamInLobby(std::shared_ptr profile, KartTeam team); void setTemporaryTeamInLobby(std::shared_ptr profile, int team); void applyPermutationToTeams(const std::map& permutation); From 07ad1e653f2a702904c3e22214a7037719e7b3a1 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 15 Mar 2025 14:30:44 +0400 Subject: [PATCH 600/830] Protocol cleanup: one packet --- src/network/event.cpp | 2 +- src/network/network_string.cpp | 98 +++++++++ src/network/network_string.hpp | 6 + src/network/packet_types.hpp | 191 ++++++++++++++++++ src/network/packet_types_base.hpp | 74 +++++++ src/network/protocols/client_lobby.cpp | 30 +-- src/network/protocols/lobby_protocol.hpp | 58 +----- src/network/protocols/server_lobby.cpp | 32 +-- src/network/stk_host.cpp | 2 +- .../dialogs/network_player_dialog.cpp | 8 +- .../dialogs/race_paused_dialog.cpp | 2 +- .../dialogs/server_configuration_dialog.cpp | 2 +- .../online/network_kart_selection.cpp | 6 +- .../online/networking_lobby.cpp | 4 +- src/states_screens/online/tracks_screen.cpp | 2 +- src/utils/chat_manager.cpp | 2 +- src/utils/string_utils.hpp | 25 +++ 17 files changed, 448 insertions(+), 96 deletions(-) create mode 100644 src/network/packet_types.hpp create mode 100644 src/network/packet_types_base.hpp diff --git a/src/network/event.cpp b/src/network/event.cpp index adc242262f0..6c5227ef85f 100644 --- a/src/network/event.cpp +++ b/src/network/event.cpp @@ -35,7 +35,7 @@ constexpr bool isConnectionRequestPacket(unsigned char* data, size_t length) { // Connection request is not synchronous return length < 2 ? false : (uint8_t)data[0] == PROTOCOL_LOBBY_ROOM && - (uint8_t)data[1] == LobbyProtocol::LE_CONNECTION_REQUESTED; + (uint8_t)data[1] == LobbyEvent::LE_CONNECTION_REQUESTED; } // isConnectionRequestPacket // ============================================================================ diff --git a/src/network/network_string.cpp b/src/network/network_string.cpp index 9816b6eeb0a..ea2d4c69901 100644 --- a/src/network/network_string.cpp +++ b/src/network/network_string.cpp @@ -238,7 +238,105 @@ std::string BareNetworkString::getLogMessage(const std::string &indent) const if(line+16 +void BareNetworkString::encode(const uint32_t& value) +{ + Log::debug("BareNetworkString", "before encode %s", getLogMessage(" ").c_str()); + addUInt32(value); + Log::debug("BareNetworkString", " after encode %s", getLogMessage(" ").c_str()); +} // encode(uint32_t) +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +template<> +void BareNetworkString::decode(uint32_t& value) +{ + Log::debug("BareNetworkString", "before decode %s", getLogMessage(" ").c_str()); + value = getUInt32(); + Log::debug("BareNetworkString", " after decode %s", getLogMessage(" ").c_str()); +} // decode(uint32_t) +//----------------------------------------------------------------------------- +template<> +void BareNetworkString::encode(const uint8_t& value) +{ + Log::debug("BareNetworkString", "before encode %s", getLogMessage(" ").c_str()); + addUInt8(value); + Log::debug("BareNetworkString", " after encode %s", getLogMessage(" ").c_str()); +} // encode(uint8_t) +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +template<> +void BareNetworkString::decode(uint8_t& value) +{ + Log::debug("BareNetworkString", "before decode %s", getLogMessage(" ").c_str()); + value = getUInt8(); + Log::debug("BareNetworkString", " after decode %s", getLogMessage(" ").c_str()); +} // decode(uint8_t) +//----------------------------------------------------------------------------- +template<> +void BareNetworkString::encode(const irr::core::stringw& value) +{ + Log::debug("BareNetworkString", "before encode %s", getLogMessage(" ").c_str()); + encodeString(value); + Log::debug("BareNetworkString", " after encode %s", getLogMessage(" ").c_str()); +} // encode(irr::core::stringw) +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +template<> +void BareNetworkString::decode(irr::core::stringw& value) +{ + Log::debug("BareNetworkString", "before decode %s", getLogMessage(" ").c_str()); + decodeStringW(&value); + Log::debug("BareNetworkString", " after decode %s", getLogMessage(" ").c_str()); +} // decode(irr::core::stringw) +//----------------------------------------------------------------------------- +template<> +void BareNetworkString::encode(const std::string& value) +{ + Log::debug("BareNetworkString", "before encode %s", getLogMessage(" ").c_str()); + encodeString(value); + Log::debug("BareNetworkString", " after encode %s", getLogMessage(" ").c_str()); +} // encode(std::string) +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +template<> +void BareNetworkString::decode(std::string& value) +{ + Log::debug("BareNetworkString", "before decode %s", getLogMessage(" ").c_str()); + decodeString(&value); + Log::debug("BareNetworkString", " after decode %s", getLogMessage(" ").c_str()); +} // decode(std::string) +//----------------------------------------------------------------------------- +template<> +void BareNetworkString::encode(const bool& value) +{ + Log::debug("BareNetworkString", "before encode %s", getLogMessage(" ").c_str()); + addUInt8(value ? 1 : 0); + Log::debug("BareNetworkString", " after encode %s", getLogMessage(" ").c_str()); +} // encode(bool) +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +template<> +void BareNetworkString::decode(bool& value) +{ + Log::debug("BareNetworkString", "before decode %s", getLogMessage(" ").c_str()); + value = getUInt8() == 1; + Log::debug("BareNetworkString", " after decode %s", getLogMessage(" ").c_str()); +} // decode(bool) +//----------------------------------------------------------------------------- +// template<> +// void BareNetworkString::encode(const T& value) +// { + +// } // encode(T) +// //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// template<> +// void BareNetworkString::decode(T& value) +// { + +// } // decode(T) +// //----------------------------------------------------------------------------- diff --git a/src/network/network_string.hpp b/src/network/network_string.hpp index 4fe26bc751b..fe362af8f82 100644 --- a/src/network/network_string.hpp +++ b/src/network/network_string.hpp @@ -398,6 +398,12 @@ friend class Crypto; return q; } // getQuat // ------------------------------------------------------------------------ + template + void encode(const T& value); + // ------------------------------------------------------------------------ + template + void decode(T& value); + // ------------------------------------------------------------------------ }; // class BareNetworkString diff --git a/src/network/packet_types.hpp b/src/network/packet_types.hpp new file mode 100644 index 00000000000..2eb81fe1771 --- /dev/null +++ b/src/network/packet_types.hpp @@ -0,0 +1,191 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef PACKET_TYPES_HPP +#define PACKET_TYPES_HPP + +#include "network/network_string.hpp" +#include "utils/string_utils.hpp" +#include + +/** + * IMPORTANT! + * This class is meant to describe the overall structure of network packets + * and operations on them, using only the "network/packet_types_base.hpp". + * No other files should include the base header as it has no guards. + * Include this header instead. + */ + +//---------------------- Enums ------------------------------------------------ + +/** Lists all lobby events (LE). */ + +enum LobbyEvent: uint8_t +{ + LE_CONNECTION_REQUESTED = 1, // a connection to the server + LE_CONNECTION_REFUSED, // Connection to server refused + LE_CONNECTION_ACCEPTED, // Connection to server accepted + LE_SERVER_INFO, // inform client about server info + LE_REQUEST_BEGIN, // begin of kart selection + LE_UPDATE_PLAYER_LIST, // inform client about player list update + LE_KART_SELECTION, // Player selected kart + LE_PLAYER_DISCONNECTED, // Client disconnected + LE_CLIENT_LOADED_WORLD, // Client finished loading world + LE_LOAD_WORLD, // Clients should load world + LE_START_RACE, // Server to client to start race + LE_START_SELECTION, // inform client to start selection + LE_RACE_FINISHED, // race has finished, display result + LE_RACE_FINISHED_ACK, // client went back to lobby + LE_BACK_LOBBY, // Force clients to go back to lobby + LE_VOTE, // Track vote + LE_CHAT, // Client chat message + LE_SERVER_OWNERSHIP, // Tell client he is now the server owner + LE_KICK_HOST, // Server owner kicks some other peer in game + LE_CHANGE_TEAM, // Client wants to change his team + LE_BAD_TEAM, // Tell server owner that the team is unbalanced + LE_BAD_CONNECTION, // High ping or too many packets loss + LE_CONFIG_SERVER, // Server owner config server game mode or difficulty + LE_CHANGE_HANDICAP, // Client changes handicap + LE_LIVE_JOIN, // Client live join or spectate + LE_LIVE_JOIN_ACK, // Server tell client live join or spectate succeed + LE_KART_INFO, // Client or server exchange new kart info + LE_CLIENT_BACK_LOBBY, // Client tell server to go back lobby + LE_REPORT_PLAYER, // Client report some player in server + // (like abusive behaviour) + LE_ASSETS_UPDATE, // Client tell server with updated assets + LE_COMMAND, // Command +}; + +enum RejectReason : uint8_t +{ + RR_BUSY = 0, + RR_BANNED = 1, + RR_INCORRECT_PASSWORD = 2, + RR_INCOMPATIBLE_DATA = 3, + RR_TOO_MANY_PLAYERS = 4, + RR_INVALID_PLAYER = 5 +}; + +enum BackLobbyReason : uint8_t +{ + BLR_NONE = 0, + BLR_NO_GAME_FOR_LIVE_JOIN = 1, + BLR_NO_PLACE_FOR_LIVE_JOIN = 2, + BLR_ONE_PLAYER_IN_RANKED_MATCH = 3, + BLR_SERVER_ONWER_QUITED_THE_GAME = 4, + BLR_SPECTATING_NEXT_GAME = 5 +}; + +//---------------------- Initialization --------------------------------------- + +#define DEFINE_CLASS(Name) \ +struct Name { \ + public: \ + void toNetworkString(NetworkString* ns) const; \ + void fromNetworkString(NetworkString* ns); + +#define SYNCHRONOUS(Value) bool isSynchronous() { return Value; } +#define DEFINE_FIELD(Type, Var) Type Var; +#define DEFINE_FIXED_FIELD(Type, Var, Value) Type Var; +#define DEFINE_VECTOR(Type, Size, Var) std::vector Var; +#define END_DEFINE_CLASS(Name) }; + +#include "network/packet_types_base.hpp" +#undef DEFINE_CLASS +#undef SYNCHRONOUS +#undef DEFINE_FIELD +#undef DEFINE_FIXED_FIELD +#undef DEFINE_VECTOR +#undef END_DEFINE_CLASS + +//---------------------- To NetworkString ------------------------------------- + +#define DEFINE_CLASS(Name) \ +inline void Name::toNetworkString(NetworkString* ns) const \ +{ + +#define SYNCHRONOUS(Value) \ + ns->setSynchronous(Value); + +#define DEFINE_FIELD(Type, Var) \ + ns->encode(Var); + +#define DEFINE_FIXED_FIELD(Type, Var, Value) \ + ns->encode(Value); + +#define DEFINE_VECTOR(Type, Size, Value) \ + for (unsigned Value##_cnt = 0; Value##_cnt < Size; ++Value##_cnt) { \ + Value[Value##_cnt].toNetworkString(ns); \ + } + +#define END_DEFINE_CLASS(Name) \ +} + +#include "network/packet_types_base.hpp" +#undef DEFINE_CLASS +#undef SYNCHRONOUS +#undef DEFINE_FIELD +#undef DEFINE_FIXED_FIELD +#undef DEFINE_VECTOR +#undef END_DEFINE_CLASS + +//---------------------- From NetworkString ----------------------------------- + +#define DEFINE_CLASS(Name) \ +inline void Name::fromNetworkString(NetworkString* ns) \ +{ + +#define SYNCHRONOUS(Value) + +#define DEFINE_FIELD(Type, Var) \ + ns->decode(Var); + +#define DEFINE_FIXED_FIELD(Type, Var, Value) + +#define DEFINE_VECTOR(Type, Size, Var) \ + Var.resize(Size); \ + for (unsigned Var##_cnt = 0; Var##_cnt < Size; ++Var##_cnt) { \ + Var[Var##_cnt].fromNetworkString(ns); \ + } + +#define END_DEFINE_CLASS(Name) \ +} + +#include "network/packet_types_base.hpp" +#undef DEFINE_CLASS +#undef SYNCHRONOUS +#undef DEFINE_FIELD +#undef DEFINE_FIXED_FIELD +#undef DEFINE_VECTOR +#undef END_DEFINE_CLASS + +//---------------------- End -------------------------------------------------- + +#endif // PACKET_TYPES_HPP + +/* + //\ + //Log::debug("PacketTypes", "type: %s; value: %s", #Type, StringUtils::toString(Var).c_str()); + //\ + //ns->decode(Var); \ + //Log::debug("PacketTypes", "type: %s; value: %s", #Type, StringUtils::toString(Var).c_str()); \ + //if (Var != Value) \ + // Log::error("PacketTypes", "Expected fixed field %d, received %d!", Value, Var); + + +*/ \ No newline at end of file diff --git a/src/network/packet_types_base.hpp b/src/network/packet_types_base.hpp new file mode 100644 index 00000000000..b364ffb3f3d --- /dev/null +++ b/src/network/packet_types_base.hpp @@ -0,0 +1,74 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** + * IMPORTANT! + * This file has NO ifndef/define guards. + * This is done on purpose to provide an easy interface for making new + * types of packets, without the need to mention all fields more than once. + * Always #include "network/packet_types.hpp" and NOT this file. + * packet_types.hpp is the ONLY file allowed to include this file. + */ + +/** + * IMPORTANT! + * The structures in this file have DIRECT relation to STK network protocol. + * You should NOT modify them unless you know what you are doing, as that + * could cause the server to not talk the same language as clients! + */ + +/** + * For now, for each non-vector type you have in the packets, you have + * to define encode and decode for BareNetworkString. + * + * If you need to use a type tbhat includes a comma, such as std::map, + * you can use either a #define or using = to pass it anyway. + */ + +#include "irrString.h" +#include "utils/types.hpp" + +#include +#include +#include +#include + +using widestr = irr::core::stringw; + +// Note that bools are encoded using int8_t + +DEFINE_CLASS(PlayerListProfilePacket) + DEFINE_FIELD(uint32_t, host_id) + DEFINE_FIELD(uint32_t, online_id) + DEFINE_FIELD(uint8_t, local_player_id) + DEFINE_FIELD(widestr, profile_name) + DEFINE_FIELD(uint8_t, mask) + DEFINE_FIELD(uint8_t, handicap) + DEFINE_FIELD(uint8_t, kart_team) + DEFINE_FIELD(std::string, country_code) +END_DEFINE_CLASS(PlayerListProfilePacket) + +DEFINE_CLASS(PlayerListPacket) + SYNCHRONOUS(true) + DEFINE_FIXED_FIELD(uint8_t, type, LE_UPDATE_PLAYER_LIST) + DEFINE_FIELD(bool, game_started) + DEFINE_FIELD(uint8_t, all_profiles_size) + DEFINE_VECTOR(PlayerListProfilePacket, all_profiles_size, all_profiles) +END_DEFINE_CLASS(PlayerListPacket) + +// end \ No newline at end of file diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp index ddae89bb156..fb372a7746c 100644 --- a/src/network/protocols/client_lobby.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -45,6 +45,7 @@ #include "network/network_config.hpp" #include "network/network_player_profile.hpp" #include "network/network_timer_synchronizer.hpp" +#include "network/packet_types.hpp" #include "network/peer_vote.hpp" #include "network/protocols/connect_to_server.hpp" #include "network/protocols/game_protocol.hpp" @@ -513,7 +514,7 @@ void ClientLobby::update(int ticks) // Send a message to the server to start m_auto_started = true; NetworkString start(PROTOCOL_LOBBY_ROOM); - start.addUInt8(LobbyProtocol::LE_REQUEST_BEGIN); + start.addUInt8(LobbyEvent::LE_REQUEST_BEGIN); STKHost::get()->sendToServer(&start, PRM_RELIABLE); } if (m_background_download.joinable()) @@ -823,7 +824,11 @@ void ClientLobby::updatePlayerList(Event* event) { if (!checkDataSize(event, 1)) return; NetworkString& data = event->data(); - bool waiting = data.getUInt8() == 1; + + PlayerListPacket list_packet; + list_packet.fromNetworkString(&data); + + bool waiting = list_packet.game_started; if (m_waiting_for_game && !waiting) { // The waiting game finished @@ -831,21 +836,22 @@ void ClientLobby::updatePlayerList(Event* event) } m_waiting_for_game = waiting; - unsigned player_count = data.getUInt8(); + unsigned player_count = list_packet.all_profiles_size; core::stringw total_players; m_lobby_players.clear(); bool client_server_owner = false; for (unsigned i = 0; i < player_count; i++) { + PlayerListProfilePacket packet = list_packet.all_profiles[i]; LobbyPlayer lp = {}; - lp.m_host_id = data.getUInt32(); - lp.m_online_id = data.getUInt32(); - uint8_t local_id = data.getUInt8(); + lp.m_host_id = packet.host_id; + lp.m_online_id = packet.online_id; + uint8_t local_id = packet.local_player_id; lp.m_handicap = HANDICAP_NONE; lp.m_local_player_id = local_id; - data.decodeStringW(&lp.m_user_name); + lp.m_user_name = packet.profile_name; total_players += lp.m_user_name; - uint8_t boolean_combine = data.getUInt8(); + uint8_t boolean_combine = packet.mask; bool is_peer_waiting_for_game = (boolean_combine & 1) == 1; bool is_spectator = ((boolean_combine >> 1) & 1) == 1; bool is_peer_server_owner = ((boolean_combine >> 2) & 1) == 1; @@ -862,12 +868,12 @@ void ClientLobby::updatePlayerList(Event* event) lp.m_icon_id = 5; if (ready) lp.m_icon_id = 4; - lp.m_handicap = (HandicapLevel)data.getUInt8(); + lp.m_handicap = (HandicapLevel)packet.handicap; if (lp.m_handicap != HANDICAP_NONE) { lp.m_user_name = _("%s (handicapped)", lp.m_user_name); } - KartTeam team = (KartTeam)data.getUInt8(); + KartTeam team = (KartTeam)packet.kart_team; if (is_spectator) lp.m_kart_team = KART_TEAM_NONE; else @@ -880,7 +886,7 @@ void ClientLobby::updatePlayerList(Event* event) auto& local_players = NetworkConfig::get()->getNetworkPlayers(); std::get<2>(local_players.at(local_id)) = lp.m_handicap; } - data.decodeString(&lp.m_country_code); + lp.m_country_code = packet.country_code; m_lobby_players.push_back(lp); } STKHost::get()->setAuthorisedToControl(client_server_owner); @@ -1475,7 +1481,7 @@ void ClientLobby::sendChat(irr::core::stringw text, KartTeam team) if (text.size() > 0) { NetworkString* chat = getNetworkString(); - chat->addUInt8(LobbyProtocol::LE_CHAT); + chat->addUInt8(LobbyEvent::LE_CHAT); core::stringw name; PlayerProfile* player = PlayerManager::getCurrentPlayer(); diff --git a/src/network/protocols/lobby_protocol.hpp b/src/network/protocols/lobby_protocol.hpp index 6c338e401b4..2426a8e5c40 100644 --- a/src/network/protocols/lobby_protocol.hpp +++ b/src/network/protocols/lobby_protocol.hpp @@ -20,6 +20,7 @@ #define LOBBY_PROTOCOL_HPP #include "network/protocol.hpp" +#include "network/packet_types.hpp" #include "utils/stk_process.hpp" class GameSetup; @@ -46,62 +47,7 @@ class Track; class LobbyProtocol : public Protocol { public: - /** Lists all lobby events (LE). */ - enum : uint8_t - { - LE_CONNECTION_REQUESTED = 1, // a connection to the server - LE_CONNECTION_REFUSED, // Connection to server refused - LE_CONNECTION_ACCEPTED, // Connection to server accepted - LE_SERVER_INFO, // inform client about server info - LE_REQUEST_BEGIN, // begin of kart selection - LE_UPDATE_PLAYER_LIST, // inform client about player list update - LE_KART_SELECTION, // Player selected kart - LE_PLAYER_DISCONNECTED, // Client disconnected - LE_CLIENT_LOADED_WORLD, // Client finished loading world - LE_LOAD_WORLD, // Clients should load world - LE_START_RACE, // Server to client to start race - LE_START_SELECTION, // inform client to start selection - LE_RACE_FINISHED, // race has finished, display result - LE_RACE_FINISHED_ACK, // client went back to lobby - LE_BACK_LOBBY, // Force clients to go back to lobby - LE_VOTE, // Track vote - LE_CHAT, // Client chat message - LE_SERVER_OWNERSHIP, // Tell client he is now the server owner - LE_KICK_HOST, // Server owner kicks some other peer in game - LE_CHANGE_TEAM, // Client wants to change his team - LE_BAD_TEAM, // Tell server owner that the team is unbalanced - LE_BAD_CONNECTION, // High ping or too many packets loss - LE_CONFIG_SERVER, // Server owner config server game mode or difficulty - LE_CHANGE_HANDICAP, // Client changes handicap - LE_LIVE_JOIN, // Client live join or spectate - LE_LIVE_JOIN_ACK, // Server tell client live join or spectate succeed - LE_KART_INFO, // Client or server exchange new kart info - LE_CLIENT_BACK_LOBBY, // Client tell server to go back lobby - LE_REPORT_PLAYER, // Client report some player in server - // (like abusive behaviour) - LE_ASSETS_UPDATE, // Client tell server with updated assets - LE_COMMAND, // Command - }; - - enum RejectReason : uint8_t - { - RR_BUSY = 0, - RR_BANNED = 1, - RR_INCORRECT_PASSWORD = 2, - RR_INCOMPATIBLE_DATA = 3, - RR_TOO_MANY_PLAYERS = 4, - RR_INVALID_PLAYER = 5 - }; - - enum BackLobbyReason : uint8_t - { - BLR_NONE = 0, - BLR_NO_GAME_FOR_LIVE_JOIN = 1, - BLR_NO_PLACE_FOR_LIVE_JOIN = 2, - BLR_ONE_PLAYER_IN_RANKED_MATCH = 3, - BLR_SERVER_ONWER_QUITED_THE_GAME = 4, - BLR_SPECTATING_NEXT_GAME = 5 - }; + // Enums were moved to packet_types.hpp protected: const ProcessType m_process_type; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index bb331d21c4f..ff1958f3013 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -32,6 +32,7 @@ #include "network/game_setup.hpp" #include "network/network_config.hpp" #include "network/network_player_profile.hpp" +#include "network/packet_types.hpp" #include "network/protocol_manager.hpp" #include "network/protocols/connect_to_peer.hpp" #include "network/protocols/command_manager.hpp" @@ -2859,13 +2860,13 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) m_state.load() > WAITING_FOR_START_GAME && !update_when_reset_server) return; - NetworkString* pl = getNetworkString(); - pl->setSynchronous(true); - pl->addUInt8(LE_UPDATE_PLAYER_LIST) - .addUInt8((uint8_t)(game_started ? 1 : 0)) - .addUInt8((uint8_t)all_profiles.size()); + PlayerListPacket list_packet; + list_packet.game_started = game_started; + list_packet.all_profiles_size = all_profiles.size(); + for (auto profile : all_profiles) { + PlayerListProfilePacket packet; auto profile_name = profile->getName(); // get OS information @@ -2903,9 +2904,10 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) profile_name = StringUtils::utf8ToWide(prefix) + profile_name; - pl->addUInt32(profile->getHostId()).addUInt32(profile->getOnlineId()) - .addUInt8(profile->getLocalPlayerId()) - .encodeString(profile_name); + packet.host_id = profile->getHostId(); + packet.online_id = profile->getOnlineId(); + packet.local_player_id = profile->getLocalPlayerId(); + packet.profile_name = profile_name; std::shared_ptr p = profile->getPeer(); uint8_t boolean_combine = 0; @@ -2923,15 +2925,19 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) boolean_combine |= (1 << 3); if ((p && p->isAIPeer()) || isAIProfile(profile)) boolean_combine |= (1 << 4); - pl->addUInt8(boolean_combine); - pl->addUInt8(profile->getHandicap()); + packet.mask = boolean_combine; + packet.handicap = profile->getHandicap(); if (getSettings()->hasTeamChoosing()) - pl->addUInt8(profile->getTeam()); + packet.kart_team = profile->getTeam(); else - pl->addUInt8(KART_TEAM_NONE); - pl->encodeString(profile->getCountryCode()); + packet.kart_team = KART_TEAM_NONE; + packet.country_code = profile->getCountryCode(); + list_packet.all_profiles.push_back(packet); } + NetworkString* pl = getNetworkString(); + list_packet.toNetworkString(pl); + // Don't send this message to in-game players STKHost::get()->sendPacketToAllPeersWith([game_started] (std::shared_ptr p) diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index 60ee0b5b058..c21adaaba27 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -924,7 +924,7 @@ void STKHost::mainLoop(ProcessType pt) p.second->setWarnedForHighPing(true); NetworkString msg(PROTOCOL_LOBBY_ROOM); msg.setSynchronous(true); - msg.addUInt8(LobbyProtocol::LE_BAD_CONNECTION); + msg.addUInt8(LobbyEvent::LE_BAD_CONNECTION); p.second->sendPacket(&msg, PRM_RELIABLE); } } diff --git a/src/states_screens/dialogs/network_player_dialog.cpp b/src/states_screens/dialogs/network_player_dialog.cpp index 7bbbdcb4836..94957abc995 100644 --- a/src/states_screens/dialogs/network_player_dialog.cpp +++ b/src/states_screens/dialogs/network_player_dialog.cpp @@ -203,7 +203,7 @@ void NetworkPlayerDialog::onUpdate(float dt) if (info.empty()) return false; NetworkString report(PROTOCOL_LOBBY_ROOM); - report.addUInt8(LobbyProtocol::LE_REPORT_PLAYER) + report.addUInt8(LobbyEvent::LE_REPORT_PLAYER) .addUInt32(host_id).encodeString16(info); STKHost::get()->sendToServer(&report, PRM_RELIABLE); return true; @@ -247,7 +247,7 @@ GUIEngine::EventPropagation else if (selection == m_kick_widget->m_properties[PROP_ID]) { NetworkString kick(PROTOCOL_LOBBY_ROOM); - kick.addUInt8(LobbyProtocol::LE_KICK_HOST).addUInt32(m_host_id); + kick.addUInt8(LobbyEvent::LE_KICK_HOST).addUInt32(m_host_id); STKHost::get()->sendToServer(&kick, PRM_RELIABLE); m_self_destroy = true; return GUIEngine::EVENT_BLOCK; @@ -256,7 +256,7 @@ GUIEngine::EventPropagation selection == m_change_team_widget->m_properties[PROP_ID]) { NetworkString change_team(PROTOCOL_LOBBY_ROOM); - change_team.addUInt8(LobbyProtocol::LE_CHANGE_TEAM) + change_team.addUInt8(LobbyEvent::LE_CHANGE_TEAM) .addUInt8(m_local_id); STKHost::get()->sendToServer(&change_team, PRM_RELIABLE); m_self_destroy = true; @@ -271,7 +271,7 @@ GUIEngine::EventPropagation new_handicap = HANDICAP_MEDIUM; } NetworkString change_handicap(PROTOCOL_LOBBY_ROOM); - change_handicap.addUInt8(LobbyProtocol::LE_CHANGE_HANDICAP) + change_handicap.addUInt8(LobbyEvent::LE_CHANGE_HANDICAP) .addUInt8(m_local_id).addUInt8(new_handicap); STKHost::get()->sendToServer(&change_handicap, PRM_RELIABLE); m_self_destroy = true; diff --git a/src/states_screens/dialogs/race_paused_dialog.cpp b/src/states_screens/dialogs/race_paused_dialog.cpp index 1171077c15f..b454052260f 100644 --- a/src/states_screens/dialogs/race_paused_dialog.cpp +++ b/src/states_screens/dialogs/race_paused_dialog.cpp @@ -387,7 +387,7 @@ GUIEngine::EventPropagation // back lobby NetworkString back(PROTOCOL_LOBBY_ROOM); back.setSynchronous(true); - back.addUInt8(LobbyProtocol::LE_CLIENT_BACK_LOBBY); + back.addUInt8(LobbyEvent::LE_CLIENT_BACK_LOBBY); STKHost::get()->sendToServer(&back, PRM_RELIABLE); } else diff --git a/src/states_screens/dialogs/server_configuration_dialog.cpp b/src/states_screens/dialogs/server_configuration_dialog.cpp index c2c28187363..6cc37bcf605 100644 --- a/src/states_screens/dialogs/server_configuration_dialog.cpp +++ b/src/states_screens/dialogs/server_configuration_dialog.cpp @@ -87,7 +87,7 @@ GUIEngine::EventPropagation { m_self_destroy = true; NetworkString change(PROTOCOL_LOBBY_ROOM); - change.addUInt8(LobbyProtocol::LE_CONFIG_SERVER); + change.addUInt8(LobbyEvent::LE_CONFIG_SERVER); change.addUInt8((uint8_t)m_difficulty_widget ->getSelection(PLAYER_ID_GAME_MASTER)); switch (m_game_mode_widget->getSelection(PLAYER_ID_GAME_MASTER)) diff --git a/src/states_screens/online/network_kart_selection.cpp b/src/states_screens/online/network_kart_selection.cpp index 8f8cc6bb0d8..d99cb0a2836 100644 --- a/src/states_screens/online/network_kart_selection.cpp +++ b/src/states_screens/online/network_kart_selection.cpp @@ -126,12 +126,12 @@ void NetworkKartSelectionScreen::allPlayersDone() if (m_live_join) { kart.setSynchronous(true); - kart.addUInt8(LobbyProtocol::LE_LIVE_JOIN) + kart.addUInt8(LobbyEvent::LE_LIVE_JOIN) // not spectator .addUInt8(0); } else - kart.addUInt8(LobbyProtocol::LE_KART_SELECTION); + kart.addUInt8(LobbyEvent::LE_KART_SELECTION); kart.addUInt8(kart_count); for (unsigned n = 0; n < kart_count; n++) { @@ -187,7 +187,7 @@ bool NetworkKartSelectionScreen::onEscapePressed() // server doesn't react in time we exit the server m_exit_timeout = StkTime::getMonoTimeMs() + 5000; NetworkString back(PROTOCOL_LOBBY_ROOM); - back.addUInt8(LobbyProtocol::LE_CLIENT_BACK_LOBBY); + back.addUInt8(LobbyEvent::LE_CLIENT_BACK_LOBBY); STKHost::get()->sendToServer(&back, PRM_RELIABLE); } return false; diff --git a/src/states_screens/online/networking_lobby.cpp b/src/states_screens/online/networking_lobby.cpp index a2bc4284cf1..16e0f823f8d 100644 --- a/src/states_screens/online/networking_lobby.cpp +++ b/src/states_screens/online/networking_lobby.cpp @@ -862,7 +862,7 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name, { // Send a message to the server to start NetworkString start(PROTOCOL_LOBBY_ROOM); - start.addUInt8(LobbyProtocol::LE_REQUEST_BEGIN); + start.addUInt8(LobbyEvent::LE_REQUEST_BEGIN); STKHost::get()->sendToServer(&start, PRM_RELIABLE); } } @@ -880,7 +880,7 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name, { NetworkString start(PROTOCOL_LOBBY_ROOM); start.setSynchronous(true); - start.addUInt8(LobbyProtocol::LE_LIVE_JOIN) + start.addUInt8(LobbyEvent::LE_LIVE_JOIN) // is spectating .addUInt8(1); STKHost::get()->sendToServer(&start, PRM_RELIABLE); diff --git a/src/states_screens/online/tracks_screen.cpp b/src/states_screens/online/tracks_screen.cpp index 61c5fb1eb84..50fe33386bf 100644 --- a/src/states_screens/online/tracks_screen.cpp +++ b/src/states_screens/online/tracks_screen.cpp @@ -732,7 +732,7 @@ void TracksScreen::voteForPlayer() UserConfigParams::m_random_arena_item = m_reversed->getState(); NetworkString vote(PROTOCOL_LOBBY_ROOM); - vote.addUInt8(LobbyProtocol::LE_VOTE); + vote.addUInt8(LobbyEvent::LE_VOTE); core::stringw player_name; if (PlayerManager::getCurrentPlayer()) player_name = PlayerManager::getCurrentPlayer()->getName(); diff --git a/src/utils/chat_manager.cpp b/src/utils/chat_manager.cpp index 644f7b9728d..c6e5f20f78a 100644 --- a/src/utils/chat_manager.cpp +++ b/src/utils/chat_manager.cpp @@ -219,7 +219,7 @@ void ChatManager::handleNormalChatMessage(std::shared_ptr peer, NetworkString* chat = getLobby()->getNetworkString(); chat->setSynchronous(true); - chat->addUInt8(getLobby()->LE_CHAT).encodeString16(StringUtils::utf8ToWide(message)); + chat->addUInt8(LobbyEvent::LE_CHAT).encodeString16(StringUtils::utf8ToWide(message)); STKHost::get()->sendPacketToAllPeersWith( std::bind(&ChatManager::shouldMessageBeSent, diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index a6568ad3cc1..8dca7dac009 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -348,6 +348,31 @@ namespace StringUtils Precision(double value, int precision): m_value(value), m_precision(precision) {} }; std::ostream& operator << (std::ostream& os, const Precision& item); + // ------------------------------------------------------------------------ + + // I'm lazy to move it to .cpp + template <> + inline std::string toString(const irr::core::stringw& any) + { + return wideToUtf8(any); + } // toString template + // ------------------------------------------------------------------------ + + // I'm lazy to move it to .cpp + template <> + inline std::string toString(const uint8_t& any) + { + return toString((int)any); + } // toString template + // ------------------------------------------------------------------------ + + // I'm lazy to move it to .cpp + template <> + inline std::string toString(const uint32_t& any) + { + return toString((int)any); + } // toString template + // ------------------------------------------------------------------------ } // namespace StringUtils From 7675e3774f694e91a07bb9c6f2b4e96a2274cc6f Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 15 Mar 2025 14:41:24 +0400 Subject: [PATCH 601/830] Try to fix compilation --- src/network/network_string.cpp | 21 --------------------- src/network/packet_types.hpp | 14 -------------- src/network/packet_types_base.hpp | 4 +--- 3 files changed, 1 insertion(+), 38 deletions(-) diff --git a/src/network/network_string.cpp b/src/network/network_string.cpp index ea2d4c69901..8d2a396b994 100644 --- a/src/network/network_string.cpp +++ b/src/network/network_string.cpp @@ -238,7 +238,6 @@ std::string BareNetworkString::getLogMessage(const std::string &indent) const if(line+16 void BareNetworkString::encode(const uint32_t& value) { - Log::debug("BareNetworkString", "before encode %s", getLogMessage(" ").c_str()); addUInt32(value); - Log::debug("BareNetworkString", " after encode %s", getLogMessage(" ").c_str()); } // encode(uint32_t) //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template<> void BareNetworkString::decode(uint32_t& value) { - Log::debug("BareNetworkString", "before decode %s", getLogMessage(" ").c_str()); value = getUInt32(); - Log::debug("BareNetworkString", " after decode %s", getLogMessage(" ").c_str()); } // decode(uint32_t) //----------------------------------------------------------------------------- template<> void BareNetworkString::encode(const uint8_t& value) { - Log::debug("BareNetworkString", "before encode %s", getLogMessage(" ").c_str()); addUInt8(value); - Log::debug("BareNetworkString", " after encode %s", getLogMessage(" ").c_str()); } // encode(uint8_t) //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template<> void BareNetworkString::decode(uint8_t& value) { - Log::debug("BareNetworkString", "before decode %s", getLogMessage(" ").c_str()); value = getUInt8(); - Log::debug("BareNetworkString", " after decode %s", getLogMessage(" ").c_str()); } // decode(uint8_t) //----------------------------------------------------------------------------- template<> void BareNetworkString::encode(const irr::core::stringw& value) { - Log::debug("BareNetworkString", "before encode %s", getLogMessage(" ").c_str()); encodeString(value); - Log::debug("BareNetworkString", " after encode %s", getLogMessage(" ").c_str()); } // encode(irr::core::stringw) //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template<> void BareNetworkString::decode(irr::core::stringw& value) { - Log::debug("BareNetworkString", "before decode %s", getLogMessage(" ").c_str()); decodeStringW(&value); - Log::debug("BareNetworkString", " after decode %s", getLogMessage(" ").c_str()); } // decode(irr::core::stringw) //----------------------------------------------------------------------------- template<> void BareNetworkString::encode(const std::string& value) { - Log::debug("BareNetworkString", "before encode %s", getLogMessage(" ").c_str()); encodeString(value); - Log::debug("BareNetworkString", " after encode %s", getLogMessage(" ").c_str()); } // encode(std::string) //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template<> void BareNetworkString::decode(std::string& value) { - Log::debug("BareNetworkString", "before decode %s", getLogMessage(" ").c_str()); decodeString(&value); - Log::debug("BareNetworkString", " after decode %s", getLogMessage(" ").c_str()); } // decode(std::string) //----------------------------------------------------------------------------- template<> void BareNetworkString::encode(const bool& value) { - Log::debug("BareNetworkString", "before encode %s", getLogMessage(" ").c_str()); addUInt8(value ? 1 : 0); - Log::debug("BareNetworkString", " after encode %s", getLogMessage(" ").c_str()); } // encode(bool) //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template<> void BareNetworkString::decode(bool& value) { - Log::debug("BareNetworkString", "before decode %s", getLogMessage(" ").c_str()); value = getUInt8() == 1; - Log::debug("BareNetworkString", " after decode %s", getLogMessage(" ").c_str()); } // decode(bool) //----------------------------------------------------------------------------- // template<> diff --git a/src/network/packet_types.hpp b/src/network/packet_types.hpp index 2eb81fe1771..37be504b495 100644 --- a/src/network/packet_types.hpp +++ b/src/network/packet_types.hpp @@ -20,8 +20,6 @@ #define PACKET_TYPES_HPP #include "network/network_string.hpp" -#include "utils/string_utils.hpp" -#include /** * IMPORTANT! @@ -177,15 +175,3 @@ inline void Name::fromNetworkString(NetworkString* ns) \ //---------------------- End -------------------------------------------------- #endif // PACKET_TYPES_HPP - -/* - //\ - //Log::debug("PacketTypes", "type: %s; value: %s", #Type, StringUtils::toString(Var).c_str()); - //\ - //ns->decode(Var); \ - //Log::debug("PacketTypes", "type: %s; value: %s", #Type, StringUtils::toString(Var).c_str()); \ - //if (Var != Value) \ - // Log::error("PacketTypes", "Expected fixed field %d, received %d!", Value, Var); - - -*/ \ No newline at end of file diff --git a/src/network/packet_types_base.hpp b/src/network/packet_types_base.hpp index b364ffb3f3d..558399d9e9b 100644 --- a/src/network/packet_types_base.hpp +++ b/src/network/packet_types_base.hpp @@ -43,10 +43,8 @@ #include "irrString.h" #include "utils/types.hpp" -#include -#include -#include #include +#include using widestr = irr::core::stringw; From c3bf411adfb568df9e8123c13de09b2dd0e5ca75 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 16 Mar 2025 18:48:48 +0400 Subject: [PATCH 602/830] Remove debug stringutils stuff that led to negative ip --- src/utils/string_utils.hpp | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index 8dca7dac009..86864b448ac 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -350,30 +350,6 @@ namespace StringUtils std::ostream& operator << (std::ostream& os, const Precision& item); // ------------------------------------------------------------------------ - // I'm lazy to move it to .cpp - template <> - inline std::string toString(const irr::core::stringw& any) - { - return wideToUtf8(any); - } // toString template - // ------------------------------------------------------------------------ - - // I'm lazy to move it to .cpp - template <> - inline std::string toString(const uint8_t& any) - { - return toString((int)any); - } // toString template - // ------------------------------------------------------------------------ - - // I'm lazy to move it to .cpp - template <> - inline std::string toString(const uint32_t& any) - { - return toString((int)any); - } // toString template - // ------------------------------------------------------------------------ - } // namespace StringUtils #endif From 0b34cc95bf168b3a159ad4823e4c4b777d9b21bd Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 17 Mar 2025 21:53:34 +0400 Subject: [PATCH 603/830] Fix crash that didn't happen in Debug --- src/items/bowling.cpp | 4 +++- src/items/cake.cpp | 4 +++- src/items/swatter.cpp | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/items/bowling.cpp b/src/items/bowling.cpp index 34c3fc4303e..3bf2b257e41 100644 --- a/src/items/bowling.cpp +++ b/src/items/bowling.cpp @@ -157,7 +157,9 @@ bool Bowling::updateAndDelete(int ticks) */ bool Bowling::hit(AbstractKart* kart, PhysicalObject* obj) { - auto hp = kart->getHitProcessor(); + std::shared_ptr hp; + if (kart) + hp = kart->getHitProcessor(); if (hp) hp->setTeammateHitOwner(getOwnerId(),m_ticks_since_thrown); diff --git a/src/items/cake.cpp b/src/items/cake.cpp index 199b73d2b74..ffe24e4994c 100644 --- a/src/items/cake.cpp +++ b/src/items/cake.cpp @@ -62,7 +62,9 @@ void Cake::init(const XMLNode &node, scene::IMesh *cake_model) */ bool Cake::hit(AbstractKart* kart, PhysicalObject* obj) { - auto hp = kart->getHitProcessor(); + std::shared_ptr hp; + if (kart) + hp = kart->getHitProcessor(); if (hp) hp->setTeammateHitOwner(getOwnerId()); diff --git a/src/items/swatter.cpp b/src/items/swatter.cpp index b6674b1377b..ac03f8815b4 100644 --- a/src/items/swatter.cpp +++ b/src/items/swatter.cpp @@ -410,7 +410,10 @@ void Swatter::squashThingsAround() if (wasHit) { // check if we are in team gp and hit a teammate and should punish attacker - auto hp = m_kart->getHitProcessor(); + + std::shared_ptr hp; + if (m_kart) + hp = m_kart->getHitProcessor(); if (hp && !m_closest_kart->hasFinishedRace()) hp->handleSwatterHit(m_kart->getWorldKartId(), m_closest_kart->getWorldKartId(), success, m_has_hit_kart, From 7275aa71463ba13598702c39edb81b13792bb71e Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Fri, 21 Mar 2025 00:57:09 +0800 Subject: [PATCH 604/830] Straightforwardly fix #5157 --- data/gui/dialogs/online/player_rankings_dialog.stkgui | 2 +- data/gui/screens/online/profile_settings.stkgui | 5 +++-- src/guiengine/skin.cpp | 11 ++++++++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/data/gui/dialogs/online/player_rankings_dialog.stkgui b/data/gui/dialogs/online/player_rankings_dialog.stkgui index 14d931ae3bc..8a04938aa33 100644 --- a/data/gui/dialogs/online/player_rankings_dialog.stkgui +++ b/data/gui/dialogs/online/player_rankings_dialog.stkgui @@ -5,7 +5,7 @@ word_wrap="true" I18N="In player rankings dialog" text="Top 10 players"/> - + diff --git a/data/gui/screens/online/profile_settings.stkgui b/data/gui/screens/online/profile_settings.stkgui index 1ade93cbfc8..a98ce34f7bf 100644 --- a/data/gui/screens/online/profile_settings.stkgui +++ b/data/gui/screens/online/profile_settings.stkgui @@ -17,16 +17,17 @@
+
diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index e4e1569d6eb..40464026c22 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -1840,7 +1840,16 @@ void Skin::drawSpinnerChild(const core::recti &rect, Widget* widget, return; SpinnerWidget* spinner = dynamic_cast(widget->m_event_handler); - bool spinner_focused = spinner->isFocusedForPlayer(PLAYER_ID_GAME_MASTER); + + bool spinner_focused = false; + for (unsigned i = 1; i < MAX_PLAYER_COUNT + 1; i++) + { + if (spinner->isFocusedForPlayer(i - 1)) + { + spinner_focused = true; + break; + } + } if (pressed || (spinner->isButtonSelected(right) && spinner_focused)) { From 5275ebdca171e0c08ed59cf43ca1bf044286b513 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 18 Mar 2025 01:15:52 +0400 Subject: [PATCH 605/830] Cooldown for starting the game MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merci à mes amis français qui démarrent le jeu immédiatement même si on leur demande de ne pas le faire --- NETWORKING.md | 3 ++ data/commands.xml | 15 ++++++++ src/network/protocols/command_manager.cpp | 45 +++++++++++++++++++++++ src/network/protocols/command_manager.hpp | 2 + src/network/protocols/server_lobby.cpp | 15 +++++++- src/network/server_config.hpp | 5 +++ src/utils/lobby_settings.cpp | 12 ++++++ src/utils/lobby_settings.hpp | 7 ++++ 8 files changed, 102 insertions(+), 2 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index 4825e382182..168bff117d8 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -397,6 +397,9 @@ A typical current server configuration xml that fits the current code version is + + + ``` diff --git a/data/commands.xml b/data/commands.xml index d355f6a5f50..420bb97bf14 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -1139,6 +1139,21 @@ here later. For now, please refer to the code for the strings being used. --> permissions="UP_HAMMER" />
+ + + sendStringToPeer(peer, StringUtils::insertValues( + "Cooldown for starting the game: %d", + getSettings()->getLobbyCooldown())); +} // process_cooldown +// ======================================================================== + +void CommandManager::process_cooldown_assign(Context& context) +{ + auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } + if (argv.size() < 2) + { + error(context); + return; + } + int new_cooldown = -1; + // kimden: figure out what's with epsilons in STK + if (!StringUtils::parseString(argv[1], &new_cooldown) || new_cooldown < 0) + { + error(context); + return; + } + getSettings()->setLobbyCooldown(new_cooldown); + + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "Set cooldown for starting the game to %d", + new_cooldown)); +} // process_cooldown_assign +// ======================================================================== + void CommandManager::special(Context& context) { auto peer = context.m_peer.lock(); diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index f8bbd4d3015..9a1c50019ec 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -345,6 +345,8 @@ class CommandManager: public LobbyContextComponent void process_why_hourglass(Context& context); void process_available_teams(Context& context); void process_available_teams_assign(Context& context); + void process_cooldown(Context& context); + void process_cooldown_assign(Context& context); void special(Context& context); public: diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index ff1958f3013..45dc60f0647 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -739,9 +739,10 @@ void ServerLobby::asynchronousUpdate() forbid_starting = true; bool timer_finished = (!forbid_starting && m_timeout.load() < (int64_t)StkTime::getMonoTimeMs()); - bool players_ready = (checkPeersReady(true/*ignore_ai_peer*/, BEFORE_SELECTION) && (int)players >= starting_limit); + bool players_ready = (checkPeersReady(true/*ignore_ai_peer*/, BEFORE_SELECTION) + && (int)players >= starting_limit); - if (timer_finished || players_ready) + if (timer_finished || (players_ready && !getSettings()->isCooldown())) { resetPeersReady(); startSelection(); @@ -1728,6 +1729,8 @@ void ServerLobby::unregisterServer(bool now, std::weak_ptr sl) void ServerLobby::startSelection(const Event *event) { bool need_to_update = false; + bool cooldown = getSettings()->isCooldown(); + if (event != NULL) { if (m_state.load() != WAITING_FOR_START_GAME) @@ -1779,7 +1782,15 @@ void ServerLobby::startSelection(const Event *event) return; } } + if (cooldown) + { + sendStringToPeer(peer, "Starting the game is forbidden by server cooldown"); + return; + } } else { + // Even if cooldown is bigger than server timeout, start happens upon + // timeout expiration. If all players clicked before timeout, no start + // happens - it's handled in another place if (!getSettings()->isAllowedToStart()) { // Produce no log spam diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index fe4f8d3b4f3..40535eeb471 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -795,6 +795,11 @@ namespace ServerConfig SERVER_CFG_DEFAULT(BoolServerConfigParam(true, "start-allowed", "Whether the game can be started immediately when the server is opened.")); + SERVER_CFG_PREFIX IntServerConfigParam m_lobby_cooldown + SERVER_CFG_DEFAULT(IntServerConfigParam(0, "lobby-cooldown", + "Timeout in seconds during which you cannot start the next game, " + "regardless of hammers, votes, or buttons pressed.")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index 4c8eab672f7..700eafb6687 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -56,6 +56,8 @@ void LobbySettings::setupContextUser() m_shuffle_gp = ServerConfig::m_shuffle_gp; m_consent_on_replays = false; + m_last_reset = 0; + m_fixed_direction = ServerConfig::m_fixed_direction; setDefaultLapRestrictions(); @@ -130,6 +132,7 @@ void LobbySettings::setupContextUser() m_register_table_name = ServerConfig::m_register_table_name; m_official_karts_threshold = ServerConfig::m_official_karts_threshold; m_official_tracks_threshold = ServerConfig::m_official_tracks_threshold; + m_lobby_cooldown = ServerConfig::m_lobby_cooldown; } // setupContextUser //----------------------------------------------------------------------------- @@ -684,6 +687,8 @@ void LobbySettings::onServerSetup() m_battle_time_limit = 0.0f; m_winner_peer_id = 0; + m_last_reset = StkTime::getMonoTimeMs(); + NetworkConfig::get()->setTuxHitboxAddon(m_live_players); } // onServerSetup //----------------------------------------------------------------------------- @@ -728,4 +733,11 @@ void LobbySettings::tryKickingAnotherPeer(std::shared_ptr initiator, } } } // tryKickingAnotherPeer +//----------------------------------------------------------------------------- + +bool LobbySettings::isCooldown() const +{ + int64_t passed_since_reset = (int64_t)StkTime::getMonoTimeMs() - m_last_reset; + return passed_since_reset < 1000 * m_lobby_cooldown; +} // isCooldown //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index b4b75bb3c0e..05ddbdf00ea 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -105,6 +105,9 @@ class LobbySettings: public LobbyContextComponent void setBattleHitCaptureLimit(int value) { m_battle_hit_capture_limit = value; } void setBattleTimeLimit(float value) { m_battle_time_limit = value; } + void setLobbyCooldown(int value) { m_lobby_cooldown = value; } + + bool isCooldown() const; void onServerSetup(); @@ -171,6 +174,7 @@ class LobbySettings: public LobbyContextComponent std::string getRegisterTableName() const { return m_register_table_name; } float getOfficialKartsThreshold() const { return m_official_karts_threshold; } float getOfficialTracksThreshold() const { return m_official_tracks_threshold; } + int getLobbyCooldown() const { return m_lobby_cooldown; } private: GameSetup* m_game_setup; @@ -191,6 +195,8 @@ class LobbySettings: public LobbyContextComponent std::string m_help_message; + uint64_t m_last_reset; + std::set m_available_difficulties; std::set m_available_modes; @@ -279,6 +285,7 @@ class LobbySettings: public LobbyContextComponent std::string m_register_table_name; float m_official_karts_threshold; float m_official_tracks_threshold; + int m_lobby_cooldown; // These should be moved to voting manager ==================================== From 9141f3a7a2efa7d838638da0060cf181d9278576 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 18 Mar 2025 23:05:32 +0400 Subject: [PATCH 606/830] GP standings fix + refactor for legacy gp mode and a test command --- data/commands.xml | 7 ++++++ src/network/protocols/command_manager.cpp | 26 ++++++++++++++++++++++- src/network/protocols/command_manager.hpp | 4 ++++ src/network/protocols/server_lobby.cpp | 15 +++++++------ src/network/protocols/server_lobby.hpp | 4 ++++ src/utils/lobby_gp_manager.cpp | 21 ++++++++++++++---- src/utils/lobby_settings.cpp | 3 +++ src/utils/lobby_settings.hpp | 18 ++++++++++++++-- 8 files changed, 84 insertions(+), 14 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index 420bb97bf14..48f14f47944 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -1154,6 +1154,13 @@ here later. For now, please refer to the code for the strings being used. --> permissions="UP_HAMMER" /> + isGrandPrix() || */!getSettings()->isLivePlayers()) + if (getSettings()->isLegacyGPMode() || !getSettings()->isLivePlayers()) response = "Server doesn't support spectating"; if (!response.empty()) @@ -3982,6 +3983,29 @@ void CommandManager::process_cooldown_assign(Context& context) } // process_cooldown_assign // ======================================================================== +void CommandManager::process_temp250318(Context& context) +{ + auto& argv = context.m_argv; + auto peer = context.m_peer.lock(); + if (!peer) + { + error(context, true); + return; + } + int value = 0; + if (argv.size() < 2 || !StringUtils::parseString(argv[1], &value)) + { + error(context); + return; + } + auto settings = getSettings(); + settings->m_legacy_gp_mode = ((value >> 1) & 1); + settings->m_legacy_gp_mode_started = ((value >> 0) & 1); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "ok value = %d", value)); +} // process_temp250318 +// ======================================================================== + void CommandManager::special(Context& context) { auto peer = context.m_peer.lock(); diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 9a1c50019ec..8eaf680ecea 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -347,6 +347,10 @@ class CommandManager: public LobbyContextComponent void process_available_teams_assign(Context& context); void process_cooldown(Context& context); void process_cooldown_assign(Context& context); + + // Temporary command + void process_temp250318(Context& context); + void special(Context& context); public: diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 45dc60f0647..6b78d7977d6 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -613,8 +613,8 @@ void ServerLobby::asynchronousUpdate() if (getSettings()->isRanked() && m_state.load() == WAITING_FOR_START_GAME) m_ranking->cleanup(); - if (allowJoinedPlayersWaiting() /*|| (m_game_setup->isGrandPrix() && - m_state.load() == WAITING_FOR_START_GAME)*/) + if (allowJoinedPlayersWaiting() || (getSettings()->isLegacyGPMode() && + m_state.load() == WAITING_FOR_START_GAME)) { // Only poll the STK server if server has been registered. if (m_server_id_online.load() != 0 && @@ -1827,8 +1827,9 @@ void ServerLobby::startSelection(const Event *event) auto& spectators_by_limit = getSpectatorsByLimit(); if (spectators_by_limit.size() == peers.size()) { - Log::error("ServerLobby", "Too many players and cannot set " - "spectate for late coming players!"); + // produce no log spam for now + // Log::error("ServerLobby", "Too many players and cannot set " + // "spectate for late coming players!"); return; } for (auto &peer : spectators_by_limit) @@ -3206,8 +3207,8 @@ void ServerLobby::playerFinishedResult(Event *event) //----------------------------------------------------------------------------- bool ServerLobby::waitingForPlayers() const { - // if (m_game_setup->isGrandPrix() && m_game_setup->isGrandPrixStarted()) - // return false; + if (getSettings()->isLegacyGPMode() && getSettings()->isLegacyGPModeStarted()) + return false; return m_state.load() >= WAITING_FOR_START_GAME; } // waitingForPlayers @@ -3408,7 +3409,7 @@ void ServerLobby::configPeersStartTime() //----------------------------------------------------------------------------- bool ServerLobby::allowJoinedPlayersWaiting() const { - return true; //!m_game_setup->isGrandPrix(); + return !getSettings()->isLegacyGPMode(); } // allowJoinedPlayersWaiting //----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index dcaa3bcac31..69fe349ab35 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -370,6 +370,10 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser void saveDisconnectingIdInfo(int id) const; void sendServerInfoToEveryone() const; + bool isWorldPicked() const { return m_state.load() >= LOAD_WORLD; } + bool isWorldFinished() const { return m_state.load() >= RESULT_DISPLAY; } + + //------------------------------------------------------------------------- // The functions below reset/set ASM_NO_TEAM if needed by team changing procedure. void checkNoTeamSpectator(std::shared_ptr peer); void setSpectateModeProperly(std::shared_ptr peer, AlwaysSpectateMode mode); diff --git a/src/utils/lobby_gp_manager.cpp b/src/utils/lobby_gp_manager.cpp index c0cb1a59184..bf118d4afe6 100644 --- a/src/utils/lobby_gp_manager.cpp +++ b/src/utils/lobby_gp_manager.cpp @@ -75,13 +75,26 @@ std::string LobbyGPManager::getGrandPrixStandings(bool showIndividual, bool show } auto game_setup = getLobby()->getGameSetup(); - uint8_t passed = (uint8_t)game_setup->getAllTracks().size(); + int passed = (int)game_setup->getAllTracks().size(); + bool ongoing = false; + if (getLobby()->isWorldPicked() && !getLobby()->isWorldFinished()) + { + --passed; + ongoing = true; + } + uint8_t total = game_setup->getExtraServerInfo(); - if (passed != 0) - response << " after " << (int)passed << " of " << (int)total << " games:\n"; + if (passed != 0 || ongoing) + { + response << " after " << (int)passed << " of " << (int)total << " games"; + if (ongoing) + response << " (before this game)"; + } else - response << ", " << (int)total << " games:\n"; + response << ", " << (int)total << " games"; + response << ":\n"; + if (showIndividual) { std::vector> results; diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index 700eafb6687..9a61b78e06e 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -55,6 +55,9 @@ void LobbySettings::setupContextUser() ); m_shuffle_gp = ServerConfig::m_shuffle_gp; m_consent_on_replays = false; + + m_legacy_gp_mode = false; + m_legacy_gp_mode_started = false; m_last_reset = 0; diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 05ddbdf00ea..92ea1c0a53b 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -176,11 +176,15 @@ class LobbySettings: public LobbyContextComponent float getOfficialTracksThreshold() const { return m_official_tracks_threshold; } int getLobbyCooldown() const { return m_lobby_cooldown; } + // This one might not get into the config (as it originated from official + // code's GP, where it is useless unless you want to make a private + // server), however, it might be useful regardless + bool isLegacyGPMode() const { return m_legacy_gp_mode; } + bool isLegacyGPModeStarted() const { return m_legacy_gp_mode_started; } + private: GameSetup* m_game_setup; -// These are fine here ======================================================== - int m_battle_hit_capture_limit; float m_battle_time_limit; @@ -287,6 +291,16 @@ class LobbySettings: public LobbyContextComponent float m_official_tracks_threshold; int m_lobby_cooldown; + // Special, temporarily public +public: + + bool m_legacy_gp_mode; + + // This one corresponds to m_game_setup->isGrandPrixStarted() + bool m_legacy_gp_mode_started; + + // Special, temporarily public END +private: // These should be moved to voting manager ==================================== From d4ad6bf5311eea1cff0770a4ddc894de6f7ea2d6 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 19 Mar 2025 21:44:10 +0400 Subject: [PATCH 607/830] Removing useless AJPW Maybe something else, don't remember --- src/network/protocols/server_lobby.cpp | 26 +++++++++++++------------- src/network/protocols/server_lobby.hpp | 2 +- src/network/requests.cpp | 2 +- src/network/stk_host.cpp | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 6b78d7977d6..96a56ef32bd 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -613,7 +613,7 @@ void ServerLobby::asynchronousUpdate() if (getSettings()->isRanked() && m_state.load() == WAITING_FOR_START_GAME) m_ranking->cleanup(); - if (allowJoinedPlayersWaiting() || (getSettings()->isLegacyGPMode() && + if (!getSettings()->isLegacyGPMode() || (getSettings()->isLegacyGPMode() && m_state.load() == WAITING_FOR_START_GAME)) { // Only poll the STK server if server has been registered. @@ -624,7 +624,7 @@ void ServerLobby::asynchronousUpdate() } if (m_server_id_online.load() != 0 && - allowJoinedPlayersWaiting() && + !getSettings()->isLegacyGPMode() && StkTime::getMonoTimeMs() > m_last_unsuccess_poll_time && StkTime::getMonoTimeMs() > m_last_success_poll_time.load() + 30000) { @@ -691,7 +691,7 @@ void ServerLobby::asynchronousUpdate() { // For non grand prix server we only need to register to stk // addons once - if (allowJoinedPlayersWaiting()) + if (!getSettings()->isLegacyGPMode()) m_registered_for_once_only = true; m_state = WAITING_FOR_START_GAME; updatePlayerList(); @@ -1929,7 +1929,7 @@ void ServerLobby::startSelection(const Event *event) getSettings()->initializeDefaultVote(); - if (!allowJoinedPlayersWaiting()) + if (getSettings()->isLegacyGPMode()) { ProtocolManager::lock()->findAndTerminate(PROTOCOL_CONNECTION); if (m_server_id_online.load() != 0) @@ -1998,7 +1998,7 @@ void ServerLobby::startSelection(const Event *event) updatePlayerList(); } - if (!allowJoinedPlayersWaiting()) + if (getSettings()->isLegacyGPMode()) { // Drop all pending players and keys if doesn't allow joinning-waiting for (auto& p : m_pending_connection) @@ -2365,7 +2365,7 @@ void ServerLobby::connectionRequested(Event* event) peer->cleanPlayerProfiles(); // can we add the player ? - if (!allowJoinedPlayersWaiting() && + if (getSettings()->isLegacyGPMode() && (m_state.load() != WAITING_FOR_START_GAME /*|| m_game_setup->isGrandPrixStarted()*/)) { @@ -2868,7 +2868,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) m_lobby_players.store((int)all_profiles.size()); // No need to update player list (for started grand prix currently) - if (!allowJoinedPlayersWaiting() && + if (getSettings()->isLegacyGPMode() && m_state.load() > WAITING_FOR_START_GAME && !update_when_reset_server) return; @@ -3406,12 +3406,6 @@ void ServerLobby::configPeersStartTime() }); } // configPeersStartTime -//----------------------------------------------------------------------------- -bool ServerLobby::allowJoinedPlayersWaiting() const -{ - return !getSettings()->isLegacyGPMode(); -} // allowJoinedPlayersWaiting - //----------------------------------------------------------------------------- void ServerLobby::addWaitingPlayersToGame() { @@ -5042,4 +5036,10 @@ void ServerLobby::sendServerInfoToEveryone() const sendMessageToPeers(server_info); delete server_info; } // sendServerInfoToEveryone +//----------------------------------------------------------------------------- + +bool ServerLobby::isLegacyGPMode() const +{ + return getSettings()->isLegacyGPMode(); +} // isLegacyGPMode //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 69fe349ab35..4dc66c5dbf1 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -319,7 +319,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser virtual bool allPlayersReady() const OVERRIDE { return m_state.load() >= WAIT_FOR_RACE_STARTED; } virtual bool isRacing() const OVERRIDE { return m_state.load() == RACING; } - bool allowJoinedPlayersWaiting() const; void setSaveServerConfig(bool val) { m_save_server_config = val; } float getStartupBoostOrPenaltyForKart(uint32_t ping, unsigned kart_id); int getDifficulty() const { return m_difficulty.load(); } @@ -372,6 +371,7 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser bool isWorldPicked() const { return m_state.load() >= LOAD_WORLD; } bool isWorldFinished() const { return m_state.load() >= RESULT_DISPLAY; } + bool isLegacyGPMode() const; //------------------------------------------------------------------------- // The functions below reset/set ASM_NO_TEAM if needed by team changing procedure. diff --git a/src/network/requests.cpp b/src/network/requests.cpp index 2f841b83b24..49ad16038cd 100644 --- a/src/network/requests.cpp +++ b/src/network/requests.cpp @@ -105,7 +105,7 @@ void PollServerRequest::afterOperation() return; sl->resetSuccessPollTime(); if (!sl->isWaitingForStartGame() && - !sl->allowJoinedPlayersWaiting()) + sl->isLegacyGPMode()) { sl->replaceKeys(keys); return; diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index c21adaaba27..95306516820 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -867,7 +867,7 @@ void STKHost::mainLoop(ProcessType pt) std::unique_lock peer_lock(m_peers_mutex); const float timeout = ServerConfig::m_validation_timeout; bool need_ping = false; - if (sl && (!sl->isRacing() || sl->allowJoinedPlayersWaiting()) && + if (sl && (!sl->isRacing() || !sl->isLegacyGPMode()) && last_ping_time < StkTime::getMonoTimeMs()) { // If not racing, send an reliable packet at the 10 packets @@ -955,7 +955,7 @@ void STKHost::mainLoop(ProcessType pt) for (auto it = m_peers.begin(); it != m_peers.end();) { if (!ping_packet.getBuffer().empty() && - (!sl->allowJoinedPlayersWaiting() || + (sl->isLegacyGPMode() || !sl->isRacing() || it->second->isWaitingForGame())) { ENetPacket* packet = enet_packet_create(ping_packet.getData(), From 49f2166ded1832997689992283bfc3ae1b1b6401 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 20 Mar 2025 01:12:29 +0400 Subject: [PATCH 608/830] Move scoring to its separate class, store it inside LobbyGPManager --- src/modes/world_with_rank.cpp | 92 +++--------- src/modes/world_with_rank.hpp | 13 +- src/network/protocols/command_manager.cpp | 8 +- src/network/protocols/server_lobby.cpp | 1 + src/utils/gp_scoring.cpp | 167 ++++++++++++++++++++++ src/utils/gp_scoring.hpp | 50 +++++++ src/utils/lobby_context.cpp | 1 + src/utils/lobby_gp_manager.cpp | 58 ++++++-- src/utils/lobby_gp_manager.hpp | 9 ++ src/utils/lobby_settings.cpp | 62 +------- src/utils/lobby_settings.hpp | 6 - 11 files changed, 301 insertions(+), 166 deletions(-) create mode 100644 src/utils/gp_scoring.cpp create mode 100644 src/utils/gp_scoring.hpp diff --git a/src/modes/world_with_rank.cpp b/src/modes/world_with_rank.cpp index f2845333500..8d2aa794b24 100644 --- a/src/modes/world_with_rank.cpp +++ b/src/modes/world_with_rank.cpp @@ -24,6 +24,7 @@ #include "tracks/graph.hpp" #include "tracks/track.hpp" #include "tracks/track_sector.hpp" +#include "utils/gp_scoring.hpp" #include "utils/log.hpp" #include @@ -53,7 +54,7 @@ void WorldWithRank::init() if (!m_custom_scoring) stk_config->getAllScores(&m_score_for_position, getNumKarts()); else - refreshCustomScores(getNumKarts()); + m_custom_scoring->refreshCustomScores(getNumKarts(), m_score_for_position); Track *track = Track::getCurrentTrack(); // Don't init track sector if navmesh is not found in arena @@ -231,37 +232,13 @@ int WorldWithRank::getScoreForPosition(int p) */ int WorldWithRank::getScoreForPosition(int p, float time) { - assert(p - 1 >= 0); - assert(p - 1 < (int)m_score_for_position.size()); - m_race_times[p] = time; if (!m_custom_scoring) - return m_score_for_position[p - 1]; - if (m_custom_scoring_type == "inc" || m_custom_scoring_type == "fixed") - return m_score_for_position[p - 1]; - if (m_custom_scoring_type == "linear-gap" - || m_custom_scoring_type == "exp-gap") { - double delta = time - m_race_times[1]; - if (m_custom_scoring_type == "exp-gap") - { - if (m_race_times[1] < 1e-6) // just in case - return 0; - delta = log(time / m_race_times[1]) / log(2); - } - double points = m_custom_scoring_params[2] * 0.001; - bool continuous = (m_custom_scoring_params[5] != 0); - double time_step = m_custom_scoring_params[3] * 0.001; - double decrease = m_custom_scoring_params[4] * 0.001; - delta /= time_step; - if (!continuous) - delta = floor(delta); - points -= delta * decrease; - if (points < 0.0) - points = 0.0; - return round(points); + if (p - 1 >= 0 && p - 1 < (int)m_score_for_position.size()) + return m_score_for_position[p - 1]; + return 0; } - Log::error("WorldWithRank", "Unknown scoring type: %s. Giving 0 points", m_custom_scoring_type.c_str()); - return 0; + return m_custom_scoring->getScoreForPosition(p, time, m_race_times, m_score_for_position); } // getScoreForPosition //----------------------------------------------------------------------------- @@ -274,14 +251,10 @@ int WorldWithRank::getScoreForPosition(int p, float time) */ bool WorldWithRank::canGetScoreForPosition(int p) { - if (m_custom_scoring_type == "linear-gap" - || m_custom_scoring_type == "exp-gap") - { - if (p == 1 || m_race_times.count(1)) - return true; - return false; - } - return true; + if (!m_custom_scoring) + return true; + + return m_custom_scoring->canGetScoreForPosition(p, m_race_times); } // canGetScoreForPosition //----------------------------------------------------------------------------- @@ -328,53 +301,22 @@ void WorldWithRank::updateSectorForKarts() } // updateSectorForKarts //----------------------------------------------------------------------------- -void WorldWithRank::setCustomScoringSystem(std::string& type, std::vector& params) +void WorldWithRank::setCustomScoringSystem(std::shared_ptr scoring) { - m_custom_scoring_type = type; - m_custom_scoring_params = params; - if (type == "" || type == "standard" || type == "default") { - m_custom_scoring = false; + m_custom_scoring = scoring; + if (m_custom_scoring && m_custom_scoring->isStandard()) { + m_custom_scoring.reset(); return; } - m_custom_scoring = true; - refreshCustomScores(getNumKarts()); + m_custom_scoring->refreshCustomScores(getNumKarts(), m_score_for_position); } // setCustomScoringSystem //----------------------------------------------------------------------------- -void WorldWithRank::refreshCustomScores(int num_karts) -{ - if (m_custom_scoring_type == "inc") - { - m_score_for_position.clear(); - for (unsigned i = 2; i < m_custom_scoring_params.size(); i++) - m_score_for_position.push_back(m_custom_scoring_params[i]); - m_score_for_position.resize(num_karts, 0); - std::sort(m_score_for_position.begin(), m_score_for_position.end()); - for (unsigned i = 1; i < m_score_for_position.size(); i++) - m_score_for_position[i] += m_score_for_position[i - 1]; - std::reverse(m_score_for_position.begin(), m_score_for_position.end()); - } - else if (m_custom_scoring_type == "fixed") - { - m_score_for_position.clear(); - for (unsigned i = 2; i < m_custom_scoring_params.size(); i++) - m_score_for_position.push_back(m_custom_scoring_params[i]); - m_score_for_position.resize(num_karts, 0); - } - else if (m_custom_scoring_type == "linear-gap" - || m_custom_scoring_type == "exp-gap") - { - m_score_for_position.clear(); - m_score_for_position.resize(num_karts, 0); - } -} // refreshCustomScores -//----------------------------------------------------------------------------- - int WorldWithRank::getFastestLapPoints() const { if (!m_custom_scoring) return 0; - return m_custom_scoring_params[1]; + return m_custom_scoring->getFastestLapPoints(); } // getFastestLapPoints //----------------------------------------------------------------------------- @@ -382,6 +324,6 @@ int WorldWithRank::getPolePoints() const { if (!m_custom_scoring) return 0; - return m_custom_scoring_params[0]; + return m_custom_scoring->getPolePoints(); } // getPolePoints //----------------------------------------------------------------------------- diff --git a/src/modes/world_with_rank.hpp b/src/modes/world_with_rank.hpp index 1828426f4c6..adfe2458ce1 100644 --- a/src/modes/world_with_rank.hpp +++ b/src/modes/world_with_rank.hpp @@ -24,6 +24,7 @@ class AbstractKart; class TrackSector; +class GPScoring; /** * A WorldWithRank is a world where the karts are ranked. This is the base @@ -48,11 +49,7 @@ class WorldWithRank : public World * 0 based, so using race-position - 1. */ std::vector m_score_for_position; - bool m_custom_scoring; - - std::vector m_custom_scoring_params; - - std::string m_custom_scoring_type; + std::shared_ptr m_custom_scoring; std::map m_race_times; @@ -76,9 +73,7 @@ class WorldWithRank : public World void updateSectorForKarts(); public: - WorldWithRank() : World() { - m_custom_scoring = false; - } + WorldWithRank() : World() {} virtual ~WorldWithRank(); /** call just after instanciating. can't be moved to the contructor as child classes must be instanciated, otherwise polymorphism will fail and the @@ -117,7 +112,7 @@ class WorldWithRank : public World // ------------------------------------------------------------------------ int getSectorForKart(const AbstractKart *kart) const; // ------------------------------------------------------------------------ - void setCustomScoringSystem(std::string& type, std::vector& params); + void setCustomScoringSystem(std::shared_ptr scoring); // ------------------------------------------------------------------------ void refreshCustomScores(int num_karts); // ------------------------------------------------------------------------ diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 5a38072282a..000e2932d20 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -3114,7 +3114,7 @@ void CommandManager::process_scoring(Context& context) error(context, true); return; } - getLobby()->sendStringToPeer(peer, getSettings()->getScoringAsString()); + getLobby()->sendStringToPeer(peer, getGPManager()->getScoringAsString()); } // process_scoring // ======================================================================== @@ -3130,14 +3130,10 @@ void CommandManager::process_scoring_assign(Context& context) } std::string cmd2; CommandManager::restoreCmdByArgv(cmd2, argv, ' ', '"', '"', '\\', 1); - if (getSettings()->loadCustomScoring(cmd2)) - { + if (getGPManager()->trySettingGPScoring(cmd2)) getLobby()->sendStringToAllPeers("Scoring set to \"" + cmd2 + "\""); - } else - { getLobby()->sendStringToPeer(peer, "Scoring could not be parsed from \"" + cmd2 + "\""); - } } // process_scoring_assign // ======================================================================== diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 96a56ef32bd..44148d13768 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1596,6 +1596,7 @@ void ServerLobby::update(int ticks) Log::info("ServerLobby", "Starting the race loading."); // This will create the world instance, i.e. load track and karts loadWorld(); + getGPManager()->updateWorldScoring(); getSettings()->updateWorldSettings(m_game_info); m_state = WAIT_FOR_WORLD_LOADED; break; diff --git a/src/utils/gp_scoring.cpp b/src/utils/gp_scoring.cpp new file mode 100644 index 00000000000..5722d0c9482 --- /dev/null +++ b/src/utils/gp_scoring.cpp @@ -0,0 +1,167 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/gp_scoring.hpp" + +#include "network/server_config.hpp" +#include "utils/string_utils.hpp" +#include "utils/log.hpp" + +#include +#include + + +std::shared_ptr GPScoring::createFromIntParamString(const std::string& input) +{ + std::shared_ptr new_scoring = std::make_shared(); + + std::set available_scoring_types = { + "standard", "default", "", "inc", "fixed", "linear-gap", "exp-gap" + }; + if (!input.empty()) + { + std::vector params = StringUtils::split(input, ' '); + if (params.empty()) + { + new_scoring->m_type = ""; + return new_scoring; + } + new_scoring->m_type = params[0]; + if (available_scoring_types.count(params[0]) == 0) + throw std::logic_error("Unknown scoring type " + params[0]); + + for (unsigned i = 1; i < params.size(); i++) + { + int param; + if (!StringUtils::fromString(params[i], param)) + throw std::logic_error("Unable to parse integer from custom scoring data"); + + new_scoring->m_params.push_back(param); + } + } + return new_scoring; +} // createFromIntParamString +//----------------------------------------------------------------------------- + +bool GPScoring::isStandard() const +{ + return m_type == "" + || m_type == "standard" + || m_type == "default"; +} // isStandard +//----------------------------------------------------------------------------- + +void GPScoring::refreshCustomScores(int num_karts, + std::vector& score_for_position) +{ + if (m_type == "inc") + { + // Testing indicates that number of parameters is not validated. + // Do it when splitting into separate classes. + score_for_position.clear(); + for (unsigned i = 2; i < m_params.size(); i++) + score_for_position.push_back(m_params[i]); + score_for_position.resize(num_karts, 0); + std::sort(score_for_position.begin(), score_for_position.end()); + for (unsigned i = 1; i < score_for_position.size(); i++) + score_for_position[i] += score_for_position[i - 1]; + std::reverse(score_for_position.begin(), score_for_position.end()); + } + else if (m_type == "fixed") + { + score_for_position.clear(); + for (unsigned i = 2; i < m_params.size(); i++) + score_for_position.push_back(m_params[i]); + score_for_position.resize(num_karts, 0); + } + else if (m_type == "linear-gap" + || m_type == "exp-gap") + { + score_for_position.clear(); + score_for_position.resize(num_karts, 0); + } +} // refreshCustomScores +//----------------------------------------------------------------------------- + +int GPScoring::getPolePoints() const +{ + return m_params[0]; +} // getPolePoints +//----------------------------------------------------------------------------- + +int GPScoring::getFastestLapPoints() const +{ + return m_params[1]; +} // getFastestLapPoints +//----------------------------------------------------------------------------- + +int GPScoring::getScoreForPosition(int p, float time, + std::map& race_times, + const std::vector& score_for_position) const +{ + race_times[p] = time; + if (m_type == "inc" || m_type == "fixed") + return score_for_position[p - 1]; + if (m_type == "linear-gap" + || m_type == "exp-gap") + { + double delta = time - race_times[1]; + if (m_type == "exp-gap") + { + if (race_times[1] < 1e-6) // just in case + return 0; + delta = log(time / race_times[1]) / log(2); + } + double points = m_params[2] * 0.001; + bool continuous = (m_params[5] != 0); + double time_step = m_params[3] * 0.001; + double decrease = m_params[4] * 0.001; + delta /= time_step; + if (!continuous) + delta = floor(delta); + points -= delta * decrease; + if (points < 0.0) + points = 0.0; + return round(points); + } + Log::error("GPScoring", "Unknown scoring type: %s. Giving 0 points", m_type.c_str()); + return 0; +} // getScoreForPosition +//----------------------------------------------------------------------------- + +bool GPScoring::canGetScoreForPosition(int p, const std::map& race_times) const +{ + if (m_type == "linear-gap" + || m_type == "exp-gap") + { + if (p == 1 || race_times.count(1)) + return true; + return false; + } + return true; +} // canGetScoreForPosition +//----------------------------------------------------------------------------- + +std::string GPScoring::toString() const +{ + std::string res = m_type; + for (int param: m_params) + res += StringUtils::insertValues(" %d", param); + return res; +} // toString +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/gp_scoring.hpp b/src/utils/gp_scoring.hpp new file mode 100644 index 00000000000..b49793eaf38 --- /dev/null +++ b/src/utils/gp_scoring.hpp @@ -0,0 +1,50 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef GP_SCORING_HPP +#define GP_SCORING_HPP + +#include "irrString.h" + +#include +#include +#include +#include +#include + +class GPScoring +{ +public: + static std::shared_ptr createFromIntParamString(const std::string& input); + bool isStandard() const; + void refreshCustomScores(int num_karts, + std::vector& score_for_position); + int getPolePoints() const; + int getFastestLapPoints() const; + int getScoreForPosition(int p, float time, + std::map& race_times, + const std::vector& score_for_position) const; + bool canGetScoreForPosition(int p, const std::map& race_times) const; + std::string toString() const; + +private: + std::vector m_params; + std::string m_type; +}; + +#endif // GP_SCORING_HPP \ No newline at end of file diff --git a/src/utils/lobby_context.cpp b/src/utils/lobby_context.cpp index 7eb0e1cf02a..7f4f705e678 100644 --- a/src/utils/lobby_context.cpp +++ b/src/utils/lobby_context.cpp @@ -29,6 +29,7 @@ #include "utils/team_manager.hpp" #include "utils/tournament.hpp" #include "utils/lobby_gp_manager.hpp" +#include "utils/gp_scoring.hpp" LobbyContext::LobbyContext(ServerLobby* lobby, bool make_tournament) : m_lobby(lobby) diff --git a/src/utils/lobby_gp_manager.cpp b/src/utils/lobby_gp_manager.cpp index bf118d4afe6..601856b90ce 100644 --- a/src/utils/lobby_gp_manager.cpp +++ b/src/utils/lobby_gp_manager.cpp @@ -18,21 +18,23 @@ #include "utils/lobby_gp_manager.hpp" -#include "network/server_config.hpp" -#include "utils/string_utils.hpp" -#include "network/game_setup.hpp" -#include "network/protocols/server_lobby.hpp" -#include "network/network_player_profile.hpp" -#include "modes/world.hpp" #include "karts/abstract_kart.hpp" -#include "utils/team_manager.hpp" -#include "modes/world_with_rank.hpp" #include "modes/linear_world.hpp" +#include "modes/world.hpp" +#include "modes/world_with_rank.hpp" +#include "network/game_setup.hpp" +#include "network/network_player_profile.hpp" #include "network/network_string.hpp" +#include "network/protocols/server_lobby.hpp" +#include "network/server_config.hpp" +#include "utils/gp_scoring.hpp" +#include "utils/string_utils.hpp" +#include "utils/team_manager.hpp" void LobbyGPManager::setupContextUser() { - + if (!trySettingGPScoring(ServerConfig::m_gp_scoring)) + m_gp_scoring = {}; } // setupContextUser //----------------------------------------------------------------------------- @@ -249,4 +251,42 @@ void LobbyGPManager::updateGPScores(std::vector& gp_changes, NetworkStrin .addFloat(overall_times[i]); } } // updateGPScores +//----------------------------------------------------------------------------- + +bool LobbyGPManager::trySettingGPScoring(const std::string& input) +{ + std::shared_ptr new_scoring; + + try + { + new_scoring = GPScoring::createFromIntParamString(input); + } + catch (std::logic_error& ex) + { + Log::warn("Failed to create GP scoring from string (%s): %s", + input.c_str(), ex.what()); + return false; + } + + std::swap(m_gp_scoring, new_scoring); + return true; +} // trySettingGPScoring +//----------------------------------------------------------------------------- + +void LobbyGPManager::updateWorldScoring() const +{ + WorldWithRank *wwr = dynamic_cast(World::getWorld()); + if (wwr) + wwr->setCustomScoringSystem(m_gp_scoring); +} // updateWorldScoring +//----------------------------------------------------------------------------- + +std::string LobbyGPManager::getScoringAsString() const +{ + std::string msg = "Current scoring is \""; + if (m_gp_scoring) + msg += m_gp_scoring->toString(); + msg += "\""; + return msg; +} // getScoringAsString //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/lobby_gp_manager.hpp b/src/utils/lobby_gp_manager.hpp index 11502b33980..aa8f0b1ec99 100644 --- a/src/utils/lobby_gp_manager.hpp +++ b/src/utils/lobby_gp_manager.hpp @@ -28,6 +28,7 @@ class NetworkPlayerProfile; class NetworkString; +class GPScoring; struct GPScore { @@ -62,11 +63,19 @@ class LobbyGPManager: public LobbyContextComponent void updateGPScores(std::vector& gp_changes, NetworkString* ns); + bool trySettingGPScoring(const std::string& input); + + void updateWorldScoring() const; + + std::string getScoringAsString() const; + private: std::map m_gp_scores; std::map m_gp_team_scores; + std::shared_ptr m_gp_scoring; + }; #endif // LOBBY_GP_MANAGER_HPP \ No newline at end of file diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index 9a61b78e06e..f7bf5ffe6b8 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -70,8 +70,7 @@ void LobbySettings::setupContextUser() initAvailableModes(); initAvailableTracks(); - std::string scoring = ServerConfig::m_gp_scoring; - loadCustomScoring(scoring); + loadWhiteList(); loadPreservedSettings(); @@ -183,50 +182,6 @@ void LobbySettings::initAvailableTracks() } // initAvailableTracks //----------------------------------------------------------------------------- -bool LobbySettings::loadCustomScoring(std::string& scoring) -{ - std::set available_scoring_types = { - "standard", "default", "", "inc", "fixed", "linear-gap", "exp-gap" - }; - auto previous_params = m_scoring_int_params; - auto previous_type = m_scoring_type; - m_scoring_int_params.clear(); - m_scoring_type = ""; - if (!scoring.empty()) - { - std::vector params = StringUtils::split(scoring, ' '); - if (params.empty()) - { - m_scoring_type = ""; - return true; - } - m_scoring_type = params[0]; - if (available_scoring_types.count(m_scoring_type) == 0) - { - Log::warn("ServerLobby", "Unknown scoring type %s, " - "fallback.", m_scoring_type.c_str()); - m_scoring_int_params = previous_params; - m_scoring_type = previous_type; - return false; - } - for (unsigned i = 1; i < params.size(); i++) - { - int param; - if (!StringUtils::fromString(params[i], param)) - { - Log::warn("ServerLobby", "Unable to parse integer from custom " - "scoring data, fallback."); - m_scoring_int_params = previous_params; - m_scoring_type = previous_type; - return false; - } - m_scoring_int_params.push_back(param); - } - } - return true; -} // loadCustomScoring -//----------------------------------------------------------------------------- - void LobbySettings::loadWhiteList() { std::vector tokens = StringUtils::split( @@ -424,11 +379,6 @@ std::vector LobbySettings::getMissingAssets( void LobbySettings::updateWorldSettings(std::shared_ptr game_info) { World::getWorld()->setGameInfo(game_info); - WorldWithRank *wwr = dynamic_cast(World::getWorld()); - if (wwr) - { - wwr->setCustomScoringSystem(m_scoring_type, m_scoring_int_params); - } SoccerWorld *sw = dynamic_cast(World::getWorld()); if (sw) { @@ -473,16 +423,6 @@ bool LobbySettings::isPreservingMode() const } // isPreservingMode //----------------------------------------------------------------------------- -std::string LobbySettings::getScoringAsString() const -{ - std::string msg = "Current scoring is \"" + m_scoring_type; - for (int param: m_scoring_int_params) - msg += StringUtils::insertValues(" %d", param); - msg += "\""; - return msg; -} // getScoringAsString -//----------------------------------------------------------------------------- - std::string LobbySettings::getPreservedSettingsAsString() const { std::string msg = "Preserved settings:"; diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 92ea1c0a53b..44a79d01cf3 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -50,7 +50,6 @@ class LobbySettings: public LobbyContextComponent void initAvailableTracks(); void initAvailableModes(); - bool loadCustomScoring(std::string& scoring); void loadWhiteList(); void loadPreservedSettings(); bool hasConsentOnReplays() const { return m_consent_on_replays; } @@ -82,7 +81,6 @@ class LobbySettings: public LobbyContextComponent void updateWorldSettings(std::shared_ptr game_info); void onResetToDefaultSettings(); bool isPreservingMode() const; - std::string getScoringAsString() const; std::string getPreservedSettingsAsString() const; void eraseFromPreserved(const std::string& value); void insertIntoPreserved(const std::string& value); @@ -215,10 +213,6 @@ class LobbySettings: public LobbyContextComponent double m_default_lap_multiplier; - std::vector m_scoring_int_params; - - std::string m_scoring_type; - std::set m_usernames_white_list; std::set m_preserve; From c99ae247f8870b4221296fb89729a047efd5a091 Mon Sep 17 00:00:00 2001 From: Nytik Birudavolu <91942626+iamnytik@users.noreply.github.com> Date: Fri, 21 Mar 2025 22:07:17 +0530 Subject: [PATCH 609/830] Update cutscene_gui.cpp (#5374) * Update cutscene_gui.cpp This update will move the subtitles from the bottom of the screen a few pixels above.This is intended so that the subtitles stay above the Skip buttons in cutscenes * Update cutscene_gui.cpp lowered the positioning of subtitles by modifying 10 to 6 font size --- src/states_screens/cutscene_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/states_screens/cutscene_gui.cpp b/src/states_screens/cutscene_gui.cpp index 5a4ede06401..d3e466cb3c0 100644 --- a/src/states_screens/cutscene_gui.cpp +++ b/src/states_screens/cutscene_gui.cpp @@ -54,7 +54,7 @@ void CutsceneGUI::renderGlobal(float dt) if (m_subtitle.size() > 0) { - core::rect r(0, screen_size.Height - GUIEngine::getFontHeight()*2, + core::rect r(0, screen_size.Height - GUIEngine::getFontHeight()*6, screen_size.Width, screen_size.Height); if (GUIEngine::getFont()->getDimension(m_subtitle.c_str()).Width > screen_size.Width) From c9efa23bdfa76effe8c4868f35b28fb4a5868a32 Mon Sep 17 00:00:00 2001 From: Deve Date: Fri, 21 Mar 2025 17:43:40 +0100 Subject: [PATCH 610/830] Use vsync on android. It solves the issue when game rendering just hangs after a while on phones with game mode. --- lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp b/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp index 406884d06cd..0079ea54cd5 100644 --- a/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp +++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp @@ -396,8 +396,8 @@ extern "C" void update_fullscreen_desktop(int val) // Used in OptionsScreenVideo for live updating vertical sync config extern "C" void update_swap_interval(int swap_interval) { -#ifndef IOS_STK - // iOS always use vertical sync +#ifndef MOBILE_STK + // Mobile always use vertical sync if (swap_interval > 1) swap_interval = 1; From 295631c994b664e39485fa0a29de64bf471faaab Mon Sep 17 00:00:00 2001 From: Deve Date: Fri, 21 Mar 2025 17:45:35 +0100 Subject: [PATCH 611/830] Disable 1000 fps and 200% scale nonsense on mobile --- src/states_screens/options/options_screen_video.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/states_screens/options/options_screen_video.cpp b/src/states_screens/options/options_screen_video.cpp index 75db196ba72..26bf9f4834a 100644 --- a/src/states_screens/options/options_screen_video.cpp +++ b/src/states_screens/options/options_screen_video.cpp @@ -124,9 +124,11 @@ void OptionsScreenVideo::initPresets() m_scale_rtts_custom_presets.push_back({ 0.9f }); m_scale_rtts_custom_presets.push_back({ 0.95f }); m_scale_rtts_custom_presets.push_back({ 1.0f }); +#ifndef MOBILE_STK m_scale_rtts_custom_presets.push_back({ 1.25f }); m_scale_rtts_custom_presets.push_back({ 1.5f }); m_scale_rtts_custom_presets.push_back({ 2.0f }); +#endif } // initPresets @@ -252,7 +254,11 @@ void OptionsScreenVideo::init() vsync->clearLabels(); //I18N: In the video options vsync->addLabel(_("Vertical Sync")); +#ifdef MOBILE_STK + std::set fps = { 30, 60, 120 }; +#else std::set fps = { 30, 60, 120, 180, 250, 500, 1000 }; +#endif fps.insert(UserConfigParams::m_max_fps); for (auto& i : fps) vsync->addLabel(core::stringw(i)); @@ -295,9 +301,11 @@ void OptionsScreenVideo::init() scale_rtts->addLabel("90%"); scale_rtts->addLabel("95%"); scale_rtts->addLabel("100%"); +#ifndef MOBILE_STK scale_rtts->addLabel("125%"); scale_rtts->addLabel("150%"); scale_rtts->addLabel("200%"); +#endif // --- set gfx settings values updateGfxSlider(); @@ -741,4 +749,4 @@ void OptionsScreenVideo::unloaded() m_inited = false; } // unloaded -// -------------------------------------------------------------------------------------------- \ No newline at end of file +// -------------------------------------------------------------------------------------------- From fef37db681576023f14cbbd3a843fede69ec1f83 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 24 Mar 2025 03:56:49 +0800 Subject: [PATCH 612/830] Disable ghost version check & Disable ghost skid sound --- src/karts/ghost_kart.cpp | 15 --------------- src/states_screens/ghost_replay_selection.cpp | 2 +- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/karts/ghost_kart.cpp b/src/karts/ghost_kart.cpp index fb46ed5b191..b118c8320f7 100644 --- a/src/karts/ghost_kart.cpp +++ b/src/karts/ghost_kart.cpp @@ -256,21 +256,6 @@ void GhostKart::updateSound(float dt) updateEngineSFX(dt); - if (m_skid_sound) - { - if(m_all_replay_events[idx].m_skidding_effect) - { - if (m_skid_sound->getStatus()!=SFXBase::SFX_PLAYING) - { - m_skid_sound->play(getSmoothedXYZ()); - } - } - else if(m_skid_sound->getStatus()==SFXBase::SFX_PLAYING) - { - m_skid_sound->stop(); - } - } - if (m_nitro_sound) { if(m_all_replay_events[idx].m_nitro_usage) diff --git a/src/states_screens/ghost_replay_selection.cpp b/src/states_screens/ghost_replay_selection.cpp index aae51d01f20..762baa2f99e 100644 --- a/src/states_screens/ghost_replay_selection.cpp +++ b/src/states_screens/ghost_replay_selection.cpp @@ -112,7 +112,7 @@ void GhostReplaySelection::loadedFromFile() m_replay_version_toggle_widget = getWidget("replay_version_toggle"); - m_replay_version_toggle_widget->setState(/* default value */ true); + m_replay_version_toggle_widget->setState(/* default value */ false); m_same_version = m_replay_version_toggle_widget->getState(); m_best_times_toggle_widget = From 888b9e50177b7b5969769fb54ec684c780c562a1 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 24 Mar 2025 05:06:54 +0800 Subject: [PATCH 613/830] Add warning to oversampling --- src/guiengine/widgets/player_kart_widget.cpp | 10 ++- src/guiengine/widgets/player_kart_widget.hpp | 8 +- src/guiengine/widgets/player_name_spinner.cpp | 77 ------------------- src/guiengine/widgets/player_name_spinner.hpp | 54 ------------- src/guiengine/widgets/spinner_widget.cpp | 40 +++++++++- src/guiengine/widgets/spinner_widget.hpp | 24 ++++-- src/states_screens/kart_selection.cpp | 2 +- src/states_screens/kart_selection.hpp | 1 - .../options/options_screen_video.cpp | 12 ++- 9 files changed, 76 insertions(+), 152 deletions(-) delete mode 100644 src/guiengine/widgets/player_name_spinner.cpp delete mode 100644 src/guiengine/widgets/player_name_spinner.hpp diff --git a/src/guiengine/widgets/player_kart_widget.cpp b/src/guiengine/widgets/player_kart_widget.cpp index 804261b2f58..27b91f4603e 100644 --- a/src/guiengine/widgets/player_kart_widget.cpp +++ b/src/guiengine/widgets/player_kart_widget.cpp @@ -24,7 +24,6 @@ #include #include "guiengine/widgets/kart_stats_widget.hpp" #include "guiengine/widgets/model_view_widget.hpp" -#include "guiengine/widgets/player_name_spinner.hpp" #include "input/input_device.hpp" #include "karts/kart_model.hpp" #include "karts/kart_properties.hpp" @@ -72,7 +71,10 @@ PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent, // ---- Player identity spinner m_player_ident_spinner = NULL; - m_player_ident_spinner = new PlayerNameSpinner(parent, m_player_id); + m_player_ident_spinner = new SpinnerWidget(); + m_player_ident_spinner->setUseBackgroundColor(); + m_player_ident_spinner->setSpinnerWidgetPlayerID(m_player_id); + m_player_ident_spinner->m_x = player_name_x; m_player_ident_spinner->m_y = player_name_y; m_player_ident_spinner->m_w = player_name_w; @@ -310,14 +312,14 @@ void PlayerKartWidget::setPlayerID(const int newPlayerID) // Change the player ID m_player_id = newPlayerID; if (!m_ready) - m_player_ident_spinner->setID(m_player_id); + m_player_ident_spinner->setSpinnerWidgetPlayerID(m_player_id); m_kart_stats->setDisplayIcons(m_player_id == 0); // restore previous focus, but with new player ID if (focus != NULL) focus->setFocusForPlayer(m_player_id); if (m_player_ident_spinner != NULL) { - m_player_ident_spinner->setID(m_player_id); + m_player_ident_spinner->setSpinnerWidgetPlayerID(m_player_id); } } // setPlayerID diff --git a/src/guiengine/widgets/player_kart_widget.hpp b/src/guiengine/widgets/player_kart_widget.hpp index 9d8ace15894..ae81652799a 100644 --- a/src/guiengine/widgets/player_kart_widget.hpp +++ b/src/guiengine/widgets/player_kart_widget.hpp @@ -30,15 +30,15 @@ class KartSelectionScreen; namespace GUIEngine { - class PlayerNameSpinner; class KartStatsWidget; class ModelViewWidget; class LabelWidget; + class SpinnerWidget; /** A widget representing the kart selection for a player (i.e. the player's * number, name, the kart view, the kart's name) */ class PlayerKartWidget : public GUIEngine::Widget, - public GUIEngine::SpinnerWidget::ISpinnerConfirmListener + public SpinnerWidget::ISpinnerConfirmListener { /** Whether this player confirmed their selection */ bool m_ready; @@ -79,7 +79,7 @@ namespace GUIEngine LEAK_CHECK() /** Sub-widgets created by this widget */ - PlayerNameSpinner* m_player_ident_spinner; + SpinnerWidget* m_player_ident_spinner; KartStatsWidget* m_kart_stats; ModelViewWidget* m_model_view; LabelWidget* m_kart_name; @@ -106,7 +106,7 @@ namespace GUIEngine /** Called when players are renumbered (changes the player ID) */ void setPlayerID(const int newPlayerID); // ------------------------------------------------------------------------ - PlayerNameSpinner* getPlayerNameSpinner() const + SpinnerWidget* getPlayerNameSpinner() const { return m_player_ident_spinner; } // ------------------------------------------------------------------------ /** Returns the ID of this player */ diff --git a/src/guiengine/widgets/player_name_spinner.cpp b/src/guiengine/widgets/player_name_spinner.cpp deleted file mode 100644 index 178ca0562de..00000000000 --- a/src/guiengine/widgets/player_name_spinner.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// SuperTuxKart - a fun racing game with go-kart -// -// Copyright (C) 2006-2015 SuperTuxKart-Team -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 3 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include "guiengine/widgets/player_name_spinner.hpp" -#include "guiengine/engine.hpp" -#include "graphics/irr_driver.hpp" -#include "io/file_manager.hpp" -#include - -using namespace GUIEngine; - -PlayerNameSpinner::PlayerNameSpinner(KartSelectionScreen* parent, - const int player_id) -{ - m_player_id = player_id; - m_incorrect = false; - m_red_mark_widget = NULL; - m_parent = parent; - setUseBackgroundColor();//except for multiplayer kart selection, this is false - setSpinnerWidgetPlayerID(m_player_id); -} // PlayerNameSpinner -// ------------------------------------------------------------------------ -void PlayerNameSpinner::setID(const int m_player_id) -{ - PlayerNameSpinner::m_player_id = m_player_id; - setSpinnerWidgetPlayerID(m_player_id); -} // setID -// ------------------------------------------------------------------------ -/** Add a red mark on the spinner to mean "invalid choice" */ -void PlayerNameSpinner::markAsIncorrect() -{ - if (m_incorrect) return; // already flagged as incorrect - - m_incorrect = true; - - irr::video::ITexture* texture = irr_driver->getTexture(FileManager::GUI_ICON, - "red_mark.png" ); - const int mark_size = m_h; - const int mark_x = m_w - mark_size*2; - const int mark_y = 0; - core::recti red_mark_area(mark_x, mark_y, mark_x + mark_size, - mark_y + mark_size); - m_red_mark_widget = GUIEngine::getGUIEnv()->addImage( red_mark_area, - /* parent */ m_element ); - m_red_mark_widget->setImage(texture); - m_red_mark_widget->setScaleImage(true); - m_red_mark_widget->setTabStop(false); - m_red_mark_widget->setUseAlphaChannel(true); -} // markAsIncorrect - -// ------------------------------------------------------------------------ -/** Remove any red mark set with 'markAsIncorrect' */ -void PlayerNameSpinner::markAsCorrect() -{ - if (m_incorrect) - { - m_red_mark_widget->remove(); - m_red_mark_widget = NULL; - m_incorrect = false; - } -} // markAsCorrect - diff --git a/src/guiengine/widgets/player_name_spinner.hpp b/src/guiengine/widgets/player_name_spinner.hpp deleted file mode 100644 index 9b32c2e0186..00000000000 --- a/src/guiengine/widgets/player_name_spinner.hpp +++ /dev/null @@ -1,54 +0,0 @@ -// SuperTuxKart - a fun racing game with go-kart -// -// Copyright (C) 2006-2015 SuperTuxKart-Team -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 3 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef PLAYER_NAME_SPINNER_HPP -#define PLAYER_NAME_SPINNER_HPP - -#include "guiengine/widgets/spinner_widget.hpp" -#include - -class KartSelectionScreen; - -namespace GUIEngine -{ - /** A small extension to the spinner widget to add features like player ID - * management or badging */ - class PlayerNameSpinner : public GUIEngine::SpinnerWidget - { - int m_player_id; - bool m_incorrect; - irr::gui::IGUIImage* m_red_mark_widget; - KartSelectionScreen* m_parent; - //virtual EventPropagation focused(const int m_playerID) ; - - public: - PlayerNameSpinner(KartSelectionScreen* parent, const int playerID); - // ------------------------------------------------------------------------ - void setID(const int m_playerID); - - // ------------------------------------------------------------------------ - /** Add a red mark on the spinner to mean "invalid choice" */ - void markAsIncorrect(); - // ------------------------------------------------------------------------ - /** Remove any red mark set with 'markAsIncorrect' */ - void markAsCorrect(); - }; -} - -#endif - diff --git a/src/guiengine/widgets/spinner_widget.cpp b/src/guiengine/widgets/spinner_widget.cpp index 05535405cd3..1ac88c25331 100644 --- a/src/guiengine/widgets/spinner_widget.cpp +++ b/src/guiengine/widgets/spinner_widget.cpp @@ -22,6 +22,7 @@ #include "guiengine/scalable_font.hpp" #include "guiengine/widgets/spinner_widget.hpp" #include "io/file_manager.hpp" +#include "states_screens/state_manager.hpp" #include "utils/string_utils.hpp" #include "utils/log.hpp" @@ -98,14 +99,51 @@ SpinnerWidget::SpinnerWidget(const bool gauge) : Widget(WTYPE_SPINNER) m_value = -1; m_badge_x_shift = 0; m_use_background_color=false; - m_spinner_widget_player_id=-1; + m_spinner_widget_player_id=PLAYER_ID_GAME_MASTER; m_min = 0; m_max = 999; m_step = 1.0; m_left_selected = false; m_right_selected = false; + m_incorrect = false; + m_red_mark_widget = NULL; } +// ------------------------------------------------------------------------ +/** Add a red mark on the spinner to mean "invalid choice" */ +void SpinnerWidget::markAsIncorrect() +{ + if (m_incorrect) return; // already flagged as incorrect + + m_incorrect = true; + + irr::video::ITexture* texture = irr_driver->getTexture(FileManager::GUI_ICON, + "red_mark.png" ); + const int mark_size = m_h * 4 / 5; + const int mark_x = m_w - m_h * 19 / 10; + const int mark_y = m_h / 10; + core::recti red_mark_area(mark_x, mark_y, mark_x + mark_size, + mark_y + mark_size); + m_red_mark_widget = GUIEngine::getGUIEnv()->addImage( red_mark_area, + /* parent */ m_element ); + m_red_mark_widget->setImage(texture); + m_red_mark_widget->setScaleImage(true); + m_red_mark_widget->setTabStop(false); + m_red_mark_widget->setUseAlphaChannel(true); +} // markAsIncorrect + +// ------------------------------------------------------------------------ +/** Remove any red mark set with 'markAsIncorrect' */ +void SpinnerWidget::markAsCorrect() +{ + if (m_incorrect) + { + m_red_mark_widget->remove(); + m_red_mark_widget = NULL; + m_incorrect = false; + } +} // markAsCorrect + // ----------------------------------------------------------------------------- void SpinnerWidget::setRange(float min, float max, float step) { diff --git a/src/guiengine/widgets/spinner_widget.hpp b/src/guiengine/widgets/spinner_widget.hpp index e74ae2c3c49..6536e6b9443 100644 --- a/src/guiengine/widgets/spinner_widget.hpp +++ b/src/guiengine/widgets/spinner_widget.hpp @@ -31,6 +31,8 @@ namespace irr #include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" +#include + namespace GUIEngine { @@ -52,12 +54,15 @@ namespace GUIEngine virtual EventPropagation onSpinnerConfirmed() = 0; }; - protected: + private: std::function m_value_updated_callback; ISpinnerConfirmListener* m_listener; int m_value, m_min, m_max; float m_step; + + bool m_incorrect; + irr::gui::IGUIImage* m_red_mark_widget; int m_spinner_widget_player_id; bool m_use_background_color; @@ -126,11 +131,11 @@ namespace GUIEngine void clearLabels(); // next four functions are for background colour behind playername in multikart screen selection - void setUseBackgroundColor() {m_use_background_color=true; } - bool getUseBackgroundColor() {return m_use_background_color; } - void setSpinnerWidgetPlayerID(int playerID) {m_spinner_widget_player_id=playerID;} - int getSpinnerWidgetPlayerID() {return m_spinner_widget_player_id; } - void unsetUseBackgroundColor() {m_use_background_color=false; } + void setUseBackgroundColor() { m_use_background_color=true; } + bool getUseBackgroundColor() const { return m_use_background_color; } + void setSpinnerWidgetPlayerID(int playerID) { m_spinner_widget_player_id=playerID; } + int getSpinnerWidgetPlayerID() const { return m_spinner_widget_player_id; } + void unsetUseBackgroundColor() { m_use_background_color=false; } void activateSelectedButton(); void setSelectedButton(bool right) @@ -264,6 +269,13 @@ namespace GUIEngine m_min = n; if(getValue()("kart_class"); DynamicRibbonWidget* w = getWidget("karts"); diff --git a/src/states_screens/kart_selection.hpp b/src/states_screens/kart_selection.hpp index 6b921b8a393..e6471995af8 100644 --- a/src/states_screens/kart_selection.hpp +++ b/src/states_screens/kart_selection.hpp @@ -52,7 +52,6 @@ class KartSelectionScreen : public GUIEngine::Screen, public GUIEngine::ITextBoxWidgetListener { friend class KartHoverListener; - friend class PlayerNameSpinner; friend class FocusDispatcher; protected: /** Contains the custom widget shown for every player. (ref only since diff --git a/src/states_screens/options/options_screen_video.cpp b/src/states_screens/options/options_screen_video.cpp index 26bf9f4834a..36ad14f4afc 100644 --- a/src/states_screens/options/options_screen_video.cpp +++ b/src/states_screens/options/options_screen_video.cpp @@ -124,11 +124,9 @@ void OptionsScreenVideo::initPresets() m_scale_rtts_custom_presets.push_back({ 0.9f }); m_scale_rtts_custom_presets.push_back({ 0.95f }); m_scale_rtts_custom_presets.push_back({ 1.0f }); -#ifndef MOBILE_STK m_scale_rtts_custom_presets.push_back({ 1.25f }); m_scale_rtts_custom_presets.push_back({ 1.5f }); m_scale_rtts_custom_presets.push_back({ 2.0f }); -#endif } // initPresets @@ -301,11 +299,9 @@ void OptionsScreenVideo::init() scale_rtts->addLabel("90%"); scale_rtts->addLabel("95%"); scale_rtts->addLabel("100%"); -#ifndef MOBILE_STK scale_rtts->addLabel("125%"); scale_rtts->addLabel("150%"); scale_rtts->addLabel("200%"); -#endif // --- set gfx settings values updateGfxSlider(); @@ -437,6 +433,14 @@ void OptionsScreenVideo::updateScaleRTTsSlider() { scale_rtts_level->setValue(l); found = true; + if (m_scale_rtts_custom_presets[l].value > 1.0f) + { + scale_rtts_level->markAsIncorrect(); + } + else + { + scale_rtts_level->markAsCorrect(); + } break; } } From e5c5468caddb32bd5b3d3f94d276e249f3c40a1a Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 24 Mar 2025 01:51:28 +0400 Subject: [PATCH 614/830] Quick teamchat and KartTeamSet fixes --- src/network/remote_kart_info.hpp | 19 +++++++++++++------ src/utils/chat_manager.cpp | 7 +++++-- src/utils/tournament.cpp | 2 +- src/utils/tournament.hpp | 5 ++++- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/network/remote_kart_info.hpp b/src/network/remote_kart_info.hpp index f7c1e936c87..1ba403aed72 100644 --- a/src/network/remote_kart_info.hpp +++ b/src/network/remote_kart_info.hpp @@ -42,12 +42,19 @@ struct KartTeamSet { int state; KartTeamSet(int x = 0): state(x) {} - KartTeamSet add (KartTeam team) const { return KartTeamSet(state | (1 << (team + 1))); } - KartTeamSet remove (KartTeam team) const { return KartTeamSet(state & ~(1 << (team + 1))); } - KartTeamSet flip (KartTeam team) const { return KartTeamSet(state ^ (1 << (team + 1))); } - bool has (KartTeam team) const { return ((state >> (team + 1)) & 1); } - KartTeamSet intersect (KartTeamSet rhs) const { return KartTeamSet(state & rhs.state); } - bool empty () const { return state == 0; } + + bool has (KartTeam team) const { return ((state >> (team + 1)) & 1); } + bool empty() const { return state == 0; } + + KartTeamSet operator + (KartTeam team) const { return KartTeamSet(state | (1 << (team + 1))); } + KartTeamSet operator - (KartTeam team) const { return KartTeamSet(state & ~(1 << (team + 1))); } + KartTeamSet operator ^ (KartTeam team) const { return KartTeamSet(state ^ (1 << (team + 1))); } + KartTeamSet operator & (KartTeamSet rhs) const { return KartTeamSet(state & rhs.state); } + + void add (KartTeam team) { state |= (1 << (team + 1)); } + void remove (KartTeam team) { state &= ~(1 << (team + 1)); } + void flip (KartTeam team) { state ^= (1 << (team + 1)); } + void intersect(KartTeamSet rhs) { state &= rhs.state; } }; /** Handicap per player. */ diff --git a/src/utils/chat_manager.cpp b/src/utils/chat_manager.cpp index c6e5f20f78a..bf903a6fbce 100644 --- a/src/utils/chat_manager.cpp +++ b/src/utils/chat_manager.cpp @@ -252,6 +252,9 @@ bool ChatManager::shouldMessageBeSent(std::shared_ptr sender, { if (target->isSpectator()) return false; + + if (!Tournament::hasProfileFromTeam(target, target_team)) + return false; } if (isTournament()) @@ -263,7 +266,7 @@ bool ChatManager::shouldMessageBeSent(std::shared_ptr sender, if (target_team != KART_TEAM_NONE) { if (!tournament->hasProfileThatSeesTeamchats(target) && - !tournament->hasProfileFromTeam(target, target_team)) + !Tournament::hasProfileFromTeam(target, target_team)) return false; } } @@ -275,7 +278,7 @@ bool ChatManager::shouldMessageBeSent(std::shared_ptr sender, { // this should be moved into a new function for peer, // unless all profiles have the same team forcibly rn - bool someone_good = !(getTeamsForPeer(sender).intersect(getTeamsForPeer(target))).empty(); + bool someone_good = !(getTeamsForPeer(sender) & getTeamsForPeer(target)).empty(); if (!someone_good && (!isTournament() || !getTournament()->hasProfileThatSeesTeamchats(target))) return false; } diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp index 891c52dbd0b..7fde6f8b040 100644 --- a/src/utils/tournament.cpp +++ b/src/utils/tournament.cpp @@ -498,7 +498,7 @@ bool Tournament::hasProfileThatSeesTeamchats(std::shared_ptr peer) cons } // hasProfileThatSeesTeamchats //----------------------------------------------------------------------------- -bool Tournament::hasProfileFromTeam(std::shared_ptr peer, KartTeam target_team) const +bool Tournament::hasProfileFromTeam(std::shared_ptr peer, KartTeam target_team) { for (auto& player : peer->getPlayerProfiles()) { diff --git a/src/utils/tournament.hpp b/src/utils/tournament.hpp index 035e1c70cd3..8479d5f1f4f 100644 --- a/src/utils/tournament.hpp +++ b/src/utils/tournament.hpp @@ -92,7 +92,10 @@ class Tournament: public LobbyContextComponent std::shared_ptr target) const; bool hasProfileThatSeesTeamchats(std::shared_ptr peer) const; - bool hasProfileFromTeam(std::shared_ptr peer, KartTeam target_team) const; + + // Technically this should be either in STKPeer or in TeamManager, + // quick fix is to just make it static + static bool hasProfileFromTeam(std::shared_ptr peer, KartTeam target_team); private: From f667fdd934dbed79a31a1608f500be109276fac8 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 24 Mar 2025 16:17:41 +0800 Subject: [PATCH 615/830] Proper fix for lighting according to d339d9a --- src/graphics/irr_driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 214a3cb755d..6302985ae19 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -1848,7 +1848,7 @@ void IrrDriver::setAmbientLight(const video::SColorf &light, bool force_SH_compu { #ifndef SERVER_ONLY video::SColorf color = light; - if (CVS->isGLSL()) + if (m_video_driver->getDriverType() != EDT_VULKAN) { color.r = powf(color.r, 1.0f / 2.2f); color.g = powf(color.g, 1.0f / 2.2f); From 1b663ae960dab5c6cae21bf5aab6f0977107ab1c Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Tue, 25 Mar 2025 00:58:27 +0800 Subject: [PATCH 616/830] Move srgb255ToLinear to GE --- lib/graphics_engine/include/ge_main.hpp | 29 +++++++++++++++++++++++ src/graphics/cpu_particle_manager.cpp | 6 ++--- src/graphics/material.cpp | 7 +++--- src/graphics/skid_marks.cpp | 8 +++---- src/graphics/sp/sp_base.hpp | 31 ------------------------- src/graphics/sp/sp_mesh_buffer.cpp | 6 ++--- src/graphics/sp/sp_texture.cpp | 7 +++--- src/graphics/stk_text_billboard.cpp | 4 ++-- src/items/rubber_band.cpp | 9 ++++--- 9 files changed, 54 insertions(+), 53 deletions(-) diff --git a/lib/graphics_engine/include/ge_main.hpp b/lib/graphics_engine/include/ge_main.hpp index 656963c99d9..4e632e15f50 100644 --- a/lib/graphics_engine/include/ge_main.hpp +++ b/lib/graphics_engine/include/ge_main.hpp @@ -57,6 +57,35 @@ inline int get4x4CompressedTextureSize(int width, int height) return blockcount * blocksize; } irr::scene::IAnimatedMesh* convertIrrlichtMeshToSPM(irr::scene::IMesh* mesh); +inline uint8_t srgb255ToLinear(unsigned color_srgb_255) +{ + static unsigned srgb_linear_map[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, + 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, + 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, + 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, + 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22, 22, + 23, 23, 24, 24, 25, 26, 26, 27, 27, 28, 29, 29, + 30, 31, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38, + 38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 47, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, + 85, 87, 88, 89, 90, 92, 93, 94, 95, 97, 98, 99, + 101, 102, 103, 105, 106, 107, 109, 110, 112, 113, 114, 116, + 117, 119, 120, 122, 123, 125, 126, 128, 129, 131, 132, 134, + 135, 137, 139, 140, 142, 144, 145, 147, 148, 150, 152, 153, + 155, 157, 159, 160, 162, 164, 166, 167, 169, 171, 173, 175, + 176, 178, 180, 182, 184, 186, 188, 190, 192, 193, 195, 197, + 199, 201, 203, 205, 207, 209, 211, 213, 215, 218, 220, 222, + 224, 226, 228, 230, 232, 235, 237, 239, 241, 243, 245, 248, + 250, 252, 255 + }; + return uint8_t(srgb_linear_map[color_srgb_255]); +} } #endif diff --git a/src/graphics/cpu_particle_manager.cpp b/src/graphics/cpu_particle_manager.cpp index 765c9a8d856..b33dff31ead 100644 --- a/src/graphics/cpu_particle_manager.cpp +++ b/src/graphics/cpu_particle_manager.cpp @@ -17,7 +17,6 @@ #include "graphics/cpu_particle_manager.hpp" -#include "graphics/sp/sp_base.hpp" #include "graphics/stk_particle.hpp" #include "graphics/irr_driver.hpp" #include "graphics/material.hpp" @@ -27,6 +26,7 @@ #include #ifndef SERVER_ONLY +#include #include #include #include @@ -120,7 +120,7 @@ CPUParticle::CPUParticle(const core::vector3df& position, int b = core::clamp((int)(ret.Z * 255.0f), 0, 255); if (CVS->isDeferredEnabled() && CVS->isGLSL()) { - using namespace SP; + using namespace GE; r = srgb255ToLinear(r); g = srgb255ToLinear(g); b = srgb255ToLinear(b); @@ -146,7 +146,7 @@ CPUParticle::CPUParticle(scene::IBillboardSceneNode* node) node->getColor(m_color_lifetime, unused_bottom); if (CVS->isDeferredEnabled() && CVS->isGLSL()) { - using namespace SP; + using namespace GE; m_color_lifetime.setRed(srgb255ToLinear(m_color_lifetime.getRed())); m_color_lifetime.setGreen(srgb255ToLinear(m_color_lifetime.getGreen())); m_color_lifetime.setBlue(srgb255ToLinear(m_color_lifetime.getBlue())); diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index e1ec4c5ee8a..507ddf39bb9 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -31,7 +31,6 @@ #include "graphics/central_settings.hpp" #include "graphics/irr_driver.hpp" #include "graphics/particle_kind_manager.hpp" -#include "graphics/sp/sp_base.hpp" #include "graphics/stk_tex_manager.hpp" #include "io/file_manager.hpp" #include "io/xml_node.hpp" @@ -413,9 +412,9 @@ video::ITexture* Material::getTexture(bool srgb, bool premul_alpha) for (unsigned int i = 0; i < img->getDimension().Width * img->getDimension().Height; i++) { - data[i * 4] = SP::srgb255ToLinear(data[i * 4]); - data[i * 4 + 1] = SP::srgb255ToLinear(data[i * 4 + 1]); - data[i * 4 + 2] = SP::srgb255ToLinear(data[i * 4 + 2]); + data[i * 4] = GE::srgb255ToLinear(data[i * 4]); + data[i * 4 + 1] = GE::srgb255ToLinear(data[i * 4 + 1]); + data[i * 4 + 2] = GE::srgb255ToLinear(data[i * 4 + 2]); } img->unlock(); }; diff --git a/src/graphics/skid_marks.cpp b/src/graphics/skid_marks.cpp index f7d45d66964..2a4848703d5 100644 --- a/src/graphics/skid_marks.cpp +++ b/src/graphics/skid_marks.cpp @@ -37,7 +37,7 @@ #include "mini_glm.hpp" #ifndef SERVER_ONLY - +#include #include #include #include @@ -276,9 +276,9 @@ SkidMarks::SkidMarkQuads::SkidMarkQuads(const Vec3 &left, if (CVS->isDeferredEnabled()) { - m_start_color.setRed(SP::srgb255ToLinear(m_start_color.getRed())); - m_start_color.setGreen(SP::srgb255ToLinear(m_start_color.getGreen())); - m_start_color.setBlue(SP::srgb255ToLinear(m_start_color.getBlue())); + m_start_color.setRed(GE::srgb255ToLinear(m_start_color.getRed())); + m_start_color.setGreen(GE::srgb255ToLinear(m_start_color.getGreen())); + m_start_color.setBlue(GE::srgb255ToLinear(m_start_color.getBlue())); } add(left, right, normal, 0.0f); diff --git a/src/graphics/sp/sp_base.hpp b/src/graphics/sp/sp_base.hpp index a44a499f94f..56e8ad92e59 100644 --- a/src/graphics/sp/sp_base.hpp +++ b/src/graphics/sp/sp_base.hpp @@ -166,37 +166,6 @@ inline uint8_t srgbToLinear(float color_srgb) } return uint8_t(irr::core::clamp(ret, 0, 255)); } -// ---------------------------------------------------------------------------- -inline uint8_t srgb255ToLinear(unsigned color_srgb_255) -{ - static unsigned srgb_linear_map[256] = - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, - 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, - 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, - 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, - 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, - 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22, 22, - 23, 23, 24, 24, 25, 26, 26, 27, 27, 28, 29, 29, - 30, 31, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38, - 38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 47, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 55, 56, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, - 85, 87, 88, 89, 90, 92, 93, 94, 95, 97, 98, 99, - 101, 102, 103, 105, 106, 107, 109, 110, 112, 113, 114, 116, - 117, 119, 120, 122, 123, 125, 126, 128, 129, 131, 132, 134, - 135, 137, 139, 140, 142, 144, 145, 147, 148, 150, 152, 153, - 155, 157, 159, 160, 162, 164, 166, 167, 169, 171, 173, 175, - 176, 178, 180, 182, 184, 186, 188, 190, 192, 193, 195, 197, - 199, 201, 203, 205, 207, 209, 211, 213, 215, 218, 220, 222, - 224, 226, 228, 230, 232, 235, 237, 239, 241, 243, 245, 248, - 250, 252, 255 - }; - return uint8_t(srgb_linear_map[color_srgb_255]); -} - // ---------------------------------------------------------------------------- inline uint8_t linearToSrgb(float color_linear) { diff --git a/src/graphics/sp/sp_mesh_buffer.cpp b/src/graphics/sp/sp_mesh_buffer.cpp index 1bcd811ed60..56d10d1c988 100644 --- a/src/graphics/sp/sp_mesh_buffer.cpp +++ b/src/graphics/sp/sp_mesh_buffer.cpp @@ -174,9 +174,9 @@ void SPMeshBuffer::uploadGLMesh() video::SColor vc = m_vertices[i].m_color; if (CVS->isDeferredEnabled()) { - vc.setRed(srgb255ToLinear(vc.getRed())); - vc.setGreen(srgb255ToLinear(vc.getGreen())); - vc.setBlue(srgb255ToLinear(vc.getBlue())); + vc.setRed(GE::srgb255ToLinear(vc.getRed())); + vc.setGreen(GE::srgb255ToLinear(vc.getGreen())); + vc.setBlue(GE::srgb255ToLinear(vc.getBlue())); } memcpy(ptr + v_size + offset, &vc, 4); offset += 4; diff --git a/src/graphics/sp/sp_texture.cpp b/src/graphics/sp/sp_texture.cpp index bf612747d8f..98c3f6af755 100644 --- a/src/graphics/sp/sp_texture.cpp +++ b/src/graphics/sp/sp_texture.cpp @@ -35,6 +35,7 @@ #include #if !defined(SERVER_ONLY) +#include #include static_assert(squish::kColourClusterFit == (1 << 5), "Wrong header"); static_assert(squish::kColourRangeFit == (1 << 6), "Wrong header"); @@ -221,9 +222,9 @@ std::shared_ptr SPTexture::getTextureImage() const if (m_undo_srgb && (!use_tex_compress || force_undo_srgb)) { - data[i * 4] = srgb255ToLinear(data[i * 4]); - data[i * 4 + 1] = srgb255ToLinear(data[i * 4 + 1]); - data[i * 4 + 2] = srgb255ToLinear(data[i * 4 + 2]); + data[i * 4] = GE::srgb255ToLinear(data[i * 4]); + data[i * 4 + 1] = GE::srgb255ToLinear(data[i * 4 + 1]); + data[i * 4 + 2] = GE::srgb255ToLinear(data[i * 4 + 2]); } } #endif diff --git a/src/graphics/stk_text_billboard.cpp b/src/graphics/stk_text_billboard.cpp index 2d8fde6b3e4..04d31ab50f7 100644 --- a/src/graphics/stk_text_billboard.cpp +++ b/src/graphics/stk_text_billboard.cpp @@ -18,11 +18,11 @@ #ifndef SERVER_ONLY #include "graphics/stk_text_billboard.hpp" -#include "graphics/sp/sp_base.hpp" #include "graphics/central_settings.hpp" #include "graphics/irr_driver.hpp" #include "graphics/graphics_restrictions.hpp" +#include #include #include #include @@ -44,7 +44,7 @@ STKTextBillboard::STKTextBillboard(const video::SColor& color_top, : ISceneNode(parent, mgr, id, position, core::vector3df(0.0f, 0.0f, 0.0f), scale) { - using namespace SP; + using namespace GE; m_color_top = color_top; if (CVS->isDeferredEnabled() && CVS->isGLSL()) { diff --git a/src/items/rubber_band.cpp b/src/items/rubber_band.cpp index 3e137c7361f..3c13f17df67 100644 --- a/src/items/rubber_band.cpp +++ b/src/items/rubber_band.cpp @@ -34,8 +34,11 @@ #include "race/race_manager.hpp" #include "utils/string_utils.hpp" +#ifndef SERVER_ONLY #include +#include #include +#endif #include #include #include @@ -64,9 +67,9 @@ RubberBand::RubberBand(Plunger *plunger, AbstractKart *kart) { if (CVS->isDeferredEnabled()) { - color.setRed(SP::srgb255ToLinear(color.getRed())); - color.setGreen(SP::srgb255ToLinear(color.getGreen())); - color.setBlue(SP::srgb255ToLinear(color.getBlue())); + color.setRed(GE::srgb255ToLinear(color.getRed())); + color.setGreen(GE::srgb255ToLinear(color.getGreen())); + color.setBlue(GE::srgb255ToLinear(color.getBlue())); } m_dy_dc = std::make_shared (scene::EPT_TRIANGLE_STRIP, SP::SPShaderManager::get()->getSPShader From b4849caf69c9b336a974866246a72aa540246f04 Mon Sep 17 00:00:00 2001 From: Deve Date: Mon, 24 Mar 2025 22:41:15 +0100 Subject: [PATCH 617/830] Use 100% scale on good enough devices --- src/main_android.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main_android.cpp b/src/main_android.cpp index 517d161d79f..7f378c50295 100644 --- a/src/main_android.cpp +++ b/src/main_android.cpp @@ -23,6 +23,7 @@ #include "utils/string_utils.hpp" #ifdef ANDROID +#include "SDL_cpuinfo.h" #include "SDL_stdinc.h" #include "SDL_system.h" #include @@ -200,14 +201,21 @@ void override_default_params_for_mobile() break; } - // Update rtts scale based on display DPI - if (ddpi < 1) + int total_memory = ceilf((float)(SDL_GetSystemRAM()) / 1024); + + if ((total_memory >= 8) && (SDL_GetAndroidSDKVersion() >= 31)) + { + // Use 100% scale on devices with 8GB RAM and Android >= 12 + UserConfigParams::m_scale_rtts_factor = 1.0f; + } + else if (ddpi < 1) { Log::warn("MainAndroid", "Failed to get display DPI."); UserConfigParams::m_scale_rtts_factor = 0.7f; } else { + // Update rtts scale based on display DPI if (ddpi > 400) UserConfigParams::m_scale_rtts_factor = 0.6f; else if (ddpi > 300) @@ -220,9 +228,10 @@ void override_default_params_for_mobile() UserConfigParams::m_scale_rtts_factor = 0.8f; Log::info("MainAndroid", "Display DPI: %i", ddpi); - Log::info("MainAndroid", "Render scale: %f", - (float)UserConfigParams::m_scale_rtts_factor); } + + Log::info("MainAndroid", "Render scale: %f", + (float)UserConfigParams::m_scale_rtts_factor); #endif // Enable screen keyboard From 398805ae1d622ff6fbeeee8aa464948ac463c692 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Tue, 25 Mar 2025 13:24:22 +0800 Subject: [PATCH 618/830] Use srgb255ToLinear for GE PBR if needed --- lib/graphics_engine/include/ge_main.hpp | 11 ++++++++ .../include/ge_vulkan_driver.hpp | 2 +- lib/graphics_engine/src/ge_main.cpp | 17 +++++++++++++ lib/graphics_engine/src/ge_spm_buffer.cpp | 9 ++----- .../src/ge_vulkan_draw_call.cpp | 21 ++++++++++++++-- lib/graphics_engine/src/ge_vulkan_driver.cpp | 25 +++++++++++++++++-- .../src/ge_vulkan_dynamic_spm_buffer.cpp | 11 +++----- .../src/ge_vulkan_mesh_cache.cpp | 11 ++------ .../dialogs/custom_video_settings.cpp | 6 ++--- src/utils/debug.cpp | 21 +++++++++++++++- 10 files changed, 101 insertions(+), 33 deletions(-) diff --git a/lib/graphics_engine/include/ge_main.hpp b/lib/graphics_engine/include/ge_main.hpp index 4e632e15f50..17d00134b5a 100644 --- a/lib/graphics_engine/include/ge_main.hpp +++ b/lib/graphics_engine/include/ge_main.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -18,6 +19,7 @@ namespace irr namespace GE { +class GESPMBuffer; class GEVulkanDriver; struct GEConfig { @@ -86,6 +88,15 @@ inline uint8_t srgb255ToLinear(unsigned color_srgb_255) }; return uint8_t(srgb_linear_map[color_srgb_255]); } +inline irr::video::SColor srgb255ToLinearFromSColor(irr::video::SColor scolor_srgb) +{ + irr::video::SColor out = scolor_srgb; + out.setRed(srgb255ToLinear(scolor_srgb.getRed())); + out.setGreen(srgb255ToLinear(scolor_srgb.getGreen())); + out.setBlue(srgb255ToLinear(scolor_srgb.getBlue())); + return out; +} +void copyToMappedBuffer(uint32_t* mapped, GESPMBuffer* spmb, size_t offset = 0); } #endif diff --git a/lib/graphics_engine/include/ge_vulkan_driver.hpp b/lib/graphics_engine/include/ge_vulkan_driver.hpp index ca618da1d65..cdc87eb31b1 100644 --- a/lib/graphics_engine/include/ge_vulkan_driver.hpp +++ b/lib/graphics_engine/include/ge_vulkan_driver.hpp @@ -341,7 +341,7 @@ namespace GE destroySwapChainRelated(false/*handle_surface*/); createSwapChainRelated(false/*handle_surface*/); } - void updateDriver(bool reload_shaders = false); + void updateDriver(bool pbr_changed = false); uint32_t getGraphicsFamily() const { return m_graphics_family; } unsigned getGraphicsQueueCount() const { return m_graphics_queue_count; } diff --git a/lib/graphics_engine/src/ge_main.cpp b/lib/graphics_engine/src/ge_main.cpp index 04b02d9b899..ab042214f36 100644 --- a/lib/graphics_engine/src/ge_main.cpp +++ b/lib/graphics_engine/src/ge_main.cpp @@ -173,4 +173,21 @@ irr::scene::IAnimatedMesh* convertIrrlichtMeshToSPM(irr::scene::IMesh* mesh) return spm; } +void copyToMappedBuffer(uint32_t* mapped, GESPMBuffer* spmb, size_t offset) +{ + for (unsigned i = offset; i < spmb->getVertexCount(); i++) + { + auto& vv = spmb->getVerticesVector(); + memcpy(mapped, &vv[i], 4 * sizeof(uint32_t)); + mapped += 4; + if (getGEConfig()->m_pbr) + *mapped = srgb255ToLinearFromSColor(vv[i].m_color).color; + else + memcpy(mapped, &vv[i].m_color, sizeof(video::SColor)); + mapped += 1; + memcpy(mapped, vv[i].m_all_uvs, 3 * sizeof(uint32_t)); + mapped += 3; + } +} + } diff --git a/lib/graphics_engine/src/ge_spm_buffer.cpp b/lib/graphics_engine/src/ge_spm_buffer.cpp index 1179a732566..20b8f1757f3 100644 --- a/lib/graphics_engine/src/ge_spm_buffer.cpp +++ b/lib/graphics_engine/src/ge_spm_buffer.cpp @@ -55,13 +55,8 @@ void GESPMBuffer::createVertexIndexBuffer() throw std::runtime_error("createVertexIndexBuffer vmaMapMemory failed"); size_t real_size = getVertexCount() * total_pitch; - uint8_t* loc = mapped; - for (unsigned i = 0; i < real_size; i += total_pitch) - { - uint8_t* vertices = ((uint8_t*)getVertices()) + i; - memcpy(loc, vertices, static_pitch); - loc += static_pitch; - } + copyToMappedBuffer((uint32_t*)mapped, this); + uint8_t* loc = mapped + getVertexCount() * static_pitch; memcpy(loc, m_indices.data(), m_indices.size() * sizeof(uint16_t)); if (m_has_skinning) diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index c78d02d15cd..518b05057b3 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -72,9 +72,21 @@ void ObjectData::init(irr::scene::ISceneNode* node, int material_id, else m_hue_change = 0.0f; if (ri) - m_custom_vertex_color = ri->getVertexColor(); + { + if (getGEConfig()->m_pbr) + { + m_custom_vertex_color = + srgb255ToLinearFromSColor(ri->getVertexColor()).color; + } + else + { + m_custom_vertex_color = ri->getVertexColor(); + } + } else + { m_custom_vertex_color = irr::video::SColor((uint32_t)-1); + } } // init // ============================================================================ @@ -100,6 +112,8 @@ void ObjectData::init(irr::scene::IBillboardSceneNode* node, int material_id, output.setRed((top.getRed() + bottom.getRed()) / 2); output.setGreen((top.getGreen() + bottom.getGreen()) / 2); output.setBlue((top.getBlue() + bottom.getBlue()) / 2); + if (getGEConfig()->m_pbr) + output = srgb255ToLinearFromSColor(output).color; m_custom_vertex_color = output; } // init @@ -176,7 +190,10 @@ void ObjectData::init(const irr::scene::SParticle& particle, int material_id, m_texture_trans[0] = 0.0f; m_texture_trans[1] = 0.0f; m_hue_change = 0.0f; - m_custom_vertex_color = particle.color; + if (getGEConfig()->m_pbr) + m_custom_vertex_color = srgb255ToLinearFromSColor(particle.color).color; + else + m_custom_vertex_color = particle.color; } // init // ---------------------------------------------------------------------------- diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index 6ae8f7202d8..daecd0a7565 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -2505,13 +2505,13 @@ bool GEVulkanDriver::setRenderTarget(video::ITexture* texture, } // setRenderTarget // ---------------------------------------------------------------------------- -void GEVulkanDriver::updateDriver(bool reload_shaders) +void GEVulkanDriver::updateDriver(bool pbr_changed) { waitIdle(); setDisableWaitIdle(true); clearDrawCallsCache(); destroySwapChainRelated(false/*handle_surface*/); - if (reload_shaders) + if (pbr_changed) { GEVulkanShaderManager::destroy(); GEVulkanShaderManager::init(this); @@ -2520,6 +2520,27 @@ void GEVulkanDriver::updateDriver(bool reload_shaders) GEVulkanShaderManager::getSamplerSize(), GEVulkanShaderManager::getMeshTextureLayer(), GEVulkanFeatures::supportsBindMeshTexturesAtOnce()); + GEVulkanMeshCache* mc = getVulkanMeshCache(); + if (!GEVulkanFeatures::supportsBaseVertexRendering()) + { + for (unsigned i = 0; i < mc->getMeshCount(); i++) + { + scene::IAnimatedMesh* mesh = mc->getMeshByIndex(i); + if (mesh->getMeshType() != scene::EAMT_SPM) + continue; + for (unsigned j = 0; j < mesh->getMeshBufferCount(); j++) + { + GESPMBuffer* mb = static_cast( + mesh->getMeshBuffer(j)); + mb->destroyVertexIndexBuffer(); + mb->createVertexIndexBuffer(); + } + } + } + else + mc->meshCacheChanged(); + for (GEVulkanDynamicSPMBuffer* buffer : m_dynamic_spm_buffers) + buffer->setDirtyOffset(0, irr::scene::EBT_VERTEX); } createSwapChainRelated(false/*handle_surface*/); for (auto& dc : static_cast( diff --git a/lib/graphics_engine/src/ge_vulkan_dynamic_spm_buffer.cpp b/lib/graphics_engine/src/ge_vulkan_dynamic_spm_buffer.cpp index 829727eeb38..635865cd601 100644 --- a/lib/graphics_engine/src/ge_vulkan_dynamic_spm_buffer.cpp +++ b/lib/graphics_engine/src/ge_vulkan_dynamic_spm_buffer.cpp @@ -49,14 +49,9 @@ void GEVulkanDynamicSPMBuffer::updateVertexIndexBuffer(int buffer_index) uint8_t* mapped_addr = (uint8_t*)m_vertex_buffer->getMappedAddr() [buffer_index]; - unsigned voffset = m_vertex_update_offsets[buffer_index] * stride; - mapped_addr += voffset; - for (unsigned i = m_vertex_update_offsets[buffer_index]; - i < m_vertices.size(); i++) - { - memcpy(mapped_addr, &m_vertices[i], stride); - mapped_addr += stride; - } + mapped_addr += m_vertex_update_offsets[buffer_index] * stride; + copyToMappedBuffer((uint32_t*)mapped_addr, this, + m_vertex_update_offsets[buffer_index]); m_vertex_update_offsets[buffer_index] = m_vertices.size(); double index_size = (double)(m_indices.size() * sizeof(uint16_t)); diff --git a/lib/graphics_engine/src/ge_vulkan_mesh_cache.cpp b/lib/graphics_engine/src/ge_vulkan_mesh_cache.cpp index a821ee4a962..341584f3417 100644 --- a/lib/graphics_engine/src/ge_vulkan_mesh_cache.cpp +++ b/lib/graphics_engine/src/ge_vulkan_mesh_cache.cpp @@ -98,16 +98,9 @@ void GEVulkanMeshCache::updateCache() size_t offset = 0; for (GESPMBuffer* spm_buffer : buffers) { - size_t real_size = spm_buffer->getVertexCount() * total_pitch; - size_t copy_size = spm_buffer->getVertexCount() * static_pitch; - uint8_t* loc = mapped + offset; - for (unsigned i = 0; i < real_size; i += total_pitch) - { - uint8_t* vertices = ((uint8_t*)spm_buffer->getVertices()) + i; - memcpy(loc, vertices, static_pitch); - loc += static_pitch; - } + copyToMappedBuffer((uint32_t*)(mapped + offset), spm_buffer); spm_buffer->setVBOOffset(offset / static_pitch); + size_t copy_size = spm_buffer->getVertexCount() * static_pitch; offset += copy_size; } m_ibo_offset = offset; diff --git a/src/states_screens/dialogs/custom_video_settings.cpp b/src/states_screens/dialogs/custom_video_settings.cpp index 0ae695fe49c..5fb6e22ff19 100644 --- a/src/states_screens/dialogs/custom_video_settings.cpp +++ b/src/states_screens/dialogs/custom_video_settings.cpp @@ -144,10 +144,10 @@ GUIEngine::EventPropagation CustomVideoSettingsDialog::processEvent(const std::s if (selection == "apply") { bool advanced_pipeline = getWidget("dynamiclight")->getState(); - bool update_needed = false; + bool pbr_changed = false; if (UserConfigParams::m_dynamic_lights != advanced_pipeline) { - update_needed = true; + pbr_changed = true; GE::getGEConfig()->m_pbr = advanced_pipeline; } UserConfigParams::m_dynamic_lights = advanced_pipeline; @@ -219,7 +219,7 @@ GUIEngine::EventPropagation CustomVideoSettingsDialog::processEvent(const std::s OptionsScreenVideo::getInstance()->updateGfxSlider(); OptionsScreenVideo::getInstance()->updateBlurSlider(); #ifndef SERVER_ONLY - if (update_needed && GE::getDriver()->getDriverType() == video::EDT_VULKAN) + if (pbr_changed && GE::getDriver()->getDriverType() == video::EDT_VULKAN) GE::getVKDriver()->updateDriver(true); #endif OptionsScreenVideo::setImageQuality(quality); diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index de40959984b..da18f43c5c3 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -72,6 +72,10 @@ #include #include +#ifndef SERVER_ONLY +#include +#include +#endif using namespace irr; using namespace gui; @@ -100,6 +104,7 @@ enum DebugMenuCommand DEBUG_PROFILER_WRITE_REPORT, DEBUG_FONT_DUMP_GLYPH_PAGE, DEBUG_FONT_RELOAD, + DEBUG_GE_PBR, DEBUG_SP_RESET, DEBUG_SP_TOGGLE_CULLING, DEBUG_SP_WN_VIZ, @@ -372,6 +377,19 @@ bool handleContextMenuAction(s32 cmd_id) physics->setDebugMode(IrrDebugDrawer::DM_NO_KARTS_GRAPHICS); break; } + case DEBUG_GE_PBR: +#ifndef SERVER_ONLY + { + GE::GEVulkanDriver* vk = GE::getVKDriver(); + if (vk) + { + UserConfigParams::m_dynamic_lights = !UserConfigParams::m_dynamic_lights; + GE::getGEConfig()->m_pbr = UserConfigParams::m_dynamic_lights; + vk->updateDriver(true); + } + break; + } +#endif case DEBUG_SP_RESET: irr_driver->resetDebugModes(); if (physics) @@ -1277,8 +1295,9 @@ bool onEvent(const SEvent &event) sub->addItem(L"Clear nitro (Delete)", DEBUG_NITRO_CLEAR ); sub->addItem(L"Clear attachment (Delete)", DEBUG_ATTACHMENT_NOTHING); - mnu->addItem(L"SP debug >",-1,true, true); + mnu->addItem(L"SP / GE debug >",-1,true, true); sub = mnu->getSubMenu(6); + sub->addItem(L"Toggle GE PBR", DEBUG_GE_PBR); sub->addItem(L"Reset SP debug", DEBUG_SP_RESET); sub->addItem(L"Toggle culling", DEBUG_SP_TOGGLE_CULLING); sub->addItem(L"Draw world normal in texture", DEBUG_SP_WN_VIZ); From 2d3a0fbbb5d3ff78de1b603944f57c93e620bde0 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Tue, 25 Mar 2025 14:23:32 +0800 Subject: [PATCH 619/830] Don't add skid mark quads too frequently which breaks fade-out effect --- src/graphics/skid_marks.cpp | 12 ++++++++++-- src/graphics/skid_marks.hpp | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/graphics/skid_marks.cpp b/src/graphics/skid_marks.cpp index 2a4848703d5..468b4b01fba 100644 --- a/src/graphics/skid_marks.cpp +++ b/src/graphics/skid_marks.cpp @@ -64,6 +64,7 @@ SkidMarks::SkidMarks(const AbstractKart& kart, float width) : m_kart(kart) m_shader->isSrgbForTextureLayer(0), m_material->getContainerId()); } m_skid_marking = false; + m_dt = 0.0f; } // SkidMark //----------------------------------------------------------------------------- @@ -95,7 +96,14 @@ void SkidMarks::update(float dt, bool force_skid_marks, if (m_kart.isWheeless()) return; - float f = dt / stk_config->m_skid_fadeout_time; + // Don't add skid mark quads too frequently which breaks fade-out effect + const float min_dt = stk_config->ticks2Time(1); + m_dt += dt; + if (m_dt < min_dt) + return; + + float f = m_dt / stk_config->m_skid_fadeout_time; + m_dt = 0.0f; auto it = m_left.begin(); // Don't clean the current skidmarking while (it != m_left.end()) @@ -274,7 +282,7 @@ SkidMarks::SkidMarkQuads::SkidMarkQuads(const Vec3 &left, video::SColor(255, SkidMarks::m_start_grey, SkidMarks::m_start_grey, SkidMarks::m_start_grey)); - if (CVS->isDeferredEnabled()) + if (CVS->isGLSL() && CVS->isDeferredEnabled()) { m_start_color.setRed(GE::srgb255ToLinear(m_start_color.getRed())); m_start_color.setGreen(GE::srgb255ToLinear(m_start_color.getGreen())); diff --git a/src/graphics/skid_marks.hpp b/src/graphics/skid_marks.hpp index 7ed20560672..af1f89bfce7 100644 --- a/src/graphics/skid_marks.hpp +++ b/src/graphics/skid_marks.hpp @@ -74,6 +74,7 @@ class SkidMarks : public NoCopy /** Shader(alphablend) to use for the skid marks. */ std::shared_ptr m_shader; + float m_dt; // ------------------------------------------------------------------------ class SkidMarkQuads : public NoCopy { From b07e338a32b862ae97c1e5f11fd1f34e8b14bd4f Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Wed, 26 Mar 2025 01:07:14 +0800 Subject: [PATCH 620/830] Properly reset vsync setting (default on) for everyone --- lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp | 4 ++-- src/config/user_config.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp b/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp index 0079ea54cd5..406884d06cd 100644 --- a/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp +++ b/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp @@ -396,8 +396,8 @@ extern "C" void update_fullscreen_desktop(int val) // Used in OptionsScreenVideo for live updating vertical sync config extern "C" void update_swap_interval(int swap_interval) { -#ifndef MOBILE_STK - // Mobile always use vertical sync +#ifndef IOS_STK + // iOS always use vertical sync if (swap_interval > 1) swap_interval = 1; diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index 509f4def317..36dd878d6ed 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -994,7 +994,7 @@ namespace UserConfigParams "Quality of anisotropic filtering (usual values include 2-4-8-16; 0 to disable)") ); PARAM_PREFIX IntUserConfigParam m_swap_interval - PARAM_DEFAULT( IntUserConfigParam(0, "swap-interval", + PARAM_DEFAULT( IntUserConfigParam(1, "swap-interval-vsync", &m_graphics_quality, "Swap interval for vsync: 0 = disabled, 1 = full") ); PARAM_PREFIX BoolUserConfigParam m_motionblur From 8749429fdea2c9999fa9bf7cb514d1ed77e67896 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Wed, 26 Mar 2025 10:15:59 +0800 Subject: [PATCH 621/830] Move vertex and index buffer updates into separate conditions --- .../src/ge_vulkan_dynamic_spm_buffer.cpp | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/lib/graphics_engine/src/ge_vulkan_dynamic_spm_buffer.cpp b/lib/graphics_engine/src/ge_vulkan_dynamic_spm_buffer.cpp index 635865cd601..360d3387aad 100644 --- a/lib/graphics_engine/src/ge_vulkan_dynamic_spm_buffer.cpp +++ b/lib/graphics_engine/src/ge_vulkan_dynamic_spm_buffer.cpp @@ -36,40 +36,42 @@ GEVulkanDynamicSPMBuffer::~GEVulkanDynamicSPMBuffer() // ---------------------------------------------------------------------------- void GEVulkanDynamicSPMBuffer::updateVertexIndexBuffer(int buffer_index) { - if (m_vertex_update_offsets[buffer_index] == m_vertices.size() && - m_index_update_offsets[buffer_index] == m_indices.size()) - return; - const size_t stride = sizeof(irr::video::S3DVertexSkinnedMesh) - 16; - double vertex_size = (double)(m_vertices.size() * stride); - double base = std::log2(vertex_size); - unsigned frame_count = GEVulkanDriver::getMaxFrameInFlight() + 1; - if (m_vertex_buffer->resizeIfNeeded(2 << (unsigned)base)) - std::fill_n(m_vertex_update_offsets, frame_count, 0); - - uint8_t* mapped_addr = (uint8_t*)m_vertex_buffer->getMappedAddr() - [buffer_index]; - mapped_addr += m_vertex_update_offsets[buffer_index] * stride; - copyToMappedBuffer((uint32_t*)mapped_addr, this, - m_vertex_update_offsets[buffer_index]); - m_vertex_update_offsets[buffer_index] = m_vertices.size(); + const unsigned frame_count = GEVulkanDriver::getMaxFrameInFlight() + 1; + if (m_vertex_update_offsets[buffer_index] != m_vertices.size()) + { + double vertex_size = (double)(m_vertices.size() * stride); + double base = std::log2(vertex_size); + if (m_vertex_buffer->resizeIfNeeded(2 << (unsigned)base)) + std::fill_n(m_vertex_update_offsets, frame_count, 0); - double index_size = (double)(m_indices.size() * sizeof(uint16_t)); - base = std::log2(index_size); - if (m_index_buffer->resizeIfNeeded(2 << (unsigned)base)) - std::fill_n(m_index_update_offsets, frame_count, 0); + uint8_t* mapped_addr = (uint8_t*)m_vertex_buffer->getMappedAddr() + [buffer_index]; + mapped_addr += m_vertex_update_offsets[buffer_index] * stride; + copyToMappedBuffer((uint32_t*)mapped_addr, this, + m_vertex_update_offsets[buffer_index]); + m_vertex_update_offsets[buffer_index] = m_vertices.size(); + } - mapped_addr = (uint8_t*)m_index_buffer->getMappedAddr() - [buffer_index]; - unsigned ioffset = m_index_update_offsets[buffer_index] * sizeof(uint16_t); - mapped_addr += ioffset; - for (unsigned i = m_index_update_offsets[buffer_index]; - i < m_indices.size(); i++) + if (m_index_update_offsets[buffer_index] != m_indices.size()) { - memcpy(mapped_addr, &m_indices[i], sizeof(uint16_t)); - mapped_addr += sizeof(uint16_t); + double index_size = (double)(m_indices.size() * sizeof(uint16_t)); + double base = std::log2(index_size); + if (m_index_buffer->resizeIfNeeded(2 << (unsigned)base)) + std::fill_n(m_index_update_offsets, frame_count, 0); + + uint8_t* mapped_addr = (uint8_t*)m_index_buffer->getMappedAddr() + [buffer_index]; + unsigned ioffset = m_index_update_offsets[buffer_index] * sizeof(uint16_t); + mapped_addr += ioffset; + for (unsigned i = m_index_update_offsets[buffer_index]; + i < m_indices.size(); i++) + { + memcpy(mapped_addr, &m_indices[i], sizeof(uint16_t)); + mapped_addr += sizeof(uint16_t); + } + m_index_update_offsets[buffer_index] = m_indices.size(); } - m_index_update_offsets[buffer_index] = m_indices.size(); } // updateVertexIndexBuffer // ---------------------------------------------------------------------------- From ac2ca194ada6b41afb70fbee7fbed52b95b0d3da Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Wed, 26 Mar 2025 11:36:39 +0800 Subject: [PATCH 622/830] Fix crash when re-entering options screen --- src/guiengine/widgets/spinner_widget.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/guiengine/widgets/spinner_widget.hpp b/src/guiengine/widgets/spinner_widget.hpp index 6536e6b9443..7f3b4e79700 100644 --- a/src/guiengine/widgets/spinner_widget.hpp +++ b/src/guiengine/widgets/spinner_widget.hpp @@ -300,6 +300,11 @@ namespace GUIEngine { m_value_updated_callback = callback; } + virtual void elementRemoved() + { + m_incorrect = false; + m_red_mark_widget = NULL; + } }; From 5e4809c9ebd77e05ba19d696108b5653a1af89d2 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 27 Mar 2025 03:19:45 +0400 Subject: [PATCH 623/830] Words [skip ci] --- ANTI_TROLL.md | 4 ++-- FORK_CHANGES.md | 38 ++++++++++++++++++++++++++------------ README.md | 4 +++- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/ANTI_TROLL.md b/ANTI_TROLL.md index bc9a67d8aad..45a5b21ccda 100644 --- a/ANTI_TROLL.md +++ b/ANTI_TROLL.md @@ -1,6 +1,6 @@ ## Info on experimental anti-troll system If activated, a timer is kept for all players. System can be activated in xml config or in the lobby with command: -\admin troll [0,1] +/troll [0,1] Timer is increased by the amount of time when * a player drives in the wrong way @@ -19,7 +19,7 @@ Config can be controlled in xml file like this: + /troll [0,1] --> diff --git a/FORK_CHANGES.md b/FORK_CHANGES.md index cc73679df3b..bd47a0030b2 100644 --- a/FORK_CHANGES.md +++ b/FORK_CHANGES.md @@ -1,4 +1,4 @@ -This page lists the major changes of this repository compared to standard STK code, as of April 2024. Most changes (sadly, not all of them) here are implemented as options, that is, you can disable them and return to standard behaviour. +This page lists the major changes of this repository compared to standard STK code, as of March 2025. Most changes (sadly, not all of them) here are implemented as options, that is, you can disable them and return to standard behaviour. You can find more information such as explanations and minor details in [wiki](https://github.com/kimden/stk-code/wiki/). It will be probably filled with even more data in the future. @@ -8,15 +8,15 @@ You can find more information such as explanations and minor details in [wiki](h * Players can pick karts, join or leave * Custom scoring systems * Custom teams (up to 9) -* Standings ingame (short) and in the lobby (longer) +* Standings ingame (short) and in the lobby (longer), including teams * Anti-troll and team hit punishment systems, by Heuchi1 * Allows to shuffle the starting grid every race ## Records, replays and stats -* Game results for racing and battle modes can be saved to the database, together with game settings and kart statistics +* Game results for **all** modes can be saved to the database, together with game settings and kart statistics. * Public or private record tables can be created using that information -* Ghost replays can be recorded on servers if players agree +* Ghost replays can be recorded on servers if set if the config and if players agree * Players who beat server records can be notified (includes separation of times set with different config files) * Maximum replay size is increased @@ -24,7 +24,7 @@ You can find more information such as explanations and minor details in [wiki](h * Private chat with an arbitrary set of players * Teamchat during CTF and soccer which works both ingame and in the lobby -* Messages are never logged, even by the bots (though they pass through the server code) +* Messages are **never** logged, even by the bots (though they pass through the server code) ## Game configuration, available maps and karts, playing restrictions @@ -46,8 +46,8 @@ Command manager is an entity made to manipulate all existing server commands eas * commands with voting * text commands / commands reading external files -* auth commands -* setting permissions for commands without recompiling the code and/or depending on server +* auth commands, which allow to authenticate on other sites using STK accounts +* setting permissions for commands depending on server, without recompiling the code * subcommands and different permissions for them * fixing errors in arguments (usernames, map names) * showing available commands depending on permissions @@ -61,10 +61,10 @@ All the commands and their descriptions are available in `data/commands.xml`. Th * It's possible to disable kicks attempted by the crowned player * If a player kicks another player, the fact of the kick can be stored in the database table with reports * Inactive players can be kicked automatically from the lobby too, not only from the game -* A hammer mode is added: players having a password can get a hammer, then they can change server settings and kick players +* A hammer mode is added: if a player has a password from the config, or if a player is specified in it, they can get a 'hammer' and change server settings and kick players * There are commands to ban (or unban) a player temporary from a single server by username, as opposed to standard bans which are applied to all servers using the same database, and are usually banning by online id or IP address * Players are allowed to report something to server owner without reporting other people -* Starting the game can be allowed or forbidden using a command +* Starting the game can be allowed or forbidden using a command, or before the server start using config ## Game modes and their improvements @@ -75,13 +75,13 @@ These are not implemented as separate modes, but are rather additions to functio Separate changes for modes: -* Soccer games produce a log of all goals / actions that happened (originally made for tournament mode, but can be used without it too), if the score is edited using tournament commands, the game shows it as a message after each goal and at the end +* Soccer games produce a log of all goals / actions that happened (originally made for tournament mode, but can be used without it too), if the score is edited using tournament commands, the game shows it as a message after each goal and at the end. (This is, however, slightly deprecated by the new database features that allow storing all game results.) * FFA and CTF scores are preserved per username during the game, so that leaving the game is not punished ## Other features * You can allow only the crowned player to play (speedrun server), or no one at all (chat server) -* Minor `/spectate` changes (you can invoke it ingame, game doesn't start with everyone spectating) +* Minor `/spectate` changes (you can invoke it ingame, game doesn't start with everyone spectating, you can choose to stay in lobby without watching the game) * For a configurable server, you can specify which exact difficulties and modes are allowed * Players can send a message to the server owner (without reporting anyone else), and the server owner can send one-time messages to specific players * For private servers, players can be whitelisted so that they can enter any password to join @@ -91,4 +91,18 @@ Separate changes for modes: * Server git version and whether it's modified is shown in `/version` * Server console allows sending arbitrary messages to players * Supported player categories aka sets of players (for now only displaying their names, and some minor usage) -* Minor additions in StringUtils used in typo fixing and string parsing \ No newline at end of file +* Minor additions in StringUtils used in typo fixing and string parsing + +## Current and future feature plans + +Since 2025, my approach for developing the code in this repository has changed, as I stopped believing I should do everything in the same way as the developers of the main game, and stopped being afraid of merge conflicts. After all, I even submitted a couple big patches into the official repository that way, and it was fine... + +Currently, the big restructurization of the code is underway, and one of the biggest and most complicated files in STK, `server_lobby.cpp`, got split into several files so that each file contains methods about the area it corresponds to. It allowed to fix a few hidden bugs, and will allow adding features in a simpler way in the future. + +Another big topic is STK network protocol. It is messy and it's spread all over the codebase, while it's often hard to understand what exactly is being sent. That prevents its modification and advanced usage, and it's planned to rework it, so that it at least is understandable (which would also make the other code near the network packets cleaner). + +## Better code + +The aforementioned `server_lobby.cpp` is heavily used in all server-side forks, and no wonder its size can skyrocket in them, as people want to add many commands. Several frequently used forks have 12.5k and 7.3k lines of code in that file, while the official code has 4.8k lines. This repository has even fewer lines there, but more smaller files — for most features, there are simply much better places and ways to use them! + +The code has no proprietary scripts that are hardcoded inside to be unusable by others, no hidden anti-features such as secretly logged private chats, and here we do credit contributors according to what they have done (as in, `git blame` works correctly). Sadly, that's not a frequent offer in the world of STK — but you can make this offer even better by contributing to it! diff --git a/README.md b/README.md index 709132ddb76..1d197d1f7a4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Windows build status](https://github.com/kimden/stk-code/actions/workflows/windows.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/windows.yml) [![Switch build status](https://github.com/kimden/stk-code/actions/workflows/switch.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/switch.yml) -This repository contains a **modified** version of SuperTuxKart (STK), mainly intended for server-side usage. Most important changes are listed [here](/FORK_CHANGES.md). Standard version of STK can be found [here](https://github.com/supertuxkart/stk-code/), and the changes between it and latest commits of this repo can be found [here](https://github.com/supertuxkart/stk-code/compare/master...kimden:stk-code:command-manager-prototype). +This repository contains a **modified** version of SuperTuxKart (STK), mainly intended for server-side usage. Most important changes are listed [here](/FORK_CHANGES.md). Standard version of STK can be found [here](https://github.com/supertuxkart/stk-code/), and the changes between it and latest commits of this repo can be found [here](https://github.com/supertuxkart/stk-code/compare/master...kimden:stk-code:master). ## Important branches @@ -15,6 +15,8 @@ This repository contains a **modified** version of SuperTuxKart (STK), mainly in There are also several less important branches. +[Tyre Mod Edition](https://github.com/Nomagno/stk-code/tree/tyre2X) by Nomagno is also using branches of this repository for both server and client updates. + --- The software is released under the GNU General Public License (GPL) which can be found in the file [`COPYING`](/COPYING) in the same directory as this file. From b1490fbf674ee7e24fa32eb41f1f4403152533e5 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Thu, 27 Mar 2025 11:15:28 +0800 Subject: [PATCH 624/830] Fix more crash --- src/guiengine/widgets/spinner_widget.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/guiengine/widgets/spinner_widget.hpp b/src/guiengine/widgets/spinner_widget.hpp index 7f3b4e79700..2334def3556 100644 --- a/src/guiengine/widgets/spinner_widget.hpp +++ b/src/guiengine/widgets/spinner_widget.hpp @@ -304,6 +304,7 @@ namespace GUIEngine { m_incorrect = false; m_red_mark_widget = NULL; + Widget::elementRemoved(); } }; From bbc836404938380869741b95d316f56894ffea37 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Thu, 27 Mar 2025 12:22:24 +0800 Subject: [PATCH 625/830] Add initSamplers to SP for reloading samplers live --- src/graphics/sp/sp_base.cpp | 19 ++++++++++++++++--- src/graphics/sp/sp_base.hpp | 2 ++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/graphics/sp/sp_base.cpp b/src/graphics/sp/sp_base.cpp index f05fd30cec0..3d1c32b57ac 100644 --- a/src/graphics/sp/sp_base.cpp +++ b/src/graphics/sp/sp_base.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -98,7 +99,7 @@ std::unordered_map g_instances; // ---------------------------------------------------------------------------- -std::array g_samplers; +std::array g_samplers = {{ }}; // ---------------------------------------------------------------------------- // Check sp_shader.cpp for the name std::array sp_prefilled_tex; @@ -472,6 +473,18 @@ void init() glBindBufferBase(GL_UNIFORM_BUFFER, 2, sp_fog_ubo); glBindBuffer(GL_UNIFORM_BUFFER, 0); + initSamplers(); +} // init + +// ---------------------------------------------------------------------------- +void initSamplers() +{ + if (std::all_of(g_samplers.begin(), g_samplers.end() - 1, + [](int value) { return value != 0; })) + { + glDeleteSamplers((unsigned)g_samplers.size() - 1, g_samplers.data()); + g_samplers.fill(0); + } for (unsigned st = ST_NEAREST; st < ST_COUNT; st++) { @@ -605,7 +618,7 @@ void init() break; } } -} // init +} // initSamplers // ---------------------------------------------------------------------------- void destroy() @@ -638,7 +651,7 @@ void destroy() } glDeleteBuffers(1, &sp_fog_ubo); glDeleteSamplers((unsigned)g_samplers.size() - 1, g_samplers.data()); - + g_samplers.fill(0); } // destroy // ---------------------------------------------------------------------------- diff --git a/src/graphics/sp/sp_base.hpp b/src/graphics/sp/sp_base.hpp index 56e8ad92e59..c7d7ee792b0 100644 --- a/src/graphics/sp/sp_base.hpp +++ b/src/graphics/sp/sp_base.hpp @@ -124,6 +124,8 @@ void addObject(SPMeshNode*); // ---------------------------------------------------------------------------- void initSTKRenderer(ShaderBasedRenderer*); // ---------------------------------------------------------------------------- +void initSamplers(); +// ---------------------------------------------------------------------------- void prepareScene(); // ---------------------------------------------------------------------------- void handleDynamicDrawCall(); From 16d6a1821bf71a916bb86efabddc085b0f71ff8a Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Thu, 27 Mar 2025 14:42:01 +0800 Subject: [PATCH 626/830] Make SPTexture reload work with texture compression when max size changed --- src/graphics/sp/sp_texture.cpp | 78 +++++++++++++------------- src/graphics/sp/sp_texture.hpp | 11 ++-- src/graphics/sp/sp_texture_manager.cpp | 16 +++++- 3 files changed, 59 insertions(+), 46 deletions(-) diff --git a/src/graphics/sp/sp_texture.cpp b/src/graphics/sp/sp_texture.cpp index 98c3f6af755..45777e755ae 100644 --- a/src/graphics/sp/sp_texture.cpp +++ b/src/graphics/sp/sp_texture.cpp @@ -59,41 +59,12 @@ namespace SP // ---------------------------------------------------------------------------- SPTexture::SPTexture(const std::string& path, Material* m, bool undo_srgb, const std::string& container_id) - : m_path(path), m_width(0), m_height(0), m_material(m), - m_undo_srgb(undo_srgb) + : m_path(path), m_container_id(container_id), m_width(0), m_height(0), + m_material(m), m_undo_srgb(undo_srgb) { #ifndef SERVER_ONLY glGenTextures(1, &m_texture_name); - createWhite(false/*private_init*/); - - if (!CVS->isTextureCompressionEnabled() || container_id.empty()) - { - return; - } - - std::string cache_subdir = "hd"; - if ((UserConfigParams::m_high_definition_textures & 0x01) == 0x01) - { - cache_subdir = "hd"; - } - else - { - cache_subdir = StringUtils::insertValues("resized_%i", - (int)UserConfigParams::m_max_texture_size); - } - -#ifdef USE_GLES2 - if (m_undo_srgb && !CVS->isEXTTextureCompressionS3TCSRGBUsable()) - { - cache_subdir += "-linear"; - } -#endif - - m_cache_directory = file_manager->getCachedTexturesDir() + - cache_subdir + "/" + container_id; - file_manager->checkAndCreateDirectoryP(m_cache_directory); - #endif } // SPTexture @@ -125,6 +96,36 @@ SPTexture::~SPTexture() #endif } // ~SPTexture +// ---------------------------------------------------------------------------- +std::string SPTexture::getCacheDirectory() +{ + std::string cache_subdir = "hd"; +#ifndef SERVER_ONLY + if (!CVS->isTextureCompressionEnabled() || m_container_id.empty()) + return ""; + + if ((UserConfigParams::m_high_definition_textures & 0x01) == 0x01) + { + cache_subdir = "hd"; + } + else + { + cache_subdir = StringUtils::insertValues("resized_%i", + (int)UserConfigParams::m_max_texture_size); + } + +#ifdef USE_GLES2 + if (m_undo_srgb && !CVS->isEXTTextureCompressionS3TCSRGBUsable()) + { + cache_subdir += "-linear"; + } +#endif + +#endif + return file_manager->getCachedTexturesDir() + + cache_subdir + "/" + m_container_id; +} // getCacheDirectory + // ---------------------------------------------------------------------------- std::shared_ptr SPTexture::getImageFromPath (const std::string& path) const @@ -204,7 +205,7 @@ std::shared_ptr SPTexture::getTextureImage() const image->getDimension().Height; i++) { const bool use_tex_compress = CVS->isTextureCompressionEnabled() && - !m_cache_directory.empty(); + !m_container_id.empty(); #ifndef USE_GLES2 if (use_tex_compress) { @@ -363,16 +364,15 @@ bool SPTexture::saveCompressedTexture(std::shared_ptr texture, // ---------------------------------------------------------------------------- bool SPTexture::useTextureCache(const std::string& full_path, + const std::string& cache_directory, std::string* cache_loc) { #ifndef SERVER_ONLY - if (!CVS->isTextureCompressionEnabled() || m_cache_directory.empty()) - { + if (cache_directory.empty()) return false; - } std::string basename = StringUtils::getBasename(m_path); - *cache_loc = m_cache_directory + "/" + basename + ".sptz"; + *cache_loc = cache_directory + "/" + basename + ".sptz"; if (file_manager->fileExists(*cache_loc) && file_manager->fileIsNewer(*cache_loc, m_path)) @@ -438,11 +438,11 @@ std::shared_ptr SPTexture::getTextureCache(const std::string& p, } // getTextureCache // ---------------------------------------------------------------------------- -bool SPTexture::threadedLoad() +bool SPTexture::threadedLoad(const std::string& cache_directory) { #ifndef SERVER_ONLY std::string cache_loc; - if (useTextureCache(m_path, &cache_loc)) + if (useTextureCache(m_path, cache_directory, &cache_loc)) { std::vector > sizes; std::shared_ptr cache = getTextureCache(cache_loc, @@ -471,7 +471,7 @@ bool SPTexture::threadedLoad() } std::shared_ptr mipmaps; - if (!m_cache_directory.empty() && CVS->isTextureCompressionEnabled() && + if (!cache_directory.empty() && CVS->isTextureCompressionEnabled() && image->getDimension().Width >= 4 && image->getDimension().Height >= 4) { auto r = compressTexture(image); diff --git a/src/graphics/sp/sp_texture.hpp b/src/graphics/sp/sp_texture.hpp index 19a5bc81ceb..b09aded45a7 100644 --- a/src/graphics/sp/sp_texture.hpp +++ b/src/graphics/sp/sp_texture.hpp @@ -50,7 +50,7 @@ class SPTexture : public NoCopy private: std::string m_path; - std::string m_cache_directory; + std::string m_container_id; GLuint m_texture_name = 0; @@ -153,7 +153,9 @@ class SPTexture : public NoCopy std::vector > compressTexture(std::shared_ptr& texture); // ------------------------------------------------------------------------ - bool useTextureCache(const std::string& full_path, std::string* cache_loc); + bool useTextureCache(const std::string& full_path, + const std::string& cache_directory, + std::string* cache_loc); // ------------------------------------------------------------------------ std::shared_ptr getTextureCache(const std::string& path, std::vector >* sizes); @@ -191,8 +193,9 @@ class SPTexture : public NoCopy // ------------------------------------------------------------------------ unsigned getHeight() const { return m_height.load(); } // ------------------------------------------------------------------------ - bool threadedLoad(); - + bool threadedLoad(const std::string& cache_directory); + // ------------------------------------------------------------------------ + std::string getCacheDirectory(); }; diff --git a/src/graphics/sp/sp_texture_manager.cpp b/src/graphics/sp/sp_texture_manager.cpp index 307885f858c..5e1e822fb8c 100644 --- a/src/graphics/sp/sp_texture_manager.cpp +++ b/src/graphics/sp/sp_texture_manager.cpp @@ -147,7 +147,10 @@ std::shared_ptr SPTextureManager::getTexture(const std::string& p, } std::shared_ptr t = std::make_shared(p, m, undo_srgb, cid); - addThreadedFunction(std::bind(&SPTexture::threadedLoad, t)); + std::string cache_directory = t->getCacheDirectory(); + if (!cache_directory.empty()) + file_manager->checkAndCreateDirectoryP(cache_directory); + addThreadedFunction(std::bind(&SPTexture::threadedLoad, t, cache_directory)); m_textures[p] = t; return t; } // getTexture @@ -191,7 +194,11 @@ core::stringw SPTextureManager::reloadTexture(const core::stringw& name) { continue; } - addThreadedFunction(std::bind(&SPTexture::threadedLoad, p.second)); + std::string cache_directory = p.second->getCacheDirectory(); + if (!cache_directory.empty()) + file_manager->checkAndCreateDirectoryP(cache_directory); + addThreadedFunction(std::bind(&SPTexture::threadedLoad, p.second, + cache_directory)); Log::info("SPTextureManager", "%s reloaded", p.second->getPath().c_str()); } @@ -216,8 +223,11 @@ core::stringw SPTextureManager::reloadTexture(const core::stringw& name) std::string tex_name = StringUtils::getBasename(tex_path); if (fname == tex_name || fname == tex_path) { + std::string cache_directory = p.second->getCacheDirectory(); + if (!cache_directory.empty()) + file_manager->checkAndCreateDirectoryP(cache_directory); addThreadedFunction(std::bind(&SPTexture::threadedLoad, - p.second)); + p.second, cache_directory)); result += tex_name.c_str(); result += L" "; break; From ec24238c9bf3df20fbdb1334d49ae74c53857296 Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Thu, 27 Mar 2025 17:01:54 +0800 Subject: [PATCH 627/830] Remove m_max_size in all ge textures --- lib/graphics_engine/include/ge_texture.hpp | 3 +- lib/graphics_engine/src/ge_dx9_texture.cpp | 6 +-- lib/graphics_engine/src/ge_dx9_texture.hpp | 2 +- lib/graphics_engine/src/ge_gl_texture.cpp | 11 +++-- lib/graphics_engine/src/ge_gl_texture.hpp | 2 +- lib/graphics_engine/src/ge_texture.cpp | 6 ++- .../src/ge_vulkan_array_texture.cpp | 11 ++--- .../src/ge_vulkan_array_texture.hpp | 2 +- .../src/ge_vulkan_depth_texture.cpp | 2 +- .../src/ge_vulkan_fbo_texture.cpp | 2 +- lib/graphics_engine/src/ge_vulkan_texture.cpp | 45 ++++++++++--------- lib/graphics_engine/src/ge_vulkan_texture.hpp | 4 +- 12 files changed, 53 insertions(+), 43 deletions(-) diff --git a/lib/graphics_engine/include/ge_texture.hpp b/lib/graphics_engine/include/ge_texture.hpp index 8e19fedfa2f..ae5e8501488 100644 --- a/lib/graphics_engine/include/ge_texture.hpp +++ b/lib/graphics_engine/include/ge_texture.hpp @@ -18,7 +18,8 @@ irr::core::dimension2d getResizingTarget( const irr::core::dimension2d& max_size); irr::video::IImage* getResizedImage(const std::string& path, const irr::core::dimension2d& max_size, - irr::core::dimension2d* orig_size = NULL); + irr::core::dimension2d* orig_size = NULL, + const irr::core::dimension2d* target_size = NULL); irr::video::IImage* getResizedImageFullPath(const irr::io::path& fullpath, const irr::core::dimension2d& max_size, irr::core::dimension2d* orig_size = NULL, diff --git a/lib/graphics_engine/src/ge_dx9_texture.cpp b/lib/graphics_engine/src/ge_dx9_texture.cpp index 9c57ae98de0..23ad70bda3f 100644 --- a/lib/graphics_engine/src/ge_dx9_texture.cpp +++ b/lib/graphics_engine/src/ge_dx9_texture.cpp @@ -16,8 +16,6 @@ GEDX9Texture::GEDX9Texture(const std::string& path, m_device_9(NULL), m_texture_9(NULL), m_texture_size(0), m_disable_reload(false) { - m_max_size = getDriver()->getDriverAttributes() - .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); getDevice9(); reload(); } // GEDX9Texture @@ -108,8 +106,10 @@ void GEDX9Texture::reload() return; } + const core::dimension2du& max_size = getDriver()->getDriverAttributes() + .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); video::IImage* texture_image = getResizedImage(NamedPath.getPtr(), - m_max_size, &m_orig_size); + max_size, &m_orig_size); if (texture_image == NULL) { LoadingFailed = true; diff --git a/lib/graphics_engine/src/ge_dx9_texture.hpp b/lib/graphics_engine/src/ge_dx9_texture.hpp index 1be77018337..5e67766735b 100644 --- a/lib/graphics_engine/src/ge_dx9_texture.hpp +++ b/lib/graphics_engine/src/ge_dx9_texture.hpp @@ -17,7 +17,7 @@ namespace GE class GEDX9Texture : public video::ITexture { private: - core::dimension2d m_size, m_orig_size, m_max_size; + core::dimension2d m_size, m_orig_size; std::function m_image_mani; diff --git a/lib/graphics_engine/src/ge_gl_texture.cpp b/lib/graphics_engine/src/ge_gl_texture.cpp index 1dc95760847..1774f28da8b 100644 --- a/lib/graphics_engine/src/ge_gl_texture.cpp +++ b/lib/graphics_engine/src/ge_gl_texture.cpp @@ -21,8 +21,6 @@ GEGLTexture::GEGLTexture(const std::string& path, m_driver_type(GE::getDriver()->getDriverType()), m_disable_reload(false), m_single_channel(false) { - m_max_size = getDriver()->getDriverAttributes() - .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); reload(); } // GEGLTexture @@ -94,8 +92,10 @@ void GEGLTexture::reload() { if (m_disable_reload) return; + const core::dimension2du & max_size = getDriver()->getDriverAttributes() + .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); video::IImage* texture_image = getResizedImage(NamedPath.getPtr(), - m_max_size, &m_orig_size); + max_size, &m_orig_size); if (texture_image == NULL) { LoadingFailed = true; @@ -155,7 +155,10 @@ void* GEGLTexture::lock(video::E_TEXTURE_LOCK_MODE mode, u32 mipmap_level) if (m_driver_type == video::EDT_OGLES2 || !glGetTexImage) { - video::IImage* img = getResizedImage(NamedPath.getPtr(), m_max_size); + const core::dimension2du & max_size = getDriver()->getDriverAttributes() + .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); + video::IImage* img = getResizedImage(NamedPath.getPtr(), max_size, + NULL, &m_size); if (!img) return NULL; img->setDeleteMemory(false); diff --git a/lib/graphics_engine/src/ge_gl_texture.hpp b/lib/graphics_engine/src/ge_gl_texture.hpp index 6f1cff49a99..869e09eb34b 100644 --- a/lib/graphics_engine/src/ge_gl_texture.hpp +++ b/lib/graphics_engine/src/ge_gl_texture.hpp @@ -14,7 +14,7 @@ namespace GE class GEGLTexture : public video::ITexture { private: - core::dimension2d m_size, m_orig_size, m_max_size; + core::dimension2d m_size, m_orig_size; std::function m_image_mani; diff --git a/lib/graphics_engine/src/ge_texture.cpp b/lib/graphics_engine/src/ge_texture.cpp index 314d266c914..86316bcc712 100644 --- a/lib/graphics_engine/src/ge_texture.cpp +++ b/lib/graphics_engine/src/ge_texture.cpp @@ -12,13 +12,15 @@ namespace GE using namespace irr; video::IImage* getResizedImage(const std::string& path, const core::dimension2du& max_size, - core::dimension2d* orig_size) + core::dimension2d* orig_size, + const core::dimension2d* target_size) { io::IReadFile* file = getDriver()->getFileSystem()->createAndOpenFile(path.c_str()); if (file == NULL) return NULL; - video::IImage* image = getResizedImage(file, max_size, orig_size); + video::IImage* image = getResizedImage(file, max_size, orig_size, + target_size); file->drop(); return image; } // getResizedImage diff --git a/lib/graphics_engine/src/ge_vulkan_array_texture.cpp b/lib/graphics_engine/src/ge_vulkan_array_texture.cpp index 0f817dc40fd..83d1fa21d6d 100644 --- a/lib/graphics_engine/src/ge_vulkan_array_texture.cpp +++ b/lib/graphics_engine/src/ge_vulkan_array_texture.cpp @@ -43,7 +43,7 @@ GEVulkanArrayTexture::GEVulkanArrayTexture(const std::vector& list, m_vma_allocation = VK_NULL_HANDLE; m_has_mipmaps = true; m_locked_data = NULL; - m_max_size = m_vk->getDriverAttributes() + core::dimension2du max_size = m_vk->getDriverAttributes() .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); m_internal_format = VK_FORMAT_R8G8B8A8_UNORM; @@ -51,9 +51,9 @@ GEVulkanArrayTexture::GEVulkanArrayTexture(const std::vector& list, m_image_view_lock.lock(); m_thread_loading_lock.lock(); GEVulkanCommandLoader::addMultiThreadingCommand( - [list, image_mani, this]() + [list, image_mani, max_size, this]() { - reloadInternal(list, image_mani); + reloadInternal(list, image_mani, max_size); }); } // GEVulkanArrayTexture @@ -71,7 +71,8 @@ GEVulkanArrayTexture::GEVulkanArrayTexture( // ---------------------------------------------------------------------------- void GEVulkanArrayTexture::reloadInternal(const std::vector& list, std::function image_mani) + unsigned)> image_mani, + const core::dimension2du& max_size) { VkDeviceSize image_size = 0; VkDeviceSize mipmap_data_size = 0; @@ -136,7 +137,7 @@ void GEVulkanArrayTexture::reloadInternal(const std::vector& list, { const io::path& fullpath = list[i]; video::IImage* texture_image = getResizedImageFullPath(fullpath, - m_max_size, NULL, &m_size); + max_size, NULL, &m_size); if (texture_image == NULL) goto destroy; if (image_mani) diff --git a/lib/graphics_engine/src/ge_vulkan_array_texture.hpp b/lib/graphics_engine/src/ge_vulkan_array_texture.hpp index e5c88c6963b..7ebae010192 100644 --- a/lib/graphics_engine/src/ge_vulkan_array_texture.hpp +++ b/lib/graphics_engine/src/ge_vulkan_array_texture.hpp @@ -11,7 +11,7 @@ class GEVulkanArrayTexture : public GEVulkanTexture private: void reloadInternal(const std::vector& list, std::function - image_mani); + image_mani, const core::dimension2du& max_size); public: // ------------------------------------------------------------------------ GEVulkanArrayTexture(const std::vector& full_path_list, diff --git a/lib/graphics_engine/src/ge_vulkan_depth_texture.cpp b/lib/graphics_engine/src/ge_vulkan_depth_texture.cpp index 0411c617df6..26376754628 100644 --- a/lib/graphics_engine/src/ge_vulkan_depth_texture.cpp +++ b/lib/graphics_engine/src/ge_vulkan_depth_texture.cpp @@ -19,7 +19,7 @@ GEVulkanDepthTexture::GEVulkanDepthTexture(GEVulkanDriver* vk, m_vma_allocation = VK_NULL_HANDLE; m_has_mipmaps = false; m_locked_data = NULL; - m_size = m_orig_size = m_max_size = size; + m_size = m_orig_size = size; std::vector preferred = { diff --git a/lib/graphics_engine/src/ge_vulkan_fbo_texture.cpp b/lib/graphics_engine/src/ge_vulkan_fbo_texture.cpp index 834a0b43b1e..ba9cc673bda 100644 --- a/lib/graphics_engine/src/ge_vulkan_fbo_texture.cpp +++ b/lib/graphics_engine/src/ge_vulkan_fbo_texture.cpp @@ -21,7 +21,7 @@ GEVulkanFBOTexture::GEVulkanFBOTexture(GEVulkanDriver* vk, m_vma_allocation = VK_NULL_HANDLE; m_has_mipmaps = false; m_locked_data = NULL; - m_size = m_orig_size = m_max_size = size; + m_size = m_orig_size = size; m_internal_format = VK_FORMAT_R8G8B8A8_UNORM; if (!createImage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | diff --git a/lib/graphics_engine/src/ge_vulkan_texture.cpp b/lib/graphics_engine/src/ge_vulkan_texture.cpp index c3d977ec7da..ce39db88a06 100644 --- a/lib/graphics_engine/src/ge_vulkan_texture.cpp +++ b/lib/graphics_engine/src/ge_vulkan_texture.cpp @@ -38,7 +38,7 @@ GEVulkanTexture::GEVulkanTexture(const std::string& path, m_internal_format(VK_FORMAT_R8G8B8A8_UNORM), m_vk(getVKDriver()) { - m_max_size = getDriver()->getDriverAttributes() + core::dimension2du max_size = getDriver()->getDriverAttributes() .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); m_full_path = getDriver()->getFileSystem()->getAbsolutePath(NamedPath); if (!getDriver()->getFileSystem()->existFileOnly(m_full_path)) @@ -58,7 +58,7 @@ GEVulkanTexture::GEVulkanTexture(const std::string& path, getDriver()->createImageFromFile(file, &loader); if (loader && loader->getImageSize(file, &m_orig_size)) { - m_size = getResizingTarget(m_orig_size, m_max_size); + m_size = getResizingTarget(m_orig_size, max_size); if (m_size.Width < 4 || m_size.Height < 4) m_has_mipmaps = false; setPlaceHolderView(); @@ -73,7 +73,7 @@ GEVulkanTexture::GEVulkanTexture(const std::string& path, m_image_view_lock.lock(); m_thread_loading_lock.lock(); GEVulkanCommandLoader::addMultiThreadingCommand( - std::bind(&GEVulkanTexture::reloadInternal, this)); + std::bind(&GEVulkanTexture::reloadInternal, this, max_size)); } // GEVulkanTexture // ---------------------------------------------------------------------------- @@ -501,19 +501,18 @@ void GEVulkanTexture::clearVulkanData() } // clearVulkanData // ---------------------------------------------------------------------------- -void GEVulkanTexture::reloadInternal() +void GEVulkanTexture::reloadInternal(const core::dimension2du& max_size) { if (m_disable_reload) return; clearVulkanData(); - video::IImage* texture_image = NULL; - if (m_ondemand_load) + video::IImage* texture_image = getResizedImageFullPath(m_full_path, + max_size, &m_orig_size); + if (texture_image == NULL) { - texture_image = getResizedImageFullPath(m_full_path, m_max_size, - NULL, &m_size); - if (texture_image == NULL) + if (m_ondemand_load) { printf("Missing texture_image in getResizedImageFullPath when " "reloadInternal during ondemand loading for %s\n", @@ -523,20 +522,18 @@ void GEVulkanTexture::reloadInternal() m_thread_loading_lock.unlock(); return; } - } - else - { - texture_image = getResizedImageFullPath(m_full_path, m_max_size, - &m_orig_size); - if (texture_image == NULL) + else { throw std::runtime_error( "Missing texture_image in getResizedImageFullPath"); } - m_size = texture_image->getDimension(); - if (m_size.Width < 4 || m_size.Height < 4) - m_has_mipmaps = false; } + + m_size = texture_image->getDimension(); + if (m_size.Width < 4 || m_size.Height < 4) + m_has_mipmaps = false; + else + m_has_mipmaps = true; m_size_lock.unlock(); if (m_image_mani) @@ -598,8 +595,10 @@ uint8_t* GEVulkanTexture::getTextureData() if (m_full_path.empty()) return NULL; + const core::dimension2du& max_size = getDriver()->getDriverAttributes() + .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); video::IImage* texture_image = getResizedImageFullPath(m_full_path, - m_max_size, NULL, &m_size); + max_size, NULL, &m_size); if (texture_image == NULL) return NULL; texture_image->setDeleteMemory(false); @@ -874,11 +873,13 @@ void GEVulkanTexture::reload() } else if (!m_disable_reload) { + core::dimension2du max_size = getDriver()->getDriverAttributes() + .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); m_size_lock.lock(); m_image_view_lock.lock(); m_thread_loading_lock.lock(); GEVulkanCommandLoader::addMultiThreadingCommand( - std::bind(&GEVulkanTexture::reloadInternal, this)); + std::bind(&GEVulkanTexture::reloadInternal, this, max_size)); } } // reload @@ -910,10 +911,12 @@ std::shared_ptr > GEVulkanTexture::getImageViewLive( else { GEVulkanTexture* tex = const_cast(this); + core::dimension2du max_size = getDriver()->getDriverAttributes() + .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); tex->m_thread_loading_lock.lock(); tex->m_ondemand_loading.store(true); GEVulkanCommandLoader::addMultiThreadingCommand( - std::bind(&GEVulkanTexture::reloadInternal, tex)); + std::bind(&GEVulkanTexture::reloadInternal, tex, max_size)); return m_placeholder_view; } } diff --git a/lib/graphics_engine/src/ge_vulkan_texture.hpp b/lib/graphics_engine/src/ge_vulkan_texture.hpp index a0973d9862a..f216862eda7 100644 --- a/lib/graphics_engine/src/ge_vulkan_texture.hpp +++ b/lib/graphics_engine/src/ge_vulkan_texture.hpp @@ -23,7 +23,7 @@ class GEVulkanDriver; class GEVulkanTexture : public video::ITexture { protected: - core::dimension2d m_size, m_orig_size, m_max_size; + core::dimension2d m_size, m_orig_size; std::function m_image_mani; @@ -99,7 +99,7 @@ class GEVulkanTexture : public video::ITexture // ------------------------------------------------------------------------ void clearVulkanData(); // ------------------------------------------------------------------------ - void reloadInternal(); + void reloadInternal(const core::dimension2du& max_size); // ------------------------------------------------------------------------ void bgraConversion(uint8_t* img_data); // ------------------------------------------------------------------------ From 948a408840b7b3989648c2f2aca04ac2f206609e Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Fri, 28 Mar 2025 15:54:26 +0800 Subject: [PATCH 628/830] Clean up Material::getMaskImageMani --- src/graphics/material.cpp | 47 +++++++++++++-------------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index 507ddf39bb9..6b315031a84 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -1018,22 +1018,20 @@ std::function Material::getMaskImageMani() const { #ifndef SERVER_ONLY std::function image_mani; - core::dimension2du max_size = irr_driver->getVideoDriver() - ->getDriverAttributes().getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); // Material using alpha channel will be colorized as a whole if (CVS->supportsColorization() && !useAlphaChannel() && (!m_colorization_mask.empty() || m_colorization_factor > 0.0f || m_colorizable)) { - std::string colorization_mask; + io::path colorization_mask; if (!m_colorization_mask.empty()) { - colorization_mask = StringUtils::getPath(m_sampler_path[0]) + "/" + - m_colorization_mask; + colorization_mask = (StringUtils::getPath(m_sampler_path[0]) + "/" + + m_colorization_mask).c_str(); } float colorization_factor = m_colorization_factor; - image_mani = [colorization_mask, colorization_factor, max_size] + image_mani = [colorization_mask, colorization_factor] (video::IImage* img)->void { video::IImage* mask = NULL; @@ -1043,7 +1041,9 @@ std::function Material::getMaskImageMani() const uint8_t* mask_data = NULL; if (!colorization_mask.empty()) { - mask = GE::getResizedImage(colorization_mask, max_size); + core::dimension2du max_size; + mask = GE::getResizedImageFullPath(colorization_mask, max_size, + NULL, &img_size); if (!mask) { Log::warn("Material", @@ -1051,24 +1051,6 @@ std::function Material::getMaskImageMani() const colorization_mask.c_str()); return; } - core::dimension2du mask_size = mask->getDimension(); - if (mask->getColorFormat() != video::ECF_A8R8G8B8 || - img_size != mask_size) - { - video::IImage* new_mask = irr_driver - ->getVideoDriver()->createImage(video::ECF_A8R8G8B8, - img_size); - if (img_size != mask_size) - { - mask->copyToScaling(new_mask); - } - else - { - mask->copyTo(new_mask); - } - mask->drop(); - mask = new_mask; - } mask_data = (uint8_t*)mask->lock(); } else @@ -1094,25 +1076,26 @@ std::function Material::getMaskImageMani() const return image_mani; } - std::string mask_full_path; + io::path mask_full_path; if (!m_mask.empty()) { - mask_full_path = StringUtils::getPath(m_sampler_path[0]) + "/" + - m_mask; + mask_full_path = (StringUtils::getPath(m_sampler_path[0]) + "/" + + m_mask).c_str(); } if (!mask_full_path.empty()) { - image_mani = [mask_full_path, max_size](video::IImage* img)->void + image_mani = [mask_full_path](video::IImage* img)->void { - video::IImage* converted_mask = - GE::getResizedImage(mask_full_path, max_size); + core::dimension2du dim = img->getDimension(); + core::dimension2du max_size; + video::IImage* converted_mask = GE::getResizedImageFullPath( + mask_full_path, max_size, NULL, &dim); if (converted_mask == NULL) { Log::warn("Material", "Applying alpha mask failed for '%s'!", mask_full_path.c_str()); return; } - const core::dimension2du& dim = img->getDimension(); for (unsigned int x = 0; x < dim.Width; x++) { for (unsigned int y = 0; y < dim.Height; y++) From 19a0df17c77fdec797dd319aabddbe5ef06ac57f Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Fri, 28 Mar 2025 18:31:02 +0800 Subject: [PATCH 629/830] Fix OptionsScreenVideo::setImageQuality for reloading live Only handle mesh texture reloading for now --- src/graphics/stk_tex_manager.cpp | 70 ++++++++++++++++++- src/graphics/stk_tex_manager.hpp | 2 +- .../options/options_screen_video.cpp | 50 +++++++------ .../options/options_screen_video.hpp | 1 - 4 files changed, 97 insertions(+), 26 deletions(-) diff --git a/src/graphics/stk_tex_manager.cpp b/src/graphics/stk_tex_manager.cpp index 348aacf72b6..cf83eeac4d9 100644 --- a/src/graphics/stk_tex_manager.cpp +++ b/src/graphics/stk_tex_manager.cpp @@ -22,6 +22,10 @@ #include "graphics/server_dummy_texture.hpp" #include "guiengine/engine.hpp" #include "io/file_manager.hpp" +#include "karts/kart_properties.hpp" +#include "karts/kart_properties_manager.hpp" +#include "tracks/track.hpp" +#include "tracks/track_manager.hpp" #include "utils/string_utils.hpp" #include "utils/log.hpp" @@ -247,7 +251,7 @@ bool STKTexManager::hasTexture(const std::string& path) } // hasTexture // ---------------------------------------------------------------------------- -void STKTexManager::reloadAllTextures() +void STKTexManager::reloadAllTextures(bool mesh_texture_only) { #ifndef SERVER_ONLY GE::GEVulkanDriver* gevd = GE::getVKDriver(); @@ -258,11 +262,73 @@ void STKTexManager::reloadAllTextures() } #endif + std::set mesh_texture_paths, icons; + if (mesh_texture_only) + { + io::IFileSystem* fs = file_manager->getFileSystem(); + mesh_texture_paths.insert(fs->getAbsolutePath( + file_manager->getAssetDirectory(FileManager::TEXTURE).c_str()) + .c_str()); + mesh_texture_paths.insert(fs->getAbsolutePath( + file_manager->getAssetDirectory(FileManager::LIBRARY).c_str()) + .c_str()); + mesh_texture_paths.insert(fs->getAbsolutePath( + file_manager->getAssetDirectory(FileManager::MODEL).c_str()) + .c_str()); + for (auto d : *kart_properties_manager->getAllKartDirs()) + { + if (!d.empty() && d.back() == '/') + d.pop_back(); + mesh_texture_paths.insert(fs->getAbsolutePath( + StringUtils::getPath(d).c_str()).c_str()); + } + for (unsigned i = 0; i < kart_properties_manager->getNumberOfKarts(); i++) + { + const KartProperties* kp = kart_properties_manager->getKartById(i); + io::path ic = kp->getAbsoluteIconFile().c_str(); + if (!ic.empty()) + icons.insert(fs->getAbsolutePath(ic).c_str()); + video::ITexture* mi = kp->getMinimapIcon(); + if (mi) + icons.insert(fs->getAbsolutePath(mi->getFullPath()).c_str()); + } + for (auto d : *track_manager->getAllTrackDirs()) + { + if (!d.empty() && d.back() == '/') + d.pop_back(); + mesh_texture_paths.insert(fs->getAbsolutePath( + StringUtils::getPath(d).c_str()).c_str()); + } + for (unsigned i = 0; i < track_manager->getNumberOfTracks(); i++) + { + io::path sc = track_manager->getTrack(i)->getScreenshotFile() + .c_str(); + if (!sc.empty()) + icons.insert(fs->getAbsolutePath(sc).c_str()); + } + } for (auto p : m_all_textures) { if (p.second == NULL) continue; - p.second->reload(); + if (mesh_texture_only) + { + std::string full_path = file_manager->getFileSystem() + ->getAbsolutePath(p.second->getFullPath()).c_str(); + if (icons.find(full_path) != icons.end()) + continue; + for (auto& mtp : mesh_texture_paths) + { + if (StringUtils::startsWith(full_path, mtp)) + { + Log::info("STKTexManager","%s reloaded", full_path.c_str()); + p.second->reload(); + break; + } + } + } + else + p.second->reload(); } #ifndef SERVER_ONLY diff --git a/src/graphics/stk_tex_manager.hpp b/src/graphics/stk_tex_manager.hpp index 678ebddf735..d084c88e1f0 100644 --- a/src/graphics/stk_tex_manager.hpp +++ b/src/graphics/stk_tex_manager.hpp @@ -65,7 +65,7 @@ class STKTexManager : public Singleton, NoCopy // ------------------------------------------------------------------------ int dumpTextureUsage(); // ------------------------------------------------------------------------ - void reloadAllTextures(); + void reloadAllTextures(bool mesh_texture_only = false); // ------------------------------------------------------------------------ /** Returns the currently defined texture error message, which is used * by event_handler.cpp to print additional info about irrlicht diff --git a/src/states_screens/options/options_screen_video.cpp b/src/states_screens/options/options_screen_video.cpp index 36ad14f4afc..9c8523708b4 100644 --- a/src/states_screens/options/options_screen_video.cpp +++ b/src/states_screens/options/options_screen_video.cpp @@ -20,6 +20,10 @@ #include "graphics/central_settings.hpp" #include "graphics/irr_driver.hpp" +#include "graphics/shader.hpp" +#include "graphics/sp/sp_base.hpp" +#include "graphics/sp/sp_texture_manager.hpp" +#include "graphics/stk_tex_manager.hpp" #include "io/file_manager.hpp" #include "states_screens/dialogs/custom_video_settings.hpp" #include "states_screens/dialogs/recommend_video_settings.hpp" @@ -158,6 +162,8 @@ int OptionsScreenVideo::getImageQuality() void OptionsScreenVideo::setImageQuality(int quality) { #ifndef SERVER_ONLY + core::dimension2du prev_max_size = irr_driver->getVideoDriver() + ->getDriverAttributes().getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); GE::GEVulkanTextureDescriptor* td = NULL; if (GE::getVKDriver()) td = GE::getVKDriver()->getMeshTextureDescriptor(); @@ -168,21 +174,21 @@ void OptionsScreenVideo::setImageQuality(int quality) UserConfigParams::m_high_definition_textures = 0x02; UserConfigParams::m_hq_mipmap = false; if (td) - td->setSamplerUse(GE::GVS_3D_MESH_MIPMAP_2); + td->setSamplerUse(GE::GVS_3D_MESH_MIPMAP_4); break; case 1: UserConfigParams::m_anisotropic = 16; UserConfigParams::m_high_definition_textures = 0x02; UserConfigParams::m_hq_mipmap = false; if (td) - td->setSamplerUse(GE::GVS_3D_MESH_MIPMAP_2); + td->setSamplerUse(GE::GVS_3D_MESH_MIPMAP_16); break; case 2: UserConfigParams::m_anisotropic = 16; UserConfigParams::m_high_definition_textures = 0x03; UserConfigParams::m_hq_mipmap = false; if (td) - td->setSamplerUse(GE::GVS_3D_MESH_MIPMAP_4); + td->setSamplerUse(GE::GVS_3D_MESH_MIPMAP_16); break; case 3: UserConfigParams::m_anisotropic = 16; @@ -194,14 +200,28 @@ void OptionsScreenVideo::setImageQuality(int quality) default: assert(false); } + + irr_driver->setMaxTextureSize(); + SP::setMaxTextureSize(); + core::dimension2du cur_max_size = irr_driver->getVideoDriver() + ->getDriverAttributes().getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); + + if (CVS->isGLSL()) + { + ShaderBase::killShaders(); + SP::initSamplers(); + if (prev_max_size != cur_max_size) + SP::SPTextureManager::get()->reloadTexture(""); + } + else if (prev_max_size != cur_max_size) + STKTexManager::getInstance()->reloadAllTextures(true/*mesh_texture_only*/); #endif } // setImageQuality // -------------------------------------------------------------------------------------------- OptionsScreenVideo::OptionsScreenVideo() : Screen("options/options_video.stkgui"), - m_prev_adv_pipline(false), - m_prev_img_quality(-1) + m_prev_adv_pipline(false) { m_inited = false; initPresets(); @@ -236,7 +256,6 @@ void OptionsScreenVideo::init() OptionsCommon::setTabStatus(); m_prev_adv_pipline = UserConfigParams::m_dynamic_lights; - m_prev_img_quality = getImageQuality(); RibbonWidget* ribbon = getWidget("options_choice"); assert(ribbon != NULL); ribbon->setFocusForPlayer(PLAYER_ID_GAME_MASTER); @@ -715,27 +734,14 @@ void OptionsScreenVideo::tearDown() /* Returns 1 or 2 if a restart will be done, 0 otherwise */ int OptionsScreenVideo::applySettings() { - int restart = 0; #ifndef SERVER_ONLY if (m_prev_adv_pipline != UserConfigParams::m_dynamic_lights && CVS->isGLSL()) - restart = 1; - - if (m_prev_img_quality != getImageQuality()) { - irr_driver->setMaxTextureSize(); - // A full restart is needed to properly apply anisotropic filtering if it was changed - // We assume that all ImageQuality settings >= 1 use the same x16 setting. - if ((m_prev_img_quality == 0 && getImageQuality() != 0) || - (m_prev_img_quality != 0 && getImageQuality() == 0)) - restart = 2; - } - - if (restart == 1) irr_driver->sameRestart(); - else if (restart == 2) - irr_driver->fullRestart(); + return 1; + } #endif - return restart; + return 0; } // applySettings // -------------------------------------------------------------------------------------------- diff --git a/src/states_screens/options/options_screen_video.hpp b/src/states_screens/options/options_screen_video.hpp index 4b3a56910ae..30175475ef7 100644 --- a/src/states_screens/options/options_screen_video.hpp +++ b/src/states_screens/options/options_screen_video.hpp @@ -62,7 +62,6 @@ class OptionsScreenVideo : public GUIEngine::Screen, public GUIEngine::ScreenSin { private: bool m_prev_adv_pipline; - int m_prev_img_quality; OptionsScreenVideo(); bool m_inited; std::vector m_presets; From be34827fd8dc240ebff92c5a187353c56482438b Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 23 Mar 2025 16:19:32 +0400 Subject: [PATCH 630/830] Friendship ended with CommandManager, move stuff to Asset- and new CrownMgr. Now no one is my best friend. Also some m_timeout refactors. --- src/network/protocols/command_manager.cpp | 121 ++------ src/network/protocols/command_manager.hpp | 33 +- src/network/protocols/server_lobby.cpp | 361 ++++++---------------- src/network/protocols/server_lobby.hpp | 42 +-- src/utils/crown_manager.cpp | 281 +++++++++++++++++ src/utils/crown_manager.hpp | 64 ++++ src/utils/hourglass_reason.hpp | 4 +- src/utils/lobby_asset_manager.cpp | 82 ++++- src/utils/lobby_asset_manager.hpp | 39 +++ src/utils/lobby_context.cpp | 3 + src/utils/lobby_context.hpp | 4 + src/utils/lobby_settings.cpp | 59 +--- src/utils/lobby_settings.hpp | 62 ++-- src/utils/team_manager.cpp | 44 ++- src/utils/team_manager.hpp | 4 + 15 files changed, 688 insertions(+), 515 deletions(-) create mode 100644 src/utils/crown_manager.cpp create mode 100644 src/utils/crown_manager.hpp diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 000e2932d20..ad2d0c60818 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -33,6 +33,7 @@ #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/chat_manager.hpp" +#include "utils/crown_manager.hpp" #include "utils/file_utils.hpp" #include "utils/hit_processor.hpp" #include "utils/hourglass_reason.hpp" @@ -814,22 +815,10 @@ int CommandManager::getCurrentModeScope() } // getCurrentModeScope // ======================================================================== -int CommandManager::getCurrentStateScope() -{ - auto state = getLobby()->m_state.load(); - if (state < ServerLobby::WAITING_FOR_START_GAME - || state > ServerLobby::RESULT_DISPLAY) - return 0; - if (state == ServerLobby::WAITING_FOR_START_GAME) - return SS_LOBBY; - return SS_INGAME; -} // getCurrentStateScope -// ======================================================================== - bool CommandManager::isAvailable(std::shared_ptr c) { return (getCurrentModeScope() & c->m_mode_scope) != 0 - && (getCurrentStateScope() & c->m_state_scope) != 0; + && (getLobby()->getCurrentStateScope() & c->m_state_scope) != 0; } // getCurrentModeScope // ======================================================================== @@ -1118,7 +1107,7 @@ void CommandManager::process_replay(Context& context) void CommandManager::process_start(Context& context) { - if (!getSettings()->isOwnerLess() && (context.m_user_permissions & UP_CROWNED) == 0) + if (!getCrownManager()->isOwnerLess() && (context.m_user_permissions & UP_CROWNED) == 0) { context.m_voting = true; } @@ -1141,7 +1130,7 @@ void CommandManager::process_config(Context& context) } int difficulty = getLobby()->getDifficulty(); int mode = getLobby()->getGameMode(); - bool goal_target = (getLobby()->m_game_setup->hasExtraServerInfo() ? getLobby()->isSoccerGoalTarget() : false); + bool goal_target = (getLobby()->getGameSetup()->hasExtraServerInfo() ? getLobby()->isSoccerGoalTarget() : false); // m_aux_goal_aliases[goal_target ? 1 : 0][0] std::string msg = "Current config: "; auto get_first_if_exists = [&](std::vector& v) -> std::string { @@ -1172,7 +1161,7 @@ void CommandManager::process_config_assign(Context& context) const auto& argv = context.m_argv; int difficulty = getLobby()->getDifficulty(); int mode = getLobby()->getGameMode(); - bool goal_target = (getLobby()->m_game_setup->hasExtraServerInfo() ? getLobby()->isSoccerGoalTarget() : false); + bool goal_target = (getLobby()->getGameSetup()->hasExtraServerInfo() ? getLobby()->isSoccerGoalTarget() : false); bool user_chose_difficulty = false; bool user_chose_mode = false; bool user_chose_target = false; @@ -1271,18 +1260,18 @@ void CommandManager::process_spectate(Context& context) } if (value >= 1) { - if (getLobby()->m_process_type == PT_CHILD && - peer->getHostId() == getLobby()->m_client_server_host_id.load()) + if (getLobby()->isChildProcess() && + getLobby()->isClientServerHost(peer)) { getLobby()->sendStringToPeer(peer, "Graphical client server cannot spectate"); return; } AlwaysSpectateMode type = (value == 2 ? ASM_COMMAND_ABSENT : ASM_COMMAND); - getLobby()->setSpectateModeProperly(peer, type); + getCrownManager()->setSpectateModeProperly(peer, type); } else { - getLobby()->setSpectateModeProperly(peer, ASM_NONE); + getCrownManager()->setSpectateModeProperly(peer, ASM_NONE); } getLobby()->updateServerOwner(true); getLobby()->updatePlayerList(); @@ -1329,7 +1318,7 @@ void CommandManager::process_addons(Context& context) if (!p || !p->isValidated()) continue; if ((!more_own || p != peer) && (p->isWaitingForGame() - || !getLobby()->canRace(p) || p->isCommandSpectator())) + || !getCrownManager()->canRace(p) || p->isCommandSpectator())) continue; if (!p->hasPlayerProfiles()) continue; @@ -1467,7 +1456,7 @@ void CommandManager::process_checkaddon(Context& context) for (auto p : peers) { if (!p || !p->isValidated() || p->isWaitingForGame() - || !getLobby()->canRace(p) || p->isCommandSpectator() + || !getCrownManager()->canRace(p) || p->isCommandSpectator() || !p->hasPlayerProfiles()) continue; std::string username = p->getMainName(); @@ -1758,7 +1747,7 @@ void CommandManager::process_kick(Context& context) if (argv[0] == "kickban") { Log::info("CommandManager", "%s is now banned", player_name.c_str()); - getLobby()->m_temp_banned.insert(player_name); + getSettings()->tempBan(player_name); getLobby()->sendStringToPeer(peer, StringUtils::insertValues( "%s is now banned", player_name.c_str())); } @@ -1786,7 +1775,7 @@ void CommandManager::process_unban(Context& context) return; } Log::info("CommandManager", "%s is now unbanned", player_name.c_str()); - getLobby()->m_temp_banned.erase(player_name); + getSettings()->tempUnban(player_name); getLobby()->sendStringToPeer(peer, StringUtils::insertValues( "%s is now unbanned", player_name.c_str())); } // process_unban @@ -1814,7 +1803,7 @@ void CommandManager::process_ban(Context& context) return; } Log::info("CommandManager", "%s is now banned", player_name.c_str()); - getLobby()->m_temp_banned.insert(player_name); + getSettings()->tempBan(player_name); getLobby()->sendStringToPeer(peer, StringUtils::insertValues( "%s is now banned", player_name.c_str())); } // process_ban @@ -2207,7 +2196,7 @@ void CommandManager::process_standings(Context& context) } if (!isGP && !isGnu) { - if (getLobby()->m_game_setup->isGrandPrix()) + if (getLobby()->getGameSetup()->isGrandPrix()) isGP = true; else isGnu = true; @@ -2750,8 +2739,7 @@ void CommandManager::process_timeout(Context& context) error(context); return; } - getLobby()->m_timeout.store((int64_t)StkTime::getMonoTimeMs() + - (int64_t)(seconds * 1000.0f)); + getLobby()->setTimeoutFromNow(seconds); getLobby()->updatePlayerList(); getLobby()->sendStringToPeer(peer, "Successfully changed timeout"); } // process_timeout @@ -3329,7 +3317,7 @@ void CommandManager::process_role(Context& context) StringUtils::utf8ToWide(u)); std::vector missing_assets; if (player_peer) - missing_assets = getSettings()->getMissingAssets(player_peer); + missing_assets = getAssetManager()->getMissingAssets(player_peer); bool fail = false; switch (role_char) { @@ -3566,7 +3554,7 @@ void CommandManager::process_slots(Context& context) error(context, true); return; } - int current = getLobby()->m_current_max_players_in_game.load(); + int current = getSettings()->getCurrentMaxPlayersInGame(); getLobby()->sendStringToPeer(peer, "Number of slots is currently " + std::to_string(current)); } // process_slots @@ -3574,7 +3562,7 @@ void CommandManager::process_slots(Context& context) void CommandManager::process_slots_assign(Context& context) { - if (getSettings()->hasOnlyHostRiding()) + if (getCrownManager()->hasOnlyHostRiding()) { auto peer = context.m_peer.lock(); // may be nullptr, here we don't care getLobby()->sendStringToPeer(peer, @@ -3598,7 +3586,7 @@ void CommandManager::process_slots_assign(Context& context) vote(context, "slots", argv[1]); return; } - getLobby()->m_current_max_players_in_game.store((unsigned)number); + getSettings()->setCurrentMaxPlayersInGame((unsigned)number); getLobby()->updatePlayerList(); getLobby()->sendStringToAllPeers("Number of playable slots is now " + argv[1]); } // process_slots_assign @@ -3815,62 +3803,9 @@ void CommandManager::process_why_hourglass(Context& context) error(context); return; } - auto it = getLobby()->m_why_peer_cannot_play.find(player_peer); - if (it == getLobby()->m_why_peer_cannot_play.end()) - { - Log::error("CommandManager", "Hourglass status undefined for a player!"); - response = "For some reason, server doesn't know about the hourglass status of this player."; - } - else - { - switch (it->second) - { - case HR_NONE: - response = "%s can play (but if hourglass is present, there are not enough slots on the server)."; - break; - case HR_ABSENT_PEER: - response = "Player %s is not present on the server."; - break; - case HR_NOT_A_TOURNAMENT_PLAYER: - response = "%s is not a tournament player for this game."; - break; - case HR_SPECTATOR_BY_LIMIT: - response = "Not enough slots to fit %s."; - break; - case HR_NO_KARTS_AFTER_FILTER: - response = "After applying all kart filters, %s doesn't have karts to play."; - break; - case HR_NO_MAPS_AFTER_FILTER: - response = "After applying all map filters, %s doesn't have maps to play."; - break; - case HR_LACKING_REQUIRED_MAPS: - response = "%s lacks required maps."; - break; - case HR_ADDON_KARTS_PLAY_THRESHOLD: - response = "Player %s doesn't have enough addon karts."; - break; - case HR_ADDON_TRACKS_PLAY_THRESHOLD: - response = "Player %s doesn't have enough addon tracks."; - break; - case HR_ADDON_ARENAS_PLAY_THRESHOLD: - response = "Player %s doesn't have enough addon arenas."; - break; - case HR_ADDON_FIELDS_PLAY_THRESHOLD: - response = "Player %s doesn't have enough addon fields."; - break; - case HR_OFFICIAL_KARTS_PLAY_THRESHOLD: - response = "The number of official karts for %s is lower than the threshold."; - break; - case HR_OFFICIAL_TRACKS_PLAY_THRESHOLD: - response = "The number of official tracks for %s is lower than the threshold."; - break; - default: - response = ""; - break; - } - response = StringUtils::insertValues(response, player_name.c_str()); - } - getLobby()->sendStringToPeer(peer, response); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + getCrownManager()->getWhyPeerCannotPlayAsString(player_peer), + player_name)); } // process_why_hourglass // ======================================================================== @@ -4036,7 +3971,7 @@ bool CommandManager::assignRandomTeams(int intended_number, int player_number = 0; for (auto& p : STKHost::get()->getPeers()) { - if (!getLobby()->canRace(p)) + if (!getCrownManager()->canRace(p)) continue; if (p->alwaysSpectateButNotNeutral()) continue; @@ -4082,7 +4017,7 @@ bool CommandManager::assignRandomTeams(int intended_number, getTeamManager()->clearTemporaryTeams(); for (auto& p : STKHost::get()->getPeers()) { - if (!getLobby()->canRace(p)) + if (!getCrownManager()->canRace(p)) continue; if (p->alwaysSpectateButNotNeutral()) continue; @@ -4223,10 +4158,10 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, } // hasTypo // ======================================================================== -void CommandManager::onResetServer() +void CommandManager::onServerSetup() { update(); -} // onResetServer +} // onServerSetup // ======================================================================== void CommandManager::onStartSelection() @@ -4267,7 +4202,7 @@ void CommandManager::Command::changePermissions(int permissions, std::string CommandManager::getAddonPreferredType() const { - int mode = getLobby()->m_game_mode.load(); + int mode = getLobby()->getGameMode(); if (0 <= mode && mode <= 4) return "track"; if (mode == 6) diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 8eaf680ecea..7a7ff099897 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -55,6 +55,22 @@ class STKPeer; class CommandManager: public LobbyContextComponent { +public: + enum ModeScope: int + { + MS_DEFAULT = 1, + MS_SOCCER_TOURNAMENT = 2 + // add more powers of two if needed + }; + + enum StateScope: int + { + SS_LOBBY = 1, + SS_INGAME = 2, + SS_ALWAYS = SS_LOBBY | SS_INGAME + }; + +private: struct FileResource { std::string m_file_name; @@ -90,20 +106,6 @@ class CommandManager: public LobbyContextComponent template void add_to_queue(int x, int mask, bool to_front, std::string& s) const; - enum ModeScope: int - { - MS_DEFAULT = 1, - MS_SOCCER_TOURNAMENT = 2 - // add more powers of two if needed - }; - - enum StateScope: int - { - SS_LOBBY = 1, - SS_INGAME = 2, - SS_ALWAYS = SS_LOBBY | SS_INGAME - }; - struct Command; struct Context @@ -249,7 +251,6 @@ class CommandManager: public LobbyContextComponent void initAssets(); int getCurrentModeScope(); - int getCurrentStateScope(); bool isAvailable(std::shared_ptr c); @@ -383,7 +384,7 @@ class CommandManager: public LobbyContextComponent SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is, bool dont_replace = false, int subidx = 0, int substr_l = -1, int substr_r = -1); - void onResetServer(); + void onServerSetup(); void onStartSelection(); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 44148d13768..909d71e9302 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -51,6 +51,7 @@ #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/chat_manager.hpp" +#include "utils/crown_manager.hpp" #include "utils/kart_elimination.hpp" #include "utils/game_info.hpp" #include "utils/hit_processor.hpp" @@ -215,8 +216,6 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_client_server_host_id.store(0); m_lobby_players.store(0); - m_current_max_players_in_game.store(ServerConfig::m_max_players_in_game); - m_lobby_context = std::make_shared(this, (bool)ServerConfig::m_soccer_tournament); m_lobby_context->setup(); m_context = m_lobby_context.get(); @@ -231,7 +230,6 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_registered_for_once_only = false; setHandleDisconnections(true); m_state = SET_PUBLIC_ADDRESS; - m_save_server_config = true; if (ServerConfig::m_ranked) { Log::info("ServerLobby", "This server will submit ranking scores to " @@ -267,7 +265,7 @@ ServerLobby::~ServerLobby() } delete m_result_ns; delete m_items_complete_state; - if (m_save_server_config) + if (getSettings()->isSavingServerConfig()) ServerConfig::writeServerConfigToDisk(); #ifdef ENABLE_SQLITE3 @@ -330,9 +328,9 @@ void ServerLobby::setup() // Initialise the data structures to detect if all clients and // the server are ready: resetPeersReady(); - m_timeout.store(std::numeric_limits::max()); + setInfiniteTimeout(); m_server_started_at = m_server_delay = 0; - getCommandManager()->onResetServer(); + getCommandManager()->onServerSetup(); m_game_info = {}; Log::info("ServerLobby", "Resetting the server to its initial state."); } // setup @@ -701,11 +699,11 @@ void ServerLobby::asynchronousUpdate() } case WAITING_FOR_START_GAME: { - if (getSettings()->isOwnerLess()) + if (getCrownManager()->isOwnerLess()) { // Ensure that a game can auto-start if the server meets the config's starting limit or if it's already full. int starting_limit = std::min((int)getSettings()->getMinStartGamePlayers(), (int)getSettings()->getServerMaxPlayers()); - unsigned current_max_players_in_game = m_current_max_players_in_game.load(); + unsigned current_max_players_in_game = getSettings()->getCurrentMaxPlayersInGame(); if (current_max_players_in_game > 0) // 0 here means it's not the limit starting_limit = std::min(starting_limit, (int)current_max_players_in_game); @@ -713,32 +711,31 @@ void ServerLobby::asynchronousUpdate() STKHost::get()->updatePlayers(&players); if (((int)players >= starting_limit || m_game_setup->isGrandPrixStarted()) && - m_timeout.load() == std::numeric_limits::max()) + isInfiniteTimeout()) { if (getSettings()->getStartGameCounter() >= -1e-5) { - m_timeout.store((int64_t)StkTime::getMonoTimeMs() + - (int64_t) - (getSettings()->getStartGameCounter() * 1000.0f)); + setTimeoutFromNow(getSettings()->getStartGameCounter()); } else { - m_timeout.store(std::numeric_limits::max()); + setInfiniteTimeout(); } } else if ((int)players < starting_limit && !m_game_setup->isGrandPrixStarted()) { resetPeersReady(); - if (m_timeout.load() != std::numeric_limits::max()) + if (!isInfiniteTimeout()) updatePlayerList(); - m_timeout.store(std::numeric_limits::max()); + + setInfiniteTimeout(); } bool forbid_starting = false; if (getTournament() && getTournament()->forbidStarting()) forbid_starting = true; - bool timer_finished = (!forbid_starting && m_timeout.load() < (int64_t)StkTime::getMonoTimeMs()); + bool timer_finished = (!forbid_starting && isTimeoutExpired()); bool players_ready = (checkPeersReady(true/*ignore_ai_peer*/, BEFORE_SELECTION) && (int)players >= starting_limit); @@ -1128,7 +1125,7 @@ void ServerLobby::liveJoinRequest(Event* event) peer->clearAvailableKartIDs(); if (!spectator) { - auto& spectators_by_limit = getSpectatorsByLimit(); + auto& spectators_by_limit = getCrownManager()->getSpectatorsByLimit(); setPlayerKarts(data, peer); std::vector used_id; @@ -1618,14 +1615,14 @@ void ServerLobby::update(int ticks) resetPeersReady(); // Set the delay before the server forces all clients to exit the race // result screen and go back to the lobby - m_timeout.store((int64_t)StkTime::getMonoTimeMs() + 15000); + setTimeoutFromNow(15); m_state = RESULT_DISPLAY; sendMessageToPeers(m_result_ns, PRM_RELIABLE); Log::info("ServerLobby", "End of game message sent"); break; case RESULT_DISPLAY: if (checkPeersReady(true/*ignore_ai_peer*/, AFTER_GAME) || - (int64_t)StkTime::getMonoTimeMs() > m_timeout.load()) + isTimeoutExpired()) { // Send a notification to all clients to exit // the race result screen @@ -1741,21 +1738,21 @@ void ServerLobby::startSelection(const Event *event) m_state.load()); return; } - if (getSettings()->isSleepingServer()) + if (getCrownManager()->isSleepingServer()) { Log::warn("ServerLobby", "An attempt to start a race on a sleeping server."); return; } auto peer = event->getPeerSP(); - if (getSettings()->isOwnerLess()) + if (getCrownManager()->isOwnerLess()) { if (!getSettings()->isAllowedToStart()) { sendStringToPeer(peer, "Starting the game is forbidden by server owner"); return; } - if (!canRace(peer)) + if (!getCrownManager()->canRace(peer)) { sendStringToPeer(peer, "You cannot play so pressing ready has no action"); return; @@ -1799,7 +1796,7 @@ void ServerLobby::startSelection(const Event *event) } } - if (!getSettings()->isOwnerLess() && getSettings()->hasTeamChoosing() && + if (!getCrownManager()->isOwnerLess() && getSettings()->hasTeamChoosing() && !getSettings()->hasFreeTeams() && RaceManager::get()->teamEnabled()) { auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); @@ -1825,7 +1822,7 @@ void ServerLobby::startSelection(const Event *event) std::set> always_spectate_peers; // Set late coming player to spectate if too many players - auto& spectators_by_limit = getSpectatorsByLimit(); + auto& spectators_by_limit = getCrownManager()->getSpectatorsByLimit(); if (spectators_by_limit.size() == peers.size()) { // produce no log spam for now @@ -1847,7 +1844,7 @@ void ServerLobby::startSelection(const Event *event) { if (!peer->isValidated() || peer->isWaitingForGame()) continue; - bool can_race = canRace(peer); + bool can_race = getCrownManager()->canRace(peer); if (!can_race && !peer->alwaysSpectate()) { peer->setAlwaysSpectate(ASM_FULL); @@ -1947,7 +1944,7 @@ void ServerLobby::startSelection(const Event *event) { if (peer->isDisconnected() && !peer->isValidated()) continue; - if (!canRace(peer) || peer->isWaitingForGame()) + if (!getCrownManager()->canRace(peer) || peer->isWaitingForGame()) continue; // they are handled below NetworkString *ns = getNetworkString(1); @@ -2014,7 +2011,7 @@ void ServerLobby::startSelection(const Event *event) } // Will be changed after the first vote received - m_timeout.store(std::numeric_limits::max()); + setInfiniteTimeout(); getGPManager()->onStartSelection(); @@ -2514,7 +2511,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, if (online_id > 0) { std::string username = StringUtils::wideToUtf8(online_name); - if (m_temp_banned.count(username)) + if (getSettings()->isTempBanned(username)) { NetworkString* message = getNetworkString(2); message->setSynchronous(true); @@ -2679,14 +2676,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, NetworkString* message_ack = getNetworkString(4); message_ack->setSynchronous(true); // connection success -- return the host id of peer - float auto_start_timer = 0.0f; - if (m_timeout.load() == std::numeric_limits::max()) - auto_start_timer = std::numeric_limits::max(); - else - { - auto_start_timer = - (m_timeout.load() - (int64_t)StkTime::getMonoTimeMs()) / 1000.0f; - } + float auto_start_timer = getTimeUntilExpiration(); message_ack->addUInt8(LE_CONNECTION_ACCEPTED).addUInt32(peer->getHostId()) .addUInt32(ServerConfig::m_server_version); @@ -2827,7 +2817,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) all_profiles_size--; } - auto& spectators_by_limit = getSpectatorsByLimit(true); + auto& spectators_by_limit = getCrownManager()->getSpectatorsByLimit(true); // N - 1 AI auto ai_instance = m_ai_peer.lock(); @@ -2932,7 +2922,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) boolean_combine |= (1 << 1); if (p && m_server_owner_id.load() == p->getHostId()) boolean_combine |= (1 << 2); - if (getSettings()->isOwnerLess() && !game_started && + if (getCrownManager()->isOwnerLess() && !game_started && m_peers_ready.find(p) != m_peers_ready.end() && m_peers_ready.at(p)) boolean_combine |= (1 << 3); @@ -2969,7 +2959,7 @@ void ServerLobby::updateServerOwner(bool force) { if (m_state.load() < WAITING_FOR_START_GAME || m_state.load() > RESULT_DISPLAY || - getSettings()->isOwnerLess()) + getCrownManager()->isOwnerLess()) return; if (!force && !m_server_owner.expired()) return; @@ -4165,96 +4155,6 @@ void ServerLobby::clientSelectingAssetsWantsToBackLobby(Event* event) delete server_info; } // clientSelectingAssetsWantsToBackLobby -//----------------------------------------------------------------------------- -std::set>& ServerLobby::getSpectatorsByLimit(bool update) -{ - if (!update) - return m_spectators_by_limit; - - m_why_peer_cannot_play.clear(); - m_spectators_by_limit.clear(); - - auto peers = STKHost::get()->getPeers(); - - unsigned player_limit = getSettings()->getServerMaxPlayers(); - // If the server has an in-game player limit lower than the lobby limit, apply it, - // A value of 0 for this parameter means no limit. - unsigned current_max_players_in_game = m_current_max_players_in_game.load(); - if (current_max_players_in_game > 0) - player_limit = std::min(player_limit, (unsigned)current_max_players_in_game); - - - // only 10 players allowed for FFA and 14 for CTF and soccer - if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_FREE_FOR_ALL) - player_limit = std::min(player_limit, 10u); - - if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) - player_limit = std::min(player_limit, 14u); - - if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_SOCCER) - player_limit = std::min(player_limit, 14u); - - unsigned ingame_players = 0, waiting_players = 0, total_players = 0; - STKHost::get()->updatePlayers(&ingame_players, &waiting_players, &total_players); - - for (int i = 0; i < (int)peers.size(); ++i) - { - if (!peers[i]->isValidated()) - { - swap(peers[i], peers.back()); - peers.pop_back(); - --i; - } - } - - std::sort(peers.begin(), peers.end(), - [](const std::shared_ptr& a, - const std::shared_ptr& b) - { return a->getRejoinTime() < b->getRejoinTime(); }); - - unsigned player_count = 0; - if (m_state.load() >= RACING) - { - for (auto &peer : peers) - if (peer->isSpectator()) - ingame_players -= (int)peer->getPlayerProfiles().size(); - player_count = ingame_players; - } - - for (unsigned i = 0; i < peers.size(); i++) - { - auto& peer = peers[i]; - if (!peer->isValidated()) - continue; - bool ignore = false; - if (m_state.load() < RACING) - { - if (peer->alwaysSpectate() || peer->isWaitingForGame()) - ignore = true; - else if (!canRace(peer)) - { - m_spectators_by_limit.insert(peer); - ignore = true; - } - } - else - { - if (!peer->isWaitingForGame()) - ignore = true; // we already counted them properly in ingame_players - } - if (!ignore) - { - player_count += (unsigned)peer->getPlayerProfiles().size(); - if (player_count > player_limit) - m_spectators_by_limit.insert(peer); - } - } - return m_spectators_by_limit; -} // getSpectatorsByLimit - //----------------------------------------------------------------------------- void ServerLobby::saveInitialItems(std::shared_ptr nim) { @@ -4285,7 +4185,7 @@ bool ServerLobby::checkPeersReady(bool ignore_ai_peer, SelectionPhase phase) continue; if (ignore_ai_peer && peer->isAIPeer()) continue; - if (phase == BEFORE_SELECTION && !canRace(peer)) + if (phase == BEFORE_SELECTION && !getCrownManager()->canRace(peer)) continue; someone_races = true; all_ready = all_ready && p.second; @@ -4663,92 +4563,6 @@ void ServerLobby::sendStringToAllPeers(const std::string& s) delete chat; } // sendStringToAllPeers //----------------------------------------------------------------------------- - -bool ServerLobby::canRace(std::shared_ptr peer) -{ - auto it = m_why_peer_cannot_play.find(peer); - if (it != m_why_peer_cannot_play.end()) - return it->second == 0; - - if (!peer || peer->getPlayerProfiles().empty()) - { - m_why_peer_cannot_play[peer] = HR_ABSENT_PEER; - return false; - } - std::string username = peer->getMainName(); - if (getTournament() && !getTournament()->canPlay(username)) - { - m_why_peer_cannot_play[peer] = HR_NOT_A_TOURNAMENT_PLAYER; - return false; - } - else if (m_spectators_by_limit.find(peer) != m_spectators_by_limit.end()) - { - m_why_peer_cannot_play[peer] = HR_SPECTATOR_BY_LIMIT; - return false; - } - - if (!getSettings()->getMissingAssets(peer).empty()) - { - m_why_peer_cannot_play[peer] = HR_LACKING_REQUIRED_MAPS; - return false; - } - - if (peer->addon_karts_count < getSettings()->getAddonKartsPlayThreshold()) - { - m_why_peer_cannot_play[peer] = HR_ADDON_KARTS_PLAY_THRESHOLD; - return false; - } - if (peer->addon_tracks_count < getSettings()->getAddonTracksPlayThreshold()) - { - m_why_peer_cannot_play[peer] = HR_ADDON_TRACKS_PLAY_THRESHOLD; - return false; - } - if (peer->addon_arenas_count < getSettings()->getAddonArenasPlayThreshold()) - { - m_why_peer_cannot_play[peer] = HR_ADDON_ARENAS_PLAY_THRESHOLD; - return false; - } - if (peer->addon_soccers_count < getSettings()->getAddonSoccersPlayThreshold()) - { - m_why_peer_cannot_play[peer] = HR_ADDON_FIELDS_PLAY_THRESHOLD; - return false; - } - - std::set maps = peer->getClientAssets().second; - std::set karts = peer->getClientAssets().first; - - float karts_fraction = getAssetManager()->officialKartsFraction(karts); - float maps_fraction = getAssetManager()->officialMapsFraction(maps); - - if (karts_fraction < getSettings()->getOfficialKartsPlayThreshold()) - { - m_why_peer_cannot_play[peer] = HR_OFFICIAL_KARTS_PLAY_THRESHOLD; - return false; - } - if (maps_fraction < getSettings()->getOfficialTracksPlayThreshold()) - { - m_why_peer_cannot_play[peer] = HR_OFFICIAL_TRACKS_PLAY_THRESHOLD; - return false; - } - - getAssetManager()->applyAllFilters(maps, true); - getAssetManager()->applyAllKartFilters(username, karts, false); - - if (karts.empty()) - { - m_why_peer_cannot_play[peer] = HR_NO_KARTS_AFTER_FILTER; - return false; - } - if (maps.empty()) - { - m_why_peer_cannot_play[peer] = HR_NO_MAPS_AFTER_FILTER; - return false; - } - - m_why_peer_cannot_play[peer] = 0; - return true; -} // canRace -//----------------------------------------------------------------------------- bool ServerLobby::canVote(std::shared_ptr peer) const { if (!peer || peer->getPlayerProfiles().empty()) @@ -4793,7 +4607,7 @@ int ServerLobby::getPermissions(std::shared_ptr peer) const if (peer == m_server_owner.lock()) { mask |= CommandPermissions::PE_CROWNED; - if (getSettings()->hasOnlyHostRiding()) + if (getCrownManager()->hasOnlyHostRiding()) mask |= CommandPermissions::PE_SINGLE; } if (peer->isAngryHost()) @@ -4979,53 +4793,6 @@ void ServerLobby::saveDisconnectingIdInfo(int id) const info.m_result = RaceManager::get()->getKartRaceTime(id); } } // saveDisconnectingIdInfo - -//----------------------------------------------------------------------------- - -void ServerLobby::checkNoTeamSpectator(std::shared_ptr peer) -{ - if (!peer) - return; - - if (RaceManager::get()->teamEnabled()) - { - bool has_teamed = false; - for (auto& other: peer->getPlayerProfiles()) - { - if (other->getTeam() != KART_TEAM_NONE) - { - has_teamed = true; - break; - } - } - - if (!has_teamed && peer->getAlwaysSpectate() == ASM_NONE) - setSpectateModeProperly(peer, ASM_NO_TEAM); - - if (has_teamed && peer->getAlwaysSpectate() == ASM_NO_TEAM) - setSpectateModeProperly(peer, ASM_NONE); - } -} // checkNoTeamSpectator - -//----------------------------------------------------------------------------- -void ServerLobby::setSpectateModeProperly(std::shared_ptr peer, AlwaysSpectateMode mode) -{ - auto state = m_state.load(); - bool selection_started = (state >= ServerLobby::SELECTING); - bool no_racing_yet = (state < ServerLobby::RACING); - - peer->setDefaultAlwaysSpectate(mode); - if (!selection_started || !no_racing_yet) - peer->setAlwaysSpectate(mode); - else - { - erasePeerReady(peer); - peer->setAlwaysSpectate(mode); - peer->setWaitingForGame(true); - } - if (mode == ASM_NONE) - checkNoTeamSpectator(peer); -} // setSpectateModeProperly //----------------------------------------------------------------------------- void ServerLobby::sendServerInfoToEveryone() const @@ -5043,4 +4810,68 @@ bool ServerLobby::isLegacyGPMode() const { return getSettings()->isLegacyGPMode(); } // isLegacyGPMode -//----------------------------------------------------------------------------- \ No newline at end of file +//----------------------------------------------------------------------------- + +int ServerLobby::getCurrentStateScope() +{ + auto state = m_state.load(); + if (state < WAITING_FOR_START_GAME + || state > RESULT_DISPLAY) + return 0; + if (state == WAITING_FOR_START_GAME) + return CommandManager::StateScope::SS_LOBBY; + return CommandManager::StateScope::SS_INGAME; +} // getCurrentStateScope +//----------------------------------------------------------------------------- + +bool ServerLobby::isClientServerHost(const std::shared_ptr& peer) +{ + return peer->getHostId() == m_client_server_host_id.load(); +} // isClientServerHost +//----------------------------------------------------------------------------- + +void ServerLobby::setTimeoutFromNow(int seconds) +{ + m_timeout.store((int64_t)StkTime::getMonoTimeMs() + + (int64_t)(seconds * 1000.0f)); +} // setTimeoutFromNow +//----------------------------------------------------------------------------- + +void ServerLobby::setInfiniteTimeout() +{ + m_timeout.store(std::numeric_limits::max()); +} // setInfiniteTimeout +//----------------------------------------------------------------------------- + +bool ServerLobby::isInfiniteTimeout() const +{ + return m_timeout.load() == std::numeric_limits::max(); +} // isInfiniteTimeout +//----------------------------------------------------------------------------- + +bool ServerLobby::isTimeoutExpired() const +{ + return m_timeout.load() < (int64_t)StkTime::getMonoTimeMs(); +} // isTimeoutExpired +//----------------------------------------------------------------------------- + +float ServerLobby::getTimeUntilExpiration() const +{ + int64_t timeout = m_timeout.load(); + if (timeout == std::numeric_limits::max()) + return std::numeric_limits::max(); + + return (timeout - (int64_t)StkTime::getMonoTimeMs()) / 1000.0f; +} // getTimeUntilExpiration +//----------------------------------------------------------------------------- + +void ServerLobby::onSpectatorStatusChange(const std::shared_ptr& peer) +{ + auto state = m_state.load(); + if (state >= ServerLobby::SELECTING && state < ServerLobby::RACING) + { + erasePeerReady(peer); + peer->setWaitingForGame(true); + } +} // onSpectatorStatusChange +//----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 4dc66c5dbf1..baf9d59d4a9 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -130,8 +130,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser bool m_registered_for_once_only; - bool m_save_server_config; - /** Counts how many peers have finished loading the world. */ std::map, bool, std::owner_less > > m_peers_ready; @@ -178,8 +176,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser std::shared_ptr m_ranking; - friend CommandManager; - unsigned m_item_seed; uint64_t m_client_starting_time; @@ -187,14 +183,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser // Calculated before each game started unsigned m_ai_count; - std::set> m_spectators_by_limit; - - std::map, int> m_why_peer_cannot_play; - - std::set m_temp_banned; - - std::atomic m_current_max_players_in_game; - std::shared_ptr m_game_info; // connection management @@ -216,12 +204,16 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser public: // I'll see if it should be private later void updatePlayerList(bool update_when_reset_server = false); + void updateServerOwner(bool force = false); private: - void updateServerOwner(bool force = false); void handleServerConfiguration(Event* event); + +public: // I'll see if it should be private later void handleServerConfiguration(std::shared_ptr peer, int difficulty, int mode, bool soccer_goal_target); + +private: void updateMapsForMode(); bool checkPeersReady(bool ignore_ai_peer, SelectionPhase phase); void resetPeersReady() @@ -285,7 +277,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser void handleKartInfo(Event* event); void clientInGameWantsToBackLobby(Event* event); void clientSelectingAssetsWantsToBackLobby(Event* event); - std::set>& getSpectatorsByLimit(bool update = false); void kickPlayerWithReason(std::shared_ptr peer, const char* reason) const; void testBannedForIP(std::shared_ptr peer) const; void testBannedForIPv6(std::shared_ptr peer) const; @@ -294,11 +285,12 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser void writePlayerReport(Event* event); bool supportsAI(); void initTournamentPlayers(); +public: void changeColors(); - bool canRace(std::shared_ptr peer); + void changeLimitForTournament(bool goal_target); +private: bool canVote(std::shared_ptr peer) const; bool hasHostRights(std::shared_ptr peer) const; - void changeLimitForTournament(bool goal_target); public: ServerLobby(); @@ -319,7 +311,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser virtual bool allPlayersReady() const OVERRIDE { return m_state.load() >= WAIT_FOR_RACE_STARTED; } virtual bool isRacing() const OVERRIDE { return m_state.load() == RACING; } - void setSaveServerConfig(bool val) { m_save_server_config = val; } float getStartupBoostOrPenaltyForKart(uint32_t ping, unsigned kart_id); int getDifficulty() const { return m_difficulty.load(); } int getGameMode() const { return m_game_mode.load(); } @@ -371,12 +362,23 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser bool isWorldPicked() const { return m_state.load() >= LOAD_WORLD; } bool isWorldFinished() const { return m_state.load() >= RESULT_DISPLAY; } + bool isStateAtLeastRacing() const { return m_state.load() >= RACING; } bool isLegacyGPMode() const; + int getCurrentStateScope(); + bool isChildProcess() { return m_process_type == PT_CHILD; } + + bool isClientServerHost(const std::shared_ptr& peer); + void setTimeoutFromNow(int seconds); + void setInfiniteTimeout(); + bool isInfiniteTimeout() const; + bool isTimeoutExpired() const; + float getTimeUntilExpiration() const; + void onSpectatorStatusChange(const std::shared_ptr& peer); + + //------------------------------------------------------------------------- + // More auxiliary functions //------------------------------------------------------------------------- - // The functions below reset/set ASM_NO_TEAM if needed by team changing procedure. - void checkNoTeamSpectator(std::shared_ptr peer); - void setSpectateModeProperly(std::shared_ptr peer, AlwaysSpectateMode mode); std::shared_ptr getGameInfo() const { return m_game_info; } std::shared_ptr getServerOwner() const diff --git a/src/utils/crown_manager.cpp b/src/utils/crown_manager.cpp new file mode 100644 index 00000000000..3493103d690 --- /dev/null +++ b/src/utils/crown_manager.cpp @@ -0,0 +1,281 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/crown_manager.hpp" + +#include "network/server_config.hpp" +#include "utils/hourglass_reason.hpp" +#include "network/stk_host.hpp" +#include "network/stk_peer.hpp" +#include "network/protocols/server_lobby.hpp" +#include "utils/lobby_settings.hpp" +#include "utils/lobby_asset_manager.hpp" +#include "utils/team_manager.hpp" +#include "utils/tournament.hpp" + +#include + + +namespace +{ + const std::string g_hr_unknown = "For some reason, server doesn't know about the hourglass status of player %s."; + const std::string g_hr_none = "%s can play (but if hourglass is present, there are not enough slots on the server)."; + const std::string g_hr_absent_peer = "Player %s is not present on the server."; + const std::string g_hr_not_tournament = "%s is not a tournament player for this game."; + const std::string g_hr_limit_spectator = "Not enough slots to fit %s."; + const std::string g_hr_no_karts_after = "After applying all kart filters, %s doesn't have karts to play."; + const std::string g_hr_no_maps_after = "After applying all map filters, %s doesn't have maps to play."; + const std::string g_hr_lack_required_maps = "%s lacks required maps."; + const std::string g_hr_addon_karts_thr = "Player %s doesn't have enough addon karts."; + const std::string g_hr_addon_tracks_thr = "Player %s doesn't have enough addon tracks."; + const std::string g_hr_addon_arenas_thr = "Player %s doesn't have enough addon arenas."; + const std::string g_hr_addon_fields_thr = "Player %s doesn't have enough addon fields."; + const std::string g_hr_off_karts_thr = "The number of official karts for %s is lower than the threshold."; + const std::string g_hr_off_tracks_thr = "The number of official tracks for %s is lower than the threshold."; + const std::string g_hr_empty = ""; +} // namespace +//----------------------------------------------------------------------------- + +void CrownManager::setupContextUser() +{ + m_only_host_riding = ServerConfig::m_only_host_riding; + m_owner_less = ServerConfig::m_owner_less; + m_sleeping_server = ServerConfig::m_sleeping_server; +} // setupContextUser +//----------------------------------------------------------------------------- + +std::set>& CrownManager::getSpectatorsByLimit(bool update) +{ + if (!update) + return m_spectators_by_limit; + + m_why_peer_cannot_play.clear(); + m_spectators_by_limit.clear(); + + auto peers = STKHost::get()->getPeers(); + + unsigned player_limit = getSettings()->getServerMaxPlayers(); + + // If the server has an in-game player limit lower than the lobby limit, apply it, + // A value of 0 for this parameter means no limit. + unsigned current_max_players_in_game = getSettings()->getCurrentMaxPlayersInGame(); + if (current_max_players_in_game > 0) + player_limit = std::min(player_limit, current_max_players_in_game); + + // only 10 players allowed for FFA and 14 for CTF and soccer + if (RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_FREE_FOR_ALL) + player_limit = std::min(player_limit, 10u); + + if (RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) + player_limit = std::min(player_limit, 14u); + + if (RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_SOCCER) + player_limit = std::min(player_limit, 14u); + + unsigned ingame_players = 0, waiting_players = 0, total_players = 0; + STKHost::get()->updatePlayers(&ingame_players, &waiting_players, &total_players); + + for (int i = 0; i < (int)peers.size(); ++i) + { + if (!peers[i]->isValidated()) + { + std::swap(peers[i], peers.back()); + peers.pop_back(); + --i; + } + } + + std::sort(peers.begin(), peers.end(), + [](const std::shared_ptr& a, + const std::shared_ptr& b) + { return a->getRejoinTime() < b->getRejoinTime(); }); + + unsigned player_count = 0; + + bool is_racing = getLobby()->isStateAtLeastRacing(); + + if (is_racing) + { + for (auto &peer : peers) + if (peer->isSpectator()) + ingame_players -= (int)peer->getPlayerProfiles().size(); + player_count = ingame_players; + } + + for (unsigned i = 0; i < peers.size(); i++) + { + auto& peer = peers[i]; + if (!peer->isValidated()) + continue; + bool ignore = false; + if (!is_racing) + { + if (peer->alwaysSpectate() || peer->isWaitingForGame()) + ignore = true; + else if (!canRace(peer)) + { + m_spectators_by_limit.insert(peer); + ignore = true; + } + } + else + { + if (!peer->isWaitingForGame()) + ignore = true; // we already counted them properly in ingame_players + } + if (!ignore) + { + player_count += (unsigned)peer->getPlayerProfiles().size(); + if (player_count > player_limit) + m_spectators_by_limit.insert(peer); + } + } + return m_spectators_by_limit; +} // getSpectatorsByLimit + +//----------------------------------------------------------------------------- + +bool CrownManager::canRace(std::shared_ptr peer) +{ + auto it = m_why_peer_cannot_play.find(peer); + if (it != m_why_peer_cannot_play.end()) + return it->second == 0; + + if (!peer || peer->getPlayerProfiles().empty()) + { + m_why_peer_cannot_play[peer] = HR_ABSENT_PEER; + return false; + } + std::string username = peer->getMainName(); + if (getTournament() && !getTournament()->canPlay(username)) + { + m_why_peer_cannot_play[peer] = HR_NOT_A_TOURNAMENT_PLAYER; + return false; + } + else if (m_spectators_by_limit.find(peer) != m_spectators_by_limit.end()) + { + m_why_peer_cannot_play[peer] = HR_SPECTATOR_BY_LIMIT; + return false; + } + + if (!getAssetManager()->getMissingAssets(peer).empty()) + { + m_why_peer_cannot_play[peer] = HR_LACKING_REQUIRED_MAPS; + return false; + } + + if (peer->addon_karts_count < getAssetManager()->getAddonKartsPlayThreshold()) + { + m_why_peer_cannot_play[peer] = HR_ADDON_KARTS_PLAY_THRESHOLD; + return false; + } + if (peer->addon_tracks_count < getAssetManager()->getAddonTracksPlayThreshold()) + { + m_why_peer_cannot_play[peer] = HR_ADDON_TRACKS_PLAY_THRESHOLD; + return false; + } + if (peer->addon_arenas_count < getAssetManager()->getAddonArenasPlayThreshold()) + { + m_why_peer_cannot_play[peer] = HR_ADDON_ARENAS_PLAY_THRESHOLD; + return false; + } + if (peer->addon_soccers_count < getAssetManager()->getAddonSoccersPlayThreshold()) + { + m_why_peer_cannot_play[peer] = HR_ADDON_FIELDS_PLAY_THRESHOLD; + return false; + } + + std::set maps = peer->getClientAssets().second; + std::set karts = peer->getClientAssets().first; + + float karts_fraction = getAssetManager()->officialKartsFraction(karts); + float maps_fraction = getAssetManager()->officialMapsFraction(maps); + + if (karts_fraction < getAssetManager()->getOfficialKartsPlayThreshold()) + { + m_why_peer_cannot_play[peer] = HR_OFFICIAL_KARTS_PLAY_THRESHOLD; + return false; + } + if (maps_fraction < getAssetManager()->getOfficialTracksPlayThreshold()) + { + m_why_peer_cannot_play[peer] = HR_OFFICIAL_TRACKS_PLAY_THRESHOLD; + return false; + } + + getAssetManager()->applyAllFilters(maps, true); + getAssetManager()->applyAllKartFilters(username, karts, false); + + if (karts.empty()) + { + m_why_peer_cannot_play[peer] = HR_NO_KARTS_AFTER_FILTER; + return false; + } + if (maps.empty()) + { + m_why_peer_cannot_play[peer] = HR_NO_MAPS_AFTER_FILTER; + return false; + } + + m_why_peer_cannot_play[peer] = 0; + return true; +} // canRace +//----------------------------------------------------------------------------- + +std::string CrownManager::getWhyPeerCannotPlayAsString( + const std::shared_ptr& player_peer) const +{ + auto it = m_why_peer_cannot_play.find(player_peer); + std::string response; + if (it == m_why_peer_cannot_play.end()) + { + Log::error("LobbySettings", "Hourglass status undefined for a player!"); + return g_hr_unknown; + } + + switch (it->second) + { + case HR_NONE: return g_hr_none; + case HR_ABSENT_PEER: return g_hr_absent_peer; + case HR_NOT_A_TOURNAMENT_PLAYER: return g_hr_not_tournament; + case HR_SPECTATOR_BY_LIMIT: return g_hr_limit_spectator; + case HR_NO_KARTS_AFTER_FILTER: return g_hr_no_karts_after; + case HR_NO_MAPS_AFTER_FILTER: return g_hr_no_maps_after; + case HR_LACKING_REQUIRED_MAPS: return g_hr_lack_required_maps; + case HR_ADDON_KARTS_PLAY_THRESHOLD: return g_hr_addon_karts_thr; + case HR_ADDON_TRACKS_PLAY_THRESHOLD: return g_hr_addon_tracks_thr; + case HR_ADDON_ARENAS_PLAY_THRESHOLD: return g_hr_addon_arenas_thr; + case HR_ADDON_FIELDS_PLAY_THRESHOLD: return g_hr_addon_fields_thr; + case HR_OFFICIAL_KARTS_PLAY_THRESHOLD: return g_hr_off_karts_thr; + case HR_OFFICIAL_TRACKS_PLAY_THRESHOLD: return g_hr_off_tracks_thr; + default: return g_hr_empty; + } +} // getWhyPeerCannotPlayAsString +//----------------------------------------------------------------------------- + +void CrownManager::setSpectateModeProperly(std::shared_ptr peer, AlwaysSpectateMode mode) +{ + peer->setDefaultAlwaysSpectate(mode); + peer->setAlwaysSpectate(mode); + getLobby()->onSpectatorStatusChange(peer); + if (mode == ASM_NONE) + getTeamManager()->checkNoTeamSpectator(peer); +} // setSpectateModeProperly +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/crown_manager.hpp b/src/utils/crown_manager.hpp new file mode 100644 index 00000000000..bf2c3ce0a83 --- /dev/null +++ b/src/utils/crown_manager.hpp @@ -0,0 +1,64 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef CROWN_MANAGER_HPP +#define CROWN_MANAGER_HPP + +#include "irrString.h" +#include "utils/lobby_context.hpp" +#include "utils/types.hpp" + +#include +#include +#include +#include + +class STKPeer; +enum AlwaysSpectateMode : uint8_t; + +class CrownManager: public LobbyContextComponent +{ +public: + CrownManager(LobbyContext* context): LobbyContextComponent(context) {} + + void setupContextUser() OVERRIDE; + + std::set>& getSpectatorsByLimit(bool update = false); + + bool canRace(std::shared_ptr peer); + bool hasOnlyHostRiding() const { return m_only_host_riding; } + bool isOwnerLess() const { return m_owner_less; } + bool isSleepingServer() const { return m_sleeping_server; } + + std::string getWhyPeerCannotPlayAsString( + const std::shared_ptr& player_peer) const; + + void setSpectateModeProperly(std::shared_ptr peer, AlwaysSpectateMode mode); + +private: + bool m_only_host_riding; + bool m_owner_less; + bool m_sleeping_server; + + std::set> m_spectators_by_limit; + + std::map, int> m_why_peer_cannot_play; + +}; + +#endif // CROWN_MANAGER_HPP diff --git a/src/utils/hourglass_reason.hpp b/src/utils/hourglass_reason.hpp index b972230e7a9..a5d6238603f 100644 --- a/src/utils/hourglass_reason.hpp +++ b/src/utils/hourglass_reason.hpp @@ -19,9 +19,9 @@ #ifndef HOURGLASS_REASON_HPP #define HOURGLASS_REASON_HPP -enum HourglassReason : int +enum HourglassReason : int32_t { - HR_NONE = 0, + HR_NONE = 0, HR_ABSENT_PEER = (1 << 0), HR_NOT_A_TOURNAMENT_PLAYER = (1 << 1), HR_SPECTATOR_BY_LIMIT = (1 << 2), diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp index e6c4ec72791..df83bfc1e08 100644 --- a/src/utils/lobby_asset_manager.cpp +++ b/src/utils/lobby_asset_manager.cpp @@ -39,6 +39,7 @@ void LobbyAssetManager::setupContextUser() { init(); + initAvailableTracks(); updateAddons(); } // setupContextUser //----------------------------------------------------------------------------- @@ -65,6 +66,19 @@ void LobbyAssetManager::init() if (!t->isAddon()) m_official_kts.second.insert(t->getIdent()); } + + m_official_karts_play_threshold = ServerConfig::m_official_karts_play_threshold; + m_official_tracks_play_threshold = ServerConfig::m_official_tracks_play_threshold; + m_addon_karts_join_threshold = ServerConfig::m_addon_karts_join_threshold; + m_addon_tracks_join_threshold = ServerConfig::m_addon_tracks_join_threshold; + m_addon_arenas_join_threshold = ServerConfig::m_addon_arenas_join_threshold; + m_addon_soccers_join_threshold = ServerConfig::m_addon_soccers_join_threshold; + m_addon_arenas_play_threshold = ServerConfig::m_addon_arenas_play_threshold; + m_addon_karts_play_threshold = ServerConfig::m_addon_karts_play_threshold; + m_addon_soccers_play_threshold = ServerConfig::m_addon_soccers_play_threshold; + m_addon_tracks_play_threshold = ServerConfig::m_addon_tracks_play_threshold; + m_official_karts_threshold = ServerConfig::m_official_karts_threshold; + m_official_tracks_threshold = ServerConfig::m_official_tracks_threshold; } // init //----------------------------------------------------------------------------- @@ -353,14 +367,14 @@ bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer, Log::info("LobbyAssetManager", "Player has the following addons: %d/%d(%d) karts," " %d/%d(%d) tracks, %d/%d(%d) arenas, %d/%d(%d) soccer fields.", - addon_karts, settings->getAddonKartsJoinThreshold(), - settings->getAddonKartsPlayThreshold(), - addon_tracks, settings->getAddonTracksJoinThreshold(), - settings->getAddonTracksPlayThreshold(), - addon_arenas, settings->getAddonArenasJoinThreshold(), - settings->getAddonArenasPlayThreshold(), - addon_soccers, settings->getAddonSoccersJoinThreshold(), - settings->getAddonSoccersPlayThreshold()); + addon_karts, getAddonKartsJoinThreshold(), + getAddonKartsPlayThreshold(), + addon_tracks, getAddonTracksJoinThreshold(), + getAddonTracksPlayThreshold(), + addon_arenas, getAddonArenasJoinThreshold(), + getAddonArenasPlayThreshold(), + addon_soccers, getAddonSoccersJoinThreshold(), + getAddonSoccersPlayThreshold()); bool bad = false; @@ -393,37 +407,37 @@ bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer, bad = true; } - if (okt < getSettings()->getOfficialKartsThreshold()) + if (okt < getAssetManager()->getOfficialKartsThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: bad official kart threshold"); bad = true; } - if (ott < getSettings()->getOfficialTracksThreshold()) + if (ott < getAssetManager()->getOfficialTracksThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: bad official track threshold"); bad = true; } - if (addon_karts < getSettings()->getAddonKartsJoinThreshold()) + if (addon_karts < getAssetManager()->getAddonKartsJoinThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: too little addon karts"); bad = true; } - if (addon_tracks < getSettings()->getAddonTracksJoinThreshold()) + if (addon_tracks < getAssetManager()->getAddonTracksJoinThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: too little addon tracks"); bad = true; } - if (addon_arenas < getSettings()->getAddonArenasJoinThreshold()) + if (addon_arenas < getAssetManager()->getAddonArenasJoinThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: too little addon arenas"); bad = true; } - if (addon_soccers < getSettings()->getAddonSoccersJoinThreshold()) + if (addon_soccers < getAssetManager()->getAddonSoccersJoinThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: too little addon soccers"); bad = true; @@ -614,7 +628,7 @@ void LobbyAssetManager::applyAllFilters(std::set& maps, bool use_hi map_context.wildcards = m_map_history; map_context.applied_at_selection_start = true; map_context.elements = maps; - getSettings()->applyGlobalFilter(map_context); + applyGlobalFilter(map_context); if (use_history) { @@ -636,7 +650,7 @@ void LobbyAssetManager::applyAllKartFilters(const std::string& username, std::se kart_context.applied_at_selection_start = !afterSelection; kart_context.elements = karts; - getSettings()->applyGlobalKartsFilter(kart_context); + applyGlobalKartsFilter(kart_context); getQueues()->applyFrontKartFilters(kart_context); swap(karts, kart_context.elements); } // applyAllKartFilters @@ -671,4 +685,40 @@ std::string LobbyAssetManager::getKartForBadKartChoice( std::advance(it, rg.get((int)karts.size())); return *it; } // getKartForRandomKartChoice +//----------------------------------------------------------------------------- + +void LobbyAssetManager::applyGlobalFilter(FilterContext& map_context) const +{ + m_global_filter.apply(map_context); +} // applyGlobalFilter +//----------------------------------------------------------------------------- + +void LobbyAssetManager::applyGlobalKartsFilter(FilterContext& kart_context) const +{ + m_global_karts_filter.apply(kart_context); +} // applyGlobalKartsFilter +//----------------------------------------------------------------------------- + +void LobbyAssetManager::initAvailableTracks() +{ + m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); + m_global_karts_filter = KartFilter(ServerConfig::m_only_played_karts_string); + getAssetManager()->setMustHaveMaps(ServerConfig::m_must_have_tracks_string); + m_play_requirement_tracks = StringUtils::split( + ServerConfig::m_play_requirement_tracks_string, ' ', false); +} // initAvailableTracks +//----------------------------------------------------------------------------- + +std::vector LobbyAssetManager::getMissingAssets( + std::shared_ptr peer) const +{ + if (m_play_requirement_tracks.empty()) + return {}; + + std::vector ans; + for (const std::string& required_track : m_play_requirement_tracks) + if (peer->getClientAssets().second.count(required_track) == 0) + ans.push_back(required_track); + return ans; +} // getMissingAssets //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/lobby_asset_manager.hpp b/src/utils/lobby_asset_manager.hpp index d620e7fa8a7..75dc0386889 100644 --- a/src/utils/lobby_asset_manager.hpp +++ b/src/utils/lobby_asset_manager.hpp @@ -22,6 +22,7 @@ #include "network/stk_peer.hpp" #include "race/race_manager.hpp" #include "utils/lobby_context.hpp" +#include "utils/track_filter.hpp" #include "utils/types.hpp" #include @@ -41,6 +42,7 @@ class LobbyAssetManager: public LobbyContextComponent void setupContextUser() OVERRIDE; void init(); + void initAvailableTracks(); void updateAddons(); void updateMapsForMode(RaceManager::MinorRaceModeType mode); void onServerSetup(); @@ -78,6 +80,9 @@ class LobbyAssetManager: public LobbyContextComponent void applyAllFilters(std::set& maps, bool use_history) const; void applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection = false) const; + void applyGlobalFilter(FilterContext& map_context) const; + void applyGlobalKartsFilter(FilterContext& kart_context) const; + std::string getKartForBadKartChoice( std::shared_ptr peer, const std::string& username, @@ -97,6 +102,21 @@ class LobbyAssetManager: public LobbyContextComponent bool hasAddonSoccer(const std::string& id) const { return m_addon_soccers.find(id) != m_addon_soccers.end(); } + std::vector getMissingAssets(std::shared_ptr peer) const; + + float getOfficialKartsPlayThreshold() const { return m_official_karts_play_threshold; } + float getOfficialTracksPlayThreshold() const { return m_official_tracks_play_threshold; } + int getAddonKartsJoinThreshold() const { return m_addon_karts_join_threshold; } + int getAddonTracksJoinThreshold() const { return m_addon_tracks_join_threshold; } + int getAddonArenasJoinThreshold() const { return m_addon_arenas_join_threshold; } + int getAddonSoccersJoinThreshold() const { return m_addon_soccers_join_threshold; } + int getAddonKartsPlayThreshold() const { return m_addon_karts_play_threshold; } + int getAddonTracksPlayThreshold() const { return m_addon_tracks_play_threshold; } + int getAddonArenasPlayThreshold() const { return m_addon_arenas_play_threshold; } + int getAddonSoccersPlayThreshold() const { return m_addon_soccers_play_threshold; } + float getOfficialKartsThreshold() const { return m_official_karts_threshold; } + float getOfficialTracksThreshold() const { return m_official_tracks_threshold; } + public: /** Official karts and maps available in server. */ std::pair, std::set > m_official_kts; @@ -121,6 +141,25 @@ class LobbyAssetManager: public LobbyContextComponent std::vector m_must_have_maps; std::vector m_map_history; + + TrackFilter m_global_filter; + + KartFilter m_global_karts_filter; + + std::vector m_play_requirement_tracks; + + float m_official_karts_play_threshold; + float m_official_tracks_play_threshold; + int m_addon_karts_join_threshold; + int m_addon_tracks_join_threshold; + int m_addon_arenas_join_threshold; + int m_addon_soccers_join_threshold; + int m_addon_arenas_play_threshold; + int m_addon_karts_play_threshold; + int m_addon_soccers_play_threshold; + int m_addon_tracks_play_threshold; + float m_official_karts_threshold; + float m_official_tracks_threshold; }; #endif // LOBBY_ASSET_MANAGER_HPP diff --git a/src/utils/lobby_context.cpp b/src/utils/lobby_context.cpp index 7f4f705e678..786c366b48f 100644 --- a/src/utils/lobby_context.cpp +++ b/src/utils/lobby_context.cpp @@ -30,6 +30,7 @@ #include "utils/tournament.hpp" #include "utils/lobby_gp_manager.hpp" #include "utils/gp_scoring.hpp" +#include "utils/crown_manager.hpp" LobbyContext::LobbyContext(ServerLobby* lobby, bool make_tournament) : m_lobby(lobby) @@ -45,6 +46,7 @@ LobbyContext::LobbyContext(ServerLobby* lobby, bool make_tournament) m_chat_manager = std::make_shared(this); m_team_manager = std::make_shared(this); m_gp_manager = std::make_shared(this); + m_crown_manager = std::make_shared(this); if (make_tournament) m_tournament = std::make_shared(this); @@ -64,6 +66,7 @@ void LobbyContext::setup() m_team_manager->setupContextUser(); m_command_manager->setupContextUser(); m_gp_manager->setupContextUser(); + m_crown_manager->setupContextUser(); if (m_tournament) m_tournament->setupContextUser(); diff --git a/src/utils/lobby_context.hpp b/src/utils/lobby_context.hpp index 5cc4b1fbc82..bec9d0822de 100644 --- a/src/utils/lobby_context.hpp +++ b/src/utils/lobby_context.hpp @@ -35,6 +35,7 @@ class ServerLobby; class TeamManager; class Tournament; class LobbyGPManager; +class CrownManager; class LobbyContext { @@ -51,6 +52,7 @@ class LobbyContext std::shared_ptr m_chat_manager; std::shared_ptr m_team_manager; std::shared_ptr m_gp_manager; + std::shared_ptr m_crown_manager; public: @@ -71,6 +73,7 @@ class LobbyContext std::shared_ptr getChatManager() const { return m_chat_manager; } std::shared_ptr getTeamManager() const { return m_team_manager; } std::shared_ptr getGPManager() const { return m_gp_manager; } + std::shared_ptr getCrownManager() const { return m_crown_manager; } }; class LobbyContextUser @@ -90,6 +93,7 @@ class LobbyContextUser std::shared_ptr getChatManager() const { return m_context->getChatManager(); } std::shared_ptr getTeamManager() const { return m_context->getTeamManager(); } std::shared_ptr getGPManager() const { return m_context->getGPManager(); } + std::shared_ptr getCrownManager() const { return m_context->getCrownManager(); } public: void setContext(LobbyContext* context) { m_context = context; } diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index f7bf5ffe6b8..a9286e89aec 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -26,6 +26,7 @@ #include "network/network_string.hpp" #include "network/peer_vote.hpp" #include "network/server_config.hpp" +#include "network/stk_host.hpp" #include "network/stk_peer.hpp" #include "network/protocols/server_lobby.hpp" #include "network/game_setup.hpp" @@ -39,6 +40,7 @@ #include "utils/string_utils.hpp" #include "utils/tournament.hpp" + void LobbySettings::setupContextUser() { m_game_setup = getLobby()->getGameSetup(); @@ -60,16 +62,18 @@ void LobbySettings::setupContextUser() m_legacy_gp_mode_started = false; m_last_reset = 0; + m_save_server_config = true; m_fixed_direction = ServerConfig::m_fixed_direction; + m_current_max_players_in_game = ServerConfig::m_max_players_in_game; + setDefaultLapRestrictions(); m_default_vote = new PeerVote(); m_allowed_to_start = ServerConfig::m_allowed_to_start; initAvailableModes(); - initAvailableTracks(); loadWhiteList(); loadPreservedSettings(); @@ -93,10 +97,6 @@ void LobbySettings::setupContextUser() m_kicks_allowed = ServerConfig::m_kicks_allowed; m_max_ping = ServerConfig::m_max_ping; m_min_start_game_players = ServerConfig::m_min_start_game_players; - m_official_karts_play_threshold = ServerConfig::m_official_karts_play_threshold; - m_official_tracks_play_threshold = ServerConfig::m_official_tracks_play_threshold; - m_only_host_riding = ServerConfig::m_only_host_riding; - m_owner_less = ServerConfig::m_owner_less; m_preserve_battle_scores = ServerConfig::m_preserve_battle_scores; m_private_server_password = ServerConfig::m_private_server_password; m_ranked = ServerConfig::m_ranked; @@ -106,7 +106,6 @@ void LobbySettings::setupContextUser() m_server_difficulty = ServerConfig::m_server_difficulty; m_server_max_players = ServerConfig::m_server_max_players; m_server_mode = ServerConfig::m_server_mode; - m_sleeping_server = ServerConfig::m_sleeping_server; m_soccer_goal_target = ServerConfig::m_soccer_goal_target; m_sql_management = ServerConfig::m_sql_management; m_start_game_counter = ServerConfig::m_start_game_counter; @@ -122,18 +121,8 @@ void LobbySettings::setupContextUser() m_validating_player = ServerConfig::m_validating_player; m_voting_timeout = ServerConfig::m_voting_timeout; m_commands_file = ServerConfig::m_commands_file; - m_addon_karts_join_threshold = ServerConfig::m_addon_karts_join_threshold; - m_addon_tracks_join_threshold = ServerConfig::m_addon_tracks_join_threshold; - m_addon_arenas_join_threshold = ServerConfig::m_addon_arenas_join_threshold; - m_addon_soccers_join_threshold = ServerConfig::m_addon_soccers_join_threshold; - m_addon_arenas_play_threshold = ServerConfig::m_addon_arenas_play_threshold; - m_addon_karts_play_threshold = ServerConfig::m_addon_karts_play_threshold; - m_addon_soccers_play_threshold = ServerConfig::m_addon_soccers_play_threshold; - m_addon_tracks_play_threshold = ServerConfig::m_addon_tracks_play_threshold; m_power_password = ServerConfig::m_power_password; m_register_table_name = ServerConfig::m_register_table_name; - m_official_karts_threshold = ServerConfig::m_official_karts_threshold; - m_official_tracks_threshold = ServerConfig::m_official_tracks_threshold; m_lobby_cooldown = ServerConfig::m_lobby_cooldown; } // setupContextUser //----------------------------------------------------------------------------- @@ -172,16 +161,6 @@ void LobbySettings::initAvailableModes() } // initAvailableModes //----------------------------------------------------------------------------- -void LobbySettings::initAvailableTracks() -{ - m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); - m_global_karts_filter = KartFilter(ServerConfig::m_only_played_karts_string); - getAssetManager()->setMustHaveMaps(ServerConfig::m_must_have_tracks_string); - m_play_requirement_tracks = StringUtils::split( - ServerConfig::m_play_requirement_tracks_string, ' ', false); -} // initAvailableTracks -//----------------------------------------------------------------------------- - void LobbySettings::loadWhiteList() { std::vector tokens = StringUtils::split( @@ -362,20 +341,6 @@ std::string LobbySettings::getWhetherShuffledGPGridAsString(bool just_edited) co } // getWhetherShuffledGPGridAsString //----------------------------------------------------------------------------- -std::vector LobbySettings::getMissingAssets( - std::shared_ptr peer) const -{ - if (m_play_requirement_tracks.empty()) - return {}; - - std::vector ans; - for (const std::string& required_track : m_play_requirement_tracks) - if (peer->getClientAssets().second.count(required_track) == 0) - ans.push_back(required_track); - return ans; -} // getMissingAssets -//----------------------------------------------------------------------------- - void LobbySettings::updateWorldSettings(std::shared_ptr game_info) { World::getWorld()->setGameInfo(game_info); @@ -516,18 +481,6 @@ void LobbySettings::initializeDefaultVote() } // initializeDefaultVote //----------------------------------------------------------------------------- -void LobbySettings::applyGlobalFilter(FilterContext& map_context) const -{ - m_global_filter.apply(map_context); -} // applyGlobalFilter -//----------------------------------------------------------------------------- - -void LobbySettings::applyGlobalKartsFilter(FilterContext& kart_context) const -{ - m_global_karts_filter.apply(kart_context); -} // applyGlobalKartsFilter -//----------------------------------------------------------------------------- - void LobbySettings::applyRestrictionsOnVote(PeerVote* vote, Track* t) const { if (RaceManager::get()->modeHasLaps()) @@ -683,4 +636,4 @@ bool LobbySettings::isCooldown() const int64_t passed_since_reset = (int64_t)StkTime::getMonoTimeMs() - m_last_reset; return passed_since_reset < 1000 * m_lobby_cooldown; } // isCooldown -//----------------------------------------------------------------------------- \ No newline at end of file +//----------------------------------------------------------------------------- diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 44a79d01cf3..55d74907c4f 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -22,7 +22,6 @@ #include "irrString.h" #include "utils/lobby_context.hpp" #include "utils/team_utils.hpp" -#include "utils/track_filter.hpp" #include @@ -48,7 +47,6 @@ class LobbySettings: public LobbyContextComponent void setupContextUser() OVERRIDE; ~LobbySettings(); - void initAvailableTracks(); void initAvailableModes(); void loadWhiteList(); void loadPreservedSettings(); @@ -77,7 +75,6 @@ class LobbySettings: public LobbyContextComponent bool isGPGridShuffled() const; void setGPGridShuffled(bool value); std::string getWhetherShuffledGPGridAsString(bool just_edited = false) const; - std::vector getMissingAssets(std::shared_ptr peer) const; void updateWorldSettings(std::shared_ptr game_info); void onResetToDefaultSettings(); bool isPreservingMode() const; @@ -85,8 +82,6 @@ class LobbySettings: public LobbyContextComponent void eraseFromPreserved(const std::string& value); void insertIntoPreserved(const std::string& value); void initializeDefaultVote(); - void applyGlobalFilter(FilterContext& map_context) const; - void applyGlobalKartsFilter(FilterContext& kart_context) const; void applyRestrictionsOnVote(PeerVote* vote, Track* t) const; void encodeDefaultVote(NetworkString* ns) const; void setDefaultVote(PeerVote winner_vote); @@ -103,15 +98,28 @@ class LobbySettings: public LobbyContextComponent void setBattleHitCaptureLimit(int value) { m_battle_hit_capture_limit = value; } void setBattleTimeLimit(float value) { m_battle_time_limit = value; } - void setLobbyCooldown(int value) { m_lobby_cooldown = value; } + void setLobbyCooldown(int value) { m_lobby_cooldown = value; } bool isCooldown() const; + bool isSavingServerConfig() const { return m_save_server_config; } void onServerSetup(); void tryKickingAnotherPeer(std::shared_ptr initiator, std::shared_ptr target) const; + unsigned getCurrentMaxPlayersInGame() const + { return m_current_max_players_in_game; } + void setCurrentMaxPlayersInGame(unsigned value) + { m_current_max_players_in_game = value; } + + bool isTempBanned(const std::string& username) + { return m_temp_banned.find(username) != m_temp_banned.end(); } + void tempBan(const std::string& username) + { m_temp_banned.insert(username); } + void tempUnban(const std::string& username) + { m_temp_banned.erase(username); } + // These were used unchanged from ServerConfig bool isLivePlayers() const { return m_live_players; } bool canConnectAiAnywhere() const { return m_ai_anywhere; } @@ -131,10 +139,6 @@ class LobbySettings: public LobbyContextComponent bool hasKicksAllowed() const { return m_kicks_allowed; } int getMaxPing() const { return m_max_ping; } int getMinStartGamePlayers() const { return m_min_start_game_players; } - float getOfficialKartsPlayThreshold() const { return m_official_karts_play_threshold; } - float getOfficialTracksPlayThreshold() const { return m_official_tracks_play_threshold; } - bool hasOnlyHostRiding() const { return m_only_host_riding; } - bool isOwnerLess() const { return m_owner_less; } bool isPreservingBattleScores() const { return m_preserve_battle_scores; } std::string getPrivateServerPassword() const { return m_private_server_password; } bool isRanked() const { return m_ranked; } @@ -144,7 +148,6 @@ class LobbySettings: public LobbyContextComponent int getServerDifficulty() const { return m_server_difficulty; } int getServerMaxPlayers() const { return m_server_max_players; } int getServerMode() const { return m_server_mode; } - bool isSleepingServer() const { return m_sleeping_server; } bool isSoccerGoalTargetInConfig() const { return m_soccer_goal_target; } bool hasSqlManagement() const { return m_sql_management; } float getStartGameCounter() const { return m_start_game_counter; } @@ -160,18 +163,8 @@ class LobbySettings: public LobbyContextComponent bool isValidatingPlayer() const { return m_validating_player; } float getVotingTimeout() const { return m_voting_timeout; } std::string getCommandsFile() const { return m_commands_file; } - int getAddonKartsJoinThreshold() const { return m_addon_karts_join_threshold; } - int getAddonTracksJoinThreshold() const { return m_addon_tracks_join_threshold; } - int getAddonArenasJoinThreshold() const { return m_addon_arenas_join_threshold; } - int getAddonSoccersJoinThreshold() const { return m_addon_soccers_join_threshold; } - int getAddonKartsPlayThreshold() const { return m_addon_karts_play_threshold; } - int getAddonTracksPlayThreshold() const { return m_addon_tracks_play_threshold; } - int getAddonArenasPlayThreshold() const { return m_addon_arenas_play_threshold; } - int getAddonSoccersPlayThreshold() const { return m_addon_soccers_play_threshold; } std::string getPowerPassword() const { return m_power_password; } std::string getRegisterTableName() const { return m_register_table_name; } - float getOfficialKartsThreshold() const { return m_official_karts_threshold; } - float getOfficialTracksThreshold() const { return m_official_tracks_threshold; } int getLobbyCooldown() const { return m_lobby_cooldown; } // This one might not get into the config (as it originated from official @@ -187,8 +180,6 @@ class LobbySettings: public LobbyContextComponent float m_battle_time_limit; - std::vector m_play_requirement_tracks; - std::set m_config_available_tracks; std::map> m_config_track_limitations; @@ -203,10 +194,6 @@ class LobbySettings: public LobbyContextComponent std::set m_available_modes; - TrackFilter m_global_filter; - - KartFilter m_global_karts_filter; - int m_fixed_lap; int m_fixed_direction; @@ -242,10 +229,6 @@ class LobbySettings: public LobbyContextComponent bool m_kicks_allowed; int m_max_ping; int m_min_start_game_players; - float m_official_karts_play_threshold; - float m_official_tracks_play_threshold; - bool m_only_host_riding; - bool m_owner_less; bool m_preserve_battle_scores; std::string m_private_server_password; bool m_ranked; @@ -255,7 +238,6 @@ class LobbySettings: public LobbyContextComponent int m_server_difficulty; int m_server_max_players; int m_server_mode; - bool m_sleeping_server; bool m_soccer_goal_target; bool m_sql_management; float m_start_game_counter; @@ -271,20 +253,12 @@ class LobbySettings: public LobbyContextComponent bool m_validating_player; float m_voting_timeout; std::string m_commands_file; - int m_addon_karts_join_threshold; - int m_addon_tracks_join_threshold; - int m_addon_arenas_join_threshold; - int m_addon_soccers_join_threshold; - int m_addon_arenas_play_threshold; - int m_addon_karts_play_threshold; - int m_addon_soccers_play_threshold; - int m_addon_tracks_play_threshold; std::string m_power_password; std::string m_register_table_name; - float m_official_karts_threshold; - float m_official_tracks_threshold; int m_lobby_cooldown; + bool m_save_server_config; + // Special, temporarily public public: @@ -296,6 +270,10 @@ class LobbySettings: public LobbyContextComponent // Special, temporarily public END private: + unsigned m_current_max_players_in_game; + + std::set m_temp_banned; + // These should be moved to voting manager ==================================== // Default game settings if no one has ever vote, and save inside here for diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp index dbf38475e2f..9f17f033686 100644 --- a/src/utils/team_manager.cpp +++ b/src/utils/team_manager.cpp @@ -18,18 +18,19 @@ #include "utils/team_manager.hpp" -#include "utils/team_utils.hpp" -#include "network/remote_kart_info.hpp" #include "network/network_player_profile.hpp" #include "network/protocols/server_lobby.hpp" -#include "utils/string_utils.hpp" +#include "network/protocols/server_lobby.hpp" +#include "network/remote_kart_info.hpp" #include "network/server_config.hpp" #include "network/stk_host.hpp" #include "network/stk_peer.hpp" +#include "utils/crown_manager.hpp" #include "utils/lobby_gp_manager.hpp" #include "utils/lobby_settings.hpp" +#include "utils/string_utils.hpp" +#include "utils/team_utils.hpp" #include "utils/tournament.hpp" -#include "network/protocols/server_lobby.hpp" void TeamManager::setupContextUser() { @@ -67,7 +68,7 @@ void TeamManager::setTeamInLobby(std::shared_ptr profile, profile->getTemporaryTeam() ); - getLobby()->checkNoTeamSpectator(profile->getPeer()); + checkNoTeamSpectator(profile->getPeer()); } // setTeamInLobby //----------------------------------------------------------------------------- @@ -84,7 +85,7 @@ void TeamManager::setTemporaryTeamInLobby(std::shared_ptr profile->getTemporaryTeam() ); - getLobby()->checkNoTeamSpectator(profile->getPeer()); + checkNoTeamSpectator(profile->getPeer()); } // setTemporaryTeamInLobby //----------------------------------------------------------------------------- @@ -269,7 +270,7 @@ void TeamManager::changeTeam(std::shared_ptr player) auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); if (isTournament() && !getTournament()->canChangeTeam()) { - Log::info("ServerLobby", "Team change requested by %s, but tournament forbids it.", player->getName().c_str()); + Log::info("TeamManager", "Team change requested by %s, but tournament forbids it.", player->getName().c_str()); return; } @@ -292,4 +293,31 @@ void TeamManager::changeTeam(std::shared_ptr player) setTeamInLobby(player, KART_TEAM_BLUE); } getLobby()->updatePlayerList(); -} \ No newline at end of file +} // changeTeam +//----------------------------------------------------------------------------- + +void TeamManager::checkNoTeamSpectator(std::shared_ptr peer) +{ + if (!peer) + return; + + if (RaceManager::get()->teamEnabled()) + { + bool has_teamed = false; + for (auto& other: peer->getPlayerProfiles()) + { + if (other->getTeam() != KART_TEAM_NONE) + { + has_teamed = true; + break; + } + } + + if (!has_teamed && peer->getAlwaysSpectate() == ASM_NONE) + getCrownManager()->setSpectateModeProperly(peer, ASM_NO_TEAM); + + if (has_teamed && peer->getAlwaysSpectate() == ASM_NO_TEAM) + getCrownManager()->setSpectateModeProperly(peer, ASM_NONE); + } +} // checkNoTeamSpectator +//----------------------------------------------------------------------------- diff --git a/src/utils/team_manager.hpp b/src/utils/team_manager.hpp index cef177b811a..8cedb48e728 100644 --- a/src/utils/team_manager.hpp +++ b/src/utils/team_manager.hpp @@ -30,6 +30,7 @@ enum KartTeam: int8_t; class NetworkPlayerProfile; +class STKPeer; class TeamManager: public LobbyContextComponent { @@ -69,6 +70,9 @@ class TeamManager: public LobbyContextComponent void shuffleTemporaryTeams(const std::map& permutation); void changeTeam(std::shared_ptr player); + // The functions below reset/set ASM_NO_TEAM if needed by team changing procedure. + void checkNoTeamSpectator(std::shared_ptr peer); + private: std::string m_available_teams; From cae443aca0a410d783a35cda0f9a13a88db7f3bd Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 24 Mar 2025 01:09:14 +0400 Subject: [PATCH 631/830] Get rid of m_result_ns and simplify calls to GameSetup --- src/network/protocols/command_manager.cpp | 8 ++-- src/network/protocols/server_lobby.cpp | 45 +++++++++++++---------- src/network/protocols/server_lobby.hpp | 7 +--- src/utils/lobby_context.cpp | 1 + src/utils/lobby_context.hpp | 5 +++ src/utils/lobby_gp_manager.cpp | 10 ++--- src/utils/lobby_settings.cpp | 2 +- 7 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index ad2d0c60818..120863497a7 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -1130,7 +1130,7 @@ void CommandManager::process_config(Context& context) } int difficulty = getLobby()->getDifficulty(); int mode = getLobby()->getGameMode(); - bool goal_target = (getLobby()->getGameSetup()->hasExtraServerInfo() ? getLobby()->isSoccerGoalTarget() : false); + bool goal_target = (getGameSetupFromCtx()->hasExtraServerInfo() ? getLobby()->isSoccerGoalTarget() : false); // m_aux_goal_aliases[goal_target ? 1 : 0][0] std::string msg = "Current config: "; auto get_first_if_exists = [&](std::vector& v) -> std::string { @@ -1161,7 +1161,7 @@ void CommandManager::process_config_assign(Context& context) const auto& argv = context.m_argv; int difficulty = getLobby()->getDifficulty(); int mode = getLobby()->getGameMode(); - bool goal_target = (getLobby()->getGameSetup()->hasExtraServerInfo() ? getLobby()->isSoccerGoalTarget() : false); + bool goal_target = (getGameSetupFromCtx()->hasExtraServerInfo() ? getLobby()->isSoccerGoalTarget() : false); bool user_chose_difficulty = false; bool user_chose_mode = false; bool user_chose_target = false; @@ -2196,7 +2196,7 @@ void CommandManager::process_standings(Context& context) } if (!isGP && !isGnu) { - if (getLobby()->getGameSetup()->isGrandPrix()) + if (getGameSetupFromCtx()->isGrandPrix()) isGP = true; else isGnu = true; @@ -2904,7 +2904,7 @@ void CommandManager::process_resetgp(Context& context) error(context); return; } - getLobby()->getGameSetup()->setGrandPrixTrack(number_of_games); + getGameSetupFromCtx()->setGrandPrixTrack(number_of_games); } getGPManager()->resetGrandPrix(); getLobby()->sendStringToAllPeers("GP is now reset"); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 909d71e9302..201c5e44b51 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -220,6 +220,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_lobby_context->setup(); m_context = m_lobby_context.get(); m_game_setup->setContext(m_context); + m_context->setGameSetup(m_game_setup); m_current_ai_count.store(0); @@ -238,8 +239,6 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_ranking = std::make_shared(); } - m_result_ns = getNetworkString(); - m_result_ns->setSynchronous(true); m_items_complete_state = new BareNetworkString(); m_server_id_online.store(0); m_difficulty.store(ServerConfig::m_server_difficulty); @@ -263,7 +262,6 @@ ServerLobby::~ServerLobby() // For child process the request manager will keep on running unregisterServer(m_process_type == PT_MAIN ? true : false/*now*/); } - delete m_result_ns; delete m_items_complete_state; if (getSettings()->isSavingServerConfig()) ServerConfig::writeServerConfigToDisk(); @@ -1574,6 +1572,8 @@ void ServerLobby::update(int ticks) handlePlayerDisconnection(); + NetworkString* ns; + switch (m_state.load()) { case SET_PUBLIC_ADDRESS: @@ -1601,7 +1601,7 @@ void ServerLobby::update(int ticks) if (World::getWorld() && RaceEventManager::get() && RaceEventManager::get()->isRunning()) { - checkRaceFinished(); + checkRaceFinished(ns); } break; case WAIT_FOR_RACE_STOPPED: @@ -1617,7 +1617,8 @@ void ServerLobby::update(int ticks) // result screen and go back to the lobby setTimeoutFromNow(15); m_state = RESULT_DISPLAY; - sendMessageToPeers(m_result_ns, PRM_RELIABLE); + sendMessageToPeers(ns, PRM_RELIABLE); + delete ns; Log::info("ServerLobby", "End of game message sent"); break; case RESULT_DISPLAY: @@ -2072,7 +2073,7 @@ void ServerLobby::checkIncomingConnectionRequests() * to state RESULT_DISPLAY, during which the race result gui is shown and all * clients can click on 'continue'. */ -void ServerLobby::checkRaceFinished() +void ServerLobby::checkRaceFinished(NetworkString* result) { assert(RaceEventManager::get()->isRunning()); assert(World::getWorld()); @@ -2095,19 +2096,20 @@ void ServerLobby::checkRaceFinished() GameProtocol::lock()->requestTerminate(); // Save race result before delete the world - m_result_ns->clear(); - m_result_ns->addUInt8(LE_RACE_FINISHED); + result = getNetworkString(); + result->setSynchronous(true); + result->addUInt8(LE_RACE_FINISHED); std::vector gp_changes; if (m_game_setup->isGrandPrix()) { - getGPManager()->updateGPScores(gp_changes, m_result_ns); + getGPManager()->updateGPScores(gp_changes, result); } else if (RaceManager::get()->modeHasLaps()) { int fastest_lap = static_cast(World::getWorld())->getFastestLapTicks(); - m_result_ns->addUInt32(fastest_lap); - m_result_ns->encodeString(static_cast(World::getWorld()) + result->addUInt32(fastest_lap); + result->encodeString(static_cast(World::getWorld()) ->getFastestLapKartName()); } @@ -2116,7 +2118,7 @@ void ServerLobby::checkRaceFinished() ranking_changes_indication = 1; if (m_game_setup->isGrandPrix()) ranking_changes_indication = 1; - m_result_ns->addUInt8(ranking_changes_indication); + result->addUInt8(ranking_changes_indication); if (getKartElimination()->isEnabled()) { @@ -2132,16 +2134,16 @@ void ServerLobby::checkRaceFinished() if (getSettings()->isRanked()) { - computeNewRankings(); + computeNewRankings(result); submitRankingsToAddons(); } else if (m_game_setup->isGrandPrix()) { unsigned player_count = RaceManager::get()->getNumPlayers(); - m_result_ns->addUInt8((uint8_t)player_count); + result->addUInt8((uint8_t)player_count); for (unsigned i = 0; i < player_count; i++) { - m_result_ns->addFloat(gp_changes[i]); + result->addFloat(gp_changes[i]); } } m_state.store(WAIT_FOR_RACE_STOPPED); @@ -2155,7 +2157,7 @@ void ServerLobby::checkRaceFinished() /** Compute the new player's rankings used in ranked servers */ -void ServerLobby::computeNewRankings() +void ServerLobby::computeNewRankings(NetworkString* ns) { // No ranking for battle mode if (!RaceManager::get()->modeHasLaps()) @@ -2193,12 +2195,12 @@ void ServerLobby::computeNewRankings() } // Used to display rating change at the end of a race - m_result_ns->addUInt8((uint8_t)player_count); + ns->addUInt8((uint8_t)player_count); for (unsigned i = 0; i < player_count; i++) { const uint32_t id = RaceManager::get()->getKartInfo(i).getOnlineId(); double change = m_ranking->getDelta(id); - m_result_ns->addFloat((float)change); + ns->addFloat((float)change); } } // computeNewRankings //----------------------------------------------------------------------------- @@ -4227,7 +4229,6 @@ void ServerLobby::updateGnuElimination() //----------------------------------------------------------------------------- void ServerLobby::storeResults() { -#ifdef ENABLE_SQLITE3 World* w = World::getWorld(); if (!w) return; @@ -4301,7 +4302,9 @@ void ServerLobby::storeResults() if (racing_mode) { +#ifdef ENABLE_SQLITE3 record_fetched = m_db_connector->getBestResult(*m_game_info, &record_exists, &best_user, &best_result); +#endif } int best_cur_player_idx = -1; @@ -4444,7 +4447,10 @@ void ServerLobby::storeResults() // ffa: elapsed_string << std::setprecision(0) << std::fixed << score; m_game_info->m_saved_ffa_points.clear(); + +#ifdef ENABLE_SQLITE3 m_db_connector->insertManyResults(*m_game_info); +#endif // end of insertions if (record_fetched && best_cur_player_idx != -1) // implies racing_mode { @@ -4465,7 +4471,6 @@ void ServerLobby::storeResults() if (!message.empty()) sendStringToAllPeers(message); } -#endif } // storeResults //----------------------------------------------------------------------------- void ServerLobby::resetToDefaultSettings() diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index baf9d59d4a9..36c3cda667f 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -149,9 +149,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser std::map m_pending_peer_connection; - /* Saved the last game result */ - NetworkString* m_result_ns; - /* Used to make sure clients are having same item list at start */ BareNetworkString* m_items_complete_state; @@ -248,8 +245,8 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser bool handleAllVotes(PeerVote* winner); void getRankingForPlayer(std::shared_ptr p); void submitRankingsToAddons(); - void computeNewRankings(); - void checkRaceFinished(); + void computeNewRankings(NetworkString* ns); + void checkRaceFinished(NetworkString* result); void getHitCaptureLimit(); void configPeersStartTime(); void resetServer(); diff --git a/src/utils/lobby_context.cpp b/src/utils/lobby_context.cpp index 786c366b48f..65649b4384c 100644 --- a/src/utils/lobby_context.cpp +++ b/src/utils/lobby_context.cpp @@ -31,6 +31,7 @@ #include "utils/lobby_gp_manager.hpp" #include "utils/gp_scoring.hpp" #include "utils/crown_manager.hpp" +#include "network/game_setup.hpp" LobbyContext::LobbyContext(ServerLobby* lobby, bool make_tournament) : m_lobby(lobby) diff --git a/src/utils/lobby_context.hpp b/src/utils/lobby_context.hpp index bec9d0822de..68335aca103 100644 --- a/src/utils/lobby_context.hpp +++ b/src/utils/lobby_context.hpp @@ -36,11 +36,13 @@ class TeamManager; class Tournament; class LobbyGPManager; class CrownManager; +class GameSetup; class LobbyContext { private: ServerLobby* m_lobby; + GameSetup* m_game_setup; std::shared_ptr m_hit_processor; std::shared_ptr m_asset_manager; std::shared_ptr m_tournament; @@ -59,8 +61,10 @@ class LobbyContext LobbyContext(ServerLobby* lobby, bool make_tournament); void setup(); + void setGameSetup(GameSetup* game_setup) { m_game_setup = game_setup; } ServerLobby* getLobby() const { return m_lobby; } + GameSetup* getGameSetup() const { return m_game_setup; } std::shared_ptr getHitProcessor() const { return m_hit_processor; } std::shared_ptr getAssetManager() const { return m_asset_manager; } bool isTournament() const { return m_tournament.get() != nullptr; } @@ -81,6 +85,7 @@ class LobbyContextUser protected: LobbyContext* m_context; ServerLobby* getLobby() const { return m_context->getLobby(); } + GameSetup* getGameSetupFromCtx() const { return m_context->getGameSetup(); } std::shared_ptr getHitProcessor() const { return m_context->getHitProcessor(); } std::shared_ptr getAssetManager() const { return m_context->getAssetManager(); } bool isTournament() const { return m_context->isTournament(); } diff --git a/src/utils/lobby_gp_manager.cpp b/src/utils/lobby_gp_manager.cpp index 601856b90ce..874122aec36 100644 --- a/src/utils/lobby_gp_manager.cpp +++ b/src/utils/lobby_gp_manager.cpp @@ -40,7 +40,7 @@ void LobbyGPManager::setupContextUser() void LobbyGPManager::onStartSelection() { - if (!getLobby()->getGameSetup()->isGrandPrixStarted()) + if (!getGameSetupFromCtx()->isGrandPrixStarted()) { m_gp_scores.clear(); m_gp_team_scores.clear(); @@ -51,7 +51,7 @@ void LobbyGPManager::onStartSelection() void LobbyGPManager::setScoresToPlayer(std::shared_ptr player) const { std::string username = StringUtils::wideToUtf8(player->getName()); - if (getLobby()->getGameSetup()->isGrandPrix()) + if (getGameSetupFromCtx()->isGrandPrix()) { auto it = m_gp_scores.find(username); if (it != m_gp_scores.end()) @@ -76,7 +76,7 @@ std::string LobbyGPManager::getGrandPrixStandings(bool showIndividual, bool show showTeam = true; } - auto game_setup = getLobby()->getGameSetup(); + auto game_setup = getGameSetupFromCtx(); int passed = (int)game_setup->getAllTracks().size(); bool ongoing = false; if (getLobby()->isWorldPicked() && !getLobby()->isWorldFinished()) @@ -141,7 +141,7 @@ void LobbyGPManager::resetGrandPrix() { m_gp_scores.clear(); m_gp_team_scores.clear(); - getLobby()->getGameSetup()->stopGrandPrix(); + getGameSetupFromCtx()->stopGrandPrix(); getLobby()->sendServerInfoToEveryone(); getLobby()->updatePlayerList(); @@ -174,7 +174,7 @@ void LobbyGPManager::updateGPScores(std::vector& gp_changes, NetworkStrin std::string fastest_kart = StringUtils::wideToUtf8(fastest_kart_wide); // all gp tracks - auto game_setup = getLobby()->getGameSetup(); + auto game_setup = getGameSetupFromCtx(); int points_fl = 0; // Commented until used to remove the warning diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index a9286e89aec..6b196fd2e13 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -43,7 +43,7 @@ void LobbySettings::setupContextUser() { - m_game_setup = getLobby()->getGameSetup(); + m_game_setup = getGameSetupFromCtx(); m_motd = StringUtils::wideToUtf8( m_game_setup->readOrLoadFromFile( From a7c1a0eee93cc5370fc3cfc424eb0709fa27eba5 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 25 Mar 2025 21:15:50 +0400 Subject: [PATCH 632/830] Minor cleanups, mostly in TeamManager --- src/network/protocols/command_manager.cpp | 13 +++-- src/network/protocols/server_lobby.cpp | 2 +- src/network/protocols/server_lobby.hpp | 2 +- src/network/stk_host.cpp | 4 +- src/utils/team_manager.cpp | 63 +++++++++++++++-------- src/utils/team_manager.hpp | 22 +++++--- src/utils/tournament.cpp | 4 +- 7 files changed, 70 insertions(+), 40 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 120863497a7..c3d384bc9fd 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2956,13 +2956,16 @@ void CommandManager::process_cat(Context& context) } if (argv[0] == "catshow") { - int displayed; + int displayed = -1; // Validation should happen in LS - if (argv.size() != 3 || !StringUtils::parseString(argv[2], &displayed) - || displayed < 0 || displayed > 1) + if (argv.size() >= 2) { - error(context); - return; + if (argv.size() != 3 || !StringUtils::parseString(argv[2], &displayed) + || displayed < -1 || displayed > 1) + { + error(context); + return; + } } std::string category = argv[1]; getTeamManager()->makeCategoryVisible(category, displayed); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 201c5e44b51..6c269eebdcb 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2073,7 +2073,7 @@ void ServerLobby::checkIncomingConnectionRequests() * to state RESULT_DISPLAY, during which the race result gui is shown and all * clients can click on 'continue'. */ -void ServerLobby::checkRaceFinished(NetworkString* result) +void ServerLobby::checkRaceFinished(NetworkString*& result) { assert(RaceEventManager::get()->isRunning()); assert(World::getWorld()); diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 36c3cda667f..f93a52837d9 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -246,7 +246,7 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser void getRankingForPlayer(std::shared_ptr p); void submitRankingsToAddons(); void computeNewRankings(NetworkString* ns); - void checkRaceFinished(NetworkString* result); + void checkRaceFinished(NetworkString*& result); void getHitCaptureLimit(); void configPeersStartTime(); void resetServer(); diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index 95306516820..db1ff5dcfed 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -1464,8 +1464,8 @@ std::shared_ptr STKHost::findPeerByHostId(uint32_t id) const }); return ret != m_peers.end() ? ret->second : nullptr; } // findPeerByHostId - //----------------------------------------------------------------------------- + std::shared_ptr STKHost::findPeerByName(const core::stringw& name) const { @@ -1486,8 +1486,8 @@ std::shared_ptr }); return ret != m_peers.end() ? ret->second : nullptr; } // findPeerByName - //----------------------------------------------------------------------------- + std::shared_ptr STKHost::findPeerByWildcard(const core::stringw& name_pattern, std::string& name_found) const { diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp index 9f17f033686..d764e91dc39 100644 --- a/src/utils/team_manager.cpp +++ b/src/utils/team_manager.cpp @@ -20,7 +20,6 @@ #include "network/network_player_profile.hpp" #include "network/protocols/server_lobby.hpp" -#include "network/protocols/server_lobby.hpp" #include "network/remote_kart_info.hpp" #include "network/server_config.hpp" #include "network/stk_host.hpp" @@ -32,6 +31,11 @@ #include "utils/team_utils.hpp" #include "utils/tournament.hpp" +namespace +{ + static const std::set empty_string_set = {}; +} + void TeamManager::setupContextUser() { m_available_teams = ServerConfig::m_init_available_teams; @@ -42,17 +46,19 @@ void TeamManager::setupContextUser() void TeamManager::setTemporaryTeamInLobby(const std::string& username, int team) { irr::core::stringw wide_player_name = StringUtils::utf8ToWide(username); - std::shared_ptr player_peer = STKHost::get()->findPeerByName( - wide_player_name); - if (player_peer) + + // kimden: this code, as well as findPeerByName, assumes (wrongly) that + // there cannot be two profiles with the same name. Fix that pls. + std::shared_ptr player_peer = STKHost::get()->findPeerByName(wide_player_name); + if (!player_peer) + return; + + for (auto& profile : player_peer->getPlayerProfiles()) { - for (auto& profile : player_peer.get()->getPlayerProfiles()) + if (profile->getName() == wide_player_name) { - if (profile->getName() == wide_player_name) - { - getTeamManager()->setTemporaryTeamInLobby(profile, team); - break; - } + getTeamManager()->setTemporaryTeamInLobby(profile, team); + break; } } } // setTemporaryTeamInLobby (username) @@ -72,14 +78,17 @@ void TeamManager::setTeamInLobby(std::shared_ptr profile, } // setTeamInLobby //----------------------------------------------------------------------------- -void TeamManager::setTemporaryTeamInLobby(std::shared_ptr profile, int team) +// Used for racing + FFA, where everything can be defined by a temporary team +void TeamManager::setTemporaryTeamInLobby( + std::shared_ptr profile, int team) { - // Used for racing+FFA, where everything can be defined by a temporary team profile->setTemporaryTeam(team); + if (RaceManager::get()->teamEnabled()) profile->setTeam((KartTeam)(TeamUtils::getKartTeamFromIndex(team))); else profile->setTeam(KART_TEAM_NONE); + setTeamForUsername( StringUtils::wideToUtf8(profile->getName()), profile->getTemporaryTeam() @@ -164,22 +173,34 @@ void TeamManager::initCategories() } // initCategories //----------------------------------------------------------------------------- -void TeamManager::addPlayerToCategory(const std::string& player, const std::string& category) +void TeamManager::addPlayerToCategory( + const std::string& player, const std::string& category) { m_player_categories[category].insert(player); m_categories_for_player[player].insert(category); } // addPlayerToCategory //----------------------------------------------------------------------------- -void TeamManager::erasePlayerFromCategory(const std::string& player, const std::string& category) +void TeamManager::erasePlayerFromCategory( + const std::string& player, const std::string& category) { - m_player_categories[category].erase(player); - m_categories_for_player[player].erase(category); + auto& container_for_categ = m_player_categories[category]; + auto& container_for_player = m_categories_for_player[player]; + + container_for_categ.erase(player); + container_for_player.erase(category); + + if (container_for_categ.empty()) + m_player_categories.erase(category); + + if (container_for_player.empty()) + m_categories_for_player.erase(player); } // erasePlayerFromCategory //----------------------------------------------------------------------------- -void TeamManager::makeCategoryVisible(const std::string category, bool value) +void TeamManager::makeCategoryVisible(const std::string category, int value) { + m_hidden_categories.set(category, value); if (value) { m_hidden_categories.erase(category); } else { @@ -194,7 +215,8 @@ bool TeamManager::isCategoryVisible(const std::string category) const } // isCategoryVisible //----------------------------------------------------------------------------- -std::vector TeamManager::getVisibleCategoriesForPlayer(const std::string& profile_name) const +std::vector TeamManager::getVisibleCategoriesForPlayer( + const std::string& profile_name) const { auto it = m_categories_for_player.find(profile_name); if (it == m_categories_for_player.end()) @@ -209,12 +231,11 @@ std::vector TeamManager::getVisibleCategoriesForPlayer(const std::s } // getVisibleCategoriesForPlayer //----------------------------------------------------------------------------- - -std::set TeamManager::getPlayersInCategory(const std::string& category) const +const std::set& TeamManager::getPlayersInCategory(const std::string& category) const { auto it = m_player_categories.find(category); if (it == m_player_categories.end()) - return {}; + return empty_string_set; return it->second; } // getPlayersInCategory diff --git a/src/utils/team_manager.hpp b/src/utils/team_manager.hpp index 8cedb48e728..30fed9b71d4 100644 --- a/src/utils/team_manager.hpp +++ b/src/utils/team_manager.hpp @@ -21,6 +21,7 @@ #include "irrString.h" #include "utils/lobby_context.hpp" +#include "utils/set_with_flip.hpp" #include "utils/types.hpp" #include @@ -46,26 +47,33 @@ class TeamManager: public LobbyContextComponent void setTemporaryTeamInLobby(std::shared_ptr profile, int team); void applyPermutationToTeams(const std::map& permutation); std::string getAvailableTeams() const; - std::map> getCategories() const - { return m_player_categories; } void initCategories(); void addPlayerToCategory(const std::string& player, const std::string& category); void erasePlayerFromCategory(const std::string& player, const std::string& category); - void makeCategoryVisible(const std::string category, bool value); + void makeCategoryVisible(const std::string category, int value); bool isCategoryVisible(const std::string category) const; - std::vector getVisibleCategoriesForPlayer(const std::string& profile_name) const; - std::set getPlayersInCategory(const std::string& category) const; + + std::vector getVisibleCategoriesForPlayer( + const std::string& profile_name) const; + + const std::set& getPlayersInCategory( + const std::string& category) const; + std::string getInternalAvailableTeams() const { return m_available_teams; } void setInternalAvailableTeams(std::string& s) { m_available_teams = s; } + void setTeamForUsername(const std::string& name, int team) { m_team_for_player[name] = team; } + int getTeamForUsername(const std::string& name); void clearTeams() { m_team_for_player.clear(); } + bool hasTeam(const std::string& name) { return m_team_for_player.find(name) != m_team_for_player.end(); } bool isInHammerWhitelist(const std::string& str) const { return m_hammer_whitelist.find(str) != m_hammer_whitelist.end(); } + void clearTemporaryTeams(); void shuffleTemporaryTeams(const std::map& permutation); void changeTeam(std::shared_ptr player); @@ -79,9 +87,7 @@ class TeamManager: public LobbyContextComponent std::map> m_player_categories; - std::set m_hidden_categories; - - std::set m_special_categories; + SetWithFlip m_hidden_categories; std::map> m_categories_for_player; diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp index 7fde6f8b040..5c5e524facf 100644 --- a/src/utils/tournament.cpp +++ b/src/utils/tournament.cpp @@ -221,8 +221,8 @@ void Tournament::initTournamentPlayers() type == "B" ? m_blue_players : m_referees); - auto categories = getTeamManager()->getCategories(); - for (const std::string& member: categories[cat_name]) + const auto& players = getTeamManager()->getPlayersInCategory(cat_name); + for (const std::string& member: players) dest.insert(member); } else if (type == "R") From 6e825020241772e12d9a5a408c9f3394f8a1fb54 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 25 Mar 2025 22:30:09 +0400 Subject: [PATCH 633/830] Most hasTypo -> validate, remove extra GameInfo from LobbySettings and other minor cleanups for CommandManager. At least some of affected commands seem to work. --- src/network/protocols/command_manager.cpp | 146 +++++++--------------- src/network/protocols/command_manager.hpp | 18 ++- src/network/protocols/server_lobby.cpp | 2 +- src/utils/lobby_settings.cpp | 9 +- src/utils/lobby_settings.hpp | 1 - src/utils/team_manager.cpp | 70 +++++++++++ src/utils/team_manager.hpp | 2 + 7 files changed, 136 insertions(+), 112 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index c3d384bc9fd..34f252fda08 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -231,6 +231,18 @@ CommandManager::Command::Command(std::string name, } // Command::Command(5) // ======================================================================== +const SetTypoFixer& CommandManager::getFixer(TypoFixerType type) +{ + switch (type) + { + case TFT_PRESENT_USERS: return m_stf_present_users; + case TFT_ALL_MAPS: return m_stf_all_maps; + case TFT_ADDON_MAPS: return m_stf_addon_maps; + } + throw std::logic_error("Invalid TypoFixerType " + std::to_string(type)); +} // getFixer +//----------------------------------------------------------------------------- + // From the result perspective, it works in the same way as // ServerConfig - just as there, there can be two files, one of them // overriding another. However, I'm right now lazy to make them use the @@ -1432,8 +1444,7 @@ void CommandManager::process_checkaddon(Context& context) error(context); return; } - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 1, m_stf_addon_maps, 3, false, true)) + if (!validate(context, 1, TFT_ADDON_MAPS, false, true)) return; std::string id = argv[1]; const unsigned HAS_KART = 1; @@ -1551,8 +1562,7 @@ void CommandManager::process_id(Context& context) error(context); return; } - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 1, m_stf_all_maps, 3, false, true)) + if (!validate(context, 1, TFT_ALL_MAPS, false, true)) return; getLobby()->sendStringToPeer(peer, "Server knows this map, copy it below:\n" + argv[1]); @@ -1657,11 +1667,9 @@ void CommandManager::process_pha(Context& context) return; } - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 1, m_stf_addon_maps, 3, false, true)) + if (!validate(context, 1, TFT_ADDON_MAPS, false, true)) return; - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 2, m_stf_present_users, 3, false, false)) + if (!validate(context, 2, TFT_PRESENT_USERS, false, false)) return; std::string addon_id = argv[1]; @@ -1713,8 +1721,7 @@ void CommandManager::process_kick(Context& context) return; } - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 1, m_stf_present_users, 3, false, false)) + if (!validate(context, 1, TFT_PRESENT_USERS, false, false)) return; std::string player_name = argv[1]; @@ -1833,8 +1840,7 @@ void CommandManager::process_pas(Context& context) } else { - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 1, m_stf_present_users, 3, false, false)) + if (!validate(context, 1, TFT_PRESENT_USERS, false, false)) return; player_name = argv[1]; } @@ -2000,11 +2006,9 @@ void CommandManager::process_mute(Context& context) return; } - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 1, m_stf_present_users, 3, false, false)) + if (!validate(context, 1, TFT_PRESENT_USERS, false, false)) return; - std::string player_name = argv[1]; player_peer = STKHost::get()->findPeerByName(StringUtils::utf8ToWide(player_name)); @@ -2243,8 +2247,7 @@ void CommandManager::process_to(Context& context) std::vector receivers; for (unsigned i = 1; i < argv.size(); ++i) { - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - i, m_stf_present_users, 3, false, true)) + if (!validate(context, i, TFT_PRESENT_USERS, false, true)) return; receivers.push_back(argv[i]); } @@ -2283,9 +2286,10 @@ void CommandManager::process_record(Context& context) return; } bool error = false; - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 1, m_stf_all_maps, 3, false, true)) + + if (!validate(context, 1, TFT_ALL_MAPS, false, true)) return; + // todo replace with available aliases? std::string track_name = argv[1]; std::string mode_name = (argv[2] == "t" || argv[2] == "tt" @@ -2760,8 +2764,7 @@ void CommandManager::process_team(Context& context) error(context); return; } - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 2, m_stf_present_users, 3, false, true)) + if (!validate(context, 2, TFT_PRESENT_USERS, false, true)) return; std::string player = argv[2]; @@ -2877,7 +2880,7 @@ void CommandManager::process_randomteams(Context& context) vote(context, "randomteams", ""); return; } - if (!assignRandomTeams(teams_number, &final_number, &players_number)) + if (!getTeamManager()->assignRandomTeams(teams_number, &final_number, &players_number)) { std::string msg; if (players_number == 0) @@ -2929,8 +2932,7 @@ void CommandManager::process_cat(Context& context) return; } std::string category = argv[1]; - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 2, m_stf_present_users, 3, false, true)) + if (!validate(context, 2, TFT_PRESENT_USERS, false, true)) return; std::string player = argv[2]; getTeamManager()->addPlayerToCategory(player, category); @@ -2946,8 +2948,7 @@ void CommandManager::process_cat(Context& context) } std::string category = argv[1]; std::string player = argv[2]; - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 2, m_stf_present_users, 3, false, true)) + if (!validate(context, 2, TFT_PRESENT_USERS, false, true)) return; player = argv[2]; getTeamManager()->erasePlayerFromCategory(player, category); @@ -3289,8 +3290,7 @@ void CommandManager::process_role(Context& context) { swap(argv[1], argv[2]); } - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 2, m_stf_present_users, 3, false, true)) + if (!validate(context, 2, TFT_PRESENT_USERS, false, true)) return; std::string role = argv[1]; std::string username = argv[2]; @@ -3715,8 +3715,7 @@ void CommandManager::process_history_assign(Context& context) error(context); return; } - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 2, m_stf_all_maps, 3, false, false)) + if (!validate(context, 2, TFT_ALL_MAPS, false, false)) return; std::string id = argv[2]; if (!tournament->assignToHistory(index, id)) @@ -3794,8 +3793,7 @@ void CommandManager::process_why_hourglass(Context& context) } else { - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, - 1, m_stf_present_users, 3, false, false)) + if (!validate(context, 1, TFT_PRESENT_USERS, false, false)) return; player_name = argv[1]; } @@ -3966,74 +3964,6 @@ void CommandManager::special(Context& context) } // special // ======================================================================== -bool CommandManager::assignRandomTeams(int intended_number, - int* final_number, int* final_player_number) -{ - int teams_number = intended_number; - *final_number = teams_number; - int player_number = 0; - for (auto& p : STKHost::get()->getPeers()) - { - if (!getCrownManager()->canRace(p)) - continue; - if (p->alwaysSpectateButNotNeutral()) - continue; - player_number += p->getPlayerProfiles().size(); - } - if (player_number == 0) { - *final_number = teams_number; - *final_player_number = player_number; - return false; - } - int max_number_of_teams = TeamUtils::getNumberOfTeams(); - std::string available_colors_string = getTeamManager()->getAvailableTeams(); - if (available_colors_string.empty()) - return false; - if (max_number_of_teams > (int)available_colors_string.length()) - max_number_of_teams = (int)available_colors_string.length(); - if (teams_number == -1 || teams_number < 1 || teams_number > max_number_of_teams) - { - teams_number = (int)round(sqrt(player_number)); - if (teams_number > max_number_of_teams) - teams_number = max_number_of_teams; - if (player_number > 1 && teams_number <= 1 && max_number_of_teams >= 2) - teams_number = 2; - } - - *final_number = teams_number; - *final_player_number = player_number; - std::vector available_colors; - std::vector profile_colors; - for (const char& c: available_colors_string) - available_colors.push_back(TeamUtils::getIndexByCode(std::string(1, c))); - - std::random_device rd; - std::mt19937 g(rd()); - std::shuffle(available_colors.begin(), available_colors.end(), g); - available_colors.resize(teams_number); - - for (int i = 0; i < player_number; ++i) - profile_colors.push_back(available_colors[i % teams_number]); - - std::shuffle(profile_colors.begin(), profile_colors.end(), g); - - getTeamManager()->clearTemporaryTeams(); - for (auto& p : STKHost::get()->getPeers()) - { - if (!getCrownManager()->canRace(p)) - continue; - if (p->alwaysSpectateButNotNeutral()) - continue; - for (auto& profile : p->getPlayerProfiles()) { - getTeamManager()->setTemporaryTeamInLobby(profile, profile_colors.back()); - if (profile_colors.size() > 1) // prevent crash just in case - profile_colors.pop_back(); - } - } - return true; -} // assignRandomTeams -// ======================================================================== - void CommandManager::addUser(std::string& s) { m_users.insert(s); @@ -4082,12 +4012,24 @@ void CommandManager::restoreCmdByArgv(std::string& cmd, cmd.push_back(e); } } -} // restoreCmdByArgv +} // restoreCmdByArgv // ======================================================================== +bool CommandManager::validate(Context& ctx, int idx, + TypoFixerType fixer_type, bool case_sensitive, bool allow_as_is) +{ + auto peer = ctx.m_peer.lock(); + const SetTypoFixer& stf = getFixer(fixer_type); + + // We show 3 options by default + return !hasTypo(peer, ctx.m_voting, ctx.m_argv, ctx.m_cmd, idx, + stf, 3, case_sensitive, allow_as_is); +} // validate +//----------------------------------------------------------------------------- + bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, std::vector& argv, std::string& cmd, int idx, - SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is, + const SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is, bool dont_replace, int subidx, int substr_l, int substr_r) { if (!peer.get()) // voted diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 7a7ff099897..5a7f672f052 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -234,6 +234,15 @@ class CommandManager: public LobbyContextComponent SetTypoFixer m_stf_addon_maps; + enum TypoFixerType + { + TFT_PRESENT_USERS, + TFT_ALL_MAPS, + TFT_ADDON_MAPS + }; + + const SetTypoFixer& getFixer(TypoFixerType type); + std::vector m_current_argv; // Auxiliary things, should be moved somewhere because they just help @@ -379,9 +388,14 @@ class CommandManager: public LobbyContextComponent std::vector& argv, char c, char d, char e, char f, int from = 0); + // A simple version of hasTypo for validating simple arguments. + // Returns the opposite bool value. + bool validate(Context& ctx, int idx, + TypoFixerType fixer_type, bool case_sensitive, bool allow_as_is); + bool hasTypo(std::shared_ptr peer, bool voting, std::vector& argv, std::string& cmd, int idx, - SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is, + const SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is, bool dont_replace = false, int subidx = 0, int substr_l = -1, int substr_r = -1); void onServerSetup(); @@ -397,8 +411,6 @@ class CommandManager: public LobbyContextComponent // Helper functions, unrelated to CommandManager inner structure std::string getAddonPreferredType() const; - bool assignRandomTeams(int intended_number, int* final_number, int* player_number); - }; #endif // COMMAND_MANAGER_HPP diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 6c269eebdcb..4535b461e92 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3702,7 +3702,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, { int final_number, players_number; getTeamManager()->clearTeams(); - getCommandManager()->assignRandomTeams(2, &final_number, &players_number); + getTeamManager()->assignRandomTeams(2, &final_number, &players_number); } else { diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index 6b196fd2e13..efe9f8e2dd8 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -43,15 +43,14 @@ void LobbySettings::setupContextUser() { - m_game_setup = getGameSetupFromCtx(); m_motd = StringUtils::wideToUtf8( - m_game_setup->readOrLoadFromFile( + getGameSetupFromCtx()->readOrLoadFromFile( (std::string) ServerConfig::m_motd ) ); m_help_message = StringUtils::wideToUtf8( - m_game_setup->readOrLoadFromFile( + getGameSetupFromCtx()->readOrLoadFromFile( (std::string) ServerConfig::m_help ) ); @@ -456,7 +455,7 @@ void LobbySettings::initializeDefaultVote() } else { - if (m_game_setup->isSoccerGoalTarget()) + if (getGameSetupFromCtx()->isSoccerGoalTarget()) { m_default_vote->m_num_laps = (uint8_t)(UserConfigParams::m_num_goals); @@ -498,7 +497,7 @@ void LobbySettings::applyRestrictionsOnVote(PeerVote* vote, Track* t) const } else if (RaceManager::get()->isSoccerMode()) { - if (m_game_setup->isSoccerGoalTarget()) + if (getGameSetupFromCtx()->isSoccerGoalTarget()) { if (hasMultiplier()) { diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 55d74907c4f..79a131e7e3b 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -174,7 +174,6 @@ class LobbySettings: public LobbyContextComponent bool isLegacyGPModeStarted() const { return m_legacy_gp_mode_started; } private: - GameSetup* m_game_setup; int m_battle_hit_capture_limit; diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp index d764e91dc39..ea45fe5e204 100644 --- a/src/utils/team_manager.cpp +++ b/src/utils/team_manager.cpp @@ -31,6 +31,8 @@ #include "utils/team_utils.hpp" #include "utils/tournament.hpp" +#include + namespace { static const std::set empty_string_set = {}; @@ -342,3 +344,71 @@ void TeamManager::checkNoTeamSpectator(std::shared_ptr peer) } } // checkNoTeamSpectator //----------------------------------------------------------------------------- + +bool TeamManager::assignRandomTeams(int intended_number, + int* final_number, int* final_player_number) +{ + int teams_number = intended_number; + *final_number = teams_number; + int player_number = 0; + for (auto& p : STKHost::get()->getPeers()) + { + if (!getCrownManager()->canRace(p)) + continue; + if (p->alwaysSpectateButNotNeutral()) + continue; + player_number += p->getPlayerProfiles().size(); + } + if (player_number == 0) { + *final_number = teams_number; + *final_player_number = player_number; + return false; + } + int max_number_of_teams = TeamUtils::getNumberOfTeams(); + std::string available_colors_string = getTeamManager()->getAvailableTeams(); + if (available_colors_string.empty()) + return false; + if (max_number_of_teams > (int)available_colors_string.length()) + max_number_of_teams = (int)available_colors_string.length(); + if (teams_number == -1 || teams_number < 1 || teams_number > max_number_of_teams) + { + teams_number = (int)round(sqrt(player_number)); + if (teams_number > max_number_of_teams) + teams_number = max_number_of_teams; + if (player_number > 1 && teams_number <= 1 && max_number_of_teams >= 2) + teams_number = 2; + } + + *final_number = teams_number; + *final_player_number = player_number; + std::vector available_colors; + std::vector profile_colors; + for (const char& c: available_colors_string) + available_colors.push_back(TeamUtils::getIndexByCode(std::string(1, c))); + + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(available_colors.begin(), available_colors.end(), g); + available_colors.resize(teams_number); + + for (int i = 0; i < player_number; ++i) + profile_colors.push_back(available_colors[i % teams_number]); + + std::shuffle(profile_colors.begin(), profile_colors.end(), g); + + getTeamManager()->clearTemporaryTeams(); + for (auto& p : STKHost::get()->getPeers()) + { + if (!getCrownManager()->canRace(p)) + continue; + if (p->alwaysSpectateButNotNeutral()) + continue; + for (auto& profile : p->getPlayerProfiles()) { + getTeamManager()->setTemporaryTeamInLobby(profile, profile_colors.back()); + if (profile_colors.size() > 1) // prevent crash just in case + profile_colors.pop_back(); + } + } + return true; +} // assignRandomTeams +//----------------------------------------------------------------------------- diff --git a/src/utils/team_manager.hpp b/src/utils/team_manager.hpp index 30fed9b71d4..c3e12b655a8 100644 --- a/src/utils/team_manager.hpp +++ b/src/utils/team_manager.hpp @@ -81,6 +81,8 @@ class TeamManager: public LobbyContextComponent // The functions below reset/set ASM_NO_TEAM if needed by team changing procedure. void checkNoTeamSpectator(std::shared_ptr peer); + bool assignRandomTeams(int intended_number, int* final_number, int* player_number); + private: std::string m_available_teams; From 9326d3e55b71211c943c3e4b9e2374ff69686845 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 25 Mar 2025 22:40:55 +0400 Subject: [PATCH 634/830] Remove getABCD from all LobbyContext files abcd.cpp --- src/utils/lobby_asset_manager.cpp | 14 +++++++------- src/utils/team_manager.cpp | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp index df83bfc1e08..a57c237770b 100644 --- a/src/utils/lobby_asset_manager.cpp +++ b/src/utils/lobby_asset_manager.cpp @@ -407,37 +407,37 @@ bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer, bad = true; } - if (okt < getAssetManager()->getOfficialKartsThreshold()) + if (okt < getOfficialKartsThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: bad official kart threshold"); bad = true; } - if (ott < getAssetManager()->getOfficialTracksThreshold()) + if (ott < getOfficialTracksThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: bad official track threshold"); bad = true; } - if (addon_karts < getAssetManager()->getAddonKartsJoinThreshold()) + if (addon_karts < getAddonKartsJoinThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: too little addon karts"); bad = true; } - if (addon_tracks < getAssetManager()->getAddonTracksJoinThreshold()) + if (addon_tracks < getAddonTracksJoinThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: too little addon tracks"); bad = true; } - if (addon_arenas < getAssetManager()->getAddonArenasJoinThreshold()) + if (addon_arenas < getAddonArenasJoinThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: too little addon arenas"); bad = true; } - if (addon_soccers < getAssetManager()->getAddonSoccersJoinThreshold()) + if (addon_soccers < getAddonSoccersJoinThreshold()) { Log::verbose("LobbyAssetManager", "Bad player: too little addon soccers"); bad = true; @@ -703,7 +703,7 @@ void LobbyAssetManager::initAvailableTracks() { m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); m_global_karts_filter = KartFilter(ServerConfig::m_only_played_karts_string); - getAssetManager()->setMustHaveMaps(ServerConfig::m_must_have_tracks_string); + setMustHaveMaps(ServerConfig::m_must_have_tracks_string); m_play_requirement_tracks = StringUtils::split( ServerConfig::m_play_requirement_tracks_string, ' ', false); } // initAvailableTracks diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp index ea45fe5e204..c18c2f9f153 100644 --- a/src/utils/team_manager.cpp +++ b/src/utils/team_manager.cpp @@ -59,7 +59,7 @@ void TeamManager::setTemporaryTeamInLobby(const std::string& username, int team) { if (profile->getName() == wide_player_name) { - getTeamManager()->setTemporaryTeamInLobby(profile, team); + setTemporaryTeamInLobby(profile, team); break; } } @@ -365,7 +365,7 @@ bool TeamManager::assignRandomTeams(int intended_number, return false; } int max_number_of_teams = TeamUtils::getNumberOfTeams(); - std::string available_colors_string = getTeamManager()->getAvailableTeams(); + std::string available_colors_string = getAvailableTeams(); if (available_colors_string.empty()) return false; if (max_number_of_teams > (int)available_colors_string.length()) @@ -396,7 +396,7 @@ bool TeamManager::assignRandomTeams(int intended_number, std::shuffle(profile_colors.begin(), profile_colors.end(), g); - getTeamManager()->clearTemporaryTeams(); + clearTemporaryTeams(); for (auto& p : STKHost::get()->getPeers()) { if (!getCrownManager()->canRace(p)) @@ -404,7 +404,7 @@ bool TeamManager::assignRandomTeams(int intended_number, if (p->alwaysSpectateButNotNeutral()) continue; for (auto& profile : p->getPlayerProfiles()) { - getTeamManager()->setTemporaryTeamInLobby(profile, profile_colors.back()); + setTemporaryTeamInLobby(profile, profile_colors.back()); if (profile_colors.size() > 1) // prevent crash just in case profile_colors.pop_back(); } From 761befcaf03eea0906f3a286fdf895b190aadc81 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 26 Mar 2025 02:23:52 +0400 Subject: [PATCH 635/830] Moved GameInfo fill out of ServerLobby, added DatabaseConnector to LobbyContext Also allow configurable by hammer ownerless servers (probably works). Database seems to work. --- src/modes/capture_the_flag.cpp | 26 +- src/modes/soccer_world.cpp | 44 +-- src/network/database_connector.cpp | 6 + src/network/database_connector.hpp | 7 +- src/network/protocols/server_lobby.cpp | 500 ++++--------------------- src/network/protocols/server_lobby.hpp | 9 +- src/network/server_config.cpp | 2 +- src/utils/game_info.cpp | 485 ++++++++++++++++++++++++ src/utils/game_info.hpp | 21 +- src/utils/lobby_context.cpp | 9 + src/utils/lobby_context.hpp | 17 + 11 files changed, 634 insertions(+), 492 deletions(-) diff --git a/src/modes/capture_the_flag.cpp b/src/modes/capture_the_flag.cpp index f12d1f32d8b..5d879b9ca0e 100644 --- a/src/modes/capture_the_flag.cpp +++ b/src/modes/capture_the_flag.cpp @@ -416,28 +416,10 @@ void CaptureTheFlag::ctfScored(int kart_id, bool red_team_scored, std::shared_ptr game_info = getGameInfo(); if (game_info) { - game_info->m_player_info.emplace_back(false/* reserved */, - true/* game event*/); - auto& info = game_info->m_player_info.back(); - RemoteKartInfo& rki = RaceManager::get()->getKartInfo(kart_id); - info.m_username = StringUtils::wideToUtf8(name); - info.m_result = (red_team_scored ? 1 : -1); - info.m_kart = rki.getKartName(); - info.m_kart_class = rki.getKartData().m_kart_type; - info.m_kart_color = rki.getDefaultKartColor(); - info.m_team = (int8_t)rki.getKartTeam(); - if (info.m_team == KartTeam::KART_TEAM_NONE) - { - auto npp = rki.getNetworkPlayerProfile().lock(); - if (npp) - info.m_team = npp->getTemporaryTeam() - 1; - } - info.m_handicap = (uint8_t)rki.getHandicap(); - info.m_start_position = getStartPosition(kart_id); - info.m_online_id = rki.getOnlineId(); - info.m_country_code = rki.getCountryCode(); - info.m_when_joined = stk_config->ticks2Time(getTicksSinceStart()); - info.m_when_left = info.m_when_joined; + unsigned start_pos = getStartPosition(kart_id); + float time_since_start = stk_config->ticks2Time(getTicksSinceStart()); + game_info->onFlagCaptured(red_team_scored, name, + kart_id, start_pos, time_since_start); } #ifndef SERVER_ONLY // Don't set animation and show message if receiving in live join diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp index 0c088dff8a8..d7f757733b8 100644 --- a/src/modes/soccer_world.cpp +++ b/src/modes/soccer_world.cpp @@ -580,51 +580,21 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) else if (!sd.m_correct_goal) { if (!stopped) + { Log::info("SoccerWorld", "SoccerMatchLog: [Goal] %s scored an own goal for %s", player_name.c_str(), team_name.c_str()); + } + m_karts[sd.m_id]->getKartModel() ->setAnimation(KartModel::AF_LOSE_START, true/* play_non_loop*/); } std::shared_ptr game_info = getGameInfo(); if (game_info) { - int sz = game_info->m_player_info.size(); - game_info->m_player_info.emplace_back(false/* reserved */, - true/* game event*/); - Log::info("SoccerWorld", "player info size before: %d, after: %d", sz, (int)game_info->m_player_info.size()); - auto& info = game_info->m_player_info.back(); - RemoteKartInfo& rki = RaceManager::get()->getKartInfo(sd.m_id); - info.m_username = player_name; - info.m_result = (sd.m_correct_goal ? 1 : -1); - info.m_kart = rki.getKartName(); - info.m_kart_class = rki.getKartData().m_kart_type; - info.m_kart_color = rki.getDefaultKartColor(); - info.m_team = (int8_t)rki.getKartTeam(); - if (info.m_team == KartTeam::KART_TEAM_NONE) - { - auto npp = rki.getNetworkPlayerProfile().lock(); - if (npp) - info.m_team = npp->getTemporaryTeam() - 1; - } - info.m_handicap = (uint8_t)rki.getHandicap(); - info.m_start_position = getStartPosition(sd.m_id); - info.m_online_id = rki.getOnlineId(); - info.m_country_code = rki.getCountryCode(); - info.m_when_joined = stk_config->ticks2Time(getTicksSinceStart()); - info.m_when_left = info.m_when_joined; - if (rki.isReserved()) - { - // Unfortunately it's unknown which ID the corresponding player - // has. Maybe the placement of items for disconnected players - // should be changed in GameInfo::m_player_info. I have no idea - // right now... - info.m_not_full = 1; - } - else - { - info.m_not_full = 0; - game_info->m_player_info[sd.m_id].m_result += info.m_result; - } + unsigned start_pos = getStartPosition(sd.m_id); + float time_since_start = stk_config->ticks2Time(getTicksSinceStart()); + game_info->onGoalScored(sd.m_correct_goal, sd.m_player, + sd.m_id, start_pos, time_since_start); } if (stopped) diff --git a/src/network/database_connector.cpp b/src/network/database_connector.cpp index 55a6776617e..6f887387a8b 100644 --- a/src/network/database_connector.cpp +++ b/src/network/database_connector.cpp @@ -84,6 +84,12 @@ std::function BinderCollection::getBindFunction() cons }; } // BinderCollection::getBindFunction +//----------------------------------------------------------------------------- + +void DatabaseConnector::setupContextUser() +{ + initDatabase(); +} // initDatabase //----------------------------------------------------------------------------- /** Opens the database, sets its busy handler and variables related to it. */ void DatabaseConnector::initDatabase() diff --git a/src/network/database_connector.hpp b/src/network/database_connector.hpp index f2929d39883..1b2dc473e35 100644 --- a/src/network/database_connector.hpp +++ b/src/network/database_connector.hpp @@ -23,6 +23,7 @@ #include "utils/string_utils.hpp" #include "utils/time.hpp" +#include "utils/lobby_context.hpp" #include #include @@ -105,7 +106,7 @@ std::ostream& operator << (std::ostream& os, const Binder& binder); * of this class, while the logic corresponding to those queries should not * belong here. */ -class DatabaseConnector +class DatabaseConnector: public LobbyContextComponent { private: sqlite3* m_db; @@ -121,6 +122,10 @@ class DatabaseConnector uint64_t m_last_poll_db_time; public: + DatabaseConnector(LobbyContext* context): LobbyContextComponent(context) {} + + void setupContextUser() OVERRIDE; + /** Corresponds to the row of IPv4 ban table. */ struct IpBanTableData { diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 4535b461e92..126a68cea09 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -244,11 +244,6 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_difficulty.store(ServerConfig::m_server_difficulty); m_game_mode.store(ServerConfig::m_server_mode); -#ifdef ENABLE_SQLITE3 - m_db_connector = std::make_shared(); - m_db_connector->initDatabase(); -#endif - m_game_info = {}; } // ServerLobby @@ -267,7 +262,7 @@ ServerLobby::~ServerLobby() ServerConfig::writeServerConfigToDisk(); #ifdef ENABLE_SQLITE3 - m_db_connector->destroyDatabase(); + getDbConnector()->destroyDatabase(); #endif } // ~ServerLobby @@ -276,7 +271,7 @@ ServerLobby::~ServerLobby() void ServerLobby::initServerStatsTable() { #ifdef ENABLE_SQLITE3 - m_db_connector->initServerStatsTable(); + getDbConnector()->initServerStatsTable(); #endif } // initServerStatsTable @@ -456,20 +451,21 @@ bool ServerLobby::notifyEventAsynchronous(Event* event) */ void ServerLobby::pollDatabase() { - if (!getSettings()->hasSqlManagement() || !m_db_connector->hasDatabase()) + auto db_connector = getDbConnector(); + if (!getSettings()->hasSqlManagement() || !db_connector->hasDatabase()) return; - if (!m_db_connector->isTimeToPoll()) + if (!db_connector->isTimeToPoll()) return; - m_db_connector->updatePollTime(); + db_connector->updatePollTime(); std::vector ip_ban_list = - m_db_connector->getIpBanTableData(); + db_connector->getIpBanTableData(); std::vector ipv6_ban_list = - m_db_connector->getIpv6BanTableData(); + db_connector->getIpv6BanTableData(); std::vector online_id_ban_list = - m_db_connector->getOnlineIdBanTableData(); + db_connector->getOnlineIdBanTableData(); for (std::shared_ptr p : STKHost::get()->getPeers()) { @@ -533,7 +529,7 @@ void ServerLobby::pollDatabase() } } // for p in peers - m_db_connector->clearOldReports(); + db_connector->clearOldReports(); auto peers = STKHost::get()->getPeers(); std::vector hosts; @@ -546,7 +542,7 @@ void ServerLobby::pollDatabase() hosts.push_back(peer->getHostId()); } } - m_db_connector->setDisconnectionTimes(hosts); + db_connector->setDisconnectionTimes(hosts); } // pollDatabase #endif @@ -554,7 +550,8 @@ void ServerLobby::pollDatabase() void ServerLobby::writePlayerReport(Event* event) { #ifdef ENABLE_SQLITE3 - if (!m_db_connector->hasDatabase() || !m_db_connector->hasPlayerReportsTable()) + auto db_connector = getDbConnector(); + if (!db_connector->hasDatabase() || !db_connector->hasPlayerReportsTable()) return; std::shared_ptr reporter = event->getPeerSP(); if (!reporter->hasPlayerProfiles()) @@ -572,7 +569,7 @@ void ServerLobby::writePlayerReport(Event* event) return; auto reporting_npp = reporting_peer->getPlayerProfiles()[0]; - bool written = m_db_connector->writeReport(reporter, reporter_npp, + bool written = db_connector->writeReport(reporter, reporter_npp, reporting_peer, reporting_npp, info); if (written) { @@ -967,39 +964,8 @@ void ServerLobby::asynchronousUpdate() } } m_game_info = std::make_shared(); - for (int i = 0; i < (int)RaceManager::get()->getNumPlayers(); i++) - { - GameInfo::PlayerInfo info; - RemoteKartInfo& rki = RaceManager::get()->getKartInfo(i); - if (!rki.isReserved()) - { - info = GameInfo::PlayerInfo(false/* reserved */, - false/* game event*/); - // TODO: I suspected it to be local name, but it's not! - info.m_username = StringUtils::wideToUtf8(rki.getPlayerName()); - info.m_kart = rki.getKartName(); - //info.m_start_position = i; - info.m_when_joined = 0; - info.m_country_code = rki.getCountryCode(); - info.m_online_id = rki.getOnlineId(); - info.m_kart_class = rki.getKartData().m_kart_type; - info.m_kart_color = rki.getDefaultKartColor(); - info.m_handicap = (uint8_t)rki.getHandicap(); - info.m_team = (int8_t)rki.getKartTeam(); - if (info.m_team == KartTeam::KART_TEAM_NONE) - { - auto npp = rki.getNetworkPlayerProfile().lock(); - if (npp) - info.m_team = npp->getTemporaryTeam() - 1; - } - } - else - { - info = GameInfo::PlayerInfo(true/* reserved */, - false/* game event*/); - } - m_game_info->m_player_info.push_back(info); - } + m_game_info->setContext(m_lobby_context.get()); + m_game_info->fillFromRaceManager(); } break; } @@ -1287,43 +1253,10 @@ void ServerLobby::finishedLoadingLiveJoinClient(Event* event) for (const int id : peer->getAvailableKartIDs()) { const RemoteKartInfo& rki = RaceManager::get()->getKartInfo(id); - std::string name = StringUtils::wideToUtf8(rki.getPlayerName()); int points = 0; if (m_game_info) - { - - if (!m_game_info->m_player_info[id].isReserved()) - { - Log::error("ServerLobby", "While live joining kart %d, " - "player info was not reserved.", id); - } - auto& info = m_game_info->m_player_info[id]; - info = GameInfo::PlayerInfo(false/* reserved */, - false/* game event*/); - info.m_username = StringUtils::wideToUtf8(rki.getPlayerName()); - info.m_kart = rki.getKartName(); - info.m_start_position = w->getStartPosition(id); - info.m_when_joined = stk_config->ticks2Time(w->getTicksSinceStart()); - info.m_country_code = rki.getCountryCode(); - info.m_online_id = rki.getOnlineId(); - info.m_kart_class = rki.getKartData().m_kart_type; - info.m_kart_color = rki.getDefaultKartColor(); - info.m_handicap = (uint8_t)rki.getHandicap(); - info.m_team = (int8_t)rki.getKartTeam(); - if (info.m_team == KartTeam::KART_TEAM_NONE) - { - auto npp = rki.getNetworkPlayerProfile().lock(); - if (npp) - info.m_team = npp->getTemporaryTeam() - 1; - } - if (RaceManager::get()->isBattleMode()) - { - if (getSettings()->isPreservingBattleScores()) - points = m_game_info->m_saved_ffa_points[name]; - info.m_result -= points; - } - } + points = m_game_info->onLiveJoinedPlayer(id, rki, w); else Log::warn("ServerLobby", "GameInfo is not accessible??"); @@ -1572,8 +1505,6 @@ void ServerLobby::update(int ticks) handlePlayerDisconnection(); - NetworkString* ns; - switch (m_state.load()) { case SET_PUBLIC_ADDRESS: @@ -1601,7 +1532,7 @@ void ServerLobby::update(int ticks) if (World::getWorld() && RaceEventManager::get() && RaceEventManager::get()->isRunning()) { - checkRaceFinished(ns); + checkRaceFinished(); } break; case WAIT_FOR_RACE_STOPPED: @@ -1617,8 +1548,8 @@ void ServerLobby::update(int ticks) // result screen and go back to the lobby setTimeoutFromNow(15); m_state = RESULT_DISPLAY; - sendMessageToPeers(ns, PRM_RELIABLE); - delete ns; + sendMessageToPeers(m_result_ns, PRM_RELIABLE); + delete m_result_ns; Log::info("ServerLobby", "End of game message sent"); break; case RESULT_DISPLAY: @@ -2073,7 +2004,7 @@ void ServerLobby::checkIncomingConnectionRequests() * to state RESULT_DISPLAY, during which the race result gui is shown and all * clients can click on 'continue'. */ -void ServerLobby::checkRaceFinished(NetworkString*& result) +void ServerLobby::checkRaceFinished() { assert(RaceEventManager::get()->isRunning()); assert(World::getWorld()); @@ -2096,20 +2027,20 @@ void ServerLobby::checkRaceFinished(NetworkString*& result) GameProtocol::lock()->requestTerminate(); // Save race result before delete the world - result = getNetworkString(); - result->setSynchronous(true); - result->addUInt8(LE_RACE_FINISHED); + m_result_ns = getNetworkString(); + m_result_ns->setSynchronous(true); + m_result_ns->addUInt8(LE_RACE_FINISHED); std::vector gp_changes; if (m_game_setup->isGrandPrix()) { - getGPManager()->updateGPScores(gp_changes, result); + getGPManager()->updateGPScores(gp_changes, m_result_ns); } else if (RaceManager::get()->modeHasLaps()) { int fastest_lap = static_cast(World::getWorld())->getFastestLapTicks(); - result->addUInt32(fastest_lap); - result->encodeString(static_cast(World::getWorld()) + m_result_ns->addUInt32(fastest_lap); + m_result_ns->encodeString(static_cast(World::getWorld()) ->getFastestLapKartName()); } @@ -2118,7 +2049,7 @@ void ServerLobby::checkRaceFinished(NetworkString*& result) ranking_changes_indication = 1; if (m_game_setup->isGrandPrix()) ranking_changes_indication = 1; - result->addUInt8(ranking_changes_indication); + m_result_ns->addUInt8(ranking_changes_indication); if (getKartElimination()->isEnabled()) { @@ -2134,16 +2065,16 @@ void ServerLobby::checkRaceFinished(NetworkString*& result) if (getSettings()->isRanked()) { - computeNewRankings(result); + computeNewRankings(m_result_ns); submitRankingsToAddons(); } else if (m_game_setup->isGrandPrix()) { unsigned player_count = RaceManager::get()->getNumPlayers(); - result->addUInt8((uint8_t)player_count); + m_result_ns->addUInt8((uint8_t)player_count); for (unsigned i = 0; i < player_count; i++) { - result->addFloat(gp_changes[i]); + m_result_ns->addFloat(gp_changes[i]); } } m_state.store(WAIT_FOR_RACE_STOPPED); @@ -2217,8 +2148,13 @@ void ServerLobby::clientDisconnected(Event* event) std::shared_ptr peer = event->getPeerSP(); getChatManager()->onPeerDisconnect(peer); // No warnings otherwise, as it could happen during lobby period - if (w && m_game_info) - saveDisconnectingPeerInfo(peer); + if (m_game_info) + { + if (w) + m_game_info->saveDisconnectingPeerInfo(peer); + } + else + Log::warn("ServerLobby", "GameInfo is not accessible??"); NetworkString* msg = getNetworkString(2); const bool waiting_peer_disconnected = @@ -2254,7 +2190,7 @@ void ServerLobby::clientDisconnected(Event* event) delete msg; #ifdef ENABLE_SQLITE3 - m_db_connector->writeDisconnectInfoTable(event->getPeerSP()); + getDbConnector()->writeDisconnectInfoTable(event->getPeerSP()); #endif } // clientDisconnected @@ -2276,7 +2212,7 @@ void ServerLobby::kickPlayerWithReason(std::shared_ptr peer, const char void ServerLobby::saveIPBanTable(const SocketAddress& addr) { #ifdef ENABLE_SQLITE3 - m_db_connector->saveAddressToIpBanTable(addr); + getDbConnector()->saveAddressToIpBanTable(addr); #endif } // saveIPBanTable //----------------------------------------------------------------------------- @@ -2585,9 +2521,9 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, #ifdef ENABLE_SQLITE3 if (country_code.empty() && !peer->getAddress().isIPv6()) - country_code = m_db_connector->ip2Country(peer->getAddress()); + country_code = getDbConnector()->ip2Country(peer->getAddress()); if (country_code.empty() && peer->getAddress().isIPv6()) - country_code = m_db_connector->ipv62Country(peer->getAddress()); + country_code = getDbConnector()->ipv62Country(peer->getAddress()); #endif auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); @@ -2756,7 +2692,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, } #ifdef ENABLE_SQLITE3 - m_db_connector->onPlayerJoinQueries(peer, online_id, player_count, country_code); + getDbConnector()->onPlayerJoinQueries(peer, online_id, player_count, country_code); #endif if (getKartElimination()->isEnabled()) { @@ -3458,7 +3394,8 @@ void ServerLobby::resetServer() void ServerLobby::testBannedForIP(std::shared_ptr peer) const { #ifdef ENABLE_SQLITE3 - if (!m_db_connector->hasDatabase() || !m_db_connector->hasIpBanTable()) + auto db_connector = getDbConnector(); + if (!db_connector->hasDatabase() || !db_connector->hasIpBanTable()) return; // Test for IPv4 @@ -3470,7 +3407,7 @@ void ServerLobby::testBannedForIP(std::shared_ptr peer) const uint32_t ip_end = 0; std::vector ip_ban_list = - m_db_connector->getIpBanTableData(peer->getAddress().getIP()); + db_connector->getIpBanTableData(peer->getAddress().getIP()); if (!ip_ban_list.empty()) { is_banned = true; @@ -3485,7 +3422,7 @@ void ServerLobby::testBannedForIP(std::shared_ptr peer) const kickPlayerWithReason(peer, reason.c_str()); } if (is_banned) - m_db_connector->increaseIpBanTriggerCount(ip_start, ip_end); + db_connector->increaseIpBanTriggerCount(ip_start, ip_end); #endif } // testBannedForIP @@ -3493,15 +3430,16 @@ void ServerLobby::testBannedForIP(std::shared_ptr peer) const void ServerLobby::getMessagesFromHost(std::shared_ptr peer, int online_id) { #ifdef ENABLE_SQLITE3 + auto db_connector = getDbConnector(); std::vector messages = - m_db_connector->getServerMessages(online_id); + db_connector->getServerMessages(online_id); // in case there will be more than one later for (const auto& message: messages) { Log::info("ServerLobby", "A message from server was delivered"); sendStringToPeer(peer, "A message from the server (" + std::string(message.timestamp) + "):\n" + std::string(message.message)); - m_db_connector->deleteServerMessage(message.row_id); + db_connector->deleteServerMessage(message.row_id); } #endif } // getMessagesFromHost @@ -3510,7 +3448,8 @@ void ServerLobby::getMessagesFromHost(std::shared_ptr peer, int online_ void ServerLobby::testBannedForIPv6(std::shared_ptr peer) const { #ifdef ENABLE_SQLITE3 - if (!m_db_connector->hasDatabase() || !m_db_connector->hasIpv6BanTable()) + auto db_connector = getDbConnector(); + if (!db_connector->hasDatabase() || !db_connector->hasIpv6BanTable()) return; // Test for IPv6 @@ -3521,7 +3460,7 @@ void ServerLobby::testBannedForIPv6(std::shared_ptr peer) const std::string ipv6_cidr = ""; std::vector ipv6_ban_list = - m_db_connector->getIpv6BanTableData(peer->getAddress().toString(false)); + db_connector->getIpv6BanTableData(peer->getAddress().toString(false)); if (!ipv6_ban_list.empty()) { @@ -3536,7 +3475,7 @@ void ServerLobby::testBannedForIPv6(std::shared_ptr peer) const kickPlayerWithReason(peer, reason.c_str()); } if (is_banned) - m_db_connector->increaseIpv6BanTriggerCount(ipv6_cidr); + db_connector->increaseIpv6BanTriggerCount(ipv6_cidr); #endif } // testBannedForIPv6 @@ -3545,12 +3484,13 @@ void ServerLobby::testBannedForOnlineId(std::shared_ptr peer, uint32_t online_id) const { #ifdef ENABLE_SQLITE3 - if (!m_db_connector->hasDatabase() || !m_db_connector->hasOnlineIdBanTable()) + auto db_connector = getDbConnector(); + if (!db_connector->hasDatabase() || !db_connector->hasOnlineIdBanTable()) return; bool is_banned = false; std::vector online_id_ban_list = - m_db_connector->getOnlineIdBanTableData(online_id); + db_connector->getOnlineIdBanTableData(online_id); if (!online_id_ban_list.empty()) { @@ -3564,7 +3504,7 @@ void ServerLobby::testBannedForOnlineId(std::shared_ptr peer, kickPlayerWithReason(peer, reason.c_str()); } if (is_banned) - m_db_connector->increaseOnlineIdBanTriggerCount(online_id); + db_connector->increaseOnlineIdBanTriggerCount(online_id); #endif } // testBannedForOnlineId @@ -3572,7 +3512,7 @@ void ServerLobby::testBannedForOnlineId(std::shared_ptr peer, void ServerLobby::listBanTable() { #ifdef ENABLE_SQLITE3 - m_db_connector->listBanTable(); + getDbConnector()->listBanTable(); #endif } // listBanTable @@ -3839,12 +3779,10 @@ void ServerLobby::handlePlayerDisconnection() const continue; } - if (!m_game_info) - Log::warn("ServerLobby", "GameInfo is not accessible??"); + if (m_game_info) + m_game_info->saveDisconnectingIdInfo(i); else - { - saveDisconnectingIdInfo(i); - } + Log::warn("ServerLobby", "GameInfo is not accessible??"); rki.makeReserved(); @@ -4066,10 +4004,10 @@ void ServerLobby::clientInGameWantsToBackLobby(Event* event) return; } - if (!m_game_info) - Log::warn("ServerLobby", "GameInfo is not accessible??"); + if (m_game_info) + m_game_info->saveDisconnectingPeerInfo(peer); else - saveDisconnectingPeerInfo(peer); + Log::warn("ServerLobby", "GameInfo is not accessible??"); for (const int id : peer->getAvailableKartIDs()) { @@ -4229,248 +4167,13 @@ void ServerLobby::updateGnuElimination() //----------------------------------------------------------------------------- void ServerLobby::storeResults() { - World* w = World::getWorld(); - if (!w) - return; if (!m_game_info) { Log::warn("ServerLobby", "GameInfo is not accessible??"); return; } - RaceManager* rm = RaceManager::get(); - m_game_info->m_timestamp = StkTime::getLogTimeFormatted("%Y-%m-%d %H:%M:%S"); - m_game_info->m_venue = rm->getTrackName(); - m_game_info->m_reverse = (rm->getReverseTrack() || - rm->getRandomItemsIndicator() ? "reverse" : "normal"); - m_game_info->m_mode = rm->getMinorModeName(); - m_game_info->m_value_limit = 0; - m_game_info->m_time_limit = rm->getTimeTarget(); - m_game_info->m_difficulty = getDifficulty(); - m_game_info->setPowerupString(powerup_manager->getFileName()); - m_game_info->setKartCharString(kart_properties_manager->getFileName()); - - if (rm->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) - { - m_game_info->m_value_limit = rm->getHitCaptureLimit(); - m_game_info->m_flag_return_timeout = getSettings()->getFlagReturnTimeout(); - m_game_info->m_flag_deactivated_time = getSettings()->getFlagDeactivatedTime(); - } - else if (rm->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) - { - m_game_info->m_value_limit = rm->getHitCaptureLimit(); // TODO doesn't work - m_game_info->m_flag_return_timeout = 0; - m_game_info->m_flag_deactivated_time = 0; - } - else if (rm->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) - { - m_game_info->m_value_limit = rm->getMaxGoal(); // TODO doesn't work - m_game_info->m_flag_return_timeout = 0; - m_game_info->m_flag_deactivated_time = 0; - } - else - { - m_game_info->m_value_limit = rm->getNumLaps(); - m_game_info->m_flag_return_timeout = 0; - m_game_info->m_flag_deactivated_time = 0; - } - - // m_game_info->m_timestamp = TODO; - bool racing_mode = false; - bool soccer = false; - bool ffa = false; - bool ctf = false; - auto minor_mode = RaceManager::get()->getMinorMode(); - racing_mode |= minor_mode == RaceManager::MINOR_MODE_NORMAL_RACE; - racing_mode |= minor_mode == RaceManager::MINOR_MODE_TIME_TRIAL; - racing_mode |= minor_mode == RaceManager::MINOR_MODE_LAP_TRIAL; - ffa |= minor_mode == RaceManager::MINOR_MODE_FREE_FOR_ALL; - ctf |= minor_mode == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG; - soccer |= minor_mode == RaceManager::MINOR_MODE_SOCCER; - - // Kart class for standard karts - // Goal scoring policy? - // Do we really need round()/int for ingame timestamps? - - FreeForAll* ffa_world = dynamic_cast(World::getWorld()); - LinearWorld* linear_world = dynamic_cast(World::getWorld()); - - bool record_fetched = false; - bool record_exists = false; - double best_result = 0.0; - std::string best_user = ""; - - if (racing_mode) - { -#ifdef ENABLE_SQLITE3 - record_fetched = m_db_connector->getBestResult(*m_game_info, &record_exists, &best_user, &best_result); -#endif - } - - int best_cur_player_idx = -1; - std::string best_cur_player_name = ""; - double best_cur_time = 1e18; - - double current_game_timestamp = stk_config->ticks2Time(w->getTicksSinceStart()); - - auto& vec = m_game_info->m_player_info; - - // Set game duration for all items, including game events - // and reserved PlayerInfos (even if those will be removed) - for (unsigned i = 0; i < vec.size(); i++) - { - auto& info = vec[i]; - info.m_game_duration = current_game_timestamp; - if (!info.isReserved() && info.m_kart_class.empty()) - { - float width, height, length; - Vec3 gravity_shift; - const KartProperties* kp = OfficialKarts::getKartByIdent(info.m_kart, - &width, &height, &length, &gravity_shift); - if (kp) - info.m_kart_class = kp->getKartType(); - } - } - // For those players inside the game, set some variables - for (unsigned i = 0; i < RaceManager::get()->getNumPlayers(); i++) - { - auto& info = vec[i]; - if (info.isReserved()) - continue; - info.m_when_left = current_game_timestamp; - info.m_start_position = w->getStartPosition(i); - if (ffa || ctf) - { - int points = 0; - if (ffa_world) - points = ffa_world->getKartScore(i); - else - Log::error("ServerLobby", "storeResults: battle mode but FFAWorld is not found"); - info.m_result += points; - // I thought it would make sense to set m_autofinish to 1 if - // someone wins before time expires. However, it's not hard - // to check after reading the database I suppose... - info.m_autofinish = 0; - } - else if (racing_mode) - { - info.m_fastest_lap = -1; - info.m_sog_time = -1; - info.m_autofinish = -1; - info.m_result = rm->getKartRaceTime(i); - float finish_timeout = std::numeric_limits::max(); - if (linear_world) - { - info.m_fastest_lap = (double)linear_world->getFastestLapForKart(i); - finish_timeout = linear_world->getWorstFinishTime(); - info.m_sog_time = linear_world->getStartTimeForKart(i); - info.m_autofinish = (info.m_result < finish_timeout ? 0 : 1); - } - else - Log::error("ServerLobby", "storeResults: racing mode but LinearWorld is not found"); - info.m_not_full = 0; - } - else if (soccer) - { - // Soccer's m_result is handled in SoccerWorld - info.m_autofinish = 0; - } - } - // If the mode is not racing (in which case we set it separately), - // set m_not_full to false iff he was present all the time - if (!racing_mode) - { - for (unsigned i = 0; i < vec.size(); i++) - { - if (vec[i].m_reserved == 0 && vec[i].m_game_event == 0) - vec[i].m_not_full = (vec[i].m_when_joined == 0 && - vec[i].m_when_left == current_game_timestamp ? 0 : 1); - } - } - // Remove reserved PlayerInfos. Note that the first getNumPlayers() items - // no longer correspond to same ID in RaceManager (if they exist even) - for (int i = 0; i < (int)vec.size(); i++) - { - if (vec[i].isReserved()) - { - std::swap(vec[i], vec.back()); - vec.pop_back(); - --i; - } - } - bool sort_asc = !racing_mode; - std::sort(vec.begin(), vec.end(), [sort_asc] - (GameInfo::PlayerInfo& lhs, GameInfo::PlayerInfo& rhs) -> bool { - if (lhs.m_game_event != rhs.m_game_event) - return lhs.m_game_event < rhs.m_game_event; - if (lhs.m_when_joined != rhs.m_when_joined) - return lhs.m_when_joined < rhs.m_when_joined; - if (lhs.m_result != rhs.m_result) - return (lhs.m_result > rhs.m_result) ^ sort_asc; - return false; - }); - if (soccer || ctf) - { - for (unsigned i = 1; i < vec.size(); i++) - { - if (vec[i].m_game_event == 1) - { - double previous = 0; - if (vec[i - 1].m_game_event == 1) - previous = vec[i - 1].m_when_joined; - vec[i].m_sog_time = vec[i].m_when_joined - previous; - } - } - } - // For racing, find who won and possibly beaten the record - if (racing_mode) - { - for (unsigned i = 0; i < vec.size(); i++) - { - if (vec[i].m_reserved == 0 && vec[i].m_game_event == 0 && - vec[i].m_not_full == 0 && - (best_cur_player_idx == -1 || vec[i].m_result < best_cur_time)) - { - best_cur_player_idx = i; - best_cur_time = vec[i].m_result; - best_cur_player_name = vec[i].m_username; - } - } - } - - // Note that before, when online_id was 0, "* " was added to the beginning - // of the name. I'm not sure it's really needed now that online_id is saved. - - // Note that before, string was used to write the result to take into - // account increased precision for racing. Examples: - // racing: elapsed_string << std::setprecision(4) << std::fixed << score; - // ffa: elapsed_string << std::setprecision(0) << std::fixed << score; - - m_game_info->m_saved_ffa_points.clear(); - -#ifdef ENABLE_SQLITE3 - m_db_connector->insertManyResults(*m_game_info); -#endif - // end of insertions - if (record_fetched && best_cur_player_idx != -1) // implies racing_mode - { - std::string message; - if (!record_exists) - { - message = StringUtils::insertValues( - "%s has just set a server record: %s\nThis is the first time set.", - best_cur_player_name, StringUtils::timeToString(best_cur_time)); - } - else if (best_result > best_cur_time) - { - message = StringUtils::insertValues( - "%s has just beaten a server record: %s\nPrevious record: %s by %s", - best_cur_player_name, StringUtils::timeToString(best_cur_time), - StringUtils::timeToString(best_result), best_user); - } - if (!message.empty()) - sendStringToAllPeers(message); - } + m_game_info->fillAndStoreResults(); } // storeResults //----------------------------------------------------------------------------- void ServerLobby::resetToDefaultSettings() @@ -4484,7 +4187,8 @@ void ServerLobby::resetToDefaultSettings() void ServerLobby::writeOwnReport(std::shared_ptr reporter, std::shared_ptr reporting, const std::string& info) { #ifdef ENABLE_SQLITE3 - if (!m_db_connector->hasDatabase() || !m_db_connector->hasPlayerReportsTable()) + auto db_connector = getDbConnector(); + if (!db_connector->hasDatabase() || !db_connector->hasPlayerReportsTable()) return; if (!reporting) reporting = reporter; @@ -4500,7 +4204,7 @@ void ServerLobby::writeOwnReport(std::shared_ptr reporter, std::shared_ return; auto reporting_npp = reporting->getPlayerProfiles()[0]; - bool written = m_db_connector->writeReport(reporter, reporter_npp, + bool written = db_connector->writeReport(reporter, reporter_npp, reporting, reporting_npp, info_w); if (written) { @@ -4631,16 +4335,17 @@ bool ServerLobby::writeOnePlayerReport(std::shared_ptr reporter, const std::string& table, const std::string& info) { #ifdef ENABLE_SQLITE3 - if (!m_db_connector->hasDatabase()) + auto db_connector = getDbConnector(); + if (!db_connector->hasDatabase()) return false; - if (!m_db_connector->hasPlayerReportsTable()) + if (!db_connector->hasPlayerReportsTable()) return false; if (!reporter->hasPlayerProfiles()) return false; auto reporter_npp = reporter->getPlayerProfiles()[0]; auto info_w = StringUtils::utf8ToWide(info); - bool written = m_db_connector->writeReport(reporter, reporter_npp, + bool written = db_connector->writeReport(reporter, reporter_npp, reporter, reporter_npp, info_w); return written; #else @@ -4677,7 +4382,7 @@ std::string ServerLobby::getRecord(std::string& track, std::string& mode, double best_result = 0.0; std::string best_user = ""; - record_fetched = m_db_connector->getBestResult(temp_info, &record_exists, &best_user, &best_result); + record_fetched = getDbConnector()->getBestResult(temp_info, &record_exists, &best_user, &best_result); if (!record_fetched) return "Failed to make a query"; @@ -4737,67 +4442,12 @@ void ServerLobby::setKartDataProperly(KartData& kart_data, const std::string& ka bool ServerLobby::playerReportsTableExists() const { #ifdef ENABLE_SQLITE3 - return m_db_connector->hasPlayerReportsTable(); + return getDbConnector()->hasPlayerReportsTable(); #else return false; #endif } // playerReportsTableExists -//----------------------------------------------------------------------------- -void ServerLobby::saveDisconnectingPeerInfo(std::shared_ptr peer) const -{ - if (worldIsActive() && !peer->isWaitingForGame()) - { - for (const int id : peer->getAvailableKartIDs()) - { - saveDisconnectingIdInfo(id); - } - } -} // saveDisconnectingPeerInfo - -//----------------------------------------------------------------------------- -void ServerLobby::saveDisconnectingIdInfo(int id) const -{ - World* w = World::getWorld(); - FreeForAll* ffa_world = dynamic_cast(w); - LinearWorld* linear_world = dynamic_cast(w); - RemoteKartInfo& rki = RaceManager::get()->getKartInfo(id); - int points = 0; - m_game_info->m_player_info.emplace_back(true/* reserved */, - false/* game event*/); - std::swap(m_game_info->m_player_info.back(), m_game_info->m_player_info[id]); - auto& info = m_game_info->m_player_info.back(); - if (RaceManager::get()->isBattleMode()) - { - if (ffa_world) - points = ffa_world->getKartScore(id); - info.m_result += points; - if (getSettings()->isPreservingBattleScores()) - m_game_info->m_saved_ffa_points[StringUtils::wideToUtf8(rki.getPlayerName())] = points; - } - info.m_when_left = stk_config->ticks2Time(w->getTicksSinceStart()); - info.m_start_position = w->getStartPosition(id); - if (RaceManager::get()->isLinearRaceMode()) - { - info.m_autofinish = 0; - info.m_fastest_lap = -1; - info.m_sog_time = -1; - if (linear_world) - { - info.m_fastest_lap = (double)linear_world->getFastestLapForKart(id); - info.m_sog_time = linear_world->getStartTimeForKart(id); - } - info.m_not_full = 1; - // If a player disconnects before the final screen but finished, - // don't set him as "quitting" - if (w->getKart(id)->hasFinishedRace()) - info.m_not_full = 0; - if (info.m_not_full == 1) - info.m_result = info.m_when_left; - else - info.m_result = RaceManager::get()->getKartRaceTime(id); - } -} // saveDisconnectingIdInfo //----------------------------------------------------------------------------- void ServerLobby::sendServerInfoToEveryone() const diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index f93a52837d9..a0ea55b0e5e 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -94,8 +94,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser private: #ifdef ENABLE_SQLITE3 - std::shared_ptr m_db_connector; - void pollDatabase(); #endif @@ -149,6 +147,9 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser std::map m_pending_peer_connection; + /* Saved the last game result */ + NetworkString* m_result_ns; + /* Used to make sure clients are having same item list at start */ BareNetworkString* m_items_complete_state; @@ -246,7 +247,7 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser void getRankingForPlayer(std::shared_ptr p); void submitRankingsToAddons(); void computeNewRankings(NetworkString* ns); - void checkRaceFinished(NetworkString*& result); + void checkRaceFinished(); void getHitCaptureLimit(); void configPeersStartTime(); void resetServer(); @@ -353,8 +354,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser bool playerReportsTableExists() const; - void saveDisconnectingPeerInfo(std::shared_ptr peer) const; - void saveDisconnectingIdInfo(int id) const; void sendServerInfoToEveryone() const; bool isWorldPicked() const { return m_state.load() >= LOAD_WORLD; } diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 4f9601adcf0..f2e846ff574 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -436,7 +436,7 @@ void loadServerLobbyFromConfig() } if (!m_live_players) m_team_choosing = false; - m_server_configurable = false; + // m_server_configurable = false; } if (modes.second == RaceManager::MAJOR_MODE_GRAND_PRIX) m_server_configurable = false; diff --git a/src/utils/game_info.cpp b/src/utils/game_info.cpp index e75761b3ae6..6a266ce2037 100644 --- a/src/utils/game_info.cpp +++ b/src/utils/game_info.cpp @@ -18,6 +18,26 @@ #include "utils/game_info.hpp" +#include "config/stk_config.hpp" +#include "karts/kart_properties.hpp" +#include "karts/kart_properties_manager.hpp" +#include "karts/official_karts.hpp" +#include "modes/free_for_all.hpp" +#include "modes/linear_world.hpp" +#include "modes/soccer_world.hpp" +#include "modes/world.hpp" +#include "network/database_connector.hpp" +#include "network/network_player_profile.hpp" +#include "network/protocols/server_lobby.hpp" +#include "network/race_event_manager.hpp" +#include "network/remote_kart_info.hpp" +#include "network/stk_peer.hpp" +#include "race/race_manager.hpp" +#include "utils/lobby_settings.hpp" +#include "utils/string_utils.hpp" + +#include + namespace { @@ -25,6 +45,21 @@ namespace const std::string g_default_powerup_string = "powerup.xml"; const std::string g_default_kart_char_string = "kart_characteristics.xml"; + //------------------------------------------------------------------------- + // This function also exists in an anonymous namespace in ServerLobby. + // I'll decide later what to do with it. + + /** Returns true if world is active for clients to live join, spectate or + * going back to lobby live + */ + bool worldIsActive() + { + return World::getWorld() && RaceEventManager::get()->isRunning() && + !RaceEventManager::get()->isRaceOver() && + World::getWorld()->getPhase() == WorldStatus::RACE_PHASE; + } // worldIsActive + //------------------------------------------------------------------------- + } // namespace @@ -45,5 +80,455 @@ void GameInfo::setKartCharString(const std::string&& str) else m_kart_char_string = str; } // setKartCharString +//----------------------------------------------------------------------------- + +void GameInfo::fillFromRaceManager() +{ + for (int i = 0; i < (int)RaceManager::get()->getNumPlayers(); i++) + { + PlayerInfo info; + RemoteKartInfo& rki = RaceManager::get()->getKartInfo(i); + if (!rki.isReserved()) + { + info = GameInfo::PlayerInfo(false/* reserved */, + false/* game event*/); + // TODO: I suspected it to be local name, but it's not! + info.m_username = StringUtils::wideToUtf8(rki.getPlayerName()); + info.m_kart = rki.getKartName(); + //info.m_start_position = i; + info.m_when_joined = 0; + info.m_country_code = rki.getCountryCode(); + info.m_online_id = rki.getOnlineId(); + info.m_kart_class = rki.getKartData().m_kart_type; + info.m_kart_color = rki.getDefaultKartColor(); + info.m_handicap = (uint8_t)rki.getHandicap(); + info.m_team = (int8_t)rki.getKartTeam(); + if (info.m_team == KartTeam::KART_TEAM_NONE) + { + auto npp = rki.getNetworkPlayerProfile().lock(); + if (npp) + info.m_team = npp->getTemporaryTeam() - 1; + } + } + else + { + info = GameInfo::PlayerInfo(true/* reserved */, + false/* game event*/); + } + m_player_info.push_back(info); + } +} // fillFromRaceManager +//----------------------------------------------------------------------------- + +int GameInfo::onLiveJoinedPlayer(int id, const RemoteKartInfo& rki, World* w) +{ + if (!m_player_info[id].isReserved()) + { + Log::error("GameInfo", "While live joining kart %d, " + "player info was not reserved.", id); + } + std::string name = StringUtils::wideToUtf8(rki.getPlayerName()); + auto& info = m_player_info[id]; + info = GameInfo::PlayerInfo(false/* reserved */, + false/* game event*/); + info.m_username = StringUtils::wideToUtf8(rki.getPlayerName()); + info.m_kart = rki.getKartName(); + info.m_start_position = w->getStartPosition(id); + info.m_when_joined = stk_config->ticks2Time(w->getTicksSinceStart()); + info.m_country_code = rki.getCountryCode(); + info.m_online_id = rki.getOnlineId(); + info.m_kart_class = rki.getKartData().m_kart_type; + info.m_kart_color = rki.getDefaultKartColor(); + info.m_handicap = (uint8_t)rki.getHandicap(); + info.m_team = (int8_t)rki.getKartTeam(); + if (info.m_team == KartTeam::KART_TEAM_NONE) + { + auto npp = rki.getNetworkPlayerProfile().lock(); + if (npp) + info.m_team = npp->getTemporaryTeam() - 1; + } + int points = 0; + if (RaceManager::get()->isBattleMode()) + { + if (getSettings()->isPreservingBattleScores()) + points = m_saved_ffa_points[name]; + + info.m_result -= points; + } + return points; +} // onLiveJoinedPlayer +//----------------------------------------------------------------------------- + +void GameInfo::saveDisconnectingPeerInfo(std::shared_ptr peer) +{ + if (worldIsActive() && !peer->isWaitingForGame()) + { + for (const int id : peer->getAvailableKartIDs()) + { + saveDisconnectingIdInfo(id); + } + } +} // saveDisconnectingPeerInfo + +//----------------------------------------------------------------------------- +void GameInfo::saveDisconnectingIdInfo(int id) +{ + World* w = World::getWorld(); + FreeForAll* ffa_world = dynamic_cast(w); + LinearWorld* linear_world = dynamic_cast(w); + RemoteKartInfo& rki = RaceManager::get()->getKartInfo(id); + int points = 0; + m_player_info.emplace_back(true/* reserved */, + false/* game event*/); + std::swap(m_player_info.back(), m_player_info[id]); + auto& info = m_player_info.back(); + if (RaceManager::get()->isBattleMode()) + { + if (ffa_world) + points = ffa_world->getKartScore(id); + info.m_result += points; + if (getSettings()->isPreservingBattleScores()) + m_saved_ffa_points[StringUtils::wideToUtf8(rki.getPlayerName())] = points; + } + info.m_when_left = stk_config->ticks2Time(w->getTicksSinceStart()); + info.m_start_position = w->getStartPosition(id); + if (RaceManager::get()->isLinearRaceMode()) + { + info.m_autofinish = 0; + info.m_fastest_lap = -1; + info.m_sog_time = -1; + if (linear_world) + { + info.m_fastest_lap = (double)linear_world->getFastestLapForKart(id); + info.m_sog_time = linear_world->getStartTimeForKart(id); + } + info.m_not_full = 1; + // If a player disconnects before the final screen but finished, + // don't set him as "quitting" + if (w->getKart(id)->hasFinishedRace()) + info.m_not_full = 0; + if (info.m_not_full == 1) + info.m_result = info.m_when_left; + else + info.m_result = RaceManager::get()->getKartRaceTime(id); + } +} // saveDisconnectingIdInfo +//----------------------------------------------------------------------------- + +void GameInfo::fillAndStoreResults() +{ + World* w = World::getWorld(); + if (!w) + return; + + RaceManager* rm = RaceManager::get(); + m_timestamp = StkTime::getLogTimeFormatted("%Y-%m-%d %H:%M:%S"); + m_venue = rm->getTrackName(); + m_reverse = (rm->getReverseTrack() || + rm->getRandomItemsIndicator() ? "reverse" : "normal"); + m_mode = rm->getMinorModeName(); + m_value_limit = 0; + m_time_limit = rm->getTimeTarget(); + m_difficulty = getLobby()->getDifficulty(); + setPowerupString(powerup_manager->getFileName()); + setKartCharString(kart_properties_manager->getFileName()); + + if (rm->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) + { + m_value_limit = rm->getHitCaptureLimit(); + m_flag_return_timeout = getSettings()->getFlagReturnTimeout(); + m_flag_deactivated_time = getSettings()->getFlagDeactivatedTime(); + } + else if (rm->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) + { + m_value_limit = rm->getHitCaptureLimit(); // TODO doesn't work + m_flag_return_timeout = 0; + m_flag_deactivated_time = 0; + } + else if (rm->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) + { + m_value_limit = rm->getMaxGoal(); // TODO doesn't work + m_flag_return_timeout = 0; + m_flag_deactivated_time = 0; + } + else + { + m_value_limit = rm->getNumLaps(); + m_flag_return_timeout = 0; + m_flag_deactivated_time = 0; + } + // m_timestamp = TODO; + + bool racing_mode = false; + bool soccer = false; + bool ffa = false; + bool ctf = false; + auto minor_mode = RaceManager::get()->getMinorMode(); + racing_mode |= minor_mode == RaceManager::MINOR_MODE_NORMAL_RACE; + racing_mode |= minor_mode == RaceManager::MINOR_MODE_TIME_TRIAL; + racing_mode |= minor_mode == RaceManager::MINOR_MODE_LAP_TRIAL; + ffa |= minor_mode == RaceManager::MINOR_MODE_FREE_FOR_ALL; + ctf |= minor_mode == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG; + soccer |= minor_mode == RaceManager::MINOR_MODE_SOCCER; + + // Kart class for standard karts + // Goal scoring policy? + // Do we really need round()/int for ingame timestamps? + + FreeForAll* ffa_world = dynamic_cast(World::getWorld()); + LinearWorld* linear_world = dynamic_cast(World::getWorld()); + + bool record_fetched = false; + bool record_exists = false; + double best_result = 0.0; + std::string best_user = ""; + + if (racing_mode) + { +#ifdef ENABLE_SQLITE3 + record_fetched = getDbConnector()->getBestResult(*this, &record_exists, &best_user, &best_result); +#endif + } + + int best_cur_player_idx = -1; + std::string best_cur_player_name = ""; + double best_cur_time = 1e18; + + double current_game_timestamp = stk_config->ticks2Time(w->getTicksSinceStart()); + + auto& vec = m_player_info; + + // Set game duration for all items, including game events + // and reserved PlayerInfos (even if those will be removed) + for (unsigned i = 0; i < vec.size(); i++) + { + auto& info = vec[i]; + info.m_game_duration = current_game_timestamp; + if (!info.isReserved() && info.m_kart_class.empty()) + { + float width, height, length; + Vec3 gravity_shift; + const KartProperties* kp = OfficialKarts::getKartByIdent(info.m_kart, + &width, &height, &length, &gravity_shift); + if (kp) + info.m_kart_class = kp->getKartType(); + } + } + // For those players inside the game, set some variables + for (unsigned i = 0; i < RaceManager::get()->getNumPlayers(); i++) + { + auto& info = vec[i]; + if (info.isReserved()) + continue; + info.m_when_left = current_game_timestamp; + info.m_start_position = w->getStartPosition(i); + if (ffa || ctf) + { + int points = 0; + if (ffa_world) + points = ffa_world->getKartScore(i); + else + Log::error("GameInfo", "storeResults: battle mode but FFAWorld is not found"); + info.m_result += points; + // I thought it would make sense to set m_autofinish to 1 if + // someone wins before time expires. However, it's not hard + // to check after reading the database I suppose... + info.m_autofinish = 0; + } + else if (racing_mode) + { + info.m_fastest_lap = -1; + info.m_sog_time = -1; + info.m_autofinish = -1; + info.m_result = rm->getKartRaceTime(i); + float finish_timeout = std::numeric_limits::max(); + if (linear_world) + { + info.m_fastest_lap = (double)linear_world->getFastestLapForKart(i); + finish_timeout = linear_world->getWorstFinishTime(); + info.m_sog_time = linear_world->getStartTimeForKart(i); + info.m_autofinish = (info.m_result < finish_timeout ? 0 : 1); + } + else + Log::error("GameInfo", "storeResults: racing mode but LinearWorld is not found"); + info.m_not_full = 0; + } + else if (soccer) + { + // Soccer's m_result is handled in SoccerWorld + info.m_autofinish = 0; + } + } + // If the mode is not racing (in which case we set it separately), + // set m_not_full to false iff he was present all the time + if (!racing_mode) + { + for (unsigned i = 0; i < vec.size(); i++) + { + if (vec[i].m_reserved == 0 && vec[i].m_game_event == 0) + vec[i].m_not_full = (vec[i].m_when_joined == 0 && + vec[i].m_when_left == current_game_timestamp ? 0 : 1); + } + } + // Remove reserved PlayerInfos. Note that the first getNumPlayers() items + // no longer correspond to same ID in RaceManager (if they exist even) + for (int i = 0; i < (int)vec.size(); i++) + { + if (vec[i].isReserved()) + { + std::swap(vec[i], vec.back()); + vec.pop_back(); + --i; + } + } + bool sort_asc = !racing_mode; + std::sort(vec.begin(), vec.end(), [sort_asc] + (GameInfo::PlayerInfo& lhs, GameInfo::PlayerInfo& rhs) -> bool { + if (lhs.m_game_event != rhs.m_game_event) + return lhs.m_game_event < rhs.m_game_event; + if (lhs.m_when_joined != rhs.m_when_joined) + return lhs.m_when_joined < rhs.m_when_joined; + if (lhs.m_result != rhs.m_result) + return (lhs.m_result > rhs.m_result) ^ sort_asc; + return false; + }); + if (soccer || ctf) + { + for (unsigned i = 1; i < vec.size(); i++) + { + if (vec[i].m_game_event == 1) + { + double previous = 0; + if (vec[i - 1].m_game_event == 1) + previous = vec[i - 1].m_when_joined; + vec[i].m_sog_time = vec[i].m_when_joined - previous; + } + } + } + // For racing, find who won and possibly beaten the record + if (racing_mode) + { + for (unsigned i = 0; i < vec.size(); i++) + { + if (vec[i].m_reserved == 0 && vec[i].m_game_event == 0 && + vec[i].m_not_full == 0 && + (best_cur_player_idx == -1 || vec[i].m_result < best_cur_time)) + { + best_cur_player_idx = i; + best_cur_time = vec[i].m_result; + best_cur_player_name = vec[i].m_username; + } + } + } + + // Note that before, when online_id was 0, "* " was added to the beginning + // of the name. I'm not sure it's really needed now that online_id is saved. + // Note that before, string was used to write the result to take into + // account increased precision for racing. Examples: + // racing: elapsed_string << std::setprecision(4) << std::fixed << score; + // ffa: elapsed_string << std::setprecision(0) << std::fixed << score; + + m_saved_ffa_points.clear(); + +#ifdef ENABLE_SQLITE3 + getDbConnector()->insertManyResults(*this); +#endif + // end of insertions + if (record_fetched && best_cur_player_idx != -1) // implies racing_mode + { + std::string message; + if (!record_exists) + { + message = StringUtils::insertValues( + "%s has just set a server record: %s\nThis is the first time set.", + best_cur_player_name, StringUtils::timeToString(best_cur_time)); + } + else if (best_result > best_cur_time) + { + message = StringUtils::insertValues( + "%s has just beaten a server record: %s\nPrevious record: %s by %s", + best_cur_player_name, StringUtils::timeToString(best_cur_time), + StringUtils::timeToString(best_result), best_user); + } + if (!message.empty()) + getLobby()->sendStringToAllPeers(message); + } + +} // fillAndStoreResults +//----------------------------------------------------------------------------- + +void GameInfo::onFlagCaptured(bool red_team_scored, const irr::core::stringw& name, + int kart_id, unsigned start_pos, float time_since_start) +{ + m_player_info.emplace_back(false/* reserved */, + true/* game event*/); + auto& info = m_player_info.back(); + RemoteKartInfo& rki = RaceManager::get()->getKartInfo(kart_id); + info.m_username = StringUtils::wideToUtf8(name); + info.m_result = (red_team_scored ? 1 : -1); + info.m_kart = rki.getKartName(); + info.m_kart_class = rki.getKartData().m_kart_type; + info.m_kart_color = rki.getDefaultKartColor(); + info.m_team = (int8_t)rki.getKartTeam(); + if (info.m_team == KartTeam::KART_TEAM_NONE) + { + auto npp = rki.getNetworkPlayerProfile().lock(); + if (npp) + info.m_team = npp->getTemporaryTeam() - 1; + } + info.m_handicap = (uint8_t)rki.getHandicap(); + info.m_start_position = start_pos; + info.m_online_id = rki.getOnlineId(); + info.m_country_code = rki.getCountryCode(); + info.m_when_joined = time_since_start; + info.m_when_left = info.m_when_joined; +} // onFlagCaptured //----------------------------------------------------------------------------- + +// Note that the signature is a bit different in the first bool +void GameInfo::onGoalScored(bool correct_goal, const irr::core::stringw& name, + int kart_id, unsigned start_pos, float time_since_start) +{ + int sz = m_player_info.size(); + m_player_info.emplace_back(false/* reserved */, + true/* game event*/); + + Log::info("SoccerWorld", "player info size before: %d, after: %d", + sz, (int)m_player_info.size()); + + auto& info = m_player_info.back(); + RemoteKartInfo& rki = RaceManager::get()->getKartInfo(kart_id); + info.m_username = StringUtils::wideToUtf8(name); + info.m_result = (correct_goal ? 1 : -1); + info.m_kart = rki.getKartName(); + info.m_kart_class = rki.getKartData().m_kart_type; + info.m_kart_color = rki.getDefaultKartColor(); + info.m_team = (int8_t)rki.getKartTeam(); + if (info.m_team == KartTeam::KART_TEAM_NONE) + { + auto npp = rki.getNetworkPlayerProfile().lock(); + if (npp) + info.m_team = npp->getTemporaryTeam() - 1; + } + info.m_handicap = (uint8_t)rki.getHandicap(); + info.m_start_position = start_pos; + info.m_online_id = rki.getOnlineId(); + info.m_country_code = rki.getCountryCode(); + info.m_when_joined = time_since_start; + info.m_when_left = info.m_when_joined; + if (rki.isReserved()) + { + // Unfortunately it's unknown which ID the corresponding player + // has. Maybe the placement of items for disconnected players + // should be changed in GameInfo::m_player_info. I have no idea + // right now... + info.m_not_full = 1; + } + else + { + info.m_not_full = 0; + m_player_info[kart_id].m_result += info.m_result; + } +} // onGoalScored +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/game_info.hpp b/src/utils/game_info.hpp index 2b7831b9557..e827450ffbc 100644 --- a/src/utils/game_info.hpp +++ b/src/utils/game_info.hpp @@ -19,15 +19,22 @@ #ifndef GAME_INFO_HPP #define GAME_INFO_HPP +#include "utils/lobby_context.hpp" +#include "irrString.h" + #include #include #include +class RemoteKartInfo; +class STKPeer; +class World; + /** A simple structure to store the info about the game. * It includes game settings, the results of individual players, as well as * important team game events like flag captures or goals. */ -struct GameInfo +struct GameInfo: public LobbyContextUser { struct PlayerInfo { @@ -83,6 +90,18 @@ struct GameInfo void setKartCharString(const std::string&& str); std::string getPowerupString() const { return m_powerup_string; } std::string getKartCharString() const { return m_kart_char_string; } + + void fillFromRaceManager(); + int onLiveJoinedPlayer(int id, const RemoteKartInfo& rki, World* w); + void saveDisconnectingPeerInfo(std::shared_ptr peer); + void saveDisconnectingIdInfo(int id); + void fillAndStoreResults(); + + void onFlagCaptured(bool red_team_scored, const irr::core::stringw& name, + int kart_id, unsigned start_pos, float time_since_start); + + void onGoalScored(bool correct_goal, const irr::core::stringw& name, + int kart_id, unsigned start_pos, float time_since_start); }; #endif diff --git a/src/utils/lobby_context.cpp b/src/utils/lobby_context.cpp index 65649b4384c..d14781bc90f 100644 --- a/src/utils/lobby_context.cpp +++ b/src/utils/lobby_context.cpp @@ -32,6 +32,7 @@ #include "utils/gp_scoring.hpp" #include "utils/crown_manager.hpp" #include "network/game_setup.hpp" +#include "network/database_connector.hpp" LobbyContext::LobbyContext(ServerLobby* lobby, bool make_tournament) : m_lobby(lobby) @@ -48,6 +49,10 @@ LobbyContext::LobbyContext(ServerLobby* lobby, bool make_tournament) m_team_manager = std::make_shared(this); m_gp_manager = std::make_shared(this); m_crown_manager = std::make_shared(this); + +#ifdef ENABLE_SQLITE3 + m_db_connector = std::make_shared(this); +#endif if (make_tournament) m_tournament = std::make_shared(this); @@ -69,6 +74,10 @@ void LobbyContext::setup() m_gp_manager->setupContextUser(); m_crown_manager->setupContextUser(); +#ifdef ENABLE_SQLITE3 + m_db_connector->setupContextUser(); +#endif + if (m_tournament) m_tournament->setupContextUser(); } // setup diff --git a/src/utils/lobby_context.hpp b/src/utils/lobby_context.hpp index 68335aca103..4034017cc52 100644 --- a/src/utils/lobby_context.hpp +++ b/src/utils/lobby_context.hpp @@ -38,6 +38,11 @@ class LobbyGPManager; class CrownManager; class GameSetup; +#ifdef ENABLE_SQLITE3 +class DatabaseConnector; +#endif + + class LobbyContext { private: @@ -56,6 +61,10 @@ class LobbyContext std::shared_ptr m_gp_manager; std::shared_ptr m_crown_manager; +#ifdef ENABLE_SQLITE3 + std::shared_ptr m_db_connector; +#endif + public: LobbyContext(ServerLobby* lobby, bool make_tournament); @@ -78,6 +87,10 @@ class LobbyContext std::shared_ptr getTeamManager() const { return m_team_manager; } std::shared_ptr getGPManager() const { return m_gp_manager; } std::shared_ptr getCrownManager() const { return m_crown_manager; } + +#ifdef ENABLE_SQLITE3 + std::shared_ptr getDbConnector() const { return m_db_connector; } +#endif }; class LobbyContextUser @@ -100,6 +113,10 @@ class LobbyContextUser std::shared_ptr getGPManager() const { return m_context->getGPManager(); } std::shared_ptr getCrownManager() const { return m_context->getCrownManager(); } +#ifdef ENABLE_SQLITE3 + std::shared_ptr getDbConnector() const { return m_context->getDbConnector(); } +#endif + public: void setContext(LobbyContext* context) { m_context = context; } }; From 8eec69087d3a3a19e6c029dfb86331720f00f852 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 26 Mar 2025 21:56:56 +0400 Subject: [PATCH 636/830] Minor movements --- src/network/protocols/server_lobby.cpp | 80 ++++++++++---------------- src/network/protocols/server_lobby.hpp | 1 - src/utils/lobby_settings.cpp | 39 +++++++++++++ src/utils/lobby_settings.hpp | 8 ++- 4 files changed, 74 insertions(+), 54 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 126a68cea09..1a7df1999e8 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -606,8 +606,7 @@ void ServerLobby::asynchronousUpdate() if (getSettings()->isRanked() && m_state.load() == WAITING_FOR_START_GAME) m_ranking->cleanup(); - if (!getSettings()->isLegacyGPMode() || (getSettings()->isLegacyGPMode() && - m_state.load() == WAITING_FOR_START_GAME)) + if (!getSettings()->isLegacyGPMode() || m_state.load() == WAITING_FOR_START_GAME) { // Only poll the STK server if server has been registered. if (m_server_id_online.load() != 0 && @@ -727,7 +726,7 @@ void ServerLobby::asynchronousUpdate() setInfiniteTimeout(); } bool forbid_starting = false; - if (getTournament() && getTournament()->forbidStarting()) + if (isTournament() && getTournament()->forbidStarting()) forbid_starting = true; bool timer_finished = (!forbid_starting && isTimeoutExpired()); @@ -808,16 +807,7 @@ void ServerLobby::asynchronousUpdate() } if (go_on_race) { - if (getSettings()->hasFixedLapCount()) - { - winner_vote.m_num_laps = getSettings()->getFixedLapCount(); - Log::info("ServerLobby", "Enforcing %d lap race", getSettings()->getFixedLapCount()); - } - if (getSettings()->hasFixedDirection()) - { - winner_vote.m_reverse = (getSettings()->getDirection() == 1); - Log::info("ServerLobby", "Enforcing direction %d", (int)getSettings()->getDirection()); - } + getSettings()->applyRestrictionsOnWinnerVote(&winner_vote); getSettings()->setDefaultVote(winner_vote); m_item_seed = (uint32_t)StkTime::getTimeSinceEpoch(); ItemManager::updateRandomSeed(m_item_seed); @@ -887,7 +877,7 @@ void ServerLobby::asynchronousUpdate() if (peer) peer->addAvailableKartID(i); } - getHitCaptureLimit(); + getSettings()->getLobbyHitCaptureLimit(); // Add placeholder players for live join addLiveJoinPlaceholder(players); @@ -2386,8 +2376,8 @@ void ServerLobby::connectionRequested(Event* event) return; } - // Reject non-valiated player joinning if WAN server and not disabled - // encforement of validation, unless it's player from localhost or lan + // Reject non-validated player joinning if WAN server and not disabled + // enforcement of validation, unless it's player from localhost or lan // And no duplicated online id or split screen players in ranked server // AIPeer only from lan and only 1 if ai handling std::set all_online_ids = @@ -2395,16 +2385,27 @@ void ServerLobby::connectionRequested(Event* event) bool duplicated_ranked_player = all_online_ids.find(online_id) != all_online_ids.end(); - if (((encrypted_size == 0 || online_id == 0) && - !(peer->getAddress().isPublicAddressLocalhost() || - peer->getAddress().isLAN()) && - NetworkConfig::get()->isWAN() && - getSettings()->isValidatingPlayer()) || - (getSettings()->hasStrictPlayers() && - (player_count != 1 || online_id == 0 || duplicated_ranked_player)) || - (peer->isAIPeer() && !peer->getAddress().isLAN() && !getSettings()->canConnectAiAnywhere()) || - (peer->isAIPeer() && - getSettings()->hasAiHandling() && !m_ai_peer.expired())) + bool failed_validation = + (encrypted_size == 0 || online_id == 0) && + !(peer->getAddress().isPublicAddressLocalhost() || peer->getAddress().isLAN()) && + NetworkConfig::get()->isWAN() && + getSettings()->isValidatingPlayer(); + + bool failed_strictness = + getSettings()->hasStrictPlayers() && + (player_count != 1 || online_id == 0 || duplicated_ranked_player); + + bool failed_anywhere_ai = + peer->isAIPeer() && + !peer->getAddress().isLAN() && + !getSettings()->canConnectAiAnywhere(); + + bool failed_unhandled_ai = + peer->isAIPeer() && + getSettings()->hasAiHandling() && + !m_ai_peer.expired(); + + if (failed_validation || failed_strictness || failed_anywhere_ai || failed_unhandled_ai) { NetworkString* message = getNetworkString(2); message->setSynchronous(true); @@ -3069,30 +3070,6 @@ bool ServerLobby::handleAllVotes(PeerVote* winner_vote) ); } // handleAllVotes -// ---------------------------------------------------------------------------- -void ServerLobby::getHitCaptureLimit() -{ - int hit_capture_limit = std::numeric_limits::max(); - float time_limit = 0.0f; - if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) - { - if (getSettings()->getCaptureLimit() > 0) - hit_capture_limit = getSettings()->getCaptureLimit(); - if (getSettings()->getTimeLimitCtf() > 0) - time_limit = (float)getSettings()->getTimeLimitCtf(); - } - else - { - if (getSettings()->getHitLimit() > 0) - hit_capture_limit = getSettings()->getHitLimit(); - if (getSettings()->getTimeLimitFfa() > 0.0f) - time_limit = (float)getSettings()->getTimeLimitFfa(); - } - getSettings()->setBattleHitCaptureLimit(hit_capture_limit); - getSettings()->setBattleTimeLimit(time_limit); -} // getHitCaptureLimit - // ---------------------------------------------------------------------------- /** Called from the RaceManager of the server when the world is loaded. Marks * the server to be ready to start the race. @@ -4272,6 +4249,7 @@ void ServerLobby::sendStringToAllPeers(const std::string& s) delete chat; } // sendStringToAllPeers //----------------------------------------------------------------------------- + bool ServerLobby::canVote(std::shared_ptr peer) const { if (!peer || peer->getPlayerProfiles().empty()) @@ -4283,6 +4261,7 @@ bool ServerLobby::canVote(std::shared_ptr peer) const return getTournament()->canVote(peer); } // canVote //----------------------------------------------------------------------------- + bool ServerLobby::hasHostRights(std::shared_ptr peer) const { if (!peer || peer->getPlayerProfiles().empty()) @@ -4297,6 +4276,7 @@ bool ServerLobby::hasHostRights(std::shared_ptr peer) const return false; } // hasHostRights //----------------------------------------------------------------------------- + int ServerLobby::getPermissions(std::shared_ptr peer) const { int mask = 0; diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index a0ea55b0e5e..14cfb862295 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -248,7 +248,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser void submitRankingsToAddons(); void computeNewRankings(NetworkString* ns); void checkRaceFinished(); - void getHitCaptureLimit(); void configPeersStartTime(); void resetServer(); void addWaitingPlayersToGame(); diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index efe9f8e2dd8..0d103b06027 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -538,6 +538,21 @@ void LobbySettings::applyRestrictionsOnVote(PeerVote* vote, Track* t) const } // applyRestrictionsOnVote //----------------------------------------------------------------------------- +void LobbySettings::applyRestrictionsOnWinnerVote(PeerVote* winner_vote) const +{ + if (hasFixedLapCount()) + { + winner_vote->m_num_laps = getFixedLapCount(); + Log::info("LobbySettings", "Enforcing %d lap race", getFixedLapCount()); + } + if (hasFixedDirection()) + { + winner_vote->m_reverse = (getDirection() == 1); + Log::info("LobbySettings", "Enforcing direction %d", (int)getDirection()); + } +} // applyRestrictionsOnWinnerVote +//----------------------------------------------------------------------------- + void LobbySettings::encodeDefaultVote(NetworkString* ns) const { ns->addUInt32(m_winner_peer_id); @@ -636,3 +651,27 @@ bool LobbySettings::isCooldown() const return passed_since_reset < 1000 * m_lobby_cooldown; } // isCooldown //----------------------------------------------------------------------------- + +void LobbySettings::getLobbyHitCaptureLimit() +{ + int hit_capture_limit = std::numeric_limits::max(); + float time_limit = 0.0f; + if (RaceManager::get()->getMinorMode() == + RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) + { + if (m_capture_limit > 0) + hit_capture_limit = m_capture_limit; + if (m_time_limit_ctf > 0) + time_limit = (float)m_time_limit_ctf; + } + else + { + if (m_hit_limit > 0) + hit_capture_limit = m_hit_limit; + if (m_time_limit_ffa > 0.0f) + time_limit = (float)m_time_limit_ffa; + } + m_battle_hit_capture_limit = hit_capture_limit; + m_battle_time_limit = time_limit; +} // getLobbyHitCaptureLimit +// ---------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 79a131e7e3b..6f92eb0bb57 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -83,6 +83,7 @@ class LobbySettings: public LobbyContextComponent void insertIntoPreserved(const std::string& value); void initializeDefaultVote(); void applyRestrictionsOnVote(PeerVote* vote, Track* t) const; + void applyRestrictionsOnWinnerVote(PeerVote* winner_vote) const; void encodeDefaultVote(NetworkString* ns) const; void setDefaultVote(PeerVote winner_vote); PeerVote getDefaultVote() const; @@ -95,9 +96,9 @@ class LobbySettings: public LobbyContextComponent int getBattleHitCaptureLimit() const { return m_battle_hit_capture_limit; } float getBattleTimeLimit() const { return m_battle_time_limit; } - void setBattleHitCaptureLimit(int value) - { m_battle_hit_capture_limit = value; } - void setBattleTimeLimit(float value) { m_battle_time_limit = value; } + // void setBattleHitCaptureLimit(int value) + // { m_battle_hit_capture_limit = value; } + // void setBattleTimeLimit(float value) { m_battle_time_limit = value; } void setLobbyCooldown(int value) { m_lobby_cooldown = value; } bool isCooldown() const; @@ -119,6 +120,7 @@ class LobbySettings: public LobbyContextComponent { m_temp_banned.insert(username); } void tempUnban(const std::string& username) { m_temp_banned.erase(username); } + void getLobbyHitCaptureLimit(); // These were used unchanged from ServerConfig bool isLivePlayers() const { return m_live_players; } From 0a9dce9f0ac39da31fa594c544a5407f9fad3529 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 27 Mar 2025 22:17:05 +0400 Subject: [PATCH 637/830] STKConfig is no longer a lonely pointer Let it be 100+ files changed, I'm tired of that :) --- src/addons/addons_manager.cpp | 12 ++-- src/addons/news_manager.cpp | 2 + src/animations/three_d_animation.cpp | 2 +- src/config/hardware_stats.cpp | 2 +- src/config/stk_config.cpp | 12 +++- src/config/stk_config.hpp | 11 +-- src/graphics/camera/camera.cpp | 2 +- src/graphics/camera/camera_debug.cpp | 2 +- src/graphics/camera/camera_fps.cpp | 2 +- src/graphics/camera/camera_normal.cpp | 2 +- src/graphics/explosion.cpp | 1 + src/graphics/material.cpp | 6 +- src/graphics/referee.cpp | 2 +- src/graphics/shader_files_manager.cpp | 2 +- src/graphics/skid_marks.cpp | 2 + src/graphics/skybox.cpp | 2 +- src/graphics/slip_stream.cpp | 6 +- src/graphics/sp/sp_base.cpp | 10 +-- src/graphics/sp/sp_texture.cpp | 2 +- src/guiengine/screen.hpp | 2 +- src/guiengine/skin.cpp | 1 + src/items/attachment.cpp | 7 +- src/items/bowling.cpp | 2 +- src/items/flyable.cpp | 2 +- src/items/item.cpp | 7 +- src/items/item_manager.cpp | 4 +- src/items/plunger.cpp | 2 +- src/items/powerup.cpp | 4 ++ src/items/powerup_manager.cpp | 2 + src/items/rubber_ball.cpp | 12 ++-- src/items/rubber_band.cpp | 4 +- src/items/swatter.cpp | 6 ++ src/karts/abstract_kart_animation.cpp | 2 +- src/karts/cannon_animation.cpp | 4 +- src/karts/controller/ai_base_controller.cpp | 2 + src/karts/controller/arena_ai.cpp | 6 +- src/karts/controller/end_controller.cpp | 2 +- .../controller/local_player_controller.cpp | 2 +- .../controller/network_player_controller.hpp | 2 +- src/karts/controller/player_controller.cpp | 10 +-- src/karts/controller/skidding_ai.cpp | 67 +++++++++++-------- src/karts/controller/test_ai.cpp | 53 ++++++++------- src/karts/explosion_animation.cpp | 8 +-- src/karts/ghost_kart.cpp | 3 + src/karts/kart.cpp | 36 +++++++--- src/karts/kart_properties.cpp | 8 ++- src/karts/kart_properties_manager.cpp | 2 + src/karts/kart_rewinder.cpp | 2 +- src/karts/kart_with_stats.cpp | 2 +- src/karts/moveable.cpp | 2 +- src/karts/rescue_animation.cpp | 5 ++ src/karts/skidding.cpp | 6 +- src/main.cpp | 10 ++- src/main_loop.cpp | 2 + src/modes/capture_the_flag.cpp | 6 +- src/modes/cutscene_world.cpp | 2 +- src/modes/follow_the_leader.cpp | 11 ++- src/modes/linear_world.cpp | 6 +- src/modes/linear_world.hpp | 6 +- src/modes/soccer_world.cpp | 8 ++- src/modes/soccer_world.hpp | 2 +- src/modes/three_strikes_battle.cpp | 4 +- src/modes/world.cpp | 6 +- src/modes/world_status.cpp | 14 +++- src/modes/world_with_rank.cpp | 2 +- src/network/child_loop.cpp | 3 + src/network/network_config.cpp | 5 +- src/network/protocols/client_lobby.cpp | 1 + src/network/protocols/connect_to_server.cpp | 2 +- src/network/protocols/server_lobby.cpp | 16 ++++- src/network/rewind_manager.cpp | 2 +- src/network/server_config.cpp | 4 ++ src/network/servers_manager.cpp | 12 +++- src/network/smooth_network_body.cpp | 3 + src/network/stk_host.cpp | 4 +- src/online/http_request.cpp | 4 +- src/physics/btKart.cpp | 2 + src/physics/btKart.hpp | 2 +- src/physics/physical_object.cpp | 3 +- src/physics/physics.cpp | 7 ++ src/physics/triangle_mesh.cpp | 9 ++- src/race/race_manager.cpp | 4 +- src/replay/replay_recorder.cpp | 10 ++- src/states_screens/credits.cpp | 2 +- src/states_screens/credits.hpp | 2 +- src/states_screens/feature_unlocked.cpp | 7 +- src/states_screens/gp_info_screen.cpp | 2 +- src/states_screens/grand_prix_lose.cpp | 2 +- src/states_screens/grand_prix_win.cpp | 2 +- src/states_screens/online/register_screen.cpp | 2 +- src/states_screens/race_gui_base.cpp | 10 +-- src/states_screens/race_result_gui.cpp | 2 + src/states_screens/track_info_screen.cpp | 2 + src/tracks/track.cpp | 8 +-- src/tracks/track_manager.cpp | 8 ++- src/tracks/track_manager.hpp | 2 +- src/tracks/track_object.cpp | 2 +- src/tracks/track_object_manager.cpp | 3 + src/utils/debug.cpp | 6 +- src/utils/game_info.cpp | 6 +- src/utils/hit_processor.cpp | 8 +-- src/utils/string_utils.cpp | 2 +- 102 files changed, 398 insertions(+), 213 deletions(-) diff --git a/src/addons/addons_manager.cpp b/src/addons/addons_manager.cpp index e8419485bc3..5be30e8da8c 100644 --- a/src/addons/addons_manager.cpp +++ b/src/addons/addons_manager.cpp @@ -204,12 +204,14 @@ void AddonsManager::initAddons(const XMLNode *xml) bool wrong_version=false; + auto& stk_config = STKConfig::get(); + if(addon.getType()=="kart") - wrong_version = stk_version m_min_kart_version || - stk_version >stk_config->m_max_kart_version ; + wrong_version = stk_version < stk_config->m_min_kart_version || + stk_version > stk_config->m_max_kart_version ; else - wrong_version = stk_version m_min_track_version || - stk_version >stk_config->m_max_track_version ; + wrong_version = stk_version < stk_config->m_min_track_version || + stk_version > stk_config->m_max_track_version ; // If the add-on is included, behave like it is a wrong version if (addon.testIncluded(addon.getMinIncludeVer(), addon.getMaxIncludeVer())) wrong_version = true; @@ -658,7 +660,7 @@ void AddonsManager::saveInstalled() xml_installed << "" << std::endl; // Get server address from config - const std::string server = stk_config->m_server_addons; + const std::string server = STKConfig::get()->m_server_addons; // Find the third slash (end of the domain) std::string::size_type index = server.find('/'); diff --git a/src/addons/news_manager.cpp b/src/addons/news_manager.cpp index 77d109e5829..2fd6fd644dd 100644 --- a/src/addons/news_manager.cpp +++ b/src/addons/news_manager.cpp @@ -226,6 +226,8 @@ void NewsManager::downloadNews() */ void NewsManager::checkRedirect(const XMLNode *xml) { + auto& stk_config = STKConfig::get(); + if (stk_config->m_allow_news_redirects) { // NOTE: Before 0.10 there were just two redirect attributes diff --git a/src/animations/three_d_animation.cpp b/src/animations/three_d_animation.cpp index c4e70ee0b8f..e7cbfbb62c4 100644 --- a/src/animations/three_d_animation.cpp +++ b/src/animations/three_d_animation.cpp @@ -86,7 +86,7 @@ void ThreeDAnimation::updateWithWorldTicks(bool has_physics) if (!m_is_paused) { int cur_ticks = World::getWorld()->getTicksSinceStart(); - m_current_time = stk_config->ticks2Time(cur_ticks); + m_current_time = STKConfig::get()->ticks2Time(cur_ticks); } AnimationBase::getAt(m_current_time, &xyz, &m_hpr, &scale); //updates all IPOs diff --git a/src/config/hardware_stats.cpp b/src/config/hardware_stats.cpp index 87021f3f4f1..5c4e5da0317 100644 --- a/src/config/hardware_stats.cpp +++ b/src/config/hardware_stats.cpp @@ -419,7 +419,7 @@ void reportHardwareStats() request->addParameter("type", "hwdetect"); request->addParameter("version", report_version); request->addParameter("data", json.toString()); - const std::string request_url = stk_config->m_server_hardware_report + "/upload/v1/"; + const std::string request_url = STKConfig::get()->m_server_hardware_report + "/upload/v1/"; request->setURL(request_url); //request->setURL("http://127.0.0.1:8000/upload/v1/"); request->queue(); diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp index 655a7dd3d48..bc729fd5eff 100644 --- a/src/config/stk_config.cpp +++ b/src/config/stk_config.cpp @@ -30,7 +30,6 @@ #include "utils/log.hpp" #include "utils/string_utils.hpp" -STKConfig* stk_config=0; float STKConfig::UNDEFINED = -99.9f; //----------------------------------------------------------------------------- @@ -88,6 +87,13 @@ STKConfig::~STKConfig() } } // ~STKConfig +//----------------------------------------------------------------------------- + +std::shared_ptr& STKConfig::get() +{ + static std::shared_ptr instance = std::make_shared(); + return instance; +} // get //----------------------------------------------------------------------------- /** Loads the stk configuration file. After loading it checks if all necessary * values are actually defined, otherwise an error message is printed and STK @@ -518,7 +524,7 @@ void STKConfig::getAllData(const XMLNode * root) switch_node->get("items", &m_switch_items ); float f; if( switch_node->get("time", &f) ) - m_item_switch_ticks = stk_config->time2Ticks(f); + m_item_switch_ticks = STKConfig::get()->time2Ticks(f); } if(const XMLNode *bubblegum_node= root->getNode("bubblegum")) @@ -707,7 +713,7 @@ void STKConfig::initMusicFiles() * for each position. * \param num_karts Number of karts. */ -void STKConfig::getAllScores(std::vector *all_scores, int num_karts) +void STKConfig::getAllScores(std::vector *all_scores, int num_karts) const { std::vector sorted_score_increase; diff --git a/src/config/stk_config.hpp b/src/config/stk_config.hpp index a3144e4f0e9..5a587257b07 100644 --- a/src/config/stk_config.hpp +++ b/src/config/stk_config.hpp @@ -35,6 +35,7 @@ #include #include #include +#include class KartProperties; class MusicInformation; @@ -287,13 +288,14 @@ class STKConfig : public NoCopy public: STKConfig(); ~STKConfig(); + static std::shared_ptr& get(); void init_defaults(); void getAllData(const XMLNode * root); void load(const std::string &filename); const std::string &getMainMenuPicture(int n); const std::string &getBackgroundPicture(int n); void initMusicFiles(); - void getAllScores(std::vector *all_scores, int num_karts); + void getAllScores(std::vector *all_scores, int num_karts) const; // ------------------------------------------------------------------------ /** Returns the default kart properties for each kart. */ const KartProperties & @@ -304,21 +306,20 @@ class STKConfig : public NoCopy * \throw out_of_range if there is no data for 'type'. * \param type Type of kart (e.g. heavy, medium, ...). */ - const KartProperties& getKartProperties(const std::string &type) + const KartProperties& getKartProperties(const std::string &type) const { return *m_kart_properties.at(type); } // getKartProperties // ------------------------------------------------------------------------ /** Converts a tick value (in physics time step size) into seconds. */ - float ticks2Time(int ticks) { return float(ticks)/m_physics_fps; } + float ticks2Time(int ticks) const { return float(ticks)/m_physics_fps; } // ------------------------------------------------------------------------ /** Converts a time value into ticks (of physics time steps). */ - int time2Ticks(float t) { return int(t * m_physics_fps); } + int time2Ticks(float t) const { return int(t * m_physics_fps); } // ------------------------------------------------------------------------ /** Returns the physics frame per seconds rate. */ int getPhysicsFPS() const { return m_physics_fps; } } ; // STKConfig -extern STKConfig* stk_config; #endif diff --git a/src/graphics/camera/camera.cpp b/src/graphics/camera/camera.cpp index e20f645c279..93bad416d41 100644 --- a/src/graphics/camera/camera.cpp +++ b/src/graphics/camera/camera.cpp @@ -131,7 +131,7 @@ Camera::Camera(CameraType type, int camera_index, AbstractKart* kart) if (RaceManager::get()->getNumLocalPlayers() > 1) { - m_fov = DEGREE_TO_RAD * stk_config->m_camera_fov + m_fov = DEGREE_TO_RAD * STKConfig::get()->m_camera_fov [RaceManager::get()->getNumLocalPlayers() - 1]; } else diff --git a/src/graphics/camera/camera_debug.cpp b/src/graphics/camera/camera_debug.cpp index f722d66f7b3..a01b0548d2e 100644 --- a/src/graphics/camera/camera_debug.cpp +++ b/src/graphics/camera/camera_debug.cpp @@ -187,7 +187,7 @@ void CameraDebug::positionCamera(float dt, float above_kart, float cam_angle, fabsf(distance)*tan_up+above_kart, distance); btTransform t=m_kart->getSmoothedTrans(); - if(stk_config->m_camera_follow_skid && + if (STKConfig::get()->m_camera_follow_skid && m_kart->getSkidding()->getVisualSkidRotation()!=0) { // If the camera should follow the graphical skid, add the diff --git a/src/graphics/camera/camera_fps.cpp b/src/graphics/camera/camera_fps.cpp index 7ac6639b8c4..cbf0e8f5c0c 100644 --- a/src/graphics/camera/camera_fps.cpp +++ b/src/graphics/camera/camera_fps.cpp @@ -225,7 +225,7 @@ void CameraFPS::update(float dt) // Move the camera with the kart btTransform t = m_kart->getSmoothedTrans(); - if (stk_config->m_camera_follow_skid && + if (STKConfig::get()->m_camera_follow_skid && m_kart->getSkidding()->getVisualSkidRotation() != 0) { // If the camera should follow the graphical skid, add the diff --git a/src/graphics/camera/camera_normal.cpp b/src/graphics/camera/camera_normal.cpp index 7b0fe092c3a..61ce1fb75b0 100644 --- a/src/graphics/camera/camera_normal.cpp +++ b/src/graphics/camera/camera_normal.cpp @@ -402,7 +402,7 @@ void CameraNormal::positionCamera(float dt, float above_kart, float cam_angle, fabsf(distance)*tan_up+above_kart, distance); btTransform t=m_kart->getSmoothedTrans(); - if(stk_config->m_camera_follow_skid && + if (STKConfig::get()->m_camera_follow_skid && m_kart->getSkidding()->getVisualSkidRotation()!=0) { // If the camera should follow the graphical skid, add the diff --git a/src/graphics/explosion.cpp b/src/graphics/explosion.cpp index 3bdbddced2e..2658fe0a8c5 100644 --- a/src/graphics/explosion.cpp +++ b/src/graphics/explosion.cpp @@ -39,6 +39,7 @@ Explosion::Explosion(const Vec3& coord, const char* explosion_sound, const char { // short emision time, explosion, not constant flame + auto& stk_config = STKConfig::get(); m_explosion_ticks = stk_config->time2Ticks(2.0f); m_remaining_ticks = stk_config->time2Ticks(0.1f); m_emission_frames = 0; diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index c50b08dff12..0ff6b27ff6f 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -162,9 +162,9 @@ Material::Material(const XMLNode *node, bool deprecated) node->get("ignore", &m_ignore ); node->get("max-speed", &m_max_speed_fraction ); - float f = stk_config->ticks2Time(m_slowdown_ticks); + float f = STKConfig::get()->ticks2Time(m_slowdown_ticks); node->get("slowdown-time", &f ); - m_slowdown_ticks = stk_config->time2Ticks(f); + m_slowdown_ticks = STKConfig::get()->time2Ticks(f); node->get("colorizable", &m_colorizable ); node->get("colorization-factor", &m_colorization_factor); node->get("hue-settings", &m_hue_settings ); @@ -516,7 +516,7 @@ void Material::init() m_colorization_factor = 0.0f; m_colorization_mask = ""; m_max_speed_fraction = 1.0f; - m_slowdown_ticks = stk_config->time2Ticks(1.0f); + m_slowdown_ticks = STKConfig::get()->time2Ticks(1.0f); m_sfx_name = ""; m_sfx_min_speed = 0.0f; m_sfx_max_speed = 30; diff --git a/src/graphics/referee.cpp b/src/graphics/referee.cpp index 18cc6dd0117..328e83ae3b6 100644 --- a/src/graphics/referee.cpp +++ b/src/graphics/referee.cpp @@ -291,7 +291,7 @@ void Referee::selectReadySetGo(int rsg) */ void Referee::setAnimationFrameWithCreatedTicks(int created_ticks) { - float dur = stk_config->ticks2Time( + float dur = STKConfig::get()->ticks2Time( World::getWorld()->getTicksSinceStart() - created_ticks); dur *= 25.0f; float ref_dur = (float)(m_st_last_rescue_frame - m_st_first_rescue_frame); diff --git a/src/graphics/shader_files_manager.cpp b/src/graphics/shader_files_manager.cpp index 899a5e5ca28..348bd931e92 100644 --- a/src/graphics/shader_files_manager.cpp +++ b/src/graphics/shader_files_manager.cpp @@ -210,7 +210,7 @@ ShaderFilesManager::SharedShader ShaderFilesManager::loadShader code << "precision mediump sampler2DArray;\n"; } #endif - code << "#define MAX_BONES " << stk_config->m_max_skinning_bones << "\n"; + code << "#define MAX_BONES " << STKConfig::get()->m_max_skinning_bones << "\n"; code << getHeader(); diff --git a/src/graphics/skid_marks.cpp b/src/graphics/skid_marks.cpp index f7d45d66964..09ee5e4668b 100644 --- a/src/graphics/skid_marks.cpp +++ b/src/graphics/skid_marks.cpp @@ -95,6 +95,8 @@ void SkidMarks::update(float dt, bool force_skid_marks, if (m_kart.isWheeless()) return; + auto& stk_config = STKConfig::get(); + float f = dt / stk_config->m_skid_fadeout_time; auto it = m_left.begin(); // Don't clean the current skidmarking diff --git a/src/graphics/skybox.cpp b/src/graphics/skybox.cpp index 87d7a967126..a30c05d1d17 100644 --- a/src/graphics/skybox.cpp +++ b/src/graphics/skybox.cpp @@ -211,7 +211,7 @@ void Skybox::generateCubeMapFromTextures() bool needs_srgb_format = CVS->isDeferredEnabled(); glBindTexture(GL_TEXTURE_CUBE_MAP, m_cube_map); - const unsigned tc_flag = squish::kDxt5 | stk_config->m_tc_quality; + const unsigned tc_flag = squish::kDxt5 | STKConfig::get()->m_tc_quality; if (CVS->isTextureCompressionEnabled()) { unsigned tex_size = GE::get4x4CompressedTextureSize(size, size); diff --git a/src/graphics/slip_stream.cpp b/src/graphics/slip_stream.cpp index 55c91d19e53..d97193d0806 100644 --- a/src/graphics/slip_stream.cpp +++ b/src/graphics/slip_stream.cpp @@ -869,7 +869,7 @@ void SlipStream::update(int ticks) updateQuad(); } - float dt = stk_config->ticks2Time(ticks); + float dt = STKConfig::get()->ticks2Time(ticks); #ifndef SERVER_ONLY if (!GUIEngine::isNoGraphics()) { @@ -1063,7 +1063,7 @@ void SlipStream::update(int ticks) m_slipstream_time = 0.0f; m_bonus_active = true; - m_speed_increase_duration = stk_config->time2Ticks(m_bonus_time); + m_speed_increase_duration = STKConfig::get()->time2Ticks(m_bonus_time); m_speed_increase_ticks = World::getWorld()->getTicksSinceStart(); } @@ -1138,7 +1138,7 @@ void SlipStream::updateSpeedIncrease() const KartProperties* kp = m_kart->getKartProperties(); float speed_increase = kp->getSlipstreamMaxSpeedIncrease(); float add_power = kp->getSlipstreamAddPower(); - int fade_out = stk_config->time2Ticks(kp->getSlipstreamFadeOutTime()); + int fade_out = STKConfig::get()->time2Ticks(kp->getSlipstreamFadeOutTime()); m_kart->instantSpeedIncrease( MaxSpeed::MS_INCREASE_SLIPSTREAM, speed_increase, speed_increase, add_power, m_speed_increase_duration, fade_out); diff --git a/src/graphics/sp/sp_base.cpp b/src/graphics/sp/sp_base.cpp index f05fd30cec0..3d3a6c14e74 100644 --- a/src/graphics/sp/sp_base.cpp +++ b/src/graphics/sp/sp_base.cpp @@ -262,7 +262,7 @@ void resizeSkinning(unsigned number) m.pointer()); glBindTexture(GL_TEXTURE_2D, 0); static std::vector > - tmp_buf(stk_config->m_max_skinning_bones); + tmp_buf(STKConfig::get()->m_max_skinning_bones); g_joint_ptr = tmp_buf.data(); } else @@ -300,6 +300,8 @@ void initSkinning() { static_assert(sizeof(std::array) == 64, "No padding"); + auto& stk_config = STKConfig::get(); + int max_size = 0; if (!skinningUseTBO()) @@ -448,7 +450,7 @@ void init() int skinning_tbo_limit; glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE_ARB, &skinning_tbo_limit); - g_skinning_use_tbo = skinning_tbo_limit >= stk_config->m_max_skinning_bones << 6; + g_skinning_use_tbo = skinning_tbo_limit >= STKConfig::get()->m_max_skinning_bones << 6; } else { @@ -840,11 +842,11 @@ void addObject(SPMeshNode* node) { added_for_skinning = true; int skinning_offset = g_skinning_offset + node->getTotalJoints(); - if (skinning_offset > int(stk_config->m_max_skinning_bones)) + if (skinning_offset > int(STKConfig::get()->m_max_skinning_bones)) { Log::error("SPBase", "No enough space to render skinned" " mesh %s! Max joints can hold: %d", - node->getName(), stk_config->m_max_skinning_bones); + node->getName(), STKConfig::get()->m_max_skinning_bones); return; } node->setSkinningOffset(g_skinning_offset); diff --git a/src/graphics/sp/sp_texture.cpp b/src/graphics/sp/sp_texture.cpp index bf612747d8f..04f6aa0b4b8 100644 --- a/src/graphics/sp/sp_texture.cpp +++ b/src/graphics/sp/sp_texture.cpp @@ -737,7 +737,7 @@ std::vector > } } - const unsigned tc_flag = squish::kDxt5 | stk_config->m_tc_quality; + const unsigned tc_flag = squish::kDxt5 | STKConfig::get()->m_tc_quality; for (auto& size : mipmap_sizes) { size.second = squish::GetStorageRequirements( diff --git a/src/guiengine/screen.hpp b/src/guiengine/screen.hpp index e26acfab0b3..0e2e9364270 100644 --- a/src/guiengine/screen.hpp +++ b/src/guiengine/screen.hpp @@ -283,7 +283,7 @@ namespace GUIEngine /** * \return which music to play at this screen */ - virtual MusicInformation* getMusic() const { return stk_config->m_title_music; } + virtual MusicInformation* getMusic() const { return STKConfig::get()->m_title_music; } /** * \return which music to play at this screen, if accessed in "in-game-menu" mode diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index e4e1569d6eb..778524284c5 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -187,6 +187,7 @@ namespace SkinConfig static void loadFromFile(std::string file, bool clear_prev_params) { m_data_path.clear(); + auto& stk_config = STKConfig::get(); if (clear_prev_params) { // Clear global variables diff --git a/src/items/attachment.cpp b/src/items/attachment.cpp index 87d2b3fdfaa..134840c09f2 100644 --- a/src/items/attachment.cpp +++ b/src/items/attachment.cpp @@ -137,7 +137,7 @@ void Attachment::set(AttachmentType type, int ticks, m_ticks_left = ticks; m_previous_owner = current_kart; m_scaling_end_ticks = World::getWorld()->getTicksSinceStart() + - stk_config->time2Ticks(0.7f); + STKConfig::get()->time2Ticks(0.7f); m_initial_speed = 0; // A parachute can be attached as result of the usage of an item. In this @@ -282,6 +282,8 @@ void Attachment::hitBanana(ItemState *item_state) m_ticks_left = 0; return; } + + auto& stk_config = STKConfig::get(); int leftover_ticks = 0; @@ -401,6 +403,7 @@ void Attachment::hitBanana(ItemState *item_state) void Attachment::handleCollisionWithKart(AbstractKart *other) { Attachment *attachment_other=other->getAttachment(); + auto& stk_config = STKConfig::get(); if(getType()==Attachment::ATTACH_BOMB) { @@ -606,6 +609,8 @@ void Attachment::updateGraphics(float dt) if (m_plugin) m_plugin->updateGraphics(dt); + auto& stk_config = STKConfig::get(); + if (m_type != ATTACH_NOTHING) { m_node->setVisible(true); diff --git a/src/items/bowling.cpp b/src/items/bowling.cpp index 3bf2b257e41..eb3d6b05675 100644 --- a/src/items/bowling.cpp +++ b/src/items/bowling.cpp @@ -251,5 +251,5 @@ void Bowling::onFireFlyable() setAdjustUpVelocity(false); // should not live forever, auto-destruct after 20 seconds - m_max_lifespan = stk_config->time2Ticks(20); + m_max_lifespan = STKConfig::get()->time2Ticks(20); } // onFireFlyable diff --git a/src/items/flyable.cpp b/src/items/flyable.cpp index d22b6e64e7d..b305d886d96 100644 --- a/src/items/flyable.cpp +++ b/src/items/flyable.cpp @@ -538,7 +538,7 @@ bool Flyable::isOwnerImmunity(const AbstractKart* kart_hit) const { return m_owner_has_temporary_immunity && kart_hit == m_owner && - (int)m_ticks_since_thrown < stk_config->time2Ticks(2.0f); + (int)m_ticks_since_thrown < STKConfig::get()->time2Ticks(2.0f); } // isOwnerImmunity // ---------------------------------------------------------------------------- diff --git a/src/items/item.cpp b/src/items/item.cpp index 79f1b6f2781..b08d87ead20 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -59,7 +59,7 @@ ItemState::ItemState(ItemType type, const AbstractKart *owner, int id) m_previous_owner = owner; m_used_up_counter = -1; if (owner) - setDeactivatedTicks(stk_config->time2Ticks(1.5f)); + setDeactivatedTicks(STKConfig::get()->time2Ticks(1.5f)); else setDeactivatedTicks(0); } // ItemState(ItemType) @@ -90,7 +90,7 @@ void ItemState::setDisappearCounter() switch (m_type) { case ITEM_BUBBLEGUM: - m_used_up_counter = stk_config->m_bubblegum_counter; break; + m_used_up_counter = STKConfig::get()->m_bubblegum_counter; break; case ITEM_EASTER_EGG: m_used_up_counter = -1; break; default: @@ -135,6 +135,7 @@ void ItemState::update(int ticks) */ void ItemState::collected(const AbstractKart *kart) { + auto& stk_config = STKConfig::get(); if (m_type == ITEM_EASTER_EGG) { // They will disappear 'forever' @@ -447,6 +448,8 @@ void Item::updateGraphics(float dt) m_graphical_type = getGrahpicalType(); } + auto& stk_config = STKConfig::get(); + float time_till_return = stk_config->ticks2Time(getTicksTillReturn()); bool is_visible = isAvailable() || time_till_return <= 1.0f || (getType() == ITEM_BUBBLEGUM && diff --git a/src/items/item_manager.cpp b/src/items/item_manager.cpp index f192e33cec0..e2e28cf8e38 100644 --- a/src/items/item_manager.cpp +++ b/src/items/item_manager.cpp @@ -179,7 +179,7 @@ ItemManager::ItemManager() m_switch_to.reserve(ItemState::ITEM_COUNT); for(unsigned int i=ItemState::ITEM_FIRST; im_switch_items); + setSwitchItems(STKConfig::get()->m_switch_items); if(Graph::get()) { @@ -586,7 +586,7 @@ void ItemManager::switchItemsInternal(std::vector &all_items) // if the items are already switched (m_switch_ticks >=0) // then switch back, and set m_switch_ticks to -1 to indicate // that the items are now back to normal. - m_switch_ticks = m_switch_ticks < 0 ? stk_config->m_item_switch_ticks : -1; + m_switch_ticks = m_switch_ticks < 0 ? STKConfig::get()->m_item_switch_ticks : -1; } // switchItems diff --git a/src/items/plunger.cpp b/src/items/plunger.cpp index 6ea2ec91180..0be206f73e4 100644 --- a/src/items/plunger.cpp +++ b/src/items/plunger.cpp @@ -218,7 +218,7 @@ bool Plunger::hit(AbstractKart *kart, PhysicalObject *obj) } else { - m_keep_alive = (int16_t)stk_config->time2Ticks(m_owner->getKartProperties() + m_keep_alive = (int16_t)STKConfig::get()->time2Ticks(m_owner->getKartProperties() ->getPlungerBandDuration()); if(kart) { diff --git a/src/items/powerup.cpp b/src/items/powerup.cpp index 822f40abbe9..fce24691769 100644 --- a/src/items/powerup.cpp +++ b/src/items/powerup.cpp @@ -282,6 +282,8 @@ void Powerup::use() m_sound_use = SFXManager::get()->createSoundSource("shoot"); } + auto& stk_config = STKConfig::get(); + m_number--; World *world = World::getWorld(); ItemManager* im = Track::getCurrentTrack()->getItemManager(); @@ -583,6 +585,8 @@ void Powerup::hitBonusBox(const ItemState &item_state) new_powerup = powerup_manager->getRandomPowerup(position, &n, random_number); + auto& stk_config = STKConfig::get(); + // Always add a new powerup in ITEM_MODE_NEW (or if the kart // doesn't have a powerup atm). if(m_type == PowerupManager::POWERUP_NOTHING || diff --git a/src/items/powerup_manager.cpp b/src/items/powerup_manager.cpp index 497df341b2b..2bbba7c2474 100644 --- a/src/items/powerup_manager.cpp +++ b/src/items/powerup_manager.cpp @@ -612,6 +612,8 @@ PowerupManager::PowerupType PowerupManager::getRandomPowerup(unsigned int pos, else *n=1; + auto& stk_config = STKConfig::get(); + // Prevents early explosive items if (World::getWorld() && stk_config->ticks2Time(World::getWorld()->getTicksSinceStart()) < diff --git a/src/items/rubber_ball.cpp b/src/items/rubber_ball.cpp index 1dc41243738..fef1cfe9572 100644 --- a/src/items/rubber_ball.cpp +++ b/src/items/rubber_ball.cpp @@ -100,7 +100,7 @@ void RubberBall::onFireFlyable() // Do not adjust the up velocity setAdjustUpVelocity(false); - m_max_lifespan = stk_config->time2Ticks(9999); + m_max_lifespan = STKConfig::get()->time2Ticks(9999); m_target = NULL; m_aiming_at_target = false; m_fast_ping = false; @@ -291,6 +291,8 @@ void RubberBall::getNextControlPoint() */ void RubberBall::init(const XMLNode &node, scene::IMesh *rubberball) { + auto& stk_config = STKConfig::get(); + m_st_interval = 1.0f; m_st_squash_duration = 3.0f; m_st_squash_slowdown = 0.5f; @@ -445,7 +447,7 @@ bool RubberBall::updateAndDelete(int ticks) // Flyable::update for basket balls. TerrainInfo::update(next_xyz + getNormal()*vertical_offset, -getNormal()); - m_height_timer += stk_config->ticks2Time(ticks); + m_height_timer += STKConfig::get()->ticks2Time(ticks); float height = updateHeight()+m_extend.getY()*0.5f; if(UserConfigParams::logFlyable()) @@ -522,7 +524,7 @@ void RubberBall::moveTowardsTarget(Vec3 *next_xyz, int ticks) *next_xyz = getXYZ() - getNormal()*m_previous_height; else { - float dt = stk_config->ticks2Time(ticks); + float dt = STKConfig::get()->ticks2Time(ticks); *next_xyz = getXYZ() - getNormal()*m_previous_height + (dt*m_speed / diff.length())*diff; } @@ -560,7 +562,7 @@ void RubberBall::updateWeightedSpeed(int ticks) // Get the speed depending on difficulty but not on kart type/handicap float targeted_speed = kp->getEngineGenericMaxSpeed(); - float dt = stk_config->ticks2Time(ticks); + float dt = STKConfig::get()->ticks2Time(ticks); //Calculate the targeted weighted speed if (m_distance_to_target <= m_st_min_offset_distance) @@ -610,7 +612,7 @@ void RubberBall::interpolate(Vec3 *next_xyz, int ticks) { // If we have reached or overshot the next control point, move to the // the next section of the spline - float dt = stk_config->ticks2Time(ticks); + float dt = STKConfig::get()->ticks2Time(ticks); m_t += m_t_increase * dt; if(m_t > 1.0f) { diff --git a/src/items/rubber_band.cpp b/src/items/rubber_band.cpp index 3e137c7361f..27d74d497ed 100644 --- a/src/items/rubber_band.cpp +++ b/src/items/rubber_band.cpp @@ -299,8 +299,8 @@ void RubberBand::update(int ticks) m_owner->increaseMaxSpeed(MaxSpeed::MS_INCREASE_RUBBER, kp->getPlungerBandSpeedIncrease(), /*engine_force*/ 0.0f, - /*duration*/stk_config->time2Ticks(0.1f), - stk_config->time2Ticks(kp->getPlungerBandFadeOutTime())); + /*duration*/STKConfig::get()->time2Ticks(0.1f), + STKConfig::get()->time2Ticks(kp->getPlungerBandFadeOutTime())); if(m_attached_state==RB_TO_KART) m_hit_kart->getBody()->applyCentralForce(diff*(-force)); } diff --git a/src/items/swatter.cpp b/src/items/swatter.cpp index ac03f8815b4..c3c1df4c5bc 100644 --- a/src/items/swatter.cpp +++ b/src/items/swatter.cpp @@ -73,6 +73,9 @@ Swatter::Swatter(AbstractKart *kart, int16_t bomb_ticks, int ticks, m_bomb_remaining = bomb_ticks; m_scene_node = NULL; m_bomb_scene_node = NULL; + + auto& stk_config = STKConfig::get(); + m_swatter_duration = stk_config->time2Ticks( kart->getKartProperties()->getSwatterDuration()); if (m_bomb_remaining != -1) @@ -109,6 +112,7 @@ Swatter::~Swatter() // ---------------------------------------------------------------------------- void Swatter::updateGraphics(float dt) { + auto& stk_config = STKConfig::get(); #ifndef SERVER_ONLY if (m_bomb_remaining != -1) { @@ -244,6 +248,8 @@ bool Swatter::updateAndTestFinished() if (m_bomb_remaining != -1) return false; + auto& stk_config = STKConfig::get(); + if (!m_discard_now) { switch (m_animation_phase) diff --git a/src/karts/abstract_kart_animation.cpp b/src/karts/abstract_kart_animation.cpp index 9eef2b58e7e..f6fadc9536a 100644 --- a/src/karts/abstract_kart_animation.cpp +++ b/src/karts/abstract_kart_animation.cpp @@ -151,7 +151,7 @@ float AbstractKartAnimation::getAnimationTimer() const World* w = World::getWorld(); if (!w) return 0.0f; - return stk_config->ticks2Time(m_end_ticks - w->getTicksSinceStart()); + return STKConfig::get()->ticks2Time(m_end_ticks - w->getTicksSinceStart()); } // getAnimationTimer // ---------------------------------------------------------------------------- diff --git a/src/karts/cannon_animation.cpp b/src/karts/cannon_animation.cpp index 24403745902..2e56e7355cb 100644 --- a/src/karts/cannon_animation.cpp +++ b/src/karts/cannon_animation.cpp @@ -118,7 +118,7 @@ void CannonAnimation::init(Ipo *ipo, const Vec3 &start_left, m_current_rotation = MiniGLM::compressQuaternion(m_created_transform.getRotation()); m_curve = new AnimationBase(ipo); - m_end_ticks = m_created_ticks + stk_config->time2Ticks(ipo->getEndTime()); + m_end_ticks = m_created_ticks + STKConfig::get()->time2Ticks(ipo->getEndTime()); // First make sure that left and right points are indeed correct // ------------------------------------------------------------- @@ -324,7 +324,7 @@ void CannonAnimation::update(int ticks) // Adjust the horizontal location based on steering // Use values from getControls directly because in networking steering // can be smoothed for remote karts - float dt = stk_config->ticks2Time(ticks); + float dt = STKConfig::get()->ticks2Time(ticks); m_fraction_of_line += m_kart->getControls().getSteer() * dt * 2.0f; btClamp(m_fraction_of_line, -1.0f, 1.0f); } // if m_kart diff --git a/src/karts/controller/ai_base_controller.cpp b/src/karts/controller/ai_base_controller.cpp index 32c3fb59d25..39960283bf2 100644 --- a/src/karts/controller/ai_base_controller.cpp +++ b/src/karts/controller/ai_base_controller.cpp @@ -234,6 +234,8 @@ bool AIBaseController::disableSlipstreamBonus() const */ void AIBaseController::crashed(const Material *m) { + auto& stk_config = STKConfig::get(); + // Defines how many collision in what time will trigger a rescue. // Note that typically it takes ~0.5 seconds for the AI to hit // the track again if it is stuck (i.e. time for the push back plus diff --git a/src/karts/controller/arena_ai.cpp b/src/karts/controller/arena_ai.cpp index b99c54514d3..7b85ca3ea8b 100644 --- a/src/karts/controller/arena_ai.cpp +++ b/src/karts/controller/arena_ai.cpp @@ -107,6 +107,8 @@ void ArenaAI::update(int ticks) m_ticks_since_off_road = 0; } + auto& stk_config = STKConfig::get(); + // If the kart needs to be rescued, do it now (and nothing else) if (m_ticks_since_off_road > stk_config->time2Ticks(5.0f) && m_kart->isOnGround() ) @@ -357,7 +359,7 @@ void ArenaAI::configSpeed() else { // Otherwise accelerate - m_controls->setAccel(stk_config->m_ai_acceleration * handicap); + m_controls->setAccel(STKConfig::get()->m_ai_acceleration * handicap); } } // configSpeed @@ -395,6 +397,8 @@ bool ArenaAI::gettingUnstuck(int ticks) if (!m_is_stuck || m_is_uturn) return false; resetAfterStop(); + + auto& stk_config = STKConfig::get(); float dt = stk_config->ticks2Time(ticks); setSteering(0.0f, dt); m_controls->setBrake(true); diff --git a/src/karts/controller/end_controller.cpp b/src/karts/controller/end_controller.cpp index b5691d2ead9..241b82f7bbe 100644 --- a/src/karts/controller/end_controller.cpp +++ b/src/karts/controller/end_controller.cpp @@ -202,7 +202,7 @@ void EndController::update(int ticks) calcSteps(); /*Response handling functions*/ - float dt = stk_config->ticks2Time(ticks); + float dt = STKConfig::get()->ticks2Time(ticks); handleSteering(dt); handleRescue(dt); } // update diff --git a/src/karts/controller/local_player_controller.cpp b/src/karts/controller/local_player_controller.cpp index cc0bda814c3..ba9d1c3336a 100644 --- a/src/karts/controller/local_player_controller.cpp +++ b/src/karts/controller/local_player_controller.cpp @@ -480,7 +480,7 @@ void LocalPlayerController::doCrashHaptics() { int now = World::getWorld()->getTicksSinceStart(); int lastCrash = m_last_crash; m_last_crash = now; - if ((now - lastCrash) < stk_config->time2Ticks(0.2f)) + if ((now - lastCrash) < STKConfig::get()->time2Ticks(0.2f)) return; float strength = diff --git a/src/karts/controller/network_player_controller.hpp b/src/karts/controller/network_player_controller.hpp index 74d2ea9542a..51d3cb26a78 100644 --- a/src/karts/controller/network_player_controller.hpp +++ b/src/karts/controller/network_player_controller.hpp @@ -57,7 +57,7 @@ class NetworkPlayerController : public PlayerController if (NetworkConfig::get()->isClient()) { m_controls->setSteer( m_controls->getSteer() - * stk_config->m_network_steering_reduction); + * STKConfig::get()->m_network_steering_reduction); } } // update diff --git a/src/karts/controller/player_controller.cpp b/src/karts/controller/player_controller.cpp index 7117d7ec121..7e8731912b9 100644 --- a/src/karts/controller/player_controller.cpp +++ b/src/karts/controller/player_controller.cpp @@ -270,9 +270,9 @@ void PlayerController::steer(int ticks, int steer_val) // Get the old value, compute the new steering value, // and set it at the end of this function float steer = m_controls->getSteer(); - if(stk_config->m_disable_steer_while_unskid && - m_controls->getSkidControl()==KartControl::SC_NONE && - m_kart->getSkidding()->getVisualSkidRotation()!=0) + if (STKConfig::get()->m_disable_steer_while_unskid && + m_controls->getSkidControl() == KartControl::SC_NONE && + m_kart->getSkidding()->getVisualSkidRotation() != 0) { steer = 0; } @@ -280,7 +280,7 @@ void PlayerController::steer(int ticks, int steer_val) // Amount the steering is changed for digital devices. // If the steering is 'back to straight', a different steering // change speed is used. - float dt = stk_config->ticks2Time(ticks); + float dt = STKConfig::get()->ticks2Time(ticks); const float STEER_CHANGE = ( (steer_val<=0 && steer<0) || (steer_val>=0 && steer>0) ) ? dt/m_kart->getKartProperties()->getTurnTimeResetSteer() @@ -420,5 +420,5 @@ core::stringw PlayerController::getName(bool include_handicap_string) const // ---------------------------------------------------------------------------- void PlayerController::displayPenaltyWarning() { - m_penalty_ticks = stk_config->m_penalty_ticks; + m_penalty_ticks = STKConfig::get()->m_penalty_ticks; } // displayPenaltyWarning diff --git a/src/karts/controller/skidding_ai.cpp b/src/karts/controller/skidding_ai.cpp index 53b2d664e1d..8e6ba51246a 100644 --- a/src/karts/controller/skidding_ai.cpp +++ b/src/karts/controller/skidding_ai.cpp @@ -224,7 +224,7 @@ unsigned int SkiddingAI::getNextSector(unsigned int index) */ void SkiddingAI::update(int ticks) { - float dt = stk_config->ticks2Time(ticks); + float dt = STKConfig::get()->ticks2Time(ticks); // Clear stored items if they were deleted (for example a switched nitro) if (m_item_to_collect && @@ -1182,6 +1182,8 @@ void SkiddingAI::handleItems(const float dt, const Vec3 *aim_point, int last_nod //items_to_avoid and items_to_collect now contain the closest item information needed after //What matters is (a) if the lists are void ; (b) if they are not, what kind of item it is + auto& stk_config = STKConfig::get(); + switch( m_kart->getPowerup()->getType() ) { case PowerupManager::POWERUP_BUBBLEGUM: @@ -1373,6 +1375,9 @@ void SkiddingAI::handleBubblegum(int item_skill, m_controls->setLookBack(false); return; } + + auto& stk_config = STKConfig::get(); + //if it is a bomb, wait : we may pass it to another kart before the timer runs out if (item_skill == 5 && type == Attachment::ATTACH_BOMB) { @@ -1687,6 +1692,8 @@ void SkiddingAI::handleSwatter(int item_skill) m_controls->setFire(true); return; } + + auto& stk_config = STKConfig::get(); // Use swatter to remove bad attachments if((item_skill == 4) || (item_skill == 5)) @@ -2053,7 +2060,7 @@ void SkiddingAI::handleAccelerationAndBraking(int ticks) return; } - m_controls->setAccel(stk_config->m_ai_acceleration); + m_controls->setAccel(STKConfig::get()->m_ai_acceleration); } // handleAccelerationAndBraking @@ -2129,35 +2136,37 @@ void SkiddingAI::handleBraking(float max_turn_speed, float min_speed) //----------------------------------------------------------------------------- void SkiddingAI::handleRaceStart() { - if( m_start_delay < 0 ) + if (m_start_delay >= 0) + return; + + auto& stk_config = STKConfig::get(); + + if (m_enabled_network_ai) { - if (m_enabled_network_ai) - { - m_start_delay = 0; - return; - } - // Each kart starts at a different, random time, and the time is - // smaller depending on the difficulty. - m_start_delay = stk_config->time2Ticks( - m_ai_properties->m_min_start_delay - + (float) rand() / (float) RAND_MAX - * (m_ai_properties->m_max_start_delay - - m_ai_properties->m_min_start_delay) ); - - float false_start_probability = - m_superpower == RaceManager::SUPERPOWER_NOLOK_BOSS - ? 0.0f : m_ai_properties->m_false_start_probability; - - // Now check for a false start. If so, add 1 second penalty time. - if (rand() < (float) RAND_MAX * false_start_probability) - { - m_start_delay+=stk_config->m_penalty_ticks; - return; - } - m_kart->setStartupBoost(m_kart->getStartupBoostFromStartTicks( - m_start_delay + stk_config->time2Ticks(1.0f))); m_start_delay = 0; + return; + } + // Each kart starts at a different, random time, and the time is + // smaller depending on the difficulty. + m_start_delay = stk_config->time2Ticks( + m_ai_properties->m_min_start_delay + + (float) rand() / (float) RAND_MAX + * (m_ai_properties->m_max_start_delay - + m_ai_properties->m_min_start_delay) ); + + float false_start_probability = + m_superpower == RaceManager::SUPERPOWER_NOLOK_BOSS + ? 0.0f : m_ai_properties->m_false_start_probability; + + // Now check for a false start. If so, add 1 second penalty time. + if (rand() < (float) RAND_MAX * false_start_probability) + { + m_start_delay += stk_config->m_penalty_ticks; + return; } + m_kart->setStartupBoost(m_kart->getStartupBoostFromStartTicks( + m_start_delay + stk_config->time2Ticks(1.0f))); + m_start_delay = 0; } // handleRaceStart //----------------------------------------------------------------------------- @@ -2197,7 +2206,7 @@ void SkiddingAI::handleNitroAndZipper(float max_safe_speed) //Nitro continue to be advantageous during the fadeout (nitro ticks continue to tick in the negatives) int nitro_ticks = m_kart->getSpeedIncreaseTicksLeft(MaxSpeed::MS_INCREASE_NITRO); - float time_until_fadeout = ( stk_config->ticks2Time(nitro_ticks) + float time_until_fadeout = ( STKConfig::get()->ticks2Time(nitro_ticks) + m_kart->getKartProperties()->getNitroFadeOutTime() ); // Because it takes some time after nitro activation to accelerate to the increased max speed, diff --git a/src/karts/controller/test_ai.cpp b/src/karts/controller/test_ai.cpp index be53f0e6e85..bf8f99b49e6 100644 --- a/src/karts/controller/test_ai.cpp +++ b/src/karts/controller/test_ai.cpp @@ -228,7 +228,7 @@ unsigned int SkiddingAI::getNextSector(unsigned int index) */ void SkiddingAI::update(int ticks) { - float dt = stk_config->ticks2Time(ticks); + float dt = STKConfig::get()->ticks2Time(ticks); // This is used to enable firing an item backwards. m_controls->setLookBack(false); m_controls->setNitro(false); @@ -1194,6 +1194,8 @@ void SkiddingAI::handleItems(const float dt) // ------------------- float min_bubble_time = 2.0f; + auto& stk_config = STKConfig::get(); + switch( m_kart->getPowerup()->getType() ) { case PowerupManager::POWERUP_BUBBLEGUM: @@ -1539,37 +1541,38 @@ void SkiddingAI::handleAcceleration(int ticks) return; } - m_controls->setAccel(stk_config->m_ai_acceleration); + m_controls->setAccel(STKConfig::get()->m_ai_acceleration); } // handleAcceleration //----------------------------------------------------------------------------- void SkiddingAI::handleRaceStart() { - if( m_start_delay < 0 ) - { - // Each kart starts at a different, random time, and the time is - // smaller depending on the difficulty. - m_start_delay = stk_config->time2Ticks( - m_ai_properties->m_min_start_delay - + (float) rand() / RAND_MAX - * (m_ai_properties->m_max_start_delay - - m_ai_properties->m_min_start_delay) ); - - float false_start_probability = - m_superpower == RaceManager::SUPERPOWER_NOLOK_BOSS - ? 0.0f : m_ai_properties->m_false_start_probability; - - // Now check for a false start. If so, add 1 second penalty time. - if (rand() < RAND_MAX * false_start_probability) - { - m_start_delay+=stk_config->m_penalty_ticks; - return; - } - m_kart->setStartupBoost(m_kart->getStartupBoostFromStartTicks( - m_start_delay + stk_config->time2Ticks(1.0f))); - m_start_delay = 0; + if (m_start_delay >= 0) + return; + + auto& stk_config = STKConfig::get(); + // Each kart starts at a different, random time, and the time is + // smaller depending on the difficulty. + m_start_delay = stk_config->time2Ticks( + m_ai_properties->m_min_start_delay + + (float) rand() / RAND_MAX + * (m_ai_properties->m_max_start_delay - + m_ai_properties->m_min_start_delay) ); + + float false_start_probability = + m_superpower == RaceManager::SUPERPOWER_NOLOK_BOSS + ? 0.0f : m_ai_properties->m_false_start_probability; + + // Now check for a false start. If so, add 1 second penalty time. + if (rand() < RAND_MAX * false_start_probability) + { + m_start_delay += stk_config->m_penalty_ticks; + return; } + m_kart->setStartupBoost(m_kart->getStartupBoostFromStartTicks( + m_start_delay + stk_config->time2Ticks(1.0f))); + m_start_delay = 0; } // handleRaceStart //----------------------------------------------------------------------------- diff --git a/src/karts/explosion_animation.cpp b/src/karts/explosion_animation.cpp index 79326e11454..28744445499 100644 --- a/src/karts/explosion_animation.cpp +++ b/src/karts/explosion_animation.cpp @@ -122,7 +122,7 @@ ExplosionAnimation::ExplosionAnimation(AbstractKart* kart, bool direct_hit) } float t = m_kart->getKartProperties()->getExplosionInvulnerabilityTime(); - m_kart->setInvulnerableTicks(stk_config->time2Ticks(t)); + m_kart->setInvulnerableTicks(STKConfig::get()->time2Ticks(t)); m_kart->playCustomSFX(SFXManager::CUSTOM_EXPLODE); m_kart->getAttachment()->clear(); // Clear powerups when direct hit in CTF @@ -204,9 +204,9 @@ void ExplosionAnimation::init(bool direct_hit, const Vec3& normal, RaceManager::MINOR_MODE_CAPTURE_THE_FLAG && direct_hit) { m_reset_ticks = m_created_ticks + - stk_config->time2Ticks(timer * 0.8f); + STKConfig::get()->time2Ticks(timer * 0.8f); } - m_end_ticks = m_created_ticks + stk_config->time2Ticks(timer); + m_end_ticks = m_created_ticks + STKConfig::get()->time2Ticks(timer); if (m_reset_ticks != -1) m_reset_trans = reset_trans; @@ -252,7 +252,7 @@ void ExplosionAnimation::init(bool direct_hit, const Vec3& normal, */ void ExplosionAnimation::update(int ticks) { - float dur = stk_config->ticks2Time( + float dur = STKConfig::get()->ticks2Time( World::getWorld()->getTicksSinceStart() - m_created_ticks); float velocity = m_velocity - diff --git a/src/karts/ghost_kart.cpp b/src/karts/ghost_kart.cpp index e58225c62ff..a6f0f580a49 100644 --- a/src/karts/ghost_kart.cpp +++ b/src/karts/ghost_kart.cpp @@ -150,6 +150,9 @@ void GhostKart::update(int ticks) } Moveable::updatePosition(); + + auto& stk_config = STKConfig::get(); + float dt = stk_config->ticks2Time(ticks); getKartModel()->update(dt, dt*(m_all_physic_info[idx].m_speed), m_all_physic_info[idx].m_steer, m_all_physic_info[idx].m_speed, diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index aab994acd9e..865ea9c6f81 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -121,6 +121,8 @@ Kart::Kart (const std::string& ident, unsigned int world_kart_id, # pragma warning(1:4355) #endif { + auto& stk_config = STKConfig::get(); + m_max_speed = new MaxSpeed(this); m_terrain_info = new TerrainInfo(); m_powerup = new Powerup(this); @@ -332,7 +334,7 @@ void Kart::reset() m_min_nitro_ticks = 0; m_energy_to_min_ratio = 0; - m_consumption_per_tick = stk_config->ticks2Time(1) * + m_consumption_per_tick = STKConfig::get()->ticks2Time(1) * m_kart_properties->getNitroConsumption(); // Reset star effect in case that it is currently being shown. @@ -609,7 +611,7 @@ void Kart::blockViewWithPlunger() if(m_view_blocked_by_plunger<=0 && !isShielded()) { m_view_blocked_by_plunger = (int16_t) - stk_config->time2Ticks(m_kart_properties->getPlungerInFaceTime()); + STKConfig::get()->time2Ticks(m_kart_properties->getPlungerInFaceTime()); } if(isShielded()) { @@ -758,7 +760,7 @@ void Kart::createPhysics() // ------------------------- m_vehicle_raycaster.reset( new btKartRaycaster(Physics::get()->getPhysicsWorld(), - stk_config->m_smooth_normals && + STKConfig::get()->m_smooth_normals && Track::getCurrentTrack()->smoothNormals())); m_vehicle.reset(new btKart(m_body.get(), m_vehicle_raycaster.get(), this)); @@ -945,6 +947,9 @@ void Kart::finishedRace(float time, bool from_server) RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE || RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL || RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER; + + auto& stk_config = STKConfig::get(); + if (NetworkConfig::get()->isNetworking() && !from_server) { if (NetworkConfig::get()->isServer()) @@ -1138,6 +1143,8 @@ void Kart::collectedItem(ItemState *item_state) float old_energy = m_collected_energy; const Item::ItemType type = item_state->getType(); + auto& stk_config = STKConfig::get(); + switch (type) { case Item::ITEM_BANANA: @@ -1193,10 +1200,10 @@ void Kart::collectedItem(ItemState *item_state) */ float Kart::getStartupBoostFromStartTicks(int ticks) const { - int ticks_since_ready = ticks - stk_config->time2Ticks(1.0f); + int ticks_since_ready = ticks - STKConfig::get()->time2Ticks(1.0f); if (ticks_since_ready < 0) return 0.0f; - float t = stk_config->ticks2Time(ticks_since_ready); + float t = STKConfig::get()->ticks2Time(ticks_since_ready); std::vector startup_times = m_kart_properties->getStartupTime(); for (unsigned int i = 0; i < startup_times.size(); i++) { @@ -1251,7 +1258,7 @@ bool Kart::isNearGround() const return false; else return ((getXYZ().getY() - m_terrain_info->getHoT()) - < stk_config->m_near_ground); + < STKConfig::get()->m_near_ground); } // isNearGround // ------------------------------------------------------------------------ @@ -1261,7 +1268,7 @@ void Kart::setShieldTime(float t) { if(isShielded()) { - getAttachment()->setTicksLeft(stk_config->time2Ticks(t)); + getAttachment()->setTicksLeft(STKConfig::get()->time2Ticks(t)); } } // setShieldTime @@ -1290,7 +1297,7 @@ bool Kart::isShielded() const float Kart::getShieldTime() const { if (isShielded()) - return stk_config->ticks2Time(getAttachment()->getTicksLeft()); + return STKConfig::get()->ticks2Time(getAttachment()->getTicksLeft()); else return 0.0f; } // getShieldTime @@ -1394,6 +1401,8 @@ void Kart::update(int ticks) else if (NetworkConfig::get()->roundValuesNow()) CompressNetworkBody::compress(m_body.get(), m_motion_state.get()); + auto& stk_config = STKConfig::get(); + float dt = stk_config->ticks2Time(ticks); if (!RewindManager::get()->isRewinding()) { @@ -1871,6 +1880,8 @@ bool Kart::setSquash(float time, float slowdown) return true; } + auto& stk_config = STKConfig::get(); + m_max_speed->setSlowdown(MaxSpeed::MS_DECREASE_SQUASH, slowdown, stk_config->time2Ticks(0.1f), stk_config->time2Ticks(time)); @@ -2217,6 +2228,8 @@ void Kart::handleZipper(const Material *material, bool play_sound) // Ignore a zipper that's activated while braking if(m_controls.getBrake() || m_speed<0) return; + auto& stk_config = STKConfig::get(); + m_max_speed->instantSpeedIncrease(MaxSpeed::MS_INCREASE_ZIPPER, max_speed_increase, speed_gain, engine_force, @@ -2284,6 +2297,8 @@ void Kart::updateNitro(int ticks) if(m_nitro_sound->getStatus() != SFXBase::SFX_PLAYING && !rewinding) m_nitro_sound->play(); + auto& stk_config = STKConfig::get(); + m_max_speed->increaseMaxSpeed(MaxSpeed::MS_INCREASE_NITRO, m_kart_properties->getNitroMaxSpeedIncrease(), m_kart_properties->getNitroEngineForce(), @@ -2347,6 +2362,7 @@ void Kart::crashed(const Material *m, const Vec3 &normal) } #endif + auto& stk_config = STKConfig::get(); const LinearWorld *lw = dynamic_cast(World::getWorld()); if(m_kart_properties->getTerrainImpulseType() ==KartProperties::IMPULSE_NORMAL && @@ -2610,6 +2626,8 @@ void Kart::updatePhysics(int ticks) { if (m_startup_boost > 0.0f) { + auto& stk_config = STKConfig::get(); + m_kart_gfx->setCreationRateAbsolute(KartGFX::KGFX_ZIPPER, 100.0f * m_startup_boost); m_max_speed->instantSpeedIncrease(MaxSpeed::MS_INCREASE_ZIPPER, @@ -2830,7 +2848,7 @@ void Kart::updateEnginePowerAndBrakes(int ticks) applyEngineForce(engine_power-braking_power*3); m_brake_ticks += ticks; // Apply the brakes - include the time dependent brake increase - float f = 1.0f + stk_config->ticks2Time(m_brake_ticks) + float f = 1.0f + STKConfig::get()->ticks2Time(m_brake_ticks) * m_kart_properties->getEngineBrakeTimeIncrease(); m_vehicle->setAllBrakes(m_kart_properties->getEngineBrakeFactor() * f); } diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index 15eda0c2926..0b32eeefcaf 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -228,20 +228,22 @@ void KartProperties::load(const std::string &filename, const std::string &node) const XMLNode* root = new XMLNode(filename); std::string kart_type; + auto& stk_config = STKConfig::get(); + if (root->get("type", &kart_type)) { // Handle the case that kart_type might be incorrect try { - copyFrom(&stk_config->getKartProperties(kart_type)); + copyFrom(&(stk_config->getKartProperties(kart_type))); } catch (std::out_of_range &) { - copyFrom(&stk_config->getDefaultKartProperties()); + copyFrom(&(stk_config->getDefaultKartProperties())); } // try .. catch } else - copyFrom(&stk_config->getDefaultKartProperties()); + copyFrom(&(stk_config->getDefaultKartProperties())); // m_kart_model must be initialised after assigning the default // values from stk_config (otherwise all kart_properties will diff --git a/src/karts/kart_properties_manager.cpp b/src/karts/kart_properties_manager.cpp index 833542f8e02..a812181e2f8 100644 --- a/src/karts/kart_properties_manager.cpp +++ b/src/karts/kart_properties_manager.cpp @@ -302,6 +302,8 @@ bool KartPropertiesManager::loadKart(const std::string &dir) return false; } + auto& stk_config = STKConfig::get(); + // If the version of the kart file is not supported, // ignore this .kart file if (kart_properties->getVersion() < stk_config->m_min_kart_version || diff --git a/src/karts/kart_rewinder.cpp b/src/karts/kart_rewinder.cpp index ddde87d6b13..0cb9af76e30 100644 --- a/src/karts/kart_rewinder.cpp +++ b/src/karts/kart_rewinder.cpp @@ -388,7 +388,7 @@ void KartRewinder::restoreState(BareNetworkString *buffer, int count) float timed_rotation_y = buffer->getFloat(); // Set timed rotation divides by time_rot m_vehicle->setTimedRotation(time_rot, - stk_config->ticks2Time(time_rot) * timed_rotation_y); + STKConfig::get()->ticks2Time(time_rot) * timed_rotation_y); } else m_vehicle->setTimedRotation(0, 0.0f); diff --git a/src/karts/kart_with_stats.cpp b/src/karts/kart_with_stats.cpp index 14aafb0609e..d3508539867 100644 --- a/src/karts/kart_with_stats.cpp +++ b/src/karts/kart_with_stats.cpp @@ -62,7 +62,7 @@ void KartWithStats::update(int ticks) { Kart::update(ticks); if(getSpeed()>m_top_speed ) m_top_speed = getSpeed(); - float dt = stk_config->ticks2Time(ticks); + float dt = STKConfig::get()->ticks2Time(ticks); if(getControls().getSkidControl()) m_skidding_time += dt; if(getControls().getBrake() ) m_brake_count ++; LinearWorld *world = dynamic_cast(World::getWorld()); diff --git a/src/karts/moveable.cpp b/src/karts/moveable.cpp index 8054eff8485..960aedefa7d 100644 --- a/src/karts/moveable.cpp +++ b/src/karts/moveable.cpp @@ -193,7 +193,7 @@ void Moveable::createBody(float mass, btTransform& trans, btRigidBody::btRigidBodyConstructionInfo info(mass, m_motion_state.get(), shape, inertia); info.m_restitution = restitution; - info.m_friction = stk_config->m_default_moveable_friction; + info.m_friction = STKConfig::get()->m_default_moveable_friction; // Then create a rigid body // ------------------------ diff --git a/src/karts/rescue_animation.cpp b/src/karts/rescue_animation.cpp index 7cad01fa955..0bd22117acc 100644 --- a/src/karts/rescue_animation.cpp +++ b/src/karts/rescue_animation.cpp @@ -136,6 +136,9 @@ void RescueAnimation::init(const btTransform& rescue_transform, { m_rescue_transform = rescue_transform; float timer = m_kart->getKartProperties()->getRescueDuration(); + + auto& stk_config = STKConfig::get(); + m_end_ticks = m_created_ticks + stk_config->time2Ticks(timer); m_rescue_moment = m_created_ticks + stk_config->time2Ticks(timer * 0.4f); m_velocity = velocity; @@ -161,6 +164,8 @@ RescueAnimation::~RescueAnimation() */ void RescueAnimation::update(int ticks) { + auto& stk_config = STKConfig::get(); + if (World::getWorld()->getTicksSinceStart() > m_rescue_moment) { float dur = stk_config->ticks2Time(m_end_ticks - m_rescue_moment - diff --git a/src/karts/skidding.cpp b/src/karts/skidding.cpp index d022bf5e47f..1329e836068 100644 --- a/src/karts/skidding.cpp +++ b/src/karts/skidding.cpp @@ -147,6 +147,8 @@ void Skidding::checkSmoothing() */ float Skidding::updateSteering(float steer, int ticks) { + auto& stk_config = STKConfig::get(); + float dt = stk_config->ticks2Time(ticks); float skid_time_float = stk_config->ticks2Time(m_skid_time); float steer_result = 0.0f; @@ -353,6 +355,8 @@ float Skidding::updateGraphics(float dt) void Skidding::update(int ticks, bool is_on_ground, float steering, KartControl::SkidControl skidding) { + auto& stk_config = STKConfig::get(); + float dt = stk_config->ticks2Time(ticks); m_remaining_jump_time -= dt; @@ -613,7 +617,7 @@ unsigned int Skidding::getSkidBonus(float *bonus_time, *bonus_force = 0; for (unsigned int i = 0; i < kp->getSkidBonusSpeed().size(); i++) { - if (stk_config->ticks2Time(m_skid_time) <= + if (STKConfig::get()->ticks2Time(m_skid_time) <= kp->getSkidTimeTillBonus()[i]) return i; *bonus_speed = kp->getSkidBonusSpeed()[i]; diff --git a/src/main.cpp b/src/main.cpp index db1d31a03f9..22b6c9a2466 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -869,7 +869,7 @@ int handleCmdLinePreliminary() std::string s; if(CommandLine::has("--stk-config", &s)) { - stk_config->load(file_manager->getAsset(s)); + STKConfig::get()->load(file_manager->getAsset(s)); Log::info("main", "STK config will be read from %s.",s.c_str()); } if(CommandLine::has("--render-driver", &s)) @@ -1682,6 +1682,7 @@ int handleCmdLine(bool has_server_config, bool has_parent_process) if(CommandLine::has("--numkarts", &n) ||CommandLine::has("-k", &n)) { + auto& stk_config = STKConfig::get(); UserConfigParams::m_default_num_karts = n; if(UserConfigParams::m_default_num_karts > stk_config->m_max_karts) { @@ -1862,8 +1863,6 @@ void initUserConfig() } translations = new Translations(); // needs file_manager - stk_config = new STKConfig(); // in case of --stk-config - // command line parameters } // initUserConfig //============================================================================= @@ -1945,7 +1944,7 @@ void initRest() } #endif - stk_config->initMusicFiles(); + STKConfig::get()->initMusicFiles(); // This only initialises the non-network part of the add-ons manager. The // online section of the add-ons manager will be initialised from a // separate thread running in network HTTP. @@ -2247,7 +2246,7 @@ int main(int argc, char *argv[]) handleCmdLinePreliminary(); // ServerConfig will use stk_config for server version testing - stk_config->load(file_manager->getAsset("stk_config.xml")); + STKConfig::get()->load(file_manager->getAsset("stk_config.xml")); NetworkConfig::initSystemIP(); // Client port depends on user config file and stk_config NetworkConfig::get()->initClientPort(); @@ -2827,7 +2826,6 @@ static void cleanSuperTuxKart() */ static void cleanUserConfig() { - if(stk_config) delete stk_config; if(translations) delete translations; if (user_config) { diff --git a/src/main_loop.cpp b/src/main_loop.cpp index 2544f697eb7..5a364bbb300 100644 --- a/src/main_loop.cpp +++ b/src/main_loop.cpp @@ -457,6 +457,8 @@ void MainLoop::run() PROFILER_PUSH_CPU_MARKER("Main loop", 0xFF, 0x00, 0xF7); TimePoint frame_start = std::chrono::steady_clock::now(); + auto& stk_config = STKConfig::get(); + left_over_time += getLimitedDt(); int num_steps = stk_config->time2Ticks(left_over_time); float dt = stk_config->ticks2Time(1); diff --git a/src/modes/capture_the_flag.cpp b/src/modes/capture_the_flag.cpp index 5d879b9ca0e..ee05e48ce71 100644 --- a/src/modes/capture_the_flag.cpp +++ b/src/modes/capture_the_flag.cpp @@ -181,7 +181,7 @@ void CaptureTheFlag::updateGraphics(float dt) // a point has been scored recently const bool scored_recently = getTicksSinceStart() > m_last_captured_flag_ticks && - getTicksSinceStart() - m_last_captured_flag_ticks < stk_config->time2Ticks(2.0f); + getTicksSinceStart() - m_last_captured_flag_ticks < STKConfig::get()->time2Ticks(2.0f); if (m_red_flag_status != m_red_flag->getStatus()) { if (m_red_flag->getHolder() != -1) @@ -231,7 +231,7 @@ void CaptureTheFlag::update(int ticks) for (auto it = m_swatter_reset_kart_ticks.begin(); it != m_swatter_reset_kart_ticks.end();) { - if (it->second < getTicksSinceStart() - stk_config->time2Ticks(8.0f)) + if (it->second < getTicksSinceStart() - STKConfig::get()->time2Ticks(8.0f)) { it = m_swatter_reset_kart_ticks.erase(it); } @@ -417,7 +417,7 @@ void CaptureTheFlag::ctfScored(int kart_id, bool red_team_scored, if (game_info) { unsigned start_pos = getStartPosition(kart_id); - float time_since_start = stk_config->ticks2Time(getTicksSinceStart()); + float time_since_start = STKConfig::get()->ticks2Time(getTicksSinceStart()); game_info->onFlagCaptured(red_team_scored, name, kart_id, start_pos, time_since_start); } diff --git a/src/modes/cutscene_world.cpp b/src/modes/cutscene_world.cpp index d702df740f5..85b883d5cb8 100644 --- a/src/modes/cutscene_world.cpp +++ b/src/modes/cutscene_world.cpp @@ -89,7 +89,7 @@ void CutsceneWorld::init() Camera* stk_cam = Camera::createCamera(NULL, 0); m_camera = stk_cam->getCameraSceneNode(); - m_camera->setFOV(stk_config->m_cutscene_fov); + m_camera->setFOV(STKConfig::get()->m_cutscene_fov); m_camera->bindTargetAndRotation(true); // no "look-at" // --- Build list of sounds to play at certain frames diff --git a/src/modes/follow_the_leader.cpp b/src/modes/follow_the_leader.cpp index 0a69448c5c2..cffe3332698 100644 --- a/src/modes/follow_the_leader.cpp +++ b/src/modes/follow_the_leader.cpp @@ -40,6 +40,8 @@ FollowTheLeaderRace::FollowTheLeaderRace() : LinearWorld() // after crossing the start line RaceManager::get()->setNumLaps(99999); + auto& stk_config = STKConfig::get(); + m_leader_intervals = stk_config->m_leader_intervals; for(unsigned int i=0; igetAllScores(&m_score_for_position, getNumKarts() - 1); + STKConfig::get()->getAllScores(&m_score_for_position, getNumKarts() - 1); getKart(0)->setOnScreenText(_("Leader")); getKart(0)->setBoostAI(true); } // init @@ -80,6 +82,9 @@ FollowTheLeaderRace::~FollowTheLeaderRace() void FollowTheLeaderRace::reset(bool restart) { LinearWorld::reset(restart); + + auto& stk_config = STKConfig::get(); + m_last_eliminated_time = 0.0f; m_leader_intervals.clear(); m_leader_intervals = stk_config->m_leader_intervals; @@ -114,7 +119,7 @@ const btTransform &FollowTheLeaderRace::getStartTransform(int index) return Track::getCurrentTrack()->getStartTransform(index); // Otherwise the karts will start at the rear starting positions - int start_index = stk_config->m_max_karts + int start_index = STKConfig::get()->m_max_karts - RaceManager::get()->getNumberOfKarts() + index; return Track::getCurrentTrack()->getStartTransform(start_index); } // getStartTransform @@ -230,7 +235,7 @@ bool FollowTheLeaderRace::isRaceOver() void FollowTheLeaderRace::leaderHit() { int countdown = getTimeTicks(); - countdown += stk_config->time2Ticks(LEADER_HIT_TIME); + countdown += STKConfig::get()->time2Ticks(LEADER_HIT_TIME); setTicks(countdown); m_leader_hit_count++; } // leaderHit diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index d4de352c294..5aca21d7364 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -200,7 +200,7 @@ void LinearWorld::update(int ticks) if (getPhase() == RACE_PHASE && m_finish_timeout != std::numeric_limits::max()) { - m_finish_timeout -= stk_config->ticks2Time(ticks); + m_finish_timeout -= STKConfig::get()->ticks2Time(ticks); if (m_finish_timeout < 0.0f) { endRaceEarly(); @@ -532,7 +532,7 @@ void LinearWorld::newLap(unsigned int kart_index) { // To avoid negative times in countdown mode if (getClockMode() == CLOCK_COUNTDOWN) - ticks_per_lap = stk_config->time2Ticks(RaceManager::get()->getTimeTarget()) - getTimeTicks(); + ticks_per_lap = STKConfig::get()->time2Ticks(RaceManager::get()->getTimeTarget()) - getTimeTicks(); else ticks_per_lap = getTimeTicks(); } @@ -676,7 +676,7 @@ void LinearWorld::getKartsDisplayInfo( // Don't compare times when crossing the start line first if(laps_of_leader>0 && (getTimeTicks() - getTicksAtLapForKart(kart->getWorldKartId()) < - stk_config->time2Ticks(8) || + STKConfig::get()->time2Ticks(8) || rank_info.lap != laps_of_leader) && raceHasLaps()) { // Display for 5 seconds diff --git a/src/modes/linear_world.hpp b/src/modes/linear_world.hpp index 3b93bccc0af..76163de1333 100644 --- a/src/modes/linear_world.hpp +++ b/src/modes/linear_world.hpp @@ -214,7 +214,7 @@ class LinearWorld : public WorldWithRank { if (m_kart_info[kart_index].m_start_time == INT_MAX) return -1.0; - return stk_config->ticks2Time( + return STKConfig::get()->ticks2Time( m_kart_info[kart_index].m_start_time); } // getStartTimeForKart // ------------------------------------------------------------------------ @@ -222,7 +222,7 @@ class LinearWorld : public WorldWithRank { if (m_kart_info[kart_index].m_fastest_lap_ticks == INT_MAX) return -1.0; - return stk_config->ticks2Time( + return STKConfig::get()->ticks2Time( m_kart_info[kart_index].m_fastest_lap_ticks); } // getFastestLapForKart // ------------------------------------------------------------------------ @@ -246,7 +246,7 @@ class LinearWorld : public WorldWithRank /** Returns time for the fastest laps */ float getFastestLap() const { - return stk_config->ticks2Time(m_fastest_lap_ticks); + return STKConfig::get()->ticks2Time(m_fastest_lap_ticks); } // ------------------------------------------------------------------------ /** Returns the kart name that made the fastest lap time */ diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp index d7f757733b8..79937ee0022 100644 --- a/src/modes/soccer_world.cpp +++ b/src/modes/soccer_world.cpp @@ -521,6 +521,9 @@ void SoccerWorld::onCheckGoalTriggered(bool first_goal) if (getTicksSinceStart() < m_ticks_back_to_own_goal) return; + + auto& stk_config = STKConfig::get(); + m_ticks_back_to_own_goal = getTicksSinceStart() + stk_config->time2Ticks(3.0f); m_goal_sound->play(); @@ -753,7 +756,8 @@ void SoccerWorld::handlePlayerGoalFromServer(const NetworkString& ns) msg = _("%s scored a goal!", sd.m_player); else msg = _("Oops, %s made an own goal!", sd.m_player); - float time = stk_config->ticks2Time(ticks_back_to_own_goal - ticks_now); + + float time = STKConfig::get()->ticks2Time(ticks_back_to_own_goal - ticks_now); // May happen if this message is added when spectate started if (time > 3.0f) time = 3.0f; @@ -908,6 +912,8 @@ void SoccerWorld::updateBallPosition(int ticks) if (Track::getCurrentTrack()->hasNavMesh()) { + auto& stk_config = STKConfig::get(); + m_ball_track_sector ->update(getBallPosition(), true/*ignore_vertical*/); diff --git a/src/modes/soccer_world.hpp b/src/modes/soccer_world.hpp index 881e79eb753..e0de86fd9f3 100644 --- a/src/modes/soccer_world.hpp +++ b/src/modes/soccer_world.hpp @@ -271,7 +271,7 @@ class SoccerWorld : public WorldWithRank virtual bool isGoalPhase() const OVERRIDE { int diff = m_ticks_back_to_own_goal - getTicksSinceStart(); - return diff > 0 && diff < stk_config->time2Ticks(3.0f); + return diff > 0 && diff < STKConfig::get()->time2Ticks(3.0f); } // ------------------------------------------------------------------------ AbstractKart* getKartAtDrawingPosition(unsigned int p) const OVERRIDE diff --git a/src/modes/three_strikes_battle.cpp b/src/modes/three_strikes_battle.cpp index c4f4c7982f9..9449c827025 100644 --- a/src/modes/three_strikes_battle.cpp +++ b/src/modes/three_strikes_battle.cpp @@ -104,7 +104,7 @@ void ThreeStrikesBattle::reset(bool restart) RaceManager::get()->getDifficulty() == RaceManager::DIFFICULTY_HARD ? 30.0f : RaceManager::get()->getDifficulty() == RaceManager::DIFFICULTY_MEDIUM ? 25.0f : 20.0f; - m_next_sta_spawn_ticks = stk_config->time2Ticks(next_spawn_time); + m_next_sta_spawn_ticks = STKConfig::get()->time2Ticks(next_spawn_time); const unsigned int kart_amount = (unsigned int)m_karts.size(); for(unsigned int n=0; ntime2Ticks(lifespan); + int lifespan_ticks = STKConfig::get()->time2Ticks(lifespan); // Spawn spare tire kart when necessary m_next_sta_spawn_ticks = int( lifespan_ticks + getTicksSinceStart() * inc_factor diff --git a/src/modes/world.cpp b/src/modes/world.cpp index ee7cf557053..56cc82efa7b 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -886,7 +886,7 @@ void World::resetAllKarts() (*i)->getMaterial() && (*i)->getMaterial()->hasGravity() ? (*i)->getNormal() * -g : Vec3(0, -g, 0)); } - for(int i=0; igetPhysicsFPS(); i++) + for (int i = 0; i < STKConfig::get()->getPhysicsFPS(); i++) Physics::get()->update(1); for ( KartList::iterator i=m_karts.begin(); i!=m_karts.end(); i++) @@ -969,7 +969,7 @@ void World::updateTimeTargetSound() } if (time_left <= (RaceManager::get()->isFollowMode() ? 3 : 5) && - getTimeTicks() % stk_config->time2Ticks(1.0f) == 0 && + getTimeTicks() % STKConfig::get()->time2Ticks(1.0f) == 0 && !World::getWorld()->isRaceOver() && time_left > 0) { SFXManager::get()->quickSound("pre_start_race"); @@ -1183,7 +1183,7 @@ void World::update(int ticks) PROFILER_POP_CPU_MARKER(); PROFILER_PUSH_CPU_MARKER("World::update (Track object manager)", 0x20, 0x7F, 0x40); - Track::getCurrentTrack()->getTrackObjectManager()->update(stk_config->ticks2Time(ticks)); + Track::getCurrentTrack()->getTrackObjectManager()->update(STKConfig::get()->ticks2Time(ticks)); PROFILER_POP_CPU_MARKER(); PROFILER_PUSH_CPU_MARKER("World::update (Kart::upate)", 0x40, 0x7F, 0x00); diff --git a/src/modes/world_status.cpp b/src/modes/world_status.cpp index 711697a0b93..f3afeec9f92 100644 --- a/src/modes/world_status.cpp +++ b/src/modes/world_status.cpp @@ -79,6 +79,9 @@ void WorldStatus::reset(bool restart) m_auxiliary_ticks = 0; m_count_up_ticks = 0; m_start_music_ticks = -1; + + auto& stk_config = STKConfig::get(); + // how long to display the 'music' message m_race_ticks = stk_config->time2Ticks(stk_config->m_music_credit_time); @@ -159,6 +162,9 @@ void WorldStatus::startEngines() void WorldStatus::setClockMode(const ClockType mode, const float initial_time) { m_clock_mode = mode; + + auto& stk_config = STKConfig::get(); + m_time_ticks = stk_config->time2Ticks(initial_time); m_time = stk_config->ticks2Time(m_time_ticks); } // setClockMode @@ -209,6 +215,7 @@ void WorldStatus::update(int ticks) */ void WorldStatus::updateTime(int ticks) { + auto& stk_config = STKConfig::get(); switch (m_phase.load()) { // Note: setup phase must be a separate phase, since the race_manager @@ -509,6 +516,8 @@ void WorldStatus::updateTime(int ticks) */ void WorldStatus::setTime(const float time) { + auto& stk_config = STKConfig::get(); + int new_time_ticks = stk_config->time2Ticks(time); m_time_ticks = new_time_ticks; m_time = stk_config->ticks2Time(new_time_ticks); @@ -521,7 +530,7 @@ void WorldStatus::setTime(const float time) void WorldStatus::setTicks(int ticks) { m_time_ticks = ticks; - m_time = stk_config->ticks2Time(ticks); + m_time = STKConfig::get()->ticks2Time(ticks); } // setTicks //----------------------------------------------------------------------------- @@ -531,6 +540,7 @@ void WorldStatus::setTicks(int ticks) void WorldStatus::setTicksForRewind(int ticks) { m_count_up_ticks = ticks; + auto& stk_config = STKConfig::get(); if (RaceManager::get()->hasTimeTarget()) { m_time_ticks = stk_config->time2Ticks(RaceManager::get()->getTimeTarget()) - @@ -587,6 +597,8 @@ void WorldStatus::unpause() */ void WorldStatus::endLiveJoinWorld(int ticks_now) { + auto& stk_config = STKConfig::get(); + m_live_join_ticks = ticks_now; m_live_join_world = false; m_auxiliary_ticks = 0; diff --git a/src/modes/world_with_rank.cpp b/src/modes/world_with_rank.cpp index 8d2aa794b24..4bc6cb8e1ed 100644 --- a/src/modes/world_with_rank.cpp +++ b/src/modes/world_with_rank.cpp @@ -52,7 +52,7 @@ void WorldWithRank::init() m_position_setting_initialised = false; #endif if (!m_custom_scoring) - stk_config->getAllScores(&m_score_for_position, getNumKarts()); + STKConfig::get()->getAllScores(&m_score_for_position, getNumKarts()); else m_custom_scoring->refreshCustomScores(getNumKarts(), m_score_for_position); diff --git a/src/network/child_loop.cpp b/src/network/child_loop.cpp index ee0324509a6..ef95e7fe526 100644 --- a/src/network/child_loop.cpp +++ b/src/network/child_loop.cpp @@ -113,6 +113,9 @@ void ChildLoop::run() m_curr_time = StkTime::getMonoTimeMs(); float left_over_time = 0; + + auto& stk_config = STKConfig::get(); + while (!m_abort) { if (STKHost::existHost() && STKHost::get()->requestedShutdown()) diff --git a/src/network/network_config.cpp b/src/network/network_config.cpp index 6d3f676cfb8..3b077c09d7b 100644 --- a/src/network/network_config.cpp +++ b/src/network/network_config.cpp @@ -169,7 +169,7 @@ NetworkConfig::NetworkConfig() void NetworkConfig::initClientPort() { m_client_port = UserConfigParams::m_random_client_port ? - 0 : stk_config->m_client_port; + 0 : STKConfig::get()->m_client_port; } // initClientPort // ---------------------------------------------------------------------------- @@ -730,6 +730,9 @@ const std::vector >& { static std::vector > ipv4_list; static std::vector > ipv6_list; + + auto& stk_config = STKConfig::get(); + if (ipv4) { if (ipv4_list.empty()) diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp index fb372a7746c..84cc5c38f37 100644 --- a/src/network/protocols/client_lobby.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -403,6 +403,7 @@ std::vector > //----------------------------------------------------------------------------- void ClientLobby::update(int ticks) { + auto& stk_config = STKConfig::get(); switch (m_state.load()) { case LINKED: diff --git a/src/network/protocols/connect_to_server.cpp b/src/network/protocols/connect_to_server.cpp index 598273c2a70..e434d261cba 100644 --- a/src/network/protocols/connect_to_server.cpp +++ b/src/network/protocols/connect_to_server.cpp @@ -838,7 +838,7 @@ bool ConnectToServer::detectPort() address = *m_server->getIPV6Address(); else address = m_server->getAddress(); - address.setPort(stk_config->m_server_discovery_port); + address.setPort(STKConfig::get()->m_server_discovery_port); nw->sendRawPacket(s, address); SocketAddress sender; const int LEN = 2048; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 1a7df1999e8..9acd543dace 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -909,6 +909,8 @@ void ServerLobby::asynchronousUpdate() } } + auto& stk_config = STKConfig::get(); + NetworkString* load_world_message = getLoadWorldMessage(players, false/*live_join*/); m_game_setup->setHitCaptureTime(getSettings()->getBattleHitCaptureLimit(), @@ -921,7 +923,7 @@ void ServerLobby::asynchronousUpdate() (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL || RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE)) RaceManager::get()->setRecordRace(true); - uint16_t flag_deactivated_time = (uint16_t)stk_config->time2Ticks( + uint16_t flag_deactivated_time = (uint16_t)STKConfig::get()->time2Ticks( getSettings()->getFlagDeactivatedTime()); RaceManager::get()->setFlagDeactivatedTicks(flag_deactivated_time); configRemoteKart(players, 0); @@ -979,6 +981,8 @@ NetworkString* ServerLobby::getLoadWorldMessage( load_world_message->addUInt32(m_item_seed); if (RaceManager::get()->isBattleMode()) { + auto& stk_config = STKConfig::get(); + load_world_message->addUInt32(getSettings()->getBattleHitCaptureLimit()) .addFloat(getSettings()->getBattleTimeLimit()); uint16_t flag_return_time = (uint16_t)stk_config->time2Ticks( @@ -1225,6 +1229,8 @@ void ServerLobby::finishedLoadingLiveJoinClient(Event* event) uint64_t live_join_start_time = STKHost::get()->getNetworkTimer(); + auto& stk_config = STKConfig::get(); + // Instead of using getTicksSinceStart we caculate the current world ticks // only from network timer, because if the server hangs in between the // world ticks may not be up to date @@ -2308,6 +2314,9 @@ void ServerLobby::connectionRequested(Event* event) // Check server version int version = data.getUInt32(); + + auto& stk_config = STKConfig::get(); + if (version < stk_config->m_min_server_version || version > stk_config->m_max_server_version) { @@ -2619,6 +2628,8 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, message_ack->addUInt8(LE_CONNECTION_ACCEPTED).addUInt32(peer->getHostId()) .addUInt32(ServerConfig::m_server_version); + auto& stk_config = STKConfig::get(); + message_ack->addUInt16( (uint16_t)stk_config->m_network_capabilities.size()); for (const std::string& cap : stk_config->m_network_capabilities) @@ -3503,6 +3514,9 @@ float ServerLobby::getStartupBoostOrPenaltyForKart(uint32_t ping, uint64_t now = STKHost::get()->getNetworkTimer(); uint64_t client_time = now - ping / 2; uint64_t server_time = client_time + m_server_delay; + + auto& stk_config = STKConfig::get(); + int ticks = stk_config->time2Ticks( (float)(server_time - m_server_started_at) / 1000.0f); if (ticks < stk_config->time2Ticks(1.0f)) diff --git a/src/network/rewind_manager.cpp b/src/network/rewind_manager.cpp index 1eef6b9ba7c..e6afe109976 100644 --- a/src/network/rewind_manager.cpp +++ b/src/network/rewind_manager.cpp @@ -87,7 +87,7 @@ void RewindManager::reset() m_is_rewinding = false; m_not_rewound_ticks.store(0); m_overall_state_size = 0; - m_state_frequency = stk_config->getPhysicsFPS() / + m_state_frequency = STKConfig::get()->getPhysicsFPS() / NetworkConfig::get()->getStateFrequency(); if (!m_enable_rewind_manager) return; diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index f2e846ff574..fd4cc5762db 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -156,6 +156,8 @@ void loadServerConfigXML(const XMLNode* root, bool default_config) return; } + auto& stk_config = STKConfig::get(); + int config_file_version = -1; if (root->get("version", &config_file_version) < 1 || config_file_version < stk_config->m_min_server_version || @@ -309,6 +311,8 @@ void loadServerLobbyFromConfig() if (unsupportedGameMode()) Log::fatal("ServerConfig", "Unsupported game mode"); + auto& stk_config = STKConfig::get(); + if (stk_config->time2Ticks(m_flag_return_timeout) > 65535 || m_flag_return_timeout <= 0.0f) { diff --git a/src/network/servers_manager.cpp b/src/network/servers_manager.cpp index 4187a319f7a..eae2b42c156 100644 --- a/src/network/servers_manager.cpp +++ b/src/network/servers_manager.cpp @@ -138,6 +138,8 @@ std::shared_ptr ServersManager::getWANRefreshRequest() const return; } + auto& stk_config = STKConfig::get(); + const XMLNode *servers_xml = getXMLData()->getNode("servers"); for (unsigned int i = 0; i < servers_xml->getNumNodes(); i++) { @@ -148,6 +150,7 @@ std::shared_ptr ServersManager::getWANRefreshRequest() const int version = 0; si->get("version", &version); assert(version != 0); + if (version < stk_config->m_max_server_version || version > stk_config->m_max_server_version) { @@ -262,6 +265,9 @@ std::shared_ptr ServersManager::getLANRefreshRequest() const // because e.g. a local client would answer as 127.0.0.1 and // 192.168.**. std::map > servers_now; + + auto& stk_config = STKConfig::get(); + while (StkTime::getMonoTimeMs() - start_time < DURATION) { SocketAddress sender; @@ -340,7 +346,7 @@ std::vector ServersManager::getDefaultBroadcastAddresses() { // Add some common LAN addresses std::vector result; - uint16_t port = stk_config->m_server_discovery_port; + uint16_t port = STKConfig::get()->m_server_discovery_port; result.emplace_back(std::string("192.168.255.255"), port); result.emplace_back(std::string("192.168.0.255"), port); result.emplace_back(std::string("192.168.1.255"), port); @@ -379,7 +385,7 @@ void ServersManager::addAllBroadcastAddresses(const SocketAddress &a, int len, { unsigned int mask = (1 << len) - 1; SocketAddress bcast(a.getIP() | mask, - stk_config->m_server_discovery_port); + STKConfig::get()->m_server_discovery_port); Log::info("Broadcast", "address %s length %d mask %x --> %s", a.toString().c_str(), len, mask, @@ -468,7 +474,7 @@ std::vector ServersManager::getBroadcastAddresses(bool ipv6) continue; used_scope_id.insert(idx); SocketAddress socket_address("ff02::1", - stk_config->m_server_discovery_port); + STKConfig::get()->m_server_discovery_port); sockaddr_in6* in6 = (sockaddr_in6*)socket_address.getSockaddr(); in6->sin6_scope_id = idx; result.push_back(socket_address); diff --git a/src/network/smooth_network_body.cpp b/src/network/smooth_network_body.cpp index 195d845b539..080a6066c60 100644 --- a/src/network/smooth_network_body.cpp +++ b/src/network/smooth_network_body.cpp @@ -28,6 +28,9 @@ SmoothNetworkBody::SmoothNetworkBody(bool enable) m_enabled = enable; m_smooth_rotation = true; m_adjust_vertical_offset = true; + + auto& stk_config = STKConfig::get(); + m_min_adjust_length = stk_config->m_snb_min_adjust_length; m_max_adjust_length = stk_config->m_snb_max_adjust_length; m_min_adjust_speed = stk_config->m_snb_min_adjust_speed; diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index db1ff5dcfed..adc7c91a6a7 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -278,7 +278,7 @@ STKHost::STKHost(bool server) #endif addr.port = ServerConfig::m_server_port; if (addr.port == 0 && !UserConfigParams::m_random_server_port) - addr.port = stk_config->m_server_port; + addr.port = STKConfig::get()->m_server_port; // Reserve 1 peer to deliver full server message int peer_count = ServerConfig::m_server_max_players + 1; // 1 more peer to hold ai peer @@ -811,7 +811,7 @@ void STKHost::mainLoop(ProcessType pt) NetworkConfig::get()->isPublicServer()) { ENetAddress eaddr = {}; - eaddr.port = stk_config->m_server_discovery_port; + eaddr.port = STKConfig::get()->m_server_discovery_port; direct_socket = new Network(1, 1, 0, 0, &eaddr); if (direct_socket->getENetHost() == NULL) { diff --git a/src/online/http_request.cpp b/src/online/http_request.cpp index c98b07fa4a0..30e9d3bb90f 100644 --- a/src/online/http_request.cpp +++ b/src/online/http_request.cpp @@ -105,6 +105,8 @@ namespace Online void HTTPRequest::setApiURL(const std::string& path, const std::string &action) { + auto& stk_config = STKConfig::get(); + // Old (0.8.1) API: send to client-user.php, and add action as a parameter if (stk_config->m_server_api_version == 1) { @@ -135,7 +137,7 @@ namespace Online */ void HTTPRequest::setAddonsURL(const std::string& path) { - setURL(stk_config->m_server_addons + "/" + path); + setURL(STKConfig::get()->m_server_addons + "/" + path); } // set AddonsURL // ------------------------------------------------------------------------ diff --git a/src/physics/btKart.cpp b/src/physics/btKart.cpp index 657e99686f4..5d3302efead 100644 --- a/src/physics/btKart.cpp +++ b/src/physics/btKart.cpp @@ -499,6 +499,8 @@ void btKart::updateVehicle( btScalar step ) m_chassisBody->applyCentralImpulse(downwards_impulse); } + auto& stk_config = STKConfig::get(); + // Apply additional impulse set by supertuxkart // -------------------------------------------- if(m_ticks_additional_impulse>0) diff --git a/src/physics/btKart.hpp b/src/physics/btKart.hpp index 65ecdd28286..5b84b408710 100644 --- a/src/physics/btKart.hpp +++ b/src/physics/btKart.hpp @@ -250,7 +250,7 @@ class btKart : public btActionInterface if (t > 0) { m_additional_rotation = - rot_in_y_axis / (stk_config->ticks2Time(t)); + rot_in_y_axis / (STKConfig::get()->ticks2Time(t)); } m_ticks_additional_rotation = t; } // setTimedTorque diff --git a/src/physics/physical_object.cpp b/src/physics/physical_object.cpp index 5d898964288..8bb271bca7b 100644 --- a/src/physics/physical_object.cpp +++ b/src/physics/physical_object.cpp @@ -720,6 +720,7 @@ void PhysicalObject::reset() // ---------------------------------------------------------------------------- void PhysicalObject::handleExplosion(const Vec3& pos, bool direct_hit) { + auto& stk_config = STKConfig::get(); if(direct_hit) { @@ -740,7 +741,7 @@ void PhysicalObject::handleExplosion(const Vec3& pos, bool direct_hit) // = diff*impulseSize/len(diff)^3 // We use diff*impulseSize/len(diff)^2 here, this makes the impulse // somewhat larger, which is actually more fun :) - btVector3 impulse=diff*stk_config->m_explosion_impulse_objects/len2; + btVector3 impulse = diff * stk_config->m_explosion_impulse_objects / len2; m_body->applyCentralImpulse(impulse); } m_body->activate(); diff --git a/src/physics/physics.cpp b/src/physics/physics.cpp index ded8a5346be..2d1eeaf6de5 100644 --- a/src/physics/physics.cpp +++ b/src/physics/physics.cpp @@ -104,6 +104,9 @@ void Physics::init(const Vec3 &world_min, const Vec3 &world_max) // Get the solver settings from the config file btContactSolverInfo& info = m_dynamics_world->getSolverInfo(); + + auto& stk_config = STKConfig::get(); + info.m_numIterations = stk_config->m_solver_iterations; info.m_splitImpulse = stk_config->m_solver_split_impulse; info.m_splitImpulsePenetrationThreshold = @@ -195,6 +198,8 @@ void Physics::update(int ticks) double start; if(UserConfigParams::m_physics_debug) start = StkTime::getRealTime(); + auto& stk_config = STKConfig::get(); + m_dynamics_world->stepSimulation(stk_config->ticks2Time(1), 1, stk_config->ticks2Time(1) ); if (UserConfigParams::m_physics_debug) @@ -526,6 +531,8 @@ void Physics::KartKartCollision(AbstractKart *kart_a, f_left = f_left * f_left; f_right = f_right * f_right; + auto& stk_config = STKConfig::get(); + // First push one kart to the left (if there is not already // an impulse happening - one collision might cause more // than one impulse otherwise) diff --git a/src/physics/triangle_mesh.cpp b/src/physics/triangle_mesh.cpp index b4f31d181e5..ef9a2d2063f 100644 --- a/src/physics/triangle_mesh.cpp +++ b/src/physics/triangle_mesh.cpp @@ -73,11 +73,14 @@ void TriangleMesh::addTriangle(const btVector3 &t1, const btVector3 &t2, btVector3 normal = (t2-t1).cross(t3-t1); normal.normalize(); - m_normals.push_back( normal.angle(n1)>stk_config->m_smooth_angle_limit + + auto& stk_config = STKConfig::get(); + + m_normals.push_back( normal.angle(n1) > stk_config->m_smooth_angle_limit ? normal : n1 ); - m_normals.push_back( normal.angle(n2)>stk_config->m_smooth_angle_limit + m_normals.push_back( normal.angle(n2) > stk_config->m_smooth_angle_limit ? normal : n2 ); - m_normals.push_back( normal.angle(n3)>stk_config->m_smooth_angle_limit + m_normals.push_back( normal.angle(n3) > stk_config->m_smooth_angle_limit ? normal : n3 ); m_mesh.addTriangle(t1, t2, t3); diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index a71dfa36ce3..a3e0239b9b4 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -120,6 +120,8 @@ void RaceManager::clear() */ RaceManager::RaceManager() { + auto& stk_config = STKConfig::get(); + // Several code depends on this, e.g. kart_properties assert(DIFFICULTY_FIRST == 0); m_num_karts = UserConfigParams::m_default_num_karts; @@ -442,7 +444,7 @@ void RaceManager::startNew(bool from_overworld) } // if grand prix // command line parameters: negative numbers=all karts - if(m_num_karts < 0 ) m_num_karts = stk_config->m_max_karts; + if(m_num_karts < 0 ) m_num_karts = STKConfig::get()->m_max_karts; if((size_t)m_num_karts < m_player_karts.size()) m_num_karts = (int)m_player_karts.size(); diff --git a/src/replay/replay_recorder.cpp b/src/replay/replay_recorder.cpp index a312f9d41ea..4ea878cb47f 100644 --- a/src/replay/replay_recorder.cpp +++ b/src/replay/replay_recorder.cpp @@ -53,6 +53,8 @@ ReplayRecorder::ReplayRecorder() m_incorrect_replay = false; m_previous_steer = 0.0f; + auto& stk_config = STKConfig::get(); + assert(stk_config->m_replay_max_frames >= 0); m_max_frames = stk_config->m_replay_max_frames; } // ReplayRecorder @@ -120,8 +122,10 @@ void ReplayRecorder::update(int ticks) const bool single_player = RaceManager::get()->getNumPlayers() == 1; unsigned int num_karts = world->getNumKarts(); + auto& stk_config = STKConfig::get(); + float time = world->getTime(); - for(unsigned int i=0; igetKart(i); // If a single player give up in game menu, stop recording @@ -178,9 +182,9 @@ void ReplayRecorder::update(int ticks) float speed_change = fabsf(kart->getSpeed() - q_prev->m_speed); if ( speed_change > stk_config->m_replay_delta_speed ) { - if (speed_change > 4*stk_config->m_replay_delta_speed) + if (speed_change > 4 * stk_config->m_replay_delta_speed) force_update = true; - else if (speed_change > 2*stk_config->m_replay_delta_speed && + else if (speed_change > 2 * stk_config->m_replay_delta_speed && time - m_last_saved_time[i] > (stk_config->m_replay_dt/8.0f)) force_update = true; else if (time - m_last_saved_time[i] > (stk_config->m_replay_dt/3.0f)) diff --git a/src/states_screens/credits.cpp b/src/states_screens/credits.cpp index 11cbe556ce6..b5bdad7a9eb 100644 --- a/src/states_screens/credits.cpp +++ b/src/states_screens/credits.cpp @@ -407,7 +407,7 @@ void CreditsScreen::eventCallback(GUIEngine::Widget* widget, if (name == "donate") { // Open donation page - Online::LinkHelper::openURL(stk_config->m_donate_url); + Online::LinkHelper::openURL(STKConfig::get()->m_donate_url); } } diff --git a/src/states_screens/credits.hpp b/src/states_screens/credits.hpp index dc7a51f399e..cb5d730e1ff 100644 --- a/src/states_screens/credits.hpp +++ b/src/states_screens/credits.hpp @@ -89,7 +89,7 @@ class CreditsScreen : public GUIEngine::Screen, if (m_is_victory_music) return music_manager->getMusicInformation("win_theme.music"); else - return stk_config->m_title_music; + return STKConfig::get()->m_title_music; } virtual void onResize() OVERRIDE diff --git a/src/states_screens/feature_unlocked.cpp b/src/states_screens/feature_unlocked.cpp index ced123309ac..f1f3748d130 100644 --- a/src/states_screens/feature_unlocked.cpp +++ b/src/states_screens/feature_unlocked.cpp @@ -749,7 +749,7 @@ void FeatureUnlockedCutScene::continueButtonPressed() { // simulate all the steps of the animation until we reach the end onUpdate(0.4f); - World::getWorld()->updateWorld(stk_config->time2Ticks(0.4f)); + World::getWorld()->updateWorld(STKConfig::get()->time2Ticks(0.4f)); } } else @@ -775,6 +775,7 @@ void FeatureUnlockedCutScene::eventCallback(GUIEngine::Widget* widget, MusicInformation* FeatureUnlockedCutScene::getInGameMenuMusic() const { - MusicInformation* mi = stk_config->m_unlock_music; + MusicInformation* mi = STKConfig::get()->m_unlock_music; return mi; -} +} // getInGameMenuMusic +//----------------------------------------------------------------------------- diff --git a/src/states_screens/gp_info_screen.cpp b/src/states_screens/gp_info_screen.cpp index 71db9c06c49..0efd30b9149 100644 --- a/src/states_screens/gp_info_screen.cpp +++ b/src/states_screens/gp_info_screen.cpp @@ -218,7 +218,7 @@ void GPInfoScreen::init() m_ai_kart_spinner->setActive(true); m_ai_kart_spinner->setValue(num_ai); - m_ai_kart_spinner->setMax(stk_config->m_max_karts - local_players); + m_ai_kart_spinner->setMax(STKConfig::get()->m_max_karts - local_players); m_ai_kart_spinner->setMin(min_ai); } // has_AI diff --git a/src/states_screens/grand_prix_lose.cpp b/src/states_screens/grand_prix_lose.cpp index 97cbfe0d240..ef7a207a684 100644 --- a/src/states_screens/grand_prix_lose.cpp +++ b/src/states_screens/grand_prix_lose.cpp @@ -238,7 +238,7 @@ void GrandPrixLose::setKarts(std::vector > ident_a MusicInformation* GrandPrixLose::getInGameMenuMusic() const { - MusicInformation* mi = stk_config->m_gp_lose_music; + MusicInformation* mi = STKConfig::get()->m_gp_lose_music; return mi; } diff --git a/src/states_screens/grand_prix_win.cpp b/src/states_screens/grand_prix_win.cpp index b14c0db8c89..436a264a4ce 100644 --- a/src/states_screens/grand_prix_win.cpp +++ b/src/states_screens/grand_prix_win.cpp @@ -458,7 +458,7 @@ void GrandPrixWin::setKarts(const std::pair idents_arg[3]) MusicInformation* GrandPrixWin::getInGameMenuMusic() const { - MusicInformation* mi = stk_config->m_gp_win_music; + MusicInformation* mi = STKConfig::get()->m_gp_win_music; return mi; } diff --git a/src/states_screens/online/register_screen.cpp b/src/states_screens/online/register_screen.cpp index 0360c7cd8b9..c9f3e003c19 100644 --- a/src/states_screens/online/register_screen.cpp +++ b/src/states_screens/online/register_screen.cpp @@ -523,7 +523,7 @@ void RegisterScreen::eventCallback(Widget* widget, const std::string& name, else if (name == "password_reset") { // Open password reset page - Online::LinkHelper::openURL(stk_config->m_password_reset_url); + Online::LinkHelper::openURL(STKConfig::get()->m_password_reset_url); } else if (name == "back") { diff --git a/src/states_screens/race_gui_base.cpp b/src/states_screens/race_gui_base.cpp index bb3a19adcc4..e1a83348477 100644 --- a/src/states_screens/race_gui_base.cpp +++ b/src/states_screens/race_gui_base.cpp @@ -540,7 +540,7 @@ void RaceGUIBase::update(float dt) // already 1 second ahead of time when crossing finished line) if (k->getNetworkConfirmedFinishTicks() > 0 && w->getTicksSinceStart() > - k->getNetworkConfirmedFinishTicks() + stk_config->time2Ticks(1.0f)) + k->getNetworkConfirmedFinishTicks() + STKConfig::get()->time2Ticks(1.0f)) { m_enabled_network_spectator = true; cl->setSpectator(true); @@ -616,6 +616,8 @@ void RaceGUIBase::drawGlobalMusicDescription() const int fheight = font->getDimension(L"X").Height; + auto& stk_config = STKConfig::get(); + float race_time = stk_config->ticks2Time(World::getWorld()->getMusicDescriptionTicks()); @@ -1283,13 +1285,13 @@ void RaceGUIBase::drawPlungerInFace(const Camera *camera, float dt) m_plunger_speed = core::vector2df(0, 0); } - if(World::getWorld()->getPhase()!=World::IN_GAME_MENU_PHASE) + if (World::getWorld()->getPhase() != World::IN_GAME_MENU_PHASE) { m_plunger_move_time -= dt; - if(m_plunger_move_time < dt && m_plunger_state!=PLUNGER_STATE_FAST) + if (m_plunger_move_time < dt && m_plunger_state != PLUNGER_STATE_FAST) { const float fast_time = 0.3f; - if(kart->getBlockedByPlungerTicks()time2Ticks(fast_time)) + if (kart->getBlockedByPlungerTicks() < STKConfig::get()->time2Ticks(fast_time)) { // First time we reach faste state: select random target point // at top of screen and set speed accordingly diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index d51ea046213..53674f2c47a 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -129,6 +129,8 @@ void RaceResultGUI::init() m_finish_sound = SFXManager::get()->quickSound( human_win ? "race_finish_victory" : "race_finish"); + auto& stk_config = STKConfig::get(); + // Play different result music based on player kart positions. if (has_human_players) { diff --git a/src/states_screens/track_info_screen.cpp b/src/states_screens/track_info_screen.cpp index 2a9a4a50a43..12229d32a20 100644 --- a/src/states_screens/track_info_screen.cpp +++ b/src/states_screens/track_info_screen.cpp @@ -139,6 +139,8 @@ void TrackInfoScreen::init() { m_record_this_race = false; + auto& stk_config = STKConfig::get(); + const int max_arena_players = std::min(m_track->getMaxArenaPlayers(), unsigned(stk_config->m_max_karts)); const int local_players = RaceManager::get()->getNumLocalPlayers(); const bool has_laps = RaceManager::get()->modeHasLaps(); diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 93311bf6ef9..950c53d1612 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -530,7 +530,7 @@ void Track::loadTrackInfo() m_fog_height_start = 0.0f; m_fog_height_end = 100.0f; m_gravity = 9.80665f; - m_friction = stk_config->m_default_track_friction; + m_friction = STKConfig::get()->m_default_track_friction; m_smooth_normals = false; m_godrays = false; m_godrays_opacity = 1.0f; @@ -709,7 +709,7 @@ void Track::getMusicInformation(std::vector& filenames, if (m_music.empty() && !isInternal() && !m_is_cutscene) { - m_music.push_back(stk_config->m_default_music); + m_music.push_back(STKConfig::get()->m_default_music); Log::warn("track", "Music information for track '%s' replaced by default music.\n", @@ -1681,7 +1681,7 @@ void Track::update(int ticks) m_current_track[PT_CHILD] = child_track; } } - float dt = stk_config->ticks2Time(ticks); + float dt = STKConfig::get()->ticks2Time(ticks); m_check_manager->update(dt); m_item_manager->update(ticks); @@ -1999,7 +1999,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) { // In a FTL race the non-leader karts are placed at the end of the // field, so we need all start positions. - m_start_transforms.resize(stk_config->m_max_karts); + m_start_transforms.resize(STKConfig::get()->m_max_karts); } else m_start_transforms.resize(RaceManager::get()->getNumberOfKarts()); diff --git a/src/tracks/track_manager.cpp b/src/tracks/track_manager.cpp index 142e3e36404..d68414db1ce 100644 --- a/src/tracks/track_manager.cpp +++ b/src/tracks/track_manager.cpp @@ -57,7 +57,7 @@ TrackManager::~TrackManager() } // ~TrackManager //----------------------------------------------------------------------------- -std::shared_ptr TrackManager::get() +std::shared_ptr& TrackManager::get() { static std::shared_ptr instance = std::make_shared(); return instance; @@ -226,8 +226,10 @@ bool TrackManager::loadTrack(const std::string& dirname) return false; } - if (track->getVersion()m_min_track_version || - track->getVersion()>stk_config->m_max_track_version) + auto& stk_config = STKConfig::get(); + + if (track->getVersion() < stk_config->m_min_track_version || + track->getVersion() > stk_config->m_max_track_version) { Log::warn("TrackManager", "Track '%s' is not supported " "by this binary, ignored. (Track is version %i, this " diff --git a/src/tracks/track_manager.hpp b/src/tracks/track_manager.hpp index 43cd256ade5..94c66ab10da 100644 --- a/src/tracks/track_manager.hpp +++ b/src/tracks/track_manager.hpp @@ -92,7 +92,7 @@ class TrackManager TrackManager(); ~TrackManager(); - static std::shared_ptr get(); + static std::shared_ptr& get(); static void removeTrackSearchDirs(); static void addTrackSearchDir(const std::string &dir); diff --git a/src/tracks/track_object.cpp b/src/tracks/track_object.cpp index a6de8bcc871..f7c1402a6df 100644 --- a/src/tracks/track_object.cpp +++ b/src/tracks/track_object.cpp @@ -556,7 +556,7 @@ void TrackObject::resetAfterRewind() btTransform new_trans; m_physical_object->getMotionState()->getWorldTransform(new_trans); m_physical_object->getBody()->setCenterOfMassTransform(new_trans); - m_physical_object->getBody()->saveKinematicState(stk_config->ticks2Time(1)); + m_physical_object->getBody()->saveKinematicState(STKConfig::get()->ticks2Time(1)); } // resetAfterRewind // ---------------------------------------------------------------------------- diff --git a/src/tracks/track_object_manager.cpp b/src/tracks/track_object_manager.cpp index d8cb5e0a3e5..5d5234b2c7f 100644 --- a/src/tracks/track_object_manager.cpp +++ b/src/tracks/track_object_manager.cpp @@ -70,6 +70,9 @@ void TrackObjectManager::init() { int moveable_objects = 0; bool warned = false; + + auto& stk_config = STKConfig::get(); + for (unsigned i = 0; i < m_all_objects.m_contents_vector.size(); i++) { TrackObject* curr = m_all_objects.m_contents_vector[i]; diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index 93b251aef52..b1a69a3c5f6 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -205,7 +205,11 @@ void setNitro(int amount) void addAttachment(Attachment::AttachmentType type) { World* world = World::getWorld(); - if (world == NULL) return; + if (world == NULL) + return; + + auto& stk_config = STKConfig::get(); + for (unsigned int i = 0; i < world->getNumKarts(); i++) { AbstractKart *kart = world->getLocalPlayerKart(i); diff --git a/src/utils/game_info.cpp b/src/utils/game_info.cpp index 6a266ce2037..85fa7cf3270 100644 --- a/src/utils/game_info.cpp +++ b/src/utils/game_info.cpp @@ -134,7 +134,7 @@ int GameInfo::onLiveJoinedPlayer(int id, const RemoteKartInfo& rki, World* w) info.m_username = StringUtils::wideToUtf8(rki.getPlayerName()); info.m_kart = rki.getKartName(); info.m_start_position = w->getStartPosition(id); - info.m_when_joined = stk_config->ticks2Time(w->getTicksSinceStart()); + info.m_when_joined = STKConfig::get()->ticks2Time(w->getTicksSinceStart()); info.m_country_code = rki.getCountryCode(); info.m_online_id = rki.getOnlineId(); info.m_kart_class = rki.getKartData().m_kart_type; @@ -190,7 +190,7 @@ void GameInfo::saveDisconnectingIdInfo(int id) if (getSettings()->isPreservingBattleScores()) m_saved_ffa_points[StringUtils::wideToUtf8(rki.getPlayerName())] = points; } - info.m_when_left = stk_config->ticks2Time(w->getTicksSinceStart()); + info.m_when_left = STKConfig::get()->ticks2Time(w->getTicksSinceStart()); info.m_start_position = w->getStartPosition(id); if (RaceManager::get()->isLinearRaceMode()) { @@ -294,7 +294,7 @@ void GameInfo::fillAndStoreResults() std::string best_cur_player_name = ""; double best_cur_time = 1e18; - double current_game_timestamp = stk_config->ticks2Time(w->getTicksSinceStart()); + double current_game_timestamp = STKConfig::get()->ticks2Time(w->getTicksSinceStart()); auto& vec = m_player_info; diff --git a/src/utils/hit_processor.cpp b/src/utils/hit_processor.cpp index 84cb10c58e2..5cb17fd44d3 100644 --- a/src/utils/hit_processor.cpp +++ b/src/utils/hit_processor.cpp @@ -97,7 +97,7 @@ void HitProcessor::sendTeammateHitMsg(std::string& s) return; int ticks = w->getTicksSinceStart(); - if (ticks - m_last_hit_msg > stk_config->time2Ticks(g_hit_message_delay)) + if (ticks - m_last_hit_msg > STKConfig::get()->time2Ticks(g_hit_message_delay)) { m_last_hit_msg = ticks; getLobby()->sendStringToAllPeers(s); @@ -123,7 +123,7 @@ void HitProcessor::handleTeammateHits() // currently only bowling balls have their creation time registered // so cakes will always count - if (m_ticks_since_thrown > stk_config->time2Ticks(MAX_BOWL_TEAMMATE_HIT_TIME)) + if (m_ticks_since_thrown > STKConfig::get()->time2Ticks(MAX_BOWL_TEAMMATE_HIT_TIME)) return; if (showTeammateHits()) @@ -258,7 +258,7 @@ void HitProcessor::handleSwatterHit(unsigned int ownerID, unsigned int victimID, // if this is the first kart hit and the swatter is in use // for less than 3s, the attacker also gets an anvil if (!has_hit_kart - && ticks_active < stk_config->time2Ticks(3.0f) + && ticks_active < STKConfig::get()->time2Ticks(3.0f) && success) { // we cannot do this here, will be done in update() @@ -345,7 +345,7 @@ void HitProcessor::punishKart(AbstractKart* kart, float value, float value2) auto time_used = kart->getKartProperties()->getAnvilDuration(); kart->getAttachment()->set(Attachment::ATTACH_ANVIL, - stk_config->time2Ticks(time_used) * value + leftover_ticks); + STKConfig::get()->time2Ticks(time_used) * value + leftover_ticks); auto factor = kart->getKartProperties()->getAnvilSpeedFactor(); kart->adjustSpeed(factor / value); diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index 09aaee4caf4..dc0f0db576e 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -626,7 +626,7 @@ namespace StringUtils /** Returns the time (in seconds) as string, based on ticks. */ std::string ticksTimeToString(int ticks) { - return timeToString(stk_config->ticks2Time(ticks)); + return timeToString(STKConfig::get()->ticks2Time(ticks)); } // ticksTimeToString(ticks) // ------------------------------------------------------------------------ From b15c5b9d791e41c0abce3a1063bf32184b15313f Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 29 Mar 2025 02:27:02 +0400 Subject: [PATCH 638/830] Trying some compilation fixes --- src/network/servers_manager.cpp | 2 +- src/states_screens/dialogs/download_assets.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/servers_manager.cpp b/src/network/servers_manager.cpp index eae2b42c156..19507e2f77e 100644 --- a/src/network/servers_manager.cpp +++ b/src/network/servers_manager.cpp @@ -551,7 +551,7 @@ std::vector ServersManager::getBroadcastAddresses(bool ipv6) continue; used_scope_id.insert(scope_id); SocketAddress socket_address("ff02::1", - stk_config->m_server_discovery_port); + STKConfig::get()->m_server_discovery_port); in6 = (sockaddr_in6*)socket_address.getSockaddr(); in6->sin6_scope_id = scope_id; result.push_back(socket_address); diff --git a/src/states_screens/dialogs/download_assets.cpp b/src/states_screens/dialogs/download_assets.cpp index e3dacf24c9b..7ad54da0a6f 100644 --- a/src/states_screens/dialogs/download_assets.cpp +++ b/src/states_screens/dialogs/download_assets.cpp @@ -59,7 +59,7 @@ class DownloadAssetsRequest : public HTTPRequest : HTTPRequest("stk-assets.zip", /*priority*/5) { m_extraction_error = true; - std::string download_url = stk_config->m_assets_download_url; + std::string download_url = STKConfig::get()->m_assets_download_url; download_url += STK_VERSION; download_url += "/stk-assets.zip"; setURL(download_url); From 7705e309414114da11ed4a60048408ce4b7b60da Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 29 Mar 2025 04:13:13 +0400 Subject: [PATCH 639/830] Move two more methods out of ServerLobby The majority of the rest seems to be packets packets packets packets packets packets It's going to be a long run... --- src/network/protocols/command_manager.cpp | 5 ++- src/network/protocols/server_lobby.cpp | 51 +++-------------------- src/network/protocols/server_lobby.hpp | 2 - src/utils/kart_elimination.cpp | 25 +++++++++-- src/utils/kart_elimination.hpp | 2 +- src/utils/team_manager.cpp | 21 ++++++++++ src/utils/team_manager.hpp | 1 + 7 files changed, 54 insertions(+), 53 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 34f252fda08..b75aede7e78 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -3248,7 +3248,10 @@ void CommandManager::process_game(Context& context) getSettings()->setFixedLapCount(new_duration); if (tournament->hasColorsSwapped(new_game_number) ^ tournament->hasColorsSwapped(old_game_number)) - getLobby()->changeColors(); + { + getTeamManager()->changeColors(); + getLobby()->updatePlayerList(); + } if (tournament->hasGoalsLimit(new_game_number) ^ tournament->hasGoalsLimit(old_game_number)) getLobby()->changeLimitForTournament(tournament->hasGoalsLimit()); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 9acd543dace..6f7b3345af1 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2049,9 +2049,9 @@ void ServerLobby::checkRaceFinished() if (getKartElimination()->isEnabled()) { - // ServerLobby's function because we need to take - // the list of players from somewhere - updateGnuElimination(); + std::string msg = getKartElimination()->onRaceFinished(); + if (!msg.empty()) + sendStringToAllPeers(msg); } if (getSettings()->isStoringResults()) @@ -4137,25 +4137,7 @@ void ServerLobby::handleServerCommand(Event* event) getCommandManager()->handleCommand(event, peer); } // handleServerCommand //----------------------------------------------------------------------------- -void ServerLobby::updateGnuElimination() -{ - World* w = World::getWorld(); - assert(w); - int player_count = RaceManager::get()->getNumPlayers(); - std::map order; - for (int i = 0; i < player_count; i++) - { - std::string username = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(i).getPlayerName()); - if (w->getKart(i)->isEliminated()) - order[username] = KartElimination::INF_TIME; - else - order[username] = RaceManager::get()->getKartRaceTime(i); - } - std::string msg = getKartElimination()->update(order); - if (!msg.empty()) - sendStringToAllPeers(msg); -} // updateGnuElimination -//----------------------------------------------------------------------------- + void ServerLobby::storeResults() { if (!m_game_info) @@ -4167,6 +4149,7 @@ void ServerLobby::storeResults() m_game_info->fillAndStoreResults(); } // storeResults //----------------------------------------------------------------------------- + void ServerLobby::resetToDefaultSettings() { if (getSettings()->isServerConfigurable() && !getSettings()->isPreservingMode()) @@ -4175,6 +4158,7 @@ void ServerLobby::resetToDefaultSettings() getSettings()->onResetToDefaultSettings(); } // resetToDefaultSettings //----------------------------------------------------------------------------- + void ServerLobby::writeOwnReport(std::shared_ptr reporter, std::shared_ptr reporting, const std::string& info) { #ifdef ENABLE_SQLITE3 @@ -4213,29 +4197,6 @@ void ServerLobby::writeOwnReport(std::shared_ptr reporter, std::shared_ #endif } // writeOwnReport //----------------------------------------------------------------------------- -void ServerLobby::changeColors() -{ - // We assume here that it's soccer, as it's only called - // from tournament command - auto peers = STKHost::get()->getPeers(); - for (auto peer : peers) - { - if (peer->hasPlayerProfiles()) - { - auto pp = peer->getPlayerProfiles()[0]; - if (pp->getTeam() == KART_TEAM_RED) - { - getTeamManager()->setTeamInLobby(pp, KART_TEAM_BLUE); - } - else if (pp->getTeam() == KART_TEAM_BLUE) - { - getTeamManager()->setTeamInLobby(pp, KART_TEAM_RED); - } - } - } - updatePlayerList(); -} // changeColors -//----------------------------------------------------------------------------- void ServerLobby::sendStringToPeer(std::shared_ptr peer, const std::string& s) { diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 14cfb862295..4b12fea64e8 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -283,7 +283,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser bool supportsAI(); void initTournamentPlayers(); public: - void changeColors(); void changeLimitForTournament(bool goal_target); private: bool canVote(std::shared_ptr peer) const; @@ -330,7 +329,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser bool writeOnePlayerReport(std::shared_ptr reporter, const std::string& table, const std::string& info); // int getTrackMaxPlayers(std::string& name) const; - void updateGnuElimination(); void sendStringToPeer(std::shared_ptr peer, const std::string& s); void sendStringToAllPeers(const std::string& s); diff --git a/src/utils/kart_elimination.cpp b/src/utils/kart_elimination.cpp index 0b34e804394..66512e6f4ab 100644 --- a/src/utils/kart_elimination.cpp +++ b/src/utils/kart_elimination.cpp @@ -20,6 +20,10 @@ #include "utils/log.hpp" #include "utils/string_utils.hpp" +#include "race/race_manager.hpp" +#include "modes/world.hpp" +#include "network/protocols/server_lobby.hpp" +#include "karts/abstract_kart.hpp" #include #include @@ -120,9 +124,21 @@ std::string KartElimination::getWarningMessage(bool isEliminated) const } // getWarningMessage //----------------------------------------------------------------------------- -std::string KartElimination::update( - std::map& order) +std::string KartElimination::onRaceFinished() { + World* w = World::getWorld(); + assert(w); + int player_count = RaceManager::get()->getNumPlayers(); + std::map order; + for (int i = 0; i < player_count; i++) + { + std::string username = StringUtils::wideToUtf8(RaceManager::get()->getKartInfo(i).getPlayerName()); + if (w->getKart(i)->isEliminated()) + order[username] = KartElimination::INF_TIME; + else + order[username] = RaceManager::get()->getKartRaceTime(i); + } + assert(m_remained != 0); if (m_remained < 0) { @@ -162,6 +178,7 @@ std::string KartElimination::update( msg += "\nGnu Elimination has finished! " "Congratulations to " + m_participants[0] + " !"; } + return msg; -} // update -//----------------------------------------------------------------------------- +} // onRaceFinished +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/kart_elimination.hpp b/src/utils/kart_elimination.hpp index 82f91d1aace..e1a3c139ff2 100644 --- a/src/utils/kart_elimination.hpp +++ b/src/utils/kart_elimination.hpp @@ -54,7 +54,7 @@ class KartElimination: public LobbyContextComponent std::string getStandings() const; std::string getStartingMessage() const; std::string getWarningMessage(bool isEliminated) const; - std::string update(std::map& order); + std::string onRaceFinished(); }; #endif diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp index c18c2f9f153..7cd2f1b6d99 100644 --- a/src/utils/team_manager.cpp +++ b/src/utils/team_manager.cpp @@ -412,3 +412,24 @@ bool TeamManager::assignRandomTeams(int intended_number, return true; } // assignRandomTeams //----------------------------------------------------------------------------- + +void TeamManager::changeColors() +{ + // We assume here that it's soccer, as it's only called + // from tournament command + auto peers = STKHost::get()->getPeers(); + for (auto peer : peers) + { + if (peer->hasPlayerProfiles()) + { + // kimden: you assume that only [0] can be checked, but in other places + // of the code you are somehow not so sure about that... :) + auto pp = peer->getPlayerProfiles()[0]; + if (pp->getTeam() == KART_TEAM_RED) + setTeamInLobby(pp, KART_TEAM_BLUE); + else if (pp->getTeam() == KART_TEAM_BLUE) + setTeamInLobby(pp, KART_TEAM_RED); + } + } +} // changeColors +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/team_manager.hpp b/src/utils/team_manager.hpp index c3e12b655a8..03db3a96473 100644 --- a/src/utils/team_manager.hpp +++ b/src/utils/team_manager.hpp @@ -82,6 +82,7 @@ class TeamManager: public LobbyContextComponent void checkNoTeamSpectator(std::shared_ptr peer); bool assignRandomTeams(int intended_number, int* final_number, int* player_number); + void changeColors(); private: From cfe350d23174e2b344750bdc11b43e165d5cab21 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 29 Mar 2025 15:13:11 +0400 Subject: [PATCH 640/830] A few more logs in db connector --- src/network/database_connector.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/network/database_connector.cpp b/src/network/database_connector.cpp index 6f887387a8b..1e56bee6a8f 100644 --- a/src/network/database_connector.cpp +++ b/src/network/database_connector.cpp @@ -173,7 +173,10 @@ bool DatabaseConnector::easySQLQuery( std::string null_value) const { if (!m_db) + { + Log::error("DatabaseConnector", "easySQLQuery: There is no database!"); return false; + } sqlite3_stmt* stmt = NULL; int ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &stmt, 0); if (ret == SQLITE_OK) @@ -1160,7 +1163,10 @@ bool DatabaseConnector::getBestResult(const GameInfo& game_info, bool* exists, std::string* user, double* result) { if (!m_records_table_exists) + { + Log::error("DatabaseConnector", "getBestResult: records table doesn't exist!"); return false; + } std::shared_ptr coll = std::make_shared(); // Note that IS is important, as the strings corresponding to value/time // limits can be NULL instead. SQLite manual specifies that IS can be used From 43a07453ddd4cae369204ae75c4f7f81fec2fe30 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 29 Mar 2025 22:46:16 +0400 Subject: [PATCH 641/830] Fix /length x value not accepting doubles --- src/utils/lobby_settings.cpp | 2 +- src/utils/lobby_settings.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index 0d103b06027..5a8d1f30c47 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -208,7 +208,7 @@ int LobbySettings::getFixedLapCount() const } // getFixedLapCount //----------------------------------------------------------------------------- -void LobbySettings::setMultiplier(int new_value) +void LobbySettings::setMultiplier(double new_value) { m_default_lap_multiplier = new_value; m_fixed_lap = -1; diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 6f92eb0bb57..3b664ed8027 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -60,7 +60,7 @@ class LobbySettings: public LobbyContextComponent bool hasFixedLapCount() const; int getMultiplier() const; int getFixedLapCount() const; - void setMultiplier(int new_value); + void setMultiplier(double new_value); void setFixedLapCount(int new_value); void resetLapRestrictions(); void setDefaultLapRestrictions(); From 297399a97a367f6c9d686f528c98ef06b7dbce9e Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 30 Mar 2025 11:21:51 +0800 Subject: [PATCH 642/830] Erase inserted texture in m_ondemand_load_texture_paths one by one --- src/graphics/material.cpp | 2 +- src/karts/kart_properties.cpp | 17 +++++++++++++---- src/karts/kart_properties.hpp | 2 +- src/tracks/track.cpp | 12 ++++++++++-- src/tracks/track_manager.cpp | 4 ++++ 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index 6b315031a84..adc12471957 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -586,7 +586,7 @@ void Material::install(std::function image_mani, m_sampler_path[i]); m_vk_textures[i - 2] = STKTexManager::getInstance()->getTexture( m_sampler_path[i]); - GE::getGEConfig()->m_ondemand_load_texture_paths.clear(); + GE::getGEConfig()->m_ondemand_load_texture_paths.erase(m_sampler_path[i]); if (m_vk_textures[i - 2]) m_vk_textures[i - 2]->grab(); } diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index 15eda0c2926..30a034b7048 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -189,11 +189,13 @@ void KartProperties::copyFrom(const KartProperties *source) } // copyFrom //----------------------------------------------------------------------------- -void KartProperties::handleOnDemandLoadTexture() +std::vector KartProperties::handleOnDemandLoadTexture() { + std::vector odt; #ifndef SERVER_ONLY if (GE::getDriver()->getDriverType() != video::EDT_VULKAN) - return; + return odt; + std::set files; // Remove the last / m_root_absolute_path = StringUtils::getPath(m_root); @@ -210,9 +212,13 @@ void KartProperties::handleOnDemandLoadTexture() { if (image_extensions.find(StringUtils::getExtension(f)) != image_extensions.end()) + { GE::getGEConfig()->m_ondemand_load_texture_paths.insert(f); + odt.push_back(f); + } } #endif + return odt; } // handleOnDemandLoadTexture //----------------------------------------------------------------------------- @@ -259,7 +265,7 @@ void KartProperties::load(const std::string &filename, const std::string &node) m_is_addon = true; } - handleOnDemandLoadTexture(); + std::vector odt = handleOnDemandLoadTexture(); try { if(!root || root->getName()!="kart") @@ -378,7 +384,10 @@ void KartProperties::load(const std::string &filename, const std::string &node) #ifndef SERVER_ONLY if (GE::getDriver()->getDriverType() == video::EDT_VULKAN) - GE::getGEConfig()->m_ondemand_load_texture_paths.clear(); + { + for (auto& t : odt) + GE::getGEConfig()->m_ondemand_load_texture_paths.erase(t); + } #endif } // load diff --git a/src/karts/kart_properties.hpp b/src/karts/kart_properties.hpp index c3f75848299..1e2fc014466 100644 --- a/src/karts/kart_properties.hpp +++ b/src/karts/kart_properties.hpp @@ -210,7 +210,7 @@ class KartProperties m_wheel_base = fabsf(kart_length / 1.425f); } - void handleOnDemandLoadTexture(); + std::vector handleOnDemandLoadTexture(); public: /** Returns the string representation of a handicap level. */ static std::string getHandicapAsString(HandicapLevel h); diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 66a595c0c30..bdb094a4479 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -2523,15 +2523,16 @@ void Track::handleSky(const XMLNode &xml_node, const std::string &filename) #endif // !SERVER_ONLY { #ifndef SERVER_ONLY + std::string fullpath; if (GE::getDriver()->getDriverType() == video::EDT_VULKAN) { io::path p = file_manager->searchTexture(v[i]).c_str(); if (!p.empty()) { - io::path fullpath = file_manager->getFileSystem() + fullpath = file_manager->getFileSystem() ->getAbsolutePath(p).c_str(); GE::getGEConfig()->m_ondemand_load_texture_paths. - insert(fullpath.c_str()); + insert(fullpath); } } #endif @@ -2541,6 +2542,13 @@ void Track::handleSky(const XMLNode &xml_node, const std::string &filename) t->grab(); obj = t; } +#ifndef SERVER_ONLY + if (GE::getDriver()->getDriverType() == video::EDT_VULKAN) + { + GE::getGEConfig()->m_ondemand_load_texture_paths.erase( + fullpath); + } +#endif } if (obj) { diff --git a/src/tracks/track_manager.cpp b/src/tracks/track_manager.cpp index 667cc7ad842..483fbc34341 100644 --- a/src/tracks/track_manager.cpp +++ b/src/tracks/track_manager.cpp @@ -543,5 +543,9 @@ void TrackManager::updateScreenshotCache() GE::getGEConfig()->m_ondemand_load_texture_paths.insert(full_path); #endif irr_driver->getTexture(t->getScreenshotFile()); +#ifndef SERVER_ONLY + if (GE::getDriver()->getDriverType() == video::EDT_VULKAN) + GE::getGEConfig()->m_ondemand_load_texture_paths.erase(full_path); +#endif } } // updateScreenshotCache From 957b10e5ad6ffe36856c50b95a5cf891d612685e Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Sun, 30 Mar 2025 12:20:16 +0800 Subject: [PATCH 643/830] Ignore PBR data in kart textures preloading --- src/karts/kart_properties_manager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/karts/kart_properties_manager.cpp b/src/karts/kart_properties_manager.cpp index 833542f8e02..7f40e0a359b 100644 --- a/src/karts/kart_properties_manager.cpp +++ b/src/karts/kart_properties_manager.cpp @@ -25,6 +25,7 @@ #include "config/stk_config.hpp" #include "config/user_config.hpp" #include "graphics/irr_driver.hpp" +#include "graphics/material_manager.hpp" #include "guiengine/engine.hpp" #include "io/file_manager.hpp" #include "karts/kart_properties.hpp" @@ -753,7 +754,8 @@ void KartPropertiesManager::onDemandLoadKartTextures( { for (auto& dir : ingame_karts_folder) { - if (StringUtils::startsWith(full_path, dir)) + if (StringUtils::startsWith(full_path, dir) && + material_manager->getMaterialFor(tex.second)) { in_use = true; break; From 84d0e3dc62a0bb01cc5f2a79047335ce21496319 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 30 Mar 2025 17:42:27 +0400 Subject: [PATCH 644/830] Make loading screen icons fit ~40% of it (#5383) I don't know how to get the number of icons in advance, nor I can make proper animations, so for now the jump in size is like that. I will add more commits if I find out how. --- src/graphics/irr_driver.cpp | 1 + src/guiengine/engine.cpp | 41 ++++++++++++++++++++++++++- src/guiengine/engine.hpp | 3 ++ src/karts/kart_model.cpp | 2 +- src/karts/kart_properties_manager.cpp | 1 + src/main.cpp | 2 ++ 6 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 6302985ae19..7ed753a3300 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -1140,6 +1140,7 @@ void IrrDriver::applyResolutionSettings(bool recreate_device) // Input manager set first so it recieves SDL joystick event // Re-init GUI engine GUIEngine::init(m_device, m_video_driver, StateManager::get()); + GUIEngine::reserveLoadingIcons(3); // If not recreate device we need to add the previous joystick manually if (!recreate_device) input_manager->addJoystick(); diff --git a/src/guiengine/engine.cpp b/src/guiengine/engine.cpp index 76907f06fac..3c69828e983 100644 --- a/src/guiengine/engine.cpp +++ b/src/guiengine/engine.cpp @@ -1095,6 +1095,9 @@ namespace GUIEngine g_is_no_graphics[PT_CHILD] = false; } // resetGlobalVariables + + int g_expected_icon_count = 0; + // ----------------------------------------------------------------------- void init(IrrlichtDevice* device_a, IVideoDriver* driver_a, AbstractStateManager* state_manager, bool loading) @@ -1103,6 +1106,7 @@ namespace GUIEngine g_device = device_a; g_driver = driver_a; g_state_manager = state_manager; + g_expected_icon_count = 0; for (unsigned int n=0; n int { + int size_with_margin = (icon_size + icon_margin); + int rows = (y_from - text_height * 1.2f) / size_with_margin - 1; + int cols = (screen_w - icon_margin) / size_with_margin; + int max_good_rows = (rows * 4 + 9) / 10; + return max_good_rows * cols; + }; + + int can_have_now = f(icon_size, ICON_MARGIN); + + if (can_have_now < expected_count) + { + int left = ICON_MARGIN; + int right = icon_size; + int mid; + while (right - left > 1) + { + mid = (right + left) / 2; + can_have_now = f(mid, ICON_MARGIN); + if (can_have_now >= expected_count) + left = mid; + else + right = mid; + } + icon_size = left; + } + int x = ICON_MARGIN; int y = y_from - icon_size - ICON_MARGIN - text_height * 1.2f; for (int n=0; n result; file_manager->listFiles(result, *dir); + GUIEngine::reserveLoadingIcons(result.size()); for(std::set::const_iterator subdir=result.begin(); subdir!=result.end(); subdir++) { diff --git a/src/main.cpp b/src/main.cpp index c52e014cfc7..9016c6bb671 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1889,6 +1889,7 @@ void clearGlobalVariables() //============================================================================= void initRest() { + GUIEngine::reserveLoadingIcons(2); SP::setMaxTextureSize(); irr_driver = new IrrDriver(); @@ -2310,6 +2311,7 @@ int main(int argc, char *argv[]) wiimote_manager = new WiimoteManager(); #endif + GUIEngine::reserveLoadingIcons(4); int parent_pid; bool has_parent_process = false; if (CommandLine::has("--parent-process", &parent_pid)) From 58b005fb8def35419f848ac708140d61a09b1b0d Mon Sep 17 00:00:00 2001 From: CodingJellyfish Date: Mon, 31 Mar 2025 20:43:59 +0800 Subject: [PATCH 645/830] Shader Fix Bundle (#5375) * That's hell a lot of fix * More fixes --- data/shaders/IBL.frag | 79 ++++++++++++---------------- data/shaders/pointlight.frag | 6 +-- data/shaders/sp_grass_pass.vert | 2 +- data/shaders/sp_pass.vert | 9 ++-- data/shaders/sp_skinning.vert | 9 ++-- data/shaders/sunlight.frag | 2 +- data/shaders/sunlightshadow.frag | 2 +- data/shaders/sunlightshadowpcss.frag | 8 ++- data/shaders/utils/DiffuseIBL.frag | 2 +- src/graphics/lighting_passes.cpp | 16 +++--- src/graphics/texture_shader.cpp | 25 +++++++-- src/graphics/texture_shader.hpp | 4 +- 12 files changed, 87 insertions(+), 77 deletions(-) diff --git a/data/shaders/IBL.frag b/data/shaders/IBL.frag index 9292a9c9967..2aca7502102 100644 --- a/data/shaders/IBL.frag +++ b/data/shaders/IBL.frag @@ -1,5 +1,6 @@ uniform sampler2D ntex; uniform sampler2D dtex; +uniform sampler2DShadow stex; uniform sampler2D albedo; uniform sampler2D ssao; uniform sampler2D ctex; @@ -13,23 +14,17 @@ out vec4 Spec; #endif #stk_include "utils/decodeNormal.frag" +#stk_include "utils/encode_normal.frag" #stk_include "utils/getPosFromUVDepth.frag" #stk_include "utils/DiffuseIBL.frag" #stk_include "utils/SpecularIBL.frag" -vec3 CalcViewPositionFromDepth(in vec2 uv) +vec3 CalcCoordFromPosition(in vec3 pos) { - // Combine UV & depth into XY & Z (NDC) - float z = texture(dtex, uv).x; - return getPosFromUVDepth(vec3(uv, z), u_inverse_projection_matrix).xyz; -} - -vec2 CalcCoordFromPosition(in vec3 pos) -{ - vec4 projectedCoord = u_projection_matrix * vec4(pos, 1.0); - projectedCoord.xy /= projectedCoord.w; - projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5; - return projectedCoord.xy; + vec4 projectedCoord = u_projection_matrix * vec4(pos, 1.0); + projectedCoord.xyz /= projectedCoord.w; + projectedCoord.xyz = projectedCoord.xyz * 0.5 + 0.5; + return projectedCoord.xyz; } // Fade out edges of screen buffer tex @@ -45,31 +40,22 @@ float GetEdgeFade(vec2 coords) vec2 RayCast(vec3 dir, vec3 hitCoord) { - vec2 projectedCoord; - vec3 dirstep = dir * 0.5f; - float depth; - hitCoord += dirstep; + dir *= 0.5; + hitCoord += dir; - for (int i = 1; i <= 32; i++) - { - projectedCoord = CalcCoordFromPosition(hitCoord); - - float depth = CalcViewPositionFromDepth(projectedCoord).z; + vec3 projectedCoord = CalcCoordFromPosition(hitCoord); + float factor = 1.0; - float directionSign = sign(abs(hitCoord.z) - depth); - dirstep = dirstep * (1.0 - 0.5 * max(directionSign, 0.0)); - hitCoord += dirstep * (-directionSign); - } - - if (projectedCoord.x > 0.0 && projectedCoord.x < 1.0 && - projectedCoord.y > 0.0 && projectedCoord.y < 1.0) - { - return projectedCoord.xy; - } - else + for (int i = 0; i < 32; i++) { - return vec2(0.f); + float direction = texture(stex, projectedCoord); + factor *= direction; + dir = dir * (0.5 + 0.5 * factor); + hitCoord += dir * (2. * direction - 1.); + projectedCoord = CalcCoordFromPosition(hitCoord); } + + return projectedCoord.xy; } vec3 gtaoMultiBounce(float visibility, vec3 albedo) @@ -87,7 +73,7 @@ vec3 gtaoMultiBounce(float visibility, vec3 albedo) void main(void) { vec2 uv = gl_FragCoord.xy / u_screen; - vec3 normal = DecodeNormal(texture(ntex, uv).xy); + vec3 normal = (u_view_matrix * vec4(DecodeNormal(texture(ntex, uv).xy), 0)).xyz; float z = texture(dtex, uv).x; @@ -116,31 +102,34 @@ void main(void) // Fallback (if the ray can't find an intersection we display the sky) vec3 fallback = .25 * SpecularIBL(normal, eyedir, specval); + // Reflection vector + vec3 reflected = reflect(-eyedir, normal); + // Disable raycasts towards camera + float cosine = dot(reflected, eyedir); + // Only calculate reflections if the reflectivity value is high enough, // otherwise just use specular IBL - if (specval > 0.5) - { - // Reflection vector - vec3 reflected = reflect(-eyedir, normal); - + if (specval < 0.5 || cosine > 0.2) { + outColor = fallback; + } else { vec2 coords = RayCast(reflected, xpos.xyz); - if (coords.x == 0.0 && coords.y == 0.0) { + if (coords.x < 0. || coords.x > 1. || coords.y < 0. || coords.y > 1.) { outColor = fallback; } else { - // FIXME We need to generate mipmap to take into account the gloss map + // Disable raycasts onto another reflective surface + float mirror = texture(ntex, coords).z; + outColor = textureLod(albedo, coords, 0.f).rgb; outColor = mix(fallback, outColor, GetEdgeFade(coords)); + outColor = mix(fallback, outColor, 1. - max(cosine * 5., 0.)); + outColor = mix(fallback, outColor, 4. - max(mirror * 4., 3.)); // TODO temporary measure the lack of mipmapping for RTT albedo // Implement it in proper way // Use (specval - 0.5) * 2.0 to bring specval from 0.5-1.0 range to 0.0-1.0 range outColor = mix(fallback, outColor, (specval - 0.5) * 2.0); } } - else - { - outColor = fallback; - } Diff = vec4(0.25 * DiffuseIBL(normal) * ao_multi, 1.); Spec = vec4(outColor.rgb * ao_spec_multi, 1.0); diff --git a/data/shaders/pointlight.frag b/data/shaders/pointlight.frag index 3fc1c063f05..cef44536ad3 100644 --- a/data/shaders/pointlight.frag +++ b/data/shaders/pointlight.frag @@ -27,7 +27,7 @@ void main() { vec2 texc = gl_FragCoord.xy / u_screen; float z = texture(dtex, texc).x; - vec3 norm = DecodeNormal(texture(ntex, texc).xy); + vec3 norm = (u_view_matrix * vec4(DecodeNormal(texture(ntex, texc).xy), 0)).xyz; float roughness = texture(ntex, texc).z; vec4 xpos = getPosFromUVDepth(vec3(texc, z), u_inverse_projection_matrix); @@ -43,7 +43,7 @@ void main() if (att <= 0.) discard; // Light Direction - vec3 L = -normalize(xpos.xyz - light_pos); + vec3 L = (light_pos - xpos.xyz) / d; float NdotL = clamp(dot(norm, L), 0., 1.); vec3 Specular = SpecularBRDF(norm, eyedir, L, vec3(1.), roughness); @@ -51,4 +51,4 @@ void main() Diff = vec4(Diffuse * NdotL * light_col * att, 1.); Spec = vec4(Specular * NdotL * light_col * att, 1.); -} +} \ No newline at end of file diff --git a/data/shaders/sp_grass_pass.vert b/data/shaders/sp_grass_pass.vert index 768932f0855..ce5d0136166 100644 --- a/data/shaders/sp_grass_pass.vert +++ b/data/shaders/sp_grass_pass.vert @@ -35,7 +35,7 @@ void main() i_rotation, i_scale.xyz, i_position); vec3 world_normal = rotateVector(i_rotation, i_normal.xyz); - normal = (u_view_matrix * vec4(world_normal, 0.0)).xyz; + normal = world_normal; uv = i_uv; hue_change = float(i_misc_data.y) * 0.01; gl_Position = u_projection_view_matrix * world_position; diff --git a/data/shaders/sp_pass.vert b/data/shaders/sp_pass.vert index 6f49469c853..63848926b04 100644 --- a/data/shaders/sp_pass.vert +++ b/data/shaders/sp_pass.vert @@ -48,12 +48,9 @@ void main() vec3 v_world_normal = rotateVector(i_rotation, i_normal.xyz); vec3 world_tangent = rotateVector(i_rotation, i_tangent.xyz); - tangent = (u_view_matrix * vec4(world_tangent, 0.0)).xyz; - bitangent = (u_view_matrix * - // bitangent sign - vec4(cross(v_world_normal, world_tangent) * i_tangent.w, 0.0) - ).xyz; - normal = (u_view_matrix * vec4(v_world_normal, 0.0)).xyz; + tangent = world_tangent; + bitangent = cross(v_world_normal, world_tangent) * i_tangent.w; + normal = v_world_normal; uv = vec2(i_uv.x + (i_texture_trans.x * i_normal.w), i_uv.y + (i_texture_trans.y * i_normal.w)); diff --git a/data/shaders/sp_skinning.vert b/data/shaders/sp_skinning.vert index 08d40ee028f..6256434068e 100644 --- a/data/shaders/sp_skinning.vert +++ b/data/shaders/sp_skinning.vert @@ -113,12 +113,9 @@ void main() vec3 world_normal = rotateVector(i_rotation, skinned_normal.xyz); vec3 world_tangent = rotateVector(i_rotation, skinned_tangent.xyz); - tangent = (u_view_matrix * vec4(world_tangent, 0.0)).xyz; - bitangent = (u_view_matrix * - // bitangent sign - vec4(cross(world_normal, world_tangent) * i_tangent.w, 0.0) - ).xyz; - normal = (u_view_matrix * vec4(world_normal, 0.0)).xyz; + tangent = world_tangent; + bitangent = cross(world_normal, world_tangent) * i_tangent.w; + normal = world_normal; uv = vec2(i_uv.x + (i_texture_trans.x * i_normal.w), i_uv.y + (i_texture_trans.y * i_normal.w)); diff --git a/data/shaders/sunlight.frag b/data/shaders/sunlight.frag index 8ad88c32ade..f755acdf683 100644 --- a/data/shaders/sunlight.frag +++ b/data/shaders/sunlight.frag @@ -23,7 +23,7 @@ void main() { float z = texture(dtex, uv).x; vec4 xpos = getPosFromUVDepth(vec3(uv, z), u_inverse_projection_matrix); - vec3 norm = DecodeNormal(texture(ntex, uv).xy); + vec3 norm = (u_view_matrix * vec4(DecodeNormal(texture(ntex, uv).xy), 0)).xyz; float roughness = texture(ntex, uv).z; vec3 eyedir = -normalize(xpos.xyz); diff --git a/data/shaders/sunlightshadow.frag b/data/shaders/sunlightshadow.frag index 55a8ae252b1..3ba827b25a3 100644 --- a/data/shaders/sunlightshadow.frag +++ b/data/shaders/sunlightshadow.frag @@ -106,7 +106,7 @@ void main() { vec3 ddy = dFdy(xpos.xyz); vec3 geo_norm = normalize(cross(ddy, ddx)); - vec3 norm = DecodeNormal(texture(ntex, uv).xy); + vec3 norm = (u_view_matrix * vec4(DecodeNormal(texture(ntex, uv).xy), 0)).xyz; float roughness = texture(ntex, uv).z; vec3 eyedir = -normalize(xpos.xyz); diff --git a/data/shaders/sunlightshadowpcss.frag b/data/shaders/sunlightshadowpcss.frag index 5b288f5ff13..e48a837051a 100644 --- a/data/shaders/sunlightshadowpcss.frag +++ b/data/shaders/sunlightshadowpcss.frag @@ -5,7 +5,13 @@ uniform highp sampler2D dtex; #else uniform sampler2D dtex; #endif + +#if defined(GL_ES) && defined(GL_FRAGMENT_PRECISION_HIGH) +uniform highp sampler2DArray shadowtexdepth; +#else uniform sampler2DArray shadowtexdepth; +#endif + uniform sampler2DArrayShadow shadowtex; uniform float split0; @@ -201,7 +207,7 @@ void main() { float z = texture(dtex, uv).x; vec4 xpos = getPosFromUVDepth(vec3(uv, z), u_inverse_projection_matrix); - vec3 norm = DecodeNormal(texture(ntex, uv).xy); + vec3 norm = (u_view_matrix * vec4(DecodeNormal(texture(ntex, uv).xy), 0)).xyz; float roughness = texture(ntex, uv).z; vec3 eyedir = -normalize(xpos.xyz); diff --git a/data/shaders/utils/DiffuseIBL.frag b/data/shaders/utils/DiffuseIBL.frag index e9ca3974435..c581c9d41a6 100644 --- a/data/shaders/utils/DiffuseIBL.frag +++ b/data/shaders/utils/DiffuseIBL.frag @@ -17,7 +17,7 @@ mat4 getMatrix(float L00, float L1m1, float L10, float L11, float L2m2, float L2 vec3 DiffuseIBL(vec3 normal) { // Convert normal in wobLd space (where SH coordinates were computed) - vec4 extendednormal = transpose(u_view_matrix) * vec4(normal, 0.); + vec4 extendednormal = vec4(normal, 0.); extendednormal.w = 1.; #ifdef UBO_DISABLED diff --git a/src/graphics/lighting_passes.cpp b/src/graphics/lighting_passes.cpp index 76588df5c56..6f0b507d11d 100644 --- a/src/graphics/lighting_passes.cpp +++ b/src/graphics/lighting_passes.cpp @@ -170,7 +170,7 @@ class PointLightScatterShader : public TextureShader +class IBLShader : public TextureShader { public: IBLShader() @@ -180,10 +180,11 @@ class IBLShader : public TextureShader assignUniforms(); assignSamplerNames(0, "ntex", ST_NEAREST_FILTERED, 1, "dtex", ST_NEAREST_FILTERED, - 2, "probe", ST_TRILINEAR_CUBEMAP, - 3, "albedo",ST_NEAREST_FILTERED, - 4, "ssao", ST_NEAREST_FILTERED, - 5, "ctex", ST_NEAREST_FILTERED); + 2, "stex", ST_SHADOW_SAMPLER, + 3, "probe", ST_TRILINEAR_CUBEMAP, + 4, "albedo",ST_NEAREST_FILTERED, + 5, "ssao", ST_NEAREST_FILTERED, + 6, "ctex", ST_NEAREST_FILTERED); } // IBLShader }; // IBLShader @@ -217,7 +218,7 @@ class ShadowedSunLightShaderPCF : public TextureShadersetTextureUnits( normal_depth_texture, depth_stencil_texture, + depth_stencil_texture, specular_probe, albedo_buffer, ssao_texture, diff --git a/src/graphics/texture_shader.cpp b/src/graphics/texture_shader.cpp index 443844cd28e..ed7628b161f 100644 --- a/src/graphics/texture_shader.cpp +++ b/src/graphics/texture_shader.cpp @@ -28,8 +28,9 @@ TextureShaderBase::BindFunction TextureShaderBase::m_all_bind_functions[] = /* ST_TRILINEAR_ANISOTROPIC_FILTERED */ &TextureShaderBase::bindTextureTrilinearAnisotropic, /* ST_TRILINEAR_CUBEMAP */ &TextureShaderBase::bindCubemapTrilinear, /* ST_BILINEAR_FILTERED */ &TextureShaderBase::bindTextureBilinear, - /* ST_NEAREST_FILTERED_ARRAY2D */ &TextureShaderBase::bindTextureNearestArrayTexture, + /* ST_NEAREST_FILTERED_ARRAY2D */ &TextureShaderBase::bindTextureNearestArray, /* ST_SHADOW_SAMPLER */ &TextureShaderBase::bindTextureShadow, + /* ST_SHADOW_SAMPLER_ARRAY2D */ &TextureShaderBase::bindTextureShadowArray, /* ST_TRILINEAR_CLAMPED_ARRAY2D */ &TextureShaderBase::bindTrilinearClampedArrayTexture, /* ST_VOLUME_LINEAR_FILTERED */ &TextureShaderBase::bindTextureVolume, /* ST_NEARED_CLAMPED_FILTERED */ &TextureShaderBase::bindTextureNearestClamped, @@ -44,7 +45,8 @@ GLuint TextureShaderBase::m_all_texture_types[] = /* ST_TRILINEAR_CUBEMAP */ GL_TEXTURE_CUBE_MAP, /* ST_BILINEAR_FILTERED */ GL_TEXTURE_2D , /* ST_NEAREST_FILTERED_ARRAY2D */ GL_TEXTURE_2D_ARRAY, - /* ST_SHADOW_SAMPLER */ GL_TEXTURE_2D_ARRAY, + /* ST_SHADOW_SAMPLER */ GL_TEXTURE_2D, + /* ST_SHADOW_SAMPLER_ARRAY2D */ GL_TEXTURE_2D_ARRAY, /* ST_TRILINEAR_CLAMPED_ARRAY2D */ GL_TEXTURE_2D_ARRAY, /* ST_VOLUME_LINEAR_FILTERED */ GL_TEXTURE_3D, /* ST_NEARED_CLAMPED_FILTERED */ GL_TEXTURE_2D, @@ -171,7 +173,7 @@ void TextureShaderBase::bindTextureSemiTrilinear(GLuint tex_unit, GLuint tex_id) } // bindTextureSemiTrilinear // ---------------------------------------------------------------------------- -void TextureShaderBase::bindTextureNearestArrayTexture(GLuint tex_unit, GLuint tex_id) +void TextureShaderBase::bindTextureNearestArray(GLuint tex_unit, GLuint tex_id) { glActiveTexture(GL_TEXTURE0 + tex_unit); glBindTexture(GL_TEXTURE_2D_ARRAY, tex_id); @@ -185,7 +187,7 @@ void TextureShaderBase::bindTextureNearestArrayTexture(GLuint tex_unit, GLuint t void TextureShaderBase::bindTextureShadow(GLuint tex_unit, GLuint tex_id) { glActiveTexture(GL_TEXTURE0 + tex_unit); - glBindTexture(GL_TEXTURE_2D_ARRAY, tex_id); + glBindTexture(GL_TEXTURE_2D, tex_id); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -194,6 +196,19 @@ void TextureShaderBase::bindTextureShadow(GLuint tex_unit, GLuint tex_id) glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); } // bindTextureShadow + +// ---------------------------------------------------------------------------- +void TextureShaderBase::bindTextureShadowArray(GLuint tex_unit, GLuint tex_id) +{ + glActiveTexture(GL_TEXTURE0 + tex_unit); + glBindTexture(GL_TEXTURE_2D_ARRAY, tex_id); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); +} // bindTextureShadow // ---------------------------------------------------------------------------- void TextureShaderBase::bindTrilinearClampedArrayTexture(unsigned tex_unit, unsigned tex_id) @@ -234,6 +249,7 @@ GLuint TextureShaderBase::createSamplers(SamplerTypeNew sampler_type) switch (sampler_type) { case ST_NEAREST_FILTERED: + case ST_NEAREST_FILTERED_ARRAY2D: return createNearestSampler(); case ST_TRILINEAR_ANISOTROPIC_FILTERED: return createTrilinearSampler(); @@ -242,6 +258,7 @@ GLuint TextureShaderBase::createSamplers(SamplerTypeNew sampler_type) case ST_BILINEAR_FILTERED: return createBilinearSampler(); case ST_SHADOW_SAMPLER: + case ST_SHADOW_SAMPLER_ARRAY2D: return createShadowSampler(); case ST_TRILINEAR_CLAMPED_ARRAY2D: return createTrilinearClampedArray(); diff --git a/src/graphics/texture_shader.hpp b/src/graphics/texture_shader.hpp index 9e7dd059f19..cbb62016167 100644 --- a/src/graphics/texture_shader.hpp +++ b/src/graphics/texture_shader.hpp @@ -39,6 +39,7 @@ enum SamplerTypeNew ST_BILINEAR_FILTERED, ST_NEAREST_FILTERED_ARRAY2D, ST_SHADOW_SAMPLER, + ST_SHADOW_SAMPLER_ARRAY2D, ST_TRILINEAR_CLAMPED_ARRAY2D, ST_VOLUME_LINEAR_FILTERED, ST_NEARED_CLAMPED_FILTERED, @@ -71,8 +72,9 @@ class TextureShaderBase static void bindTextureTrilinearAnisotropic(GLuint tex_unit, GLuint tex_id); static void bindTextureSemiTrilinear(GLuint tex_unit, GLuint tex_id); static void bindCubemapTrilinear(GLuint tex_unit, GLuint tex_id); - static void bindTextureNearestArrayTexture(GLuint tex_unit, GLuint tex_id); + static void bindTextureNearestArray(GLuint tex_unit, GLuint tex_id); static void bindTextureShadow(GLuint tex_unit, GLuint tex_id); + static void bindTextureShadowArray(GLuint tex_unit, GLuint tex_id); static void bindTrilinearClampedArrayTexture(GLuint tex_unit, GLuint tex_id); static void bindTextureVolume(GLuint tex_unit, GLuint tex_id); static void bindTextureBuffer(GLuint tex_unit, GLuint tex_id); From cb66ff69d1228d0bc9c332dfef965654a50dcb76 Mon Sep 17 00:00:00 2001 From: Deve Date: Wed, 2 Apr 2025 22:21:27 +0200 Subject: [PATCH 646/830] More vulkan work --- .../src/ge_vulkan_draw_call.cpp | 64 ++++++++++--------- .../src/ge_vulkan_draw_call.hpp | 9 +-- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index 518b05057b3..cedd0f4fd46 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -273,8 +273,11 @@ void GEVulkanDrawCall::addNode(irr::scene::ISceneNode* node) .emplace_back(dbuffer, node); continue; } - m_visible_nodes[buffer][shader].emplace_back(node, i); - m_mb_map[buffer] = mesh; + const irr::video::SMaterial& m = node->getMaterial(i); + TexturesList t = getTexturesList(m); + std::pair k = std::make_pair(buffer, t); + m_visible_nodes[k][getShader(m)].emplace_back(node, i); + m_mb_map[k] = mesh; if (anode && !added_skinning && !anode->getSkinningMatrices().empty() && m_skinning_nodes.find(anode) == m_skinning_nodes.end()) @@ -301,7 +304,8 @@ void GEVulkanDrawCall::addBillboardNode(irr::scene::ISceneNode* node, m_billboard_buffers[textures] = new GEVulkanBillboardBuffer(m); GESPMBuffer* buffer = m_billboard_buffers.at(textures); const std::string& shader = getShader(node, 0); - m_visible_nodes[buffer][shader].emplace_back(node, + std::pair k = std::make_pair(buffer, textures); + m_visible_nodes[k][shader].emplace_back(node, node_type == irr::scene::ESNT_BILLBOARD ? BILLBOARD_NODE : PARTICLE_NODE); } // addBillboardNode @@ -312,7 +316,7 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) if (!m_visible_nodes.empty() && m_data_layout == VK_NULL_HANDLE) createVulkanData(); - using Nodes = std::pair, std::unordered_map< std::string, std::vector > > >; std::vector visible_nodes; @@ -324,32 +328,32 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) { if (p.second.empty()) { - nodes_area[p.first] = std::numeric_limits::max(); + nodes_area[p.first.first] = std::numeric_limits::max(); continue; } for (auto& q : p.second) { if (q.second.empty()) { - nodes_area[p.first] = std::numeric_limits::max(); + nodes_area[p.first.first] = std::numeric_limits::max(); continue; } - irr::core::aabbox3df bb = p.first->getBoundingBox(); + irr::core::aabbox3df bb = p.first.first->getBoundingBox(); q.second[0].first->getAbsoluteTransformation().transformBoxEx(bb); - nodes_area[p.first] = bb.getArea() * (float)q.second.size(); + nodes_area[p.first.first] = bb.getArea() * (float)q.second.size(); break; } } std::stable_sort(visible_nodes.begin(), visible_nodes.end(), [&nodes_area](const Nodes& a, const Nodes& b) { - return nodes_area.at(a.first) < nodes_area.at(b.first) ; + return nodes_area.at(a.first.first) < nodes_area.at(b.first.first); }); size_t min_size = 0; start: m_cmds.clear(); - m_materials.clear(); + m_dyspmb_materials.clear(); m_materials_data.clear(); m_update_data_descriptor_sets = m_sbo_data->resizeIfNeeded(min_size) || @@ -435,7 +439,7 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) getShader(m)); ObjectData* data = (ObjectData*)mapped_addr; data->init(node, material_id, -1, 0); - m_materials[q.first] = material_id; + m_dyspmb_materials[q.first] = material_id; written_size += dynamic_spm_size; mapped_addr += dynamic_spm_size; } @@ -461,20 +465,18 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) std::unordered_map offset_map; for (auto& p : visible_nodes) { - const irr::video::SMaterial& m = p.first->getMaterial(); - TexturesList textures = getTexturesList(m); + GESPMBuffer* mb = p.first.first; + TexturesList& textures = p.first.second; const irr::video::ITexture** list = &textures[0]; - int material_id = m_texture_descriptor->getTextureID(list, - getShader(m)); - m_materials[p.first] = material_id; - - const bool skinning = p.first->hasSkinning(); + const bool skinning = mb->hasSkinning(); for (auto& q : p.second) { unsigned visible_count = q.second.size(); if (visible_count == 0) continue; std::string cur_shader = q.first; + int material_id = m_texture_descriptor->getTextureID(list, + cur_shader); if (skinning) cur_shader += "_skinning"; if (m_graphics_pipelines.find(cur_shader) == @@ -509,7 +511,7 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) } key.m_nodes.push_back(node); } - irr::scene::IMesh* m = m_mb_map[p.first]; + irr::scene::IMesh* m = m_mb_map[std::make_pair(mb, textures)]; auto& cur_key = instance_keys[m]; auto it = cur_key.end(); if (!skip_instance_key) @@ -606,10 +608,10 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) } } VkDrawIndexedIndirectCommand cmd; - cmd.indexCount = p.first->getIndexCount(); + cmd.indexCount = mb->getIndexCount(); cmd.instanceCount = visible_count; - cmd.firstIndex = use_base_vertex ? p.first->getIBOOffset() : 0; - cmd.vertexOffset = use_base_vertex ? p.first->getVBOOffset() : 0; + cmd.firstIndex = use_base_vertex ? mb->getIBOOffset() : 0; + cmd.vertexOffset = use_base_vertex ? mb->getVBOOffset() : 0; if (skip_instance_key || it == cur_key.end()) { cmd.firstInstance = accumulated_instance; @@ -637,7 +639,7 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) cmd.firstInstance = it->m_first_instance; std::string sorting_key = std::string(1, settings.m_drawing_priority) + cur_shader; - m_cmds.push_back({ cmd, cur_shader, sorting_key, p.first, + m_cmds.push_back({ cmd, cur_shader, sorting_key, mb, material_id, settings.isTransparent(), offset_map[cmd.firstInstance] }); if (!skip_instance_key && it == cur_key.end()) cur_key.push_back(key); @@ -648,7 +650,7 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) std::stable_sort(m_cmds.begin(), m_cmds.end(), [this](const DrawCallData& a, const DrawCallData& b) { - return m_materials[a.m_mb] < m_materials[b.m_mb]; + return a.m_material_id < b.m_material_id; }); } @@ -731,7 +733,7 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) cur_shader = cmd.m_shader; } m_materials_data[cmd.m_shader].second - .push_back(m_materials[cmd.m_mb]); + .push_back(cmd.m_material_id); } auto& material = m_materials_data[m_cmds.back().m_shader]; @@ -1526,7 +1528,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 1, 1, &m_data_descriptor_sets[current_buffer_idx], dynamic_offsets.size(), dynamic_offsets.data()); - int dy_mat = m_materials[buf.first]; + int dy_mat = m_dyspmb_materials[buf.first]; if (dy_mat != cur_mid) { cur_mid = dy_mat; @@ -1542,9 +1544,9 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, } m_dynamic_spm_buffers.erase(it); } - if (cur_mid != m_materials[m_cmds[0].m_mb]) + if (cur_mid != m_cmds[0].m_material_id) { - cur_mid = m_materials[m_cmds[0].m_mb]; + cur_mid = m_cmds[0].m_material_id; vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, 1, &m_texture_descriptor->getDescriptorSet()[cur_mid], 0, NULL); @@ -1580,7 +1582,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 1, 1, &m_data_descriptor_sets[current_buffer_idx], dynamic_offsets.size(), dynamic_offsets.data()); - int dy_mat = m_materials[buf.first]; + int dy_mat = m_dyspmb_materials[buf.first]; if (dy_mat != cur_mid) { cur_mid = dy_mat; @@ -1597,7 +1599,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, m_dynamic_spm_buffers.erase(it); } } - int mid = m_materials[m_cmds[i].m_mb]; + int mid = m_cmds[i].m_material_id; if (cur_mid != mid) { cur_mid = mid; @@ -1654,7 +1656,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, } else { - int dy_mat = m_materials[buf.first]; + int dy_mat = m_dyspmb_materials[buf.first]; if (dy_mat != cur_mid) { cur_mid = dy_mat; diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp index f6be7ba0ccf..7df7d4e8e0b 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp @@ -89,6 +89,7 @@ struct DrawCallData std::string m_shader; std::string m_sorting_key; GESPMBuffer* m_mb; + int m_material_id; bool m_transparent; uint32_t m_dynamic_offset; }; @@ -109,11 +110,11 @@ class GEVulkanDrawCall btQuaternion m_billboard_rotation; - std::unordered_map, std::unordered_map > > > m_visible_nodes; - std::unordered_map m_mb_map; + std::map, irr::scene::IMesh*> m_mb_map; std::map > > @@ -152,7 +153,7 @@ class GEVulkanDrawCall std::unordered_map > m_graphics_pipelines; - std::unordered_map m_materials; + std::unordered_map m_dyspmb_materials; GEVulkanTextureDescriptor* m_texture_descriptor; @@ -248,7 +249,7 @@ class GEVulkanDrawCall m_mb_map.clear(); m_cmds.clear(); m_visible_objects.clear(); - m_materials.clear(); + m_dyspmb_materials.clear(); m_skinning_nodes.clear(); m_materials_data.clear(); m_dynamic_spm_buffers.clear(); From f0a2d6ac4157eea939d9125ea1d81b905fc70ad3 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sun, 6 Apr 2025 14:48:07 +0200 Subject: [PATCH 647/830] Update the changelog and credits - Put Jellyfish in a separate tab due to his substantial number of commits for 1.5 - Add all major changes since the last changelog update - Remove a duplicate changelog entry - Add some missing information about new tracks and track updates in old releases --- CHANGELOG.md | 21 ++++++++++++++++----- data/CREDITS | 10 +++++++--- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc0997b1264..56039c7232a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ For similar reasons, and because some features are vastly more complex than othe ## SuperTuxKart 1.5 +* Fix camera weird transitions when switching views + ### Networking * Improve the track-voting logic when no majority is achieved, by kimden * Prevent tracks missed by spectators from limiting the choice of active players, by kimden @@ -27,11 +29,12 @@ For similar reasons, and because some features are vastly more complex than othe * Fix incorrect unlock information in Story Mode after a Grand Prix, by CodingJellyfish * Make the progression of audio levels geometrical and increase default steps, allowing to set lower audio levels and better accuracy for low audio levels (especially useful for headphone users), by Alayan * Fix drive-on sound from materials being played when the game is paused, by Alayan -* Fix incorrect unlock information in Story Mode after a Grand Prix, by CodingJellyfish * Fix a crash trying to read replays when the random starting position setting is enabled, by Alayan * Handle track names with spaces in the replay reader, by Alayan * Enable smooth scrolling for Irrlicht, by CodingJellyfish * Add launchable tag and use rDNS format for AppData file, by AsciiWolf +* Fix the last lap music sometimes failing to play, and improvements in the last lap music transition, by Alayan +* Tweaks to the camera, by CodingJellyfish * Various build system updates, by deveee, tobbi, ognevny and others * Various compiler fixes, by heirecka, limburgher, nyllet and others * Substantial changes improving code quality, by Alayan and kimden @@ -42,8 +45,11 @@ For similar reasons, and because some features are vastly more complex than othe * Improve the accuracy of the framerate limiter, by Benau * Add more maximum framerate options to the built-in framerate limiter, by Benau * Add some graphical effects for legacy video drivers, by Benau +* Improved animations for the parachute and bubblegum shield, by Semphris * Replace inaccurate normal compression algorithm with Octahedron Normal Vector, by CodingJellyfish -* Fix incorrect Screen-Space Reflection shader, by CodingJellyfish +* Fix the Screen-Space Reflection shader, by CodingJellyfish +* Fix and improve the Screen-Space Ambiant Occlusion shader, by CodingJellyfish +* Implement Percentage-Closer Soft Shadows, by CodingJellyfish * Guarantee an overall bone limit of 2048 for skinned mesh (up from 1024), by CodingJellyfish * Improve Cascaded Shadow Mapping, by CodingJellyfish * Improve the performance of scene node iteration, by CodingJellyfish @@ -51,6 +57,7 @@ For similar reasons, and because some features are vastly more complex than othe * Enable new higher LoD and shadows settings, by Alayan * Integrate LoD (Geometry Detail) settings in the graphics presets, and add a 7th graphics preset, by Alayan * Prefer displaying a lower quality LoD model over switching to a higher quality one when too close, by Alayan +* Allow to run the game's render resolution at higher than native (up to 200%), by Alayan * Remove the distance limit on the display of on-track items (such as gift boxes), by Alayan * Improve image quality on low and medium presets with better anisotropic filtering, by Alayan * Various bugfixes and improvements, by zmike, Icenowy and others @@ -69,6 +76,8 @@ For similar reasons, and because some features are vastly more complex than othe * Generate higher resolution texture for scalable fonts, by CodingJellyfish * Various enhancements, by QwertyChouskie, Nomagno, Nstelt and others + + #### In-race UI * Add color and sound indicators when an elimination is about to happen in Follow-The-Leader, by Alayan * Correctly display the remaining time in FtL when extra-time is added, by Alayan @@ -476,8 +485,8 @@ For similar reasons, and because some features are vastly more complex than othe ### Tracks and modeling #### Tracks * Better support for driving tracks in reverse +* New track layout and improved graphics for Oliver's Math Class, by samuncle * Smaller tweaks and improvements to several tracks including - * Math class * XR591 * Fort Magma * Gran Paradiso Island @@ -517,9 +526,10 @@ For similar reasons, and because some features are vastly more complex than othe * Updated Beastie kart #### Tracks * STK Enterprise by Rubberduck (replace Star Track) +* Redesign of Minigolf, by Rubberduck +* New longer track layout and improved graphics for Lighthouse, by samuncle * Gameplay and graphical updates to several tracks : * The Old Mine - * Lighthouse * Zen Garden #### Miscellaneous * Updated nitro models @@ -535,11 +545,11 @@ For similar reasons, and because some features are vastly more complex than othe #### Tracks * Green Valley by Wolfs (replace Tux Tollway) * Blackhill Mansion by samuncle (replace Crescent Crossing) +* New track layout and improved graphics for Shifting Sands (formerly Sand) * Gameplay and graphical updates to several tracks : * XR591 * Fort Magma * Jungle - * Sand ## SuperTuxKart 0.7.3 (2. November 2011) @@ -558,6 +568,7 @@ For similar reasons, and because some features are vastly more complex than othe * New Suzanne kart #### Tracks * Zen Garden by samuncle (replace Secret Garden) +* Minigolf, by Mac * New Subsea * New Island battle arena #### Miscellaneous diff --git a/data/CREDITS b/data/CREDITS index 1844d141a3b..dcac4446d85 100644 --- a/data/CREDITS +++ b/data/CREDITS @@ -33,7 +33,7 @@ Developer = Jean-Manuel Clémençon (Samuncle) = -Lead graphical artist +Former lead graphical artist - Art work: - Cocoa temple, Grand Paradiso Island, Old Mine - Ravenbridge Mansion, Hacienda, Fort Magma, XR591 @@ -54,6 +54,12 @@ Developer - Android port - General improvements and many many bugfixes += CodingJellyfish = + +Developer +- Many UI tweaks and improvements +- Shader fixes and improvements + = Online = Add-ons website - Daniel Butum (leyyin) @@ -64,7 +70,6 @@ Add-ons website Significant bug fixes & misc. contributions for 1.0 and 1.1 - Ben Krajancic - QwertyChouskie -- CodingJellyfish - Mrxx99 - Pelya - Riso @@ -72,7 +77,6 @@ Significant bug fixes & misc. contributions for 1.0 and 1.1 Significant bug fixes & misc. contributions for 1.2 to 1.5 - QwertyChouskie -- CodingJellyfish - Mary - Luffah - CodedOre From 99d9576344b81731989a8981216fbfbd14e10ab6 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sun, 6 Apr 2025 15:11:40 +0200 Subject: [PATCH 648/830] Fix #5318 - Remove a useless loop - Prevent selecting highscore entries in the track info screen and high score info dialog --- CHANGELOG.md | 2 -- src/states_screens/dialogs/high_score_info_dialog.cpp | 1 + src/states_screens/track_info_screen.cpp | 7 ++----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56039c7232a..8a90c1545e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,6 @@ For similar reasons, and because some features are vastly more complex than othe ## SuperTuxKart 1.5 -* Fix camera weird transitions when switching views - ### Networking * Improve the track-voting logic when no majority is achieved, by kimden * Prevent tracks missed by spectators from limiting the choice of active players, by kimden diff --git a/src/states_screens/dialogs/high_score_info_dialog.cpp b/src/states_screens/dialogs/high_score_info_dialog.cpp index bc6372a724d..037bafb80ed 100644 --- a/src/states_screens/dialogs/high_score_info_dialog.cpp +++ b/src/states_screens/dialogs/high_score_info_dialog.cpp @@ -105,6 +105,7 @@ HighScoreInfoDialog::HighScoreInfoDialog(Highscores* highscore, bool is_linear, icon_bank->setScale(1.5f / 128.0f); icon_bank->setTargetIconSize(128, 128); m_high_score_list->setIcons(icon_bank, 1.5f); + m_high_score_list->setActive(false); // Improve keyboard navigation updateHighscoreEntries(); diff --git a/src/states_screens/track_info_screen.cpp b/src/states_screens/track_info_screen.cpp index f5d699def2d..dcd8e5081db 100644 --- a/src/states_screens/track_info_screen.cpp +++ b/src/states_screens/track_info_screen.cpp @@ -95,11 +95,7 @@ void TrackInfoScreen::loadedFromFile() m_icon_unknown_kart = m_icon_bank->addTextureAsSprite(kart_not_found); m_highscore_label = getWidget("highscores"); - - for (unsigned int i=0;i("highscore_entries"); - } + m_highscore_entries = getWidget("highscore_entries"); GUIEngine::IconButtonWidget* screenshot = getWidget("screenshot"); screenshot->setFocusable(false); @@ -349,6 +345,7 @@ void TrackInfoScreen::init() m_icon_bank->setTargetIconSize(128, 128); m_highscore_entries->setIcons(m_icon_bank, 1.2f); m_highscore_entries->setVisible(has_highscores); + m_highscore_entries->setActive(false); // Improve keyboard navigation updateHighScores(); } //has_highscores From 5a2acb2b797a50af619b2e5faabe0a82dad23f39 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Tue, 8 Apr 2025 23:35:01 +0200 Subject: [PATCH 649/830] Avoid duplicate names when the active player is not the first See issue #5247 --- src/guiengine/widgets/player_kart_widget.cpp | 2 -- src/states_screens/kart_selection.cpp | 7 ++++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/guiengine/widgets/player_kart_widget.cpp b/src/guiengine/widgets/player_kart_widget.cpp index 27b91f4603e..ee8768ce178 100644 --- a/src/guiengine/widgets/player_kart_widget.cpp +++ b/src/guiengine/widgets/player_kart_widget.cpp @@ -69,8 +69,6 @@ PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent, target_h = m_h; // ---- Player identity spinner - m_player_ident_spinner = NULL; - m_player_ident_spinner = new SpinnerWidget(); m_player_ident_spinner->setUseBackgroundColor(); m_player_ident_spinner->setSpinnerWidgetPlayerID(m_player_id); diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index e2de64405a2..cf6025681e5 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -592,7 +592,12 @@ bool KartSelectionScreen::joinPlayer(InputDevice* device, PlayerProfile* p) { // Give each player a different start profile const int num_active_players = StateManager::get()->activePlayerCount(); - profile_to_use = PlayerManager::get()->getPlayer(num_active_players); + // This doesn't check for players having manually changed the name already before adding new names + // But it avoids the game immediately producing a duplicate if the active account is not the 1st + if (PlayerManager::get()->getPlayer(num_active_players) == PlayerManager::getCurrentPlayer()) + profile_to_use = PlayerManager::get()->getPlayer(0); + else + profile_to_use = PlayerManager::get()->getPlayer(num_active_players); removeMultiplayerMessage(); } From 76ac9af6f83a70484a4bef0b7f4da63077f957d7 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 9 Apr 2025 02:38:25 +0400 Subject: [PATCH 650/830] Don't apply ranking 64 times (left from testing) (#5393) Note from maintainer: regression originally introduced in commit 3dbf360 --- src/network/protocols/server_lobby.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index c305d708fb5..3cd2dc8f6cd 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2394,9 +2394,7 @@ void ServerLobby::computeNewRankings() data.push_back(entry); } - for (int i = 0; i < 64; ++i) { - m_ranking->computeNewRankings(data, RaceManager::get()->isTimeTrialMode()); - } + m_ranking->computeNewRankings(data, RaceManager::get()->isTimeTrialMode()); // Used to display rating change at the end of a race m_result_ns->addUInt8((uint8_t)player_count); From 634121ad3176fdfc0f99bb921982509b5e94a52d Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 8 Apr 2025 22:58:23 +0200 Subject: [PATCH 651/830] Enable vulkan synchronization validation --- lib/graphics_engine/src/ge_vulkan_driver.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index daecd0a7565..2d70c8cb48c 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -45,8 +45,10 @@ extern "C" VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data) { - std::string msg = callback_data->pMessage; - if (msg.find("UNASSIGNED-CoreValidation-Shader-OutputNotConsumed") != std::string::npos) + std::string msg = callback_data->pMessageIdName; + msg += " "; + msg += callback_data->pMessage; + if (msg.find("WARNING-Shader-OutputNotConsumed") != std::string::npos) return VK_FALSE; #ifdef __ANDROID__ android_LogPriority alp; @@ -798,10 +800,15 @@ void GEVulkanDriver::createInstance(SDL_Window* window) VkValidationFeaturesEXT validation_features = {}; validation_features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT; - validation_features.enabledValidationFeatureCount = 1; - VkValidationFeatureEnableEXT enabled_validation_features = - VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT; - validation_features.pEnabledValidationFeatures = &enabled_validation_features; + std::array enabled_validation_features = + { + VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT, + VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT + }; + validation_features.pEnabledValidationFeatures = + enabled_validation_features.data(); + validation_features.enabledValidationFeatureCount = + enabled_validation_features.size(); create_info.pNext = &validation_features; extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); From edbafecac668c7eb5170c44aeddb8592d7a286ae Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 8 Apr 2025 23:43:19 +0200 Subject: [PATCH 652/830] Fix vulkan synchronization issues From https://github.com/SaschaWillems/Vulkan/commit/ba8fea35ac27f02b62b4f1aa93ae0c3262ee8852 and https://github.com/Overv/VulkanTutorial/commit/dc02dccc6253ebec5d031debceee583f71109bb5 --- lib/graphics_engine/src/ge_vulkan_driver.cpp | 10 ++++++---- lib/graphics_engine/src/ge_vulkan_fbo_texture.cpp | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index 2d70c8cb48c..faef674f1f6 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -1560,13 +1560,15 @@ void GEVulkanDriver::createRenderPass() dependency.dstSubpass = 0; dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; if (m_depth_texture) - dependency.srcStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.srcAccessMask = 0; + dependency.srcStageMask |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + if (m_depth_texture) + dependency.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + else + dependency.srcAccessMask = 0; dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; if (m_depth_texture) dependency.dstStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; if (m_depth_texture) dependency.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; diff --git a/lib/graphics_engine/src/ge_vulkan_fbo_texture.cpp b/lib/graphics_engine/src/ge_vulkan_fbo_texture.cpp index ba9cc673bda..3e4c27c48ee 100644 --- a/lib/graphics_engine/src/ge_vulkan_fbo_texture.cpp +++ b/lib/graphics_engine/src/ge_vulkan_fbo_texture.cpp @@ -99,7 +99,8 @@ void GEVulkanFBOTexture::createRTT() dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT; dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; @@ -109,7 +110,8 @@ void GEVulkanFBOTexture::createRTT() dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; From db8585f55074005ebe512bd2ba00cc4c989d3b50 Mon Sep 17 00:00:00 2001 From: Deve Date: Wed, 9 Apr 2025 21:14:04 +0200 Subject: [PATCH 653/830] Fix pbr with rotated preTransform --- .../utils/get_pos_from_frag_coord.glsl | 10 +++++----- .../src/ge_vulkan_camera_scene_node.cpp | 18 ++++++++++++++---- .../src/ge_vulkan_scene_manager.cpp | 5 +++-- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/data/shaders/ge_shaders/utils/get_pos_from_frag_coord.glsl b/data/shaders/ge_shaders/utils/get_pos_from_frag_coord.glsl index 3153f6cadce..cbf2f3e3e3b 100644 --- a/data/shaders/ge_shaders/utils/get_pos_from_frag_coord.glsl +++ b/data/shaders/ge_shaders/utils/get_pos_from_frag_coord.glsl @@ -1,8 +1,8 @@ vec3 getPosFromFragCoord(vec4 frag_coord, vec4 viewport, mat4 inverse_projection_matrix) { - return vec3( - ((frag_coord.x - viewport.x) / viewport.z * 2.0 - 1.0) * inverse_projection_matrix[0][0], - ((frag_coord.y - viewport.y) / viewport.w * 2.0 - 1.0) * inverse_projection_matrix[1][1], - inverse_projection_matrix[3][2] - ) / frag_coord.w; + vec2 ndc = vec2((frag_coord.x - viewport.x) / viewport.z * 2.0 - 1.0, + (frag_coord.y - viewport.y) / viewport.w * 2.0 - 1.0); + vec4 clip = vec4(ndc, 1.0, 1.0); + vec4 view_space = inverse_projection_matrix * clip; + return view_space.xyz / frag_coord.w; } diff --git a/lib/graphics_engine/src/ge_vulkan_camera_scene_node.cpp b/lib/graphics_engine/src/ge_vulkan_camera_scene_node.cpp index 3f38f3ebc52..53a7a09442e 100644 --- a/lib/graphics_engine/src/ge_vulkan_camera_scene_node.cpp +++ b/lib/graphics_engine/src/ge_vulkan_camera_scene_node.cpp @@ -58,10 +58,20 @@ void GEVulkanCameraSceneNode::render() m_ubo_data.m_projection_view_matrix.getInverse( m_ubo_data.m_inverse_projection_view_matrix); - m_ubo_data.m_viewport.UpperLeftCorner.X = m_viewport.UpperLeftCorner.X; - m_ubo_data.m_viewport.UpperLeftCorner.Y = m_viewport.UpperLeftCorner.Y; - m_ubo_data.m_viewport.LowerRightCorner.X = m_viewport.getWidth(); - m_ubo_data.m_viewport.LowerRightCorner.Y = m_viewport.getHeight(); + VkViewport vp = {}; + float scale = getGEConfig()->m_render_scale; + if (vk->getSeparateRTTTexture()) + scale = 1.0f; + vp.x = m_viewport.UpperLeftCorner.X * scale; + vp.y = m_viewport.UpperLeftCorner.Y * scale; + vp.width = m_viewport.getWidth() * scale; + vp.height = m_viewport.getHeight() * scale; + vk->getRotatedViewport(&vp, true/*handle_rtt*/); + + m_ubo_data.m_viewport.UpperLeftCorner.X = vp.x; + m_ubo_data.m_viewport.UpperLeftCorner.Y = vp.y; + m_ubo_data.m_viewport.LowerRightCorner.X = vp.width; + m_ubo_data.m_viewport.LowerRightCorner.Y = vp.height; } // render // ---------------------------------------------------------------------------- diff --git a/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp b/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp index 36b8c97545a..b3ff5623139 100644 --- a/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp +++ b/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp @@ -196,6 +196,9 @@ void GEVulkanSceneManager::drawAll(irr::u32 flags) GEVulkanCameraSceneNode* cam = static_cast< GEVulkanCameraSceneNode*>(getActiveCamera()); std::unique_ptr& dc = m_draw_calls.at(cam); + cam->setViewPort( + core::recti(0, 0, rtt->getSize().Width, rtt->getSize().Height)); + cam->render(); dc->uploadDynamicData(vk, cam, cmd); VkRenderPassBeginInfo render_pass_info = {}; @@ -209,8 +212,6 @@ void GEVulkanSceneManager::drawAll(irr::u32 flags) render_pass_info.pClearValues = &clear_values[0]; vkCmdBeginRenderPass(cmd, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); - cam->setViewPort( - core::recti(0, 0, rtt->getSize().Width, rtt->getSize().Height)); dc->render(vk, cam, cmd); vk->addRTTPolyCount(dc->getPolyCount()); dc->reset(); From 0f6dbc741a455bb363427d5d3b3cd1637b8f13b9 Mon Sep 17 00:00:00 2001 From: Deve Date: Thu, 10 Apr 2025 21:50:23 +0200 Subject: [PATCH 654/830] Remove duplicated code in GEVulkanSkyBoxRenderer --- data/shaders/ge_shaders/skybox.frag | 11 +- .../include/ge_vulkan_driver.hpp | 4 + .../src/ge_vulkan_draw_call.cpp | 87 +++- .../src/ge_vulkan_draw_call.hpp | 12 +- lib/graphics_engine/src/ge_vulkan_driver.cpp | 14 +- .../src/ge_vulkan_scene_manager.cpp | 3 +- .../src/ge_vulkan_skybox_renderer.cpp | 399 ++++-------------- .../src/ge_vulkan_skybox_renderer.hpp | 38 +- 8 files changed, 214 insertions(+), 354 deletions(-) diff --git a/data/shaders/ge_shaders/skybox.frag b/data/shaders/ge_shaders/skybox.frag index 563d975cb18..70f699f24c0 100644 --- a/data/shaders/ge_shaders/skybox.frag +++ b/data/shaders/ge_shaders/skybox.frag @@ -1,18 +1,15 @@ -layout(push_constant) uniform Constants -{ - mat4 m_inverse_projection_view_matrix; -} u_push_constants; - layout(location = 0) in vec2 f_uv; layout(binding = 0) uniform samplerCube f_skybox_texture; layout(location = 0) out vec4 o_color; +#include "utils/camera.glsl" + void main() { vec2 uv = 2.0f * f_uv - 1.0f; - vec4 front = u_push_constants.m_inverse_projection_view_matrix * vec4(uv, -1.0, 1.0); - vec4 back = u_push_constants.m_inverse_projection_view_matrix * vec4(uv, 1.0, 1.0); + vec4 front = u_camera.m_inverse_projection_view_matrix * vec4(uv, -1.0, 1.0); + vec4 back = u_camera.m_inverse_projection_view_matrix * vec4(uv, 1.0, 1.0); vec3 dir = back.xyz / back.w - front.xyz / front.w; o_color = texture(f_skybox_texture, dir); } diff --git a/lib/graphics_engine/include/ge_vulkan_driver.hpp b/lib/graphics_engine/include/ge_vulkan_driver.hpp index cdc87eb31b1..69b26b2ecd4 100644 --- a/lib/graphics_engine/include/ge_vulkan_driver.hpp +++ b/lib/graphics_engine/include/ge_vulkan_driver.hpp @@ -30,6 +30,7 @@ namespace GE class GEVulkanDynamicSPMBuffer; class GEVulkanFBOTexture; class GEVulkanMeshCache; + class GEVulkanSkyBoxRenderer; class GEVulkanTextureDescriptor; enum GEVulkanSampler : unsigned { @@ -355,6 +356,8 @@ namespace GE VkFormatFeatureFlags features); VmaAllocator getVmaAllocator() const { return m_vk->allocator; } GEVulkanMeshCache* getVulkanMeshCache() const; + GEVulkanSkyBoxRenderer* getSkyBoxRenderer() const + { return m_skybox_renderer; } GEVulkanTextureDescriptor* getMeshTextureDescriptor() const { return m_mesh_texture_descriptor; } GEVulkanFBOTexture* getRTTTexture() const { return m_rtt_texture; } @@ -508,6 +511,7 @@ namespace GE IrrlichtDevice* m_irrlicht_device; GEVulkanDepthTexture* m_depth_texture; + GEVulkanSkyBoxRenderer* m_skybox_renderer; GEVulkanTextureDescriptor* m_mesh_texture_descriptor; GEVulkanFBOTexture* m_rtt_texture; GEVulkanFBOTexture* m_prev_rtt_texture; diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index cedd0f4fd46..54c5b959b64 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -211,6 +211,8 @@ GEVulkanDrawCall::GEVulkanDrawCall() m_data_layout = VK_NULL_HANDLE; m_descriptor_pool = VK_NULL_HANDLE; m_pipeline_layout = VK_NULL_HANDLE; + m_skybox_layout = VK_NULL_HANDLE; + m_skybox_renderer = NULL; m_texture_descriptor = getVKDriver()->getMeshTextureDescriptor(); } // GEVulkanDrawCall @@ -230,6 +232,7 @@ GEVulkanDrawCall::~GEVulkanDrawCall() for (auto& p : m_graphics_pipelines) vkDestroyPipeline(vk->getDevice(), p.second.first, NULL); vkDestroyPipelineLayout(vk->getDevice(), m_pipeline_layout, NULL); + vkDestroyPipelineLayout(vk->getDevice(), m_skybox_layout, NULL); } } // ~GEVulkanDrawCall @@ -909,6 +912,17 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) settings.m_shader_name = "additive"; settings.m_drawing_priority = (char)11; createPipeline(vk, settings); + + settings.m_alphablend = false; + settings.m_additive = false; + settings.m_fs_quad_pl = m_skybox_layout; + settings.m_backface_culling = true; + settings.m_skinning_vertex_shader = ""; + settings.m_vertex_shader = "fullscreen_quad.vert"; + settings.m_fragment_shader = "skybox.frag"; + settings.m_shader_name = "skybox"; + createPipeline(vk, settings); + } // createAllPipelines // ---------------------------------------------------------------------------- @@ -985,10 +999,13 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input_info.vertexBindingDescriptionCount = 2; - vertex_input_info.vertexAttributeDescriptionCount = 8; - vertex_input_info.pVertexBindingDescriptions = binding_descriptions.data(); - vertex_input_info.pVertexAttributeDescriptions = attribute_descriptions.data(); + if (settings.m_fs_quad_pl == VK_NULL_HANDLE) + { + vertex_input_info.vertexBindingDescriptionCount = 2; + vertex_input_info.vertexAttributeDescriptionCount = 8; + vertex_input_info.pVertexBindingDescriptions = binding_descriptions.data(); + vertex_input_info.pVertexAttributeDescriptions = attribute_descriptions.data(); + } VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; @@ -1034,7 +1051,8 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depth_stencil.depthTestEnable = settings.m_depth_test; depth_stencil.depthWriteEnable = settings.m_depth_write; - depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS; + depth_stencil.depthCompareOp = settings.m_fs_quad_pl == VK_NULL_HANDLE ? + VK_COMPARE_OP_LESS : VK_COMPARE_OP_EQUAL; depth_stencil.depthBoundsTestEnable = VK_FALSE; depth_stencil.stencilTestEnable = VK_FALSE; @@ -1095,7 +1113,8 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, pipeline_info.pDepthStencilState = &depth_stencil; pipeline_info.pColorBlendState = &color_blending; pipeline_info.pDynamicState = &dynamic_state_info; - pipeline_info.layout = m_pipeline_layout; + pipeline_info.layout = settings.m_fs_quad_pl == VK_NULL_HANDLE ? + m_pipeline_layout : settings.m_fs_quad_pl; pipeline_info.renderPass = vk->getRTTTexture() ? vk->getRTTTexture()->getRTTRenderPass() : vk->getRenderPass(); pipeline_info.subpass = 0; @@ -1257,7 +1276,20 @@ void GEVulkanDrawCall::createVulkanData() NULL, &m_pipeline_layout); if (result != VK_SUCCESS) - throw std::runtime_error("vkCreatePipelineLayout failed"); + { + throw std::runtime_error( + "vkCreatePipelineLayout failed for m_pipeline_layout"); + } + + all_layouts[0] = vk->getSkyBoxRenderer()->getDescriptorSetLayout(); + result = vkCreatePipelineLayout(vk->getDevice(), &pipeline_layout_info, + NULL, &m_skybox_layout); + + if (result != VK_SUCCESS) + { + throw std::runtime_error( + "vkCreatePipelineLayout failed for m_skybox_layout"); + } createAllPipelines(vk); @@ -1471,7 +1503,12 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, if (m_cmds[i].m_transparent && !drawn_skybox) { drawn_skybox = true; - GEVulkanSkyBoxRenderer::render(cmd, cam); + drawSkyBox(cmd, current_buffer_idx, dynamic_offsets); + + vkCmdBindDescriptorSets(cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, + 1, 1, &m_data_descriptor_sets[current_buffer_idx], + dynamic_offsets.size(), dynamic_offsets.data()); vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, @@ -1557,7 +1594,12 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, if (m_cmds[i].m_transparent && !drawn_skybox) { drawn_skybox = true; - GEVulkanSkyBoxRenderer::render(cmd, cam); + drawSkyBox(cmd, current_buffer_idx, dynamic_offsets); + + vkCmdBindDescriptorSets(cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, + 1, 1, &m_data_descriptor_sets[current_buffer_idx], + dynamic_offsets.size(), dynamic_offsets.data()); vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, 1, @@ -1634,7 +1676,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, } } if (!drawn_skybox) - GEVulkanSkyBoxRenderer::render(cmd, cam); + drawSkyBox(cmd, current_buffer_idx, dynamic_offsets); for (auto& p : m_dynamic_spm_buffers) { bindPipeline(cmd, getShaderFromKey(p.first)); @@ -1795,4 +1837,29 @@ void GEVulkanDrawCall::updateDataDescriptorSets(GEVulkanDriver* vk) data_set.data(), 0, NULL); } } // updateDataDescriptor + +// ---------------------------------------------------------------------------- +void GEVulkanDrawCall::addSkyBox(scene::ISceneNode* node) +{ + m_skybox_renderer = getVKDriver()->getSkyBoxRenderer(); + m_skybox_renderer->addSkyBox(node); +} // addSkyBox + +// ---------------------------------------------------------------------------- +void GEVulkanDrawCall::drawSkyBox(VkCommandBuffer cmd, int current_buffer_idx, + std::vector& dynamic_offsets) +{ + if (!m_skybox_renderer) + return; + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + m_graphics_pipelines["skybox"].first); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + m_skybox_layout, 0, 1, m_skybox_renderer->getDescriptorSet(), 0, NULL); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + m_skybox_layout, + 1, 1, &m_data_descriptor_sets[current_buffer_idx], + dynamic_offsets.size(), dynamic_offsets.data()); + vkCmdDraw(cmd, 3, 1, 0, 0); +} // drawSkyBox + } diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp index 7df7d4e8e0b..7af76009d87 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp @@ -37,6 +37,7 @@ class GEVulkanCameraSceneNode; class GEVulkanDriver; class GEVulkanDynamicBuffer; class GEVulkanDynamicSPMBuffer; +class GEVulkanSkyBoxRenderer; class GEVulkanTextureDescriptor; struct ObjectData @@ -79,6 +80,7 @@ struct PipelineSettings bool m_depth_write; char m_drawing_priority; std::function m_push_constants_func; + VkPipelineLayout m_fs_quad_pl; bool isTransparent() const { return m_alphablend || m_additive; } }; @@ -148,13 +150,15 @@ class GEVulkanDrawCall std::vector m_data_descriptor_sets; - VkPipelineLayout m_pipeline_layout; + VkPipelineLayout m_pipeline_layout, m_skybox_layout; std::unordered_map > m_graphics_pipelines; std::unordered_map m_dyspmb_materials; + GEVulkanSkyBoxRenderer* m_skybox_renderer; + GEVulkanTextureDescriptor* m_texture_descriptor; std::unordered_set m_skinning_nodes; @@ -214,6 +218,9 @@ class GEVulkanDrawCall // ------------------------------------------------------------------------ std::string getShaderFromKey(const std::string& key) const { return key.substr(2); } + // ------------------------------------------------------------------------ + void drawSkyBox(VkCommandBuffer cmd, int current_buffer_idx, + std::vector& dynamic_offsets); public: // ------------------------------------------------------------------------ GEVulkanDrawCall(); @@ -253,7 +260,10 @@ class GEVulkanDrawCall m_skinning_nodes.clear(); m_materials_data.clear(); m_dynamic_spm_buffers.clear(); + m_skybox_renderer = NULL; } + // ------------------------------------------------------------------------ + void addSkyBox(irr::scene::ISceneNode* node); }; // GEVulkanDrawCall } diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index faef674f1f6..bb35dc43935 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -504,10 +504,11 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params, IrrlichtDevice* device) : CNullDriver(io, core::dimension2d(0, 0)), m_params(params), m_irrlicht_device(device), - m_depth_texture(NULL), m_mesh_texture_descriptor(NULL), - m_rtt_texture(NULL), m_prev_rtt_texture(NULL), - m_separate_rtt_texture(NULL), m_rtt_polycount(0), - m_billboard_quad(NULL), m_current_buffer_idx(0) + m_depth_texture(NULL), m_skybox_renderer(NULL), + m_mesh_texture_descriptor(NULL), m_rtt_texture(NULL), + m_prev_rtt_texture(NULL), m_separate_rtt_texture(NULL), + m_rtt_polycount(0), m_billboard_quad(NULL), + m_current_buffer_idx(0) { m_vk.reset(new VK()); m_physical_device = VK_NULL_HANDLE; @@ -640,7 +641,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params, GE::setVideoDriver(this); createUnicolorTextures(); GEVulkan2dRenderer::init(this); - GEVulkanSkyBoxRenderer::init(); + m_skybox_renderer = new GEVulkanSkyBoxRenderer(); m_mesh_texture_descriptor = new GEVulkanTextureDescriptor( GEVulkanShaderManager::getSamplerSize(), GEVulkanShaderManager::getMeshTextureLayer(), @@ -703,7 +704,7 @@ void GEVulkanDriver::destroyVulkan() m_irrlicht_device->getSceneManager()->getMeshCache()) getVulkanMeshCache()->destroy(); delete m_mesh_texture_descriptor; - GEVulkanSkyBoxRenderer::destroy(); + delete m_skybox_renderer; GEVulkan2dRenderer::destroy(); GEVulkanShaderManager::destroy(); @@ -2555,7 +2556,6 @@ void GEVulkanDriver::updateDriver(bool pbr_changed) for (auto& dc : static_cast( m_irrlicht_device->getSceneManager())->getDrawCalls()) dc.second = std::unique_ptr(new GEVulkanDrawCall); - GEVulkanSkyBoxRenderer::destroy(); GEVulkan2dRenderer::destroy(); GEVulkan2dRenderer::init(this); setDisableWaitIdle(false); diff --git a/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp b/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp index b3ff5623139..72b7bb55822 100644 --- a/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp +++ b/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp @@ -42,7 +42,6 @@ void GEVulkanSceneManager::clear() irr::scene::CSceneManager::clear(); static_cast(getVideoDriver()) ->getMeshTextureDescriptor()->clear(); - GEVulkanSkyBoxRenderer::destroy(); } // clear // ---------------------------------------------------------------------------- @@ -235,7 +234,7 @@ irr::u32 GEVulkanSceneManager::registerNodeForRendering( if (node->getType() == irr::scene::ESNT_SKY_BOX) { - GEVulkanSkyBoxRenderer::addSkyBox(cam, node); + m_draw_calls.at(cam)->addSkyBox(node); return 1; } diff --git a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp index 82977f00785..fd4962f6183 100644 --- a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp +++ b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp @@ -1,186 +1,23 @@ #include "ge_vulkan_skybox_renderer.hpp" #include "ge_main.hpp" -#include "ge_vma.hpp" #include "ge_vulkan_array_texture.hpp" -#include "ge_vulkan_camera_scene_node.hpp" #include "ge_vulkan_driver.hpp" -#include "ge_vulkan_features.hpp" -#include "ge_vulkan_fbo_texture.hpp" -#include "ge_vulkan_shader_manager.hpp" #include #include #include -#include -#include namespace GE { -namespace GEVulkanSkyBoxRenderer -{ -// ============================================================================ -irr::scene::ISceneNode* g_skybox = NULL; -std::unordered_map g_render_skybox; - -GEVulkanArrayTexture* g_texture_cubemap = NULL; -bool g_updated_texture_descriptor = false; - -VkDescriptorSetLayout g_descriptor_layout = VK_NULL_HANDLE; -VkDescriptorPool g_descriptor_pool = VK_NULL_HANDLE; -VkDescriptorSet g_descriptor_set = VK_NULL_HANDLE; -VkPipelineLayout g_pipeline_layout = VK_NULL_HANDLE; -VkPipeline g_graphics_pipeline = VK_NULL_HANDLE; -} // GEVulkanSkyBoxRenderer - -// ============================================================================ -void GEVulkanSkyBoxRenderer::init() -{ - g_skybox = NULL; - g_render_skybox.clear(); - g_descriptor_layout = VK_NULL_HANDLE; - g_descriptor_pool = VK_NULL_HANDLE; - g_descriptor_set = VK_NULL_HANDLE; - g_pipeline_layout = VK_NULL_HANDLE; - g_graphics_pipeline = VK_NULL_HANDLE; - g_updated_texture_descriptor = true; -} // init - // ---------------------------------------------------------------------------- -void GEVulkanSkyBoxRenderer::destroy() +GEVulkanSkyBoxRenderer::GEVulkanSkyBoxRenderer() { - GEVulkanDriver* vk = getVKDriver(); - if (!vk) - return; - vk->waitIdle(); - - if (g_texture_cubemap != NULL) - { - g_texture_cubemap->drop(); - g_texture_cubemap = NULL; - } - - if (g_graphics_pipeline != VK_NULL_HANDLE) - vkDestroyPipeline(vk->getDevice(), g_graphics_pipeline, NULL); - g_graphics_pipeline = VK_NULL_HANDLE; - - if (g_pipeline_layout != VK_NULL_HANDLE) - vkDestroyPipelineLayout(vk->getDevice(), g_pipeline_layout, NULL); - g_pipeline_layout = VK_NULL_HANDLE; - - if (g_descriptor_pool != VK_NULL_HANDLE) - vkDestroyDescriptorPool(vk->getDevice(), g_descriptor_pool, NULL); - g_descriptor_pool = VK_NULL_HANDLE; - - if (g_descriptor_layout != VK_NULL_HANDLE) - { - vkDestroyDescriptorSetLayout(vk->getDevice(), g_descriptor_layout, - NULL); - } - g_descriptor_layout = VK_NULL_HANDLE; - - g_descriptor_set = VK_NULL_HANDLE; - g_skybox = NULL; - g_render_skybox.clear(); - g_updated_texture_descriptor = true; -} // destroy - -// ---------------------------------------------------------------------------- -void GEVulkanSkyBoxRenderer::render(VkCommandBuffer cmd, - GEVulkanCameraSceneNode* cam) -{ - if (g_render_skybox.find(cam) == g_render_skybox.end() || - !g_render_skybox.at(cam)) - return; - g_render_skybox.at(cam) = false; - - if (!g_updated_texture_descriptor) - { - g_updated_texture_descriptor = true; - - GEVulkanDriver* vk = getVKDriver(); - VkDescriptorImageInfo info; - info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - info.sampler = vk->getSampler(GVS_SKYBOX); - info.imageView = (VkImageView)g_texture_cubemap->getTextureHandler(); - - VkWriteDescriptorSet write_descriptor_set = {}; - write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptor_set.dstBinding = 0; - write_descriptor_set.dstArrayElement = 0; - write_descriptor_set.descriptorType = - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - write_descriptor_set.descriptorCount = 1; - write_descriptor_set.pBufferInfo = 0; - write_descriptor_set.dstSet = g_descriptor_set; - write_descriptor_set.pImageInfo = &info; - - vkUpdateDescriptorSets(vk->getDevice(), 1, &write_descriptor_set, 0, - NULL); - } - - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, g_graphics_pipeline); - - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - g_pipeline_layout, 0, 1, &g_descriptor_set, 0, NULL); - - vkCmdPushConstants(cmd, g_pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, - sizeof(irr::core::matrix4), - cam->getUBOData()->m_inverse_projection_view_matrix.pointer()); - - vkCmdDraw(cmd, 3, 1, 0, 0); -} // render - -// ---------------------------------------------------------------------------- -void GEVulkanSkyBoxRenderer::addSkyBox(GEVulkanCameraSceneNode* cam, - irr::scene::ISceneNode* skybox) -{ - if (skybox->getType() != irr::scene::ESNT_SKY_BOX) - return; - if (g_skybox == skybox) - { - g_render_skybox[cam] = true; - return; - } - - destroy(); - std::vector sky_tex; - std::array order = {{ 1, 3, 4, 5, 2, 0}}; - - for (unsigned i = 0; i < 6; i++) - { - video::ITexture* tex = skybox->getMaterial(order[i]).getTexture(0); - if (!tex) - return; - sky_tex.push_back(static_cast(tex)); - } - - auto swap_pixels = [](video::IImage* img, unsigned idx) - { - if (!(idx == 2 || idx == 3)) - return; - unsigned width = img->getDimension().Width; - uint8_t* tmp = new uint8_t[width * width * 4]; - uint32_t* tmp_array = (uint32_t*)tmp; - uint32_t* img_data = (uint32_t*)img->lock(); - for (unsigned i = 0; i < width; i++) - { - for (unsigned j = 0; j < width; j++) - tmp_array[j * width + i] = img_data[i * width + (width - j - 1)]; - } - uint8_t* u8_data = (uint8_t*)img->lock(); - delete [] u8_data; - img->setMemory(tmp); - }; - g_texture_cubemap = new GEVulkanArrayTexture(sky_tex, - VK_IMAGE_VIEW_TYPE_CUBE, swap_pixels); - g_updated_texture_descriptor = false; + m_skybox = NULL; + m_texture_cubemap = NULL; - g_skybox = skybox; - g_render_skybox[cam] = true; GEVulkanDriver* vk = getVKDriver(); - - // g_descriptor_layout + // m_descriptor_layout VkDescriptorSetLayoutBinding texture_layout_binding; texture_layout_binding.binding = 0; texture_layout_binding.descriptorCount = 1; @@ -195,13 +32,13 @@ void GEVulkanSkyBoxRenderer::addSkyBox(GEVulkanCameraSceneNode* cam, setinfo.pBindings = &texture_layout_binding; setinfo.bindingCount = 1; if (vkCreateDescriptorSetLayout(vk->getDevice(), &setinfo, - NULL, &g_descriptor_layout) != VK_SUCCESS) + NULL, &m_descriptor_layout) != VK_SUCCESS) { throw std::runtime_error("vkCreateDescriptorSetLayout failed for " - "addSkyBox"); + "GEVulkanSkyBoxRenderer"); } - // g_descriptor_pool + // m_descriptor_pool VkDescriptorPoolSize pool_size; pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; pool_size.descriptorCount = 1; @@ -213,175 +50,105 @@ void GEVulkanSkyBoxRenderer::addSkyBox(GEVulkanCameraSceneNode* cam, pool_info.poolSizeCount = 1; pool_info.pPoolSizes = &pool_size; if (vkCreateDescriptorPool(vk->getDevice(), &pool_info, NULL, - &g_descriptor_pool) != VK_SUCCESS) + &m_descriptor_pool) != VK_SUCCESS) { throw std::runtime_error("vkCreateDescriptorPool failed for " - "addSkyBox"); + "GEVulkanSkyBoxRenderer"); } - // g_descriptor_set - std::vector layouts(1, g_descriptor_layout); + // m_descriptor_set + std::vector layouts(1, m_descriptor_layout); VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = g_descriptor_pool; + alloc_info.descriptorPool = m_descriptor_pool; alloc_info.descriptorSetCount = layouts.size(); alloc_info.pSetLayouts = layouts.data(); if (vkAllocateDescriptorSets(vk->getDevice(), &alloc_info, - &g_descriptor_set) != VK_SUCCESS) + &m_descriptor_set) != VK_SUCCESS) { throw std::runtime_error("vkAllocateDescriptorSets failed for " - "addSkyBox"); + "GEVulkanSkyBoxRenderer"); } +} // init +// ---------------------------------------------------------------------------- +GEVulkanSkyBoxRenderer::~GEVulkanSkyBoxRenderer() +{ + GEVulkanDriver* vk = getVKDriver(); + if (!vk) + return; + vk->waitIdle(); - // g_pipeline_layout - VkPipelineLayoutCreateInfo pipeline_layout_info = {}; - pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipeline_layout_info.setLayoutCount = 1; - pipeline_layout_info.pSetLayouts = &g_descriptor_layout; + if (m_texture_cubemap != NULL) + m_texture_cubemap->drop(); + vkDestroyDescriptorPool(vk->getDevice(), m_descriptor_pool, NULL); + vkDestroyDescriptorSetLayout(vk->getDevice(), m_descriptor_layout, + NULL); +} // ~GEVulkanSkyBoxRenderer - VkPushConstantRange push_constant; - push_constant.offset = 0; - push_constant.size = sizeof(irr::core::matrix4); - push_constant.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - pipeline_layout_info.pPushConstantRanges = &push_constant; - pipeline_layout_info.pushConstantRangeCount = 1; +// ---------------------------------------------------------------------------- +void GEVulkanSkyBoxRenderer::addSkyBox(irr::scene::ISceneNode* skybox) +{ + if (skybox->getType() != irr::scene::ESNT_SKY_BOX) + return; + if (m_skybox == skybox) + return; + + m_skybox = skybox; + std::vector sky_tex; + std::array order = {{ 1, 3, 4, 5, 2, 0}}; - if (vkCreatePipelineLayout(vk->getDevice(), &pipeline_layout_info, - NULL, &g_pipeline_layout) != VK_SUCCESS) + for (unsigned i = 0; i < 6; i++) { - throw std::runtime_error("vkCreatePipelineLayout failed for " - "addSkyBox"); + video::ITexture* tex = skybox->getMaterial(order[i]).getTexture(0); + if (!tex) + return; + sky_tex.push_back(static_cast(tex)); } - // g_graphics_pipeline - VkPipelineShaderStageCreateInfo vert_shader_stage_info = {}; - vert_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; - vert_shader_stage_info.module = GEVulkanShaderManager::getShader("fullscreen_quad.vert"); - vert_shader_stage_info.pName = "main"; - - VkPipelineShaderStageCreateInfo frag_shader_stage_info = {}; - frag_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - frag_shader_stage_info.module = GEVulkanShaderManager::getShader("skybox.frag"); - frag_shader_stage_info.pName = "main"; - - std::array shader_stages = - {{ - vert_shader_stage_info, - frag_shader_stage_info - }}; - - VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; - vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input_info.vertexBindingDescriptionCount = 0; - vertex_input_info.vertexAttributeDescriptionCount = 0; - vertex_input_info.pVertexBindingDescriptions = NULL; - vertex_input_info.pVertexAttributeDescriptions = NULL; - - VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; - input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - input_assembly.primitiveRestartEnable = VK_FALSE; - - VkViewport viewport = {}; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = (float)vk->getSwapChainExtent().width; - viewport.height = (float)vk->getSwapChainExtent().height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = {}; - scissor.offset = {0, 0}; - scissor.extent = vk->getSwapChainExtent(); - - VkPipelineViewportStateCreateInfo viewport_state = {}; - viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_state.viewportCount = 1; - viewport_state.pViewports = &viewport; - viewport_state.scissorCount = 1; - viewport_state.pScissors = &scissor; - - VkPipelineRasterizationStateCreateInfo rasterizer = {}; - rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.depthClampEnable = VK_FALSE; - rasterizer.rasterizerDiscardEnable = VK_FALSE; - rasterizer.polygonMode = VK_POLYGON_MODE_FILL; - rasterizer.lineWidth = 1.0f; - rasterizer.cullMode = VK_CULL_MODE_FRONT_BIT; - rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterizer.depthBiasEnable = VK_FALSE; - - VkPipelineMultisampleStateCreateInfo multisampling = {}; - multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.sampleShadingEnable = VK_FALSE; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - - VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; - depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depth_stencil.depthTestEnable = VK_TRUE; - depth_stencil.depthWriteEnable = VK_FALSE; - depth_stencil.depthCompareOp = VK_COMPARE_OP_EQUAL; - depth_stencil.depthBoundsTestEnable = VK_FALSE; - depth_stencil.stencilTestEnable = VK_FALSE; - - VkPipelineColorBlendAttachmentState color_blend_attachment = {}; - color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | - VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | - VK_COLOR_COMPONENT_A_BIT; - color_blend_attachment.blendEnable = VK_FALSE; - - VkPipelineColorBlendStateCreateInfo color_blending = {}; - color_blending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - color_blending.logicOpEnable = VK_FALSE; - color_blending.logicOp = VK_LOGIC_OP_COPY; - color_blending.attachmentCount = 1; - color_blending.pAttachments = &color_blend_attachment; - color_blending.blendConstants[0] = 0.0f; - color_blending.blendConstants[1] = 0.0f; - color_blending.blendConstants[2] = 0.0f; - color_blending.blendConstants[3] = 0.0f; - - std::array dynamic_state = - {{ - VK_DYNAMIC_STATE_SCISSOR, - VK_DYNAMIC_STATE_VIEWPORT - }}; - - VkPipelineDynamicStateCreateInfo dynamic_state_info = {}; - dynamic_state_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, - dynamic_state_info.dynamicStateCount = dynamic_state.size(), - dynamic_state_info.pDynamicStates = dynamic_state.data(); - - VkGraphicsPipelineCreateInfo pipeline_info = {}; - pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipeline_info.stageCount = shader_stages.size(); - pipeline_info.pStages = shader_stages.data(); - pipeline_info.pVertexInputState = &vertex_input_info; - pipeline_info.pInputAssemblyState = &input_assembly; - pipeline_info.pViewportState = &viewport_state; - pipeline_info.pRasterizationState = &rasterizer; - pipeline_info.pMultisampleState = &multisampling; - pipeline_info.pDepthStencilState = &depth_stencil; - pipeline_info.pColorBlendState = &color_blending; - pipeline_info.pDynamicState = &dynamic_state_info; - pipeline_info.layout = g_pipeline_layout; - pipeline_info.renderPass = vk->getRTTTexture() ? - vk->getRTTTexture()->getRTTRenderPass() : vk->getRenderPass(); - pipeline_info.subpass = 0; - pipeline_info.basePipelineHandle = VK_NULL_HANDLE; - - if (vkCreateGraphicsPipelines(vk->getDevice(), VK_NULL_HANDLE, - 1, &pipeline_info, NULL, &g_graphics_pipeline) != VK_SUCCESS) + auto swap_pixels = [](video::IImage* img, unsigned idx) { - throw std::runtime_error("vkCreateGraphicsPipelines failed for " - "addSkyBox"); - } + if (!(idx == 2 || idx == 3)) + return; + unsigned width = img->getDimension().Width; + uint8_t* tmp = new uint8_t[width * width * 4]; + uint32_t* tmp_array = (uint32_t*)tmp; + uint32_t* img_data = (uint32_t*)img->lock(); + for (unsigned i = 0; i < width; i++) + { + for (unsigned j = 0; j < width; j++) + tmp_array[j * width + i] = img_data[i * width + (width - j - 1)]; + } + uint8_t* u8_data = (uint8_t*)img->lock(); + delete [] u8_data; + img->setMemory(tmp); + }; + if (m_texture_cubemap) + m_texture_cubemap->drop(); + m_texture_cubemap = new GEVulkanArrayTexture(sky_tex, + VK_IMAGE_VIEW_TYPE_CUBE, swap_pixels); + GEVulkanDriver* vk = getVKDriver(); + VkDescriptorImageInfo info; + info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + info.sampler = vk->getSampler(GVS_SKYBOX); + info.imageView = (VkImageView)m_texture_cubemap->getTextureHandler(); + + VkWriteDescriptorSet write_descriptor_set = {}; + write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptor_set.dstBinding = 0; + write_descriptor_set.dstArrayElement = 0; + write_descriptor_set.descriptorType = + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_descriptor_set.descriptorCount = 1; + write_descriptor_set.pBufferInfo = 0; + write_descriptor_set.dstSet = m_descriptor_set; + write_descriptor_set.pImageInfo = &info; + + vkUpdateDescriptorSets(vk->getDevice(), 1, &write_descriptor_set, 0, + NULL); } // addSkyBox } diff --git a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp index beccf3f5ab1..b04c1d21c4c 100644 --- a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp +++ b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp @@ -10,18 +10,34 @@ namespace irr namespace GE { -class GEVulkanCameraSceneNode; -class GEVulkanDriver; -namespace GEVulkanSkyBoxRenderer +class GEVulkanArrayTexture; + +class GEVulkanSkyBoxRenderer { -// ---------------------------------------------------------------------------- -void init(); -// ---------------------------------------------------------------------------- -void destroy(); -// ---------------------------------------------------------------------------- -void render(VkCommandBuffer, GEVulkanCameraSceneNode*); -// ---------------------------------------------------------------------------- -void addSkyBox(GEVulkanCameraSceneNode*, irr::scene::ISceneNode*); +private: + irr::scene::ISceneNode* m_skybox; + + GEVulkanArrayTexture* m_texture_cubemap; + + VkDescriptorSetLayout m_descriptor_layout; + + VkDescriptorPool m_descriptor_pool; + + VkDescriptorSet m_descriptor_set; +public: + // ------------------------------------------------------------------------ + GEVulkanSkyBoxRenderer(); + // ------------------------------------------------------------------------ + ~GEVulkanSkyBoxRenderer(); + // ------------------------------------------------------------------------ + void addSkyBox(irr::scene::ISceneNode* node); + // ------------------------------------------------------------------------ + VkDescriptorSetLayout getDescriptorSetLayout() const + { return m_descriptor_layout; } + // ------------------------------------------------------------------------ + const VkDescriptorSet* getDescriptorSet() const + { return &m_descriptor_set; } + }; // GEVulkanSkyBoxRenderer } From 6b24709aaaa7002032d72f5d86ca220bcaf641de Mon Sep 17 00:00:00 2001 From: Deve Date: Thu, 10 Apr 2025 22:38:10 +0200 Subject: [PATCH 655/830] Add GEVulkanAttachmentTexture Use VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT for depth texture, from https://docs.vulkan.org/samples/latest/samples/performance/render_passes/README.html --- lib/graphics_engine/CMakeLists.txt | 2 +- .../include/ge_vulkan_driver.hpp | 7 +-- .../src/ge_vulkan_attachment_texture.cpp | 54 +++++++++++++++++++ ...e.hpp => ge_vulkan_attachment_texture.hpp} | 20 ++++--- .../src/ge_vulkan_depth_texture.cpp | 41 -------------- lib/graphics_engine/src/ge_vulkan_driver.cpp | 4 +- .../src/ge_vulkan_fbo_texture.cpp | 7 ++- .../src/ge_vulkan_fbo_texture.hpp | 4 +- lib/graphics_engine/src/ge_vulkan_texture.cpp | 2 + 9 files changed, 83 insertions(+), 58 deletions(-) create mode 100644 lib/graphics_engine/src/ge_vulkan_attachment_texture.cpp rename lib/graphics_engine/src/{ge_vulkan_depth_texture.hpp => ge_vulkan_attachment_texture.hpp} (80%) delete mode 100644 lib/graphics_engine/src/ge_vulkan_depth_texture.cpp diff --git a/lib/graphics_engine/CMakeLists.txt b/lib/graphics_engine/CMakeLists.txt index b42ff383c70..1dc1e294380 100644 --- a/lib/graphics_engine/CMakeLists.txt +++ b/lib/graphics_engine/CMakeLists.txt @@ -74,10 +74,10 @@ set(GE_SOURCES src/ge_vulkan_2d_renderer.cpp src/ge_vulkan_array_texture.cpp src/ge_vulkan_animated_mesh_scene_node.cpp + src/ge_vulkan_attachment_texture.cpp src/ge_vulkan_billboard_buffer.cpp src/ge_vulkan_camera_scene_node.cpp src/ge_vulkan_command_loader.cpp - src/ge_vulkan_depth_texture.cpp src/ge_vulkan_driver.cpp src/ge_vulkan_draw_call.cpp src/ge_vulkan_dynamic_buffer.cpp diff --git a/lib/graphics_engine/include/ge_vulkan_driver.hpp b/lib/graphics_engine/include/ge_vulkan_driver.hpp index 69b26b2ecd4..220c5e477f3 100644 --- a/lib/graphics_engine/include/ge_vulkan_driver.hpp +++ b/lib/graphics_engine/include/ge_vulkan_driver.hpp @@ -25,7 +25,7 @@ using namespace video; namespace GE { class GESPM; - class GEVulkanDepthTexture; + class GEVulkanAttachmentTexture; class GEVulkanDrawCall; class GEVulkanDynamicSPMBuffer; class GEVulkanFBOTexture; @@ -350,7 +350,8 @@ namespace GE void waitIdle(bool flush_command_loader = false); void setDisableWaitIdle(bool val) { m_disable_wait_idle = val; } IrrlichtDevice* getIrrlichtDevice() const { return m_irrlicht_device; } - GEVulkanDepthTexture* getDepthTexture() const { return m_depth_texture; } + GEVulkanAttachmentTexture* getDepthTexture() const + { return m_depth_texture; } VkFormat findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features); @@ -510,7 +511,7 @@ namespace GE bool m_disable_wait_idle; IrrlichtDevice* m_irrlicht_device; - GEVulkanDepthTexture* m_depth_texture; + GEVulkanAttachmentTexture* m_depth_texture; GEVulkanSkyBoxRenderer* m_skybox_renderer; GEVulkanTextureDescriptor* m_mesh_texture_descriptor; GEVulkanFBOTexture* m_rtt_texture; diff --git a/lib/graphics_engine/src/ge_vulkan_attachment_texture.cpp b/lib/graphics_engine/src/ge_vulkan_attachment_texture.cpp new file mode 100644 index 00000000000..30a5853764b --- /dev/null +++ b/lib/graphics_engine/src/ge_vulkan_attachment_texture.cpp @@ -0,0 +1,54 @@ +#include + +#include "ge_vulkan_attachment_texture.hpp" + +#include "ge_main.hpp" +#include "ge_vulkan_driver.hpp" + +#include + +namespace GE +{ +GEVulkanAttachmentTexture::GEVulkanAttachmentTexture(GEVulkanDriver* vk, + const core::dimension2d& size, + VkFormat format, + VkImageUsageFlags iu, + VkImageAspectFlags ia) + : GEVulkanTexture() +{ + m_vk = vk; + m_vulkan_device = m_vk->getDevice(); + m_image = VK_NULL_HANDLE; + m_vma_allocation = VK_NULL_HANDLE; + m_has_mipmaps = false; + m_locked_data = NULL; + m_size = m_orig_size = size; + m_internal_format = format; + + if (!createImage(iu)) + throw std::runtime_error("createImage failed for attachment texture"); + + if (!createImageView(ia)) + throw std::runtime_error("createImageView failed for attachment texture"); +} // GEVulkanAttachmentTexture + +// ---------------------------------------------------------------------------- +GEVulkanAttachmentTexture* GEVulkanAttachmentTexture::createDepthTexture( + GEVulkanDriver* vk, const core::dimension2d& size) +{ + std::vector preferred = + { + VK_FORMAT_D32_SFLOAT, + VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_D24_UNORM_S8_UINT + }; + VkFormat format = vk->findSupportedFormat(preferred, + VK_IMAGE_TILING_OPTIMAL, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); + return new GEVulkanAttachmentTexture(vk, size, format, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, + VK_IMAGE_ASPECT_DEPTH_BIT); +} // createDepthTexture + +} diff --git a/lib/graphics_engine/src/ge_vulkan_depth_texture.hpp b/lib/graphics_engine/src/ge_vulkan_attachment_texture.hpp similarity index 80% rename from lib/graphics_engine/src/ge_vulkan_depth_texture.hpp rename to lib/graphics_engine/src/ge_vulkan_attachment_texture.hpp index 09718c623f3..2701b28cdec 100644 --- a/lib/graphics_engine/src/ge_vulkan_depth_texture.hpp +++ b/lib/graphics_engine/src/ge_vulkan_attachment_texture.hpp @@ -1,19 +1,21 @@ -#ifndef HEADER_GE_VULKAN_DEPTH_TEXTURE_HPP -#define HEADER_GE_VULKAN_DEPTH_TEXTURE_HPP +#ifndef HEADER_GE_VULKAN_ATTACHMENT_TEXTURE_HPP +#define HEADER_GE_VULKAN_ATTACHMENT_TEXTURE_HPP #include "ge_vulkan_texture.hpp" namespace GE { class GEVulkanDriver; -class GEVulkanDepthTexture : public GEVulkanTexture +class GEVulkanAttachmentTexture : public GEVulkanTexture { public: // ------------------------------------------------------------------------ - GEVulkanDepthTexture(GEVulkanDriver* vk, - const core::dimension2d& size); + GEVulkanAttachmentTexture(GEVulkanDriver* vk, + const core::dimension2d& size, + VkFormat format, VkImageUsageFlags iu, + VkImageAspectFlags ia); // ------------------------------------------------------------------------ - virtual ~GEVulkanDepthTexture() {} + virtual ~GEVulkanAttachmentTexture() {} // ------------------------------------------------------------------------ virtual void* lock(video::E_TEXTURE_LOCK_MODE mode = video::ETLM_READ_WRITE, u32 mipmap_level = 0) @@ -49,7 +51,11 @@ class GEVulkanDepthTexture : public GEVulkanTexture virtual std::shared_ptr > getImageView( bool srgb = false) const { return m_image_view; } -}; // GEVulkanDepthTexture + // ------------------------------------------------------------------------ + static GEVulkanAttachmentTexture* createDepthTexture( + GEVulkanDriver* vk, const core::dimension2d& size); + +}; // GEVulkanAttachmentTexture } diff --git a/lib/graphics_engine/src/ge_vulkan_depth_texture.cpp b/lib/graphics_engine/src/ge_vulkan_depth_texture.cpp deleted file mode 100644 index 26376754628..00000000000 --- a/lib/graphics_engine/src/ge_vulkan_depth_texture.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include - -#include "ge_vulkan_depth_texture.hpp" - -#include "ge_main.hpp" -#include "ge_vulkan_driver.hpp" - -#include - -namespace GE -{ -GEVulkanDepthTexture::GEVulkanDepthTexture(GEVulkanDriver* vk, - const core::dimension2d& size) - : GEVulkanTexture() -{ - m_vk = vk; - m_vulkan_device = m_vk->getDevice(); - m_image = VK_NULL_HANDLE; - m_vma_allocation = VK_NULL_HANDLE; - m_has_mipmaps = false; - m_locked_data = NULL; - m_size = m_orig_size = size; - - std::vector preferred = - { - VK_FORMAT_D32_SFLOAT, - VK_FORMAT_D32_SFLOAT_S8_UINT, - VK_FORMAT_D24_UNORM_S8_UINT - }; - m_internal_format = m_vk->findSupportedFormat(preferred, - VK_IMAGE_TILING_OPTIMAL, - VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); - - if (!createImage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) - throw std::runtime_error("createImage failed for depth texture"); - - if (!createImageView(VK_IMAGE_ASPECT_DEPTH_BIT)) - throw std::runtime_error("createImageView failed for depth texture"); -} // GEVulkanDepthTexture - -} diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index bb35dc43935..a34e25553da 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -7,9 +7,9 @@ #include "ge_spm_buffer.hpp" #include "ge_vulkan_2d_renderer.hpp" +#include "ge_vulkan_attachment_texture.hpp" #include "ge_vulkan_camera_scene_node.hpp" #include "ge_vulkan_command_loader.hpp" -#include "ge_vulkan_depth_texture.hpp" #include "ge_vulkan_draw_call.hpp" #include "ge_vulkan_dynamic_spm_buffer.hpp" #include "ge_vulkan_fbo_texture.hpp" @@ -1339,7 +1339,7 @@ void GEVulkanDriver::createSwapChain() } else { - m_depth_texture = new GEVulkanDepthTexture(this, + m_depth_texture = GEVulkanAttachmentTexture::createDepthTexture(this, core::dimension2du(m_swap_chain_extent.width, m_swap_chain_extent.height)); } diff --git a/lib/graphics_engine/src/ge_vulkan_fbo_texture.cpp b/lib/graphics_engine/src/ge_vulkan_fbo_texture.cpp index 3e4c27c48ee..d9ea80a648d 100644 --- a/lib/graphics_engine/src/ge_vulkan_fbo_texture.cpp +++ b/lib/graphics_engine/src/ge_vulkan_fbo_texture.cpp @@ -1,7 +1,7 @@ #include "ge_vulkan_fbo_texture.hpp" #include "ge_main.hpp" -#include "ge_vulkan_depth_texture.hpp" +#include "ge_vulkan_attachment_texture.hpp" #include "ge_vulkan_driver.hpp" #include @@ -35,7 +35,10 @@ GEVulkanFBOTexture::GEVulkanFBOTexture(GEVulkanDriver* vk, m_rtt_render_pass = VK_NULL_HANDLE; m_rtt_frame_buffer = VK_NULL_HANDLE; if (create_depth) - m_depth_texture = new GEVulkanDepthTexture(m_vk, size); + { + m_depth_texture = GEVulkanAttachmentTexture::createDepthTexture( + m_vk, size); + } } // GEVulkanFBOTexture // ---------------------------------------------------------------------------- diff --git a/lib/graphics_engine/src/ge_vulkan_fbo_texture.hpp b/lib/graphics_engine/src/ge_vulkan_fbo_texture.hpp index 69242438545..8eade1216a5 100644 --- a/lib/graphics_engine/src/ge_vulkan_fbo_texture.hpp +++ b/lib/graphics_engine/src/ge_vulkan_fbo_texture.hpp @@ -5,11 +5,11 @@ namespace GE { -class GEVulkanDepthTexture; +class GEVulkanAttachmentTexture; class GEVulkanFBOTexture : public GEVulkanTexture { private: - GEVulkanDepthTexture* m_depth_texture; + GEVulkanAttachmentTexture* m_depth_texture; VkRenderPass m_rtt_render_pass; diff --git a/lib/graphics_engine/src/ge_vulkan_texture.cpp b/lib/graphics_engine/src/ge_vulkan_texture.cpp index ce39db88a06..751ca9eb60d 100644 --- a/lib/graphics_engine/src/ge_vulkan_texture.cpp +++ b/lib/graphics_engine/src/ge_vulkan_texture.cpp @@ -297,6 +297,8 @@ bool GEVulkanTexture::createImage(VkImageUsageFlags usage) m_vma_info = {}; VmaAllocationCreateInfo alloc_info = {}; alloc_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; + if ((usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0) + alloc_info.preferredFlags = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; VkResult result = vmaCreateImage(m_vk->getVmaAllocator(), &image_info, &alloc_info, &m_image, &m_vma_allocation, &m_vma_info); From 9c36b797f39e990f7cc94f8781e4c3796e1bd155 Mon Sep 17 00:00:00 2001 From: Deve Date: Fri, 11 Apr 2025 21:54:05 +0200 Subject: [PATCH 656/830] Make push constants reproducible --- .../src/ge_vulkan_draw_call.cpp | 9 +++++++ .../src/ge_vulkan_draw_call.hpp | 25 +++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index 54c5b959b64..4e5da0856f3 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -1292,6 +1292,14 @@ void GEVulkanDrawCall::createVulkanData() } createAllPipelines(vk); + for (auto& p : m_graphics_pipelines) + { + if (p.second.second.m_push_constants_func) + { + m_push_constants[p.second.second.m_shader_name] = + std::vector(); + } + } size_t extra_size = 0; const bool use_multidraw = @@ -1409,6 +1417,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering(); const bool bind_mesh_textures = GEVulkanFeatures::supportsBindMeshTexturesAtOnce(); + updatePushConstants(); updateDataDescriptorSets(vk); m_texture_descriptor->updateDescriptor(); diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp index 7af76009d87..5fd258ceca3 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp @@ -150,6 +150,8 @@ class GEVulkanDrawCall std::vector m_data_descriptor_sets; + std::unordered_map > m_push_constants; + VkPipelineLayout m_pipeline_layout, m_skybox_layout; std::unordered_map > @@ -181,13 +183,12 @@ class GEVulkanDrawCall { auto& ret = m_graphics_pipelines.at(name); vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ret.first); - if (ret.second.m_push_constants_func) + auto it = m_push_constants.find(ret.second.m_shader_name); + if (it != m_push_constants.end()) { - uint32_t size; - void* data; - ret.second.m_push_constants_func(&size, &data); vkCmdPushConstants(cmd, m_pipeline_layout, - VK_SHADER_STAGE_ALL_GRAPHICS, 0, size, data); + VK_SHADER_STAGE_ALL_GRAPHICS, 0, it->second.size(), + it->second.data()); } } // ------------------------------------------------------------------------ @@ -221,6 +222,20 @@ class GEVulkanDrawCall // ------------------------------------------------------------------------ void drawSkyBox(VkCommandBuffer cmd, int current_buffer_idx, std::vector& dynamic_offsets); + // ------------------------------------------------------------------------ + void updatePushConstants() + { + for (auto& p : m_push_constants) + { + auto& f = + m_graphics_pipelines.at(p.first).second.m_push_constants_func; + uint32_t size; + void* data; + f(&size, &data); + p.second.resize(size); + memcpy(p.second.data(), data, size); + } + } public: // ------------------------------------------------------------------------ GEVulkanDrawCall(); From fe0d89c29b3a76463c1440785b72133b813a1be8 Mon Sep 17 00:00:00 2001 From: Deve Date: Sat, 12 Apr 2025 20:41:53 +0200 Subject: [PATCH 657/830] Enable depth prepass if necessary --- data/shaders/ge_shaders/alphatest_depth.frag | 12 + data/shaders/ge_shaders/depth_only.frag | 3 + .../src/ge_vulkan_draw_call.cpp | 515 ++++++++++++------ .../src/ge_vulkan_draw_call.hpp | 53 +- 4 files changed, 408 insertions(+), 175 deletions(-) create mode 100644 data/shaders/ge_shaders/alphatest_depth.frag create mode 100644 data/shaders/ge_shaders/depth_only.frag diff --git a/data/shaders/ge_shaders/alphatest_depth.frag b/data/shaders/ge_shaders/alphatest_depth.frag new file mode 100644 index 00000000000..680f5d6d7ba --- /dev/null +++ b/data/shaders/ge_shaders/alphatest_depth.frag @@ -0,0 +1,12 @@ +layout(location = 0) in vec4 f_vertex_color; +layout(location = 1) in vec2 f_uv; +layout(location = 3) flat in int f_material_id; + +#include "utils/sample_mesh_texture.glsl" + +void main() +{ + vec4 tex_color = sampleMeshTexture0(f_material_id, f_uv); + if (tex_color.a * f_vertex_color.a < 0.5) + discard; +} diff --git a/data/shaders/ge_shaders/depth_only.frag b/data/shaders/ge_shaders/depth_only.frag new file mode 100644 index 00000000000..919810306a4 --- /dev/null +++ b/data/shaders/ge_shaders/depth_only.frag @@ -0,0 +1,3 @@ +void main() +{ +} diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index 4e5da0856f3..ca34655048b 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -29,6 +29,7 @@ #include "../source/Irrlicht/os.h" #include "quaternion.h" +#define DEPTH_ONLY_FRAG_SHADER "depth_only.frag" namespace GE { @@ -229,8 +230,7 @@ GEVulkanDrawCall::~GEVulkanDrawCall() GEVulkanDriver* vk = getVKDriver(); vkDestroyDescriptorSetLayout(vk->getDevice(), m_data_layout, NULL); vkDestroyDescriptorPool(vk->getDevice(), m_descriptor_pool, NULL); - for (auto& p : m_graphics_pipelines) - vkDestroyPipeline(vk->getDevice(), p.second.first, NULL); + m_graphics_pipelines.clear(); vkDestroyPipelineLayout(vk->getDevice(), m_pipeline_layout, NULL); vkDestroyPipelineLayout(vk->getDevice(), m_skybox_layout, NULL); } @@ -528,7 +528,7 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) }); } const PipelineSettings& settings = - m_graphics_pipelines[cur_shader].second; + m_graphics_pipelines[cur_shader].m_settings; for (auto& r : q.second) { irr::scene::ISceneNode* node = r.first; @@ -849,6 +849,7 @@ void GEVulkanDrawCall::prepare(GEVulkanCameraSceneNode* cam) void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) { PipelineSettings settings = {}; + std::unordered_map > dp_cache; settings.m_depth_test = true; settings.m_depth_write = true; settings.m_backface_culling = true; @@ -856,21 +857,23 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) settings.m_vertex_shader = "spm.vert"; settings.m_skinning_vertex_shader = "spm_skinning.vert"; settings.m_fragment_shader = "solid.frag"; + settings.m_depth_only_fragment_shader = DEPTH_ONLY_FRAG_SHADER; settings.m_shader_name = "solid"; - createPipeline(vk, settings); + createPipeline(vk, settings, dp_cache); settings.m_fragment_shader = "normalmap.frag"; settings.m_shader_name = "normalmap"; - createPipeline(vk, settings); + createPipeline(vk, settings, dp_cache); settings.m_fragment_shader = "decal.frag"; settings.m_shader_name = "decal"; - createPipeline(vk, settings); + createPipeline(vk, settings, dp_cache); settings.m_fragment_shader = "alphatest.frag"; settings.m_shader_name = "alphatest"; + settings.m_depth_only_fragment_shader = "alphatest_depth.frag"; settings.m_drawing_priority = (char)5; - createPipeline(vk, settings); + createPipeline(vk, settings, dp_cache); settings.m_vertex_shader = "grass.vert"; settings.m_skinning_vertex_shader = ""; @@ -884,10 +887,11 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) *size = sizeof(irr::core::vector3df); *data = &wind_direction; }; - createPipeline(vk, settings); + createPipeline(vk, settings, dp_cache); settings.m_vertex_shader = "spm.vert"; settings.m_skinning_vertex_shader = "spm_skinning.vert"; + settings.m_depth_only_fragment_shader = ""; settings.m_push_constants_func = nullptr; settings.m_depth_write = true; @@ -896,7 +900,7 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) settings.m_drawing_priority = (char)9; settings.m_fragment_shader = "ghost.frag"; settings.m_shader_name = "ghost"; - createPipeline(vk, settings); + createPipeline(vk, settings, dp_cache); settings.m_depth_write = false; settings.m_backface_culling = false; @@ -904,14 +908,14 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) settings.m_fragment_shader = "transparent.frag"; settings.m_shader_name = "alphablend"; - createPipeline(vk, settings); + createPipeline(vk, settings, dp_cache); settings.m_alphablend = false; settings.m_additive = true; settings.m_fragment_shader = "transparent.frag"; settings.m_shader_name = "additive"; settings.m_drawing_priority = (char)11; - createPipeline(vk, settings); + createPipeline(vk, settings, dp_cache); settings.m_alphablend = false; settings.m_additive = false; @@ -921,30 +925,23 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) settings.m_vertex_shader = "fullscreen_quad.vert"; settings.m_fragment_shader = "skybox.frag"; settings.m_shader_name = "skybox"; - createPipeline(vk, settings); + createPipeline(vk, settings, dp_cache); } // createAllPipelines // ---------------------------------------------------------------------------- void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, - const PipelineSettings& settings) + const PipelineSettings& settings, + std::unordered_map >& dp_cache) { - bool creating_animated_pipeline_for_skinning = false; - std::string shader_name = settings.m_shader_name; - -start: VkPipelineShaderStageCreateInfo vert_shader_stage_info = {}; vert_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; - vert_shader_stage_info.module = GEVulkanShaderManager::getShader( - creating_animated_pipeline_for_skinning ? - settings.m_skinning_vertex_shader : settings.m_vertex_shader); vert_shader_stage_info.pName = "main"; VkPipelineShaderStageCreateInfo frag_shader_stage_info = {}; frag_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - frag_shader_stage_info.module = GEVulkanShaderManager::getShader(settings.m_fragment_shader); frag_shader_stage_info.pName = "main"; std::array shader_stages = @@ -1120,26 +1117,137 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, pipeline_info.subpass = 0; pipeline_info.basePipelineHandle = VK_NULL_HANDLE; + shader_stages[0].module = GEVulkanShaderManager::getShader( + settings.m_vertex_shader); + shader_stages[1].module = GEVulkanShaderManager::getShader( + settings.m_fragment_shader); + + bool depth_only = false; + std::string depth_only_fs = settings.m_depth_only_fragment_shader; + if (!doDepthOnlyRenderingFirst()) + depth_only_fs = ""; + if (!depth_only_fs.empty()) + { + depth_only = true; + shader_stages[1].module = GEVulkanShaderManager::getShader( + depth_only_fs); + } + + auto insert_from_cache = [&dp_cache, this](const PipelineSettings& s, + bool skinning) + { + std::string vs = skinning ? + s.m_skinning_vertex_shader : s.m_vertex_shader; + auto it = dp_cache.find(vs + s.m_depth_only_fragment_shader); + if (it == dp_cache.end()) + return false; + std::string key = s.m_shader_name; + if (skinning) + key += "_skinning"; + if (m_graphics_pipelines.find(key) == m_graphics_pipelines.end()) + { + m_graphics_pipelines[key] = {}; + m_graphics_pipelines[key].m_settings = s; + } + m_graphics_pipelines[key].m_depth_only_pipeline = it->second; + return true; + }; + + auto insert_pipeline = [vk, &dp_cache, this](VkPipeline p, + const PipelineSettings& s, + bool depth_only, + bool skinning) + { + std::string key = s.m_shader_name; + if (skinning) + key += "_skinning"; + if (m_graphics_pipelines.find(key) == m_graphics_pipelines.end()) + { + m_graphics_pipelines[key] = {}; + m_graphics_pipelines[key].m_settings = s; + } + auto dp = [vk](VkPipeline* p) + { + vkDestroyPipeline(vk->getDevice(), *p, NULL); + delete p; + }; + if (depth_only) + { + auto sp = std::shared_ptr(new VkPipeline(p), dp); + m_graphics_pipelines[key].m_depth_only_pipeline = sp; + std::string vs = skinning ? + s.m_skinning_vertex_shader : s.m_vertex_shader; + dp_cache[vs + s.m_depth_only_fragment_shader] = sp; + } + else + m_graphics_pipelines[key].m_pipeline = + std::shared_ptr(new VkPipeline(p), dp); + }; + VkPipeline graphics_pipeline; + const std::string& shader_name = settings.m_shader_name; + + if (!insert_from_cache(settings, false)) + { + VkResult result = vkCreateGraphicsPipelines(vk->getDevice(), + VK_NULL_HANDLE, 1, &pipeline_info, NULL, &graphics_pipeline); + if (result != VK_SUCCESS) + { + throw std::runtime_error("vkCreateGraphicsPipelines failed for " + + shader_name); + } + insert_pipeline(graphics_pipeline, settings, depth_only, false); + } + + if (!settings.m_skinning_vertex_shader.empty() && + !insert_from_cache(settings, true)) + { + shader_stages[0].module = GEVulkanShaderManager::getShader( + settings.m_skinning_vertex_shader); + VkResult result = vkCreateGraphicsPipelines(vk->getDevice(), + VK_NULL_HANDLE, 1, &pipeline_info, NULL, &graphics_pipeline); + if (result != VK_SUCCESS) + { + throw std::runtime_error("vkCreateGraphicsPipelines failed for " + + shader_name); + } + insert_pipeline(graphics_pipeline, settings, depth_only, true); + } + if (depth_only_fs.empty()) + return; + + depth_only = false; + VkPipelineDepthStencilStateCreateInfo color_after_depth = depth_stencil; + color_after_depth.depthWriteEnable = VK_FALSE; + color_after_depth.depthCompareOp = VK_COMPARE_OP_EQUAL; + pipeline_info.pDepthStencilState = &color_after_depth; + shader_stages[0].module = GEVulkanShaderManager::getShader( + settings.m_vertex_shader); + shader_stages[1].module = GEVulkanShaderManager::getShader( + settings.m_fragment_shader); + VkResult result = vkCreateGraphicsPipelines(vk->getDevice(), VK_NULL_HANDLE, 1, &pipeline_info, NULL, &graphics_pipeline); - if (result != VK_SUCCESS) { throw std::runtime_error("vkCreateGraphicsPipelines failed for " + shader_name); } - m_graphics_pipelines[shader_name] = std::make_pair( - graphics_pipeline, settings); + insert_pipeline(graphics_pipeline, settings, depth_only, false); if (settings.m_skinning_vertex_shader.empty()) return; - else if (creating_animated_pipeline_for_skinning) - return; - creating_animated_pipeline_for_skinning = true; - shader_name = settings.m_shader_name + "_skinning"; - goto start; + shader_stages[0].module = GEVulkanShaderManager::getShader( + settings.m_skinning_vertex_shader); + result = vkCreateGraphicsPipelines(vk->getDevice(), + VK_NULL_HANDLE, 1, &pipeline_info, NULL, &graphics_pipeline); + if (result != VK_SUCCESS) + { + throw std::runtime_error("vkCreateGraphicsPipelines failed for " + + shader_name); + } + insert_pipeline(graphics_pipeline, settings, depth_only, true); } // createPipeline // ---------------------------------------------------------------------------- @@ -1294,9 +1402,9 @@ void GEVulkanDrawCall::createVulkanData() createAllPipelines(vk); for (auto& p : m_graphics_pipelines) { - if (p.second.second.m_push_constants_func) + if (p.second.m_settings.m_push_constants_func) { - m_push_constants[p.second.second.m_shader_name] = + m_push_constants[p.second.m_settings.m_shader_name] = std::vector(); } } @@ -1441,8 +1549,14 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, scissor.extent.height = vp.height; vkCmdSetScissor(cmd, 0, 1, &scissor); + bool depth_only = doDepthOnlyRenderingFirst(); + bool bound_mesh_textures_once = false; + VkPipeline prev_dp = VK_NULL_HANDLE; +start: std::string cur_pipeline = m_cmds[0].m_shader; + auto dynamic_spm_buffers = m_dynamic_spm_buffers; bool drawn_skybox = false; + bool bound = false; size_t sbo_alignment = m_limits.minStorageBufferOffsetAlignment; const size_t dynamic_spm_size = sizeof(ObjectData) + getPadding( sizeof(ObjectData), sbo_alignment); @@ -1458,9 +1572,13 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, }; if (bind_mesh_textures) { - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - m_pipeline_layout, 0, 1, m_texture_descriptor->getDescriptorSet(), - 0, NULL); + if (!bound_mesh_textures_once) + { + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + m_pipeline_layout, 0, 1, + m_texture_descriptor->getDescriptorSet(), 0, NULL); + bound_mesh_textures_once = true; + } size_t indirect_offset = sizeof(GEVulkanCameraUBO); const size_t indirect_size = sizeof(VkDrawIndexedIndirectCommand); unsigned draw_count = 0; @@ -1473,38 +1591,40 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, { if (m_cmds[i].m_shader != cur_pipeline) { - bindPipeline(cmd, cur_pipeline); - auto it = m_dynamic_spm_buffers.find( + bound = bindPipeline(cmd, cur_pipeline, depth_only, &prev_dp); + auto it = dynamic_spm_buffers.find( getDynamicBufferKey(cur_pipeline)); - if (it != m_dynamic_spm_buffers.end()) + if (it != dynamic_spm_buffers.end()) { for (auto& buf : it->second) { - rebind_base_vertex = true; - dynamic_offsets[1] = dynamic_spm_offset; - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, - 1, 1, &m_data_descriptor_sets[current_buffer_idx], - dynamic_offsets.size(), dynamic_offsets.data()); - buf.first->drawDynamicVertexIndexBuffer(cmd, - current_buffer_idx); + if (bound) + { + dynamic_offsets[1] = dynamic_spm_offset; + rebind_base_vertex = true; + bindDataDescriptor(cmd, current_buffer_idx, + dynamic_offsets); + buf.first->drawDynamicVertexIndexBuffer(cmd, + current_buffer_idx); + } dynamic_spm_offset += dynamic_spm_size; } - m_dynamic_spm_buffers.erase(it); + dynamic_spm_buffers.erase(it); } if (rebind_base_vertex) { bindBaseVertex(vk, cmd); rebind_base_vertex = false; } - dynamic_offsets[1] = m_dynamic_spm_padded_size; - dynamic_offsets[3] = m_materials_data[cur_pipeline].first; - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 1, 1, - &m_data_descriptor_sets[current_buffer_idx], - dynamic_offsets.size(), dynamic_offsets.data()); - vkCmdDrawIndexedIndirect(cmd, indirect_buffer, indirect_offset, - draw_count, indirect_size); + if (bound) + { + dynamic_offsets[1] = m_dynamic_spm_padded_size; + dynamic_offsets[3] = m_materials_data[cur_pipeline].first; + bindDataDescriptor(cmd, current_buffer_idx, + dynamic_offsets); + vkCmdDrawIndexedIndirect(cmd, indirect_buffer, + indirect_offset, draw_count, indirect_size); + } indirect_offset += draw_count * indirect_size; draw_count = 1; cur_pipeline = m_cmds[i].m_shader; @@ -1512,90 +1632,88 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, if (m_cmds[i].m_transparent && !drawn_skybox) { drawn_skybox = true; - drawSkyBox(cmd, current_buffer_idx, dynamic_offsets); - - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, - 1, 1, &m_data_descriptor_sets[current_buffer_idx], - dynamic_offsets.size(), dynamic_offsets.data()); + if (!depth_only) + { + drawSkyBox(cmd, current_buffer_idx, dynamic_offsets); - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, - 1, m_texture_descriptor->getDescriptorSet(), 0, NULL); + bindDataDescriptor(cmd, current_buffer_idx, + dynamic_offsets); + vkCmdBindDescriptorSets(cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, + 0, 1, m_texture_descriptor->getDescriptorSet(), 0, + NULL); + } } continue; } draw_count++; } - bindPipeline(cmd, m_cmds.back().m_shader); - auto it = m_dynamic_spm_buffers.find( + bound = bindPipeline(cmd, m_cmds.back().m_shader, depth_only, + &prev_dp); + auto it = dynamic_spm_buffers.find( getDynamicBufferKey(m_cmds.back().m_shader)); - if (it != m_dynamic_spm_buffers.end()) + if (it != dynamic_spm_buffers.end()) { for (auto& buf : it->second) { - rebind_base_vertex = true; - dynamic_offsets[1] = dynamic_spm_offset; - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 1, 1, - &m_data_descriptor_sets[current_buffer_idx], - dynamic_offsets.size(), dynamic_offsets.data()); - buf.first->drawDynamicVertexIndexBuffer(cmd, - current_buffer_idx); + if (bound) + { + dynamic_offsets[1] = dynamic_spm_offset; + rebind_base_vertex = true; + bindDataDescriptor(cmd, current_buffer_idx, + dynamic_offsets); + buf.first->drawDynamicVertexIndexBuffer(cmd, + current_buffer_idx); + } dynamic_spm_offset += dynamic_spm_size; } - m_dynamic_spm_buffers.erase(it); + dynamic_spm_buffers.erase(it); } if (rebind_base_vertex) bindBaseVertex(vk, cmd); - dynamic_offsets[1] = m_dynamic_spm_padded_size; - dynamic_offsets[3] = m_materials_data[m_cmds.back().m_shader].first; - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 1, 1, - &m_data_descriptor_sets[current_buffer_idx], - dynamic_offsets.size(), dynamic_offsets.data()); - vkCmdDrawIndexedIndirect(cmd, indirect_buffer, indirect_offset, - draw_count, indirect_size); + if (bound) + { + dynamic_offsets[1] = m_dynamic_spm_padded_size; + dynamic_offsets[3] = m_materials_data[m_cmds.back().m_shader].first; + bindDataDescriptor(cmd, current_buffer_idx, dynamic_offsets); + vkCmdDrawIndexedIndirect(cmd, indirect_buffer, indirect_offset, + draw_count, indirect_size); + } } else { dynamic_offsets.resize(3); bool rebind_base_vertex = true; - bindPipeline(cmd, cur_pipeline); - auto it = m_dynamic_spm_buffers.find( + bound = bindPipeline(cmd, cur_pipeline, depth_only, &prev_dp); + auto it = dynamic_spm_buffers.find( getDynamicBufferKey(cur_pipeline)); - if (it != m_dynamic_spm_buffers.end()) + if (it != dynamic_spm_buffers.end()) { for (auto& buf : it->second) { - rebind_base_vertex = true; - dynamic_offsets[1] = dynamic_spm_offset; - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, - 1, 1, &m_data_descriptor_sets[current_buffer_idx], - dynamic_offsets.size(), dynamic_offsets.data()); int dy_mat = m_dyspmb_materials[buf.first]; if (dy_mat != cur_mid) { cur_mid = dy_mat; - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, - m_pipeline_layout, 0, 1, - &m_texture_descriptor->getDescriptorSet()[cur_mid], 0, - NULL); + bindSingleMaterial(cmd, cur_pipeline, cur_mid, depth_only); + } + if (bound) + { + dynamic_offsets[1] = dynamic_spm_offset; + rebind_base_vertex = true; + bindDataDescriptor(cmd, current_buffer_idx, + dynamic_offsets); + buf.first->drawDynamicVertexIndexBuffer(cmd, + current_buffer_idx); } - buf.first->drawDynamicVertexIndexBuffer(cmd, - current_buffer_idx); dynamic_spm_offset += dynamic_spm_size; } - m_dynamic_spm_buffers.erase(it); + dynamic_spm_buffers.erase(it); } if (cur_mid != m_cmds[0].m_material_id) { cur_mid = m_cmds[0].m_material_id; - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - m_pipeline_layout, 0, 1, - &m_texture_descriptor->getDescriptorSet()[cur_mid], 0, NULL); + bindSingleMaterial(cmd, cur_pipeline, cur_mid, depth_only); } for (unsigned i = 0; i < m_cmds.size(); i++) { @@ -1603,102 +1721,93 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, if (m_cmds[i].m_transparent && !drawn_skybox) { drawn_skybox = true; - drawSkyBox(cmd, current_buffer_idx, dynamic_offsets); - - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, - 1, 1, &m_data_descriptor_sets[current_buffer_idx], - dynamic_offsets.size(), dynamic_offsets.data()); - - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, 1, - &m_texture_descriptor->getDescriptorSet()[cur_mid], 0, - NULL); - if (use_base_vertex) - rebind_base_vertex = true; + if (!depth_only) + { + drawSkyBox(cmd, current_buffer_idx, dynamic_offsets); + + bindDataDescriptor(cmd, current_buffer_idx, + dynamic_offsets); + vkCmdBindDescriptorSets(cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, + 1, &m_texture_descriptor->getDescriptorSet()[cur_mid], + 0, NULL); + if (use_base_vertex) + rebind_base_vertex = true; + } } if (m_cmds[i].m_shader != cur_pipeline) { cur_pipeline = m_cmds[i].m_shader; - bindPipeline(cmd, cur_pipeline); - auto it = m_dynamic_spm_buffers.find( + bound = bindPipeline(cmd, cur_pipeline, depth_only, &prev_dp); + auto it = dynamic_spm_buffers.find( getDynamicBufferKey(cur_pipeline)); - if (it != m_dynamic_spm_buffers.end()) + if (it != dynamic_spm_buffers.end()) { for (auto& buf : it->second) { - rebind_base_vertex = true; - dynamic_offsets[1] = dynamic_spm_offset; - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, - 1, 1, &m_data_descriptor_sets[current_buffer_idx], - dynamic_offsets.size(), dynamic_offsets.data()); int dy_mat = m_dyspmb_materials[buf.first]; if (dy_mat != cur_mid) { cur_mid = dy_mat; - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, - m_pipeline_layout, 0, 1, - &m_texture_descriptor->getDescriptorSet() - [cur_mid], 0, NULL); + bindSingleMaterial(cmd, cur_pipeline, cur_mid, + depth_only); + } + if (bound) + { + dynamic_offsets[1] = dynamic_spm_offset; + rebind_base_vertex = true; + bindDataDescriptor(cmd, current_buffer_idx, + dynamic_offsets); + buf.first->drawDynamicVertexIndexBuffer(cmd, + current_buffer_idx); } - buf.first->drawDynamicVertexIndexBuffer(cmd, - current_buffer_idx); dynamic_spm_offset += dynamic_spm_size; } - m_dynamic_spm_buffers.erase(it); + dynamic_spm_buffers.erase(it); } } int mid = m_cmds[i].m_material_id; if (cur_mid != mid) { cur_mid = mid; - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - m_pipeline_layout, 0, 1, - &m_texture_descriptor->getDescriptorSet()[cur_mid], 0, - NULL); + bindSingleMaterial(cmd, cur_pipeline, cur_mid, depth_only); } if (use_base_vertex && rebind_base_vertex) { bindBaseVertex(vk, cmd); rebind_base_vertex = false; dynamic_offsets[1] = m_dynamic_spm_padded_size; - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 1, 1, - &m_data_descriptor_sets[current_buffer_idx], - dynamic_offsets.size(), dynamic_offsets.data()); + bindDataDescriptor(cmd, current_buffer_idx, + dynamic_offsets); } - if (!use_base_vertex) + if (bound) { - dynamic_offsets[1] = m_dynamic_spm_padded_size + - m_cmds[i].m_dynamic_offset; - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - m_pipeline_layout, 1, 1, - &m_data_descriptor_sets[current_buffer_idx], - dynamic_offsets.size(), dynamic_offsets.data()); - m_cmds[i].m_mb->bindVertexIndexBuffer(cmd); + if (!use_base_vertex) + { + dynamic_offsets[1] = m_dynamic_spm_padded_size + + m_cmds[i].m_dynamic_offset; + bindDataDescriptor(cmd, current_buffer_idx, + dynamic_offsets); + m_cmds[i].m_mb->bindVertexIndexBuffer(cmd); + } + vkCmdDrawIndexed(cmd, cur_cmd.indexCount, + cur_cmd.instanceCount, cur_cmd.firstIndex, + cur_cmd.vertexOffset, + use_base_vertex ? cur_cmd.firstInstance : 0); } - vkCmdDrawIndexed(cmd, cur_cmd.indexCount, cur_cmd.instanceCount, - cur_cmd.firstIndex, cur_cmd.vertexOffset, - use_base_vertex ? cur_cmd.firstInstance : 0); } } - if (!drawn_skybox) + if (!drawn_skybox && !depth_only) drawSkyBox(cmd, current_buffer_idx, dynamic_offsets); - for (auto& p : m_dynamic_spm_buffers) + for (auto& p : dynamic_spm_buffers) { - bindPipeline(cmd, getShaderFromKey(p.first)); + std::string dy_pipeline = getShaderFromKey(p.first); + bound = bindPipeline(cmd, dy_pipeline, depth_only, &prev_dp); for (auto& buf : p.second) { - dynamic_offsets[1] = dynamic_spm_offset; - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, - 1, 1, &m_data_descriptor_sets[current_buffer_idx], - dynamic_offsets.size(), dynamic_offsets.data()); if (bind_mesh_textures) { - if (!drawn_skybox) + if (!drawn_skybox && !depth_only) { vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, @@ -1711,16 +1820,26 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, if (dy_mat != cur_mid) { cur_mid = dy_mat; - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, - 1, &m_texture_descriptor->getDescriptorSet()[cur_mid], - 0, NULL); + bindSingleMaterial(cmd, dy_pipeline, cur_mid, depth_only); } } - buf.first->drawDynamicVertexIndexBuffer(cmd, current_buffer_idx); + if (bound) + { + dynamic_offsets[1] = dynamic_spm_offset; + bindDataDescriptor(cmd, current_buffer_idx, + dynamic_offsets); + buf.first->drawDynamicVertexIndexBuffer(cmd, + current_buffer_idx); + } dynamic_spm_offset += dynamic_spm_size; } } + + if (depth_only) + { + depth_only = false; + goto start; + } } // render // ---------------------------------------------------------------------------- @@ -1861,7 +1980,7 @@ void GEVulkanDrawCall::drawSkyBox(VkCommandBuffer cmd, int current_buffer_idx, if (!m_skybox_renderer) return; vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - m_graphics_pipelines["skybox"].first); + *m_graphics_pipelines["skybox"].m_pipeline.get()); vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_skybox_layout, 0, 1, m_skybox_renderer->getDescriptorSet(), 0, NULL); vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, @@ -1871,4 +1990,66 @@ void GEVulkanDrawCall::drawSkyBox(VkCommandBuffer cmd, int current_buffer_idx, vkCmdDraw(cmd, 3, 1, 0, 0); } // drawSkyBox +// ---------------------------------------------------------------------------- +void GEVulkanDrawCall::bindSingleMaterial(VkCommandBuffer cmd, + const std::string& cur_pipeline, + int material_id, bool depth_only) +{ + const PipelineData& data = m_graphics_pipelines.at(cur_pipeline); + const PipelineSettings s = data.m_settings; + if (depth_only && + (s.m_depth_only_fragment_shader == DEPTH_ONLY_FRAG_SHADER || + s.m_depth_only_fragment_shader.empty())) + return; + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + m_pipeline_layout, 0, 1, + &m_texture_descriptor->getDescriptorSet()[material_id], 0, NULL); +} // bindSingleMaterial + +// ---------------------------------------------------------------------------- +bool GEVulkanDrawCall::doDepthOnlyRenderingFirst() +{ + enum Status + { + UNDEFINED, + ENABLED, + DISABLED_NOT_PBR, + DISABLED_ARM, + }; + static Status status = UNDEFINED; + auto ret = []() + { + if (!getGEConfig()->m_pbr) + return DISABLED_NOT_PBR; + // https://developer.arm.com/documentation/101897/0304/Optimizing-application-logic/Avoid-using-depth-prepasses +#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined (_M_ARM64) + return DISABLED_ARM; +#else + return ENABLED; +#endif + }; + Status prev_status = status; + status = ret(); + if (prev_status != status) + { + switch (status) + { + case ENABLED: + printf("Enabled depth prepass.\n"); + break; + case DISABLED_NOT_PBR: + printf("Disabled depth prepass because it will make non-PBR" + " rendering slower.\n"); + break; + case DISABLED_ARM: + printf("Disabled depth prepass because it isn't necessary for" + " tile-based GPU.\n"); + break; + default: + break; + } + } + return status == ENABLED; +} // doDepthOnlyRenderingFirst + } diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp index 5fd258ceca3..20431619212 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +73,7 @@ struct PipelineSettings std::string m_vertex_shader; std::string m_skinning_vertex_shader; std::string m_fragment_shader; + std::string m_depth_only_fragment_shader; std::string m_shader_name; bool m_alphablend; bool m_additive; @@ -85,6 +87,13 @@ struct PipelineSettings bool isTransparent() const { return m_alphablend || m_additive; } }; + +struct PipelineData +{ + PipelineSettings m_settings; + std::shared_ptr m_pipeline, m_depth_only_pipeline; +}; + struct DrawCallData { VkDrawIndexedIndirectCommand m_cmd; @@ -154,8 +163,7 @@ class GEVulkanDrawCall VkPipelineLayout m_pipeline_layout, m_skybox_layout; - std::unordered_map > - m_graphics_pipelines; + std::unordered_map m_graphics_pipelines; std::unordered_map m_dyspmb_materials; @@ -171,7 +179,8 @@ class GEVulkanDrawCall // ------------------------------------------------------------------------ void createAllPipelines(GEVulkanDriver* vk); // ------------------------------------------------------------------------ - void createPipeline(GEVulkanDriver* vk, const PipelineSettings& settings); + void createPipeline(GEVulkanDriver* vk, const PipelineSettings& settings, + std::unordered_map >& dp_cache); // ------------------------------------------------------------------------ void createVulkanData(); // ------------------------------------------------------------------------ @@ -179,17 +188,29 @@ class GEVulkanDrawCall // ------------------------------------------------------------------------ std::string getShader(irr::scene::ISceneNode* node, int material_id); // ------------------------------------------------------------------------ - void bindPipeline(VkCommandBuffer cmd, const std::string& name) const + bool bindPipeline(VkCommandBuffer cmd, const std::string& name, + bool depth_only, VkPipeline* prev_dp) const { auto& ret = m_graphics_pipelines.at(name); - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ret.first); - auto it = m_push_constants.find(ret.second.m_shader_name); + VkPipeline p = *ret.m_pipeline.get(); + if (depth_only) + { + if (!ret.m_depth_only_pipeline) + return false; + p = *ret.m_depth_only_pipeline.get(); + if (*prev_dp == p) + return true; + *prev_dp = p; + } + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, p); + auto it = m_push_constants.find(ret.m_settings.m_shader_name); if (it != m_push_constants.end()) { vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_ALL_GRAPHICS, 0, it->second.size(), it->second.data()); } + return true; } // ------------------------------------------------------------------------ TexturesList getTexturesList(const irr::video::SMaterial& m) @@ -212,7 +233,7 @@ class GEVulkanDrawCall const PipelineSettings* settings = &default_settings; auto it = m_graphics_pipelines.find(shader); if (it != m_graphics_pipelines.end()) - settings = &it->second.second; + settings = &it->second.m_settings; return std::string(1, settings->isTransparent() ? (char)1 : (char)0) + std::string(1, settings->m_drawing_priority) + shader; } @@ -228,7 +249,8 @@ class GEVulkanDrawCall for (auto& p : m_push_constants) { auto& f = - m_graphics_pipelines.at(p.first).second.m_push_constants_func; + m_graphics_pipelines.at(p.first).m_settings + .m_push_constants_func; uint32_t size; void* data; f(&size, &data); @@ -236,6 +258,21 @@ class GEVulkanDrawCall memcpy(p.second.data(), data, size); } } + // ------------------------------------------------------------------------ + void bindSingleMaterial(VkCommandBuffer cmd, + const std::string& cur_pipeline, + int material_id, bool depth_only); + // ------------------------------------------------------------------------ + void bindDataDescriptor(VkCommandBuffer cmd, int current_buffer_idx, + std::vector& dynamic_offsets) + { + vkCmdBindDescriptorSets(cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 1, 1, + &m_data_descriptor_sets[current_buffer_idx], + dynamic_offsets.size(), dynamic_offsets.data()); + } + // ------------------------------------------------------------------------ + bool doDepthOnlyRenderingFirst(); public: // ------------------------------------------------------------------------ GEVulkanDrawCall(); From b238cacc66c00146652a945507391835e60b2cd1 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 15 Apr 2025 01:30:12 +0400 Subject: [PATCH 658/830] Refresh cooldown when changing the mode/difficulty Thanks to @nomagno who paid my attention --- src/network/protocols/server_lobby.cpp | 2 ++ src/utils/lobby_settings.cpp | 6 ++++++ src/utils/lobby_settings.hpp | 1 + 3 files changed, 9 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 6f7b3345af1..d0d534b5514 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -3606,6 +3606,8 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, m_game_mode.store(mode); updateMapsForMode(); + getSettings()->onServerConfiguration(); + auto peers = STKHost::get()->getPeers(); for (auto& peer : peers) { diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index 5a8d1f30c47..0a669a17ad2 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -603,6 +603,12 @@ void LobbySettings::onServerSetup() } // onServerSetup //----------------------------------------------------------------------------- +void LobbySettings::onServerConfiguration() +{ + m_last_reset = StkTime::getMonoTimeMs(); +} // onServerConfiguration +//----------------------------------------------------------------------------- + void LobbySettings::tryKickingAnotherPeer(std::shared_ptr initiator, std::shared_ptr target) const { diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 3b664ed8027..4b857358f09 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -105,6 +105,7 @@ class LobbySettings: public LobbyContextComponent bool isSavingServerConfig() const { return m_save_server_config; } void onServerSetup(); + void onServerConfiguration(); void tryKickingAnotherPeer(std::shared_ptr initiator, std::shared_ptr target) const; From f1f322a654062ae3109e877e3415549c26aeb661 Mon Sep 17 00:00:00 2001 From: Wilmaster734 Date: Wed, 16 Apr 2025 06:23:32 -0400 Subject: [PATCH 659/830] Add a clickable link to the stk website in the credits page (#5398) Fix #5259 --- data/gui/screens/credits.stkgui | 4 +++- data/stk_config.xml | 3 ++- src/config/stk_config.cpp | 1 + src/config/stk_config.hpp | 3 ++- src/states_screens/credits.cpp | 5 +++++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/data/gui/screens/credits.stkgui b/data/gui/screens/credits.stkgui index c33d677f50c..5cd8c7187d2 100644 --- a/data/gui/screens/credits.stkgui +++ b/data/gui/screens/credits.stkgui @@ -1,9 +1,11 @@ +
+
-
diff --git a/data/stk_config.xml b/data/stk_config.xml index 951ea047fe1..2162d36cfef 100644 --- a/data/stk_config.xml +++ b/data/stk_config.xml @@ -190,7 +190,8 @@ delta-steering="0.26" /> - diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp index c67804d369c..101d709a5bd 100644 --- a/src/config/stk_config.cpp +++ b/src/config/stk_config.cpp @@ -554,6 +554,7 @@ void STKConfig::getAllData(const XMLNode * root) if (const XMLNode *urls = root->getNode("urls")) { + urls->get("stk-website", &m_stk_website_url); urls->get("donate", &m_donate_url); urls->get("password-reset", &m_password_reset_url); urls->get("assets-download", &m_assets_download_url); diff --git a/src/config/stk_config.hpp b/src/config/stk_config.hpp index a3144e4f0e9..bc157bb6427 100644 --- a/src/config/stk_config.hpp +++ b/src/config/stk_config.hpp @@ -227,7 +227,8 @@ class STKConfig : public NoCopy uint16_t m_client_port; uint16_t m_server_port; - /* URLs for donating and reseting the password */ + /* URLs for the stk website, donating and reseting the password */ + std::string m_stk_website_url; std::string m_donate_url; std::string m_password_reset_url; std::string m_assets_download_url; diff --git a/src/states_screens/credits.cpp b/src/states_screens/credits.cpp index 11cbe556ce6..36ac32e9d5b 100644 --- a/src/states_screens/credits.cpp +++ b/src/states_screens/credits.cpp @@ -409,6 +409,11 @@ void CreditsScreen::eventCallback(GUIEngine::Widget* widget, // Open donation page Online::LinkHelper::openURL(stk_config->m_donate_url); } + if (name == "stk-website") + { + // Open stk website main page + Online::LinkHelper::openURL(stk_config->m_stk_website_url); + } } // ---------------------------------------------------------------------------- From 949df5c476087e52b3b1b4907979da88e5d05a85 Mon Sep 17 00:00:00 2001 From: Deve Date: Wed, 16 Apr 2025 22:09:17 +0200 Subject: [PATCH 660/830] Remove duplicated pbr code in vulkan shaders --- data/shaders/ge_shaders/alphatest.frag | 29 ++++--------------- data/shaders/ge_shaders/decal.frag | 12 ++++++++ data/shaders/ge_shaders/normalmap.frag | 29 ++++--------------- data/shaders/ge_shaders/solid.frag | 29 ++++--------------- data/shaders/ge_shaders/utils/handle_pbr.glsl | 27 +++++++++++++++++ 5 files changed, 54 insertions(+), 72 deletions(-) create mode 100644 data/shaders/ge_shaders/utils/handle_pbr.glsl diff --git a/data/shaders/ge_shaders/alphatest.frag b/data/shaders/ge_shaders/alphatest.frag index 90e5f1e040d..267f233665a 100644 --- a/data/shaders/ge_shaders/alphatest.frag +++ b/data/shaders/ge_shaders/alphatest.frag @@ -8,12 +8,11 @@ layout(location = 5) in vec3 f_normal; layout(location = 0) out vec4 o_color; -#include "utils/camera.glsl" -#include "utils/get_pos_from_frag_coord.glsl" -#include "utils/pbr_light.glsl" #include "utils/sample_mesh_texture.glsl" -#include "utils/sun_direction.glsl" #include "../utils/rgb_conversion.frag" +#ifdef PBR_ENABLED +#include "utils/handle_pbr.glsl" +#endif void main() { @@ -34,25 +33,7 @@ void main() #else vec3 diffuse_color = tex_color.xyz * f_vertex_color.xyz; vec3 normal = normalize(f_normal.xyz); - - vec4 pbr = sampleMeshTexture2(f_material_id, f_uv); - vec3 xpos = getPosFromFragCoord(gl_FragCoord, u_camera.m_viewport, u_camera.m_inverse_projection_matrix); - vec3 eyedir = -normalize(xpos); - - vec3 sun = sunDirection(normal, eyedir, vec3(-642.22, 673.75, -219.26)); - vec3 lightdir = normalize(sun.xyz); - - vec3 mixed_color = PBRSunAmbientEmitLight( - normal, eyedir, lightdir, diffuse_color, - vec3(211./256., 235./256., 110./256.), - vec3(120./256., 120./256., 120./256.), - 1.0 - pbr.x, pbr.y, pbr.z); - - float factor = (1.0 - exp(length(xpos) * -0.0001)); - mixed_color = mixed_color + vec3(0.5) * factor; - - mixed_color = (mixed_color * (6.9 * mixed_color + 0.5)) / (mixed_color * (5.2 * mixed_color + 1.7) + 0.06); - - o_color = vec4(mixed_color, 1.0); + vec3 pbr = sampleMeshTexture2(f_material_id, f_uv).xyz; + o_color = vec4(handlePBR(diffuse_color, pbr, normal), 1.0); #endif } diff --git a/data/shaders/ge_shaders/decal.frag b/data/shaders/ge_shaders/decal.frag index 2d8486b1852..ca5f2e3849c 100644 --- a/data/shaders/ge_shaders/decal.frag +++ b/data/shaders/ge_shaders/decal.frag @@ -1,10 +1,16 @@ layout(location = 1) in vec2 f_uv; layout(location = 2) in vec2 f_uv_two; layout(location = 3) flat in int f_material_id; +#ifdef PBR_ENABLED +layout(location = 5) in vec3 f_normal; +#endif layout(location = 0) out vec4 o_color; #include "utils/sample_mesh_texture.glsl" +#ifdef PBR_ENABLED +#include "utils/handle_pbr.glsl" +#endif void main() { @@ -12,5 +18,11 @@ void main() vec4 layer_two_tex = sampleMeshTexture1(f_material_id, f_uv_two); layer_two_tex.rgb = layer_two_tex.a * layer_two_tex.rgb; vec3 final_color = layer_two_tex.rgb + color.rgb * (1.0 - layer_two_tex.a); +#ifndef PBR_ENABLED o_color = vec4(final_color, 1.0); +#else + vec3 normal = normalize(f_normal.xyz); + vec3 pbr = sampleMeshTexture2(f_material_id, f_uv).xyz; + o_color = vec4(handlePBR(final_color, vec3(0.0), normal), 1.0); +#endif } diff --git a/data/shaders/ge_shaders/normalmap.frag b/data/shaders/ge_shaders/normalmap.frag index 9518197996d..dba754525ae 100644 --- a/data/shaders/ge_shaders/normalmap.frag +++ b/data/shaders/ge_shaders/normalmap.frag @@ -10,12 +10,11 @@ layout(location = 7) in vec3 f_bitangent; layout(location = 0) out vec4 o_color; -#include "utils/camera.glsl" -#include "utils/get_pos_from_frag_coord.glsl" -#include "utils/pbr_light.glsl" #include "utils/sample_mesh_texture.glsl" -#include "utils/sun_direction.glsl" #include "../utils/rgb_conversion.frag" +#ifdef PBR_ENABLED +#include "utils/handle_pbr.glsl" +#endif void main() { @@ -51,25 +50,7 @@ void main() mat3 t_b_n = mat3(frag_tangent, frag_bitangent, frag_normal); vec3 normal = normalize(t_b_n * tangent_space_normal); - - vec4 pbr = sampleMeshTexture2(f_material_id, f_uv); - vec3 xpos = getPosFromFragCoord(gl_FragCoord, u_camera.m_viewport, u_camera.m_inverse_projection_matrix); - vec3 eyedir = -normalize(xpos); - - vec3 sun = sunDirection(normal, eyedir, vec3(-642.22, 673.75, -219.26)); - vec3 lightdir = normalize(sun.xyz); - - vec3 mixed_color = PBRSunAmbientEmitLight( - normal, eyedir, lightdir, diffuse_color, - vec3(211./256., 235./256., 110./256.), - vec3(120./256., 120./256., 120./256.), - 1.0 - pbr.x, pbr.y, pbr.z); - - float factor = (1.0 - exp(length(xpos) * -0.0001)); - mixed_color = mixed_color + vec3(0.5) * factor; - - mixed_color = (mixed_color * (6.9 * mixed_color + 0.5)) / (mixed_color * (5.2 * mixed_color + 1.7) + 0.06); - - o_color = vec4(mixed_color, 1.0); + vec3 pbr = sampleMeshTexture2(f_material_id, f_uv).xyz; + o_color = vec4(handlePBR(diffuse_color, pbr, normal), 1.0); #endif } diff --git a/data/shaders/ge_shaders/solid.frag b/data/shaders/ge_shaders/solid.frag index b4e25068ad4..662f35e6c58 100644 --- a/data/shaders/ge_shaders/solid.frag +++ b/data/shaders/ge_shaders/solid.frag @@ -8,12 +8,11 @@ layout(location = 5) in vec3 f_normal; layout(location = 0) out vec4 o_color; -#include "utils/camera.glsl" -#include "utils/get_pos_from_frag_coord.glsl" -#include "utils/pbr_light.glsl" #include "utils/sample_mesh_texture.glsl" -#include "utils/sun_direction.glsl" #include "../utils/rgb_conversion.frag" +#ifdef PBR_ENABLED +#include "utils/handle_pbr.glsl" +#endif void main() { @@ -41,25 +40,7 @@ void main() #else vec3 diffuse_color = tex_color.xyz * f_vertex_color.xyz; vec3 normal = normalize(f_normal.xyz); - - vec4 pbr = sampleMeshTexture2(f_material_id, f_uv); - vec3 xpos = getPosFromFragCoord(gl_FragCoord, u_camera.m_viewport, u_camera.m_inverse_projection_matrix); - vec3 eyedir = -normalize(xpos); - - vec3 sun = sunDirection(normal, eyedir, vec3(-642.22, 673.75, -219.26)); - vec3 lightdir = normalize(sun.xyz); - - vec3 mixed_color = PBRSunAmbientEmitLight( - normal, eyedir, lightdir, diffuse_color, - vec3(211./256., 235./256., 110./256.), - vec3(120./256., 120./256., 120./256.), - 1.0 - pbr.x, pbr.y, pbr.z); - - float factor = (1.0 - exp(length(xpos) * -0.0001)); - mixed_color = mixed_color + vec3(0.5) * factor; - - mixed_color = (mixed_color * (6.9 * mixed_color + 0.5)) / (mixed_color * (5.2 * mixed_color + 1.7) + 0.06); - - o_color = vec4(mixed_color, 1.0); + vec3 pbr = sampleMeshTexture2(f_material_id, f_uv).xyz; + o_color = vec4(handlePBR(diffuse_color, pbr, normal), 1.0); #endif } diff --git a/data/shaders/ge_shaders/utils/handle_pbr.glsl b/data/shaders/ge_shaders/utils/handle_pbr.glsl new file mode 100644 index 00000000000..9df7c01bc8f --- /dev/null +++ b/data/shaders/ge_shaders/utils/handle_pbr.glsl @@ -0,0 +1,27 @@ +#include "camera.glsl" +#include "get_pos_from_frag_coord.glsl" +#include "pbr_light.glsl" +#include "sun_direction.glsl" + +vec3 handlePBR(vec3 diffuse_color, vec3 pbr, vec3 normal) +{ + vec3 xpos = getPosFromFragCoord(gl_FragCoord, u_camera.m_viewport, + u_camera.m_inverse_projection_matrix); + vec3 eyedir = -normalize(xpos); + + vec3 sun = sunDirection(normal, eyedir, vec3(-642.22, 673.75, -219.26)); + vec3 lightdir = normalize(sun.xyz); + + vec3 mixed_color = PBRSunAmbientEmitLight( + normal, eyedir, lightdir, diffuse_color, + vec3(211./256., 235./256., 110./256.), + vec3(120./256., 120./256., 120./256.), + 1.0 - pbr.x, pbr.y, pbr.z); + + float factor = (1.0 - exp(length(xpos) * -0.0001)); + mixed_color = mixed_color + vec3(0.5) * factor; + + mixed_color = (mixed_color * (6.9 * mixed_color + 0.5)) / + (mixed_color * (5.2 * mixed_color + 1.7) + 0.06); + return mixed_color; +} From 4fcbd2ada4aa53ca3e1898f346d194924bf543c4 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 18 Apr 2025 21:16:30 +0200 Subject: [PATCH 661/830] Improve the credits code - Make the credits code more organized - Add more timing variables instead of relying on obscure code tricks - Add spacing between the website button and the screen border --- data/gui/screens/credits.stkgui | 2 +- src/states_screens/credits.cpp | 224 ++++++++++++++++---------------- src/states_screens/credits.hpp | 16 ++- 3 files changed, 126 insertions(+), 116 deletions(-) diff --git a/data/gui/screens/credits.stkgui b/data/gui/screens/credits.stkgui index 5cd8c7187d2..9dc85a18b97 100644 --- a/data/gui/screens/credits.stkgui +++ b/data/gui/screens/credits.stkgui @@ -1,7 +1,7 @@ -
+
diff --git a/src/states_screens/credits.cpp b/src/states_screens/credits.cpp index 36ac32e9d5b..86289de9069 100644 --- a/src/states_screens/credits.cpp +++ b/src/states_screens/credits.cpp @@ -37,8 +37,10 @@ using irr::core::stringc; #include "utils/translation.hpp" using namespace GUIEngine; -const float TIME_SECTION_FADE = 0.8f; -const float ENTRIES_FADE_TIME = 0.3f; +const float TIME_SECTION_FADE = 0.8f; +const float TIME_PER_ENTRY = 2.4f; +const float TIME_BETWEEN_SECTIONS = 0.3f; +const float ENTRIES_FADE_TIME = 0.4f; // ---------------------------------------------------------------------------- @@ -249,43 +251,28 @@ void CreditsScreen::reset() { m_curr_section = 0; m_curr_element = -1; - time_before_next_step = TIME_SECTION_FADE; - m_time_element = 2.5f; + m_time_til_next_step = TIME_SECTION_FADE * 2; // Delay the credits roll + m_current_stage = SECTION_FADE_IN; } // reset // ---------------------------------------------------------------------------- void CreditsScreen::onDraw(float elapsed_time) { - // multiply by 0.8 to slow it down a bit as a whole - time_before_next_step -= elapsed_time*0.8f; - - const bool before_first_elem = (m_curr_element == -1); - const bool after_last_elem = - (m_curr_element >= (int)m_sections[m_curr_section].m_entries.size()); - + // TODO : make credits display speed configurable with control buttons + float m_speed = 1.0f; + m_time_til_next_step -= elapsed_time * m_speed; // ---- section name - video::SColor color = GUIEngine::getSkin()->getColor("credits_text::neutral"); video::SColor white_color( 255, 255, 255, 255 ); - // manage fade-in - if (before_first_elem) - { - // I use 425 instead of 255 so that there is a little pause after - int alpha = 425 - (int)(time_before_next_step/TIME_SECTION_FADE * 425); - if (alpha < 0) alpha = 0; - else if (alpha > 255) alpha = 255; - white_color.setAlpha( alpha ); - } - // manage fade-out - else if (after_last_elem) + // Manage fade-in and fade-out + if (m_current_stage != ELEMENTS_DISPLAY) { - // I use 425 instead of 255 so that there is a little pause after - int alpha = - (int)(time_before_next_step/TIME_SECTION_FADE * 425) - (425-255); - if (alpha < 0) alpha = 0; - else if (alpha > 255) alpha = 255; + int alpha = 255 - (int)(m_time_til_next_step/TIME_SECTION_FADE * 255); + alpha = (m_current_stage == PAUSE_BETWEEN_SECTIONS) ? 0 : + (m_current_stage == SECTION_FADE_OUT ) ? 255 - alpha : alpha; + alpha = std::max(0, std::min(255, alpha)); // Clamp between 0 and 255 white_color.setAlpha( alpha ); } @@ -294,106 +281,117 @@ void CreditsScreen::onDraw(float elapsed_time) true /* center h */, true /* center v */ ); // draw entries - if (!before_first_elem && !after_last_elem) - { - int text_offset = 0; + if (m_current_stage == ELEMENTS_DISPLAY) + drawEntries(); - // fade in - if (time_before_next_step < ENTRIES_FADE_TIME) + // Handle moving between stages + // If a section has multiple elements ; only one element is displayed at once + if (m_time_til_next_step < 0) + { + switch(m_current_stage) { - const float fade_in = time_before_next_step / ENTRIES_FADE_TIME; - - int alpha = (int)(fade_in * 255); + case SECTION_FADE_IN: + m_current_stage = ELEMENTS_DISPLAY; + m_curr_element++; + m_time_til_next_step = displayTimeForElement(m_curr_element); + break; + case ELEMENTS_DISPLAY: + m_curr_element++; - if (alpha < 0) alpha = 0; - else if (alpha > 255) alpha = 255; + // Fade out of the section after we have displayed all its elements + if (m_curr_element >= (int)m_sections[m_curr_section].m_entries.size()) + { + m_current_stage = SECTION_FADE_OUT; + m_time_til_next_step = TIME_SECTION_FADE; + break; + } - color.setAlpha( alpha ); + m_time_til_next_step = displayTimeForElement(m_curr_element); + break; + case SECTION_FADE_OUT: + m_current_stage = PAUSE_BETWEEN_SECTIONS; + m_time_til_next_step = TIME_BETWEEN_SECTIONS; + break; + case PAUSE_BETWEEN_SECTIONS: + m_current_stage = SECTION_FADE_IN; + m_time_til_next_step = TIME_SECTION_FADE; - text_offset = (int)((1.0f - fade_in) * GUIEngine::getFontHeight()); + // Switch to the next section + m_curr_section++; + m_curr_element = -1; + // Loop over if we have reached the end + if (m_curr_section >= (int)m_sections.size()) + reset(); + break; } - // fade out - else if (time_before_next_step >= m_time_element - ENTRIES_FADE_TIME) - { - const float fade_out = - (time_before_next_step - (m_time_element - ENTRIES_FADE_TIME)) - / ENTRIES_FADE_TIME; - - int alpha = 255 - (int)(fade_out * 255); - if(alpha < 0) alpha = 0; - else if(alpha > 255) alpha = 255; - color.setAlpha( alpha ); + } - text_offset = -(int)(fade_out * GUIEngine::getFontHeight()); - } +} // onDraw +// ---------------------------------------------------------------------------- - GUIEngine::getFont()->draw( - m_sections[m_curr_section].m_entries[m_curr_element] - .m_name.c_str(), - core::recti( m_x + text_offset, m_y + m_h/6, - m_x + m_w + text_offset, m_y + m_h/3 ), - color, false /* center h */, true /* center v */, NULL, - true /* ignore RTL */ ); - - const int subamount = (int)m_sections[m_curr_section] - .m_entries[m_curr_element].m_subentries.size(); - int suby = m_y + m_h/3; - const int inc = subamount == 0 ? m_h/8 - : std::min(m_h/8, - (m_h - m_h/3)/(subamount+1)); - for(int i=0; idraw(m_sections[m_curr_section] - .m_entries[m_curr_element] - .m_subentries[i].c_str(), - core::recti( m_x + GUIEngine::getFontHeight()/2, - suby + text_offset/(1+1), - m_x + m_w + GUIEngine::getFontHeight()/2, - suby + m_h/8 - + text_offset/(1+1) ), - color, false/* center h */, - true /* center v */, NULL, - true /* ignore RTL */ ); - suby += inc; - } +float CreditsScreen::displayTimeForElement(int element_id) +{ + const int count = (int)m_sections[m_curr_section].m_entries[element_id] + .m_subentries.size(); + return (TIME_PER_ENTRY + (TIME_PER_ENTRY / 3) * count); +} // displayTimeForElement - } +// ---------------------------------------------------------------------------- - // is it time to move on? - if (time_before_next_step < 0) - { - if (after_last_elem) - { - // switch to next element - m_curr_section++; - m_curr_element = -1; - time_before_next_step = TIME_SECTION_FADE; +void CreditsScreen::drawEntries() +{ + video::SColor color = GUIEngine::getSkin()->getColor("credits_text::neutral"); + int text_offset = 0; - if (m_curr_section >= (int)m_sections.size()) reset(); - } - else - { - // move on - m_curr_element++; + // Manage fade-in and fade-out + float m_fade_in_limit = displayTimeForElement(m_curr_element) - ENTRIES_FADE_TIME; - if (m_curr_element >= - (int)m_sections[m_curr_section].m_entries.size()) - { - time_before_next_step = TIME_SECTION_FADE; - } - else - { - const int count = - (int)m_sections[m_curr_section].m_entries[m_curr_element] - .m_subentries.size(); - m_time_element = 2.0f + count*0.6f; - time_before_next_step = m_time_element; - } - } + if (m_time_til_next_step >= m_fade_in_limit || m_time_til_next_step < ENTRIES_FADE_TIME) + { + float fade_factor = (m_time_til_next_step < ENTRIES_FADE_TIME) ? m_time_til_next_step : + ENTRIES_FADE_TIME - m_time_til_next_step + m_fade_in_limit; + fade_factor = fade_factor / ENTRIES_FADE_TIME; + + int alpha = (int)(fade_factor * 255); + alpha = std::max(0, std::min(255, alpha)); // Clamp between 0 and 255 + color.setAlpha(alpha); + + // Have the text move from left to right on fade-in and on fade-out + text_offset = (int)((1.0f - fade_factor) * GUIEngine::getFontHeight()); + if (m_time_til_next_step >= m_fade_in_limit) + text_offset *= -1; } -} // onUpdate + GUIEngine::getFont()->draw( + m_sections[m_curr_section].m_entries[m_curr_element].m_name.c_str(), + core::recti( m_x + text_offset, m_y + m_h/6, + m_x + m_w + text_offset, m_y + m_h/3 ), + color, false /* center h */, true /* center v */, NULL, + true /* ignore RTL */ ); + + const int subamount = (int)m_sections[m_curr_section] + .m_entries[m_curr_element].m_subentries.size(); + int suby = m_y + m_h/3; + const int inc = subamount == 0 ? m_h/8 + : std::min(m_h/8, + (m_h - m_h/3)/(subamount+1)); + for(int i=0; idraw(m_sections[m_curr_section] + .m_entries[m_curr_element] + .m_subentries[i].c_str(), + core::recti( m_x + GUIEngine::getFontHeight()/2, + suby + text_offset/(1+1), + m_x + m_w + GUIEngine::getFontHeight()/2, + suby + m_h/8 + + text_offset/(1+1) ), + color, false/* center h */, + true /* center v */, NULL, + true /* ignore RTL */ ); + suby += inc; + } +} // drawEntries // ---------------------------------------------------------------------------- diff --git a/src/states_screens/credits.hpp b/src/states_screens/credits.hpp index dc7a51f399e..9ca381da16c 100644 --- a/src/states_screens/credits.hpp +++ b/src/states_screens/credits.hpp @@ -41,7 +41,15 @@ class CreditsSection; class CreditsScreen : public GUIEngine::Screen, public GUIEngine::ScreenSingleton { - float m_time_element; + // ---------------------------------------------------------------------------------------- + /** Used to track the current stage of credit display. */ + enum CreditStage + { + SECTION_FADE_IN = 0, + ELEMENTS_DISPLAY = 1, + SECTION_FADE_OUT = 2, + PAUSE_BETWEEN_SECTIONS = 3 + }; PtrVector m_sections; CreditsSection* getCurrentSection(); @@ -52,11 +60,15 @@ class CreditsScreen : public GUIEngine::Screen, int m_curr_section; int m_curr_element; - float time_before_next_step; + CreditStage m_current_stage; + + float m_time_til_next_step; friend class GUIEngine::ScreenSingleton; CreditsScreen(); bool getLineAsWide(std::ifstream& file, core::stringw* out); + float displayTimeForElement(int element_id); + void drawEntries(); bool m_is_victory_music; void updateAreaSize(); From 0d6537b09ac91b8a775ce2dab2964f1a19d3ed8f Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 18 Apr 2025 21:19:57 +0200 Subject: [PATCH 662/830] Update changelog and credits - Add relevant assets change to the 1.5 changelog ('Oasis' and 'Hole Drop' were not present on 1.4's release and have been moved accordingly) - Improve structure of some older changelog entries - Add the initial overworld release to the changelog - Update credits for contributions in 1.5 --- CHANGELOG.md | 119 +++++++++++++++++++++++++++++++++++++-------------- data/CREDITS | 26 ++++++----- 2 files changed, 103 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a90c1545e1..fd5416a8129 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ For similar reasons, and because some features are vastly more complex than othe * Fix incorrect unlock information in Story Mode after a Grand Prix, by CodingJellyfish * Make the progression of audio levels geometrical and increase default steps, allowing to set lower audio levels and better accuracy for low audio levels (especially useful for headphone users), by Alayan * Fix drive-on sound from materials being played when the game is paused, by Alayan +* Make the switch powerup sound effect global, by Alayan * Fix a crash trying to read replays when the random starting position setting is enabled, by Alayan * Handle track names with spaces in the replay reader, by Alayan * Enable smooth scrolling for Irrlicht, by CodingJellyfish @@ -74,22 +75,31 @@ For similar reasons, and because some features are vastly more complex than othe * Generate higher resolution texture for scalable fonts, by CodingJellyfish * Various enhancements, by QwertyChouskie, Nomagno, Nstelt and others - - #### In-race UI * Add color and sound indicators when an elimination is about to happen in Follow-The-Leader, by Alayan * Correctly display the remaining time in FtL when extra-time is added, by Alayan * Show score with color on the center of speedometer in battles, by CodingJellyfish * Display correctly themed attachment icons if the base theme has been changed before the last restart, by CodingJellyfish +### Mobile +* Don't keep the rescue button active after it stops being touched, when the finger keeps touching the screen (e. g. to handle the steering wheel), by S0nter + ### Tracks and modeling -* New music for Las Dunas Arena/Las Dunas Soccer, by ALBatross -* Update Godette face texture, by ZAQraven99 +* Visually improved overworld, by Sven Andreas Belting + +#### Tracks * Fix Northern Resort skybox, by CrystalDaEevee * Various cut/checkline fixes, by CrystalDaEevee -### Mobile -* Don't keep the rescue button active after it stops being touched, when the finger keeps touching the screen (e. g. to handle the steering wheel), by S0nter +#### Karts +* Update Godette face texture, by ZAQraven99 + +#### Arenas +* XR-4R3N4 (soccer field), by CrystalDaEevee +* Hole Drop (soccer field), by CrystalDaEevee, music by DernisNW +* Oasis (soccer field), by CrystalDaEevee +* New music for Las Dunas Arena/Las Dunas Soccer, by ALBatross + ## SuperTuxKart 1.4 (31. October 2022) ### General @@ -114,16 +124,6 @@ For similar reasons, and because some features are vastly more complex than othe * Increase the use of on-demand loading for textures, by Benau * Make sky particle always fall vertically (instead of perpendicularly to the player camera), by Benau -### Tracks and modeling -* Updated Konqi, by ZAQraven99 -* New Godette kart, by ZAQraven99 -* New Hole Drop Soccer Field, by CrystalDaEevee, music by DernisNW -* New Oasis Soccer Field, by CrystalDaEevee -* Updated Battle Island and Cave X, by Typhon306 -* Fix broken invisible wall in Antediluvian Abyss, by Benau -* New textures in Shifting Sands, by KartOym -* Balanced starting positions in all official soccer fields, by CrystalDaEevee - ### Networking * Make the in-server and in-game player limits independent, allowing extra slots for spectators, by Waldlaubsaengernest * Allow using real addon karts (same hitbox and kart type as in local game), by Benau @@ -134,6 +134,20 @@ For similar reasons, and because some features are vastly more complex than othe * Add track searching to the network track screen, by Benau * Minor enhancements and fixes in the end race screen +### Tracks and modeling +#### Tracks +* Fix broken invisible wall in Antediluvian Abyss, by Benau +* New textures in Shifting Sands, by KartOym + +#### Karts +* Updated Konqi, by ZAQraven99 +* Godette kart (replaces Beastie), by ZAQraven99 + +#### Arenas +* Balanced starting positions in all official soccer fields, by CrystalDaEevee +* Updated Battle Island and Cave X, by Typhon306 + + ## SuperTuxKart 1.3 (28. September 2021) ### Networking * Server bookmarks, by Benau @@ -176,12 +190,18 @@ For similar reasons, and because some features are vastly more complex than othe * Use MojoAL instead of OpenAL, which iOS currently has issues with, by Benau ### Tracks and modeling +#### Tracks +* Add lap line extensions to Hacienda, Old Mine, Ravenbridge Mansion and Shifting Sands, by Benau + +#### Karts +* Pepper (replaces Sara the Wizard), by ZAQraven99 +* Improved Adiumy, Emule, GNU and Sara karts, by ZAQraven99 + +#### Arenas * Alien Signal, by Samuncle * Ancient Colosseum Labyrinth, by Typhon306 * Improved Las Dunas Soccer, by Benau -* Add lap line extensions to Hacienda, Old Mine, Ravenbridge Mansion and Shifting Sands, by Benau -* New Pepper kart, by ZAQraven99 -* Improved Adiumy, Emule, GNU and Sara karts, by ZAQraven99 + ## SuperTuxKart 1.2 (27. August 2020) @@ -235,7 +255,8 @@ For similar reasons, and because some features are vastly more complex than othe * New version of Kiki, by Typhon306 and ZAQraven99 * Improved karts, by CrystalDaEevee * Pidgin, Puffy -* Improved beastie animation, by D_ft Kid +* Improved Beastie animation, by D_ft Kid + ## SuperTuxKart 1.1 (4. January 2020) @@ -339,6 +360,7 @@ For similar reasons, and because some features are vastly more complex than othe #### Arenas * Pumpkin Park, by samuncle + ## SuperTuxKart 1.0 (20. April 2019) ### Networking * Networking support for normal race, time trial, free for all, capture the flag and soccer by Benau and hiker : @@ -432,6 +454,7 @@ For similar reasons, and because some features are vastly more complex than othe * New version of Beastie by Jymis * New version of Kiki by Benau + ## SuperTuxKart 0.9.3 (28. October 2017) * Reduced RAM and VRAM usage, reducing load times by Auria and Benau * New mesh format optimized for space and hardware skinning @@ -446,6 +469,7 @@ For similar reasons, and because some features are vastly more complex than othe * 3 Strikes Battles : added spare tire karts * Visual representation of the start line in all tracks * Various improvements (starting boost effect, wall driving fixes, parachutes, GP points, help page for bananas, cannon fixes, colorization shader) + ### Tracks and modeling #### Karts * Kiki by Benau @@ -453,10 +477,11 @@ For similar reasons, and because some features are vastly more complex than othe * New version of Konqi by Benau #### Tracks * All tracks drivable in reverse, with arrows pointing in the correct direction -* Candela City by samuncle (replace Shiny Suburbs) -* Cornfield Crossing by samuncle (replace Bovine Barnyard) +* Candela City by samuncle (replaces Shiny Suburbs) +* Cornfield Crossing by samuncle (replaces Bovine Barnyard) * New battle track Las Dunas Arena by samuncle + ## SuperTuxKart 0.9.2 (1. July 2016) * Ghost replay races by Benau * Battle mode AI by Benau @@ -469,17 +494,20 @@ For similar reasons, and because some features are vastly more complex than othe * Tweak to challenges * New farm track song by 0zone0ne and Krobonil * Bugfixes + ### Tracks and modeling #### Tracks -* Antediluvian Abysses by samuncle (replace Subsea) +* Antediluvian Abysses by samuncle (replaces Subsea) * Volcano Island by Ponzino * New icy soccer field by samuncle and Benau + ## SuperTuxKart 0.9.1 (17. October 2015) * Many bug fixes * Started to use scripting in tracks * Significant audio performance improvements * Tweak to challenges + ### Tracks and modeling #### Tracks * Better support for driving tracks in reverse @@ -490,6 +518,7 @@ For similar reasons, and because some features are vastly more complex than othe * Gran Paradiso Island * Subsea + ## SupertTuxKart 0.9 (24. April 2015) * Fully shader-based rendering engine * Online login which allows to: @@ -498,15 +527,17 @@ For similar reasons, and because some features are vastly more complex than othe * collect online achievements * Grand Prix editor, including creation of random GPs * Different kart physics + ### Tracks and modeling #### Karts * New karts Amanda and Gavroche by XGhost * New and improved Tux, Adiumy, Sara the Wizard and the Racer, Xue #### Tracks -* Cocoa Temple by samuncle (replace Amazonian Journey) -* Gran Paradiso Island by samuncle (replace The Island) +* Cocoa Temple by samuncle (replaces Amazonian Journey) +* Gran Paradiso Island by samuncle (replaces The Island) * Graphical improvements to many other tracks + ## SuperTuxKart 0.8.1 (26. November 2013) * New Soccer mode * New Egg Hunt mode @@ -518,12 +549,13 @@ For similar reasons, and because some features are vastly more complex than othe * Add ability to save and resume Grand Prix * Improve skid marks and nitro effects * Wiimote support + ### Tracks and modeling #### Karts * New karts Xue and Sara * Updated Beastie kart #### Tracks -* STK Enterprise by Rubberduck (replace Star Track) +* STK Enterprise by Rubberduck (replaces Star Track) * Redesign of Minigolf, by Rubberduck * New longer track layout and improved graphics for Lighthouse, by samuncle * Gameplay and graphical updates to several tracks : @@ -532,6 +564,7 @@ For similar reasons, and because some features are vastly more complex than othe #### Miscellaneous * Updated nitro models + ## SuperTuxKart 0.8 (11. December 2012) * Story mode and new challenge set * Improved AI @@ -539,10 +572,12 @@ For similar reasons, and because some features are vastly more complex than othe * Reverse mode * Updated menus * New music + ### Tracks and modeling +* New overworld for the Story Mode by Auria #### Tracks -* Green Valley by Wolfs (replace Tux Tollway) -* Blackhill Mansion by samuncle (replace Crescent Crossing) +* Green Valley by Wolfs (replaces Tux Tollway) +* Blackhill Mansion by samuncle (replaces Crescent Crossing) * New track layout and improved graphics for Shifting Sands (formerly Sand) * Gameplay and graphical updates to several tracks : * XR591 @@ -561,23 +596,26 @@ For similar reasons, and because some features are vastly more complex than othe * Improved kart control at high speeds * Better placement of rescued karts * Transition track-making to blender 2.5/2.6 + ### Tracks and modeling #### Karts * New Suzanne kart #### Tracks -* Zen Garden by samuncle (replace Secret Garden) +* Zen Garden by samuncle (replaces Secret Garden) * Minigolf, by Mac * New Subsea * New Island battle arena #### Miscellaneous * Added Thunderbird as race referee + ## SuperTuxKart 0.7.2 (15. July 2011) * Added in-game addon manager * Fixed major memory leaks * Show when you get a highscore * Improve gamepad configuration under Windows (add ability to tell gamepads apart) * Various other tweaks done and glitches fixed + ### Tracks and modeling #### Karts * New Beastie kart. @@ -585,10 +623,12 @@ For similar reasons, and because some features are vastly more complex than othe * Improved Snow Peak by samuncle * Improved Star Track UFO by Rudy + ## SuperTuxKart 0.7.1b (21. April 2011) * Fix circular dependency in challenges * Updated translations + ## SuperTuxKart 0.7.1 (15. April 2011) * Particle (smoke, splash, fire) and weather effects * Added internet news @@ -605,6 +645,7 @@ For similar reasons, and because some features are vastly more complex than othe * Fixed character names that contain non-ASCII characters * Full RTL (right to left) support * Various other tweaks done and glitches fixed + ### Tracks and modeling #### Karts * New Beagle kart by wolterh @@ -612,6 +653,7 @@ For similar reasons, and because some features are vastly more complex than othe * New Fort Magma by samuncle * New Shiny Suburbs by Horace + ## SuperTuxKart 0.7 (December 2010) Too many to list them all. Main points: @@ -623,17 +665,20 @@ Too many to list them all. Main points: * Other improvements - Allowed alternative ways/shortcuts in tracks - New item 'switch' + ### Tracks and modeling #### Tracks - Farm -- Hacienda by samuncle (replace Beach) +- Hacienda by samuncle (replaces Beach) - Scotland by Canis Lupus - Secret Garden + ## SuperTuxKart 0.6.2a (October 2009) * Bugfix: STK would crash while trying to save the config file on Windows Vista. + ## SuperTuxKart 0.6.2 (July 2009) * Bugfix: Game could crash in rare circumstances. * Bugfix: Restarting a GP (with the in-race menu ESC) would not subtract already allocated points. @@ -644,9 +689,11 @@ Too many to list them all. Main points: * Bugfix: GP result showed kart identifier instead of name. * Improvement: there is now 1 1 sec. wait period for the race result screen, avoiding the problem that someone presses space/enter at the end of a race, immediately quitting the menu before it can be read. + ## SuperTuxKart 0.6.1a (February 2009) * Bugfix: battle mode would not display track groups. + ## SuperTuxKart 0.6.1 (February 2009) * New music for Snow Mountain. * Fixed bug in track selection screen that could cause a crash when track groups were used. @@ -656,6 +703,7 @@ Too many to list them all. Main points: * A plunger in the face is now removed when restarting. * Added slow-down for karts driving backwards. * Somewhat reduced 'shaking' of AI driven karts. + ### Tracks and modeling #### Karts - New Puffy kart @@ -699,6 +747,7 @@ Too many to list them all. Main points: * Improved track : * Star track + ## SuperTuxKart 0.5 (May 2008) * Complete Challenges to unlock game modes, new tracks and a skidding preview * New Follow the Leader game mode @@ -720,6 +769,7 @@ Too many to list them all. Main points: * BSODs Battlements renamed to Fort Magma * Improved Crescent Crossing, Fort Magma, and Star Track + ## SuperTuxKart 0.4 (February 2008) * New physics handling using the bullet physics engine * Improved AI @@ -729,11 +779,12 @@ Too many to list them all. Main points: * Additional music and main theme ### Tracks and modeling #### Karts -* New kart: wilber +* New kart: Wilber #### Tracks * Improved 'Shifting Sands' and 'Lighthouse' - + + ## SuperTuxKart 0.3 (May 2007) * Highscore lists * Shortcut detection @@ -764,6 +815,7 @@ Too many to list them all. Main points: - Fixed keyboard keys unable to work on the first key press bug - And others + ## SuperTuxKart 0.2 (22. Sep 2006) * Significant performance improvement by using display lists * Improved AI @@ -782,6 +834,7 @@ Too many to list them all. Main points: * Added help and about screens, added credits to track designer * Items were added to all tracks + ## SuperTuxKart 0.1 (04. May 2006) (not officially released) * Significant speedup by using a new HOT and collision algorithm --> all tracks are now playable * Removed all SDL dependencies, only plib is needed @@ -790,12 +843,14 @@ Too many to list them all. Main points: * Some bug fixes and small improvements * Added profile option to support automatic profiling + ## SuperTuxKart 0.0.0 (22. Dec 2004) * new tracks * new characters and karts * new user-interface * some additional effects (skid-marks, smoke) + ##TuxKart v0.4.0 (March 19th 2004) * Changes for compatibility with PLIB 1.8.0 and later. * Removed some features that were only there to support diff --git a/data/CREDITS b/data/CREDITS index dcac4446d85..18de01cdbf0 100644 --- a/data/CREDITS +++ b/data/CREDITS @@ -82,14 +82,15 @@ Significant bug fixes & misc. contributions for 1.2 to 1.5 - CodedOre - Riso - mrkubax10 +- Kimden = Visual art = Tracks -- Sven Andreas Belting : Black Forest -- Mac_DMH : Minigolf -- Rubberduck : STK Enterprise -- Ponzino : Volcan Island +- Sven Andreas Belting : 'Black Forest' & Overworld improvements +- Mac_DMH : 'Minigolf' +- Rubberduck : 'STK Enterprise' +- Ponzino : 'Volcan Island' Tracks - Canis Lupus : Original 'Northern Resort' & 'Scotland' @@ -99,6 +100,7 @@ Tracks Tracks - Typhon306 : 'Ancient Colosseum Labyrinth', updated 'Battle Island' & 'Cave X' +- CrystalDaEvee: 'Oasis', 'Hole Drop' and 'XR-4R3N4' soccer fields Karts - JunglePenguin : Xue @@ -116,8 +118,9 @@ Karts Objects - GeekPenguinBR, TuxKartDriver : Models from Las Dunas Stadium -Miscellaneous -- Semphris : Item respawn animations +Semphris +- Item respawn animations, +- Improved spawn animations for the bubble gum shields and parachutes Jymis - Karts and icons @@ -230,23 +233,26 @@ Development Babies Software used - Irrlicht - Bullet +- SDL2 +- Blender - enet - curl -- freetype2 -- OpenAL + Software used +- OpenAL - ogg - vorbis - SheenBidi -- blender +- freetype2 - wiiuse -- harfbuzz Software used +- harfbuzz - sqlite - openssl - mcpp +- MojoAL = Previous contributors = From 84b214d0a307efc1b9ecbc85c1c408e12219f536 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 18 Apr 2025 22:11:03 +0200 Subject: [PATCH 663/830] Fix #5251 Also, when unchecking the 'compare replay' box, the replay that will not be shown is hidden from the list to provide greater clarity on which of the two replays remain active after disabling the comparison. If checking the box back, the second replay will show up again. --- .../dialogs/ghost_replay_info_dialog.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/states_screens/dialogs/ghost_replay_info_dialog.cpp b/src/states_screens/dialogs/ghost_replay_info_dialog.cpp index d70f3bf9ae8..d3194cc7bfa 100644 --- a/src/states_screens/dialogs/ghost_replay_info_dialog.cpp +++ b/src/states_screens/dialogs/ghost_replay_info_dialog.cpp @@ -120,10 +120,11 @@ GhostReplayInfoDialog::GhostReplayInfoDialog(unsigned int replay_id, if (m_compare_ghost) { m_watch_only = true; + m_watch_widget->setActive(false); m_record_race = false; m_record_widget->setState(false); - m_record_widget->setVisible(!m_watch_only); - getWidget("record-race-text")->setVisible(!m_watch_only); + m_record_widget->setVisible(false); + getWidget("record-race-text")->setVisible(false); } // Display this checkbox only if there is another replay file to compare with @@ -342,6 +343,11 @@ GUIEngine::EventPropagation { m_watch_only = true; m_watch_widget->setState(true); + m_watch_widget->setActive(false); + } + else + { + m_watch_widget->setActive(true); } m_record_widget->setVisible(!m_watch_only); getWidget("record-race-text")->setVisible(!m_watch_only); @@ -349,6 +355,7 @@ GUIEngine::EventPropagation refreshMainScreen(); m_replay_id = ReplayPlay::get()->getReplayIdByUID(m_rd.m_replay_uid); + updateReplayDisplayedInfo(); } return GUIEngine::EVENT_LET; From 222b4d6562ce53ffc0879f5ecd2723ceb2e91a8a Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 18 Apr 2025 22:22:46 +0200 Subject: [PATCH 664/830] Improve the ghost replay dialog - Move the info bubble to be above the control checkboxes - Don't display the info bubble if the active replay's info field is empty --- data/gui/dialogs/ghost_replay_info_dialog.stkgui | 2 +- src/states_screens/dialogs/ghost_replay_info_dialog.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/data/gui/dialogs/ghost_replay_info_dialog.stkgui b/data/gui/dialogs/ghost_replay_info_dialog.stkgui index f6f71c1ccd9..2bb13920f73 100644 --- a/data/gui/dialogs/ghost_replay_info_dialog.stkgui +++ b/data/gui/dialogs/ghost_replay_info_dialog.stkgui @@ -19,6 +19,7 @@
+
@@ -34,7 +35,6 @@
-
diff --git a/src/states_screens/dialogs/ghost_replay_info_dialog.cpp b/src/states_screens/dialogs/ghost_replay_info_dialog.cpp index d3194cc7bfa..4836b694b33 100644 --- a/src/states_screens/dialogs/ghost_replay_info_dialog.cpp +++ b/src/states_screens/dialogs/ghost_replay_info_dialog.cpp @@ -58,7 +58,10 @@ GhostReplayInfoDialog::GhostReplayInfoDialog(unsigned int replay_id, loadFromFile("ghost_replay_info_dialog.stkgui"); m_info_widget = getWidget("info"); - m_info_widget->setText(m_rd.m_info); + if (m_rd.m_info == "") + m_info_widget->setVisible(false); + else + m_info_widget->setText(m_rd.m_info); Track* track = track_manager->getTrack(m_rd.m_track_name); From 10fcbd2536f9fa36d76c855a0ece62732f1fe077 Mon Sep 17 00:00:00 2001 From: Deve Date: Fri, 18 Apr 2025 23:09:37 +0200 Subject: [PATCH 665/830] Fix possible exit crash --- lib/graphics_engine/src/ge_vulkan_driver.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index a34e25553da..11efce0f176 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -673,7 +673,7 @@ void GEVulkanDriver::destroyVulkan() m_depth_texture->drop(); m_depth_texture = NULL; } - if (m_rtt_texture) + if (m_rtt_texture && m_rtt_texture != m_separate_rtt_texture) { m_rtt_texture->drop(); m_rtt_texture = NULL; @@ -694,15 +694,16 @@ void GEVulkanDriver::destroyVulkan() m_billboard_quad = NULL; } - if (m_irrlicht_device->getSceneManager() && - m_irrlicht_device->getSceneManager()->getActiveCamera()) + if (m_irrlicht_device->getSceneManager()) { - m_irrlicht_device->getSceneManager()->setActiveCamera(NULL); + getGEConfig()->m_enable_draw_call_cache = false; + m_irrlicht_device->getSceneManager()->clear(); + if (m_irrlicht_device->getSceneManager()->getActiveCamera()) + m_irrlicht_device->getSceneManager()->setActiveCamera(NULL); + if (m_irrlicht_device->getSceneManager()->getMeshCache()) + getVulkanMeshCache()->destroy(); } - if (m_irrlicht_device->getSceneManager() && - m_irrlicht_device->getSceneManager()->getMeshCache()) - getVulkanMeshCache()->destroy(); delete m_mesh_texture_descriptor; delete m_skybox_renderer; GEVulkan2dRenderer::destroy(); From 80eabf39159711f705a36ec997242477825d059d Mon Sep 17 00:00:00 2001 From: Deve Date: Fri, 18 Apr 2025 23:50:17 +0200 Subject: [PATCH 666/830] Fix missing leak sanitizer report --- CMakeLists.txt | 1 + src/main.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 010a663f039..7037c35609b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,6 +118,7 @@ endif() if(USE_ASAN) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer") + ADD_DEFINITIONS(-DASAN_STK) endif() if(USE_TSAN) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -fno-omit-frame-pointer") diff --git a/src/main.cpp b/src/main.cpp index 9016c6bb671..6ab5c32b98c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2673,7 +2673,7 @@ int main(int argc, char *argv[]) { Log::closeOutputFiles(); #endif -#ifndef ANDROID +#if !defined(ANDROID) && !defined(ASAN_STK) fclose(stderr); fclose(stdout); #endif From b3860cb662db97deb0e7d5a1270fef1f43384364 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 20 Apr 2025 17:57:23 +0400 Subject: [PATCH 667/830] Various fixes for *mute commands and formatting - listmute got proper quoting and formatting - quoting was extracted from CM to StringUtils - wildcards for mute/unmute were fixed (however, they only can get replaced with present players for now - will be fixed for unmute later) --- src/network/protocols/command_manager.cpp | 48 +++++++---------------- src/utils/chat_manager.cpp | 29 +++++++------- src/utils/string_utils.cpp | 24 ++++++++++++ src/utils/string_utils.hpp | 2 + 4 files changed, 56 insertions(+), 47 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index b75aede7e78..d0d6b82ca3c 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2006,20 +2006,13 @@ void CommandManager::process_mute(Context& context) return; } - if (!validate(context, 1, TFT_PRESENT_USERS, false, false)) + if (!validate(context, 1, TFT_PRESENT_USERS, false, true)) return; std::string player_name = argv[1]; - player_peer = STKHost::get()->findPeerByName(StringUtils::utf8ToWide(player_name)); - - if (!player_peer || player_peer == peer) - { - error(context); - return; - } - getChatManager()->addMutedPlayerFor(peer, player_name); - getLobby()->sendStringToPeer(peer, "Muted player " + player_name); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "Muted player %s", player_name.c_str())); } // process_mute // ======================================================================== @@ -2040,16 +2033,20 @@ void CommandManager::process_unmute(Context& context) return; } - std::string player_name = argv[1]; - - if (!getChatManager()->removeMutedPlayerFor(peer, player_name)) - { - error(context); + // Should also iterate over those names muted - but later. + if (!validate(context, 1, TFT_PRESENT_USERS, false, true)) return; - } - getLobby()->sendStringToPeer(peer, "Unmuted player " + player_name); + std::string player_name = argv[1]; + std::string msg; + + if (getChatManager()->removeMutedPlayerFor(peer, player_name)) + msg = "Unmuted player %s"; + else + msg = "Player %s was already unmuted"; + getLobby()->sendStringToPeer(peer, + StringUtils::insertValues(msg, player_name.c_str())); } // process_unmute // ======================================================================== @@ -3995,25 +3992,10 @@ void CommandManager::restoreCmdByArgv(std::string& cmd, { cmd.clear(); for (int i = from; i < (int)argv.size(); ++i) { - bool quoted = false; - if (argv[i].find(c) != std::string::npos || argv[i].empty()) { - quoted = true; - } if (i > from) { cmd.push_back(c); } - if (quoted) { - cmd.push_back(d); - } - for (unsigned j = 0; j < argv[i].size(); ++j) { - if (argv[i][j] == d || argv[i][j] == e || argv[i][j] == f) { - cmd.push_back(f); - } - cmd.push_back(argv[i][j]); - } - if (quoted) { - cmd.push_back(e); - } + cmd += StringUtils::quoteEscape(argv[i], c, d, e, f); } } // restoreCmdByArgv // ======================================================================== diff --git a/src/utils/chat_manager.cpp b/src/utils/chat_manager.cpp index bf903a6fbce..69ca3784c98 100644 --- a/src/utils/chat_manager.cpp +++ b/src/utils/chat_manager.cpp @@ -54,19 +54,13 @@ void ChatManager::addMutedPlayerFor(std::shared_ptr peer, bool ChatManager::removeMutedPlayerFor(std::shared_ptr peer, const std::string& name) { - // I'm not sure why the implementation was so long auto& collection = m_peers_muted_players[std::weak_ptr(peer)]; - for (auto it = collection.begin(); it != collection.end(); ) - { - if (*it == name) - { - it = collection.erase(it); - return true; - } - else - it++; - } - return false; + auto it = collection.find(name); + if (it == collection.end()) + return false; + + collection.erase(it); + return true; } // removeMutedPlayerFor //----------------------------------------------------------------------------- @@ -87,10 +81,17 @@ std::string ChatManager::getMutedPlayersAsString(std::shared_ptr peer) int num_players = 0; for (auto& name : m_peers_muted_players[std::weak_ptr(peer)]) { - response += name; - response += " "; + response += StringUtils::quoteEscape(name, ' ', '"', '"', '\\'); + response += ", "; ++num_players; } + + if (response.size() >= 2) + { + response.resize(response.size() - 2); + response.push_back(' '); + } + if (num_players == 0) response = "No player has been muted by you"; else diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index dc0f0db576e..a0a7d28d642 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -222,7 +222,31 @@ namespace StringUtils exit(1); } } // split + //------------------------------------------------------------------------- + + std::string quoteEscape(const std::string& s, char c, + char d, char e, char f) + { + std::string ans = ""; + bool quoted = false; + + if (s.find(c) != std::string::npos || s.empty()) + quoted = true; + + if (quoted) + ans.push_back(d); + + for (unsigned j = 0; j < s.size(); ++j) { + if (s[j] == d || s[j] == e || s[j] == f) { + ans.push_back(f); + } + ans.push_back(s[j]); + } + if (quoted) + ans.push_back(e); + return ans; + } // quoteEscape //------------------------------------------------------------------------- /** Splits a string into substrings separated by a certain character, and * returns a std::vector of all those substring. E.g.: diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index 86864b448ac..d83586468e1 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -56,6 +56,8 @@ namespace StringUtils std::string toLowerCase(const std::string&); std::vector splitQuoted(const std::string& s, char c, char d, char e, char f); + std::string quoteEscape(const std::string& s, char c, + char d, char e, char f); std::vector split(const std::string& s, char c, bool keepSplitChar=false); std::vector split(const std::u32string& s, char32_t c, From a2d5500d8f8fd90a7eca207da90a8f5a670bc700 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 31 Mar 2025 02:41:00 +0400 Subject: [PATCH 668/830] Initial, by far incomplete decorator implementation It was done in January, then I got disappointed and started rewriting all code, now it doesn't seem like very nasty to have --- src/network/network_player_profile.cpp | 12 ++++ src/network/network_player_profile.hpp | 5 ++ src/network/protocols/command_manager.cpp | 70 +++++++++++-------- src/network/protocols/server_lobby.cpp | 46 ++++++++---- src/network/protocols/server_lobby.hpp | 11 +++ src/network/stk_host.cpp | 2 +- src/network/stk_peer.cpp | 6 ++ src/network/stk_peer.hpp | 2 + src/utils/chat_manager.cpp | 7 +- src/utils/chat_manager.hpp | 4 +- .../name_decorators/generic_decorator.cpp | 25 +++++++ .../name_decorators/generic_decorator.hpp | 45 ++++++++++++ src/utils/team_manager.cpp | 2 +- 13 files changed, 188 insertions(+), 49 deletions(-) create mode 100644 src/utils/name_decorators/generic_decorator.cpp create mode 100644 src/utils/name_decorators/generic_decorator.hpp diff --git a/src/network/network_player_profile.cpp b/src/network/network_player_profile.cpp index b00045d075e..ac44a2fcc03 100644 --- a/src/network/network_player_profile.cpp +++ b/src/network/network_player_profile.cpp @@ -19,6 +19,9 @@ #include "network/network_player_profile.hpp" #include "network/network_config.hpp" #include "network/stk_host.hpp" +#include "utils/string_utils.hpp" +#include "utils/name_decorators/generic_decorator.hpp" + // ---------------------------------------------------------------------------- /** Returns true if this player is local, i.e. running on this computer. This @@ -31,3 +34,12 @@ bool NetworkPlayerProfile::isLocalPlayer() const return NetworkConfig::get()->isClient() && m_host_id == STKHost::get()->getMyHostId(); } // isLocalPlayer + +// ---------------------------------------------------------------------------- +/** Asks decorator for a name to show in a certain conditions. + */ +core::stringw NetworkPlayerProfile::getDecoratedName(std::shared_ptr decorator) +{ + return StringUtils::utf8ToWide(decorator->decorate(StringUtils::wideToUtf8(m_player_name))); +} // getDecoratedName +// ---------------------------------------------------------------------------- diff --git a/src/network/network_player_profile.hpp b/src/network/network_player_profile.hpp index 1e68278851b..7df9c6eca40 100644 --- a/src/network/network_player_profile.hpp +++ b/src/network/network_player_profile.hpp @@ -33,6 +33,7 @@ #include class STKPeer; +class GenericDecorator; enum KartTeam : int8_t; enum HandicapLevel : uint8_t; @@ -188,6 +189,10 @@ class NetworkPlayerProfile void setKartData(const KartData& data) { m_kart_data = data; } // ------------------------------------------------------------------------ const KartData& getKartData() const { return m_kart_data; } + // ------------------------------------------------------------------------ + core::stringw getDecoratedName(std::shared_ptr decorator); + // ------------------------------------------------------------------------ + }; // class NetworkPlayerProfile #endif // HEADER_NETWORK_PLAYER_PROFILE diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index d0d6b82ca3c..2cafc5f61aa 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -1006,7 +1006,7 @@ void CommandManager::process_auth(Context& context) + command->getFullName(); else { - auto profile = peer->getPlayerProfiles()[0]; + auto profile = peer->getMainProfile(); std::string username = StringUtils::wideToUtf8(profile->getName()); int online_id = profile->getOnlineId(); if (online_id == 0) @@ -1319,7 +1319,7 @@ void CommandManager::process_addons(Context& context) ))); if (apply_filters) getAssetManager()->applyAllFilters(from, false); // happily the type is never karts in this line - std::vector>> result; + std::vector>>> result; for (const std::string& s: from) result.push_back({s, {}}); @@ -1335,19 +1335,18 @@ void CommandManager::process_addons(Context& context) if (!p->hasPlayerProfiles()) continue; ++num_players; - std::string username = p->getMainName(); const auto& kt = p->getClientAssets(); const auto& container = (argv[1] == "kart" ? kt.first : kt.second); for (auto& pr: result) if (container.find(pr.first) == container.end()) - pr.second.push_back(username); + pr.second.push_back(p->getMainProfile()); } std::random_device rd; std::mt19937 g(rd()); std::shuffle(result.begin(), result.end(), g); std::stable_sort(result.begin(), result.end(), - [](const std::pair>& a, - const std::pair>& b) -> bool { + [](const std::pair>>& a, + const std::pair>>& b) -> bool { if (a.second.size() != b.second.size()) return a.second.size() > b.second.size(); return false; @@ -1367,15 +1366,15 @@ void CommandManager::process_addons(Context& context) { auto result2 = result; result.clear(); - std::string asking_username = ""; + std::shared_ptr asker = {}; if (peer->hasPlayerProfiles()) - asking_username = peer->getMainName(); + asker = peer->getMainProfile(); for (unsigned i = 0; i < result2.size(); ++i) { bool present = false; for (unsigned j = 0; j < result2[i].second.size(); ++j) { - if (result2[i].second[j] == asking_username) + if (result2[i].second[j] == asker) { present = true; break; @@ -1417,7 +1416,7 @@ void CommandManager::process_addons(Context& context) std::sort(result[i].second.begin(), result[i].second.end()); for (unsigned j = 0; j < result[i].second.size(); ++j) { - response += " " + result[i].second[j]; + response += " " + getLobby()->encodeProfileNameForPeer(result[i].second[j], peer.get()); } } } @@ -1451,7 +1450,7 @@ void CommandManager::process_checkaddon(Context& context) const unsigned HAS_MAP = 2; unsigned server_status = 0; - std::vector players[4]; + std::vector> players[4]; auto asset_manager = getAssetManager(); if (asset_manager->hasAddonKart(id)) @@ -1470,14 +1469,14 @@ void CommandManager::process_checkaddon(Context& context) || !getCrownManager()->canRace(p) || p->isCommandSpectator() || !p->hasPlayerProfiles()) continue; - std::string username = p->getMainName(); + const auto& kt = p->getClientAssets(); unsigned status = 0; if (kt.first.find(id) != kt.first.end()) status |= HAS_KART; if (kt.second.find(id) != kt.second.end()) status |= HAS_MAP; - players[status].push_back(username); + players[status].push_back(p->getMainProfile()); } std::string response = ""; @@ -1512,10 +1511,10 @@ void CommandManager::process_checkaddon(Context& context) response += "doesn't have"; response += " " + item_name[item] + " " + argv[1] + "\n"; - std::vector categories[2]; + std::vector> categories[2]; for (unsigned status = 0; status < 4; ++status) { - for (const std::string& s: players[status]) + for (const std::shared_ptr& s: players[status]) categories[(status & item ? 1 : 0)].push_back(s); } for (int i = 0; i < 2; ++i) @@ -1534,7 +1533,7 @@ void CommandManager::process_checkaddon(Context& context) { if (j) response += ", "; - response += categories[i][j]; + response += getLobby()->encodeProfileNameForPeer(categories[i][j], peer.get()); } if (categories[i].size() > 5) response += ", ..."; @@ -1892,7 +1891,7 @@ void CommandManager::process_everypas(Context& context) if (argv.size() > 2) sorting_direction = argv[2]; std::string response = "Addon scores:"; - using Pair = std::pair>; + using Pair = std::pair, std::vector>; std::vector result; for (const auto& p: STKHost::get()->getPeers()) { @@ -1900,12 +1899,11 @@ void CommandManager::process_everypas(Context& context) continue; if (!p->hasPlayerProfiles()) continue; - std::string player_name = p->getMainName(); auto &scores = p->getAddonsScores(); std::vector overall; for (int item = 0; item < AS_TOTAL; item++) overall.push_back(scores[item]); - result.emplace_back(player_name, overall); + result.emplace_back(p->getMainProfile(), overall); } int sorting_idx = -1; if (sorting_type == "kart" || sorting_type == "karts") @@ -1918,17 +1916,24 @@ void CommandManager::process_everypas(Context& context) sorting_idx = 3; if (sorting_idx != -1) { + // Sorting order for equal players WILL DEPEND ON NAME DECORATOR! + // This sorting is clearly bad because we ask lobby every time. Change it later. + auto lobby = getLobby(); + std::stable_sort(result.begin(), result.end(), [lobby, peer](const Pair& lhs, const Pair& rhs) -> bool { + return lobby->encodeProfileNameForPeer(lhs.first, peer.get()) + < lobby->encodeProfileNameForPeer(rhs.first, peer.get()); + }); if (sorting_direction == "asc") std::sort(result.begin(), result.end(), [sorting_idx] (const Pair& lhs, const Pair& rhs) -> bool { int diff = lhs.second[sorting_idx] - rhs.second[sorting_idx]; - return (diff < 0 || (diff == 0 && lhs.first < rhs.first)); + return diff < 0; }); else - std::sort(result.begin(), result.end(), [sorting_idx] + std::stable_sort(result.begin(), result.end(), [sorting_idx] (const Pair& lhs, const Pair& rhs) -> bool { int diff = lhs.second[sorting_idx] - rhs.second[sorting_idx]; - return (diff > 0 || (diff == 0 && lhs.first < rhs.first)); + return diff > 0; }); } // I don't really know if it should be soccer or field, both are used @@ -1936,7 +1941,7 @@ void CommandManager::process_everypas(Context& context) std::vector desc = { "karts", "tracks", "arenas", "fields" }; for (auto& row: result) { - response += "\n" + row.first; + response += "\n" + getLobby()->encodeProfileNameForPeer(row.first, peer.get()); bool negative = true; for (int item = 0; item < AS_TOTAL; item++) negative &= row.second[item] == -1; @@ -3137,7 +3142,7 @@ void CommandManager::process_register(Context& context) } if (!peer->hasPlayerProfiles()) return; - int online_id = peer->getPlayerProfiles()[0]->getOnlineId(); + int online_id = peer->getMainProfile()->getOnlineId(); if (online_id <= 0) { getLobby()->sendStringToPeer(peer, "Please join with a valid online STK account."); @@ -3338,7 +3343,7 @@ void CommandManager::process_role(Context& context) if (player_peer) { if (player_peer->hasPlayerProfiles()) - getTeamManager()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_RED); + getTeamManager()->setTeamInLobby(player_peer->getMainProfile(), KART_TEAM_RED); getLobby()->sendStringToPeer(player_peer, StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } @@ -3358,7 +3363,7 @@ void CommandManager::process_role(Context& context) if (player_peer) { if (player_peer->hasPlayerProfiles()) - getTeamManager()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_BLUE); + getTeamManager()->setTeamInLobby(player_peer->getMainProfile(), KART_TEAM_BLUE); getLobby()->sendStringToPeer(player_peer, StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } @@ -3371,7 +3376,7 @@ void CommandManager::process_role(Context& context) if (player_peer) { if (player_peer->hasPlayerProfiles()) - getTeamManager()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); + getTeamManager()->setTeamInLobby(player_peer->getMainProfile(), KART_TEAM_NONE); getLobby()->sendStringToPeer(player_peer, StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } @@ -3382,7 +3387,7 @@ void CommandManager::process_role(Context& context) if (player_peer) { if (player_peer->hasPlayerProfiles()) - getTeamManager()->setTeamInLobby(player_peer->getPlayerProfiles()[0], KART_TEAM_NONE); + getTeamManager()->setTeamInLobby(player_peer->getMainProfile(), KART_TEAM_NONE); getLobby()->sendStringToPeer(player_peer, StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } @@ -3542,7 +3547,8 @@ void CommandManager::process_test(Context& context) std::string username = "Vote"; if (peer.get() && peer->hasPlayerProfiles()) { - username = peer->getMainName(); + username = getLobby()->encodeProfileNameForPeer( + peer->getMainProfile(), peer.get()); } username = "{" + argv[1].substr(4) + "} " + username; getLobby()->sendStringToAllPeers(username + ", " + argv[2] + ", " + argv[3]); @@ -3804,9 +3810,13 @@ void CommandManager::process_why_hourglass(Context& context) error(context); return; } + + std::string encoded_name = getLobby()->encodeProfileNameForPeer( + player_peer->getMainProfile(), peer.get()); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( getCrownManager()->getWhyPeerCannotPlayAsString(player_peer), - player_name)); + encoded_name)); } // process_why_hourglass // ======================================================================== diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index d0d534b5514..dfb40eecf5a 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -60,6 +60,7 @@ #include "utils/lobby_settings.hpp" #include "utils/lobby_queues.hpp" #include "utils/map_vote_handler.hpp" +#include "utils/name_decorators/generic_decorator.hpp" #include "utils/team_manager.hpp" #include "utils/tournament.hpp" #include "utils/translation.hpp" @@ -77,13 +78,14 @@ namespace { void encodePlayers(BareNetworkString* bns, - std::vector >& players) + std::vector >& players, + const std::shared_ptr& decorator) { bns->addUInt8((uint8_t)players.size()); for (unsigned i = 0; i < players.size(); i++) { std::shared_ptr& player = players[i]; - bns->encodeString(player->getName()) + bns->encodeString(player->getDecoratedName(decorator)) .addUInt32(player->getHostId()) .addFloat(player->getDefaultKartColor()) .addUInt32(player->getOnlineId()) @@ -239,6 +241,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_ranking = std::make_shared(); } + m_name_decorator = std::make_shared(); m_items_complete_state = new BareNetworkString(); m_server_id_online.store(0); m_difficulty.store(ServerConfig::m_server_difficulty); @@ -371,7 +374,7 @@ void ServerLobby::handleChat(Event* event) target_team = (KartTeam)event->data().getUInt8(); getChatManager()->handleNormalChatMessage(peer, - StringUtils::wideToUtf8(message), target_team); + StringUtils::wideToUtf8(message), target_team, m_name_decorator); } // handleChat //----------------------------------------------------------------------------- @@ -509,7 +512,7 @@ void ServerLobby::pollDatabase() } if (!is_kicked && !p->getPlayerProfiles().empty()) { - uint32_t online_id = p->getPlayerProfiles()[0]->getOnlineId(); + uint32_t online_id = p->getMainProfile()->getOnlineId(); for (auto& item: online_id_ban_list) { if (item.online_id == online_id) @@ -556,7 +559,7 @@ void ServerLobby::writePlayerReport(Event* event) std::shared_ptr reporter = event->getPeerSP(); if (!reporter->hasPlayerProfiles()) return; - auto reporter_npp = reporter->getPlayerProfiles()[0]; + auto reporter_npp = reporter->getMainProfile(); uint32_t reporting_host_id = event->data().getUInt32(); core::stringw info; @@ -567,7 +570,7 @@ void ServerLobby::writePlayerReport(Event* event) auto reporting_peer = STKHost::get()->findPeerByHostId(reporting_host_id); if (!reporting_peer || !reporting_peer->hasPlayerProfiles()) return; - auto reporting_npp = reporting_peer->getPlayerProfiles()[0]; + auto reporting_npp = reporting_peer->getMainProfile(); bool written = db_connector->writeReport(reporter, reporter_npp, reporting_peer, reporting_npp, info); @@ -977,7 +980,7 @@ NetworkString* ServerLobby::getLoadWorldMessage( load_world_message->addUInt8(LE_LOAD_WORLD); getSettings()->encodeDefaultVote(load_world_message); load_world_message->addUInt8(live_join ? 1 : 0); - encodePlayers(load_world_message, players); + encodePlayers(load_world_message, players, m_name_decorator); load_world_message->addUInt32(m_item_seed); if (RaceManager::get()->isBattleMode()) { @@ -1290,7 +1293,7 @@ void ServerLobby::finishedLoadingLiveJoinClient(Event* event) // starting of race std::vector > players = getLivePlayers(); - encodePlayers(ns, players); + encodePlayers(ns, players, m_name_decorator); for (unsigned i = 0; i < players.size(); i++) players[i]->getKartData().encode(ns); } @@ -2699,7 +2702,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, if (getSettings()->isRanked()) { - getRankingForPlayer(peer->getPlayerProfiles()[0]); + getRankingForPlayer(peer->getMainProfile()); } } @@ -2820,7 +2823,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) for (auto profile : all_profiles) { PlayerListProfilePacket packet; - auto profile_name = profile->getName(); + auto profile_name = profile->getDecoratedName(m_name_decorator); // get OS information auto version_os = StringUtils::extractVersionOS(profile->getPeer()->getUserVersion()); @@ -3024,9 +3027,12 @@ void ServerLobby::handlePlayerVote(Event* event) } // Store vote: - vote.m_player_name = event->getPeer()->getPlayerProfiles()[0]->getName(); + vote.m_player_name = event->getPeer()->getMainProfile()->getName(); addVote(event->getPeer()->getHostId(), vote); + // After adding the vote, show decorated name instead + vote.m_player_name = event->getPeer()->getMainProfile()->getDecoratedName(m_name_decorator); + // Now inform all clients about the vote NetworkString other = NetworkString(PROTOCOL_LOBBY_ROOM); other.setSynchronous(true); @@ -3352,7 +3358,7 @@ void ServerLobby::addWaitingPlayersToGame() uint32_t online_id = profile->getOnlineId(); if (getSettings()->isRanked() && !m_ranking->has(online_id)) { - getRankingForPlayer(peer->getPlayerProfiles()[0]); + getRankingForPlayer(peer->getMainProfile()); } } // Re-activiate the ai @@ -4171,7 +4177,7 @@ void ServerLobby::writeOwnReport(std::shared_ptr reporter, std::shared_ reporting = reporter; if (!reporter->hasPlayerProfiles()) return; - auto reporter_npp = reporter->getPlayerProfiles()[0]; + auto reporter_npp = reporter->getMainProfile(); if (info.empty()) return; @@ -4179,7 +4185,7 @@ void ServerLobby::writeOwnReport(std::shared_ptr reporter, std::shared_ if (!reporting->hasPlayerProfiles()) return; - auto reporting_npp = reporting->getPlayerProfiles()[0]; + auto reporting_npp = reporting->getMainProfile(); bool written = db_connector->writeReport(reporter, reporter_npp, reporting, reporting_npp, info_w); @@ -4227,6 +4233,16 @@ void ServerLobby::sendStringToAllPeers(const std::string& s) } // sendStringToAllPeers //----------------------------------------------------------------------------- +std::string ServerLobby::encodeProfileNameForPeer( + std::shared_ptr npp, + STKPeer* peer) +{ + if (npp) + return StringUtils::wideToUtf8(npp->getDecoratedName(m_name_decorator)); + return ""; +} // encodeProfileNameForPeer +//----------------------------------------------------------------------------- + bool ServerLobby::canVote(std::shared_ptr peer) const { if (!peer || peer->getPlayerProfiles().empty()) @@ -4299,7 +4315,7 @@ bool ServerLobby::writeOnePlayerReport(std::shared_ptr reporter, return false; if (!reporter->hasPlayerProfiles()) return false; - auto reporter_npp = reporter->getPlayerProfiles()[0]; + auto reporter_npp = reporter->getMainProfile(); auto info_w = StringUtils::utf8ToWide(info); bool written = db_connector->writeReport(reporter, reporter_npp, diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 4b12fea64e8..d45022f7dd2 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -44,6 +44,7 @@ class BareNetworkString; class CommandManager; class DatabaseConnector; +class GenericDecorator; class HitProcessor; class KartElimination; class LobbyAssetManager; @@ -174,6 +175,8 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser std::shared_ptr m_ranking; + std::shared_ptr m_name_decorator; + unsigned m_item_seed; uint64_t m_client_starting_time; @@ -331,7 +334,15 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser // int getTrackMaxPlayers(std::string& name) const; void sendStringToPeer(std::shared_ptr peer, const std::string& s); + + // TODO: When using different decorators for everyone, you would need + // a structure to store "player profile" placeholders in a string, so that + // you can apply decorators at the very last moment inside sendStringToAllPeers + // and similar functions. void sendStringToAllPeers(const std::string& s); + std::string encodeProfileNameForPeer( + std::shared_ptr npp, + STKPeer* peer); int getPermissions(std::shared_ptr peer) const; bool isSoccerGoalTarget() const; diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index adc7c91a6a7..c378114da14 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -1446,7 +1446,7 @@ std::set STKHost::getAllPlayerOnlineIds() const if (!peer.second->getPlayerProfiles().empty()) { online_ids.insert( - peer.second->getPlayerProfiles()[0]->getOnlineId()); + peer.second->getMainProfile()->getOnlineId()); } } lock.unlock(); diff --git a/src/network/stk_peer.cpp b/src/network/stk_peer.cpp index 5032ecde567..5d10a76218b 100644 --- a/src/network/stk_peer.cpp +++ b/src/network/stk_peer.cpp @@ -197,6 +197,12 @@ void STKPeer::setCrypto(std::unique_ptr&& c) } // setCrypto // ---------------------------------------------------------------------------- +std::shared_ptr STKPeer::getMainProfile() +{ + return m_players[0]; +} // getMainProfile +// ---------------------------------------------------------------------------- + // A method for convenience only. // For now, returns an empty string if there are no profiles. // Might be better to throw an exception. I will see later. diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index efd0f91d556..17a3a3bd8a3 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -383,6 +383,8 @@ class STKPeer : public NoCopy // ------------------------------------------------------------------------ void setAngryHost(bool val) { m_angry_host.store(val); } // ------------------------------------------------------------------------ + std::shared_ptr getMainProfile(); + // ------------------------------------------------------------------------ std::string getMainName() const; // ------------------------------------------------------------------------ }; // STKPeer diff --git a/src/utils/chat_manager.cpp b/src/utils/chat_manager.cpp index 69ca3784c98..d483db03528 100644 --- a/src/utils/chat_manager.cpp +++ b/src/utils/chat_manager.cpp @@ -163,7 +163,8 @@ void ChatManager::onPeerDisconnect(std::shared_ptr peer) //----------------------------------------------------------------------------- void ChatManager::handleNormalChatMessage(std::shared_ptr peer, - std::string message, KartTeam target_team) + std::string message, KartTeam target_team, + const std::shared_ptr& decorator) { // Update so that the peer is not kicked peer->updateLastActivity(); @@ -195,6 +196,10 @@ void ChatManager::handleNormalChatMessage(std::shared_ptr peer, return; } + std::string new_prefix = StringUtils::wideToUtf8( + peer->getMainProfile()->getDecoratedName(decorator)) + ": "; + message = new_prefix + message.substr(prefix.length()); + if (message.size() == 0) return; diff --git a/src/utils/chat_manager.hpp b/src/utils/chat_manager.hpp index e3523cb5a30..a060837c816 100644 --- a/src/utils/chat_manager.hpp +++ b/src/utils/chat_manager.hpp @@ -31,6 +31,7 @@ class STKPeer; enum KartTeam : int8_t; struct KartTeamSet; +class GenericDecorator; class ChatManager: public LobbyContextComponent { @@ -78,7 +79,8 @@ class ChatManager: public LobbyContextComponent int getChatConsecutiveInterval() const { return m_chat_consecutive_interval; } void handleNormalChatMessage(std::shared_ptr peer, - std::string message, KartTeam target_team); + std::string message, KartTeam target_team, + const std::shared_ptr& decorator); bool shouldMessageBeSent(std::shared_ptr sender, std::shared_ptr target, diff --git a/src/utils/name_decorators/generic_decorator.cpp b/src/utils/name_decorators/generic_decorator.cpp new file mode 100644 index 00000000000..12c8fcf53a4 --- /dev/null +++ b/src/utils/name_decorators/generic_decorator.cpp @@ -0,0 +1,25 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2004-2020 Steve Baker , +// Copyright (C) 2004-2020 Ingo Ruhnke +// Copyright (C) 2006-2020 SuperTuxKart-Team +// Copyright (C) 2020 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/name_decorators/generic_decorator.hpp" + + +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/name_decorators/generic_decorator.hpp b/src/utils/name_decorators/generic_decorator.hpp new file mode 100644 index 00000000000..effd2e2255f --- /dev/null +++ b/src/utils/name_decorators/generic_decorator.hpp @@ -0,0 +1,45 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2004-2020 Steve Baker , +// Copyright (C) 2004-2020 Ingo Ruhnke +// Copyright (C) 2006-2020 SuperTuxKart-Team +// Copyright (C) 2020 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef GENERIC_DECORATOR_HPP +#define GENERIC_DECORATOR_HPP + +// #include "network/network_player_profile.hpp" +// #include "utils/types.hpp" +// #include +#include +// #include +// #include +// #include +// #include + +class GenericDecorator +{ +public: + virtual std::string decorate(const std::string& s) + { + return s; + } +}; + + + +#endif diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp index 7cd2f1b6d99..c78a9e71ce9 100644 --- a/src/utils/team_manager.cpp +++ b/src/utils/team_manager.cpp @@ -424,7 +424,7 @@ void TeamManager::changeColors() { // kimden: you assume that only [0] can be checked, but in other places // of the code you are somehow not so sure about that... :) - auto pp = peer->getPlayerProfiles()[0]; + auto pp = peer->getMainProfile(); if (pp->getTeam() == KART_TEAM_RED) setTeamInLobby(pp, KART_TEAM_BLUE); else if (pp->getTeam() == KART_TEAM_BLUE) From 9d050d7b31f3688e3ee2e537b7268f9a13afcfb6 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 2 Apr 2025 03:35:26 +0400 Subject: [PATCH 669/830] =?UTF-8?q?updateServerOwner=20=E2=86=92=20CrownMa?= =?UTF-8?q?nager=20minus=20sort?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/network/protocols/server_lobby.cpp | 76 +++++++++++++++----------- src/utils/crown_manager.cpp | 29 ++++++++++ src/utils/crown_manager.hpp | 6 ++ 3 files changed, 79 insertions(+), 32 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index dfb40eecf5a..fa1395cddd5 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2906,54 +2906,65 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) }, pl); delete pl; } // updatePlayerList - //----------------------------------------------------------------------------- + void ServerLobby::updateServerOwner(bool force) { - if (m_state.load() < WAITING_FOR_START_GAME || - m_state.load() > RESULT_DISPLAY || - getCrownManager()->isOwnerLess()) + ServerState state = m_state.load(); + if (state < WAITING_FOR_START_GAME || state > RESULT_DISPLAY) + return; + + if (getCrownManager()->isOwnerLess()) return; + if (!force && !m_server_owner.expired()) return; + auto peers = STKHost::get()->getPeers(); - if (peers.empty()) - return; - std::sort(peers.begin(), peers.end(), [](const std::shared_ptr a, - const std::shared_ptr b)->bool - { - if (a->isCommandSpectator() ^ b->isCommandSpectator()) - return b->isCommandSpectator(); - return a->getRejoinTime() < b->getRejoinTime(); - }); - std::shared_ptr owner; - for (auto peer: peers) + if (m_process_type != PT_MAIN) { - // Only matching host id can be server owner in case of - // graphics-client-server - if (peer->isValidated() && !peer->isAIPeer() && - (m_process_type == PT_MAIN || - peer->getHostId() == m_client_server_host_id.load())) + auto id = m_client_server_host_id.load(); + for (unsigned i = 0; i < peers.size(); ) { - owner = peer; - break; + const auto& peer = peers[i]; + if (peer->getHostId() != id) + { + std::swap(peers[i], peers.back()); + peers.pop_back(); + continue; + } + ++i; } } - if (owner) + + for (unsigned i = 0; i < peers.size(); ) { - if (m_server_owner.expired() || m_server_owner.lock() != owner) + const auto& peer = peers[i]; + if (!peer->isValidated() || peer->isAIPeer()) { - NetworkString* ns = getNetworkString(); - ns->setSynchronous(true); - ns->addUInt8(LE_SERVER_OWNERSHIP); - owner->sendPacket(ns); - delete ns; + std::swap(peers[i], peers.back()); + peers.pop_back(); + continue; } - m_server_owner = owner; - m_server_owner_id.store(owner->getHostId()); - updatePlayerList(); + ++i; } + + if (peers.empty()) + return; + + std::shared_ptr owner = getCrownManager()->getFirstInCrownOrder(peers); + if (m_server_owner.expired() || m_server_owner.lock() != owner) + { + NetworkString* ns = getNetworkString(); + ns->setSynchronous(true); + ns->addUInt8(LE_SERVER_OWNERSHIP); + owner->sendPacket(ns); + delete ns; + } + m_server_owner = owner; + m_server_owner_id.store(owner->getHostId()); + updatePlayerList(); } // updateServerOwner //----------------------------------------------------------------------------- @@ -3620,6 +3631,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, auto assets = peer->getClientAssets(); if (!peer->isValidated() || assets.second.empty()) // this check will fail hard when I introduce vavriable limits continue; + if (getAssetManager()->checkIfNoCommonMaps(assets)) { NetworkString *message = getNetworkString(2); diff --git a/src/utils/crown_manager.cpp b/src/utils/crown_manager.cpp index 3493103d690..65da8cd3f70 100644 --- a/src/utils/crown_manager.cpp +++ b/src/utils/crown_manager.cpp @@ -278,4 +278,33 @@ void CrownManager::setSpectateModeProperly(std::shared_ptr peer, Always if (mode == ASM_NONE) getTeamManager()->checkNoTeamSpectator(peer); } // setSpectateModeProperly +//----------------------------------------------------------------------------- + +// This was a sorting comparator in original code. +// Peers are guaranteed to already be validated and non-AI, +// and eligible for crown (theoretically) +std::shared_ptr CrownManager::getFirstInCrownOrder( + const std::vector>& peers) +{ + if (peers.empty()) // Shouldn't happen but just in case + return {}; + + unsigned best = 0; + for (unsigned i = 1; i < peers.size(); ++i) + if (defaultOrderComparator(peers[i], peers[best])) + best = i; + + return peers[best]; +} // getFirstInCrownOrder +//----------------------------------------------------------------------------- + +bool CrownManager::defaultOrderComparator( + const std::shared_ptr a, + const std::shared_ptr b) +{ + if (a->isCommandSpectator() ^ b->isCommandSpectator()) + return b->isCommandSpectator(); + + return a->getRejoinTime() < b->getRejoinTime(); +} // defaultOrderComparator //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/crown_manager.hpp b/src/utils/crown_manager.hpp index bf2c3ce0a83..e1731a16971 100644 --- a/src/utils/crown_manager.hpp +++ b/src/utils/crown_manager.hpp @@ -50,6 +50,12 @@ class CrownManager: public LobbyContextComponent void setSpectateModeProperly(std::shared_ptr peer, AlwaysSpectateMode mode); + std::shared_ptr getFirstInCrownOrder( + const std::vector>& peers); + + bool defaultOrderComparator(const std::shared_ptr a, + const std::shared_ptr b); + private: bool m_only_host_riding; bool m_owner_less; From c5a8651a30f179476ab73fafa4ce9e6fefefff46 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 2 Apr 2025 23:16:55 +0400 Subject: [PATCH 670/830] Minus one method --- src/network/protocols/server_lobby.cpp | 19 ++++++------------- src/network/protocols/server_lobby.hpp | 1 - 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index fa1395cddd5..56ef46c45a6 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1049,7 +1049,9 @@ void ServerLobby::rejectLiveJoin(std::shared_ptr peer, BackLobbyReason reset->addUInt8(LE_BACK_LOBBY).addUInt8(blr); peer->sendPacket(reset, PRM_RELIABLE); delete reset; + updatePlayerList(); + NetworkString* server_info = getNetworkString(); server_info->setSynchronous(true); server_info->addUInt8(LE_SERVER_INFO); @@ -2059,7 +2061,10 @@ void ServerLobby::checkRaceFinished() if (getSettings()->isStoringResults()) { - storeResults(); + if (m_game_info) + m_game_info->fillAndStoreResults(); + else + Log::warn("ServerLobby", "GameInfo is not accessible??"); } if (getSettings()->isRanked()) @@ -4158,18 +4163,6 @@ void ServerLobby::handleServerCommand(Event* event) } // handleServerCommand //----------------------------------------------------------------------------- -void ServerLobby::storeResults() -{ - if (!m_game_info) - { - Log::warn("ServerLobby", "GameInfo is not accessible??"); - return; - } - - m_game_info->fillAndStoreResults(); -} // storeResults -//----------------------------------------------------------------------------- - void ServerLobby::resetToDefaultSettings() { if (getSettings()->isServerConfigurable() && !getSettings()->isPreservingMode()) diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index d45022f7dd2..5f0d1b01423 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -323,7 +323,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser return std::find(m_ai_profiles.begin(), m_ai_profiles.end(), npp) != m_ai_profiles.end(); } - void storeResults(); uint32_t getServerIdOnline() const { return m_server_id_online; } void setClientServerHostId(uint32_t id) { m_client_server_host_id = id; } void resetToDefaultSettings(); From 8eb0db23e1825bd1ee45cb5545839acf4b47767b Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sun, 20 Apr 2025 17:11:18 +0200 Subject: [PATCH 671/830] Remove duplicated code Tabs and vertical tab ribbons can use the same creation code to add children elements --- src/guiengine/widgets/ribbon_widget.cpp | 60 ++----------------------- 1 file changed, 3 insertions(+), 57 deletions(-) diff --git a/src/guiengine/widgets/ribbon_widget.cpp b/src/guiengine/widgets/ribbon_widget.cpp index 1b8b76ef728..ceafa8af654 100644 --- a/src/guiengine/widgets/ribbon_widget.cpp +++ b/src/guiengine/widgets/ribbon_widget.cpp @@ -110,8 +110,8 @@ void RibbonWidget::add() // so care must be taken to not break things for (int i=0; iaddButton(init_rect, btn, - same_id, L"", L""); - - IGUIButton* icon = - GUIEngine::getGUIEnv()->addButton(init_rect, tab, - same_id, L""); - icon->setScaleImage(true); - std::string filename = GUIEngine::getSkin()->getThemedIcon( - m_active_children[i].m_properties[PROP_ICON]); - icon->setImage( irr_driver->getTexture(filename.c_str()) ); - icon->setUseAlphaChannel(true); - icon->setDrawBorder(false); - icon->setTabStop(false); - - IGUIStaticText* label = - GUIEngine::getGUIEnv()->addStaticText(message.c_str(), - init_rect, - false /* border */, - true /* word wrap */, - tab, same_id); - - label->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER); - label->setTabStop(false); - label->setNotClipped(true); - m_labels.push_back(label); - m_child_data[i] = std::make_pair(label, icon); - - tab->setTabStop(false); - tab->setTabGroup(false); - } - else - { - Log::error("RibbonWidget", "Invalid tab bar contents"); - } - - m_active_children[i].m_element = tab; - } // vertical-tabs - + } // tabs and vertical tabs // ---- icon ribbons else if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) From 952ef1887e7c843db036a7366bc051dcf93d8297 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sun, 20 Apr 2025 19:38:04 +0200 Subject: [PATCH 672/830] Improve the code for tab dimensions - Avoid duplicating a lot of code between tabs and vertical tabs - Add a few enhancements to tab logic that were present for vertical tabs: -- Make the font smaller if there is not enough height for a split message (fix text overflow issues in the highscore tabs) -- Avoid an icon taking more than half the tab's width --- src/guiengine/widgets/ribbon_widget.cpp | 193 ++++++++---------------- 1 file changed, 67 insertions(+), 126 deletions(-) diff --git a/src/guiengine/widgets/ribbon_widget.cpp b/src/guiengine/widgets/ribbon_widget.cpp index ceafa8af654..a4342c9b42e 100644 --- a/src/guiengine/widgets/ribbon_widget.cpp +++ b/src/guiengine/widgets/ribbon_widget.cpp @@ -734,10 +734,10 @@ void RibbonWidget::resize() const int button_y = GUIEngine::getFontHeight() / 5; - const int one_button_width = (subbuttons_amount == 0 ? m_w : + const int one_button_width = ((subbuttons_amount == 0 || getRibbonType() == RIBBON_VERTICAL_TABS) ? m_w : int(roundf((float)m_w / (float)subbuttons_amount))); - const int one_button_height = (subbuttons_amount == 0 ? m_h : + const int one_button_height = ((subbuttons_amount == 0 || getRibbonType() == RIBBON_TABS) ? m_h : int(roundf((float)m_h / (float)subbuttons_amount))); int widget_x = -1; @@ -762,60 +762,76 @@ void RibbonWidget::resize() int VERT_PADDING = round(SkinConfig::getValue(SkinConfig::PADDING, WTYPE_RIBBON, getRibbonType(), SkinConfig::VERTICAL)); // ---- tab ribbons - if (getRibbonType() == RIBBON_TABS) + if (getRibbonType() == RIBBON_TABS || getRibbonType() == RIBBON_VERTICAL_TABS) { const int large_tab = (int)((with_label + without_label) - *one_button_width + * one_button_width / (with_label + without_label/2.0f)); const int small_tab = large_tab/2; stringw& message = m_active_children[i].m_text; - if (message.size() == 0) + if (getRibbonType() == RIBBON_TABS) { - if (widget_x == -1) widget_x = small_tab/2; - else widget_x += small_tab/2; + widget_y = 0; + if (message.size() == 0) + { + if (widget_x == -1) widget_x = small_tab/2; + else widget_x += small_tab/2; + } + else + { + if (widget_x == -1) widget_x = large_tab/2; + else widget_x += large_tab/2; + } } - else + else if (getRibbonType() == RIBBON_VERTICAL_TABS) { - if (widget_x == -1) widget_x = large_tab/2; - else widget_x += large_tab/2; + widget_x = large_tab/2; + if (widget_y == -1) + widget_y = 0; + else + widget_y += one_button_height; } rect tab_rect_abs; if (message.size() == 0) { - tab_rect_abs = rect(widget_x - small_tab/2 + HORZ_MARGIN, VERT_MARGIN, - widget_x + small_tab/2 - HORZ_MARGIN, m_h - VERT_MARGIN); + tab_rect_abs = rect(widget_x - small_tab/2 - HORZ_MARGIN, widget_y + VERT_MARGIN, + widget_x + small_tab/2 + HORZ_MARGIN, widget_y + one_button_height - VERT_MARGIN); } else { - tab_rect_abs = rect(widget_x - large_tab/2 + HORZ_MARGIN, VERT_MARGIN, - widget_x + large_tab/2 - HORZ_MARGIN, m_h - VERT_MARGIN); + tab_rect_abs = rect(widget_x - large_tab/2 - HORZ_MARGIN, widget_y + VERT_MARGIN, + widget_x + large_tab/2 + HORZ_MARGIN, widget_y + one_button_height - VERT_MARGIN); } // Once height is available to us, adjust for scaling - TOP_BORDER = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)TOP_BORDER ); - BOTTOM_BORDER = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)BOTTOM_BORDER ); - LEFT_BORDER = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)LEFT_BORDER ); - RIGHT_BORDER = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)RIGHT_BORDER ); - - HORZ_PADDING = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)HORZ_PADDING ); - VERT_PADDING = round( GUIEngine::getSkin()->getScalingFactor("tab::neutral", tab_rect_abs.getHeight()) * (float)VERT_PADDING ); - - // Automatically guess from position on-screen if tabs go up or down - RibbonFlip flip = getRibbonFlip(); - bool vertical_flip = (unsigned int)widget_size.UpperLeftCorner.Y < - irr_driver->getActualScreenSize().Height / 2; - // Force flip direction when the direction is defined - if(flip == FLIP_UP_LEFT) - vertical_flip = true; - else if(flip == FLIP_DOWN_RIGHT) - vertical_flip = false; - - if (vertical_flip) - swap(TOP_BORDER, BOTTOM_BORDER); + std::string tab_code = (getRibbonType() == RIBBON_TABS) ? "tab::neutral" : "verticalTab::neutral"; + TOP_BORDER = round( GUIEngine::getSkin()->getScalingFactor(tab_code, tab_rect_abs.getHeight()) * (float)TOP_BORDER ); + BOTTOM_BORDER = round( GUIEngine::getSkin()->getScalingFactor(tab_code, tab_rect_abs.getHeight()) * (float)BOTTOM_BORDER ); + LEFT_BORDER = round( GUIEngine::getSkin()->getScalingFactor(tab_code, tab_rect_abs.getHeight()) * (float)LEFT_BORDER ); + RIGHT_BORDER = round( GUIEngine::getSkin()->getScalingFactor(tab_code, tab_rect_abs.getHeight()) * (float)RIGHT_BORDER ); + + HORZ_PADDING = round( GUIEngine::getSkin()->getScalingFactor(tab_code, tab_rect_abs.getHeight()) * (float)HORZ_PADDING ); + VERT_PADDING = round( GUIEngine::getSkin()->getScalingFactor(tab_code, tab_rect_abs.getHeight()) * (float)VERT_PADDING ); + + if (getRibbonType() == RIBBON_TABS) + { + // Automatically guess from position on-screen if tabs go up or down + RibbonFlip flip = getRibbonFlip(); + bool vertical_flip = (unsigned int)widget_size.UpperLeftCorner.Y < + irr_driver->getActualScreenSize().Height / 2; + // Force flip direction when the direction is defined + if(flip == FLIP_UP_LEFT) + vertical_flip = true; + else if(flip == FLIP_DOWN_RIGHT) + vertical_flip = false; + + if (vertical_flip) + swap(TOP_BORDER, BOTTOM_BORDER); + } // Used to position sub-elements, coords needs to be relative to tab_rect_abs rect tab_contents_rect = rect(LEFT_BORDER + HORZ_PADDING, @@ -825,10 +841,13 @@ void RibbonWidget::resize() if (m_active_children[i].m_type == WTYPE_ICON_BUTTON || m_active_children[i].m_type == WTYPE_BUTTON) { + int icon_size = std::min(tab_contents_rect.getHeight(), tab_contents_rect.getWidth()/2); + const int y = (getRibbonType() == RIBBON_TABS) ? 0 : tab_contents_rect.getHeight()/2 - icon_size/2; + rect icon_part = rect(tab_contents_rect.UpperLeftCorner.X, - tab_contents_rect.UpperLeftCorner.Y, - tab_contents_rect.UpperLeftCorner.X + tab_contents_rect.getHeight(), - tab_contents_rect.UpperLeftCorner.Y + tab_contents_rect.getHeight()); + tab_contents_rect.UpperLeftCorner.Y + y, + tab_contents_rect.UpperLeftCorner.X + icon_size, + tab_contents_rect.UpperLeftCorner.Y + y + icon_size); if (message.size() == 0) { @@ -840,101 +859,21 @@ void RibbonWidget::resize() tab_contents_rect.UpperLeftCorner.Y + tab_contents_rect.getHeight()); } - rect label_part = rect(tab_contents_rect.UpperLeftCorner.X, + // Define the label area and ensure the label doesn't overlap with the icon + rect label_part = rect(icon_part.LowerRightCorner.X + 5, tab_contents_rect.UpperLeftCorner.Y, tab_contents_rect.LowerRightCorner.X, tab_contents_rect.LowerRightCorner.Y); - // label at the *right* of the icon (for tabs) - if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) - label_part.UpperLeftCorner.X += icon_part.getWidth() + 15; - m_active_children[i].m_element->setRelativePosition(tab_rect_abs); if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) m_child_data.at(i).second->setRelativePosition(icon_part); IGUIStaticText* label = m_child_data.at(i).first; label->setRelativePosition(label_part); - if ((int)GUIEngine::getFont()->getDimension(message.c_str()) - .Width > label_part.getWidth()&& - message.findFirst(L' ') == -1 && - message.findFirst(L'\u00AD') == -1 ) - { - // if message too long and contains no space and no soft - // hyphen, make the font smaller - label->setOverrideFont(GUIEngine::getSmallFont()); - } - else - { - label->setOverrideFont(NULL); - } - } - else - { - Log::error("RibbonWidget", "Invalid tab bar contents"); - } - - if (message.size() == 0) widget_x += small_tab/2; - else widget_x += large_tab/2; - } // tabs - - - // ---- vertical tab ribbons - else if (getRibbonType() == RIBBON_VERTICAL_TABS) - { - const int tab_width = (int)((with_label + without_label) - *m_w - / (with_label + without_label/2.0f)); - - stringw& message = m_active_children[i].m_text; - - widget_x = tab_width/2; - - if (widget_y == -1) - widget_y = 0; - else - widget_y += one_button_height; - - rect tab_rect_abs = rect(widget_x - (tab_width/2) - HORZ_MARGIN, widget_y + VERT_MARGIN, - widget_x + (tab_width/2) + HORZ_MARGIN, widget_y + one_button_height - VERT_MARGIN); - - // Once height is available to us, adjust for scaling - TOP_BORDER = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)TOP_BORDER ); - BOTTOM_BORDER = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)BOTTOM_BORDER ); - LEFT_BORDER = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)LEFT_BORDER ); - RIGHT_BORDER = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)RIGHT_BORDER ); - - HORZ_PADDING = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)HORZ_PADDING ); - VERT_PADDING = round( GUIEngine::getSkin()->getScalingFactor("verticalTab::neutral", tab_rect_abs.getHeight()) * (float)VERT_PADDING ); - - // Used to position sub-elements, coords needs to be relative to tab_rect_abs - rect tab_contents_rect = rect(LEFT_BORDER + HORZ_PADDING, - TOP_BORDER + VERT_PADDING, - tab_rect_abs.getWidth() - RIGHT_BORDER - HORZ_PADDING, - tab_rect_abs.getHeight() - BOTTOM_BORDER - VERT_PADDING); - - // TODO Add support for BUTTON type when needed - if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) - { - int icon_size = std::min(tab_contents_rect.getHeight(), tab_contents_rect.getWidth()/2); - const int y = tab_contents_rect.getHeight()/2 - icon_size/2; - - rect icon_part = rect(tab_contents_rect.UpperLeftCorner.X, - tab_contents_rect.UpperLeftCorner.Y + y, - tab_contents_rect.UpperLeftCorner.X + icon_size, - tab_contents_rect.UpperLeftCorner.Y + y + icon_size); - - // label at the *right* of the icon (for tabs) - rect label_part = rect(icon_part.LowerRightCorner.X+5, - tab_contents_rect.UpperLeftCorner.Y, - tab_contents_rect.LowerRightCorner.X, - tab_contents_rect.LowerRightCorner.Y); - - m_active_children[i].m_element->setRelativePosition(tab_rect_abs); - IGUIStaticText* label = m_child_data.at(i).first; - label->setRelativePosition(label_part); - m_child_data.at(i).second->setRelativePosition(icon_part); - + // If the message is too long and contains no space and no soft hyphen, + // or if it can be split but the tab doesn't have enough height for + // two lines of message, make the font smaller. if (((int)GUIEngine::getFont()->getDimension(message.c_str()) .Width > label_part.getWidth() && message.findFirst(L' ') == -1 && @@ -944,8 +883,6 @@ void RibbonWidget::resize() (int)GUIEngine::getFont()->getDimension(message.c_str()) .Height*2 > label_part.getHeight())) { - // if message is too long and contains no space and no soft - // hyphen, or too tall, make the font smaller label->setOverrideFont(GUIEngine::getSmallFont()); } else @@ -958,8 +895,12 @@ void RibbonWidget::resize() Log::error("RibbonWidget", "Invalid tab bar contents"); } - } // vertical-tabs - + if (getRibbonType() == RIBBON_TABS) + { + if (message.size() == 0) widget_x += small_tab/2; + else widget_x += large_tab/2; + } + } // tabs // ---- icon ribbons else if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) From b177f3d49d11194115b1b3a06f8ccadeb8e93f59 Mon Sep 17 00:00:00 2001 From: Deve Date: Sun, 20 Apr 2025 22:51:09 +0200 Subject: [PATCH 673/830] Add asynchronous skybox loading --- .../src/ge_vulkan_array_texture.cpp | 365 +++++++++--------- .../src/ge_vulkan_array_texture.hpp | 29 +- .../src/ge_vulkan_draw_call.cpp | 2 +- .../src/ge_vulkan_skybox_renderer.cpp | 104 +++-- .../src/ge_vulkan_skybox_renderer.hpp | 9 +- 5 files changed, 291 insertions(+), 218 deletions(-) diff --git a/lib/graphics_engine/src/ge_vulkan_array_texture.cpp b/lib/graphics_engine/src/ge_vulkan_array_texture.cpp index 83d1fa21d6d..60ad1f0549c 100644 --- a/lib/graphics_engine/src/ge_vulkan_array_texture.cpp +++ b/lib/graphics_engine/src/ge_vulkan_array_texture.cpp @@ -16,6 +16,171 @@ namespace GE { +// ============================================================================ +GEVulkanArrayTexture::ThreadLoader::ThreadLoader(GEVulkanArrayTexture* texture, + const std::vector& list, + std::function image_mani) + : m_texture(texture), m_list(list), + m_image_mani(image_mani) +{ + m_images.resize(m_texture->m_layer_count); + m_mipmaps.resize(m_texture->m_layer_count); + m_texture->m_image_view_lock.lock(); + m_texture->m_thread_loading_lock.lock(); +} // GEVulkanArrayTexture::ThreadLoader + +// ---------------------------------------------------------------------------- +GEVulkanArrayTexture::ThreadLoader::~ThreadLoader() +{ + VkDeviceSize image_size = 0; + switch (m_texture->m_internal_format) + { + case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: + case VK_FORMAT_BC7_UNORM_BLOCK: + case VK_FORMAT_BC3_UNORM_BLOCK: + image_size = get4x4CompressedTextureSize(m_texture->m_size.Width, + m_texture->m_size.Height); + break; + default: + image_size = m_texture->m_size.Width * m_texture->m_size.Height * 4; + break; + } + VkDeviceSize mipmap_data_size = m_mipmaps[0]->getMipmapSizes(); + VkDeviceSize image_total_size = image_size + mipmap_data_size; + image_total_size *= m_mipmaps.size(); + + VkBuffer staging_buffer = VK_NULL_HANDLE; + VmaAllocation staging_buffer_allocation = NULL; + VmaAllocationCreateInfo staging_buffer_create_info = {}; + staging_buffer_create_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST; + staging_buffer_create_info.flags = + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + staging_buffer_create_info.preferredFlags = + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + uint8_t* mapped; + unsigned offset = 0; + VkCommandBuffer command_buffer = VK_NULL_HANDLE; + GEVulkanDriver* vk = m_texture->m_vk; + + if (!vk->createBuffer(image_total_size, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, staging_buffer_create_info, + staging_buffer, staging_buffer_allocation)) + { + goto destroy; + } + if (vmaMapMemory(vk->getVmaAllocator(), + staging_buffer_allocation, (void**)&mapped) != VK_SUCCESS) + { + goto destroy; + } + + for (unsigned i = 0; i < m_mipmaps.size(); i++) + { + for (GEImageLevel& level : m_mipmaps[i]->getAllLevels()) + { + memcpy(mapped, level.m_data, level.m_size); + mapped += level.m_size; + } + } + vmaUnmapMemory(vk->getVmaAllocator(), staging_buffer_allocation); + vmaFlushAllocation(vk->getVmaAllocator(), staging_buffer_allocation, 0, + image_total_size); + + if (!m_texture->createImage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)) + goto destroy; + + command_buffer = GEVulkanCommandLoader::beginSingleTimeCommands(); + + m_texture->transitionImageLayout(command_buffer, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + for (unsigned i = 0; i < m_mipmaps.size(); i++) + { + std::vector& levels = m_mipmaps[i]->getAllLevels(); + for (unsigned j = 0; j < levels.size(); j++) + { + GEImageLevel& level = levels[j]; + m_texture->copyBufferToImage(command_buffer, staging_buffer, + level.m_dim.Width, level.m_dim.Height, 0, 0, offset, j, i); + offset += level.m_size; + } + } + m_texture->transitionImageLayout(command_buffer, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + GEVulkanCommandLoader::endSingleTimeCommands(command_buffer); + + m_texture->createImageView(VK_IMAGE_ASPECT_COLOR_BIT); + +destroy: + m_texture->m_image_view_lock.unlock(); + for (video::IImage* image : m_images) + image->drop(); + for (GEMipmapGenerator* mipmap_generator : m_mipmaps) + delete mipmap_generator; + if (staging_buffer != VK_NULL_HANDLE) + { + vmaDestroyBuffer(vk->getVmaAllocator(), staging_buffer, + staging_buffer_allocation); + } + m_texture->m_thread_loading_lock.unlock(); +} // ~GEVulkanArrayTexture::ThreadLoader + +// ---------------------------------------------------------------------------- +void GEVulkanArrayTexture::ThreadLoader::load(unsigned layer) +{ + const io::path& fullpath = m_list[layer]; + core::dimension2du size = m_texture->m_size; + video::IImage* texture_image = getResizedImageFullPath(fullpath, size, + NULL, &size); + if (texture_image == NULL) + { + throw std::runtime_error( + "Missing texture_image in " + "GEVulkanArrayTexture::ThreadLoader::load"); + } + if (m_image_mani) + m_image_mani(texture_image, layer); + uint8_t* texture_data = (uint8_t*)texture_image->lock(); + m_texture->bgraConversion(texture_data); + GEMipmapGenerator* mipmap_generator = NULL; + const bool normal_map = (std::string(fullpath.c_str()).find( + "_Normal.") != std::string::npos); + bool texture_compression = getGEConfig()->m_texture_compression; + if (texture_compression && GEVulkanFeatures::supportsASTC4x4()) + { + if (layer == 0) + m_texture->m_internal_format = VK_FORMAT_ASTC_4x4_UNORM_BLOCK; + mipmap_generator = new GECompressorASTC4x4(texture_data, 4, size, + normal_map); + } + else if (texture_compression && GEVulkanFeatures::supportsBPTCBC7()) + { + if (layer == 0) + m_texture->m_internal_format = VK_FORMAT_BC7_UNORM_BLOCK; + mipmap_generator = new GECompressorBPTCBC7(texture_data, 4, size, + normal_map); + } + else if (texture_compression && GEVulkanFeatures::supportsS3TCBC3()) + { + if (layer == 0) + m_texture->m_internal_format = VK_FORMAT_BC3_UNORM_BLOCK; + mipmap_generator = new GECompressorS3TCBC3(texture_data, 4, size, + normal_map); + } + else + { + if (layer == 0) + m_texture->m_internal_format = VK_FORMAT_R8G8B8A8_UNORM; + mipmap_generator = new GEMipmapGenerator(texture_data, 4, size, + normal_map); + } + m_mipmaps[layer] = mipmap_generator; + m_images[layer] = texture_image; +} // GEVulkanArrayTexture::load + // ============================================================================ std::vector getPathList(const std::vector& tlist) { @@ -43,57 +208,10 @@ GEVulkanArrayTexture::GEVulkanArrayTexture(const std::vector& list, m_vma_allocation = VK_NULL_HANDLE; m_has_mipmaps = true; m_locked_data = NULL; - core::dimension2du max_size = m_vk->getDriverAttributes() - .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); m_internal_format = VK_FORMAT_R8G8B8A8_UNORM; - m_size_lock.lock(); - m_image_view_lock.lock(); - m_thread_loading_lock.lock(); - GEVulkanCommandLoader::addMultiThreadingCommand( - [list, image_mani, max_size, this]() - { - reloadInternal(list, image_mani, max_size); - }); -} // GEVulkanArrayTexture - -// ---------------------------------------------------------------------------- -GEVulkanArrayTexture::GEVulkanArrayTexture( - const std::vector& textures, - VkImageViewType type, - std::function - image_mani) - : GEVulkanArrayTexture(getPathList(textures), type, - image_mani) -{ -} // GEVulkanArrayTexture - -// ---------------------------------------------------------------------------- -void GEVulkanArrayTexture::reloadInternal(const std::vector& list, - std::function image_mani, - const core::dimension2du& max_size) -{ - VkDeviceSize image_size = 0; - VkDeviceSize mipmap_data_size = 0; - VkDeviceSize image_total_size = 0; - std::vector images; - std::vector mipmaps; - - VkBuffer staging_buffer = VK_NULL_HANDLE; - VmaAllocation staging_buffer_allocation = NULL; - VmaAllocationCreateInfo staging_buffer_create_info = {}; - staging_buffer_create_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST; - staging_buffer_create_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; - staging_buffer_create_info.preferredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - - assert(m_layer_count == list.size()); - uint8_t* mapped; - VkCommandBuffer command_buffer = VK_NULL_HANDLE; - unsigned offset = 0; unsigned width = 0; unsigned height = 0; - for (unsigned i = 0; i < list.size(); i++) { const io::path& fullpath = list[i]; @@ -101,9 +219,9 @@ void GEVulkanArrayTexture::reloadInternal(const std::vector& list, io::IReadFile* file = io::createReadFile(fullpath); if (!file) { - printf("Missing file %s in GEVulkanArrayTexture::reloadInternal", - fullpath.c_str()); - goto destroy; + printf("Missing file %s in GEVulkanArrayTexture, layer %d", + fullpath.c_str(), i); + return; } m_vk->createImageFromFile(file, &loader); core::dimension2du dim; @@ -111,8 +229,8 @@ void GEVulkanArrayTexture::reloadInternal(const std::vector& list, { file->drop(); printf("Missing image loader for %s in " - "GEVulkanArrayTexture::reloadInternal", fullpath.c_str()); - goto destroy; + "GEVulkanArrayTexture, layer %d", fullpath.c_str(), i); + return; } file->drop(); if (m_image_view_type == VK_IMAGE_VIEW_TYPE_CUBE || @@ -127,136 +245,31 @@ void GEVulkanArrayTexture::reloadInternal(const std::vector& list, height = std::max(height, dim.Height); } } - + const core::dimension2du& max_size = m_vk->getDriverAttributes() + .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); + width = std::min(width, max_size.Width); + height = std::min(height, max_size.Height); m_size = core::dimension2du(width, height); - image_size = m_size.Width * m_size.Height * 4; m_orig_size = m_size; - m_size_lock.unlock(); + std::shared_ptr tl = std::make_shared(this, + list, image_mani); for (unsigned i = 0; i < list.size(); i++) { - const io::path& fullpath = list[i]; - video::IImage* texture_image = getResizedImageFullPath(fullpath, - max_size, NULL, &m_size); - if (texture_image == NULL) - goto destroy; - if (image_mani) - image_mani(texture_image, i); - uint8_t* texture_data = (uint8_t*)texture_image->lock(); - bgraConversion(texture_data); - GEMipmapGenerator* mipmap_generator = NULL; - const bool normal_map = (std::string(fullpath.c_str()).find( - "_Normal.") != std::string::npos); - bool texture_compression = getGEConfig()->m_texture_compression; - if (texture_compression && GEVulkanFeatures::supportsASTC4x4()) - { - if (i == 0) - { - image_size = get4x4CompressedTextureSize(m_size.Width, - m_size.Height); - m_internal_format = VK_FORMAT_ASTC_4x4_UNORM_BLOCK; - } - mipmap_generator = new GECompressorASTC4x4(texture_data, 4, m_size, - normal_map); - } - else if (texture_compression && GEVulkanFeatures::supportsBPTCBC7()) - { - if (i == 0) - { - image_size = get4x4CompressedTextureSize(m_size.Width, - m_size.Height); - m_internal_format = VK_FORMAT_BC7_UNORM_BLOCK; - } - mipmap_generator = new GECompressorBPTCBC7(texture_data, 4, m_size, - normal_map); - } - else if (texture_compression && GEVulkanFeatures::supportsS3TCBC3()) - { - if (i == 0) - { - image_size = get4x4CompressedTextureSize(m_size.Width, - m_size.Height); - m_internal_format = VK_FORMAT_BC3_UNORM_BLOCK; - } - mipmap_generator = new GECompressorS3TCBC3(texture_data, 4, m_size, - normal_map); - } - else - { - if (i == 0) - m_internal_format = VK_FORMAT_R8G8B8A8_UNORM; - mipmap_generator = new GEMipmapGenerator(texture_data, 4, m_size, - normal_map); - } - mipmap_data_size = mipmap_generator->getMipmapSizes(); - if (mipmaps.empty()) - { - image_total_size = image_size + mipmap_data_size; - image_total_size *= m_layer_count; - if (!m_vk->createBuffer(image_total_size, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, staging_buffer_create_info, - staging_buffer, staging_buffer_allocation)) - { - goto destroy; - } - if (vmaMapMemory(m_vk->getVmaAllocator(), - staging_buffer_allocation, (void**)&mapped) != VK_SUCCESS) - { - goto destroy; - } - } - mipmaps.push_back(mipmap_generator); - for (GEImageLevel& level : mipmap_generator->getAllLevels()) - { - memcpy(mapped, level.m_data, level.m_size); - mapped += level.m_size; - } - images.push_back(texture_image); + GEVulkanCommandLoader::addMultiThreadingCommand( + [tl, i](){ tl->load(i); }); } - vmaUnmapMemory(m_vk->getVmaAllocator(), staging_buffer_allocation); - vmaFlushAllocation(m_vk->getVmaAllocator(), - staging_buffer_allocation, 0, image_total_size); - - if (!createImage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)) - goto destroy; - - command_buffer = GEVulkanCommandLoader::beginSingleTimeCommands(); - - transitionImageLayout(command_buffer, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - for (unsigned i = 0; i < list.size(); i++) - { - std::vector& levels = mipmaps[i]->getAllLevels(); - for (unsigned j = 0; j < levels.size(); j++) - { - GEImageLevel& level = levels[j]; - copyBufferToImage(command_buffer, staging_buffer, - level.m_dim.Width, level.m_dim.Height, 0, 0, offset, j, i); - offset += level.m_size; - } - } - transitionImageLayout(command_buffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - GEVulkanCommandLoader::endSingleTimeCommands(command_buffer); - - createImageView(VK_IMAGE_ASPECT_COLOR_BIT); - -destroy: - m_image_view_lock.unlock(); - for (video::IImage* image : images) - image->drop(); - for (GEMipmapGenerator* mipmap_generator : mipmaps) - delete mipmap_generator; - if (staging_buffer != VK_NULL_HANDLE) - { - vmaDestroyBuffer(m_vk->getVmaAllocator(), staging_buffer, - staging_buffer_allocation); - } - m_thread_loading_lock.unlock(); +} // GEVulkanArrayTexture -} // reloadInternal +// ---------------------------------------------------------------------------- +GEVulkanArrayTexture::GEVulkanArrayTexture( + const std::vector& textures, + VkImageViewType type, + std::function + image_mani) + : GEVulkanArrayTexture(getPathList(textures), type, + image_mani) +{ +} // GEVulkanArrayTexture } diff --git a/lib/graphics_engine/src/ge_vulkan_array_texture.hpp b/lib/graphics_engine/src/ge_vulkan_array_texture.hpp index 7ebae010192..eeb66e99c2d 100644 --- a/lib/graphics_engine/src/ge_vulkan_array_texture.hpp +++ b/lib/graphics_engine/src/ge_vulkan_array_texture.hpp @@ -5,13 +5,36 @@ namespace GE { +class GEMipmapGenerator; class GEVulkanDriver; class GEVulkanArrayTexture : public GEVulkanTexture { private: - void reloadInternal(const std::vector& list, - std::function - image_mani, const core::dimension2du& max_size); + + class ThreadLoader + { + private: + GEVulkanArrayTexture* m_texture; + + std::vector m_images; + + std::vector m_mipmaps; + + std::vector m_list; + + core::dimension2du m_max_size; + + std::function m_image_mani; + public: + // -------------------------------------------------------------------- + ThreadLoader(GEVulkanArrayTexture* texture, + const std::vector& list, + std::function image_mani); + // -------------------------------------------------------------------- + ~ThreadLoader(); + // -------------------------------------------------------------------- + void load(unsigned layer); + }; public: // ------------------------------------------------------------------------ GEVulkanArrayTexture(const std::vector& full_path_list, diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index ca34655048b..747d61f030d 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -1977,7 +1977,7 @@ void GEVulkanDrawCall::addSkyBox(scene::ISceneNode* node) void GEVulkanDrawCall::drawSkyBox(VkCommandBuffer cmd, int current_buffer_idx, std::vector& dynamic_offsets) { - if (!m_skybox_renderer) + if (!m_skybox_renderer || !m_skybox_renderer->getDescriptorSet()) return; vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphics_pipelines["skybox"].m_pipeline.get()); diff --git a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp index fd4962f6183..c236666e7e6 100644 --- a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp +++ b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp @@ -11,7 +11,7 @@ namespace GE { // ---------------------------------------------------------------------------- -GEVulkanSkyBoxRenderer::GEVulkanSkyBoxRenderer() +GEVulkanSkyBoxRenderer::GEVulkanSkyBoxRenderer() : m_skybox_loading(false) { m_skybox = NULL; m_texture_cubemap = NULL; @@ -81,6 +81,7 @@ GEVulkanSkyBoxRenderer::~GEVulkanSkyBoxRenderer() return; vk->waitIdle(); + while (m_skybox_loading.load()); if (m_texture_cubemap != NULL) m_texture_cubemap->drop(); vkDestroyDescriptorPool(vk->getDevice(), m_descriptor_pool, NULL); @@ -96,6 +97,7 @@ void GEVulkanSkyBoxRenderer::addSkyBox(irr::scene::ISceneNode* skybox) if (m_skybox == skybox) return; + while (m_skybox_loading.load()); m_skybox = skybox; std::vector sky_tex; std::array order = {{ 1, 3, 4, 5, 2, 0}}; @@ -108,47 +110,75 @@ void GEVulkanSkyBoxRenderer::addSkyBox(irr::scene::ISceneNode* skybox) sky_tex.push_back(static_cast(tex)); } - auto swap_pixels = [](video::IImage* img, unsigned idx) + class ImageManipulator { - if (!(idx == 2 || idx == 3)) - return; - unsigned width = img->getDimension().Width; - uint8_t* tmp = new uint8_t[width * width * 4]; - uint32_t* tmp_array = (uint32_t*)tmp; - uint32_t* img_data = (uint32_t*)img->lock(); - for (unsigned i = 0; i < width; i++) - { - for (unsigned j = 0; j < width; j++) - tmp_array[j * width + i] = img_data[i * width + (width - j - 1)]; - } - uint8_t* u8_data = (uint8_t*)img->lock(); - delete [] u8_data; - img->setMemory(tmp); + private: + GEVulkanSkyBoxRenderer* m_sky; + public: + // ---------------------------------------------------------------- + ImageManipulator(GEVulkanSkyBoxRenderer* sky) : m_sky(sky) + { + m_sky->m_skybox_loading.store(true); + } + // ---------------------------------------------------------------- + ~ImageManipulator() + { + GEVulkanDriver* vk = getVKDriver(); + VkDescriptorImageInfo info; + info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + info.sampler = vk->getSampler(GVS_SKYBOX); + info.imageView = (VkImageView) + m_sky->m_texture_cubemap->getTextureHandler(); + + VkWriteDescriptorSet write_descriptor_set = {}; + write_descriptor_set.sType = + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptor_set.dstBinding = 0; + write_descriptor_set.dstArrayElement = 0; + write_descriptor_set.descriptorType = + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_descriptor_set.descriptorCount = 1; + write_descriptor_set.pBufferInfo = 0; + write_descriptor_set.dstSet = m_sky->m_descriptor_set; + write_descriptor_set.pImageInfo = &info; + + vkUpdateDescriptorSets(vk->getDevice(), 1, + &write_descriptor_set, 0, NULL); + m_sky->m_skybox_loading.store(false); + } + // ---------------------------------------------------------------- + void swapPixels(video::IImage* img, unsigned idx) + { + if (!(idx == 2 || idx == 3)) + return; + unsigned width = img->getDimension().Width; + uint8_t* tmp = new uint8_t[width * width * 4]; + uint32_t* tmp_array = (uint32_t*)tmp; + uint32_t* img_data = (uint32_t*)img->lock(); + for (unsigned i = 0; i < width; i++) + { + for (unsigned j = 0; j < width; j++) + { + tmp_array[j * width + i] = + img_data[i * width + (width - j - 1)]; + } + } + uint8_t* u8_data = (uint8_t*)img->lock(); + delete [] u8_data; + img->setMemory(tmp); + } + }; + + std::shared_ptr image_manipulator = + std::make_shared(this); + auto real_mani = [image_manipulator](video::IImage* img, unsigned idx) + { + image_manipulator->swapPixels(img, idx); }; if (m_texture_cubemap) m_texture_cubemap->drop(); m_texture_cubemap = new GEVulkanArrayTexture(sky_tex, - VK_IMAGE_VIEW_TYPE_CUBE, swap_pixels); - - GEVulkanDriver* vk = getVKDriver(); - VkDescriptorImageInfo info; - info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - info.sampler = vk->getSampler(GVS_SKYBOX); - info.imageView = (VkImageView)m_texture_cubemap->getTextureHandler(); - - VkWriteDescriptorSet write_descriptor_set = {}; - write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptor_set.dstBinding = 0; - write_descriptor_set.dstArrayElement = 0; - write_descriptor_set.descriptorType = - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - write_descriptor_set.descriptorCount = 1; - write_descriptor_set.pBufferInfo = 0; - write_descriptor_set.dstSet = m_descriptor_set; - write_descriptor_set.pImageInfo = &info; - - vkUpdateDescriptorSets(vk->getDevice(), 1, &write_descriptor_set, 0, - NULL); + VK_IMAGE_VIEW_TYPE_CUBE, real_mani); } // addSkyBox } diff --git a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp index b04c1d21c4c..67ea959d035 100644 --- a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp +++ b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp @@ -2,6 +2,7 @@ #define HEADER_GE_VULKAN_SKYBOX_RENDERER_HPP #include "vulkan_wrapper.h" +#include namespace irr { @@ -24,6 +25,8 @@ class GEVulkanSkyBoxRenderer VkDescriptorPool m_descriptor_pool; VkDescriptorSet m_descriptor_set; + + std::atomic_bool m_skybox_loading; public: // ------------------------------------------------------------------------ GEVulkanSkyBoxRenderer(); @@ -36,7 +39,11 @@ class GEVulkanSkyBoxRenderer { return m_descriptor_layout; } // ------------------------------------------------------------------------ const VkDescriptorSet* getDescriptorSet() const - { return &m_descriptor_set; } + { + if (m_skybox_loading.load() == true) + return NULL; + return &m_descriptor_set; + } }; // GEVulkanSkyBoxRenderer From 068c1ba209634330da9e795bf7b9a89f1910c53b Mon Sep 17 00:00:00 2001 From: Deve Date: Sun, 20 Apr 2025 23:38:36 +0200 Subject: [PATCH 674/830] Add unicolor array texture It has VK_IMAGE_USAGE_STORAGE_BIT so can be used in a compute shader --- .../src/ge_vulkan_array_texture.cpp | 82 +++++++++++++++++-- .../src/ge_vulkan_array_texture.hpp | 9 +- lib/graphics_engine/src/ge_vulkan_texture.cpp | 23 +++++- lib/graphics_engine/src/ge_vulkan_texture.hpp | 3 +- 4 files changed, 104 insertions(+), 13 deletions(-) diff --git a/lib/graphics_engine/src/ge_vulkan_array_texture.cpp b/lib/graphics_engine/src/ge_vulkan_array_texture.cpp index 60ad1f0549c..b035a36afba 100644 --- a/lib/graphics_engine/src/ge_vulkan_array_texture.cpp +++ b/lib/graphics_engine/src/ge_vulkan_array_texture.cpp @@ -19,9 +19,10 @@ namespace GE // ============================================================================ GEVulkanArrayTexture::ThreadLoader::ThreadLoader(GEVulkanArrayTexture* texture, const std::vector& list, - std::function image_mani) + std::function image_mani, + video::SColor unicolor) : m_texture(texture), m_list(list), - m_image_mani(image_mani) + m_image_mani(image_mani), m_unicolor(unicolor) { m_images.resize(m_texture->m_layer_count); m_mipmaps.resize(m_texture->m_layer_count); @@ -32,6 +33,7 @@ GEVulkanArrayTexture::ThreadLoader::ThreadLoader(GEVulkanArrayTexture* texture, // ---------------------------------------------------------------------------- GEVulkanArrayTexture::ThreadLoader::~ThreadLoader() { + bool storage_image = m_list[0].empty(); VkDeviceSize image_size = 0; switch (m_texture->m_internal_format) { @@ -61,6 +63,10 @@ GEVulkanArrayTexture::ThreadLoader::~ThreadLoader() unsigned offset = 0; VkCommandBuffer command_buffer = VK_NULL_HANDLE; GEVulkanDriver* vk = m_texture->m_vk; + VkImageUsageFlags usage_flags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + if (storage_image) + usage_flags |= VK_IMAGE_USAGE_STORAGE_BIT; if (!vk->createBuffer(image_total_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, staging_buffer_create_info, @@ -86,8 +92,7 @@ GEVulkanArrayTexture::ThreadLoader::~ThreadLoader() vmaFlushAllocation(vk->getVmaAllocator(), staging_buffer_allocation, 0, image_total_size); - if (!m_texture->createImage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)) + if (!m_texture->createImage(usage_flags)) goto destroy; command_buffer = GEVulkanCommandLoader::beginSingleTimeCommands(); @@ -108,11 +113,12 @@ GEVulkanArrayTexture::ThreadLoader::~ThreadLoader() } m_texture->transitionImageLayout(command_buffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + storage_image ? + VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); GEVulkanCommandLoader::endSingleTimeCommands(command_buffer); - m_texture->createImageView(VK_IMAGE_ASPECT_COLOR_BIT); + m_texture->createImageView(VK_IMAGE_ASPECT_COLOR_BIT, !storage_image); destroy: m_texture->m_image_view_lock.unlock(); @@ -133,8 +139,15 @@ void GEVulkanArrayTexture::ThreadLoader::load(unsigned layer) { const io::path& fullpath = m_list[layer]; core::dimension2du size = m_texture->m_size; - video::IImage* texture_image = getResizedImageFullPath(fullpath, size, - NULL, &size); + video::IImage* texture_image; + if (fullpath.empty()) + { + std::vector data(size.Width * size.Height, m_unicolor); + texture_image = m_texture->m_vk->createImageFromData( + video::ECF_A8R8G8B8, size, data.data(), false/*ownForeignMemory*/); + } + else + texture_image = getResizedImageFullPath(fullpath, size, NULL, &size); if (texture_image == NULL) { throw std::runtime_error( @@ -148,7 +161,8 @@ void GEVulkanArrayTexture::ThreadLoader::load(unsigned layer) GEMipmapGenerator* mipmap_generator = NULL; const bool normal_map = (std::string(fullpath.c_str()).find( "_Normal.") != std::string::npos); - bool texture_compression = getGEConfig()->m_texture_compression; + bool texture_compression = getGEConfig()->m_texture_compression && + !fullpath.empty(); if (texture_compression && GEVulkanFeatures::supportsASTC4x4()) { if (layer == 0) @@ -272,4 +286,54 @@ GEVulkanArrayTexture::GEVulkanArrayTexture( { } // GEVulkanArrayTexture +// ---------------------------------------------------------------------------- +GEVulkanArrayTexture::GEVulkanArrayTexture(VkFormat internal_format, + VkImageViewType type, + const core::dimension2du& size, + unsigned layer_count, + video::SColor unicolor) +{ + m_layer_count = layer_count; + m_image_view_type = type; + m_vk = getVKDriver(); + m_vulkan_device = m_vk->getDevice(); + m_image = VK_NULL_HANDLE; + m_vma_allocation = VK_NULL_HANDLE; + m_has_mipmaps = true; + m_locked_data = NULL; + m_internal_format = internal_format; + if (size.Width < 4 || size.Height < 4) + throw std::runtime_error("Minimum width and height of 4 is required."); + m_orig_size = m_size = size; + + if (m_internal_format == VK_FORMAT_R8G8B8A8_UNORM) + { + std::vector list; + for (unsigned i = 0; i < m_layer_count; i++) + list.push_back(""); + std::shared_ptr tl = std::make_shared(this, + list, nullptr, unicolor); + for (unsigned i = 0; i < list.size(); i++) + { + GEVulkanCommandLoader::addMultiThreadingCommand( + [tl, i](){ tl->load(i); }); + } + } + else + { + if (!createImage(VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT)) + { + throw std::runtime_error( + "createImage failed in storage array texture creation"); + } + VkCommandBuffer command_buffer = + GEVulkanCommandLoader::beginSingleTimeCommands(); + transitionImageLayout(command_buffer, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_GENERAL); + GEVulkanCommandLoader::endSingleTimeCommands(command_buffer); + createImageView(VK_IMAGE_ASPECT_COLOR_BIT); + } +} // GEVulkanArrayTexture + } diff --git a/lib/graphics_engine/src/ge_vulkan_array_texture.hpp b/lib/graphics_engine/src/ge_vulkan_array_texture.hpp index eeb66e99c2d..48b81cbab15 100644 --- a/lib/graphics_engine/src/ge_vulkan_array_texture.hpp +++ b/lib/graphics_engine/src/ge_vulkan_array_texture.hpp @@ -25,11 +25,14 @@ class GEVulkanArrayTexture : public GEVulkanTexture core::dimension2du m_max_size; std::function m_image_mani; + + video::SColor m_unicolor; public: // -------------------------------------------------------------------- ThreadLoader(GEVulkanArrayTexture* texture, const std::vector& list, - std::function image_mani); + std::function image_mani, + video::SColor unicolor = video::SColor()); // -------------------------------------------------------------------- ~ThreadLoader(); // -------------------------------------------------------------------- @@ -47,6 +50,10 @@ class GEVulkanArrayTexture : public GEVulkanTexture std::function image_mani = nullptr); // ------------------------------------------------------------------------ + GEVulkanArrayTexture(VkFormat internal_format, + VkImageViewType type, const core::dimension2du& size, + unsigned layer_count, video::SColor unicolor); + // ------------------------------------------------------------------------ virtual ~GEVulkanArrayTexture() {} // ------------------------------------------------------------------------ virtual void* lock(video::E_TEXTURE_LOCK_MODE mode = diff --git a/lib/graphics_engine/src/ge_vulkan_texture.cpp b/lib/graphics_engine/src/ge_vulkan_texture.cpp index 751ca9eb60d..3933e4358e3 100644 --- a/lib/graphics_engine/src/ge_vulkan_texture.cpp +++ b/lib/graphics_engine/src/ge_vulkan_texture.cpp @@ -392,6 +392,24 @@ void GEVulkanTexture::transitionImageLayout(VkCommandBuffer command_buffer, source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; destination_stage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; } + else if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED && + new_layout == VK_IMAGE_LAYOUT_GENERAL) + { + barrier.srcAccessMask = 0; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + destination_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } + else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && + new_layout == VK_IMAGE_LAYOUT_GENERAL) + { + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; + destination_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } else { return; @@ -423,7 +441,8 @@ void GEVulkanTexture::copyBufferToImage(VkCommandBuffer command_buffer, } // copyBufferToImage // ---------------------------------------------------------------------------- -bool GEVulkanTexture::createImageView(VkImageAspectFlags aspect_flags) +bool GEVulkanTexture::createImageView(VkImageAspectFlags aspect_flags, + bool create_srgb_view) { VkImageViewCreateInfo view_info = {}; view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; @@ -452,7 +471,7 @@ bool GEVulkanTexture::createImageView(VkImageAspectFlags aspect_flags) image_view.get()->store(view_ptr); m_image_view = image_view; VkFormat srgb_format = getSRGBformat(m_internal_format); - if (m_internal_format != srgb_format) + if (create_srgb_view && m_internal_format != srgb_format) { image_view = std::make_shared >(); view_info.format = srgb_format; diff --git a/lib/graphics_engine/src/ge_vulkan_texture.hpp b/lib/graphics_engine/src/ge_vulkan_texture.hpp index f216862eda7..051e752fb77 100644 --- a/lib/graphics_engine/src/ge_vulkan_texture.hpp +++ b/lib/graphics_engine/src/ge_vulkan_texture.hpp @@ -85,7 +85,8 @@ class GEVulkanTexture : public video::ITexture // ------------------------------------------------------------------------ bool createImage(VkImageUsageFlags usage); // ------------------------------------------------------------------------ - bool createImageView(VkImageAspectFlags aspect_flags); + bool createImageView(VkImageAspectFlags aspect_flags, + bool create_srgb_view = true); // ------------------------------------------------------------------------ void transitionImageLayout(VkCommandBuffer command_buffer, VkImageLayout old_layout, From 7e6b312e820b0eccdc718b99b67ace5899e51862 Mon Sep 17 00:00:00 2001 From: Deve Date: Sun, 20 Apr 2025 23:56:20 +0200 Subject: [PATCH 675/830] Restore previous sampler use in mesh texture descriptor --- lib/graphics_engine/include/ge_vulkan_texture_descriptor.hpp | 2 ++ lib/graphics_engine/src/ge_vulkan_driver.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/graphics_engine/include/ge_vulkan_texture_descriptor.hpp b/lib/graphics_engine/include/ge_vulkan_texture_descriptor.hpp index c0f1ba10e69..157b16e32db 100644 --- a/lib/graphics_engine/include/ge_vulkan_texture_descriptor.hpp +++ b/lib/graphics_engine/include/ge_vulkan_texture_descriptor.hpp @@ -105,6 +105,8 @@ class GEVulkanTextureDescriptor // ------------------------------------------------------------------------ VkDescriptorSet* getDescriptorSet() { return m_descriptor_sets.data(); } + // ------------------------------------------------------------------------ + GEVulkanSampler getSamplerUse() const { return m_sampler_use; } }; // GEVulkanTextureDescriptor } diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index 11efce0f176..c5079c84200 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -2526,11 +2526,13 @@ void GEVulkanDriver::updateDriver(bool pbr_changed) { GEVulkanShaderManager::destroy(); GEVulkanShaderManager::init(this); + GEVulkanSampler sampler = m_mesh_texture_descriptor->getSamplerUse(); delete m_mesh_texture_descriptor; m_mesh_texture_descriptor = new GEVulkanTextureDescriptor( GEVulkanShaderManager::getSamplerSize(), GEVulkanShaderManager::getMeshTextureLayer(), GEVulkanFeatures::supportsBindMeshTexturesAtOnce()); + m_mesh_texture_descriptor->setSamplerUse(sampler); GEVulkanMeshCache* mc = getVulkanMeshCache(); if (!GEVulkanFeatures::supportsBaseVertexRendering()) { From a75ac1cd54723eaac56dc8ba89a40e50aaaf0b62 Mon Sep 17 00:00:00 2001 From: Deve Date: Mon, 21 Apr 2025 21:39:52 +0200 Subject: [PATCH 676/830] Make it possible to reload shaders in vulkan --- .../include/ge_vulkan_driver.hpp | 1 + lib/graphics_engine/src/ge_vulkan_driver.cpp | 16 ++++++++++++++++ src/utils/debug.cpp | 17 +++++++++++++---- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/lib/graphics_engine/include/ge_vulkan_driver.hpp b/lib/graphics_engine/include/ge_vulkan_driver.hpp index 220c5e477f3..3d2433f7b28 100644 --- a/lib/graphics_engine/include/ge_vulkan_driver.hpp +++ b/lib/graphics_engine/include/ge_vulkan_driver.hpp @@ -343,6 +343,7 @@ namespace GE createSwapChainRelated(false/*handle_surface*/); } void updateDriver(bool pbr_changed = false); + void reloadShaders(); uint32_t getGraphicsFamily() const { return m_graphics_family; } unsigned getGraphicsQueueCount() const { return m_graphics_queue_count; } diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index c5079c84200..b26e0835924 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -2564,6 +2564,22 @@ void GEVulkanDriver::updateDriver(bool pbr_changed) setDisableWaitIdle(false); } // updateDriver +// ---------------------------------------------------------------------------- +void GEVulkanDriver::reloadShaders() +{ + waitIdle(); + setDisableWaitIdle(true); + clearDrawCallsCache(); + GEVulkanShaderManager::destroy(); + GEVulkanShaderManager::init(this); + for (auto& dc : static_cast( + m_irrlicht_device->getSceneManager())->getDrawCalls()) + dc.second = std::unique_ptr(new GEVulkanDrawCall); + GEVulkan2dRenderer::destroy(); + GEVulkan2dRenderer::init(this); + setDisableWaitIdle(false); +} // reloadShaders + // ---------------------------------------------------------------------------- void GEVulkanDriver::clearDrawCallsCache() { diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index da18f43c5c3..11957b66641 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -323,11 +323,20 @@ bool handleContextMenuAction(s32 cmd_id) { case DEBUG_GRAPHICS_RELOAD_SHADERS: #ifndef SERVER_ONLY + { Log::info("Debug", "Reloading shaders..."); - SP::SPShaderManager::get()->unloadAll(); - ShaderBase::killShaders(); - ShaderFilesManager::getInstance()->removeAllShaderFiles(); - SP::SPShaderManager::get()->initAll(); + GE::GEVulkanDriver* vk = GE::getVKDriver(); + if (vk) + vk->reloadShaders(); + else + { + SP::SPShaderManager::get()->unloadAll(); + ShaderBase::killShaders(); + ShaderFilesManager::getInstance()->removeAllShaderFiles(); + SP::SPShaderManager::get()->initAll(); + } + break; + } #endif break; case DEBUG_GRAPHICS_RELOAD_TEXTURES: From 79df88bdd3316e89bf004905313c2fc07e97d82f Mon Sep 17 00:00:00 2001 From: Deve Date: Mon, 21 Apr 2025 22:05:48 +0200 Subject: [PATCH 677/830] Fix gles ibl shader --- data/shaders/IBL.frag | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/data/shaders/IBL.frag b/data/shaders/IBL.frag index 2aca7502102..01912d1320e 100644 --- a/data/shaders/IBL.frag +++ b/data/shaders/IBL.frag @@ -1,6 +1,8 @@ uniform sampler2D ntex; uniform sampler2D dtex; +#if !defined(GL_ES) uniform sampler2DShadow stex; +#endif uniform sampler2D albedo; uniform sampler2D ssao; uniform sampler2D ctex; @@ -19,6 +21,7 @@ out vec4 Spec; #stk_include "utils/DiffuseIBL.frag" #stk_include "utils/SpecularIBL.frag" +#if !defined(GL_ES) vec3 CalcCoordFromPosition(in vec3 pos) { vec4 projectedCoord = u_projection_matrix * vec4(pos, 1.0); @@ -67,6 +70,7 @@ vec3 gtaoMultiBounce(float visibility, vec3 albedo) return max(vec3(visibility), ((visibility * a + b) * visibility + c) * visibility); } +#endif // Main =================================================================== From b4c1fa10dddb035e9f0a4a3da4c1da94f42cbc76 Mon Sep 17 00:00:00 2001 From: Deve Date: Sat, 26 Apr 2025 23:28:03 +0200 Subject: [PATCH 678/830] Fixed some crashes in performance test --- src/karts/ghost_kart.cpp | 7 ++++--- src/utils/profiler.cpp | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/karts/ghost_kart.cpp b/src/karts/ghost_kart.cpp index b118c8320f7..66cdb9b3ed0 100644 --- a/src/karts/ghost_kart.cpp +++ b/src/karts/ghost_kart.cpp @@ -285,13 +285,14 @@ float GhostKart::getSpeed() const dynamic_cast(getController()); unsigned int current_index = gc->getCurrentReplayIndex(); - const float rd = gc->getReplayDelta(); - - assert(gc->getCurrentReplayIndex() < m_all_physic_info.size()); if (current_index >= m_all_physic_info.size() - 1) return m_all_physic_info.back().m_speed; + const float rd = gc->getReplayDelta(); + + assert(gc->getCurrentReplayIndex() < m_all_physic_info.size()); + return (1-rd)*m_all_physic_info[current_index ].m_speed + rd *m_all_physic_info[current_index + 1].m_speed; } // getSpeed diff --git a/src/utils/profiler.cpp b/src/utils/profiler.cpp index 102128a372b..344f327addc 100644 --- a/src/utils/profiler.cpp +++ b/src/utils/profiler.cpp @@ -138,6 +138,8 @@ void Profiler::reset() m_current_frame = 0; m_has_wrapped_around = false; m_freeze_state = UNFROZEN; + + init(); } // reset //----------------------------------------------------------------------------- From ebbbaa6e6afa66c4f31bca58d6f0b4280a4d0efb Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sun, 27 Apr 2025 22:22:18 +0200 Subject: [PATCH 679/830] Fix #5288 - When navigating vertically from a wide widget, prefer navigating to left-aligned widgets than to centered widgets. - Rename the offsets variable to be more logical --- src/guiengine/event_handler.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/guiengine/event_handler.cpp b/src/guiengine/event_handler.cpp index c931c6d2cd6..d38c6f697ef 100644 --- a/src/guiengine/event_handler.cpp +++ b/src/guiengine/event_handler.cpp @@ -591,9 +591,9 @@ int EventHandler::findIDClosestWidget(const NavigationDirection nav, const int p // Better select an item on the side that one much higher, // so make the vertical distance matter much more // than the horizontal offset. - // The multiplicator of 100 is meant so that the offset will matter + // The multiplicator of 500 is meant so that the offset will matter // only if there are two or more widget with a (nearly) equal vertical height. - distance *= 100; + distance *= 500; wrapping_distance = distance; // if the two widgets are not well aligned, consider them farther @@ -602,8 +602,8 @@ int EventHandler::findIDClosestWidget(const NavigationDirection nav, const int p // If w_test's are between w's, // we subtract the smaller from the bigger // else, the smaller is 0 and we keep the bigger - int right_offset = std::max(0, w_test->m_x - w->m_x); - int left_offset = std::max(0, (w->m_x + w->m_w) - rightmost); + int left_offset = 10 * std::max(0, w_test->m_x - w->m_x); + int right_offset = std::max(0, (w->m_x + w->m_w) - rightmost); offset = std::max (right_offset - left_offset, left_offset - right_offset); } else if (nav == NAV_LEFT || nav == NAV_RIGHT) From 52f7629c3b219ebc6ea9f4834ac776e09e3046da Mon Sep 17 00:00:00 2001 From: Deve Date: Sun, 27 Apr 2025 22:54:09 +0200 Subject: [PATCH 680/830] Add ibl for vulkan --- .../ge_shaders/diffuse_irradiance.comp | 53 +++ data/shaders/ge_shaders/ghost.frag | 3 +- .../ge_shaders/specular_prefilter.comp | 82 +++++ data/shaders/ge_shaders/transparent.frag | 3 +- .../ge_shaders/utils/constants_utils.glsl | 16 + .../ge_shaders/utils/environment_map.glsl | 47 +++ data/shaders/ge_shaders/utils/handle_pbr.glsl | 27 +- data/shaders/ge_shaders/utils/pbr_light.glsl | 80 +---- data/shaders/ge_shaders/utils/pbr_utils.glsl | 91 +++++ lib/graphics_engine/CMakeLists.txt | 1 + lib/graphics_engine/include/ge_main.hpp | 1 + .../include/ge_vulkan_driver.hpp | 3 +- .../include/ge_vulkan_features.hpp | 2 + lib/graphics_engine/src/ge_main.cpp | 1 + .../src/ge_vulkan_draw_call.cpp | 50 ++- lib/graphics_engine/src/ge_vulkan_driver.cpp | 18 +- .../src/ge_vulkan_environment_map.cpp | 334 ++++++++++++++++++ .../src/ge_vulkan_environment_map.hpp | 37 ++ .../src/ge_vulkan_features.cpp | 10 + .../src/ge_vulkan_shader_manager.cpp | 2 + .../src/ge_vulkan_skybox_renderer.cpp | 201 +++++++++-- .../src/ge_vulkan_skybox_renderer.hpp | 24 +- lib/graphics_engine/src/ge_vulkan_texture.hpp | 6 + src/graphics/irr_driver.cpp | 2 + .../dialogs/custom_video_settings.cpp | 24 +- src/utils/debug.cpp | 18 +- 26 files changed, 1017 insertions(+), 119 deletions(-) create mode 100644 data/shaders/ge_shaders/diffuse_irradiance.comp create mode 100644 data/shaders/ge_shaders/specular_prefilter.comp create mode 100644 data/shaders/ge_shaders/utils/constants_utils.glsl create mode 100644 data/shaders/ge_shaders/utils/environment_map.glsl create mode 100644 data/shaders/ge_shaders/utils/pbr_utils.glsl create mode 100644 lib/graphics_engine/src/ge_vulkan_environment_map.cpp create mode 100644 lib/graphics_engine/src/ge_vulkan_environment_map.hpp diff --git a/data/shaders/ge_shaders/diffuse_irradiance.comp b/data/shaders/ge_shaders/diffuse_irradiance.comp new file mode 100644 index 00000000000..720531e9a59 --- /dev/null +++ b/data/shaders/ge_shaders/diffuse_irradiance.comp @@ -0,0 +1,53 @@ +layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +// Binding for the input skybox cubemap. +layout(set = 0, binding = 0) uniform samplerCube uSkybox; +// Binding for the output irradiance (diffuse) cube map stored as a 2D array (each layer is one face). +#ifdef SHADER_STORAGE_IMAGE_EXTENDED_FORMATS +layout(set = 0, binding = 1, rgb10_a2) uniform restrict writeonly image2DArray uIrradianceMap; +#else +layout(set = 0, binding = 1, rgba8) uniform restrict writeonly image2DArray uIrradianceMap; +#endif + +#include "utils/environment_map.glsl" + +void main() +{ + ivec2 pix = ivec2(gl_GlobalInvocationID.xy); + if (pix.x >= pc.size || pix.y >= pc.size) return; + + // Get normalized UV for current pixel. + vec2 uv = (vec2(pix) + 0.5) / vec2(pc.size, pc.size); + int face = int(gl_GlobalInvocationID.z); + vec3 normal = FaceUVtoDir(face, uv); + + // Establish a tangent space basis. + vec3 up = abs(normal.y) < 0.999 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0); + vec3 right = normalize(cross(up, normal)); + vec3 tangent = cross(normal, right); + + vec3 irradiance = vec3(0.0); + float weight = 0.0; + uint sampleCount = uint(pc.sampleCount); + + for (uint i = 0u; i < sampleCount; i++) + { + vec2 xi = Hammersley(i, sampleCount); + // Cosine-weighted hemisphere sampling. + float phi = 2.0 * PI * xi.x; + float cosTheta = sqrt(1.0 - xi.y); // weight factor equals cos(theta) + float sinTheta = sqrt(xi.y); + vec3 sampleDir = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); + + // Transform sample direction from tangent space to world space. + vec3 sampleVec = normalize(right * sampleDir.x + tangent * sampleDir.y + normal * sampleDir.z); + + vec3 sampleColor = texture(uSkybox, sampleVec).rgb; + irradiance += sampleColor * cosTheta; + weight += cosTheta; + } + irradiance /= weight; + + imageStore(uIrradianceMap, ivec3(pix, face), vec4(irradiance, 1.0)); + +} diff --git a/data/shaders/ge_shaders/ghost.frag b/data/shaders/ge_shaders/ghost.frag index 02ace7268c8..9f3a770ff51 100644 --- a/data/shaders/ge_shaders/ghost.frag +++ b/data/shaders/ge_shaders/ghost.frag @@ -5,6 +5,7 @@ layout(location = 4) in float f_hue_change; layout(location = 0) out vec4 o_color; +#include "utils/constants_utils.glsl" #include "utils/sample_mesh_texture.glsl" #include "../utils/rgb_conversion.frag" @@ -32,7 +33,7 @@ void main() vec3 mixed_color = tex_color.xyz * f_vertex_color.xyz; mixed_color *= 0.5; #ifdef PBR_ENABLED - mixed_color = (mixed_color * (6.9 * mixed_color + 0.5)) / (mixed_color * (5.2 * mixed_color + 1.7) + 0.06); + mixed_color = convertColor(mixed_color); #endif o_color = vec4(mixed_color, 0.5); } diff --git a/data/shaders/ge_shaders/specular_prefilter.comp b/data/shaders/ge_shaders/specular_prefilter.comp new file mode 100644 index 00000000000..d7c6e3ffaae --- /dev/null +++ b/data/shaders/ge_shaders/specular_prefilter.comp @@ -0,0 +1,82 @@ +layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +// Binding for the input skybox cubemap. +layout(set = 0, binding = 0) uniform samplerCube uSkybox; +// Output prefiltered environment specular map (stored as a 2D array for cube faces). +#ifdef SHADER_STORAGE_IMAGE_EXTENDED_FORMATS +layout(set = 0, binding = 1, rgb10_a2) uniform restrict writeonly image2DArray uPrefilterMap; +#else +layout(set = 0, binding = 1, rgba8) uniform restrict writeonly image2DArray uPrefilterMap; +#endif + +#include "utils/environment_map.glsl" +#include "utils/pbr_utils.glsl" + +void main() +{ + ivec2 pix = ivec2(gl_GlobalInvocationID.xy); + if (pix.x >= pc.size || pix.y >= pc.size) return; + + // Get normalized UV for current pixel. + vec2 uv = (vec2(pix) + 0.5) / vec2(pc.size, pc.size); + int face = int(gl_GlobalInvocationID.z); + + float roughness = float(pc.mipmapLevel) / float(pc.mipmapCount - 1); + vec3 R = FaceUVtoDir(face, uv); + vec3 V = normalize(R); + // Don't need to sample skybox when roughness is 0. + // Since it's a perfect reflector. + if (roughness == 0.0) + { + vec4 color = textureLod(uSkybox, V, 0); + imageStore(uPrefilterMap, ivec3(pix, face), color); + return; + } + + vec3 prefilteredColor = vec3(0.0); + float totalWeight = 0.0; + uint sampleCount = uint(pc.sampleCount); + for (uint i = 0u; i < sampleCount; ++i) + { + vec2 xi = Hammersley(i, sampleCount); + // Importance sampling with a GGX distribution. + float a = roughness * roughness; + float phi = 2.0 * PI * xi.x; + // GGX importance sampling for the cosine of the angle. + float cosTheta = sqrt((1.0 - xi.y) / (1.0 + (a * a - 1.0) * xi.y)); + float sinTheta = sqrt(1.0 - cosTheta * cosTheta); + vec3 H = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); + + // Construct TBN basis from view direction V. + vec3 up = abs(V.y) < 0.999 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0); + vec3 tangent = normalize(cross(up, V)); + vec3 bitangent = cross(V, tangent); + mat3 TBN = mat3(tangent, bitangent, V); + H = normalize(TBN * H); + + // Compute reflection vector L. + vec3 L = normalize(reflect(-V, H)); + float NdotL = max(dot(V, L), 0.0); + + if (NdotL > 0.0) + { + // Calculate the mip level based on the PDF. + // In a skybox/environment map scenario, N = V. + float NoH = max(dot(V, H), 0.0); + float VoH = max(dot(V, H), 0.0); + + float D = D_GGX(roughness, NoH); + float pdf = D * NoH / (4.0 * VoH); + float omegaS = 1.0 / (float(sampleCount) * pdf); + float omegaP = 4.0 * PI / (6.0 * float(pc.size * pc.size)); + float mipLevel = 0.5 * log2(omegaS / omegaP); + + vec3 sampleColor = textureLod(uSkybox, L, mipLevel).rgb; + prefilteredColor += sampleColor * NdotL; + totalWeight += NdotL; + } + } + prefilteredColor = prefilteredColor / totalWeight; + + imageStore(uPrefilterMap, ivec3(pix, face), vec4(prefilteredColor, 1.0)); +} diff --git a/data/shaders/ge_shaders/transparent.frag b/data/shaders/ge_shaders/transparent.frag index cc1f4a69c6b..5a7042e9a18 100644 --- a/data/shaders/ge_shaders/transparent.frag +++ b/data/shaders/ge_shaders/transparent.frag @@ -4,6 +4,7 @@ layout(location = 3) flat in int f_material_id; layout(location = 0) out vec4 o_color; +#include "utils/constants_utils.glsl" #include "utils/sample_mesh_texture.glsl" void main() @@ -12,7 +13,7 @@ void main() vec3 mixed_color = color.xyz; float alpha = color.w; #ifdef PBR_ENABLED - mixed_color = (mixed_color * (6.9 * mixed_color + 0.5)) / (mixed_color * (5.2 * mixed_color + 1.7) + 0.06); + mixed_color = convertColor(mixed_color); #endif o_color = vec4(mixed_color * alpha, alpha); } diff --git a/data/shaders/ge_shaders/utils/constants_utils.glsl b/data/shaders/ge_shaders/utils/constants_utils.glsl new file mode 100644 index 00000000000..f6a1ef0ef40 --- /dev/null +++ b/data/shaders/ge_shaders/utils/constants_utils.glsl @@ -0,0 +1,16 @@ +layout (constant_id = 0) const bool u_ibl = true; +layout (constant_id = 1) const float u_specular_levels_minus_one = 0.0; + +vec3 convertColor(vec3 input_color) +{ + if (u_ibl) + { + return (input_color * (6.5 * input_color + 0.45)) / + (input_color * (5.0 * input_color + 1.75) + 0.05); + } + else + { + return (input_color * (7.0 * input_color + 0.75)) / + (input_color * (5.0 * input_color + 1.75) + 0.05); + } +} diff --git a/data/shaders/ge_shaders/utils/environment_map.glsl b/data/shaders/ge_shaders/utils/environment_map.glsl new file mode 100644 index 00000000000..c6a3fd8c4da --- /dev/null +++ b/data/shaders/ge_shaders/utils/environment_map.glsl @@ -0,0 +1,47 @@ +// Push constants to pass face index, dimensions, and sample count. +layout(push_constant) uniform PushConstants { + int size; // width and height for current mipmap level + int sampleCount; // number of samples for integration + int mipmapLevel; // current mipmap level + int mipmapCount; // total mipmap levels +} pc; + +// Returns the radical inverse of "bits" with base 2. +float RadicalInverse_VdC(uint bits) +{ + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; +} + +// Generate a 2D Hammersley sequence value. +vec2 Hammersley(uint i, uint N) +{ + return vec2(float(i) / float(N), RadicalInverse_VdC(i)); +} + +// Converts face index and UV coordinates in [0,1] to a normalized direction vector. +vec3 FaceUVtoDir(int face, vec2 uv) +{ + // Map UV from [0, 1] to [-1, 1] + uv = uv * 2.0 - 1.0; + vec3 dir; + if (face == 0) // +X + dir = vec3(1.0, -uv.y, -uv.x); + else if (face == 1) // -X + dir = vec3(-1.0, -uv.y, uv.x); + else if (face == 2) // +Y + dir = vec3(uv.x, 1.0, uv.y); + else if (face == 3) // -Y + dir = vec3(uv.x, -1.0, -uv.y); + else if (face == 4) // +Z + dir = vec3(uv.x, -uv.y, 1.0); + else if (face == 5) // -Z + dir = vec3(-uv.x, -uv.y, -1.0); + return normalize(dir); +} + +const float PI = 3.14159265359; diff --git a/data/shaders/ge_shaders/utils/handle_pbr.glsl b/data/shaders/ge_shaders/utils/handle_pbr.glsl index 9df7c01bc8f..fdf47ee4497 100644 --- a/data/shaders/ge_shaders/utils/handle_pbr.glsl +++ b/data/shaders/ge_shaders/utils/handle_pbr.glsl @@ -1,4 +1,10 @@ +layout (set = 2, binding = 0) uniform samplerCube u_diffuse; +layout (set = 2, binding = 1) uniform samplerCube u_specular; + #include "camera.glsl" +#include "constants_utils.glsl" +#include "pbr_utils.glsl" + #include "get_pos_from_frag_coord.glsl" #include "pbr_light.glsl" #include "sun_direction.glsl" @@ -8,20 +14,33 @@ vec3 handlePBR(vec3 diffuse_color, vec3 pbr, vec3 normal) vec3 xpos = getPosFromFragCoord(gl_FragCoord, u_camera.m_viewport, u_camera.m_inverse_projection_matrix); vec3 eyedir = -normalize(xpos); + vec3 reflection = reflect(-eyedir, normal); + + float perceptual_roughness = 1.0 - pbr.x; + float radiance_level = perceptual_roughness * u_specular_levels_minus_one; + vec3 world_normal = (u_camera.m_inverse_view_matrix * vec4(normal, 0.0)).xyz; + vec3 world_reflection = (u_camera.m_inverse_view_matrix * vec4(reflection, 0.0)).xyz; + + vec3 irradiance = vec3(0.0); + vec3 radiance = vec3(0.0); + if (u_ibl) + { + irradiance = texture(u_diffuse, world_normal).rgb; + radiance = textureLod(u_specular, world_reflection, radiance_level).rgb; + } vec3 sun = sunDirection(normal, eyedir, vec3(-642.22, 673.75, -219.26)); vec3 lightdir = normalize(sun.xyz); vec3 mixed_color = PBRSunAmbientEmitLight( normal, eyedir, lightdir, diffuse_color, + irradiance, radiance, vec3(211./256., 235./256., 110./256.), vec3(120./256., 120./256., 120./256.), - 1.0 - pbr.x, pbr.y, pbr.z); + perceptual_roughness, pbr.y, pbr.z); float factor = (1.0 - exp(length(xpos) * -0.0001)); mixed_color = mixed_color + vec3(0.5) * factor; - mixed_color = (mixed_color * (6.9 * mixed_color + 0.5)) / - (mixed_color * (5.2 * mixed_color + 1.7) + 0.06); - return mixed_color; + return convertColor(mixed_color); } diff --git a/data/shaders/ge_shaders/utils/pbr_light.glsl b/data/shaders/ge_shaders/utils/pbr_light.glsl index a12eb1b1e33..4283b0c7208 100644 --- a/data/shaders/ge_shaders/utils/pbr_light.glsl +++ b/data/shaders/ge_shaders/utils/pbr_light.glsl @@ -1,68 +1,3 @@ -vec2 F_AB(float perceptual_roughness, float NdotV) -{ - vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); - vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); - vec4 r = perceptual_roughness * c0 + c1; - float a004 = min(r.x * r.x, pow(2.0, -9.28 * NdotV)) * r.x + r.y; - return vec2(-1.04, 1.04) * a004 + r.zw; -} - -// Lambert model -float F_Schlick(float f0, float f90, float VdotH) -{ - return mix(f0, f90, pow(1.0 - VdotH, 5.0)); -} - -float Fd_Burley(float roughness, float NdotV, float NdotL, float LdotH) -{ - // Don't divide by Pi to avoid light being too dim. - float f90 = 0.5 + 2.0 * roughness * LdotH * LdotH; - float lightScatter = F_Schlick(1.0, f90, NdotL); - float viewScatter = F_Schlick(1.0, f90, NdotV); - return lightScatter * viewScatter; -} - -// Calculate distribution. -// Based on https://google.github.io/filament/Filament.html#citation-walter07 -// D_GGX(h,α) = α^2 / { π ((n⋅h)^2 (α2−1) + 1)^2 } -// Simple implementation, has precision problems when using fp16 instead of fp32 -// see https://google.github.io/filament/Filament.html#listing_speculardfp16 -float D_GGX(float roughness, float NdotH) -{ - // Don't divide by Pi to avoid light being too dim. - float oneMinusNdotHSquared = 1.0 - NdotH * NdotH; - float a = NdotH * roughness; - float k = roughness / (oneMinusNdotHSquared + a * a); - return k * k; -} - -// Calculate visibility. -// Hammon 2017, "PBR Diffuse Lighting for GGX+Smith Microsurfaces" -// see https://google.github.io/filament/Filament.html#listing_approximatedspecularv -float V_Smith_GGX_Correlated(float roughness, float NdotV, float NdotL) -{ - return 0.5 / mix(2.0 * NdotL * NdotV, NdotL + NdotV, roughness); -} - -// Fresnel function -// see https://google.github.io/filament/Filament.html#citation-schlick94 -// F_Schlick(v,h,f_0,f_90) = f_0 + (f_90 − f_0) (1 − v⋅h)^5 -vec3 fresnel(vec3 f0, float f90, float VdotH) -{ - return f0 + (f90 - f0) * pow(1.0 - VdotH, 5.0); -} - -vec3 envBRDFApprox(vec3 F0, vec2 F_ab) -{ - return F0 * F_ab.x + F_ab.y; -} - -float perceptualRoughnessToRoughness(float perceptual_roughness) -{ - float roughness = clamp(perceptual_roughness, 0.089, 1.0); - return roughness * roughness; -} - vec3 PBRLight( vec3 normal, vec3 eyedir, @@ -104,6 +39,8 @@ vec3 PBRSunAmbientEmitLight( vec3 eyedir, vec3 sundir, vec3 color, + vec3 irradiance, + vec3 radiance, vec3 sun_color, vec3 ambient_color, float perceptual_roughness, @@ -142,7 +79,18 @@ vec3 PBRSunAmbientEmitLight( vec3 specular_ambient = F90 * envBRDFApprox(F0, F_ab); + // Other 0.6 comes from skybox + ambient_color *= 0.4; + vec3 environment = vec3(0.325, 0.35, 0.375) * ambient_color * diffuse_color; + if (u_ibl) + { + environment = environmentLight(irradiance, radiance, roughness, + diffuse_color, F_ab, F0, F90, NdotV); + } + vec3 emit = emissive * color * 4.0; - return sun_color * sunlight + ambient_color * (diffuse_ambient + specular_ambient) + emit; + return sun_color * sunlight + + environment + emit + + (diffuse_ambient + specular_ambient) * ambient_color; } diff --git a/data/shaders/ge_shaders/utils/pbr_utils.glsl b/data/shaders/ge_shaders/utils/pbr_utils.glsl new file mode 100644 index 00000000000..a9e02a9437d --- /dev/null +++ b/data/shaders/ge_shaders/utils/pbr_utils.glsl @@ -0,0 +1,91 @@ +vec2 F_AB(float perceptual_roughness, float NdotV) +{ + vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); + vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); + vec4 r = perceptual_roughness * c0 + c1; + float a004 = min(r.x * r.x, pow(2.0, -9.28 * NdotV)) * r.x + r.y; + return vec2(-1.04, 1.04) * a004 + r.zw; +} + +// Lambert model +float F_Schlick(float f0, float f90, float VdotH) +{ + return mix(f0, f90, pow(1.0 - VdotH, 5.0)); +} + +float Fd_Burley(float roughness, float NdotV, float NdotL, float LdotH) +{ + // Don't divide by Pi to avoid light being too dim. + float f90 = 0.5 + 2.0 * roughness * LdotH * LdotH; + float lightScatter = F_Schlick(1.0, f90, NdotL); + float viewScatter = F_Schlick(1.0, f90, NdotV); + return lightScatter * viewScatter; +} + +// Calculate distribution. +// Based on https://google.github.io/filament/Filament.html#citation-walter07 +// D_GGX(h,α) = α^2 / { π ((n⋅h)^2 (α2−1) + 1)^2 } +// Simple implementation, has precision problems when using fp16 instead of fp32 +// see https://google.github.io/filament/Filament.html#listing_speculardfp16 +float D_GGX(float roughness, float NdotH) +{ + float oneMinusNdotHSquared = 1.0 - NdotH * NdotH; + float a = NdotH * roughness; + float k = roughness / (oneMinusNdotHSquared + a * a); + return k * k * (1.0 / 3.14159265359); +} + +// Calculate visibility. +// Hammon 2017, "PBR Diffuse Lighting for GGX+Smith Microsurfaces" +// see https://google.github.io/filament/Filament.html#listing_approximatedspecularv +float V_Smith_GGX_Correlated(float roughness, float NdotV, float NdotL) +{ + return 0.5 / mix(2.0 * NdotL * NdotV, NdotL + NdotV, roughness); +} + +// Fresnel function +// see https://google.github.io/filament/Filament.html#citation-schlick94 +// F_Schlick(v,h,f_0,f_90) = f_0 + (f_90 − f_0) (1 − v⋅h)^5 +vec3 fresnel(vec3 f0, float f90, float VdotH) +{ + return f0 + (f90 - f0) * pow(1.0 - VdotH, 5.0); +} + +vec3 envBRDFApprox(vec3 F0, vec2 F_ab) +{ + return F0 * F_ab.x + F_ab.y; +} + +float perceptualRoughnessToRoughness(float perceptual_roughness) +{ + float roughness = clamp(perceptual_roughness, 0.089, 1.0); + return roughness * roughness; +} + +vec3 environmentLight( + vec3 irradiance, + vec3 radiance, + float roughness, + vec3 diffuse_color, + vec2 F_ab, + vec3 F0, + float F90, + float NdotV) +{ + // Multiscattering approximation: https://www.jcgt.org/published/0008/01/03/paper.pdf + // Useful reference: https://bruop.github.io/ibl + vec3 Fr = max(vec3(1.0 - roughness), F0) - F0; + vec3 kS = F0 + Fr * pow(1.0 - NdotV, 5.0); + float Ess = F_ab.x + F_ab.y; + vec3 FssEss = kS * Ess * F90; + float Ems = 1.0 - Ess; + vec3 Favg = F0 + (1.0 - F0) / 21.0; + vec3 Fms = FssEss * Favg / (1.0 - Ems * Favg); + vec3 FmsEms = Fms * Ems; + vec3 Edss = 1.0 - (FssEss + FmsEms); + vec3 kD = diffuse_color * Edss; + + vec3 diffuse = (FmsEms + kD) * irradiance; + vec3 specular = FssEss * radiance; + return diffuse + specular; +} diff --git a/lib/graphics_engine/CMakeLists.txt b/lib/graphics_engine/CMakeLists.txt index 1dc1e294380..ad13602c4db 100644 --- a/lib/graphics_engine/CMakeLists.txt +++ b/lib/graphics_engine/CMakeLists.txt @@ -82,6 +82,7 @@ set(GE_SOURCES src/ge_vulkan_draw_call.cpp src/ge_vulkan_dynamic_buffer.cpp src/ge_vulkan_dynamic_spm_buffer.cpp + src/ge_vulkan_environment_map.cpp src/ge_vulkan_fbo_texture.cpp src/ge_vulkan_features.cpp src/ge_vulkan_mesh_cache.cpp diff --git a/lib/graphics_engine/include/ge_main.hpp b/lib/graphics_engine/include/ge_main.hpp index 17d00134b5a..8d1540de2ab 100644 --- a/lib/graphics_engine/include/ge_main.hpp +++ b/lib/graphics_engine/include/ge_main.hpp @@ -29,6 +29,7 @@ bool m_texture_compression; bool m_fullscreen_desktop; bool m_enable_draw_call_cache; bool m_pbr; +bool m_ibl; std::unordered_set m_ondemand_load_texture_paths; float m_render_scale; }; diff --git a/lib/graphics_engine/include/ge_vulkan_driver.hpp b/lib/graphics_engine/include/ge_vulkan_driver.hpp index 3d2433f7b28..fe8f64f7dae 100644 --- a/lib/graphics_engine/include/ge_vulkan_driver.hpp +++ b/lib/graphics_engine/include/ge_vulkan_driver.hpp @@ -342,7 +342,8 @@ namespace GE destroySwapChainRelated(false/*handle_surface*/); createSwapChainRelated(false/*handle_surface*/); } - void updateDriver(bool pbr_changed = false); + void updateDriver(bool scale_changed = true, bool pbr_changed = false, + bool ibl_changed = false); void reloadShaders(); uint32_t getGraphicsFamily() const { return m_graphics_family; } unsigned getGraphicsQueueCount() const diff --git a/lib/graphics_engine/include/ge_vulkan_features.hpp b/lib/graphics_engine/include/ge_vulkan_features.hpp index e19ed9ea125..a7c8ae3729a 100644 --- a/lib/graphics_engine/include/ge_vulkan_features.hpp +++ b/lib/graphics_engine/include/ge_vulkan_features.hpp @@ -42,6 +42,8 @@ bool supportsS3TCBC3(); bool supportsBPTCBC7(); // ---------------------------------------------------------------------------- bool supportsASTC4x4(); +// ---------------------------------------------------------------------------- +bool supportsShaderStorageImageExtendedFormats(); }; // GEVulkanFeatures } diff --git a/lib/graphics_engine/src/ge_main.cpp b/lib/graphics_engine/src/ge_main.cpp index ab042214f36..fd767aa69b6 100644 --- a/lib/graphics_engine/src/ge_main.cpp +++ b/lib/graphics_engine/src/ge_main.cpp @@ -22,6 +22,7 @@ GEConfig g_config = true, false, false, + true, {}, 1.0f }; diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index 747d61f030d..dc0584c230c 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -10,6 +10,7 @@ #include "ge_vulkan_driver.hpp" #include "ge_vulkan_dynamic_buffer.hpp" #include "ge_vulkan_dynamic_spm_buffer.hpp" +#include "ge_vulkan_environment_map.hpp" #include "ge_vulkan_fbo_texture.hpp" #include "ge_vulkan_features.hpp" #include "ge_vulkan_mesh_cache.hpp" @@ -1117,6 +1118,36 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, pipeline_info.subpass = 0; pipeline_info.basePipelineHandle = VK_NULL_HANDLE; + struct Constants + { + VkBool32 m_ibl; + float m_specular_levels_minus_one; + }; + Constants constants = {}; + constants.m_ibl = getGEConfig()->m_pbr && getGEConfig()->m_ibl && + GEVulkanFeatures::supportsComputeInMainQueue() && + m_skybox_renderer != NULL; + float ts = GEVulkanEnvironmentMap::getSpecularEnvironmentMapSize().Width; + constants.m_specular_levels_minus_one = std::floor(std::log2(ts)); + std::array specialization_entries = {}; + specialization_entries[0].constantID = 0; + specialization_entries[0].offset = offsetof(Constants, m_ibl); + specialization_entries[0].size = sizeof(VkBool32); + specialization_entries[1].constantID = 1; + specialization_entries[1].offset = offsetof(Constants, + m_specular_levels_minus_one); + specialization_entries[1].size = sizeof(float); + VkSpecializationInfo specialization_info = {}; + specialization_info.mapEntryCount = specialization_entries.size(); + specialization_info.pMapEntries = specialization_entries.data(); + specialization_info.dataSize = sizeof(Constants); + specialization_info.pData = &constants; + if (getGEConfig()->m_pbr) + { + shader_stages[0].pSpecializationInfo = &specialization_info; + shader_stages[1].pSpecializationInfo = &specialization_info; + } + shader_stages[0].module = GEVulkanShaderManager::getShader( settings.m_vertex_shader); shader_stages[1].module = GEVulkanShaderManager::getShader( @@ -1360,11 +1391,16 @@ void GEVulkanDrawCall::createVulkanData() } // m_pipeline_layout - std::array all_layouts = - {{ + std::vector all_layouts = + { *m_texture_descriptor->getDescriptorSetLayout(), m_data_layout - }}; + }; + if (getGEConfig()->m_pbr) + { + all_layouts.push_back( + vk->getSkyBoxRenderer()->getEnvDescriptorSetLayout()); + } VkPipelineLayoutCreateInfo pipeline_layout_info = {}; pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; @@ -1389,6 +1425,8 @@ void GEVulkanDrawCall::createVulkanData() "vkCreatePipelineLayout failed for m_pipeline_layout"); } + all_layouts.resize(2); + pipeline_layout_info.setLayoutCount = all_layouts.size(); all_layouts[0] = vk->getSkyBoxRenderer()->getDescriptorSetLayout(); result = vkCreatePipelineLayout(vk->getDevice(), &pipeline_layout_info, NULL, &m_skybox_layout); @@ -1570,6 +1608,12 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, 0u, 0u, }; + if (getGEConfig()->m_pbr) + { + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + m_pipeline_layout, 2, 1, + vk->getSkyBoxRenderer()->getEnvDescriptorSet(), 0, NULL); + } if (bind_mesh_textures) { if (!bound_mesh_textures_once) diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index b26e0835924..af77da6fe4a 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -2516,12 +2516,14 @@ bool GEVulkanDriver::setRenderTarget(video::ITexture* texture, } // setRenderTarget // ---------------------------------------------------------------------------- -void GEVulkanDriver::updateDriver(bool pbr_changed) +void GEVulkanDriver::updateDriver(bool scale_changed, bool pbr_changed, + bool ibl_changed) { waitIdle(); setDisableWaitIdle(true); clearDrawCallsCache(); - destroySwapChainRelated(false/*handle_surface*/); + if (scale_changed) + destroySwapChainRelated(false/*handle_surface*/); if (pbr_changed) { GEVulkanShaderManager::destroy(); @@ -2555,12 +2557,18 @@ void GEVulkanDriver::updateDriver(bool pbr_changed) for (GEVulkanDynamicSPMBuffer* buffer : m_dynamic_spm_buffers) buffer->setDirtyOffset(0, irr::scene::EBT_VERTEX); } - createSwapChainRelated(false/*handle_surface*/); + if (pbr_changed || ibl_changed) + m_skybox_renderer->reset(); + if (scale_changed) + createSwapChainRelated(false/*handle_surface*/); for (auto& dc : static_cast( m_irrlicht_device->getSceneManager())->getDrawCalls()) dc.second = std::unique_ptr(new GEVulkanDrawCall); - GEVulkan2dRenderer::destroy(); - GEVulkan2dRenderer::init(this); + if (scale_changed || pbr_changed) + { + GEVulkan2dRenderer::destroy(); + GEVulkan2dRenderer::init(this); + } setDisableWaitIdle(false); } // updateDriver diff --git a/lib/graphics_engine/src/ge_vulkan_environment_map.cpp b/lib/graphics_engine/src/ge_vulkan_environment_map.cpp new file mode 100644 index 00000000000..50ebf781a47 --- /dev/null +++ b/lib/graphics_engine/src/ge_vulkan_environment_map.cpp @@ -0,0 +1,334 @@ +#include "ge_vulkan_environment_map.hpp" + +#include "ge_main.hpp" +#include "ge_vulkan_array_texture.hpp" +#include "ge_vulkan_command_loader.hpp" +#include "ge_vulkan_driver.hpp" +#include "ge_vulkan_shader_manager.hpp" +#include "ge_vulkan_skybox_renderer.hpp" + +#include +#include + +namespace GE +{ +// ---------------------------------------------------------------------------- +GEVulkanEnvironmentMap::GEVulkanEnvironmentMap(GEVulkanSkyBoxRenderer* skybox) + : m_skybox(skybox) +{ + m_skybox->m_env_cubemap_loading.store(true); +} // GEVulkanEnvironmentMap + +// ---------------------------------------------------------------------------- +GEVulkanEnvironmentMap::~GEVulkanEnvironmentMap() +{ + m_skybox->m_env_cubemap_loading.store(false); +} // ~GEVulkanEnvironmentMap + +// ---------------------------------------------------------------------------- +void GEVulkanEnvironmentMap::load() +{ + struct PushConstants + { + int m_size; + int m_sample_count; + int m_level; + int m_total_mipmaps; + }; + PushConstants pc; + VkPushConstantRange push_constant = {}; + push_constant.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + push_constant.offset = 0; + push_constant.size = sizeof(PushConstants); + + VkPipelineLayoutCreateInfo pipeline_layout_info = {}; + pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_info.setLayoutCount = 1; + pipeline_layout_info.pushConstantRangeCount = 1; + pipeline_layout_info.pPushConstantRanges = &push_constant; + + std::array bindings = {}; + bindings[0].binding = 0; + bindings[0].descriptorCount = 1; + bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + bindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + bindings[1].binding = 1; + bindings[1].descriptorCount = 1; + bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + bindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + + VkDescriptorSetLayoutCreateInfo setinfo = {}; + setinfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + setinfo.pBindings = bindings.data(); + setinfo.bindingCount = bindings.size(); + + GEVulkanDriver* vk = getVKDriver(); + VkDescriptorSetLayout layout = VK_NULL_HANDLE; + VkDescriptorPool descriptor_pool = VK_NULL_HANDLE; + std::vector descriptor_sets; + VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; + VkPipeline diffuse_pipeline = VK_NULL_HANDLE; + VkPipeline specular_pipeline = VK_NULL_HANDLE; + + auto levels = [](GEVulkanArrayTexture* t) + { + std::vector l; + l.push_back(t->getSize().Width); + unsigned width = l.back(); + while (true) + { + width = width < 2 ? 1 : width >> 1; + l.push_back(width); + if (width == 1) + break; + } + return l; + }; + GEVulkanArrayTexture* texture_cubemap = m_skybox->m_texture_cubemap; + GEVulkanArrayTexture* diffuse_env_cubemap = + m_skybox->m_diffuse_env_cubemap; + GEVulkanArrayTexture* specular_env_cubemap = + m_skybox->m_specular_env_cubemap; + std::vector diffuse_levels = levels(diffuse_env_cubemap); + std::vector specular_levels = levels(specular_env_cubemap); + unsigned total_levels = diffuse_levels.size() + specular_levels.size(); + std::array pool_sizes = + {{ + { + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, total_levels + }, + { + VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, total_levels + } + }}; + VkDescriptorPoolCreateInfo pool_info = {}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.maxSets = total_levels; + pool_info.poolSizeCount = pool_sizes.size(); + pool_info.pPoolSizes = pool_sizes.data(); + + std::vector data_layouts; + VkDescriptorSetAllocateInfo alloc_info = {}; + + VkComputePipelineCreateInfo compute_info = {}; + compute_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + compute_info.stage.sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + compute_info.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; + compute_info.stage.pName = "main"; + + VkCommandBuffer cmd = VK_NULL_HANDLE; + + std::vector image_infos; + std::vector image_views; + for (unsigned i = 0; i < diffuse_levels.size(); i++) + { + VkImageViewCreateInfo view_info = {}; + view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + view_info.image = diffuse_env_cubemap->getImage(); + view_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + view_info.format = diffuse_env_cubemap->getInternalFormat(); + view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view_info.subresourceRange.baseMipLevel = i; + view_info.subresourceRange.levelCount = 1; + view_info.subresourceRange.baseArrayLayer = 0; + view_info.subresourceRange.layerCount = 6; + VkImageView view = VK_NULL_HANDLE; + if (vkCreateImageView(vk->getDevice(), &view_info, NULL, &view) + != VK_SUCCESS) + { + printf("vkCreateImageView failed for " + "GEVulkanEnvironmentMap::load"); + goto destroy; + } + image_views.push_back(view); + } + for (unsigned i = 0; i < specular_levels.size(); i++) + { + VkImageViewCreateInfo view_info = {}; + view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + view_info.image = specular_env_cubemap->getImage(); + view_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + view_info.format = specular_env_cubemap->getInternalFormat(); + view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view_info.subresourceRange.baseMipLevel = i; + view_info.subresourceRange.levelCount = 1; + view_info.subresourceRange.baseArrayLayer = 0; + view_info.subresourceRange.layerCount = 6; + VkImageView view = VK_NULL_HANDLE; + if (vkCreateImageView(vk->getDevice(), &view_info, NULL, &view) + != VK_SUCCESS) + { + printf("vkCreateImageView failed for " + "GEVulkanEnvironmentMap::load"); + goto destroy; + } + image_views.push_back(view); + } + + if (vkCreateDescriptorSetLayout(vk->getDevice(), &setinfo, NULL, + &layout) != VK_SUCCESS) + { + printf("vkCreateDescriptorSetLayout failed for " + "GEVulkanEnvironmentMap::load"); + goto destroy; + } + + if (vkCreateDescriptorPool(vk->getDevice(), &pool_info, NULL, + &descriptor_pool) != VK_SUCCESS) + { + printf("createDescriptorPool for GEVulkanEnvironmentMap::load"); + goto destroy; + } + + data_layouts.resize(total_levels, layout); + descriptor_sets.resize(total_levels); + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = descriptor_pool; + alloc_info.descriptorSetCount = data_layouts.size(); + alloc_info.pSetLayouts = data_layouts.data(); + if (vkAllocateDescriptorSets(vk->getDevice(), &alloc_info, + descriptor_sets.data()) != VK_SUCCESS) + { + printf("vkAllocateDescriptorSets failed for " + "GEVulkanEnvironmentMap::load"); + goto destroy; + } + + for (VkImageView view : image_views) + { + VkDescriptorImageInfo info = {}; + info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + info.sampler = vk->getSampler(GVS_SKYBOX); + info.imageView = texture_cubemap->getImageView(true/*srgb*/)->load(); + image_infos.push_back(info); + info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + info.imageView = view; + image_infos.push_back(info); + } + + for (unsigned i = 0; i < total_levels; i++) + { + std::array write_descriptor_set = {}; + write_descriptor_set[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptor_set[0].dstSet = descriptor_sets[i]; + write_descriptor_set[0].dstBinding = 0; + write_descriptor_set[0].descriptorType = + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_descriptor_set[0].descriptorCount = 1; + write_descriptor_set[0].pImageInfo = &image_infos[i * 2]; + + write_descriptor_set[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptor_set[1].dstSet = descriptor_sets[i]; + write_descriptor_set[1].dstBinding = 1; + write_descriptor_set[1].descriptorType = + VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + write_descriptor_set[1].descriptorCount = 1; + write_descriptor_set[1].pImageInfo = &image_infos[i * 2 + 1]; + + vkUpdateDescriptorSets(vk->getDevice(), write_descriptor_set.size(), + write_descriptor_set.data(), 0, NULL); + } + + pipeline_layout_info.pSetLayouts = &layout; + if (vkCreatePipelineLayout(vk->getDevice(), &pipeline_layout_info, NULL, + &pipeline_layout) != VK_SUCCESS) + { + printf("vkCreatePipelineLayout failed for " + "GEVulkanEnvironmentMap::load"); + goto destroy; + } + + compute_info.stage.module = + GEVulkanShaderManager::getShader("diffuse_irradiance.comp"); + compute_info.layout = pipeline_layout; + if (vkCreateComputePipelines(vk->getDevice(), NULL, 1, &compute_info, + NULL, &diffuse_pipeline) != VK_SUCCESS) + { + printf("vkCreateComputePipelines failed for " + "GEVulkanEnvironmentMap::load"); + goto destroy; + } + + compute_info.stage.module = + GEVulkanShaderManager::getShader("specular_prefilter.comp"); + if (vkCreateComputePipelines(vk->getDevice(), NULL, 1, &compute_info, + NULL, &specular_pipeline) != VK_SUCCESS) + { + printf("vkCreateComputePipelines failed for " + "GEVulkanEnvironmentMap::load"); + goto destroy; + } + + cmd = GEVulkanCommandLoader::beginSingleTimeCommands(); + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, diffuse_pipeline); + for (unsigned i = 0; i < diffuse_levels.size(); i++) + { + PushConstants pc; + pc.m_size = diffuse_levels[i]; + pc.m_sample_count = getDiffuseEnvironmentMapSampleCount(); + pc.m_level = i; + pc.m_total_mipmaps = diffuse_levels.size(); + + vkCmdPushConstants(cmd, pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(PushConstants), &pc); + + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, + pipeline_layout, 0, 1, &descriptor_sets[i], 0, NULL); + + // Calculate dispatch size (ceil(size/16)) + uint32_t dispatch_size = (pc.m_size + 15) / 16; + vkCmdDispatch(cmd, dispatch_size, dispatch_size, 6); + } + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, specular_pipeline); + for (unsigned i = 0; i < specular_levels.size(); i++) + { + const unsigned offset = diffuse_levels.size(); + auto next_power_of_2 = [](unsigned v) + { + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; + }; + PushConstants pc; + pc.m_size = specular_levels[i]; + // Calculate sample count: start with size / 2, minimum 16 + pc.m_sample_count = std::max(16u, + next_power_of_2(specular_levels[i] / 2)); + pc.m_level = i; + pc.m_total_mipmaps = specular_levels.size(); + + vkCmdPushConstants(cmd, pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(PushConstants), &pc); + + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, + pipeline_layout, 0, 1, &descriptor_sets[i + offset], 0, NULL); + + uint32_t dispatch_size = (pc.m_size + 15) / 16; + vkCmdDispatch(cmd, dispatch_size, dispatch_size, 6); + } + +destroy: + if (cmd != VK_NULL_HANDLE) + GEVulkanCommandLoader::endSingleTimeCommands(cmd); + if (specular_pipeline != VK_NULL_HANDLE) + vkDestroyPipeline(vk->getDevice(), specular_pipeline, NULL); + if (diffuse_pipeline != VK_NULL_HANDLE) + vkDestroyPipeline(vk->getDevice(), diffuse_pipeline, NULL); + if (pipeline_layout != VK_NULL_HANDLE) + vkDestroyPipelineLayout(vk->getDevice(), pipeline_layout, NULL); + if (descriptor_pool != VK_NULL_HANDLE) + vkDestroyDescriptorPool(vk->getDevice(), descriptor_pool, NULL); + if (layout != VK_NULL_HANDLE) + vkDestroyDescriptorSetLayout(vk->getDevice(), layout, NULL); + for (VkImageView view : image_views) + vkDestroyImageView(vk->getDevice(), view, NULL); +} // load + +} diff --git a/lib/graphics_engine/src/ge_vulkan_environment_map.hpp b/lib/graphics_engine/src/ge_vulkan_environment_map.hpp new file mode 100644 index 00000000000..1b161dc1361 --- /dev/null +++ b/lib/graphics_engine/src/ge_vulkan_environment_map.hpp @@ -0,0 +1,37 @@ +#ifndef HEADER_GE_VULKAN_ENVIRONMENT_MAP_HPP +#define HEADER_GE_VULKAN_ENVIRONMENT_MAP_HPP + +#include "dimension2d.h" + +namespace GE +{ +class GEVulkanSkyBoxRenderer; + +class GEVulkanEnvironmentMap +{ +private: + GEVulkanSkyBoxRenderer* m_skybox; +public: + // ------------------------------------------------------------------------ + GEVulkanEnvironmentMap(GEVulkanSkyBoxRenderer* skybox); + // ------------------------------------------------------------------------ + ~GEVulkanEnvironmentMap(); + // ------------------------------------------------------------------------ + /** A much lower resolution than the input cubemap is sufficient because + * diffuse reflections are inherently blurry. + */ + const static irr::core::dimension2du getDiffuseEnvironmentMapSize() + { return irr::core::dimension2du(32, 32); } + // ------------------------------------------------------------------------ + const static irr::core::dimension2du getSpecularEnvironmentMapSize() + { return irr::core::dimension2du(256, 256); } + // ------------------------------------------------------------------------ + const static unsigned getDiffuseEnvironmentMapSampleCount() + { return 256; } + // ------------------------------------------------------------------------ + void load(); +}; // GEVulkanEnvironmentMap + +} + +#endif diff --git a/lib/graphics_engine/src/ge_vulkan_features.cpp b/lib/graphics_engine/src/ge_vulkan_features.cpp index ec3dabd7543..38f5580a0e6 100644 --- a/lib/graphics_engine/src/ge_vulkan_features.cpp +++ b/lib/graphics_engine/src/ge_vulkan_features.cpp @@ -32,6 +32,7 @@ bool g_supports_shader_draw_parameters = false; bool g_supports_s3tc_bc3 = false; bool g_supports_bptc_bc7 = false; bool g_supports_astc_4x4 = false; +bool g_supports_shader_storage_image_extended_format = false; } // GEVulkanFeatures // ============================================================================ @@ -89,6 +90,7 @@ void GEVulkanFeatures::init(GEVulkanDriver* vk) vkGetPhysicalDeviceFormatProperties(vk->getPhysicalDevice(), VK_FORMAT_ASTC_4x4_UNORM_BLOCK, &format_properties); g_supports_astc_4x4 = format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; + g_supports_shader_storage_image_extended_format = vk->getPhysicalDeviceFeatures().shaderStorageImageExtendedFormats; uint32_t extension_count; vkEnumerateDeviceExtensionProperties(vk->getPhysicalDevice(), NULL, @@ -235,6 +237,8 @@ void GEVulkanFeatures::printStats() os::Printer::log( "Vulkan supports adaptive scalable texture compression (4x4 block)", supportsASTC4x4() ? "true" : "false"); + os::Printer::log("Vulkan supports shader storage image extended formats", + supportsShaderStorageImageExtendedFormats() ? "true" : "false"); os::Printer::log( "Vulkan descriptor indexes can be dynamically non-uniform", g_supports_non_uniform_indexing ? "true" : "false"); @@ -339,4 +343,10 @@ bool GEVulkanFeatures::supportsASTC4x4() return g_supports_astc_4x4 && GECompressorASTC4x4::loaded(); } // supportsASTC4x4 +// ---------------------------------------------------------------------------- +bool GEVulkanFeatures::supportsShaderStorageImageExtendedFormats() +{ + return g_supports_shader_storage_image_extended_format; +} // supportsShaderStorageImageExtendedFormats + } diff --git a/lib/graphics_engine/src/ge_vulkan_shader_manager.cpp b/lib/graphics_engine/src/ge_vulkan_shader_manager.cpp index 9ddcd68b805..ca336ec07fe 100644 --- a/lib/graphics_engine/src/ge_vulkan_shader_manager.cpp +++ b/lib/graphics_engine/src/ge_vulkan_shader_manager.cpp @@ -75,6 +75,8 @@ void GEVulkanShaderManager::init(GEVulkanDriver* vk) } else oss << "#define GE_SAMPLE_TEX_INDEX int\n"; + if (GEVulkanFeatures::supportsShaderStorageImageExtendedFormats()) + oss << "#define SHADER_STORAGE_IMAGE_EXTENDED_FORMATS\n"; g_predefines = oss.str(); loadAllShaders(); diff --git a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp index c236666e7e6..7b03c049688 100644 --- a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp +++ b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp @@ -3,6 +3,8 @@ #include "ge_main.hpp" #include "ge_vulkan_array_texture.hpp" #include "ge_vulkan_driver.hpp" +#include "ge_vulkan_environment_map.hpp" +#include "ge_vulkan_features.hpp" #include #include @@ -11,42 +13,61 @@ namespace GE { // ---------------------------------------------------------------------------- -GEVulkanSkyBoxRenderer::GEVulkanSkyBoxRenderer() : m_skybox_loading(false) +GEVulkanSkyBoxRenderer::GEVulkanSkyBoxRenderer() + : m_skybox(NULL), m_texture_cubemap(NULL), + m_diffuse_env_cubemap(NULL), + m_specular_env_cubemap(NULL), + m_dummy_env_cubemap(NULL), + m_descriptor_layout(VK_NULL_HANDLE), + m_env_descriptor_layout(VK_NULL_HANDLE), + m_descriptor_pool(VK_NULL_HANDLE), + m_skybox_loading(false), m_env_cubemap_loading(false) { - m_skybox = NULL; - m_texture_cubemap = NULL; + m_dummy_env_cubemap = new GEVulkanArrayTexture(VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_VIEW_TYPE_CUBE, core::dimension2du(4, 4), 6, + video::SColor(0)); GEVulkanDriver* vk = getVKDriver(); // m_descriptor_layout - VkDescriptorSetLayoutBinding texture_layout_binding; - texture_layout_binding.binding = 0; - texture_layout_binding.descriptorCount = 1; - texture_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - texture_layout_binding.pImmutableSamplers = NULL; - texture_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + std::vector texture_layout_binding(2); + texture_layout_binding[0].binding = 0; + texture_layout_binding[0].descriptorCount = 1; + texture_layout_binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + texture_layout_binding[0].pImmutableSamplers = NULL; + texture_layout_binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; VkDescriptorSetLayoutCreateInfo setinfo = {}; setinfo.flags = 0; setinfo.pNext = NULL; setinfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - setinfo.pBindings = &texture_layout_binding; + setinfo.pBindings = texture_layout_binding.data(); setinfo.bindingCount = 1; if (vkCreateDescriptorSetLayout(vk->getDevice(), &setinfo, NULL, &m_descriptor_layout) != VK_SUCCESS) { throw std::runtime_error("vkCreateDescriptorSetLayout failed for " - "GEVulkanSkyBoxRenderer"); + "GEVulkanSkyBoxRenderer::m_descriptor_layout"); + } + + texture_layout_binding[1] = texture_layout_binding[0]; + texture_layout_binding[1].binding = 1; + setinfo.bindingCount = 2; + if (vkCreateDescriptorSetLayout(vk->getDevice(), &setinfo, + NULL, &m_env_descriptor_layout) != VK_SUCCESS) + { + throw std::runtime_error("vkCreateDescriptorSetLayout failed for " + "GEVulkanSkyBoxRenderer::m_env_descriptor_layout"); } // m_descriptor_pool VkDescriptorPoolSize pool_size; pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - pool_size.descriptorCount = 1; + pool_size.descriptorCount = 1 + m_env_descriptor_set.size() * 2; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = 0; - pool_info.maxSets = 1; + pool_info.maxSets = 1 + m_env_descriptor_set.size(); pool_info.poolSizeCount = 1; pool_info.pPoolSizes = &pool_size; if (vkCreateDescriptorPool(vk->getDevice(), &pool_info, NULL, @@ -69,8 +90,37 @@ GEVulkanSkyBoxRenderer::GEVulkanSkyBoxRenderer() : m_skybox_loading(false) &m_descriptor_set) != VK_SUCCESS) { throw std::runtime_error("vkAllocateDescriptorSets failed for " - "GEVulkanSkyBoxRenderer"); + "GEVulkanSkyBoxRenderer::m_descriptor_set"); } + + layouts.clear(); + layouts.resize(2, m_env_descriptor_layout); + alloc_info.descriptorSetCount = layouts.size(); + alloc_info.pSetLayouts = layouts.data(); + if (vkAllocateDescriptorSets(vk->getDevice(), &alloc_info, + m_env_descriptor_set.data()) != VK_SUCCESS) + { + throw std::runtime_error("vkAllocateDescriptorSets failed for " + "GEVulkanSkyBoxRenderer::m_env_descriptor_set"); + } + + std::array info; + info[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL; + info[0].sampler = vk->getSampler(GVS_SKYBOX); + info[0].imageView = (VkImageView)m_dummy_env_cubemap->getTextureHandler(); + info[1] = info[0]; + + VkWriteDescriptorSet write_descriptor_set = {}; + write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptor_set.dstBinding = 0; + write_descriptor_set.dstArrayElement = 0; + write_descriptor_set.descriptorType = + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_descriptor_set.descriptorCount = 2; + write_descriptor_set.pBufferInfo = 0; + write_descriptor_set.dstSet = m_env_descriptor_set[0]; + write_descriptor_set.pImageInfo = info.data(); + vkUpdateDescriptorSets(vk->getDevice(), 1, &write_descriptor_set, 0, NULL); } // init // ---------------------------------------------------------------------------- @@ -82,11 +132,27 @@ GEVulkanSkyBoxRenderer::~GEVulkanSkyBoxRenderer() vk->waitIdle(); while (m_skybox_loading.load()); + while (m_env_cubemap_loading.load()); if (m_texture_cubemap != NULL) m_texture_cubemap->drop(); - vkDestroyDescriptorPool(vk->getDevice(), m_descriptor_pool, NULL); - vkDestroyDescriptorSetLayout(vk->getDevice(), m_descriptor_layout, - NULL); + if (m_diffuse_env_cubemap != NULL) + m_diffuse_env_cubemap->drop(); + if (m_specular_env_cubemap != NULL) + m_specular_env_cubemap->drop(); + if (m_dummy_env_cubemap != NULL) + m_dummy_env_cubemap->drop(); + if (m_descriptor_pool != VK_NULL_HANDLE) + vkDestroyDescriptorPool(vk->getDevice(), m_descriptor_pool, NULL); + if (m_env_descriptor_layout != VK_NULL_HANDLE) + { + vkDestroyDescriptorSetLayout(vk->getDevice(), m_env_descriptor_layout, + NULL); + } + if (m_descriptor_layout != VK_NULL_HANDLE) + { + vkDestroyDescriptorSetLayout(vk->getDevice(), m_descriptor_layout, + NULL); + } } // ~GEVulkanSkyBoxRenderer // ---------------------------------------------------------------------------- @@ -98,6 +164,7 @@ void GEVulkanSkyBoxRenderer::addSkyBox(irr::scene::ISceneNode* skybox) return; while (m_skybox_loading.load()); + while (m_env_cubemap_loading.load()); m_skybox = skybox; std::vector sky_tex; std::array order = {{ 1, 3, 4, 5, 2, 0}}; @@ -114,14 +181,8 @@ void GEVulkanSkyBoxRenderer::addSkyBox(irr::scene::ISceneNode* skybox) { private: GEVulkanSkyBoxRenderer* m_sky; - public: // ---------------------------------------------------------------- - ImageManipulator(GEVulkanSkyBoxRenderer* sky) : m_sky(sky) - { - m_sky->m_skybox_loading.store(true); - } - // ---------------------------------------------------------------- - ~ImageManipulator() + void updateDescriptor() { GEVulkanDriver* vk = getVKDriver(); VkDescriptorImageInfo info; @@ -146,6 +207,24 @@ void GEVulkanSkyBoxRenderer::addSkyBox(irr::scene::ISceneNode* skybox) &write_descriptor_set, 0, NULL); m_sky->m_skybox_loading.store(false); } + public: + // ---------------------------------------------------------------- + ImageManipulator(GEVulkanSkyBoxRenderer* sky) : m_sky(sky) + { + m_sky->m_skybox_loading.store(true); + } + // ---------------------------------------------------------------- + ~ImageManipulator() + { + if (m_sky->m_diffuse_env_cubemap != NULL) + { + GEVulkanEnvironmentMap env(m_sky); + updateDescriptor(); + env.load(); + } + else + updateDescriptor(); + } // ---------------------------------------------------------------- void swapPixels(video::IImage* img, unsigned idx) { @@ -175,10 +254,84 @@ void GEVulkanSkyBoxRenderer::addSkyBox(irr::scene::ISceneNode* skybox) { image_manipulator->swapPixels(img, idx); }; + + if (getGEConfig()->m_pbr && getGEConfig()->m_ibl && + GEVulkanFeatures::supportsComputeInMainQueue()) + { + VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; + if (GEVulkanFeatures::supportsShaderStorageImageExtendedFormats()) + format = VK_FORMAT_A2B10G10R10_UNORM_PACK32; + bool update_descriptor = false; + if (m_diffuse_env_cubemap == NULL) + { + m_diffuse_env_cubemap = + new GEVulkanArrayTexture(format, VK_IMAGE_VIEW_TYPE_CUBE, + GEVulkanEnvironmentMap::getDiffuseEnvironmentMapSize(), 6, + video::SColor(0)); + update_descriptor = true; + } + if (m_specular_env_cubemap == NULL) + { + m_specular_env_cubemap = + new GEVulkanArrayTexture(format, VK_IMAGE_VIEW_TYPE_CUBE, + GEVulkanEnvironmentMap::getSpecularEnvironmentMapSize(), 6, + video::SColor(0)); + update_descriptor = true; + } + if (update_descriptor) + { + GEVulkanDriver* vk = getVKDriver(); + std::array info; + info[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL; + info[0].sampler = vk->getSampler(GVS_SKYBOX); + info[0].imageView = (VkImageView) + m_diffuse_env_cubemap->getTextureHandler(); + info[1] = info[0]; + info[1].imageView = (VkImageView) + m_specular_env_cubemap->getTextureHandler(); + + VkWriteDescriptorSet write_descriptor_set = {}; + write_descriptor_set.sType = + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptor_set.dstBinding = 0; + write_descriptor_set.dstArrayElement = 0; + write_descriptor_set.descriptorType = + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_descriptor_set.descriptorCount = 2; + write_descriptor_set.pBufferInfo = 0; + write_descriptor_set.dstSet = m_env_descriptor_set[1]; + write_descriptor_set.pImageInfo = info.data(); + vkUpdateDescriptorSets(vk->getDevice(), 1, &write_descriptor_set, + 0, NULL); + } + } + else + { + if (m_diffuse_env_cubemap != NULL) + { + m_diffuse_env_cubemap->drop(); + m_diffuse_env_cubemap = NULL; + } + if (m_specular_env_cubemap != NULL) + { + m_specular_env_cubemap->drop(); + m_specular_env_cubemap = NULL; + } + } + if (m_texture_cubemap) m_texture_cubemap->drop(); m_texture_cubemap = new GEVulkanArrayTexture(sky_tex, VK_IMAGE_VIEW_TYPE_CUBE, real_mani); } // addSkyBox +// ---------------------------------------------------------------------------- +const VkDescriptorSet* GEVulkanSkyBoxRenderer::getEnvDescriptorSet() const +{ + if (m_diffuse_env_cubemap == NULL || m_skybox_loading.load() == true || + m_env_cubemap_loading.load() == true) + return &m_env_descriptor_set[0]; + return &m_env_descriptor_set[1]; +} // getEnvDescriptorSet + } diff --git a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp index 67ea959d035..9d44a06e471 100644 --- a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp +++ b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp @@ -2,6 +2,7 @@ #define HEADER_GE_VULKAN_SKYBOX_RENDERER_HPP #include "vulkan_wrapper.h" +#include #include namespace irr @@ -12,21 +13,26 @@ namespace irr namespace GE { class GEVulkanArrayTexture; +class GEVulkanEnvironmentMap; class GEVulkanSkyBoxRenderer { private: + friend class GEVulkanEnvironmentMap; irr::scene::ISceneNode* m_skybox; - GEVulkanArrayTexture* m_texture_cubemap; + GEVulkanArrayTexture *m_texture_cubemap, *m_diffuse_env_cubemap, + *m_specular_env_cubemap, *m_dummy_env_cubemap; - VkDescriptorSetLayout m_descriptor_layout; + VkDescriptorSetLayout m_descriptor_layout, m_env_descriptor_layout; VkDescriptorPool m_descriptor_pool; VkDescriptorSet m_descriptor_set; - std::atomic_bool m_skybox_loading; + std::array m_env_descriptor_set; + + std::atomic_bool m_skybox_loading, m_env_cubemap_loading; public: // ------------------------------------------------------------------------ GEVulkanSkyBoxRenderer(); @@ -38,12 +44,24 @@ class GEVulkanSkyBoxRenderer VkDescriptorSetLayout getDescriptorSetLayout() const { return m_descriptor_layout; } // ------------------------------------------------------------------------ + VkDescriptorSetLayout getEnvDescriptorSetLayout() const + { return m_env_descriptor_layout; } + // ------------------------------------------------------------------------ const VkDescriptorSet* getDescriptorSet() const { if (m_skybox_loading.load() == true) return NULL; return &m_descriptor_set; } + // ------------------------------------------------------------------------ + const VkDescriptorSet* getEnvDescriptorSet() const; + // ------------------------------------------------------------------------ + void reset() + { + while (m_skybox_loading.load()); + while (m_env_cubemap_loading.load()); + m_skybox = NULL; + } }; // GEVulkanSkyBoxRenderer diff --git a/lib/graphics_engine/src/ge_vulkan_texture.hpp b/lib/graphics_engine/src/ge_vulkan_texture.hpp index 051e752fb77..cff13027e64 100644 --- a/lib/graphics_engine/src/ge_vulkan_texture.hpp +++ b/lib/graphics_engine/src/ge_vulkan_texture.hpp @@ -244,6 +244,12 @@ class GEVulkanTexture : public video::ITexture virtual const io::path& getFullPath() const { return m_full_path; } // ------------------------------------------------------------------------ VkFormat getInternalFormat() const { return m_internal_format; } + // ------------------------------------------------------------------------ + VkImage getImage() const + { + waitImageView(); + return m_image; + } }; // GEVulkanTexture } diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 7ed753a3300..a0d1480b810 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -522,6 +522,8 @@ void IrrDriver::initDevice() UserConfigParams::m_scale_rtts_factor; GE::getGEConfig()->m_pbr = UserConfigParams::m_dynamic_lights; + GE::getGEConfig()->m_ibl = + !UserConfigParams::m_degraded_IBL; #endif } else diff --git a/src/states_screens/dialogs/custom_video_settings.cpp b/src/states_screens/dialogs/custom_video_settings.cpp index 5fb6e22ff19..e3d59dc8567 100644 --- a/src/states_screens/dialogs/custom_video_settings.cpp +++ b/src/states_screens/dialogs/custom_video_settings.cpp @@ -145,6 +145,7 @@ GUIEngine::EventPropagation CustomVideoSettingsDialog::processEvent(const std::s { bool advanced_pipeline = getWidget("dynamiclight")->getState(); bool pbr_changed = false; + bool ibl_changed = false; if (UserConfigParams::m_dynamic_lights != advanced_pipeline) { pbr_changed = true; @@ -181,8 +182,13 @@ GUIEngine::EventPropagation CustomVideoSettingsDialog::processEvent(const std::s UserConfigParams::m_light_shaft = advanced_pipeline && getWidget("lightshaft")->getState(); - UserConfigParams::m_degraded_IBL = - !advanced_pipeline || !getWidget("ibl")->getState(); + bool degraded_ibl = !advanced_pipeline || !getWidget("ibl")->getState(); + if (UserConfigParams::m_degraded_IBL != degraded_ibl) + { + ibl_changed = true; + GE::getGEConfig()->m_ibl = !degraded_ibl; + UserConfigParams::m_degraded_IBL = degraded_ibl; + } UserConfigParams::m_glow = advanced_pipeline && getWidget("glow")->getState(); @@ -195,9 +201,7 @@ GUIEngine::EventPropagation CustomVideoSettingsDialog::processEvent(const std::s UserConfigParams::m_texture_compression = getWidget("texture_compression")->getState(); -#ifndef SERVER_ONLY GE::getGEConfig()->m_texture_compression = UserConfigParams::m_texture_compression; -#endif UserConfigParams::m_particles_effects = getWidget("particles_effects")->getValue(); @@ -218,10 +222,8 @@ GUIEngine::EventPropagation CustomVideoSettingsDialog::processEvent(const std::s ModalDialog::dismiss(); OptionsScreenVideo::getInstance()->updateGfxSlider(); OptionsScreenVideo::getInstance()->updateBlurSlider(); -#ifndef SERVER_ONLY - if (pbr_changed && GE::getDriver()->getDriverType() == video::EDT_VULKAN) - GE::getVKDriver()->updateDriver(true); -#endif + if ((pbr_changed || ibl_changed) && GE::getDriver()->getDriverType() == video::EDT_VULKAN) + GE::getVKDriver()->updateDriver(false/*scale_changed*/, pbr_changed, ibl_changed); OptionsScreenVideo::setImageQuality(quality); return GUIEngine::EVENT_BLOCK; } @@ -245,12 +247,14 @@ void CustomVideoSettingsDialog::updateActivation() { #ifndef SERVER_ONLY bool light = getWidget("dynamiclight")->getState(); + bool real_light = light; if (!CVS->isGLSL()) { getWidget("dynamiclight")->setActive(false); light = false; } - if (GE::getDriver()->getDriverType() == video::EDT_VULKAN) + bool vk = GE::getDriver()->getDriverType() == video::EDT_VULKAN; + if (vk) getWidget("dynamiclight")->setActive(true); getWidget("motionblur")->setActive(light); getWidget("dof")->setActive(light); @@ -258,7 +262,7 @@ void CustomVideoSettingsDialog::updateActivation() getWidget("mlaa")->setActive(light); getWidget("ssao")->setActive(light); getWidget("lightshaft")->setActive(light); - getWidget("ibl")->setActive(light); + getWidget("ibl")->setActive(light || (vk && real_light)); getWidget("glow")->setActive(light); getWidget("bloom")->setActive(light); getWidget("lightscattering")->setActive(light); diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index 11957b66641..303b7b93e04 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -105,6 +105,7 @@ enum DebugMenuCommand DEBUG_FONT_DUMP_GLYPH_PAGE, DEBUG_FONT_RELOAD, DEBUG_GE_PBR, + DEBUG_GE_IBL, DEBUG_SP_RESET, DEBUG_SP_TOGGLE_CULLING, DEBUG_SP_WN_VIZ, @@ -394,7 +395,21 @@ bool handleContextMenuAction(s32 cmd_id) { UserConfigParams::m_dynamic_lights = !UserConfigParams::m_dynamic_lights; GE::getGEConfig()->m_pbr = UserConfigParams::m_dynamic_lights; - vk->updateDriver(true); + vk->updateDriver(false/*scale_changed*/, true/*pbr_changed*/); + } + break; + } +#endif + case DEBUG_GE_IBL: +#ifndef SERVER_ONLY + { + GE::GEVulkanDriver* vk = GE::getVKDriver(); + if (vk) + { + UserConfigParams::m_degraded_IBL = !UserConfigParams::m_degraded_IBL; + GE::getGEConfig()->m_ibl = !UserConfigParams::m_degraded_IBL; + vk->updateDriver(false/*scale_changed*/, false/*pbr_changed*/, + true/*ibl_changed*/); } break; } @@ -1307,6 +1322,7 @@ bool onEvent(const SEvent &event) mnu->addItem(L"SP / GE debug >",-1,true, true); sub = mnu->getSubMenu(6); sub->addItem(L"Toggle GE PBR", DEBUG_GE_PBR); + sub->addItem(L"Toggle GE IBL", DEBUG_GE_IBL); sub->addItem(L"Reset SP debug", DEBUG_SP_RESET); sub->addItem(L"Toggle culling", DEBUG_SP_TOGGLE_CULLING); sub->addItem(L"Draw world normal in texture", DEBUG_SP_WN_VIZ); From 35ede2eb19a141578d2e9292876e258e8373b670 Mon Sep 17 00:00:00 2001 From: Deve Date: Sun, 27 Apr 2025 23:15:39 +0200 Subject: [PATCH 681/830] Improve vulkan pipeline settings --- .../src/ge_vulkan_draw_call.cpp | 121 ++++++++++-------- .../src/ge_vulkan_draw_call.hpp | 9 +- 2 files changed, 75 insertions(+), 55 deletions(-) diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index dc0584c230c..7f511064b0d 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -854,6 +854,8 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) settings.m_depth_test = true; settings.m_depth_write = true; settings.m_backface_culling = true; + settings.m_depth_op = VK_COMPARE_OP_LESS; + settings.m_vertex_description = getDefaultVertexDescription(); settings.m_vertex_shader = "spm.vert"; settings.m_skinning_vertex_shader = "spm_skinning.vert"; @@ -920,7 +922,9 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) settings.m_alphablend = false; settings.m_additive = false; - settings.m_fs_quad_pl = m_skybox_layout; + settings.m_custom_pl = m_skybox_layout; + settings.m_depth_op = VK_COMPARE_OP_EQUAL; + settings.m_vertex_description = {}; settings.m_backface_culling = true; settings.m_skinning_vertex_shader = ""; settings.m_vertex_shader = "fullscreen_quad.vert"; @@ -951,58 +955,15 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, frag_shader_stage_info }}; - size_t bone_pitch = sizeof(int16_t) * 8; - size_t static_pitch = sizeof(irr::video::S3DVertexSkinnedMesh) - bone_pitch; - std::array binding_descriptions; - binding_descriptions[0].binding = 0; - binding_descriptions[0].stride = static_pitch; - binding_descriptions[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - binding_descriptions[1].binding = 1; - binding_descriptions[1].stride = bone_pitch; - binding_descriptions[1].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - std::array attribute_descriptions = {}; - attribute_descriptions[0].binding = 0; - attribute_descriptions[0].location = 0; - attribute_descriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT; - attribute_descriptions[0].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_position); - attribute_descriptions[1].binding = 0; - attribute_descriptions[1].location = 1; - attribute_descriptions[1].format = VK_FORMAT_A2B10G10R10_SNORM_PACK32; - attribute_descriptions[1].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_normal); - attribute_descriptions[2].binding = 0; - attribute_descriptions[2].location = 2; - attribute_descriptions[2].format = VK_FORMAT_A8B8G8R8_UNORM_PACK32; - attribute_descriptions[2].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_color); - attribute_descriptions[3].binding = 0; - attribute_descriptions[3].location = 3; - attribute_descriptions[3].format = VK_FORMAT_R16G16_SFLOAT; - attribute_descriptions[3].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_all_uvs); - attribute_descriptions[4].binding = 0; - attribute_descriptions[4].location = 4; - attribute_descriptions[4].format = VK_FORMAT_R16G16_SFLOAT; - attribute_descriptions[4].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_all_uvs) + (sizeof(int16_t) * 2); - attribute_descriptions[5].binding = 0; - attribute_descriptions[5].location = 5; - attribute_descriptions[5].format = VK_FORMAT_A2B10G10R10_SNORM_PACK32; - attribute_descriptions[5].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_tangent); - attribute_descriptions[6].binding = 1; - attribute_descriptions[6].location = 6; - attribute_descriptions[6].format = VK_FORMAT_R16G16B16A16_SINT; - attribute_descriptions[6].offset = 0; - attribute_descriptions[7].binding = 1; - attribute_descriptions[7].location = 7; - attribute_descriptions[7].format = VK_FORMAT_R16G16B16A16_SFLOAT; - attribute_descriptions[7].offset = sizeof(int16_t) * 4; - VkPipelineVertexInputStateCreateInfo vertex_input_info = {}; vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - if (settings.m_fs_quad_pl == VK_NULL_HANDLE) + auto& vertex_desc = settings.m_vertex_description; + if (!vertex_desc.first.empty()) { - vertex_input_info.vertexBindingDescriptionCount = 2; - vertex_input_info.vertexAttributeDescriptionCount = 8; - vertex_input_info.pVertexBindingDescriptions = binding_descriptions.data(); - vertex_input_info.pVertexAttributeDescriptions = attribute_descriptions.data(); + vertex_input_info.vertexBindingDescriptionCount = vertex_desc.first.size(); + vertex_input_info.vertexAttributeDescriptionCount = vertex_desc.second.size(); + vertex_input_info.pVertexBindingDescriptions = vertex_desc.first.data(); + vertex_input_info.pVertexAttributeDescriptions = vertex_desc.second.data(); } VkPipelineInputAssemblyStateCreateInfo input_assembly = {}; @@ -1049,8 +1010,7 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depth_stencil.depthTestEnable = settings.m_depth_test; depth_stencil.depthWriteEnable = settings.m_depth_write; - depth_stencil.depthCompareOp = settings.m_fs_quad_pl == VK_NULL_HANDLE ? - VK_COMPARE_OP_LESS : VK_COMPARE_OP_EQUAL; + depth_stencil.depthCompareOp = settings.m_depth_op; depth_stencil.depthBoundsTestEnable = VK_FALSE; depth_stencil.stencilTestEnable = VK_FALSE; @@ -1111,8 +1071,8 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, pipeline_info.pDepthStencilState = &depth_stencil; pipeline_info.pColorBlendState = &color_blending; pipeline_info.pDynamicState = &dynamic_state_info; - pipeline_info.layout = settings.m_fs_quad_pl == VK_NULL_HANDLE ? - m_pipeline_layout : settings.m_fs_quad_pl; + pipeline_info.layout = settings.m_custom_pl == VK_NULL_HANDLE ? + m_pipeline_layout : settings.m_custom_pl; pipeline_info.renderPass = vk->getRTTTexture() ? vk->getRTTTexture()->getRTTRenderPass() : vk->getRenderPass(); pipeline_info.subpass = 0; @@ -2096,4 +2056,57 @@ bool GEVulkanDrawCall::doDepthOnlyRenderingFirst() return status == ENABLED; } // doDepthOnlyRenderingFirst +// ---------------------------------------------------------------------------- +VertexDescription GEVulkanDrawCall::getDefaultVertexDescription() const +{ + VertexDescription vertex_description; + auto& binding_descriptions = vertex_description.first; + binding_descriptions.resize(2); + size_t bone_pitch = sizeof(int16_t) * 8; + size_t static_pitch = sizeof(irr::video::S3DVertexSkinnedMesh) - bone_pitch; + binding_descriptions[0].binding = 0; + binding_descriptions[0].stride = static_pitch; + binding_descriptions[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + binding_descriptions[1].binding = 1; + binding_descriptions[1].stride = bone_pitch; + binding_descriptions[1].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + auto& attribute_descriptions = vertex_description.second; + attribute_descriptions.resize(8); + attribute_descriptions[0].binding = 0; + attribute_descriptions[0].location = 0; + attribute_descriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT; + attribute_descriptions[0].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_position); + attribute_descriptions[1].binding = 0; + attribute_descriptions[1].location = 1; + attribute_descriptions[1].format = VK_FORMAT_A2B10G10R10_SNORM_PACK32; + attribute_descriptions[1].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_normal); + attribute_descriptions[2].binding = 0; + attribute_descriptions[2].location = 2; + attribute_descriptions[2].format = VK_FORMAT_A8B8G8R8_UNORM_PACK32; + attribute_descriptions[2].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_color); + attribute_descriptions[3].binding = 0; + attribute_descriptions[3].location = 3; + attribute_descriptions[3].format = VK_FORMAT_R16G16_SFLOAT; + attribute_descriptions[3].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_all_uvs); + attribute_descriptions[4].binding = 0; + attribute_descriptions[4].location = 4; + attribute_descriptions[4].format = VK_FORMAT_R16G16_SFLOAT; + attribute_descriptions[4].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_all_uvs) + (sizeof(int16_t) * 2); + attribute_descriptions[5].binding = 0; + attribute_descriptions[5].location = 5; + attribute_descriptions[5].format = VK_FORMAT_A2B10G10R10_SNORM_PACK32; + attribute_descriptions[5].offset = offsetof(irr::video::S3DVertexSkinnedMesh, m_tangent); + attribute_descriptions[6].binding = 1; + attribute_descriptions[6].location = 6; + attribute_descriptions[6].format = VK_FORMAT_R16G16B16A16_SINT; + attribute_descriptions[6].offset = 0; + attribute_descriptions[7].binding = 1; + attribute_descriptions[7].location = 7; + attribute_descriptions[7].format = VK_FORMAT_R16G16B16A16_SFLOAT; + attribute_descriptions[7].offset = sizeof(int16_t) * 4; + + return vertex_description; +} // getDefaultVertexDescription + } diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp index 20431619212..3dfccca7fde 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp @@ -41,6 +41,9 @@ class GEVulkanDynamicSPMBuffer; class GEVulkanSkyBoxRenderer; class GEVulkanTextureDescriptor; +typedef std::pair, + std::vector > VertexDescription; + struct ObjectData { float m_translation_x; @@ -82,7 +85,9 @@ struct PipelineSettings bool m_depth_write; char m_drawing_priority; std::function m_push_constants_func; - VkPipelineLayout m_fs_quad_pl; + VkPipelineLayout m_custom_pl; + VkCompareOp m_depth_op; + VertexDescription m_vertex_description; bool isTransparent() const { return m_alphablend || m_additive; } }; @@ -273,6 +278,8 @@ class GEVulkanDrawCall } // ------------------------------------------------------------------------ bool doDepthOnlyRenderingFirst(); + // ------------------------------------------------------------------------ + VertexDescription getDefaultVertexDescription() const; public: // ------------------------------------------------------------------------ GEVulkanDrawCall(); From acb90832dd4ff63908b2d8cfd49082fb4223a3f4 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 28 Apr 2025 22:22:34 +0200 Subject: [PATCH 682/830] Greatly improve the layout of multi-row ribbons The old formula assigned way too much importance on area, the new one limits it to little more than a tiebreak factor, and better weighs the number of displayed icons and the resulting icon sizes. Unfortunately, the overall behavior is still complex, so changing slightly the resolution doesn't always produce the expected result. Nonetheless, the results are much better across the board. - Move the score computations inside the function that used to compute icon-button properties. - Consider not only having icons at full height, but also icons at a reduced height. This sometimes allow to display all needed elements without having to use another row and even smaller icons. This is especially important for ribbons with a small number of icons, such as the game mode ribbon. - Take into account the readability margin between columns when computing how many elements can be shown - Don't pretend that more icons can't fit within a row if icons are below the XML target icon width ; there is already a penalty for layouts with icons lacking height - If the ribbon has a label, don't count the label area as part of the total area to cover with icons - Introduce a penalty for not showing the target number of items, to greatly reduce near-misses where the ribbon is scrollable because of a tiny number of elements. - Transmit the computed target size to the individual icon-buttons, so that margins between buttons can be preserved. - Use a const value to define the side-margin target - Don't penalize icons that are above the target size defined in XML - Minor adjustments to code layout and removal of a few useless lines --- .../widgets/dynamic_ribbon_widget.cpp | 194 +++++++++++------- .../widgets/dynamic_ribbon_widget.hpp | 9 + src/guiengine/widgets/icon_button_widget.cpp | 14 +- src/guiengine/widgets/icon_button_widget.hpp | 9 + 4 files changed, 146 insertions(+), 80 deletions(-) diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.cpp b/src/guiengine/widgets/dynamic_ribbon_widget.cpp index b7af7ead872..f6d4952bbeb 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.cpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.cpp @@ -36,6 +36,8 @@ using namespace GUIEngine; using namespace irr::core; using namespace irr::gui; +const float READABILITY_FACTOR = 1.15f; + DynamicRibbonWidget::DynamicRibbonWidget(const bool combo, const bool multi_row) : Widget(WTYPE_DYNAMIC_RIBBON) { m_scroll_offset = 0; @@ -79,34 +81,6 @@ DynamicRibbonWidget::~DynamicRibbonWidget() } } -// ----------------------------------------------------------------------------- - -/** Function that estimates the area (in squared pixels) that ribbon icons - * would take given a number of rows (used to estimate the best number of - * rows) - * \param[out] visibleItems number of items that can be displayed in this - * configuration - * \param[out] takenArea how many square pixels are taken by the icons - * \param[out] itemHeight how high each item would be in this configuration - */ -void estimateIconAreaFor(const int rowCount, const int wantedIconWidth, - const int width, const int height, - const float iconAspectRatio, const int maxIcons, - int* visibleItems, int* takenArea, int* itemHeight) -{ - assert(height > 0); - const int row_height = height / rowCount; - - float icon_height = (float)row_height; - float icon_width = row_height * iconAspectRatio; - *itemHeight = int(icon_height); - - const int icons_per_row = std::min(int(width / icon_width), int(width / wantedIconWidth)); - - *visibleItems = std::min(maxIcons, icons_per_row * rowCount); - *takenArea = int(*visibleItems * icon_width * icon_height); -} - void DynamicRibbonWidget::add() { //printf("****DynamicRibbonWidget::add()****\n"); @@ -254,18 +228,102 @@ void DynamicRibbonWidget::updateForResizing() m_left_widget->m_w = left_arrow_location.getWidth(); m_left_widget->m_h = left_arrow_location.getHeight(); m_left_widget->resize(); -} +} // updateForResizing + +// ----------------------------------------------------------------------------- + +/** Computes a score based on multiple icon properties + * (used to estimate the best number of rows) + * There are three parameters we try to optimize for: + * 1 - Showing as many items as possible ; + * 2 - having icons sufficiently big ; + * 3 - Using the available area (least important) + * \param[out] heightRatio the proportion of max height that should be used + */ +float DynamicRibbonWidget::estimateRowScore(const int rowCount, const int width, const int height, + const float iconAspectRatio, const int maxIcons, float* heightRatio) +{ + assert(height > 0); + + const float row_height = (float)height / (float)rowCount; + float test_height_ratio = 1.0f; + float max_score_so_far = -1; + float nextRowRatio = (float)(rowCount)/(float)(rowCount + 1); + + // We test multiple icons heights, as a smaller height might + // be better than full height or an additional row + while (test_height_ratio > nextRowRatio) + { + float icon_height = row_height * test_height_ratio; + float icon_width = icon_height * iconAspectRatio * READABILITY_FACTOR; + + // FIXME - this doesn't account for the space that is lost to scrolling arrows, + // if there are scrolling arrows + const int icons_per_row = int(width / icon_width); + int visible_items = std::min(maxIcons, icons_per_row * rowCount); + // Screens with a huge amount of icons lose readability, + // so items beyond the 30th count less + float visible_items_score = std::min((float)visible_items, 18.0f + 0.4f * visible_items); + + // Used to penalize layouts where the icons are smaller than requested in XML + // The penalty starts as less than quadratic, but becomes quickly more than + // quadratic, to avoid layouts with tiny icons + // Icons above the requested size don't receive a penalty + // TODO: check how this interacts with high-dpi + // TODO: properly account for the margins between rows, which reduce the true available height + float icon_size_ratio = std::min(1.0f, icon_height / (float)m_child_height); + icon_size_ratio = (icon_size_ratio * icon_size_ratio * icon_size_ratio * sqrtf(icon_size_ratio)) * + (2.0f - icon_size_ratio) * (2.0f - icon_size_ratio) * std::min(1.0f, icon_size_ratio * 1.5f); + + // We slightly penalize layouts that don't cover well the available area, + // this mostly acts as a tie-breaker when all items can be displayed + // at the requested icon size + int taken_area = int(visible_items * icon_width * icon_height); + float total_area = (float)(width * height); + float area_factor = std::min(taken_area/total_area, 1.0f); + area_factor = 0.9f + area_factor * 0.1f; + + // We compute the final score by combining the three elements, + // with an extra penalty for missing the target number of icons + // (which helps to avoid layouts that barely miss the target) + float score = visible_items_score * icon_size_ratio * area_factor; + if (visible_items < maxIcons) + score *= 0.7f; + if (visible_items < (maxIcons/2)) + score *= 0.9f; + if (visible_items < (maxIcons/3)) + score *= 0.9f; + if (visible_items < (maxIcons/4)) + score *= 0.9f; + + /*Log::info("DynamicRibbonWidget", "rows = %d; height ratio = %f; visible items = %d; area factor = %f; " + "icon_height = %f; icon size ratio = %f; score = %f", rowCount, visible_items, test_height_ratio, + area_factor, icon_height, icon_size_ratio, score);*/ + + if (score > max_score_so_far) + { + *heightRatio = test_height_ratio; + max_score_so_far = score; + } + + test_height_ratio -= 0.05f; + } // while icon height > greatest icon height possible with another row + + return max_score_so_far; +} // estimateRowScore // ----------------------------------------------------------------------------- void DynamicRibbonWidget::buildInternalStructure() { + const float aspect_ratio = (float)m_child_width / (float)m_child_height; + // FIXME: The height of the tabs that are associated with a ribbon widget + // don't change smoothly, as a result the available areas for the ribbon + // icons may decrease when increasing screen height if (m_multi_row) { // determine row amount - const float aspect_ratio = (float)m_child_width / (float)m_child_height; - // const int count = m_items.size(); - m_row_amount = -1; + m_size_ratio = 1.0f; if (m_h - m_label_height < 0) { @@ -275,57 +333,30 @@ void DynamicRibbonWidget::buildInternalStructure() else { float max_score_so_far = -1; - for (int row_count = 1; row_count < 10; row_count++) - { - int visible_items; - int taken_area; - int item_height; - - int item_count = m_item_count_hint; - - if (item_count < 1) - { - item_count = (int) m_items.size(); - } - - if (item_count < 1) - { - // No idea so make assumptions - item_count = 20; - } - - estimateIconAreaFor(row_count, m_child_width, m_w, m_h - m_label_height, - aspect_ratio, item_count, &visible_items, &taken_area, &item_height); + int item_count = m_item_count_hint; - // FIXME: this system to determine the best number of columns is really complicated! - // the score is computed from taken screen area AND visible item count. - // A number of rows that allows for the screen space to be used a lot will - // get a better score. A number of rows that allows showing very few items - // will be penalized. A configuration that makes items much smaller than - // requested in the XML file will also be penalized. - float ratio = (float)item_height / (float)m_child_height; - - // huge icons not so good either - if (ratio > 1.0f) - { - ratio = 1.0f - ratio/5.0f; - if (ratio < 0.0f) ratio = 0.0f; - } + if (item_count < 1) + item_count = (int) m_items.size(); - float total_area = (float)(m_w * m_h); - const float score = log(2.0f*visible_items) * - std::min(ratio, 1.0f) * std::min(taken_area/total_area, 1.0f); + // No hint or actual number, so make assumptions + if (item_count < 1) + item_count = 20; - //Log::info("DynamicRibbonWidget", "%d rown: %d visible items; area = %f; " - // "size penalty = %f; score = %f", row_count, visible_items, taken_area, - // std::min((float)item_height / (float)m_child_height, 1.0f), score); + for (int row_count = 1; row_count < 10; row_count++) + { + float height_ratio; + // Get the best score for this number of rows + float score = estimateRowScore(row_count, m_w, m_h - m_label_height, + aspect_ratio, item_count, &height_ratio); if (score > max_score_so_far) { m_row_amount = row_count; + m_size_ratio = height_ratio; max_score_so_far = score; } } + //Log::info("DynamicRibbonWidget", "The size ratio of the best score is %f.", m_size_ratio); assert(m_row_amount != -1); } @@ -345,6 +376,7 @@ void DynamicRibbonWidget::buildInternalStructure() } else { + // TODO: use the estimateRowScore logic to potentially downscale slightly the ribbon elements m_row_amount = 1; } @@ -379,9 +411,13 @@ void DynamicRibbonWidget::buildInternalStructure() // ---- determine column amount const float row_height = (float)(m_h - m_label_height)/(float)m_row_amount; float col_width = (float)(row_height * m_child_width / m_child_height); + if (m_multi_row) // not properly defined otherwise + col_width *= m_size_ratio; + + float target_width = col_width; // Give some margin for columns for better readability - col_width *= 1.2f; + col_width *= READABILITY_FACTOR; m_col_amount = std::max((int)floor( m_w / col_width ), 1); @@ -409,8 +445,12 @@ void DynamicRibbonWidget::buildInternalStructure() m_scrolling_enabled = true; m_left_widget->m_element->setVisible(true); m_right_widget->m_element->setVisible(true); + // Reserve space for the scrolling arrows + target_width = target_width * 0.92f; } + float target_height = target_width / aspect_ratio; + // ---- add rows int added_item_count = 0; for (int n=0; nm_properties[PROP_WIDTH] = m_properties[PROP_CHILD_WIDTH]; icon->m_properties[PROP_HEIGHT] = m_properties[PROP_CHILD_HEIGHT]; - icon->m_w = atoi(icon->m_properties[PROP_WIDTH].c_str()); - icon->m_h = atoi(icon->m_properties[PROP_HEIGHT].c_str()); + if (m_multi_row) // not properly defined otherwise + icon->setTargetSize(target_width, target_height); // If we want each icon to have its own label, we must make it non-empty, otherwise // it will assume there is no label and none will be created (FIXME: that's ugly) @@ -473,6 +513,7 @@ void DynamicRibbonWidget::buildInternalStructure() break; } } + m_children.push_back( ribbon ); m_rows.push_back( ribbon ); ribbon->add(); @@ -975,7 +1016,6 @@ void DynamicRibbonWidget::updateItemDisplay() const int row_amount = (int)m_rows.size(); const int item_amount = (int)m_items.size(); - //FIXME: isn't this set by 'buildInternalStructure' already? m_needed_cols = (int)ceil( (float)item_amount / (float)row_amount ); //const int max_scroll = std::max(m_col_amount, m_needed_cols) - 1; diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.hpp b/src/guiengine/widgets/dynamic_ribbon_widget.hpp index 031cd41da8d..c70a68f52ee 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.hpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.hpp @@ -124,6 +124,10 @@ namespace GUIEngine int m_row_amount; int m_col_amount; + /** The ratio between the targeted child height and the maximum height that would fit with + with the current row amount. It is applied to both height and width. */ + float m_size_ratio; + /** The total number of columns given item count and row count (even counting not visible with current scrolling) */ int m_needed_cols; @@ -163,6 +167,11 @@ namespace GUIEngine /** Callback called widget is focused */ EventPropagation focused(const int playerID); + /** Computes a score based on multiple icon properties + (used to estimate the best number of rows) */ + float estimateRowScore(const int rowCount, const int width, const int height, + const float iconAspectRatio, const int maxIcons, float* heightRatio); + /** Removes all previously added contents icons, and re-adds them (calculating the new amount) */ void buildInternalStructure(); diff --git a/src/guiengine/widgets/icon_button_widget.cpp b/src/guiengine/widgets/icon_button_widget.cpp index 4a475bb6901..01436e82fff 100644 --- a/src/guiengine/widgets/icon_button_widget.cpp +++ b/src/guiengine/widgets/icon_button_widget.cpp @@ -52,6 +52,8 @@ IconButtonWidget::IconButtonWidget(ScaleMode scale_mode, const bool tab_stop, m_highlight_texture = NULL; m_custom_aspect_ratio = 1.0f; + m_target_width = -1.0f; + m_target_height = -1.0f; m_texture_w = 0; m_texture_h = 0; @@ -383,14 +385,20 @@ void IconButtonWidget::updateIconRect() useAspectRatio = m_custom_aspect_ratio; } - int suggested_h = m_h; + int suggested_h = (int)m_h; int suggested_w = (int)((useAspectRatio < 0 ? m_w : useAspectRatio * suggested_h)); + if (m_target_width > 0.0f) + { + suggested_h = (int)m_target_height; + suggested_w = (int)m_target_width; + } + if (suggested_w > m_w) { const float needed_scale_factor = (float)m_w / (float)suggested_w; - suggested_w = (int)(suggested_w*needed_scale_factor); - suggested_h = (int)(suggested_h*needed_scale_factor); + suggested_w = (int)(suggested_w * needed_scale_factor); + suggested_h = (int)(suggested_h * needed_scale_factor); } bool left_horizontal = m_properties[PROP_ICON_ALIGN] == "left"; diff --git a/src/guiengine/widgets/icon_button_widget.hpp b/src/guiengine/widgets/icon_button_widget.hpp index 458c9d88e4a..a15c2e4b033 100644 --- a/src/guiengine/widgets/icon_button_widget.hpp +++ b/src/guiengine/widgets/icon_button_widget.hpp @@ -48,6 +48,8 @@ namespace GUIEngine irr::video::ITexture* m_deactivated_texture; irr::video::ITexture* m_highlight_texture; int m_texture_w, m_texture_h; + float m_target_width; + float m_target_height; video::ITexture* getDeactivatedTexture(video::ITexture* texture); void setLabelFont(); @@ -156,6 +158,13 @@ namespace GUIEngine m_highlight_texture = texture; } + // -------------------------------------------------------------------- + void setTargetSize(float width, float height) + { + m_target_width = width; + m_target_height = height; + } + // -------------------------------------------------------------------- /** \brief override from base class */ virtual EventPropagation focused(const int playerID) OVERRIDE; From ca1bdf5f3a156efbae9c14d2d42cd5b0a1861b98 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 28 Apr 2025 22:36:44 +0200 Subject: [PATCH 683/830] Improve the layout of screens using dynamic ribbons This works together with the previous commit to produce as good results as possible. Most notably, the game mode ribbon doesn't require scrolling at any sensible resolution, and the track selection screen stops being always short of showing all standard tracks by a handful, again removing the need for scrolling. People with many addon karts and tracks are also able to see a greater number at once, provided the game screen size is big enough. - Remove the hint on the number of karts in the kart selection screen, in favor of using the real number of karts - Update the hint for game mode selection to target 8 items, as there are currently 8 game modes available - Remove the hint on the number of tracks in the track selection screen, in favor of using the real number of tracks - Other minor tweaks and adjustments to the GUI files, such as picking icon size targets that produce better results --- data/gui/screens/karts.stkgui | 1 + data/gui/screens/race_setup.stkgui | 10 +++++----- data/gui/screens/tracks_and_gp.stkgui | 2 +- src/states_screens/kart_selection.cpp | 6 ------ src/states_screens/race_setup_screen.cpp | 2 +- src/states_screens/tracks_and_gp_screen.cpp | 5 +---- 6 files changed, 9 insertions(+), 17 deletions(-) diff --git a/data/gui/screens/karts.stkgui b/data/gui/screens/karts.stkgui index 2351e815c37..c448ca398a7 100644 --- a/data/gui/screens/karts.stkgui +++ b/data/gui/screens/karts.stkgui @@ -31,6 +31,7 @@ +
diff --git a/data/gui/screens/race_setup.stkgui b/data/gui/screens/race_setup.stkgui index aa3a0096fa2..da1013d9f85 100644 --- a/data/gui/screens/race_setup.stkgui +++ b/data/gui/screens/race_setup.stkgui @@ -6,7 +6,7 @@ - + - + + + - -
diff --git a/data/gui/screens/tracks_and_gp.stkgui b/data/gui/screens/tracks_and_gp.stkgui index 495ebe9803c..40f1f647d16 100644 --- a/data/gui/screens/tracks_and_gp.stkgui +++ b/data/gui/screens/tracks_and_gp.stkgui @@ -38,7 +38,7 @@ + child_width="176" child_height="132" /> diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index cf6025681e5..ca4d9a70721 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -365,12 +365,6 @@ void KartSelectionScreen::beforeAddingWidget() kart_class->addLabel(_(class_str.c_str())); } kart_class->addLabel(_("All")); - - DynamicRibbonWidget* w = getWidget("karts"); - assert( w != NULL ); - - // Avoid too many items shown at the same time - w->setItemCountHint(std::min((int)kart_properties_manager->getNumberOfKarts(), 20)); } // beforeAddingWidget // ---------------------------------------------------------------------------- diff --git a/src/states_screens/race_setup_screen.cpp b/src/states_screens/race_setup_screen.cpp index 27a7f33e9f9..26603ef1a54 100644 --- a/src/states_screens/race_setup_screen.cpp +++ b/src/states_screens/race_setup_screen.cpp @@ -174,7 +174,7 @@ void RaceSetupScreen::init() break; } - w2->setItemCountHint(5); + w2->setItemCountHint(8); { RibbonWidget* w = getWidget("difficulty"); diff --git a/src/states_screens/tracks_and_gp_screen.cpp b/src/states_screens/tracks_and_gp_screen.cpp index 124002d6ace..72861f6de50 100644 --- a/src/states_screens/tracks_and_gp_screen.cpp +++ b/src/states_screens/tracks_and_gp_screen.cpp @@ -195,10 +195,7 @@ void TracksAndGPScreen::beforeAddingWidget() tabs->addTextChild( _(groups[n].c_str()) , groups[n]); } // for n("tracks"); - - // Avoid too many items shown at the same time - tracks_widget->setItemCountHint(std::min((int)track_manager->getNumberOfTracks()+1, 20)); + // Don't give a hint as to how many tracks should be displayed and trust the ribbon logic } // beforeAddingWidget // ----------------------------------------------------------------------------- From 4f1f2d5c6cf854f809ca2dc3dab9f4a9a7cf709f Mon Sep 17 00:00:00 2001 From: fiftydinar <65243233+fiftydinar@users.noreply.github.com> Date: Tue, 29 Apr 2025 15:47:03 +0200 Subject: [PATCH 684/830] Add `StartupWMClass` to the desktop file (#5404) This resolves some edge-cases where desktop icon isn't shown, like in Gnome's dash panel for example. --- data/supertuxkart.desktop | 1 + 1 file changed, 1 insertion(+) diff --git a/data/supertuxkart.desktop b/data/supertuxkart.desktop index 4b99be47cdc..d366bfed02e 100644 --- a/data/supertuxkart.desktop +++ b/data/supertuxkart.desktop @@ -1,6 +1,7 @@ [Desktop Entry] Name=SuperTuxKart Icon=supertuxkart +StartupWMClass=supertuxkart #I18N: Generic name in desktop file entry, summary in AppData and short description in Google Play GenericName[ar]=لعبة سباق سيارات ثلاثية الأبعاد مفتوحة المصدر GenericName[be]=3D-гульня для гонак на картах з адкрытым зыходным кодам From 2d235dd19a33de7ae4702555552796b179ead6be Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 2 May 2025 13:50:18 +0200 Subject: [PATCH 685/830] Add a font to render Hindi --- data/stk_config.xml | 2 +- data/ttf/NotoSansDevanagari-Regular.ttf | Bin 0 -> 221084 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 data/ttf/NotoSansDevanagari-Regular.ttf diff --git a/data/stk_config.xml b/data/stk_config.xml index 2162d36cfef..86fb8124eac 100644 --- a/data/stk_config.xml +++ b/data/stk_config.xml @@ -536,7 +536,7 @@ which leads to crash with STK), but the fonts are to blame, what's the point of not using industry standard nowadays... --> - diff --git a/data/ttf/NotoSansDevanagari-Regular.ttf b/data/ttf/NotoSansDevanagari-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ab3f43341721c903f3eaec8e4c386792577485ad GIT binary patch literal 221084 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 z zD%Ih%1HRIiJNp>(@8rLu}2<xZ|)n2+{79{#~2t>xcQzhK8mV&f6j_uqmw zf5VS6KgZJ|8TBJ$&c`_Yy%gZE1;Ng-fBGw{|>*d)mh>Ctkrtf#H}epo309_?Uj1& z+`SmWaN7cdMogT({KT|Pk8hIbZA(DTj@hy?Njv%7n0d&{ouua}%&gA&P2ja)&q?}r z_|=I61)rYo`OwXwIMz+|kM;fc8ZYWFMC)+QL0l9tIvhpYNNp#aBqArP<7f(;E2)?m z5bRH^K&t2mE%q{@V)>{DN(9&|Ahr&Vj)wX&?qu92WFo${P$5g%=B20ah$s9M7#ec z)YRW|Ckg$}zY9TK-qGP8|94@jKAy{*tXK_OD?rG>M~7YAhn|Deg)=xOVoVg;p=t)V zQ-gvq-wxmTg!TyEemvj)EVfC|4m_}=pT`9^ljpZ^bliQ*vOP#u=6qG1da@a8gM7x%_w*@Ymm<9ilDL z?hvTq`83=sf-kT^I~0tO_MHMN8D|ZDKLFZ+Ad9ruyX(*-?GWRV_Go7v`0<1JBkiV6 zJGO(+59m?SK0?~#P@fIaAGGsz;nZV%|1}DtFlYx)oIHPg_r0VJ8$qU@w7dEKPr(rl zJP$}UZb#n`#K`zhgbyjx~md-<-uUpv{;;JfXePbSMfYWSX+e!bH0>(;Lfk8hToQGJ~HOiz|XEG^5_ zZ=*h(M3``Yl&=9;>dll84+Tf{-7m|SFF;4#ogfhWN`?e~G8rKEGV$)7C)MKkPIL;R zJz$e)F8RG~YGmD-@sB4E+VGVlts6I0KdG%8dF?pf)8|R;xR6v0bVf+BH>-0YFgOH` z%~v5;BRJ!qmSxErK5Ue&jyuS8ofCMT29}|5HlDbzAleR2Awe|1hAORLZz?Nc`=VZgWz~ z>m2@TzIgQ!MhnPsJ(7F~wQu8ZKeDAkj5zGFwThq;FK;9zz zQO0s9XrQZj$uM)@H|x!O7#KeDaRvJXBt5+B`}w3tWhLhUI|TWTp|6sBM_RTz-+^ns zh4?NRuNjW4^7{rr;Y%03W%W1UeF6KCRDhF=0jU5NLbVcDu+C^!3TZPtQE>Q|aWZ@(U#=nix{zeh&$O;tC}&-pu7gh|OT`Y?O?=Lr=2=gxOk z@3rAiS7KEiTqzPK`SRD$J)}R_ag3Tl4b{rsfo|1s44q+MZ~fxhQt{j`LVy1J+H!HC z;a(^8;#kju&q(qME9rz@oF8D;o~rRE((Glwid=`U9p^CqL)VXEq~UqKIt8o ziht+fO3MMlFC(}Q^%mvjTs;JO4EC4%ejHa(-nmcSftp}+KY_yX?gv%T{eQ&5gX*}t zoU1m+pKc{~p7R;LPb9{R&kh)m!&Z+;Bs&w2zx(t<7oD5x2Po^I3(twpewE6QH`1_| z5NlwJ9x{<@cXPe^a{%YR?qwf&%PREj(4~Vve2YqS?({+J5=c0?m(Zg*4)XCps;~#K z577AdRfjH0H`PDs4YrjV7)p6a86UHfK{2&(xX%bvZh^yAGX1|+28xIhDa!~F1Lq8t5 zd;XC1>v$Jl<=HXdiapE@4;<#ZoDFBr$*VwT?eR8o;60ms+CfT&<; zMV>W4Z}=v@CWooKfqwS`0DJ?>pQ6OqtipKV3SbBOeY)A)Qopf)_F>ErV{kVUYlZJ> z;woKi3p)53E$zvw;u>8%5I+n=3j2u%v-V0)Zc(rGZ1^oovF#YrjU2^Y?K$`IRi9Ig z8K$i+DBC)^extwt_w>(*c!D0pRp$qYM&>=k^sNM+H-XKEzBoR{kPPg z=Wfe<9_9aSHRxE{zC!Ajah(L<8rbV+-fkuO`L_hG`ZNJ;@A<}CV7BbDl=ryXhi|^` zNGsAMFv5q3*MQ|VPB@#V4kf#gX2ctYQzW{MKtV%qO*I#Ka=A)OVTZW->Yk7ZM^hTw zr3sC~y;g{?9^~t)Z{q8$Nxe1HUcdLQ=x0Ax=&dwsQWVkzU@(9uO|S;tP5TQc_&4<5CT)3bAoqa&N#mAQVkbSu~YGe!{{W ztM$W&FCUTFibdz}*5bhAxJO5S9BpQQiR7okXBZi=CuO7KwE;)97BWZp?_aVTfN!j{ zr#27^y9!!4cn;Ln!pDeiIuXZ1fXzVGgJ3g&hLU!Ien2~5O$6iVRAJXJVgT)X`Svar z$W>vZeSAN5zMm7hDr|HD-@eGV@1h_EhJH@s+fxDudG8h+okIJ`eE(f6kRRtMeEX|B z7WgxcivaEC+rQ0MNneCx8R+L!zJJuk0wE58_S5+G9b`O!`QexV+E3@(s~yY_YcOa( zgYSQ3zTh`Q`3p^IiCnccI+t(Pk@sTE5Bv&v{ye_@>JH|| zRa>L;`Su1suP3q1h3DVHwWAK^x7cgjs4r7L0!>eBv=B$J`2HH8v|JS^p`Qb_j~zEI zvn+;d`&?xmoZg-c0Htbe8fxUT!^8EHwjRfh2p9kLb5tMyCwf9Z8f`8FqvP&SIN%!A zV(6dTG2S+q7&|c9n!Tpkyr!vI`!Q2)MC4vS9uY(YhZ~W&=Ngn`)j+1HyO+;Gh4EL= zW2@*T4j#f$of}VJ1tF|g!&-FmA%Jz_x4W^y1$)<1S$N2d2)I);`caF0zfiq=VF^_{ z?0)Z*H#|8N5l4N41*c)?;H(JyULD#j@8m|7pBaBT4{^DxQPilJj7h75MOu{`X)aZU z1;X}U0VKi^VHmiCKqqv*+RH1ZfER|%CHz+u7?}zbeDr8yF{E~SH@Z_52o(gJO2#l3 z1DX&5Z172h|Fqd!sqB^^`Q)@aYh#~8h1^`!J3VMNR8#30i*5Nfp?cr)pZG5kvoAS@ zOySX)`Lo%}sK~M3gU`QeOhtR^|MT`GfRU6{{$15ql1|@8^?g;}_uc94bkd!qyK~=@ z%zeNNGt3Ob47c3KeF!q3up*)^9;_?i;wmnJ0;{_mE~~4nvaE{-9^k5rpmI#*|Gui~ zPN&nAWCr}BnPk4{RQ=xj-h1DB@B6;@Hu)EZ7Oqbx(ua%C{`o^jwKcdnAom&#I$_n2 z3A^GhwXf(8T0rX2M%%CInE`15C~j&n0Bwaej&&i)Sj8}GlT01bN3(ik zSxIP>YF8&ds#aue)xMztrCloSG%6fci`g2Jb^fKk{5(JX(PFgl!F+Gnow5vSt*~MZ z`p&1W!0-Cjx1sQ>T-R%xn_0N>61l7^88W9WZY8Nvsh}?D?FZE=RUsHn^7#cE*Q!-& zLhbwJ?@&(y`1(^a-k0*4%{r4*qVmN|frzqHt6itl$OwtJvz*CQVL$CpOXD=ZTyT16 z05a&8gYU;=&(n>x0+NBc14f9MYs;nKY~>Re>7SNHxz(1UiYJolf_%6i-cIW z$b)r$U*k+FXj9uw1aX?NGHlIg0&Ch`Jz2URAJ-GLaCOFH>Q={%GObwHCGCj${0?7D zt@yS#NN7q5xmJy3PL3nDQr}qURH@QY!Yu)>55o$WQl(NFwchW4u)}B8I3#AVTB^_r zvB6W~7P`ObL=~47>lJ>|gqBJ4sG&E&dr+8%R9;eRuv*6c zAEVB|-ZU*_w;r@;KZ1>kb;;pUGCpCz?w_V|_;b{;Q>*0zNm%M^gKcrdlU3luwFHzK zw&}6aGtUH%+;(b3et4+*<6UoIlSxW$Z0j3*t8VZtXWB-VP3^)^%{Jv zAN8xxz=~7#=Q+{=seIy@V?Q2C+xh zwQB~r`#g0NaW`mlr4qKunys8j411^VI&|cy!7e3|2C2RS+M0L7!_NNc>h!{xDI^s^ z=j%WuZ9l8d*aqD}M-4*Us zjmSjYarX*$3irM@IYxQ=3H*8BrvYLJTH{x&0DoOM#f9&`INtkLkvkkb00MfR9O2oa zPZyot14W0B3M?Y)Io6w5p>>gu^04f`!@971{{`6sVezz{%%0Mik@_Zf;_x|Sk5@aM z%g%V6zSD<#cW2YP`bP{?XGaFek!*I#>+qg-w`(|)AGDI^L!8yAaTvmWqoHiJQ&*6+ zbZ)@n{O}`kwfkSsyFyE;3C?Ai+!D+gS_nKyFVyeOlQ= zOlSKq-d!Gbl96cDQ{_T@xpO$19<2-ucC}RVfEd&muo>XgS zbt8wvhCo=|ZD;olVX0!GU3zNx<8>t+8M7oE&;2)4y`0|C(9t}8#R2Nf3+A?;zP%is z2s(Xx%9Vq~>n{sfs3&pJ)ez12=lWz;lTIb9=~KaE+UU!=Q805Y3TANclLKSb5v#52 zaHmfjJo8Nb9RMBH(Ip)|43zNcDk>T1BF39Rk>@h9B=p_}?{TG^wBfy)4%N_1fUU=e zsTaxz`>s9eCT99Zu05-7UvK`*VUn0GRIWTQI_2?4(i8r%p@~hQKy3E38T#nvVRAG- zH)gwhpKdlgJ4sy)1`18U#d~yt6B6g#!slrm5%?!^4!={mOVXZCA+Xq>8W5-5K7TAH2mW5!oZP% zv19#}a|gu&>ihU2^>4A!U^YQ!7L%c|<80XJv*@+ZuddgS4tf#|OL+k^S2tRZjZ_!? zi9MCUZ4u!OwG%Iza-rCS-ds#X`rxV!t>ciPIRe>}MOw#CCRT*0Z2NI7Q?accgJW5U z4`YR^@=)<4u_8W9?5@X$)6?^Z#_xnrU7qa^HGRrygU$+l*6Hbmt?5*MHefdsmUhwL zKsG;0Jx+hbYSvq&5~V+8^7~}H5G@)y#hrsaJnL9Y(UTYh>)4(rp*Xph>E|6opSj`&vJ-{q%i93x3yL$cRYHad$ZfF`vhUWW(xG z!Hu4VY*0@Gw+!uC%xg38P}(G@OVIMC(l(GFnjat^r_u7UvyJ_Og_Og`bSxYB`f5w( zV0GZhFBiC9sZaa|HY6mui3`^z)1uT8+33dJ|zOg~K%YZMr*|L4TNW3xY-xw%n{@^7f4unNL$^q=6vce5$u z&ADVfWz3v1psS)W=i;Dx#0)q~LU>2L6@2{#sH)dpcVYIov8yIps$D{O2hXpC((&eJ zBYED9lYl-6nJ~KIS|dZ61G%`2KE*v6?_9DRk2^*n3s*H|32A!6rVv)=4jydc~ zeaIPFsQ54YKurOYK_0wx^Ol8S)Z0uIa#EjDL30hgO+QS0a`5_$OKFu`oH3gzAQNY`)m9otA?{%3Q=e4nT*l|NjQ>qx&^V?6W{0W3gy{N4CdH1a_n$R4T|caqrMB6Ns8 zlOYI?2vjypfJ|olaHg#tP)PsC$G2L-GH8xerzt`PHx1D=op=j>szFmo6?RhY%!mia z!h1$llh7$WR@|4WIx$S+)W*9sQn%BYPxzH(Rc2`FlY=*`CONfCa#7rw%AZxc1ta^t z;n5IY?db71!q~5ULw;k}CCPMXjY^|aA1sje$V3l_9h%8a*z3R#E%FPQTXLb?WE3)C#duBn+CIFkLFKw8!Ba z?Io=}KJ4vGX!z+x;zrNVA z4vFwb4!rx)sd8pTq}nd={~lOJ^KK{KPwT`q;@v6g1RVx3H))xLp0Q(~AdJGGd}lV3 zAPA=u3dEz&@T{&AJm>3iZp#wJbQ?dsu z-h+irQ9iCA#Hxg;O9w4sWkO#7$IVf5&yERO*gSjWQ{}5ukycaDtT&>rzU;xFdxehS zgeULF#+AlyMVG2WX?8drA*JYTfhFg)MYS@y62q`TjPJ4#mTp{-+MKIIw?N2>BK@60 zRN24}{@%sBkFON6m!EkWCf*Z=BM zf6u^?_Fx1v zuoCdG|3w@WfazMbq#eNLRtPmUlKp~zZ)y@MYCs3ZzHA^do{^`u$-WW9gK(?Zu3X`Y zAhv(e{fo!vAC3D-PRrqmefG>~fw(b@LdtrmcNF zbq(GZEb0WU(D*}UzpQh4;R`u~bA!H%&#x&?e4KAPc$=Gph86tU;zjXQ%YACgE_%5y=JG{Y?o+4t z7YJjgPAk(}72Vp-u6cJ5x(DhAk+|5=kxzKzI$aMatwbpm!pSnU`Yq9SDoJ#Ls8V-I zGLY+KqwD%w$QFu#WHOUlMti>6q!K%WDQ0ZJBv$i;zvP;m-${KJE=$gQ+#-G;6|%Y~ z#!L5M1`n!mY=9=OX8!FW6ZeeIo*Y$*fWW`9h|~iCZu;`K#S>E zomFTY`;|2!hyAWL3Vj5hXee}069FG}Vi&E;{Y5e{9ub9PeOo^@bX~@?N|m>>&T21m zRx|mts^Z0AZ-1maC(ik!zG#(e3Rs;oSB#B>UaOM3?Jzf$*b zCa0HAG`OewSETz+y!@Wn^dY0p-R^`#+`*o3cyD}MdVA>vojXKTHN0?Yg$^Q>Bx}U8 za8{FXalNc5K*ts!KDmuLgijur`IaeVR}q+2_q1Hr?b*&=MVR@O8O32Ie#}=m3^JSI z$)OuGDnh0+QG_R?A0i%VtZd>j~5wmcEEKSxI@P%R`nLxj>m z^x6XV3HY$mFvzf5RoYm=N0zioUDp&|J1}#7bcRs;P9&9dy9&CfMyXd@ZSrinS3C5g zUMMnPI)luh(CJix-q7s`Cf1p>r7`S!f6Uz7-9=GKX}3)+BNWOGlhxcwToUY*cc}Gr zrWHi*Avj~oRIQ&xJC@98S7h%|klnC7NLlK44jjwnhS17Ldwos6P!9vwD^>-kWwSdA zdY@9HAXSCYYENc?ur~_eSMf9VL#2WFQ>bGFrSqWG+tWp2X+1r5LJ>#QOk%(U@R7V%MMdxhVa0`Q=+r6REKx4HN%)p%_#kuassFWS<3V_IL><#GgFfq->xt50Vh2zq;LVxjcn z;A=LCPK#kqn>Fr{iJ`jA4A#Zh+Eq&Dq}!Eq3>JN(4y7#%g>?dkZhZ#wpH90m4ZU&+ z37`5EbdSJnIgeN)R?U{L?G<%f)kcrbqr*N7toRmM%Z%{H0!!^l(Mm7Ts|W>c*cgo; z^A}bS=x{o-Zqb1B*h!H0a4T&V(l=GGpLGys(F}Bb7w94(>t2P-BN!Af%m>70*%bi< z7##W{9;hzXR1yb{A~#GBBsf?Tgd6&L&j|&$MPvR6ciQi%#RnF`Waz@|1SZ@+L;a7# z?Q>e9&Wlt&s9d13W&J}%)98=&LV@cqqE5TooHGq+f?Ch8mn@JYg`G>iU^woEtb zGB&3j`ip0%9g;4oOD9Eblu2{9k+w=q2FJMcx?mb;GQj=`oP95&9YS=(iZ(|yZOA%7 z$EJpXLZ%8V5gLY$YHTiJZ8-*pV1K}OAD9WXRKUtT+)@FH`cZmw&Fso1+6%Ma9U%87 znFV6K5?MP$TC;pTkyaQXbYb-K30h)DP}j138>9=WSs{gFgO+78Ubo5(6}8bSnorcr zTqVyf*iw6cjvs<&W^i|ea z(Sn9HmA+D#RroI)M$A$OW%|uRK?29*u&!81H+Ji?c6P&=Xk?2G5FNVbxrmB%ygMDw%Ky;>()>OKlAc6G`9PAso zY(d$j>Y6EMddJOrW1!+oEjnzTvtEn86?;u>QO?7D-bA-SOOBUP!%#)~XFu=jl1aQK zPe5T+mrZuu>w3$pf-|%Z$ebQ?Ms3~fNsw)TF2Eay=y-PQsZ%wqh=f>~)P97XnC;XsOw45Vz)KmT(WX)5~tfP2X z`ltAta>op2P`ZhUQ%#V^7Ugl#G=xAf6Stza>N8HWr4yV;wCfHIxU5-|U8 z_9Fvq1f{;w5DeA=FHwW|WoJ`Aaz@PR-hs^_Yi=QXLpX1q6l=5>r^bBba8{Oz1TOSM zvT_-}*!7C47-EBTl|}E8QX~GwU77Gm%B;^Psb63c8!0#R!~)}0^5R_Xe525IelFLm zFe#26HQDJ*?+kt^&_lpZB=S#b_hoHrU~z4whF(k|%K!x3sIY57Bf%d59hV*fI-(YJ zabQc>*1I*o&_CsY7OCEu)VR+#lJuy9R=xH6R~laFCZkQ61|Xu}w|RFaI-apQXNTXy z6r^7XTamuuigULoW6&5&F$3zX%v+k_M*(|`J|T>dqZ|k<)Nm-2@c|HHmv^4(nJOIt z4U$nHg63yA$7)YVQLsCws-%9yJ!ruF6;#+l?qT z`=s465lXLsX;4aF@@Sf7`3|5d2dBfJTQrm(WN1RBLd+Irp#!C+NP)e$z{Fla9Bp?v zi0jNuCGRFxHSn2yO5a63GrGAwOYUK~* z_HS{OwnUBnxp%QHow3`Lix9X_Vl(3=6 zCG={0H>+v4)0QKJRI(Pfk)Q_T0i(1oDvs-ctxr2RU z&KY}pd+(@IpNn2r7^@a#WLHP0L1uQi3}i&E)n$+k@x}EFSY$)`LyOyD;jygMUdd6f zVuq;8S_rv^YaTyb7AXmZd7N*B)PP>vqc+ex9Ww${L)Qy^rZ=G*HT%F9sXJO(a8T-! ziF}p1jyl}*R5vRi7(vLTG$jj|T_e=Rfq)$ncqZHAO|0bGsHaUjW6~ZBc8Lv9UvU_8 zG69O~EQ|;Gr^8*?z=?yPqSMo?diwkpHUB;)I4u z#^ria&1h<>uFhn^-HVhq*VAAVwjILee-~`P}aDqkv`H0sAGY|tXe1)C+ljkgm;6`IV{uigIi}8y$GznC00|DU1 zXX^Eh27yS{evCgz%Np`Ym$RAZOan?G)~6T6`?P0*R+ajm4Ga)E5hN7}x--_Blmvh9 zz|61RRj-S%XacohA?+yJP2^OtZy}uAoRu1+y=AA#5j9Bod~(3?vFT|hs`bV;2YQ4! zh7ph=ODa@VwK6oBPLGGgm@wehTU;)&RA8-m@WFd%{dj@yeaMIWJnS2w3@of*Cy)1W zY7l$;0naEb)a#;kSDl}t(Vp0o+!0zAt9{guPoR!Pyrr+RcTHag8ANsG&f;B4ui9_$ zQPqqvZyu~48)eeU!m*od!-EPm{3BT$}lHD40|ES7X3S_1YCJ@j512dG~F6j)qB%AcP)<~3-| z22;Y2$fe|xF!jIK=Rc%2*dU`W_BwUl5^=3l(XEaW*^(yE?@yaz*kxco;H0hGkhEu~ za=I?Z$S|3yU6dtLu(|GWbgKu!2uftA`T=wwS~`G#3h3Sj^QL8tKC^%`SDEN5>?mxd zgH{kfpuDM~JF@_wmAuEbO(|d>(VuBGU&#hUA1R=Nw#&Z!c9g2OLI;L7u5N571M>NL5V~A^bf=Tj`p|xq&8UsTCB&;42Em4 z+L#Nm;3PtsyXo_ZuVF7!kC{w5S5RYj$#9YA%+1+D$$&YNv%0fzj5C4SP}4n8dHh~L z0W}B9tC!8D*EV^<^-E^-YT6`={N4jIu7-#~J!G0`*d0%=V14=YY(wB&)H|r)(vNR! z$dl33Npq-`(S>+jyzouWMoS~&QI6ORyt z+E40oTjHCJ=9r&dxj}31d|FRxYHDNOw9aAb?$U?*J+_P;H7KjSY_JgSfZE|xcVgH0(mCkDLfT{f?!5=it5J4HRDzt69c$>QfSvrfH?qdQ1Rl>a`3eMH#5p~L=$ z7O-X*=*2#<;pQPb^82=h3ciu?U^?w2%?ToGsm3a!+e;g3C_+(gxRe#^vv^61ORvjX ztW(7@oKNQQs2A~nps72xvkwsQvVI=xltQMBv1H)YeMD{UXn&sX6S$?ZR~qiN>OSNi z8jXe%T9;Pm)mVv)ePnj~)X@HUPp^N@(X!ni8_#UpLT~qH3xyJF_d6?I>Mzr~0v@RQ zE0ah|O8G?pz)0@w8JfN~*ox$kGb}U78PHtXHnE7o_Oku}$RSc-dTnI=)b{5VvBwj` zp5g4UH6BUW>`|w|FgT|&ZG={d%|N~30^41c#yX^a2i#UxRiwJ_yXMfTxaLEQtH~UK zf&*x^e*@nQGp2^n$c2 z8JYKHjRl)4pttl|9kZAiN)xQRbfC!Z4Za?*i(&86gDO{-VWC7m3LKuSOHCtkV5Wx; zrBF6T3wEcuKg^E|nRgFNPL35f4_Rxbbiw5bMQkd&g7DpmT|r%S*}Amp4dx1_Rz5%8 z*FW9+f$gS+ePJ)@wRd(F4cK=!LMH7o{1nX*^y+&Rc?|fy*hhGKnQ=rvjK8)#4pJ(o z-oXC@yxKI%Y@bR`3dZ>W7A_xG$l|h%_NX||Q1Ogx-m+PoOGn+7gykf=Rs2e+86WH$ z7lL;|x@`&tEv3}cILc^fA^L%Uh>3e!!#<)ew#4t4P^`|GNt|_Ebdkg8bi!^u?CL(RCjc#jclKee+ zQ11xl6TS1H9(`?R9`=Kw0%@RPrXH`9viUqRmQqPcDjzQlGP!!{OQ;evO%<#LCr{N{ z=8}W1ZL`VTwoIL_!(4`vgS70VKS2yEq?SqhLR(9T?8+`Y4YV0ykFWxo$#`gVEhW~% zBS#fPECWg3Wl5v`S`a@rvTe$&(Sg0WvgpV0im4|&RJB)gsjYi5dtVuu>l?}!Gdj1< z7$)?(0`&+P9G^r}n!bddQY;i0^mIFYTsBPTJ6dTe0Hs| zyIV3Km1FbJZzIE=7lw8l%qdI}y{Dpq8V!SJcaXh#)1(~$nK3#m$LO{j$fTlVC!N%# zPdFg58R}bQ82e_T=Bdp(i|M#sA21tq1#Enh&=u9PklPs6>4~1-0t@)~&?-x~ zHbaK3seXW(i8Weg>eO^mRj)L1l`Fu^Agz=dJt$?Se{h&l%EG>4brUG%P;q}G;Tj9Z zVogf9X_&3Zj&0KQl8Fq;wCD)Po_$N^*O|$9sAtBTA_g{RvNh6ObbHH2>U$wy)=82! zv!lDKuUj_UQvy#7Ru`apCrB_uHAE-xjq0^@wWCh=&8z9|87kHmCTsrbRAEnkWV6qo zzLQZ}4M~7^W7hQ8>fTMi!Qn6f`Pf){(vzdEfTl1RUnc!OYx8c0U1NqT+sz^$z+OK<+yqNR~ch;ego@iYf|5;OY+LbIKJU{EV?Dv z+!u#>dbLr-ohyZRxmQlgP%;ef$gOOZgXZ{Kc!{>aC~p99_xd)tEj4RRZo?3-CMmm^ zY$oZo4O-(mSq?K0vA96ZfDs^N3FcK*b0_P=7ua=A&?CNu}|3T)1iUOhHX7( zWHU7%O6E|1)+k->L90s%FUF|-OL3^hfd0p;WFb=bimCnI@I6|%j__gv>d+RR-hWF5&~5cbmOV{)2xMsjMOrXd!bJV>Jeg@ zGC^Y95K>5FPI)-yG~+)Y%w|Gov21n>yQ)>OuwNhu`<#7HrHg*UJk2*VWI5aNE}Kdw zv>J$3vUDbl)s^fcEpJJhEf%T#T0tfnO$uX}(QGkc`2LnR-r;aKRkCai$-2{?suPMtwnt>gY7T717}+*j)F?(Bmz4jx;{vGSEH?NOR`JIbuDBR@K#1wyedPYVj|^gvynl0vDZ z4VZ?A*(b@t3M*ntM~G}eC7@^IazLelil9NLRMJl7bOeXcwM^0-t;iPJ2;raGu&xzl zi(KB*f*Pkbft0>R^Ae5ZeEsQkEgr4v)Uz5xGZ>2P9yH9bcpqRXTcpvgo1Z5jlziX*K0~M$~M&V z*sZV(9K!v|x+vSpIwxSzZiF}hh?TSidRw;VK;+hfd2<-HxDyJk!m9Kl9as+?zW-ya zLIiyF5~MIV7|C+dM|0AOZVs%N(N>g5GuDFHUsse;a=6IqNgyhccC8P%p*9~a570^z z3Cf)zJ2!Fx%~7O3D%dacqZ1Z`tMPJb&st<$ksL2Iv>ed4)ur{PU?nB3ip5PCPK7{L z?DU+#KF5j~q1SO(f$EMLvffELB=&kEcs477ya=;>Fj-f)U5dC>;Z|E?Zs~x`Vv&%t zP+7~zF}=s(@=CEPMmXVUY^RW4V%Lr*Jtn?79wNLJIMUal6kD8fVs?F3rwrbh zRDs-t0pnL_j7D@mbPWxJZ9&k$4T0Xop^nr`8zrKxT5g0M1JIKJdKAzz6VBL!@6^mu zG(9AoY8gN`>(-$Nr3>0m0*BtON!xBN(r#+A zmaa+VwwBpCZKbofv;@V8Kg$dAuM~;UDTt+|6TgGG1g{6b;(9oiEq$BF{N5zkFs3CuP z=jiB8^-As^Na-oYERRUqN*O%`GwLJOJOizZ zBg&qVb-TPgCBt<+zOgBE;^TfUNcDv~-H4|;R2{oop$X{OI!bfJ!1FG98cksvht9T# z`P~)h4!6-zu4%;IXhxb^shan+0*A^h3m|7j{`n#gk}}wb*vq>C@(6r-{5e+stZT}j z5DsM@s2OoBBc!Tg5#!@$N4c4G{W&&FW?J12`>DBoH zM#HQI!ultkxP53yD(Ua&3X_haha3mQ=xOKBPm{yFj;80)8>yalYur0CkJJTXi_X}@ zbPIvraiktl+ecOg)KJ3|z3oXByPXHUUl9Ien{||9;@_Fs+VaL?n`uTUT3+7bY5^Z% z-gr3JTR4r2W(q~oj3-O4AT%V@;uakS{Y`eq^pJVZHarta7PQh?h4M7@%oa?^ztUAZ zvr^j;$wr~?wk7Wv-a>tj>BGuC|9W`77GgQxT%E?czl`1j*K6tLFDR4;ch28&QEu9mRqLE|h@sNkf*~hmGUbbamXCj}p#)uO8aQ5ksZ}jPB@7eL`>yq>S!

YjBfPl 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 Date: Fri, 2 May 2025 13:51:28 +0200 Subject: [PATCH 686/830] Update translations --- data/po/ar.po | 2105 ++++++++------ data/po/be.po | 2061 ++++++++------ data/po/bg.po | 2063 ++++++++------ data/po/ca.po | 2061 ++++++++------ data/po/cs.po | 2078 ++++++++------ data/po/cy.po | 6861 ++++++++++++++++++++++++++++++++++++++++++++++ data/po/da.po | 2393 +++++++++------- data/po/de.po | 2067 ++++++++------ data/po/eo.po | 2068 ++++++++------ data/po/es.po | 2064 ++++++++------ data/po/fi.po | 2065 ++++++++------ data/po/fil.po | 2064 ++++++++------ data/po/fr.po | 2117 ++++++++------ data/po/gl.po | 2077 ++++++++------ data/po/he.po | 2212 ++++++++------- data/po/hi.po | 6849 +++++++++++++++++++++++++++++++++++++++++++++ data/po/hu.po | 2071 ++++++++------ data/po/is.po | 2101 ++++++++------ data/po/ka.po | 6845 +++++++++++++++++++++++++++++++++++++++++++++ data/po/la.po | 2082 ++++++++------ data/po/lt.po | 2067 ++++++++------ data/po/ml.po | 2139 +++++++++------ data/po/nl.po | 2119 ++++++++------ data/po/nn.po | 2076 ++++++++------ data/po/pl.po | 2068 ++++++++------ data/po/pt.po | 2076 ++++++++------ data/po/pt_BR.po | 2064 ++++++++------ data/po/ro.po | 2955 +++++++++++--------- data/po/ru.po | 2063 ++++++++------ data/po/rue.po | 2071 ++++++++------ data/po/sl.po | 2065 ++++++++------ data/po/sr.po | 2062 ++++++++------ data/po/sv.po | 2063 ++++++++------ data/po/tr.po | 2116 ++++++++------ data/po/vi.po | 2137 +++++++++------ data/po/zh_CN.po | 2092 ++++++++------ data/po/zh_TW.po | 2062 ++++++++------ 37 files changed, 63016 insertions(+), 29583 deletions(-) create mode 100644 data/po/cy.po create mode 100644 data/po/hi.po create mode 100644 data/po/ka.po diff --git a/data/po/ar.po b/data/po/ar.po index 6e5320881fe..2287b8d06a0 100644 --- a/data/po/ar.po +++ b/data/po/ar.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the supertuxkart package. # # Translators: -# Ahmed Mohammed, 2024 +# Ahmed Mohammed, 2024-2025 # A.Karim S., 2018 # Benamara Mohamed , 2015 # FIRST AUTHOR , 2011 @@ -21,9 +21,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Ahmed Mohammed, 2024\n" +"Last-Translator: Ahmed Mohammed, 2024-2025\n" "Language-Team: Arabic (http://app.transifex.com/supertuxkart/supertuxkart/language/ar/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -41,7 +41,7 @@ msgstr "خطأ في استخراج بيانات اللعبة" #. I18N: In Android UI, po_extract_error_msg msgid "Check remaining device space or reinstall SuperTuxKart." -msgstr "تحقق من المساحة المتبقية على الجهاز أو أعد تثبيت \"عربة البطريق الممتاز\"." +msgstr "تحقق من المساحة المتبقية على الجهاز أو أعد تثبيت سوبرتكس‌كارت." #. I18N: In Android UI, po_quit #. I18N: ./data/gui/screens/main_menu.stkgui @@ -180,7 +180,7 @@ msgstr "عند نهاية العالم" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "ارجع" @@ -202,7 +202,7 @@ msgstr "اختر ما يناسبك من أنواع التحكّم" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "مقياس التسارع" @@ -216,13 +216,13 @@ msgstr "مقياس التسارع" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "المِدوار" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "المِقود" @@ -253,35 +253,37 @@ msgstr "إعدادات جهاز اللمس" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "عامّ" @@ -349,30 +351,33 @@ msgstr "استعِد الأوضاع الافتراضية" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "ألغِ" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "نعم" @@ -550,9 +555,9 @@ msgstr "انضمّ" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -613,7 +618,7 @@ msgstr "الهدف" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "التقدّم" @@ -648,7 +653,7 @@ msgstr "أرسِل" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "عُد إلى السباق" @@ -665,7 +670,7 @@ msgstr "عُد إلى الرِواق" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "أعد السّباق" @@ -729,12 +734,12 @@ msgstr "املأ اسم المستخدم وعنوان البريد الإلكت #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "اسم المستخدم" @@ -775,7 +780,7 @@ msgstr "صعوبة" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "مبتدئ" @@ -787,7 +792,7 @@ msgstr "مبتدئ" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "متوسّط" @@ -799,7 +804,7 @@ msgstr "متوسّط" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "متمرّس" @@ -811,7 +816,7 @@ msgstr "متمرّس" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "سوبرتكس‌" @@ -819,8 +824,8 @@ msgstr "سوبرتكس‌" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "وضع اللعب" @@ -831,8 +836,8 @@ msgstr "وضع اللعب" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "سباق عاديّ" @@ -845,7 +850,7 @@ msgstr "سباق عاديّ" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "ضدّ الوقت" @@ -853,7 +858,8 @@ msgstr "ضدّ الوقت" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "معركة" @@ -862,24 +868,24 @@ msgstr "معركة" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "كرة قدم" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "كلمة المرور" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "احفظ هذا السيرفر" @@ -890,7 +896,7 @@ msgstr "أضف لاعبًا" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "الاسم" @@ -984,6 +990,50 @@ msgstr "أسند إلى مفتاح ESC" msgid "Assign nothing" msgstr "أسند لا شيء" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "إعدادات الفيديو الموصى بها" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "الأداء" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "جودة الرّسوم" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "ابدأ الاختبار" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -998,11 +1048,11 @@ msgstr "أعدّ سباقًا" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "تابع" @@ -1043,10 +1093,15 @@ msgstr "الحلبات" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "المُثَّبتة" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "عدِّل الحلبات المفضَّلة" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1056,20 +1111,20 @@ msgstr "المُثَّبتة" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "قياسيّ" @@ -1080,12 +1135,12 @@ msgstr "قياسيّ" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "الإضافات" @@ -1099,27 +1154,28 @@ msgstr "الإضافات" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "الكلّ" @@ -1158,9 +1214,9 @@ msgstr "انقل لأسفل" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "أضف" @@ -1197,7 +1253,7 @@ msgstr "اختيار شبح الإعادة" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "قنّاص البيض" @@ -1244,10 +1300,10 @@ msgstr "اعكس" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "الزّمن الأقصى (دقيقة)" @@ -1279,9 +1335,9 @@ msgstr "انسخ" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1292,80 +1348,80 @@ msgstr "أعد التّسمية" msgid "Save Grand Prix" msgstr "احفظ سباق الجائزة الكبرى" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "مساعدة سوبرتكس‌كارت" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "أوضاع اللعب" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "نقاط القوة" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "موز" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1373,56 +1429,57 @@ msgstr "موز" msgid "Story Mode" msgstr "وضع القصّة" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "انواع العربات" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "متعدّدة اللاعبين" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "بدء الدورة التعليمية" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "اجمع علب الهدايا الزرقاء، وسوف تعطيك نقاط قوة." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "تجنّب الموز!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1430,14 +1487,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "يتيح لك جمع النيترو الحصول على تعزيزات السرعة متى شئت بالضغط على المفتاح أو الزر المناسب. يمكنك رؤية مستواك الحالي من النيترو في المقياس أسفل يمين شاشة السباق." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "إن رأيت زرًّا بقفل كهذا، سيكون عليك إكمال تحدّي لإزالة قفله." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1446,34 +1503,34 @@ msgid "" "carefully before!" msgstr "يمكنك الانزلاق بالضغط على مفتاح أو زر خاص. تساعد الانزلاقات القصيرة المتتالية على الدوران الحاد؛ بينما تعزز الانزلاقات المتوسطة سرعتك، تزداد سرعة الانزلاقات الطويلة. لا يمكنك التوقف عن الدوران أثناء الانزلاق، لذا قم بتوجيه العربة الخاصة بك بعناية قبل ذلك!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "يمكنك الحصول على تعزيز بدء التشغيل بالضغط على زر التسريع في \"تعيين!\"، قبل بدء السباق." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* روابط المفاتيح الحالية يمكن رؤيتها/تغييرها في قائمة الخيارات" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" -msgstr "تدعم \"عربة البطريق الممتاز\" عدة أوضاع للعبة:" +msgstr "تدعم سوبرتكس‌كارت عدة أوضاع للعبة:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "السباق العادي: جميع الضربات مسموحة، لذا اجمع نقاط القوة واستخدمها بذكاء!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "ضدّ الوقت: لا يحتوي على نقاط قوة، فقط مهاراتك في القيادة مهمة!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1481,7 +1538,7 @@ msgid "" " leader will get you eliminated too!" msgstr "اتبع المتزعّم: اسعَ إلى المرتبة الثّانية، فالعربة الأخيرة ستُحرم كلّما وصل العدّاد إلى الصفر. احترس: أن تكون أمام القائد يُبعدك أيضًا!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1491,30 +1548,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "هناك 3 أنواع من أوضاع المعركة: في معركة الضربات الـ3، تحتاج إلى ضرب الآخرين بالأسلحة حتى يفقدوا حياتهم كلها. في مشاجرة عامة، اللاعب الذي يضرب الآخرين أكثر من غيره سيفوز بضربة معينة أو حد زمني معين. في أمسك العَلَم، يحتاج فريقك إلى إحضار علم الفريق الآخر إلى قاعدة العلم الخاصة بك، طالما لم يتم التقاط علمك من قبل الفريق الآخر." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "كرة القدم: استخدم عربتك لتدفع الكرة في المرمى." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "قنّاص البيض: استكشف المسارات للعثور على كلّ البيضات المخفيّة." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "شبح الإعادة: تسابق ضد شبح الإعادة في ضدّ الوقت أو وضع مطاردة البيض، وسجل بنفسك!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "لفّة تجريبية: أكمل أكبر عدد ممكن من اللفّات في فترة زمنية المحددة." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1523,93 +1580,93 @@ msgid "" "wins the cup." msgstr "* يمكن أيضًا لعب العديد من أوضاع اللعبة هذه بأسلوب الجائزة الكبرى: بدلاً من لعب سباق واحد، يمكنك لعب عدة سباقات متتالية. كلما حصلت على ترتيب أفضل، حصلت على نقاط أكثر. في النهاية، يفوز اللاعب الذي يحصل على أكبر عدد من النقاط بالكأس." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "لمساعدتك على الفوز، ثمّة بعض التّحسينات التي يمكنك التقاطها:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "علكة - احمِ نفسك بدرع، أو استخدمها وأنت تطالع الخلف لترك بركة ورديّة لزجة خلفك." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "السَحَّاب - سوف يمنحك سرعة قوية. لكن احذر من فقدان السيطرة على العربة الخاصة بك!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "الكعكة - يتم إلقاؤها على أقرب منافس، والأفضل في المسافات القصيرة والطويلة. كما أنه يؤثر على عربات أخرى قريبة من الانفجار." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "شفّاط - ارمه مباشرةً لسحب خصم للوراء، أو ارمه وأنت تطالع الخلف لإفقاد شخص بصره." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "كرة البولينج - تذهب مباشرة حتى تضرب، يمكنها أن ترتد عن طريق الجدران. إذا كنت تنظر إلى الوراء، فسيتم قلبه للخلف." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "مظلّة - تبطئ كلّ العربات في مرتبة أعلى." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "المُقايض - تتحول علب الهدايا إلى موز وعلب نيترو إلى علكة، والعكس صحيح لفترة قصيرة." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "كرة مضرب - تنطّ حتّى المتزعّم، وقد تسحق وتبطئ العربات في طريقها." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "المِنشّة - سوف تسحق العربات بالقرب منك، مما يؤدي إلى إبطائها. يمكن استخدامها أيضًا لإزالة المظلات والقنابل." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "الارتطام بموزة يمكن أن يؤدي إلى تعلق أحد الأشياء التالية بالعربة:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "المرساة - تبطئ العربة فجأة." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "المظلة - تبطئ العربة بشكل تدريجي أكثر من المرساة. كلما تقدمت بشكل أسرع، زادت قوة إبطائك." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "القنبلة - تنفجر بعد فترة من الوقت، مما يؤدي إلى قذف العربة في الهواء. اصطدم بعربة أخرى لنقل القنبلة إليها." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "نولوك الشرير استولى على جنو! إليك بعض النصائح لمساعدتك:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1618,7 +1675,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "يوضح هذا الرمز الموجود على الخريطة المصغرة التحديات المتاحة التي لم تكملها. في الجزء العلوي الأيمن من الشاشة، يخبرك أيضًا بعدد النقاط التي لديك حاليًا. أكمل أكبر عدد ممكن من التحديات، وسيقبل نولوك السباق ضدك. انتصر لتحرير جنو!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1626,20 +1683,20 @@ msgid "" " the cup and the more points it is worth." msgstr "عندما تكمل التحدي، تحصل على كوب. كل كوب يستحق عدة نقاط. كلما زادت الصعوبة التي أكملت فيها التحدي، كان الكوب أفضل و زادت النقاط التي تستحقها." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "عندما تحصل على عدد النقاط المشار إليه أسفل هذا الرمز، ستحصل على مفاجأة. هناك العديد لتجميعها." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "كل العربات لا تقود بنفس الشكل! ينتمون إلى أصناف متعددة الاختلافات:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1647,7 +1704,7 @@ msgid "" " resistant to explosions." msgstr "الكتلة - توجد ثلاث فئات من العربات، حسب كتلتها: خفيفة ومتوسطة وثقيلة. العربات الثقيلة أقل تأثراً بالمظلات وأكثر مقاومة للانفجارات." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1655,7 +1712,7 @@ msgid "" " especially at low speeds." msgstr "التسارع - مفيد بشكل خاص في البداية أو بعد وقوع حادث أو في المسارات التي بها الكثير من المنحنيات الحادة. كلما كانت العربة أخف زاد تسارعها، خاصة عند السرعات المنخفضة." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1663,14 +1720,14 @@ msgid "" " top speed." msgstr "السرعة القصوى - كلما زادت، زادت سرعة العربة. مفيد بشكل خاص في المسارات ذات الخطوط المستقيمة والمنحنيات اللطيفة. العربات الأثقل لها سرعة قصوى أعلى." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "كفاءة النيترو - كلما كانت أعلى، زادت السرعة التي تحصل عليها من علبة نيترو. سيكون للعربة الأخف وزنًا كفاءة نيترو أعلى." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1678,12 +1735,12 @@ msgid "" "easier it is." msgstr "إذا تَبِعت عربة أخرى عن قرب لبضع ثوانٍ، فستحصل على مكافأة سرعة الانزلاق عند تجاوزها. كلما كانت عربتك أخف وزنًا، كان ذلك أسهل." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" -msgstr "يمكن تشغيل \"عربة البطريق الممتاز\" في وضع متعدّد اللاعبين عبر الإنترنت...:" +msgstr "يمكن تشغيل سوبرتكس‌كارت في وضع متعدّد اللاعبين عبر الإنترنت...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1693,7 +1750,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "أولاً، حدد رمز \"متصل\" في القائمة الرئيسية. اختر إما شبكة محلية أو شبكة عامة (يتطلب تمكين الإنترنت في الخيارات). بعد ذلك، يمكنك إما إنشاء الخادم الخاص بك بخيارات مخصصة، أو البحث بين قائمة الخوادم الحالية للانضمام. يوصى ببعض منها مع سباقات مرتبة اختياريا." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1703,12 +1760,12 @@ msgid "" "players and the server." msgstr "بمجرد الدخول إلى الخادم، سيبدأ السباق بمجرد أن يقرر مالكه (الذي يرمز إليه بالتاج) ذلك. قد تبدأ الخوادم الرسمية السباقات تلقائيًا فقط عندما يكون هناك عدد كافٍ من اللاعبين. بعد ذلك، يمكنك اختيار عربتك والتصويت للمسار التالي للتسابق فيه. لا يُسمح بالمسار الإضافي إلا إذا كان موجودًا لدى جميع اللاعبين المنضمين والخادم." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... أو على نفس الجهاز:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1718,7 +1775,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "أولاً، ستحتاج إلى عدة أجهزة إدخال. استخدم شاشة إعدادات الإدخال لإعدادهم. تعد لوحات الألعاب أو أجهزة التحكم المتعددة مثالية: على لوحة (لوحات) المفاتيح، سيحتاج كل لاعب إلى مجموعة مختلفة من المفاتيح، ومعظم لوحات المفاتيح غير مناسبة للاعبين المتعددين لأنها لا تدعم ضغطات المفاتيح المتعددة المتزامنة." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1738,7 +1795,7 @@ msgstr "اختيار نتيجة عالية" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "لفّة تجريبية" @@ -1746,9 +1803,9 @@ msgstr "لفّة تجريبية" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "سباق الجائزة الكبرى" @@ -1759,6 +1816,20 @@ msgstr "سباق الجائزة الكبرى" msgid "Choose a Kart" msgstr "اختر عربة" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "نوع العربات" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "عدِّل العربات المفضلة" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1772,11 +1843,11 @@ msgstr "تقسيم الشاشة متعددة اللاعبين" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "عبر الشبكة" @@ -1793,7 +1864,7 @@ msgstr "الدّرس التّعليميّ" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "نتائج عالية" @@ -1801,7 +1872,7 @@ msgstr "نتائج عالية" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "الإنجازات" @@ -1855,30 +1926,30 @@ msgstr "اعثر على خادوم" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "أنشئ خادومًا" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "الرّدهة" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "التكوين" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "ابدأ السباق" @@ -1904,9 +1975,9 @@ msgstr "أدخل عنوان الخادم" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "ملفّك الشّخصيّ" @@ -1924,7 +1995,7 @@ msgstr "تصنيفات اللاعبين" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "الأصدقاء" @@ -1949,7 +2020,7 @@ msgstr "لعب سريع" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "إعدادات الحساب" @@ -1999,8 +2070,8 @@ msgid "Online Username" msgstr "اسم المستخدم الشّبكيّ" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "اعادة ضبط كلمة المرور" @@ -2013,7 +2084,7 @@ msgid "" msgstr "يمكنك اللعب دون إنشاء حساب شبكيّ من خلال تحديد حساب بلا اتّصال. لكنك لن تتمكن من الاتّصال بالأصدقاء، أو التصويت على الإضافات، أو إلخ. من فضلك طالع بيان الخصوصية الخاص بنا على https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "حدّد خادومًا" @@ -2031,339 +2102,409 @@ msgstr "استخدم اتصال IPv6" msgid "User search" msgstr "بحث المستخدم" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "خيارات سوبرتكس‌كارت" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +msgid "Display" +msgstr "العرض" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "الرّسوم" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "الصّوت" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "الواجهة" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "اللاعبون" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "التّحكّمات" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "اللغة" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "الموسيقى" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "ممكّن" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "المستوى" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "المؤثّرات الصّوتيّة" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "احذف الضّبط" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "تعطيل التكوين" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "ارجع إلى قائمة الأجهزة" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "إعادة تسمية التكوين" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "تمكين فرض الملاحظات (إذا كان مدعومًا)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "الميز" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "ملء الشّاشة" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "تذكّر مكان النّافذة" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "طبّق الميز الجديد" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "تخطيط تقسيم الشاشة متعددة اللاعبين" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "خيارات الشبكة" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "أظهر شاشة الولوج دائمًا" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "اتّصل بالشّابكة" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "تفعيل الدردشة عبر الشبكة" +msgid "Enable chatting in online lobbies" +msgstr "تمكين الدردشة في الردهات عبر الشبكة" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "تمكين الدردشة في الألعاب عبر الشبكة" +msgid "Enable chatting in online matches" +msgstr "تمكين الدردشة في المباريات عبر الشبكة" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "خيارات متنوعة" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "مكّن المعوّقات لكلّ لاعب" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "قم بإزالة أصول اللعبة الكاملة" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "اضغط enter أو انقر مزدوجًا على جهاز لضبطه" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "أضف جهازًا" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "سيُستنتج أي ضبط يُستخدم من مفتاح 'التّحديد' المضغوط للانضمام إلى اللعبة." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "المظهر" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "الخريطة المصغرة" +msgid "Skin variant" +msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "تخطيط تقسيم الشاشة متعددة اللاعبين" +msgid "Minimap" +msgstr "الخريطة المصغرة" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "حجم الخط" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "مُصوِّرة" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "مخصَّص..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "اعرض إطار/ثا" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "عرض نقاط القوة في العربات الأخرى" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "قم بتمكين مؤقت وضع القصة" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "قم بتمكين عداد السرعة" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "دِقَّة العارض" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "مستوى المؤثّرات الرّسوميّة" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "مستوى مؤثّرات التمويه" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "الحد الأقصى من الإطارات في الثانية" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "إعدادات مخصّصة..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "الميز" +msgid "Performance tests" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "ملء الشّاشة" +msgid "Performance test of the current settings" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "تذكّر مكان النّافذة" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "تذكّر كلمة المرور" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "طبّق الميز الجديد" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "احذف" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "لون العربة" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2390,15 +2531,15 @@ msgstr "الفريق الازرق" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "عدد اللفّات" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "عدد عربات الذّكاء الإصطناعيّ" @@ -2413,33 +2554,17 @@ msgstr "عدد عربات الكومبيوتر للفريق الأزرق" msgid "Random Grand Prix" msgstr "سباق جائزة كبرى عشوائيّ" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "لِج" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "تذكّر كلمة المرور" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "احذف" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "لون العربة" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "يمكن تغيير سطح واجهة المستخدم في خيارات واجهة المستخدم." @@ -2558,238 +2683,306 @@ msgid "" msgstr "لا تقف في طريق زميل في الفريق يحمل الكرة، على الرغم من أنه يمكنك محاولة ضرب الخصوم في محاولة لمنعهم من التسجيل." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "اديامي" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "اماندا" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "غوديت" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "إميول" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "غافروتش" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "جنو" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "هكسلي" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "كيكي" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "كونكي" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "نولوك" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "بيدجن" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "بافي" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "فلفل" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "سارا" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "سوزان" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "تكس" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "ويلبر" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "كزو" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "هاوية ما قبل الطوفان" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "إشارة من الفضائيين " #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "متاهة الكولوسيوم القديمة" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "مدينة كانديلا" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "جزيرة النّزال" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "الغابة السوداء" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "الكهف س" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "معبد الكاكّاو" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "معبر كورنفيلد" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "حصن الصّهارة" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "جزيرة غران باراديسو" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "المزرعة" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "سقوط الحفرة" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "ملعب كرة القدم الجليدي" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "ما المشكلة؟ قائدك العظيم جنو مفقود؟" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "آه أجل، هو الآن في قصري وسيُقدّم على العشاء..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "لكنّني مخلوق عادل، لذلك سأعقد صفقة." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "إن أمكنك هزيمتي في السّباق، سأطلق سراح العجوز غريب الأطوار." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "ولكنّك أيّها الغبيّ الصّغير المثير للشّفقة لن تستطيع هزيمتي - أنا ملك العربات!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "حلبة لاس دوناس" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "ملعب لاس دوناس لكرة القدم" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "حول المنارة" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "المنجم القديم" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "الغولف المصغّر" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "الواحة" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "صفّ رياضيات أوليڤر" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "حديقة اليقطين" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "قصر رافنبريدج" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "الرّمال المتحرّكة" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "بركة نيسي" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "المنتجع الشّماليّ" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "قمّة الثّلوج" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "ملعب كرة القدم" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "الملعب" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "مؤسّسة STK" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "المعبد" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "جزيرة البركان" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "إكس‌آر591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "حديقة زِن" @@ -2798,11 +2991,11 @@ msgstr "حديقة زِن" msgid "Completed achievement \"%s\"." msgstr "أكملت الإنجاز \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." -msgstr "فشل الاتصال بخادم إضافات \"عربة البطريق الممتاز\"." +msgstr "فشل الاتصال بخادوم إضافات سوبرتكس‌كارت." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "خطأ في تنزيل الأخبار: '%s'." @@ -2868,7 +3061,7 @@ msgid "New kart '%s' now available" msgstr "العربة الجديدة '%s' متوفّرة الآن" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2900,32 +3093,32 @@ msgid "" "created." msgstr "ملفّ ضبطك كان قديمًا جدًّا، لذلك حُذف وسيُنشأ آخر جديد." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "بدأ تسجيل الفيديو." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "تم حفظ الفيديو خلال \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "تقدم الترميز:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "إطار/ثا: %d/%d/%d - %d كيلومثلّث، اختبار الاتصال: %d ملي ثانية" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "الحافة: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "يحمّل" @@ -2947,19 +3140,18 @@ msgstr "كفاءة النيترو" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (مُعاق)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s جاهز" @@ -3433,21 +3625,21 @@ msgid "Axis %d" msgstr "المحور %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "زرّ لوحة اللعب %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "زرّ الفأرة %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "محور الفأرة %d %s" @@ -3579,14 +3771,14 @@ msgstr "%s مستوى البطارية منخفض." msgid "" "Connect your wiimote to the Bluetooth manager, then click on Ok. Detailed " "instructions at https://supertuxkart.net/Wiimote" -msgstr "قم بتوصيل wiimote الخاص بك بالبلوتوث، ثم انقر على موافق. تجد تعليمات مفصلة على https://supertuxkart.net/Wiimote" +msgstr "وصِّب Wiimote الخاص بك بالبلوتوث، ثم انقر على موافق. تجد تعليمات مفصلة على https://supertuxkart.net/Wiimote" #: src/input/wiimote_manager.cpp:382 msgid "" "Press the buttons 1+2 simultaneously on your wiimote to put it in discovery " "mode, then click on Ok. Detailed instructions at " "https://supertuxkart.net/Wiimote" -msgstr "ضغط على الأزرار 1+2 في وقت واحد على wiimote الخاص بك لوضعها في وضع الاكتشاف ، ثم انقر على موافق.تجد تعليمات مفصلة على https://supertuxkart.net/Wiimote " +msgstr "اضغط على الأزرار 1+2 في وقت واحد على Wiimote الخاص بك لوضعها في وضع الاكتشاف ، ثم انقر على موافق. تجد تعليمات مفصلة على https://supertuxkart.net/Wiimote " #: src/input/wiimote_manager.cpp:405 #, c-format @@ -3623,83 +3815,87 @@ msgstr "يمكنك الحصول على 3 أرواح على الأكثر!" msgid "+1 life." msgstr "+1 روح." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "لقد كنت بطيئًا جدًا!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "لقد ربحت السّباق!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "لقد أنهيت السباق في الترتيب %d!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s خرج من اللعبة." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." " Would you like this feature to be enabled? (To change this setting at a " "later time, go to options, select tab 'General', and edit \"Connect to the " "Internet\")." -msgstr "قد يتصل \"عربة البطريق الممتاز\" بخادم لتنزيل الإضافات وإعلامك بالتحديثات. يرجى قراءة سياسة الخصوصية الخاصة بنا على https://supertuxkart.net/Privacy. هل ترغب في تمكين هذه الميزة؟ (لتغيير هذا الإعداد في وقت لاحق، انتقل إلى الخيارات، وحدد علامة التبويب \"عام\"، ثم قم بتعديل \"الاتصال بالشبكة\")." +msgstr "قد تتصل سوبرتكس‌كارت بخادوم لتنزيل الإضافات وإعلامك بالتحديثات. يرجى قراءة سياسة الخصوصية الخاصة بنا على https://supertuxkart.net/Privacy. أترغب في تمكين هذه الميزة؟ (لتغيير هذا الإعداد في وقت لاحق، انتقل إلى الخيارات، وحدد علامة التبويب \"عام\"، ثم قم بتعديل \"الاتصال بالشبكة\")." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." -msgstr "دقة الشاشة منخفضة جدا لتشغيل اللعبة." +msgstr "دقة الشاشة منخفضة جدا لتشغيل سوبرتكس‌كارت." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "إصدارة مشغّلك قديمة جدًّا. فضلًا ثبّت أحدث مشغّلات المرئيّات." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " "available. SuperTuxKart recommends a driver supporting %s or better. The " "game will likely still run, but in a reduced-graphics mode." -msgstr "يبدو أن برنامج تشغيل الرسوميات الخاص بك قديم جدًا. يرجى التحقق مما إذا كان هناك تحديث متاح. توصي \"عربة البطريق الممتاز\" ببرنامج تشغيل يدعم %s أو أفضل. من المحتمل أن تظل اللعبة قيد التشغيل، ولكن في وضع رسوميات منخفضة." +msgstr "يبدو أن برنامج تشغيل الرسوميات الخاص بك قديم جدًا. يرجى التحقق مما إذا كان هناك تحديث متاح. توصي سوبرتكس‌كارت بتعريف يدعم %s أو أفضل. من المحتمل أن تظل اللعبة قيد التشغيل، ولكن في وضع رسوميات منخفضة." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "انتهت مهلة الاتصال بالخادم." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%sلديه الراية الحمراء!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "تم استعادة الراية الحمراء!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s لديه الراية الزرقاء! " #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "تم استعادة الراية الزرقاء!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%sاخذ الراية الزرقاء!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s أخذ الراية الحمراء!" @@ -3709,7 +3905,7 @@ msgstr "%s أخذ الراية الحمراء!" msgid "Eggs: %d / %d" msgstr "البيض: %d/%d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "المتزعّم" @@ -3717,22 +3913,22 @@ msgstr "المتزعّم" msgid "Final lap!" msgstr "اللفّة الأخيرة!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "اللفّة %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s لِـ %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "أسرع لفة جديدة" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "اتجاهك خطأ!" @@ -3746,7 +3942,7 @@ msgstr "%s سجل هدف!" msgid "Oops, %s made an own goal!" msgstr "آخ،%s سجَّلت هدفًا في مَرماك!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" @@ -3757,187 +3953,187 @@ msgstr[3] "تم إنتاج %i إطارات إحتياطية للكارت" msgstr[4] "تم إنتاج %i إطار إحتياطي للكارت" msgstr[5] "تم إنتاج %i إطار احتياطي للعربة!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "لقد استُبعدت!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "لقد استُبعد '%s'." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "لقد تم إغلاق الخادم." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "لقد تم طردك من الخادم." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "لقد تم طردك: اختبار الاتصال مرتفع جدًا." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "اكتشاف اتصال شبكي سيِّء." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "آلي" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s غير متصل." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "اضغط على اسم اللاعب في القائمة لإدارة اللاعب ومعلومات الترتيب." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "الصعوبة: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "الحد الأقصى لعدد اللاعبين: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "وضع اللعب: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "المهلة" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "حد الأهداف" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "نوع لعبة كرة القدم: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "سَيْر الجائزة الكبرى: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "جميع اللاعبين انضموا إلى الفريق الأحمر أو الأزرق." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "انت الآن مدير الخادم." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "تم رفض الاتصال: الخادم مشغول." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "الاتصال مرفوض: أنت ممنوع من الخادم." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "تم رفض الاتصال: كلمة مرور الخادم غير صحيحة." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "تم رفض الاتصال: بيانات اللعبة غير متوافقة." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "تم رفض الاتصال: الخادم ممتلئ." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "تم رفض الاتصال: اتصال لاعب غير صالح." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "فشل بدء لعبة الشبكة." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "انتهت اللعبة، لا يمكنك الانضمام أو المشاهدة بعد الآن." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "لا يوجد مكان متبق في الساحة - تم تعطيل الانضمام المباشر." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "بقي لاعب واحد فقط، العودة إلى الرواق." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "مالك الخادم ترك اللعبة." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "سوف تشاهد اللعبة القادمة." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s انضم للفريق الأحمر." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%sانضم للفريق الأزرق." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s انضم الى اللعبة." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3945,15 +4141,15 @@ msgid "" msgstr "إضغط <%s> أو <%s> لتغيير اللاعب المستهدف، <%s> أو <%s> لمكان المُصوِرة." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "تم الإبلاغ بنجاح %s." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3984,38 +4180,38 @@ msgstr "ضدّ الوقت (الجائزة الكبرى)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" -msgstr "مجانا للجميع" +msgstr "حُرٌ للجميع" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "استحوِذ على الراية" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s متّصل الآن." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s و %s متّصلين الآن." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s، و %s و %s متّصلين الآن." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4027,12 +4223,12 @@ msgstr[4] "%d صديقًا متّصل الآن." msgstr[5] "%d صديق متّصل الآن." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s الآن على الخادم \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4043,7 +4239,7 @@ msgstr[3] "لديك %d طلبات صداقة جديدة!" msgstr[4] "لديك %d طلب صداقة جديد!" msgstr[5] "لديك %d طلب صداقة جديد!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "لديك طلب صداقة جديد!" @@ -4072,12 +4268,12 @@ msgid "" msgstr "ملفّ النّتائج العليا كان قديمًا جدًّا،\nمُسحت كلّ النّتائج العليا." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "اتبع المتزعّم" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "قتال الثّلاث ضربات" @@ -4090,95 +4286,88 @@ msgstr "ملف الإعادة غير المكتمل لن يتم حفظه." msgid "Replay saved in \"%s\"." msgstr "تم حفظ الإعادة خلال \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "أسبوع واحد" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "أسبوعان" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "شهر واحد" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 أشهر" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 أشهر" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 أشهر" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "سنة واحدة" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "سنتان" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "اسم الإضافة" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "تاريخ التّحديث" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "غير مثبت" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s لِـ %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "فضلًا انتظر بينما تُحدّث الإضافات" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "آسفون، حدث خطأ أثناء الاتّصال بموقع وِبّ الإضافات. تأكّد من اتّصالك بالشّابكة وأن سوبرتكس‌كارت لا يمنعها جدار نار" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "المفضّلة" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "مقفل: حلّ التّحدّيات النّشطة لتحصل على نفاذ لغيرها!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "حلبة عشوائية" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d حلبة غير متوفرة عند اللعب الإنفرادي. " -msgstr[1] "%d حلبة غير متوفرة عند اللعب الإنفرادي." -msgstr[2] "%d حلبتان غير متوفرة عند اللعب الإنفرادي. " -msgstr[3] "%d حلبات غير متوفرة عند اللعب الإنفرادي. " -msgstr[4] "%d حلبة غير متوفرة عند اللعب الإنفرادي. " -msgstr[5] "%d حلبة غير متوفرة عند اللعب الإنفرادي." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "فريق عرب‌آيز للتّرجمة http://www.arabeyes.org (سابقًا)\nصفا الفليج، 2015–2019\nBenamara Mohamed, 2015\nMoaaz Mohamed, 2017\nIbrahim Al-Darra, 2017\nA.Karim S., 2018\nHasan Nahleh, 2019–2022\nmahmoudtark25, 2020\nخليل مراطلة، 2021\nأحمد محمد، 2024\nالمترجمون السابقون (منصّة لنشباد):\nBenjamin Kerensa - Dawid Gan - Hichem Razgallah - Majid Al-Dharrab\nSAKOUM Yassine - STK-team - abdXelrhman - محمد الحرقان" @@ -4399,13 +4588,13 @@ msgstr "انتهت مباريات التقاط الراية" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:230 msgid "Free-for-All matches started" -msgstr "بدأت مباريات مجانا للجميع" +msgstr "بدأت مباريات حُرٌ للجميع" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:232 msgid "Free-for-All matches finished" -msgstr "انتهت مباريات مجانا للجميع" +msgstr "انتهت مباريات حُرٌ للجميع" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4466,7 +4655,7 @@ msgstr "الموز المجموع" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "الإنزلاق" @@ -4569,7 +4758,7 @@ msgstr "انتهت قنّاص البيض" msgid " (official tracks matching the goal)" msgstr "(المسارات الرسمية تطابق الهدف)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4577,91 +4766,95 @@ msgid "" msgstr "ستظهر لوحات الألعاب وأذرع التحكم الجديدة تلقائيًا في القائمة عند توصيلها بهذا الجهاز.\n\nلإضافة إعداد لوحة مفاتيح، يمكنك استخدام الزر أدناه، ومع ذلك يرجى ملاحظة أن معظم لوحات المفاتيح تدعم فقط مقدارًا محدودًا من ضغطات المفاتيح المتزامنة وبالتالي فهي غير مناسبة للعب متعدد اللاعبين. (ومع ذلك، يمكنك توصيل لوحات مفاتيح متعددة بهذا الجهاز. تذكر أن كل شخص لا يزال بحاجة إلى روابط مفاتيح مختلفة في هذه الحالة.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "أضف حاكوم وي" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "أضف ضبط لوحة مفاتيح" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "حدّث" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "الإصدارة : %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "مميّزة" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "الحجم: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "آسفون، فشل تنزيل الإضافة" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "مشاكل في تثبيت الإضافة '%s'." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "حاول مجدّدًا" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "مشاكل في إزالة الإضافة '%s'." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "تم التحميل في الخلفية." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "تحميل في الخلفية" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "التحميل في الخلفية جارٍ." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "كلمة المرور الحاليّة غير صالحة." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "يجب أن يكون طول كلمة المرور بين 8 محارف و30 محرفًا!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "كلمات المرور لا تتطابق!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "يتحقّق من المعلومات" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "تغيّرت كلمة المرور بنجاح." @@ -4686,79 +4879,109 @@ msgstr "درجات الدقة الأصغر من 1024 × 768 أو 1280 × 720 غ #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "مطاردة الطائرات بدون طيار" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "مخصّصة" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "معطّل" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "المهم فقط" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "منخفض جدا" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "منخفض" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "متوسط" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "مرتفع" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "مرتفع جدا" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "فائق" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " "don't have a wifi connection." -msgstr "ستقوم \"عربة البطريق الممتاز\" بتنزيل الأصول الكاملة (بما في ذلك القوام والموسيقى عالية الجودة) للحصول على تجربة لعب أفضل، وهذا سيستخدم بيانات هاتفك المحمول إذا لم يكن لديك اتصال لاسلكي." +msgstr "ستقوم سوبرتكس‌كارت بتنزيل الأصول الكاملة (بما في ذلك القوام والموسيقى عالية الجودة) للحصول على تجربة لعب أفضل، وهذا سيستخدم بيانات هاتفك المحمول إذا لم يكن لديك اتصال لاسلكي." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." -msgstr "ستقوم اللعبة بتنزيل الملفات كاملة (بما في ذلك الشخصيات والمسارات والموسيقى عالية الجودة) للحصول على تجربة لعب أفضل." +msgstr "ستنزل سوبرتكس‌كارت الملفات كاملة (بما في ذلك الشخصيات والمسارات والموسيقى عالية الجودة) للحصول على تجربة لعب أفضل." #: src/states_screens/dialogs/enter_address_dialog.cpp:42 msgid "" @@ -4771,101 +4994,102 @@ msgstr "أدخل عنوان السيرفر اختياريًا متبوعًا ب msgid "Invalid server address: %s." msgstr "عنوان الخادم غير صالح: %s ." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "عكسي" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "الصعوبة" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "اللفّات" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "الوقت" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "العربة" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "المستخدم" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "الإصدار" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "لا" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "المسار" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "أفضل %d نتائج عالية" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "عدد العربات: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "الهدف الزمني: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "اللفّات: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "عكسي: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(فارغ)" @@ -4953,33 +5177,41 @@ msgid "Press any key..." msgstr "اضغط على اي مفتاح..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "تم تعطيل الدردشة، قم بتمكينها في قائمة الخيارات." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "عُد إلى اختبار الأداء" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "العودة للمعركة" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "انشأ لعبة جديدة" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "إعادة المعركة" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "الخروج من المعركة" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "أعدّ سباق جديد" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "اخرج من السباق" @@ -4995,18 +5227,18 @@ msgstr "%s لا يوجد ترتيب حتى الآن." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s هو رقم %d في الترتيب بنتيجة %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "اسم المستخدم و/أو عنوان البريد الإلكترونيّ غير صالح." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " "agree to these terms in order to register an account for STK. If you have " "any questions or comments regarding these terms, one of the members of the " "development team would gladly assist you." -msgstr "يرجى قراءة شروط وأحكام \"عربة البطريق الممتاز\" على '%s'. يجب أن توافق على هذه الشروط من أجل تسجيل حساب في \"ع ب م\". إذا كانت لديك أي أسئلة أو تعليقات بخصوص هذه الشروط، فسيكون من دواعي سرور أحد أعضاء فريق التطوير مساعدتك." +msgstr "يرجى قراءة شروط وأحكام سوبرتكس‌كارت على '%s'. يجب أن توافق على هذه الشروط من أجل تسجيل حساب في سوبرتكس‌كارت. إذا كانت لديك أي أسئلة أو تعليقات بخصوص هذه الشروط، فسيكون من دواعي سرور أحد أعضاء فريق التطوير مساعدتك." #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:60 @@ -5021,7 +5253,7 @@ msgstr "سباق شبح الإعادة" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "لفات: %i" @@ -5034,21 +5266,21 @@ msgstr "النوع: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "الرّتبة المطلوبة: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "الزّمن المطلوب: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "نقاط النّيترو المطلوبة: %i" @@ -5061,54 +5293,54 @@ msgstr "عدد عربات الذّكاء الإصطناعيّ: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "وضع المعركة" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "نوع لعبة كرة القدم" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "موقع الخادم: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "المسار الحالي: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "الرّتبة" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "اللاعب" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "نتائج" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "وقت اللعب" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "حذف من قائمة المحفوظات" @@ -5121,74 +5353,74 @@ msgid "No player available for connecting to server." msgstr "لا يوجد لاعب متاح للاتصال بالخادم." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "اسم المستخدم: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "ألغِ الطّلب" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "اليوم" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "أُرسل طلب صداقة!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "قُبل طلب الصّداقة!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "رُفض طلب الصّداقة!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "أُزيل الصّديق!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "أُلغي طلب الصّداقة!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "يعالج" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "يجلب آخر تصويت" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "يمكنك تكييف التقييم السابق من خلال النقر على النجوم في الأسفل." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "لم تصوّت لهذه الإضافة بعد. حدّد التّصويت المرغوب بنقر النّجوم بالأسفل" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "نجح التّصويت! يمكنك إغلاق النّافذة." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "إجراء التصويت" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "مسار عشوائيّ" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5217,7 +5449,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "حدث خطأ أثناء حفظ سباق الجائزة الكبرى." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "حدّد مسارًا" @@ -5261,12 +5493,12 @@ msgstr "لقد أزلت قفل المسار %0" msgid "You unlocked grand prix %0" msgstr "لقد أزلت قفل سباق الجائزة الكبرى %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "المسار" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5287,19 +5519,19 @@ msgstr "فضلًا أدخل اسم سباق الجائزة الكبرى" msgid "Please select a Grand Prix" msgstr "من فضلك اختر جائزة كبرى" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "عرّفها المستخدم" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "الاسم فارغ." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "هناك سباق جائزة كبرى بنفس الاسم موجود بالفعل." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "الاسم طويل جدًّا." @@ -5308,19 +5540,19 @@ msgstr "الاسم طويل جدًّا." msgid "Better luck next time!" msgstr "حظًا أوفر في المرّة القادمة!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "لقد أكملت التّحدّي!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "فُزتَ بالجائزة الكبرى!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "لقد أكملت سباق الجائزة الكبرى!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "عدد العربات" @@ -5333,110 +5565,125 @@ msgstr "هل أنت متأكد من أنك تريد إزالة إدخال الد msgid "Are you sure you want to remove all of your high scores?" msgstr "هل أنت متأكد أنك تريد إزالة جميع درجاتك العالية؟" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "قم بتوصيل لوحة مفاتيح أو لوحة ألعاب للعب متعدد اللاعبين على الشاشة المنقسمة" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "عربة عشوائيّة" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "مقفل" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "الجميع:\nاضغطوا على زر التحديد \"Select\" للانضمام إلى اللعبة" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "هل ترغب في تشغيل الدرس التعليمي للعبة؟" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "لا يمكنك اللعب على الشّبكة بلا نفاذ إليها. إن أردت اللعب على الشّبكة، اذهب إلى قائمة الخيارات، وحدّد \"الاتصال بالشبكة\"." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "لا يمكنك تنزيل الإضافات بلا نفاذ إلى الشبكة. إذا كنت ترغب في تنزيل الإضافات، انتقل إلى قائمة الخيارات ، وحدّد \"الاتصال بالشبكة\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "لا يمكنك تنزيل الإضافات بلا نفاذ إلى الشبكة. إذا كنت ترغب في تنزيل الإضافات، انتقل إلى قائمة الخيارات، وحدّد \"الاتصال بالشبكة\".\n\nومع ذلك، يمكنك حذف الإضافات التي تم تنزيلها بالفعل." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "وحدة الإضافات معطّلة حاليًّا في شاشة الخيارات" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "فضلًا انتظر بينما تُحمّل الإضافات" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" -msgstr "هل أنت متأكد أنك تريد الخروج من \"عربة البطريق الممتاز\"؟" +msgstr "أمتأكد أنك تريد الخروج من سوبرتكس‌كارت؟" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "إنشاء خادم الشبكة المحلية LAN" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "خادوم %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "رقم. مسار (مسارات) الجائزة الكبرى" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "يجب أن يكون طول الاسم بين 4 محارف و30 محرفًا!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "أحرف غير صحيحة في كلمة المرور!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "جاهز" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "الانضمام المباشر" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "مُتفرج" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "تثبيت الإضافات" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5444,7 +5691,7 @@ msgstr "من فضلك انتظر ريثما تنتهي اللعبة الجاري #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "الرجاء انتظار نهاية اللعبة الحالية، الوقت المتبقي المقدر: %s." @@ -5452,24 +5699,24 @@ msgstr "الرجاء انتظار نهاية اللعبة الحالية، ال #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "يرجى انتظار انتهاء اللعبة الحالية (%s)، التقدُم المُقدر: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "يرجى انتظار انتهاء اللعبة الحالية، التقدُم المُقدر: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "يرجى انتظار انتهاء اللعبة الحالية." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5482,7 +5729,7 @@ msgstr[5] "ستبدأ اللعبة إذا كان هناك أكثر من %d لا #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5495,96 +5742,108 @@ msgstr[3] "تبدأ اللعبة بعد %d ثواني، أو بعد أن يضغ msgstr[4] "تبدأ اللعبة بعد %d ثواني، أو بعد أن يضغط جميع اللاعبين على زر \"جاهز\"." msgstr[5] "تبدأ اللعبة بعد %dثانية، أو بعد أن يضغط جميع اللاعبين على زر \"جاهز\"." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "الاتصال بالخادم %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "إيجاد خادم لعب سريع" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "الوقت المتبقي: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "الأهداف" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "يجلب الإنجازات" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "ملفّ %s الشّخصيّ" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "منذ" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "الحالة" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "يجلب الأصدقاء" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "طلب جديد" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "معلق" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "غير متصل" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "ادخل البريد الإلكتروني الجديد:" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "البريد الإلكتروني يجب أن يكون بين 5 و 254 حرفًا!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "البريد الإلكتروني الجديد غير صحيح!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "تم تغيير البريد الإلكتروني!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "حصل خطأ في محاولة تغيير البريد الإلكتروني: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "الأخبار من مدونة STK" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "التاريخ" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "يجب عليك تسجيل الدخول للعب الشبكات العالمية. انقر فوق اسم المستخدم الخاص بك أعلاه." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "البحث" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "اخرج من اللعبة" @@ -5662,34 +5921,34 @@ msgid "Distance (km)" msgstr "المسافة (كم)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "مجهول" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "لم يتم الكشف عن IPv4، قد لا تتمكن من الانضمام إلى أية خوادم." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "لم يتم اكتشاف IPv6، قد لا تتمكن من الانضمام إلى أية خوادم." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "لا خوادم متاحة." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "يجلب الخواديم" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "السيرفرات المحفوظة" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5697,149 +5956,149 @@ msgstr "إذا اختار غالبية اللاعبين نفس إعدادات ا #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "موقع العنصر العشوائي" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "عدد الأهداف لربحها" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "تسابق بالعكس" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "مغلق: حل التحديات النشطة للوصول إلى المزيد!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "الإجراء" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "مفتاح الرّبط" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "عطّل الجهاز" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "مكّن الجهاز" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "تمكين الإعدادات" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "مفاتيح اللعب" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "مفاتيح القائمة" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "الانعطاف يسارًا" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "الانعطاف يمينًا" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "التّسارع" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "الفرامل / عكسي" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "الإطلاق" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "النّيترو" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "مطالعة الخلف" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "الإنقاذ" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "إلباث اللعبة" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "أعلى" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "الأسفل" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "اليسار" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "اليمين" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "التّحديد" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "ألغِ/ارجع" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* يعني العنصر الأزرق تعارضًا مع ضبط آخر" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* يعني العنصر الأحمر تعارضًا مع الضبط الحاليّ" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5847,17 +6106,27 @@ msgid "" msgstr "تحذير: مفتاح التبديل 'Shift' غير موصى به. عندما تضغط عليه، كل المفاتيح التي تحتوي حروفا تختلف عن حالتها الكبيرة ستتوقف عن العمل." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "أمتأكّد من حذف هذا الضّبط نهائيًّا؟" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "أدخل اسم التكوين الجديد، اتركه فارغًا للعودة إلى القيمة الافتراضية." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "عمودي" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "أفقي" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5865,89 +6134,74 @@ msgstr "في وضع متعددة اللاعبين، يمكن للاعبين اخ #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "قم بتثبيت أصول اللعبة الكاملة" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "هل أنت متأكد من إلغاء تثبيت أصول اللعبة الكاملة؟" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "لوحة المفاتيح %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "أجهزة لمس" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "اضغط على جهاز لتكوينه" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "لغة النّظام" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "أسفل اليسار" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "على جهة اليمين" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "مخفي" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "في الوسط" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "عمودي" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "أفقي" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "صغير جدا" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "صغير" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "متوسط" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "كبير" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "كبير جدًا" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5957,128 +6211,133 @@ msgid "" msgstr "وضع سرعة التشغيل يمكن تمكينه فقط إذا لم يتم إغلاق اللعبة منذ بدء وضع القصة.\n\nيؤدي إغلاق اللعبة قبل اكتمال وضع القصة إلى إبطال المؤقت.\n\nلاستخدام وضع سرعة التشغيل، يرجى استخدام ملف تعريف جديد." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "تزامن عمودي" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "تفرض تزامن Vsync على بطاقة الرسومات توفير إطار جديد\nفقط عندما تكون الشاشة جاهزة لعرضها." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "لن يعمل تزامن Vsync إذا كانت برامج التشغيل لديك لا تدعمها." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "مُؤثِّرات الجسيمات: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "شخصيّات متحرّكة: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "أضواء متحركة: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "تشتت الضوء: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "تنعيم: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "تعتيم المحيط: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "الظّلال: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "الظّلال: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "سُطوع: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "توهُّج (الحدود): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "شعاع الضوء (أشعة مقدسة): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "جودة الصورة المعروضة: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "غشاوة الحركة: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "عمق مجال الرؤية: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "تم تعطيل الوصول إلى الشبكة. هل تريد تمكينه؟" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "عليك إدخال كلمة مرور." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "يخرج من '%s'" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "يلج إلى '%s'" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "لا يمكنك حذف اللاعب الوحيد." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "أتريد حقا حذف اللاعب \"%s\"؟" @@ -6106,7 +6365,7 @@ msgstr "هدف!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "بانتظار الآخرين" @@ -6141,7 +6400,7 @@ msgstr "اتبع المتزعّم!" msgid "Top %i" msgstr "أفضل %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "فشل التّحدّي" @@ -6165,102 +6424,199 @@ msgstr "اضغط على أيقونة المنصة لبدء التحدي" msgid "Press fire to start the challenge" msgstr "اضغط 'إطلاق' لبدء التّحدّي" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "عُد إلى إعدادات الفيديو" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "عُد إلى القائمة الرئيسة" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "الخروج من الخادم" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "أجهض سباق الجائزة الكبرى" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "أعد التّشغيل" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "ارجع إلى اختيار التّحدّي" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "سباق ضد شبح الإعادة الجديد" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "ارجع إلى القائمة" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "أمتأكّد من إجهاض سباق الجائزة الكبرى؟" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "فاز الفريق الأحمر" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "فاز الفريق الأزرق" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "إنّه تعادل" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "يتم الإقصاء بعد: %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "استُبعد" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(هدف خاص)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "المسار %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "تقدّم سباق الجائزة الكبرى:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "النّتائج العليا" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "أفضل وقت للفة: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "بواسطة %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "لقد انجرت التحدي!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "لقد فشلت في التحدي!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "تم الوصول إلى متطلبات سوبر تاكس" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "أضواء حركيّة: مفعّلة" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "أضواء حركيّة: ملغية" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "منع التعرّج: مفعّل" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "منع التعرّج: ملغي" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "كلّ الضّربات مسموحة، لذا التقط الأسلحة واستخدمها بذكاء!" @@ -6301,28 +6657,28 @@ msgstr "اضغط على أيقونة كرة القدم الحمراء أو ال #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "مسار لِـ %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "الحد الأقصى لعدد اللاعبين: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "عدد عربات الكومبيوتر للفريق الأحمر" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "لا يمكنك المشاركة بسباق الجائزة الكبرى، لأنه يحتوي على مسارات مقفلة!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "مقفل!" @@ -6344,10 +6700,12 @@ msgid "%d/%m/%Y" msgstr "%d/%ش/%س" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "أكمل التّحديات لإلغاء قفل الباب الكبير!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6356,41 +6714,48 @@ msgid "" msgstr "تحتاج نقاط أكثر\nللدّخول إلى هذا التّحدّي!\nطالع الخريطة المصغّرة\nلتعرف التّحدّيات المتوفّرة." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "تسارع بـ <%s>، وانعطف بـ <%s> و <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "تسارع من خلال لمس الجزء العلوي من المِقود، وانعطف بتحريكه يسارًا أو يمينًا." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "تسارع عن طريق تحريك المسرع لأعلى، وقم بالانعطاف عن طريق إمالة جهازك." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "تسارع عن طريق تحريك المسرع لأعلى، وقم بالانعطاف عن طريق تدوير جهازك." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "اجمع صناديق الهدايا وأطلق السّلاح بِـ <%s> لضرب هذه الصّناديق بعيدًا!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "جمع علب الهدايا، وإطلاق النار عن طريق الضغط على أيقونة البولينج لتفجير هذه الصناديق!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6398,34 +6763,41 @@ msgid "" msgstr "اضغط <%s> للنظر إلى الخلف.\nأطلق النار من السلاح بواسطة <%s> أثناء الضغط <%s> لإطلاق النار من الخلف!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "اضغط على أيقونة المرآة للنظر خلفك.\nأطلق النار من السلاح خلفك من خلال الضغط على أيقونة المرآة ثم التمرير سريعًا إلى أيقونة البولينج!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "استخدم النّيترو الّذي جمعت بضغط <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "استخدم النيترو الذي جمعته بالضغط على أيقونة النيترو" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "اجمع عبوات النّيترو (سنستخدمها بعد المنعطف)" #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "آخ! أنت في ورطة، اضغط <%s> لتُنقذ" #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "آخ! عندما تكون في ورطة، اضغط على أيقونة الطائر ليتم إنقاذك." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6433,24 +6805,27 @@ msgid "" msgstr "تسارع واضغط على <%s> مفتاح أثناء التحول إلى الانزلاق.\nيمكن أن يساعدك الانزلاق لفترة قصيرة على الانعطاف بشكل أسرع لأخذ المنعطفات الحادة." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "تسارع واضغط على أيقونة الانزلاق أثناء التحول إلى الانزلاق.\nيمكن أن يساعدك الانزلاق لفترة قصيرة على الانعطاف بشكل أسرع لأخذ المنعطفات الحادة." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "لاحظ أنّه إن انزلقت لبضع ثوان ستستقبل سرعة إضافيّة كمكافأة!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "أنت جاهز لتتسابق! حظًّا موفّقًا!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "لعبة سباق سيارات ثلاثية الأبعاد مفتوحة المصدر" @@ -6460,15 +6835,15 @@ msgstr "لعبة سباق سيارات ثلاثية الأبعاد مفتوحة msgid "tux;game;race;" msgstr "بطريق؛لعبة؛سباق؛" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " "game that is more fun than realistic, and provide an enjoyable experience " "for all ages." -msgstr "شغل العربة. جهز النيترو. انطلق! لعبة سوبر تاكس كارت هي لعبة سباق ثلاثيية الأبعاد ومفتوحة المصدر، فيها مجموعة متنوعة من الشخصيات والمسارات وأنماط اللعب. هدفنا ابتكار لعبة ممتعة أكثر من كونها واقعية، وتوفر تجربة ممتعة لجميع الأعمار." +msgstr "شغل العربة. جهز النيترو. انطلق! لعبة سوبرتكس‌كارت هي لعبة سباق ثلاثية الأبعاد ومفتوحة المصدر، وفيها مجموعة متنوعة من الشخصيات والمسارات وأنماط اللعب. هدفنا ابتكار لعبة ممتعة أكثر من كونها واقعية، وتوفر تجربة ممتعة لجميع الأعمار." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6477,7 +6852,7 @@ msgid "" "your opponents." msgstr "لدينا العديد من المسارات بمواضيع مختلفة ليستمتع بها اللاعبون، من القيادة تحت الماء أو الأراضي الزراعية الريفية أو الأدغال أو حتى في الفضاء! ابذل قصارى جهدك وتجنب العربات الأخرى لأنها قد تتفوق عليك، ولا تأكل الموز! انتبه لكرات البولينج والمكابس وعلكة الفقاعات والكعك التي يريميها خصومك." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6486,27 +6861,27 @@ msgid "" "your racing skills!" msgstr "يمكنك لعب سباق واحد ضد عربات أخرى، أو التنافس في واحدة من العديد من سباقات الجائرة الكبرى، أو محاولة الحصول على وقت سريع في وضع التجربة الزمنية، أو اللعب في وضع المعركة ضد الكمبيوتر أو أصدقائك، والمزيد! لتحدي أكبر، انضم عبر الإنترنت وقابل لاعبين من جميع أنحاء العالم وأثبت مهاراتك في السباق!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "لا يوجد إعلانات في هذه اللعبة." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." -msgstr "هذه نسخة غير مستقرة من لعبة سوبر تكس كارت، و تحتوي على أحدث الاضافات. يتم إصدارها بشكل أساسي للاختبار، لجعل اللعبة المستقرة جيدة قدر الإمكان." +msgstr "هذه نسخة غير مستقرة من لعبة سوبرتكس‌كارت، و تحتوي على أحدث الإضافات. تصدر بشكل أساسي للاختبار، لجعل اللعبة المستقرة جيدة قدر الإمكان." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "يمكن تثبيت هذا الإصدار بالتوازي مع الإصدار الثابت على الجهاز." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "إذا كنت بحاجة إلى مزيد من الاستقرار، فكر في استخدام الإصدار الثابت: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" -msgstr "فريق سوبر تكس كارت" +msgstr "فريق سوبرتكس‌كارت" diff --git a/data/po/be.po b/data/po/be.po index 3d30c7fd1e2..8b302a12c23 100644 --- a/data/po/be.po +++ b/data/po/be.po @@ -14,7 +14,7 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" "Last-Translator: Денис Ким , 2019-2024\n" "Language-Team: Belarusian (http://app.transifex.com/supertuxkart/supertuxkart/language/be/)\n" @@ -173,7 +173,7 @@ msgstr "На краі свету" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Назад" @@ -195,7 +195,7 @@ msgstr "Абярыце пераважны тып кіравання" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Акселерометр" @@ -209,13 +209,13 @@ msgstr "Акселерометр" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Гіраскоп" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Стрыно" @@ -246,35 +246,37 @@ msgstr "Налады сэнсарнай прылады" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Асноўнае" @@ -342,30 +344,33 @@ msgstr "Аднавіць прадвызначаныя" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Скасаваць" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Так" @@ -543,9 +548,9 @@ msgstr "Далучыцца" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -606,7 +611,7 @@ msgstr "Мэта" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Прагрэс" @@ -641,7 +646,7 @@ msgstr "Адправіць" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Назад да гонкі" @@ -658,7 +663,7 @@ msgstr "Назад у лобі" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Перазапусціць гонку" @@ -722,12 +727,12 @@ msgstr "Запоўніце імя карыстальніка ды адрас э #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Імя карыстальніка" @@ -768,7 +773,7 @@ msgstr "Складанасць" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Пачатковец" @@ -780,7 +785,7 @@ msgstr "Пачатковец" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Сярэднячок" @@ -792,7 +797,7 @@ msgstr "Сярэднячок" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Эксперт" @@ -804,7 +809,7 @@ msgstr "Эксперт" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "Супер Тукс" @@ -812,8 +817,8 @@ msgstr "Супер Тукс" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Рэжым гульні" @@ -824,8 +829,8 @@ msgstr "Рэжым гульні" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Звычайная гонка" @@ -838,7 +843,7 @@ msgstr "Звычайная гонка" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Гонка на час" @@ -846,7 +851,8 @@ msgstr "Гонка на час" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Бітва" @@ -855,24 +861,24 @@ msgstr "Бітва" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Футбол" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Пароль" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Дадаць гэты сервер у закладкі" @@ -883,7 +889,7 @@ msgstr "Дадаць гульца" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Імя" @@ -977,6 +983,50 @@ msgstr "Прызначыць да кнопкі ESC" msgid "Assign nothing" msgstr "Не прызначаць нічога" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Рэкамендаваныя налады відэа" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Рэкамендаваныя налады будуць сапраўдныя для бягучай раздзяляльнай здольнасці." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Які прыярытэт павінен быць у наладаў?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Прадукцыйнасць" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Баланс прадукцыйнасці і якасці графікі" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Якасць графікі" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Захаванне энергіі" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Ці вам падабаюцца графічныя эфекты, што ствараюць размытасць?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Пачаць тэст" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -991,11 +1041,11 @@ msgstr "Налады гонкі" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Далей" @@ -1036,10 +1086,15 @@ msgstr "Арэны" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Усталявана" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1049,20 +1104,20 @@ msgstr "Усталявана" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Стандартныя" @@ -1073,12 +1128,12 @@ msgstr "Стандартныя" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Дадаткі" @@ -1092,27 +1147,28 @@ msgstr "Дадаткі" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Усе" @@ -1151,9 +1207,9 @@ msgstr "Перамясціць ніжэй" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Дадаць" @@ -1190,7 +1246,7 @@ msgstr "Выбар паўтору з прывідам" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Паляванне на яйкі" @@ -1237,10 +1293,10 @@ msgstr "У адваротным напрамку" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Максімальны час (хв.)" @@ -1272,9 +1328,9 @@ msgstr "Капіраваць" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1285,80 +1341,80 @@ msgstr "Змяніць назву" msgid "Save Grand Prix" msgstr "Захаваць Гран-пры" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Даведка SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Рэжымы гульні" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Бонусы" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Бананы" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1366,56 +1422,57 @@ msgstr "Бананы" msgid "Story Mode" msgstr "Рэжым гісторыі" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Класы картаў" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Сумесная гульня" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Пачаць навучанне" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Збірайце сінія скрыні — яны даюць бонусы." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Абмінайце бананы!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1423,14 +1480,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Збіранне нітра дазваляе вам павялічыць хуткасць у любы пажаданы момант, націснуўшы адпаведную кнопку. Вы можаце бачыць ваш бягучы ўзровень нітра на панэлі ў ніжнім правым куце экрана гонкі." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Калі вы бачыце замок, то гэта азначае, што трэба закончыць спаборніцтва, каб разблакаваць яго." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1439,34 +1496,34 @@ msgid "" "carefully before!" msgstr "Вы можаце слізгаць націскаючы адмысловую клавішу ці кнопку. Паспяховыя кароткія слізганні дапамагаюць рабіць рэзкія павароты; у той час як сярэднія слізганні дададуць хуткасці, а працяглыя — яшчэ больш. Падчас слізгання вы не можаце спаніць паварот, так што выбірайце арыентацыю вашага карта загадзя!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Вы можаце атрымаць стартавае паскарэнне, калі націсніце кнопку газу пасля сігналу 'Увага!' да старту гонкі." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Бягучыя прызначэнні кнопак можна ўбачыць/змяніць у меню параметраў" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart мае некалькі рэжымаў гульні:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Звычайная гонка: усё дазваляецца, так што збірайце зброю і з розумам ужывайце яе!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Гонка на час: няма бонусаў, так што толькі навыкі кіравання маюць значэнне!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1474,7 +1531,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Трымайся за лідарам: будзьце на другім месцы, бо апошні карт будзе дыскваліфікаваны як толькі лічыльнік абнуліцца. Сцеражыцеся абганяць лідара — гэта прывядзе да вашай дыскваліфікацыі!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1484,30 +1541,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Ёсць 3 тыпы рэжымаў бітвы. У \"Бітве трох удараў\" вам неабходна выкарыстоўваць зброю супраць іншых гульцоў, пакуль яны не страцяць усе свае жыцці. У \"Бітве супраць усіх\" той гулец, які стукне іншых больш разоў, пераможа, калі набярэ некаторую колькасць удараў або скончыцца час гульні. У гульні \"Захоп сцяга\" вашай камандзе трэба прынесці сцяг іншай каманды на сваю базу, пры гэтым ваш сцяг павінны быць на вашай базе." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Футбол: з дапамогай свайго карта штурхайце мяч у вароты." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Паляванне на яйкі: даследуйце трасы ў пошуках усіх схаваных яек." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Паўтор з прывідам: Гуляйце супраць паўтораў з прывідам у рэжыме гонкі на час або палявання на яйкі, або запісвайце свой паўтор!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Гонка на кругі: Завяршыце як мага больш кругоў за дадзены прамежак часу." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1516,93 +1573,93 @@ msgid "" "wins the cup." msgstr "* Большасць гэтых рэжымаў гульні можа гуляцца ў стылі Гран-Пры: замест адной гульні, вы гуляеце некалькі запар. Чым лепш ваша месца, тым больш балаў вы атрымліваеце. У канцы Гран-Пры той гулец, што набраў больш балаў, атрымлівае кубак." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Для таго, каб перамагчы, збірайце наступныя бонусы:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Жуйка — абароніць з дапамогай шчыта або, калі глядзець назад, пакіне ліпкую ружовую пляму." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Паскаральнік - дае вам вялікую прыбаўку ў хуткасці. Але будзьце асцярожнымі і не губляйце кантроль над сваім картам!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Піражок - ляціць у бліжэйшага суперніка. Лепш за ўсё ўжываць яго на кароткіх дыстанцыях і доўгіх прамых. Таксама ўплывае на іншыя карты побач з выбухам." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Вантуз — кідаецца проста, каб зачапіцца за суперніка, ці назад, каб закрыць яму агляд." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Шар для боўлінга - рушыць прама, пакуль не стукне, можа адскокваць ад сцен. Калі глядзець назад, ён будзе кінуты ў адваротным напрамку." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Парашут — стрымлівае ўсе карты, што маюць лепшую пазіцыю." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Заменнік - скрынкі з бонусамі ператвараюцца ў бананы, а бутэлькі з нітра - ў жуйкі, і наадварот на кароткі час." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Баскетбольны мяч — скача за лідарам гонкі і можа распляскаць і запаволіць карты на сваім шляху." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Мухабойка — расплюшчвае і запавольвае карты, што знаходзяцца побач. Можа таксама выкарыстоўвацца, каб пазбавіцца ад парашутаў і бомб." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Калі наехаць на банан, то карт можа атрымаць нешта з наступнага:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Якар - нечакана запавольвае карт." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Парашут - запавольвае карт больш паступова, чым якар. Чым хутчэй вы спрабуеце рухацца, тым больш ваш карт запавольваецца." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Бомба - ўзрываецца пасля кароткага прамежку часу і падкідвае карт у паветра. Ударце іншы карт, каб перадаць бомбу іншаму гульцу." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Злы Нолак захапіў Гну! Вось некалькі парадаў, якія могуць вам дапамагчы:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1611,7 +1668,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Гэтая іконка на міні-мапе паказвае даступныя выклікі, якія вы яшчэ не скончылі. У правым верхнім куце экрана вы можаце бачыць, колькі пунктаў вы ўжо маеце. Скончыце як мага больш выклікаў, і Нолак згадзіцца на спаборніцтва з вамі. Будзьце хутчэй за яго, каб вызваліць Гну!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1619,20 +1676,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Калі вы скончыце выклік, вы атрымаеце кубак. Кожны кубак каштуе некалькі пунктаў. Чым вышэйшая складанасць скончанага вамі выкліка, тым лепш кубак і тым больш пунктаў ён каштуе." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Калі вы атрымаеце столькі пунктаў, колькі пазначана ўнізе гэтай іконкі, вы атрымаеце сюрпрыз. Усяго ёсць некалькі сюрпрызаў, якія вы можаце сабраць." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Не ўсе карты аднолькавыя! Яны належаць да некалькіх класаў, што маюць адрозненні:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1640,7 +1697,7 @@ msgid "" " resistant to explosions." msgstr "Вага - ёсць тры класы картаў у залежнасці ад іх вагі: лёгкія, сярэднія і цяжкія. Цяжэйшыя карты больш устойлівыя да выбухаў, і на іх менш уплываюць парашуты." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1648,7 +1705,7 @@ msgid "" " especially at low speeds." msgstr "Паскарэнне - асабліва важнае на старце, пасля сутыкнення або на трасах з вялікай колькасцю вострых паваротаў. Чым лягчэйшы карт, тым хутчэйшым будзе яго паскарэнне, асабліва пры нізкай хуткасці." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1656,14 +1713,14 @@ msgid "" " top speed." msgstr "Максімальная хуткасць - чым яна больш, тым хутчэй карт можа рухацца. Яна асабліва патрэбная на трасах з прамымі і плаўнымі паваротамі. Цяжэйшыя карты маюць большую максімальную хуткасць." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Эфектыўнасць нітра - чым яна большая, тым большую хуткасць вы можаце атрымаць ад аднаго нітра-зарада. Чым лягчэйшы карт, тым большую эфектыўнасць нітра ён мае." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1671,12 +1728,12 @@ msgid "" "easier it is." msgstr "Калі вы блізка прытрымліваецеся іншага карта на працягу некалькіх секунд і спрабуеце яго абагнаць, вы атрымліваеце бонус да хуткасці ад сліпстрыму. Чым лягчэйшы ваш карт, тым лягчэй атрымаць бонус." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "У SuperTuxKart можна гуляць у рэжыме сумеснай гульні ў сеціве..." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1686,7 +1743,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Спачатку націсніце кнопку сеціўнай гульні ў галоўным меню. Абярыце лакальнае злучэнне або глабальнае злучэнне (што патрабуе далучэння да інтэрнэту ў наладах). Затым вы можаце або стварыць свой сервер са спецыяльнымі наладамі, або знайсці які-небудзь сервер у спісе існуючых сервераў і далучыцца да яго. Некаторыя серверы ў спісе з'яўляюцца рэкамендаванымі і, магчыма, праводзяць рэйтынгавыя гонкі." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1696,12 +1753,12 @@ msgid "" "players and the server." msgstr "Гульня на серверы пачнецца, калі яго ўладальнік (адзначаны каронай) вырашыць пачаць яе. Афіцыйныя серверы могуць пачаць гульню аўтаматычна праз пэўны час, калі на серверы дастаткова гульцоў. Затым гульцы абіраюць свой карт і галасуюць за трасу для наступнай гульні. Дадатковыя трасы можна абраць, толькі калі сервер і ўсе прысутныя гульцы маюць яе." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "...або на той жа прыладзе." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1711,7 +1768,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Па-першае, вам спатрэбяцца некалькі прыладаў уводу. Каб наладзіць іх, карыстайцеся адпаведным экранам наладаў. Ідэальна вам патрэбны некалькі геймпадаў або джойсцікаў, бо для гульні на клавіятуры(ах) кожнаму гульцу спатрэбяцца розныя наборы клавішаў. Але большасць клавіятур не падыходзяць для сумеснай гульні, таму што не падтрымліваюць адначасовае націсканне на некалькі клавішаў." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1731,7 +1788,7 @@ msgstr "Выбар лепшага выніку" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Гонка на кругі" @@ -1739,9 +1796,9 @@ msgstr "Гонка на кругі" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Гран-пры" @@ -1752,6 +1809,20 @@ msgstr "Гран-пры" msgid "Choose a Kart" msgstr "Абярыце карт" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Клас картаў:" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1765,11 +1836,11 @@ msgstr "Сумесная гульня з падзеленым экранам" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Сеціўная гульня" @@ -1786,7 +1857,7 @@ msgstr "Навучанне" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Лепшыя вынікі" @@ -1794,7 +1865,7 @@ msgstr "Лепшыя вынікі" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Дасягненні" @@ -1848,30 +1919,30 @@ msgstr "Знайсці сервер" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Стварыць сервер" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Лобі" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Канфігурацыя" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Пачаць гонку" @@ -1897,9 +1968,9 @@ msgstr "Увядзіце адрас сервера" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Ваш профіль" @@ -1917,7 +1988,7 @@ msgstr "Рэйтынг гульцоў" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Сябры" @@ -1942,7 +2013,7 @@ msgstr "Хуткая гульня" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Налады рахунка" @@ -1992,8 +2063,8 @@ msgid "Online Username" msgstr "Сеціўнае імя карыстальніка" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Скінуць пароль" @@ -2006,7 +2077,7 @@ msgid "" msgstr "Вы можаце гуляць без стварэння сеціўнага рахунка, абраўшы пазасеціўны рахунак. Але пры гэтым вы не зможаце злучыцца з сябрамі, галасаваць за дадаткі і інш. Азнаёмцеся з нашымі ўмовамі канфідэнцыйнасці на https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Выбар сервера" @@ -2024,339 +2095,409 @@ msgstr "Выкарыстоўваць злучэнне па IPv6" msgid "User search" msgstr "Пошук карыстальнікаў" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Параметры SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Дысплэй" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Графіка" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Аўдыё" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Інтэрфейс" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Гульцы" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Кіраванне" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Мова" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Музыка" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Уключана" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Гучнасць" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Гукавыя эфекты" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Выдаліць канфігурацыю" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Адключыць канфігурацыю" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Назад да спіса прылад" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Перайменаваць канфігурацыю" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Уключыць зваротны водклік (калі падтрымліваецца)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Раздзяляльная здольнасць" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "На ўвесь экран" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Памятаць месца акна" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Ужыць новую раздзяляльную здольнасць" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Раскладка падзеленага экрана сумеснай гульні" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Налады Інтэрнэту" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Заўсёды паказваць экран уваходу" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Злучэнне з інтэрнэтам" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Уключыць размовы ў сеціўных гульнях" +msgid "Enable chatting in online lobbies" +msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Уключыць ліставанне ў сеткавых гульнях" +msgid "Enable chatting in online matches" +msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Розныя налады" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Асобныя гандыкапы для кожнага гульца" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Выдаліць поўныя рэсурсы гульні" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Націсніце Enter ці двойчы пстрыкніце па прыладзе, каб наладзіць яе." -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Дадаць прыладу" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Тое, якую канфігурацыю выкарыстаць, будзе вызначана паводле таго, якая кнопка 'Абраць' націснута для ўвахода ў гульню." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Выгляд" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Мінімапа" +msgid "Skin variant" +msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Раскладка падзеленага экрана сумеснай гульні" +msgid "Minimap" +msgstr "Мінімапа" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Памер шрыфту" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Камера" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Карыстальніцкая…" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Паказваць FPS" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Паказваць бонусы іншых картаў" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Уключыць таймер для рэжыму гісторыі" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Уключыць таймер для хуткага праходжання гульні" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Разрозненне адмалёўкі" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Узровень графічных эфектаў" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Узровень эфектаў размытасці" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Максімальны FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Асабістыя налады…" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Раздзяляльная здольнасць" +msgid "Performance tests" +msgstr "Тэсты прадукцыйнасці" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "На ўвесь экран" +msgid "Performance test of the current settings" +msgstr "Тэст прадукцыйнасці бягучых наладаў" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Памятаць месца акна" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Памятаць пароль" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Ужыць новую раздзяляльную здольнасць" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Выдаліць" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Колер карта" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2383,15 +2524,15 @@ msgstr "Сіняя каманда" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Колькасць кругоў" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Колькасць ботаў" @@ -2406,33 +2547,17 @@ msgstr "Колькасць ботаў у сіняй камандзе" msgid "Random Grand Prix" msgstr "Выпадковы Гран-пры" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Увайсці" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Памятаць пароль" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Выдаліць" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Колер карта" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Афармленне інтэрфейсу можна памяняць у наладах інтэрфейсу." @@ -2551,238 +2676,306 @@ msgid "" msgstr "Не стойце на шляху таварыша па камандзе, што вядзе мяч. Але трэба спрабаваць атакаваць супернікаў, каб перашкодзіць ім забіць гол." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Адзюма" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Аманда" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Гадэтта" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Вослік" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Гаўрош" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Гну" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Хекслі" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Кікі" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Конкі" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Нолак" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Піджын" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Паффі" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Пеппер" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Сара" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Сюзанна" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Тукс" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Ўілбер" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Сʼю" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Старажытная бездань" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Іншапланетны Сігнал" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Лабірынт старажытнага Калізея" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Горад Кандэла" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Баявы востраў" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Чорны лес" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Сакрэтная пячора" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Храм какавы" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Кукурузнае перакрыжаванне" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Форт магмы" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Востраў Гран Парадыза" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Гасіенда" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Падзенне" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Ледзяное футбольнае поле" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Штосьці не так, маленькі хіпі? Твой вялікі лідар гну знік?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "О так, глядзі, ён цяпер у маім замку і будзе паданы на абед…" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Але я сумленная істота, таму прапаную ўгоду." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Калі ты зможаш перамагчы мяне ў гонцы, я вызвалю гэтага старога дзівака." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "Але ты, гаротны валацуга, ніколі не зможаш адолець мяне — караля картаў!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Арэна Лас-Дунас" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Футбольны стадыён Лас-Дунас" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Вакол маяка" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Старая рудня" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Мінігольф" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Аазіс" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Клас матэматыкі Олівера" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Гарбузовы Парк" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Асабняк Равэнбрыдж" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Зыбучыя пяскі" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Сажалка Нэссі" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Паўночны курорт" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Снежны пік" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Футбольнае поле" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Стадыён" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "Прадпрыемства STK" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Храм" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Вулканічны востраў" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Сад Дзэн" @@ -2791,11 +2984,11 @@ msgstr "Сад Дзэн" msgid "Completed achievement \"%s\"." msgstr "Завершанае дасягненне «%s»." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Не атрымалася злучыцца з северам дадаткаў SuperTuxKart." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Памылка пры атрыманні навін: «%s»." @@ -2861,7 +3054,7 @@ msgid "New kart '%s' now available" msgstr "Даступны новы карт «%s»" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2893,32 +3086,32 @@ msgid "" "created." msgstr "Ваш файл канфігурацыі занадта стары. Ён будзе выдалены і заменены новым." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Пачаўся запіс відэа." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Відэа захавана ў «%s»." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Прагрэс кадавання:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Пінг: %dмс" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Парада: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Запуск" @@ -2940,19 +3133,18 @@ msgstr "Эфектыўнасць нітра" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (з гандыкапам)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s гатовы" @@ -3426,21 +3618,21 @@ msgid "Axis %d" msgstr "Вось %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Кнопка геймпада %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Кнопка мышы %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Вось мышы %d %s" @@ -3614,26 +3806,30 @@ msgstr "Вы можаце мець максімум 3 жыцця!" msgid "+1 life." msgstr "+1 жыццё." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Вы былі занадта павольныя!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Вы перамаглі ў гонцы!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Вы завяршылі гонку на пазіцыі %d!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s пакінуў гульню." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3642,16 +3838,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart можа падлучацца да сервера, каб спампаваць дадаткі і паведамляць вам пра абнаўленні. Калі ласка, прачытайце нашую палітыку прыватнасці тут: https://supertuxkart.net/Privacy. Жадаеце, каб гэта было ўключана? (Каб змяніць гэта пазней, перайдзіце ў налады, абярыце «Асноўнае», і змяніце «Злучэнне з інтэрнэтам»). " -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Раздзяляльная здольнасць вашага экрана занадта нізкая для STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Ваш відэадрайвер занадта стары. Калі ласка, абнавіце яго." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3659,38 +3855,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Вашы графічныя драйверы занадта старыя. Калі ласка, праверце, ці ёсць да іх абнаўленні. SuperTuxKart рэкамендуе драйверы, што падтрымліваюць %sабо лепш. Гульня, хутчэй за ўсё, будзе працаваць, але ў рэжыме зніжанай графікі." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Час злучэння з серверам выйшаў" #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s узяў чырвоны сцяг!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Чырвоны сцяг цяпер вернуты!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s узяў сіні сцяг!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Cіні сцяг цяпер вернуты!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s захапіў сіні сцяг!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s захапіў чырвоны сцяг!" @@ -3700,7 +3896,7 @@ msgstr "%s захапіў чырвоны сцяг!" msgid "Eggs: %d / %d" msgstr "Яйкі: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Лідар" @@ -3708,22 +3904,22 @@ msgstr "Лідар" msgid "Final lap!" msgstr "Апошні круг!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Круг %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s ад %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Новы лепшы круг" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "НЯПРАВІЛЬНЫ НАКІРУНАК!" @@ -3737,7 +3933,7 @@ msgstr "%s забіў гол!" msgid "Oops, %s made an own goal!" msgstr "Ой, аўтагол ад %s!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" @@ -3746,187 +3942,187 @@ msgstr[1] "%i запаскі для карта з'явіліся!" msgstr[2] "%i запасак для карта з'явілася!" msgstr[3] "%i запасак для карта з'явілася!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Вас дыскваліфікавалі!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "«%s» дыскваліфікаваны." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Сервер быў выключаны." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Вас вытурылі з сервера." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Вас вытурылі з сервера - пінг занадта высокі." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Выяўлена кепскае падключэнне да сеціва." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Бот" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s адлучаны." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Націсніце імя гульца ў спісе, каб даведацца пра яго рэйтынг і кіраваць дзеяннямі ў адносінах да яго." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Складанасць: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Максімум гульцоў: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Рэжым гульні: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Ліміт часу" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Ліміт галоў" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Тып футбола: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Прагрэс Гран-пры: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Усе гульцы далучыліся да чырвонай або да сіняй каманды." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Цяпер вы ўладальнік сервера" -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "У злучэнні адмоўлена: сервер заняты" -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "У злучэнні адмоўлена: вас заблакавалі на серверы" -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "У злучэнні адмоўлена: хібны пароль." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "У злучэнні адмоўлена: даныя гульні несумяшчальныя." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "У злучэнні адмоўлена: няма месца на серверы." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "У злучэнні адмоўлена: хібнае падлучэнне гульца." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Не ўдалося пачаць сеціўную гульню." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Гульня скончылася, вы больш не можаце далучыцца да гульні ці назіраць яе." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "У арэне больш няма месца - далучэнне да гульні адключана." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Толькі 1 гулец застаўся, вяртаемся ў лобі." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Уладальнік сервера выйшаў з гульні." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Вы будзеце назіраць наступную гульню." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s далучыўся да чырвонай каманды." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s далучыўся да сіняй каманды." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s далучыўся да гульні." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3934,15 +4130,15 @@ msgid "" msgstr "Націсніце <%s> або <%s>, каб назіраць іншага гульца; <%s> або <%s>, каб змяніць становішча камеры." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "Паспяхова паскардзіліся на %s." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3973,38 +4169,38 @@ msgstr "Часовая гонка (Гран-пры)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Бітва супраць усіх" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Захоп сцяга" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s зараз у сеціве." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s і %s зараз у сеціве." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s і %s зараз у сеціве." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4014,12 +4210,12 @@ msgstr[2] "%d сяброў цяпер анлайн." msgstr[3] "%d сяброў цяпер анлайн." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s цяпер на серверы \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4028,7 +4224,7 @@ msgstr[1] "У вас %d новыя запыты на сяброўства!" msgstr[2] "У вас %d новых запытаў на сяброўства!" msgstr[3] "У вас %d новых запытаў на сяброўства!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "У вас новы запыт на сяброўства!" @@ -4057,12 +4253,12 @@ msgid "" msgstr "Файл вынікаў занадта стары.\nУсе вынікі выдалены." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Руш за лідарам" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Бітва 3 удараў" @@ -4075,93 +4271,88 @@ msgstr "Файл незавершанага паўтору не будзе за msgid "Replay saved in \"%s\"." msgstr "Паўтор захаваны ў «%s»." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 тыдзень" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 тыдні" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 месяц" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 месяцы" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 месяцаў" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 месяцаў" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 год" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 гады" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Назва дадатка" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Дата абнаўлення" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Не ўсталявана" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s, аўтар %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Калі ласка, пачакайце, пакуль дадаткі абновяцца" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Выбачайце, пры звароце да сайта дадаткаў адбылася памылка. Пераканайцеся, што вы злучаны з інтэрнэтам і што SuperTuxKart не блакуецца фаерволам." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Заблакавана: перамажыце ў дзейных спаборніцтвах, каб атрымаць доступ да новых!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Выпадковая арэна" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d арэна недаступная ў самотнай гульне." -msgstr[1] "%d арэны недаступная ў самотнай гульне." -msgstr[2] "%d арэн недаступная ў самотнай гульне." -msgstr[3] "%d арэн недаступна ў самотнай гульне." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\n, 2015\nДенис Ким, 2019-2020\nViktar Vauchkevich, 2017-2019,2021\nŹmicier Turok, 2018\nZmicer Turok, >, 2018\nДенис Ким, 2019-2022\nViktar Vauchkevich, 2017-2019" @@ -4449,7 +4640,7 @@ msgstr "Бананаў сабрана" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Слізганне" @@ -4552,7 +4743,7 @@ msgstr "Скончана паляванняў на яйкі" msgid " (official tracks matching the goal)" msgstr " (афіцыйныя трасы, што адпавядаюць мэце)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4560,91 +4751,95 @@ msgid "" msgstr "Новыя геймпады і джойсцікі аўтаматычна з'явяцца ў спісе, калі вы далучыце іх да гэтай прылады.\n\nКаб дадаць канфігурацыю клавіятуры, вы можаце выкарыстоўваць кнопку ніжэй, АДНАК звярніце ўвагу, што большасць клавіятур падтрымлівае толькі абмежаваную колькасць адначасовых націсканняў клавіш і, такім чынам, непрыдатныя для шматкарыстальніцкай гульні. (Але вы можаце падключыць да гэтай прылады некалькі клавіятур. Памятайце, што ў гэтым выпадку кожнаму па-ранейшаму патрэбны розныя спалучэнні клавіш.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Дадаць Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Дадаць канфігурацыю клавіятуры" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Абнавіць" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Версія: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "рэкамендуецца" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Памер: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Выбачайце, не атрымалася спампаваць дадатак" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Праблемы з усталёўкай дадатка «%s»." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Паспрабаваць зноў" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Праблемы з выдаленнем дадатка «%s»." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Фонавая спампоўка скончаная." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Спампаваць у фоне" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Фонавая спампоўка ужо пачалася." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Бягучы пароль хібны." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Пароль мусіць быць даўжынёй ад 8 да 30 сімвалаў!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Паролі не супадаюць!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Праверка інфармацыі" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Пароль паспяхова зменены." @@ -4667,67 +4862,97 @@ msgstr "Разрозненні, меншыя за 1024x768 або 1280x720, не #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Здымка дронам" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Адвольны" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Выключана" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Толькі важнае" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Вельмі нізкі" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Нізкі" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Сярэдні" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Высокі" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ультра" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4735,7 +4960,7 @@ msgid "" msgstr "SuperTuxKart спампуе поўныя рэсурсы гульні (што ўключаюць тэкстуры высокай якасці і музыку) для лепшай якасці гульні. Калі вы не маеце wifi-злучэння, ваша мабільнае злучэнне з Інтэрнэтам будзе выкарыстана." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4752,101 +4977,102 @@ msgstr "Увядзіце адрас сервера. Вы можаце такса msgid "Invalid server address: %s." msgstr "Хібны адрас сервера: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "У адваротным напрамку" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Складанасць" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Кругі" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Час" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Карт" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Карыстальнік" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Версія" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Не" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Траса" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "%d лепшых вынікаў" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Колькасць картаў: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Мэта часу: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Колаў: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "У адваротным напрамку: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Пуста)" @@ -4934,33 +5160,41 @@ msgid "Press any key..." msgstr "Націсніце любую клавішу..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Чат зараз выключаны, уключыце яго ў меню наладаў." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Назад да бітвы" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Новая гульня" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Перазапусціць бітву" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Выйсці з бітвы" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Новая гонка" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Выйсці з гонкі" @@ -4976,11 +5210,11 @@ msgstr "%s пакуль не мае рэйтынгу" msgid "%s is number %d in the rankings with a score of %f." msgstr "%s мае месца %d у рэйтынгу з рэзультатам %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Імя і/або пароль карыстальніка хібныя." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5002,7 +5236,7 @@ msgstr "Паўтор гонкі з прывідам" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Кругоў: %i" @@ -5015,21 +5249,21 @@ msgstr "Тып: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Неабходны ранг: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Неабходны час: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Неабходная колькасць нітра: %i" @@ -5042,54 +5276,54 @@ msgstr "Колькасць ботаў: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Рэжым бітвы" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Тып футболу" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Лакацыя сервера: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Бягучая траса: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Ранг" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Гулец" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Рэйтынг" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Час гульні" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Выдаліць з закладак" @@ -5102,74 +5336,74 @@ msgid "No player available for connecting to server." msgstr "Гульцоў для злучэння з серверам няма." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Імя карыстальніка: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Скасаваць запыт" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Сёння" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Запыт на сяброўства адпраўлены!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Запыт на сяброўства ўхвалены!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Запыт на сяброўства адхілены!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Сябар выдалены!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Запыт на сяброўства скасаваны!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Апрацоўка" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Атрыманне апошняга голасу" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Вы можаце змяніць рэйтынг націсканнем на зорачкі ніжэй." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Вы яшчэ не галасавалі за гэты дадатак. Абярыце жадаемы рэйтынг націсканнем на зорачкі ніжэй" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Голас залічаны! Вы можаце закрыць акно." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Выкананне галасавання" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Выпадковая траса" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5198,7 +5432,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Падчас спробы захавання Гран-пры адбылася памылка." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Абярыце трасу" @@ -5242,12 +5476,12 @@ msgstr "Вы разблакавалі трасу %0" msgid "You unlocked grand prix %0" msgstr "Вы разблакавалі Гран-пры %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Траса" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5268,19 +5502,19 @@ msgstr "Задайце назву для Гран-пры" msgid "Please select a Grand Prix" msgstr "Калі ласка, абярыце Гран-пры" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Вызначаныя карыстальнікам" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Назва пустая." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Іншы Гран-пры з такой назвай ужо існуе." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Назва занадта доўгая." @@ -5289,19 +5523,19 @@ msgstr "Назва занадта доўгая." msgid "Better luck next time!" msgstr "Пашчасціць наступным разам!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Вы завяршылі спаборніцтва!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Вы перамаглі ў Гран-Пры!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Вы завяршылі Гран-пры!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Колькасць картаў" @@ -5314,110 +5548,125 @@ msgstr "Вы ўпэўнены, што хочаце выдаліць запіс msgid "Are you sure you want to remove all of your high scores?" msgstr "Вы ўпэўнены, што хочаце выдаліць усе запісы з лепшых вынікаў?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Лёгкія" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Цяжкія" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Далучыце клавіятуру ці геймпад, каб згульць у сумесную гульню з раздзяленнем экрана" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Выпадковы карт" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Заблакавана" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Націсніце «Абраць», каб далучыцца да гульні" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Ці жадаеце прайсці навучанне гульні?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Вы не можаце гуляць у сеціве без доступу ў інтэрнэт. Калі жадаеце, перайдзіце ў налады і ўключыце «Злучэнне з інтэрнэтам»." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Вы не можаце спампаваць дадаткі без доступу ў інтэрнэт. Калі жадаеце спампаваць іх, перайдзіце ў налады і ўключыце «Злучэнне з інтэрнэтам»." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Вы не можаце спампаваць дадаткі без доступу ў інтэрнэт. Калі жадаеце спампаваць іх, перайдзіце ў налады і ўключыце «Злучэнне з інтэрнэтам».\n\nАле вы можаце выдаліць ужо усталяваныя дадаткі." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Модуль дадаткаў выключаны ў наладах" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Калі ласка, пачакайце, пакуль дадаткі загрузяцца" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Ці вы упэўненыя, што хочаце выйсці з STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Стварыць LAN-сервер" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Сервер %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Трасы Гран-пры адсутнічаюць" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Назва мусіць быць даўжынёй ад 4 да 30 сімвалаў!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "У паролі хібныя сімвалы!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Гатовы" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Далучыцца" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Глядзець" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Усталяваць дадатак" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5425,7 +5674,7 @@ msgstr "Пачакайце, пакуль бягучая гульня (%s) ско #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Пачакайце, пакуль бягучая гульня скончыцца, разліковы час чакання: %s." @@ -5433,24 +5682,24 @@ msgstr "Пачакайце, пакуль бягучая гульня сконч #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Пачакайце, пакуль бягучая гульня (%s) скончыцца, разліковы прагрэс: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Пачакайце, пакуль бягучая гульня скончыцца, разліковы прагрэс: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Пачакайце, пакуль бягучая гульня скончыцца." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5461,7 +5710,7 @@ msgstr[3] "Гульня пачнецца, калі будзе больш за %d #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5472,96 +5721,108 @@ msgstr[1] "Старт праз %d секунды, або калі ўсе гул msgstr[2] "Старт праз %d секунд, або калі ўсе гульцы націснуць кнопку 'Гатовы'." msgstr[3] "Старт праз %d секунд, або калі ўсе гульцы націснуць кнопку 'Гатовы'." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Злучэнне з серверам %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Пошук сервера хуткай гульні" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Засталося часу: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Мэты" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Атрыманне дасягненняў" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Профіль %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Ад" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Статус" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Атрыманне сяброў" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Новы запыт" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Чаканне" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Па-за сецівам" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Увядзіце новы E-mail ніжэй" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Новы E-mail павінен мець ад 5 да 254 сімвалаў!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Новы E-mail несапраўдны!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "E-mail зменены!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Не ўдалося змяніць E-mail: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Навіны з блогу STK" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Дата" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Вам трэба ўвайсці ў сеціўны акаўнт, каб гуляць у глабальным сеціве. Націсніце сваё імя карыстальніка наверсе." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Пошук" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Выйсці з гульні" @@ -5639,34 +5900,34 @@ msgid "Distance (km)" msgstr "Дыстанцыя (км)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Невядома" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Не ўдалося выявіць IPv4, магчыма, вы не зможаце далучацца да сервераў па гэтаму пратаколу." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Не ўдалося выявіць IPv6, магчыма, вы не зможаце далучацца да сервераў па гэтаму пратаколу." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Няма даступных сервераў." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Атрыманне сервераў" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Серверныя закладкі" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5674,149 +5935,149 @@ msgstr "Калі большасць гульцоў абярэ трасу і на #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Выпадкова размешчаныя бонусы" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Колькасць галоў для перамогі" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Адваротны накірунак" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Заблакавана: каб атрымаць доступ, спачатку прайдзіце даступныя спаборніцтвы!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Дзеянне" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Кнопка" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Выключыць прыладу" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Уключыць прыладу" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Уключыць канфігурацыю" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Гульнявыя дзеянні" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Дзеянні ў меню" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Кіраваць налева" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Кіраваць направа" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Паскарэнне" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Тормаз / Задні ход" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Атака" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Нітра" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Паглядзець назад" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Паратунак" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Прыпыніць гульню" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Вышэй" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Ніжэй" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Налева" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Направа" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Абраць" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Скасаваць/назад" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Сіні элемент азначае канфлікт з іншай канфігурацыяй" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Чырвоны элемент азначае канфлікт з бягучай канфігурацыяй" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5824,17 +6085,27 @@ msgid "" msgstr "Увага: не рэкамендуецца ўжываць «Shift», таму што пры яго націсканні клавішы ніжняга рэгістру могуць не працаваць." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Вы ўпэўнены, што хочаце назаўжды выдаліць гэтую канфігурацыю?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Увядзіце новае імя канфігурацыі, пакіньце пустым, каб вярнуць значэнне па змаўчанні." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Вертыкальная" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Гарызантальная" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5842,89 +6113,74 @@ msgstr "У рэжыме сумеснай гульні гульцы могуць #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Усталяваць поўныя рэсурсы гульні" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Ці вы упэўнены, што хочаце выдаліць поўныя рэсурсы гульні?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Клавіятура %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Сэнсарная прылада" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Націсніце на прыладу, каб наладзіць яе" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Сістэмная мова" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Унізе злева" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "Справа" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Схаваная" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "У цэнтры" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Вертыкальная" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Гарызантальная" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Вельмі маленькі" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Маленькі" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Сярэдні" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Вялікі" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Велізарны" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5934,128 +6190,133 @@ msgid "" msgstr "Рэжым хуткага прахождання гульні можа быць уключаны, толькі калі гульня не была закрыта пасля запуску рэжыма гісторыі.\n\nЗакрыццё гульні да таго, як рэжым гісторыі быў пройдзены, інвалідуе таймер.\n\nКаб выкарыстоўваць рэжым хуткага праходжання гульні, калі ласка, стварыце новы профіль." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Вертыкальная сінхранізацыя" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Вертыкальная сінхранізацыя прымушае графічную карту згенераваць наступны кадр толькі тады, калі экран гатовы яго паказаць." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Вертыкальная сінхранізацыя не будзе працаваць, калі вашы драйверы яе не падтрымліваюць." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Эфекты часціц: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Анімацыя персанажаў: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Дынамічае асвятленне: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Рассейванне святла: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Згладжванне: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Навакольная аклюзія: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Цені: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Цені: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Свячэнне: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Контурнае свячэнне: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Промні святла (God rays): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Якасць адмаляванай выявы: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Размыццё руху: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Глыбіня рэзкасці: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Доступ у Інтэрнэт выключаны. Ці жадаеце уключыць яго?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Вам неабходна ўвесці пароль." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Выхад з «%s»" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Уваход у «%s»" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Вы не можаце выдаліць адзінага гульца." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Вы сапраўды хочаце выдаліць гульца '%s'?" @@ -6083,7 +6344,7 @@ msgstr "ГОЛ!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Чаканне астатніх" @@ -6118,7 +6379,7 @@ msgstr "Руш за лідарам!" msgid "Top %i" msgstr "Топ %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Спаборніцтва правалена" @@ -6142,102 +6403,199 @@ msgstr "Націсніце значок подыума, каб пачаць сп msgid "Press fire to start the challenge" msgstr "Націсніце атаку, каб пачаць спаборніцтва" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Выйсці з сервера." -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Скасаваць Гран-пры" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Перазапуск" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Назад да выбару спаборніцтва" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Правесці паўтор гонкі з прывідам" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Назад да меню" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Вы сапраўды хочаце скасаваць Гран-пры?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Перамаглі чырвоныя" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Перамаглі сінія" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Гэта нічыя" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Выбыў праз %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Выбыў" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Гол сабе)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Траса %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Прагрэс Гран-пры:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Лепшыя вынікі" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Лепшы час круга: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "ад %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Вы завяршылі спаборніцтва!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Вы правалілі спаборніцтва!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Патрабаванні для складанасці SuperTux дасягнутыя" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Усе прыёмы дазволены, таму бярыце зброю і ўжывайце яе напоўніцу!" @@ -6278,28 +6636,28 @@ msgstr "Націсніце чырвоную або сінюю іконку фу #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Аўтар %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Максімальная колькасць гульцоў: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Колькасць ботаў у чырвонай камандзе" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Вы не можаце гуляць у гэтае Гран-Пры, бо некаторыя трасы ў ім яшчэ не разблакаваныя!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Заблакавана!" @@ -6321,10 +6679,12 @@ msgid "%d/%m/%Y" msgstr "%d.%m.%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Завяршыце ўсе спаборніцтвы, каб адчыніць вялікія дзверы!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6333,41 +6693,48 @@ msgid "" msgstr "Вам патрэбна больш балаў для\nўдзелу ў гэтым спаборніцтве!\nШукайце даступныя\nспаборніцтвы на мінімапе." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Паскарайцеся пры дапамозе <%s> і кіруйце — <%s> і <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Паскарайцеся з дапамогай націску на верхнюю частку руля. Каб павярнуць, перамясціце дотык налева/направа." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Каб паскорыцца, перадвіньце акселератар наверх. Каб павярнуць, нахіліце вашу прыладу." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Каб паскорыцца, перадвіньце акселератар наверх. Каб павярнуць, павярніце вашу прыладу." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Збірайце скрыні з падарункамі ды страляйце пры дапамозе <%s>, каб прыбраць вялікія скрыні з дарогі!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Збірайце скрыні з падарункамі ды страляйце пры дапамозе іконкі шара для боўлінга, каб прыбраць вялікія скрыні з дарогі! " #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6375,34 +6742,41 @@ msgid "" msgstr "Націсніце <%s>, каб азірнуцца.\nСтраляйце ўзад пры дапамозе <%s>, утрымліваючы <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Націсніце на іконку люстэрка, каб паглядзець назад.\nКаб запусціць зброю назад, націсніце на іконку люстэрка і правядзіце ад яе да іконцы стральбы!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Выкарыстоўвайце назбіранае нітра пры дапамозе <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Націсніце іконку нітра, каб выкарыстаць сабраныя нітра-зарады" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Збірайце бутэлькі з нітра (выкарыстаем іх пасля павароту)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Вой! Калі ў вас праблемы, націсніце <%s> для выратавання." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Вой! Калі ў вас праблемы, націсніце іконку птушкі для выратавання." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6410,24 +6784,27 @@ msgid "" msgstr "Разганіцеся і націсніце <%s> падчас заносу.\nСлізганне дапаможа вам мінуць крутыя павароты хутчэй." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Разганіцеся і націсніце іконку заносу пры павароце, каб пайсці ў занос.\nСлізганне на кароткі час дапаможа вам мінуць крутыя павароты хутчэй." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Звярніце ўвагу, што калі вы кантралюеце занос некалькі секунд, то атрымаеце бонус хуткасці!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Цяпер вы падрыхтаваны да гонкі. Удачы!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "3D-гульня для гонак на картах з адкрытым зыходным кодам" @@ -6437,7 +6814,7 @@ msgstr "3D-гульня для гонак на картах з адкрытым msgid "tux;game;race;" msgstr "tux;game;race;тукс;такс;гульня;гонка;футбол;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6445,7 +6822,7 @@ msgid "" "for all ages." msgstr "Карты. Нітра. Старт! SuperTuxKart - гэта 3D аркадныя гонкі з адкрытым зыходным кодам і разнастайнымі персанажамі, трасамі і рэжымамі гульні. Наша мэта - стварыць гульню, ад якой гульцы любога ўзросту атрымаюць задавальненне, з большым акцэнтам на працэсс гульні, чым на рэалістычнасць." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6454,7 +6831,7 @@ msgid "" "your opponents." msgstr "У гульні ёсць шмат разнастайных трэкаў - пад вадой, на ферме, у джунглях, альбо нават у космасе! Пакажыце, на што вы здольныя, але пазбягайце сутыкненняў з іншымі картамі, бо яны могуць абагнаць вас, і з бананамі! Будзьце ўважлівыя з шарамі для боўлінга, вантузамі, жуйкамі і піражкамі ад вашых супернікаў." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6463,27 +6840,27 @@ msgid "" "your racing skills!" msgstr "Вы можаце правесці адну гонку супраць іншых картаў, паспаборнічаць у адным з некалькіх Гран-пры, паспрабаваць самастойна пабіць лепшы час, гуляць у рэжыме бою супраць кампутара або сваіх сяброў і многае іншае! Далучайцеся да анлайн і сустракайцеся з гульцамі з усяго свету і пакажыце свае гоначныя навыкі!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Гэтая гульня не змяшчае рэкламы." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Гэтая версія SuperTuxKart - нестабільная, але мае нядаўнія паляпшэнні. Яна выпушчаная ў асноўным для тэстаў, каб зрабіць стабільную версію як мага лепш." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Вы можаце ўсталяваць гэтую версію на вашай прыладзе паралельна са стабільнай версіяй." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Калі вам патрэбна больш стабільнасці, вы можаце карыстацца стабільнай версіяй: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "Каманда SuperTuxKart" diff --git a/data/po/bg.po b/data/po/bg.po index 1b3b667fa44..2919c980b09 100644 --- a/data/po/bg.po +++ b/data/po/bg.po @@ -7,14 +7,14 @@ # FIRST AUTHOR , 2010 # Любомир Василев, 2015-2016 # Любомир Василев, 2016-2020 -# Любомир Василев, 2020-2023 +# Любомир Василев, 2020-2024 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Любомир Василев, 2020-2023\n" +"Last-Translator: Любомир Василев, 2020-2024\n" "Language-Team: Bulgarian (http://app.transifex.com/supertuxkart/supertuxkart/language/bg/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -171,7 +171,7 @@ msgstr "На края на света" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Назад" @@ -193,7 +193,7 @@ msgstr "Избери предпочитан вид управление" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Акселерометър" @@ -207,13 +207,13 @@ msgstr "Акселерометър" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Жироскоп" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Волан" @@ -244,35 +244,37 @@ msgstr "Настройки на сензорно устройство" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Общи" @@ -340,30 +342,33 @@ msgstr "Връщане на настройките по подразбиране #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Отказ" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Да" @@ -541,9 +546,9 @@ msgstr "Присъединяване" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -604,7 +609,7 @@ msgstr "Цел" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Напредък" @@ -639,7 +644,7 @@ msgstr "Готово" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Към състезанието" @@ -656,7 +661,7 @@ msgstr "Обратно към стаята." #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Рестартиране" @@ -720,12 +725,12 @@ msgstr "Въведи потребителското име и е-пощата, #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Потребителско име" @@ -766,7 +771,7 @@ msgstr "Трудност" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "За начинаещи" @@ -778,7 +783,7 @@ msgstr "За начинаещи" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Средно" @@ -790,7 +795,7 @@ msgstr "Средно" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Трудно" @@ -802,7 +807,7 @@ msgstr "Трудно" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "Супер Тъкс" @@ -810,8 +815,8 @@ msgstr "Супер Тъкс" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Режим на игра" @@ -822,8 +827,8 @@ msgstr "Режим на игра" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Обикновено състезание" @@ -836,7 +841,7 @@ msgstr "Обикновено състезание" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Състезание за време" @@ -844,7 +849,8 @@ msgstr "Състезание за време" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Битка" @@ -853,24 +859,24 @@ msgstr "Битка" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Футбол" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Парола" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Запазване на този сървър" @@ -881,7 +887,7 @@ msgstr "Добавяне на играч" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Име" @@ -975,6 +981,50 @@ msgstr "Задаване на клавиша ЕСК" msgid "Assign nothing" msgstr "Премахване" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Препоръчителни графични настройки" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Препоръчителните настройки ще бъдат приложими за текущата разделителна способност." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Какъв да бъде приоритетът на настройките?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Производителност" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Баланс между производителност и качество на графиката" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Качество на графиката" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Пестене на енергия" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Искаш ли графичните ефекти да създават размазване на картината?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Начало на теста" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -989,11 +1039,11 @@ msgstr "Настройка на състезанието" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Напред" @@ -1034,10 +1084,15 @@ msgstr "Арени" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Инсталирано" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Редактиране на любимите арени" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1047,20 +1102,20 @@ msgstr "Инсталирано" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Стандартни" @@ -1071,12 +1126,12 @@ msgstr "Стандартни" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Добавки" @@ -1090,27 +1145,28 @@ msgstr "Добавки" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Всички" @@ -1149,9 +1205,9 @@ msgstr "Преместване надолу" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Добавяне" @@ -1188,7 +1244,7 @@ msgstr "Избор на призрачен запис" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Лов на яйца" @@ -1235,10 +1291,10 @@ msgstr "Наобратно" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Време (минути)" @@ -1270,9 +1326,9 @@ msgstr "Копиране" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1283,80 +1339,80 @@ msgstr "Преименуване" msgid "Save Grand Prix" msgstr "Запазване на Голямата награда" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Помощ за Супер Тъкс Карт" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Режими на игра" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Предмети" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Банани" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1364,56 +1420,57 @@ msgstr "Банани" msgid "Story Mode" msgstr "История" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Класове колички" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "В мрежа" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Начало на обучението" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Събирай сините подаръци. В тях има различни предмети." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Избягвай бананите!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1421,14 +1478,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Събирайки азот, ще можеш да получаваш ускорение когато пожелаеш, чрез натискане на съответния клавиш или бутон. Можеш да видиш текущото ниво на азота на лентата в дясната част на екрана." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Ако видиш бутон с катинар, като този, трябва да изпълниш някакво предизвикателство, за да го отключиш." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1437,34 +1494,34 @@ msgid "" "carefully before!" msgstr "Можеш да караш количката да поднася, използвайки специалния клавиш или бутон.. Кратките последователни поднасяния може да ти помогнат при вземането на остри завои. Средно дългите поднасяния ще ти дадат ускорение, а дългите – още по-голямо такова. Количката не може да завива докато поднася, така че я насочи правилно предварително!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Можеш да получиш допълнително ускорение в началото на състезанието, като натиснеш бутона за газта при командата „Приготви се!“." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Действията на бутоните могат да бъдат прегледани/променени в менюто с настройките" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "В Супер Тъкс Карт има няколко режима на игра:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Обикновено състезание: Всичко е позволено, така че събирай предмети и ги използвай умно!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Състезание за време: Няма предмети за вземане, така че само шофьорските умения имат значение!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1472,7 +1529,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Следвай водача: Стреми се към второто място, тъй като всеки път, когато броячът стигне нула, последната количка ще отпадне от състезанието. Внимавай: ако изпревариш водача, също ще бъдеш отстранен/а!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1482,30 +1539,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Има 3 вида режими на битката: В „3 удара“ трябва да удряш другите с оръжия, докато не изгубят всичките си животи. В „Свободна битка“ играчът, който удари най-много пъти останалите, ще спечели, като се играе до определен брой удари или време. В „Плени знамето“ отборът ти трябва да грабне и донесе знамето на другия отбор в базата си, като в същото време собственият ви флаг не трябва да е в ръцете на другия отбор." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Футбол: Използвай количката си, за да избуташ топката във вратата." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Лов на яйца: Изследвай пистите, за да откриеш скритите яйца." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Призрачно преиграване: Състезавай се срещу призрачни повторения в режим „Състезание за време“ или „Лов на яйца“, и направи своя най-добър резултат!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Състезание за обиколки: Завърши колкото може повече обиколки за определено време." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1514,93 +1571,93 @@ msgid "" "wins the cup." msgstr "* Много от тези режими могат да бъдат играни и във вариант на Голяма награда: вместо едно състезание, се играят няколко подред. Колкото по-добре се класираш, толкова повече точки получаваш. Накрая играчът с най-много точки печели купата." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "За да ти е по-лесно, можеш да събираш различни видове предмети:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Дъвка – използвай я като щит или остави лепкаво розово петно след себе си като я използваш докато гледаш назад." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Ускорител – увеличава скоростта. Но внимавай да не изгубиш контрол над количката си!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Кексче – може да бъде хвърлено по най-близкия съперник, като върши най-добра работа на близки разстояния или на дълги прави участъци. Засяга и количките, които се намират близо до експлозията." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Бутало – хвърлено напред може да дръпне противник назад, а хвърлено назад, може да попречи на някого да вижда." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Топка за боулинг – търкаля с в права линия, докато не удари нещо. Може да отскача от стените. Ако гледаш назад, ще бъде хвърлена назад." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Парашут – забавя всички колички на по-предно място." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Размяна – за кратко време подаръците се превръщат в банани, бутилките с азот – в дъвки и обратно." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Топка за баскетбол – подскача след водача и може да смачка или забави количките на пътя си." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Мухобойка – смачква и забавя близките колички. Може да се използва и за премахване на парашути и бомби." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Ако минеш през банан, едно от следните неща ще бъде прикачено към количката ти:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Котва – рязко забавя количката." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Парашут – забавя количката, но по-постепенно от котвата. Колкото по-бързо се движиш, толкова по-силно е забавянето." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Бомба – след малко се взривява и подхвърля количката във въздуха. Блъсни количката си в друга количка, за да ѝ прехвърлиш бомбата." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Злият Нолок е пленил Гну! Ето няколко съвета, които ще са ти от помощ:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1609,7 +1666,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Тази иконка на малката карта показва достъпните неизпълнени предизвикателства. В горната дясна част на екрана можеш да видиш колко точки имаш в момента. Завърши колкото можеш повече предизвикателства, и Нолок ще се съгласи да се състезава с теб. Спечели състезанието, за да освободиш Гну!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1617,20 +1674,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Когато завършиш предизвикателство, получаваш купа. Всяка купа ти носи няколко точки. На колкото по-висока трудност изпълниш предизвикателството, толкова по-добра е купата и толкова повече точки носи." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Когато достигнеш точките под тази иконка, ще получиш награда. Има няколко такива за събиране." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Не всички колички се карат по един и същ начин! Те са разделени на няколко класа с различни характеристики:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1638,7 +1695,7 @@ msgid "" " resistant to explosions." msgstr "Тегло – има три класа колички според теглото: леки, средни и тежки. По-тежките колички се влияят по-малко от парашутите и са по-издръжливи на експлозии." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1646,7 +1703,7 @@ msgid "" " especially at low speeds." msgstr "Ускорение – това е особено полезно на старта, след инцидент и на писти с много остри завои. Колкото по-лека е количката, толкова по-бързо ускорява, особено на ниска скорост." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1654,14 +1711,14 @@ msgid "" " top speed." msgstr "Максимална скорост – колкото по-висока е, толкова по-бързо може да се движи количката. Особено полезно на писти с прави отсечки и леки завои. По-тежките колички имат по-висока максимална скорост." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Ефективност на азота – колкото по-висока е, толкова повече скорост може да се извлече от една бутилка с азот. Колкото е по-лека количката, толкова по-висока е и ефективността ѝ при ползване на азот." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1669,12 +1726,12 @@ msgid "" "easier it is." msgstr "Ако караш много близо зад друга количка в продължение на няколко секунди, ще получиш допълнителна скорост, когато я изпревариш. Колкото по-лека е количката, толкова по-лесно е това." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "Супер Тъкс Карт може да се играе в режим на мрежова игра по Интернет…" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1684,7 +1741,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Първо, избери иконката за игра в Интернет от главното меню. Избери локална или глобална мрежа (това изисква в настройките да бъде включена възможността за игра по Интернет). След това можеш да създадеш свой собствен сървър с персонализирани настройки, или да прегледаш списъка от налични сървъри и да избереш някой, с който да се свържеш. Някои от тях са препоръчани сървъри, в които може да се състезаваш за ранг." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1694,12 +1751,12 @@ msgid "" "players and the server." msgstr "След като се свържеш със сървъра, състезанието ще започне, когато собственикът на сървъра (този с коронката) реши. На официалните сървъри състезанието може да започне, когато се съберат достатъчно играчи. След това можеш да си избереш количка и да гласуваш за следващата писта, на която да се играе. Пистите от добавки са позволени само ако сървърът и всички играчи разполагат с тях." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "…или на едно устройство:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1709,7 +1766,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Първо, ще трябват няколко входящи устройства. Използвай екрана за настройка на входа, за да ги настроите. Най-добре е да се използват няколко контролера. На клавиатурата всеки от играчите ще трябва да разполага с различен набор от клавиши, а и имайте предвид, че повечето клавиатури не са подходящи за целта, тъй като на тях не може да бъдат натиснати твърде много клавиши едновременно." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1729,7 +1786,7 @@ msgstr "Избор на най-добри резултати" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Състезание за обиколки" @@ -1737,9 +1794,9 @@ msgstr "Състезание за обиколки" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Голяма награда" @@ -1750,6 +1807,20 @@ msgstr "Голяма награда" msgid "Choose a Kart" msgstr "Избери количка" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Клас колична" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Редактиране на любимите колички" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1763,11 +1834,11 @@ msgstr "Разделен екран" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "На линия" @@ -1784,7 +1855,7 @@ msgstr "Обучение" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Най-добри резултати" @@ -1792,7 +1863,7 @@ msgstr "Най-добри резултати" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Постижения" @@ -1846,30 +1917,30 @@ msgstr "Търсене на сървър" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Създаване на сървър" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Стая" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Настройка" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Начало на състезанието" @@ -1895,9 +1966,9 @@ msgstr "Въведи адрес на сървъра" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Твоят профил" @@ -1915,7 +1986,7 @@ msgstr "Рангове на играчите" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Приятели" @@ -1940,7 +2011,7 @@ msgstr "Бърза игра" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Настройки на профила" @@ -1990,8 +2061,8 @@ msgid "Online Username" msgstr "Интернет име" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Нулиране на паролата" @@ -2004,7 +2075,7 @@ msgid "" msgstr "Можеш да играеш без да си създаваш профил в Интернет, като избереш обикновен профил. Но така няма да можеш да се свързваш с приятели, да гласуваш за добавки и т.н. Моля, прочети нашата декларация за поверителност тук: https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Избор на сървър" @@ -2022,339 +2093,409 @@ msgstr "Използване на връзка чрез IPv6" msgid "User search" msgstr "Търсене на потребител" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Настройки на Супер Тъкс Карт" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Изглед" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Графика" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Звук" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Интерфейс" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Играчи" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Управление" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Език" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Музика" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Включено" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Сила на звука" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Звукови ефекти" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Изтриване на настройката" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Изключване на настройката" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Назад към списъка с устройства" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Преименуване на конфигурацията" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Включване на осезаемото противодействие (ако се поддържа)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Разделителна способност" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "На цял екран" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Запомняне на местоположението на прозореца" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Прилагане на новата разделителна способност" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Разделяне на екрана" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Настройки за Интернет" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Показване на екрана за вход всеки път" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Свързване с Интернет" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Разрешаване на писането на съобщения в игри по Интернет" +msgid "Enable chatting in online lobbies" +msgstr "Разрешаване на писането на съобщения в чакалните за игра по Интернет" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Разрешаване на писането на съобщения в игри по Интернет" +msgid "Enable chatting in online matches" +msgstr "Разрешаване на писането на съобщения в мачове по Интернет" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Други настройки" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Затруднения за отделни играчи" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Деинсталиране на големите файлове на играта" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Натисни Ентер или щракни два пъти върху устройство, за да го настроиш" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Добавяне на устройство" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Коя конфигурация ще се използва се определя от това кой бутон „Избиране“ е натиснат за присъединяване към играта." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Облик" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Малка карта" +msgid "Skin variant" +msgstr "Вариант на облика" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Разделяне на екрана" +msgid "Minimap" +msgstr "Малка карта" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Размер на шрифта" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Камера" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Персонализиране…" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Показване на кадрите в секунда" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Показване на предметите, държани от другите колички" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Следене на времето в режима на историята" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Следене на времето при скоростно изиграване" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Разделителна способност на изчертаването" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Ниво на графичните ефекти" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Ниво на ефектите на замъгляване" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Макс. кадри/сек" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Доп. настройки…" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Разделителна способност" +msgid "Performance tests" +msgstr "Тестове на производителността" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "На цял екран" +msgid "Performance test of the current settings" +msgstr "Тест на производителността при текущите настройки" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Запомняне на местоположението на прозореца" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Запомняне на паролата" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Прилагане на новата разделителна способност" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Изтриване" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Цвят на количката" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2381,15 +2522,15 @@ msgstr "Син отбор" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Брой обиколки" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Брой колички, управлявани от ИИ" @@ -2404,33 +2545,17 @@ msgstr "Брой колички от синия отбор, управляван msgid "Random Grand Prix" msgstr "Случайна Голяма награда" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Редактиране на любимите писти" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Вход" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Запомняне на паролата" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Изтриване" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Цвят на количката" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Обликът на интерфейса може да бъде променен от настройките на интерфейса." @@ -2549,238 +2674,306 @@ msgid "" msgstr "Не се пречкай на съотборника, у когото е топката, но можеш да се опитваш да удряш противниците, които се опитват да го спрат да отбележи." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Адиуми" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Аманда" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Годет" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Емуле" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Гаврош" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Гну" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Хексли" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Кики" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Конки" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Нолок" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Пидгин" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Пъфи" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Пепър" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Сара" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Сузане" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Тъкс" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Уилбър" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Ксю" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Допотопна бездна" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Извънземен сигнал" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Лабиринт в древния Колизей" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Град Кандела" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Боен остров" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Черна гора" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Пещера Х" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Какаов храм" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Царевична нива" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Магмена крепост" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "о-в Голям Рай" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Ранчо" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Игрище с дупки" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Заледено игрище за футбол" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Какво има, малки хипита? Да не би великият ви водач гну да го няма?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "О, да, виждате ли, той е в замъка ми и ще бъде сервиран за вечеря…" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Но аз съм честно създание, така че ви предлагам сделка." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Ако ме победите в състезание, ще освободя стария чудак." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "Но вие, жалки нищожества, никога няма да победите мен –царя на количките!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Арена лас Дунас" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Футболен стадион Лас Дунас" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Около фара" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Стара мина" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Мини-голф" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Оазис" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Час по математика" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Тиквен парк" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Имението Рейвънбридж" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Плаващи пясъци" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Езерото на Неси" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Северен курорт" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Снежен връх" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Игрище за футбол" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Стадионът" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "СТК Ентърпрайз" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Храм" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Остров с вулкан" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "ХР591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Дзен градина" @@ -2789,11 +2982,11 @@ msgstr "Дзен градина" msgid "Completed achievement \"%s\"." msgstr "Изпълнено е постижението „%s“." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Не може да бъде установена връзка със сървъра за добавки." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Грешка при изтеглянето на новините: „%s“." @@ -2859,7 +3052,7 @@ msgid "New kart '%s' now available" msgstr "Налична е нова количка: „%s“" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2891,32 +3084,32 @@ msgid "" "created." msgstr "Файлът с настройките беше твърде стар, затова беше изтрит и ще бъде създаден нов." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Записът на видео започна." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Видеото е запазено в „%s“." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Напредък по кодирането:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "кадри/сек: %d/%d/%d – %d хил. триъгълника, закъснение: %d мсек" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Съвет: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Зареждане" @@ -2938,19 +3131,18 @@ msgstr "Ефективност на азота" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (затруднен)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s е готов" @@ -3424,21 +3616,21 @@ msgid "Axis %d" msgstr "Ос %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Бутон %d на контролера" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Бутон %d на мишката" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Ос %d %s на мишката" @@ -3610,26 +3802,30 @@ msgstr "Можеш да имаш най-много 3 живота!" msgid "+1 life." msgstr "+1 живот." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Ти беше много бавен!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Ти завърши състезанието!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Ти спечели състезанието!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Ти завърши състезанието на ранг %d!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s напусна играта." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3638,16 +3834,16 @@ msgid "" "Internet\")." msgstr "Супер Тъкс Карт може да се свързва със сървър, за да сваля добавки и да те известява за обновления. Моля, прочети нашата декларация за поверителност тук: https://supertuxkart.net/Privacy. Би ли искал тази функционалност да бъде включена? (За да промениш тази настройка по-късно, отиди в настройките, избери раздела „Общи“ и промени „Свързване с Интернет“)." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Разделителната способност на екрана е твърде малка." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Версията на драйвера е твърде стара. Моля, инсталирай най-новия драйвер за видео картата." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3655,38 +3851,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Драйверът за графичната карта изглежда е много стар. Моля, провери дали има по-нов. Супер Тъкс Карт препоръчва драйвер, който поддържа %s или по-нова версия. Играта най-вероятно пак ще работи, но в ограничен графичен режим." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Времето за изчакване на сървъра изтече." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "Червеният флаг е в %s!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Червеният флаг бе върнат!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "Синият флаг е в %s!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Синият флаг бе върнат!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s плени синьото знаме!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s плени червеното знаме!" @@ -3696,7 +3892,7 @@ msgstr "%s плени червеното знаме!" msgid "Eggs: %d / %d" msgstr "Яйца: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Водач" @@ -3704,22 +3900,22 @@ msgstr "Водач" msgid "Final lap!" msgstr "Последна обиколка" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Обиколка %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s от %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Нова най-бърза обиколка" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "ГРЕШНА ПОСОКА!" @@ -3733,194 +3929,194 @@ msgstr "%s отбеляза гол!" msgid "Oops, %s made an own goal!" msgstr "Опа, %s си вкара автогол!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "Създадена е %i резервна количка!" msgstr[1] "Създадени са %i резервни колички!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Те беше отстранен!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "„%s“ беше отстранен." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Сървърът беше изключен." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Изритаха те от сървъра." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Изритаха те от сървъра: има твърде много забавяне във връзката със сървъра" -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Засечена е лоша връзка с мрежата." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Бот" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s се разкачи." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Щракни името на играч в списъка за управление и информация за ранга." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Трудност: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Макс. брой играчи: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Режим на игра: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Времево ограничение" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Ограничение на головете" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Вид футболна игра: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Напредък в Голямата награда: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Всички играчи са в червения или синия отбор." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Вече ти си собственик на сървъра." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Връзката е отказана: сървърът е зает." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Връзката е отказана: достъпът ти до сървъра е забранен." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Връзката е отказана: паролата за сървъра е грешна." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Връзката е отказана: данните на играта са несъвместими." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Връзката е отказана: сървърът е пълен." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Връзката е отказана: свързващият се играч е неразпознаваем." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Мрежовата игра не успя да се стартира." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Играта приключи. Вече не можеш да се присъединиш или да наблюдаваш." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Няма свободни места в арената – присъединяването е невъзможно." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Остава само 1 играч, връщане към стаята…" -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Създателят на сървъра напусна играта." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "По време на следващата игра ще си наблюдател." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s се присъедини към червения отбор." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s се присъедини към синия отбор." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s се присъедини към играта." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3928,15 +4124,15 @@ msgid "" msgstr "Натисни <%s> или <%s>, за да промениш това кой играч следиш, <%s> или <%s> за позицията на камерата." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "%s беше докладван успешно." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3967,38 +4163,38 @@ msgstr "Състезание за време (Голяма награда)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Свободна битка" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Плени знамето" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s е на линия." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s и %s са на линия." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s и %s са на линия." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4006,19 +4202,19 @@ msgstr[0] "%d приятел е на линия." msgstr[1] "%d приятели са на линия." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s вече е на сървъра „%s“." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "Имаш %d нова покана за приятелство!" msgstr[1] "Имаш %d нови покани за приятелство!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Имаш нова покана за приятелство!" @@ -4047,12 +4243,12 @@ msgid "" msgstr "Файлът с най-добри резултати беше твърде стар.\nВсички резултати бяха изтрити." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Следвай водача" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "3 удара" @@ -4065,91 +4261,88 @@ msgstr "Не може да бъде запазен файл с непълен з msgid "Replay saved in \"%s\"." msgstr "Записът е запазен в „%s“." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 седмица" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 седмици" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 месец" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 месеца" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 месеца" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 месеца" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 година" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 години" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Име на добавката" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Дата на обновяване" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Не инсталирано" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s от %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Моля, изчакай докато добавките бъдат обновени" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Съжаляваме, но възникна грешка при свързването със сървъра за добавките. Увери се, че си свързан към Интернет и че Супер Тъкс Карт не е блокиран от защитна стена." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Любими" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Заключено: завърши повече предизвикателства, за да получиш достъп!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Случайна арена" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d арена е недостъпна в самостоятелен режим на игра." -msgstr[1] "%d арени са недостъпни в самостоятелен режим на игра." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Принос от Launchpad:\nBenau, 2018-2019\nDawid Gan\nSvetoslav Stefanov\nПринос от Трансифекс:\nЛюбомир Василев" @@ -4437,7 +4630,7 @@ msgstr "Събрани банани" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Поднасяне" @@ -4540,7 +4733,7 @@ msgstr "Завършени ловувания на яйца" msgid " (official tracks matching the goal)" msgstr "(официални писти, отговарящи на целта)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4548,91 +4741,95 @@ msgid "" msgstr "Новите контролери ще се появят автоматично в списъка, когато ги включите към това устройство.\n\nЗа да добавите клавиатурна настройка, може да използвате бутона отдолу, НО имайте предвид, че повечето клавиатури поддържат ограничен брой натиснати едновременно клавиши, така че не са подходящи за игра с повече хора. (Но можете да свържете повече от една клавиатура към това устройство. Запомнете, че дори и по този начин, всеки играч трябва да използва различни клавиши.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Добавяне на Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Добавяне на клавиатурна конфигурация" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Обновяване" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Версия: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "отличена" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Размер: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Трябва да си вписан(а), за да оцениш тази добавка." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Съжаляваме, свалянето на добавката беше неуспешно" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Имаше проблем при инсталирането на добавката „%s“." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Нов опит" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Имаше проблем при премахването на добавката „%s“." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Свалянето на фона приключи." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Сваляне на фона" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Свалянето на фона вече е започнало." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Текущата парола е грешна." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Дължината на паролата трябва да бъде между 8 и 30 знака!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Паролите не съвпадат!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Проверка на информацията" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Паролата бе сменена успешно." @@ -4653,67 +4850,97 @@ msgstr "Не се поддържат резолюции, по-малки от 10 #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Следване с дрон" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Персонализирани" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Изключено" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Само на важните" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Много ниско" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Ниско" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Среден" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Високо" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Много високо" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ултра" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4721,7 +4948,7 @@ msgid "" msgstr "Супер Тъкс Карт ще свали целите големи файлове (включително текстури с високо качество и музика). Ако нямаш безжична връзка с Интернет, ще се използват мобилните данни." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4738,101 +4965,102 @@ msgstr "Въведи адреса на сървъра и (ако е нужно) msgid "Invalid server address: %s." msgstr "Неправилен адрес на сървър: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Наобратно" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Трудност" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Обиколки" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Време" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Количка" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Потребител" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Версия" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Не" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Писта" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Най-добрите %d резултата" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Брой колички: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Целево време: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Обиколки: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Наобратно: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Празно)" @@ -4920,33 +5148,41 @@ msgid "Press any key..." msgstr "Натисни произволен клавиш…" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Писането на съобщения е изключено. Може да бъде включено от настройките." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Назад към теста на производителността" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Изход от теста на производителността" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Обратно към битката" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Нова игра" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Рестартиране на битката" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Изход от битката" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Ново състезание" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Изход от състезанието" @@ -4962,11 +5198,11 @@ msgstr "%s все още няма ранг." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s е номер %d в класацията, с резултат %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Потребителското име и/или е-пощата е грешна." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4988,7 +5224,7 @@ msgstr "Преиграване с призрак" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Обиколки: %i" @@ -5001,21 +5237,21 @@ msgstr "Вид: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Нужен ранг: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Нужно време: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Нежни точки азот: %i" @@ -5028,54 +5264,54 @@ msgstr "Брой колички, управлявани от ИИ: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Режим на битка" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Вид футболна игра" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Местонахождение на играча: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Текуща писта: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Ранг" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Играч" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Резултати" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Изиграно време" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Премахване от запазените" @@ -5088,74 +5324,74 @@ msgid "No player available for connecting to server." msgstr "Няма наличен играч за свързване със сървъра." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Потребителско име: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Отказ от заявката" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Днес" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Поканата за приятелство беше изпратена!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Поканата за приятелство беше приета!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Поканата за приятелство беше отказана!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Приятелят е премахнат!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Поканата за приятелство беше отменена!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Обработване" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Получаване на последния глас" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Можеш да промениш предишната си оценка като щракнеш върху звездите по-долу." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Все още не си гласувал(а) за тази добавка. Избери оценката си като щракнеш върху звездите по-долу" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Гласуването беше успешно! Вече може да затвориш прозореца." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Изпращане на гласа" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Случайна писта" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5184,7 +5420,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Възникна грешка при опита за запазване на Голямата награда." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Избери писта" @@ -5228,12 +5464,12 @@ msgstr "Ти отключи пистата %0" msgid "You unlocked grand prix %0" msgstr "Ти отключи Голямата награда %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Писта" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5254,19 +5490,19 @@ msgstr "Моля, въведи името на Голямата награда" msgid "Please select a Grand Prix" msgstr "Моля, избери Голяма награда" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Потребителско" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Името е празно." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Вече съществува Голяма награда с това име." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Името е твърде дълго." @@ -5275,19 +5511,19 @@ msgstr "Името е твърде дълго." msgid "Better luck next time!" msgstr "Повече късмет следващия път!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Ти завърши предизвикателство!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Ти спечели Голямата награда!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Ти завърши Голямата награда!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Брой колички" @@ -5300,110 +5536,125 @@ msgstr "Наистина ли искаш да премахнеш този зап msgid "Are you sure you want to remove all of your high scores?" msgstr "Наистина ли искаш да премахнеш всички свои най-добри резултати?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Любимо" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Леки" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Тежки" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Свържи клавиатура или контролер, за да играете на разделен екран" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Случайна количка" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Заключена" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Всички играчи:\nНатиснете бутона „Избиране“, за да се присъедините към играта" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Искаш ли да изиграеш обучението на играта?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Не може да играеш по Интернет без достъп до него. Ако искаш да играеш по Интернет, отиди в настройките и включи „Свързване с Интернет“." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Не може да сваляш добавки без достъп до Интернет. Ако искаш да сваляш добавки, отиди в настройките и включи „Свързване с Интернет“." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Не може да сваляш добавки без достъп до Интернет. Ако искаш да сваляш добавки, отиди в настройките и включи „Свързване с Интернет“.\n\nНо може да изтриеш вече свалените добавки." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Функционалността за добавките в момента е изключена от настройките" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Моля, изчакай докато се заредят добавките" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Наистина ли искаш да излезеш от играта?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Създаване на локален сървър" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Сървърът на %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Брой писти в Голямата награда" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Дължината на името трябва да бъде между 4 и 30 знака!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "В паролата има непозволени знаци!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Готов" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Присъединяване веднага" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Наблюдаване" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Инсталиране на добавката" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5411,7 +5662,7 @@ msgstr "Моля, изчакай края на текущата игра (%s) П #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Моля, изчакай да завърши текущата игра. Очаквано оставащо време: %s." @@ -5419,24 +5670,24 @@ msgstr "Моля, изчакай да завърши текущата игра. #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Моля, изчакай края на текущата игра (%s). Предполагаем напредък: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Моля, изчакай да завърши текущата игра. Предполагаем напредък: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Моля, изчакай да завърши текущата игра." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5445,7 +5696,7 @@ msgstr[1] "Играта ще започне, ако има повече от %d #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5454,96 +5705,108 @@ msgid_plural "" msgstr[0] "Започва след %d секунда, или когато всички натиснат бутона, че са готови." msgstr[1] "Започва след %d секунди, или когато всички натиснат бутона, че са готови." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Свързване със сървъра %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Търсене на сървър за бърза игра" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Оставащо време: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Цели" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Получаване на постиженията" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Профилът на %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "От" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Състояние" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Получаване на приятелите" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Нова покана" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "В изчакване" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Извън линия" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Въведи новата е-поща по-долу" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Дължината на новата е-поща трябва да бъде между 5 и 254 знака!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Новата е-поща е грешна!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "Е-пощата е променена!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Е-пощата не може да бъде променена: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Новини от блога на СТК" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Дата" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "В момента няма новини." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Трябва да си вписан(а), за да играеш в глобалната мрежа. Щракни върху потребителското си име по-горе." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Търсене" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Изход от играта" @@ -5621,34 +5884,34 @@ msgid "Distance (km)" msgstr "Разстояние (км)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Неизвестно" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Няма засечена поддръжка на IPv4. Възможно е да не можеш да се свържеш с нито един сървър." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Няма засечена поддръжка на IPv6. Възможно е да не можеш да се свържеш с нито един сървър." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Няма налични сървъри." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Получаване на сървърите" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Запазени сървъри" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5656,149 +5919,149 @@ msgstr "Ако по-голямата част от играчите избера #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Случайни места на предметите" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Брой голове за победа" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Каране наобратно" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Заключена: завърши повече предизвикателства, за да получиш достъп!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Действие" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Бутон" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Забраняване на устройството" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Разрешаване на устройството" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Включване на настройката" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Бутони за игра" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Бутони за менюто" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Завиване наляво" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Завиване надясно" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Ускоряване" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Спирачка / Назад" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Стрелба" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Азот" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Поглеждане назад" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Освобождаване" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Пауза" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Нагоре" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Надолу" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Наляво" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Надясно" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Select" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Отказ/Назад" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Синият цвят означава, че бутонът вече се използва в друга конфигурация" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Червеният цвят означава, че бутонът вече се използва в тази конфигурация" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5806,17 +6069,27 @@ msgid "" msgstr "Внимание: Не е препоръчително да се използва клавишът Шифт, тъй като когато той е натиснат, повечето клавиши извеждат друг символ, така че те няма да работят." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Наистина ли искаш да изтриеш завинаги тази конфигурация?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Въведи име за конфигурацията или го остави празно, при което ще се върне стойността по подразбиране." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Вертикално" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Хоризонтално" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5824,89 +6097,74 @@ msgstr "В режима на мрежова игра, играчите мога #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Инсталиране на големите файлове на играта" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Настина ли искаш да се деинсталират големите файлове на играта?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Клавиатура %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Сензорно устройство" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Докосни устройство, за да го настроиш" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Системен език" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Долу вляво" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "Отдясно" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Скрита" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Центрирана" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Вертикално" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Хоризонтално" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Много малък" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Малък" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Среден" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Голям" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Много голям" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5916,128 +6174,133 @@ msgid "" msgstr "Режимът на скоростно изиграване може да бъде включен, само ако играта не е била затваряне след стартирането на режима на историята.\n\nЗатварянето на играта преди завършване на режима на историята нулира времето.\n\nАко искате да използвате режима на скоростно изиграване, трябва да си създадете нов профил." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Вертикална синхронизация" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Вертикалната синхронизация кара графичната карта да\nпраща нов кадър към монитора едва когато той е готов\nда го покаже." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Вертикалната синхронизация няма да работи, ако драйверите не я поддържат." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Ефекти с частици: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Анимирани персонажи: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Динамично осветление: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Разсейване на светлината: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Заглаждане на ръбовете: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Околно затъмнение: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Сенки: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Сенки: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Проникване на светлината: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Греене (контури): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Светлинни снопи: %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Качество на изчертаните изображения %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Детайли на формите: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Размазване на движението: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Дълбочина на полето: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Достъпът до Интернет е забранен. Искаш ли да го включиш?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Трябва да въведеш парола." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Излизане от „%s“" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Влизане като „%s“" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Единственият играч не може да бъде изтрит." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Наистина ли искаш да изтриеш играча „%s“ ?" @@ -6065,7 +6328,7 @@ msgstr "ГОЛ!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Изчакване на останалите" @@ -6100,7 +6363,7 @@ msgstr "Следвай водача!" msgid "Top %i" msgstr "Най-добрите %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Предизвикателството не беше изпълнено" @@ -6124,102 +6387,199 @@ msgstr "Натисни иконката с подиума, за да започ msgid "Press fire to start the challenge" msgstr "Натисни ОГЪН, за да започнеш предизвикателството" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Назад към графичните настроки" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Запазване на резултатите от теста" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Назад към основното меню" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Напускане на сървъра" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Напускане на Голямата награда" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Рестартиране" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Назад към избора на предизвикателство" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Състезаване срещу новия призрачен запис" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Назад към менюто" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Наистина ли искаш да напуснеш Голямата награда?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Докладът за производителността е запазен в „%s“." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Червеният отбор печели" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Синият отбор печели" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Равен резултат" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Отстранен/а след %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Отстранен/а" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(автогол)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Писта %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Напредък в Голямата награда:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Класиране" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Най-добра обиколка: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "от %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Ти завърши предизвикателството!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Ти не успя да завършиш предизвикателството!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Изпълнени изисквания на Супер Тъкс" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Резултати от теста на производителността" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Продължителност на теста: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Брой кадри: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "Постоянни кадри/сек: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "Предимно постоянни кадри/сек: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "Типични кадри/сек: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Хоризонтална разделителна способност: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Хоризонтална разделителна способност: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Динамично осветление: ВКЛ" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Динамично осветление: ИЗКЛ" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Разделителна способност на изчертаването: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Заглаждане на ръбовете: ВКЛ" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Заглаждане на ръбовете: ИЗКЛ" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Осветяване чрез изображения: ИЗКЛ" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Осветяване чрез изображения: ВКЛ" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Околно затъмнение: ВКЛ" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Околно затъмнение: ИЗКЛ" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Разделителна способност на сенките: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Всичко е позволено, така че събирай предмети и ги използвай умно!" @@ -6260,28 +6620,28 @@ msgstr "Натисни иконката с червена или синя фут #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Пистата е създадена от %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Максимален брой играчи: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Брой колички от червения отбор, управлявани от ИИ" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Не можеш да играеш състезанията за тази Голяма награда, защото тя включва писти, които са заключени!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Заключена!" @@ -6303,10 +6663,12 @@ msgid "%d/%m/%Y" msgstr "%d.%m.%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Завърши още предизвикателства, за да отключиш голямата врата!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6315,41 +6677,48 @@ msgid "" msgstr "Трябват ти повече точки, за да\nвлезеш в това предизвикателство!\nПровери малката карта за\nналичните предизвикателства." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Давай газ с <%s> и завивай с <%s> и <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Давай газ като докоснеш горната част на волана, и завивай с плъзгане наляво и надясно." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Давай газ като движиш елемента за ускорение нагоре, и завивай с накланяне на устройството." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Давай газ като движиш елемента за ускорение нагоре, и завивай със завъртане на устройството." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Събирай подаръци и стреляй с оръжието с <%s>, за да отнесеш тези кутии!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Събирай подаръци и стреляй като натиснеш иконката с топка за боулинг, за да отнесеш тези кутии!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6357,34 +6726,41 @@ msgid "" msgstr "Натисни <%s>, за да погледнеш назад.\nСтреляй с оръжието с <%s>, докато натискаш <%s>, за да стреляш назад!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Натисни иконката с огледало, за да погледнеш назад.\nСтреляй с оръжието назад, като задържиш иконката с огледалото и след това плъзнеш към иконката с топка за боулинг!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Използвай събрания азот с <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Използвай събрания азот като натиснеш иконката с азота" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Събирай бутилки с азот (ще ги използваме след завоя)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Опа! Когато си загазил, натисни <%s>, за да се спасиш." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Опа! Когато си загазил, натисни иконката с птица, за да се спасиш." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6392,24 +6768,27 @@ msgid "" msgstr "Дай газ и натисни <%s>, докато завиваш, за да поднесеш.\nЕдно кратко поднасяне може да ти помогне да завиеш по-бързо на някой остър завой." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Дай газ и натисни иконката за поднасяне, докато завиваш, за да поднесеш.\nЕдно кратко поднасяне може да ти помогне да завиеш по-бързо на някой остър завой." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Ако успееш да поднесете за няколко секунди, ще получиш допълнително ускорение!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Вече си готов да се състезаваш. Успех!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "3-измерна състезателна игра с колички, с отворен код" @@ -6419,7 +6798,7 @@ msgstr "3-измерна състезателна игра с колички, с msgid "tux;game;race;" msgstr "тъкс;кола;коли;количка;колички;състезание;състезания" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6427,7 +6806,7 @@ msgid "" "for all ages." msgstr "Колички. Азот. Екшън! Супер Тъкс Карт е 3-измерна състезателна игра с отворен код, която включва множество персонажи, писти и режими на игра. Целта ни е да създадем игра, която е повече забавна, отколкото реалистична – такава, която предоставя приятно изживяване за хора от всички възрасти." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6436,7 +6815,7 @@ msgid "" "your opponents." msgstr "Разполагаме с разнообразни писти с най-различни тематики – карай под водата, из полята, джунглите и дори в космоса! Дай най-доброто от себе си, избягвай другите колички и в никакъв случай не яж бананите! Пази се от топките за боулинг, буталата, дъвките и кексчетата, които противниците ти ще се опитат да хвърлят по теб." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6445,27 +6824,27 @@ msgid "" "your racing skills!" msgstr "Можеш да изиграеш единично състезание срещу други колички, да се съревноваваш в някой от турнирите за Голямата награда, да се опиташ да победиш най-доброто време сам, да играеш бойния режим срещу компютъра или приятелите си, и още! Ако имаш нужда от по-голямо предизвикателство, можеш да се състезаваш по Интернет срещу други играчи от целия свят и да им докажеш, че си най-добрият!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "В тази игра няма реклами." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Това е нестабилна версия на Супер Тъкс Карт, която съдържа последните подобрения. Тя се използва основно за тестване, с цел да направим стабилната версия на СТК колкото е възможно по-добра." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Тази версия може да бъде инсталирана на устройството едновременно със стабилната." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Ако се притеснявате за стабилността на приложението, използвайте стабилната версия: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "Екипът на Супар Тъкс Карт" diff --git a/data/po/ca.po b/data/po/ca.po index b3561f16eef..cbe6fe2b167 100644 --- a/data/po/ca.po +++ b/data/po/ca.po @@ -6,14 +6,14 @@ # Benau, 2018 # Benau, 2018 # Marc Coll Carrillo, 2012 -# Marc Coll Carrillo , 2015-2023 +# Marc Coll Carrillo , 2015-2024 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Marc Coll Carrillo , 2015-2023\n" +"Last-Translator: Marc Coll Carrillo , 2015-2024\n" "Language-Team: Catalan (http://app.transifex.com/supertuxkart/supertuxkart/language/ca/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -170,7 +170,7 @@ msgstr "A la fi del món" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Tornar" @@ -192,7 +192,7 @@ msgstr "Selecciona el tipus de controlador que prefereixis" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Acceleròmetre" @@ -206,13 +206,13 @@ msgstr "Acceleròmetre" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Giroscopi" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Volant" @@ -243,35 +243,37 @@ msgstr "Configuració del dispositiu tàctil" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "General" @@ -339,30 +341,33 @@ msgstr "Restaura la configuració predeterminada" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Cancel·la" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Sí" @@ -540,9 +545,9 @@ msgstr "Unir-se" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -603,7 +608,7 @@ msgstr "Objectiu" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Progrés" @@ -638,7 +643,7 @@ msgstr "Envia" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Tornar a la cursa" @@ -655,7 +660,7 @@ msgstr "Tornar al rebedor" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Reiniciar la cursa" @@ -719,12 +724,12 @@ msgstr "Introdueix el nom d'usuari i l'adreça de correu electrònic que vas pro #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Nom d'usuari" @@ -765,7 +770,7 @@ msgstr "Dificultat" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Novell" @@ -777,7 +782,7 @@ msgstr "Novell" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Intermedi" @@ -789,7 +794,7 @@ msgstr "Intermedi" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Expert" @@ -801,7 +806,7 @@ msgstr "Expert" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -809,8 +814,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Mode de joc" @@ -821,8 +826,8 @@ msgstr "Mode de joc" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Cursa normal" @@ -835,7 +840,7 @@ msgstr "Cursa normal" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Contra rellotge" @@ -843,7 +848,8 @@ msgstr "Contra rellotge" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Batalla" @@ -852,24 +858,24 @@ msgstr "Batalla" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Futbol" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Contrasenya" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Afegeix a la llista de preferits" @@ -880,7 +886,7 @@ msgstr "Afegeix jugador" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Nom" @@ -974,6 +980,50 @@ msgstr "Assignar a la tecla ESC" msgid "Assign nothing" msgstr "No assignis res" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Recomana'm la configuració de vídeo" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "La configuració recomanada serà vàlida per a la resolució actual" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Què hauria de prioritzar la configuració?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Rendiment" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Equilibri entre rendiment i qualitat gràfica" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Qualitat gràfica" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Estalviar energia" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "T'agraden els efectes gràfics que provoquen difuminació?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Començar el test" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -988,11 +1038,11 @@ msgstr "Configuració de la cursa" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Continua" @@ -1033,10 +1083,15 @@ msgstr "Arenes" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Instal·lat" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Editar les arenes preferides" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1046,20 +1101,20 @@ msgstr "Instal·lat" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Estàndard" @@ -1070,12 +1125,12 @@ msgstr "Estàndard" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Complements" @@ -1089,27 +1144,28 @@ msgstr "Complements" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Tots" @@ -1148,9 +1204,9 @@ msgstr "Mou cap avall" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Afegeix" @@ -1187,7 +1243,7 @@ msgstr "Selecció de la repetició fantasma" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "A la recerca dels ous perduts" @@ -1234,10 +1290,10 @@ msgstr "A l'inrevés" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Màxim de temps (min.)" @@ -1269,9 +1325,9 @@ msgstr "Copia" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1282,80 +1338,80 @@ msgstr "Canvia el nom" msgid "Save Grand Prix" msgstr "Desa el campionat" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Ajuda del SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Modes de joc" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Millores" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Plàtans" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1363,56 +1419,57 @@ msgstr "Plàtans" msgid "Story Mode" msgstr "Història" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Classes de karts" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Multijugador" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Comença el tutorial" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Recull les caixes blaves, et donaran millores. " -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Evita els plàtans!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1420,14 +1477,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Recollir nitro et permet obtenir augments de velocitat quan vulguis prement la tecla o el botó corresponent. Pots veure el teu nivell actual de nitro a l'indicador que hi ha a la part inferior dreta de la pantalla." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Si veus un botó amb un cadenat com aquest, cal que completis un repte per desbloquejar-lo." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1436,34 +1493,34 @@ msgid "" "carefully before!" msgstr "Pots derrapar prement una tecla o botó especial. Els derrapatges curts i seguits t'ajuden a agafar corbes tancades. Els derrapatges mitjans faran augmentar la teva velocitat, i els llargs encara més. No pots deixar de girar quan derrapes, així que orienta bé el teu kart abans!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Pots obtenir una millor arrencada prement el botó d'accelerar en el \"Llestos!\", abans de començar la cursa." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Les assignacions de tecles actuals es poden veure/modificar al menú d'opcions" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart té diferents modes de joc:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Cursa normal: Tots els cops estan permesos, o sigui que agafa millores i fes-ne un bon ús!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Contra rellotge: no conté millores, o sigui que només compten les teves habilitats al volant!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1471,7 +1528,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Segueix al líder: Corre per quedar segon, doncs el darrer kart serà desqualificat cada vegada que el comptador arribi a zero. Compte: anar per davant del líder també t'eliminarà!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1481,30 +1538,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Hi ha tres tipus de modes de batalla: A la batalla a 3 cops cal que ataquis als altres amb armes fins que perdin totes les seves vides. A la batalla per lliure, el jugador que colpegi més als altres guanyarà un cop s'arribi a un cert objectiu o límit de temps. En el mode de capturar la bandera, el teu equip ha de portar la bandera de l'altre equip a la vostra base, sempre que la vostra bandera no hagi estat capturada per l'altre equip." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Futbol: Fes servir el teu kart per ficar la pilota la porteria." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "A la recerca dels ous perduts: explora circuits per trobar tots els ous amagats" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Repetició fantasma: Corre contra repeticions fantasma en mode contra rellotge o recerca dels ous perduts, i grava el teu propi!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Competició de voltes: Completa tantes voltes com sigui possible en un cert temps." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1513,93 +1570,93 @@ msgid "" "wins the cup." msgstr "* La majoria d'aquests modes de joc també es poden jugar com un campionat: en comptes de jugar una sola cursa, s'en juguen vàries seguides. A millor posició, més punts. Al final, el jugador amb més punts guanya la copa." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Per ajudar-te a guanyar, hi ha algunes millores que pots recollir:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Xiclet - protegeix-te amb un escut, o fes-lo servir mentre mires enrere per deixar una taca rosa enganxosa darrera teu." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Turbo - et donarà un gran increment de velocitat. Però procura no perdre el control del teu kart!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Pastís - llençat contra el rival més proper, millor a poca distància i en rectes llargues. També afecta a altres karts a prop de l'explosió." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Desembussador - llença'l cap endavant per estirar un oponent pel darrera, o llença'l mentre mires cap enrere per fer que un d'ells perdi visió." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Bola de bitlles - va recte fins que topa amb alguna cosa, rebota a les parets. Si mires darrere teu, serà llençada cap enrere." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Paracaigudes - frena tots els karts millor posicionats." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Intercanviador - les caixes es transformen en plàtans, les ampolles de nitro en xiclets, i viceversa durant un curt període de temps." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Pilota de bàsquet - rebota empaitant el líder, i pot esclafar i frenar karts pel camí." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Matamosques - esclafarà els karts al teu voltant, frenant-los. També es pot fer servir per eliminar paracaigudes i bombes." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Agafar un plàtan pot provocar que una de les següents coses se t'enganxi al kart:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Àncora - frena el kart de cop." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Paracaigudes - frena el kart de manera més progressiva que l'àncora. Quan més ràpid vas, més et frena." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bomba - detona al cap d'una estona, fent saltar el kart pels aires. Xoca amb un altre kart per passar-li la bomba." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "El malvat Nolok ha capturat a en Gnu! Aquí tens uns consells per ajudar-te:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1608,7 +1665,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Aquesta icona al mapa en miniatura mostra els reptes disponibles que encara no has completat. A la part superior dreta de la pantalla també et diu quants punts tens actualment. Completa tants reptes com sigui possible, i Nolok acceptarà competir amb tu. Guanya per alliberar a en Gnu!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1616,20 +1673,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Quan completes un repte, reps una copa. Cada copa val varis punts. Com més difícil sigui el repte que hagis completat, millor serà la copa i més punts valdrà." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Quan obtinguis el nombre de punts indicat a sota d'aquesta icona, rebràs un regal sorpresa. N'hi ha varis per recollir." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "No tots els karts es condueixen igual! Pertanyen a classes amb vàries diferències:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1637,7 +1694,7 @@ msgid "" " resistant to explosions." msgstr "Massa - hi ha tres classes de kart, depenent de la seva massa: lleuger, mitjà i pesat. Als karts més pesats no els afecten tant els paracaigudes, i són més resistents a les explosions." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1645,7 +1702,7 @@ msgid "" " especially at low speeds." msgstr "Acceleració: especialment útil a l'inici, després d'un accident o en circuits amb moltes corbes tancades. Com més lleuger sigui el kart, més ràpid accelerarà, especialment a baixa velocitat." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1653,14 +1710,14 @@ msgid "" " top speed." msgstr "Velocitat màxima: com més alta sigui, més ràpid pot anar el kart. Especialment útil en circuits amb moltes rectes i corbes suaus. Els karts més pesats tenen una velocitat punta més alta." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Eficiència de nitro: com més alta sigui, més velocitat podràs obtenir d'una ampolla de nitro. Com més lleuger sigui el kart, major serà la seva eficiència de nitro." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1668,12 +1725,12 @@ msgid "" "easier it is." msgstr "Si segueixes de prop un altre kart durant uns segons, obtindràs un extra de velocitat de rebuf quan l'adelantis. Com més lleuger sigui el kart, més fàcil és." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart es pot jugar en mode multijugador en línia...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1683,7 +1740,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Primer, selecciona la icona 'en línia' del menú principal. Tria o bé xarxa local, o bé global (cal tenir habilitat l'accés a Internet a les opcions). Després, pots o bé crear el teu propi servidor amb opcions a mida, o bé buscar entre la llista de servidors existents per unir-te. Alguns d'ells són servidors recomanats amb curses opcionals amb classificacions." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1693,12 +1750,12 @@ msgid "" "players and the server." msgstr "Un cop estiguis en un servidor, una cursa començarà tan bon punt el seu propietari (simbolitzat amb la corona) ho decideixi. Els servidors oficials poden començar curses automàticament només quan hi ha suficients jugadors. Aleshores, podràs triar el teu kart i votar pel proper circuit on córrer. Un circuit de complement només es permet si existeix a tots els jugadors que s'han unit i al servidor." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... o al mateix dispositiu:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1708,7 +1765,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Primer, necessitareu diferents dispositius d'entrada. Feu servir la pantalla de configuració de dispositius d'entrada per configurar-los. Tenir múltiples comandaments o joysticks és lo ideal: als teclats cada jugador necessitarà un joc de tecles diferent, i la majoria de teclats no són adequats per al mode multijugador perquè no permeten moltes tecles pitjades alhora." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1728,7 +1785,7 @@ msgstr "Selecció de millors puntuacions" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Competició de voltes" @@ -1736,9 +1793,9 @@ msgstr "Competició de voltes" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Campionats" @@ -1749,6 +1806,20 @@ msgstr "Campionats" msgid "Choose a Kart" msgstr "Tria un kart" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Classe de kart" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Editar els karts preferits" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1762,11 +1833,11 @@ msgstr "Multijugador en pantalla dividida" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "En línia" @@ -1783,7 +1854,7 @@ msgstr "Tutorial" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Millors puntuacions" @@ -1791,7 +1862,7 @@ msgstr "Millors puntuacions" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Assoliments" @@ -1845,30 +1916,30 @@ msgstr "Troba un servidor" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Crea un servidor" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Rebedor" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Configuració" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Comença la cursa" @@ -1894,9 +1965,9 @@ msgstr "Introdueix l'adreça del servidor" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "El teu perfil" @@ -1914,7 +1985,7 @@ msgstr "Classificacions del jugador" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Amics" @@ -1939,7 +2010,7 @@ msgstr "Partida ràpida" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Paràmetres del compte" @@ -1989,8 +2060,8 @@ msgid "Online Username" msgstr "Nom d'usuari en línia" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Reinicia la contrasenya" @@ -2003,7 +2074,7 @@ msgid "" msgstr "Pots jugar sense crear un compte en línia seleccionant un compte fora de línia. Però aleshores no podràs connectar-te amb amics, votar complements, etc. Llegeix la nostra declaració de privacitat a https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Selecció del servidor" @@ -2021,339 +2092,409 @@ msgstr "Fes servir connexió IPv6" msgid "User search" msgstr "Cerca usuaris" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Opcions del SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Pantalla" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Gràfics" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "So" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Interfície" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Jugadors" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Controls" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Idioma" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Música" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Habilitat" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Volum" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Efectes de so" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Esborra la configuració" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Deshabilita la configuració" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Tornar a la llista de dispositius" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Reanomena la configuració" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Activar la retroalimentació de força (si està suportada)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Resolució" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Pantalla completa" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Recorda la posició de la finestra" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Aplica la nova resolució" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Disposició de la pantalla dividida" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Opcions d'Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Mostra sempre la pantalla d'inici de sessió" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Connectar-se a Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Habilita el xat en línia" +msgid "Enable chatting in online lobbies" +msgstr "Habilita el xat al rebedor de les partides en xarxa" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" +msgid "Enable chatting in online matches" msgstr "Habilita el xat a les partides en xarxa" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Opcions diverses" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Habilita les limitacions per jugador" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Desinstal·lar els recursos complets" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Prem intro o fes doble clic sobre un dispositiu per configurar-lo" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Afegeix un dispositiu" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* La configuració a emprar dependrà de quina tecla 'Seleccionar' es premi per unir-se a la partida." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Aparença" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Mapa en miniatura" +msgid "Skin variant" +msgstr "Variant de l'aparença" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Disposició de la pantalla dividida" +msgid "Minimap" +msgstr "Mapa en miniatura" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Mida de la font" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Càmera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "A mida..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Mostrar FPS" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Mostra les millores dels altres karts" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Habilita el temporitzador en el mode història" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Habilita el temporitzador de speedrun" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Resolució de renderització" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Nivell d'efectes gràfics" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Nivell de difuminació" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "FPS màxims" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Configuració a mida..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Resolució" +msgid "Performance tests" +msgstr "Tests de rendiment" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Pantalla completa" +msgid "Performance test of the current settings" +msgstr "Rendiment de la configuració actual" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Recorda la posició de la finestra" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Recorda la contrasenya" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Aplica la nova resolució" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Esborra" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Color del kart" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2380,15 +2521,15 @@ msgstr "Equip blau" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Nombre de voltes" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Karts controlats per l'ordinador" @@ -2403,33 +2544,17 @@ msgstr "Nombre de karts blaus controlats per l'ordinador" msgid "Random Grand Prix" msgstr "Campionat aleatori" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Editar els circuits preferits" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Inicia una sessió" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Recorda la contrasenya" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Esborra" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Color del kart" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "L'aparença de la interfície es pot canviar des de les opcions d'interfície d'usuari." @@ -2548,238 +2673,306 @@ msgid "" msgstr "No entorpeixis a un company d'equip que tingui la pilota, tot i que pot intentar colpejar als oponents que intentin impedir que marqui un gol." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Abisme antediluvià" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Senyal extraterrestre" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "El laberint de l'antic Coliseu" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Candela City" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Illa de batalla" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Selva negra" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Cova X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Temple del cacau" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Camp de moresc" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Fort Magma" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Illa Gran Paradiso" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Caiguda pel forat" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Camp de futbol gelat" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Què passa, petits hippys? El vostre gran líder Gnu ha desaparegut?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Oh, sí! Veuràs, ara mateix es troba al meu castell, i serà servit com a sopar..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Però sóc una criatura justa, així que us oferiré un tracte." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Si podeu guanyar-me en una cursa, deixaré anar al vell xaruc." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " Però vosaltres, patètics gamarussos, mai sereu capaços de guanyar-me a mi, el rei dels karts!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Estadi de Les Dunes" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Estadi de futbol Las Dunas" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Al voltant del far" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "La vella mina" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oasi" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Classe de mates de l'Oliver" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Parc de les carbasses" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Mansió Ravenbridge" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Arenes movedisses" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "L'estany de Nessie" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Resort nòrdic" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Pic nevat" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Camp de futbol" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "L'estadi" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Enterprise" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Temple" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Illa volcànica" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Jardí zen" @@ -2788,11 +2981,11 @@ msgstr "Jardí zen" msgid "Completed achievement \"%s\"." msgstr "Has completat l'assoliment '%s'." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "No s'ha pogut connectar al servidor de complements de SuperTuxKart." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Error descarregant notícies: '%s'." @@ -2858,7 +3051,7 @@ msgid "New kart '%s' now available" msgstr "Nou kart '%s' ja disponible" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2890,32 +3083,32 @@ msgid "" "created." msgstr "El teu fitxer de configuració era massa antic, així que s'ha esborrat i s'en crearà un de nou." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "S'ha iniciat la gravació de video" -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Video desat a \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Codificació en curs:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Consell: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Carregant" @@ -2937,19 +3130,18 @@ msgstr "Eficiència de nitro" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (limitat)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s està llest" @@ -3423,21 +3615,21 @@ msgid "Axis %d" msgstr "Eix %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Botó %d del comandament" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Botó %d del ratolí" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Eix %d %s del ratolí" @@ -3609,26 +3801,30 @@ msgstr "Pots tenir 3 vides com a molt!" msgid "+1 life." msgstr "+1 vida." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Has estat massa lent!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Has acabat la cursa!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Has guanyat la cursa!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Has acabat la cursa en %dª posició!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s ha abandonat la partida." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3637,16 +3833,16 @@ msgid "" "Internet\")." msgstr "El SuperTuxKart pot connectar-se a un servidor per descarregar complements i notificar-te sobre actualitzacions. Llegeix la nostra política de privacitat a https://supertuxkart.net/Privacy. T'agradaria habilitar aquesta característica? (Per canviar aquest paràmetre més endavant, vés a les opcions, selecciona la pestanya \"General\", i edita els paràmetres \"Connectar-se a Internet\")." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "La resolució de la teva pantalla és massa baixa per executar el STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "La versió del teu controlador és massa antiga. Si us plau, instal·la la darrera versió." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3654,38 +3850,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "El treu controlador gràfic sembla ser molt antic. Si us plau, comprova si hia una actualització disponible. SuperTuxKart recomana un controlador que admeti %s o millor. El joc probablement funcioni, però en un mode gràfic reduit." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "La connexió amb el servidor ha excedit el temps d'espera." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s té la bandera vermella!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "La bandera vermella ha tornat!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s té la bandera blava!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "La bandera blava ha tornat!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s ha capturat la bandera blava!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s ha capturat la bandera vermella!" @@ -3695,7 +3891,7 @@ msgstr "%s ha capturat la bandera vermella!" msgid "Eggs: %d / %d" msgstr "Ous: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Líder" @@ -3703,22 +3899,22 @@ msgstr "Líder" msgid "Final lap!" msgstr "Última volta!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Volta %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s per %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Nova volta ràpida" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "DIRECCIÓ CONTRÀRIA!" @@ -3732,194 +3928,194 @@ msgstr "%s ha marcat un gol!" msgid "Oops, %s made an own goal!" msgstr "Ups, %s ha marcat un gol en pròpia porta!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "S'ha engendrat %i kart de rodes de recanvi!" msgstr[1] "S'han engendrat %i karts de rodes de recanvi!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Estàs eliminat!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "'%s' ha estat eliminat" -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "El servidor s'ha tancat." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "T'han expulsat del servidor." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "T'han expulsat. El teu ping era massa alt." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "S'ha detectat una mala connexió de xarxa." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s s'ha desconnectat." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Fes clic al nom de l'usuari de la llista per gestionar el jugador i veure informació de la seva classificació." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Dificultat: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Màx. jugadors: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Mode de joc: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Límit de temps" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Límit de gols" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Tipus de partida de futbol: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Progrés del campionat: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Tots els jugadors s'han unit a l'equip blau o al vermell." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Ara ets el propietari del servidor." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Connexió rebutjada. El servidor està ocupat." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Connexió rebutjada. T'han expulsat del servidor." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Connexió rebutjada. La contrasenya del servidor no és correcta." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Connexió rebutjada. Les dades del joc són incompatibles." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Connexió rebutjada. El servidor està ple." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Connexió rebutjada. S'està connectant un jugador invàlid." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "No s'ha pogut iniciar la partida en xarxa." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "La partida s'ha acabat, ja no t'hi pots unir en directe ni observar-la." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "No queda lloc a l'arena - unir-se en directe es troba deshabilitat." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Només queda un jugador, tornant al rebedor." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "El propietari del servidor ha abandonat la partida." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Estaràs observant la propera partida." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s s'ha unit a l'equip vermell." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s s'ha unit a l'equip blau." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s s'ha unit a la partida." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3927,15 +4123,15 @@ msgid "" msgstr "Prem <%s> o <%s> per canviar de jugador, <%s> o <%s> per canviar la posició de la càmera." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "%s ha estat reportat." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3966,38 +4162,38 @@ msgstr "Contra rellotge (campionat)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Per lliure" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Captura la bandera" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s està en línia." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s i %s estan en línia." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s i %s estan en línia." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4005,19 +4201,19 @@ msgstr[0] "%d amic en línia." msgstr[1] "%d amics en línia." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s ara està al servidor \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "Tens %d petició d'amistat!" msgstr[1] "Tens %d peticions d'amistat!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Tens una nova petició d'amistat!" @@ -4046,12 +4242,12 @@ msgid "" msgstr "El fitxer de puntuacions era massa antic,\ntotes les puntuacions han estat esborrades." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Segueix al líder" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Batalla a 3 cops" @@ -4064,91 +4260,88 @@ msgstr "El fitxer incomplet de repetició no es desarà." msgid "Replay saved in \"%s\"." msgstr "Repetició desada a \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 setmana" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 setmanes" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 mes" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 mesos" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 mesos" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 mesos" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 any" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 anys" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Nom del complement" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Data d'actualització" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "No instal·lat" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s per %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Espera mentre s'actualitzen els complements" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "S'ha produït un error mentre es contactava amb el servidor de complements. Assegura't que estàs connectat a Internet i que el Supertuxkart no està bloquejat per un tallafocs" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Preferits" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Bloquejat: resol els reptes actius per accedir a més!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Arena aleatòria" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d arena no disponible amb un sol jugador." -msgstr[1] "%d arenes no disponibles amb un sol jugador." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nBenau, 2018\nMarc Coll Carrillo, 2012\nMarc Coll Carrillo, 2015-2022\nMarc Coll Carrillo, 2015-2021\nAljullu\nDawid Gan\nMarc Coll Carrillo\nSTK-team\nTae-Wong SEO\nVPablo" @@ -4436,7 +4629,7 @@ msgstr "Plàtans recollits" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Derrapar" @@ -4539,7 +4732,7 @@ msgstr "Recerques d'ous acabades" msgid " (official tracks matching the goal)" msgstr "(circuits oficials que encaixen amb l'objectiu)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4547,91 +4740,95 @@ msgid "" msgstr "Nous comandaments i joysticks apareixeran automàticament a la llista quan els connectis a aquest dispositiu.\n\nPer afegir una configuració de teclat pots fer servir el botó inferior, PERÒ tingues en compte que la majoria de teclats només permeten una limitada quantitat de tecles pitjades simultàniament, i per tant no són apropiats per als modes multijugador. (Tanmateix, pots connectar diferents teclats a l'ordinador. Recorda que tot i així tothom necessitarà un joc de tecles diferent)." #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Afegeix un Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Afegeix configuració de teclat" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Actualitza" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Versió: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "Destacats" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Mida: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Cal estar connectat per poder puntuar aquest complement." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "No s'ha pogut descarregar el complement" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Problemes instal·lant el complement '%s'." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Tornar-ho a provar" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Problemes eliminant el complement '%s'." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Descàrrega en segon pla completada." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Descàrrega en segon pla" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "La descàrrega en segon pla ja ha començat." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "La contrasenya actual no és vàlida" -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "La contrasenya ha de tenir entre 8 i 30 caràcters!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Les contrasenyes no coïncideixen!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "S'està validant la informació" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "La contrasenya s'ha canviat correctament." @@ -4652,67 +4849,97 @@ msgstr "Les resolucions més petites de 1024x768 o 1280x720 no estan suportades. #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Seguiment de dron" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "A mida" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Deshabilitat" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Només lo important" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Molt baix" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Baix" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Mitjana" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Alt" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Molt alt" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4720,7 +4947,7 @@ msgid "" msgstr "El SuperTuxKart descarregarà els recursos complets (inclosos textures d'alta qualitat i música) per a una millor experiència de joc. Això farà servir les teves dades mòbils si no tens una connexió wifi." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4737,101 +4964,102 @@ msgstr "Introdueix l'adreça del servidor opcionalment seguida per : i després msgid "Invalid server address: %s." msgstr "Adreça del servidor invàlida: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "A l'inrevés" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Dificultat" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Voltes" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Temps" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Kart" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Usuari" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Versió" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "No" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Circuit" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Les %d millors puntuacions" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Nombre de karts: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Objectiu de temps: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Voltes: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "A l'inrevés: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Buit)" @@ -4919,33 +5147,41 @@ msgid "Press any key..." msgstr "Prem qualsevol tecla" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "El xat està deshabilitat, activa'l des del menú d'opcions" -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Tornar al test de rendment" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Sortir del test de rendiment" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Tornar a la batalla" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Configurar una nova partida" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Reiniciar la batalla" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Sortir de la batalla" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Configurar una nova cursa" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Sortir de la cursa" @@ -4961,11 +5197,11 @@ msgstr "%s encara no té cap classificació." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s és el número %d de la classificació amb una puntuació de %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "El nom d'usuari i/o el correu electrònic no són vàlids." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4987,7 +5223,7 @@ msgstr "Cursa de repetició fantasma" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Voltes: %i" @@ -5000,21 +5236,21 @@ msgstr "Tipus: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Posició requerida: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Temps requerit: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Punts de nitro requerits: %i" @@ -5027,54 +5263,54 @@ msgstr "Karts controlats per l'ordinador: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Mode de batalla" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Tipus de partida de futbol" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Ubicació del servidor: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Circuit actual: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Classificació" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Jugador" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Puntuacions" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Temps jugat" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Elimina de la llista de preferits" @@ -5087,74 +5323,74 @@ msgid "No player available for connecting to server." msgstr "No hi ha cap jugador disponible per connectar-se al servidor." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Nom d'usuari: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Cancel·la la sol·licitud" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Avui" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "La petició d'amistat s'ha enviat!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "La petició d'amistat ha estat acceptada!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "La petició d'amistat s'ha rebutjat!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "S'ha eliminat l'amic!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "La petició d'amistat s'ha cancel·lat!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "S'està processant" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Obtenint el darrer vot" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Pots canviar la teva qualificació anterior fent clic a les estrelles d'aquí sota." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Encara no has votat per aquest complement. Selecciona la qualificació que desitgis fent clic a les estrelles inferiors" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "El vot s'ha enviat correctament! Ja pots tancar la finestra." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "S'està realitzant la votació" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Circuit aleatori" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5183,7 +5419,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "S'ha produït un error mentre s'intentava desar el teu campionat." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Selecciona un circuit" @@ -5227,12 +5463,12 @@ msgstr "Has desbloquejat el circuit %0" msgid "You unlocked grand prix %0" msgstr "Has desbloquejat el campionat %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Circuit" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5253,19 +5489,19 @@ msgstr "Introdueix el nom del campionat" msgid "Please select a Grand Prix" msgstr "Selecciona un campionat" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Definits per l'usuari" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "El nom és buit." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Ja existeix un altre campionat amb aquest nom." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "El nom és massa llarg." @@ -5274,19 +5510,19 @@ msgstr "El nom és massa llarg." msgid "Better luck next time!" msgstr "Més sort la propera vegada!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Has completat un repte!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Has guanyat el campionat!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Has completat el campionat!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Nombre de karts" @@ -5299,110 +5535,125 @@ msgstr "Segur que vols eliminar aquesta puntuació?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Segur que vols eliminar totes les teves millors puntuacions?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Preferit" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Lleuger" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Pesat" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Connecta un teclat o un comandament per jugar en pantalla dividida" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Kart aleatori" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Bloquejat" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Tothom:\nPremeu el botó 'Seleccionar' per unir-vos a la partida" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Vols jugar al tutorial del joc?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "No pots jugar en línia sense accés a Internet. Si vols jugar en línia, vés al menú d'opcions i selecciona \"Connectar-se a Internet\"." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "No pots descarregar complements sense accés a Internet. Si vols descarregar complements, vés al menú d'opcions i selecciona \"Connectar-se a Internet\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "No pots descarregar complements sense accés a Internet. Si vols descarregar complements, vés al menú d'opcions i selecciona \"Connectar-se a Internet\".\n\nPerò sí que pots eliminar complements ja descarregats." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "El mòdul de complements actualment es troba deshabilitat a la finestra d'opcions" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Espera mentre es carreguen els complements" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Segur que vols sortir del STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Crea un servidor local" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Servidor de %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Nº de circuits al campionat" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "El nom ha de tenir entre 4 i 30 caràcters!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Caràcters invàlids a la contrasenya!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Preparat" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Unir-se en directe" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Observar" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Instal·la el complement" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5410,7 +5661,7 @@ msgstr "Si us plau, espera't a que la partida actual (%s) s'acabi. Temps restant #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Si us plau, espera't a que acabi la partida actual. Temps restant estimat: %s." @@ -5418,24 +5669,24 @@ msgstr "Si us plau, espera't a que acabi la partida actual. Temps restant estima #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Si us plau, espera't a que la partida actual (%s) s'acabi. Progrés estimat: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Si us plau, espera't a que acabi la partida actual. Progrés estimat: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Si us plau, espera't a que acabi la partida actual." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5444,7 +5695,7 @@ msgstr[1] "La partida començarà si hi ha més de %d jugadors." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5453,96 +5704,108 @@ msgid_plural "" msgstr[0] "Començant en %d segon, o quan tothom hagi premut el botó 'Llestos'." msgstr[1] "Començant en %d segons, o quan tothom hagi premut el botó 'Preparat'." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Connectant al servidor %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Buscant un servidor de partides ràpides" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Temps restant: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Objectius" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Obtenint assoliments" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Perfil de %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Des de" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Estat" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Obtenint amics" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Nova petició" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Pendent" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Fora de línia" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Introdueix la nova adreça a sota" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "L'adreça ha de tenir entre 5 i 254 caràcters!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "La nova adreça no és vàlida!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "S'ha canviat l'adreça!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "No s'ha pogut canviar l'adreça: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Notícies del blog del STK" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Data" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Actualment no hi ha cap notícia disponible." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Has d'iniciar sessió per poder jugar a la xarxa global. Fes clic al teu nom d'usuari aquí dalt." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "S'està cercant" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Surt del joc" @@ -5620,34 +5883,34 @@ msgid "Distance (km)" msgstr "Distància (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Desconegut" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "No s'ha detectat IPv4. És posssible que no puguis unir-te a cap servidor." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "No s'ha detectat IPv6. És posssible que no puguis unir-te a cap servidor." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "No hi ha cap servidor disponible." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Obtenint servidors" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Servidors preferits" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5655,149 +5918,149 @@ msgstr "Si una majoria de jugadors selecciona el mateix circuit i la mateixa con #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Localització aleatòria dels elements" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Nombre de gols per guanyar" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Condueix a l'inrevés" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Bloquejat: resol els reptes actius per accedir-ne a més!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Acció" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Tecla assignada" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Deshabilita el dispositiu" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Habilita el dispositiu" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Habilita la configuració" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Tecles del joc" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Tecles del menú" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Gira a l'esquerra" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Gira a la dreta" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Accelera" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Fre / Marxa enrera" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Foc" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Mirar enrere" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Rescat" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Pausa" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Amunt" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Avall" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Esquerra" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Dreta" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Selecciona" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Cancel·lar/Tornar" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Un element blau indica un conflicte amb una altra configuració" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "Un element vermell indica un conflicte a la configuració actual" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5805,17 +6068,27 @@ msgid "" msgstr "Atenció: La tecla 'Majúscules' no és una tecla gaire recomanable. Quan es premi aquesta tecla deixaran de funcionar totes les tecles que continguin un caràcter diferent en majúscules." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Estàs segur que vols esborrar permanentment aquesta configuració?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Introdueix un nou nom per a la configuració. Deixa'l buit per revertir-lo al valor per defecte." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Vertical" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Horitzontal" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5823,89 +6096,74 @@ msgstr "En mode multijugador els jugadors poden seleccionar perfils limitats\n(m #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Instal·lar els recursos complets" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Estàs segur de que vols desinstal·lar els recursos complets?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Teclat %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Dispositiu tàctil" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Fes un toc sobre un dispositiu per configurar-lo" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Idioma del sistema" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "A baix a l'esquerra" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "Al costat dret" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Ocult" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Centrat" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Vertical" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Horitzontal" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Molt petita" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Petita" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Mitjana" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Gran" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Molt gran" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5915,128 +6173,133 @@ msgid "" msgstr "El mode speedrun només es pot habilitar si el joc no s'ha tancat des de que es va iniciar el mode història.\n\nTancar el joc abans de completar el mode història invalida el temporitzador.\n\nPer fer servir el mode speedrun, fes servir un nou perfil, si us plau." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Sincronització vertical" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Vsync obliga a la targeta gràfica a proporcionar un nou quadre\nnomés quan el monitor està llest per mostrar-lo." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Vsync no funcionarà si els teus controladors gràfics no ho suporten." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Efectes de partícules: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Personatges animats: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Llums dinàmiques: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Dispersió lluminosa: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Antialiàsing: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Oclusió ambiental: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Ombres: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Ombres: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Lluïssor: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Resplendor (contorns): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Rajos crepusculars (rajos de Déu): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Qualitat de la imatge renderitzada: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Detall geomètric: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Difuminació de moviment: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Profunditat de camp: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "L'accés a Internet està deshabilitat. Vols habilitar-lo?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Cal que introdueixis una contrasenya." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "S'està desconnectant '%s'" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "S'està connectant '%s'" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "No pots eliminar a l'únic jugador." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Realment vols eliminar el jugador '%s'?" @@ -6064,7 +6327,7 @@ msgstr "GOL!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Esperant als altres" @@ -6099,7 +6362,7 @@ msgstr "Segueix al líder!" msgid "Top %i" msgstr "Top %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Repte no superat" @@ -6123,102 +6386,199 @@ msgstr "Prem la icona del podi per començar el repte" msgid "Press fire to start the challenge" msgstr "Prem 'Foc' per començar el repte" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Tornar a la configuració de vídeo" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Desar els resultats" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Tornar al menú principal" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Abandonar el servidor" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Avorta el campionat" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Reiniciar" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Tornar a la selecció de reptes" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Corre contra la nova repetició fantasma" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Tornar al menú" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Realment vols avortar el campionat?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Informe de rendiment desat a \"%s\"." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "L'equip vermell guanya" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "L'equip blau guanya" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Empatats" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Eliminat després de %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Eliminat" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(en pròpia porta)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Circuit %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Progrés del campionat:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Millors temps" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Millor volta: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "per %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Has completat el repte!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "No has completat el repte!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "S'han complert els requisits del SuperTux" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Resultat del test de rendiment" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Durada del test: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Nombre de quadres: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "FPS estable: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "FPS majoritàriament estable: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "FPS típic: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Resolució horizontal: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Resolució vertical: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Llums dinàmiques: SÍ" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Llums dinàmiques: NO" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Resolució del renderitzat: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Antialiàsing: SÍ" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Antialiàsing: NO" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Il·luminació basada en imatges: SÍ" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Il·luminació basada en imatges: NO" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Oclusió ambiental: SÍ" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Oclusió ambiental: NO" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Resolució de les ombres: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Totes els cops estan permesos, o sigui que agafa armes i fes-ne un bon ús!" @@ -6259,28 +6619,28 @@ msgstr "Prem la icona de futbol blava o vermella per canviar d'equip" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Circuit creat per %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Màx. jugadors permesos: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Nombre de karts vermells controlats per l'ordinador" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "No pots participar en aquest campionat perquè conté circuits que estan bloquejats!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Bloquejat!" @@ -6302,10 +6662,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Completa tots els reptes per obrir la porta gran!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6314,41 +6676,48 @@ msgid "" msgstr "Necessites més punts\nper entrar en aquest repte!\nBusca els reptes disponibles\nal mapa en miniatura." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Accelera amb <%s>, i gira amb <%s> i <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Accelera tocant la part superior del volant, i gira movent-te a dreta o esquerra." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Accelera movent l'accelerador cap amunt, i gira inclinant el teu dispositiu." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Accelera movent l'accelerador cap amunt, i gira fent rotar el teu dispositiu." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Recull caixes de regal, i dispara l'arma amb <%s> per fer explotar aquestes capses!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Recull caixes de regal, i dispara prement la icona de les bitlles per fer explotar aquestes capses!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6356,34 +6725,41 @@ msgid "" msgstr "Prem <%s> per mirar enrere.\nDispara l'arma amb <%s> mentre prems <%s> per disparar cap enrere!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Prem el botó del retrovisor per mirar cap enrere.\nDispara l'arma cap enrere arrossegant la icona del mirall cap a la bola de bitlles!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Fes servir el nitro que has recollit prement <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Fes servir el nitro que has recollit prement la icona del nitro." #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Recull ampolles de nitro (les farem servir després de la corba)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Ups! Quan tinguis problemes, prem <%s> per ser rescatat." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Ups! Quan tinguis problemes, prem la icona de l'ocell per ser rescatat." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6391,24 +6767,27 @@ msgid "" msgstr "Accelera i prem la tecla <%s> mentre gires per derrapar.\nDerrapar una mica pot ajudar-te a girar més ràpid per agafar corbes tancades." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Accelera i prem la icona del derrapatge mentre gires per derrapar.\nDerrapar una mica pot ajudar-te a girar més ràpid per agafar corbes tancades." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Tingues en compte que si aconsegueixes derrapar durant varis segons, rebràs un increment de velocitat com a recompensa!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Ja estàs preparat per competir. Bona sort!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Un joc de curses de karts en 3D de codi obert." @@ -6418,7 +6797,7 @@ msgstr "Un joc de curses de karts en 3D de codi obert." msgid "tux;game;race;" msgstr "tux;joc;cursa;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6426,7 +6805,7 @@ msgid "" "for all ages." msgstr "Karts. Nitro. Acció! El SuperTuxKart és un joc de curses 3D de codi obert amb una gran varietat de personatges, circuits i maneres de jugar. El nostre objectiu és crear un joc que sigui més divertit que realista, i proporcionar una experiència agradable per a totes les edats." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6435,7 +6814,7 @@ msgid "" "your opponents." msgstr "Tenim varis circuits amb diferents ambientacions per disfrutar, des de conduir sota l'aigua, terres de cultiu rurals, selves o fins i tot l'espai! Dona-ho tot mentre evites que els altres karts t'avancin, però no et mengis els plàtans! Vigila amb les boles de bitlles, desembussadors, xiclets i pastissos llançats pels teus oponents." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6444,27 +6823,27 @@ msgid "" "your racing skills!" msgstr "Pots córrer una sola cursa contra altres karts, competir en un o varis campionats, intentar superar les puntuacions màximes en les teves pròpies curses contra rellotge, jugar en mode batalla contra l'ordinador o els teus amics, i més! Per a un desafiament encara més gran, competeix en línia contra jugadors de tot el món i demostra les teves habilitats al volant!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Auest joc no té anuncis." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Aquesta és una versió inestable del SuperTuxKart que conté les últimes millores. Es publica principalment per provar-la, per fer que la versió estable del STK sigui tan bona com sigui possible." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Aquesta versió es pot instal·lar en paral·lel amb la versió estable en el dispositiu." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Si necessites més estabilitat, pots fer servir la versió estable: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "L'equip del SuperTuxKart" diff --git a/data/po/cs.po b/data/po/cs.po index 722d8066a9c..26bc8e91b62 100644 --- a/data/po/cs.po +++ b/data/po/cs.po @@ -3,6 +3,7 @@ # This file is distributed under the same license as the supertuxkart package. # # Translators: +# Drahomir Sobotka, 2024 # GamingasCZ , 2021 # Jakub Vaněk , 2015-2016 # Pavel Borecki , 2015-2019 @@ -13,9 +14,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Tomáš Pártl , 2019\n" +"Last-Translator: Drahomir Sobotka, 2024\n" "Language-Team: Czech (http://app.transifex.com/supertuxkart/supertuxkart/language/cs/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -172,7 +173,7 @@ msgstr "Na konci světa" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Zpět" @@ -194,7 +195,7 @@ msgstr "Vyberte požadovaný typ ovládání" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Akcelerometr" @@ -208,13 +209,13 @@ msgstr "Akcelerometr" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Gyroskop" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Volant" @@ -245,35 +246,37 @@ msgstr "Nastavení dotykového zařízení" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Obecné" @@ -341,30 +344,33 @@ msgstr "Obnovit výchozí nastavení" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Zrušit" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Ano" @@ -542,9 +548,9 @@ msgstr "Připojit" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -605,7 +611,7 @@ msgstr "Cíl" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Postup" @@ -640,7 +646,7 @@ msgstr "Odeslat" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Vrátit se do závodu" @@ -657,7 +663,7 @@ msgstr "Návrat do čekárny" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Restartovat závod" @@ -721,12 +727,12 @@ msgstr "Aby bylo možné obnovit heslo, vyplňte uživatelské jméno a e-mailov #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Uživatelské jméno" @@ -767,7 +773,7 @@ msgstr "Obtížnost" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Nováček" @@ -779,7 +785,7 @@ msgstr "Nováček" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Pokročilý" @@ -791,7 +797,7 @@ msgstr "Pokročilý" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Expert" @@ -803,7 +809,7 @@ msgstr "Expert" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -811,8 +817,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Herní režim" @@ -823,8 +829,8 @@ msgstr "Herní režim" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Normální závod" @@ -837,7 +843,7 @@ msgstr "Normální závod" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Závod na čas" @@ -845,7 +851,8 @@ msgstr "Závod na čas" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Bitva" @@ -854,24 +861,24 @@ msgstr "Bitva" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Fotbal" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Heslo" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Přidat tento server do záložek" @@ -882,7 +889,7 @@ msgstr "Přidat hráče" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Název" @@ -924,17 +931,17 @@ msgstr "Přidat kamaráda" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Přijmout pozvánku" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Zamítnout pozvánku" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Zobrazit profil" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -976,6 +983,50 @@ msgstr "Přiřadit ke klávese ESC" msgid "Assign nothing" msgstr "Nic nepřiřazovat" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Začít test" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -990,11 +1041,11 @@ msgstr "Nastavení závodu" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Pokračovat" @@ -1035,10 +1086,15 @@ msgstr "Arény" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Nainstalováno" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Editovat oblíbené arény" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1048,20 +1104,20 @@ msgstr "Nainstalováno" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Standardní" @@ -1072,12 +1128,12 @@ msgstr "Standardní" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Zásuvné moduly" @@ -1091,27 +1147,28 @@ msgstr "Zásuvné moduly" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Všechny" @@ -1122,7 +1179,7 @@ msgstr "Poděkování" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Přeskočit" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1150,9 +1207,9 @@ msgstr "Přesunout dolů" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Přidat" @@ -1189,7 +1246,7 @@ msgstr "Výběr opakovačky s duchem" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Lov vajíček" @@ -1236,10 +1293,10 @@ msgstr "Opačný směr" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Maximální doba (min.)" @@ -1271,9 +1328,9 @@ msgstr "Kopírovat" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1284,80 +1341,80 @@ msgstr "Přejmenovat" msgid "Save Grand Prix" msgstr "Uložit Velkou cenu" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Nápověda k SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Herní režimy" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Bonusy" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Banány" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1365,56 +1422,57 @@ msgstr "Banány" msgid "Story Mode" msgstr "Režim příběhu" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Třídy motokár" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Hra více hráčů" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Spustit výuku" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Sbírejte modré krabice. Přidají vám bonusy." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Vyhněte se banánům!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1422,14 +1480,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Sběr nitra vám umožní získat zvýšení rychlosti, kdykoliv budete chtít, stisknutím přiřazené klávesy nebo tlačítka. Svou současnou úroveň nitra můžete vidět na indikátoru v pravém dolním rohu obrazovky závodu." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Vidíte-li tlačítko se zámkem jako je toto, musíte pro odemčení splnit výzvu." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1438,34 +1496,34 @@ msgid "" "carefully before!" msgstr "Pomocí speciální klávesy nebo tlačítka můžete udělat smyk. Postupné krátké smyky pomáhají dělat ostré zatáčky; zatímco střední smyky zvýší vaši rychlost, dlouhé smyky ještě více. Při smyku nemůžete přestat zatáčet, takže nejprve pečlivě orientujte svou motokáru!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Urychlit start můžete stisknutím tlačítka zrychlení při povelu 'Pozor!' před startem závodu." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Stávající přiřazení kláves lze zobrazit/změnit v nabídce Možnosti" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart nabízí několik herních režimů:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Běžný závod: Všechny údery jsou povoleny, takže sbírejte bonusy a chytře je používejte!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Závod na čas: Neobsahuje žádné bonusy, takže záleží pouze na vašich řidičských schopnostech!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1473,7 +1531,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Následujte vedoucího: Jezděte na druhém místě, protože poslední motokára bude diskvalifikována pokaždé, když odpočítávání dosáhne nuly. Pozor: za jízdu před vedoucím budete vyloučeni taky!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1483,30 +1541,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Existují 3 typy bitevního režimu: V režimu Bitva na 3 zásahy musíte zasáhnout ostatní zbraněmi, dokud neztratí všechny své životy. V režimu Volný pro vše vyhraje hráč, který zasáhne ostatní nejvícekrát v daném časovém limitu. V režimu Zmocni se vlajky musí váš tým přivézt vlajku druhého týmu na vaši vlastní vlajkovou základnu, dokud vaše vlajka není polapena jiným týmem." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Fotbal: Použijte svou motokáru k natlačení míče do branky." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Lov vajíček: Prozkoumejte tratě a najděte všechna skrytá vejce." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Opakovačka s duchem: Závoďte proti záznamu s duchem v závodu na čas nebo v režimu lovu vajec a nahrajte si vlastní!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1515,93 +1573,93 @@ msgid "" "wins the cup." msgstr "* Většinu těchto herních režimů lze hrát v módu Velké ceny: místo jednoho závodu jich pojedete několik v řadě. Čím lépe se umístíte, tím více bodů získáte. Kdo má na konci nejvíc bodů vyhrává pohár." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Abyste si usnadnili cestu k výhře, můžete sbírat následující bonusy:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Žvýkačka – chraňte se jí jako štítem, nebo při pohledu dozadu upusťte za sebe jako růžovou lepkavou louži." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Zip – umožní vám výrazné zvýšení rychlosti. Ale dejte si pozor, abyste neztratili kontrolu nad svou motokárou!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Dort – házejte na nejbližší soupeře, nejlépe na krátkých vzdálenostech a dlouhých rovinkách. Ovlivňuje také ostatní motokáry v blízkosti výbuchu." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Zvon – trefte protivníkova záda a přitáhněte se. Nebo se ohlédněte a hoďte zvon dozadu – soupeř, kterého trefíte, přijde o výhled." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Bowlingová koule – jede rovně dokud nenarazí, může se odrážet od stěn. Pokud se podíváte zpět, bude hozena dozadu." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Padák – zpomalí všechny hráče před vámi." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Prohazovačka – dárky se na krátkou chvíli přemění na banány, plechovky s nitrem na žvýkačky a naopak." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Basketbalový míč – odrazí se za vedoucím a může přitom přimáčknout a zpomalit ostatní motokáry, se kterými se setká." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Plácačka – rozplácne motokáry v blízkosti a tím je zpomalí. Lze ji také použít k odstranění padáků a bomb." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Náraz do banánu může mít za následek, že se připojí k motokáře jedna z následujících položek:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Kotva – způsobuje náhlé zpomalení motokáry." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Padák – zpomaluje motokáru, progresivněji než kotva. Čím rychleji jedete, tím silněji zpomaluje." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bomba – po určité době vybuchne a vyhodí motokáru do vzduchu. Nárazem do jiné motokáry přehodíte bombu na jiného hráče." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Zlý Nolok polapil Gnu! Zde je několik tipů, které vám pomohou:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1610,7 +1668,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Tato ikona na minimapě zobrazuje dostupné výzvy, které jste nedokončili. V pravém horním rohu obrazovky se také dozvíte, kolik bodů aktuálně máte. Dokončete co nejvíce výzev a Nolok přijme závod proti vám. Vyhrajte a osvobozte Gnu!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1618,20 +1676,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Když dokončíte výzvu, dostanete pohár. Každý pohár má hodnotu několika bodů. Čím vyšší obtížnost jste dokončili, tím lepší pohár a více bodů dostanete." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Když získáte pod touto ikonou uvedený počet bodů, budete odměněni. Je jich tu několik k výběru." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Ne všechny motokáry jezdí stejně! Patří do tříd s několika rozdíly:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1639,7 +1697,7 @@ msgid "" " resistant to explosions." msgstr "Hmotnost – existují tři třídy motokár, v závislosti na jejich hmotnosti: lehké, střední a těžké. Těžší motokáry jsou méně ovlivněny padáky a jsou odolnější vůči výbuchům." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1647,7 +1705,7 @@ msgid "" " especially at low speeds." msgstr "Zrychlení – obzvláště užitečné při startu, po nehodě nebo na tratích s mnoha ostrými zatáčkami. Čím je motokára lehčí, tím rychleji zrychluje, zejména při nízkých rychlostech." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1655,14 +1713,14 @@ msgid "" " top speed." msgstr "Maximální rychlost – čím vyšší je, tím rychleji může jet motokára. Zvláště užitečné na tratích s přímým vedením a mírnými zatáčkami. Těžší motokáry mají vyšší maximální rychlost." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Nitro efektivita – čím vyšší je, tím vyšší rychlost dostanete z plechovky nitra. Lehčí motokára bude mít vyšší nitro efektivitu." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1670,12 +1728,12 @@ msgid "" "easier it is." msgstr "Pokud budete několik vteřin těsně následovat další motokáru, dostanete aerodynamický rychlostní bonus, když ji předjedete. Čím lehčí je vaše motokára, tím je to jednodušší." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart lze hrát on-line v režimu pro více hráčů…:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1685,7 +1743,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Nejprve vyberte ikonu „On-line“ v hlavní nabídce. Vyberte místní síť nebo globální síť (v možnostech je třeba povolit internet). Potom si můžete vytvořit svůj vlastní server s vlastními volbami nebo si nějaký vyhledat v seznamu existujících serverů, ke kterým se můžete připojit. Některé z nich jsou doporučované servery s možností hodnocení závodů." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1695,12 +1753,12 @@ msgid "" "players and the server." msgstr "Pokud jde o server, závod začne, jakmile to rozhodne jeho vlastník (symbolizovaný korunou). Oficiální servery mohou automaticky spustit start pouze pokud je dostatek hráčů. Poté si můžete vybrat svou motokáru a hlasovat pro další trať, na které se bude závodit. Tratě ze zásuvných modulů jsou povoleny pouze pokud se vyskytují u všech připojených hráčů a na serveru." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "… nebo na stejném zařízení:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1710,7 +1768,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Nejprve budete potřebovat několik vstupních zařízení. Pomocí obrazovky pro nastavení vstupu je nastavte. Ideální je více gamepadů nebo joysticků: na klávesnici (klávesnicích) bude každý hráč potřebovat jinou sadu kláves a většina klávesnic není vhodná pro hru více hráčů, protože nepodporují více současných stisknutí kláves." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1730,7 +1788,7 @@ msgstr "Výběr nejlepšího skóre" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Počet kol na čas" @@ -1738,9 +1796,9 @@ msgstr "Počet kol na čas" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Velká cena" @@ -1751,6 +1809,20 @@ msgstr "Velká cena" msgid "Choose a Kart" msgstr "Vyberte si motokáru" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Třídy motokár" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Editovat oblíbené motokáry" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1764,11 +1836,11 @@ msgstr "Hra více hráčů" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "On-line" @@ -1785,7 +1857,7 @@ msgstr "Výuka" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Nejlepší skóre" @@ -1793,7 +1865,7 @@ msgstr "Nejlepší skóre" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Úspěchy" @@ -1847,30 +1919,30 @@ msgstr "Najít server" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Vytvořit server" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Čekárna" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Nastavení" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Start závodu" @@ -1896,9 +1968,9 @@ msgstr "Zadejte adresu serveru" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Váš profil" @@ -1916,7 +1988,7 @@ msgstr "Hodnocení hráčů" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Přátelé" @@ -1941,7 +2013,7 @@ msgstr "Rychlá hra" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Nastavení účtu" @@ -1991,8 +2063,8 @@ msgid "Online Username" msgstr "On-line uživatelské jméno" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Resetovat heslo" @@ -2002,10 +2074,10 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Můžete hrát bez vytvoření on-line účtu výběrem režimu off-line účet. Nebudete schopni připojovat se k přátelům, hlasovat pro addony atd. Přečtěte si prosím naše prohlášení o ochraně soukromí na http://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Výběr serveru" @@ -2023,339 +2095,409 @@ msgstr "Použít připojení IPv6" msgid "User search" msgstr "Hledání uživatele" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Předvolby pro SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Obrazovka" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Grafika" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Zvuk" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Rozhraní" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Hráči" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Ovládání" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Jazyk" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Hudba" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Zapnuto" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Hlasitost" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Zvukové efekty" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Smazat nastavení" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Vypnout nastavování" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Zpět k seznamu zařízení" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Přejmenovat konfiguraci" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Povolit zpětnou vazbu (pokud je podporována)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Rozlišení" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Celá obrazovka" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Zapamatovat si umístění okna" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Použít nové rozlišení" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Rozdělení obrazovky hry pro více hráčů" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Internetové možnosti" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Vždy zobrazovat přihlašovací obrazovku" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Připojit k Internetu" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Povolit chatování on-line" +msgid "Enable chatting in online lobbies" +msgstr "Povolit chatování v on-line hrách" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Povolit chatování v on-line hrách" +msgid "Enable chatting in online matches" +msgstr "Povolit chatování v on-line zápasech" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Různé možnosti" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Používat handicapy pro hráče" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Odinstalovat všechny herní prvky" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Stiskněte enter nebo poklepejte na zařízení, které chcete nastavit" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Přidat vstupní zařízení" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Kterou konfiguraci budete chtít použít, bude vyvozeno z toho, kterou klávesu 'Vybrat' stisknete při vstupu do hry." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Motiv vzhledu" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Minimapa" +msgid "Skin variant" +msgstr "Varianta skinu" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Rozdělení obrazovky hry pro více hráčů" +msgid "Minimap" +msgstr "Minimapa" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Velikost písma" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Kamera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Vlastní…" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Zobrazovat počet snímků/s" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Zobrazit bonusy ostatních motokár" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Zapnout odpočet režimu příběhu" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Zapnout rychlostní odpočet" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Rozlišení vykreslování" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Úroveň grafických efektů" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Úroveň efektů rozostření" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Maximální FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Vlastní nastavení…" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Rozlišení" +msgid "Performance tests" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Celá obrazovka" +msgid "Performance test of the current settings" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Zapamatovat si umístění okna" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Zapamatovat heslo" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Použít nové rozlišení" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Odstranit" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Barva motokáry" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2382,15 +2524,15 @@ msgstr "Modrý tým" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Počet kol" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Počet počítačem ovládaných motokár" @@ -2405,33 +2547,17 @@ msgstr "Počet počítačem ovládaných motokár modrého týmu" msgid "Random Grand Prix" msgstr "Náhodná Velká cena" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Editovat oblíbené dráhy" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Přihlášení" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Zapamatovat heslo" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Odstranit" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Barva motokáry" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Motiv vzhledu uživatelského rozhraní lze změnit v možnostech uživatelského rozhraní." @@ -2515,7 +2641,7 @@ msgstr "Basketbalové míče lze zničit pomocí přesných zpětných výstřel msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "" +msgstr "Pokuste se zabránit nárazu do zad jiných motokár, protože vás to zpomalí." #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." @@ -2550,238 +2676,306 @@ msgid "" msgstr "Nesnažte se zbytečně bránit spoluhráči vezoucímu míč, ale můžete se pokusit zasáhnout soupeře a pokusit se tak zabránit jim vstřelit branku." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Pakůň Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Paprika" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sára" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Předpotopní propast" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Mimozemský signál" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Bludiště dávného kolosea" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Město Candela" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Bitevní ostrov" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Černý les" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Jeskyně X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Kakaový chrám" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Kros kukuřičným polem" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Pevnost Magma" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Ostrov Velký ráj" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Ledové fotbalové hřiště" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Co se děje, prckové? Snad vám nechybí váš šéf pakůň?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Jasně, koukni, je v mém zámku a bude podáván k večeři…" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Ale já jsem spravedlivý tvor, takže ti nabídnu dohodu." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Když mě porazíš na trati, tak toho starce pustím." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " Takoví spratci jako vy, mě nikdy nemůžou porazit – krále všech motokár!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Písečné duny" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Fotbalový stadion Las Dunas" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Kolem majáku" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Starý důl" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" -msgstr "" +msgstr "Oáza" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Hodina matiky" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Dýňový park" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Zámek Ravenbridge" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Tekuté písky" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Jezero Lochnesky" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Severní letovisko" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Sněžný vrchol" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Fotbalové hřiště" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Stadion" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "Podnik STK" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Chrám" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Sopečný ostrov" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Japonská zahrada" @@ -2790,11 +2984,11 @@ msgstr "Japonská zahrada" msgid "Completed achievement \"%s\"." msgstr "Cíl „%s“ dosažen." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Nepodařilo se připojit k serveru doplňků SuperTuxKart." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Chyba při stahování novinek: '%s'." @@ -2860,7 +3054,7 @@ msgid "New kart '%s' now available" msgstr "Nová motokára '%s' nyní k dispozici" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2892,32 +3086,32 @@ msgid "" "created." msgstr "Soubor nastavení byl zastaralý, proto byl smazán a bude vytvořen nový." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Zahájeno nahrávání videa." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Video uloženo do „%s“." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Průběh enkódování:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d –⁠ %d tisíc trojúh., ping: %d ms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Tip: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Načítání" @@ -2939,19 +3133,18 @@ msgstr "Nitro efektivita" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (handicapovaný)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s je připraven" @@ -3425,21 +3618,21 @@ msgid "Axis %d" msgstr "Osa %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Tlačítko gamepadu %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Tlačítko myši %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Osa myši %d %s" @@ -3613,26 +3806,30 @@ msgstr "Můžete mít maximálně 3 životy!" msgid "+1 life." msgstr "+1 život." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Byli jste příliš pomalí!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Dokončil jsi závod!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Vyhráli jste závod!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Dokončili jste závod na %d. místě!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s opustil(a) hru." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3641,16 +3838,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart se může připojit k serveru a stahovat doplňky a upozorňovat vás na aktualizace. Přečtěte si prosím naše zásady ochrany osobních údajů na adrese https://supertuxkart.net/Privacy. Chcete tuto funkci povolit? (Budete-li chtít toto nastavení změnit později, přejděte na možnosti, vyberte kartu „Obecné“ a upravte volbu „Připojit k Internetu“)." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Vaše rozlišení obrazovky je příliš nízké pro spuštění STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Ovladač grafické karty, který je nyní používán na tomto systému, je zastaralý. Nainstalujte jeho nejnovější verzi." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3658,38 +3855,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Váš grafický ovladač se zdá být velmi starý. Zkontrolujte, zda je k dispozici aktualizace. SuperTuxKart doporučuje ovladač podporující %s nebo lepší. Hra pravděpodobně ještě poběží, ale v redukovaném grafickém režimu." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Časový limit připojení k serveru vypršel." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s má červenou vlajku!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Červená vlajka se vrátila!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s má modrou vlajku!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Modrá vlajka se vrátila!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s získal modrou vlajku!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s získal červenou vlajku!" @@ -3699,7 +3896,7 @@ msgstr "%s získal červenou vlajku!" msgid "Eggs: %d / %d" msgstr "Vejce: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Vedoucí" @@ -3707,22 +3904,22 @@ msgstr "Vedoucí" msgid "Final lap!" msgstr "Poslední kolo!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Kolo %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s od %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Nové nejrychlejší kolo" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "ŠPATNÝ SMĚR!" @@ -3736,7 +3933,7 @@ msgstr "%s vstřelil gól!" msgid "Oops, %s made an own goal!" msgstr "Ajaj, %s si dal vlastní gól!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" @@ -3745,187 +3942,187 @@ msgstr[1] "Vznikly %i náhradní pneumatiky pro motokáru!" msgstr[2] "Vzniklo %i náhradních pneumatik pro motokáru!" msgstr[3] "Vzniklo %i náhradních pneumatik pro motokáru!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Byli jste vyřazeni!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "„%s“ byl vyřazen." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Server byl vypnut." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Byli jste vykopnutí ze serveru." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Byli jste vykopnuti: Příliš vysoký ping." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Bylo zjištěno špatné připojení k síti." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s odpojen." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Stiskněte jméno hráče v seznamu pro správu hráčů a informace o hodnocení." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Obtížnost: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Maximálně hráčů: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Herní režim: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Limit času" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Limit branek" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Typ fotbalové hry: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Průběh Velké ceny: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Všichni hráči se připojili k červenému nebo modrému týmu." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Nyní jste vlastníkem serveru." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Připojení odmítnuto: Server je zaneprázdněn." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Připojení odmítnuto: Ze serveru jste zakázáni." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Připojení odmítnuto: Heslo serveru je nesprávné." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Připojení odmítnuto: Údaje hry nejsou kompatibilní." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Připojení odmítnuto: Server je plný." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Připojení odmítnuto: Připojení neplatného hráče." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Nepodařilo se spustit síťovou hru." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Hra skončila, už se nemůžete živě připojit nebo dívat." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Žádné zbývající místo v aréně – připojení zakázáno." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Zbývá pouze 1 hráč, návrat do čekárny." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Vlastník serveru ukončil hru." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Budete sledovat další hru." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s se připojil(a) k červenému týmu." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s se připojil(a) k modrému týmu." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s se připojil ke hře." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3933,15 +4130,15 @@ msgid "" msgstr "Stiskněte <%s> nebo <%s> pro změnu zaměřeného hráče, <%s> nebo <%s> pro polohu kamery." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "%s úspěšně nahlášen." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3972,38 +4169,38 @@ msgstr "Závod na čas (Velká cena)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Volný pro vše" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Zmocni se vlajky" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s je nyní on-line." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s a %s jsou nyní on-line." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s a %s jsou nyní on-line." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4013,12 +4210,12 @@ msgstr[2] "%d kamarádů je nyní on-line." msgstr[3] "%d kamarádů je nyní on-line." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s je nyní na serveru \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4027,7 +4224,7 @@ msgstr[1] "Máte %d nové žádosti o přátelství!" msgstr[2] "Máte %d nových žádostí o kamarádství!" msgstr[3] "Máte %d nových žádostí o kamarádství!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Máte novou žádost o kamarádství!" @@ -4056,12 +4253,12 @@ msgid "" msgstr "Soubor s nejvyšším skóre byl příliš starý,\nvšechna nejvyšší skóre byla smazána." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Následujte vedoucího" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Bitva na 3 zásahy" @@ -4074,93 +4271,88 @@ msgstr "Neúplný soubor s opakovačkou nebude uložen." msgid "Replay saved in \"%s\"." msgstr "Opakovačka uložena do „%s“." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 týden" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 týdny" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 měsíc" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 měsíce" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 měsíců" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 měsíců" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 rok" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 roky" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Název doplňku" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Datum aktualizace" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Nenainstalováno" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s od %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Chvíli strpení, aktualizují se doplňky" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Omlouváme se, během připojování k webu doplňků se vyskytla chyba. Ověřte, že jste připojení k Internetu a že SuperTuxKart není blokován bránou firewall" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Oblíbené" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Zamčeno: splňte aktivní výzvy k získání přístupu!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Náhodná aréna" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d aréna není k dispozici v režimu hry jednoho hráče." -msgstr[1] "%d arény nejsou k dispozici v režimu hry jednoho hráče." -msgstr[2] "%d arén není k dispozici v režimu hry jednoho hráče." -msgstr[3] "%d arén není k dispozici v režimu hry jednoho hráče." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nGamingasCZ, 2021\nJakub Vaněk, 2015-2016\nPavel Borecki, 2015-2019\nToMáš Marný, 2015\nToMáš Marný, 2015-2016,2022\nTomáš Pártl, 2019\nToMáš Marný, 2015-2022\nAri Green\nDavid Kolibáč\nDawid Gan\ndonny\ndtfjgk\nFrantišek Zatloukal\nH0ff1\nJakub Talich\nJan Srb\nJirka Folta\nLukáš Machyán\nMichal Kundrát\nMightyPork\nOndřej Holý\nPavel Borecki, 2015\nPetr Wudi\nSTK-team\nTadeáš Pařík\nTomáš Velecký" @@ -4448,7 +4640,7 @@ msgstr "Posbírané banány" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Smyk" @@ -4551,7 +4743,7 @@ msgstr "Dokončené lovy vajíček" msgid " (official tracks matching the goal)" msgstr " (oficiální trasy odpovídající cíli)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4559,91 +4751,95 @@ msgid "" msgstr "Nové gamepady a joysticky se automaticky objeví v seznamu, když je připojíte k tomuto zařízení.\n\nChcete-li přidat konfiguraci klávesnice, můžete použít níže uvedené tlačítko, AVŠAK pamatujte, že většina klávesnic podporuje pouze omezené množství současných stisků kláves, a jsou proto nevhodné pro hraní více hráčů. (K tomuto zařízení však můžete připojit více klávesnic. Nezapomeňte ale, že v tomto případě všichni stále potřebují různé klávesové zkratky.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Přidat Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Přidat nastavení klávesnice" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Aktualizovat" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Verze: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "oblíbené" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Velikost: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Musíš být přihlášený, aby jsi ohodnotil tento addon." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Omlouváme se, ale stahování doplňku se nezdařilo" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Problémy s instalací doplňku „%s“." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Zkuste znovu" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Problémy s odinstalací doplňku „%s“." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Stahování na pozadí bylo dokončeno." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Stahování na pozadí" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Stahování na pozadí již začalo." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Stávající heslo je chybně zadané." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Je třeba, aby heslo bylo dlouhé nejméně 8 a nejvíce 30 znaků!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Hesla se neshodují!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Ověřování informací" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Heslo bylo úspěšně změněno." @@ -4666,67 +4862,97 @@ msgstr "Rozlišení menší než 1024x768 nebo 1280x720 nejsou podporována. Ně #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Pronásledování dronem" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Vlastní" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Zakázáno" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Pouze důležité" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Velmi nízká" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Nízká" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Střední" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Vysoká" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Velmi výsoká" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4734,7 +4960,7 @@ msgid "" msgstr "SuperTuxKart stáhne veškeré herní prvky (včetně vysoce kvalitních textur a hudby) pro váš lepší herní zážitek. Pokud nemáte připojení Wi-Fi, použijí se k tomu vaše mobilní data." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4751,101 +4977,102 @@ msgstr "Zadejte adresu serveru, případně také : a číslo portu, nebo vybert msgid "Invalid server address: %s." msgstr "Neplatná adresa serveru: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Opačný směr" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Obtížnost" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Kola" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Čas" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Motokára" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Uživatel" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Verze" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Ne" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Trať" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "%d nejlepších výsledků" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Počet motokár: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Cílový čas: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Kola: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Opačný směr: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Prázdné)" @@ -4933,33 +5160,41 @@ msgid "Press any key..." msgstr "Stiskněte libovolnou klávesu…" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Chat vypnut, zapnete v nabídce předvoleb." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Vrátit se do bitvy" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Nastavit novou hru" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Restartovat zápas" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Opustit bitvu" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Nastavit nový závod" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Odejít ze závodu" @@ -4975,11 +5210,11 @@ msgstr "%s zatím nemá žádné hodnocení." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s je číslo %d v žebříčku se skóre %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Uživatelské jméno a/nebo e-mailová adresa jsou neplatné." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5001,7 +5236,7 @@ msgstr "Opakovaný závod s duchem" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Kol: %i" @@ -5014,21 +5249,21 @@ msgstr "Typ: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Požadované hodnocení: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Požadovaný čas: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Požadovaných nitro bodů: %i" @@ -5041,54 +5276,54 @@ msgstr "Počet motokár ovládaných počítačem: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Režim bitvy" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Typ fotbalové hry" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Umístění serveru: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Současná trať: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Pořadí" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Hráč" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Výsledky" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Odehraný čas" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Odebrat ze záložek" @@ -5101,74 +5336,74 @@ msgid "No player available for connecting to server." msgstr "Pro připojení k serveru není k dispozici žádný hráč." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Uživatelské jméno: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Zrušit požadavek" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Dnes" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Žádost o přátelství odeslána!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Žádost o přátelství přijata!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Žádost o přátelství odmítnuta!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Kamarád odebrán!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Žádost o přátelství zrušena!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Zpracovávání" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Načítání posledního hlasování" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Můžete upravit své předchozí hodnocení kliknutím na správný počet hvězd níže." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Ještě jste nehlasovali pro tento zásuvný modul. Vyberte požadované hodnocení kliknutím na počet hvězd níže" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Hlasování bylo úspěšné! Nyní můžete zavřít okno." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Provádění hlasování" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Náhodná trať" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5197,7 +5432,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Vyskytla se chyba při pokusu uložit vaši Velkou cenu." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Vyberte trať" @@ -5241,12 +5476,12 @@ msgstr "Odemkli jste trať %0" msgid "You unlocked grand prix %0" msgstr "Odemkli jste Velkou cenu %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Trať" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5267,19 +5502,19 @@ msgstr "Zadejte název této Velké ceny" msgid "Please select a Grand Prix" msgstr "Vyberte Velkou cenu" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Určeno uživatelem" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Název je prázdný." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Další Velká cena s tímto názvem již existuje." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Název je příliš dlouhý." @@ -5288,19 +5523,19 @@ msgstr "Název je příliš dlouhý." msgid "Better luck next time!" msgstr "Příště více štěstí!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Dokončili jste výzvu!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Vyhráli jste velkou cenu!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Velká cena dokončena!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Počet motokár" @@ -5313,110 +5548,125 @@ msgstr "Opravdu chcete smazat toto vysoké skóre?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Opravdu chcete smazat všechna svá nejlepší skóre?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Oblíbené" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Lehké" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Těžké" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Připojte klávesnici nebo gamepad, abyste mohli hrát hru pro více hráčů" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Náhodná motokára" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Zamčeno" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Všem:\nDo hry se zapojíte stiskem tlačítka „Vybrat“" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Chtěli byste hrát tutoriál s výukou hry?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Nemůžete hrát on-line bez přístupu k internetu. Pokud chcete hrát on-line, přejděte do nabídky Možnosti a zaškrtněte volbu „Připojit k Internetu“." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Zásuvné moduly nelze stahovat bez přístupu k internetu. Pokud chcete stahovat zásuvné moduly, přejděte do nabídky Možností a zaškrtněte volbu \"Připojit k Internetu\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Zásuvné moduly nelze stahovat bez přístupu k internetu. Pokud chcete stahovat zásuvné moduly, přejděte do nabídky Možností a zaškrtněte volbu \"Připojit k Internetu\".\nMůžete však odstranit již stažené zásuvné moduly." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Modul „Doplňky“ je momentálně vypnutý v nabídce „Předvolby“" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Chvíli strpení, načítají se doplňky" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Opravdu chcete opustit STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Vytvořit LAN server" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Server %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Počet kol velké ceny" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Je třeba, aby délka názvu byla 4 až 30 znaků!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Nepatřičné znaky v hesle!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Připraveno" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Živě připojit" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Pozorovat" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Nainstalovat doplněk" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5424,7 +5674,7 @@ msgstr "Počkejte prosím na konec aktuální hry (%s), odhadovaný zbývající #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Počkejte prosím na konec aktuální hry, odhadovaný zbývající čas: %s." @@ -5432,24 +5682,24 @@ msgstr "Počkejte prosím na konec aktuální hry, odhadovaný zbývající čas #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Počkejte prosím na konec aktuální hry (%s), odhadovaný pokrok: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Počkejte prosím na konec aktuální hry, odhadovaný pokrok: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Počkejte prosím na konec aktuální hry." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5460,7 +5710,7 @@ msgstr[3] "Hra začne, pokud je zde více než %d hráčů." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5471,96 +5721,108 @@ msgstr[1] "Start začne po %d sekundách, nebo jakmile každý stiskne tlačítk msgstr[2] "Start začne po %d sekundách, nebo jakmile každý stiskne tlačítko „Připraveno“." msgstr[3] "Start začne po %d sekundách, nebo jakmile každý stiskne tlačítko „Připraveno“." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Připojení k serveru %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Vyhledání serveru rychlé hry" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Zbývající čas: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Cíle" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Načítání úspěchů" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Profil %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Od" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Stav" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Načítání kamarádů" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Nová žádost" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Čeká" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Nepřipojen" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Níže zadejte nový e-mail" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Nový e -mail musí mít 5 až 254 znaků!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Nový e -mail je neplatný!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "E-mail změněn!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Nepodařilo se změnit e-mail: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Novinky z STK Blogu" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Datum" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Momentálně nejsou žádné dostupné novinky." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Abyste mohli hrát přes globální síť, musíte být přihlášeni. Klikněte na své uživatelské jméno výše." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Hledání" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Ukončit hru" @@ -5638,34 +5900,34 @@ msgid "Distance (km)" msgstr "Vzdálenost (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Není známo" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Nebyla detekována žádná IPv4, možná se nebudete moci připojit k žádným serverům." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Nebyla detekována žádná IPv6, možná se nebudete moci připojit k žádným serverům." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Není k dispozici žádný server." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Načítání serverů" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Serverové záložky" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5673,149 +5935,149 @@ msgstr "Pokud většina hráčů vybere stejné nastavení trati a závodu, hlas #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Náhodně rozmístěné položky" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Počet splněných cílů do vítězství" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Jet pozpátku" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Zamčeno: splň aktivní výzvy k získání přístupu!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Akce" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Přiřazená klávesa" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Zakázat zařízení" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Povolit zařízení" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Zapnout nastavení" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Herní klávesy" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Klávesy nabídky" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Zatočit doleva" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Zatočit doprava" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Zrychlení" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Brzda / zpátečka" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Střelba" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Ohlédnout se" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Záchrana" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Pozastavit hru" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Zrychlení" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Dolů" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Doleva" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Doprava" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Vybrat" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Zrušit/Zpět" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Modrá položka znamená konflikt s jiným nastavením" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Červená položka znamená konflikt ve stávajícím nastavení" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5823,17 +6085,27 @@ msgid "" msgstr "Upozornění: Klávesa „Shift“ se nedoporučuje. Pokud zmáčknete „Shift“, všechny klávesy které představují znak, který je odlišný při stisknuté klávese „Shift“, zde přestanou fungovat." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Opravdu chcete trvale smazat toto nastavení?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Zadejte nový název konfigurace, ponechte prázdné, pokud chcete vrátit výchozí hodnotu." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Svisle" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Vodorovně" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5841,89 +6113,74 @@ msgstr "V režimu hry více hráčů si mohou hráči vybrat handicapované\n(ob #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Nainstalovat plné herní prvky" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Opravdu chcete odinstalovat veškeré herní prvky?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Klávesnice %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Dotykové zařízení" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Klepnutím na zařízení jej nakonfigurujte" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Systémový jazyk" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Vlevo dole" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "Na pravé straně" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Skryté" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Na středu" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Svisle" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Vodorovně" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Velmi malé" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Malé" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Střední" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Velké" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Velmi velké" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5933,128 +6190,133 @@ msgid "" msgstr "Rychlostní režim lze aktivovat pouze v případě, že hra nebyla ukončena od spuštění režimu příběhu.\n\nUkončení hry před dokončením režimu příběhu zneplatní odpočet\n\nChcete-li použít rychlostní režim, použijte nový profil." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Vertikální synchronizace" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Vertikální synchronizace nutí grafickou kartu k dodání nového\nsnímku pouze pokud je monitor připraven k jeho zobrazení." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Vertikální synchronizace nebude fungovat, pokud to vaše ovladače nepodporují." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Částicové efekty: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Animované postavy: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Dynamická světla: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Rozptyl světla: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Vyhlazování hran: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Zastínění okolím: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Stíny: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Stíny: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Bloom: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Záře (obrysy): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Světelné paprsky: %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Kvalita vykreslovaného obrazu: 1%s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Pohybová neostrost: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Hloubka ostrosti: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Přístup k internetu je zakázán. Chcete ho povolit?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Je třeba zadat heslo." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Odhlášení '%s'" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Přihlašování '%s'" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Není možné smazat posledního zbývajícího hráče." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Opravdu chcete hráče „%s“ smazat?" @@ -6082,7 +6344,7 @@ msgstr "GÓL!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Čekání na ostatní" @@ -6117,7 +6379,7 @@ msgstr "Následujte vedoucího!" msgid "Top %i" msgstr "Prvních %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Výzva selhala" @@ -6141,102 +6403,199 @@ msgstr "Klepnutím na ikonu pódia zahajte výzvu" msgid "Press fire to start the challenge" msgstr "Stiskněte tlačítko střelby pro zahájení výzvy" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Uložit výsledky testu" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Zpět do hlavního menu" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Opustit server" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Ukončit Velkou cenu" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Restart" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Zpět na výběr výzev" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Závod proti nové opakovačce s duchem" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Zpět do nabídky" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Opravdu chcete ukončit Velkou cenu?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Vyhrává červený tým" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Vyhrává modrý tým" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Je to remíza" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Eliminován po %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Vyřazen" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(vlastní gól)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Trať %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Průběh Velké ceny:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Nejvyšší skóre" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Nejlepší čas kola: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "od %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Dokončili jste výzvu!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Neuspěli jste ve výzvě!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Splněny požadavky úrovně SuperTux" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Durace testu: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Počet snímků: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Horizontální rozlišení: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Vertikální rozlišení: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Dynamické osvětlení: ANO" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Dynamické osvětlení: NE" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Anti-aliasing: ANO" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Anti-aliasing : NE" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Všechny údery povoleny, takže sbírejte zbraně a chytře je použijte!" @@ -6277,28 +6636,28 @@ msgstr "Stisknutím červené nebo modré fotbalové ikony změníte tým" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Autor tratě: %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Nejvyšší umožněný počet hráčů: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Počet počítačem ovládaných motokár červeného týmu" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Tuto Velkou cenu nemůžete hrát, protože obsahuje tratě, které nejsou odemčené!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Zamčeno!" @@ -6320,10 +6679,12 @@ msgid "%d/%m/%Y" msgstr "%d. %m. %Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Dokončete všechny výzvy, abyste odemkli velké dveře!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6332,41 +6693,48 @@ msgid "" msgstr "Potřebujete více bodů\npro vstup do této výzvy!\nZkontrolujte minimapu\nna dostupné výzvy." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Pomocí <%s> zrychlujte a <%s> a <%s> řiďte." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Zrychlujte dotykem na horní část volantu a šoférujte pohybem doleva nebo doprava." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Zrychlujte pohybem akcelerátoru směrem vzhůru a šoférujte nakloněním zařízení." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Zrychlujte pohybem akcelerátoru směrem vzhůru a šoférujte otáčením zařízení." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Dárky buď sbírejte, nebo je rozstřílejte pomocí <%s>, aby je nedostali soupeři!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Dárky buď sbírejte, nebo je rozstřílejte pomocí ikony bowlingu, aby je nedostali soupeři!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6374,34 +6742,41 @@ msgid "" msgstr "Stisknutím <%s> se ohlédnete za sebe.\nPomocí <%s> a při současném stisknutí <%s> vystřelíte zbraň dozadu!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Stisknutím ikony zrcadla se podíváte dozadu.\nZbraň vystřelíte za sebe tak, že podržíte ikonu zrcadla, a poté zaútočíte bowlingovou ikonou!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Použijte posbírané nitro stisknutím <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Použijte posbírané nitro stisknutím ikony nitro" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Sbírejte láhve s nitrem (použijeme je za zatáčkou)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Jejda! Když jste v potížích, zachraňte se stisknutím <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Jejda! Když jste v potížích, zachraňte se stisknutím ikony ptáka." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6409,24 +6784,27 @@ msgid "" msgstr "Zrychlujte a stiskněte klávesu <%s>, přitom točte do smyku.\nKrátkodobý smyk vám může pomoci projet ostré zatáčky rychleji." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Zrychlujte a stiskněte ikonu smyku, přitom točte do smyku.\nKrátkodobý smyk vám může pomoci projet ostré zatáčky rychleji." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Všimněte si, že pokud zvládnete několik sekund řídit smykem, dostanete jako odměnu bonusové zrychlení!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Nyní jste připravení na závod. Hodně štěstí!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "3D open source závodní hra motokár" @@ -6436,7 +6814,7 @@ msgstr "3D open source závodní hra motokár" msgid "tux;game;race;" msgstr "tux;hra;závod;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6444,7 +6822,7 @@ msgid "" "for all ages." msgstr "Motokáry. Nitro. Akce! SuperTuxKart je 3D arkádová závodní hra s otevřeným zdrojovým kódem, která nabízí různé postavy, tratě a režimy. Naším cílem je vytvořit hru, která je spíš zábavnější než realistická a poskytne příjemný zážitek všem věkovým skupinám." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6453,7 +6831,7 @@ msgid "" "your opponents." msgstr "Máme několik tratí s různými tématy, které si hráči mohou užít, od tratí pod vodou, venkovských a zemědělských tratí, džunglí nebo dokonce trať ve vesmíru! Snažte se ze všech sil vyhýbat se ostatním motokárám, protože vás mohou předjet, ale nejezte banány! Dávejte pozor na bowlingové koule, zvony, žvýkačky a dorty hozené vašimi protivníky." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6462,27 +6840,27 @@ msgid "" "your racing skills!" msgstr "Můžete absolvovat samostatný závod s jinými motokáry, soutěžit v jedné z několika Velkých cen, pokusit se porazit vysoké skóre v závodech na čas, hrát bojový režim proti počítači nebo svým přátelům a další! Pro ještě větší výzvu se připojte on-line a potkejte se s hráči z celého světa a prokažte své závodní schopnosti!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Tato hra neobsahuje žádné reklamy." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Toto je nestabilní verze SuperTuxKart, která obsahuje nejnovější vylepšení. Je vydávána hlavně pro testování, aby byla stabilní verze SuperTuxKart co nejlepší." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Tuto verzi lze na zařízení nainstalovat paralelně se stabilní verzí." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Pokud potřebujete větší stabilitu, zvažte použití stabilní verze: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "Tým SuperTuxKart" diff --git a/data/po/cy.po b/data/po/cy.po new file mode 100644 index 00000000000..d5ae95108e8 --- /dev/null +++ b/data/po/cy.po @@ -0,0 +1,6861 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the supertuxkart package. +# +# Translators: +# Rhoslyn Prys, 2023 +# Rhoslyn Prys, 2023 +msgid "" +msgstr "" +"Project-Id-Version: SuperTuxKart\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" +"PO-Revision-Date: 2015-02-15 01:58+0000\n" +"Last-Translator: Rhoslyn Prys, 2023\n" +"Language-Team: Welsh (http://app.transifex.com/supertuxkart/supertuxkart/language/cy/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: cy\n" +"Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;\n" + +#. I18N: In Android UI, po_extract_game_data +msgid "Extracting game data..." +msgstr "Yn echdynnu data gêm..." + +#. I18N: In Android UI, po_extract_error +msgid "Game data extraction error" +msgstr "Gwall echdynnu data gêm" + +#. I18N: In Android UI, po_extract_error_msg +msgid "Check remaining device space or reinstall SuperTuxKart." +msgstr "Gwiria ofod y dyfais sy'n weddill neu ailosod SuperTuxKart." + +#. I18N: In Android UI, po_quit +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "Quit" +msgstr "Gadael" + +#. I18N: ./data/achievements.xml +msgid "Christoffel Columbus" +msgstr "Christoffel Columbus" + +#. I18N: ./data/achievements.xml +msgid "Play every official track at least once." +msgstr "Chwarae pob trac swyddogol o leiaf unwaith." + +#. I18N: ./data/achievements.xml +msgid "Strike!" +msgstr "Ergyd!" + +#. I18N: ./data/achievements.xml +msgid "Hit 10 karts with a bowling-ball." +msgstr "Taro 10 cart gyda phêl fowlio." + +#. I18N: ./data/achievements.xml +msgid "Arch Enemy" +msgstr "Archelyn" + +#. I18N: ./data/achievements.xml +msgid "Hit the same kart at least 5 times in one race." +msgstr "Taro'r un cart o leiaf 5 gwaith mewn un ras." + +#. I18N: ./data/achievements.xml +msgid "Marathoner" +msgstr "Marathonwr" + +#. I18N: ./data/achievements.xml +msgid "Finish a race with at least twice the track's default lap number." +msgstr "Gorffen ras gydag o leiaf ddwywaith rhif lap rhagosodedig y trac." + +#. I18N: ./data/achievements.xml +msgid "Skid-row" +msgstr "Rhes sgidio" + +#. I18N: ./data/achievements.xml +msgid "Skid 5 times in a single lap." +msgstr "Sgidio 5 gwaith mewn un lap." + +#. I18N: ./data/achievements.xml +msgid "Gold driver" +msgstr "Gyrrwr aur" + +#. I18N: ./data/achievements.xml +msgid "" +"Win against at least 3 AIs in normal race, time-trial, and follow the " +"leader." +msgstr "Ennill yn erbyn o leiaf 3 AI mewn ras arferol, treial amser, a dilyn yr arweinydd." + +#. I18N: ./data/achievements.xml +msgid "Powerup Love" +msgstr "Caru Pweru" + +#. I18N: ./data/achievements.xml +msgid "Use 10 or more powerups in a race." +msgstr "Defnyddia 10 pweru neu fwy mewn ras." + +#. I18N: ./data/achievements.xml +msgid "Unstoppable" +msgstr "Anataladwy" + +#. I18N: ./data/achievements.xml +msgid "" +"Win 5 single races in a row against at least 3 AIs. Beware, restarting a " +"race counts as a loss." +msgstr "Enilla 5 ras unigol yn olynol yn erbyn o leiaf 3 AI. Bydd yn ofalus, mae ailgychwyn ras yn cyfrif fel colled." + +#. I18N: ./data/achievements.xml +msgid "Banana Lover" +msgstr "Carwr Bananas" + +#. I18N: ./data/achievements.xml +msgid "Collect at least 5 bananas in one race." +msgstr "Casgla o leiaf 5 banana mewn un ras." + +#. I18N: ./data/achievements.xml +msgid "It's secret" +msgstr "Mae'n gyfrinach" + +#. I18N: ./data/achievements.xml +msgid "Really ... a secret." +msgstr "Wir yn... gyfrinach." + +#. I18N: ./data/achievements.xml +msgid "Mosquito Hunter" +msgstr "Heliwr Mosgito" + +#. I18N: ./data/achievements.xml +msgid "" +"Take your opponents for mosquitos! With the swatter, squash them at least 5 " +"times in a race." +msgstr "Cymra dy wrthwynebwyr fel mosgitos! Gyda'r swatiwr, gwasga nhw o leiaf 5 gwaith mewn ras." + +#. I18N: ./data/achievements.xml +msgid "Beyond Luck" +msgstr "Tu Hwnt i Lwc" + +#. I18N: ./data/achievements.xml +msgid "" +"Win 10 single races in a row in Expert or SuperTux against at least 5 AIs. " +"Beware, restarting a race counts as a loss." +msgstr "Enilla 10 ras unigol yn olynol yn Arbenigwr neu SuperTux yn erbyn o leiaf 5 AI. Bydd yn ofalus, mae ailgychwyn ras yn cyfrif fel colled." + +#. I18N: ./data/grandprix/1_penguinplayground.grandprix +msgid "Penguin Playground" +msgstr "Maes Chwarae Pengwiniaid" + +#. I18N: ./data/grandprix/2_offthebeatentrack.grandprix +msgid "Off the Beaten Track" +msgstr "Oddi ar y Llwybr Caled" + +#. I18N: ./data/grandprix/3_tothemoonandback.grandprix +msgid "To the Moon and Back" +msgstr "I'r Lleuad ac yn Ôl" + +#. I18N: ./data/grandprix/4_atworldsend.grandprix +msgid "At World's End" +msgstr "Ar Ddiwedd y Byd" + +#. I18N: ./data/gui/dialogs/addons_loading.stkgui +#. I18N: Add-on screen action +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +#. I18N: ./data/gui/dialogs/high_score_info_dialog.stkgui +#. I18N: High score info screen action +#. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui +#. I18N: In the server info dialog +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:157 +#: src/states_screens/dialogs/addons_loading.cpp:320 +msgid "Back" +msgstr "Nôl" + +#. I18N: ./data/gui/dialogs/addons_loading.stkgui +#. I18N: Add-on screen action +msgid "Install" +msgstr "Gosod" + +#. I18N: ./data/gui/dialogs/addons_loading.stkgui +#. I18N: Add-on screen action +msgid "Uninstall" +msgstr "Dadosod" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +msgid "Select a type of control that you prefer" +msgstr "Dewisa'r fath o reolaeth rwyt ti eisiau" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: Control type +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 +msgid "Accelerometer" +msgstr "Cyflymydd" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: Control type +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +#. I18N: Race paused button +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 +msgid "Gyroscope" +msgstr "Gyrosgop" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: Control type +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 +msgid "Steering wheel" +msgstr "Olwyn llywio" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Auto acceleration" +msgstr "Cyflymu awto/ceir" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +msgid "You can change it later in touch device settings." +msgstr "Gelli ei newid yn ddiweddarach yng ngosodiadau dy dyfais cyffwrdd." + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +#. I18N: ./data/gui/dialogs/kart_color_slider.stkgui +#. I18N: In the kart color slider dialog +msgid "Apply" +msgstr "Gosod" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +msgid "Touch Device Settings" +msgstr "Gosodiadau Dyfais Cyffwrdd" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "General" +msgstr "Cyffredinol" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Device enabled" +msgstr "Dyfais wedi'i galluogi" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Inverted buttons" +msgstr "Botymau wedi'u gwrthdroi" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Buttons scale" +msgstr "Graddio botymau" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Advanced" +msgstr "Uwch" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Deadzone" +msgstr "Parth marw" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Sensitivity X" +msgstr "Sensitifrwydd X" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Sensitivity Y" +msgstr "Sensitifrwydd Y" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +msgid "Restore defaults" +msgstr "Adfer y rhagosodiadau" + +#. I18N: ./data/gui/dialogs/confirm_dialog.stkgui +#. I18N: In a 'are you sure?' dialog +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +#. I18N: ./data/gui/dialogs/enter_address_dialog.stkgui +#. I18N: In the enter address dialog +#. I18N: ./data/gui/dialogs/general_text_field_dialog.stkgui +#. I18N: In the general textfield dialog +#. I18N: ./data/gui/dialogs/kart_color_slider.stkgui +#. I18N: In the kart color slider dialog +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/dialogs/online/registration_terms.stkgui +#. I18N: In the registration dialog +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +#. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui +#. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +#. I18N: ./data/gui/screens/edit_track.stkgui +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 +#: src/states_screens/online/register_screen.cpp:168 +#: src/states_screens/options/user_screen.cpp:115 +msgid "Cancel" +msgstr "Na" + +#. I18N: ./data/gui/dialogs/confirm_dialog.stkgui +#. I18N: In a 'are you sure?' dialog +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 +#: src/states_screens/edit_gp_screen.cpp:261 +#: src/states_screens/ghost_replay_selection.cpp:394 +#: src/states_screens/high_score_selection.cpp:265 +msgid "Yes" +msgstr "Iawn" + +#. I18N: ./data/gui/dialogs/confirm_resolution_dialog.stkgui +#. I18N: In the 'confirm resolution' dialog, that's shown when switching +#. resoluton +msgid "Revert" +msgstr "Dychwelyd" + +#. I18N: ./data/gui/dialogs/confirm_resolution_dialog.stkgui +#. I18N: In the 'confirm resolution' dialog, that's shown when switching +#. resoluton +#. I18N: ./data/gui/dialogs/online/registration_terms.stkgui +#. I18N: In the registration dialog +msgid "Accept" +msgstr "Derbyn" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +msgid "Camera Settings" +msgstr "Gosodiadau Camera" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera settings +msgid "Player camera" +msgstr "Camera chwaraewr" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "FOV" +msgstr "*FOV" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Distance" +msgstr "Pellter" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Angle" +msgstr "Ongl" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Smooth camera" +msgstr "Camera llyfn" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera settings +msgid "Backward camera" +msgstr "Camera'r cefn" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Follow ball in soccer mode" +msgstr "Dilyn y bêl yn y modd pêl-droed" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Reset" +msgstr "Ailosod" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +msgid "Graphics Settings" +msgstr "Gosodiadau Graffeg" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Advanced pipeline (lights, etc.)" +msgstr "Piblinell uwch (goleuadau, ac ati)" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Shadows" +msgstr "Cysgodion" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Bloom" +msgstr "Blŵm" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Light shaft (God rays)" +msgstr "Siafft golau (pelydrau Duw)" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Ambient occlusion" +msgstr "Achludiad amgylchynol" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Depth of field" +msgstr "Dyfnder ffocws" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Glow (Outlines)" +msgstr "Tywynnu (Amlinelliadau)" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Anti-aliasing" +msgstr "Gwrth-lyfnhau" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Motion blur" +msgstr "Pylu symud" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Image-based lighting" +msgstr "Goleuo ar sail delwedd" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Light Scattering" +msgstr "Gwasgaru Golau" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Animated characters" +msgstr "Nodau animeiddiedig" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Texture compression" +msgstr "Cywasgu gwead" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Particle effects" +msgstr "Effeithiau gronynnau" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Rendered image quality" +msgstr "Ansawdd delwedd wedi'i rendro" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Geometry detail" +msgstr "Manylion geometreg" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "* Restart STK to apply new settings" +msgstr "* Ailgychwyn STK i osod y gosodiadau newydd" + +#. I18N: ./data/gui/dialogs/debug_slider.stkgui +#. I18N: ./data/gui/dialogs/online/recovery_info.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Close" +msgstr "Cau" + +#. I18N: ./data/gui/dialogs/enter_address_dialog.stkgui +#. I18N: In the enter address dialog +#. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui +#. I18N: In the server info dialog +msgid "Join" +msgstr "Ymuno" + +#. I18N: ./data/gui/dialogs/general_text_field_dialog.stkgui +#. I18N: In the general textfield dialog +#. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui +#. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +#. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui +#. I18N: Vote dialog +#. I18N: ./data/gui/screens/edit_track.stkgui +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/dialogs/message_dialog.cpp:127 +#: src/states_screens/dialogs/message_dialog.cpp:138 +#: src/states_screens/dialogs/message_dialog.cpp:143 +msgid "OK" +msgstr "Iawn" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +msgid "Record the race for ghost replay" +msgstr "Recordio'r ras ar gyfer ailchwarae ysbrydion" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +msgid "Watch replay only" +msgstr "Dim ond gwylio'r ailchwarae" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +msgid "Compare to another ghost" +msgstr "Cymharu ag ysbryd arall" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +#. I18N: ./data/gui/dialogs/high_score_info_dialog.stkgui +#. I18N: High score info screen action +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +msgid "Remove" +msgstr "Tynnu" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info screen action +msgid "Compare ghost" +msgstr "Cymharu'r ysbryd" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info screen action +#. I18N: ./data/gui/dialogs/high_score_info_dialog.stkgui +#. I18N: High score info screen action +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +msgid "Start Race" +msgstr "Cychwyn Ras" + +#. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui +#. I18N: Objective shown in achievement dialog +msgid "Goal" +msgstr "Nod" + +#. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui +#. I18N: Progress shown in achievement dialog +#. I18N: Progress in achievement +#: src/states_screens/online/online_profile_achievements.cpp:87 +msgid "Progress" +msgstr "Cynnydd" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +msgid "Password Change" +msgstr "Newid Cyfrinair" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +msgid "Current Password" +msgstr "Cyfrinair Cyfredol" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +msgid "New Password" +msgstr "Cyfrinair Newydd" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "Confirm" +msgstr "Cadarnhau" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +msgid "Submit" +msgstr "Cyflwyno" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +msgid "Back to Race" +msgstr "Nôl i'r Ras" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +msgid "Quit Server" +msgstr "Gadael y Gweinydd" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Show in network ingame dialog to allow user to go back to lobby to +#. end spectating (for example) +msgid "Back to lobby" +msgstr "Yn ôl i'r cyntedd" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 +msgid "Restart Race" +msgstr "Ail Gychwyn Ras" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +#. I18N: Race paused button +msgid "Give Up Race" +msgstr "Rhoi'r Gorau Iddi" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "Options" +msgstr "Dewisiadau" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "Help" +msgstr "Cymorth" + +#. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui +#. I18N: In player rankings dialog +msgid "Top 10 players" +msgstr "Y 10 Chwaraewr Gorau" + +#. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui +msgid "Refresh" +msgstr "Adnewyddu" + +#. I18N: ./data/gui/dialogs/online/recovery_info.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +msgid "Account Recovery" +msgstr "Adfer Cyfrif" + +#. I18N: ./data/gui/dialogs/online/recovery_info.stkgui +#. I18N: In the recovery dialog +msgid "" +"You will receive an email with further instructions on how to reset your " +"password. Please be patient and be sure to check your spam folder." +msgstr "Byddi'n derbyn e-bost gyda chyfarwyddiadau pellach ar sut i ailosod dy gyfrinair. Bydd yn amyneddgar a gwna'n siŵr dy fod yn gwirio dy ffolder sbam." + +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +msgid "" +"Fill in the username and email address you supplied at registration to be " +"able to reset your password." +msgstr "Rho'r enw defnyddiwr a'r cyfeiriad e-bost nes ti eu defnyddio wrth gofrestru er mwyn gallu ailosod dy gyfrinair." + +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 +msgid "Username" +msgstr "Enw Defnyddiwr" + +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "Email" +msgstr "E-bost" + +#. I18N: ./data/gui/dialogs/online/registration_terms.stkgui +#. I18N: In the registration dialog +msgid "Terms and Agreement" +msgstr "Telerau a Chytundeb" + +#. I18N: ./data/gui/dialogs/online/registration_terms.stkgui +#. I18N: In the registration dialog +msgid "I agree to the above terms and am 13 years or older. " +msgstr "Rwy'n cytuno â'r telerau uchod ac rwy'n 13 oed neu'n hŷn. " + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +msgid "Server Configuration" +msgstr "Ffurfweddiad Gweinydd" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Difficulty" +msgstr "Anhawster" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: Difficulty +#: src/race/race_manager.cpp:1317 +msgid "Novice" +msgstr "Dechreuwr" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: Difficulty +#: src/race/race_manager.cpp:1318 +msgid "Intermediate" +msgstr "Canolradd" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: Difficulty +#: src/race/race_manager.cpp:1319 +msgid "Expert" +msgstr "Arbenigwr" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: Difficulty +#: src/race/race_manager.cpp:1320 +msgid "SuperTux" +msgstr "SuperTux" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 +msgid "Game mode" +msgstr "Modd gêm" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Multiplayer game mode +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Multiplayer game mode +#. I18N: Game mode +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 +msgid "Normal Race" +msgstr "Ras Arferol" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Multiplayer game mode +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Multiplayer game mode +#. I18N: Game mode +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 +msgid "Time Trial" +msgstr "Treialon Amser" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Multiplayer game mode +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Multiplayer game mode +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 +msgid "Battle" +msgstr "Brwydr" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Multiplayer game mode +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Multiplayer game mode +#. I18N: Game mode +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 +msgid "Soccer" +msgstr "Pêl-droed" + +#. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Password" +msgstr "Cyfrinair" + +#. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui +#. I18N: In the server info dialog +#: src/states_screens/dialogs/server_info_dialog.cpp:292 +msgid "Bookmark this server" +msgstr "Nod tudalen i'r gweinydd hwn" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "Add player" +msgstr "Ychwanegu chwaraewr" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +#: src/states_screens/online/online_profile_achievements.cpp:78 +msgid "Name" +msgstr "Enw" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "Handicap" +msgstr "Anfantais" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "Press the 'All players ready' button after the player list is ready." +msgstr "Pwysa'r botwm 'Pob chwaraewr yn barod' pan fydd y rhestr chwaraewyr yn barod." + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "Clear players" +msgstr "Clirio'r chwaraewyr" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "All players ready" +msgstr "Pob chwaraewr yn barod" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "User Info" +msgstr "Gwybodaeth Ddefnyddwyr" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Remove Friend" +msgstr "Tynnu Ffrind" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Add Friend" +msgstr "Ychwanegu Ffrind" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Accept Invite" +msgstr "Derbyn Gwahoddiad" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Decline Invite" +msgstr "Gwrthod Gwahoddiad" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "View Profile" +msgstr "Gweld Proffil" + +#. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui +#. I18N: In the vote dialog +msgid "Vote" +msgstr "Pleidleisio" + +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +msgid "Paused" +msgstr "Oedwyd" + +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +msgid "Back to Game" +msgstr "Nôl i'r Gêm" + +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +msgid "Back to menu" +msgstr "Nôl i'r ddewislen" + +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +msgid "Select kart" +msgstr "Dewis cart" + +#. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui +#. I18N: When changing input configurations +msgid "Press fully and release..." +msgstr "Pwysa'n llawn a rhyddhau..." + +#. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui +#. I18N: When configuring input +msgid "Assign to ESC key" +msgstr "Aseinio i allwedd ESC" + +#. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui +#. I18N: When configuring input +msgid "Assign nothing" +msgstr "Aseinio dim byd" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Gosodiadau Fideo gorau" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Bydd y gosodiadau gorau'n ddilys ar gyfer y cyferbyniad cyfredol." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Beth ddylai'r gosodiadau flaenoriaethu?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Perfformiad" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Cydbwyso perfformiad ac ansawdd graffeg" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Ansawdd graffeg" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Arbed ynni" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Ydych chi'n hoffi effeithiau graffeg yn creu pŵl?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Dechreuwch y prawf" + +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: ./data/gui/screens/soccer_setup.stkgui +msgid "Race Setup" +msgstr "Gosodiad Ras" + +#. I18N: ./data/gui/dialogs/tutorial_message_dialog.stkgui +#. I18N: Button in tutorial +#. I18N: ./data/gui/screens/grand_prix_lose.stkgui +#. I18N: ./data/gui/screens/grand_prix_win.stkgui +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: ./data/gui/screens/soccer_setup.stkgui +#. I18N: In soccer setup screen +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 +msgid "Continue" +msgstr "Parhau" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +msgid "SuperTuxKart Addons" +msgstr "Ychwanegion SuperTuxKart" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In addons screen, in the filtering bar, to enable a filter that will +#. show only recently updated items +msgid "Updated" +msgstr "Diweddarwyd" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In addons screen, in the filtering bar, to enable a filter that will +#. show only items with good rating +msgid "Rating >=" +msgstr "Graddio >=" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In the addons screen +msgid "Karts" +msgstr "Cartiau" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In the addons screen +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +msgid "Tracks" +msgstr "Traciau" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In the addons screen +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracks selection screen +msgid "Arenas" +msgstr "Arenau" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In addons screen, above the list of addons to be installed +#: src/states_screens/addons_screen.cpp:138 +msgid "Installed" +msgstr "Wedi'i osod" + +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Golygu hoff arenâu" + +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: track group +#. I18N: ./data/gui/screens/easter_egg.stkgui +#. I18N: track group +#. I18N: track group name +#. I18N: kart group name +#. I18N: track group name +#. I18N: In the UI options, Camera setting: Standard +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 +#: src/states_screens/dialogs/custom_camera_settings.cpp:69 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 +#: src/states_screens/gp_info_screen.cpp:256 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 +msgid "Standard" +msgstr "Safonol" + +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: track group +#. I18N: ./data/gui/screens/easter_egg.stkgui +#. I18N: track group +#. I18N: track group name +#. I18N: kart group name +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 +msgid "Add-Ons" +msgstr "Ychwanegion" + +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: track group +#. I18N: ./data/gui/screens/easter_egg.stkgui +#. I18N: track group +#. I18N: Time filters for add-ons +#. I18N: name of the tab that will show arenas from all groups +#. I18N: track group name +#. I18N: name of the tab that will show tracks from all groups +#. I18N: track group name +#. I18N: name of the tab that will show karts from all groups +#. I18N: kart group/class name +#. I18N: name of the tab that will show tracks from all groups +#. I18N: track group name +#. I18N: name of the tab that will show tracks from all groups +#. I18N: track group name +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 +#: src/states_screens/gp_info_screen.cpp:79 +#: src/states_screens/gp_info_screen.cpp:249 +#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/kart_selection.cpp:321 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 +msgid "All" +msgstr "Y Cyfan" + +#. I18N: ./data/gui/screens/credits.stkgui +#. I18N: Title in credits screen +msgid "Credits" +msgstr "Diolchiadau" + +#. I18N: ./data/gui/screens/cutscene.stkgui +msgid "Skip" +msgstr "Hepgor" + +#. I18N: ./data/gui/screens/easter_egg.stkgui +#. I18N: Section in easter egg tracks selection screen +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/tracks.stkgui +#. I18N: In the track selection screen +msgid "All Tracks" +msgstr "Pob Trac" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Title in edit grand prix screen +msgid "Edit Grand Prix" +msgstr "Golygu Grand Prix" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +msgid "Move up" +msgstr "Symud i fyny" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +msgid "Move down" +msgstr "Symud i lawr" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Add" +msgstr "Ychwanegu" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +msgid "Edit" +msgstr "Golygu" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +msgid "Save" +msgstr "Cadw" + +#. I18N: ./data/gui/screens/edit_track.stkgui +#. I18N: In the edit track screen +msgid "Number of laps:" +msgstr "Nifer o lapiau:" + +#. I18N: ./data/gui/screens/edit_track.stkgui +#. I18N: In the edit track screen +msgid "Reverse:" +msgstr "Am yn Ôl:" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Ghost Replay Selection" +msgstr "Dewis Ailchwarae Ysbrydion" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: Game mode +#: src/race/race_manager.cpp:1304 +msgid "Egg Hunt" +msgstr "Helfa Wyau" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Only show the best times" +msgstr "Dim ond dangos yr amseroedd gorau" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Compare replay" +msgstr "Cymharu'r ailchwarae" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Only show replays matching the current difficulty" +msgstr "Dim ond yn dangos ailchwarae sy'n cyfateb i'r anhawster presennol" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Only show replays matching the current version" +msgstr "Dim ond dangos ailchwaraeon sy'n cyfateb i'r fersiwn gyfredol" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Hide multiplayer replays" +msgstr "Cuddio ailchwarae aml-chwaraewr" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Record a ghost replay" +msgstr "Recordio ailchwarae ysbryd" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +msgid "AI karts" +msgstr "Cartiau AI" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +msgid "Reverse" +msgstr "Am yn Ôl" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +#. I18N: In track screen +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 +msgid "Maximum time (min.)" +msgstr "Uchafswm amser (mun.)" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +msgid "Track group" +msgstr "Grŵp trac" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +#: src/states_screens/gp_info_screen.cpp:164 +msgid "Continue saved GP" +msgstr "Parhau gyda'r GP wedi'i gadw" + +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Title in grand prix editor screen +msgid "Grand Prix editor" +msgstr "Golygydd Grand Prix" + +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +msgid "New" +msgstr "Newydd" + +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +msgid "Copy" +msgstr "Copïo" + +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/online/register_screen.cpp:71 +msgid "Rename" +msgstr "Ailenwi" + +#. I18N: ./data/gui/screens/grand_prix_lose.stkgui +#. I18N: ./data/gui/screens/grand_prix_win.stkgui +msgid "Save Grand Prix" +msgstr "Cadw Grand Prix" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui +msgid "SuperTuxKart Help" +msgstr "Cymorth SuperTuxKart" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Game Modes" +msgstr "Moddau Gêm" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Powerups" +msgstr "Pweriadau" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Bananas" +msgstr "Bananas" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +#: src/io/rich_presence.cpp:501 +msgid "Story Mode" +msgstr "Modd Stori" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Kart classes" +msgstr "Dosbarthiadau cartiau" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Multiplayer" +msgstr "Aml-chwaraewr" + +#. I18N: ./data/gui/screens/help/help1.stkgui +msgid "Start the tutorial" +msgstr "'r tiwtorial" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "Collect blue gift boxes, they will give you powerups." +msgstr "Casgla flychau anrhegion glas, byddan nhw'n rhoi pweriadau i ti." + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +#: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 +msgid "Avoid bananas!" +msgstr "Osgoa fananas!" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "" +"Collecting nitro allows you to get speed boosts whenever you wish by " +"pressing the appropriate key or button. You can see your current level of " +"nitro in the gauge at the bottom-right of the race screen." +msgstr "Mae casglu nitro yn caniatáu i ti gael hwb cyflymder pryd bynnag y byddi eisiau trwy bwyso'r fysell neu'r botwm priodol. Gelli weld dy lefel bresennol o nitro yn y mesurydd ar waelod ochr dde'r sgrin rasio." + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "" +"If you see a button with a lock like this one, you need to complete a " +"challenge to unlock it." +msgstr "Os gweli di fotwm gyda chlo fel hwn, mae'n rhaid i ti gwblhau her i'w ddatgloi." + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "" +"You can skid by pressing a special key or button. Successive short skids " +"help to take sharp turns; while medium skids will boost your speed, long " +"skids more so. You can't stop turning while skidding, so orient your kart " +"carefully before!" +msgstr "Mae modd i ti sgidio trwy bwyso bysell neu fotwm arbennig. Mae sgidiau byr olynol yn helpu i gymryd tro sydyn; tra bydd sgidiau canolig yn rhoi hwb i dy gyflymder, sgidiau hir yn fwy felly. Does dim modd stopio troi wrth sgidio, felly cyfeiria dy gart yn ofalus o'r cychwyn!" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "" +"You can get a startup boost by pressing the accelerate button at 'Set!', " +"before the race's start." +msgstr "Mae modd gael hwb cychwynnol trwy bwyso'r botwm cyflymu yn 'Set!', cyn i'r ras gychwyn." + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: in the help screen +msgid "* Current key bindings can be seen/changed in the Options menu" +msgstr "* Mae modd gweld/newid y dynodiad bysell cyfredol yn y ddewislen Dewisiadau" + +#. I18N: ./data/gui/screens/help/help2.stkgui +msgid "SuperTuxKart features several game modes:" +msgstr "Mae SuperTuxKart yn cynnwys sawl modd gemau:" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"Regular Race: All blows allowed, so collect powerups and use them smartly!" +msgstr "Ras Arferol: Yn caniatáu pob ergyd, felly casgla pweriadau a'u defnyddio'n slic!" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "Time Trial: Contains no powerups, so only your driving skills matter!" +msgstr "Treialon Amser: Nid yw'n cynnwys unrhyw bweriadau, felly dim ond eich sgiliau gyrru sy'n bwysig!" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"Follow the leader: Run for second place, as the last kart will be " +"disqualified every time the counter hits zero. Beware: going in front of the" +" leader will get you eliminated too!" +msgstr "Dilyn yr arweinydd: Rheda am yr ail safle, gan y bydd y cart olaf yn cael ei ddiarddel bob tro y bydd y cownter yn taro sero. Bydd yn ofalus: bydd mynd o flaen yr arweinydd yn dy ddileu hefyd!" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " +"others with weapons until they lose all their lives. In Free-For-All, the " +"player who hits others the most will win in a given hit or time limit. In " +"Capture The Flag, your team needs to bring the flag of the other team to " +"your own flag base, as long as your flag is not captured by the other team." +msgstr "Mae yna 3 math o fodd brwydr: Yn y Frwydr 3 Hergwd, mae angen i ti daro eraill gydag arfau nes iddyn nhw golli eu holl fywydau. Yn y Rhydd i Bawb, y chwaraewr sy'n taro pawb arall fwyaf fydd yn ennill cyfnod neu ergyd benodol. Yn Cipio'r Faner, mae angen i dy dîm ddod â baner y tîm arall i gartref dy faner, cyn belled nad yw dy faner yn cael ei chipio gan y tîm arall." + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "Soccer: Use your kart to push the ball into the goal." +msgstr "Pêl-droed: Defnyddia dy gart i wthio'r bêl i mewn i'r gôl." + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "Egg hunt: Explore tracks to find all hidden eggs." +msgstr "Helfa wyau: Chwilia'r traciau i ddod o hyd i'r holl wyau cudd." + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" +" record your own!" +msgstr "Ailchwarae ysbrydion: Rasio yn erbyn ailchwarae ysbrydion yn y modd treialon amser neu helfa wyau, a chofnodi dy un di!" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"Lap Trial: Complete as many laps as possible in a given amount of time." +msgstr "Treialon Lapiau: Cwblha gymaint o lapiau â phosibl mewn cyfnod penodol o amser." + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"* Many of these game modes can also be played in a Grand Prix fashion: " +"instead of playing a single race, you play many in a row. The better you " +"rank, the more points you get. In the end, the player with the most points " +"wins the cup." +msgstr "* Mae modd chwarae llawer o'r moddau gêm hyn hefyd fel mewn Grand Prix: yn lle chwarae un ras, rwyt ti'n chwarae llawer un ar ôl y llall. Y gorau rwyt ti'n gwneud, y mwyaf o bwyntiau ti'n cael. Yn y diwedd, y chwaraewr gyda'r mwyaf o bwyntiau sy'n ennill y cwpan." + +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: In the help menu +msgid "To help you win, there are some powerups you can collect:" +msgstr "I dy helpu i ennill, mae rhai pweriadau y mae modd i ti eu casglu:" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"BubbleGum - protect yourself with a shield, or use while looking back to " +"leave a sticky pink puddle behind you." +msgstr "GwmSwigod - diogela dy hun gyda tharian, neu ei defnyddio, wrth edrych yn ôl, i adael pwll pinc gludiog ar dy ôl." + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Zipper - will give you a strong speed boost. But beware of not losing " +"control of your kart!" +msgstr "Sipiwr - bydd yn rhoi hwb cyflymder cryf i ti. Ond bydd yn ofalus rhag colli rheolaeth ar dy gart!" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Cake - thrown at the closest rival, best on short ranges and long straights." +" It also affects other karts close to the explosion." +msgstr "Cacen - wedi'i daflu at dy gystadleuydd agosaf, yn orau os yn agos ac ar drac hir a syth. Mae hefyd yn effeithio ar gartiau eraill sy'n agos at y ffrwydrad." + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Plunger - throw straight to pull an opponent back, or throw while looking " +"back to make one lose sight." +msgstr "Plymiwr - tafla'n syth i dynnu dy wrthwynebydd yn ôl, neu ei daflu wrth edrych yn ôl i wneud i un golli golwg." + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Bowling Ball - goes straight until it strikes, it can bounce off walls. If " +"you are looking back, it will be thrown backwards." +msgstr "Pêl Fowlio - yn mynd yn syth nes ei fod yn taro, yna gall fownsio oddi ar y waliau. Os wyt ti'n edrych nôl, bydd yn cael ei daflu am yn ôl." + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "Parachute - slows down all karts in a better position." +msgstr "Parasiwt - yn arafu pob cart sydd mewn sefyllfa well." + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Swapper - gift boxes are transformed into bananas, nitro cans into " +"bubblegums, and vice versa for a short time." +msgstr "Swapiwr - mae blychau rhoddion yn cael eu trawsnewid yn fananas, caniau nitro yn gwm swigod, ac yn ôl am gyfnod byr." + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Basket Ball - bounces after the leader, and might squash and slow down karts" +" down on the way." +msgstr "Pêl Fasged - yn bownsio ar ôl yr arweinydd, ac efallai yn gwasgu ac arafu cartiau ar y ffordd." + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Swatter - will squash karts close by, slowing them down. Can also be used to" +" remove parachutes and bombs." +msgstr "Swatiwr - bydd yn cywasgu cartiau sydd gerllaw, gan eu harafu. Mae modd ei ddefnyddio hefyd i gael gwared ar barasiwtiau a bomiau." + +#. I18N: ./data/gui/screens/help/help4.stkgui +msgid "" +"Hitting a banana can result in one of the following being attached to the " +"kart:" +msgstr "Gall taro banana olygu bod un o'r canlynol yn cydio i'r cart:" + +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: In the help menu +msgid "Anchor - slows down the kart suddenly." +msgstr "Angor - yn arafu'r cart yn sydyn." + +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: In the help menu +msgid "" +"Parachute - slows down the kart, more progressively than the anchor. The " +"faster you go, the stronger it slows you down." +msgstr "Parasiwt - yn arafu'r cart, yn fwy cynyddol na'r angor. Po gyflymaf yr ei di, y cryfaf y bydd yn dy arafu." + +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: In the help menu +msgid "" +"Bomb - detonates after some amount of time, throwing the kart up in the air." +" Bump into another kart to transfer the bomb to it." +msgstr "Bom - bydd yn tanio ar ôl peth amser, gan daflu'r cart i fyny yn yr awyr. Trosglwydda i gert arall drwy daro yn ei erbyn." + +#. I18N: ./data/gui/screens/help/help5.stkgui +msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" +msgstr "Mae'r Nolok drwg wedi cipio Gnu! Dyma rhai awgrymiadau i dy helpu:" + +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: In the help menu +msgid "" +"This icon on the minimap shows the available challenges you've not " +"completed. In the top-right of the screen, it also tells you how many points" +" you currently have. Complete as many challenges as possible, and Nolok will" +" accept to race against you. Win to liberate Gnu!" +msgstr "Mae'r eicon hwn ar y map bychan yn dangos yr heriau sydd ar gael nad wyt ti wedi'u cwblhau. Ar ochr dde uchaf y sgrin, mae hefyd yn dweud wrthyt faint o bwyntiau sydd gennyt ar hyn o bryd. Ceisia gwblhau gynifer o heriau â phosibl, a bydd Nolok yn derbyn yr her o rasio yn dy erbyn. Rhaid ennill i ryddhau Gnu!" + +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: In the help menu +msgid "" +"When you complete a challenge, you get a cup. Each cup is worth several " +"points. The higher the difficulty you completed the challenge in, the better" +" the cup and the more points it is worth." +msgstr "Pan fyddi wedi cwblhau her, rwyt ti'n cael cwpan. Mae pob cwpan yn werth sawl pwynt. Po fwyaf yr anhawster yr her, y gorau yw'r cwpan a'r mwyaf o bwyntiau y mae'n werth." + +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: In the help menu +msgid "" +"When you get the number of points indicated below this icon, you'll be " +"gifted a surprise. There are several to collect." +msgstr "Pan gei di'r nifer o bwyntiau sy'n cael eu dangos o dan yr eicon hwn, byddi'n cael syrpreis. Mae yna sawl un i'w casglu." + +#. I18N: ./data/gui/screens/help/help6.stkgui +msgid "" +"Not all karts drive the same! They belong to classes with several " +"differences:" +msgstr "Nid yw pob cart yn gyrru'r un peth! Maen nhw'n perthyn i ddosbarthiadau gyda nifer o wahaniaethau:" + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"Mass - there are three classes of karts, depending on their mass: light, " +"medium and heavy. Heavier karts are less affected by parachutes and are more" +" resistant to explosions." +msgstr "Màs - mae tri dosbarth o gartiau, yn dibynnu ar eu màs: ysgafn, canolig a thrwm. Mae cartiau trymach yn cael eu heffeithio llai gan barasiwtiau ac maen nhw'n gallu gwrthsefyll ffrwydradau yn well." + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"Acceleration - especially useful at start, after an accident, or in tracks " +"with a lot of sharp curves. The lighter the kart, the faster it accelerates," +" especially at low speeds." +msgstr "Cyflymiad - yn arbennig o ddefnyddiol ar y cychwyn, ar ôl damwain, neu mewn traciau gyda llawer o droadau tynn. Po ysgafnaf yw'r cart, y cyflymaf y mae'n cyflymu, yn enwedig ar gyflymder isel." + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"Max speed - the higher it is, the faster the kart can go. Especially useful " +"in tracks with straight lines and gentle curves. Heavier karts have a higher" +" top speed." +msgstr "Cyflymder uchaf - po uchaf ydyw, y cyflymaf y gall y cart fynd. Yn arbennig o ddefnyddiol mewn traciau gyda llinellau syth a throadau mawr. Mae gan gartiau trymach gyflymder uchaf uwch." + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"Nitro efficiency - The higher it is, the more speed you get from a can of " +"nitro. A lighter kart will have higher nitro efficiency." +msgstr "Effeithlonrwydd nitro - po uchaf yw hi, y mwyaf o gyflymder gewch o gan o nitro. Bydd gan gart ysgafnach effeithlonrwydd nitro uwch." + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"If you follow closely another kart for a few seconds, you'll get a " +"slipstream speed bonus when you overtake it. The lighter your kart, the " +"easier it is." +msgstr "Os dilynwch gert arall yn agos am ychydig eiliadau, fe gewch chi fonws cyflymder sgilwynt pan fyddwch chi'n ei basio. Po ysgafnaf yw eich cart, yr hawsaf yw i wneud hynny." + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "SuperTuxKart can be played in multiplayer mode online...:" +msgstr "Mae'n bosibl chwarae SuperTuxKart yn y modd aml-chwaraewr ar-lein...:" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "" +"First, select the 'online' icon in the main menu. Choose either local " +"networking, or global networking (requires internet to be enabled in the " +"options). Then, you can either create your own server with custom options, " +"or search among a list of existing servers to join. Some of them are " +"recommended servers with optionally ranked races." +msgstr "Yn gyntaf, dewisa'r eicon 'ar-lein' yn y brif ddewislen. Dewisa naill ai rhwydweithio lleol, neu rwydweithio byd-eang (mae angen galluogi rhyngrwyd yn y Dewisiadau). Yna, gelli naill ai greu dy weinydd dy hun gyda dewisiadau arferol, neu chwilio ymhlith rhestr o weinyddion cyfredol i ymuno â nhw. Mae rhai ohonyn nhw'n weinyddion sy'n cael eu hargymell, gyda rasys o ddewis wedi'u rhestru." + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "" +"Once in a server, a race will begin once its owner (symbolized with the " +"crown) decides so. Official servers may auto-start races only when there are" +" enough players. Then, you can choose your kart and vote for the next track " +"to race on. An addon track is allowed only if it exists on all joined " +"players and the server." +msgstr "Unwaith o fewn gweinydd, bydd ras yn cychwyn unwaith y bydd ei berchennog (wedi'i symboleiddio â'r goron) yn penderfynu gwneud hynny. Dim ond pan fydd digon o chwaraewyr ar gael y gall gweinyddwyr swyddogol gychwyn rasys yn awtomatig. Yna, gelli ddewis dy gart a phleidleisio dros y trac nesaf i rasio arno. Mae trac ychwanegol yn cael ei ganiatáu dim ond os yw'n bodoli ar yr holl chwaraewyr sydd wedi ymuno a'r gweinydd." + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "... or on the same device:" +msgstr "... neu ar yr un ddyfais:" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "" +"First, you will need several input devices. Use the input configuration " +"screen to set them up. Multiple gamepads or joysticks are ideal: on " +"keyboard(s), each player will need a different set of keys, and most " +"keyboards are not appropriate for multiplayer because they don't support " +"multiple simultaneous keypresses." +msgstr "Yn gyntaf, bydd angen sawl dyfais mewnbwn arnat ti. Defnyddia'r sgrin ffurfweddu mewnbwn i'w gosod. Padiau gêm neu ffyn reoli yr un sydd orau. Ar fysellfyrddau, bydd angen set gwahanol o allweddi ar bob chwaraewr, ac nid yw'r rhan fwyaf o fysellfyrddau yn briodol ar gyfer aml-chwaraewr oherwydd nad ydyn nhw'n cynnal gwasgu bysellfyrddau lluosog ar yr un pryd." + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "" +"When input devices are configured, select the 'Splitscreen Multiplayer' icon" +" in the main menu. Each player can press the 'fire' key of their gamepad or " +"keyboard to join the game, and use their input device to select their kart. " +"The game continues when everyone selected their kart. Note that the mouse " +"may not be used for this operation." +msgstr "Pan fydd dyfeisiau mewnbwn wedi'u ffurfweddu, dewisa'r eicon 'Sgrin Hollt Aml-chwaraewr' yn y brif ddewislen. Gall pob chwaraewr bwyso bysell 'fire' eu pad gêm neu fysellfwrdd i ymuno â'r gêm, a defnyddio eu dyfais fewnbynnu i ddewis eu cart. Mae'r gêm yn parhau ar ôl i bawb ddewis eu cart. Nid oes modd defnyddio llygoden i wneud hyn." + +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +msgid "High Score Selection" +msgstr "Dewisiadau Sgôr Uchel" + +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: Game mode +#. I18N: Lap Trial: Complete as many laps as possible in a given amount of +#. time. +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 +msgid "Lap Trial" +msgstr "Treialon Lapio" + +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 +#: src/states_screens/dialogs/select_challenge.cpp:51 +#: src/states_screens/high_score_selection.cpp:139 +msgid "Grand Prix" +msgstr "Grand Prix" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the kart selection (player setup) screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the kart selection (player setup) screen +msgid "Choose a Kart" +msgstr "Dewis Cart" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Dosbarth Cart" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Golygu hoff gartiau" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +msgid "Singleplayer" +msgstr "Chwaraewr unigol" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +msgid "Splitscreen Multiplayer" +msgstr "Sgrin Hollt Aml-chwaraewr" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/online/online_profile_friends.cpp:245 +msgid "Online" +msgstr "Ar-lein" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +msgid "Addons" +msgstr "Ychwanegion" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +#: src/states_screens/race_gui_overworld.cpp:530 +msgid "Tutorial" +msgstr "Tiwtorial" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +#: src/states_screens/track_info_screen.cpp:343 +msgid "High Scores" +msgstr "Sgoriau Uchel" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +#. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui +#. I18N: Section in the profile screen +#: src/states_screens/online/online_profile_base.cpp:113 +msgid "Achievements" +msgstr "Llwyddiannau" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "Grand Prix Editor" +msgstr "Golygydd Grand Prix" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "About" +msgstr "Ynghylch" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Server Creation" +msgstr "Creu Gweinydd" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Name of the server" +msgstr "Enw'r gweinydd" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Max. number of players" +msgstr "Uchafwsm nifer o chwaraewyr" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Password for private server (optional)" +msgstr "Cyfrinair ar gyfer gweinydd preifat (dewisol)" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Create" +msgstr "Creu" + +#. I18N: ./data/gui/screens/online/lan.stkgui +msgid "Local Networking" +msgstr "Rhwydweithio Lleol" + +#. I18N: ./data/gui/screens/online/lan.stkgui +#. I18N: In the online multiplayer screen +#. I18N: ./data/gui/screens/online/profile_servers.stkgui +#. I18N: In the online multiplayer screen +msgid "Find Server" +msgstr "Canfod Gweinydd" + +#. I18N: ./data/gui/screens/online/lan.stkgui +#. I18N: In the online multiplayer screen +#. I18N: ./data/gui/screens/online/profile_servers.stkgui +#. I18N: In the online multiplayer screen +#: src/states_screens/online/create_server_screen.cpp:108 +msgid "Create Server" +msgstr "Creu Gweinydd" + +#. I18N: ./data/gui/screens/online/networking_lobby.stkgui +#. I18N: In networking lobby +#. I18N: In the networking lobby +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 +msgid "Lobby" +msgstr "Cyntedd" + +#. I18N: ./data/gui/screens/online/networking_lobby.stkgui +#. I18N: In the network lobby +#. I18N: In networking lobby to configuration server settings +#: src/states_screens/online/networking_lobby.cpp:201 +msgid "Configuration" +msgstr "Ffurfweddiad" + +#. I18N: ./data/gui/screens/online/networking_lobby.stkgui +#. I18N: In the network lobby +#: src/states_screens/online/networking_lobby.cpp:193 +msgid "Start race" +msgstr "Cychwyn y ras" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: In the networking menu +msgid "Enable splitscreen or player handicaps" +msgstr "Galluogi anfanteision sgrin hollt neu chwaraewr" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: Networking menu button +msgid "Local networking" +msgstr "Rhwydweithio lleol" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: Networking menu button +msgid "Global networking" +msgstr "Rhwydweithio byd-eang" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: Networking menu button +msgid "Enter server address" +msgstr "Rhoi cyfeiriad y gweinydd" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: Networking menu button +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 +msgid "Your profile" +msgstr "Dy broffil" + +#. I18N: ./data/gui/screens/online/profile_achievements.stkgui +#. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui +#. I18N: ./data/gui/screens/online/profile_friends.stkgui +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +msgid "..." +msgstr "..." + +#. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui +#. I18N: In the achievements screen +msgid "Player rankings" +msgstr "Safle chwaraewyr" + +#. I18N: ./data/gui/screens/online/profile_friends.stkgui +#. I18N: Section in the profile screen +#: src/states_screens/online/online_profile_base.cpp:112 +msgid "Friends" +msgstr "Ffrindiau" + +#. I18N: ./data/gui/screens/online/profile_friends.stkgui +#. I18N: In the profile screen +msgid "Look for more friends:" +msgstr "Chwilio am ragor o ffrindiau:" + +#. I18N: ./data/gui/screens/online/profile_friends.stkgui +#. I18N: ./data/gui/screens/online/user_search.stkgui +msgid "Search" +msgstr "Chwilio" + +#. I18N: ./data/gui/screens/online/profile_servers.stkgui +msgid "Global Networking" +msgstr "Rhwydweithio Byd-eang" + +#. I18N: ./data/gui/screens/online/profile_servers.stkgui +#. I18N: In the online multiplayer screen +msgid "Quick Play" +msgstr "Chwarae Cyflym" + +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +#. I18N: Section in the profile screen +#: src/states_screens/online/online_profile_base.cpp:114 +msgid "Account Settings" +msgstr "Gosodiadau Cyfrif" + +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +#. I18N: In the online account settings screen +msgid "Password:" +msgstr "Cyfrinair:" + +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +msgid "Change" +msgstr "Newid" + +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +#. I18N: In the online account settings screen +msgid "E-mail:" +msgstr "E-bost:" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +#: src/states_screens/online/register_screen.cpp:73 +msgid "Create User" +msgstr "Creu Defnyddiwr" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: Section in the register screen +msgid "New Online Account" +msgstr "Cyfrif Ar-lein Newydd" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: Section in the register screen +msgid "Existing Online Account" +msgstr "Cyfrif Ar-lein Cyfredol" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: Section in the register screen +msgid "Offline Account" +msgstr "Cyfrif All-lein" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "Local Name" +msgstr "Enw Lleol" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "Online Username" +msgstr "Enw Defnyddiwr Ar-lein" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui +msgid "Reset password" +msgstr "Ailosod cyfrinair" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "" +"You can play without creating an online account by selecting an offline " +"account. Though then you can not connect to friends, vote for addons etc. " +"Please read our privacy statement at https://privacy.supertuxkart.net" +msgstr "Mae modd i ti chwarae heb greu cyfrif ar-lein trwy ddewis cyfrif all-lein. Er hynny nid oes modd i ti gysylltu â ffrindiau, pleidleisio dros ategion ac ati. Darllena ein datganiad preifatrwydd yn https://privacy.supertuxkart.net" + +#. I18N: ./data/gui/screens/online/server_selection.stkgui +#: src/states_screens/online/server_selection.cpp:578 +msgid "Server Selection" +msgstr "Dewis Gweinydd" + +#. I18N: ./data/gui/screens/online/server_selection.stkgui +#. I18N: In the server selection screen +msgid "Show private server(s)" +msgstr "Dangos gweinydd(ion) preifat" + +#. I18N: ./data/gui/screens/online/server_selection.stkgui +#. I18N: In the server selection screen +msgid "Use IPv6 connection" +msgstr "Defnyddio cysylltiad IPv6" + +#. I18N: ./data/gui/screens/online/user_search.stkgui +msgid "User search" +msgstr "Chwilio defnyddiwr" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +msgid "SuperTuxKart Options" +msgstr "Dewisiadau SuperTuxKart" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Dangos" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Graphics" +msgstr "Graffigau" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Audio" +msgstr "Sain" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Interface" +msgstr "Rhyngwyneb" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Players" +msgstr "Chwaraewyr" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Controls" +msgstr "Rheolyddion" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Language" +msgstr "Iaith" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: In the audio options screen +msgid "Music" +msgstr "Cerddoriaeth" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: In the audio options screen +#. I18N: in the graphical options tooltip; +#. indicates a graphical feature is enabled +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 +msgid "Enabled" +msgstr "Galluogwyd" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: In the audio options screen +msgid "Volume" +msgstr "Lefel Sain" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: In the audio options screen +msgid "Sound Effects" +msgstr "Effeithiau Sain" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen +msgid "Delete Configuration" +msgstr "Dileu Ffurfweddiad" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen +#. I18N: button to disable a keyboard configuration +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 +msgid "Disable Configuration" +msgstr "Analluogi Ffurfweddu" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen +msgid "Back to device list" +msgstr "Nôl i'r rhestr dyfeisiau" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen +msgid "Rename Configuration" +msgstr "Ailenwi Ffurfweddiad" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen, for gamepad +msgid "Enable force feedback (if supported)" +msgstr "Galluogi adborth grym (os caiff ei gefnogi)" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Cydraniad" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Sgrin Lawn" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Cofio lleoliad ffenestr" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Gosod cydraniad newydd" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Cynllun Sgrin Hollt Aml-chwaraewr" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Internet options" +msgstr "Dewisiadau rhyngrwyd" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Always show login screen" +msgstr "Dangos y sgrin mewngofnodi bob tro" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Connect to the Internet" +msgstr "Cysylltu â'r Rhyngrwyd" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Enable chatting in online lobbies" +msgstr "Galluogi sgwrsio mewn lobïau ar-lein" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Enable chatting in online matches" +msgstr "Galluogi sgwrsio mewn gemau ar-lein" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Miscellaneous options" +msgstr "Dewisiadau amrywiol" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Enable per-player handicaps" +msgstr "Galluogi anfanteision fesul chwaraewr" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: For mobile version for STK, uninstall the downloaded assets +#: src/states_screens/options/options_screen_general.cpp:79 +msgid "Uninstall full game assets" +msgstr "Dadosod asedau gêm llawn" + +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: In the input configuration screen +#: src/states_screens/options/options_screen_input.cpp:191 +msgid "Press enter or double-click on a device to configure it" +msgstr "Pwysa Enter neu clicio ddwywaith ar ddyfais i'w ffurfweddu" + +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: In the input configuration screen +msgid "Add a device" +msgstr "Ychwanegu dyfais" + +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: In the input configuration screen +msgid "" +"* Which config to use will be inferred from which 'Select' key is pressed to" +" join the game." +msgstr "* Bydd pa ffurfweddiad i'w ddefnyddio yn cael ei gasglu o ba fysell 'Dewis' sy'n cael ei bwyso i ymuno â'r gêm." + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Skin" +msgstr "Croen" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Skin variant" +msgstr "Amrywiad croen" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Minimap" +msgstr "Map Bychan" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Font size" +msgstr "Maint ffont" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Camera" +msgstr "Camera" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Custom..." +msgstr "Cyfaddasu..." + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Display FPS" +msgstr "Dangos FPS" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Show other karts' held powerups" +msgstr "Dangos pweriadau cartiau eraill" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Enable the story mode timer" +msgstr "Galluogi'r amserydd modd stori" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Enable the speedrun timer" +msgstr "Galluogi'r amserydd rhediad cyflym" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Render resolution" +msgstr "Cydraniad rendro" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Graphical Effects Level" +msgstr "Lefel Effeithiau Graffigol" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Blur Effects Level" +msgstr "Lefel Effeithiau Pwl" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video options, maximum frame per second +msgid "Maximum FPS" +msgstr "Uchafswm FPS" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Custom settings..." +msgstr "Gosodiadau cyfaddas..." + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Performance tests" +msgstr "Profion perfformiad" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Performance test of the current settings" +msgstr "Prawf perfformiad o'r gosodiadau cyfredol" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Cofio cyfrinair" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Dileu" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Lliw cart" + +#. I18N: ./data/gui/screens/race_setup.stkgui +msgid "Select a difficulty" +msgstr "Dewis anhawster" + +#. I18N: ./data/gui/screens/race_setup.stkgui +msgid "Select a game mode" +msgstr "Dewis pa fodd gêm" + +#. I18N: ./data/gui/screens/soccer_setup.stkgui +#. I18N: In soccer setup screen +msgid "Use left/right to choose your team and press fire" +msgstr "Defnyddio chwith/dde i ddewis dy dîm a phwyso'r botwm tanio" + +#. I18N: ./data/gui/screens/soccer_setup.stkgui +#. I18N: In soccer setup screen +msgid "Red Team" +msgstr "Tîm Coch" + +#. I18N: ./data/gui/screens/soccer_setup.stkgui +#. I18N: In soccer setup screen +msgid "Blue Team" +msgstr "Tîm Glas" + +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 +msgid "Number of laps" +msgstr "Nifer o lapiau" + +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 +msgid "Number of AI karts" +msgstr "Nifer y cartiau AI" + +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +msgid "Number of blue team AI karts" +msgstr "Nifer y cartiau AI tîm glas" + +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +#: src/race/grand_prix_data.cpp:623 +msgid "Random Grand Prix" +msgstr "Grand Prix ar hap" + +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Golygu hoff draciau" + +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: Used as a verb, appears on the main networking menu (login button) +#: src/states_screens/online/online_screen.cpp:69 +msgid "Login" +msgstr "Mewngofnodi" + +#. I18N: ./data/tips.xml +msgid "The UI skin can be changed in the UI options." +msgstr "Mae modd newid croen y rhyngwyneb yn Newisiadau'r rhyngwyneb." + +#. I18N: ./data/tips.xml +msgid "You can see other karts' powerups by enabling it in the UI options." +msgstr "Mae modd gweld pweriadau cartiau eraill trwy ei alluogi yn Newidiadau'r Rhyngwyneb." + +#. I18N: ./data/tips.xml +msgid "The font size can be changed in the UI options." +msgstr "Mae modd newid maint y ffont yn Newidiadau'r Rhyngwyneb." + +#. I18N: ./data/tips.xml +msgid "The help menu has lots of useful information." +msgstr "Mae llawer o wybodaeth ddefnyddiol yn y ddewislen Cymorth." + +#. I18N: ./data/tips.xml +msgid "In single-player, you can watch and challenge recorded time-trials." +msgstr "Fel chwaraewr unigol, mae modd gwylio a herio profion amser wedi'u recordio." + +#. I18N: ./data/tips.xml +msgid "" +"You can visit https://supertuxkart.net/ for more information about the game." +msgstr "Mae ragor o wybodaeth am y gêm yn https://supertuxkart.net/." + +#. I18N: ./data/tips.xml +msgid "Short nitro boosts are more efficient." +msgstr "Mae hybiau nitro byr yn fwy effeithlon." + +#. I18N: ./data/tips.xml +msgid "Only use zippers when it is safe. Long straight lines are ideal." +msgstr "Defnyddia Sipiau dim ond pan fydd yn ddiogel. Traciau hir a syth sydd orau." + +#. I18N: ./data/tips.xml +msgid "" +"Don't use multiple zippers quickly in row, instead, wait until the speed " +"boost wears off." +msgstr "Paid â defnyddio sipiau lluosog yn gyflym un ar ôl y llall, arhosa nes bod yr hwb cyflymder yn pylu." + +#. I18N: ./data/tips.xml +msgid "Skidding makes you much faster, do it whenever safe." +msgstr "Mae sgidio yn dy wneud yn llawer cyflymach, gwna hynny pryd bynnag mae'n ddiogel." + +#. I18N: ./data/tips.xml +msgid "The swatter can be used to remove bombs or parachutes." +msgstr "Mae modd defnyddio'r swatiwr i ddileu bomiau neu barasiwtiau." + +#. I18N: ./data/tips.xml +msgid "" +"You can't stop turning while skidding. Good kart orientation at the skid's " +"start is paramount." +msgstr "Nid oes modd peidio â throi wrth sgidio. Mae gosod cyfeiriad y cart ar gychwyn y sgid yn hollbwysig." + +#. I18N: ./data/tips.xml +msgid "You get a startup boost if you start accelerating during \"Set\"." +msgstr "Byddi'n cael hwb cychwyn os byddi'n cychwyn cyflymu yn ystod \"Set\"." + +#. I18N: ./data/tips.xml +msgid "Braking allows to get rid of parachutes quicker." +msgstr "Mae brecio'n caniatáu i ti gael gwared ar barasiwtiau yn gyflymach." + +#. I18N: ./data/tips.xml +msgid "First and foremost, focus on where your kart is going." +msgstr "Yn gyntaf oll, canolbwyntia ar ble mae'ch cart yn mynd." + +#. I18N: ./data/tips.xml +msgid "The rescue key (button) is very useful." +msgstr "Mae'r allwedd achub (botwm) yn ddefnyddiol iawn." + +#. I18N: ./data/tips.xml +msgid "Be careful when close to other karts, they may attack you!" +msgstr "Bydd yn ofalus pan fyddi'n agos at gartiau eraill, efallai y byddan nhw'n ymosod arnat ti!" + +#. I18N: ./data/tips.xml +msgid "" +"Basketballs can be destroyed using precise backward shots with a bowling " +"ball, cake, or plunger." +msgstr "Mae modd dinistrio peli-fasged gan ddefnyddio ergydion manwl tuag yn ôl gyda phêl fowlio, cacen, neu blymiwr." + +#. I18N: ./data/tips.xml +msgid "" +"Try to avoid crashing into the backs of other karts as this will slow you " +"down." +msgstr "Ceisia osgoi taro i mewn i gefn cartiau eraill gan y bydd hyn yn dy arafu." + +#. I18N: ./data/tips.xml +msgid "You can use bowling balls to push and block the ball." +msgstr "Gelli ddefnyddio peli bowlio i wthio a rhwystro'r bêl." + +#. I18N: ./data/tips.xml +msgid "In soccer, always work as a team for good results." +msgstr "Mewn pêl-droed, gweithiwch fel tîm bob amser i gael canlyniadau da." + +#. I18N: ./data/tips.xml +msgid "" +"If you miss the ball and an opponent is approaching, try hitting them with a" +" powerup or block their way." +msgstr "Os byddi'n colli'r bêl a bod gwrthwynebydd yn agosáu, ceisia eu taro â phweriad neu rwystro'u ffordd." + +#. I18N: ./data/tips.xml +msgid "Good rotation of positions (attack and defense) is essential." +msgstr "Mae symud safleoedd effeithiol (ymosod ac amddiffyn) yn hanfodol." + +#. I18N: ./data/tips.xml +msgid "Make sure to store at least 2 big cans worth of nitro." +msgstr "Gwna'n siŵr dy fod yn storio o leiaf 2 gan fawr o nitro." + +#. I18N: ./data/tips.xml +msgid "Never use the three bowling balls all at the same time." +msgstr "Peidia byth â defnyddio'r tair pêl bowlio i gyd ar yr un pryd." + +#. I18N: ./data/tips.xml +msgid "" +"Don't get in the way of a teammate carrying the ball, though you can try to " +"hit opponents attempting to stop them from scoring." +msgstr "Paid â rhwystro cyd-chwaraewr rhag cario'r bêl, er y gelli geisio taro gwrthwynebwyr sy'n ceisio ei atal rhag sgorio." + +#. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml +msgid "Adiumy" +msgstr "Adiumy" + +#. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml +msgid "Amanda" +msgstr "Amanda" + +#. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml +msgid "Godette" +msgstr "Godette" + +#. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml +msgid "Emule" +msgstr "Emule" + +#. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml +msgid "Gavroche" +msgstr "Gavroche" + +#. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml +msgid "Gnu" +msgstr "Gnu" + +#. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml +msgid "Hexley" +msgstr "Hexley" + +#. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml +msgid "Kiki" +msgstr "Kiki" + +#. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml +msgid "Konqi" +msgstr "Konqi" + +#. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml +msgid "Nolok" +msgstr "Nolok" + +#. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml +msgid "Pidgin" +msgstr "Pidgin" + +#. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml +msgid "Puffy" +msgstr "Puffy" + +#. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml +msgid "Pepper" +msgstr "Pupur" + +#. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml +msgid "Sara" +msgstr "Sara" + +#. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml +msgid "Suzanne" +msgstr "Suzanne" + +#. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml +msgid "Tux" +msgstr "Tux" + +#. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml +msgid "Wilber" +msgstr "Wilber" + +#. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml +msgid "Xue" +msgstr "Xue" + +#. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml +msgid "Antediluvian Abyss" +msgstr "Bwlch y Cynfyd" + +#. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml +msgid "Alien Signal" +msgstr "Arwydd Estron" + +#. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml +msgid "Ancient Colosseum Labyrinth" +msgstr "Hen Ddrysle'r Colosseum" + +#. I18N: ../stk-assets/tracks/arena_candela_city/track.xml +#. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml +msgid "Candela City" +msgstr "Dinas Candela" + +#. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml +msgid "Battle Island" +msgstr "Ynys y Frwydr" + +#. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml +msgid "Black Forest" +msgstr "Coedwig Ddu" + +#. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml +msgid "Cave X" +msgstr "Ogof X" + +#. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml +msgid "Cocoa Temple" +msgstr "Teml Coco" + +#. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml +msgid "Cornfield Crossing" +msgstr "Croesfan Maes Grawn" + +#. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml +msgid "Fort Magma" +msgstr "Caer Magma" + +#. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml +msgid "Gran Paradiso Island" +msgstr "Ynys Gran Paradiso" + +#. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml +msgid "Hacienda" +msgstr "Hacienda" + +#. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml +msgid "Hole Drop" +msgstr "Pant Twll" + +#. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml +msgid "Icy Soccer Field" +msgstr "Maes Pêl-droed Oer" + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "What's wrong, little hippies? Your great gnu leader is missing?" +msgstr "Beth sy'n bod, hipis bach? Mae'ch arweinydd gnu gwych ar goll?" + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "Oh yes, see, he's in my castle now and will be served for supper..." +msgstr "O ie, edrychwch, mae yn fy nghastell i nawr a bydd yn cael ei weini fel swper..." + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "But I'm a fair creature, so I'll make you a deal." +msgstr "Ond rwy'n creadur teg, felly fe wna i fargen â chi." + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "If you can beat me at racing, I will free the old codger." +msgstr "Os gallwch chi fy nghuro wrth rasio, mi wna i ryddhau'r hen ddyn." + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "" +" But you pathetic little twerps will never be able to beat me - King of the " +"Karts!" +msgstr " Ond fydd dim modd i drueiniaid bach anobeithiol fel chi fy nghuro i - Brenin y Cartiau!" + +#. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml +msgid "Las Dunas Arena" +msgstr "Arena Las Dunas" + +#. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml +msgid "Las Dunas Soccer Stadium" +msgstr "Stadiwm Pêl-droed Las Dunas" + +#. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml +msgid "Around the Lighthouse" +msgstr "O Amgylch y Goleudy" + +#. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml +msgid "Old Mine" +msgstr "Hen Fwynglawdd" + +#. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml +msgid "Minigolf" +msgstr "Minigolff" + +#. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml +msgid "Oasis" +msgstr "Oasis" + +#. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml +msgid "Oliver's Math Class" +msgstr "Dosbarth Mathemateg Oliver" + +#. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml +msgid "Pumpkin Park" +msgstr "Parc Pwmpen" + +#. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml +msgid "Ravenbridge Mansion" +msgstr "Plasty Ravenbridge" + +#. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml +msgid "Shifting Sands" +msgstr "Twyni Symudol" + +#. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml +msgid "Nessie's Pond" +msgstr "Pwll Nessie" + +#. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml +msgid "Northern Resort" +msgstr "Gwyliau'r Gogledd" + +#. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml +msgid "Snow Peak" +msgstr "Copa Eira" + +#. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml +msgid "Soccer Field" +msgstr "Maes Pêl-droed" + +#. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml +msgid "The Stadium" +msgstr "Y Stadiwm" + +#. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml +msgid "STK Enterprise" +msgstr "Menter STK" + +#. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml +msgid "Temple" +msgstr "Teml" + +#. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml +msgid "Volcan Island" +msgstr "Ynys Volcan" + +#. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml +msgid "XR591" +msgstr "XR591" + +#. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml +msgid "Zen Garden" +msgstr "Gardd Zen" + +#: src/achievements/achievement.cpp:387 +#, c-format +msgid "Completed achievement \"%s\"." +msgstr "Cwblhawyd cyflawniad \"%s\"." + +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 +msgid "Failed to connect to the SuperTuxKart add-ons server." +msgstr "Wedi methu â chysylltu â gweinydd ychwanegion SuperTuxKart." + +#: src/addons/news_manager.cpp:184 +#, c-format +msgid "Error downloading news: '%s'." +msgstr "Gwall wrth lwytho newyddion: '%s'." + +#: src/challenges/challenge_data.cpp:303 src/network/server_config.cpp:261 +msgid "Normal Race (Grand Prix)" +msgstr "Ras Arferol (Grand Prix)" + +#: src/challenges/challenge_data.cpp:305 +msgid "Time-Trial (Grand Prix)" +msgstr "Treialon Amser (Grand Prix)" + +#: src/challenges/challenge_data.cpp:310 +msgid "Time-Trial - beat the replay" +msgstr "Treialon Amser - curo'r ailchwarae" + +#: src/challenges/challenge_data.cpp:312 +msgid "Time-Trial - nitro challenge" +msgstr "Treialon Amser - her nitro" + +#: src/challenges/challenge_data.cpp:314 +msgid "Normal Race (single race)" +msgstr "Ras Arferol (ras unigol)" + +#: src/challenges/challenge_data.cpp:316 +msgid "Time-Trial (single race)" +msgstr "Treialon Amser (ras unigol)" + +#: src/challenges/challenge_data.cpp:318 +msgid "Follow the Leader (single race)" +msgstr "Dilyn yr Arweinydd (ras unigol)" + +#. I18N: In the Select challenge dialog, tell user this challenge has reversed +#. laps +#: src/challenges/challenge_data.cpp:324 +#: src/states_screens/dialogs/select_challenge.cpp:78 +msgid "Mode: Reverse" +msgstr "Modd: Am yn Ôl" + +#: src/challenges/challenge_data.cpp:601 +#, c-format +msgid "New track '%s' now available" +msgstr "Mae trac newydd '%s' ar gael nawr" + +#: src/challenges/challenge_data.cpp:605 +#, c-format +msgid "New game mode '%s' now available" +msgstr "Mae modd gêm newydd '%s' ar gael nawr" + +#: src/challenges/challenge_data.cpp:615 +#, c-format +msgid "New Grand Prix '%s' now available" +msgstr "Mae Grand Prix '%s' newydd ar gael nawr" + +#: src/challenges/challenge_data.cpp:619 +#, c-format +msgid "New difficulty '%s' now available" +msgstr "Mae anhawster newydd '%s' ar gael nawr" + +#: src/challenges/challenge_data.cpp:629 +#, c-format +msgid "New kart '%s' now available" +msgstr "Mae cart newydd '%s' ar gael nawr" + +#: src/challenges/story_mode_timer.cpp:281 +#: src/states_screens/options/options_screen_ui.cpp:280 +msgid "" +"Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" +"\n" +"Closing the game before the story mode's completion invalidates the timer.\n" +"\n" +"To use the speedrun mode, please use a new profile." +msgstr "Mae Rhediad Cyflym wedi'i analluogi. Dim ond os nad yw'r gêm wedi cau ers lansio'r modd stori y mae modd ei alluogi.\n\nMae cau'r gêm cyn cwblhau'r modd stori yn annilysu'r amserydd.\n\nI ddefnyddio'r modd Rhediad Cyflym, defnyddia broffil newydd." + +#. I18N: Name of first guest player (without number) +#: src/config/player_manager.cpp:396 +msgid "Guest" +msgstr "Gwestai" + +#. I18N: Name of further guest players, with a 1, 2, ... attached +#: src/config/player_manager.cpp:401 +#, c-format +msgid "Guest %d" +msgstr "Gwestai %d" + +#: src/config/user_config.cpp:688 +msgid "" +"Your config file was malformed, so it was deleted and a new one will be " +"created." +msgstr "Roedd dy ffeil ffurfweddu wedi'i chamffurfio, felly cafodd ei dileu a bydd un newydd yn cael ei chreu." + +#: src/config/user_config.cpp:699 +msgid "" +"Your config file was too old, so it was deleted and a new one will be " +"created." +msgstr "Roedd dy ffeil ffurfweddu'n rhy hen, felly cafodd ei dileu a bydd un newydd yn cael ei chreu." + +#: src/graphics/irr_driver.cpp:738 +msgid "Video recording started." +msgstr "Dechreuwyd recordio'r fideo." + +#: src/graphics/irr_driver.cpp:745 +#, c-format +msgid "Video saved in \"%s\"." +msgstr "Fideo wedi'i gadw yn \"%s\"." + +#: src/graphics/irr_driver.cpp:749 +msgid "Encoding progress:" +msgstr "Cynnydd amgodio:" + +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 +#, c-format +msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" +msgstr "FPS: %d/%d/%d - %d KTris, Ping: %dms" + +#. I18N: Tip shown in gui for giving player hints +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 +#, c-format +msgid "Tip: %s" +msgstr "Awgrym: %s" + +#: src/guiengine/engine.cpp:1510 +msgid "Loading" +msgstr "Wrthi'n llwytho" + +#: src/guiengine/widgets/kart_stats_widget.cpp:104 +msgid "Mass" +msgstr "Màs" + +#: src/guiengine/widgets/kart_stats_widget.cpp:110 +msgid "Maximum speed" +msgstr "Cyflymder eithaf" + +#: src/guiengine/widgets/kart_stats_widget.cpp:117 +msgid "Acceleration" +msgstr "Cyflymiad" + +#: src/guiengine/widgets/kart_stats_widget.cpp:123 +msgid "Nitro efficiency" +msgstr "Effeithlonrwydd nitro" + +#. I18N: 'handicapped' indicates that per-player handicaps are +#. activated for this kart (i.e. it will drive slower) +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 +#: src/karts/controller/local_player_controller.cpp:468 +#: src/karts/controller/player_controller.cpp:413 +#: src/network/protocols/client_lobby.cpp:868 +#: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 +#: src/states_screens/race_result_gui.cpp:1675 +#, c-format +msgid "%s (handicapped)" +msgstr "%s (anfantais)" + +#: src/guiengine/widgets/player_kart_widget.cpp:448 +#, c-format +msgid "%s is ready" +msgstr "Mae %s yn barod" + +#. I18N: Unbound key binding +#: src/input/binding.cpp:85 +msgid "[none]" +msgstr "[dim]" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:92 +msgctxt "input_key" +msgid "Left Mouse Button" +msgstr "Botwm Chwith y Llygoden" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:94 +msgctxt "input_key" +msgid "Right Mouse Button" +msgstr "Botwm De Llygoden" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:96 +msgctxt "input_key" +msgid "Cancel" +msgstr "Na" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:98 +msgctxt "input_key" +msgid "Middle Mouse Button" +msgstr "Botwm Canol Llygoden" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:100 +msgctxt "input_key" +msgid "X1 Mouse Button" +msgstr "Botwm Llygoden X1" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:102 +msgctxt "input_key" +msgid "X2 Mouse Button" +msgstr "Botwm Llygoden X2" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:104 +msgctxt "input_key" +msgid "Backspace" +msgstr "Bysell Nôl" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:106 +msgctxt "input_key" +msgid "Tab" +msgstr "Tab" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:108 +msgctxt "input_key" +msgid "Clear" +msgstr "Clirio" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:110 +msgctxt "input_key" +msgid "Return" +msgstr "Return" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:112 +msgctxt "input_key" +msgid "Shift" +msgstr "Shift" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:114 +msgctxt "input_key" +msgid "Control" +msgstr "Control" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:116 +msgctxt "input_key" +msgid "Alt/Menu" +msgstr "Alt/Menu" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:118 +msgctxt "input_key" +msgid "Pause" +msgstr "Oedi" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:120 +msgctxt "input_key" +msgid "Caps Lock" +msgstr "Clo Nodau Mawr" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:122 +msgctxt "input_key" +msgid "Kana" +msgstr "Kana" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:124 +msgctxt "input_key" +msgid "Junja" +msgstr "Junja" + +#. I18N: input configuration screen: keyboard key +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:127 +msgctxt "input_key" +msgid "Final" +msgstr "Terfynol" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:129 +msgctxt "input_key" +msgid "Escape" +msgstr "Dianc" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:131 +msgctxt "input_key" +msgid "Convert" +msgstr "Trosi" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:133 +msgctxt "input_key" +msgid "Nonconvert" +msgstr "Di-drosi" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:135 +msgctxt "input_key" +msgid "Accept" +msgstr "Derbyn" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:137 +msgctxt "input_key" +msgid "Modechange" +msgstr "Newid modd" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:139 +msgctxt "input_key" +msgid "Space" +msgstr "Bwlch" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:141 +msgctxt "input_key" +msgid "Page Up" +msgstr "Page Up" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:143 +msgctxt "input_key" +msgid "Page Down" +msgstr "Page Down" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:145 +msgctxt "input_key" +msgid "End" +msgstr "End" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:147 +msgctxt "input_key" +msgid "Home" +msgstr "Home" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:149 +msgctxt "input_key" +msgid "Left" +msgstr "Chwith" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:151 +msgctxt "input_key" +msgid "Up" +msgstr "I fyny" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:153 +msgctxt "input_key" +msgid "Right" +msgstr "De" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:155 +msgctxt "input_key" +msgid "Down" +msgstr "I lawr" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:157 +msgctxt "input_key" +msgid "Select" +msgstr "Dewis" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:159 +msgctxt "input_key" +msgid "Print" +msgstr "Argraffu" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:161 +msgctxt "input_key" +msgid "Exec" +msgstr "Gweithredwr" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:163 +msgctxt "input_key" +msgid "Print Screen" +msgstr "Print Screen" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:165 +msgctxt "input_key" +msgid "Insert" +msgstr "Insert" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:167 +msgctxt "input_key" +msgid "Delete" +msgstr "Delete" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:169 +msgctxt "input_key" +msgid "Help" +msgstr "Cymorth" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:207 +msgctxt "input_key" +msgid "Left Logo" +msgstr "Logo Chwith" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:209 +msgctxt "input_key" +msgid "Right Logo" +msgstr "Logo iawn" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:211 +msgctxt "input_key" +msgid "Apps" +msgstr "Apiau" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:213 +msgctxt "input_key" +msgid "Sleep" +msgstr "Cysgu" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:215 +msgctxt "input_key" +msgid "Numpad 0" +msgstr "Rhif pad 0" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:217 +msgctxt "input_key" +msgid "Numpad 1" +msgstr "Rhif pad 1" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:219 +msgctxt "input_key" +msgid "Numpad 2" +msgstr "Rhif pad 2" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:221 +msgctxt "input_key" +msgid "Numpad 3" +msgstr "Rhif pad 3" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:223 +msgctxt "input_key" +msgid "Numpad 4" +msgstr "Rhif pad 4" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:225 +msgctxt "input_key" +msgid "Numpad 5" +msgstr "Rhif pad 5" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:227 +msgctxt "input_key" +msgid "Numpad 6" +msgstr "Rhif pad 6" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:229 +msgctxt "input_key" +msgid "Numpad 7" +msgstr "Rhif pad 7" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:231 +msgctxt "input_key" +msgid "Numpad 8" +msgstr "Rhif pad 8" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:233 +msgctxt "input_key" +msgid "Numpad 9" +msgstr "Rhif pad 9" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:237 +msgctxt "input_key" +msgid "Separator" +msgstr "Ymwahanydd" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:239 +msgctxt "input_key" +msgid "- (Subtract)" +msgstr "- (Tynnu)" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:241 +msgctxt "input_key" +msgid "Decimal" +msgstr "Degol" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:243 +msgctxt "input_key" +msgid "/ (Divide)" +msgstr "/ (Rhannu)" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:269 +msgctxt "input_key" +msgid "Num Lock" +msgstr "Bysell 'Num Lock'" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:271 +msgctxt "input_key" +msgid "Scroll Lock" +msgstr "Clo Sgrolio" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:273 +msgctxt "input_key" +msgid "Left Shift" +msgstr "Shift Chwith" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:275 +msgctxt "input_key" +msgid "Right Shift" +msgstr "Shift De" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:277 +msgctxt "input_key" +msgid "Left Control" +msgstr "Control Chwith" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:279 +msgctxt "input_key" +msgid "Right Control" +msgstr "Control De" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:281 +msgctxt "input_key" +msgid "Left Menu" +msgstr "Dewislen Chwith" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:283 +msgctxt "input_key" +msgid "Right Menu" +msgstr "Dewislen De" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:289 +msgctxt "input_key" +msgid "Attn" +msgstr "Attn" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:291 +msgctxt "input_key" +msgid "Crsel" +msgstr "Cresel" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:293 +msgctxt "input_key" +msgid "Exsel" +msgstr "Exsel" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:295 +msgctxt "input_key" +msgid "Ereof" +msgstr "Ereof" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:297 +msgctxt "input_key" +msgid "Play" +msgstr "Chwarae" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:299 +msgctxt "input_key" +msgid "Zoom" +msgstr "Chwyddo" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:301 +msgctxt "input_key" +msgid "Pa1" +msgstr "Pa1" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:303 +msgctxt "input_key" +msgid "Oem Clear" +msgstr "Oem Clir" + +#. I18N: to appear in input configuration screen, for gamepad hats +#: src/input/binding.cpp:343 src/input/binding.cpp:348 +#, c-format +msgid "Gamepad hat %d" +msgstr "Het gamepad %d" + +#. I18N: to appear in input configuration screen, for gamepad axes +#: src/input/binding.cpp:355 +#, c-format +msgid "Axis %d %s" +msgstr "Echel %d %s" + +#. I18N: to appear in input configuration screen, for gamepad axes +#: src/input/binding.cpp:362 +#, c-format +msgid "Axis %d inverted" +msgstr "Echel %d wedi'i gwrthdroi" + +#. I18N: to appear in input configuration screen, for gamepad axes +#: src/input/binding.cpp:367 +#, c-format +msgid "Axis %d" +msgstr "Echel %d" + +#. I18N: to appear in input configuration screen, for gamepad buttons +#: src/input/binding.cpp:374 +#, c-format +msgid "Gamepad button %d" +msgstr "Botwm pad gêm %d" + +#. I18N: to appear in input configuration screen, for mouse (might not be used +#. at all) +#: src/input/binding.cpp:377 +#, c-format +msgid "Mouse button %d" +msgstr "Botwm llygoden %d" + +#. I18N: to appear in input configuration screen, for mouse (might not be used +#. at all) +#: src/input/binding.cpp:381 +#, c-format +msgid "Mouse axis %d %s" +msgstr "Echel llygoden %d %s" + +#. I18N: shown when config file is too old +#: src/input/device_manager.cpp:496 +msgid "Please re-configure your key bindings." +msgstr "Ail-ffurfwedda dy ddynodiad bysell." + +#: src/input/device_manager.cpp:497 +msgid "Your input config file is not compatible with this version of STK." +msgstr "Nid yw eich ffeil ffurfweddu mewnbwn yn gydnaws â'r fersiwn hon o STK." + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:159 +msgid "Guide" +msgstr "Canllaw" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:161 +msgid "Start" +msgstr "Cychwyn" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:163 +msgid "Left thumbstick press" +msgstr "Pwyso bawd chwith" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:165 +msgid "Right thumbstick press" +msgstr "Pwyso bawd dde" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:167 +msgid "Left shoulder" +msgstr "Ysgwydd chwith" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:169 +msgid "Right shoulder" +msgstr "Ysgwydd dde" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:171 +msgid "DPad up" +msgstr "DPad i fyny" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:173 +msgid "DPad down" +msgstr "DPad i lawr" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:175 +msgid "DPad left" +msgstr "DPad chwith" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:177 +msgid "DPad right" +msgstr "DPad de" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:181 +msgid "Left thumbstick right" +msgstr "Ffon bawd chwith i'r dde" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:183 +msgid "Left thumbstick left" +msgstr "Ffon bawd chwith i'r chwith" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:185 +msgid "Left thumbstick down" +msgstr "Ffon bawd chwith i lawr" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:187 +msgid "Left thumbstick up" +msgstr "Ffon bawd chwith i fyny" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:189 +msgid "Right thumbstick right" +msgstr "Ffon bawd dde i'r dde" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:191 +msgid "Right thumbstick left" +msgstr "Ffon bawd dde i'r chwith" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:193 +msgid "Right thumbstick down" +msgstr "Ffon bawd dde i lawr" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:195 +msgid "Right thumbstick up" +msgstr "Ffon bawd dde i fyny" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:197 +msgid "Left trigger" +msgstr "Sbardun chwith" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:199 +msgid "Right trigger" +msgstr "Sbardun de" + +#: src/input/input_manager.cpp:867 +#, c-format +msgid "Ignoring '%s'. You needed to join earlier to play!" +msgstr "Yn anwybyddu '%s'. Roedd angen ymuno yn gynt i chwarae!" + +#: src/input/input_manager.cpp:903 +msgid "Only the Game Master may act at this point!" +msgstr "Dim ond Meistr y Gêm all weithredu ar y pwynt hwn!" + +#: src/input/sdl_controller.cpp:253 +#, c-format +msgid "%s has low battery level." +msgstr "Mae gan %s lefel batri isel." + +#: src/input/wiimote_manager.cpp:379 +msgid "" +"Connect your wiimote to the Bluetooth manager, then click on Ok. Detailed " +"instructions at https://supertuxkart.net/Wiimote" +msgstr "Cysyllta dy Wiimote â'r rheolwr Bluetooth, yna clicia ar Iawn. Cyfarwyddiadau manwl yn https://supertuxkart.net/Wiimote" + +#: src/input/wiimote_manager.cpp:382 +msgid "" +"Press the buttons 1+2 simultaneously on your wiimote to put it in discovery " +"mode, then click on Ok. Detailed instructions at " +"https://supertuxkart.net/Wiimote" +msgstr "Pwysa'r botymau 1+2 ar yr un pryd ar dy Wiimote i'w roi yn y modd darganfod, yna clicio Iawn. Cyfarwyddiadau manwl yn https://supertuxkart.net/Wiimote" + +#: src/input/wiimote_manager.cpp:405 +#, c-format +msgid "Found %d wiimote" +msgid_plural "Found %d wiimotes" +msgstr[0] "Wedi darganfod %d Wiimote" +msgstr[1] "Wedi darganfod %d Wiimote" +msgstr[2] "Wedi darganfod %d Wiimote" +msgstr[3] "Wedi darganfod %d Wiimote" + +#: src/input/wiimote_manager.cpp:410 +msgid "Could not detect any wiimote :/" +msgstr "Methu darganfod unrhyw Wiimote :/" + +#: src/io/rich_presence.cpp:477 +msgid "Getting ready to race" +msgstr "Yn paratoi i rasio" + +#: src/karts/controller/local_player_controller.cpp:329 +msgid "Penalty time!!" +msgstr "Amser cosb!!" + +#: src/karts/controller/local_player_controller.cpp:332 +msgid "Don't accelerate before 'Set!'" +msgstr "Paid â chyflymu cyn 'Barod!'" + +#: src/karts/controller/spare_tire_ai.cpp:150 +msgid "You can have at most 3 lives!" +msgstr "Mae gyda ti 3 bywyd ar y mwyaf!" + +#: src/karts/controller/spare_tire_ai.cpp:157 +msgid "+1 life." +msgstr "+1 bywyd." + +#: src/karts/kart.cpp:1032 +msgid "You were too slow!" +msgstr "Roeddet ti'n rhy araf!" + +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Rydych wedi gorffen y ras!" + +#: src/karts/kart.cpp:1034 +msgid "You won the race!" +msgstr "Rwyt ti wedi ennill y ras!" + +#: src/karts/kart.cpp:1035 +#, c-format +msgid "You finished the race in rank %d!" +msgstr "Rwyt ti wedi gorffen y ras yn safle %d!" + +#. I18N: Message shown in game to tell player left the game in network +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 +#, c-format +msgid "%s left the game." +msgstr "Mae %s wedi gadael y gêm." + +#: src/main.cpp:2042 +msgid "" +"SuperTuxKart may connect to a server to download add-ons and notify you of " +"updates. Please read our privacy policy at https://supertuxkart.net/Privacy." +" Would you like this feature to be enabled? (To change this setting at a " +"later time, go to options, select tab 'General', and edit \"Connect to the " +"Internet\")." +msgstr "Gall SuperTuxKart gysylltu â gweinydd i lwytho ychwanegion i lawr a rhoi gwybod i ti am ddiweddariadau. Darllena'n polisi preifatrwydd yn https://supertuxkart.net/Privacy. Hoffet ti i'r nodwedd hon gael ei galluogi? (I newid y gosodiad hwn yn nes ymlaen, rhaid mynd i'r Dewisiadau, dewis tab 'Cyffredinol', a golygu \"Cysylltu â'r Rhyngrwyd\")." + +#: src/main.cpp:2393 +msgid "Your screen resolution is too low to run STK." +msgstr "Mae cydraniad dy sgrin yn rhy isel i redeg STK." + +#: src/main.cpp:2444 +msgid "" +"Your driver version is too old. Please install the latest video drivers." +msgstr "Mae fersiwn dy yrrwr yn rhy hen. Gosoda'r gyrwyr fideo diweddaraf." + +#: src/main.cpp:2464 +#, c-format +msgid "" +"Your graphics driver appears to be very old. Please check if an update is " +"available. SuperTuxKart recommends a driver supporting %s or better. The " +"game will likely still run, but in a reduced-graphics mode." +msgstr "Mae'n ymddangos bod dy yrrwr graffeg yn hen iawn. Gwiria a oes diweddariad ar gael. Mae SuperTuxKart yn argymell gyrrwr sy'n cefnogi %s neu well. Mae'n debyg y bydd y gêm yn dal i redeg, ond mewn modd graffeg lai." + +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 +msgid "Server connection timed out." +msgstr "Cysylltiad gweinydd wedi dod i ben." + +#. I18N: Show when a player gets the red flag in CTF +#: src/modes/capture_the_flag.cpp:190 +#, c-format +msgid "%s has the red flag!" +msgstr "Mae gan %s y faner goch!" + +#. I18N: Show when the red flag is returned to its base in CTF +#: src/modes/capture_the_flag.cpp:197 +msgid "The red flag has returned!" +msgstr "Mae'r faner goch wedi dychwelyd!" + +#. I18N: Show when a player gets the blue flag in CTF +#: src/modes/capture_the_flag.cpp:208 +#, c-format +msgid "%s has the blue flag!" +msgstr "Mae gan %s y faner las!" + +#. I18N: Show when the blue flag is returned to its base in CTF +#: src/modes/capture_the_flag.cpp:215 +msgid "The blue flag has returned!" +msgstr "Mae'r faner las wedi dychwelyd!" + +#: src/modes/capture_the_flag.cpp:408 +#, c-format +msgid "%s captured the blue flag!" +msgstr "Mae %s wedi cipio'r faner las!" + +#: src/modes/capture_the_flag.cpp:412 +#, c-format +msgid "%s captured the red flag!" +msgstr "Mae %s wedi cipio'r faner goch!" + +#: src/modes/easter_egg_hunt.cpp:222 +#, c-format +msgid "Eggs: %d / %d" +msgstr "Wyau: %d / %d" + +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 +msgid "Leader" +msgstr "Arweinydd" + +#: src/modes/linear_world.cpp:418 +msgid "Final lap!" +msgstr "Lap olaf!" + +#: src/modes/linear_world.cpp:450 +#, c-format +msgid "Lap %i" +msgstr "Lap %i" + +#: src/modes/linear_world.cpp:552 +#, c-format +msgctxt "fastest_lap" +msgid "%s by %s" +msgstr "%s gan %s" + +#: src/modes/linear_world.cpp:558 +msgid "New fastest lap" +msgstr "Lap cyflymaf newydd" + +#: src/modes/linear_world.cpp:1100 +msgid "WRONG WAY!" +msgstr "Y FFORDD ANGHYWIR!" + +#: src/modes/soccer_world.cpp:533 src/modes/soccer_world.cpp:660 +#, c-format +msgid "%s scored a goal!" +msgstr "Mae %s wedi sgorio gôl!" + +#: src/modes/soccer_world.cpp:535 src/modes/soccer_world.cpp:662 +#, c-format +msgid "Oops, %s made an own goal!" +msgstr "Wps, mae %s wedi sgorio yn ei gôl ei hun!" + +#: src/modes/three_strikes_battle.cpp:665 +#, c-format +msgid "%i spare tire kart has been spawned!" +msgid_plural "%i spare tire karts have been spawned!" +msgstr[0] "Mae %i cart teiars sbâr wedi'i greu!" +msgstr[1] "Mae %i cart teiars sbâr wedi'i greu!" +msgstr[2] "Mae %i cart teiars sbâr wedi'i greu!" +msgstr[3] "Mae %i cart teiars sbâr wedi'i greu!" + +#: src/modes/world.cpp:1400 +msgid "You have been eliminated!" +msgstr "Rwyt ti allan o'r gêm!" + +#: src/modes/world.cpp:1407 +#, c-format +msgid "'%s' has been eliminated." +msgstr "Mae '%s'allan o'r gêm." + +#: src/network/protocols/client_lobby.cpp:130 +msgid "Server has been shut down." +msgstr "Mae'r gweinydd wedi'i gau." + +#: src/network/protocols/client_lobby.cpp:131 +msgid "You were kicked from the server." +msgstr "Rwyt ti wedi dy daro allan o'r gweinydd." + +#: src/network/protocols/client_lobby.cpp:133 +msgid "You were kicked: Ping too high." +msgstr "Rwyt ti wedi dy daro allan: Ping rhy uchel." + +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 +msgid "Bad network connection is detected." +msgstr "Wedi canfod cysylltiad rhwydwaith gwael." + +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 +msgid "Bot" +msgstr "Bot" + +#: src/network/protocols/client_lobby.cpp:642 +#, c-format +msgid "%s disconnected." +msgstr "%s wedi'i ddatgysylltu." + +#. I18N: Message shown in network lobby to tell user that +#. player name is clickable +#: src/network/protocols/client_lobby.cpp:673 +msgid "" +"Press player name in the list for player management and ranking information." +msgstr "Pwysa enw'r chwaraewr yn y rhestr i gael gwybodaeth am reoli a mesur chwaraewyr." + +#. I18N: In the networking lobby +#. I18N: In server info dialog +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 +#, c-format +msgid "Difficulty: %s" +msgstr "Anhawster: %s" + +#. I18N: In the networking lobby +#: src/network/protocols/client_lobby.cpp:744 +#, c-format +msgid "Max players: %d" +msgstr "Uchafswm chwaraewyr: %d" + +#. I18N: In server info dialog +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 +#, c-format +msgid "Game mode: %s" +msgstr "Modd gêm: %s" + +#. I18N: In the create server screen for soccer server +#: src/network/protocols/client_lobby.cpp:770 +#: src/states_screens/dialogs/server_configuration_dialog.cpp:174 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 +msgid "Time limit" +msgstr "Terfyn amser" + +#. I18N: In the create server screen for soccer server +#: src/network/protocols/client_lobby.cpp:771 +#: src/states_screens/dialogs/server_configuration_dialog.cpp:175 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 +msgid "Goals limit" +msgstr "Terfyn goliau" + +#. I18N: In the networking lobby +#: src/network/protocols/client_lobby.cpp:775 +#, c-format +msgid "Soccer game type: %s" +msgstr "Math o gêm bêl-droed: %s" + +#: src/network/protocols/client_lobby.cpp:785 +#, c-format +msgid "Grand prix progress: %d / %d" +msgstr "Cynnydd Grand Prix: %d / %d" + +#. I18N: Display when all players are in red or blue team, which the race +#. will not be allowed to start +#: src/network/protocols/client_lobby.cpp:904 +msgid "All players joined red or blue team." +msgstr "Ymunodd pob chwaraewr â thîm coch neu las." + +#. I18N: Display when a player is allow to control the server +#: src/network/protocols/client_lobby.cpp:924 +msgid "You are now the owner of server." +msgstr "Ti nawr yw perchennog y gweinydd." + +#: src/network/protocols/client_lobby.cpp:967 +msgid "Connection refused: Server is busy." +msgstr "Gwrthodwyd y cysylltiad: Mae'r gweinydd yn brysur." + +#: src/network/protocols/client_lobby.cpp:972 +msgid "Connection refused: You are banned from the server." +msgstr "Gwrthodwyd y cysylltiad: Rwyt ti wedi dy wahardd o'r gweinydd." + +#: src/network/protocols/client_lobby.cpp:987 +msgid "Connection refused: Server password is incorrect." +msgstr "Gwrthodwyd y cysylltiad: Mae cyfrinair y gweinydd yn anghywir." + +#: src/network/protocols/client_lobby.cpp:991 +msgid "Connection refused: Game data is incompatible." +msgstr "Gwrthodwyd y cysylltiad: Mae data gêm yn anghydnaws." + +#: src/network/protocols/client_lobby.cpp:995 +msgid "Connection refused: Server is full." +msgstr "Gwrthodwyd y cysylltiad: Gweinydd yn llawn." + +#: src/network/protocols/client_lobby.cpp:999 +msgid "Connection refused: Invalid player connecting." +msgstr "Gwrthodwyd y cysylltiad: Cyswllt chwaraewr annilys." + +#: src/network/protocols/client_lobby.cpp:1027 +msgid "Failed to start the network game." +msgstr "Wedi methu cychwyn y gêm rhwydwaith." + +#. I18N: Error message shown if live join or spectate failed in network +#: src/network/protocols/client_lobby.cpp:1242 +msgid "The game has ended, you can't live join or spectate anymore." +msgstr "Mae'r gêm wedi dod i ben, nid oes modd i ti ymuno na gwylio'n fyw bellach." + +#. I18N: Error message shown if live join failed in network +#: src/network/protocols/client_lobby.cpp:1246 +msgid "No remaining place in the arena - live join disabled." +msgstr "Dim lle ar ôl yn yr arena - mae ymuno'n fyw wedi ei analluogi." + +#. I18N: Error message shown if only 1 player remains in network +#: src/network/protocols/client_lobby.cpp:1250 +msgid "Only 1 player remaining, returning to lobby." +msgstr "Dim ond 1 chwaraewr ar ôl, yn mynd i'r cyntedd." + +#: src/network/protocols/client_lobby.cpp:1256 +msgid "Server owner quit the game." +msgstr "Mae perchennog y gweinydd yn gadael y gêm." + +#. I18N: Status shown to player when he will be spectating the next game +#: src/network/protocols/client_lobby.cpp:1260 +msgid "You will be spectating the next game." +msgstr "Byddi'n gwylio'r gêm nesaf." + +#. I18N: Show when player join red team of the started game in +#. network +#: src/network/protocols/client_lobby.cpp:1436 +#, c-format +msgid "%s joined the red team." +msgstr "Ymunodd %s â'r tîm coch." + +#. I18N: Show when player join blue team of the started game in +#. network +#: src/network/protocols/client_lobby.cpp:1442 +#, c-format +msgid "%s joined the blue team." +msgstr "Ymunodd %s â'r tîm glas." + +#. I18N: Show when player join the started game in network +#: src/network/protocols/client_lobby.cpp:1448 +#, c-format +msgid "%s joined the game." +msgstr "Ymunodd %s â'r gêm." + +#. I18N: Message shown in game to tell the player it's possible to change +#. the camera target in spectate mode of network +#: src/network/protocols/client_lobby.cpp:1639 +#, c-format +msgid "" +"Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " +"camera position." +msgstr "Pwysa <%s> neu <%s> i newid y chwaraewr targed, <%s> neu <%s> leoliad y camera." + +#. I18N: Tell player he has successfully report this named player +#: src/network/protocols/client_lobby.cpp:1655 +#, c-format +msgid "Successfully reported %s." +msgstr "Wedi adrodd ar %s yn llwyddiannus." + +#. I18N: Shown when there is download error for assets download +#. in the first run +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 +msgid "" +"Failed to download assets, check your storage space or internet connection " +"and try again later." +msgstr "Wedi methu â llwytho asedau i lawr, gwiria dy ofod storio neu gysylltiad rhyngrwyd a rho gynnig arall arni yn nes ymlaen." + +#: src/network/protocols/connect_to_server.cpp:230 +msgid "No quick play server available." +msgstr "Dim gweinydd chwarae cyflym ar gael." + +#: src/network/protocols/connect_to_server.cpp:380 +#, c-format +msgid "Cannot connect to server %s." +msgstr "Methu cysylltu â gweinydd %s." + +#. I18N: Show the failed detect port server name +#: src/network/protocols/connect_to_server.cpp:883 +#, c-format +msgid "Failed to detect port number for server %s." +msgstr "Wedi methu canfod rhif porth ar gyfer gweinydd %s." + +#: src/network/protocols/lobby_protocol.cpp:294 +msgid "Network grand prix has been finished." +msgstr "Rhwydwaith Grand Prix wedi gorffen." + +#: src/network/server_config.cpp:263 +msgid "Time Trial (Grand Prix)" +msgstr "Treialon Amser (Grand Prix)" + +#. I18N: Game mode +#. I18N: In the create server screen for battle server +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 +#: src/states_screens/dialogs/server_configuration_dialog.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 +msgid "Free-For-All" +msgstr "Rhydd-i-Pawb" + +#. I18N: Game mode +#. I18N: In the create server screen for battle server +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 +#: src/states_screens/dialogs/server_configuration_dialog.cpp:162 +#: src/states_screens/online/create_server_screen.cpp:244 +msgid "Capture The Flag" +msgstr "Cipio'r Faner" + +#: src/online/online_player_profile.cpp:456 +#, c-format +msgid "%s is now online." +msgstr "Mae %s nawr ar-lein." + +#: src/online/online_player_profile.cpp:460 +#, c-format +msgid "%s and %s are now online." +msgstr "Mae %s a %s ar-lein nawr." + +#: src/online/online_player_profile.cpp:465 +#, c-format +msgid "%s, %s and %s are now online." +msgstr "Mae %s, %s a %s ar-lein nawr." + +#. I18N: Only used for count > 3 +#: src/online/online_player_profile.cpp:471 +#, c-format +msgid "%d friend is now online." +msgid_plural "%d friends are now online." +msgstr[0] "Mae %d ffrind ar-lein nawr." +msgstr[1] "Mae %d ffrind ar-lein nawr." +msgstr[2] "Mae %d ffrind ar-lein nawr." +msgstr[3] "Mae %d ffrind ar-lein nawr." + +#. I18N: Tell your friend if he is on any server in game +#: src/online/online_player_profile.cpp:520 +#, c-format +msgid "%s is now on server \"%s\"." +msgstr "Mae %s nawr ar weinydd \"%s\"." + +#: src/online/online_player_profile.cpp:551 +#, c-format +msgid "You have %d new friend request!" +msgid_plural "You have %d new friend requests!" +msgstr[0] "Mae gennyt %d cais ffrind newydd!" +msgstr[1] "Mae gennyt %d gais ffrind newydd!" +msgstr[2] "Mae gennyt %d cais ffrind newydd!!" +msgstr[3] "Mae gennyt %d cais ffrind newydd!" + +#: src/online/online_player_profile.cpp:557 +msgid "You have a new friend request!" +msgstr "Mae gennyt gais ffrind newydd!" + +#: src/online/xml_request.cpp:83 +msgid "" +"Unable to connect to the server. Check your internet connection or try again" +" later." +msgstr "Methu cysylltu â'r gweinydd. Gwiria dy gysylltiad rhyngrwyd neu geisio eto yn nes ymlaen." + +#: src/race/grand_prix_data.cpp:639 src/states_screens/gp_info_screen.cpp:77 +msgid "Default" +msgstr "Rhagosodiad" + +#: src/race/grand_prix_data.cpp:641 src/states_screens/gp_info_screen.cpp:78 +msgid "None" +msgstr "Dim" + +#: src/race/grand_prix_data.cpp:645 src/states_screens/gp_info_screen.cpp:80 +msgid "Random" +msgstr "Ar Hap" + +#: src/race/highscore_manager.cpp:102 +msgid "" +"The highscore file was too old,\n" +"all highscores have been erased." +msgstr "Roedd y ffeil sgôr uchel yn rhy hen,\nmae pob sgôr uchel wedi'u dileu." + +#. I18N: Game mode +#: src/race/race_manager.cpp:1294 +msgid "Follow the Leader" +msgstr "Dilyn yr Arweinydd" + +#. I18N: Game mode +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 +msgid "3 Strikes Battle" +msgstr "Brwydr 3 Hergwd" + +#: src/replay/replay_recorder.cpp:358 +msgid "Incomplete replay file will not be saved." +msgstr "Fydd y ffeil ailchwarae anghyflawn ddim yn cael ei chadw." + +#: src/replay/replay_recorder.cpp:394 +#, c-format +msgid "Replay saved in \"%s\"." +msgstr "Ailchwarae wedi'i gadw yn \"%s\"." + +#: src/states_screens/addons_screen.cpp:51 +msgid "1 week" +msgstr "1 wythnos" + +#: src/states_screens/addons_screen.cpp:52 +msgid "2 weeks" +msgstr "Pythefnos" + +#: src/states_screens/addons_screen.cpp:53 +msgid "1 month" +msgstr "1 mis" + +#: src/states_screens/addons_screen.cpp:54 +msgid "3 months" +msgstr "3 mis" + +#: src/states_screens/addons_screen.cpp:55 +msgid "6 months" +msgstr "6 mis" + +#: src/states_screens/addons_screen.cpp:56 +msgid "9 months" +msgstr "9 mis" + +#: src/states_screens/addons_screen.cpp:57 +msgid "1 year" +msgstr "Blwyddyn" + +#: src/states_screens/addons_screen.cpp:58 +msgid "2 years" +msgstr "2 flynedd" + +#: src/states_screens/addons_screen.cpp:109 +msgid "Add-on name" +msgstr "Enw ychwanegyn" + +#: src/states_screens/addons_screen.cpp:110 +msgid "Updated date" +msgstr "Dyddiad wedi'i ddiweddaru" + +#. I18N: Addon not installed for fillter +#: src/states_screens/addons_screen.cpp:140 +msgid "Not installed" +msgstr "Heb ei osod" + +#. I18N: as in: The Old Island by Johannes Sjolund +#: src/states_screens/addons_screen.cpp:326 +#, c-format +msgctxt "addons" +msgid "%s by %s" +msgstr "%s gan %s" + +#: src/states_screens/addons_screen.cpp:447 +msgid "Please wait while addons are updated" +msgstr "Arhosa tra bod yr ychwanegion yn cael eu diweddaru" + +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 +msgid "" +"Sorry, an error occurred while contacting the add-ons website. Make sure you" +" are connected to the Internet and that SuperTuxKart is not blocked by a " +"firewall" +msgstr "Ymddiheuriadau, bu gwall wrth gysylltu â'r wefan ychwanegion. Gwna'n siŵr dy fod wedi dy gysylltu â'r Rhyngrwyd ac nad oes mur cadarn yn rhwystro SuperTuxKart" + +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Ffefrynnau" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 +#: src/states_screens/race_setup_screen.cpp:101 +msgid "Locked : solve active challenges to gain access to more!" +msgstr "O dan glo: datrysa heriau gweithredol i gael mynediad at ragor!" + +#: src/states_screens/arenas_screen.cpp:351 +msgid "Random Arena" +msgstr "Arena ar Hap" + +#: src/states_screens/credits.cpp:184 +msgid "translator-credits" +msgstr "Rhoslyn Prys post@meddal.com" + +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:65 +msgctxt "achievement_info" +msgid "Subgoals" +msgstr "Is-nodau" + +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:67 +msgctxt "achievement_info" +msgid "Progress" +msgstr "Cynnydd" + +#. I18N: For achievements, a parent goal linking logically several subgoals +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:162 +msgid "Fulfill all the subgoals" +msgstr "Cyflawnu'r holl is-nodau" + +#. I18N: For achievements, a parent goal linking logically several subgoals +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:164 +msgid "Fulfill all the subgoals at the same time" +msgstr "Cyflawnu'r holl is-nodau ar yr un pryd" + +#. I18N: For achievements, a parent goal linking logically several subgoals +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:166 +msgid "Fulfill at least one subgoal" +msgstr "Cyflawnu o leiaf un is-nod" + +#. I18N: For achievements, a parent goal linking logically several subgoals +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:168 +msgid "The sum of the subgoals must reach the indicated value" +msgstr "Rhaid i swm yr is-nodau gyrraedd y gwerth sy'n cael ei nodi" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:170 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:276 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:301 +msgid "Races won" +msgstr "Rasys wedi'u hennill" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:172 +msgid "Normal races won" +msgstr "Rasys arferol wedi'u hennill" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:174 +msgid "Time-trial races won" +msgstr "Rasys Treialon amser wedi'u hennill" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:176 +msgid "Follow-the-Leader races won" +msgstr "Rasys Dilyn yr Arweinydd wedi eu hennill" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:178 +msgid "Consecutive won races" +msgstr "Rasys Olynol wedi'u hennill" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:180 +msgid "Consecutive won races in Expert or SuperTux" +msgstr "Rasys Arbenigwr neu SuperTux olynol wedi'u hennill" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:182 +msgid "Novice races started" +msgstr "Rasys Dechreuwyr wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:184 +msgid "Novice races finished" +msgstr "Rasys Dechreuwyr wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:186 +msgid "Intermediate races started" +msgstr "Rasys Canolraddol wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:188 +msgid "Intermediate races finished" +msgstr "Rasys Canolradd wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:190 +msgid "Expert races started" +msgstr "Rasys Arbenigwyr wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:192 +msgid "Expert races finished" +msgstr "Rasys Arbenigwyr wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:194 +msgid "SuperTux races started" +msgstr "Rasys SuperTux wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:196 +msgid "SuperTux races finished" +msgstr "Rasys SuperTux wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:198 +msgid "Normal races started" +msgstr "Rasys Arferol wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:200 +msgid "Normal races finished" +msgstr "Rasys Arferol wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:202 +msgid "Time-trial races started" +msgstr "Rasys Treialon Amser wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:204 +msgid "Time-trial races finished" +msgstr "Rasys Treialon Amser wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:206 +msgid "Follow-the-Leader races started" +msgstr "Rasys Dilyn yr Arweinydd wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:208 +msgid "Follow-the-Leader races finished" +msgstr "Rasys Dilyn yr Arweinydd wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:210 +msgid "3 Strikes battles started" +msgstr "Brwydrau 3 Hergwd wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:212 +msgid "3 Strikes battles finished" +msgstr "Brwydrau 3 Hergwd wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:214 +msgid "Soccer matches started" +msgstr "Gemau Pêl-droed wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:216 +msgid "Soccer matches finished" +msgstr "Gemau Pêl-droed wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:218 +msgid "Egg Hunts started" +msgstr "Helfeydd Wyau wedi'u dechau" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:220 +msgid "Egg Hunts finished" +msgstr "Helfeydd Wyau wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:222 +msgid "Races started with a ghost replay" +msgstr "Rasys ailchwarae ysbrydion wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:224 +msgid "Races finished with a ghost replay" +msgstr "Rasys ailchwarae ysbrydion wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:226 +msgid "Capture-the-Flag matches started" +msgstr "Gemau Cipio'r Faner wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:228 +msgid "Capture-the-Flag matches finished" +msgstr "Gemau Cipio'r Faner wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:230 +msgid "Free-for-All matches started" +msgstr "Gemau Rhydd i Bawb wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:232 +msgid "Free-for-All matches finished" +msgstr "Gemau Rhydd i Bawb wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:234 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:236 +msgid "Powerups used" +msgstr "Pweriadau wedi'u defnyddio" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:236 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:240 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:244 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:248 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:250 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:254 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:262 +msgid " (1 race)" +msgstr " (1 ras)" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:238 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:240 +msgid "Bowling ball hits" +msgstr "Trawiadau pêl bowlio" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:242 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:244 +msgid "Swatter hits" +msgstr "Trawiadau Swatiwr" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:246 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:248 +msgid "All hits" +msgstr "Pob trawiad" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:250 +msgid "Hits against the same kart" +msgstr "Trawiadau yn erbyn yr un cart" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:252 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:254 +msgid "Bananas collected" +msgstr "Bananas wedi'u casglu" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#. I18N: Key binding name +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 +#: src/states_screens/options/options_screen_device.cpp:264 +msgid "Skidding" +msgstr "Sgidio" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:269 +msgid " (1 lap)" +msgstr " (1 lap)" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:272 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:297 +msgid "Races started" +msgstr "Rasys wedi'u cychwyn" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:272 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:274 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:276 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:278 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:280 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:282 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:284 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:286 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:288 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:294 +msgid " (maximum on one official track)" +msgstr " (uchafswm ar un trac swyddogol)" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:274 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:299 +msgid "Races finished" +msgstr "Rasys wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:278 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:303 +msgid "Reverse direction races finished" +msgstr "Rasys am yn ôl wedi gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:280 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:305 +msgid "Races finished alone" +msgstr "Rasys wedi'u gorffen ar ben fy hun" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:282 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:307 +msgid "Races with less than the default lap number" +msgstr "Rasys gyda llai na'r rhif lap rhagosodedig" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:284 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:309 +msgid "Races with more than the default lap number" +msgstr "Rasys gyda mwy na'r rhif lap rhagosodedig" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:286 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:311 +msgid "Races with at least twice as much as the default lap number" +msgstr "Rasys gydag o leiaf ddwywaith cymaint â'r rhif lap rhagosodedig" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:288 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:313 +msgid "Egg hunts started" +msgstr "Helfeydd Wyau wedi'u dechau" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:292 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:317 +msgid "Egg hunts finished" +msgstr "Helfeydd Wyau wedi'u gorffen" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:297 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:299 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:301 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:303 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:305 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:307 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:309 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:311 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:313 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:319 +msgid " (official tracks matching the goal)" +msgstr " (traciau swyddogol yn cyfateb i'r nod)" + +#: src/states_screens/dialogs/add_device_dialog.cpp:48 +msgid "" +"New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" +"\n" +"To add a keyboard config, you can use the button below, HOWEVER please note that most keyboards only support a limited amount of simultaneous keypresses and are thus inappropriate for multiplayer gameplay. (You can, however, connect multiple keyboards to this device. Remember that everyone still needs different keybindings in this case.)" +msgstr "Bydd padiau gêm a ffyn rheoli newydd yn ymddangos yn awtomatig yn y rhestr pan fyddi'n eu cysylltu â'r ddyfais hon.\n\nI ychwanegu ffurfweddiad bysellfwrdd, gelli ddefnyddio'r botwm isod, FODD BYNNAG sylwa fod y rhan fwyaf o fysellfyrddau ond yn cynnal nifer gyfyngedig o fysellau bysellfyrddau ac felly'n anaddas ar gyfer chwarae aml-chwaraewr. (Gelli hefyd gysylltu nifer o fysellfyrddau i'r ddyfais hon. Cofia fod angen dynodiad bysellfyrddau gwahanol ar bawb o hyd yn yr achos hwn.)" + +#. I18N: In the 'add new input device' dialog +#: src/states_screens/dialogs/add_device_dialog.cpp:71 +msgid "Add Wiimote" +msgstr "Ychwanegu Wiimote" + +#. I18N: In the 'add new input device' dialog +#: src/states_screens/dialogs/add_device_dialog.cpp:88 +msgid "Add Keyboard Configuration" +msgstr "Ychwanegu Ffurfweddiad Bysellfwrdd" + +#: src/states_screens/dialogs/addons_loading.cpp:126 +msgid "Update" +msgstr "Diweddariad" + +#: src/states_screens/dialogs/addons_loading.cpp:138 +#, c-format +msgid "Version: %d" +msgstr "Fersiwn: %d" + +#: src/states_screens/dialogs/addons_loading.cpp:169 +msgid "featured" +msgstr "nodwedd" + +#. I18N: File size of game assets or addons downloading +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 +#, c-format +msgid "Size: %s" +msgstr "Maint: %s" + +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Rhaid i chi fod wedi mewngofnodi i raddio'r ategyn hwn." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 +msgid "Sorry, downloading the add-on failed" +msgstr "Ymddiheuriad, nid oedd modd llwytho'r ychwanegyn i lawr" + +#: src/states_screens/dialogs/addons_loading.cpp:391 +#, c-format +msgid "Problems installing the addon '%s'." +msgstr "Problemau wrth osod yr ategyn '%s'." + +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 +msgid "Try again" +msgstr "Ceisia eto" + +#: src/states_screens/dialogs/addons_loading.cpp:442 +#, c-format +msgid "Problems removing the addon '%s'." +msgstr "Problemau wrth dynnu'r ategyn '%s'." + +#: src/states_screens/dialogs/addons_pack.cpp:71 +msgid "Background download completed." +msgstr "Cwblhawyd y llwytho i lawr yn y cefndir." + +#: src/states_screens/dialogs/addons_pack.cpp:132 +msgid "Background download" +msgstr "Llwytho i lawr yn y cefndir" + +#: src/states_screens/dialogs/addons_pack.cpp:141 +msgid "Background download has already started." +msgstr "Mae llwytho i lawr yn y cefndir eisoes wedi cychwyn." + +#: src/states_screens/dialogs/change_password_dialog.cpp:140 +msgid "Current password invalid." +msgstr "Cyfrinair presennol yn annilys." + +#: src/states_screens/dialogs/change_password_dialog.cpp:146 +#: src/states_screens/online/register_screen.cpp:382 +msgid "Password has to be between 8 and 30 characters long!" +msgstr "Rhaid i'r cyfrinair fod rhwng 8 a 30 nod o hyd!" + +#: src/states_screens/dialogs/change_password_dialog.cpp:153 +#: src/states_screens/online/register_screen.cpp:358 +msgid "Passwords don't match!" +msgstr "Nid yw'r cyfrineiriau yn cydweddu!" + +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 +#: src/states_screens/online/register_screen.cpp:448 +msgid "Validating info" +msgstr "Yn dilysu manylion" + +#: src/states_screens/dialogs/change_password_dialog.cpp:250 +msgid "Password successfully changed." +msgstr "Newidiwyd y cyfrinair yn llwyddiannus." + +#. I18N: In the 'confirm resolution' dialog, that's shown when switching +#. resoluton +#: src/states_screens/dialogs/confirm_resolution_dialog.cpp:86 +#, c-format +msgid "Confirm resolution within %i second" +msgid_plural "Confirm resolution within %i seconds" +msgstr[0] "Cadarnhau'r cydraniad o fewn %i eiliad" +msgstr[1] "Cadarnhau'r cydraniad o fewn %i eiliad" +msgstr[2] "Cadarnhau'r cydraniad o fewn %i eiliad" +msgstr[3] "Cadarnhau'r cydraniad o fewn %i eiliad" + +#: src/states_screens/dialogs/confirm_resolution_dialog.cpp:93 +msgid "" +"Resolutions smaller than 1024x768 or 1280x720 are unsupported. Some parts of" +" the UI may not work correctly." +msgstr "Nid yw cydraniadau sy'n llai na 1024x768 neu 1280x720 yn cael eu cefnogi. Efallai na fydd rhai rhannau o'r Rhyngwyneb yn gweithio'n iawn." + +#. I18N: In the UI options, Camera setting: Drone chase +#: src/states_screens/dialogs/custom_camera_settings.cpp:86 +#: src/states_screens/options/options_screen_ui.cpp:126 +msgid "Drone chase" +msgstr "Hela drôn" + +#. I18N: In the UI options, Camera setting: Custom +#. I18N: custom video settings +#: src/states_screens/dialogs/custom_camera_settings.cpp:103 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 +msgid "Custom" +msgstr "Cyfaddas" + +#. I18N: in the graphical options tooltip; +#. indicates a graphical feature is disabled +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 +msgid "Disabled" +msgstr "Analluogwyd" + +#. I18N: if only important particles effects is enabled +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 +msgid "Important only" +msgstr "Pwysig yn unig" + +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 +msgid "Very Low" +msgstr "Isel Iawn" + +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 +msgid "Low" +msgstr "Isel" + +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Canolig" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 +msgid "High" +msgstr "Uchel" + +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Uchel Iawn" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Llawn" + +#. I18N: In download assets dialog +#: src/states_screens/dialogs/download_assets.cpp:113 +msgid "" +"SuperTuxKart will download full assets (including high quality textures and " +"music) for better gaming experience, this will use your mobile data if you " +"don't have a wifi connection." +msgstr "Bydd SuperTuxKart yn llwytho asedau llawn i lawr (gan gynnwys gweadau a cherddoriaeth o ansawdd uchel) ar gyfer gwell profiad hapchwarae, bydd hyn yn defnyddio'ch data symudol os nad oes gennych gysylltiad wifi." + +#. I18N: In download assets dialog +#: src/states_screens/dialogs/download_assets.cpp:121 +msgid "" +"SuperTuxKart will download full assets (including high quality textures and " +"music) for better gaming experience." +msgstr "Bydd SuperTuxKart yn llwytho asedau llawn i lawr (gan gynnwys gweadau a cherddoriaeth o ansawdd uchel) ar gyfer gwell profiad hapchwarae." + +#: src/states_screens/dialogs/enter_address_dialog.cpp:42 +msgid "" +"Enter the server address optionally followed by : and then port or select " +"address from list." +msgstr "Rhowch gyfeiriad y gweinydd ac o ddewis rhowch : ac yna nodi porth neu dewiswch gyfeiriad o'r rhestr." + +#: src/states_screens/dialogs/enter_address_dialog.cpp:124 +#, c-format +msgid "Invalid server address: %s." +msgstr "Cyfeiriad gweinydd annilys: %s." + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 +msgctxt "column_name" +msgid "Reverse" +msgstr "Am yn Ôl" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/online/server_selection.cpp:135 +msgctxt "column_name" +msgid "Difficulty" +msgstr "Anhawster" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 +msgctxt "column_name" +msgid "Laps" +msgstr "Lapiau" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 +msgctxt "column_name" +msgid "Time" +msgstr "Amser" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 +msgctxt "column_name" +msgid "Kart" +msgstr "Cart" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 +msgctxt "column_name" +msgid "User" +msgstr "Defnyddiwr" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 +msgctxt "column_name" +msgid "Version" +msgstr "Fersiwn" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 +#: src/states_screens/edit_gp_screen.cpp:261 +#: src/states_screens/ghost_replay_selection.cpp:394 +#: src/states_screens/high_score_selection.cpp:265 +msgid "No" +msgstr "Na" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 +#: src/states_screens/edit_gp_screen.cpp:151 +#: src/states_screens/high_score_selection.cpp:141 +msgid "Track" +msgstr "Trac" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 +#, c-format +msgid "Top %d High Scores" +msgstr "Y %d Sgôr Uchel Uchaf" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 +#, c-format +msgid "Number of karts: %d" +msgstr "Nifer y cartiau: %d" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 +#, c-format +msgid "Time target: %s" +msgstr "Targed amser: %s" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 +#, c-format +msgid "Laps: %d" +msgstr "Lapiau: %d" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 +#, c-format +msgid "Reverse: %s" +msgstr "Am yn Ôl: %s" + +#. I18N: for empty highscores entries +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 +msgid "(Empty)" +msgstr "(Gwag)" + +#. I18N: In kart color choosing dialog +#: src/states_screens/dialogs/kart_color_slider_dialog.cpp:47 +msgid "Use original color" +msgstr "Defnyddio'r lliw gwreiddiol" + +#. I18N: In kart color choosing dialog +#: src/states_screens/dialogs/kart_color_slider_dialog.cpp:49 +msgid "Pick a color from slider" +msgstr "Dewis lliw o'r llithrydd" + +#: src/states_screens/dialogs/message_dialog.cpp:145 +msgid "Don't show again" +msgstr "Peidio â dangos eto" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:50 +msgid "Player info" +msgstr "Manylion chwaraewr" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:55 +#, c-format +msgid "Player name: %s" +msgstr "Enw'r chwaraewr: %s" + +#. I18N: In the network player dialog, show the player location with +#. country name (based on IP geolocation) +#: src/states_screens/dialogs/network_player_dialog.cpp:64 +#, c-format +msgid "Player location: %s" +msgstr "Lleoliad y chwaraewr: %s" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:108 +msgid "Kick" +msgstr "Cic" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:124 +msgid "Change team" +msgstr "Newid tîm" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:139 +msgid "Enable handicap" +msgstr "Galluogi anfantais" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:144 +msgid "Disable handicap" +msgstr "Analluogi anfantais" + +#. I18N: In the network player dialog, +#. report player about for example abusive behaviour in game +#: src/states_screens/dialogs/network_player_dialog.cpp:159 +msgid "Report player" +msgstr "Adrodd ar chwaraewr" + +#. I18N: In the network player dialog, showing when waiting for +#. the result of the ranking info of a player +#: src/states_screens/dialogs/network_player_dialog.cpp:181 +#: src/states_screens/dialogs/player_rankings_dialog.cpp:141 +#, c-format +msgid "Fetching ranking info for %s" +msgstr "Wrthi'n nôl manylion llwyddiant %s" + +#. I18N: In the network player dialog, instruction for reporting player +#: src/states_screens/dialogs/network_player_dialog.cpp:194 +#, c-format +msgid "Tell server administrator about this player (%s):" +msgstr "Dweud wrth weinyddwr y gweinydd am y chwaraewr hwn (%s):" + +#. I18N: In press a key dialog, tell user to press a key to bind configuration +#: src/states_screens/dialogs/press_a_key_dialog.cpp:43 +msgid "" +"Press any key...\n" +"(Press ESC to cancel)" +msgstr "Pwyso unrhyw fysell...\n(Pwysa ESC i ddiddymu)" + +#: src/states_screens/dialogs/press_a_key_dialog.cpp:49 +msgid "Press any key..." +msgstr "Pwyso unrhyw fysell..." + +#: src/states_screens/dialogs/race_paused_dialog.cpp:117 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 +msgid "Chat is disabled, enable in options menu." +msgstr "Mae Sgwrsio wedi'i analluogi, galluoga yn y ddewislen Dewisiadau." + +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Yn ôl i'r Prawf Perfformiad" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Gadael y Prawf Perfformiad" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +msgid "Back to Battle" +msgstr "Nôl i'r Frwydr" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 +msgid "Setup New Game" +msgstr "Gosod Gêm Newydd" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 +msgid "Restart Battle" +msgstr "Ailgychwyn y Frwydr" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 +msgid "Exit Battle" +msgstr "Gadael y Frwydr" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 +msgid "Setup New Race" +msgstr "Gosod Ras Newydd" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 +msgid "Exit Race" +msgstr "Gadael y Ras" + +#. I18N: In the network player dialog, indiciating a network +#. player has no ranking +#: src/states_screens/dialogs/ranking_callback.hpp:44 +#, c-format +msgid "%s has no ranking yet." +msgstr "Nid oes gan %s raddiad eto." + +#: src/states_screens/dialogs/ranking_callback.hpp:56 +#, c-format +msgid "%s is number %d in the rankings with a score of %f." +msgstr "Mae %s yn rhif %d yn y graddio gyda sgôr o %f." + +#: src/states_screens/dialogs/recovery_dialog.cpp:124 +msgid "Username and/or email address invalid." +msgstr "Enw defnyddiwr a/neu gyfeiriad e-bost annilys." + +#: src/states_screens/dialogs/registration_dialog.cpp:43 +#, c-format +msgid "" +"Please read the terms and conditions for SuperTuxKart at '%s'. You must " +"agree to these terms in order to register an account for STK. If you have " +"any questions or comments regarding these terms, one of the members of the " +"development team would gladly assist you." +msgstr "Darllena'r telerau ac amodau ar gyfer SuperTuxKart yn '%s'. Rhaid i ti gytuno i'r telerau hyn er mwyn cofrestru cyfrif ar gyfer STK. Os oes gennyt unrhyw gwestiynau neu sylwadau am y telerau hyn, byddai un o aelodau'r tîm datblygu yn falch o dy gynorthwyo." + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:60 +msgid "Nitro challenge" +msgstr "Her Nitro" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:65 +#: src/states_screens/race_setup_screen.cpp:137 +msgid "Ghost replay race" +msgstr "Ras ailchwarae ysbrydion" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:72 +#: src/states_screens/race_result_gui.cpp:2074 +#, c-format +msgid "Laps: %i" +msgstr "Lapiau: %i" + +#. I18N: In the Select challenge dialog, type of this challenge +#: src/states_screens/dialogs/select_challenge.cpp:82 +#, c-format +msgid "Type: %s" +msgstr "Math: %s" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:90 +#: src/states_screens/race_result_gui.cpp:2249 +#, c-format +msgid "Required Rank: %i" +msgstr "Safle Gofynnol: %i" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:96 +#: src/states_screens/race_result_gui.cpp:2258 +#, c-format +msgid "Required Time: %i" +msgstr "Amser Angenrheidiol: %i" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:103 +#: src/states_screens/race_result_gui.cpp:2270 +#, c-format +msgid "Required Nitro Points: %i" +msgstr "Pwyntiau Nitro Gofynnol: %i" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:109 +#, c-format +msgid "Number of AI Karts: %i" +msgstr "Nifer y Cartiau AI: %i" + +#. I18N: In the create server screen, show various battle mode available +#: src/states_screens/dialogs/server_configuration_dialog.cpp:158 +#: src/states_screens/online/create_server_screen.cpp:238 +msgid "Battle mode" +msgstr "Modd brwydr" + +#. I18N: In the create server screen +#: src/states_screens/dialogs/server_configuration_dialog.cpp:171 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 +msgid "Soccer game type" +msgstr "Math o gêm bêl-droed" + +#. I18N: In the server info dialog, show the server location with +#. country name (based on IP geolocation) +#: src/states_screens/dialogs/server_info_dialog.cpp:111 +#, c-format +msgid "Server location: %s" +msgstr "Lleoliad y gweinydd: %s" + +#. I18N: In server info dialog, showing the current track playing in server +#: src/states_screens/dialogs/server_info_dialog.cpp:120 +#, c-format +msgid "Current track: %s" +msgstr "Trac cyfredol: %s" + +#: src/states_screens/dialogs/server_info_dialog.cpp:130 +msgid "Rank" +msgstr "Safle" + +#. I18N: Show above the player list in server info dialog, tell +#. the user name on server +#: src/states_screens/dialogs/server_info_dialog.cpp:133 +msgid "Player" +msgstr "Chwaraewr" + +#. I18N: Show above the player list in server info dialog, tell +#. the scores of user calculated by player rankings +#: src/states_screens/dialogs/server_info_dialog.cpp:136 +msgid "Scores" +msgstr "Sgorau" + +#. I18N: Show above the player list in server info dialog, tell +#. the user time played on server +#: src/states_screens/dialogs/server_info_dialog.cpp:139 +msgid "Time played" +msgstr "Amser chwaraewyd" + +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 +msgid "Remove from bookmarks" +msgstr "Tynnu o'r nodau tudalennau" + +#: src/states_screens/dialogs/splitscreen_player_dialog.cpp:130 +msgid "Input device already exists." +msgstr "Mae dyfais fewnbynnu eisoes yn bodoli." + +#: src/states_screens/dialogs/splitscreen_player_dialog.cpp:147 +msgid "No player available for connecting to server." +msgstr "Nid oes chwaraewr ar gael i gysylltu â'r gweinydd." + +#. I18N: In the user info dialog +#: src/states_screens/dialogs/user_info_dialog.cpp:61 +#, c-format +msgid "Username: %s" +msgstr "Enw defnyddiwr: %s" + +#: src/states_screens/dialogs/user_info_dialog.cpp:65 +msgid "Cancel Request" +msgstr "Diddymu'r Cais" + +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 +msgid "Today" +msgstr "Heddiw" + +#: src/states_screens/dialogs/user_info_dialog.cpp:169 +msgid "Friend request sent!" +msgstr "Cais ffrind wedi'i anfon!" + +#: src/states_screens/dialogs/user_info_dialog.cpp:226 +msgid "Friend request accepted!" +msgstr "Cais ffrind wedi'i dderbyn!" + +#: src/states_screens/dialogs/user_info_dialog.cpp:278 +msgid "Friend request declined!" +msgstr "Cais ffrind wedi'i wrthod!" + +#: src/states_screens/dialogs/user_info_dialog.cpp:324 +msgid "Friend removed!" +msgstr "Ffrind wedi'i dynnu!" + +#: src/states_screens/dialogs/user_info_dialog.cpp:375 +msgid "Friend request cancelled!" +msgstr "Cais ffrind wedi'i diddymu!" + +#: src/states_screens/dialogs/user_info_dialog.cpp:485 +msgid "Processing" +msgstr "Prosesu" + +#: src/states_screens/dialogs/vote_dialog.cpp:178 +msgid "Fetching last vote" +msgstr "Yn estyn y bleidlais ddiwethaf" + +#: src/states_screens/dialogs/vote_dialog.cpp:197 +msgid "You can adapt your previous rating by clicking the stars beneath." +msgstr "Gelli addasu dy sgôr blaenorol trwy glicio ar y sêr oddi tano." + +#: src/states_screens/dialogs/vote_dialog.cpp:202 +msgid "" +"You have not yet voted for this addon. Select your desired rating by " +"clicking the stars beneath" +msgstr "Nid wyt wedi pleidleisio dros yr ategyn hwn eto. Dewisa sgôr dymunol trwy glicio ar y sêr isod" + +#: src/states_screens/dialogs/vote_dialog.cpp:236 +msgid "Vote successful! You can now close the window." +msgstr "Pleidlais yn llwyddiannus! Nawr gelli gau'r ffenestr." + +#: src/states_screens/dialogs/vote_dialog.cpp:253 +msgid "Performing vote" +msgstr "Wrthi'n pleidleisio" + +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 +msgid "Random Track" +msgstr "Trac ar Hap" + +#: src/states_screens/edit_gp_screen.cpp:117 +#: src/states_screens/ghost_replay_selection.cpp:513 +#: src/states_screens/grand_prix_editor_screen.cpp:111 +#, c-format +msgid "Are you sure you want to remove '%s'?" +msgstr "Wyt ti'n siŵr dy fod am dynnu '%s'?" + +#: src/states_screens/edit_gp_screen.cpp:134 +#: src/states_screens/edit_gp_screen.cpp:382 +msgid "Do you want to save your changes?" +msgstr "Wyt ti eisiau cadw dy newidiadau?" + +#: src/states_screens/edit_gp_screen.cpp:152 +msgid "Laps" +msgstr "Lapiau" + +#: src/states_screens/edit_gp_screen.cpp:153 +msgid "Reversed" +msgstr "Am yn Ôl" + +#. I18N: Indicate that the grand prix is modified and not saved +#: src/states_screens/edit_gp_screen.cpp:290 +#, c-format +msgid "%s (+)" +msgstr "%s (+)" + +#: src/states_screens/edit_gp_screen.cpp:330 +msgid "An error occurred while trying to save your grand prix." +msgstr "Digwyddodd gwall wrth geisio cadw dy Grand Prix." + +#: src/states_screens/edit_track_screen.cpp:317 +msgid "Select a track" +msgstr "Dewisa drac" + +#: src/states_screens/feature_unlocked.cpp:254 +#, c-format +msgid "You completed the easy challenge! Points earned on this level: %i/%i" +msgstr "Rwyt ti wedi cwblhau'r her hawdd! Pwyntiau wedi'u hennill ar y lefel hon: %i/%i" + +#: src/states_screens/feature_unlocked.cpp:260 +#, c-format +msgid "" +"You completed the intermediate challenge! Points earned on this level: %i/%i" +msgstr "Rwyt ti wedi cwblhau'r her ganolradd! Pwyntiau wedi'u hennill ar y lefel hon: %i/%i" + +#: src/states_screens/feature_unlocked.cpp:266 +#, c-format +msgid "" +"You completed the difficult challenge! Points earned on this level: %i/%i" +msgstr "Rwyt ti wedi cwblhau'r her anodd! Pwyntiau wedi'u hennill ar y lefel hon: %i/%i" + +#: src/states_screens/feature_unlocked.cpp:272 +#, c-format +msgid "" +"You completed the SuperTux challenge! Points earned on this level: %i/%i" +msgstr "Rwyt ti wedi cwblhau'r her SuperTux! Pwyntiau wedi'u hennill ar y lefel hon: %i/%i" + +#: src/states_screens/feature_unlocked.cpp:315 +#, c-format +msgid "You unlocked %s!" +msgstr "Rwyt ti wedi datgloi %s!" + +#: src/states_screens/feature_unlocked.cpp:645 +msgid "Challenge Completed" +msgstr "Wedi'i Chwblhau'r Her" + +#: src/states_screens/feature_unlocked.cpp:684 +msgid "You unlocked track %0" +msgstr "Rwyt wedi datgloi trac %0" + +#: src/states_screens/feature_unlocked.cpp:730 +msgid "You unlocked grand prix %0" +msgstr "Rwyt wedi datgloi grand prix %0" + +#: src/states_screens/ghost_replay_selection.cpp:157 +msgctxt "column_name" +msgid "Track" +msgstr "Trac" + +#: src/states_screens/ghost_replay_selection.cpp:168 +#: src/states_screens/online/server_selection.cpp:134 +msgctxt "column_name" +msgid "Players" +msgstr "Chwaraewyr" + +#: src/states_screens/gp_info_screen.cpp:172 +#: src/states_screens/gp_info_screen.cpp:230 +msgid "Reload" +msgstr "Ail-lwytho" + +#: src/states_screens/grand_prix_cutscene.cpp:77 +#: src/states_screens/grand_prix_editor_screen.cpp:100 +#: src/states_screens/grand_prix_editor_screen.cpp:117 +msgid "Please enter the name of the grand prix" +msgstr "Rho enw'r grand prix" + +#: src/states_screens/grand_prix_editor_screen.cpp:168 +msgid "Please select a Grand Prix" +msgstr "Dewisa Grand Prix" + +#: src/states_screens/grand_prix_editor_screen.cpp:338 +msgid "User defined" +msgstr "Defnyddiwr diffiniedig" + +#: src/states_screens/grand_prix_editor_screen.cpp:351 +msgid "Name is empty." +msgstr "Mae'r enw'n wag." + +#: src/states_screens/grand_prix_editor_screen.cpp:359 +msgid "Another grand prix with this name already exists." +msgstr "Mae grand prix arall gyda'r enw hwn eisoes yn bodoli." + +#: src/states_screens/grand_prix_editor_screen.cpp:365 +msgid "Name is too long." +msgstr "Mae'r enw'n rhy hir." + +#. I18N: when failing a GP +#: src/states_screens/grand_prix_lose.cpp:157 +msgid "Better luck next time!" +msgstr "Gwell lwc tro nesa!" + +#: src/states_screens/grand_prix_win.cpp:169 +msgid "You completed a challenge!" +msgstr "Rwyt ti wedi cwblhau her!" + +#: src/states_screens/grand_prix_win.cpp:325 +msgid "You won the Grand Prix!" +msgstr "Rwyt ti wedi ennill y Grand Prix!" + +#: src/states_screens/grand_prix_win.cpp:326 +msgid "You completed the Grand Prix!" +msgstr "Rwyt ti wedi cwblhau'r Grand Prix!" + +#: src/states_screens/high_score_selection.cpp:147 +msgctxt "column_name" +msgid "Number of karts" +msgstr "Nifer y cartiau" + +#: src/states_screens/high_score_selection.cpp:352 +msgid "Are you sure you want to remove this high score entry?" +msgstr "Wyt ti'n siŵr dy fod am ddileu'r cofnod sgôr uchel hwn?" + +#: src/states_screens/high_score_selection.cpp:360 +msgid "Are you sure you want to remove all of your high scores?" +msgstr "Wyt ti'n siŵr dy fod am ddileu dy holl gofnodion sgôr uchel?" + +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Hoffi" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Ysgafn" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Trwm" + +#: src/states_screens/kart_selection.cpp:490 +msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" +msgstr "Cysyllta fysellfwrdd neu bad gemau i chwarae sgrin hollt aml-chwaraewr" + +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 +msgid "Random Kart" +msgstr "Cart ar Hap" + +#: src/states_screens/kart_selection.cpp:1003 +msgid "Locked" +msgstr "Wedi Cloi" + +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 +msgid "" +"Everyone:\n" +"Press the 'Select' button to join the game" +msgstr "Pawb:\nPwyswch y botwm 'Dewis' i ymuno â'r gêm" + +#: src/states_screens/main_menu_screen.cpp:343 +msgid "Would you like to play the tutorial of the game?" +msgstr "Hoffet ti chwarae tiwtorial y gêm?" + +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 +msgid "" +"You can not play online without internet access. If you want to play online," +" go in the options menu, and check \"Connect to the Internet\"." +msgstr "Nid oes modd i ti chwarae ar-lein heb fynediad i'r rhyngrwyd. Os wyt ti eisiau chwarae ar-lein, rhaid mynd i'r ddewislen Dewisiadau, a thicio \"Cysylltu â'r Rhyngrwyd\"." + +#: src/states_screens/main_menu_screen.cpp:619 +msgid "" +"You can not download addons without internet access. If you want to download" +" addons, go in the options menu, and check \"Connect to the Internet\"." +msgstr "Nid oes modd i ti lwytho ategion i lawr heb fynediad i'r rhyngrwyd. Os wyt ti eisiau chwarae ar-lein, rhaid mynd i'r ddewislen Dewisiadau, a thicio \"Cysylltu â'r Rhyngrwyd\"." + +#: src/states_screens/main_menu_screen.cpp:627 +msgid "" +"You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" +"\n" +"You can however delete already downloaded addons." +msgstr "Nid oes modd i ti lwytho ategion i lawr heb fynediad i'r rhyngrwyd. Os wyt ti eisiau chwarae ar-lein, rhaid mynd i'r ddewislen Dewisiadau, a thicio \"Cysylltu â'r Rhyngrwyd\".\n\nFodd bynnag, mae modd i ti ddileu ategion sydd eisoes wedi'u llwytho i lawr." + +#: src/states_screens/main_menu_screen.cpp:666 +msgid "The add-ons module is currently disabled in the Options screen" +msgstr "Mae'r modiwl ychwanegion wedi'i analluogi ar hyn o bryd yn y sgrin Dewisiadau" + +#: src/states_screens/main_menu_screen.cpp:678 +msgid "Please wait while the add-ons are loading" +msgstr "Arhosa tra bod yr ychwanegion yn llwytho" + +#: src/states_screens/main_menu_screen.cpp:699 +msgid "Are you sure you want to quit STK?" +msgstr "Wyt ti'n siŵr dy fod am adael STK?" + +#: src/states_screens/online/create_server_screen.cpp:107 +msgid "Create LAN Server" +msgstr "Creu Gweinydd LAN" + +#: src/states_screens/online/create_server_screen.cpp:112 +#, c-format +msgid "%s's server" +msgstr "Gweinydd %s" + +#. I18N: In the create server screen +#: src/states_screens/online/create_server_screen.cpp:220 +msgid "No. of grand prix track(s)" +msgstr "Nifer y trac(iau) grand prix" + +#: src/states_screens/online/create_server_screen.cpp:303 +msgid "Name has to be between 4 and 30 characters long!" +msgstr "Rhaid i'r enw fod rhwng 4 a 30 nod o hyd!" + +#: src/states_screens/online/create_server_screen.cpp:320 +msgid "Incorrect characters in password!" +msgstr "Mae nodau anghywir yn y cyfrinair!" + +#. I18N: In the networking lobby, ready button is to allow player to tell +#. server that he is ready for next game for owner less server +#: src/states_screens/online/networking_lobby.cpp:196 +msgid "Ready" +msgstr "Parod" + +#. I18N: Live join is displayed in networking lobby to allow players +#. to join the current started in-progress game +#: src/states_screens/online/networking_lobby.cpp:199 +msgid "Live join" +msgstr "Ymuno'n fyw" + +#. I18N: Spectate is displayed in networking lobby to allow players +#. to join the current started in-progress game +#: src/states_screens/online/networking_lobby.cpp:204 +msgid "Spectate" +msgstr "Gwylio" + +#: src/states_screens/online/networking_lobby.cpp:205 +msgid "Install addon" +msgstr "Gosod ychwanegyn" + +#. I18N: In the networking lobby, show when player is required to +#. wait before the current game finish with remaining time, +#. showing the current track name inside bracket +#: src/states_screens/online/networking_lobby.cpp:572 +#, c-format +msgid "" +"Please wait for the current game's (%s) end, estimated remaining time: %s." +msgstr "Arhosa hyd ddiwedd y gêm gyfredol (%s), amcangyfrif o faint sy'n weddill: %s." + +#. I18N: In the networking lobby, show when player is required +#. to wait before the current game finish with remaining time +#: src/states_screens/online/networking_lobby.cpp:580 +#, c-format +msgid "Please wait for the current game's end, estimated remaining time: %s." +msgstr "Arhosa hyd ddiwedd y gêm gyfredol, amcangyfrif o faint sy'n weddill: %s." + +#. I18N: In the networking lobby, show when player is required +#. to wait before the current game finish with progress in +#. percent, showing the current track name inside bracket +#: src/states_screens/online/networking_lobby.cpp:592 +msgid "Please wait for the current game's (%s) end, estimated progress: %s%." +msgstr "Arhosa hyd ddiwedd y gêm gyfredol (%s), amcangyfrif o faint sy'n weddill: %s%." + +#. I18N: In the networking lobby, show when player is required +#. to wait before the current game finish with progress in +#. percent +#: src/states_screens/online/networking_lobby.cpp:601 +msgid "Please wait for the current game's end, estimated progress: %d%." +msgstr "Arhosa hyd ddiwedd y gêm gyfredol, amcangyfrif o'r cynnydd: %d%." + +#. I18N: In the networking lobby, show when player is required to +#. wait before the current game finish +#: src/states_screens/online/networking_lobby.cpp:609 +msgid "Please wait for the current game's end." +msgstr "Arhosa hyd ddiwedd y gêm gyfredol." + +#: src/states_screens/online/networking_lobby.cpp:676 +#, c-format +msgid "Game will start if there is more than %d player." +msgid_plural "Game will start if there are more than %d players." +msgstr[0] "Bydd y gêm yn cychwyn os oes mwy na %d chwaraewr." +msgstr[1] "Bydd y gêm yn cychwyn os oes mwy na %d chwaraewr." +msgstr[2] "Bydd y gêm yn cychwyn os oes mwy na %d chwaraewr." +msgstr[3] "Bydd y gêm yn cychwyn os oes mwy na %d chwaraewr." + +#. I18N: In the networking lobby, display the starting timeout +#. for owner-less server to begin a game +#: src/states_screens/online/networking_lobby.cpp:690 +#, c-format +msgid "" +"Starting after %d second, or once everyone has pressed the 'Ready' button." +msgid_plural "" +"Starting after %d seconds, or once everyone has pressed the 'Ready' button." +msgstr[0] "Yn cychwyn ar ôl %d eiliad, neu unwaith mae pawb wedi pwyso'r botwm 'Barod'." +msgstr[1] "Yn cychwyn ar ôl %d eiliad, neu unwaith mae pawb wedi pwyso'r botwm 'Barod'." +msgstr[2] "Yn cychwyn ar ôl %d eiliad, neu unwaith mae pawb wedi pwyso'r botwm 'Barod'." +msgstr[3] "Yn cychwyn ar ôl %d eiliad, neu unwaith mae pawb wedi pwyso'r botwm 'Barod'." + +#: src/states_screens/online/networking_lobby.cpp:727 +#, c-format +msgid "Connecting to server %s" +msgstr "Yn cysylltu â gweinydd %s" + +#: src/states_screens/online/networking_lobby.cpp:732 +msgid "Finding a quick play server" +msgstr "Yn canfod gweinydd chwarae cyflym" + +#. I18N: In kart screen, show before the voting period in network ends. +#: src/states_screens/online/network_kart_selection.cpp:218 +#: src/states_screens/online/tracks_screen.cpp:952 +#, c-format +msgid "Remaining time: %d" +msgstr "Amser yn weddill: %d" + +#. I18N: Goals in achievement +#: src/states_screens/online/online_profile_achievements.cpp:85 +msgid "Goals" +msgstr "Nodau" + +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 +msgid "Fetching achievements" +msgstr "Yn estyn cyflawniadau" + +#: src/states_screens/online/online_profile_base.cpp:121 +#, c-format +msgid "%s's profile" +msgstr "Proffil %s" + +#: src/states_screens/online/online_profile_friends.cpp:80 +msgid "Since" +msgstr "Ers" + +#: src/states_screens/online/online_profile_friends.cpp:81 +msgid "Status" +msgstr "Statws" + +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 +msgid "Fetching friends" +msgstr "Yn estyn ffrindiau" + +#: src/states_screens/online/online_profile_friends.cpp:241 +msgid "New Request" +msgstr "Cais Newydd" + +#: src/states_screens/online/online_profile_friends.cpp:242 +msgid "Pending" +msgstr "Danystyriaeth" + +#: src/states_screens/online/online_profile_friends.cpp:246 +msgid "Offline" +msgstr "All-lein" + +#: src/states_screens/online/online_profile_settings.cpp:83 +msgid "Enter new E-mail below" +msgstr "Rho e-bost newydd isod" + +#: src/states_screens/online/online_profile_settings.cpp:88 +msgid "New Email has to be between 5 and 254 characters long!" +msgstr "Rhaid i e-bost newydd fod rhwng 5 a 254 nod o hyd!" + +#: src/states_screens/online/online_profile_settings.cpp:97 +msgid "New Email is invalid!" +msgstr "Mae'r e-bost newydd yn annilys!" + +#: src/states_screens/online/online_profile_settings.cpp:122 +msgid "E-mail changed!" +msgstr "Mae'r e-bost wedi newid!" + +#: src/states_screens/online/online_profile_settings.cpp:124 +#, c-format +msgid "Failed to change E-mail: %s" +msgstr "Wedi methu â newid e-bost: %s" + +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Newyddion o Flog STK" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Dyddiad" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Does dim newyddion ar gael ar hyn o bryd." + +#. I18N: Shown to players when he is not is not logged in +#: src/states_screens/online/online_screen.cpp:317 +msgid "" +"You must be logged in to play Global networking. Click your username above." +msgstr "Rhaid i ti fod wedi mewngofnodi i chwarae rhwydweithio byd-eang. Clicia ar dy enw defnyddiwr uchod." + +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 +msgid "Searching" +msgstr "Yn chwilio" + +#: src/states_screens/online/register_screen.cpp:169 +#: src/states_screens/options/user_screen.cpp:114 +msgid "Exit game" +msgstr "Gadael y gêm" + +#: src/states_screens/online/register_screen.cpp:282 +#: src/states_screens/online/register_screen.cpp:289 +#, c-format +msgid "Could not create player '%s'." +msgstr "Methu creu chwaraewr '%s'." + +#: src/states_screens/online/register_screen.cpp:306 +msgid "User name cannot be empty." +msgstr "Nid oes modd i enw defnyddiwr fod yn wag." + +#: src/states_screens/online/register_screen.cpp:362 +msgid "Online username and password must not be the same!" +msgstr "Ddylai enw defnyddiwr a chyfrinair ar-lein ddim fod yr un peth!" + +#: src/states_screens/online/register_screen.cpp:366 +msgid "Emails don't match!" +msgstr "Nid yw'r e-byst yn cyfateb!" + +#: src/states_screens/online/register_screen.cpp:370 +msgid "" +"Online username can only contain alphanumeric (ASCII) characters, periods, " +"dashes and underscores!" +msgstr "Gall enw defnyddiwr ar-lein gynnwys dim ond nodau alffaniwmerig (ASCII), llinellau toriad a thanlinellau!" + +#: src/states_screens/online/register_screen.cpp:374 +msgid "Online username has to be between 3 and 30 characters long!" +msgstr "Rhaid i enw defnyddiwr ar-lein fod rhwng 3 a 30 nod o hyd!" + +#: src/states_screens/online/register_screen.cpp:378 +msgid "Online username must not start with a number!" +msgstr "Ddylai enw defnyddiwr ar-lein ddim cychwyn gyda rhif!" + +#: src/states_screens/online/register_screen.cpp:386 +msgid "Email has to be between 5 and 254 characters long!" +msgstr "Rhaid i e-bost newydd fod rhwng 5 a 254 nod o hyd!" + +#: src/states_screens/online/register_screen.cpp:392 +msgid "Email is invalid!" +msgstr "Mae'r e-bost yn annilys!" + +#: src/states_screens/online/register_screen.cpp:456 +msgid "" +"You will receive an email with further instructions regarding account " +"activation. Please be patient and be sure to check your spam folder." +msgstr "Byddi'n derbyn e-bost gyda chyfarwyddiadau pellach ynghylch gweithredu cyfrif. Bydd yn amyneddgar a gwna'n siŵr i edrych yn dy ffolder sbam." + +#: src/states_screens/online/register_screen.cpp:495 +msgid "Internet access is disabled, please enable it in the options" +msgstr "Mae mynediad i'r rhyngrwyd wedi'i analluogi, galluoga ef yn y Dewisiadau" + +#: src/states_screens/online/server_selection.cpp:132 +msgctxt "column_name" +msgid "Name" +msgstr "Enw" + +#: src/states_screens/online/server_selection.cpp:133 +msgctxt "column_name" +msgid "Game mode" +msgstr "Modd gêm" + +#. I18N: In server selection screen, owner of server, only displayed +#. if it's localhost or friends' +#: src/states_screens/online/server_selection.cpp:140 +msgctxt "column_name" +msgid "Owner" +msgstr "Perchennog" + +#. I18N: In server selection screen, distance to server +#: src/states_screens/online/server_selection.cpp:142 +msgctxt "column_name" +msgid "Distance (km)" +msgstr "Pellter (km)" + +#. I18N: In server selection screen, unknown distance to server +#: src/states_screens/online/server_selection.cpp:316 +msgid "Unknown" +msgstr "Anhysbys" + +#. I18N: Message shown to user if no IPv4 detected by STK +#: src/states_screens/online/server_selection.cpp:361 +msgid "No IPv4 detected, you may not be able to join any servers." +msgstr "Heb ganfod IPv4, efallai na fyddi'n gallu ymuno ag unrhyw weinyddion." + +#. I18N: Message shown to user if no IPv6 detected by STK +#: src/states_screens/online/server_selection.cpp:363 +msgid "No IPv6 detected, you may not be able to join any servers." +msgstr "Heb ganfod IPv6, efallai na fyddi'n gallu ymuno ag unrhyw weinyddion." + +#: src/states_screens/online/server_selection.cpp:502 +msgid "No server is available." +msgstr "Dim gweinydd ar gael." + +#: src/states_screens/online/server_selection.cpp:510 +msgid "Fetching servers" +msgstr "Estyn gweinyddion" + +#: src/states_screens/online/server_selection.cpp:576 +msgid "Server Bookmarks" +msgstr "Nodau Tudalen Gweinyddion" + +#. I18N: In track screen for networking, clarify voting phase +#: src/states_screens/online/tracks_screen.cpp:322 +msgid "" +"If a majority of players all select the same track and race settings, voting" +" will end early." +msgstr "Os bydd mwyafrif o chwaraewyr i gyd yn dewis yr un gosodiadau trac a ras, bydd y pleidleisio'n dod i ben yn gynnar." + +#. I18N: In track screen +#. I18N: In the track info screen +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 +msgid "Random item location" +msgstr "Lleoliad eitem ar hap" + +#. I18N: In track screen +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 +msgid "Number of goals to win" +msgstr "Nifer o nodau i'w hennill" + +#. I18N: In the track info screen +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 +msgid "Drive in reverse" +msgstr "Gyrru am yn Ôl" + +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 +msgid "Locked: solve active challenges to gain access to more!" +msgstr "O dan glo: datrysa heriau gweithredol i gael mynediad at ragor!" + +#: src/states_screens/options/options_screen_device.cpp:56 +msgid "Action" +msgstr "Gweithredu" + +#: src/states_screens/options/options_screen_device.cpp:57 +msgid "Key binding" +msgstr "Dynodi bysell" + +#. I18N: button to disable a gamepad configuration +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 +msgid "Disable Device" +msgstr "Analluogi Dyfais" + +#. I18N: button to enable a gamepad configuration +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 +msgid "Enable Device" +msgstr "Galluogi Dyfais" + +#. I18N: button to enable a keyboard configuration +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 +msgid "Enable Configuration" +msgstr "Galluogi Ffurfweddiad" + +#. I18N: Key binding section +#: src/states_screens/options/options_screen_device.cpp:156 +msgid "Game Keys" +msgstr "Bysellau Gêm" + +#. I18N: Key binding section +#: src/states_screens/options/options_screen_device.cpp:170 +msgid "Menu Keys" +msgstr "Bysellau Dewislen" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:246 +msgid "Steer Left" +msgstr "Llywio i'r Chwith" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:249 +msgid "Steer Right" +msgstr "Llywio i'r Dde" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:252 +msgid "Accelerate" +msgstr "Cyflymu" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:255 +msgid "Brake / Reverse" +msgstr "Brecio / Am yn Ôl" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:258 +msgid "Fire" +msgstr "Tânio" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:261 +msgid "Nitro" +msgstr "Nitro" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:267 +msgid "Look Back" +msgstr "Edrych Nôl" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:270 +msgid "Rescue" +msgstr "Achub" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:273 +msgid "Pause Game" +msgstr "Oedi Gêm" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:278 +msgid "Up" +msgstr "I fyny" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:281 +msgid "Down" +msgstr "I lawr" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:284 +msgid "Left" +msgstr "Chwith" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:287 +msgid "Right" +msgstr "De" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:290 +msgid "Select" +msgstr "Dewis" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:293 +msgid "Cancel/Back" +msgstr "Na/Nôl" + +#: src/states_screens/options/options_screen_device.cpp:384 +msgid "* A blue item means a conflict with another configuration" +msgstr "* Mae eitem las yn golygu gwrthdaro â ffurfweddiad arall" + +#: src/states_screens/options/options_screen_device.cpp:389 +msgid "* A red item means a conflict in the current configuration" +msgstr "* Mae eitem goch yn golygu gwrthdaro yn y ffurfweddiad cyfredol" + +#: src/states_screens/options/options_screen_device.cpp:494 +msgid "" +"Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," +" all keys that contain a character that is different in upper-case will stop" +" working." +msgstr "Rhybudd: Nid yw'r 'Shift' yn fysell sy'n cael ei argymell. Pan fydd 'Shift' yn cael ei bwyso, bydd pob bysell sy'n cynnwys nod sy'n wahanol mewn priflythrennau yn stopio gweithio." + +#. I18N: shown before deleting an input configuration +#: src/states_screens/options/options_screen_device.cpp:578 +msgid "Are you sure you want to permanently delete this configuration?" +msgstr "Wyt ti'n siŵr dy fod am ddileu'r ffurfweddiad hwn yn barhaol?" + +#: src/states_screens/options/options_screen_device.cpp:606 +msgid "Enter new configuration name, leave empty to revert default value." +msgstr "Rho enw ffurfweddiad newydd, gad yn wag i adfer y gwerth rhagosodedig." + +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Fertigol" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Llorweddol" + +#. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text +#. fits the screen in low resolutions. +#: src/states_screens/options/options_screen_general.cpp:69 +msgid "" +"In multiplayer mode, players can select handicapped\n" +"(more difficult) profiles on the kart selection screen" +msgstr "Yn y modd aml-chwaraewr, gall chwaraewyr ddewis\nproffiliau anfanteisiol (anoddach) ar y sgrin dewis cart" + +#. I18N: For mobile version for STK, install the full game assets which +#. will download from stk server +#: src/states_screens/options/options_screen_general.cpp:85 +msgid "Install full game assets" +msgstr "Gosod asedau'r gêm llawn" + +#: src/states_screens/options/options_screen_general.cpp:189 +msgid "Are you sure to uninstall full game assets?" +msgstr "Wyt ti'n siŵr o fod eisiau dadosod asedau'r gêm llawn?" + +#: src/states_screens/options/options_screen_input.cpp:98 +#, c-format +msgid "Keyboard %i" +msgstr "Bysellfwrdd %i" + +#: src/states_screens/options/options_screen_input.cpp:149 +msgid "Touch Device" +msgstr "Dyfais Gyffwrdd" + +#. I18N: In the input configuration screen, help for touch device +#: src/states_screens/options/options_screen_input.cpp:186 +msgid "Tap on a device to configure it" +msgstr "Tapia ar ddyfais i'w ffurfweddu" + +#. I18N: in the language choice, to select the same language as the OS +#: src/states_screens/options/options_screen_language.cpp:62 +msgid "System Language" +msgstr "Iaith y System" + +#. I18N: In the UI options, minimap position in the race UI +#: src/states_screens/options/options_screen_ui.cpp:67 +msgid "In the bottom-left" +msgstr "Yn y gwaelod-chwith" + +#. I18N: In the UI options, minimap position in the race UI +#: src/states_screens/options/options_screen_ui.cpp:69 +msgid "On the right side" +msgstr "Ar yr ochr dde" + +#. I18N: In the UI options, minimap position in the race UI +#: src/states_screens/options/options_screen_ui.cpp:71 +msgid "Hidden" +msgstr "Cudd" + +#. I18N: In the UI options, minimap position in the race UI +#: src/states_screens/options/options_screen_ui.cpp:73 +msgid "Centered" +msgstr "Canolwyd" + +#. I18N: In the UI options, Very small font size +#: src/states_screens/options/options_screen_ui.cpp:92 +msgid "Very small" +msgstr "Bach iawn" + +#. I18N: In the UI options, Small font size +#: src/states_screens/options/options_screen_ui.cpp:94 +msgid "Small" +msgstr "Bach" + +#. I18N: In the UI options, Large font size +#: src/states_screens/options/options_screen_ui.cpp:98 +msgid "Large" +msgstr "Mawr" + +#. I18N: In the UI options, Very large font size +#: src/states_screens/options/options_screen_ui.cpp:100 +msgid "Very large" +msgstr "Mawr iawn" + +#: src/states_screens/options/options_screen_ui.cpp:537 +msgid "" +"Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" +"\n" +"Closing the game before the story mode's completion invalidates the timer.\n" +"\n" +"To use the speedrun mode, please use a new profile." +msgstr "Dim ond os nad yw'r gêm wedi cau ers agor y modd stori y mae modd galluogi modd Rhedeg Cyflym.\n\nMae cau'r gêm cyn cwblhau'r modd stori yn annilysu'r amserydd.\n\nI ddefnyddio'r modd Rhedeg Cyflym, defnyddia broffil newydd." + +#. I18N: In the video options +#: src/states_screens/options/options_screen_video.cpp:249 +msgid "Vertical Sync" +msgstr "Cyweddu Fertigol" + +#. I18N: in graphical options. The \n is a newline character, place it where +#. appropriate, two can be used if required. +#: src/states_screens/options/options_screen_video.cpp:266 +msgid "" +"Vsync forces the graphics card to supply a new frame\n" +"only when the monitor is ready to display it." +msgstr "Mae Vsync yn gorfodi'r cerdyn graffeg i gyflenwi ffrâm newydd\ndim ond pan fydd y monitor yn barod i'w ddangos." + +#. I18N: in graphical options. +#: src/states_screens/options/options_screen_video.cpp:269 +msgid "Vsync will not work if your drivers don't support it." +msgstr "Ni fydd Vsync yn gweithio os nad yw dy yrwyr yn ei gefnogi." + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:466 +#, c-format +msgid "Particles Effects: %s" +msgstr "Effeithiau Gronynnau: %s" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:472 +#, c-format +msgid "Animated Characters: %s" +msgstr "Nodau Animeiddiedig: %s" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:475 +#, c-format +msgid "Dynamic lights: %s" +msgstr "Goleuadau deinamig: %s" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:478 +#, c-format +msgid "Light scattering: %s" +msgstr "Gwasgaru golau: %s" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:481 +#, c-format +msgid "Anti-aliasing: %s" +msgstr "Gwrth-lyfnhau: %s" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:484 +#, c-format +msgid "Ambient occlusion: %s" +msgstr "Achludiad amgylchynol: %s" + +#: src/states_screens/options/options_screen_video.cpp:488 +#, c-format +msgid "Shadows: %s" +msgstr "Cysgodion: %s" + +#: src/states_screens/options/options_screen_video.cpp:490 +#, c-format +msgid "Shadows: %i" +msgstr "Cysgodion: %i" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:493 +#, c-format +msgid "Bloom: %s" +msgstr "Blŵm: %s" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:497 +#, c-format +msgid "Glow (outlines): %s" +msgstr "Tywynnu (Amlinelliadau): %s" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:501 +#, c-format +msgid "Light shaft (God rays): %s" +msgstr "Siafft golau (pelydrau Duw): %s" + +#: src/states_screens/options/options_screen_video.cpp:506 +#, c-format +msgid "Rendered image quality: %s" +msgstr "Ansawdd delwedd wedi'i rendro: %s" + +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Manylion geometreg: %s" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:538 +#, c-format +msgid "Motion blur: %s" +msgstr "Pwl symud: %s" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:542 +#, c-format +msgid "Depth of field: %s" +msgstr "Dyfnder ffocws: %s" + +#: src/states_screens/options/user_screen.cpp:353 +msgid "Internet access is disabled. Do you want to enable it?" +msgstr "Mae mynediad i'r rhyngrwyd wedi'i analluogi. Wyt ti am ei alluogi?" + +#: src/states_screens/options/user_screen.cpp:541 +msgid "You need to enter a password." +msgstr "Mae angen i ti roi cyfrinair." + +#: src/states_screens/options/user_screen.cpp:562 +#, c-format +msgid "Logging out '%s'" +msgstr "Allgofnodi '%s'" + +#: src/states_screens/options/user_screen.cpp:563 +#, c-format +msgid "Logging in '%s'" +msgstr "Mewngofnodi '%s'" + +#: src/states_screens/options/user_screen.cpp:646 +msgid "You can't delete the only player." +msgstr "Nid oes modd i ti ddileu'r unig chwaraewr." + +#. I18N: In the player info dialog (when deleting) +#: src/states_screens/options/user_screen.cpp:654 +#, c-format +msgid "Do you really want to delete player '%s'?" +msgstr "Wyt ti wir eisiau dileu chwaraewr '%s'?" + +#. I18N: as in "ready, set, go", shown at the beginning of the race +#: src/states_screens/race_gui_base.cpp:73 +msgid "Ready!" +msgstr "Parod!" + +#. I18N: as in "ready, set, go", shown at the beginning of the race +#: src/states_screens/race_gui_base.cpp:75 +msgid "Set!" +msgstr "Gosod!" + +#. I18N: as in "ready, set, go", shown at the beginning of the race +#: src/states_screens/race_gui_base.cpp:77 +msgid "Go!" +msgstr "Mynd!" + +#. I18N: Shown when a goal is scored +#: src/states_screens/race_gui_base.cpp:79 +msgid "GOAL!" +msgstr "GÔL!" + +#. I18N: Shown waiting for other players in network to finish loading or +#. waiting +#: src/states_screens/race_gui_base.cpp:82 +#: src/states_screens/race_result_gui.cpp:429 +msgid "Waiting for others" +msgstr "Aros am eraill" + +#. I18N: Shown waiting for the server in network if live join or spectate +#: src/states_screens/race_gui_base.cpp:84 +msgid "Waiting for the server" +msgstr "Aros am y gweinydd" + +#. I18N: string used to show the song title (e.g. "Sunny Song") +#: src/states_screens/race_gui_base.cpp:646 +#, c-format +msgid "\"%s\"" +msgstr "%s" + +#. I18N: string used to show the author of the music. (e.g. "Sunny Song" by +#. "John Doe") +#: src/states_screens/race_gui_base.cpp:656 +msgid "by" +msgstr "gan" + +#: src/states_screens/race_gui_base.cpp:769 +msgid "Collect nitro!" +msgstr "Casglu nitro!" + +#: src/states_screens/race_gui_base.cpp:771 +msgid "Follow the leader!" +msgstr "Dilyn yr arweinydd!" + +#. I18N: When some GlobalPlayerIcons are hidden, write "Top 10" to show it +#: src/states_screens/race_gui_base.cpp:954 +#, c-format +msgid "Top %i" +msgstr "%i uchaf" + +#: src/states_screens/race_gui.cpp:445 +msgid "Challenge Failed" +msgstr "Her wedi Methu" + +#. I18N: Shown when multitouch GUI exists +#. and press the podium (2, 1, 3 like) icon instead of fire button +#: src/states_screens/race_gui_overworld.cpp:541 +msgid "Press podium icon to start tutorial" +msgstr "Pwysa eicon y podiwm i agor y tiwtorial" + +#: src/states_screens/race_gui_overworld.cpp:547 +msgid "Press fire to start the tutorial" +msgstr "Pwysa tanio i gychwyn y tiwtorial" + +#. I18N: Shown when multitouch GUI exists +#. and press the podium (2, 1, 3 like) icon instead of fire button +#: src/states_screens/race_gui_overworld.cpp:623 +msgid "Press podium icon to start the challenge" +msgstr "Pwysa eicon y podiwm i gychwyn yr her" + +#: src/states_screens/race_gui_overworld.cpp:629 +msgid "Press fire to start the challenge" +msgstr "Pwysa tanio i gychwyn yr her" + +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Yn ôl i osodiadau fideo" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Cadw canlyniadau'r prawf" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Yn ôl i'r brif ddewislen" + +#: src/states_screens/race_result_gui.cpp:289 +msgid "Quit the server" +msgstr "Gadael y gweinydd" + +#: src/states_screens/race_result_gui.cpp:330 +msgid "Abort Grand Prix" +msgstr "Gadael Grand Prix" + +#: src/states_screens/race_result_gui.cpp:350 +msgid "Restart" +msgstr "Ail gychwyn" + +#: src/states_screens/race_result_gui.cpp:357 +msgid "Back to challenge selection" +msgstr "Nôl i ddewis her" + +#: src/states_screens/race_result_gui.cpp:365 +msgid "Race against the new ghost replay" +msgstr "Ras yn erbyn yr ailchwarae ysbrydion newydd" + +#: src/states_screens/race_result_gui.cpp:373 +msgid "Back to the menu" +msgstr "Nôl i'r ddewislen" + +#: src/states_screens/race_result_gui.cpp:556 +msgid "Do you really want to abort the Grand Prix?" +msgstr "Wyt ti wir eisiau gadael y Grand Prix?" + +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Adroddiad perfformiad wedi'i gadw yn \"%s\"." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 +msgid "Red Team Wins" +msgstr "Mae'r Tîm Coch Wedi Ennill" + +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 +msgid "Blue Team Wins" +msgstr "Mae'r Tîm Glas Wedi Ennill" + +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 +msgid "It's a draw" +msgstr "Mae'n Gyfartal" + +#: src/states_screens/race_result_gui.cpp:935 +#, c-format +msgid "Eliminated after %s" +msgstr "Allan ar ôl %s" + +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 +msgid "Eliminated" +msgstr "Allan" + +#. I18N: indicates a player that scored in their own goal in result screen +#: src/states_screens/race_result_gui.cpp:1681 +msgid "(Own Goal)" +msgstr "(I'w Rwyd ei Hun)" + +#: src/states_screens/race_result_gui.cpp:1770 +#, c-format +msgid "Track %i/%i" +msgstr "Trac %i/%i" + +#: src/states_screens/race_result_gui.cpp:1889 +msgid "Grand Prix progress:" +msgstr "Cynnydd Grand Prix:" + +#: src/states_screens/race_result_gui.cpp:1975 +msgid "Highscores" +msgstr "Sgorau uchel" + +#: src/states_screens/race_result_gui.cpp:2142 +#, c-format +msgid "Best lap time: %s" +msgstr "Yr amser lap gorau: %s" + +#. I18N: is used to indicate who has the bast laptime (best laptime "by +#. kart_name") +#: src/states_screens/race_result_gui.cpp:2155 +#, c-format +msgid "by %s" +msgstr "gan %s" + +#: src/states_screens/race_result_gui.cpp:2229 +msgid "You completed the challenge!" +msgstr "Rwyt wedi cwblhau'r her!" + +#: src/states_screens/race_result_gui.cpp:2229 +msgid "You failed the challenge!" +msgstr "Rwyt wedi methu'r her!" + +#: src/states_screens/race_result_gui.cpp:2282 +msgid "Reached Requirements of SuperTux" +msgstr "Wedi cyrraedd Gofynion SuperTux" + +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Canlyniadau Profion Perfformiad" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Hyd y prawf: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Nifer y fframiau: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "FPS cyson: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "FPS Sefydlog yn Bennaf: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "FPS nodweddiadol: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Cydraniad llorweddol: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Cydraniad fertigol: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Goleuo deinamig: YMLAEN" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Goleuo deinamig: I FFWRDD" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Cydraniad rendrad: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Gwrth-aliasio: YMLAEN" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Gwrth-aliasio: I FFWRDD" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Goleuo ar sail delwedd: I FFWRDD" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Goleuo ar sail delwedd: YMLAEN" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Achludiad amgylchol: YMLAEN" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Achludiad amgylchol: I FFWRDD" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Cydraniad cysgodol: %s" + +#: src/states_screens/race_setup_screen.cpp:89 +msgid "All blows allowed, so catch weapons and make clever use of them!" +msgstr "Yn caniatáu pob ergyd, felly cipia arfau a gwna ddefnydd clyfar ohonyn nhw!" + +#: src/states_screens/race_setup_screen.cpp:96 +msgid "Contains no powerups, so only your driving skills matter!" +msgstr "Nid yw'n cynnwys unrhyw bweriadau, felly dim ond dy sgiliau gyrru sy'n bwysig!" + +#. I18N: short definition for follow-the-leader game mode +#: src/states_screens/race_setup_screen.cpp:109 +msgid "Keep up with the leader kart but don't overtake it!" +msgstr "Cadw fyny gyda chart yr arweinydd ond paid â'i basio!" + +#: src/states_screens/race_setup_screen.cpp:115 +msgid "Hit others with weapons until they lose all their lives." +msgstr "Taro eraill gydag arfau nes iddyn nhw golli eu bywydau i gyd." + +#: src/states_screens/race_setup_screen.cpp:120 +msgid "Push the ball into the opposite cage to score goals." +msgstr "Gwthia'r bêl i'r cawell gyferbyn i sgorio goliau." + +#: src/states_screens/race_setup_screen.cpp:130 +msgid "Explore tracks to find all hidden eggs" +msgstr "Chwilia'r traciau i ddod o hyd i'r holl wyau cudd" + +#: src/states_screens/race_setup_screen.cpp:138 +msgid "Race against ghost karts and try to beat them!" +msgstr "Rasio'n erbyn cartiau ysbrydion a cheisio eu curo!" + +#: src/states_screens/race_setup_screen.cpp:143 +msgid "Complete as many laps as possible in a given amount of time." +msgstr "Cwblhau gymaint o lapiau â phosibl mewn cyfnod penodol o amser." + +#. I18N: In soccer setup screen +#: src/states_screens/soccer_setup_screen.cpp:120 +msgid "Press red or blue soccer icon to change team" +msgstr "Pwysa eicon pêl-droed coch neu las i newid tîm" + +#. I18N: when showing who is the author of track '%s' +#. I18N: (place %s where the name of the author should appear) +#: src/states_screens/track_info_screen.cpp:151 +#, c-format +msgid "Track by %s" +msgstr "Trac gan %s" + +#. I18N: the max players supported by an arena. +#: src/states_screens/track_info_screen.cpp:159 +#, c-format +msgid "Max players supported: %d" +msgstr "Cefnogi uchafswm o chwaraewyr: %d" + +#: src/states_screens/track_info_screen.cpp:389 +msgid "Number of red team AI karts" +msgstr "Nifer y cartiau AI tîm coch" + +#: src/states_screens/tracks_and_gp_screen.cpp:124 +msgid "" +"You cannot play this Grand Prix because it contains tracks that aren't " +"unlocked!" +msgstr "Nid oes modd i ti chwarae'r Grand Prix hwn oherwydd ei fod yn cynnwys traciau sydd heb eu datgloi!" + +#: src/states_screens/tracks_and_gp_screen.cpp:245 +msgid "Locked!" +msgstr "Wedi Cloi!" + +#: src/utils/string_utils.cpp:1242 +#, c-format +msgid "%s MB" +msgstr "%s MB" + +#: src/utils/string_utils.cpp:1249 src/utils/string_utils.cpp:1253 +#, c-format +msgid "%s KB" +msgstr "%s KB" + +#. I18N: Format for dates (%d = day, %m = month, %Y = year). See +#. http://www.cplusplus.com/reference/ctime/strftime/ for more info about date +#. formats. +#: src/utils/time.cpp:74 +msgid "%d/%m/%Y" +msgstr "%d/%m/%Y" + +#: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 +msgid "Complete all challenges to unlock the big door!" +msgstr "Cwblha bob her i ddatgloi'r drws mawr!" + +#: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 +msgid "" +"You need more points\n" +"to enter this challenge!\n" +"Check the minimap for\n" +"available challenges." +msgstr "Ti angen mwy o bwyntiau\ni gymryd rhan yn yr her!\nEdrycha ar y map bach\nam heriau sydd ar gael." + +#: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 +#, c-format +msgid "Accelerate with <%s>, and steer with <%s> and <%s>." +msgstr "Cyflyma gyda <%s>, a llywio gyda <%s> a <%s>." + +#: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 +msgid "" +"Accelerate by touching the upper part of the wheel, and steer by moving left" +" or right." +msgstr "Cyflyma trwy gyffwrdd â rhan uchaf yr olwyn, a llywio trwy symud i'r chwith neu'r dde." + +#: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 +msgid "" +"Accelerate by moving the accelerator upwards, and steer by tilting your " +"device." +msgstr "Cyflyma trwy symud y cyflymydd i fyny, a llywio trwy droi dy dyfais." + +#: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 +msgid "" +"Accelerate by moving the accelerator upwards, and steer by rotating your " +"device." +msgstr "Cyflyma trwy symud y cyflymydd i fyny, a llywio trwy droi dy ddyfais." + +#: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 +#, c-format +msgid "" +"Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" +msgstr "Casgla focsys anrhegion, a thanio'r arf gyda <%s> i chwythu'r blychau hyn i ffwrdd!" + +#: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 +msgid "" +"Collect gift boxes, and fire by pressing the bowling icon to blow away these" +" boxes!" +msgstr "Casgla flychau anrhegion, a thanio trwy bwyso'r eicon bowlio i chwythu'r blychau hyn i ffwrdd!" + +#: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 +#, c-format +msgid "" +"Press <%s> to look behind.\n" +"Fire the weapon with <%s> while pressing <%s> to fire behind!" +msgstr "Pwysa <%s> i edrych y tu ôl.\nTania'r arf gyda <%s> wrth bwyso <%s> i danio nôl!" + +#: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 +msgid "" +"Press the mirror icon to look behind.\n" +"Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" +msgstr "Pwysa'r eicon drych i edrych y tu ôl.\nTania'r arf y tu ôl trwy ddal yr eicon drych ac yna troi at yr eicon bowlio!" + +#: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 +#, c-format +msgid "Use the nitro you collected by pressing <%s>!" +msgstr "Defnyddia'r nitro ti wedi ei gasglu trwy bwyso <%s>!" + +#: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 +msgid "Use the nitro you collected by pressing the nitro icon" +msgstr "Defnyddia'r nitro ti wedi ei gasglu trwy wasgu'r eicon nitro" + +#: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 +msgid "Collect nitro bottles (we will use them after the curve)." +msgstr "Casgla boteli nitro (byddwn yn eu defnyddio ar ôl y tro)." + +#: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 +#, c-format +msgid "Oops! When you're in trouble, press <%s> to be rescued." +msgstr "Wps! Pan fyddi mewn trafferth, pwysa <%s> i gael dy achub." + +#: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 +msgid "Oops! When you're in trouble, press the bird icon to be rescued." +msgstr "Wps! Pan fyddi mewn trafferth, pwysa'r eicon adar i gael dy achub." + +#: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 +#, c-format +msgid "" +"Accelerate and press the <%s> key while turning to skid.\n" +"Skidding for a short while can help you turn faster to take sharp turns." +msgstr "Cyflyma a phwysa'r fysell <%s> wrth droi i sgid.\nGall sgidio am gyfnod byr dy helpu i droi'n gynt i gymryd tro'n sydyn." + +#: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 +msgid "" +"Accelerate and press the skid icon while turning to skid.\n" +"Skidding for a short while can help you turn faster to take sharp turns." +msgstr "Cyflyma a phwysa'r fysell sgid wrth droi i sgid.\nGall sgidio am gyfnod byr dy helpu i droi'n gynt i gymryd tro'n sydyn." + +#: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 +msgid "" +"Note that if you manage to skid for several seconds, you will receive a " +"bonus speedup as a reward!" +msgstr "Sylwa, os byddi'n llwyddo i sgidio am sawl eiliad, byddi'n derbyn bonws cyflymu sydyn fel gwobr!" + +#: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 +msgid "You are now ready to race. Good luck!" +msgstr "Rwyt ti nawr yn barod i rasio. Pob lwc!" + +#. I18N: Generic name in desktop file entry, summary in AppData and short +#. description in Google Play +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 +msgid "A 3D open-source kart racing game" +msgstr "Gêm rasio cart cod agored 3D" + +#. I18N: Keywords in desktop entry, translators please keep it separated with +#. semicolons +#: supertuxkart.desktop:11 +msgid "tux;game;race;" +msgstr "tux;gêm;rasio;" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 +msgid "" +"Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " +"variety of characters, tracks, and modes to play. Our aim is to create a " +"game that is more fun than realistic, and provide an enjoyable experience " +"for all ages." +msgstr "Cartiau. Nitro. Antur! Mae SuperTuxKart yn gêm rasio arcêd cod agored 3D gydag amrywiaeth o gymeriadau, traciau a moddau i'w chwarae. Ein nod yw creu gêm sy'n fwy o hwyl na realistig, ac yn cynnig profiad pleserus i bob oed." + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 +msgid "" +"We have several tracks with various themes for players to enjoy, from " +"driving underwater, rural farmlands, jungles or even in space! Try your best" +" while avoiding other karts as they may overtake you, but don't eat the " +"bananas! Watch for bowling balls, plungers, bubble gum, and cakes thrown by " +"your opponents." +msgstr "Mae gennym ni sawl trac gyda themâu amrywiol i chwaraewyr eu mwynhau, o yrru o dan y dŵr, tiroedd ffermydd gwledig, jyngl neu yn y gofod! Gwna dy orau wrth osgoi cartiau eraill oherwydd efallai y byddan nhw'n dy basio, ond paid â bwyta'r bananas! Gwylia am beli bowlio, plymwyr, gwm swigen, a chacennau wedi'u taflu gan dy wrthwynebwyr." + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 +msgid "" +"You can do a single race against other karts, compete in one of several " +"Grand Prix, try to beat the high score in time trials on your own, play " +"battle mode against the computer or your friends, and more! For a greater " +"challenge, join online and meet players from all over the world and prove " +"your racing skills!" +msgstr "Gelli wneud ras unigol yn erbyn cartiau eraill, cystadlu mewn un o nifer o Grand Prix, ceisio curo'r sgôr uchel mewn treialon amser ar dy ben dy hun, chwarae modd brwydr yn erbyn y cyfrifiadur neu dy ffrindiau, a mwy! Am her fwy, ymuna ar-lein a chwrdd â chwaraewyr o bob cwr o'r byd a phrofi dy sgiliau rasio!" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 +msgid "This game has no ads." +msgstr "Nid oes gan y gêm hon unrhyw hysbysebion." + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 +msgid "" +"This is an unstable version of SuperTuxKart that contains latest " +"improvements. It is released mainly for testing, to make stable STK as good " +"as possible." +msgstr "Mae hwn yn fersiwn ansefydlog o SuperTuxKart sy'n cynnwys y gwelliannau diweddaraf. Mae'n cael ei ryddhau'n bennaf ar gyfer profi, i wneud y STK sefydlog gorau posibl." + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 +msgid "" +"This version can be installed in parallel with the stable version on the " +"device." +msgstr "Mae modd gosod y fersiwn hon ochr yn ochr â'r fersiwn sefydlog ar y ddyfais." + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 +msgid "If you need more stability, consider using the stable version: %s" +msgstr "Os oes angen mwy o sefydlogrwydd arnat, ystyria ddefnyddio'r fersiwn sefydlog: %s" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 +msgid "SuperTuxKart Team" +msgstr "Tîm SuperTuxKart" diff --git a/data/po/da.po b/data/po/da.po index d555ccf6d1e..70e40023b6d 100644 --- a/data/po/da.po +++ b/data/po/da.po @@ -6,16 +6,16 @@ # Benau, 2018 # Benau, 2018 # Joe Hansen , 2009,2015 -# Lars Lyngby , 2019-2023 -# scootergrisen, 2015-2021 +# Lars Lyngby , 2019-2024 +# scootergrisen, 2015-2021,2025 # Søren Dyhr , 2015-2016 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Lars Lyngby , 2019-2023\n" +"Last-Translator: scootergrisen, 2015-2021,2025\n" "Language-Team: Danish (http://app.transifex.com/supertuxkart/supertuxkart/language/da/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -47,7 +47,7 @@ msgstr "Christoffel Columbus" #. I18N: ./data/achievements.xml msgid "Play every official track at least once." -msgstr "Spil alle de officielle baner mindst en gang." +msgstr "Spil alle de officielle baner mindst én gang." #. I18N: ./data/achievements.xml msgid "Strike!" @@ -83,17 +83,17 @@ msgstr "Drift 5 gange i samme omgang." #. I18N: ./data/achievements.xml msgid "Gold driver" -msgstr "Guldfører" +msgstr "Guldkører" #. I18N: ./data/achievements.xml msgid "" "Win against at least 3 AIs in normal race, time-trial, and follow the " "leader." -msgstr "Vind mod mindst 3 computerstyrede i normalt løb, tidskørsel og følg lederen." +msgstr "Vind mod mindst 3 computerstyrede i normalt løb, tidskørsel og følg den forreste." #. I18N: ./data/achievements.xml msgid "Powerup Love" -msgstr "Vild med powerup" +msgstr "Vild med powerups" #. I18N: ./data/achievements.xml msgid "Use 10 or more powerups in a race." @@ -115,7 +115,7 @@ msgstr "Bananelsker" #. I18N: ./data/achievements.xml msgid "Collect at least 5 bananas in one race." -msgstr "Kør ind i mindst 5 bananer i samme løb." +msgstr "Saml mindst 5 bananer i samme løb." #. I18N: ./data/achievements.xml msgid "It's secret" @@ -133,11 +133,11 @@ msgstr "Myggejæger" msgid "" "Take your opponents for mosquitos! With the swatter, squash them at least 5 " "times in a race." -msgstr "Behandl dine modstandere som myg! Smask dem mindst 5 gange med fluesmækkeren i et løb." +msgstr "Behandl dine modstandere som myg! Smask dem mindst 5 gange med fluesmækkeren i samme løb." #. I18N: ./data/achievements.xml msgid "Beyond Luck" -msgstr "Mere end heldig" +msgstr "Mere end blot heldig" #. I18N: ./data/achievements.xml msgid "" @@ -155,11 +155,11 @@ msgstr "Offroadkørsel" #. I18N: ./data/grandprix/3_tothemoonandback.grandprix msgid "To the Moon and Back" -msgstr "Til månen og tilbage" +msgstr "Til månen og hjem igen" #. I18N: ./data/grandprix/4_atworldsend.grandprix msgid "At World's End" -msgstr "Verdens ende" +msgstr "Ved verdens ende" #. I18N: ./data/gui/dialogs/addons_loading.stkgui #. I18N: Add-on screen action @@ -172,7 +172,7 @@ msgstr "Verdens ende" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Tilbage" @@ -194,7 +194,7 @@ msgstr "Vælg den type af styring du foretrækker" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Accelerometer" @@ -208,13 +208,13 @@ msgstr "Accelerometer" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Gyroskop" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Rat" @@ -245,35 +245,37 @@ msgstr "Indstillinger for berøringsenhed" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Generelt" @@ -281,7 +283,7 @@ msgstr "Generelt" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Device enabled" -msgstr "Inputenhed aktiveret" +msgstr "Enhed aktiveret" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -341,30 +343,33 @@ msgstr "Gendan standarder" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Annuller" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Ja" @@ -415,7 +420,7 @@ msgstr "Blød kamerabevægelse" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera settings msgid "Backward camera" -msgstr "Bagudkamera" +msgstr "Bagvendt kamera" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -434,7 +439,7 @@ msgstr "Grafikindstillinger" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Advanced pipeline (lights, etc.)" -msgstr "Avanceret pipeline (lys, osv.)" +msgstr "Avanceret pipeline (lys osv.)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -449,12 +454,12 @@ msgstr "Bloom" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Light shaft (God rays)" -msgstr "Lysstråler" +msgstr "Lysskakt" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Ambient occlusion" -msgstr "Ambient okklusion" +msgstr "Okklusion af omgivelser" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -464,7 +469,7 @@ msgstr "Skarphedsdybde" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Glow (Outlines)" -msgstr "Glød (omrids)" +msgstr "Glød (kantlinjer)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -542,9 +547,9 @@ msgstr "Deltag" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -605,7 +610,7 @@ msgstr "Mål" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Forløb" @@ -640,7 +645,7 @@ msgstr "Indsend" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Tilbage til løbet" @@ -657,9 +662,9 @@ msgstr "Tilbage til lobbyen" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" -msgstr "Kør løbet igen" +msgstr "Genstart løbet" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button @@ -704,7 +709,7 @@ msgstr "Opdater" #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog msgid "Account Recovery" -msgstr "Kontogenskabelse" +msgstr "Genskabelse af konto" #. I18N: ./data/gui/dialogs/online/recovery_info.stkgui #. I18N: In the recovery dialog @@ -717,16 +722,16 @@ msgstr "Du vil modtage en e-mail med instruktioner til at nulstille din adgangsk msgid "" "Fill in the username and email address you supplied at registration to be " "able to reset your password." -msgstr "Indtast brugernavnet og e-mailadressen, du oplyste ved registreringen, for at nulstille din adgangskode." +msgstr "Indtast det brugernavn og den e-mailadresse, du oplyste ved registreringen, for at nulstille din adgangskode." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Brugernavn" @@ -740,7 +745,7 @@ msgstr "E-mail" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog msgid "Terms and Agreement" -msgstr "Vilkår og aftale" +msgstr "Vilkår og accept" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog @@ -767,7 +772,7 @@ msgstr "Sværhedsgrad" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Nybegynder" @@ -779,7 +784,7 @@ msgstr "Nybegynder" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Øvet" @@ -791,7 +796,7 @@ msgstr "Øvet" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Ekspert" @@ -803,7 +808,7 @@ msgstr "Ekspert" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -811,8 +816,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Spiltilstand" @@ -823,8 +828,8 @@ msgstr "Spiltilstand" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Normalt løb" @@ -837,7 +842,7 @@ msgstr "Normalt løb" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Tidskørsel" @@ -845,7 +850,8 @@ msgstr "Tidskørsel" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Kamp" @@ -854,24 +860,24 @@ msgstr "Kamp" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Fodbold" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Adgangskode" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Bogmærk serveren" @@ -882,7 +888,7 @@ msgstr "Tilføj spiller" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Navn" @@ -976,6 +982,50 @@ msgstr "Indstil til ESC-tasten" msgid "Assign nothing" msgstr "Fjern tildelt tast" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Anbefalede skærmindstillinger" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "De anbefalede indstillinger vil gælde for den nuværende opløsning." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Hvad skal indstillingerne prioritere?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Ydelse" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Balancér ydelse og grafikkvalitet" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Grafikkvalitet" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Energibesparelse" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Kan du lide grafikeffekter, der skaber sløring?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Start testen" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -990,11 +1040,11 @@ msgstr "Opsætning af løb" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Fortsæt" @@ -1035,10 +1085,15 @@ msgstr "Arenaer" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Installeret" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Rediger favoritarenaer" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1048,20 +1103,20 @@ msgstr "Installeret" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Standard" @@ -1072,12 +1127,12 @@ msgstr "Standard" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Udvidelser" @@ -1091,27 +1146,28 @@ msgstr "Udvidelser" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Alle" @@ -1150,9 +1206,9 @@ msgstr "Flyt ned" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Tilføj" @@ -1177,7 +1233,7 @@ msgstr "Antal omgange:" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: In the edit track screen msgid "Reverse:" -msgstr "Modsat retning:" +msgstr "Modsatte retning:" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen @@ -1189,7 +1245,7 @@ msgstr "Valg af spøgelsesgengivelse" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Æggejagt" @@ -1231,15 +1287,15 @@ msgstr "Computerstyrede karts" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen msgid "Reverse" -msgstr "Modsat retning" +msgstr "Modsatte retning" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Maksimal tid (min.)" @@ -1257,7 +1313,7 @@ msgstr "Fortsæt et gemt grandprix" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Title in grand prix editor screen msgid "Grand Prix editor" -msgstr "Grandprix-redigeringsværktøj" +msgstr "Grandprix-redigering" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item @@ -1271,9 +1327,9 @@ msgstr "Kopiér" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1284,80 +1340,80 @@ msgstr "Omdøb" msgid "Save Grand Prix" msgstr "Gem grandprix" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Hjælp til SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Spiltilstande" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Powerups" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" -msgstr "Bananaer" +msgstr "Bananer" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1365,71 +1421,72 @@ msgstr "Bananaer" msgid "Story Mode" msgstr "Fortælletilstand" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Kartklasser" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Flere spillere" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" -msgstr "Start introduktionen" +msgstr "Start oplæringen" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Saml blå gaveæsker, de giver dig powerups." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" -msgstr "Undgå bananskræller!" +msgstr "Undgå bananer!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " "pressing the appropriate key or button. You can see your current level of " "nitro in the gauge at the bottom-right of the race screen." -msgstr "Indsamling af nitro giver dig mulighed for fartboosts, som du selv aktiverer ved at trykke på en passende tast eller knap. Du kan se din nitrobeholdning i måleren nederst til højre på løbsskærmen." +msgstr "Indsamling af nitro giver dig mulighed for fartboosts, som du selv aktiverer ved at trykke på den passende tast eller knap. Du kan se dit nuværende nitroniveau i måleren nederst til højre på løbsskærmen." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Hvis du ser en knap med en hængelås som denne, skal du gennemføre en udfordring for at låse den op." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1438,42 +1495,42 @@ msgid "" "carefully before!" msgstr "Du kan drifte ved at trykke på en speciel tast eller knap. Korte drift hjælper dig med at tage skarpe sving, mens medium drift booster din fart. Lange drift booster farten mere. Du kan ikke stoppe med at dreje, mens du drifter, så peg først din kart den rigtige vej!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Du kan få et startboost ved at trykke på accelerér-knappen ved 'Parat!', inden løbet begynder." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" -msgstr "* Nuværende tastebindinger kan ses/ændres i indstillingsmenuen" +msgstr "* De nuværende tastebindinger kan ses/ændres i indstillingsmenuen" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart har flere spiltilstande:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" -msgstr "Normalt løb: Alt er tilladt. Så saml powerups og brug dem klogt!" +msgstr "Normalt løb: Alt er tilladt, så saml powerups og brug dem klogt!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" -msgstr "Tidskørsel: Indeholder ingen powerups. Så kun dine køreegenskaber tæller!" +msgstr "Tidskørsel: Har ingen powerups, så det er kun dine kørefærdigheder, der har betydning!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " "disqualified every time the counter hits zero. Beware: going in front of the" " leader will get you eliminated too!" -msgstr "Følg lederen: kør efter andenpladsen da den sidste kart bliver diskvalificeret, hver gang tælleren når nul. Pas på: Du bliver også elimineret, hvis du kører foran lederen!" +msgstr "Følg den forreste: kør efter andenpladsen da den sidste kart bliver diskvalificeret, hver gang tælleren når nul. Pas på: Du bliver også elimineret, hvis du kører foran den forreste!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1483,125 +1540,125 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Der er 3 typer kamptilstande: I 3-slags-kamp skal du ramme andre med våben indtil de mister alle deres liv. I alle mod alle vinder spilleren som rammer andre flest gange indenfor en given ram- eller tidsgrænse. I fang flaget skal dit hold bringe det andet holds flag til basen af dit eget flag, så længe dit flag ikke er fanget af det andet hold." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Fodbold: Brug din kart til at skubbe bolden i mål." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Æggejagt: Udforsk baner for at finde alle de gemte æg." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Spøgelsesgengivelse: Kør mod spøgelsesgengivelser i tidskørsel eller æggejagt-tilstand, og optag dine egne!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Omgangskørsel: Fuldfør så mange omgange som muligt indenfor et givent tidsrum." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " "instead of playing a single race, you play many in a row. The better you " "rank, the more points you get. In the end, the player with the most points " "wins the cup." -msgstr "* Mange af spiltilstandene kan også spilles som grandprix: I stedet for at spille et enkelt løb, spiller du mange i træk. Jo bedre rangering du får, des flere point modtager du. Til slut vinder spilleren med de fleste point pokalen." +msgstr "* Mange af spiltilstandene kan også spilles som grandprix: I stedet for at spille et enkeltløb, spiller du mange i træk. Jo bedre rangering du får, des flere point modtager du. Til slut vinder spilleren med de fleste point pokalen." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Du kan samle powerups for at hjælpe dig med at vinde:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Tyggegummi - beskyt dig selv med et skjold, eller efterlad en klistrende klat bag dig, hvis du bruger den, når du kigger bagud." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" -msgstr "Zipper - giver dig et kraftigt fartboost. Men pas på du ikke mister kontrollen over din kart!" +msgstr "Fartpil - giver dig et kraftigt fartboost. Men pas på du ikke mister kontrollen over din kart!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Kage - flyver automatisk mod nærmeste fjende. Bedst til korte distancer eller lige veje. Det påvirker også andre karts tæt på eksplosionen." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Svupper - kast fremad for at trække an modstander tilbage, eller kast den bagud så en modspiller mister synet." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Bowlingkugle - går ligeud indtil den rammer. Den kan hoppe tilbage fra vægge. Hvis du kigger tilbage, vil den blive kastet bagud." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Faldskærm - bremser alle karts foran dig." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Bytter - gaveæsker bliver kortvarigt lavet om til bananer, nitroflasker til tyggegummi og omvendt." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." -msgstr "Basketball - hopper efter den førende spiller og smasker måske andre karts undervejs, så de kører langsommere." +msgstr "Basketball - hopper efter den forreste kart og smasker måske andre karts undervejs, så de kører langsommere." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Fluesmækker - smasker karts i nærheden, så de kører langsommere. Kan også bruges til at fjerne faldskærme og bomber." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Rammes en banan, kan det medføre, at en af følgende vedhæftes karten:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Anker - bremser karten pludseligt." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Faldskærm - bremser karten mere gradvist end ankeret. Jo hurtigere du kører, des kraftigere bremser den dig." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bombe - detonerer efter kort tid og kaster karten op i luften. Kør ind i en anden kart for at overføre bomben til en anden spiller." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Den onde Nolok har fanget Gnu! Her er nogle tips til at hjælpe dig:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1610,7 +1667,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Dette ikon på minikortet viser tilgængelige udfordringer, som du ikke har gennemført. Øverst til højre på skærmen vises også, hvor mange point du har. Gennemfør så mange udfordringer som muligt. Så vil Nolok acceptere at køre mod dig. Vind for at befri Gnu!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1618,20 +1675,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Når du gennemfører en udfordring, får du en pokal. Hver pokal er flere point værd. Jo højere sværhedsgrad du gennemførte udfordringen i, des bedre vil pokalen være, og des flere point er den værd." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Når du når det antal point, der er vist under ikonet, får du en overraskelse. Du kan samle mange overraskelser." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Ikke alle karts kører på samme måde! De tilhører klasser med flere forskelle:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1639,7 +1696,7 @@ msgid "" " resistant to explosions." msgstr "Vægt - der er tre klasser karts, afhængig af deres vægt: lette, medium og tunge. Tungere karts påvirkes mindre af faldskærme og modstår bedre eksplosioner." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1647,7 +1704,7 @@ msgid "" " especially at low speeds." msgstr "Acceleration - særlig nyttig ved start, efter et uheld eller på baner med mange skarpe sving. Jo lettere karten er, des hurtigere accelererer den. Specielt ved lave hastigheder." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1655,14 +1712,14 @@ msgid "" " top speed." msgstr "Topfart - jo højere den er, des hurtigere er karten. Særlig nyttig på baner med lige veje og lette sving. Tunge karts har højere topfart." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Nitroeffektivitet - Jo højere den er, des mere fart kan du få fra en nitroflaske. En let kart har højere nitroeffektivitet." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1670,12 +1727,12 @@ msgid "" "easier it is." msgstr "Hvis du følger en anden kart tæt på i nogle få sekunder, så får du en fartbonus i slipstrømmen, når du overhaler den. Jo lettere din kart er, des nemmere er det." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart kan spilles online i flere spillere-tilstand ...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1685,7 +1742,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Vælg først 'online'-ikonet i hovedmenuen. Vælg enten lokale netværk eller globale netværk (kræver at internet er aktiveret i indstillingerne). Herefter kan du enten oprette din egen server med tilpassede indstillinger eller søge i en liste over eksisterende servere, som du kan deltage i. Nogle af dem er anbefalede servere med mulighed for rangeret løb." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1695,12 +1752,12 @@ msgid "" "players and the server." msgstr "Når du er på en server, starter løbet, når ejeren (vist med kronen) vælger det. Officielle servere kan starte løb automatisk, når der er nok spillere. Herefter kan du vælge din kart og stemme på den bane, der skal køres på næste gang. En udvidelsesbane er kun tilladt, hvis den findes hos alle deltagende spillere og på serveren." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... eller på den samme enhed:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1708,9 +1765,9 @@ msgid "" "keyboard(s), each player will need a different set of keys, and most " "keyboards are not appropriate for multiplayer because they don't support " "multiple simultaneous keypresses." -msgstr "Først har du brug for flere inputenheder. Brug inputkonfigurationsskærmen til at opsætte dem. Flere gamepads eller joysticks er at foretrække: På tastatur(er) skal hver spille have et sæt forskellige taster. De fleste tastaturer er ikke egnede til flere spillere, fordi samtidige tryk på flere taster ikke virker." +msgstr "Først har du brug for flere inputenheder. Brug inputkonfigurationsskærmen til at opsætte dem. Flere gamepads eller joysticks er at foretrække: På tastatur(er) skal hver spille have et sæt forskellige taster. De fleste tastaturer er ikke egnede til flere spillere, fordi det ikke virker når man trykker på flere taster på samme tid." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1718,7 +1775,7 @@ msgid "" "keyboard to join the game, and use their input device to select their kart. " "The game continues when everyone selected their kart. Note that the mouse " "may not be used for this operation." -msgstr "Efter konfiguration af inputenheder vælg 'Skærmopdeling flere spillere'-ikonet i hovedmenuen. Spillere skal trykke på 'skyd'-knappen på deres gamepad eller tastatur og vælge kart med deres inputenhed for at deltage i løbet. Løbet går i gang, når alle deltagere har valgt kart. Bemærk at musen ikke kan bruges til det." +msgstr "Efter konfiguration af inputenheder vælg 'Flere spillere (skærmopdeling)'-ikonet i hovedmenuen. Spillere skal trykke på 'skyd'-knappen på deres gamepad eller tastatur og vælge kart med deres inputenhed for at deltage i løbet. Løbet går i gang, når alle deltagere har valgt kart. Bemærk at musen ikke kan bruges til det." #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen @@ -1730,7 +1787,7 @@ msgstr "Valg af topresultater" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Omgangskørsel" @@ -1738,9 +1795,9 @@ msgstr "Omgangskørsel" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Grandprix" @@ -1751,6 +1808,20 @@ msgstr "Grandprix" msgid "Choose a Kart" msgstr "Vælg kart" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Kartklasse" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Rediger favoritkarts" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1759,16 +1830,16 @@ msgstr "Enkeltspiller" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Splitscreen Multiplayer" -msgstr "Skærmopdeling flere spillere" +msgstr "Flere spillere\n(skærmopdeling)" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Online" @@ -1781,11 +1852,11 @@ msgstr "Udvidelser" #. I18N: In the main screen #: src/states_screens/race_gui_overworld.cpp:530 msgid "Tutorial" -msgstr "Introduktion" +msgstr "Oplæring" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Topresultater" @@ -1793,14 +1864,14 @@ msgstr "Topresultater" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Præstationer" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen msgid "Grand Prix Editor" -msgstr "Grandprix-redigeringsværktøj" +msgstr "Grandprix-redigering" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen @@ -1847,30 +1918,30 @@ msgstr "Find server" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Opret server" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Lobby" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Konfiguration" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Start løb" @@ -1896,9 +1967,9 @@ msgstr "Indtast serveradresse" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Din profil" @@ -1916,7 +1987,7 @@ msgstr "Spillerrangeringer" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Venner" @@ -1941,7 +2012,7 @@ msgstr "Hurtigspil" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Kontoindstillinger" @@ -1988,11 +2059,11 @@ msgstr "Lokale navn" #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog msgid "Online Username" -msgstr "Online-brugernavn" +msgstr "Online brugernavn" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Nulstil adgangskode" @@ -2002,10 +2073,10 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "Du kan spille uden en online konto ved at vælge offlinekonto. Men så kan du ikke forbinde dig til venner, stemme for udvidelser osv. Læs venligst vores privatlivserklæring på https://privacy.supertuxkart.net" +msgstr "Du kan spille uden at oprette en onlinekonto, ved at vælge en offlinekonto. Men så kan du ikke oprettte forbindelse til venner, stemme på udvidelser osv. Læs venligst vores privatlivserklæring på https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Valg af server" @@ -2023,343 +2094,413 @@ msgstr "Brug IPv6-forbindelse" msgid "User search" msgstr "Brugersøgning" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "SuperTuxKart-indstillinger" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Skærm" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Grafik" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Lyd" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Brugerflade" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Spillere" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Styring" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Sprog" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Musik" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Aktiveret" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Lydstyrke" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Lydeffekter" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Fjern konfiguration" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Deaktivér konfiguration" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Tilbage til enhedslisten" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Omdøb konfiguration" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Aktivér haptisk feedback (hvis det understøttes)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Opløsning" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Fuldskærm" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Husk vinduets placering" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Anvend ny opløsning" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Layout for flere spillere (skærmopdeling)" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Internetindstillinger" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Vis altid indlogningsskærm" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Opret forbindelse til internettet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Aktivér chat online" +msgid "Enable chatting in online lobbies" +msgstr "Aktivér chat i onlinelobbyer" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Aktivér chat i onlinespil" +msgid "Enable chatting in online matches" +msgstr "Aktivér chat i onlinedyster" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Diverse indstillinger" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Aktivér per-spiller handikap" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Afinstaller alle spilmaterialer" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Tryk på eller dobbeltklik på en enhed for at konfigurere den" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Tilføj en enhed" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." -msgstr "* Konfigurationen bestemmes ud fra den 'Vælg'-tast, der bliver trykket på, for at deltage i løbet." +msgstr "* Hvilken konfiguration som anvendes bestemmes ud fra den 'Vælg'-tast, der bliver trykket på, når der deltages i et spil." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Tema" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Minikort" +msgid "Skin variant" +msgstr "Temavariant" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Layout for skærmopdeling flere spillere" +msgid "Minimap" +msgstr "Minikort" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Skriftstørrelse" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Kamera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." -msgstr "Tilpas ..." +msgstr "Tilpassede ..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Vis FPS" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Vis hvilke powerups de andre karts har" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" -msgstr "Aktivér timeren i fortælling" +msgstr "Aktivér timeren til fortælletilstand" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" -msgstr "Aktivér timeren i speedrun" +msgstr "Aktivér timeren til speedrun" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Gengivelsesopløsning" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Niveau for grafikeffekter" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Niveau for sløringseffekter" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Maksimal FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Tilpassede indstillinger ..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Opløsning" +msgid "Performance tests" +msgstr "Ydelsestester" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Fuldskærm" +msgid "Performance test of the current settings" +msgstr "Ydelsestest med de nuværende indstillinger" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Husk vinduets placering" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Husk adgangskode" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Anvend ny opløsning" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Slet" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Kartfarve" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" -msgstr "Vælg sværhedsgrad" +msgstr "Vælg en sværhedsgrad" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a game mode" @@ -2382,15 +2523,15 @@ msgstr "Blåt hold" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Antal omgange" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Antal computerstyrede karts" @@ -2405,32 +2546,16 @@ msgstr "Antal computerstyrede karts på blåt hold" msgid "Random Grand Prix" msgstr "Tilfældigt grandprix" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Rediger favoritbaner" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" -msgstr "Login" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Husk adgangskode" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Slet" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Kartfarve" +msgstr "Log ind" #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." @@ -2442,7 +2567,7 @@ msgstr "Du kan se hvilke powerups de andre karts har ved at aktivere det i bruge #. I18N: ./data/tips.xml msgid "The font size can be changed in the UI options." -msgstr "Skrifttypens størrelse kan ændres i brugerfladeindstillingerne." +msgstr "Tekstens størrelse kan ændres i brugerfladeindstillingerne." #. I18N: ./data/tips.xml msgid "The help menu has lots of useful information." @@ -2450,7 +2575,7 @@ msgstr "Hjælpemenuen har massere af nyttige informationer." #. I18N: ./data/tips.xml msgid "In single-player, you can watch and challenge recorded time-trials." -msgstr "I enkeltspiller kan du se og udfordre optagede tidskørsler." +msgstr "I enkeltspiller kan du se og køre mod optagede tidskørsler." #. I18N: ./data/tips.xml msgid "" @@ -2463,13 +2588,13 @@ msgstr "Korte nitroboosts er mere effektive." #. I18N: ./data/tips.xml msgid "Only use zippers when it is safe. Long straight lines are ideal." -msgstr "Brug kun zippere når det er sikkert. Lange lige linjer er ideelt." +msgstr "Brug kun fartpile når det er sikkert. Lange lige strækninger er at foretrække." #. I18N: ./data/tips.xml msgid "" "Don't use multiple zippers quickly in row, instead, wait until the speed " "boost wears off." -msgstr "Brug ikke flere zippere hurtigt i træk. Vent i stedet til hastighedsboostet fortaber sig." +msgstr "Brug ikke mere end én fartpil af gangen. Vent til hastighedsboostet fortaber sig." #. I18N: ./data/tips.xml msgid "Skidding makes you much faster, do it whenever safe." @@ -2483,7 +2608,7 @@ msgstr "Fluesmækkeren kan bruges til at fjerne bomber og faldskærme." msgid "" "You can't stop turning while skidding. Good kart orientation at the skid's " "start is paramount." -msgstr "Du kan ikke stoppe med at dreje, mens du drifter. God placering ved begyndelsen af drift er altafgørende." +msgstr "Du kan ikke stoppe med at dreje, mens du drifter. Det er altafgørende at dreje karten korrekt ved begyndelsen af drift." #. I18N: ./data/tips.xml msgid "You get a startup boost if you start accelerating during \"Set\"." @@ -2495,11 +2620,11 @@ msgstr "Du kan slippe af med faldskærme hurtigere ved at bremse." #. I18N: ./data/tips.xml msgid "First and foremost, focus on where your kart is going." -msgstr "Vær først og fremmest opmærksom på hvor din kart er på vej hen." +msgstr "Hav først og fremmest fokus på hvor din kart er på vej hen." #. I18N: ./data/tips.xml msgid "The rescue key (button) is very useful." -msgstr "Red-tasten (knap) er meget nyttig." +msgstr "Red-tasten (knappen) er meget nyttig." #. I18N: ./data/tips.xml msgid "Be careful when close to other karts, they may attack you!" @@ -2515,7 +2640,7 @@ msgstr "En basketball kan ødelægges med præcise skud bagud med en bowlingkugl msgid "" "Try to avoid crashing into the backs of other karts as this will slow you " "down." -msgstr "Prøv at undgå at smadre ind i ryggen på andre karts, da det vil sætte din hastighed ned, og du ikke får ekstrapoint ved at smadre dem." +msgstr "Prøv at undgå at køre ind i bagenden af de andre karts, da det nedsætter din hastighed." #. I18N: ./data/tips.xml msgid "You can use bowling balls to push and block the ball." @@ -2537,7 +2662,7 @@ msgstr "Godt skifte mellem positioner (angreb og forsvar) er essentielt." #. I18N: ./data/tips.xml msgid "Make sure to store at least 2 big cans worth of nitro." -msgstr "Sørg for at gemme nitro der svarer til mindst 2 store flasker." +msgstr "Sørg for at have mindst 2 store flasker nitro på lager." #. I18N: ./data/tips.xml msgid "Never use the three bowling balls all at the same time." @@ -2550,251 +2675,319 @@ msgid "" msgstr "Kom ikke i vejen for en holdkammerat som har bolden, men du kan prøve og ramme de modstandere som forsøger at stoppe den i at score." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Antediluviansk afgrund" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" -msgstr "Fremmede signal" +msgstr "Signal udefra" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Labyrinten i det antikke Colosseum" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Lysets by" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Kampøen" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Den sorte skov" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "X-grotten" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Kakaotemplet" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Kornmarksoverfart" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Magmafortet" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Gran Paradiso-øen" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" -msgstr "Faldhul" +msgstr "Ned i hullerne" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Frossen fodboldbane" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Hvad er der galt, små hippier? Er jeres store gnu-leder blevet væk?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Åh ja, se, han er nu i min borg, og vil blive serveret til middagsmad ..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Men jeg er en retfærdig skabning, så jeg vil slå en handel af med jer." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." -msgstr "Hvis I kan slå mig i racerløb, vil jeg befri den gamle knark." +msgstr "Hvis du kan vinde over mig i racerløb, så vil jeg befri den gamle knark." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" -msgstr " Men I patetiske små skvatmikler vil aldrig være i stand til at slå mig; Kong Kart!" +msgstr " Men I patetiske små skvatmikler vil aldrig være i stand til at vinde over mig; Kongen af kart!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Las Dunas-arenaen" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Las Dunas-fodboldstadion" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Rundt om fyrtårnet" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Den gamle mine" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oase" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Olivers matematiktime" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Græskarparken" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Ravnebros palæ" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Sanddyner" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Nessies sø" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Nordligt feriested" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Sneklædt bjergtop" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Fodboldbane" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Stadiet" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Enterprise" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Templet" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Vulkanøen" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Zenhaven" #: src/achievements/achievement.cpp:387 #, c-format msgid "Completed achievement \"%s\"." -msgstr "Gennemførte præstation \"%s\"." +msgstr "Gennemførte præstationen \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Kunne ikke oprette forbindelse til SuperTuxKart-udvidelsesserveren." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Fejl ved download af nyheder: \"%s\"." @@ -2817,22 +3010,22 @@ msgstr "Tidskørsel - nitroudfordring" #: src/challenges/challenge_data.cpp:314 msgid "Normal Race (single race)" -msgstr "Normalt løb (enkelt løb)" +msgstr "Normalt løb (enkeltløb)" #: src/challenges/challenge_data.cpp:316 msgid "Time-Trial (single race)" -msgstr "Tidskørsel (enkelt løb)" +msgstr "Tidskørsel (enkeltløb)" #: src/challenges/challenge_data.cpp:318 msgid "Follow the Leader (single race)" -msgstr "Følg lederen (enkelt løb)" +msgstr "Følg den forreste (enkeltløb)" #. I18N: In the Select challenge dialog, tell user this challenge has reversed #. laps #: src/challenges/challenge_data.cpp:324 #: src/states_screens/dialogs/select_challenge.cpp:78 msgid "Mode: Reverse" -msgstr "Tilstand: Modsat retning" +msgstr "Tilstand: Modsatte retning" #: src/challenges/challenge_data.cpp:601 #, c-format @@ -2860,14 +3053,14 @@ msgid "New kart '%s' now available" msgstr "Ny kart \"%s\" er nu tilgængelig" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" "Closing the game before the story mode's completion invalidates the timer.\n" "\n" "To use the speedrun mode, please use a new profile." -msgstr "Speedrun-tilstand er deaktiveret. Speedrun kan kun aktiveres, hvis løbet ikke er blevet lukket efter opstart af fortælletilstand.\n\nLukkes løbet inden fortællingen er afsluttet, bliver timeren uanvendelig.\n\nBrug venligst en ny profil til at komme i speedrun-tilstand." +msgstr "Speedrun-tilstand er deaktiveret. Den kan kun aktiveres, hvis spillet ikke er blevet lukket efter start af fortælletilstanden.\n\nHvis spillet lukkes inden fortælletilstanden er fuldført, så gøres timeren ugyldig.\n\nBrug venligst en ny profil, for at bruge speedrun-tilstanden." #. I18N: Name of first guest player (without number) #: src/config/player_manager.cpp:396 @@ -2892,32 +3085,32 @@ msgid "" "created." msgstr "Din konfigurationsfil var for gammel, så den blev slettet og en ny oprettet." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." -msgstr "Startede videooptagelse." +msgstr "Videooptagelse startet." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." -msgstr "Video gemt i \"%s\"." +msgstr "Videoen blev gemt i \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Kodningsforløb:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d ktris, ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Tip: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Indlæser" @@ -2939,19 +3132,18 @@ msgstr "Nitroeffektivitet" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (handikappet)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s er klar" @@ -3425,21 +3617,21 @@ msgid "Axis %d" msgstr "Akse %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Gamepadknap %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Museknap %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Museakse %d %s" @@ -3451,7 +3643,7 @@ msgstr "Konfigurer dine tastebindinger igen." #: src/input/device_manager.cpp:497 msgid "Your input config file is not compatible with this version of STK." -msgstr "Din input-konfigurationsfil er ikke kompatibel med denne STK-version." +msgstr "Din inputkonfigurationsfil er ikke kompatibel med denne STK-version." #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:159 @@ -3560,7 +3752,7 @@ msgstr "Ignorerer \"%s\". Du skulle have tilmeldt dig tidligere for at spille!" #: src/input/input_manager.cpp:903 msgid "Only the Game Master may act at this point!" -msgstr "Kun spilmesteren kan gøre noget nu!" +msgstr "Det er kun spilmesteren der kan gøre noget nu!" #: src/input/sdl_controller.cpp:253 #, c-format @@ -3601,7 +3793,7 @@ msgstr "Straftid!!" #: src/karts/controller/local_player_controller.cpp:332 msgid "Don't accelerate before 'Set!'" -msgstr "Accellerér ikke inden 'Parat!'" +msgstr "Accelerér ikke inden 'Parat!'" #: src/karts/controller/spare_tire_ai.cpp:150 msgid "You can have at most 3 lives!" @@ -3611,44 +3803,48 @@ msgstr "Du kan højst have 3 liv!" msgid "+1 life." msgstr "+1 liv." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Du var for langsom!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Du fuldførte løbet!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Du vandt løbet!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" -msgstr "Du gennemførte løbet på %d. pladsen!" +msgstr "Du fuldførte løbet på %d. pladsen!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s forlod spillet." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." " Would you like this feature to be enabled? (To change this setting at a " "later time, go to options, select tab 'General', and edit \"Connect to the " "Internet\")." -msgstr "SuperTuxKart kan åbne en forbindelse til en server for at downloade tilføjelser og give dig besked om opdateringer. Læs venligst vores privatlivspolitik på https://supertuxkart.net/Privacy. Skal funktionaliteten aktiveres? (gå til fanebladet 'Generelt' og rediger \"Opret forbindelse til internettet\" for at ændre det senere)." +msgstr "SuperTuxKart kan oprette forbindelse til en server for at downloade tilføjelser og give dig besked om opdateringer. Læs venligst vores privatlivspolitik på https://supertuxkart.net/Privacy. Skal funktionaliteten aktiveres? (gå til fanebladet 'Generelt' og rediger \"Opret forbindelse til internettet\" for at ændre det senere)." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Din skærmopløsning er for lav til STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Din driverversion er for gammel. Installer venligst de seneste videodrivere." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3656,38 +3852,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Din grafikkortdriver ser ud til at være meget gammel. Tjek venligst om der findes en opdatering. SuperTuxKart anbefaler en driver, som understøtter %s eller bedre. Spillet kan sandsynligvis køre - men med en dårligere grafiktilstand." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Serverforbindelsen fik timeout." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s har det røde flag!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Det røde flag er tilbage!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s har det blå flag!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Det blå flag er tilbage!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s fangede det blå flag!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s fangede det røde flag!" @@ -3697,30 +3893,30 @@ msgstr "%s fangede det røde flag!" msgid "Eggs: %d / %d" msgstr "Æg: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" -msgstr "Leder" +msgstr "Den forreste" #: src/modes/linear_world.cpp:418 msgid "Final lap!" msgstr "Sidste omgang!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "%i. omgang" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s af %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Ny hurtigste omgang" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "FORKERTE VEJ!" @@ -3734,210 +3930,210 @@ msgstr "%s scorede et mål!" msgid "Oops, %s made an own goal!" msgstr "Ups, %s lavede selvmål!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" -msgstr[0] "%i kart med reservedæk er blevet spawned!" +msgstr[0] "%i kart med reservedæk er dukket frem!" msgstr[1] "%i karts med reservedæk er dukket frem!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Du blev elimineret!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." -msgstr "\"%s\" er blevet elimineret." +msgstr "\"%s\" blev elimineret." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Serveren blev lukket." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Du blev sparket fra serveren." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Du blev sparket: Ping for høj." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." -msgstr "Dårlig netforbindelse registreret." +msgstr "Dårlig netværksforbindelse registreret." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s afbrød forbindelsen." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." -msgstr "Tryk på spillernavnet i listen for spillerhåndtering og rangeringsinformation." +msgstr "Tryk på et spillernavn i listen, for spillerhåndtering og rangeringsinformation." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Sværhedsgrad: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Maks. spillere: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Spiltilstand: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Tidsbegrænsning" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Målbegrænsning" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Fodboldsspiltype: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Grandprixforløb: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Alle spillere deltager på rødt eller blåt hold." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." -msgstr "Du er nu ejer af serveren." +msgstr "Nu er det dig der ejer serveren." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Forbindelse nægtet: Serveren er optaget." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Forbindelse nægtet: Du er udelukket fra serveren." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Forbindelse nægtet: Adgangskoden til serveren er forkert." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Forbindelse nægtet: Spildata er ikke kompatible." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Forbindelse nægtet: Serveren er fuld." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Forbindelse nægtet: Ugyldig spiller opretter forbindelse." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Kunne ikke starte netværksspillet." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Løbet er slut. Du kan ikke længere livedeltage eller se med." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Ingen tilbageværende plads i arenaen - livedeltag er deaktiveret." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." -msgstr "Kun 1 spiller tilbage. Vender tilbage til lobbyen." +msgstr "Der er kun 1 spiller tilbage. Vender tilbage til lobbyen." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Serverens ejer forlod spillet." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Du ser med i det næste spil." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s deltager på det røde hold." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s deltager på det blå hold." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s deltager i løbet." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " "camera position." -msgstr "Tryk på <%s> eller <%s> for at skifte den valgte spiller, <%s> eller <%s> for at skifte kameraets placering." +msgstr "Tryk på <%s> eller <%s> for at skifte den valgte spiller, <%s> eller <%s> for at skifte kameraets placering." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "%s blev rapporteret." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3960,7 +4156,7 @@ msgstr "Kunne ikke registrere portnummer for serveren %s." #: src/network/protocols/lobby_protocol.cpp:294 msgid "Network grand prix has been finished." -msgstr "Netgrandprix er afsluttet." +msgstr "Netværksgrandprix er fuldført." #: src/network/server_config.cpp:263 msgid "Time Trial (Grand Prix)" @@ -3968,38 +4164,38 @@ msgstr "Tidskørsel (grandprix)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Alle mod alle" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Fang flaget" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s er nu online." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s og %s er nu online." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s og %s er nu online." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4007,19 +4203,19 @@ msgstr[0] "%d ven er nu online." msgstr[1] "%d venner er nu online." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s er nu på serveren \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "Du har %d ny venneanmodning!" msgstr[1] "Du har %d nye venneanmodninger!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Du har en ny venneanmodning!" @@ -4048,112 +4244,109 @@ msgid "" msgstr "Filen over topresultater var for gammel.\nAlle topresultater er blevet slettet." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" -msgstr "Følg lederen" +msgstr "Følg den forreste" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "3-slags-kamp" #: src/replay/replay_recorder.cpp:358 msgid "Incomplete replay file will not be saved." -msgstr "Ufuldstændig gengivelsesfil vil ikke blive gemt." +msgstr "Ufuldstændig gengivelsesfil gemmes ikke." #: src/replay/replay_recorder.cpp:394 #, c-format msgid "Replay saved in \"%s\"." -msgstr "Gengivelse gemt i \"%s\"." +msgstr "Gengivelsen blev gemt i \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 uge" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 uger" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 måned" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 måneder" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 måneder" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 måneder" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 år" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 år" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Navn på udvidelse" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Opdateret" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Ikke installeret" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s af %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Vent venligst mens udvidelserne opdateres" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Beklager, der opstod en fejl i forsøget på at kontakte webstedet med udvidelser. Sørg for, at du har forbindelse til internettet, og at SuperTuxKart ikke blokeres af en firewall" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Favoritter" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" -msgstr "Låst: Gennemfør udfordringerne for at få adgang til flere!" +msgstr "Låst: Gennemfør åbne udfordringer for at få adgang til flere!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Tilfældig arena" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d utilgængelig arena i enkeltspiller." -msgstr[1] "%d utilgængelige arenaer i enkeltspiller." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" -msgstr "Launchpad Contributions:\nBenau, 2018\nJoe Hansen, 2009,2015\nLars Lyngby, 2019-2022\nscootergrisen, 2015-2021\nSøren Dyhr, 2015-2016\nLars Lyngby, 2019-2021\n1001sd\nAputsiaĸ Niels Janussen\nAuria\nJ\nMarcus Møller\nSTK-team\nLars Lyngby\nscootergrisen" +msgstr "Launchpad Contributions:\nBenau, 2018\nJoe Hansen, 2009,2015\nLars Lyngby, 2019-2022\nSøren Dyhr, 2015-2016\nLars Lyngby, 2019-2021\n1001sd\nAputsiaĸ Niels Janussen\nAuria\nJ\nMarcus Møller\nSTK-team\nLars Lyngby\nscootergrisen" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:65 msgctxt "achievement_info" @@ -4197,31 +4390,31 @@ msgstr "Vundne løb" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:172 msgid "Normal races won" -msgstr "Vundne normalt-løb" +msgstr "Vundne løb i normalt løb" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:174 msgid "Time-trial races won" -msgstr "Vundne tidskørsel-løb" +msgstr "Vundne løb i tidskørsel" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:176 msgid "Follow-the-Leader races won" -msgstr "Vundne følg lederen-løb" +msgstr "Vundne løb i følg den forreste" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:178 msgid "Consecutive won races" -msgstr "Fortløbende vundne løb" +msgstr "Vundne løb i træk" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:180 msgid "Consecutive won races in Expert or SuperTux" -msgstr "Fortløbende vundne løb i ekspert eller SuperTux" +msgstr "Vundne løb i træk, i ekspert eller SuperTux" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4299,13 +4492,13 @@ msgstr "Fuldførte tidskørsel-løb" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:206 msgid "Follow-the-Leader races started" -msgstr "Startede følg lederen-løb" +msgstr "Startede følg den forreste-løb" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:208 msgid "Follow-the-Leader races finished" -msgstr "Fuldførte følg lederen-løb" +msgstr "Fuldførte følg den forreste-løb" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4403,27 +4596,27 @@ msgstr " (1 løb)" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:238 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:240 msgid "Bowling ball hits" -msgstr "Bowlingkugleslag" +msgstr "Træf med bowlingkugle" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:242 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:244 msgid "Swatter hits" -msgstr "Fluesmækkerslag" +msgstr "Træf med fluesmækker" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:246 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:248 msgid "All hits" -msgstr "Alle slag" +msgstr "Alle træf" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:250 msgid "Hits against the same kart" -msgstr "Slag mod den samme kart" +msgstr "Træf mod den samme kart" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4438,7 +4631,7 @@ msgstr "Bananer indsamlet" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Drift" @@ -4482,7 +4675,7 @@ msgstr "Fuldførte løb" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:278 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:303 msgid "Reverse direction races finished" -msgstr "Fuldførte løb i modsat retning" +msgstr "Fuldførte løb i modsatte retning" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4541,99 +4734,103 @@ msgstr "Fuldførte æggejagt" msgid " (official tracks matching the goal)" msgstr " (officielle baner som passer til målet)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" "To add a keyboard config, you can use the button below, HOWEVER please note that most keyboards only support a limited amount of simultaneous keypresses and are thus inappropriate for multiplayer gameplay. (You can, however, connect multiple keyboards to this device. Remember that everyone still needs different keybindings in this case.)" -msgstr "Nye gamepads og joysticks vises automatisk i listen når du forbinder dem til enheden.\n\nFor at tilføje en tastaturkonfiguration kan du bruge knappen herunder, men vær opmærksom på at mange tastaturer kun understøtter et begrænset antal samtidige tastetryk. Derfor er de upraktiske til spil med flere spillere. (Du kan dog forbinde flere tastaturer til enheden. Husk blot at alle spillere her har brug for unikke genvejstaster)." +msgstr "Nye gamepads og joysticks vises automatisk i listen, når du tilslutter dem til enheden.\n\nDu kan bruge knappen nedenfor for at tilføje en ny tastaturkonfiguration, MEN bemærk venligst at de fleste tastaturer kun understøtter et begrænset antal tastetryk på samme tid og derfor ikke er egnet til spil med flere spillere. (Du kan dog tilslutte flere tastaturer til enheden. Husk blot at hver spiller skal bruge forskellige tastebindinger)." #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Tilføj wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Tilføj tastaturkonfiguration" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Opdatér" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Version: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" -msgstr "fremhævet" +msgstr "udvalgt" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Størrelse: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Du skal være logget ind, for at bedømme tilføjelsen." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" -msgstr "Beklager. Download af udvidelsen slog fejl." +msgstr "Beklager. Kunne ikke downloade udvidelsen" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Problemer under installationen af udvidelsen \"%s\"." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Prøv igen" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Problemer under afinstallation af udvidelsen \"%s\"." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Download i baggrunden er gennemført." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Download i baggrunden" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Download i baggrunden kører allerede." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Nuværende adgangskode er ugyldig." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Adgangskoden skal være mellem 8 og 30 tegn lang!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Adgangskoderne er ikke ens!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Validerer information" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Adgangskoden blev ændret." @@ -4654,67 +4851,97 @@ msgstr "Opløsninger mindre end 1024x768 eller 1280x720 understøttes ikke. Dele #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Droneforfølgelse" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" -msgstr "Tilpasset" +msgstr "Tilpassede" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Deaktiveret" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Kun vigtige" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Meget lav" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Lav" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Medium" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Høj" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Meget høj" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4722,7 +4949,7 @@ msgid "" msgstr "SuperTuxKart downloader alle spilmaterialer (herunder højkvalitets strukturer og musik) for en bedre spiloplevelse. Mobildataforbindelsen vil blive brugt, hvis du ikke har wifi-forbindelse." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4732,110 +4959,111 @@ msgstr "SuperTuxKart downloader alle spilmaterialer (højkvalitets strukturer og msgid "" "Enter the server address optionally followed by : and then port or select " "address from list." -msgstr "Indtast serveradressen valgfrit efterfulgt af : og portnummer eller vælg en adresse i listen." +msgstr "Indtast serveradressen, valgfrit efterfulgt af : og portnummer. Eller vælg en adresse i listen." #: src/states_screens/dialogs/enter_address_dialog.cpp:124 #, c-format msgid "Invalid server address: %s." msgstr "Ugyldig serveradresse: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" -msgstr "Modsat retning" +msgstr "Modsatte retning" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Sværhedsgrad" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Omgange" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Tid" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Kart" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Bruger" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Version" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Nej" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Bane" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" -msgstr "De %d bedste topresultater" +msgstr "Top %d topresultater" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Antal karts: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Tidsmål: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Omgange: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" -msgstr "Modsat retning: %s" +msgstr "Modsatte retning: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" -msgstr "(Tom)" +msgstr "(tom)" #. I18N: In kart color choosing dialog #: src/states_screens/dialogs/kart_color_slider_dialog.cpp:47 @@ -4921,33 +5149,41 @@ msgid "Press any key..." msgstr "Tryk på en tast ..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Chat er deaktiveret. Aktivér i indstillingsmenuen." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Tilbage til ydelsestesten" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Afslut ydelsestesten" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Tilbage til kampen" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" -msgstr "Opsætning af nyt spil" +msgstr "Nyt spil" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Genstart kampen" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" -msgstr "Forlad kampen" +msgstr "Afslut kampen" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Nyt løb" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Afslut løbet" @@ -4963,11 +5199,11 @@ msgstr "%s har endnu ingen rangering." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s er nummer %d i rangeringen med et resultat på %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." -msgstr "Brugernavn og/eller e-mailadresse er ugyldig." +msgstr "Brugernavnet og/eller e-mailadressen er ugyldig." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4989,7 +5225,7 @@ msgstr "Løb med spøgelsesgengivelse" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Omgange: %i" @@ -5002,24 +5238,24 @@ msgstr "Type: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" -msgstr "Krævet rang: %i" +msgstr "Nødvendige rang: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" -msgstr "Krævet tid: %i" +msgstr "Nødvendige tid: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" -msgstr "Krævet nitropoint: %i" +msgstr "Nødvendige nitropoint: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:109 @@ -5029,54 +5265,54 @@ msgstr "Antal computerstyrede karts: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Kamptilstand" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Fodboldsspiltype" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Serverplacering: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Nuværende bane: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Rang" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Spiller" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Resultater" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Spilletid" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Fjern fra bogmærker" @@ -5089,74 +5325,74 @@ msgid "No player available for connecting to server." msgstr "Ingen tilgængelige spillere som kan oprette forbindelse til serveren." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Brugernavn: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Annuller anmodning" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "I dag" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Venneanmodning afsendt!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Venneanmodning accepteret!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Venneanmodning afvist!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Ven fjernet!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Venneanmodning annulleret!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Arbejder" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Henter sidste stemme" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Du kan ændre din tidligere bedømmelse ved at klikke på stjernerne." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Du har endnu ikke stemt på udvidelsen. Vælg den ønskede bedømmelse ved at klikke på de nedenstående stjerner" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Afstemningen lykkedes! Du kan nu lukke vinduet." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Udfører stemme" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Tilfældig bane" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5173,7 +5409,7 @@ msgstr "Omgange" #: src/states_screens/edit_gp_screen.cpp:153 msgid "Reversed" -msgstr "Modsat retning" +msgstr "Modsatte retning" #. I18N: Indicate that the grand prix is modified and not saved #: src/states_screens/edit_gp_screen.cpp:290 @@ -5185,7 +5421,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Der opstod en fejl under forsøget på at gemme dit grandprix." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Vælg bane" @@ -5198,7 +5434,7 @@ msgstr "Du gennemførte den nemme udfordring! Point som blev indtjent på dette #, c-format msgid "" "You completed the intermediate challenge! Points earned on this level: %i/%i" -msgstr "Du gennemførte den middelsvære udfordring! Point som blev indtjent på dette niveau: %i/%i" +msgstr "Du gennemførte den øvet udfordring! Point som blev indtjent på dette niveau: %i/%i" #: src/states_screens/feature_unlocked.cpp:266 #, c-format @@ -5229,12 +5465,12 @@ msgstr "Du låste op for banen %0" msgid "You unlocked grand prix %0" msgstr "Du låste op for grandprixet %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Bane" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5249,25 +5485,25 @@ msgstr "Genindlæs" #: src/states_screens/grand_prix_editor_screen.cpp:100 #: src/states_screens/grand_prix_editor_screen.cpp:117 msgid "Please enter the name of the grand prix" -msgstr "Indtast navnet på grandprixet" +msgstr "Indtast venligst navnet på grandprixet" #: src/states_screens/grand_prix_editor_screen.cpp:168 msgid "Please select a Grand Prix" msgstr "Vælg venligst et grandprix" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" -msgstr "Brugerdefineret" +msgstr "Brugerdefinerede" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Navnet er tomt." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Der findes allerede et grandprix med samme navn." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Navnet er for langt." @@ -5276,19 +5512,19 @@ msgstr "Navnet er for langt." msgid "Better luck next time!" msgstr "Bedre held næste gang!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Du gennemførte en udfordring!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Du vandt grandprixet!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Du gennemførte grandprixet!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Antal karts" @@ -5301,110 +5537,125 @@ msgstr "Er du sikker på, du vil fjerne topresultatet?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Er du sikker på, du vil fjerne alle dine topresultater?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Favorit" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Lette" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Tunge" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" -msgstr "Forbind et tastatur eller gamepad for at spille skærmopdeling flere spillere" +msgstr "Forbind et tastatur eller gamepad for at spille flere spillere (skærmopdeling)" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Tilfældig kart" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Låst" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Alle:\nTryk på 'Vælg'-knappen for at deltage i løbet" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" -msgstr "Vil du spille introduktionen til spillet?" +msgstr "Vil du spille oplæringen til spillet?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Du kan ikke spille online uden internetadgang. Hvis du vil spille online så gå ind i indstillingsmenuen og tilvælg \"Opret forbindelse til internettet\"." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Du kan ikke downloade udvidelser uden internetadgang. Hvis du vil downloade udvidelser så gå ind i indstillingsmenuen og tilvælg \"Opret forbindelse til internettet\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." -msgstr "Du kan ikke downloade udvidelser uden internetadgang. Hvis du vil downloade udvidelser så gå ind i indstillingsmenuen og tilvælg \"Opret forbindelse til Internettet\".\n\nDu kan dog slette udvidelser, som allerede er downloadet." +msgstr "Du kan ikke downloade udvidelser uden internetadgang. Hvis du vil downloade udvidelser, så gå ind i indstillingsmenuen og tilvælg \"Opret forbindelse til Internettet\".\n\nDu kan dog slette udvidelser, som allerede er downloadet." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Udvidelsesmodulet er deaktiveret i indstillinger" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Vent venligst mens udvidelserne indlæses" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Er du sikker på, at du vil afslutte STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Opret LAN-server" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "%ss server" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Antal baner i grandprix" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Navnet skal være imellem 4 og 30 tegn langt!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Ugyldige tegn i adgangskode!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Klar" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Livedeltag" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Se med" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Installer tilføjelse" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5412,7 +5663,7 @@ msgstr "Vent venligst på at løbet (%s) slutter. Anslået tilbageværende tid: #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Vent venligst på at løbet slutter. Anslået tilbageværende tid: %s." @@ -5420,24 +5671,24 @@ msgstr "Vent venligst på at løbet slutter. Anslået tilbageværende tid: %s." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Vent venligst på at løbet (%s) slutter. Anslået forløb: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Vent venligst på at løbet slutter. Anslået forløb: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Vent venligst på at løbet slutter." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5446,7 +5697,7 @@ msgstr[1] "Spillet starter, hvis der er mere end %d spillere." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5455,96 +5706,108 @@ msgid_plural "" msgstr[0] "Starter om %d sekund, eller når alle har trykket på 'Klar'-knappen." msgstr[1] "Starter om %d sekunder, eller når alle har trykket på 'Klar'-knappen." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Opretter forbindelse til %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Finder en server med hurtigspil" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Tilbageværende tid: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Mål" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Henter præstationer" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "%ss profil" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Siden" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Status" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Henter venner" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Ny forespørgsel" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Afventer" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Offline" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Indtast ny e-mail herunder" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Ny e-mail skal være fra 5 til 254 tegn lang!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Ny e-mail er ugyldig!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "E-mail ændret!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Kunne ikke ændre e-mail: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Nyheder fra STK-bloggen" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Dato" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Der er ingen nyheder i øjeblikket." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Du skal være logget ind for at kunne spille på det globale netværk. Klik på dit brugernavn ovenfor." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Søger" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Afslut spillet" @@ -5556,11 +5819,11 @@ msgstr "Kunne ikke oprette spilleren \"%s\"." #: src/states_screens/online/register_screen.cpp:306 msgid "User name cannot be empty." -msgstr "Brugernavn må ikke være tomt." +msgstr "Brugernavnet må ikke være tomt." #: src/states_screens/online/register_screen.cpp:362 msgid "Online username and password must not be the same!" -msgstr "Online brugernavn og kodeord må ikke være ens!" +msgstr "Online brugernavnet og adgangskoden må ikke være ens!" #: src/states_screens/online/register_screen.cpp:366 msgid "Emails don't match!" @@ -5570,19 +5833,19 @@ msgstr "E-mailene er ikke ens!" msgid "" "Online username can only contain alphanumeric (ASCII) characters, periods, " "dashes and underscores!" -msgstr "Online brugernavn må kun indeholde bogstaver a-z (ASCII), punktummer, bindestreger og understregningstegn _!" +msgstr "Online brugernavnet må kun indeholde bogstaver a-z (ASCII), punktummer, bindestreger og understregningstegn _!" #: src/states_screens/online/register_screen.cpp:374 msgid "Online username has to be between 3 and 30 characters long!" -msgstr "Online-brugernavn skal være mellem 3 og 30 tegn langt!" +msgstr "Online brugernavnet skal være mellem 3 og 30 tegn lang!" #: src/states_screens/online/register_screen.cpp:378 msgid "Online username must not start with a number!" -msgstr "Online-brugernavn må ikke starte med et tal!" +msgstr "Online brugernavnet må ikke begynde med et tal!" #: src/states_screens/online/register_screen.cpp:386 msgid "Email has to be between 5 and 254 characters long!" -msgstr "E-mail skal være mellem 5 og 254 tegn lang!" +msgstr "E-mailen skal være mellem 5 og 254 tegn lang!" #: src/states_screens/online/register_screen.cpp:392 msgid "Email is invalid!" @@ -5622,184 +5885,184 @@ msgid "Distance (km)" msgstr "Afstand (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Ukendt" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Ingen IPv4 registreret — du vil måske ikke være i stand til at deltage på nogen servere." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Ingen IPv6 registreret — du vil måske ikke være i stand til at deltage på nogen servere." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Ingen tilgængelige servere." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Henter servere" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Serverbogmærker" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." -msgstr "Hvis en stor del af spillerne vælger samme bane og løbsindstillinger, så afsluttes afstemningen tidligt." +msgstr "Hvis mange af spillerne vælger samme bane og løbsindstillinger, så slutter afstemningen tidligt." #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Tilfældig placering af ting" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Antal mål for at vinde" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" -msgstr "Kør i modsat retning" +msgstr "Kør i modsatte retning" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" -msgstr "Låst: Gennemfør udfordringerne for at få adgang til flere!" +msgstr "Låst: Gennemfør åbne udfordringer for at få adgang til flere!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Handling" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Tastebinding" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Deaktivér enhed" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Aktivér enhed" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Aktivér konfiguration" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Spiltaster" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Menutaster" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Drej til venstre" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Drej til højre" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Accelerér" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Brems/baglæns" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Skyd" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Kig tilbage" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Red" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Pause" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Op" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Ned" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Venstre" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Højre" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Vælg" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Annuller/tilbage" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" -msgstr "* Et blåt element viser en konflikt med en anden konfiguration" +msgstr "* Et blåt punkt viser en konflikt med en anden konfiguration" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" -msgstr "* Et rødt element viser en konflikt i den nuværende konfiguration" +msgstr "* Et rødt punkt viser en konflikt i den nuværende konfiguration" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5807,238 +6070,238 @@ msgid "" msgstr "Advarsel: Tasten \"Skift\" anbefales ikke. Når \"Skift\" holdes nede, vil taster med bogstaver der ændres til et stort bogstav holde op med at virke." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Er du sikker på, at du vil slette konfigurationen permanent?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Indtast nyt konfigurationsnavn, lad den være tomt for at vende tilbage til standardværdien." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Lodret" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Vandret" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" -msgstr "I flere spillere-tilstand kan spillere vælge profiler med handikap (sværere) på skærmen hvor der vælges kart" +msgstr "I flere spillere-tilstand kan spillere vælge profiler\nmed handikap (sværere) på skærmen hvor der vælges kart" #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Installer alle spilmaterialer" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Er du sikker på, at du vil afinstallere alle spilmaterialer?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Tastatur %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Berøringsenhed" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Tryk på en enhed for at konfigurere den" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Systemets sprog" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Nederst til venstre" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "I højre side" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Skjult" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Centreret" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Lodret" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Vandret" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Meget lille" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Lille" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Medium" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Stor" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Meget stor" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" "Closing the game before the story mode's completion invalidates the timer.\n" "\n" "To use the speedrun mode, please use a new profile." -msgstr "Speedrun-tilstand kan kun aktiveres, hvis løbet ikke er blevet lukket efter opstart af fortælletilstand.\n\nLukkes løbet inden fortællingen er afsluttet, bliver timeren uanvendelig.\n\nBrug venligst en ny profil til at komme i speedrun-tilstanden." +msgstr "Speedrun-tilstand kan kun aktiveres, hvis spillet ikke er blevet lukket efter start af fortælletilstanden.\n\nHvis spillet lukkes inden fortælletilstanden er fuldført, så gøres timeren ugyldig.\n\nBrug venligst en ny profil, for at bruge speedrun-tilstanden." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Lodret synk." #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." -msgstr "Vsync tvinger grafikkortet til kun at vise et nyt billede\nnår skærmen er klar til at vise det." +msgstr "Lodret synkronisering tvinger grafikkortet til kun at leverer et nyt billede\nnår skærmen er klar til at vise det." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." -msgstr "Vsync virker kun hvis dine drivere understøtter det." +msgstr "Lodret synkronisering virker kun hvis dine drivere understøtter det." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Partikeleffekter: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Animerede karakterer: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Dynamiske lys: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Lysspredning: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Antialias: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" -msgstr "Ambient okklusion: %s" +msgstr "Okklusion af omgivelser: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Skygger: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Skygger: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Bloom: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" -msgstr "Glød (omrids): %s" +msgstr "Glød (kantlinjer): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" -msgstr "Tusmørkestråler: %s" +msgstr "Lysskakt: %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Gengivet billedkvalitet: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Geometridetaljer: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Bevægelsessløring: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Skarphedsdybde: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Internetadgang er deaktiveret. Vil du aktivere den?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Du skal indtaste en adgangskode." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Logger ud som \"%s\"" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Logger ind som \"%s\"" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Du kan ikke slette den eneste spiller." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Vil du virkelig slette spilleren '%s'?" @@ -6066,7 +6329,7 @@ msgstr "MÅL!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Venter på de andre" @@ -6093,7 +6356,7 @@ msgstr "Saml nitro!" #: src/states_screens/race_gui_base.cpp:771 msgid "Follow the leader!" -msgstr "Følg lederen!" +msgstr "Følg den forreste!" #. I18N: When some GlobalPlayerIcons are hidden, write "Top 10" to show it #: src/states_screens/race_gui_base.cpp:954 @@ -6101,19 +6364,19 @@ msgstr "Følg lederen!" msgid "Top %i" msgstr "Top %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" -msgstr "Udfordring mislykket" +msgstr "Udfordringen mislykkedes" #. I18N: Shown when multitouch GUI exists #. and press the podium (2, 1, 3 like) icon instead of fire button #: src/states_screens/race_gui_overworld.cpp:541 msgid "Press podium icon to start tutorial" -msgstr "Tryk på podiumikonet for at starte introduktionen" +msgstr "Tryk på podiumikonet for at starte oplæringen" #: src/states_screens/race_gui_overworld.cpp:547 msgid "Press fire to start the tutorial" -msgstr "Tryk på skyd for at starte introduktionen" +msgstr "Tryk på skyd for at starte oplæringen" #. I18N: Shown when multitouch GUI exists #. and press the podium (2, 1, 3 like) icon instead of fire button @@ -6125,114 +6388,211 @@ msgstr "Tryk på podiumikonet for at starte udfordringen" msgid "Press fire to start the challenge" msgstr "Tryk på skyd for at starte udfordringen" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Tilbage til skærmindstillinger" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Gem testresultaterne" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Tilbage til hovedmenuen" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Forlad serveren" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Afbryd grandprix" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" -msgstr "Kør igen" +msgstr "Genstart" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" -msgstr "Valg af tilbage til udfordringer" +msgstr "Tilbage til valg af udfordringer" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Kør mod den nye spøgelsesgengivelse" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Tilbage til menuen" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Vil du virkelig afbryde grandprixet?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Ydelsesrapporten blev gemt i \"%s\"." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" -msgstr "Rødt hold vinder" +msgstr "Rødt hold vandt" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" -msgstr "Blåt hold vinder" +msgstr "Blåt hold vandt" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Uafgjort" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Elimineret efter %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Elemineret" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" -msgstr "(eget mål)" +msgstr "(selvmål)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Bane %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Grandprixforløb:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Topresultater" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Bedste omgangstid: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "af %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Du gennemførte udfordringen!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Udfordringen mislykkedes for dig!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" -msgstr "Opnåede forudsætninger for at køre SuperTux" +msgstr "Opnåede de nødvendige krav til SuperTux" + +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Resultater for ydelsestest" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Varighed af test: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Antal billeder: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "Stabil FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "For det meste stabil FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "Typisk FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Vandret opløsning: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Lodret opløsning: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Dynamisk belysning: AKTIVERET" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Dynamisk belysning: DEAKTIVERET" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Gengivelsesopløsning: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Antialiasing: AKTIVERET" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Antialiasing : DEAKTIVERET" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Billedbaseret belysning: DEAKTIVERET" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Billedbaseret belysning: AKTIVERET" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Okklusion af omgivelser: AKTIVERET" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Okklusion af omgivelser: DEAKTIVERET" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Opløsning for skygger: %s" #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" -msgstr "Alt er tilladt så grib nogle våben og brug dem klogt!" +msgstr "Alt er tilladt, så saml våben og brug dem klogt!" #: src/states_screens/race_setup_screen.cpp:96 msgid "Contains no powerups, so only your driving skills matter!" -msgstr "Ingen powerups. Så det er kun dine kørefærdigheder, der har betydning!" +msgstr "Har ingen powerups, så det er kun dine kørefærdigheder, der har betydning!" #. I18N: short definition for follow-the-leader game mode #: src/states_screens/race_setup_screen.cpp:109 msgid "Keep up with the leader kart but don't overtake it!" -msgstr "Følg med den førende kart men undlad at overhale den!" +msgstr "Følg med den forreste kart, men lad være med at overhale den!" #: src/states_screens/race_setup_screen.cpp:115 msgid "Hit others with weapons until they lose all their lives." @@ -6240,7 +6600,7 @@ msgstr "Ram andre med våben indtil de mister alle deres liv." #: src/states_screens/race_setup_screen.cpp:120 msgid "Push the ball into the opposite cage to score goals." -msgstr "Skub bolden ind i modsatte bur for at score mål." +msgstr "Skub bolden i det modsatte mål for at score." #: src/states_screens/race_setup_screen.cpp:130 msgid "Explore tracks to find all hidden eggs" @@ -6248,11 +6608,11 @@ msgstr "Udforsk baner for at finde alle de gemte æg" #: src/states_screens/race_setup_screen.cpp:138 msgid "Race against ghost karts and try to beat them!" -msgstr "Kør mod spøgelseskarts og prøv at slå dem!" +msgstr "Kør mod spøgelseskarts og prøv at vinde over dem!" #: src/states_screens/race_setup_screen.cpp:143 msgid "Complete as many laps as possible in a given amount of time." -msgstr "Fuldfør så mange omgange som muligt i et givet tidsrum." +msgstr "Fuldfør så mange omgange som muligt indenfor et givent tidsrum." #. I18N: In soccer setup screen #: src/states_screens/soccer_setup_screen.cpp:120 @@ -6261,28 +6621,28 @@ msgstr "Tryk på det røde eller blå fodboldsikon for at skifte hold" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" -msgstr "Banen er fremstillet af %s" +msgstr "Banen er lavet af %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Maks. spillere understøttet: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Antal computerstyrede karts på rødt hold" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Du kan ikke deltage i grandprixet, fordi det indeholder baner, som ikke er låst op!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Låst!" @@ -6304,10 +6664,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Gennemfør alle udfordringer for at låse den store port op!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6316,41 +6678,48 @@ msgid "" msgstr "Du skal have flere point \nfor at spille udfordringen!\nSe tilgængelige udfordringer \npå minikortet." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Accelerér med <%s> og drej med <%s> og <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." -msgstr "Accelerér ved at røre øverste del af rattet og styr ved at flytte til venstre eller højre." +msgstr "Accelerér ved at røre den øverste del af rattet og drej ved at flytte det til venstre eller højre." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." -msgstr "Accelerér ved at flytte acceleratoren opad og styr ved at vippe din enhed." +msgstr "Accelerér ved at flytte acceleratoren opad og drej ved at vippe din enhed." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." -msgstr "Accelerér ved at flytte acceleratoren opad og styr ved at rotere din enhed." +msgstr "Accelerér ved at flytte acceleratoren opad og drej ved at rotere din enhed." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Saml gaveæsker og affyr våbnet med <%s> så kasserne skydes væk!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Saml gaveæsker og affyr ved at trykke på bowling-ikonet så kasserne skydes væk!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6358,34 +6727,41 @@ msgid "" msgstr "Tryk på <%s> for at kigge bagud.\nAffyr våbnet med <%s> mens der trykkes på <%s> for at skyde bagud!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Tryk på spejl-ikonet for at se bagud.\nAffyr våbnet bagud ved at holde på spejl-ikonet og stryge mod bowling-ikonet!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Brug den indsamlet nitro ved at trykke på <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Brug den indsamlet nitro ved at trykke på nitro-ikonet" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Saml nitroflasker (vi bruger dem efter svinget)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." -msgstr "Ups! Når du er i problemer, kan du trykke på <%s> for at blive reddet." +msgstr "Ups! Når du er i knibe, kan du trykke på <%s> for at blive reddet." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." -msgstr "Ups! Når du er i problemer, kan du trykke på fugl-ikonet for at blive reddet." +msgstr "Ups! Når du er i knibe, kan du trykke på fugl-ikonet for at blive reddet." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6393,26 +6769,29 @@ msgid "" msgstr "Accelerér og tryk på <%s>-tasten mens du drejer for at drifte.\nDrifting i kort tid kan hjælpe dig med at dreje hurtigere i skarpe sving." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Accelerér og tryk på drift-ikonet mens du drejer for at drifte.\nDrifting i kort tid kan hjælpe dig med at dreje hurtigere i skarpe sving." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" -msgstr "Hvis du kan drifte i flere sekunder, så får du en fartbonus som belønning!" +msgstr "Bemærk at du får en fartbonus som belønning, hvis du formår at drifte i nogle sekunder!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" -msgstr "Du er nu klar til at køre løb. Held og lykke!" +msgstr "Nu er du klar til at køre løb. Held og lykke!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" -msgstr "Et 3D-kartracerspil i open source" +msgstr "Et open source 3D-racerspil med karts" #. I18N: Keywords in desktop entry, translators please keep it separated with #. semicolons @@ -6420,7 +6799,7 @@ msgstr "Et 3D-kartracerspil i open source" msgid "tux;game;race;" msgstr "tux;spil;racerløb;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6428,7 +6807,7 @@ msgid "" "for all ages." msgstr "Karts. nitro. action! SuperTuxKart er en 3D-arkaderacer i open source med et udvalg af karakterer, spor og tilstande som kan spilles. Vores mål er at skabe et spil som er mere sjovt end det er realistisk og give alle aldersgrupper en god oplevelse." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6437,36 +6816,36 @@ msgid "" "your opponents." msgstr "Vi har baner med diverse temaer, som spillere kan fornøje sig med fra kørsel under vandet, landbrug, jungler og endda i rummet! Gør dit bedste, mens du undviger andre karts, der overhaler dig, men spis ikke bananerne! Pas på bowlingkugler, svuppere, tyggegummi og kager som kastes af dine modstandere." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " "battle mode against the computer or your friends, and more! For a greater " "challenge, join online and meet players from all over the world and prove " "your racing skills!" -msgstr "Du kan tage et enkelt race mod andre karts, dyste i en af mange grandprixer, prøve at slå highscore i tidskørsel på egen hånd, spille i kamptilstand mod computeren eller dine venner og mere! For en større udfordring kan du tilslutte dig online, møde og bevise dine køreevner med og for spillere fra hele verden!" +msgstr "Du kan tage et enkeltløb mod andre karts, dyste i en af mange grandprixer, prøve at slå highscore i tidskørsel på egen hånd, spille i kamptilstand mod computeren eller dine venner og mere! For en større udfordring kan du tilslutte dig online, møde og bevise dine køreevner med og for spillere fra hele verden!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Spillet har ingen reklamer." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Dette er den ustabile version af SuperTuxKart som indeholder de seneste forbedringer. Den udgives primært til testning, for at gøre den stabile STK så god som muligt." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Denne version kan installeres på enheden, parallelt med den stabile version." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Hvis du har brug for mere stabilitet, så overvej at bruge den stabile version: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "SuperTuxKart-teamet" diff --git a/data/po/de.po b/data/po/de.po index 00dd1aa0885..ae3d9774b70 100644 --- a/data/po/de.po +++ b/data/po/de.po @@ -8,9 +8,10 @@ # Benau, 2018 # Benau, 2018-2020 # bonifarz , 2015 +# Daniel Tonscherer, 2025 # Ettore Atalan , 2015-2017,2019-2020 # FabianF, 2020 -# FabianF, 2020-2023 +# FabianF, 2020-2023,2025 # Flakebi, 2015 # Flakebi, 2015 # hiker , 2015 @@ -25,6 +26,7 @@ # Markus Enzenberger , 2019 # Maximilian Wagenbach , 2016 # Maximilian Wagenbach , 2016 +# Sven Andreas Belting, 2025 # FabianF, 2020 # Tim, 2022 # Tim, 2022 @@ -36,9 +38,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Iwan Gabovitch, 2023\n" +"Last-Translator: Sven Andreas Belting, 2025\n" "Language-Team: German (http://app.transifex.com/supertuxkart/supertuxkart/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -195,7 +197,7 @@ msgstr "Am Ende der Welt" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Zurück" @@ -217,7 +219,7 @@ msgstr "Wähle einen Steuerungstyp, den du bevorzugst" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Beschleunigungsmesser" @@ -231,13 +233,13 @@ msgstr "Beschleunigungsmesser" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Gyroskop" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Lenkrad" @@ -268,35 +270,37 @@ msgstr "Berührungssensor-Einstellungen" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Allgemein" @@ -364,30 +368,33 @@ msgstr "Standardeinstellungen wiederherstellen" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Abbrechen" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Ja" @@ -565,9 +572,9 @@ msgstr "Verbinden" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -628,7 +635,7 @@ msgstr "Ziel" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Fortschritt" @@ -663,7 +670,7 @@ msgstr "Anwenden" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Zurück zum Rennen" @@ -680,7 +687,7 @@ msgstr "Zurück zur Lobby" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Rennen neu starten" @@ -744,12 +751,12 @@ msgstr "Gib den Benutzernamen und die E-Mail-Adresse von der Registrierung ein, #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Benutzername" @@ -790,7 +797,7 @@ msgstr "Schwierigkeitsgrad" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Anfänger" @@ -802,7 +809,7 @@ msgstr "Anfänger" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Fortgeschrittener" @@ -814,7 +821,7 @@ msgstr "Fortgeschrittener" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Experte" @@ -826,7 +833,7 @@ msgstr "Experte" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -834,8 +841,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Spielmodus" @@ -846,8 +853,8 @@ msgstr "Spielmodus" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Normales Rennen" @@ -860,7 +867,7 @@ msgstr "Normales Rennen" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Zeitrennen" @@ -868,7 +875,8 @@ msgstr "Zeitrennen" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Kampf" @@ -877,24 +885,24 @@ msgstr "Kampf" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Fußball" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Passwort" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Lesezeichen für diesen Server setzen" @@ -905,7 +913,7 @@ msgstr "Spieler hinzufügen" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Name" @@ -999,6 +1007,50 @@ msgstr "Der Esc-Taste zuweisen" msgid "Assign nothing" msgstr "Nichts zuweisen" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Empfohlene Videoeinstellungen" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Die empfohlenen Einstellungen funktionieren mit der aktuellen Auflösung." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Was sollen die Einstellungen bevorzugen?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Leistung" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Balance zwischen Grafikqualität und Leistung" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Grafikqualität" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Energie sparen" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Magst du Unschärfe-Effekte?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Test starten" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -1013,11 +1065,11 @@ msgstr "Renneinstellungen" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Weiter" @@ -1058,10 +1110,15 @@ msgstr "Arenen" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Installiert" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Lieblingsarenas bearbeiten" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1071,20 +1128,20 @@ msgstr "Installiert" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Standard" @@ -1095,12 +1152,12 @@ msgstr "Standard" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Add-ons" @@ -1114,27 +1171,28 @@ msgstr "Add-ons" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Alle" @@ -1173,9 +1231,9 @@ msgstr "Nach unten bewegen" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Hinzufügen" @@ -1212,7 +1270,7 @@ msgstr "Geisterwiederholungsauswahl" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Eierjagd" @@ -1259,10 +1317,10 @@ msgstr "Rückwärts" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Maximale Dauer (min)" @@ -1294,9 +1352,9 @@ msgstr "Kopieren" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1307,80 +1365,80 @@ msgstr "Umbenennen" msgid "Save Grand Prix" msgstr "GP speichern" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "SuperTuxKart-Hilfe" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Spielmodi" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Boni" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Bananen" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1388,56 +1446,57 @@ msgstr "Bananen" msgid "Story Mode" msgstr "Story-Modus" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Kartklassen" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Mehrspieler" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Tutorial starten" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Sammle blaue Geschenkboxen ein, sie werden dir Boni geben." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Weich den Bananen aus!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1445,14 +1504,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Nitro sammeln erlaubt dir einen Geschwindigkeits-Schub, wann immer du willst. Benutze die entsprechende Taste (oder einen Knopf). Du kannst die Menge des verfügbaren Nitros in der Anzeige rechts unten im Rennbildschirm sehen." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Wenn du einen Knopf mit einem Schloss wie dem da links siehst, musst du eine Herausforderung meistern, um es zu öffnen." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1461,34 +1520,34 @@ msgid "" "carefully before!" msgstr "Du schlitterst, indem du eine bestimmte Taste bzw. einen Knopf drückst. Kurzes Schlittern in Folge hilft dir, scharfe Kurven zu kratzen, während mittellanges Schlittern dir einen kleinen Geschwindigkeitsschub gibt, und langes Schlittern einen großen. Beim Schlittern wirst du dich immer drehen, also richte dein Kart vorher gut aus!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Du kannst am Start einen Geschwindigkeitsschub erhalten, wenn du vor Rennbeginn die Beschleunigungstaste bei „Fertig?“ drückst." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Aktuelle Tastenbelegungen können im Einstellungsmenü angesehen/geändert werden" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart hat mehrere Spielmodi:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Normales Rennen: Alles ist erlaubt, also schnapp dir Boni und gebrauch sie klug!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Zeitrennen: Keine Boni – auf dein Können kommt es an!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1496,7 +1555,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Folge dem Spitzenreiter: Bleib auf dem zweiten Platz, weil das letzte Kart jedes Mal, wenn der Zähler auf null herunterläuft, disqualifiziert wird. Achtung: Wenn du den Spitzenreiter überholst, wirst du ebenfalls disqualifiziert!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1506,30 +1565,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Es gibt 3 Kampfmodi: Im 3-Treffer-Kampf musst du andere mit Waffen treffen, bis sie all ihre Leben verloren haben. Bei Jeder gegen Jeden gewinnt der Spieler mit den meisten Treffern innerhalb eines bestimmten Treffer- oder Zeitlimits. In Capture the Flag muss dein Team die Flagge zum anderen Team deiner eigenen Flaggenbasis bringen, solange die Flagge nicht vom anderen Team geklaut wurde." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Fußball: Benutz dein Kart, um den Ball ins Tor zu schießen." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Eierjagd: Durchsuche Strecken, um alle versteckten Eier zu finden." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Geisterwiederholung: Fahr ein Rennen gegen Geisterwiederholungen im Zeitrennen- oder Eierjagdmodus und zeichne deine eigenen Geister auf!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Rundenrennen: Fahre innerhalb der vorgegebenen Zeit so viele Runden wie möglich." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1538,93 +1597,93 @@ msgid "" "wins the cup." msgstr "* Viele dieser Spielmodi können außerdem als Grand Prix gespielt werden. Anstatt ein einzelnes Rennen zu spielen, spielst du viele hintereinander. Je besser deine Platzierung ist, desto mehr Punkte erhältst du. Am Schluss gewinnt der Spieler mit den meisten Punkten den Pokal." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Um dir zum Sieg zu verhelfen, gibt es kleine Boni zum Aufsammeln:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Kaugummi – schütze dich mit einem Schild, oder benutze ihn beim Zurückschauen, um eine klebrige rosa Spur zu hinterlassen." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Turbo – gibt dir einen starken Geschwindigkeitsschub. Aber pass auf, dass du nicht die Kontrolle über dein Kart verlierst!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Kuchen – Wird auf den Gegner geworfen, der am nächsten ist; wirkt am Besten auf kurzen und geraden Strecken. Betrifft auch andere Karts in der Nähe der Explosion." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Pömpel – Wirf ihn nach vorne, um einen Gegner zurückzuziehen, oder wirf ihn, während du nach hinten schaust, um die Sicht des Gegners zu blockieren." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Bowlingkugel – rollt geradeaus, bis sie trifft, sie kann von Wänden abprallen. Wird nach hinten geworfen, wenn du nach hinten schaust." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Fallschirm – Bremst alle Karts weiter vorne ab." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Wandler – Geschenke werden für kurze Zeit zu Bananen, Nitrokanister zu Kaugummi, und umgekehrt." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Basketball – springt zum Spitzenreiter und kann andere Karts auf dem Weg dorthin zerquetschen und abbremsen." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Fliegenklatsche – Zerquetscht nahe Karts und bremst sie dadurch ab. Kann auch benutzt werden, um Fallschirme und Bomben loszuwerden." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Eines der folgenden Dinge wird deinem Kart angehängt, wenn du eine Banane triffst:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Anker – verlangsamt das Kart schlagartig." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Fallschirm – verlangsamt das Kart zunehmend. Je schneller du unterwegs bist, desto stärker ist der Verlangsamungseffekt." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bombe – explodiert nach einer gewissen Zeit, was das Kart in die Luft schleudert. Kollidiere mit einem anderen Kart, um ihm die Bombe zu geben." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Der böse Nolok hat Gnu gefangen genommen. Hier sind ein paar Tipps, um dir zu helfen:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1633,7 +1692,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Das Symbol auf der Übersichtskarte zeigt die vorhandenen Herausforderungen, die du noch nicht vollendet hast. In der oberen rechten Ecke des Bildschirms siehst du außerdem, wie viele Punkte du derzeit hast. Vollende so viele Herausforderungen wie möglich, dann wird Nolok dir gestatten, Rennen gegen ihn zu fahren. Gewinne, um Gnu zu befreien!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1641,20 +1700,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Wenn du eine Herausforderung abschließt, erhältst du einen Pokal. Jeder Pokal ist einige Punkte wert. Je höher der Schwierigkeitsgrad der Herausforderung ist, desto besser ist der Pokal und desto mehr Punkte ist er wert." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Wenn du die Anzahl der Punkte, die sich unter diesem Symbol befinden, hast, gibt es eine Überraschung. Es gibt einiges zum Sammlen." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Nicht alle Karts haben das gleiche Fahrverhalten! Sie gehören zu Klassen mit einigen Unterschieden:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1662,7 +1721,7 @@ msgid "" " resistant to explosions." msgstr "Masse – es gibt drei Kartklassen, abhängig von ihrer Masse: leicht, mittel und schwer. Schwerere Karts werden weniger von Fallschirmen beeinflusst und sind widerstandsfähiger gegenüber Explosionen." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1670,7 +1729,7 @@ msgid "" " especially at low speeds." msgstr "Beschleunigung – besonders nützlich am Start, nach einem Unfall oder auf Strecken mit vielen scharfen Kurven. Je leichter das Kart ist, desto schneller beschleunigt es, besonders bei niedrigen Geschwindigkeiten." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1678,14 +1737,14 @@ msgid "" " top speed." msgstr "Höchstgeschwindigkeit – je höher sie ist, desto schneller kann sich das Kart fortbewegen. Besonders nützlich auf Strecken mit geraden Linien und sanften Kurven. Schwerere Karts haben eine höhere Höchstgeschwindigkeit." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Nitroeffizienz – Je höher sie ist, desto mehr kannst du von einer Nitroflasche beschleunigt werden. Ein leichteres Kart wird eine höhere Nitroeffizienz haben." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1693,12 +1752,12 @@ msgid "" "easier it is." msgstr "Wenn du einem Kart für ein paar Sekunden folgst, erhältst du einen Windschattengeschwindigkeitsbonus, wenn du ihn überholst. Je leichter dein Kart ist, desto einfacher wird es." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart kann im Mehrspielermodus online gespielt werden ...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1708,7 +1767,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Wähle zuerst den „Online“-Knopf im Hauptmenü aus. Wähle dann entweder „Lokales Netzwerk“ oder „Globales Netzwerk“ (dafür muss das Internet in den Einstellungen eingeschaltet sein). Dann kannst du entweder deinen eigenen Server mit von dir gewählten Einstellungen starten oder einen existierenden Server aus einer Liste zum Verbinden aussuchen. Einige von ihnen sind empfohlene Server, auf denen gewertete Rennen laufen können." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1718,12 +1777,12 @@ msgid "" "players and the server." msgstr "Wenn du dich in einem Server befindest, wird ein Rennen beginnen, sobald der Inhaber (mit einer Krone symbolisiert) entscheidet, zu starten. Offizielle Server werden Rennen evtl. nur automatisch starten, wenn es genügend Spieler gibt. Dann kannst du dein Kart auswählen und für die nächste Rennstrecke abstimmen. Add-on-Strecken sind nur erlaubt, wenn alle Spieler und der Server sie installiert haben." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... oder auf dem selben Gerät:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1733,7 +1792,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Zuerst wirst du mehrere Eingabegeräte benötigen. Benutze die Eingabeeinstellungen, um sie einzurichten. Mehrere Gamepads oder Joysticks sind ideal. Mit Tastatur(en) braucht jeder Spieler einen anderen Satz Tasten; die meisten Tastaturen sind für Mehrspieler ungeeignet, da sie mehrere gleichzeitige Tastendrücke nicht unterstützen." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1753,17 +1812,17 @@ msgstr "Rekordzeit-Auswahl" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" -msgstr "Rundenversuch" +msgstr "Rundenrennen" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Grand Prix" @@ -1774,6 +1833,20 @@ msgstr "Grand Prix" msgid "Choose a Kart" msgstr "Wähle ein Kart" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Kartklasse" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Lieblingskarts bearbeiten" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1787,11 +1860,11 @@ msgstr "Splitscreen-​Mehrspieler" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Online" @@ -1808,7 +1881,7 @@ msgstr "Tutorial" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Beste Zeiten" @@ -1816,7 +1889,7 @@ msgstr "Beste Zeiten" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Auszeichnungen" @@ -1870,30 +1943,30 @@ msgstr "Server finden" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Server erstellen" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Lobby" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Einstellungen" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Rennen starten" @@ -1919,9 +1992,9 @@ msgstr "Server-Adresse eingeben" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Dein Profil" @@ -1939,7 +2012,7 @@ msgstr "Spielerplatzierungen" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Freunde" @@ -1964,7 +2037,7 @@ msgstr "Schnelles Spiel" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Kontoeinstellungen" @@ -2014,8 +2087,8 @@ msgid "Online Username" msgstr "Online-Benutzername" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Passwort zurücksetzen" @@ -2028,7 +2101,7 @@ msgid "" msgstr "Du kannst spielen, ohne ein Online-Konto zu erstellen, indem du ein Offline-Konto auswählst. Allerdings kannst du dich dann nicht mit Freunden verbinden, für Add-ons abstimmen usw. Bitte lies unsere Datenschutzerklärung unter https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Serverauswahl" @@ -2046,339 +2119,409 @@ msgstr "Benutze IPv6-Verbindung" msgid "User search" msgstr "Benutzersuche" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "SuperTuxKart-Einstellungen" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Anzeige" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Grafik" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Ton" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Oberfläche" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Spieler" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Steuerung" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Sprache" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Musik" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Aktiviert" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Lautstärke" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Klangeffekte" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Konfiguration löschen" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Konfiguration deaktivieren" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Zurück zur Geräteliste" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Konfiguration umbennen" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Force Feedback aktivieren (falls möglich)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Auflösung" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Vollbildmodus" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Fensterposition merken" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Neue Auflösung anwenden" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Splitscreen-Mehrspieler-Layout" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Internetoptionen" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Anmeldedialog immer zeigen" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Mit dem Internet verbinden" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Online-Chat aktivieren" +msgid "Enable chatting in online lobbies" +msgstr "Chat in Online-Lobbys aktivieren" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" +msgid "Enable chatting in online matches" msgstr "Chat in Online-Spielen aktivieren" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Sonstige Einstellungen" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Spieler-Handicaps aktivieren" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Vollständige Spieldaten deinstallieren" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Drücke Enter oder doppelklicke auf ein Gerät, um es zu konfigurieren" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Gerät hinzufügen" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Welche Konfiguration benutzt werden soll, wird von der benutzten „Auswählen“-Taste abgeleitet." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Design" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Übersichtskarte" +msgid "Skin variant" +msgstr "Skin variante" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Splitscreen-Mehrspieler-Layout" +msgid "Minimap" +msgstr "Übersichtskarte" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Schriftgröße" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Kamera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Benutzerdefiniert ..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Bildrate anzeigen" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Boni im Besitz der anderen Karts zeigen" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Story-Modus-Stoppuhr aktivieren" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Speedrun-Stoppuhr aktivieren" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" -msgstr "Auflösung rendern" +msgstr "Renderauflösung" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Grafikeffekt-Stufe" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Unschärfeneffektstufe" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Maximale FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Benutzerdefiniert ..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Auflösung" +msgid "Performance tests" +msgstr "Leistungstests" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Vollbildmodus" +msgid "Performance test of the current settings" +msgstr "Leistungstest mit den aktuellen Einstellungen" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Fensterposition merken" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Passwort speichern" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Neue Auflösung anwenden" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Entfernen" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Kartfarbe" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2405,15 +2548,15 @@ msgstr "Blaues Team" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Anzahl der Runden" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Anzahl der KI-Karts" @@ -2428,33 +2571,17 @@ msgstr "Anzahl der blauen KI-Karts" msgid "Random Grand Prix" msgstr "Zufälliger Grand Prix" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Lieblingsstrecken bearbeiten" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Einloggen" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Passwort speichern" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Entfernen" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Kartfarbe" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Das Design der Benutzeroberfläche kann in den Benutzeroberflächenoptionen geändert werden." @@ -2573,238 +2700,306 @@ msgid "" msgstr "Versuche nicht, an den Fußball zu kommen, wenn dieser bereits im Besitz deiner Mannschaft ist, sondern konzentriere dich darauf, Gegner abzuschießen, die versuchen, deine Mannschaft am Toreschießen zu hindern." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Vorsintflutlicher Abgrund" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Außerirdisches Signal" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Antikes Kolosseumslabyrinth" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Kerzenstadt" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Kampfinsel" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Schwarzwald" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Höhle X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Cocoa-Tempel" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Kornfeldkreuzung" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Fort Magma" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Gran-Paradiso-Insel" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Hole Drop" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Vereistes Fußballfeld" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Was ist los, ihr kleinen Hippies? Fehlt euch euer Gnu-Anführer?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Oh ja, er ist jetzt in meiner Burg und wird zum Abendessen serviert werden …" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Aber ich bin fair, also mach ich euch ein Angebot." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Wenn ihr mich beim Rennen schlagen könnt, dann werd ich den alten Knacker freilassen." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " Aber ihr erbärmlichen Knilche werdet mich niemals besiegen – den König der Karts!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Las-Dunas-Arena" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Las-Dunas-Fußballstadion" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Um den Leuchtturm" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Alte Mine" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oase" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Olivers Mathestunde" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Kürbispark" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Villa Rabenbrück" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Treibsand" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Nessies Teich" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Im hohen Norden" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Schneegipfel" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Fußballplatz" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Das Stadion" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Enterprise" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Tempel" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Vulkaninsel" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Zengarten" @@ -2813,11 +3008,11 @@ msgstr "Zengarten" msgid "Completed achievement \"%s\"." msgstr "Auszeichnung „%s“ erhalten." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Es konnte sich nicht mit dem SuperTuxKart-Add-ons-Server verbunden werden." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Fehler beim Herunterladen der Nachrichten: „%s“." @@ -2883,7 +3078,7 @@ msgid "New kart '%s' now available" msgstr "Neues Kart „%s“ verfügbar" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2915,32 +3110,32 @@ msgid "" "created." msgstr "Die Konfigurationsdatei war zu alt, daher wurde sie gelöscht und eine neue wird erstellt." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Videoaufnahme gestartet." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Video in „%s“ gespeichert." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Kodierungsfortschritt:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d – %d Tsd. Dreiecke, Ping: %d ms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Tipp: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Laden" @@ -2962,19 +3157,18 @@ msgstr "Nitroeffizienz" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (mit Handicap)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s ist bereit" @@ -3448,21 +3642,21 @@ msgid "Axis %d" msgstr "Achse %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Gamepad-Taste %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Maustaste %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Mausachse %d %s" @@ -3634,26 +3828,30 @@ msgstr "Du kannst bis zu 3 Leben haben!" msgid "+1 life." msgstr "+1 Leben." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Du warst zu langsam!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Du hast das Rennen beendet!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Du hast das Rennen gewonnen!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Du hast das Rennen auf dem %d. Platz beendet!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s verließ das Spiel." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3662,16 +3860,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart kann sich mit einem Server verbinden, um Add-ons herunterzuladen und dich über Aktualisierungen zu informieren. Bitte lies unsere Datenschutzerklärung unter https://supertuxkart.net/Privacy. Möchtest du diese Funktion aktivieren? (Um diese Einstellung später zu ändern, gehe zu den Optionen, wähle die Registerkarte \"Allgemein\" und ändere \"Mit dem Internet verbinden\")." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Deine Bildschirmauflösung ist zu klein für STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Dein Treiber ist zu alt. Bitte installiere die neuste Version des Grafiktreibers." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3679,38 +3877,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Dein Grafiktreiber scheint sehr alt zu sein. Bitte schaue nach, ob eine Aktualisierung verfügbar ist. SuperTuxKart empfiehlt einen Treiber, der %s oder besser unterstützt. Das Spiel wird wahrscheinlich noch laufen, aber in einem reduzierten Grafikmodus." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Netzwerkzeitüberschreitung bei Serververbindung." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s hat die rote Flagge!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Die rote Flagge ist zurückgekehrt!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s hat die blaue Flagge!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Die blaue Flagge ist zurückgekehrt!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s hat die blaue Flagge erobert!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s hat die rote Flagge erobert!" @@ -3720,7 +3918,7 @@ msgstr "%s hat die rote Flagge erobert!" msgid "Eggs: %d / %d" msgstr "Eier: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Spitzenreiter" @@ -3728,22 +3926,22 @@ msgstr "Spitzenreiter" msgid "Final lap!" msgstr "Letzte Runde!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "%i. Runde" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s von %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Neue schnellste Runde" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "FALSCHE RICHTUNG!" @@ -3757,194 +3955,194 @@ msgstr "%s hat ein Tor geschossen!" msgid "Oops, %s made an own goal!" msgstr "Ups, %s hat ein Eigentor geschossen!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "%i Ersatzreifenkart ist aufgetaucht!" msgstr[1] "%i Ersatzreifenkarts sind aufgetaucht!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Du bist ausgeschieden!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "%s ist ausgeschieden." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Server wurde abgeschaltet." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Du wurdest vom Server hinausgeworfen." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Du wurdest hinausgeworfen: Zu hoher Ping." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Schlechte Netzwerkverbindung wurde erkannt." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s wurde getrennt." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Wähle einen Spielernamen in der Liste für Spielerverwaltung und Ranginformationen." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Schwierigkeit: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Max. Spieler: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Spielmodus: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Zeitlimit" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Torlimit" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Fußballspieltyp: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Grand-Prix-Fortschritt: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Alle Spieler sind dem roten oder blauen Team beigetreten." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Du bist nun der Inhaber des Servers." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Verbindung abgewiesen: Server ist beschäftigt." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Verbindung abgewiesen: Du bist vom Server gebannt." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Verbindung abgewiesen: Serverpasswort ist falsch." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Verbindung abgewiesen: Spieldaten sind inkompatibel." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Verbindung abgewiesen: Server ist voll." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Verbindung abgewiesen: Verbindung eines ungültigen Spielers." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Netzwerkspiel konnte nicht gestartet werden." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Das Spiel ist vorbei, du kannst nicht mehr beitreten oder zuschauen." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "In der Arena ist kein Platz mehr frei – Beitreten ist deaktiviert." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Nur 1 Spieler übrig, es geht zurück in die Lobby." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Der Inhaber des Servers hat das Spiel beendet." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Du wirst im nächsten Spiel zuschauen." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s ist dem roten Team beigetreten." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s ist dem blauen Team beigetreten." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s ist dem Spiel beigetreten." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3952,15 +4150,15 @@ msgid "" msgstr "Drücke <%s> oder <%s>, um einen anderen Spieler auszuwählen, <%s> oder <%s>, um die Kameraposition zu ändern." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "%s erfolgreich gemeldet." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3991,38 +4189,38 @@ msgstr "Zeitrennen (Grand Prix)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Jeder gegen Jeden" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Capture the Flag" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s ist nun online." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s und %s sind jetzt online." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s und %s sind jetzt online." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4030,19 +4228,19 @@ msgstr[0] "%d Freund ist nun online." msgstr[1] "%d Freunde sind nun online." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s ist nun auf dem Server „%s“." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "Du hast %d neue Freundschaftsanfrage!" msgstr[1] "Du hast %d neue Freundschaftsanfragen!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Du hast eine neue Freundschaftsanfrage!" @@ -4071,12 +4269,12 @@ msgid "" msgstr "Die Bestenliste war zu alt,\nalle Platzierungen wurden gelöscht." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Folge dem Spitzenreiter" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "3-Treffer-Kampf" @@ -4089,91 +4287,88 @@ msgstr "Unvollständige Wiederholungsdatei wird nicht gespeichert." msgid "Replay saved in \"%s\"." msgstr "Wiederholung in „%s“ gespeichert." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 Woche" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 Wochen" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 Monat" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 Monate" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 Monate" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 Monate" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 Jahr" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 Jahre" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Add-on-Name" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Aktualisiert am" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Nicht installiert" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s von %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Bitte warte, während die Add-ons aktualisiert werden" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Während der Verbindung zur Add-ons-Webpräsenz ist ein Fehler aufgetreten. Bitte stelle sicher, dass du mit dem Internet verbunden bist und, dass die Verbindung nicht durch eine Firewall blockiert wird" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Favoriten" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Gesperrt: Meistere Herausforderungen, um mehr freizuschalten!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Zufällige Arena" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d Arena im Einzelspielermodus nicht verfügbar." -msgstr[1] "%d Arenen im Einzelspielermodus nicht verfügbar." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\n79353a696ad19dc202b261b3067b7640_bec941e, 2015\nWuzzy, 2015-2018\nBenau, 2018\nBenau, 2018-2020\nbonifarz, 2015\nEttore Atalan, 2015-2017,2019-2020\nFabianF, 2020-2022\nFlakebi, 2015\nhiker, 2015\nJuli X, 2022\nkonstin, 2015\nLink_Mario, 2019\nMarkus Enzenberger, 2019\nMaximilian Wagenbach, 2016\nFabianF, 2020\nTim, 2022\nTobias Markus, 2015-2016\nWasilis Mandratzis-Walz, 2015\nwesen, 2016\nFabianF, 2020-2021\nAuria\nBendetto\nDHermit\nDaBASCHT\nDavid Roth\nDawid Gan\nDennis\nEvolution\nFelix\nGerjet Kleine-Weischede\nGregor Santner\nH0ff1\nJohn Doe\nMatthias Lange\nRobert Kurz\nSTK-team\nSalesome\nSimeon\nTobias Bannert\nWolfs\nWuzzy\ncmdrhenner\ne\nenz\nhiker\nkonstin\npert7" @@ -4461,7 +4656,7 @@ msgstr "Gesammelte Bananen" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Schlittern" @@ -4564,7 +4759,7 @@ msgstr "Abgeschlossene Eierjagden" msgid " (official tracks matching the goal)" msgstr " (offizielle Strecken, die zum Ziel passen)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4572,91 +4767,95 @@ msgid "" msgstr "Neue Gamepads und Joysticks werden automatisch in der Liste erscheinen, wenn du sie mit diesem Gerät verbindest.\n\nUm eine Tastaturkonfiguration hinzuzufügen, nutze den unteren Knopf. ABER BITTE BEACHTE, dass die meisten Tastaturen nur eine beschränkte Anzahl an gleichzeitig drückbaren Tasten unterstützen und somit ungeeignet für Mehrspieler-Spiele sind. (Du kannst jedoch mehrere Tastaturen mit diesem Gerät verbinden. Denke aber daran, dass auch in diesem Fall jeder unterschiedliche Tastenkombinationen benötigt.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Wiimote hinzufügen" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Tastaturkonfiguration hinzufügen" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Aktualisieren" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Version: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "vorgestellt" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Größe: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Du musst angemeldet sein um dieses Add-on zu bewerten." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Add-on-Download fehlgeschlagen" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Beim Installieren des Add-ons „%s“ ist ein Problem aufgetreten." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Nochmal versuchen" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Beim Entfernen des Add-ons „%s“ ist ein Problem aufgetreten." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Hintergrund-Download abgeschlossen." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Hintergrund-Download" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Hintergrund-Download wurde bereits gestartet." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Aktuelles Passwort ist ungültig." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Das Passwort muss zwischen 8 und 30 Zeichen lang sein!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Passwörter stimmen nicht überein!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Informationen überprüfen" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Das Passwort wurde erfolgreich geändert." @@ -4677,67 +4876,97 @@ msgstr "Auflösungen, die kleiner als 1024×768 oder 1280×720 sind, werden nich #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Drohnenjagd" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Benutzerdefiniert" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Deaktiviert" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Nur Wichtige" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Sehr niedrig" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Niedrig" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Mittel" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Hoch" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Sehr hoch" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4745,7 +4974,7 @@ msgid "" msgstr "SuperTuxKart wird vollständige Spieldaten (mit allen Strecken, hochqualitativen Texturen und Musik) für ein besseres Spielerlebnis herunterladen; dies wird deine Mobilen Daten in Anspruch nehmen, falls du keine WLAN-Verbindung hast." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4762,101 +4991,102 @@ msgstr "Gib die Server-Adresse ein, optional gefolgt von einem Doppelpunkt, und msgid "Invalid server address: %s." msgstr "Ungültige Server-Adresse: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Rückwärts" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Schwierigkeit" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Runden" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Zeit" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Kart" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Benutzer" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Version" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Nein" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Strecke" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Beste %d Zeiten" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s:%s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Anzahl der Karts: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Ziel-Zeit: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Runden: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Rückwärts: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Leer)" @@ -4944,33 +5174,41 @@ msgid "Press any key..." msgstr "Drücke eine beliebige Taste ..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Chat ist deaktiviert, aktiviere ihn in den Einstellungen." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Zurück zum Leistungstest" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Leistungstest verlassen" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Zurück zum Kampf" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Neues Spiel" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Kampf neu starten" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Kampf verlassen" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Neues Rennen" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Rennen beenden" @@ -4986,11 +5224,11 @@ msgstr "%s hat noch keine Platzierung." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s ist auf dem %d. Platz mit einer Punktzahl von %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Benutzername und/oder E-Mail-Adresse ungültig." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5012,7 +5250,7 @@ msgstr "Geisterwiederholungsrennen" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Runden: %i" @@ -5025,21 +5263,21 @@ msgstr "Art: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Benötigter Rang: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Benötigte Zeit: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Benötigte Nitropunkte: %i" @@ -5052,54 +5290,54 @@ msgstr "Anzahl an KI-Karts: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Kampfmodus" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Fußballspieltyp" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Server-Ort: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Aktuelle Strecke: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Rang" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Spieler" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Punkte" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Spielzeit" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Aus Lesezeichen entfernen" @@ -5112,74 +5350,74 @@ msgid "No player available for connecting to server." msgstr "Kein Spieler verfügbar, der sich zum Server verbinden könnte." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Benutzername: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Anfrage verwerfen" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Heute" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Freundschaftsanfrage gesendet!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Frendschaftsanfrage akzeptiert!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Freundschaftsanfrage abgelehnt!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Freund entfernt!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Freundschaftsanfrage abgebrochen!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Verarbeitung läuft" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Letzte Stimme laden" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Du kannst deine vorherige Bewertung bearbeiten, indem du auf die Sterne darunter klickst." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Du hast für dieses Add-on noch keine Stimme abgegeben. Wähle deine gewünschte Bewertung, indem du die Sterne darunter anklickst" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Abstimmung erfolgreich! Du kannst nun das Fenster schließen." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Stimme abgeben" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Zufällige Strecke" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5208,7 +5446,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Beim Speichern deines Grand Prix trat ein Fehler auf." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Strecke auswählen" @@ -5252,12 +5490,12 @@ msgstr "Du hast die Strecke „%0“ freigeschaltet" msgid "You unlocked grand prix %0" msgstr "Du hast den Grand Prix „%0“ freigeschaltet" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Strecke" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5278,19 +5516,19 @@ msgstr "Bitte gib den Namen des Grand Prix ein" msgid "Please select a Grand Prix" msgstr "Bitte wähle einen Grand Prix aus" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Benutzerdefiniert" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Der Name ist leer." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Ein anderer Grand Prix mit diesem Namen existiert bereits." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Der Name ist zu lang." @@ -5299,19 +5537,19 @@ msgstr "Der Name ist zu lang." msgid "Better luck next time!" msgstr "Vielleicht klappt es beim nächsten Mal!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Du hast eine Herausforderung gemeistert!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Du hast den Grand Prix gewonnen!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Du hast den Grand Prix beendet!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Anzahl der Karts" @@ -5324,110 +5562,125 @@ msgstr "Bist du sicher, dass du diesen Rekordzeit-Eintrag löschen möchtest?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Bist du sicher, dass du alle Rekordzeiten löschen willst?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Favorit" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "leicht" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "schwer" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Verbinde eine Tastatur oder ein Gamepad, um Splitscreen-Mehrspieler zu spielen" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Zufälliges Kart" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Gesperrt" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "An alle:\nDrückt jetzt den „Auswählen“-Knopf, um dem Spiel beizutreten" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Möchtest du das Tutorial des Spiels machen?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Du kannst ohne Internetzugang nicht online spielen. Wenn du online spielen möchtest, gehe ins Einstellungsmenü und kreuze „Mit dem Internet verbinden“ an." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Du kannst ohne Internetzugang keine Add-ons herunterladen. Wenn du Add-ons herunterladen möchtest, gehe ins Einstellungsmenü und kreuze „Mit dem Internet verbinden“ an." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Du kannst ohne Internetzugang keine Add-ons herunterladen. Wenn du Add-ons herunterladen möchtest, gehe ins Einstellungsmenü und kreuze „Mit dem Internet verbinden“ an.\n\nDu kannst jedoch bereits heruntergeladene Add-ons löschen." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Das Add-ons-Modul ist derzeit in den Einstellungen deaktiviert" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Bitte warte, bis die Add-ons geladen sind" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Möchtest du STK wirklich beenden?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "LAN-Server erstellen" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Server von %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Anzahl der Grand-Prix-Strecken" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Der Name muss zwischen 4 und 30 Zeichen lang sein!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Ungültige Zeichen im Passwort!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Bereit" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Direkt beitreten" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Zuschauen" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Add-on installieren" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5435,7 +5688,7 @@ msgstr "Bitte warte auf das Ende des laufenden Spiels (%s); geschätzte verbleib #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Bitte warte auf das Ende des laufenden Spiels; geschätzte verbleibende Zeit: %s." @@ -5443,24 +5696,24 @@ msgstr "Bitte warte auf das Ende des laufenden Spiels; geschätzte verbleibende #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Bitte warte auf das Ende des laufenden Spiels (%s); geschätzter Fortschritt: %d%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Bitte warte auf das Ende des laufenden Spiels; geschätzter Fortschritt: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Bitte warte auf das Ende des laufenden Spiels." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5469,7 +5722,7 @@ msgstr[1] "Das Spiel wird starten, wenn mehr als %d Spieler anwesend sind." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5478,96 +5731,108 @@ msgid_plural "" msgstr[0] "Los geht's nach %d Sekunde oder, wenn jeder auf „Bereit“ gedrückt hat." msgstr[1] "Los geht's nach %d Sekunden oder nachdem jeder auf „Bereit“ gedrückt hat." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Verbindung zum Server %s wird hergestellt" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Nach Schnellspielserver suchen" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Verbleibende Zeit: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Ziele" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Auszeichnungen abholen" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Profil von %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Seit" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Status" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Freunde abholen" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Neue Anfrage" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Ausstehend" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Offline" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Gebe unten die neue E-Mail-Adresse ein" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Neue E-Mail-Adresse muss zwischen 5 und 254 Zeichen lang sein!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Neue E-Mail-Adresse ist ungültig!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "E-Mail-Adresse geändert!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Fehler beim Ändern der E-Mail-Adresse: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Neuigkeiten vom STK Blog" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Datum" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Zur Zeit sind keine Neuigkeiten verfügbar." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Du musst eingeloggt sein, um im globalen Netzwerk zu spielen. Klick oben auf deinen Benutzernamen." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Suche läuft" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Spiel verlassen" @@ -5645,34 +5910,34 @@ msgid "Distance (km)" msgstr "Distanz (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Unbekannt" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Kein IPv4 erkannt, es ist gegebenenfalls nicht möglich, sich mit Servern zu verbinden." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Kein IPv6 erkannt, es ist gegebenenfalls nicht möglich, sich mit Servern zu verbinden." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Kein Server ist verfügbar." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Server abholen" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Server-Lesezeichen" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5680,149 +5945,149 @@ msgstr "Falls eine Mehrheit der Spieler die selbe Strecke und Renneinstellungen #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Zufällige Gegenstandspositionen" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Anzahl der Tore bis zum Sieg" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Rückwärts fahren" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Gesperrt: Meistere Herausforderungen, um mehr freizuschalten!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Aktion" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Tastenbelegung" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Gerät deaktivieren" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Gerät aktivieren" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Konfiguration aktivieren" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Spiel-Tasten" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Menü-Tasten" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Links lenken" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Rechts lenken" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Beschleunigen" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Bremse / Rückwärts" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Schießen" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Zurückschauen" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Retten" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Spiel pausieren" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Nach oben" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Nach unten" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Links" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Rechts" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Auswählen" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Abbrechen/Zurück" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Blaue Einträge deuten auf einen Konflikt mit einer anderen Einstellung hin" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Rot markierte Stellen zeigen einen Konflikt in der aktuellen Konfiguration" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5830,17 +6095,27 @@ msgid "" msgstr "Achtung, die Umschalttaste ist als Taste nicht empfohlen. Alle Tasten, die mit ihr ein anderes Zeichen erzeugen, werden nicht mehr funktionieren." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Willst du diese Konfiguration wirklich unwiderruflich löschen?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Gib den neuen Konfigurationsnamen ein oder lasse leer, um den Standardwert wiederzugeben." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Vertikal" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Horizontal" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5848,89 +6123,74 @@ msgstr "Im Mehrspielermodus können Spieler (schwierigere)\nProfile mit Handicap #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Vollständige Spieldaten installieren" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Möchtest du die vollständigen Spieldaten wirklich deinstallieren?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Tastatur %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Gerät mit Berührungssensor" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Tippe auf ein Gerät, um es zu konfigurieren" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Systemsprache" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Unten links" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "Rechte Seite" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Verborgen" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Zentriert" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Vertikal" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Horizontal" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Sehr klein" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Klein" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Mittel" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Groß" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Sehr groß" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5940,128 +6200,133 @@ msgid "" msgstr "Der Speedrun-Modus kann nur aktiviert werden, wenn das Spiel ab dem Start des Story-Modus nicht geschlossen wurde.\n\nWird das Spiel vor dem Abschluss des Story-Modus geschlossen, wird die Zeit verworfen.\n\nUm den Speedrun-Modus zu benutzen, benutze bitte ein neues Profil." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Vertikale Synchronisation" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "VSync zwingt die Grafikkarte dazu, ein neues Frame\n(Einzelbild) nur dann zu liefern, wenn der Bildschirm bereit ist,\nes anzuzeigen." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "VSync wird nicht funktionieren, falls deine Treiber es nicht unterstützen." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Partikeleffekte: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Animierte Figuren: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Dynamische Lichter: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Lichtstreuung: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Kantenglättung: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Umgebungsverdeckung: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Schatten: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Schatten: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Bloom: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Leuchten (Umrisse): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Lichtschacht (Gottesstrahlen): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Qualität gerenderter Bilder: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Geometriedetail: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Bewegungsunschärfe: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Tiefenschärfe: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Internetzugang ist deaktiviert. Möchtest du ihn aktivieren?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Du musst ein Passwort eingeben." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Abmelden: „%s“" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Anmelden: „%s“" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Du kannst den einzigen Spieler nicht löschen." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Willst du den Spieler „%s“ wirklich löschen?" @@ -6089,7 +6354,7 @@ msgstr "TOR!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Auf andere warten" @@ -6124,7 +6389,7 @@ msgstr "Folge dem Spitzenreiter!" msgid "Top %i" msgstr "Top %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Herausforderung gescheitert" @@ -6148,102 +6413,199 @@ msgstr "Drücke das Podium-Symbol, um die Herausforderung zu starten" msgid "Press fire to start the challenge" msgstr "Drücke „Schießen“, um die Herausforderung zu starten" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Zurück zu den Videoeinstellungen" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Die Testergebnisse speichern" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Zurück zum Hauptmenü" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Den Server verlassen" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Grand Prix abbrechen" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Neu starten" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Zurück zur Herausforderungs-Auswahl" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Rennen gegen die neue Geisterwiederholung fahren" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Zurück zum Menü" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Möchtest du den Grand Prix wirklich abbrechen?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Leistungstest Bericht in \"%s\" gespeichert" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Rotes Team gewinnt" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Blaues Team gewinnt" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Es ist unentschieden" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Ausgeschieden nach %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Ausgeschieden" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Eigentor)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Strecke %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Grand-Prix-Fortschritt:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Bestenliste" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Beste Rundenzeit: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "von %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Du hast die Herausforderung gemeistert!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Du bist an der Herausforderung gescheitert!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Anforderungen für SuperTux erfüllt" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Leistungstest Ergebnis" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Testdauer: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Anzahl der Bilder: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "Stabile FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "Großteils stabile FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "Typische FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Horizontale Auflösung: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Vertikale Auflösung: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Dynamische Lichter: an" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Dynamische Lichter: aus" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Renderauflösung: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Kantenglättung: an" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Kantenglättung: aus" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Bildbasierte Beleuchtung: aus" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Bildbasierte Beleuchtung: an" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Umgebungsverdeckung: an" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Umgebungsverdeckung: aus" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Schattenauflösung: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Alles ist erlaubt, also hol dir Waffen und setze sie geschickt ein!" @@ -6284,28 +6646,28 @@ msgstr "Drücke das blaue oder das rote Fußball-Symbol, um zum jeweiligen Team #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Strecke von %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Maximal unterstützte Spieler: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Anzahl der roten KI-Karts" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Du kannst diesen Grand Prix nicht spielen, weil er Strecken enthält, die noch nicht freigeschaltet sind!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Gesperrt!" @@ -6327,10 +6689,12 @@ msgid "%d/%m/%Y" msgstr "%d. %m. %Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Gewinne alle Herausforderungen, um das große Tor zu öffnen!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6339,41 +6703,48 @@ msgid "" msgstr "Für diese Herausforderung\nbenötigst du mehr Punkte!\nVerfügbare Herausforderungen\nwerden auf der Karte angezeigt." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Beschleunige mit <%s> und lenke mit <%s> und <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Beschleunige, indem du den oberen Teil des Rades berührst, lenke mit Links- oder Rechtsbewegung." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Beschleunige, indem du das Gaspedal nach oben bewegst, lenke, indem du dein Gerät kippst." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Beschleunige, indem du das Gaspedal nach oben bewegst, lenke, indem du dein Gerät rotierst." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Sammle Geschenke und feuer die Waffe mit <%s> ab, um die Kisten wegzusprengen!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Sammle Geschenkkisten und mach einen Schuss mit dem Bowlingsymbol, um diese Kisten wegzupusten!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6381,34 +6752,41 @@ msgid "" msgstr "Drücke <%s>, um zurückzuschauen.\nSchieße nach hinten, indem du <%s> und <%s> gleichzeitig drückst." #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Drücke das Spiegel-Symbol, um zurückzuschauen.\nSchieße nach hinten, indem du erst das Spiegel-Symbol und dann das Bowling-Symbol drückst!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Nutze das Nitro, das du gesammelt hast, indem du <%s> drückst!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Nutze das Nitro, das du gesammelt hast, indem du das Nitrosymbol drückst" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Sammle Nitroflaschen (wir werden sie nach der Kurve brauchen)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Ups! Wenn du ein Problem hast, drücke <%s>, um gerettet zu werden." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Ups! Wenn du ein Problem hast, drücke das Vogelsymbol, um gerettet zu werden." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6416,24 +6794,27 @@ msgid "" msgstr "Beschleunige und drücke die <%s> Taste, während du dich zum Schlittern drehst. \nKurzes Schlittern kann dir dabei helfen, scharfe Kurven besser nehmen zu können." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Beschleunige und drücke das Schlittern-Symbol, während du dich zum Schlittern drehst. \nKurzes Schlittern kann dir dabei helfen, scharfe Kurven besser nehmen zu können." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Übrigens, wenn du es schaffst, für mehrere Sekunden zu schlittern, bekommst du einen Geschwindigkeitsschub als Belohnung!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Du bist jetzt bereit für Rennen. Viel Glück!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Ein Open-Source 3D-Kart-Rennspiel" @@ -6443,7 +6824,7 @@ msgstr "Ein Open-Source 3D-Kart-Rennspiel" msgid "tux;game;race;" msgstr "tux;spiel;rennen;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6451,7 +6832,7 @@ msgid "" "for all ages." msgstr "Karts. Nitro. Action! SuperTuxKart ist ein Open-Source 3D-Arcade-Rennspiel mit einer Vielzahl von Charakteren, Strecken und Spielmodi. Unser Ziel ist es, ein Spiel zu schaffen, das mehr Spaß macht als realistisch ist, und eine unterhaltsame Erfahrung für alle Altersgruppen bietet." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6460,7 +6841,7 @@ msgid "" "your opponents." msgstr "Wir haben mehrere Strecken mit verschiedenen Themen für Spieler, die sie genießen können: Fahrten unter Wasser, über ländliches Ackerland, durch den Dschungel oder sogar im Weltraum! Versuche dein Bestes und vermeide dabei andere Karts, da diese möglicherweise überholen, aber esse keine Bananen! Achte auf Bowlingkugeln, Pömpel, Kaugummi und Kuchen, die von deinen Gegnern geworfen werden." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6469,27 +6850,27 @@ msgid "" "your racing skills!" msgstr "Du kannst ein einzelnes Rennen gegen andere Karts fahren, an einem von mehreren Grands Prix teilnehmen, versuchen, den Rekord im Zeitfahren zu schlagen, im Kampfmodus gegen den Computer oder deine Freunde spielen und vieles mehr! Für eine noch größere Herausforderung kannst du dich online mit Spielern aus der ganzen Welt messen und deine Rennkünste unter Beweis stellen!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Dieses Spiel enthält keine Werbung." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Dies ist eine instabile Version von SuperTuxKart, die die neuesten Verbesserungen enthält. Sie wird hauptsächlich zum Testen freigegeben, um die stabile Version so gut wie möglich zu machen." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Diese Version kann parallel zur stabilen Version auf dem Gerät installiert werden." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Solltest du mehr Stabilität benötigen, verwende die stabile Version: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "SuperTuxKart-Team" diff --git a/data/po/eo.po b/data/po/eo.po index ba6ad2286fa..33c18968bd0 100644 --- a/data/po/eo.po +++ b/data/po/eo.po @@ -6,8 +6,9 @@ # FIRST AUTHOR , 2011 # Hendur Saga , 2020 # Lagash, 2022 -# Jakub Fabijan (Felidae) , 2021 -# Jakub Fabijan (Felidae) , 2023 +# jano2137, 2021 +# jano2137, 2023 +# Jakub Szafranek Fabijan , 2025 # Jonas Marx , 2017 # Jorge , 2021 # Kevin G , 2021 @@ -27,9 +28,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Nicolas G, 2022-2023\n" +"Last-Translator: Jakub Szafranek Fabijan , 2025\n" "Language-Team: Esperanto (http://app.transifex.com/supertuxkart/supertuxkart/language/eo/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -186,7 +187,7 @@ msgstr "Ĉe la mondfino" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Reen" @@ -208,7 +209,7 @@ msgstr "Elelktu la tipon de kontrolo ke vi preferas" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Akcelometro" @@ -222,13 +223,13 @@ msgstr "Akcelometro" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Giroskopo" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Stirilo" @@ -259,35 +260,37 @@ msgstr "Agordoj de la tuŝa aparato" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Ĝenerale" @@ -355,30 +358,33 @@ msgstr "Restaŭrigu defaŭltojn" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Nuligi" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Jes" @@ -556,9 +562,9 @@ msgstr "Aniĝi" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -619,7 +625,7 @@ msgstr "Celo" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Progreso" @@ -654,7 +660,7 @@ msgstr "Sendi" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Reen al la vetkuro" @@ -671,7 +677,7 @@ msgstr "Reveni al lobio" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Restartigi la vetkuron" @@ -735,12 +741,12 @@ msgstr "Entajpu uzantnomon kaj retadreson per kiu vi registriĝis por esti rajti #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Uzantnomo" @@ -781,7 +787,7 @@ msgstr "Facileco" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Novulo" @@ -793,7 +799,7 @@ msgstr "Novulo" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Meza" @@ -805,7 +811,7 @@ msgstr "Meza" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Spertula" @@ -817,7 +823,7 @@ msgstr "Spertula" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTukso" @@ -825,8 +831,8 @@ msgstr "SuperTukso" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Ludmodo" @@ -837,8 +843,8 @@ msgstr "Ludmodo" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Normala Vetkuro" @@ -851,7 +857,7 @@ msgstr "Normala Vetkuro" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Tempa Provo" @@ -859,7 +865,8 @@ msgstr "Tempa Provo" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Batalo" @@ -868,24 +875,24 @@ msgstr "Batalo" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Piedpilko" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Pasvorto" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Legosignu ĉi tiu servilo" @@ -896,7 +903,7 @@ msgstr "Aldonu ludanto" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Nomo" @@ -990,6 +997,50 @@ msgstr "Atribui al Eskapa Klavo" msgid "Assign nothing" msgstr "Atribui nenion" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -1004,11 +1055,11 @@ msgstr "Vetkura aranĝado" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Daŭrigi" @@ -1049,10 +1100,15 @@ msgstr "Arenoj" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Instalita" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1062,20 +1118,20 @@ msgstr "Instalita" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Standardo" @@ -1086,12 +1142,12 @@ msgstr "Standardo" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Aldonaĵoj" @@ -1105,27 +1161,28 @@ msgstr "Aldonaĵoj" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Ĉio" @@ -1164,9 +1221,9 @@ msgstr "Moviĝu suben" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Aldoni" @@ -1203,7 +1260,7 @@ msgstr "Elekto de fantomaj ripetludoj" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Ovoĉasado" @@ -1250,10 +1307,10 @@ msgstr "Inverse" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Maksimuma tempo (min.)" @@ -1285,9 +1342,9 @@ msgstr "Kopii" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1298,80 +1355,80 @@ msgstr "Renomi" msgid "Save Grand Prix" msgstr "Konservu Grandan Prezon" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "SuperTuxKart helpo" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Ludaj modoj" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Plifortigiloj" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Bananoj" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1379,56 +1436,57 @@ msgstr "Bananoj" msgid "Story Mode" msgstr "Rakonta modo" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Gokartaj klasoj" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Multludista" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Komenci la instuilon" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Kolektu bluajn donacajn ujojn, ili donos vin plifortigilojn." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Evitu la bananojn!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1436,14 +1494,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Kolekti nitron permesas al vi obteni rapidajn akcelojn kiam ajn vi deziras premante la taŭgan butonon. Vi povas vidi vian aktualan nivelon de nitron en la mezurilo ĉe la malsupre-dekstre de la ekrano de la vetkuro." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Se vi vidus butonon kun pendseruro kiel ĉi tiun, vi devos kompletigi defion por malŝlosi ĝin." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1452,34 +1510,34 @@ msgid "" "carefully before!" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart inkluzivas plurajn modojn de ludo:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Tempa Provo: Ne enhavas plifortigilojn, do sole via vetkurada kapableco gravas!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1487,7 +1545,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Sekvu la unuan: Penu ĉiam esti en la dua loko, ĉar ĉiun fojon kiam la tempumilo sonas, la lasta gokarto estos eliminita. Atentu: se vi preterpasus la unuan gokarton, vi ankaŭ estos eliminita." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1497,30 +1555,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Futbalo: Uzu vian gokarton por puŝi pilkon en la golejon." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Ova ĉasado: Esploru kurejojn por trovi ĉiujn kaŝitajn ovojn." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1529,93 +1587,93 @@ msgid "" "wins the cup." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Kiel helpo por venki haveblas plifortigiloj kiujn vi kolektu:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Maĉgumo - Protektas vin kun ŝildo, aŭ uzu ĝin vidante malantaŭen por lasi gluecaĵon post vi." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Malŝtopilo - ĵetu rekten por malantaŭtiri kontraŭulojn, aŭ ĵetu vidante malantaŭen por malebligi bonvidon de kontraŭulo." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Paraŝuto - malrapidigas ĉijn gokartojn en pli bona posicio." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Basketpilko - resaltas post la gvidisto kaj eble platigas kaj malrapidigas gokartojn survoje." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Se vi trafus bananon, unu el la jenaj povas alkroĉiĝi al via gokarto:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Ankro - tuj malrapidigas la gokarton." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1624,7 +1682,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1632,20 +1690,20 @@ msgid "" " the cup and the more points it is worth." msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1653,7 +1711,7 @@ msgid "" " resistant to explosions." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1661,7 +1719,7 @@ msgid "" " especially at low speeds." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1669,14 +1727,14 @@ msgid "" " top speed." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1684,12 +1742,12 @@ msgid "" "easier it is." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1699,7 +1757,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1709,12 +1767,12 @@ msgid "" "players and the server." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "aŭ sur la sama aparato:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1724,7 +1782,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1744,7 +1802,7 @@ msgstr "Rekorda elekto" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Rondira Provo" @@ -1752,9 +1810,9 @@ msgstr "Rondira Provo" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Granda Prezo" @@ -1765,6 +1823,20 @@ msgstr "Granda Prezo" msgid "Choose a Kart" msgstr "Elektu gokarton" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1778,11 +1850,11 @@ msgstr "Dividita-Ekrana Multludista" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Enreta" @@ -1799,7 +1871,7 @@ msgstr "Instruiloj" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Rekordoj" @@ -1807,7 +1879,7 @@ msgstr "Rekordoj" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Atingoj" @@ -1861,30 +1933,30 @@ msgstr "Trovi servilon" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Krei servilon" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Lobio" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Agordaro" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Komencu kuron" @@ -1910,9 +1982,9 @@ msgstr "Enigu servilan adreson" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Via profilo" @@ -1930,7 +2002,7 @@ msgstr "Ludantaj rangoj" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Amikoj" @@ -1955,7 +2027,7 @@ msgstr "Tuja ludo" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Kontaj agordoj" @@ -2005,8 +2077,8 @@ msgid "Online Username" msgstr "Reta Uzantnomo" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Rekomencigi pasvorto" @@ -2019,7 +2091,7 @@ msgid "" msgstr "" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Servila elekto" @@ -2037,339 +2109,409 @@ msgstr "Uzu IPv6 retkonekto" msgid "User search" msgstr "Uzantoserĉo" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "SuperTuxKart agordoj" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Grafikaĵoj" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Sonoj" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Aspekto" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Ludantoj" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Stiriloj" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Lingvo" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Muziko" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Enŝaltita" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Laŭteco" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Sonaj efektoj" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Forigi agordaron" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Malŝalti agordaron" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Reen al listo de aparatoj" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Alinomi agordaron" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Ekrandistingivo" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Plenekrane" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Memori fenestrolokon" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Apliki novan ekrandistingivon" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Dividita-Ekrana Multludista aranĝo" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Interretaj agordoj" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Ĉiam montru ensalutilon" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Konektu kun la interreto" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Ŝalti enretan babiladon" +msgid "Enable chatting in online lobbies" +msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Ŝaltu babiladon en retaj ludoj" +msgid "Enable chatting in online matches" +msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Diversaj agordoj" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Enŝaltu perludistajn handikapojn" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Malinstali ĉiujn valoraĵojn de la ludo" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Premu 'akcepti' aŭ dufoje klaku al via stirilo por agordi ĝin" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Aldoni stirilojn" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Kiun agordon por uzi estas implikita de kiu 'elekti' klavo estas premita por aniĝi la ludon." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Aspektoj" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Miniatura carto" +msgid "Skin variant" +msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Dividita-Ekrana Multludista aranĝo" +msgid "Minimap" +msgstr "Miniatura carto" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Tipara grando" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Kamerao" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Adaptita..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Montri KES (kadroj en sekundo)" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Montri tenita plifortigiloj de aliaj gokartoj" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Nivelo de grafikaj efektoj" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Maksimuma KES" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Propraj agordoj..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Ekrandistingivo" +msgid "Performance tests" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Plenekrane" +msgid "Performance test of the current settings" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Memori fenestrolokon" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Memoru pasvorton" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Apliki novan ekrandistingivon" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Forigi" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Gokarta koloro" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2396,15 +2538,15 @@ msgstr "Blua teamo" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Nombro da rondiroj" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Nombro de la AI gokartoj" @@ -2419,33 +2561,17 @@ msgstr "" msgid "Random Grand Prix" msgstr "Ajna Granda Prezo" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Ensaluti" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Memoru pasvorton" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Forigi" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Gokarta koloro" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "" @@ -2564,238 +2690,306 @@ msgid "" msgstr "" #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumulo" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emulo" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavrulo" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnuo" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hekslej" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konkvi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" -msgstr "Nolok'" +msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Piĝino" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Pufi" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepero" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Saro" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanjo" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tukso" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Vilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Iksue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Antaŭdiluva Abismo" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Fremda Signalo" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Antikva Kolosea Labirinto" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Kalaĵo Krucigo" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Batalinsulo" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Nigra Arbaro" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Groto Ikso" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Kakaotemplo" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Kalaĵo Krucigo" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Magma kastelo" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Grandparadiza insulo" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Bieno" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Glacia Piedpilkejo" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Kio malbonas, etaj hipioj? Via bonega gnuestro mankas?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Ho jes, vidu, li estas en mia kastelo nun kaj estos noktomanĝo ..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Sed mi estas justa kreaturo, do mi proponas negocion." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Se vi povas superi min en vetkuro, mi liberiĝos vian maljunulon." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "Sed vi ridindaj uloj neniam kapablos superi min - Reĝon de la gokartoj!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Ĉirkaŭ la lumdomon" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Malnova minejo" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolfo" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oazo" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Matematikklaso de Oliver" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Kukurba Parko" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Movanta sablo" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Lageto Neso" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Norda parko" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Neĝa pinto" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Piedpilkejo" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "La stadio" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Kosmoveturilo" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Templo" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Vulkana insulo" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Zena ĵardeno" @@ -2804,11 +2998,11 @@ msgstr "Zena ĵardeno" msgid "Completed achievement \"%s\"." msgstr "Kompletis atingon \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "" -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Eraro elŝutante novaĵojn: '%s'." @@ -2874,7 +3068,7 @@ msgid "New kart '%s' now available" msgstr "Nova gokarto '%s' nun haveblas" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2906,32 +3100,32 @@ msgid "" "created." msgstr "Via agorddosiero estis tro malnova, do ĝi estis forigita kaj nova estos kreita." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Videoa registrado komencis." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Videaĵo konservita al \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Kodanta pregreso:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Konsileto: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Ŝarĝanta" @@ -2953,19 +3147,18 @@ msgstr "Nitroa rendimento" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (handikapite)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s pretas" @@ -3439,21 +3632,21 @@ msgid "Axis %d" msgstr "Akso %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Ludila butono %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Musbutono %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Musakso %d %s" @@ -3625,26 +3818,30 @@ msgstr "Vi povas havi plejen 3 vivojn!" msgid "+1 life." msgstr "+1 vivo." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Vi estis tro lantan!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Vi venkis la vetkuron!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Vi finis la vetkuron en rango %d!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s foriris la ludon." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3653,16 +3850,16 @@ msgid "" "Internet\")." msgstr "" -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "" -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Via peliloversio tro malnovas. Bonvole instalu plej lastajn videopelilojn." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3670,38 +3867,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "" -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Servila retkonekto tempolimitan." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s havas la ruĝan flagon!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "La ruĝa flago estas revenigita." #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s havas la bluan flagon!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "La blua flago estas revenigita." -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s kaptis la bluan flagon!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s kaptis la ruĝan flagon!" @@ -3711,7 +3908,7 @@ msgstr "%s kaptis la ruĝan flagon!" msgid "Eggs: %d / %d" msgstr "Ovoj: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Estro" @@ -3719,22 +3916,22 @@ msgstr "Estro" msgid "Final lap!" msgstr "Fina rondiro!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Rondiro %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s de %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Nova plej rapida rondiro" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "MALĜUSTA DIREKTO!" @@ -3748,194 +3945,194 @@ msgstr "%s poentis golon!" msgid "Oops, %s made an own goal!" msgstr "Ups, %s faris memgolon!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "" msgstr[1] "" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Vi estis eliminita!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "'%s' estis eliminita" -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Servilo estis malŝaltita." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Vi estis elĵetita de la servilo." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "" -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Malbona retkonekto estas detekita." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Roboto" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s elkonektita." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "" #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Facileco: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Maksimume ludantoj: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Luda modo: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Tempolimo" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Gollimo" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Piedpilka luda tipo: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Ĉiuj ludantoj aliĝis ruĝan aŭ bluan teamon." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Vi estas nun la propulo de la servilo." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Retkonekto rifuzis: Servilo estas okupita." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Retkonekto rifuzis: Vi estas malpermisita de la servilo." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Retkonekto rifuzis: Servila pasvorto estas malĝusta." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "" -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Retkonekto rifuzis: Servilo estas tro plena." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "" -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "" #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "" #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "" #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "" -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Servila propulo forlasis la ludon." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "" #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s aliĝis la ruĝan teamon." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s aliĝis la bluan teamon." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s aliĝis la ludon." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3943,15 +4140,15 @@ msgid "" msgstr "Premu <%s> aŭ <%s> por ŝanĝi spektatan ludanton, <%s> aŭ <%s> por la kameraa pozicio." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "Sukcese raportis %s." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3982,38 +4179,38 @@ msgstr "Tempa Provo (Granda Prezo)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Libera por ĉiuj" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Kapti La Flagon" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s enretas nun." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s kaj %s enretas nun." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s kaj %s enretas nun." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4021,19 +4218,19 @@ msgstr[0] "%d amiko nun enretas." msgstr[1] "%d amikoj nun enretas." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s nun estas ĉe servilo \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "Vi havas %d novan amikpeton!" msgstr[1] "Vi havas %d novajn amikpetojn!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Vi havas novan amikpeton!" @@ -4062,12 +4259,12 @@ msgid "" msgstr "La rekorddosiero estis tro malnova,\nĈiuj rekordoj estis forigitaj." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Sekvu la estron" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "3 Frapaj Batalo" @@ -4080,91 +4277,88 @@ msgstr "Nekompleta ripetludodosiero ne estos konservita." msgid "Replay saved in \"%s\"." msgstr "Ripetludo konservita en \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 semajno" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 semajnoj" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 monato" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 monatoj" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 monatoj" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 monatoj" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 jaro" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 jaroj" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Nomo de aldonaĵo" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Ĝisdatigita dato" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Ne instalita" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s de %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Bonvole atendu dum aldonaĵoj estas ĝisdatigitaj" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Pardonu, eraro okazis dum kontakti l aldonaĵpaĝon. Certigu ke vi estas konektita al interreto kaj ke SuperTuxKart ne estas haltigita de fajromuro" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Ŝlosita : Solvu aktivajn konkursojn por ricevi akiron por tio!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Ajna areno" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d areno ne haveblas en solludista modo." -msgstr[1] "%d arenoj ne haveblas en solludista modo." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nHendur Saga, 2020\nLagash, 2022\nJakub Fabijan, 2021\nJonas Marx, 2017\nJorge Maldonado Ventura, 2021\nKevin G, 2021\nNicolas G, 2022\nRachel Singh, 2018\nRobin van der Vliet, 2015\nStefan R. Grotz, 2019\nЛюбомир Василев, 2016\nЛюбомир Василев, 2016-2017\nRubén\nSTK-team\nÉfrit" @@ -4452,7 +4646,7 @@ msgstr "Kolektitaj bananoj" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Gliti" @@ -4555,7 +4749,7 @@ msgstr "Ovoĉasadoj finitaj" msgid " (official tracks matching the goal)" msgstr "" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4563,91 +4757,95 @@ msgid "" msgstr "" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Aldoni Viilon" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Aldoni klavarilan agordon" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Ĝisdatigi" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Versio: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "Prezentita" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Grandeco: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Pardonu, elŝuti la aldonaĵon eraris" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Problemoj instali la aldonaĵon '%s'." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Reprovu" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Problemoj forigi la aldonaĵon '%s'." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Fona elŝutaĵo finis." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Fona elŝuti" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Nuntempa pasvorto malĝustas." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Pasvorto estu inter 8 kaj 30 literoj!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Pasvorto ne kongruas!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Validante informon" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Pasvorto sukcese ŝanĝita." @@ -4668,67 +4866,97 @@ msgstr "" #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Propra" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Malŝaltita" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Grava sole" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Malaltega" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Malalta" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Meza" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Alta" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4736,7 +4964,7 @@ msgid "" msgstr "" #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4753,101 +4981,102 @@ msgstr "" msgid "Invalid server address: %s." msgstr "Malvalida servila adreso: %s" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Malfacilaĵo" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Rondiroj" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Tempo" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Gokarto" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Usanto" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Versio" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Ne" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Kurejo" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Plej Bona %d Rekordoj" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Nombro da gokartoj: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Tempa celo: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Rondiroj: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Malplena)" @@ -4935,33 +5164,41 @@ msgid "Press any key..." msgstr "Entajpi ajn klavo..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Reveni al batalo" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Restarti Batalon" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Foriri batalon" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Aranĝu novan vetkuton" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Eliri vetkuron" @@ -4977,11 +5214,11 @@ msgstr "%s ne havas rangon ankoraŭ." msgid "%s is number %d in the rankings with a score of %f." msgstr "" -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Uzantnomo kaj/aŭ retadreso estas malvalida." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5003,7 +5240,7 @@ msgstr "Fantoma ripetludvetkuro" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Rondiroj: %i" @@ -5016,21 +5253,21 @@ msgstr "Tipo: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Necesa rango: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Necesa tempo: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Necesaj Nitroo poentoj: %i" @@ -5043,54 +5280,54 @@ msgstr "Nombro de AI gokartoj: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Batala modo" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Piedpilka luda tipo" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Servila loko: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Nuna kurejo: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Rango" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Ludanto" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Poentoj" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Tempo ludita" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "" @@ -5103,74 +5340,74 @@ msgid "No player available for connecting to server." msgstr "" #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Uzantnomo: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Nuligi peton" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Hodiaŭ" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Amikiĝpeto sendita!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Amikiĝpeto akceptita!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Amikiĝpeto malakceptita!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Amiko forigita!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Amikiĝpeto nuligita!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Traktante" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Venigi lastan voĉdono" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Vi povas adapti vian antaŭan taksadon klikante suban stelon." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Vi ankoraŭ ne voĉdonis por ĉi tiu aldonaĵo. Elektu vian dezititan taksadon klikante la suban stelon" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Voĉdono sukcesis! Vi povas malfermi fenestron nun." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Farante voĉdonon" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Ajna kurejo" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5199,7 +5436,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Eraro okazis provante konservi vian Grandan Prezon." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Elektu kurejon" @@ -5243,12 +5480,12 @@ msgstr "Vi malŝlosis la kurejon %0" msgid "You unlocked grand prix %0" msgstr "Vi liberigis Grandan Prezon %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Kurejo" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5269,19 +5506,19 @@ msgstr "Bonvole entajpu la nomon de la Granda Prezo" msgid "Please select a Grand Prix" msgstr "Bonvole elektu Grandan Prezon" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Uzante definita" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Nomo malplenas." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Plia Granda Prezo kun sama nomo jam ekzistas." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Tro longa nomo." @@ -5290,19 +5527,19 @@ msgstr "Tro longa nomo." msgid "Better luck next time!" msgstr "Plibonan sorton venontfoje!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Vi kompletigis la konkurson!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Vi gajnis la Grandan Premion!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Vi kompletigis la Grandan Prezon" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Nombro de la gokartoj" @@ -5315,110 +5552,125 @@ msgstr "" msgid "Are you sure you want to remove all of your high scores?" msgstr "" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Ajnan gokarton" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Ŝlosita" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Ĉiu:\nPremu la 'Elekti' butonon por aniĝi la ludon" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "" -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "La aldonaĵoj-modulo nuntempe estas malŝaltita en la agordoj" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Bonvole atentu dum la aldonaĵoj estas ŝarĝantaj" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Ĉu vi certe volas eliri STK -on?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Kreu LAN servilon" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Servilo de %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Nombro da granda(j)n preza(j)n kurejo(j)n" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Nomo estu longa inter 4 kaj 30 literoj!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Preta" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Spektantu" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Instalu aldonaĵon" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5426,7 +5678,7 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "" @@ -5434,24 +5686,24 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "" -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5460,7 +5712,7 @@ msgstr[1] "" #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5469,96 +5721,108 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Konektanta al servilo %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Restanta tempo: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Goloj" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Venigante atingojn" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Profilo de %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Ekde" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Statuso" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Venigante amikojn" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Nova peto" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Pritraktata" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Malenreta" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Enigu novan retadreson piede" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Nova retadreso estas malvalida!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "Retadreso estas ŝanĝita!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "" -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Serĉante" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Foriri ludon" @@ -5636,34 +5900,34 @@ msgid "Distance (km)" msgstr "Distanco (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Obskura" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "" #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "" -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Neniu servilo estas disponebla." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Venigante servilojn" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Servilaj Legosignoj" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5671,149 +5935,149 @@ msgstr "" #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Ajna objektloko" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Nombro de goaloj por venki" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Veturu inverse" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Ŝlosita: kompletigu defiojn por ricevi aliron al pliaj!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Ago" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Klavligo" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Malvalidigi Stirilon" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Validigi Stirilon" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Ludklavoj" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Klavoj de menuo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Stiru liven" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Stiru dekstren" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Plirapidigi" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Pafi" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Vidi malantaŭen" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Savi" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Paŭzi ludon" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Supren" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Suben" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Liva" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Dekstra" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Elekti" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Rezigni/Reen" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "Blua objekto signifas konflikton inter alia agordaĵo" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "Ruĝa objekto signifas konflikton inter nuntempa agordaĵo" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5821,17 +6085,27 @@ msgid "" msgstr "Atento: La 'ŝovi' ne estas rekomendita klabvo. Kiam 'ŝovi' estas premita, ĉiuj aliaj klavoj kun alia signifo en grandlitera modo ĉesas labori." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Ĉu vi certas, ke vi volas forigi daŭre ĉi tiun agordon?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "" +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Vertikala" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Horizontala" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5839,89 +6113,74 @@ msgstr "" #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Klavaro %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Sistema lingvo" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Kaŝitaj" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Centra" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Vertikala" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Horizontala" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Tre malgranda" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Malgranda" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Meza" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Granda" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Tre granda" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5931,128 +6190,133 @@ msgid "" msgstr "" #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "" #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Animitaj karakteroj: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Dinamikaj lumoj: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Glatigo: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Ĉirkaŭa kaŝadefekto: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Ombroj: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Ombroj: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Bloomfiltrilo: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Brilo (siluetoj): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Lumŝafto (diaj radioj): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Mova filtro: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Profundeco de kampo: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Vi devas entajpi pasvorton" -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Elsaluti '%s'" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Ensaluti '%s'" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "" #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "" @@ -6080,7 +6344,7 @@ msgstr "GOLO!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Atentas aliulojn" @@ -6115,7 +6379,7 @@ msgstr "Sekvu la estron!" msgid "Top %i" msgstr "Supraj %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Konkurso malsukcesis" @@ -6139,102 +6403,199 @@ msgstr "" msgid "Press fire to start the challenge" msgstr "Premu 'pafi' komenci la konkurson" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Eliri el la servilo" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Ĉesigu Grandan Prezon" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Restarti" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Reen al konkursa elektado" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Reen al la menuo" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Ĉu vi vere volas ĉesigi la Grandan Prezon?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Ruĝa teamo venkas" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Blua teamo venkas" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Egalvenko" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Eliminita poste %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Eliminita" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Memgolo)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Kurejo %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Grandpreza progreso:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Rekordoj" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Plej rapida rondiro: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "de %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Vi finis la konkurson!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Vi malsukcesis la konkurson!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Ĉio permesita, do atingu armilojn kaj lerte uzu ilin!" @@ -6275,28 +6636,28 @@ msgstr "" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Kurejo de %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Maksimumaj ludistoj subtenitaj: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Nombro da ruĝaj robot-ludantoj" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Ŝlosita!" @@ -6318,10 +6679,12 @@ msgid "%d/%m/%Y" msgstr "%d.%m.%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Kompletigu ĉiujn konkursojn por malŝlosi la grandan pordon!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6330,41 +6693,48 @@ msgid "" msgstr "Vi bezonas pliajn poentojn\npor aniĝi la konkurson!\nKontrolu minimapon por\nludeblaj konkursoj." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "akceli kun <%s>, kaj stiru kun <%s> kaj <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Kolektu donacajn ujojn kaj pafu armilojn kun <%s> por forigi tiujn ujojn!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6372,34 +6742,41 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Uzu la nitron kiun ki kolektis presante <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Kolektu nitron botelojn (ni uzos ilin post la kurvo)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Ups! Kiam vi havos malfacilaĵojn, premu <%s> por esti savita." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6407,24 +6784,27 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Memoru se vi sukcesas gliti por kelkaj sekundoj, vi ricevos bonusan rapidigon kiel premio!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Vi pretas nun por vetkuri. Sukceson!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "3D-a malfermitkoda karta vetkurad-ludo" @@ -6434,7 +6814,7 @@ msgstr "3D-a malfermitkoda karta vetkurad-ludo" msgid "tux;game;race;" msgstr "tukso;ludo;vetkuro;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6442,7 +6822,7 @@ msgid "" "for all ages." msgstr "" -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6451,7 +6831,7 @@ msgid "" "your opponents." msgstr "" -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6460,27 +6840,27 @@ msgid "" "your racing skills!" msgstr "" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Ĉi tiu ludo ne enhavas reklamojn." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "" -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "" -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "SuperTuxKart Teamo" diff --git a/data/po/es.po b/data/po/es.po index 3fc68fbd2d7..3e10d92fd00 100644 --- a/data/po/es.po +++ b/data/po/es.po @@ -5,10 +5,10 @@ # Translators: # Benau, 2018 # Benau, 2018,2024 -# Marc Coll Carrillo , 2015-2023 +# Marc Coll Carrillo , 2015-2024 # MxtApps , 2022 # MxtApps , 2022 -# Tagomago , 2020-2021,2023 +# Tagomago , 2020-2021,2023-2024 # Verónica Clémençon, 2017 # Verónica Clémençon, 2017 # William Beltrán , 2016 @@ -17,9 +17,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Benau, 2018,2024\n" +"Last-Translator: Marc Coll Carrillo , 2015-2024\n" "Language-Team: Spanish (http://app.transifex.com/supertuxkart/supertuxkart/language/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -176,7 +176,7 @@ msgstr "En el fin del mundo" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Volver" @@ -198,7 +198,7 @@ msgstr "Selecciona el tipo de controlador que prefieras." #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Acelerómetro" @@ -212,13 +212,13 @@ msgstr "Acelerómetro" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Giroscopio" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Volante" @@ -249,35 +249,37 @@ msgstr "Configuración del dispositivo táctil" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "General" @@ -345,30 +347,33 @@ msgstr "Restaurar coniguración por defecto" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Cancelar" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Sí" @@ -546,9 +551,9 @@ msgstr "Unirse" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -609,7 +614,7 @@ msgstr "Objectivo" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Progreso" @@ -644,7 +649,7 @@ msgstr "Enviar" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Volver a la carrera" @@ -661,7 +666,7 @@ msgstr "Volver al vestíbulo" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Reiniciar la carrera" @@ -725,12 +730,12 @@ msgstr "Introduce el nombre de usuario y la dirección de correo electrónico qu #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Nombre de usuario" @@ -771,7 +776,7 @@ msgstr "Dificultad" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Principiante" @@ -783,7 +788,7 @@ msgstr "Principiante" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Intermedio" @@ -795,7 +800,7 @@ msgstr "Intermedio" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Experto" @@ -807,7 +812,7 @@ msgstr "Experto" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -815,8 +820,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Modo de juego" @@ -827,8 +832,8 @@ msgstr "Modo de juego" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Carrera normal" @@ -841,7 +846,7 @@ msgstr "Carrera normal" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Contrarreloj" @@ -849,7 +854,8 @@ msgstr "Contrarreloj" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Batalla" @@ -858,24 +864,24 @@ msgstr "Batalla" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Fútbol" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Contraseña" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Añadir este servidor a favoritos" @@ -886,7 +892,7 @@ msgstr "Añadir jugador" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Nombre" @@ -980,6 +986,50 @@ msgstr "Asignar a la tecla ESC" msgid "Assign nothing" msgstr "No asignes nada" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Recomiéndame la configuración de vídeo" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "La configuración recomendada será válida para la resolución actual" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "¿Qué debería priorizar la configuración?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Rendimiento" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Equilibrio entre rendimiento y calidad gráfica" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Calidad gráfica" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Ahorro de energía" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "¿Te gustan los efectos gráficos que provocan difuminación?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Empezar el test" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -994,11 +1044,11 @@ msgstr "Configuración de la carrera" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Continuar" @@ -1039,10 +1089,15 @@ msgstr "Arenas" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Instalado" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Editar las arenas favoritas" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1052,20 +1107,20 @@ msgstr "Instalado" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Estándar" @@ -1076,12 +1131,12 @@ msgstr "Estándar" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Complementos" @@ -1095,27 +1150,28 @@ msgstr "Complementos" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Todos" @@ -1154,9 +1210,9 @@ msgstr "Mover hacia abajo" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Añadir" @@ -1193,7 +1249,7 @@ msgstr "Selección de repetición fantasma" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "En busca de los huevos perdidos" @@ -1240,10 +1296,10 @@ msgstr "Al revés" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Tiempo máximo (min.)" @@ -1275,9 +1331,9 @@ msgstr "Copiar" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1288,80 +1344,80 @@ msgstr "Renombrar" msgid "Save Grand Prix" msgstr "Guardar el campeonato" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Ayuda de SupertuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Modos de juego" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Mejoras" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Plátanos" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1369,56 +1425,57 @@ msgstr "Plátanos" msgid "Story Mode" msgstr "Historia" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Clases de karts" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Multijugador" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Empezar el tutorial" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Recoge las cajas azules, te darán mejoras." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "¡Evita los plátanos!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1426,14 +1483,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Recoger nitros te permite alcanzar mayor velocidad cuando quieras pulsando la tecla o botón correspondiente. Puedes ver tu nivel actual de nitro en el indicador situado en la parte inferior derecha de la pantalla de juego." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Si ves un botón con un candado como este, necesitas completar un reto para desbloquearlo." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1442,34 +1499,34 @@ msgid "" "carefully before!" msgstr "Puedes derrapar pulsando una tecla o botón especial. Los derrapes cortos y seguidos te ayudan a coger curvas cerradas. Los medios aumentan tu velocidad, y los largos más aún. No puedes dejar de girar cuando derrapas, ¡así que orienta bien tu kart antes!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Puedes obtener una mejora en el arranque pulsando el botón de acelerar en el \"¡Listos!\", antes de empezar la carrera." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* La asignación de teclas actual puede verse/cambiarse en el menú Opciones." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart tiene diferentes modos de juego:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Carrera normal: ¡Todo está permitido, así que coge mejoras y haz buen uso de ellas!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Contrarreloj: no hay mejoras, así que ¡sólo importa tu habilidad al volante!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1477,7 +1534,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Sigue al líder: Corre por el segundo puesto, ya que el último kart será descalificado cada vez que el contador llegue a cero. Cuidado: ¡si vas por delante del líder también serás eliminado!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1487,30 +1544,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Hay tres tipos de modos de batalla: En la batalla a 3 golpes debes atacar a los demás con armas hasta que pierdan todas su vidas. En la batalla por libre, el jugador que golpee más a los demás ganará una vez se alcance un cierto objectivo o límite de tiempo. En el modo de capturar la bandera, tu equipo debe traer la bandera del otro equipo a vuestra base, siempre que vuestra bandera no haya sido capturada por el otro equipo." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Fútbol: Usa tu kart para empujar la pelota dentro de la portería." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "En busca de los huevos perdidos: Explora circuitos para encontrar todos los huevos escondidos." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Repetición fantasma: Corre contra repeticiones fantasma en modo contrarreloj o búsqueda de los huevos perdidos, ¡y graba el tuyo propio!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Competición de vueltas: Completa tantas vueltas como sea posible en un tiempo determinado." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1519,93 +1576,93 @@ msgid "" "wins the cup." msgstr "* La mayoría de estos modos de juego pueden jugarse como un campeonato: en vez de jugar una sola carrera, juegas varias consecutivamente. Cuanto mejor sea tu posición, más puntos obtendrás. Al final, el jugador con más puntos ganará la copa." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Para ayudarte a ganar, hay ciertas mejoras que puedes recoger:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Chicle - protégete con un escudo, o úsalo mientras miras hacia atrás para dejar una mancha rosa y pegadiza detrás de ti." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Turbo - te dará un gran incremento de velocidad. ¡Pero procura no perdrer el control del tu kart!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Pastel - lanzado contra el rival más próximo, mejor a poca distància i en rectas largas. También afecta a otros karts cerca de la explosión." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Desatascador - lánzalo hacia adelante para tirar de un oponente hacia atrás, o lánzalo mientras miras hacia atrás para que pierda visión." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Bola de bolos - va recto hasta que se topa topa con algo, rebota en las paredes. Si estás mirando atrás, la bola se lanzará hacia atrás." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Paracaídas - frena a todos los karts mejor posicionados" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Intercambiador - las cajas se transforman en plátanos, las botellas de nitro en chicles, y viceversa por un corto periodo de tiempo." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Pelota de baloncesto - rebota tras el líder, y puede aplastar y frenar karts por el camino." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Matamoscas - aplastará a los karts a su alrededor, frenándolos. También se puede usar para eliminar paracaídas i bombas." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Coger un plátano puede provocar que una de las sigüientes cosas se te pegue al kart:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Ancla - frena el kart de golpe." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Paracaídas - frena el kart de forma más progresiva que el ancla. Cuanto más rápdio vas, más te frena." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bomba - detona al cabo de un tiempo, lanzando al kart por los aires. Choca con otro kart para pasarle la bomba." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "¡El malvado Nolok ha capturado a Gnu! Aquí tienes algunos consejos para ayudarte:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1614,7 +1671,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Este icono en el mapa en miniatura muestra los retos disponibles que aún no has completado. En la parte superior derecha de la pantalla también te dice cuantos puntos tienes actualmente. Completa tantos retos como sea posible, y Nolok aceptará competir contra ti. ¡Gana para liberar a Gnu!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1622,20 +1679,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Cuando completas un reto, rcibes una copa. Cada copa vale varios puntos. Cuanto más difícil sea el reto que hayas completado, mejor será la copa y más puntos valdrá." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Cuando obtengas el número de puntos indicado debajo de este icono, recibirás un regalo sorpresa. Hay varios para recoger." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "¡No todos los karts se conducen igual! Pertenecen a clases con varias diferencias:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1643,7 +1700,7 @@ msgid "" " resistant to explosions." msgstr "Masa - hay tres clases de kart, dependiendo de su masa: ligero, medio y pesado. A los karts más pesados no les afectan tanto los paracaídas, y son más resistentes a las explosiones." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1651,7 +1708,7 @@ msgid "" " especially at low speeds." msgstr "Aceleración: especialmente útil en el inicio, después de un accidente o en circuitos con muchas curvas cerradas. Cuanto más ligero sea el kart, más rápdio acelerará, especialmente a baja velocidad." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1659,14 +1716,14 @@ msgid "" " top speed." msgstr "Velocidad máxima: cuanto más alta sea, más rápido puede ir el kart. Especialmente útil en circuitos con muchas rectas y curvas suaves. Los karts más pesados tienen una velocidad punta más alta." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Eficiencia de nitro: cuanto más alta sea, más velocidad podrás obtener de una botella de nitro. Cuanto más ligero sea el kart, mayor será su eficiencia de nitro." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1674,12 +1731,12 @@ msgid "" "easier it is." msgstr "Si sigues de cerca a otro kart durante unos segundos, obtendrás un extra de velocidad de rebufo cuando lo adelantes. Cuanto más ligero sea el kart, más fácil es." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart se puede jugar en modo multijugador en línea...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1689,7 +1746,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Primero, selecciona el icono 'en línea' del menú principal. Elige o bien red local, o bien global (es necesario tener activado el acceso a Internet en las opciones). Después, puedes o bien crear tu propio servidor con opciones a medida, o bien buscar entre la lista de servidores existentes para unirte. Algunos de ellos son servidores recomendados con carreras opcionales con classificaciones." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1699,12 +1756,12 @@ msgid "" "players and the server." msgstr "Una vez estés en un servidor, una carrera comenzará en cuanto su propietario (simbolitzado con la corona) lo decida. Los servidores oficiales pueden comenzar carreras automáticamente sólo cuando haya suficientes jugadores. Entonces, podrás elegir tu kart i votar por el próximo circuito donde correr. Un un circuito de complemento sólo se permite si existe en todos los jugadores que se han unido y en el servidor." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... o en el mismo dispositivo:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1714,7 +1771,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Primero, necesitarás varios dispositivos de entrada. Usa la pantalla de configuración de dispositivos de entrada para configurarlos. Tener múltiples mandos o joysticks es lo ideal: en los teclados cada jugador necesitará un conjunto diferente de teclas, y la mayoría de teclados no son apropiados para un juego multijugador, ya que no permiten pulsar muchas teclas a la vez." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1734,7 +1791,7 @@ msgstr "Selección de mejores puntuaciones" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Competición de vueltas" @@ -1742,9 +1799,9 @@ msgstr "Competición de vueltas" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Campeonatos" @@ -1755,6 +1812,20 @@ msgstr "Campeonatos" msgid "Choose a Kart" msgstr "Elige un kart" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Clase de kart" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Editar los karts favoritos" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1768,11 +1839,11 @@ msgstr "Multijugador en pantalla dividida" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Conectado" @@ -1789,7 +1860,7 @@ msgstr "Tutorial" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Mejores puntuaciones" @@ -1797,7 +1868,7 @@ msgstr "Mejores puntuaciones" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Logros" @@ -1851,30 +1922,30 @@ msgstr "Encontrar servidor" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Crear servidor" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Vestíbulo" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Configuración" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Empezar carrera" @@ -1900,9 +1971,9 @@ msgstr "Introduce la dirección del servidor" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Tu perfil" @@ -1920,7 +1991,7 @@ msgstr "Clasificaciones de los jugadores" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Amigos" @@ -1945,7 +2016,7 @@ msgstr "Partida rápida" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Configuración de la cuenta" @@ -1995,8 +2066,8 @@ msgid "Online Username" msgstr "Nombre de usuario en línea" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Reinicia la contraseña" @@ -2009,7 +2080,7 @@ msgid "" msgstr "Puedes jugar sin crear una cuenta de usuario en línea seleccionando una cuenta de usuario fuera de línea. Pero entonces no podrás conectar con amigos, votar complementos, etc. Por favor, lee nuestra declaración de privacidad en https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Selección del servidor" @@ -2027,339 +2098,409 @@ msgstr "Utilizar conexión IPv6" msgid "User search" msgstr "Buscar usuarios" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Opciones de SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Pantalla" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Gráficos" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Sonido" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Interfaz" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Jugadores" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Controles" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Idioma" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Música" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Activado" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Volumen" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Efectos de sonido" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Eliminar configuración" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Desactiva la configuración" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Volver a la lista de dispositivos" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Renombra la configuración" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Activar la retroalimentación de fuerza (si está soportada)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Resolución" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Pantalla completa" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Recordar la posición de la ventana" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Aplicar la nueva resolución" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Disposición de la pantalla dividida" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Opciones de Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Mostrar siempre la pantalla de inicio de sesión" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Conectarse a Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Activa el chat en línea" +msgid "Enable chatting in online lobbies" +msgstr "Activa el chat en el vestíbulo de las partidas por red" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" +msgid "Enable chatting in online matches" msgstr "Activa el chat en las partidas por red" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Opciones diversas" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Activa las limitaciones por jugador" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Desinstalar los recursos completos" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Pulsa intro o haz doble clic sobre un dispositivo para configurarlo" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Añadir un dispositivo" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* La configuración a usar dependerá de qué tecla 'Seleccionar' se pulse para unirse a la partida." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Apariencia" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Mapa en miniatura" +msgid "Skin variant" +msgstr "Variante de la apariencia" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Disposición de la pantalla dividida" +msgid "Minimap" +msgstr "Mapa en miniatura" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Tamaño de la fuente" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Cámara" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "A medida..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Mostrar FPS" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Muestra las mejoras de los otros karts" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Activa el temporizador del modo historia" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Activa el temporizador de speedrun" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Resolución del renderizado" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Nivel de efectos gráficos" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Nivel de difuminación" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "FPS Máximos" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Configuración personalizada..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Resolución" +msgid "Performance tests" +msgstr "Tests de rendimiento" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Pantalla completa" +msgid "Performance test of the current settings" +msgstr "Test de rendimiento de la configuración actual" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Recordar la posición de la ventana" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Recordar la contraseña" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Aplicar la nueva resolución" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Borrar" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Color del kart" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2386,15 +2527,15 @@ msgstr "Equipo Azul" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Número de vueltas" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Karts controlados por el ordenador" @@ -2409,33 +2550,17 @@ msgstr "Número de karts azules controlados por el ordenador" msgid "Random Grand Prix" msgstr "Campeonato aleatorio" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Editar los circuitos favoritos" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Iniciar sesión" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Recordar la contraseña" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Borrar" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Color del kart" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "La apariencia de la interfaz de usuario se puede cambiar desde las opciones de interfaz de usuario." @@ -2554,238 +2679,306 @@ msgid "" msgstr "No entorpezcas a un compañero de equipo que tenga la pelota, aunque puedes intentar golpear a los oponentes que intenten impedir que marque gol." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Abismo antediluviano" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Señal alienígena" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "El laberinto del antiguo Coliseo" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Candela City" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Isla de batalla" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Selva negra" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Cueva X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Templo del cacao" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Campo de maíz" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Fort Magma" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Isla Gran Paradiso" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Caída por el agujero" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Campo de fútbol helado" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "¿Qué pasa, pequeños hippies? ¿Vuestro gran líder Gnu ha desaparecido?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "¡Oh, sí! Ahora está en mi castillo, y será servido como cena..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Pero soy una criatura justa, así que os ofreceré un trato." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Si podéis ganarme en una carrera, soltaré al vejestorio." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " ¡Pero nunca podréis vencerme, patéticos idiotas, porque yo soy el rey de los karts!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Arena Las Dunas" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Estadio de fútbol Las Dunas" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Alrededor del faro" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "La vieja mina" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oasis" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Clase de mates de Oliver" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Parque de las calabazas" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Mansión Ravenbridge" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Arenas movedizas" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "El estanque de Nessie" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Resort nórdico" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Pico nevado" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Campo de fútbol" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "El estadio" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Enterprise" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Templo" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Isla volcánica" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Jardín zen" @@ -2794,11 +2987,11 @@ msgstr "Jardín zen" msgid "Completed achievement \"%s\"." msgstr "Has completado el logro \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "No se ha podido conectar al servidor de complementos de SuperTuxKart." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Error descargando noticias: '%s'." @@ -2864,7 +3057,7 @@ msgid "New kart '%s' now available" msgstr "Nuevo kart '%s' ahora disponible" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2896,32 +3089,32 @@ msgid "" "created." msgstr "Tu fichero de configuración era demasiado antiguo, así que ha sido borrado y uno nuevo será creado." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Grabación de vídeo iniciada." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Vídeo guardado en \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Progreso de la codificación:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Consejo: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Cargando" @@ -2943,19 +3136,18 @@ msgstr "Eficiencia de nitro" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (limitado)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s está listo" @@ -3429,21 +3621,21 @@ msgid "Axis %d" msgstr "Eje %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Botón del mando %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Botón del ratón %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Eje del ratón %d %s" @@ -3616,26 +3808,30 @@ msgstr "Como mucho puedes tener 3 vidas!" msgid "+1 life." msgstr "+1 vida." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "¡Has ido demasiado lento!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "¡Has finalizado la carrera!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "¡Has ganado la carrera!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "¡Has finalizado la carrera en %dª posición!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s ha abandonado la partida." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3644,16 +3840,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart puede conectarse a un servidor para descargar complementos y notificarte sobre actualizaciones. Lee nuestra declaración de privacidad en https://supertuxkart.net/Privacy. ¿Te gustaría habilitar esta característica? (Para cambiar este parámetro más adelante, ve a las opciones, selecciona la pestaña \"General\" y edita \"Conectarse a Internet\")." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "La resolución de tu pantalla es demasiado baja para ejecutar STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "La versión de tu controlador gráfico es demasiado antigua. Por favor, instala la última versión." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3661,38 +3857,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Tu controlador gráfico parece ser muy antiguo. Por favor, comprueba si hay una actualización disponible. SuperTuxKart recomienda un controlador que permita %s o mejor. El juego probablemente funcionará, pero en un modo gráfico reducido." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "La conexión con el servidor ha superado el tiempo de espera." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "¡%s tiene la bandera roja!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "¡La bandera roja ha vuelto!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "¡%s tiene la bandera azul!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "¡La bandera azul ha vuelto!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "¡%s ha capturado la bandera azul!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "¡%s ha capturado la bandera roja!" @@ -3702,7 +3898,7 @@ msgstr "¡%s ha capturado la bandera roja!" msgid "Eggs: %d / %d" msgstr "Huevos: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Líder" @@ -3710,22 +3906,22 @@ msgstr "Líder" msgid "Final lap!" msgstr "¡Última vuelta!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Vuelta %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s por %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Nueva vuelta rápida" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "¡DIRECCIÓN CONTRARIA!" @@ -3739,7 +3935,7 @@ msgstr "¡%s ha marcado un gol!" msgid "Oops, %s made an own goal!" msgstr "¡Ups, %s ha marcado un gol en propia puerta!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" @@ -3747,187 +3943,187 @@ msgstr[0] "Se ha engendrado %i kart de ruedas de recambio!" msgstr[1] "Se han engendrado %i karts de ruedas de recambio!" msgstr[2] "Se han engendrado %i karts de ruedas de recambio!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "¡Has sido eliminado!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "'%s' ha sido eliminado." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "El servidor ha sido cerrado." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Te han expulsado del servidor." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Te han expulsado. Tu ping era demasiado alto." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Se ha detectado una mala conexión de red." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s se ha desconectado." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Pulsa en el nombre del usuario de la lista para gestionar el jugador y ver información de su classificación." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Dificultad: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Máximos jugadores: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Modo de juego: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Límite de tiempo" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Límite de goles" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Tipo de partida de fútbol: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Progreso del campeonato: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Todos los jugadores se han unido al equipo rojo o azul." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Ahora eres el propietario del servidor." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Conexión rechazada: el servidor está ocupado." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Conexión rechazada: has sido expulsado del servidor." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Conexión rechazada: la contraseña del servidor es incorrecta." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Conexión rechazada: Los datos del juego son incompatibles." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Conexión rechazada: el servidor está lleno." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Conexión rechazada: se está conectando un jugador inválido." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "No se ha podido iniciar la partida en red." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "La partida ha terminado, ya no puedes unirte en directo ni observarla." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "No queda sitio en la arena - unirse en directo desactivado." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Sólo queda un jugador, volviendo al vestíbulo." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "El propietario del servidor ha abandonado la partida." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Estarás observando la próxima partida." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s se ha unido al equipo rojo." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s se ha unido al equipo azul." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s se ha unido a la partida." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3935,15 +4131,15 @@ msgid "" msgstr "Pulsa <%s> o <%s> para cambiar de jugador, <%s> o <%s> para cambiar la posición de la cámara." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "%sha sido reportado." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3974,38 +4170,38 @@ msgstr "Carrera contrarreloj (campeonato)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Por libre" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Capturar la bandera" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s está en línea." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s y %s están en línea." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s y %s están en línea." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4014,12 +4210,12 @@ msgstr[1] "%d amigos están en línea." msgstr[2] "%d amigos están en línea." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s ahora está en el servidor \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4027,7 +4223,7 @@ msgstr[0] "¡Tienes %d nueva petición de amistad!" msgstr[1] "¡Tienes %d nuevas peticiones de amistad!" msgstr[2] "¡Tienes %d nuevas peticiones de amistad!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "¡Tienes una nueva petición de amistad!" @@ -4056,12 +4252,12 @@ msgid "" msgstr "El archivo de máximas puntuaciones era demasiado antiguo,\ntodas las máximas puntuaciones han sido borradas." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Sigue al líder" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Batalla a 3 golpes" @@ -4074,92 +4270,88 @@ msgstr "No se guardará archivo de repetición incompleto." msgid "Replay saved in \"%s\"." msgstr "Repetición guardada en \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 semana" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 semanas" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 mes" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 meses" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 meses" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 meses" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 año" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 años" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Nombre del complemento" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Fecha de actualización" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "No instalado" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s por %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Espera mientras se cargan los complementos" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Ocurrió un error cuando se conectaba con la página de complementos. Asegúrate de que estás conectado a Internet y de que SuperTuxKart no está bloqueado por un cortafuegos" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Favoritos" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Bloqueado : ¡completa los retos activos para tener acceso a más!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Arena aleatoria" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d arena no disponible en modo de un jugador" -msgstr[1] "%d arenas no disponibles en modo de un jugador" -msgstr[2] "%d arenas no disponibles en modo de un jugador" - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nBenau, 2018\nMarc Coll Carrillo, 2015-2022\nMxtApps, 2022\nTagomago, 2020-2021\nVerónica Clémençon, 2017\nWilliam Beltrán, 2016\nWilliam Beltrán, 2016-2017\nMarc Coll Carrillo, 2015-2021\nWilliam Beltrán, 2017\nAdolfo Jayme\nAlejandro Pérez\nAlvaro Ortiz\nCaArRi\nDavid Ballesteros Mayo\nDawid Gan\nDiegoJ\nEduardo Battaglia\nEugenio M. Vigo\nFelipe Hommen\nJonay\nJose\nJosé Luis Bandala Pérez\nLeo Juszkiewicz\nLinuxNerdo\nLouis DC\nMarc Coll Carrillo\nMariano Agüero\nMorgan w c.\nSTK-team\nSimón Roca\nTae-Wong SEO\nVPablo\nelhoir\njuanman\nraven2286\nsimon\nzer berros\nÁngel" @@ -4447,7 +4639,7 @@ msgstr "Plátanos recogidos" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Derrapar" @@ -4550,7 +4742,7 @@ msgstr "Búsquedas de huevos acabadas" msgid " (official tracks matching the goal)" msgstr "(circuitos oficiales que encajan con el objetivo)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4558,91 +4750,95 @@ msgid "" msgstr "Nuevos mandos y joysticks aparecerán automáticamente en la lista cuando los conectes a este dispositivo.\n\nPara añadir una configuración de teclado, usa el botón de abajo, SIN EMBARGO ten en cuenta que la mayoría de los teclados sólo permiten pulsar simultáneamente un número limitado de teclas y por tanto son inadecuados para el modo multijugador. (Puedes, no obstante, conectar varios teclados a tu ordenador. Recuerda que en este caso cada uno seguirá necesitando distintas combinaciones de teclas)." #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Añadir Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Añadir configuración de teclado" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Actualizar" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Versión: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "Destacados" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Tamaño: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Debes iniciar sesión para puntuar este complemento" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "No se ha podido descargar el complemento" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Problemas instalando el complemento '%s'." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Inténtalo de nuevo" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Problemas eliminando el complemento '%s'." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Descarga en segundo plano completada." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Descarga en segundo plano" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "La descarga en segundo plano ya ha empezado." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "La contraseña actual no es válida." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "¡La contraseña debe tener entre 8 y 30 caracteres!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "¡Las contraseñas no coinciden!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Validando información" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Contraseña cambiada correctamente." @@ -4664,67 +4860,97 @@ msgstr "Las resoluciones más pequeñas de 1024x768 o 1280x720 no están soporta #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Seguimiento de dron" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Personalizada" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Desactivado" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Sólo lo importante" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Muy bajo" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Bajo" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Media" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Alto" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Muy alto" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4732,7 +4958,7 @@ msgid "" msgstr "SuperTuxKart descargará los recursos completos (incluídos texturas de alta calidad y música) para una mejor experiencia de juego. Esto usará tus datos móviles si no tienes una conexión wi fi." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4749,101 +4975,102 @@ msgstr "Introduce la dirección del servidor opcionalmente seguida de : y el pue msgid "Invalid server address: %s." msgstr "Dirección del servidor inválida: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Al revés" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Dificultad" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Vueltas" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Tiempo" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Kart" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Usuario" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Versión" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "No" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Circuito" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Las %d mejores puntuaciones" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Número de karts: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Objetivo de tiempo: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Vueltas: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Al revés: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Vacío)" @@ -4931,33 +5158,41 @@ msgid "Press any key..." msgstr "Pulsa cualquier tecla" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "El chat está desactivado, actívalo desde el menú de opciones" -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Volver al test de rendimiento" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Salir del test de rendimiento" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Volver a la batalla" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Configurar una nueva partida" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Reiniciar la batalla" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Salir de la batalla" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Configurar una nueva carrera" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Salir de la carrera" @@ -4973,11 +5208,11 @@ msgstr "%s todavía no tiene clasificación." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s es el número %d de la clasificación con una puntuación de %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Nombre de usuario y/o correo electrónico no válido." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4999,7 +5234,7 @@ msgstr "Carrera de repetición fantasma" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Vueltas: %i" @@ -5012,21 +5247,21 @@ msgstr "Tipo: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Posición requerida: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Tiempo requerido: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Puntos de nitro requeridos: %i" @@ -5039,54 +5274,54 @@ msgstr "Karts controlados por el ordenador: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Modo de batalla" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Tipo de partida de fútbol" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Ubicación del servidor: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Circuito actual: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Posición" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Jugador" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Puntuaciones" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Tiempo jugado" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Eliminar de favoritos" @@ -5099,74 +5334,74 @@ msgid "No player available for connecting to server." msgstr "No hay ningún jugador disponible para conectarse al servidor." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Nombre de usuario: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Cancelar petición" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Hoy" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "¡Petición de amistad enviada!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "¡Petición de amistad aceptada!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "¡Petición de amistad rechazada!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "¡Amigo eliminado!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "¡Petición de amistad cancelada!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Procesando" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Obteniendo el último voto" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Puedes cambiar tu calificación anterior haciendo clic en las estrellas inferiores." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Todavía no has votado por este complemento. Selecciona la calificación que desees haciendo clic en las estrellas inferiores" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "¡El voto se ha enviado correctamente! Ya puedes cerrar la ventana." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Realizando voto" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Circuito aleatorio" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5195,7 +5430,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Se ha producido un error mientras se intentaba guardar tu campeonato." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Selecciona un circuito" @@ -5239,12 +5474,12 @@ msgstr "Has desbloqueado el circuito %0" msgid "You unlocked grand prix %0" msgstr "Has desbloqueado el campeonato %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Circuito" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5265,19 +5500,19 @@ msgstr "Introduce el nombre del campeonato" msgid "Please select a Grand Prix" msgstr "Selecciona un campeonato" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Definidos por el usuario" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "El nombre está vacío." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Ya existe otro campeonato con ese nombre." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "El nombre es demasiado largo" @@ -5286,19 +5521,19 @@ msgstr "El nombre es demasiado largo" msgid "Better luck next time!" msgstr "¡Más suerte la próxima vez!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "¡Has completado un reto!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "¡Has ganado el campeonato!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "¡Has completado el campeonato!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Número de karts" @@ -5311,110 +5546,125 @@ msgstr "¿Seguro que quieres eliminar esta puntuación?" msgid "Are you sure you want to remove all of your high scores?" msgstr "¿Seguro que quieres eliminar todas tus mejores puntuaciones?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Favorito" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Ligero" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Pesado" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Conecta un teclado o un mando para jugar en pantalla dividida" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Kart aleatorio" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Bloqueado" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Todo el mundo:\n¡Pulsad el botón 'Seleccionar' para uniros a la partida!" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "¿Quieres jugar al tutorial del juego?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "No puedes jugar en línea sin acceso a Internet. Si quieres jugar en línea, ve al menú de opciones y selecciona \"Conectarse a Internet\"." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "No puedes descargar complementos sin acceso a Internet. Si quieres descargar complementos, ve al menú de opciones y selecciona \"Conectarse a Internet\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "No puedes descargar complementos sin acceso a Internet. Si quieres descargar complementos, ve al menú de opciones y selecciona \"Conectarse a Internet\".\n\nPero sí que puedes eliminar complementos ya descargados." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "El módulo de complementos está desactivado en la pantalla de opciones" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Espera mientras se cargan los complementos" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "¿Seguro que quieres salir de STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Crear servidor LAN" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Servidor de %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Nº de circuitos del campeonato" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "¡El nombre debe tener entre 4 y 30 caracteres!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "¡Caracteres incorrectos en la contraseña!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Preparado" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Unirse en directo" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Observar" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Instalar complemento" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5422,7 +5672,7 @@ msgstr "Por favor, espera a que la partida actual (%s) termine. Tiempo restante #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Por favor, espera a que termine la partida actual. Tiempo restante estimado: %s." @@ -5430,24 +5680,24 @@ msgstr "Por favor, espera a que termine la partida actual. Tiempo restante estim #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Por favor, espera a que la partida actual (%s) termine. Progreso estimado: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Por favor, espera a que termine la partida actual. Progreso estimado: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Por favor, espera a que termine la partida actual." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5457,7 +5707,7 @@ msgstr[2] "La partida empezará si hay más de %d jugadores." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5467,96 +5717,108 @@ msgstr[0] "Empezando en %d segundo, o cuando todo el mundo haya pulsado el botó msgstr[1] "Empezando en %d segundos, o cuando todo el mundo haya pulsado el botón 'Preparado'." msgstr[2] "Empezando en %d segundos, o cuando todo el mundo haya pulsado el botón 'Preparado'." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Conectando con el servidor %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Buscando un servidor de partidas rápidas" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Tiempo restante: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Objetivos" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Obteniendo logros" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Perfil de %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Desde" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Estado" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Obteniendo amigos" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Nueva petición" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Pendiente" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Desconectado" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Introduce la nueva dirección debajo" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "La nueva dirección debe tener una longitud de entre 5 y 254 carácteres." -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "¡La nueva dirección no es válida!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "¡La dirección se ha cambiado!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "No se ha podido cambiar la dirección: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Noticias del blog de STK" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Fecha" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "No hay noticias disponibles en este momento" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Debes iniciar sesión para poder jugar en red global. Pulsa en tu nombre de usuario aquí arriba." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Buscando" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Salir del juego" @@ -5634,34 +5896,34 @@ msgid "Distance (km)" msgstr "Distancia (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Desconocido" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "No se ha detectado IPv4. Es posible que no puedas unirte a ningún servidor." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "No se ha detectado IPv6. Es posible que no puedas unirte a ningún servidor." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "No hay servidores disponibles." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Obteniendo servidores" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Servidores Favoritos" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5669,149 +5931,149 @@ msgstr "Si una mayoría de jugadores selecciona el mismo circuito y la misma con #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Localización aleatoria de los elementos" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Número de goles para ganar" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Conducir al revés" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Bloqueado: ¡completa los retos activos para tener acceso a más!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Acción" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Tecla asignada" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Desactivar dispositivo" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Activar dispositivo" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Aactiva la configuración" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Teclas del juego" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Teclas del menú" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Girar a la izquierda" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Girar a la derecha" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Acelerar" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Freno / Marcha atrás" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Fuego" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Mirar atrás" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Rescate" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Pausar el juego" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Arriba" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Abajo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Izquierda" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Derecha" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Seleccionar" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Cancelar/Volver" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Un elemento azul indica un conflicto con otra configuración" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "Un elemento rojo indica un conflicto en la configuración actual" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5819,17 +6081,27 @@ msgid "" msgstr "Cuidado: la tecla 'Mayúsculas' no se recomienda. Cuando se pulse esta tecla dejarán de funcionar todas las teclas que contengan un carácter que sea diferente en mayúsculas." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "¿Seguro que quieres eliminar permanentemente esta configuración?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Introduce un nuevo nombre para la configuración. Déjalo vacío para revertirlo al valor por defecto." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Vertical" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Horizontal" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5837,89 +6109,74 @@ msgstr "En modo multijugador, los jugadores pueden seleccionar perfiles limitado #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Instalar los recursos completos" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "¿Estás seguro de que quieres desinstalar los recursos completos?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Teclado %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Dispositivo táctil" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Da un toque sobre un dispositivo para configurarlo" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Idioma del sistema" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Abajo a la izquierda" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "En el lado derecho" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Oculto" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Centrado" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Vertical" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Horizontal" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Muy pequeña" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Pequeña" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Media" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Grande" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Muy grande" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5929,128 +6186,133 @@ msgid "" msgstr "El modo speedrun sólo se puede activar si el juego no se ha cerrado después de iniciar el modo historia.\n\nCerrar el juego antes de completar el modo historia invalida el temporizador.\n\nPara usar el modo speedrun, utiliza un nuevo perfil, por favor." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Sincronización Vertical" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Vsync obliga a la tarjeta gráfica a proporcionar un nuevo cuadro\nsólo cuando el monitor está listo para mostrarlo." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Vsync no funcionará si tus controladores gràficos no lo soportan." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Efectos de partículas: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Personajes animados: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Luces dinámicas: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Dispersión luminosa: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Antialiasing: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Oclusión ambiental: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Sombras: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Sombras: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Resplandor: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Resplandor (contornos): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Rayos crepusculares (rayos de Dios): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Calidad de la imagen renderizada: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Detalle geométrico: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Difuminación de movimiento: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Profundidad de campo: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "El acceso a Internet está desactivado. ¿Quieres activarlo?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Debes introducir una contraseña." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Cerrando sesión '%s'" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Iniciando sesión '%s'" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "No se puede eliminar al único jugador." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "¿Realmente quieres eliminar al jugador '%s'?" @@ -6078,7 +6340,7 @@ msgstr "¡GOL!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Esperando a los demás" @@ -6113,7 +6375,7 @@ msgstr "Sigue al líder!" msgid "Top %i" msgstr "Top %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Reto no superado" @@ -6137,102 +6399,199 @@ msgstr "Pulsa el icono del podio para empezar el reto" msgid "Press fire to start the challenge" msgstr "Pulsa 'Fuego' para comenzar el reto" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Volver a la configuración de vídeo" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Guardar el resultado del test" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Volver al menú principal" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Abandonar el servidor." -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Cancelar el campeonato" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Reiniciar" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Volver a la selección de retos" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Correr contra la nueva repetición fantasma." -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Volver al menú" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "¿Realmente quieres abortar el campeonato?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Informe de rendimiento guardado en \"%s\"." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "El equipo rojo gana" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "El equipo azul gana" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Empatados" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Eliminado tras %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Eliminado" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(En propia puerta)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Circuito %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Progreso del campeonato:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Máximas puntuaciones" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Mejor vuelta: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "por %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "¡Has completado el reto!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "¡No has completado el reto!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Alcanzados los Requerimientos de SuperTux" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Resultado del test de rendimiento" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Duración del test: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Número de cuadros: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "FPS estable: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "FPS mayormente estable: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "FPS típico: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Resolución horizontal: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Resolución vertical: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Luces dinámicas: SÍ" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Luces dinámicas: NO" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Resolución del renderizado: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Antialiasing: SÍ" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Antialiasing: NO" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Iluminación basada en imágenes: SÍ" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Iluminación basada en imágenes: NO" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Oclusión ambiental: SÍ" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Oclusión ambiental: NO" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Resolución de las sombras: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "¡Todo está permitido, así que coge las armas y haz un buen uso de ellas!" @@ -6273,28 +6632,28 @@ msgstr "Pulsa el icono de fútbol rojo o azul para cambiar de equipo" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Circuito creado por %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Máximos jugadores permitidos: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Número de karts rojos controlados por el ordenador" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "¡No puedes jugar a este campeonato porque contiene circuitos que no están desbloqueados!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "¡Bloqueado!" @@ -6316,10 +6675,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "¡Completa todos los retos para desbloquear la puerta grande!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6328,41 +6689,48 @@ msgid "" msgstr "¡Necesitas más puntos\npara entrar en este reto!\nBusca los retos disponibles\nen el mapa en miniatura." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Acelera con <%s>, y gira con <%s> y <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Acelera tocando la parte superior del volante, y gira moviéndote a derecha e izquierda." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Acelera moviendo el acelerador hacia arriba, y gira inclinando tu dispositivo." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Acelera moviendo el acelerador hacia arriba, y gira rotando tu dispositivo." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "¡Recoge cajas de regalo, y dispara el arma con <%s> para hacer explotar esas cajas!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "¡Recoge cajas de regalo, y dispara pulsando el icono de los bolos para hacer explotar esas cajas!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6370,34 +6738,41 @@ msgid "" msgstr "Pulsa <%s> para mirar detrás de ti.\n¡Dispara el arma con <%s> mientras pulsas <%s> para disparar hacia atrás!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Pulsa el botón del retrovisor para mirar hacia atrás.\nDispara el arma por detrás arrastrando el icono del retrovisor hacia el icono de los bolos." #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "¡Usa la nitro que has recogido pulsando <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "¡Usa la nitro que has recogido pulsando el icono de nitro!" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Recoge botellas de nitro (las usaremos después de la curva)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "¡Ups! Cuando tengas problemas, pulsa <%s> para que te rescaten." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "¡Ups! Cuando tengas problemas, pulsa el icono del pájaro para que te rescaten." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6405,24 +6780,27 @@ msgid "" msgstr "Acelera y pulsa la tecla <%s> mientras giras para derrapar.\nDerrapar un poco puede ayudarte a girar más rápido para tomar curvas cerradas." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Acelera y pulsa el icono del derrape mientras giras para derrapar.\nDerrapar un poco puede ayudarte a girar más rápido para tomar curvas cerradas." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Ten en cuenta que si consigues derrapar durante varios segundos, ¡recibirás un incremento de velocidad como recompensa!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Ya estás preparado para competir. ¡Buena suerte!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Un juego de carreras de karts en 3D de código abierto." @@ -6432,7 +6810,7 @@ msgstr "Un juego de carreras de karts en 3D de código abierto." msgid "tux;game;race;" msgstr "tux;juego;carreras;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6440,7 +6818,7 @@ msgid "" "for all ages." msgstr "Karts. Nitro. ¡Acción! SuperTuxKart es un juego de carreras 3D de código abierto con una gran variedad de personajes, circuitos y formas de jugar. Nuestro objectivo es crear un juego que sea más divertido que realista, y proporcionar una experiencia agradable para todas las edades." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6449,7 +6827,7 @@ msgid "" "your opponents." msgstr "Tenemos unos cuantos circuitos con temas varios para el disfrute de los jugadores, desde carreras subacuáticas, granjas rurales, junglas o incluso en el espacio! Hazlo lo mejor posible y evita a los otros karts, ya que pueden adelantarte, ¡pero no comas los plátanos! Cuidado con las bolas de bolos, los desatascadores, los chicles y los pasteles lanzados por tus oponentes." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6458,27 +6836,27 @@ msgid "" "your racing skills!" msgstr "Puedes correr una carrera suelta contra otros karts, competir en uno de los varios Campeonatos, intentar batir la máxima puntuación en las contrarreloj tú solo, jugar el modo batalla contra el ordenador o contra tus amigos, ¡y más! ¡Si quieres un reto mayor, únete al online y reúnete con jugadores de todo el mundo para probar tus habilidades de corredor!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Este juego no tiene anuncios." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Esta es una versión inestable de SuperTuxKart que contiene las últimas mejoras. Se publica principalmente para probarla, para hacer que la versión estable de STK sea tan buena com sea posible." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Esta versión se puede instalar en paralelo con la versión estable en el dispositivo." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Si necesitas más estabilidad, puedes usar la versión estable: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "El equipo de SuperTuxKart." diff --git a/data/po/fi.po b/data/po/fi.po index d3c882bfc02..f58f04e3bc3 100644 --- a/data/po/fi.po +++ b/data/po/fi.po @@ -5,16 +5,16 @@ # Translators: # Jaakoppi Horila , 2018-2019,2022 # Jiri Grönroos , 2015-2023 -# Kristian Laakkonen, 2018-2019,2021 +# Kristian Laakkonen, 2018-2019,2021,2025 # Markus Mikkonen , 2021 # Oi Suomi On! , 2020-2021 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Jiri Grönroos , 2015-2023\n" +"Last-Translator: Kristian Laakkonen, 2018-2019,2021,2025\n" "Language-Team: Finnish (http://app.transifex.com/supertuxkart/supertuxkart/language/fi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -171,7 +171,7 @@ msgstr "Maailman laidalla" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Takaisin" @@ -193,7 +193,7 @@ msgstr "Valitse ensisijainen ohjaustapa" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Kiihtyvyysanturi" @@ -207,13 +207,13 @@ msgstr "Kiihtyvyysanturi" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Gyroskooppi" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Ratti" @@ -244,35 +244,37 @@ msgstr "Kosketuslaitteen asetukset" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Yleistä" @@ -340,30 +342,33 @@ msgstr "Palauta oletukset" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Peru" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Kyllä" @@ -428,7 +433,7 @@ msgstr "Nollaus" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui msgid "Graphics Settings" -msgstr "Graafiset asetukset" +msgstr "Grafiikka-asetukset" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -541,9 +546,9 @@ msgstr "Liity" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -604,7 +609,7 @@ msgstr "Tavoite" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Edistyminen" @@ -639,7 +644,7 @@ msgstr "Vaihda salasana" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Takaisin kilpailuun" @@ -656,7 +661,7 @@ msgstr "Takaisin aulaan" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Käynnistä kilpailu uudelleen" @@ -720,12 +725,12 @@ msgstr "Anna rekisteröitymisen yhteydessä antamasi käyttäjätunnus ja salasa #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Käyttäjätunnus" @@ -766,7 +771,7 @@ msgstr "Vaikeustaso" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Aloittelija" @@ -778,7 +783,7 @@ msgstr "Aloittelija" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Keskitaso" @@ -790,7 +795,7 @@ msgstr "Keskitaso" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Kokenut" @@ -802,7 +807,7 @@ msgstr "Kokenut" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -810,8 +815,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Pelimuoto" @@ -822,8 +827,8 @@ msgstr "Pelimuoto" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Normaali kilpailu" @@ -836,7 +841,7 @@ msgstr "Normaali kilpailu" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Aika-ajo" @@ -844,7 +849,8 @@ msgstr "Aika-ajo" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Taistelu" @@ -853,24 +859,24 @@ msgstr "Taistelu" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Jalkapallo" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Salasana" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Lisää palvelin kirjanmerkkeihin" @@ -881,7 +887,7 @@ msgstr "Lisää pelaaja" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Nimi" @@ -975,6 +981,50 @@ msgstr "Aseta näppäimelle ESC" msgid "Assign nothing" msgstr "Älä aseta mitään" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Suosittele grafiikka-asetuksia" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Suositellut asetukset ovat voimassa nykyisellä resoluutiolla." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Mikä on tärkeintä asetuksissa?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Suorituskyky" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Painota suorituskykyä ja grafiikan laatua yhtä paljon" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Grafiikan laatu" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Energiansäästö" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Pidätkö sumentavista graafisista tehosteista?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Käynnistä testi" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -989,11 +1039,11 @@ msgstr "Kilpailun asetukset" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Jatka" @@ -1034,10 +1084,15 @@ msgstr "Areenat" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Asennettu" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1047,20 +1102,20 @@ msgstr "Asennettu" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Vakio" @@ -1071,12 +1126,12 @@ msgstr "Vakio" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Lisäosat" @@ -1090,27 +1145,28 @@ msgstr "Lisäosat" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Kaikki" @@ -1149,9 +1205,9 @@ msgstr "Siirry alas" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Lisää" @@ -1188,7 +1244,7 @@ msgstr "Haamu-uusinnan valinta" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Munajahti" @@ -1235,10 +1291,10 @@ msgstr "Käänteinen suunta" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Enimmäisaika (min)" @@ -1270,9 +1326,9 @@ msgstr "Kopioi" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1283,80 +1339,80 @@ msgstr "Nimeä uudelleen" msgid "Save Grand Prix" msgstr "Tallenna Grand Prix" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "SuperTuxKartin ohje" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Pelimuodot" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Esineet" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Banaanit" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1364,56 +1420,57 @@ msgstr "Banaanit" msgid "Story Mode" msgstr "Tarinapeli" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Autoluokat" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Moninpeli" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Aloita opastus" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Kerää sinisiä lahjapaketteja, saat niistä esineitä." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Vältä banaaneja!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1421,14 +1478,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Nitroa keräämällä voit lisätä nopeuttasi milloin haluat painamalla siihen tarkoitettua näppäintä tai nappia. Näet nykyisen nitron määrän ruudun oikeassa alareunassa olevasta mittarista." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Jos näet oheisen kaltaisen lukollisen painikkeen, sinun täytyy suorittaa haaste avataksesi lukituksen." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1437,34 +1494,34 @@ msgid "" "carefully before!" msgstr "Voit saada autosi luisuun painamalla tähän tarkoitettua näppäintä tai nappia. Peräkkäiset lyhyet luisut auttavat tiukoissa mutkissa, kun taas keskipitkät ja pitkät luisut lisäävät vauhtiasi. Et pysty kääntämään autoasi luisun aikana, joten suuntaa autosi oikein sitä ennen!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Voit saada alkukiihdytyksen lähdössä painamalla kaasua, kun \"Valmiit!\"-teksti ilmestyy näkyviin juuri ennen kilpailun alkua." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Nykyisiä näppäinasetuksia voi tarkastella/muokata Asetukset-valikossa" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart sisältää lukuisia eri pelitiloja:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Normaali kilpailu: Kaikki keinot sallittuja, joten kerää esineitä ja käytä niitä järkevästi!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Aika-ajo: ei sisällä esineitä, joten vain ajotaidoillasi on merkitystä!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1472,7 +1529,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Seuraa johtajaa: Pysy toisena, sillä viimeisenä oleva kilpailija poistetaan kisasta joka kerta kun laskuri menee nollaan. Varo myös menemästä johtajan edelle - silloinkin sinut poistetaan!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1482,30 +1539,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Taistelumuotoja on 3 erilaista: Kolmen iskun taistelussa toiset kilpailijat yritetään saada menettämään kaikki elämänsä osumalla heihin aseilla. Kaikki vastaan kaikki -kisassa voittaa pelaaja, joka osuu toisiin eniten tietyn aikarajan tai osumamäärärajan sisällä. Lipunryöstö -kisassa joukkueesi täytyy tuoda toisen joukkueen lippu omaan tukikohtaanne sekä välttää oman lippunne kaappaus." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Jalkapallo: Käytä autoasi työntääksesi pallon maaliin." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Munajahti: Löydä kaikki radoille piilotetut munat." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Haamu-uusinta: Kisaa haamu-uusintoja vastaan aika-ajossa tai munajahdissa ja nauhoita oma uusintasi!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Kierrosajo: Suorita mahdollisimman monta kierrosta annetussa ajassa." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1514,93 +1571,93 @@ msgid "" "wins the cup." msgstr "* Monia näistä pelimuodoista voi pelata myös Grand Prix -tyyliin, eli yhden kisan sijasta pelataan monta peräkkäin. Mitä paremmin sijoitut, sitä enemmän saat pisteitä. Eniten pisteitä saanut voittaa." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Seuraavat kerättävät esineet voivat auttaa sinua voittoon:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Purukumi - käytä suojakilpenä, tai jätä tahmea pinkki klöntti taaksesi." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Turbo - antaa huomattavasti lisää nopeutta. Mutta varo, ettet menetä autosi hallintaa!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Kakku - heitetään lähintä vastustajaa päin, paras teho lyhyillä etäisyyksillä ja pitkillä suorilla. Vaikuttaa myös muihin jysäyksen lähellä oleviin autoihin." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Imukuppi - Heitä eteenpäin kiskoaksesi edellä olevaa kilpailijaa takaisin, tai taaksepäin seuraajasi näköesteeksi." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Keilapallo - kulkee suoraan kunnes osuu johonkin, voi kimmota seinämistä. Jos katsot taakse heittäessäsi pallon, pallo suuntautuu taaksepäin." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Laskuvarjo - hidastaa kaikkia edelläsi olevia kilpailijoita." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Vaihtaja - lahjapaketit muutetaan banaaneiksi, nitropullot purukumeiksi ja päinvastoin lyhyeksi aikaa." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Koripallo - pomppii kärjessä olevan perään, saattaa lytätä ja hidastaa muita autoja." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Kärpäslätkä - osuu lähellä oleviin autoihin ja hidastaa niiden kulkua. Voidaan käyttää myös laskuvarjojen ja pommien poistamiseen." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Banaaniin osuminen voi johtaa jonkin seuraavista kiinnitymiseen autoon:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Ankkuri - hidastaa autoa yhtäkkiä." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Laskuvarjo - hidastaa autoa, vaikutus on suurempi kuin ankkurilla. Mitä kovempaa kuljet, sitä enemmän laskuvarjo hidastaa kulkuasi." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Pommi - räjähtää hetken viiveellä ja heittää auton ilmaan. Törmää toiseen autoon, jos haluat siirtää pommin siihen." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Paha Nolok on kaapannut Gnu'n! Tässä muutamia vinkkejä avuksesi:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1609,7 +1666,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Tämä kuva pienoiskartalla osoittaa haasteet, joita et ole vielä suorittanut. Se myös kertoo ruudun oikeassa ylänurkassa, kuinka monta pistettä sinulla tällä hetkellä on. Suorita mahdollisimman monta haastetta, niin Nolok hyväksyy haasteen kisata sinua vastaan. Voita hänet vapauttaaksesi Gnun!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1617,20 +1674,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Suoritettuasi haasteen saat pokaalin. Jokainen pokaali on tietyn pistemäärän arvoinen. Mitä korkeammalla vaikeustasolla suoritat haasteen, sitä suurempi on pokaalin pistemäärä." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Saat yllätyslahjan, kun saavutat tämän kuvan alapuolella osoitetun määrän pisteitä. Yllätyksiä on useita kerättäväksi." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Kaikki autot eivät ole samanlaisia! Ne kuuluvat eri ominaisuuksilla varustettuihin luokkiin:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1638,7 +1695,7 @@ msgid "" " resistant to explosions." msgstr "Paino - autoja on kolme eri painoluokkaa; kevyt, tavallinen ja raskas. Laskuvarjot ja räjähdykset vaikuttavat vähemmän raskaisiin kuin kevyisiin autoihin." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1646,7 +1703,7 @@ msgid "" " especially at low speeds." msgstr "Kiihtyvyys - erityisen hyödyllinen lähdössä, onnettomuuden jälkeen tai paljon kurveja sisältävissä radoissa. Mitä kevyempi auto, sitä nopeammin se kiihtyy, varsinkin matalilla nopeuksilla." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1654,14 +1711,14 @@ msgid "" " top speed." msgstr "Enimmäisnopeus - mitä korkeampi, sitä kovempaa auto kulkee. Erityisen hyödyllinen paljon suoria tai pieniä kurveja sisältävillä radoilla. Painavilla autoilla on kevyempiä autoja korkeampi enimmäisnopeus." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Nitron tehokkuus - mitä korkeampi se on, sitä enemmän vauhtia saat nitropurkista. Nitrotehokkuus on kevyemmällä ajokilla korkeampi. " -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1669,12 +1726,12 @@ msgid "" "easier it is." msgstr "Jos seuraat toista autoa lähietäisyydellä muutaman sekunnin ajan, saat peesauksesta vauhtiedun, kun ohitat auton. Mitä kevyempi autosi on, sen helpompaa edun saaminen on." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKartia voi pelata moninpelitilassa verkossa:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1684,7 +1741,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Aluksi, valitse 'verkkopeli'-ikoni päävalikosta. Valitse joko paikallisverkko tai maailmanlajuinen verkko (vaatii internet-yhteyden sallimisen asetuksissa). Sitten, voit luoda oman serverisi mukautettavilla valinnoilla, tai etsiä listasta olemassaolevia servereitä, joihin liittyä. Jotkut niistä ovat suositeltuja servereitä vapaaehtoisesti sijoitukseen vaikuttavilla kisoilla." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1694,12 +1751,12 @@ msgid "" "players and the server." msgstr "Kun olet palvelimella, kisa alkaa sen omistajan (merkitty kruunulla) päättäessä niin. Virallisilla palvelimilla kisa voi alkaa automaattisesti vain kun kasassa on tarpeeksi pelaajia. Sen jälkeen, voit valita ajokkisi ja äänestää seuraavaa rataa. Lisärata sallitaan vain mikäli se on olemassa kaikille pelaajille sekä palvelimella." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... tai samalla laitteella:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1709,7 +1766,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Ensiksi tarvitset useamman syöttölaitteen. Laita niiden asetukset kuntoon ohjainasetuksissa. Useamman peliohjaimen tai joystickin käyttö on suositeltavaa. Myös näppäimistö(i)llä pelaaminen on mahdollista, mutta jokaisella pelaajalla täytyy olla eri näppäinasetukset ja useimmat näppäimistöt tukevat varsin rajoitettua määrää yhtäaikaisia näppäimenpainalluksia." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1729,7 +1786,7 @@ msgstr "Huippupisteiden valinta" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Kierrosajo" @@ -1737,9 +1794,9 @@ msgstr "Kierrosajo" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Grand Prix" @@ -1750,6 +1807,20 @@ msgstr "Grand Prix" msgid "Choose a Kart" msgstr "Valitse auto" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1763,11 +1834,11 @@ msgstr "Jaetun näytön moninpeli" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Verkkopeli" @@ -1784,7 +1855,7 @@ msgstr "Opaskierros" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Huippupisteet" @@ -1792,7 +1863,7 @@ msgstr "Huippupisteet" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Saavutukset" @@ -1846,30 +1917,30 @@ msgstr "Etsi palvelin" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Luo palvelin" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Aula" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Määritykset" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Aloita kisa" @@ -1895,9 +1966,9 @@ msgstr "Anna palvelimen osoite" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Profiilisi" @@ -1915,7 +1986,7 @@ msgstr "Pelaajasijoitukset" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Kaverit" @@ -1940,7 +2011,7 @@ msgstr "Pikapeli" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Tilin asetukset" @@ -1990,8 +2061,8 @@ msgid "Online Username" msgstr "Verkkopelitunnus" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Nollaa salasana" @@ -2004,7 +2075,7 @@ msgid "" msgstr "Voit pelata luomatta verkkotiliä valitsemalla \"Yhteydetön tili\". Yhteydettömällä tilillä et voi yhdistää kavereidesi kanssa, äänestää lisäosia jne. Lue tietosuojaseloste osoitteessa https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Palvelinvalinta" @@ -2022,339 +2093,409 @@ msgstr "Käytä IPv6-yhteyttä" msgid "User search" msgstr "Käyttäjähaku" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "SuperTuxKartin asetukset" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Grafiikka" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Ääni" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Käyttöliittymä" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Pelaajat" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Ohjaimet" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Kieli" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Musiikki" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Käytössä" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Voimakkuus" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Äänitehosteet" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Poista näppäinasetukset" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Poista asetukset käytöstä" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Takaisin laitelistaan" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Nimeä asetukset uudelleen" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Käytä force feedbackia (jos tuki olemassa)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Resoluutio" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Koko näytön tila" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Muista ikkunan sijainti" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Käytä uutta resoluutiota" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Jaetun näytön moninpelin asettelu" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Internet-asetukset" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Näytä aina kirjautumisnäkymä" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Yhdistä internetiin" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Käytä keskustelua verkkopeleissä" +msgid "Enable chatting in online lobbies" +msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Salli keskustelu verkkopeleissä" +msgid "Enable chatting in online matches" +msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Muut valinnat" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Käytä pelaajakohtaisia tasoituksia" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Poista koko pelin resurssit" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Kaksoisnapsauta laitetta tai paina enter sen kohdalla säätääksesi asetuksia" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Lisää laite" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Käytettävä asetus päätellään sen mukaan, minkä ohjaimen \"Valitse\"-näppäintä painetaan peliin liitymisen yhteydessä." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Ulkoasu" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Pienoiskartta" +msgid "Skin variant" +msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Jaetun näytön moninpelin asettelu" +msgid "Minimap" +msgstr "Pienoiskartta" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Fontin koko" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Kamera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Mukautettu..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Näytä ruudunpäivitysnopeus (FPS)" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Näytä muiden autojen esineet" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Käytä tarinatilan ajastinta" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Käytä speedrun-ajastinta" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Hahmonnuksen tarkkuus" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Graafisten tehosteiden taso" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Liikepehmennyksen tehosteiden taso" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "FPS enintään" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Omat asetukset..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Resoluutio" +msgid "Performance tests" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Koko näytön tila" +msgid "Performance test of the current settings" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Muista ikkunan sijainti" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Muista salasana" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Käytä uutta resoluutiota" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Poista" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Auton väri" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2381,15 +2522,15 @@ msgstr "Sininen joukkue" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Kierrosten määrä" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Tietokoneen ohjaamien pelaajien määrä" @@ -2404,33 +2545,17 @@ msgstr "Sinisen joukkueen tietokoneen ohjaamien autojen määrä" msgid "Random Grand Prix" msgstr "Satunnainen Grand Prix" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Kirjaudu" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Muista salasana" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Poista" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Auton väri" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Käyttöliittymän teemaa on mahdollista vaihtaa käyttöliittymän asetuksista." @@ -2549,238 +2674,306 @@ msgid "" msgstr "Älä ajaudu palloa pitävän joukkuekaverin tielle, vaikka voitkin yrittää osua vastustajiin, jotka yrittävät estää omiasi tekemästä maalia." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Paprika" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Vedenalainen maailma" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Muukalaissignaali" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Muinainen Colosseum-labyrintti" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Candela City" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Taistelusaari" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Schwarzwald" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Luola X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Kaakaotemppeli" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Maissipellon risteys" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Magmalinnoitus" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Gran Paradiso -saari" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Pudotusaukko" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Jäinen jalkapallokenttä" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Mikä hätänä, pikkukaverit? Onko suuri johtajanne Gnu kadonnut?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Niin, nähkääs, hän on nyt linnassani ja kohta hänet tarjoillaan illallisena..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Mutta olen reilu otus, joten teen teille tarjouksen." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Jos voitatte minut kilvanajossa, vapautan vanhan höppänän." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " Mutta te typerykset ette koskaan tule voittamaan minua, mikroautoilun kuningasta!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Las Dunasin areena" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Las Dunas -jalkapallostadion" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Majakan ympäri" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Vanha kaivos" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Keidas" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Oliverin matikantunti" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Kurpitsapuisto" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Korppisillan kartano" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Liikkuvat hiekat" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Nessien lampi" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Pohjoinen hiihtokeskus" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Lumihuippu" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Jalkapallokenttä" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Stadion" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Enterprise" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Temppeli" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Tulivuorisaari" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Zen-puutarha" @@ -2789,11 +2982,11 @@ msgstr "Zen-puutarha" msgid "Completed achievement \"%s\"." msgstr "Suoritettiin saavutus \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Yhdistäminen SuperTuxKart-lisäosien palvelimeen epäonnistui." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Virhe uutisia ladattaessa: '%s'." @@ -2859,7 +3052,7 @@ msgid "New kart '%s' now available" msgstr "Uusi auto, \"%s\", on nyt käytössäsi" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2891,32 +3084,32 @@ msgid "" "created." msgstr "Asetustiedosto oli liian vanha, joten se poistettiin ja uusi luodaan tilalle." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Videon tallennus aloitettu." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Video tallennettu sijaintiin \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Pakkauksen edistyminen:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %d ms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Vinkki: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Ladataan" @@ -2938,19 +3131,18 @@ msgstr "Nitron tehokkuus" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (tasoitettu)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s on valmis" @@ -3424,21 +3616,21 @@ msgid "Axis %d" msgstr "Akseli %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Peliohjaimen nappi %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Hiiren näppäin %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Hiiren akseli %d%s" @@ -3610,26 +3802,30 @@ msgstr "Sinulla voi olla korkeintaan 3 elämää!" msgid "+1 life." msgstr "+1 elämä." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Olit liian hidas!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Voitit kilpailun!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Kisa päättyi osaltasi sijoitukseen %d!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s poistui pelistä." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3638,16 +3834,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart voi yhdistää palvelimelle ladatakseen lisäosia sekä ilmoittaakseen sinulle päivityksistä. Lue yksityisyyskäytäntömme osoitteessa https://supertuxkart.net/Privacy. Haluatko että tämä kyseinen ominaisuus kytketään päälle? (Muuttaaksesi tätä asetusta myöhemmin, mene asetuksiin, valitse välilehti 'Yleistä', ja muokkaa \"Yhdistä internetiin\") " -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Näyttösi resoluutio on liian matala STK:n pelaamista varten." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Ajuriversiosi on liian vanha. Asenna näytönohjaimen uusin ajuri." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3655,38 +3851,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Näytönohjaimesi ajuri vaikuttaa olevan erittäin vanha. Tarkista onko sille saatavilla päivitystä. SuperTuxKart suosittelee ajuria, joka tarjoaa %s-tuen tai uudemmalle. Kaikesta huolimatta peli luultavasti toimii, mutta matalassa grafiikkatilassa." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Palvelinyhteys aikakatkaistiin." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s sai punaisen lipun!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Punainen lippu on palautunut!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s sai sinisen lipun!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Sininen lippu on palautunut!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s kaappasi sinisen lipun!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s kaappasi punaisen lipun!" @@ -3696,7 +3892,7 @@ msgstr "%s kaappasi punaisen lipun!" msgid "Eggs: %d / %d" msgstr "Munia: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Johtaja" @@ -3704,22 +3900,22 @@ msgstr "Johtaja" msgid "Final lap!" msgstr "Viimeinen kierros!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "%i. kierros" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s (%s)" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Uusi nopein kierros" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "VÄÄRÄ SUUNTA!" @@ -3733,194 +3929,194 @@ msgstr "%s teki maalin!" msgid "Oops, %s made an own goal!" msgstr "Hups, %s teki oman maalin!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "%i vararengasauto lisätty!" msgstr[1] "%i vararengasautoa lisätty!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Sinut poistettiin kisasta!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "%s on poistettu." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Palvelin on sammutettu." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Sinut potkittiin pois palvelimelta." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Sinut potkittiin pois: ping on liian korkea." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Verkkoyhteydessä havaittiin ongelmia." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Botti" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s katkaisi yhteyden." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Paina pelaajan nimeä listassa hallitaksesi pelaajia ja nähdäksesi sijoitustietoja." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Vaikeustaso: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Pelaajia enintään: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Pelitila: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Aikaraja" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Maaliraja" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Jalkapallopelin tyyppi: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Grand prix'n edistyminen: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Kaikki pelaajat liittyivät punaiseen tai siniseen joukkueeseen." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Olet nyt palvelimen omistaja." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Yhteys estettiin: palvelin on varattu." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Yhteys estettiin: sinulla on porttikielto palvelimelle." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Yhteys estetty: palvelimen salasana oli väärin." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Yhteys estetty: pelin tiedot eivät ole yhteensopivia." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Yhteys estettiin: palvelin on täynnä." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Yhteys estettiin: Virheellinen pelaaja yritti muodostaa yhteyden." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Verkkopelin käynnistäminen epäonnistui." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Peli on päättynyt, et voi enää liittyä suoraan tai katsella." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Areenalla ei ole tilaa – suoraan liittyminen ei ole mahdollista." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Vain 1 pelaaja jäljellä, palataan aulaan." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Palvelimen omistaja lopetti pelin." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Olet katselutilassa seuraavassa pelissä." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s liittyi punaiseen joukkueeseen." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s liittyi siniseen joukkueeseen." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s liittyi peliin." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3928,15 +4124,15 @@ msgid "" msgstr "Paina <%s> tai <%s> vaihtaaksesi kohdepelaajaa, <%s> tai <%s> valitaksesi kamera-asennon." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "Pelaajasta %s ilmoitettiin onnistuneesti." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3967,38 +4163,38 @@ msgstr "Aika-ajo (Grand Prix)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Kaikki vastaan kaikki" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Lipunryöstö" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s on nyt linjoilla." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s ja %s ovat nyt linjoilla." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s ja %s ovat nyt linjoilla." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4006,19 +4202,19 @@ msgstr[0] "%d kaveri on nyt linjoilla." msgstr[1] "%d kaveria on nyt linjoilla." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s on nyt palvelimella \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "Sinulla on %d uusi kaveripyyntö!" msgstr[1] "Sinulla on %d uutta kaveripyyntöä!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Sinulla on uusi kaveripyyntö!" @@ -4047,12 +4243,12 @@ msgid "" msgstr "Huippupisteiden tiedosto oli liian vanha.\nKaikki huippupisteet on nyt nollattu." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Seuraa johtajaa" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Kolmen iskun taistelu" @@ -4065,91 +4261,88 @@ msgstr "Puutteellista uusintatiedostoa ei tallenneta." msgid "Replay saved in \"%s\"." msgstr "Uusinta tallennettu \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 viikko" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 viikkoa" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 kuukausi" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 kuukautta" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 kuukautta" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 kuukautta" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 vuosi" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 vuotta" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Lisäosan nimi" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Päivitetty" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Ei asennettu" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s, tekijä: %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Odota, lisäosia päivitetään" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Lisäosasivustoon ei saatu yhteyttä. Tarkista, että yhteys internetiin toimii ja ettei palomuuri estä SuperTuxKartia ottamasta yhteyttä verkkoon." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Lukittu. Suorita aktiivisia haasteita saadaksesi käyttöön uusia ominaisuuksia!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Satunnainen areena" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d areena ei käytettävissä yksinpelissä." -msgstr[1] "%d areenaa ei käytettävissä yksinpelissä." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nJaakoppi Horila, 2018-2019,2022\nJiri Grönroos, 2015-2022\nKristian Laakkonen, 2018-2019,2021\nMarkus Mikkonen, 2021\nOi Suomi On!, 2020-2021\nJaakoppi Horila, 2018-2019\nJiri Grönroos, 2015-2021\nLaunchpad Contributions:\nDawid Gan\nJoonas Nurmi\nKristian Laakkonen\nSTK-team" @@ -4437,7 +4630,7 @@ msgstr "Banaaneja kerätty" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Sivuluisu" @@ -4540,7 +4733,7 @@ msgstr "Munajahteja suoritettu" msgid " (official tracks matching the goal)" msgstr "(viralliset radat, jotka sopivat tavoitteeseen)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4548,91 +4741,95 @@ msgid "" msgstr "Uudet pad-ohjaimet ja sauvaohjaimet ilmestyvät luetteloon automaattisesti kytkiessäsi ne tähän laitteeseen.\n\nLisää näppäimistöasetus, käyttämällä allaolevaa painiketta, mutta ota KUITENKIN huomioon että useimmat näppäimistöt tukevat yhdenaikaisia näppäinpainalluksia vain rajallisesti ja ovat täten sopimattomia moninpeliin. (Tästä huolimatta, voit liittää useita näppäimistöjä tähän laitteeseen. Muistathan että tässäkin tapauksessa kaikki pelaajat tarvitsevat edelleenkin eri näppäinsidonnat.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Lisää Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Lisää uudet näppäinasetukset" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Päivitä" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Versio: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "suositeltu" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Koko: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Lisäosan lataaminen epäonnistui" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Lisäosan \"%s\" asentaminen epäonnistui." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Yritä uudelleen" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Lisäosan \"%s\" poistaminen epännistui." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Taustalataus valmistui." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Taustalataus" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Taustalataus on jo käynnistynyt." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Nykyinen salasana on virheellinen." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Salasanan tulee olla pituudeltaan 8-30 merkkiä!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Salasanat eivät täsmää!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Varmistetaan tietoja" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Salasana vaihdettu onnistuneesti." @@ -4653,67 +4850,97 @@ msgstr "Vain 1024x768 ja 1280x720 ja sitä suuremmat näyttötarkuudet ovat tuet #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Lennokkijahti" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Oma" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Ei käytössä" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Vain tärkeä" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Erittäin matala" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Matala" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Tavallinen" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Korkea" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4721,7 +4948,7 @@ msgid "" msgstr "SuperTuxKart lataa kaikki resurssit (mukaan lukien korkeatasoiset tekstuurit ja musiikin) hyvän pelikokemuksen saavuttamiseksi. Tämä käyttää mobiilidatayhteyttä, jos käytössä ei ole wifi-yhteyttä." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4738,101 +4965,102 @@ msgstr "Kirjoita palvelimen osoite (valinnaisesti perässä : ja portin numero) msgid "Invalid server address: %s." msgstr "Virheellinen palvelimen osoite: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Käänteinen" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Vaikeustaso" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Kierrokset" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Aika" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Auto" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Käyttäjä" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Versio" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Ei" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Rata" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Huippupisteiden %d parasta" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Autojen määrä: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Aikatavoite: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Kierroksia: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Käänteinen: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Tyhjä)" @@ -4920,33 +5148,41 @@ msgid "Press any key..." msgstr "Paina mitä tahansa näppäintä..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Keskustelu on pois käytöstä, ota se käyttöön asetusvalikosta." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Takaisin taisteluun" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Määritä uusi peli" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Käynnistä taistelu uudelleen" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Poistu taistelusta" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Uusi kilpailu" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Poistu kilpailusta" @@ -4962,11 +5198,11 @@ msgstr "Pelaajalla %s ei ole vielä sijoitusta." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s on sijalla %d pistemäärällä %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Virheellinen käyttäjätunnus ja/tai sähköpostiosoite." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4988,7 +5224,7 @@ msgstr "Haamu-uusinta" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Kierroksia: %i" @@ -5001,21 +5237,21 @@ msgstr "Tyyppi: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Vaadittu sijoitus: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Vaadittu aika: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Vaaditut nitropisteet: %i" @@ -5028,54 +5264,54 @@ msgstr "Tietokoneen ohjaamien autojen määrä: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Taistelutila" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Jalkapallopelin tyyppi" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Palvelimen sijainti: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Nykyinen rata: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Sijoitus" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Pelaaja" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Pisteet" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Peliaika" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Poista kirjanmerkeistä" @@ -5088,74 +5324,74 @@ msgid "No player available for connecting to server." msgstr "Ei pelaajaa, joka voisi yhdistää palvelimeen" #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Käyttäjätunnus: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Peru pyyntö" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Tänään" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Kaveripyyntö lähetetty!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Kaveripyyntö hyväksytty!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Kaveripyyntö hylätty!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Kaveri poistettu!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Kaveripyyntö peruttu!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Käsitellään" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Noudetaan viimeistä ääntä" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Voit muokata aiempaa arvosteluasi napsauttamalla alapuolella olevia tähtiä." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Et ole vielä äänestänyt tätä lisäosaa. Arvostele lisäosa napsauttamalla alla olevia tähtiä" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Äänestys onnistui! Voit nyt sulkea ikkunan." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Suoritetaan äänestystä" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Satunnainen rata" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5184,7 +5420,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Grand Prix'tä tallennettaessa tapahtui virhe." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Valitse rata" @@ -5228,12 +5464,12 @@ msgstr "Avasit radan %0" msgid "You unlocked grand prix %0" msgstr "Avasit %0 -Grand Prix'n lukituksen" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Rata" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5254,19 +5490,19 @@ msgstr "Anna nimi Grand Prix'lle" msgid "Please select a Grand Prix" msgstr "Valitse Grand Prix" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Käyttäjän määrittämä" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Nimi on tyhjä." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Toinen grand prix samalla nimellä on jo olemassa." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Nimi on liian pitkä." @@ -5275,19 +5511,19 @@ msgstr "Nimi on liian pitkä." msgid "Better luck next time!" msgstr "Parempi onni ensi kerralla!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Suoritit haasteen!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Voitit Grand Prix'in!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Läpäisit Grand Prix'n!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Autojen määrä" @@ -5300,110 +5536,125 @@ msgstr "Haluatko varmasti poistaa tämän tietueen huippupisteistä?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Haluatko varmasti poistaa kaikki huippupisteesi?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Yhdistä näppäimistö tai peliohjain pelataksesi moninpeliä jaetulla näytöllä" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Satunnainen auto" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Lukittu" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Kaikki:\nPainakaa valintapainiketta liittyäksenne peliin" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Haluatko pelata pelin opaskierroksen?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Verkossa ei voi pelata ilman internetyhteyttä. Jos haluat pelata verkossa, mene Asetukset-valikkoon ja valitse \"Yhdistä internetiin\"." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Et voi ladata lisäosia ilman pääsyä internetiin. Jos haluat ladata lisäosia, mene Asetukset-valikkoon ja rastita \"Yhdistä internetiin\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Et voi ladata lisäosia ilman pääsyä internetiin. Jos haluat ladata lisäosia, mene Asetukset-valikkoon ja rastita \"Yhdistä internetiin\".\n\nVoit kuitenkin poistaa jo ladattuja lisäosia." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Lisäosamoduuli ei ole tällä hetkellä käytössä Asetukset-valikossa" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Odota, lisäosia ladataan" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Haluatko varmasti lopettaa STK:n?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Luo LAN-palvelin" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Käyttäjän %s palvelin" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Grand Prix -ratojen määrä:" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Nimen tulee olla pituudeltaan 4-30 merkkiä!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Vääriä kirjaimia salasanassa!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Valmis" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Liity suoraan" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Katsele" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Asenna lisäosa" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5411,7 +5662,7 @@ msgstr "Odota kunnes nykyinen peli (%s) päättyy. Aikaa jäljellä arviolta: %s #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Odota kunnes nykyinen peli päättyy. Aikaa jäljellä arviolta: %s." @@ -5419,24 +5670,24 @@ msgstr "Odota kunnes nykyinen peli päättyy. Aikaa jäljellä arviolta: %s." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Odota kunnes nykyinen peli (%s) päättyy. Arvioitu edistyminen: %s %." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Odota kunnes nykyinen peli päättyy. Arvioitu edistyminen: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Odota kunnes nykyinen peli päättyy." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5445,7 +5696,7 @@ msgstr[1] "Peli alkaa, kun mukana on enemmän kuin %d pelaajaa." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5454,96 +5705,108 @@ msgid_plural "" msgstr[0] "Alkaa %d sekunnin kuluttua, tai kun kaikki ovat painaneet \"Valmis\"-painiketta." msgstr[1] "Alkaa %d sekunnin kuluttua, tai kun kaikki ovat painaneet \"Valmis\"-painiketta." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Yhdistetään palvelimeen %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Etsitään pikapelipalvelin" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Aikaa jäljellä: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Tavoitteet" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Noudetaan saavutuksia" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Käyttäjän %s profiili" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Lähtien" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Tila" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Noudetaan kavereita" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Uusi määrä" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Odottaa" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Ei linjoilla" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Kirjoita uusi sähköpostiosoite alapuolelle" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Uuden sähköpostiosoitteen tulee olla 5-254 merkkiä pitkä!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Uusi sähköpostiosoite on virheellinen!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "Sähköpostiosoite vaihdettu!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Sähköpostiosoitteen vaihtaminen epäonnistui: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Sinun täytyy olla kirjautunut, jotta voit pelata maailmanlaajuisessa verkossa. Napsauta käyttäjänimeäsi yläpuolelta." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Etsitään" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Poistu pelistä" @@ -5621,34 +5884,34 @@ msgid "Distance (km)" msgstr "Etäisyys (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Tuntematon" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "IPv4:ää ei havaittu, liittyminen palvelimille ei välttämättä ole mahdollista." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "IPv6:tta ei havaittu, liittyminen palvelimille ei välttämättä ole mahdollista." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Ei palvelinta käytettävissä." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Noudetaan palvelimia" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Palvelinten kirjanmerkit" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5656,149 +5919,149 @@ msgstr "Jos suurin osa pelaajista valitsee saman radan ja kisa-asetukset, ääne #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Satunnainen esineiden sijainti" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Voittoon tarvittavien maalien määrä" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Aja vastasuuntaan" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Lukittu: suorita aktiivisia haasteita saadaksesi käyttöön uusia ominaisuuksia!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Toiminto" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Näppäinsidos" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Poista laite käytöstä" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Ota laite käyttöön" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Ota asetukset käyttöön" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Pelinäppäimet" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Valikkonäppäimet" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Ohjaa vasemmalle" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Ohjaa oikealle" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Kiihdytä" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Jarru/peruutus" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Ampumisnäppäin" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Katso taakse" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Pelastus" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Pysäytä peli" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Ylös" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Alas" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Vasen" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Oikea" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Valitse" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Peru/takaisin" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Sininen merkintä tarkoittaa ristiriitaa toisen asetuksen kanssa" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Punainen merkintä tarkoittaa ristiriitaa nykyisten asetusten kanssa" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5806,17 +6069,27 @@ msgid "" msgstr "Varoitus: Shift-näppäimen käyttöä ei suositella. Shift-näppäintä painettaessa kaikki ne näppäimet, jotka tuottavat eri merkin yhdessä Shift-näppäimen kanssa, eivät toimi." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Haluatko varmasti poistaa nämä asetukset?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Syötä asetuksille uusi nimi, jätä tyhjäksi palataksesi vakioarvoihin." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Pystysuunta" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Vaakasuunta" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5824,89 +6097,74 @@ msgstr "Moninpelimuodossa pelaajat voivat valita tasoitettuja\n(vaikeampia) prof #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Asenna koko pelin resurssit" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Haluatko varmasti poistaa koko pelin resurssit?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Näppäimistö %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Kosketuslaite" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Napauta laitetta säätääksesi sen asetuksia" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Järjestelmän kieli" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Vasen alareuna" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "Oikea laita" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Piilotettu" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Keskitetty" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Pystysuunta" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Vaakasuunta" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Erittäin pieni" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Pieni" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Tavallinen" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Suuri" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Erittäin suuri" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5916,128 +6174,133 @@ msgid "" msgstr "Speedrun-pikapeluutila voidaan kytkeä päälle vain jos peliä ei ole suljettu tarinatilan käynnistämisen jälkeen.\n\nPelin sulkeminen ennen tarinatilan loppuun saattamista mitätöi ajastimen.\n\nKäyttääksesi speedrun-pikapeluutilaa, ota käyttöön uusi profiili." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Vertikaalinen synkronointi" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Vsync eli vertikaalinen synkronointi pakottaa näytönohjaimen tarjoamaan uuden kuvan vain silloin, kun näyttö on valmis näyttämään sen." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Vsync (vertikaalinen synkronointi) ei toimi, jos näytönohjaimen ajurit eivät tue sitä." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Partikkelitehosteet: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Animoidut hahmot: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Dynaaminen valaistus: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Valon sironta: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Reunojen pehmennys: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Ambientin okkluusio: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Varjot: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Varjot: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Kukoistus: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Hohto (ääriviivat): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Valokeila (jumalsäteet): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Renderöidyn kuvan laatu: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Liikepehmennys: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Terävyysalue: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Internetin käyttö on estetty. Haluatko käyttää internetiä?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Salasana vaaditaan." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Kirjataan ulos '%s'" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Kirjataan sisään '%s'" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Et voi poistaa ainoaa pelaajaa." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Haluatko varmasti poistaa pelaajan '%s'?" @@ -6065,7 +6328,7 @@ msgstr "MAALI!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Odotetaan muita" @@ -6100,7 +6363,7 @@ msgstr "Seuraa johtajaa!" msgid "Top %i" msgstr "%i:n kärki" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Haasteen suorittaminen epäonnistui" @@ -6124,102 +6387,199 @@ msgstr "Paina palkintokorokkeen kuvaketta aloittaaksesi haasteen" msgid "Press fire to start the challenge" msgstr "Paina ampumisnäppäintä aloittaaksesi haasteen" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Lopeta palvelin" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Keskeytä Grand Prix" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Käynnistä uudelleen" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Takaisin haasteen valintaan" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Kilpaile uutta haamu-uusintaa vastaan" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Takaisin valikkoon" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Haluatko varmasti keskeyttää Grand Prixin?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Punainen joukkue voittaa" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Sininen joukkue voittaa" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Tasapeli" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Poistettu %s jälkeen" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Poistettu" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Oma maali)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Rata %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Grand Prix'n tilanne:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Huippupisteet" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Paras kierrosaika: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "pelaaja %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Suoritit haasteen!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Epäonnistuit haasteessa!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Saavutettiin SuperTuxin vaatimukset" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Kaikki keinot ovat sallittuja, joten poimi aseita ja käytä niitä järkevästi!" @@ -6260,28 +6620,28 @@ msgstr "Paina punaista tai sinistä jalkapallon kuvaketta vaihtaaksesi joukkuett #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Radan tekijä: %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Enimmäispelaajien tuettu määrä: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Punaisen joukkueen tietokoneen ohjaamien autojen määrä" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Et voi pelata tätä Grand Prix'tä, koska se sisältää ratoja, jotka on lukittu!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Lukittu!" @@ -6303,10 +6663,12 @@ msgid "%d/%m/%Y" msgstr "%d.%m.%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Suorita kaikki haasteet avataksesi suuren oven!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6315,41 +6677,48 @@ msgid "" msgstr "Tarvitset enemmän pisteitä\nvoidaksesi ottaa osaa tähän\nhaasteeseen! Katso mini-\nkartasta saatavilla olevat haasteet." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Kiihdytä painamalla <%s>, ohjaa näppäimillä <%s> ja <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Kosketa ratin yläosaa kaasuttaaksesi, ja ohjaa liikuttaen vasemmalle tai oikealle." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Liikuta kaasutinta ylöspäin kaasuttaaksesi, ja ohjaa kallistelemalla laitettasi." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Liikuta kaasutinta ylöspäin kaasuttaaksesi, ja ohjaa kiertämällä laitettasi." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Kerää lahjapaketteja. Näppäimellä <%s> voit ampua paketteja pois." #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Kerää lahjapaketteja, ja paina keilauskuvaketta ampuaksesi nuo laatikot taivaan tuuliin!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6357,34 +6726,41 @@ msgid "" msgstr "Paina <%s> katsoaksesi taakse.\nAmmu painamalla <%s>, ammu taaksepäin pitämällä <%s> pohjassa samanaikaisesti!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Paina peilikuvaketta katsoaksesi taakse.\nAmmu aseella taaksepäin painaen peilikuvaketta pitkään ja sitten sipaisemalla keilauskuvaketta! " #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Käytä keräämääsi nitroa näppäimellä <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Käytä keräämäsi nitro painamalla nitron kuvaketta." #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Kerää nitropulloja (voit käyttää niitä mutkan jälkeen)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "O-ou! Kun olet pulassa, paina <%s> tullaksesi pelastetuksi." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Hups! Kun olet pulassa, paina linnun kuvaketta tullaksesi pelastetuksi." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6392,24 +6768,27 @@ msgid "" msgstr "Kaasuta ja paina <%s> näppäintä samalla kun käännyt liirtämään.\nLyhytaikainen liirto auttaa sinua kääntymään nopeammin tehdäksesi tiukkoja käännöksiä. " #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Kaasuta ja paina liirtokuvaketta liirtoon kääntyessäsi.\nLyhytaikainen liirto auttaa sinua kääntymään nopeammin tehdäksesi tiukkoja käännöksiä." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Jos onnistut pysymään sivuluisussa useamman sekunnin ajan, saat nopeusbonuksen palkinnoksi!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Olet nyt valmiina kisaamaan. Onnea!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Avoimen lähdekoodin kolmiulotteinen kilpa-ajopeli" @@ -6419,7 +6798,7 @@ msgstr "Avoimen lähdekoodin kolmiulotteinen kilpa-ajopeli" msgid "tux;game;race;" msgstr "tux;game;race;peli;ralli;kilpa-ajo;autopeli;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6427,7 +6806,7 @@ msgid "" "for all ages." msgstr "Ajokit. Nitrot. Toimintaa! SuperTuxKart on 3D avoimen lähdekoodin kolikkopelityylinen kilvanajopeli jossa on kirjava valikoima erilaisia hahmoja, ratoja, ja pelityyppejä. Tavoitteenamme on luoda peli joka on enemmänkin hauska kuin todenmukainen, sekä tarjota nautittava pelikokemus kaikenikäisille." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6436,7 +6815,7 @@ msgid "" "your opponents." msgstr "Pelattavana on useita ratoja eri teemoilla; aja veden alla, maaseudun viljelysmaalla, viidakossa tai jopa avaruudessa! Yritä parhaasi samalla muita autoja vältellen, ja muista olla syömättä banaaneja! Varo keilapalloja, imukuppeja, purukumia ja kakkuja, joita muut pelaajat kohdistavat vastustajiin." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6445,27 +6824,27 @@ msgid "" "your racing skills!" msgstr "Voit suorittaa yksittäisiä kisoja muita ajokkeja vastaan, ottaa mittaa jossakin lukuisista Grand Prix -osakilpailuista, pyrkiä rikkomaan aikaennätyksiä yksin, pelata taistelumuotoista kahakkaa tietokonetta tai ystäviäsi vastaan ja paljon muuta! Jos mielit isompien haasteiden pariin, aja kilpaa verkkopeleissä, missä pelaajia on kaikkialta maailmasta ja todista ajotaitosi!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Tämä peli ei sisällä mainoksia." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Tämä on epävakaa versio SuperTuxKartista, joka sisältää uusimmat parannukset. Se julkaistaan pääasiallisesti testausta varten, jotta vakaasta STK:sta voidaan tehdä paras mahdollinen kokemus." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Tämä versio on mahdollista asentaa laitteelle vakaan version rinnalle." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Jos tarvitset enemmän vakautta, harkitse vakaan version käyttöä: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "SuperTuxKart-tiimi" diff --git a/data/po/fil.po b/data/po/fil.po index 0e1e23e0b8e..56da293f021 100644 --- a/data/po/fil.po +++ b/data/po/fil.po @@ -3,15 +3,16 @@ # This file is distributed under the same license as the supertuxkart package. # # Translators: -# searinminecraft, 2022-2023 +# searingmoonlight, 2022-2023 +# searingmoonlight, 2025 # searinminecraft, 2022 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: searinminecraft, 2022-2023\n" +"Last-Translator: searingmoonlight, 2025\n" "Language-Team: Filipino (http://app.transifex.com/supertuxkart/supertuxkart/language/fil/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -168,7 +169,7 @@ msgstr "Sa Katapusan ng Mundo" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Bumalik" @@ -190,7 +191,7 @@ msgstr "Pumili ng uri ng kontrol na gusto mo" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Accelerometer" @@ -204,13 +205,13 @@ msgstr "Accelerometer" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Gyroscope" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Steering wheel" @@ -241,35 +242,37 @@ msgstr "Mga Setting sa Touch Device" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "General" @@ -337,30 +340,33 @@ msgstr "I-restore ang mga default" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Kanselahin" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Oo" @@ -538,9 +544,9 @@ msgstr "Sumali" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -601,7 +607,7 @@ msgstr "Hamon" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Progress" @@ -636,7 +642,7 @@ msgstr "I-sumbit" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Bumalik sa Karera" @@ -653,7 +659,7 @@ msgstr "Bumalik sa lobby" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Ulitin ang Karera" @@ -717,12 +723,12 @@ msgstr "Ipasok ang username at email address na ginamit mo sa registration para #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Pangalan" @@ -763,7 +769,7 @@ msgstr "Kahirapan" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Bagito" @@ -775,7 +781,7 @@ msgstr "Bagito" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Intermediate" @@ -787,7 +793,7 @@ msgstr "Intermediate" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Eksperto" @@ -799,7 +805,7 @@ msgstr "Eksperto" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -807,8 +813,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Uri ng laro" @@ -819,8 +825,8 @@ msgstr "Uri ng laro" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Normal na Karera" @@ -833,7 +839,7 @@ msgstr "Normal na Karera" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Pagsubok sa Oras" @@ -841,7 +847,8 @@ msgstr "Pagsubok sa Oras" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Labanan" @@ -850,24 +857,24 @@ msgstr "Labanan" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Soccer" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Password" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "I-bookmark ang server" @@ -878,7 +885,7 @@ msgstr "Magdagdag ng manlalaro" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Pangalan" @@ -972,6 +979,50 @@ msgstr "I-assign sa ESC key" msgid "Assign nothing" msgstr "Mag-assign ng wala" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Mga Inirerekomendang Setting ng Video" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Ang mga inirerekomendang setting ay magiging wasto para sa kasalukuyang resolution." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Anong uunahin ng mga setting?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Pagganap" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Balansehin ang pagganap at kalidad ng graphics" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Kalidad ng graphics" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Sparing energy" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Gusto mo ba ang paggawa ng blur ng mga effect ng graphics?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Simulan ang pagsubok" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -986,11 +1037,11 @@ msgstr "Setup ng Karera" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Magpatuloy" @@ -1031,10 +1082,15 @@ msgstr "Mga Arena" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Naka-install" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "I-edit ang mga paboritong arena" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1044,20 +1100,20 @@ msgstr "Naka-install" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Standard" @@ -1068,12 +1124,12 @@ msgstr "Standard" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Mga Add-On" @@ -1087,27 +1143,28 @@ msgstr "Mga Add-On" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Lahat" @@ -1146,9 +1203,9 @@ msgstr "Ilipat pababa" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Magdagdag" @@ -1185,7 +1242,7 @@ msgstr "Pagpili ng Ghost Replay" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Paghanap ng Itlog" @@ -1232,10 +1289,10 @@ msgstr "Reverse" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Maximum na oras (min.)" @@ -1267,9 +1324,9 @@ msgstr "Kopyahin" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1280,80 +1337,80 @@ msgstr "Palitan ang pangalan" msgid "Save Grand Prix" msgstr "I-save ang Grand Prix" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Tulong sa SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Mga Game Mode" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Mga Powerup" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Mga Saging" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1361,56 +1418,57 @@ msgstr "Mga Saging" msgid "Story Mode" msgstr "Story Mode" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Mga uri ng kart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Multiplayer" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Simulan ang tutorial" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Mangolekta ng asul na gift box, bibigyan ka nila ng mga powerup." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Iwasan ang mga saging!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1418,14 +1476,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Ang pagkolekta ng nitro ay nagbibigyan-daan sa iyo upang magkaroon ng speed boost kapag gusto mo sa pamamagitan ng pag-pindot ng wasto na key o button. Makikita mo ang kasulukuyang lebel ng nitro sa gauge sa ibabang kanan ng screen ng karera." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Kapag may nakita kang button na may lock na parang ganito, kailangan mong magkumpleto ng isang challenge para i-unlock yan." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1434,34 +1492,34 @@ msgid "" "carefully before!" msgstr "Pwede kang mag-skid sa pamamagitan ng pagpindot ng espesyal na key o button. Ang sunud-sunod na maikling skids ay nakakatulong sa paggawa ng sharp na ikot; habang ang medium na skid ay napapalakas ng iyong bilis, ang mahabang skid ay higit pa. Hindi ka maaring tumigil sa pag-ikot habang nagsi-skid, kaya i-orient ang iyong kart nang mabuti bago!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Pwede ka magkaroon ng startup boost sa pamamagitan ng pagpindot ng accelerate na button sa 'Itakda!', bago magsimula ang karera." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Ang mga kasalukuyang key binding ay makikita/mapapalitan sa menu ng Opsyon." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "Nagtatampok ang SuperTuxKart ng ilang uri ng laro:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Regular na Karera: Pinapayagan ang lahat ng suntok, kaya mangolekta ng mga powerup at gamitin sila ng matalino!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Pagsubok ng Oras: Walang mga powerup, kaya mahalaga ang iyong driving skills!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1469,7 +1527,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Sundin ang Pinuno: Tumakbo ng second place, dahil ang huling kart ay madidisqualify sa tuwing ang counter ay magiging zero. Mag-ingat: Ang pagpunta sa harap ng pinuno ay makakatangal sa iyo!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1479,30 +1537,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "May tatlong uri ng labanan: Sa 3 Strikes Battle, kaylangan mong tamaan ang mga iba gamit ng mga armas hangang mawalan sila ng kanilang buong buhay. Sa Free-For-All, ang manlalaro na natamaan ang iba ng pinakamarami ay mananalo sa ibinigay na hit o limitasyon ng oras. Sa Kunin Ang Bandila, kailan ng iyong koponan na kunin ang bandila ng ibang koponan sa sarili mong base ng bandila, hanggat ang iyong bandila ay hindi nakuha ng ibang koponan." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Soccer: Gamitin ang iyong kart para itulak ang bola sa goal." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Paghanap ng Itlog: I-explore ang mga track para hanapin lahat ng nakatagong itlog." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Ghost replay: Makipagkarera laban sa mga ghost replay sa pagsubok ng oras o paghanap ng itlog na mode, at mag-record ng sarili mo!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Pagsubok sa Lap: Kumpletuhin ang pinakamaraming lap hangga't maaari sa isang naibigay na tagal ng oras." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1511,93 +1569,93 @@ msgid "" "wins the cup." msgstr "* Ang marami sa mga uri ng laro na ito ay pwede laruin sa isang Grand Prix Fasion: sa halip na maglaro ng isang karera, maglalaro ka ng marami sa isang hilera. Kung mas mahusay ang iyong ranggo, mas maraming puntos ang makukuha mo. Sa huli, ang manlalaro na may pinakamaraming puntos ang mananalo ng cup." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Para tulungan kang manalo, ito ang mga powerup na pwede mong kolektahin:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "BubbleGum - protektahin ang sarili mo gamit ng shield, o gamitin habang tumitingin sa likod para umiwan ng malagkit na pink puddle sa likod mo." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Zipper - bigigyan ka ng malakas na speed boost. Pero mag-ingat sa mawalan ng kontrol sa iyong kart!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Cake - ibabato sa pinakamalapit na rival, maganda sa maliit na saklaw at mahabang straights. Nakakaapekto rin ito sa mga ibang kart na malapit sa explosion." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Plunger - ibato ng tuwid para ihila ang opponent pabalik, o ibato habang tumitingin sa likod para mawalan ng paningin." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Bowling Ball - dumidiretso hanggang sa tumama, pwede itong tumalbog sa mga pader. Kung tumingin ka sa likod, ibabato ito patalikod." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Parasyut - pinababagal ang lahat ng karts sa mas mataas na posisyon." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Swapper - Ang mga gift box ay magiging saging, mga nitro cans sa bubble gums, at kabaliktaran sa maikling oras." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Basketbol - tumaltalbog pagkatapos ng pinuno, at baka ma-squash at pabagalin ang mga kart sa daanan." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Swatter - Isa-squash ang mga karts na malapit, pinababagal sila. Pwede rin gamitin para tanggalin ang mga parasyut at mga bomba." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Ang pagtama ng saging ay magresulta sa mga sumusunod na ikakabit sa kart:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Anchor - pinababagal ang kart ng bigla-biglaan." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Parasyut - pinababagal ang kart, mas progresibo kaysa sa anchor. Kapag mas mabilis ka, mas malakas na pinababagal sa iyo." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bomba - sasabog pagkatapos ng ilang oras, tinatapon ang kart sa hangin. Bumungo sa isa pang kart para ilipat ang bomba diyan." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Nabihag ng masamang Nolok si Gnu! Ito ang mga ilang tips para tulungan ka:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1606,7 +1664,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Ang icon na ito sa minimap ay nagpapakita ng available na mga hamon na hindi mo pa natatapos. Sa itaas kanan ng screen, sinasabi rin sa iyo kung gaano karami ang puntos na mayroon ka. Magkumpleto ng maraming hamon hangga't maari, at si Nolok ay itatanggap na makipagkarera laban sa iyo. Manalo upang palayain si Gnu!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1614,20 +1672,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Kapag nakakumpleto ka ng hamon, magkakaroon ka ng cup. Ang bawat cup ay nagkakahalaga ng ilang puntos. Kung mas mataas ang kahirapan na natapos ang hamon, mas mahusay na cup at mas maraming puntos ang halaga." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Kapag magkaroon ka ng numero ng puntos na nakalagay sa ibaba ng icon na ito, mareregalo ka ng surprise. May marami na pwedeng kolektahin." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Hindi lahat ng kart ay nagmamaneho ng pareho! Nabibilang sila sa mga klase na may maraming kakaibahan:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1635,7 +1693,7 @@ msgid "" " resistant to explosions." msgstr "Timbang - mayroong tatlong klase ng kart, depende sa kanilang timbang: magaan, daluyan at mabigat. Ang mas mabigat na kart ay hindi gaanong apektado sa mga parasyut at mas lumalaban sa mga pagsabog." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1643,7 +1701,7 @@ msgid "" " especially at low speeds." msgstr "Acceleration - paki-pakinabang sa simula, pagkatapos ng aksidente, o sa mga track na may maraming sharp na kurba. Kapag mas-magaan ang kart, mas mabilis mag-accelerate, lalo na sa mababang bilis." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1651,14 +1709,14 @@ msgid "" " top speed." msgstr "Max speed - kapag mas mataas, mas mabilis ang kart na maaring pumunta. Lalo na paki-pakinabang sa track na may tuwid na linya at banayad na kurba. Ang mga mabigat na kart ay may pinkamataas na bilis" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Nitro effciency - Kapag mas-mataas, mas maraming bilis na makukuha mo sa can ng nitro. Ang mas-magaan na kart ay magkakaroon ng mas-mataas na nitro efficiency." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1666,12 +1724,12 @@ msgid "" "easier it is." msgstr "Kung susundin mong mabuti ang isa pang kart sa loob ng ilang segundo, magkakaroon ka ng slipstream speed bonus kapag nalampasan mo. Kung mas magaan ang iyong kart, mas madali itong gawin." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "Pwedeng laruin ang SuperTuxKart sa multiplayer mode online...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1681,7 +1739,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Una, piliin ang 'online' na icon sa main menu. Pumili ng alinman lokal na networking o global networking (kailangang naka-enable ang internet sa mga opsyon). At pagkatapos, pwede kang alinmang gumawa ng sarili mong server na may custom na opsyon, o maghanap sa listahan ng umiiral na server para i-join. Ang iba diyan ay mga inirerekomenda na server na may opsyonal na ranked na karera." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1691,12 +1749,12 @@ msgid "" "players and the server." msgstr "Kapag nasa isang server, ang isang karera ay magsismula kapag ang may-ari (sinasagisag na may korona) ay gusto. Ang mga opisyal na server ay pwede mag auto-start kapag may tamang laman ng players. Pagkatapos ay pipili ka ng iyong kart at bumoto para sa susunod na track kung saan makikipagkarera. Ang addon track ay pwede lang kapag umiiral ito sa lahat ng naka-join na manlalaro at sa server." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... o sa kasalukuyang device:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1706,7 +1764,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Una, kailangan mo ng maraming input devices. Gamitin ang input configuration screen para i-setup sila. Ang maraming gamepad o joystick ay mas ideal: sa keyboard(s), ang mga player ay kumakailangan ng iba't-ibang set ng keys, at ang karamihan ng keyboards ay hindi angkop para sa multiplayer dahil hindi nila sinusuportahan ang maraming sabay-sabay na keypress." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1726,7 +1784,7 @@ msgstr "Pagpili ng mga High Score" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Pagsubok sa Lap" @@ -1734,9 +1792,9 @@ msgstr "Pagsubok sa Lap" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Grand Prix" @@ -1747,6 +1805,20 @@ msgstr "Grand Prix" msgid "Choose a Kart" msgstr "Pumili ng Kart" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Klase ng Kart" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "I-edit ang mga paboritong kart" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1760,11 +1832,11 @@ msgstr "Splitscreen Multiplayer" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Online" @@ -1781,7 +1853,7 @@ msgstr "Tutorial" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Mga High Score" @@ -1789,7 +1861,7 @@ msgstr "Mga High Score" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Mga Achievement" @@ -1843,30 +1915,30 @@ msgstr "Maghanap ng Server" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Gumawa ng Server" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Lobby" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Configuration" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Simulan ang karera" @@ -1892,9 +1964,9 @@ msgstr "Ilagay ang address ng server" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Ang iyong profile" @@ -1912,7 +1984,7 @@ msgstr "Mga player ranking" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Mga kaibigan" @@ -1937,7 +2009,7 @@ msgstr "Quick Play" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Mga setting sa Account" @@ -1987,8 +2059,8 @@ msgid "Online Username" msgstr "Online na Pangalan" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "I-reset ang password" @@ -2001,7 +2073,7 @@ msgid "" msgstr "Maari kang maglaro nang hindi gumawa ng online na account sa pamamagitan ng pagpili ng offline na account. Bagaman ay hindi ka makakakonekta sa mga kaibigan, bumoto sa mga addon atbp. Mangyaring basahin ang aming pribadong pahayag sa https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Pagpili ng Server" @@ -2019,339 +2091,409 @@ msgstr "Gamitin ang IPv6 na koneksyon" msgid "User search" msgstr "Paghanap ng user" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Mga Opsyon sa SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Display" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Grapiks" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Audio" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Interface" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Mga Manlalaro" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Controls" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Wika" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Tugtog" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Naka-enable" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Volume" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Mga Sound Effect" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Burahin ang Configuration" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Huwag Paganahin ang Configuration" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Bumalik sa listahan ng device" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Palitan ang pangalan ng Configuration" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Paganahin ang force feedback (kapag sinusuportahan)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Resolusyon" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Fullscreen" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Tandaan ang lokasyon ng window" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "I-apply ang bagong resolusyon" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Layout ng Splitscreen Multiplayer" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Mga opsyon sa internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Palaging ipakita ang login screen" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Kumonekta sa internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "I-enable ang pag-chat online" +msgid "Enable chatting in online lobbies" +msgstr "I-enable ang pag-chat sa mga online na lobby" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "I-enable ang pag-chat sa online na laro" +msgid "Enable chatting in online matches" +msgstr "I-enable ang pag-chat sa mga online na match" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Mga miscellaneous na opsyon" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Paganahin ang per-player handicaps" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "I-uninstall ang punong asset ng laro" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Pindutin ang enter o i-double click ang device para i-configure ito" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Magdagdag ng device" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Aling config ang gagamitin ay mahihinuha kung saan pinindot ang 'Piliin' na key upang sumali sa laro." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Skin" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Minimap" +msgid "Skin variant" +msgstr "Variant ng skin" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Layout ng Splitscreen Multiplayer" +msgid "Minimap" +msgstr "Minimap" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Laki ng font" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Camera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Custom..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Ipakita ang FPS" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Ipakita ang mga hinahawak na powerups ng ibang karts" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Paganahin ang Story mode timer" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Paganahin ang speedrun timer" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Resolusyon ng render" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Lebel ng Graphical Effects" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Lebel ng Blur Effects" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Maximum FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Custom na setting..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Resolusyon" +msgid "Performance tests" +msgstr "Mga pagsubok ng pagganap" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Fullscreen" +msgid "Performance test of the current settings" +msgstr "Pagsubok ng pagganap ng mga kasalukuyang setting" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Tandaan ang lokasyon ng window" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Tandaan ang password" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "I-apply ang bagong resolusyon" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Burahin" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Kulay ng kart" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2378,15 +2520,15 @@ msgstr "Asul na koponan" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Numero ng laps" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Numero ng AI karts" @@ -2401,33 +2543,17 @@ msgstr "Numero ng asul na koponan na AI karts" msgid "Random Grand Prix" msgstr "Random na Grand Prix" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "I-edit ang mga paboritong track" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Mag-login" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Tandaan ang password" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Burahin" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Kulay ng kart" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Pwede palitan ang UI skin sa opsyon ng UI." @@ -2546,238 +2672,306 @@ msgid "" msgstr "Huwag hadlangan ang isang teammate na nagdadala ng bola, kahit na maari mong subukang tamaan ang mga kalaban na sinusubukang pigilin sila mag-iskor." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Antediluvian Abyss" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Alien Signal" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Ancient Colosseum Labyrinth" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Candela City" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Isla ng Paglaban" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Itim na Kagubatan" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Cave X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Templo ng Kakaw" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Tawiran ng Mais" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Fort Magma" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Isla ng Grand Paradiso" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Hole Drop" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Nagyeyelong Soccer Field" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Ano ang mali, maliit na hippies? Ang iyong dakilang pinuno na si Gnu ay nawawala?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Oo, tignan mo, siya na ay nasa aking kastilyo ngayon at ihahain para sa hapunan..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Ngunit ako ay isang makatarungang nilalang, kaya gagawin kita ng isang pakikitungo." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Kung matatalo mo ako sa karera, papalayain ko ang matandang codger." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " Ngunit kayong mga kaawa-awang maliit na twerps ay hinding-hindi makakatalo sa akin - ang Hari ng mga Karts!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Las Dunas Arena" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Las Dunas Soccer Stadium" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Sa paligid ng Parola" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Lumang Minahan" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oasis" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Math Class ni Oliver" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Parke ng Kalabasa" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Ravenbridge Mansion" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Shifting Sands" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Nessie's Pond" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Northern Resort" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Snow Peak" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Soccer Field" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Ang Stadium" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Enterprise" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Templo" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Volcan Island" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Zen Garden" @@ -2786,11 +2980,11 @@ msgstr "Zen Garden" msgid "Completed achievement \"%s\"." msgstr "Nakumpleto ang achievement na \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Nabigong kumonekta sa SuperTuxKart add-ons server." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Nabigong I-download ang news: '%s'." @@ -2856,7 +3050,7 @@ msgid "New kart '%s' now available" msgstr "Ang bagong kart na '%s' ay available na" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2888,32 +3082,32 @@ msgid "" "created." msgstr "Masyadong luma ang iyong config file, kaya binura ito at gagawa ng bago." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Nagsimula ang video recording." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Nai-save ang video sa \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Progress sa encoding:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Tip: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Naglo-load" @@ -2935,19 +3129,18 @@ msgstr "Nitro efficiency" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (handicapped)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "Handa na si %s" @@ -3421,21 +3614,21 @@ msgid "Axis %d" msgstr "Axis %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Gamepad button %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Mouse button %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Mouse axis %d %s" @@ -3607,26 +3800,30 @@ msgstr "Maari kang magkaroon ng hindi hihigit sa 3 na buhay!" msgid "+1 life." msgstr "+1 buhay." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Masyado kang mabagal!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Natapos mo ang karera!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Nanalo ka sa karera!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Natapos mo ang karera sa ranggong %d!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "Umalis sa laro si %s." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3635,16 +3832,16 @@ msgid "" "Internet\")." msgstr "Pwedeng kumonekta ang SuperTuxKart sa isang server para mag-download ng add-ons at mag-notify sa iyo ng updates. Pakibasa ang ating privacy policy sa https://supertuxkart.net/Privacy. Gusto mo bang paganahin ang feature na ito? (Para baguhin ang setting sa ibang pagkakataon, pumunta sa mga opsyon, pindutin ang 'General', at i-edit ang \"Kumonekta sa Internet\")." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Masyadong mababa ang iyong screen resolution para matakbo ang STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Masyadong luma ang iyong driver. Manyaring i-install ang pinakabagong video drivers." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3652,38 +3849,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Mukhang luma ang iyong graphics driver. Paki check kapag may available na update. Inirerekomenda ng SuperTuxKart ang isang driver na sinusuportahan ang %s o mas mahusay. Ang laro ay malamang na tatakbo pa rin, pero sa isang reduced-graphics mode." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Nag-time out ang koneksyon sa server." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "Na kay %s ang pulang bandila!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Bumalik na ang pulang bandila!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "Na kay %s ang asul na bandila!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Bumalik na ang asul na bandila!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "Na-capture ni %s ang asul na bandila!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "Na-capture ni %s ang pulang bandila!" @@ -3693,7 +3890,7 @@ msgstr "Na-capture ni %s ang pulang bandila!" msgid "Eggs: %d / %d" msgstr "Mga Itlog: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Pinuno" @@ -3701,22 +3898,22 @@ msgstr "Pinuno" msgid "Final lap!" msgstr "Huling Lap!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Lap %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s ni %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Bagong pinakamabilis na lap" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "MALING DAANAN!" @@ -3730,194 +3927,194 @@ msgstr "Nakapuntos si %s ng isang goal!" msgid "Oops, %s made an own goal!" msgstr "Oops, gumawa si %s ng sarili niyang goal!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "%i spare tire karts ay nag-spawn na!" msgstr[1] "%i spare tire karts ay nag-spawn na!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Inalis ka na!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "Inalis na si '%s'." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Nag-shut down ang server." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Tinanggal ka sa server." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Tinanggal ka: Masyadong mataas ang iyong ping." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "May nakitang hindi mahusay na koneksyon sa network." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "Nadiskonekta si %s." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Pindutin ang pangalan ng manlalaro para sa management ng mga manlalaro at impormasyon tunkol sa ranking." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Difficulty: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Max na manlalaro: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Uri ng laro: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Takdang oras" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Limitasyon sa Goal" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Uri ng Soccer: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Progress ng Grand prix: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Ang lahat ng tao ay sumali sa pula o asul na koponan." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Ikaw na ang may-ari ng server." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Tinanggihan ang koneksyon: Busy ang server." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Tinanggihan ang koneksyon: Ipinagbawal ka sa server na ito." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Tinanggihan ang koneksyon: Mali ang password ng server." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Tinanggihan ang koneksyon: Hindi tugma ang data ng laro." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Tinanggihan ang koneksyon: Puno na ang server." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Tinanggihan ang koneksyon: Hindi wastong manlalaro ang kumokonekta." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Nabigong magsimula ang network na laro." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Tapos na ang laro, hindi ka na pwedeng mag-join ng live o manood." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Wala nang natitirang lugar sa arena - na-disable ang live join." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "1 player na lang ang natitira, babalik na sa lobby." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Umalis sa laro ang may-ari ng server." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Ikaw ang manonood sa susunod na laro." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "Sumali si %s sa pulang koponan." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "Sumali si %s sa asul na koponan." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "Sumali si %s sa laro. " #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3925,15 +4122,15 @@ msgid "" msgstr "Pindutin ang <%s> o <%s> para palitan ang targeted na manlalaro, <%s> o <%s> para sa posisyon ng camera." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "Matagumpay na naiulat si %s." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3964,38 +4161,38 @@ msgstr "Pagsubok sa Oras (Grand Prix)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Free-For-All" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Kunin ang Bandila" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "Online na si %s." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "Sina %s at %s ay online na." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "Sina %s, %s at %s ay online na." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4003,19 +4200,19 @@ msgstr[0] "%d kaibigan ay online na." msgstr[1] "%d mga kaibigan ay online na." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "Si %s ngayon ay nasa server na \"%s\"" -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "May %d kang bagong friend request!" msgstr[1] "May %d kang bagong friend requests!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "May bago kang friend request!" @@ -4044,12 +4241,12 @@ msgid "" msgstr "Masyadong luma ang highscore file\nlahat ng highscore ay binura na." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Sundan ang Pinuno" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "3 Strikes Battle" @@ -4062,91 +4259,88 @@ msgstr "Hindi mase-save ang hindi kumpletong replay file." msgid "Replay saved in \"%s\"." msgstr "Nai-save ang replay sa \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 linggo" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 linggo" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 buwan" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 buwan" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 buwan" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 buwan" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 taon" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 taon" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Pangalan ng Add-on" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Kailan in-update" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Hindi naka-install" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s ni/nina %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Mangyaring maghintay habang ina-update ang mga addon." -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Paumanhin, may naganap na error habang nakikipag-ugnayan sa add-ons website. Tiyaking nakakonekta ka sa Internet at ang SuperTuxKart ay hindi na-block ng firewall." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Mga paborito" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Naka-lock : lutasin ang mga aktibong hamon upang makakuha ng access sa higit pa!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Random na Arena" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "Ang %d arena ay hindi available sa single player." -msgstr[1] "Ang %d mga arena ay unavailable sa single player" - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nsearinminecraft, 2022" @@ -4434,7 +4628,7 @@ msgstr "Mga nakolektang saging" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Pag-skid" @@ -4537,7 +4731,7 @@ msgstr "Mga natapos na Paghanap ng Itlog" msgid " (official tracks matching the goal)" msgstr "(opisyal na mga track na tumutugma sa goal)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4545,91 +4739,95 @@ msgid "" msgstr "Ang mga bagong gamepad at joystick ay awtomatikong lalabas sa listahan kapag konektahin mo sila sa device mo.\n\nPara magdagdag ng keyboard config, pwede mong gamitin ang button sa baba. PERO pakitandaan na ang karamihan ng mga keyboard ay sinusuportahan lamang ng limitadong halaga ng sabay-sabay na mga keypress at kaya hindi naangkop para sa multiplayer gameplay. (Gayumpaman, maari mong ikonekta ang maraming keyboard sa device na ito. Tandaan na kailangan pa rin ng lahat ng iba't ibang keybinding para sa kasong ito.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Magdagdag ng Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Magdagdag ng Keyboard Configuration" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "I-update" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Bersyon: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "featured" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Laki: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Kailangang naka-login ka para i-rate ang addon na ito." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Paumanhin, nabigo ang pag-download ng add-on." -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Nagkaproblema sa pag-install ng addon na '%s'." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Subukan muli" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Nagkaproblema sa pagtanggal ng addon na '%s'." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Tapos na ang background download." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Background download" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Nagsimula na ang background download." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Hindi angkop ang kasalukuyang password." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Ang password ay dapat nasa pagitan ng 8 at 30 na character pahaba!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Hindi tugma ang mga password!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Pinapatunay ang impormasyon" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Natagumpay na nabago ang password." @@ -4650,67 +4848,97 @@ msgstr "Ang mga resolusyon na mas maliit sa 1024x768 o 1280x720 ay hindi sinusup #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Drone chase" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Custom" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Naka-disable" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Importante lamang" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Mas mababa" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Mababa" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Daluyan" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Mataas" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Mas Mataas" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4718,7 +4946,7 @@ msgid "" msgstr "Magda-download ang SuperTuxKart ng lahat ng assets (kasama ang mataas na kalidad na textures at tugtog) para sa mas magandang karanasan sa laro. Gagamitin ito ng iyong mobile data kapag wala kang koneksyon sa wifi." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4735,101 +4963,102 @@ msgstr "Ipasok ang address ng server na opsyonal na sinusunod ng : at ang port o msgid "Invalid server address: %s." msgstr "Hindi wastong address: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Reverse" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Difficulty" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Mga lap" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Oras" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Kart" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "User" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Bersyon" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Hindi" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Track" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Top %d na high scores" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Numero ng karts: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Target ng oras: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Numero ng laps: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Reverse: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Walang laman)" @@ -4917,33 +5146,41 @@ msgid "Press any key..." msgstr "Pumindot ng kahit anong key..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Naka-disable ang chat, paganahin sa menu ng opsyon." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Bumalik sa Pagsubok ng Pagganap" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Umalis sa Pagsubok ng Pagganap" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Bumalik sa Labanan" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Mag-setup ng bagong laro" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Ulitin ang Laban" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Umails sa Laban" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Mag-setup ng Bagong Karera" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Umalis sa Karera" @@ -4959,11 +5196,11 @@ msgstr "Wala pang ranggo si %s." msgid "%s is number %d in the rankings with a score of %f." msgstr "SI %s ay nasa numerong %d sa mga ranggo na may iskor na %f" -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Hindi angkop ang username at/o email address." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4985,7 +5222,7 @@ msgstr "Ghost replay na karera" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Mga lap: %i" @@ -4998,21 +5235,21 @@ msgstr "Uri: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Kinakailangang Ranggo: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Kinakailangang Oras: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Kinakailangang Nitro Points: %i" @@ -5025,54 +5262,54 @@ msgstr "Numero ng AI Karts: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Labanan" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Uri ng laro ng Soccer" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Lokasyon ng server: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Kasalukuyang track: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Ranggo" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Manlalaro" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Mga Iskor" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Oras na naglaro" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Tanggalin sa bookmarks" @@ -5085,74 +5322,74 @@ msgid "No player available for connecting to server." msgstr "Walang available na manlalaro para sa pagkonekta sa server." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Pangalan: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Kanselahin ang Request" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Ngayon" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Napadala ang friend request!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Tinanggap ang friend request!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Tinanggihan ang friend request!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Tinanggal ang kaibigan!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Kinansela ang friend request!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Pinoproseso" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Kinukuha ang huling boto" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Maari mong iakma ang iyong nakaarang rating sa pamamagitan ng pag-click sa mga bitwin sa ibaba." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Hindi ka pa bumoto para sa addon na ito. Piliin ang iyong gustong rating sa pamamagitan ng pag-click sa mga bitwin sa ibaba." -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Matagumpay ang boto! Pwede mo na ngayong isarado ang window na ito." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Isinasagawa ang boto" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Random na Track" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5181,7 +5418,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "May naganap na error habang sinusubukang i-save ang iyong grand prix." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Pumili ng track" @@ -5225,12 +5462,12 @@ msgstr "Na-unlock mo ang track na %0" msgid "You unlocked grand prix %0" msgstr "Na-unlock mo ang grand prix na %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Track" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5251,19 +5488,19 @@ msgstr "Pakilagay ang pangalan ng grand prix" msgid "Please select a Grand Prix" msgstr "Pumili ng Grand Prix" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "User defined" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Walang laman ang pangalan." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Mayroon nang isang grand prix na may ganitong pangalan." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Masyadong mahaba ang pangalan." @@ -5272,19 +5509,19 @@ msgstr "Masyadong mahaba ang pangalan." msgid "Better luck next time!" msgstr "Baka palarin sa susunod!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Nakakumpleto ka ng hamon!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Nalalo ka sa Grand Prix!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Nakumpleto mo ang Grand Prix!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Numero ng karts" @@ -5297,110 +5534,125 @@ msgstr "Sigurado ka bang gusto mong tanggalin ang high score entry na ito?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Sigurado ka bang gusto mong tanggalin ang lahat ng high score mo?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Paborito" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Magaan" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Mabigat" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Kumonekta ng keyboard o gamepad para maglaro ng splitscreen multiplayer" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Random na Kart" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Naka-lock" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Lahat:\nPindutin ang 'Piliin' na button para sumali sa laro" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Gusto mo bang laruin ang tutorial ng laro na ito?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Hindi ka pwedeng maglaro ng online nang walang access sa Internet. Kung gusto mong maglaro online, pumunta sa menu ng mga opsyon, at i-check ang \"Kumonekta sa Internet\"." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Hindi ka pwedeng mag-download ng mga addon nang walang access sa Internet. Kung gusto mong mag-download ng addons, pumunta sa menu ng mga opsyon, at i-check ang \"Kumonekta sa Internet\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Hindi ka pwedeng mag-download ng mga addon nang walang access sa Internet. Kung gusto mong mag-download ng addons, pumunta sa menu ng mga opsyon, at i-check ang \"Kumonekta sa Internet\".\n\nGayumpaman, maari mong burahin ang mga na-download na addon." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Kasalukuyang hindi pinagana ang module ng mga add-on sa screen ng Mga Opsyon." -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Mangyaring maghintay habang naglo-load ang mga add-on." -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Sigurado ka bang gusto mong umalis sa STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Gumawa ng LAN Server" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Server ni %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Nu. ng mga grand prix track(s)" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Ang pangalan ay dapat nasa pagitan ng 4 at 30 na character pahaba!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Maling characters sa password!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Handa na" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Mag live join" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Manood" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "I-install ang addon" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5408,7 +5660,7 @@ msgstr "Mangyaring hintayin ang pagtatapos ng kasalukuyang laro (%s), tinantayan #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Mangyaring hintayin ang pagtatapos ng kasalukuyang laro, tinantayang natitirang oras: %s." @@ -5416,24 +5668,24 @@ msgstr "Mangyaring hintayin ang pagtatapos ng kasalukuyang laro, tinantayang nat #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Mangyaring hintayin ang pagtatapos ng kasalukuyang laro (%s), tinantayang progress: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Mangyaring hintayin ang pagtatapos ng kasalukuyang laro, tinantayang progress: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Mangyaring hintayin ang pagtatapos ng kasalukuyang laro." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5442,7 +5694,7 @@ msgstr[1] "Magsisimula ang laro kung higit sa %d mga manlalaro." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5451,96 +5703,108 @@ msgid_plural "" msgstr[0] "Magsisimula pagkatapos ng %d segundo, o kapag pinindot na ng lahat ang 'Handa na' na button." msgstr[1] "Magsisimula pagkatapos ng %d segundo, o kapag pinindot na ng lahat ang 'Handa na' na button." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Kumokonekta sa server na %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Naghahanap ng quick play server" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Natitrang oras: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Mga goal" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Kinukuha ang mga achievements" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Profile ni %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Noong" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Status" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Kinukuha ang mga kaibigan" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Bagong Request" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Pending" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Offline" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Maglagay ng bagong E-mail sa ibaba" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Ang Bagong Email ay dapat nasa pagitan ng 5 at 254 na character ang haba!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Hindi wasto ang bagong Email!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "Nabago ang E-mail!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Nabigong baguhin ang E-mail: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Balita mula sa STK Blog" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Petsa" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Walang available na balita sa ngayon." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Dapat kang naka-log in upang maglaro ng Global networking. I-click ang iyong username sa itaas." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Naghahanap" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Umalis sa laro" @@ -5618,34 +5882,34 @@ msgid "Distance (km)" msgstr "Distansya (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Hindi alam" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Walang natukoy na IPv4. Maaring hindi ka makasali sa kahit anong server." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Walang natukoy na IPv6. Maaring hindi ka makasali sa kahit anong server." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Walang available na server." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Kinukuha ang mga server" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Mga server bookmark" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5653,149 +5917,149 @@ msgstr "Kung ang karamihan sa mga manlalaro ay pipili ng parehong mga setting ng #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Random na lokasyon ng item" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Bilang ng goals upang manalo" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Magmaneho nang reverse" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Naka-lock : lutasin ang mga aktibong hamon upang makakuha ng access sa higit pa!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Aksyon" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Key Binding" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Huwag Paganahin ang Device" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Paganahin ang Device" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Paganahin ang Configuration" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Mga keys ng Laro" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Mga keys ng Menu" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Lumiko sa Kaliwa" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Lumiko sa Kanan" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Mag-accelerate" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Brake / Reverse" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Fire" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Tumgingin sa Likod" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Rescue" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "I-pause ang laro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Pataas" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Pababa" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Kaliwa" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Kanan" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Piliin" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Kanselahin/Bumalik" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Ang isang asul na item ay nangangahulugang isang salungatan sa isa pang configuration" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Ang isang pulang item ay nangangahulugang isang salungatan sa kasalukuyang configuration" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5803,17 +6067,27 @@ msgid "" msgstr "Babala: Hindi inirerekomenda ang 'Shift' key. Kapag pinindot ang 'Shift', hindi gagana ang mga keys na naglalaman ng character na naiiba sa upper-case." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Sigurado ka bang gusto mong permanenteng tanggalin ang configuration na ito?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Maglagay ng bagong pangalan ng configuration, iwanang walang naman upang ibalik sa default na value." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Patayo" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Pahalang" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5821,89 +6095,74 @@ msgstr "Sa multiplayer mode, maaaring pumili ang mga manlalaro ng mga profile na #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "I-install ang punong asset ng laro" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Sigurado ka bang i-uninstall ang buong asset ng laro?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Keyboard %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Touch Device" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Pumindot sa isang device para i-configure." #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Wika ng System" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Sa ibabang kaliwa" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "Sa kanang bahagi" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Nakatago" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Nakasentro" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Patayo" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Pahalang" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Mas maliit" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Maliit" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Daluyan" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Malaki" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Mas malaki" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5913,128 +6172,133 @@ msgid "" msgstr "Mae-enable lang ang speedrun mode kapag hindi isinarado ang laro noong ilunsad ang story mode.\n\nAng pagsara ng laro bago ang katapusan ng story mode ay mapapawalang-bisa sa timer.\n\nPara gamitin ang speedrun mode, mangyaring gumamit ng bagong profile." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Vertical Sync" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Pinipilit ng Vsync ang graphics card na magbigay ng bagong frame\nkapag handa na ang monitor na ipakita ito." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Hindi gagana ang Vsync kapag hindi ito sinusuportahan ng iyong driver." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Particles Effects: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Gumagalaw na characters: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Dinamika na ilaw: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Pagkalat ng ilaw: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Anti-ailasing: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Ambient occlusion: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Mga anino: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Mga anino: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Bloom: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Glow (Mga outline): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Light shaft (God rays): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Rendered na kalidad ng imahe: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Detalye ng geometry: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Motion blur: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Depth of field: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Naka-disable ang access sa Internet. Gusto mo ba itong paganahin?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Kailangang mong magpasok ng password." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Logging out '%s'" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Logging in '%s'" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Hindi mo pwedeng tanggalin ang nag-iisang manlalaro." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Gusto mo ba talagang tanggalin ang manlalaro na si '%s'?" @@ -6062,7 +6326,7 @@ msgstr "GOAL!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Hinihintay ang iba" @@ -6097,7 +6361,7 @@ msgstr "Sundan ang Pinuno!" msgid "Top %i" msgstr "Top %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Nabigo ang Hamon" @@ -6121,102 +6385,199 @@ msgstr "Pindutin ang icon ng podium para simulan ang hamon" msgid "Press fire to start the challenge" msgstr "Pindutin ang fire para simulan ang hamon" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Bumalik sa mga setting ng video" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "I-save ang mga resulta ng pagsubok" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Bumalik sa main menu" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Umalis sa server" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "I-abort ang Grand Prix" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Ulitin" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Bumalik sa pagpili ng hamon" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Makipagkarera laban sa bagong ghost replay" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Bumalik sa menu" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Gusto mo ba talagang i-abort ang Grand Prix?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Na-save ang ulat ng pagganap sa \"%s\"" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Nalalo ang Pulang Koponan" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Nalalo ang Asul na Koponan" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Isang draw ito" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Tinanggal pagkatapos ng %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Tinanggal" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Sariling Goal)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Track %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Grand Prix progress:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Mga highscore" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Pinakamahusay na lap time: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "ni/nina %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Nakumpleto mo ang hamon!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Nabigo ka sa hamon!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Naabot ang mga kinakailangan ng SuperTux" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Mga Resulta ng Pagsubok ng Pagganap" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Tagal ng Pagsubok: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Numero ng mga frame: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "Steady FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "Halos Steady na FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "Tipikal na FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Horizontal resolution: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Vertical resolution: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Dinamika na ilaw: ON" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Dinamika na ilaw: OFF" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Render resolution: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Anti-aliasing: ON" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Anti-aliasing : OFF" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Image-based na ilaw: OFF" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr " Image-based na ilaw: ON" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Ambient occlusion: ON" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Ambient occlusion: OFF" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Resolusyon ng shadow: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Pinapayagan ang lahat ng suntok, kaya kumuha ng mga armas at gamitin ang mga ito ng matalino!" @@ -6257,28 +6618,28 @@ msgstr "Pindutin ang pula o asul na soccer icon para palitan ang team." #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Track na ginawa ni/nina %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Max na manlalaro na sinusuportahan: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Numero ng pulang koponan na AI karts" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Hindi mo maaring laruin ang Grand Prix na ito dahil naglalaman ito ng mga track na hindi pa naka-unlock!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Naka-lock!" @@ -6300,10 +6661,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Kumpletuhin ang lahat ng mga hamon upang i-unlock and malaking pintuan!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6312,41 +6675,48 @@ msgid "" msgstr "Kailangan mo ng higit pang puntos\npara makapasok sa hamon na ito!\nTignan ang minimap para sa mga\navailable na hamon!" #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Mag-accelerate gamit ng <%s>, at umikot gamit ng <%s> at <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Mag-accelerate sa pamamagitan ng pagpindot sa itaas na bahagi ng gulong, at mag-steer sa pamamagitan ng paggalaw pakaliwa o pakanan." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Mag-accelerate sa pamamagitan ng paggalaw ng accelerator pataas, at umikot sa pamamagitan ng pag-ikot ng iyong device." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Mag-accelerate sa pamamagitan ng paggalaw ng accelerator pataas, at umikot sa pamamagitan ng pag-ikot ng iyong device." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Mangolekta ng mga gift box, at i-fire ang armas gamit ng <%s> upang tangayin ang mga kahon na ito!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Mangolekta ng mga gift box, at i-fire sa pamamagitan ng pagpindot ng bowling icon upang tangayin ang mga kahon na ito!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6354,34 +6724,41 @@ msgid "" msgstr "Pindutin ang <%s> para tumingin sa likod.\\nI-fire ang armas gamit ang <%s> habang pinindot ang <%s> para mag-fire sa likod!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Pindutin ang mirror icon upang tumingin sa likod.\\nI-fire ang armas sa likod sa pamamagitan ng pagpindot sa mirror icon at pagkatapos ay mag-swipe sa bowling icon!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Gamitin ang nitro na iyong nakolekta sa pamamagitan ng pagpindot sa <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Gamitin ang nitro na iyong nakolekta sa pamamagitan ng pagpindot ng nitro icon" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Mangolekta ng nitro bottle (gamamitin natin ang mga ito pagkatapos ng kurba)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Oops! Kapag nagkakaproblema ka, pindutin ang <%s> para makailigtas." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Oops! Kapag nagkakaproblema ka, pindutin ang icon ng ibon upang makailigtas." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6389,24 +6766,27 @@ msgid "" msgstr "Mag-accelerate at pindutin ang <%s> key habang lumiliko para mag-skid.\nMakakatulong sa iyo ang pag-skid nang panandalian na lumiko nang mas mabilis para umikot." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Mag-accelerate at pindutin ang skid icon habang lumiliko para mag-skid.\nMakakatulong sa iyo ang pag-skid nang panandalian na lumiko nang mas mabilis para umikot." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Tandaan na kung nagawa mong mag-skid ng ilang segundo, makakatanggap ka ng bonus speedup bilang reward!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Handa ka nang makipagkarera. Good luck!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Isang 3D at open-source na kart racing game." @@ -6416,7 +6796,7 @@ msgstr "Isang 3D at open-source na kart racing game." msgid "tux;game;race;" msgstr "tux;game;race;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6424,7 +6804,7 @@ msgid "" "for all ages." msgstr "Mga Kart, Nitro, Aksyon! Ang SuperTuxKart ay isang 3D at open-source na arcade racer na may iba't ibang character, track, at modes na laruin. Ang aming layunin ay lumikha ng isang laro na mas masaya kaysa makatotohanan, at magbigay ng kasiya-siyang karanasan para sa lahat ng edad. " -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6433,7 +6813,7 @@ msgid "" "your opponents." msgstr "Mayroon kaming ilang track na may iba't ibang tema para sa mga manlalaro upang tamasahin, mula sa pagmaneho sa tubig, rural farmlands, jungles, o kahit naman sa space! Subukan ang iyong makakaya habang umiiwas sa iba pang mga kart dahil maaring maabutan ka nila, ngunit huwag kainin ang mga saging! Tumingin para sa mga bowling ball, mga plunger, bubble gum, at cake na ibinato ng iyong mga kalaban." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6442,27 +6822,27 @@ msgid "" "your racing skills!" msgstr "Maari kang gumawa ng isang karera laban sa ibang mga kart, makipagkumpetensya sa isa sa maraming Grand Prix, subukang talunin ang mga high score sa mga pagsubok sa oras o mag-isa. maglaro ng battle mode laban sa computer or sa iyong mga kaibigan, at higit pa! Para sa mas malaking hamon, sumali online at makilala ang mga manlalaro mula sa buong mundo at patunayan ang iyong driving skills!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Walang mga ad ang laro na ito." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Ito ay isang unstable na bersyon ng SuperTuxKart na naglalaman ng pinakabagong improvement. Ito ay inilabas pangunahin para sa pagsubok, upang gawing mas mahusay ang STk hangga't maari." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Maaaring i-install ang bersyon na ito nang kahanay sa stable na bersyon sa device" -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Kung gusto mo ng higit pang stability, isaalang-alang ang paggamit ng stable na bersyon: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "SuperTuxKart Team" diff --git a/data/po/fr.po b/data/po/fr.po index 5ee7f4744c5..b5fbc803b3e 100644 --- a/data/po/fr.po +++ b/data/po/fr.po @@ -4,7 +4,7 @@ # # Translators: # adrien vigneron , 2015 -# Alayan, 2018-2019,2024 +# Alayan, 2018-2019,2024-2025 # alfu5, 2022 # Anard0 , 2020 # Anard0 , 2020 @@ -21,6 +21,7 @@ # Éfrit, 2015 # florian mesnier, 2021 # florian mesnier, 2021 +# Jérôme HERBINET, 2025 # Jérôme HERBINET, 2023 # Loïs Doyenard, 2021 # Loïs Doyenard, 2021 @@ -36,9 +37,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Alayan, 2018-2019,2024\n" +"Last-Translator: Alayan, 2018-2019,2024-2025\n" "Language-Team: French (http://app.transifex.com/supertuxkart/supertuxkart/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -112,7 +113,7 @@ msgstr "Un vrai pilote de Formule 1 !" msgid "" "Win against at least 3 AIs in normal race, time-trial, and follow the " "leader." -msgstr "Gagne contre au moins 3 IA dans les modes Course normale, Course contre la montre et Suivez-le-Chef." +msgstr "Gagne contre au moins 3 IA dans les modes Course normale, Course contre-la-montre et Suivez-le-Meneur." #. I18N: ./data/achievements.xml msgid "Powerup Love" @@ -195,7 +196,7 @@ msgstr "Au bout du monde" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Retour" @@ -217,7 +218,7 @@ msgstr "Sélectionne un type de contrôleur que tu préfères" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Accéléromètre" @@ -231,13 +232,13 @@ msgstr "Accéléromètre" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Gyroscope" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Volant de voiture" @@ -268,35 +269,37 @@ msgstr "Paramètres de l'écran tactile" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Général" @@ -364,30 +367,33 @@ msgstr "Revenir aux valeurs par défaut" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Annuler" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Oui" @@ -565,9 +571,9 @@ msgstr "Rejoindre" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -628,7 +634,7 @@ msgstr "Objectif" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Avancement" @@ -663,7 +669,7 @@ msgstr "Soumettre" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Retour à la course" @@ -680,7 +686,7 @@ msgstr "Retour au salon" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Recommencer la course" @@ -744,12 +750,12 @@ msgstr "Saisis le nom et l’adresse de messagerie que tu as fournis lors de l #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Nom d’utilisateur" @@ -790,7 +796,7 @@ msgstr "Difficulté" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Novice" @@ -802,7 +808,7 @@ msgstr "Novice" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Intermédiaire" @@ -814,7 +820,7 @@ msgstr "Intermédiaire" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Expert" @@ -826,7 +832,7 @@ msgstr "Expert" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -834,8 +840,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Mode de jeu" @@ -846,8 +852,8 @@ msgstr "Mode de jeu" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Course normale" @@ -860,7 +866,7 @@ msgstr "Course normale" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Contre-la-montre" @@ -868,7 +874,8 @@ msgstr "Contre-la-montre" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Bataille" @@ -877,24 +884,24 @@ msgstr "Bataille" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Football" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Mot de passe" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Ajouter ce serveur aux favoris" @@ -905,7 +912,7 @@ msgstr "Ajouter le joueur" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Nom" @@ -999,6 +1006,50 @@ msgstr "Assigner à la touche Échap" msgid "Assign nothing" msgstr "Ne rien assigner" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Recommander des paramètres vidéo" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Les paramètres recommandés seront valables pour la résolution actuelle." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Que doivent privilégier les paramètres ?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Performance" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Équilibre entre performance et qualité d'image" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Qualité d'image" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Économie d'énergie" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Appréciez-vous les effets graphiques de flou ?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Lancer le test" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -1013,11 +1064,11 @@ msgstr "Réglages de la course" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Continuer" @@ -1058,10 +1109,15 @@ msgstr "Arènes" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Installé" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Modifier les arènes favorites" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1071,20 +1127,20 @@ msgstr "Installé" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Standard" @@ -1095,12 +1151,12 @@ msgstr "Standard" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Extensions" @@ -1114,27 +1170,28 @@ msgstr "Extensions" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Tout" @@ -1173,9 +1230,9 @@ msgstr "Descendre d’un niveau" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Ajouter" @@ -1212,7 +1269,7 @@ msgstr "Sélection d'un enregistrement" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Chasse aux œufs" @@ -1259,10 +1316,10 @@ msgstr "À l’envers" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Temps maximum (min.)" @@ -1294,9 +1351,9 @@ msgstr "Copier" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1307,80 +1364,80 @@ msgstr "Renommer" msgid "Save Grand Prix" msgstr "Enregistrer le Grand Prix" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Aide SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Modes de jeu" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Bonus" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Bananes" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1388,56 +1445,57 @@ msgstr "Bananes" msgid "Story Mode" msgstr "Mode histoire" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Classes de karts" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Multijoueur" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Débuter le tutoriel" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Ramasse les cadeaux bleus, ils te donneront des bonus." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Évite les bananes !" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1445,14 +1503,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Collecter de la nitro vous permet d'avoir un bonus de vitesse quand vous le souhaitez en pressant la touche ou le bouton approprié. Vous pouvez voir votre niveau actuel de nitro dans la jauge en bas à droite de l'interface de course." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Si tu vois un bouton avec un cadenas comme celui-ci, tu dois réussir un défi pour le déverrouiller." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1461,42 +1519,42 @@ msgid "" "carefully before!" msgstr "Vous pouvez déraper en pressant une touche ou un bouton spécial. De courts dérapages successifs aident dans les virages serrés, des dérapages moyens augmentent votre vitesse, des longs davantage. Vous ne pouvez pas arrêter de tourner en cours de dérapage, donc avant cela orientez votre kart soigneusement !" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Vous pouvez obtenir une impulsion au début de la course en appuyant sur le bouton d'accélération lorsque \"Prêt\" s'affiche." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Les commandes peuvent être consultées ou modifiées dans le menu Options" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart contient plusieurs modes de jeu :" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Course normale : tous les coups sont permis, alors collecte des bonus et utilise-les judicieusement !" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Contre-la-montre : Pas de bonus - seuls tes talents de conduite comptent !" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " "disqualified every time the counter hits zero. Beware: going in front of the" " leader will get you eliminated too!" -msgstr "Suivez-le-Chef : vise la deuxième place, car le dernier kart sera éliminé à chaque fois que le décompte atteint zéro. Attention : dépasser le chef (le meneur) vous éliminera également !" +msgstr "Suivez-le-Meneur : vise la deuxième place, car le dernier kart sera éliminé à chaque fois que le décompte atteint zéro. Attention : dépasser le meneur vous éliminera également !" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1506,30 +1564,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Il y a trois types de modes de bataille : Dans Bataille en 3 coups, vous aurez besoin de toucher les autres avec des armes avant qu'ils ne perdent toutes leurs vies. Dans Chacun pour soi, le joueur qui touche les autres le plus gagnera suivant un certain objectif de coups ou dans le temps imparti. Dans Capture le drapeau, votre équipe à besoin de ramener le drapeau de l'autre équipe à votre propre base, tant que votre drapeau n'est pas capturé par l'autre équipe." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Football : Utilise ton kart pour pousser le ballon dans le but." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Chasse aux œufs : Explore les pistes afin de trouver tous les œufs cachés." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Course contre un enregistrement : Faites la course contre des enregistrements fantômes en mode contre-la-montre ou chasse aux œufs, et enregistrez les vôtres !" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Tours contre-la-montre : terminer autant de tours que possible en un temps donné" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1538,93 +1596,93 @@ msgid "" "wins the cup." msgstr "* Beaucoup de ces modes de jeux peuvent être joués à la manière du Grand Prix: au lieu d’une seule course, vous en disputez plusieurs à la suite. Plus vous atteignez une place élevée du classement, et plus vous gagnez de points. À la fin, le joueur ayant le plus de points remporte la coupe." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Pour t'aider à gagner, il y a des bonus que tu peux ramasser :" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Chewing-gum - te protège avec un bouclier, ou laisse une flaque rose collante derrière toi lorsque tu regardes en arrière." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Zipper - vous donne un puissant bonus de vitesse. Mais attention à ne pas perdre le contrôle de votre kart !" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Gâteau - se lance sur ton plus proche rival, idéal à courte distance et sur de longues routes droites. Affecte aussi les autres karts près de l'explosion." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Ventouse - lance-la droit devant pour tirer un opposant vers l’arrière, ou lance-la en regardant en arrière pour obstruer la vue d’un concurrent." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Boule de bowling - roule en ligne droite jusqu'à ce qu'elle frappe, elle peut rebondir sur les murs. Elle sera lancée en arrière si tu regardes derrière toi." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Parachute - ralentit tous les karts en meilleure position." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Échangeur - pour une courte durée, les cadeaux sont transformés en bananes, les nitros sont transformées en chewing-gums, et vice-versa." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." -msgstr "Balle de basket - poursuit le meneur en rebondissant, et peut écraser et ralentir les karts sur son passage." +msgstr "Ballon de basket - poursuit le meneur en rebondissant, et peut écraser et ralentir les karts sur son passage." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Tapette à mouche - aplatit les karts qui s'approchent de toi pour les ralentir. Peut aussi enlever les parachutes et les bombes." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Un kart qui frappe une banane se retrouvera avec un de ces malus :" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Ancre - ralentit le kart subitement." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Parachute - ralentit le kart plus progressivement que l'ancre. Plus le kart va vite, plus le ralentissement est important." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bombe - explose en lançant le kart dans les airs après une courte période de temps. Cogne ton kart sur un adversaire pour lui passer la bombe." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Le vil Nolok a capturé Gnu ! Voici quelques conseils pour vous aider :" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1633,7 +1691,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Cette icône sur la mini-carte montre les défis disponibles que vous n'avez pas complétés. Dans le coin supérieur-droit de l'écran, elle vous indique aussi combien de points vous avez actuellement. Complétez autant de défis que possible, et Nolok acceptera de faire la course contre vous. Gagnez pour libérer Gnu !" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1641,20 +1699,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Quand vous complétez un défi, vous obtenez une coupe. Chaque coupe vaut plusieurs points. Plus la difficulté dans laquelle vous avez complété le défi est élevée, meilleure est la coupe et plus elle vaut de points." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Quand tu obtiendras le nombre de points indiqué sous cette icône, tu recevras une surprise. Il y en a plusieurs à collectionner." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Les karts ne se conduisent pas tous pareil ! Ils appartiennent à des classes avec plusieurs différences :" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1662,7 +1720,7 @@ msgid "" " resistant to explosions." msgstr "Masse - il y a trois classes de karts, selon leur masse : léger, moyen et lourd. Les karts plus lourds sont moins affectés par les parachutes et sont plus résistants aux explosions." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1670,7 +1728,7 @@ msgid "" " especially at low speeds." msgstr "Accélération - particulièrement utile au départ, après un accident, ou dans les circuits avec beaucoup de virages serrés. Plus un kart est léger, plus il accélère vite, en particulier quand sa vitesse est faible." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1678,14 +1736,14 @@ msgid "" " top speed." msgstr "Vitesse maximale - plus elle est élevée, plus vite va le kart. Particulièrement utile dans les circuits avec des lignes droites et des virages peu serrés. Les karts plus lourds ont une plus grande vitesse maximale." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Efficacité nitro - Plus elle est élevée, plus la nitro augmente la vitesse. Un kart léger aura une plus grande efficacité nitro." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1693,12 +1751,12 @@ msgid "" "easier it is." msgstr "Si vous suivez de près un autre kart pendant quelques secondes, vous obtiendrez un bonus d'aspiration quand vous le doublerez. Plus votre kart est léger, plus c'est facile." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "Il est possible de jouer à SuperTuxKart en multijoueur en réseau... :" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1708,7 +1766,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "D'abord, choisissez l'icône \"En ligne\" dans le menu principal. Choisissez le réseau local, ou le réseau global (nécessite qu'Internet soit activé dans les options). Puis, vous pouvez alors créer votre propre serveur avec des options personnalisées, ou chercher parmi une liste de serveurs à rejoindre. Certains d'entre eux sont des serveurs sûr, pour certains avec des courses classées." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1718,12 +1776,12 @@ msgid "" "players and the server." msgstr "Une fois dans un serveur, une course débutera quand son propriétaire (symbolisé par la couronne) le décide. Un serveur officiel peut être configuré pour débuter automatiquement une fois qu'il y a assez de joueurs. Vous pouvez alors choisir votre kart et voter pour la prochaine piste. Une piste extension est offerte seulement si elle est installée chez tous les joueurs connectés au serveur." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... ou sur le même appareil:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1733,7 +1791,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Tout d’abord, tu vas avoir besoin de plusieurs périphériques. Va dans le menu de configuration pour les régler. Avoir plusieurs manettes est idéal : sur clavier, chaque joueur aura besoin d’un ensemble différent de touches, et la plupart des claviers ne sont pas appropriés pour le jeu multijoueur car ils ne supportent qu’un nombre limité d’appuis de touches simultanés." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1746,14 +1804,14 @@ msgstr "Lorsque plusieurs périphériques sont configurés, sélectionne 'Multij #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen msgid "High Score Selection" -msgstr "Sélection du score" +msgstr "Sélection des meilleurs scores" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Tours contre-la-montre" @@ -1761,9 +1819,9 @@ msgstr "Tours contre-la-montre" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Grand Prix" @@ -1774,6 +1832,20 @@ msgstr "Grand Prix" msgid "Choose a Kart" msgstr "Choisis un kart" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Classe de kart" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Modifier les karts favoris" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1787,11 +1859,11 @@ msgstr "Multijoueur écran divisé" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "En ligne" @@ -1808,7 +1880,7 @@ msgstr "Tutoriel" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Meilleurs scores" @@ -1816,7 +1888,7 @@ msgstr "Meilleurs scores" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Succès" @@ -1870,30 +1942,30 @@ msgstr "Trouver un serveur" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Créer un serveur" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Salle d’attente" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Configuration" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Commencer la course" @@ -1919,9 +1991,9 @@ msgstr "Entrez l'adresse du serveur" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Ton profil" @@ -1939,7 +2011,7 @@ msgstr "Classement des joueurs" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Amis" @@ -1964,7 +2036,7 @@ msgstr "Partie rapide" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Paramètres du compte" @@ -1980,7 +2052,7 @@ msgstr "Modifier" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: In the online account settings screen msgid "E-mail:" -msgstr "Email : " +msgstr "E-mail : " #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog @@ -2014,8 +2086,8 @@ msgid "Online Username" msgstr "Nom d’utilisateur en ligne" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Réinitialiser le mot de passe" @@ -2028,14 +2100,14 @@ msgid "" msgstr "Tu peux jouer sans créer de compte en ligne en sélectionnant un compte hors-ligne. Toutefois, tu ne pourras pas communiquer avec tes amis, noter les extensions, etc. Merci de lire notre déclaration de confidentialité sur https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Sélection du serveur" #. I18N: ./data/gui/screens/online/server_selection.stkgui #. I18N: In the server selection screen msgid "Show private server(s)" -msgstr "Afficher les serveurs privées" +msgstr "Afficher les serveurs privés" #. I18N: ./data/gui/screens/online/server_selection.stkgui #. I18N: In the server selection screen @@ -2046,339 +2118,409 @@ msgstr "Utiliser la connexion IPv6" msgid "User search" msgstr "Recherche d’utilisateurs" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Options SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Affichage" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Graphismes" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Audio" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Interface" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Joueurs" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Commandes" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Langue" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Musique" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Activé" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Volume" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Effets sonores" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Supprimer la configuration" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Désactiver la configuration" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Retour à la liste des périphériques" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Renommer la configuration" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Activer le retour de force (si supporté)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Résolution" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Plein écran" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Mémoriser la position de la fenêtre" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Appliquer la nouvelle résolution" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Affichage avec l'écran partagé pour jouer à plusieurs" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Options Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Toujours afficher l’écran de connexion" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Se connecter à Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Activer le chat en ligne" +msgid "Enable chatting in online lobbies" +msgstr "Activer le chat dans les salons de serveur" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" +msgid "Enable chatting in online matches" msgstr "Activer le chat durant les parties en ligne" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Options diverses" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Activer les handicaps par joueur" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Désinstalle tout les actifs de tout le jeu" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Appuie sur Entrée ou double-clique sur un périphérique pour le configurer" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Ajouter un périphérique" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* La configuration à utiliser sera déduite de la touche « Sélectionner » utilisée pour rejoindre la partie." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Thème" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Minicarte" +msgid "Skin variant" +msgstr "Variante du thème" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Affichage avec l'écran partagé pour jouer à plusieurs" +msgid "Minimap" +msgstr "Minicarte" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Taille de la police" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Caméra" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Personnaliser..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Afficher le nombre d’images par seconde (FPS)" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Afficher les bonus tenus par les autres karts" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Activer le chronomètre en mode histoire" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Activer le chronomètre pour speedrun" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Résolution de rendu" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Niveau d’effets visuels" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Niveau d'effets de flou" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "FPS maximum" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Paramètres personnalisés…" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Résolution" +msgid "Performance tests" +msgstr "Tests de performance" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Plein écran" +msgid "Performance test of the current settings" +msgstr "Test de performance des paramètres actuels" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Mémoriser la position de la fenêtre" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Mémoriser le mot de passe" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Appliquer la nouvelle résolution" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Supprimer" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Couleur du kart" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2405,15 +2547,15 @@ msgstr "L'équipe des bleus" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Nombre de tours" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Nombre de karts IA" @@ -2428,33 +2570,17 @@ msgstr "Nombre de karts IA équipe bleu" msgid "Random Grand Prix" msgstr "Grand Prix aléatoire" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Modifier les pistes favorites" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "S'identifier" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Mémoriser le mot de passe" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Supprimer" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Couleur du kart" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "L´interface graphique peut être modifiée dans le menu des options d'interface." @@ -2486,7 +2612,7 @@ msgstr "Utiliser la nitro par courtes impulsions est plus efficace." #. I18N: ./data/tips.xml msgid "Only use zippers when it is safe. Long straight lines are ideal." -msgstr "Utilise les zippers uniquement lorsque c'est sécuritaire. Les longues lignes droites sont idéales." +msgstr "N'utilise les zippers que lorsque c'est sans danger. Les longues lignes droites sont idéales." #. I18N: ./data/tips.xml msgid "" @@ -2573,238 +2699,306 @@ msgid "" msgstr "Ne vous placez jamais sur la voie d´un coéquipier en train de rapporter la balle, cependant vous pouvez cogner les adversaires pour les empêcher de marquer des points." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Abysses antédiluviennes" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" -msgstr "Signal Sidéral" +msgstr "Signal extraterrestre" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" -msgstr "Antique Colisée labyrinthique" +msgstr "Labyrinthe du Colisée antique" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "La cité Candela" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" -msgstr "Île de comaa" +msgstr "Île de bataille" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Forêt-Noire" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Caverne X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Temple cacao" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Croisée campagnarde" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Fort magma" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "L’île Grand Paradiso" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" -msgstr "Trou de Chute" +msgstr "Cercles creux" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Terrain de football glacé" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Qu’est-ce qui se passe les petits hippies ? Votre grand chef gnou a disparu ?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Oh oui, vois-tu, il est dans mon château en ce moment et il sera servi pour le dîner …" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Mais je suis une créature honnête, alors je vais te faire une offre." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Si tu me bats à la course, je libérerai le vieux bonhomme." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "Mais jamais de pathétiques petits abrutis comme vous ne réussiront à me vaincre moi, le roi du karting !" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "Arène Las Dunas" +msgstr "Arène de Las Dunas" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" -msgstr "Le stade de soccer Las Dunas " +msgstr "Stade de football de Las Dunas" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Autour du phare" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Vieille mine" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oasis" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Classe de maths d’Oliver" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" -msgstr "Parc des potirons" +msgstr "Parc aux citrouilles" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Manoir du pont au corbeau" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Sables mouvants" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "L’étang de Nessie" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Station nordique" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Pic enneigé" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Terrain de football" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Le stade" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Entreprise" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Temple" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Ile volcanique" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Jardin zen" @@ -2813,11 +3007,11 @@ msgstr "Jardin zen" msgid "Completed achievement \"%s\"." msgstr "Succès « %s » accompli." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Impossible de se connecter au serveur des extensions de SuperTuxKart." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Erreur lors du téléchargement des nouvelles : « %s »." @@ -2848,7 +3042,7 @@ msgstr "Contre la montre (course simple)" #: src/challenges/challenge_data.cpp:318 msgid "Follow the Leader (single race)" -msgstr "Suivez-le-Chef (course simple)" +msgstr "Suivez-le-Meneur (course simple)" #. I18N: In the Select challenge dialog, tell user this challenge has reversed #. laps @@ -2883,7 +3077,7 @@ msgid "New kart '%s' now available" msgstr "Nouveau kart « %s » déverrouillé" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2915,32 +3109,32 @@ msgid "" "created." msgstr "Ton fichier de configuration est périmé, il a donc été réinitialisé." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Enregistrement vidéo lancé." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Vidéo sauvegardée sur \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Progrès de l'encodage : " -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "IPS : %d/%d/%d - %d KTris, Ping : %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Astuce : %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Chargement" @@ -2962,19 +3156,18 @@ msgstr "Efficacité de la nitro" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (handicapé)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s est prêt" @@ -3448,21 +3641,21 @@ msgid "Axis %d" msgstr "Axe %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Manette, bouton %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Souris, bouton %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Souris, axe %d %s" @@ -3635,26 +3828,30 @@ msgstr "Tu peux avoir un maximum de 3 vies !" msgid "+1 life." msgstr "+1 vie." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Tu étais trop lent !" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Vous avez fini la course !" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Tu as gagné la course !" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Vous avez fini la course au rang %d !" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s a quitté la partie." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3663,16 +3860,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart peut se connecter à un serveur pour télécharger des extensions et t’avertir des mises à jour. Notre politique de confidentialité est disponible sur https://supertuxkart.net/Privacy. Souhaites-tu que ces fonctionnalités soient activées ? (Pour modifier ton choix plus tard, va dans les options, sélectionne l’onglet « Général », et modifie « Se connecter à Internet » et « Envoyer des statistiques anonymes sur la configuration matérielle »)." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Votre résolution d'écran est trop petite pour utiliser STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Ton pilote graphique est trop vieux. Installe les derniers pilotes graphiques." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3680,38 +3877,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Vos pilotes de carte graphique semblent désuets. Veuillez vérifier si une mise à jour est disponible. SuperTuxKart recommande un pilote supportant %s ou mieux. Le jeu fonctionnera probablement, mais avec des graphismes réduits." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Impossible de se connecter, le serveur ne répond pas." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s a le drapeau rouge !" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Le drapeau rouge est revenu !" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s a le drapeau bleu !" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Le drapeau bleu est revenu !" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s a capturé le drapeau bleu !" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s a capturé le drapeau rouge !" @@ -3721,7 +3918,7 @@ msgstr "%s a capturé le drapeau rouge !" msgid "Eggs: %d / %d" msgstr "Œufs : %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Meneur" @@ -3729,22 +3926,22 @@ msgstr "Meneur" msgid "Final lap!" msgstr "Dernier tour !" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Tour %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s par %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Nouveau meilleur temps au tour" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "MAUVAISE DIRECTION !" @@ -3758,7 +3955,7 @@ msgstr "%s a marqué un but !" msgid "Oops, %s made an own goal!" msgstr "Oups, %s a marqué contre son camp !" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" @@ -3766,187 +3963,187 @@ msgstr[0] "%ipneu de rechange entre en jeu!" msgstr[1] "%ipneus de rechange entrent en jeu !" msgstr[2] "%ipneus de rechange entrent en jeu !" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Tu as été éliminé !" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "« %s » a été éliminé." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Le serveur a été arrêté." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Vous avez été expulsé du serveur." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Vous avez été expulsé du serveur : Réseau trop lent" -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Une mauvaise connexion réseau est détectée." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Robot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s s'est déconnecté." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Cliquez le nom d'un joueur dans la liste pour accéder aux informations de classement et aux options de gestion." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Difficulté : %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Nombre maximal de joueurs : %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Mode du jeu : %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Limite de temps" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Limites des objectifs" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Type de jeu de Soccer : %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Progression du Grand Prix : %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Tous les joueurs ont rejoint l'équipe rouge ou bleu." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Vous êtes maintenant le propriétaire du serveur." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Connexion refusée : Le serveur est occupé." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Connexion refusée : Vous êtes banni du serveur." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Connexion au serveur refusée : mot de passe invalide." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Connexion refusée : Les données du jeu sont incompatibles." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Connexion refusée : le serveur est plein." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Connexion refusée : Joueur invalide se connectant." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Erreur lors du démarrage de la partie en ligne" #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "La partie est terminée, vous ne pouvez plus la rejoindre ou la regarder." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Plus de place dans l'arène - impossible de rejoindre la partie." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Seulement 1 joueur restant, retour au lobby." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Le propriétaire du serveur a quitté la partie." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Tu seras spectateur sur la prochaine partie." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s a rejoint l'équipe rouge." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s a rejoint l'équipe bleue." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s a rejoint la partie." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3954,15 +4151,15 @@ msgid "" msgstr "Appuyez sur <%s> ou <%s> pour changer le joueur visé, <%s> ou <%s> pour la position de la caméra." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "Rapporté avec succès%s." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3993,38 +4190,38 @@ msgstr "Contre la montre (Grand Prix)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Mêlée générale" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Capture le drapeau" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s est maintenant en ligne." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s et %s sont maintenant en ligne." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s et %s sont maintenant en ligne." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4033,12 +4230,12 @@ msgstr[1] "%d amis sont maintenant en ligne." msgstr[2] "%d amis sont maintenant en ligne." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s est sur le serveur \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4046,7 +4243,7 @@ msgstr[0] "Tu as %d nouvelle demande d'ami !" msgstr[1] "Tu as %d nouvelles demandes d’ami !" msgstr[2] "Tu as %d nouvelles demandes d’ami !" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Tu as une nouvelle demande d'ami !" @@ -4075,12 +4272,12 @@ msgid "" msgstr "Le fichier des meilleurs scores était trop vieux,\n il a donc été supprimé." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" -msgstr "Suivez-le-Chef" +msgstr "Suivez-le-Meneur" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Bataille en 3 coups" @@ -4093,92 +4290,88 @@ msgstr "L'enregistrement incomplet ne sera pas sauvegardé." msgid "Replay saved in \"%s\"." msgstr "Enregistrement sauvegardé sur \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 semaine" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 semaines" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 mois" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 mois" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 mois" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 mois" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 an" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 ans" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Nom de l’extension" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Date de mise à jour" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Non installé" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s par %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Veuillez patienter durant la mise à jour des extensions" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Désolé, une erreur s’est produite lors de la connexion au site web des extensions. Assure-toi d’être connecté à Internet et vérifie que SuperTuxKart n’est pas bloqué par un pare-feu." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Favoris" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Verrouillé : remporte des défis pour y accéder !" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Arène aléatoire" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d arène non disponible pour le jeu solo." -msgstr[1] "%d arènes non disponibles pour le jeu solo." -msgstr[2] "%d arènes non disponibles pour le jeu solo." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nadrien vigneron, 2015\nAlayan, 2018-2019\nAnard0, 2020\nAnard0, 2021-2022\nAuria, 2015-2021\nBenau, 2020-2021\nClément Escude--Cotinat, 2022\ndevnoname120, 2015\nAlayan, 2018\nÉfrit, 2015\nflorian mesnier, 2021\nLoïs Doyenard, 2021\nnad0, 2015\nPoorPockets McNewHold, 2022\nPoorPockets McNewHold, 2019-2020\nSylvain St-Amand, 2018-2019\nSylvain St-Amand, 2019\nSylvain St-Amand, 2018\n51251df01484cc547f4d59bd93cd7512, 2016-2018\nAnard, 2020\nAlexis Lavaud\nAudiger Jeremy\nAuria\nBaptiste Fontaine\nFlorent (LSc)\nJuju Croco\nKalsan\nLouis-Philippe Breton\nMCMic\nMarwane K.\nMax Perkins\nNicolas Delvaux\nOtourly\nSTK-team\nSyl\nThomas P T\nlondumas\nmath07\nnoname120\ntipiak\nxapantu\nxemard.nicolas\nÉfrit" @@ -4237,7 +4430,7 @@ msgstr "Courses contre-la-montre remportées" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:176 msgid "Follow-the-Leader races won" -msgstr "Courses Suivez-le-Chef gagnées" +msgstr "Courses Suivez-le-Meneur gagnées" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4327,13 +4520,13 @@ msgstr "Courses contre-la-montre complétées" #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:206 msgid "Follow-the-Leader races started" -msgstr "Courses Suivez-le-Chef commencées" +msgstr "Courses Suivez-le-Meneur commencées" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. #: src/states_screens/dialogs/achievement_progress_dialog.cpp:208 msgid "Follow-the-Leader races finished" -msgstr "Courses Suivez-le-Chef complétées" +msgstr "Courses Suivez-le-Meneur complétées" #. I18N: A goal for achievements. If this text is in (), it's a precision #. added to multiple different goals. @@ -4466,7 +4659,7 @@ msgstr "Bananes collectées" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Dérapage" @@ -4569,7 +4762,7 @@ msgstr "Chasse aux œufs terminées" msgid " (official tracks matching the goal)" msgstr "(courses officielles correspondant à l'objectif)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4577,91 +4770,95 @@ msgid "" msgstr "Les manettes de jeu apparaîtront automatiquement dans la liste quand tu les connecteras à ton appareil.\n\nPour ajouter une configuration clavier, tu peux utiliser le boutons ci-dessous, CEPENDANT garde en tête que la plupart des claviers n'acceptent qu'un nombre limité d'appuis simultanés et qu'utiliser un seul clavier sera inapproprié en multijoueur. (En revanche, tu peux connecter plusieurs claviers à cet appareil. Souviens-toi seulement que chacun devra tout de même choisir des touches différentes dans ce cas.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Ajouter une Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Ajouter une configuration de clavier" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Mettre à jour" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Version : %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "à l’honneur" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Taille : %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Vous devez être connecté pour noter cette extension" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Désolé, le téléchargement de l’extension a échoué" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Problèmes lors de l’installation de l’extension « %s »." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Réessayer" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Problèmes lors de la suppression de l’extension « %s »." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Le téléchargement en arrière plan est terminé." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Téléchargement en arrière-plan" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Le téléchargement en arrière plan est déjà commencé." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Mot de passe actuel invalide." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "La taille du mot de passe doit être comprise entre 8 et 30 caractères !" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Les mots de passe ne correspondent pas !" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Validation des infos" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Mot de passe modifié avec succès." @@ -4683,67 +4880,97 @@ msgstr "Les résolutions plus petites que 1024x768 ou 1280x720 ne sont pas suppo #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Vue de dessus" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Personnalisation" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Désactivé" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Important seulement" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Très basse" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Basse" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Médium" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Élevée" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Très élevée" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra élevée" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4751,7 +4978,7 @@ msgid "" msgstr "SuperTuxKart va télécharger toutes les données (en incluant les textures de hautes qualités et les musiques) pour une meilleure expérience de jeu, cela utilisera vos données mobiles si vous n´avez pas de connexion wifi." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4768,101 +4995,102 @@ msgstr "Entrez l’adresse du serveur optionnellement suivie d'un : et du numér msgid "Invalid server address: %s." msgstr "Adresse de serveur invalide : %s" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "À l’envers" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Difficulté" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Tours" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Temps" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Kart" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Utilisateur" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Version" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Non" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Piste" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Les %d meilleurs scores" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s : %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Nombre de karts : %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Temps à battre: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Tours : %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Direction opposée : %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Vide)" @@ -4943,40 +5171,48 @@ msgstr "Informer l'administrateur du serveur sur ce joueur (%s) :" msgid "" "Press any key...\n" "(Press ESC to cancel)" -msgstr "Appiyez sur une touche...\n(Echap pour annuler)" +msgstr "Appuyez sur une touche...\n(Echap pour annuler)" #: src/states_screens/dialogs/press_a_key_dialog.cpp:49 msgid "Press any key..." msgstr "Appuyez sur une touche..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Le chat est désactivé, vous pouvez l'activer dans les options." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Retour au test de performance" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Quitter le test de performance" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Retour au combat" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Préparer une nouvelle partie" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Recommencer le combat" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Sortir du combat" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Régler une nouvelle course" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Quitter la course" @@ -4992,11 +5228,11 @@ msgstr "%s n'a pas encore de rang." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s est numéro %d au classement avec un score de %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Le nom d’utilisateur et/ou l’adresse de messagerie sont invalides." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5018,7 +5254,7 @@ msgstr "Course contre un enregistrement" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Tours : %i" @@ -5031,21 +5267,21 @@ msgstr "Type : %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Rang requis : %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Temps requis : %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Points de Nitro requis : %i" @@ -5058,54 +5294,54 @@ msgstr "Nombre de joueurs IA : %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Mode bataille" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Type de jeu de Soccer" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Emplacement du serveur : %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Piste actuelle : %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Classement" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Joueur" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Scores" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Temps de jeu" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Retirer des favoris" @@ -5118,74 +5354,74 @@ msgid "No player available for connecting to server." msgstr "Aucun joueur disponible pour la connexion au serveur." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Nom d'utilisateur : %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Annuler la requête" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Aujourd’hui" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Demande d'ami envoyée !" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Demande d'ami acceptée !" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Demande d'ami refusée !" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Ami retiré !" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Demande d'ami annulée !" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Traitement en cours" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Récupération du dernier vote" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Tu peux modifier ton vote en cliquant sur les étoiles ci-dessous." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Tu n’as pas encore voté pour cette extension. Clique sur les étoiles ci-dessous pour la noter." -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Vote réussi ! Tu peux maintenant fermer la fenêtre." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Vote en cours …" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Piste aléatoire" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5214,7 +5450,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Une erreur est survenue en sauvegardant le Grand Prix." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Sélectionne une piste" @@ -5258,12 +5494,12 @@ msgstr "Tu as déverrouillé la piste %0" msgid "You unlocked grand prix %0" msgstr "Tu as déverrouillé le Grand Prix %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Piste" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5284,19 +5520,19 @@ msgstr "Veuillez saisir le nom du Grand Prix" msgid "Please select a Grand Prix" msgstr "Veuillez sélectionner un Grand Prix" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Défini par l’utilisateur" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Le nom est vide." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Un autre Grand Prix portant le même nom existe déjà." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Le nom est trop long." @@ -5305,19 +5541,19 @@ msgstr "Le nom est trop long." msgid "Better luck next time!" msgstr "Tu auras plus de chance la prochaine fois !" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Tu as remporté un défi !" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Tu as gagné le Grand Prix !" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Tu as complété le Grand Prix !" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Nombre de karts" @@ -5328,112 +5564,127 @@ msgstr "Voulez-vous vraiment retirer ce score ?" #: src/states_screens/high_score_selection.cpp:360 msgid "Are you sure you want to remove all of your high scores?" -msgstr "Voulez-vous vraiment retirer tous vos scores ?" +msgstr "Êtes-vous sûr de vouloir supprimer tous vos meilleurs scores ?" + +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Favoris" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Léger" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Lourd" -#: src/states_screens/kart_selection.cpp:447 +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Branche un clavier ou une manette pour jouer en écran partagé multijoueurs." -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Kart aléatoire" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Verrouillé" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Tout le monde : \nAppuyez sur le bouton « Sélection » pour rejoindre la partie" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Veux-tu jouer au tutoriel du jeu ?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Tu ne peux pas jouer en ligne sans accès à Internet. Si tu veux le faire, va dans les options, et coche la case « Se connecter à Internet »." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Vous ne pouvez pas télécharger d'extensions sans accès à Internet. Si vous souhaitez télécharger des extensions, allez dans les options, et cochez \"Se connecter à Internet\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Vous ne pouvez pas télécharger d'extensions sans accès Internet. Si vous souhaitez télécharger des extensions, allez dans les options, et cochez \"Se connecter à Internet\".\n\nVous pouvez cependant supprimer des extensions déjà téléchargées." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Le module des extensions est actuellement désactivé dans les options" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Veuillez patienter durant le chargement des extensions" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Voulez-vous vraiment quitter STK ?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Créer un serveur LAN" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Serveur de %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Nb. de piste(s) du grand prix" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "La taille du nom doit être comprise entre 4 et 30 caractères !" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Le mot de passe contient des caractères invalides!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Prêt" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Rejoindre" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Regarder" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Installer l'extension" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5441,7 +5692,7 @@ msgstr "Veuillez attendre la fin de la partie en cours (%s), temps restant estim #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Veuillez attendre la fin de la partie en cours, temps restant estimé %s." @@ -5449,24 +5700,24 @@ msgstr "Veuillez attendre la fin de la partie en cours, temps restant estimé %s #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Veuillez attendre la fin de la partie en cours (%s), estimation : %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Veuillez attendre la fin de la partie en cours, estimation : %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Veuillez attendre la fin de la partie en cours." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5476,7 +5727,7 @@ msgstr[2] "La partie va commencer s'il y a plus de %d joueurs." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5486,96 +5737,108 @@ msgstr[0] "Début dans %d seconde, ou lorsque tout le monde aura pressé le bout msgstr[1] "Début dans %d secondes, ou lorsque tout le monde aura pressé le bouton \"prêt\"." msgstr[2] "Début dans %d secondes, ou lorsque tout le monde aura pressé le bouton \"prêt\"." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Connexion au serveur %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Trouver un serveur pour partie rapide" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Temps restant : %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Objectifs" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Récupération des succès" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Profil de %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Depuis" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "État" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Récupération des amis" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Nouvelle requête" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "En attente" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Hors ligne" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Entrez le nouvel e-mail ci-dessous" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" -msgstr "Le nouvel e-mail doit contenir entre 5 et 254 caractères!" +msgstr "Le nouvel e-mail doit contenir entre 5 et 254 caractères !" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" -msgstr "Le nouvel e-mail est invalide!" +msgstr "Le nouvel e-mail est invalide !" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" -msgstr "E-mail modifié!" +msgstr "E-mail modifié !" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Échec de modification de l'e-mail : %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Nouvelles du blog STK" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Date" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Il n'y a actuellement pas de nouvelles disponibles." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Vous devez être connecté pour jouer en ligne. Cliquez votre nom d'utilisateur ci-dessus." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Recherche en cours" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Quitter la partie" @@ -5653,34 +5916,34 @@ msgid "Distance (km)" msgstr "Distance (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Inconnue" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Pas d´IPv4 détectée, vous ne pourrez pas rejoindre de serveurs." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Pas d´IPv6 détectée, vous ne pourrez pas rejoindre de serveurs." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Aucun serveur disponible." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Récupération de la liste des serveurs" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Serveurs favoris" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5688,167 +5951,177 @@ msgstr "Si une majorité de joueurs sélectionnent la même piste et les mêmes #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Placer les items aléatoirement" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Nombre de buts pour l’emporter" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Conduire en sens opposé" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Verrouillé : remporte des défis pour y accéder !" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Action" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Touche assignée" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Désactiver le périphérique" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Activer le périphérique" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Activer la configuration" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Commandes de jeu" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Touches pour le menu" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Tourner à gauche" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Tourner à droite" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Accélérer" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Frein / Reculer" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Tirer" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Regarder en arrière" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Sauvetage" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Suspendre le jeu" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Haut" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Bas" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Gauche" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Droite" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Sélectionner" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" -msgstr "Annuler/Retour" +msgstr "Annuler / Retour" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Un élément en bleu représente un conflit avec une autre configuration" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Un élément en rouge représente un conflit avec la configuration actuelle" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" " working." -msgstr "Avertissement : utiliser la touche Maj est déconseillée car lorsqu’elle est enfoncée, toute touche qui contient un caractère différent en majuscule cessera de fonctionner." +msgstr "Avertissement : utiliser la touche Maj est déconseillé car lorsqu’elle est enfoncée, toute touche qui contient un caractère différent en majuscule cessera de fonctionner." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Êtes-vous sûr de vouloir définitivement supprimer cette configuration ?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Entrez un nouveau nom de configuration, laissez le vide pour revenir à la valeur par défaut." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Vertical" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Horizontal" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5856,89 +6129,74 @@ msgstr "En multijoueur, les joueurs peuvent sélectionner des profils\navec hand #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Installe tout les actifs de tout le jeu" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Êtes-vous certain de désinstaller tous les actifs de tout le jeu ?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Clavier %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Écran tactile" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Appuyez sur un dispositif pour le configurer." #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Langue du système" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "En bas à gauche" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "À droite" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Masquée" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Centrée" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Vertical" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Horizontal" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Très petite" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Petite" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Médium" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Grande" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Très grande" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5948,128 +6206,133 @@ msgid "" msgstr "Le mode speedrun peut seulement être activé si le jeu n'a pas été fermé depuis que le mode histoire a été lancé.\n\nFermer le jeu avant la fin du mode histoire annule le chronomètre.\n\nPour utiliser le mode speedrun, veuillez créer un nouveau profil" #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Syncronisation verticale" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Vsync force la carte graphique à fournir une nouvelle image seulement quand le moniteur est prêt à l'afficher." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Vsync ne va pas fonctionner si votre pilote graphique ne le supporte pas." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Effets de particules : %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Personnages animés : %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Lumières dynamiques : %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Diffusion de lumière: %s " #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Anticrénelage : %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Occlusion ambiante : %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Ombres : %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Ombres : %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Flou lumineux (bloom) : %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Contours en surbrillance : %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Puits de lumière : %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Qualité de rendu d'image : %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Détail de la géométrie : %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Flou cinétique : %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Profondeur de champ : %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "L'accès internet est désactivé. Voulez-vous l'activer ?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Le mot de passe est obligatoire." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Déconnexion de « %s »" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Connexion sous le nom « %s »" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Impossible de supprimer le seul joueur." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Voulez-vous vraiment supprimer joueur '%s ' ?" @@ -6097,7 +6360,7 @@ msgstr "BUT !" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "En attente des autres" @@ -6124,7 +6387,7 @@ msgstr "Ramasse de la nitro !" #: src/states_screens/race_gui_base.cpp:771 msgid "Follow the leader!" -msgstr "Suivez le chef !" +msgstr "Suivez le meneur !" #. I18N: When some GlobalPlayerIcons are hidden, write "Top 10" to show it #: src/states_screens/race_gui_base.cpp:954 @@ -6132,7 +6395,7 @@ msgstr "Suivez le chef !" msgid "Top %i" msgstr "%i premiers" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Défi perdu" @@ -6156,102 +6419,199 @@ msgstr "Clique sur le podium pour commencer le défi" msgid "Press fire to start the challenge" msgstr "Appuie sur « tirer » pour commencer le défi" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Retour aux paramètres vidéo" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Sauvegarder les résultats du test" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Retour au menu principal" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Quitter le serveur" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Abandonner le Grand Prix" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Recommencer" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Retour à la sélection du défi" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Jouer contre la nouvelle course enregistrée" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Retour au menu" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Veux-tu vraiment interrompre le Grand Prix ?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Compte-rendu de performance sauvegardé dans \"%s\"." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Les Rouges l’emportent" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Les Bleus l’emportent" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Match nul" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Éliminé après %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Éliminé" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(contre son camp)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Piste %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Progrès dans le Grand Prix :" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Meilleurs scores" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Tour le plus rapide : %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "par %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Défi complété!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Défi échoué!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Les conditions requises de SuperTux sont atteintes" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Résultats du test de performance" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Durée du test : %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Nombre d'images : %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "IPS stable : %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "IPS plutôt stable : %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "IPS typique : %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Résolution horizontale : %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Résolution verticale : %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Lumières dynamiques : ACTIVÉES" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Lumières dynamiques : DÉSACTIVÉES" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Résolution de rendu : %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Anticrénelage : ACTIVÉ" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Anticrénelage : DÉSACTIVÉ" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Éclairage basé sur l’image : DÉSACTIVÉ" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Éclairage basé sur l’image : ACTIVÉ" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Occlusion ambiante : ACTIVÉE" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Occlusion ambiante : DÉSACTIVÉE" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Résolution des ombres : %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Tous les coups sont permis, alors collecte des armes et utilise-les judicieusement !" @@ -6292,28 +6652,28 @@ msgstr "Appuyez l´icône de ballon rouge ou bleu pour changer d´équipe." #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Piste par %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Nombre maximal de joueurs supportés : %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Nombre de karts IA équipe rouge" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Vous ne pouvez pas jouer à ce Grand Prix car il contient des pistes verrouillées!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Verrouillé !" @@ -6335,10 +6695,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Remporte tous les défis pour déverrouiller la grande porte !" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6347,41 +6709,48 @@ msgid "" msgstr "Tu as besoin de plus de\npoints pour relever ce défi !\nConsulte la carte pour\nvisualiser les défis disponibles." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Accélère avec <%s> et oriente-toi avec <%s> et <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Accélère en touchant le haut du volant, et dirige le kart en déplaçant vers la gauche ou la droite." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Accélère en déplaçant l'accélérateur vers le haut, et dirige le kart en inclinant ton appareil." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Accélère en déplaçant l'accélérateur vers le haut, et dirige le kart en tournant ton appareil." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Ramasse des cadeaux, et utilise ton arme avec la touche <%s> pour détruire ces caisses !" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Collecte les cadeaux et appuie sur l'icône de boule de bowling pour faire feu et souffler les caisses!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6389,34 +6758,41 @@ msgid "" msgstr "Appuie sur <%s> pour regarder en arrière.\nSors ton arme avec <%s> et maintiens la touche <%s> appuyée pour tirer derrière toi !" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Appuie sur l'icône miroir pour regarder vers l'arrière.\nPour faire feu vers l'arrière, garde enfoncé l'icône miroir puis glisse vers l'icône boule de bowling !" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Utilise la nitro que tu as récoltée en appuyant sur <%s>  !" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Utilise la nitro que tu as collectée en appuyant sur l'icône nitro" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Récolte des bouteilles de nitro (nous allons les utiliser après le virage)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Oups ! Quand tu es en difficulté, appuie sur <%s> pour être secouru." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Oups ! Quand tu es en difficulté, appuie sur l'icône oiseau pour être secouru." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6424,24 +6800,27 @@ msgid "" msgstr "Accélère et appuie sur la touche <%s> en tournant pour déraper.\nDéraper pendant un court moment permet de mieux aborder les virages serrés." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Pour déraper, accélère et appuie sur l'icône de dérapage tout en tournant.\nDéraper sur une courte distance peut aider à tourner plus rapidement afin de prendre un virage serré." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Remarque que si tu arrives à déraper pendant plusieurs secondes, tu recevras un bonus de vitesse en récompense !" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Tu es maintenant prêt à faire la course. Bonne chance !" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Un jeu libre de course de karts en 3D" @@ -6451,7 +6830,7 @@ msgstr "Un jeu libre de course de karts en 3D" msgid "tux;game;race;" msgstr "tux;jeu;course;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6459,7 +6838,7 @@ msgid "" "for all ages." msgstr "Karts. Nitro. Action! SuperTuxKart est un jeu de course arcade en 3D avec une variété de personnages, pistes et modes de jeu. Notre objectif est de créer un jeu orienté vers le divertissement plutôt que le réalisme et d'offrir une expérience agréable pour les joueurs de tous ages." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6468,7 +6847,7 @@ msgid "" "your opponents." msgstr "Nous avons plusieurs circuits dans plusieurs thématiques : des pistes sous-marines, des fermes rurales, des jungles ou même dans l'espace! Faites de votre mieux pour éviter les autres karts car ils tenteront de vous doubler, mais ne mangez pas les bananes! Prenez garde aux boules de bowling, aux ventouses, aux gommes et gâteaux lancés par vos adversaires." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6477,27 +6856,27 @@ msgid "" "your racing skills!" msgstr "Vous pouvez faire une simple course contre d'autres karts, faire la compétition sur l'un de nos Grands Prix, essayer de battre le record au contre la montre, faire une bataille contre l'ordinateur ou vous amis, et plus encore ! Si vous cherchez le défi, rejoignez le mode en ligne, rencontrez des joueurs des quatre coins du monde et prouvez vos talents de pilote !" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Ce jeu ne contient aucune publicité." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Ceci est une version non stable de SuperTuxKart qui contient les dernières améliorations. Elle est disponible principalement afin de tester, afin que la version stable soit aussi bonne que possible." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Cette version peut être installée en même temps que la version stable sur cet appareil." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Si vous désirez davantage de stabilité, utilisez la version stable : %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "L'équipe SuperTuxKart" diff --git a/data/po/gl.po b/data/po/gl.po index 3fd2e168ab6..630fe82d71e 100644 --- a/data/po/gl.po +++ b/data/po/gl.po @@ -4,20 +4,20 @@ # # Translators: # Taitow, 2021-2023 -# Adrián Chaves Fernández , 2010,2015 -# Adrián Chaves Fernández , 2015-2016 -# Adrián Chaves Fernández , 2010 -# Adrián Chaves Fernández , 2010-2011,2013 -# nin hum , 2024 -# Taitow, 2023 +# Adrián Chaves Fernández , 2010,2015 +# Adrián Chaves Fernández , 2015-2016 +# Adrián Chaves Fernández , 2010 +# Adrián Chaves Fernández , 2010-2011,2013 +# nin hum , 2024-2025 +# Taitow, 2023,2025 # Toño Calo , 2023 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: nin hum , 2024\n" +"Last-Translator: nin hum , 2024-2025\n" "Language-Team: Galician (http://app.transifex.com/supertuxkart/supertuxkart/language/gl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -174,7 +174,7 @@ msgstr "Fin do mundo" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Volver" @@ -196,7 +196,7 @@ msgstr "Selecciona o tipo de controlador que prefiras" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Acelerómetro" @@ -210,13 +210,13 @@ msgstr "Acelerómetro" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Xiroscopio" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Volante" @@ -247,35 +247,37 @@ msgstr "Configuracións do Dispositivo de Toque" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Xeral" @@ -343,30 +345,33 @@ msgstr "Restaurar a configuración por defecto" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Cancelar" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Si" @@ -471,7 +476,7 @@ msgstr "Resplandor (Contorno)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Anti-aliasing" -msgstr "Suavizado das curvas" +msgstr "Suavizado de bordes" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -544,9 +549,9 @@ msgstr "Xuntar" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -607,7 +612,7 @@ msgstr "Obxectivo" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Progreso" @@ -642,7 +647,7 @@ msgstr "Enviar" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Volver á carreira" @@ -659,7 +664,7 @@ msgstr "Voltar a sala de espera" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Reiniciar a carreira" @@ -723,12 +728,12 @@ msgstr "Escribe o nome de usuario e mailo enderezo de correo electrónico que fo #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Nome de usuario" @@ -769,7 +774,7 @@ msgstr "Dificultade" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Principiante" @@ -781,7 +786,7 @@ msgstr "Principiante" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Intermedio" @@ -793,7 +798,7 @@ msgstr "Intermedio" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Experto" @@ -805,7 +810,7 @@ msgstr "Experto" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "Supertux" @@ -813,8 +818,8 @@ msgstr "Supertux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Modo de xogo" @@ -825,8 +830,8 @@ msgstr "Modo de xogo" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Carreira normal" @@ -839,7 +844,7 @@ msgstr "Carreira normal" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Contra o Reloxo" @@ -847,7 +852,8 @@ msgstr "Contra o Reloxo" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Batalla" @@ -856,24 +862,24 @@ msgstr "Batalla" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Fútbol" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Contrasinal" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Engadir este servidor aos marcadores" @@ -884,7 +890,7 @@ msgstr "Engadir xogador" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Nome" @@ -978,6 +984,50 @@ msgstr "Asignar á tecla «Esc»" msgid "Assign nothing" msgstr "Non asignar nada" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Configuración gráfica recomendada" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "A configuración recomendada será valida para a resolución actual." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Que debe priorizar a configuración?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Desempeño" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Equilibrar o desempeño e a calidade gráfica" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Calidade gráfica" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Aforro de enerxía" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Gústanche os efectos gráficos que crean desenfoque?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Comezar o test" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -992,11 +1042,11 @@ msgstr "Configuración da carreira" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Continuar" @@ -1037,10 +1087,15 @@ msgstr "Arenas" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Instalado" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Editar arenas favoritas" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1050,20 +1105,20 @@ msgstr "Instalado" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Estándar" @@ -1074,12 +1129,12 @@ msgstr "Estándar" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Complementos" @@ -1093,27 +1148,28 @@ msgstr "Complementos" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Todo" @@ -1152,9 +1208,9 @@ msgstr "Baixar" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Engadir" @@ -1191,7 +1247,7 @@ msgstr "Selección de repetición fantasma" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "A caza do ovo" @@ -1238,10 +1294,10 @@ msgstr "Traxecto inverso." #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Tempo máximo en minutos" @@ -1273,9 +1329,9 @@ msgstr "Copiar" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1286,80 +1342,80 @@ msgstr "Cambiar o nome" msgid "Save Grand Prix" msgstr "Gardar o campionato" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Axuda" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Modos de xogo" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Potenciadores" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Plátanos" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1367,56 +1423,57 @@ msgstr "Plátanos" msgid "Story Mode" msgstr "Aventura" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Clases de karts" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Multixogador" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Comezar o titorial" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Apaña os agasallos azuis, eles vante dar potenciadores." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Esquiva os plátanos!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1424,14 +1481,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Recolleitar nitro permíteche obter máis velocidade cando queiras premendo a tecla ou botón correspondente. Podes ver o teu nivel actual de nitro no indicador na parte inferior dereita da pantalla da carreira." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Cando vexas un botón cun cadeado coma este, significa que tes que superar un desafío para desbloquealo." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1440,34 +1497,34 @@ msgid "" "carefully before!" msgstr "Podes derrapar premendo unha tecla ou botón especial. Derrapaxes curtas sucesivas axudan a tomar curvas pechadas; mentres que derrapaxes medias aumentarán a túa velocidade, e as derrapaxes longas aínda máis. Non podes deixar de xirar mentres derrapas, así que orienta o teu kart con coidado antes!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Podes obter un impulso de saída premendo o botón de acelerar en 'Listos!', antes de que comece a carreira." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "Os atallos de teclado poden ser vistos e alterados no menú de Opcións" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "O SuperTuxKart ten varios modos de xogo:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Carreira normal: Todos os golpes están permitidos, por iso recolle os potenciadores e úsaos con cabeza!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Contra-Reloxo: Non hai melloras, só o teu talento ao volante conta!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1475,7 +1532,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Seguir ao líder: Intenta manterte en segundo lugar, porque o último kart quedará descalificado cada vez que o contador chegue a cero. Pero ollo: se vas por diante do líder tamén quedarás descalificado!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1485,30 +1542,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Hai 3 tipos de modo de batalla: En Batalla de 3 golpes, tes que golpear aos demais con armas ata que perdan todas as súas vidas. En Todos contra todos, o xogador que máis golpee aos demais gañará nun límite de golpes ou de tempo determinado. En Captura a bandeira, o teu equipo debe levar a bandeira do outro equipo á túa propia base de bandeira, sempre que a túa bandeira non sexa capturada polo outro equipo." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Fútbol: Usa o kart para meter a bóla na portaría." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "A caza do ovo: Explora circuítos para atopar todos os ovos agochados." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Repetición fantasma: Corre contra repeticións fantasma no modo Contra-Reloxo ou A caza dos Ovos, e grava a túa propia!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Proba de voltas: Completa tantas voltas como sexa posible nun tempo determinado." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1517,93 +1574,93 @@ msgid "" "wins the cup." msgstr "* Moitos destes modos de xogo tamén se poden xogar de xeito Gran Premio: en lugar de xogar unha única carreira, xogas a moitas seguidas. Canto mellor clasifiques, máis puntos conseguirás. Ao final, o xogador con máis puntos gaña a copa." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Existen bonificacións que podes recoller para axudarte a gañar:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Goma de mascar — Protéxete cun escudo, ou úsaa mentres miras cara atrás para deixar tras de ti unha substancia rosa pegañenta." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Turbo - darache un forte impulso de velocidade. Pero ten coidado de non perder o control do teu kart!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Torta - lanzada ao rival máis próximo, ideal a curtas distancias e en rectas longas. Tamén afecta a outros karts próximos á explosión." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Chupón — Lánzao cara adiante para ralentizar a un opoñente, ou lánzao cara atrás para cegar a quen lle atines." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Bóla de birlos - vai en liña recta até golpear, pode rebotar nas paredes. Se estás mirando cara atrás, será lanzada cara atrás." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Paracaídas — Ralentiza todos os karts por diante de ti." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Intercambiador - as caixas de agasallos transfórmase en plátanos, as latas de nitro en gomas de mascar, e viceversa durante un curto período de tempo." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Balón de baloncesto — Vai saltando en dirección ao líder, e ralentiza os karts que se atope polo camiño." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Matamoscas - esmagará os karts próximos, abrandándoos. Tamén pode usarse para eliminar paracaídas e bombas." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Ao golpear un plátano, podes acabar cun dos seguintes enganchado ao kart:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Áncora - fai diminuír a velocidade do kart de forma súbita." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Paracaídas - fai diminuír a velocidade do kart de forma máis progresiva ca áncora. Canto máis rápido vas, máis forte é o freo." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bomba - detona despois dun certo tempo, lanzando o kart ao aire. Colide co outro kart para transferir a bomba a el." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "O malvado Nolok capturou a Gnu! Aquí tes algúns consellos para axudarche:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1612,7 +1669,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Esta icona no minimapa amosa os desafíos dispoñibles que non completaches. No canto superior dereito da pantalla, tamén te indica cantos puntos tes actualmente. Completa tantos desafíos como sexa posible, e Nolok aceptará correr contra ti. Gaña para liberar a Gnu!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1620,20 +1677,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Cando completas un desafío, recibes unha copa. Cada copa ten varios puntos de valor. Canto máis difícil sexa o desafío completado, mellor será a copa e máis puntos valerá." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Cando consigas o número de puntos indicado baixo esta icona, recibirás unha sorpresa de agasallo. Hai varias para coleccionar." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Non todos os karts conducen igual! Pertencen a clases con varias diferenzas:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1641,7 +1698,7 @@ msgid "" " resistant to explosions." msgstr "Masa - hai tres clases de karts, dependendo da súa masa: lixeiro, medio e pesado. Os karts máis pesados ​​son menos afectados polos paracaídas e son máis resistentes ás explosións." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1649,7 +1706,7 @@ msgid "" " especially at low speeds." msgstr "Aceleración - especialmente útil ao comezar, despois dun accidente ou en circuitos con moitas curvas pechadas. Canto máis lixeiro sexa o kart, máis rápido acelera, especialmente a baixas velocidades." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1657,14 +1714,14 @@ msgid "" " top speed." msgstr "Velocidade máxima - canto máis alta sexa, máis rápido pode ir o kart. Especialmente útil en circuitos con liñas rectas e curvas suaves. Os karts máis pesados teñen unha velocidade máxima maior." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Eficiencia do nitro - Canto maior sexa, máis velocidade obtés do nitro. Un kart máis lixeiro terá unha maior eficiencia de nitro." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1672,12 +1729,12 @@ msgid "" "easier it is." msgstr "Se segues de cerca outro kart durante uns segundos, obterás un bono de velocidade na estela cando o adiantes. Canto máis lixeiro sexa o teu kart, máis sinxelo será." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart pode ser xogado no modo multixogador online...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1687,7 +1744,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Primeiro, selecciona a icona 'en liña' no menú principal. Escolle entre rede local ou rede global (require conexión a internet activada nas opcións). Logo, podes crear o teu propio servidor con opcións personalizadas, ou buscar entre unha lista de servidores existentes para unirte a eles. Algúns deles son servidores recomendados con carreiras clasificadas opcionalmente." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1697,12 +1754,12 @@ msgid "" "players and the server." msgstr "Unha vez dentro dun servidor, unha carreira comezará cando o seu dono (simbolizado coa coroa) así o decida. Os servidores oficiais poden iniciar as carreiras automaticamente cando hai suficientes xogadores. Entón, podes elixir o teu kart e votar polo circuito seguinte no que correr. Un circuito adicional está permitida só se existe en todos os xogadores unidos e no servidor." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... ou no mesmo dispositivo:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1712,7 +1769,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Primeiro, precisarás varios dispositivos de entrada. Usa a pantalla de configuración de entrada para configuralos. Múltiples mandos ou joysticks son ideais: en teclado(s), cada xogador necesitará un conxunto diferente de teclas, e a maioría dos teclados non son apropiados para multixogador porque non admiten pulsacións simultáneas múltiples." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1732,7 +1789,7 @@ msgstr "Selección de Récords" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Proba de Voltas" @@ -1740,9 +1797,9 @@ msgstr "Proba de Voltas" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Campionatos" @@ -1753,6 +1810,20 @@ msgstr "Campionatos" msgid "Choose a Kart" msgstr "Escolle un kart" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Clase de Kart" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Editar karts favoritos" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1766,11 +1837,11 @@ msgstr "Multixogador en pantalla dividida" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "En liña" @@ -1787,7 +1858,7 @@ msgstr "Aprendizaxe" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Récords" @@ -1795,7 +1866,7 @@ msgstr "Récords" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Logros" @@ -1849,30 +1920,30 @@ msgstr "Atopar un servidor" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Crear un servidor" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Sala de espera" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Configuración" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Comezar carreira" @@ -1898,9 +1969,9 @@ msgstr "Introducir enderezo do servidor" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Perfil persoal" @@ -1918,7 +1989,7 @@ msgstr "Clasificacións dos xogadores" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Amizades" @@ -1943,7 +2014,7 @@ msgstr "Xogar rapidamente" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Configuración da conta" @@ -1993,8 +2064,8 @@ msgid "Online Username" msgstr "Nome de usuario por internet" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Reiniciar contrasinal" @@ -2007,7 +2078,7 @@ msgid "" msgstr "Podes xogar sen crear unha conta en liña seleccionando unha conta fora de liña. Aínda que entón non podes conectarte con amigos, votar por complementos, etc. Por favor, lea a nosa declaración de privacidade en https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Escolla de servidor" @@ -2025,339 +2096,409 @@ msgstr "Usa a conexión IPv6" msgid "User search" msgstr "Buscar usuarios" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Configuración" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Pantalla" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Gráficos" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Son" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Interface" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Usuarios" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Controis" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Lingua" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Música" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Activado" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Volume:" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Efectos de son" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Eliminar a configuración" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Desactivar Configuración" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Volver á lista de dispositivos" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Renomear Configuración" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Activar a retroalimentación de forza (se está soportada)." -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Resolución" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Pantalla completa." + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Lembrar a posición da xanela." + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Aplicar a nova resolución" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Distribución do multixogador en pantalla dividida" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Opcións da Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Mostrar sempre a pantalla de acceso." -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Conectar a internet." -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Activar o chat online" +msgid "Enable chatting in online lobbies" +msgstr "Activar o chat nas salas en liña" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Activar o chat en xogos online" +msgid "Enable chatting in online matches" +msgstr "Activar o chat nas partidas en liña" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Opcións diversas" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Activar limitacións por xogador." -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Desinstalar o paquete completo de recursos" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Preme «Intro» ou dúas veces co botón secundario para configuralo." -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Engadir un dispositivo" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* A configuración que se use dependerá da tecla de seleccionar que se prema para unirse á partida." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Aparencia:" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Minimapa" +msgid "Skin variant" +msgstr "Variante de aparencia" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Distribución do multixogador en pantalla dividida" +msgid "Minimap" +msgstr "Minimapa" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Tamaño da fonte" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Cámara" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Personalizada..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Amosar os fotogramas por segundo (FPS)." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Mostrar potenciadores dos outros karts" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Activar temporizador no modo historia" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Activar temporizador en carreira rápida" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Resolución da renderización" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Nivel dos efectos gráficos:" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Nivel de efectos de desenfoque" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Límite de FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Configuración personalizada…" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Resolución" +msgid "Performance tests" +msgstr "Probas de rendemento" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Pantalla completa." +msgid "Performance test of the current settings" +msgstr "Proba de rendemento da configuración actual" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Lembrar a posición da xanela." +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Lembrar o contrasinal" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Aplicar a nova resolución" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Eliminar" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Cor do Kart" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2384,15 +2525,15 @@ msgstr "Equipo azul" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Número de voltas" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Número de opoñentes:" @@ -2407,33 +2548,17 @@ msgstr "Número de karts IA na equipa azul" msgid "Random Grand Prix" msgstr "Campionato aleatorio" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Editar pistas favoritas" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Identificación" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Lembrar o contrasinal" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Eliminar" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Cor do Kart" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "O tema da interface pode ser cambiado nas opcións de UI." @@ -2552,238 +2677,306 @@ msgid "" msgstr "Non te poñas no camiño dun compañeiro de equipo que leva o balón, aínda que podes intentar golpear aos rivais que intenten evitar que marquen." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Abismo do Diluvio" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Sinal Alieníxena" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Labirinto dos Gladiadores" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Cidade das Candelas" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Illa bélica" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Bosque Negro" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Cova X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Templo do cacao" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Travesia do Milleiral" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Castelo de lava" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Illa de Gran Paraíso" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Facenda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Caída polo burato" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Campo de Fútbol Xeado" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Que vos pasa, raparigos? Non atopades ao voso “gran” líder o ñu?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Pois é que está no meu castelo. Apetecíame cear un bo prato de lacón con grelos… e porco ou ñu, todo é carne." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Pero sonche unha criatura xusta, así que propóñoche un trato." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Se me gañas ás carreiras, soltarei ao mamífero." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " Pero xa vos aviso, ningún de vós —patéticos ananos— conseguirá vencerme. Son o rei dos karts!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Las Dunas Area" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Estadio de Fútbol Las Dunas" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Volta ao Faro" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Mina vella" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oasis" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Clase de mates de Oliver" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Parque da Cabaza" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Mansión Ravenbridge" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Tormenta de area" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "A poza de Nessie" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Vila na montaña" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Pico nevado" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Campo de Fútbol" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Estadio" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "Compañía STK" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Templo" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Illa do Volcán" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Xardín da paz" @@ -2792,11 +2985,11 @@ msgstr "Xardín da paz" msgid "Completed achievement \"%s\"." msgstr "Conseguiches o logro «%s»." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Non foi posible conectar ao servidor de extensións do SuperTuxKart." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Non foi posíbel descargar as novas: «%s»." @@ -2862,7 +3055,7 @@ msgid "New kart '%s' now available" msgstr "Hai un novo kart dispoñíbel: %s." #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2894,32 +3087,32 @@ msgid "" "created." msgstr "O ficheiro de configuración estaba obsoleto, así que eliminouse e vaise crear un novo." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Comezou a gravación do vídeo" -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Vídeo gardado en \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Progreso de codificación:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %d ms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Tip: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Cargando" @@ -2941,19 +3134,18 @@ msgstr "Eficiencia do nitro" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (limitado)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s está listo." @@ -3427,21 +3619,21 @@ msgid "Axis %d" msgstr "Eixo %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Botón %d do mando" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Botón %d do rato" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Eixo %d do rato %s" @@ -3613,26 +3805,30 @@ msgstr "Como máximo, podes ter 3 vidas!" msgid "+1 life." msgstr "+1 vida" -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Fuches moi amodo!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Rematache a carreira!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Gañaches a carreira!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Remataches a carreira no %dº lugar!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s saíu do xogo." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3641,16 +3837,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart pode conectarse a un servidor para descargar complementos e notificarche as actualizacións. Lea a nosa política de privacidade en https://supertuxkart.net/Privacy. Queres que se habilite esta función? (Para cambiar esta configuración máis tarde, vai a opcións, selecciona a lapela \"Xeral\" e edita \"Conectar a Internet\")." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "A túa resolución de pantalla é demasiado baixa para correr o STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "A túa versión do controlador da tarxeta de vídeo é demasiado vella. Instale a última versión." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3658,38 +3854,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "O teu controlador de gráficos parece ser moi antigo. Comproba se hai unha actualización dispoñible. SuperTuxKart recomenda un controlador compatible %s ou mellor. É probable que o xogo aínda funcione, pero nun modo de gráficos reducidos." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "A conexión co servidor excedeu o tempo límite." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s ten a bandeira vermella!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "A bandeira vermella voltou á base!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s ten a bandeira azul!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "A bandeira azul voltou á base!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s capturou a bandeira azul!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s capturou a bandeira vermella!" @@ -3699,7 +3895,7 @@ msgstr "%s capturou a bandeira vermella!" msgid "Eggs: %d / %d" msgstr "Ovos: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Líder" @@ -3707,22 +3903,22 @@ msgstr "Líder" msgid "Final lap!" msgstr "Última volta!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "%iª volta" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%2$s: %1$s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Volta máis rápida:" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "VAS EN SENTIDO CONTRARIO!" @@ -3736,194 +3932,194 @@ msgstr "%s marcou un gol!" msgid "Oops, %s made an own goal!" msgstr "Ups, %s marcou en propia!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "Xurdiu %i o kart con neumático de reposto!" msgstr[1] "Xurdiron %i os karts con neumático de reposto!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Quedaches eliminado!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "%s quedou eliminado." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "O servidor foi desconectado." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Fuches expulsado do servidor." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Fuches expulsado: Ping demasiado alto." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Foi detectado unha mala conexión da rede." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s desconectouse." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Preme no nome do xogador na lista para a xestión do xogador e ver a súa clasificación." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Dificultade: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Máximo de xogadores: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Modo de xogo: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Límite de tempo" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Límite de goles" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Tipo de partida de fútbol: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Progreso do Campionato: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Todos os xogadores uníronse a equipa vermella ou azul." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Agora es o dono do servidor." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Conexión rexeitada: O servidor está ocupado." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Conexión rexeitada: Estás baneado do servidor." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Conexión rexeitada: Contrasinal do servidor incorrecto." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Conexión rexeitada: Os datos do xogo son incompatibles." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Conexión rexeitada: O servidor está cheo." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Conexión rexeitada: A conexión do xogador non é válida." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Non foi posible iniciar ao xogo online." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "O xogo rematou, xa non podes unirte en directo nin como espectador." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Non queda ningún lugar na area: unión en directo está desactivada." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Queda só 1 xogador, volvendo a sala de espera." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "O dono do servidor saíu do xogo." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Estarás mirando o próximo partido." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s entrou no equipo vermello." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s entrou no equipo azul." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s entrou no xogo." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3931,15 +4127,15 @@ msgid "" msgstr "Preme <%s> ou <%s> para cambiar o xogador, <%s> ou <%s> para cambiar a cámara." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "%s Reportado con éxito." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3970,38 +4166,38 @@ msgstr "Contra-reloxo (Campionato)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Todos contra Todos" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Capturar a Bandeira" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s conectou." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s e %s conectaron." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s e %s conectaron." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4009,19 +4205,19 @@ msgstr[0] "%d amigo conectou." msgstr[1] "%d amigos conectaron." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s está agora no servidor \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "Tes %d nova solicitude de amizade!" msgstr[1] "Tes %d novas solicitudes de amizade!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Tes unha nova solicitude de amizade!" @@ -4050,12 +4246,12 @@ msgid "" msgstr "O ficheiro das mellores puntuacións era vello de máis,\ne elimináronse todas as puntuacións." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Seguir ao líder" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Loita a 3 Vidas" @@ -4068,91 +4264,88 @@ msgstr "O ficheiro de repetición está incompleto e non se gardará." msgid "Replay saved in \"%s\"." msgstr "A repetición gardouse en «%s»." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 semana" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 semanas" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 mes" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 meses" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 meses" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 meses" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 ano" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 anos" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Nome do complemento" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Data de actualización" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Non instalado" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s, de %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Actualizando os complementos…" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Produciuse un erro ao intentar conectarse ao sitio web de complementos. Asegúrate de que estás conectado a internet e de que non tes unha devasa bloqueando SuperTuxKart." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Favoritos" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Bloqueado: supera os desafíos activos para conseguir acceso a máis!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Arena aleatoria" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d arena non dispoñíbel para modo individual." -msgstr[1] "%d arenas non dispoñíbel para modo individual." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nabloosy Freksy Woopy, 2021-2022\nAdrián Chaves Fernández, 2010,2015\nAdrián Chaves Fernández, 2015-2016\nAdrián Chaves Fernández, 2010\nAdrián Chaves Fernández, 2010-2011,2013\nAdrián Chaves Fernández\nAuria\nMiguel Anxo Bouzada\nTrutxo64" @@ -4440,7 +4633,7 @@ msgstr "Plátanos apañados" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Derrapar" @@ -4543,7 +4736,7 @@ msgstr "Caza dos ovos rematadas" msgid " (official tracks matching the goal)" msgstr "(circuítos oficiais que corresponden co obxectivo)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4551,91 +4744,95 @@ msgid "" msgstr "Os novos mandos e joysticks aparecerán automaticamente na lista cando os conectes a este dispositivo.\n\nPara engadir unha configuración de teclado, podes usar o botón de abaixo, CON TODO, ten en conta que a maioría dos teclados só admiten un número limitado de pulsacións simultáneas e, polo tanto, non son apropiados para xogos multixogador. (Con todo, podes conectar varios teclados a este dispositivo. Lembra que cada un aínda precisa diferentes combinacións de teclas neste caso.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Engadir un mando de Wii" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Engadir uns controis para o teclado." -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Actualizar" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Versión: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "Destacados" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Tamaño: %s." -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Debes estar conectado para valorar este complemento." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Non foi posíbel descargar o complemento." -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Non se puido instalar o complemento «%s»." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Volve intentalo" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Non se puido eliminar o complemento «%s»." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Descarga en segundo plano completada." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Descarga en segundo plano" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "A descarga en segundo plano xa foi iniciada" -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "O contrasinal actual non é válido." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "O contrasinal debe ter unha lonxitude entre 8 e 30 caracteres!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Os contrasinais non coinciden!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Validando a información" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "O contrasinal cambiouse correctamente." @@ -4656,67 +4853,97 @@ msgstr "As resolucións menores a 1024x768 ou 1280x720 non son soportadas. Algun #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Cámara de dron" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Personalizada" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Desactivado" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Só importantes" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Moi Baixo" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Baixo" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Medio" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Alto" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Moi alto" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4724,7 +4951,7 @@ msgid "" msgstr "SuperTuxKart descargará todos os recursos (incluíndo texturas e música de alta calidade) para proporcionar unha mellor experiencia do xogo. Isto utilizará os teus datos móviles se non tes unha conexión sen fios dispoñíbel." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4741,101 +4968,102 @@ msgstr "Introduce o enderezo do servidor, opcionalmente seguido de : e o porto, msgid "Invalid server address: %s." msgstr "Enderezo do servidor inválido: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Marcha atrás" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Dificultade" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Voltas" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Tempo" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Kart" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Usuario" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Versión" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Non" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Circuíto" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Os %d Mellores Tempos" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s : %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Número de karts: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Obxectivo de tempo: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Voltas: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Sentido Contrario: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(baleiro)" @@ -4923,33 +5151,41 @@ msgid "Press any key..." msgstr "Preme calquera tecla..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "O chat está desactivado, actívao no menú de Opcións." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Volver ás probas de rendemento" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Saír da proba de rendemento" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Voltar á Batalla" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Configurar Novo Xogo" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Reiniciar Batalla" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Saír da Batalla" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Nova carreira" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Saír da carreira" @@ -4965,11 +5201,11 @@ msgstr "%s aínda non ten clasificación." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s é o número %d da clasificación cunha puntuación de %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "O nome de usuario ou o enderezo de correo electrónico non son correctos." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4991,7 +5227,7 @@ msgstr "Carreira de repetición fantasma" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Voltas: %i" @@ -5004,21 +5240,21 @@ msgstr "Tipo: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Posición necesaria: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Tempo necesario: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Puntos de nitro necesarios: %i" @@ -5031,54 +5267,54 @@ msgstr "Número de karts da IA: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Modo de Batalla" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Tipo partida de fútbol" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Localización do servidor: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Pista actual: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Posición" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Xogador" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Clasificacións" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Tempo xogado" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Remover dos marcadores" @@ -5091,74 +5327,74 @@ msgid "No player available for connecting to server." msgstr "Non existe ningún xogador dispoñible para se conectar ao servidor." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Nome de usuario: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Cancelar a solicitude" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Hoxe" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Enviouse a solicitude de amizade!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Aceptouse a solicitude de amizade!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Rexeitouse a solicitude de amizade!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Eliminouse a amizade!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Cancelouse a solicitude de amizade!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Procesando" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Obtendo o último voto" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Podes premer as estrelas de embaixo para modificar a túa puntuación." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Aínda non votaches por este complemento. Preme as estrelas de embaixo para escoller a puntuación que queres outorgarlle." -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Rexistrouse o voto! Xa podes pechar a xanela." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Votando" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Circuíto aleatorio" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5187,7 +5423,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Produciuse un erro ao intentar gardar o campionato." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Escolle un circuíto" @@ -5231,12 +5467,12 @@ msgstr "Desbloqueaches o circuíto «%0»." msgid "You unlocked grand prix %0" msgstr "Desbloqueaches o campionato «%0»." -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Circuíto" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5257,19 +5493,19 @@ msgstr "Escribe o nome do campionato." msgid "Please select a Grand Prix" msgstr "Selecciona un campionato." -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Definido polo usuario" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "O nome está baleiro." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Xa existe outro campionato co mesmo nome." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "O nome é longo de máis." @@ -5278,19 +5514,19 @@ msgstr "O nome é longo de máis." msgid "Better luck next time!" msgstr "Máis sorte a próxima vez!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Superaches un desafío!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Gañaches o Gran Premio!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Completaches o campionato!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Número de karts" @@ -5303,110 +5539,125 @@ msgstr "Estás certo de que queres eliminar esta entrada de alta puntuación?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Estás certo de que queres eliminar todas as túas puntuacións máis altas?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Favorito" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Lixeiro" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Pesado" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Conecta un teclado ou un mando para xogar ao modo multixogador en pantalla dividida" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Kart aleatorio" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Bloqueado" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Todos:\nPremede o botón de seleccionar para unirvos á partida." -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Queres xogar o titorial do xogo?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Non podes xogar en liña sen acceso a internet. Se queres xogar en liña, vai ao menú de opcións e marca \"Conectar á internet\"." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Non podes descargar complementos sen acceso a Internet. Se queres descargar complementos, vai no menú de opcións e marca \"Conectar a Internet\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Non podes descargar complementos sen acceso a Internet. Se queres descargar complementos, vai no menú de opcións e marca \"Conectar a Internet\".\n\nNon obstante, pode eliminar os complementos xa descargados." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "O módulo de complementos está actualmente desactivado da pantalla de configuración." -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Cargando os complementos…" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Estás seguro de querer saír do STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Crear un servidor para a rede local" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Servidor de %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Número de circuíto(s) do Gran Premio" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "O nome debe ter unha lonxitude entre 4 e 30 caracteres!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Caracteres incorrectos no contrasinal!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Preparado" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Unirse en directo" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Observar" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Instalar complemento" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5414,7 +5665,7 @@ msgstr "Por favor, agarda a que o xogo actual (%s) remate: Tempo restante estima #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Por favor, agarda a que o xogo actual remate, tempo restante estimado: %s." @@ -5422,24 +5673,24 @@ msgstr "Por favor, agarda a que o xogo actual remate, tempo restante estimado: % #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Agarda a que finalice (%s) o xogo actual, progreso estimado: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Agarda ata que remate o xogo actual, progreso estimado: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Por favor, agarda a que o xogo actual remate." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5448,7 +5699,7 @@ msgstr[1] "O xogo comezará se hai máis de %d xogadores." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5457,96 +5708,108 @@ msgid_plural "" msgstr[0] "Comezando despois de %d segundo, ou unha vez que todos premeron o botón \"Listo\"." msgstr[1] "Comezando despois de %d segundos, ou unha vez que todos premeron o botón \"Listo\"." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Conectando ao servidor %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Procurando un servidor de xogo rápido" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Tempo restante: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Oxectivos" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Obtendo os logros" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Perfil de %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Desde" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Estado" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Obtendo as amizades" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Nova solicitude" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Pendente" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Desconectado" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Escribe o novo Email abaixo" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "O novo Email deberá ter entre 5 e 254 caracteres!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "O novo Email é inválido!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "Email mudado!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Non foi posible mudar o Email: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Novas do blog de STK" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Data" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Actualmente non hai novas dispoñibles." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Tes que estar autenticado para xogar na rede Global. Fai clic no teu nome de usuario arriba." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Buscando" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Saír do xogo" @@ -5624,34 +5887,34 @@ msgid "Distance (km)" msgstr "Distancia (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Descoñecido" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "No foi detectada a IPv4, non poderás entrar en servidores" #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Non foi detectada unha IPv6, non poderás entrar en servidores" -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Non hai servidores dispoñibles" -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Obtendo os servidores" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Marcadores de servidor" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5659,149 +5922,149 @@ msgstr "Se a maioría dos xogadores escollen o mesmo circuíto e configuracións #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Lugar do elemento aleatorio" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Número de goles para gañar" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Conducir marcha atrás" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Bloqueado: supera os desafíos activos para conseguir acceso a máis!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Acción" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Tecla asociada" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Desactivar o dispositivo" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Activar o dispositivo" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Activar Configuración" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Teclas do xogo" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Teclas do menú" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Xirar á esquerda" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Xirar á dereita" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Acelerar" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Frear / Marcha Atrás" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Disparar" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Mirar cara atrás" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Rescatar" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Pór en pausa a partida" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Arriba" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Abaixo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Esquerda" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Dereita" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Escoller" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Cancelar ou volver" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Cando apareza un elemento en azul, será porque entra en conflito con outra configuración." -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Un elemento de cor vermella indica un conflito na configuración actual." -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5809,17 +6072,27 @@ msgid "" msgstr "Aviso: Non se recomenda usar a tecla Maiús. Ao premer Maiús, todas as teclas que conteñan un carácter que sexa distinto en maiúsculas deixarán de funcionar." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Seguro que queres eliminar a configuración?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Escribe o nome da configuración, deixa en branco para tornar ao nome predefinido" +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Vertical" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Horizontal" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5827,89 +6100,74 @@ msgstr "No modo multixogador, os xogadores poden seleccionar perfís con \ndesva #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Instalar o paquete completo de recursos" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Seguro que queres desinstalar o paquete completo de recursos do xogo?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Teclado %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Dispositivo Táctil" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Toca nun dispositivo para o configurares" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Lingua do sistema" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "No fondo á esquerda" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "No lado dereito" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Oculto" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Centrado" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Vertical" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Horizontal" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Moi pequeno" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Pequeno" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Medio" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Grande" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Moi Grande" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5919,128 +6177,133 @@ msgid "" msgstr "O modo carreira rápida só se pode activar se o xogo non se pechou desde o lanzamento do modo historia.\n\nPechar o xogo antes de completar o modo historia invalida o temporizador.\n\nPara usar o modo carreira rápida, utiliza un novo perfil." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Sincronización vertical" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "A Sincronización vertical forza a tarxeta gráfica a fornecer un novo fotograma só cando o monitor está pronto para mostralo." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Sincronización vertical non funcionará se os teus controladores non o admiten." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Efectos de Partículas: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Personaxes animadas: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Iluminación dinámica: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Dispersión da luz: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" -msgstr "Suavizado das curvas: %s" +msgstr "Suavizado de bordes: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Oclusión ambiental: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Sombras: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Sombras: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Incandescencia: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Resplandor: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Raios crepusculares: %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Calidade da imaxe renderizada: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Detalle xeométrico: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Desenfoque por movemento: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Profundidade de campo: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "O acceso a internet está desactivado. Queres activalo?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Ten que escribir un contrasinal." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Saíndo como «%s»" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Accedendo como «%s»" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Non podes eliminar ao único xogador." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Seguro que queres eliminar ao xogador '%s'?" @@ -6068,7 +6331,7 @@ msgstr "GOL!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Agardando polos demáis" @@ -6103,7 +6366,7 @@ msgstr "Seguir ao líder!" msgid "Top %i" msgstr "%i mellores" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Desafío non superado" @@ -6127,102 +6390,199 @@ msgstr "Preme na icona do podio para iniciar o desafio" msgid "Press fire to start the challenge" msgstr "Dálle a disparar para comezar o desafío." -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Volver á configuración de vídeo" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Gardar os resultados da proba" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Volver ao menú principal" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Saír do servidor" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Cancelar o campionato" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Reiniciar" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Volver á sección de desafíos" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Correr contra a nova repetición fantasma" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Volver ao menú" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Seguro que queres cancelar o campionato?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Informe de rendemento gardado en \"%s\"." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Gaña o equipo vermello" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Gaña o equipo azul" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Empate" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Eliminado despois de %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Eliminado" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Gol en propia meta)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Circuíto %i de %i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Progreso do campionato:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Mellores puntuacións" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Mellor tempo de volta: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "por %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Completaches o desafío!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Fallaches o desafío!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Requisitos da dificultade SuperTux acadados" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Resultados da proba de rendemento" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Duración da proba: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Número de fotogramas: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "FPS estable: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "FPS maiormente estable: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "FPS típico: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Resolución horizontal: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Resolución vertical: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Iluminación dinámica: ACTIVADA" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Iluminación dinámica: DESACTIVADA" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Resolución de renderizado: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Suavizado de bordes: ACTIVADO" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Suavizado de bordes: DESACTIVADO" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Iluminación baseada en imaxes: DESACTIVADA" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Iluminación por imaxe: ACTIVADA" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Oclusión ambiental: ACTIVADA" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Oclusión ambiental: DESACTIVADA" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Resolución das sombras: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Permítense todas as armas, así que sácalles o mellor partido!" @@ -6263,28 +6623,28 @@ msgstr "Toca nas iconas de fútbol vermella ou azul para mudar a equipa" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Circuíto creado por %s." #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Número máximo de xogadores permitidos: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Número de karts AI no equipo vermello" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Non podes xogar este Campeonato porque contén circuítos aínda por desbloquear!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Bloqueado" @@ -6306,10 +6666,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Supera todos os desafíos para desbloquear a porta grande!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6318,41 +6680,48 @@ msgid "" msgstr "Necesitas máis puntos\npara acceder a este desafío!\nBusca desafíos dispoñíbeis\nno minimapa." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Acelera con <%s>, e xira con <%s> e <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Acelera tocando a parte superior do volante e vira movendo cara á esquerda ou á dereita." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Acelera movendo o acelerador cara arriba e xira inclinando o teu dispositivo." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Acelera movendo o acelerador cara arriba e xira rotando o teu dispositivo." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Recolle caixas de agasallos, e dispara con <%s> para estoupar estas caixas!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Recolle caixas de agasallos e dispara premendo na icona de birlos para facelas explotar!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6360,34 +6729,41 @@ msgid "" msgstr "Preme <%s> para mirar atrás.\nDispara a arma con <%s> mentres premes <%s> para disparar de costas!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Preme na ícona do espello para mirar atrás. Dispara a arma que está detrás mantendo premido o ícono do espello e logo deslizando cara á icona de birlos!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Preme <%s> para usar o nitro que recolliches!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Usa o nitro que collas premendo a icona do nitro" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Recolle botellas de nitro (usarémolas pasada a curva)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Ups! Cando teñas problemas, preme <%s> para que te rescaten." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Ups! Cando esteas en problemas, preme na icona do paxaro para ser rescatado." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6395,24 +6771,27 @@ msgid "" msgstr "Acelere e prema a tecla <%s> mentres xira para derrapar.\nDerrapar un pouco pode axudarche a virar máis rápido para dar curvas pronunciadas." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Acelera e preme na icona de derrape mentres estás a virar para derrapar.\nDerrapar durante un curto período de tempo pode axudarte a virar máis rápido para tomar curvas pechadas." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Ten en conta que se consegues derrapar durante varios segundos, conseguirás unha bonificación de velocidade como recompensa!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Estás listo para correr. Sorte!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Un xogo de carreiras de karts en 3D e de código aberto." @@ -6422,7 +6801,7 @@ msgstr "Un xogo de carreiras de karts en 3D e de código aberto." msgid "tux;game;race;" msgstr "tux;xogo;carreira;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6430,7 +6809,7 @@ msgid "" "for all ages." msgstr "Karts. Nitro. Action! SuperTuxKart é un xogo de carreiras arcade en 3D de código aberto con varios personaxes, circuítos e modos para xogar. O noso obxectivo é crear un xogo que sexa máis divertido que realista e ofrecer unha experiencia agradable para todas as idades." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6439,7 +6818,7 @@ msgid "" "your opponents." msgstr "Temos varios circuítos con diferentes temas para que os xogadores gocen, desde conducir baixo a auga, terras agrícolas rurais, xunglas ou incluso no espazo! Tenta ser o mellor mentres evitas cos outros karts che adianten, pero non comas os plátanos! Ollo ás bolas de birlos, chupóns, gomas de mascar e tortas lanzadas polos teus opoñentes." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6448,27 +6827,27 @@ msgid "" "your racing skills!" msgstr "Podes facer unha carreira individual contra outros karts, competir nun dos varios Grand Prix, intentar superar a puntuación máis alta en probas de tempo por ti mesmo, xogar en modo de batalla contra o ordenador ou os teus amigos e moito máis! Para un maior desafío, únete en liña e conéctate con xogadores de todo o mundo para demostrar as túas habilidades como piloto!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Este xogo non contén anuncios." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Esta é unha versión inestable do SuperTuxKart que contén as últimas melloras. Publícase principalmente para probar o xogo e facer unha versión estable do STK tan boa como sexa posible." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Esta versión pódese instalar en paralelo coa versión estable." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Se precisas de maior estabilidade, proba a usar a versión estable: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "Equipo SuperTuxKart" diff --git a/data/po/he.po b/data/po/he.po index d6138713bc9..7f8cd66b03c 100644 --- a/data/po/he.po +++ b/data/po/he.po @@ -24,7 +24,7 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" "Last-Translator: Omer I.S., 2020-2022,2024\n" "Language-Team: Hebrew (http://app.transifex.com/supertuxkart/supertuxkart/language/he/)\n" @@ -54,7 +54,7 @@ msgstr "יציאה" #. I18N: ./data/achievements.xml msgid "Christoffel Columbus" -msgstr "כּריסטוֹפֵל קולומבוס" +msgstr "כּריסטוֹפֶל קולומבוס" #. I18N: ./data/achievements.xml msgid "Play every official track at least once." @@ -94,7 +94,7 @@ msgstr "ביצוע 5 החלקות בהקפה אחת." #. I18N: ./data/achievements.xml msgid "Gold driver" -msgstr "הצטיינות במרוצים" +msgstr "מקום ראשון" #. I18N: ./data/achievements.xml msgid "" @@ -122,11 +122,11 @@ msgstr "ניצחון ב־5 מרוצים בודדים ברצף, נגד 3 מתחר #. I18N: ./data/achievements.xml msgid "Banana Lover" -msgstr "אי אפשר בלי בננות" +msgstr "מזל חלקלק" #. I18N: ./data/achievements.xml msgid "Collect at least 5 bananas in one race." -msgstr "איסוף של 5 בננות לפחות במרוץ אחד." +msgstr "החלקה מ־5 בננות לפחות במרוץ אחד." #. I18N: ./data/achievements.xml msgid "It's secret" @@ -183,7 +183,7 @@ msgstr "בסוף העולם" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "חזרה" @@ -205,7 +205,7 @@ msgstr "נא לבחור את סוג הפקדים המועדף" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "מד תאוצה" @@ -219,13 +219,13 @@ msgstr "מד תאוצה" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "ג׳יירוסקופ" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "הגה" @@ -256,35 +256,37 @@ msgstr "הגדרות התקן מגע" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "כללי" @@ -352,30 +354,33 @@ msgstr "שחזור לברירת המחדל" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "ביטול" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "כן" @@ -431,7 +436,7 @@ msgstr "מצלמה קדמית" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "Follow ball in soccer mode" -msgstr "במצב כדורגל יש לעקוב אחר הכדור" +msgstr "מעקב אחר הכדור במצב כדורגל" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -520,7 +525,7 @@ msgstr "איכות מסירת התמונה" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Geometry detail" -msgstr "רמת פרטי גאומטריה" +msgstr "רמת פירוט גיאומטרי" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -553,9 +558,9 @@ msgstr "הצטרפות" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -616,7 +621,7 @@ msgstr "מטרה" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "התקדמות" @@ -651,7 +656,7 @@ msgstr "שליחה" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "חזרה למרוץ" @@ -668,7 +673,7 @@ msgstr "חזרה למבואה" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "התחלת המרוץ מחדש" @@ -732,12 +737,12 @@ msgstr "נא למלא את שם המשתמש וכתובת הדוא״ל שסיפ #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "שם משתמש" @@ -778,7 +783,7 @@ msgstr "רמת קושי" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "למתחילים" @@ -790,7 +795,7 @@ msgstr "למתחילים" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "רמת ביניים" @@ -802,7 +807,7 @@ msgstr "רמת ביניים" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "למומחים" @@ -814,7 +819,7 @@ msgstr "למומחים" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "רמת סופר־טַקס" @@ -822,8 +827,8 @@ msgstr "רמת סופר־טַקס" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "מצב משחק" @@ -834,8 +839,8 @@ msgstr "מצב משחק" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "מרוץ רגיל" @@ -848,7 +853,7 @@ msgstr "מרוץ רגיל" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "נגד השעון" @@ -856,7 +861,8 @@ msgstr "נגד השעון" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "קרב" @@ -865,24 +871,24 @@ msgstr "קרב" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "כדורגל" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "סיסמה" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "הוספת השרת לסימניות" @@ -893,7 +899,7 @@ msgstr "הוספת שחקן/ית" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "שם" @@ -987,6 +993,50 @@ msgstr "שיוך למקש ESC" msgid "Assign nothing" msgstr "לא לשייך דבר" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "הגדרות תצוגה מומלצות" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "ההגדרות המומלצות יהיו תקינות ברזולוציה הנוכחית" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "אילו הגדרות להעדיף?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "ביצועים" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "איזון בין הביצועים לאיכות התצוגה" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "איכות התצוגה" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "חיסכון בחשמל" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "להפעיל אפקט טשטוש בהגדרות התצוגה?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "התחלת המבחן" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -1001,11 +1051,11 @@ msgstr "הגדרת המרוץ" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "המשך" @@ -1046,10 +1096,15 @@ msgstr "זירות" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "מותקנים" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "עריכת זירות מועדפות" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1059,20 +1114,20 @@ msgstr "מותקנים" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "רגיל" @@ -1083,12 +1138,12 @@ msgstr "רגיל" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "תוספים" @@ -1102,27 +1157,28 @@ msgstr "תוספים" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "הכול" @@ -1161,9 +1217,9 @@ msgstr "הזזה למטה" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "הוספה" @@ -1200,7 +1256,7 @@ msgstr "בחירת שידור רפאים" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "צֵיד ביצים" @@ -1247,10 +1303,10 @@ msgstr "היפוך" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "זמן מרבי (דקות)" @@ -1263,7 +1319,7 @@ msgstr "קבוצת מסלולים" #. I18N: In the grand prix info screen #: src/states_screens/gp_info_screen.cpp:164 msgid "Continue saved GP" -msgstr "להמשיך גרנד פרי שמור" +msgstr "להמשיך סבב מרוצים שמור" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Title in grand prix editor screen @@ -1282,9 +1338,9 @@ msgstr "העתקה" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1295,80 +1351,80 @@ msgstr "שינוי שם" msgid "Save Grand Prix" msgstr "שמירת סבב מרוצים" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "עזרה בנוגע ל־SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "מצבי משחק" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "חיזוקים" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "בננות" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1376,56 +1432,57 @@ msgstr "בננות" msgid "Story Mode" msgstr "מצב עלילה" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "שיעורי נהיגה" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "משחק מרובה משתתפים" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "התחלת ההדרכה" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "יש לאסוף את קופסאות המתנה הכחולות, הן יעניקו לך חיזוקים." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "זהירות מבננות!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1433,58 +1490,58 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "צבירת גז טורבו מאפשרת לקבל האצת מהירות מתי שרוצים בלחיצה על המקש או הכפתור המתאים. אפשר לראות את הרמה הנוכחית של גז הטורבו בפס שנמצא למטה בצדו הימני של מסך המרוץ." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "כשרואים כפתור עם מנעול כמו זה, יש להשלים אתגר כדי לשחרר אותו." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " "help to take sharp turns; while medium skids will boost your speed, long " "skids more so. You can't stop turning while skidding, so orient your kart " "carefully before!" -msgstr "אפשר להחליק בעזרת לחיצה על מקש או כפתור מיוחדים. החלקות קצרות ורצופות מועילות כשיש פנייה חדה. החלקות בינוניות נותנות האצת מהירות, אבל החלקות ארוכות נותנות האצה גדולה יותר. אי אפשר להסתובב בזמן שמחליקים, אז חשוב להטות את המכונית לכיוון הנכון לפני כן!" +msgstr "אפשר להחליק בעזרת לחיצה על מקש או כפתור מיוחדים. החלקות קצרות ורצופות מועילות כשיש פנייה חדה. החלקות בינוניות נותנות האצת מהירות, אבל החלקות ארוכות נותנות האצה גדולה יותר. אי אפשר להסתובב בזמן שמחליקים, לכן חשוב להטות את המכונית לכיוון הנכון לפני כן!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "אפשר לקבל האצה בהזנקה באמצעות לחיצה על כפתור ההאצה ב„היכון!”, לפני שהמרוץ מתחיל." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* אפשר לראות ולשנות את מקשי המשחק באפשרויות התפריט" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "עם SuperTuxKart מגיעים מגוון מצבי משחק:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "מרוץ רגיל: כל האמצעים כשרים, אז יש לאסוף חיזוקים ולהשתמש בהם בחוכמה!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" -msgstr "נגד השעון: ללא חיזוקים כלל, כך שרק כישורי הנהיגה שלך משנים!" +msgstr "נגד השעון: ללא חיזוקים כלל, כך שרק כישורי הנהיגה משנים!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " "disqualified every time the counter hits zero. Beware: going in front of the" " leader will get you eliminated too!" -msgstr "בעקבות המכונית המובילה: להתחרות על המקום השני, המכונית האחרונה תיפסל בכל פעם שבה המונה יתאפס. זהירות: עקיפת המכונית המובילה פוסלת גם כן!" +msgstr "בעקבות המכונית המובילה: מתחרים על המקום השני, המכונית האחרונה תיפסל בכל פעם שבה המונה יתאפס. זהירות: עקיפת המכונית המובילה פוסלת גם כן!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1494,125 +1551,125 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "יש 3 סוגים למצב הקרב: בקרב 3 פגיעות, יש לתקוף אחרים בעזרת הנשקים עד שייגמרו להם כל הפסילות. בתחרות חופשית, השחקנים שפוגעים באחרים הכי הרבה בטווח הזמן או הפגיעות. ב\"לתפוס את הדגל\", על הקבוצה שלך להביא את דגל הקבוצה האחרת לבסיס הדגל שלכם, לכמה שיותר זמן מבלי שהדגל שלכם ייתפס על ידי הקבוצה האחרת." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "כדורגל: משתמשים במכונית כדי לדחוף את הכדור לעבר השער." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "ציד ביצים: מסיירים במסלולים ומוצאים את כל הביצים הנסתרות." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "שידור רפאים: להתחרות נגד שידורי רפאים במרוצים נגד השעון או בציד ביצים, ולהקליט שידור משלך!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "שיא הקפות: השלמה של כמה שיותר הקפות בזמן נתון." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " "instead of playing a single race, you play many in a row. The better you " "rank, the more points you get. In the end, the player with the most points " "wins the cup." -msgstr "* ברוב מצבי המשחק האלה אפשר לשחק גם בתור סבב מרוצים: במקום לשחק במרוץ בודד, משחקים בכמה ברצף. ככל שהדירוג טוב יותר, מקבלים יותר נקודות. בסוף, השחקן/ית עם הניקוד הכי גבוה זוכה בגביע." +msgstr "* ברוב מצבי המשחק האלה אפשר לשחק גם בתור סבב מרוצים: במקום לשחק במרוץ בודד, משחקים בכמה ברצף. ככל שהדירוג טוב יותר, מקבלים יותר נקודות. בסוף, השחקן עם הניקוד הכי גבוה זוכה בגביע." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "אפשר לאסוף את החיזוקים הבאים שיעזרו לך לנצח:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." -msgstr "גומי לעיסה - עוזר לך ליצור מגן חסינות, או לחלופין באמצעות מבט לאחור, להשאיר מאחוריך שלולית ורודה דביקה." +msgstr "מסטיק - יוצר מגן חסינות סביב למכונית שלך, או לחלופין באמצעות מבט לאחור, משליך שלולית ורודה ודביקה לאחור." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" -msgstr "מאיצן - נותן לך האצת מהירות חזקה. אך יש להיזהר שלא לאבד את השליטה במכונית שלך!" +msgstr "מאיצן - נותן לך האצת מהירות עצומה. אך יש להיזהר שלא לאבד את השליטה במכונית שלך!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." -msgstr "עוגה - נזרקת על המתחרה הכי קרוב, מועילה במיוחד בטווחים קצרים ולמרחקים ארוכים בקווים ישרים. היא משפיעה גם על המכוניות האחרות שסמוכות לפיצוץ." +msgstr "עוגה - נזרקת על המתחרה הכי קרוב, הכי יעילה בירייה לטווחים קצרים ולמרחקים ארוכים בקווים ישרים. היא משפיעה גם על מכוניות אחרות שסמוכות לפיצוץ." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "פומפה - נזרקת קדימה למשיכת יריבים לאחור, או נזרקת במבט לאחור כדי לעוור יריבים." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "כדור באולינג - נע ישר עד שהוא פוגע, הוא יכול לנתר מקירות. במבט לאחור, הוא יכול להיזרק לאחור." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "מצנח – מאט את כל המכוניות מלפנים." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "מחליפן - מחליף את כל קופסאות המתנה בבננות, פחיות של גז טורבו בגומי לעיסה ולהפך, למשך זמן קצר." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "כדורסל - מקפץ בעקבות המכונית המובילה, ועשוי למעוך ולהאט מכוניות בדרך." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "מחבט יתושים - מוחץ מכוניות סמוכות ומאט אותן. אפשר להשתמש בו גם להסרת מצנחים ופצצות." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "היתקלות בבננה תצמיד למכונית את אחד מהדברים הבאים:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "עוגן - מאט את המכונית בפתאומיות." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." -msgstr "מצנח - מאט את המכונית, בהדרגה גבוהה משל המצנח. ככל שהנסיעה מהירה יותר, כך גם עוצמת ההאטה." +msgstr "מצנח - מאט את המכונית, בהדרגה גבוהה משל העוגן. ככל שהנסיעה מהירה יותר, כך גם עוצמת ההאטה." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "פצצה - מתפוצצת לאחר זמן מה ומעיפה את המכונית. אפשר להתנגש במכונית אחרת כדי להעביר אליה את הפצצה." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "נוֹלוֹק הרשע לכד את גנו! הינה כמה עצות שיעזרו לך:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1621,7 +1678,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "הסמל הזה במפה הממוזערת מסמל את האתגרים הזמינים שלא הושלמו. בפינה הימנית־עליונה של המסך ניתן לראות גם כמה נקודות צברת עד כה. יש להשלים כמה שיותר שלבים, ואז נוֹלוֹק יהיה מוכן להתחרות נגדך. הגורל של גנו תלוי בך!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1629,20 +1686,20 @@ msgid "" " the cup and the more points it is worth." msgstr "כשמשלימים אתגר, מקבלים גביע. כל גביע שווה מספר נקודות. ככל שהרמה שבה סיימת את האתגר גבוהה יותר, רמת הגביע עולה וגם מספר הנקודות שהוא שווה." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "לאחר שצוברים את כמות הנקודות המופיעה מתחת לסמל הזה, מקבלים הפתעה. יש כל מיני הפתעות שאפשר לקבל." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "לא כל המכוניות זהות! יש להן דרגות שונות עם מספר הבדלים:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1650,7 +1707,7 @@ msgid "" " resistant to explosions." msgstr "מסה - יש שלושה סוגים של מכוניות, תלוי במסה שלהן: קלילות, בינוניות, וכבדות. המכוניות הכבדות יותר מושפעות פחות ממצנחים וחסינות יותר לפיצוצים." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1658,7 +1715,7 @@ msgid "" " especially at low speeds." msgstr "האצה - שימושית במיוחד בהתחלה, לאחר תאונה, או במסלולים עם עקומות חדות. ככל שהמכונית קלה יותר, כך היא מאיצה מהר יותר, במיוחד במהירויות נמוכות." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1666,14 +1723,14 @@ msgid "" " top speed." msgstr "מהירות מרבית - ככל שהיא גבוהה יותר, כך גם מהירות המכונית. שימושית במיוחד במסלולים ישרים עם עקומות עדינות. המהירות הטובה ביותר היא אצל המכוניות הכבדות." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "יעילות גז טורבו - ככל שהיא גבוהה יותר, כך גם המהירות שמקבלים מפחית של גז טורבו. למכוניות קלות יש יעילות גז טורבו גבוהה יותר." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1681,12 +1738,12 @@ msgid "" "easier it is." msgstr "כאשר נצמדים למכונית אחרת למשך כמה שניות, מקבלים בונוס של האצת מהירות אם עוקפים אותה. ככל שהמכונית קלה יותר, יותר קל לעקוף אותה." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "אפשר לשחק ב־SuperTuxKart במצב מרובה משתתפים ברשת...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1696,7 +1753,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "תחילה, יש לבחור בסמל „משחק ברשת” שנמצא בתפריט הראשי. אפשר לבחור בין משחק ברשת המקומית או העולמית (יש צורך בחיבור לאינטרנט). לאחר מכן אפשר ליצור שרת מותאם אישית משלך, או לבחור להצטרף לשרת קיים מתוך הרשימה. חלק מהשרתים הם שרתים מומלצים, עם דירוגי מרוץ שונים." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1706,12 +1763,12 @@ msgid "" "players and the server." msgstr "לאחר שהתחברת לשרת, המרוץ יתחיל לפי ההחלטה של המנהל/ת (עם הסימן של הכתר). בשרתים רשמיים המרוץ עשוי להתחיל אוטומטית כאשר יש מספיק שחקנים. אז, תהיה לך אפשרות לבחור מכונית ולהצביע בנוגע למסלול שיהיה בסיבוב הבא. ניתן לבחור מכוניות מהתוספים אך ורק אם הן מותקנות אצל כל השחקנים שהצטרפו וגם בשרת." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... או על אותו התקן:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1719,9 +1776,9 @@ msgid "" "keyboard(s), each player will need a different set of keys, and most " "keyboards are not appropriate for multiplayer because they don't support " "multiple simultaneous keypresses." -msgstr "ראשית, נחוצים כמה התקני קלט. אפשר להגדיר אותם דרך מסך תצורת הקלט. יש עדיפות לשימוש בבקרי משחק או ג׳ויסטיקים מרובים: כשמשחקים עם המקלד(ו)ת, לכל שחקן/ית יוקצה מערך מקשים אחר, וגם רוב המקלדות לא תומכות במשחק מרובה משתתפים, מכיוון שאין בהן תמיכה בלחיצה על מקשים מרובים בבת אחת." +msgstr "ראשית, נחוצים כמה התקני קלט. אפשר להגדיר אותם דרך מסך תצורת הקלט. יש עדיפות לשימוש בבקרי משחק או ג׳ויסטיקים מרובים: כשמשחקים עם המקלד(ו)ת, לכל שחקן יוקצה מערך מקשים אחר, וגם רוב המקלדות לא תומכות במשחק מרובה משתתפים, מכיוון שאין בהן תמיכה בלחיצה על מקשים מרובים בבת אחת." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1729,7 +1786,7 @@ msgid "" "keyboard to join the game, and use their input device to select their kart. " "The game continues when everyone selected their kart. Note that the mouse " "may not be used for this operation." -msgstr "לאחר הגדרת התקני הקלט, בוחרים בסמל „משחק מרובה משתתפים במסך מפוצל” שבתפריט הראשי. כל השחקנים יכולים ללחוץ על מקש „ירייה” בבקר המשחק שלהם כדי להצטרף למשחק, ואז לבחור מכונית בעזרת התקן הקלט איתו הצטרפו. המשחק ממשיך לאחר שכולם בחרו מכונית. לתשומת ליבך, לא ניתן להשתמש בעכבר לצורך פעולה זו." +msgstr "לאחר שהוגדרו התקני הקלט, בוחרים בסמל „משחק מרובה משתתפים במסך מפוצל” שבתפריט הראשי. כל השחקנים יכולים ללחוץ על מקש „ירייה” בבקר המשחק שלהם כדי להצטרף למשחק, ואז לבחור מכונית בעזרת התקן הקלט שדרכו הצטרפו. המשחק ממשיך לאחר שכולם בחרו מכונית. לתשומת ליבך, לא ניתן להשתמש בעכבר לצורך פעולה זו." #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen @@ -1741,7 +1798,7 @@ msgstr "בחירת שיאים" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "שיא הקפות" @@ -1749,9 +1806,9 @@ msgstr "שיא הקפות" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "סבב מרוצים" @@ -1762,6 +1819,20 @@ msgstr "סבב מרוצים" msgid "Choose a Kart" msgstr "נא לבחור מכונית" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "סוג מכונית" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "עריכת מכוניות מועדפות" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1775,11 +1846,11 @@ msgstr "משחק מרובה משתתפים\nבמסך מפוצל" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "משחק ברשת" @@ -1796,7 +1867,7 @@ msgstr "הדרכה" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "שיאים" @@ -1804,7 +1875,7 @@ msgstr "שיאים" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "הישגים" @@ -1858,30 +1929,30 @@ msgstr "איתור שרת" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "יצירת שרת" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "מבואה" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "הגדרה" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "התחלת המרוץ" @@ -1907,9 +1978,9 @@ msgstr "הכנסת כתובת שרת" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "הפרופיל שלך" @@ -1927,7 +1998,7 @@ msgstr "דירוג שחקנים" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "חברים" @@ -1952,7 +2023,7 @@ msgstr "משחק מהיר" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "הגדרות החשבון" @@ -2002,8 +2073,8 @@ msgid "Online Username" msgstr "שם משתמש ברשת" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "איפוס הסיסמה" @@ -2016,7 +2087,7 @@ msgid "" msgstr "אפשר לשחק גם דרך חשבון מקומי, מבלי ליצור חשבון ברשת. אולם אז, לא יהיה ניתן להתחבר לחברים, לדרג תוספים וכו׳. מומלץ לקרוא את הצהרת הפרטיות שלנו בכתובת https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "בחירת שרת" @@ -2034,339 +2105,409 @@ msgstr "שימוש בחיבור IPv6" msgid "User search" msgstr "חיפוש משתמשים" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "אפשרויות SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "צג" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "תצוגה" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" -msgstr "שמע" +msgstr "צלילים" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" -msgstr "ממשק" +msgstr "ממשק משתמש" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "שחקנים" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "מקשים" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "שפה" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "מוזיקה" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" -msgstr "פעיל" +msgstr "מופעל" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "עוצמת קול" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "אפקטים קוליים" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "מחיקת תצורה" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "בטל הגדרה" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "חזרה לרשימת ההתקנים" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "שינוי שם ההגדרה" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "הפעלת \"Force Feedback\" (אם נתמך)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "רזולוציה" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "מסך מלא" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "שמירת מיקום חלון" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "החלת הרזולוציה החדשה" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "פריסת מסך מפוצל למשחק מרובה משתתפים" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "אפשרויות אינטרנט" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "תמיד להציג את מסך ההתחברות" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "התחברות לאינטרנט" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "התרת התכתבות ברשת" +msgid "Enable chatting in online lobbies" +msgstr "הפעלת התכתבויות במבואות של שרתים ברשת" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "התרת התכתבות במשחקים ברשת" +msgid "Enable chatting in online matches" +msgstr "הפעלת התכתבויות בתחרויות ברשת" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "אפשרויות שונות" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" -msgstr "הפעלת הגבלות לכל שחקן/ית" +msgstr "הפעלת הגבלות לכל שחקן" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "הסרת משאבי המשחק המלאים" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "לחיצה על Enter או לחיצה כפולה על התקן להגדרתו" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "הוספת התקן" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* מקש הבחירה שאיתו מצטרפים למשחק יקבע באיזו תצורה ייעשה שימוש." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "מעטפת" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "מפה מוקטנת" +msgid "Skin variant" +msgstr "ערכת נושא" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "פריסת מסך מפוצל למשחק מרובה משתתפים" +msgid "Minimap" +msgstr "מפה מוקטנת" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "גודל גופן" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "מצלמה" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "התאמה אישית..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "הצגת FPS" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "הצגת החיזוקים שמחזיקות מכוניות אחרות" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "הפעלת קוצב זמן למצב העלילה" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "הפעלת קוצב זמן למצב המשחק המהיר" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "איכות מסירה" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "רמת אפקטים גרפיים" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "רמת אפקטים של טשטוש" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "FPS מרבי" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "הגדרות מותאמות אישית..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "רזולוציה" +msgid "Performance tests" +msgstr "מבחני ביצועים" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "מסך מלא" +msgid "Performance test of the current settings" +msgstr "מבחן הביצועים עם ההגדרות הנוכחיות" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "לזכור את מיקום חלון" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "לזכור את הסיסמה" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "החלת הרזולוציה החדשה" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "מחיקה" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "צבע המכונית" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2379,7 +2520,7 @@ msgstr "נא לבחור מצב משחק" #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen msgid "Use left/right to choose your team and press fire" -msgstr "יש להשתמש במקשים ימינה/שמאלה לבחירת הקבוצה שלך וללחוץ על \"ירייה\"" +msgstr "יש להשתמש במקשים ימינה/שמאלה כדי לבחור קבוצה וללחוץ על \"ירייה\"" #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen @@ -2393,15 +2534,15 @@ msgstr "קבוצה כחולה" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "מספר הקפות" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "מספר המתחרים המדומים" @@ -2416,33 +2557,17 @@ msgstr "מספר המתחרים המדומים בקבוצה הכחולה" msgid "Random Grand Prix" msgstr "סבב מרוצים אקראי" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "עריכת מסלולים מועדפים" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "כניסה" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "לזכור את הסיסמה" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "מחיקה" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "צבע המכונית" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "אפשר לשנות את ערכת הנושא באפשרויות הממשק." @@ -2520,7 +2645,7 @@ msgstr "כשמתקרבים למכוניות אחרות יש להיזהר, הן msgid "" "Basketballs can be destroyed using precise backward shots with a bowling " "ball, cake, or plunger." -msgstr "אפשר להשמיד כדורסל בעזרת זריקה מדויקת לאחור של כדורי באולינג, עוגות, או פומפה." +msgstr "אפשר להשמיד כדורי סל בעזרת זריקה מדויקת לאחור של כדורי באולינג, עוגות, או פומפה." #. I18N: ./data/tips.xml msgid "" @@ -2561,238 +2686,306 @@ msgid "" msgstr "לא חוסמים את הדרך לחברי הקבוצה כשהם מחזיקים את הכדור, אלא מנסים לירות על שחקני הקבוצה היריבה שמנסים למנוע מהם להבקיע גול." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "אַדיוּמי" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "אמנדה" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "גוֹדֵט" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "אימיוּל" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "גַּאברוֹש" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "גנו" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "הקסלי" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "קיקי" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "קוֹנקי" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "נוֹלוֹק" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "פּידג׳ן" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "פּאפי" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "פפר" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "שרה" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "סוזן" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "טַקס" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "וילבֶּר" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" -msgstr "סו" +msgstr "סוּ" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "מצולות עתיקות" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "אותות מהחלל החיצון" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "מבוך הקולוסאום העתיק" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "העיר קַנַדֶלָה" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "אי הקרב" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "היער השחור" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "מערה X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "מקדש הקקאו" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "דרך שדה התירס" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "מבצר המגמה" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "האי גְרַאן פָּרָדיסוֹ" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "המערב הפרוע" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "גומות בקרקע" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "מגרש הכדורגל הקפוא" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "מה קרה, היפים קטנים? המנהיג הדגול שלכם, גנו, נעלם?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "אה כן, תראו, הוא בטירה שלי עכשיו והוא יוגש בתור ארוחת ערב..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "אבל אני יצור הגון, אז אעשה איתכם עסקה." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "אם ינצחו אותי במרוץ, אשחרר את הברנש הזקן." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " אבל טיפשים קטנים ועלובים שכמותכם לעולם לא ינצחו אותי - מלך המכוניות!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "הזירה של לאס דוּנַאס" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "אצטדיון הכדורגל של לאס דוּנַאס" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "מסביב למגדלור" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "המכרה הישן" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "מיני גולף" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "נווה מדבר" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "הכיתה של אוליבר" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "חלקת הדלועים" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "אחוזת רֶיְיבֶנבּרידג׳" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "חולות נודדים" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "האגם של נֶסי" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "נופש בצפון" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "פסגה מושלגת" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "מגרש כדורגל" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "האצטדיון" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "המטה של SuperTuxKart" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "המקדש" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "אי הר הגעש" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "גן יפני עתיק" @@ -2801,11 +2994,11 @@ msgstr "גן יפני עתיק" msgid "Completed achievement \"%s\"." msgstr "הושלם ההישג \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." -msgstr "ההתחברות לשרת התוספים של SuperTuxKart נכשלה." +msgstr "נכשלה ההתחברות לשרת התוספים של SuperTuxKart." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "שגיאה בהורדת החדשות: „%s”." @@ -2871,7 +3064,7 @@ msgid "New kart '%s' now available" msgstr "המכונית החדשה „%s” זמינה כעת" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2895,40 +3088,40 @@ msgstr "אורח/ת %d" msgid "" "Your config file was malformed, so it was deleted and a new one will be " "created." -msgstr "קובץ התצורה שלך היה פגום, ולכן הוא נמחק ויוחלף בקובץ חדש." +msgstr "קובץ התצורה היה פגום, ולכן הוא נמחק ויוחלף בקובץ חדש." #: src/config/user_config.cpp:699 msgid "" "Your config file was too old, so it was deleted and a new one will be " "created." -msgstr "קובץ התצורה שלך היה ישן מדיי, ולכן הוא נמחק ויוחלף בקובץ חדש." +msgstr "קובץ התצורה היה ישן מדי, ולכן הוא נמחק ויוחלף בקובץ חדש." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "הקלטת וידאו החלה." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "ההקלטה נשמרה בתוך \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "התקדמות הקידוד:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" -msgstr "FPS:‏ %d/%d/%d ‏- %d KTris, פינג: %dמ״ש" +msgstr "FPS: %d/%d/%d - %d KTris, Ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "עצה: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "בטעינה" @@ -2950,19 +3143,18 @@ msgstr "יעילות גז טורבו" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "‏%s (עם מגבלות)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s מוכן/ה" @@ -3048,7 +3240,7 @@ msgstr "Ctrl" #: src/input/binding.cpp:116 msgctxt "input_key" msgid "Alt/Menu" -msgstr "" +msgstr "Alt/Menu" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:118 @@ -3079,7 +3271,7 @@ msgstr "Junja" #: src/input/binding.cpp:127 msgctxt "input_key" msgid "Final" -msgstr "" +msgstr "Final" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:129 @@ -3091,7 +3283,7 @@ msgstr "Esc" #: src/input/binding.cpp:131 msgctxt "input_key" msgid "Convert" -msgstr "" +msgstr "Convert" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:133 @@ -3223,7 +3415,7 @@ msgstr "סמליל ימני" #: src/input/binding.cpp:211 msgctxt "input_key" msgid "Apps" -msgstr "" +msgstr "Apps" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:213 @@ -3367,25 +3559,25 @@ msgstr "תפריט ימני" #: src/input/binding.cpp:289 msgctxt "input_key" msgid "Attn" -msgstr "" +msgstr "Attn" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:291 msgctxt "input_key" msgid "Crsel" -msgstr "" +msgstr "Crsel" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:293 msgctxt "input_key" msgid "Exsel" -msgstr "" +msgstr "Exsel" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:295 msgctxt "input_key" msgid "Ereof" -msgstr "" +msgstr "Ereof" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:297 @@ -3409,7 +3601,7 @@ msgstr "Pa1" #: src/input/binding.cpp:303 msgctxt "input_key" msgid "Oem Clear" -msgstr "" +msgstr "Oem Clear" #. I18N: to appear in input configuration screen, for gamepad hats #: src/input/binding.cpp:343 src/input/binding.cpp:348 @@ -3436,21 +3628,21 @@ msgid "Axis %d" msgstr "ציר %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "לחצן בקר %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "כפתור עכבר %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "ציר עכבר %d %s" @@ -3458,11 +3650,11 @@ msgstr "ציר עכבר %d %s" #. I18N: shown when config file is too old #: src/input/device_manager.cpp:496 msgid "Please re-configure your key bindings." -msgstr "נא להגדיר מחדש את המקשים." +msgstr "נא להגדיר מחדש את מערך המקשים." #: src/input/device_manager.cpp:497 msgid "Your input config file is not compatible with this version of STK." -msgstr "קובץ הגדרת הקלט שלך לא מתאים לגרסה זו של SuperTuxKart." +msgstr "קובץ תצורת הקלט לא מתאים לגרסה זו של SuperTuxKart." #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:159 @@ -3487,12 +3679,12 @@ msgstr "לחיצה עם מוט ההיגוי הימני" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:167 msgid "Left shoulder" -msgstr "" +msgstr "לחצן אחורי שמאלי" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:169 msgid "Right shoulder" -msgstr "" +msgstr "לחצן אחורי ימני" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:171 @@ -3589,7 +3781,7 @@ msgid "" "Press the buttons 1+2 simultaneously on your wiimote to put it in discovery " "mode, then click on Ok. Detailed instructions at " "https://supertuxkart.net/Wiimote" -msgstr "יש ללחוץ בבת אחת על המקשים 1 ו־2 בשלט ה־Wii בשביל להעביר אותו למצב איתור התקנים בקרבת מקום ואז ללחוץ על „אישור”. ניתן למצוא הוראות מפורטות בכתובת https://supertuxkart.net/Wiimote" +msgstr "יש להעביר את שלט ה־Wii למצב איתור התקנים קרובים בעזרת לחיצה על המקשים 1 ו־2 באותו הזמן, ואז ללחוץ על „אישור”. ניתן למצוא הוראות מפורטות בכתובת https://supertuxkart.net/Wiimote" #: src/input/wiimote_manager.cpp:405 #, c-format @@ -3601,7 +3793,7 @@ msgstr[2] "נמצאו %d שלטי Wii" #: src/input/wiimote_manager.cpp:410 msgid "Could not detect any wiimote :/" -msgstr "לא היה אפשר לאתר אף שלט Wii :/" +msgstr "לא אותר אף שלט Wii :/" #: src/io/rich_presence.cpp:477 msgid "Getting ready to race" @@ -3623,26 +3815,30 @@ msgstr "אפשר לצבור רק עד 3 פסילות!" msgid "+1 life." msgstr "+1 פסילות." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "נסעת לאט מדיי!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "סיימת את המרוץ!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "ניצחת במרוץ!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "סיימת את המרוץ במקום מספר %d!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "‏%s עזב/ה את המשחק." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3651,55 +3847,55 @@ msgid "" "Internet\")." msgstr "באפשרות SuperTuxKart להתחבר לשרת כדי להוריד תוספים ולהודיע לך על עדכונים. נא לקרוא את מדיניות הפרטיות בכתובת https://supertuxkart.net/Privacy. להפעיל את האפשרות הזאת? (כדי לשנות את ההגדרה הזאת מאוחר יותר, יש לעבור למסך האפשרויות, לבחור בלשונית \"ממשק\" ולערוך את הסימון של \"התחברות לאינטרנט\")." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." -msgstr "רזולוציית המסך שלך נמוכה מדי להפעלת SuperTuxKart." +msgstr "רזולוציית המסך נמוכה מדי להפעלת SuperTuxKart." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "גרסת מנהל ההתקן ישנה מדי. נא להתקין את מנהל ההתקן העדכני ביותר. " -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " "available. SuperTuxKart recommends a driver supporting %s or better. The " "game will likely still run, but in a reduced-graphics mode." -msgstr "מנהל ההתקן של כרטיס המסך שלך נראה ישן מאוד. נא לבדוק אם עדכון זמין. SuperTuxKart ממליצים על מנהל התקנים שתומך ב־%s וטובים יותר. סביר להניח שהמשחק עדיין יפעל, אך במצב של תצוגה באיכות מופחתת." +msgstr "מנהל ההתקן של כרטיס המסך שלך כנראה ישן מאוד. נא לבדוק אם עדכון זמין. SuperTuxKart ממליצים על מנהל התקנים שתומך ב־%s וטובים יותר. סביר להניח שהמשחק עדיין יפעל, אך במצב של תצוגה באיכות מופחתת." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "זמן החיבור לשרת אזל." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "הדגל האדום אצל %s!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "הדגל האדום הוחזר!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "הדגל הכחול אצל %s!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "הדגל הכחול הוחזר!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "הדגל הכחול נתפס על ידי %s!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "הדגל האדום נתפס על ידי %s!" @@ -3709,7 +3905,7 @@ msgstr "הדגל האדום נתפס על ידי %s!" msgid "Eggs: %d / %d" msgstr "ביצים: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "המכונית המובילה" @@ -3717,22 +3913,22 @@ msgstr "המכונית המובילה" msgid "Final lap!" msgstr "הקפה אחרונה!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "הקפה %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s על ידי %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "שיא חדש מהירות חדש להקפה" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "טעות בדרך!" @@ -3746,7 +3942,7 @@ msgstr "‏%s הבקיע/ה גול!" msgid "Oops, %s made an own goal!" msgstr "אופס, %s הבקיע/ה גול עצמי!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" @@ -3754,207 +3950,207 @@ msgstr[0] "הופיעה מכונית צמיגים חלופיים %i!" msgstr[1] "הופיעו %i מכוניות צמיגים חלופיים!" msgstr[2] "הופיעו %i מכוניות צמיגים חלופיים!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "נפסלת!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "„%s” נפסל/ה." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "השרת נכבה." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "סולקת מהשרת." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "סולקת: פינג גבוה מדיי." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "זוהה חיבור לא תקין לרשת." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "בוט" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "‏%s התנתק/ה." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "אפשר ללחוץ על שם של שחקן ברשימה לצורך ניהול ופרטי דירוג השחקן." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "רמה: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "מספר שחקנים מרבי: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "מצב משחק: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "הגבלת זמן" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "מגבלת כמות גולים" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "סוג משחק כדורגל: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "התקדמות בסבב המרוצים: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "כל השחקנים הצטרפו לקבוצה האדומה או הכחולה." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "השרת בניהולך כעת." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "החיבור נדחה: עומס על השרת." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "החיבור נדחה: סולקת מהשרת." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "החיבור נדחה: הסיסמה לשרת שגויה." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "החיבור נדחה: נתוני המשחק אינם שלמים." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "החיבור נדחה: השרת מלא." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." -msgstr "החיבור נדחה: התחברות שחקן/ית שאינה תקינה." +msgstr "החיבור נדחה: התחברות שחקן/ית שגויה." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "התחלת משחק הרשת נכשלה." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "המשחק הסתיים, כבר אי אפשר להצטרף אליו בזמן־אמת או לצפות בו מהצד." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "לא נותר מקום בזירה - ההצטרפות בזמן־אמת הושבתה." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "לא נותרו עוד שחקנים, חוזרים למבואה." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "מנהל/ת השרת יצא/ה מהמשחק." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "עד המשחק הבא יש לצפות במשחק הנוכחי מהצד." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "‏%s הצטרף/ה לקבוצה האדומה." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "‏%s הצטרף/ה לקבוצה הכחולה." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "‏%s הצטרף/ה למשחק." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " "camera position." -msgstr "יש ללחוץ על <%s> או על <%s> כדי לבחור שחקן/ית אחר/ת, על <%s> או על <%s> לשינוי זווית המצלמה." +msgstr "יש ללחוץ על <%s> או על <%s> כדי לבחור שחקן אחר, על <%s> או על <%s> לשינוי זווית המצלמה." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." -msgstr "הדיווח על %s הצליח." +msgstr "הדיווח על %s נשלח בהצלחה." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." -msgstr "הורדת המשאבים נכשלה, יש לבדוק את שטח האחסון שלך או את החיבור לאינטרנט ולנסות שוב מאוחר יותר." +msgstr "נכשלה הורדת המשאבים, נא לבדוק את שטח האחסון או את החיבור לאינטרנט ולנסות שוב מאוחר יותר." #: src/network/protocols/connect_to_server.cpp:230 msgid "No quick play server available." @@ -3969,7 +4165,7 @@ msgstr "אי אפשר להתחבר לשרת %s." #: src/network/protocols/connect_to_server.cpp:883 #, c-format msgid "Failed to detect port number for server %s." -msgstr "כשל בזיהוי מספר הפִּתחה של השרת %s." +msgstr "לא זוהתה פִּתחת השרת %s." #: src/network/protocols/lobby_protocol.cpp:294 msgid "Network grand prix has been finished." @@ -3981,38 +4177,38 @@ msgstr "נגד השעון (סבב מרוצים)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "תחרות חופשית" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "לתפוס את הדגל" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s מחובר/ת כעת." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s וגם %s מחוברים כעת." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s וגם %s מחוברים כעת." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4021,12 +4217,12 @@ msgstr[1] "%d חברים מחוברים כעת." msgstr[2] "%d חברים מחוברים כעת." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s עכשיו בשרת \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4034,7 +4230,7 @@ msgstr[0] "יש לך %d בקשת חברות חדשה!" msgstr[1] "יש לך %d בקשות חברות חדשות!" msgstr[2] "יש לך %d בקשות חברות חדשות!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "יש לך בקשת חברות חדשה!" @@ -4042,7 +4238,7 @@ msgstr "יש לך בקשת חברות חדשה!" msgid "" "Unable to connect to the server. Check your internet connection or try again" " later." -msgstr "אי אפשר להתחבר לשרת. יש לבדוק את החיבור שלך לאינטרנט או לנסות שוב מאוחר יותר." +msgstr "אי אפשר להתחבר לשרת. נא לבדוק את החיבור לאינטרנט או לנסות שוב מאוחר יותר." #: src/race/grand_prix_data.cpp:639 src/states_screens/gp_info_screen.cpp:77 msgid "Default" @@ -4063,12 +4259,12 @@ msgid "" msgstr "קובץ השיאים היה ישן מדי.\nכל השיאים נמחקו." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "בעקבות המכונית המובילה" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "קרב 3 פגיעות" @@ -4081,92 +4277,88 @@ msgstr "קובץ שידור שאינו שלם לא יישמר." msgid "Replay saved in \"%s\"." msgstr "השידור נשמר בתוך \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "שבוע" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "שבועיים" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "חודש" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 חודשים" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "חצי שנה" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 חודשים" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "שנה" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "שנתיים" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "שם התוסף" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "תאריך עדכון" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "לא מותקן" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s מאת %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "נא להמתין במהלך עדכון התוספים" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "אירעה שגיאה בעת ההתחברות לאתר התוספים, עמך הסליחה. נא לוודא שיש לך חיבור לאינטרנט ושחומת אש לא חוסמת את SuperTuxKart" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "מועדפים" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "נעול: יש להשלים אתגרים פעילים כדי לקבל גישה לעוד!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "זירה אקראית" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] " זירה %d אינה זמינה במשחק יחידי." -msgstr[1] "%d זירות אינן זמינות במשחק יחידי." -msgstr[2] "%d זירות אינן זמינות במשחק יחידי." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nNiv Baehr, 2016-2017\nCapri, 2015\ngk, 2015-2016\nLiran, 2016-2017\nOmer I.S., 2020-2024\nעומר רוזנר, 2018\nYaroslav Serhieiev, 2018\nYevgney Sliosarenko, 2015\nעומר רוזנר, 2018-2019\nרואי לוי, 2016\nGenghisKhan, 2015-2016\n‫רואי לוי‬‎, 2016\nAsael\nAuria\nDdorda\nGenghisKhan\nJorge Mariano\nLeo Juszkiewicz\nNiv Baehr\nReuma Mordechai\nSTK-team\nShai Shapira\nShimi Chen\nYaron" @@ -4454,7 +4646,7 @@ msgstr "בננות שנאספו" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "החלקה" @@ -4557,7 +4749,7 @@ msgstr "סיבובי ציד ביצים שהסתיימו" msgid " (official tracks matching the goal)" msgstr " (מסלולים רשמיים שמתאימים למטרה)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4565,91 +4757,95 @@ msgid "" msgstr "בקרי משחק חדשים וג׳ויסטיקים יופיעו ברשימה באופן אוטומטי בעת התחברות למכשיר הזה.\n\nכדי להוסיף תצורת מקלדת, אפשר להשתמש בלחצן שלמטה. עם זאת, יש לשים לב כי רוב המקלדות תומכות בהקשה על מספר מוגבל של מקשים בו־זמנית, ולכן אינן מתאימות למשחק מרובה משתתפים. (אפשר, עם זאת, לחבר כמה מקלדות למחשב. יש לזכור שגם במקרה הזה כל אחת צריכה מערך מקשים שונה.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "הוספת שלט Wii" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "הוספת תצורת מקלדת" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "עדכון" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "גרסה: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "מומלצים" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "גודל: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "בשביל לדרג את התוסף יש להתחבר לחשבון." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "הורדת התוסף נכשלה, עימך הסליחה" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "התקנת התוסף „%s” נתקלה בבעיות." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "ניסיון חוזר" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "הסרת התוסף „%s” נתקלה בבעיות." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "ההורדה ברקע הושלמה." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "הורדה ברקע" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "כבר החלה הורדה ברקע." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "הסיסמה הנוכחית שגויה." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "על אורך הסיסמה להיות בין 8 ל־30 תווים." -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "הסיסמות אינן תואמות." -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "המידע בהליכי אימות" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "הסיסמה שונתה בהצלחה." @@ -4671,67 +4867,97 @@ msgstr "אין תמיכה ברזולוציות נמוכות מ־1024x768 או מ #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "מרדף רחפנים" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "בהתאמה אישית" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "מושבת" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "חשובים בלבד" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "נמוכה מאוד" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "נמוכה" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "בינוני" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "גבוהה" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "גבוהה מאוד" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "גבוהה ביותר" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4739,7 +4965,7 @@ msgid "" msgstr "תתבצע הורדה של משאבי המשחק המלאים של SuperTuxKart (לרבות מרקמים ומוזיקה באיכות גבוהה) בשביל לספק חוויית משחק מיטבית, ייעשה שימוש בחבילת הנתונים הניידים אם אין חיבור פעיל לרשת אלחוטית." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4756,101 +4982,102 @@ msgstr "נא לספק את כתובת השרת אליה אפשר להוסיף msgid "Invalid server address: %s." msgstr "כתובת שרת לא תקינה: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "רוורס" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "רמת קושי" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "הקפות" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "זמן" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "מכונית" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "משתמש/ת" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "גרסה" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "לא" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "מסלול" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "%d השיאים הטובים ביותר" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "מספר מכוניות: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "זמן יעד: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "הקפות: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "נסיעה ברוורס: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(ריק)" @@ -4938,33 +5165,41 @@ msgid "Press any key..." msgstr "נא ללחוץ על מקש כלשהו..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "הצ׳אט מושבת, אפשר להפעילו בתפריט האפשרויות." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "חזרה למבחן הביצועים" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "יציאה ממבחן הביצועים" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "חזרה לקרב" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "הגדרת משחק חדש" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "התחלת הקרב מחדש" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "יציאה מהקרב" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "הגדרת מרוץ חדש" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "יציאה מהמרוץ" @@ -4980,11 +5215,11 @@ msgstr "ל־%s עדיין אין דירוג." msgid "%s is number %d in the rankings with a score of %f." msgstr "‏%s במקום מספר %d עם ניקוד %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "שם המשתמש ו/או כתובת הדוא״ל אינם תקינים." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5006,7 +5241,7 @@ msgstr "מרוץ שידור רפאים" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "הקפות: %i" @@ -5019,21 +5254,21 @@ msgstr "סוג: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "מקום נדרש: %i לפחות" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "זמן נדרש: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "נקודות נדרשות של גז טורבו: %i" @@ -5046,54 +5281,54 @@ msgstr "מספר המתחרים המדומים: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "מצב קרב" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "סוג משחק כדורגל" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "מיקום שרת: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "הרצועה הנוכחית: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "דירוג" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "שחקן/ית" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "ניקוד" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "זמן משחק" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "הסרה מהמועדפים" @@ -5106,74 +5341,74 @@ msgid "No player available for connecting to server." msgstr "אין שחקנים מחוברים לשרת." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "שם משתמש: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "ביטול בקשה" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "היום" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "בקשת החברות נשלחה!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "בקשת חברות אושרה!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "בקשת החברות נדחתה." -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "הסרת את החבר/ה." -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "בקשת החברות בוטלה." -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "מתבצע עיבוד" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "ההצבעה האחרונה מתקבלת" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "אפשר להתאים את הדירוג הקודם שלך בעזרת לחיצה על הכוכבים שלמטה." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "עדיין לא הצבעת לגבי התוסף הזה. יש לבחור את הדירוג הרצוי באמצעות לחיצה על הכוכבים מתחת" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." -msgstr "ההצבעה הצליחה! עכשיו אפשר לסגור את החלון." +msgstr "ההצבעה בוצעה בהצלחה! עכשיו אפשר לסגור את החלון." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "מתבצעת הצבעה" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "מסלול אקראי" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5202,7 +5437,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "אירעה שגיאה במהלך שמירת סבב המרוצים." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "נא לבחור מסלול" @@ -5227,7 +5462,7 @@ msgstr "השלמת את האתגר הקשה! הנקודות שצברת בשלב #, c-format msgid "" "You completed the SuperTux challenge! Points earned on this level: %i/%i" -msgstr "סיימת את אתגר הסופּר־טַקס! הנקודות שצברת בשלב הזה: %i/%i" +msgstr "השלמת את אתגר הסופּר־טַקס! הנקודות שצברת בשלב הזה: %i/%i" #: src/states_screens/feature_unlocked.cpp:315 #, c-format @@ -5246,12 +5481,12 @@ msgstr "פתחת את המסלול %0" msgid "You unlocked grand prix %0" msgstr "נפתח סבב המרוצים %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "מסלול" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5272,19 +5507,19 @@ msgstr "נא לתת שם לסבב המרוצים" msgid "Please select a Grand Prix" msgstr "נא לבחור סבב מרוצים" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "בהגדרת המשתמש/ת" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "נא להקליד שם." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "כבר קיים סבב מרוצים בשם הזה." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "השם ארוך מדי." @@ -5293,19 +5528,19 @@ msgstr "השם ארוך מדי." msgid "Better luck next time!" msgstr "בהצלחה בפעם הבאה!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "השלמת אתגר!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "ניצחת בסבב המרוצים!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "השלמת את סבב המרוצים!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "מספר מכוניות" @@ -5318,110 +5553,125 @@ msgstr "להסיר את הערך הזה מטבלת השיאים?" msgid "Are you sure you want to remove all of your high scores?" msgstr "להסיר את כל השיאים?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "מועדפות" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "קלה" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "כבדה" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "לצורך משחק מרובה משתתפים במסך מפוצל, יש לחבר מקלדת או בקר משחק" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "מכונית אקראית" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "נעול" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "כולם:\nלחצו על כפתור הבחירה כדי להצטרף למשחק" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "להפעיל את ההדרכה של המשחק?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." -msgstr "אי אפשר לשחק ברשת ללא גישה לאינטרנט. אם רוצים לשחק ברשת, יש לגשת לתפריט האפשרויות ולסמן את האפשרות „התחברות לאינטרנט”." +msgstr "אי אפשר לשחק ברשת ללא גישה לאינטרנט. אם ברצונך לשחק ברשת, יש לגשת לתפריט האפשרויות ולסמן את האפשרות „התחברות לאינטרנט”." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." -msgstr "אי אפשר להוריד תוספים ללא גישה לאינטרנט. אם ברצונך להוריד תוספים, יש לעבור לתפריט האפשרויות, ולסמן את \"התחברות לאינטרנט\"." +msgstr "אי אפשר להוריד תוספים ללא גישה לאינטרנט. אם ברצונך להוריד תוספים, יש לעבור לתפריט האפשרויות, ולסמן את האפשרות „התחברות לאינטרנט”." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "אי אפשר להוריד תוספים כשאין גישה לאינטרנט. אם ברצונך להוריד תוספים, יש לעבור לתפריט האפשרויות, ולסמן את \"התחברות לאינטרנט\".\n\nעדיין אפשר למחוק תוספים שכבר הורדו." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "מודול התוספים מושבת כרגע במסך האפשרויות" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "נא להמתין במהלך טעינת התוספים" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "לצאת מ־SuperTuxKart?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "יצירת שרת מקומי" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "השרת של %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "כמות המסלול(ים) בסבב המרוצים" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "על אורך השם להיות בין 4 ל־30 תווים!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "ישנם תווים לא תקינים בסיסמה." #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "מוכנים" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "הצטרפות בזמן אמת" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "צפייה מהצד" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "התקנת התוסף" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5429,7 +5679,7 @@ msgstr "נא להמתין עד סוף המשחק הנוכחי (%s), זמן נו #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "נא להמתין עד הסוף המשחק הנוכחי, הזמן המשוער שנותר: %s." @@ -5437,24 +5687,24 @@ msgstr "נא להמתין עד הסוף המשחק הנוכחי, הזמן המש #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "נא להמתין עד סוף המשחק הנוכחי (%s), התקדמות משוערת: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "נא להמתין עד סוף המשחק הנוכחי, התקדמות משוערת: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "נא להמתין עד סוף המשחק הנוכחי." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5464,7 +5714,7 @@ msgstr[2] "המשחק יתחיל אם יש יותר מ־%d שחקנים." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5474,96 +5724,108 @@ msgstr[0] "מתחילים לאחר שנייה %d, או לאחר שכולם לח msgstr[1] "מתחילים לאחר %d שניות, או לאחר שכולם לחצו על כפתור \"מוכנים\"." msgstr[2] "מתחילים לאחר %d שניות, או לאחר שכולם לחצו על כפתור \"מוכנים\"." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "מתבצעת התחברות לשרת %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "מתבצע איתור שרת למשחק מהיר" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "הזמן שנותר: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "מטרות" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "ההישגים מתקבלים" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "הפרופיל של %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "מאז" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "מצב" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "רשימת החברים מתקבלת" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "בקשה חדשה" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "בהמתנה" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "לא מחובר/ת" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "נא לספק כתובת דוא״ל חדשה למטה" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "על אורך כתובת הדוא״ל החדשה להיות בין 5 ל־254 תווים!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "כתובת הדוא״ל החדשה אינה תקינה." -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "כתובת הדוא״ל שונתה." -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "שינוי כתובת הדוא״ל נכשל: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "חדשות מהבלוג של SuperTuxKart" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "תאריך" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "אין חדשות זמינות כרגע." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "יש להתחבר לחשבון כדי לשחק ברשת העולמית. לשם כך, יש ללחוץ על שם המשתמש שלך למעלה." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "מתבצע חיפוש" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "יציאה מהמשחק" @@ -5641,34 +5903,34 @@ msgid "Distance (km)" msgstr "מרחק (ק״מ)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "לא ידוע" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "לא זוהה IPv4, ייתכן שלא יהיה אפשר כלל להתחבר לשרתים." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "לא זוהה IPv6, ייתכן שלא יהיה אפשר כלל להתחבר לשרתים." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "אין שרתים זמינים." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "השרתים מתקבלים" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "שרתים מועדפים" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5676,149 +5938,149 @@ msgstr "אם רוב השחקנים יבחרו את אותו המסלול ואת #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "מיקום חפצים אקראי" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "מספר גולים עד לניצחון" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "נהיגה ברוורס" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "נעול: יש להשלים אתגרים פעילים כדי לקבל גישה לעוד!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "פעולה" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "מקשים" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "נטרול התקן" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "הפעלת ההתקן" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "לאפשר הגדרה" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "מקשי משחק" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "מקשי תפריט" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "הטיה שמאלה" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "הטיה ימינה" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "האצה" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "בלמים / רוורס" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "ירייה" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "גז טורבו" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "מבט לאחור" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "חילוץ" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "השהיית המשחק" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "למעלה" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "למטה" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "שמאלה" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "ימינה" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "בחירה" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "ביטול/חזרה" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* פריט בצבע כחול מסמל סתירה של תצורה אחרת" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* פריט אדום מסמל סתירה בתצורה הנוכחית" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5826,107 +6088,102 @@ msgid "" msgstr "אזהרה: לא מומלץ לבחור במקש „Shift”. כאשר „Shift” לחוץ, כל המקשים הדו־מצביים יפסיקו לעבוד." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "למחוק הגדרה זו לצמיתות?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." -msgstr "נא לספק שם הגדרה חדש, יש להשאיר ריק כדי לשחזר לערך ברירת המחדל." +msgstr "נא לתת שם תצורה חדש, ניתן להשאיר שדה זה ריק על מנת לשחזר לברירת המחדל." + +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "אנכי" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "אופקי" #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" -msgstr "במצב משחק מרובה משתתפים, השחקנים יכולים לבחור\nפרופילים עם הגבלות (קשה יותר) במסכי בחירת המכונית" +msgstr "במצב מרובה משתתפים, השחקנים יכולים לבחור בהגבלות\nלפרופיל (שהופכות את המשחק למאתגר יותר) במסך בחירת המכונית" #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "התקנת משאבי המשחק המלאים" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "להסיר את משאבי המשחק המלאים?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "מקלדת %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "התקן מגע" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "יש להקיש על התקן כדי להגדירו" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "שפת המערכת" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "בצד שמאל למטה" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "בצד ימין" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "מוסתר" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "במרכז" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "אנכי" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "אופקי" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" -msgstr "קטן מאוד" +msgstr "פצפון" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "קטן" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "בינוני" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "גדול" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" -msgstr "גדול מאוד" +msgstr "ענק" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5936,128 +6193,133 @@ msgid "" msgstr "אפשר להפעיל את מצב המשחק המהיר רק אם המשחק לא נסגר מאז הפעלת מצב העלילה לראשונה.\n\nסגירת המשחק לפני סיום מצב העלילה תבטל את קוצב הזמן.\n\nכדי להשתמש במצב המשחק המהיר, נא להשתמש בפרופיל חדש." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "סנכרון אנכי (Vsync)" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "הסנכרון האנכי (Vsync) מכריח את כרטיס המסך\nלספק מסגרת חדשה רק כאשר הצג מוכן להציגה." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." -msgstr "הסנכרון האנכי (Vsync) לא יפעל אם למנהלי ההתקנים שלך אין תמיכה בו." +msgstr "הסנכרון האנכי (Vsync) לא יפעל אם למנהלי ההתקנים במכשיר אין תמיכה בו." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "אפקטים של חלקיקים: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "דמויות מונפשות: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" -msgstr "אורות דינמיים: %s" +msgstr "תאורה דינמית: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "פיר אור: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "החלקת עקומות: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "אטימות מקיפה: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "צללים: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "צללים: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "פריחה: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "זוהר (מתווה): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "פיר אור: %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "איכות מסירת תמונה: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "רמת פירוט גיאומטרי: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "טשטוש תנועה: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "עומק שדה: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "הגישה לאינטרנט מושבתת. להפעיל אותה?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "יש להזין סיסמה." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "מתבצעת יציאה מחשבון „%s”" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "מתבצעת התחברות לחשבון „%s”" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "אי אפשר למחוק את השחקן/ית היחיד/ה." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "למחוק את „%s”?" @@ -6085,7 +6347,7 @@ msgstr "גול!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "בהמתנה לאחרים" @@ -6120,9 +6382,9 @@ msgstr "צאו בעקבות המכונית המובילה!" msgid "Top %i" msgstr "%i הטובים ביותר" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" -msgstr "נכשלת באתגר" +msgstr "האתגר נחל כישלון" #. I18N: Shown when multitouch GUI exists #. and press the podium (2, 1, 3 like) icon instead of fire button @@ -6144,109 +6406,206 @@ msgstr "יש ללחוץ על סמל הפודיום להתחלת האתגר" msgid "Press fire to start the challenge" msgstr "יש ללחוץ על ירייה להתחלת האתגר" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "חזרה להגדרות התצוגה" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "שמירת תוצאות הבדיקה" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "חזרה לתפריט הראשי" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "יציאה מהשרת" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "נטישת סבב המרוצים" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "התחלה מחדש" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "חזרה לבחירת אתגרים" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" -msgstr "להתחרות נגד שידור הרפאים החדש" +msgstr "מרוץ נגד שידור הרפאים החדש" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "חזרה לתפריט" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "לנטוש את סבב המרוצים?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "דו״ח הביצועים נשמר בתוך „%s”." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "הניצחון בידי הקבוצה האדומה" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "הניצחון בידי הקבוצה הכחולה" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "זהו תיקו" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "נפסלת לאחר %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "נפסל/ה" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(גול עצמי)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "מסלול %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "התקדמות בסבב המרוצים:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "שיאים" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "זמן ההקפה הטוב ביותר: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "על ידי %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "השלמת את האתגר!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" -msgstr "נכשלת באתגר!" +msgstr "השלמת האתגר נחלה כישלון!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "הגעת ליכולות הנחוצות לרמת סופר־טַקס" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "תוצאות מבחן הביצועים" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "משך הזמן של הבדיקה: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "מספר תמוניות: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "רמת FPS יציבה: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "רמת FPS כמעט יציבה: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "רמת FPS ממוצעת: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "רזולוציה אופקית: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "רזולוציה אנכית: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "תאורה דינמית: מופעלת" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "תאורה דינמית: מושבתת" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "איכות מסירה: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "החלקת עקומות: מופעלת" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "החלקת עקומות: מושבתת" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "תאורה בהתאם לתמונה: מושבתת" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "תאורה בהתאם לתמונה: מופעלת" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "אטימות מקיפה: מופעלת" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "אטימות מקיפה: מושבתת" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "רזולוציית צל: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "כל האמצעים כשרים, אז יש לאסוף נשקים ולהשתמש בהם בחוכמה!" #: src/states_screens/race_setup_screen.cpp:96 msgid "Contains no powerups, so only your driving skills matter!" -msgstr "ללא חיזוקים כלל, כך שרק כישורי הנהיגה שלך משנים!" +msgstr "ללא חיזוקים כלל, כך שרק כישורי הנהיגה משנים!" #. I18N: short definition for follow-the-leader game mode #: src/states_screens/race_setup_screen.cpp:109 @@ -6280,28 +6639,28 @@ msgstr "לחצו על סמל כדורגל אדום או כחול כדי לשנו #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "מסלול מאת %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "מספר השחקנים המרבי שנתמך: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "מספר המתחרים המדומים בקבוצה האדומה" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "אי אפשר לשחק בסבב המרוצים הזה מכיוון שהוא מכיל מסלולים שלא נפתחו עדיין." -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "נעול!" @@ -6323,10 +6682,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "יש להשלים את כל האתגרים כדי לפתוח את הדלת הגדולה!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6335,76 +6696,90 @@ msgid "" msgstr "נקודות נוספות נחוצות\nכדי להיכנס לאתגר הזה!\nיש לבדוק את המפה המוקטנת\nכדי למצוא אתגרים זמינים." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "אפשר להאיץ עם <%s>, ולנווט עם <%s> ועם <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "יש להאיץ בעזרת לחיצה על החלק העליון של ההגה, ואפשר לפנות ימינה או שמאלה." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "יש להאיץ בעזרת הרמת דוושת ההאצה, ואפשר להטות את המכשיר לצדדים בשביל לפנות." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "יש להאיץ בעזרת הרמת דוושת ההאצה, ואפשר לסובב את ההתקן כדי לִפנות." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" -msgstr "אפשר לאסוף קופסאות מתנה, ולירות את כלי הנשק באמצעות <%s> כדי להעיף את הארגזים מכאן!" +msgstr "זה הזמן לאסוף מתנות, לירות את כלי הנשק ולהעיף את הארגזים האלה באמצעות <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" -msgstr "אפשר לאסוף קופסאות מתנה, ולירות את כלי הנשק באמצעות סמל כדור הבאולינג כדי להעיף את הארגזים מכאן!" +msgstr "זה הזמן לאסוף מתנות, לירות את כלי הנשק ולהעיף את הארגזים האלה באמצעות סמל כדור הבאולינג!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" "Fire the weapon with <%s> while pressing <%s> to fire behind!" -msgstr "אפשר ללחוץ על <%s> כדי להסתכל לאחור.\nאפשר לירות את כלי הנשק עם <%s> במהלך לחיצה על <%s> כדי לירות אותו לאחור!" +msgstr "בשביל להביט לאחור, לוחצים על <%s>.\nאפשר לירות את כלי הנשק בעזרת לחיצה על <%s> ועל <%s> בו־זמנית כדי לירות אותו לאחור!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" -msgstr "אפשר ללחוץ על סמל המראה כדי להסתכל לאחור.\nאפשר לירות את כלי הנשק לאחור באמצעות החזקת סמל המראה לחוץ ואז לחיצה על סמל כדור הבאולינג!" +msgstr "בשביל להביט לאחור, לוחצים על סמל המראה.\nאפשר לירות את כלי הנשק לאחור בעזרת החזקת סמל המראה לחוץ ולחיצה על סמל כדור הבאולינג!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" -msgstr "אפשר להשתמש בגז הטורבו שצברת בלחיצה על <%s>!" +msgstr "אפשר להשתמש בגז הטורבו שצברת בלחיצה על <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" -msgstr "אפשר להשתמש בגז הטורבו שצברת בעזרת לחיצה על סמל של גז הטורבו" +msgstr "אפשר להשתמש בגז הטורבו שצברת בעזרת לחיצה על סמל גז הטורבו" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "כעת יש לאסוף בקבוקי גז טורבו (נשתמש בהם לאחר העקומה)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." -msgstr "אופס! אם נקלעת לצרה, לחיצה על <%s> תחלץ אותך." +msgstr "אופס! אם תעית בדרך, לחיצה על <%s> תחלץ אותך." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." -msgstr "אופס! אם נקלעת לצרה, לחיצה על סמל הציפור תחלץ אותך." +msgstr "אופס! אם תעית בדרך, לחיצה על סמל הציפור תחלץ אותך." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6412,24 +6787,27 @@ msgid "" msgstr "אפשר להאיץ וללחוץ על מקש <%s> במהלך פנייה כדי להחליק. החלקה למשך זמן קצר תעזור לך להסתובב מהר יותר כדי לפנות פניות חדות." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." -msgstr "יש להאיץ וללחוץ על סמל ההחלקה תוך כדי סיבוב כדי להחליק.\nהחלקה לזמן קצר יכולה לעזור לך להסתובב מהר יותר בשביל פניות חדות." +msgstr "בשביל להחליק על המסלול, לוחצים ומחזיקים על סמל ההחלקה תוך כדי שמסתובבים.\nהחלקה לזמן קצר יכולה לעזור לך להסתובב מהר יותר בשביל פניות חדות." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "לתשומת ליבך, אם מצליחים להחליק למשך כמה שניות, מקבלים האצה נוספת בתור פרס!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "עברת בהצלחה את ההכשרה למרוץ. בהצלחה!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "משחק תלת־ממדי בקוד פתוח של מֵרוצי מכוניות" @@ -6439,24 +6817,24 @@ msgstr "משחק תלת־ממדי בקוד פתוח של מֵרוצי מכוני msgid "tux;game;race;" msgstr "tux;game;race;טקס;טאקס;טוקס;משחק;מרוץ;מרוצים;מירוץ;מירוצים;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " "game that is more fun than realistic, and provide an enjoyable experience " "for all ages." -msgstr "מכוניות. גז טורבו. אקשן! SuperTuxKart הוא משחק ארקייד תלת־ממדי בקוד פתוח של תחרויות מרוץ עם מגוון דמויות, מסלולים, ומצבים למשחק. מטרתנו ליצור משחק מהנה יותר מהמציאות, ולספק חוויה מהנה לכל הגילאים." +msgstr "מכוניות. גז טורבו. אקשן! SuperTuxKart הוא משחק ארקייד תלת־ממדי בקוד פתוח של תחרויות מרוץ עם מגוון דמויות, מסלולים, ומצבי משחק. מטרתנו ליצור משחק מהנה יותר מהמציאות, ולספק חוויה מהנה לכל הגילאים." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" " while avoiding other karts as they may overtake you, but don't eat the " "bananas! Watch for bowling balls, plungers, bubble gum, and cakes thrown by " "your opponents." -msgstr "יש לנו כמה מסלולים במגוון נושאים שהשחקנים יכולים ליהנות מהם, החל מצלילה במצולות, חוות חקלאיות, ג׳ונגלים, ועד לחלל! במשחק יש לנסוע במיטב יכולתך תוך הימנעות ממכוניות אחרות שעלולות לעקוף אותך, ולא לאכול את הבננות! אפשר לצפות בכדורי באולינג, פומפות, גומי לעיסה, ועוגות שזורקים היריבים שלך." +msgstr "יש לנו מגוון מסלולים מהנים בנושאים שונים, החל מצלילה במצולות, חוות חקלאיות, ג׳ונגלים, ועד לחלל! מטרת המשחק היא לנסוע הכי טוב שאפשר, להתחמק ממכוניות אחרות שעלולות לעקוף אותך, ולא לאכול את הבננות! זהירות מכדורי באולינג, פומפות, מסטיקים, ועוגות שזורקים היריבים." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6465,27 +6843,27 @@ msgid "" "your racing skills!" msgstr "אפשר להתחרות במרוץ בודד נגד מכוניות אחרות, להתחרות באחד מסבבי המרוצים, לנסות לשבור את השיא שלך לבד במרוץ נגד השעון, לשחק במצב קרב מול המחשב או החברים, ועוד! אתגר גדול יותר: להצטרף למרוץ ברשת, לפגוש שחקנים מכל רחבי העולם ולהוכיח את כישורי המרוץ שלך!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "במשחק הזה אין פרסומות." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "זוהי גרסה לא יציבה של SuperTuxKart, המכילה את השיפורים החדשים ביותר. היא פורסמה בעיקר למטרות בדיקה, בשביל לוודא שהגרסה היציבה של SuperTuxKart תהיה טובה ככל האפשר." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "ניתן להתקין גרסה זו על המכשיר במקביל לגרסה היציבה." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "אם יש לך צורך בעוד יציבות, נא לשקול להשתמש בגרסה היציבה: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "צוות SuperTuxKart" diff --git a/data/po/hi.po b/data/po/hi.po new file mode 100644 index 00000000000..a1989f3e6b5 --- /dev/null +++ b/data/po/hi.po @@ -0,0 +1,6849 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the supertuxkart package. +# +# Translators: +# Bashishtha Narayan Singh , 2021-2024 +# FIRST AUTHOR , 2011 +# Kevin 008, 2021,2024-2025 +# Romal Joseph , 2019 +msgid "" +msgstr "" +"Project-Id-Version: SuperTuxKart\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" +"PO-Revision-Date: 2015-02-15 01:58+0000\n" +"Last-Translator: Kevin 008, 2021,2024-2025\n" +"Language-Team: Hindi (http://app.transifex.com/supertuxkart/supertuxkart/language/hi/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: hi\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. I18N: In Android UI, po_extract_game_data +msgid "Extracting game data..." +msgstr "गेम डेटा निष्कर्षण हो रहा रहा है..." + +#. I18N: In Android UI, po_extract_error +msgid "Game data extraction error" +msgstr "गेम डेटा निष्कर्षण त्रुटि" + +#. I18N: In Android UI, po_extract_error_msg +msgid "Check remaining device space or reinstall SuperTuxKart." +msgstr "डिवाइस में शेष स्थान की जाँच करें या SuperTuxKart को पुनः स्थापित करें." + +#. I18N: In Android UI, po_quit +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "Quit" +msgstr "निकल जाएं" + +#. I18N: ./data/achievements.xml +msgid "Christoffel Columbus" +msgstr "क्रिस्टोफेल कोलंबस" + +#. I18N: ./data/achievements.xml +msgid "Play every official track at least once." +msgstr "हर आधिकारिक ट्रैक को कम से कम एक बार चलायें." + +#. I18N: ./data/achievements.xml +msgid "Strike!" +msgstr "स्ट्राइक!" + +#. I18N: ./data/achievements.xml +msgid "Hit 10 karts with a bowling-ball." +msgstr "एक बॉलिंग-बॉल से 10 कार्ट्स को निशाना बनाएं." + +#. I18N: ./data/achievements.xml +msgid "Arch Enemy" +msgstr "कट्टर दुश्मन" + +#. I18N: ./data/achievements.xml +msgid "Hit the same kart at least 5 times in one race." +msgstr "एक रेस में उसी कार्ट को कम से कम 5 बार धक्का मारें." + +#. I18N: ./data/achievements.xml +msgid "Marathoner" +msgstr "मैराथन धावक" + +#. I18N: ./data/achievements.xml +msgid "Finish a race with at least twice the track's default lap number." +msgstr "ट्रैक की डिफ़ॉल्ट लैप संख्या के साथ कम से कम दो बार दौड़ पूरी करें।" + +#. I18N: ./data/achievements.xml +msgid "Skid-row" +msgstr "स्किड-पंक्ति" + +#. I18N: ./data/achievements.xml +msgid "Skid 5 times in a single lap." +msgstr "एक ही गोद में 5 बार स्किड करें।" + +#. I18N: ./data/achievements.xml +msgid "Gold driver" +msgstr "गोल्ड ड्राइवर" + +#. I18N: ./data/achievements.xml +msgid "" +"Win against at least 3 AIs in normal race, time-trial, and follow the " +"leader." +msgstr "सामान्य दौड़, समय-परीक्षण में कम से कम 3 एआई के खिलाफ जीतें और नेता का पालन करें।" + +#. I18N: ./data/achievements.xml +msgid "Powerup Love" +msgstr "पावरअप लव" + +#. I18N: ./data/achievements.xml +msgid "Use 10 or more powerups in a race." +msgstr "दौड़ में 10 या अधिक पावरअप का प्रयोग करें।" + +#. I18N: ./data/achievements.xml +msgid "Unstoppable" +msgstr "अजेय" + +#. I18N: ./data/achievements.xml +msgid "" +"Win 5 single races in a row against at least 3 AIs. Beware, restarting a " +"race counts as a loss." +msgstr "कम से कम 3 AI के खिलाफ एक पंक्ति में 5 एकल दौड़ जीतें। खबरदार, दौड़ को फिर से शुरू करने से नुकसान होता है।" + +#. I18N: ./data/achievements.xml +msgid "Banana Lover" +msgstr "केला प्रेमी" + +#. I18N: ./data/achievements.xml +msgid "Collect at least 5 bananas in one race." +msgstr "एक दौड़ में कम से कम 5 केले जीतें।" + +#. I18N: ./data/achievements.xml +msgid "It's secret" +msgstr "ये एक रहस्य है" + +#. I18N: ./data/achievements.xml +msgid "Really ... a secret." +msgstr "सचमुच एक रहस्य है ये" + +#. I18N: ./data/achievements.xml +msgid "Mosquito Hunter" +msgstr "मच्छर शिकारी" + +#. I18N: ./data/achievements.xml +msgid "" +"Take your opponents for mosquitos! With the swatter, squash them at least 5 " +"times in a race." +msgstr "अपने विरोधियों को मच्छरों से बदलें! स्वैटर के साथ, उन्हें दौड़ में कम से कम 5 बार स्क्वैश करें। " + +#. I18N: ./data/achievements.xml +msgid "Beyond Luck" +msgstr "भाग्य से परे" + +#. I18N: ./data/achievements.xml +msgid "" +"Win 10 single races in a row in Expert or SuperTux against at least 5 AIs. " +"Beware, restarting a race counts as a loss." +msgstr "एक्सपर्ट या सुपरटक्स में कम से कम 5 AI के खिलाफ लगातार 10 एकल रेस जीतें। सावधान रहें, दौड़ को फिर से शुरू करना नुकसान के रूप में गिना जाता है। " + +#. I18N: ./data/grandprix/1_penguinplayground.grandprix +msgid "Penguin Playground" +msgstr "पेंगुइन खेल-मैदान" + +#. I18N: ./data/grandprix/2_offthebeatentrack.grandprix +msgid "Off the Beaten Track" +msgstr "अनजान रास्ते" + +#. I18N: ./data/grandprix/3_tothemoonandback.grandprix +msgid "To the Moon and Back" +msgstr "चंदामामा की सैर" + +#. I18N: ./data/grandprix/4_atworldsend.grandprix +msgid "At World's End" +msgstr "अनंत से भी आगे" + +#. I18N: ./data/gui/dialogs/addons_loading.stkgui +#. I18N: Add-on screen action +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +#. I18N: ./data/gui/dialogs/high_score_info_dialog.stkgui +#. I18N: High score info screen action +#. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui +#. I18N: In the server info dialog +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:157 +#: src/states_screens/dialogs/addons_loading.cpp:320 +msgid "Back" +msgstr "पीछे" + +#. I18N: ./data/gui/dialogs/addons_loading.stkgui +#. I18N: Add-on screen action +msgid "Install" +msgstr "स्थापित करें" + +#. I18N: ./data/gui/dialogs/addons_loading.stkgui +#. I18N: Add-on screen action +msgid "Uninstall" +msgstr "विस्थापित करें" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +msgid "Select a type of control that you prefer" +msgstr "एक प्रकार का नियंत्रण चुनें जिसे आप पसंद करते हैं" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: Control type +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 +msgid "Accelerometer" +msgstr "त्वरणमापी" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: Control type +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +#. I18N: Race paused button +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 +msgid "Gyroscope" +msgstr "जाइरोस्कोप" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: Control type +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 +msgid "Steering wheel" +msgstr "स्टीयरिंग व्हील" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Auto acceleration" +msgstr "ऑटो त्वरण" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +msgid "You can change it later in touch device settings." +msgstr "आप इसे बाद में टच डिवाइस सेटिंग में बदल सकते हैं।" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +#. I18N: ./data/gui/dialogs/kart_color_slider.stkgui +#. I18N: In the kart color slider dialog +msgid "Apply" +msgstr "लागू करें" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +msgid "Touch Device Settings" +msgstr "टच डिवाइस सेटिंग्स" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "General" +msgstr "सामान्य" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Device enabled" +msgstr "डिवाइस सक्षम" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Inverted buttons" +msgstr "उल्टे बटन" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Buttons scale" +msgstr "बटन स्केल" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Advanced" +msgstr "उन्नत" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Deadzone" +msgstr "मृत क्षेत्र" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Sensitivity X" +msgstr "X संवेदनशीलता" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Sensitivity Y" +msgstr "Y संवेदनशीलता" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +msgid "Restore defaults" +msgstr "डिफॉल्ट्स का पुनःस्थापन" + +#. I18N: ./data/gui/dialogs/confirm_dialog.stkgui +#. I18N: In a 'are you sure?' dialog +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +#. I18N: ./data/gui/dialogs/enter_address_dialog.stkgui +#. I18N: In the enter address dialog +#. I18N: ./data/gui/dialogs/general_text_field_dialog.stkgui +#. I18N: In the general textfield dialog +#. I18N: ./data/gui/dialogs/kart_color_slider.stkgui +#. I18N: In the kart color slider dialog +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/dialogs/online/registration_terms.stkgui +#. I18N: In the registration dialog +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +#. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui +#. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +#. I18N: ./data/gui/screens/edit_track.stkgui +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 +#: src/states_screens/online/register_screen.cpp:168 +#: src/states_screens/options/user_screen.cpp:115 +msgid "Cancel" +msgstr "रद्द" + +#. I18N: ./data/gui/dialogs/confirm_dialog.stkgui +#. I18N: In a 'are you sure?' dialog +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 +#: src/states_screens/edit_gp_screen.cpp:261 +#: src/states_screens/ghost_replay_selection.cpp:394 +#: src/states_screens/high_score_selection.cpp:265 +msgid "Yes" +msgstr "हाँ" + +#. I18N: ./data/gui/dialogs/confirm_resolution_dialog.stkgui +#. I18N: In the 'confirm resolution' dialog, that's shown when switching +#. resoluton +msgid "Revert" +msgstr "पूर्वस्थिति में लौटें" + +#. I18N: ./data/gui/dialogs/confirm_resolution_dialog.stkgui +#. I18N: In the 'confirm resolution' dialog, that's shown when switching +#. resoluton +#. I18N: ./data/gui/dialogs/online/registration_terms.stkgui +#. I18N: In the registration dialog +msgid "Accept" +msgstr "स्वीकार करें" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +msgid "Camera Settings" +msgstr "कैमरा सेटिंग" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera settings +msgid "Player camera" +msgstr "उपयोगकर्ता का कैमरा" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "FOV" +msgstr "FOV" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Distance" +msgstr "दूरी" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Angle" +msgstr "कोण" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Smooth camera" +msgstr "जादुई कैमरा " + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera settings +msgid "Backward camera" +msgstr "पीछेवाला कैमरा" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Follow ball in soccer mode" +msgstr "बॉल का पीछे चले" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Reset" +msgstr "रीसेट" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +msgid "Graphics Settings" +msgstr "ग्राफिक्स सेटिंग्स" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Advanced pipeline (lights, etc.)" +msgstr "उन्नत पाइपलाइन (रोशनी, आदि)" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Shadows" +msgstr "परछाई" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Bloom" +msgstr "कली" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Light shaft (God rays)" +msgstr "प्रकाश पुँज (आभा किरणें)" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Ambient occlusion" +msgstr "परिवेशी बाधा" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Depth of field" +msgstr "क्षेत्र की गहराई" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Glow (Outlines)" +msgstr "चमक (रूपरेखा)" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Anti-aliasing" +msgstr "एंटी-एलियासिंग" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Motion blur" +msgstr "मोशन ब्लर" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Image-based lighting" +msgstr "छवि-आधारित प्रकाश व्यवस्था" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Light Scattering" +msgstr "प्रकाश प्रकीर्णन" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Animated characters" +msgstr "एनिमेटेड पात्र" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Texture compression" +msgstr "टेक्सचर कंप्रेशन" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Particle effects" +msgstr "कण प्रभाव" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Rendered image quality" +msgstr "प्रदान की गई छवि गुणवत्ता" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Geometry detail" +msgstr "ज्यामिति विवरण" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "* Restart STK to apply new settings" +msgstr "* नई सेटिंग्स लागू करने के लिए STK को पुनरारंभ करें" + +#. I18N: ./data/gui/dialogs/debug_slider.stkgui +#. I18N: ./data/gui/dialogs/online/recovery_info.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Close" +msgstr "बंद करें" + +#. I18N: ./data/gui/dialogs/enter_address_dialog.stkgui +#. I18N: In the enter address dialog +#. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui +#. I18N: In the server info dialog +msgid "Join" +msgstr "जुड़ें" + +#. I18N: ./data/gui/dialogs/general_text_field_dialog.stkgui +#. I18N: In the general textfield dialog +#. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui +#. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +#. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui +#. I18N: Vote dialog +#. I18N: ./data/gui/screens/edit_track.stkgui +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/dialogs/message_dialog.cpp:127 +#: src/states_screens/dialogs/message_dialog.cpp:138 +#: src/states_screens/dialogs/message_dialog.cpp:143 +msgid "OK" +msgstr "ठीक" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +msgid "Record the race for ghost replay" +msgstr "रीप्ले के लिए भूत रेस रिकॉर्ड करें" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +msgid "Watch replay only" +msgstr "केवल रीप्ले देखें" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +msgid "Compare to another ghost" +msgstr "दूसरे भूत से तुलना करें" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +#. I18N: ./data/gui/dialogs/high_score_info_dialog.stkgui +#. I18N: High score info screen action +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +msgid "Remove" +msgstr "हटाएं" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info screen action +msgid "Compare ghost" +msgstr "भूत की तुलना करें" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info screen action +#. I18N: ./data/gui/dialogs/high_score_info_dialog.stkgui +#. I18N: High score info screen action +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +msgid "Start Race" +msgstr "रेस आरंभ करें" + +#. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui +#. I18N: Objective shown in achievement dialog +msgid "Goal" +msgstr "गोल" + +#. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui +#. I18N: Progress shown in achievement dialog +#. I18N: Progress in achievement +#: src/states_screens/online/online_profile_achievements.cpp:87 +msgid "Progress" +msgstr "प्रगति" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +msgid "Password Change" +msgstr "पासवर्ड बदलना" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +msgid "Current Password" +msgstr "वर्तमान पासवर्ड" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +msgid "New Password" +msgstr "नया पासवर्ड" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "Confirm" +msgstr "पुष्टि करें" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +msgid "Submit" +msgstr "प्रस्तुत करें" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +msgid "Back to Race" +msgstr "वापिस दौड़ में" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +msgid "Quit Server" +msgstr "सर्वर से निकलें" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Show in network ingame dialog to allow user to go back to lobby to +#. end spectating (for example) +msgid "Back to lobby" +msgstr "पीछे लॉबी में जाएं" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 +msgid "Restart Race" +msgstr "रेस पुन: आरंभ करें" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +#. I18N: Race paused button +msgid "Give Up Race" +msgstr "रेस छोड़ दें" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "Options" +msgstr "विकल्प" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "Help" +msgstr "मदद" + +#. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui +#. I18N: In player rankings dialog +msgid "Top 10 players" +msgstr "10 शीर्ष खिलाड़ी" + +#. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui +msgid "Refresh" +msgstr "रिफ्रेश" + +#. I18N: ./data/gui/dialogs/online/recovery_info.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +msgid "Account Recovery" +msgstr "खाता वापस पाएँ" + +#. I18N: ./data/gui/dialogs/online/recovery_info.stkgui +#. I18N: In the recovery dialog +msgid "" +"You will receive an email with further instructions on how to reset your " +"password. Please be patient and be sure to check your spam folder." +msgstr "आपको अपना पासवर्ड रीसेट करने के तरीके के बारे में कई निर्देशों के साथ एक ईमेल प्राप्त होगा. कृपया धैर्य रखें और अपने स्पैम फ़ोल्डर की जांच अवश्य करें. " + +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +msgid "" +"Fill in the username and email address you supplied at registration to be " +"able to reset your password." +msgstr "अपना पासवर्ड रीसेट करने में सक्षम होने के लिए पंजीकरण के समय आपके द्वारा प्रदान किया गया उपयोगकर्ता नाम और ईमेल पता भरें." + +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 +msgid "Username" +msgstr "उपयोगकर्ता नाम" + +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "Email" +msgstr "ईमेल" + +#. I18N: ./data/gui/dialogs/online/registration_terms.stkgui +#. I18N: In the registration dialog +msgid "Terms and Agreement" +msgstr "शर्तें और अनुबंध" + +#. I18N: ./data/gui/dialogs/online/registration_terms.stkgui +#. I18N: In the registration dialog +msgid "I agree to the above terms and am 13 years or older. " +msgstr "मैं उपरोक्त शर्तों से सहमत हूं और मेरी उम्र 13 वर्ष या उससे अधिक है." + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +msgid "Server Configuration" +msgstr "सर्वर कॉन्फ़िगरेशन" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Difficulty" +msgstr "कठिनाई" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: Difficulty +#: src/race/race_manager.cpp:1317 +msgid "Novice" +msgstr "नौसिखुआ" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: Difficulty +#: src/race/race_manager.cpp:1318 +msgid "Intermediate" +msgstr "मध्यवर्ती कठिनाई" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: Difficulty +#: src/race/race_manager.cpp:1319 +msgid "Expert" +msgstr "दिग्गज" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: Difficulty +#: src/race/race_manager.cpp:1320 +msgid "SuperTux" +msgstr "सुपरटक्स" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 +msgid "Game mode" +msgstr "खेल मोड" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Multiplayer game mode +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Multiplayer game mode +#. I18N: Game mode +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 +msgid "Normal Race" +msgstr "साधारण रेस" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Multiplayer game mode +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Multiplayer game mode +#. I18N: Game mode +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 +msgid "Time Trial" +msgstr "समय परीक्षण" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Multiplayer game mode +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Multiplayer game mode +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 +msgid "Battle" +msgstr "लड़ाई" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Multiplayer game mode +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Multiplayer game mode +#. I18N: Game mode +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 +msgid "Soccer" +msgstr "फ़ुटबॉल" + +#. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Password" +msgstr "पासवर्ड" + +#. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui +#. I18N: In the server info dialog +#: src/states_screens/dialogs/server_info_dialog.cpp:292 +msgid "Bookmark this server" +msgstr "इस सर्वर को बुक-मार्क बनाएँ" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "Add player" +msgstr "खिलाड़ी जोड़ें" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +#: src/states_screens/online/online_profile_achievements.cpp:78 +msgid "Name" +msgstr "नाम" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "Handicap" +msgstr "दिव्यांग" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "Press the 'All players ready' button after the player list is ready." +msgstr "खिलाड़ी सूची तैयार होने के बाद 'सभी खिलाड़ी तैयार' बटन दबाएँ." + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "Clear players" +msgstr "खिलाड़ी हटाएँ" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "All players ready" +msgstr "सभी खिलाड़ी तैयार" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "User Info" +msgstr "उपयोगकर्ता सूचना" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Remove Friend" +msgstr "मित्र को हटाएँ" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Add Friend" +msgstr "दोस्त बनाओ" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Accept Invite" +msgstr "आमंत्रण स्वीकार करें" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Decline Invite" +msgstr "आमंत्रण को अस्वीकार करें" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "View Profile" +msgstr "प्रोफ़ाइल देखें" + +#. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui +#. I18N: In the vote dialog +msgid "Vote" +msgstr "वोट करें" + +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +msgid "Paused" +msgstr "ठहरा हुआ" + +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +msgid "Back to Game" +msgstr "पुन: खेलें" + +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +msgid "Back to menu" +msgstr "मेनू पर जाएँ" + +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +msgid "Select kart" +msgstr "गाड़ी चुनें" + +#. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui +#. I18N: When changing input configurations +msgid "Press fully and release..." +msgstr "पूरा दबाकर छोड़ें" + +#. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui +#. I18N: When configuring input +msgid "Assign to ESC key" +msgstr "Assign to ESC key" + +#. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui +#. I18N: When configuring input +msgid "Assign nothing" +msgstr "कुछ कार्यभार नहीं दें" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "" + +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: ./data/gui/screens/soccer_setup.stkgui +msgid "Race Setup" +msgstr "रेस सेटअप" + +#. I18N: ./data/gui/dialogs/tutorial_message_dialog.stkgui +#. I18N: Button in tutorial +#. I18N: ./data/gui/screens/grand_prix_lose.stkgui +#. I18N: ./data/gui/screens/grand_prix_win.stkgui +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: ./data/gui/screens/soccer_setup.stkgui +#. I18N: In soccer setup screen +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 +msgid "Continue" +msgstr "आगे बढ़ें" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +msgid "SuperTuxKart Addons" +msgstr "सुपरटक्सकार्ट ऐडऑन्स" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In addons screen, in the filtering bar, to enable a filter that will +#. show only recently updated items +msgid "Updated" +msgstr "अपडेट हो गया" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In addons screen, in the filtering bar, to enable a filter that will +#. show only items with good rating +msgid "Rating >=" +msgstr "रेटिंग >=" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In the addons screen +msgid "Karts" +msgstr "कार्ट्स" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In the addons screen +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +msgid "Tracks" +msgstr "ट्रैक्स" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In the addons screen +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracks selection screen +msgid "Arenas" +msgstr "खेल मैदान" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In addons screen, above the list of addons to be installed +#: src/states_screens/addons_screen.cpp:138 +msgid "Installed" +msgstr "स्थापित" + +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "" + +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: track group +#. I18N: ./data/gui/screens/easter_egg.stkgui +#. I18N: track group +#. I18N: track group name +#. I18N: kart group name +#. I18N: track group name +#. I18N: In the UI options, Camera setting: Standard +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 +#: src/states_screens/dialogs/custom_camera_settings.cpp:69 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 +#: src/states_screens/gp_info_screen.cpp:256 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 +msgid "Standard" +msgstr "साधारण" + +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: track group +#. I18N: ./data/gui/screens/easter_egg.stkgui +#. I18N: track group +#. I18N: track group name +#. I18N: kart group name +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 +msgid "Add-Ons" +msgstr "Add-Ons" + +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: track group +#. I18N: ./data/gui/screens/easter_egg.stkgui +#. I18N: track group +#. I18N: Time filters for add-ons +#. I18N: name of the tab that will show arenas from all groups +#. I18N: track group name +#. I18N: name of the tab that will show tracks from all groups +#. I18N: track group name +#. I18N: name of the tab that will show karts from all groups +#. I18N: kart group/class name +#. I18N: name of the tab that will show tracks from all groups +#. I18N: track group name +#. I18N: name of the tab that will show tracks from all groups +#. I18N: track group name +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 +#: src/states_screens/gp_info_screen.cpp:79 +#: src/states_screens/gp_info_screen.cpp:249 +#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/kart_selection.cpp:321 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 +msgid "All" +msgstr "समस्त" + +#. I18N: ./data/gui/screens/credits.stkgui +#. I18N: Title in credits screen +msgid "Credits" +msgstr "क्रेडिट" + +#. I18N: ./data/gui/screens/cutscene.stkgui +msgid "Skip" +msgstr "छोड़ें" + +#. I18N: ./data/gui/screens/easter_egg.stkgui +#. I18N: Section in easter egg tracks selection screen +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/tracks.stkgui +#. I18N: In the track selection screen +msgid "All Tracks" +msgstr "सारे मैदान" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Title in edit grand prix screen +msgid "Edit Grand Prix" +msgstr "ग्रांड प्रिक्स संपादित करें " + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +msgid "Move up" +msgstr "ऊपर जाएँ" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +msgid "Move down" +msgstr "नीचे जाएँ" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Add" +msgstr "जोड़ें" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +msgid "Edit" +msgstr "संपादन" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +msgid "Save" +msgstr "सहेजें" + +#. I18N: ./data/gui/screens/edit_track.stkgui +#. I18N: In the edit track screen +msgid "Number of laps:" +msgstr "लैपों की संख्या" + +#. I18N: ./data/gui/screens/edit_track.stkgui +#. I18N: In the edit track screen +msgid "Reverse:" +msgstr "पीछे जाएं :" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Ghost Replay Selection" +msgstr "घोस्ट रीप्ले चयन" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: Game mode +#: src/race/race_manager.cpp:1304 +msgid "Egg Hunt" +msgstr "अंडों की खोज" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Only show the best times" +msgstr "केवल सबसे अच्छा समय दिखाएँ" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Compare replay" +msgstr "रिप्ले की तुलना करें" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Only show replays matching the current difficulty" +msgstr "केवल वर्तमान कठिनाई से मेल खाते रिप्ले दिखाएं" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Only show replays matching the current version" +msgstr "केवल वर्तमान संस्करण से मेल खाते रिप्ले दिखाएं" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Hide multiplayer replays" +msgstr "मल्टीप्लेयर रिप्ले छुपाएँ" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Record a ghost replay" +msgstr "घोस्ट रीप्ले रिकॉर्ड करें" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +msgid "AI karts" +msgstr "AI कार्ट्स" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +msgid "Reverse" +msgstr "पीछे जाएं" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +#. I18N: In track screen +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 +msgid "Maximum time (min.)" +msgstr "महत्तम समय (मिनट)" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +msgid "Track group" +msgstr "ट्रैक ग्रुप" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +#: src/states_screens/gp_info_screen.cpp:164 +msgid "Continue saved GP" +msgstr "संचित GP में आगे जाएं" + +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Title in grand prix editor screen +msgid "Grand Prix editor" +msgstr "ग्रांड प्रिक्स संपादक" + +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +msgid "New" +msgstr "नया" + +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +msgid "Copy" +msgstr "कॉपी" + +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/online/register_screen.cpp:71 +msgid "Rename" +msgstr "नया नाम दें" + +#. I18N: ./data/gui/screens/grand_prix_lose.stkgui +#. I18N: ./data/gui/screens/grand_prix_win.stkgui +msgid "Save Grand Prix" +msgstr "ग्रांड प्रिक्स सहेजें" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui +msgid "SuperTuxKart Help" +msgstr "SuperTuxKart सहायता" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Game Modes" +msgstr "खेल के मोड" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Powerups" +msgstr "शक्तिवर्धन" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Bananas" +msgstr "केला" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +#: src/io/rich_presence.cpp:501 +msgid "Story Mode" +msgstr "कहानी मोड " + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Kart classes" +msgstr "कार्ट वर्गीकरण" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Multiplayer" +msgstr "मल्टीप्लेयर" + +#. I18N: ./data/gui/screens/help/help1.stkgui +msgid "Start the tutorial" +msgstr "ट्यूटोरियल प्रारंभ करें" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "Collect blue gift boxes, they will give you powerups." +msgstr "नीले उपहार बक्से ले लीजिए, वे आपको शक्तिवर्धन देंगे." + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +#: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 +msgid "Avoid bananas!" +msgstr "केलों से बचिए!" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "" +"Collecting nitro allows you to get speed boosts whenever you wish by " +"pressing the appropriate key or button. You can see your current level of " +"nitro in the gauge at the bottom-right of the race screen." +msgstr "नाइट्रो एकत्र करने से आप जब चाहें उपयुक्त कुंजी या बटन दबाकर गति बढ़ा सकते हैं. आप रेस स्क्रीन के नीचे-दाईं ओर गेज में अपने वर्तमान नाइट्रो स्तर को देख सकते हैं." + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "" +"If you see a button with a lock like this one, you need to complete a " +"challenge to unlock it." +msgstr "यदि आप इस तरह का ताला वाला बटन देखते हैं, तो आपको इसे खोलने के लिए एक चुनौती पूरी करनी होगी." + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "" +"You can skid by pressing a special key or button. Successive short skids " +"help to take sharp turns; while medium skids will boost your speed, long " +"skids more so. You can't stop turning while skidding, so orient your kart " +"carefully before!" +msgstr "आप एक विशेष कुंजी या बटन दबाकर स्किड कर सकते हैं. लगातार छोटी स्किड्स तीखे मोड़ लेने में मदद करती हैं; जबकि मध्यम स्किड्स आपकी गति को बढ़ाएंगे, लंबी स्किड्स और तेज. आप स्किडिंग करते समय मुड़ना बंद नहीं कर सकते हैं, इसलिए अपने कार्ट को पहले सावधानी से उन्मुख करें!" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "" +"You can get a startup boost by pressing the accelerate button at 'Set!', " +"before the race's start." +msgstr "आप दौड़ शुरू होने से पहले 'सेट!' पर त्वरित करें बटन दबाकर स्टार्टअप बूस्ट प्राप्त कर सकते हैं." + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: in the help screen +msgid "* Current key bindings can be seen/changed in the Options menu" +msgstr "* वर्तमान कुंजी जुड़ाव को विकल्प मेनू में देखा/बदला जा सकता है" + +#. I18N: ./data/gui/screens/help/help2.stkgui +msgid "SuperTuxKart features several game modes:" +msgstr "SuperTuxKart में कई गेम मोड हैं :" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"Regular Race: All blows allowed, so collect powerups and use them smartly!" +msgstr "नियमित दौड़: सभी प्रकार के वार की अनुमति है, इसलिए अतिरिक्त-शक्ति इकट्ठा करें और उनका बुद्धिमानी से उपयोग करें!" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "Time Trial: Contains no powerups, so only your driving skills matter!" +msgstr "समय परीक्षण: इसमें कोई भी शक्तिवर्धक नहीं है, अत: केवल आपके ड्राइविंग कौशल पर सब कुछ निर्भर है!" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"Follow the leader: Run for second place, as the last kart will be " +"disqualified every time the counter hits zero. Beware: going in front of the" +" leader will get you eliminated too!" +msgstr "नेता का अनुसरण करें: दूसरे स्थान के लिए दौड़ें, क्योंकि हर बार काउंटर के शून्य पर पहुंचने पर अंतिम कार्ट को अयोग्य घोषित कर दिया जाएगा. खबरदार: नेता के सामने जाने से आपका भी सफाया हो जाएगा!" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " +"others with weapons until they lose all their lives. In Free-For-All, the " +"player who hits others the most will win in a given hit or time limit. In " +"Capture The Flag, your team needs to bring the flag of the other team to " +"your own flag base, as long as your flag is not captured by the other team." +msgstr "3 प्रकार के युद्ध मोड हैं: 3 स्ट्राइक बैटल में, आपको दूसरों को हथियारों से तब तक मारना होगा जब तक कि वे अपना सारा जीवन नहीं खो देते. फ्री-फॉर-ऑल में, जो खिलाड़ी दूसरों को सबसे ज्यादा हिट करता है, वह किसी दिए गए हिट या समय सीमा में जीत जाएगा. कैप्चर द फ़्लैग में, आपकी टीम को दूसरी टीम के फ़्लैग को आपके अपने फ़्लैग बेस पर लाने की ज़रूरत होती है, जब तक कि आपका फ़्लैग दूसरी टीम द्वारा कैप्चर नहीं किया जाता है." + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "Soccer: Use your kart to push the ball into the goal." +msgstr "फ़ुटबॉल: गेंद को गोल में धकेलने के लिए अपने कार्ट का उपयोग करें." + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "Egg hunt: Explore tracks to find all hidden eggs." +msgstr "एग हंट: सभी छिपे हुए अंडों को खोजने के लिए ट्रैक एक्सप्लोर करें." + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" +" record your own!" +msgstr "घोस्ट रिप्ले: टीम-ट्रायल या एग हंट मोड में घोस्ट के साथ रेस रिप्ले करें, और अपना खुद का रिकॉर्ड बनाएं!" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"Lap Trial: Complete as many laps as possible in a given amount of time." +msgstr "" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"* Many of these game modes can also be played in a Grand Prix fashion: " +"instead of playing a single race, you play many in a row. The better you " +"rank, the more points you get. In the end, the player with the most points " +"wins the cup." +msgstr "* इनमें से कई गेम मोड ग्रैंड प्रि की तरह भी खेले जा सकते हैं: एक ही रेस खेलने के बजाय, आप कई रेस एक के बाद एक खेलते हैं. आप जितनी बेहतर रैंक करेंगे, आपको उतने ही अधिक अंक मिलेंगे. अंत में, सबसे अधिक अंक वाला खिलाड़ी कप जीतता है." + +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: In the help menu +msgid "To help you win, there are some powerups you can collect:" +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"BubbleGum - protect yourself with a shield, or use while looking back to " +"leave a sticky pink puddle behind you." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Zipper - will give you a strong speed boost. But beware of not losing " +"control of your kart!" +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Cake - thrown at the closest rival, best on short ranges and long straights." +" It also affects other karts close to the explosion." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Plunger - throw straight to pull an opponent back, or throw while looking " +"back to make one lose sight." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Bowling Ball - goes straight until it strikes, it can bounce off walls. If " +"you are looking back, it will be thrown backwards." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "Parachute - slows down all karts in a better position." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Swapper - gift boxes are transformed into bananas, nitro cans into " +"bubblegums, and vice versa for a short time." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Basket Ball - bounces after the leader, and might squash and slow down karts" +" down on the way." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Swatter - will squash karts close by, slowing them down. Can also be used to" +" remove parachutes and bombs." +msgstr "" + +#. I18N: ./data/gui/screens/help/help4.stkgui +msgid "" +"Hitting a banana can result in one of the following being attached to the " +"kart:" +msgstr "" + +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: In the help menu +msgid "Anchor - slows down the kart suddenly." +msgstr "" + +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: In the help menu +msgid "" +"Parachute - slows down the kart, more progressively than the anchor. The " +"faster you go, the stronger it slows you down." +msgstr "" + +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: In the help menu +msgid "" +"Bomb - detonates after some amount of time, throwing the kart up in the air." +" Bump into another kart to transfer the bomb to it." +msgstr "" + +#. I18N: ./data/gui/screens/help/help5.stkgui +msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" +msgstr "" + +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: In the help menu +msgid "" +"This icon on the minimap shows the available challenges you've not " +"completed. In the top-right of the screen, it also tells you how many points" +" you currently have. Complete as many challenges as possible, and Nolok will" +" accept to race against you. Win to liberate Gnu!" +msgstr "" + +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: In the help menu +msgid "" +"When you complete a challenge, you get a cup. Each cup is worth several " +"points. The higher the difficulty you completed the challenge in, the better" +" the cup and the more points it is worth." +msgstr "" + +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: In the help menu +msgid "" +"When you get the number of points indicated below this icon, you'll be " +"gifted a surprise. There are several to collect." +msgstr "" + +#. I18N: ./data/gui/screens/help/help6.stkgui +msgid "" +"Not all karts drive the same! They belong to classes with several " +"differences:" +msgstr "" + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"Mass - there are three classes of karts, depending on their mass: light, " +"medium and heavy. Heavier karts are less affected by parachutes and are more" +" resistant to explosions." +msgstr "" + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"Acceleration - especially useful at start, after an accident, or in tracks " +"with a lot of sharp curves. The lighter the kart, the faster it accelerates," +" especially at low speeds." +msgstr "" + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"Max speed - the higher it is, the faster the kart can go. Especially useful " +"in tracks with straight lines and gentle curves. Heavier karts have a higher" +" top speed." +msgstr "" + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"Nitro efficiency - The higher it is, the more speed you get from a can of " +"nitro. A lighter kart will have higher nitro efficiency." +msgstr "" + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"If you follow closely another kart for a few seconds, you'll get a " +"slipstream speed bonus when you overtake it. The lighter your kart, the " +"easier it is." +msgstr "" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "SuperTuxKart can be played in multiplayer mode online...:" +msgstr "" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "" +"First, select the 'online' icon in the main menu. Choose either local " +"networking, or global networking (requires internet to be enabled in the " +"options). Then, you can either create your own server with custom options, " +"or search among a list of existing servers to join. Some of them are " +"recommended servers with optionally ranked races." +msgstr "" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "" +"Once in a server, a race will begin once its owner (symbolized with the " +"crown) decides so. Official servers may auto-start races only when there are" +" enough players. Then, you can choose your kart and vote for the next track " +"to race on. An addon track is allowed only if it exists on all joined " +"players and the server." +msgstr "" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "... or on the same device:" +msgstr "" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "" +"First, you will need several input devices. Use the input configuration " +"screen to set them up. Multiple gamepads or joysticks are ideal: on " +"keyboard(s), each player will need a different set of keys, and most " +"keyboards are not appropriate for multiplayer because they don't support " +"multiple simultaneous keypresses." +msgstr "" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "" +"When input devices are configured, select the 'Splitscreen Multiplayer' icon" +" in the main menu. Each player can press the 'fire' key of their gamepad or " +"keyboard to join the game, and use their input device to select their kart. " +"The game continues when everyone selected their kart. Note that the mouse " +"may not be used for this operation." +msgstr "" + +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +msgid "High Score Selection" +msgstr "" + +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: Game mode +#. I18N: Lap Trial: Complete as many laps as possible in a given amount of +#. time. +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 +msgid "Lap Trial" +msgstr "" + +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 +#: src/states_screens/dialogs/select_challenge.cpp:51 +#: src/states_screens/high_score_selection.cpp:139 +msgid "Grand Prix" +msgstr "" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the kart selection (player setup) screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the kart selection (player setup) screen +msgid "Choose a Kart" +msgstr "गड्डी चुनिए" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +msgid "Singleplayer" +msgstr "" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +msgid "Splitscreen Multiplayer" +msgstr "" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/online/online_profile_friends.cpp:245 +msgid "Online" +msgstr "" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +msgid "Addons" +msgstr "ऐडऑन्स" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +#: src/states_screens/race_gui_overworld.cpp:530 +msgid "Tutorial" +msgstr "" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +#: src/states_screens/track_info_screen.cpp:343 +msgid "High Scores" +msgstr "" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +#. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui +#. I18N: Section in the profile screen +#: src/states_screens/online/online_profile_base.cpp:113 +msgid "Achievements" +msgstr "" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "Grand Prix Editor" +msgstr "" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "About" +msgstr "इसके बारे में" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Server Creation" +msgstr "" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Name of the server" +msgstr "सर्वर का नाम" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Max. number of players" +msgstr "" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Password for private server (optional)" +msgstr "" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Create" +msgstr "बनाएं" + +#. I18N: ./data/gui/screens/online/lan.stkgui +msgid "Local Networking" +msgstr "" + +#. I18N: ./data/gui/screens/online/lan.stkgui +#. I18N: In the online multiplayer screen +#. I18N: ./data/gui/screens/online/profile_servers.stkgui +#. I18N: In the online multiplayer screen +msgid "Find Server" +msgstr "" + +#. I18N: ./data/gui/screens/online/lan.stkgui +#. I18N: In the online multiplayer screen +#. I18N: ./data/gui/screens/online/profile_servers.stkgui +#. I18N: In the online multiplayer screen +#: src/states_screens/online/create_server_screen.cpp:108 +msgid "Create Server" +msgstr "सर्वर बनाएं" + +#. I18N: ./data/gui/screens/online/networking_lobby.stkgui +#. I18N: In networking lobby +#. I18N: In the networking lobby +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 +msgid "Lobby" +msgstr "" + +#. I18N: ./data/gui/screens/online/networking_lobby.stkgui +#. I18N: In the network lobby +#. I18N: In networking lobby to configuration server settings +#: src/states_screens/online/networking_lobby.cpp:201 +msgid "Configuration" +msgstr "" + +#. I18N: ./data/gui/screens/online/networking_lobby.stkgui +#. I18N: In the network lobby +#: src/states_screens/online/networking_lobby.cpp:193 +msgid "Start race" +msgstr "रेस शुरू कीजिए" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: In the networking menu +msgid "Enable splitscreen or player handicaps" +msgstr "" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: Networking menu button +msgid "Local networking" +msgstr "" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: Networking menu button +msgid "Global networking" +msgstr "" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: Networking menu button +msgid "Enter server address" +msgstr "" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: Networking menu button +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 +msgid "Your profile" +msgstr "" + +#. I18N: ./data/gui/screens/online/profile_achievements.stkgui +#. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui +#. I18N: ./data/gui/screens/online/profile_friends.stkgui +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +msgid "..." +msgstr "..." + +#. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui +#. I18N: In the achievements screen +msgid "Player rankings" +msgstr "" + +#. I18N: ./data/gui/screens/online/profile_friends.stkgui +#. I18N: Section in the profile screen +#: src/states_screens/online/online_profile_base.cpp:112 +msgid "Friends" +msgstr "दोस्त" + +#. I18N: ./data/gui/screens/online/profile_friends.stkgui +#. I18N: In the profile screen +msgid "Look for more friends:" +msgstr "" + +#. I18N: ./data/gui/screens/online/profile_friends.stkgui +#. I18N: ./data/gui/screens/online/user_search.stkgui +msgid "Search" +msgstr "खोज" + +#. I18N: ./data/gui/screens/online/profile_servers.stkgui +msgid "Global Networking" +msgstr "" + +#. I18N: ./data/gui/screens/online/profile_servers.stkgui +#. I18N: In the online multiplayer screen +msgid "Quick Play" +msgstr "" + +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +#. I18N: Section in the profile screen +#: src/states_screens/online/online_profile_base.cpp:114 +msgid "Account Settings" +msgstr "" + +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +#. I18N: In the online account settings screen +msgid "Password:" +msgstr "" + +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +msgid "Change" +msgstr "" + +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +#. I18N: In the online account settings screen +msgid "E-mail:" +msgstr "E-mail:" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +#: src/states_screens/online/register_screen.cpp:73 +msgid "Create User" +msgstr "" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: Section in the register screen +msgid "New Online Account" +msgstr "" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: Section in the register screen +msgid "Existing Online Account" +msgstr "" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: Section in the register screen +msgid "Offline Account" +msgstr "" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "Local Name" +msgstr "" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "Online Username" +msgstr "" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui +msgid "Reset password" +msgstr "" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "" +"You can play without creating an online account by selecting an offline " +"account. Though then you can not connect to friends, vote for addons etc. " +"Please read our privacy statement at https://privacy.supertuxkart.net" +msgstr "" + +#. I18N: ./data/gui/screens/online/server_selection.stkgui +#: src/states_screens/online/server_selection.cpp:578 +msgid "Server Selection" +msgstr "" + +#. I18N: ./data/gui/screens/online/server_selection.stkgui +#. I18N: In the server selection screen +msgid "Show private server(s)" +msgstr "" + +#. I18N: ./data/gui/screens/online/server_selection.stkgui +#. I18N: In the server selection screen +msgid "Use IPv6 connection" +msgstr "" + +#. I18N: ./data/gui/screens/online/user_search.stkgui +msgid "User search" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +msgid "SuperTuxKart Options" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Graphics" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Audio" +msgstr "ऑडियो" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Interface" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Players" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Controls" +msgstr "नियंत्रण" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Language" +msgstr "भाषा" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: In the audio options screen +msgid "Music" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: In the audio options screen +#. I18N: in the graphical options tooltip; +#. indicates a graphical feature is enabled +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 +msgid "Enabled" +msgstr "सक्रिय किया" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: In the audio options screen +msgid "Volume" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: In the audio options screen +msgid "Sound Effects" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen +msgid "Delete Configuration" +msgstr "कॉन्फ़िगरेशन हटाएं" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen +#. I18N: button to disable a keyboard configuration +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 +msgid "Disable Configuration" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen +msgid "Back to device list" +msgstr "डिवाइस सूची पर वापस जाएं" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen +msgid "Rename Configuration" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen, for gamepad +msgid "Enable force feedback (if supported)" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "नयी Resolution भिड़ाओ" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Internet options" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Always show login screen" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Connect to the Internet" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Enable chatting in online lobbies" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Enable chatting in online matches" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Miscellaneous options" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Enable per-player handicaps" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: For mobile version for STK, uninstall the downloaded assets +#: src/states_screens/options/options_screen_general.cpp:79 +msgid "Uninstall full game assets" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: In the input configuration screen +#: src/states_screens/options/options_screen_input.cpp:191 +msgid "Press enter or double-click on a device to configure it" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: In the input configuration screen +msgid "Add a device" +msgstr "डिवाइस जोडें" + +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: In the input configuration screen +msgid "" +"* Which config to use will be inferred from which 'Select' key is pressed to" +" join the game." +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Skin" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Skin variant" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Minimap" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Font size" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Camera" +msgstr "कैमरा" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Custom..." +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Display FPS" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Show other karts' held powerups" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Enable the story mode timer" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Enable the speedrun timer" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Render resolution" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Graphical Effects Level" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Blur Effects Level" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video options, maximum frame per second +msgid "Maximum FPS" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Custom settings..." +msgstr "" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Performance tests" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Performance test of the current settings" +msgstr "" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "" + +#. I18N: ./data/gui/screens/race_setup.stkgui +msgid "Select a difficulty" +msgstr "" + +#. I18N: ./data/gui/screens/race_setup.stkgui +msgid "Select a game mode" +msgstr "" + +#. I18N: ./data/gui/screens/soccer_setup.stkgui +#. I18N: In soccer setup screen +msgid "Use left/right to choose your team and press fire" +msgstr "" + +#. I18N: ./data/gui/screens/soccer_setup.stkgui +#. I18N: In soccer setup screen +msgid "Red Team" +msgstr "" + +#. I18N: ./data/gui/screens/soccer_setup.stkgui +#. I18N: In soccer setup screen +msgid "Blue Team" +msgstr "" + +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 +msgid "Number of laps" +msgstr "" + +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 +msgid "Number of AI karts" +msgstr "" + +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +msgid "Number of blue team AI karts" +msgstr "" + +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +#: src/race/grand_prix_data.cpp:623 +msgid "Random Grand Prix" +msgstr "" + +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "" + +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: Used as a verb, appears on the main networking menu (login button) +#: src/states_screens/online/online_screen.cpp:69 +msgid "Login" +msgstr "" + +#. I18N: ./data/tips.xml +msgid "The UI skin can be changed in the UI options." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "You can see other karts' powerups by enabling it in the UI options." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "The font size can be changed in the UI options." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "The help menu has lots of useful information." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "In single-player, you can watch and challenge recorded time-trials." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"You can visit https://supertuxkart.net/ for more information about the game." +msgstr "आप यहाँ पर जाके गेम का और जानकारी जान सकते हैं https://supertuxkart.net/" + +#. I18N: ./data/tips.xml +msgid "Short nitro boosts are more efficient." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Only use zippers when it is safe. Long straight lines are ideal." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"Don't use multiple zippers quickly in row, instead, wait until the speed " +"boost wears off." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Skidding makes you much faster, do it whenever safe." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "The swatter can be used to remove bombs or parachutes." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"You can't stop turning while skidding. Good kart orientation at the skid's " +"start is paramount." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "You get a startup boost if you start accelerating during \"Set\"." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Braking allows to get rid of parachutes quicker." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "First and foremost, focus on where your kart is going." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "The rescue key (button) is very useful." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Be careful when close to other karts, they may attack you!" +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"Basketballs can be destroyed using precise backward shots with a bowling " +"ball, cake, or plunger." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"Try to avoid crashing into the backs of other karts as this will slow you " +"down." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "You can use bowling balls to push and block the ball." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "In soccer, always work as a team for good results." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"If you miss the ball and an opponent is approaching, try hitting them with a" +" powerup or block their way." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Good rotation of positions (attack and defense) is essential." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Make sure to store at least 2 big cans worth of nitro." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Never use the three bowling balls all at the same time." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"Don't get in the way of a teammate carrying the ball, though you can try to " +"hit opponents attempting to stop them from scoring." +msgstr "" + +#. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml +msgid "Adiumy" +msgstr "आड्युमि" + +#. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml +msgid "Amanda" +msgstr "" + +#. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml +msgid "Godette" +msgstr "" + +#. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml +msgid "Emule" +msgstr "" + +#. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml +msgid "Gavroche" +msgstr "" + +#. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml +msgid "Gnu" +msgstr "" + +#. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml +msgid "Hexley" +msgstr "" + +#. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml +msgid "Kiki" +msgstr "किकी" + +#. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml +msgid "Konqi" +msgstr "" + +#. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml +msgid "Nolok" +msgstr "" + +#. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml +msgid "Pidgin" +msgstr "" + +#. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml +msgid "Puffy" +msgstr "" + +#. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml +msgid "Pepper" +msgstr "" + +#. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml +msgid "Sara" +msgstr "सारा" + +#. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml +msgid "Suzanne" +msgstr "" + +#. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml +msgid "Tux" +msgstr "टक्स" + +#. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml +msgid "Wilber" +msgstr "" + +#. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml +msgid "Xue" +msgstr "सुई" + +#. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml +msgid "Antediluvian Abyss" +msgstr "" + +#. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml +msgid "Alien Signal" +msgstr "" + +#. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml +msgid "Ancient Colosseum Labyrinth" +msgstr "" + +#. I18N: ../stk-assets/tracks/arena_candela_city/track.xml +#. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml +msgid "Candela City" +msgstr "" + +#. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml +msgid "Battle Island" +msgstr "" + +#. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml +msgid "Black Forest" +msgstr "" + +#. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml +msgid "Cave X" +msgstr "" + +#. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml +msgid "Cocoa Temple" +msgstr "" + +#. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml +msgid "Cornfield Crossing" +msgstr "" + +#. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml +msgid "Fort Magma" +msgstr "" + +#. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml +msgid "Gran Paradiso Island" +msgstr "" + +#. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml +msgid "Hacienda" +msgstr "" + +#. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml +msgid "Hole Drop" +msgstr "" + +#. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml +msgid "Icy Soccer Field" +msgstr "" + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "What's wrong, little hippies? Your great gnu leader is missing?" +msgstr "क्या गलत है छोटे? आपका बड़ा नेता क्या गुम हो गया क्या?" + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "Oh yes, see, he's in my castle now and will be served for supper..." +msgstr "और हा, देख, वह अब मेरे किले में है और वह मेरे रात का खाना हो जाएंगे" + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "But I'm a fair creature, so I'll make you a deal." +msgstr "" + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "If you can beat me at racing, I will free the old codger." +msgstr "" + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "" +" But you pathetic little twerps will never be able to beat me - King of the " +"Karts!" +msgstr "" + +#. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml +msgid "Las Dunas Arena" +msgstr "" + +#. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml +msgid "Las Dunas Soccer Stadium" +msgstr "" + +#. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml +msgid "Around the Lighthouse" +msgstr "" + +#. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml +msgid "Old Mine" +msgstr "पुरानी खान" + +#. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml +msgid "Minigolf" +msgstr "" + +#. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml +msgid "Oasis" +msgstr "" + +#. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml +msgid "Oliver's Math Class" +msgstr "" + +#. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml +msgid "Pumpkin Park" +msgstr "" + +#. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml +msgid "Ravenbridge Mansion" +msgstr "" + +#. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml +msgid "Shifting Sands" +msgstr "" + +#. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml +msgid "Nessie's Pond" +msgstr "" + +#. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml +msgid "Northern Resort" +msgstr "" + +#. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml +msgid "Snow Peak" +msgstr "" + +#. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml +msgid "Soccer Field" +msgstr "" + +#. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml +msgid "The Stadium" +msgstr "" + +#. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml +msgid "STK Enterprise" +msgstr "" + +#. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml +msgid "Temple" +msgstr "" + +#. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml +msgid "Volcan Island" +msgstr "" + +#. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml +msgid "XR591" +msgstr "" + +#. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml +msgid "Zen Garden" +msgstr "" + +#: src/achievements/achievement.cpp:387 +#, c-format +msgid "Completed achievement \"%s\"." +msgstr "" + +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 +msgid "Failed to connect to the SuperTuxKart add-ons server." +msgstr "" + +#: src/addons/news_manager.cpp:184 +#, c-format +msgid "Error downloading news: '%s'." +msgstr "" + +#: src/challenges/challenge_data.cpp:303 src/network/server_config.cpp:261 +msgid "Normal Race (Grand Prix)" +msgstr "साधारण रेस (ग्रैंड प्रिक्स)" + +#: src/challenges/challenge_data.cpp:305 +msgid "Time-Trial (Grand Prix)" +msgstr "" + +#: src/challenges/challenge_data.cpp:310 +msgid "Time-Trial - beat the replay" +msgstr "" + +#: src/challenges/challenge_data.cpp:312 +msgid "Time-Trial - nitro challenge" +msgstr "" + +#: src/challenges/challenge_data.cpp:314 +msgid "Normal Race (single race)" +msgstr "साधारण रेस (एकल रेस)" + +#: src/challenges/challenge_data.cpp:316 +msgid "Time-Trial (single race)" +msgstr "" + +#: src/challenges/challenge_data.cpp:318 +msgid "Follow the Leader (single race)" +msgstr "" + +#. I18N: In the Select challenge dialog, tell user this challenge has reversed +#. laps +#: src/challenges/challenge_data.cpp:324 +#: src/states_screens/dialogs/select_challenge.cpp:78 +msgid "Mode: Reverse" +msgstr "" + +#: src/challenges/challenge_data.cpp:601 +#, c-format +msgid "New track '%s' now available" +msgstr "" + +#: src/challenges/challenge_data.cpp:605 +#, c-format +msgid "New game mode '%s' now available" +msgstr "" + +#: src/challenges/challenge_data.cpp:615 +#, c-format +msgid "New Grand Prix '%s' now available" +msgstr "" + +#: src/challenges/challenge_data.cpp:619 +#, c-format +msgid "New difficulty '%s' now available" +msgstr "" + +#: src/challenges/challenge_data.cpp:629 +#, c-format +msgid "New kart '%s' now available" +msgstr "" + +#: src/challenges/story_mode_timer.cpp:281 +#: src/states_screens/options/options_screen_ui.cpp:280 +msgid "" +"Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" +"\n" +"Closing the game before the story mode's completion invalidates the timer.\n" +"\n" +"To use the speedrun mode, please use a new profile." +msgstr "" + +#. I18N: Name of first guest player (without number) +#: src/config/player_manager.cpp:396 +msgid "Guest" +msgstr "" + +#. I18N: Name of further guest players, with a 1, 2, ... attached +#: src/config/player_manager.cpp:401 +#, c-format +msgid "Guest %d" +msgstr "" + +#: src/config/user_config.cpp:688 +msgid "" +"Your config file was malformed, so it was deleted and a new one will be " +"created." +msgstr "" + +#: src/config/user_config.cpp:699 +msgid "" +"Your config file was too old, so it was deleted and a new one will be " +"created." +msgstr "" + +#: src/graphics/irr_driver.cpp:738 +msgid "Video recording started." +msgstr "" + +#: src/graphics/irr_driver.cpp:745 +#, c-format +msgid "Video saved in \"%s\"." +msgstr "" + +#: src/graphics/irr_driver.cpp:749 +msgid "Encoding progress:" +msgstr "" + +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 +#, c-format +msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" +msgstr "" + +#. I18N: Tip shown in gui for giving player hints +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 +#, c-format +msgid "Tip: %s" +msgstr "" + +#: src/guiengine/engine.cpp:1510 +msgid "Loading" +msgstr "" + +#: src/guiengine/widgets/kart_stats_widget.cpp:104 +msgid "Mass" +msgstr "" + +#: src/guiengine/widgets/kart_stats_widget.cpp:110 +msgid "Maximum speed" +msgstr "" + +#: src/guiengine/widgets/kart_stats_widget.cpp:117 +msgid "Acceleration" +msgstr "" + +#: src/guiengine/widgets/kart_stats_widget.cpp:123 +msgid "Nitro efficiency" +msgstr "" + +#. I18N: 'handicapped' indicates that per-player handicaps are +#. activated for this kart (i.e. it will drive slower) +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 +#: src/karts/controller/local_player_controller.cpp:468 +#: src/karts/controller/player_controller.cpp:413 +#: src/network/protocols/client_lobby.cpp:868 +#: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 +#: src/states_screens/race_result_gui.cpp:1675 +#, c-format +msgid "%s (handicapped)" +msgstr "" + +#: src/guiengine/widgets/player_kart_widget.cpp:448 +#, c-format +msgid "%s is ready" +msgstr "%s तैयार है" + +#. I18N: Unbound key binding +#: src/input/binding.cpp:85 +msgid "[none]" +msgstr "" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:92 +msgctxt "input_key" +msgid "Left Mouse Button" +msgstr "" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:94 +msgctxt "input_key" +msgid "Right Mouse Button" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:96 +msgctxt "input_key" +msgid "Cancel" +msgstr "रद्द करें" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:98 +msgctxt "input_key" +msgid "Middle Mouse Button" +msgstr "" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:100 +msgctxt "input_key" +msgid "X1 Mouse Button" +msgstr "" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:102 +msgctxt "input_key" +msgid "X2 Mouse Button" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:104 +msgctxt "input_key" +msgid "Backspace" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:106 +msgctxt "input_key" +msgid "Tab" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:108 +msgctxt "input_key" +msgid "Clear" +msgstr "हटाना" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:110 +msgctxt "input_key" +msgid "Return" +msgstr "वापिस " + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:112 +msgctxt "input_key" +msgid "Shift" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:114 +msgctxt "input_key" +msgid "Control" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:116 +msgctxt "input_key" +msgid "Alt/Menu" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:118 +msgctxt "input_key" +msgid "Pause" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:120 +msgctxt "input_key" +msgid "Caps Lock" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:122 +msgctxt "input_key" +msgid "Kana" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:124 +msgctxt "input_key" +msgid "Junja" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:127 +msgctxt "input_key" +msgid "Final" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:129 +msgctxt "input_key" +msgid "Escape" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:131 +msgctxt "input_key" +msgid "Convert" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:133 +msgctxt "input_key" +msgid "Nonconvert" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:135 +msgctxt "input_key" +msgid "Accept" +msgstr "स्वीकार करें" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:137 +msgctxt "input_key" +msgid "Modechange" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:139 +msgctxt "input_key" +msgid "Space" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:141 +msgctxt "input_key" +msgid "Page Up" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:143 +msgctxt "input_key" +msgid "Page Down" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:145 +msgctxt "input_key" +msgid "End" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:147 +msgctxt "input_key" +msgid "Home" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:149 +msgctxt "input_key" +msgid "Left" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:151 +msgctxt "input_key" +msgid "Up" +msgstr "ऊपर" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:153 +msgctxt "input_key" +msgid "Right" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:155 +msgctxt "input_key" +msgid "Down" +msgstr "नीचे" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:157 +msgctxt "input_key" +msgid "Select" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:159 +msgctxt "input_key" +msgid "Print" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:161 +msgctxt "input_key" +msgid "Exec" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:163 +msgctxt "input_key" +msgid "Print Screen" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:165 +msgctxt "input_key" +msgid "Insert" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:167 +msgctxt "input_key" +msgid "Delete" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:169 +msgctxt "input_key" +msgid "Help" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:207 +msgctxt "input_key" +msgid "Left Logo" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:209 +msgctxt "input_key" +msgid "Right Logo" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:211 +msgctxt "input_key" +msgid "Apps" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:213 +msgctxt "input_key" +msgid "Sleep" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:215 +msgctxt "input_key" +msgid "Numpad 0" +msgstr "संख्यापैड 0" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:217 +msgctxt "input_key" +msgid "Numpad 1" +msgstr "संख्यापैड 1" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:219 +msgctxt "input_key" +msgid "Numpad 2" +msgstr "संख्यापैड 2" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:221 +msgctxt "input_key" +msgid "Numpad 3" +msgstr "संख्यापैड 3" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:223 +msgctxt "input_key" +msgid "Numpad 4" +msgstr "संख्यापैड 4" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:225 +msgctxt "input_key" +msgid "Numpad 5" +msgstr "संख्यापैड 5" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:227 +msgctxt "input_key" +msgid "Numpad 6" +msgstr "संख्यापैड 6" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:229 +msgctxt "input_key" +msgid "Numpad 7" +msgstr "संख्यापैड 7" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:231 +msgctxt "input_key" +msgid "Numpad 8" +msgstr "संख्यापैड 8" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:233 +msgctxt "input_key" +msgid "Numpad 9" +msgstr "संख्यापैड 9" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:237 +msgctxt "input_key" +msgid "Separator" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:239 +msgctxt "input_key" +msgid "- (Subtract)" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:241 +msgctxt "input_key" +msgid "Decimal" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:243 +msgctxt "input_key" +msgid "/ (Divide)" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:269 +msgctxt "input_key" +msgid "Num Lock" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:271 +msgctxt "input_key" +msgid "Scroll Lock" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:273 +msgctxt "input_key" +msgid "Left Shift" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:275 +msgctxt "input_key" +msgid "Right Shift" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:277 +msgctxt "input_key" +msgid "Left Control" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:279 +msgctxt "input_key" +msgid "Right Control" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:281 +msgctxt "input_key" +msgid "Left Menu" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:283 +msgctxt "input_key" +msgid "Right Menu" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:289 +msgctxt "input_key" +msgid "Attn" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:291 +msgctxt "input_key" +msgid "Crsel" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:293 +msgctxt "input_key" +msgid "Exsel" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:295 +msgctxt "input_key" +msgid "Ereof" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:297 +msgctxt "input_key" +msgid "Play" +msgstr "खेलो" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:299 +msgctxt "input_key" +msgid "Zoom" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:301 +msgctxt "input_key" +msgid "Pa1" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:303 +msgctxt "input_key" +msgid "Oem Clear" +msgstr "" + +#. I18N: to appear in input configuration screen, for gamepad hats +#: src/input/binding.cpp:343 src/input/binding.cpp:348 +#, c-format +msgid "Gamepad hat %d" +msgstr "" + +#. I18N: to appear in input configuration screen, for gamepad axes +#: src/input/binding.cpp:355 +#, c-format +msgid "Axis %d %s" +msgstr "Axis %d %s" + +#. I18N: to appear in input configuration screen, for gamepad axes +#: src/input/binding.cpp:362 +#, c-format +msgid "Axis %d inverted" +msgstr "" + +#. I18N: to appear in input configuration screen, for gamepad axes +#: src/input/binding.cpp:367 +#, c-format +msgid "Axis %d" +msgstr "" + +#. I18N: to appear in input configuration screen, for gamepad buttons +#: src/input/binding.cpp:374 +#, c-format +msgid "Gamepad button %d" +msgstr "" + +#. I18N: to appear in input configuration screen, for mouse (might not be used +#. at all) +#: src/input/binding.cpp:377 +#, c-format +msgid "Mouse button %d" +msgstr "" + +#. I18N: to appear in input configuration screen, for mouse (might not be used +#. at all) +#: src/input/binding.cpp:381 +#, c-format +msgid "Mouse axis %d %s" +msgstr "" + +#. I18N: shown when config file is too old +#: src/input/device_manager.cpp:496 +msgid "Please re-configure your key bindings." +msgstr "" + +#: src/input/device_manager.cpp:497 +msgid "Your input config file is not compatible with this version of STK." +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:159 +msgid "Guide" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:161 +msgid "Start" +msgstr "शुरू करे" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:163 +msgid "Left thumbstick press" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:165 +msgid "Right thumbstick press" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:167 +msgid "Left shoulder" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:169 +msgid "Right shoulder" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:171 +msgid "DPad up" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:173 +msgid "DPad down" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:175 +msgid "DPad left" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:177 +msgid "DPad right" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:181 +msgid "Left thumbstick right" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:183 +msgid "Left thumbstick left" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:185 +msgid "Left thumbstick down" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:187 +msgid "Left thumbstick up" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:189 +msgid "Right thumbstick right" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:191 +msgid "Right thumbstick left" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:193 +msgid "Right thumbstick down" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:195 +msgid "Right thumbstick up" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:197 +msgid "Left trigger" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:199 +msgid "Right trigger" +msgstr "" + +#: src/input/input_manager.cpp:867 +#, c-format +msgid "Ignoring '%s'. You needed to join earlier to play!" +msgstr "" + +#: src/input/input_manager.cpp:903 +msgid "Only the Game Master may act at this point!" +msgstr "" + +#: src/input/sdl_controller.cpp:253 +#, c-format +msgid "%s has low battery level." +msgstr "" + +#: src/input/wiimote_manager.cpp:379 +msgid "" +"Connect your wiimote to the Bluetooth manager, then click on Ok. Detailed " +"instructions at https://supertuxkart.net/Wiimote" +msgstr "" + +#: src/input/wiimote_manager.cpp:382 +msgid "" +"Press the buttons 1+2 simultaneously on your wiimote to put it in discovery " +"mode, then click on Ok. Detailed instructions at " +"https://supertuxkart.net/Wiimote" +msgstr "" + +#: src/input/wiimote_manager.cpp:405 +#, c-format +msgid "Found %d wiimote" +msgid_plural "Found %d wiimotes" +msgstr[0] "" +msgstr[1] "" + +#: src/input/wiimote_manager.cpp:410 +msgid "Could not detect any wiimote :/" +msgstr "" + +#: src/io/rich_presence.cpp:477 +msgid "Getting ready to race" +msgstr "" + +#: src/karts/controller/local_player_controller.cpp:329 +msgid "Penalty time!!" +msgstr "" + +#: src/karts/controller/local_player_controller.cpp:332 +msgid "Don't accelerate before 'Set!'" +msgstr "" + +#: src/karts/controller/spare_tire_ai.cpp:150 +msgid "You can have at most 3 lives!" +msgstr "" + +#: src/karts/controller/spare_tire_ai.cpp:157 +msgid "+1 life." +msgstr "" + +#: src/karts/kart.cpp:1032 +msgid "You were too slow!" +msgstr "" + +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "" + +#: src/karts/kart.cpp:1034 +msgid "You won the race!" +msgstr "" + +#: src/karts/kart.cpp:1035 +#, c-format +msgid "You finished the race in rank %d!" +msgstr "" + +#. I18N: Message shown in game to tell player left the game in network +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 +#, c-format +msgid "%s left the game." +msgstr "" + +#: src/main.cpp:2042 +msgid "" +"SuperTuxKart may connect to a server to download add-ons and notify you of " +"updates. Please read our privacy policy at https://supertuxkart.net/Privacy." +" Would you like this feature to be enabled? (To change this setting at a " +"later time, go to options, select tab 'General', and edit \"Connect to the " +"Internet\")." +msgstr "" + +#: src/main.cpp:2393 +msgid "Your screen resolution is too low to run STK." +msgstr "" + +#: src/main.cpp:2444 +msgid "" +"Your driver version is too old. Please install the latest video drivers." +msgstr "" + +#: src/main.cpp:2464 +#, c-format +msgid "" +"Your graphics driver appears to be very old. Please check if an update is " +"available. SuperTuxKart recommends a driver supporting %s or better. The " +"game will likely still run, but in a reduced-graphics mode." +msgstr "" + +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 +msgid "Server connection timed out." +msgstr "" + +#. I18N: Show when a player gets the red flag in CTF +#: src/modes/capture_the_flag.cpp:190 +#, c-format +msgid "%s has the red flag!" +msgstr "" + +#. I18N: Show when the red flag is returned to its base in CTF +#: src/modes/capture_the_flag.cpp:197 +msgid "The red flag has returned!" +msgstr "" + +#. I18N: Show when a player gets the blue flag in CTF +#: src/modes/capture_the_flag.cpp:208 +#, c-format +msgid "%s has the blue flag!" +msgstr "" + +#. I18N: Show when the blue flag is returned to its base in CTF +#: src/modes/capture_the_flag.cpp:215 +msgid "The blue flag has returned!" +msgstr "" + +#: src/modes/capture_the_flag.cpp:408 +#, c-format +msgid "%s captured the blue flag!" +msgstr "" + +#: src/modes/capture_the_flag.cpp:412 +#, c-format +msgid "%s captured the red flag!" +msgstr "" + +#: src/modes/easter_egg_hunt.cpp:222 +#, c-format +msgid "Eggs: %d / %d" +msgstr "" + +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 +msgid "Leader" +msgstr "" + +#: src/modes/linear_world.cpp:418 +msgid "Final lap!" +msgstr "आखिरी चक्कर!" + +#: src/modes/linear_world.cpp:450 +#, c-format +msgid "Lap %i" +msgstr "" + +#: src/modes/linear_world.cpp:552 +#, c-format +msgctxt "fastest_lap" +msgid "%s by %s" +msgstr "" + +#: src/modes/linear_world.cpp:558 +msgid "New fastest lap" +msgstr "" + +#: src/modes/linear_world.cpp:1100 +msgid "WRONG WAY!" +msgstr "" + +#: src/modes/soccer_world.cpp:533 src/modes/soccer_world.cpp:660 +#, c-format +msgid "%s scored a goal!" +msgstr "" + +#: src/modes/soccer_world.cpp:535 src/modes/soccer_world.cpp:662 +#, c-format +msgid "Oops, %s made an own goal!" +msgstr "" + +#: src/modes/three_strikes_battle.cpp:665 +#, c-format +msgid "%i spare tire kart has been spawned!" +msgid_plural "%i spare tire karts have been spawned!" +msgstr[0] "" +msgstr[1] "" + +#: src/modes/world.cpp:1400 +msgid "You have been eliminated!" +msgstr "" + +#: src/modes/world.cpp:1407 +#, c-format +msgid "'%s' has been eliminated." +msgstr "'%s' का पत्ता साफ़" + +#: src/network/protocols/client_lobby.cpp:130 +msgid "Server has been shut down." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:131 +msgid "You were kicked from the server." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:133 +msgid "You were kicked: Ping too high." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 +msgid "Bad network connection is detected." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 +msgid "Bot" +msgstr "" + +#: src/network/protocols/client_lobby.cpp:642 +#, c-format +msgid "%s disconnected." +msgstr "" + +#. I18N: Message shown in network lobby to tell user that +#. player name is clickable +#: src/network/protocols/client_lobby.cpp:673 +msgid "" +"Press player name in the list for player management and ranking information." +msgstr "" + +#. I18N: In the networking lobby +#. I18N: In server info dialog +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 +#, c-format +msgid "Difficulty: %s" +msgstr "" + +#. I18N: In the networking lobby +#: src/network/protocols/client_lobby.cpp:744 +#, c-format +msgid "Max players: %d" +msgstr "" + +#. I18N: In server info dialog +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 +#, c-format +msgid "Game mode: %s" +msgstr "" + +#. I18N: In the create server screen for soccer server +#: src/network/protocols/client_lobby.cpp:770 +#: src/states_screens/dialogs/server_configuration_dialog.cpp:174 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 +msgid "Time limit" +msgstr "" + +#. I18N: In the create server screen for soccer server +#: src/network/protocols/client_lobby.cpp:771 +#: src/states_screens/dialogs/server_configuration_dialog.cpp:175 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 +msgid "Goals limit" +msgstr "" + +#. I18N: In the networking lobby +#: src/network/protocols/client_lobby.cpp:775 +#, c-format +msgid "Soccer game type: %s" +msgstr "" + +#: src/network/protocols/client_lobby.cpp:785 +#, c-format +msgid "Grand prix progress: %d / %d" +msgstr "" + +#. I18N: Display when all players are in red or blue team, which the race +#. will not be allowed to start +#: src/network/protocols/client_lobby.cpp:904 +msgid "All players joined red or blue team." +msgstr "" + +#. I18N: Display when a player is allow to control the server +#: src/network/protocols/client_lobby.cpp:924 +msgid "You are now the owner of server." +msgstr "अब आप सर्वर के स्वामी हैं." + +#: src/network/protocols/client_lobby.cpp:967 +msgid "Connection refused: Server is busy." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:972 +msgid "Connection refused: You are banned from the server." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:987 +msgid "Connection refused: Server password is incorrect." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:991 +msgid "Connection refused: Game data is incompatible." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:995 +msgid "Connection refused: Server is full." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:999 +msgid "Connection refused: Invalid player connecting." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:1027 +msgid "Failed to start the network game." +msgstr "" + +#. I18N: Error message shown if live join or spectate failed in network +#: src/network/protocols/client_lobby.cpp:1242 +msgid "The game has ended, you can't live join or spectate anymore." +msgstr "" + +#. I18N: Error message shown if live join failed in network +#: src/network/protocols/client_lobby.cpp:1246 +msgid "No remaining place in the arena - live join disabled." +msgstr "" + +#. I18N: Error message shown if only 1 player remains in network +#: src/network/protocols/client_lobby.cpp:1250 +msgid "Only 1 player remaining, returning to lobby." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:1256 +msgid "Server owner quit the game." +msgstr "" + +#. I18N: Status shown to player when he will be spectating the next game +#: src/network/protocols/client_lobby.cpp:1260 +msgid "You will be spectating the next game." +msgstr "" + +#. I18N: Show when player join red team of the started game in +#. network +#: src/network/protocols/client_lobby.cpp:1436 +#, c-format +msgid "%s joined the red team." +msgstr "" + +#. I18N: Show when player join blue team of the started game in +#. network +#: src/network/protocols/client_lobby.cpp:1442 +#, c-format +msgid "%s joined the blue team." +msgstr "" + +#. I18N: Show when player join the started game in network +#: src/network/protocols/client_lobby.cpp:1448 +#, c-format +msgid "%s joined the game." +msgstr "" + +#. I18N: Message shown in game to tell the player it's possible to change +#. the camera target in spectate mode of network +#: src/network/protocols/client_lobby.cpp:1639 +#, c-format +msgid "" +"Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " +"camera position." +msgstr "" + +#. I18N: Tell player he has successfully report this named player +#: src/network/protocols/client_lobby.cpp:1655 +#, c-format +msgid "Successfully reported %s." +msgstr "" + +#. I18N: Shown when there is download error for assets download +#. in the first run +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 +msgid "" +"Failed to download assets, check your storage space or internet connection " +"and try again later." +msgstr "" + +#: src/network/protocols/connect_to_server.cpp:230 +msgid "No quick play server available." +msgstr "" + +#: src/network/protocols/connect_to_server.cpp:380 +#, c-format +msgid "Cannot connect to server %s." +msgstr "" + +#. I18N: Show the failed detect port server name +#: src/network/protocols/connect_to_server.cpp:883 +#, c-format +msgid "Failed to detect port number for server %s." +msgstr "" + +#: src/network/protocols/lobby_protocol.cpp:294 +msgid "Network grand prix has been finished." +msgstr "" + +#: src/network/server_config.cpp:263 +msgid "Time Trial (Grand Prix)" +msgstr "" + +#. I18N: Game mode +#. I18N: In the create server screen for battle server +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 +#: src/states_screens/dialogs/server_configuration_dialog.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 +msgid "Free-For-All" +msgstr "" + +#. I18N: Game mode +#. I18N: In the create server screen for battle server +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 +#: src/states_screens/dialogs/server_configuration_dialog.cpp:162 +#: src/states_screens/online/create_server_screen.cpp:244 +msgid "Capture The Flag" +msgstr "" + +#: src/online/online_player_profile.cpp:456 +#, c-format +msgid "%s is now online." +msgstr "%s अभी ऑनलाइन हैं" + +#: src/online/online_player_profile.cpp:460 +#, c-format +msgid "%s and %s are now online." +msgstr "%sऔर %s अभी ऑनलाइन हैं" + +#: src/online/online_player_profile.cpp:465 +#, c-format +msgid "%s, %s and %s are now online." +msgstr "%s, %sऔर %s अभी ऑनलाइन हैं" + +#. I18N: Only used for count > 3 +#: src/online/online_player_profile.cpp:471 +#, c-format +msgid "%d friend is now online." +msgid_plural "%d friends are now online." +msgstr[0] "" +msgstr[1] "" + +#. I18N: Tell your friend if he is on any server in game +#: src/online/online_player_profile.cpp:520 +#, c-format +msgid "%s is now on server \"%s\"." +msgstr "" + +#: src/online/online_player_profile.cpp:551 +#, c-format +msgid "You have %d new friend request!" +msgid_plural "You have %d new friend requests!" +msgstr[0] "" +msgstr[1] "" + +#: src/online/online_player_profile.cpp:557 +msgid "You have a new friend request!" +msgstr "" + +#: src/online/xml_request.cpp:83 +msgid "" +"Unable to connect to the server. Check your internet connection or try again" +" later." +msgstr "" + +#: src/race/grand_prix_data.cpp:639 src/states_screens/gp_info_screen.cpp:77 +msgid "Default" +msgstr "" + +#: src/race/grand_prix_data.cpp:641 src/states_screens/gp_info_screen.cpp:78 +msgid "None" +msgstr "" + +#: src/race/grand_prix_data.cpp:645 src/states_screens/gp_info_screen.cpp:80 +msgid "Random" +msgstr "" + +#: src/race/highscore_manager.cpp:102 +msgid "" +"The highscore file was too old,\n" +"all highscores have been erased." +msgstr "" + +#. I18N: Game mode +#: src/race/race_manager.cpp:1294 +msgid "Follow the Leader" +msgstr "" + +#. I18N: Game mode +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 +msgid "3 Strikes Battle" +msgstr "3 मौत की जंग" + +#: src/replay/replay_recorder.cpp:358 +msgid "Incomplete replay file will not be saved." +msgstr "" + +#: src/replay/replay_recorder.cpp:394 +#, c-format +msgid "Replay saved in \"%s\"." +msgstr "" + +#: src/states_screens/addons_screen.cpp:51 +msgid "1 week" +msgstr "1 हफ़्ता" + +#: src/states_screens/addons_screen.cpp:52 +msgid "2 weeks" +msgstr "2 हफ्तों" + +#: src/states_screens/addons_screen.cpp:53 +msgid "1 month" +msgstr "1 महीना" + +#: src/states_screens/addons_screen.cpp:54 +msgid "3 months" +msgstr "3 महीने" + +#: src/states_screens/addons_screen.cpp:55 +msgid "6 months" +msgstr "6 महीने" + +#: src/states_screens/addons_screen.cpp:56 +msgid "9 months" +msgstr "9 महीने" + +#: src/states_screens/addons_screen.cpp:57 +msgid "1 year" +msgstr "1 साल" + +#: src/states_screens/addons_screen.cpp:58 +msgid "2 years" +msgstr "2 साल" + +#: src/states_screens/addons_screen.cpp:109 +msgid "Add-on name" +msgstr "" + +#: src/states_screens/addons_screen.cpp:110 +msgid "Updated date" +msgstr "" + +#. I18N: Addon not installed for fillter +#: src/states_screens/addons_screen.cpp:140 +msgid "Not installed" +msgstr "" + +#. I18N: as in: The Old Island by Johannes Sjolund +#: src/states_screens/addons_screen.cpp:326 +#, c-format +msgctxt "addons" +msgid "%s by %s" +msgstr "%s के द्वारा %s" + +#: src/states_screens/addons_screen.cpp:447 +msgid "Please wait while addons are updated" +msgstr "" + +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 +msgid "" +"Sorry, an error occurred while contacting the add-ons website. Make sure you" +" are connected to the Internet and that SuperTuxKart is not blocked by a " +"firewall" +msgstr "" + +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 +#: src/states_screens/race_setup_screen.cpp:101 +msgid "Locked : solve active challenges to gain access to more!" +msgstr "" + +#: src/states_screens/arenas_screen.cpp:351 +msgid "Random Arena" +msgstr "" + +#: src/states_screens/credits.cpp:184 +msgid "translator-credits" +msgstr "Launchpad Contributions:\n Akela https://launchpad.net/~sdake\n STK-team https://launchpad.net/~stk\n sid https://launchpad.net/~sidchat1\nBashishtha https://www.transifex.com\nKevin08 https://www.transifex.com\nAadithyan SS https://transifex.com" + +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:65 +msgctxt "achievement_info" +msgid "Subgoals" +msgstr "" + +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:67 +msgctxt "achievement_info" +msgid "Progress" +msgstr "" + +#. I18N: For achievements, a parent goal linking logically several subgoals +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:162 +msgid "Fulfill all the subgoals" +msgstr "" + +#. I18N: For achievements, a parent goal linking logically several subgoals +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:164 +msgid "Fulfill all the subgoals at the same time" +msgstr "" + +#. I18N: For achievements, a parent goal linking logically several subgoals +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:166 +msgid "Fulfill at least one subgoal" +msgstr "" + +#. I18N: For achievements, a parent goal linking logically several subgoals +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:168 +msgid "The sum of the subgoals must reach the indicated value" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:170 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:276 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:301 +msgid "Races won" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:172 +msgid "Normal races won" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:174 +msgid "Time-trial races won" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:176 +msgid "Follow-the-Leader races won" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:178 +msgid "Consecutive won races" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:180 +msgid "Consecutive won races in Expert or SuperTux" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:182 +msgid "Novice races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:184 +msgid "Novice races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:186 +msgid "Intermediate races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:188 +msgid "Intermediate races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:190 +msgid "Expert races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:192 +msgid "Expert races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:194 +msgid "SuperTux races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:196 +msgid "SuperTux races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:198 +msgid "Normal races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:200 +msgid "Normal races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:202 +msgid "Time-trial races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:204 +msgid "Time-trial races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:206 +msgid "Follow-the-Leader races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:208 +msgid "Follow-the-Leader races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:210 +msgid "3 Strikes battles started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:212 +msgid "3 Strikes battles finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:214 +msgid "Soccer matches started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:216 +msgid "Soccer matches finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:218 +msgid "Egg Hunts started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:220 +msgid "Egg Hunts finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:222 +msgid "Races started with a ghost replay" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:224 +msgid "Races finished with a ghost replay" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:226 +msgid "Capture-the-Flag matches started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:228 +msgid "Capture-the-Flag matches finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:230 +msgid "Free-for-All matches started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:232 +msgid "Free-for-All matches finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:234 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:236 +msgid "Powerups used" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:236 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:240 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:244 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:248 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:250 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:254 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:262 +msgid " (1 race)" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:238 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:240 +msgid "Bowling ball hits" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:242 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:244 +msgid "Swatter hits" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:246 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:248 +msgid "All hits" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:250 +msgid "Hits against the same kart" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:252 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:254 +msgid "Bananas collected" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#. I18N: Key binding name +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 +#: src/states_screens/options/options_screen_device.cpp:264 +msgid "Skidding" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:269 +msgid " (1 lap)" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:272 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:297 +msgid "Races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:272 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:274 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:276 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:278 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:280 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:282 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:284 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:286 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:288 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:294 +msgid " (maximum on one official track)" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:274 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:299 +msgid "Races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:278 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:303 +msgid "Reverse direction races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:280 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:305 +msgid "Races finished alone" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:282 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:307 +msgid "Races with less than the default lap number" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:284 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:309 +msgid "Races with more than the default lap number" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:286 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:311 +msgid "Races with at least twice as much as the default lap number" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:288 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:313 +msgid "Egg hunts started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:292 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:317 +msgid "Egg hunts finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:297 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:299 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:301 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:303 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:305 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:307 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:309 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:311 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:313 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:319 +msgid " (official tracks matching the goal)" +msgstr "" + +#: src/states_screens/dialogs/add_device_dialog.cpp:48 +msgid "" +"New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" +"\n" +"To add a keyboard config, you can use the button below, HOWEVER please note that most keyboards only support a limited amount of simultaneous keypresses and are thus inappropriate for multiplayer gameplay. (You can, however, connect multiple keyboards to this device. Remember that everyone still needs different keybindings in this case.)" +msgstr "" + +#. I18N: In the 'add new input device' dialog +#: src/states_screens/dialogs/add_device_dialog.cpp:71 +msgid "Add Wiimote" +msgstr "" + +#. I18N: In the 'add new input device' dialog +#: src/states_screens/dialogs/add_device_dialog.cpp:88 +msgid "Add Keyboard Configuration" +msgstr "कीबोर्ड कॉन्फ़िगरेशन जोड़ें" + +#: src/states_screens/dialogs/addons_loading.cpp:126 +msgid "Update" +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:138 +#, c-format +msgid "Version: %d" +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:169 +msgid "featured" +msgstr "" + +#. I18N: File size of game assets or addons downloading +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 +#, c-format +msgid "Size: %s" +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 +msgid "Sorry, downloading the add-on failed" +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:391 +#, c-format +msgid "Problems installing the addon '%s'." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 +msgid "Try again" +msgstr "पुन: प्रयास करें" + +#: src/states_screens/dialogs/addons_loading.cpp:442 +#, c-format +msgid "Problems removing the addon '%s'." +msgstr "" + +#: src/states_screens/dialogs/addons_pack.cpp:71 +msgid "Background download completed." +msgstr "" + +#: src/states_screens/dialogs/addons_pack.cpp:132 +msgid "Background download" +msgstr "" + +#: src/states_screens/dialogs/addons_pack.cpp:141 +msgid "Background download has already started." +msgstr "" + +#: src/states_screens/dialogs/change_password_dialog.cpp:140 +msgid "Current password invalid." +msgstr "" + +#: src/states_screens/dialogs/change_password_dialog.cpp:146 +#: src/states_screens/online/register_screen.cpp:382 +msgid "Password has to be between 8 and 30 characters long!" +msgstr "" + +#: src/states_screens/dialogs/change_password_dialog.cpp:153 +#: src/states_screens/online/register_screen.cpp:358 +msgid "Passwords don't match!" +msgstr "" + +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 +#: src/states_screens/online/register_screen.cpp:448 +msgid "Validating info" +msgstr "" + +#: src/states_screens/dialogs/change_password_dialog.cpp:250 +msgid "Password successfully changed." +msgstr "" + +#. I18N: In the 'confirm resolution' dialog, that's shown when switching +#. resoluton +#: src/states_screens/dialogs/confirm_resolution_dialog.cpp:86 +#, c-format +msgid "Confirm resolution within %i second" +msgid_plural "Confirm resolution within %i seconds" +msgstr[0] "" +msgstr[1] "" + +#: src/states_screens/dialogs/confirm_resolution_dialog.cpp:93 +msgid "" +"Resolutions smaller than 1024x768 or 1280x720 are unsupported. Some parts of" +" the UI may not work correctly." +msgstr "" + +#. I18N: In the UI options, Camera setting: Drone chase +#: src/states_screens/dialogs/custom_camera_settings.cpp:86 +#: src/states_screens/options/options_screen_ui.cpp:126 +msgid "Drone chase" +msgstr "" + +#. I18N: In the UI options, Camera setting: Custom +#. I18N: custom video settings +#: src/states_screens/dialogs/custom_camera_settings.cpp:103 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 +msgid "Custom" +msgstr "" + +#. I18N: in the graphical options tooltip; +#. indicates a graphical feature is disabled +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 +msgid "Disabled" +msgstr "अक्षम" + +#. I18N: if only important particles effects is enabled +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 +msgid "Important only" +msgstr "" + +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 +msgid "Very Low" +msgstr "" + +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 +msgid "Low" +msgstr "" + +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 +msgid "High" +msgstr "" + +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "" + +#. I18N: In download assets dialog +#: src/states_screens/dialogs/download_assets.cpp:113 +msgid "" +"SuperTuxKart will download full assets (including high quality textures and " +"music) for better gaming experience, this will use your mobile data if you " +"don't have a wifi connection." +msgstr "" + +#. I18N: In download assets dialog +#: src/states_screens/dialogs/download_assets.cpp:121 +msgid "" +"SuperTuxKart will download full assets (including high quality textures and " +"music) for better gaming experience." +msgstr "" + +#: src/states_screens/dialogs/enter_address_dialog.cpp:42 +msgid "" +"Enter the server address optionally followed by : and then port or select " +"address from list." +msgstr "" + +#: src/states_screens/dialogs/enter_address_dialog.cpp:124 +#, c-format +msgid "Invalid server address: %s." +msgstr "" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 +msgctxt "column_name" +msgid "Reverse" +msgstr "" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/online/server_selection.cpp:135 +msgctxt "column_name" +msgid "Difficulty" +msgstr "" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 +msgctxt "column_name" +msgid "Laps" +msgstr "" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 +msgctxt "column_name" +msgid "Time" +msgstr "समय" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 +msgctxt "column_name" +msgid "Kart" +msgstr "" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 +msgctxt "column_name" +msgid "User" +msgstr "" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 +msgctxt "column_name" +msgid "Version" +msgstr "" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 +#: src/states_screens/edit_gp_screen.cpp:261 +#: src/states_screens/ghost_replay_selection.cpp:394 +#: src/states_screens/high_score_selection.cpp:265 +msgid "No" +msgstr "नहीं" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 +#: src/states_screens/edit_gp_screen.cpp:151 +#: src/states_screens/high_score_selection.cpp:141 +msgid "Track" +msgstr "" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 +#, c-format +msgid "Top %d High Scores" +msgstr "" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 +#, c-format +msgid "%s: %s" +msgstr "" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 +#, c-format +msgid "Number of karts: %d" +msgstr "" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 +#, c-format +msgid "Time target: %s" +msgstr "" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 +#, c-format +msgid "Laps: %d" +msgstr "" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 +#, c-format +msgid "Reverse: %s" +msgstr "" + +#. I18N: for empty highscores entries +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 +msgid "(Empty)" +msgstr "(खाली)" + +#. I18N: In kart color choosing dialog +#: src/states_screens/dialogs/kart_color_slider_dialog.cpp:47 +msgid "Use original color" +msgstr "" + +#. I18N: In kart color choosing dialog +#: src/states_screens/dialogs/kart_color_slider_dialog.cpp:49 +msgid "Pick a color from slider" +msgstr "" + +#: src/states_screens/dialogs/message_dialog.cpp:145 +msgid "Don't show again" +msgstr "" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:50 +msgid "Player info" +msgstr "" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:55 +#, c-format +msgid "Player name: %s" +msgstr "" + +#. I18N: In the network player dialog, show the player location with +#. country name (based on IP geolocation) +#: src/states_screens/dialogs/network_player_dialog.cpp:64 +#, c-format +msgid "Player location: %s" +msgstr "" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:108 +msgid "Kick" +msgstr "" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:124 +msgid "Change team" +msgstr "" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:139 +msgid "Enable handicap" +msgstr "" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:144 +msgid "Disable handicap" +msgstr "" + +#. I18N: In the network player dialog, +#. report player about for example abusive behaviour in game +#: src/states_screens/dialogs/network_player_dialog.cpp:159 +msgid "Report player" +msgstr "" + +#. I18N: In the network player dialog, showing when waiting for +#. the result of the ranking info of a player +#: src/states_screens/dialogs/network_player_dialog.cpp:181 +#: src/states_screens/dialogs/player_rankings_dialog.cpp:141 +#, c-format +msgid "Fetching ranking info for %s" +msgstr "" + +#. I18N: In the network player dialog, instruction for reporting player +#: src/states_screens/dialogs/network_player_dialog.cpp:194 +#, c-format +msgid "Tell server administrator about this player (%s):" +msgstr "" + +#. I18N: In press a key dialog, tell user to press a key to bind configuration +#: src/states_screens/dialogs/press_a_key_dialog.cpp:43 +msgid "" +"Press any key...\n" +"(Press ESC to cancel)" +msgstr "" + +#: src/states_screens/dialogs/press_a_key_dialog.cpp:49 +msgid "Press any key..." +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:117 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 +msgid "Chat is disabled, enable in options menu." +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +msgid "Back to Battle" +msgstr "खेल में वापिस" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 +msgid "Setup New Game" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 +msgid "Restart Battle" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 +msgid "Exit Battle" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 +msgid "Setup New Race" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 +msgid "Exit Race" +msgstr "Race ख़त्म करो" + +#. I18N: In the network player dialog, indiciating a network +#. player has no ranking +#: src/states_screens/dialogs/ranking_callback.hpp:44 +#, c-format +msgid "%s has no ranking yet." +msgstr "" + +#: src/states_screens/dialogs/ranking_callback.hpp:56 +#, c-format +msgid "%s is number %d in the rankings with a score of %f." +msgstr "" + +#: src/states_screens/dialogs/recovery_dialog.cpp:124 +msgid "Username and/or email address invalid." +msgstr "" + +#: src/states_screens/dialogs/registration_dialog.cpp:43 +#, c-format +msgid "" +"Please read the terms and conditions for SuperTuxKart at '%s'. You must " +"agree to these terms in order to register an account for STK. If you have " +"any questions or comments regarding these terms, one of the members of the " +"development team would gladly assist you." +msgstr "" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:60 +msgid "Nitro challenge" +msgstr "" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:65 +#: src/states_screens/race_setup_screen.cpp:137 +msgid "Ghost replay race" +msgstr "" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:72 +#: src/states_screens/race_result_gui.cpp:2074 +#, c-format +msgid "Laps: %i" +msgstr "" + +#. I18N: In the Select challenge dialog, type of this challenge +#: src/states_screens/dialogs/select_challenge.cpp:82 +#, c-format +msgid "Type: %s" +msgstr "" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:90 +#: src/states_screens/race_result_gui.cpp:2249 +#, c-format +msgid "Required Rank: %i" +msgstr "" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:96 +#: src/states_screens/race_result_gui.cpp:2258 +#, c-format +msgid "Required Time: %i" +msgstr "" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:103 +#: src/states_screens/race_result_gui.cpp:2270 +#, c-format +msgid "Required Nitro Points: %i" +msgstr "" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:109 +#, c-format +msgid "Number of AI Karts: %i" +msgstr "" + +#. I18N: In the create server screen, show various battle mode available +#: src/states_screens/dialogs/server_configuration_dialog.cpp:158 +#: src/states_screens/online/create_server_screen.cpp:238 +msgid "Battle mode" +msgstr "" + +#. I18N: In the create server screen +#: src/states_screens/dialogs/server_configuration_dialog.cpp:171 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 +msgid "Soccer game type" +msgstr "" + +#. I18N: In the server info dialog, show the server location with +#. country name (based on IP geolocation) +#: src/states_screens/dialogs/server_info_dialog.cpp:111 +#, c-format +msgid "Server location: %s" +msgstr "" + +#. I18N: In server info dialog, showing the current track playing in server +#: src/states_screens/dialogs/server_info_dialog.cpp:120 +#, c-format +msgid "Current track: %s" +msgstr "" + +#: src/states_screens/dialogs/server_info_dialog.cpp:130 +msgid "Rank" +msgstr "" + +#. I18N: Show above the player list in server info dialog, tell +#. the user name on server +#: src/states_screens/dialogs/server_info_dialog.cpp:133 +msgid "Player" +msgstr "" + +#. I18N: Show above the player list in server info dialog, tell +#. the scores of user calculated by player rankings +#: src/states_screens/dialogs/server_info_dialog.cpp:136 +msgid "Scores" +msgstr "" + +#. I18N: Show above the player list in server info dialog, tell +#. the user time played on server +#: src/states_screens/dialogs/server_info_dialog.cpp:139 +msgid "Time played" +msgstr "" + +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 +msgid "Remove from bookmarks" +msgstr "" + +#: src/states_screens/dialogs/splitscreen_player_dialog.cpp:130 +msgid "Input device already exists." +msgstr "" + +#: src/states_screens/dialogs/splitscreen_player_dialog.cpp:147 +msgid "No player available for connecting to server." +msgstr "" + +#. I18N: In the user info dialog +#: src/states_screens/dialogs/user_info_dialog.cpp:61 +#, c-format +msgid "Username: %s" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:65 +msgid "Cancel Request" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 +msgid "Today" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:169 +msgid "Friend request sent!" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:226 +msgid "Friend request accepted!" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:278 +msgid "Friend request declined!" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:324 +msgid "Friend removed!" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:375 +msgid "Friend request cancelled!" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:485 +msgid "Processing" +msgstr "" + +#: src/states_screens/dialogs/vote_dialog.cpp:178 +msgid "Fetching last vote" +msgstr "" + +#: src/states_screens/dialogs/vote_dialog.cpp:197 +msgid "You can adapt your previous rating by clicking the stars beneath." +msgstr "" + +#: src/states_screens/dialogs/vote_dialog.cpp:202 +msgid "" +"You have not yet voted for this addon. Select your desired rating by " +"clicking the stars beneath" +msgstr "" + +#: src/states_screens/dialogs/vote_dialog.cpp:236 +msgid "Vote successful! You can now close the window." +msgstr "" + +#: src/states_screens/dialogs/vote_dialog.cpp:253 +msgid "Performing vote" +msgstr "" + +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 +msgid "Random Track" +msgstr "" + +#: src/states_screens/edit_gp_screen.cpp:117 +#: src/states_screens/ghost_replay_selection.cpp:513 +#: src/states_screens/grand_prix_editor_screen.cpp:111 +#, c-format +msgid "Are you sure you want to remove '%s'?" +msgstr "" + +#: src/states_screens/edit_gp_screen.cpp:134 +#: src/states_screens/edit_gp_screen.cpp:382 +msgid "Do you want to save your changes?" +msgstr "" + +#: src/states_screens/edit_gp_screen.cpp:152 +msgid "Laps" +msgstr "" + +#: src/states_screens/edit_gp_screen.cpp:153 +msgid "Reversed" +msgstr "" + +#. I18N: Indicate that the grand prix is modified and not saved +#: src/states_screens/edit_gp_screen.cpp:290 +#, c-format +msgid "%s (+)" +msgstr "" + +#: src/states_screens/edit_gp_screen.cpp:330 +msgid "An error occurred while trying to save your grand prix." +msgstr "" + +#: src/states_screens/edit_track_screen.cpp:317 +msgid "Select a track" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:254 +#, c-format +msgid "You completed the easy challenge! Points earned on this level: %i/%i" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:260 +#, c-format +msgid "" +"You completed the intermediate challenge! Points earned on this level: %i/%i" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:266 +#, c-format +msgid "" +"You completed the difficult challenge! Points earned on this level: %i/%i" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:272 +#, c-format +msgid "" +"You completed the SuperTux challenge! Points earned on this level: %i/%i" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:315 +#, c-format +msgid "You unlocked %s!" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:645 +msgid "Challenge Completed" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:684 +msgid "You unlocked track %0" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:730 +msgid "You unlocked grand prix %0" +msgstr "" + +#: src/states_screens/ghost_replay_selection.cpp:157 +msgctxt "column_name" +msgid "Track" +msgstr "" + +#: src/states_screens/ghost_replay_selection.cpp:168 +#: src/states_screens/online/server_selection.cpp:134 +msgctxt "column_name" +msgid "Players" +msgstr "" + +#: src/states_screens/gp_info_screen.cpp:172 +#: src/states_screens/gp_info_screen.cpp:230 +msgid "Reload" +msgstr "" + +#: src/states_screens/grand_prix_cutscene.cpp:77 +#: src/states_screens/grand_prix_editor_screen.cpp:100 +#: src/states_screens/grand_prix_editor_screen.cpp:117 +msgid "Please enter the name of the grand prix" +msgstr "" + +#: src/states_screens/grand_prix_editor_screen.cpp:168 +msgid "Please select a Grand Prix" +msgstr "" + +#: src/states_screens/grand_prix_editor_screen.cpp:338 +msgid "User defined" +msgstr "" + +#: src/states_screens/grand_prix_editor_screen.cpp:351 +msgid "Name is empty." +msgstr "" + +#: src/states_screens/grand_prix_editor_screen.cpp:359 +msgid "Another grand prix with this name already exists." +msgstr "" + +#: src/states_screens/grand_prix_editor_screen.cpp:365 +msgid "Name is too long." +msgstr "" + +#. I18N: when failing a GP +#: src/states_screens/grand_prix_lose.cpp:157 +msgid "Better luck next time!" +msgstr "इस बार नही अगली बार सही!" + +#: src/states_screens/grand_prix_win.cpp:169 +msgid "You completed a challenge!" +msgstr "अपने एक चुनौती पूरी की!" + +#: src/states_screens/grand_prix_win.cpp:325 +msgid "You won the Grand Prix!" +msgstr "" + +#: src/states_screens/grand_prix_win.cpp:326 +msgid "You completed the Grand Prix!" +msgstr "" + +#: src/states_screens/high_score_selection.cpp:147 +msgctxt "column_name" +msgid "Number of karts" +msgstr "" + +#: src/states_screens/high_score_selection.cpp:352 +msgid "Are you sure you want to remove this high score entry?" +msgstr "" + +#: src/states_screens/high_score_selection.cpp:360 +msgid "Are you sure you want to remove all of your high scores?" +msgstr "" + +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "" + +#: src/states_screens/kart_selection.cpp:490 +msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" +msgstr "" + +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 +msgid "Random Kart" +msgstr "" + +#: src/states_screens/kart_selection.cpp:1003 +msgid "Locked" +msgstr "" + +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 +msgid "" +"Everyone:\n" +"Press the 'Select' button to join the game" +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:343 +msgid "Would you like to play the tutorial of the game?" +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 +msgid "" +"You can not play online without internet access. If you want to play online," +" go in the options menu, and check \"Connect to the Internet\"." +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:619 +msgid "" +"You can not download addons without internet access. If you want to download" +" addons, go in the options menu, and check \"Connect to the Internet\"." +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:627 +msgid "" +"You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" +"\n" +"You can however delete already downloaded addons." +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:666 +msgid "The add-ons module is currently disabled in the Options screen" +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:678 +msgid "Please wait while the add-ons are loading" +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:699 +msgid "Are you sure you want to quit STK?" +msgstr "" + +#: src/states_screens/online/create_server_screen.cpp:107 +msgid "Create LAN Server" +msgstr "" + +#: src/states_screens/online/create_server_screen.cpp:112 +#, c-format +msgid "%s's server" +msgstr "" + +#. I18N: In the create server screen +#: src/states_screens/online/create_server_screen.cpp:220 +msgid "No. of grand prix track(s)" +msgstr "" + +#: src/states_screens/online/create_server_screen.cpp:303 +msgid "Name has to be between 4 and 30 characters long!" +msgstr "" + +#: src/states_screens/online/create_server_screen.cpp:320 +msgid "Incorrect characters in password!" +msgstr "" + +#. I18N: In the networking lobby, ready button is to allow player to tell +#. server that he is ready for next game for owner less server +#: src/states_screens/online/networking_lobby.cpp:196 +msgid "Ready" +msgstr "" + +#. I18N: Live join is displayed in networking lobby to allow players +#. to join the current started in-progress game +#: src/states_screens/online/networking_lobby.cpp:199 +msgid "Live join" +msgstr "" + +#. I18N: Spectate is displayed in networking lobby to allow players +#. to join the current started in-progress game +#: src/states_screens/online/networking_lobby.cpp:204 +msgid "Spectate" +msgstr "" + +#: src/states_screens/online/networking_lobby.cpp:205 +msgid "Install addon" +msgstr "" + +#. I18N: In the networking lobby, show when player is required to +#. wait before the current game finish with remaining time, +#. showing the current track name inside bracket +#: src/states_screens/online/networking_lobby.cpp:572 +#, c-format +msgid "" +"Please wait for the current game's (%s) end, estimated remaining time: %s." +msgstr "" + +#. I18N: In the networking lobby, show when player is required +#. to wait before the current game finish with remaining time +#: src/states_screens/online/networking_lobby.cpp:580 +#, c-format +msgid "Please wait for the current game's end, estimated remaining time: %s." +msgstr "" + +#. I18N: In the networking lobby, show when player is required +#. to wait before the current game finish with progress in +#. percent, showing the current track name inside bracket +#: src/states_screens/online/networking_lobby.cpp:592 +msgid "Please wait for the current game's (%s) end, estimated progress: %s%." +msgstr "" + +#. I18N: In the networking lobby, show when player is required +#. to wait before the current game finish with progress in +#. percent +#: src/states_screens/online/networking_lobby.cpp:601 +msgid "Please wait for the current game's end, estimated progress: %d%." +msgstr "" + +#. I18N: In the networking lobby, show when player is required to +#. wait before the current game finish +#: src/states_screens/online/networking_lobby.cpp:609 +msgid "Please wait for the current game's end." +msgstr "" + +#: src/states_screens/online/networking_lobby.cpp:676 +#, c-format +msgid "Game will start if there is more than %d player." +msgid_plural "Game will start if there are more than %d players." +msgstr[0] "" +msgstr[1] "" + +#. I18N: In the networking lobby, display the starting timeout +#. for owner-less server to begin a game +#: src/states_screens/online/networking_lobby.cpp:690 +#, c-format +msgid "" +"Starting after %d second, or once everyone has pressed the 'Ready' button." +msgid_plural "" +"Starting after %d seconds, or once everyone has pressed the 'Ready' button." +msgstr[0] "" +msgstr[1] "" + +#: src/states_screens/online/networking_lobby.cpp:727 +#, c-format +msgid "Connecting to server %s" +msgstr "" + +#: src/states_screens/online/networking_lobby.cpp:732 +msgid "Finding a quick play server" +msgstr "" + +#. I18N: In kart screen, show before the voting period in network ends. +#: src/states_screens/online/network_kart_selection.cpp:218 +#: src/states_screens/online/tracks_screen.cpp:952 +#, c-format +msgid "Remaining time: %d" +msgstr "" + +#. I18N: Goals in achievement +#: src/states_screens/online/online_profile_achievements.cpp:85 +msgid "Goals" +msgstr "" + +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 +msgid "Fetching achievements" +msgstr "" + +#: src/states_screens/online/online_profile_base.cpp:121 +#, c-format +msgid "%s's profile" +msgstr "" + +#: src/states_screens/online/online_profile_friends.cpp:80 +msgid "Since" +msgstr "" + +#: src/states_screens/online/online_profile_friends.cpp:81 +msgid "Status" +msgstr "" + +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 +msgid "Fetching friends" +msgstr "" + +#: src/states_screens/online/online_profile_friends.cpp:241 +msgid "New Request" +msgstr "" + +#: src/states_screens/online/online_profile_friends.cpp:242 +msgid "Pending" +msgstr "" + +#: src/states_screens/online/online_profile_friends.cpp:246 +msgid "Offline" +msgstr "" + +#: src/states_screens/online/online_profile_settings.cpp:83 +msgid "Enter new E-mail below" +msgstr "" + +#: src/states_screens/online/online_profile_settings.cpp:88 +msgid "New Email has to be between 5 and 254 characters long!" +msgstr "" + +#: src/states_screens/online/online_profile_settings.cpp:97 +msgid "New Email is invalid!" +msgstr "" + +#: src/states_screens/online/online_profile_settings.cpp:122 +msgid "E-mail changed!" +msgstr "" + +#: src/states_screens/online/online_profile_settings.cpp:124 +#, c-format +msgid "Failed to change E-mail: %s" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + +#. I18N: Shown to players when he is not is not logged in +#: src/states_screens/online/online_screen.cpp:317 +msgid "" +"You must be logged in to play Global networking. Click your username above." +msgstr "" + +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 +msgid "Searching" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:169 +#: src/states_screens/options/user_screen.cpp:114 +msgid "Exit game" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:282 +#: src/states_screens/online/register_screen.cpp:289 +#, c-format +msgid "Could not create player '%s'." +msgstr "" + +#: src/states_screens/online/register_screen.cpp:306 +msgid "User name cannot be empty." +msgstr "" + +#: src/states_screens/online/register_screen.cpp:362 +msgid "Online username and password must not be the same!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:366 +msgid "Emails don't match!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:370 +msgid "" +"Online username can only contain alphanumeric (ASCII) characters, periods, " +"dashes and underscores!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:374 +msgid "Online username has to be between 3 and 30 characters long!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:378 +msgid "Online username must not start with a number!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:386 +msgid "Email has to be between 5 and 254 characters long!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:392 +msgid "Email is invalid!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:456 +msgid "" +"You will receive an email with further instructions regarding account " +"activation. Please be patient and be sure to check your spam folder." +msgstr "" + +#: src/states_screens/online/register_screen.cpp:495 +msgid "Internet access is disabled, please enable it in the options" +msgstr "" + +#: src/states_screens/online/server_selection.cpp:132 +msgctxt "column_name" +msgid "Name" +msgstr "" + +#: src/states_screens/online/server_selection.cpp:133 +msgctxt "column_name" +msgid "Game mode" +msgstr "" + +#. I18N: In server selection screen, owner of server, only displayed +#. if it's localhost or friends' +#: src/states_screens/online/server_selection.cpp:140 +msgctxt "column_name" +msgid "Owner" +msgstr "" + +#. I18N: In server selection screen, distance to server +#: src/states_screens/online/server_selection.cpp:142 +msgctxt "column_name" +msgid "Distance (km)" +msgstr "" + +#. I18N: In server selection screen, unknown distance to server +#: src/states_screens/online/server_selection.cpp:316 +msgid "Unknown" +msgstr "" + +#. I18N: Message shown to user if no IPv4 detected by STK +#: src/states_screens/online/server_selection.cpp:361 +msgid "No IPv4 detected, you may not be able to join any servers." +msgstr "" + +#. I18N: Message shown to user if no IPv6 detected by STK +#: src/states_screens/online/server_selection.cpp:363 +msgid "No IPv6 detected, you may not be able to join any servers." +msgstr "" + +#: src/states_screens/online/server_selection.cpp:502 +msgid "No server is available." +msgstr "" + +#: src/states_screens/online/server_selection.cpp:510 +msgid "Fetching servers" +msgstr "" + +#: src/states_screens/online/server_selection.cpp:576 +msgid "Server Bookmarks" +msgstr "" + +#. I18N: In track screen for networking, clarify voting phase +#: src/states_screens/online/tracks_screen.cpp:322 +msgid "" +"If a majority of players all select the same track and race settings, voting" +" will end early." +msgstr "" + +#. I18N: In track screen +#. I18N: In the track info screen +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 +msgid "Random item location" +msgstr "" + +#. I18N: In track screen +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 +msgid "Number of goals to win" +msgstr "" + +#. I18N: In the track info screen +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 +msgid "Drive in reverse" +msgstr "" + +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 +msgid "Locked: solve active challenges to gain access to more!" +msgstr "" + +#: src/states_screens/options/options_screen_device.cpp:56 +msgid "Action" +msgstr "" + +#: src/states_screens/options/options_screen_device.cpp:57 +msgid "Key binding" +msgstr "" + +#. I18N: button to disable a gamepad configuration +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 +msgid "Disable Device" +msgstr "डिवाइस अक्षम करें" + +#. I18N: button to enable a gamepad configuration +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 +msgid "Enable Device" +msgstr "डिवाइस सक्षम करें" + +#. I18N: button to enable a keyboard configuration +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 +msgid "Enable Configuration" +msgstr "" + +#. I18N: Key binding section +#: src/states_screens/options/options_screen_device.cpp:156 +msgid "Game Keys" +msgstr "" + +#. I18N: Key binding section +#: src/states_screens/options/options_screen_device.cpp:170 +msgid "Menu Keys" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:246 +msgid "Steer Left" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:249 +msgid "Steer Right" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:252 +msgid "Accelerate" +msgstr "गति बढ़ाएं" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:255 +msgid "Brake / Reverse" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:258 +msgid "Fire" +msgstr "फ़यर" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:261 +msgid "Nitro" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:267 +msgid "Look Back" +msgstr "पीछे देखे" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:270 +msgid "Rescue" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:273 +msgid "Pause Game" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:278 +msgid "Up" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:281 +msgid "Down" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:284 +msgid "Left" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:287 +msgid "Right" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:290 +msgid "Select" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:293 +msgid "Cancel/Back" +msgstr "रद्द करें/पीछे जाएं" + +#: src/states_screens/options/options_screen_device.cpp:384 +msgid "* A blue item means a conflict with another configuration" +msgstr "" + +#: src/states_screens/options/options_screen_device.cpp:389 +msgid "* A red item means a conflict in the current configuration" +msgstr "" + +#: src/states_screens/options/options_screen_device.cpp:494 +msgid "" +"Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," +" all keys that contain a character that is different in upper-case will stop" +" working." +msgstr "" + +#. I18N: shown before deleting an input configuration +#: src/states_screens/options/options_screen_device.cpp:578 +msgid "Are you sure you want to permanently delete this configuration?" +msgstr "क्या आप सच-मुच इस कॉन्फ़िगरेशन को स्थायी रूप से हटाना चाहते हैं?" + +#: src/states_screens/options/options_screen_device.cpp:606 +msgid "Enter new configuration name, leave empty to revert default value." +msgstr "" + +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "" + +#. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text +#. fits the screen in low resolutions. +#: src/states_screens/options/options_screen_general.cpp:69 +msgid "" +"In multiplayer mode, players can select handicapped\n" +"(more difficult) profiles on the kart selection screen" +msgstr "" + +#. I18N: For mobile version for STK, install the full game assets which +#. will download from stk server +#: src/states_screens/options/options_screen_general.cpp:85 +msgid "Install full game assets" +msgstr "" + +#: src/states_screens/options/options_screen_general.cpp:189 +msgid "Are you sure to uninstall full game assets?" +msgstr "" + +#: src/states_screens/options/options_screen_input.cpp:98 +#, c-format +msgid "Keyboard %i" +msgstr "" + +#: src/states_screens/options/options_screen_input.cpp:149 +msgid "Touch Device" +msgstr "" + +#. I18N: In the input configuration screen, help for touch device +#: src/states_screens/options/options_screen_input.cpp:186 +msgid "Tap on a device to configure it" +msgstr "" + +#. I18N: in the language choice, to select the same language as the OS +#: src/states_screens/options/options_screen_language.cpp:62 +msgid "System Language" +msgstr "" + +#. I18N: In the UI options, minimap position in the race UI +#: src/states_screens/options/options_screen_ui.cpp:67 +msgid "In the bottom-left" +msgstr "" + +#. I18N: In the UI options, minimap position in the race UI +#: src/states_screens/options/options_screen_ui.cpp:69 +msgid "On the right side" +msgstr "" + +#. I18N: In the UI options, minimap position in the race UI +#: src/states_screens/options/options_screen_ui.cpp:71 +msgid "Hidden" +msgstr "" + +#. I18N: In the UI options, minimap position in the race UI +#: src/states_screens/options/options_screen_ui.cpp:73 +msgid "Centered" +msgstr "" + +#. I18N: In the UI options, Very small font size +#: src/states_screens/options/options_screen_ui.cpp:92 +msgid "Very small" +msgstr "बहुत छोटा" + +#. I18N: In the UI options, Small font size +#: src/states_screens/options/options_screen_ui.cpp:94 +msgid "Small" +msgstr "छोटा" + +#. I18N: In the UI options, Large font size +#: src/states_screens/options/options_screen_ui.cpp:98 +msgid "Large" +msgstr "बड़ा" + +#. I18N: In the UI options, Very large font size +#: src/states_screens/options/options_screen_ui.cpp:100 +msgid "Very large" +msgstr "बहुत बड़ा" + +#: src/states_screens/options/options_screen_ui.cpp:537 +msgid "" +"Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" +"\n" +"Closing the game before the story mode's completion invalidates the timer.\n" +"\n" +"To use the speedrun mode, please use a new profile." +msgstr "" + +#. I18N: In the video options +#: src/states_screens/options/options_screen_video.cpp:249 +msgid "Vertical Sync" +msgstr "" + +#. I18N: in graphical options. The \n is a newline character, place it where +#. appropriate, two can be used if required. +#: src/states_screens/options/options_screen_video.cpp:266 +msgid "" +"Vsync forces the graphics card to supply a new frame\n" +"only when the monitor is ready to display it." +msgstr "" + +#. I18N: in graphical options. +#: src/states_screens/options/options_screen_video.cpp:269 +msgid "Vsync will not work if your drivers don't support it." +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:466 +#, c-format +msgid "Particles Effects: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:472 +#, c-format +msgid "Animated Characters: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:475 +#, c-format +msgid "Dynamic lights: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:478 +#, c-format +msgid "Light scattering: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:481 +#, c-format +msgid "Anti-aliasing: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:484 +#, c-format +msgid "Ambient occlusion: %s" +msgstr "" + +#: src/states_screens/options/options_screen_video.cpp:488 +#, c-format +msgid "Shadows: %s" +msgstr "" + +#: src/states_screens/options/options_screen_video.cpp:490 +#, c-format +msgid "Shadows: %i" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:493 +#, c-format +msgid "Bloom: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:497 +#, c-format +msgid "Glow (outlines): %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:501 +#, c-format +msgid "Light shaft (God rays): %s" +msgstr "" + +#: src/states_screens/options/options_screen_video.cpp:506 +#, c-format +msgid "Rendered image quality: %s" +msgstr "" + +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:538 +#, c-format +msgid "Motion blur: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:542 +#, c-format +msgid "Depth of field: %s" +msgstr "" + +#: src/states_screens/options/user_screen.cpp:353 +msgid "Internet access is disabled. Do you want to enable it?" +msgstr "" + +#: src/states_screens/options/user_screen.cpp:541 +msgid "You need to enter a password." +msgstr "" + +#: src/states_screens/options/user_screen.cpp:562 +#, c-format +msgid "Logging out '%s'" +msgstr "" + +#: src/states_screens/options/user_screen.cpp:563 +#, c-format +msgid "Logging in '%s'" +msgstr "" + +#: src/states_screens/options/user_screen.cpp:646 +msgid "You can't delete the only player." +msgstr "" + +#. I18N: In the player info dialog (when deleting) +#: src/states_screens/options/user_screen.cpp:654 +#, c-format +msgid "Do you really want to delete player '%s'?" +msgstr "" + +#. I18N: as in "ready, set, go", shown at the beginning of the race +#: src/states_screens/race_gui_base.cpp:73 +msgid "Ready!" +msgstr "" + +#. I18N: as in "ready, set, go", shown at the beginning of the race +#: src/states_screens/race_gui_base.cpp:75 +msgid "Set!" +msgstr "" + +#. I18N: as in "ready, set, go", shown at the beginning of the race +#: src/states_screens/race_gui_base.cpp:77 +msgid "Go!" +msgstr "" + +#. I18N: Shown when a goal is scored +#: src/states_screens/race_gui_base.cpp:79 +msgid "GOAL!" +msgstr "" + +#. I18N: Shown waiting for other players in network to finish loading or +#. waiting +#: src/states_screens/race_gui_base.cpp:82 +#: src/states_screens/race_result_gui.cpp:429 +msgid "Waiting for others" +msgstr "" + +#. I18N: Shown waiting for the server in network if live join or spectate +#: src/states_screens/race_gui_base.cpp:84 +msgid "Waiting for the server" +msgstr "" + +#. I18N: string used to show the song title (e.g. "Sunny Song") +#: src/states_screens/race_gui_base.cpp:646 +#, c-format +msgid "\"%s\"" +msgstr "\"%s\"" + +#. I18N: string used to show the author of the music. (e.g. "Sunny Song" by +#. "John Doe") +#: src/states_screens/race_gui_base.cpp:656 +msgid "by" +msgstr "" + +#: src/states_screens/race_gui_base.cpp:769 +msgid "Collect nitro!" +msgstr "" + +#: src/states_screens/race_gui_base.cpp:771 +msgid "Follow the leader!" +msgstr "" + +#. I18N: When some GlobalPlayerIcons are hidden, write "Top 10" to show it +#: src/states_screens/race_gui_base.cpp:954 +#, c-format +msgid "Top %i" +msgstr "" + +#: src/states_screens/race_gui.cpp:445 +msgid "Challenge Failed" +msgstr "" + +#. I18N: Shown when multitouch GUI exists +#. and press the podium (2, 1, 3 like) icon instead of fire button +#: src/states_screens/race_gui_overworld.cpp:541 +msgid "Press podium icon to start tutorial" +msgstr "" + +#: src/states_screens/race_gui_overworld.cpp:547 +msgid "Press fire to start the tutorial" +msgstr "" + +#. I18N: Shown when multitouch GUI exists +#. and press the podium (2, 1, 3 like) icon instead of fire button +#: src/states_screens/race_gui_overworld.cpp:623 +msgid "Press podium icon to start the challenge" +msgstr "" + +#: src/states_screens/race_gui_overworld.cpp:629 +msgid "Press fire to start the challenge" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:289 +msgid "Quit the server" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:330 +msgid "Abort Grand Prix" +msgstr "ग्रांड प्रिक्स ख़त्म करें" + +#: src/states_screens/race_result_gui.cpp:350 +msgid "Restart" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:357 +msgid "Back to challenge selection" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:365 +msgid "Race against the new ghost replay" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:373 +msgid "Back to the menu" +msgstr "पीछे मेनू पर जाएं" + +#: src/states_screens/race_result_gui.cpp:556 +msgid "Do you really want to abort the Grand Prix?" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 +msgid "Red Team Wins" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 +msgid "Blue Team Wins" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 +msgid "It's a draw" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:935 +#, c-format +msgid "Eliminated after %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 +msgid "Eliminated" +msgstr "" + +#. I18N: indicates a player that scored in their own goal in result screen +#: src/states_screens/race_result_gui.cpp:1681 +msgid "(Own Goal)" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:1770 +#, c-format +msgid "Track %i/%i" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:1889 +msgid "Grand Prix progress:" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:1975 +msgid "Highscores" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2142 +#, c-format +msgid "Best lap time: %s" +msgstr "" + +#. I18N: is used to indicate who has the bast laptime (best laptime "by +#. kart_name") +#: src/states_screens/race_result_gui.cpp:2155 +#, c-format +msgid "by %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2229 +msgid "You completed the challenge!" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2229 +msgid "You failed the challenge!" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2282 +msgid "Reached Requirements of SuperTux" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + +#: src/states_screens/race_setup_screen.cpp:89 +msgid "All blows allowed, so catch weapons and make clever use of them!" +msgstr "सब प्रकार के दाँव-पेंच की अनुमति है, तो हथियारों को इकट्ठा कर लें और चालाकी से उनका प्रयोग करें!" + +#: src/states_screens/race_setup_screen.cpp:96 +msgid "Contains no powerups, so only your driving skills matter!" +msgstr "इसमें कोई भी शक्तिवर्धक नहीं है, अत: केवल आपके ड्राइविंग कौशल पर सब कुछ निर्भर है!" + +#. I18N: short definition for follow-the-leader game mode +#: src/states_screens/race_setup_screen.cpp:109 +msgid "Keep up with the leader kart but don't overtake it!" +msgstr "" + +#: src/states_screens/race_setup_screen.cpp:115 +msgid "Hit others with weapons until they lose all their lives." +msgstr "" + +#: src/states_screens/race_setup_screen.cpp:120 +msgid "Push the ball into the opposite cage to score goals." +msgstr "" + +#: src/states_screens/race_setup_screen.cpp:130 +msgid "Explore tracks to find all hidden eggs" +msgstr "" + +#: src/states_screens/race_setup_screen.cpp:138 +msgid "Race against ghost karts and try to beat them!" +msgstr "" + +#: src/states_screens/race_setup_screen.cpp:143 +msgid "Complete as many laps as possible in a given amount of time." +msgstr "" + +#. I18N: In soccer setup screen +#: src/states_screens/soccer_setup_screen.cpp:120 +msgid "Press red or blue soccer icon to change team" +msgstr "" + +#. I18N: when showing who is the author of track '%s' +#. I18N: (place %s where the name of the author should appear) +#: src/states_screens/track_info_screen.cpp:151 +#, c-format +msgid "Track by %s" +msgstr "" + +#. I18N: the max players supported by an arena. +#: src/states_screens/track_info_screen.cpp:159 +#, c-format +msgid "Max players supported: %d" +msgstr "" + +#: src/states_screens/track_info_screen.cpp:389 +msgid "Number of red team AI karts" +msgstr "" + +#: src/states_screens/tracks_and_gp_screen.cpp:124 +msgid "" +"You cannot play this Grand Prix because it contains tracks that aren't " +"unlocked!" +msgstr "" + +#: src/states_screens/tracks_and_gp_screen.cpp:245 +msgid "Locked!" +msgstr "" + +#: src/utils/string_utils.cpp:1242 +#, c-format +msgid "%s MB" +msgstr "%s MB" + +#: src/utils/string_utils.cpp:1249 src/utils/string_utils.cpp:1253 +#, c-format +msgid "%s KB" +msgstr "%s KB" + +#. I18N: Format for dates (%d = day, %m = month, %Y = year). See +#. http://www.cplusplus.com/reference/ctime/strftime/ for more info about date +#. formats. +#: src/utils/time.cpp:74 +msgid "%d/%m/%Y" +msgstr "" + +#: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 +msgid "Complete all challenges to unlock the big door!" +msgstr "" + +#: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 +msgid "" +"You need more points\n" +"to enter this challenge!\n" +"Check the minimap for\n" +"available challenges." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 +#, c-format +msgid "Accelerate with <%s>, and steer with <%s> and <%s>." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 +msgid "" +"Accelerate by touching the upper part of the wheel, and steer by moving left" +" or right." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 +msgid "" +"Accelerate by moving the accelerator upwards, and steer by tilting your " +"device." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 +msgid "" +"Accelerate by moving the accelerator upwards, and steer by rotating your " +"device." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 +#, c-format +msgid "" +"Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 +msgid "" +"Collect gift boxes, and fire by pressing the bowling icon to blow away these" +" boxes!" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 +#, c-format +msgid "" +"Press <%s> to look behind.\n" +"Fire the weapon with <%s> while pressing <%s> to fire behind!" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 +msgid "" +"Press the mirror icon to look behind.\n" +"Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 +#, c-format +msgid "Use the nitro you collected by pressing <%s>!" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 +msgid "Use the nitro you collected by pressing the nitro icon" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 +msgid "Collect nitro bottles (we will use them after the curve)." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 +#, c-format +msgid "Oops! When you're in trouble, press <%s> to be rescued." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 +msgid "Oops! When you're in trouble, press the bird icon to be rescued." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 +#, c-format +msgid "" +"Accelerate and press the <%s> key while turning to skid.\n" +"Skidding for a short while can help you turn faster to take sharp turns." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 +msgid "" +"Accelerate and press the skid icon while turning to skid.\n" +"Skidding for a short while can help you turn faster to take sharp turns." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 +msgid "" +"Note that if you manage to skid for several seconds, you will receive a " +"bonus speedup as a reward!" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 +msgid "You are now ready to race. Good luck!" +msgstr "आप रेस खेलने खेलिये तैयार है" + +#. I18N: Generic name in desktop file entry, summary in AppData and short +#. description in Google Play +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 +msgid "A 3D open-source kart racing game" +msgstr "" + +#. I18N: Keywords in desktop entry, translators please keep it separated with +#. semicolons +#: supertuxkart.desktop:11 +msgid "tux;game;race;" +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 +msgid "" +"Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " +"variety of characters, tracks, and modes to play. Our aim is to create a " +"game that is more fun than realistic, and provide an enjoyable experience " +"for all ages." +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 +msgid "" +"We have several tracks with various themes for players to enjoy, from " +"driving underwater, rural farmlands, jungles or even in space! Try your best" +" while avoiding other karts as they may overtake you, but don't eat the " +"bananas! Watch for bowling balls, plungers, bubble gum, and cakes thrown by " +"your opponents." +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 +msgid "" +"You can do a single race against other karts, compete in one of several " +"Grand Prix, try to beat the high score in time trials on your own, play " +"battle mode against the computer or your friends, and more! For a greater " +"challenge, join online and meet players from all over the world and prove " +"your racing skills!" +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 +msgid "This game has no ads." +msgstr "इस खेल में विज्ञापन नहीं हैं" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 +msgid "" +"This is an unstable version of SuperTuxKart that contains latest " +"improvements. It is released mainly for testing, to make stable STK as good " +"as possible." +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 +msgid "" +"This version can be installed in parallel with the stable version on the " +"device." +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 +msgid "If you need more stability, consider using the stable version: %s" +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 +msgid "SuperTuxKart Team" +msgstr "SuperTuxKart टीम" diff --git a/data/po/hu.po b/data/po/hu.po index 66541375dfb..5fcc70cdce1 100644 --- a/data/po/hu.po +++ b/data/po/hu.po @@ -12,15 +12,15 @@ # Bangó Máté , 2016 # FIRST AUTHOR , 2010 # Guih48, 2022 -# Guih48, 2022-2023 +# Guih48, 2022-2023,2025 # Viktor Busanszki , 2015 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Guih48, 2022-2023\n" +"Last-Translator: Guih48, 2022-2023,2025\n" "Language-Team: Hungarian (http://app.transifex.com/supertuxkart/supertuxkart/language/hu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -177,7 +177,7 @@ msgstr "A világ végén" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Vissza" @@ -199,7 +199,7 @@ msgstr "Válaszd ki az előnyben részesített irányítás típusát" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Gyorsulásmérő" @@ -213,13 +213,13 @@ msgstr "Gyorsulásmérő" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Giroszkóp" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Kormánykerék" @@ -250,35 +250,37 @@ msgstr "Érintőeszköz beállításai" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Általános" @@ -346,30 +348,33 @@ msgstr "Alapértékek visszatöltése" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Mégse" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Igen" @@ -547,9 +552,9 @@ msgstr "Csatlakozás" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -610,7 +615,7 @@ msgstr "Cél" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Folyamat" @@ -645,7 +650,7 @@ msgstr "Elküldés" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Vissza a versenybe" @@ -662,7 +667,7 @@ msgstr "Vissza a váróba" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Verseny újrakezdése" @@ -726,12 +731,12 @@ msgstr "Írd be a regisztrációkor megadott felhasználónevet és az e-mail c #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Felhasználónév" @@ -772,7 +777,7 @@ msgstr "Nehézség" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Kezdő" @@ -784,7 +789,7 @@ msgstr "Kezdő" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Haladó" @@ -796,7 +801,7 @@ msgstr "Haladó" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Nehéz" @@ -808,7 +813,7 @@ msgstr "Nehéz" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -816,8 +821,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Játékmód" @@ -828,8 +833,8 @@ msgstr "Játékmód" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Normál verseny" @@ -842,7 +847,7 @@ msgstr "Normál verseny" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Időfutam" @@ -850,7 +855,8 @@ msgstr "Időfutam" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Csata" @@ -859,24 +865,24 @@ msgstr "Csata" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Foci" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Jelszó" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Kiszolgáló könyvjelzőzése" @@ -887,7 +893,7 @@ msgstr "Játékos hozzáadása" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Név" @@ -919,7 +925,7 @@ msgstr "Felhasználó-információk" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Ismerős eltávolítása" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -929,17 +935,17 @@ msgstr "Ismerős hozzáadása" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Meghívás elfogadása" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Meghívás visszautasítása" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Profil megtekintése" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -981,6 +987,50 @@ msgstr "Hozzárendelés az ESC billentyűhöz" msgid "Assign nothing" msgstr "Semmi hozzárendelése" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Ajánlott videobeállítások" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Az ajánlott beállítások lesznek alkalmazva a jelenlegi felbontás esetén." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -995,11 +1045,11 @@ msgstr "Versenybeállítások" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Folytatás" @@ -1040,10 +1090,15 @@ msgstr "Arénák" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Telepítve" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1053,20 +1108,20 @@ msgstr "Telepítve" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Szabványos" @@ -1077,12 +1132,12 @@ msgstr "Szabványos" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Bővítmények" @@ -1096,27 +1151,28 @@ msgstr "Bővítmények" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Összes" @@ -1155,9 +1211,9 @@ msgstr "Mozgatás le" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Hozzáadás" @@ -1194,7 +1250,7 @@ msgstr "Szellemvisszajátszás kiválasztása" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Tojásvadászat" @@ -1241,10 +1297,10 @@ msgstr "Megfordítás" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Legtöbb idő (perc)" @@ -1276,9 +1332,9 @@ msgstr "Másolás" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1289,80 +1345,80 @@ msgstr "Átnevezés" msgid "Save Grand Prix" msgstr "Nagydíj mentése" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "SuperTuxKart súgó" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Játékmódok" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Bónuszok" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Banánok" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1370,56 +1426,57 @@ msgstr "Banánok" msgid "Story Mode" msgstr "Történet mód" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Gokart osztályok" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Többszemélyes" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Ismertető indítása" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Gyűjts kék ajándékdobozokat, bónuszokat fognak adni." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Kerüld el a banánokat!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1427,14 +1484,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "A nitró begyűjtése a megfelelő billentyű vagy gomb megnyomásával lehetővé teszi a sebességlöketeket, amikor csak szeretnéd. A nitró aktuális szintjét a verseny képernyőjének jobb alsó sarkán lévő műszeren láthatod." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Ha látsz egy gombot egy ehhez hasonló lakattal, akkor teljesítened kell egy kihívást, hogy kinyisd azt." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1443,34 +1500,34 @@ msgid "" "carefully before!" msgstr "Egy különleges billentyű vagy gomb lenyomásával farolhatsz. Az egymást követő rövid farolások segítenek bevenni az éles kanyarokat, míg a közepes farolások megnövelik a sebességed, a hosszú farolások pedig még inkább növelik azt. Nem tudod megállítani a fordulást farolás közben, szóval figyelj a gokart megfelelő irányba állítására előtte!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Indítási löketet kaphatsz a gyorsítás gomb megnyomásával a „Kész!” elhangzásakor, mielőtt a verseny elindul." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* A jelenlegi billentyűkiosztások a Beállítások menüben tekinthetők meg vagy módosíthatók" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "A SuperTuxKart számos játékmódot nyújt:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Normál verseny: minden csapás megengedett, ezért gyűjts bónuszokat és használd őket okosan!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Időfutam: nem tartalmaz bónuszokat, így csak a vezetési képességek számítanak!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1478,7 +1535,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Kövesd a vezért: fuss a második helyért, mivel az utolsó gokart ki fog esni minden alkalommal, amikor a számláló nullához ér. Vigyázz: a vezér előtt menve te is ki leszel zárva!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1488,30 +1545,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "3 típusú csatamód létezik: a 3-csapásos csatában ki kell ütnöd a többieket a fegyverekkel, amíg el nem veszítik az összes életüket. A mindenki elleni csatában az a játékos nyer, aki a legtöbbször kiüti a többieket egy adott kiütés- vagy időkorlát alatt. A zászló megszerzése módban a csapatodnak el kell hoznia a másik csapat zászlaját a saját zászlóbázisodra, feltéve hogy a saját zászlódat nem szerezte meg a másik csapat." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Foci: a gokart használatával üsd be a labdát a kapuba." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Tojásvadászat: fedezd fel a pályákat, hogy megtaláld az összes rejtett tojást." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Szellemvisszajátszás: versenyezz szellemvisszajátszások ellen időfutam vagy tojásvadászat módban, és rögzítsd a sajátod!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Kör futam: teljesíts minnél több kört a megadott idő alatt." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1520,93 +1577,93 @@ msgid "" "wins the cup." msgstr "* Ezen játékmódok közül a legtöbb játszható nagydíj módban is: ahelyett, hogy egy önálló versenyt futnál, többet is játszhatsz egyhuzamban. Minél jobb a helyezésed, annál több pontot kapsz. A végén a legtöbb pontot elérő játékos nyeri a serleget." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Hogy segítsünk nyerni, van néhány bónusz, amelyeket összegyűjthetsz:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Rágógumi - védd magad egy pajzzsal, vagy használd hátranézéskor egy ragacsos rózsaszín tócsa hátrahagyásához." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Villám – erős sebességlöketet fog adni. De vigyázz, ne veszítsd el az irányítást a gokart felett!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Torta – dobd a legközelebbi ellenfélre, a legjobb rövidtávon és hosszú egyeneseken. A robbanáshoz közeli többi gokartra is hatással van." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "WC-pumpa - dobd el az egyenesben egy ellenfél visszahúzásához, vagy hátranézés közben, hogy eltakard valaki kilátását." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Tekegolyó – egyenesen gurul, amíg ki nem üt valakit. Visszapattanhat a falakról. Ha hátranézel, akkor hátra is gurítható." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Ejtőernyő - lelassítja az összes olyan gokartot, amelyek jobb helyen állnak." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Kicserélő – az ajándékdobozok banánokká, a nitrós kannák rágógumikká változnak egy rövid ideig és fordítva." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Kosárlabda - az első helyen álló után pattog, valamint szétlapíthatja és lelassíthatja az útban lévő gokartokat." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Légycsapó – lecsapja a közelben lévő gokartokat, lelassítva azokat. Használható ejtőernyők és bombák eltávolításához is." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Egy banán elütése azt okozhatja, hogy a következők egyike lesz a gokartra akadva:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Vasmacska – hirtelen lelassítja a gokartot." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Ejtőernyő – fokozatosabban lassítja le a gokartot mint a vasmacska. Minél gyorsabban mész, annál jobban fog lassítani." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bomba – egy kis idő múlva felrobban, és a gokartot a levegőbe repíti. Ütközz egy másik gokarttal, hogy áttedd arra a bombát." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "A gonosz Nolok elrabolta Gnu-t! Itt van néhány tipp, hogy segíts neki:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1615,7 +1672,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Ez az ikon a minitérképen azokat az elérhető kihívásokat jeleníti meg, amelyeket még nem teljesítettél. A képernyő jobb felső sarkában azt is mutatja, hogy jelenleg mennyi pontod van. Teljesíts annyi kihívást, amennyit csak lehetséges, és Nolok bele fog egyezni, hogy versenyezz ellene. Győzz, hogy kiszabadítsd Gnu-t!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1623,20 +1680,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Amikor teljesítesz egy kihívást, akkor kapsz egy serleget. Minden egyes serleg különböző pontot ér. Minél magasabb a teljesített kihívás nehézsége, annál jobb a serleg és annál több pontot ér." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Amikor az ikon alatt jelzett pontszámot eléred, kapsz egy meglepetést. Több is van, amiket összegyűjthetsz." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Nem minden gokartot kell ugyanúgy vezetni! Osztályokba sorolhatók számos különbséggel:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1644,7 +1701,7 @@ msgid "" " resistant to explosions." msgstr "Tömeg – a gokartok három osztálya létezik a tömegüktől függően: könnyű, közepes és nehéz. A nehezebb gokartokra kevésbé hatnak az ejtőernyők és ellenállóbbak a robbanásokkal szemben." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1652,7 +1709,7 @@ msgid "" " especially at low speeds." msgstr "Gyorsulás – különösen hasznos induláskor, egy baleset után vagy a sok éles kanyarral rendelkező pályákon. Minél könnyebb a gokart, annál jobb a gyorsulása, különösen alacsony sebességnél." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1660,14 +1717,14 @@ msgid "" " top speed." msgstr "Végsebesség – minél magasabb, annál gyorsabban tud menni a gokart. Különösen hasznos a hosszú egyeneseket és enyhe kanyarokat tartalmazó pályákon. A nehezebb gokartoknak nagyobb a végsebessége." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Nitróhatásfok – minél magasabb, annál több sebességet kapsz egy kanna nitrótól. Egy könnyebb gokartnak magasabb lesz a nitróhatásfoka." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1675,12 +1732,12 @@ msgid "" "easier it is." msgstr "Ha elég közel követsz egy másik gokartot néhány másodpercig, akkor szélárnyék sebességbónuszt kapsz, amikor megelőzöd. Minél könnyebb a gokartod, ez annál egyszerűbb." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "A SuperTuxKart játszható többszemélyes módban az interneten…:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1690,7 +1747,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Először válaszd az „internet” ikont a főmenüben. Válassz vagy helyi hálózatot vagy globális hálózatot (az internet engedélyezését igényli a beállításokban). Ezután létrehozhatod a saját kiszolgálódat egyéni beállításokkal, vagy kereshetsz a meglévő kiszolgálók között a csatlakozáshoz. Ezek némelyike ajánlott kiszolgáló esetleges rangsorolt versenyekkel." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1700,12 +1757,12 @@ msgid "" "players and the server." msgstr "Egy kiszolgálón egy verseny akkor fog elkezdődni, amikor a (koronával jelzett) tulajdonosa úgy dönt. A hivatalos kiszolgálók csak akkor indíthatják el automatikusan a versenyeket, amikor elegendő játékos van. Ezután választhatod ki a gokartot, és szavazhatsz a következő pályára a versenyzéshez. Kiegészítő pálya csak akkor engedélyezett, ha az létezik az összes csatlakozott játékosnál és a kiszolgálón is." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "...vagy ugyanazon az eszközön:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1715,7 +1772,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Először szükséged lesz néhány bemeneti eszközre. Használd a bemenet beállítása képernyőt a beállításukhoz. Több játékvezérlő vagy botkormány az ideális: a billentyűzeteken minden egyes játékosnak különböző billentyűk szükségesek, és a legtöbb billentyűzet nem megfelelő a többszemélyes játékhoz, mert nem támogatják az egyidejűleg több billentyűlenyomást." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1735,7 +1792,7 @@ msgstr "Legmagasabb pontszám kiválasztás" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Körfutam" @@ -1743,9 +1800,9 @@ msgstr "Körfutam" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Nagydíj" @@ -1756,6 +1813,20 @@ msgstr "Nagydíj" msgid "Choose a Kart" msgstr "Válassz egy gokartot" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1769,11 +1840,11 @@ msgstr "Osztott képernyős többszemélyes" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Internet" @@ -1790,7 +1861,7 @@ msgstr "Ismertető" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Legmagasabb pontszámok" @@ -1798,7 +1869,7 @@ msgstr "Legmagasabb pontszámok" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Teljesítmények" @@ -1852,30 +1923,30 @@ msgstr "Kiszolgáló keresése" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Kiszolgáló létrehozása" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Váró" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Beállítás" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Verseny indítása" @@ -1901,9 +1972,9 @@ msgstr "Kiszolgáló címének megadása" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Saját profil" @@ -1921,7 +1992,7 @@ msgstr "Játékos rangsor" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Ismerősök" @@ -1946,7 +2017,7 @@ msgstr "Gyors játék" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Fiókbeállítások" @@ -1996,8 +2067,8 @@ msgid "Online Username" msgstr "Internetes felhasználónév" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Jelszó visszaállítása" @@ -2010,7 +2081,7 @@ msgid "" msgstr "" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Kiszolgálóválasztás" @@ -2028,339 +2099,409 @@ msgstr "IPv6 kapcsolat használata" msgid "User search" msgstr "Felhasználókeresés" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "SuperTuxKart beállítások" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Grafika" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Hang" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Felület" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Játékosok" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Irányítás" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Nyelv" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Zene" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Engedélyezve" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Hangerő" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Hanghatások" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Beállítás törlése" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Beállítás letiltása" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Vissza az eszközlistához" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Beállítás átnevezése" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Erővisszacsatolás engedélyezése (ha támogatott)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Felbontás" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Teljes képernyő" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Ablakpozíció megjegyzése" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Új felbontás alkalmazása" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Osztott képernyős többszemélyes elrendezés" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Internetbeállítások" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Mindig jelenjen meg a bejelentkező képernyő" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Csatlakozás az Internethez" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Internetes csevegés engedélyezése" +msgid "Enable chatting in online lobbies" +msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Csevegés engedélyezése az internetes játékokban" +msgid "Enable chatting in online matches" +msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Egyéb beállítások" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Játékosonkénti hátrányok engedélyezése" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Teljes játékelemek eltávolítása" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Nyomj entert vagy kattints duplán egy eszközödön annak beállításához" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Eszköz hozzáadása" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Mely használandó beállítások legyenek magukkal hozva abból, hogy mely „Kiválasztás” gombot nyomják meg a játékhoz való csatlakozáshoz." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Megjelenés" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Minitérkép" +msgid "Skin variant" +msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Osztott képernyős többszemélyes elrendezés" +msgid "Minimap" +msgstr "Minitérkép" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Betűméret" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Kamera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Egyéni…" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "FPS (képkocka/másodperc) megjelenítése" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Más gokartok viselt bónuszainak megjelenítése" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "A történet mód időmérőjének engedélyezése" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "A gyors végigjátszás időmérőjének engedélyezése" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Megjelenítési felbontás" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Grafikai hatások szintje" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Elmosási hatások szintje" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Legnagyobb FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Egyéni beállítások…" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Felbontás" +msgid "Performance tests" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Teljes képernyő" +msgid "Performance test of the current settings" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Ablakpozíció megjegyzése" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Jelszó megjegyzése" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Új felbontás alkalmazása" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Törlés" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Gokart színe" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2387,15 +2528,15 @@ msgstr "Kék csapat" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Körök száma" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Számítógépes gokartok száma" @@ -2410,33 +2551,17 @@ msgstr "Kék csapat számítógépes gokartjainak száma" msgid "Random Grand Prix" msgstr "Véletlen nagydíj" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Belépés" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Jelszó megjegyzése" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Törlés" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Gokart színe" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "A felhasználói felület megjelenése a felhasználói felület beállításaiban változtatható meg." @@ -2555,238 +2680,306 @@ msgid "" msgstr "Ne állj a labdát vivő csapattársad útjába, habár megpróbálhatod eltalálni azokat az ellenfeleket, akik megpróbálják megakadályozni őt a pontszerzésben." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Özönvíz előtti szakadék" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Idegen jel" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Ősi kolosszeum labirintusa" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Candela város" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Csata sziget" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Fekete erdő" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "X barlang" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Kakaótemplom" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Kukoricamező átkelés" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Magma erőd" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Nagy Paradicsom sziget" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Farm" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Jeges focipálya" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Mi a baj, ti kis hippik? A hatalmas gnú vezetőtök hiányzik?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Ó, igen, most már a kastélyomban van, és fel lesz szolgálva vacsorára…" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "De én becsületes lény vagyok, ezért alkut fogok ajánlani." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Ha le tudsz győzni versenyzésben, akkor el fogom engedni az öreg pasast." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "De ti szánalmas kis hitvány fráterek soha nem lesztek képesek legyőzni engem - a gokartok királyát!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "A dűnék arénája" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "A dűnék focistadion" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "A világítótorony körül" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Régi bánya" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oázis" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Olivér matek osztálya" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Sütőtök park" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Hollóhíd kúria" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Futóhomok" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Nessie tavacskája" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Északi menedékhely" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Havas csúcs" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Focipálya" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "A stadion" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Enterprise" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Templom" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Vulkán sziget" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Japán sziklakert" @@ -2795,11 +2988,11 @@ msgstr "Japán sziklakert" msgid "Completed achievement \"%s\"." msgstr "Befejezett teljesítmény: „%s”." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Nem sikerült a SuperTuxKart kiegészítő-kiszolgálóhoz való kapcsolódás." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Hiba a hírek letöltésekor: „%s”." @@ -2865,7 +3058,7 @@ msgid "New kart '%s' now available" msgstr "Az új „%s” gokart mostantól elérhető" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2897,32 +3090,32 @@ msgid "" "created." msgstr "A beállítófájlod túl régi volt, ezért törölve lett, és egy új került létrehozásra." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Videórögzítés elindítva." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Videó elmentve ide: „%s”" -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Kódolási folyamat:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Tipp: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Betöltés" @@ -2944,19 +3137,18 @@ msgstr "Nitróhatékonyság" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (hátrányban van)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s kész" @@ -3430,21 +3622,21 @@ msgid "Axis %d" msgstr "%d. tengely" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "%d. játékvezérlő gomb" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "%d. egérgomb" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "%d. %s egértengely" @@ -3616,26 +3808,30 @@ msgstr "Legfeljebb 3 életed lehet!" msgid "+1 life." msgstr "+1 élet." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Túl lassú voltál!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Megnyerted a versenyt!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "%d. helyen fejezted be a versenyt!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s kilépett a játékból." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3644,16 +3840,16 @@ msgid "" "Internet\")." msgstr "A SuperTuxKart csatlakozhat egy kiszolgálóhoz kiegészítők letöltéséhez, és a értesít a frissítésekről. Olvasd el az adatvédelmi irányelveinket a https://supertuxkart.net/Privacy angol nyelvű oldalon. Szeretnéd ezt a szolgáltatást engedélyezni? (Ezen beállítás későbbi megváltoztatásához menj a beállításokhoz, válaszd az „Általános” lapot, és szerkeszd a „Csatlakozás az Internethez” beállítást)." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "A képernyőfelbontásod túl alacsony az STK futtatásához." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Az illesztőprogramod verziója túl régi. Kérlek telepítsd a legfrissebb videokártya illesztőprogramokat." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3661,38 +3857,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "A grafikus illesztőprogramod nagyon réginek tűnik. Nézd meg, hogy van-e elérhető frissítés. A SuperTuxKart olyan illesztőprogramot javasol, amely %s vagy jobb támogatással rendelkezik. A játék valószínűleg még futni fog, de csak csökkentett grafikus módban." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "A kiszolgáló-kapcsolat túllépte az időkorlátot." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s megszerezte a piros zászlót!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "A piros zászló visszakerült!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s megszerezte a kék zászlót!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "A kék zászló visszakerült!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s elrabolta a kék zászlót!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s elrabolta a piros zászlót!" @@ -3702,7 +3898,7 @@ msgstr "%s elrabolta a piros zászlót!" msgid "Eggs: %d / %d" msgstr "Tojások: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Vezér" @@ -3710,22 +3906,22 @@ msgstr "Vezér" msgid "Final lap!" msgstr "Utolsó kör!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "%i. kör" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s - %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Új leggyorsabb kör" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "ROSSZ IRÁNY!" @@ -3739,194 +3935,194 @@ msgstr "%s gólt lőtt!" msgid "Oops, %s made an own goal!" msgstr "Hoppá, %s öngólt lőtt!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "%i pótkerék gokart jelent meg!" msgstr[1] "%i pótkerék gokart jelent meg!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Kizártak a versenyből!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "„%s” kizárva." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "A kiszolgáló le lett állítva." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Kidobtak a kiszolgálóról." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Ki lettél rúgva: a ping túl nagy." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Rossz hálózati kapcsolat észlelhető." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Robot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s leszakadt." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Nyomj rá a játékos nevére a listában a játékoskezeléshez és a rangsor-információkhoz." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Nehézség: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Legtöbb játékos: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Játékmód: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Időkorlát" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Gól korlát" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Foci játéktípus: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Nagydíj állapota: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Az összes játékos csatlakozott a piros vagy a kék csapathoz." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Most te vagy a kiszolgáló tulajdonosa." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Kapcsolódás elutasítva: a kiszolgáló foglalt." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Kapcsolódás elutasítva: kitiltottak a kiszolgálóról." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Kapcsolódás elutasítva: a kiszolgáló jelszava helytelen." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Kapcsolódás elutasítva: a játékadatok nem megfelelőek." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Kapcsolódás elutasítva: a kiszolgáló megtelt." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Kapcsolódás elutasítva: érvénytelen játékos kapcsolódás." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Nem sikerült elindítani a hálózati játékot." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "A játék befejeződött, nem tudsz azonnal csatlakozni vagy megfigyelni többé." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Nincs több hely az arénában – az azonnali csatlakozás le van tiltva." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Csak 1 játékos van hátra, visszatérés a váróba." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "A kiszolgáló tulajdonosa kilépett a játékból." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "A következő játékban megfigyelőként veszel részt." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s csatlakozott a piros csapathoz." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s csatlakozott a kék csapathoz." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s csatlakozott a játékhoz." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3934,15 +4130,15 @@ msgid "" msgstr "Nyomd meg a(z) <%s> vagy <%s> gombot a célba vett játékos módosításához, és a(z) <%s> vagy <%s> gombot a kamera pozíciójának megváltoztatásához." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "%s sikeresen jelentve." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3973,38 +4169,38 @@ msgstr "Időfutam (nagydíj)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Mindenki ellen" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Zászló megszerzése" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s mostantól elérhető." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s és %s mostantól elérhető." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s és %s mostantól elérhető." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4012,19 +4208,19 @@ msgstr[0] "%d ismerős mostantól elérhető." msgstr[1] "%d ismerős mostantól elérhető." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s most a következő kiszolgálón van: „%s”." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "%d új ismerőskérésed van!" msgstr[1] "%d új ismerőskérésed van!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Új ismerőskérésed van!" @@ -4053,12 +4249,12 @@ msgid "" msgstr "A ranglista fájl túl régi volt,\naz összes ranglista törölve lett." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Kövesd a vezért" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "3-csapásos csata" @@ -4071,91 +4267,88 @@ msgstr "Befejezetlen visszajátszási fájl nem lesz elmentve." msgid "Replay saved in \"%s\"." msgstr "Visszajátszás elmentve ide: „%s”." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 hét" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 hét" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 hónap" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 hónap" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 hónap" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 hónap" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 év" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 év" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Kiegészítő neve" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Frissítési dátum" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Nincs telepítve" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s - %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Kérlek várj, amíg a kiegészítők frissítésre kerülnek" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Sajnos egy hiba történt a kiegészítők oldalának elérése közben. Ellenőrizd, hogy csatlakoztál-e az Internethez, és hogy a tűzfal nem blokkolja-e a SuperTuxKart programot." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Zárolt: teljesítsd az aktív kihívásokat, hogy a többihez is hozzáférj!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Véletlenszerű aréna" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d aréna nem érhető el egyszemélyes módban." -msgstr[1] "%d aréna nem érhető el egyszemélyes módban." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nBalázs Meskó, 2019\nBalázs Meskó, 2019,2021\nBalázs Úr, 2019\nBalázs Úr, 2019-2022\nBalázs Úr, 2018-2019\nBalázs Úr, 2016-2018\nBangó Máté, 2016\nGuih48, 2022\nViktor Busanszki, 2015\nBusanszki Viktor, 2015\nGyönki Bendegúz\nMeskó Balázs, 2019-2022\nMolditz György\nPapp Bence\nÚr Balázs, 2016-2022" @@ -4443,7 +4636,7 @@ msgstr "Összegyűjtött banánok" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Farolás" @@ -4546,7 +4739,7 @@ msgstr "Tojásvadászatok befejezve" msgid " (official tracks matching the goal)" msgstr " (a célnak megfelelő hivatalos pályák)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4554,91 +4747,95 @@ msgid "" msgstr "Az új játékvezérlők és botkormányok automatikusan meg fognak jelenni a listában, ha csatlakoztatod azokat ehhez az eszközhöz.\n\nEgy billentyűzetbeállítás hozzáadásához használhatod a lenti gombokat, AZONBAN ne feledd, hogy a legtöbb billentyűzet csak egyidejűleg korlátozott mennyiségű billentyű lenyomását támogatja, és emiatt nem alkalmasak többszemélyes játékhoz. (Azonban csatlakoztathatsz több billentyűzetet is ehhez az eszközhöz. Ne feledd, hogy ebben az esetben továbbra is mindenkinek különböző billentyűzettársításokra van szüksége.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Wiimote hozzáadása" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Billentyűzetbeállítás hozzáadása" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Frissítés" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Verzió: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "ajánlott" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Méret: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Sajnálom, a kiegészítő letöltése nem sikerült" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Probléma lépett fel az új „%s” kiegészítő telepítésekor." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Próbáld újra" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Probléma lépett fel a meglévő „%s” kiegészítő eltávolításakor." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "A letöltés a háttérben befejeződött." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Letöltés a háttérben" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "A letöltés a háttérben már elindult." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "A jelenlegi jelszó érvénytelen." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "A jelszónak 8 és 30 karakter közötti hosszúnak kell lennie!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "A jelszavak nem egyeznek!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Információk ellenőrzése" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "A jelszó sikeresen megváltoztatva." @@ -4659,67 +4856,97 @@ msgstr "Az 1024×768 vagy 1280×720 képpontnál kisebb felbontások nem támoga #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Drónvadászat" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Egyéni" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Letiltva" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Csak fontosak" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Nagyon alacsony" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Alacsony" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Közepes" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Magas" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4727,7 +4954,7 @@ msgid "" msgstr "A SuperTuxKart program le fogja tölteni a teljes adatelemet (beleértve a jó minőségű textúrákat és zenét) a jobb játékélményhez. Ez a mobil adatforgalmadat fogja használni, ha nincs Wi-Fi kapcsolatod." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4744,101 +4971,102 @@ msgstr "Add meg a kiszolgáló címét és esetlegesen kettősponttal elválaszt msgid "Invalid server address: %s." msgstr "Érvénytelen kiszolgálócím: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Fordítva" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Nehézség" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Körök" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Idő" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Gokart" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Felhasználó" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Verzió" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Nem" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Pálya" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Legjobb %d legmagasabb pontszám" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Gokartok száma: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Célidő: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Kör: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Fordított: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Üres)" @@ -4926,33 +5154,41 @@ msgid "Press any key..." msgstr "Nyomj meg egy billentyűt…" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "A csevegés le van tiltva, engedélyezd a beállítások menüben." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Vissza a csatába" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Új játék beállítása" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Csata újrakezdése" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Kilépés a csatából" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Új verseny beállítása" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Verseny elhagyása" @@ -4968,11 +5204,11 @@ msgstr "%s még nincs rangsorolva." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s %d. helyen áll a rangsorban %f pontszámmal." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "A felhasználónév és/vagy az e-mail cím érvénytelen." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4994,7 +5230,7 @@ msgstr "Szellemvisszajátszás verseny" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Kör: %i" @@ -5007,21 +5243,21 @@ msgstr "Típus: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Szükséges helyezés: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Szükséges idő: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Szükséges nitrópontok: %i" @@ -5034,54 +5270,54 @@ msgstr "Számítógépes gokartok száma: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Csata mód" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Foci játéktípus" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Kiszolgáló helye: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Jelenlegi pálya: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Helyezés" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Játékos" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Pontok" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Játékkal töltött idő" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Eltávolítás a könyvjelzők közül" @@ -5094,74 +5330,74 @@ msgid "No player available for connecting to server." msgstr "Nincs elérhető játékos a kiszolgálóhoz való kapcsolódáshoz." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Felhasználónév: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Kérés megszakítása" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Ma" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Ismerőskérés elküldve!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Ismerőskérés elfogadva!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Ismerőskérés elutasítva!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Ismerős eltávolítva!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Ismerőskérés megszakítva!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Feldolgozás" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Utolsó szavazás lekérése" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Alkalmazhatod az előző értékelésed az alatta lévő csillagokra kattintva." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Még nem szavaztál erre a kiegészítőre. Válaszd ki a kívánt értékelésed az alatta lévő csillagokra kattintva." -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Sikeres szavazás! Most már bezárhatod az ablakot." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Szavazás végrehajtása" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Véletlen pálya" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5190,7 +5426,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Hiba történt a nagydíj mentésének kísérlete közben." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Válassz egy pályát" @@ -5234,12 +5470,12 @@ msgstr "Feloldottad ezt a pályát: %0" msgid "You unlocked grand prix %0" msgstr "Feloldottad ezt a nagydíjat: %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Pálya" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5260,19 +5496,19 @@ msgstr "Írd be a nagydíj nevét" msgid "Please select a Grand Prix" msgstr "Kérlek válassz egy nagydíjat" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Felhasználó által megadott" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "A név üres." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Ezzel a névvel már létezik egy másik nagydíj." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "A név túl hosszú." @@ -5281,19 +5517,19 @@ msgstr "A név túl hosszú." msgid "Better luck next time!" msgstr "Több szerencsét legközelebb!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Teljesítettél egy kihívást!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Megnyerted a nagydíjat!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Teljesítetted a nagydíjat!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Gokartok száma" @@ -5306,110 +5542,125 @@ msgstr "Biztosan el szeretnéd távolítani ezt a legmagasabb pontszám bejegyz msgid "Are you sure you want to remove all of your high scores?" msgstr "Biztosan el szeretnéd távolítani az összes legmagasabb pontszámod?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Osztott képernyős többszemélyes játékhoz csatlakoztass egy billentyűzetet vagy játékvezérlőt" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Véletlen gokart" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Zárolt" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Mindenki:\nNyomd meg a „kiválasztás\" gombot a csatlakozáshoz" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Szeretnél játszani a játék ismertetőjével?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Nem játszhatsz az interneten internet-hozzáférés nélkül. Ha az interneten szeretnél játszani, akkor menj a beállítások menübe, és jelöld be a „Kapcsolódás az internethez” négyzetet." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Nem tölthetsz le kiegészítőket internet-hozzáférés nélkül. Ha kiegészítőket szeretnél letölteni, akkor menj a beállítások menübe, és jelöld be a „Kapcsolódás az internethez” négyzetet." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Nem tölthetsz le kiegészítőket internet-hozzáférés nélkül. Ha kiegészítőket szeretnél letölteni, akkor menj a beállítások menübe, és jelöld be a „Kapcsolódás az internethez” négyzetet.\n\nAzonban törölheted a már letöltött kiegészítőket." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "A kiegészítők modul jelenleg le van tiltva a beállítások képernyőn" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Kérlek várj, amíg a kiegészítők betöltődnek" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Biztosan ki szeretnél lépni az STK játékból?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "LAN kiszolgáló létrehozása" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "%s kiszolgálója" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Nagydíj pályák száma" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "A névnek 4 és 30 karakter közötti hosszúnak kell lennie!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Helytelen karakterek a jelszóban!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Kész" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Azonnali csatlakozás" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Megfigyelés" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Kiegészítő telepítése" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5417,7 +5668,7 @@ msgstr "Várj a jelenlegi játék (%s) befejezésére. A becsült hátralévő i #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Várj a jelenlegi játék befejezésére. A becsült hátralévő idő: %s." @@ -5425,24 +5676,24 @@ msgstr "Várj a jelenlegi játék befejezésére. A becsült hátralévő idő: #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Várj a jelenlegi játék (%s) befejezésére. A becsült állapot: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Várj a jelenlegi játék befejezésére. A becsült állapot: %d%. " #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Várj a jelenlegi játék befejezésére." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5451,7 +5702,7 @@ msgstr[1] "A játék akkor indul, ha több mint %d játékos van." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5460,96 +5711,108 @@ msgid_plural "" msgstr[0] "Indítás %d másodperc múlva, vagy amikor mindenki megnyomta a „Kész” gombot." msgstr[1] "Indítás %d másodperc múlva, vagy amikor mindenki megnyomta a „Kész” gombot." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Kapcsolódás a kiszolgálóhoz: %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Gyors játékú kiszolgáló keresése" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Hátralévő idő: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Célok" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Teljesítmények lekérése" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "%s profilja" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Mióta:" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Állapot" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Ismerősök lekérése" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Új kérés" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Függőben" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Kilépett" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Adj meg új e-mail-címet lent" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Az új e-mail-címnek 5 és 254 karakter közötti hosszúnak kell lennie!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Az új e-mail-cím érvénytelen!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "Az e-mail-cím megváltozott!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Az e-mail-cím megváltoztatása sikertelen: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Be kell jelentkezned a globális hálózati játékhoz. Kattints a felhasználónevedre fent." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Keresés" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Kilépés a játékból" @@ -5627,34 +5890,34 @@ msgid "Distance (km)" msgstr "Távolság (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Ismeretlen" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Nem észlelhető IPv4, ezért lehet, hogy nem tudsz csatlakozni semmilyen kiszolgálóhoz." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Nem észlelhető IPv6, ezért lehet, hogy nem tudsz csatlakozni semmilyen kiszolgálóhoz." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Nincs elérhető kiszolgáló." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Kiszolgálók lekérése" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Kiszolgáló-könyvjelzők" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5662,149 +5925,149 @@ msgstr "Ha a játékosok többsége mind ugyanazt a pályát és versenybeállí #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Véletlenszerű elemelhelyezés" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Célok száma a nyeréshez" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Fordítva vezetés" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Zárolt: " -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Művelet" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Billentyűparancs" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Eszköz letiltása" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Eszköz engedélyezése" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Beállítás engedélyezése" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Játék billentyűk" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Menü billentyűk" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Balra fordulás" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Jobbra fordulás" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Gyorsítás" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Fékezés / megfordítás" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Tüzelés" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitró" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Hátranézés" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Kimentés" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Játék szüneteltetése" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Fel" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Le" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Balra" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Jobbra" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Kiválasztás" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Mégse / vissza" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* A kék elem ütközést jelent egy másik beállítással" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* A piros elem ütközést jelent a jelenlegi beállításban" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5812,17 +6075,27 @@ msgid "" msgstr "Figyelmeztetés: A „Shift” nem ajánlott billentyű. Amikor a „Shift” le van nyomva, akkor egyik olyan karaktert tartalmazó billentyű sem fog működni, amely eltérő nagybetűként." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Biztosan véglegesen törölni szeretnéd ezt a beállítást?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Add meg az új beállítás nevét, vagy hagyd üresen az alapértelmezett érték visszaállításához." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Függőleges" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Vízszintes" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5830,89 +6103,74 @@ msgstr "Többszemélyes módban a játékosok választhatnak hátránnyal\nindul #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Teljes játékelemek telepítése" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Biztosan eltávolítod a teljes játékelemeket?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "%i. billentyűzet" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Érintőeszköz" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Koppints egy eszközre annak beállításához" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Rendszer nyelve" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Bal alul" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "A jobb oldalon" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Rejtett" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Középre igazított" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Függőleges" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Vízszintes" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Nagyon kicsi" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Kicsi" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Közepes" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Nagy" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Nagyon nagy" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5922,128 +6180,133 @@ msgid "" msgstr "A gyors végigjátszás módot csak akkor lehet engedélyezni, ha a játék nem lett bezárva a történet mód indítása óta.\n\nA játék bezárása a történet mód befejezése előtt érvényteleníti az időmérőt.\n\nA gyors végigjátszás mód használatához használj új profilt." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Függőleges szinkronizáció" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "A vsync arra kényszeríti a grafikus kártyát, hogy csak akkor\nadjon új képkockát, ha a monitor kész megjeleníteni azt." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "A vsync nem fog működni, ha az illesztőprogramok nem támogatják." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Részecske hatások: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Animált karakterek: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Dinamikus fények: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Fény szóródás: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Élsimítás: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Környezeti árnyékolás: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Árnyékok: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Árnyékok: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Ragyogás: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Ragyogás (körvonalak): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Fénysugarak (napsugarak): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Megjelenített képminőség: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Elmosás: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Mélységélesség: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Az internet-hozzáférés le van tiltva. Szeretnéd engedélyezni?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Meg kell adnod egy jelszót." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Kijelentkezés: „%s”" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Bejelentkezés: „%s”" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Nem törölheted az egyetlen játékost." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Valóban törölni szeretnéd „%s” játékost?" @@ -6071,7 +6334,7 @@ msgstr "GÓL!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Várakozás a többiekre" @@ -6106,7 +6369,7 @@ msgstr "Kövesd a vezért!" msgid "Top %i" msgstr "Legjobb %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Kihívás sikertelen" @@ -6130,102 +6393,199 @@ msgstr "Nyomd meg a dobogó ikont a kihívás indításához" msgid "Press fire to start the challenge" msgstr "Nyomd meg a tüzelést a kihívás indításához" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Kilépés a kiszolgálóról" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Nagydíj megszakítása" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Újrakezdés" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Vissza a kihívásválasztóhoz" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Verseny az új szellemvisszajátszás ellen" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Vissza a menübe" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Valóban meg szeretnéd szakítani a nagydíjat?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "A piros csapat nyert" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "A kék csapat nyert" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Döntetlen" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "%s után kieesett" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Kizárva" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Öngól)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "%i/%i pálya" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "A nagydíj állása:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Dicsőségtábla" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Legjobb köridő: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "– %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Teljesítetted a kihívást!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Elvesztetted a kihívást!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Elérted SuperTux követelményeit" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Az összes csapás megengedett, úgyhogy vedd fel a fegyvereket, és használd okosan azokat!" @@ -6266,28 +6626,28 @@ msgstr "Nyomd meg a piros vagy a kék foci ikont a csapat megváltoztatásához" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "A pálya készítője: %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Támogatott legtöbb játékos: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Piros csapat számítógépes gokartjainak száma" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Nem játszhatsz ezen a nagydíjon, mert olyan pályákat tartalmaz, melyek még nem érhetők el!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Zárolt!" @@ -6309,10 +6669,12 @@ msgid "%d/%m/%Y" msgstr "%Y-%m-%d" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Teljesítsd az összes kihívást a nagy ajtó kinyitásához!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6321,41 +6683,48 @@ msgid "" msgstr "Több pontra van szükséged,\nhogy elfogadhasd a kihívást!\nNézd meg a minitérképet az\nelérhető kihívásokért." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Gyorsítás: <%s>, illetve kanyarodás: <%s> és <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Gyorsítás a kerék felső részének megérintésével, és kanyarodás balra vagy jobbra mozgatással." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Gyorsítás a gyorsító felfelé mozgatásával, és kanyarodás az eszköz billentésével." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Gyorsítás a gyorsító felfelé mozgatásával, és kanyarodás az eszköz forgatásával." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Gyűjts ajándékdobozokat, és a dobozok ellökéséhez tüzelj a fegyverrel: <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Gyűjts ajándékdobozokat, és tüzelj a tekegolyó ikon megnyomásával a dobozok ellökéséhez!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6363,34 +6732,41 @@ msgid "" msgstr "Nézz hátra ennek megnyomásával: <%s>.\nTüzelj a fegyverrel magad mögé! Nyomd meg: <%s>, miközben ezt is nyomva tartod: <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Nyomd meg a tükör ikont a hátranézéshez.\nTüzelj a fegyverrel hátra a tükör ikon nyomva tartásával és utána a tekegolyó ikonra pöccintve!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Használd az összegyűjtött nitrót, nyomd meg ezt: <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Használd az összegyűjtött nitrót a nitró ikon megnyomásával" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Gyűjts nitrós kannákat (a kanyar után fogjuk használni)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Hoppá! Amikor bajban vagy, nyomd meg ezt a kimentéshez: <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Hoppá! Amikor bajban vagy, nyomd meg a madár ikont a kimentéshez." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6398,24 +6774,27 @@ msgid "" msgstr "A faroláshoz gyorsíts, és kanyarodás közben nyomd meg ezt: <%s>.\nEgy rövid ideig farolva gyorsabban beveheted az éles kanyarokat." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "A faroláshoz gyorsíts, és kanyarodás közben nyomd meg a csúszás ikont.\nEgy rövid ideig farolva gyorsabban beveheted az éles kanyarokat." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Ne feledd, hogy ha sikerül farolni néhány másodpercig, akkor egy bónusz sebességlöketet fogsz kapni jutalmul!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Most már készen állsz a versenyzésre. Sok szerencsét!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Egy 3D-s, nyílt forráskódú gokartverseny játék" @@ -6425,7 +6804,7 @@ msgstr "Egy 3D-s, nyílt forráskódú gokartverseny játék" msgid "tux;game;race;" msgstr "tux;játék;verseny;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6433,7 +6812,7 @@ msgid "" "for all ages." msgstr "Gokartok. Nitró. Akcíó! A SuperTuxKart egy 3D-s, nyílt forráskódú versenyjáték számos karakterrel, pályával és játékmóddal. A célunk, hogy a játék szórakoztatóbb legyen, mintsem valósághű, és szórakoztató élményt nyújtson minden korosztálynak." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6442,7 +6821,7 @@ msgid "" "your opponents." msgstr "Számos pályánk van különböző témával, amelyet élvezhetnek a játékosok: vezetés a víz alatt, egy vidéki gazdaságban, a dzsungelben vagy akár akár a világűrben! Próbáld elkerülni a többi gokartot, mert leelőzhetnek, de ne edd meg a banánokat! Figyelj az ellenfelek által kilőtt tekegolyókra, WC-pumpákra, rágógumikra és tortákra. " -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6451,27 +6830,27 @@ msgid "" "your racing skills!" msgstr "Versenyezhetsz más gokartokkal különálló futamokon, részt vehetsz nagydíjakon, megpróbálhatod egyedül elérni a legjobb köridőt, játszhatsz csata módban a számítógép ellen vagy barátokkal, és még sok mást! A nagyobb kihíváshoz csatlakozz az internetre, találkozz játékosokkal a világ minden tájáról, és mutasd meg a vezetési képességeidet!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "A játékban nincsenek reklámok." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Ez a SuperTuxKart nem stabil verziója, amely a legújabb fejlesztéseket tartalmazza. Főként tesztelési céllal lett kiadva, hogy a stabil SuperTuxKart a lehető legjobb legyen." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Ezt a verziót az eszközön lévő stabil verzió mellé is lehet telepíteni." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Ha nagyobb stabilitásra van szükséged, akkor fontold meg a stabil verzió használatát: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "A SuperTuxKart csapat" diff --git a/data/po/is.po b/data/po/is.po index f3550d4373a..1c2bed549d9 100644 --- a/data/po/is.po +++ b/data/po/is.po @@ -11,7 +11,7 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" "Last-Translator: Tómas Helgason, 2024\n" "Language-Team: Icelandic (http://app.transifex.com/supertuxkart/supertuxkart/language/is/)\n" @@ -31,7 +31,7 @@ msgstr "Villa kom upp við útdrátt á leikjagögnum" #. I18N: In Android UI, po_extract_error_msg msgid "Check remaining device space or reinstall SuperTuxKart." -msgstr "Skoðaðu laust Geymslurými eftir eða endursettu SuperTuxKart." +msgstr "Skoðaðu laust Geymslurými eftir eða endursettu SúperTuxKart." #. I18N: In Android UI, po_quit #. I18N: ./data/gui/screens/main_menu.stkgui @@ -141,7 +141,7 @@ msgstr "Handan heppni" msgid "" "Win 10 single races in a row in Expert or SuperTux against at least 5 AIs. " "Beware, restarting a race counts as a loss." -msgstr "Sigraðu 10 stakar keppnir í röð á móti að minnsta kosti 5 Gervigreindum á Erfitt eða SuperTux Erfiðleikastigi. Hafðu í huga að endurtökur á keppnum tells sem tap. " +msgstr "Sigraðu 10 stakar keppnir í röð á móti að minnsta kosti 5 Gervigreindum á Erfitt eða SúperTux Erfiðleikastigi. Hafðu í huga að endurtökur á keppnum tells sem tap. " #. I18N: ./data/grandprix/1_penguinplayground.grandprix msgid "Penguin Playground" @@ -170,7 +170,7 @@ msgstr "Á enda heimsins" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Til baka" @@ -192,7 +192,7 @@ msgstr "Veldu tengund af fjarstýringu sem þú hyggist" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Hröðunarmælir" @@ -206,13 +206,13 @@ msgstr "Hröðunarmælir" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Gyroscope" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Stýrihjól" @@ -243,35 +243,37 @@ msgstr "Snertitækja Stillingar" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Almennt" @@ -339,30 +341,33 @@ msgstr "Endurheimtu sjálgefnar breytur" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Hætta við" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Já" @@ -408,111 +413,111 @@ msgstr "Horn" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "Smooth camera" -msgstr "" +msgstr "Slétt myndavél" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera settings msgid "Backward camera" -msgstr "" +msgstr "Öfug myndavél" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "Follow ball in soccer mode" -msgstr "" +msgstr "Fylgdu boltanum í fótboltahami" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "Reset" -msgstr "" +msgstr "Núllstilla" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui msgid "Graphics Settings" -msgstr "" +msgstr "Grafíkstillingar" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Advanced pipeline (lights, etc.)" -msgstr "" +msgstr "Ítarleg leiðsla (ljós osfrv.)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Shadows" -msgstr "" +msgstr "Skuggar" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Bloom" -msgstr "" +msgstr "Blómi" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Light shaft (God rays)" -msgstr "" +msgstr "Ljósskaft (Geislar)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Ambient occlusion" -msgstr "" +msgstr "Umhverfis hylling" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Depth of field" -msgstr "" +msgstr "Dýpt sjónsvið" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Glow (Outlines)" -msgstr "" +msgstr "Ljómi (Útlínur)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Anti-aliasing" -msgstr "" +msgstr "Anti-aliasing" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Motion blur" -msgstr "" +msgstr "Hreyfiþoka" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Image-based lighting" -msgstr "" +msgstr "Myndbundin lýsing" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Light Scattering" -msgstr "" +msgstr "Ljós dreifing" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Animated characters" -msgstr "" +msgstr "Ljóslifandi persónur" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Texture compression" -msgstr "" +msgstr "Áferð þjöppun" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Particle effects" -msgstr "" +msgstr "Agnaráhrif" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Rendered image quality" -msgstr "" +msgstr "Útgefin myndgæði" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Geometry detail" -msgstr "" +msgstr "Upplýsingar um rúmfræði" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "* Restart STK to apply new settings" -msgstr "" +msgstr "* Endurræstu STK til að beita nýjum stillingum" #. I18N: ./data/gui/dialogs/debug_slider.stkgui #. I18N: ./data/gui/dialogs/online/recovery_info.stkgui @@ -520,14 +525,14 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Close" -msgstr "" +msgstr "Loka" #. I18N: ./data/gui/dialogs/enter_address_dialog.stkgui #. I18N: In the enter address dialog #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog msgid "Join" -msgstr "" +msgstr "Taka þátt" #. I18N: ./data/gui/dialogs/general_text_field_dialog.stkgui #. I18N: In the general textfield dialog @@ -540,22 +545,22 @@ msgstr "" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:143 msgid "OK" -msgstr "" +msgstr "Ókey" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info action #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen msgid "Record the race for ghost replay" -msgstr "" +msgstr "Taktu upp keppnina fyrir drauga endurspilum" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info action @@ -603,7 +608,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "" @@ -638,7 +643,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "" @@ -655,7 +660,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "" @@ -719,12 +724,12 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "" @@ -765,7 +770,7 @@ msgstr "" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Létt" @@ -777,7 +782,7 @@ msgstr "Létt" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Venjulegt" @@ -789,7 +794,7 @@ msgstr "Venjulegt" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Erfitt" @@ -801,16 +806,16 @@ msgstr "Erfitt" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" -msgstr "" +msgstr "SúperTux" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "" @@ -821,8 +826,8 @@ msgstr "" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "" @@ -835,7 +840,7 @@ msgstr "" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "" @@ -843,7 +848,8 @@ msgstr "" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "" @@ -852,24 +858,24 @@ msgstr "" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "" @@ -880,7 +886,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "" @@ -974,6 +980,50 @@ msgstr "" msgid "Assign nothing" msgstr "" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -988,11 +1038,11 @@ msgstr "" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "" @@ -1033,10 +1083,15 @@ msgstr "" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1046,20 +1101,20 @@ msgstr "" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "" @@ -1070,12 +1125,12 @@ msgstr "" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Bætingar" @@ -1089,27 +1144,28 @@ msgstr "Bætingar" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Allt" @@ -1148,9 +1204,9 @@ msgstr "" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "" @@ -1187,7 +1243,7 @@ msgstr "" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "" @@ -1234,10 +1290,10 @@ msgstr "" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "" @@ -1269,9 +1325,9 @@ msgstr "" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1282,80 +1338,80 @@ msgstr "" msgid "Save Grand Prix" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1363,56 +1419,57 @@ msgstr "" msgid "Story Mode" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1420,14 +1477,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1436,34 +1493,34 @@ msgid "" "carefully before!" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1471,7 +1528,7 @@ msgid "" " leader will get you eliminated too!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1481,30 +1538,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1513,93 +1570,93 @@ msgid "" "wins the cup." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1608,7 +1665,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1616,20 +1673,20 @@ msgid "" " the cup and the more points it is worth." msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1637,7 +1694,7 @@ msgid "" " resistant to explosions." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1645,7 +1702,7 @@ msgid "" " especially at low speeds." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1653,14 +1710,14 @@ msgid "" " top speed." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1668,12 +1725,12 @@ msgid "" "easier it is." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1683,7 +1740,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1693,12 +1750,12 @@ msgid "" "players and the server." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1708,7 +1765,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1728,7 +1785,7 @@ msgstr "" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "" @@ -1736,9 +1793,9 @@ msgstr "" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "" @@ -1749,6 +1806,20 @@ msgstr "" msgid "Choose a Kart" msgstr "" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1762,11 +1833,11 @@ msgstr "" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "" @@ -1783,7 +1854,7 @@ msgstr "" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "" @@ -1791,7 +1862,7 @@ msgstr "" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "" @@ -1845,30 +1916,30 @@ msgstr "" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "" @@ -1894,9 +1965,9 @@ msgstr "" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "" @@ -1914,7 +1985,7 @@ msgstr "" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "" @@ -1939,7 +2010,7 @@ msgstr "" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "" @@ -1989,8 +2060,8 @@ msgid "Online Username" msgstr "" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "" @@ -2003,7 +2074,7 @@ msgid "" msgstr "" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "" @@ -2021,338 +2092,408 @@ msgstr "" msgid "User search" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" +msgid "Enable chatting in online lobbies" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" +msgid "Enable chatting in online matches" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Bæta við tæki" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" +msgid "Skin variant" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" +msgid "Minimap" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" +msgid "Performance tests" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" +msgid "Performance test of the current settings" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" msgstr "" #. I18N: ./data/gui/screens/race_setup.stkgui @@ -2380,15 +2521,15 @@ msgstr "" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "" @@ -2403,31 +2544,15 @@ msgstr "" msgid "Random Grand Prix" msgstr "" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 -msgid "Login" -msgstr "" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" msgstr "" #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" +#. I18N: Used as a verb, appears on the main networking menu (login button) +#: src/states_screens/online/online_screen.cpp:69 +msgid "Login" msgstr "" #. I18N: ./data/tips.xml @@ -2548,238 +2673,306 @@ msgid "" msgstr "" #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "" @@ -2788,11 +2981,11 @@ msgstr "" msgid "Completed achievement \"%s\"." msgstr "" -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "" -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "" @@ -2858,7 +3051,7 @@ msgid "New kart '%s' now available" msgstr "" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2890,32 +3083,32 @@ msgid "" "created." msgstr "" -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "" -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "" -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "" @@ -2937,19 +3130,18 @@ msgstr "" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s er tilbúin/n" @@ -3423,21 +3615,21 @@ msgid "Axis %d" msgstr "" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "" @@ -3609,26 +3801,30 @@ msgstr "" msgid "+1 life." msgstr "" -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "" -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3637,16 +3833,16 @@ msgid "" "Internet\")." msgstr "" -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "" -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "" -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3654,38 +3850,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "" -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "" #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "" @@ -3695,7 +3891,7 @@ msgstr "" msgid "Eggs: %d / %d" msgstr "" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "" @@ -3703,22 +3899,22 @@ msgstr "" msgid "Final lap!" msgstr "" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s eftir %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "" @@ -3732,194 +3928,194 @@ msgstr "" msgid "Oops, %s made an own goal!" msgstr "" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "" msgstr[1] "" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "'%s' hefur verið dæmd/ur úr leik." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "" -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "" -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "" -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "" -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "" #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "" #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "" #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "" -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "" -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "" -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "" -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "" -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "" -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "" -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "" #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "" #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "" #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "" -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "" #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "" #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "" #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "" #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "" #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3927,15 +4123,15 @@ msgid "" msgstr "" #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "" #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3966,38 +4162,38 @@ msgstr "" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "" -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "" -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "" #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4005,19 +4201,19 @@ msgstr[0] "" msgstr[1] "" #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "" -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "" msgstr[1] "" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "" @@ -4046,12 +4242,12 @@ msgid "" msgstr "" #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "3ja villu keppni" @@ -4064,91 +4260,88 @@ msgstr "" msgid "Replay saved in \"%s\"." msgstr "" -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Bæting nafn" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s eftir %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "" -msgstr[1] "" - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\n111more1, 2022\nBenedikt Scheving-Thorsteinsson\nOlafur Skorrdal\nSTK-team" @@ -4436,7 +4629,7 @@ msgstr "" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "" @@ -4539,7 +4732,7 @@ msgstr "" msgid " (official tracks matching the goal)" msgstr "" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4547,91 +4740,95 @@ msgid "" msgstr "" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Bæta við Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Bæta við lýklaborðs stillingu" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "" @@ -4652,67 +4849,97 @@ msgstr "" #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4720,7 +4947,7 @@ msgid "" msgstr "" #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4737,101 +4964,102 @@ msgstr "" msgid "Invalid server address: %s." msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Tómt)" @@ -4919,33 +5147,41 @@ msgid "Press any key..." msgstr "" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 -msgid "Back to Battle" +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" msgstr "" #: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +msgid "Back to Battle" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "" @@ -4961,11 +5197,11 @@ msgstr "" msgid "%s is number %d in the rankings with a score of %f." msgstr "" -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "" -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4987,7 +5223,7 @@ msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "" @@ -5000,21 +5236,21 @@ msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "" @@ -5027,54 +5263,54 @@ msgstr "" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "" @@ -5087,74 +5323,74 @@ msgid "No player available for connecting to server." msgstr "" #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5183,7 +5419,7 @@ msgstr "" msgid "An error occurred while trying to save your grand prix." msgstr "" -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "" @@ -5227,12 +5463,12 @@ msgstr "" msgid "You unlocked grand prix %0" msgstr "" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5253,19 +5489,19 @@ msgstr "" msgid "Please select a Grand Prix" msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "" @@ -5274,19 +5510,19 @@ msgstr "" msgid "Better luck next time!" msgstr "" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "" @@ -5299,110 +5535,125 @@ msgstr "" msgid "Are you sure you want to remove all of your high scores?" msgstr "" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "" -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5410,7 +5661,7 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "" @@ -5418,24 +5669,24 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "" -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5444,7 +5695,7 @@ msgstr[1] "" #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5453,96 +5704,108 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "" -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "" @@ -5620,34 +5883,34 @@ msgid "Distance (km)" msgstr "" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "" #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "" -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "" -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5655,149 +5918,149 @@ msgstr "" #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Auka hraða" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5805,17 +6068,27 @@ msgid "" msgstr "" #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "" +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5823,89 +6096,74 @@ msgstr "" #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5915,128 +6173,133 @@ msgid "" msgstr "" #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "" #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "" -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "" #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "" @@ -6064,7 +6327,7 @@ msgstr "" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "" @@ -6099,7 +6362,7 @@ msgstr "" msgid "Top %i" msgstr "" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "" @@ -6123,102 +6386,199 @@ msgstr "" msgid "Press fire to start the challenge" msgstr "" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Hætta Grand Prix" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "" @@ -6259,28 +6619,28 @@ msgstr "" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "" @@ -6302,10 +6662,12 @@ msgid "%d/%m/%Y" msgstr "" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6314,41 +6676,48 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6356,34 +6725,41 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6391,24 +6767,27 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "" @@ -6418,7 +6797,7 @@ msgstr "" msgid "tux;game;race;" msgstr "" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6426,7 +6805,7 @@ msgid "" "for all ages." msgstr "" -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6435,7 +6814,7 @@ msgid "" "your opponents." msgstr "" -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6444,27 +6823,27 @@ msgid "" "your racing skills!" msgstr "" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "" -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "" -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "" -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "" diff --git a/data/po/ka.po b/data/po/ka.po new file mode 100644 index 00000000000..894f8ac0a27 --- /dev/null +++ b/data/po/ka.po @@ -0,0 +1,6845 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the supertuxkart package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: SuperTuxKart\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" +"PO-Revision-Date: 2015-02-15 01:58+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Georgian (http://app.transifex.com/supertuxkart/supertuxkart/language/ka/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ka\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" + +#. I18N: In Android UI, po_extract_game_data +msgid "Extracting game data..." +msgstr "" + +#. I18N: In Android UI, po_extract_error +msgid "Game data extraction error" +msgstr "" + +#. I18N: In Android UI, po_extract_error_msg +msgid "Check remaining device space or reinstall SuperTuxKart." +msgstr "" + +#. I18N: In Android UI, po_quit +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "Quit" +msgstr "გასვლა" + +#. I18N: ./data/achievements.xml +msgid "Christoffel Columbus" +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Play every official track at least once." +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Strike!" +msgstr "დარტყმა!" + +#. I18N: ./data/achievements.xml +msgid "Hit 10 karts with a bowling-ball." +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Arch Enemy" +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Hit the same kart at least 5 times in one race." +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Marathoner" +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Finish a race with at least twice the track's default lap number." +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Skid-row" +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Skid 5 times in a single lap." +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Gold driver" +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "" +"Win against at least 3 AIs in normal race, time-trial, and follow the " +"leader." +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Powerup Love" +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Use 10 or more powerups in a race." +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Unstoppable" +msgstr "შეუჩერებელი" + +#. I18N: ./data/achievements.xml +msgid "" +"Win 5 single races in a row against at least 3 AIs. Beware, restarting a " +"race counts as a loss." +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Banana Lover" +msgstr "ბანანის მოყვარული" + +#. I18N: ./data/achievements.xml +msgid "Collect at least 5 bananas in one race." +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "It's secret" +msgstr "ეს საიდუმლოა" + +#. I18N: ./data/achievements.xml +msgid "Really ... a secret." +msgstr "მართლა ... საიდუმლოა." + +#. I18N: ./data/achievements.xml +msgid "Mosquito Hunter" +msgstr "კოღოებზე მონადირე" + +#. I18N: ./data/achievements.xml +msgid "" +"Take your opponents for mosquitos! With the swatter, squash them at least 5 " +"times in a race." +msgstr "" + +#. I18N: ./data/achievements.xml +msgid "Beyond Luck" +msgstr "ძალიან იღბლიანი" + +#. I18N: ./data/achievements.xml +msgid "" +"Win 10 single races in a row in Expert or SuperTux against at least 5 AIs. " +"Beware, restarting a race counts as a loss." +msgstr "" + +#. I18N: ./data/grandprix/1_penguinplayground.grandprix +msgid "Penguin Playground" +msgstr "" + +#. I18N: ./data/grandprix/2_offthebeatentrack.grandprix +msgid "Off the Beaten Track" +msgstr "" + +#. I18N: ./data/grandprix/3_tothemoonandback.grandprix +msgid "To the Moon and Back" +msgstr "" + +#. I18N: ./data/grandprix/4_atworldsend.grandprix +msgid "At World's End" +msgstr "" + +#. I18N: ./data/gui/dialogs/addons_loading.stkgui +#. I18N: Add-on screen action +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +#. I18N: ./data/gui/dialogs/high_score_info_dialog.stkgui +#. I18N: High score info screen action +#. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui +#. I18N: In the server info dialog +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:157 +#: src/states_screens/dialogs/addons_loading.cpp:320 +msgid "Back" +msgstr "უკან" + +#. I18N: ./data/gui/dialogs/addons_loading.stkgui +#. I18N: Add-on screen action +msgid "Install" +msgstr "დაყენება" + +#. I18N: ./data/gui/dialogs/addons_loading.stkgui +#. I18N: Add-on screen action +msgid "Uninstall" +msgstr "წაშლა" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +msgid "Select a type of control that you prefer" +msgstr "" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: Control type +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 +msgid "Accelerometer" +msgstr "" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: Control type +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +#. I18N: Race paused button +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 +msgid "Gyroscope" +msgstr "გიროსკოპის" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: Control type +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 +msgid "Steering wheel" +msgstr "" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Auto acceleration" +msgstr "" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +msgid "You can change it later in touch device settings." +msgstr "" + +#. I18N: ./data/gui/dialogs/android/init_android.stkgui +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +#. I18N: ./data/gui/dialogs/kart_color_slider.stkgui +#. I18N: In the kart color slider dialog +msgid "Apply" +msgstr "გადატარება" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +msgid "Touch Device Settings" +msgstr "" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "General" +msgstr "ზოგადი" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Device enabled" +msgstr "მოწყობილობა ჩართულია" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Inverted buttons" +msgstr "" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Buttons scale" +msgstr "" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Advanced" +msgstr "დამატებით" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Deadzone" +msgstr "" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Sensitivity X" +msgstr "" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +#. I18N: In the multitouch settings screen +msgid "Sensitivity Y" +msgstr "" + +#. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui +msgid "Restore defaults" +msgstr "ნაგულისხმები მნიშვნელობების აღდგენა" + +#. I18N: ./data/gui/dialogs/confirm_dialog.stkgui +#. I18N: In a 'are you sure?' dialog +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +#. I18N: ./data/gui/dialogs/enter_address_dialog.stkgui +#. I18N: In the enter address dialog +#. I18N: ./data/gui/dialogs/general_text_field_dialog.stkgui +#. I18N: In the general textfield dialog +#. I18N: ./data/gui/dialogs/kart_color_slider.stkgui +#. I18N: In the kart color slider dialog +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/dialogs/online/registration_terms.stkgui +#. I18N: In the registration dialog +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +#. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui +#. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +#. I18N: ./data/gui/screens/edit_track.stkgui +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 +#: src/states_screens/online/register_screen.cpp:168 +#: src/states_screens/options/user_screen.cpp:115 +msgid "Cancel" +msgstr "გაუქმება" + +#. I18N: ./data/gui/dialogs/confirm_dialog.stkgui +#. I18N: In a 'are you sure?' dialog +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 +#: src/states_screens/edit_gp_screen.cpp:261 +#: src/states_screens/ghost_replay_selection.cpp:394 +#: src/states_screens/high_score_selection.cpp:265 +msgid "Yes" +msgstr "კი" + +#. I18N: ./data/gui/dialogs/confirm_resolution_dialog.stkgui +#. I18N: In the 'confirm resolution' dialog, that's shown when switching +#. resoluton +msgid "Revert" +msgstr "დაბრუნება" + +#. I18N: ./data/gui/dialogs/confirm_resolution_dialog.stkgui +#. I18N: In the 'confirm resolution' dialog, that's shown when switching +#. resoluton +#. I18N: ./data/gui/dialogs/online/registration_terms.stkgui +#. I18N: In the registration dialog +msgid "Accept" +msgstr "დასტური" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +msgid "Camera Settings" +msgstr "კამერის მორგება" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera settings +msgid "Player camera" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "FOV" +msgstr "ხედვის არე" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Distance" +msgstr "მანძილი" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Angle" +msgstr "კუთხე" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Smooth camera" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera settings +msgid "Backward camera" +msgstr "კამერა უკან" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Follow ball in soccer mode" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui +#. I18N: In the ui/camera screen +msgid "Reset" +msgstr "ჩამოყრა" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +msgid "Graphics Settings" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Advanced pipeline (lights, etc.)" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Shadows" +msgstr "ჩრდილები" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Bloom" +msgstr "გაფურჩქვნა" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Light shaft (God rays)" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Ambient occlusion" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Depth of field" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Glow (Outlines)" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Anti-aliasing" +msgstr "მომრგვალება" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Motion blur" +msgstr "გადღაბნილი მოძრაობა" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Image-based lighting" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Light Scattering" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Animated characters" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Texture compression" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Particle effects" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Rendered image quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "Geometry detail" +msgstr "" + +#. I18N: ./data/gui/dialogs/custom_video_settings.stkgui +#. I18N: Video settings +msgid "* Restart STK to apply new settings" +msgstr "" + +#. I18N: ./data/gui/dialogs/debug_slider.stkgui +#. I18N: ./data/gui/dialogs/online/recovery_info.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Close" +msgstr "დახურვა" + +#. I18N: ./data/gui/dialogs/enter_address_dialog.stkgui +#. I18N: In the enter address dialog +#. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui +#. I18N: In the server info dialog +msgid "Join" +msgstr "შეერთება" + +#. I18N: ./data/gui/dialogs/general_text_field_dialog.stkgui +#. I18N: In the general textfield dialog +#. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui +#. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +#. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui +#. I18N: Vote dialog +#. I18N: ./data/gui/screens/edit_track.stkgui +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/dialogs/message_dialog.cpp:127 +#: src/states_screens/dialogs/message_dialog.cpp:138 +#: src/states_screens/dialogs/message_dialog.cpp:143 +msgid "OK" +msgstr "დიახ" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +msgid "Record the race for ghost replay" +msgstr "" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +msgid "Watch replay only" +msgstr "" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +msgid "Compare to another ghost" +msgstr "" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info action +#. I18N: ./data/gui/dialogs/high_score_info_dialog.stkgui +#. I18N: High score info screen action +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +msgid "Remove" +msgstr "წაშლა" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info screen action +msgid "Compare ghost" +msgstr "" + +#. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui +#. I18N: Ghost replay info screen action +#. I18N: ./data/gui/dialogs/high_score_info_dialog.stkgui +#. I18N: High score info screen action +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +msgid "Start Race" +msgstr "რბოლის დაწყება" + +#. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui +#. I18N: Objective shown in achievement dialog +msgid "Goal" +msgstr "მიზანი" + +#. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui +#. I18N: Progress shown in achievement dialog +#. I18N: Progress in achievement +#: src/states_screens/online/online_profile_achievements.cpp:87 +msgid "Progress" +msgstr "მიმდინარეობა" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +msgid "Password Change" +msgstr "პაროლის შეცვლა" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +msgid "Current Password" +msgstr "მიმდინარე პაროლი" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +msgid "New Password" +msgstr "ახალი პაროლი" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "Confirm" +msgstr "დადასტურება" + +#. I18N: ./data/gui/dialogs/online/change_password.stkgui +#. I18N: In the change password dialog +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +msgid "Submit" +msgstr "გაგზავნა" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +msgid "Back to Race" +msgstr "რბოლაზე დაბრუნება" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +msgid "Quit Server" +msgstr "სერვერიდან გასვლა" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Show in network ingame dialog to allow user to go back to lobby to +#. end spectating (for example) +msgid "Back to lobby" +msgstr "ლობიში დაბრუნება" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 +msgid "Restart Race" +msgstr "რბოლის თავიდან დაწყება" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +#. I18N: Race paused button +msgid "Give Up Race" +msgstr "რბოლაზე უარის თქმა" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "Options" +msgstr "მორგება" + +#. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +#. I18N: Race paused button +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "Help" +msgstr "დახმარება" + +#. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui +#. I18N: In player rankings dialog +msgid "Top 10 players" +msgstr "საუკეთესო 10 მოთამაშე" + +#. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui +msgid "Refresh" +msgstr "განახლება" + +#. I18N: ./data/gui/dialogs/online/recovery_info.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +msgid "Account Recovery" +msgstr "ანგარიშის აღდგენა" + +#. I18N: ./data/gui/dialogs/online/recovery_info.stkgui +#. I18N: In the recovery dialog +msgid "" +"You will receive an email with further instructions on how to reset your " +"password. Please be patient and be sure to check your spam folder." +msgstr "" + +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +msgid "" +"Fill in the username and email address you supplied at registration to be " +"able to reset your password." +msgstr "" + +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 +msgid "Username" +msgstr "მომხმარებლის სახელი" + +#. I18N: ./data/gui/dialogs/online/recovery_input.stkgui +#. I18N: In the recovery dialog +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "Email" +msgstr "ელფოსტა" + +#. I18N: ./data/gui/dialogs/online/registration_terms.stkgui +#. I18N: In the registration dialog +msgid "Terms and Agreement" +msgstr "" + +#. I18N: ./data/gui/dialogs/online/registration_terms.stkgui +#. I18N: In the registration dialog +msgid "I agree to the above terms and am 13 years or older. " +msgstr "" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +msgid "Server Configuration" +msgstr "სერვერის კონფიგურაცია" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Difficulty" +msgstr "სირთულე" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: Difficulty +#: src/race/race_manager.cpp:1317 +msgid "Novice" +msgstr "ახალბედა" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: Difficulty +#: src/race/race_manager.cpp:1318 +msgid "Intermediate" +msgstr "შუალედური" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: Difficulty +#: src/race/race_manager.cpp:1319 +msgid "Expert" +msgstr "ექსპერტი" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Difficulty +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: Difficulty +#: src/race/race_manager.cpp:1320 +msgid "SuperTux" +msgstr "" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: In the server configuration screen +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 +msgid "Game mode" +msgstr "თამაშის რეჟიმი" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Multiplayer game mode +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Multiplayer game mode +#. I18N: Game mode +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 +msgid "Normal Race" +msgstr "" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Multiplayer game mode +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Multiplayer game mode +#. I18N: Game mode +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 +msgid "Time Trial" +msgstr "" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Multiplayer game mode +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Multiplayer game mode +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 +msgid "Battle" +msgstr "" + +#. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui +#. I18N: Multiplayer game mode +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: Multiplayer game mode +#. I18N: Game mode +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 +msgid "Soccer" +msgstr "სოკერი" + +#. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Password" +msgstr "პაროლი" + +#. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui +#. I18N: In the server info dialog +#: src/states_screens/dialogs/server_info_dialog.cpp:292 +msgid "Bookmark this server" +msgstr "" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "Add player" +msgstr "" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +#: src/states_screens/online/online_profile_achievements.cpp:78 +msgid "Name" +msgstr "სახელი" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "Handicap" +msgstr "" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "Press the 'All players ready' button after the player list is ready." +msgstr "" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "Clear players" +msgstr "" + +#. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui +#. I18N: Splitscreen player in network +msgid "All players ready" +msgstr "ყველა მოთამაშე მზადაა" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "User Info" +msgstr "ინფორმაცია მომხმარებელზე" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Remove Friend" +msgstr "მეგობრის წაშლა" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Add Friend" +msgstr "მეგობრის დამატება" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Accept Invite" +msgstr "მოწვევის მიღება" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "Decline Invite" +msgstr "" + +#. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui +#. I18N: User info dialog +msgid "View Profile" +msgstr "პროფილის ნახვა" + +#. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui +#. I18N: In the vote dialog +msgid "Vote" +msgstr "ხმის მიცემა" + +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui +msgid "Paused" +msgstr "შეჩერება" + +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +msgid "Back to Game" +msgstr "თამაშში დაბრუნება" + +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +msgid "Back to menu" +msgstr "მენიუზე დაბრუნება" + +#. I18N: ./data/gui/dialogs/overworld_dialog.stkgui +#. I18N: In the in-game dialog +msgid "Select kart" +msgstr "" + +#. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui +#. I18N: When changing input configurations +msgid "Press fully and release..." +msgstr "" + +#. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui +#. I18N: When configuring input +msgid "Assign to ESC key" +msgstr "" + +#. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui +#. I18N: When configuring input +msgid "Assign nothing" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "წარმადობა" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "" + +#. I18N: ./data/gui/dialogs/select_challenge.stkgui +#. I18N: ./data/gui/screens/race_setup.stkgui +#. I18N: ./data/gui/screens/soccer_setup.stkgui +msgid "Race Setup" +msgstr "" + +#. I18N: ./data/gui/dialogs/tutorial_message_dialog.stkgui +#. I18N: Button in tutorial +#. I18N: ./data/gui/screens/grand_prix_lose.stkgui +#. I18N: ./data/gui/screens/grand_prix_win.stkgui +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: ./data/gui/screens/soccer_setup.stkgui +#. I18N: In soccer setup screen +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 +msgid "Continue" +msgstr "გაგრძელება" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +msgid "SuperTuxKart Addons" +msgstr "" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In addons screen, in the filtering bar, to enable a filter that will +#. show only recently updated items +msgid "Updated" +msgstr "განახლებულია" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In addons screen, in the filtering bar, to enable a filter that will +#. show only items with good rating +msgid "Rating >=" +msgstr "შეფასება >=" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In the addons screen +msgid "Karts" +msgstr "" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In the addons screen +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +msgid "Tracks" +msgstr "ტრეკი" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In the addons screen +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracks selection screen +msgid "Arenas" +msgstr "" + +#. I18N: ./data/gui/screens/addons_screen.stkgui +#. I18N: In addons screen, above the list of addons to be installed +#: src/states_screens/addons_screen.cpp:138 +msgid "Installed" +msgstr "დაყენებულია" + +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "" + +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: track group +#. I18N: ./data/gui/screens/easter_egg.stkgui +#. I18N: track group +#. I18N: track group name +#. I18N: kart group name +#. I18N: track group name +#. I18N: In the UI options, Camera setting: Standard +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 +#: src/states_screens/dialogs/custom_camera_settings.cpp:69 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 +#: src/states_screens/gp_info_screen.cpp:256 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 +msgid "Standard" +msgstr "სტანდარტული" + +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: track group +#. I18N: ./data/gui/screens/easter_egg.stkgui +#. I18N: track group +#. I18N: track group name +#. I18N: kart group name +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 +msgid "Add-Ons" +msgstr "" + +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: track group +#. I18N: ./data/gui/screens/easter_egg.stkgui +#. I18N: track group +#. I18N: Time filters for add-ons +#. I18N: name of the tab that will show arenas from all groups +#. I18N: track group name +#. I18N: name of the tab that will show tracks from all groups +#. I18N: track group name +#. I18N: name of the tab that will show karts from all groups +#. I18N: kart group/class name +#. I18N: name of the tab that will show tracks from all groups +#. I18N: track group name +#. I18N: name of the tab that will show tracks from all groups +#. I18N: track group name +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 +#: src/states_screens/gp_info_screen.cpp:79 +#: src/states_screens/gp_info_screen.cpp:249 +#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/kart_selection.cpp:321 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 +msgid "All" +msgstr "ყველა" + +#. I18N: ./data/gui/screens/credits.stkgui +#. I18N: Title in credits screen +msgid "Credits" +msgstr "კრედიტები" + +#. I18N: ./data/gui/screens/cutscene.stkgui +msgid "Skip" +msgstr "გამოტოვება" + +#. I18N: ./data/gui/screens/easter_egg.stkgui +#. I18N: Section in easter egg tracks selection screen +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/tracks.stkgui +#. I18N: In the track selection screen +msgid "All Tracks" +msgstr "ყველა ტრეკი" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Title in edit grand prix screen +msgid "Edit Grand Prix" +msgstr "" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +msgid "Move up" +msgstr "აწევა" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +msgid "Move down" +msgstr "ქვემოთ ჩამოწევა" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Add" +msgstr "დამატება" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +msgid "Edit" +msgstr "ჩასწორება" + +#. I18N: ./data/gui/screens/edit_gp.stkgui +#. I18N: Menu item +msgid "Save" +msgstr "შენახვა" + +#. I18N: ./data/gui/screens/edit_track.stkgui +#. I18N: In the edit track screen +msgid "Number of laps:" +msgstr "" + +#. I18N: ./data/gui/screens/edit_track.stkgui +#. I18N: In the edit track screen +msgid "Reverse:" +msgstr "" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Ghost Replay Selection" +msgstr "" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: Game mode +#: src/race/race_manager.cpp:1304 +msgid "Egg Hunt" +msgstr "" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Only show the best times" +msgstr "" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Compare replay" +msgstr "" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Only show replays matching the current difficulty" +msgstr "" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Only show replays matching the current version" +msgstr "" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Hide multiplayer replays" +msgstr "" + +#. I18N: ./data/gui/screens/ghost_replay_selection.stkgui +#. I18N: In the ghost replay selection screen +msgid "Record a ghost replay" +msgstr "" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +msgid "AI karts" +msgstr "" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +msgid "Reverse" +msgstr "რევერსი" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +#. I18N: In track screen +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 +msgid "Maximum time (min.)" +msgstr "" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +msgid "Track group" +msgstr "" + +#. I18N: ./data/gui/screens/gp_info.stkgui +#. I18N: In the grand prix info screen +#: src/states_screens/gp_info_screen.cpp:164 +msgid "Continue saved GP" +msgstr "" + +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Title in grand prix editor screen +msgid "Grand Prix editor" +msgstr "" + +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +msgid "New" +msgstr "ახალი" + +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +msgid "Copy" +msgstr "კოპირება" + +#. I18N: ./data/gui/screens/grand_prix_editor.stkgui +#. I18N: Menu item +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/online/register_screen.cpp:71 +msgid "Rename" +msgstr "სახელის გადარქმევა" + +#. I18N: ./data/gui/screens/grand_prix_lose.stkgui +#. I18N: ./data/gui/screens/grand_prix_win.stkgui +msgid "Save Grand Prix" +msgstr "" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui +msgid "SuperTuxKart Help" +msgstr "" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Game Modes" +msgstr "თამაშის რეჟიმები" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Powerups" +msgstr "ძალის მოსამატებლები" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Bananas" +msgstr "ბანანები" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +#: src/io/rich_presence.cpp:501 +msgid "Story Mode" +msgstr "" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Kart classes" +msgstr "" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: Tab in help menu +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: Tab in help menu +msgid "Multiplayer" +msgstr "" + +#. I18N: ./data/gui/screens/help/help1.stkgui +msgid "Start the tutorial" +msgstr "" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "Collect blue gift boxes, they will give you powerups." +msgstr "" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +#: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 +msgid "Avoid bananas!" +msgstr "" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "" +"Collecting nitro allows you to get speed boosts whenever you wish by " +"pressing the appropriate key or button. You can see your current level of " +"nitro in the gauge at the bottom-right of the race screen." +msgstr "" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "" +"If you see a button with a lock like this one, you need to complete a " +"challenge to unlock it." +msgstr "" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "" +"You can skid by pressing a special key or button. Successive short skids " +"help to take sharp turns; while medium skids will boost your speed, long " +"skids more so. You can't stop turning while skidding, so orient your kart " +"carefully before!" +msgstr "" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: In the help menu +msgid "" +"You can get a startup boost by pressing the accelerate button at 'Set!', " +"before the race's start." +msgstr "" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: in the help screen +msgid "* Current key bindings can be seen/changed in the Options menu" +msgstr "" + +#. I18N: ./data/gui/screens/help/help2.stkgui +msgid "SuperTuxKart features several game modes:" +msgstr "" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"Regular Race: All blows allowed, so collect powerups and use them smartly!" +msgstr "" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "Time Trial: Contains no powerups, so only your driving skills matter!" +msgstr "" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"Follow the leader: Run for second place, as the last kart will be " +"disqualified every time the counter hits zero. Beware: going in front of the" +" leader will get you eliminated too!" +msgstr "" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " +"others with weapons until they lose all their lives. In Free-For-All, the " +"player who hits others the most will win in a given hit or time limit. In " +"Capture The Flag, your team needs to bring the flag of the other team to " +"your own flag base, as long as your flag is not captured by the other team." +msgstr "" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "Soccer: Use your kart to push the ball into the goal." +msgstr "" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "Egg hunt: Explore tracks to find all hidden eggs." +msgstr "" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" +" record your own!" +msgstr "" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"Lap Trial: Complete as many laps as possible in a given amount of time." +msgstr "" + +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: In the help menu +msgid "" +"* Many of these game modes can also be played in a Grand Prix fashion: " +"instead of playing a single race, you play many in a row. The better you " +"rank, the more points you get. In the end, the player with the most points " +"wins the cup." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: In the help menu +msgid "To help you win, there are some powerups you can collect:" +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"BubbleGum - protect yourself with a shield, or use while looking back to " +"leave a sticky pink puddle behind you." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Zipper - will give you a strong speed boost. But beware of not losing " +"control of your kart!" +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Cake - thrown at the closest rival, best on short ranges and long straights." +" It also affects other karts close to the explosion." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Plunger - throw straight to pull an opponent back, or throw while looking " +"back to make one lose sight." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Bowling Ball - goes straight until it strikes, it can bounce off walls. If " +"you are looking back, it will be thrown backwards." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "Parachute - slows down all karts in a better position." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Swapper - gift boxes are transformed into bananas, nitro cans into " +"bubblegums, and vice versa for a short time." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Basket Ball - bounces after the leader, and might squash and slow down karts" +" down on the way." +msgstr "" + +#. I18N: ./data/gui/screens/help/help3.stkgui +msgid "" +"Swatter - will squash karts close by, slowing them down. Can also be used to" +" remove parachutes and bombs." +msgstr "" + +#. I18N: ./data/gui/screens/help/help4.stkgui +msgid "" +"Hitting a banana can result in one of the following being attached to the " +"kart:" +msgstr "" + +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: In the help menu +msgid "Anchor - slows down the kart suddenly." +msgstr "" + +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: In the help menu +msgid "" +"Parachute - slows down the kart, more progressively than the anchor. The " +"faster you go, the stronger it slows you down." +msgstr "" + +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: In the help menu +msgid "" +"Bomb - detonates after some amount of time, throwing the kart up in the air." +" Bump into another kart to transfer the bomb to it." +msgstr "" + +#. I18N: ./data/gui/screens/help/help5.stkgui +msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" +msgstr "" + +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: In the help menu +msgid "" +"This icon on the minimap shows the available challenges you've not " +"completed. In the top-right of the screen, it also tells you how many points" +" you currently have. Complete as many challenges as possible, and Nolok will" +" accept to race against you. Win to liberate Gnu!" +msgstr "" + +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: In the help menu +msgid "" +"When you complete a challenge, you get a cup. Each cup is worth several " +"points. The higher the difficulty you completed the challenge in, the better" +" the cup and the more points it is worth." +msgstr "" + +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: In the help menu +msgid "" +"When you get the number of points indicated below this icon, you'll be " +"gifted a surprise. There are several to collect." +msgstr "" + +#. I18N: ./data/gui/screens/help/help6.stkgui +msgid "" +"Not all karts drive the same! They belong to classes with several " +"differences:" +msgstr "" + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"Mass - there are three classes of karts, depending on their mass: light, " +"medium and heavy. Heavier karts are less affected by parachutes and are more" +" resistant to explosions." +msgstr "" + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"Acceleration - especially useful at start, after an accident, or in tracks " +"with a lot of sharp curves. The lighter the kart, the faster it accelerates," +" especially at low speeds." +msgstr "" + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"Max speed - the higher it is, the faster the kart can go. Especially useful " +"in tracks with straight lines and gentle curves. Heavier karts have a higher" +" top speed." +msgstr "" + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"Nitro efficiency - The higher it is, the more speed you get from a can of " +"nitro. A lighter kart will have higher nitro efficiency." +msgstr "" + +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: In the help menu +msgid "" +"If you follow closely another kart for a few seconds, you'll get a " +"slipstream speed bonus when you overtake it. The lighter your kart, the " +"easier it is." +msgstr "" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "SuperTuxKart can be played in multiplayer mode online...:" +msgstr "" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "" +"First, select the 'online' icon in the main menu. Choose either local " +"networking, or global networking (requires internet to be enabled in the " +"options). Then, you can either create your own server with custom options, " +"or search among a list of existing servers to join. Some of them are " +"recommended servers with optionally ranked races." +msgstr "" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "" +"Once in a server, a race will begin once its owner (symbolized with the " +"crown) decides so. Official servers may auto-start races only when there are" +" enough players. Then, you can choose your kart and vote for the next track " +"to race on. An addon track is allowed only if it exists on all joined " +"players and the server." +msgstr "" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "... or on the same device:" +msgstr "" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "" +"First, you will need several input devices. Use the input configuration " +"screen to set them up. Multiple gamepads or joysticks are ideal: on " +"keyboard(s), each player will need a different set of keys, and most " +"keyboards are not appropriate for multiplayer because they don't support " +"multiple simultaneous keypresses." +msgstr "" + +#. I18N: ./data/gui/screens/help/help7.stkgui +#. I18N: In the help menu +msgid "" +"When input devices are configured, select the 'Splitscreen Multiplayer' icon" +" in the main menu. Each player can press the 'fire' key of their gamepad or " +"keyboard to join the game, and use their input device to select their kart. " +"The game continues when everyone selected their kart. Note that the mouse " +"may not be used for this operation." +msgstr "" + +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +msgid "High Score Selection" +msgstr "" + +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: Game mode +#. I18N: Lap Trial: Complete as many laps as possible in a given amount of +#. time. +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 +msgid "Lap Trial" +msgstr "" + +#. I18N: ./data/gui/screens/high_score_selection.stkgui +#. I18N: In the high score selection screen +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 +#: src/states_screens/dialogs/select_challenge.cpp:51 +#: src/states_screens/high_score_selection.cpp:139 +msgid "Grand Prix" +msgstr "" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the kart selection (player setup) screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the kart selection (player setup) screen +msgid "Choose a Kart" +msgstr "" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +msgid "Singleplayer" +msgstr "" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +msgid "Splitscreen Multiplayer" +msgstr "" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +#: src/states_screens/online/online_profile_friends.cpp:245 +msgid "Online" +msgstr "ონლაინ" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: Main menu button +msgid "Addons" +msgstr "დამატებები" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +#: src/states_screens/race_gui_overworld.cpp:530 +msgid "Tutorial" +msgstr "სახელმძღვანელო" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +#: src/states_screens/track_info_screen.cpp:343 +msgid "High Scores" +msgstr "უმაღლესი ქულები" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +#. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui +#. I18N: Section in the profile screen +#: src/states_screens/online/online_profile_base.cpp:113 +msgid "Achievements" +msgstr "მიღწევები" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "Grand Prix Editor" +msgstr "" + +#. I18N: ./data/gui/screens/main_menu.stkgui +#. I18N: In the main screen +msgid "About" +msgstr "შესახებ" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Server Creation" +msgstr "" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Name of the server" +msgstr "სერვერის სახელი" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Max. number of players" +msgstr "" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Password for private server (optional)" +msgstr "" + +#. I18N: ./data/gui/screens/online/create_server.stkgui +#. I18N: In the server creation screen +msgid "Create" +msgstr "შექმნა" + +#. I18N: ./data/gui/screens/online/lan.stkgui +msgid "Local Networking" +msgstr "" + +#. I18N: ./data/gui/screens/online/lan.stkgui +#. I18N: In the online multiplayer screen +#. I18N: ./data/gui/screens/online/profile_servers.stkgui +#. I18N: In the online multiplayer screen +msgid "Find Server" +msgstr "" + +#. I18N: ./data/gui/screens/online/lan.stkgui +#. I18N: In the online multiplayer screen +#. I18N: ./data/gui/screens/online/profile_servers.stkgui +#. I18N: In the online multiplayer screen +#: src/states_screens/online/create_server_screen.cpp:108 +msgid "Create Server" +msgstr "" + +#. I18N: ./data/gui/screens/online/networking_lobby.stkgui +#. I18N: In networking lobby +#. I18N: In the networking lobby +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 +msgid "Lobby" +msgstr "" + +#. I18N: ./data/gui/screens/online/networking_lobby.stkgui +#. I18N: In the network lobby +#. I18N: In networking lobby to configuration server settings +#: src/states_screens/online/networking_lobby.cpp:201 +msgid "Configuration" +msgstr "კონფიგურაცია" + +#. I18N: ./data/gui/screens/online/networking_lobby.stkgui +#. I18N: In the network lobby +#: src/states_screens/online/networking_lobby.cpp:193 +msgid "Start race" +msgstr "" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: In the networking menu +msgid "Enable splitscreen or player handicaps" +msgstr "" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: Networking menu button +msgid "Local networking" +msgstr "" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: Networking menu button +msgid "Global networking" +msgstr "" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: Networking menu button +msgid "Enter server address" +msgstr "" + +#. I18N: ./data/gui/screens/online/online.stkgui +#. I18N: Networking menu button +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 +msgid "Your profile" +msgstr "თქვენი პროფილი" + +#. I18N: ./data/gui/screens/online/profile_achievements.stkgui +#. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui +#. I18N: ./data/gui/screens/online/profile_friends.stkgui +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +msgid "..." +msgstr "..." + +#. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui +#. I18N: In the achievements screen +msgid "Player rankings" +msgstr "" + +#. I18N: ./data/gui/screens/online/profile_friends.stkgui +#. I18N: Section in the profile screen +#: src/states_screens/online/online_profile_base.cpp:112 +msgid "Friends" +msgstr "მეგობრები" + +#. I18N: ./data/gui/screens/online/profile_friends.stkgui +#. I18N: In the profile screen +msgid "Look for more friends:" +msgstr "" + +#. I18N: ./data/gui/screens/online/profile_friends.stkgui +#. I18N: ./data/gui/screens/online/user_search.stkgui +msgid "Search" +msgstr "ძებნა" + +#. I18N: ./data/gui/screens/online/profile_servers.stkgui +msgid "Global Networking" +msgstr "" + +#. I18N: ./data/gui/screens/online/profile_servers.stkgui +#. I18N: In the online multiplayer screen +msgid "Quick Play" +msgstr "" + +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +#. I18N: Section in the profile screen +#: src/states_screens/online/online_profile_base.cpp:114 +msgid "Account Settings" +msgstr "ანგარიშის მორგება" + +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +#. I18N: In the online account settings screen +msgid "Password:" +msgstr "პაროლი:" + +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +msgid "Change" +msgstr "ცვლილება" + +#. I18N: ./data/gui/screens/online/profile_settings.stkgui +#. I18N: In the online account settings screen +msgid "E-mail:" +msgstr "ელფოსტა:" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +#: src/states_screens/online/register_screen.cpp:73 +msgid "Create User" +msgstr "მომხმარებლის შექმნა" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: Section in the register screen +msgid "New Online Account" +msgstr "ახალი ონლაინ ანგარიში" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: Section in the register screen +msgid "Existing Online Account" +msgstr "" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: Section in the register screen +msgid "Offline Account" +msgstr "ანგარიში ოფლაინაა" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "Local Name" +msgstr "ლოკალური სახელი" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "Online Username" +msgstr "" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui +msgid "Reset password" +msgstr "პაროლის ჩამოყრა" + +#. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: In the registration dialog +msgid "" +"You can play without creating an online account by selecting an offline " +"account. Though then you can not connect to friends, vote for addons etc. " +"Please read our privacy statement at https://privacy.supertuxkart.net" +msgstr "" + +#. I18N: ./data/gui/screens/online/server_selection.stkgui +#: src/states_screens/online/server_selection.cpp:578 +msgid "Server Selection" +msgstr "" + +#. I18N: ./data/gui/screens/online/server_selection.stkgui +#. I18N: In the server selection screen +msgid "Show private server(s)" +msgstr "" + +#. I18N: ./data/gui/screens/online/server_selection.stkgui +#. I18N: In the server selection screen +msgid "Use IPv6 connection" +msgstr "" + +#. I18N: ./data/gui/screens/online/user_search.stkgui +msgid "User search" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +msgid "SuperTuxKart Options" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "ჩვენება" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Graphics" +msgstr "გრაფიკა" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Audio" +msgstr "აუდიო" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Interface" +msgstr "ინტერფეისი" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Players" +msgstr "მოთამაშეები" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Controls" +msgstr "მმართველები" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Language" +msgstr "ენა" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: In the audio options screen +msgid "Music" +msgstr "მუსიკა" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: In the audio options screen +#. I18N: in the graphical options tooltip; +#. indicates a graphical feature is enabled +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 +msgid "Enabled" +msgstr "ჩართულია" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: In the audio options screen +msgid "Volume" +msgstr "ხმა" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: In the audio options screen +msgid "Sound Effects" +msgstr "ხმის ეფექტები" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen +msgid "Delete Configuration" +msgstr "კონფიგურაციის წაშლა" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen +#. I18N: button to disable a keyboard configuration +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 +msgid "Disable Configuration" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen +msgid "Back to device list" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen +msgid "Rename Configuration" +msgstr "კონფიგურაციის სახელის გადარქმევა" + +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: In the input configuration screen, for gamepad +msgid "Enable force feedback (if supported)" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "გარჩევადობა" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "სრულ ეკრანზე" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Internet options" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Always show login screen" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Connect to the Internet" +msgstr "ინტერნეტთან მიერთება" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Enable chatting in online lobbies" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Enable chatting in online matches" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Miscellaneous options" +msgstr "სხვადასხვა პარამეტრები" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: In the general settings +msgid "Enable per-player handicaps" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: For mobile version for STK, uninstall the downloaded assets +#: src/states_screens/options/options_screen_general.cpp:79 +msgid "Uninstall full game assets" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: In the input configuration screen +#: src/states_screens/options/options_screen_input.cpp:191 +msgid "Press enter or double-click on a device to configure it" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: In the input configuration screen +msgid "Add a device" +msgstr "მოწყობილობის დამატება" + +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: In the input configuration screen +msgid "" +"* Which config to use will be inferred from which 'Select' key is pressed to" +" join the game." +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Skin" +msgstr "კანი" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Skin variant" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Minimap" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Font size" +msgstr "ფონტის ზომა" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Camera" +msgstr "კამერა" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Custom..." +msgstr "ხელით..." + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Display FPS" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Show other karts' held powerups" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Enable the story mode timer" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: In the ui settings +msgid "Enable the speedrun timer" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Render resolution" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Graphical Effects Level" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Blur Effects Level" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video options, maximum frame per second +msgid "Maximum FPS" +msgstr "მაქს. კადრი/წმ" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Custom settings..." +msgstr "" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Performance tests" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: In the video settings +msgid "Performance test of the current settings" +msgstr "" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "პაროლის დამახსოვრება" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "წაშლა" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "" + +#. I18N: ./data/gui/screens/race_setup.stkgui +msgid "Select a difficulty" +msgstr "" + +#. I18N: ./data/gui/screens/race_setup.stkgui +msgid "Select a game mode" +msgstr "" + +#. I18N: ./data/gui/screens/soccer_setup.stkgui +#. I18N: In soccer setup screen +msgid "Use left/right to choose your team and press fire" +msgstr "" + +#. I18N: ./data/gui/screens/soccer_setup.stkgui +#. I18N: In soccer setup screen +msgid "Red Team" +msgstr "" + +#. I18N: ./data/gui/screens/soccer_setup.stkgui +#. I18N: In soccer setup screen +msgid "Blue Team" +msgstr "" + +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 +msgid "Number of laps" +msgstr "" + +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 +msgid "Number of AI karts" +msgstr "" + +#. I18N: ./data/gui/screens/track_info.stkgui +#. I18N: In the track info screen +msgid "Number of blue team AI karts" +msgstr "" + +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +#: src/race/grand_prix_data.cpp:623 +msgid "Random Grand Prix" +msgstr "" + +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "" + +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: Used as a verb, appears on the main networking menu (login button) +#: src/states_screens/online/online_screen.cpp:69 +msgid "Login" +msgstr "შესვლა" + +#. I18N: ./data/tips.xml +msgid "The UI skin can be changed in the UI options." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "You can see other karts' powerups by enabling it in the UI options." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "The font size can be changed in the UI options." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "The help menu has lots of useful information." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "In single-player, you can watch and challenge recorded time-trials." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"You can visit https://supertuxkart.net/ for more information about the game." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Short nitro boosts are more efficient." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Only use zippers when it is safe. Long straight lines are ideal." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"Don't use multiple zippers quickly in row, instead, wait until the speed " +"boost wears off." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Skidding makes you much faster, do it whenever safe." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "The swatter can be used to remove bombs or parachutes." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"You can't stop turning while skidding. Good kart orientation at the skid's " +"start is paramount." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "You get a startup boost if you start accelerating during \"Set\"." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Braking allows to get rid of parachutes quicker." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "First and foremost, focus on where your kart is going." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "The rescue key (button) is very useful." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Be careful when close to other karts, they may attack you!" +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"Basketballs can be destroyed using precise backward shots with a bowling " +"ball, cake, or plunger." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"Try to avoid crashing into the backs of other karts as this will slow you " +"down." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "You can use bowling balls to push and block the ball." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "In soccer, always work as a team for good results." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"If you miss the ball and an opponent is approaching, try hitting them with a" +" powerup or block their way." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Good rotation of positions (attack and defense) is essential." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Make sure to store at least 2 big cans worth of nitro." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "Never use the three bowling balls all at the same time." +msgstr "" + +#. I18N: ./data/tips.xml +msgid "" +"Don't get in the way of a teammate carrying the ball, though you can try to " +"hit opponents attempting to stop them from scoring." +msgstr "" + +#. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml +msgid "Adiumy" +msgstr "" + +#. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml +msgid "Amanda" +msgstr "ამანდა" + +#. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml +msgid "Godette" +msgstr "" + +#. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml +msgid "Emule" +msgstr "" + +#. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml +msgid "Gavroche" +msgstr "" + +#. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml +msgid "Gnu" +msgstr "" + +#. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml +msgid "Hexley" +msgstr "" + +#. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml +msgid "Kiki" +msgstr "" + +#. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml +msgid "Konqi" +msgstr "Konqi" + +#. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml +msgid "Nolok" +msgstr "" + +#. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml +msgid "Pidgin" +msgstr "" + +#. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml +msgid "Puffy" +msgstr "" + +#. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml +msgid "Pepper" +msgstr "" + +#. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml +msgid "Sara" +msgstr "" + +#. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml +msgid "Suzanne" +msgstr "" + +#. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml +msgid "Tux" +msgstr "პინგვინი" + +#. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml +msgid "Wilber" +msgstr "" + +#. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml +msgid "Xue" +msgstr "" + +#. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml +msgid "Antediluvian Abyss" +msgstr "" + +#. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml +msgid "Alien Signal" +msgstr "" + +#. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml +msgid "Ancient Colosseum Labyrinth" +msgstr "" + +#. I18N: ../stk-assets/tracks/arena_candela_city/track.xml +#. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml +msgid "Candela City" +msgstr "" + +#. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml +msgid "Battle Island" +msgstr "" + +#. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml +msgid "Black Forest" +msgstr "" + +#. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml +msgid "Cave X" +msgstr "" + +#. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml +msgid "Cocoa Temple" +msgstr "" + +#. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml +msgid "Cornfield Crossing" +msgstr "" + +#. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml +msgid "Fort Magma" +msgstr "" + +#. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml +msgid "Gran Paradiso Island" +msgstr "" + +#. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml +msgid "Hacienda" +msgstr "" + +#. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml +msgid "Hole Drop" +msgstr "" + +#. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml +msgid "Icy Soccer Field" +msgstr "" + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "What's wrong, little hippies? Your great gnu leader is missing?" +msgstr "" + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "Oh yes, see, he's in my castle now and will be served for supper..." +msgstr "" + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "But I'm a fair creature, so I'll make you a deal." +msgstr "" + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "If you can beat me at racing, I will free the old codger." +msgstr "" + +#. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml +msgid "" +" But you pathetic little twerps will never be able to beat me - King of the " +"Karts!" +msgstr "" + +#. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml +msgid "Las Dunas Arena" +msgstr "" + +#. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml +msgid "Las Dunas Soccer Stadium" +msgstr "" + +#. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml +msgid "Around the Lighthouse" +msgstr "" + +#. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml +msgid "Old Mine" +msgstr "" + +#. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml +msgid "Minigolf" +msgstr "" + +#. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml +msgid "Oasis" +msgstr "" + +#. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml +msgid "Oliver's Math Class" +msgstr "" + +#. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml +msgid "Pumpkin Park" +msgstr "" + +#. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml +msgid "Ravenbridge Mansion" +msgstr "" + +#. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml +msgid "Shifting Sands" +msgstr "" + +#. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml +msgid "Nessie's Pond" +msgstr "" + +#. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml +msgid "Northern Resort" +msgstr "" + +#. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml +msgid "Snow Peak" +msgstr "" + +#. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml +msgid "Soccer Field" +msgstr "" + +#. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml +msgid "The Stadium" +msgstr "" + +#. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml +msgid "STK Enterprise" +msgstr "" + +#. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml +msgid "Temple" +msgstr "ტემპლი" + +#. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml +msgid "Volcan Island" +msgstr "" + +#. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml +msgid "XR591" +msgstr "XR591" + +#. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml +msgid "Zen Garden" +msgstr "" + +#: src/achievements/achievement.cpp:387 +#, c-format +msgid "Completed achievement \"%s\"." +msgstr "" + +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 +msgid "Failed to connect to the SuperTuxKart add-ons server." +msgstr "" + +#: src/addons/news_manager.cpp:184 +#, c-format +msgid "Error downloading news: '%s'." +msgstr "" + +#: src/challenges/challenge_data.cpp:303 src/network/server_config.cpp:261 +msgid "Normal Race (Grand Prix)" +msgstr "" + +#: src/challenges/challenge_data.cpp:305 +msgid "Time-Trial (Grand Prix)" +msgstr "" + +#: src/challenges/challenge_data.cpp:310 +msgid "Time-Trial - beat the replay" +msgstr "" + +#: src/challenges/challenge_data.cpp:312 +msgid "Time-Trial - nitro challenge" +msgstr "" + +#: src/challenges/challenge_data.cpp:314 +msgid "Normal Race (single race)" +msgstr "" + +#: src/challenges/challenge_data.cpp:316 +msgid "Time-Trial (single race)" +msgstr "" + +#: src/challenges/challenge_data.cpp:318 +msgid "Follow the Leader (single race)" +msgstr "" + +#. I18N: In the Select challenge dialog, tell user this challenge has reversed +#. laps +#: src/challenges/challenge_data.cpp:324 +#: src/states_screens/dialogs/select_challenge.cpp:78 +msgid "Mode: Reverse" +msgstr "" + +#: src/challenges/challenge_data.cpp:601 +#, c-format +msgid "New track '%s' now available" +msgstr "" + +#: src/challenges/challenge_data.cpp:605 +#, c-format +msgid "New game mode '%s' now available" +msgstr "" + +#: src/challenges/challenge_data.cpp:615 +#, c-format +msgid "New Grand Prix '%s' now available" +msgstr "" + +#: src/challenges/challenge_data.cpp:619 +#, c-format +msgid "New difficulty '%s' now available" +msgstr "" + +#: src/challenges/challenge_data.cpp:629 +#, c-format +msgid "New kart '%s' now available" +msgstr "" + +#: src/challenges/story_mode_timer.cpp:281 +#: src/states_screens/options/options_screen_ui.cpp:280 +msgid "" +"Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" +"\n" +"Closing the game before the story mode's completion invalidates the timer.\n" +"\n" +"To use the speedrun mode, please use a new profile." +msgstr "" + +#. I18N: Name of first guest player (without number) +#: src/config/player_manager.cpp:396 +msgid "Guest" +msgstr "სტუმარი" + +#. I18N: Name of further guest players, with a 1, 2, ... attached +#: src/config/player_manager.cpp:401 +#, c-format +msgid "Guest %d" +msgstr "" + +#: src/config/user_config.cpp:688 +msgid "" +"Your config file was malformed, so it was deleted and a new one will be " +"created." +msgstr "" + +#: src/config/user_config.cpp:699 +msgid "" +"Your config file was too old, so it was deleted and a new one will be " +"created." +msgstr "" + +#: src/graphics/irr_driver.cpp:738 +msgid "Video recording started." +msgstr "" + +#: src/graphics/irr_driver.cpp:745 +#, c-format +msgid "Video saved in \"%s\"." +msgstr "" + +#: src/graphics/irr_driver.cpp:749 +msgid "Encoding progress:" +msgstr "" + +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 +#, c-format +msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" +msgstr "" + +#. I18N: Tip shown in gui for giving player hints +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 +#, c-format +msgid "Tip: %s" +msgstr "" + +#: src/guiengine/engine.cpp:1510 +msgid "Loading" +msgstr "იტვირთება" + +#: src/guiengine/widgets/kart_stats_widget.cpp:104 +msgid "Mass" +msgstr "მასა" + +#: src/guiengine/widgets/kart_stats_widget.cpp:110 +msgid "Maximum speed" +msgstr "მაქსიმალური სიჩქარე" + +#: src/guiengine/widgets/kart_stats_widget.cpp:117 +msgid "Acceleration" +msgstr "აპარატურული აჩქარება" + +#: src/guiengine/widgets/kart_stats_widget.cpp:123 +msgid "Nitro efficiency" +msgstr "" + +#. I18N: 'handicapped' indicates that per-player handicaps are +#. activated for this kart (i.e. it will drive slower) +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 +#: src/karts/controller/local_player_controller.cpp:468 +#: src/karts/controller/player_controller.cpp:413 +#: src/network/protocols/client_lobby.cpp:868 +#: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 +#: src/states_screens/race_result_gui.cpp:1675 +#, c-format +msgid "%s (handicapped)" +msgstr "" + +#: src/guiengine/widgets/player_kart_widget.cpp:448 +#, c-format +msgid "%s is ready" +msgstr "%s მზადაა" + +#. I18N: Unbound key binding +#: src/input/binding.cpp:85 +msgid "[none]" +msgstr "[არცერთი]" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:92 +msgctxt "input_key" +msgid "Left Mouse Button" +msgstr "თაგუნას მარცხენა ღილაკი" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:94 +msgctxt "input_key" +msgid "Right Mouse Button" +msgstr "თაგუნის მარჯვენა ღილაკი" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:96 +msgctxt "input_key" +msgid "Cancel" +msgstr "გაუქმება" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:98 +msgctxt "input_key" +msgid "Middle Mouse Button" +msgstr "შუა თაგუნას ღილაკი" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:100 +msgctxt "input_key" +msgid "X1 Mouse Button" +msgstr "X1 თაგუნას ღილაკი" + +#. I18N: input configuration screen: mouse button +#: src/input/binding.cpp:102 +msgctxt "input_key" +msgid "X2 Mouse Button" +msgstr "X2 თაგუნას ღილაკი" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:104 +msgctxt "input_key" +msgid "Backspace" +msgstr "Backspace" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:106 +msgctxt "input_key" +msgid "Tab" +msgstr "ჩანართი" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:108 +msgctxt "input_key" +msgid "Clear" +msgstr "გასუფთავება" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:110 +msgctxt "input_key" +msgid "Return" +msgstr "Enter" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:112 +msgctxt "input_key" +msgid "Shift" +msgstr "Shift" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:114 +msgctxt "input_key" +msgid "Control" +msgstr "კონტროლი" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:116 +msgctxt "input_key" +msgid "Alt/Menu" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:118 +msgctxt "input_key" +msgid "Pause" +msgstr "შეჩერება" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:120 +msgctxt "input_key" +msgid "Caps Lock" +msgstr "Caps Lock" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:122 +msgctxt "input_key" +msgid "Kana" +msgstr "კანა" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:124 +msgctxt "input_key" +msgid "Junja" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:127 +msgctxt "input_key" +msgid "Final" +msgstr "საბოლოო" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:129 +msgctxt "input_key" +msgid "Escape" +msgstr "Escape" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:131 +msgctxt "input_key" +msgid "Convert" +msgstr "გადაყვანა" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:133 +msgctxt "input_key" +msgid "Nonconvert" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:135 +msgctxt "input_key" +msgid "Accept" +msgstr "დასტური" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:137 +msgctxt "input_key" +msgid "Modechange" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:139 +msgctxt "input_key" +msgid "Space" +msgstr "ჰარე" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:141 +msgctxt "input_key" +msgid "Page Up" +msgstr "ღილაკი Page Up" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:143 +msgctxt "input_key" +msgid "Page Down" +msgstr "ღილაკი Page Down" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:145 +msgctxt "input_key" +msgid "End" +msgstr "დასასრული" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:147 +msgctxt "input_key" +msgid "Home" +msgstr "მთავარი" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:149 +msgctxt "input_key" +msgid "Left" +msgstr "წავიდა" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:151 +msgctxt "input_key" +msgid "Up" +msgstr "ჩართული" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:153 +msgctxt "input_key" +msgid "Right" +msgstr "მარჯვნივ" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:155 +msgctxt "input_key" +msgid "Down" +msgstr "ქვემოთ" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:157 +msgctxt "input_key" +msgid "Select" +msgstr "არჩევა" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:159 +msgctxt "input_key" +msgid "Print" +msgstr "ბეჭდვა" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:161 +msgctxt "input_key" +msgid "Exec" +msgstr "გაშვ" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:163 +msgctxt "input_key" +msgid "Print Screen" +msgstr "ეკრანის დაბეჭდვა" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:165 +msgctxt "input_key" +msgid "Insert" +msgstr "ჩასმა" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:167 +msgctxt "input_key" +msgid "Delete" +msgstr "წაშლა" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:169 +msgctxt "input_key" +msgid "Help" +msgstr "დახმარება" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:207 +msgctxt "input_key" +msgid "Left Logo" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:209 +msgctxt "input_key" +msgid "Right Logo" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:211 +msgctxt "input_key" +msgid "Apps" +msgstr "აპები" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:213 +msgctxt "input_key" +msgid "Sleep" +msgstr "ძილი" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:215 +msgctxt "input_key" +msgid "Numpad 0" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:217 +msgctxt "input_key" +msgid "Numpad 1" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:219 +msgctxt "input_key" +msgid "Numpad 2" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:221 +msgctxt "input_key" +msgid "Numpad 3" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:223 +msgctxt "input_key" +msgid "Numpad 4" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:225 +msgctxt "input_key" +msgid "Numpad 5" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:227 +msgctxt "input_key" +msgid "Numpad 6" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:229 +msgctxt "input_key" +msgid "Numpad 7" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:231 +msgctxt "input_key" +msgid "Numpad 8" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:233 +msgctxt "input_key" +msgid "Numpad 9" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:237 +msgctxt "input_key" +msgid "Separator" +msgstr "გამყოფი" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:239 +msgctxt "input_key" +msgid "- (Subtract)" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:241 +msgctxt "input_key" +msgid "Decimal" +msgstr "ათობითი" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:243 +msgctxt "input_key" +msgid "/ (Divide)" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:269 +msgctxt "input_key" +msgid "Num Lock" +msgstr "Num Lock" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:271 +msgctxt "input_key" +msgid "Scroll Lock" +msgstr "Scroll Lock" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:273 +msgctxt "input_key" +msgid "Left Shift" +msgstr "მარცხენა Shift" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:275 +msgctxt "input_key" +msgid "Right Shift" +msgstr "მარჯვენა Shift" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:277 +msgctxt "input_key" +msgid "Left Control" +msgstr "მარცხენა Ctrl" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:279 +msgctxt "input_key" +msgid "Right Control" +msgstr "მარჯვენა Ctrl" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:281 +msgctxt "input_key" +msgid "Left Menu" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:283 +msgctxt "input_key" +msgid "Right Menu" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:289 +msgctxt "input_key" +msgid "Attn" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:291 +msgctxt "input_key" +msgid "Crsel" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:293 +msgctxt "input_key" +msgid "Exsel" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:295 +msgctxt "input_key" +msgid "Ereof" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:297 +msgctxt "input_key" +msgid "Play" +msgstr "დაკვრა" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:299 +msgctxt "input_key" +msgid "Zoom" +msgstr "მასშტაბი" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:301 +msgctxt "input_key" +msgid "Pa1" +msgstr "" + +#. I18N: input configuration screen: keyboard key +#: src/input/binding.cpp:303 +msgctxt "input_key" +msgid "Oem Clear" +msgstr "" + +#. I18N: to appear in input configuration screen, for gamepad hats +#: src/input/binding.cpp:343 src/input/binding.cpp:348 +#, c-format +msgid "Gamepad hat %d" +msgstr "" + +#. I18N: to appear in input configuration screen, for gamepad axes +#: src/input/binding.cpp:355 +#, c-format +msgid "Axis %d %s" +msgstr "" + +#. I18N: to appear in input configuration screen, for gamepad axes +#: src/input/binding.cpp:362 +#, c-format +msgid "Axis %d inverted" +msgstr "" + +#. I18N: to appear in input configuration screen, for gamepad axes +#: src/input/binding.cpp:367 +#, c-format +msgid "Axis %d" +msgstr "ღერძი %d" + +#. I18N: to appear in input configuration screen, for gamepad buttons +#: src/input/binding.cpp:374 +#, c-format +msgid "Gamepad button %d" +msgstr "" + +#. I18N: to appear in input configuration screen, for mouse (might not be used +#. at all) +#: src/input/binding.cpp:377 +#, c-format +msgid "Mouse button %d" +msgstr "" + +#. I18N: to appear in input configuration screen, for mouse (might not be used +#. at all) +#: src/input/binding.cpp:381 +#, c-format +msgid "Mouse axis %d %s" +msgstr "" + +#. I18N: shown when config file is too old +#: src/input/device_manager.cpp:496 +msgid "Please re-configure your key bindings." +msgstr "" + +#: src/input/device_manager.cpp:497 +msgid "Your input config file is not compatible with this version of STK." +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:159 +msgid "Guide" +msgstr "გიდი" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:161 +msgid "Start" +msgstr "დაწყება" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:163 +msgid "Left thumbstick press" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:165 +msgid "Right thumbstick press" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:167 +msgid "Left shoulder" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:169 +msgid "Right shoulder" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:171 +msgid "DPad up" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:173 +msgid "DPad down" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:175 +msgid "DPad left" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:177 +msgid "DPad right" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:181 +msgid "Left thumbstick right" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:183 +msgid "Left thumbstick left" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:185 +msgid "Left thumbstick down" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:187 +msgid "Left thumbstick up" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:189 +msgid "Right thumbstick right" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:191 +msgid "Right thumbstick left" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:193 +msgid "Right thumbstick down" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:195 +msgid "Right thumbstick up" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:197 +msgid "Left trigger" +msgstr "" + +#. I18N: name of buttons on gamepads +#: src/input/gamepad_config.cpp:199 +msgid "Right trigger" +msgstr "" + +#: src/input/input_manager.cpp:867 +#, c-format +msgid "Ignoring '%s'. You needed to join earlier to play!" +msgstr "" + +#: src/input/input_manager.cpp:903 +msgid "Only the Game Master may act at this point!" +msgstr "" + +#: src/input/sdl_controller.cpp:253 +#, c-format +msgid "%s has low battery level." +msgstr "" + +#: src/input/wiimote_manager.cpp:379 +msgid "" +"Connect your wiimote to the Bluetooth manager, then click on Ok. Detailed " +"instructions at https://supertuxkart.net/Wiimote" +msgstr "" + +#: src/input/wiimote_manager.cpp:382 +msgid "" +"Press the buttons 1+2 simultaneously on your wiimote to put it in discovery " +"mode, then click on Ok. Detailed instructions at " +"https://supertuxkart.net/Wiimote" +msgstr "" + +#: src/input/wiimote_manager.cpp:405 +#, c-format +msgid "Found %d wiimote" +msgid_plural "Found %d wiimotes" +msgstr[0] "" +msgstr[1] "" + +#: src/input/wiimote_manager.cpp:410 +msgid "Could not detect any wiimote :/" +msgstr "" + +#: src/io/rich_presence.cpp:477 +msgid "Getting ready to race" +msgstr "" + +#: src/karts/controller/local_player_controller.cpp:329 +msgid "Penalty time!!" +msgstr "" + +#: src/karts/controller/local_player_controller.cpp:332 +msgid "Don't accelerate before 'Set!'" +msgstr "" + +#: src/karts/controller/spare_tire_ai.cpp:150 +msgid "You can have at most 3 lives!" +msgstr "" + +#: src/karts/controller/spare_tire_ai.cpp:157 +msgid "+1 life." +msgstr "" + +#: src/karts/kart.cpp:1032 +msgid "You were too slow!" +msgstr "" + +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "" + +#: src/karts/kart.cpp:1034 +msgid "You won the race!" +msgstr "" + +#: src/karts/kart.cpp:1035 +#, c-format +msgid "You finished the race in rank %d!" +msgstr "" + +#. I18N: Message shown in game to tell player left the game in network +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 +#, c-format +msgid "%s left the game." +msgstr "" + +#: src/main.cpp:2042 +msgid "" +"SuperTuxKart may connect to a server to download add-ons and notify you of " +"updates. Please read our privacy policy at https://supertuxkart.net/Privacy." +" Would you like this feature to be enabled? (To change this setting at a " +"later time, go to options, select tab 'General', and edit \"Connect to the " +"Internet\")." +msgstr "" + +#: src/main.cpp:2393 +msgid "Your screen resolution is too low to run STK." +msgstr "" + +#: src/main.cpp:2444 +msgid "" +"Your driver version is too old. Please install the latest video drivers." +msgstr "" + +#: src/main.cpp:2464 +#, c-format +msgid "" +"Your graphics driver appears to be very old. Please check if an update is " +"available. SuperTuxKart recommends a driver supporting %s or better. The " +"game will likely still run, but in a reduced-graphics mode." +msgstr "" + +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 +msgid "Server connection timed out." +msgstr "" + +#. I18N: Show when a player gets the red flag in CTF +#: src/modes/capture_the_flag.cpp:190 +#, c-format +msgid "%s has the red flag!" +msgstr "" + +#. I18N: Show when the red flag is returned to its base in CTF +#: src/modes/capture_the_flag.cpp:197 +msgid "The red flag has returned!" +msgstr "" + +#. I18N: Show when a player gets the blue flag in CTF +#: src/modes/capture_the_flag.cpp:208 +#, c-format +msgid "%s has the blue flag!" +msgstr "" + +#. I18N: Show when the blue flag is returned to its base in CTF +#: src/modes/capture_the_flag.cpp:215 +msgid "The blue flag has returned!" +msgstr "" + +#: src/modes/capture_the_flag.cpp:408 +#, c-format +msgid "%s captured the blue flag!" +msgstr "" + +#: src/modes/capture_the_flag.cpp:412 +#, c-format +msgid "%s captured the red flag!" +msgstr "" + +#: src/modes/easter_egg_hunt.cpp:222 +#, c-format +msgid "Eggs: %d / %d" +msgstr "" + +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 +msgid "Leader" +msgstr "ლიდერი" + +#: src/modes/linear_world.cpp:418 +msgid "Final lap!" +msgstr "" + +#: src/modes/linear_world.cpp:450 +#, c-format +msgid "Lap %i" +msgstr "წრე %i" + +#: src/modes/linear_world.cpp:552 +#, c-format +msgctxt "fastest_lap" +msgid "%s by %s" +msgstr "" + +#: src/modes/linear_world.cpp:558 +msgid "New fastest lap" +msgstr "" + +#: src/modes/linear_world.cpp:1100 +msgid "WRONG WAY!" +msgstr "" + +#: src/modes/soccer_world.cpp:533 src/modes/soccer_world.cpp:660 +#, c-format +msgid "%s scored a goal!" +msgstr "" + +#: src/modes/soccer_world.cpp:535 src/modes/soccer_world.cpp:662 +#, c-format +msgid "Oops, %s made an own goal!" +msgstr "" + +#: src/modes/three_strikes_battle.cpp:665 +#, c-format +msgid "%i spare tire kart has been spawned!" +msgid_plural "%i spare tire karts have been spawned!" +msgstr[0] "" +msgstr[1] "" + +#: src/modes/world.cpp:1400 +msgid "You have been eliminated!" +msgstr "" + +#: src/modes/world.cpp:1407 +#, c-format +msgid "'%s' has been eliminated." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:130 +msgid "Server has been shut down." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:131 +msgid "You were kicked from the server." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:133 +msgid "You were kicked: Ping too high." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 +msgid "Bad network connection is detected." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 +msgid "Bot" +msgstr "ბოტი" + +#: src/network/protocols/client_lobby.cpp:642 +#, c-format +msgid "%s disconnected." +msgstr "%s გაითიშა." + +#. I18N: Message shown in network lobby to tell user that +#. player name is clickable +#: src/network/protocols/client_lobby.cpp:673 +msgid "" +"Press player name in the list for player management and ranking information." +msgstr "" + +#. I18N: In the networking lobby +#. I18N: In server info dialog +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 +#, c-format +msgid "Difficulty: %s" +msgstr "" + +#. I18N: In the networking lobby +#: src/network/protocols/client_lobby.cpp:744 +#, c-format +msgid "Max players: %d" +msgstr "" + +#. I18N: In server info dialog +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 +#, c-format +msgid "Game mode: %s" +msgstr "" + +#. I18N: In the create server screen for soccer server +#: src/network/protocols/client_lobby.cpp:770 +#: src/states_screens/dialogs/server_configuration_dialog.cpp:174 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 +msgid "Time limit" +msgstr "" + +#. I18N: In the create server screen for soccer server +#: src/network/protocols/client_lobby.cpp:771 +#: src/states_screens/dialogs/server_configuration_dialog.cpp:175 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 +msgid "Goals limit" +msgstr "" + +#. I18N: In the networking lobby +#: src/network/protocols/client_lobby.cpp:775 +#, c-format +msgid "Soccer game type: %s" +msgstr "" + +#: src/network/protocols/client_lobby.cpp:785 +#, c-format +msgid "Grand prix progress: %d / %d" +msgstr "" + +#. I18N: Display when all players are in red or blue team, which the race +#. will not be allowed to start +#: src/network/protocols/client_lobby.cpp:904 +msgid "All players joined red or blue team." +msgstr "" + +#. I18N: Display when a player is allow to control the server +#: src/network/protocols/client_lobby.cpp:924 +msgid "You are now the owner of server." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:967 +msgid "Connection refused: Server is busy." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:972 +msgid "Connection refused: You are banned from the server." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:987 +msgid "Connection refused: Server password is incorrect." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:991 +msgid "Connection refused: Game data is incompatible." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:995 +msgid "Connection refused: Server is full." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:999 +msgid "Connection refused: Invalid player connecting." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:1027 +msgid "Failed to start the network game." +msgstr "" + +#. I18N: Error message shown if live join or spectate failed in network +#: src/network/protocols/client_lobby.cpp:1242 +msgid "The game has ended, you can't live join or spectate anymore." +msgstr "" + +#. I18N: Error message shown if live join failed in network +#: src/network/protocols/client_lobby.cpp:1246 +msgid "No remaining place in the arena - live join disabled." +msgstr "" + +#. I18N: Error message shown if only 1 player remains in network +#: src/network/protocols/client_lobby.cpp:1250 +msgid "Only 1 player remaining, returning to lobby." +msgstr "" + +#: src/network/protocols/client_lobby.cpp:1256 +msgid "Server owner quit the game." +msgstr "" + +#. I18N: Status shown to player when he will be spectating the next game +#: src/network/protocols/client_lobby.cpp:1260 +msgid "You will be spectating the next game." +msgstr "" + +#. I18N: Show when player join red team of the started game in +#. network +#: src/network/protocols/client_lobby.cpp:1436 +#, c-format +msgid "%s joined the red team." +msgstr "" + +#. I18N: Show when player join blue team of the started game in +#. network +#: src/network/protocols/client_lobby.cpp:1442 +#, c-format +msgid "%s joined the blue team." +msgstr "" + +#. I18N: Show when player join the started game in network +#: src/network/protocols/client_lobby.cpp:1448 +#, c-format +msgid "%s joined the game." +msgstr "" + +#. I18N: Message shown in game to tell the player it's possible to change +#. the camera target in spectate mode of network +#: src/network/protocols/client_lobby.cpp:1639 +#, c-format +msgid "" +"Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " +"camera position." +msgstr "" + +#. I18N: Tell player he has successfully report this named player +#: src/network/protocols/client_lobby.cpp:1655 +#, c-format +msgid "Successfully reported %s." +msgstr "" + +#. I18N: Shown when there is download error for assets download +#. in the first run +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 +msgid "" +"Failed to download assets, check your storage space or internet connection " +"and try again later." +msgstr "" + +#: src/network/protocols/connect_to_server.cpp:230 +msgid "No quick play server available." +msgstr "" + +#: src/network/protocols/connect_to_server.cpp:380 +#, c-format +msgid "Cannot connect to server %s." +msgstr "" + +#. I18N: Show the failed detect port server name +#: src/network/protocols/connect_to_server.cpp:883 +#, c-format +msgid "Failed to detect port number for server %s." +msgstr "" + +#: src/network/protocols/lobby_protocol.cpp:294 +msgid "Network grand prix has been finished." +msgstr "" + +#: src/network/server_config.cpp:263 +msgid "Time Trial (Grand Prix)" +msgstr "" + +#. I18N: Game mode +#. I18N: In the create server screen for battle server +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 +#: src/states_screens/dialogs/server_configuration_dialog.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 +msgid "Free-For-All" +msgstr "" + +#. I18N: Game mode +#. I18N: In the create server screen for battle server +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 +#: src/states_screens/dialogs/server_configuration_dialog.cpp:162 +#: src/states_screens/online/create_server_screen.cpp:244 +msgid "Capture The Flag" +msgstr "" + +#: src/online/online_player_profile.cpp:456 +#, c-format +msgid "%s is now online." +msgstr "" + +#: src/online/online_player_profile.cpp:460 +#, c-format +msgid "%s and %s are now online." +msgstr "" + +#: src/online/online_player_profile.cpp:465 +#, c-format +msgid "%s, %s and %s are now online." +msgstr "" + +#. I18N: Only used for count > 3 +#: src/online/online_player_profile.cpp:471 +#, c-format +msgid "%d friend is now online." +msgid_plural "%d friends are now online." +msgstr[0] "" +msgstr[1] "" + +#. I18N: Tell your friend if he is on any server in game +#: src/online/online_player_profile.cpp:520 +#, c-format +msgid "%s is now on server \"%s\"." +msgstr "" + +#: src/online/online_player_profile.cpp:551 +#, c-format +msgid "You have %d new friend request!" +msgid_plural "You have %d new friend requests!" +msgstr[0] "" +msgstr[1] "" + +#: src/online/online_player_profile.cpp:557 +msgid "You have a new friend request!" +msgstr "" + +#: src/online/xml_request.cpp:83 +msgid "" +"Unable to connect to the server. Check your internet connection or try again" +" later." +msgstr "" + +#: src/race/grand_prix_data.cpp:639 src/states_screens/gp_info_screen.cpp:77 +msgid "Default" +msgstr "ნაგულისხმევი" + +#: src/race/grand_prix_data.cpp:641 src/states_screens/gp_info_screen.cpp:78 +msgid "None" +msgstr "არცერთი" + +#: src/race/grand_prix_data.cpp:645 src/states_screens/gp_info_screen.cpp:80 +msgid "Random" +msgstr "შემთხვევითი" + +#: src/race/highscore_manager.cpp:102 +msgid "" +"The highscore file was too old,\n" +"all highscores have been erased." +msgstr "" + +#. I18N: Game mode +#: src/race/race_manager.cpp:1294 +msgid "Follow the Leader" +msgstr "" + +#. I18N: Game mode +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 +msgid "3 Strikes Battle" +msgstr "" + +#: src/replay/replay_recorder.cpp:358 +msgid "Incomplete replay file will not be saved." +msgstr "" + +#: src/replay/replay_recorder.cpp:394 +#, c-format +msgid "Replay saved in \"%s\"." +msgstr "" + +#: src/states_screens/addons_screen.cpp:51 +msgid "1 week" +msgstr "1 კვირა" + +#: src/states_screens/addons_screen.cpp:52 +msgid "2 weeks" +msgstr "2 კვირა" + +#: src/states_screens/addons_screen.cpp:53 +msgid "1 month" +msgstr "1 თვე" + +#: src/states_screens/addons_screen.cpp:54 +msgid "3 months" +msgstr "" + +#: src/states_screens/addons_screen.cpp:55 +msgid "6 months" +msgstr "ექვსი თვე" + +#: src/states_screens/addons_screen.cpp:56 +msgid "9 months" +msgstr "" + +#: src/states_screens/addons_screen.cpp:57 +msgid "1 year" +msgstr "1 წელი" + +#: src/states_screens/addons_screen.cpp:58 +msgid "2 years" +msgstr "" + +#: src/states_screens/addons_screen.cpp:109 +msgid "Add-on name" +msgstr "" + +#: src/states_screens/addons_screen.cpp:110 +msgid "Updated date" +msgstr "განახლებული თარიღი" + +#. I18N: Addon not installed for fillter +#: src/states_screens/addons_screen.cpp:140 +msgid "Not installed" +msgstr "დაყენებული არაა" + +#. I18N: as in: The Old Island by Johannes Sjolund +#: src/states_screens/addons_screen.cpp:326 +#, c-format +msgctxt "addons" +msgid "%s by %s" +msgstr "" + +#: src/states_screens/addons_screen.cpp:447 +msgid "Please wait while addons are updated" +msgstr "" + +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 +msgid "" +"Sorry, an error occurred while contacting the add-ons website. Make sure you" +" are connected to the Internet and that SuperTuxKart is not blocked by a " +"firewall" +msgstr "" + +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "სანიშნეები" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 +#: src/states_screens/race_setup_screen.cpp:101 +msgid "Locked : solve active challenges to gain access to more!" +msgstr "" + +#: src/states_screens/arenas_screen.cpp:351 +msgid "Random Arena" +msgstr "" + +#: src/states_screens/credits.cpp:184 +msgid "translator-credits" +msgstr "თემური დოღონაძე" + +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:65 +msgctxt "achievement_info" +msgid "Subgoals" +msgstr "" + +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:67 +msgctxt "achievement_info" +msgid "Progress" +msgstr "მიმდინარეობა" + +#. I18N: For achievements, a parent goal linking logically several subgoals +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:162 +msgid "Fulfill all the subgoals" +msgstr "" + +#. I18N: For achievements, a parent goal linking logically several subgoals +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:164 +msgid "Fulfill all the subgoals at the same time" +msgstr "" + +#. I18N: For achievements, a parent goal linking logically several subgoals +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:166 +msgid "Fulfill at least one subgoal" +msgstr "" + +#. I18N: For achievements, a parent goal linking logically several subgoals +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:168 +msgid "The sum of the subgoals must reach the indicated value" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:170 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:276 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:301 +msgid "Races won" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:172 +msgid "Normal races won" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:174 +msgid "Time-trial races won" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:176 +msgid "Follow-the-Leader races won" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:178 +msgid "Consecutive won races" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:180 +msgid "Consecutive won races in Expert or SuperTux" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:182 +msgid "Novice races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:184 +msgid "Novice races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:186 +msgid "Intermediate races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:188 +msgid "Intermediate races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:190 +msgid "Expert races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:192 +msgid "Expert races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:194 +msgid "SuperTux races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:196 +msgid "SuperTux races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:198 +msgid "Normal races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:200 +msgid "Normal races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:202 +msgid "Time-trial races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:204 +msgid "Time-trial races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:206 +msgid "Follow-the-Leader races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:208 +msgid "Follow-the-Leader races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:210 +msgid "3 Strikes battles started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:212 +msgid "3 Strikes battles finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:214 +msgid "Soccer matches started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:216 +msgid "Soccer matches finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:218 +msgid "Egg Hunts started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:220 +msgid "Egg Hunts finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:222 +msgid "Races started with a ghost replay" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:224 +msgid "Races finished with a ghost replay" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:226 +msgid "Capture-the-Flag matches started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:228 +msgid "Capture-the-Flag matches finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:230 +msgid "Free-for-All matches started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:232 +msgid "Free-for-All matches finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:234 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:236 +msgid "Powerups used" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:236 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:240 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:244 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:248 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:250 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:254 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:262 +msgid " (1 race)" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:238 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:240 +msgid "Bowling ball hits" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:242 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:244 +msgid "Swatter hits" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:246 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:248 +msgid "All hits" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:250 +msgid "Hits against the same kart" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:252 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:254 +msgid "Bananas collected" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#. I18N: Key binding name +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 +#: src/states_screens/options/options_screen_device.cpp:264 +msgid "Skidding" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:269 +msgid " (1 lap)" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:272 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:297 +msgid "Races started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:272 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:274 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:276 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:278 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:280 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:282 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:284 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:286 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:288 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:294 +msgid " (maximum on one official track)" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:274 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:299 +msgid "Races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:278 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:303 +msgid "Reverse direction races finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:280 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:305 +msgid "Races finished alone" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:282 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:307 +msgid "Races with less than the default lap number" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:284 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:309 +msgid "Races with more than the default lap number" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:286 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:311 +msgid "Races with at least twice as much as the default lap number" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:288 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:313 +msgid "Egg hunts started" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:292 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:317 +msgid "Egg hunts finished" +msgstr "" + +#. I18N: A goal for achievements. If this text is in (), it's a precision +#. added to multiple different goals. +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:297 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:299 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:301 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:303 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:305 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:307 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:309 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:311 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:313 +#: src/states_screens/dialogs/achievement_progress_dialog.cpp:319 +msgid " (official tracks matching the goal)" +msgstr "" + +#: src/states_screens/dialogs/add_device_dialog.cpp:48 +msgid "" +"New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" +"\n" +"To add a keyboard config, you can use the button below, HOWEVER please note that most keyboards only support a limited amount of simultaneous keypresses and are thus inappropriate for multiplayer gameplay. (You can, however, connect multiple keyboards to this device. Remember that everyone still needs different keybindings in this case.)" +msgstr "" + +#. I18N: In the 'add new input device' dialog +#: src/states_screens/dialogs/add_device_dialog.cpp:71 +msgid "Add Wiimote" +msgstr "" + +#. I18N: In the 'add new input device' dialog +#: src/states_screens/dialogs/add_device_dialog.cpp:88 +msgid "Add Keyboard Configuration" +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:126 +msgid "Update" +msgstr "განახლება" + +#: src/states_screens/dialogs/addons_loading.cpp:138 +#, c-format +msgid "Version: %d" +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:169 +msgid "featured" +msgstr "" + +#. I18N: File size of game assets or addons downloading +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 +#, c-format +msgid "Size: %s" +msgstr "ზომა: %s" + +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 +msgid "Sorry, downloading the add-on failed" +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:391 +#, c-format +msgid "Problems installing the addon '%s'." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 +msgid "Try again" +msgstr "კიდევ სცადეთ" + +#: src/states_screens/dialogs/addons_loading.cpp:442 +#, c-format +msgid "Problems removing the addon '%s'." +msgstr "" + +#: src/states_screens/dialogs/addons_pack.cpp:71 +msgid "Background download completed." +msgstr "" + +#: src/states_screens/dialogs/addons_pack.cpp:132 +msgid "Background download" +msgstr "" + +#: src/states_screens/dialogs/addons_pack.cpp:141 +msgid "Background download has already started." +msgstr "" + +#: src/states_screens/dialogs/change_password_dialog.cpp:140 +msgid "Current password invalid." +msgstr "" + +#: src/states_screens/dialogs/change_password_dialog.cpp:146 +#: src/states_screens/online/register_screen.cpp:382 +msgid "Password has to be between 8 and 30 characters long!" +msgstr "" + +#: src/states_screens/dialogs/change_password_dialog.cpp:153 +#: src/states_screens/online/register_screen.cpp:358 +msgid "Passwords don't match!" +msgstr "" + +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 +#: src/states_screens/online/register_screen.cpp:448 +msgid "Validating info" +msgstr "" + +#: src/states_screens/dialogs/change_password_dialog.cpp:250 +msgid "Password successfully changed." +msgstr "" + +#. I18N: In the 'confirm resolution' dialog, that's shown when switching +#. resoluton +#: src/states_screens/dialogs/confirm_resolution_dialog.cpp:86 +#, c-format +msgid "Confirm resolution within %i second" +msgid_plural "Confirm resolution within %i seconds" +msgstr[0] "" +msgstr[1] "" + +#: src/states_screens/dialogs/confirm_resolution_dialog.cpp:93 +msgid "" +"Resolutions smaller than 1024x768 or 1280x720 are unsupported. Some parts of" +" the UI may not work correctly." +msgstr "" + +#. I18N: In the UI options, Camera setting: Drone chase +#: src/states_screens/dialogs/custom_camera_settings.cpp:86 +#: src/states_screens/options/options_screen_ui.cpp:126 +msgid "Drone chase" +msgstr "" + +#. I18N: In the UI options, Camera setting: Custom +#. I18N: custom video settings +#: src/states_screens/dialogs/custom_camera_settings.cpp:103 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 +msgid "Custom" +msgstr "ხელით" + +#. I18N: in the graphical options tooltip; +#. indicates a graphical feature is disabled +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 +msgid "Disabled" +msgstr "გამორთული" + +#. I18N: if only important particles effects is enabled +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 +msgid "Important only" +msgstr "" + +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 +msgid "Very Low" +msgstr "ძალიან დაბალი" + +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 +msgid "Low" +msgstr "დაბალი" + +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "საშუალო" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 +msgid "High" +msgstr "მაღალი" + +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "ძალიან მაღალი" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "" + +#. I18N: In download assets dialog +#: src/states_screens/dialogs/download_assets.cpp:113 +msgid "" +"SuperTuxKart will download full assets (including high quality textures and " +"music) for better gaming experience, this will use your mobile data if you " +"don't have a wifi connection." +msgstr "" + +#. I18N: In download assets dialog +#: src/states_screens/dialogs/download_assets.cpp:121 +msgid "" +"SuperTuxKart will download full assets (including high quality textures and " +"music) for better gaming experience." +msgstr "" + +#: src/states_screens/dialogs/enter_address_dialog.cpp:42 +msgid "" +"Enter the server address optionally followed by : and then port or select " +"address from list." +msgstr "" + +#: src/states_screens/dialogs/enter_address_dialog.cpp:124 +#, c-format +msgid "Invalid server address: %s." +msgstr "" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 +msgctxt "column_name" +msgid "Reverse" +msgstr "რევერსი" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/online/server_selection.cpp:135 +msgctxt "column_name" +msgid "Difficulty" +msgstr "სირთულე" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 +msgctxt "column_name" +msgid "Laps" +msgstr "წრე" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 +msgctxt "column_name" +msgid "Time" +msgstr "დრო" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 +msgctxt "column_name" +msgid "Kart" +msgstr "" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 +msgctxt "column_name" +msgid "User" +msgstr "მომხმარებელი" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 +msgctxt "column_name" +msgid "Version" +msgstr "ვერსია" + +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 +#: src/states_screens/edit_gp_screen.cpp:261 +#: src/states_screens/ghost_replay_selection.cpp:394 +#: src/states_screens/high_score_selection.cpp:265 +msgid "No" +msgstr "" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 +#: src/states_screens/edit_gp_screen.cpp:151 +#: src/states_screens/high_score_selection.cpp:141 +msgid "Track" +msgstr "ტრეკი" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 +#, c-format +msgid "Top %d High Scores" +msgstr "" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 +#, c-format +msgid "Number of karts: %d" +msgstr "" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 +#, c-format +msgid "Time target: %s" +msgstr "" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 +#, c-format +msgid "Laps: %d" +msgstr "" + +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 +#, c-format +msgid "Reverse: %s" +msgstr "" + +#. I18N: for empty highscores entries +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 +msgid "(Empty)" +msgstr "(ცარიელი)" + +#. I18N: In kart color choosing dialog +#: src/states_screens/dialogs/kart_color_slider_dialog.cpp:47 +msgid "Use original color" +msgstr "" + +#. I18N: In kart color choosing dialog +#: src/states_screens/dialogs/kart_color_slider_dialog.cpp:49 +msgid "Pick a color from slider" +msgstr "" + +#: src/states_screens/dialogs/message_dialog.cpp:145 +msgid "Don't show again" +msgstr "მეორედ არ მაჩვენო" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:50 +msgid "Player info" +msgstr "" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:55 +#, c-format +msgid "Player name: %s" +msgstr "" + +#. I18N: In the network player dialog, show the player location with +#. country name (based on IP geolocation) +#: src/states_screens/dialogs/network_player_dialog.cpp:64 +#, c-format +msgid "Player location: %s" +msgstr "" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:108 +msgid "Kick" +msgstr "გაგდება" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:124 +msgid "Change team" +msgstr "" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:139 +msgid "Enable handicap" +msgstr "" + +#. I18N: In the network player dialog +#: src/states_screens/dialogs/network_player_dialog.cpp:144 +msgid "Disable handicap" +msgstr "" + +#. I18N: In the network player dialog, +#. report player about for example abusive behaviour in game +#: src/states_screens/dialogs/network_player_dialog.cpp:159 +msgid "Report player" +msgstr "" + +#. I18N: In the network player dialog, showing when waiting for +#. the result of the ranking info of a player +#: src/states_screens/dialogs/network_player_dialog.cpp:181 +#: src/states_screens/dialogs/player_rankings_dialog.cpp:141 +#, c-format +msgid "Fetching ranking info for %s" +msgstr "" + +#. I18N: In the network player dialog, instruction for reporting player +#: src/states_screens/dialogs/network_player_dialog.cpp:194 +#, c-format +msgid "Tell server administrator about this player (%s):" +msgstr "" + +#. I18N: In press a key dialog, tell user to press a key to bind configuration +#: src/states_screens/dialogs/press_a_key_dialog.cpp:43 +msgid "" +"Press any key...\n" +"(Press ESC to cancel)" +msgstr "" + +#: src/states_screens/dialogs/press_a_key_dialog.cpp:49 +msgid "Press any key..." +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:117 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 +msgid "Chat is disabled, enable in options menu." +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +msgid "Back to Battle" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 +msgid "Setup New Game" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 +msgid "Restart Battle" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 +msgid "Exit Battle" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 +msgid "Setup New Race" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 +msgid "Exit Race" +msgstr "" + +#. I18N: In the network player dialog, indiciating a network +#. player has no ranking +#: src/states_screens/dialogs/ranking_callback.hpp:44 +#, c-format +msgid "%s has no ranking yet." +msgstr "" + +#: src/states_screens/dialogs/ranking_callback.hpp:56 +#, c-format +msgid "%s is number %d in the rankings with a score of %f." +msgstr "" + +#: src/states_screens/dialogs/recovery_dialog.cpp:124 +msgid "Username and/or email address invalid." +msgstr "" + +#: src/states_screens/dialogs/registration_dialog.cpp:43 +#, c-format +msgid "" +"Please read the terms and conditions for SuperTuxKart at '%s'. You must " +"agree to these terms in order to register an account for STK. If you have " +"any questions or comments regarding these terms, one of the members of the " +"development team would gladly assist you." +msgstr "" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:60 +msgid "Nitro challenge" +msgstr "" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:65 +#: src/states_screens/race_setup_screen.cpp:137 +msgid "Ghost replay race" +msgstr "" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:72 +#: src/states_screens/race_result_gui.cpp:2074 +#, c-format +msgid "Laps: %i" +msgstr "" + +#. I18N: In the Select challenge dialog, type of this challenge +#: src/states_screens/dialogs/select_challenge.cpp:82 +#, c-format +msgid "Type: %s" +msgstr "ტიპი: %s" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:90 +#: src/states_screens/race_result_gui.cpp:2249 +#, c-format +msgid "Required Rank: %i" +msgstr "" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:96 +#: src/states_screens/race_result_gui.cpp:2258 +#, c-format +msgid "Required Time: %i" +msgstr "" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:103 +#: src/states_screens/race_result_gui.cpp:2270 +#, c-format +msgid "Required Nitro Points: %i" +msgstr "" + +#. I18N: In the Select challenge dialog +#: src/states_screens/dialogs/select_challenge.cpp:109 +#, c-format +msgid "Number of AI Karts: %i" +msgstr "" + +#. I18N: In the create server screen, show various battle mode available +#: src/states_screens/dialogs/server_configuration_dialog.cpp:158 +#: src/states_screens/online/create_server_screen.cpp:238 +msgid "Battle mode" +msgstr "" + +#. I18N: In the create server screen +#: src/states_screens/dialogs/server_configuration_dialog.cpp:171 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 +msgid "Soccer game type" +msgstr "" + +#. I18N: In the server info dialog, show the server location with +#. country name (based on IP geolocation) +#: src/states_screens/dialogs/server_info_dialog.cpp:111 +#, c-format +msgid "Server location: %s" +msgstr "" + +#. I18N: In server info dialog, showing the current track playing in server +#: src/states_screens/dialogs/server_info_dialog.cpp:120 +#, c-format +msgid "Current track: %s" +msgstr "" + +#: src/states_screens/dialogs/server_info_dialog.cpp:130 +msgid "Rank" +msgstr "რანგი" + +#. I18N: Show above the player list in server info dialog, tell +#. the user name on server +#: src/states_screens/dialogs/server_info_dialog.cpp:133 +msgid "Player" +msgstr "დამკვრელი" + +#. I18N: Show above the player list in server info dialog, tell +#. the scores of user calculated by player rankings +#: src/states_screens/dialogs/server_info_dialog.cpp:136 +msgid "Scores" +msgstr "ქულები" + +#. I18N: Show above the player list in server info dialog, tell +#. the user time played on server +#: src/states_screens/dialogs/server_info_dialog.cpp:139 +msgid "Time played" +msgstr "" + +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 +msgid "Remove from bookmarks" +msgstr "სანიშნეებიდან წაშლა" + +#: src/states_screens/dialogs/splitscreen_player_dialog.cpp:130 +msgid "Input device already exists." +msgstr "" + +#: src/states_screens/dialogs/splitscreen_player_dialog.cpp:147 +msgid "No player available for connecting to server." +msgstr "" + +#. I18N: In the user info dialog +#: src/states_screens/dialogs/user_info_dialog.cpp:61 +#, c-format +msgid "Username: %s" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:65 +msgid "Cancel Request" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 +msgid "Today" +msgstr "დღეს" + +#: src/states_screens/dialogs/user_info_dialog.cpp:169 +msgid "Friend request sent!" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:226 +msgid "Friend request accepted!" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:278 +msgid "Friend request declined!" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:324 +msgid "Friend removed!" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:375 +msgid "Friend request cancelled!" +msgstr "" + +#: src/states_screens/dialogs/user_info_dialog.cpp:485 +msgid "Processing" +msgstr "დამუშავება" + +#: src/states_screens/dialogs/vote_dialog.cpp:178 +msgid "Fetching last vote" +msgstr "" + +#: src/states_screens/dialogs/vote_dialog.cpp:197 +msgid "You can adapt your previous rating by clicking the stars beneath." +msgstr "" + +#: src/states_screens/dialogs/vote_dialog.cpp:202 +msgid "" +"You have not yet voted for this addon. Select your desired rating by " +"clicking the stars beneath" +msgstr "" + +#: src/states_screens/dialogs/vote_dialog.cpp:236 +msgid "Vote successful! You can now close the window." +msgstr "" + +#: src/states_screens/dialogs/vote_dialog.cpp:253 +msgid "Performing vote" +msgstr "" + +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 +msgid "Random Track" +msgstr "" + +#: src/states_screens/edit_gp_screen.cpp:117 +#: src/states_screens/ghost_replay_selection.cpp:513 +#: src/states_screens/grand_prix_editor_screen.cpp:111 +#, c-format +msgid "Are you sure you want to remove '%s'?" +msgstr "" + +#: src/states_screens/edit_gp_screen.cpp:134 +#: src/states_screens/edit_gp_screen.cpp:382 +msgid "Do you want to save your changes?" +msgstr "გნებავთ თქვენი ცვლილებების შენახვა?" + +#: src/states_screens/edit_gp_screen.cpp:152 +msgid "Laps" +msgstr "წრე" + +#: src/states_screens/edit_gp_screen.cpp:153 +msgid "Reversed" +msgstr "შებრუნებულია" + +#. I18N: Indicate that the grand prix is modified and not saved +#: src/states_screens/edit_gp_screen.cpp:290 +#, c-format +msgid "%s (+)" +msgstr "" + +#: src/states_screens/edit_gp_screen.cpp:330 +msgid "An error occurred while trying to save your grand prix." +msgstr "" + +#: src/states_screens/edit_track_screen.cpp:317 +msgid "Select a track" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:254 +#, c-format +msgid "You completed the easy challenge! Points earned on this level: %i/%i" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:260 +#, c-format +msgid "" +"You completed the intermediate challenge! Points earned on this level: %i/%i" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:266 +#, c-format +msgid "" +"You completed the difficult challenge! Points earned on this level: %i/%i" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:272 +#, c-format +msgid "" +"You completed the SuperTux challenge! Points earned on this level: %i/%i" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:315 +#, c-format +msgid "You unlocked %s!" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:645 +msgid "Challenge Completed" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:684 +msgid "You unlocked track %0" +msgstr "" + +#: src/states_screens/feature_unlocked.cpp:730 +msgid "You unlocked grand prix %0" +msgstr "" + +#: src/states_screens/ghost_replay_selection.cpp:157 +msgctxt "column_name" +msgid "Track" +msgstr "ტრეკი" + +#: src/states_screens/ghost_replay_selection.cpp:168 +#: src/states_screens/online/server_selection.cpp:134 +msgctxt "column_name" +msgid "Players" +msgstr "მოთამაშეები" + +#: src/states_screens/gp_info_screen.cpp:172 +#: src/states_screens/gp_info_screen.cpp:230 +msgid "Reload" +msgstr "თავიდან ჩატვირთვა" + +#: src/states_screens/grand_prix_cutscene.cpp:77 +#: src/states_screens/grand_prix_editor_screen.cpp:100 +#: src/states_screens/grand_prix_editor_screen.cpp:117 +msgid "Please enter the name of the grand prix" +msgstr "" + +#: src/states_screens/grand_prix_editor_screen.cpp:168 +msgid "Please select a Grand Prix" +msgstr "" + +#: src/states_screens/grand_prix_editor_screen.cpp:338 +msgid "User defined" +msgstr "მომხმარებლის მიერ განსაზღვრული" + +#: src/states_screens/grand_prix_editor_screen.cpp:351 +msgid "Name is empty." +msgstr "სახელი ცარიელია." + +#: src/states_screens/grand_prix_editor_screen.cpp:359 +msgid "Another grand prix with this name already exists." +msgstr "" + +#: src/states_screens/grand_prix_editor_screen.cpp:365 +msgid "Name is too long." +msgstr "" + +#. I18N: when failing a GP +#: src/states_screens/grand_prix_lose.cpp:157 +msgid "Better luck next time!" +msgstr "" + +#: src/states_screens/grand_prix_win.cpp:169 +msgid "You completed a challenge!" +msgstr "" + +#: src/states_screens/grand_prix_win.cpp:325 +msgid "You won the Grand Prix!" +msgstr "" + +#: src/states_screens/grand_prix_win.cpp:326 +msgid "You completed the Grand Prix!" +msgstr "" + +#: src/states_screens/high_score_selection.cpp:147 +msgctxt "column_name" +msgid "Number of karts" +msgstr "" + +#: src/states_screens/high_score_selection.cpp:352 +msgid "Are you sure you want to remove this high score entry?" +msgstr "" + +#: src/states_screens/high_score_selection.cpp:360 +msgid "Are you sure you want to remove all of your high scores?" +msgstr "" + +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "რჩეული" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "ღია" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "მძიმე" + +#: src/states_screens/kart_selection.cpp:490 +msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" +msgstr "" + +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 +msgid "Random Kart" +msgstr "" + +#: src/states_screens/kart_selection.cpp:1003 +msgid "Locked" +msgstr "დაბლოკილია" + +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 +msgid "" +"Everyone:\n" +"Press the 'Select' button to join the game" +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:343 +msgid "Would you like to play the tutorial of the game?" +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 +msgid "" +"You can not play online without internet access. If you want to play online," +" go in the options menu, and check \"Connect to the Internet\"." +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:619 +msgid "" +"You can not download addons without internet access. If you want to download" +" addons, go in the options menu, and check \"Connect to the Internet\"." +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:627 +msgid "" +"You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" +"\n" +"You can however delete already downloaded addons." +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:666 +msgid "The add-ons module is currently disabled in the Options screen" +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:678 +msgid "Please wait while the add-ons are loading" +msgstr "" + +#: src/states_screens/main_menu_screen.cpp:699 +msgid "Are you sure you want to quit STK?" +msgstr "" + +#: src/states_screens/online/create_server_screen.cpp:107 +msgid "Create LAN Server" +msgstr "" + +#: src/states_screens/online/create_server_screen.cpp:112 +#, c-format +msgid "%s's server" +msgstr "" + +#. I18N: In the create server screen +#: src/states_screens/online/create_server_screen.cpp:220 +msgid "No. of grand prix track(s)" +msgstr "" + +#: src/states_screens/online/create_server_screen.cpp:303 +msgid "Name has to be between 4 and 30 characters long!" +msgstr "" + +#: src/states_screens/online/create_server_screen.cpp:320 +msgid "Incorrect characters in password!" +msgstr "" + +#. I18N: In the networking lobby, ready button is to allow player to tell +#. server that he is ready for next game for owner less server +#: src/states_screens/online/networking_lobby.cpp:196 +msgid "Ready" +msgstr "მზადაა" + +#. I18N: Live join is displayed in networking lobby to allow players +#. to join the current started in-progress game +#: src/states_screens/online/networking_lobby.cpp:199 +msgid "Live join" +msgstr "" + +#. I18N: Spectate is displayed in networking lobby to allow players +#. to join the current started in-progress game +#: src/states_screens/online/networking_lobby.cpp:204 +msgid "Spectate" +msgstr "ყურება" + +#: src/states_screens/online/networking_lobby.cpp:205 +msgid "Install addon" +msgstr "" + +#. I18N: In the networking lobby, show when player is required to +#. wait before the current game finish with remaining time, +#. showing the current track name inside bracket +#: src/states_screens/online/networking_lobby.cpp:572 +#, c-format +msgid "" +"Please wait for the current game's (%s) end, estimated remaining time: %s." +msgstr "" + +#. I18N: In the networking lobby, show when player is required +#. to wait before the current game finish with remaining time +#: src/states_screens/online/networking_lobby.cpp:580 +#, c-format +msgid "Please wait for the current game's end, estimated remaining time: %s." +msgstr "" + +#. I18N: In the networking lobby, show when player is required +#. to wait before the current game finish with progress in +#. percent, showing the current track name inside bracket +#: src/states_screens/online/networking_lobby.cpp:592 +msgid "Please wait for the current game's (%s) end, estimated progress: %s%." +msgstr "" + +#. I18N: In the networking lobby, show when player is required +#. to wait before the current game finish with progress in +#. percent +#: src/states_screens/online/networking_lobby.cpp:601 +msgid "Please wait for the current game's end, estimated progress: %d%." +msgstr "" + +#. I18N: In the networking lobby, show when player is required to +#. wait before the current game finish +#: src/states_screens/online/networking_lobby.cpp:609 +msgid "Please wait for the current game's end." +msgstr "" + +#: src/states_screens/online/networking_lobby.cpp:676 +#, c-format +msgid "Game will start if there is more than %d player." +msgid_plural "Game will start if there are more than %d players." +msgstr[0] "" +msgstr[1] "" + +#. I18N: In the networking lobby, display the starting timeout +#. for owner-less server to begin a game +#: src/states_screens/online/networking_lobby.cpp:690 +#, c-format +msgid "" +"Starting after %d second, or once everyone has pressed the 'Ready' button." +msgid_plural "" +"Starting after %d seconds, or once everyone has pressed the 'Ready' button." +msgstr[0] "" +msgstr[1] "" + +#: src/states_screens/online/networking_lobby.cpp:727 +#, c-format +msgid "Connecting to server %s" +msgstr "" + +#: src/states_screens/online/networking_lobby.cpp:732 +msgid "Finding a quick play server" +msgstr "" + +#. I18N: In kart screen, show before the voting period in network ends. +#: src/states_screens/online/network_kart_selection.cpp:218 +#: src/states_screens/online/tracks_screen.cpp:952 +#, c-format +msgid "Remaining time: %d" +msgstr "" + +#. I18N: Goals in achievement +#: src/states_screens/online/online_profile_achievements.cpp:85 +msgid "Goals" +msgstr "მიზნებ" + +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 +msgid "Fetching achievements" +msgstr "" + +#: src/states_screens/online/online_profile_base.cpp:121 +#, c-format +msgid "%s's profile" +msgstr "" + +#: src/states_screens/online/online_profile_friends.cpp:80 +msgid "Since" +msgstr "საწყისი დრო" + +#: src/states_screens/online/online_profile_friends.cpp:81 +msgid "Status" +msgstr "სტატუსი" + +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 +msgid "Fetching friends" +msgstr "" + +#: src/states_screens/online/online_profile_friends.cpp:241 +msgid "New Request" +msgstr "" + +#: src/states_screens/online/online_profile_friends.cpp:242 +msgid "Pending" +msgstr "დარჩენილი" + +#: src/states_screens/online/online_profile_friends.cpp:246 +msgid "Offline" +msgstr "ინტერნეტგარეშე" + +#: src/states_screens/online/online_profile_settings.cpp:83 +msgid "Enter new E-mail below" +msgstr "" + +#: src/states_screens/online/online_profile_settings.cpp:88 +msgid "New Email has to be between 5 and 254 characters long!" +msgstr "" + +#: src/states_screens/online/online_profile_settings.cpp:97 +msgid "New Email is invalid!" +msgstr "" + +#: src/states_screens/online/online_profile_settings.cpp:122 +msgid "E-mail changed!" +msgstr "" + +#: src/states_screens/online/online_profile_settings.cpp:124 +#, c-format +msgid "Failed to change E-mail: %s" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "თარიღი" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + +#. I18N: Shown to players when he is not is not logged in +#: src/states_screens/online/online_screen.cpp:317 +msgid "" +"You must be logged in to play Global networking. Click your username above." +msgstr "" + +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 +msgid "Searching" +msgstr "ძებნა" + +#: src/states_screens/online/register_screen.cpp:169 +#: src/states_screens/options/user_screen.cpp:114 +msgid "Exit game" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:282 +#: src/states_screens/online/register_screen.cpp:289 +#, c-format +msgid "Could not create player '%s'." +msgstr "" + +#: src/states_screens/online/register_screen.cpp:306 +msgid "User name cannot be empty." +msgstr "" + +#: src/states_screens/online/register_screen.cpp:362 +msgid "Online username and password must not be the same!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:366 +msgid "Emails don't match!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:370 +msgid "" +"Online username can only contain alphanumeric (ASCII) characters, periods, " +"dashes and underscores!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:374 +msgid "Online username has to be between 3 and 30 characters long!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:378 +msgid "Online username must not start with a number!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:386 +msgid "Email has to be between 5 and 254 characters long!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:392 +msgid "Email is invalid!" +msgstr "" + +#: src/states_screens/online/register_screen.cpp:456 +msgid "" +"You will receive an email with further instructions regarding account " +"activation. Please be patient and be sure to check your spam folder." +msgstr "" + +#: src/states_screens/online/register_screen.cpp:495 +msgid "Internet access is disabled, please enable it in the options" +msgstr "" + +#: src/states_screens/online/server_selection.cpp:132 +msgctxt "column_name" +msgid "Name" +msgstr "სახელი" + +#: src/states_screens/online/server_selection.cpp:133 +msgctxt "column_name" +msgid "Game mode" +msgstr "თამაშის რეჟიმი" + +#. I18N: In server selection screen, owner of server, only displayed +#. if it's localhost or friends' +#: src/states_screens/online/server_selection.cpp:140 +msgctxt "column_name" +msgid "Owner" +msgstr "მფლობელი" + +#. I18N: In server selection screen, distance to server +#: src/states_screens/online/server_selection.cpp:142 +msgctxt "column_name" +msgid "Distance (km)" +msgstr "" + +#. I18N: In server selection screen, unknown distance to server +#: src/states_screens/online/server_selection.cpp:316 +msgid "Unknown" +msgstr "უცნობი" + +#. I18N: Message shown to user if no IPv4 detected by STK +#: src/states_screens/online/server_selection.cpp:361 +msgid "No IPv4 detected, you may not be able to join any servers." +msgstr "" + +#. I18N: Message shown to user if no IPv6 detected by STK +#: src/states_screens/online/server_selection.cpp:363 +msgid "No IPv6 detected, you may not be able to join any servers." +msgstr "" + +#: src/states_screens/online/server_selection.cpp:502 +msgid "No server is available." +msgstr "" + +#: src/states_screens/online/server_selection.cpp:510 +msgid "Fetching servers" +msgstr "" + +#: src/states_screens/online/server_selection.cpp:576 +msgid "Server Bookmarks" +msgstr "" + +#. I18N: In track screen for networking, clarify voting phase +#: src/states_screens/online/tracks_screen.cpp:322 +msgid "" +"If a majority of players all select the same track and race settings, voting" +" will end early." +msgstr "" + +#. I18N: In track screen +#. I18N: In the track info screen +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 +msgid "Random item location" +msgstr "" + +#. I18N: In track screen +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 +msgid "Number of goals to win" +msgstr "" + +#. I18N: In the track info screen +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 +msgid "Drive in reverse" +msgstr "" + +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 +msgid "Locked: solve active challenges to gain access to more!" +msgstr "" + +#: src/states_screens/options/options_screen_device.cpp:56 +msgid "Action" +msgstr "ქმედება" + +#: src/states_screens/options/options_screen_device.cpp:57 +msgid "Key binding" +msgstr "ღილაკის მიბმა" + +#. I18N: button to disable a gamepad configuration +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 +msgid "Disable Device" +msgstr "" + +#. I18N: button to enable a gamepad configuration +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 +msgid "Enable Device" +msgstr "" + +#. I18N: button to enable a keyboard configuration +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 +msgid "Enable Configuration" +msgstr "" + +#. I18N: Key binding section +#: src/states_screens/options/options_screen_device.cpp:156 +msgid "Game Keys" +msgstr "" + +#. I18N: Key binding section +#: src/states_screens/options/options_screen_device.cpp:170 +msgid "Menu Keys" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:246 +msgid "Steer Left" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:249 +msgid "Steer Right" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:252 +msgid "Accelerate" +msgstr "აჩქარება" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:255 +msgid "Brake / Reverse" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:258 +msgid "Fire" +msgstr "ცეცხლი" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:261 +msgid "Nitro" +msgstr "ნიტრო" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:267 +msgid "Look Back" +msgstr "" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:270 +msgid "Rescue" +msgstr "შველა" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:273 +msgid "Pause Game" +msgstr "თამაშის შეჩერება" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:278 +msgid "Up" +msgstr "ჩართული" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:281 +msgid "Down" +msgstr "ქვემოთ" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:284 +msgid "Left" +msgstr "წავიდა" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:287 +msgid "Right" +msgstr "მარჯვნივ" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:290 +msgid "Select" +msgstr "არჩევა" + +#. I18N: Key binding name +#: src/states_screens/options/options_screen_device.cpp:293 +msgid "Cancel/Back" +msgstr "" + +#: src/states_screens/options/options_screen_device.cpp:384 +msgid "* A blue item means a conflict with another configuration" +msgstr "" + +#: src/states_screens/options/options_screen_device.cpp:389 +msgid "* A red item means a conflict in the current configuration" +msgstr "" + +#: src/states_screens/options/options_screen_device.cpp:494 +msgid "" +"Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," +" all keys that contain a character that is different in upper-case will stop" +" working." +msgstr "" + +#. I18N: shown before deleting an input configuration +#: src/states_screens/options/options_screen_device.cpp:578 +msgid "Are you sure you want to permanently delete this configuration?" +msgstr "" + +#: src/states_screens/options/options_screen_device.cpp:606 +msgid "Enter new configuration name, leave empty to revert default value." +msgstr "" + +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "ვერტიკალური" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "ჰორიზონტალური" + +#. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text +#. fits the screen in low resolutions. +#: src/states_screens/options/options_screen_general.cpp:69 +msgid "" +"In multiplayer mode, players can select handicapped\n" +"(more difficult) profiles on the kart selection screen" +msgstr "" + +#. I18N: For mobile version for STK, install the full game assets which +#. will download from stk server +#: src/states_screens/options/options_screen_general.cpp:85 +msgid "Install full game assets" +msgstr "" + +#: src/states_screens/options/options_screen_general.cpp:189 +msgid "Are you sure to uninstall full game assets?" +msgstr "" + +#: src/states_screens/options/options_screen_input.cpp:98 +#, c-format +msgid "Keyboard %i" +msgstr "" + +#: src/states_screens/options/options_screen_input.cpp:149 +msgid "Touch Device" +msgstr "" + +#. I18N: In the input configuration screen, help for touch device +#: src/states_screens/options/options_screen_input.cpp:186 +msgid "Tap on a device to configure it" +msgstr "" + +#. I18N: in the language choice, to select the same language as the OS +#: src/states_screens/options/options_screen_language.cpp:62 +msgid "System Language" +msgstr "სისტემური ენა" + +#. I18N: In the UI options, minimap position in the race UI +#: src/states_screens/options/options_screen_ui.cpp:67 +msgid "In the bottom-left" +msgstr "" + +#. I18N: In the UI options, minimap position in the race UI +#: src/states_screens/options/options_screen_ui.cpp:69 +msgid "On the right side" +msgstr "მარჯვენა მხარეს" + +#. I18N: In the UI options, minimap position in the race UI +#: src/states_screens/options/options_screen_ui.cpp:71 +msgid "Hidden" +msgstr "დამალული" + +#. I18N: In the UI options, minimap position in the race UI +#: src/states_screens/options/options_screen_ui.cpp:73 +msgid "Centered" +msgstr "შუაზე გასწორებული" + +#. I18N: In the UI options, Very small font size +#: src/states_screens/options/options_screen_ui.cpp:92 +msgid "Very small" +msgstr "ძალიან პატარა" + +#. I18N: In the UI options, Small font size +#: src/states_screens/options/options_screen_ui.cpp:94 +msgid "Small" +msgstr "პატარა" + +#. I18N: In the UI options, Large font size +#: src/states_screens/options/options_screen_ui.cpp:98 +msgid "Large" +msgstr "დიდი" + +#. I18N: In the UI options, Very large font size +#: src/states_screens/options/options_screen_ui.cpp:100 +msgid "Very large" +msgstr "ძალიან დიდი" + +#: src/states_screens/options/options_screen_ui.cpp:537 +msgid "" +"Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" +"\n" +"Closing the game before the story mode's completion invalidates the timer.\n" +"\n" +"To use the speedrun mode, please use a new profile." +msgstr "" + +#. I18N: In the video options +#: src/states_screens/options/options_screen_video.cpp:249 +msgid "Vertical Sync" +msgstr "" + +#. I18N: in graphical options. The \n is a newline character, place it where +#. appropriate, two can be used if required. +#: src/states_screens/options/options_screen_video.cpp:266 +msgid "" +"Vsync forces the graphics card to supply a new frame\n" +"only when the monitor is ready to display it." +msgstr "" + +#. I18N: in graphical options. +#: src/states_screens/options/options_screen_video.cpp:269 +msgid "Vsync will not work if your drivers don't support it." +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:466 +#, c-format +msgid "Particles Effects: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:472 +#, c-format +msgid "Animated Characters: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:475 +#, c-format +msgid "Dynamic lights: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:478 +#, c-format +msgid "Light scattering: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:481 +#, c-format +msgid "Anti-aliasing: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:484 +#, c-format +msgid "Ambient occlusion: %s" +msgstr "" + +#: src/states_screens/options/options_screen_video.cpp:488 +#, c-format +msgid "Shadows: %s" +msgstr "" + +#: src/states_screens/options/options_screen_video.cpp:490 +#, c-format +msgid "Shadows: %i" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:493 +#, c-format +msgid "Bloom: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:497 +#, c-format +msgid "Glow (outlines): %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:501 +#, c-format +msgid "Light shaft (God rays): %s" +msgstr "" + +#: src/states_screens/options/options_screen_video.cpp:506 +#, c-format +msgid "Rendered image quality: %s" +msgstr "" + +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:538 +#, c-format +msgid "Motion blur: %s" +msgstr "" + +#. I18N: in graphical options +#: src/states_screens/options/options_screen_video.cpp:542 +#, c-format +msgid "Depth of field: %s" +msgstr "" + +#: src/states_screens/options/user_screen.cpp:353 +msgid "Internet access is disabled. Do you want to enable it?" +msgstr "" + +#: src/states_screens/options/user_screen.cpp:541 +msgid "You need to enter a password." +msgstr "" + +#: src/states_screens/options/user_screen.cpp:562 +#, c-format +msgid "Logging out '%s'" +msgstr "" + +#: src/states_screens/options/user_screen.cpp:563 +#, c-format +msgid "Logging in '%s'" +msgstr "" + +#: src/states_screens/options/user_screen.cpp:646 +msgid "You can't delete the only player." +msgstr "" + +#. I18N: In the player info dialog (when deleting) +#: src/states_screens/options/user_screen.cpp:654 +#, c-format +msgid "Do you really want to delete player '%s'?" +msgstr "" + +#. I18N: as in "ready, set, go", shown at the beginning of the race +#: src/states_screens/race_gui_base.cpp:73 +msgid "Ready!" +msgstr "" + +#. I18N: as in "ready, set, go", shown at the beginning of the race +#: src/states_screens/race_gui_base.cpp:75 +msgid "Set!" +msgstr "" + +#. I18N: as in "ready, set, go", shown at the beginning of the race +#: src/states_screens/race_gui_base.cpp:77 +msgid "Go!" +msgstr "წავიდა!" + +#. I18N: Shown when a goal is scored +#: src/states_screens/race_gui_base.cpp:79 +msgid "GOAL!" +msgstr "" + +#. I18N: Shown waiting for other players in network to finish loading or +#. waiting +#: src/states_screens/race_gui_base.cpp:82 +#: src/states_screens/race_result_gui.cpp:429 +msgid "Waiting for others" +msgstr "" + +#. I18N: Shown waiting for the server in network if live join or spectate +#: src/states_screens/race_gui_base.cpp:84 +msgid "Waiting for the server" +msgstr "" + +#. I18N: string used to show the song title (e.g. "Sunny Song") +#: src/states_screens/race_gui_base.cpp:646 +#, c-format +msgid "\"%s\"" +msgstr "\"%s\"" + +#. I18N: string used to show the author of the music. (e.g. "Sunny Song" by +#. "John Doe") +#: src/states_screens/race_gui_base.cpp:656 +msgid "by" +msgstr "" + +#: src/states_screens/race_gui_base.cpp:769 +msgid "Collect nitro!" +msgstr "" + +#: src/states_screens/race_gui_base.cpp:771 +msgid "Follow the leader!" +msgstr "" + +#. I18N: When some GlobalPlayerIcons are hidden, write "Top 10" to show it +#: src/states_screens/race_gui_base.cpp:954 +#, c-format +msgid "Top %i" +msgstr "" + +#: src/states_screens/race_gui.cpp:445 +msgid "Challenge Failed" +msgstr "" + +#. I18N: Shown when multitouch GUI exists +#. and press the podium (2, 1, 3 like) icon instead of fire button +#: src/states_screens/race_gui_overworld.cpp:541 +msgid "Press podium icon to start tutorial" +msgstr "" + +#: src/states_screens/race_gui_overworld.cpp:547 +msgid "Press fire to start the tutorial" +msgstr "" + +#. I18N: Shown when multitouch GUI exists +#. and press the podium (2, 1, 3 like) icon instead of fire button +#: src/states_screens/race_gui_overworld.cpp:623 +msgid "Press podium icon to start the challenge" +msgstr "" + +#: src/states_screens/race_gui_overworld.cpp:629 +msgid "Press fire to start the challenge" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:289 +msgid "Quit the server" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:330 +msgid "Abort Grand Prix" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:350 +msgid "Restart" +msgstr "თავიდან გაშვება" + +#: src/states_screens/race_result_gui.cpp:357 +msgid "Back to challenge selection" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:365 +msgid "Race against the new ghost replay" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:373 +msgid "Back to the menu" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:556 +msgid "Do you really want to abort the Grand Prix?" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 +msgid "Red Team Wins" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 +msgid "Blue Team Wins" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 +msgid "It's a draw" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:935 +#, c-format +msgid "Eliminated after %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 +msgid "Eliminated" +msgstr "" + +#. I18N: indicates a player that scored in their own goal in result screen +#: src/states_screens/race_result_gui.cpp:1681 +msgid "(Own Goal)" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:1770 +#, c-format +msgid "Track %i/%i" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:1889 +msgid "Grand Prix progress:" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:1975 +msgid "Highscores" +msgstr "უმაღლეს ქულები" + +#: src/states_screens/race_result_gui.cpp:2142 +#, c-format +msgid "Best lap time: %s" +msgstr "" + +#. I18N: is used to indicate who has the bast laptime (best laptime "by +#. kart_name") +#: src/states_screens/race_result_gui.cpp:2155 +#, c-format +msgid "by %s" +msgstr "%s-სგან" + +#: src/states_screens/race_result_gui.cpp:2229 +msgid "You completed the challenge!" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2229 +msgid "You failed the challenge!" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2282 +msgid "Reached Requirements of SuperTux" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + +#: src/states_screens/race_setup_screen.cpp:89 +msgid "All blows allowed, so catch weapons and make clever use of them!" +msgstr "" + +#: src/states_screens/race_setup_screen.cpp:96 +msgid "Contains no powerups, so only your driving skills matter!" +msgstr "" + +#. I18N: short definition for follow-the-leader game mode +#: src/states_screens/race_setup_screen.cpp:109 +msgid "Keep up with the leader kart but don't overtake it!" +msgstr "" + +#: src/states_screens/race_setup_screen.cpp:115 +msgid "Hit others with weapons until they lose all their lives." +msgstr "" + +#: src/states_screens/race_setup_screen.cpp:120 +msgid "Push the ball into the opposite cage to score goals." +msgstr "" + +#: src/states_screens/race_setup_screen.cpp:130 +msgid "Explore tracks to find all hidden eggs" +msgstr "" + +#: src/states_screens/race_setup_screen.cpp:138 +msgid "Race against ghost karts and try to beat them!" +msgstr "" + +#: src/states_screens/race_setup_screen.cpp:143 +msgid "Complete as many laps as possible in a given amount of time." +msgstr "" + +#. I18N: In soccer setup screen +#: src/states_screens/soccer_setup_screen.cpp:120 +msgid "Press red or blue soccer icon to change team" +msgstr "" + +#. I18N: when showing who is the author of track '%s' +#. I18N: (place %s where the name of the author should appear) +#: src/states_screens/track_info_screen.cpp:151 +#, c-format +msgid "Track by %s" +msgstr "" + +#. I18N: the max players supported by an arena. +#: src/states_screens/track_info_screen.cpp:159 +#, c-format +msgid "Max players supported: %d" +msgstr "" + +#: src/states_screens/track_info_screen.cpp:389 +msgid "Number of red team AI karts" +msgstr "" + +#: src/states_screens/tracks_and_gp_screen.cpp:124 +msgid "" +"You cannot play this Grand Prix because it contains tracks that aren't " +"unlocked!" +msgstr "" + +#: src/states_screens/tracks_and_gp_screen.cpp:245 +msgid "Locked!" +msgstr "" + +#: src/utils/string_utils.cpp:1242 +#, c-format +msgid "%s MB" +msgstr "%s მბ" + +#: src/utils/string_utils.cpp:1249 src/utils/string_utils.cpp:1253 +#, c-format +msgid "%s KB" +msgstr "%s კბ" + +#. I18N: Format for dates (%d = day, %m = month, %Y = year). See +#. http://www.cplusplus.com/reference/ctime/strftime/ for more info about date +#. formats. +#: src/utils/time.cpp:74 +msgid "%d/%m/%Y" +msgstr "" + +#: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 +msgid "Complete all challenges to unlock the big door!" +msgstr "" + +#: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 +msgid "" +"You need more points\n" +"to enter this challenge!\n" +"Check the minimap for\n" +"available challenges." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 +#, c-format +msgid "Accelerate with <%s>, and steer with <%s> and <%s>." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 +msgid "" +"Accelerate by touching the upper part of the wheel, and steer by moving left" +" or right." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 +msgid "" +"Accelerate by moving the accelerator upwards, and steer by tilting your " +"device." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 +msgid "" +"Accelerate by moving the accelerator upwards, and steer by rotating your " +"device." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 +#, c-format +msgid "" +"Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 +msgid "" +"Collect gift boxes, and fire by pressing the bowling icon to blow away these" +" boxes!" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 +#, c-format +msgid "" +"Press <%s> to look behind.\n" +"Fire the weapon with <%s> while pressing <%s> to fire behind!" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 +msgid "" +"Press the mirror icon to look behind.\n" +"Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 +#, c-format +msgid "Use the nitro you collected by pressing <%s>!" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 +msgid "Use the nitro you collected by pressing the nitro icon" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 +msgid "Collect nitro bottles (we will use them after the curve)." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 +#, c-format +msgid "Oops! When you're in trouble, press <%s> to be rescued." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 +msgid "Oops! When you're in trouble, press the bird icon to be rescued." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 +#, c-format +msgid "" +"Accelerate and press the <%s> key while turning to skid.\n" +"Skidding for a short while can help you turn faster to take sharp turns." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 +msgid "" +"Accelerate and press the skid icon while turning to skid.\n" +"Skidding for a short while can help you turn faster to take sharp turns." +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 +msgid "" +"Note that if you manage to skid for several seconds, you will receive a " +"bonus speedup as a reward!" +msgstr "" + +#: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 +msgid "You are now ready to race. Good luck!" +msgstr "" + +#. I18N: Generic name in desktop file entry, summary in AppData and short +#. description in Google Play +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 +msgid "A 3D open-source kart racing game" +msgstr "" + +#. I18N: Keywords in desktop entry, translators please keep it separated with +#. semicolons +#: supertuxkart.desktop:11 +msgid "tux;game;race;" +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 +msgid "" +"Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " +"variety of characters, tracks, and modes to play. Our aim is to create a " +"game that is more fun than realistic, and provide an enjoyable experience " +"for all ages." +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 +msgid "" +"We have several tracks with various themes for players to enjoy, from " +"driving underwater, rural farmlands, jungles or even in space! Try your best" +" while avoiding other karts as they may overtake you, but don't eat the " +"bananas! Watch for bowling balls, plungers, bubble gum, and cakes thrown by " +"your opponents." +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 +msgid "" +"You can do a single race against other karts, compete in one of several " +"Grand Prix, try to beat the high score in time trials on your own, play " +"battle mode against the computer or your friends, and more! For a greater " +"challenge, join online and meet players from all over the world and prove " +"your racing skills!" +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 +msgid "This game has no ads." +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 +msgid "" +"This is an unstable version of SuperTuxKart that contains latest " +"improvements. It is released mainly for testing, to make stable STK as good " +"as possible." +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 +msgid "" +"This version can be installed in parallel with the stable version on the " +"device." +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 +msgid "If you need more stability, consider using the stable version: %s" +msgstr "" + +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 +msgid "SuperTuxKart Team" +msgstr "" diff --git a/data/po/la.po b/data/po/la.po index 9d6d8c0552c..a0d346d5ff6 100644 --- a/data/po/la.po +++ b/data/po/la.po @@ -5,14 +5,15 @@ # Translators: # Alisa P , 2016 # André Lippok , 2016-2017 +# semi, 2024 # Supernova 888 , 2016 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Supernova 888 , 2016\n" +"Last-Translator: semi, 2024\n" "Language-Team: Latin (http://app.transifex.com/supertuxkart/supertuxkart/language/la/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -98,7 +99,7 @@ msgstr "Utere 10 vel plura adiumenta in cursu." #. I18N: ./data/achievements.xml msgid "Unstoppable" -msgstr "Prohiberi non posse" +msgstr "Insuperabilis" #. I18N: ./data/achievements.xml msgid "" @@ -130,11 +131,11 @@ msgstr "Venator culicidae" msgid "" "Take your opponents for mosquitos! With the swatter, squash them at least 5 " "times in a race." -msgstr "" +msgstr "Sint tibi nunc adversarii quasi culicidae! Comprime saltem 5 adversarios cum muscario in cursu ipso." #. I18N: ./data/achievements.xml msgid "Beyond Luck" -msgstr "" +msgstr "Ultra Fortunam" #. I18N: ./data/achievements.xml msgid "" @@ -152,11 +153,11 @@ msgstr "" #. I18N: ./data/grandprix/3_tothemoonandback.grandprix msgid "To the Moon and Back" -msgstr "" +msgstr "Ad Lunam et Prior" #. I18N: ./data/grandprix/4_atworldsend.grandprix msgid "At World's End" -msgstr "In extremo mundi" +msgstr "Ad Finem Mundi" #. I18N: ./data/gui/dialogs/addons_loading.stkgui #. I18N: Add-on screen action @@ -169,7 +170,7 @@ msgstr "In extremo mundi" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Retro" @@ -191,9 +192,9 @@ msgstr "" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" -msgstr "" +msgstr "Mensura celeritatis" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type @@ -205,15 +206,15 @@ msgstr "" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" -msgstr "" +msgstr "Circocustos" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" -msgstr "" +msgstr "Rota gubernationis" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui @@ -242,35 +243,37 @@ msgstr "" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Generalis" @@ -338,30 +341,33 @@ msgstr "" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Claudere" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Sic est" @@ -539,9 +545,9 @@ msgstr "Adjunge me" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -602,7 +608,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Progressio" @@ -637,7 +643,7 @@ msgstr "Mitte" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Redi cursum" @@ -654,7 +660,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Incipe iterum cursum" @@ -708,7 +714,7 @@ msgstr "Rationis reconciliatio" msgid "" "You will receive an email with further instructions on how to reset your " "password. Please be patient and be sure to check your spam folder." -msgstr "Litteras electronicas accipies cum praeceptione de renovando signi. Quaeso, expecta et etiam vide indicem litterarum malarum(spam folder)." +msgstr "Litteras electronicas accipies cum praeceptione de renovando signi. Quaeso, expecta et etiam vide indicem litterarum malarum (spam folder)." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui msgid "" @@ -718,12 +724,12 @@ msgstr "Scrib nomen usoris et inscriptio cursualis electronica tua, quae dedisti #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Nomen usoris" @@ -764,7 +770,7 @@ msgstr "Gradus difficultatis" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Infans" @@ -776,7 +782,7 @@ msgstr "Infans" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Adultus" @@ -788,7 +794,7 @@ msgstr "Adultus" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Artifex" @@ -800,7 +806,7 @@ msgstr "Artifex" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "Tux Maximus" @@ -808,8 +814,8 @@ msgstr "Tux Maximus" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Modus ludendi" @@ -820,8 +826,8 @@ msgstr "Modus ludendi" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Cursus solitus" @@ -834,7 +840,7 @@ msgstr "Cursus solitus" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Contra tempus" @@ -842,7 +848,8 @@ msgstr "Contra tempus" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "" @@ -851,24 +858,24 @@ msgstr "" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Pediludium" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Signum" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "" @@ -879,7 +886,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Nomen" @@ -973,6 +980,50 @@ msgstr "ESC clavem addicere" msgid "Assign nothing" msgstr "Assigna nihil" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -987,11 +1038,11 @@ msgstr "Praeparatio cursus" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Continuare" @@ -1032,10 +1083,15 @@ msgstr "Arenae" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1045,20 +1101,20 @@ msgstr "" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Norma" @@ -1069,12 +1125,12 @@ msgstr "Norma" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Additamenta" @@ -1088,27 +1144,28 @@ msgstr "Additamenta" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Omnes" @@ -1147,9 +1204,9 @@ msgstr "Descende" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Adde" @@ -1186,7 +1243,7 @@ msgstr "Optio iterum lundendi spiritus" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Ovorum venatio" @@ -1233,10 +1290,10 @@ msgstr "Rursus" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Tempus maximum (minutum)" @@ -1268,9 +1325,9 @@ msgstr "Copia" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1281,80 +1338,80 @@ msgstr "Novum nomen" msgid "Save Grand Prix" msgstr "Serva Grande Premium" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "SuperTuxKart auxilium" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Modi ludendi" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1362,56 +1419,57 @@ msgstr "" msgid "Story Mode" msgstr "Facinus audax" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Cede bananas!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1419,14 +1477,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Si videas clavem cum claustra ut hac, provocationem superandum sit." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1435,34 +1493,34 @@ msgid "" "carefully before!" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1470,7 +1528,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Sequere ducem: Es prope ducentem autocinetum, sed noli antecedere eum. Post brevi tempore postumum autocinetum eliminabitur, usque solus unus manet autocinetorum cum duce." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1480,30 +1538,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Pediludium: Pilam autocineto tuo in portam promove." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Ovorum venatio: Explora circos ut reperias occulta ova." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1512,93 +1570,93 @@ msgid "" "wins the cup." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Ut auxilient te, haec sunt adiumenta, collegere potes:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Cummis masticabilis - defende te ipsum cum scuto vel utere cum spectes retro ut relinquas lentam purpuream maculam." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Sugens latrinam - iace recte ut trahas hostem vel cum spectes post te iace ut hostis spectare non possit." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Umbrella descensoria - tardat omnes autocineta ante te." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Globus canistriludii - salit in via ad ducem et fortasse comprimatet tardetque autocineta." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1607,7 +1665,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1615,20 +1673,20 @@ msgid "" " the cup and the more points it is worth." msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1636,7 +1694,7 @@ msgid "" " resistant to explosions." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1644,7 +1702,7 @@ msgid "" " especially at low speeds." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1652,14 +1710,14 @@ msgid "" " top speed." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1667,12 +1725,12 @@ msgid "" "easier it is." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1682,7 +1740,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1692,12 +1750,12 @@ msgid "" "players and the server." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1707,7 +1765,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1727,7 +1785,7 @@ msgstr "" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "" @@ -1735,9 +1793,9 @@ msgstr "" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Grande Praemium" @@ -1748,6 +1806,20 @@ msgstr "Grande Praemium" msgid "Choose a Kart" msgstr "Delige autocinetum" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1761,11 +1833,11 @@ msgstr "" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Interrete" @@ -1782,7 +1854,7 @@ msgstr "Institutio" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "" @@ -1790,7 +1862,7 @@ msgstr "" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Praemii" @@ -1844,30 +1916,30 @@ msgstr "Reperi moderatrum" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Crea novum moderatrum" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Vestibulum" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "" @@ -1893,9 +1965,9 @@ msgstr "" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Informatio de te" @@ -1913,7 +1985,7 @@ msgstr "" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Amici" @@ -1938,7 +2010,7 @@ msgstr "Ludere celere" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Rationis usoris optiones" @@ -1988,8 +2060,8 @@ msgid "Online Username" msgstr "Usoris nomen interretis" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "" @@ -2002,7 +2074,7 @@ msgid "" msgstr "" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Moderatrorum optio" @@ -2020,339 +2092,409 @@ msgstr "" msgid "User search" msgstr "Usoris quaesitio" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Optiones SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Pictura" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Sonitus" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Lusores" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Gubernatio" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Musica" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Habilitatus est" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Vis" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Accentus sonitus" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Dele optiones." -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Reverte ad index periphericorum" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Qualitas imaginis" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Monitorium totum" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Recordare locum fenestrae" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Qualitatem imaginis apta" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Ostende ineundi monitorium semper" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Adnecte interrete" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" +msgid "Enable chatting in online lobbies" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" +msgid "Enable chatting in online matches" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Habilita impedimenta differentes esse omnibus" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Prem 'Enter' vel duis prem mure periphericum ut mutes id" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Adde periphericum" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Optiones designantur a disiuncta 'delige' clave, quam premis ut intersis ludo." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Modus picturae" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" +msgid "Skin variant" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" +msgid "Minimap" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Ostende numerus imagoinum in secundo" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Modus formae picturae" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Adcommodati optiones..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Qualitas imaginis" +msgid "Performance tests" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Monitorium totum" +msgid "Performance test of the current settings" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Recordare locum fenestrae" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Admone signum" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Qualitatem imaginis apta" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Dele" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2379,15 +2521,15 @@ msgstr "Caeruleus manus" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Numerus spatiorum" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Numerus AI autocinetorum" @@ -2402,33 +2544,17 @@ msgstr "" msgid "Random Grand Prix" msgstr "Grande Praemium fortuitum" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Inire interrete" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Admone signum" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Dele" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "" @@ -2547,238 +2673,306 @@ msgid "" msgstr "" #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Avis adii" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Easinus" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqui" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Susanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Vilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Abyssus ante Diluvium" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Insula pugnae" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Caverna X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Cacavatis templum" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Arx magmatum" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Grandis insula paradisiaca" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Villa" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Campus pedilusorius glaciei" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Quid agitis, stulti? Voster grandis dux deest?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Vide, nunc est in mea arce et cena mea erit..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Tamen sum iustus , ideo propono tibi negotium." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Si tu vinces me in cursu , liberabo eum senem." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "Sed mendici parvi molesti numquam potestis superaturum me esse - Rex autocinetorum!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Cuniculus vetus" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minipillamalleus" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Oliveris ludus mathematicae" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Labunt arenae" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Locus otii septentrionalis" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Cacumen nivis" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Arena" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Astronavis" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Templum" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Insula vulcani" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR DXCI" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Hortus Zen" @@ -2787,11 +2981,11 @@ msgstr "Hortus Zen" msgid "Completed achievement \"%s\"." msgstr "Praemii finita \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "" -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Non potest arcessere nuntios '%s'." @@ -2857,7 +3051,7 @@ msgid "New kart '%s' now available" msgstr "Novum autocinetum patens est '%s'" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2889,32 +3083,32 @@ msgid "" "created." msgstr "Sententiae 'config' tuae antiquiores erant, itaque deletae sunt et novae factae erint." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "" -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "" -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Mane " @@ -2936,19 +3130,18 @@ msgstr "" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (inpeditus)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "Paratus %s est" @@ -3422,21 +3615,21 @@ msgid "Axis %d" msgstr "Directio %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Clavis %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Clavis muris %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Positio muris %d %s" @@ -3608,26 +3801,30 @@ msgstr "" msgid "+1 life." msgstr "" -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "VINCES" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "" -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3636,16 +3833,16 @@ msgid "" "Internet\")." msgstr "" -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "" -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Possibilitas mutatoris tua antiquior est. Acquire motores imaginum mutabilum noviores." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3653,38 +3850,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "" -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "" #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "" @@ -3694,7 +3891,7 @@ msgstr "" msgid "Eggs: %d / %d" msgstr "Ova: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Dux" @@ -3702,22 +3899,22 @@ msgstr "Dux" msgid "Final lap!" msgstr "Spatium ultimum" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Spatium %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s de %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Novum spatium celerrimum" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "Via falsa" @@ -3731,194 +3928,194 @@ msgstr "" msgid "Oops, %s made an own goal!" msgstr "" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "" msgstr[1] "" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Eliminatus es!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "'%s' eliminatus est." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "" -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "" -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "" -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "" -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "" #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "" #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Gradus difficultatis: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "" #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "" -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "" -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "" -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "" -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "" -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "" -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "" -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "" #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "" #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "" #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "" -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "" #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "" #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "" #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "" #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "" #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3926,15 +4123,15 @@ msgid "" msgstr "" #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "" #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3965,38 +4162,38 @@ msgstr "" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s nunc in interrete est." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s et %s nunc in interrete sunt." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s %s et %s nunc in interrete sunt." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4004,19 +4201,19 @@ msgstr[0] "%d amicus in interrete nunc est." msgstr[1] "%d amici in interrete nunc sunt." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "" -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "%d quaerit amicitiam tuam!" msgstr[1] "%d quaerunt amicitiam tuam!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Aliquis quaerit amicitiam tuam!" @@ -4045,12 +4242,12 @@ msgid "" msgstr "Index optimorum nimis vetus est, \nideo deletus est." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Sequere ducem" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "3 ictorum bellum" @@ -4063,91 +4260,88 @@ msgstr "Inperfectam iterationem non servabitur. " msgid "Replay saved in \"%s\"." msgstr "Iteratio servatur in \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 hebdomas" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 hebdomades" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 mensis" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 menses" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 menses" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 menses" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 annus" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 anni" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Nomen additamenti" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Renovatus est in " #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s de %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Expecta renovare additamentorum" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Vitum factum est, dum ad paginam magnificationum coniuntus erat. Proba coniunctionem ad coniunctionem computatorum et sententiam, quod SuperTuxKart muro ignis clausus non est." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Clausus est: supera provocationes ut plura aperiant!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Arena fortuita" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d arena clausa est in modo lusoris singularis." -msgstr[1] "%d arenae clausae sunt in modo lusoris singularis." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nAlisa P, 2016\nAndré Lippok, 2016-2017\nSupernova 888, 2016" @@ -4435,7 +4629,7 @@ msgstr "" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Labere" @@ -4538,7 +4732,7 @@ msgstr "" msgid " (official tracks matching the goal)" msgstr "" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4546,91 +4740,95 @@ msgid "" msgstr "" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Adde wiimotem" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Adde optiones clavitaturae." -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Renovatio" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Versio: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "ostendetur" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Magnitudo: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Arcessere non potest additamentam" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Problemae instituendi additamentam '%s'." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Cona iterum" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Problemae delendi additamentam '%s'." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Iam signum non ratum est." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Signum debet esse inter 8 et 300 litteras!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Signa non constant" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Authenticare informationem" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Signi mutare bonum est." @@ -4651,67 +4849,97 @@ msgstr "" #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Adcommodatus" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Debilitatus est" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4719,7 +4947,7 @@ msgid "" msgstr "" #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4736,101 +4964,102 @@ msgstr "" msgid "Invalid server address: %s." msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Non" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Circus" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Vacuus)" @@ -4918,33 +5147,41 @@ msgid "Press any key..." msgstr "" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 -msgid "Back to Battle" +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" msgstr "" #: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +msgid "Back to Battle" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Novum cursum fac" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Relinque cursum" @@ -4960,11 +5197,11 @@ msgstr "" msgid "%s is number %d in the rankings with a score of %f." msgstr "" -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Nomen usoris vel inscriptio cursualis electronica non inefficaces sunt." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4986,7 +5223,7 @@ msgstr "Cursus spiritus iterum" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Spatia: %i" @@ -4999,21 +5236,21 @@ msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Egetur gradus: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Egetur tempus: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Egentur nitra: %i" @@ -5026,54 +5263,54 @@ msgstr "Numerus AI autocinetorum: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Gradus" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "" @@ -5086,74 +5323,74 @@ msgid "No player available for connecting to server." msgstr "" #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr " Quaestionem abice" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Hodie" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Quaestionem amicitiae mittebat!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Quaestionem amicitae accepit bene!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Sprevit quaestionem amicitiae!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Expulsus amicus est." -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Quaestionem amicitiae abiecit!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Tractare" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Arcessere suffragium proximum" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Prem stellas iterum, ut mutes vetum suffragium." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Adhuc non suffragabas additamento. Prem stellas, ut optes suffragium acceptum tuum." -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Suffragare bonum est! Potes claudere fenestram." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Suffragare" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Circus fortuitus" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5182,7 +5419,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Conservare Grande Praemium non posse." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Delige circum" @@ -5226,12 +5463,12 @@ msgstr "Nunc circus %0 liber est." msgid "You unlocked grand prix %0" msgstr "Nunc Grande Praemium %0 liberum est" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5252,19 +5489,19 @@ msgstr "Scribe nomen Grandis Praemii" msgid "Please select a Grand Prix" msgstr "Delige Grande Praemium." -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Usor constituebatur" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Nomen vaccum est." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Aliud Grande Praemium cum aequo hoc nomine est." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Nomen nimium longum est." @@ -5273,19 +5510,19 @@ msgstr "Nomen nimium longum est." msgid "Better luck next time!" msgstr "Meliorem fortunam tibi proximo conatus tuo." -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Finis provocationem!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Finivisti Grande Praemium." -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "" @@ -5298,110 +5535,125 @@ msgstr "" msgid "Are you sure you want to remove all of your high scores?" msgstr "" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Fortuitum autocinetum" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Clausus est." -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Omnes:\nPrem clavem 'delige' ut intersint ludo." -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "" -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Additamenta nunc debilitata sunt in optionibus" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Expecta legendum additamentorum" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Crea LAN moderatrum" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Moderatrum %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Nomen debet esse inter 4 et 30 litteras!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5409,7 +5661,7 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "" @@ -5417,24 +5669,24 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "" -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5443,7 +5695,7 @@ msgstr[1] "" #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5452,96 +5704,108 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Arcessere praemios" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Informatio de %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Abhinc" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Status" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Arcessere amicos" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Novam quaestionem" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Appendere" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Abest interreti" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "" -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Quaerere" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Relinque ludum." @@ -5619,34 +5883,34 @@ msgid "Distance (km)" msgstr "" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "" #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "" -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "" -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Arcessere moderatra" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5654,149 +5918,149 @@ msgstr "" #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Fortuitus locus rei." #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Numerus portarum ad victoriam" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Age retro" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Clausus est: supera provocationes ut plura aperiant!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Factum" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Officia clavum" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Debilita periphericum" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Habilita periphericum" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Claves ludi" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Claves electionis" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Guberna sinistrum" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Guberna dextrum" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Accelera" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" -msgstr "" +msgstr "Sufflamine / Redi" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Iaculare" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitrum" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Respice" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Eripe" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "moram facitur ludus" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Sursum" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Deorsus" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Sinister" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Dexter" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Delige" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Retexe/Redi" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Punctum caeruleum conflictionem confictione clavum alia significat." -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Punctum rubrum conflictionem in ea confictione clavum significat." -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5804,17 +6068,27 @@ msgid "" msgstr "Cave: 'Litterae magnae' clavis commendata non est. Cum pressa est, omnes claves, ubi signum magnum variat, non agent." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Esne cerus delere optiones haec sempiterner?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "" +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Directus" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Horizontalis" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5822,89 +6096,74 @@ msgstr "" #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Claviatura %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Systemae lingua" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" -msgstr "" +msgstr "Minimus" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" -msgstr "" - -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "" +msgstr "Parvus" #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" -msgstr "" +msgstr "Magnus" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" -msgstr "" +msgstr "Maximus" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5914,128 +6173,133 @@ msgid "" msgstr "" #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "" #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Communicatores animati: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Luces mutabiles: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "An-duplicationibus: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Circumventio circumiectus: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Umbrae: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Umbrae: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Flores: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Lucem facere (lineae tantum): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Lineae lucis (vectores deorum): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Motio motionis: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Altitudo infra agris: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Signum scribendum est." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Exit '%s'" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Init '%s'" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "" #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "" @@ -6063,7 +6327,7 @@ msgstr "PORTAE" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "" @@ -6098,7 +6362,7 @@ msgstr "Sequere ducem!" msgid "Top %i" msgstr "Optimi %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Succubuisti provocationem" @@ -6122,102 +6386,199 @@ msgstr "" msgid "Press fire to start the challenge" msgstr "Prem iaculare ut incipias provocationem" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Incide Grande Praemium" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Incipe iterum" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Redi ad optionem provocationum" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Redi optiones priam" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Esne certus incidere Grande Praemium?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Ruber manus vicit" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Caeruleus manus vicit" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Anceps, neuter vicit" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Eliminatus est" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(porta sua)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Circus %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Progressus Grandis Praemii:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Index optimorum" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Optimum spatium: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Omnes impeti licet, ideo arma collige atque utere sapienter!" @@ -6258,28 +6619,28 @@ msgstr "" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Circi auctor %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Limes maximus lusorum: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Clausus est!" @@ -6301,10 +6662,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Solus, qui omnes provocationes superavit, per magnam portam venit!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6313,41 +6676,48 @@ msgid "" msgstr "Eges plus peritiam\nut intres hanc provocationem!\nVide relicas provocationes\nin charta parva. " #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Prem <%s> ut acceleres, et <%s> atque <%s> ut gubernes." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Collige dona et iaculare telum per premere <%s> ut abicias arcas." #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6355,34 +6725,41 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Prem <%s>, ut nitra collegta utaris." #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Collige nitrorum lagoenas (post flexum viae utimur)" #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Si in periculo sis, prem <%s> ut voces auxilium." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6390,24 +6767,27 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Si labas paulisper, additum accelerandum accipias." #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Paratus es ad cursus. Bona fortuna tibi!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "" @@ -6417,7 +6797,7 @@ msgstr "" msgid "tux;game;race;" msgstr "" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6425,7 +6805,7 @@ msgid "" "for all ages." msgstr "" -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6434,7 +6814,7 @@ msgid "" "your opponents." msgstr "" -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6443,27 +6823,27 @@ msgid "" "your racing skills!" msgstr "" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "" -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "" -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "" -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "" diff --git a/data/po/lt.po b/data/po/lt.po index c63600e4d21..1a63f07b2c0 100644 --- a/data/po/lt.po +++ b/data/po/lt.po @@ -9,7 +9,7 @@ # Jonas Kr , 2015,2018-2019 # Mantas Kriaučiūnas Baltix , 2015-2016 # Moo, 2020-2022 -# Moo, 2023 +# Moo, 2023-2024 # Vytautas Butenas , 2019 # Zygimantus , 2017 # Zygimantus , 2017 @@ -17,9 +17,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Moo, 2023\n" +"Last-Translator: Moo, 2023-2024\n" "Language-Team: Lithuanian (http://app.transifex.com/supertuxkart/supertuxkart/language/lt/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -176,7 +176,7 @@ msgstr "Pasaulio pakrašty" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Grįžti" @@ -198,7 +198,7 @@ msgstr "Pasirink tau labiau patinkantį kontrolavimą" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Akselerometras" @@ -212,13 +212,13 @@ msgstr "Akselerometras" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Giroskopas" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Vairas" @@ -249,35 +249,37 @@ msgstr "Liečiamojo įrenginio nustatymai" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Bendri" @@ -345,30 +347,33 @@ msgstr "Sugrąžinti numatytuosius" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Atsisakyti" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Taip" @@ -546,9 +551,9 @@ msgstr "Prisijungti" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -609,7 +614,7 @@ msgstr "Tikslas" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Progresas" @@ -644,7 +649,7 @@ msgstr "Pateikti" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Grįžti į žaidimą" @@ -661,7 +666,7 @@ msgstr "Grįžti į pradžią" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Pradėti iš naujo" @@ -725,12 +730,12 @@ msgstr "Norint paleisti slaptažodį užpildykite vardą ir e-paštą naudotą r #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Naudotojo vardas" @@ -771,7 +776,7 @@ msgstr "Sudėtingumas" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Naujokas" @@ -783,7 +788,7 @@ msgstr "Naujokas" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Vidutiniokas" @@ -795,7 +800,7 @@ msgstr "Vidutiniokas" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Ekspertas" @@ -807,7 +812,7 @@ msgstr "Ekspertas" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -815,8 +820,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Žaidimo režimas" @@ -827,8 +832,8 @@ msgstr "Žaidimo režimas" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Paprastos lenktynės" @@ -841,7 +846,7 @@ msgstr "Paprastos lenktynės" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Tikros lenktynės" @@ -849,7 +854,8 @@ msgstr "Tikros lenktynės" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Kova" @@ -858,24 +864,24 @@ msgstr "Kova" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Futbolas" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Slaptažodis" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "" @@ -886,7 +892,7 @@ msgstr "Pridėti žaidėją" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Vardas" @@ -980,6 +986,50 @@ msgstr "Susieti ESC klavišą" msgid "Assign nothing" msgstr "Susieti nieką" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -994,11 +1044,11 @@ msgstr "Lenktynių nustatymai" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Tęsti" @@ -1039,10 +1089,15 @@ msgstr "Arenos" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Įdiegta" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1052,20 +1107,20 @@ msgstr "Įdiegta" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Standartiniai" @@ -1076,12 +1131,12 @@ msgstr "Standartiniai" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Papildymai" @@ -1095,27 +1150,28 @@ msgstr "Papildymai" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Viskas" @@ -1154,9 +1210,9 @@ msgstr "Judėti žemyn" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Pridėti" @@ -1193,7 +1249,7 @@ msgstr "Vaiduoklio peržiūros pasirinkimas" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Rask paslėptus kiaušus" @@ -1240,10 +1296,10 @@ msgstr "Priešinga kryptimi" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Maksimalus laikas (min.)" @@ -1275,9 +1331,9 @@ msgstr "Kopijuoti" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1288,80 +1344,80 @@ msgstr "Pervadinti" msgid "Save Grand Prix" msgstr "Įrašyti čempionatą" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "SuperTuxKart žinynas" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Žaidimo režimai" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Dalykėliai" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Bananai" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1369,56 +1425,57 @@ msgstr "Bananai" msgid "Story Mode" msgstr "Pradžia ir užduotys" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Kartų klasės" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Keli žaidėjai" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Pradėti pamoką" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Rink mėlynas dovanėlės, ten rasi dalykėlius" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Apvažiuok bananus!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1426,14 +1483,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Nitro rinkimas padeda važiuoti greičiau paspaudus tam skirtą klavišą ar mygtuką. Nitro likutį galima matyti lenktynėse, ekrano apačioje, dešinėje pusėje" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Jei matai mygtuką su užraktu kaip šis, norint atrakinti tau reikia įveikti užduotį." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1442,34 +1499,34 @@ msgid "" "carefully before!" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Dabartinius klavišus galite pamatyti bei pakeisti nustatymuose" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart palaiko skirtingus žaidimo režimus" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Paprastos lenktynės: Leidžiama viskas, todėl rinkite daiktus ir jais protingai naudokitės!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Laiko lenktynės: Nėra jokių padedančių daiktų, todėl svarbūs tik vairavimo įgūdžiai!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1477,7 +1534,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Sekite vadovą: Jūs turite likti antroje vietoje, nes paskutinė mašina bus diskvalifikuota kiekvieną kartą, kai laikmatis pasieks nulį. Tačiau neskubėkite, nes jei aplenksite vadovą, būsite diskvalifikuoti." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1487,30 +1544,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Futbolas: Naudokite kartą, norint įstumti kamuolį į vartus." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Paslėpti kiaušiniai: Tyrinėk trasas ir surask visus paslėptus kiaušinius." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1519,93 +1576,93 @@ msgid "" "wins the cup." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Pagalba norint laimėti - dalykėliai kuriuos galite rinkti" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Kramtomoji guma - apsaugo jus su skydu arba naudojama norint palikti lipnią rožinę balutę." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Tortas - metamas į artimiausią priešininką, geriausiai naudojamas nedideliame nuotolyje. Jis taip pat paveikia aplink sprogimą esančius kartus." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Naras - metamas į priekį, siekiant truktelti priešininką atgal, arba metamas, žiūrint atgal, norint apakinti priešininką." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Boulingo kamuolys - rieda tiesiai kol atsitrenkia į priešininką, jis gali atsimušti nuo sienų ir gali būti šaunamas žiurint atgal." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Parašiutas - sulėtina visus kartus esančius geresnėje pozicijoj nei tu." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Pakeitiklis - pakeičia dovanėles į bananus, nitro bakus į lipnią kramtomają gumą ir atvirkščiai trumpam laikui." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Krepšinio kamuolys - šokinėja paskui pirmaujantį ir gali suploti jo kelyje esančius kartus." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Inkaras - smarkei sulėtina kartą ribotam laikui" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Parašiutas - sulėtina kartą tačiau ne taip smarkiai kaip inkaras, bet kuo greičiau važiuosite tuo jis smarkiau stabdys jūsų kartą." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Piktasis Nolokas sugavo Gnu! Štai keli padedantys patarimai:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1614,7 +1671,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1622,20 +1679,20 @@ msgid "" " the cup and the more points it is worth." msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Ne visi kartai yra vienodi! Jie priklauso skirtingoms klasėms su skirtingais privalumais:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1643,7 +1700,7 @@ msgid "" " resistant to explosions." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1651,7 +1708,7 @@ msgid "" " especially at low speeds." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1659,14 +1716,14 @@ msgid "" " top speed." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1674,12 +1731,12 @@ msgid "" "easier it is." msgstr "Jeigu kelias sekundes arti važiuosi už kito karto įgausi pagreitį. Kuo kartas lengvesnis tuo didesnis bus pagreitis" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart gali būti žaidžiamas su kitais žaidėjais tinkle...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1689,7 +1746,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1699,12 +1756,12 @@ msgid "" "players and the server." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1714,7 +1771,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1734,7 +1791,7 @@ msgstr "" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "" @@ -1742,9 +1799,9 @@ msgstr "" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Čempionatai (Grand Prix)" @@ -1755,6 +1812,20 @@ msgstr "Čempionatai (Grand Prix)" msgid "Choose a Kart" msgstr "Pasirinkite automobilį" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1768,11 +1839,11 @@ msgstr "" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Internete" @@ -1789,7 +1860,7 @@ msgstr "Pamokos" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "" @@ -1797,7 +1868,7 @@ msgstr "" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Pasiekimai" @@ -1851,30 +1922,30 @@ msgstr "Rasti serverį" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Sukurti serverį" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Pradžia" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Konfigūracija" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Pradėti lenktynes" @@ -1900,9 +1971,9 @@ msgstr "Įvesti serverio adresą" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Tavo duomenys" @@ -1920,7 +1991,7 @@ msgstr "Žaidėjų reitingai" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Draugai" @@ -1945,7 +2016,7 @@ msgstr "Greitas žaidimas" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Paskyros Nustatymai" @@ -1995,8 +2066,8 @@ msgid "Online Username" msgstr "Prisijungimo vardas" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Pakeisti slaptažodį" @@ -2009,7 +2080,7 @@ msgid "" msgstr "" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Serverio Pasirinkimas" @@ -2027,339 +2098,409 @@ msgstr "Naudoti IPv6 ryšį" msgid "User search" msgstr "Naudotojų paieška" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "SuperTuxKart nustatymai" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Vaizdas" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Garsas" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Sąsaja" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Žaidėjai" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Valdymas" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Kalba" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Muzika" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Įjungta" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Garsumas" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Garso efektai" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Pašalinti valdymo nustatymus" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Išjungti konfigūraciją" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Grįžti į įrenginių sąrašą" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Pervadinti konfigūraciją" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Raiška" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Visame ekrane" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Įsiminti lango vietą" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Pritaikyt pasirinktą raišką" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Interneto parinktys" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Visada rodyti prisijungimo langą" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Prisijungti prie interneto" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" +msgid "Enable chatting in online lobbies" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Įjungti pokalbius žaidimui tinkle" +msgid "Enable chatting in online matches" +msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Įvairios parinktys" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Norint konfigūruoti, paspauskite „Enter“ arba dukart su pele ant įrenginio" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Pridėti valdymo įrenginį" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Išvaizdos tema" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Mini žemėlapis" +msgid "Skin variant" +msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "" +msgid "Minimap" +msgstr "Mini žemėlapis" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Šrifto dydis" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Kamera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Tinkinta..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Rodyti kadrų skaičių (FPS)" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Grafinių efektų lygis" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Derinti nustatymus..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Raiška" +msgid "Performance tests" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Visame ekrane" +msgid "Performance test of the current settings" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Įsiminti lango vietą" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Atsiminti slaptažodį" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Pritaikyt pasirinktą raišką" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Pašalinti" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Karto spalva" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2386,15 +2527,15 @@ msgstr "Mėlynoji komanda" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Trasos ratų kiekis" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Kompiuterinių žaidėjų:" @@ -2409,33 +2550,17 @@ msgstr "" msgid "Random Grand Prix" msgstr "Atsitiktinis čempionatas" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Prisijungti" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Atsiminti slaptažodį" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Pašalinti" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Karto spalva" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "" @@ -2554,238 +2679,306 @@ msgid "" msgstr "" #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Pingvinas Tuksas" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Antediluvian bedugnė" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Candelos miestas" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Kovų sala" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Juodasis miškas" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Ola X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Kakavos šventykla" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Kukurūzų perėja" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Magmos fortas" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Gran Paradiso sala" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Ledinio futbolo laukas" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Las Dunas Arena" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Las Dunas futbolo stadionas" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Aplink švyturį" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Sena kasykla" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolfas" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Oliverio matematikos pamoka" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Moliūgų parkas" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Dykumos smėliai" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Northern Resort" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Snow Peak" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Stadionas" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK įmonė" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Šventykla" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Vulkanų sala" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Zen Garden" @@ -2794,11 +2987,11 @@ msgstr "Zen Garden" msgid "Completed achievement \"%s\"." msgstr "Jums suteiktas titulas „%s“." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Nepavyko prisijungti prie SuperTuxKart papildinių serverio" -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Klaida atsiunčiant naujienas: '%s'." @@ -2864,7 +3057,7 @@ msgid "New kart '%s' now available" msgstr "Galėsite žaisti nauju kartu „%s“" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2896,32 +3089,32 @@ msgid "" "created." msgstr "Jūsų konfigūracija buvo per sena, ji buvo ištrinta, bus sukurta nauja." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Video įrašymas prasidėjo" -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Video išsaugotas %s" -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Kodavimo progresas:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %d ms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Įkeliama" @@ -2943,19 +3136,18 @@ msgstr "Nitro efektyvumas" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s yra pasiruošęs" @@ -3429,21 +3621,21 @@ msgid "Axis %d" msgstr "Ašis(kryptis) %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Gamepad klavišas %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Pelės mygtukas %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Pelės ašis %d %s" @@ -3617,26 +3809,30 @@ msgstr "Daugiausiai galite turėti 3 gyvybes!" msgid "+1 life." msgstr "+1 gyvybė." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Jūs laimėjote lenktynes!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s paliko lenktynes." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3645,16 +3841,16 @@ msgid "" "Internet\")." msgstr "" -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "" -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Vaizdo valdyklės (drivers) jūsų sistemoje yra per senos. Prašome įdiegti naujesnę vaizdo valdyklę." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3662,38 +3858,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "" -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "" #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s turi raudoną vėliavą!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s turi mėlyną vėliavą!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s perėmė mėlyną vėliavą!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s perėmė raudoną vėliavą!" @@ -3703,7 +3899,7 @@ msgstr "%s perėmė raudoną vėliavą!" msgid "Eggs: %d / %d" msgstr "Kiaušiniai: %d iš %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Pirmaujantis" @@ -3711,22 +3907,22 @@ msgstr "Pirmaujantis" msgid "Final lap!" msgstr "Paskutinis ratas!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Ratas %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s įveikė %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Naujas greičiausias ratas" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "NETEISINGA VAŽIAVIMO KRYPTIS!" @@ -3740,7 +3936,7 @@ msgstr "%s įmušė įvartį!" msgid "Oops, %s made an own goal!" msgstr "Oi, %s įmušė įvartį į savo vartus!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" @@ -3749,187 +3945,187 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Jūs buvote pašalintas!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "„%s“ buvo pašalintas." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "" -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "" -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "" -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Aptiktas blogas tinklo ryšys." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "" #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "" #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Sudėtingumas: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Max. Žaidėjų kiekis: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Laiko limitas" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Įvarčių limitas" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Visi žaidėjai prisijungė prie raudonos ar mėlynos komandos" #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Jūs esate serverio savininkas." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "" -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "" -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "" -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "" -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "" -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "" -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "" #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "" #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "" #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "" -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "" #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "" #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s prisijungė prie raudonos komandos." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s prisijungė prie mėlynos komandos." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s prisijungė prie žaidimo." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3937,15 +4133,15 @@ msgid "" msgstr "" #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "" #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3976,38 +4172,38 @@ msgstr "Laiko išbandymas (čempionatas)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Kiekvienas už save" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Vėliavos perėmimas " -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s jau prisijungė." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s ir %s dabar prisijungę." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s ir %s dabar prisijungę." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4017,12 +4213,12 @@ msgstr[2] "%d draugų dabar prisijungę." msgstr[3] "%d draugų dabar prisijungę." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "" -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4031,7 +4227,7 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "" @@ -4060,12 +4256,12 @@ msgid "" msgstr "Geriausių rezultatų failas buvo per senas.\nvisi rezultatai buvo ištrinti." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Sekite paskui pirmaujantį" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Trijų smūgių kova" @@ -4078,93 +4274,88 @@ msgstr "" msgid "Replay saved in \"%s\"." msgstr "" -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 savaitė" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 savaitės" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 mėnuo" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 mėnesiai" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 mėnesiai" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 mėnesiai" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 metai" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 metai" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Papildinio pavadinimas" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Atnaujinimo data" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s sukūrė %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Palaukite kol papildiniai bus atnaujinti" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Deja, jungiantis prie papildinių svetainės kilo klaida. Įsitikinkite jog jūs prisijungę prie interneto ir „SuperTuxKart“ neblokuojamas ugniasienės" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Užrakinta: įvykdykite aktyvias užduotis (iššūkius) ir gausite daugiau galimybių!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Atsitiktinė arena" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" -msgstr[3] "" - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nAlgimantas Margevičius, 2011\nJonas Kr, 2015\nJonas Kr, 2015,2018-2019\nMantas Kriaučiūnas Baltix, 2015-2016\nMoo, 2020-2021\nVytautas Butenas, 2019\nZygimantus, 2017\nJonas Kr, 2018-2019\nAlgimantas Margevičius\nJonas Kriaučiūnas," @@ -4452,7 +4643,7 @@ msgstr "Surinkti bananai" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Slydimas" @@ -4555,7 +4746,7 @@ msgstr "Kiaušinių medžioklės pabaigtos" msgid " (official tracks matching the goal)" msgstr "" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4563,91 +4754,95 @@ msgid "" msgstr "" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Pridėti Wii valdiklį" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Pridėti klavišų nustatymus kitam žaidėjui" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Atnaujinti" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Versija: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "atliko" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Dydis: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Atsiprašome papildinio atsiuntimas nepavyko" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Įdiegiant papildinį „%s“ kilo bėdų." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Bandyti dar kartą" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Šalinant papildinį „%s“ kilo bėdų." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Dabartinis slaptažodis netinkamas." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Slaptažodis turi būti nuo 8 iki 30 simbolių!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Slaptažodžiai nesutampa!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Patvirtinama informacija" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Slaptažodis sėkmingai pakeistas" @@ -4670,67 +4865,97 @@ msgstr "" #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Parinkti" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Išjungta" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Tiktais būtini" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Labai žemi" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Žemi" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Aukšti" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4738,7 +4963,7 @@ msgid "" msgstr "" #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4755,101 +4980,102 @@ msgstr "" msgid "Invalid server address: %s." msgstr "Neteisingas serverio adresas %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Priešingi" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Sudėtingumas" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Ratai" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Laikas" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Kartas" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Naudotojas" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Versija" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Ne" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Trasa" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Nėra)" @@ -4937,33 +5163,41 @@ msgid "Press any key..." msgstr "Paspauskite bet kurį klavišą..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 -msgid "Back to Battle" +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" msgstr "" #: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +msgid "Back to Battle" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Naujos lenktynės" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Baigti lenktynes" @@ -4979,11 +5213,11 @@ msgstr "" msgid "%s is number %d in the rankings with a score of %f." msgstr "" -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Vartotojo vardas ar/ir slaptažodis neteisingas." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5005,7 +5239,7 @@ msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Ratai: %i" @@ -5018,21 +5252,21 @@ msgstr "Tipas: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Reikalingas laikas: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Reikalingi nitro taškai: %i" @@ -5045,54 +5279,54 @@ msgstr "Kompiuterinių žaidėjų: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Kovos būdas" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Futbolo žaidimo tipas" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Serverio vieta: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Dabartinė trasa: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Vieta" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Žaidėjas" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Rezultatai" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Pražaistas laikas" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "" @@ -5105,74 +5339,74 @@ msgid "No player available for connecting to server." msgstr "" #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Naudotojo vardas: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Atsisakyti prašymo" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Šiandien" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Išsiųstas prašymas draugui!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Draugo prašymas priimtas!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Draugo prašymas atmestas!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Pašalintas draugas!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Draugystės pasiūlymas atmestas!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Apdorojama" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Balsuojama" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Atsitiktinė trasa" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5201,7 +5435,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "" -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Pasirinkti trasą" @@ -5245,12 +5479,12 @@ msgstr "Jūs atskleidėte trasą %0" msgid "You unlocked grand prix %0" msgstr "Jūs atsirakinote čempionatą %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Trasa" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5271,19 +5505,19 @@ msgstr "Įveskite čempionato pavadinimą" msgid "Please select a Grand Prix" msgstr "Pasirinkite čempionatą" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Naudotojas nustatytas" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Pavadinimas tuščias?" -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Kitas čempionatas (grand prix) tokiu pačiu pavadinimu jau yra." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Pavadinimas yra per ilgas." @@ -5292,19 +5526,19 @@ msgstr "Pavadinimas yra per ilgas." msgid "Better luck next time!" msgstr "Sėkmės lenktyniaujant kitą kart!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Jūs įvykdėte užduotį!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Jūs laimėjote čempionatą!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Jūs baigėte čempionatą (Grand Prix)!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "" @@ -5317,110 +5551,125 @@ msgstr "" msgid "Are you sure you want to remove all of your high scores?" msgstr "" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Atsitiktinis kartas" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Užrakinta" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Visiems:\nPaspauskite Pasirinkti mygtuką, kad patektumėt į žaidimą" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "" -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Šiuo metu papildinių modulis yra išjungtas, pasirinkčių ekrane" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Palaukite kol papildiniai įkraunami" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Sukurti LAN serverį" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "serveris „%s“" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Netinkami simboliai slaptažodyje!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Pasiruošęs" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Stebėti" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5428,7 +5677,7 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "" @@ -5436,24 +5685,24 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "" -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5464,7 +5713,7 @@ msgstr[3] "Žaidimas prasidės kai bus daugiau nei %d žaidėjai." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5475,96 +5724,108 @@ msgstr[1] "" msgstr[2] "" msgstr[3] "" -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Jungiamasi prie serverio %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Likęs laikas: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Įvarčiai" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Atsiunčiami titulai" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Naudotojo %s duomenys" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Būsena" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Naujas kvietimas" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Laukiama" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Neprisijungęs" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Turite būti prisijungęs prie Internetinio tinklo. Paspauskite vartotojo vardą apačioje." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Ieškoma" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Baigti žaidimą" @@ -5642,34 +5903,34 @@ msgid "Distance (km)" msgstr "Atstumas (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Nežinomas" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "" #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "" -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "" -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Gaunami serveriai" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5677,149 +5938,149 @@ msgstr "" #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Atsitiktinė daiktų vieta" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Įvarčių kiekis pergaliai" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Važiuoti priešinga kryptimi" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Veiksmas" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Išjungti įrenginį" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Įjungti įrenginį" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Įgalinti konfiguraciją" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Valdymo klavišai" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Meniu klavišai" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Sukimas kairėn" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Sukimas dešinėn" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Greitinimas" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Šaudymas" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Žiūrėjimas atgal" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Išgelbėjimas" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Sustabdyti žaidimą" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Aukštyn (rodyklė)" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Žemyn (rodyklė)" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Kairėn (rodyklė)" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Dešinėn (rodyklė)" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Pasirinkti" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Atsisakyti/Grįžti" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Mėlynas elementas reiškia nustatymas nesuderinamas su kitu" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5827,17 +6088,27 @@ msgid "" msgstr "" #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Ar esate įsitikinę jog norite ištrinti konfigūraciją visam laikui?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "" +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5845,89 +6116,74 @@ msgstr "" #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Klaviatūra %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Liečiamas įrenginys" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Sistemos kalba" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Paslėptas" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5937,128 +6193,133 @@ msgid "" msgstr "" #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "" #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Šešėlis: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Šešėliai: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" -msgstr "" +msgstr "Interneto prieiga išjungta. Ar norite ją įjungti?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Turite įvesti slaptažodį." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Jūs negalite ištrinti vienintelio žaidėjo." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Ar tikrai norite ištrinti žaidėją %s?" @@ -6086,7 +6347,7 @@ msgstr "Įvartis!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Laukiama kitų" @@ -6121,7 +6382,7 @@ msgstr "Sekite pirmaujantį lyderį!" msgid "Top %i" msgstr "Top %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Neįvykdėte užduoties" @@ -6145,102 +6406,199 @@ msgstr "" msgid "Press fire to start the challenge" msgstr "Užduočiai pradėti paspauskite šaudymo mygtuką" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Atgal į pagrindinį meniu" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Palikti serverį" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Nutraukti čempionatą" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Pradėti iš naujo" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Grįžti į užduočių pasirinkimą" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Grįžti į meniu" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Ar tikrai norite palikti čempionatą?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Raudona komanda laimi" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Mėlyna komanda laimėjo" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Lygiosios" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Eliminuotas" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Jūsų įvarčiai)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Trąsa %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Čempionato eiga:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Geriausi rezultatai" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Geriausias rato laikas: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Glodinimas: ĮJUNGTAS" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Glodinimas: IŠJUNGTAS" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Leidžiama viskas, taigi - rinkite ginklus bei kitus gerus dalykėlius ir juos naudokite tinkamai!" @@ -6281,28 +6639,28 @@ msgstr "" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Trasą sukūrė %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Maksimalus žaidėjų skaičius: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Užrakintas!" @@ -6324,10 +6682,12 @@ msgid "%d/%m/%Y" msgstr "" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Įvykdykite visas užduotis jog atrakintumėte didžiąsias duris!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6336,41 +6696,48 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6378,34 +6745,41 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Panaudokite surinktą „nitro“ kurą paspausdami <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6413,24 +6787,27 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Jūs jau pasiruošęs lenktynėms. Sėkmės!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "" @@ -6440,7 +6817,7 @@ msgstr "" msgid "tux;game;race;" msgstr "" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6448,7 +6825,7 @@ msgid "" "for all ages." msgstr "" -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6457,7 +6834,7 @@ msgid "" "your opponents." msgstr "" -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6466,27 +6843,27 @@ msgid "" "your racing skills!" msgstr "" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." -msgstr "" +msgstr "Šiame žaidime nėra reklamų." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "" -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "" -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "SuperTuxKart komanda" diff --git a/data/po/ml.po b/data/po/ml.po index 7b6749bb272..862c483be58 100644 --- a/data/po/ml.po +++ b/data/po/ml.po @@ -5,16 +5,16 @@ # Translators: # Adithyan S S , 2020 # Adithyan S S , 2020 -# Adithyan S S , 2020-2022,2024 +# Adithyan S S , 2020-2022,2024-2025 # Kevin 008, 2021 # Kevin 008, 2021 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Adithyan S S , 2020-2022,2024\n" +"Last-Translator: Adithyan S S , 2020-2022,2024-2025\n" "Language-Team: Malayalam (http://app.transifex.com/supertuxkart/supertuxkart/language/ml/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -42,7 +42,7 @@ msgstr "ഉപേക്ഷിക്കുക" #. I18N: ./data/achievements.xml msgid "Christoffel Columbus" -msgstr "ക്രിസ്റ്റോഫെൽ കൊളമ്പസ്" +msgstr "ക്രിസ്തപ്പൻ കൊളമ്പസ്" #. I18N: ./data/achievements.xml msgid "Play every official track at least once." @@ -171,7 +171,7 @@ msgstr "ലോകത്തിൻ്റെ അതിർത്തിയിൽ" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "പിന്നോട്ട്" @@ -193,7 +193,7 @@ msgstr "നിങ്ങൾ ഇഷ്ടപ്പെടുന്ന നിയന #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "ത്വരണമാപകം" @@ -207,13 +207,13 @@ msgstr "ത്വരണമാപകം" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "ജൈറോസ്കോപ്പ്" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "സ്റ്റിയറിംഗ് വീൽ" @@ -244,35 +244,37 @@ msgstr "ടച്ച്-ഉപകരണ ക്രമീകരണങ്ങൾ" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "പൊതുവസ്തുതകൾ" @@ -340,30 +342,33 @@ msgstr "പൂർവ്വസ്ഥിതിയിലാക്കുക" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "റദ്ദാക്കുക" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "അതെ" @@ -448,7 +453,7 @@ msgstr "ശോഭ" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Light shaft (God rays)" -msgstr "പ്രകാശരശ്മികൾ (അർക്കകിരണങ്ങൾ)" +msgstr "പ്രകാശധാര (അർക്കകിരണങ്ങൾ)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -541,9 +546,9 @@ msgstr "ചേരുക" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -604,7 +609,7 @@ msgstr "ലക്ഷ്യം" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "പുരോഗതി" @@ -639,7 +644,7 @@ msgstr "സമർപ്പിക്കുക" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "തിരികെ റേസിലേക്ക്" @@ -656,7 +661,7 @@ msgstr "തിരികെ ഉപശാലയിലേക്ക്" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "റേസ് പുനരാരംഭിക്കുക" @@ -716,16 +721,16 @@ msgstr "താങ്കളുടെ രഹസ്യവാക്ക് വീണ msgid "" "Fill in the username and email address you supplied at registration to be " "able to reset your password." -msgstr "താങ്കളുടെ പാസ് വേഡ് വീണ്ടെടുക്കുന്നതിനായി താങ്കൾ റെജിസ്ട്രേഷനിടെ പ്രദാനംചെയ്ത ഉപയോക്തൃനാമവും ഇമെയിൽ വിലാസവും എഴുതുക." +msgstr "താങ്കളുടെ പാസ് വേഡ് വീണ്ടെടുക്കുന്നതിനായി താങ്കൾ രേഖചേർക്കുന്നതിനിടെ പ്രദാനംചെയ്ത ഉപയോക്തൃനാമവും ഇമെയിൽ വിലാസവും എഴുതുക." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "ഉപയോക്തൃനാമം" @@ -766,7 +771,7 @@ msgstr "പ്രയാസം" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "തുടക്കക്കാരൻ" @@ -778,7 +783,7 @@ msgstr "തുടക്കക്കാരൻ" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "അർധജ്ഞാനി" @@ -790,7 +795,7 @@ msgstr "അർധജ്ഞാനി" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "വിദ്വാൻ" @@ -802,7 +807,7 @@ msgstr "വിദ്വാൻ" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "സൂപ്പർടക്സ്" @@ -810,8 +815,8 @@ msgstr "സൂപ്പർടക്സ്" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "ഗെയിം മോഡ്" @@ -822,8 +827,8 @@ msgstr "ഗെയിം മോഡ്" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "സാധാരണ റേസ്" @@ -836,7 +841,7 @@ msgstr "സാധാരണ റേസ്" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "സമയസാമർഥ്യം" @@ -844,7 +849,8 @@ msgstr "സമയസാമർഥ്യം" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "യുദ്ധം" @@ -853,24 +859,24 @@ msgstr "യുദ്ധം" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "സോക്കർ" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "രഹസ്യവാക്ക്" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "ഈ സെർവർ ബുക്ക്മാർക്ക് ചെയ്യാം" @@ -881,7 +887,7 @@ msgstr "കളിക്കാരെ ചേർക്കുക" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "പേര്" @@ -975,6 +981,50 @@ msgstr "ESC കീയിലേക്ക് നിയമിക്കുക" msgid "Assign nothing" msgstr "ഒന്നും നിയമിക്കേണ്ട" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "വീഡിയോ ക്രമീകരണങ്ങൾ നിർദ്ദേശിക്കുക" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "നിർദ്ദേശിച്ച ഈ ക്രമീകരണങ്ങൾ നിലവിലെ മിഴിവുമായി ഇണങ്ങുന്നതാണ്." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "ക്രമീകരണങ്ങളുടെ പ്രഥമോദ്ദേശ്യം എന്താകണം?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "പ്രകടനം" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "പ്രകടനത്തിന്റെയും ഗ്രാഫിക്സ് നിലവാരത്തിന്റെയും സന്തുലനം" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr " ഗ്രാഫിക്സ് നിലവാരം" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "ഊർജ്ജത്തിലെ ലുബ്ധത" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "ഗ്രാഫിക്സ് പ്രഭാവങ്ങൾ മങ്ങൽ സൃഷ്ടിക്കുന്നത് നിങ്ങൾക്കിഷ്ടമാണോ?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "പരീക്ഷണം ആരംഭിക്കാം" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -989,11 +1039,11 @@ msgstr "റേസ് രൂപീകരണം" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "തുടരാം" @@ -1011,7 +1061,7 @@ msgstr "പുതുക്കിയത്" #. I18N: In addons screen, in the filtering bar, to enable a filter that will #. show only items with good rating msgid "Rating >=" -msgstr "നിലവാരം >=" +msgstr "മൂല്യം >=" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In the addons screen @@ -1034,10 +1084,15 @@ msgstr "മേഖലകൾ" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "ഇൻസ്റ്റാൾ ചെയ്തത്" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "അഭീഷ്ടമേഖലകൾ തിരുത്തുക" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1047,22 +1102,22 @@ msgstr "ഇൻസ്റ്റാൾ ചെയ്തത്" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" -msgstr "സ്റ്റാൻഡേർഡ്" +msgstr "പ്രതിമാനം" #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group @@ -1071,12 +1126,12 @@ msgstr "സ്റ്റാൻഡേർഡ്" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "ആഡ്-ഓണുകൾ" @@ -1090,27 +1145,28 @@ msgstr "ആഡ്-ഓണുകൾ" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "എല്ലാം" @@ -1149,9 +1205,9 @@ msgstr "താഴ്ത്തുക" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "ചേർക്കുക" @@ -1188,7 +1244,7 @@ msgstr "പ്രേത റീപ്ലേ തിരഞ്ഞെടുക്ക #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "മുട്ട വേട്ട" @@ -1235,10 +1291,10 @@ msgstr "എതിർദിശ" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "പരമാവധി സമയം (മിനി.)" @@ -1270,9 +1326,9 @@ msgstr "പകർത്തുക" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1283,80 +1339,80 @@ msgstr "പേരുമാറ്റുക" msgid "Save Grand Prix" msgstr "ഗ്രാന്റ് പ്രീ സംഭരിക്കുക" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "സൂപ്പർടക്സ്കാർട്ട് സഹായം" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "ഗെയിം മോഡുകൾ" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "ആയുധങ്ങൾ" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "പഴത്തൊലികൾ" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1364,56 +1420,57 @@ msgstr "പഴത്തൊലികൾ" msgid "Story Mode" msgstr "കഥാ മോഡ്" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "കാർട്ട് തരങ്ങൾ" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "സംഘറേസ്" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "മാതൃക ആരംഭിക്കാം" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "ശേഖരിക്കണം നീല സമ്മാനപ്പൊതികൾ, അവ നിങ്ങൾക്ക് ആയുധങ്ങൾ തരും." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "പഴത്തൊലികളെ ശ്രദ്ധിക്കുകയേ വേണ്ട!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1421,14 +1478,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "നൈട്രോ ശേഖരിക്കുന്നത് ഇഷ്ടാനുസൃതം ഉചിതമായ കീയോ ബട്ടണോ അമർത്തി സ്പീഡ് ബൂസ്റ്റുകൾ നേടാൻ നിങ്ങളെ അനുവദിക്കുന്നു. നിങ്ങളുടെ തത്സമയ നൈട്രോ നിരക്ക് റേസ് സ്ക്രീനിന്റെ താഴെ-ഇടതുവശത്തെ ഗേജിൽ നിങ്ങൾക്ക് കാണാൻ സാധിക്കും." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "ഇത്തരം ഒരു പൂട്ട് അടങ്ങിയ ഒരു ബട്ടൺ നിങ്ങൾ കാണുകയാണെങ്കിൽ, അതു തുറക്കാൻ നിങ്ങൾക്ക് ഒരു വെല്ലുവിളി പൂർത്തിയാക്കേണ്ടതുണ്ട് എന്നർത്ഥം." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1437,34 +1494,34 @@ msgid "" "carefully before!" msgstr "ഒരു സവിശേഷ കിയോ ബട്ടണോ അമർത്തുന്നതിലുടെ നിങ്ങൾ സ്കിഡ്ഡ് ചെയ്യുന്നു. അനുസ്യൂതമായ ചെറിയ സ്കിഡ്ഡുകൾ കൂർത്ത തിരിവുകൾ എടുക്കാൻ സഹായിക്കും; മിതമായ സ്കിഡ്ഡുകൾ നിങ്ങളുടെ വേഗത വർദ്ധിപ്പിക്കുമ്പോൾ, ദൈർഘ്യമേറിയ സ്കിഡ്ഡുകൾ അതിനും മേലെയാണ്. സ്കിഡ്ഡിങ്ങിനിടെയുള്ള തിരിയൽ അനിയന്ത്രിതമാണ്, അതിനാൽ നിങ്ങളുടെ കാർട്ടിനെ ശ്രദ്ധാപൂർവ്വം വിന്യസിക്കേണേ!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "റേസ് ആരംഭിക്കുന്നതിന് മുൻപായി 'ഒരുങ്ങിക്കോ!' കാണിക്കുമ്പോൾ 'ത്വരണ' ബട്ടൺ അമർത്തുന്നതിലൂടെ ഒരു പ്രാരംഭ ബൂസ്റ്റ് നിങ്ങൾക്ക് ലഭിക്കുന്നു." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* നിലവിലെ കീ അനുക്രമണങ്ങൾ ഐച്ഛിക മെനുവിൽ കാണാൻ/മാറ്റുവാൻ സാധിക്കും." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "സൂപ്പർടക്സ്കാർട്ട് വ്യത്യസ്തമായ ഗെയിം മോഡുകളാൽ സമ്പുഷ്ടമാണ്:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "സാധാരണ റേസ്: എല്ലാ പ്രഹരങ്ങളും അനുവദിച്ചിരിക്കുന്നു, അതിനാൽ ആയുധങ്ങൾ ശേഖരിച്ച് അവ തന്ത്രപരമായി ഉപയോഗിക്കൂ!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "സമയസാമർഥ്യം: ആയുധങ്ങൾ ഒന്നുമില്ല, അതിനാൽ നിങ്ങളുടെ ഡ്രെെവിംഗ് മിടുക്കുകൾക്കാണ് ഇവിടെ കാര്യം!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1472,7 +1529,7 @@ msgid "" " leader will get you eliminated too!" msgstr "നേതാവിനെ പിന്തുടരൂ: രണ്ടാം സ്ഥാനത്തിനായി മത്സരിക്കുക, കൗണ്ടർ പൂജ്യമടിക്കുന്ന ഓരോ സമയത്തും അവസാനത്തെ കാർട്ട് അയോഗ്യമായിക്കൊണ്ടിരിക്കും. സൂക്ഷിക്കണേ: നേതാവിന് മുന്നിൽകൂടി പോകുന്നത് നിങ്ങളെയും സ്ഥാനഭ്രംശം ചെയ്യാൻ ഇടയാക്കും!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1482,30 +1539,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "3 തരം യുദ്ധരീതികളാണ് ആകെയുള്ളത്: 3 പ്രഹര-യുദ്ധത്തിൽ, നിങ്ങൾ മറ്റുള്ളവരുടെ ജീവനുകളെല്ലാം നഷ്ടമാകുന്നതുവരെ അവരെ ആയുധങ്ങൾകൊണ്ട് പ്രഹരിക്കണം. എല്ലാറ്റിനും-സ്വാതന്ത്ര്യത്തിൽ, തന്നിരിക്കുന്ന പ്രഹരങ്ങളുടെയോ സമയത്തിെന്റെയോ നിരക്കിനുള്ളിൽ മറ്റുള്ളവരെ ഏറ്റവും കൂടുതൽ പ്രഹരിക്കുന്ന കളിക്കാരൻ ജയിക്കും. പതാകപ്പിടിത്തത്തിൽ, നിങ്ങളുടെ ടീം എതിർടീമിന്റെ പതാക സ്വസ്ഥാനത്ത് കൊണ്ടുവരണം, എതിർടീം നിങ്ങളുടെ പതാക കയ്യടക്കാത്തിടത്തോളം നേരം." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "സോക്കർ: നിങ്ങളുടെ കാർട്ടുപയോഗിച്ച് പന്ത് ലക്ഷ്യസ്ഥാനത്തേക്ക് തട്ടിവിടുക." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "മുട്ട വേട്ട: വിവിധ സ്ഥലങ്ങൾ സന്ദർശിച്ച് ഒളിഞ്ഞിരിക്കുന്ന എല്ലാ മുട്ടകളും കണ്ടെത്തുക." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "പ്രേത റീപ്ലേ: സമയസാമർഥ്യത്തിലോ മുട്ട വേട്ടരീതിയിലോ പ്രേത റീപ്ലേകൾക്കെതിരെ മത്സരിക്കുക, സ്വയം നേട്ടംകൊയ്യുക!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "ലാപ്പ് മത്സരം: തന്നിരിക്കുന്ന സമയത്തിനകം കഴിയുന്നത്ര ലാപ്പുകൾ പൂർത്തീകരിക്കുക." +msgstr "ലാപ്പ് വേല: തന്നിരിക്കുന്ന സമയത്തിനകം കഴിയുന്നത്ര ലാപ്പുകൾ പൂർത്തീകരിക്കുക." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1514,93 +1571,93 @@ msgid "" "wins the cup." msgstr "* ഈ ഗെയിം മോഡുകളിലധികവും ഗ്രാന്റ് പ്രീ പ്രകൃതത്തിലും കളിക്കാവുന്നവയാണ്. ഒരൊറ്റ റേസ് കളിക്കുന്നതിനുപകരം, ഒരു നിരയിലാകും നിങ്ങൾ കളിക്കുക. എത്ര നിങ്ങൾ റാങ്ക് ചെയ്യുന്നുവോ, അത്രയും പോയിന്റുകൾ നിങ്ങൾക്കു ലഭിക്കും. അവസാനം, ഏറ്റവും കൂടുതൽ പോയിന്റുള്ള കളിക്കാരൻ കപ്പടിക്കും." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "നിങ്ങളുടെ ജയത്തിനുതകാൻ, നിങ്ങൾക്കു ശേഖരിക്കാവുന്ന ചില ആയുധങ്ങളാണിവ:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "ബബിൾഗം - ഒരു കവചത്താൽ സ്വയം സംരക്ഷിക്കുക, അല്ലെങ്കിൽ തിരിഞ്ഞു നോക്കുന്നതിനിടെ ഒട്ടിപ്പിടിക്കുന്ന ഒരു പിങ്ക് കറ പിന്നോടുവിടുക." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "സിപ്പർ - ഒരു ശക്തമായ വേഗതാ ബൂസ്റ്റ് നൽകും. പക്ഷേ നിങ്ങളുടെ കാർട്ടിന്റെ നിയന്ത്രണം വിടാതിരിക്കാൻ ശ്രദ്ധിക്കണേ!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "കേക്ക് - ഏറ്റവുമടുത്ത ശത്രുവിന്റ നേർക്ക് എറിയപ്പെടുന്നു, കുറഞ്ഞ പരിധിയിലും നീണ്ട നേർപ്പാതകളിലും ഗുണം ചെയ്യും. സ്‌ഫോടനത്തിേനോട് ചേർന്നുള്ള കാർട്ടുകളെയും ഇത് ബാധിക്കുന്നു." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "പ്ലഞ്ചർ - നേരെയെറിഞ്ഞാൽ ഒരെതിരാളിയെ പിന്നോട്ട് വലിച്ചിടാം, അല്ലെങ്കിൽ പിന്നോട്ടുനോക്കുന്നതിനിടെ എറിഞ്ഞാൽ ഒരുവന്റെ കാഴ്ച്ച കളയാം." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "ബൗളിംഗ് ബോൾ - ആഘാതമുണ്ടാക്കുന്നതുവരെ ഇത് രേഖീയമായി സഞ്ചരിക്കുന്നു, ഇതിന് ഭിത്തികൾ തട്ടിത്തെറിപ്പിക്കാൻ കഴിയും. നിങ്ങൾ തിരിഞ്ഞുനോക്കുന്നുവെങ്കിൽ, പിന്നിലേക്കിത് എറിയെപ്പെടും." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "പാരഷ്യൂട്ട്: ഒരു നല്ല സ്ഥാനത്തുള്ള എല്ലാ കാർട്ടുകളുടെയും വേഗംകുറയ്ക്കുന്നു." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "പകരംമാറ്റി - കുറച്ചുസമയത്തേക്ക് സമ്മാനപ്പൊതികൾ പഴത്തൊലികളായും, നൈട്രോ കാനുകൾ ബബിൾഗമ്മുകളായും, നേരെമറിച്ചും രൂപമാറ്റം വരുത്തുന്നു." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." -msgstr "ബാസ്ക്കറ്റ് ബോൾ: ഒന്നാംസ്ഥാനക്കാരന്റെ പിന്നാലെ തട്ടിത്തെറിച്ചുപോകുന്നു, പിന്നെ വഴിക്കുള്ള കാർട്ടുകളെ അടിച്ചുപരത്തുകയും വേഗം കുറയ്ക്കുകയും ചെയ്തേക്കാം." +msgstr "ബാസ്ക്കറ്റ് ബോൾ: ഒന്നാംസ്ഥാനക്കാരന്റെ പിന്നാലെ തട്ടിത്തെറിച്ചുപോകുന്നു, പിന്നെ വഴിക്കുള്ള കാർട്ടുകളെ അടിച്ചുപരത്തുകയും വേഗം കുറയ്ക്കുകയും ചെയ്യുന്നതാകും." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "സ്വാറ്റർ - സമീപമുള്ള കാർട്ടുകളെ അടിച്ചുപരത്തി, അവയുടെ വേഗംകുറയ്ക്കും. പാരഷ്യൂട്ടുകളെയും ബോംബുകളെയും ഇല്ലാതാക്കാനും ഉപയോഗിക്കാം." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "പഴത്തൊലിയിൽ തട്ടുന്നത് താഴെപ്പറയുന്ന ഏതെങ്കിലുമൊന്ന് കാർട്ടിനുപിന്നിൽ ഘടിപ്പിക്കെപ്പെടുന്നത് ഫലം ചെയ്യും:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "നങ്കൂരം - കാർട്ടിന്റെ വേഗം പെട്ടെന്ന് കുറയ്ക്കുന്നു." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." -msgstr "പാരഷ്യൂട്ട് - നങ്കൂരത്തേക്കാൾ സാവധാനം, കാർട്ടിന്റെ വേഗംക്കുറയ്ക്കുന്നു. എത്ര വേഗത്തിൽ നിങ്ങൾ പോകുന്നുവോ, അത്ര ബലത്തിൽ അത് നിങ്ങളുെടെ വേഗം കുറയ്ക്കുന്നു." +msgstr "പാരഷ്യൂട്ട് - നങ്കൂരത്തേക്കാൾ സാവധാനം, കാർട്ടിന്റെ വേഗംകുറയ്ക്കുന്നു. എത്ര വേഗത്തിൽ നിങ്ങൾ പോകുന്നുവോ, അത്ര ബലത്തിൽ അത് നിങ്ങളുടെ വേഗം കുറയ്ക്കുന്നു." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "ബോംബ് - കുറഞ്ഞൊരളവ് സമയത്തിനു ശേഷം പൊട്ടിത്തെറിക്കുന്നു, കാർട്ടിനെ മുകളിലേക്ക് പറത്തിക്കൊണ്ട്. മറ്റൊരു കാർട്ടിലേക്ക് ബോംബ് കൈമാറാൻ അതിലേക്ക് ചെന്നു മുട്ടുക." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "ദുഷ്ടൻ നോലോക്ക് ഗ്നുവിനെ പിടിച്ചുകൊണ്ടുപോയിരിക്കുന്നു! നിങ്ങളെ സഹായിക്കാൻ ചില വഴികൾ ഇതാ:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1609,7 +1666,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "മിനിമാപ്പിലെ ഈ ഐകൺ നിങ്ങൾ പൂർത്തികരിക്കാത്ത ലഭ്യമായ വെല്ലുവിളികൾ കാണിക്കുന്നു. സ്ക്രീനിന്റെ മുകളിൽ-വലത്തായി, അത് നിങ്ങൾക്ക് എത്ര പോയിന്റുകൾ നിലവിലുണ്ടെന്നുകൂടി പറയുന്നു. കഴിയുന്നത്ര വെല്ലുവിളികൾ പൂർത്തിയാക്കുക, ശേഷം നോലോക്കിന് നിങ്ങൾ പന്തയത്തിനു യോഗ്യനെന്ന് ബോധ്യപ്പെടും. വിജയിച്ച് ഗ്നുവിനെ മോചിപ്പിക്കൂ!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1617,28 +1674,28 @@ msgid "" " the cup and the more points it is worth." msgstr "ഒരു വെല്ലുവിളി നിങ്ങൾ പൂർത്തിയാക്കുമ്പോൾ, നിങ്ങളൊരു കപ്പ് നേടുന്നു. ഓരോ കപ്പും പലേ പോയിന്റുകൾ മതിക്കുന്നതാണ്. എത്ര ഉയർന്ന പ്രയാസത്തിലാണോ നിങ്ങൾ വെല്ലുവിളി പൂർത്തിയാക്കിയത്, കപ്പ് അത്ര മികച്ചതും കൂടുതൽ പോയിന്റുകൾ അവ മതിക്കുന്നതുമായിരിക്കും." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "ഈ ഐകണുതാഴെ സൂചിപ്പിച്ചിരിക്കുന്നത്രയും പോയിന്റുകൾ നിങ്ങൾ നേടുമ്പോൾ. നിങ്ങൾക്കൊരത്ഭുതം സമ്മാനിക്കപ്പെടുന്നു, ശേഖരിക്കാൻ ഒരുപാടുണ്ടിവ." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "എല്ലാ കാർട്ടുകളും ഒരുപോലെയല്ല ഓടിക്കുന്നത്! അവ ഒരുപാട് വ്യത്യാസങ്ങളാൽ പല തരങ്ങളിൽ പെടുന്നു." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " "medium and heavy. Heavier karts are less affected by parachutes and are more" " resistant to explosions." -msgstr "ഭാരം - കാർട്ടുകളുടെ ഭാരമനുസരിച്ച്, അവ മൂന്നു തരമുണ്ട്: ലഘു, ഇടത്തരം പിന്നെ ഭാരമേറിയത്. ഭാരമേറിയ കാർട്ടുകൾക്ക് പാരഷ്യൂട്ടുകൾ നിസ്സാരബാധകവും സ്ഫോടനങ്ങളോട് കൂടുതൽ പ്രതിരോധവും ഉള്ളവയാണ്." +msgstr "ഭാരം - കാർട്ടുകളുടെ ഭാരമനുസരിച്ച്, അവ മൂന്നു തരമുണ്ട്: ലഘു, ഇടത്തരം, കഠിനം എന്നിവയാണവ. ഭാരമേറിയ കാർട്ടുകൾക്ക് പാരഷ്യൂട്ടുകൾ നിസ്സാരബാധകവും സ്ഫോടനങ്ങളോട് കൂടുതൽ പ്രതിരോധവും ഉള്ളവയാണ്." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1646,7 +1703,7 @@ msgid "" " especially at low speeds." msgstr "ത്വരണം - പ്രത്യേകിച്ച് തുടക്കത്തിൽ, ഒരുപകടത്തിനുശേഷം, അല്ലെങ്കിൽ അനേകം കൂർത്ത വളവുകള്ളുള്ള പാതകളിൽ ഉപയോഗപ്രദം. കാർട്ടെത്ര ലഘുവാണോ, അത്ര വേഗത്തിൽ അത് ത്വരണംചെയ്യുന്നു, പ്രത്യേകിച്ചും കുറഞ്ഞ വേഗതകളിൽ." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1654,14 +1711,14 @@ msgid "" " top speed." msgstr "പരമ. വേഗം - എത്ര ഉയർന്നതോ അത്, അത്ര വേഗത്തിൽ കാർട്ടിനുപോകാൻ സാധിക്കും. പ്രത്യേകിച്ച് നേർരേഖകളും നേർത്ത വളവുകളുമുള്ള പാതകളിൽ ഉപകരിക്കുന്നു. ഭാരേമേറിയ കാർട്ടുകൾക്ക് വിശാലമായ വേഗപരിധി ഉണ്ട്." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "നൈട്രോ ക്ഷമത - എത്ര ഉയർന്നതോ അത്, അത്ര കൂടുതൽ വേഗത ഒരു നൈട്രോ കാനിൽനിന്ന് നിങ്ങൾക്ക് ലഭിക്കുന്നു. ഒരു ലഘുവായ കാർട്ടിനായിരിക്കും കൂടുതൽ നൈട്രാ ക്ഷമത." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1669,12 +1726,12 @@ msgid "" "easier it is." msgstr "കുറച്ചുനിമിഷത്തേക്ക് മറ്റൊരു കാർട്ടിനോടു ചേർന്ന് നിങ്ങൾ പിന്തുടർന്നാൽ, അതിനെ മറികടക്കുമ്പോൾ നിങ്ങൾക്കൊരു സ്ലിപ്പ്സ്ട്രീം വേഗതാബോണസ് ലഭിക്കും. നിങ്ങളുടെ കാർട്ടെത്ര ലഘുവോ, അത്ര എളുപ്പമാണത്." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "സൂപ്പർടക്സ്കാർട്ട് ഓൺലൈനിൽ സംഘമായും കളിക്കാവുന്നതാണ്...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1684,7 +1741,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "ആദ്യം, പ്രധാന മെനുവിലെ 'ഓൺലൈൻ' ഐകൺ തിരഞ്ഞെടുക്കുക. പ്രാദേശിക നെറ്റ്‌വർക്കിംഗോ അല്ലെങ്കിൽ ആഗോള നെറ്റ്‌വർക്കിംഗോ (ഐച്ഛികങ്ങളിൽ ഇന്റർനെറ്റ് ലഭ്യമാക്കിയിടേണ്ടത് അനിവാര്യമാണ്) വേണ്ടത് നിർണ്ണയിക്കുക. ശേഷം, നിങ്ങൾക്ക് ഒന്നുകിൽ സ്വന്തമായൊരു സെർവർ കൃത്രിമ ഐച്ഛികങ്ങൾ ഉപയോഗിച്ചു സൃഷ്ടിക്കാം, അല്ലെങ്കിൽ നിലവിലെ സെർവറുകളുടെ ഒരു ലിസ്റ്റിൽനിന്ന് കണ്ടുപിടിച്ചു ചേരാം. അവയിൽ ചിലത് സവിശേഷമായി റാങ്കുചെയ്ത റേസുകളാൽ ശുപാർശ ചെയ്ത സെർവറുകളാണ്." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1694,12 +1751,12 @@ msgid "" "players and the server." msgstr "ഒരു സെർവറിൽ, അതിൻ്റെ ഉടമ (കിരീടംകൊണ്ട് പ്രധിനിധീകരിച്ചത്) താൽപര്യപ്പെടുന്ന പക്ഷം ഒരു റേസ് ആരംഭിക്കുന്നതാണ്. ഔദ്യോഗിക സെർവറുകൾ മതിയായ കളിക്കാരുള്ളപ്പോൾ മാത്രം റേസുകൾ സ്വയം ആരംഭിച്ചേക്കാം. ശേഷം, നിങ്ങൾക്ക് റേസിനുവേണ്ട കാർട്ട് തിരഞ്ഞെടുത്ത് തുടർന്നുള്ള പാതയ്ക്കായി വോട്ടുചെയ്യാം. ഒരു ആഡോൺപഥം ചേർന്നിരിക്കുന്ന എല്ലാ കളിക്കാരിലും സെർവറിലുമെല്ലാം നിലനിൽക്കുന്നെങ്കിൽ മാത്രമാണ് അനുവദനീയം." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... അല്ലെങ്കിൽ ഒരുപകരണത്തിൽ തന്നെ:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1709,7 +1766,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "ആദ്യം, നിങ്ങൾക്ക് അനവധി ഇൻപുട്ട് ഉപകരണങ്ങൾ വേണ്ടതാണ്. അവയെ പ്രാപ്തമാക്കിയെടുക്കുവാൻ ഇൻപുട്ട് ക്രമീകരണങ്ങൾ എന്ന തിരശ്ശീല ഉപയോഗിക്കുക. ഒന്നിലധികം ഗെയിംപാഡുകളോ ജോയ്സ്റ്റിക്കുകളോ ആണ് അനുേയോജ്യം: കീബോർഡിൽ, ഓരോ കളിക്കാരനും വ്യത്യസ്തതരം കീകൾ വേണം, മാത്രവുമല്ല മിക്ക കീബോർഡുകളും ഒരേസമയം ഒരുപാട് കീ പ്രസ്സുകൾ അനുവദിക്കുന്നതല്ല എന്നതുകൊണ്ടു തന്നെ സംഘറേസുകളിൽ ഇവ അനുയോജ്യമല്ല." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1729,17 +1786,17 @@ msgstr "ഉയർന്ന സ്കോർ തിരഞ്ഞെടുക്ക #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" -msgstr "ലാപ്പ് ട്രയൽ" +msgstr "ലാപ്പ് വേല" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "ഗ്രാന്റ് പ്രീ" @@ -1750,6 +1807,20 @@ msgstr "ഗ്രാന്റ് പ്രീ" msgid "Choose a Kart" msgstr "ഒരു കാർട്ട് തിരഞ്ഞെടുക്കുക" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "കാർട്ട് തരം" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "അഭീഷ്ടകാർട്ടുകൾ തിരുത്തുക" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1763,11 +1834,11 @@ msgstr "സ്പ്ലിറ്റ്സ്ക്രീൻ സംഘറേസ #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "ഓൺലൈൻ" @@ -1784,7 +1855,7 @@ msgstr "മാതൃക" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "ഉയർന്ന സ്കോറുകൾ" @@ -1792,7 +1863,7 @@ msgstr "ഉയർന്ന സ്കോറുകൾ" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "പുരസ്കാരങ്ങൾ" @@ -1846,30 +1917,30 @@ msgstr "സെർവർ കണ്ടെത്തുക" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "സെർവർ സൃഷ്ടിക്കുക" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "ഉപശാല" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "ക്രമീകരണം" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "റേസ് ആരംഭിക്കാം" @@ -1895,9 +1966,9 @@ msgstr "സെർവർ വിലാസം എഴുതുക" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "നിങ്ങളുടെ പ്രൊഫൈൽ" @@ -1915,7 +1986,7 @@ msgstr "കളിക്കാരന്റെ സ്ഥാനമാനങ്ങ #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "സുഹൃത്തുക്കൾ" @@ -1940,7 +2011,7 @@ msgstr "ഉടൻ കളിക്കാം" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "അക്കൗണ്ട് ക്രമീകരണങ്ങൾ" @@ -1990,8 +2061,8 @@ msgid "Online Username" msgstr "ഓൺലൈൻ ഉപയോക്തൃനാമം" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "രഹസ്യവാക്ക് വീണ്ടെടുക്കാം" @@ -2004,7 +2075,7 @@ msgid "" msgstr "ഒരു ഓഫ്‌ലൈൻ അക്കൗണ്ട് തിരഞ്ഞെടുക്കുന്നതു വഴി ഓൺലൈൻ അക്കൗണ്ട് ഇല്ലാതെയും നിങ്ങൾക്ക് കളിക്കാൻ സാധിക്കും. അങ്ങനെയെങ്കിൽ നിങ്ങൾക്ക് സുഹൃത്തുക്കളുമായി ബന്ധപ്പെടൽ, ആഡോണുകൾക്ക് വോട്ട് ചെയ്യൽ, മുതലായവ സാധിക്കുന്നതല്ല. ദയവായി ഞങ്ങളുടെ സ്വകാര്യതാനയം https://privacy.supertuxkart.net -ൽ വായിക്കുക." #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "സെർവർ തിരഞ്ഞെടുക്കൽ" @@ -2022,339 +2093,409 @@ msgstr "IPv6 കണക്ഷൻ ഉപയോഗിക്കുക" msgid "User search" msgstr "ഉപയോക്താവിനെ തിരയൽ" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "സൂപ്പർടക്സ്കാർട്ട് ഐച്ഛികങ്ങൾ" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "ദൃശ്യം" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "ഗ്രാഫിക്സ്" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "ശബ്ദം" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "പണിയിടം" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "കളിക്കാർ" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "നിയന്ത്രണങ്ങൾ" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "ഭാഷ" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "സംഗീതം" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "ലഭ്യമാണ്" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "ശബ്ദനിരക്ക്" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "ശബ്ദാലങ്കാരം" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "ക്രമീകരണം ഇല്ലാതാക്കുക" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "ക്രമീകരണം നിർത്തലാക്കുക" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "തിരികെ ഉപകരണ ലിസ്റ്റിലേക്ക്" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "ക്രമീകരണത്തിന്റെ പേരുമാറ്റുക" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "ഫോഴ്സ് ഫീഡ്ബാക്ക് ലഭ്യമാക്കുക (പിന്തുണയ്ക്കുന്നുവെങ്കിൽ)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "മിഴിവ്" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "സ്ക്രീൻ നിറഞ്ഞ്" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "വിൻഡോ സ്ഥാനം ഓർത്തുവയ്ക്കുക" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "പുതിയ മിഴിവ് പ്രയോഗിക്കുക" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "സ്പ്ലിറ്റ്സ്ക്രീൻ സംഘറേസ് ആമുഖം" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "ഇന്റർനെറ്റ് ഐച്ഛികങ്ങൾ" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" -msgstr "ലോഗിൻ സ്ക്രീൻ എല്ലായ്പ്പോഴും കാണിക്കുക" +msgstr "പുനഃപ്രവേശന സ്ക്രീൻ എല്ലായ്പ്പോഴും കാണിക്കുക" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "ഇന്റർനെറ്റുമായി ബന്ധപ്പെടാം" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "ഓൺലൈനിൽ സംസാരം ലഭ്യമാക്കാം" +msgid "Enable chatting in online lobbies" +msgstr "ഓൺലൈൻ ഉപശാലകളിൽ സംസാരം ലഭ്യമാക്കണം" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "ഓൺലൈൻ കളികളിൽ സംസാരം ലഭ്യമാക്കാം" +msgid "Enable chatting in online matches" +msgstr "ഓൺലൈൻ മത്സരങ്ങളിൽ സംസാരം ലഭ്യമാക്കണം" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "പലവക ഐച്ഛികങ്ങൾ" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "കളിക്കാരിൽ ദൗർഭല്യങ്ങൾ ലഭ്യമാക്കുക" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "മുഴുവൻ ഗെയിം ആസ്ഥികൾ അണിൻസ്റ്റാൾ ചെയ്യുക" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "ഒരുപകരണം ക്രമീകരിക്കാൻ അതിൽ ഇരട്ട-ക്ലിക്കോ എന്റർകീ അമർത്തുകയോ ചെയ്യൂ." -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "ഒരു ഉപകരണം ചേർക്കാം" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* ഏതു ക്രമീകരണം ഉപയോഗിക്കാമെന്ന് അനുമാനിക്കുന്നത് ഗെയിമിൽ ചേരാൻ ഏതു 'തിരഞ്ഞെടുക്കാം' കീയാണ് അമർത്തിയതെന്നുസരിച്ചാണ്." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "പുറംചട്ട" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "മിനിമാപ്പ്" +msgid "Skin variant" +msgstr "പുറംചട്ടാ വകഭേദം" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "സ്പ്ലിറ്റ്സ്ക്രീൻ സംഘറേസ് ആമുഖം" +msgid "Minimap" +msgstr "മിനിമാപ്പ്" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "ഫോണ്ട് വലിപ്പം" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "ക്യാമറ" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "കൃത്രിമം..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "FPS കാണിക്കുക" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "മറ്റു കാർട്ടുകൾക്കുള്ള ആയുധങ്ങൾ കാണിക്കുക" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "കഥ മോഡ് ടൈമർ ലഭ്യമാക്കാം" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "സ്പീഡ്റൺ ടൈമർ ലഭ്യമാക്കാം" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "അവതരണമിഴിവ്" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "ഗ്രാഫിക്കൽ ഇഫക്ടുകൾ നിരക്ക്" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "മങ്ങൽ ഇഫക്ടുകൾ നിരക്ക്" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "പരമാവധി FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "കൃത്രിമ ക്രമീകരണങ്ങൾ..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "മിഴിവ്" +msgid "Performance tests" +msgstr "പ്രകടനപരീക്ഷകൾ" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "സ്ക്രീൻ നിറഞ്ഞ്" +msgid "Performance test of the current settings" +msgstr "നിലവിലെ ക്രമീകരണങ്ങളുടെ പ്രകടനപരീക്ഷണം" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "വിൻഡോ സ്ഥാനം ഓർത്തുവയ്ക്കുക" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "രഹസ്യവാക്ക് ഓർത്തുവയ്ക്കുക" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "പുതിയ മിഴിവ് പ്രയോഗിക്കുക" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "ഇല്ലാതാക്കുക" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "കാർട്ട് നിറം" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2381,15 +2522,15 @@ msgstr "നീല ടീം" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "ലാപ്പുകളുടെ എണ്ണം" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "AI കാർട്ടുകളുടെ എണ്ണം" @@ -2404,32 +2545,16 @@ msgstr "നീല ടീം AI കാർട്ടുകളുടെ എണ്ണ msgid "Random Grand Prix" msgstr "ആകസ്മിക ഗ്രാന്റ് പ്രീ" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "അഭീഷ്ടപാതകൾ തിരുത്തുക" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" -msgstr "ലോഗിൻ" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "രഹസ്യവാക്ക് ഓർത്തുവയ്ക്കുക" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "ഇല്ലാതാക്കുക" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "കാർട്ട് നിറം" +msgstr "പ്രവേശിക്കുക" #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." @@ -2549,238 +2674,306 @@ msgid "" msgstr "പന്തുവഹിക്കുന്നൊരു കൂട്ടാളിയുടെ വഴിക്കുകയറരുത്, എങ്കിലും നിങ്ങൾ അവരെ സ്കോർ ചെയ്യുന്നത് തടയാൻ ശ്രമിക്കുന്ന എതിരാളികളെ പ്രഹരിക്കാൻ നോക്കുക." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "അഡ്യൂമി" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "അമാൻഡ" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "ഗോഡെറ്റ്" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "ഇമ്യൂൾ" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "ഗാവ്രോഷെ" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "ഗ്നു" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "ഹെക്സ്​ലി" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "കികി" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "കോൺക്വി" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "നോലോക്ക്" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "പിഡ്ജിൻ" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "പഫി" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "പെപ്പർ" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "സാറ" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "സൂസന്നെ" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "ടക്സ്" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "വിൽബർ" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "സ്യൂ" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "അത്യാദിമകാല തുരങ്കപ്പാത" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "അന്യഗ്രഹ സിഗ്നൽ" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "പ്രാചീന കൊളോസിയ വ്യൂഹം" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "കാൻഡെല നഗരം" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "യുദ്ധദ്വീപ്" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "മേഘവർണ്ണക്കാട്" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "X ഗുഹ" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "കൊക്കോ ക്ഷേത്രം" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "ചോളപ്പാടത്തിനു കുറുകെ" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "ചെകുത്താൻ കോട്ട" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "ഗ്രാൻ പാരഡിസോ ദ്വീപ്" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "ഹസിയെൻഡ" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "ന്യൂജെൻ ഗോലികളി" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "ഹിമ സോക്കർ ഫീൽഡ്" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" -msgstr "എന്തുപറ്റി, കുഞ്ഞുകോമാളികളെ? നിങ്ങളുടെ മഹാനായ ഗ്നു നേതാവിനെ കാണാനില്ലെന്നോ?" +msgstr "എന്തുപറ്റി, കുഞ്ഞുകോമാളികളെ? നിങ്ങളുടെ മഹാനായ ഗ്നു നേതാവിനെ കാണ്മനില്ലെന്നോ?\n​​​​​​​​​​​​​​\n​​​​​​​​​​​​" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." -msgstr "ഓ അതെ, നോക്ക്, അവനിപ്പോൾ എന്റെ മാളികയിലാണ്, അത്താഴത്തിനായി ഞാനവനെ വിളമ്പുന്നതായിരിക്കും..." +msgstr "ഓ അതെ, നോക്ക്, അവനിപ്പോൾ എന്റെ മാളികയിലാണ്, അത്താഴത്തിനായി ഞാനവനെ വിളമ്പുന്നതായിരിക്കും...\n​​​​​\n​​​​​​" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." -msgstr "പക്ഷേ ഞാനൊരു നീതിമാനായ ജീവിയാണ്, അതിനാൽ ഞാനും നീയുമായി ഒരു കരാറിടാം." +msgstr "പക്ഷേ ഞാനൊരു നീതിമാനായ ജീവിയാണ്, അതിനാൽ ഞാനും നീയുമായി ഒരു കരാറിടാം.\n​​​​​​​​​​​​​​​​​\n​​​​​​​​​​​" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." -msgstr "നിനക്കെന്നെ റേസിംഗിൽ തോല്പിക്കാമെങ്കിൽ, ഞാനാ പഴയ കാർന്നോരെ വിട്ടയയ്ക്കാം." +msgstr "നിനക്കെന്നെ റേസിംഗിൽ തോല്പിക്കാമെങ്കിൽ, ഞാനാ പഴയ കാർന്നോരെ വിട്ടയയ്ക്കാം.\n​​​​​​\n​​​​​​​​" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" -msgstr "പക്ഷേ നിങ്ങൾ പരിതാപകരായ കുഞ്ഞുവങ്കന്മാർക്ക് ഒരിക്കലും എന്നെ തോല്പിക്കാൻ ആകില്ല - ഈ കാർട്ടുകളുടെ രാജാവിനെ!" +msgstr "പക്ഷേ നിങ്ങൾ പരിതാപകരായ കുഞ്ഞുവങ്കന്മാർക്ക് ഒരിക്കലും എന്നെ തോല്പിക്കാൻ ആകില്ല - ഈ കാർട്ടുകളുടെ രാജാവിനെ!\n​​​​​​​​\n​​​​​​​​" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "ലാസ് ഡൂനാസ് മേഖല" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "ലാസ് ഡൂനാസ് സോക്കർ സ്റ്റേഡിയം" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "വിളക്കുമാടത്തിനുചുറ്റും" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "പഴയ ഖനി" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "മിനിഗോൾഫ്" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "മരുപ്പച്ച" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "ഒലിവറുടെ ഗണിത ക്ലാസ്" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "മത്തൻ പാർക്ക്" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "റാവൻബ്രിഡ്ജ് മാളിക" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "പാറും മണൽത്തരികൾ" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "നെസ്സീയുടെ കുളം" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "ഉത്തരദ്രുവ റിസോർട്ട്" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "മഞ്ഞു കൊടുമുടി" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "സോക്കർ ഫീൽഡ്" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "സ്റ്റേഡിയം" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK നിലയം" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "ക്ഷേത്രം" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "അഗ്നിപർവ്വ ദ്വീപ്" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "സെൻ ഉദ്യാനം" @@ -2789,11 +2982,11 @@ msgstr "സെൻ ഉദ്യാനം" msgid "Completed achievement \"%s\"." msgstr "പുരസ്കാരം നേടിയിരിക്കുന്നു \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "സൂപ്പർടക്സ്കാർട്ട് ആഡ്-ഓൺ സെർവറുമായി ബന്ധപ്പെടൽ പരാജയപ്പെട്ടു." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "വാർത്ത ഡൗൺലോഡ് ചെയ്യുന്നതിൽ പിശക്: '%s'." @@ -2859,7 +3052,7 @@ msgid "New kart '%s' now available" msgstr "പുതിയ കാർട്ട് '%s' ഇപ്പോൾ ലഭ്യമാണ്" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2891,32 +3084,32 @@ msgid "" "created." msgstr "താങ്കളുടെ ക്രമീകരണ ഫയൽ തീരെ പഴയതായിരുന്നു, അതിനാലത് ഇല്ലാതാക്കി പുതിയൊരെണ്ണം സൃഷ്ടിച്ചിരിക്കുന്നു." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "വീഡിയോ റെക്കോർഡിംഗ് ആരംഭിച്ചിരിക്കുന്നു" -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." -msgstr "വീഡിയോ \"%s\" -ൽ സൂക്ഷിച്ചിരിക്കുന്നു." +msgstr "വീഡിയോ \"%s\"-ൽ സൂക്ഷിച്ചിരിക്കുന്നു." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "എൻകോഡിംഗ് പുരോഗതി:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" -msgstr "FPS: %d/%d/%d - %d കെട്രിസ്, പിങ്: %dms" +msgstr "FPS: %d/%d/%d - %d ടി-മൂഭുജജാലം, പിങ്: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "സൂത്രം: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "സജ്ജീകരിക്കുന്നു" @@ -2938,19 +3131,18 @@ msgstr "നൈട്രോ ക്ഷമത" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (ദുർബലപ്പെടുത്തി)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s തയ്യാറാണ്" @@ -3424,21 +3616,21 @@ msgid "Axis %d" msgstr "അച്ചുതണ്ട് %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "ഗെയിംപാഡ് ബട്ടൺ %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "മൗസ് ബട്ടൺ %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "മൗസ് അച്ചുതണ്ട് %d%s" @@ -3610,26 +3802,30 @@ msgstr "നിങ്ങൾക്കു കൂടിയത് 3 ജീവനു msgid "+1 life." msgstr "+1 ജീവൻ" -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "നിങ്ങൾ തീരെ പതുക്കെയായിരുന്നു!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "നിങ്ങൾ റേസ് പൂർത്തീകരിച്ചു!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "നിങ്ങൾ റേസ് വിജയിച്ചിരിക്കുന്നു!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "റാങ്ക് %d-ൽ നിങ്ങൾ റേസ് പൂർത്തീകരിച്ചു!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s ഗെയിം വിട്ടു." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3638,16 +3834,16 @@ msgid "" "Internet\")." msgstr "സൂപ്പർടക്സ്കാർട്ട് ആഡ്-ഓണുകൾ ഡൗൺലോഡ് ചെയ്യുന്നതിനും പുതുമകളപ്പറ്റി താങ്കളെ അറിയിക്കുന്നതിനുമായി ഒരു സെർവറുമായി ബന്ധപ്പെട്ടേക്കാം. ദയവായി ഞങ്ങളുടെ സ്വകാര്യതാനയം https://supertuxkart.net/Privacy -ൽ വായിക്കുക. താങ്കൾ ഈ പ്രത്യേകത ലഭ്യമാക്കാൻ ആഗ്രഹിക്കുന്നുവോ? (ഈ ക്രമീകരണം പിൽക്കാലത്ത് മാറ്റുന്നതിനായി, ഐച്ഛികങ്ങളിലേക്കു പോകുക, 'പൊതുവസ്തുതകൾ' ടാബ് തിരഞ്ഞെടുക്കുക, ശേഷം \"ഇന്റർനെറ്റുമായി ബന്ധപ്പെടുക\" തിരുത്തുക)." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "താങ്കളുടെ സ്ക്രീൻ മിഴിവ് STK പ്രവർത്തിക്കാൻ തീരെ കുറവാണ്." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "താങ്കളുടെ ഡ്രൈവർ വേർഷൻ തീരെ പഴയതാണ്. ദയവായി ഏറ്റവുംപുതിയ വീഡിയോ ഡ്രൈവറുകൾ ഇൻസ്റ്റാൾ ചെയ്യുക." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3655,38 +3851,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "താങ്കളുടെ ഗ്രാഫിക്സ് ഡ്രൈവർ വളരെ പഴയതായി കാണുന്നു. ദയവായി ഏതെങ്കിലും അപ്ഡേറ്റുകൾ ഉണ്ടോയെന്ന് പരിശോധിക്കുക. സൂപ്പർടക്സ്കാർട്ട് ശുപാർശ ചെയ്യുന്നത് %s-ഓ മികച്ചതോ പിന്തുണയ്ക്കുന്ന ഒരു ഡ്രൈവറാണ്. ഗെയിം ഇപ്പോഴും പ്രവർത്തിക്കാനാണ് സാധ്യത, ഒരു ലഘു-ഗ്രാഫിക്സ് മോഡിലാണെന്നുമാത്രം." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "സെർവറുമായി ബന്ധപ്പെടൽ സമയം നീണ്ടു." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s ചുവപ്പ് പതാക വഹിക്കുന്നു!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "ചുവന്ന പതാക പിൻവലിച്ചിരിക്കുന്നു!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s നീല പതാക വഹിക്കുന്നു!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "നീല പതാക പിൻവലിച്ചിരിക്കുന്നു!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s പതാക പിടിച്ചടക്കി!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s ചുവന്ന പതാക പിടിച്ചടക്കി!" @@ -3696,7 +3892,7 @@ msgstr "%s ചുവന്ന പതാക പിടിച്ചടക്കി! msgid "Eggs: %d / %d" msgstr "മുട്ടകൾ: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "നേതാവ്" @@ -3704,22 +3900,22 @@ msgstr "നേതാവ്" msgid "Final lap!" msgstr "അവസാന ലാപ്പ്!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "ലാപ്പ് %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s-ൽ %s കൈവരിച്ചു" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "പുതിയ വേഗമേറിയ ലാപ്പ്" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "തെറ്റായ വഴി!" @@ -3733,194 +3929,194 @@ msgstr "%s ഒരു ഗോളടിച്ചു!" msgid "Oops, %s made an own goal!" msgstr "അയ്യോ, %s ഒരു സ്വയം ഗോളടിച്ചു!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "%i സ്‌പെയർ ചക്ര കാർട്ടിനെ നിരത്തിലിറക്കിയിരിക്കുന്നു!" msgstr[1] "%i സ്‌പെയർ ചക്ര കാർട്ടുകളെ നിരത്തിലിറക്കിയിരിക്കുന്നു!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "നിങ്ങളെ സ്ഥാനഭ്രംശം ചെയ്തിരിക്കുന്നു!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "'%s' എന്നയാളെ സ്ഥാനഭ്രംശം ചെയ്തിരിക്കുന്നു!" -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "സെർവർ ഷട്ട് ഡൗൺ ചെയ്തിരിക്കുന്നു." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "നിങ്ങളെ സെർവറിൽ നിന്ന് തട്ടിമാറ്റിയിരിക്കുന്നു." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." -msgstr "നിങ്ങളെ തട്ടിമാറ്റി: പിങ് തീരെ കൂടുതൽ." +msgstr "നിങ്ങളെ തട്ടിമാറ്റി: പിങ് ഏറെ കൂടുതൽ." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "മോശം നെറ്റ്‌വർക്ക് കണക്ഷൻ കണ്ടെത്തി." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "യന്ത്രം" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s ബന്ധം വിച്ഛേദിച്ചു." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "കളിക്കാരുടെ നിർവ്വഹണത്തിനും റാങ്കിംഗ് വിവരങ്ങൾക്കുമായി ലിസ്റ്റിൽ കളിക്കാരന്റെ പേരിനുനേരെ അമർത്തുക." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "പ്രയാസം: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "ഏറിയ കളിക്കാർ: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "ഗെയിം മോഡ്: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "സമയപരിധി" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "ഗോൾ പരിധി" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "സോക്കർ ഗെയിം രീതി: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "ഗ്രാന്റ് പ്രീ പുരോഗതി: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "ചുവപ്പോ നീലയോ ടീമുകളിലായി എല്ലാ കളിക്കാരും ചേർന്നിരിക്കുന്നു." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "നിങ്ങളാണ് ഇപ്പോൾ സെർവറിന്റെ ഉടമ." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "ബന്ധപ്പെടൽ വിലക്കി: സെർവർ തിരക്കിലാണ്." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "ബന്ധപ്പെടൽ വിലക്കി: നിങ്ങളെ സെർവറിൽ നിന്ന് നിരോധിച്ചിരിക്കയാണ്." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "ബന്ധപ്പെടൽ വിലക്കി: സെർവർ രഹസ്യവാക്ക് തെറ്റാണ്." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "ബന്ധപ്പെടൽ വിലക്കി: ഗെയിം വിവരങ്ങൾ അപര്യാപ്തമാണ്." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "ബന്ധപ്പെടൽ വിലക്കി: സെർവർ നിറഞ്ഞിരിക്കുന്നു." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "ബന്ധപ്പെടൽ വിലക്കി: അസാധുവായ കളിക്കാരൻ ബന്ധപ്പെടുന്നു." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "നെറ്റ്‌വർക്ക് ഗെയിം ആരംഭിക്കാൻ പരാജയപ്പെട്ടു." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "ഗെയിം അവസാനിച്ചിരിക്കുന്നു, നിങ്ങൾക്ക് ഇനിയധികം തത്സമയം ചേരാനോ ദർശിക്കാനോ കഴിയുകയില്ല." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "ഒരവശേഷിക്കുന്ന ഒഴിവും മേഖലയിലില്ല - തത്സമയ ചേരൽ ലഭ്യമല്ല." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "1 കളിക്കാൻ മാത്രമേ ശേഷിക്കുന്നുള്ളു, ഉപശാലയിലേക്ക് മടങ്ങുന്നു." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "സെർവർ ഉടമ ഗെയിം ഉപേക്ഷിച്ചു." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "നിങ്ങൾ അടുത്ത ഗെയിം ദർശിക്കുന്നതായിരിക്കും." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s ചുവപ്പ് ടീമിൽ ചേർന്നു." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s നീല ടീമിൽ ചേർന്നു." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s ഗെയിമിൽ ചേർന്നു." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3928,15 +4124,15 @@ msgid "" msgstr "ലക്ഷ്യംവച്ച കളിക്കാരനെ മാറ്റുവാൻ <%s> അല്ലെങ്കിൽ <%s> അമർത്തുക, <%s> അല്ലെങ്കിൽ <%s> ക്യാമറ സ്ഥാനത്തിനായും." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "%s എന്നയാളെ വിജയകരമായി പരാതിപ്പെട്ടു." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3967,38 +4163,38 @@ msgstr "സമയസാമർഥ്യം (ഗ്രാന്റ് പ്രീ #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "എല്ലാറ്റിനും-സ്വാതന്ത്ര്യം" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "പതാക പിടിച്ചടക്കുക" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s ഇപ്പോൾ ഓൺലൈനിലുണ്ട്." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s, %s എന്നിവർ ഇപ്പോൾ ഓൺലൈനിലുണ്ട്." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s പിന്നെ %s എന്നിവർ ഇപ്പോൾ ഓൺലൈനിലുണ്ട്." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4006,19 +4202,19 @@ msgstr[0] "%d സുഹൃത്ത് ഇപ്പോൾ ഓൺലൈനില msgstr[1] "%d സുഹൃത്തുക്കൾ ഇപ്പോൾ ഓൺലൈനിലുണ്ട്." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s ഇപ്പോൾ \"%s\" സെർവറിലാണ്." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "നിങ്ങൾക്ക് %d പുതിയ സുഹൃത്ത് അപേക്ഷ ഉണ്ട്!" msgstr[1] "നിങ്ങൾക്ക് %d പുതിയ സുഹൃത്ത് അപേക്ഷകൾ ഉണ്ട്!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "നിങ്ങൾക്ക് ഒരു പുതിയ സുഹൃത്ത് അപേക്ഷ ഉണ്ട്!" @@ -4047,12 +4243,12 @@ msgid "" msgstr "ഉയർന്ന സ്കോറുകളുടെ ഫയൽ തീരെ പഴയതായിരുന്നു,\nഎല്ലാ ഉയർന്ന സ്കോറുകളും മായ്ച്ചിരിക്കുന്നു." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "നേതാവിനെ പിന്തുടരൂ" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "3 പ്രഹര യുദ്ധം" @@ -4063,93 +4259,90 @@ msgstr "അപൂർണ്ണമായ റീപ്ലേ ഫയൽ സുക് #: src/replay/replay_recorder.cpp:394 #, c-format msgid "Replay saved in \"%s\"." -msgstr "റീപ്ലേ \"%s\" -ൽ സൂക്ഷിച്ചിരിക്കുന്നു." +msgstr "റീപ്ലേ \"%s\"-ൽ സൂക്ഷിച്ചിരിക്കുന്നു." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 ആഴ്ച" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 ആഴ്ചകൾ" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 മാസം" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 മാസങ്ങൾ" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 മാസങ്ങൾ" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 മാസങ്ങൾ" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 വർഷം" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 വർഷങ്ങൾ" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "ആഡ്-ഓൺ നാമം" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "പുതുക്കിയ തീയതി" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "ഇൻസ്റ്റാൾ ചെയ്യാത്തത്" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s നിർമ്മിച്ചത്: %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "ആഡോണുകൾ പുതുക്കുംവരെ ദയവായി കാത്തിരിക്കുക" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "ക്ഷമിക്കണം, ആഡ്-ഓണുകളുടെ വെബ്സൈറ്റുമായി ബന്ധപ്പെടുന്നതിനിടെ ഒരു പിശക് സംഭവിച്ചു. ദയവായി താങ്കൾ ഇന്റർനെറ്റുമായി ബന്ധപ്പെട്ടിട്ടുണ്ടെന്നും സൂപ്പർടക്സ്കാർട്ടിനെ ഒരു ഫയർവാളും തടഞ്ഞിട്ടില്ലെന്നും ഉറപ്പാക്കുക" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "ഇഷ്ടമുള്ളവ" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" -msgstr "പൂട്ടിയിരിക്കുന്നു: അധികയോഗ്യതകൾ നേടാൻ സജീവ വെല്ലുവിളികൾ പരിഹരിക്കൂ!" +msgstr "പൂട്ടിയിരിക്കുന്നു: അധികയോഗ്യതകൾ നേടാൻ സജീവവെല്ലുവിളികൾ പരിഹരിക്കൂ!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "ആകസ്മിക മേഖല" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d മേഖല ഒറ്റയാളിൽ അലഭ്യമാണ്." -msgstr[1] "%d മേഖലകൾ ഒറ്റയാളിൽ അലഭ്യമാണ്." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nAdithyan S S, 2020\nAdithyan S S, 2020-2024\nAdithyan S S, 2020-2022\nAdithyan S S, 2020-2021\nAdithyan SS ആദിത്യൻ എസ് എസ് (aka Alphacelestius)\nLaunchpad: ~thestrawberryandkiwi-2\nGitHub: The-Legendary-Psycho" @@ -4437,7 +4630,7 @@ msgstr "ശേഖരിച്ച പഴത്തൊലികൾ" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "സ്കിഡ്ഡിംഗ്" @@ -4540,7 +4733,7 @@ msgstr "പൂർത്തീകരിച്ച മുട്ട വേട്ട msgid " (official tracks matching the goal)" msgstr "(ലക്ഷ്യവുമായി ചേരുന്ന ഔദ്യോഗിക പാതകൾ)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4548,91 +4741,95 @@ msgid "" msgstr "പുതിയ ഗെയിംപാഡുകളും ജോയിസ്റ്റിക്കുകളും നിങ്ങൾ ഈ ഉപകരണവുമായി ബന്ധിപ്പിക്കുമ്പോൾ അവ സ്വയം പ്രത്യക്ഷപ്പെടുന്നതാണ്.\n\nഒരു കീബോർഡ് ക്രമീകരണം ചേർക്കാൻ, നിങ്ങൾക്ക് താഴെയുള്ള ബട്ടൺ ഉപയോഗിക്കാം, എന്നിരുന്നാലും മിക്ക കീബോർഡുകളും ഒരു പരിമിതമായ അളവിൽ മാത്രമേ സമകാലിക കീപ്രസ്സുകൾ പിന്തുണയ്ക്കുള്ളുവെന്നും തന്മൂലം അവ സംഘറേസ് ഗെയിംപ്ലേകൾക്ക് അനുചിതമാണെന്നും ദയവായി ശ്രദ്ധിക്കുക. (എന്നിരുന്നാലും, നിങ്ങൾക്ക് കഴിയും, ഒന്നിലധികം കീബോർഡുകൾ ഈ ഉപകരണവുമായി ബന്ധിപ്പിക്കാൻ. ഈ സ്ഥിതിയിൽ എല്ലാവർക്കും വ്യത്യസ്ത കീയനുക്രമണങ്ങൾ അപ്പോഴും വേണമെന്ന് ഓർക്കുക.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "വീമോട്ട് ചേർക്കാം" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "കീബോർഡ് ക്രമീകരണം ചേർക്കാം" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "പുതുക്കുക" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "വേർഷൻ: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "സവിശേഷം" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "വലിപ്പം: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "ഈ ആഡോണിനു മൂല്യമിടാൻ നിങ്ങൾ പ്രവേശിച്ചിരിക്കണം." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "ക്ഷമിക്കണം, ആഡ്-ഓൺ ഡൗൺലോഡ് ചെയ്യൽ പരാജയപ്പെട്ടു" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "ആഡോൺ '%s' ഇൻസ്റ്റാൾ ചെയ്യുന്നതിൽ പ്രശ്നങ്ങൾ." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "വീണ്ടും ശ്രമിക്കാം" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "ആഡോൺ '%s' നീക്കം ചെയ്യുന്നതിൽ പ്രശ്നങ്ങൾ." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "പശ്ചാത്തല ഡൗൺലോഡ് പൂർത്തിയാക്കി." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "പശ്ചാത്തല ഡൗൺലോഡ്" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "പശ്ചാത്തല ഡൗൺലോഡ് ഇതിനകം ആരംഭിച്ചിരിക്കുന്നു." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "ഇപ്പോഴത്തെ രഹസ്യവാക്ക് അസാധുവാണ്." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "രഹസ്യവാക്ക് 8നും 30നും മദ്ധ്യേ പ്രതീകങ്ങൾ നീളുന്നതാകണം!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "രഹസ്യവാക്കുകൾ തമ്മിൽ യോജിക്കുന്നില്ല!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "വിവരം സാധൂകരിക്കുന്നു" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "രഹസ്യവാക്ക് വിജയകരമായി മാറ്റിയിരിക്കുന്നു." @@ -4653,67 +4850,97 @@ msgstr "1024x768 അല്ലെങ്കിൽ 1280x720-നെക്കാൾ #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" -msgstr "ഡ്രോൺ ചേസ്" +msgstr "ഡ്രോൺ അനുഗമനം" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "കൃത്രിമം" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "ലഭ്യമല്ല" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "പ്രധാനപ്പെട്ടതുമാത്രം" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "വളരെ താഴ്ന്നത്" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "താഴ്ന്നത്" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "ഇടത്തരം" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "ഉയർന്നത്" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "വളരെ ഉയർന്നത്" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "അത്യുഗ്രം" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4721,7 +4948,7 @@ msgid "" msgstr "മികച്ച ഗെയിമിംഗ് അനുഭവത്തിനായി സൂപ്പർടക്സ്കാർട്ട് സമ്പൂർണ്ണ ആസ്ഥികളും (ഉന്നത നിലവാരത്തിലുള്ള ടെക്സ്ച്ചറുകളും സംഗീതവും ഉൾപ്പെടെ) ഡൗൺലോഡ് ചെയ്യുന്നതാണ്, നിങ്ങൾക്കു വൈഫൈ കണക്ഷൻ ഇല്ലെങ്കിൽ ഇത് നിങ്ങളുടെ മൊബൈൽ ഡേറ്റയാണ് ഉപയോഗിക്കുന്നത്." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4738,101 +4965,102 @@ msgstr "ഇഷ്ടാനുസൃതമായി : -നു പിന്നാ msgid "Invalid server address: %s." msgstr "അസാധുവായ സെർവർ വിലാസം: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "എതിർദിശ" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "പ്രയാസം" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "ലാപ്പുകൾ" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "സമയം" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "കാർട്ട്" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "ഉപയോക്താവ്" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "വേർഷൻ" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "ഇല്ല" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "പാത" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "ആദ്യ %d ഉയർന്ന സ്കോറുകൾ" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "കാർട്ടുകളുടെ എണ്ണം: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "സമയ ലക്ഷ്യം: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "ലാപ്പുകൾ: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "എതിർദിശ: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(ശൂന്യം)" @@ -4920,33 +5148,41 @@ msgid "Press any key..." msgstr "ഏതെങ്കിലുമൊരു കീ അമർത്തൂ..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "സംസാരം ലഭ്യമല്ല, ഐച്ഛികമെനുവിൽ ലഭ്യമാക്കുക." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "തിരികെ പ്രകടനപരീക്ഷയിലേക്ക്" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "പ്രകടനപരീക്ഷ ഉപേക്ഷിക്കുക" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "തിരികെ യുദ്ധത്തിലേക്ക്" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "പുതിയ ഗെയിം രൂപീകരിക്കുക" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "യുദ്ധം പുനരാരംഭിക്കുക" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "യുദ്ധം ഉപേക്ഷിക്കുക" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "പുതിയ റേസ് രൂപീകരിക്കുക" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "റേസ് ഉപേക്ഷിക്കുക" @@ -4962,18 +5198,18 @@ msgstr "%s എന്നയാൾക്ക് ഇതുവരെ ഒരു സ് msgid "%s is number %d in the rankings with a score of %f." msgstr "%s എന്നയാൾ %d റാങ്കിലാണ്, %f സ്കോറോടൊപ്പം." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "ഉപയോക്തൃനാമമോ ഇമെയിൽ വിലാസമോ രണ്ടുംകൂടിയോ അസാധുവാണ്." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " "agree to these terms in order to register an account for STK. If you have " "any questions or comments regarding these terms, one of the members of the " "development team would gladly assist you." -msgstr "ദയവായി സൂപ്പർടക്സ്കാർട്ടിനായുള്ള നിബന്ധനകളും വ്യവസ്ഥകളും '%s' -ൽ വായിക്കുക. STK-യിൽ ഒരു അക്കൗണ്ട് റെജിസ്റ്റർ ചെയ്യുന്നതിലേക്കായി താങ്കൾ ഈ നിബന്ധനകളും വ്യവസ്ഥകളും പാലിച്ചിരിക്കേണ്ടതുണ്ട്. ഈ നിബന്ധനകളുമായി ബന്ധപ്പെട്ട് താങ്കൾക്ക് എന്തെങ്കിലും ചോദ്യങ്ങളോ അഭിപ്രായങ്ങളോ ഉണ്ടെങ്കിൽ, ഞങ്ങളുടെ ഡെവലപ്മെന്റ് ടീമിലെ ഒരംഗം താങ്കളെ സന്തോഷപൂർവം സേവിക്കുന്നതായിരിക്കും." +msgstr "ദയവായി സൂപ്പർടക്സ്കാർട്ടിനായുള്ള നിബന്ധനകളും വ്യവസ്ഥകളും '%s'-ൽ വായിക്കുക. STK-യിൽ ഒരു അക്കൗണ്ട് രേഖപ്പെടുത്തുന്നതിലേക്കായി താങ്കൾ ഈ നിബന്ധനകളും വ്യവസ്ഥകളും പാലിച്ചിരിക്കേണ്ടതുണ്ട്. ഈ നിബന്ധനകളുമായി ബന്ധപ്പെട്ട് താങ്കൾക്ക് എന്തെങ്കിലും ചോദ്യങ്ങളോ അഭിപ്രായങ്ങളോ ഉണ്ടെങ്കിൽ, ഞങ്ങളുടെ ആവിർഭാവസംഘത്തിലെ ഒരംഗം താങ്കളെ സന്തോഷപൂർവം സേവിക്കുന്നതായിരിക്കും." #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:60 @@ -4988,7 +5224,7 @@ msgstr "പ്രേത റീപ്ലേ റേസ്" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "ലാപ്പുകൾ: %i" @@ -5001,21 +5237,21 @@ msgstr "രീതി: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "അനിവാര്യ സ്ഥാനം: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "അനിവാര്യ സമയം: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "അനിവാര്യ നൈട്രോ പോയിന്റുകൾ: %i" @@ -5028,54 +5264,54 @@ msgstr "AI കാർട്ടുകളുടെ എണ്ണം: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "യുദ്ധ മോഡ്" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "സോക്കർ ഗെയിം രീതി" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "സെർവർ സ്ഥലം: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "ഇപ്പോഴത്തെ പാത: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "സ്ഥാനം" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "കളിക്കാരൻ" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "സ്കോറുകൾ" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "കളിച്ച സമയം" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "ബുക്ക്മാർക്ക് നീക്കം ചെയ്യാം" @@ -5088,74 +5324,74 @@ msgid "No player available for connecting to server." msgstr "സെർവറുമായി ബന്ധപ്പെടാൻ ഒരു കളിക്കാരനേയും ലഭിച്ചില്ല." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "ഉപയോക്തൃനാമം: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "അപേക്ഷ റദ്ദുചെയ്യുക" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "ഇന്ന്" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "സുഹൃത്ത് അപേക്ഷ അയച്ചു!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "സുഹൃത്ത് അപേക്ഷ അംഗീകരിച്ചു!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "സുഹൃത്ത് അപേക്ഷ നിക്ഷേധിച്ചു!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "സുഹൃത്തിനെ നീക്കംചെയ്തു!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "സുഹൃത്ത് അപേക്ഷ റദ്ദുചെയ്തു!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "സ്വീകരിക്കുന്നു" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "അവസാന വോട്ട് സമാഹരിക്കുന്നു" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." -msgstr "കീഴെയുള്ള നക്ഷത്രങ്ങൾ ക്ലിക്കുചെയ്ത് നിങ്ങൾക്ക് മുൻപത്തെ റേറ്റിംഗ് ആവിഷ്കരിക്കാൻ സാധിക്കും." +msgstr "കീഴെയുള്ള നക്ഷത്രങ്ങൾ ക്ലിക്കുചെയ്ത് നിങ്ങൾക്ക് മുൻപത്തെ മൂല്യനിർണയം ആർജ്ജിക്കാൻ സാധിക്കും." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" -msgstr "നിങ്ങളിതുവരെയും ഈ ആഡോണിനായി വോട്ടുചെയ്തിട്ടില്ല. കീഴെയുെള്ള നക്ഷത്രങ്ങൾ ക്ലിക്കുചെയ്ത് നിങ്ങളുടെ ഇച്ഛാനുസൃതം റേറ്റിംഗ് തിരഞ്ഞെടുക്കുക." +msgstr "നിങ്ങളിതുവരെയും ഈ ആഡോണിനായി വോട്ടുചെയ്തിട്ടില്ല. കീഴെയുെള്ള നക്ഷത്രങ്ങൾ ക്ലിക്കുചെയ്ത് നിങ്ങളുടെ ഇച്ഛാനുസൃതം മൂല്യം തിരഞ്ഞെടുക്കുക." -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "വോട്ട് വിജയകരമായി! നിങ്ങൾക്ക് ഇനിയി ജാലകം അടയ്ക്കാം." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "വോട്ട് പ്രകടിപ്പിക്കുന്നു" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "ആകസ്മിക പാത" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5184,7 +5420,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "നിങ്ങളുടെ ഗ്രാന്റ് പ്രീ സൂക്ഷിക്കാൻ ശ്രമിക്കുമ്പോൾ ഒരു പിഴവു പറ്റി." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "ഒരു പാത തിരഞ്ഞെടുക്കുക" @@ -5228,12 +5464,12 @@ msgstr "നിങ്ങൾ തുറന്നു പാത %0" msgid "You unlocked grand prix %0" msgstr "നിങ്ങൾ തുറന്നു ഗ്രാന്റ് പ്രീ %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "പാത" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5254,40 +5490,40 @@ msgstr "ദയവായി ഗ്രാന്റ് പ്രീയുടെ ന msgid "Please select a Grand Prix" msgstr "ദയവായി ഗ്രാന്റ് പ്രീ തിരഞ്ഞെടുക്കുക" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "ഉപയോക്തൃസംഗ്രഹം" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "നാമം ശൂന്യമാണ്" -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "ഇതേ പേരുള്ള മറ്റൊരു ഗ്രാന്റ് പ്രീ ഇതിനകം നിലനിൽക്കുന്നു." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." -msgstr "നാമം തീരെ നീണ്ടതാണ്" +msgstr "നാമം ഏറെ നീണ്ടതാണ്." #. I18N: when failing a GP #: src/states_screens/grand_prix_lose.cpp:157 msgid "Better luck next time!" msgstr "അടുത്ത തവണ ഭാഗ്യം തുണയ്ക്കും!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "നിങ്ങൾ ഒരു വെല്ലുവിളി പൂർത്തീകരിച്ചിരിക്കുന്നു!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "നിങ്ങൾ ഗ്രാന്റ് പ്രീ വിജയിച്ചിരിക്കുന്നു!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "നിങ്ങൾ ഗ്രാന്റ് പ്രീ പൂർത്തീകരിച്ചിരിക്കുന്നു!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "കാർട്ടുകളുടെ എണ്ണം" @@ -5300,110 +5536,125 @@ msgstr "നിങ്ങൾക്ക് ഈ ഉയർന്ന സ്കോർ msgid "Are you sure you want to remove all of your high scores?" msgstr "നിങ്ങൾക്ക് നിങ്ങളുടെ ഉയർന്ന സ്കോറുകളെല്ലാം നീക്കംചെയ്യണമെന്ന് ഉറപ്പാണോ?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "ഇഷ്ടമുള്ളത്" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "ലഘു" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "കഠിനം" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "സ്പ്ലിറ്റ്സ്ക്രീൻ സംഘറേസ് കളിക്കുന്നതിനായി ഒരു കീബോർഡോ ഗെയിംപാഡോ ബന്ധിപ്പിക്കുക" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "ആകസ്മിക കാർട്ട്" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "പൂട്ടിയിരിക്കുന്നു" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "എല്ലാവരും:\nഗെയിമിൽ ചേരാൻ 'തിരഞ്ഞെടുക്കാം' ബട്ടൺ അമർത്തുക" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "ഗെയിമിന്റെ മാതൃക കളിക്കുവാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുവോ?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "ഇന്റർനെറ്റ് ലഭ്യതയില്ലാതെ നിങ്ങൾക്ക് ഓൺലൈനായി കളിക്കാൻ കഴിയില്ല. നിങ്ങൾക്ക് ഓൺലൈനായി കളിക്കണമെങ്കിൽ, ഐച്ഛിക മെനുവിലേക്ക് പോകുക, പിന്നെ \"ഇന്റർനെറ്റുമായി ബന്ധപ്പെടുക\"യിൽ ശരിയിടുക." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "ഇന്റർനെറ്റ് ലഭ്യതയില്ലാതെ നിങ്ങൾക്ക് ആഡോണുകൾ ഡൗൺലോഡ് ചെയ്യാൻ കഴിയില്ല. നിങ്ങൾക്ക് ആഡോണുകൾ ഡൗൺലോഡ് ചെയ്യണമെങ്കിൽ ഐച്ഛിക മെനുവിലേക്ക് പോകുക, പിന്നെ \"ഇന്റർനെറ്റുമായി ബന്ധപ്പെടുക\"യിൽ ശരിയിടുക." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "ഇന്റർനെറ്റ് ലഭ്യതയില്ലാതെ നിങ്ങൾക്ക് ആഡോണുകൾ ഡൗൺലോഡ് ചെയ്യാൻ കഴിയില്ല. നിങ്ങൾക്ക് ആഡോണുകൾ ഡൗൺലോഡ് ചെയ്യണമെങ്കിൽ ഐച്ഛിക മെനുവിലേക്ക് പോകുക, പിന്നെ \"ഇന്റർനെറ്റുമായി ബന്ധപ്പെടുക\"യിൽ ശരിയിടുക.\n\nഎന്നിരുന്നാലും നിങ്ങൾക്ക് ഇതിനകം ഡൗൺലോഡ് ചെയ്ത ആഡോണുകൾ ഇല്ലാതാക്കാൻ കഴിയും." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "ആഡോണുകൾ പരിമാണം നിലവിൽ ഐച്ഛിക സ്ക്രീനിൽ ലഭ്യമല്ല." -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "ആഡോണുകൾ ഒരുങ്ങുംവരെ ദയവായി കാത്തിരിക്കുക" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "STK വിടണമെന്ന് നിങ്ങൾക്കുറപ്പാണോ?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "LAN സെർവർ സൃഷ്ടിക്കാം" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "%s-ന്റെ സെർവർ" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "ഗ്രാന്റ് പ്രീ പഥങ്ങളുടെ എണ്ണം" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "നാമം 4നും 30നും മദ്ധ്യേ പ്രതീകങ്ങൾ നീളുന്നതാകണം!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "രഹസ്യവാക്കിൽ തെറ്റായ പ്രതീകങ്ങൾ!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "തയ്യാർ" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "തത്സമയ ചേരൽ" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "സാക്ഷ്യംവഹിക്കുക" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "ആഡോൺ ഇൻസ്റ്റാൾ ചെയ്യുക" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5411,7 +5662,7 @@ msgstr "ദയവായി ഇപ്പോഴത്തെ ഗെയിമിന #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "ദയവായി ഇപ്പോഴത്തെ ഗെയിമിന്റെ അന്ത്യംവരെ കാത്തിരിക്കുക, ഉദ്ദേശം അവശേഷിക്കുന്ന സമയം: %s." @@ -5419,24 +5670,24 @@ msgstr "ദയവായി ഇപ്പോഴത്തെ ഗെയിമിന #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "ദയവായി ഇപ്പോഴത്തെ ഗെയിമിന്റെ (%s) അന്ത്യംവരെ കാത്തിരിക്കുക, ഉദ്ദേശപുരോഗതി: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "ദയവായി ഇപ്പോഴത്തെ ഗെയിമിന്റെ അന്ത്യംവരെ കാത്തിരിക്കുക, ഉദ്ദേശപുരോഗതി: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "ദയവായി ഇപ്പോഴത്തെ ഗെയിമിന്റെ അന്ത്യംവരെ കാത്തിരിക്കുക." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5445,7 +5696,7 @@ msgstr[1] "%d കളിക്കാരിൽ കൂടുതൽ ഉള്ളപ #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5454,96 +5705,108 @@ msgid_plural "" msgstr[0] "%d നിമിഷത്തിനുശേഷം ആരംഭിക്കുന്നു, അല്ലെങ്കിൽ എല്ലാവരും 'തയ്യാറാണ്' ബട്ടൻ അമർത്തുന്നൊരിക്കൽ." msgstr[1] "%d നിമിഷങ്ങൾക്കുശേഷം ആരംഭിക്കുന്നു, അല്ലെങ്കിൽ എല്ലാവരും 'തയ്യാറാണ്' ബട്ടൻ അമർത്തുന്നൊരിക്കൽ." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "%s സെർവറുമായി ബന്ധപ്പെടുന്നു" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "ഉടൻ കളിക്കാൻ ഒരു സെർവർ കണ്ടെത്തുന്നു" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "അവശേഷിക്കുന്ന സമയം: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "ലക്ഷ്യങ്ങൾ" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "പുരസ്കാരങ്ങൾ കണ്ടെടുക്കുന്നു" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "%s-ന്റെ പ്രോഫൈൽ" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "മുതൽ" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "സ്ഥിതി" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "സുഹൃത്തുക്കളെ കണ്ടെടുക്കുന്നു" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "പുതിയ അപേക്ഷ" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "വൈകുന്നു" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "ഓഫ്‌ലൈൻ" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "താഴെ പുതിയ ഇ-മെയിൽ എഴുതുക" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "പുതിയ ഇമെയിൽ 5നും 254നും മദ്ധ്യേ പ്രതീകങ്ങൾ നീളുന്നതാകണം!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "പുതിയ ഇമെയിൽ അസാധുവാണ്!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "ഇ-മെയിൽ മാറ്റി!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "ഇ-മെയിൽ മാറ്റൽ പരാജയപ്പെട്ടു: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "STK ബ്ലോഗിൽ നിന്നുള്ള വാർത്ത" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "തീയതി" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "നിലവിൽ ഒരു വാർത്തയും ലഭ്യമല്ല." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." -msgstr "ആഗോള നെറ്റ്‌വർക്കിംഗ് കളിക്കുവാൻ നിങ്ങൾ തീർച്ചയായും ലോഗിൻ ചെയ്തിട്ടുണ്ടാകണം. മുകളിൽ നിങ്ങളുടെ ഉപയോക്തൃനാമം ക്ലിക്കുചെയ്യുക." +msgstr "ആഗോള നെറ്റ്‌വർക്കിംഗ് കളിക്കുവാൻ നിങ്ങൾ തീർച്ചയായും പ്രവേശിച്ചിട്ടുണ്ടാകണം. മുകളിൽ നിങ്ങളുടെ ഉപയോക്തൃനാമം ക്ലിക്കുചെയ്യുക." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "തിരയുന്നു" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "ഗെയിം ഉപേക്ഷിക്കുക" @@ -5621,34 +5884,34 @@ msgid "Distance (km)" msgstr "ദൂരം (കി.മി.)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "അജ്ഞാതം" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "IPv4 ഒന്നും കണാനായില്ല, നിങ്ങൾക്ക് സെർവറുകളിലൊന്നിലും ചേരാൻ ആയെന്നുവരില്ല." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "IPv6 ഒന്നും കണാനായില്ല, നിങ്ങൾക്ക് സെർവറുകളിലൊന്നിലും ചേരാൻ ആയെന്നുവരില്ല." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "ഒരു സെർവറും ലഭ്യമല്ല." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "സെർവറുകൾ കണ്ടെടുക്കുന്നു" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "സെർവർ ബുക്ക്മാർക്കുകൾ" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5656,149 +5919,149 @@ msgstr "ഒരു ഭൂരിപക്ഷം കളിക്കാർ എല് #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "ആകസ്മിക വസ്തുസ്ഥലം" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "ജയിക്കാൻവേണ്ട ഗോളുകളുടെ എണ്ണം" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "എതിർദിശയിൽ ഓടിക്കുക" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "പൂട്ടിയിരിക്കുന്നു: കൂടുതൽ യോഗ്യതകൾ പ്രാപ്തമാക്കാൻ സജീവ വെല്ലുവിളികൾ പരിഹരിക്കൂ!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "ആംഗ്യം" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "കീ അനുക്രമണം" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "ഉപകരണം അലഭ്യമാക്കുക" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "ഉപകരണം ലഭ്യമാക്കുക" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "ക്രമീകരണം ലഭ്യമാക്കുക" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "ഗെയിം കീകൾ" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "മെനു കീകൾ" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "ഇടത്തോട്ടു തിരിക്കാം" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "വലത്തോട്ടു തിരിക്കാം" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "ത്വരിപ്പിക്കാം" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "ബ്രേക്ക് / എതിർദിശ" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "ഫയർ" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "നൈട്രോ" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "തിരിഞ്ഞുനോക്കാം" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "രക്ഷ" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "ഗെയിം നിർത്താം" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "മുന്നോട്ട്" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "താഴോട്ട്" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "ഇടത്" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "വലത്" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "തിരഞ്ഞെടുക്കാം" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "റദ്ദാക്കുക/പിന്നോട്ട്" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* നീലനിറം മറ്റൊരു ക്രമീകരണവുമായുള്ള ഒരു സംഘട്ടനം അർത്ഥമാക്കുന്നു" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* ചുവപ്പുനിറം നിലവിലെ ക്രമീകരണവുമായുള്ള ഒരു സംഘട്ടനം അർത്ഥമാക്കുന്നു" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5806,17 +6069,27 @@ msgid "" msgstr "മുന്നറിയിപ്പ്: 'ഷിഫ്റ്റ്' ശുപാർശചെയ്യപ്പെട്ട ഒരു കീ അല്ല. 'ഷിഫ്റ്റ്' താഴേക്കമർത്തുമ്പോൾ, ഉച്ചശ്രേണിയിൽ വ്യത്യാസം പ്രകടിപ്പിക്കുന്ന ഒരു പ്രതീകമുളള കീകളെല്ലാം പണിമുടക്കുന്നു." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "നിങ്ങൾക്ക് ഈ ക്രമീകരണം എന്നെന്നേക്കുമായി ഇല്ലാക്കണമെന്ന് ഉറപ്പാണോ?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "പുതിയ ക്രമീകരണനാമം എഴുതുക, സ്വതേയുള്ള മൂല്യം പ്രതിഗമിക്കുവാൻ ശൂന്യമായി ഇടുക." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "ലംഭം" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "തിരശ്ചീനം" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5824,89 +6097,74 @@ msgstr "സംഘറേസ് മോഡിൽ, കളിക്കാർക്ക #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "മുഴുവൻ ഗെയിം ആസ്ഥികൾ ഡൗൺലോഡ് ചെയ്യുക" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "നിങ്ങൾക്ക് മുഴുവൻ ഗെയിം ആസ്ഥികളും അണിൻസ്റ്റാൾ ചെയ്യാൻ ഉറപ്പാണോ?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "കീബോർഡ് %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "ടച്ച് ഉപകരണം" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "ഒരുപകരണം ക്രമീകരിക്കാൻ അതിൽ സ്പർശിക്കുക" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "സിസ്റ്റം ഭാഷ" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "താഴെ-ഇടത്തായി" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "വലതു വശത്തായി" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "മറഞ്ഞിരിക്കുന്നു" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "കേന്ദ്രീകൃതം" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "ലംഭം" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "തിരശ്ചീനം" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "വളരെ ചെറുത്" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "ചെറുത്" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "ഇടത്തരം" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "വലുത്" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "വളരെ വലുത്" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5916,128 +6174,133 @@ msgid "" msgstr "കഥാ മോഡിന്റെ വിക്ഷേപണം മുതൽക്കേ ഗെയിം അടച്ചിട്ടില്ലെങ്കിൽ മാത്രമേ സ്പീഡ്റൺ മോഡ് ലഭ്യമാക്കാനാവൂ.\n\nകഥ മോഡിന്റെ പൂർത്തീകരണത്തിനു മുൻപേ ഗെയിം അടയ്ക്കുന്നത് ടൈമർ അസാധുവാക്കുന്നു.\n\nസ്പീഡ്റൺ മോഡ് ഉപയോഗിക്കുന്നതിനായി, ദയവായി ഒരു പുതിയ പ്രൊഫൈൽ ഉപയോഗിക്കുക." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "വെർറ്റിക്കൽ സിങ്ക്" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "വിസിങ്ക് മോണിറ്റർ പ്രദർശിപ്പിക്കാൻ തുനിയുമ്പോൾ\nമാത്രം പുതിയൊരു ഫ്രെയിം അതിനായി\nനിയോഗിക്കാൻ ഗ്രാഫിക്സ് കാർഡിനെ നിർബന്ധിക്കുന്നു." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "നിങ്ങളുടെ ഉപകരണം പര്യാപ്തമല്ലെങ്കിൽ വിസിങ്ക് പ്രവർത്തിക്കുകയില്ല." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "തന്മാത്രകൾ ഗുണങ്ങൾ: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "ചലിക്കുന്ന കഥാപാത്രങ്ങൾ: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "ചലനാത്മക പ്രകാശങ്ങൾ: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "പ്രകാശം ചിതറിക്കൽ: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" -msgstr "ആന്റി-എലീസിംഗ്: %s" +msgstr "ആകാരമൃദുവൽകരണം: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" -msgstr "ആംബിയന്റ് ഒക്ലൂഷൻ: %s" +msgstr "പരിസ്ഥിതി ഗൂഹനം: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "നിഴലുകൾ: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "നിഴലുകൾ: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "ശോഭ: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "തിളക്കം (ഔട്ട്ലൈനുകൾ): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" -msgstr "പ്രകാശരശ്മികൾ (അർക്കകിരണങ്ങൾ): %s" +msgstr "പ്രകാശധാര (അർക്കകിരണങ്ങൾ): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "അവതരിപ്പിച്ച ചിത്രത്തിൻ്റെ വ്യക്തത: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "ജ്യാമിതിവിവരണം: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "ചലന അവ്യക്തത: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" -msgstr "ഡെപ്ത് ഓഫ് ഫീൽഡ്: %s" +msgstr "പരിസരവ്യാപ്തി: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "ഇന്റർനെറ്റ് ലഭ്യത നിഷേധിച്ചിരിക്കുന്നു, നിങ്ങൾക്കത് ലഭ്യമാക്കണമോ?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "നിങ്ങൾ ഒരു രഹസ്യവാക്ക് എഴുതേണ്ടതാണ്." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" -msgstr "'%s' ലോഗൗട്ട് ചെയ്യുന്നു" +msgstr "'%s' പുറത്തുകടക്കുന്നു" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" -msgstr "'%s' ലോഗിൻ ചെയ്യുന്നു" +msgstr "'%s' പ്രവേശിക്കുന്നു" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "ശേഷിക്കുന്ന കളിക്കാരനെ ഇല്ലാതാക്കാനാകില്ല." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "നിങ്ങൾക്ക് ശരിക്കും '%s' എന്നയാളെ നീക്കംചെയ്യണമോ?" @@ -6065,7 +6328,7 @@ msgstr "ഗോോൾ!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "മറ്റുള്ളവർക്കായി കാക്കുന്നു" @@ -6098,9 +6361,9 @@ msgstr "നേതാവിനെ പിന്തുടരൂ!" #: src/states_screens/race_gui_base.cpp:954 #, c-format msgid "Top %i" -msgstr "ആദ്യ %i" +msgstr "%i മുന്നണികൾ" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "വെല്ലുവിളി പരാജയപ്പെട്ടു" @@ -6124,109 +6387,206 @@ msgstr "വെല്ലുവിളി ആരംഭിക്കുവാൻ സ msgid "Press fire to start the challenge" msgstr "വെല്ലുവിളി ആരംഭിക്കുവാൻ ഫയർ അമർത്തൂ" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "തിരികെ വീഡിയോ ക്രമീകരണങ്ങളിലേക്ക്\n​​​​​​​​​​​​​​​​​​​" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "പരീക്ഷണഫലങ്ങൾ സൂക്ഷിക്കുക" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "തിരികെ പ്രധാനമെനുവിലേക്ക്" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "സെർവർ ഉപേക്ഷിക്കുക" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "ഗ്രാന്റ് പ്രീ നിഷ്ഫലമാക്കുക" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "പുനരാരംഭിക്കുക" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "തിരികെ വെല്ലുവിളി തിരയലിലേക്ക്" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "പുതിയ പ്രേത റീപ്ലേയ്ക്കെതിരെ റേസ് ചെയ്യാം" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "തിരികെ മെനുവിലേക്ക്" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "നിങ്ങൾക്ക് ശരിക്കും ഗ്രാന്റ് പ്രീ നിഷ്ഫലമാക്കണമോ?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "പ്രകടനരേഖ \"%s\"-ൽ സൂക്ഷിച്ചിരിക്കുന്നു." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "ചുവപ്പ് ടീമിന് ജയം" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "നീല ടീമിന് ജയം" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "അത് സമനിലയിലെത്തി" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "%s-നു ശേഷം സ്ഥാനഭ്രംശനാക്കി" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "സ്ഥാനഭ്രംശനാക്കി" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(സ്വയം ഗോൾ)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "പാത: %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "ഗ്രാന്റ് പ്രീ പുരോഗതി:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "ഉയർന്ന സ്കോറുകൾ" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "മികച്ച ലാപ്പ് സമയം: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "%s കൈവരിച്ചു" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "നിങ്ങൾ വെല്ലുവിളി\n പൂർത്തീകരിച്ചിരിക്കുന്നു!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "നിങ്ങൾ വെല്ലുവിളിയിൽ പരാജയപ്പെട്ടു!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "സൂപ്പർടക്സിന്റെ യോഗ്യതകളിൽ എത്തിച്ചേർന്നു." +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "പ്രകടനപരീക്ഷാഫലങ്ങൾ" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "പരീക്ഷണ ദൈർഘ്യം: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "ഫ്രെയിമുകളുടെ എണ്ണം: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "സുസ്ഥിര FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "പ്രായേണ സ്ഥിര FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "ലക്ഷണമൊത്ത FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "തിരശ്ചീനമിഴിവ്: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "ലംഭമിഴിവ്: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "ചലനാത്മകദീപ്തി: സജീവം" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "ചലനാത്മകദീപ്തി: അജീവം" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "അവതരണമിഴിവ്: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "ആകാരമൃദുവൽകരണം: സജീവം" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "ആകാരമൃദുവൽകരണം: അജീവം" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "ചിത്രാധിഷ്ടിതദീപ്തി: അജീവം" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "ചിത്രാധിഷ്ടിതദീപ്തി: സജീവം" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "പരിസ്ഥിതി ഗൂഹനം: സജീവം" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "പരിസ്ഥിതി ഗൂഹനം: അജീവം" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "നിഴൽ മിഴിവ്: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "എല്ലാ പ്രഹരങ്ങളും അനുവദിച്ചിരിക്കുന്നു, അതിനാൽ ആയുധങ്ങൾ ശേഖരിച്ച് അവയുടെ ബുദ്ധിപരമായ ഉപയോഗം കാഴ്ച്ചവയ്ക്കൂ!" #: src/states_screens/race_setup_screen.cpp:96 msgid "Contains no powerups, so only your driving skills matter!" -msgstr "ആയുധങ്ങളൊന്നുമില്ല, അതുകൊണ്ട് നിങ്ങളുടെ ഡ്രെെവിങ്ങ് മിടുക്കുകൾക്കാണ് ഇവിടെ കാര്യം!" +msgstr "ആയുധങ്ങളൊന്നുമില്ല, അതുകൊണ്ട് നിങ്ങളുടെ ഡ്രെെവിംഗ് മിടുക്കുകൾക്കാണ് ഇവിടെ കാര്യം!" #. I18N: short definition for follow-the-leader game mode #: src/states_screens/race_setup_screen.cpp:109 @@ -6260,28 +6620,28 @@ msgstr "ടീം മാറ്റുവാൻ സോക്കർ ഐകൺ ച #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "പാത നിർമ്മിച്ചത്: %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "പരമ. പിന്തുണയ്ക്കുന്ന കളിക്കാർ: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "ചുവപ്പ് ടീം AI കാർട്ടുകളുടെ എണ്ണം" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "ഈ ഗ്രാന്റ് പ്രീയിൽ അടങ്ങിയിരിക്കുന്ന ചില പാതകൾ തുറക്കപ്പെടാത്തതിനാൽ കളിക്കാൻ സാധിക്കുന്നതല്ല." -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "പൂട്ടിയിരിക്കുന്നു!" @@ -6303,53 +6663,62 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "ഭീമൻ വാതിൽ തുറക്കുവാൻ എല്ലാ വെല്ലുവിളികളും പൂർത്തീകരിക്കുക!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" "Check the minimap for\n" "available challenges." -msgstr "ഈ വെല്ലുവിളിയിൽ പ്രവേശി\n-ക്കാൻ നിങ്ങൾക്ക് കൂടുതൽ\nപോയിന്റുകൾ വേണം! ലഭ്യമായ\nവെല്ലുവിളികൾക്കായി മിനിമാപ്പ്\nപരിശോധിക്കൂ." +msgstr "ഈ വെല്ലുവിളിയിൽ കയറുവാൻ\nനിങ്ങൾക്ക് കൂടുതൽ \nപോയിന്റുകൾ വേണം! ലഭ്യമായ\nവെല്ലുവിളികൾക്കായി മിനിമാപ്പ്\nപരിശോധിക്കൂ." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "<%s> ത്വരിപ്പിക്കുവാൻ, കൂടാതെ വളയ്ക്കുവാൻ <%s> പിന്നെ <%s>" #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "ചക്രത്തിന്റെ മുകൾഭാഗത്ത് സ്പർശിച്ചുകൊണ്ട് ത്വരണംചെയ്യുക, ഇടതോ വലതോ ചലിപ്പിച്ച് വളയ്ക്കാൻ ശ്രമിക്കുക." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "ആക്സിലറേറ്റർ മുകളിലേക്ക് ചലിപ്പിച്ച് ത്വരണംചെയ്യുക, നിങ്ങളുടെ ഉപകരണം ചരിച്ചുകൊണ്ട് വളയ്ക്കാൻ ശ്രമിക്കുക." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "ആക്സിലറേറ്റർ മുകളിലേക്ക് ചലിപ്പിച്ച് ത്വരണംചെയ്യുക, നിങ്ങളുടെ ഉപകരണം കറക്കിക്കൊണ്ട് വളയ്ക്കാൻ ശ്രമിക്കുക." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "സമ്മാനപ്പൊതികൾ ശേഖരിക്കുക, ഈ പെട്ടികളെ വകഞ്ഞുമാറ്റാൻ <%s> കൊണ്ട് ആയുധം എയ്യൂ!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "സമ്മാനപ്പൊതികൾ ശേഖരിക്കുക, ഈ പെട്ടികളെ വകഞ്ഞുമാറ്റാൻ ബൗളിംഗ് ഐകൺ അമർത്തി എയ്യൂ!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6357,34 +6726,41 @@ msgid "" msgstr "പിൻപോട്ടു നോക്കുവാൻ <%s> അമർത്തൂ.\n<%s> കൊണ്ട് ആയുധം എയ്യുന്നതിനിടെ <%s> അമർത്തി പിൻപോട്ടു എയ്യൂ!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "പിൻപോട്ടു നോക്കുവാൻ കണ്ണാടി ഐകൺ അമർത്തുക.\nകണ്ണാടി ഐകൺ അമർത്തിപ്പിടിച്ചശേഷം ബൗളിംഗ് ഐകണിലേക്ക് സ്വൈപ്പ് ചെയ്ത് ആയുധം എയ്യൂ!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "<%s> അമർത്തി നിങ്ങൾ ശേഖരിച്ച നൈട്രോ ഉപയോഗിക്കൂ!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "നൈട്രോ ഐകൺ അമർത്തി നിങ്ങൾ ശേഖരിച്ച നൈട്രോ ഉപയോഗിക്കുക" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "നൈട്രോ കുപ്പികൾ ശേഖരിക്കൂ (നാം ഒരു വളവിനുശേഷം അവ ഉപയോഗിക്കും)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "അയ്യോ! നിങ്ങൾ കുഴപ്പത്തിലാകുമ്പോൾ, രക്ഷനേടാൻ <%s> അമർത്തൂ." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "അയ്യോ! നിങ്ങൾ കുഴപ്പത്തിലാകുമ്പോൾ, രക്ഷനേടാൻ പക്ഷി ഐകൺ അമർത്തൂ." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6392,24 +6768,27 @@ msgid "" msgstr "സ്കിഡ്ഡ് ചെയ്യാൻ ത്വരണംചെയ്ത് തിരിയുന്നതിനിടെ <%s> അമർത്തൂ.\nഅല്പനേരത്തെ സ്കിഡ്ഡിംഗ് വേഗത്തിൽ തിരിയാൻ ഉതകുന്നതുവഴി നിങ്ങളെ കൂർത്ത വളവുകൾ എടുക്കാൻ സഹായിക്കും." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "സ്കിഡ്ഡ് ചെയ്യാൻ ത്വരണംചെയ്ത് തിരിയുന്നതിനിടെ സ്കിഡ്ഡ് ഐകൺ അമർത്തൂ.\nഅല്പനേരം സ്കിഡ്ഡ് ചെയ്യുന്നത് വേഗത്തിൽ തിരിയാൻ ഉതകുന്നതുവഴി നിങ്ങളെ കൂർത്ത വളവുകൾ എടുക്കാൻ സഹായിക്കും." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "കുറേനിമിഷത്തേക്ക് നിങ്ങൾ സ്കിഡ്ഡ് കൈകാര്യം ചെയ്താൽ, പ്രതിഫലമെന്നോണം നിങ്ങൾക്കൊരു വേഗോന്നതി ബോണസ് ലഭിക്കുമെന്ന് ഓർക്കുക!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "ഇപ്പോൾ നിങ്ങൾ റേസിനു സജ്ജമാണ്. ഭാഗ്യം നേരുന്നു!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "ഒരു സ്വതന്ത്ര 3D കാർട്ട് റേസിംഗ് ഗെയിം" @@ -6419,7 +6798,7 @@ msgstr "ഒരു സ്വതന്ത്ര 3D കാർട്ട് റേസ msgid "tux;game;race;" msgstr "ടക്സ്;ഗെയിം;റേസ്;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6427,16 +6806,16 @@ msgid "" "for all ages." msgstr "കാർട്ടുകൾ. നൈട്രോ. ആക്ഷൻ! സൂപ്പർടക്സ്കാർട്ട് വൈവിധ്യമാർന്ന കഥാപാത്രങ്ങളും, സ്ഥലങ്ങളും, കളിക്കുവാൻ പല മോഡുകളും അണിനിരക്കുന്ന ഒരു സ്വതന്ത്ര 3D ആർക്കേഡ് റേസറാണ്. യാഥാർത്ഥ്യം എന്നതിലുപരി രസകരമായ, എല്ലാ പ്രായക്കാരിലും ആസ്വാദ്യാനുഭവം ഉളവാക്കുന്ന ഒരു ഗെയിം സൃഷ്ടിക്കുക എന്നതാണ് ഞങ്ങളുടെ ലക്ഷ്യം." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" " while avoiding other karts as they may overtake you, but don't eat the " "bananas! Watch for bowling balls, plungers, bubble gum, and cakes thrown by " "your opponents." -msgstr "കളിക്കാരുടെ ആസ്വാദനത്തിനായി ഞങ്ങൾ അവതരിപ്പിക്കുന്നു വിവിധ ആശയങ്ങൾ ഉൾക്കൊള്ളിച്ച പാതകൾ, പന്തയം ആഴക്കടലിൽ തുടങ്ങി, ഗ്രാമീണ കൃഷിയിടങ്ങളും, വനങ്ങളും കടന്ന് ശൂന്യകാശം വരെയെത്തുന്നു! മറ്റു കാർട്ടുകൾ നിങ്ങളെ എതിരിടുമെന്നതിനാൽ അവരെ പരമാവധി ഒഴിവാക്കാൻ ശ്രമിക്കുക, പക്ഷേ പഴത്തൊലികൾ തിന്നരുത്! നിങ്ങളുടെ എതിരാളികൾ എറിയുന്ന ബൗളിംഗ് ബോളുകൾ, പ്ലഞ്ചറുകൾ, ബബിൾ ഗം, പിന്നെ കേക്കുകൾ എന്നിവയ്ക്കുമേൽ ഒരു കണ്ണു വേണം." +msgstr "കളിക്കാരുടെ ആസ്വാദനത്തിനായി ഞങ്ങൾ അവതരിപ്പിക്കുന്നു വിവിധ ആശയങ്ങൾ ഉൾക്കൊള്ളിച്ച പാതകൾ, പന്തയം ആഴക്കടലിൽ തുടങ്ങി, ഗ്രാമീണ കൃഷിയിടങ്ങളും, വനങ്ങളും കടന്ന് ശൂന്യകാശം വരെയെത്തുന്നു! മറ്റു കാർട്ടുകൾ നിങ്ങളെ എതിരിടുമെന്നതിനാൽ അവരെ പരമാവധി ഒഴിവാക്കാൻ ശ്രമിക്കുക, പക്ഷേ പഴത്തൊലികൾ തിന്നരുത്! നിങ്ങളുടെ എതിരാളികൾ എറിയുന്ന ബൗളിംഗ് ബോളുകൾ, പ്ലഞ്ചറുകൾ, ബബിൾ ഗം, കേക്കുകൾ എന്നിവയ്ക്കുമേൽ ഒരു കണ്ണു വേണം." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6445,27 +6824,27 @@ msgid "" "your racing skills!" msgstr "മറ്റു കാർട്ടുകൾക്കെതിരെ നിങ്ങൾക്ക് ഒരു ഒറ്റയാൾ റേസ് നടത്താൻ സാധിക്കും, ഒരുപാട് ഗ്രാന്റ് പ്രീകളിലൊന്നിൽ മത്സരിക്കാനും, നിങ്ങൾക്ക് സ്വന്തമായി സമയ-സാമർഥ്യ കളികളിലെ ഉയർന്ന സ്കോർ പരാജയപ്പെടുത്താനും, കമ്പ്യൂട്ടറിനോ നിങ്ങളുടെ സുഹൃത്തുക്കൾക്കോ എതിരെ യുദ്ധമോഡിൽ കളിക്കാനും കൂടാതെ ധാരാളം! വിപുലമായ ഒരു വെല്ലുവിളിക്കായി, ഓൺലൈനിൽ ചേർന്ന് ലോകത്താകമാനമുള്ള കളിക്കാരെ കണ്ടുമുട്ടി നിങ്ങളുടെ റേസിംഗ് മിടുക്കുകൾ തെളിയിക്കു!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "ഈ ഗെയിം പരസ്യരഹിതമാണ്." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "ഇത് ഏറ്റവുംപുതിയ പരിഷ്ക്കാരങ്ങൾ ഉൾക്കൊള്ളിച്ച സൂപ്പർടക്സ്കാർട്ടിന്റെ ഒരു അസ്ഥിര വേർഷനാണ്. ഇത് സ്ഥിര STK കഴിയുന്നത്ര മികച്ചതാക്കുവാൻ, പ്രധാനമായും പരിശോധനയ്ക്കായി റിലീസ് ചെയ്തിരിക്കുന്നതാണ്." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "ഈ വേർഷൻ സ്ഥിര വേർഷനോട് സമാന്തരമായി ഉപകരണത്തിൽ ഇൻസ്റ്റാൾ ചെയ്യാവുന്നതാണ്." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "കൂടുതൽ സ്ഥിരത നിങ്ങൾക്കു ആവശ്യമെങ്കിൽ, സ്ഥിര വേർഷൻ ഉപയോഗിക്കുന്നത് പരിഗണിക്കുക: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "സൂപ്പർടക്സ്കാർട്ട് ടീം" diff --git a/data/po/nl.po b/data/po/nl.po index 04a5eb2a3ab..20fe9bb0615 100644 --- a/data/po/nl.po +++ b/data/po/nl.po @@ -6,7 +6,7 @@ # David Blaszyk , 2017 # Dennis Holierhoek , 2016 # Frans van Rijn , 2015-2016 -# Heimen Stoffels , 2021-2023 +# Heimen Stoffels , 2021-2024 # Heimen Stoffels , 2019-2021 # Steven van Tetering , 2019 # Ward Muylaert , 2015-2017 @@ -16,9 +16,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Heimen Stoffels , 2021-2023\n" +"Last-Translator: Heimen Stoffels , 2021-2024\n" "Language-Team: Dutch (http://app.transifex.com/supertuxkart/supertuxkart/language/nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -140,7 +140,7 @@ msgstr "Doe alsof je tegenstanders muggen zijn! Mep met de vliegenmepper in éé #. I18N: ./data/achievements.xml msgid "Beyond Luck" -msgstr "Meer dan geluk" +msgstr "Grote geluksvogel" #. I18N: ./data/achievements.xml msgid "" @@ -175,7 +175,7 @@ msgstr "Het einde van de wereld" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Terug" @@ -197,7 +197,7 @@ msgstr "Geef aan hoe je karts wilt besturen" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Versnellingsmeter" @@ -211,15 +211,15 @@ msgstr "Versnellingsmeter" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Gyroscoop" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" -msgstr "Extern stuur" +msgstr "Fysiek stuur" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui @@ -248,35 +248,37 @@ msgstr "Apparaatinstellingen" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Algemeen" @@ -344,30 +346,33 @@ msgstr "Standaardwaarden terugzetten" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Annuleren" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Ja" @@ -545,9 +550,9 @@ msgstr "Deelnemen" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -608,7 +613,7 @@ msgstr "Doel" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Voortgang" @@ -643,7 +648,7 @@ msgstr "Versturen" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Terug naar wedstrijd" @@ -660,7 +665,7 @@ msgstr "Terug naar lobby" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Wedstrijd herstarten" @@ -714,7 +719,7 @@ msgstr "Account herstellen" msgid "" "You will receive an email with further instructions on how to reset your " "password. Please be patient and be sure to check your spam folder." -msgstr "Je ontvangt een e-mail met instructies m.b.t. het herstellen van je wachtwoord. Dit kan even duren. Controleer ook de spammap." +msgstr "Je ontvangt een e-mail met instructies die je kunt volgen om je wachtwoord te herstellen. Dit kan even duren. Controleer ook de spammap." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui msgid "" @@ -724,12 +729,12 @@ msgstr "Voer de gebruikersnaam en het e-mailadres in die je gebruikt hebt bij he #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Gebruikersnaam" @@ -770,7 +775,7 @@ msgstr "Moeilijkheidsgraad" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Beginner" @@ -782,7 +787,7 @@ msgstr "Beginner" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Behendig" @@ -794,7 +799,7 @@ msgstr "Behendig" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Deskundig" @@ -806,7 +811,7 @@ msgstr "Deskundig" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -814,8 +819,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Spelvorm" @@ -826,8 +831,8 @@ msgstr "Spelvorm" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Normale race" @@ -840,7 +845,7 @@ msgstr "Normale race" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Tijdrit" @@ -848,7 +853,8 @@ msgstr "Tijdrit" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Gevecht" @@ -857,24 +863,24 @@ msgstr "Gevecht" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Voetbal" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Wachtwoord" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Server toevoegen aan favorieten" @@ -885,7 +891,7 @@ msgstr "Speler toevoegen" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Naam" @@ -979,6 +985,50 @@ msgstr "Esc-toets gebruiken" msgid "Assign nothing" msgstr "Niets toewijzen" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Aanbevolen grafische instellingen" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "De aanbevolen instellingen zijn samengesteld op basis van de huidige resolutie." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Waar moet de voorkeur aan worden gegeven?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Prestaties" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Balans tussen prestaties en grafische kwaliteit" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Grafische kwaliteit" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Energiebesparing" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Vind je het mooi als er vervagingen worden getoond?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Test starten" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -993,11 +1043,11 @@ msgstr "Wedstrijdregels" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Doorgaan" @@ -1015,7 +1065,7 @@ msgstr "Bijgewerkt" #. I18N: In addons screen, in the filtering bar, to enable a filter that will #. show only items with good rating msgid "Rating >=" -msgstr "Waardering >=" +msgstr "Beoordeling >=" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In the addons screen @@ -1038,10 +1088,15 @@ msgstr "Arena's" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Geïnstalleerd" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Favoriete arenas aanpassen" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1051,20 +1106,20 @@ msgstr "Geïnstalleerd" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Standaard" @@ -1075,12 +1130,12 @@ msgstr "Standaard" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Uitbreidingen" @@ -1094,27 +1149,28 @@ msgstr "Uitbreidingen" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Alle" @@ -1153,9 +1209,9 @@ msgstr "Omlaag verplaatsen" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Toevoegen" @@ -1192,7 +1248,7 @@ msgstr "Kies een spookherhaling" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Eieren zoeken" @@ -1239,10 +1295,10 @@ msgstr "Tegengesteld" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Maximumtijd (min.)" @@ -1274,9 +1330,9 @@ msgstr "Kopiëren" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1287,80 +1343,80 @@ msgstr "Naam wijzigen" msgid "Save Grand Prix" msgstr "Grand Prix opslaan" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "SuperTuxKart-hulp" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Spelvormen" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Bonusitems" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Bananen" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1368,56 +1424,57 @@ msgstr "Bananen" msgid "Story Mode" msgstr "Verhaalmodus" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Kartclassificaties" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Meerdere spelers" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Uitleg starten" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Verzamel blauwe cadeaus - deze bevatten bonusitems." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Vermijd bananen!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1425,14 +1482,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Verzamel turbogas om extra snelheid te krijgen wanneer jij dat wilt door op de bijbehorende toets te drukken. Je turbometer, tijdens het spel rechtsonder in beeld, geeft aan hoeveel je nog over hebt." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Als je een knop met een slot als dit ziet, dan moet je een uitdaging voltooien om hem te ontgrendelen." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1441,34 +1498,34 @@ msgid "" "carefully before!" msgstr "Je kunt slippen door op een speciale toets of knop te drukken. Korte slips helpen je scherpe bochten te nemen, gemiddelde slips geven je extra snelheid en lange slips geven je nóg meer snelheid. Tijdens het slippen kun je niet rechtuit rijden, dus oriënteer je kart zorgvuldig!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Je krijgt een snelheidsverhoging als je op de toets ‘gas geven’ drukt zodra de tekst ‘Klaar!’ verschijnt." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Bekijk en/of wijzig de huidige toetsinstellingen in het instellingenmenu" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart bevat meerdere spelvormen:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Standaardrace: geweld is toegestaan, dus pak bonusitems en gebruik ze verstandig!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Tijdrit: er zijn geen bonusitems, dus alles hangt af van je stuurmanskunst!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1476,7 +1533,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Zwaan-kleef-aan: volg de leider, maar eindig niet als laatste! Als de klok op nul staat, dan wordt de laatste kart uitgeschakeld. Let op: als je vóór de leider rijdt, word je ook uitgeschakeld." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1486,30 +1543,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Er zijn 3 soorten gevechtsvormen: ‘Veldslag’, waar je anderen beschiet, net zolang tot ze al hun levens kwijt zijn - ‘Vrijheid, blijheid’, waar degene die anderen het vaakst heeft geraakt binnen het gestelde (tijds)limiet wint - ‘Vlaggenroof’, waar je de vlag van de tegenstander moet overbrengen naar je eigen teambasis, maar zorg er ondertussen ook voor dat de vlag van je eigen team niet gepakt wordt!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Voetbal: gebruik je kart om de bal in het doel te duwen." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Eieren zoeken: doorzoek parcours en vind alle verstopte eieren." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Spookherhaling: race tegen spookherhalingen in tijdritten of tijdens het eieren zoeken, en neem ook je eigen herhaling op!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Rondetijdrit: leg zoveel mogelijk ronden af binnen de opgegeven tijd." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1518,93 +1575,93 @@ msgid "" "wins the cup." msgstr "* De meeste spelvormen kunnen tevens worden gespeeld als Grand Prix: je speelt dan een aantal wedstrijden achter elkaar. Hoe hoger je eindigt, hoe meer punten je verzamelt. De speler met de meeste punten wint de beker." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Om je te helpen, kun je deze bonusitems verzamelen en gebruiken:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Kauwgom: bescherm jezelf met een schild, of gebruik het terwijl je achterom kijkt om een kleverige plakboel achter te laten." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Rits: geeft je een enorme snelheidsverhoging. Maar zorg dat je niet de controle over je kart verliest!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Muffin: wordt naar de dichtstbijzijnde kart gegooid. Handig op rechte stukken. Andere in de buurt zijnde karts worden ook geraakt." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Plopper: gooi vooruit om je aan je tegenstander op te trekken of achteruit om zijn zicht te benemen." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Bowlingbal: blijft rollen tot je een strike hebt. Als je achterom kijkt, wordt hij naar achteren gegooid." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Parachute: vertraagt alle karts die voor je rijden." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Wisselaar: cadeaus worden tijdelijk omgezet in bananen, turboblikken in kauwgom, en omgekeerd." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Basketbal: stuitert de leider van de baan en vertraagt onderweg geraakte karts." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Vliegenmepper: plet karts naast je, waardoor ze langzamer gaan rijden, of gebruik om parachutes en dynamiet te ontmantelen." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Als je op een bananenschil terechtkomt, dan kan er één van de volgende voorwerpen aan je kart worden gehangen:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Anker: leidt tot een noodstop." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Parachute: vertraagt de kart, maar minder dan het anker. Hoe harder je rijdt, hoe meer je vertraagt." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Dynamiet: ontploft na een tijdje en gooit je kart de lucht in. Bots tegen een andere kart om de bom aan een andere speler te geven." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "De kwaadaardige Nolok heeft Gnu gekidnapt! Deze tips kunnen je helpen:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1613,7 +1670,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Dit pictogram op de minikaart laat zien welke uitdagingen je nog niet volbracht hebt. Rechtsbovenin zie je hoeveel punten je al hebt verzameld. Volbreng zoveel mogelijk uitdagingen; Nolok gaat dan de strijd met je aan. Win die wedstrijd om Gnu te bevrijden!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1621,20 +1678,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Als je een uitdaging volbrengt, dan krijg je een beker. Elke beker is punten waard. Hoe hoger het niveau, hoe beter de beker en hoe meer punten hij waard is." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Als je het hieronder genoemde puntenaantal bereikt, dan krijg je een cadeau. Er zijn verschillende te verzamelen cadeaus." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Niet alle karts rijden hetzelfde! Ze zijn ingedeeld in klassen met verschillen:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1642,7 +1699,7 @@ msgid "" " resistant to explosions." msgstr "Massa: er zijn drie soorten karts: lichte, normale en zware. Zwaardere karts zijn beter beschermd tegen parachuten en explosies." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1650,7 +1707,7 @@ msgid "" " especially at low speeds." msgstr "Versnelling: vooral handig aan het begin, na een ongeluk en op parcours met veel scherpe bochten. Hoe lichter de kart, hoe beter de versnelling, vooral bij lage snelheden." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1658,14 +1715,14 @@ msgid "" " top speed." msgstr "Maximale snelheid: hoe hoger, hoe harder de kart kan gaan. Vooral handig op rechte parcours met flauwe bochten. Zwaardere karts hebben een hogere maximumsnelheid." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Turbo-efficiëntie: hoe hoger, hoe meer snelheid je kunt halen uit een turboblik. En hoe lichter de kart, hoe hoger de efficiëntie." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1673,12 +1730,12 @@ msgid "" "easier it is." msgstr "Als je een andere kart een paar seconden lang op korte afstand volgt, dan krijg je een slipbonus als je hem/haar passeert. Hoe lichter de kart, hoe eenvoudiger." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart kan door meerdere spelers online worden gespeeld…:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1688,7 +1745,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Klik op het ‘online’-pictogram in het hoofdmenu. Kies voor een lokaal of wereldwijd netwerk (hiervoor moet je internettoegang inschakelen in de instellingen). Zet daarna je eigen server op met speciale instellingen of kies een bestaande. Sommige bestaande servers zijn aanbevolen servers met klassementen (optioneel)." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1698,12 +1755,12 @@ msgid "" "players and the server." msgstr "Als je je op een server bevindt, moet je wachten tot de beheerder (die met het kroontje) bepaalt wanneer de wedstrijd begint. Officiële servers kunnen wedstrijden automatisch starten als er voldoende spelers zijn. Kies daarna je kart en stem op je favoriete parcours. Een kart uit de uitbreidingenreeks is alleen toegestaan als alle spelers én de server deze ook hebben." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "…of op hetzelfde apparaat:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1713,7 +1770,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Meerdere spelers spelen het beste met hun eigen gamepad of joystick. Ga naar het invoer-configuratiescherm en stel de verschillende invoerapparaten in. Het is niet verstandig om twee of meer spelers hetzelfde toetsenbord te laten gebruiken, omdat de meeste toetsenborden maximaal 2 of 3 toetsaanslagen tegelijk aankunnen." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1733,7 +1790,7 @@ msgstr "Topscoreselectie" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Ronde-tijdrit" @@ -1741,9 +1798,9 @@ msgstr "Ronde-tijdrit" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Grand Prix" @@ -1754,6 +1811,20 @@ msgstr "Grand Prix" msgid "Choose a Kart" msgstr "Kies een kart" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Kartclassificatie" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Favoriete karts aanpassen" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1767,11 +1838,11 @@ msgstr "Meerdere spelers (gesplitst scherm)" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Meerdere spelers (online)" @@ -1788,7 +1859,7 @@ msgstr "Uitleg" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Topscores" @@ -1796,7 +1867,7 @@ msgstr "Topscores" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Prestaties" @@ -1850,30 +1921,30 @@ msgstr "Servers zoeken" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Server opzetten" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Foyer" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Instellingen" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Wedstrijd starten" @@ -1899,9 +1970,9 @@ msgstr "Voer een serveradres in" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Mijn profiel" @@ -1919,7 +1990,7 @@ msgstr "Spelersklassement" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Vrienden" @@ -1944,7 +2015,7 @@ msgstr "Snel spelen" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Accountinstellingen" @@ -1994,8 +2065,8 @@ msgid "Online Username" msgstr "Online-gebruikersnaam" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Wachtwoord herstellen" @@ -2008,7 +2079,7 @@ msgid "" msgstr "Je kunt zonder online-account spelen door te kiezen voor ‘Offline-account’. Let op: je kunt dan niet met vrienden praten, op uitbreidingen stemmen, enz. Ons privacybeleid is te vinden op http://privacy.supertuxkart.net (Engels)." #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Serverselectie" @@ -2026,339 +2097,409 @@ msgstr "IPv6-verbinding gebruiken" msgid "User search" msgstr "Gebruikers zoeken" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "SuperTuxKart-instellingen" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Weergave" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Beeld" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Geluid" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Vormgeving" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Spelers" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Besturing" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Taal" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Muziek" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Ingeschakeld" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Volume" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Geluidseffecten" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Instellingen verwijderen" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Instellingen uitschakelen" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Terug naar apparaatlijst" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Naam wijzigen" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Haptische feedback gebruiken (indien ondersteund)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Resolutie" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Beeldvullend" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Vensterpositie onthouden" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Nieuwe resolutie toepassen" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Scherm splitsen bij meerdere spelers" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Internetinstellingen" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Inlogscherm altijd tonen" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Verbinding maken met internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Online-chatten inschakelen" +msgid "Enable chatting in online lobbies" +msgstr "Chatten in online-lobby's inschakelen" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Chatten in online-spellen inschakelen" +msgid "Enable chatting in online matches" +msgstr "Chatten in online-toernooien inschakelen" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Overige instellingen" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Gebruikers met handicaps toestaan" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Alle spelelementen verwijderen" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Druk op enter of dubbelklik op een apparaat om het in te stellen" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Apparaat toevoegen" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Bij het starten van het spel worden de instellingen bepaald aan de hand van de gebruikte ‘selectieknop’." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Thema" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Minikaart" +msgid "Skin variant" +msgstr "Huidskleur" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Scherm splitsen bij meerdere spelers" +msgid "Minimap" +msgstr "Minikaart" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Tekstgrootte" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Camera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Aangepast…" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Ververssnelheid tonen" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Binnengehaalde bonusitems van andere karts tonen" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Tijdklok gebruiken in verhaalmodus" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Snellerondeklok gebruiken" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Weergaveresolutie" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Niveau van de grafische effecten" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Niveau van de vervagingseffecten" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Maximumaantal FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Aangepaste instellingen…" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Resolutie" +msgid "Performance tests" +msgstr "Prestatietests" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Beeldvullend" +msgid "Performance test of the current settings" +msgstr "Prestatietest met de huidige instellingen" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Vensterpositie onthouden" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Wachtwoord onthouden" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Nieuwe resolutie toepassen" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Verwijderen" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Kleur van kart" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2385,15 +2526,15 @@ msgstr "Team blauw" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Aantal ronden" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Aantal karts" @@ -2408,33 +2549,17 @@ msgstr "Aantal computerkarts in blauwe team" msgid "Random Grand Prix" msgstr "Willekeurige Grand Prix" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Favoriete parcours aanpassen" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Inloggen" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Wachtwoord onthouden" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Verwijderen" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Kleur van kart" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Wijzig het thema via Instellingen --> Vormgeving." @@ -2553,238 +2678,306 @@ msgid "" msgstr "Versper niet de weg van een teamgenoot - versper alleen de weg van tegenstanders die proberen te scoren." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Peper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "De afgrond van Atlantis" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Aliensignaal" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Het oude Colosseumlabyrint" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Candela-Stad" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Oorlogseiland" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Zwarte Woud" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Grot X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "De cacaotempel" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Maïsveldkruispunt" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Fort Magma" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Gran Paradiso-eiland" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Spaanse villa" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Niet voor één gat te vangen" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "IJzig voetbalveld" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Wat scheelt er, kleine hippies? Is jullie grote gnoe-leider verdwenen?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Jazeker! Die zit nu in mijn kasteel en wordt opgediend als diner…" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Maar ik ben een eerlijk wezen, dus doe ik je een voorstel." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Als je me kunt verslaan, dan laat ik die oude mopperpot vrij." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " Maar kleine sufferds zoals jullie kunnen mij, de Koning van de Karts, nooit verslaan!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Duinarena" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Duinstadion" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Vuurtoren van Urk" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "De oude mijn" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Midgetgolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oase" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Oliviers wiskundeklas" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Pompoenpark" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Het Ravensburg-landhuis" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Vloek van de Farao" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Nessie's vijver" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Noordelijk oord" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Besneeuwde top" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Voetbalveld" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Het stadion" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Enterprise" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "De tempel" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Vulkaaneiland" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Meditatietuin" @@ -2793,11 +2986,11 @@ msgstr "Meditatietuin" msgid "Completed achievement \"%s\"." msgstr "Je hebt de prestatie ‘%s’ behaald." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Kan niet verbinden met de SuperTuxKart-uitbreidingsserver." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Het nieuws kan niet worden opgehaald: ‘%s’" @@ -2863,7 +3056,7 @@ msgid "New kart '%s' now available" msgstr "De kart ‘%s’ is nu beschikbaar" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2895,32 +3088,32 @@ msgid "" "created." msgstr "Je configuratiebestand was verouderd. Het is verwijderd en er wordt een nieuw bestand aangemaakt." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Video-opname gestart." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "De video is opgeslagen in ‘%s’." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Omzetproces:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Tip: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Bezig met laden…" @@ -2942,19 +3135,18 @@ msgstr "Turbo-efficiëntie" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (met handicap)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s is klaar" @@ -3428,21 +3620,21 @@ msgid "Axis %d" msgstr "As %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Gamepad-knop %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Muisknop %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Muisas %d %s" @@ -3614,26 +3806,30 @@ msgstr "Je kunt maximaal 3 levens hebben!" msgid "+1 life." msgstr "+1 leven." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Je was te langzaam!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "De wedstrijd is afgelopen!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Je hebt de wedstrijd gewonnen!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Je bent geëindigd op plaats %d!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s heeft de wedstrijd verlaten." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3642,16 +3838,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart kan verbinding maken met het internet om add-ons te downloaden en updatemeldingen te tonen. Wij verzamelen ook geanonimiseerde gegevens over hardwareprestaties t.b.v. productverbetering. Lees onze privacyverklaring op https://supertuxkart.net/Privacy Wil je deze optie activeren? (Als je dit later wilt aanpassen, ga dan naar Instellingen -> Algemeen en pas ‘Verbinden met het internet’ aan.)" -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Je schermresolutie is te laag om STK te kunnen spelen." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." -msgstr "Je videostuurprogramma is verouderd. Installeer een recenter stuurprogramma." +msgstr "Je videostuurprogramma is verouderd. Installeer de nieuwste versie van het stuurprogramma." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3659,38 +3855,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Je grafische stuurprogramma lijkt verouderd; controleer of er een update beschikbaar is. SuperTuxKart raadt je aan om een stuurprogramma te gebruiken met ondersteuning voor %s of hoger. Het spel draait waarschijnlijk nog wel, maar met lagere grafische instellingen." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Serververbinding verbroken." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s heeft de rode vlag in handen!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "De rode vlag is teruggekeerd!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s heeft de blauwe vlag in handen!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "De blauwe vlag is teruggekeerd!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s heeft de blauwe vlag veroverd!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s heeft de rode vlag veroverd!" @@ -3700,7 +3896,7 @@ msgstr "%s heeft de rode vlag veroverd!" msgid "Eggs: %d / %d" msgstr "Eieren: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Leider" @@ -3708,22 +3904,22 @@ msgstr "Leider" msgid "Final lap!" msgstr "Laatste ronde!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Ronde %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s, gereden door %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Nieuwe snelste ronde" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "JE GAAT DE VERKEERDE KANT OP!" @@ -3737,194 +3933,194 @@ msgstr "%s heeft een doelpunt gemaakt!" msgid "Oops, %s made an own goal!" msgstr "Oeps, %s heeft in het eigen doel geschopt!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "%i banden uitdelende kart is verschenen!" msgstr[1] "%i banden uitdelende karts zijn verschenen!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Je bent uitgeschakeld!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "%s is uitgeschakeld." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "De server is offline." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Je bent weggestuurd." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Je bent weggestuurd omdat je ping te hoog was." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Zwakke internetvebinding." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Computer" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s is weggegaan." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Klik op een spelersnaam op de lijst om spelersbeheer en klassementinformatie te tonen." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Moeilijkheidsgraad: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Max. aantal spelers: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Spelvorm: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Tijdslimiet" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Doellimiet" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Soort voetbal: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Grand Prix-voortgang: %d/%d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Alle spelers hebben zich aangesloten bij het rode of blauwe team." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Je bent vanaf nu serverbeheerder." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Verbinding geweigerd: de server is bezig." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Verbinding geweigerd: je bent verbannen van de server." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Verbinding geweigerd: het serverwachtwoord is onjuist." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Verbinding geweigerd: de spelgegevens zijn incompatibel." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Verbinding geweigerd: er is geen plaats meer op de server." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Verbinding geweigerd: een ongeldige speler probeert verbinding te maken." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Kan netwerkspel niet starten." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "De wedstrijd is afgelopen; je kunt niet langer deelnemen of toekijken." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Geen plaats meer in de arena - deelname is uitgeschakeld." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Slechts één resterende speler; je gaat terug naar de foyer…" -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "De servereigenaar heeft het spel verlaten." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Bij de volgende ronde ben je alleen toeschouwer." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s heeft zich aangesloten bij het rode team." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%sheeft zich aangesloten bij het blauwe team. " #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s neemt deel aan de wedstrijd." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3932,15 +4128,15 @@ msgid "" msgstr "Druk op <%s> of <%s> om een andere speler te kiezen, of op <%s> of <%s> om de camera te verstellen." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "%s is gerapporteerd." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3971,38 +4167,38 @@ msgstr "Tijdrit (Grand Prix)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Vrijheid, blijheid" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Vlaggenroof" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s is nu online." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s en %s zijn nu online." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s en %s zijn nu online" #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4010,19 +4206,19 @@ msgstr[0] "%d vriend is nu online." msgstr[1] "%d vrienden zijn nu online." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s speelt op de server ‘%s’." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "Je hebt %d nieuw vriendschapsverzoek!" msgstr[1] "Je hebt %d nieuwe vriendschapsverzoeken!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Je hebt een nieuw vriendschapsverzoek!" @@ -4051,12 +4247,12 @@ msgid "" msgstr "Het recordbestand was te oud;\nde records zijn verwijderd." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Zwaan-kleef-aan" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Veldslag" @@ -4069,91 +4265,88 @@ msgstr "Onvolledige herhalingen worden niet opgeslagen." msgid "Replay saved in \"%s\"." msgstr "De herhaling is opgeslagen in ‘%s’." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 week" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 weken" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 maand" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 maanden" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 maanden" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 maanden" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 jaar" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 jaar" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Naam van uitbreiding" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Bijgewerkt op" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Niet geïnstalleerd" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s, gemaakt door %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Bezig met bijwerken; even geduld…" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Er kan geen verbinding worden gemaakt met de uitbreidingenwebsite. Controleer je internetverbinding en of SuperTuxKart niet wordt geblokkerd door een firewall." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Favorieten" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Op slot: ontgrendel het slot door uitdagingen te volbrengen!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Willekeurige arena" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d arena niet beschikbaar in de éénspelermodus." -msgstr[1] "%d arena's niet beschikbaar in de éénspelermodus." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nDavid Blaszyk, 2017\nDennis Holierhoek, 2016\nFrans van Rijn, 2015-2016\nHeimen Stoffels, 2021-2022\nHeimen Stoffels, 2019-2021\nSteven van Tetering, 2019\nWard Muylaert, 2015-2017\nWillem Sonke, 2019\nHeimen Stoffels, 2021\nAsciimonster\nDawid Gan\nFoppe Benedictus\nGuus\nHeimen Stoffels\nKaj-Ivar\nKoen_VL\nSTK-team\nWard Muylaert\nWillem Sonke\nWim Champagne\nplutgamer\ntoams" @@ -4441,7 +4634,7 @@ msgstr "Aantal verzamelde bananen" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Slippen" @@ -4544,7 +4737,7 @@ msgstr "Aantal afgeronde eierzoektochten" msgid " (official tracks matching the goal)" msgstr "(officiële parcours die overeenkomen met het doel)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4552,91 +4745,95 @@ msgid "" msgstr "Moderne gamepads en joysticks worden na het aankoppelen automatisch toegevoegd aan de lijst.\n\nMet onderstaande knop voeg je een toetsenbordindeling toe, maar LET OP: \nde meeste toetsenborden kunnen maar een beperkt aantal toetsaanslagen per keer verwerken, wat spelen met meerdere spelers moeilijk maakt. Je kunt meerdere toetsenborden aan dit apparaat koppelen, maar de twee spelers moeten verschillende toetscombinaties gebruiken." #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Wiimote toevoegen" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Toetsenbordconfiguratie toevoegen" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Bijwerken" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Versie: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "uitgelicht" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Grootte: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Log in om deze uitbreiding te beoordelen." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "De uitbreiding kan niet worden gedownload" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "De uitbreiding ‘%s’ kan niet worden geïnstalleerd." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Opnieuw proberen" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "De uitbreiding ‘%s’ kan niet worden verwijderd." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "De achtergronddownload is voltooid." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Achtergronddownload" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "De achtergronddownload is gestart." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Het ingevoerde wachtwoord is onjuist." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Het wachtwoord moet tussen de 8 en 30 tekens lang zijn!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "De wachtwoorden komen niet overeen!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Bezig met controleren…" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Het wachtwoord is gewijzigd." @@ -4657,67 +4854,97 @@ msgstr "SuperTuxKart heeft geen ondersteuning voor resoluties lager dan 1024x768 #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Drone-achtervolging" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Aangepast" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Uitgeschakeld" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Alleen belangrijk" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Heel laag" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Laag" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Normaal" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Hoog" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Heel hoog" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Allerhoogst" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4725,7 +4952,7 @@ msgid "" msgstr "SuperTuxKart moet alles downloaden (alle parcours en muziek in hoge kwaliteit). Als je niet verbonden bent met wifi, dan wordt je mobiele internetverbinding gebruikt." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4742,101 +4969,102 @@ msgstr "Voer het serveradres in, gevolgd door : (optioneel) en het poortnummer." msgid "Invalid server address: %s." msgstr "Ongeldig serveradres: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Tegengesteld" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Moeilijkheidsgraad" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Ronden" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Tijd" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Kart" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Gebruiker" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Versie" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Nee" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Parcours" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Topscores: top %d " -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Aantal karts: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Doel: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Aantal ronden: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Tegengesteld: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(leeg)" @@ -4924,33 +5152,41 @@ msgid "Press any key..." msgstr "Druk op een toets…" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Chatten is uitgeschakeld. Schakel chatten in via de instellingen." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Terug naar prestatietest" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Prestatietest afsluiten" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Terug naar gevecht" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Nieuwe wedstrijd organiseren" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Gevecht herstarten" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Gevecht verlaten" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Nieuwe wedstrijd organiseren" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Wedstrijd verlaten" @@ -4966,11 +5202,11 @@ msgstr "%s heeft nog geen rang." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s is nummer %d in het klassement, met een score van %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Onjuiste gebruikersnaam en/of e-mailadres." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4992,7 +5228,7 @@ msgstr "Spookherhaling" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Ronden: %i" @@ -5005,21 +5241,21 @@ msgstr "Soort: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Benodigde plaats: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Benodigde tijd: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Benodigde hoeveelheid turbogas: %i" @@ -5032,54 +5268,54 @@ msgstr "Aantal computerkarts: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Gevechtsmodus" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Soort voetbal" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Serverlocatie: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Huidig parcours: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Rang" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Speler" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Scores" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Speeltijd" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Verwijderen uit favorieten" @@ -5092,74 +5328,74 @@ msgid "No player available for connecting to server." msgstr "Geen speler beschikbaar voor de server." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Gebruikersnaam: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Verzoek annuleren" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Vandaag" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Het vriendschapsverzoek is verstuurd!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Het vriendschapsverzoek is geaccepteerd!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Het vriendschapsverzoek is geweigerd!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Vriend is verwijderd!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Het vriendschapsverzoek is geannuleerd!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Bezig met verwerken…" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Bezig met ophalen van laatste stem…" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Je kunt je stem aanpassen door op de sterren eronder te klikken." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Je hebt nog geen stem uitgebracht. Kies hieronder het aantal sterren dat je wilt toekennen." -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Je hebt gestemd! Dit scherm kan worden afgesloten." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Bezig met stemmen…" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Willekeurig parcours" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5188,7 +5424,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Er is een fout opgetreden bij het opslaan van de Grand Prix." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Kies een parcours" @@ -5232,12 +5468,12 @@ msgstr "Je hebt het parcours ‘%0’ ontgrendeld" msgid "You unlocked grand prix %0" msgstr "Je hebt de Grand Prix ‘%0’ ontgrendeld" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Parcours" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5258,19 +5494,19 @@ msgstr "Voer de naam in van de Grand Prix" msgid "Please select a Grand Prix" msgstr "Kies een Grand Prix" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Aangepast" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Geen naam opgegeven." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Er is al een Grand Prix met dezelfde naam." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "De naam is te lang." @@ -5279,19 +5515,19 @@ msgstr "De naam is te lang." msgid "Better luck next time!" msgstr "Volgende keer beter!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Je hebt een uitdaging volbracht!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Je hebt de Grand Prix gewonnen!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Je hebt de Grand Prix volledig afgelegd!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Aantal karts" @@ -5304,110 +5540,125 @@ msgstr "Weet je zeker dat je deze topscore wilt verwijderen?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Weet je zeker dat je alle topscores wilt verwijderen?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Favoriet" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Licht" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Zwaar" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Plug een toetsenbord of camepad in om met meerdere spelers te spelen op een gesplitst scherm" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Willekeurige kart" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Op slot" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Aan iedereen:\nDruk nu op ‘Selecteren’ om mee te doen aan dit spel!" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Wil je de speluitleg starten?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Zonder internettoegang kun je niet online spelen. Wil je dat wel? Ga dan naar de instellingen en kies de optie ‘Verbinden met het internet’." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Zonder internettoegang kun je geen uitbreidingen downloaden. Wil je dat wel? Ga dan naar de instellingen en kies de optie ‘Verbinden met het internet’." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Zonder internettoegang kun je geen uitbreidingen downloaden. Wil je dat wel? Ga dan naar de instellingen en kies de optie ‘Verbinden met het internet’.\n\nWél kun je reeds gedownloade uitbreidingen verwijderen." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "De uitbreidingenmodule is momenteel uitgeschakeld op de instellingenpagina." -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Bezig met laden van uitbreidingen; even geduld…" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Weet je zeker dat je STK wilt afsluiten?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "LAN-server opzetten" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Server van %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Aantal Grand Prix-parcours" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "De naam moet tussen de 4 en 30 tekens lang zijn!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Je wachtwoord bevat ongeldige tekens!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Klaar" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Live meedoen" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Toekijken" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Uitbreiding installeren" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5415,7 +5666,7 @@ msgstr "Wacht tot de huidige wedstrijd (%s) is afgelopen. Resterende tijd (gesch #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Wacht tot de huidige wedstrijd is afgelopen. Resterende tijd (geschat): %s." @@ -5423,24 +5674,24 @@ msgstr "Wacht tot de huidige wedstrijd is afgelopen. Resterende tijd (geschat): #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Wacht tot de huidige wedstrijd (%s) is afgelopen. Voortgang (geschat): %s." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Wacht tot de huidige wedstrijd is afgelopen. Voortgang (geschat): %s." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Wacht tot de huidige wedstrijd is afgelopen." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5449,7 +5700,7 @@ msgstr[1] "De wedstrijd gaat van start zodra er meer dan %d spelers zijn." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5458,96 +5709,108 @@ msgid_plural "" msgstr[0] "De wedstrijd gaat van start over %d seconde of zodra iedereen op ‘Klaar’ heeft gedrukt." msgstr[1] "De wedstrijd gaat van start over %d seconden of zodra iedereen op ‘Klaar’ heeft gedrukt." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Bezig met verbinden met %s…" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Bezig met zoeken naar server voor snelle wedstrijden…" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Resterende tijd: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Doelen" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Bezig met ophalen van prestaties…" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Profiel van %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Sinds" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Status" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Bezig met ophalen van vrienden…" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Nieuw verzoek" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "In afwachting" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Offline" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Voer hieronder het nieuwe e-mailadres in" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Het nieuwe e-mailadres moet tussen de 5 en 254 tekens lang zijn." -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Het nieuwe e-mailadres is ongeldig." -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "Het e-mailadres is gewijzigd." -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Het e-mailadres kan niet worden gewijzigd: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "SuperTuxKart-nieuws" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Datum" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Er zijn momenteel geen nieuwsberichten." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Log in door hierboven op je gebruikersnaam te klikken." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Bezig met zoeken…" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Wedstrijd afbreken" @@ -5625,34 +5888,34 @@ msgid "Distance (km)" msgstr "Afstand (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Onbekend" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Geen IPv4 gedecteerd. Mogelijk kun je niet spelen op servers." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Geen IPv6 gedecteerd. Mogelijk kun je niet spelen op servers." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Er zijn geen servers beschikbaar." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Bezig met ophalen van servers…" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Favoriete servers" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5660,149 +5923,149 @@ msgstr "De stemming stopt vroegtijdig als het merendeel van de spelers heeft gek #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Willekeurige itemplaatsing" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Aantal te behalen doelen" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Spookrijden" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Op slot: ontgrendel het slot door uitdagingen te volbrengen!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Actie" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Toetstoewijzing" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Apparaat uitschakelen" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Apparaat inschakelen" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Configuratie inschakelen" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Speltoetsen" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Menutoetsen" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Naar links sturen" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Naar rechts sturen" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Versnellen" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Rem/Achteruit" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Vuren" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Turbo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Achterom kijken" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Gered worden" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Wedstrijd pauzeren" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Omhoog" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Omlaag" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Links" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Rechts" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Selecteren" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Annuleren/Terug" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Blauwe items duiden een aan conflict met een andere configuratie" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Rode items duiden een conflict aan in de huidige configuratie" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5810,17 +6073,27 @@ msgid "" msgstr "LET OP: ‘Shift’ is een onhandige toets. Als Shift ingedrukt is, werken andere toetsen niet meer omdat hoofdletters en kleine letters verschillend worden behandeld." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Weet je zeker dat je deze configuratie permanent wilt verwijderen?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Voer een nieuwe configuratienaam in. Laat leeg om de standaardnaam te gebruiken." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Verticaal" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Horizontaal" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5828,89 +6101,74 @@ msgstr "In de meerspelermodus kunnen spelers een extra moeilijkheidsgraad (handi #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Alle spelelementen installeren" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Weet je zeker dat je alle spelelementen wilt verwijderen?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Toetsenbord %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Touchapparaat" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Klik op een apparaat om het in te stellen" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Systeemtaal" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Linksonder" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "Rechts" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Verborgen" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Gecentreerd" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Verticaal" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Horizontaal" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Erg klein" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Klein" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Normaal" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Groot" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Erg groot" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5920,128 +6178,133 @@ msgid "" msgstr "De snellerondemodus kan alleen worden gestart als het spel niet is afgesloten nadat de verhaalmodus is gestart.\n\nDe tijdklok wordt afgekeurd als het spel wordt afgesloten voordat de verhaalmodus is afgerond.\n\nMaak een nieuw profiel aan om de snellerondemodus te gebruiken." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Verticale synchronisatie" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Vsync zorgt ervoor dat de videokaart alleen een nieuw frame verstuurt\nals het beeldscherm er klaar voor is." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Vsync werkt niet als je stuurprogramma het niet ondersteunt." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Deeltjeseffecten: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Bewegende personages: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Dynamisch licht: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Lichtverstrooiing: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Anti-kartelvorming: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Omgevingsafsluiting: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Schaduwen: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Schaduwen: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Gloeiing: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Gloeiing (randen): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Lichtval (godenstralen): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Gerenderde beeldkwaliteit: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Geometriedetails: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Bewegingsvervaging: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Scherptediepte: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Internettoegang is uitgeschakeld. Wil je dit inschakelen?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Je moet een wachtwoord invoeren." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Bezig met uitloggen van ‘%s’…" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Bezig met inloggen van ‘%s’…" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Je kunt niet de enige speler verwijderen." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Weet je zeker dat je ‘%s’ wilt verwijderen?" @@ -6069,7 +6332,7 @@ msgstr "DOELPUNT!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Bezig met wachten op anderen…" @@ -6082,7 +6345,7 @@ msgstr "Bezig met wachten op server…" #: src/states_screens/race_gui_base.cpp:646 #, c-format msgid "\"%s\"" -msgstr "\"%s\"" +msgstr "“%s”" #. I18N: string used to show the author of the music. (e.g. "Sunny Song" by #. "John Doe") @@ -6104,7 +6367,7 @@ msgstr "Zwaan, kleef aan!" msgid "Top %i" msgstr "Top %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Uitdaging niet volbracht" @@ -6128,101 +6391,198 @@ msgstr "Druk op het podiumpictogram om de uitdaging te starten" msgid "Press fire to start the challenge" msgstr "Druk op de vuurknop om de uitdaging te starten" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Terug naar grafische instellingen" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Testresultaten opslaan" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Terug naar hoofdmenu" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Server verlaten" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Grand Prix afbreken" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Herstarten" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Terug naar uitdagingen" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Racen tegen de nieuwe spookherhaling" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Terug naar hoofdmenu" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Weet je zeker dat je de Grand Prix wilt afbreken?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Het prestatieverslag is opgeslagen in ‘%s’." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Team Rood heeft gewonnen" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Team Blauw heeft gewonnen" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Het is gelijkspel" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Uitgeschakeld na %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Uitgeschakeld" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(eigen doelpunt)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Parcours %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Voortgang van de Grand Prix:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Topscores" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Beste rondetijd: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" -msgstr ", gereden door %s" +msgstr ", verreden door %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Je hebt de uitdaging volbracht!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Je hebt de uitdaging niet volbracht!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" -msgstr "Niet voldaan aan SuperTux-vereisten" +msgstr "Voldaan aan SuperTux-vereisten" + +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Resultaten van prestatietest" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Testduur: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Aantal frames: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "Gelijkmatige fps: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "Bijna gelijkmatige fps: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "Gemiddelde fps: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Horizontale resolutie: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Verticale resolutie: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Dynamische belichting: AAN" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Dynamische belichting: UIT" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Weergaveresolutie: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Anti-kartelvorming: AAN" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Anti-kartelvorming: UIT" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Beeldgebaseerde verlichting: UIT" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Beeldgebaseerde verlichting: AAN" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Omgevingsafsluiting: AAN" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Omgevingsafsluiting: UIT" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Schaduwresolutie: %s" #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" @@ -6264,28 +6624,28 @@ msgstr "Druk op het rode of blauwe voetbalpictogram om een ander team te kiezen" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Dit parcours is gemaakt door %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Maximum aantal spelers: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Aantal computerkarts in rode team" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" -msgstr "Je kunt deze Grand Prix niet spelen omdat er parcours worden afgelegd die je nog niet hebt ontgrendeld!" +msgstr "Je kunt deze Grand Prix niet starten, omdat er parcours worden afgelegd die je nog niet hebt ontgrendeld!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Op slot!" @@ -6307,115 +6667,134 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "De grote deur gaat pas open als alle uitdagingen volbracht zijn!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" "Check the minimap for\n" "available challenges." -msgstr "Je hebt meer punten nodig \nom deze uitdaging te starten! \nBekijk de minikaart voor \nbeschikbare uitdagingen." +msgstr "Je hebt te weinig punten \nom deze uitdaging te starten! \nKijk op de minikaart welke \nuitdagingen je wél kunt volbrengen." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Versnel met <%s>. Stuur met <%s> en <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." -msgstr "Geef gas door de bovenkant van het stuurwiel vast te pakken, en stuur door naar links of recht te bewegen." +msgstr "Geef gas door de bovenkant van het stuurwiel vast te pakken en stuur door naar links of rechts te bewegen." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." -msgstr "Geef gas door de versnelling omhoog te schuiven, en stuur door je apparaat te kantelen." +msgstr "Geef gas door de versnelling omhoog te schuiven en stuur door je apparaat te kantelen." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." -msgstr "Geef gas door de versnelling omhoog te schuiven, en stuur door je apparaat te kantelen." +msgstr "Geef gas door de versnelling omhoog te schuiven en stuur door je apparaat te kantelen." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Verzamel cadeaus en schiet met <%s> de dozen uit de weg!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Verzamel cadeaus en druk op het bowlingbalpictogram om de dozen uit de weg te ruimen!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" "Fire the weapon with <%s> while pressing <%s> to fire behind!" -msgstr "Gebruik <%s> om achterom te kijken.\nGebruik de vuurknop <%s> tegelijk met <%s> om naar achteren te vuren!" +msgstr "Druk op <%s> om achterom te kijken.\nDruk de vuurknop (<%s>) tegelijk in met <%s> om naar achteren te vuren!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" -msgstr "Druk op het spiegelpictogram om achterom te kijken.\nSchiet naar achteren met je wapen door het spiegelpictogram ingedrukt te houden en te vegen over het bowlingbalpictogram!" +msgstr "Druk op het spiegelpictogram om achterom te kijken.\nSchiet naar achteren door het spiegelpictogram ingedrukt te houden en over het bowlingbalpictogram te vergen!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" -msgstr "Gebruik het verzamelde turbogas door op <%s> te drukken!" +msgstr "Druk op <%s> om het verzamelde turbogas in te zetten!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" -msgstr "Gebruik het verzamelde turbogas door op het turbogaspictogram te drukken" +msgstr "Druk op het turbogaspictogram om het verzamelde turbogas in te zetten" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Verzamel flessen turbogas (we gebruiken ze na de bocht)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." -msgstr "Oeps! Als je in de penarie zit, druk dan op <%s> om gered te worden." +msgstr "Foutje, bedankt! Als je in de penarie zit, druk dan op <%s> om gered te worden." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." -msgstr "Oeps! Als je in de penarie zit, druk dan op het vogelpictogram om gered te worden." +msgstr "Foutje, bedankt! Als je in de penarie zit, druk dan op het vogelpictogram om gered te worden." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." -msgstr "Versnel en druk tijdens het draaien op de <%s>-toets om te slippen.\nHierdoor ga je korter en sneller door de bocht." +msgstr "Versnel en druk tijdens het draaien op de <%s>-toets om te slippen.\nZo maak je kortere, snellere bochten." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." -msgstr "Versnel en druk tijdens het draaien op het slippictogram om te slippen.\nHierdoor ga je korter en sneller door de bocht." +msgstr "Versnel en druk tijdens het draaien op het slippictogram om te slippen.\nZo maak je kortere, snellere bochten." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" -msgstr "Als het lukt om gedurende enkele seconden te slippen, dan krijg je extra snelheid!" +msgstr "Als het je lukt om enkele seconden te slippen, dan word je beloond met extra snelheid!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" -msgstr "Je bent nu klaar om te racen. Veel succes!" +msgstr "Je bent er helemaal klaar voor. Veel succes!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" -msgstr "Een open source 3D kartracespel" +msgstr "Een opensource 3D-kartracespel" #. I18N: Keywords in desktop entry, translators please keep it separated with #. semicolons @@ -6423,53 +6802,53 @@ msgstr "Een open source 3D kartracespel" msgid "tux;game;race;" msgstr "tux;game;race;spel;kart;super;auto;parcours;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " "game that is more fun than realistic, and provide an enjoyable experience " "for all ages." -msgstr "Karts. Turbogas. Actie! SuperTuxKart is een open source 3D-racespel met verschillende personages, parcours en spelmodi. Ons doel is om een spel te maken dat leuk is en niet per se heel realistisch. Een spel wat iedereen, ongeacht de leeftijd, met plezier kan spelen." +msgstr "Karts, turbogas, actie! SuperTuxKart is een opensource 3D-racespel met diverse personages, parcours en spelmodi. Ons doel is niet om een zo realistisch mogelijk spel te maken, maar gewoon een spel dat leuk is. Een spel waar iedereen - ongeacht leeftijd - plezier aan beleeft." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" " while avoiding other karts as they may overtake you, but don't eat the " "bananas! Watch for bowling balls, plungers, bubble gum, and cakes thrown by " "your opponents." -msgstr "Er zijn verschillende parcours met wisselende thema's, zoals een onderwaterparcours, maar ook een boerderij-, jungle- en ruimteparcours. Zet je beste beentje voor en zorg dat andere karts je niet inhalen! O ja, eet geen bananenschillen en pas op voor bowlingballen, ploppers, kauwgom en taarten die je tegenstanders op je afvuren!" +msgstr "Er zijn diverse parcours met wisselende thema's, zoals een onderwaterparcours, maar ook boerderij-, jungle- en ruimteparcours. Zet je beste beentje voor en zorg dat andere karts je niet inhalen! O ja, eet geen bananenschillen en pas op voor bowlingballen, ploppers, kauwgom en taarten die tegenstanders op je afvuren!" -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " "battle mode against the computer or your friends, and more! For a greater " "challenge, join online and meet players from all over the world and prove " "your racing skills!" -msgstr "Je kunt een wedstrijd organiseren tegen andere karts, meedoen aan één van de vele toernooien, de topscores verbeteren in tijdraces, tegen elkaar vechten (zowel tegen de computer als je vrienden) en nog veel meer! Zoek je nóg meer uitdaging? Race dan online tegen personen van over heel de wereld en laat zien hoe goed je bent!" +msgstr "Je kunt een wedstrijd organiseren tegen andere karts, meedoen aan een van de vele toernooien, de topscores verbeteren in tijdraces, tegen elkaar vechten (zowel tegen de computer als je vrienden) en nog veel meer! Zoek je nóg meer uitdaging? Race dan online tegen personen van over heel de wereld en laat zien hoe goed je bent!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Dit spel bevat geen reclame." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." -msgstr "Dit is een vroegtijdig vrijgegeven versie die alle recente verbeteringen bevat en is voornamelijk gericht op testers, zodat ze kunnen helpen de aankomende stabiele versie zo stabiel mogelijk te maken." +msgstr "Dit is een vroegtijdig vrijgegeven versie die alle recente verbeteringen bevat en is voornamelijk gericht op testers, zodat ze kunnen helpen de aankomende versie zo stabiel mogelijk te maken." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Deze versie kan naast de stabiele versie worden geïnstalleerd." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Als je meer zekerheid wilt, installeer dan de stabiele versie: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "Het SuperTuxKart-team" diff --git a/data/po/nn.po b/data/po/nn.po index cb6a61463cf..5c25ffe8443 100644 --- a/data/po/nn.po +++ b/data/po/nn.po @@ -4,13 +4,14 @@ # # Translators: # Karl Ove Hufthammer , 2011,2015-2016,2018-2023 +# Laura Kursula, 2025 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Karl Ove Hufthammer , 2011,2015-2016,2018-2023\n" +"Last-Translator: Laura Kursula, 2025\n" "Language-Team: Norwegian Nynorsk (http://app.transifex.com/supertuxkart/supertuxkart/language/nn/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -167,7 +168,7 @@ msgstr "Ved verdas ende" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Tilbake" @@ -189,7 +190,7 @@ msgstr "Vel kva type styring du føretrekkjer" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Akselerometer" @@ -203,13 +204,13 @@ msgstr "Akselerometer" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Gyroskop" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Ratt" @@ -240,35 +241,37 @@ msgstr "Innstillingar for peikeskjerm" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Generelt" @@ -336,30 +339,33 @@ msgstr "Tilbakestill til standard" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Avbryt" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Ja" @@ -537,9 +543,9 @@ msgstr "Vert med" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -600,7 +606,7 @@ msgstr "Mål" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Framgang" @@ -635,7 +641,7 @@ msgstr "Send" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Tilbake til løpet" @@ -652,7 +658,7 @@ msgstr "Tilbake til lobbyen" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Start løpet på nytt" @@ -716,12 +722,12 @@ msgstr "Skriv inn brukarnamnet og e-postadressa du oppgav ved registreringa ders #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Brukarnamn" @@ -762,7 +768,7 @@ msgstr "Vanskegrad" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Nybegynnar" @@ -774,7 +780,7 @@ msgstr "Nybegynnar" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Vidarekommen" @@ -786,7 +792,7 @@ msgstr "Vidarekommen" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Ekspert" @@ -798,7 +804,7 @@ msgstr "Ekspert" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -806,8 +812,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Spelmodus" @@ -818,8 +824,8 @@ msgstr "Spelmodus" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Vanleg løp" @@ -832,7 +838,7 @@ msgstr "Vanleg løp" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Tidsløp" @@ -840,7 +846,8 @@ msgstr "Tidsløp" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Kamp" @@ -849,24 +856,24 @@ msgstr "Kamp" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Fotball" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Passord" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Bokmerk denne tenaren" @@ -877,7 +884,7 @@ msgstr "Legg til spelar" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Namn" @@ -909,7 +916,7 @@ msgstr "Brukarinfo" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Fjern som ven" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -919,17 +926,17 @@ msgstr "Legg til venn" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "" +msgstr "Godta innbydinga" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "" +msgstr "Avslå innbydinga" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "" +msgstr "Sjå profil" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog @@ -971,6 +978,50 @@ msgstr "Bruk «Escape»-knappen" msgid "Assign nothing" msgstr "Tildel ingenting" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Tilråd grafikkinnstillingar" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Dei tilrådde innstillingane vil vere gyldige for den noverande oppløysinga." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Kva lyt innstillingane leggje vekt på?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Yting" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Balansere yting og biletekvalitet" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Biletekvalitet" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Energisparing" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Likar du dimmande effektar?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Byrje prøven" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -985,11 +1036,11 @@ msgstr "Set opp løp" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Hald fram" @@ -1030,10 +1081,15 @@ msgstr "Arenaar" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Installert" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Endre favorittarenaar" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1043,20 +1099,20 @@ msgstr "Installert" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Standard" @@ -1067,12 +1123,12 @@ msgstr "Standard" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Tillegg" @@ -1086,27 +1142,28 @@ msgstr "Tillegg" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Alle" @@ -1117,7 +1174,7 @@ msgstr "Bidragsytarar" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" -msgstr "" +msgstr "Hopp over" #. I18N: ./data/gui/screens/easter_egg.stkgui #. I18N: Section in easter egg tracks selection screen @@ -1145,9 +1202,9 @@ msgstr "Flytt ned" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Legg til" @@ -1184,7 +1241,7 @@ msgstr "Val for skuggeopptak" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Eggejakt" @@ -1231,10 +1288,10 @@ msgstr "Baklengs" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Tidsgrense (minutt)" @@ -1266,9 +1323,9 @@ msgstr "Kopier" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1279,80 +1336,80 @@ msgstr "Endra namn" msgid "Save Grand Prix" msgstr "Lagra turnering" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "SuperTuxKart-hjelp" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Spelmodus" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Bonusar" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Bananar" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1360,56 +1417,57 @@ msgstr "Bananar" msgid "Story Mode" msgstr "Forteljings­modus" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Køyreeigenskapar" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Fleire spelarar" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Start opplæringsbana" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Samla blå gåveesker. Dei gjev deg våpen og andre fordelar." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Unngå bananar!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1417,14 +1475,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Nitroar gjev deg høgare fart når du held inne nitrotasten/-knappen. Du kan sjå kor mykje nitro du har att i nitromålaren nede til høgre på skjermen." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Viss du ser ein knapp med ein lås som denne, må du fullføra ei utfordring for å låsa han opp." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1433,34 +1491,34 @@ msgid "" "carefully before!" msgstr "Du kan sladda ved å halda inne ein eigen tast/knapp. Fleire stutte sladdingar hjelper deg å ta krappare svingar, mens lengre sladding gjev deg meir fart. Du kan ikkje slutta å svinga mens du sladdar, så pass på at køyretøyet peikar i rett retning før du startar sladdinga." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Du kan auka startfarten ved å akselerera når nedteljinga til løpet viser «Ferdig!»." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Du kan sjå og endra gjeldande tasteoppsett i «Oppsett»-menyen" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart har fleire spelmodusar:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Vanleg løp: Alt er lov, så plukk opp våpen og bruk dei på motstandarane!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Tidsløp: Inneheld ingen bonusar, så berre køyreteknikken din avgjer resultatet." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1468,7 +1526,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Følg leiaren: Prøv å heile tida vera på andreplass, sidan køyretøyet på sisteplass vert diska kvar gong teljaren når null. Obs: Er du framfor leiaren, vert du også diska!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1478,30 +1536,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Det finst tre ulike kampmodusar: I «3 liv» vinn du når du skadar motstandarane med våpen heilt til dei ikkje har fleire liv att. I «Fritt vilt» vinn spelaren som skadar andre flest gongar innan ei viss tids- eller treffgrense. I «Flaggrov» må laget ditt få flagget til motstandarlaget til flaggbasen dykkar samtidig som dykkar eige flagg ikkje vert teke av det andre laget." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Fotball: Køyr på ballen for å sparka han i mål." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Eggejakt: Utforsk banene for å finna alle dei gøymde egga." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Skuggeopptaksløp: Spel mot «skuggen» til andre spelarar i tidsløp eller eggejakt, og ta opp ditt eige skuggeopptak." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Flest rundar: Fullfør så mange rundar du klarar innan oppgjeven tid." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1510,93 +1568,93 @@ msgid "" "wins the cup." msgstr "* Du kan òg spela mange av spelvariantane i turnering. I staden for å køyra eitt løp, køyrer du då fleire på rad. Jo betre plassering du har i eit løp, desto fleire poeng får du. Spelaren som sit att med flest poeng til slutt, vinn turneringa." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "For å hjelpa deg å vinna kan du plukka opp bonusgjenstandar:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Tyggis: Vern deg med eit skjold eller, viss du ser bakover, lat etter deg ein rosa klisterpøl." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Fartspil: Gjev deg ei kort stund ein kraftig fartsauke. Men pass på at du ikkje mistar kontrollen over køyretøyet!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Kake: Vert hiven mot den næraste motstandaren. Verkar best på korte avstandar eller på lange, rette vegstrekningar. Verkar òg på køyretøy i nærleiken av eksplosjonen." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Sugekopp: Skyt framover for å trekkja ein motstandar bakover, eller skyt mens du ser bakover for å sperra utsikta." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Bowlingkule: Rullar rett framover til han treff noko (og sprett når han treff autovernet). Sjå bakover for å rulla han ut bak deg." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Fallskjerm: Sakkar farten til alle framfor deg." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Forvandling: Gjer for ei kort stund om gåver til bananar, eller nitroflasker til tyggis (eller omvendt)." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Basketball: Sprett etter personen som leiar, og kan skvisa og sakka andre køyretøy på vegen." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Flugesmekke: Skvis bilar i nærleiken, noko som sakkar farten deira. Kan òg brukast til å fjerna fallskjermar og bomber." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Køyrer du på ein banan, vert éin av desse hengjande på køyretøyet ditt:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Anker: Sakkar brått ned farten din." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Fallskjerm: Sakkar farten din gradvis ned. Jo raskare du køyrer, jo større effekt har han." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bombe: Eksploderer etter ei kort stund – og blåser då køyretøyet til himmels. Dult borti ein annan spelar for å overføra bomba til han." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Den vonde Nolok har teke Gnu til fange! Her har du nokre tips:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1605,7 +1663,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Dette ikonet på minikartet viser tilgjengelege utfordringar som du ikkje har klart enno. Oppe til høgre viser det deg òg kor mange poeng du har. Viss du klarar alle utfordringane, vil Nolok gå med på eit løp mot deg. Vinn for å frigjera Gnu!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1613,20 +1671,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Når du klarar ei utfordring, får du ein pokal. Kvar pokal er verd fleire poeng. Jo høgare vanskegrad du klarar utfordringa på, jo meir verdifull pokal får du." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Når du har fått så mange poeng som vert viste under dette ikonet, får du ei gåve. Det finst fleire ulike gåver du kan få." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Køyreeigenskapane varierer mellom køyretøya. Det finst fleire ulike eigenskapar:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1634,7 +1692,7 @@ msgid "" " resistant to explosions." msgstr "Vekt: Det finst tre vektklassar for køyretøya – lett, middels og tung. Tyngre køyretøy vert mindre påverka av fallskjermar, og dei toler eksplosjonar betre." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1642,7 +1700,7 @@ msgid "" " especially at low speeds." msgstr "Akselerasjon: Er spesielt nyttig i starten av løpet, etter ulukker og på baner med mange krappe svingar. Jo lettare køyretøyet er, jo raskare akselererer det, spesielt ved låg fart." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1650,14 +1708,14 @@ msgid "" " top speed." msgstr "Toppfart: Høg toppfart gjer at du kan køyra raskare. Er spesielt nyttig på baner med lange, rette vegstrekningar og slake svingar. Tyngre køyretøy har høgare toppfart." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Nitroeffektivitet: Jo høgare effektivitet, jo meir fart får du frå ei flaske nitro. Lettare køyretøy har høgare effektivitet." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1665,12 +1723,12 @@ msgid "" "easier it is." msgstr "Viss du følgjer rett etter eit anna køyretøy i nokre sekund, gjev dragsugseffekten deg fartsbonus når du køyrer forbi. Lettare køyretøy gjer dette enklare." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "Du kan spela SuperTuxKart saman med andre over nettet …:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1680,7 +1738,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Vel først «Over nettet» på hovudmenyen. Vel anten lokalnettverk eller Internett (Internett-tilgang må vera påslått i innstillingane). Du kan så oppretta din eigen tenar med innstillingane du føretrekkjer, eller velja ein tenar som andre har oppretta. Nokre av tenarane er anbefalte og har rankinglister." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1690,12 +1748,12 @@ msgid "" "players and the server." msgstr "Når du er inne på ein tenar, startar eit løp når eigaren (merkt med ei krone) vel å starta det. Offisielle tenarar kan starta løp automatisk når det er komme mange nok spelarar. Du kan så velja køyretøy og stemma på kva bane de skal spela. Tilleggsbaner kan brukast berre viss dei er installerte både hos alle spelarane og på tenaren." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "… eller på same maskin:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1705,7 +1763,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "De treng fleire styreeiningar. Gå til oppsettmenyen for styreeiningar for å setja dei opp. Det beste er å ha fleire handhaldne spelkontrollarar eller styrespakar. De kan òg spela på (eitt eller fleire) tastatur, men kvar spelar må ha sine eigne tastar, og dei fleste tastatura støttar ikkje at ein held inne mange tastar samtidig." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1725,7 +1783,7 @@ msgstr "Beste tider" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Flest rundar" @@ -1733,9 +1791,9 @@ msgstr "Flest rundar" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Turnering" @@ -1746,6 +1804,20 @@ msgstr "Turnering" msgid "Choose a Kart" msgstr "Vel køyretøy" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Køyretøyklasse" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Endre favorittkøyretøy" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1759,11 +1831,11 @@ msgstr "Fleire spelarar (delt skjerm)" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Over nettet" @@ -1780,7 +1852,7 @@ msgstr "Opplæringsbane" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Beste tider" @@ -1788,7 +1860,7 @@ msgstr "Beste tider" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Bragder" @@ -1842,30 +1914,30 @@ msgstr "Finn tenar" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Opprett tenar" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Lobby" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Oppsett" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Start løp" @@ -1891,9 +1963,9 @@ msgstr "Skriv inn tenaradresse" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Profilen din" @@ -1911,7 +1983,7 @@ msgstr "Rankingliste" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Vennar" @@ -1936,7 +2008,7 @@ msgstr "Kjappstart" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Kontoinnstillingar" @@ -1986,8 +2058,8 @@ msgid "Online Username" msgstr "Brukarnamn (nett)" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Tilbakestill passordet" @@ -1997,10 +2069,10 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Du kan spele utan å laga ein nettkonto ved å velje fråkopla konto, men då kan du ikkje ha venar eller røyste på tilegg, med meir. Ver venleg og les personvernerklæringa vår på https://privacy.supertuxkart.net." #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Tenarval" @@ -2018,339 +2090,409 @@ msgstr "Bruk IPv6-tilkopling" msgid "User search" msgstr "Brukarsøk" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "SuperTuxKart-oppsett" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Skjerm" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Grafikk" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Lyd" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Brukar­flate" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Spelarar" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Styring" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Språk" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Musikk" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "På" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Lydstyrke" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Lydeffektar" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Slett oppsett" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Slå av styreoppsettet" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Tilbake til einingslista" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Endra namn på styreoppsettet" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Slå på fysisk respons (viss støtta)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Oppløysing" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Fullskjerm" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Hugs vindaugsplasseringa" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Bruk ny oppløysing" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Fleire spelarar (delt skjerm)" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Internett-val" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Vis alltid påloggingsvindauget" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Kopla til Internett" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Slå på nettprat" +msgid "Enable chatting in online lobbies" +msgstr "Slå på chatt i venterom på nett" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Slå på nettprat for spel over nettet" +msgid "Enable chatting in online matches" +msgstr "Slå på chatt under kampar på nett" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Ymse val" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Bruk spelarspesifikke handikapp" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Avinstaller fullstendige speldata" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Trykk «Enter» eller dobbeltklikk på eit oppsett for å endra det" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Legg til kontrollar" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Kva oppsett som vert brukt, vert automatisk valt basert på tasten du brukar til å slutta deg til spelet." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Tema" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Minikart" +msgid "Skin variant" +msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Fleire spelarar (delt skjerm)" +msgid "Minimap" +msgstr "Minikart" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Skriftstorleik" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Kamera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Tilpassa …" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Vis talet på bilete per sekund" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Vis kva bonusar motspelarar har" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Vis totaltid i forteljingsmodus" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Vis totaltid for «speedrun»-forsøk" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Oppteiknings­oppløysing" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Grafiske effektar" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Sløringseffektar" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Maksgrense for bilete per sekund" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Tilpassa innstillingar …" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Oppløysing" +msgid "Performance tests" +msgstr "Ytingsprøver" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Fullskjerm" +msgid "Performance test of the current settings" +msgstr "Ytingsprøve med noverande innstillingar" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Hugs vindaugsplasseringa" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Hugs passordet" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Bruk ny oppløysing" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Slett" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Køyretøy­farge" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2377,15 +2519,15 @@ msgstr "Blått lag" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Talet på rundar" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Talet på datamotstandarar" @@ -2400,33 +2542,17 @@ msgstr "Talet på blå datamotstandarar" msgid "Random Grand Prix" msgstr "Tilfeldig turnering" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Endre favorittbaner" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Innlogging" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Hugs passordet" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Slett" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Køyretøy­farge" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Du kan velja tema for brukarflata under «Brukarflate» i innstillingane." @@ -2545,238 +2671,306 @@ msgid "" msgstr "Gå ikkje i vegen for ein medspelar som har ballen. Men du kan godt takla motstandarar når dei har ballen." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepar" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Djuphavsdykket" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Romsignal" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Labyrinten i Colosseum" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Landsbyen Lumen" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Kampøya" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Svartskogen" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Hole X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Kakaotempelet" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Maisgule marker" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Fort Magma" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Gran Paradiso ferieøy" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Haciendaen" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Fallhòl" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Frosen fotballbane" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Kva er gale, små hippiar? Saknar de den store gnu-leiaren dykkar?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "De skjønar, han er i slottet mitt no, og vert servert til kveldsmat …" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Men eg er eit vennleg vesen, så me kan gjera ei avtale." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Viss de kan slå meg i kappløp, skal eg sleppa den gamle sulliken fri." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " Men de patetiske små naut slår aldri meg – køyrekongen!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Las Dunas arena" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Las Dunas stadion" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Rundt fyrtårnet" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Den gamle gruva" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oasen" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Olivers mattetime" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Tusenfrykt" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Ramnkloppen herregard" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Solfylte sanddyner" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Nessies innsjø" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Høgfjellshotell" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Snødekte svingar" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Fotballbane" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Stadionet" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK AS" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Tempel" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Vulkanøya" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Zen-hagen" @@ -2785,11 +2979,11 @@ msgstr "Zen-hagen" msgid "Completed achievement \"%s\"." msgstr "Klarte bragda «%s»!" -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Klarte ikkje kopla til tenaren for SuperTuxKart-tillegg." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Feil ved nedlasting av nyheiter: «%s»" @@ -2855,7 +3049,7 @@ msgid "New kart '%s' now available" msgstr "Det nye køyretøyet «%s» er no tilgjengeleg" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2887,32 +3081,32 @@ msgid "" "created." msgstr "Oppsettfila var for gammal, og vart derfor sletta." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Videoopptak starta." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Videoen vart lagra i «%s»." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Kodar video:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d – %d kilotrekantar – ping: %d ms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Tips: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Lastar" @@ -2934,19 +3128,18 @@ msgstr "Nitroeffektivitet" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (handikappa)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s er klar" @@ -3420,21 +3613,21 @@ msgid "Axis %d" msgstr "Akse %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Spelkontroll-knapp %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Museknapp %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Museakse %d %s" @@ -3606,26 +3799,30 @@ msgstr "Du kan maks ha 3 liv!" msgid "+1 life." msgstr "+1 liv." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Du var for treg!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Du fullførte løpet!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Du vann løpet!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" -msgstr "Du fullførte løpet med %d poeng!" +msgstr "Du fullførte løpet med plass %d!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s forlét spelet." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3634,16 +3831,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart kan kopla til ein tenar for å lasta ned speltillegg og varsla deg om oppdateringar. Les meir om personvern på https://supertuxkart.net/Privacy. Ønskjer du å bruka denne funksjonaliteten? (For å endra dette seinare kan du gå til innstillingsvindauget, velja fana «Generelt» og kryssa av for «Kopla til Internett».)" -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Skjermoppløysinga di er for låg til at du kan køyra STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Skjermkortdrivaren din er for gammal, og du må oppgradera han." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3651,38 +3848,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Skjermkortdrivaren din er veldig gammal. Sjå om det har komme ei drivaroppdatering. SuperTuxKart verkar best med ein drivar som støttar %s eller høgare. Spelet vil framleis køyra, men med redusert grafikkvalitet." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Tidsavbrot på sambandet til tenaren." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s har det raude flagget!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Det raude flagget er tilbake!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s har det blå flagget!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Det blå flagget er tilbake!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s tok det blå flagget!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s tok det raude flagget!" @@ -3692,7 +3889,7 @@ msgstr "%s tok det raude flagget!" msgid "Eggs: %d / %d" msgstr "Egg: %d/%d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Leiar" @@ -3700,22 +3897,22 @@ msgstr "Leiar" msgid "Final lap!" msgstr "Siste runde!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Runde %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s av %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Ny runderekord" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "FEIL VEG!" @@ -3729,194 +3926,194 @@ msgstr "%s skåra!" msgid "Oops, %s made an own goal!" msgstr "Uff då – %s skåra sjølvmål!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "Det er no sett ut %i vogn med reservehjul!" msgstr[1] "Det er no sett ut %i vogner med reservehjul!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Du er no ute av løpet!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "%s er no ute av spelet." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Tenaren er stengd ned." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Du vart sparka ut av tenaren." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Du vart sparka ut: For høge ping-verdiar." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Oppdaga dårleg nettverkssamband." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s kopla frå." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Trykk på spelarnamnet i lista for spelarhandsaming og rankingoversikt." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Vanskegrad: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Makstal spelarar: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Spelmodus: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Tidsgrense" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Målgrense" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Type fotballspel: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Turneringsframgang: %d/%d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Alle spelarane er på same lag." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Du er no eigar av tenaren." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Nekta tilkopling: Tenaren er oppteken." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Nekta tilkopling: Du er utestengd frå tenaren." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Nekta tilkopling: Feil passord til tenaren." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Nekta tilkopling: Speldataa er ikkje kompatible." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Nekta tilkopling: Tenaren er full." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Nekta tilkopling: Ugyldig spelar prøvde å kopla seg til." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Klarte ikkje starta nettverksspelet." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Løpet er ferdig, så du kan ikkje lenger delta eller vera tilskodar." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Kan ikkje delta, då det ikkje er fleire ledige plassar i arenaen." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Berre 1 spelar att. Går tilbake til lobbyen." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Tenareigaren avslutta spelet." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Du vert tilskodar til neste løp." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s vart med på det raude laget." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s vart med på det blå laget." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s vart med." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3924,15 +4121,15 @@ msgid "" msgstr "Trykk <%s> eller <%s> for å byta målspelar og <%s> eller <%s> for å byta kameraplassering." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "Spelaren %s er no rapportert." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3963,38 +4160,38 @@ msgstr "Tidsløp (turnering)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Fritt vilt" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Flaggrov" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s er no tilkopla." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s og %s er no tilkopla." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s og %s er no tilkopla." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4002,19 +4199,19 @@ msgstr[0] "%d venn er no tilkopla." msgstr[1] "%d vennar er no tilkopla." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s er no på tenaren «%s»." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "Du har fått %d ny venneførespurnad!" msgstr[1] "Du har fått %d nye venneførespurnadar!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Du har fått ein ny venneførespurnad!" @@ -4043,12 +4240,12 @@ msgid "" msgstr "Rekordfila var for gammal, og\nalle rekordane vart derfor fjerna." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Følg leiaren" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Tre liv" @@ -4061,91 +4258,88 @@ msgstr "Ufullstendig skuggeopptaksfil vert ikkje lagra." msgid "Replay saved in \"%s\"." msgstr "Skuggeopptak lagra i «%s»." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 veke" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 veker" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 månad" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 månadar" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 månadar" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 månadar" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 år" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 år" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Namn" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Dato oppdatert" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Ikkje installert" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s av %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Vent mens tillegga vert oppdaterte" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Klarte ikkje kontakta nettstaden som har speltillegga. Sjå til at du er kopla til Internett, og at ein brannmur ikkje hindrar SuperTuxKart å få kontakt med nettet." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Favorittar" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Låst: Fullfør utfordringar for å få tilgang til meir!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Tilfeldig arena" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d arena ikkje tilgjengeleg i éinspelarmodus." -msgstr[1] "%d arenaar ikkje tilgjengelege i éinspelarmodus." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Karl Ove Hufthammer" @@ -4433,7 +4627,7 @@ msgstr "Samla bananar" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Sladding" @@ -4536,7 +4730,7 @@ msgstr "Fullførte eggejakter" msgid " (official tracks matching the goal)" msgstr " (offisielle baner i samsvar med mål)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4544,91 +4738,95 @@ msgid "" msgstr "Nye spel­kontrollarar og styre­spakar vil automatisk dukka opp i spelkontrollar­oversikta når du koplar dei til.\n\nDu kan leggja til eit tasteoppsett med knappen nedanfor. Men merk at dei fleste tastatura ikkje støttar at du held inne mange tastar samtidig, og vil derfor fungera dårleg for fleire spelarar. Du kan òg kopla til fleire tastatur, men hugs at alle spelarane likevel må bruka ulike tastar." #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Legg til Wii-kontrollar" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Legg til tasteoppsett" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Oppdater" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Versjon: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "Anbefalt" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Storleik: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Du må vere innlogga for å vurdere dette tillegget." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Klarte ikkje lasta ned tillegget" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Problem med installering av tillegget «%s»." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Prøv på nytt" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Problem med fjerning av tillegget «%s»." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Bakgrunnsnedlastinga er no fullført." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Bakgrunnsnedlasting" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Bakgrunnsnedlastinga er alt starta." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Det gjeldande passordet er ugyldig." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Passordet må vera mellom 8 og 30 teikn langt." -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Passorda er ikkje like." -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Kontrollerer informasjon" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Passordet er no endra." @@ -4649,67 +4847,97 @@ msgstr "Skjermoppløysingar lågare enn 1024 × 768 og 1280 × 720 er ikkje of #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Dronefølgje" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Tilpassa" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Av" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Berre viktige" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Veldig låg" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Låg" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Middels" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Høg" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Svært høg" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4717,7 +4945,7 @@ msgid "" msgstr "SuperTuxKart vil lasta ned fullstendige speldata (grafikk av høgare kvalitet og musikk), for å gje ei betre speloppleving. Dette vil bruka mobildata dersom du ikkje er tilkopla Wi-Fi." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4734,101 +4962,102 @@ msgstr "Skriv inn tenaradressa, eventuelt etterfølgt av kolon («:») og portnu msgid "Invalid server address: %s." msgstr "Ugyldig tenaradresse: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Baklengs" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Vanskegrad" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Rundar" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Tid" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Køyretøy" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Brukar" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Versjon" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Nei" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Bane" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Dei %d beste tidene" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Talet på køyretøy: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Tidsmål: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Rundar: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Baklengs: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Tom)" @@ -4916,33 +5145,41 @@ msgid "Press any key..." msgstr "Trykk ein tast …" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Prat i lobbyen er slått av. Du kan slå det på i innstillingane." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Attende til ytingsprøva" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Gå frå ytingsprøva" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Tilbake til kampen" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Set opp ny kamp" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Start kampen på nytt" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Avslutt kampen" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Set opp nytt løp" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Avslutt løpet" @@ -4958,11 +5195,11 @@ msgstr "%s har ikkje fått rankingpoeng enno." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s ligg på %d. plass på rankinglista, med %f poeng." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Brukarnamnet eller e-postadressa er ugyldig." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4984,7 +5221,7 @@ msgstr "Skuggeopptaksløp" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Rundar: %i" @@ -4997,21 +5234,21 @@ msgstr "Type: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Nødvendig plassering: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Nødvendig tid: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Nødvendige nitropoeng: %i" @@ -5024,54 +5261,54 @@ msgstr "Talet på datamotstandarar: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Kampmodus" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Type fotballspel" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Tenarplassering: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Gjeldande bane: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Plass" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Spelar" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Poeng" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Tid spelt" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Fjern frå bokmerke" @@ -5084,74 +5321,74 @@ msgid "No player available for connecting to server." msgstr "Ingen spelar tilgjengeleg for kopling til tenar." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Brukarnamn: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Avbryt førespurnad" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "I dag" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Venneførespurnad send!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Venneførespurnad godteken!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Venneførespurnad avslått!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Venn fjerna!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Venneførespurnad avbroten!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Handsamar" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Hentar siste røyst" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Du kan endra karakteren du gav tidlegare ved å trykkja på stjernene under." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Du har ikkje røysta på dette tillegget enno. Vel karakter ved å trykkja på ei av stjernene nedanfor." -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Røyst registrert! Du kan no lukka vindauget." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Røystar" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Tilfeldig bane" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5180,7 +5417,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Det oppstod ein feil ved lagringa av turneringa." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Vel bane" @@ -5224,12 +5461,12 @@ msgstr "Du låste opp bana %0!" msgid "You unlocked grand prix %0" msgstr "Du låste opp turneringa %0!" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Bane" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5250,19 +5487,19 @@ msgstr "Skriv inn eit namn på den nye turneringa" msgid "Please select a Grand Prix" msgstr "Vel ei turnering" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Sjølvlaga" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Namnet er tomt." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Det finst alt ei turnering med dette namnet." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Namnet er for langt." @@ -5271,19 +5508,19 @@ msgstr "Namnet er for langt." msgid "Better luck next time!" msgstr "Betre lukke neste gong!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Du klarte ei utfordring!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Du vann heile turneringa!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Du fullførte turneringa!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Talet på køyretøy" @@ -5296,110 +5533,125 @@ msgstr "Er du sikker på at du vil fjerna denne rekorden?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Er du sikker på at du vil fjerna alle rekordane dine?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Favoritt" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Lett" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Tung" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Kopla til eit tastatur eller ein spelkontrollar for å spela fleire over delt skjerm" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Tilfeldig køyretøy" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Låst" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Alle:\nTrykk på «Vel»-knappen for å verta med i spelet" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Ønskjer du å spela opplæringsbana?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Du kan ikkje spela over nettet utan Internett-tilgang. Viss du vil spela over nettet, vel «Kopla til Internett» i innstillingane." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Du kan ikkje lasta ned tillegg utan Internett-tilgang. Viss du vil lasta ned nye tillegg, vel «Kopla til Internett» i innstillingane." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Du kan ikkje lasta ned tillegg utan Internett-tilgang. Viss du vil lasta ned nye tillegg, vel «Kopla til Internett» i innstillingane.\n\nMen du kan godt sletta tillegg du tidlegare har lasta ned." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Tillegg-modulen er slått av i «Oppsett»-menyen" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Vent mens tillegga vert lasta inn" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Er du sikker på at du vil avslutta STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Opprett LAN-tenar" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "%s sin tenar" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Baner i turnering" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Namnet må vera mellom 4 og 30 teikn langt." -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Ugyldige teikn i passordet!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Klar" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Delta" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Tilskodar" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Installer tillegg" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5407,7 +5659,7 @@ msgstr "Vent til løpet («%s») er ferdig. Det er om lag så lenge til: %s." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Vent til løpet er ferdig. Det er om lag så lenge til: %s." @@ -5415,24 +5667,24 @@ msgstr "Vent til løpet er ferdig. Det er om lag så lenge til: %s." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Vent til løpet («%s») er ferdig. Det har komme om lag så langt: %s %." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Vent til løpet er ferdig. Det har komme om lag så langt: %s %." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Vent til løpet er ferdig." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5441,7 +5693,7 @@ msgstr[1] "Spelet startar når det er fleire enn %d spelarar." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5450,96 +5702,108 @@ msgid_plural "" msgstr[0] "Startar om %d sekund, eller når alle har trykt på «Klar»." msgstr[1] "Start om %d sekund, eller når alle har trykt på «Klar»." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Koplar til tenaren «%s»" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Leitar etter ein kjappstart-tenar" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Tid att: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Mål" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Hentar bragder" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Profilen til %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Sidan" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Status" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Hentar vennar" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Ny førespurnad" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Ventar" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Fråkopla" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Skriv inn ny e-postadresse nedanfor" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Den nye e-postadressa må vera mellom 5 og 254 teikn lang." -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Den nye e-postadressa er ugyldig." -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "E-postadressa er no endra." -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Klarte ikkje endra e-postadresse: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Nyhende frå STK-vevloggen" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Dato" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Det finst ingen nyhende for tida" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Du må vera logga inn før du kan spela over Internett. Trykk på brukarnamnet ditt ovanfor." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Søkjer" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Avslutt spelet" @@ -5617,34 +5881,34 @@ msgid "Distance (km)" msgstr "Avstand (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Ukjend" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Fann ikkje IPv4-tilgang. Det kan vera du ikkje får tilgang til nokon tenarar." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Fann ikkje IPv6-tilgang. Det kan vera du ikkje får tilgang til nokon tenarar." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Ingen tenarar er tilgjengelege." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Hentar tenaroversikt" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Tenarbokmerke" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5652,149 +5916,149 @@ msgstr "Viss fleirtalet av spelarane har valt same bane og innstillingar, vert a #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Tilfeldig plassering av gjenstandar" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Talet på mål å vinna" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Køyr baklengs" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Låst: Fullfør utfordringar for å få tilgang til meir!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Handling" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Tastebinding" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Fjern oppsett" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Bruk eining" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Slå på styreoppsettet" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Speltastar" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Menytastar" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Sving til venstre" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Sving til høgre" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Akselerer" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Brems/baklengs" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Skyt" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Sjå bakover" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Redning" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Pause" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Opp" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Ned" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Venstre" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Høgre" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Vel" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Avbryt/tilbake" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Eit blått element tyder at det er ein konflikt med eit anna oppsett" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Raud tekst tyder at det er ein konflikt i oppsettet" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5802,17 +6066,27 @@ msgid "" msgstr "Åtvaring: Du bør ikkje bruka tasten «Shift», sidan alle tastar som endrar teikn når du held inne «Shift» ikkje vil fungera skikkeleg." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Er du sikker på at du vil fjerna dette oppsettet?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Vel namn på det nye oppsettet. La feltet stå tomt for å bruka standardnamnet." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Venstre/høgre" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Oppe/nede" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5820,89 +6094,74 @@ msgstr "Spelarar kan velja handikappa (vanskelegare)\nprofilar på køyretøyskj #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Installer fullstendige speldata" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Er du sikker på at du vil avinstaller fullstendige speldata?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Tastatur %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Peikeskjerm-eining" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Trykk på eininga du vil setja opp" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Systemspråket" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Nede til venstre" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "På høgre side" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Gøymt" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Sentrert" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Venstre/høgre" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Oppe/nede" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Veldig liten" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Liten" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Middels" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Stor" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Veldig stor" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5912,128 +6171,133 @@ msgid "" msgstr "«Speedrun»-modus kan berre slåast på dersom spelet ikkje har blitt lukka sidan du starta forteljingsmodusen.\n\nViss du lukkar spelet før fullføring av forteljingsmodus, er ikkje lenger tidtakaren gyldig.\n\nViss du vil bruka «speedrun»-modus, lag ein ny profil." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Vertikal synkronisering" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Vertikal synkronisering («vsync») tvingar skjermkortet til å\nsenda eit nytt bilete først når skjermen er klar til å visa det." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Vsync verkar berre dersom drivaren støttar det." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Partikkeleffektar: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Animerte figurar: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Dynamisk lyssetjing: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Lysspreiing: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Kantutjamning: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Omgjevnadsskugge: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Skuggar: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Skuggar: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Glød: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Kantlinjeglød: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Lyssjakt (gudestrålar): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Biletkvalitet: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Rørslesløring: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Djupneskarpleik: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Internett-tilgangen er slått av. Vil du slå han på?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Du må oppgje passord." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Loggar ut «%s»" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Loggar inn «%s»" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Du kan ikkje sletta den einaste spelaren." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Er du sikker på at du vil sletta spelaren «%s»?" @@ -6061,7 +6325,7 @@ msgstr "MÅL!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Ventar på andre" @@ -6096,7 +6360,7 @@ msgstr "Følg leiaren!" msgid "Top %i" msgstr "%i beste" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Klarte ikkje utfordringa" @@ -6120,102 +6384,199 @@ msgstr "Trykk på podiet for å starta utfordringa" msgid "Press fire to start the challenge" msgstr "Trykk skyt for å starta utfordringa" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Attende til grafikkinnstillingar" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Lagre prøveresultata" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Attende til hovedmenyen" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Kopla frå tenaren" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Avbryt turneringa" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Start på nytt" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Tilbake til val av utfordring" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Spel mot det nye skuggeopptaket" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Tilbake til menyen" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Er du sikker på at du vil avbryta turneringa?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Ytingsmelding vart lagra i \"%s\"." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Det raude laget vann" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Det blå laget vann" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Uavgjort" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Ute etter %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Ute" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Sjølvmål)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Bane %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Turneringsframgang" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Beste tider" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Beste rundetid: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "av %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Du klarte utfordringa!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Du klarte ikkje utfordringa!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Oppfylte SuperTux-krava" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Ytingsprøveresultat" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Prøvevarigskap: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Vannrett oppløysing: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Loddrett oppløysing: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Dynamisk belysning: PÅ" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Dynamisk belysning: AV" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Alt er lov, så plukk opp våpen og bruk dei på motstandarane!" @@ -6256,28 +6617,28 @@ msgstr "Trykk på den raude eller blå fotballen for å velja lag" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Bana er laga av %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Makstal spelarar: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Talet på raude datamotstandarar" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Du kan ikkje spela denne turneringa, då ho inneheld baner som ikkje er opplåste." -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Låst!" @@ -6299,10 +6660,12 @@ msgid "%d/%m/%Y" msgstr "%d.%m.%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Klar alle utfordringane for å låsa opp den store døra!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6311,41 +6674,48 @@ msgid "" msgstr "Du treng fleire poeng\nfor å kunna prøva deg på\ndenne utfordringa. Du\nkan sjå kva utfordringar\nsom tilgjengelege på kartet." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Akselerer med <%s>, og styr med <%s> og <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Akselerer ved å trykka oppe på rattet, og styr ved å dra det til venstre og høgre." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Akselerer ved å flytta akselerometeret oppover, og styr ved å vippa mobilen/eininga." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Akselerer ved å flytta akselerometeret oppover, og styr ved å dreia mobilen/eininga." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Plukk opp gåver, og trykk så skyteknappen <%s> for å verta kvitt desse kassane!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Plukk opp gåver, og trykk så på bowlingkula for å verta kvitt desse kassane!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6353,34 +6723,41 @@ msgid "" msgstr "Trykk <%s> for å sjå bak deg.\nUtløys våpenet med <%s> mens du held inne <%s> for å skyta det bakover!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Trykk på spegelen for å sjå bak deg.\nSkyt bakover ved å halda inne spegelen mens du sveipar til bowlingkula!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Trykk <%s> for å bruka nitroflaskene!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Trykk på nitroflaska for å bruka nitroen!" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Plukk opp nitroflasker (me skal bruka dei etter svingen)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Oi sann! Når du får problem, kan du trykkja <%s> for å verta redda." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Oi sann! Når du får problem, kan du trykkja på fuglen for å verta redda." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6388,24 +6765,27 @@ msgid "" msgstr "Akselerer og trykk <%s> mens du svingar for å sladda.\nOm du sladdar litt, kan du klara å ta krappare svingar." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Akselerer og trykk på sladdehjula mens du svingar for å sladda.\nOm du sladdar litt, kan du klara å ta krappare svingar." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Viss du klarar å sladda i fleire sekund, får du også ein fartsbonus som lønn for strevet!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Du er no klar til å køyra ekte løp. Lukke til!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Eit racerspel i 3D med open kjeldekode" @@ -6415,7 +6795,7 @@ msgstr "Eit racerspel i 3D med open kjeldekode" msgid "tux;game;race;" msgstr "tux;spel;billøp;racerspel;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6423,7 +6803,7 @@ msgid "" "for all ages." msgstr "Racerkøyretøy – nitroar – action! SuperTuxKart eit racerspel i 3D, med open kjeldekode og mange ulike køyretøy, baner og spel­modusar. Målet er eit spel med meir vekt på underhaldning enn på realisme – eit som gjev mykje moro for folk i alle aldrar." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6432,7 +6812,7 @@ msgid "" "your opponents." msgstr "Me har fleire baner du kan køyra på – med spennande tema som djuphavet, bonde­landet, jungelen og verds­rommet! Køyr så godt du kan, for å unngå at motstandarane klarar å komma forbi deg. Og ikkje et bananane! Pass deg òg for bowling­kulene, suge­koppane, tyggisane og kakene som motstandarane prøver å hiva på deg for å øydeleggja." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6441,27 +6821,27 @@ msgid "" "your racing skills!" msgstr "Du kan blant anna konkurrera mot vennar eller datamaskina i enkeltløp, ulike turneringar og kampmodus, eller prøva å slå gamle tidsrekordar! Og ønskjer du ei større utfordring, kan du møta og prøva deg mot spelarar frå heile verda via nettet!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Spelet er heilt utan reklame." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Dette er ein ustabil testversjon av SuperTuxKart med dei nyaste forbetringane. Han er hovudsakleg meint for testing, slik at den endelege versjonen vert så god som mogleg." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Denne versjonen kan installerast parallelt med den stabile versjonen på denne eininga." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Viss du vil vera sikra ei meir stabil spel­oppleving, bør du bruka den stabile versjonen: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "SuperTuxKart-utviklarlaget" diff --git a/data/po/pl.po b/data/po/pl.po index 9a5658a09e1..259c3e409f7 100644 --- a/data/po/pl.po +++ b/data/po/pl.po @@ -5,10 +5,11 @@ # Translators: # Deve , 2015 # Deve , 2015-2021 -# Jakub Fabijan (Felidae) , 2021 +# jano2137, 2021 # Jakub Wojtkowiak , 2016,2021 # Marcin Węclewski, 2022 -# Marcin Węclewski, 2022-2023 +# Marcin Węclewski, 2022-2023,2025 +# Michał Wijas, 2025 # mrkubax10 _ , 2022-2023 # Patryk Wychowaniec , 2015-2016 # Tomek Woźniak , 2019 @@ -16,9 +17,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Marcin Węclewski, 2022-2023\n" +"Last-Translator: Marcin Węclewski, 2022-2023,2025\n" "Language-Team: Polish (http://app.transifex.com/supertuxkart/supertuxkart/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -175,7 +176,7 @@ msgstr "Na Końcu Świata" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Powrót" @@ -197,7 +198,7 @@ msgstr "Wybiesz rodzaj sterowania jaki preferujesz" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Akcelerometr" @@ -211,13 +212,13 @@ msgstr "Akcelerometr" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Żyroskop" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Kierownica" @@ -248,35 +249,37 @@ msgstr "Ustawienia urządzenia dotykowego" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Ogólne" @@ -344,30 +347,33 @@ msgstr "Przywróć domyślne" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Anuluj" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Tak" @@ -545,9 +551,9 @@ msgstr "Dołącz" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -608,7 +614,7 @@ msgstr "Cel" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Postęp" @@ -643,7 +649,7 @@ msgstr "Wyślij" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Powrót do wyścigu" @@ -660,7 +666,7 @@ msgstr "Powrót do pokoju" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Powtórz wyscig" @@ -724,12 +730,12 @@ msgstr "Wpisz nazwę użytkownika i adres e-mail podany przy rejestracji w celu #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Nazwa użytkownika" @@ -770,7 +776,7 @@ msgstr "Trudność" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Nowicjusz" @@ -782,7 +788,7 @@ msgstr "Nowicjusz" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Średniak" @@ -794,7 +800,7 @@ msgstr "Średniak" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Ekspert" @@ -806,7 +812,7 @@ msgstr "Ekspert" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -814,8 +820,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Styl gry" @@ -826,8 +832,8 @@ msgstr "Styl gry" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Zwykły wyścig" @@ -840,7 +846,7 @@ msgstr "Zwykły wyścig" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Czasówka" @@ -848,7 +854,8 @@ msgstr "Czasówka" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Bitwa" @@ -857,24 +864,24 @@ msgstr "Bitwa" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Piłka Nożna" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Hasło" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Dodaj zakładkę" @@ -885,7 +892,7 @@ msgstr "Dodaj gracza" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Nazwa" @@ -979,6 +986,50 @@ msgstr "Przypisz do ESC" msgid "Assign nothing" msgstr "Nie przydzielaj" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Zalecane ustawienia graficzne" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Zalecane ustawienia będą zastosowane dla obecnej rozdzielczości." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Co powinny wyróżniać ustawienia?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Wydajność" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Zrównoważ wydajność i jakość grafiki" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Jakość grafiki" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Oszczędzanie energii" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Czy podobają ci się efekty graficzne rozmywające obraz?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Rozpocznij test" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -993,11 +1044,11 @@ msgstr "Ustawienia wyścigu" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Kontynuuj" @@ -1038,10 +1089,15 @@ msgstr "Areny" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Zainstalowany" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Edytuj ulubione areny" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1051,20 +1107,20 @@ msgstr "Zainstalowany" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Standardowe" @@ -1075,12 +1131,12 @@ msgstr "Standardowe" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Dodatki" @@ -1094,27 +1150,28 @@ msgstr "Dodatki" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Wszystko" @@ -1153,9 +1210,9 @@ msgstr "Przesuń w dół" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Dodaj" @@ -1192,7 +1249,7 @@ msgstr "Wyścig z duchem" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Polowanie Na Pisanki" @@ -1239,10 +1296,10 @@ msgstr "Przeciwny kierunek" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Maksymalny czas (min.)" @@ -1274,9 +1331,9 @@ msgstr "Kopiuj" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1287,80 +1344,80 @@ msgstr "Zmień nazwę" msgid "Save Grand Prix" msgstr "Zapisz Grand Prix" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Pomoc gry SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Style gry" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Bonusy" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Banany" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1368,56 +1425,57 @@ msgstr "Banany" msgid "Story Mode" msgstr "Historia" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Klasy gokartów" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Wielu graczy" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Zacznij samouczek" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Zbieraj niebieskie skrzynki, dadzą ci bonusy" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Unikaj bananów!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1425,14 +1483,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Zbieranie nitro pozwala Ci przyspieszyć, gdy naciśniesz odpowiedni do tego klawisz. Możesz zobaczyć swój obecny stan nitro na wskaźniku w prawym dolnym rogu ekranu." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Jeśli widzisz taki przycisk jak obok, musisz ukończyć wyzwanie, aby to odblokować." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1441,34 +1499,34 @@ msgid "" "carefully before!" msgstr "Klawisz ślizgania umożliwia poślizg. Krótkie ślizganie pomaga na ostrych zakrętach. Jeśli ślizgasz się wystarczająco długo, otrzymasz przyspieszenie. Podczas ślizgania nie da się zmienić kierunku jazdy, więc ustaw wcześniej swojego gokarta w odpowiednią stronę." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Możesz otrzymać dodatkowe przyspieszenie naciskając przycisk przyspieszenia podczas komendy \"Do startu!\" przed rozpoczęciem wyścigu." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Ustawienia klawiszy można przejrzeć/zedytować w opcjach" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart oferuje kilka trybów gry:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Normalny wyścig: wszystkie chwyty dozwolone, więc zbieraj bonusy i zrób z nich użytek!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Czasówka: nie zawiera bonusów, więc możesz przetestować swoje umiejętności kierowcy!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1476,7 +1534,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Śledź Lidera: bądź na drugim miejscu. Ostatni gracz zostanie zdyskwalifikowany, kiedy czas osiągnie 0. UWAGA: jazda przed liderem też eleminuje!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1486,30 +1544,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Są trzy rodzaje trybu bitwy: W Walce 3 Walnięć musisz uderzać innych bronią, aż stracą wszystkie swoje życia. W Każdy na Każdego wygrywa gracz, który trafi innych najwięcej razy w czasie gry. W Zdobądź Flagę Twoja drużyna musi przynieść flagę przeciwnika do swojej bazy, zanim przeciwnik zabierze Waszą flagę." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Piłka Nożna: Użyj swojego gokarta, aby wepchnąć piłkę do bramki." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Polowanie Na Pisanki: Znajdź wszystkie ukryte jajka" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Wyścig z duchem: Ścigaj się z duchem w trybach Czasówka oraz Polowanie na Pisanki i nagraj własnego ducha!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Test Okrążeniowy: Wykonaj jak najwięcej okrążeń w danym przedziale czasowym." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1518,93 +1576,93 @@ msgid "" "wins the cup." msgstr "* Większość z tych trybów gry można zagrać w trybie Grand Prix - zamiast grać jeden wyścig, można kilka pod rząd. Im wyżej w rankingu, tym więcej punktów dostaniesz. Na końcu, gracz z największą ilością punktów wygrywa puchar." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "W wyścigu pomogą ci bonusy do zbierania:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Guma do żucia - ochroń się osłoną lub użyj patrząc wstecz, aby zostawić lepką różową kałużę za sobą." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Suwak - daje mocne przyspieszenie. Uważaj, aby nie stracić kontroli nad swoim gokartem!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Tort - rzucany w najbliższego rywala, doskonały w krótkim zasięgu i długich prostych. Dosięga też inne gokarty w pobliżu eksplozji." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Przepychaczka - rzuć do przodu, by złapać przeciwnika lub rzuć do tyłu, by przeciwnik stracił widoczność." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Kula do kręgli - kula się do przodu aż w coś uderzy, odbija się od ścian. Jeśli partzysz w tył, kula zostanie puszczona za ciebie." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Spadochron - spowalnia wszystkie gokarty na lepszych pozycjach" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Podmieniacz - prezenty zostają zamienione w bananany, a nitro w gumy do żucia i na odwrót przez krótki czas." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Piłka do koszykówki - odbija się w kierunku lidera, może zmiażdżyć i spowolnić gokarty znajdujące się na jej drodze." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Packa - spowalnia gokarty. Może być też użyta, aby usunąć spadochrony i bomby." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Zebranie banana może skutkować załączeniem do gokarta jednego z przedmiotów:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Kotwica - spowalnia gokarta." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Spadochron - spowalnia gokarta bardziej stopniowo niż kotwica. Im szybciej jedziesz, tym mocniej spowalnia." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bomba - wybucha po krótkim czasie, wyrzucając gokarta w powietrze. Uderz w innego gokarta, aby przenieść bombę na innego gracza." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Zły Nolok złapał Gnu! Oto kilka wskazówek, które mogą Ci pomóc:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1613,7 +1671,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Ta ikona na mapie oznacza wyzwania, których jeszcze nie ukończyłeś. W prawym górnym rogu ekranu możesz też zobaczyć jak dużo aktualnie masz punktów. Ukończ tak dużo wyzwań jak to możliwe, a Nolok pozwoli Ci zmierzyć się z nim. Wygraj wyścig, aby uwolnić Gnu!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1621,20 +1679,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Gdy ukończysz wyzwanie, dostajesz puchar. Każdy puchar warty jest kilka punktów. Im wyższy wybrany poziom trudności, tym lepszy puchar i więcej punktów." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Gdy zdobędziesz ilość punktów podaną poniżej tej ikony, otrzymasz niespodziankę. Jest ich kilka do zdobycia." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Nie wszystkie gokarty jeżdżą tak samo! Należą one do klas z kilkoma różnicami:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1642,7 +1700,7 @@ msgid "" " resistant to explosions." msgstr "Masa - są trzy klasy gokartów w zależności od ich masy: lekkie, średnie i ciężkie. Im cięższy jest gokart, tym bardziej odporny jest na spadochrony i eksplozje." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1650,7 +1708,7 @@ msgid "" " especially at low speeds." msgstr "Przyspieszenie - szczególnie przydatnie przy starcie, po stłuczce lub na trasie z wieloma ostrymi zakrętami. Im lżejszy jest gokart, tym szybciej przyspiesza, w szczególności przy niskich prędkościach." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1658,14 +1716,14 @@ msgid "" " top speed." msgstr "Maksymalna prędkość - im wyższa, tym szybciej może jechać Twój gokart. Szczególnie przydatne na trasach z długimi prostymi i delikatnymi zakrętami. Cięższe gokarty mają większą maksymalną prędkość." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Wydajność nitro - Im większa, tym mniej zużyjesz nitro, aby się rozpędzić. Lżejsze gokarty zużywają mniej nitro." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1673,12 +1731,12 @@ msgid "" "easier it is." msgstr "Jeśli będziesz jechał przez kilka sekund blisko za innym gokartem, otrzymasz dodatkowe przyspieszenie jako bonus. Im lżejszy jest Twój gokart, tym jest to łatwiejsze." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "W SuperTuxKart można grać w trybie dla wielu graczy przez internet...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1688,7 +1746,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Najpierw wybierz ikonę \"online\" w menu głównym. Wybierz lokalne lub globalne połączenie (wymaga włączonego internetu w opcjach). Następnie możesz utworzyć własny serwer z wybranymi opcjami, lub znaleźć na liście istniejący serwer i dołączyć do niego. Niektóre z nich są zalecanymi serwerami, opcjonalnie z rankingiem." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1698,12 +1756,12 @@ msgid "" "players and the server." msgstr "Gdy jesteś połączony z serwerem, wyścig zacznie się gdy właściciel serwera (oznaczony koroną) tak zadecyduje. Oficjalne serwery mogą startować automatycznie, gdy wystarczająco dużo graczy jest połączonych. Następnie możesz wybrać swojego gokarta i głosować na trasę, na której chciałbyś zagrać. Trasy z dodatków są dozwolone tylko gdy są zainstalowane u wszystkich graczy i na serwerze." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... lub na tym samym urządzeniu:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1713,7 +1771,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Po pierwsze, potrzebujesz kilku różnych urządzeń kontrolujących (najlepszym rozwiązaniem do gry w kilka osób jest posiadanie większej ilości gamepadów i/lub dżojstików). Idź do konfiguracji sterowania i zmień ustawienia kontrolerów. Jest też możliwość grania na klawiaturze/klawiaturach, jednakże każdy gracz potrzebuje innych klawiszy. Trzeba mieć także na uwadze to, że większość klawiatur nie obsługuje dużej ilości wciśniętych klawiszy na raz." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1733,7 +1791,7 @@ msgstr "Wybór rekordu" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Test Okrążeniowy" @@ -1741,9 +1799,9 @@ msgstr "Test Okrążeniowy" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Grand Prix" @@ -1754,6 +1812,20 @@ msgstr "Grand Prix" msgid "Choose a Kart" msgstr "Wybierz pojazd" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Klasa gokarta" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Edytuj ulubione gokarty" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1767,11 +1839,11 @@ msgstr "Podzielony ekran" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Online" @@ -1788,7 +1860,7 @@ msgstr "Samouczek" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Rekordy" @@ -1796,7 +1868,7 @@ msgstr "Rekordy" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Osiągnięcia" @@ -1850,30 +1922,30 @@ msgstr "Znajdź serwer" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Utwórz serwer" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Pokój" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Konfiguracja" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Zacznij wyścig" @@ -1899,9 +1971,9 @@ msgstr "Wpisz adres serwera" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Twój profil" @@ -1919,7 +1991,7 @@ msgstr "Ranking graczy" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Przyjaciele" @@ -1944,7 +2016,7 @@ msgstr "Szybka gra" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Ustawienia konta" @@ -1994,8 +2066,8 @@ msgid "Online Username" msgstr "Nazwa online" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Zresetuj hasło" @@ -2008,7 +2080,7 @@ msgid "" msgstr "Możesz grać bez tworzenia konta online, wybierając konto offline. Jednak w takim przypadku nie będziesz mógł połączyć się ze znajomymi, oceniać dodatków, itp. Prosimy zapoznać się z naszą polityką prywatności na stronie https://privacy.supertuxkart.net." #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Wybór serwera" @@ -2026,339 +2098,409 @@ msgstr "Użyj połączenia IPv6" msgid "User search" msgstr "Szukaj użytkownika" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Opcje gry SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Wyświetlanie" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Grafika" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Dźwięk" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Interfejs" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Gracze" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Sterowanie" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Język" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Muzyka" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Włączone" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Głośność" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Efekty dźwiękowe" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Usuń konfigurację" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Wyłącz konfigurację" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Powrót do listy urządzeń" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Zmień nazwę" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Włącz force feedback (jeśli obsługiwane)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Rozdzielczość" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Pełny ekran" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Zapamiętaj położenie okna" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Potwierdź nową rozdzielczość" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Podzielony ekran" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Zawsze pokazuj ekran logowania" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Połącz się z siecią" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Włącz czat online" +msgid "Enable chatting in online lobbies" +msgstr "Włącz rozmowy w lobby online" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Włącz rozmowy w grach online" +msgid "Enable chatting in online matches" +msgstr "Włącz rozmowy w meczach online" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Różne" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Włącz utrudnienia dla graczy" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Odinstaluj pełne zasoby gry" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Naciśnij enter lub kliknij dwukrotnie na urządzeniu, aby je skonfigurować" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Dodaj urządzenie" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Naciśnięcie klawisza 'Wybierz' podczas dołączania się do gry ustala której konfiguracji użyć" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Skórka" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Mapa" +msgid "Skin variant" +msgstr "Wariant skórki" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Podzielony ekran" +msgid "Minimap" +msgstr "Mapa" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Rozmiar czcionek" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Kamera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Zaawansowane..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Wyświetlaj FPS" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Pokaż bronie innych gokartów" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Włącz licznik trybu historii" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Włącz licznik Speedrun" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Rozdzielczość renderowania" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Poziom efektów graficznych" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Efekty rozmycia" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Maksymalne FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Zaawansowane..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Rozdzielczość" +msgid "Performance tests" +msgstr "Testy wydajności" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Pełny ekran" +msgid "Performance test of the current settings" +msgstr "Test wydajności bieżących ustawień" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Zapamiętaj położenie okna" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Zapamiętaj hasło" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Potwierdź nową rozdzielczość" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Usuń" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Kolor gokarta" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2385,15 +2527,15 @@ msgstr "Drużyna Niebieska" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Liczba okrążeń" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Liczba przeciwników" @@ -2408,33 +2550,17 @@ msgstr "Komputery w niebieskiej drużynie" msgid "Random Grand Prix" msgstr "Losowe Grand Prix" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Edytuj ulubione trasy" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Logowanie" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Zapamiętaj hasło" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Usuń" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Kolor gokarta" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Skórkę interfejsu można zmienić w opcjach" @@ -2553,238 +2679,306 @@ msgid "" msgstr "Nie wchodź w drogę kolegom z drużyny jadącym z piłką, możesz jednak próbować trafić przeciwników, powstrzymując ich przed zdobyciem bramki." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Rozdymka" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Morskie Głębiny" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Obcy Sygnał" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Labirynt Starożytnego Koloseum" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Miasto Candela" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Wojenna Wyspa" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Czarny Las" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Jaskinia X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Świątynia Kakao" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Pole Kukurydzy" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Fort Magma" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Rajska Wyspa" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Zrzut" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Lodowe Boisko" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Co się stało, mali hipisi? Wasz wielki przywódca Gnu zniknął?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "O tak, spójrz, jest teraz w moim zamku i zostanie podany na kolację..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Ale jestem uczciwym stworem, więc proponuję zakład." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Jeśli pokonasz mnie w wyścigu, uwolnię starego dziwaka." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " Ale wy, żałośni głupcy nigdy nie pokonacie mnie - Króla Gokartów!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Arena Las Dunas" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Stadion Las Dunas" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Dookoła Latarni Morskiej" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Stara Kopalnia" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oaza" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Klasa Matematyczna Olivera" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Park Dyniowy" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Dwór Ravenbridge" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Zmienne Piaski" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Staw Nessiego" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Północny Kurort" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Śnieżny Szczyt" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Boisko" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Stadion" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "Na Statku Kosmicznym" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Świątynia" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Wulkaniczna Wyspa" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Ogród Zen" @@ -2793,11 +2987,11 @@ msgstr "Ogród Zen" msgid "Completed achievement \"%s\"." msgstr "Ukończone osiągnięcie \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Nie można połączyć się z serwerem dodatków SuperTuxKart." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Błąd podczas pobierania aktualności: \"%s\"." @@ -2863,7 +3057,7 @@ msgid "New kart '%s' now available" msgstr "Nowy gracz '%s' już dostępny" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2895,32 +3089,32 @@ msgid "" "created." msgstr "Plik konfiguracyjny za stary. Usuwanie i tworzenie nowego." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Rozpoczęto nagrywanie wideo." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Wideo zapisane w \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Postęp kodowania:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Wskazówka: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Ładowanie" @@ -2942,19 +3136,18 @@ msgstr "Wydajność nitro" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (z utrudnieniem)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s jest gotowy" @@ -3428,21 +3621,21 @@ msgid "Axis %d" msgstr "Oś %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Przycisk gamepada %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Przycisk myszy %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Oś myszy %d %s" @@ -3616,26 +3809,30 @@ msgstr "Możesz mieć co najwyżej 3 życia!" msgid "+1 life." msgstr "+1 życie" -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Byłeś zbyt wolny!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Ukończyłeś wyścig!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Wygrałeś wyścig!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Ukończyłeś wyścig na %d miejscu!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s opuścił grę." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3644,16 +3841,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart może łączyć się z serwerem w celu pobrania dodatków oraz powiadamiania o aktualizacjach. Zapoznaj się z naszą polityką prywatności na https://supertuxkart.net/Privacy. Czy chcesz, żeby ta opcja była włączona? Aby zmienić to ustawienie później, edytuj pole \"Połącz się z siecią\" w zakładce \"Ogólne\"." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Twoja rozdzielczość ekranu jest zbyt niska, aby uruchomić grę." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Twój sterownik karty graficznej jest przestarzały. Zainstaluj najnowszą wersję." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3661,38 +3858,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Sterownik karty graficznej wygląda na bardzo stary. Sprawdź czy jest dostępna aktualizacja. SuperTuxKart działa najlepiej ze sterownikiem wspierającym co najmniej %s. Gra powinna wciąż działać, ale w trybie z ograniczoną grafiką." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Upłynął limit czasu połączenia z serwerem." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s ma czerwoną flagę!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Czerwona flaga powróciła!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s ma niebieską flagę!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Niebieska flaga powróciła!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s zdobył niebieską flagę!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s zdobył czerwoną flagę!" @@ -3702,7 +3899,7 @@ msgstr "%s zdobył czerwoną flagę!" msgid "Eggs: %d / %d" msgstr "Pisanki: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Lider" @@ -3710,22 +3907,22 @@ msgstr "Lider" msgid "Final lap!" msgstr "Ostatnie okrążenie!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Okrążenie nr %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s, autor: %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Najszybsze okrążenie!" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "ZŁA DROGA!" @@ -3739,7 +3936,7 @@ msgstr "%s zdobył bramkę!" msgid "Oops, %s made an own goal!" msgstr "Ups, %s strzelił samobója!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" @@ -3748,187 +3945,187 @@ msgstr[1] "%i zapasowe koła zostały utworzone!" msgstr[2] "%i zapasowych kół zostało utworzonych!" msgstr[3] "%i zapasowych kół zostało utworzonych!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Zostałeś wyeliminowany!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "'%s' został wyeliminowany." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Serwer został zamknięty." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Zostałeś wyrzucony z serwera." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Zostałeś wyrzucony: zbyt wysoki ping." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Wykryto złe połączenie." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s rozłączył się." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Wybierz nazwę gracza na liście, aby zarządzać graczem i zobaczyć informację o rankingu." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Poziom trudności: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Maksymalna liczba graczy: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Tryb gry: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Limit czasu" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Limit bramek" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Piłka nożna - rodzaj gry: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Postęp Grand Prix: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Wszyscy gracze dołączyli do czerwonej lub niebieskiej drużyny." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Jesteś teraz właścicielem serwera." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Połączenie odrzucone: Serwer jest zajęty." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Połączenie odrzucone: Zostałeś zbanowany na tym serwerze." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Połączenie odrzucone: Hasło serwera jest niepoprawne." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Połączenie odrzucone: Dane gry są niekompatybilne." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Połączenie odrzucone: Serwer jest pełny." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Połączenie odrzucone: nieuwierzytelniony gracz." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Nie udało się uruchomić gry sieciowej." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Gra zakończyła się, nie możesz już dołączyć ani obserwować." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Nie ma wystarczająco dużo miejsca na arenie - dołączanie nieaktywne" #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Pozostał tylko 1 gracz, powrót do pokoju." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Właściciel serwera opuścił grę." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Będziesz obserwował następną grę." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s dołączył do czerwonej drużyny." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s dołączył do niebieskiej drużyny." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s dołączył do gry." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3936,15 +4133,15 @@ msgid "" msgstr "Naciśnij <%s> lub <%s> aby zmienić obserwowanego gracza, <%s> lub <%s> aby zmienić kamerę." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "Pomyślnie zgłoszono %s." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3975,38 +4172,38 @@ msgstr "Czasówka (Grand Prix)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Każdy na Każdego" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Zdobądź Flagę" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s jest dostępny" -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s i %s są dostępni" -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s i %s są dostępni" #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4016,12 +4213,12 @@ msgstr[2] "%d przyjaciół jest dostępnych" msgstr[3] "%d przyjaciół jest dostępnych" #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s jest teraz na serwerze \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4030,7 +4227,7 @@ msgstr[1] "Otrzymałeś %d nowe zaproszenia!" msgstr[2] "Otrzymałeś %d nowych zaproszeń!" msgstr[3] "Otrzymałeś %d nowych zaproszeń!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Otrzymałeś nowe zaproszenie!" @@ -4059,12 +4256,12 @@ msgid "" msgstr "Plik wyników jest za stary.\nObecne wyniki zostaną usunięte." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Śledź Lidera" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Walka 3 Walnięć" @@ -4077,93 +4274,88 @@ msgstr "Niekompletny plik powtórki nie zostanie zapisany." msgid "Replay saved in \"%s\"." msgstr "Powtórka zapisana w \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "Tydzień" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 tygodnie" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "Miesiąc" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 miesiące" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 miesięcy" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 miesięcy" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "Rok" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 lata" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Nazwa dodatku" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Data aktualizacji" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Nie zainstalowany" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s, autor: %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Proszę czekać, dodatki się aktualizują" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Przepraszamy, nie można się połączyć z serwerem dodatków. Sprawdź czy jesteś podłączony do internetu i czy Twój firewall nie blokuje SuperTuxKart." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Ulubione" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Zablokowane: ukończ aktywne wyzwania, aby otrzymać więcej!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Przypadkowa arena" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d arena niedostępna w trybie dla jednego gracza." -msgstr[1] "%d areny niedostępne w trybie dla jednego gracza." -msgstr[2] "%d aren niedostępnych w trybie dla jednego gracza." -msgstr[3] "%d aren niedostępnych w trybie dla jednego gracza." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nDeve, 2015\nDeve, 2015-2021\nJakub Fabijan, 2021\nJakub Wojtkowiak, 2016,2021\nMarcin Węclewski, 2022\nmrkubax10 _, 2022\nPatryk Wychowaniec, 2015-2016\nTomek Woźniak, 2019\nDeve, 2016-2021\nAuria\nBill\nDawid Gan\nKuba Polankowski\nPatryk Wychowaniec\nSTK-team\nTwojwujaszek" @@ -4451,7 +4643,7 @@ msgstr "Zebrane banany" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Poślizg" @@ -4554,7 +4746,7 @@ msgstr "Ukończone Polowania Na Pisanki" msgid " (official tracks matching the goal)" msgstr "(oficjalne trasy spełniające cel)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4562,91 +4754,95 @@ msgid "" msgstr "Nowe gamepady i joysticki automatycznie pojawią się na liście, gdy podłączysz je do tego urządzenia.\n\nAby dodać ustawienia klawiatury, użyj przycisku poniżej, JEDNAKŻE pamiętaj, że większość klawiatur obsługuje tylko limitowaną ilość wciśniętych klawiszy, więc nie nadaje się do gier dla wielu graczy. (Możesz jednak podłączyć kilka klawiatur. Pamiętaj, że wtedy każdy musi mieć inne ustawienia klawiszy)." #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Dodaj konsolę Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Dodaj konfigurację klawiatury" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Aktualizacja" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Wersja: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "zalecane" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Rozmiar: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Musisz być zalogowany żeby ocenić ten dodatek." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Pobieranie nie powiodło się" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Problemy z instalacją dodatku '%s'" -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Spróbuj ponownie" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Problemy z usunięciem dodatku '%s'" -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Pobieranie w tle zakończone." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Pobieranie w tle" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Pobieranie w tle zostało już rozpoczęte." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Aktualne hasło jest niepoprawne" -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Hasło musi zawierać od 8 do 30 znaków!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Hasła się nie zgadzają!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Sprawdzanie poprawności danych" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Hasło zostało zmienione." @@ -4669,67 +4865,97 @@ msgstr "Rozdzielczości mniejsze niż 1024x768 lub 1280x720 nie są wspierane. N #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Widok z góry" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Niestandardowe" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Wyłączone" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Tylko ważne" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Bardzo niskie" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Niskie" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Średni" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Wysokie" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Bardzo wysokie" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4737,7 +4963,7 @@ msgid "" msgstr "SuperTuxKart pobierze pełne zasoby gry (wysokiej jakości tekstury i muzykę) dla lepszych wrażeń z gry. Jeśli nie masz połączenia z siecią wifi, zostanie użyta mobilna transmisja danych." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4754,101 +4980,102 @@ msgstr "Wpisz adres serwera, opcjonalnie podając numer portu po dwukropku, lub msgid "Invalid server address: %s." msgstr "Nieprawidłowy adres serwera: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Odwrotnie" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Trudność" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Okrąż." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Czas" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Gokart" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Gracz" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Wersja" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Nie" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Trasa" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "%d najlepszych rekordów" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Liczba gokartów: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Cel czasowy: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Okrążenia: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Odwrotnie: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Pusty)" @@ -4936,33 +5163,41 @@ msgid "Press any key..." msgstr "Naciśnij dowolny klawisz..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Czat jest wyłączony, możesz go włączyć w opcjach." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Wróć do Testu Wydajności" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Opuść Test Wydajności" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Powrót do bitwy" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Nowa gra" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Powtórz bitwę" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Wyjście z bitwy" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Nowy wyścig" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Wyjście z wyścigu" @@ -4978,11 +5213,11 @@ msgstr "%s nie ma jeszcze rankingu." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s jest na %d miejscu w rankingu z liczbą punktów %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Nazwa użytkownika lub adres e-mail jest niepoprawny." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5004,7 +5239,7 @@ msgstr "Wyścig z duchem" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Okrążenia: %i" @@ -5017,21 +5252,21 @@ msgstr "Typ: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Wymagane miejsce: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Wymagany czas: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Wymagana ilość nitro: %i" @@ -5044,54 +5279,54 @@ msgstr "Liczba przeciwników: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Bitwa" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Piłka nożna - rodzaj gry" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Lokalizacja serwera: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Aktualna trasa: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Miejsce" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Gracz" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Punkty" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Czas gry" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Usuń z zakładek" @@ -5104,74 +5339,74 @@ msgid "No player available for connecting to server." msgstr "Nie ma dostępnych graczy do połączenia z serwerem." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Nazwa użytkownika: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Anuluj zaproszenie" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Dzisiaj" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Zaproszenie wysłane!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Zaproszenie zaakceptowane!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Zaproszenie odrzucone!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Przyjaciel usunięty!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Zaproszenie anulowane!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Przetwarzanie" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Pobieranie ostatniej oceny" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Możesz zmienić swoją poprzednią ocenę klikając na gwiazdki poniżej." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Nie oceniałeś jeszcze tego dodatku. Możesz to zrobić klikając na gwiazdki poniżej." -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Głosowanie powiodło się. Możesz teraz zamknąć okno." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Dokonywanie oceny" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Przypadkowa trasa" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5200,7 +5435,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Wystąpił błąd podczas próby zapisu Grand Prix" -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Wybierz trasę" @@ -5244,12 +5479,12 @@ msgstr "Odblokowałeś trasę %0" msgid "You unlocked grand prix %0" msgstr "Odblokowałeś Grand Prix %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Trasa" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5270,19 +5505,19 @@ msgstr "Wpisz nazwę Grand Prix" msgid "Please select a Grand Prix" msgstr "Wybierz Grand Prix" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Użytkownika" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Imię jest puste" -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Istnieje już inne Grand Prix o takiej nazwie" -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Nazwa jest zbyt długa." @@ -5291,19 +5526,19 @@ msgstr "Nazwa jest zbyt długa." msgid "Better luck next time!" msgstr "Powodzenia następnym razem!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Ukończono wyzwanie!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Wygrałeś Grand Prix!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Ukończono Grand Prix!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Liczba gokartów" @@ -5316,110 +5551,125 @@ msgstr "Czy na pewno chcesz usunąć ten rekord?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Czy na pewno chcesz usunąć wszystkie twoje rekordy?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Ulubiony" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Lekki" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Ciężki" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Podłącz klawiaturę lub gamepad, aby zagrać w trybie z podzielonym ekranem." -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Przypadkowy kart" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Zablokowane" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Naciśnij 'Wybierz' aby dołączyć do gry!" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Czy chciałbyś uruchomić tutorial gry?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Nie możesz grać online bez dostępu do sieci. Jeśli chcesz grać online, zaznacz pole \"Połącz się z siecią\" w opcjach gry." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Nie możesz pobierać dodatków bez dostępu do sieci. Jeśli chcesz pobierać dodatki, zaznacz pole \"Połącz się z siecią\" w opcjach gry." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Nie możesz pobierać dodatków bez dostępu do sieci. Jeśli chcesz pobierać dodatki, zaznacz pole \"Połącz się z siecią\" w opcjach gry.\n\nMożesz jednak usunąć już pobrane dodatki." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Dodatki są aktualnie wyłączone w opcjach." -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Proszę czekać, dodatki są ładowane." -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Czy na pewno chcesz wyjść z STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Utwórz serwer LAN" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Serwer %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Liczba tras Grand Prix" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Imię musi zawierać od 4 do 30 znaków!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Hasło zawiera nieprawidłowe znaki!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Gotowy" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Dołącz" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Obserwuj" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Zainstaluj dodatek" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5427,7 +5677,7 @@ msgstr "Proszę czekać do zakończenia aktualnej gry (%s), szacowany pozostały #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Proszę czekać do zakończenia aktualnej gry, szacowany pozostały czas: %s." @@ -5435,24 +5685,24 @@ msgstr "Proszę czekać do zakończenia aktualnej gry, szacowany pozostały czas #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Proszę czekać do zakończenia aktualnej gry (%s), szacowany postęp: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Proszę czekać do zakończenia aktualnej gry, szacowany postęp: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Proszę czekać do zakończenia aktualnej gry." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5463,7 +5713,7 @@ msgstr[3] "Gra rozpocznie się gdy dołączy więcej niż %d graczy." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5474,96 +5724,108 @@ msgstr[1] "Rozpoczęcie po %d sekundach, lub gdy wszyscy wcisną przycisk \"Goto msgstr[2] "Rozpoczęcie po %d sekundach, lub gdy wszyscy wcisną przycisk \"Gotowy\"." msgstr[3] "Rozpoczęcie po %d sekundach, lub gdy wszyscy wcisną przycisk \"Gotowy\"." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Łączenie z serwerem %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Znajdowanie serwera dla szybkiej gry." #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Pozostały czas: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Cele" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Pobieranie osiągnięć" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Profil %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Od" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Stan" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Pobieranie listy przyjaciół" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Nowe zaproszenie" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Oczekiwanie" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Niedostępny" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Wpisz adres e-mail poniżej" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Nowy adres e-mail musi mieć długość od 5 do 254 znaków." -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Nowy adres e-mail jest nieprawidłowy!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "Adres e-mail został zmieniony!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Nie udało zmienić się adresu e-mail: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Wiadomości z Blogu STK" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Data" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Aktualnie brak dostępnych wiadomości." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Musisz być zalogowany aby grać w sieci globalnej. Kliknij nazwę swojego użytkownika powyżej." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Wyszukiwanie" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Wyjdź z gry" @@ -5641,34 +5903,34 @@ msgid "Distance (km)" msgstr "Odl. (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Nieznany" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Nie wykryto IPv4, możesz nie być w stanie połączyć się z żadnym serwerem." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Nie wykryto IPv6, możesz nie być w stanie połączyć się z żadnym serwerem." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Nie ma dostępnych serwerów." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Pobieranie serwerów" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Zakładki serwerów" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5676,149 +5938,149 @@ msgstr "Jeśli większość graczy wybierze tą samą trasę i ustawienia wyści #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Losowe rozmieszczenie przedmiotów" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Liczba bramek, aby wygrać" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Przeciwny kierunek" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Zablokowane: ukończ aktywne wyzwania, aby otrzymać więcej!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Akcja" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Przypisanie klawiszy" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Wyłącz urządzenie" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Włącz urządzenie" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Włącz konfigurację" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Klawisze gry" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Klawisze menu" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Skręt w lewo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Skręt w prawo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Przyspieszacz" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Hamulec / Cofanie" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Ognia" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Spojrzenie w tył" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Ratunek" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Pauza" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Góra" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Dół" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Lewo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Prawo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Wybór" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Anuluj/Powróć" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "Niebieski obiekt może być przyczyną konfliktów pomiędzy konfiguracjami." -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Czerwone pole oznacza konflikt w aktualnych ustawieniach" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5826,17 +6088,27 @@ msgid "" msgstr "Uwaga! Klawisz 'Shift' nie jest zalecany. Kiedy Shift jest wciśnięty, wszystkie klawisze, które zawierają inny znak górny, przestaną działać." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Czy na pewno chcesz na stałe usunąć tę konfigurację?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Wpisz nową nazwę konfiguracji. Pozostaw puste, aby przywrócić domyślną wartość." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Pionowo" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Poziomo" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5844,89 +6116,74 @@ msgstr "W trybie dla wielu graczy można wybrać profile \nz utrudnieniami w ekr #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Zainstaluj pełne zasoby gry" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Na pewno chcesz odinstalować pełne zasoby gry?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Klawiatura %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Urządzenie dotykowe" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Naciśnij na urządzenie, aby je skonfigurować" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Język Systemu" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Na dole po lewej" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "Po prawej" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Ukryty" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Na środku" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Pionowo" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Poziomo" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Bardzo mały" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Mały" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Średni" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Duży" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Bardzo duży" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5936,128 +6193,133 @@ msgid "" msgstr "Tryb Speedrun może zostać włączony, jeśli gra nie została zamknięta od czasu włączenia trybu historii.\n\nZamknięcie gry przed ukończeniem trybu historii unieważnia licznik.\n\nAby użyć trybu Speedrun, utwórz nowy profil." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Synchronizacja pionowa" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Synchronizacja pionowa wymusza wysyłanie nowej ramki\ndopiero gdy monitor jest gotowy, żeby ją wyświetlić." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Synchronizacja pionowa nie będzie działać, jeśli \nnie jest obsługiwana przez sterownik." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Efekty cząsteczkowe: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Animowane postacie: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Dynamiczne oświetlenie: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Rozpraszanie światła: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Wygładzanie krawędzi: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Cieniowanie powierzchni: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Cienie: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Cienie: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Poświata: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Poświata (kontury): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Promienie światła: %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Jakość obrazu: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Szczegóły modeli: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Rozmycie ruchu: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Głębia ostrości: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Dostęp do sieci jest nieaktywny. Czy chesz go włączyć?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Musisz wpisać hasło." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Wylogowywanie '%s'" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Logowanie '%s'" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Nie możesz usunąć jedynego gracza." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Czy na prawdę chcesz usunąć gracza: %s?" @@ -6085,7 +6347,7 @@ msgstr "BRAMKA!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Oczekiwanie na innych" @@ -6120,7 +6382,7 @@ msgstr "Śledź Lidera!" msgid "Top %i" msgstr "Top %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Wyzwanie nie powiodło się" @@ -6144,102 +6406,199 @@ msgstr "Naciśnij ikonę podium, aby zacząć wyzwanie." msgid "Press fire to start the challenge" msgstr "Naciśnij 'Ognia', aby rozpocząć wyzwanie" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Wróć do ustawień grafiki" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Zapisz wyniki testu" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Wróć do menu głównego" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Opuść serwer." -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Zakończ Grand Prix" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Ponowny start" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Powrót do wyboru wyzwania" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Graj z nowym duchem" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Powrót do menu" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Czy na pewno chcesz opuścić Grand Prix?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Raport wydajności zapisany w \"%s\"." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Wygrywa drużyna czerwona" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Wygrywa drużyna niebieska" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Remis" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Wyeliminowany po %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Odpada" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Własny)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Trasa %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Postęp Grand Prix:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Najlepsze wyniki" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Najlepsze okrążenie: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "autor %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Ukończono wyzwanie!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Nie udało się ukończyć wyzwania!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Osiągnięto wymagania SuperTux'a" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Wyniki Testu Wydajności" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Długość testu: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Liczba klatek: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "Stabilne FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "Przeważnie stabilne FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "Typowe FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Rozdzielczość pozioma: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Rozdzielczość pionowa: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Dynamiczne oświetlenie: Wł" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Dynamiczne oświetlenie: Wył" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Rozdzielczość renderowania: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Wygładzanie krawędzi: WŁ" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Wygładzanie krawędzi: WYŁ" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Oświetlenie IBL: WYŁ" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Oświetlenie IBL: WŁ" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Cieniowanie powierzchni: WŁ" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Cieniowanie powierzchni: WYŁ" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Rozdzielczość cieni: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Wszystkie ciosy są dozwolone, więc weź broń i zrób z niej użytek!" @@ -6280,28 +6639,28 @@ msgstr "Naciśnij ikonę z czerwoną lub niebieską piłką, aby zmienić druży #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Autor trasy: %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Maksymalna liczba graczy: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Komputery w czerwonej drużynie" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Nie możesz zagrać tego Grand Prix, ponieważ zawiera nieodblokowane trasy." -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Zablokowane!" @@ -6323,10 +6682,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Ukończ wszystkie wyzwania, aby otworzyć bramę!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6335,41 +6696,48 @@ msgid "" msgstr "Potrzebujesz więcej \npunktów aby rozpocząć\nto wyzwanie. Zobacz\ndostępne wyzwania\nna mapie." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Przyspiesz używając <%s> i skręcaj za pomocą <%s> i <%s>\"" #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Przyspiesz dotykając górnej części kierownicy i skręcaj przesuwając ją w lewo lub w prawo." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Przyspiesz przesuwając drążek w górę i skręcaj przechylając swoje urządzenie." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Przyspiesz przesuwając drążek w górę i skręcaj obracając swoje urządzenie." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Zbierz prezenty i wystrzel broń używając <%s> aby pozbyć się tych skrzyni!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Zbierz prezenty i wystrzel broń używając ikony z kulą, aby pozbyć się tych skrzyni!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6377,34 +6745,41 @@ msgid "" msgstr "Wciśnij <%s> aby spojrzeć w tył, a następnie wciśnij <%s> ciągle trzymając <%s>, aby strzelić za siebie!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Naciśnij ikonę z lusterkiem, aby spojrzeć w tył. Wystrzej broń do tyłu przyciskając ikonę lusterka, a następnie przesuwając na ikonę z kulą do kręgli." #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Użyj zebranego nitro naciskając <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Użyj zebranego nitro naciskając ikonę z nitro!" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Zbierz butelki z nitro (użyjemy ich za zakrętem)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Ups! Mamy kłopoty, wciśnij <%s> aby zawołać pomoc." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Ups! Mamy kłopoty, wciśnij ikonę z ptakiem, aby zawołać pomoc." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6412,24 +6787,27 @@ msgid "" msgstr "Przyspiesz i podczas skręcania wciśnij <%s> aby się ślizgać. Chwilowe ślizganie może pomóc Ci szybciej się obrócić, aby pokonać ostre zakręty." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Przyspiesz i podczas skręcania wciśnij ikonę ślizgania, aby się ślizgać. Chwilowe ślizganie może pomóc Ci szybciej się obrócić, aby pokonać ostre zakręty." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Zauważ, że jeśli uda Ci się ślizgać przez kilka sekund, otrzymasz bonusowe przyspieszenie jako nagrodę!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Jesteś gotowy do wyścigu. Powodzenia!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Trójwymiarowe wyścigi gokartów open-source" @@ -6439,7 +6817,7 @@ msgstr "Trójwymiarowe wyścigi gokartów open-source" msgid "tux;game;race;" msgstr "tux;gra;wyścigi;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6447,7 +6825,7 @@ msgid "" "for all ages." msgstr "Gokarty. Nitro. Akcja! SuperTuxKart to trójwymiarowa zręcznościowa gra wyścigowa open-source z wieloma postaciami, trasami i trybami gry. Naszym celem jest stworzenie gry, która będzie bardziej zabawna niż realistyczna i zapewni przyjemne wrażenia dla wszystkich grup wiekowych." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6456,7 +6834,7 @@ msgid "" "your opponents." msgstr "Mamy dla graczy kilka torów z różnymi motywami, od jazdy pod wodą, przez wiejskie pola uprawne, dżungle, a nawet w kosmosie! Postaraj się jechać jak najlepiej, unikając innych gokartów, ponieważ mogą cię wyprzedzić, ale nie jedz bananów! Uważaj na kule do kręgli, odtykaczki, gumę balonową i ciastka rzucane przez przeciwników. " -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6465,27 +6843,27 @@ msgid "" "your racing skills!" msgstr "Możesz rozegrać pojedynczy wyścig z innymi gokartami, wziąć udział w jednym z kilku Grand Prix, spróbować pobić swój najwyższy wynik w próbach czasowych, zagrać w trybie bitwy z komputerem lub znajomymi i nie tylko! Dla większych wyzwań dołącz do gry online, poznaj graczy z całego świata i pokaż swoje umiejętności wyścigowe!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Gra nie zawiera reklam." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "To jest niestabilna wersja SuperTuxKart, która zawiera najnowsze poprawki. Jest wydawana głównie do testów, aby stabilna wersja STK była jak najlepsza." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Ta wersja może być zainstalowana równolegle z wersją stabilną na tym samym urządzeniu." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Jeśli oczekujesz większej stabilności, możesz użyć wersji stabilnej: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "SuperTuxKart Team" diff --git a/data/po/pt.po b/data/po/pt.po index 679651c09fe..4f2c8b27dcf 100644 --- a/data/po/pt.po +++ b/data/po/pt.po @@ -10,7 +10,7 @@ # Daniel Luiz Lorenzi , 2022 # FIRST AUTHOR , 2010 # Hugo Carvalho , 2024 -# João Frade <100nome.portugal@gmail.com>, 2023-2024 +# João Frade <100nome.portugal@gmail.com>, 2023-2025 # Pedroxz , 2017 # Pedroxz , 2017 # Pedroxz , 2017 @@ -20,9 +20,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: João Frade <100nome.portugal@gmail.com>, 2023-2024\n" +"Last-Translator: João Frade <100nome.portugal@gmail.com>, 2023-2025\n" "Language-Team: Portuguese (http://app.transifex.com/supertuxkart/supertuxkart/language/pt/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -179,7 +179,7 @@ msgstr "Nos Confins do Mundo" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Voltar" @@ -201,7 +201,7 @@ msgstr "Seleciona o tipo de controlo que preferes" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Acelerómetro" @@ -215,13 +215,13 @@ msgstr "Acelerómetro" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Giroscópio" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Volante" @@ -252,35 +252,37 @@ msgstr "Definições de Dispositivo de Toque" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Geral" @@ -348,30 +350,33 @@ msgstr "Restaurar padrão" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Cancelar" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Sim" @@ -486,7 +491,7 @@ msgstr "Desfoque de movimento" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Image-based lighting" -msgstr "Luz baseada em imagem" +msgstr "Iluminação baseada em imagem" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -549,9 +554,9 @@ msgstr "Entrar" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -612,7 +617,7 @@ msgstr "Objetivo" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Progresso" @@ -647,7 +652,7 @@ msgstr "Submeter" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Voltar à Corrida" @@ -664,7 +669,7 @@ msgstr "Voltar ao Átrio" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Reiniciar Corrida" @@ -728,12 +733,12 @@ msgstr "Preenche com o nome de utilizador e endereço de e-mail que introduziste #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Nome de utilizador" @@ -774,7 +779,7 @@ msgstr "Dificuldade" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Principiante" @@ -786,7 +791,7 @@ msgstr "Principiante" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Intermédio" @@ -798,7 +803,7 @@ msgstr "Intermédio" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Perito" @@ -810,7 +815,7 @@ msgstr "Perito" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -818,8 +823,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Modo de jogo" @@ -830,8 +835,8 @@ msgstr "Modo de jogo" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Corrida Normal" @@ -844,7 +849,7 @@ msgstr "Corrida Normal" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Contrarrelógio" @@ -852,7 +857,8 @@ msgstr "Contrarrelógio" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Batalha" @@ -861,24 +867,24 @@ msgstr "Batalha" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Futebol" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Palavra-passe" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Marcar este servidor" @@ -889,7 +895,7 @@ msgstr "Adicionar jogador" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Nome" @@ -983,6 +989,50 @@ msgstr "Atribuir à tecla ESC" msgid "Assign nothing" msgstr "Não atribuir nada" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Definições gráficas recomendadas" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "As definições recomendadas serão válidas para a resolução atual." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "O que devem as definições priorizar?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Desempenho" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Equilibrar o desempenho e a qualidade gráfica" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Qualidade gráfica" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Poupança de energia" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Gostas de efeitos gráficos que criem desfoque?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Iniciar o teste" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -997,11 +1047,11 @@ msgstr "Configuração de Corrida" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Continuar" @@ -1042,10 +1092,15 @@ msgstr "Arenas" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Instalado" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Editar arenas favoritas" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1055,20 +1110,20 @@ msgstr "Instalado" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Padrão" @@ -1079,12 +1134,12 @@ msgstr "Padrão" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Extensões" @@ -1098,27 +1153,28 @@ msgstr "Extensões" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Tudo" @@ -1157,9 +1213,9 @@ msgstr "Mover para baixo" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Adicionar" @@ -1196,7 +1252,7 @@ msgstr "Seleção de Repetição Fantasma" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Caça aos Ovos" @@ -1243,10 +1299,10 @@ msgstr "Sentido inverso" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Tempo máximo (minutos)" @@ -1278,9 +1334,9 @@ msgstr "Copiar" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1291,80 +1347,80 @@ msgstr "Mudar nome" msgid "Save Grand Prix" msgstr "Guardar Campeonato" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Ajuda do SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Modos de Jogo" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Potenciadores" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Bananas" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1372,56 +1428,57 @@ msgstr "Bananas" msgid "Story Mode" msgstr "Modo História" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Classes de karts" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Multijogador" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Iniciar o tutorial" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Apanha presentes azuis, eles vão dar-te potenciadores." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Evita as bananas!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1429,14 +1486,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Apanhar nitro permite-te obter impulsos de velocidade quando quiseres premindo a tecla ou botão apropriados. Podes ver o teu nível atual de nitro no medidor do canto inferior direito durante a corrida." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Se vires um botão com um cadeado como este, terás de completar um desafio para desbloqueá-lo." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1445,34 +1502,34 @@ msgid "" "carefully before!" msgstr "Podes derrapar premindo uma tecla ou botão especiais. Sucessivas derrapagens curtas ajudam a fazer curvas apertadas; enquanto que derrapagens médias impulsionam a tua velocidade e longas ainda mais. Não podes parar de virar durante a derrapagem, por isso orienta o teu kart com cuidado antes de saíres da curva!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Podes ganhar um impulso inicial premindo o botão de acelerar em \"Preparar!\", antes do começo da corrida." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* As atuais atribuições de teclas podem ser vistas/alteradas no menu Opções" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "O SuperTuxKart tem vários modos de jogo:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Corrida Normal: todo o golpe é lícito, por isso apanha potenciadores e usa-os com cabeça!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Contrarrelógio: não há potenciadores, só o teu talento ao volante conta!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1480,7 +1537,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Seguir o Líder: disputa o segundo lugar, porque o último kart será desqualificado sempre que o cronómetro chega ao zero. Atenção: ir à frente do líder também te vai eliminar!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1490,30 +1547,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Existem 3 tipos de Batalha: em Batalha de 3 Vidas, tens de atingir os outros com armas até ficarem sem vidas. Em Todos Contra Todos, o jogador que golpear mais os outros vence, num dado limite de golpes ou tempo. Em Capturar a Bandeira, tu e a tua equipa têm de trazer a bandeira da equipa adversária até à vossa base, desde que a vossa bandeira não seja capturada pela outra equipa." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Futebol: usa o teu kart para empurrar a bola para a baliza adversária e marcar golos." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Caça aos Ovos: explora as pistas e encontra todos os ovos escondidos." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Corrida Contra Fantasma: corre contra repetições fantasma de Contrarrelógio ou Caça aos Ovos e grava as tuas próprias!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Resistência: completa o máximo de voltas possível num dado tempo." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1522,93 +1579,93 @@ msgid "" "wins the cup." msgstr "* Muitos destes modos também podem ser jogados em formato de Campeonato: em vez de jogar uma corrida única, jogas várias de seguida. Quanto melhores as tuas posições finais, mais pontos ganhas. No fim, o jogador com mais pontos ganha a taça." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Para te ajudar a ganhar, aqui estão alguns potenciadores que podes apanhar:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Pastilha Elástica - protege-te com um escudo ou utiliza-a enquanto olhas à retaguarda para deixares uma poça rosa pegajosa atrás de ti." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Zarpador - dá-te um grande impulso de velocidade. Mas cuidado para não perderes o controlo do teu kart!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Bolo - dispara contra o rival mais próximo; é melhor em distâncias curtas e retas compridas. Também afeta outros karts próximos da explosão." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Desentupidor - dispara-o em frente para puxares um adversário para trás ou dispara à retaguarda para cegares alguém." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Bola de Bólingue - vai em linha reta até atingir alguém. A bola faz ricochete nas paredes. Se estiveres a olhar à retaguarda, ela será lançada para trás." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Paraquedas - abranda todos os karts à tua frente." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Alternador - presentes são transformados em bananas e garrafas de nitro em pastilhas elásticas, e vice-versa, por um curto período de tempo." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Bola de Basquete - saltita atrás do líder e pode esmagar e abrandar karts pelo caminho." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Mata-Moscas - esmaga os karts próximos, abrandando-os. Também pode ser usado para remover paraquedas e bombas." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Apanhar uma banana pode resultar num dos seguintes efeitos no kart:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Âncora - abranda repentinamente o kart." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Paraquedas - abranda o kart de forma mais progressiva que a âncora. Quanto mais rápido fores, mais te abrandará." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bomba - explode após algum tempo, atirando o kart ao ar. Bate contra outro kart para transferires a bomba para ele." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "O malvado Nolok capturou Gnu! Aqui estão algumas dicas para te ajudar:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1617,7 +1674,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Este ícone no minimapa mostra os desafios disponíveis que não completaste. No canto superior direito do ecrã, também mostra os pontos que tens atualmente. Completa o máximo de desafios possível e Nolok aceitará correr contra ti. Vence para libertares Gnu!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1625,20 +1682,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Quando completas um desafio, ganhas uma taça. Cada taça vale vários pontos. Quanto maior for a dificuldade do desafio concluído, melhor será a taça e mais pontos valerá." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Quando consegues o número de pontos indicado abaixo deste ícone, és presenteado com uma surpresa. Existem várias para colecionar." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Nem todos os karts se pilotam igual! Eles pertencem a classes com várias diferenças:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1646,7 +1703,7 @@ msgid "" " resistant to explosions." msgstr "Peso - existem três classes de karts tendo em conta o seu peso: leve, médio e pesado. Os karts mais pesados são menos afetados por paraquedas e são mais resistentes a explosões." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1654,7 +1711,7 @@ msgid "" " especially at low speeds." msgstr "Aceleração - particularmente útil no momento de Partida, após um acidente ou em pistas com muitas curvas apertadas. Quanto mais leve for o kart, mais rápido ele acelera, especialmente a baixas velocidades." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1662,14 +1719,14 @@ msgid "" " top speed." msgstr "Velocidade máxima - quanto maior, mais rápido o kart pode ir. É útil em pistas com linhas retas e curvas suaves. Os karts mais pesados têm maior velocidade máxima." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Eficiência do nitro - quanto maior for, maior será o impulso que obterás de uma garrafa de nitro. Um kart mais leve terá uma eficiência de nitro maior." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1677,12 +1734,12 @@ msgid "" "easier it is." msgstr "Se seguires de perto outro kart por alguns segundos, receberás um impulso de cone de ar bónus ao ultrapassá-lo. Quanto mais leve for o teu kart, mais fácil será fazê-lo." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart pode ser jogado no modo multijogador online...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1692,7 +1749,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Primeiro, seleciona o ícone 'Online' no menu inicial. Escolhe entre rede local ou rede global (requer que a Internet esteja ativada nas Opções). Depois poderás tanto criar o teu próprio servidor com opções personalizadas como escolher de entre uma lista de servidores existentes para te juntares. Alguns deles são servidores recomendados com a opção de corridas para Classificação." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1702,12 +1759,12 @@ msgid "" "players and the server." msgstr "Entrando num servidor, uma corrida iniciará quando o dono (indicado por uma coroa) o decidir. Servidores oficiais apenas poderão autoiniciá-la assim que houver jogadores suficientes. A seguir, poderás escolher o teu kart e votar na próxima pista a correr. Uma pista de extensão só é permitida se todos os jogadores no servidor a tiverem." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... ou no mesmo dispositivo:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1717,7 +1774,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Primeiro necessitarás de vários dispositivos de entrada. Usa o menu Controlos, nas Opções, para os configurares. Múltiplos comandos de jogo ou joysticks é o ideal: com teclado(s), cada jogador necessitará de um conjunto diferente de teclas, e a maioria dos teclados não é apropriada para multijogador porque não suporta o uso de várias teclas em simultâneo." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1737,7 +1794,7 @@ msgstr "Seleção de Recordes" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Resistência" @@ -1745,9 +1802,9 @@ msgstr "Resistência" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Campeonato" @@ -1758,6 +1815,20 @@ msgstr "Campeonato" msgid "Choose a Kart" msgstr "Escolhe um Kart" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Classe de Karts" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Editar karts favoritos" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1771,11 +1842,11 @@ msgstr "Multijogador em Ecrã Dividido" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Online" @@ -1792,7 +1863,7 @@ msgstr "Tutorial" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Recordes" @@ -1800,7 +1871,7 @@ msgstr "Recordes" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Proezas" @@ -1854,30 +1925,30 @@ msgstr "Encontrar Servidor" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Criar Servidor" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Átrio" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Configuração" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Iniciar Corrida" @@ -1903,9 +1974,9 @@ msgstr "Introduzir endereço do servidor" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "O teu perfil" @@ -1923,7 +1994,7 @@ msgstr "Classificações de jogadores" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Amigos" @@ -1948,7 +2019,7 @@ msgstr "Jogo Rápido" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Definições da Conta" @@ -1998,8 +2069,8 @@ msgid "Online Username" msgstr "Nome de utilizador online" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Repor palavra-passe" @@ -2012,7 +2083,7 @@ msgid "" msgstr "Podes jogar sem criar uma conta online selecionando uma conta offline. Contudo, não poderás ligar-te a amigos, votar em extensões, etc. Por favor, lê a nossa política de privacidade em https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Seleção de Servidor" @@ -2030,339 +2101,409 @@ msgstr "Usar ligação IPv6" msgid "User search" msgstr "Procurar Utilizador" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Opções do SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Ecrã" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Gráficos" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Áudio" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Interface (IU)" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Jogadores" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Controlos" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Idioma" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Música" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Ativado" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Volume" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Efeitos Sonoros" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Eliminar Configuração" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Desativar Configuração" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "<= voltar à lista de dispositivos" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Renomear Configuração" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Ativar vibração (Force Feedback, se for suportado)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Resolução" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Ecrã inteiro" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Memorizar localização da janela" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Aplicar nova resolução" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Esquema de Multijogador em Ecrã Dividido" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Opções da Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Mostrar sempre o ecrã de início de sessão" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Ligar à Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Ativar conversação online" +msgid "Enable chatting in online lobbies" +msgstr "Ativar conversação em átrios online" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Ativar conversação em jogos online" +msgid "Enable chatting in online matches" +msgstr "Ativar conversação em partidas online" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Opções diversas" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Ativar desvantagem em jogadores" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Desinstalar recursos completos do jogo" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Prime Enter ou faz duplo clique num dispositivo para configurá-lo" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Adicionar dispositivo" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* A configuração a usar será assumida tendo em conta a tecla 'Selecionar' que for premida ao entrar no jogo." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Tema" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Minimapa" +msgid "Skin variant" +msgstr "Variante do tema" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Esquema de Multijogador em Ecrã Dividido" +msgid "Minimap" +msgstr "Minimapa" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Tamanho da fonte" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Câmara" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Personalizada..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Mostrar FPS" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Mostrar potenciadores dos outros karts" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Mostrar cronometragem do Modo História" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Ativar cronómetro para Speedrun" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Resolução da renderização" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Nível de efeitos gráficos" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Nível de efeitos de desfoque" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Limite de FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Definições personalizadas..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Resolução" +msgid "Performance tests" +msgstr "Testes de desempenho" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Ecrã inteiro" +msgid "Performance test of the current settings" +msgstr "Testar desempenho das definições atuais" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Memorizar localização da janela" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Lembrar palavra-passe" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Aplicar nova resolução" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Eliminar" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Cor do kart" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2389,15 +2530,15 @@ msgstr "Equipa Azul" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Número de voltas" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Número de karts IA" @@ -2412,33 +2553,17 @@ msgstr "Número de Karts IA na equipa azul" msgid "Random Grand Prix" msgstr "Campeonato Aleatório" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Editar pistas favoritas" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Entrar" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Lembrar palavra-passe" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Eliminar" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Cor do kart" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "O tema da interface pode ser mudado nas opções de IU." @@ -2557,238 +2682,306 @@ msgid "" msgstr "Não atrapalhes o teu colega de equipa se este estiver com a bola, mas poderás sempre atingir adversários que o tentam impedir de marcar." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Abismo Antediluviano" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Sinal Alienígena" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Labirinto do Antigo Coliseu" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Cidade de Candela" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Ilha da Batalha" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Floresta Negra" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Caverna Secreta" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Templo do Cacau" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Travessia do Milharal" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Fortaleza Magma" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Ilha Gran Paradiso" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Queda no Buraco" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Campo de Futebol Gelado" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Que é agora, seus hippiezinhos? O vosso grande líder gnu desapareceu?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Oh, sim. Vejam, ele está no meu castelo agora e será servido ao jantar..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Mas sou uma criatura justa, por isso proponho-vos um acordo." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Se me conseguirem vencer em corridas, eu liberto o velho ranzinza." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "Mas vocês, patéticos insignificantes, nunca me conseguirão vencer - Rei dos Karts!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Arena Las Dunas" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Estádio de Futebol Las Dunas" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "À Volta do Farol" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Mina Antiga" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolfe" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oásis" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Aula de Matemática do Oliver" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Parque das Abóboras" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Mansão Ravenbridge" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Areias Movediças" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Lagoa do Nessie" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Resort do Norte" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Pico de Neve" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Campo de Futebol" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Estádio" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "Empresa STK" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Templo" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Ilha do Vulcão" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Jardim Zen" @@ -2797,14 +2990,14 @@ msgstr "Jardim Zen" msgid "Completed achievement \"%s\"." msgstr "Proeza concluída \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Não foi possível ligar ao servidor de extensões do SuperTuxKart." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." -msgstr "Erro ao descarregar as notícias: '%s'." +msgstr "Erro ao descarregar as novidades: '%s'." #: src/challenges/challenge_data.cpp:303 src/network/server_config.cpp:261 msgid "Normal Race (Grand Prix)" @@ -2867,7 +3060,7 @@ msgid "New kart '%s' now available" msgstr "Novo kart '%s' já disponível" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2899,32 +3092,32 @@ msgid "" "created." msgstr "O ficheiro de configurações é antigo e por isso foi eliminado. Vai ser criado um novo." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Começou a gravação do vídeo." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Vídeo gravado em \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Processo de codificação:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Dica: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "A carregar" @@ -2946,19 +3139,18 @@ msgstr "Eficiência do nitro" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (em desvantagem)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s está pronto" @@ -3432,21 +3624,21 @@ msgid "Axis %d" msgstr "Eixo %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Botão %d do comando de jogo" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Botão %d do rato" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Eixo do rato %d %s" @@ -3619,26 +3811,30 @@ msgstr "Podes ter no máximo 3 vidas!" msgid "+1 life." msgstr "+1 vida." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Foste demasiado lento!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Terminaste a corrida!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Venceste a corrida!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Terminaste a corrida em %dº lugar!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s saiu do jogo." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3647,16 +3843,16 @@ msgid "" "Internet\")." msgstr "O SuperTuxKart poderá ligar ao servidor para descarregar extensões e notificar-te de atualizações. Lê a nossa política de privacidade em https://supertuxkart.net/Privacy. Gostarias de ativar esta função? (Para mudar esta opção mais tarde, vai a Opções, no separador 'Geral', e marca \"Ligar à Internet\".)" -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "A tua resolução do ecrã é demasiado baixa para correr o STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "A versão do controlador de vídeo que tens instalada é demasiado antiga. Por favor, instala os controladores de vídeo mais recentes." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3664,38 +3860,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "O teu controlador de gráficos parece ser muito antigo. Por favor, verifica se existe uma atualização disponível. O SuperTuxKart recomenda um controlador que suporte %s ou superior. É provável que o jogo ainda seja executado, mas num modo de gráficos reduzidos." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "A ligação ao servidor excedeu o tempo limite." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s tem a bandeira vermelha!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "A bandeira vermelha voltou à base!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s tem a bandeira azul!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "A bandeira azul voltou à base!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s capturou a bandeira azul!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s capturou a bandeira vermelha!" @@ -3705,7 +3901,7 @@ msgstr "%s capturou a bandeira vermelha!" msgid "Eggs: %d / %d" msgstr "Ovos: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Líder" @@ -3713,22 +3909,22 @@ msgstr "Líder" msgid "Final lap!" msgstr "Última volta!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Volta %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s por %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Nova volta mais rápida" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "SENTIDO ERRADO!" @@ -3742,7 +3938,7 @@ msgstr "%s marcou um golo!" msgid "Oops, %s made an own goal!" msgstr "Ups, %s marcou autogolo!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" @@ -3750,187 +3946,187 @@ msgstr[0] "Surgiu %i kart com pneus sobresselentes!" msgstr[1] "Surgiram %i karts com pneus sobresselentes!" msgstr[2] "Surgiram %i karts com pneus sobresselentes!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Foste eliminado!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "%s foi eliminado." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "O servidor foi desligado." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Foste expulso do servidor." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Foste expulso: o teu ping é demasiado alto." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Foi detetada uma má ligação de rede." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s desligou-se." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Clica num jogador da lista para gestão do jogador e infos de classificação." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Dificuldade: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Máximo de jogadores: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Modo de jogo: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Limite de tempo" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Limite de golos" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Tipo de partida de futebol: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Progresso do Campeonato: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Todos os jogadores se juntaram à mesma equipa." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Agora és o dono do servidor." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Ligação recusada: o servidor está ocupado." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Ligação recusada: estás banido do servidor." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Ligação recusada: palavra-passe do servidor incorreta." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Ligação recusada: os dados do jogo são incompatíveis." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Ligação recusada: o servidor está cheio." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Ligação recusada: jogador inválido a ligar." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Não foi possível iniciar o jogo online." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "O jogo terminou. Já não podes participar ao vivo nem assistir." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Sem lugares restantes na arena - participação ao vivo desativada." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Apenas 1 jogador restante. A voltar ao átrio." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "O dono do servidor saiu do jogo." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Irás assistir ao próximo jogo." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s entrou na equipa vermelha." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s entrou na equipa azul." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s entrou no jogo." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3938,15 +4134,15 @@ msgid "" msgstr "Prime <%s> ou <%s> para mudar o jogador alvo; <%s> ou <%s> para a posição da câmara." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "%s denunciado com sucesso." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3977,38 +4173,38 @@ msgstr "Contrarrelógio (Campeonato)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Todos Contra Todos" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Capturar a Bandeira" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s está agora online." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s e %s estão agora online." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s e %s estão agora online." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4017,12 +4213,12 @@ msgstr[1] "%d amigos estão agora online." msgstr[2] "%d amigos estão agora online." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s está agora no servidor \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4030,7 +4226,7 @@ msgstr[0] "Tens %d novo pedido de amizade!" msgstr[1] "Tens %d novos pedidos de amizade!" msgstr[2] "Tens %d novos pedidos de amizade!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Tens um novo pedido de amizade!" @@ -4059,12 +4255,12 @@ msgid "" msgstr "O ficheiro de recordes era muito antigo.\nTodos os recordes foram apagados." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Seguir o Líder" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Batalha de 3 Vidas" @@ -4077,92 +4273,88 @@ msgstr "O ficheiro de repetição incompleto não será gravado." msgid "Replay saved in \"%s\"." msgstr "Repetição gravada em \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 semana" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 semanas" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 mês" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 meses" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 meses" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 meses" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 ano" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 anos" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Nome da extensão" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Últ. atualização" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Não instalado" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s por %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Por favor, aguarda enquanto as extensões são atualizadas" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Ocorreu um erro na ligação ao site de extensões. Certifica-te de que estás ligado à Internet e que o SuperTuxKart não está a ser bloqueado pela firewall" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Favoritos" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Bloqueado: tens de superar os desafios para teres acesso a mais!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Arena Aleatória" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d arena indisponível para o modo Um Jogador." -msgstr[1] "%d arenas indisponíveis para o modo Um Jogador." -msgstr[2] "%d arenas indisponíveis para o modo Um Jogador." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Contribuições no Launchpad/Transifex:\nJoão Frade / 100Nome.blogs.sapo.pt\n274fb1bc2f045587a5bbfc0549580229_c79ef42 , 2015\nBenau, 2018-2020\nCrystalDaEevee, 2019-2023\nDaniel Luiz Lorenzi, 2022\nPedroxz, 2017\nRui, 2016-2019\nAuria\nDawid Gan\nBruno Ramalhete\nDouglas Moura\nEvandro P. Alves\nFátima de Menezes Dantas\nRicardo Conde\nSTK-team\nSérgio Marques\nHugo Carvalho" @@ -4450,7 +4642,7 @@ msgstr "Bananas apanhadas" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Derrapagens" @@ -4553,7 +4745,7 @@ msgstr "Caças aos Ovos finalizadas" msgid " (official tracks matching the goal)" msgstr " (pistas oficiais que correspondem ao objetivo)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4561,91 +4753,95 @@ msgid "" msgstr "Novos comandos de jogo aparecerão automaticamente na lista quando os ligares a este dispositivo.\n\nPara adicionar uma configuração de teclado, usa o botão abaixo, CONTUDO tem em atenção que a maioria dos teclados só regista um número limitado de teclas premidas ao mesmo tempo, sendo assim inapropriados para multijogador. (No entanto, poderás ligar vários teclados a este dispositivo. Lembra-te de que ainda assim todos os teclados terão de ter atribuições de teclas diferentes.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Adicionar Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Adicionar Configuração de Teclado" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Atualizar" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Versão: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "destacado" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Tamanho: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Precisas de ter sessão iniciada para avaliar esta extensão." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Infelizmente, ocorreu um erro ao descarregar a extensão" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Ocorreu um erro ao instalar a extensão %s." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Tentar novamente" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Ocorreu um erro ao remover a extensão %s." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Descarga em segundo plano completa." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Descarga em segundo plano" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "A descarga em segundo plano já foi iniciada." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Palavra-passe atual inválida." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "A palavra-passe tem de ter entre 8 e 30 caracteres!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "As palavras-passe não são iguais!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "A validar a informação" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "A palavra-passe foi alterada com sucesso." @@ -4667,67 +4863,97 @@ msgstr "As resoluções menores que 1024x768 ou 1280x720 não são suportadas. A #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Câmara de drone" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Personalizado" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Desativado" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Apenas importantes" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Muito Baixo" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Baixo" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Médio" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Alto" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Muito Alto" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4735,7 +4961,7 @@ msgid "" msgstr "O SuperTuxKart vai descarregar recursos completos (incluindo texturas de alta qualidade e música) para uma melhor experiência de jogo; isto usará os teus dados móveis se não tiveres uma ligação wifi." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4752,101 +4978,102 @@ msgstr "Introduz o endereço do servidor, opcionalmente seguido de : (dois ponto msgid "Invalid server address: %s." msgstr "Endereço de servidor inválido: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Sent. inverso" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Dificuldade" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Voltas" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Tempo" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Kart" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Utilizador" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Versão" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Não" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Pista" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Top %d Recordes" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Número de karts: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Tempo alvo: 1 %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Voltas: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Sentido inverso: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Vazio)" @@ -4934,33 +5161,41 @@ msgid "Press any key..." msgstr "Prime qualquer tecla..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "A conversação está desativada, ativa-a no menu Opções." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Voltar ao Teste de Desempenho" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Sair do Teste de Desempenho" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Voltar à Batalha" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Configurar Novo Jogo" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Reiniciar Batalha" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Sair da Batalha" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Configurar Nova Corrida" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Sair da Corrida" @@ -4976,11 +5211,11 @@ msgstr "%s ainda não tem classificação." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s é o número %d nas Classificações com uma pontuação de %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Nome de utilizador e/ou endereço de e-mail incorreto." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5002,7 +5237,7 @@ msgstr "Corrida Contra Fantasma" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Voltas: %i" @@ -5015,21 +5250,21 @@ msgstr "Tipo: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Posição alvo: %iº lugar" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Tempo alvo: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Pontos de nitro alvo: %i" @@ -5042,54 +5277,54 @@ msgstr "Número de Karts IA: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Modo de batalha" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Tipo de partida de futebol" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Localização do servidor: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Pista atual: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Posição" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Jogador" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Classificação" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Tempo jogado" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Remover dos marcadores" @@ -5102,74 +5337,74 @@ msgid "No player available for connecting to server." msgstr "Sem jogadores disponíveis para uma ligação ao servidor." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Nome de utilizador: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Cancelar Pedido" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Hoje" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Pedido de amizade enviado!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Pedido de amizade aceite!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Pedido de amizade recusado!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Amigo removido!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Pedido de amizade cancelado!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "A processar" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "A obter o último voto" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Podes alterar a avaliação que atribuíste anteriormente clicando nas estrelas abaixo." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Ainda não votaste nesta extensão. Clica nas estrelas abaixo para escolher a tua avaliação." -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Voto bem sucedido! Podes agora fechar a janela." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Realizar voto" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Pista Aleatória" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5198,7 +5433,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Ocorreu um erro ao tentar gravar o teu Campeonato." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Seleciona uma pista" @@ -5242,12 +5477,12 @@ msgstr "Desbloqueaste a pista %0" msgid "You unlocked grand prix %0" msgstr "Desbloqueaste o campeonato %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Pista" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5268,19 +5503,19 @@ msgstr "Introduz um nome para o campeonato" msgid "Please select a Grand Prix" msgstr "Por favor, seleciona um Campeonato" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Criações pessoais" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "O nome está em branco." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Já existe um Campeonato com este nome." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "O nome é demasiado longo." @@ -5289,19 +5524,19 @@ msgstr "O nome é demasiado longo." msgid "Better luck next time!" msgstr "Pode ser que tenhas mais sorte da próxima!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Completaste um desafio!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Venceste o Campeonato!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Terminaste o Campeonato!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Número de karts" @@ -5314,110 +5549,125 @@ msgstr "Tens a certeza de que queres remover este tempo recorde?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Tens a certeza de que queres remover todos os tempos recorde?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Favorito" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Leve" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Pesado" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Liga um teclado ou comando de jogo para jogares Multijogador em Ecrã Dividido" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Kart Aleatório" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Bloqueado" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" -msgstr "Para todos:\nPrime o botão 'Selecionar' para entrar no jogo" +msgstr "Atenção, jogadores:\n\nPrimam o vosso botão de 'Selecionar' para entrarem no jogo" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Gostarias de jogar o tutorial do jogo?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Não podes jogar online sem ter acesso à Internet. Se queres jogar online, acede ao menu Opções e marca a opção \"Ligar à Internet\"." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Não podes descarregar extensões sem acesso à Internet. Se quiseres descarregar extensões, acede ao menu Opções e marca a opção \"Ligar à Internet\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Não podes descarregar extensões sem acesso à Internet. Se quiseres descarregar extensões, acede ao menu Opções e marca a opção \"Ligar à Internet\".\n\nPodes no entanto eliminar extensões descarregadas anteriormente." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "De momento, o módulo de extensões está desativado no ecrã de Opções" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Por favor, aguarda enquanto as extensões são carregadas" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Tens a certeza de que queres sair do STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Criar servidor de rede local" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Servidor de %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Nº de pistas para Campeonato" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "O nome tem de ter entre 4 e 30 caracteres!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Caracteres inválidos na palavra-passe!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Pronto" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Participar ao Vivo" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Assistir" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Instalar extensão" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5425,7 +5675,7 @@ msgstr "Por favor, aguarda que o jogo atual (%s) termine; tempo restante estimad #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Por favor, aguarda que o jogo atual termine; tempo restante estimado: %s." @@ -5433,24 +5683,24 @@ msgstr "Por favor, aguarda que o jogo atual termine; tempo restante estimado: %s #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Por favor, aguarda que o jogo atual (%s) termine; progresso estimado: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Por favor, aguarda que o jogo atual termine; progresso estimado: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Por favor, aguarda que o jogo atual termine." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5460,7 +5710,7 @@ msgstr[2] "O jogo iniciará se houver mais de %d jogadores." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5470,96 +5720,108 @@ msgstr[0] "A iniciar dentro de %d segundo ou quando todos premirem o botão 'Pro msgstr[1] "A iniciar dentro de %d segundos ou quando todos premirem o botão 'Pronto'." msgstr[2] "A iniciar dentro de %d segundos ou quando todos premirem o botão 'Pronto'." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "A ligar ao servidor %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "A procurar um servidor de jogo rápido" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Tempo restante: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Objetivos" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "A obter proezas" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Perfil de %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Desde" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Estado" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "A obter lista de amigos" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Novo Pedido" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Pendente" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Offline" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Introduz o novo e-mail em baixo" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "O novo e-mail deverá ter entre 5 e 254 caracteres!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "O novo e-mail é inválido!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "O e-mail foi alterado!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Falha ao alterar o e-mail: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Novidades do blogue do STK" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Data" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "De momento não há novidades disponíveis." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Tens de estar autenticado para jogar na rede global. Clica no teu nome de utilizador acima." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "A procurar" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Sair do Jogo" @@ -5637,34 +5899,34 @@ msgid "Distance (km)" msgstr "Distância (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Desconhecido" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Não foi detetado IPv4; poderás não conseguir entrar em nenhum servidor." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Não foi detetado IPv6; poderás não conseguir entrar em nenhum servidor." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Nenhum servidor disponível." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "A obter servidores" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Servidores Marcados" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5672,149 +5934,149 @@ msgstr "Se uma maioria de jogadores escolher a mesma pista e configurações de #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Localização aleatória dos itens" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Número de golos para vitória" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Conduzir em sentido inverso" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Bloqueado: tens de superar os desafios para teres acesso a mais!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Ação" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Tecla atribuída" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Desativar Dispositivo" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Ativar Dispositivo" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Ativar Configuração" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Teclas de Jogo" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Teclas do Menu" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Virar à Esquerda" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Virar à Direita" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Acelerar" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Travar / Marcha Atrás" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Disparar" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Olhar à Retaguarda" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Resgate" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Pausar Jogo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Cima" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Baixo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Esquerda" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Direita" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Selecionar" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Cancelar/Voltar" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Um item azul significa um conflito com outra configuração" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Um item vermelho significa um conflito na configuração atual" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5822,17 +6084,27 @@ msgid "" msgstr "Aviso: a tecla Shift não é recomendada. Quando 'Shift' é premido, todas as teclas que contenham um caráter que seja diferente em maiúsculas deixarão de funcionar." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Tens a certeza de que queres eliminar permanentemente esta configuração?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Introduz o novo nome da configuração; deixa em branco para reverter para o nome padrão." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Vertical" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Horizontal" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5840,89 +6112,74 @@ msgstr "No modo multijogador, os jogadores poderão selecionar perfis em\ndesvan #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Instalar recursos completos do jogo" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Tens a certeza de que queres desinstalar o pacote completo dos recursos do jogo?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Teclado %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Dispositivo Tátil" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Toca num dispositivo para o configurares" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Idioma do Sistema" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "No fundo à esquerda" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "No lado direito" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Oculto" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "No centro" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Vertical" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Horizontal" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Muito pequeno" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Pequeno" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Médio" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Grande" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Muito grande" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5932,128 +6189,133 @@ msgid "" msgstr "O modo Speedrun só pode ser ativado se o jogo não tiver sido fechado depois de iniciado o modo História.\n\nFechar o jogo antes de completado o modo História invalida o cronómetro.\n\nPara ativares o modo Speedrun, por favor usa um perfil novo." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Sincronização vertical" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "A sincronização vertical força a placa gráfica a só fornecer\num novo frame quando o monitor estiver pronto a mostrá-lo." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "A sincronização vertical não funcionará se os controladores\ninstalados não a suportarem." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Efeitos de partículas: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Personagens animadas: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Luzes dinâmicas: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Dispersão da luz: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Antisserrilhado: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Oclusão do ambiente: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Sombras: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Sombras: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Florescência: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Aura (contornos): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Raios de luz: %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Qualidade da imagem renderizada: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Detalhes da geometria: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Desfoque de movimento: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Profundidade de campo: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "O acesso à Internet está desativado. Queres ativá-lo?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Tens de introduzir a palavra-passe." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "A terminar sessão de '%s'" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "A iniciar sessão como '%s'" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Não podes eliminar o único jogador." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Queres mesmo eliminar o jogador '%s'?" @@ -6081,14 +6343,14 @@ msgstr "GOLO!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "À espera dos outros" #. I18N: Shown waiting for the server in network if live join or spectate #: src/states_screens/race_gui_base.cpp:84 msgid "Waiting for the server" -msgstr "A esperar pelo servidor" +msgstr "À espera do servidor" #. I18N: string used to show the song title (e.g. "Sunny Song") #: src/states_screens/race_gui_base.cpp:646 @@ -6116,7 +6378,7 @@ msgstr "Segue o líder!" msgid "Top %i" msgstr "Top %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Desafio Falhado" @@ -6140,102 +6402,199 @@ msgstr "Toca no pódio para iniciar o desafio" msgid "Press fire to start the challenge" msgstr "Prime Disparar para iniciar o desafio" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Voltar às definições gráficas" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Guardar resultados do teste" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Voltar ao menu inicial" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Sair do Servidor" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Abortar Campeonato" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Reiniciar" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Voltar à Seleção de Desafio" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Correr contra o novo fantasma" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Voltar ao Menu" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Queres mesmo abortar o Campeonato?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Relatório de desempenho guardado em \"%s\"." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" -msgstr "Vence a Equipa Vermelha!" +msgstr "Vitória da Equipa Vermelha" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" -msgstr "Vence a Equipa Azul!" +msgstr "Vitória da Equipa Azul" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "É um empate" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Eliminado após %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Eliminado" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Autogolo)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Pista %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Progresso do campeonato:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Recordes" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Melhor volta: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "por %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Completaste o desafio!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Falhaste o desafio!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Requisitos para SuperTux atingidos" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Resultados do Teste de Desempenho" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Duração do teste: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Número de frames: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "FPS estável: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "FPS geralmente estável: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "FPS típico: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Resolução horizontal: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Resolução vertical: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Iluminação dinâmica: SIM" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Iluminação dinâmica: NÃO" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Resolução de renderização: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Antisserrilhado: SIM" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Antisserrilhado: NÃO" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Iluminação baseada em imagem: SIM" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Iluminação baseada em imagem: NÃO" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Oclusão do ambiente: SIM" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Oclusão do ambiente: NÃO" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Resolução da sombra: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Todo o golpe é lícito, então apanha armas e usa-as com cabeça!" @@ -6276,28 +6635,28 @@ msgstr "Toca nos ícones vermelho ou azul para mudares de equipa" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Pista por %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Nº máximo de jogadores suportados: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Número de Karts IA na equipa vermelha" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Não podes jogar este Campeonato porque contém pistas ainda por desbloquear!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Bloqueado!" @@ -6319,10 +6678,12 @@ msgid "%d/%m/%Y" msgstr "%Y/%m/%d" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Completa todos os desafios para abrir a porta grande!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6331,41 +6692,48 @@ msgid "" msgstr "Precisas de mais pontos\npara entrar neste desafio!\nProcura no minimapa por\ndesafios disponíveis." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Acelera com <%s> e vira com <%s> e <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Acelera tocando na parte de cima do volante e vira movendo para a esquerda ou direita." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Acelera movendo o acelerador para cima e vira inclinando o teu dispositivo." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Acelera movendo o acelerador para cima e vira rodando o teu dispositivo." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Apanha presentes e dispara com <%s> para para derrubares estas caixas!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Apanha presentes e dispara tocando no ícone de bólingue para derrubares estas caixas!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6373,34 +6741,41 @@ msgid "" msgstr "Prime <%s> para olhares à retaguarda.\nDispara com <%s> ou enquanto primes <%s> para disparar atrás!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Toca no ícone do espelho para olhares à retaguarda.\nDispara para trás segurando o ícone do espelho e depois deslizando para o ícone de bólingue!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Usa o nitro que apanhaste premindo a tecla <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Usa o nitro que apanhaste tocando no ícone da garrafa de nitro" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Apanha garrafas de nitro (vamos usá-las após a curva)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Oh, não! Quando estiveres em apuros, prime <%s> para chamar o resgate." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Oh, não! Quando estiveres em apuros, toca no ícone do pássaro para chamar o resgate." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6408,24 +6783,27 @@ msgid "" msgstr "Acelera e prime <%s> ao virar para derrapar.\nDerrapar por pouco tempo ajuda-te a virar mais rápido em curvas apertadas." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Acelera e toca no ícone de derrapar ao virar para derrapar.\nDerrapar por pouco tempo ajuda-te a virar mais rápido em curvas apertadas." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Nota que, se derrapares por vários segundos, receberás um impulso extra!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Estás pronto para correr. Boa sorte!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Um jogo de karting de código aberto em 3D" @@ -6435,7 +6813,7 @@ msgstr "Um jogo de karting de código aberto em 3D" msgid "tux;game;race;" msgstr "tux;jogo;corrida;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6443,7 +6821,7 @@ msgid "" "for all ages." msgstr "Karts. Nitro. Ação! SuperTuxKart é um arcada de corrida 3D em código aberto com uma variedade de personagens, pistas e modos para jogar. O nosso objetivo é criar um jogo que seja mais divertido do que realista, e propiciar uma experiência agradável para todas as idades." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6452,7 +6830,7 @@ msgid "" "your opponents." msgstr "Temos uma variedade de pistas com diferentes temas para os jogadores desfrutarem, desde corridas debaixo de água, quintas rurais, selvas e até no espaço! Dá o teu melhor a desviar-te de outros karts à medida que (possivelmente) te ultrapassam, só não comas as bananas! Cuidado com bolas de bólingue, desentupidores, pastilhas elásticas e bolos atirados pelos teus adversários." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6461,27 +6839,27 @@ msgid "" "your racing skills!" msgstr "Podes fazer uma corrida contra outros karts, competir num Campeonato, tentar bater o recorde em Contrarrelógios por ti mesmo, jogar o modo Batalha contra o computador ou amigos teus, e mais! Para um desafio maior, joga online, conhece jogadores de todo o mundo e prova de que és feito!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Este jogo não contém anúncios." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Esta é uma versão instável do SuperTuxKart que contém as mais recentes melhorias. Ela é lançada sobretudo para testes ao jogo, possibilitando uma versão estável no seu melhor." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Esta versão pode ser instalada no dispositivo em paralelo com a versão estável." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Se desejas mais estabilidade, considera usar a versão estável: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "Equipa SuperTuxKart" diff --git a/data/po/pt_BR.po b/data/po/pt_BR.po index bf3a3831a43..1f8fb3a4168 100644 --- a/data/po/pt_BR.po +++ b/data/po/pt_BR.po @@ -14,7 +14,7 @@ # flaviozavan , 2015-2017 # Laete Meireles , 2015 # Matheus Meneghini Leal, 2022 -# Matheus Meneghini Leal, 2022-2023 +# Matheus Meneghini Leal, 2022-2024 # Maximilian Weiss-Föder, 2021 # Maximilian Weiss-Föder, 2021-2023 # Pablo do Amaral Ferreira , 2015 @@ -23,9 +23,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Matheus Meneghini Leal, 2022-2023\n" +"Last-Translator: Matheus Meneghini Leal, 2022-2024\n" "Language-Team: Portuguese (Brazil) (http://app.transifex.com/supertuxkart/supertuxkart/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -182,7 +182,7 @@ msgstr "Jornada ao Fim do Mundo" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Voltar" @@ -204,7 +204,7 @@ msgstr "Selecione o tipo de controle desejado" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Acelerômetro" @@ -218,13 +218,13 @@ msgstr "Acelerômetro" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Giroscópio" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Volante" @@ -255,35 +255,37 @@ msgstr "Configurações para dispositivos táteis" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Geral" @@ -351,30 +353,33 @@ msgstr "Retornar aos valores padrão" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Cancelar" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Sim" @@ -552,9 +557,9 @@ msgstr "Entrar" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -615,7 +620,7 @@ msgstr "Objetivo" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Progresso" @@ -650,7 +655,7 @@ msgstr "Enviar" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Retornar ao jogo" @@ -667,7 +672,7 @@ msgstr "Retornar ao saguão" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Reiniciar partida" @@ -731,12 +736,12 @@ msgstr "Informe o seu nome de usuário e o seu e-mail de cadastro." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Nome de usuário" @@ -777,7 +782,7 @@ msgstr "Dificuldade" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Amador" @@ -789,7 +794,7 @@ msgstr "Amador" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Intermediário" @@ -801,7 +806,7 @@ msgstr "Intermediário" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Experiente" @@ -813,7 +818,7 @@ msgstr "Experiente" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "Super Tux" @@ -821,8 +826,8 @@ msgstr "Super Tux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Modalidade" @@ -833,8 +838,8 @@ msgstr "Modalidade" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Corrida normal" @@ -847,7 +852,7 @@ msgstr "Corrida normal" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Corrida sem itens" @@ -855,7 +860,8 @@ msgstr "Corrida sem itens" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Batalha" @@ -864,24 +870,24 @@ msgstr "Batalha" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Futebol" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Senha" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Adicionar aos favoritos" @@ -892,7 +898,7 @@ msgstr "Adicionar jogador" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Nome" @@ -986,6 +992,50 @@ msgstr "Mapear à tecla ESC" msgid "Assign nothing" msgstr "Não mapear nada" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Configurações de Vídeo Recomendadas" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "As configurações recomendadas serão válidas para a resolução atual." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "O que as configurações devem priorizar?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Performance" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Balanciar performance e qualidade gráfica" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Qualidade gráfica" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Economizar energia" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Você gosta de efeitos gráficos que criam borrões?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Iniciar o teste" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -1000,11 +1050,11 @@ msgstr "Opções da partida" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Continuar" @@ -1045,10 +1095,15 @@ msgstr "Arenas" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Instalados" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Editar arenas favoritas" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1058,20 +1113,20 @@ msgstr "Instalados" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Oficiais" @@ -1082,12 +1137,12 @@ msgstr "Oficiais" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Complementares" @@ -1101,27 +1156,28 @@ msgstr "Complementares" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Todos" @@ -1160,9 +1216,9 @@ msgstr "Postergar" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Inserir" @@ -1199,7 +1255,7 @@ msgstr "Selecionar fantasma" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Ovos escondidos" @@ -1246,10 +1302,10 @@ msgstr "Sentido contrário" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Duração (em minutos)" @@ -1281,9 +1337,9 @@ msgstr "Copiar" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1294,80 +1350,80 @@ msgstr "Renomear" msgid "Save Grand Prix" msgstr "Salvar campeonato" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Ajuda do SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Modalidades" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Itens" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Bananas" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1375,56 +1431,57 @@ msgstr "Bananas" msgid "Story Mode" msgstr "Modo História" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Tipos de kart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Modo multijogador" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Iniciar tutorial" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Pegue as caixas de presente para ganhar poderes especiais." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Não encoste nas bananas!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1432,14 +1489,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Colete os cilindros azuis para aumentar seu estoque de nitro, indicado no canto inferior direito da tela. Aperte o botão correspondente para usá-lo." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Este cadeado indica algo que ainda precisa ser desbloqueado no Modo História." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1448,34 +1505,34 @@ msgid "" "carefully before!" msgstr "Derrape seu kart para fazer curvas mais fechadas. Se você derrapar por algum tempo, aparecerão faíscas amarelas e vermelhas que aumentam a sua velocidade. Não é possível passar a virar para a outra direção durante uma derrapagem." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Para largar com mais velocidade, comece a acelerar assim que o sinal amarelo se acender, no \"Prepare-se!\"" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Acesse o menu de configurações para visualizar ou alterar os controles" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "O SuperTuxKart apresenta diversas modalidades de jogo:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Corrida normal: Contém diversos itens espalhados na pista. Utilize-os com inteligência para vencer." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Corrida sem itens: Só as habilidades ao volante contam!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1483,7 +1540,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Siga o mestre: Procure ficar sempre em segundo, pois quem estiver na frente do líder ou em último será eliminado periodicamente." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1493,30 +1550,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Há três tipos de batalha:\n\"Três vidas\": você começa com três vidas e perde uma toda vez que for atingido por um item.\n\"Luta livre\": vence quem atingir os oponentes mais vezes, até o contador de tempo ou de pontos chegar ao final.\n\"Pega-bandeira\": os jogadores se separam em dois times, ganhando um ponto sempre que trouxerem a bandeira da equipe adversária para a própria base, sem a própria bandeira estar nas mãos do outro time." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Futebol: Abuse de sua destreza (ou canhotice) para levar a bola ao gol!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Ovos escondidos: Encontre todos os ovos da pista!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Modo fantasma: Enfrente fantasmas dos modos \"Corrida sem itens\" e \"Ovos escondidos\", ou grave um novo!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Conta-voltas: faça o maior número de voltas possível antes de acabar o tempo." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1525,93 +1582,93 @@ msgid "" "wins the cup." msgstr "* É possível jogar diversas dessas modalidades em modo campeonato. Ou seja, você joga várias partidas seguidas, em vez de uma isolada. No final, vence quem acumular mais pontos." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "As caixas de presente contêm diversos itens:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Chiclete - Ele forma um escudo protetor. Se você o utilizar olhando para trás, ele funcionará como uma espécie de mina." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Seta turbo - Dá um grande impulso de velocidade. Cuidado para não perder o controle!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Torta - Vai em direção ao adversário mais próximo, afetando também os que estiverem bem perto dele. Acertá-la é mais fácil em retas e a curtas distâncias." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Desentupidor - Se acertar um adversário à frente, diminui a velocidade dele. Se acertar um atrás, tampa a sua vista." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Bola de boliche - Vai sempre reto, ricocheteando nas paredes, até acertar um adversário. Também pode ser atirada para trás. " -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Paraquedas - Diminui a velocidade dos karts que estiverem na sua frente." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Magia - Transforma, por alguns segundos, os presentes em bananas e os nitros em chicletes. As bananas viram presentes e os chicletes, barris de nitro." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Bola de basquete - Vai quicando até atingir o primeiro colocado, sendo capaz de esmagar vários oponentes em seu percurso." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Mata-moscas - Esmaga os oponentes que estiverem ao seu lado, deixando-os muito mais lentos. Também remove paraquedas e bombas-relógio." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Se você encostar em uma banana, um destes objetos se prenderá ao seu kart:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Âncora - Desacelera abruptamente o seu kart." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Paraquedas - Também diminui a velocidade, mas de forma menos abrupta e mais duradoura." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bomba-relógio - Explode depois de algum tempo. Encoste em outro kart para repassá-la." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "O malvadão do Nolok sequestrou o Gnu! Eis algumas dicas para derrotá-lo:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1620,7 +1677,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Esse ícone mostra, no minimapa, os desafios que ainda não foram concluídos. A sua quantidade de pontos é indicada no canto superior direito da tela. Acumule pontos suficientes para o Nolok aceitar o seu duelo e ganhe dele para libertar o Gnu! " -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1628,20 +1685,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Quando você vence um desafio, ganha um troféu e uma certa quantidade de pontos, que aumenta de acordo com o nível de dificuldade." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Você ganha uma surpresa sempre que alcançar a quantidade de pontos indicada embaixo desse ícone." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Há três categorias de karts, que se diferenciam da seguinte forma:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1649,7 +1706,7 @@ msgid "" " resistant to explosions." msgstr "Peso: Os karts podem ser leves, pesados ou médios. Os pesados são mais resistentes a paraquedas e explosões." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1657,7 +1714,7 @@ msgid "" " especially at low speeds." msgstr "Aceleração: Ajuda muito no início da corrida, após acidentes e em pistas com curvas muito fechadas. Os karts leves são os que aceleram mais rapidamente, enquanto os pesados demoram mais para adquirir velocidade." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1665,14 +1722,14 @@ msgid "" " top speed." msgstr "Velocidade máxima: Indica a velocidade que o kart pode alcançar. Altas velocidades ajudam muito em pistas com muitas retas e curvas leves. A velocidade máxima dos karts pesados é maior que a dos leves." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Nitroeficiência: Os karts leves são os mais eficientes, ganhando mais velocidade com o uso do nitro. " -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1680,12 +1737,12 @@ msgid "" "easier it is." msgstr "Se você ficar logo atrás de um adversário por alguns segundos, em seu vácuo, ganhará um impulso de velocidade. Com um kart leve, isso é mais fácil." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "O SuperTuxKart pode ser jogado com vários amigos em rede..." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1695,7 +1752,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Para tanto, selecione a opção \"Multijogador em rede\" no menu principal. Em seguida, escolha entre \"Rede local\" ou \"Jogar pela internet\". Para jogar na internet, marque a caixa \"Conectar-se à internet\" no menu de configurações. Por fim, selecione entre os servidores existentes ou crie um novo, com suas próprias especificações. Alguns dos servidores em destaque podem inclusive afetar sua pontuação no ranking mundial." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1705,12 +1762,12 @@ msgid "" "players and the server." msgstr "Geralmente é o jogador com a coroa que inicia as partidas. Nos servidores oficiais, elas só podem começar se houver um número mínimo de jogadores. Iniciada a partida, os jogadores escolhem seus karts e, em seguida, a pista. Pistas complementares só estarão disponíveis se estiverem instaladas no servidor e também nos dispositivos de todos os jogadores presentes." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "...ou em um mesmo dispositivo:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1720,7 +1777,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Nesse caso, o ideal é empregar um controlador, entre gamepads, joysticks e teclados, para cada jogador, pois a maioria dos teclados não funciona direito quando diversas teclas são pressionadas ao mesmo tempo. Para configurar os controladores, acesse o menu de configurações. Infelizmente não é possível utilizar o mouse para controlar seu kart." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1740,7 +1797,7 @@ msgstr "Melhores tempos" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Contagem de voltas" @@ -1748,9 +1805,9 @@ msgstr "Contagem de voltas" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Campeonato" @@ -1761,6 +1818,20 @@ msgstr "Campeonato" msgid "Choose a Kart" msgstr "Escolha seu kart" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Classe Kart" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Editar os karts favoritos" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1774,11 +1845,11 @@ msgstr "Multijogador local" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Online" @@ -1795,7 +1866,7 @@ msgstr "Tutorial" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Recordes" @@ -1803,7 +1874,7 @@ msgstr "Recordes" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Conquistas" @@ -1857,30 +1928,30 @@ msgstr "Procurar servidor" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Criar servidor" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Saguão" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Configurações" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Iniciar partida" @@ -1906,9 +1977,9 @@ msgstr "Servidor específico" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Perfil pessoal" @@ -1926,7 +1997,7 @@ msgstr "Classificação dos jogadores" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Amigos" @@ -1951,7 +2022,7 @@ msgstr "Seleção automática" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Configurações da conta" @@ -2001,8 +2072,8 @@ msgid "Online Username" msgstr "Nome na internet" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Restaurar senha" @@ -2015,7 +2086,7 @@ msgid "" msgstr "Você pode jogar sem criar uma conta online selecionando uma conta offline. Porém você não poderá se conectar aos amigos, dar votos aos complementos, etc. Por favor, leia nossa Declaração de Privacidade em https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Selecionar servidor" @@ -2033,339 +2104,409 @@ msgstr "Conectar-se por IPv6" msgid "User search" msgstr "Buscar usuário" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Configurações do SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Tela" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Gráficos" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Áudio" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Interface" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Jogadores" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Controladores" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Idioma" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Música" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Habilitado" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Volume" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Efeitos sonoros" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Excluir configuração" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Desabilitar configuração" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Voltar à lista de dispositivos" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Renomear configuração" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Ativar vibração no controle, se houver suporte" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Resolução" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Tela cheia" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Lembrar posição da janela" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Aplicar nova resolução" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Divisão da tela para multijogador local" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Configurações de Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Sempre mostrar a tela de login" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Conectar-se à Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Habilitar chat em rede" +msgid "Enable chatting in online lobbies" +msgstr "Habilitar chat em salas onlines" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Habilitar chat em jogos em rede" +msgid "Enable chatting in online matches" +msgstr "Habilitar chat em partidas online" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Outras configurações" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Ativar desvantagens individuais" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Desinstalar pacote de alta resolução" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Para configurar um dispositivo, selecione-o e aperte Enter, ou clique duas vezes sobre ele" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Inserir controlador" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* O jogador utilizará o controlador cuja tecla ou botão apertou para entrar na partida." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Aparência" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Minimapa" +msgid "Skin variant" +msgstr "Pele alternativa" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Divisão da tela para multijogador local" +msgid "Minimap" +msgstr "Minimapa" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Tamanho da fonte" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Câmera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Personalizar" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Mostrar FPS" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Exibir os itens dos outros jogadores" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Exibir cronômetro do modo história" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Habilitar cronômetro de \"speedrun\"" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Porcentagem utilizada da tela" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Nível gráfico" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Nível de borramento" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "FPS máximo" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Configurações personalizadas..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Resolução" +msgid "Performance tests" +msgstr "Testes de performance" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Tela cheia" +msgid "Performance test of the current settings" +msgstr "Teste de performance das configurações atuais" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Lembrar posição da janela" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Lembrar senha" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Aplicar nova resolução" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Excluir" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Cor do kart" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2392,15 +2533,15 @@ msgstr "Time azul" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Número de voltas" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Karts controlados pelo computador" @@ -2415,33 +2556,17 @@ msgstr "Karts azuis computadorizados" msgid "Random Grand Prix" msgstr "Sortear campeonato" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Editar as pistas favoritas" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Login" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Lembrar senha" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Excluir" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Cor do kart" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Há diversos temas gráficos disponíveis nas configurações de interface." @@ -2560,238 +2685,306 @@ msgid "" msgstr "Não tente roubar a bola de um companheiro de equipe. Em vez disso, atinja os adversários para eles não impedirem o gol." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Fossas Primevais" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Contato Alienígena" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Labirinto dos Gladiadores" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Cidade de Candela" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Ilha das Toninhas" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Floresta Negra" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Caverna Misteriosa" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Templo do Cacau" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Campos de Milho" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Fortaleza Magmática" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Ilha de Gran-Paradiso" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Caça-caçapa" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Campo de Hóquei" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "O que aconteceu, seus bobocas? O grande líder de vocês sumiu?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "He he! Ele está no meu castelo agora, e logo irá para a panela!" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Mas como sou um monstrinho justo, farei um acordo com vocês!" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Se vocês me vencerem em uma corrida, soltarei o velhaco." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "Mas eu tenho certeza que vocês, bichinhos patéticos, jamais ganhariam de mim, o rei dos karts!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Arena de Las Dunas" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Estádio de Las Dunas" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Volta do Farol" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Mina Antiga" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolfe" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oásis" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Aula de Matemática" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Parque das Abóboras" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Pontal dos Corvos" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Areias Movediças" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Lago do Nessie" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Refúgio do Norte" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Picos Nevados" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Campo de Futebol" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Estádio Esportivo" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Enterprise" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Templo" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Ilha Vulcânica" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Jardim Zen" @@ -2800,11 +2993,11 @@ msgstr "Jardim Zen" msgid "Completed achievement \"%s\"." msgstr "Você conquistou o título \"%s\"!" -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Não foi possível se conectar ao servidor de complementos do SuperTuxKart." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Erro ao baixar as notícias: \"%s\"" @@ -2870,7 +3063,7 @@ msgid "New kart '%s' now available" msgstr "Kart \"%s\" liberado" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2902,32 +3095,32 @@ msgid "" "created." msgstr "Seu arquivo de configuração estava muito antigo, sendo portanto excluído e substituído." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Gravando vídeo." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Vídeo salvo em \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Andamento da codificação:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Dica: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Carregando" @@ -2949,19 +3142,18 @@ msgstr "Nitroeficiência" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (com desvantagem)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s está pronto" @@ -3435,21 +3627,21 @@ msgid "Axis %d" msgstr "Eixo %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Botão %d do controle" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Botão %d do mouse" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Eixo %d %s do mouse" @@ -3622,26 +3814,30 @@ msgstr "Não é possível ter mais de três vidas!" msgid "+1 life." msgstr "Vida extra." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Você foi devagar demais!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Você terminou a corrida!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Parabéns! Ganhou a corrida!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Chegou em %d°!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s saiu da partida." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3650,16 +3846,16 @@ msgid "" "Internet\")." msgstr "O SuperTuxKart se conecta ao nosso servidor central para baixar notícias e complementos. Nossa política de privacidade está disponível para consulta em https://supertuxkart.net/Privacy. Você deseja ativar essa opção? Para ativá-la ou desativá-la posteriormente, entre no menu de configurações e acesse a aba \"Geral\"." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Sua tela está com uma resolução baixa demais para o STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Seu driver de vídeo está em uma versão muito antiga. Atualize-o." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3667,38 +3863,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Parece que seu driver de vídeo está em uma versão muito antiga. Não haveria uma mais recente disponível? Para o jogo poder rodar, colocaremos os gráficos em um nível bem baixo. Recomendamos utilizar um driver compatível com %s ou superior." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "A conexão com o servidor caiu." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s pegou a bandeira vermelha!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "A bandeira vermelha voltou para a base!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s pegou a bandeira azul!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "A bandeira azul voltou para a base!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s conseguiu trazer a bandeira azul à própria base!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s conseguiu trazer a bandeira vermelha à própria base!" @@ -3708,7 +3904,7 @@ msgstr "%s conseguiu trazer a bandeira vermelha à própria base!" msgid "Eggs: %d / %d" msgstr "Ovos encontrados: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Mestre" @@ -3716,22 +3912,22 @@ msgstr "Mestre" msgid "Final lap!" msgstr "Última volta!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "%iª volta" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s, por %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Volta mais rápida" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "CONTRAMÃO!" @@ -3745,7 +3941,7 @@ msgstr "%s marcou um gol!" msgid "Oops, %s made an own goal!" msgstr "Oops, %s fez um gol contra!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" @@ -3753,187 +3949,187 @@ msgstr[0] "1%i kart de estepe foi criado!" msgstr[1] "%i pneus de kart apareceram na pista! Eles dão vida extra!" msgstr[2] "%i pneus de kart apareceram na pista! Eles dão vida extra!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Você foi eliminado!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "%s foi eliminado." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "O servidor foi desligado." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Você foi removido do servidor." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Removido do servidor. Ping alto demais." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Má conexão" -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Computadorizado" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s se desconectou." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Aperte em um dos jogadores da lista para o gerenciar e ver sua qualificação no ranking mundial." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Dificuldade: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Máximo de jogadores: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Modalidade: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Limite de tempo" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Limite de gols" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Tipo de partida: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Corridas concluídas: %d/%d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Todos os jogadores entraram no time vermelho ou azul." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Agora é você quem controla o servidor." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Servidor ocupado." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Você foi banido desse servidor." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Senha incorreta." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Dados incompatíveis com o servidor." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Servidor lotado." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Jogador inválido." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Não foi possível iniciar a partida em rede." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "A partida já terminou. Não é mais possível participar ou assistir." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Não há lugares restantes e não é possível entrar no meio de partidas neste servidor." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Apenas um jogador presente. Voltando ao saguão." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "O dono do servidor saiu do jogo." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Você só assistirá à próxima partida." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s entrou para o time vermelho." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s entrou para o time azul." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s entrou no jogo." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3941,15 +4137,15 @@ msgid "" msgstr "Aperte <%s> ou <%s> para escolher outro alvo, e <%s> ou <%s> para alterar a câmera. " #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "Sua denúncia contra %s foi recebida." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3980,38 +4176,38 @@ msgstr "Corridas sem itens (campeonato)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Luta livre" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Pega-bandeira" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s se conectou." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s e %s se conectaram." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s e %s se conectaram." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4020,12 +4216,12 @@ msgstr[1] "Há %d amigos conectados." msgstr[2] "Há %d amigos conectados." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s entrou no servidor \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4033,7 +4229,7 @@ msgstr[0] "Você tem %d nova requisição de amizade!" msgstr[1] "Você recebeu %d novas solicitações de amizade!" msgstr[2] "Você recebeu %d novas solicitações de amizade!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Você recebeu uma nova solicitação de amizade!" @@ -4062,12 +4258,12 @@ msgid "" msgstr "O arquivo de recordes local estava muito antigo\ne todos eles foram removidos." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Siga o mestre" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Três vidas" @@ -4080,92 +4276,88 @@ msgstr "O fantasma de replay está incompleto e não será salvo." msgid "Replay saved in \"%s\"." msgstr "Fantasma salvo em \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "Uma semana" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "Duas semanas" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "Um mês" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "Três meses" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "Seis meses" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "Nove meses" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "Um ano" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "Dois anos" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Nome do complemento" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Última atualização" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Não instalados" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s\nAutoria: %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Aguarde a atualização dos complementos" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Houve um erro ao tentar contatar o servidor dos complementos. Verifique sua conexão à internet e se o SuperTuxKart não está bloqueado por um firewall." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Favoritos" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Bloqueado: supere mais desafios do Modo História para destravá-lo!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Sortear arena" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d arena indisponível no modo de um jogador." -msgstr[1] "%d arenas indisponíveis no modo de um jogador." -msgstr[2] "%d arenas indisponíveis no modo de um jogador." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nAdevair Junior, 2018-2021\nAndré Marcelo Alvarenga, 2017-2018\nMaximilian Weiss-Föder, 2021\nBenau, 2018,2020\nC. E., 2019-2020\nC. E., 2020,2022\nC. E., 2019\nflaviozavan, 2015-2017\nLaete Meireles, 2015\nMatheus Meneghini Leal, 2022\nMaximilian Weiss-Föder, 2021-2022\nPablo do Amaral Ferreira, 2015\nRui, 2018\nC. E., 2020\nAdevair Heleno\nAverage John\nEberval Oliveira Castro\nEdvaldo de Souza Cruz\nFelipe Menezes\nFlávio Zavan\nGuilherme Marçal\nMarcelo R. de Sa\nMateus Ferreira Silva\nMihailov\nNeliton Pereira Jr.\nPaulo Roberto de Oliveira Castro\nPedro Folha\nRafael Neri\nRodrigo Borges\nRubens Bueno\nSTK-team\nTeylo Laundos Aguiar\nVitor da Silva Gonçalves\nfarrer" @@ -4453,7 +4645,7 @@ msgstr "Bananas encostadas" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Derrapagem" @@ -4556,7 +4748,7 @@ msgstr "Buscas por ovos finalizadas" msgid " (official tracks matching the goal)" msgstr " (em pistas oficiais)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4564,91 +4756,95 @@ msgid "" msgstr "Novos gamepads e joysticks aparecem na lista assim que são conectados.\n\nAperte o botão abaixo para inserir uma nova configuração separada para o teclado. Lembre-se que a maioria dos teclados não funcionam direito quando vários botões são apertados ao mesmo tempo, sendo portanto inadequados para o modo multijogador local.\n\nUma saída seria conectar mais de um teclado ao dispositivo. No entanto, ainda assim seria necessário mapear teclas diferentes para cada jogador." #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Inserir Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Nova configuração de teclado" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Atualizar" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Versão: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "Recomendada" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Tamanho: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Você precisa estar logado para avaliar esse complemento." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Não foi possível baixar o complemento" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Não foi possível instalar o complemento \"%s\"." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Tente mais tarde" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Não foi possível remover o complemento \"%s\"." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Download concluído em segundo plano." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Download em segundo plano" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "O download já foi iniciado em segundo plano." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "A senha atual é inválida." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "A senha deve ter entre 8 e 30 caracteres!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "As senhas se diferem!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Validando os dados" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "A senha foi modificada." @@ -4670,67 +4866,97 @@ msgstr "Não há suporte para resoluções inferiores a 1024x768 e 1280x720. Se #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Câmera aérea" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Personalizada" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Nenhuma" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Só as essenciais" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Muito baixo" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Baixo" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Médio" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Alto" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Muito Alta" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4738,7 +4964,7 @@ msgid "" msgstr "Para aprimorar o seu divertimento, o SuperTuxKart baixará o pacote de alta resolução, adequado para dispositivos mais potentes. Se você não estiver conectado a um ponto de acesso Wi-Fi, isso será descontado do pacote de dados de sua operadora de telefonia." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4755,101 +4981,102 @@ msgstr "Digite o endereço do servidor. Inclua \":\" e o número da porta, se qu msgid "Invalid server address: %s." msgstr "Endereço inválido: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Reverso" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Dificuldade" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Voltas" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Tempo" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Kart" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Usuário" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Versão" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Não" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Pista" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Os %d melhores tempos" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Número de karts: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Meta de tempo: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Voltas: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Sentido reverso: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(nenhum)" @@ -4937,33 +5164,41 @@ msgid "Press any key..." msgstr "Pressione uma tecla qualquer..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Bate-papo desativado. Para habilitá-lo, acesse o menu de configurações." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Voltar para o Teste de Performance" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Sair do Teste de Performance" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Voltar à batalha" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Configurar novo jogo" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Reiniciar batalha" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Sair da batalha" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Nova corrida" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Sair da corrida" @@ -4979,11 +5214,11 @@ msgstr "%s ainda não obteve pontos." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s está em %d° lugar no ranking mundial, com %f pontos." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Nome de usuário e/ou email inválido." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5005,7 +5240,7 @@ msgstr "Modo fantasma" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Voltas: %i" @@ -5018,21 +5253,21 @@ msgstr "Tipo: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Resultado mínimo: %iº lugar" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Tempo mínimo necessário: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Pontos de Nitro Necessários: %i" @@ -5045,54 +5280,54 @@ msgstr "Quantidade de adversários: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Batalha" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Tipo de jogo" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Localização do servidor: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Pista atual: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Classificação" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Jogador" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Pontuação" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Tempo de jogo" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Remover dos favoritos" @@ -5105,74 +5340,74 @@ msgid "No player available for connecting to server." msgstr "Nenhuma conta de jogador disponível para se conectar ao servidor." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Nome de usuário: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Revogar solicitação" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Hoje" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "A solicitação foi enviada!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "A solicitação foi aceita!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Solicitação recusada!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Removido da lista de amigos!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Solicitação revogada!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Processando" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Baixando o último voto" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Para alterar a sua avaliação, clique em uma das estrelinhas." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Você ainda não votou neste complemento. Para votar, clique nas estrelinhas." -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Parabéns! Seu voto foi computado! " -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Computando o voto" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Sortear pista" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5201,7 +5436,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Houve um erro ao salvar seu campeonato" -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Escolha sua pista" @@ -5245,12 +5480,12 @@ msgstr "Você desbloqueou a pista %0" msgid "You unlocked grand prix %0" msgstr "Você desbloqueou o campeonato %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Pista" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5271,19 +5506,19 @@ msgstr "Digite o nome do campeonato" msgid "Please select a Grand Prix" msgstr "Escolha um campeonato" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Personalizado" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Nenhum nome foi inserido." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Já existe um campeonato com esse nome." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Nome comprido demais." @@ -5292,19 +5527,19 @@ msgstr "Nome comprido demais." msgid "Better luck next time!" msgstr "Melhor sorte na próxima vez!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Parabéns! Você superou um desafio!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Parabéns! Você venceu o campeonato!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "O campeonato chegou ao fim!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Quantidade de karts" @@ -5317,110 +5552,125 @@ msgstr "Deseja mesmo remover esse recorde?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Deseja mesmo remover todos os recordes?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Favorito" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Leve" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Intenso" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Conecte um teclado ou gamepad ao dispositivo para disponibilizar o modo multijogador local" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Sortear kart" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Bloqueado" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Atenção:\nPara entrar no jogo, cada jogador deve apertar o botão \"Selecionar/Avançar\" em seu respectivo controlador." -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Deseja jogar o tutorial do jogo?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Não é possível jogar online se não houver acesso à internet. Para ativá-lo, acesse o menu de configurações e marque a caixa \"Conectar-se à internet\"." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Sem acesso à internet, não é possível baixar complementos. Para ativá-lo, acesse o menu de configurações e marque a caixa \"Conectar-se à internet\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Sem acesso à internet, não é possível baixar complementos. Para ativá-lo, acesse o menu de configurações e marque a caixa \"Conectar-se à internet\".\n\nNo entanto, ainda assim é possível excluir complementos." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "O módulo dos complementos está desativado no menu de configurações" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Carregando complementos, aguarde..." -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Deseja mesmo sair do STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Criar servidor em rede local" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Servidor de %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Número de pistas no campeonato" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "O nome precisa ter entre 4 e 30 caracteres!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "A senha apresenta caracteres inválidos!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Pronto" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Entrar na partida" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Assistir" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Instalar complemento" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5428,7 +5678,7 @@ msgstr "Espere a partida atual (%s) chegar ao fim. Tempo restante estimado: %s." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Espere a partida atual chegar ao fim. Tempo restante estimado: %s." @@ -5436,24 +5686,24 @@ msgstr "Espere a partida atual chegar ao fim. Tempo restante estimado: %s." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Espere a partida atual (%s) chegar ao fim. Andamento: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Espere a partida atual chegar ao fim. Andamento: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Espere a partida atual chegar ao fim." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5463,7 +5713,7 @@ msgstr[2] "A partida se iniciará se houver mais de %d jogadores presentes." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5473,96 +5723,108 @@ msgstr[0] "Começando dentro de %d segundo ou quando todos pressionarem o botão msgstr[1] "A partida se iniciará em %d segundos ou após todos os jogadores apertarem o botão \"Pronto\"." msgstr[2] "A partida se iniciará em %d segundos ou após todos os jogadores apertarem o botão \"Pronto\"." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Entrando no servidor %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Procurando servidor para entrada imediata" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Tempo restante: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Objetivo" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Baixando lista de conquistas" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Perfil de %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Desde" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Situação" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Baixando lista de amigos" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Solicitação nova" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Pendente" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Desconectado" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Digite o novo e-mail no campo abaixo" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "O novo e-mail precisa ter de 5 a 254 caracteres!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Esse novo e-mail não é válido!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "E-mail alterado!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Não foi possível alterar o e-mail %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Novidades do blog do STK" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Data" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "No momento não há novidades disponíveis." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "É necessário estar conectado a uma conta online para se divertir na internet. Clique no seu nome de usuário, na parte de cima da tela, para se conectar." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Procurando" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Sair do jogo" @@ -5640,34 +5902,34 @@ msgid "Distance (km)" msgstr "Distância (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Desconhecido" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Nenhum endereço IPv4 detectado. Diversos servidores podem estar inacessíveis." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Nenhum endereço IPv6 detectado. Alguns servidores podem ficar inacessíveis." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Nenhum servidor disponível" -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Baixando lista de servidores" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Servidores favoritos" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5675,149 +5937,149 @@ msgstr "Se mais da metade dos jogadores selecionar a mesma pista e as mesmas con #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Itens em locais aleatórios" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Número de gols" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Sentido reverso" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Desafio indisponível. Supere os disponíveis para liberar outros!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Efeito" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Tecla ou botão" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Desabilitar controlador" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Habilitar controlador" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Habilitar configuração" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Comandos de jogo" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Comandos de navegação no menu" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Virar à esquerda" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Virar à direita" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Acelerar" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Frear / Ré" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Disparar item" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Usar nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Olhar para trás" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Chamar resgate" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Pausar o jogo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Para cima" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Para baixo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Esquerda" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Direita" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Selecionar/Avançar" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Cancelar/Voltar" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Mapeamentos em azul estão em conflito com outras configurações" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Mapeamentos em vermelho estão em conflito com outros, da mesma configuração" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5825,17 +6087,27 @@ msgid "" msgstr "Não é recomendável mapear a tecla \"Shift\" para um comando, pois os comandos só podem ser atribuídos um caractere maiúsculo ou minúsculo, e não para ambos." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Deseja mesmo excluir para sempre essa configuração?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Digite o novo nome da configuração. Deixe em branco para voltar ao nome predefinido." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Vertical" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Horizontal" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5843,89 +6115,74 @@ msgstr "Permite que os jogadores habilitem desvantagem para si no modo multijoga #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Instalar pacote de alta resolução" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Deseja mesmo desinstalar o pacote de alta resolução?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Teclado %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Dispositivo tátil" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Toque em um dispositivo para configurá-lo" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Idioma do sistema" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Canto inferior esquerdo" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "À direita" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Nenhum" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "No meio" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Vertical" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Horizontal" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Muito pequeno" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Pequeno" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Médio" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Grande" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Muito grande" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5935,128 +6192,133 @@ msgid "" msgstr "Só é possível habilitar o modo \"speedrun\" se o modo história já não tiver sido iniciado antes.\n\nSe o modo história for interrompido, a cronometragem do speedrun será anulada.\n\nCom isso, seria necessário criar um perfil novo para o reativar." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Sincronização vertical" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Com a sincronização vertical habilitada, a placa gráfica desenha novos quadros\napenas quando o monitor puder exibi-los." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "A sincronização vertical funcionará apenas se os drivers de vídeo forem compatíveis. " #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Partículas: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Personagens animados: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Luzes dinâmicas: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Dispersão da luz: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Suavização de bordas: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Oclusão ambiental (AO): %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Sombras: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Sombras: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Incandescência: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Brilho nos contornos: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Feixes de luz: %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Qualidade da imagem: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Detalhe de geometria: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Movimentos borrados: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Profundidade do campo visual: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Deseja habilitar o acesso à internet, que está desativado?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "É necessário informar a senha." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Desconectando a conta \"%s\"" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Conectando com a conta \"%s\"" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Não é possível excluir o único jogador presente." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Deseja mesmo excluir o jogador \"%s\"?" @@ -6084,7 +6346,7 @@ msgstr "GOL!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Aguardando os outros jogadores" @@ -6119,7 +6381,7 @@ msgstr "Siga o mestre!" msgid "Top %i" msgstr "Os %i primeiros" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Que pena! Não superou o desafio!" @@ -6143,102 +6405,199 @@ msgstr "Aperte no ícone do pódio para iniciar o desafio" msgid "Press fire to start the challenge" msgstr "Aperte o botão de disparo para iniciar" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Voltar para as configurações de vídeo" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Salvar os resultados do teste" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Voltar para o menu principal" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Sair do servidor" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Desistir do campeonato" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Reiniciar" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Voltar ao mapa dos desafios" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Correr contra o novo fantasma" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Voltar ao menu" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Deseja mesmo desistir do campeonato?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Relatório de performance salvo em \"%s\"." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Vitória do time vermelho" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Vitória do time azul" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Empatou!" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Eliminado aos %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Eliminado" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(gol contra)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Corrida %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Corridas disputadas:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Recordes" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Melhor volta: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "(de %s)" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Parabéns! Superou o desafio!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Que pena! Não superou o desafio!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Você alcançou os requisitos da dificuldade Super Tux!" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Resultados do Teste de Performance" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Duração do teste: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Número de quadros: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "FPS regular: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "FPS regular predominante: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "FPS típico: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Resolução horizontal: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Resolução vertical: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Iluminação dinâmica: ATIVADA" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Iluminação dinâmica: DESATIVADA" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Resolução de renderização: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Suavização: ATIVADA" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Suavização: DESATIVADA" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Iluminação baseada na imagem: DESATIVADA" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Iluminação baseada na imagem: ATIVADA" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Oclusão de ambiente: ATIVADA" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Oclusão de ambiente: DESATIVADA" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Resolução da sombra: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Diversos itens na pista, para ajudar a vencer!" @@ -6279,28 +6638,28 @@ msgstr "Aperte no ícone vermelho ou azul para trocar de time." #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Criada por %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Máximo de jogadores: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Karts vermelhos computadorizados" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Algumas pistas ainda precisam ser desbloqueadas para esse campeonato ficar disponível!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Bloqueado!" @@ -6322,10 +6681,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Supere todos os desafios para abrir o portal do chefão!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6334,41 +6695,48 @@ msgid "" msgstr "Você não tem pontos o suficiente\npara encarar esse desafio.\nOs desafios disponíveis\nestão indicados no mapa." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Aperte <%s> para acelerar, e <%s> e <%s> para fazer curvas." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Para acelerar, aperte na parte de cima do volante. Para fazer curvas, vire-o para os lados." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Para acelerar, puxe o acelerador para cima. Para fazer curvas, incline seu dispositivo para os lados." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Para acelerar, puxe o acelerador para cima. Para fazer curvas, gire o seu dispositivo." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Colete os presentes e aperte <%s> para destruir esses caixotes!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Colete os presentes e aperte o ícone da bola de boliche para destruir esses caixotes!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6376,34 +6744,41 @@ msgid "" msgstr "Aperte <%s> para olhar para trás.\nPara atirar para trás, aperte <%s> enquanto aperta <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Para olhar para trás, aperte o ícone do espelho.\nPara atirar para trás, aperte o ícone do espelho e deslize o dedo para o da bola de boliche!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Aperte <%s> para usar o nitro!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Aperte o ícone do nitro para utilizá-lo." #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Colete os cilindros de nitro. Eles serão utilizados depois desta curva." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Aperte <%s> quando estiver em apuros." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Aperte o ícone do pássaro para ser resgatado!" #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6411,24 +6786,27 @@ msgid "" msgstr "Para derrapar, comece a virar o kart e aperte <%s>, sem soltar.\nDerrapadas curtas ajudam a fazer uma curva mais fechada." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Para derrapar, acelere e aperte o ícone da derrapagem, sem soltar.\nDerrapadas curtas ajudam a fazer uma curva mais fechada." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Se você derrapar por um tempo, aparecerão faíscas que aumentam a velocidade após a derrapagem." #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Agora você está pronto para as corridas. Divirta-se!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Corridas de kart em 3D e código aberto" @@ -6438,7 +6816,7 @@ msgstr "Corridas de kart em 3D e código aberto" msgid "tux;game;race;" msgstr "tux;jogo;corrida;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6446,7 +6824,7 @@ msgid "" "for all ages." msgstr "Karts. Nitro. Ação! O SuperTuxKart é um jogo de corrida tridimensional e de código aberto, com grande variedade de personagens, pistas e modos de jogo. Focamos mais na diversão do que no realismo, procurando agradar a todas as idades." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6455,7 +6833,7 @@ msgid "" "your opponents." msgstr "Há diversos tipos de pistas no SuperTuxKart. Temos pistas debaixo d'água, no meio rural, na selva e até mesmo no espaço! Abuse de suas habilidades na direção para se desviar dos outros karts e das bananas, e tome cuidado com as bolas de boliche, os chicletes, as tortas e os desentupidores atirados pelos adversários." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6464,27 +6842,27 @@ msgid "" "your racing skills!" msgstr "Participe de corridas, entre em campeonatos, diminua seu tempo nas pistas, mostre seu talento com a bola e encare seus adversários no modo batalha! Para mostrar do que é capaz, entre no modo online e enfrente jogadores de todas as partes do mundo!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Este jogo não contém anúncios." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Esta é uma versão experimental do SuperTuxKart. Ela contém diversas melhorias que estão sendo testadas pelos usuários antes de serem implementadas em definitivo na próxima versão oficial." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Essa versão de testes pode ser instalada junto com a versão oficial em um mesmo dispositivo." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Se você deseja mais estabilidade, recomendamos instalar a versão oficial: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "A equipe do SuperTuxKart" diff --git a/data/po/ro.po b/data/po/ro.po index 9d352e530b0..f65c04e0a1a 100644 --- a/data/po/ro.po +++ b/data/po/ro.po @@ -3,7 +3,8 @@ # This file is distributed under the same license as the supertuxkart package. # # Translators: -# Dominik Jastrzębski, 2022-2024 +# Daniel Șerbănescu , 2025 +# Dominic Iastrebschi, 2022-2024 # Har Gosmos , 2019 # Nicolae Crefelean, 2015,2017-2018 # Sorin Ingeaua , 2020 @@ -11,9 +12,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Dominik Jastrzębski, 2022-2024\n" +"Last-Translator: Daniel Șerbănescu , 2025\n" "Language-Team: Romanian (http://app.transifex.com/supertuxkart/supertuxkart/language/ro/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -27,11 +28,11 @@ msgstr "Se extrag datele jocului..." #. I18N: In Android UI, po_extract_error msgid "Game data extraction error" -msgstr "Eroare extragere date joc" +msgstr "Eroare la extragerea datelor jocului" #. I18N: In Android UI, po_extract_error_msg msgid "Check remaining device space or reinstall SuperTuxKart." -msgstr "Verifică spațiul rămas pe dispozitiv sau reinstalați SuperTuxKart." +msgstr "Verificați spațiul rămas pe dispozitiv sau reinstalați SuperTuxKart." #. I18N: In Android UI, po_quit #. I18N: ./data/gui/screens/main_menu.stkgui @@ -53,7 +54,7 @@ msgstr "Lovitură!" #. I18N: ./data/achievements.xml msgid "Hit 10 karts with a bowling-ball." -msgstr "Lovește 10 karturi cu o minge de popice." +msgstr "Lovește 10 carturi cu o minge de popice." #. I18N: ./data/achievements.xml msgid "Arch Enemy" @@ -61,7 +62,7 @@ msgstr "Adversar suprem" #. I18N: ./data/achievements.xml msgid "Hit the same kart at least 5 times in one race." -msgstr "Lovește același kart de cel puțin 5 ori în aceeași cursă." +msgstr "Lovește același cart de cel puțin 5 ori în aceeași cursă." #. I18N: ./data/achievements.xml msgid "Marathoner" @@ -77,7 +78,7 @@ msgstr "As în derapaje" #. I18N: ./data/achievements.xml msgid "Skid 5 times in a single lap." -msgstr "Patinează de 5 ori într-o rundă" +msgstr "Derapează de 5 ori într-o rundă." #. I18N: ./data/achievements.xml msgid "Gold driver" @@ -87,15 +88,15 @@ msgstr "Pilot de aur" msgid "" "Win against at least 3 AIs in normal race, time-trial, and follow the " "leader." -msgstr "Câștiga împotriva a cel puțin 3 roboți în cursa normală, cursa cronometrată, și urmărește liderul." +msgstr "Câștigă împotriva a cel puțin 3 oponenți roboți în cursa normală, în cursa cronometrată, și în urmărirea liderului." #. I18N: ./data/achievements.xml msgid "Powerup Love" -msgstr "Dragoste de powerup-uri" +msgstr "Îndrăgostit de bonusuri" #. I18N: ./data/achievements.xml msgid "Use 10 or more powerups in a race." -msgstr "Folosește peste 10 powerup-uri într-o cursă." +msgstr "Folosește peste 10 bonusuri într-o cursă." #. I18N: ./data/achievements.xml msgid "Unstoppable" @@ -105,15 +106,15 @@ msgstr "De neoprit" msgid "" "Win 5 single races in a row against at least 3 AIs. Beware, restarting a " "race counts as a loss." -msgstr "Câștigă 5 curse la rând împotriva a cel puțin 3 AIs. Atenție, repornirea unei curse este considerată o pierdere." +msgstr "Câștigă 5 curse la rând împotriva a cel puțin 3 oponenți roboți. Atenție, repornirea unei curse este considerată o pierdere." #. I18N: ./data/achievements.xml msgid "Banana Lover" -msgstr "Fan banane" +msgstr "Îndrăgostit de banane" #. I18N: ./data/achievements.xml msgid "Collect at least 5 bananas in one race." -msgstr "Colectează minim 5 banane într-o cursă." +msgstr "Colectează cel puțin 5 banane într-o cursă." #. I18N: ./data/achievements.xml msgid "It's secret" @@ -125,27 +126,27 @@ msgstr "Serios... e secret." #. I18N: ./data/achievements.xml msgid "Mosquito Hunter" -msgstr "Vânătoarea de țânțari" +msgstr "Vânător de țânțari" #. I18N: ./data/achievements.xml msgid "" "Take your opponents for mosquitos! With the swatter, squash them at least 5 " "times in a race." -msgstr "Luați adversarii ca țânțari! Cu swatter, zdrobește-i de cel puțin 5 ori într-o cursă." +msgstr "Tratați adversarii ca țânțari! Zdrobește-i de cel puțin 5 ori cu paleta de țânțari într-o cursă." #. I18N: ./data/achievements.xml msgid "Beyond Luck" -msgstr "Dincolo de noroc" +msgstr "Supra norocos" #. I18N: ./data/achievements.xml msgid "" "Win 10 single races in a row in Expert or SuperTux against at least 5 AIs. " "Beware, restarting a race counts as a loss." -msgstr "Câștigă 10 curse individuale la rând în Expert sau SuperTux împotriva a cel puțin 5 AIs. Atenție, repornirea unei curse este considerată o pierdere." +msgstr "Câștigă 10 curse individuale la rând în modurile Expert sau SuperTux împotriva a cel puțin 5 oponenți roboți. Atenție, repornirea unei curse este considerată o pierdere." #. I18N: ./data/grandprix/1_penguinplayground.grandprix msgid "Penguin Playground" -msgstr "Curtea Penguinilor" +msgstr "Zona de joacă a pinguinilor" #. I18N: ./data/grandprix/2_offthebeatentrack.grandprix msgid "Off the Beaten Track" @@ -170,7 +171,7 @@ msgstr "La sfârșitul lumii" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Înapoi" @@ -186,13 +187,13 @@ msgstr "Dezinstalează" #. I18N: ./data/gui/dialogs/android/init_android.stkgui msgid "Select a type of control that you prefer" -msgstr "Selecteaza tipul de control pe care il preferi." +msgstr "Selectați tipul preferat de control " #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Accelometru" @@ -206,13 +207,13 @@ msgstr "Accelometru" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Giroscop" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Volan" @@ -224,7 +225,7 @@ msgstr "Accelerație automată" #. I18N: ./data/gui/dialogs/android/init_android.stkgui msgid "You can change it later in touch device settings." -msgstr "Puteți să o modificați ulterior în setările dispozitivului tactil." +msgstr "Puteți să o modificați ulterior în configurările dispozitivului tactil." #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui @@ -239,42 +240,44 @@ msgstr "Aplică" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui msgid "Touch Device Settings" -msgstr "Atingeți Setări dispozitiv" +msgstr "Configurări pentru dispozitivul tactil" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" -msgstr "General" +msgstr "Generale" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -289,12 +292,12 @@ msgstr "Butoane inversate" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Buttons scale" -msgstr "Marimea Butonului" +msgstr "Mărimea butoanelor" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Advanced" -msgstr "Advansat" +msgstr "Avansate" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -313,7 +316,7 @@ msgstr "Sensitivitatea Y" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui msgid "Restore defaults" -msgstr "Restabiliti setarile de baza" +msgstr "Restabilește la implicite" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog @@ -339,30 +342,33 @@ msgstr "Restabiliti setarile de baza" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Anulează" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Da" @@ -371,7 +377,7 @@ msgstr "Da" #. I18N: In the 'confirm resolution' dialog, that's shown when switching #. resoluton msgid "Revert" -msgstr "Reveni" +msgstr "Restabilește" #. I18N: ./data/gui/dialogs/confirm_resolution_dialog.stkgui #. I18N: In the 'confirm resolution' dialog, that's shown when switching @@ -379,21 +385,21 @@ msgstr "Reveni" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog msgid "Accept" -msgstr "Acceptați" +msgstr "Acceptă" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui msgid "Camera Settings" -msgstr "Setările camerei" +msgstr "Configurări cameră" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera settings msgid "Player camera" -msgstr "Cameră de la jucător" +msgstr "Camera jucătorului" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "FOV" -msgstr "FOV" +msgstr "Câmp vizual" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -413,7 +419,7 @@ msgstr "Cameră netedă" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera settings msgid "Backward camera" -msgstr "Cameră pe spate" +msgstr "Camera din spate" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -423,11 +429,11 @@ msgstr "Urmează mingea în modul fotbal" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "Reset" -msgstr "Reset" +msgstr "Restabilește" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui msgid "Graphics Settings" -msgstr "Setări grafice" +msgstr "Configurări grafice" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -442,22 +448,22 @@ msgstr "Umbre" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Bloom" -msgstr "Bloom" +msgstr "Lumină difuză" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Light shaft (God rays)" -msgstr "Arborele luminii (razele lui Dumnezeu)" +msgstr "Raze de lumină (raze divine)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Ambient occlusion" -msgstr "Ocluzia ambientală" +msgstr "Ocluzie ambientală" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Depth of field" -msgstr "Adancimea terenului" +msgstr "Adâncimea câmpului" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -472,22 +478,22 @@ msgstr "Anti-aliasing" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Motion blur" -msgstr "Neclaritate de miscare" +msgstr "Neclaritate în mișcare" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Image-based lighting" -msgstr "illuminare bazată pe imagine" +msgstr "Iluminare bazată pe imagine" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Light Scattering" -msgstr "Împrăștierea de lumina" +msgstr "Dispersarea luminii" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Animated characters" -msgstr "Caractere Animate" +msgstr "Caractere animate" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -502,17 +508,17 @@ msgstr "Efecte asupra particulelor" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Rendered image quality" -msgstr "Calitatea imaginii redate" +msgstr "Calitatea imaginii randate" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Geometry detail" -msgstr "Detali Geometrice" +msgstr "Detalii geometrice" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "* Restart STK to apply new settings" -msgstr "* Repornește STK pentru aplicarea noilor setări" +msgstr "* Reporniți STK pentru a aplica noile configurări" #. I18N: ./data/gui/dialogs/debug_slider.stkgui #. I18N: ./data/gui/dialogs/online/recovery_info.stkgui @@ -540,9 +546,9 @@ msgstr "Intră" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -555,7 +561,7 @@ msgstr "OK" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen msgid "Record the race for ghost replay" -msgstr "Înregistrați cursa pentru reluarea fantomelor" +msgstr "Înregistrați cursa pentru a vizualiza reluarea" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info action @@ -576,7 +582,7 @@ msgstr "Comparați cu o altă fantomă" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item msgid "Remove" -msgstr "Elimina" +msgstr "Elimină" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info screen action @@ -598,19 +604,19 @@ msgstr "Începe cursa" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Objective shown in achievement dialog msgid "Goal" -msgstr "Tinta" +msgstr "Gol" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Progres" #. I18N: ./data/gui/dialogs/online/change_password.stkgui #. I18N: In the change password dialog msgid "Password Change" -msgstr "Schimbă parola" +msgstr "Schimbarea parolei" #. I18N: ./data/gui/dialogs/online/change_password.stkgui #. I18N: In the change password dialog @@ -638,7 +644,7 @@ msgstr "Trimite" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Înapoi la cursă" @@ -655,7 +661,7 @@ msgstr "Înapoi la lobby" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Reîncepe cursa" @@ -664,7 +670,7 @@ msgstr "Reîncepe cursa" #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button msgid "Give Up Race" -msgstr "Ieși din cursă" +msgstr "Renunță la cursă" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button @@ -695,7 +701,7 @@ msgstr "Top 10 jucători" #. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui msgid "Refresh" -msgstr "Reîncarca" +msgstr "Reîncarcă" #. I18N: ./data/gui/dialogs/online/recovery_info.stkgui #. I18N: In the recovery dialog @@ -709,24 +715,24 @@ msgstr "Recuperarea contului" msgid "" "You will receive an email with further instructions on how to reset your " "password. Please be patient and be sure to check your spam folder." -msgstr "Veți primi un e-mail cu instrucțiuni suplimentare despre cum să vă resetați parola. Vă rugăm să aveți răbdare și să vă asigurați că vă verificați dosarul de spam." +msgstr "Veți primi un e-mail cu instrucțiuni suplimentare despre cum să restabiliți parola. Aveți răbdare și asigurați-vă că verificați și dosarul de spam." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui msgid "" "Fill in the username and email address you supplied at registration to be " "able to reset your password." -msgstr "Completați numele de utilizator și adresa de e-mail pe care le-ați furnizat la înregistrare pentru a vă putea reseta parola." +msgstr "Completați numele de utilizator și adresa de e-mail pe care le-ați furnizat la înregistrare pentru a vă putea restabili parola." #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" -msgstr "Numele" +msgstr "Nume de utilizator" #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog @@ -738,7 +744,7 @@ msgstr "Email" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog msgid "Terms and Agreement" -msgstr "Termeni și acord" +msgstr "Termeni și condiții" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog @@ -765,9 +771,9 @@ msgstr "Dificultate" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" -msgstr "Novice" +msgstr "Începător" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: Difficulty @@ -777,7 +783,7 @@ msgstr "Novice" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Intermediar" @@ -789,7 +795,7 @@ msgstr "Intermediar" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Expert" @@ -801,7 +807,7 @@ msgstr "Expert" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -809,8 +815,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Modul de joc" @@ -821,10 +827,10 @@ msgstr "Modul de joc" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" -msgstr "Cursa normală" +msgstr "Cursă normală" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: Multiplayer game mode @@ -835,52 +841,53 @@ msgstr "Cursa normală" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" -msgstr "Cursa contra timp" +msgstr "Cursă contra timp" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" -msgstr "Batalie" +msgstr "Bătălie" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Fotbal" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" -msgstr "Parola" +msgstr "Parolă" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" -msgstr "Marcați acest server" +msgstr "Salvați acest server" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "Add player" -msgstr "Adăugați jucător" +msgstr "Adaugă jucător" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Nume" @@ -892,12 +899,12 @@ msgstr "Handicap" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "Press the 'All players ready' button after the player list is ready." -msgstr "Apăsați butonul „Toți jucătorii gata” după ce lista de jucători este gata." +msgstr "Apăsați butonul „Toți jucătorii pregătiți” după ce lista de jucători este gata." #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "Clear players" -msgstr "Jucători limpezi" +msgstr "Elimină jucătorii" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network @@ -917,62 +924,106 @@ msgstr "Ștergeți prietenul" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Add Friend" -msgstr "Adăugați prieten" +msgstr "Adăugați un prieten" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Accept Invite" -msgstr "Acceptați invitația" +msgstr "Acceptă invitația" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Decline Invite" -msgstr "Respingeți invitația" +msgstr "Refuză invitația" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "View Profile" -msgstr "Afișați profilul" +msgstr "Arată profilul" #. I18N: ./data/gui/dialogs/online/vote_dialog.stkgui #. I18N: In the vote dialog msgid "Vote" -msgstr "Votați" +msgstr "Votează" #. I18N: ./data/gui/dialogs/overworld_dialog.stkgui #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui msgid "Paused" -msgstr "Pauza" +msgstr "În pauză" #. I18N: ./data/gui/dialogs/overworld_dialog.stkgui #. I18N: In the in-game dialog msgid "Back to Game" -msgstr "Înapoi in joc" +msgstr "Înapoi la joc" #. I18N: ./data/gui/dialogs/overworld_dialog.stkgui #. I18N: In the in-game dialog msgid "Back to menu" -msgstr "Înapoi in meniu" +msgstr "Înapoi la meniu" #. I18N: ./data/gui/dialogs/overworld_dialog.stkgui #. I18N: In the in-game dialog msgid "Select kart" -msgstr "Selectați kartul" +msgstr "Selectați cartul" #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When changing input configurations msgid "Press fully and release..." -msgstr "Apăsați complet și eliberați ..." +msgstr "Apăsați complet apoi eliberați..." #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input msgid "Assign to ESC key" -msgstr "Alocați cheii ESC" +msgstr "Alocă la tasta ESC" #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input msgid "Assign nothing" -msgstr "Nu alocați nimic" +msgstr "Nu aloca nimic" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Configurări video recomandate" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Configurările recomandate vor fi valide pentru rezoluția curentă." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Care sunt prioritățile configurărilor?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Performanța" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Echilibru între performanță și calitatea graficii" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Calitatea graficii" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Economisirea energiei" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Doriți ca efectele grafice să creeze neclaritate?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Începe testul" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui @@ -988,13 +1039,13 @@ msgstr "Configurarea cursei" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" -msgstr "Continuați" +msgstr "Continuă" #. I18N: ./data/gui/screens/addons_screen.stkgui msgid "SuperTuxKart Addons" @@ -1015,7 +1066,7 @@ msgstr "Evaluare >=" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In the addons screen msgid "Karts" -msgstr "Karturi" +msgstr "Cart-uri" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In the addons screen @@ -1033,10 +1084,15 @@ msgstr "Arene" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Instalat" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Editează arene favorite" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1046,20 +1102,20 @@ msgstr "Instalat" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Standard" @@ -1070,12 +1126,12 @@ msgstr "Standard" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Suplimente" @@ -1089,34 +1145,35 @@ msgstr "Suplimente" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Toate" #. I18N: ./data/gui/screens/credits.stkgui #. I18N: Title in credits screen msgid "Credits" -msgstr "Autori" +msgstr "Credite" #. I18N: ./data/gui/screens/cutscene.stkgui msgid "Skip" @@ -1134,23 +1191,23 @@ msgstr "Toate piesele" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Title in edit grand prix screen msgid "Edit Grand Prix" -msgstr "Editați Marele Premiu" +msgstr "Editați marele premiu" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item msgid "Move up" -msgstr "Mișcați în sus" +msgstr "Mută în sus" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item msgid "Move down" -msgstr "Mișcați în jos" +msgstr "Mută în jos" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Adaugă" @@ -1160,12 +1217,12 @@ msgstr "Adaugă" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item msgid "Edit" -msgstr "Editați" +msgstr "Editare" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item msgid "Save" -msgstr "Salvați" +msgstr "Salvează" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: In the edit track screen @@ -1175,7 +1232,7 @@ msgstr "Numărul de ture:" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: In the edit track screen msgid "Reverse:" -msgstr "Cu spatele" +msgstr "Cu spatele:" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen @@ -1187,7 +1244,7 @@ msgstr "Selecția reluării fantomei" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Vânătoare de ouă" @@ -1199,32 +1256,32 @@ msgstr "Arătați doar cele mai bune timpuri" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Compare replay" -msgstr "Comparați reluarea" +msgstr "Compară reluarea" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Only show replays matching the current difficulty" -msgstr "Afișați doar reluări care se potrivesc cu dificultatea curentă" +msgstr "Arată doar reluări care se potrivesc cu dificultatea curentă" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Only show replays matching the current version" -msgstr "Afișați numai redări care corespund versiunii actuale" +msgstr "Arată numai reluări care corespund versiunii actuale" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Hide multiplayer replays" -msgstr "Ascundeți redările multiplayer" +msgstr "Ascunde reluările cu mai mulți jucători" #. I18N: ./data/gui/screens/ghost_replay_selection.stkgui #. I18N: In the ghost replay selection screen msgid "Record a ghost replay" -msgstr "Înregistrați o reluare fantomă" +msgstr "Înregistrează o reluare fantomă" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen msgid "AI karts" -msgstr "Karturi IA" +msgstr "Cart-uri robot" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen @@ -1234,10 +1291,10 @@ msgstr "Înapoi" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Timp maxim (min.)" @@ -1255,7 +1312,7 @@ msgstr "Continuați GP-ul salvat" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Title in grand prix editor screen msgid "Grand Prix editor" -msgstr "Editor de marele premiu" +msgstr "Editor de Grand Prix" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item @@ -1269,9 +1326,9 @@ msgstr "Copiază" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1280,82 +1337,82 @@ msgstr "Redenumește" #. I18N: ./data/gui/screens/grand_prix_lose.stkgui #. I18N: ./data/gui/screens/grand_prix_win.stkgui msgid "Save Grand Prix" -msgstr "Salvați Marele Premiu" - -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +msgstr "Salvați Grand Prix" + +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Ajutor SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Moduri de joc" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" -msgstr "Powerupuri" +msgstr "Bonusuri" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Banane" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1363,115 +1420,116 @@ msgstr "Banane" msgid "Story Mode" msgstr "Modul poveste" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" -msgstr "Clasa Karturilor" +msgstr "Clasele carturilor" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" -msgstr "Multiplayer" +msgstr "Jucători multipli" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" -msgstr "Începe tutorialul" +msgstr "Începe practica" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." -msgstr "Colectați cadourile albastre ca să primiți powerup" +msgstr "Colectați cadourile albastre pentru a primi bonusuri." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" -msgstr "Evită bananele!" +msgstr "Evitați bananele!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " "pressing the appropriate key or button. You can see your current level of " "nitro in the gauge at the bottom-right of the race screen." -msgstr "Colectarea nitro vă permite să obțineți creșteri de viteză ori de câte ori doriți, apăsând tasta sau butonul corespunzător. Puteți vedea nivelul dvs. actual de nitro în tubul din partea dreaptă jos a ecranului cursei." +msgstr "Colectând nitro puteți obține creșteri de viteză ori de câte ori doriți, apăsând tasta sau butonul corespunzător. În timpul cursei puteți vedea nivelul vostru actual de nitro în tubul din partea dreaptă jos a ecranului." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." -msgstr "Dacă vedeți un buton cu o blocare ca acesta, trebuie să faceți o provocare pentru a-l debloca." +msgstr "Dacă vedeți un buton cu un lacăt ca acesta, trebuie să completați o provocare pentru a-l debloca." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " "help to take sharp turns; while medium skids will boost your speed, long " "skids more so. You can't stop turning while skidding, so orient your kart " "carefully before!" -msgstr "Puteți derula apăsând o tastă sau un buton special. Patinajele scurte succesive ajută la luarea de viraje bruste; în timp ce derapajele medii vă vor crește viteza, derapajele lungi cu atât mai mult. Nu te poți opri din virare în timp ce derapezi, așa că orientează-ți kartul cu atenție înainte!" +msgstr "Puteți derapa apăsând o tastă sau un buton special. Derapajele scurte succesive ajută la viraje bruște; în timp ce derapajele medii vă vor crește viteza, derapajele lungi cu atât mai mult. Virajul nu se poate opri în timpul derapării, așa că orientați-vă cartul cu atenție dinainte!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." -msgstr "" +msgstr "Puteți primi un avans de start dacă apăsați butonul de accelerare la comanda „Pregătiți!”, înainte de începutul cursei." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Tastele de control se pot vedea/modifica în meniul Opțiuni" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" -msgstr "" +msgstr "SuperTuxKart vine cu mai multe moduri de joc:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" -msgstr "" +msgstr "Cursă normală: Toate tipurile de lovituri sunt permise, deci colectați bonusuri și folosiți-le inteligent!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" -msgstr "" +msgstr "Contra timp: Nu conține bonusuri, deci doar abilitățile de a conduce contează!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " "disqualified every time the counter hits zero. Beware: going in front of the" " leader will get you eliminated too!" -msgstr "Urmează liderul: aleargă pentru locul doi, deoarece ultimul kart va fi descalificat de fiecare dată când contorul atinge zero. Atenție: să mergi în fața liderului te va elimina și pe tine!" +msgstr "Urmează liderul: vizați locul doi, deoarece ultimul cart va fi descalificat de fiecare dată când contorul atinge zero. Atenție: dacă ajungeți în fața liderului veți fi eliminat!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1481,30 +1539,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." -msgstr "Folosestesti kartul ca sa impingi mingea in poarta" +msgstr "Fotbal: Folosește cartul pentru a împinge mingea în poartă." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." -msgstr "" +msgstr "Vânătoare de ouă: Explorează traseele pentru a găsi toate ouăle ascunse." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" -msgstr "" +msgstr "Derularea fantomei: Rulează împotriva derulării unei fantome în modul contra timp sau modul de vânătoare de ouă și înregistrează un nou record!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." -msgstr "" +msgstr "Contra tură: Completează cât de multe ture posibile în intervalul de timp dat." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1513,167 +1571,167 @@ msgid "" "wins the cup." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" -msgstr "" +msgstr "Pentru a vă asigura victoria, există niște bonusuri pe care le puteți colecta:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." -msgstr "" +msgstr "Guma de mestecat - vă protejează cu un scut, sau folosit în timp ce vă uitați înapoi va lăsa o baltă lipicioasă roză în spatele vostru." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" -msgstr "Controlați kartul" +msgstr "Fermuar - vă va da un avânt puternic de viteză. Dar aveți grijă să nu pierdeți controlul cartului!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." -msgstr "" +msgstr "Prăjitura - se aruncă către cel mai apropiat rival, cel mai bine utilizată la distanțe scurte dar și lungi. Afectează de asemenea și alte carturi în proximitatea exploziei." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." -msgstr "" +msgstr "Desfundător - aruncați-l înainte pentru a trage oponentul înapoi, sau aruncați-l în spate pentru a orbi oponentul." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." -msgstr "Dacă te uiți in spate, o să arunci în spate" +msgstr "Mingea de popice - va merge drept înainte până va lovi, poate ricoșa din pereți. Dacă vă uitați în spate, va fi aruncată înapoi." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Parasuta - incetinește toate karturile in poziții bune" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." -msgstr "" +msgstr "Schimbătorul - pentru scurt timp, cutiile cu cadouri vor fi transformate în banane, canistrele de nitro în gume de mestecat, și invers." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." -msgstr "" +msgstr "Mingea de basket - sare înspre lider, și poate strivi sau încetini carturile de-a lungul drumului." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." -msgstr "" +msgstr "Paleta de țânțari - va strivi carturile din apropiere, încetinindu-le. Poate fi folosită și la eliminarea parașutelor sau bombelor." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Lovirea unei banane poate duce la atașarea la kart a unuia dintre următoarele:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." -msgstr "" +msgstr "Ancora - încetinește instant cartul." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." -msgstr "" +msgstr "Parașuta - încetinește cartul mai intens decât ancora. Cu cât mai mult se accelerează cu atât mai mult vă va încetini." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." -msgstr "" +msgstr "Bomba - detonează după un timp, aruncând cartul în aer. Dacă vă atingeți de alt cart bomba se va transfera aceluia." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Maleficul Nolok l-a capturat pe Gnu! Iată câteva sfaturi pentru a vă ajuta:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " "completed. In the top-right of the screen, it also tells you how many points" " you currently have. Complete as many challenges as possible, and Nolok will" " accept to race against you. Win to liberate Gnu!" -msgstr "Această pictogramă de pe minimap arată provocările disponibile pe care nu le-ați finalizat. În partea dreaptă sus a ecranului, vă spune, de asemenea, câte puncte aveți în prezent. Finalizează cât mai multe provocări posibil, iar Nolok va accepta să concureze împotriva ta. Victorie pentru eliberarea lui Gnu!" +msgstr "Această iconiță de pe harta-miniatură arată provocările disponibile pe care nu le-ați finalizat. În partea dreaptă sus a ecranului, vă arată, de asemenea, câte puncte aveți în prezent. Finalizează cât mai multe provocări posibile, iar Nolok va accepta să concureze împotriva ta. Luptă pentru eliberarea lui Gnu!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " "points. The higher the difficulty you completed the challenge in, the better" " the cup and the more points it is worth." -msgstr "" +msgstr "Când completați o provocare veți primi o cupă. Fiecare cupă valorează mai multe puncte. Cu cât dificultatea provocării este mai mare cu atât este mai bună cupa și cu atât mai multe puncte valorează." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." -msgstr "" +msgstr "Când obțineți numărul de puncte indicat sub această iconiță veți primi cadou o surpriză. Sunt mai multe surprize de colectat." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" -msgstr "" +msgstr "Nu toate carturile se conduc la fel! Ele aparțin unor clase cu mai multe diferențe:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " "medium and heavy. Heavier karts are less affected by parachutes and are more" " resistant to explosions." -msgstr "" +msgstr "Masă - sunt trei clase de carturi, în funcție de masa lor: ușoare, medii și grele. Carturile mai grele sunt afectate mai puțin de parașute și sunt mai rezistente la explozii." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " "with a lot of sharp curves. The lighter the kart, the faster it accelerates," " especially at low speeds." -msgstr "" +msgstr "Accelerație - utile în special la început, după un accident, sau în curse cu multe curbe strânse. Cu cât mai ușor este cartul, cu atât va accelera mai rapid, în special la viteze joase." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " "in tracks with straight lines and gentle curves. Heavier karts have a higher" " top speed." -msgstr "" +msgstr "Viteza maximă - cu cât este mai mare, cu atât mai rapid poate avansa cartul. Este utilă în special în curse cu linii drepte și curbe line. Carturile mai grele au o viteză de top mai mare." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." -msgstr "" +msgstr "Eficiența nitro - Cu cât este mai ridicat, cu atât puteți obține o viteză mai mare de la nitro. Un cart mai ușor va avea o eficiență nitro mai mare." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " "slipstream speed bonus when you overtake it. The lighter your kart, the " "easier it is." -msgstr "Dacă urmează îndeaproape un alt kart timp de câteva secunde, vei primi un bonus de viteză slipstream atunci când îl depășiți. Cu cât kartul tău este mai ușor, cu atât este mai ușor." +msgstr "Dacă urmați îndeaproape un alt kart timp de câteva secunde, veți primi un bonus de viteză pentru rezistența aerodinamică atunci când îl depășiți. Cu cât cartul este mai ușor, cu atât va fi mai ușor să obțineți bonusul." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" -msgstr "" +msgstr "SuperTuxKart poate fi jucat online în modul jucători multipli...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1681,9 +1739,9 @@ msgid "" "options). Then, you can either create your own server with custom options, " "or search among a list of existing servers to join. Some of them are " "recommended servers with optionally ranked races." -msgstr "" +msgstr "Mai întâi, selectați iconița „online” din meniul principal. Alegeți fie rețeaua locală, sau rețeaua globală (necesită ca internetul să fie activat în meniul opțiuni). Apoi puteți fie crea propriul server cu opțiuni personalizate, sau să căutați în lista cu servere existente. Unele servere sunt recomandate cu curse evaluate opțional." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1691,14 +1749,14 @@ msgid "" " enough players. Then, you can choose your kart and vote for the next track " "to race on. An addon track is allowed only if it exists on all joined " "players and the server." -msgstr "" +msgstr "Odată ce sunteți conectați la un server, cursa va începe de îndată ce deținătorul (marcat cu o coroană) va decide să pornească. Serverele oficiale pot decide să înceapă automat o cursă numai când există suficienți jucători. Apoi veți putea alege cartul și să votați pentru viitoarea cursă. O cursă adițională este permisă numai dacă există la toți jucătorii de pe server." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" -msgstr "" +msgstr "... sau pe același dispozitiv:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1706,9 +1764,9 @@ msgid "" "keyboard(s), each player will need a different set of keys, and most " "keyboards are not appropriate for multiplayer because they don't support " "multiple simultaneous keypresses." -msgstr "" +msgstr "Mai întâi, veți avea nevoie de mai multe dispozitive de intrare. Utilizați meniul cu configurările dispozitivelor pentru a le configura. Mai multe gamepad-uri sau joystick-uri sunt ideale: la tastaturi fiecare jucător va avea nevoie de un set diferit de taste, și majoritatea tastaturilor nu sunt adecvate pentru apăsarea simultană a mai multor taste." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1716,7 +1774,7 @@ msgid "" "keyboard to join the game, and use their input device to select their kart. " "The game continues when everyone selected their kart. Note that the mouse " "may not be used for this operation." -msgstr "" +msgstr "Când dispozitivele de intrare sunt configurate, selectați iconița „Jucători multipli pe același ecran” din meniul principal. Fiecare jucător poate apăsa tasta sau butonul „trage” pentru a se alătura jocului și apoi să folosească dispozitivul lor pentru a alege cartul favorit. Jocul continuă când fiecare și-a selectat cartul. Luați aminte că mausul nu poate fi folosit pentru aceasta." #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen @@ -1728,17 +1786,17 @@ msgstr "" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" -msgstr "" +msgstr "Contra tură" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Grand Prix" @@ -1747,7 +1805,21 @@ msgstr "Grand Prix" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: In the kart selection (player setup) screen msgid "Choose a Kart" -msgstr "Alege un kart" +msgstr "Alegeți un cart" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Clasa cartului" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Modificați carturile favorite" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1757,16 +1829,16 @@ msgstr "Modul singur" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Splitscreen Multiplayer" -msgstr "" +msgstr "Jucători multipli pe același ecran" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Online" @@ -1779,26 +1851,26 @@ msgstr "Suplimente" #. I18N: In the main screen #: src/states_screens/race_gui_overworld.cpp:530 msgid "Tutorial" -msgstr "" +msgstr "Ghid" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" -msgstr "" +msgstr "Scoruri ridicate" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Realizări" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen msgid "Grand Prix Editor" -msgstr "" +msgstr "Editor de Grand Prix" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen @@ -1808,95 +1880,95 @@ msgstr "Despre joc" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen msgid "Server Creation" -msgstr "" +msgstr "Creare server" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen msgid "Name of the server" -msgstr "" +msgstr "Numele serverului" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen msgid "Max. number of players" -msgstr "" +msgstr "Numărul maxim de jucători" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen msgid "Password for private server (optional)" -msgstr "" +msgstr "Parolă pentru serverul privat (opțională)" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen msgid "Create" -msgstr "" +msgstr "Crează" #. I18N: ./data/gui/screens/online/lan.stkgui msgid "Local Networking" -msgstr "" +msgstr "Rețeaua locală" #. I18N: ./data/gui/screens/online/lan.stkgui #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen msgid "Find Server" -msgstr "" +msgstr "Caută server" #. I18N: ./data/gui/screens/online/lan.stkgui #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" -msgstr "" +msgstr "Creează server" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" -msgstr "" +msgstr "Lobby" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" -msgstr "" +msgstr "Configurare" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Începe cursa" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: In the networking menu msgid "Enable splitscreen or player handicaps" -msgstr "" +msgstr "Activează ecran divizat sau număr inegal de jucători" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button msgid "Local networking" -msgstr "" +msgstr "Rețea locală" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button msgid "Global networking" -msgstr "" +msgstr "Rețea globală" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button msgid "Enter server address" -msgstr "" +msgstr "Introduceți adresa serverului" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Profilul tău" @@ -1910,43 +1982,43 @@ msgstr "..." #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: In the achievements screen msgid "Player rankings" -msgstr "" +msgstr "Clasament jucători" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Prieteni" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: In the profile screen msgid "Look for more friends:" -msgstr "" +msgstr "Caută mai mulți prieteni:" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: ./data/gui/screens/online/user_search.stkgui msgid "Search" -msgstr "Căutare" +msgstr "Caută" #. I18N: ./data/gui/screens/online/profile_servers.stkgui msgid "Global Networking" -msgstr "" +msgstr "Rețea globală" #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen msgid "Quick Play" -msgstr "" +msgstr "Joc rapid" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" -msgstr "" +msgstr "Configurări cont" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: In the online account settings screen msgid "Password:" -msgstr "Parola:" +msgstr "Parolă:" #. I18N: ./data/gui/screens/online/profile_settings.stkgui msgid "Change" @@ -1955,13 +2027,13 @@ msgstr "Schimbă" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: In the online account settings screen msgid "E-mail:" -msgstr "" +msgstr "E-mail:" #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog #: src/states_screens/online/register_screen.cpp:73 msgid "Create User" -msgstr "" +msgstr "Creează utilizator" #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: Section in the register screen @@ -1989,10 +2061,10 @@ msgid "Online Username" msgstr "Nume online" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" -msgstr "Resetează parola" +msgstr "Restabilește parola" #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog @@ -2000,451 +2072,505 @@ msgid "" "You can play without creating an online account by selecting an offline " "account. Though then you can not connect to friends, vote for addons etc. " "Please read our privacy statement at https://privacy.supertuxkart.net" -msgstr "" +msgstr "Puteți juca offline fără a crea un cont online. Dar nu vă puteți conecta cu prieteni, vota pentru extensii ș.a. Citiți documentul de confidențialitate la https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" -msgstr "" +msgstr "Selecție server" #. I18N: ./data/gui/screens/online/server_selection.stkgui #. I18N: In the server selection screen msgid "Show private server(s)" -msgstr "" +msgstr "Arată servere private" #. I18N: ./data/gui/screens/online/server_selection.stkgui #. I18N: In the server selection screen msgid "Use IPv6 connection" -msgstr "" +msgstr "Folosește conexiune IPv6" #. I18N: ./data/gui/screens/online/user_search.stkgui msgid "User search" -msgstr "" - -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +msgstr "Căutare de utilizator" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Opțiuni de SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Afișaj" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" -msgstr "" +msgstr "Grafică" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Sunet" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" -msgstr "" +msgstr "Interfață" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Jucători" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Controale" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Limbă" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Muzică" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Activat" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Volum" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Efecte sonore" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Șterge configurația" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" -msgstr "" +msgstr "Dezactivează configurația" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Înapoi la lista dispozitivelor" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" -msgstr "" +msgstr "Redenumește configurația" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" -msgstr "" +msgstr "Activează feedback haptic (dacă este suportat)" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Rezoluție" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Ecran complet" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Memorează poziția ferestrei" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Aplică noua rezoluție" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Aranjament de ecran divizat pentru jucători multipli" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Opțiuni de internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" -msgstr "" +msgstr "Arată întotdeauna ecranul de autentificare" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" -msgstr "" +msgstr "Conectare la Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "" +msgid "Enable chatting in online lobbies" +msgstr "Activează conversațiile în lobby-uri online" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "" +msgid "Enable chatting in online matches" +msgstr "Activează conversațiile în competițiile online" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Opțiuni diverse" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" -msgstr "" +msgstr "Activează handicap pentru jucători" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" -msgstr "" +msgstr "Dezinstalează artifactele jocului complet" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" -msgstr "" +msgstr "Apăsați enter sau clic dublu pe dispozitiv pentru a-l configura" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Adaugă un dispozitiv" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." -msgstr "* Configurația folosită va fi dedusă din tasta 'Select' apăsată pentru intrarea în joc." +msgstr "* Configurația folosită va fi dedusă din tasta „Selectare” apăsată pentru intrarea în joc." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" -msgstr "Skin" +msgstr "Temă" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "" +msgid "Skin variant" +msgstr "Varianta temei" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "" +msgid "Minimap" +msgstr "Hartă miniatură" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" -msgstr "" +msgstr "Dimensiune font" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" -msgstr "" +msgstr "Cameră" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." -msgstr "" +msgstr "Personalizat..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" -msgstr "" +msgstr "Arată FPS" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" -msgstr "" +msgstr "Arată bonusurile deținute de celelalte carturi" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" -msgstr "" +msgstr "Activează temporizatorul în modul poveste" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" -msgstr "" +msgstr "Rezoluția de randat" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" -msgstr "" +msgstr "Nivelul de efecte grafice" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" -msgstr "" +msgstr "Nivelul de efecte de estompare" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" -msgstr "" +msgstr "FPS maxim" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." -msgstr "" +msgstr "Configurări personalizate..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "" +msgid "Performance tests" +msgstr "Teste de performanță" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "" +msgid "Performance test of the current settings" +msgstr "Testează performanța configurărilor curente" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Memorează parola" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Șterge" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Culoarea cartului" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" -msgstr "" +msgstr "Selectați o dificultate" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a game mode" -msgstr "" +msgstr "Selectați un mod de joc" #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen msgid "Use left/right to choose your team and press fire" -msgstr "" +msgstr "Folosiți stânga/dreapta pentru a alege echipa și apăsați „trage”" #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen msgid "Red Team" -msgstr "" +msgstr "Echipa roșie" #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen msgid "Blue Team" -msgstr "" +msgstr "Echipa albastră" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" -msgstr "" +msgstr "Număr de ture" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" -msgstr "" +msgstr "Număr de carturi robot" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen msgid "Number of blue team AI karts" -msgstr "" +msgstr "Număr de carturi robot în echipa albastră" #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen #: src/race/grand_prix_data.cpp:623 msgid "Random Grand Prix" -msgstr "" +msgstr "Grand Prix aleatoriu" + +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Editează cursele favorite" #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" -msgstr "" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "" +msgstr "Autentificare" #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." -msgstr "" +msgstr "Tema interfeței poate fi schimbată în opțiunile interfeței." #. I18N: ./data/tips.xml msgid "You can see other karts' powerups by enabling it in the UI options." -msgstr "" +msgstr "Puteți vedea bonusurile celorlalte carturi activându-le în opțiunile interfeței." #. I18N: ./data/tips.xml msgid "The font size can be changed in the UI options." -msgstr "" +msgstr "Dimensiunea fontului poate fi schimbată în opțiunile interfeței." #. I18N: ./data/tips.xml msgid "The help menu has lots of useful information." -msgstr "" +msgstr "Meniul ajutor conține multe informații folositoare." #. I18N: ./data/tips.xml msgid "In single-player, you can watch and challenge recorded time-trials." @@ -2453,29 +2579,29 @@ msgstr "" #. I18N: ./data/tips.xml msgid "" "You can visit https://supertuxkart.net/ for more information about the game." -msgstr "" +msgstr "Puteți vizita https://supertuxkart.net/ pentru mai multe informații despre joc." #. I18N: ./data/tips.xml msgid "Short nitro boosts are more efficient." -msgstr "" +msgstr "Avântările scurte de nitro sunt mai eficiente." #. I18N: ./data/tips.xml msgid "Only use zippers when it is safe. Long straight lines are ideal." -msgstr "" +msgstr "Folosiți fermoarele numai când este sigur. Culoarele drepte lungi sunt ideale." #. I18N: ./data/tips.xml msgid "" "Don't use multiple zippers quickly in row, instead, wait until the speed " "boost wears off." -msgstr "" +msgstr "Nu utilizați fermoarele multiple rapid unul după altul, în loc, așteptați până când avântul de viteză se reduce." #. I18N: ./data/tips.xml msgid "Skidding makes you much faster, do it whenever safe." -msgstr "" +msgstr "Derapările vă îmbunătățește viteza, aplicați-le ori de câte ori este sigur." #. I18N: ./data/tips.xml msgid "The swatter can be used to remove bombs or parachutes." -msgstr "" +msgstr "Paleta de țânțari poate fi folosită pentru a elimina bombe sau parașute." #. I18N: ./data/tips.xml msgid "" @@ -2548,317 +2674,385 @@ msgid "" msgstr "" #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" -msgstr "" +msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" -msgstr "" +msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" -msgstr "" +msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" -msgstr "" +msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" -msgstr "" +msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" -msgstr "" +msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" -msgstr "" +msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" -msgstr "" +msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" -msgstr "" +msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" -msgstr "" +msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" -msgstr "" +msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" -msgstr "" +msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" -msgstr "" +msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" -msgstr "" +msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" -msgstr "" +msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" -msgstr "" +msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" -msgstr "" +msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" -msgstr "" +msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" -msgstr "" +msgstr "Abisul dinaintea potopului" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" -msgstr "" +msgstr "Semnalul extratereștrilor" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" -msgstr "" +msgstr "Labirintul Coloseumului antic" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" -msgstr "" +msgstr "Orașul lumânărilor" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" -msgstr "" +msgstr "Insula duelului" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" -msgstr "" +msgstr "Pădurea neagră" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" -msgstr "" +msgstr "Peștera X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" -msgstr "" +msgstr "Templul cafeniu" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" -msgstr "" +msgstr "Trecerea prin lan" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" -msgstr "" +msgstr "Fortăreața de magmă" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" -msgstr "" +msgstr "Insula marelui paradis" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" -msgstr "" +msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" -msgstr "" +msgstr "Coborârea spre gaură" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" -msgstr "" +msgstr "Câmpul de fotbal înghețat" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" -msgstr " dar sunteți niște neisprăviți jalnici și nu mă învingeți pe mine - Regele karturilor!" +msgstr "Dar sunteți niște neisprăviți jalnici și nu mă învingeți pe mine - Regele carturilor!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" -msgstr "" +msgstr "Arena dunelor" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" -msgstr "" +msgstr "Stadionul de fotbal al dunelor" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" -msgstr "" +msgstr "În jurul farului" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" -msgstr "" +msgstr "Mina veche" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" -msgstr "" +msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" -msgstr "" +msgstr "Oaza" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" -msgstr "" +msgstr "Clasa de matematică a lui Oliver" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" -msgstr "" +msgstr "Parcul dovlecilor" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" -msgstr "" +msgstr "Conacul Ravenbridge" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" -msgstr "" +msgstr "Nisipuri mișcătoare" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" -msgstr "" +msgstr "Piscina lui Nessie" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" -msgstr "" +msgstr "Resortul din nord" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" -msgstr "" +msgstr "Vârful înzăpezit" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" -msgstr "" +msgstr "Terenul de fotbal" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" -msgstr "" +msgstr "Stadionul" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" -msgstr "" +msgstr "Templul" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" -msgstr "" +msgstr "Insula vulcanică" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" -msgstr "" +msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" -msgstr "" +msgstr "Grădina Zen" #: src/achievements/achievement.cpp:387 #, c-format msgid "Completed achievement \"%s\"." -msgstr "" +msgstr "Realizare dobândită „%s”" -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." -msgstr "" +msgstr "Nu s-a putut conecta la serverul de suplimente SuperTuxKart." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." -msgstr "" +msgstr "Eroare la descărcarea noutăților: „%s”." #: src/challenges/challenge_data.cpp:303 src/network/server_config.cpp:261 msgid "Normal Race (Grand Prix)" -msgstr "" +msgstr "Cursă normală (Grand Prix)" #: src/challenges/challenge_data.cpp:305 msgid "Time-Trial (Grand Prix)" -msgstr "" +msgstr "Contra timp (Grand Prix)" #: src/challenges/challenge_data.cpp:310 msgid "Time-Trial - beat the replay" -msgstr "" +msgstr "Contra timp - învinge reluarea" #: src/challenges/challenge_data.cpp:312 msgid "Time-Trial - nitro challenge" -msgstr "" +msgstr "Contra timp - provocarea de nitro" #: src/challenges/challenge_data.cpp:314 msgid "Normal Race (single race)" -msgstr "" +msgstr "Cursă normală (o singură cursă)" #: src/challenges/challenge_data.cpp:316 msgid "Time-Trial (single race)" -msgstr "" +msgstr "Contra timp (o singură cursă)" #: src/challenges/challenge_data.cpp:318 msgid "Follow the Leader (single race)" -msgstr "" +msgstr "Urmărește liderul (o singură cursă)" #. I18N: In the Select challenge dialog, tell user this challenge has reversed #. laps #: src/challenges/challenge_data.cpp:324 #: src/states_screens/dialogs/select_challenge.cpp:78 msgid "Mode: Reverse" -msgstr "" +msgstr "Mod: Invers" #: src/challenges/challenge_data.cpp:601 #, c-format msgid "New track '%s' now available" -msgstr "" +msgstr "O nouă cursă „%s” este disponibilă" #: src/challenges/challenge_data.cpp:605 #, c-format msgid "New game mode '%s' now available" -msgstr "" +msgstr "Nou mod de joc „%s” este disponibil" #: src/challenges/challenge_data.cpp:615 #, c-format msgid "New Grand Prix '%s' now available" -msgstr "" +msgstr "Nou Grand Prix „%s” este dispobil" #: src/challenges/challenge_data.cpp:619 #, c-format msgid "New difficulty '%s' now available" -msgstr "" +msgstr "Nouă dificultate „%s” este disponibilă" #: src/challenges/challenge_data.cpp:629 #, c-format msgid "New kart '%s' now available" -msgstr "Nou cart „%s” acuma disponibil" +msgstr "Nou cart „%s” este disponibil" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2870,13 +3064,13 @@ msgstr "" #. I18N: Name of first guest player (without number) #: src/config/player_manager.cpp:396 msgid "Guest" -msgstr "" +msgstr "Oaspete" #. I18N: Name of further guest players, with a 1, 2, ... attached #: src/config/player_manager.cpp:401 #, c-format msgid "Guest %d" -msgstr "" +msgstr "Oaspete %d" #: src/config/user_config.cpp:688 msgid "" @@ -2890,66 +3084,65 @@ msgid "" "created." msgstr "" -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." -msgstr "" +msgstr "Înregistrarea video a început." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." -msgstr "" +msgstr "Video salvat în „%s”." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" -msgstr "" +msgstr "Progresul codării:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" -msgstr "" +msgstr "FPS: %d/%d/%d - %d KTris, Ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" -msgstr "" +msgstr "Sfat: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" -msgstr "" +msgstr "Se încarcă" #: src/guiengine/widgets/kart_stats_widget.cpp:104 msgid "Mass" -msgstr "" +msgstr "Masă" #: src/guiengine/widgets/kart_stats_widget.cpp:110 msgid "Maximum speed" -msgstr "" +msgstr "Viteză maximă" #: src/guiengine/widgets/kart_stats_widget.cpp:117 msgid "Acceleration" -msgstr "" +msgstr "Accelerație" #: src/guiengine/widgets/kart_stats_widget.cpp:123 msgid "Nitro efficiency" -msgstr "" +msgstr "Eficiență nitro" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (cu handicap)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s este gata" @@ -2963,434 +3156,434 @@ msgstr "[niciuna]" #: src/input/binding.cpp:92 msgctxt "input_key" msgid "Left Mouse Button" -msgstr "" +msgstr "Butonul stâng al mausului" #. I18N: input configuration screen: mouse button #: src/input/binding.cpp:94 msgctxt "input_key" msgid "Right Mouse Button" -msgstr "" +msgstr "Butonul drept al mausului" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:96 msgctxt "input_key" msgid "Cancel" -msgstr "" +msgstr "Anulează" #. I18N: input configuration screen: mouse button #: src/input/binding.cpp:98 msgctxt "input_key" msgid "Middle Mouse Button" -msgstr "" +msgstr "Butonul mijlociu al mausului" #. I18N: input configuration screen: mouse button #: src/input/binding.cpp:100 msgctxt "input_key" msgid "X1 Mouse Button" -msgstr "" +msgstr "Butonul X1 al mausului" #. I18N: input configuration screen: mouse button #: src/input/binding.cpp:102 msgctxt "input_key" msgid "X2 Mouse Button" -msgstr "" +msgstr "Butonul X2 al mausului" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:104 msgctxt "input_key" msgid "Backspace" -msgstr "" +msgstr "Backspace" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:106 msgctxt "input_key" msgid "Tab" -msgstr "" +msgstr "Tab" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:108 msgctxt "input_key" msgid "Clear" -msgstr "" +msgstr "Curățare" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:110 msgctxt "input_key" msgid "Return" -msgstr "" +msgstr "Enter" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:112 msgctxt "input_key" msgid "Shift" -msgstr "" +msgstr "Shift" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:114 msgctxt "input_key" msgid "Control" -msgstr "" +msgstr "Control" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:116 msgctxt "input_key" msgid "Alt/Menu" -msgstr "" +msgstr "Alt/Meniu" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:118 msgctxt "input_key" msgid "Pause" -msgstr "" +msgstr "Pauză" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:120 msgctxt "input_key" msgid "Caps Lock" -msgstr "" +msgstr "Caps Lock" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:122 msgctxt "input_key" msgid "Kana" -msgstr "" +msgstr "Kana" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:124 msgctxt "input_key" msgid "Junja" -msgstr "" +msgstr "Junja" #. I18N: input configuration screen: keyboard key #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:127 msgctxt "input_key" msgid "Final" -msgstr "" +msgstr "Final" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:129 msgctxt "input_key" msgid "Escape" -msgstr "" +msgstr "Escape" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:131 msgctxt "input_key" msgid "Convert" -msgstr "" +msgstr "Convertire" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:133 msgctxt "input_key" msgid "Nonconvert" -msgstr "" +msgstr "Neconvertire" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:135 msgctxt "input_key" msgid "Accept" -msgstr "" +msgstr "Acceptă" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:137 msgctxt "input_key" msgid "Modechange" -msgstr "" +msgstr "Schimbarea modului" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:139 msgctxt "input_key" msgid "Space" -msgstr "" +msgstr "Spațiu" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:141 msgctxt "input_key" msgid "Page Up" -msgstr "" +msgstr "Page Up" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:143 msgctxt "input_key" msgid "Page Down" -msgstr "" +msgstr "Page Down" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:145 msgctxt "input_key" msgid "End" -msgstr "" +msgstr "End" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:147 msgctxt "input_key" msgid "Home" -msgstr "" +msgstr "Home" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:149 msgctxt "input_key" msgid "Left" -msgstr "" +msgstr "Stânga" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:151 msgctxt "input_key" msgid "Up" -msgstr "" +msgstr "Sus" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:153 msgctxt "input_key" msgid "Right" -msgstr "" +msgstr "Dreapta" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:155 msgctxt "input_key" msgid "Down" -msgstr "" +msgstr "Jos" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:157 msgctxt "input_key" msgid "Select" -msgstr "" +msgstr "Select" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:159 msgctxt "input_key" msgid "Print" -msgstr "" +msgstr "Print" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:161 msgctxt "input_key" msgid "Exec" -msgstr "" +msgstr "Exec" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:163 msgctxt "input_key" msgid "Print Screen" -msgstr "" +msgstr "Print Screen" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:165 msgctxt "input_key" msgid "Insert" -msgstr "" +msgstr "Insert" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:167 msgctxt "input_key" msgid "Delete" -msgstr "" +msgstr "Delete" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:169 msgctxt "input_key" msgid "Help" -msgstr "" +msgstr "Ajutor" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:207 msgctxt "input_key" msgid "Left Logo" -msgstr "" +msgstr "Logo stânga" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:209 msgctxt "input_key" msgid "Right Logo" -msgstr "" +msgstr "Logo dreapta" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:211 msgctxt "input_key" msgid "Apps" -msgstr "" +msgstr "Apps" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:213 msgctxt "input_key" msgid "Sleep" -msgstr "" +msgstr "Sleep" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:215 msgctxt "input_key" msgid "Numpad 0" -msgstr "" +msgstr "Tasta numerică 0" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:217 msgctxt "input_key" msgid "Numpad 1" -msgstr "" +msgstr "Tasta numerică 1" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:219 msgctxt "input_key" msgid "Numpad 2" -msgstr "" +msgstr "Tasta numerică 2" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:221 msgctxt "input_key" msgid "Numpad 3" -msgstr "" +msgstr "Tasta numerică 3" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:223 msgctxt "input_key" msgid "Numpad 4" -msgstr "" +msgstr "Tasta numerică 4" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:225 msgctxt "input_key" msgid "Numpad 5" -msgstr "" +msgstr "Tasta numerică 5" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:227 msgctxt "input_key" msgid "Numpad 6" -msgstr "" +msgstr "Tasta numerică 6" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:229 msgctxt "input_key" msgid "Numpad 7" -msgstr "" +msgstr "Tasta numerică 7" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:231 msgctxt "input_key" msgid "Numpad 8" -msgstr "" +msgstr "Tasta numerică 8" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:233 msgctxt "input_key" msgid "Numpad 9" -msgstr "" +msgstr "Tasta numerică 9" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:237 msgctxt "input_key" msgid "Separator" -msgstr "" +msgstr "Separator" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:239 msgctxt "input_key" msgid "- (Subtract)" -msgstr "" +msgstr "- (Scădere)" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:241 msgctxt "input_key" msgid "Decimal" -msgstr "" +msgstr "Decimală" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:243 msgctxt "input_key" msgid "/ (Divide)" -msgstr "" +msgstr "/ (Împărțire)" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:269 msgctxt "input_key" msgid "Num Lock" -msgstr "" +msgstr "Num Lock" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:271 msgctxt "input_key" msgid "Scroll Lock" -msgstr "" +msgstr "Scroll Lock" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:273 msgctxt "input_key" msgid "Left Shift" -msgstr "" +msgstr "Shift stânga" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:275 msgctxt "input_key" msgid "Right Shift" -msgstr "" +msgstr "Shift dreapta" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:277 msgctxt "input_key" msgid "Left Control" -msgstr "" +msgstr "Control stânga" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:279 msgctxt "input_key" msgid "Right Control" -msgstr "" +msgstr "Control dreapta" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:281 msgctxt "input_key" msgid "Left Menu" -msgstr "" +msgstr "Meniu stânga" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:283 msgctxt "input_key" msgid "Right Menu" -msgstr "" +msgstr "Meniu dreapta" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:289 msgctxt "input_key" msgid "Attn" -msgstr "" +msgstr "Attn" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:291 msgctxt "input_key" msgid "Crsel" -msgstr "" +msgstr "Crsel" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:293 msgctxt "input_key" msgid "Exsel" -msgstr "" +msgstr "Exsel" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:295 msgctxt "input_key" msgid "Ereof" -msgstr "" +msgstr "Ereof" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:297 msgctxt "input_key" msgid "Play" -msgstr "" +msgstr "Redă" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:299 msgctxt "input_key" msgid "Zoom" -msgstr "" +msgstr "Zoom" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:301 msgctxt "input_key" msgid "Pa1" -msgstr "" +msgstr "Pa1" #. I18N: input configuration screen: keyboard key #: src/input/binding.cpp:303 @@ -3420,32 +3613,32 @@ msgstr "" #: src/input/binding.cpp:367 #, c-format msgid "Axis %d" -msgstr "" +msgstr "Axa %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" -msgstr "" +msgstr "Butonul %d al mausului" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" -msgstr "" +msgstr "Axa %d%s a mausului" #. I18N: shown when config file is too old #: src/input/device_manager.cpp:496 msgid "Please re-configure your key bindings." -msgstr "" +msgstr "Reconfigurați asocierile de butoane." #: src/input/device_manager.cpp:497 msgid "Your input config file is not compatible with this version of STK." @@ -3454,122 +3647,122 @@ msgstr "" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:159 msgid "Guide" -msgstr "" +msgstr "Ghid" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:161 msgid "Start" -msgstr "" +msgstr "Start" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:163 msgid "Left thumbstick press" -msgstr "" +msgstr "Apăsare pe thumbstick stânga" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:165 msgid "Right thumbstick press" -msgstr "" +msgstr "Apăsare pe thumbstick dreapta" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:167 msgid "Left shoulder" -msgstr "" +msgstr "Umărul din stânga" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:169 msgid "Right shoulder" -msgstr "" +msgstr "Umărul din dreapta" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:171 msgid "DPad up" -msgstr "" +msgstr "DPad sus" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:173 msgid "DPad down" -msgstr "" +msgstr "DPad jos" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:175 msgid "DPad left" -msgstr "" +msgstr "DPad stânga" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:177 msgid "DPad right" -msgstr "" +msgstr "DPad dreapta" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:181 msgid "Left thumbstick right" -msgstr "" +msgstr "Dreapta pe thumbstick din stânga" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:183 msgid "Left thumbstick left" -msgstr "" +msgstr "Stânga pe thumbstick din stânga" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:185 msgid "Left thumbstick down" -msgstr "" +msgstr "Jos pe thumbstick din stânga" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:187 msgid "Left thumbstick up" -msgstr "" +msgstr "Sus pe thumbstick din stânga" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:189 msgid "Right thumbstick right" -msgstr "" +msgstr "Dreapta pe thumbstick din dreapta" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:191 msgid "Right thumbstick left" -msgstr "" +msgstr "Stânga pe thumbstick din dreapta" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:193 msgid "Right thumbstick down" -msgstr "" +msgstr "Jos pe thumbstick din dreapta" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:195 msgid "Right thumbstick up" -msgstr "" +msgstr "Sus pe thumbstick din dreapta" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:197 msgid "Left trigger" -msgstr "" +msgstr "Lansatorul din stânga" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:199 msgid "Right trigger" -msgstr "" +msgstr "Lansatorul din dreapta" #: src/input/input_manager.cpp:867 #, c-format msgid "Ignoring '%s'. You needed to join earlier to play!" -msgstr "" +msgstr "Se ignoră „%s”. Trebuie să vă alăturați mai devreme pentru a juca!" #: src/input/input_manager.cpp:903 msgid "Only the Game Master may act at this point!" -msgstr "" +msgstr "Numai maestrul de joc poate acționa momentan!" #: src/input/sdl_controller.cpp:253 #, c-format msgid "%s has low battery level." -msgstr "" +msgstr "%s are nivel de baterie scăzut." #: src/input/wiimote_manager.cpp:379 msgid "" "Connect your wiimote to the Bluetooth manager, then click on Ok. Detailed " "instructions at https://supertuxkart.net/Wiimote" -msgstr "" +msgstr "Conectați-vă wiimote-ul la managerul de bluetooth, apoi apăsați OK. Instrucțiuni detaliate puteți găsi la https://supertuxkart.net/Wiimote" #: src/input/wiimote_manager.cpp:382 msgid "" @@ -3582,17 +3775,17 @@ msgstr "" #, c-format msgid "Found %d wiimote" msgid_plural "Found %d wiimotes" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "S-a găsit %d wiimote" +msgstr[1] "S-au găsit %d wiimote-uri" +msgstr[2] "S-au găsit %d de wiimote-uri" #: src/input/wiimote_manager.cpp:410 msgid "Could not detect any wiimote :/" -msgstr "" +msgstr "Nu s-au detectat niciun wiimote :/" #: src/io/rich_presence.cpp:477 msgid "Getting ready to race" -msgstr "" +msgstr "Pregătire pentru cursă" #: src/karts/controller/local_player_controller.cpp:329 msgid "Penalty time!!" @@ -3600,36 +3793,40 @@ msgstr "Timp de penalizare!" #: src/karts/controller/local_player_controller.cpp:332 msgid "Don't accelerate before 'Set!'" -msgstr "" +msgstr "Nu accelerați înainte de „Pregătire!”" #: src/karts/controller/spare_tire_ai.cpp:150 msgid "You can have at most 3 lives!" -msgstr "" +msgstr "Puteți avea cel mult 3 vieți" #: src/karts/controller/spare_tire_ai.cpp:157 msgid "+1 life." -msgstr "" +msgstr "+1 viață." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" -msgstr "" +msgstr "Sunteți prea lent!" + +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Ați finalizat cursa!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Ați câștigat cursa!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" -msgstr "" +msgstr "Ați finalizat cursa pe poziția %d!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." -msgstr "" +msgstr "%s a părăsit jocul." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3638,65 +3835,65 @@ msgid "" "Internet\")." msgstr "" -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." -msgstr "" +msgstr "Rezoluția ecranului este prea mică pentru a rula STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." -msgstr "" +msgstr "Versiunea driverului este prea veche. Instalați cele mai recente drivere de video." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " "available. SuperTuxKart recommends a driver supporting %s or better. The " "game will likely still run, but in a reduced-graphics mode." -msgstr "Driverul grafic pare să fie foarte vechi. Vă rugăm să verificați dacă este disponibilă o actualizare. SuperTuxKart recomandă un driver care să suporte %s sau mai bine. Probabil că jocul va rula în continuare, dar într-un mod cu grafică redusă." +msgstr "Driverul grafic pare să fie foarte vechi. Verificați dacă este disponibilă o actualizare. SuperTuxKart recomandă un driver care să suporte %s sau mai bine. Probabil că jocul va rula în continuare, dar într-un mod cu grafică redusă." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." -msgstr "" +msgstr "Conexiunea la server a expirat" #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" -msgstr "" +msgstr "%s are steagul roșu!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" -msgstr "" +msgstr "Steagul roșu a fost restituit!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" -msgstr "" +msgstr "%s are steagul albastru!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" -msgstr "" +msgstr "Steagul albastru a fost restituit!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" -msgstr "" +msgstr "%s a capturat steagul albastru!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" -msgstr "" +msgstr "%s a capturat steagul roșu!" #: src/modes/easter_egg_hunt.cpp:222 #, c-format msgid "Eggs: %d / %d" -msgstr "" +msgstr "Ouă: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Lider" @@ -3704,224 +3901,224 @@ msgstr "Lider" msgid "Final lap!" msgstr "Tura finală!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" -msgstr "" +msgstr "Tura %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s de %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" -msgstr "O noua cea mai rapida curba" +msgstr "O noua tură record" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" -msgstr "DRUM GRESIT!" +msgstr "DRUM GREȘIT!" #: src/modes/soccer_world.cpp:533 src/modes/soccer_world.cpp:660 #, c-format msgid "%s scored a goal!" -msgstr "" +msgstr "%s a înscris un gol!" #: src/modes/soccer_world.cpp:535 src/modes/soccer_world.cpp:662 #, c-format msgid "Oops, %s made an own goal!" -msgstr "" +msgstr "Ups, %s a marcat un autogol!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "%i cart cu roți de rezervă a fost depus!" +msgstr[1] "%i carturi cu roți de rezervă au fost depuse!" +msgstr[2] "%i carturi cu roți de rezervă au fost depuse!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" -msgstr "" +msgstr "Ați fost eliminat!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." -msgstr "'%s' a fost eliminat." +msgstr "„%s” a fost eliminat." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." -msgstr "" +msgstr "Serverul a fost închis." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." -msgstr "" +msgstr "Ați fost dat afară de pe server." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." -msgstr "" +msgstr "Ați fost dat afară. Ping prea mare." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." -msgstr "" +msgstr "A fost detectată o conexiune proastă la rețea." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" -msgstr "" +msgstr "Robot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." -msgstr "" +msgstr "%s s-a deconectat." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "" #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" -msgstr "" +msgstr "Dificultate: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" -msgstr "" +msgstr "Maxim jucători: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" -msgstr "" +msgstr "Mod de joc: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" -msgstr "" +msgstr "Limită de timp" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" -msgstr "" +msgstr "Limită de goluri" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" -msgstr "" +msgstr "Mod de joc fotbal: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" -msgstr "" +msgstr "Progres Grand Prix: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." -msgstr "" +msgstr "Toți jucătorii s-au alăturat echipei roșie sau albastră." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." -msgstr "" +msgstr "Acum sunteți deținătorul serverului." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." -msgstr "" +msgstr "Conexiune refuzată: serverul este ocupat." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "" -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "" -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "" -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "" -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "" -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "" #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "" #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "" #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "" -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "" #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "" #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "" #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "" #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "" #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3929,15 +4126,15 @@ msgid "" msgstr "" #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "" #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3968,38 +4165,38 @@ msgstr "" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s s-a conectat." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s și %s sunt acum conectați." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s și %s sunt acum conectați." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4008,12 +4205,12 @@ msgstr[1] "" msgstr[2] "" #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "" -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4021,7 +4218,7 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "" @@ -4050,12 +4247,12 @@ msgid "" msgstr "" #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Urmează liderul" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Luptă cu 3 lovituri" @@ -4068,95 +4265,91 @@ msgstr "" msgid "Replay saved in \"%s\"." msgstr "" -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 săptămână" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 săptămâni" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 lună" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 luni" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 luni" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 luni" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 an" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 ani" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - #: src/states_screens/credits.cpp:184 msgid "translator-credits" -msgstr "Launchpad Contributions:\nHar Gosmos, 2019\nNicolae Crefelean, 2015,2017-2018\nSorin Ingeaua, 2020\nAlexandru Guduleasa\nDaniel Butum\nDimStar\nDominique Leuenberger aka DimStar\nMatus Michael\nNicolae Crefelean\nSTK-team\nVitalie Ciubotaru" +msgstr "Launchpad Contributions:\nHar Gosmos, 2019\nNicolae Crefelean, 2015,2017-2018\nSorin Ingeaua, 2020\nAlexandru Guduleasa\nDaniel Butum\nDimStar\nDominique Leuenberger aka DimStar\nMatus Michael\nNicolae Crefelean\nSTK-team\nVitalie Ciubotaru\nDaniel Șerbănescu, 2025" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:65 msgctxt "achievement_info" @@ -4441,7 +4634,7 @@ msgstr "" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "" @@ -4544,7 +4737,7 @@ msgstr "" msgid " (official tracks matching the goal)" msgstr "" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4552,91 +4745,95 @@ msgid "" msgstr "" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Actualizare" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Versiune: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "recomandări" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Mărime: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Probleme la îndepărtarea suplimentului „%s”" -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "" @@ -4658,67 +4855,97 @@ msgstr "" #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Personalizat" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Dezactivat" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4726,7 +4953,7 @@ msgid "" msgstr "" #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4743,101 +4970,102 @@ msgstr "" msgid "Invalid server address: %s." msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(gol)" @@ -4925,33 +5153,41 @@ msgid "Press any key..." msgstr "" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 -msgid "Back to Battle" +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" msgstr "" #: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +msgid "Back to Battle" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Configurează o nouă cursă" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Ieșire din cursă" @@ -4967,11 +5203,11 @@ msgstr "" msgid "%s is number %d in the rankings with a score of %f." msgstr "" -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "" -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4993,7 +5229,7 @@ msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "" @@ -5006,21 +5242,21 @@ msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "" @@ -5033,54 +5269,54 @@ msgstr "" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "" @@ -5093,74 +5329,74 @@ msgid "No player available for connecting to server." msgstr "" #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5189,7 +5425,7 @@ msgstr "" msgid "An error occurred while trying to save your grand prix." msgstr "" -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "" @@ -5233,12 +5469,12 @@ msgstr "" msgid "You unlocked grand prix %0" msgstr "" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5259,19 +5495,19 @@ msgstr "" msgid "Please select a Grand Prix" msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "" @@ -5280,19 +5516,19 @@ msgstr "" msgid "Better luck next time!" msgstr "Mai mult noroc data viitoare!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "" @@ -5305,110 +5541,125 @@ msgstr "" msgid "Are you sure you want to remove all of your high scores?" msgstr "" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "" -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "serverul lui %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5416,7 +5667,7 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "" @@ -5424,24 +5675,24 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "" -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5451,7 +5702,7 @@ msgstr[2] "" #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5461,96 +5712,108 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "profilul lui %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "" -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "" @@ -5628,34 +5891,34 @@ msgid "Distance (km)" msgstr "" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "" #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "" -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "" -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5663,149 +5926,149 @@ msgstr "" #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Dezactivează dispozitiv" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Activează dispozitiv" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Accelereație" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Foc" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Salvare" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "În sus" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Jos" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Stanga" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Dreapta" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Renunță/Înapoi" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Un obiect albastru indică un conflict cu altă configuraţie" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Un obiect roșu indică un conflict în configurația actuală" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5813,17 +6076,27 @@ msgid "" msgstr "" #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "" +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5831,89 +6104,74 @@ msgstr "" #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Limba sistemului" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5923,128 +6181,133 @@ msgid "" msgstr "" #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "" #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "" -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "" #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "" @@ -6072,7 +6335,7 @@ msgstr "" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "" @@ -6107,7 +6370,7 @@ msgstr "Urmăreşte liderul" msgid "Top %i" msgstr "" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "" @@ -6131,102 +6394,199 @@ msgstr "" msgid "Press fire to start the challenge" msgstr "" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Anulează Marele Premiu" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Înapoi la meniu" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Cele mai bune rezultate" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "" @@ -6267,28 +6627,28 @@ msgstr "" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "" @@ -6310,10 +6670,12 @@ msgid "%d/%m/%Y" msgstr "" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6322,41 +6684,48 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6364,34 +6733,41 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Folosiți nitro-ul pe care l-ați colectat apăsând <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Ups! Când ai probleme, apasă <%s> pentru a fi salvat." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Ups! Când ai probleme, apasă pictograma pasăre pentru a fi salvat." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6399,24 +6775,27 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Acum esti gata de cursa. Mult Noroc!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Un joc de curse 3D open-source" @@ -6424,9 +6803,9 @@ msgstr "Un joc de curse 3D open-source" #. semicolons #: supertuxkart.desktop:11 msgid "tux;game;race;" -msgstr "tux;joc;cursa" +msgstr "tux;game;race;joc;cursa;cursă;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6434,7 +6813,7 @@ msgid "" "for all ages." msgstr "" -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6443,7 +6822,7 @@ msgid "" "your opponents." msgstr "" -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6452,27 +6831,27 @@ msgid "" "your racing skills!" msgstr "" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "" -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "" -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "" -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "Echipa SuperTuxKart " diff --git a/data/po/ru.po b/data/po/ru.po index b639de81d08..77b5cb8121c 100644 --- a/data/po/ru.po +++ b/data/po/ru.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" "Last-Translator: Andrei Stepanov, 2015-2024\n" "Language-Team: Russian (http://app.transifex.com/supertuxkart/supertuxkart/language/ru/)\n" @@ -180,7 +180,7 @@ msgstr "На краю света" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Назад" @@ -202,7 +202,7 @@ msgstr "Выберите предпочтительный тип управле #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Акселерометр" @@ -216,13 +216,13 @@ msgstr "Акселерометр" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Гироскоп" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Руль" @@ -253,35 +253,37 @@ msgstr "Настройки сенсорного устройства" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Основные" @@ -349,30 +351,33 @@ msgstr "Сбросить настройки" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Отмена" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Да" @@ -550,9 +555,9 @@ msgstr "Присоединиться" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -613,7 +618,7 @@ msgstr "Цель" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Прогресс" @@ -648,7 +653,7 @@ msgstr "Подтвердить" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Вернуться в гонку" @@ -665,7 +670,7 @@ msgstr "Вернуться в лобби" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Начать заново" @@ -729,12 +734,12 @@ msgstr "Введите имя пользователя и электронную #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Имя пользователя" @@ -775,7 +780,7 @@ msgstr "Сложность" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Новичок" @@ -787,7 +792,7 @@ msgstr "Новичок" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Любитель" @@ -799,7 +804,7 @@ msgstr "Любитель" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Эксперт" @@ -811,7 +816,7 @@ msgstr "Эксперт" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "СуперТакс" @@ -819,8 +824,8 @@ msgstr "СуперТакс" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Режим игры" @@ -831,8 +836,8 @@ msgstr "Режим игры" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Обычная гонка" @@ -845,7 +850,7 @@ msgstr "Обычная гонка" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Гонка на время" @@ -853,7 +858,8 @@ msgstr "Гонка на время" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Битва" @@ -862,24 +868,24 @@ msgstr "Битва" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Футбол" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Пароль" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Добавить сервер в избранное" @@ -890,7 +896,7 @@ msgstr "Добавить игрока" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Имя" @@ -984,6 +990,50 @@ msgstr "Назначить кнопке ESC" msgid "Assign nothing" msgstr "Ничего не назначать" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Рекомендуемые настройки видео" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Рекомендуемые настройки будут действительны для текущего разрешения." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Что должно быть приоритетным для настроек?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Производительность" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Баланс производительности и качества графики" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Качество графики" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Сбережение энергии" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Вам нравятся графические эффекты, создающие размытость?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Начать проверку" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -998,11 +1048,11 @@ msgstr "Настройки гонки" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Продолжить" @@ -1043,10 +1093,15 @@ msgstr "Арены" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Установлено" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Править избранные арены" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1056,20 +1111,20 @@ msgstr "Установлено" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Стандартные" @@ -1080,12 +1135,12 @@ msgstr "Стандартные" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Дополнения" @@ -1099,27 +1154,28 @@ msgstr "Дополнения" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Все" @@ -1158,9 +1214,9 @@ msgstr "Вниз" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Добавить" @@ -1197,7 +1253,7 @@ msgstr "Выбор повтора с призраком" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Охота за яйцами" @@ -1244,10 +1300,10 @@ msgstr "В обратном направлении" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Максимальное время (мин.)" @@ -1279,9 +1335,9 @@ msgstr "Копировать" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1292,80 +1348,80 @@ msgstr "Переименовать" msgid "Save Grand Prix" msgstr "Сохранить Гран-при" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Справка SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Режимы игры" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Усилители" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Бананы" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1373,56 +1429,57 @@ msgstr "Бананы" msgid "Story Mode" msgstr "Режим истории" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Классы картов" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Совместная игра" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Пройти обучение" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Собирайте голубые коробки, они подарят вам усилители." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Избегайте бананов!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1430,14 +1487,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Собрав нитро-заряды, вы можете получить временный прирост скорости по нажатии соответствующей кнопки в нужный момент. Текущий уровень нитро показан в виде шкалы в правом нижнем углу экрана." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Изображение замка означает, что вам необходимо завершить испытание для разблокировки." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1446,34 +1503,34 @@ msgid "" "carefully before!" msgstr "Вы можете выполнить занос нажатием специальной клавиши. Удачные короткие скольжения помогут в прохождении резких поворотов. Средние и продолжительные заносы наградят приростом скорости. Поворот нельзя прекратить во время скольжения, так что старайтесь правильно ориентировать карт перед прохождением!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Вы можете получить стартовое ускорение, нажав кнопку газа на слове «Внимание!» в начале гонки." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Текущие привязки клавиш можно посмотреть и изменить в меню «Настроек»" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart предоставляет несколько режимов игры:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Обычная гонка: все возможности доступны, так что собирайте усилители и используйте их с умом!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Гонка на время: никаких усилителей, так что всё зависит от ваших навыков вождения!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1481,7 +1538,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Следуйте за лидером: будьте на втором месте, так как после того, как время заканчивается, каждый последний карт выбывает. Будьте осторожны, если вы обгоните лидера, то тоже будете дисквалифицированы!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1491,30 +1548,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Есть 3 режима сражений: в «Битве трёх ударов» вам нужно поразить других оружием, пока они не потеряют все свои жизни. В «Битве против всех» побеждает игрок, который поразит других больше всего по достижению нужного количества очков или по истечению времени. В «Захвате флага» ваша команда должна доставить флаг вражеской команды на собственную базу и не дать захватить свой флаг." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Футбол: используйте свой карт, чтобы затолкнуть мяч в ворота соперника." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Охота за яйцами: исследуйте трассы и найдите все спрятанные яйца." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Повтор с призраком: сразитесь против призрака из повтора в режимах гонки на время или охоты за яйцами и запишите свой собственный повтор!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Круговой заезд: пройдите как можно больше кругов за отведённое время." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1523,93 +1580,93 @@ msgid "" "wins the cup." msgstr "* В бо́льшую часть этих режимов игры можно сыграть в Гран-при: вместо одной трассы, вы можете проехать сразу несколько. Чем лучше ваш ранг, тем больше очков вы получите. По окончании игрок с наибольшим числом очков выигрывает кубок." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Для победы в гонке вам может помочь подбор усилителей:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Жвачка — защитите себя с помощью щита, или используйте её, обернувшись назад, чтобы оставить за собой липкую розовую жижу." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Молния — даст вам сильное ускорение. Остерегайтесь потери контроля над вашим картом!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Пирог — бросается в ближайшего соперника, действует лучше всего на коротких расстояниях и длинных прямых. Он также поражает другие карты рядом с местом взрыва." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Вантуз — бросается прямо вперёд, чтобы зацепиться за спину оппонента, либо назад, чтобы ослепить его." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Шар для боулинга — катится прямо до столкновения, может отскакивать от стен. Если в момент броска вы оглянётесь, то он будет брошен назад." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Парашют — замедляет все карты, имеющие лучшую позицию." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Заменитель — на небольшое время коробки с бонусами превращаются в бананы, нитро — в жевательную резинку, и наоборот." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Баскетбольный мяч — прыгает за лидером гонки, может раздавить и замедлить карты на своём пути." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Мухобойка — расплющивает проезжающие мимо карты, тем самым замедляя их. Также может быть использована для удаления парашютов и бомб." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Если наехать на банан, к вашему карту может прицепиться одна из следующих вещей:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Якорь — резко замедляет карт." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Парашют — замедляет карт более мягко, чем якорь. Чем выше ваша скорость, тем сильнее замедление." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Бомба — взрывается через некоторое время, подбрасывая карт в воздух. Коснитесь другого карта для передачи бомбы к нему." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Злой Нолок захватил Гну! Вот несколько советов в помощь вам:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1618,7 +1675,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Этот значок на мини-карте обозначает доступные для прохождения испытания. Он также показывает количество ваших очков в верхнем правом углу экрана. Завершите как можно больше испытаний, и Нолок посоревнуется с вами в гонке. Победите его, чтобы освободить Гну!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1626,20 +1683,20 @@ msgid "" " the cup and the more points it is worth." msgstr "По завершению испытания вы получите кубок. Каждый кубок стоит несколько очков. Чем выше сложность, в которой вы выполнили испытание, тем лучше кубок и тем больше очков он стоит." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Когда вы получите количество очков, указанное под этим значком, вы будете награждены сюрпризом. Всего есть несколько сюрпризов." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Не все карты едут одинаково! Они разделяются на классы, отличающиеся характеристиками:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1647,7 +1704,7 @@ msgid "" " resistant to explosions." msgstr "Вес — существуют три класса картов в зависимости от их массы: лёгкие, средние и тяжёлые. Более тяжёлые карты менее подвержены парашютам и более устойчивы к взрывам." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1655,7 +1712,7 @@ msgid "" " especially at low speeds." msgstr "Ускорение — особенно полезно на старте, после аварии или на трассах со множеством резких поворотов. Чем легче карт, тем быстрее он ускоряется, особенно на низких скоростях." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1663,14 +1720,14 @@ msgid "" " top speed." msgstr "Максимальная скорость — чем она выше , тем быстрее карт может ехать. Особенно полезно на трассах с прямыми линиями и плавными кривыми. У более тяжёлых картов более высокая максимальная скорость." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Эффективность нитро — чём оно выше, тем больше скорости вы можете получить от нитро. Чем легче карт, тем выше эта эффективность." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1678,12 +1735,12 @@ msgid "" "easier it is." msgstr "Если вы проедете в скользящем потоке идущего впереди карта несколько секунд, то получите бонус к скорости и сможете совершить обгон. Чем легче ваш карт, тем проще это осуществить." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "В SuperTuxKart можно играть в многопользовательском режиме по сети:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1693,7 +1750,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Сначала выберите в главном меню значок «В сети». Выберите локальную сеть или интернет (последний должен быть включён в «Настройках»). Затем вы можете создать свой сервер с нужными настройками или найти подходящий среди существующих. Некоторые из них являются рекомендованными с возможностью рейтинговых гонок." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1703,12 +1760,12 @@ msgid "" "players and the server." msgstr "На сервере старт гонки управляется его хозяином (он отмечен значком «короны»). Официальные серверы могут стартовать гонки автоматически после набора необходимого количества игроков. Затем вы можете выбрать карт и проголосовать за трассу. Трассы из дополнений разрешены только в том случае, если они есть у всех игроков на сервере." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "…или на одном и том же устройстве:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1718,7 +1775,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Прежде всего, вам нужно несколько устройств ввода. Откройте окно «Управление», чтобы настроить их. Лучше всего использовать несколько контроллеров: на клавиатуре каждому игроку нужен различный набор клавиш, но большинство клавиатур не подходят для многопользовательской игры, так как не поддерживают одновременного нажатия большого количества клавиш." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1738,7 +1795,7 @@ msgstr "Выбор лучшего результата" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Круговой заезд" @@ -1746,9 +1803,9 @@ msgstr "Круговой заезд" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Гран-при" @@ -1759,6 +1816,20 @@ msgstr "Гран-при" msgid "Choose a Kart" msgstr "Выберите карт" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Класс карта" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Править избранные карты" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1772,11 +1843,11 @@ msgstr "Игра с разделением экрана" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "В сети" @@ -1793,7 +1864,7 @@ msgstr "Обучение" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Лучшие результаты" @@ -1801,7 +1872,7 @@ msgstr "Лучшие результаты" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Достижения" @@ -1855,30 +1926,30 @@ msgstr "Найти сервер" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Создать сервер" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Лобби" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Настройки" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Начать гонку" @@ -1904,9 +1975,9 @@ msgstr "Ввести адрес сервера" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Ваш профиль" @@ -1924,7 +1995,7 @@ msgstr "Рейтинг игроков" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Друзья" @@ -1949,7 +2020,7 @@ msgstr "Быстрая гонка" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Настройки учётной записи" @@ -1999,8 +2070,8 @@ msgid "Online Username" msgstr "Сетевое имя пользователя" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Сбросить пароль" @@ -2013,7 +2084,7 @@ msgid "" msgstr "Вы можете играть без создания сетевой учётной записи, выбрав автономный аккаунт. Но тогда вы не сможете подключаться к друзьям, голосовать за дополнения и прочее. Пожалуйста, ознакомьтесь с нашим заявлением о защите персональных данных по адресу: https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Выбор сервера" @@ -2031,339 +2102,409 @@ msgstr "Использовать протокол IPv6" msgid "User search" msgstr "Поиск пользователя" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Настройки SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Экран" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Графика" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Звук" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Интерфейс" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Игроки" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Управление" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Язык" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Музыка" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Включено" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Громкость" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Звуковые эффекты" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Удалить схему" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Отключить схему" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Вернуться к списку устройств" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Переименовать схему" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Включить тактильную обратную связь (если поддерживается)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Разрешение монитора" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Полноэкранный режим" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Запоминать расположение окна" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Применить новое разрешение монитора" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Схема разделения экрана в совместной игре" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Настройки интернета" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Всегда показывать экран входа" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Подключаться к интернету" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Включить сетевой чат" +msgid "Enable chatting in online lobbies" +msgstr "Включить чат в сетевых лобби" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Включить чат в сетевых играх" +msgid "Enable chatting in online matches" +msgstr "Включить чат в сетевых матчах" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Прочие настройки" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Разрешить профили гандикапа для игроков" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Удалить ресурсы полной игры" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Нажмите «Enter» или дважды щёлкните по устройству, чтобы настроить его" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Добавить устройство" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Выбор схемы будет зависеть от того, с какого устройства нажата кнопка «Выбрать» для присоединения к игре." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Тема" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Мини-карта" +msgid "Skin variant" +msgstr "Вариант оболочки" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Схема разделения экрана в совместной игре" +msgid "Minimap" +msgstr "Мини-карта" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Размер шрифта" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Камера" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Пользовательская…" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Показывать счётчик кадров" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Показывать усилители других картов" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Включить таймер в режиме истории" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Включить таймер скоростного прохождения" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Разрешение отрисовки" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Уровень графических эффектов" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Уровень эффектов размытия" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Предел кадровой частоты" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Пользовательские настройки…" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Разрешение монитора" +msgid "Performance tests" +msgstr "Проверки производительности" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Полноэкранный режим" +msgid "Performance test of the current settings" +msgstr "Проверка производительности текущих настроек" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Запоминать расположение окна" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Запомнить пароль" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Применить новое разрешение монитора" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Удалить" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Цвет карта" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2390,15 +2531,15 @@ msgstr "Синяя команда" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Число кругов" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Число виртуальных картов" @@ -2413,33 +2554,17 @@ msgstr "Число виртуальных картов синей команды msgid "Random Grand Prix" msgstr "Случайное Гран-при" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Править избранные треки" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Вход" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Запомнить пароль" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Удалить" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Цвет карта" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Обложку интерфейса можно поменять в настройках Интерфейса." @@ -2558,238 +2683,306 @@ msgid "" msgstr "Не становитесь на пути товарища по команде, несущего мяч, но вы можете попытаться ударить соперника и тем самым помешать ему забить." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Адиуми" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Аманда" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Годетта" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Эмуль" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Гаврош" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Гну" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Хексли" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Кики" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Конки" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Нолок" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Пиджин" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Паффи" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Перчинка" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Сара" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Сюзанна" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Такс" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Вильбер" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Ксю" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Допотопная пропасть" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Инопланетный сигнал" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Древний лабиринт Колизея" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Город Кандела" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Остров баталий" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Чёрный лес" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Впадина Икс" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Храм Какао" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Кукурузное поле" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Форт Магма" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Остров Гран-Парадизо" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Асьенда" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Падение в дыру" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Ледяное футбольное поле" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Что не так, маленькие пухляши? Ваш великий вождь Гну пропал?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Ах да, видите ли, он у меня сейчас в замке и будет подан на ужин…" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Но я благородный, и потому у меня есть предложение." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Если ты победишь меня в гонке, то я освобожу старикашку." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "Но вы, жалкие дурачки, никогда не сможете победить меня — Короля гонок!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Арена Лас-Дюнас" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Футбольный Стадион Лас-Дюнас" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Вокруг маяка" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Старая шахта" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Мини-гольф" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Оазис" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Кабинет математики Оливера" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Тыквенный парк" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Особняк Рейвенбридж" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Ползучие пески" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Пруд Несси" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Северный курорт" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Снежная вершина" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Футбольное поле" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Стадион" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "Корпорация STK" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Храм" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Вулканический остров" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Сад Дзэн" @@ -2798,11 +2991,11 @@ msgstr "Сад Дзэн" msgid "Completed achievement \"%s\"." msgstr "Получено достижение «%s»." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Не удалось подключиться к серверу дополнений SuperTuxKart." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Ошибка при получении новостей: «%s»." @@ -2868,7 +3061,7 @@ msgid "New kart '%s' now available" msgstr "Доступен новый карт «%s»" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2900,32 +3093,32 @@ msgid "" "created." msgstr "Ваш файл с настройками устарел, поэтому он был удалён и заменён новым." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Началась запись видео." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Видео сохранено в «%s»." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Прогресс кодирования:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "К/с: %d/%d/%d - %d КПол, Отклик: %d мс" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Совет: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Загрузка" @@ -2947,19 +3140,18 @@ msgstr "Эффективность нитро" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (с гандикапом)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s готов(a)" @@ -3433,21 +3625,21 @@ msgid "Axis %d" msgstr "Ось %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Кнопка контроллера %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Кнопка мыши %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Ось мыши %d %s" @@ -3621,26 +3813,30 @@ msgstr "У вас может быть не больше 3 жизней!" msgid "+1 life." msgstr "+1 жизнь." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Вы были слишком медленным!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Вы завершили гонку!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Вы выиграли гонку!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Вы финишировали на %d месте!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s покинул(а) игру." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3649,16 +3845,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart может подключаться к серверу для загрузки дополнений и уведомлять вас об обновлениях. Пожалуйста, прочтите нашу политику конфиденциальности на https://supertuxkart.net/Privacy. Хотите включить эту возможность? (Для правки этой настройки перейдите в «Настройки» > «Основные» > «Подключаться к интернету»)." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Разрешение вашего монитора слишком низкое для запуска игры." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "У вас старый видеодрайвер. Пожалуйста, обновите его." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3666,38 +3862,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "У вас устаревший видеодрайвер. Пожалуйста, проверьте доступные обновления. Для SuperTuxKart желателен драйвер поддерживающий %s и выше. Игра, скорее всего, запустится, но в режиме упрощённого качества изображения." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Истекло время ожидания соединения с сервером." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s взял(а) красный флаг!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Красный флаг был возвращён!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s взял(а) синий флаг!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Синий флаг был возвращён!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s захватил(а) синий флаг!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s захватил(а) красный флаг!" @@ -3707,7 +3903,7 @@ msgstr "%s захватил(а) красный флаг!" msgid "Eggs: %d / %d" msgstr "Яйца: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Лидер" @@ -3715,22 +3911,22 @@ msgstr "Лидер" msgid "Final lap!" msgstr "Последний круг!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Круг %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr " %s от %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Новый лучший круг" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "НЕВЕРНОЕ НАПРАВЛЕНИЕ!" @@ -3744,7 +3940,7 @@ msgstr "%s забил гол!" msgid "Oops, %s made an own goal!" msgstr "Ой, %s забил гол сам себе!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" @@ -3753,187 +3949,187 @@ msgstr[1] "%i карта с запасными колёсами появилос msgstr[2] "%i картов с запасными колёсами появилось!" msgstr[3] "%i карта с запасными колёсами появилось!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Вы выбыли из гонки!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "«%s» выбыл(а) из гонки." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Сервер был отключён." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Вы были выкинуты с сервера." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Вас выкинуло: слишком долгий отклик." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Обнаружено неустойчивое соединение с сетью." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Бот" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s покинул(а) сервер." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Нажмите на имя игрока в списке для управления и получения информации по рейтингу." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Сложность: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Максимум игроков: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Режим игры: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Ограничение по времени" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Ограничение по голам" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Режим футбола: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Прохождение Гран-при: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Все игроки присоединились к красной или синей командам." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Вы теперь владелец сервера." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Соединение отклонено: сервер занят." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Соединение отклонено: выдан запрет на пребывание на сервере." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Соединение отклонено: неверный пароль сервера." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Соединение отклонено: несовместимые игровые данные." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Соединение отклонено: сервер переполнен." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Соединение отклонено: подключение недопустимого игрока." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Не удалось начать сетевую игру." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Игра закончилась, вы больше не можете подключиться или наблюдать." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Не осталось места в арене — подключение отклонено." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Всего 1 игрок остался, возврат в лобби" -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Владелец сервера покинул игру." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Вы будете наблюдать в следующей игре." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s присоединился к красной команде." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s присоединился к синей команде." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s присоединился к игре." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3941,15 +4137,15 @@ msgid "" msgstr "Нажмите «%s» или «%s» для смены наблюдаемого игрока, «%s» или «%s» — для смены позиции камеры." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "Жалоба на %s успешно отправлена." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3980,38 +4176,38 @@ msgstr "Гонка на время (Гран-при)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Битва против всех" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Захват флага" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s сейчас в сети." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s и %s сейчас в сети." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s и %s сейчас в сети." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4021,12 +4217,12 @@ msgstr[2] "%d друзей в сети." msgstr[3] "%d друзей в сети." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s сейчас на сервере «%s»." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4035,7 +4231,7 @@ msgstr[1] "У вас %d новых запроса в друзья!" msgstr[2] "У вас %d новых запросов в друзья!" msgstr[3] "У вас %d новых запросов в друзья!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "У вас новый запрос в друзья!" @@ -4064,12 +4260,12 @@ msgid "" msgstr "Таблица результатов устарела,\nвсе результаты были удалены." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Преследование лидера" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Битва трёх ударов" @@ -4082,93 +4278,88 @@ msgstr "Незаконченный повтор не будет сохранён msgid "Replay saved in \"%s\"." msgstr "Повтор сохранён в «%s»." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 неделя" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 недели" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 месяц" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 месяца" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 месяцев" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 месяцев" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 год" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 года" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Название дополнения" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Дата обновления" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Не установлено" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s, автор: %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Пожалуйста, подождите, пока дополнения обновятся" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Извините, произошла ошибка при обращении к сайту дополнений. Убедитесь в том, что соединение с интернетом активно и SuperTuxKart не заблокирован межсетевым экраном" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Избранное" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Заблокировано: пройдите активные испытания для получения доступа!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Случайная арена" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d арена недоступна в одиночном режиме." -msgstr[1] "%d арен недоступно в одиночном режиме." -msgstr[2] "%d арен недоступно в одиночном режиме." -msgstr[3] "%d арены недоступны в одиночном режиме." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nAndrei Stepanov, 2015-2022\nBenau, 2018-2020\nDmitry Dubrov, 2015\nLev Belousov, 2020\nMazur Bogdan, 2018-2019\nMIKHAIL DOMCHENKOV, 2020\nOleg, 2015\nValeri, 2016,2018\ncda3b49fcd26cff178434c994782573e_67b0153 , 2018\nОлег Лазарев, 2017,2019\nAndrei Stepanov, 2015-2021\nVladislav Tananaev, 2018\nAleXoundOS\nAlexander 'FONTER' Zinin\nAndrey Olykainen\nDenis Deryabin\nDmitriy Koshel\nDmitry\nDmitry Dubrov\nHelen Antonova\nIgor Shtompel\nKirill Babeev\nKroArtem\nMaxim Kalinin\nSTK-team\nTae-Wong SEO\nadem\npingvin\nДмитрий\nОлег\nJay ZDLin" @@ -4456,7 +4647,7 @@ msgstr "Собрано бананов" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Занос" @@ -4559,7 +4750,7 @@ msgstr "Охот за яйцами завершено" msgid " (official tracks matching the goal)" msgstr " (официальные трассы, подходящие под цель)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4567,91 +4758,95 @@ msgid "" msgstr "Новые контроллеры автоматически появятся в списке после того, как вы подключите их к этому устройству.\n\nЧтобы добавить настройки клавиатуры, вы можете нажать на кнопку, находящуюся ниже. Но учтите, что большинство клавиатур поддерживают ограниченное число одновременных нажатий клавиш и поэтому не подходят для многопользовательской игры. (Однако вы можете решить эту проблему подключением нескольких клавиатур к компьютеру. Но даже в этом случае нужно назначать различные сочетания клавиш для разных игроков.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Добавить контроллер Wii" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Добавить схему клавиатуры" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Обновить" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Версия: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "избранное" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Размер: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Вы должны войти, чтобы оценить это дополнение." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Извините, загрузка дополнения не удалась" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Проблемы с установкой дополнения «%s»." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Попробуйте снова" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Проблемы с удалением дополнения «%s»." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Фоновая загрузка завершена." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Фоновая загрузка" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Фоновая загрузка уже началась." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Текущий пароль неверен." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Пароль должен содержать от 8 до 30 символов!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Пароли не совпадают!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Подтверждение информации" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Пароль успешно изменён." @@ -4674,67 +4869,97 @@ msgstr "Разрешения меньше 1024×768 или 1280×720 не под #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Погоня за дроном" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Свои" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Откл." #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Только важные" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Очень низко" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Низко" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Средний" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Высоко" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Очень высокие" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Сверхвысокие" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4742,7 +4967,7 @@ msgid "" msgstr "SuperTuxKart скачает все ресурсы, необходимые для полноценной игры, включая текстуры высокого разрешения и музыку. Если у вас нет подключения Wi-Fi, то будет использован мобильный трафик." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4759,101 +4984,102 @@ msgstr "Введите адрес сервера, по желанию допиш msgid "Invalid server address: %s." msgstr "Неверный адрес сервера: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Обратное направление" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Сложность" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Круги" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Время" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Карт" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Пользователь" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Версия" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Нет" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Трасса" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Лучшие %d результатов" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Число картов: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Цель по времени: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Число кругов: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Обратное направление: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Пусто)" @@ -4927,7 +5153,7 @@ msgstr "Получение информации о рейтинге %s" #: src/states_screens/dialogs/network_player_dialog.cpp:194 #, c-format msgid "Tell server administrator about this player (%s):" -msgstr "Скажите администратору сервера об этом игроке (%s):" +msgstr "Расскажите администратору сервера об этом игроке (%s):" #. I18N: In press a key dialog, tell user to press a key to bind configuration #: src/states_screens/dialogs/press_a_key_dialog.cpp:43 @@ -4941,33 +5167,41 @@ msgid "Press any key..." msgstr "Нажмите любую кнопку…" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Чат отключён, включите его в меню настроек." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Вернуться к проверке производительности" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Покинуть проверку производительности" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Вернуться в битву" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Настроить новую игру" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Начать битву заново" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Покинуть битву" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Новая гонка" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Выйти из гонки" @@ -4983,11 +5217,11 @@ msgstr "%s не имеет ранга." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s занимает %d-е место в рейтинге и имеет %f очков." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Имя пользователя или электронная почта неверны." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5009,7 +5243,7 @@ msgstr "Гонка с призраком из повтора" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Число кругов: %i" @@ -5022,21 +5256,21 @@ msgstr "Тип: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Требуемый ранг: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Необходимое время: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Необходимое количество нитро: %i" @@ -5049,54 +5283,54 @@ msgstr "Число виртуальных картов: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Режим битвы" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Режим футбола" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Расположение сервера: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Текущая трасса: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Ранг" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Игрок" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Очки" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Время в игре" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Убрать сервер из избранного" @@ -5109,74 +5343,74 @@ msgid "No player available for connecting to server." msgstr "Нет доступных игроков для подключения к серверу." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Имя пользователя: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Отменить запрос" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Сегодня" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Заявка в друзья отправлена!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Заявка в друзья принята!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Заявка в друзья отклонена!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Друг удалён!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Заявка в друзья отменена!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Обработка" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Получение последнего голоса" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Вы можете изменить оценку нажатием на звёзды ниже." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Вы ещё не голосовали за это дополнение. Выберите желаемую оценку нажатием на звёзды ниже." -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Голос засчитан! Теперь вы можете закрыть окно." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Выполнение голосования" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Случайная трасса" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5205,7 +5439,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "При сохранении вашего Гран-при возникла ошибка." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Выберите трассу" @@ -5249,12 +5483,12 @@ msgstr "Вы открыли трассу «%0»" msgid "You unlocked grand prix %0" msgstr "Вы открыли Гран-при «%0»" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Трасса" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5275,19 +5509,19 @@ msgstr "Пожалуйста, введите название Гран-при" msgid "Please select a Grand Prix" msgstr "Пожалуйста, выберите Гран-при" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Пользовательские" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Название не задано." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Гран-при с таким же названием уже существует." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Слишком длинное название." @@ -5296,19 +5530,19 @@ msgstr "Слишком длинное название." msgid "Better luck next time!" msgstr "Удачи в следующий раз!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Вы прошли испытание!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Вы выиграли Гран-при!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Вы завершили Гран-при!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Число картов" @@ -5321,110 +5555,125 @@ msgstr "Вы действительно хотите удалить эту за msgid "Are you sure you want to remove all of your high scores?" msgstr "Вы действительно хотите удалить все ваши лучшие результаты?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Избранный" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Лёгкий" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Тяжёлый" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Подключите клавиатуру или контроллер для совместной игры с разделённым экраном" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Случайный карт" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Заблокировано" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Всем:\nДля присоединения к игре нажмите клавишу «Выбрать»" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Хотите начать обучение по игре?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Вы не сможете играть по сети без интернет-соединения. Если хочется поиграть по сети, то откройте «Настройки» и включите «Подключаться к интернету»." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Вы не сможете загружать дополнения без доступа к интернету. Если вы хотите загружать дополнения, то откройте «Настройки» и включите «Подключаться к интернету»." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Вы не сможете загружать дополнения без доступа к интернету. Если вы хотите загружать дополнения, , то откройте «Настройки» и включите «Подключаться к интернету».\n\nОднако, вы можете удалить уже загруженные дополнения." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Модуль дополнений отключён в «Настройках»" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Пожалуйста, подождите, пока дополнения будут загружены" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Вы действительно хотите покинуть STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Создать локальный сервер" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Сервер %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Число трасс Гран-при" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Имя должно содержать от 4 до 30 символов!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Недопустимые символы в пароле!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Готов" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Подключиться" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Наблюдать" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Установить дополнение" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5432,7 +5681,7 @@ msgstr "Пожалуйста, дождитесь конца текущей иг #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Пожалуйста, дождитесь конца текущей игры, осталось примерно: %s." @@ -5440,24 +5689,24 @@ msgstr "Пожалуйста, дождитесь конца текущей иг #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Пожалуйста, дождитесь конца текущей игры (%s), примерный прогресс: %s %." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Пожалуйста, дождитесь конца текущей игры, примерный прогресс: %d %." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Пожалуйста, дождитесь конца текущей игры." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5468,7 +5717,7 @@ msgstr[3] "Игра начнётся, если наберётся больше % #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5479,96 +5728,108 @@ msgstr[1] "Начало через %d секунды или как только msgstr[2] "Начало через %d секунд или как только все участники нажмут кнопку «Готов»." msgstr[3] "Начало через %d секунды или как только все участники нажмут кнопку «Готов»." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Подключение к серверу «%s»" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Поиск сервера для быстрой игры" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Осталось времени: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Цели" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Получение достижений" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Профиль %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Дата" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Статус" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Получение списка друзей" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Новый запрос" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Ожидание" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Не в сети" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Введите новую электронную почту ниже" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Адрес новой почты должен быть в пределах от 5 до 254 символов!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Новая эл. почта является неверной!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "Электронная почта изменена!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Не удалось сменить почту: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Новости из блога STK" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Дата" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "На данный момент нет новостей." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Вам нужно войти, чтобы играть по интернету. Выберите ваше имя пользователя выше." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Производится поиск" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Выйти из игры" @@ -5646,34 +5907,34 @@ msgid "Distance (km)" msgstr "Расстояние (км)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Неизвестно" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Не удалось распознать IPv4, скорее всего, вы не сможете подключаться к серверам по этому протоколу." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Не удалось распознать IPv6, скорее всего, вы не сможете подключаться к серверам по этому протоколу." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Нет доступных серверов." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Получение серверов" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Избранные серверы" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5681,149 +5942,149 @@ msgstr "Если большинство игроков выберет одни #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Случайное размещение усилителей" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Число голов для победы" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Гонка в обратном направлении" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Заблокировано: пройдите активные испытания для получения доступа!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Действие" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Привязка клавиш" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Отключить устройство" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Включить устройство" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Включить схему" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Игровые клавиши" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Клавиши меню" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Поворот налево" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Поворот направо" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Газ" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Тормоз / задний ход" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Огонь" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Нитро" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Оглянуться назад" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Возврат на трассу" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Поставить на паузу" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Вверх" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Вниз" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Влево" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Вправо" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Выбрать" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Отмена / назад" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Синий цвет означает конфликт с другой схемой" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Красный цвет означает конфликт в текущей схеме" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5831,17 +6092,27 @@ msgid "" msgstr "Внимание! Нежелательно использовать клавишу «Shift», так как при её нажатии все клавиши нижнего регистра могут не работать." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Вы действительно хотите удалить эту схему?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Введите название новой схемы или оставьте его пустым, чтобы вернуть стандартное значение." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Вертикальное" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Горизонтальное" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5849,89 +6120,74 @@ msgstr "В режиме совместной игры игроки могут в #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Установить ресурсы полной игры" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Вы действительно хотите удалить ресурсы полной игры?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Клавиатура %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Сенсорное устройство" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Коснитесь устройства для его настройки" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Язык системы" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "В левом нижнем углу" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "С правой стороны" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Скрыто" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "По центру" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Вертикальное" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Горизонтальное" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Самый малый" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Малый" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Средний" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Большой" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Самый большой" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5941,128 +6197,133 @@ msgid "" msgstr "Режим скоростного прохождения можно задействовать только в случае, если игра не была закрыта после начала режима истории.\n\nЗакрытие игры до завершения режима истории аннулирует таймер.\n\nЧтобы задействовать режим скоростного прохождения, пожалуйста, используйте новый профиль." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Вертикальная синхронизация" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Вертикальная синхронизация заставляет видеокарту передавать\nновый кадр только тогда, когда монитор готов его отобразить." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Не будет работать без поддержки вашим драйвером." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Эффекты частиц: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Анимированные персонажи: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Динамическое освещение: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Рассеяние света: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Сглаживание: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Глобальное затенение: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Тени: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Тени: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Свечение: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Контурное свечение: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Сумеречные лучи: %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Качество изображения: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Детализация геометрии: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Размытие в движении: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Глубина резкости: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Доступ в интернет отключён. Вы хотите включить его?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Вам нужно ввести пароль." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Выход из «%s»" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Вход как «%s»" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Вы не можете удалить единственного игрока." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Вы действительно хотите удалить игрока «%s»?" @@ -6090,7 +6351,7 @@ msgstr "ГОЛ!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Ожидание других игроков" @@ -6125,7 +6386,7 @@ msgstr "Следуйте за лидером!" msgid "Top %i" msgstr "Топ-%i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Испытание провалено" @@ -6149,102 +6410,199 @@ msgstr "Нажмите на значок подиума для старта ис msgid "Press fire to start the challenge" msgstr "Нажмите «Огонь» для старта испытания" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Вернуться к настройкам видео" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Сохранить результаты проверки" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Вернуться в главное меню" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Покинуть сервер" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Прервать Гран-при" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Начать заново" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Назад к выбору испытаний" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Гонка против нового повтора с призраком" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Вернуться в меню" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Вы действительно хотите прервать Гран-при?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Отчёт производительности сохранён в «%s»." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Красная команда победила" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Синяя команда победила" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Ничья" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Выбыл после %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Выбыл(а) из гонки" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(автогол)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Трасса %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Прогресс Гран-при:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Результаты" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Лучшее время круга: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "от %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Вы прошли испытание!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Вы провалили испытание!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Достигнуты нормативы SuperTux" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Результаты проверки производительности" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Длительность проверки: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Количество кадров: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "Постоянная частота кадров: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "Наиболее постоянная частота кадров: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "Обычная частота кадров: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Разрешение по горизонтали: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Разрешение по вертикали: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Динамическое освещение: ВКЛ" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Динамическое освещение: ОТКЛ" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Разрешение отрисовки: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Сглаживание: ВКЛ" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Сглаживание: ОТКЛ" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Освещение на основе изображения: ОТКЛ" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Освещение на основе изображения: ВКЛ" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Глобальное затенение: ВКЛ" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Глобальное затенение: ОТКЛ" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Разрешение теней: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Все возможности доступны, так что собирайте оружие и используйте его с умом!" @@ -6285,28 +6643,28 @@ msgstr "Нажмите на красный или синий футбольны #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Автор трассы: %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Максимальное число игроков: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Число виртуальных картов красной команды" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Вы не можете участвовать в этом Гран-при, потому что часть его треков не разблокирована!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Заблокировано!" @@ -6328,10 +6686,12 @@ msgid "%d/%m/%Y" msgstr "%d.%m.%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Закончите все испытания, чтобы открыть огромную дверь!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6340,41 +6700,48 @@ msgid "" msgstr "Вам нужно больше очков\nдля доступа к этому испытанию!\nДоступные испытания\nуказаны на мини-карте." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Разгоняйтесь при помощи «%s», поворачивайте нажатием «%s» и «%s»." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Разгоняйтесь, касаясь верхней части колеса, и управляйте движением влево или вправо." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Разгоняйтесь, перемещая ускоритель вверх, и управляйте голосовыми командами вашего устройства." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Разгоняйтесь, перемещая ускоритель вверх, и управляйте, наклоняя ваше устройство." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Собирайте голубые коробки и используйте оружие с помощью кнопки «%s», чтобы убрать эти ящики с пути!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Собирайте голубые коробки и используйте оружие нажатием иконки с боулингом, чтобы убрать эти ящики с пути!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6382,34 +6749,41 @@ msgid "" msgstr "Нажмите «%s», чтобы обернуться.\nНажмите кнопку огня «%s» при зажатии «%s» для стрельбы назад!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Нажмите на значок зеркала, чтобы посмотреть назад.\nЧтобы выстрелить назад, зажмите значок с зеркалом и проведите не отрываясь до значка с боулингом!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Используйте собранные вами нитро-заряды нажатием «%s»!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Используйте собранные вами нитро-заряды нажатием на значок с нитро" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Подберите нитро-заряды (мы будем использовать их после поворота)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Ой! Если вы в беде, нажмите «%s», чтобы вас спасли!" #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Ой! Если вы в беде, нажмите на значок с птицей, чтобы вас спасли!" #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6417,24 +6791,27 @@ msgid "" msgstr "Ускорьтесь и во время поворота нажмите кнопку «%s» для выполнения заноса.\nНемного проскользив, вы сможете быстрее преодолеть крутой поворот." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Ускорьтесь и во время поворота нажмите на иконку скольжения для выполнения заноса.\nНемного проскользив, вы сможете быстрее преодолеть крутой поворот." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Учтите, что если вам удастся проскользить в течение нескольких секунд, вы получите дополнительное ускорение в качестве награды." #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Теперь вы готовы к гонкам. Успехов!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Свободная трёхмерная гоночная игра на машинках" @@ -6444,7 +6821,7 @@ msgstr "Свободная трёхмерная гоночная игра на msgid "tux;game;race;" msgstr "такс;игра;гонка;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6452,7 +6829,7 @@ msgid "" "for all ages." msgstr "Карты. Нитро. Скорость! SuperTuxKart — это свободная трёхмерная аркадная гоночная игра с множеством персонажей, трасс и режимов. Прежде всего мы стремимся создать весёлую и приятную игру, подходящую для всех возрастов." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6461,7 +6838,7 @@ msgid "" "your opponents." msgstr "У нас для игроков есть несколько треков с различными темами — гонки под водой, по сельской местности, по джунглям и даже в космосе! Испытайте себя в соревновании с другими картами, но ни в коем случае не ешьте бананы! Следите за шарами для боулинга, поршнями, жевательной резинкой и пирожными, брошенными вашими противниками." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6470,27 +6847,27 @@ msgid "" "your racing skills!" msgstr "Вы можете создать гонку против других картов, посоревноваться в одном из нескольких Гран-При, попытаться побить лучшее время, устроить битву против друзей или ботов, или попробовать другие режимы! Если же вы хотите усложнить игру и показать свои навыки, то попробуйте сыграть вместе с игроками со всего мира посредством онлайн-гонок!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "В этой игре нет рекламы." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Данная версия SuperTuxKart является нестабильной и содержит последние улучшения. Она выпущена в основном для тестирования, что поможет сделать финальную версию как можно лучше." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Эта версия может быть установлена на одном устройстве вместе со стабильной версией." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Если вам нужна большая надёжность, воспользуйтесь стабильной версией: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "Команда SuperTuxKart" diff --git a/data/po/rue.po b/data/po/rue.po index 111309b0739..4315c79ccb3 100644 --- a/data/po/rue.po +++ b/data/po/rue.po @@ -11,7 +11,7 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" "Last-Translator: Ондрош Руснак, 2022-2024\n" "Language-Team: Rusyn (http://app.transifex.com/supertuxkart/supertuxkart/language/rue/)\n" @@ -170,7 +170,7 @@ msgstr "На крайови світа" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Назад" @@ -192,7 +192,7 @@ msgstr "Уберіт тіп корманьованя, кутрый ся вам #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Акцелерометер" @@ -206,13 +206,13 @@ msgstr "Акцелерометер" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Ґіроскоп" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Кормань" @@ -235,7 +235,7 @@ msgstr "Можете то пак перемінити у штімованьох #. I18N: ./data/gui/dialogs/kart_color_slider.stkgui #. I18N: In the kart color slider dialog msgid "Apply" -msgstr "Трібовати" +msgstr "Захосновати" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui msgid "Touch Device Settings" @@ -243,35 +243,37 @@ msgstr "Штімованя сенсора" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Чолові" @@ -339,30 +341,33 @@ msgstr "Вернути штімованя як было" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Одмінити" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Айно" @@ -540,9 +545,9 @@ msgstr "Прикапчати ся" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -603,7 +608,7 @@ msgstr "Цїль" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Проґрес" @@ -638,7 +643,7 @@ msgstr "Загнати" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Вернути ся од перебігови" @@ -655,7 +660,7 @@ msgstr "Вернути ся у лобі" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Перезачати перебіг" @@ -719,12 +724,12 @@ msgstr "Уведіт имня хосновача тай адрес електр #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Юзернейм" @@ -765,7 +770,7 @@ msgstr "Чажкость" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Новак" @@ -777,7 +782,7 @@ msgstr "Новак" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Просїковый" @@ -789,7 +794,7 @@ msgstr "Просїковый" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Експерта" @@ -801,7 +806,7 @@ msgstr "Експерта" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -809,8 +814,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Режім бавкы" @@ -821,8 +826,8 @@ msgstr "Режім бавкы" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Нормалный перебіг" @@ -835,7 +840,7 @@ msgstr "Нормалный перебіг" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Перебіг на час" @@ -843,7 +848,8 @@ msgstr "Перебіг на час" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Битка" @@ -852,24 +858,24 @@ msgstr "Битка" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Фодбал" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Парола" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Забити сись сервер у облюбені" @@ -880,7 +886,7 @@ msgstr "Придати бавляча" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Имня" @@ -974,6 +980,50 @@ msgstr "Намірити клопцї ESC" msgid "Assign nothing" msgstr "Нич не намірено" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Рекомендовані штімованя ґрафікы" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Рекомендовані штімованя будут чинні для тепирішнього розлученя" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Што має быти пріорітетом у штімованях?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Продуктивность" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Баланс продуктивности тай якости" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Якость ґрафікы" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Економія енерґії" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Вам ся люблять ґрафічні ефекты розмытя?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Зачати тест" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -988,11 +1038,11 @@ msgstr "Штім перебіга" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Дале" @@ -1033,10 +1083,15 @@ msgstr "Арены" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Настановлено" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Перемінити любимі арены" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1046,20 +1101,20 @@ msgstr "Настановлено" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Штандард" @@ -1070,12 +1125,12 @@ msgstr "Штандард" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Придаткы" @@ -1089,27 +1144,28 @@ msgstr "Придаткы" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Вшыткі" @@ -1148,9 +1204,9 @@ msgstr "Долї" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Придати" @@ -1187,7 +1243,7 @@ msgstr "Убераня повтора перебіга з блудилом" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Ловитва яиць" @@ -1234,10 +1290,10 @@ msgstr "Обратный порядок" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Максімум часу (у мін.)" @@ -1269,9 +1325,9 @@ msgstr "Копіровати" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1282,80 +1338,80 @@ msgstr "Переназвати" msgid "Save Grand Prix" msgstr "Всокотити Великі Перемаганкы" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "SuperTuxKart Помоч" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Режімы бавкы" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Посиленя" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Бананы" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1363,56 +1419,57 @@ msgstr "Бананы" msgid "Story Mode" msgstr "Режім історії" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Виды возикув" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Бавка ворошна" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Зачати туторіал" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Зберайте синї ладичкы, они дадут вам посиленя." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Осокочуйте ся бананув!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1420,14 +1477,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Збирай нітро, што давут возмогу примножати шіковность, коли тото вам треба, як нажмете трібну клопку. Чинный уровень заряда можете увідїти зправа-здолїв." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Кідь видите дашто на замкови, значит вам треба довершити перебіг, обы тото одкрыти." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1436,34 +1493,34 @@ msgid "" "carefully before!" msgstr "Вы можете ся поховзати, кой зажмете спеціалну клавішу вадь клопку. Успішні курті поховзы поможут Вам пройти круті кривулі; серидні поховзы збулшат вашу шіковность, а великі щи май. Вы не можете ся сперти кой вас занесе, тому добрі розрахуйте свої силы перед тым!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Достанете приспішеня на стартови, кой зажмете клопку приспішеня на словови \"Позор!\", перед стартом." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Чинні призначеня клопок мож побзерати/перемінити у Штімованях" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart має пару режімув бавкы:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Простый перебіг: Любі збыткы поволені, завто збирайте посиленя ай хоснуйте їх мудро." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Перебіг на час: не є посилень, тому важні лем ваші шоферські приукы!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1471,7 +1528,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Слїдовати за лідером: Ідіт на послїдньому містови, послїдньый возик ліквідує ся каждый раз кой міряч добігат ноля. Сокотіт ся: кідь обженете лідера та будете ліквідовані тоже!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1481,30 +1538,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Суть 3 тіпы у режімах биткы: У 3 Битках на ґепц, маєте забити свойов збруйов другых. У Слободному режімови, уграть тот тко гепне другых май булше раз, позеравучи на утрату вадь час. У захватови фаны, мусите захватити фану у другої дружины на їх базі, тай не дати захватити свою." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Фодбал: Забивайте лобду у капуру при помочи свого возика," -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Ловитва яиць: Прослїдіт автомапу тай найдіт вшыткі спрятані яйця." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Повтор блудила: Попробуйте уграти у блудила у перебігах на час вадь ловитві яиць — и учиніт своє (вашоє блудило тото ваш резултат)!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Перебіг на кругы: пробіжіт максімум, што можете кругув за такый час." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1513,93 +1570,93 @@ msgid "" "wins the cup." msgstr "* У булшу часть сих бавилных режімув мож забавити у Великых Перемаганках: намість єдної трасы, пройдете нараз пару. Чим булшый рейтінґ, тым булше балув достанете. У резултатови бавляч из булшым числом балув уграт ґарґалу." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Обы уграти, збирайте такі посиленя:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Жвачка - учинит перед вами щит вадь под час натїганя назад будете лишати лїпкый ружовый слїд за собов." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" -msgstr "Громовиця - дасть вам силноє приспішеня. Сокотіт ся, обы не стратити надзор над возиком." +msgstr "Громовиця - дасть вам силноє приспішеня. Сокотіт ся, обы не стратити управляня возиком." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Колач - мече ся у майближого противника, майефектівный на куртых одстоянях тай далечинах. Такой влыяє на другі возикы пиля детонації." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Протычка - мече ся уперед, обы притягти ся за противника ззаду, вадь вержіт ззаду обы го заслїпити." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Боулінґ-лобда - летит уперед закідь не трафит, одбиват ся од стїн. Кідь побзераєте назад перед тым, як веричи она піде у обратному порядкови." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Падак - спомалює вшыткі возикы што мавут лїпшу позіцію." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Переміник - перемінює ладичкы на бананы, нітро на жвачкы, тай наопак на куртый час." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Кошаркова лобда - скаче за лідером, може давити тай спомальовати возикы на свому путьови." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Клапа на мухы - ґепне возикы, тым самым спомалит їх. Щи мож нив забрати ефекты падака ай бомбы." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Як натрафите на банан, дашто из сього прилїпит ся на возик:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Котва - раз-нараз спомалит возик." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Падак - спомалює возик, май проґресівный чим котва. Чим май скоро ідеш, тым май сперать." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Бомба - зорве ся через даякый час, тай подверже ваш возик у воздух. Заїдьте у другый возик, обы подверичи му бомбу." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Злый Нолок захватив Гну! Сисї рады вам поможут:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1608,7 +1665,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Сись знак на малув мапі указує приступні перемаганкы, які сьте щи не довершили. Горї зправа екрана, видите кулько балув у вас тепирь. Довершіт кыммайбулше перемаганок, тай Нолок зложит ся на перебіг из вами. Уграйте у сих перебігах, обы ослободити Гну!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1616,20 +1673,20 @@ msgid "" " the cup and the more points it is worth." msgstr "За уграш у перемаганках вы достаєте ґарґалу. Кажда ґарґала варта пару балув. Чим майвысшу чажкость уберете, тым лїпша тай дорожа буде ґарґала." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Кідь заробите тулько балув кулько указує сись знак, достанете дарунок. Їх є пару видув." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Не вшыткі возикы єднакі! Они ся дїлят по такым одликам:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1637,7 +1694,7 @@ msgid "" " resistant to explosions." msgstr "Маса - суть три виды возикув, кідь брати по масі: легкі, балансовані, тай чажкі. На чажкі менше влывавут падакы тай любі розмітувучі ефекты. " -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1645,7 +1702,7 @@ msgid "" " especially at low speeds." msgstr "Розбіг (приспішеня) - дуже хосенный на стартови, пусля гаварій, вадь на автомапах з великым числом кривуль. Чим легшый возик. тым май шіковно розганят ся, май на малых шіковностях." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1653,14 +1710,14 @@ msgid "" " top speed." msgstr "Максімална шіковность - чим булше, тым шіковніше возик може іти. Май хосенно на автомапах из прямыма лініями тай безмала без кривуль. Чажкі возикы мавут булшу максімалну шіковность." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Ефектівность нітро - чим булше, тым булше нітро дає шіковности вашув машынї. Чим легша машына тым май ефектівно." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1668,12 +1725,12 @@ msgid "" "easier it is." msgstr "Кідь будете пару секунд іти ззаду пиля другого возика, ток воздуха придасть вам скороты при оббіганьови. Чим легшый возик, тым легше тото учинити." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart мож бавити ворошно онлайн....:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1683,7 +1740,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Раз уберіт іконку \"онлайн\" у чоловому меню. Уберіт локалну сїтку вадь ґлобалну сїтку (трібно обы Інтернет быв уключеный у штімови). Пак вы зможете учинити свуй сервер из помочов спеціалных опцій вадь глядати межи списками єствувучых серверув, обы прикапчати ся. Даякі з них рекомендувут ся як сервера з немусайныма рейтінґовыма перебігами." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1691,14 +1748,14 @@ msgid "" " enough players. Then, you can choose your kart and vote for the next track " "to race on. An addon track is allowed only if it exists on all joined " "players and the server." -msgstr "Кой трафите на сервер, перебіг ся зачне, кой лем владарь (має корону) рішит ї зачати. Офіціалні серверы можут пущати перебігы лем тоды, кой буде доста бавлячув. Тоды можете убрати свуй возик тай проголосовати за слїдучу пісню, на якув треба ся переганяти. Придаткові співанкы приступні лем тоды, коли они суть у вшыткых прикапчаных бавлячув ай на серверови." +msgstr "Кой трафите на сервер, перебіг ся зачне, кой лем владарь (має корону) рішит го зачати. Офіціалні серверы можут пущати перебігы лем тоды, кой буде доста бавлячув. Тоды можете убрати свуй возик тай проголосовати за слїдучу автомапу, на якув треба ся переганяти. Придаткові автомапы приступні лем тоды, коли они суть у вшыткых прикапчаных бавлячув ай на серверови." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... вадь на єдному девайсови:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1708,7 +1765,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Майскорше, треба вам пару девайсув ввода. Хоснуйте екран конфіґурації входа, обы наштімовати їх. Ідеалныма будут пару ґеймпадув вадь джойстікув: на клавешницї каждому бавлячови треба буде другый комплет клопок, а булшина клавешниць можут не подойти од ворошнув бавцї, бо не поддержувут пару рувночасных нажимань клопок." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1728,7 +1785,7 @@ msgstr "Уберіт рекорд" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Булше кругув" @@ -1736,9 +1793,9 @@ msgstr "Булше кругув" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Великі Перемаганкы" @@ -1749,6 +1806,20 @@ msgstr "Великі Перемаганкы" msgid "Choose a Kart" msgstr "Уберіт возик" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Катеґорія карта" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Перемінити любимі возикы" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1762,11 +1833,11 @@ msgstr "Бавити з подїленым екраном" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Онлайн" @@ -1783,7 +1854,7 @@ msgstr "Туторіал" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Рекорды" @@ -1791,7 +1862,7 @@ msgstr "Рекорды" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Здобытя" @@ -1845,30 +1916,30 @@ msgstr "Найти сервер" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Учинити сервер" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Лобі" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Штімованя" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Зачати перебіг" @@ -1894,9 +1965,9 @@ msgstr "Увести адрес сервера" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Ваш профіл" @@ -1914,7 +1985,7 @@ msgstr "Рейтінґы бавлячув" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Цімборы" @@ -1939,7 +2010,7 @@ msgstr "Бавка разраз" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Штімованя акаунта" @@ -1989,8 +2060,8 @@ msgid "Online Username" msgstr "Онлайн юзернейм" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Зверичи паролу" @@ -2003,7 +2074,7 @@ msgid "" msgstr "Можете бавити без учиненя онлайн акаунта, просто уберавучи офлайн акаунт. Айбо не будете скапчовати ся з цімборами, голосовати за придаткы тай дале. Будьте добрі, почитайте наш устав на https://privacy.superuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Убераня сервера" @@ -2021,339 +2092,409 @@ msgstr "Хосновати IPv6 прикапченя" msgid "User search" msgstr "Гляданя хосновачув" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "SuperTuxKart Штімованя" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Екран" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Ґрафіка" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Звук" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Хосновательськый Інтерфейс" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Бавлячі" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Корманьованя" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Бисїда" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Музика" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Уключено" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Голосность" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Звукові ефекты" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Удалити конфіґурацію" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Вуключити конфіґурацію" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Вернути ся у список девайсув" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Переназвати конфіґурацію" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Уключити модельованя фізічных атрібутув (кідь ся поддержує)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Розлученя" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Повный екран" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Запомнити місто оболока" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Захосновати новоє розлученя" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Роскладованя у бавцї з подїленым екраном" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Штімованя інтернета" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Усе указовати екран входа" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Прикапченя од Інтернетови" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Уключити чет онлайн" +msgid "Enable chatting in online lobbies" +msgstr "Уключити чет у онлайн-лобійови" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Уключити чет у онлайн бавках" +msgid "Enable chatting in online matches" +msgstr "Уключити чет у онлайн матчах" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Вшелиякі штімованя" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Уключити ограниченя для бавлячув" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Стерти докус бавилні комплеты" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Клопкніт Еnter вадь двічі клопкніт на нього, обы го наштімовати" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Придати девайс" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Якый штім буде захоснованый зависит од того, яку клопку \"Select\" зажмете обы ся прикапчати од бавцї." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Мотив оформеня" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Мала мапа" +msgid "Skin variant" +msgstr "Варіант скіна" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Роскладованя у бавцї з подїленым екраном" +msgid "Minimap" +msgstr "Мала мапа" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Розмір букв" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Камера" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Властный..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Указовати образик/сек." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Указовати посиленя другых возикув" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Уключити стопер у режімі історії" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Уключити стопер у бавцї на скорость" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Розлученя рендера" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Уровень ґрафічных ефектув" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Уровень ефектув розмытя" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Максімум образ./сек" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Властный штім..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Розлученя" +msgid "Performance tests" +msgstr "Тесты продуктивности" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Повный екран" +msgid "Performance test of the current settings" +msgstr "Тест продуктивности тепирішньых штім." -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Запомнити місто оболока" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Запомнити паролу" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Затрібовати новоє розлученя" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Стерти" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Цвіт возика" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2380,15 +2521,15 @@ msgstr "Синя дружина" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Число кругув" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Число ботув" @@ -2403,33 +2544,17 @@ msgstr "Число ботув у синюв дружині" msgid "Random Grand Prix" msgstr "Трафні Великі Перемаганкы" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Перемінити любимі автомапы" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Лоґін" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Запомнити паролу" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Стерти" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Цвіт возика" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Мотив оформеня можете перемінити у штімованях хосновательського інтерфейса." @@ -2548,238 +2673,306 @@ msgid "" msgstr "Лїпше не перебивати содружиника з лобдов, айбо можете попробовати гепнути противника." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Адюмі" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Аманда" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Ґодет" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Сомар" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Ґаврош" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Гну" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Гекслі" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" -msgstr "Кікі" +msgstr "Кікія" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Конкі" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Нолок" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Піґдін" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Паффі" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Пеппер" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Сара" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Сюзанн" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Тукс" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Вілбер" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Ксю" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Роскоповоє бездно" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Чужый сіґнал" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Старинный колізей-блудилище" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Кандела-Сіті" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Остров биток" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Хаща" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Пещера Ікс" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Храм Какао" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Кендиричноє поле" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Форт маґмы" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Остров Ґран Парадізо" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Ґацієнда" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Hole Drop" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Ледовоє фодбалноє поле" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Што не так, малинькі ґіппі? Стратив ся ваш лідер Гну?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Но айяк, позерай, ун у мому замкови тай буде ми на обід..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Айбо я чесна створа, завто маву для вас токму." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Кідь уграєте у ня перебіг, ослобожу сього старого чудака." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "Айбо вы малі дуроші ниґда ня не уграєте - Короля Возикув!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Лас Дунас Арена" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Лас Дунас Фодбалный Стадіон" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Навкруг маяка" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Стара баня" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Мініґолф" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Оазіс" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Математічный клас Олівера" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Дыньовый парк" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Віла Рейвенбріджув" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Живі піскы" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Рыбник Нессі" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Сїверна пристань" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Сніжный шпіц" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Фодбаловоє поле" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Стадіон" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Enterprise" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Храм" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Вулканостров" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Дзен-сад" @@ -2788,11 +2981,11 @@ msgstr "Дзен-сад" msgid "Completed achievement \"%s\"." msgstr "Довершено здобытя \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Хыба прикапченя од SuperTuxKart серверови придаткув." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Хыба стерьханя новостюв: \"%s\"." @@ -2858,7 +3051,7 @@ msgid "New kart '%s' now available" msgstr "Новый возик \"%s\" тепирь приступный" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2890,32 +3083,32 @@ msgid "" "created." msgstr "Ваш файл штіма быв дуже старый, тому вун буде удаленый а мы учиниме другый." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Наиграня відео зачато." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Відео усокочено у \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Проґрес кодованя:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "Образ./сек: %d/%d/%d - %d KTris, Пінґ: %dмс" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Тіп (подшепт): %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Ладованя" @@ -2937,19 +3130,18 @@ msgstr "Ефективность нітро" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (ограниченый)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s готовый" @@ -3423,21 +3615,21 @@ msgid "Axis %d" msgstr "Ось %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Клопка ґеймпада %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Клопка мыши %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Ось мыши %d%s" @@ -3609,26 +3801,30 @@ msgstr "Можете мати булше за 3 жывота!" msgid "+1 life." msgstr "+1 живот." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Дуже сьте помалі!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Вы завершили перебіг" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Уграли сьте перебіг!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Кінчили сьте перебіг у ранґови %d!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s лишив бавку." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3637,16 +3833,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart може прикапчати ся од серверови для стерьханя придаткув тай уповісток за обновленя. Будьте добрі, прочитайте нашу політику конфіденціалности за адресом https://supertuxkart.net/Privacy. Хочете лишити сю опцію уключенов? (Обы перемінити тото май пак, зайдіть у штімованя, уберіт \"Чолові\", тай перемініт \"Прикапченя од інтернетови\")." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Маєте дуже низькоє розлученя екрана. обы запустити STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Верзія вашых драйверув дуже постара. Будьте добрі. покладьте послїдню верзію драйверув." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3654,38 +3850,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Ваш ґрафічный драйвер дуже старый. Будьте добрі, перевірте, ци приступно обновеня. SuperTuxKart рекомендує драйвер, поддержувучый %sвадь выше. Скорше за вшытко, бавка и так буде робити, айбо у режімови уменшеної ґрафікы." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Час прикапченя из сервером уйшов." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s має черлену фану! " #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Черлену фану вернули!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s має синю фану!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Синю фану вернули!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s захватив синю фану!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s захватив черлену фану!" @@ -3695,7 +3891,7 @@ msgstr "%s захватив черлену фану!" msgid "Eggs: %d / %d" msgstr "Яиць: %d/ %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Лідер" @@ -3703,22 +3899,22 @@ msgstr "Лідер" msgid "Final lap!" msgstr "Послїдньый круг!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Круг %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "Лїпшый круг %s из %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Новый рекорд круга" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "НЕ ТУДЫ!" @@ -3732,194 +3928,194 @@ msgstr "%s забиват лобду!" msgid "Oops, %s made an own goal!" msgstr "Йой, %s забиват сам собі! " -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "%iвозик из запасным ґолесом уявив ся!" msgstr[1] "%iвозикы из запасным ґолесом уявили ся!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Вас ліквідовали!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "\"%s\" быв ліквідованый!" -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Сервер вуключеный." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Укопкали вас із сервера." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Укопкали вас: Пінґ дуже высокый." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Поганоє інтернет споєня найдено." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s одкапчаный." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Клопкніт на имня бавляча у спискови справованя бавлячув і рейтінґової інфо." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Чажкость: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Максімум бавлячув: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Режім бавкы: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Ліміт часу" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Ліміт ґолув" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Тіп фодбалної бавкы: %s " -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Проґрес Великых Перемаганок: %d/%d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Вшыткі бавлячі прикапчали ся од черленув вадь синюв дружині." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Вы тепирь владарь сервера." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "У спойови одказано: сервер занятый." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "У спойови одказано: забанені сьте." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "У спойови одказано: серверна парола недобра." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "У спойови одказано: дані бавкы несовмістні." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "У спойови одказано: сервер повный." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "У спойови одказано: нечинный бавляч ся прикапчує." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Хыба пущеня сїткової бавкы." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Бавка ся кончила, не можете ся прикапчати вадь позерати булше." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Не є міста на арені - прикапчати ся не мож." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Лишив ся лем єден бавляч, вертаву ся у лобі." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Владарь сервера лишив бавку." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Вы будете позерати за слїдучов бавков." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%sприкапчав ся од черленув дружині." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%sприкапчав ся од черленув дружині." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%sприкапчав ся од бавцї." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3927,15 +4123,15 @@ msgid "" msgstr "Затисніт <%s> авадь <%s>, обы перемінити убратого бавляча, <%s> вадь <%s> для позіції камеры." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "Успішно репортовано %s." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3966,38 +4162,38 @@ msgstr "Перебіг на час (Великі Перемаганкы)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Слободный режім" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Захват фаны" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s тепирь онлайн." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s и %s тепирь онлайн." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s,%s тай %sтепирь онлайн." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4005,19 +4201,19 @@ msgstr[0] "%dцімбора тепирь онлайн." msgstr[1] "%d цімборув тепирь онлайн." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%sтепирь на серверови \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "Вы маєте %d новых цімборськых жадань!" msgstr[1] "Вы маєте %d новых цімборськых жадань!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Вы маєте новоє цімборськоє жаданя!" @@ -4046,12 +4242,12 @@ msgid "" msgstr "Файл рекорда дуже старый,\nвшыткі рекорды были стерті." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Слїдовати за лідером" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "3 Биткы на ґепц" @@ -4064,91 +4260,88 @@ msgstr "Неповный файл повтора не буде усокочен msgid "Replay saved in \"%s\"." msgstr "Повтор усокочено у \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 тыждинь" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 тыждинь" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 мїсяць" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 мїсяцї" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 мїсяцюв" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 мїсяцюв" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 гуд" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 гуды" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Имня придатка" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Дата обновленя" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Не установено" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s учинено %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Почекайте, закідь придаткы ся обновлят" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Перебачте, трафила ся хыба при звертаньови од сайтови придаткув. Перевірте ци прикапчані сьте од Інтернетови, и ци SuperTuxKart не заблокованый фаєрволом." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Облюбовані" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Заблоковано: раз довершіт другі перемаганкы, обы достати приступ!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Трафна арена" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d арена неприступна у осамілув бавцї." -msgstr[1] "%d арен неприступно у осамілув бавцї." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nГондрош Руснак, 2022\nОндрош Руснак, 2022" @@ -4436,7 +4629,7 @@ msgstr "Бананув зобрато" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Поховз" @@ -4539,7 +4732,7 @@ msgstr "Ловитва яиць кончила ся" msgid " (official tracks matching the goal)" msgstr "(офіціалні автомапы одвітувучі цїлї)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4547,91 +4740,95 @@ msgid "" msgstr "Нові ґеймпады ай джойстікы самі ся появлят у спискови при прикапчені їх од сьому девайсови.\n\nОбы придати штім клавешници, можете хосновати клопку долїв, АЙБО дайте позор, ож булшина клавешниць поддержувут лем малоє число єдночасных затискув клопок тай зато не подходят для ворошної бавкы. (Айбо можете прикапчати пару клавешниць, які мавут мати рузні призначеня клавіш)." #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Придати контролер Wii" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Придати штімованя клавешници" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Обновити" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Верзія: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "обробленный" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Розмір: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Треба ся залоґінити обы покласти оцінку" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Перебачте, хыба стерьханя придатка" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Хыбы наставеня придатка \"%s\"." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Попробуйте щи раз" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Хыбы из удаленьом придатка \"%s\"." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Позадньоє стерьханя довершено." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Позадньоє стерьханя" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Позадньоє стерьханя уже ся зачало." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Чинна парола нечинна." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Парола має мати довжину межи 8 тай 30 сімболами!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Паролы не єднакі!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Перевірка інфо" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Парола успішно поміняна." @@ -4652,67 +4849,97 @@ msgstr "Розлученя менші за 1024х768 вадь 1280х720 не п #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Гонитва за дроном" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Властні" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Вуключеный" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Лем важні" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Дуже низкый" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Низкый" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Балансованый" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Великый" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Дуже высокі" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ултра" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4720,7 +4947,7 @@ msgid "" msgstr "SuperTuxKart стерьхат повні ресурсы (причислювучи у них текстуры высокої якости тай музику) для лїпшого бавилного процеса, то буде хосновати ваші мобілні дані, кідь у вас не є споєня из Wi-Fi." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4737,101 +4964,102 @@ msgstr "Уведіт адрес сервера (немусайно) пак : з msgid "Invalid server address: %s." msgstr "Нечинный адрес сервера: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Обратный порядок" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Чажкость" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Кругы" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Час" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Возик" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Хосновач" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Верзія" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "No" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Автомапа" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Топ %d Рекордув" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Число возикув: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Цїльовый час: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Кругы: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Обратный порядок: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Пусто)" @@ -4919,33 +5147,41 @@ msgid "Press any key..." msgstr "Клопкніт любу клопку..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Чет вуключеный, уключіт у штімованях." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Вернути ся ид тестови продуктивности" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Лишити тест продуктивности" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Вернути ся од битцї" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Наштімовати нову бавку" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Перезачати битку" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Уйти из биткы" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Убрати новый перебіг" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Лишити перебіг" @@ -4961,11 +5197,11 @@ msgstr "%s не має рейтінґа раз." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s номер %d у рейтінґови из резултатом %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Юзернейм тай/вадь емейл нечинні." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4987,7 +5223,7 @@ msgstr "Повтор перебіга з блудилом" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Кругув: %i" @@ -5000,21 +5236,21 @@ msgstr "Вид: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Трібный рейтінґ: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Трібный час: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Трібно нітро поінтув: %i" @@ -5027,54 +5263,54 @@ msgstr "Число возикув ботув: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Режім биткы" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Режім фодбала" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Полога сервера: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Чинна автомапа: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Ранґ" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Бавляч" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Резултаты" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Часу у бавцї" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Забрати из облюбеных" @@ -5087,74 +5323,74 @@ msgid "No player available for connecting to server." msgstr "Не є бавляча приступного для прикапченя од серверови." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Юзернейм: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Одмінити запрос" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Дниськы" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Цімборськый запрос загнаный!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Цімборськый запрос приятый!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Цімборськый запрос неприятый!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Цімбор удаленый!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Цімборськый запрос одміненый1" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Обробеня" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Достаня послїдньых голосув" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Можете перемінити свуй старый рейтінґ клопкнув звізды под ним." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Вы щи не проголосовали за сись придаток. Уберіт жадаємый рейтінґ, клопкнувши на звізды под ним" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Успішно сьте проголосовали! Тепирь можете закрыти оболок." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Проведеня голосованя" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Трафна автомапа" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5183,7 +5419,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Трафила ся хыба при провбі усокотити великі перемаганкы." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Убрати автомапу" @@ -5227,12 +5463,12 @@ msgstr "Вы розблоковали автомапу %0" msgid "You unlocked grand prix %0" msgstr "Вы розблоковали великі перемаганкы %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Автомапа" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5253,19 +5489,19 @@ msgstr "Будьте добрі, уберіт имня великых перем msgid "Please select a Grand Prix" msgstr "Уберіт Великі Перемаганкы" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Бавляч опредїленый" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Имня пустоє." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Другі великі перемаганкы из сим имньом уже єствувут." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Имня дуже великоє." @@ -5274,19 +5510,19 @@ msgstr "Имня дуже великоє." msgid "Better luck next time!" msgstr "Посеренчит у другый раз!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Вы довершили перемаганкы!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Уграли сьте Великі Перемаганкы!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Вы довершили Великі Перемаганкы!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Число возикув" @@ -5299,110 +5535,125 @@ msgstr "Вы бізувні, ож хочете стерти сись рекор msgid "Are you sure you want to remove all of your high scores?" msgstr "Вы бізувні, ож хочете стерти вшыткі свої рекорды?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Любимі" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Легкый" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Чажкый" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Прикапчайте клавешницю вадь ґеймпад обы бавити ворошну бавку з подїленым екраном" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Трафный возик" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Закрыто" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Каждому:\nКлопкніт \"Select\" обы прикапчати ся од бавцї" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Хочете пройти туторіал бавкы?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Вы не можете бавити онлайн без інтернет споєня. Кідь хочете бавити онлайн, ідіт у штімованя, ай перевірте \"Прикапченя од інтернетови\"." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Вы не можете стерьховати придаткы без інтернет споєня. Кідь хочете стерьхати їх, ідіт у штімованя, ай перевірте \"Прикапченя од інтернетови\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Вы не можете стерьховати придаткы без інтернет споєня. Кідь хочете стерьхати їх, ідіт у штімованя, ай перевірте \"Прикапченя од інтернетови\". \n\nВы можете стерти уже стерьхані придаткы." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Модул придаткув тепирь вуключеный у Штімованях" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Почекайте, кой ся придаткы наладувут" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Бізувно хочете лишити STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Учинити LAN сервер" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Сервер %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Число автомап Великых перемаганок" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Имня має мати довжину межи 4 ай 30 сімболами!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Недобрі сімболы у паролі!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Готовый" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Прикапчати ся" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Слїдити" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Настановити придаток" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5410,7 +5661,7 @@ msgstr "Почекайте закідь чинна бавка кончит ся #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Почекайте закідь чинна бавка кончит ся, лишившый ся час: %s." @@ -5418,24 +5669,24 @@ msgstr "Почекайте закідь чинна бавка кончит ся, #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Почекайте закідь чинна бавка кончит ся (%s), гаданый проґрес: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Почекайте закідь чинна бавка кончит ся, гаданый проґрес: %s%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Почекайте, закідь чинна бавка ся кончит." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5444,7 +5695,7 @@ msgstr[1] "Бавка ся зачне, кідь буде бавлячув бул #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5453,96 +5704,108 @@ msgid_plural "" msgstr[0] "Зачне ся через %d секунду, вадь коли вшыткі затискнут \"Готово\"." msgstr[1] "Зачне ся через %d секунд, вадь коли вшыткі затискнут \"Готово\"." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Прикапченя од серверови %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Гляданя сервера из разраз бавков" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Лишившый ся час: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Ґолы" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Гляданя здобытюв" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Профіл %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Из" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Статус" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Гляданя цімборув" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Новый запрос" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Чеканя" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Офлайн" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Уведіт новый емейл долї" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Новый емейл має быти межи 5 ай 254 сімболами у довжину!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Новый емейл нечинный!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "Емейл поміняный!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Хыба переміны емейла: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Новості из STK блоґа" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Дата" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Тепирь не є новых новостюв." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Вы маєте зайти у сістем, обы бавити у ґлобалнув сїтцї. Клопкніт на своє имня хосновача горї." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Гляданя" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Уйти из бавкы" @@ -5620,34 +5883,34 @@ msgid "Distance (km)" msgstr "Дістанція (км)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Незнама" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "IPv4 не найденый, майже не збируєте ся подкапчати ани єдному серверови." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "IPv6 не найденый, майже не збируєте ся подкапчати ани єдному серверови." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Сервер неприступный." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Достаєме серверы" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Облюбені серверы" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5655,149 +5918,149 @@ msgstr "Кідь булшина бавлячув уберат єднакый ш #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Трафна полога предмета" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Число голув для побіды" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Іти задньым ходом (цурікати)" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Закрыто: довершуйте чинні перемаганкы, обы одкрыти приступ од булшому!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Дїя" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Призначеня клопкы" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Вуключити девайс" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Уключити девайс" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Уключити штімованя (клавешници)" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Бавилні клопкы" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Клопкы меню" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Крятати налїво" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Крятати направо" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Приспішити ся" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Гамовати / Обратный ход" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Огынь" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Нітро" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Натїгати ся назад" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Спасати" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Пауза бавкы" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Гурі" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Долї" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Налїво" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Направо" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Убрати" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Одмінити/Назад" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Синя дружина має несовмістность из другым штімованьом" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Черлена дружина має несовмістность из другым штімованьом" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5805,17 +6068,27 @@ msgid "" msgstr "Варуєме: клавіш \"Shift\" не є рекомендуємов. При затиснкуті клавіш \"Shift\" переставут фунґовати вшыткі клопкы, мавучі сімбол, рузнячый ся од верхнього реґістра." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Бізувні сьте, ож хочете навтхема стерти сись штім?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Уведіт новоє имня штіма, лишіт пустым обы вернути мовчаноє значеня." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Вертікалный" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Ґорізонталный" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5823,89 +6096,74 @@ msgstr "У ворошному режімі бавкы бавлячі можут #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" -msgstr "Настановити вшыткі бавилні ресурсы" +msgstr "Покласти full game файлы" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" -msgstr "Бізувно хочете стерти вшыткі бавилні ресурсы?" +msgstr "Бізувно хочете стерти full game ресурсы?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Клавешниця %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Сенсор" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Клопкніт на девайс, обы го наштімовати" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Сістемна бисїда" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "У нижнюв лївув части" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "У правому боцї" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Спрятано" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "По центрови" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Вертікалный" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Ґорізонталный" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Дуже малый" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Малый" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Середньый" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Великый" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Дуже великый" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5915,128 +6173,133 @@ msgid "" msgstr "Режім бавкы на скорость вуключеный. Можете го уключити, лем кідь бавка не закрывала ся из часу запуска сюжетного режіма.\n\nЗакрытя бавкы до довершеня сюжетного режіма чинит стопер нечинным.\n\nОбы хосновати режім бавкы на скорость, учиніт новый профіл." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Вертікална сінхронізація" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Vsync заставлят відеокарту указовати новый образик лем тоды,\nкой монітор готовый го указати." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Vsync не буде робити кідь го драйвера не поддержувут." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Ефекты частиць: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Анімовані поставы: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Дінамічноє світло: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Россїйованя світла: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Згладка: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Довколашна тимїнь: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Тїні: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Тїні: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Присвіченя: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Свіченя (обрисы): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Світлові зарї (світлові стовпы): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Якость образа: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Деталізованость ґеометрії: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Скаламученя у рушаньови: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Глубля різкости: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Інтернет приступ вуключеный. Хочете го уключити?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Вам треба увести паролу." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Уйшов \"%s\"" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Зайшов \"%s\"" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Вы не можете удалити єдного бавляча." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Истно хочете удалити бавляча \"%s\"?" @@ -6064,7 +6327,7 @@ msgstr "ҐОЛ!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Чекаєме другых" @@ -6099,7 +6362,7 @@ msgstr "Слїдовати за лідером" msgid "Top %i" msgstr "Топ %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Перемаганкы завалені" @@ -6123,102 +6386,199 @@ msgstr "Клопкніт знак подіума, обы зачати перем msgid "Press fire to start the challenge" msgstr "Клопкніт огынь обы зачати перемаганкы" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Вернути ся у штім ґрафікы" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Всокотити резултаты теста" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Вернути ся у чоловоє меню" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Лишити сервер" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "За Великі Перемаганкы" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Перезачати" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Вернути ся у оддїл перемаганок" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Перебіг против нового повтора блудила" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Вернути ся у меню" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Истно хочете прервати Великі Перемаганкы?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Извіт за продуктивность усокоченый у \"%s\"." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Черлена дружина уграла" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Синя дружина уграла" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Исе реміза" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Ліквідованый пусля %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Ліквідованый" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Автоґол)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Автомапа %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Проґрес Великых Перемаганок:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Рекорды" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Лїпшый час круга: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "лїпшый час має %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Вы довершили перемаганкы!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Вы завалили перемаганкы!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Достигнуті жаданя SuperTux" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Резултаты теста продуктивности" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Довгота теста: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Кулькость кадрув: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "Стабілный FPS:%s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "В основному стабілный FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "Типічный FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Ґорізонталноє розлученя: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Вертікалноє розлученя: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Dynamic lighting: УКЛ" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Dynamic lighting: ВУКЛ" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Розлученя рендера: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Anti-aliasing: УКЛ" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Anti-aliasing : ВУКЛ" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Image-based lighting: ВУКЛ" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Image-based lighting: УКЛ" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Ambient occlusion: УКЛ" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Ambient occlusion: ВУКЛ" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Розлученя тіні: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Поволені вшыткі ґепцы, тому имай збруй и хоснуй го мудро!" @@ -6259,28 +6619,28 @@ msgstr "Клопкніт черленый вадь синьый знак обы #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Автомапа учинена %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Максімум бавлячув поддержує ся: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Число ботув у черленув дружині" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Вы не можете бавити Великі Перемаганкы, бо у ньому суть щи не розблоковані автомапы!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Закрыто!" @@ -6302,10 +6662,12 @@ msgid "%d/%m/%Y" msgstr "%d/%м/%Г" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Довершіт вшыткі перемаганкы обы одкрыти велику дверь!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6314,41 +6676,48 @@ msgid "" msgstr "Треба булше балув\nОбы ся прикапчати од перемаганкам!\nПоникай на малу мапу обы\nнайти приступні перемаганкы." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Приспішуйте ся при помочи <%s>, тай кормануйте при помочи <%s> тай <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Приспішуйте ся, кывавучи верьх кормані, тай крятайте улїво вадь управо." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Приспішуйте ся, кывавучи акцелератор горї, ай крятайте схылявучи девайс." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Приспішуйте ся, кывавучи акцелератор горї, ай крятайте обертавучи девайс." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Збирайте дарункові ладичкы, ай стріляйте из збруї <%s> обы збити сї ладичкы!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Збирайте дарункові ладичкы, ай стріляйте из збруї, затиснкувши знак боулінґа обы збити сї ладичкы!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6356,34 +6725,41 @@ msgid "" msgstr "Затискніт <%s> обы понатїгати ся назад.\nСтріляйте из збруї <%s> кой затискнуто <%s> стріляєте узад!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Затискніт знак зиркала обы понатїгати ся назад.\nСтріляйте из збруї затискнувши знак зиркала, а пак потягніт перстом по знакови боулінґа!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Хоснуйте нітро, котроє сьте зобрали затискнувши <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Хоснуйте нітро, котроє сьте зобрали затискнувши знак нітро" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Зберіт бутлі з нітро (їх будеме хосновати пусля кривуль)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Йой! Кідь вы трафили у біду, затискніт <%s>, обы вас спасли." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Йой! Кідь вы трафили у біду, затискніт знак потята, обы вас спасли." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6391,24 +6767,27 @@ msgid "" msgstr "Приспіште ся ай затискніть <%s> клавіш, обы зачати ся ховзати.\nХовзаня на куртых кривулях поможе вам зайти у них." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Приспіште ся ай затискніть знак поховза, обы зачати ся ховзати.\nХовзаня на куртых кривулях поможе вам зайти у них." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Дайте позор, кідь поховзаєте ся пару секунд, достанете бонусноє приспішеня!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Вы тепирь прилажені од перебігови. Серенчі!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "3х-мірна возикова перебігова бавка из одкрытым зачаточным кодом" @@ -6418,7 +6797,7 @@ msgstr "3х-мірна возикова перебігова бавка из о msgid "tux;game;race;" msgstr "tux;бавка;гонитва;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6426,7 +6805,7 @@ msgid "" "for all ages." msgstr "Моторвозикы. Нітро. Екшен! SuperTuxKart се 3ьохмірна аркадна гонитва яка має одкрытый зачаточный код, тай рузні особы, автомапы и режімы для бавкы. Наша цїль учинити бавку яка май весела, чим реалістічна и натїшит бавлячув усьых рокув." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6435,7 +6814,7 @@ msgid "" "your opponents." msgstr "У нас пару автомап из рузным мотивом для бавлячув од подводного шоферованя, сілськых готарьств, джунґлув вадь онь у космосови! Старайте ся як лем можете, оббігавучи другі возикы, айбо не їчте бананы! Позирайте за боулінґ-лобдами, протычками ай жвачками из колачами, котрі мечут ваші противникы." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6444,27 +6823,27 @@ msgid "" "your racing skills!" msgstr "Вы можете участвовати у єдному перебігови против другых возикув, перебігати ся у єдному вадь дакулькох Великых Перемаганках, пробовати побити рекорд у перебігах на час осаміло, бавити у режімі биткы против компютора вадь цімборув тай повно другого! Обы учинити свої перебігы май чажкыма, прикапчуйте ся од другым бавлячам из усього світа, и укажіт якый из вас шофер!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Ся бавка не має реклам удну." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Се нестабілна верзія SuperTuxKart, тримлюча послїдні новоты. Она упущена для тестованя, обы учинити стабілну бавку май лїпшов." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Сю верзію мож покласти паралелно из стабілнов." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Кідь вам треба булше стабілности, подумайте про хоснованя стабілної верзії: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "SuperTuxKart Турба" diff --git a/data/po/sl.po b/data/po/sl.po index bc4a4393cb1..07785589bee 100644 --- a/data/po/sl.po +++ b/data/po/sl.po @@ -5,7 +5,7 @@ # Translators: # Andrej Znidarsic , 2015-2016,2021 # Gorzy Gorup , 2023 -# Gorzy Gorup , 2018,2023 +# Gorzy Gorup , 2018,2023,2025 # Luka116, 2023 # Sasa Batistic , 2018 # veverica c, 2022 @@ -14,9 +14,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Gorzy Gorup , 2023\n" +"Last-Translator: Gorzy Gorup , 2018,2023,2025\n" "Language-Team: Slovenian (http://app.transifex.com/supertuxkart/supertuxkart/language/sl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -173,7 +173,7 @@ msgstr "Na koncu sveta" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Nazaj" @@ -195,7 +195,7 @@ msgstr "Izberi najljubšo vrsto krmiljenja" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Merilnik pospeška" @@ -209,13 +209,13 @@ msgstr "Merilnik pospeška" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Žiroskop" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Volan" @@ -246,35 +246,37 @@ msgstr "Nastavitve za naprave na dotik" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Splošno" @@ -342,30 +344,33 @@ msgstr "Ponastavi nastavitve" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Prekliči" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Da" @@ -543,9 +548,9 @@ msgstr "Pridruži se" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -606,7 +611,7 @@ msgstr "Cilj" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Napredek" @@ -641,7 +646,7 @@ msgstr "Pošlji" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Nazaj na dirko" @@ -658,7 +663,7 @@ msgstr "Nazaj v čakalnico" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Ponovno zaženi dirko" @@ -722,12 +727,12 @@ msgstr "Da ponastavite geslo, vnesite uporabniško ime in e-poštni naslov, s ka #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Uporabniško ime" @@ -768,7 +773,7 @@ msgstr "Težavnost" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Začetnik" @@ -780,7 +785,7 @@ msgstr "Začetnik" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Voznik" @@ -792,7 +797,7 @@ msgstr "Voznik" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Dirkač" @@ -804,7 +809,7 @@ msgstr "Dirkač" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -812,8 +817,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Igralski način" @@ -824,8 +829,8 @@ msgstr "Igralski način" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Običajna dirka" @@ -838,7 +843,7 @@ msgstr "Običajna dirka" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Dirka na čas" @@ -846,7 +851,8 @@ msgstr "Dirka na čas" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Bitka" @@ -855,24 +861,24 @@ msgstr "Bitka" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Nogomet" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Geslo" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Shrani med zaznamke" @@ -883,7 +889,7 @@ msgstr "Dodaj igralca" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Ime" @@ -977,6 +983,50 @@ msgstr "Dodeli tipki ESC" msgid "Assign nothing" msgstr "Ne dodeli ničesar" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Priporočene slikovne nastavitve" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Priporočene nastavitve bodo veljavne za trenutno ločljivost." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Čemu naj dajo nastavitve prednost?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Učinkovitost" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Uravnoteži učinkovitost in kakovost grafike" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Kakovost grafike" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Varčevanje z energijo" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Ali so ti všeč grafični učinki z zabrisom?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Začni preizkus" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -991,11 +1041,11 @@ msgstr "Nastavitev dirke" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Nadaljuj" @@ -1036,10 +1086,15 @@ msgstr "Arene" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Naloženi" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Uredi najljubše arene" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1049,20 +1104,20 @@ msgstr "Naloženi" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Običajna" @@ -1073,12 +1128,12 @@ msgstr "Običajna" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Dodatki" @@ -1092,27 +1147,28 @@ msgstr "Dodatki" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Vse" @@ -1151,9 +1207,9 @@ msgstr "Premakni navzdol" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Dodaj" @@ -1190,7 +1246,7 @@ msgstr "Izbira ponovnega dirkanja z navideznim igralcem" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Lov na jajca" @@ -1237,10 +1293,10 @@ msgstr "Vzvratno" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Najdaljši čas (najmanj)" @@ -1272,9 +1328,9 @@ msgstr "Kopiraj" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1285,80 +1341,80 @@ msgstr "Preimenuj" msgid "Save Grand Prix" msgstr "Shrani turnir" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Pomoč SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Načini igre" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Bonusi" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Banane" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1366,56 +1422,57 @@ msgstr "Banane" msgid "Story Mode" msgstr "Zgodbeni način" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Razredi vozil" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Večigralski način" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Začni hitri tečaj" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Pobiraj modre škatle, saj so v njih bonusi." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Izogni se bananam!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1423,14 +1480,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Če pobereš nitro, lahko v poljubnem trenutku s pritiskom na ustrezno tipko dosežeš večje hitrosti. Svojo trenutno količino nitra lahko vidiš v stolpcu na spodnji desni strani zaslona." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Če vidiš gumb s ključavnico, kot je ta na desni strani, moraš opraviti izziv, da jo odkleneš." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1439,34 +1496,34 @@ msgid "" "carefully before!" msgstr "S pritiskom na ustrezno tipko se lahko zadrsaš. Z več zaporednimi krajšimi zdrsi lahko lažje prevoziš ostre ovinke. Srednje dolgi zdrsi ti bodo povečali hitrost, dolgi zdrsi pa še bolj. Med zdrsi se ne moreš obračati, zato predhodno usmeri vozilo v pravo smer!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Če pred začetkom dirke, ko se prikaže napis \"Pozor\", pritisneš gumb za pospešek, dobiš začetno pospešitev." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Trenutne nastavitve tipkovnice lahko spremeniš v meniju Možnosti" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart ima različne načine igre:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Običajna igra: Vse je dovoljeno, zato pobiraj bonuse in orožja ter jih pametno uporabi!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Dirka na čas: Ni bonusov, štejejo samo tvoje vozniške veščine!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1474,7 +1531,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Sledenje vodji: Poskusi se priboriti do drugega mesta, saj bo vsakič, ko števec pade na nič, zadnje vozilo izločeno. Pozor: tudi vozila, ki zapeljejo pred vodjo, bodo izpadla!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1484,30 +1541,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Obstajajo 3 načini bitke: Pri \"bitki na tri\" moraš škodovati drugim z orožji, dokler jim ne zmanjka življenj. V načinu \"vsi proti vsem\" zmaga igralec, ki v dani časovni ali poškodbeni omejitvi zada drugim največ škode. Pri \"kraji zastave\" mora tvoja ekipa prinesti zastavo druge ekipe v svojo bazo, preden druga ekipa ukrade vašo zastavo." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Nogomet: S svojim dirkalnikom porini žogo v gol." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Lov na jajca: Preišči proge in najdi vsa skrita jajca." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Že posneta tekma: Tekmuj proti posnetim dirkam na čas ali lovom na jajca ter posnemi svoj posnetek!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Preizkus na kroge: Prevozi čim več krogov v danem času." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1516,93 +1573,93 @@ msgid "" "wins the cup." msgstr "* Večino igralskih načinov je mogoče igrati po principu turnirja: namesto igranja posamezne igre jih lahko igrate več v vrsti. Boljši kot si, več točk dobiš. Na koncu igralec z največ točkami prejme pokal." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Do zmage ti lahko pomaga tudi nekaj bonusov:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Žvečilni gumi - zaščiti se s ščitom ali poglej nazaj in pusti za seboj rožnato lepljivo lužo." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Pospeševalnik - močno poveča hitrost. A pazi, da ne izgubiš nadzora nad vozilom!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Kolaček - poleti proti najbližjemu tekmecu, najbolje deluje na kratke razdalje in na dolgih ravninah. Vpliva tudi na druga vozila v bližini eksplozije." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Odmaševalnik - vrzi ga predse in potegni nasprotnika nazaj ali ga zalučaj nazaj, da nasprotnika zaslepiš." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Kegljaška krogla - gre naravnost, dokler ne zadene nasprotnika. Lahko se tudi odbija od zidov. Če gledaš vzvratno, bo poletela nazaj." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Padalo - upočasni vsa vozila pred teboj." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Zamenjava - darilne škatle se za kratek čas spremenijo v banane, pločevinke nitra v žvečilne gumije in obratno." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Košarkarska žoga - odbija se za vodjo. Med potjo lahko potlači in upočasni druga vozila." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Lopar - splošči bližnja vozila, kar jih upočasni. Uporablja se lahko tudi za odstranjevanje padal in dinamita." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Če se zaletiš v banano, se ti lahko na vozilo priklopi nekaj izmed naštetega:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Sidro - na hitro upočasni vozilo." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Padalo - upočasni vozilo počasneje kot sidro. Hitrejši kot si, močneje te upočasni." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Dinamit - po določenem času eksplodira in vrže vozilo v zrak. Če trčiš ob drugo vozilo, preneseš dinamit nanj." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Zlobni Nolok je ugrabil Gnuja! V pomoč naj ti bo nekaj nasvetov:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1611,7 +1668,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Ikona na zemljevidu prikazuje še neopravljene izzive, ki so ti na voljo. V zgornjem desnem kotu zaslona je navedeno tvoje trenutno število točk. Če opraviš dovolj izzivov, bo Nolok privolil v dirko s teboj. Gnuja lahko rešiš le tako, da zmagaš!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1619,20 +1676,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Ko opraviš izziv, osvojiš pokal. Vsak pokal je vreden nekaj točk. Višja kot je težavnost opravljenega izziva, več točk je vreden pokal." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Ko dosežeš število točk, ki je navedeno pod to ikono, te čaka presenečenje. Zbrati jih je mogoče več." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Niso vsa vozila enaka! Delimo jih na več razredov, ki se razlikujejo po sledečem:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1640,7 +1697,7 @@ msgid "" " resistant to explosions." msgstr "Teža - glede na težo obstajajo trije razredi vozil: lahka, povprečna in težka. Težja vozila so bolj odporna na padala in eksplozije." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1648,7 +1705,7 @@ msgid "" " especially at low speeds." msgstr "Pospeševanje - še posebej uporabno na začetku dirku, po nezgodi ali na progah z veliko ostrimi ovinki. Lažje kot je vozilo, hitreje pospešuje, zlasti pri nizkih hitrostih." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1656,14 +1713,14 @@ msgid "" " top speed." msgstr "Največja hitrost - višja kot je, hitrejše je lahko vozilo. Še posebej uporabno je pri progah z ravnimi predeli in blagimi zavoji. Težja vozila imajo višjo mejno hitrost." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Učinkovitost nitra - višja kot je, večjo hitrost ti prinese pločevinka nitra. Lažje vozilo bo imelo večjo učinkovitost nitra." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1671,12 +1728,12 @@ msgid "" "easier it is." msgstr "Če nekaj sekund tesno slediš drugemu vozilu, boš ob prehitevanju dobil/a dodatno hitrost. Lažje kot je tvoje vozilo, preprosteje je." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart lahko igraš v večigralskem načinu prek omrežja:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1686,7 +1743,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Najprej izberi ikono 'omrežje'. Igraš lahko bodisi na lokalnem omrežju bodisi globalno (za slednje moraš v možnostih omogočiti internet). Potem lahko ustvariš lastni strežnik po meri ali izbereš enega s seznama obstoječih strežnikov. Nekateri med njimi so priporočeni strežniki z izbirno razvrščenimi dirkami." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1696,12 +1753,12 @@ msgid "" "players and the server." msgstr "Ko si enkrat na strežniku, se bo dirka začela na povelje lastnika strežnika (spoznaš ga po kroni). Uradni strežniki lahko samodejno sprožijo dirko samo, če je prijavljenih dovolj igralcev. Potem lahko izbereš svoje vozilo in glasuješ za naslednjo progo. Dodatne proge so na voljo samo, če jih imajo nameščene vsi prisotni igralci in strežnik." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... Ali na isti napravi:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1711,7 +1768,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Najprej boste potrebovali več vhodnih naprav. Nastaviti jih je mogoče prek krmilnih nastavitev. Najbolje je, če imate več igralnih krmilnikov in igralnih palic. Če igrate s tipkovnico/tipkovnicami, bo za vsakega igralca potreben drugačen nabor tipk, in ker večina tipkovnic ne podpira hkratnega pritiskanja večjega števila tipk, niso najprimernejše za več igralcev." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1731,7 +1788,7 @@ msgstr "Izbira rekordov" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Preizkus na kroge" @@ -1739,9 +1796,9 @@ msgstr "Preizkus na kroge" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Turnir" @@ -1752,6 +1809,20 @@ msgstr "Turnir" msgid "Choose a Kart" msgstr "Izberi vozilo" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Razred vozila" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Uredi najljubša vozila" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1765,11 +1836,11 @@ msgstr "Deljen zaslon" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Na splet" @@ -1786,7 +1857,7 @@ msgstr "Hitri tečaj" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Rekordi" @@ -1794,7 +1865,7 @@ msgstr "Rekordi" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Dosežki" @@ -1848,30 +1919,30 @@ msgstr "Najdi strežnik" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Ustvari strežnik" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Čakalnica" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Nastavitve" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Začni dirko" @@ -1897,9 +1968,9 @@ msgstr "Vnesi naslov strežnika" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Tvoj profil" @@ -1917,7 +1988,7 @@ msgstr "Razvrstitev igralcev" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Prijatelji" @@ -1942,7 +2013,7 @@ msgstr "Hitra igra" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Nastavitve računa" @@ -1992,8 +2063,8 @@ msgid "Online Username" msgstr "Spletno uporabniško ime" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Ponastavi geslo" @@ -2006,7 +2077,7 @@ msgid "" msgstr "Igrati je mogoče tudi brez spletnega računa, in sicer tako, da ustvariš nepovezani račun. Z njim se ne moreš povezati s prijatelji, glasovati za dodatke ipd. Preberi si, prosim, naš pravilnik o zasebnosti na https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Izbor strežnika" @@ -2024,339 +2095,409 @@ msgstr "Uporabi povezavo IPv6" msgid "User search" msgstr "Iskanje uporabnika" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Možnosti SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Prikaz" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Grafika" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Zvok" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Vmesnik" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Igralci" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Tipke" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Jezik" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Glasba" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Omogočeno" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Glasnost" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Zvočni učinki" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Izbriši nastavitev" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Izklopi nastavitev" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Nazaj na seznam naprav" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Preimenuj nastavitev" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Omogoči silo povratnega učinka (če je podprta)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Ločljivost" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Celozaslonski način" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Zapomni si položaj okna" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Uveljavi novo ločljivost" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Postavitev deljenega zaslona" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Možnosti za internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Vedno prikaži prijavni zaslon" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Poveži se na internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Omogoči spletni klepet" +msgid "Enable chatting in online lobbies" +msgstr "Omogoči klepet v spletnih čakalnicah" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Omogoči klepet na spletnih dirkah" +msgid "Enable chatting in online matches" +msgstr "Omogoči klepet v spletnih tekmah" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Razne možnosti" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Omogoči hendikep za posameznega igralca" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Odstrani vsa sredstva igre" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Napravo nastavite tako, da pritisnete vnosno tipko (enter) ali jo dvakrat kliknete" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Dodaj napravo" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Nastavitve bodo določene glede na to, katera tipka izbire je pritisnjena za pridružitev igri." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Tema" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Zemljevid" +msgid "Skin variant" +msgstr "Različica teme" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Postavitev deljenega zaslona" +msgid "Minimap" +msgstr "Zemljevid" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Velikost pisave" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Kamera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Po meri ..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Prikaži sličice na sekundo" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Pokaži bonuse na drugih vozilih" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Vključi časomer za zgodbeni način" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Vključi časomer za hitrostno preigravanje" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Ločljivost upodobitve" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Stopnja grafičnih učinkov" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Stopnja zabrisa" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Zgornja meja sličic na sekundo" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Nastavitve po meri" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Ločljivost" +msgid "Performance tests" +msgstr "Preizkusi učinkovitosti" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Celozaslonski način" +msgid "Performance test of the current settings" +msgstr "Preizkus učinkovitosti trenutnih nastavitev" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Zapomni si položaj okna" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Zapomni si geslo" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Uveljavi novo ločljivost" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Izbriši" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Barva vozila" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2383,15 +2524,15 @@ msgstr "Modra ekipa" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Število krogov" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Število računalniških igralcev" @@ -2406,33 +2547,17 @@ msgstr "Število računalniških igralcev v modri ekipi" msgid "Random Grand Prix" msgstr "Naključni turnir" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Uredi najljubše proge" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Prijava" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Zapomni si geslo" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Izbriši" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Barva vozila" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Temo uporabniškega vmesnika lahko spremeniš v možnostih uporabniškega vmesnika." @@ -2551,238 +2676,306 @@ msgid "" msgstr "Ne zapiraj poti soigralcu, ki vodi žogo, lahko pa poskušaš ustaviti nasprotnika, ki mu namerava preprečiti strel." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godeta" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Paprika" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzana" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tuks" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Vilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Starodavno globokovodje" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Nezemljanski signal" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Starodavni kolosejski labirint" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Svetilno mesto" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Otok bitk" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Črni gozd" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Jama X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Kakavovo svetišče" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Koruzno polje" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Magmatska utrdba" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Otok Gran Paradiso" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Naluknjana tovarna" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Ledeno nogometno igrišče" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "No, no, bizgeci? Le kje je zdaj vaš veliki gnujski vodja?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Saj res! Vidite, v mojem gradu tiči in čaka, da ga bom požrl za večerjo!" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Pa vendar sem pošteno bitje, zato vam ponujam dogovor." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Če me premagate v dirki, bom starega tepca izpustil." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr "Ampak ve kilave mevže me že ne boste premagale! Saj sem vendar kralj dirkačev!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Arena Las Dunas" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Nogometno igrišče Las Dunas" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Okoli svetilnika" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Zapuščeni rudnik" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oaza" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Oliverjev matematični pouk" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Bučni park" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Dvorec Ravenbridge" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Premikajoče sipine" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Nessijin ribnik" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Severno letovišče" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Snežni vrh" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Nogometno igrišče" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Stadion" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Enterprise" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Svetišče" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Vulkanski otok" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Zenovski vrt" @@ -2791,11 +2984,11 @@ msgstr "Zenovski vrt" msgid "Completed achievement \"%s\"." msgstr "Čestitke za dosežek \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Povezava na strežnik z dodatki ni uspela." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Napaka med prejemanjem novic: '%s'." @@ -2861,7 +3054,7 @@ msgid "New kart '%s' now available" msgstr "Na voljo je novo vozilo '%s'" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2893,32 +3086,32 @@ msgid "" "created." msgstr "Tvoja nastavitvena datoteka je bila prestara, zato smo jo pobrisali. Ustvarili bomo novo datoteko." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Snemanje videoposnetka se je začelo." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Posnetek je shranjen v \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Napredek kodiranja:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Nasvet: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Nalagam" @@ -2940,19 +3133,18 @@ msgstr "Učinkovitost nitra" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (hendikepiran)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s je nared" @@ -3426,21 +3618,21 @@ msgid "Axis %d" msgstr "Os %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Gumb na igralnem ploščku %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Miškin gumb %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Miškina os %d %s" @@ -3614,26 +3806,30 @@ msgstr "Lahko imaš največ 3 življenja!" msgid "+1 life." msgstr "+1 življenje." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Bil/a si prepočasen/a!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Odpeljal/a si dirko!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Zmagal/a si!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Dirko si zaključil/a na%d. mestu!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s je zapustil/a igro" -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3642,16 +3838,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart se lahko poveže na strežnik, da z njega prenese dodatke in te obvesti o posodobitvah. Prosim, preberi naš pravilnik o zasebnosti na spletnem mestu https://supertuxkart.net/Privacy. Želiš vklopiti to funkcionalnost? (Če želiš to nastavitev spreminjati še kasneje, pojdi pod nastavitve in v zavihku 'Splošno' spremeni opcijo 'Poveži se na internet'.)" -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Ločljivost tvojega zaslona je prenizka za igro." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Tvoja različica gonilnika je prestara. Prosim, namesti najnovejše grafične gonilnike." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3659,38 +3855,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Tvoj grafični gonilnik je zelo star. Prosim, preveri, ali so na voljo posodobitve. SuperTuxKart priporoča vsaj gonilnik, ki podpira %s. Igra bo verjetno še vedno delovala, vendar bo grafika slabša." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Povezovanje s strežnikom je trajalo predolgo." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s ima rdečo zastavo!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Rdeča zastava je nazaj!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s ima modro zastavo!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Modra zastava je nazaj!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s je ukradel/a modro zastavo!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s je ukradel/a rdečo zastavo!" @@ -3700,7 +3896,7 @@ msgstr "%s je ukradel/a rdečo zastavo!" msgid "Eggs: %d / %d" msgstr "Jajca: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Vodja" @@ -3708,22 +3904,22 @@ msgstr "Vodja" msgid "Final lap!" msgstr "Zadnji krog!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Krog %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s, prevozil/a ga je %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Nov najhitrejši krog" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "NAPAČNA SMER!" @@ -3737,7 +3933,7 @@ msgstr "%s je zadel/a gol!" msgid "Oops, %s made an own goal!" msgstr "Ups, %s je dal/a avtogol ..." -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" @@ -3746,187 +3942,187 @@ msgstr[1] "Pojavili sta se %i vozili z rezervnimi gumami!" msgstr[2] "Pojavila so se %i vozila z rezervnimi gumami!" msgstr[3] "Pojavilo se je %i vozil z rezervnimi gumami!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Izpadel/a si!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "'%s' je izpadel/a." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Strežnik se je ugasnil." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Odstranili so te s strežnika." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Odstranili so te zaradi slabe povezave." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Zaznavam slabo povezavo." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s se je odklopil/a." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "S klikom na ime igralca si lahko ogledaš možnosti in informacije o njem." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Težavnost: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Največ igralcev: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Igralni način: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Omejitev časa" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Omejitev ciljev" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Tip nogometne igre: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Napredek turnirja: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Vsi igralci so se pridružili rdeči ali modri ekipi." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Zdaj si lastnik strežnika." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Povezava zavrnjena: Strežnik je zaposlen." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Povezava zavrnjena: Imaš prepoved povezovanja na ta strežnik." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Povezava zavrnjena: Geslo za strežnik je nepravilno." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Povezava zavrnjena: Igralski podatki so neskladni." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Povezava zavrnjena: Strežnik je poln." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Povezava zavrnjena: Povezuje se neveljaven igralec." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Ni uspelo začeti omrežne igre." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Igra je zaključena. Ne moreš se ji več pridružiti ali je opazovati." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "V areni ni več prostora. Naknadno pridruževanje onemogočeno." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Ostal je le še en igralec. Vračam v čakalnico." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Lastnik strežnika je odšel." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Naslednjo igro boš opazovalec/ka." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%sse je pridružil/a rdeči ekipi." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%sse je pridružil/a modri ekipi." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%sse je pridružil/a igri." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3934,15 +4130,15 @@ msgid "" msgstr "S pritiskom na <%s> ali <%s> zamenjaš opazovanega igralca. S pritiskom na <%s> in <%s> zamenjaš položaj kamere." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "%s uspešno prijavljen." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3973,38 +4169,38 @@ msgstr "Dirka na čas (turnir)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Vsi proti vsem" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Kraja zasteve" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s je zdaj povezan/a." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s in %s sta zdaj povezana." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s in %s so zdaj povezani." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4014,12 +4210,12 @@ msgstr[2] "%d prijatelji so povezani." msgstr[3] "%d prijateljev je povezanih." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s je zdaj na strežniku \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4028,7 +4224,7 @@ msgstr[1] "Imaš %d novi zahtevi za prijateljstvo!" msgstr[2] "Imaš %d nove zahteve za prijateljstvo!" msgstr[3] "Imaš %d novih zahtev za prijateljstvo!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Imaš novo zahtevo za prijateljstvo!" @@ -4057,12 +4253,12 @@ msgid "" msgstr "Datoteka z najboljšimi izidi je bila prestara,\nzato so bili vsi rezultati izbrisani." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Sledenje vodji" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Bitka na tri" @@ -4075,93 +4271,88 @@ msgstr "Nepopolna datoteka posnetka ne bo shranjena." msgid "Replay saved in \"%s\"." msgstr "Posnetek bo shranjen v \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 teden" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 tedna" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 mesec" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 meseci" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 mesecev" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 mesecev" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 leto" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 leti" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Ime dodatka" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Posodobljeno dne" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Nenameščeno" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s avtorja/ice %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Počakaj, da se dodatki posodobijo" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Žal je pri povezovanju s spletiščem dodatkov prišlo do napake. Preveri, da si povezan na internet in da tvoj požarni zid ne blokira SuperTuxKarta." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Priljubljeno" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Zaklenjeno: reši trenutne izzive za dostop do drugih!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Naključna arena" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d arena ni na voljo v enoigralskem načinu." -msgstr[1] "%d areni nista na voljo v enoigralskem načinu." -msgstr[2] "%d arene niso na voljo v enoigralskem načinu." -msgstr[3] "%d aren ni na voljo v enoigralskem načinu." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nAndrej Znidarsic, 2015-2016,2021\nGorzy Gorup, 2018\nSasa Batistic, 2018\nveverica c, 2022\nAndrej Znidarsic, 2015-2016\nAndrej Znidarsic\nAuria\nDenis_Ubuntu\nDomen Knez\nMatic Gradišer\nSTK-team\nSasa Batistic" @@ -4449,7 +4640,7 @@ msgstr "Pobranih banan" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Zadrsov" @@ -4552,7 +4743,7 @@ msgstr "Končanih lovov na jajca" msgid " (official tracks matching the goal)" msgstr "(uradne dirke, ki ustrezajo cilju)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4560,91 +4751,95 @@ msgid "" msgstr "Novi krmilniki in igralne palice se bodo samodejno pojavili na seznamu, ko jih povežeš s to napravo.\n\nS spodnjim gumbom lahko dodaš novo nastavitev tipkovnice, VENDAR opozarjamo, da večina tipkovnic podpira le omejeno število hkratnih pritiskov tipk in zato niso primerne za več igralcev. (Lahko pa na napravo povežeš več tipkovnic. Igralci morajo v tem primeru še vedno uporabljati različne tipke.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Dodaj Wii daljinec" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Dodaj nastavitev tipkovnice" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Posodobi" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Različica: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "izbrani dodatek" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Velikost: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Da lahko oceniš ta dodatek, se moraš prijaviti." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Žal je prenos dodatka spodletel" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Težave pri namestitvi dodatka '%s'." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Poskusi znova" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Težave pri odstranjevanju dodatka '%s'." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Prenos v ozadju končan." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Prenos v ozadju" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Prenos v ozadju se je že pričel." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Trenutno geslo je neveljavno." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Geslo mora biti dolgo med 8 in 30 znakov!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Gesli se ne ujemata!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Preverjam podatke" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Geslo je bilo uspešno spremenjeno." @@ -4667,67 +4862,97 @@ msgstr "Ločljivosti, nižje od 1024x768 ali 1280x720, niso podprte. Nekateri de #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Sledilni dron" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Po meri" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Onemogočeno" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Samo pomembni" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Zelo nizka" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Nizka" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Srednja" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Visoka" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Zelo visoka" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4735,7 +4960,7 @@ msgid "" msgstr "SuperTuxKart bo naložil vse podatke (vključno s teksturami in glasbo višje kakovosti) za boljšo igralno izkušnjo. Če nimaš Wi-Fi povezave, se bodo podatki prenesli prek mobilnih podatkov." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4752,101 +4977,102 @@ msgstr "Vnesi naslov strežnika in opcijsko še številko vrat, ločeno z dvopi msgid "Invalid server address: %s." msgstr "Neveljaven naslov strežnika: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Vzvratno" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Težavnost" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Krogov" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Čas" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Vozilo" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Uporabnik" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Različica" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Ne" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Proga" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Najboljših %d rekordov" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Št. vozil: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Ciljni čas: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Št. krogov: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Vzvratno: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Prazno)" @@ -4934,33 +5160,41 @@ msgid "Press any key..." msgstr "Pritisni katerokoli tipko ..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Klepet je onemogočen, omogoči ga v nastavitvah." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Nazaj na preizkus učinkovitosti" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Zapusti preizkus učinkovitosti" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Nazaj v bitko" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Nastavi novo igro" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Ponovno začni bitko" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Zapusti bitko" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Nastavi novo dirko" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Zapusti dirko" @@ -4976,11 +5210,11 @@ msgstr "%sše ni razvrščen/a." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s je na %d. mestu z dosežkom %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Uporabniško ime in/ali e-poštni naslov sta neveljavna." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5002,7 +5236,7 @@ msgstr "Dirka z navideznim igralcem" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Št. krogov: %i" @@ -5015,21 +5249,21 @@ msgstr "Vrsta: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Zahtevano mesto: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Zahtevani čas: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Zahtevan nitro: %i točk " @@ -5042,54 +5276,54 @@ msgstr "Št. računalniških igralcev: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Način bitke" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Vrsta nogometne igre" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Lokacija strežnika: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Trenutna proga: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Mesto" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Igralec" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Točke" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Preigran čas" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Odstrani iz zaznamkov" @@ -5102,74 +5336,74 @@ msgid "No player available for connecting to server." msgstr "Ni razpoložljivih igralcev za povezavo na strežnik." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Uporabniško ime: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Prekliči zahtevo" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Danes" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Prošnja za prijateljstvo poslana!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Prošnja za prijateljstvo sprejeta!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Prošnja za prijateljstvo zavrnjena!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Prijatelj odstranjen!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Prošnja za prijateljstvo preklicana!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Obdelujem" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Pridobivam zadnji glas" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Svojo prejšnjo oceno lahko spremeniš s klikom na spodnje zvezdice." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Za ta dodatek še nisi glasoval/a. S klikom na spodnje zvezdice javi svojo oceno." -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Glasovanje opravljeno! Sedaj lahko zapreš okno." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Glasovanje" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Naključna proga" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5198,7 +5432,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Med shranjevanjem turnirja je prišlo do napake." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Izberi progo" @@ -5242,12 +5476,12 @@ msgstr "Odklenil/a si progo %0" msgid "You unlocked grand prix %0" msgstr "Odklenil/a si turnir %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Proga" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5268,19 +5502,19 @@ msgstr "Vnesi ime turnirja" msgid "Please select a Grand Prix" msgstr "Izberi turnir" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Ustvaril uporabnik" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Ime je prazno." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Obstaja že drug turnir s tem imenom." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Ime je predolgo." @@ -5289,19 +5523,19 @@ msgstr "Ime je predolgo." msgid "Better luck next time!" msgstr "Več sreče prihodnjič!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Opravil/a si izziv!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Zmagal/a si na turnirju!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Opravil/a si turnir!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Št. vozil" @@ -5314,110 +5548,125 @@ msgstr "Si prepričan/a, da želiš odstraniti ta rekord?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Si prepričan/a, da želiš odstraniti vse svoje rekorde?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Priljubljena" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Lahka" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Težka" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Za večigralsko igro z deljenim zaslonom priključi tipkovnico ali krmilnik." -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Naključno vozilo" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Zaklenjeno" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Vsi:\nPritisnite gumb za izbiro, da se pridružite igri!" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Želiš igrati hitri tečaj za spoznavanje z igro?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Brez dostopa do interneta ne moreš igrati prek omrežja. Če to vendarle želiš, v nastavitvah odkljukaj \"Poveži se na internet\"." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Brez dostopa do interneta ne moreš prenesti dodatkov. Če to vendarle želiš, v nastavitvah odkljukaj \"Poveži se na internet\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Brez dostopa do interneta ne moreš prenesti dodatkov. Če to vendarle želiš, v nastavitvah odkljukaj \"Poveži se na internet\".\n\nTudi brez povezave lahko pobrišeš že prenesene dodatke." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Modul dodatkov je trenutno onemogočen v nastavitvah" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Počakaj, da se dodatki naložijo" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Si prepričan/a, da želiš zapustiti igro?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Ustvari strežnik LAN" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "Strežnik uporabnika %s" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Št. stez(e) na turnirju" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Ime mora biti dolgo med 4 in 30 znakov!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Neveljavni znaki v geslu!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Nared" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Pridruži se naknadno" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Opazuj" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Namesti dodatek" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5425,7 +5674,7 @@ msgstr "Prosim, počakaj na konec trenutne dirke (%s), predviden čas do konca: #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Prosim, počakaj na konec trenutne dirke, predviden čas do konca: %s." @@ -5433,24 +5682,24 @@ msgstr "Prosim, počakaj na konec trenutne dirke, predviden čas do konca: %s." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Prosim, počakaj na konec trenutne dirke (%s), predviden napredek: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Prosim, počakaj na konec trenutne dirke, predviden napredek: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Prosim, počakaj na konec trenutne dirke." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5461,7 +5710,7 @@ msgstr[3] "Igra se bo začela, če bo prisotnih več kot %d igralcev." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5472,96 +5721,108 @@ msgstr[1] "Začenjam po %d sekundah, oziroma ko vsi pritisnejo gumb 'Nared'." msgstr[2] "Začenjam po %d sekundah, oziroma ko vsi pritisnejo gumb 'Nared'." msgstr[3] "Začenjam po %d sekundah, oziroma ko vsi pritisnejo gumb 'Nared'." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Povezovanje na strežnik %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Iskanje strežnika s hitro igro" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Preostali čas: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Cilji" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Pridobivanje dosežkov" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "Profil uporabnika %s" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Od" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Stanje" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Pridobivanje prijateljev" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Nova prošnja" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Na čakanju" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Nepovezan" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Spodaj vnesi nov e-poštni naslov" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Nov e-poštni naslov mora imeti med 5 in 254 znakov!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Nov e-poštni naslov ni veljaven!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "E-pošni naslov spremenjen!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Sprememba e-poštnega naslova ni uspela: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Novice z bloga STK" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Datum" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Trenutno ni na voljo nobenih novic." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Za igranje v globalnem omrežju se moraš prijaviti. Klikni na svoje uporabniško ime zgoraj." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Iščem" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Končaj igro" @@ -5639,34 +5900,34 @@ msgid "Distance (km)" msgstr "Oddaljenost (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Neznano" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Ne zaznavam IPv4, mogoče se ne boš mogel/a pridružiti nobenemu strežniku." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Ne zaznavam IPv6, mogoče se ne boš mogel/a pridružiti nobenemu strežniku." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Noben strežnik ni na voljo." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Pridobivanje strežnikov" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Strežniški zaznamki" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5674,149 +5935,149 @@ msgstr "Če večina igralcev izbere isto stezo in nastavitve dirke, bo glasovanj #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Naključna postavitev predmetov" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Število golov za zmago" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Vožnja vzvratno" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Zaklenjeno: reši trenutne izzive za dostop do drugih!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Dejanje" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Vezave na tipke" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Onemogočitev naprave" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Omogočite naprave" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Omogočitev nastavitve tipkovnice" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Tipke za igranje" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Menijske tipke" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Zavoj levo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Zavoj desno" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Pospešitev" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Zavora / Vzvratno" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Sprožitev" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Pogled nazaj" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Rešitev" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Premor" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Gor" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Dol" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Levo" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Desno" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Izbira" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Preklic/Nazaj" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Modra barva pomeni navzkrižje z drugo nastavitvijo tipk" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Rdeča barva pomeni navzkrižje s trenutno nastavitvijo tipk" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5824,17 +6085,27 @@ msgid "" msgstr "Opozorilo, ne priporočamo uporabe dvigalke (shift). Če jo pritisneš, bodo vse tipke, ki imajo različne velike in male črke, prenehale delovati." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Si prepričan, da želiš trajno izbrisati to nastavitev?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Vnesi novo ime nastavitve. Pusti prazno, če želiš vrniti na privzeto vrednost." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Navpično" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Vodoravno" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5842,89 +6113,74 @@ msgstr "V večigralskem načinu lahko igralci med izbiro vozil izberejo hendikep #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Namesti vse podatke za igro" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Res želiš odstraniti dopolnilne podatke za igro?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Tipkovnica %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Naprava na dotik" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Pritisni na napravo, da jo nastaviš" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Sistemski jezik" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Spodaj levo" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "Na desni" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Skrit" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Na sredini" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Navpično" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Vodoravno" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Zelo majhna" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Majhna" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Srednja" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Velika" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Zelo velika" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5934,128 +6190,133 @@ msgid "" msgstr "Hitrostno preigravanje lahko omogočiš le, če še nisi zaprl/a igre, odkar si zagnal/a zgodbeni način.\n\nČe igro zapreš, preden dokončaš zgodbeni način, bo izmerjeni čas neveljaven.\n\nČe hočeš vklopiti način hitrostnega preigravanja, uporabi nov profil." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Navpična uskladitev (vsync)" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Vsync prisili grafično kartico, da pošlje novo sličico šele takrat, ko jo je monitor pripravljen predvajati." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Vsync ne bo deloval, če ga tvoji gonilniki ne podpirajo." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Učinki delcev: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Animirani liki: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Dinamična svetloba: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Razpršitev svetlobe: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Glajenje robov: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Ambientno zastiranje: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Sence: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Sence: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Sijaj: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Žar (obrisi): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Svetlobni žarki: %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Kakovost upodobitve: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Natančnost geometrije: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Zabris gibanja: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Globinska ostrina: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Dostop do interneta je onemogočen. Ga želiš omogočiti?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Vnesti moraš geslo." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Odjavljam '%s'" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Prijavljam '%s'" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Ne moreš izbrisati edinega igralca." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Res želiš izbrisati igralca '%s'?" @@ -6083,7 +6344,7 @@ msgstr "GOL!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Čakanje na druge" @@ -6118,7 +6379,7 @@ msgstr "Sledi vodji!" msgid "Top %i" msgstr "Najboljših %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Izziv ni opravljen" @@ -6142,102 +6403,199 @@ msgstr "Pritisni ikono z zmagovalnimi stopničkami, da začneš izziv" msgid "Press fire to start the challenge" msgstr "Pritisni sprožilno tipko za začetek izziva" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Nazaj na slikovne nastavitve" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Shrani rezultate preizkusa" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Nazaj na glavni meni" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Zapusti strežnik" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Prekliči turnir" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Znova zaženi dirko" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Nazaj na izbiro izzivov" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Tekmuj proti novem navideznem igralcu" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Nazaj na meni" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Ali si prepričan/a, da želiš preklicati turnir?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Poročilo o učinkovitosti je shranjeno v \"%s\"." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Rdeča ekipa je zmagala" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Modra ekipa je zmagala" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Izenačeno" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Izpadel/a po %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Zpadel/a" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Avtogol)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Proga %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Napredek turnirja:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Seznam najboljših" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Najboljši čas kroga: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr ", prevozil/a ga je %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Izziv ti je uspel!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Izziv ti ni uspel!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Zahteve za SuperTux dosežene" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Rezultati preizkusa učinkovitosti" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Trajanje preizkusa: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Količina sličic: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "Stabilni FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "Večinoma stabilni FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "Tipičen FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Vodoravna ločljivost: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Navpična ločljivost: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Dinamična osvetlitev: VKLOPLJENA" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Dinamična osvetlitev: IZKLOPLJENA" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Ločljivost upodabljanja: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Glajenje robov: VKLOPLJENO" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Glajenje robov: IZKLOPLJENO" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Osvetlitev na osnovi slik: IZKLOPLJENA" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Osvetlitev na osnovi slik: VKLOPLJENA" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Ambientno zastiranje: VKLOPLJENO" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Ambientno zastiranje: IZKLOPLJENO" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Ločljivost senc: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Vse je dovoljeno, zato pobiraj orožja in jih pametno uporabi!" @@ -6278,28 +6636,28 @@ msgstr "S pritiskom na rdečo ali modro ikono zamenjaj ekipi" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Avtor/ica proge: %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Podpira največ %d igralcev" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Št. računalniških igralcev rdeče ekipe" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Ne moreš tekmovati na tem turnirju, ker vsebuje proge, ki jih še nisi odklenil/a!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Zaklenjeno!" @@ -6321,10 +6679,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Opravi vse izzive, da odkleneš velika vrata!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6333,41 +6693,48 @@ msgid "" msgstr "Za vstop v ta izziv\npotrebuješ več točk!\nNa zemljevidu poišči\nrazpoložljive izzive." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Pospeši s tipko <%s> ter zavijaj s tipkama <%s> in <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Pospešiš tako, da se dotakneš zgornjega dela volana, zavijaš pa tako, da ga premikaš levo in desno." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Pospešiš tako, da pritisneš na pedal za plin, zavijaš pa tako, da nagneš svojo napravo." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Pospešiš tako, da pritisneš na pedal za plin, zavijaš pa tako, da rotiraš svojo napravo." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Pobiraj darilne škatle in sproži orožja z/s <%s>, da škatle razstreliš!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Pobiraj darilne škatle in pritisni ikono za kegljanje, da škatle razstreliš!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6375,34 +6742,41 @@ msgid "" msgstr "Pritisni <%s>, da pogledaš nazaj.\nOrožje sprožiš nazaj tako, da pritisneš <%s>, medtem ko držiš <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Pritisni ikono z ogledalom, da pogledaš nazaj.\nOrožje sprožiš nazaj tako, da najprej držiš ikono z ogledalom in nato podrsaš do ikone za kegljanje!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Nabrani nitro uporabiš s pritiskom na tipko <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Nabrani nitro uporabiš s pritiskom na ikono za nitro" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Pobiraj steklenice z nitrom (uporabili jih bomo po ovinku)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Ups! Ko si v težavah, pritisni <%s>, da se rešiš." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Ups! Ko si v težavah, pritisni ptičjo ikono, da se rešiš." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6410,24 +6784,27 @@ msgid "" msgstr "Pospeši in pritisni tipko <%s>, medtem ko se obračaš, da se zadrsaš.\nKratkotrajno drsanje ti lahko pomaga hitreje obrniti in tako prevoziti ostre ovinke." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Pospeši in pritisni ikono za drsanje, medtem ko se obračaš, da se zadrsaš.\nKratkotrajno drsanje ti lahko pomaga hitreje obrniti in tako prevoziti ostre ovinke." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Če ti uspe drseti več sekund, za nagrado dobiš dodatno pohitritev!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Zdaj si pripravljen/a na dirkanje. Vso srečo!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "3D odprtokodna dirkalna igra" @@ -6437,7 +6814,7 @@ msgstr "3D odprtokodna dirkalna igra" msgid "tux;game;race;" msgstr "tuks;igra;dirka;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6445,7 +6822,7 @@ msgid "" "for all ages." msgstr "Vozila. Nitro. Akcija! SuperTuxKart je 3D odprtokodna arkadna dirkalnica s pestrim naborom voznikov, stez in igralnih načinov. Namen igre je prej zabava kot realizem in prijetna izkušnja za igralce vseh starosti." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6454,7 +6831,7 @@ msgid "" "your opponents." msgstr "Igralci lahko uživajo na različnih progah, od podvodnih globin, odmaknjenih kmetij in džungel pa vse do vesolja! Preizkusi svoje sposobnosti in se spoprimi z drugimi vozili, pri tem pa pazi na banane, kegljaške krogle, odmaševalnike, žvečilni gumi in torte, s katerimi te nasprotniki obmetavajo." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6463,27 +6840,27 @@ msgid "" "your racing skills!" msgstr "Prevoziš lahko eno samo dirko proti drugim vozilom, tekmuješ na turnirju, se poteguješ za najboljši rezultat v dirkah na čas, se boriš proti računalniku ali svojim prijateljem in še več! Da bo izziv večji, se poveži na splet z drugimi igralci po svetu in pokaži svoje dirkaške veščine!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Ta igra ne vsebuje reklam." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "To je nestabilna različica SuperTuxKarta, ki vsebuje najnovejše izboljšave. Namenjena je predvsem testiranju, da bo naslednja stabilna različica čim boljša." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "To različico je mogoče namestiti na to napravo vzporedno s stabilno različico." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Če hočete večjo stabilnost, priporočamo stabilno različico: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "Ekipa SuperTuxKart" diff --git a/data/po/sr.po b/data/po/sr.po index 7c9ab802a74..eb07f6662c6 100644 --- a/data/po/sr.po +++ b/data/po/sr.po @@ -20,7 +20,7 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" "Last-Translator: Саша Петровић , 2012-2014,2016,2018,2020-2024\n" "Language-Team: Serbian (http://app.transifex.com/supertuxkart/supertuxkart/language/sr/)\n" @@ -179,7 +179,7 @@ msgstr "На крају света" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Назад" @@ -201,7 +201,7 @@ msgstr "Одаберите омиљену врсту управљања" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Мерач убрзања" @@ -215,13 +215,13 @@ msgstr "Мерач убрзања" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Чигра" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Точак управљача" @@ -252,35 +252,37 @@ msgstr "Поставке додирног уређаја" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Опште" @@ -348,30 +350,33 @@ msgstr "Поврати подразумевано" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Откажи" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Да" @@ -549,9 +554,9 @@ msgstr "Прикључи се" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -612,7 +617,7 @@ msgstr "Циљ" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Напредак" @@ -647,7 +652,7 @@ msgstr "Отпреми" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Назад на трку" @@ -664,7 +669,7 @@ msgstr "Назад у предворје" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Понови трку" @@ -728,12 +733,12 @@ msgstr "Да би поништили садашњу лозинку, унесит #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Корисничко име" @@ -774,7 +779,7 @@ msgstr "Тежина" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Новајлија" @@ -786,7 +791,7 @@ msgstr "Новајлија" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Осредњак" @@ -798,7 +803,7 @@ msgstr "Осредњак" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Стручњак" @@ -810,7 +815,7 @@ msgstr "Стручњак" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "Супертакс" @@ -818,8 +823,8 @@ msgstr "Супертакс" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Начин игре" @@ -830,8 +835,8 @@ msgstr "Начин игре" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Обична трка" @@ -844,7 +849,7 @@ msgstr "Обична трка" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Временом ограничена трка" @@ -852,7 +857,8 @@ msgstr "Временом ограничена трка" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Бој" @@ -861,24 +867,24 @@ msgstr "Бој" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Ногомет" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Лозинка" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Забележи овог служитеља" @@ -889,7 +895,7 @@ msgstr "Додај играча" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Име" @@ -983,6 +989,50 @@ msgstr "Додели дугмету ЕСЦ" msgid "Assign nothing" msgstr "Немој ништа да доделиш" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Препоручене поставке видеа" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "Препоручене поставке ће вредети за тренутну размеру." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Шта ће у поставкама бити циљ?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Учинак" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Уједначи каквоће учинка и исцртавања" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Каквоћа исцртавања" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Снага спаривања" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Да ли желите да дејства исцртавања створе замућење?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Покрени проверу" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -997,11 +1047,11 @@ msgstr "Подешавање трке" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Настави" @@ -1042,10 +1092,15 @@ msgstr "Борилишта" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Уграђено" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Уреди омиљена борилишта" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1055,20 +1110,20 @@ msgstr "Уграђено" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Уобичајено" @@ -1079,12 +1134,12 @@ msgstr "Уобичајено" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Додаци" @@ -1098,27 +1153,28 @@ msgstr "Додаци" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Све" @@ -1157,9 +1213,9 @@ msgstr "Помери наниже" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Додај" @@ -1196,7 +1252,7 @@ msgstr "Одабир поновљеног снимка са духом" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Лов на јаје" @@ -1243,10 +1299,10 @@ msgstr "Уназад" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Најмање време (мин.)" @@ -1278,9 +1334,9 @@ msgstr "Умножи" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1291,80 +1347,80 @@ msgstr "Преименуј" msgid "Save Grand Prix" msgstr "Сачувај трку за велику награду" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Помоћ за Супертаксова колица" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Начин игре" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Појачања" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Банане" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1372,56 +1428,57 @@ msgstr "Банане" msgid "Story Mode" msgstr "Прича" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Класе колица" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Игра више играча" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Покрени упознавање" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Скупи модре кутије дарова, даће Вам појачање." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Избегавај банане!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1429,14 +1486,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Скупљање нитра омогућава убрзање кад год затреба притиском на одговарајуће дугме. Можете видети тренутни ниво нитра на мерачу доле-десно на приказу трке." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Уколико видите дугме са катанцем попут овог, треба да завршите изазов да бисте га откључали." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1445,34 +1502,34 @@ msgid "" "carefully before!" msgstr "Можете клизнути дугметом. Узастопна кратка клизања помажу оштра скретања; осредња клизања убрзавају, а дуга клизања још више. Не можете прекинути скретање при клизању, зато усмерите своја колица пажљиво пре тога!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Можете појачати погон притиском на дугме убрзања након „Позор!“, пре почетка трке." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Тренутне пречице дугмади могу бити прегледане/промењене у изборнику Могућности" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "Супертаксколица имају неколико начина играња:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Уобичајена трка: Све гурке су дозвољене, зато скупите појачања и употребите их паметно!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Временска трка: Не садржи појачања, тако да је битна само возачка вештина!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1480,7 +1537,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Прати вођу : возите за друго место, јер ће последња колица бити избачена из трке сваки пут кад време буде одбројано. Пазите : одлазак испред вође ће вас такође избацити!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1490,30 +1547,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Постоје 3 врсте борбе: У борби 3 ударца морате нападати остале оружјем док не изгубе све животе. У игри слободно-за-све играч који највише удара остале ће победити у датом временском року. У игри узимања заставе ваша дружба мора да донесе заставу противника у своје упориште, док истовремено ваша застава није одузета." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Ногомет: Употребите гурање лопте колицима за погодак." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Лов на јаје: Истражујте стазе у потрази за скривеним јајима." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Приказ снимка са духом. Тркајте се против снимка трке духа, временски или у лову на јаје, и снимите свој снимак!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Трка кругова; завршите што више кругова можете у датом времену." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1522,93 +1579,93 @@ msgid "" "wins the cup." msgstr "* Многи од ових начина игре се могу играти у великој награди: уместо једне игре, играте више заредом. Што боље завршите, то више бодова добијете. На крају, играч са највише бодова осваја пехар." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Да вам помогну до победе, постоје нека појачања која можете покупити:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Жвакаћа гума - браните се штитом, или је користите да гледајући уназад оставите лепљиву љубичасту смесу иза себе." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Ћушка - даће јако убрзање. Али пазите да не изгубите управљивост свог возила!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Колач - баците према најближем противнику, најбоље изблиза и на дугим правцима. Утиче и на друга колица близу пуцња." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Клип — баците га право напред да повучете противника уназад, или га баците док гледате позади да бисте некоме заклонили видик." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Кугла - иде правилно пре него што погоди нешто, а може да одскаче од зидова. Ако гледате уназад, биће бачена уназад." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Падобран — успорава све колица у бољем положају." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Мењач - свежњи дарова се претварају у банане, боце нитра у жвакаће гуме, и обрнуто, за врло кратко време." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Кошаркашка лопта одскаче за вођом, и може спљоштити и успорити колица успут." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Млатило - смождиће блиска возила, успоравајући их. Може бити коришћено за уклањање падобрана и бомби." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Удар у банану може довести до добијања следећих терета на колица:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Сидро - нагло успорава колица." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Падобран - успорава колица, наглије него сидро. Што брже идете, јаче Вас успорава." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Бомба - пукне после извесног времена, дижући колица у ваздух. Ударите друга колица ради преноса бомбе на њих." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Зли Нолок је ухватио Гнуа. Ево неколико савета помоћи:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1617,7 +1674,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Ова сличица мале карте приказује доступне изазове које нисте довршили. У горњем десном приказу, показује такође колико бодова тренутно имате. Завршите колико год изазова имате, и Нолок ће прихватити трку против Вас. Победите и ослободите Гнуа!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1625,20 +1682,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Када завршите изазов, добијете пехар. Сваки пехар вреди неколико бодова. Што је већа тежина, то је бољи пехар и то вреди више бодова." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Када добијете број бодова назначен испод сличице, добићете дар изненађења. Има их неколико за скупљање." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Немају сва колица исте возне особине. Она су разрврстана по неколико врсти разлика:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1646,7 +1703,7 @@ msgid "" " resistant to explosions." msgstr "Тежина - постоје три врсте колица, у зависности од тежине: лака, средња и тешка. Тежим колицима мање сметају падобрани и отпорнија су на пуцање бомби." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1654,7 +1711,7 @@ msgid "" " especially at low speeds." msgstr "Убрзање - нарочито је корисни при поласку, након судара, или на стазама са много оштрих кривина. Што су колица лакша, то лакше убрзавају, нарочито из малих брзина." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1662,14 +1719,14 @@ msgid "" " top speed." msgstr "Највећа брзина - што је већа, то колица могу ићи брже. Нарочито је корисно на стазама са дугим правинама и благим кривинама. Тежа колица имају више највеће брзине." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Учинак нитра - што је виша, то већу количину убрзања можете добити нитром. Лакша колица имају већи учинак нитра." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1677,12 +1734,12 @@ msgid "" "easier it is." msgstr "Ако блиско пратите друга колица неколико секунди, добићете додатни брзински доток из добијеног ваздушног тунела за претицање. Што су лакша колица, то је лакше за учинити." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "СуперТаксКарт се може играти са више играча на мрежи...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1692,7 +1749,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Прво, кликните на сличицу „на мрежи“ у главном изборнику. Изаберите или местно умрежавање, или земаљску мрежу (захтева да интернет буде дозвољен у могућностима). Затим, можете или направити сопственог служитеља са произвољним поставкама, или тражити на списку доступне служитеље да се њима придружите. Неки од њих су препоручени служитељи са додатним вредновањем трка." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1702,12 +1759,12 @@ msgid "" "players and the server." msgstr "Када се повежете са служитељем, трка ће почети када домаћин служитеља (означен круном) тако одлучи. Званични служитељи могу сами почети трку када има довољно такмичара. У том случају можете изабрати колица и гласати за наредну стазу за тркање. Додатне стазе су дозвољене само ако постоје код сваког присутног играча и на служитељу." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... или на самом уређају:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1717,7 +1774,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Прво, треба имати неколико улазних уређаја. Искористите преглед поставки уређаја да их подесите. Више гејмпедова или џојстикова су најпожељнији: на тастатурама ће сваки играч ће морати да има другачије пречице дугмади, а већина тастатура нису погодне за игру више играча јер не подржавају истовремено притискање више дугмади." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1737,7 +1794,7 @@ msgstr "Избор врхунских достигнућа" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Пробни круг" @@ -1745,9 +1802,9 @@ msgstr "Пробни круг" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Велика награда" @@ -1758,6 +1815,20 @@ msgstr "Велика награда" msgid "Choose a Kart" msgstr "Изаберите колица" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Врста колица" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Уреди омиљена колица" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1771,11 +1842,11 @@ msgstr "Местна игра више играча" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "На мрежи" @@ -1792,7 +1863,7 @@ msgstr "Упознавање" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Врхунска достигнућа" @@ -1800,7 +1871,7 @@ msgstr "Врхунска достигнућа" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Достигнућа" @@ -1854,30 +1925,30 @@ msgstr "Пронађи служитеља" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Направи служитеља" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Предворје" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Подешавање" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Почни трку" @@ -1903,9 +1974,9 @@ msgstr "Унесите адресу служитеља" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Пресек Ваших личних података" @@ -1923,7 +1994,7 @@ msgstr "Бодовања играча" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Пријатељи" @@ -1948,7 +2019,7 @@ msgstr "Брза игра" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Поставке налога" @@ -1998,8 +2069,8 @@ msgid "Online Username" msgstr "Име играча за мрежну игру" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Поништи лозинку" @@ -2012,7 +2083,7 @@ msgid "" msgstr "Можете играти без стварања налога на мрежи одабиром налога ван мреже. Али, тада се не можете повезати са пријатељима, гласати за додатке итд. Молимо вас да прочитајте нашу објаву о заштити личности на http://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Избор служитеља" @@ -2030,339 +2101,409 @@ msgstr "Користи ИПв6 за повезивање" msgid "User search" msgstr "Претрага корисника" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Могућности Супертаксових колица" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Приказ" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Исцртавање" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Звук" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Корисничко сучеље" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Играчи" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Управљање" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Језик" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Музика" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Укључено" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Гласноћа" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Звучна дејства" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Избриши подешавање" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Онемогући подешавање" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Назад на списак уређаја" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Преименуј поставке" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Омогући одзив силе (ако је омогућено)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Размера" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Пун приказ" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Запамти положај прозора" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Примени нову размеру" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Размештај подељеног приказа игре са више играча" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Могућности интернета" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Увек приказуј екран за пријаву" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Повежи се на интернет" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Омогући ћаскање на мрежи" +msgid "Enable chatting in online lobbies" +msgstr "Омогући ћаскање у предворјима на мрежи" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Омогући ћаскање у играма на мрежи" +msgid "Enable chatting in online matches" +msgstr "Омогући ћаскање у такмичењима на мрежи" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Разне могућности" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Омогућите сметње по сваком играчу посебно" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Уклони сва средства игрице" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Притисните унеси или кликните двапут на уређај да га подесите" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Додај уређај" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Одабир поставки ће се извршити по томе које дугме за одабир буде притиснутно за придруживање игри." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Кошуљица" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Мала карта" +msgid "Skin variant" +msgstr "Врста кошуљице" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Размештај подељеног приказа игре са више играча" +msgid "Minimap" +msgstr "Мала карта" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Величина словолика" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Камера" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Произвољно..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Прикажи број сличица по секунди" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Приказуј појачања осталих колица" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Омогући ограничено време у причи" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Омогући ограничено време у трци брзине" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Рашчлањивање размере" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Ступањ исцртавајућих дејстава" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Разина замућења" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Највећи број сличица по секунди" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Произвољне поставке..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Размера" +msgid "Performance tests" +msgstr "Провера учинка" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Пун приказ" +msgid "Performance test of the current settings" +msgstr "Провера учинка тренутних поставки" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Запамти положај прозора" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Запамти лозинку" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Примени нову размеру" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Обриши" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Боја колица" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2389,15 +2530,15 @@ msgstr "Плава дружина" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Број кругова" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Број роботских колица" @@ -2412,33 +2553,17 @@ msgstr "Број роботских колица плавог тима" msgid "Random Grand Prix" msgstr "Насумична трка за велику награду" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Уреди омиљене стазе" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Пријава" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Запамти лозинку" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Обриши" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Боја колица" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Кошуљица корисничког сучеља се може променити у могућностима корисничког сучеља." @@ -2557,238 +2682,306 @@ msgid "" msgstr "Избегавајте да ометате пролаз саиграчу који носи лопту, него покушавајте да ударите противнике који покушавају да га спрече да згоди лоптом циљ." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Ађуми" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Аманда" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Годета" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Јемазга" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Гаврош" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Гну" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Шестли" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Кики" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Конки" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Нолок" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Голупко" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Пуфко" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Биберче" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Зара" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Сузана" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Такс" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Вилбер" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Стју" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Препотопски бездан" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Инознак" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Древни лавиринт Колосеум" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Град свећа" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Острво битака" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Црна гора" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Пећина Икс" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Замак какаоа" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Кукурузни прелаз" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Утврђење Магма" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Острво великог раја" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Хацијенда" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "У рупу" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Ледено ногометно игралиште" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Шта није у реду, мали хипчићи? Нема вашег силног вође гнуа?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "О, да, види, он је сада у мом дворцу, и биће служен за вечеру..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Али, ја сам поштено створење, нагодићу се са тобом." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Ако ме успеш победити у трци, ослободићу стару ништарију." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " Али, ви бедне мале ништарије никад нећете моћи да победите мене - Краља колица!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Борилиште Дуна" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Ногометно игралиште Дуне" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Около светионика" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Стари рудник" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Мали голф" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Оаза" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Оливеров час математике" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Поље тикава" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Вила Врановог моста" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Живи песак" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Несино Језерце" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Северно одмориште" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Снежни вршак" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Ногометно игралиште" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Игралиште" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "Предузеће СТК-а" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Замак" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Острво вулкана" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "ХР591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Зенова башта" @@ -2797,11 +2990,11 @@ msgstr "Зенова башта" msgid "Completed achievement \"%s\"." msgstr "Испуњена достигнућа „%s“." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Нисам успео да се повежем са служитељем додатака Супер Таксових колица." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Десила се грешка приликом преузимања новости: „%s“." @@ -2867,7 +3060,7 @@ msgid "New kart '%s' now available" msgstr "Нова колица „%s“ су сада доступна" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2899,32 +3092,32 @@ msgid "" "created." msgstr "Ваша датотека подешавања је била превише стара, те је обрисана и нова ће бити направљена." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Снимање видеа је почело." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Видео је сачуван у „%s“." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Напредак кодирања:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "СПС:%d/%d/%d - %d , Одзив: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Савет: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Учитавам" @@ -2946,19 +3139,18 @@ msgstr "Учинак нитра" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (ометен)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s је спреман/на" @@ -3432,21 +3624,21 @@ msgid "Axis %d" msgstr "Осовина %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Гејмпедско дугме %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Дугме миша %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Оса миша %d %s" @@ -3619,26 +3811,30 @@ msgstr "Можете имати највише 3 живота!" msgid "+1 life." msgstr "+1 живот." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Преспор си!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Завршили сте трку!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Победили сте у трци!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Завршили сте трку на месту %d!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s је напустио игру." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3647,16 +3843,16 @@ msgid "" "Internet\")." msgstr "Супертаксова колица се могу повезивати са служитељем ради преузимања додатака и обавештења о надоградњама. Молим, прочитајте смернице о поштовању личности можете прочитати на http://privacy.supertuxkart.net. Да ли желите да ово омогућите? (Ради касније измене ових поставки, идите на могућности, изаберите лист „Опште“, и уредите „Повежите се са Интернетом“)." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Размера екрана је премала за покретање СТК-а." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Издање управљачких програма видео картице је застарело. Покушајте да уградите новије управљачке програме." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3664,38 +3860,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Ваш графички управљачки програм изгледа да је веома стар. Молимо вас да проверите дали је могуће надградити га. СуперТуксКарт препоручује управљачки програм који подржава %s или новији. Игрица би вероватно и даље радила, али са смањеним могућностима исцртавања." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Истекла је веза са служитељем." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s има црвену заставу!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Црвена застава је враћена!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s има модру заставу!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Модра застава је враћена!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s је узео модру заставу!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s је узео црвену заставу!" @@ -3705,7 +3901,7 @@ msgstr "%s је узео црвену заставу!" msgid "Eggs: %d / %d" msgstr "Јаја: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Вођа" @@ -3713,22 +3909,22 @@ msgstr "Вођа" msgid "Final lap!" msgstr "Последњи круг!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Круг %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s од %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Нови најбржи круг" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "ПОГРЕШАН ПУТ!" @@ -3742,7 +3938,7 @@ msgstr "%s постигну погодак!" msgid "Oops, %s made an own goal!" msgstr "Јој, %s погоди своју мрежу!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" @@ -3750,187 +3946,187 @@ msgstr[0] "%i колица са новим гумама су створена!" msgstr[1] "%i колица са новим гумама су створена!" msgstr[2] "%i колица са новим гумама су створена!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Испали сте!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "„%s“ је испао." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Служитељ је искључен." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Избачени сте са служитеља." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Избачени сте: одзив је превише висок." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Лоша веза је препозната." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Робот" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s је откачен." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Притисните име играча на списку управљања и података о поретку." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Тежина: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Највише играча: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Начин игре: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Временско ограничење" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Ограничење погодака" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Врста ногометне игре: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Напредак трке велике награде: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Сви играчи су се прикључили модром или црвеној дружини." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Нисте власник служитеља." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Веза је одбијена: служитељ је заузет." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Веза је одбијена: Прогнани сте са служитеља." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Веза је одбијена: лозинка служитеља није тачна." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Веза је одбијена: подаци игре нису одговарајући." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Веза је одбијена: служитељ је пун." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Веза је одбијена: повезивање невредећег играча." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Нисам успео да покренем игру на мрежи." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Игра је завршена, не можете се прикључити уживо или гледати и даље." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Нема слободног места у борилишту - прикључење је онемогућено." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Само 1 играч је остао, враћање на предворје." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Домаћин служитеља је напустио игрицу." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Посматраћете следећу игру." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s се је прикључио црвеном тиму." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s се је прикључио плавом тиму." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s се је прикључио игри." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3938,15 +4134,15 @@ msgid "" msgstr "Стисните <%s> или <%s> да промените циљаног играча, <%s> или <%s> за положај камере." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "Успешно је пријављен %s." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3977,38 +4173,38 @@ msgstr "Трка с’ временом (велика награда)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Слободно-за-све" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Освоји заставу" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s је сада повезан на мрежу." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s и %s су сада повезани са мрежом." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s и %s су сада повезани са мрежом." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4017,12 +4213,12 @@ msgstr[1] "%d пријатеља су на мрежи." msgstr[2] "%d пријатеља је на мрежи." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s је сада на служитељу „%s“." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" @@ -4030,7 +4226,7 @@ msgstr[0] "Имате %d захтев за пријатељством!" msgstr[1] "Имате %d захтева за пријатељством!" msgstr[2] "Имате %d захтева за пријатељством!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Имате нови захтев за пријатељство!" @@ -4059,12 +4255,12 @@ msgid "" msgstr "Датотека са најбољим бодовима је превише стара,\nсви записи најбољих бодовања су избрисани." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Прати вођу" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Борба на 3 удара" @@ -4077,92 +4273,88 @@ msgstr "Непотпуна датотека поновљеног снимка с msgid "Replay saved in \"%s\"." msgstr "Снимак за поновно гледање је сачуван у „%s“." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 седмица" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 седмице" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 месец" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 месеца" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 месеци" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 месеци" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 година" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 године" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Назив додатка" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Време освежења" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Није уграђен" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s од %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Молим сачекајте док се не надограде додаци" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Извините, дошло је до греше приликом ступања у везу са страницом додатака на мрежи. Проверите да ли сте повезани на Интернет и да ли ду Супертаксова колица спречена ватреним зидом" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Омиљени" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Закључано : одрадите садашње изазове да добијете приступ другима!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Насумично борилиште" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d борилиште је доступно за самосталну игру." -msgstr[1] "%d борилишта су доступна за самосталну игру." -msgstr[2] "%d борилишта је доступно за самосталну игру." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nCYBER FIGHTER, 2019-2020\nSiddhartha Gautama, 2016,2018\nSiddhartha Gautama, 2016,2018-2019\nSUABNINISAN alalalala, 2020\nМирослав Николић, 2011\nСаша Петровић, 2012-2014,2016,2018,2020-2022\nСаша Петровић, 2015-2016\nСаша Петровић, 2016\nСаша Петровић, 2016-2017\nСаша Петровић, 2018\nСаша Петровић, 2018-2019\nСаша Петровић, 2012-2014,2016,2018,2020-2021\nSTK-team\ndboki89\nМирослав Николић\nСаша Петровић" @@ -4450,7 +4642,7 @@ msgstr "Прикупљене банане" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Проклизавање" @@ -4553,7 +4745,7 @@ msgstr "Поход на јаје је завршен" msgid " (official tracks matching the goal)" msgstr " (званичне стазе одговарајуће циљу)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4561,91 +4753,95 @@ msgid "" msgstr "Да бисте додали нови гејмпед/џојстик уређај, једноставно покрените Супертаксова колица са прикљученим уређајем и он ће се појавити на списку.\n\nДа бисте додали поставке тастатуре, можете користити дугме испод, МЕЂУТИМ, обратите пажњу да већина тастатура подржава само ограничен број истовремено притиснутих дугмади, те су стога неподесне за играње са више играча. (Можете, међутим, да прикључите више тастатура на рачунар. Упамтите да и у овом случају сваки играч треба да има различите дугмиће за игру.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Додај даљински управљач конзоле Ви" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Додај подешавање тастатуре" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Освежи" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Издање: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "нова својства" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Величина: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Морате бити пријављени ради оцене овог додатка." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Жао ми је, преузимање додатака није успело" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Потешкоћа приликом уградње додатка „%s“." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Покушајте поново" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Потешкоћа приликом уклањања додатка „%s“." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Преузимање у позадини је окончано." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Преузимање у позадини" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Преузимање у позадини је већ започело." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Тренутна лозинка није исправна." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Лозинка мора да има између 8 и 30 знакова!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Лозинке се не поклапају!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Подаци о исправности" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Лозинка је успешно промењена." @@ -4667,67 +4863,97 @@ msgstr "Размера мања од 1024x768 или 1280x720 нису подр #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Јурњава летелице" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Прилагођено" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Онемогућен" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Само битни" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Врло ниска" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Ниска" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Средњи" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Висока" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Врло висок" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Крајње" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4735,7 +4961,7 @@ msgid "" msgstr "СуперТаксКолица ће преузети пуну збирку (укључујући плетиво пуног квалитета и музику) за бољи доживљај играња, а то ће користити податке мобилне мреже ако немате бежичну мрежу." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4752,101 +4978,102 @@ msgstr "Унесите адресу служитеља са могућношћу msgid "Invalid server address: %s." msgstr "Неисправна адреса служитеља: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Уназад" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Тежина" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Кругови" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Време" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Колица" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Корисник" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Издање" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Не" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Стаза" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Врхунских %d достигнућа" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Број колица: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Временски циљ: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Кругова: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Унатраг: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Празно)" @@ -4934,33 +5161,41 @@ msgid "Press any key..." msgstr "Притисните било које дугме..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Ћаскање је онемогућено, омогућите из у изборнику могућности." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Назад у проверу учинка" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Изађи из провере учинка" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Назад на битку" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Подеси нову игру" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Поново покрени битку" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Изађи из битке" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Подеси нову трку" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Напусти трку" @@ -4976,11 +5211,11 @@ msgstr "%s још увек нема бодове." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s је број %d у поретку са бројем бодова %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Корисничко име или е-пошта нису исправни." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5002,7 +5237,7 @@ msgstr "Поновљени снимак трке са духом" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Кругова: %i" @@ -5015,21 +5250,21 @@ msgstr "Врста: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Захтевано место: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Захтевано време : %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Захтевани бодови нитра: %i" @@ -5042,54 +5277,54 @@ msgstr "Број нељудских колица: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Начин битке" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Врста ногометне игре" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Положај служитеља: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Тренутна стаза: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Положај" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Играч" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Достигнућа" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Време игре" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Уклони из забележака" @@ -5102,74 +5337,74 @@ msgid "No player available for connecting to server." msgstr "Нема доступних играча за повезивање са служитељем." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Корисничко име: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Откажи захтев" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Данас" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Послат је захтев за пријатељство!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Одобрен је захтев за пријатељство!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Одбијен је захтев за пријатељство!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Уклоњен је пријатељ!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Отказана је потврда захтева за пријатељство!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Обрађујем" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Добављање података о последњем гласању" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Своје оцене можете да прилагодите кликом на звездице испод." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Још увек нисте гласали за овај додатак. Изаберите жељену оцену кликом на звездице испод" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Гласање је успешно! Сада можете да затворите прозор." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Гласање" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Насумична стаза" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5198,7 +5433,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Десила се грешка приликом покушаја чувања велике награде." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Изаберите стазу" @@ -5242,12 +5477,12 @@ msgstr "Откључали сте стазу %0" msgid "You unlocked grand prix %0" msgstr "Откључали сте велику награду %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Стаза" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5268,19 +5503,19 @@ msgstr "Молим, унесите име трке за велику награ msgid "Please select a Grand Prix" msgstr "Молим, изаберите трку за велику награду" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Кориснички одређено" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Нема имена." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Трка за велику награду са таквим именом већ постоји." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Име је предугачко." @@ -5289,19 +5524,19 @@ msgstr "Име је предугачко." msgid "Better luck next time!" msgstr "Више среће следећи пут!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Испунили сте изазов!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Освојили сте велику награду!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Завршили сте велику трку!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Број колица" @@ -5314,110 +5549,125 @@ msgstr "Да ли сте сигурни да желите да уклоните msgid "Are you sure you want to remove all of your high scores?" msgstr "Да ли сте сигурни да желите да уклоните сва своја достигнућа?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Омиљено" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Светло" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Тешко" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Повежите тастатуру или џојстик ради игре у подељеном приказу за више играча" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Насумични колица" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Закључано" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Сви:\nПритисните „Одабери“ сада ради прикључења игри" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Да ли желите да играте подучавање игрице?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Не можете да играте на мрежи без приступа Интернету. Ако желите да играте на мрежи, идите у изборник и означите „Повежи се са Интернетом“." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Не можете преузети додатке без приступа интернету. Ако желите да преузмете додатке, идите у могућности, и означите \"Повежи се на Интернет\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Не можете преузети додатке без приступа интернету. Ако желите да преузмете додатке, идите у могућности, и означите \"Повежи се на Интернет\".\n\nИпак, можете обрисати већ преузете додатке." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Јединица додатака је тренутно искључена на заклону могућности" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Молим сачекајте док се не учитају додаци" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Да ли сигурно желите да напустите СТК?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Створи месног служитеља" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "%s-ов служитељ" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Број стаза велике награде" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Име мора да има између 4 и 30 знакова!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Неодговарајући знаци у лозинки!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Спремни" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Прикључивање уживо" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Посматрај" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Угради додатак" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5425,7 +5675,7 @@ msgstr "Молим, сачекајте да се тренутна игра (%s) #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Молим, сачекајте да се тренутна игра заврши, предвиђено преостало време: %s." @@ -5433,24 +5683,24 @@ msgstr "Молим, сачекајте да се тренутна игра за #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Молим, сачекајте да се тренутна игра (%s) заврши, предвиђен напредак: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Молим, сачекајте да се тренутна игра заврши, предвиђен напредак: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Молим, сачекајте да се тренутна игра заврши." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5460,7 +5710,7 @@ msgstr[2] "Игра ће почети ако има више од %d играч #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5470,96 +5720,108 @@ msgstr[0] "Почиње након %d секунде, кад сви притис msgstr[1] "Почиње након %d секунде, кад сви притисну дугмад „Спреман“." msgstr[2] "Почиње након %d секунди, кад сви притисну дугмад „Спреман“." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Повезивање са служитељем %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Тражим служитеља брзог играња" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Преостало време: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Поготци" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Добављање података о достигнућима" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "%s-ов пресек личних података" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Од" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Стање" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Добављање података о пријатељима" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Нови захтев" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "На чекању" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Ван мреже" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Унесите нову е-пошту испод" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Нова е-пошта мора бити дугачка између 5 и 254 знака!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Нова е-пошта није исправна!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "Е-пошта је измењена!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Нисам успео да променим е-пошту: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Новости са блога СТК" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Дан" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Тренутно нема доступних вести." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Морате бити пријављени на земаљску мрежу да би играли. Кликните своје корисничко име изнад." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Претражујем" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Напусти игру" @@ -5637,34 +5899,34 @@ msgid "Distance (km)" msgstr "Растојање (км)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Непознато" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Нисам препознао ИПв4, можда нећете моћи да се придружите служитељима." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Нисам препознао ИПв6, можда нећете моћи да се придружите служитељима." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Нема доступних служитеља." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Добављање података о служитељима" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Забелешке служитеља" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5672,149 +5934,149 @@ msgstr "Ако већина играча изабере исту стазу и #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Положај насумичних ставки" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Циљни број погодака" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Вози уназад" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Закључано : одрадите садашње изазове да добијете приступ осталим изазовима!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Радња" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Пречице дугмади" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Онемогући уређај" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Омогући уређај" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Омогући поставке" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Дугмад игре" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Дугмад изборника" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Скрени лево" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Скрени десно" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Убрзај" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Кочи / Уназад" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Пуцај" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Нитро" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Поглед уназад" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Спашавање" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Застани са игром" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Горе" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Доле" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Лево" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Десно" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Изабери" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Откажи/Назад" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Плава ставка означава сукоб са другим подешавањем" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Црвена ставка значи да има сукоба са тренутним поставкама програма" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5822,17 +6084,27 @@ msgid "" msgstr "Упозорење, „померај“ (shift) није препоручиво дугме. Када је „померај“ притиснут, сва дугмад који садрже знак који је другачији када се пише великим словима, престаће да раде." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Да ли сте сигурни да желите трајно избрисати ово подешавање?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Унесите ново име поставки, оставите празно за враћање на подразумеване вредности." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Усправно" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Водорано" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5840,89 +6112,74 @@ msgstr "У игри са више играча, играчи могу одабр #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Угради све садржаје игре" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Да ли сигурно желите да уклоните све садржаје игрице?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Тастатура %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Додирни уређај" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Тапните на уређај ради његовог подешавања" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Језик склопа" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "На дну лево" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "На десној страни" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Скривено" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Усредиштен" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Усправно" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Водорано" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Малецан" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Мали" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Средњи" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Велики" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Огроман" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5932,128 +6189,133 @@ msgid "" msgstr "Брза трка може бити омогућена само ако игра није затворена од покретања у игрању приче.\n\nЗатварање игре пре окончавања игре приче поништава бројач времена.\n\nЗа коришћење брзинске трке, молим, користите нови пресек." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Усправно усклађивање" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "В-усклађивање тера графичку карту да понуди нову слику\nсамо када је заслон спреман да га прикаже." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "В-усклађивање неће радити ако га управљачки програми не подржавају." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Дејство честица: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Оживљени ликови: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Живо осветљење : %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Расијавање: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Умекшавање: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" -msgstr "Околно окружење: %s" +msgstr "Приближавање окружења: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Сене: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Сене: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Зрачење: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Сјај (обриса): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Лева палица (божији зраци): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Каквоћа приказа слике: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Појединости исцртавања: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Замућење покрета: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Дубина поља: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Приступ мрежној вези је онемогућен. Да ли је желите омогућити?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Треба да унесете лозинку." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Одјављујем вас са „%s“" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Пријављујем вас на „%s“" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Не можете да обришете јединог играча." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Да ли заиста желите избрисати играча „%s“?" @@ -6081,7 +6343,7 @@ msgstr "Погодак!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Чекам остале" @@ -6116,7 +6378,7 @@ msgstr "Прати вођу!" msgid "Top %i" msgstr "Најбољих %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Изазов није испуњен" @@ -6140,102 +6402,199 @@ msgstr "Притисните сличицу подијума ради покре msgid "Press fire to start the challenge" msgstr "Притисните пали за покретање изазова" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Назад у поставке видеа" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Сачувај налазе провере" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Назад у главни изборник" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Напусти служитеља" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Прекини Велику награду" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Поново покрени" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Назад на избор изазова" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Трка против новог духа поновног снимка" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Назад на изборник" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Да ли заиста желите да напустите велику награду?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Извештај о учинку је сачуван у „%s“." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Победа црвених" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Плави су победили" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Нерешено је" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Избачен након %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Избачен" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Самопогодак)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Стаза %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Напредак у трци за велику награду:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Најбоља достигнућа" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Време најбржег круга: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "по %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Испунили сте изазов!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Нисте успели да испуните изазов!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Достигнути су захтеви за Супертаксом" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Налази провере учинка" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Трајање провере: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Број сличица: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "Уједначене сличице по секунди: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "Углавном уједначене сличице по секунди: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "Уобичајене сличице по секунди: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Водоравна размера: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Усправна размера: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Прилагодљиво осветљење: УКЉУЧЕНО" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Прилагодљиво осветљење: ИСКЉУЧЕНО" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Рашчлани размеру: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Умекшавање: УКЉУЧЕНО" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Умекшавање: ИСКЉУЧЕНО" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Осветљење засновано на сликама: ИСКЉУЧЕНО" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Осветљење засновано на сликама: УКЉУЧЕНО" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Приближавање окружења: УКЉУЧЕНО" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Приближавање окружења: ИСКЉУЧЕНО" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Размера сене: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Сви ударци су дозвољени, зато хватајте оружја и паметно их употребите!" @@ -6276,28 +6635,28 @@ msgstr "Притисните црвену или плаву сличицу но #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Стазу је направио — %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Највећи подржани број играча: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Број роботских колица" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Не можете да играте ову велику награду јер садржи стазе које нису откључане!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Закључано!" @@ -6319,10 +6678,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Да би откључали велика врата, испуните све изазове!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6331,41 +6692,48 @@ msgid "" msgstr "Потребно вам је више бодова\nда освојите овај изазов!\nПроверите доступне промене\nна малој карти." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Убрзајте помоћу <%s>, и управљајте помоћу <%s> и <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Убрзавајте додиривањем врха управљача, управљајте померањем лево или десно." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Убрзајте померањем управљача навише, и управљајте окретањем уређаја." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Убрзајте померањем убрзивача навише, и управљајте окретањем уређаја." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Сакупите кутије дарова, и испалите оружје уз помоћ <%s> да би разнели противнике кутијама!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Сакупите кутије дарова, и испалите их притискивањем сличице куглања ради разношења ових кутија!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6373,34 +6741,41 @@ msgid "" msgstr "Притисните <%s> за поглед уназад.\nГађајте из оружја помоћу <%s> притискајући <%s> за гађање уназад!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Притисните сличицу огледала ради погледа уназад.\nИспалите из оружја уназад држећи сличицу огледала и клизањем преко сличице куглања!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Нитро који сте покупили употребите притиском на <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Употребите покупљени нитро притиском на сличицу нитра" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Сакупљајте боце са нитром (користићемо их после кривине)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Јој! Када сте у неприлици, притисните <%s> за спашавање." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Јој! Када сте у неприлици, притисните сличицу птичице да Вас спасе." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6408,24 +6783,27 @@ msgid "" msgstr "Убрзајте и притисните дугме <%s> приликом скретања ради клизања.\nКратко клизање Вам може помоћи да скренете брже ради савладавања оштрих кривина." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Убрзавајте и притисните сличицу клизања приликом скретања ради клизања.\nКратко клизање Вам може помоћи да скренете брже у оштрим кривинама." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Знајте да ако успете да клизате неколико секунди, примићете додатно убрзање као награду!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Спремни сте за трку. Срећно!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Игра тркања колицима слободног кода" @@ -6435,7 +6813,7 @@ msgstr "Игра тркања колицима слободног кода" msgid "tux;game;race;" msgstr "такс;игра;трка;тукс;игрица;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6443,7 +6821,7 @@ msgid "" "for all ages." msgstr "Колица. Нитро. Акање! Супертаксколица је аркадна просторна тркачка игра слободног кода са мноштвом ликова, стаза и начина играња. Наш циљ је да створимо игру која ће бити више забавна него ли природног изгледа, и која може пружити пријатно искуство свим нараштајима." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6452,7 +6830,7 @@ msgid "" "your opponents." msgstr "Имамо неколико стаза са разним темама за играчко уживање, од вожње под водом, сеоских предела, прашума, чак и свемира! Покушајте да избегавате остала колица јер Вас могу претећи, али не једите банане! Пазите се кугли, гума за отчепљивање цеви, жвакаћих гума, и колача које бацају Ваши противници." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6461,27 +6839,27 @@ msgid "" "your racing skills!" msgstr "Можете се тркати против осталих колица, такмичити у једној од неколико великих награда, покушати да забележите боље време од сопственог, играти битку против рачунара или својих пријатеља, и још подоста! За веће изазове, тркајте се против играча широм света и докажите своје возачко умеће!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Ова игра нема додатака." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Ово је нестабилно издање СуперТаксКолица које садржи најновија побољшања. Њено издање је углавном за пробу, да би учинили СТК најбољим што је могуће." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Ово је издање уграђено поред стабилног издања на уређају." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Ако Вам треба више стабилности, користите стабилно издање: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "Дружина СуперТаксКолица" diff --git a/data/po/sv.po b/data/po/sv.po index fcf334d5cda..16b18fae073 100644 --- a/data/po/sv.po +++ b/data/po/sv.po @@ -9,7 +9,7 @@ # Johan R. , 2017 # Johan R. , 2017-2018 # efef6ec5b435a041fce803c7f8af77d2_2341d43, 2020 -# Jonatan Nyberg, 2021-2023 +# Jonatan Nyberg, 2021-2024 # Jonatan Nyberg, 2020-2021 # Kjell Rilbe , 2016 # Kristoffer Grundström , 2016 @@ -25,9 +25,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Jonatan Nyberg, 2021-2023\n" +"Last-Translator: Jonatan Nyberg, 2021-2024\n" "Language-Team: Swedish (http://app.transifex.com/supertuxkart/supertuxkart/language/sv/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -184,7 +184,7 @@ msgstr "Vid världens ände" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Tillbaka" @@ -206,7 +206,7 @@ msgstr "Välj en kontrolltyp som du föredrar" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "Accelerometer" @@ -220,13 +220,13 @@ msgstr "Accelerometer" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Gyroskop" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Ratt" @@ -257,35 +257,37 @@ msgstr "Inställningar för tryckdon" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Allmänt" @@ -353,30 +355,33 @@ msgstr "Återställ standardvärden" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Avbryt" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Ja" @@ -554,9 +559,9 @@ msgstr "Anslut" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -617,7 +622,7 @@ msgstr "Mål" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "Framsteg" @@ -652,7 +657,7 @@ msgstr "Skicka" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Tillbaka till loppet" @@ -669,7 +674,7 @@ msgstr "Tillbaka till lobbyn" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Starta om loppet" @@ -733,12 +738,12 @@ msgstr "Fyll i användarnamnet och e-postadressen som du angav vid registreringe #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Användarnamn" @@ -779,7 +784,7 @@ msgstr "Svårighetsgrad" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Nybörjare" @@ -791,7 +796,7 @@ msgstr "Nybörjare" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Medel" @@ -803,7 +808,7 @@ msgstr "Medel" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Expert" @@ -815,7 +820,7 @@ msgstr "Expert" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -823,8 +828,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "Spelläge" @@ -835,8 +840,8 @@ msgstr "Spelläge" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Normal tävling" @@ -849,7 +854,7 @@ msgstr "Normal tävling" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Tidsförsök" @@ -857,7 +862,8 @@ msgstr "Tidsförsök" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Strid" @@ -866,24 +872,24 @@ msgstr "Strid" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Fotboll" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Lösenord" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Bokmärk denna server" @@ -894,7 +900,7 @@ msgstr "Lägg till spelare" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "Namn" @@ -988,6 +994,50 @@ msgstr "Koppla till Escape-tangenten" msgid "Assign nothing" msgstr "Inte kopplat" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Rekommendera videoinställningar" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "De rekommenderade inställningarna kommer att gälla för den aktuella upplösningen." + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "Vad ska inställningarna prioritera?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "Prestanda" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "Balansera prestanda och grafikkvalitet " + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Grafikkvalitet" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "Spara energi" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "Gillar du att grafikeffekter skapar oskärpa?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Starta testet" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -1002,11 +1052,11 @@ msgstr "Inställningar för lopp" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Fortsätt" @@ -1047,10 +1097,15 @@ msgstr "Arenor" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Installerade" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "Redigera favoritarenor" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1060,20 +1115,20 @@ msgstr "Installerade" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Standard" @@ -1084,12 +1139,12 @@ msgstr "Standard" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Tillägg" @@ -1103,27 +1158,28 @@ msgstr "Tillägg" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Alla" @@ -1162,9 +1218,9 @@ msgstr "Flytta ner" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Lägg till" @@ -1201,7 +1257,7 @@ msgstr "Urval av spökerepris" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Äggjakt" @@ -1248,10 +1304,10 @@ msgstr "Bakåt" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "Maximal tid (min.)" @@ -1283,9 +1339,9 @@ msgstr "Kopiera" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1296,80 +1352,80 @@ msgstr "Byt namn" msgid "Save Grand Prix" msgstr "Spara Grand Prix" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Hjälp för SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Spellägen" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Kraftförstärkningar" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Bananer" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1377,56 +1433,57 @@ msgstr "Bananer" msgid "Story Mode" msgstr "Berättelseläge" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Kartklasser" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Flerspelarläge" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Starta handledningen" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Samla blåa presentlådor, de kommer ge dig kraftförstärkningar." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Undvik bananer!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1434,14 +1491,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Genom att samla in nitro kan du få hastighetsökningar när du vill genom att trycka på lämplig tangent eller knapp. Du kan se din nuvarande nivå av nitro i mätaren längst ner till höger på tävlingsskärmen." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Om du ser en knapp med ett lås som den här måste du slutföra en utmaning för att låsa upp den." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1450,34 +1507,34 @@ msgid "" "carefully before!" msgstr "Du kan sladda genom att trycka på en specialtangent eller knapp. På varandra följande korta sladdningar hjälper till att ta skarpa varv medan medelstora sladdningar ökar din hastighet, långa sladdningar mer. Du kan inte sluta svänga medan du sladdar, så orientera din kart noggrant innan!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Du kan få en startförstärkning genom att trycka på accelerationsknappen vid \"Färdiga!\" Innan loppet startar." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Aktuella tangentbindningar kan ses/ändras i alternativmenyn" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart har flera spellägen:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Vanligt lopp: Alla slag är tillåtna, så samla kraftförstärkningar och använd dem smart!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Tidsförsök: Innehåller inga kraftförstärkningar, så det är bara din körförmåga som spelar roll!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1485,7 +1542,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Följ ledaren: Kör om andraplatsen, eftersom den sista karten kommer att diskvalificeras varje gång räknaren går ned till noll. Se upp: när du går framför ledaren blir du också eliminerad!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1495,30 +1552,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "Det finns tre typer av stridsläge: I 3-träffsstrid måste du slå andra med vapen tills de förlorar alla deras liv. I Fritt-för-alla vinner den spelare som träffar andra mest inom en given träff eller tidsgräns. I Fånga flaggan måste ditt lag ta med det andra lagets flagga till din egen flaggbas, så länge din flagga inte fångas av det andra laget." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Fotboll: Använd din kart för att knuffa bollen i mål." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "Äggjakt: Upptäck banor för att hitta alla gömda ägg." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Spökrepris: Tävla mot spökrepriser i tidsförsök eller äggjaktläge och spela in ditt eget!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Varvförsök: Kör så många varv som möjligt under en viss tid." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1527,93 +1584,93 @@ msgid "" "wins the cup." msgstr "* Många av dessa spellägen kan också spelas på Grand Prix-sätt: istället för att köra en enda tävling spelar du flera på raken. Ju bättre du rankar, desto fler poäng får du. Till slut vinner spelaren med flest poäng mästerskapet." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "För att du ska vinna lättare finns det kraftförstärkningar som du kan samla:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Tuggummi - skydda dig som en sköld eller använda den samtidigt som du tittar tillbaka för att lämna en klibbig rosa pöl bakom dig." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Dragkedja - ger dig en stark hastighetsökning. Men se upp för att inte tappa kontrollen över din kart!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Tårta - kastas till närmaste rival, bäst på korta avstånd och långa raksträckor. Den påverkar också andra karter nära explosionen." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Sugkopp - kasta rakt för att dra en motspelare mot dig, eller kasta medan du tittar bakåt för att förblinda en annan." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Bowlingklot - går rakt tills den träffar, den kan studsa mot väggar. Om du tittar bakåt kastas den bakåt." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Fallskärm - saktar ner alla karter framför dig." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Bytare - presentförpackningar förvandlas till bananer, nitroburkar till bubblegum och vice versa under en kort tid." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Basketboll - studsar efter ledaren, kan mosa och sakta ner karter längs med vägen." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Flugsmälla - kommer mosa karter som kommer nära och saktar ner dem. Kan också vara användbar för att ta bort bomber och fallskärmar." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Köra på en banan kan resultera i att ett av följande fäster på karten:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Ankare - Gör karten långsammare." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Fallskärm - Saktar ner karten mer gradvis än ankaret. Ju snabbare du kör, desto mer saktas du ner." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bomb - Detonerar efter en kort tid för att kasta upp karten i luften. Kör på en annan kart för att överföra bomben till en annan spelare." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Den onde Nolok har tillfångatagit Gnu! Här är några tips för att hjälpa dig:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1622,7 +1679,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Denna ikon på minikartan visar tillgängliga utmaningar som du inte har slutfört. Längst upp till höger på skärmen berättar den också hur många poäng du har för närvarande. Slutför så många utmaningar som möjligt, så accepterar Nolok att tävla mot dig. Vinn för att befria Gnu!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1630,20 +1687,20 @@ msgid "" " the cup and the more points it is worth." msgstr "När du slutför en utmaning får du en pokal. Varje pokal är värd flera poäng. Ju högre svårighet du slutförde utmaningen i, desto bättre pokal och desto fler poäng är den värt." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "När du får antalet poäng som anges under denna ikon, får du en överraskning. Det finns flera att samla in." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Inte alla karter kör på samma sätt! De tillhör klasser med flera skillnader:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1651,7 +1708,7 @@ msgid "" " resistant to explosions." msgstr "Massa - det finns tre klasser av karter, beroende på deras massa: lätt, mellan och tung. Tyngre karter påverkas mindre av fallskärmar och är mer motståndskraftiga mot explosioner." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1659,7 +1716,7 @@ msgid "" " especially at low speeds." msgstr "Acceleration - särskilt användbart vid start, efter en olycka eller i banor med många skarpa kurvor. Ju lättare kart desto snabbare accelererar den, särskilt vid låga hastigheter." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1667,14 +1724,14 @@ msgid "" " top speed." msgstr "Max hastighet - ju högre den är, desto snabbare kan karten gå. Särskilt användbart i banor med raka linjer och mjuka kurvor. Tyngre karter har högre toppfart." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Nitroeffektivitet - Ju högre det är, desto mer hastighet får du från en burk nitro. En lättare kart har högre nitroeffektivitet." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1682,12 +1739,12 @@ msgid "" "easier it is." msgstr "Om du följer noggrant en annan kart i några sekunder får du en slipstream-hastighetsbonus när du passerar den. Ju lättare din kart, desto lättare är den." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart kan spelas i flerspelarläge på nätet...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1697,7 +1754,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "Välj först ikonen \"på nätet\" i huvudmenyn. Välj antingen lokalt nätverk eller globalt nätverk (kräver att internet är aktiverat i alternativen). Sedan kan du antingen skapa din egen server med anpassade alternativ, eller söka bland en lista med befintliga servrar för att gå med. Några av dem rekommenderas servrar med valfritt rankade lopp." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1707,12 +1764,12 @@ msgid "" "players and the server." msgstr "En gång på en server börjar ett lopp när ägaren (symboliserad med kronan) beslutar det. Officiella servrar får starta tävlingar automatiskt bara när det finns tillräckligt med spelare. Sedan kan du välja din kart och rösta på nästa bana att tävla på. En tilläggsbana är endast tillåtet om det finns på alla anslutna spelare och servern." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... eller på samma enhet:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1722,7 +1779,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "Först behöver du flera inmatningsenheter. Använd inmatningskonfigurationsskärmen för att ställa in dem. Flera handkontroller eller joysticks är idealiska: på tangentbord behöver varje spelare en annan uppsättning tangenter, och de flesta tangentbord är inte lämpliga för flerspelarläge eftersom de inte stöder flera samtidiga tangenttryckningar." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1742,7 +1799,7 @@ msgstr "Val av höga poäng" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Varvförsök" @@ -1750,9 +1807,9 @@ msgstr "Varvförsök" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Grand Prix" @@ -1763,6 +1820,20 @@ msgstr "Grand Prix" msgid "Choose a Kart" msgstr "Välj en kart" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Kartklass" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Redigera favoritkarter" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1776,11 +1847,11 @@ msgstr "Delad skärm flerspelarläge" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "På nätet" @@ -1797,7 +1868,7 @@ msgstr "Handledning" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Höga poäng" @@ -1805,7 +1876,7 @@ msgstr "Höga poäng" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Presentationer" @@ -1859,30 +1930,30 @@ msgstr "Hitta server" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Skapa server" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Lobby" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Konfiguration" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Starta loppet" @@ -1908,9 +1979,9 @@ msgstr "Ange serveradress" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Din profil" @@ -1928,7 +1999,7 @@ msgstr "Spelarranking" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Vänner" @@ -1953,7 +2024,7 @@ msgstr "Snabbt spel" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Kontoinställningar" @@ -2003,8 +2074,8 @@ msgid "Online Username" msgstr "Nätanvändarnamn" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Återställ lösenord" @@ -2017,7 +2088,7 @@ msgid "" msgstr "Du kan spela utan att skapa ett nätkonto genom att välja ett frånkopplat konto. Men då kan du inte ansluta till vänner, rösta på tillägg o.s.v. Läs vår integritetspolicy på https://privacy.supertuxkart.net" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Val av server" @@ -2035,339 +2106,409 @@ msgstr "Använd IPv6-anslutning" msgid "User search" msgstr "Användarsökning" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Alternativ för SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "Visa" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Grafik" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Ljud" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Gränssnitt" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Spelare" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Kontroller" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Språk" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Musik" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Aktiverad" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Volym" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Ljudeffekter" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Ta bort konfiguration" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Inaktivera konfiguration" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Tillbaka till enhetslistan" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Byt namn på konfiguration" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Aktivera tvinga återkoppling (om det stöds)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Upplösning" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Helskärm" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Kom ihåg fönsterpositionen" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Tillämpa ny upplösning" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Delad skärm flerspelarläge layout" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "Internet-alternativ" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Visa alltid inloggningsskärm" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "Anslut till Internet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Aktivera chatt på nätet" +msgid "Enable chatting in online lobbies" +msgstr "Aktivera chatt i lobbyer på nätet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Aktivera chatt i spel på nätet" +msgid "Enable chatting in online matches" +msgstr "Aktivera chatt i matcher på nätet" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Diverse alternativ" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Aktivera handikapp per spelare" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Avinstallera hela speltillgångar" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Tryck Enter eller dubbelklicka på en enhet för att konfigurera den" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Lägg till en enhet" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Vilken konfiguration som ska användas härleds från vilken \"Välj\"-knapp som trycks in för att gå med i spelet." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Skal" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Minikarta" +msgid "Skin variant" +msgstr "Skalvariant" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Delad skärm flerspelarläge layout" +msgid "Minimap" +msgstr "Minikarta" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Teckenstorlek" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Kamera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Anpassad..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Visa FPS" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Visa andra karters kraftförstärkningar" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Aktivera tidtagaren för berättelseläge" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Aktivera hastighetskörningstidtagare" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "Rendera upplösning" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Nivå för grafiska effekter" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Nivå för suddighetseffekter" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Maximal FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Anpassade inställningar..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Upplösning" +msgid "Performance tests" +msgstr "Prestandatester" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Helskärm" +msgid "Performance test of the current settings" +msgstr "Prestandatest av aktuella inställningar" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Kom ihåg fönsterpositionen" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Kom ihåg lösenordet" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Tillämpa ny upplösning" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Ta bort" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Kartfärg" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2394,15 +2535,15 @@ msgstr "Blåa laget" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Antal varv" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Antal datorstyrda karter" @@ -2417,33 +2558,17 @@ msgstr "Antal datorstyrda karter i blått team" msgid "Random Grand Prix" msgstr "Slumpmässig Grand Prix" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Redigera favoritbanor" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Logga in" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Kom ihåg lösenordet" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Ta bort" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Kartfärg" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Skal för användargränssnittet kan ändras i alternativen för användargränssnittet." @@ -2562,238 +2687,306 @@ msgid "" msgstr "Kom inte i vägen för en lagkamrat som bär bollen, men du kan försöka slå motståndare som försöker hindra dem från att göra mål." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Duva" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Susanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Antediluvians avgrund" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Främmande signal" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Forntida Colosseum-labyrint" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Candelastaden" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Stridsön" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Svart skog" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Grotta X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Kakaotemplet" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Majsfältkorsningen" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Fort Magma" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Gran Paradiso ön" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Hacienda" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Hålsläpp" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Isig fotbollsplan" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Vad är med er små hippies? Är er älskade gnu-ledare försvunnen?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Oh ja, se, han är i mitt slott nu och kommer att serveras till kvällsmat..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Men jag är en fredlig varelse, så jag ska göra dig en deal." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Om du kan slå mig i ett lopp, kommer jag att befria gamla codger." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " Men ni, era patetiska små nollor, kommer aldrig att kunna slå mig - Kungen av karter!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Las Dunas arena" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Las Dunas fotbollsstadion" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Runt fyren" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Gammal gruva" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Bangolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Oasis" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Olivers matematiklektion" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Pumpaparken" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Ravenbridge herrgård" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Skiftande sand" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Nessys damm" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Nordlig tillflyktsort" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Snötopp" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Fotbollsplan" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Stadion" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Enterprise" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Tempel" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Vulkan-ön" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Zenträdgården" @@ -2802,11 +2995,11 @@ msgstr "Zenträdgården" msgid "Completed achievement \"%s\"." msgstr "Slutförde prestationen \"%s\"." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "Det gick inte att ansluta till tilläggsservern för SuperTuxKart." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Fel vid hämtning av nyheter: \"%s\"." @@ -2872,7 +3065,7 @@ msgid "New kart '%s' now available" msgstr "Nya karten \"%s\" finns tillgänglig" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2904,32 +3097,32 @@ msgid "" "created." msgstr "Din konfigurationsfil var för gammal, så den togs bort och en ny kommer att skapas." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Videoinspelning startad." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Video sparad i \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Kodningsframsteg:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "Tips: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Läser in" @@ -2951,19 +3144,18 @@ msgstr "Nitroeffektivitet" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (handikappad)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s är redo" @@ -3437,21 +3629,21 @@ msgid "Axis %d" msgstr "Axel %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Handkontrollsknapp %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Musknapp %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Musaxel %d %s" @@ -3623,26 +3815,30 @@ msgstr "Du kan ha som mest 3 liv!" msgid "+1 life." msgstr "+1 liv." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Du var för långsam!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Du avslutade loppet!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Du vann loppet!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Du avslutade loppet i rang %d!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s lämnade spelet." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3651,16 +3847,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart kan ansluta till en server för att hämta tillägg och meddela dig om uppdateringar. Läs vår integritetspolicy på https://supertuxkart.net/Privacy. Vill du att den här funktionen ska aktiveras? (För att ändra denna inställning vid ett senare tillfälle, gå till alternativ, välj fliken \"Allmänt\" och redigera \"Anslut till Internet\")." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "Din skärmupplösning är för låg för att köra STK." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "Drivrutinerna är för gammal. Installera de senaste grafikdrivrutinerna." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3668,38 +3864,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Din grafikdrivrutin verkar vara mycket gammal. Kontrollera om en uppdatering är tillgänglig. SuperTuxKart rekommenderar en drivrutin som stöder %s eller bättre. Spelet kommer sannolikt fortfarande att köras, men i ett reducerat grafikläge." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Tidsgränsen för serveranslutningen har löpt ut." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s har den röda flaggan!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Den röda flaggan har återvänt!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s har den blå flaggan!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Den blå flaggan har återvänt!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s tog den blå flaggan!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s tog den röda flaggan!" @@ -3709,7 +3905,7 @@ msgstr "%s tog den röda flaggan!" msgid "Eggs: %d / %d" msgstr "Ägg: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Ledare" @@ -3717,22 +3913,22 @@ msgstr "Ledare" msgid "Final lap!" msgstr "Sista varvet!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Varv %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s av %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Nytt snabbaste varv" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "FEL VÄG!" @@ -3746,194 +3942,194 @@ msgstr "%s gjorde mål!" msgid "Oops, %s made an own goal!" msgstr "Oj, %s gjorde ett självmål!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "%i reservdäckkart har uppstått!" msgstr[1] "%i reservdäckkarter har uppstått!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Du har blivit eliminerad!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "\"%s\" har eliminerats." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Servern har stängts av." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Du blev sparkad från servern." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Du blev sparkad: Ping för högt." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Dålig nätverksanslutning upptäcktes." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s frånkopplad." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Tryck på spelarnamnet i listan för information om spelarhantering och ranking." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Svårighetsgrad: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "Max antal spelare: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Spelläge: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Tidsgräns" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Målgräns" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Fotbollsspelstyp: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Grand prix-förlopp: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Alla spelare gick med i rött eller blått lag." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Du är nu ägare av servern." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Anslutning nekad: Servern är upptagen." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Anslutning nekad: Du är utestängd från servern." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Anslutning nekad: Serverlösenordet är felaktigt." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Anslutning nekad: Speldata är inte kompatibla." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Anslutning nekad: Servern är full." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Anslutning nekad: Ogiltig spelaranslutning." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Det gick inte att starta nätverksspelet." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Spelet har avslutats, du kan inte delta eller vara åskådare längre." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Ingen kvarvarande plats på arenan - live-anslutning inaktiverad." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Endast 1 spelare kvar, återvänder till lobbyn." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Serverägaren avslutade spelet." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Du kommer att vara åskådare i nästa spel." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s gick med i det röda laget." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s gick med i det blå laget." #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s gick med i spelet." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3941,15 +4137,15 @@ msgid "" msgstr "Tryck på <%s> eller <%s> att ändra den inriktade spelaren, <%s> eller <%s> för kamerans position." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "Rapporterat %s." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3980,38 +4176,38 @@ msgstr "Tidsförsök (Grand Prix)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Fritt-för-alla" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Fånga flaggan" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s är nu ansluten." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s och %s är nu anslutna." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s och %s är nu anslutna." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4019,19 +4215,19 @@ msgstr[0] "%d vän är nu på online." msgstr[1] "%ds vänner är nu på anslutna." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s är nu på servern \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "Du har %d ny vänförfrågan!" msgstr[1] "Du har %d nya vänförfrågningar!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Du har en ny vänförfrågan!" @@ -4060,12 +4256,12 @@ msgid "" msgstr "Filen för topplistan var för gammal,\nalla toppresultat har tagits bort." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Följ ledaren" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "3-träffsstrid" @@ -4078,91 +4274,88 @@ msgstr "Ofullständig reprisfil sparas inte." msgid "Replay saved in \"%s\"." msgstr "Repris sparad i \"%s\"." -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 vecka" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 veckor" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 månad" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 månader" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 månader" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 månader" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 år" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 år" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Tilläggets namn" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Datum för uppdatering" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Inte installerade" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s av %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Vänta medan tillägg uppdateras" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Tyvärr uppstod ett fel när tilläggswebbplatsen kontaktades. Se till att du är ansluten till Internet och att SuperTuxKart inte blockeras av en brandvägg" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Favoriter" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Låst: lös aktiva utmaningar för att få tillgång till mer!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Slumpmässig arena" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d arena är inte tillgängliga i enspelarläge." -msgstr[1] "%d arenor är inte tillgängliga i enspelarläge." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nefef6ec5b435a041fce803c7f8af77d2_2341d43, 2020\nEdvin Nilsson, 2015\nJohan R., 2017\nJohan R., 2017-2018\nJonatan Nyberg, 2021-2022\nJonatan Nyberg, 2020-2021\nKjell Rilbe, 2016\nKristoffer Grundström, 2016\nKristoffer Grundström, 2016,2022\nLuna Jernberg, 2020\nMarcus Larborg, 2017\nMikael Elm, 2021\ntheschitz, 2016,2018\nUbuntu Jackson, 2018\nFroppe123, 2015\nJohan R., 2018\nJonatan Nyberg, 2021\nAnders Carlsson\nArve Eriksson\nDaniel Nylander\nDawid Gan\nMDxm\nMathias Tillman\nMikael Mildén\nPhoenix\nRikard Edgren\nRikard Johansson\nSTK-team\nTransifex-bidragsgivare\nJohan R., 2017, 2018\nJonatan Nyberg, 2020, 2021\ntheschitz, 2016, 2018" @@ -4450,7 +4643,7 @@ msgstr "Bananer samlade" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Sladdar" @@ -4553,7 +4746,7 @@ msgstr "Äggjakter avslutade" msgid " (official tracks matching the goal)" msgstr " (officiella banor som matchar målet)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4561,91 +4754,95 @@ msgid "" msgstr "Nya handkontroller och joysticks visas automatiskt i listan när du ansluter dem till den här enheten.\n\nFör att lägga till en tangentbordskonfiguration, kan du använda knappen nedan. Observera DOCK att de flesta tangentbord bara stöder en begränsad mängd samtidiga tangenttryckningar och därför är olämpliga för flerspelarspel. (Du kan dock ansluta flera tangentbord till den här enheten. Kom ihåg att alla fortfarande behöver olika tangentbindningar i det här fallet.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Lägg till wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Lägg till tangentbordsinställningar" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Uppdatera" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Version: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "rekommenderad" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Storlek: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Du måste vara inloggad för att betygsätta detta tillägg." + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Tyvärr, hämtningen av tillägg misslyckades" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Problem vid installation av tillägget \"%s\"." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Försök igen" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Problem vid borttagning av tillägget \"%s\"." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Bakgrundshämtning klar." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Bakgrundshämtning" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Bakgrundshämtning har redan startat." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Nuvarande lösenord ogiltigt." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Lösenord måste vara mellan 8 och 30 tecken långt!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Lösenorden matchar inte!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Validerar info" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Lösenord har ändrats." @@ -4666,67 +4863,97 @@ msgstr "Upplösningar som är mindre än 1024x768 eller 1280x720 stöds inte. Vi #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Dronejakt" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Anpassad" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Inaktiverad" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Endast viktig" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Väldigt låg" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Låg" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Mellan" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Hög" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Mycket hög" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4734,7 +4961,7 @@ msgid "" msgstr "SuperTuxKart hämtar hela tillgångar (inklusive högkvalitativa texturer och musik) för bättre spelupplevelse, detta kommer att använda din mobildata om du inte har en Wi-Fi-anslutning." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4751,101 +4978,102 @@ msgstr "Ange serveradress eventuellt följt av : och sedan port eller välj adre msgid "Invalid server address: %s." msgstr "Ogiltig serveradress: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Backa" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Svårighet" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Varv" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Tid" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Kart" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Användare" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Version" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Nej" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "Bana" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "Topp %d höga poäng" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Antal karter: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Tidsmål: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Varv: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Omvänd: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Tom)" @@ -4933,33 +5161,41 @@ msgid "Press any key..." msgstr "Tryck på valfri knapp..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Chatten är inaktiverad, aktivera i alternativmenyn." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Tillbaka till prestationstestet" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Avsluta prestandatestet" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Tillbaka till striden" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Anordna nytt spel" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Starta om striden" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Avsluta striden" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Anordna nytt lopp" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Avsluta loppet" @@ -4975,11 +5211,11 @@ msgstr "%s har ingen ranking ännu." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s är nummer %d på rankningen med poängen %f." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Användarnamnet och/eller e-postadressen ogiltig." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -5001,7 +5237,7 @@ msgstr "Spökreprisepris lopp" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Varv: %i" @@ -5014,21 +5250,21 @@ msgstr "Typ: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Rank som krävs: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Tid som krävs: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Lustgaspoäng som krävs: %i" @@ -5041,54 +5277,54 @@ msgstr "Antal datorstyrda karter: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Stridsläge" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Typ av fotbollsspel" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Serverplats: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "Nuvarande bana: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Rankning" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Spelare" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Poäng" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Tid spelat" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Ta bort från bokmärken" @@ -5101,74 +5337,74 @@ msgid "No player available for connecting to server." msgstr "Ingen spelare tillgänglig för anslutning till servern." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Användarnamn: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "Avbryt förfrågan" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Idag" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Vänförfrågan skickades!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Vänförfrågan accepteras!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Vänförfrågan avböjdes!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Vän bort tagen!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Vänförfrågan nekas!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "Bearbetning" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Hämtar sista omröstningen" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Du kan ändra ditt tidigare betyg genom att klicka på stjärnorna nedanför." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Du har ännu inte röstat på detta tillägg. Välj ditt betyg genom att klicka på stjärnorna nedanför" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Omröstningen lyckades! Du kan nu stänga ner fönstret." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Genomför röstning" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Slumpmässig bana" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5197,7 +5433,7 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Ett fel uppstod när du försökte spara din grand prix." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "Välj en bana" @@ -5241,12 +5477,12 @@ msgstr "Du låste upp banan %0" msgid "You unlocked grand prix %0" msgstr "Du låste upp grand prix %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "Bana" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5267,19 +5503,19 @@ msgstr "Ange namnet på grand prix" msgid "Please select a Grand Prix" msgstr "Välj en Grand Prix" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Användardefinierad" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "Namnet är tomt." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "Ett annat grand prix med detta namnet finns redan." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "Namnet är för långt." @@ -5288,19 +5524,19 @@ msgstr "Namnet är för långt." msgid "Better luck next time!" msgstr "Bättre lycka nästa gång!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Du slutförde en utmaning!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Du vann Grand Prix!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Du har slutfört Grand Prix-tävlingen!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Antal karter" @@ -5313,110 +5549,125 @@ msgstr "Är du säker på att du vill ta bort denna höga poäng posten?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Är du säker på att du vill ta bort alla dina höga poäng?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Favorit" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Lätt" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Tung" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Anslut ett tangentbord eller en handkontroll för att spela flerspelarläge med delad skärm" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Slumpmässig kart" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Låst" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Alla:\nTryck på knappen \"Välj\" för att delta i spelet" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Vill du spela spelets handledning?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "Du kan inte spela på nätet utan internetuppkoppling. Om du vill spela på nätet går du till alternativmenyn och markerar \"Anslut till internet\"." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "Du kan inte hämta tillägg utan internetåtkomst. Om du vill hämta tillägg, gå till alternativmenyn och markera \"Anslut till Internet\"." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "Du kan inte hämta tillägg utan internetåtkomst. Om du vill hämta tillägg, gå till alternativmenyn och markera \"Anslut till Internet\".\n\nDu kan dock ta bort redan hämtade tillägg." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Tilläggsmodulen är för närvarande inaktiverad på skärmen Alternativ" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Vänta medan tilläggen läses in" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Är du säker på att du vill avsluta STK?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "Skapa LAN-server" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "%ss server" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Antal Grand Prix-banor" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "Namnet måste vara mellan 4 och 30 tecken långt!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Felaktiga tecken i lösenord!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Redo" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Gå med live" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Åskåda" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Installera tillägg" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5424,7 +5675,7 @@ msgstr "Vänta tills det aktuella spelet (%s) är slut, beräknad återstående #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Vänta tills det aktuella spelet är slut, beräknad återstående tid: %s." @@ -5432,24 +5683,24 @@ msgstr "Vänta tills det aktuella spelet är slut, beräknad återstående tid: #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Vänta tills det aktuella spelet (%s) är slut, beräknade framsteg: %s%." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Vänta tills det aktuella spelet är slut, beräknad framsteg: %d%." #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Vänta tills det aktuella spelet är slut." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5458,7 +5709,7 @@ msgstr[1] "Spelet startar om det finns fler än %d spelare." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5467,96 +5718,108 @@ msgid_plural "" msgstr[0] "Startar efter %d sekund eller när alla har tryckt på \"Redo\"-knappen." msgstr[1] "Startar efter %d sekunder eller när alla har tryckt på \"Redo\"-knappen." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Ansluter till servern %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Hitta en snabbspelserver" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Återstående tid: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Mål" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Hämtar prestationer" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "%ss profil" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Sedan" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Status" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Hämtar vänner" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Ny Förfrågan" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Pendlande" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Frånkopplad" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Ange ny e-post nedan" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Ny e-post måste bestå av mellan 5 och 254 tecken!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Ny e-post är ogiltig!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "E-post ändrad!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "Det gick inte att ändra e-post: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "Nyheter från STK-bloggen" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Datum" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "Det finns för närvarande inga tillgängliga nyheter." + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Du måste vara inloggad för att kunna spela globalt nätverk. Klicka på ditt användarnamn ovan." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Söker" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Avsluta spelat" @@ -5634,34 +5897,34 @@ msgid "Distance (km)" msgstr "Avstånd (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Okänd" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "Ingen IPv4 upptäckt, du kanske inte kan gå med i några servrar." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "Ingen IPv6 upptäckt, du kanske inte kan gå med i några servrar." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Ingen server är tillgänglig." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Hämtar server" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Serverbokmärken" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5669,149 +5932,149 @@ msgstr "Om en majoritet av spelarna alla väljer samma bana och tävlingsinstäl #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Slumpad placering av prylar" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Antal mål för att vinna" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Backa" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Låst: lösa aktiva utmaningar att få tillgång till mer!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Åtgärd" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Tangentbindning" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Inaktivera enhet" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Aktivera enhet" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Aktivera konfiguration" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Spelknappar" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Menyknappar" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Styr vänster" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Styr höger" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Accelerera" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Bromsa / backa" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Avfyra" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Lustgas" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Titta bakåt" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Rädda" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Pausa spelet" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Upp" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Ner" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Vänster" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Höger" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Välj" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Avbryt/Tillbaka" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Ett blått objekt betyder att det finns en konflikt med en annan konfiguration" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Ett rött objekt betyder att det finns en konflikt med en annan konfiguration" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5819,17 +6082,27 @@ msgid "" msgstr "Varning: \"Skift\" är inte en rekommenderad tangent. När \"Skift\" trycks ned, slutar alla tangenter som innehåller ett tecken som skiljer sig som versal att fungera." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Är du säker på att du verkligen permanent vill ta bort denna konfiguration?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Ange nytt konfigurationsnamn, lämna tomt för att återställa standardvärdet." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Vertikal" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Horisontell" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5837,89 +6110,74 @@ msgstr "I flerspelarläge kan spelare välja handikappade\n(svårare) profiler p #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Installera hela speltillgångar" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Är du säker på att du avinstallerar hela speltillgångar?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Tangentbord %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Tryckdon" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Klicka på en enhet för att konfigurera den" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Systemspråk" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Längst ner till vänster" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "På höger sida" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Dold" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Centrerad" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Vertikal" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Horisontell" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Väldigt liten" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Liten" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Mellan" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Stor" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Väldigt stor" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5929,128 +6187,133 @@ msgid "" msgstr "Hastighetskörningsläget kan endast aktiveras om spelet inte har stängts sedan berättelseläget lanserades.\n\nAtt stänga spelet innan berättelseläget har slutförts ogiltiggör tidtagaren.\n\nFör att använda hastighetskörningsläget, använd en ny profil." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Vertikal synkronisering" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Vsync tvingar grafikkortet att tillhandahålla en ny ram\nendast när monitorn är redo att visa den." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Vsync fungerar inte om dina förare inte stöder det." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Partikeleffekter: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Animerade karaktärer: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Dynamiskt ljus: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Ljusspridning: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Anti-aliasing: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Omgivande ocklusion: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Skuggor: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Skuggor: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Blomster: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Glimmer (konturer): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Light shaft (God rays): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "Renderad bildkvalitet: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Geometridetalj: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Rörelseoskärpa: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Fältdjup: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "Internetåtkomst är inaktiverad. Vill du aktivera det?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Du måste ange ett lösenord." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Loggar ut \"%s\"" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Loggar in \"%s\"" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Du kan inte ta bort den enda spelaren." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Vill du verkligen ta bort spelaren \"%s\"?" @@ -6078,7 +6341,7 @@ msgstr "MÅL!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Väntar på andra" @@ -6113,7 +6376,7 @@ msgstr "Följ ledaren!" msgid "Top %i" msgstr "Topp %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Utmaningen misslyckades" @@ -6137,102 +6400,199 @@ msgstr "Tryck på podiumikonen för att starta utmaningen" msgid "Press fire to start the challenge" msgstr "Tryck på avfyra för att starta utmaningen" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Tillbaka till videoinställningar" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "Spara testresultaten" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Tillbaka till huvudmenyn" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Avsluta servern" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Avbryt Grand Prix" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Starta om" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Tillbaka till utmaningsväljaren" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Tävla mot den nya spökreprisen" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Tillbaka till menyn" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Vill du verkligen avbryta Grand Prix?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "Resultatrapport sparad i \"%s\"." + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Röda laget vinner" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Blåa laget vinner" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Det är oavgjort" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "Eliminerad efter %s" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Utslagen" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Eget mål)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "Bana %i%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Grand Prix-förlopp:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Topplista" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "Bästa varvtid: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "av %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Du klarade utmaningen!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Du klarade inte utmaningen!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "Nådde kraven för SuperTux" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Prestandatestresultat" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "Testets varaktighet: %s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "Antal ramar: %s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "Stadig FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "Mestadels stadig FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "Typisk FPS: %s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "Horisontell upplösning: %s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "Vertikal upplösning: %s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "Dynamisk belysning: PÅ" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "Dynamisk belysning: AV" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "Rendera upplösning: %s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "Kantutjämning : PÅ" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "Kantutjämning : AV" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "Bildbaserad belysning: AV" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "Bildbaserad belysning: PÅ" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "Omgivningsocklusion: PÅ" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "Omgivningsocklusion: AV" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "Skuggupplösning: %s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Alla faror tillåtna, så plocka vapen och använd dem smart!" @@ -6273,28 +6633,28 @@ msgstr "Tryck på röd eller blå fotbollsikon för att byta lag" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Bana av %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "Max antal spelare som stöds: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Antal datorstyrda karter i rött team" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "Du kan inte spela denna Grand Prix eftersom den innehåller spår som inte är upplåsta!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Låst!" @@ -6316,10 +6676,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Slutför alla utmaningar för att låsa upp den stora dörren!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6328,41 +6690,48 @@ msgid "" msgstr "Du behöver fler poäng\nför att anta denna utmaningen!\nKontrollera minikartan för\ntillgängliga utmaningar." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "Accelerera med <%s> och styr med <%s> och <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Accelerera genom att röra vid den övre delen av ratten och styr genom att flytta åt vänster eller höger." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Accelerera genom att flytta gaspedalen uppåt och styr genom att luta din enhet." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Accelerera genom att flytta gaspedalen uppåt och styr genom att vrida enheten." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Samla presentförpackningar och avfyra vapnet med <%s> för att blåsa bort dessa lådor!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Samla presentförpackningar och avfyra genom att trycka på bowlingikonen för att blåsa bort dessa lådor!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6370,34 +6739,41 @@ msgid "" msgstr "Tryck på <%s> för att se bakom.\nAvfyra vapnet med <%s> medan du trycker på <%s> för att skjuta bakom!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Tryck på spegelikonen för att se bakom.\nAvfyra vapnet bakom genom att hålla spegelikonen och sedan svepa till bowlingikonen!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Använd lustgas du samlat genom att trycka <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Använd nitroen du samlat in genom att trycka på nitroikonen" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Samla lustgasflaskor (vi kommer att använda dem efter kurvan)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Hoppsan! När du är i trubbel, tryck på <%s> att räddas." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Hoppsan! När du har problem, tryck på fågelikonen för att räddas." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6405,24 +6781,27 @@ msgid "" msgstr "Accelerera och tryck på <%s>-tangenten medan du vrider för att sladda.\nAtt sladda en kort stund kan hjälpa dig att svänga snabbare för att ta skarpa svängar." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Accelerera och tryck på sladdikonen medan du vrider för att sladda.\nAtt sladda en kort stund kan hjälpa dig att svänga snabbare för att ta skarpa svängar." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Observera att om du lyckas sladda i flera sekunder får du en bonushastighet som belöning!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Du är nu redo att tävla. Lycka till!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "Ett 3D-racingspel med öppen källkod" @@ -6432,7 +6811,7 @@ msgstr "Ett 3D-racingspel med öppen källkod" msgid "tux;game;race;" msgstr "tux;spel;tävla;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6440,7 +6819,7 @@ msgid "" "for all ages." msgstr "Karter. Nitro. Handling! SuperTuxKart är en 3D-arkadracer med öppen källkod med en mängd olika karaktärer, banor och lägen att spela. Vårt mål är att skapa ett spel som är roligare än realistiskt och ger en trevlig upplevelse för alla åldrar." -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6449,7 +6828,7 @@ msgid "" "your opponents." msgstr "Vi har flera spår med olika teman för spelare att njuta av, från att köra under vattnet, jordbruksmarker, djungler eller till och med i rymden! Försök ditt bästa samtidigt som du undviker andra karter eftersom de kan köra förbi dig, men ät inte bananerna! Håll utkik efter bowlingbollar, kolvar, bubbelgummi och kakor som dina motståndare kastar." -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6458,27 +6837,27 @@ msgid "" "your racing skills!" msgstr "Du kan göra en enda tävling mot andra karter, tävla i en av flera Grand Prix, försöka slå höga poäng i tidsprov på egen hand, spela stridsläge mot datorn eller dina vänner och mer! För en större utmaning, gå med på nätet och träffa spelare från hela världen och bevisa dina tävlingsförmågor!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Det här spelet har inga annonser." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Detta är en instabil version av SuperTuxKart som innehåller de senaste förbättringarna. Den släpps främst för testning för att göra stabil STK så bra som möjligt." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Denna version kan installeras parallellt med den stabila versionen på enheten." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Om du behöver mer stabilitet, överväg att använda den stabila versionen: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "SuperTuxKart-team" diff --git a/data/po/tr.po b/data/po/tr.po index 96c5c07c06d..0bbcafd9ff5 100644 --- a/data/po/tr.po +++ b/data/po/tr.po @@ -3,7 +3,8 @@ # This file is distributed under the same license as the supertuxkart package. # # Translators: -# A. Cem Hanoğlu , 2024 +# A. Cem Hanoğlu , 2024-2025 +# A. Cem Hanoğlu , 2024 # FIRST AUTHOR , 2010 # Rover, 2022 # Rover, 2022 @@ -15,9 +16,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: A. Cem Hanoğlu , 2024\n" +"Last-Translator: A. Cem Hanoğlu , 2024-2025\n" "Language-Team: Turkish (http://app.transifex.com/supertuxkart/supertuxkart/language/tr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -113,7 +114,7 @@ msgstr "En az 3 Yapay zekaya karşı arka arkaya 5 tek yarış kazanın. Dikkat #. I18N: ./data/achievements.xml msgid "Banana Lover" -msgstr "Muz Sever" +msgstr "Muzsever" #. I18N: ./data/achievements.xml msgid "Collect at least 5 bananas in one race." @@ -153,7 +154,7 @@ msgstr "Penguen Oyun Alanı" #. I18N: ./data/grandprix/2_offthebeatentrack.grandprix msgid "Off the Beaten Track" -msgstr "Yenen Yoldan Dışarı" +msgstr "Kuş Uçmaz Kervan Geçmez" #. I18N: ./data/grandprix/3_tothemoonandback.grandprix msgid "To the Moon and Back" @@ -174,7 +175,7 @@ msgstr "Dünyanın Sonunda" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Geri" @@ -196,7 +197,7 @@ msgstr "Tercih ettiğiniz kontrol türünü seçin" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "İvme" @@ -210,13 +211,13 @@ msgstr "İvme" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "Denge" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "Direksiyon" @@ -247,35 +248,37 @@ msgstr "Dokunmatik Cihaz Ayarları" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Genel" @@ -343,30 +346,33 @@ msgstr "Varsayılanları geri yükle" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "İptal" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Evet" @@ -544,9 +550,9 @@ msgstr "Katıl" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -607,7 +613,7 @@ msgstr "Hedef" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "İlerleme" @@ -642,7 +648,7 @@ msgstr "Gönder" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Yarışa Geri Dön" @@ -659,7 +665,7 @@ msgstr "Lobiye Dön" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Yarışı Yeniden Başlat" @@ -723,12 +729,12 @@ msgstr "Parolanızı sıfırlayabilmek için kayıt sırasında verdiğiniz kull #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "Kullanıcı adı" @@ -769,7 +775,7 @@ msgstr "Zorluk" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Acemi" @@ -781,7 +787,7 @@ msgstr "Acemi" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Orta Seviye" @@ -793,7 +799,7 @@ msgstr "Orta Seviye" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Uzman" @@ -805,7 +811,7 @@ msgstr "Uzman" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -813,10 +819,10 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" -msgstr "Oyun kipi" +msgstr "Oyun modu" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: Multiplayer game mode @@ -825,8 +831,8 @@ msgstr "Oyun kipi" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Normal Yarış" @@ -839,7 +845,7 @@ msgstr "Normal Yarış" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Zamana Karşı" @@ -847,7 +853,8 @@ msgstr "Zamana Karşı" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "Savaş" @@ -856,24 +863,24 @@ msgstr "Savaş" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Futbol" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Parola" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "Bu sunucuya yer işareti koy" @@ -884,9 +891,9 @@ msgstr "Oyuncu ekle" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" -msgstr "İsim" +msgstr "Ad" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network @@ -978,6 +985,50 @@ msgstr "ESC tuşuna ata" msgid "Assign nothing" msgstr "Hiçbir tuş atama" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "Tavsiye Edilen Görüntü Ayarları " + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "Görüntü Kalitesi" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "Testi başlat" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -992,11 +1043,11 @@ msgstr "Yarış Kurulumu" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Devam" @@ -1026,7 +1077,7 @@ msgstr "Araçlar" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen msgid "Tracks" -msgstr "Yollar" +msgstr "Pistler" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In the addons screen @@ -1037,10 +1088,15 @@ msgstr "Arenalar" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "Kurulmuş" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1050,20 +1106,20 @@ msgstr "Kurulmuş" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Standart" @@ -1074,12 +1130,12 @@ msgstr "Standart" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Eklentiler" @@ -1093,27 +1149,28 @@ msgstr "Eklentiler" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Tümü" @@ -1133,7 +1190,7 @@ msgstr "Atla" #. I18N: ./data/gui/screens/tracks.stkgui #. I18N: In the track selection screen msgid "All Tracks" -msgstr "Tüm Yollar" +msgstr "Tüm Pistler" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Title in edit grand prix screen @@ -1152,9 +1209,9 @@ msgstr "Aşağı taşı" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "Ekle" @@ -1191,7 +1248,7 @@ msgstr "Hayaletinin Seçimi" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "Yumurta Avı" @@ -1238,17 +1295,17 @@ msgstr "Tersine çevir" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "En fazla süre (dak.)" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen msgid "Track group" -msgstr "Yol grubu" +msgstr "Pist grubu" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen @@ -1273,9 +1330,9 @@ msgstr "Kopyala" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1286,80 +1343,80 @@ msgstr "Adlandır" msgid "Save Grand Prix" msgstr "Grand Prix Kaydet" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "SuperTuxKart Yardım" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Oyun Kipleri" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "Güç artışları" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "Muzlar" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1367,56 +1424,57 @@ msgstr "Muzlar" msgid "Story Mode" msgstr "Hikaye Kipi" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "Araç sınıfları" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "Çok oyunculu" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "Öğreticiyi başlat" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "Mavi hediye kutuları topla, onlar sana güç artışı verecek." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Muzlardan kaç!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1424,14 +1482,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "Nitro toplamak, uygun tuşa veya düğmeye basarak istediğiniz zaman hız artışı elde etmenizi sağlar. Mevcut nitro seviyenizi yarış ekranının sağ altındaki göstergede görebilirsiniz." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Eğer burada olduğu gibi kilitli bir düğme görüyorsanız, onu açmak için bir meydan okumayı tamamlamanız gerekmektedir." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1440,34 +1498,34 @@ msgid "" "carefully before!" msgstr "Özel bir tuşa veya düğmeye basarak kayabilirsiniz. Ardışık kısa patinajlar keskin dönüşler yapmanıza yardımcı olur; orta patinajlar hızınızı arttırırken uzun patinajlar daha da yükselecek. Patinaj yaparken dönmeyi bırakamazsınız, bu nedenle aracınızı dikkatlice yönlendirin!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "Yarışa başlamadan önce 'Set!' De bulunan ivme düğmesine basarak bir başlangıç ​​takviyesi alabilirsiniz." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* Mevcut tuş ciltleri, Seçenekler menüsünde görülebilir/değiştirilebilir" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart çeşitli oyun kiplerine sahiptir:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "Düzenli Yarış: Tüm darbelere izin verilir, bu yüzden güç yükselticileri toplayın ve akıllıca kullanın!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "Zamana Karşı: Güç yükselticiler yok, bu nedenle sadece sürüş becerileriniz önemlidir!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1475,7 +1533,7 @@ msgid "" " leader will get you eliminated too!" msgstr "Lideri takip et: Sayaç her sıfıra düştüğünde en son kalan yarış aracı elendiğinden ikinci olmak üzere yarışın. Dikkat: liderini önünde olmak da sizi eleyecek!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1485,30 +1543,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "3 tür savaş kipi vardır: 3 Grev Savaşı'nda, hayatlarını kaybedinceye kadar başkalarına silahla vurmanız gerekir. Herkes tek'de diğerlerine en çok çarpan oyuncu belli bir vuruşta veya zaman sınırında kazanır. Bayrağı Yakala'da, takımınız diğer takımın bayrağını ele geçirmediği sürece, diğer takımın bayrağını kendi bayrak üssünüze getirmelidir." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "Futbol: Topu kaleye itmek için aracınızı kullanın." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." -msgstr "Yumurta avı: Tüm gizli yumurtaları bulmak için yolları keşfedin." +msgstr "Yumurta avı: Tüm gizli yumurtaları bulmak için pistleri keşfedin." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "Hayaletin: Zamana karşı veya yumurta avı kipinde hayaletine karşı yarış ve kendininkileri kaydet!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "Tur Denemesi: Belirli bir süre içinde mümkün olduğunca çok tur tamamlayın." -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1517,93 +1575,93 @@ msgid "" "wins the cup." msgstr "* Bu oyun kiplerinin birçoğu Grand Prix biçiminde de oynanabilir: tek bir yarış oynamak yerine, birçok oyunu üst üste oynarsınız. Daha iyi rütbe, daha fazla puan alırsınız. Sonunda, en yüksek puana sahip olan oyuncu kupayı kazanır." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "Kazanmanıza yardımcı olmak için toplayabileceğiniz bazı güçlendirmeler var:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "Şişen Sakız - kendini bir kalkanla koru veya arkana bakarken pembe yapışkan bir baloncuk bırakmak için kullan" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "Fermuar - Size güçlü bir hız artışı sağlayacaktır. Ancak aracınızın kontrolünü kaybetmemek için dikkat edin!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "Kek - en yakın rakibe atılmış, en iyi kısa menzillerde ve uzun boylarda. Ayrıca patlamaya yakın diğer kartları da etkiler." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Pompa - rakibi geri çekmek için düz atın veya arkaya bakarak birinin görüşünü engellemek için atın." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "Bowling Topu - Vuruncaya kadar düz gider, duvarlardan sekebilir. Geriye bakarsanız geriye doğru atılır." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Paraşüt - daha iyi konumdaki tüm araçları yavaşlatır" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "Değiştirici - hediye kutuları, muzlara, nitro kutularına sakızlara dönüştürülür ve bunun tersi de kısa bir süredir." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Basket Topu - liderin arkasından zıplar ve önündeki araçları ezip yavaşlatabilir." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "Sineklik - kartları yavaşlatır, yaklaştırır. Paraşüt ve bombaları kaldırmak için de kullanılabilir." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "Bir muzun vurulması, aşağıdakilerden birinin karta bağlanmasıyla sonuçlanabilir:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "Çapa - birinci konumdaki aracı inanılmaz derecede yavaşlatır." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "Paraşüt - kartı yavaşlatır, çapadan daha ilericidir. Ne kadar hızlı gidersen, o kadar güçlü olur seni yavaşlatır." -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "Bomba - aracı bir süre sonra patlatır, aracı havaya fırlatır. Bombayı ona aktarmak için başka bir karta çarpın." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "Kötü Nolok, Gnu'yu ele geçirdi! İşte size yardımcı olacak birkaç ipucu:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1612,7 +1670,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "Haritadaki bu simge, tamamlamadığınız mevcut zorlukları gösterir. Ekranın sağ üst köşesinde, o anda kaç puanın bulunduğunu da gösterir. Mümkün olduğu kadar çok zorluk tamamla ve Nolok sana karşı yarışmayı kabul edecek. Gnu'yu kurtarmak için kazan!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1620,20 +1678,20 @@ msgid "" " the cup and the more points it is worth." msgstr "Bir mücadeleyi tamamladığında, bir kupa alırsın. Her kupa birkaç puan değerinde. Mücadeleyi tamamladığınız zorluk ne kadar yüksekse, kupa o kadar iyi ve buna değecek kadar puan kazanın." -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "Bu simgenin altında belirtilen puan sayısını aldığınızda, size bir sürpriz hediye verilecektir. Toplanacak birkaç tane var." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "Tüm araçlar aynı şekilde sürmez! Farklılıkları olan sınıflara aittirler:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1641,30 +1699,30 @@ msgid "" " resistant to explosions." msgstr "Kütle - Kütlelerine bağlı olarak üç sınıf kart vardır: hafif, orta ve ağır. Daha ağır kartlar paraşütlerden daha az etkilenir ve patlamalara karşı daha dirençlidir." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " "with a lot of sharp curves. The lighter the kart, the faster it accelerates," " especially at low speeds." -msgstr "Hızlanma - özellikle başlangıçta, bir kazadan sonra veya çok fazla keskin viraj bulunan yollarda yararlıdır. Araç ne kadar hafif olursa, özellikle düşük hızlarda hızlanır." +msgstr "Hızlanma - özellikle başlangıçta, bir kazadan sonra veya çok fazla keskin viraj bulunan pistlerde yararlıdır. Araç ne kadar hafif olursa, özellikle düşük hızlarda hızlanır." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " "in tracks with straight lines and gentle curves. Heavier karts have a higher" " top speed." -msgstr "Azami hız - daha yüksek, araç daha hızlı gidebilir. Özellikle düz çizgiler ve yumuşak virajlı pistler için yararlıdır. Daha ağır araçlar daha yüksek bir hıza sahiptir." +msgstr "Azami hız - ne kadar yüksekse araç o kadar hızlı gidebilir. Özellikle yolları düz, yumuşak virajlı pistlerde yararlıdır. Ağır araçlar daha yüksek azami hıza sahiptir." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "Nitro verimi - Ne kadar yüksek olursa, bir nitro kutudan elde ettiğiniz hız o kadar artar. Daha hafif bir araç daha yüksek nitro verime sahip olacaktır." -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1672,12 +1730,12 @@ msgid "" "easier it is." msgstr "Birkaç saniye daha yakından takip ederseniz, solladığınızda hızlı bir hız bonusu elde edersiniz. Aracınız ne kadar hafif olursa, o kadar kolay olur." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart çevrimiçi olarak çok oyunculu kipte oynatılabilir...:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1687,7 +1745,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "İlk önce, ana menüdeki 'çevrimiçi' simgesini seçin. Yerel ağları veya genel ağları seçin (seçeneklerde İnternet'in etkinleştirilmesini gerektirir). Ardından, özel seçeneklerle kendi sunucunuzu oluşturabilir veya katılmak için mevcut sunucular arasında arama yapabilirsiniz. Bazıları isteğe bağlı olarak sıralanan yarışlara sahip sunucular önerilir." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1695,14 +1753,14 @@ msgid "" " enough players. Then, you can choose your kart and vote for the next track " "to race on. An addon track is allowed only if it exists on all joined " "players and the server." -msgstr "Bir sunucuya girdikten sonra, sahibi (taç ile belirtilir) karar verdikten sonra bir yarış başlayacaktır. Resmi sunucular yarışları yalnızca yeterli oyuncu olduğunda otomatik olarak başlatabilir. Ardından aracınızı seçebilir ve yarışacak bir sonraki bölüme oy verebilirsiniz. Bir eklenti bölümüne, yalnızca katılan tüm oynatıcılarda ve sunucuda varsa izin verilir." +msgstr "Bir sunucudayken yarışlar, sunucu sahibi (taç ile belirtilir) karar verdiğinde başlar. Resmi sunucular yarışları yalnızca yeterli oyuncu olduğunda otomatik olarak başlatabilir. Ardından aracınızı seçebilir ve yarışmak istediğiniz sonraki piste oy verebilirsiniz. Bir eklenti pistine, yalnızca katılan tüm oyuncularda ve sunucuda varsa izin verilir." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "... veya aynı cihazda:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1712,7 +1770,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "İlk önce, birkaç giriş aygıtına ihtiyacınız olacak. Onları ayarlamak için giriş yapılandırma ekranını kullanın. Birden fazla oyun kolu veya joystick idealdir: klavyelerde her bir oyuncunun farklı bir tuş takımına ihtiyacı olacaktır ve çoğu klavye çok oyunculu oyun için uygun değildir çünkü birden fazla eş zamanlı tuşa basmayı desteklemezler." -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1732,7 +1790,7 @@ msgstr "Yüksek Puan Seçimi" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "Tur Denemesi" @@ -1740,9 +1798,9 @@ msgstr "Tur Denemesi" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Grand Prix" @@ -1753,6 +1811,20 @@ msgstr "Grand Prix" msgid "Choose a Kart" msgstr "Bir Araç Seç" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "Araç Sınıfı" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "Favori araçları düzenle" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1766,11 +1838,11 @@ msgstr "Bölmeli Ekran Çok Oyunculu" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "Çevrimiçi" @@ -1787,7 +1859,7 @@ msgstr "Öğretici" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "Yüksek Puanlar" @@ -1795,7 +1867,7 @@ msgstr "Yüksek Puanlar" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "Başarılar" @@ -1849,30 +1921,30 @@ msgstr "Sunucu Bul" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "Sunucu Oluştur" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "Lobi" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "Yapılandırma" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "Yarışı başlat" @@ -1898,9 +1970,9 @@ msgstr "Sunucu adresi gir" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "Profilin" @@ -1918,7 +1990,7 @@ msgstr "Oyuncu sıralaması" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "Arkadaşlar" @@ -1943,7 +2015,7 @@ msgstr "Hızlı Oyna" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "Hesap Ayarları" @@ -1993,8 +2065,8 @@ msgid "Online Username" msgstr "Çevrimiçi Kullanıcı Adı" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "Parolayı sıfırla" @@ -2007,7 +2079,7 @@ msgid "" msgstr "Bir çevrimdışı hesap seçerek çevrimiçi bir hesap oluşturmadan oynayabilirsiniz. Ancak o zaman arkadaşlara bağlanamaz, eklentiler için oy kullanamazsınız vb. Lütfen https://privacy.supertuxkart.net adresindeki gizlilik bildirimimizi okuyun." #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "Sunucu Seçimi" @@ -2025,339 +2097,409 @@ msgstr "IPv6 bağlantısını kullan" msgid "User search" msgstr "Kullanıcı ara" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "SuperTuxKart Seçenekler" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Grafik" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Ses ve Müzik" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "Arayüz" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Oyuncular" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Kontroller" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "Diller" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Müzik" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Etkin" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Ses Seviyesi" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Ses Efektleri" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Yapılandırmayı Sil" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "Yapılandırma Devre Dışı" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Aygıt listesine geri dön" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "Yapılandırmayı Yeniden Adlandır" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "Titreşimi etkinleştir (destekleniyorsa)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Çözünürlük" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Tam ekran" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Pencere konumunu hatırla" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Yeni çözünürlüğü uygula" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "Bölmeli Ekran Çok Oyunculu düzeni" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "İnternet seçenekleri" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "Giriş ekranını her zaman göster" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "İnternete bağlan" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "Çevrimiçi sohbeti etkinleştir" +msgid "Enable chatting in online lobbies" +msgstr "Çevrimiçi odalarda sohbeti etkinleştir" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "Çevrimiçi oyunlarda sohbeti etkinleştir" +msgid "Enable chatting in online matches" +msgstr "Çevrimiçi maçlarda sohbeti etkinleştir" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "Çeşitli seçenekler" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "Oyuncu başına handikapları etkinleştir" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "Tüm oyun varlıklarını kaldır" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Bir aygıtı yapılandırmak için üstündeyken enter tuşuna basın veya iki kere tıklayın" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Aygıt ekle" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "* Yapılandırmayı kullanmak için hangisinin kullanılacağını seçmek için oyuna katılırken \"Seç\" tuşuna basılır." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Görünüm" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "Küçük Harita" +msgid "Skin variant" +msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "Bölmeli Ekran Çok Oyunculu düzeni" +msgid "Minimap" +msgstr "Küçük Harita" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "Yazı boyutu" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "Kamera" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "Özel..." -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "FPS Göster" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "Diğer araçların güç artışlarını göster" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "Hikaye kipi zamanlayıcısını etkinleştir" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "Hızlı koşu zamanlayıcısını etkinleştir" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "İşleme çözünürlüğü" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Grafik Efekt Seviyesi" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "Bulanıklık Efekt Seviyesi" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "Azami FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Özel ayarlar..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Çözünürlük" +msgid "Performance tests" +msgstr "Performans testleri" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Tam ekran" +msgid "Performance test of the current settings" +msgstr "Geçerli ayarların performans testi " -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Pencere konumunu hatırla" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "Parolayı hatırla" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Yeni çözünürlüğü uygula" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "Sil" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "Araç rengi" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2384,15 +2526,15 @@ msgstr "Mavi Takım" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "Tur sayısı" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Yapay zeka araç sayısı" @@ -2407,33 +2549,17 @@ msgstr "Mavi takım Araç sayısı" msgid "Random Grand Prix" msgstr "Rastgele Grand Prix" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "Favori pistleri düzenle " + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "Giriş yap" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "Parolayı hatırla" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "Sil" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "Araç rengi" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "Arayüz teması, Arayüz seçeneklerinden değiştirilebilir." @@ -2552,238 +2678,306 @@ msgid "" msgstr "Topu taşıyan bir takım arkadaşının önüne geçmeyin, oysa rakiplerinin golünü atmaya çalışan rakipleri vurmaya çalışabilirsiniz." #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "Su Altı Akvaryumu" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "Uzaylı Sinyali" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "Antik Kolezyum Labirenti" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "Candela Şehri" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Savaş Adası" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "Kara Orman" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Gizemli Mağara" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "Kakao Tapınağı" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "Mısır Tarlası" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Mağma Kalesi" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "Gran Paradiso Adası" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Çiftlik" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "Hole Drop" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "Buzlu Futbol Sahası" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Ne oldu küçük hippiler? Muhteşem GNU lideriniz mi kayıp?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "Ooo, evet. Şimdi benim kalemde ve akşam yemeği verilecek..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "Ama ben adil bir yaratığım, o yüzden sana bir anlaşma yapacağım." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Eğer beni yarışta yenebilirsen, yaşlı moruğu serbest bırakacağım." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " Fakat siz beceriksiz ahmaklar beni asla yenemeyeceksiniz - Araçların Kralı!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "Las Dunas Arenası" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "Las Dunas Futbol Stadyumu" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "Deniz Feneri Çevresi" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Eski Maden" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "Minigolf" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "Vaha" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Oliver'in Matematik Sınıfı" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "Balkabağı Parkı" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Ravenbridge Konağı" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Bataklık Kumları" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "Nessie'nin Göleti" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Kuzey Mesire" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Kar Tepesi" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "Futbol Sahası" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Stadyum" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK Kurumsal" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "Tapınak" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "Volkan Adası" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Zen Bahçesi" @@ -2792,11 +2986,11 @@ msgstr "Zen Bahçesi" msgid "Completed achievement \"%s\"." msgstr "\"%s\" başarısı tamamlandı." -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "SuperTuxKart eklenti sunucusuna bağlanamadı." -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "Haber indirme hatası: '%s'." @@ -2839,7 +3033,7 @@ msgstr "Kip: Ters" #: src/challenges/challenge_data.cpp:601 #, c-format msgid "New track '%s' now available" -msgstr "Yeni yol '%s' şimdi uygun" +msgstr "Yeni pist '%s' açıldı" #: src/challenges/challenge_data.cpp:605 #, c-format @@ -2862,7 +3056,7 @@ msgid "New kart '%s' now available" msgstr "Yeni araç '%s' şimdi uygun" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2894,32 +3088,32 @@ msgid "" "created." msgstr "Yapılandırma dosyanız çok eskiydi, bu yüzden silindi ve yeni bir tane oluşturulacak." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "Video kaydı başladı." -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "Video kaydedildi \"%s\"." -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "Kodlama ilerlemesi:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "Fps: %d/%d/%d - %d Ktris, Ping: %dms" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "İpucu: %s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Yükleniyor" @@ -2941,19 +3135,18 @@ msgstr "Nitro verimi" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s (engelli)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s hazır" @@ -3427,21 +3620,21 @@ msgid "Axis %d" msgstr "Eksen %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Oyun kolu düğmesi %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Fare düğmesi %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Fare ekseni %d %s" @@ -3613,26 +3806,30 @@ msgstr "En fazla 3 canınız olabilir!" msgid "+1 life." msgstr "+1 can." -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "Çok yavaştın!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Yarışı tamamladın!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Yarışı kazandınız!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "Yarışı %d sırada bitirdin!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s oyundan ayrıldı." -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3641,16 +3838,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart, eklentileri indirmek ve güncellemeleri size bildirmek için bir sunucuya bağlanabilir. Lütfen https://supertuxkart.net/Privacy adresindeki gizlilik politikamızı okuyun. Bu özelliğin etkinleştirilmesini ister misiniz? (Bu ayarı daha sonra değiştirmek için seçeneklere gidin, \"Genel\" sekmesini seçin ve \"İnternete Bağlan\" ı düzenleyin)." -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "STK'yı çalıştırmak için ekran çözünürlüğü çok düşük." -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." -msgstr "Sürücünüz çok eski. Lütfen enson ekran sürücülerini yükleyin." +msgstr "Sürücü yazılımınızın sürümü çok eski. Lütfen güncel ekran sürücülerini yükleyin." -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3658,38 +3855,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "Grafik sürücünüz çok eski görünüyor. Lütfen bir güncelleme olup olmadığını kontrol edin. SuperTuxKart %s veya daha iyisini destekleyen bir sürücü önerir. Oyun muhtemelen hala çalışır, ancak düşük grafik kipinde." -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "Sunucu bağlantısı zaman aşımına uğradı." #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s kırmızı bayrağı aldı!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "Kırmızı bayrak geri döndü!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s mavi bayrağı aldı!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "Mavi bayrak geri döndü!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s mavi bayrağı ele geçirdi!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s kırmızı bayrağı ele geçirdi!" @@ -3699,7 +3896,7 @@ msgstr "%s kırmızı bayrağı ele geçirdi!" msgid "Eggs: %d / %d" msgstr "Yumurtalar: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Lider" @@ -3707,22 +3904,22 @@ msgstr "Lider" msgid "Final lap!" msgstr "Son tur!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Tur %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s, %s tarafından" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Yeni en hızlı tur" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "YANLIŞ YÖN!" @@ -3736,194 +3933,194 @@ msgstr "%s bir gol attı!" msgid "Oops, %s made an own goal!" msgstr "Yuhhh, %s kendi kalesine gol attı!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "%i% s yedek lastik kartı üretildi! " msgstr[1] "%i yedek lastik kartı üretildi!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Elendiniz!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "'%s' yok edildi." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "Sunucu kapatıldı." -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "Sunucudan atıldın." -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "Atıldın: Ping çok yüksek." -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "Kötü ağ bağlantısı tespit edildi." -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "Bot" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s bağlantısı kesildi." #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "Oyuncu yönetimi ve sıralama bilgileri için listede oyuncu adına basın." #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "Zorluk: %s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "En fazla oyuncu: %d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "Oyun kipi: %s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "Zamana karşı" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "Gol sınırı" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "Futbol oyunu türü: %s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "Grand prix ilerlemesi: %d / %d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "Tüm oyuncular kırmızı veya mavi takıma katıldı." #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "Artık sunucunun sahibisiniz." -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "Bağlantı reddedildi: Sunucu meşgul." -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "Bağlantı reddedildi: Sunucudan yasaklandınız." -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "Bağlantı reddedildi: Sunucu parolası yanlış." -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "Bağlantı reddedildi: Oyun verileri uyumlu değil." -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "Bağlantı reddedildi: Sunucu dolu." -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "Bağlantı reddedildi: Geçersiz oyuncu bağlanıyor." -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "Ağ oyunu başlatılamadı." #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "Oyun sona erdi, artık katılamazsınız ya da izleyemezsiniz." #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "Arenada yer kalmadı - canlı katılım kapalı." #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "Sadece 1 oyuncu kaldı, lobiye dönülüyor." -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "Sunucu sahibi oyundan ayrıldı." #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "Bir sonraki oyunu izleyeceksiniz." #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s kırmızı takıma katıldı." #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%smavi takıma katıldı. " #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s oyuna katıldı." #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3931,15 +4128,15 @@ msgid "" msgstr "Bas <%s> yada <%s> hedeflenen oyuncuyu değiştirmek için, <%s> yada <%s> kamera konumu için." #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "Başarıyla rapor edildi %s." #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3970,38 +4167,38 @@ msgstr "Zamana Karşı (Grand Prix)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "Herkes Tek" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "Bayrağı Yakala" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s şuan çevrimiçi." -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s ve %s şuan çevrimiçi." -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s ve %s şuan çevrimiçi." #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." @@ -4009,19 +4206,19 @@ msgstr[0] "%d arkadaş şuan çevrimiçi." msgstr[1] "%d arkadaş şuan çevrimiçi." #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s şimdi sunucuda \"%s\"." -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "%d yeni arkadaşlık isteğin var!" msgstr[1] "%d yeni arkadaşlık isteğin var!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "Yeni bir arkadaş isteğiniz var!" @@ -4050,12 +4247,12 @@ msgid "" msgstr "Yüksek skor dosyası çok eskiydi,\ntüm yüksek skorlar silindi." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Lideri Takip Et" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "3 Vuruşlu Savaş" @@ -4068,91 +4265,88 @@ msgstr "Tamamlanmamış tekrar dosyası kaydedilmeyecek." msgid "Replay saved in \"%s\"." msgstr "Tekrar kaydedildi \"%s\"" -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 hafta" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 hafta" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 ay" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 ay" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 ay" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 ay" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 yıl" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 yıl" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Eklenti ismi" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Güncelleme zamanı" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "Kurulu değil" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s, %s tarafından" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Eklentiler güncelleninceye kadar bekleyin" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Üzgünüz, eklendi web sitesine erişilirken bir hata oluştu. Internet'e bağlı olduğunuzu ve SuperTuxKart'ın güvenlik duvarı tarafından engellenmediğinden emin olun." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "Favoriler " + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Kilitli : Daha fazlasına erişmek için aktif meydan okumaları hallet" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Rastgele Arena" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%darenası tek oyuncuda kullanılamıyor. " -msgstr[1] "%d arenası tek oyuncuda kullanılamıyor." - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nRover, 2022\nSerdar Sağlam, 2019-2022\nU. Ozan Basar, 2015\nVolkan Gezer, 2015\nyakup, 2015-2017\nSerdar Sağlam, 2019-2021\nDawid Gan\nMuhammet Kara\nOsman Tosun\nSTK-team\nVolkan Gezer\nemre can yılmaz\nlinuxseven\nmaidis\nyakup\nzeugma\nSerdar Sağlam\nRables" @@ -4440,7 +4634,7 @@ msgstr "Muz toplayıcı" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Savrulma" @@ -4541,9 +4735,9 @@ msgstr "Yumurta avları bitti" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:313 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:319 msgid " (official tracks matching the goal)" -msgstr "(hedefle eşleşen resmi yollar)" +msgstr "(hedefe uyan resmi pistler)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4551,91 +4745,95 @@ msgid "" msgstr "Yeni oyun kolu ve oyun çubukları, bu cihaza bağlandığınızda otomatik olarak listede görünecektir.\n\nBir klavye yapılandırması eklemek için, aşağıdaki düğmeyi kullanabilirsiniz, ancak, çoğu klavyenin yalnızca sınırlı miktarda eş zamanlı tuşa basmayı desteklediğini ve bu nedenle çok oyunculu oyun için uygun olmadığını lütfen unutmayın. (Ancak, bu cihaza birden fazla klavye bağlayabilirsiniz. Bu durumda herkesin hala farklı tuş bağlantılarına ihtiyacı olduğunu unutmayın.)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Wiimote Ekle" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Klavye Yapılandırması Ekle" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Güncelle" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Sürüm: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "öne çıkan" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Boyut:%s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "Bu eklentiyi puanlamak için giriş yapmalısınız. " + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Üzgünüz, eklenti indirme başarısız" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "'%s' eklentisini yüklerken hata." -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Tekrar dene" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "'%s' eklentisini kaldırırken hata." -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "Arka planda indirme tamamlandı." -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "Arka planda indir" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "Arka planda indirme zaten başladı." -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "Mevcut parola geçersiz." -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "Parola 8 ile 30 karakter arasında olmalıdır!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "Parolalar uyuşmuyor!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "Bilgi doğrulanıyor" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "Parola başarıyla değiştirildi." @@ -4656,67 +4854,97 @@ msgstr "1024x768 veya 1280x720'den küçük çözünürlükler desteklenmez. Kul #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "Drone kovalamaca" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Kişisel" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Devre Dışı" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "Sadece önemli" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "Çok Düşük" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "Düşük" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "Orta" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "Yüksek" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "Çok Yüksek" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "Ultra" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4724,7 +4952,7 @@ msgid "" msgstr "SuperTuxKart daha iyi oyun deneyimi için tam varlıkları (yüksek kaliteli dokular ve müzik dahil) indirir, bir kablosuz bağlantınız yoksa mobil verilerinizi kullanır." #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4741,101 +4969,102 @@ msgstr "Sunucu adresini girin ve ardından isteğe bağlı olarak adresin sonuna msgid "Invalid server address: %s." msgstr "Geçersiz sunucu adresi: %s." -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "Ters" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "Zorluk" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "Turlar" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "Zaman" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "Araç" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "Kullanıcı" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "Sürüm" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "Hayır" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" -msgstr "Yol" +msgstr "Pist" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "En İyi %d Yüksek Puanlar " -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "Araç sayısı: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "Zaman hedefi: %s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "Turlar: %d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "Tersten: %s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Boş)" @@ -4923,33 +5152,41 @@ msgid "Press any key..." msgstr "herhangi bir tuşa bas..." #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "Sohbet devre dışı, seçenekler menüsünden etkinleştirin." -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "Performans Testine Geri Dön " + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "Performans Testinden Çık " + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "Savaşa Geri Dön" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "Yeni Oyun Kur" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "Savaşı Yeniden Başlat" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "Savaştan Çık" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Yeni Yarış Kur" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Yarıştan Çık" @@ -4965,11 +5202,11 @@ msgstr "%s henüz bir sıralamada yok." msgid "%s is number %d in the rankings with a score of %f." msgstr "%s,%f puan alan sıralamalarda %d sayısıdır." -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "Kullanıcı adı veya eposta adresi geçersiz." -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4991,7 +5228,7 @@ msgstr "Hayaletine Karşı Yarış" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "Turlar: %i" @@ -5004,21 +5241,21 @@ msgstr "Tür: %s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "Gerekli Sıra %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "Gerekli Zaman: %i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "Gerekli Nitro Puanları: %i" @@ -5031,54 +5268,54 @@ msgstr "Yapay Zeka Araç Sayısı: %i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "Savaş kipi" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "Futbol oyunu türü" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "Sunucu konumu: %s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" -msgstr "Mevcut yol: %s" +msgstr "Şu anki pist: %s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Sıra" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "Oyuncu" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "Puanlar" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "Oynanan zaman" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "Yer imlerinden kaldır" @@ -5091,74 +5328,74 @@ msgid "No player available for connecting to server." msgstr "Sunucuya bağlanmak için uygun oyuncu yok." #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "Kullanıcı adı: %s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "İsteği İptal Et" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "Bugün" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "Arkadaşlık isteği gönderildi!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "Arkadaşlık isteği kabul edildi!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "Arkadaşlık isteği reddedildi!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "Arkadaş kaldırıldı!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "Arkadaşlık isteği iptal edildi!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "İşleniyor" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "Son oy alınıyor" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "Önceki derecelendirmenizi altındaki yıldızları tıklatarak uyarlayabilirsiniz." -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "Bu eklentiye henüz oy vermediniz. Altındaki yıldızlara tıklayarak istediğiniz puanı seçin" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "Başarıyla oy verildi! Şimdi pencereyi kapatabilirsiniz." -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "Başarı oylaması" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" -msgstr "Rastgele Yol" +msgstr "Rastgele Pist" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5187,9 +5424,9 @@ msgstr "%s (+)" msgid "An error occurred while trying to save your grand prix." msgstr "Senin grand prix kaydedilmeye çalışılırken bir hata oluştu." -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" -msgstr "Bir yol seç" +msgstr "Bir pist seç" #: src/states_screens/feature_unlocked.cpp:254 #, c-format @@ -5231,12 +5468,12 @@ msgstr "%0 yolunu açtınız" msgid "You unlocked grand prix %0" msgstr "Grand prix %0 kilidini açtınız" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" -msgstr "Yol" +msgstr "Pist" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5257,19 +5494,19 @@ msgstr "Lütfen grand prix adını girin" msgid "Please select a Grand Prix" msgstr "Lütfen bir Grand Prix seçin" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "Kullanıcı tanımlı" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "İsim boş." -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr " Bir diğer grand prix ile aynı adı taşıyor." -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "İsim çok uzun." @@ -5278,19 +5515,19 @@ msgstr "İsim çok uzun." msgid "Better luck next time!" msgstr "Bir dahaki oyunda iyi şanslar!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Bir görev tamamladınız!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "Grand Prix'i kazandınız!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Grand Prix'i tamamladınız!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "Araç sayısı" @@ -5303,110 +5540,125 @@ msgstr "Bu yüksek skoru kaldırmak istediğinizden emin misiniz?" msgid "Are you sure you want to remove all of your high scores?" msgstr "Bütün yüksek skorlarınızı kaldırmak istediğinizden emin misiniz?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "Favoriler" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "Hafif" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "Ağır " + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "Bölünmüş çok oyunculu oyun oynamak için bir klavye veya oyun kolu bağla" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Rastgele Araç" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Kilitli" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "Herkes:\nOyuna katılmak için 'Seç' düğmesine basın" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "Oyun öğreticisini oynamak ister misiniz?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "İnternet erişimi olmadan çevrimiçi oynayamazsınız. Çevrimiçi oynamak için seçenekler menüsüne gidin ve \"İnternete bağlan\" seçeneğini işaretleyin." -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "İnternet bağlantısı olmadan eklentileri indiremezsiniz. Eklentileri indirmek istiyorsanız, seçenekler menüsüne gidin ve \"İnternete bağlan\" seçeneğini işaretleyin." -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "İnternet bağlantısı olmadan eklentileri indiremezsiniz. Eklentileri indirmek istiyorsanız, seçenekler menüsüne gidin ve \"İnternete bağlan\" seçeneğini işaretleyin.\n\nAncak önceden indirilmiş eklentileri silebilirsiniz." -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Eklentiler modülü şuan Ayarlar ekranından devre dışı bırakılmış" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Eklentiler yükleninceye kadar bekleyin" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "Oyundan çıkmak istediğinizden emin misiniz?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "LAN Sunucusu Oluştur" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "%s'in sunucusu" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "Grand prix pistlerinin sayısı" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "İsim 4 ile 30 karakter arasında olmalıdır!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "Parola içinde yanlış karakterler var!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "Hazır" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "Canlı katılım" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "Seyret" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "Eklenti kur" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5414,7 +5666,7 @@ msgstr "Lütfen mevcut oyunun (%s) sonunu bekleyin, kalan tahmini süre: %s." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "Lütfen mevcut oyunun sona ermesini bekleyin, kalan tahmini süre: %s." @@ -5422,24 +5674,24 @@ msgstr "Lütfen mevcut oyunun sona ermesini bekleyin, kalan tahmini süre: %s." #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "Lütfen mevcut oyunun (%s) sonunu bekleyin, tahmini ilerleme: %%s" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "Lütfen mevcut oyunun sona ermesini bekleyin, tahmini ilerleme: %%d" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "Lütfen mevcut oyunun bitmesini bekleyin." -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5448,7 +5700,7 @@ msgstr[1] "%d'den fazla oyuncu varsa oyun başlayacaktır." #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5457,96 +5709,108 @@ msgid_plural "" msgstr[0] "%d saniye sonra veya herkes 'hazır' düğmesine bastıktan sonra başlayacak." msgstr[1] "%d saniye sonra veya herkes 'hazır' düğmesine bastıktan sonra başlayacak." -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "Sunucuya bağlanıyor %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "Hızlıca bir oyun sunucusu bul" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "Kalan süre: %d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "Hedefler" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "Başarılar getiriliyor" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "%s'in profili" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "Tarihi" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "Durum" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "Arkadaşlar alınıyor" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "Yeni İstek" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "Bekliyor" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "Çevrimdışı" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "Yeni e-postayı aşağıya giriniz" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "Yeni e-posta 5 ile 254 karakter arasında olmalıdır!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "Yeni e-posta geçersiz!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "E-posta değiştirildi!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "E-postayı değiştirirken hata oldu: %s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "Tarih" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "Genel ağda oynamak için giriş yapmalısınız. Yukarıdaki kullanıcı adınızı tıklayın." -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "Aranıyor" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "Oyundan çık" @@ -5624,184 +5888,184 @@ msgid "Distance (km)" msgstr "Mesafe (km)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "Bilinmeyen" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "IPv4 algılanmadı, hiçbir sunucuya katılamayabilirsiniz." #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "IPv6 algılanmadı, hiçbir sunucuya katılamayabilirsiniz." -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "Sunucu mevcut değil." -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "Sunucular alınıyor" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "Sunucu Yer İmleri" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." -msgstr "Çoğu oyuncu aynı pist ve yarış ayarlarını seçerse, oylama erken sona erer." +msgstr "Oyuncuların çoğunluğu aynı pist ve yarış ayarlarını seçerse, oylama erken sona erer." #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "Rasgele nesne konumu" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "Kazanmak için gol sayısı" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "Tersten sür" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "Kilitli: daha fazlasına erişmek için aktif zorlukları çöz!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "Aksiyon" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "Anahtar bağlama" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Aygıtı Devre Dışı Bırak" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Aygıtı Aktifleştir" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "Yapılandırmayı Etkinleştir" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Oyun Tuşları" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Menü Tuşları" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Sol Yap" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Sağ Yap" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Hızlandırıcı" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "Fren / Geri" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Ateş" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Nitro" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Arkaya Bak" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Kurtarma" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Oyunu Duraklat" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Yukarı" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Aşağı" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Sol" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Sağ" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Seç" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "İptal / Geri" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Bir mavi öge, başka bir yapılandırmayla çakışma demektir." -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "* Bir kırmızı öge, geçerli yapılandırmayle çakışma demektir." -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5809,17 +6073,27 @@ msgid "" msgstr "Uyarı: 'Shift' önerilen bir anahtar değildir. 'Shift' tuşuna basıldığında, büyük harflerden farklı bir karakter içeren tüm tuşlar çalışmayı durduracaktır." #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Bu yapılandırmayı kalıcı olarak silmek istediğinizden emin misiniz?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "Yeni yapılandırma adını girin, varsayılan değeri geri döndürmek için boş bırakın." +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "Dikey" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "Yatay" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5827,89 +6101,74 @@ msgstr "Çok oyunculu kipte, oyuncular handikap seçimi yapabilir\naraç seçim #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "Tüm oyun varlıklarını kur" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "Oyun varlıklarının tümü kaldırılacak emin misiniz?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Klavye %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "Dokunmatik Cihaz" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "Yapılandırmak için bir cihaza hafifçe dokunun" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Sistem Dili" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "Sol altta" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "Sağ tarafta" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "Gizli" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "Ortalanmış" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "Dikey" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "Yatay" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "Çok küçük" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "Küçük" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "Orta" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "Büyük" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "Çok büyük" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5919,128 +6178,133 @@ msgid "" msgstr "Hızlı koşu kipi, yalnızca hikaye kipinin başlamasından bu yana oyun kapatılmadıysa etkinleştirilebilir.\n\nOyunun hikaye kipi tamamlanmasından önce kapatılması zamanlayıcıyı geçersiz kılar.\n\nHızlı koşu kipini kullanmak için lütfen yeni bir profil kullanın." #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "Dikey Eşitleyici" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "Vsync, grafik kartını yeni bir çerçeve sağlamaya zorlar\nyalnızca ekran görüntülemeye hazır olduğunda." #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "Sürücüler desteklemiyorsa Vsync çalışmaz." #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "Parçacık Efektleri: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "Animasyonlu Karakterler: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "Dinamik ışıklar: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "Işık saçılması: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "Kenar yumuşatma: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "Çevresel perdeleme: %s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "Gölgeler: %s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "Gölgeler: %i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "Tazelenme: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "Parıltı (ana hatlar): %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "Işık mili (Işınlar): %s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "İşlenmiş resim kalitesi: %s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "Geometrik ayrıntılar: %s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "Hareket bulanıklığı: %s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "Alan derinliği: %s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "İnternet erişimi devre dışı. Etkinleştirmek ister misiniz?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "Bir parola girmen gerekli." -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "Çıkış yapılıyor '%s'" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "Giriş yapılıyor '%s'" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "Tek oyuncuyu silemezsin." #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "Gerçekten oyuncu silmek istiyor musunuz '%s'?" @@ -6068,7 +6332,7 @@ msgstr "GOL!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "Başkalarını bekliyorum" @@ -6103,7 +6367,7 @@ msgstr "Lideri takip et!" msgid "Top %i" msgstr "En İyi %i" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Mücadele Başarısız" @@ -6127,102 +6391,199 @@ msgstr "Meydan okumaya başlamak için podyum simgesine bas" msgid "Press fire to start the challenge" msgstr "Mücadeleyi başlatmak için ateş düğmesine bas" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "Görüntü ayarlarına geri dön" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "Ana menüye dön " + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "Sunucudan çık" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Grand Prix'i Durdur" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Yeniden Başlat" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "Meydan okuma seçimine geri dön" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "Hayaletine Karşı Tekrar Yarış" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Menüye Dön" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Gerçekten Büyük Yarış'ı iptal etmek istiyor musun?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "Kırmızı Takım Kazandı" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "Mavi Takım Kazandı" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "Berabere" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "%s sonra elendi." -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Elendi" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(Kendi Kalesine Gol)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" -msgstr "Yol %i/%i" +msgstr "Pist %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Grand Prix ilerlemesi:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Yüksek Puanlar" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "En iyi tur zamanı: %s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "%s tarafından" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "Meydan okumayı tamamladın!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "Meydan okumada başarısız oldun!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "SuperTux'un Ulaşılan Gereksinimleri" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "Performans Testi Sonuçları" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Tüm patlatmalara izin var, öyleyse silahları kap ve onları zekice kullan !" @@ -6246,7 +6607,7 @@ msgstr "Gol atmak için topu karşı kaleye doğru itin." #: src/states_screens/race_setup_screen.cpp:130 msgid "Explore tracks to find all hidden eggs" -msgstr "Tüm gizli yumurtaları bulmak için yolları keşfedin." +msgstr "Tüm gizli yumurtaları bulmak için pistleri keşfedin." #: src/states_screens/race_setup_screen.cpp:138 msgid "Race against ghost karts and try to beat them!" @@ -6263,28 +6624,28 @@ msgstr "Ekibi değiştirmek için kırmızı veya mavi futbol simgesine basın" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" -msgstr "Yolu hazırlayan: %s" +msgstr "Pisti hazırlayan: %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "En fazla oyuncu desteği: %d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "Kırmızı takım Araç sayısı" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" -msgstr "Kilidi açılmamış bölümler içerdiğinden bu Grand Prix'i oynayamazsınız!" +msgstr "Kilidi açılmamış pistler içerdiğinden bu Grand Prix'i oynayamazsınız!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Kilitli!" @@ -6306,10 +6667,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "Tüm görevleri tamamlayıp büyük kapı kilidini açın!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6318,41 +6681,48 @@ msgid "" msgstr "Bu yarışa katılabilmek için\ndaha fazla puana ihtiyacın var!\nKullanılabilir daha\nküçük yarışlar seçin." #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "<%s> ile hızlandır, bunlar ile yönlendir <%s> ve <%s>." #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "Tekerleğin üst kısmına dokunarak hızlandırın ve sola veya sağa hareket ettirerek yönlendirin." #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "Hızlandırıcıyı yukarı doğru hareket ettirerek hızlandırın ve cihazınızı eğerek yönlendirin." #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "Hızlandırıcıyı yukarı doğru hareket ettirerek hızlandırın ve cihazınızı döndürerek yönlendirin." #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "Hediye kutusu topla ve bu kutuları kullanmak için <%s> tuşu ile silahı ateşle!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "Hediye kutularını topla ve bu kutuları atmak için bowling simgesine basarak ateş et!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6360,34 +6730,41 @@ msgid "" msgstr "Arkaya bakmak için <%s> tuşuna basın.\n<%s> tuşuna basarken silahı <%s> ile ateşleyin!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "Geriye bakmak için ayna simgesine basın.\nAyna simgesini tutarak ve bowling simgesine kaydırarak silahı ateşleyin!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Topladığın nitroyu kullanmak için <%s> tuşuna bas!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "Nitro simgesine basarak topladığınız nitroyu kullanın." #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "Nitro şişeleri toplayın (bunları virajdan sonra kullanacağız)." #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "Olamaz! Başın dertte olduğunda, kurtarılmak için <%s> tuşuna bas." #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "Hata! Başınız beladayken kurtarılacak kuş simgesine basın." #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6395,24 +6772,27 @@ msgid "" msgstr "Kızağa dönerken hızlanın ve <%s> tuşuna basın.\nKısa bir süreli patinaj keskin dönüşler yapmak için daha hızlı dönmenize yardımcı olabilir." #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "Kızağa dönerken kızak simgesini hızlandırın ve basın.\nKısa bir süreli patinaj keskin dönüşler yapmak için daha hızlı dönmenize yardımcı olabilir." #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "Eğer birkaç saniye kaymayı başarırsan, ödül olarak bonus bir hızlandırma alacaksın!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Artık yarışa hazırsın. İyi şanslar!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "3D açık kaynaklı kart yarış oyunu" @@ -6422,24 +6802,24 @@ msgstr "3D açık kaynaklı kart yarış oyunu" msgid "tux;game;race;" msgstr "tux;oyun;yarış;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " "game that is more fun than realistic, and provide an enjoyable experience " "for all ages." -msgstr "Araçlar. Nitro. Aksiyon! SuperTuxKart, çeşitli karakterler, pistler ve oynanacak kiplere sahip 3B açık kaynaklı bir oyun makinesi yarışçısıdır. Amacımız gerçekçi olmaktan çok daha eğlenceli bir oyun yaratmak ve her yaşa keyifli bir deneyim sunmaktır." +msgstr "Araçlar. Nitro. Aksiyon! SuperTuxKart çeşitli karakterler, pistler ve oyun modlarına sahip 3D açık kaynaklı bir yarış oyunudur. Amacımız gerçekçiden çok eğlenceli bir oyun yaratmak ve her yaştaki insanın tadını çıkarabileceği bir deneyim sağlamaktır. " -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" " while avoiding other karts as they may overtake you, but don't eat the " "bananas! Watch for bowling balls, plungers, bubble gum, and cakes thrown by " "your opponents." -msgstr "Su altında, kırsal tarım arazilerinde, ormanlarda ve hatta uzayda sürüşten, oyuncuların eğlenmesi için çeşitli temalara sahip birkaç yolumuz var! Sizi geçebilecekleri için diğer araçlardan kaçınırken elinizden gelenin en iyisini yapın, ancak muzları yemeyin! Rakipleriniz tarafından fırlatılan bowling toplarına, pistonlara, sakızlara ve keklere dikkat edin." +msgstr "Oyuncuların tadını çıkarması için su altında sürmekten köylere, cangıllara veya hatta uzaya kadar çeşitli temalara sahip pistlerimiz bulunmakta. Diğer araçlar sizi geçebileceği için onlardan kaçınırken elinizden gelenin en iyisini yapmaya çalışın, ancak sakın muzları yemeyin! Rakipleriniz tarafından fırlatılan bovling toplarına, pompalara, sakızlara ve pastalara dikkat edin. " -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6448,27 +6828,27 @@ msgid "" "your racing skills!" msgstr "Diğer araçlara karşı tek bir yarış yapabilir, birkaç Grand Prix'den birinde yarışabilir, zaman denemelerinde kendi başınıza yüksek puanı geçmeye çalışabilir, bilgisayara veya arkadaşlarınıza karşı savaş kipini oynayabilir ve daha fazlasını yapabilirsiniz! Daha büyük bir meydan okuma için çevrimiçi katılın ve dünyanın her yerinden oyuncularla tanışın ve yarış becerilerinizi kanıtlayın!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "Bu oyunda reklam yok." -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "Bu, en son geliştirmeleri içeren SuperTuxKart'ın kararsız bir sürümüdür. STK'yı olabildiğince iyi hale getirmek için esas olarak test için yayınlandı." -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "Bu sürüm, cihazdaki kararlı sürümle paralel olarak kurulabilir." -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "Daha fazla kararlılığa ihtiyacınız varsa kararlı sürümü kullanın: %s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "SuperTuxKart Takımı" diff --git a/data/po/vi.po b/data/po/vi.po index 0a320a1a2af..4fa1166e777 100644 --- a/data/po/vi.po +++ b/data/po/vi.po @@ -4,15 +4,16 @@ # # Translators: # FIRST AUTHOR , 2011 +# Luu Tuyen, 2025 # Thanh Bách 6/1, 2022 # Thanh Bách 6/1, 2022 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: Thanh Bách 6/1, 2022\n" +"Last-Translator: Luu Tuyen, 2025\n" "Language-Team: Vietnamese (http://app.transifex.com/supertuxkart/supertuxkart/language/vi/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -48,7 +49,7 @@ msgstr "" #. I18N: ./data/achievements.xml msgid "Strike!" -msgstr "" +msgstr "Bãi công!" #. I18N: ./data/achievements.xml msgid "Hit 10 karts with a bowling-ball." @@ -98,7 +99,7 @@ msgstr "" #. I18N: ./data/achievements.xml msgid "Unstoppable" -msgstr "" +msgstr "Không thể dừng lại" #. I18N: ./data/achievements.xml msgid "" @@ -116,7 +117,7 @@ msgstr "" #. I18N: ./data/achievements.xml msgid "It's secret" -msgstr "" +msgstr "Đó là bí mật" #. I18N: ./data/achievements.xml msgid "Really ... a secret." @@ -124,7 +125,7 @@ msgstr "" #. I18N: ./data/achievements.xml msgid "Mosquito Hunter" -msgstr "" +msgstr "Thợ săn muỗi" #. I18N: ./data/achievements.xml msgid "" @@ -169,7 +170,7 @@ msgstr "Nơi tận cùng của thế giới" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "Quay về" @@ -191,7 +192,7 @@ msgstr "" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "" @@ -205,15 +206,15 @@ msgstr "" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" -msgstr "" +msgstr "Vô lăng" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui @@ -234,7 +235,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/kart_color_slider.stkgui #. I18N: In the kart color slider dialog msgid "Apply" -msgstr "" +msgstr "Áp dụng" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui msgid "Touch Device Settings" @@ -242,35 +243,37 @@ msgstr "" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "Chung" @@ -293,7 +296,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen msgid "Advanced" -msgstr "" +msgstr "Nâng cao" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen @@ -338,30 +341,33 @@ msgstr "" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "Huỷ bỏ" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "Có" @@ -378,7 +384,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/registration_terms.stkgui #. I18N: In the registration dialog msgid "Accept" -msgstr "" +msgstr "Đồng ý" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui msgid "Camera Settings" @@ -422,7 +428,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "Reset" -msgstr "" +msgstr "Đặt lại" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui msgid "Graphics Settings" @@ -526,7 +532,7 @@ msgstr "Đóng" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog msgid "Join" -msgstr "" +msgstr "Tham gia" #. I18N: ./data/gui/dialogs/general_text_field_dialog.stkgui #. I18N: In the general textfield dialog @@ -539,9 +545,9 @@ msgstr "" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -564,7 +570,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info action msgid "Compare to another ghost" -msgstr "" +msgstr "So sánh với một con ma khác" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info action @@ -580,7 +586,7 @@ msgstr "Xóa bỏ" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info screen action msgid "Compare ghost" -msgstr "" +msgstr "So sánh ma" #. I18N: ./data/gui/dialogs/ghost_replay_info_dialog.stkgui #. I18N: Ghost replay info screen action @@ -597,36 +603,36 @@ msgstr "Bắt Đầu Cuộc Đua" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Objective shown in achievement dialog msgid "Goal" -msgstr "" +msgstr "Vào" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" -msgstr "" +msgstr "Tiến bộ" #. I18N: ./data/gui/dialogs/online/change_password.stkgui #. I18N: In the change password dialog msgid "Password Change" -msgstr "" +msgstr "Thay Đổi Mật Khẩu" #. I18N: ./data/gui/dialogs/online/change_password.stkgui #. I18N: In the change password dialog msgid "Current Password" -msgstr "" +msgstr "Mật Khẩu Hiện Tại" #. I18N: ./data/gui/dialogs/online/change_password.stkgui #. I18N: In the change password dialog msgid "New Password" -msgstr "" +msgstr "Mật Khẩu Mới" #. I18N: ./data/gui/dialogs/online/change_password.stkgui #. I18N: In the change password dialog #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog msgid "Confirm" -msgstr "" +msgstr "Xác nhận" #. I18N: ./data/gui/dialogs/online/change_password.stkgui #. I18N: In the change password dialog @@ -637,7 +643,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "Quay về vòng đua" @@ -654,7 +660,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "Đua lại" @@ -694,7 +700,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/player_rankings_dialog.stkgui msgid "Refresh" -msgstr "" +msgstr "Làm mới" #. I18N: ./data/gui/dialogs/online/recovery_info.stkgui #. I18N: In the recovery dialog @@ -718,14 +724,14 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" -msgstr "" +msgstr "Tên người dùng" #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog @@ -747,7 +753,7 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: In the server configuration screen msgid "Server Configuration" -msgstr "" +msgstr "Thiết Lập Máy Chủ" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: In the server configuration screen @@ -764,7 +770,7 @@ msgstr "Độ khó" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "Dễ" @@ -776,7 +782,7 @@ msgstr "Dễ" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "Vừa phải" @@ -788,7 +794,7 @@ msgstr "Vừa phải" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "Khó" @@ -800,18 +806,18 @@ msgstr "Khó" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" -msgstr "" +msgstr "SuperTux" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" -msgstr "" +msgstr "Chế độ trò chơi" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: Multiplayer game mode @@ -820,8 +826,8 @@ msgstr "" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "Chế Độ Thường" @@ -834,7 +840,7 @@ msgstr "Chế Độ Thường" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "Đua Thời Gian" @@ -842,46 +848,47 @@ msgstr "Đua Thời Gian" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" -msgstr "" +msgstr "Trận đánh" #. I18N: ./data/gui/dialogs/online/server_configuration_dialog.stkgui #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "Đá banh" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "Mật khẩu" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network msgid "Add player" -msgstr "" +msgstr "Thêm người chơi" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" -msgstr "" +msgstr "Tên" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network @@ -911,12 +918,12 @@ msgstr "" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Remove Friend" -msgstr "" +msgstr "Xóa bạn bè" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog msgid "Add Friend" -msgstr "" +msgstr "Thêm bạn bè" #. I18N: ./data/gui/dialogs/online/user_info_dialog.stkgui #. I18N: User info dialog @@ -973,6 +980,50 @@ msgstr "Đặt cho phím ESC" msgid "Assign nothing" msgstr "" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -987,11 +1038,11 @@ msgstr "Cài đặt vòng đua" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "Tiếp tục" @@ -1032,8 +1083,13 @@ msgstr "Đấu trường" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" +msgstr "Đã cài đặt" + +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" msgstr "" #. I18N: ./data/gui/screens/arenas.stkgui @@ -1045,20 +1101,20 @@ msgstr "" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "Chuẩn" @@ -1069,12 +1125,12 @@ msgstr "Chuẩn" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "Tiện Ích" @@ -1088,27 +1144,28 @@ msgstr "Tiện Ích" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "Tất cả" @@ -1147,12 +1204,12 @@ msgstr "" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" -msgstr "" +msgstr "Thêm" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item @@ -1186,7 +1243,7 @@ msgstr "" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "" @@ -1233,10 +1290,10 @@ msgstr "Chạy Ngược" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "" @@ -1268,9 +1325,9 @@ msgstr "" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1281,80 +1338,80 @@ msgstr "Đổi tên" msgid "Save Grand Prix" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "Giúp Đỡ SuperTuxKart" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "Chế độ trò chơi" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1362,56 +1419,57 @@ msgstr "" msgid "Story Mode" msgstr "Câu Chuyện" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "Tránh những quả chuối!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1419,14 +1477,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "Nếu bạn thấy một nút với chiếc chìa khóa như thế này, bạn cần hoàn tất một thử thách để mở khóa nó." -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1435,34 +1493,34 @@ msgid "" "carefully before!" msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1470,7 +1528,7 @@ msgid "" " leader will get you eliminated too!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1480,30 +1538,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1512,93 +1570,93 @@ msgid "" "wins the cup." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "Giác hút - ném thẳng để kéo đối phương lại, hay ném khi đang nhìn ra sau để làm tầm nhìn của một người bị che khuất." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "Dù - làm chậm tất cả các xe ở phía trước mình" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "Quả bóng rổ - nhảy sau người dẫn đầu, và có thể đè bẹp và làm chậm người chơi xuống đường đua." -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1607,7 +1665,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1615,20 +1673,20 @@ msgid "" " the cup and the more points it is worth." msgstr "" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1636,7 +1694,7 @@ msgid "" " resistant to explosions." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1644,7 +1702,7 @@ msgid "" " especially at low speeds." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1652,14 +1710,14 @@ msgid "" " top speed." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1667,12 +1725,12 @@ msgid "" "easier it is." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1682,7 +1740,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1692,12 +1750,12 @@ msgid "" "players and the server." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1707,7 +1765,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1727,7 +1785,7 @@ msgstr "" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "" @@ -1735,9 +1793,9 @@ msgstr "" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "Giải Đấu Grand Prix" @@ -1748,6 +1806,20 @@ msgstr "Giải Đấu Grand Prix" msgid "Choose a Kart" msgstr "Chọn nhân vật" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1761,11 +1833,11 @@ msgstr "" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "" @@ -1782,7 +1854,7 @@ msgstr "Hướng dẫn" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "" @@ -1790,7 +1862,7 @@ msgstr "" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "" @@ -1844,30 +1916,30 @@ msgstr "" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "" @@ -1893,9 +1965,9 @@ msgstr "" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "" @@ -1913,9 +1985,9 @@ msgstr "" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" -msgstr "" +msgstr "Bạn bè" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: In the profile screen @@ -1938,7 +2010,7 @@ msgstr "" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "" @@ -1988,8 +2060,8 @@ msgid "Online Username" msgstr "" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "" @@ -2002,7 +2074,7 @@ msgid "" msgstr "" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "" @@ -2020,339 +2092,409 @@ msgstr "" msgid "User search" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "Tùy Chỉnh SuperTuxKart" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "Đồ hoạ" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "Âm thanh" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "Người chơi" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "Điều khiển" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "Âm nhạc" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "Bật" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "Âm lượng" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "Hiệu Ứng Âm thanh" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "Xóa Thiết Lập" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "Quay về danh sách thiết bị" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "Độ phân giải" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "Toàn màn hình" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "Nhớ vị trí cửa sổ" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "Áp dụng độ phân giải mới" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" +msgid "Enable chatting in online lobbies" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" +msgid "Enable chatting in online matches" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "Nhấn phím enter hay click đôi chuột vào một thiết bị để cấu hình" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "Thêm một thiết bị" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "Giao Diện" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" +msgid "Skin variant" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" +msgid "Minimap" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "Hiển thị Số Khung Hình/Giây" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "Mức hiệu ứng đồ họa" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "Tùy chỉnh tự chọn..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "Độ phân giải" +msgid "Performance tests" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "Toàn màn hình" +msgid "Performance test of the current settings" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "Nhớ vị trí cửa sổ" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "Áp dụng độ phân giải mới" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2379,15 +2521,15 @@ msgstr "" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "Số người chơi máy" @@ -2402,31 +2544,15 @@ msgstr "" msgid "Random Grand Prix" msgstr "" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 -msgid "Login" -msgstr "" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" msgstr "" #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" +#. I18N: Used as a verb, appears on the main networking menu (login button) +#: src/states_screens/online/online_screen.cpp:69 +msgid "Login" msgstr "" #. I18N: ./data/tips.xml @@ -2547,238 +2673,306 @@ msgid "" msgstr "" #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" -msgstr "" +msgstr "Thành Phố Candela" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "Hòn Đảo Chiến Đấu" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "Hang X" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "Lâu Đài Cổ" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" -msgstr "" +msgstr "Đảo Gran Paradiso" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "Miền Viễn Tây" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" -msgstr "" +msgstr "Sân Bóng Đá Băng Giá" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "Sao thế, lũ híp pi kia? Thủ lĩnh gnu vĩ đại đã mất tích à?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "À đúng rồi, ông ta đang ở lâu đài của ta và sẽ được nấu thành bữa tối..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "Nếu ngươi có thể thắng ta ở đua xe, ta sẽ trả tự do cho lão già." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " Nhưng lũ vô dụng các ngươi sẽ không thể nào đánh bại được ta - Vua Đua Xe!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "Hầm mỏ" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "Lớp Toán của Oliver" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "Kim tự tháp Ai Cập" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "Núi Tuyết" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "Đỉnh Núi Tuyết" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" -msgstr "" +msgstr "Sân Bóng Đá" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "Viện Bảo Tàng" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" -msgstr "" +msgstr "Chùa" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" -msgstr "" +msgstr "Đảo Volcan" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "Hành Tinh XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "Vườn Hoa Anh Đào" @@ -2787,11 +2981,11 @@ msgstr "Vườn Hoa Anh Đào" msgid "Completed achievement \"%s\"." msgstr "" -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "" -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "" @@ -2857,7 +3051,7 @@ msgid "New kart '%s' now available" msgstr "Nhân vật mới '%s' đã có hiệu lực" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2889,32 +3083,32 @@ msgid "" "created." msgstr "Tập tin cấu hình của bạn đã quá cũ, do đó nó đã bị xóa và một cái mới sẽ được tạo ra." -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "" -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "" -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "Đang tải" @@ -2936,19 +3130,18 @@ msgstr "" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s đã sẵn sàng" @@ -3422,21 +3615,21 @@ msgid "Axis %d" msgstr "" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "Nút gamepad %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "Nút chuột %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "Mouse axis %d %s" @@ -3453,12 +3646,12 @@ msgstr "Tập tin cấu hình của bạn không tương thích với phiên b #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:159 msgid "Guide" -msgstr "" +msgstr "Chăn Đắt" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:161 msgid "Start" -msgstr "" +msgstr "Bắt Đầu" #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:163 @@ -3607,26 +3800,30 @@ msgstr "" msgid "+1 life." msgstr "" -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "Bạn đã hoàn thành cuộc đua!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "Bạn đã chiến thắng cuộc đua!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "" -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3635,16 +3832,16 @@ msgid "" "Internet\")." msgstr "" -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "" -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "" -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3652,38 +3849,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "" -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "" #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "" @@ -3693,7 +3890,7 @@ msgstr "" msgid "Eggs: %d / %d" msgstr "Trứng: %d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "Người dẫn đầu" @@ -3701,22 +3898,22 @@ msgstr "Người dẫn đầu" msgid "Final lap!" msgstr "Vòng cuối" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "Vòng Thứ %i" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s bởi %s" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "Vòng đua mới nhanh nhất" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "SAI ĐƯỜNG" @@ -3730,193 +3927,193 @@ msgstr "" msgid "Oops, %s made an own goal!" msgstr "" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "Bạn đã bị loại!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "'%s' đã bị loại." -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "" -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "" -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "" -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "" -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "" #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "" #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "" #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "" -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "" -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "" -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "" -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "" -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "" -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "" -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "" #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "" #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "" #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "" -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "" #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "" #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "" #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "" #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "" #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3924,15 +4121,15 @@ msgid "" msgstr "" #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "" #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3963,56 +4160,56 @@ msgstr "" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "" -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "" -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "" #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." msgstr[0] "" #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "" -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "" @@ -4041,12 +4238,12 @@ msgid "" msgstr "Tập tin Kỷ Lục đã quá cũ,\ntất cả các kỷ lục đã bị xóa." #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "Theo sau người dẫn đầu" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "Trận chiến 3 lần tấn công" @@ -4059,90 +4256,88 @@ msgstr "" msgid "Replay saved in \"%s\"." msgstr "" -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "Tên Tiện Ích" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "Ngày cập nhật" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s bởi %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "Xin vui lòng đợi khi các tiện ích bổ sung được cập nhật" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "Xin lỗi, có lỗi khi đang liên lạc với trang web chứa phần mở rộng. Bạn phải chắc là đã kết nối Internet và SuperTuxKart không bị khóa bởi tường lửa." -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "Bị khóa: hoàn thành thử thách để tham gia được nhiều vòng đua hơn!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "Đấu trường ngẫu nhiên" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "" - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nThanh Bách 6/1, 2022\nDawid Gan\nHuynh Yen Loc\nSTK-team\nVo Xuan Tien\nVõ Xuân Tiến\nZombifier" @@ -4430,7 +4625,7 @@ msgstr "" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "Trượt Bánh" @@ -4533,7 +4728,7 @@ msgstr "" msgid " (official tracks matching the goal)" msgstr "" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4541,91 +4736,95 @@ msgid "" msgstr "" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "Thêm Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "Thêm cấu hình bàn phím" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "Cập nhật" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "Phiên bản: %d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "Tính Năng" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "Kích thước: %s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "Xin lỗi, việc tải các tiện ích đã thất bại" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "Có lỗi khi cài đặt phần mở rộng '%s'" -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "Thử lại" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "Có lỗi khi gỡ bỏ phần mở rộng '%s'" -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "" @@ -4645,67 +4844,97 @@ msgstr "" #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "Tùy chọn" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "Tắt" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4713,7 +4942,7 @@ msgid "" msgstr "" #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4730,101 +4959,102 @@ msgstr "" msgid "Invalid server address: %s." msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(Trống)" @@ -4912,33 +5142,41 @@ msgid "Press any key..." msgstr "" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 -msgid "Back to Battle" +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" msgstr "" #: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +msgid "Back to Battle" +msgstr "" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "Vòng Đua Mới" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "Thoát vòng đua" @@ -4954,11 +5192,11 @@ msgstr "" msgid "%s is number %d in the rankings with a score of %f." msgstr "" -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "" -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4980,7 +5218,7 @@ msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "" @@ -4993,21 +5231,21 @@ msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "" @@ -5020,54 +5258,54 @@ msgstr "" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "Xếp hạng" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "" @@ -5080,74 +5318,74 @@ msgid "No player available for connecting to server." msgstr "" #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" -msgstr "" +msgstr "Yêu cầu kết bạn đã gửi!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" -msgstr "" +msgstr "Yêu cầu kết bạn đã chấp nhận" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" -msgstr "" +msgstr "Yêu cầu kết bạn đã từ chối" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" -msgstr "" +msgstr "Yêu cầu kết bạn đã hủy" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "" -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "Vòng đua ngẫu nhiên" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5176,7 +5414,7 @@ msgstr "" msgid "An error occurred while trying to save your grand prix." msgstr "" -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "" @@ -5220,12 +5458,12 @@ msgstr "Bạn đã mở khóa đường đua %0" msgid "You unlocked grand prix %0" msgstr "Bạn đã mở khóa giải đấu Grand Prix %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5246,19 +5484,19 @@ msgstr "" msgid "Please select a Grand Prix" msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "" -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "" @@ -5267,19 +5505,19 @@ msgstr "" msgid "Better luck next time!" msgstr "Chúc may mắn lần sau!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "Bạn đã hoàn thành một thử thách!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "Bạn đã hoàn thành giải Grand Prix!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "" @@ -5292,110 +5530,125 @@ msgstr "" msgid "Are you sure you want to remove all of your high scores?" msgstr "" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "Nhân vật ngẫu nhiên" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "Bị khóa" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "" -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "" -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "Phần Tiện Ích đã bị vô hiệu hóa trong màn hình Cài Đặt" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "Xin chờ trong khi tiện ích đang được tải" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5403,7 +5656,7 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "" @@ -5411,24 +5664,24 @@ msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "" -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5436,7 +5689,7 @@ msgstr[0] "" #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5444,96 +5697,108 @@ msgid_plural "" "Starting after %d seconds, or once everyone has pressed the 'Ready' button." msgstr[0] "" -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "" -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "" @@ -5611,34 +5876,34 @@ msgid "Distance (km)" msgstr "" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "" #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "" -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "" -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5646,149 +5911,149 @@ msgstr "" #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "Vô Hiệu Thiết Bị" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "Bật thiết bị" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "Phím trò chơi" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "Phím Trình Đơn" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "Rẽ Trái" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "Rẽ Phải" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "Tăng tốc" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "Bắn" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "Tăng Tốc" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "Nhìn sau" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "Cứu trợ" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "Tạm dừng" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "Lên" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "Xuống" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "Trái" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "Phải" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "Chọn" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "Hủy bỏ/Quay lại" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "* Mục có màu xanh nghĩa là mục đó xung đột với một tùy chỉnh khác" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5796,17 +6061,27 @@ msgid "" msgstr "" #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "Bạn có chắc bạn muốn xóa hoàn toàn thiết lập này?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "" +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5814,89 +6089,74 @@ msgstr "" #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "Bàn phím %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "Ngôn Ngữ Của Hệ Thống" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5906,128 +6166,133 @@ msgid "" msgstr "" #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "" #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "" -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "" #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "" @@ -6055,7 +6320,7 @@ msgstr "" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "" @@ -6090,7 +6355,7 @@ msgstr "" msgid "Top %i" msgstr "Đứng trong %i người dẫn đầu" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "Thử Thách Thất Bại" @@ -6114,102 +6379,199 @@ msgstr "" msgid "Press fire to start the challenge" msgstr "Nhấn 'bắn' để bắt đầu thử thách" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "Ngừng giải Grand Prix" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "Chơi lại" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "Quay về trình đơn chính" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "Bạn có thực sự muốn thoát Giải Đấu?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "Đã bị loại" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "Tiến trình Grand Prix:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "Điểm Cao" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "Tất cả các chiêu đòn đều được cho phép dùng, vậy hãy nhặt vũ khí và dùng chúng cẩn thận!" @@ -6250,28 +6612,28 @@ msgstr "" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "Được tạo bởi %s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "Bị khóa" @@ -6293,10 +6655,12 @@ msgid "%d/%m/%Y" msgstr "" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6305,41 +6669,48 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6347,34 +6718,41 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "Sử dụng hộp tăng tốc bạn đã thu thập bằng phím <%s>!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6382,24 +6760,27 @@ msgid "" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "Bạn đã sẵn sàng đua. Chúc may mắn!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "" @@ -6409,7 +6790,7 @@ msgstr "" msgid "tux;game;race;" msgstr "" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6417,7 +6798,7 @@ msgid "" "for all ages." msgstr "" -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6426,7 +6807,7 @@ msgid "" "your opponents." msgstr "" -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6435,27 +6816,27 @@ msgid "" "your racing skills!" msgstr "" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "" -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "" -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "" -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "" diff --git a/data/po/zh_CN.po b/data/po/zh_CN.po index 68e03c985f6..667d7578439 100644 --- a/data/po/zh_CN.po +++ b/data/po/zh_CN.po @@ -6,7 +6,7 @@ # Ben Au, 2015 # Benau, 2016,2019-2020 # Benau, 2015-2016 -# CodingJellyfish , 2018,2021-2024 +# CodingJellyfish , 2018,2021-2025 # Jiawei Sun, 2022 # 92373a9a734415f33212259453a6274d_77ab48e, 2022 # Jin Zhang , 2015,2019-2021,2023 @@ -17,9 +17,9 @@ msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: CodingJellyfish , 2018,2021-2024\n" +"Last-Translator: CodingJellyfish , 2018,2021-2025\n" "Language-Team: Chinese (China) (http://app.transifex.com/supertuxkart/supertuxkart/language/zh_CN/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -176,7 +176,7 @@ msgstr "天涯海角" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "后退" @@ -198,7 +198,7 @@ msgstr "选择一种您适合的操控方式" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "加速计" @@ -212,13 +212,13 @@ msgstr "加速计" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "陀螺仪" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "方向盘" @@ -249,35 +249,37 @@ msgstr "触屏设备设置" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "常规" @@ -345,30 +347,33 @@ msgstr "恢复默认" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "取消" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "是" @@ -389,12 +394,12 @@ msgstr "接受" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui msgid "Camera Settings" -msgstr "游戏视角设置" +msgstr "相机设置" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera settings msgid "Player camera" -msgstr "玩家视角" +msgstr "玩家相机" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -414,12 +419,12 @@ msgstr "俯仰角度" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen msgid "Smooth camera" -msgstr "平滑摄像机" +msgstr "平滑相机" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera settings msgid "Backward camera" -msgstr "后视摄像机" +msgstr "后视相机" #. I18N: ./data/gui/dialogs/custom_camera_settings.stkgui #. I18N: In the ui/camera screen @@ -438,7 +443,7 @@ msgstr "图像设置" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Advanced pipeline (lights, etc.)" -msgstr "高级管道设置(光线等)" +msgstr "高级渲染管线(光线等)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -448,7 +453,7 @@ msgstr "阴影" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Bloom" -msgstr "Bloom 效果" +msgstr "泛光" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -458,7 +463,7 @@ msgstr "光轴渲染(云隙光)" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Ambient occlusion" -msgstr "环境光吸收 " +msgstr "环境光遮蔽 " #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -473,7 +478,7 @@ msgstr "光辉(外框) " #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Anti-aliasing" -msgstr "反锯齿" +msgstr "抗锯齿" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -483,7 +488,7 @@ msgstr "动态模糊" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings msgid "Image-based lighting" -msgstr "基于图片的照明" +msgstr "基于图像的照明" #. I18N: ./data/gui/dialogs/custom_video_settings.stkgui #. I18N: Video settings @@ -546,9 +551,9 @@ msgstr "加入" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -609,7 +614,7 @@ msgstr "目标" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "进度" @@ -644,7 +649,7 @@ msgstr "送出" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "继续游戏" @@ -661,7 +666,7 @@ msgstr "回到大堂" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "重新开始游戏" @@ -725,12 +730,12 @@ msgstr "填写您在注册时提供的用户名和电子邮箱来重置密码。 #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "用户名" @@ -771,7 +776,7 @@ msgstr "难度" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "初级" @@ -783,7 +788,7 @@ msgstr "初级" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "中级" @@ -795,7 +800,7 @@ msgstr "中级" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "专家级" @@ -807,7 +812,7 @@ msgstr "专家级" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "超级企鹅级" @@ -815,8 +820,8 @@ msgstr "超级企鹅级" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "游戏模式" @@ -827,8 +832,8 @@ msgstr "游戏模式" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "正常比赛" @@ -841,7 +846,7 @@ msgstr "正常比赛" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "竞速模式" @@ -849,7 +854,8 @@ msgstr "竞速模式" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "对战" @@ -858,24 +864,24 @@ msgstr "对战" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "足球" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "密码" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "标记该服务器" @@ -886,7 +892,7 @@ msgstr "添加玩家" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "名称" @@ -980,6 +986,50 @@ msgstr "设置为 ESC 键" msgid "Assign nothing" msgstr "未指定" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -994,11 +1044,11 @@ msgstr "建立游戏" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "继续" @@ -1039,10 +1089,15 @@ msgstr "竞技场" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "已安装" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "收藏竞技场" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1052,20 +1107,20 @@ msgstr "已安装" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "标准" @@ -1076,12 +1131,12 @@ msgstr "标准" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "附加" @@ -1095,27 +1150,28 @@ msgstr "附加" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "所有" @@ -1154,9 +1210,9 @@ msgstr "下移" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "添加" @@ -1193,7 +1249,7 @@ msgstr "重播录像选择" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "收集彩蛋" @@ -1240,10 +1296,10 @@ msgstr "反向比赛" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "最大时间(分钟)" @@ -1275,9 +1331,9 @@ msgstr "复制" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1288,80 +1344,80 @@ msgstr "重命名" msgid "Save Grand Prix" msgstr "保存锦标赛" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "SuperTuxKart 帮助" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "游戏模式" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "道具" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "香蕉" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1369,56 +1425,57 @@ msgstr "香蕉" msgid "Story Mode" msgstr "剧情模式" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "赛车种类" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "多人游戏" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "开始教学关" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "收集蓝色礼盒,他们会助您一臂之力。" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "注意香蕉皮!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1426,14 +1483,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "收集氮气作为燃料,当您按下正确的按键使用它时,赛车可以得到很大的加速。您可以在屏幕右侧看到当前燃料的数量" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "如果您看到一个按钮带有像这样的锁的图标,您就必须要先完成其它一些挑战赛才能解锁它。" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1442,34 +1499,34 @@ msgid "" "carefully before!" msgstr "您可以通过按特殊键或按钮来漂移。 短距离的漂移有助于急转弯; 而中等长度的漂移将提高您的速度,长的更是如此。 在漂移时您不能停止转弯,所以您要小心地控制您的赛车!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "在“预备”显示时按加速按钮可以得到启动加速。" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "* 可以在“选项”菜单中查看/更改当前按键设置" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart 有多种游戏模式: " -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "常规比赛:所有道具都可用,合理使用它们会有意想不到的效果!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "竞速模式:该模式下没有道具,因此该模式将考验您的驾驶技术! " -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1477,7 +1534,7 @@ msgid "" " leader will get you eliminated too!" msgstr "跟紧老大:您至多只能跑到第二名,每隔一定时间最后一名会被淘汰掉。注意:如果您超过了老大,您也会被淘汰!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1487,30 +1544,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "有三种战斗模式:在三击对战中,您需要用武器打击其他人,直到他们失去所有生命为止。 在自由混战中,在次数或时间限制内击中其他人最多的玩家取胜。 在夺旗大战中,只要您的旗帜未被其他团队夺得,您的队伍就需要将其他队伍的旗帜带到您自己队伍的旗帜旁。" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "足球模式:把球推到对面的球门里来赢得分数。" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "收集彩蛋:在赛道里探险,找到所有的隐藏彩蛋。" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "重播录像:在竞速模式或收集彩蛋中与重播录像比赛,并录制自己的!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "圈数模式:在指定的时间内达到尽可能多的圈数。" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1519,93 +1576,93 @@ msgid "" "wins the cup." msgstr "* 这些游戏模式中的许多也可以以锦标赛的方式进行:您并非进行单一的比赛,而是连续进行许多比赛。排名越高,得分越多。最后,得分最多的玩家将赢得奖杯。" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "下面这些道具可以帮助您取得游戏的胜利:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "泡泡糖 - 用大泡泡来保护您,或者在向后看时用,在您身后留下一坨粘糊糊的、粉红色的恶心东西。" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "加速 - 会使您速度提升。 但要注意不要失去对赛车的控制!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "蛋糕 - 自动瞄准最近的敌人,适合于短距离或正前方的对手。它也会同时打击到其它靠近爆炸的车辆。" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "马桶揣子 - 向前发射可以把前面玩家向后拉,同时您也会得到加速;向后发射则可以把别人的视线挡住,让他们看不清方向。" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "保龄球 - 在击中车辆前一直向前滚动,碰到墙壁会反弹,在向后看的时候,保龄球可以向后发射。 " -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "降落伞 - 减慢您前方所有玩家的速度。" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "交换器 - 使得箱子和香蕉皮、氮气和泡泡糖在短时间内暂时交换。 " -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "篮球 - 跳向领先的玩家,并可能会压扁其他赛车让其减速。" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "苍蝇拍 - 会拍扁靠近的赛车,使它们减速,也可用于移除降落伞和炸弹。" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "碰到一个香蕉皮会导致下列其中一种东西施加到赛车上:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "锚 - 瞬间减慢赛车。 " -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "降落伞 - 减缓赛车的速度,但与锚相比作用更小。 您开得越快,它的作用就越强。" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "炸弹 - 经过一段时间后引爆,将赛车炸到空中。 撞上另一辆赛车会将其转移。" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "邪恶的Nolok抓走了Gnu! 这里有一些秘诀可以帮助您:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1614,7 +1671,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "这些小地图上的图标显示您可用但尚未完成的挑战赛。 在屏幕的右上角,它也会显示您目前有多少积分。 完成尽可能多的挑战赛,最终邪恶的Nolok将接受与您竞赛。取得胜利后将解放Gnu!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1622,20 +1679,20 @@ msgid "" " the cup and the more points it is worth." msgstr "完成一项挑战赛后,您会得到一个奖杯。 每个奖杯都相当于一些积分。 您完成的挑战赛难度越高,您就会取得更高级的奖杯,对应的分数就越多。" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "当您达到这个图标下面指示的点数时,我们为您准备了一份大大的惊喜!其中有许多不同的礼物。" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "并非所有的赛车都一样! 它们分别有以下几种不同的参数:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1643,7 +1700,7 @@ msgid "" " resistant to explosions." msgstr "质量 - 根据质量可将赛车分为轻,中,重三类。较重的赛车受降落伞影响较小,对爆炸的抵抗力更强。" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1651,7 +1708,7 @@ msgid "" " especially at low speeds." msgstr "加速 - 在发生事故,事故发生后或在有许多弯路的塞道上特别有用。 赛车越轻,加速越快,特别是在低速行驶时。" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1659,14 +1716,14 @@ msgid "" " top speed." msgstr "最高速度 - 最高速度越高,赛车越快。 在直线和幅度较小的弯路中更加有用。 较重的赛车一般具有更高的最高速度。" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "氮气效率 - 氮气效率越高,使用一瓶氮气就可以得到更多的加速。 较轻赛车的氮气效率更高。" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1674,12 +1731,12 @@ msgid "" "easier it is." msgstr "如果您紧跟另一个赛车几秒钟,您将得到一个加速奖励。 您的赛车越轻,就越容易做到。" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart 支持在线上进行多人游戏 :" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1689,7 +1746,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "首先,选择主菜单中的“在线”图标。 选择本地网络或全局网络(需要在选项中启用互联网)。 然后,您可以使用自定义选项创建自己的服务器,也可以在要加入的现有服务器列表中进行搜索。 其中一些是推荐的服务器,可选择排名比赛。 " -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1699,12 +1756,12 @@ msgid "" "players and the server." msgstr "在服务器上,所有者(以皇冠标记)决定比赛的开始。官方服务器在有足够玩家的情况下可能会自动开始比赛。然后,您可以选择赛车并投票选择下一条赛道。附加赛道只有在所有玩家以及服务器都安装的情况下才可以选择。" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "…或者在同一台设备上:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1714,7 +1771,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "要进行多人游戏,,首先您需要多个输入设备。在输入选项中设置游戏手柄。多个游戏手柄或操纵杆是最理想的选择。您也可以只使用键盘进行多人游戏,但是每个玩家的按键设置不能有重复的按键,而且大多数键盘支持同时按下的按键数有限,因此不适于多人游戏。" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1734,7 +1791,7 @@ msgstr "高分选择" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "圈数模式" @@ -1742,9 +1799,9 @@ msgstr "圈数模式" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "锦标赛" @@ -1755,6 +1812,20 @@ msgstr "锦标赛" msgid "Choose a Kart" msgstr "选择赛车" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "赛车种类" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "收藏赛车" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1768,11 +1839,11 @@ msgstr "分屏多人游戏" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "在线" @@ -1789,7 +1860,7 @@ msgstr "教学关" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "高分" @@ -1797,7 +1868,7 @@ msgstr "高分" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "成就" @@ -1851,30 +1922,30 @@ msgstr "寻找服务器" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "建立服务器" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "大堂" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "设置" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "开始游戏" @@ -1900,9 +1971,9 @@ msgstr "输入服务器地址" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "个人档案" @@ -1920,7 +1991,7 @@ msgstr "玩家排名" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "好友" @@ -1945,7 +2016,7 @@ msgstr "快速游戏" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "帐号设置" @@ -1995,8 +2066,8 @@ msgid "Online Username" msgstr "在线用户名" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "重设密码" @@ -2009,7 +2080,7 @@ msgid "" msgstr "您可以选取离线帐号以避免在要游玩时建立在线帐号。虽然这样您就无法与朋友连线,为附加组件投票等。请到 https://privacy.supertuxkart.net 详阅我们的隐私政策。" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "选择服务器" @@ -2027,339 +2098,409 @@ msgstr "使用IPv6连接" msgid "User search" msgstr "用户搜索" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "SuperTuxKart 选项" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "显示" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "图像" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "音频" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "界面" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "玩家" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "操控" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "语言" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "音乐" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "已启用" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "音量" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "音效" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "删除按键设置" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "取消按键设置" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "返回设备列表" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "重命名配置" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "启用强制反馈(仅支持)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "分辨率" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "全屏幕" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "保存窗口位置" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "使用新的分辨率" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "分屏方式" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "互联网设置" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "总是显示登录界面" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "连接网络" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "开启网上聊天" +msgid "Enable chatting in online lobbies" +msgstr "在游戏大堂中开启聊天" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "在游戏中开启聊天" +msgid "Enable chatting in online matches" +msgstr "在比赛中开启聊天" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "杂项" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "开启每个玩家的让赛功能" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "卸载完整游戏组件" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "按回车或双击一个设备来配置它" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "添加设备" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "※ 使用何种设定将会由加入游戏时所按下的“选择”键来推断。" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "皮肤" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "小地图" +msgid "Skin variant" +msgstr "配色" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "分屏方式" +msgid "Minimap" +msgstr "小地图" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "字体大小" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" -msgstr "视角" +msgstr "相机" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "自定义…" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "显示帧速率" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "显示其他玩家的道具" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "开启故事模式计时器" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "开启竞速计时器" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "渲染分辨率" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "图形特效等级" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "模糊等级" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "最大 FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "自定义设置..." -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "分辨率" +msgid "Performance tests" +msgstr "性能测试" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "全屏幕" +msgid "Performance test of the current settings" +msgstr "性能测试" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "保存窗口位置" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "记住密码" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "使用新的分辨率" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "删除" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "赛车颜色" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2386,15 +2527,15 @@ msgstr "蓝队" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "圈数" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "电脑玩家数量" @@ -2409,33 +2550,17 @@ msgstr "蓝队电脑玩家数量" msgid "Random Grand Prix" msgstr "随机锦标赛" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "收藏赛道" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "登录" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "记住密码" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "删除" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "赛车颜色" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "可以在“选项”菜单中更改皮肤。" @@ -2554,238 +2679,306 @@ msgid "" msgstr "当您的队友带球的时候,避免干扰其前进的路线。您可以使用道具防止对手得分。" #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "史前深渊" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "外星讯号" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "上古迷宫" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "坎德拉城" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "战斗之岛" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "黑森林" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "X洞穴" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "可可寺院" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "飘香田野" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "熔岩城堡" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "大帕拉迪索岛" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "大庄园" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "纽扣球场" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "冰雪球场" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "怎么了,小家伙?你的伟大的 GNU 领导不见了?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "没错,你看,他正在我的城堡里,即将被当成晚餐..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "但是我是很公平的,所以我跟你打个赌。" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "如果你能在赛车上赢过我,我就会把那老家伙放了" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " 不过你们这些可怜的小蠢货是永远不可能打败我这个赛车之王的!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "沙墩竞技场" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "沙墩球场" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "灯塔海岸" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "老矿井" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "迷你高尔夫球场" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "绿洲球场" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "奥利弗的学堂" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "南瓜公园" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "渡鸦公馆" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "漂移沙漠" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "水怪之潭" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "北国风光" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "积雪顶峰" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "经典球场" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "体育场" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK 企业号" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "寺院" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "火山之岛" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "禅宗花园" @@ -2794,11 +2987,11 @@ msgstr "禅宗花园" msgid "Completed achievement \"%s\"." msgstr "已完成成就 “%s”。" -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "无法连接到 SuperTuxKart 附加组件服务器。" -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "下载新闻出错:“%s”。" @@ -2864,7 +3057,7 @@ msgid "New kart '%s' now available" msgstr "已解锁新的赛车:%s" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2896,32 +3089,32 @@ msgid "" "created." msgstr "您的配置文件太旧了,新的配置文件已经创建。" -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "视频录制开始。" -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "视频已保存到 \"%s\"。" -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "编码进度:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS: %d/%d/%d - %d KTris, Ping: %d毫秒" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "小窍门:%s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "正在读取" @@ -2943,19 +3136,18 @@ msgstr "氮气消耗" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s(让赛)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s 准备好了" @@ -3429,21 +3621,21 @@ msgid "Axis %d" msgstr "轴 %d" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "手柄按钮 %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "鼠标按钮 %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "鼠标轴 %d %s" @@ -3614,26 +3806,30 @@ msgstr "您最多可以有 3 条命! " msgid "+1 life." msgstr "+1 条命" -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "您太慢了!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "恭喜您完成比赛!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "恭喜您赢得了比赛!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "恭喜您以第 %d 名完成比赛!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s 离开了游戏。" -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3642,16 +3838,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart可能会连接到服务器下载附加组件并通知您最近的更新。请到 https://supertuxkart.net/Privacy 详阅我们的隐私政策。您想启用这个功能吗?(您稍后可以在设置中更改设定:请​​到选项中,选择“常规”页面,并编辑“连接到网络”)" -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "您的屏幕分辨率太低, 无法运行 STK。" -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "您的驱动太旧,请安装最新的显卡驱动。" -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3659,38 +3855,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "您的显卡驱动似乎太旧了,请检查可用的更新。SuperTuxKart 需要支持 %s 或更新的版本的驱动。此游戏可能仍然会正常运作,不过图形效果会减弱。" -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "连接超时" #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "红旗被 %s 夺走!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "红旗已归位!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "蓝旗被 %s 夺走! " #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "蓝旗已归位! " -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s 夺得蓝旗!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s 夺得红旗!" @@ -3700,7 +3896,7 @@ msgstr "%s 夺得红旗!" msgid "Eggs: %d / %d" msgstr "彩蛋:%d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "领跑" @@ -3708,22 +3904,22 @@ msgstr "领跑" msgid "Final lap!" msgstr "最后一圈!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "第 %i 圈" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s 由 %s 创造" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "新的最快圈速:" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "您走反了!" @@ -3737,209 +3933,209 @@ msgstr "%s进了一球!" msgid "Oops, %s made an own goal!" msgstr "不好,%s进了一个乌龙球。" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "已生成 %i 辆备胎车!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "您被淘汰了!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "%s 被淘汰了。" -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "服务器已关闭。" -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "您已被踢出服务器。" -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "您已被踢出:Ping 过高" -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "检测到网络异常。" -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "机器人" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s 已离线。" #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "在玩家名单中点击玩家以管理此玩家和查看此玩家排名" #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "难度:%s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "最大人数:%d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "游戏模式:%s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "时间限制" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "得分限制" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "球赛类型:%s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "锦标赛进度:%d/%d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "所有玩家都加入了红或蓝队。" #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "您现在是服务器的房主。" -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "连接被拒绝:服务器繁忙。" -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "连接被拒绝:您已被服务器禁止。" -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "连接被拒绝:错误的服务器密码。" -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "连接被拒绝:游戏数据不兼容。" -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "连接被拒绝:服务器已满。" -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "连接被拒绝:无效的连接。" -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "开始在线游戏失败。" #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "此游戏已结束,您不能继续加入或观赛。" #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "竞技场中没有剩余位置-实时连接已禁用。 " #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "只剩下一名玩家,正在返回大堂。 " -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "服务器所有者退出了游戏" #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "您将观看下一场比赛" #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s 加入了红队。" #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s 加入了蓝队。" #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s 加入了游戏。" #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " "camera position." -msgstr "按下%s或%s更改摄像机跟随着的目标赛车,按下%s或%s改变摄像机的位置。" +msgstr "按下%s或%s切换目标赛车,%s或%s切换相机位置。" #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "成功举报玩家 %s 。" #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3970,56 +4166,56 @@ msgstr "竞速模式(锦标赛)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "自由混战" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "夺旗大战" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s 当前在线。" -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s 和 %s 当前在线。" -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s, %s 和 %s 当前在线。" #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." msgstr[0] "现在有 %d 位朋友在线。" #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s 现在在服务器 “%s” 上。" -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "您有 %d 个新的朋友请求!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "您有一个新的朋友请求!" @@ -4048,12 +4244,12 @@ msgid "" msgstr "高分榜文件过旧,\n将会被清除。" #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "跟紧老大" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "三击对战" @@ -4066,90 +4262,88 @@ msgstr "未完整的重播录像不会被储存。" msgid "Replay saved in \"%s\"." msgstr "已储存重播录像在 \"%s\" 。" -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "1 星期" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 星期" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "1 个月" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 个月" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 个月" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 个月" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "1 年" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 年" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "附加组件名称" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "更新日期" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "未安装" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s 作者 %s" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "附加组件正在更新,请稍候" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "很抱歉,在连接到附加组件网站的过程中出现了错误。请确保您已经连接上网络,并且 SuperTuxKart 没有被防火墙拦截。" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "收藏" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "该挑战赛已被锁定:请先完成其它挑战赛!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "随机竞技场" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d 个竞技场在单人游戏中不适用。" - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nBen Au, 2015\nBenau, 2016,2019-2020\nBenau, 2015-2016\nCodingJellyfish, 2018,2021-2022\nJiawei Sun, 2022\nJin Zhang, 2015,2019-2021\nJz Pan, 2017\nCodingJellyfish, 2018-2019\nCodingJellyfish, 2018\nCodingJellyfish, 2021\nDawid Gan\nSTK-team\nSizhuang Liu\nXhacker Liu\nacme_pjz\njin\nlks\nluojie-dune\nsohey\ndumaosen" @@ -4437,7 +4631,7 @@ msgstr "踩中香蕉数量" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "漂移" @@ -4540,7 +4734,7 @@ msgstr "完成收集彩蛋 " msgid " (official tracks matching the goal)" msgstr "(与任务对应的官方赛道)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4548,91 +4742,95 @@ msgid "" msgstr "当您连接新的游戏手柄和操纵杆到此设备时,它们会自动显示在列表中。\n\n要添加键盘配置,可以使用下面的按钮。但是请注意,大多数键盘支持同时按键的数量有限制,因此不适合于多人游戏。不过您可以连接多个键盘到此设备。请记住,在这种情况下,每个人仍然需要绑定不同的按键。" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "添加 Wiimote" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "添加键盘按键设置" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "更新" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "版本:%d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "精华" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "大小:%s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "您须登录以对此评分。" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "抱歉,附加组件下载失败" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "在安装附加组件 “%s” 时遇到问题。" -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "重试" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "在移除附加组件 “%s” 时遇到问题。" -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "背景下载完成。" -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "背景下载" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "背景下载已经开始。" -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "当前密码错误" -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "密码须为 8 到 30 个字符!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "输入的密码不匹配!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "验证资料" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "密码成功更改" @@ -4652,67 +4850,97 @@ msgstr "不支持低于1024x768或1280x720的分辨率。画面的一些部分 #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "无人机跟随" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "自定义" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "已禁用" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "只有重要的" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "非常低" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "低" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "中" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "高" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "极高" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "最高" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4720,7 +4948,7 @@ msgid "" msgstr "为了更好的游戏体验,SuperTuxKart会下载全部游戏资源(包括高质量的纹理和音乐)。如果您没有连接WiFi网络,这会使用您的移动数据流量。" #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4737,101 +4965,102 @@ msgstr "输入服务器的地址(可以在最后加上 : 和端口号),或 msgid "Invalid server address: %s." msgstr "无效的服务器地址:%s。" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "反向比赛" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "难度" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "圈数" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "时间" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "赛车" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "用户" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "版本" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "否" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "赛道" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "前 %d 高分" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s:%s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "赛车数量:%d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "时间目标:%s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "圈数:%d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "反向:%s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(无)" @@ -4919,33 +5148,41 @@ msgid "Press any key..." msgstr "请按任意键... " #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "聊天功能已被禁用,请将其在选项中开启。" -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "返回性能测试" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "退出性能测试" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "继续对战" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "开始新游戏" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "重新开始对战" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "退出对战" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "开始新游戏" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "退出比赛" @@ -4961,11 +5198,11 @@ msgstr "%s 尚未有排名。" msgid "%s is number %d in the rankings with a score of %f." msgstr "玩家 %s 是第 %d 名且已获得 %f 分。" -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "用户名及/或电子邮箱位置无效。" -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4987,7 +5224,7 @@ msgstr "重播录像比赛" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "圈数:%i" @@ -5000,21 +5237,21 @@ msgstr "类型:%s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "需要排名:%i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "需要时间:%i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "需要的氮气点数:%i" @@ -5027,54 +5264,54 @@ msgstr "电脑玩家数量:%i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "对战模式" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "球赛类型" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "服务器所在地:%s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "目前赛道:%s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "排名" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "玩家" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "分数" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "游戏时间" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "取消标记" @@ -5087,74 +5324,74 @@ msgid "No player available for connecting to server." msgstr "没有可用于连接服务器的玩家。" #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "玩家名:%s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "取消请求" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "今日" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "好友请求已发送!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "好友请求已接受!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "拒绝好友请求!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "删除好友!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "好友请求已取消!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "处理中" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "正在取得最后的投票" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "您可以点击下方的星星以修改先前的评分等级。" -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "您尚未对此附加组件投票。您可以点击下方的星星以选取您想要的评分等级" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "投票成功!您现在可以关掉窗口了。" -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "进行投票" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "随机赛道" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5183,7 +5420,7 @@ msgstr "%s(+)" msgid "An error occurred while trying to save your grand prix." msgstr "保存您的锦标赛的过程中出现一个错误。" -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "选择赛道" @@ -5227,12 +5464,12 @@ msgstr "您解锁了赛道 %0" msgid "You unlocked grand prix %0" msgstr "您解锁了锦标赛 %0" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "赛道" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5253,19 +5490,19 @@ msgstr "请输入锦标赛的名称" msgid "Please select a Grand Prix" msgstr "请选择一个锦标赛" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "用户定义" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "名称是空的。" -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "该锦标赛名称已被使用。" -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "名称太长" @@ -5274,19 +5511,19 @@ msgstr "名称太长" msgid "Better luck next time!" msgstr "希望您下次运气好一些!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "您完成了一项挑战赛!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "您赢得了锦标赛!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "恭喜您完成锦标赛!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "赛车数量" @@ -5299,110 +5536,125 @@ msgstr "您确定要移除此高分吗?" msgid "Are you sure you want to remove all of your high scores?" msgstr "您确定要移除所有高分吗?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "收藏" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "轻型" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "重型" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "连接键盘或游戏手柄玩多人分屏游戏" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "随机赛车" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "已锁定" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "各位玩家:\n请按“选择”键加入游戏!" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "请问您想开始游戏的教学吗?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "您无法在没有网络连接时玩在线游戏。如果您想玩在线游戏,到​​“用户界面”页面中编辑“连接网络”选项。" -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "您无法在没有网络连接时下载附加组件。如果您想下载附加组件,到​​“用户界面”页面中编辑“连接网络”选项。" -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "您无法在没有网络连接时下载附加组件。如果您想下载附加组件,到​​“用户界面”页面中编辑“连接网络”选项。\n\n但是您可以删除已安装的附加组件。" -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "附加组件功能被禁用,请在“选项”界面中修改" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "附加组件正在加载,请稍候" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "您确定要退出游戏吗?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "创建本地服务器" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "%s 的服务器" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "锦标赛赛道数量" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "名称须为 4至 30 个字符!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "密码中出现非法字符!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "各就各位" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "实时连接" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "观赛" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "安装附加组件" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5410,7 +5662,7 @@ msgstr "请等待此游戏的(%s)结束,剩余时间:%s 。" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "请等待此游戏结束,大致剩余时间:%s 。" @@ -5418,24 +5670,24 @@ msgstr "请等待此游戏结束,大致剩余时间:%s 。" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "请等待此游戏的(%s)结束,大致进度:%s %。" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "请等待此游戏结束,大致进度:%d%。" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "请等待此游戏结束。" -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5443,7 +5695,7 @@ msgstr[0] "游戏将在人数大于 %d 后开始。" #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5451,96 +5703,108 @@ msgid_plural "" "Starting after %d seconds, or once everyone has pressed the 'Ready' button." msgstr[0] "在 %d 秒后开始,或所有人都已按下了“开始”键。" -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "正在连接服务器 %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "正在寻找合适的服务器" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "剩余时间:%d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "任务" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "正在取得成就" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "%s 的个人档案" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "添加时间" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "状态" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "正在取得好友" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "新请求" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "等待处理中" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "离线" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "在下方输入新邮箱" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "新电子邮箱须为 5 至 254 个字符!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "新电子邮箱不可用!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "邮箱修改成功!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "邮箱修改失败:%s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "新闻列表" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "日期" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "暂无新闻" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "您必须在登录后在全球网络中游戏。请点击上面的用户名。" -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "搜索中" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "退出比赛" @@ -5618,34 +5882,34 @@ msgid "Distance (km)" msgstr "距离(千米)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "未知" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "没有检测到IPv4,您可能无法加入到任何服务器。" #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "没有检测到IPv6,您可能无法加入到任何服务器。" -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "无可用服务器。" -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "正在取得服务器" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "服务器标记" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5653,149 +5917,149 @@ msgstr "如果绝大多数玩家选择同样的赛道和选项,投票就会提 #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "随机物品位置" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "还需赢得的目标数" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "反向驾驶" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "已锁定:请先完成其它挑战赛!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "行动" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "按键设置" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "禁用设备" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "开启设备" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "开启按键设置" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "游戏键位" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "菜单键" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "左转" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "右转" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "加速" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "刹车/后退" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "开火" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "氮气" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "向后看" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "自杀" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "暂停游戏" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "上" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "下" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "左" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "右" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "选择" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "取消/返回" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "※ 蓝色表示与另一个按键设置冲突" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "※ 红色表示与另一个设置存在冲突" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5803,17 +6067,27 @@ msgid "" msgstr "注意:不建议使用“Shift”键。当 Shift 按下时,所有字母键会变换大小写,因而无法使用。" #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "您确定要永久删除这个按键设置吗?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "输入新的配置名称,留空使用默认值。" +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "竖向分屏" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "横向分屏" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5821,89 +6095,74 @@ msgstr "在多人模式中,玩家可以在赛车选取画面中选取让赛( #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "下载完整游戏组件" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "您确定要卸载完整游戏组件?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "键盘 %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "触屏设备" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "点击一个设备来配置它" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "使用系统语言" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "左下角" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "右侧" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "隐藏" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "居中" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "竖向分屏" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "横向分屏" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "极小" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "小" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "中" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "大" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "极大" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5913,128 +6172,133 @@ msgid "" msgstr "竞速计时模式只有在故事模式一直开启时才会开启它。\n在故事模式未结束时关闭游戏将重置计时器。\n如果要使用竞速计时模式,请使用新的个人档案。 " #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "垂直同步" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "垂直同步将强制您的显卡在显示器准备好时再提供一帧画面。" #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "垂直同步在驱动不支持时将停止工作。" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "粒子效果:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "角色动画:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" -msgstr "动态光照:%s" +msgstr "高级渲染管线:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "光散射:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" -msgstr "反锯齿:%s" +msgstr "抗锯齿:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" -msgstr "环境光吸收:%s" +msgstr "环境光遮蔽:%s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "阴影:%s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "阴影:%i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" -msgstr "Bloom 效果:%s" +msgstr "泛光:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "光辉(外框):%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "光轴渲染(云隙光):%s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "渲染图像质量:%s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "几何细节:%s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "动态模糊:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "景深:%s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "网络连接被禁用,是否启用它 ?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "您必须输入密码。" -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "正在退出 “%s”" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "正在登录 “%s”" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "您不能删除唯一的玩家。" #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "您确定要删除玩家 “%s” ? " @@ -6062,7 +6326,7 @@ msgstr "进球!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "等待对方中" @@ -6097,7 +6361,7 @@ msgstr "跟紧老大!" msgid "Top %i" msgstr "前 %i 名" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "挑战赛失败" @@ -6121,102 +6385,199 @@ msgstr "点击颁奖图标开始挑战" msgid "Press fire to start the challenge" msgstr "按下开火键开始挑战" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "返回图像设置" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "保存测试结果" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "返回主菜单" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "退出服务器" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "放弃锦标赛" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "重新开始" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "回到挑战赛选择画面" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "与重播录像进行比赛" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "返回主菜单" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "您真的要退出锦标赛吗?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "已储存测试结果在 \"%s\" 。" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "红队取胜" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "蓝队取胜" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "平局" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "在 %s 后淘汰" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "被淘汰" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(乌龙球)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "赛道 %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "锦标赛进度:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "高分榜" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "最佳单圈成绩:%s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "由 %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "您完成了挑战!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "您挑战失败了!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "完成了神秘任务,达成SuperTux" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "性能测试结果" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "测试时间:%s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "总帧数:%s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "保证值 FPS:%s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "稳定值 FPS:%s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "典型值 FPS:%s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "横向分辨率:%s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "纵向分辨率:%s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "高级渲染管线:开启" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "高级渲染管线:关闭" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "渲染分辨率:%s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "抗锯齿:开启" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "抗锯齿:关闭" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "基于图像的照明:关闭" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "基于图像的照明:开启" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "环境光遮蔽:开启" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "环境光遮蔽:关闭" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "阴影映射分辨率:%s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "所有道具都可用,合理使用它们会有意想不到的效果哦!" @@ -6257,28 +6618,28 @@ msgstr "选择红色或蓝色足球图标可改变队伍" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "%s 设计的赛道" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "最大玩家支持数目:%d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "红队电脑玩家数量" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "您无法参加此锦标赛,因为有未解锁的赛道。" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "已锁定!" @@ -6300,10 +6661,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "大门会在完成所有的挑战赛后打开!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6312,41 +6675,48 @@ msgid "" msgstr "您需要更多的点数\n来进入这个挑战赛!\n在小地图上检查\n可用的挑战赛。" #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "按下 <%s> 键加速,<%s> 和 <%s> 控制方向。" #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "按下方向盘前端加速,向左右转动以控制方向。" #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "向前推变速杆加速,倾斜以转向。" #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "向前推变速杆加速,旋转设备以控制方向。" #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "收集礼物箱并使用<%s>键来开火,并将这些箱子撞飞!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "收集礼物箱并按下保龄球图标来开火,并将这些箱子撞飞!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6354,34 +6724,41 @@ msgid "" msgstr "按下<%s>向后看。\n按下<%s>开火,同时按下<%s>可以向后开火。" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "按下“后视镜”图标向后看。\n保持按下“后视镜”图标的同时用手指滑到“保龄球”图标可以向后开火!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "按下 <%s> 来使用收集到的氮气" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "按下氮气罐图标以使用收集到的氮气 " #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "收集氮气瓶(转弯后将会用上)。" #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "哎呀呀!当您被困住了,按 <%s> 可以恢复哦。" #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "哎呀呀!当您被困住了,按左上角的蓝鸟图标可以恢复哦。" #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6389,24 +6766,27 @@ msgid "" msgstr "转弯时可以按住加速键并按住<%s>实现漂移\n短时间漂移可以帮助您快速过弯。" #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "转弯时可以按住加速键并按住“漂移”图标实现漂移\n短时间漂移可以帮助您快速过弯。" #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "如果您成功漂移数秒,将会得到一个加速奖励哦!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "您现在已准备好开始比赛了。祝您好运!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "一个三维开源赛车游戏" @@ -6416,7 +6796,7 @@ msgstr "一个三维开源赛车游戏" msgid "tux;game;race;" msgstr "企鹅、游戏、赛车" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6424,7 +6804,7 @@ msgid "" "for all ages." msgstr "引擎轰鸣,燃气喷涌,正是赛车启动时!SuperTuxKart 是一款开源的三维街机赛车游戏,内含多种角色、赛道和游戏模式。我们的目标是创造一款比现实世界的卡丁车更有趣的、老少皆宜的游戏。" -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6433,7 +6813,7 @@ msgid "" "your opponents." msgstr "我们有很多不同主题的赛道,您可以在水下、农场、丛林,甚至在太空中比赛!尽你最大的努力,同时在超车的时候避免相撞,记住不要吃到香蕉!注意对手扔的保龄球、马桶揣子、泡泡糖和蛋糕。" -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6442,27 +6822,27 @@ msgid "" "your racing skills!" msgstr "您可以和其它赛车一起比赛;参加锦标赛;试着在竞速模式中获得更高的分数;和电脑或者您的朋友玩战斗模式;此外还有更多有趣的东西等待您去发现。如果您想要更高的挑战,去在线和来自世界各地的玩家一起比赛吧,来证明您的赛车技术!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "本游戏不含广告。" -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "此为SuperTuxKart的开发版,包含最新的改进。这一版本主要用来测试一些新的特性,以确保其进入稳定版本前得到足够的测试。" -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "在同一设备上可以同时安装这一版本和稳定版本。" -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "如果您注重稳定性,请考虑使用此稳定版本:%s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "SuperTuxKart开发团队" diff --git a/data/po/zh_TW.po b/data/po/zh_TW.po index bc17fbbad0f..7791de981b4 100644 --- a/data/po/zh_TW.po +++ b/data/po/zh_TW.po @@ -13,14 +13,14 @@ # 黃柏諺 , 2015,2017-2019 # pan93412 , 2018 # V字龍(Vdragon) , 2015 -# 黃柏諺 , 2019-2023 +# 黃柏諺 , 2019-2024 msgid "" msgstr "" "Project-Id-Version: SuperTuxKart\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-16 01:41+0800\n" +"POT-Creation-Date: 2024-10-29 22:11+0100\n" "PO-Revision-Date: 2015-02-15 01:58+0000\n" -"Last-Translator: 黃柏諺 , 2019-2023\n" +"Last-Translator: 黃柏諺 , 2019-2024\n" "Language-Team: Chinese (Taiwan) (http://app.transifex.com/supertuxkart/supertuxkart/language/zh_TW/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -177,7 +177,7 @@ msgstr "在世界的盡頭" #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: name of buttons on gamepads #: src/input/gamepad_config.cpp:157 -#: src/states_screens/dialogs/addons_loading.cpp:303 +#: src/states_screens/dialogs/addons_loading.cpp:320 msgid "Back" msgstr "返回" @@ -199,7 +199,7 @@ msgstr "選取您偏好的控制類型" #. I18N: Control type #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#: src/states_screens/dialogs/race_paused_dialog.cpp:549 +#: src/states_screens/dialogs/race_paused_dialog.cpp:572 msgid "Accelerometer" msgstr "加速計" @@ -213,13 +213,13 @@ msgstr "加速計" #. I18N: Race paused button #. I18N: ./data/gui/dialogs/race_paused_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:554 +#: src/states_screens/dialogs/race_paused_dialog.cpp:577 msgid "Gyroscope" msgstr "陀螺儀" #. I18N: ./data/gui/dialogs/android/init_android.stkgui #. I18N: Control type -#: src/states_screens/dialogs/race_paused_dialog.cpp:544 +#: src/states_screens/dialogs/race_paused_dialog.cpp:567 msgid "Steering wheel" msgstr "方向盤" @@ -250,35 +250,37 @@ msgstr "觸控裝置設定" #. I18N: ./data/gui/dialogs/android/multitouch_settings.stkgui #. I18N: In the multitouch settings screen -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "General" msgstr "一般" @@ -346,30 +348,33 @@ msgstr "恢復預設值" #. I18N: Splitscreen player in network #. I18N: ./data/gui/dialogs/press_a_key_dialog.stkgui #. I18N: When configuring input +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/dialogs/add_device_dialog.cpp:125 -#: src/states_screens/dialogs/addons_loading.cpp:222 -#: src/states_screens/dialogs/addons_pack.cpp:133 -#: src/states_screens/dialogs/download_assets.cpp:179 +#: src/states_screens/dialogs/add_device_dialog.cpp:101 +#: src/states_screens/dialogs/addons_loading.cpp:229 +#: src/states_screens/dialogs/addons_pack.cpp:138 +#: src/states_screens/dialogs/download_assets.cpp:184 #: src/states_screens/online/register_screen.cpp:168 -#: src/states_screens/options/user_screen.cpp:128 +#: src/states_screens/options/user_screen.cpp:115 msgid "Cancel" msgstr "取消" #. I18N: ./data/gui/dialogs/confirm_dialog.stkgui #. I18N: In a 'are you sure?' dialog -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 +#: src/states_screens/dialogs/recommend_video_settings.cpp:61 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "Yes" msgstr "是" @@ -547,9 +552,9 @@ msgstr "加入" #. I18N: ./data/gui/screens/edit_track.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/dialogs/message_dialog.cpp:127 #: src/states_screens/dialogs/message_dialog.cpp:138 @@ -610,7 +615,7 @@ msgstr "目標" #. I18N: ./data/gui/dialogs/online/achievement_progress_dialog.stkgui #. I18N: Progress shown in achievement dialog #. I18N: Progress in achievement -#: src/states_screens/online/online_profile_achievements.cpp:85 +#: src/states_screens/online/online_profile_achievements.cpp:87 msgid "Progress" msgstr "進度" @@ -645,7 +650,7 @@ msgstr "送出" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:143 +#: src/states_screens/dialogs/race_paused_dialog.cpp:150 msgid "Back to Race" msgstr "回到比賽" @@ -662,7 +667,7 @@ msgstr "回到大廳" #. I18N: ./data/gui/dialogs/online/network_ingame_dialog.stkgui #. I18N: Race paused button -#: src/states_screens/dialogs/race_paused_dialog.cpp:148 +#: src/states_screens/dialogs/race_paused_dialog.cpp:155 msgid "Restart Race" msgstr "比賽重來" @@ -726,12 +731,12 @@ msgstr "填入您在註冊時使用的使用者名稱及電子郵件地址以重 #. I18N: ./data/gui/dialogs/online/recovery_input.stkgui #. I18N: In the recovery dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:72 -#: src/states_screens/online/online_user_search.cpp:71 +#: src/states_screens/online/online_profile_friends.cpp:77 +#: src/states_screens/online/online_user_search.cpp:76 msgid "Username" msgstr "使用者名稱" @@ -772,7 +777,7 @@ msgstr "難度" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1309 +#: src/race/race_manager.cpp:1317 msgid "Novice" msgstr "新手難度" @@ -784,7 +789,7 @@ msgstr "新手難度" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1310 +#: src/race/race_manager.cpp:1318 msgid "Intermediate" msgstr "中等難度" @@ -796,7 +801,7 @@ msgstr "中等難度" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1311 +#: src/race/race_manager.cpp:1319 msgid "Expert" msgstr "專家" @@ -808,7 +813,7 @@ msgstr "專家" #. I18N: Difficulty #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: Difficulty -#: src/race/race_manager.cpp:1312 +#: src/race/race_manager.cpp:1320 msgid "SuperTux" msgstr "SuperTux" @@ -816,8 +821,8 @@ msgstr "SuperTux" #. I18N: In the server configuration screen #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: In the server creation screen -#: src/states_screens/high_score_selection.cpp:148 -#: src/states_screens/track_info_screen.cpp:249 +#: src/states_screens/high_score_selection.cpp:151 +#: src/states_screens/track_info_screen.cpp:251 msgid "Game mode" msgstr "遊戲模式" @@ -828,8 +833,8 @@ msgstr "遊戲模式" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1282 -#: supertuxkart.appdata.xml:33 +#: src/network/server_config.cpp:265 src/race/race_manager.cpp:1290 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:34 msgid "Normal Race" msgstr "正常比賽" @@ -842,7 +847,7 @@ msgstr "正常比賽" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1284 +#: src/network/server_config.cpp:267 src/race/race_manager.cpp:1292 msgid "Time Trial" msgstr "競速計時" @@ -850,7 +855,8 @@ msgstr "競速計時" #. I18N: Multiplayer game mode #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode -#: src/states_screens/race_setup_screen.cpp:113 supertuxkart.appdata.xml:37 +#: src/states_screens/race_setup_screen.cpp:113 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:38 msgid "Battle" msgstr "對戰" @@ -859,24 +865,24 @@ msgstr "對戰" #. I18N: ./data/gui/screens/online/create_server.stkgui #. I18N: Multiplayer game mode #. I18N: Game mode -#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1298 -#: supertuxkart.appdata.xml:41 +#: src/network/server_config.cpp:269 src/race/race_manager.cpp:1306 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:42 msgid "Soccer" msgstr "足球" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: ./data/gui/screens/online/register.stkgui #. I18N: In the registration dialog -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Password" msgstr "密碼" #. I18N: ./data/gui/dialogs/online/server_info_dialog.stkgui #. I18N: In the server info dialog -#: src/states_screens/dialogs/server_info_dialog.cpp:291 +#: src/states_screens/dialogs/server_info_dialog.cpp:292 msgid "Bookmark this server" msgstr "將此伺服器加入書籤" @@ -887,7 +893,7 @@ msgstr "新增玩家" #. I18N: ./data/gui/dialogs/online/splitscreen_player_dialog.stkgui #. I18N: Splitscreen player in network -#: src/states_screens/online/online_profile_achievements.cpp:76 +#: src/states_screens/online/online_profile_achievements.cpp:78 msgid "Name" msgstr "名稱" @@ -981,6 +987,50 @@ msgstr "指定為 ESC 鍵" msgid "Assign nothing" msgstr "未指定" +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +msgid "Recommend Video Settings" +msgstr "建議的視訊設定" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "The recommended settings will be valid for the current resolution." +msgstr "建議的設定對目前的解析度有效。" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "What should the settings prioritize?" +msgstr "設定的優先順序為何?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Performance" +msgstr "效能" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Balance performance and graphics quality" +msgstr "效能與圖形品質平衡" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Graphics quality" +msgstr "圖形品質" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Sparing energy" +msgstr "節能" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Do you like graphics effects creating blur?" +msgstr "您喜歡製作模糊的圖形效果嗎?" + +#. I18N: ./data/gui/dialogs/recommend_video_settings.stkgui +#. I18N: Recommend video settings dialog +msgid "Start the test" +msgstr "開始測試" + #. I18N: ./data/gui/dialogs/select_challenge.stkgui #. I18N: ./data/gui/screens/race_setup.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui @@ -995,11 +1045,11 @@ msgstr "比賽設定" #. I18N: ./data/gui/screens/online/network_karts.stkgui #. I18N: ./data/gui/screens/soccer_setup.stkgui #. I18N: In soccer setup screen -#: src/states_screens/race_result_gui.cpp:264 -#: src/states_screens/race_result_gui.cpp:287 -#: src/states_screens/race_result_gui.cpp:296 -#: src/states_screens/race_result_gui.cpp:304 -#: src/states_screens/race_result_gui.cpp:1142 +#: src/states_screens/race_result_gui.cpp:284 +#: src/states_screens/race_result_gui.cpp:307 +#: src/states_screens/race_result_gui.cpp:316 +#: src/states_screens/race_result_gui.cpp:324 +#: src/states_screens/race_result_gui.cpp:1191 msgid "Continue" msgstr "繼續" @@ -1040,10 +1090,15 @@ msgstr "競技場" #. I18N: ./data/gui/screens/addons_screen.stkgui #. I18N: In addons screen, above the list of addons to be installed -#: src/states_screens/addons_screen.cpp:136 +#: src/states_screens/addons_screen.cpp:138 msgid "Installed" msgstr "已安裝" +#. I18N: ./data/gui/screens/arenas.stkgui +#. I18N: Section in arena tracksselection screen +msgid "Edit favorite arenas" +msgstr "編輯最愛的競技場" + #. I18N: ./data/gui/screens/arenas.stkgui #. I18N: track group #. I18N: ./data/gui/screens/easter_egg.stkgui @@ -1053,20 +1108,20 @@ msgstr "已安裝" #. I18N: track group name #. I18N: In the UI options, Camera setting: Standard #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:82 -#: src/states_screens/arenas_screen.cpp:90 +#: src/states_screens/arenas_screen.cpp:91 +#: src/states_screens/arenas_screen.cpp:99 #: src/states_screens/dialogs/custom_camera_settings.cpp:69 -#: src/states_screens/easter_egg_screen.cpp:145 -#: src/states_screens/easter_egg_screen.cpp:153 +#: src/states_screens/easter_egg_screen.cpp:148 +#: src/states_screens/easter_egg_screen.cpp:156 #: src/states_screens/gp_info_screen.cpp:256 -#: src/states_screens/grand_prix_editor_screen.cpp:335 -#: src/states_screens/kart_selection.cpp:323 -#: src/states_screens/kart_selection.cpp:332 -#: src/states_screens/online/tracks_screen.cpp:363 -#: src/states_screens/online/tracks_screen.cpp:371 -#: src/states_screens/options/options_screen_ui.cpp:164 -#: src/states_screens/tracks_and_gp_screen.cpp:159 -#: src/states_screens/tracks_and_gp_screen.cpp:167 +#: src/states_screens/grand_prix_editor_screen.cpp:337 +#: src/states_screens/kart_selection.cpp:331 +#: src/states_screens/kart_selection.cpp:346 +#: src/states_screens/online/tracks_screen.cpp:367 +#: src/states_screens/online/tracks_screen.cpp:375 +#: src/states_screens/options/options_screen_ui.cpp:124 +#: src/states_screens/tracks_and_gp_screen.cpp:185 +#: src/states_screens/tracks_and_gp_screen.cpp:193 msgid "Standard" msgstr "標準" @@ -1077,12 +1132,12 @@ msgstr "標準" #. I18N: track group name #. I18N: kart group name #. I18N: track group name -#: src/states_screens/arenas_screen.cpp:84 -#: src/states_screens/easter_egg_screen.cpp:147 -#: src/states_screens/grand_prix_editor_screen.cpp:337 -#: src/states_screens/kart_selection.cpp:325 -#: src/states_screens/online/tracks_screen.cpp:365 -#: src/states_screens/tracks_and_gp_screen.cpp:161 +#: src/states_screens/arenas_screen.cpp:93 +#: src/states_screens/easter_egg_screen.cpp:150 +#: src/states_screens/grand_prix_editor_screen.cpp:339 +#: src/states_screens/kart_selection.cpp:333 +#: src/states_screens/online/tracks_screen.cpp:369 +#: src/states_screens/tracks_and_gp_screen.cpp:187 msgid "Add-Ons" msgstr "附加元件" @@ -1096,27 +1151,28 @@ msgstr "附加元件" #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show karts from all groups -#. I18N: kart group name +#. I18N: kart group/class name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name #. I18N: name of the tab that will show tracks from all groups #. I18N: track group name -#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:48 -#: src/states_screens/addons_screen.cpp:135 -#: src/states_screens/arenas_screen.cpp:74 -#: src/states_screens/arenas_screen.cpp:80 -#: src/states_screens/easter_egg_screen.cpp:137 -#: src/states_screens/easter_egg_screen.cpp:143 -#: src/states_screens/edit_track_screen.cpp:111 +#: src/race/grand_prix_data.cpp:643 src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:137 +#: src/states_screens/arenas_screen.cpp:81 +#: src/states_screens/arenas_screen.cpp:87 +#: src/states_screens/easter_egg_screen.cpp:140 +#: src/states_screens/easter_egg_screen.cpp:146 +#: src/states_screens/edit_track_screen.cpp:117 #: src/states_screens/gp_info_screen.cpp:79 #: src/states_screens/gp_info_screen.cpp:249 -#: src/states_screens/grand_prix_editor_screen.cpp:334 -#: src/states_screens/kart_selection.cpp:315 +#: src/states_screens/grand_prix_editor_screen.cpp:336 #: src/states_screens/kart_selection.cpp:321 -#: src/states_screens/online/tracks_screen.cpp:355 -#: src/states_screens/online/tracks_screen.cpp:361 -#: src/states_screens/tracks_and_gp_screen.cpp:151 -#: src/states_screens/tracks_and_gp_screen.cpp:157 +#: src/states_screens/kart_selection.cpp:327 +#: src/states_screens/kart_selection.cpp:368 +#: src/states_screens/online/tracks_screen.cpp:359 +#: src/states_screens/online/tracks_screen.cpp:365 +#: src/states_screens/tracks_and_gp_screen.cpp:175 +#: src/states_screens/tracks_and_gp_screen.cpp:181 msgid "All" msgstr "全部" @@ -1155,9 +1211,9 @@ msgstr "向下移動" #. I18N: ./data/gui/screens/edit_gp.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen msgid "Add" msgstr "新增" @@ -1194,7 +1250,7 @@ msgstr "重播錄像選擇" #. I18N: ./data/gui/screens/high_score_selection.stkgui #. I18N: In the high score selection screen #. I18N: Game mode -#: src/race/race_manager.cpp:1296 +#: src/race/race_manager.cpp:1304 msgid "Egg Hunt" msgstr "復活節彩蛋狩獵" @@ -1241,10 +1297,10 @@ msgstr "反向進行比賽" #. I18N: ./data/gui/screens/gp_info.stkgui #. I18N: In the grand prix info screen #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:512 -#: src/states_screens/track_info_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:284 -#: src/states_screens/track_info_screen.cpp:450 +#: src/states_screens/online/tracks_screen.cpp:517 +#: src/states_screens/track_info_screen.cpp:257 +#: src/states_screens/track_info_screen.cpp:286 +#: src/states_screens/track_info_screen.cpp:449 msgid "Maximum time (min.)" msgstr "最大時間(分鐘)" @@ -1276,9 +1332,9 @@ msgstr "複製" #. I18N: ./data/gui/screens/grand_prix_editor.stkgui #. I18N: Menu item -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen #: src/states_screens/online/register_screen.cpp:71 msgid "Rename" @@ -1289,80 +1345,80 @@ msgstr "重新命名" msgid "Save Grand Prix" msgstr "儲存大獎賽" -#. I18N: ./data/gui/screens/help1.stkgui -#. I18N: ./data/gui/screens/help2.stkgui -#. I18N: ./data/gui/screens/help3.stkgui -#. I18N: ./data/gui/screens/help4.stkgui -#. I18N: ./data/gui/screens/help5.stkgui -#. I18N: ./data/gui/screens/help6.stkgui -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui msgid "SuperTuxKart Help" msgstr "SuperTuxKart 說明" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Game Modes" msgstr "遊戲模式" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Powerups" msgstr "強化道具" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Bananas" msgstr "香蕉" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button @@ -1370,56 +1426,57 @@ msgstr "香蕉" msgid "Story Mode" msgstr "故事模式" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Kart classes" msgstr "卡丁車類型" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: Tab in help menu -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: Tab in help menu msgid "Multiplayer" msgstr "多人遊戲" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui msgid "Start the tutorial" msgstr "開始教學課程" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "Collect blue gift boxes, they will give you powerups." msgstr "收集藍色的禮物盒,它們會給你強化道具。" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu #: ../stk-assets/tracks/tutorial/scripting.as:49 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:49 msgid "Avoid bananas!" msgstr "避開香蕉皮!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "Collecting nitro allows you to get speed boosts whenever you wish by " @@ -1427,14 +1484,14 @@ msgid "" "nitro in the gauge at the bottom-right of the race screen." msgstr "收集氮氣讓您可以在需要時按下對應的按鍵或按鈕就可以加速。您可以在畫面右下角的地方看到您目前的氮氣收集量。" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "If you see a button with a lock like this one, you need to complete a " "challenge to unlock it." msgstr "若您看到一個像這樣帶有鎖頭的按鈕,表示您需要完成一項特定挑戰才能將它解鎖。" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can skid by pressing a special key or button. Successive short skids " @@ -1443,34 +1500,34 @@ msgid "" "carefully before!" msgstr "您可以按下特殊的按鍵或按鈕來甩尾。成功的甩尾可以協助過角度較大的彎,中等的甩尾可以加速,較長的甩尾則會有更多的加速。您不能在甩尾的時候變換方向,所以要看好你的卡丁車的方向!" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: In the help menu msgid "" "You can get a startup boost by pressing the accelerate button at 'Set!', " "before the race's start." msgstr "您可以在顯示「預備!」時按下加速按鈕來在比賽開始前得到速度提升。" -#. I18N: ./data/gui/screens/help1.stkgui +#. I18N: ./data/gui/screens/help/help1.stkgui #. I18N: in the help screen msgid "* Current key bindings can be seen/changed in the Options menu" msgstr "※ 目前的按鍵組合可以在「選項」選單中查看或更改" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui msgid "SuperTuxKart features several game modes:" msgstr "SuperTuxKart 有許多遊戲模式:" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Regular Race: All blows allowed, so collect powerups and use them smartly!" msgstr "一般比賽:所有的招數都能使用,所以收集強化道具並好好地使用它們吧!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Time Trial: Contains no powerups, so only your driving skills matter!" msgstr "競速計時:沒有道具可用,您只能靠您的賽車技巧!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Follow the leader: Run for second place, as the last kart will be " @@ -1478,7 +1535,7 @@ msgid "" " leader will get you eliminated too!" msgstr "緊隨領隊:保持第二名,在過程中每隔一段時間最後一名就會失去資格。注意:超過領隊也會被淘汰!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "There are 3 types of battle mode: In 3 Strikes Battle, you need to hit " @@ -1488,30 +1545,30 @@ msgid "" "your own flag base, as long as your flag is not captured by the other team." msgstr "有三種對戰模式:在三擊對戰中,您必須用武器攻擊其他人,直到他們失去所有生命為止。在自由對戰中,在次數或時間限制內擊中其他人最多次的玩家獲勝。在搶旗模式中,您的隊伍必須帶著其他隊伍的旗子回到您自己的旗子基地,前提是您的旗子沒有被其他隊伍搶走。" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Soccer: Use your kart to push the ball into the goal." msgstr "足球:使用你的賽車將球推進球門。" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "Egg hunt: Explore tracks to find all hidden eggs." msgstr "復活節彩蛋狩獵:探索賽道以找到所有隱藏的復活節彩蛋。" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Ghost replay: Race against ghost replays in time-trial or egg hunt mode, and" " record your own!" msgstr "幻影重播:在競速計時或復活節彩蛋狩獵模式中與幻影重播比賽,並紀錄您自己的!" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "Lap Trial: Complete as many laps as possible in a given amount of time." msgstr "圈數試驗:在指定的時間內盡量完成最多的圈數。" -#. I18N: ./data/gui/screens/help2.stkgui +#. I18N: ./data/gui/screens/help/help2.stkgui #. I18N: In the help menu msgid "" "* Many of these game modes can also be played in a Grand Prix fashion: " @@ -1520,93 +1577,93 @@ msgid "" "wins the cup." msgstr "※ 這些遊戲模式大多都能在大獎賽中進行。在大獎賽中,玩家會進行不只一場的比賽。玩家的名次愈高,得到分數愈多。最終由總積分最高者獲得冠軍。" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui #. I18N: In the help menu msgid "To help you win, there are some powerups you can collect:" msgstr "您可以收集這些道具來幫助您贏得比賽:" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "BubbleGum - protect yourself with a shield, or use while looking back to " "leave a sticky pink puddle behind you." msgstr "泡泡糖──變成防護罩以保護自己,或者在回頭時使用在您身後留下黏黏的粉紅色物體。" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Zipper - will give you a strong speed boost. But beware of not losing " "control of your kart!" msgstr "拉鍊 - 會給你強大的加速。但請小心,不要讓卡丁車失控!" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Cake - thrown at the closest rival, best on short ranges and long straights." " It also affects other karts close to the explosion." msgstr "蛋糕 - 丟向最近的對手,最好在短距離或是長直賽道使用。它也會影響在爆炸範圍內的其他玩家。" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Plunger - throw straight to pull an opponent back, or throw while looking " "back to make one lose sight." msgstr "吸盤──直接丟出去來拉著一名對手的背後,或是當向後看時丟出來遮蔽後頭對手的視線。" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Bowling Ball - goes straight until it strikes, it can bounce off walls. If " "you are looking back, it will be thrown backwards." msgstr "保齡球 - 在擊中物體前都會直線前進,會被牆壁反彈。如果你在向後看的時候丟出,它就會向後滾。" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "Parachute - slows down all karts in a better position." msgstr "降落傘──減慢所有領先您的車子的速度" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swapper - gift boxes are transformed into bananas, nitro cans into " "bubblegums, and vice versa for a short time." msgstr "交換器 - 在一小段時間內將禮物箱變成香蕉,氮氣罐變成泡泡糖,反之亦然。" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Basket Ball - bounces after the leader, and might squash and slow down karts" " down on the way." msgstr "籃球──跳向領頭的賽車手,並一路壓扁並降低經過的車子的速度。" -#. I18N: ./data/gui/screens/help3.stkgui +#. I18N: ./data/gui/screens/help/help3.stkgui msgid "" "Swatter - will squash karts close by, slowing them down. Can also be used to" " remove parachutes and bombs." msgstr "蒼蠅拍 - 拍扁靠近的卡丁車,會減慢他們的速度。也可以用於移除降落傘與炸彈。" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui msgid "" "Hitting a banana can result in one of the following being attached to the " "kart:" msgstr "撞到香蕉可能會導致下面的其中一種東西黏到卡丁車上:" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "Anchor - slows down the kart suddenly." msgstr "鐵錨 - 讓卡丁車立刻減速。" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Parachute - slows down the kart, more progressively than the anchor. The " "faster you go, the stronger it slows you down." msgstr "降落傘 - 讓卡丁車減速,較鐵錨更漸進式,你跑得愈快,它的減速能力就愈強。" -#. I18N: ./data/gui/screens/help4.stkgui +#. I18N: ./data/gui/screens/help/help4.stkgui #. I18N: In the help menu msgid "" "Bomb - detonates after some amount of time, throwing the kart up in the air." " Bump into another kart to transfer the bomb to it." msgstr "炸彈 - 一段時間後會引爆,將卡丁車丟到空中。撞到另一輛卡丁車會將炸彈轉移到它身上。" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui msgid "The evil Nolok has captured Gnu! Here are a few tips to help you:" msgstr "邪惡的 Nolok 把 GNU 抓走了!這裡有一些秘訣可以協助你:" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "This icon on the minimap shows the available challenges you've not " @@ -1615,7 +1672,7 @@ msgid "" " accept to race against you. Win to liberate Gnu!" msgstr "這個在迷你地圖上的圖示顯示了你尚未完成的可用挑戰。在畫面的右上角,它也會顯示你目前有多少點數。完成盡可能多的挑戰,然後 Nolok 就會接受跟你比賽。取得勝利以釋放 GNU!" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you complete a challenge, you get a cup. Each cup is worth several " @@ -1623,20 +1680,20 @@ msgid "" " the cup and the more points it is worth." msgstr "當你完成一個挑戰時,你會取得一個獎盃。每個獎盃都值數點。你完成的挑戰難度愈高,拿到的獎盃就愈好,取得的點數也愈多。" -#. I18N: ./data/gui/screens/help5.stkgui +#. I18N: ./data/gui/screens/help/help5.stkgui #. I18N: In the help menu msgid "" "When you get the number of points indicated below this icon, you'll be " "gifted a surprise. There are several to collect." msgstr "當你取得在圖示下指示的點數時,你將會得到一個驚喜。有許多可以收集。" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui msgid "" "Not all karts drive the same! They belong to classes with several " "differences:" msgstr "不是所有的卡丁車都一樣!它們屬於多種不同的類型:" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Mass - there are three classes of karts, depending on their mass: light, " @@ -1644,7 +1701,7 @@ msgid "" " resistant to explosions." msgstr "重量 - 有三種類型的卡丁車,取決於它們的重量:輕、中、重。較重的卡丁車較不會被降落傘影響,也對爆炸較有抵抗能力。" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Acceleration - especially useful at start, after an accident, or in tracks " @@ -1652,7 +1709,7 @@ msgid "" " especially at low speeds." msgstr "加速 - 在開賽、意外後或是在有許多彎道的賽道都很有用。愈輕的卡丁車加速愈快,特別是在低速的時候。" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Max speed - the higher it is, the faster the kart can go. Especially useful " @@ -1660,14 +1717,14 @@ msgid "" " top speed." msgstr "最大速度 - 這個值愈高,卡丁車就能跑得愈快。在直線與角度較小的彎道時特別有用。較重的卡丁車會有較高的極速。" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "Nitro efficiency - The higher it is, the more speed you get from a can of " "nitro. A lighter kart will have higher nitro efficiency." msgstr "氮氣效率 - 這個值愈高,你從氮氣罐取得的速度就愈多。較輕的賽車會有較高的氮氣效率。" -#. I18N: ./data/gui/screens/help6.stkgui +#. I18N: ./data/gui/screens/help/help6.stkgui #. I18N: In the help menu msgid "" "If you follow closely another kart for a few seconds, you'll get a " @@ -1675,12 +1732,12 @@ msgid "" "easier it is." msgstr "如果你跟在其它卡丁車後數秒鐘,在你超車的時候就會取得氣流加速。卡丁車愈輕,這就愈容易。" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "SuperTuxKart can be played in multiplayer mode online...:" msgstr "SuperTuxKart 可以以多人模式線上遊玩……" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, select the 'online' icon in the main menu. Choose either local " @@ -1690,7 +1747,7 @@ msgid "" "recommended servers with optionally ranked races." msgstr "首先,在主選單中選取「線上」圖示。選擇區域網路或全球網路(必須在選項中啟用網際網路)。然後,您就可以使用自訂選項建立您自己的伺服器,或搜尋既有的伺服器清單以加入。其中一些是選擇性排位賽的建議伺服器。" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "Once in a server, a race will begin once its owner (symbolized with the " @@ -1700,12 +1757,12 @@ msgid "" "players and the server." msgstr "在伺服器裡,只要擁有者(以皇冠標示)決定要開始,比賽就會開始。官方的伺服器僅會在有足夠玩家時才會自動開始。然後,你就可以選擇你的卡丁車並為下次的賽道投票。附加元件賽道僅在伺服器與加入的所有玩家都有時才能使用。" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "... or on the same device:" msgstr "……或在相同的裝置上:" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "First, you will need several input devices. Use the input configuration " @@ -1715,7 +1772,7 @@ msgid "" "multiple simultaneous keypresses." msgstr "首先,你需要有多個輸入裝置。使用輸入設定畫面以設定它們。多個手把或搖桿是最理想的,每個玩家都需要不同的按鍵設定,而多數的鍵盤都不適於同時給多個玩家使用,因為它們不支援同時按下多個按鍵。" -#. I18N: ./data/gui/screens/help7.stkgui +#. I18N: ./data/gui/screens/help/help7.stkgui #. I18N: In the help menu msgid "" "When input devices are configured, select the 'Splitscreen Multiplayer' icon" @@ -1735,7 +1792,7 @@ msgstr "高分選擇" #. I18N: Game mode #. I18N: Lap Trial: Complete as many laps as possible in a given amount of #. time. -#: src/race/race_manager.cpp:1288 src/states_screens/race_setup_screen.cpp:142 +#: src/race/race_manager.cpp:1296 src/states_screens/race_setup_screen.cpp:142 msgid "Lap Trial" msgstr "圈數計時" @@ -1743,9 +1800,9 @@ msgstr "圈數計時" #. I18N: In the high score selection screen #. I18N: ./data/gui/screens/tracks_and_gp.stkgui #. I18N: In the track and grand prix selection screen -#: src/states_screens/dialogs/high_score_info_dialog.cpp:71 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:75 #: src/states_screens/dialogs/select_challenge.cpp:51 -#: src/states_screens/high_score_selection.cpp:136 +#: src/states_screens/high_score_selection.cpp:139 msgid "Grand Prix" msgstr "大獎賽" @@ -1756,6 +1813,20 @@ msgstr "大獎賽" msgid "Choose a Kart" msgstr "選擇一台賽車" +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In karts selection screen, determine the kart group shown on the list +msgid "Kart Class" +msgstr "卡丁車類型" + +#. I18N: ./data/gui/screens/karts.stkgui +#. I18N: In the track and grand prix selection screen +#. I18N: ./data/gui/screens/online/network_karts.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite karts" +msgstr "編輯最愛的卡丁車" + #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button msgid "Singleplayer" @@ -1769,11 +1840,11 @@ msgstr "分割畫面多人遊戲" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: Main menu button #. I18N: ./data/gui/screens/online/online.stkgui -#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: In the user screen -#: src/states_screens/online/online_profile_friends.cpp:240 +#: src/states_screens/online/online_profile_friends.cpp:245 msgid "Online" msgstr "線上" @@ -1790,7 +1861,7 @@ msgstr "教學" #. I18N: ./data/gui/screens/main_menu.stkgui #. I18N: In the main screen -#: src/states_screens/track_info_screen.cpp:341 +#: src/states_screens/track_info_screen.cpp:343 msgid "High Scores" msgstr "高分" @@ -1798,7 +1869,7 @@ msgstr "高分" #. I18N: In the main screen #. I18N: ./data/gui/screens/online/profile_achievements_tab.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:109 +#: src/states_screens/online/online_profile_base.cpp:113 msgid "Achievements" msgstr "成就" @@ -1852,30 +1923,30 @@ msgstr "尋找伺服器" #. I18N: In the online multiplayer screen #. I18N: ./data/gui/screens/online/profile_servers.stkgui #. I18N: In the online multiplayer screen -#: src/states_screens/online/create_server_screen.cpp:103 +#: src/states_screens/online/create_server_screen.cpp:108 msgid "Create Server" msgstr "建立伺服器" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In networking lobby #. I18N: In the networking lobby -#: src/states_screens/online/networking_lobby.cpp:85 -#: src/states_screens/online/networking_lobby.cpp:883 -#: src/states_screens/online/networking_lobby.cpp:899 -#: src/states_screens/online/networking_lobby.cpp:1048 +#: src/states_screens/online/networking_lobby.cpp:86 +#: src/states_screens/online/networking_lobby.cpp:922 +#: src/states_screens/online/networking_lobby.cpp:940 +#: src/states_screens/online/networking_lobby.cpp:1089 msgid "Lobby" msgstr "大廳" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby #. I18N: In networking lobby to configuration server settings -#: src/states_screens/online/networking_lobby.cpp:200 +#: src/states_screens/online/networking_lobby.cpp:201 msgid "Configuration" msgstr "設定" #. I18N: ./data/gui/screens/online/networking_lobby.stkgui #. I18N: In the network lobby -#: src/states_screens/online/networking_lobby.cpp:192 +#: src/states_screens/online/networking_lobby.cpp:193 msgid "Start race" msgstr "開始競賽" @@ -1901,9 +1972,9 @@ msgstr "輸入伺服器地址" #. I18N: ./data/gui/screens/online/online.stkgui #. I18N: Networking menu button -#: src/states_screens/online/online_profile_base.cpp:114 -#: src/states_screens/online/online_profile_base.cpp:124 -#: src/states_screens/online/online_screen.cpp:60 +#: src/states_screens/online/online_profile_base.cpp:118 +#: src/states_screens/online/online_profile_base.cpp:128 +#: src/states_screens/online/online_screen.cpp:67 msgid "Your profile" msgstr "您的個人檔案" @@ -1921,7 +1992,7 @@ msgstr "玩家排名" #. I18N: ./data/gui/screens/online/profile_friends.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:108 +#: src/states_screens/online/online_profile_base.cpp:112 msgid "Friends" msgstr "朋友" @@ -1946,7 +2017,7 @@ msgstr "快速遊戲" #. I18N: ./data/gui/screens/online/profile_settings.stkgui #. I18N: Section in the profile screen -#: src/states_screens/online/online_profile_base.cpp:110 +#: src/states_screens/online/online_profile_base.cpp:114 msgid "Account Settings" msgstr "帳號設定值" @@ -1996,8 +2067,8 @@ msgid "Online Username" msgstr "線上使用者名稱" #. I18N: ./data/gui/screens/online/register.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui msgid "Reset password" msgstr "重設密碼" @@ -2010,7 +2081,7 @@ msgid "" msgstr "您可以藉由選取離線帳號,在不需要建立線上帳號的情況下進行遊戲。不過這樣您就無法與朋友連線,為附加元件投票等。請到 https://privacy.supertuxkart.net 詳閱我們的隱私聲明" #. I18N: ./data/gui/screens/online/server_selection.stkgui -#: src/states_screens/online/server_selection.cpp:580 +#: src/states_screens/online/server_selection.cpp:578 msgid "Server Selection" msgstr "伺服器選取" @@ -2028,339 +2099,409 @@ msgstr "使用 IPv6 連線" msgid "User search" msgstr "使用者搜尋" -#. I18N: ./data/gui/screens/options_audio.stkgui -#. I18N: ./data/gui/screens/options_device.stkgui -#. I18N: ./data/gui/screens/options_general.stkgui -#. I18N: ./data/gui/screens/options_input.stkgui -#. I18N: ./data/gui/screens/options_language.stkgui -#. I18N: ./data/gui/screens/options_ui.stkgui -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui msgid "SuperTuxKart Options" msgstr "SuperTuxKart 選項" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_general.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_input.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_language.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_ui.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: Section in the settings menu +msgid "Display" +msgstr "顯示" + +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Graphics" msgstr "圖像" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Audio" msgstr "音效" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Interface" msgstr "界面" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Players" msgstr "玩家" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Controls" msgstr "操控" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui +#. I18N: Section in the settings menu +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_language.stkgui +#. I18N: ./data/gui/screens/options/options_language.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: Section in the settings menu -#. I18N: ./data/gui/screens/user_screen_tab.stkgui +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui #. I18N: Section in the settings menu msgid "Language" msgstr "語言" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Music" msgstr "音樂" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen #. I18N: in the graphical options tooltip; #. indicates a graphical feature is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:71 -#: src/states_screens/options/options_screen_video.cpp:663 -#: src/states_screens/options/options_screen_video.cpp:736 +#: src/states_screens/dialogs/custom_video_settings.cpp:70 +#: src/states_screens/options/options_screen_video.cpp:445 +#: src/states_screens/options/options_screen_video.cpp:534 msgid "Enabled" msgstr "已啟用" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Volume" msgstr "音量" -#. I18N: ./data/gui/screens/options_audio.stkgui +#. I18N: ./data/gui/screens/options/options_audio.stkgui #. I18N: In the audio options screen msgid "Sound Effects" msgstr "音效" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Delete Configuration" msgstr "刪除設定" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen #. I18N: button to disable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:125 -#: src/states_screens/options/options_screen_device.cpp:632 +#: src/states_screens/options/options_screen_device.cpp:105 +#: src/states_screens/options/options_screen_device.cpp:597 msgid "Disable Configuration" msgstr "停用設定" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Back to device list" msgstr "回到裝置列表" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen msgid "Rename Configuration" msgstr "重新命名設定" -#. I18N: ./data/gui/screens/options_device.stkgui +#. I18N: ./data/gui/screens/options/options_device.stkgui #. I18N: In the input configuration screen, for gamepad msgid "Enable force feedback (if supported)" msgstr "啟用力回饋(若支援的話)" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Resolution" +msgstr "解析度" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Fullscreen" +msgstr "全螢幕" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Remember window location" +msgstr "記住視窗位置" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Apply new resolution" +msgstr "套用新的畫面解析度" + +#. I18N: ./data/gui/screens/options/options_display.stkgui +#. I18N: In the display settings +msgid "Splitscreen Multiplayer layout" +msgstr "分割畫面多人遊戲佈局" + +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Internet options" msgstr "網際網路選項" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Always show login screen" msgstr "總是顯示登入畫面" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Connect to the Internet" msgstr "連線到網路" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting online" -msgstr "啟用線上聊天" +msgid "Enable chatting in online lobbies" +msgstr "在線上大廳啟用聊天" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings -msgid "Enable chatting in online games" -msgstr "在線上遊戲啟用聊天" +msgid "Enable chatting in online matches" +msgstr "在線上比賽中啟用聊天" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Miscellaneous options" msgstr "雜項選項" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: In the general settings msgid "Enable per-player handicaps" msgstr "啟用每個玩家的讓賽功能" -#. I18N: ./data/gui/screens/options_general.stkgui +#. I18N: ./data/gui/screens/options/options_general.stkgui #. I18N: For mobile version for STK, uninstall the downloaded assets -#: src/states_screens/options/options_screen_general.cpp:113 +#: src/states_screens/options/options_screen_general.cpp:79 msgid "Uninstall full game assets" msgstr "解除安裝完整遊戲資源" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen -#: src/states_screens/options/options_screen_input.cpp:212 +#: src/states_screens/options/options_screen_input.cpp:191 msgid "Press enter or double-click on a device to configure it" msgstr "按 Enter 或對裝置雙擊以設定該裝置" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "Add a device" msgstr "新增裝置" -#. I18N: ./data/gui/screens/options_input.stkgui +#. I18N: ./data/gui/screens/options/options_input.stkgui #. I18N: In the input configuration screen msgid "" "* Which config to use will be inferred from which 'Select' key is pressed to" " join the game." msgstr "※ 使用何種設定將會由加入遊戲時所按下的「選擇」鍵來推斷。" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Skin" msgstr "外觀" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Minimap" -msgstr "迷你地圖" +msgid "Skin variant" +msgstr "造型變體" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings -msgid "Splitscreen Multiplayer layout" -msgstr "分割畫面多人遊戲佈局" +msgid "Minimap" +msgstr "迷你地圖" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Font size" msgstr "字型大小" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Camera" msgstr "攝影機" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Custom..." msgstr "自訂……" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Display FPS" msgstr "顯示畫面幀速率 (FPS)" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Show other karts' held powerups" msgstr "顯示其他卡丁車持有的道具" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the story mode timer" msgstr "啟用故事模式計時器" -#. I18N: ./data/gui/screens/options_ui.stkgui +#. I18N: ./data/gui/screens/options/options_ui.stkgui #. I18N: In the ui settings msgid "Enable the speedrun timer" msgstr "啟用競速模式計時器" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Render resolution" msgstr "彩現解析度" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Graphical Effects Level" msgstr "圖像特效等級" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Blur Effects Level" msgstr "模糊效果等級" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video options, maximum frame per second msgid "Maximum FPS" msgstr "最大 FPS" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings msgid "Custom settings..." msgstr "個別化設定" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Resolution" -msgstr "解析度" +msgid "Performance tests" +msgstr "效能測試" -#. I18N: ./data/gui/screens/options_video.stkgui +#. I18N: ./data/gui/screens/options/options_video.stkgui #. I18N: In the video settings -msgid "Fullscreen" -msgstr "全螢幕" +msgid "Performance test of the current settings" +msgstr "目前設定的效能測試" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Remember window location" -msgstr "記住視窗位置" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Remember password" +msgstr "記住密碼" -#. I18N: ./data/gui/screens/options_video.stkgui -#. I18N: In the video settings -msgid "Apply new resolution" -msgstr "套用新的畫面解析度" +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Delete" +msgstr "删除" + +#. I18N: ./data/gui/screens/options/user_screen_tab.stkgui +#. I18N: In the user screen +#. I18N: ./data/gui/screens/user_screen.stkgui +#. I18N: In the user screen +msgid "Kart color" +msgstr "賽車色彩" #. I18N: ./data/gui/screens/race_setup.stkgui msgid "Select a difficulty" @@ -2387,15 +2528,15 @@ msgstr "藍隊" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:541 -#: src/states_screens/track_info_screen.cpp:276 +#: src/states_screens/online/tracks_screen.cpp:546 +#: src/states_screens/track_info_screen.cpp:278 msgid "Number of laps" msgstr "圈數" #. I18N: ./data/gui/screens/track_info.stkgui #. I18N: In the track info screen -#: src/states_screens/online/create_server_screen.cpp:196 -#: src/states_screens/track_info_screen.cpp:195 +#: src/states_screens/online/create_server_screen.cpp:201 +#: src/states_screens/track_info_screen.cpp:197 msgid "Number of AI karts" msgstr "電腦操控的賽車數量" @@ -2410,33 +2551,17 @@ msgstr "藍隊的電腦玩家數量" msgid "Random Grand Prix" msgstr "隨機大獎賽" +#. I18N: ./data/gui/screens/tracks_and_gp.stkgui +#. I18N: In the track and grand prix selection screen +msgid "Edit favorite tracks" +msgstr "編輯最愛賽道" + #. I18N: ./data/gui/screens/user_screen.stkgui #. I18N: Used as a verb, appears on the main networking menu (login button) -#: src/states_screens/online/online_screen.cpp:62 +#: src/states_screens/online/online_screen.cpp:69 msgid "Login" msgstr "登入" -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Remember password" -msgstr "記住密碼" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Delete" -msgstr "删除" - -#. I18N: ./data/gui/screens/user_screen.stkgui -#. I18N: In the user screen -#. I18N: ./data/gui/screens/user_screen_tab.stkgui -#. I18N: In the user screen -msgid "Kart color" -msgstr "賽車色彩" - #. I18N: ./data/tips.xml msgid "The UI skin can be changed in the UI options." msgstr "介面外觀可以在使用者介面選項中變更。" @@ -2555,238 +2680,306 @@ msgid "" msgstr "儘管您可以試著攻擊對手來防止他們得分,但絕對不要妨礙隊友接球。" #. I18N: ../stk-assets/karts/adiumy/kart.xml +#. I18N: ../supertuxkart-assets/karts/adiumy/kart.xml msgid "Adiumy" msgstr "Adiumy" #. I18N: ../stk-assets/karts/amanda/kart.xml +#. I18N: ../supertuxkart-assets/karts/amanda/kart.xml msgid "Amanda" msgstr "Amanda" #. I18N: ../stk-assets/karts/beastie/kart.xml +#. I18N: ../supertuxkart-assets/karts/beastie/kart.xml msgid "Godette" msgstr "Godette" #. I18N: ../stk-assets/karts/emule/kart.xml +#. I18N: ../supertuxkart-assets/karts/emule/kart.xml msgid "Emule" msgstr "Emule" #. I18N: ../stk-assets/karts/gavroche/kart.xml +#. I18N: ../supertuxkart-assets/karts/gavroche/kart.xml msgid "Gavroche" msgstr "Gavroche" #. I18N: ../stk-assets/karts/gnu/kart.xml +#. I18N: ../supertuxkart-assets/karts/gnu/kart.xml msgid "Gnu" msgstr "Gnu" #. I18N: ../stk-assets/karts/hexley/kart.xml +#. I18N: ../supertuxkart-assets/karts/hexley/kart.xml msgid "Hexley" msgstr "Hexley" #. I18N: ../stk-assets/karts/kiki/kart.xml +#. I18N: ../supertuxkart-assets/karts/kiki/kart.xml msgid "Kiki" msgstr "Kiki" #. I18N: ../stk-assets/karts/konqi/kart.xml +#. I18N: ../supertuxkart-assets/karts/konqi/kart.xml msgid "Konqi" msgstr "Konqi" #. I18N: ../stk-assets/karts/nolok/kart.xml +#. I18N: ../supertuxkart-assets/karts/nolok/kart.xml msgid "Nolok" msgstr "Nolok" #. I18N: ../stk-assets/karts/pidgin/kart.xml +#. I18N: ../supertuxkart-assets/karts/pidgin/kart.xml msgid "Pidgin" msgstr "Pidgin" #. I18N: ../stk-assets/karts/puffy/kart.xml +#. I18N: ../supertuxkart-assets/karts/puffy/kart.xml msgid "Puffy" msgstr "Puffy" #. I18N: ../stk-assets/karts/sara_the_racer/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_racer/kart.xml msgid "Pepper" msgstr "Pepper" #. I18N: ../stk-assets/karts/sara_the_wizard/kart.xml +#. I18N: ../supertuxkart-assets/karts/sara_the_wizard/kart.xml msgid "Sara" msgstr "Sara" #. I18N: ../stk-assets/karts/suzanne/kart.xml +#. I18N: ../supertuxkart-assets/karts/suzanne/kart.xml msgid "Suzanne" msgstr "Suzanne" #. I18N: ../stk-assets/karts/tux/kart.xml +#. I18N: ../supertuxkart-assets/karts/tux/kart.xml msgid "Tux" msgstr "Tux" #. I18N: ../stk-assets/karts/wilber/kart.xml +#. I18N: ../supertuxkart-assets/karts/wilber/kart.xml msgid "Wilber" msgstr "Wilber" #. I18N: ../stk-assets/karts/xue/kart.xml +#. I18N: ../supertuxkart-assets/karts/xue/kart.xml msgid "Xue" msgstr "Xue" #. I18N: ../stk-assets/tracks/abyss/track.xml +#. I18N: ../supertuxkart-assets/tracks/abyss/track.xml msgid "Antediluvian Abyss" msgstr "史前深淵" #. I18N: ../stk-assets/tracks/alien_signal/track.xml +#. I18N: ../supertuxkart-assets/tracks/alien_signal/track.xml msgid "Alien Signal" msgstr "外星訊號" #. I18N: ../stk-assets/tracks/ancient_colosseum_labyrinth/track.xml +#. I18N: ../supertuxkart-assets/tracks/ancient_colosseum_labyrinth/track.xml msgid "Ancient Colosseum Labyrinth" msgstr "古羅馬鬥獸場迷宮" #. I18N: ../stk-assets/tracks/arena_candela_city/track.xml #. I18N: ../stk-assets/tracks/candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/arena_candela_city/track.xml +#. I18N: ../supertuxkart-assets/tracks/candela_city/track.xml msgid "Candela City" msgstr "坎德拉市" #. I18N: ../stk-assets/tracks/battleisland/track.xml +#. I18N: ../supertuxkart-assets/tracks/battleisland/track.xml msgid "Battle Island" msgstr "對戰之島" #. I18N: ../stk-assets/tracks/black_forest/track.xml +#. I18N: ../supertuxkart-assets/tracks/black_forest/track.xml msgid "Black Forest" msgstr "黑森林" #. I18N: ../stk-assets/tracks/cave/track.xml +#. I18N: ../supertuxkart-assets/tracks/cave/track.xml msgid "Cave X" msgstr "未知的洞穴" #. I18N: ../stk-assets/tracks/cocoa_temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/cocoa_temple/track.xml msgid "Cocoa Temple" msgstr "可可寺院" #. I18N: ../stk-assets/tracks/cornfield_crossing/track.xml +#. I18N: ../supertuxkart-assets/tracks/cornfield_crossing/track.xml msgid "Cornfield Crossing" msgstr "麥田隧道" #. I18N: ../stk-assets/tracks/fortmagma/track.xml +#. I18N: ../supertuxkart-assets/tracks/fortmagma/track.xml msgid "Fort Magma" msgstr "岩漿要塞" #. I18N: ../stk-assets/tracks/gran_paradiso_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/gran_paradiso_island/track.xml msgid "Gran Paradiso Island" msgstr "大天堂島" #. I18N: ../stk-assets/tracks/hacienda/track.xml +#. I18N: ../supertuxkart-assets/tracks/hacienda/track.xml msgid "Hacienda" msgstr "大地莊園" #. I18N: ../stk-assets/tracks/hole_drop/track.xml +#. I18N: ../supertuxkart-assets/tracks/hole_drop/track.xml msgid "Hole Drop" msgstr "洞穴掉落" #. I18N: ../stk-assets/tracks/icy_soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/icy_soccer_field/track.xml msgid "Icy Soccer Field" msgstr "冰雪球場" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "What's wrong, little hippies? Your great gnu leader is missing?" msgstr "怎麼了?小傢伙,你們偉大的 GNU 首領不見了嗎?" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "Oh yes, see, he's in my castle now and will be served for supper..." msgstr "沒錯,你看,他正在我的城堡裡,即將被當成晚餐..." #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "But I'm a fair creature, so I'll make you a deal." msgstr "但我是很公平的,所以我會跟你打個賭。" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "If you can beat me at racing, I will free the old codger." msgstr "如果你能在賽車上贏過我,我就會把那老傢伙放了。" #. I18N: Cutscene subtitle from ../stk-assets/tracks/introcutscene2/scene.xml #. I18N: ../stk-assets/tracks/introcutscene2/scene.xml +#. I18N: Cutscene subtitle from ../supertuxkart- +#. assets/tracks/introcutscene2/scene.xml +#. I18N: ../supertuxkart-assets/tracks/introcutscene2/scene.xml msgid "" " But you pathetic little twerps will never be able to beat me - King of the " "Karts!" msgstr " 但就憑你們這些蠢材是沒辦法打敗我的!我可是賽車之王!" #. I18N: ../stk-assets/tracks/lasdunasarena/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunasarena/track.xml msgid "Las Dunas Arena" msgstr "沙丘競技場" #. I18N: ../stk-assets/tracks/lasdunassoccer/track.xml +#. I18N: ../supertuxkart-assets/tracks/lasdunassoccer/track.xml msgid "Las Dunas Soccer Stadium" msgstr "沙丘足球場" #. I18N: ../stk-assets/tracks/lighthouse/track.xml +#. I18N: ../supertuxkart-assets/tracks/lighthouse/track.xml msgid "Around the Lighthouse" msgstr "圍繞燈塔" #. I18N: ../stk-assets/tracks/mines/track.xml +#. I18N: ../supertuxkart-assets/tracks/mines/track.xml msgid "Old Mine" msgstr "廢棄礦坑" #. I18N: ../stk-assets/tracks/minigolf/track.xml +#. I18N: ../supertuxkart-assets/tracks/minigolf/track.xml msgid "Minigolf" msgstr "迷你高爾夫" #. I18N: ../stk-assets/tracks/oasis/track.xml +#. I18N: ../supertuxkart-assets/tracks/oasis/track.xml msgid "Oasis" msgstr "舒適綠洲" #. I18N: ../stk-assets/tracks/olivermath/track.xml +#. I18N: ../supertuxkart-assets/tracks/olivermath/track.xml msgid "Oliver's Math Class" msgstr "奧力佛的數學課" #. I18N: ../stk-assets/tracks/pumpkin_park/track.xml +#. I18N: ../supertuxkart-assets/tracks/pumpkin_park/track.xml msgid "Pumpkin Park" msgstr "南瓜公園" #. I18N: ../stk-assets/tracks/ravenbridge_mansion/track.xml +#. I18N: ../supertuxkart-assets/tracks/ravenbridge_mansion/track.xml msgid "Ravenbridge Mansion" msgstr "Ravenbridge 豪宅" #. I18N: ../stk-assets/tracks/sandtrack/track.xml +#. I18N: ../supertuxkart-assets/tracks/sandtrack/track.xml msgid "Shifting Sands" msgstr "漂移沙漠" #. I18N: ../stk-assets/tracks/scotland/track.xml +#. I18N: ../supertuxkart-assets/tracks/scotland/track.xml msgid "Nessie's Pond" msgstr "尼斯湖水怪的池塘" #. I18N: ../stk-assets/tracks/snowmountain/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowmountain/track.xml msgid "Northern Resort" msgstr "北國名勝" #. I18N: ../stk-assets/tracks/snowtuxpeak/track.xml +#. I18N: ../supertuxkart-assets/tracks/snowtuxpeak/track.xml msgid "Snow Peak" msgstr "雪山巔峰" #. I18N: ../stk-assets/tracks/soccer_field/track.xml +#. I18N: ../supertuxkart-assets/tracks/soccer_field/track.xml msgid "Soccer Field" msgstr "足球場" #. I18N: ../stk-assets/tracks/stadium/track.xml +#. I18N: ../supertuxkart-assets/tracks/stadium/track.xml msgid "The Stadium" msgstr "大競技場" #. I18N: ../stk-assets/tracks/stk_enterprise/track.xml +#. I18N: ../supertuxkart-assets/tracks/stk_enterprise/track.xml msgid "STK Enterprise" msgstr "STK 企業號" #. I18N: ../stk-assets/tracks/temple/track.xml +#. I18N: ../supertuxkart-assets/tracks/temple/track.xml msgid "Temple" msgstr "寺院" #. I18N: ../stk-assets/tracks/volcano_island/track.xml +#. I18N: ../supertuxkart-assets/tracks/volcano_island/track.xml msgid "Volcan Island" msgstr "火山之島" #. I18N: ../stk-assets/tracks/xr591/track.xml +#. I18N: ../supertuxkart-assets/tracks/xr591/track.xml msgid "XR591" msgstr "XR591" #. I18N: ../stk-assets/tracks/zengarden/track.xml +#. I18N: ../supertuxkart-assets/tracks/zengarden/track.xml msgid "Zen Garden" msgstr "禪意花園" @@ -2795,11 +2988,11 @@ msgstr "禪意花園" msgid "Completed achievement \"%s\"." msgstr "已完成成就「%s」" -#: src/addons/addons_manager.cpp:111 src/addons/news_manager.cpp:343 +#: src/addons/addons_manager.cpp:113 src/addons/news_manager.cpp:353 msgid "Failed to connect to the SuperTuxKart add-ons server." msgstr "無法連線至 SuperTuxKart 附加元件伺服器。" -#: src/addons/news_manager.cpp:180 +#: src/addons/news_manager.cpp:184 #, c-format msgid "Error downloading news: '%s'." msgstr "下載新聞時錯誤:「%s」" @@ -2865,7 +3058,7 @@ msgid "New kart '%s' now available" msgstr "現在可以駕駛新的「%s」賽車" #: src/challenges/story_mode_timer.cpp:281 -#: src/states_screens/options/options_screen_ui.cpp:318 +#: src/states_screens/options/options_screen_ui.cpp:280 msgid "" "Speedrun mode disabled. It can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -2897,32 +3090,32 @@ msgid "" "created." msgstr "您的設定檔太舊了,它已經被移除並由一份新的取代。" -#: src/graphics/irr_driver.cpp:730 +#: src/graphics/irr_driver.cpp:738 msgid "Video recording started." msgstr "開始視訊錄製。" -#: src/graphics/irr_driver.cpp:737 +#: src/graphics/irr_driver.cpp:745 #, c-format msgid "Video saved in \"%s\"." msgstr "視訊儲存於「%s」。" -#: src/graphics/irr_driver.cpp:741 +#: src/graphics/irr_driver.cpp:749 msgid "Encoding progress:" msgstr "編碼進度:" -#: src/graphics/irr_driver.cpp:1913 src/graphics/irr_driver.cpp:1956 -#: src/graphics/irr_driver.cpp:1961 +#: src/graphics/irr_driver.cpp:1920 src/graphics/irr_driver.cpp:1963 +#: src/graphics/irr_driver.cpp:1968 #, c-format msgid "FPS: %d/%d/%d - %d KTris, Ping: %dms" msgstr "FPS:%d/%d/%d - %d KTris,Ping:%d毫秒" #. I18N: Tip shown in gui for giving player hints -#: src/guiengine/engine.cpp:1452 src/states_screens/race_result_gui.cpp:203 +#: src/guiengine/engine.cpp:1466 src/states_screens/race_result_gui.cpp:206 #, c-format msgid "Tip: %s" msgstr "訣竅:%s" -#: src/guiengine/engine.cpp:1496 +#: src/guiengine/engine.cpp:1510 msgid "Loading" msgstr "載入中" @@ -2944,19 +3137,18 @@ msgstr "氮氣效率" #. I18N: 'handicapped' indicates that per-player handicaps are #. activated for this kart (i.e. it will drive slower) -#: src/guiengine/widgets/player_kart_widget.cpp:387 -#: src/guiengine/widgets/player_kart_widget.cpp:758 +#: src/guiengine/widgets/player_kart_widget.cpp:391 +#: src/guiengine/widgets/player_kart_widget.cpp:767 #: src/karts/controller/local_player_controller.cpp:468 #: src/karts/controller/player_controller.cpp:413 -#: src/network/protocols/client_lobby.cpp:867 +#: src/network/protocols/client_lobby.cpp:868 #: src/states_screens/dialogs/splitscreen_player_dialog.cpp:121 -#: src/states_screens/race_result_gui.cpp:1602 -#: src/states_screens/race_result_gui.cpp:1664 +#: src/states_screens/race_result_gui.cpp:1675 #, c-format msgid "%s (handicapped)" msgstr "%s(讓賽)" -#: src/guiengine/widgets/player_kart_widget.cpp:444 +#: src/guiengine/widgets/player_kart_widget.cpp:448 #, c-format msgid "%s is ready" msgstr "%s 準備好了" @@ -3430,21 +3622,21 @@ msgid "Axis %d" msgstr "第 %d 軸" #. I18N: to appear in input configuration screen, for gamepad buttons -#: src/input/binding.cpp:375 +#: src/input/binding.cpp:374 #, c-format msgid "Gamepad button %d" msgstr "手把按鈕 %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:378 +#: src/input/binding.cpp:377 #, c-format msgid "Mouse button %d" msgstr "滑鼠按鍵 %d" #. I18N: to appear in input configuration screen, for mouse (might not be used #. at all) -#: src/input/binding.cpp:382 +#: src/input/binding.cpp:381 #, c-format msgid "Mouse axis %d %s" msgstr "滑鼠軸 %d %s" @@ -3615,26 +3807,30 @@ msgstr "您最多有三條命!" msgid "+1 life." msgstr "+1 條命。" -#: src/karts/kart.cpp:1024 +#: src/karts/kart.cpp:1032 msgid "You were too slow!" msgstr "您太慢了!" -#: src/karts/kart.cpp:1025 +#: src/karts/kart.cpp:1033 +msgid "You finished the race!" +msgstr "您完成比賽了!" + +#: src/karts/kart.cpp:1034 msgid "You won the race!" msgstr "您贏得了這場比賽!" -#: src/karts/kart.cpp:1026 +#: src/karts/kart.cpp:1035 #, c-format msgid "You finished the race in rank %d!" msgstr "您以第 %d 名完成比賽!" #. I18N: Message shown in game to tell player left the game in network -#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1172 +#: src/karts/kart_rewinder.cpp:126 src/network/protocols/client_lobby.cpp:1173 #, c-format msgid "%s left the game." msgstr "%s 已離開遊戲。" -#: src/main.cpp:2034 +#: src/main.cpp:2042 msgid "" "SuperTuxKart may connect to a server to download add-ons and notify you of " "updates. Please read our privacy policy at https://supertuxkart.net/Privacy." @@ -3643,16 +3839,16 @@ msgid "" "Internet\")." msgstr "SuperTuxKart 可能會連線到伺服器下載附加元件並提醒您更新資訊。請到 https://supertuxkart.net/Privacy 詳閱我們的隱私權政策。您想要讓此功能開啟嗎?(若要在稍後改變這個設定,請到選項中,選取「一般」分頁,然後編輯「連線到網際網路」)。" -#: src/main.cpp:2386 +#: src/main.cpp:2393 msgid "Your screen resolution is too low to run STK." msgstr "您的螢幕解析度太低了,不能玩 SuperTuxKart。" -#: src/main.cpp:2437 +#: src/main.cpp:2444 msgid "" "Your driver version is too old. Please install the latest video drivers." msgstr "你的驅動程式版本太舊。請安裝最新的顯示卡驅動程式。" -#: src/main.cpp:2457 +#: src/main.cpp:2464 #, c-format msgid "" "Your graphics driver appears to be very old. Please check if an update is " @@ -3660,38 +3856,38 @@ msgid "" "game will likely still run, but in a reduced-graphics mode." msgstr "您的顯示卡驅動程式似乎很老舊了。請檢查是否有更新。SuperTuxKart 建議支援 %s 或更新的驅動程式。遊戲仍然可以執行,但會使用較低畫質的模式。" -#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:128 +#: src/main_loop.cpp:480 src/network/protocols/client_lobby.cpp:129 msgid "Server connection timed out." msgstr "伺服器連線逾時。" #. I18N: Show when a player gets the red flag in CTF -#: src/modes/capture_the_flag.cpp:191 +#: src/modes/capture_the_flag.cpp:190 #, c-format msgid "%s has the red flag!" msgstr "%s 有紅旗!" #. I18N: Show when the red flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:198 +#: src/modes/capture_the_flag.cpp:197 msgid "The red flag has returned!" msgstr "紅旗回來了!" #. I18N: Show when a player gets the blue flag in CTF -#: src/modes/capture_the_flag.cpp:209 +#: src/modes/capture_the_flag.cpp:208 #, c-format msgid "%s has the blue flag!" msgstr "%s 有藍旗!" #. I18N: Show when the blue flag is returned to its base in CTF -#: src/modes/capture_the_flag.cpp:216 +#: src/modes/capture_the_flag.cpp:215 msgid "The blue flag has returned!" msgstr "藍旗回來了!" -#: src/modes/capture_the_flag.cpp:424 +#: src/modes/capture_the_flag.cpp:408 #, c-format msgid "%s captured the blue flag!" msgstr "%s 搶得藍旗!" -#: src/modes/capture_the_flag.cpp:428 +#: src/modes/capture_the_flag.cpp:412 #, c-format msgid "%s captured the red flag!" msgstr "%s 搶得紅旗!" @@ -3701,7 +3897,7 @@ msgstr "%s 搶得紅旗!" msgid "Eggs: %d / %d" msgstr "復活節彩蛋:%d / %d" -#: src/modes/follow_the_leader.cpp:63 src/modes/follow_the_leader.cpp:297 +#: src/modes/follow_the_leader.cpp:64 src/modes/follow_the_leader.cpp:301 msgid "Leader" msgstr "領隊" @@ -3709,22 +3905,22 @@ msgstr "領隊" msgid "Final lap!" msgstr "最後一圈!" -#: src/modes/linear_world.cpp:447 +#: src/modes/linear_world.cpp:450 #, c-format msgid "Lap %i" msgstr "第 %i 圈" -#: src/modes/linear_world.cpp:549 +#: src/modes/linear_world.cpp:552 #, c-format msgctxt "fastest_lap" msgid "%s by %s" msgstr "%s 由 %s 跑完" -#: src/modes/linear_world.cpp:555 +#: src/modes/linear_world.cpp:558 msgid "New fastest lap" msgstr "新的最快圈速" -#: src/modes/linear_world.cpp:1097 +#: src/modes/linear_world.cpp:1100 msgid "WRONG WAY!" msgstr "方向錯誤!" @@ -3738,193 +3934,193 @@ msgstr "%s 射入球了!" msgid "Oops, %s made an own goal!" msgstr "喔喔,%s 射入烏龍球!" -#: src/modes/three_strikes_battle.cpp:641 +#: src/modes/three_strikes_battle.cpp:665 #, c-format msgid "%i spare tire kart has been spawned!" msgid_plural "%i spare tire karts have been spawned!" msgstr[0] "%i 備胎卡丁車已產生!" -#: src/modes/world.cpp:1427 +#: src/modes/world.cpp:1400 msgid "You have been eliminated!" msgstr "您已經被淘汰!" -#: src/modes/world.cpp:1434 +#: src/modes/world.cpp:1407 #, c-format msgid "'%s' has been eliminated." msgstr "「%s」已經被淘汰。" -#: src/network/protocols/client_lobby.cpp:129 +#: src/network/protocols/client_lobby.cpp:130 msgid "Server has been shut down." msgstr "伺服器已關機。" -#: src/network/protocols/client_lobby.cpp:130 +#: src/network/protocols/client_lobby.cpp:131 msgid "You were kicked from the server." msgstr "您被從伺服器踢出了。" -#: src/network/protocols/client_lobby.cpp:132 +#: src/network/protocols/client_lobby.cpp:133 msgid "You were kicked: Ping too high." msgstr "您被踢出去了:延遲太高。" -#: src/network/protocols/client_lobby.cpp:297 -#: src/network/protocols/client_lobby.cpp:911 +#: src/network/protocols/client_lobby.cpp:298 +#: src/network/protocols/client_lobby.cpp:912 msgid "Bad network connection is detected." msgstr "偵測到不穩定的網路連線。" -#: src/network/protocols/client_lobby.cpp:463 -#: src/network/protocols/server_lobby.cpp:3848 +#: src/network/protocols/client_lobby.cpp:464 +#: src/network/protocols/server_lobby.cpp:3240 msgid "Bot" msgstr "機器人" -#: src/network/protocols/client_lobby.cpp:641 +#: src/network/protocols/client_lobby.cpp:642 #, c-format msgid "%s disconnected." msgstr "%s 已斷線。" #. I18N: Message shown in network lobby to tell user that #. player name is clickable -#: src/network/protocols/client_lobby.cpp:672 +#: src/network/protocols/client_lobby.cpp:673 msgid "" "Press player name in the list for player management and ranking information." msgstr "在列表中按玩家名稱以管理玩家並取得排名資訊。" #. I18N: In the networking lobby #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:738 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 -#: src/states_screens/dialogs/server_info_dialog.cpp:97 -#: src/states_screens/race_result_gui.cpp:2014 +#: src/network/protocols/client_lobby.cpp:739 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:118 +#: src/states_screens/dialogs/server_info_dialog.cpp:98 +#: src/states_screens/race_result_gui.cpp:2127 #, c-format msgid "Difficulty: %s" msgstr "難度:%s" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:743 +#: src/network/protocols/client_lobby.cpp:744 #, c-format msgid "Max players: %d" msgstr "最多玩家:%d" #. I18N: In server info dialog -#: src/network/protocols/client_lobby.cpp:756 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:131 -#: src/states_screens/dialogs/server_info_dialog.cpp:101 +#: src/network/protocols/client_lobby.cpp:757 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:134 +#: src/states_screens/dialogs/server_info_dialog.cpp:102 #, c-format msgid "Game mode: %s" msgstr "遊戲模式:%s" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:769 +#: src/network/protocols/client_lobby.cpp:770 #: src/states_screens/dialogs/server_configuration_dialog.cpp:174 -#: src/states_screens/high_score_selection.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:253 -#: src/states_screens/track_info_screen.cpp:376 +#: src/states_screens/high_score_selection.cpp:161 +#: src/states_screens/online/create_server_screen.cpp:258 +#: src/states_screens/track_info_screen.cpp:375 msgid "Time limit" msgstr "時間限制" #. I18N: In the create server screen for soccer server -#: src/network/protocols/client_lobby.cpp:770 +#: src/network/protocols/client_lobby.cpp:771 #: src/states_screens/dialogs/server_configuration_dialog.cpp:175 -#: src/states_screens/online/create_server_screen.cpp:255 -#: src/states_screens/track_info_screen.cpp:377 +#: src/states_screens/online/create_server_screen.cpp:260 +#: src/states_screens/track_info_screen.cpp:376 msgid "Goals limit" msgstr "得分限制" #. I18N: In the networking lobby -#: src/network/protocols/client_lobby.cpp:774 +#: src/network/protocols/client_lobby.cpp:775 #, c-format msgid "Soccer game type: %s" msgstr "足球比賽類型:%s" -#: src/network/protocols/client_lobby.cpp:784 +#: src/network/protocols/client_lobby.cpp:785 #, c-format msgid "Grand prix progress: %d / %d" msgstr "大獎賽進度:%d/%d" #. I18N: Display when all players are in red or blue team, which the race #. will not be allowed to start -#: src/network/protocols/client_lobby.cpp:903 +#: src/network/protocols/client_lobby.cpp:904 msgid "All players joined red or blue team." msgstr "所有玩家都加入了紅或藍隊。" #. I18N: Display when a player is allow to control the server -#: src/network/protocols/client_lobby.cpp:923 +#: src/network/protocols/client_lobby.cpp:924 msgid "You are now the owner of server." msgstr "您現在是伺服器的擁有者。" -#: src/network/protocols/client_lobby.cpp:966 +#: src/network/protocols/client_lobby.cpp:967 msgid "Connection refused: Server is busy." msgstr "連線被拒絕:伺服器忙碌中。" -#: src/network/protocols/client_lobby.cpp:971 +#: src/network/protocols/client_lobby.cpp:972 msgid "Connection refused: You are banned from the server." msgstr "連線被拒絕:您被伺服器禁止進入。" -#: src/network/protocols/client_lobby.cpp:986 +#: src/network/protocols/client_lobby.cpp:987 msgid "Connection refused: Server password is incorrect." msgstr "連線被拒絕:伺服器密碼不正確。" -#: src/network/protocols/client_lobby.cpp:990 +#: src/network/protocols/client_lobby.cpp:991 msgid "Connection refused: Game data is incompatible." msgstr "連線被拒絕:遊戲資料不相容。" -#: src/network/protocols/client_lobby.cpp:994 +#: src/network/protocols/client_lobby.cpp:995 msgid "Connection refused: Server is full." msgstr "連線被拒絕:伺服器已滿。" -#: src/network/protocols/client_lobby.cpp:998 +#: src/network/protocols/client_lobby.cpp:999 msgid "Connection refused: Invalid player connecting." msgstr "連線被拒絕:無效的玩家連線。" -#: src/network/protocols/client_lobby.cpp:1026 +#: src/network/protocols/client_lobby.cpp:1027 msgid "Failed to start the network game." msgstr "開始網路遊戲失敗。" #. I18N: Error message shown if live join or spectate failed in network -#: src/network/protocols/client_lobby.cpp:1241 +#: src/network/protocols/client_lobby.cpp:1242 msgid "The game has ended, you can't live join or spectate anymore." msgstr "遊戲已經結束,您無法再加入或觀賽了。" #. I18N: Error message shown if live join failed in network -#: src/network/protocols/client_lobby.cpp:1245 +#: src/network/protocols/client_lobby.cpp:1246 msgid "No remaining place in the arena - live join disabled." msgstr "競技場沒有空間了,停用即時加入。" #. I18N: Error message shown if only 1 player remains in network -#: src/network/protocols/client_lobby.cpp:1249 +#: src/network/protocols/client_lobby.cpp:1250 msgid "Only 1 player remaining, returning to lobby." msgstr "僅剩 1 個玩家,回到大廳。" -#: src/network/protocols/client_lobby.cpp:1255 +#: src/network/protocols/client_lobby.cpp:1256 msgid "Server owner quit the game." msgstr "伺服器擁有者離開遊戲。" #. I18N: Status shown to player when he will be spectating the next game -#: src/network/protocols/client_lobby.cpp:1259 +#: src/network/protocols/client_lobby.cpp:1260 msgid "You will be spectating the next game." msgstr "您將會觀看下一場比賽。" #. I18N: Show when player join red team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1435 +#: src/network/protocols/client_lobby.cpp:1436 #, c-format msgid "%s joined the red team." msgstr "%s 已加入紅隊。" #. I18N: Show when player join blue team of the started game in #. network -#: src/network/protocols/client_lobby.cpp:1441 +#: src/network/protocols/client_lobby.cpp:1442 #, c-format msgid "%s joined the blue team." msgstr "%s 已加入藍隊。" #. I18N: Show when player join the started game in network -#: src/network/protocols/client_lobby.cpp:1447 +#: src/network/protocols/client_lobby.cpp:1448 #, c-format msgid "%s joined the game." msgstr "%s 已加入遊戲。" #. I18N: Message shown in game to tell the player it's possible to change #. the camera target in spectate mode of network -#: src/network/protocols/client_lobby.cpp:1638 +#: src/network/protocols/client_lobby.cpp:1639 #, c-format msgid "" "Press <%s> or <%s> to change the targeted player, <%s> or <%s> for the " @@ -3932,15 +4128,15 @@ msgid "" msgstr "按下 <%s> 或 <%s> 以變更目標玩家,<%s> 或 <%s> 變更攝影機位置。" #. I18N: Tell player he has successfully report this named player -#: src/network/protocols/client_lobby.cpp:1654 +#: src/network/protocols/client_lobby.cpp:1655 #, c-format msgid "Successfully reported %s." msgstr "已成功回報 %s。" #. I18N: Shown when there is download error for assets download #. in the first run -#: src/network/protocols/client_lobby.cpp:1940 -#: src/states_screens/dialogs/download_assets.cpp:251 +#: src/network/protocols/client_lobby.cpp:1942 +#: src/states_screens/dialogs/download_assets.cpp:256 msgid "" "Failed to download assets, check your storage space or internet connection " "and try again later." @@ -3971,56 +4167,56 @@ msgstr "競速計時(大獎賽)" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1292 +#: src/network/server_config.cpp:273 src/race/race_manager.cpp:1300 #: src/states_screens/dialogs/server_configuration_dialog.cpp:161 -#: src/states_screens/online/create_server_screen.cpp:237 -#: src/states_screens/track_info_screen.cpp:252 +#: src/states_screens/online/create_server_screen.cpp:242 +#: src/states_screens/track_info_screen.cpp:254 msgid "Free-For-All" msgstr "自由對戰" #. I18N: Game mode #. I18N: In the create server screen for battle server -#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1294 +#: src/network/server_config.cpp:275 src/race/race_manager.cpp:1302 #: src/states_screens/dialogs/server_configuration_dialog.cpp:162 -#: src/states_screens/online/create_server_screen.cpp:239 +#: src/states_screens/online/create_server_screen.cpp:244 msgid "Capture The Flag" msgstr "搶旗" -#: src/online/online_player_profile.cpp:455 +#: src/online/online_player_profile.cpp:456 #, c-format msgid "%s is now online." msgstr "%s 現在在線上。" -#: src/online/online_player_profile.cpp:459 +#: src/online/online_player_profile.cpp:460 #, c-format msgid "%s and %s are now online." msgstr "%s 與 %s 現在在線上。" -#: src/online/online_player_profile.cpp:464 +#: src/online/online_player_profile.cpp:465 #, c-format msgid "%s, %s and %s are now online." msgstr "%s、%s 與 %s 都在線上。" #. I18N: Only used for count > 3 -#: src/online/online_player_profile.cpp:470 +#: src/online/online_player_profile.cpp:471 #, c-format msgid "%d friend is now online." msgid_plural "%d friends are now online." msgstr[0] "現在有 %d 個朋友在線上。" #. I18N: Tell your friend if he is on any server in game -#: src/online/online_player_profile.cpp:519 +#: src/online/online_player_profile.cpp:520 #, c-format msgid "%s is now on server \"%s\"." msgstr "%s 在伺服器「%s」上。" -#: src/online/online_player_profile.cpp:550 +#: src/online/online_player_profile.cpp:551 #, c-format msgid "You have %d new friend request!" msgid_plural "You have %d new friend requests!" msgstr[0] "您有 %d 個新的朋友請求!" -#: src/online/online_player_profile.cpp:556 +#: src/online/online_player_profile.cpp:557 msgid "You have a new friend request!" msgstr "您有一個新的朋友請求!" @@ -4049,12 +4245,12 @@ msgid "" msgstr "高分榜的檔案格式太舊了,\n所有的高分紀錄都將被清除。" #. I18N: Game mode -#: src/race/race_manager.cpp:1286 +#: src/race/race_manager.cpp:1294 msgid "Follow the Leader" msgstr "緊隨領隊" #. I18N: Game mode -#: src/race/race_manager.cpp:1290 src/states_screens/track_info_screen.cpp:251 +#: src/race/race_manager.cpp:1298 src/states_screens/track_info_screen.cpp:253 msgid "3 Strikes Battle" msgstr "三擊對戰" @@ -4067,90 +4263,88 @@ msgstr "未完整的重播錄像不會被儲存。" msgid "Replay saved in \"%s\"." msgstr "重播錄像已儲存在「%s」。" -#: src/states_screens/addons_screen.cpp:49 +#: src/states_screens/addons_screen.cpp:51 msgid "1 week" msgstr "一週" -#: src/states_screens/addons_screen.cpp:50 +#: src/states_screens/addons_screen.cpp:52 msgid "2 weeks" msgstr "2 週" -#: src/states_screens/addons_screen.cpp:51 +#: src/states_screens/addons_screen.cpp:53 msgid "1 month" msgstr "一個月" -#: src/states_screens/addons_screen.cpp:52 +#: src/states_screens/addons_screen.cpp:54 msgid "3 months" msgstr "3 個月" -#: src/states_screens/addons_screen.cpp:53 +#: src/states_screens/addons_screen.cpp:55 msgid "6 months" msgstr "6 個月" -#: src/states_screens/addons_screen.cpp:54 +#: src/states_screens/addons_screen.cpp:56 msgid "9 months" msgstr "9 個月" -#: src/states_screens/addons_screen.cpp:55 +#: src/states_screens/addons_screen.cpp:57 msgid "1 year" msgstr "一年" -#: src/states_screens/addons_screen.cpp:56 +#: src/states_screens/addons_screen.cpp:58 msgid "2 years" msgstr "2 年" -#: src/states_screens/addons_screen.cpp:107 +#: src/states_screens/addons_screen.cpp:109 msgid "Add-on name" msgstr "附加元件名稱" -#: src/states_screens/addons_screen.cpp:108 +#: src/states_screens/addons_screen.cpp:110 msgid "Updated date" msgstr "更新日期" #. I18N: Addon not installed for fillter -#: src/states_screens/addons_screen.cpp:138 +#: src/states_screens/addons_screen.cpp:140 msgid "Not installed" msgstr "未安裝" #. I18N: as in: The Old Island by Johannes Sjolund -#: src/states_screens/addons_screen.cpp:325 +#: src/states_screens/addons_screen.cpp:326 #, c-format msgctxt "addons" msgid "%s by %s" msgstr "%s 由 %s 製作" -#: src/states_screens/addons_screen.cpp:446 +#: src/states_screens/addons_screen.cpp:447 msgid "Please wait while addons are updated" msgstr "附加元件更新中請稍待" -#: src/states_screens/addons_screen.cpp:526 -#: src/states_screens/main_menu_screen.cpp:631 +#: src/states_screens/addons_screen.cpp:527 +#: src/states_screens/main_menu_screen.cpp:671 msgid "" "Sorry, an error occurred while contacting the add-ons website. Make sure you" " are connected to the Internet and that SuperTuxKart is not blocked by a " "firewall" msgstr "抱歉,連接到附加元件網站時發生錯誤。請確定您已經連接到網際網路且 SuperTuxKart 沒有被防火牆阻擋。" -#: src/states_screens/arenas_screen.cpp:278 -#: src/states_screens/arenas_screen.cpp:330 -#: src/states_screens/easter_egg_screen.cpp:229 -#: src/states_screens/easter_egg_screen.cpp:260 -#: src/states_screens/kart_selection.cpp:957 -#: src/states_screens/kart_selection.cpp:1598 +#. I18N: track group name +#: src/states_screens/arenas_screen.cpp:89 +#: src/states_screens/tracks_and_gp_screen.cpp:183 +msgid "Favorites" +msgstr "最愛" + +#: src/states_screens/arenas_screen.cpp:331 +#: src/states_screens/easter_egg_screen.cpp:267 +#: src/states_screens/kart_selection.cpp:1008 +#: src/states_screens/kart_selection.cpp:1675 #: src/states_screens/race_setup_screen.cpp:101 msgid "Locked : solve active challenges to gain access to more!" msgstr "已鎖定:您必須先通過其它挑戰才能掌握更多!" -#: src/states_screens/arenas_screen.cpp:342 +#: src/states_screens/arenas_screen.cpp:351 msgid "Random Arena" msgstr "隨機競技場" -#: src/states_screens/arenas_screen.cpp:346 -#, c-format -msgid "%d arena unavailable in single player." -msgid_plural "%d arenas unavailable in single player." -msgstr[0] "%d 個競技場在單人遊戲中不適用。" - #: src/states_screens/credits.cpp:184 msgid "translator-credits" msgstr "Launchpad Contributions:\nBen Au, 2015\nBenau, 2016,2018-2020,2022\nBenau, 2015-2016\npan93412, 2018\nHsiu-Ming Chang, 2015\nHsiu-Ming Chang, 2015-2016\nHsiu-Ming Chang, 2015,2018-2020\n黃柏諺, 2015,2017-2019\nV字龍(Vdragon), 2015\n黃柏諺, 2019-2022\nBenau, 2016,2018-2020\n黃柏諺, 2019-2021\nBill\nCarl X. Su\nJeff Huang\nSTK-team\nWM\njyc\nminhsien\ntryneeds\nV字龍(Vdragon)" @@ -4438,7 +4632,7 @@ msgstr "已收集的香蕉" #: src/states_screens/dialogs/achievement_progress_dialog.cpp:256 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:260 #: src/states_screens/dialogs/achievement_progress_dialog.cpp:267 -#: src/states_screens/options/options_screen_device.cpp:284 +#: src/states_screens/options/options_screen_device.cpp:264 msgid "Skidding" msgstr "甩尾衝刺" @@ -4541,7 +4735,7 @@ msgstr "復活節彩蛋狩獵結束" msgid " (official tracks matching the goal)" msgstr "(符合目標的官方賽道)" -#: src/states_screens/dialogs/add_device_dialog.cpp:64 +#: src/states_screens/dialogs/add_device_dialog.cpp:48 msgid "" "New gamepads and joysticks will automatically appear in the list when you connect them to this device.\n" "\n" @@ -4549,91 +4743,95 @@ msgid "" msgstr "當您將新的遊戲手把與搖桿連線到此裝置時,其將會自動出現在清單中。\n\n要新增鍵盤設定,您可以使用下方按鈕,但請注意大多數鍵盤僅支援同時按下少量的按鍵,因此不適用於多人遊戲。(您還是可以將多把鍵盤連線到此裝置。但請記住每個人都還是要有不同的按鍵組合。)" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:87 +#: src/states_screens/dialogs/add_device_dialog.cpp:71 msgid "Add Wiimote" msgstr "新增 Wii 搖桿" #. I18N: In the 'add new input device' dialog -#: src/states_screens/dialogs/add_device_dialog.cpp:108 +#: src/states_screens/dialogs/add_device_dialog.cpp:88 msgid "Add Keyboard Configuration" msgstr "新增按鍵設定" -#: src/states_screens/dialogs/addons_loading.cpp:119 +#: src/states_screens/dialogs/addons_loading.cpp:126 msgid "Update" msgstr "更新" -#: src/states_screens/dialogs/addons_loading.cpp:131 +#: src/states_screens/dialogs/addons_loading.cpp:138 #, c-format msgid "Version: %d" msgstr "版本:%d" -#: src/states_screens/dialogs/addons_loading.cpp:162 +#: src/states_screens/dialogs/addons_loading.cpp:169 msgid "featured" msgstr "特色" #. I18N: File size of game assets or addons downloading -#: src/states_screens/dialogs/addons_loading.cpp:182 -#: src/states_screens/dialogs/addons_pack.cpp:208 -#: src/states_screens/dialogs/download_assets.cpp:104 +#: src/states_screens/dialogs/addons_loading.cpp:189 +#: src/states_screens/dialogs/addons_pack.cpp:213 +#: src/states_screens/dialogs/download_assets.cpp:109 #, c-format msgid "Size: %s" msgstr "大小:%s" -#: src/states_screens/dialogs/addons_loading.cpp:298 -#: src/states_screens/dialogs/addons_pack.cpp:220 -#: src/states_screens/dialogs/download_assets.cpp:201 +#: src/states_screens/dialogs/addons_loading.cpp:295 +msgid "You must be logged in to rate this addon." +msgstr "您必須登入以對此附加元件評分。" + +#: src/states_screens/dialogs/addons_loading.cpp:315 +#: src/states_screens/dialogs/addons_pack.cpp:225 +#: src/states_screens/dialogs/download_assets.cpp:206 msgid "Sorry, downloading the add-on failed" msgstr "附加元件下載失敗,抱歉" -#: src/states_screens/dialogs/addons_loading.cpp:374 +#: src/states_screens/dialogs/addons_loading.cpp:391 #, c-format msgid "Problems installing the addon '%s'." msgstr "安裝「%s」附加元件時遇到問題。" -#: src/states_screens/dialogs/addons_loading.cpp:385 -#: src/states_screens/dialogs/addons_loading.cpp:436 -#: src/states_screens/dialogs/download_assets.cpp:266 +#: src/states_screens/dialogs/addons_loading.cpp:402 +#: src/states_screens/dialogs/addons_loading.cpp:453 +#: src/states_screens/dialogs/download_assets.cpp:271 msgid "Try again" msgstr "再試一次" -#: src/states_screens/dialogs/addons_loading.cpp:425 +#: src/states_screens/dialogs/addons_loading.cpp:442 #, c-format msgid "Problems removing the addon '%s'." msgstr "移除「%s」附加元件時遇到問題。" -#: src/states_screens/dialogs/addons_pack.cpp:66 +#: src/states_screens/dialogs/addons_pack.cpp:71 msgid "Background download completed." msgstr "背景下載完成。" -#: src/states_screens/dialogs/addons_pack.cpp:127 +#: src/states_screens/dialogs/addons_pack.cpp:132 msgid "Background download" msgstr "背景下載" -#: src/states_screens/dialogs/addons_pack.cpp:136 +#: src/states_screens/dialogs/addons_pack.cpp:141 msgid "Background download has already started." msgstr "背景下載已開始。" -#: src/states_screens/dialogs/change_password_dialog.cpp:137 +#: src/states_screens/dialogs/change_password_dialog.cpp:140 msgid "Current password invalid." msgstr "目前的密碼無效。" -#: src/states_screens/dialogs/change_password_dialog.cpp:143 +#: src/states_screens/dialogs/change_password_dialog.cpp:146 #: src/states_screens/online/register_screen.cpp:382 msgid "Password has to be between 8 and 30 characters long!" msgstr "密碼必須在 8 至 30 個字元之間!" -#: src/states_screens/dialogs/change_password_dialog.cpp:150 +#: src/states_screens/dialogs/change_password_dialog.cpp:153 #: src/states_screens/online/register_screen.cpp:358 msgid "Passwords don't match!" msgstr "輸入的密碼不一致!" -#: src/states_screens/dialogs/change_password_dialog.cpp:235 -#: src/states_screens/dialogs/recovery_dialog.cpp:207 +#: src/states_screens/dialogs/change_password_dialog.cpp:238 +#: src/states_screens/dialogs/recovery_dialog.cpp:211 #: src/states_screens/online/register_screen.cpp:448 msgid "Validating info" msgstr "驗證資訊" -#: src/states_screens/dialogs/change_password_dialog.cpp:247 +#: src/states_screens/dialogs/change_password_dialog.cpp:250 msgid "Password successfully changed." msgstr "密碼成功變更。" @@ -4653,67 +4851,97 @@ msgstr "不支援小於 1024x768 或 1280x720 的解析度。部份介面可能 #. I18N: In the UI options, Camera setting: Drone chase #: src/states_screens/dialogs/custom_camera_settings.cpp:86 -#: src/states_screens/options/options_screen_ui.cpp:166 +#: src/states_screens/options/options_screen_ui.cpp:126 msgid "Drone chase" msgstr "無人機追逐" #. I18N: In the UI options, Camera setting: Custom #. I18N: custom video settings #: src/states_screens/dialogs/custom_camera_settings.cpp:103 -#: src/states_screens/options/options_screen_ui.cpp:162 -#: src/states_screens/options/options_screen_video.cpp:582 -#: src/states_screens/options/options_screen_video.cpp:620 -#: src/states_screens/options/options_screen_video.cpp:648 +#: src/states_screens/options/options_screen_ui.cpp:122 +#: src/states_screens/options/options_screen_video.cpp:364 +#: src/states_screens/options/options_screen_video.cpp:402 +#: src/states_screens/options/options_screen_video.cpp:430 msgid "Custom" msgstr "自訂" #. I18N: in the graphical options tooltip; #. indicates a graphical feature is disabled -#: src/states_screens/dialogs/custom_video_settings.cpp:69 -#: src/states_screens/dialogs/custom_video_settings.cpp:92 -#: src/states_screens/online/create_server_screen.cpp:217 -#: src/states_screens/options/options_screen_video.cpp:666 -#: src/states_screens/options/options_screen_video.cpp:737 +#: src/states_screens/dialogs/custom_video_settings.cpp:68 +#: src/states_screens/dialogs/custom_video_settings.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:222 +#: src/states_screens/options/options_screen_video.cpp:448 +#: src/states_screens/options/options_screen_video.cpp:535 msgid "Disabled" msgstr "已停用" #. I18N: if only important particles effects is enabled -#: src/states_screens/dialogs/custom_video_settings.cpp:70 -#: src/states_screens/options/options_screen_video.cpp:668 +#: src/states_screens/dialogs/custom_video_settings.cpp:69 +#: src/states_screens/options/options_screen_video.cpp:450 msgid "Important only" msgstr "僅重要的" -#. I18N: Geometry level disabled : lowest level, no details +#. I18N: Geometry level disabled : lowest level, Level-of-Details distances +#. are very low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is very low -#: src/states_screens/dialogs/custom_video_settings.cpp:76 -#: src/states_screens/dialogs/custom_video_settings.cpp:86 -#: src/states_screens/options/options_screen_video.cpp:672 +#: src/states_screens/dialogs/custom_video_settings.cpp:75 +#: src/states_screens/dialogs/custom_video_settings.cpp:95 +#: src/states_screens/options/options_screen_video.cpp:453 msgid "Very Low" msgstr "非常低" -#. I18N: Geometry level low : few details are displayed +#. I18N: Geometry level low : everything is displayed, Level-of-Details +#. distances are low #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is low -#: src/states_screens/dialogs/custom_video_settings.cpp:78 -#: src/states_screens/dialogs/custom_video_settings.cpp:87 -#: src/states_screens/dialogs/custom_video_settings.cpp:93 -#: src/states_screens/options/options_screen_video.cpp:675 +#: src/states_screens/dialogs/custom_video_settings.cpp:77 +#: src/states_screens/dialogs/custom_video_settings.cpp:96 +#: src/states_screens/dialogs/custom_video_settings.cpp:103 +#: src/states_screens/options/options_screen_video.cpp:455 msgid "Low" msgstr "低" -#. I18N: Geometry level high : everything is displayed +#. I18N: Geometry level medium : everything is displayed, Level-of-Details +#. distances are medium +#. I18N: kart class name +#. I18N: In the UI options, Medium font size +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:79 +#: src/states_screens/dialogs/custom_video_settings.cpp:97 +#: src/states_screens/dialogs/custom_video_settings.cpp:104 +#: src/states_screens/kart_selection.cpp:337 +#: src/states_screens/options/options_screen_ui.cpp:96 +#: src/states_screens/options/options_screen_video.cpp:457 +msgid "Medium" +msgstr "中" + +#. I18N: Geometry level high : everything is displayed, Level-of-Details +#. distances are high #. I18N: in the graphical options tooltip; -#. indicates the rendered image quality is high -#: src/states_screens/dialogs/custom_video_settings.cpp:80 -#: src/states_screens/dialogs/custom_video_settings.cpp:88 -#: src/states_screens/dialogs/custom_video_settings.cpp:94 -#: src/states_screens/options/options_screen_video.cpp:678 +#: src/states_screens/dialogs/custom_video_settings.cpp:81 +#: src/states_screens/dialogs/custom_video_settings.cpp:98 +#: src/states_screens/dialogs/custom_video_settings.cpp:105 +#: src/states_screens/options/options_screen_video.cpp:459 msgid "High" msgstr "高" +#. I18N: Geometry level very high : everything is displayed, Level-of-Details +#. distances are very high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:83 +#: src/states_screens/options/options_screen_video.cpp:461 +msgid "Very High" +msgstr "非常高" + +#. I18N: Geometry level ultra : everything is displayed, Level-of-Details +#. distances are extremely high +#. I18N: in the graphical options tooltip; +#: src/states_screens/dialogs/custom_video_settings.cpp:85 +#: src/states_screens/options/options_screen_video.cpp:463 +msgid "Ultra" +msgstr "超級" + #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:108 +#: src/states_screens/dialogs/download_assets.cpp:113 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience, this will use your mobile data if you " @@ -4721,7 +4949,7 @@ msgid "" msgstr "SuperTuxKart 將會下載完整遊戲資源(包含高品質貼圖與音樂)以取得更好的遊戲體驗,如果您沒有 wifi 連線的話,這將會使用您的行動數據。" #. I18N: In download assets dialog -#: src/states_screens/dialogs/download_assets.cpp:116 +#: src/states_screens/dialogs/download_assets.cpp:121 msgid "" "SuperTuxKart will download full assets (including high quality textures and " "music) for better gaming experience." @@ -4738,101 +4966,102 @@ msgstr "輸入伺服器地址,並選擇性用 : 後加入連接埠號,或從 msgid "Invalid server address: %s." msgstr "無效的伺服器位址:%s。" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:146 -#: src/states_screens/ghost_replay_selection.cpp:155 -#: src/states_screens/high_score_selection.cpp:154 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:150 +#: src/states_screens/ghost_replay_selection.cpp:159 +#: src/states_screens/high_score_selection.cpp:157 msgctxt "column_name" msgid "Reverse" msgstr "反向進行比賽" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:148 -#: src/states_screens/ghost_replay_selection.cpp:157 -#: src/states_screens/high_score_selection.cpp:141 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:152 +#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/high_score_selection.cpp:144 #: src/states_screens/online/server_selection.cpp:135 msgctxt "column_name" msgid "Difficulty" msgstr "難度" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:151 -#: src/states_screens/ghost_replay_selection.cpp:159 -#: src/states_screens/high_score_selection.cpp:152 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 +#: src/states_screens/ghost_replay_selection.cpp:163 +#: src/states_screens/high_score_selection.cpp:155 msgctxt "column_name" msgid "Laps" msgstr "圈" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:153 -#: src/states_screens/ghost_replay_selection.cpp:160 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 +#: src/states_screens/ghost_replay_selection.cpp:164 msgctxt "column_name" msgid "Time" msgstr "時間" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:155 -#: src/states_screens/ghost_replay_selection.cpp:161 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 +#: src/states_screens/ghost_replay_selection.cpp:165 msgctxt "column_name" msgid "Kart" msgstr "卡丁車" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:157 -#: src/states_screens/ghost_replay_selection.cpp:162 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:161 +#: src/states_screens/ghost_replay_selection.cpp:166 msgctxt "column_name" msgid "User" msgstr "使用者" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:159 -#: src/states_screens/ghost_replay_selection.cpp:166 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:163 +#: src/states_screens/ghost_replay_selection.cpp:170 msgctxt "column_name" msgid "Version" msgstr "版本" -#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:200 -#: src/states_screens/dialogs/high_score_info_dialog.cpp:135 +#: src/states_screens/dialogs/ghost_replay_info_dialog.cpp:204 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:138 #: src/states_screens/dialogs/message_dialog.cpp:132 +#: src/states_screens/dialogs/recommend_video_settings.cpp:60 #: src/states_screens/edit_gp_screen.cpp:261 -#: src/states_screens/ghost_replay_selection.cpp:388 +#: src/states_screens/ghost_replay_selection.cpp:394 #: src/states_screens/high_score_selection.cpp:265 msgid "No" msgstr "否" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:78 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:82 #: src/states_screens/edit_gp_screen.cpp:151 -#: src/states_screens/high_score_selection.cpp:138 +#: src/states_screens/high_score_selection.cpp:141 msgid "Track" msgstr "賽道" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:110 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:113 #, c-format msgid "Top %d High Scores" msgstr "前 %d 高分" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:112 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:115 #, c-format msgid "%s: %s" msgstr "%s:%s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:125 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:128 #, c-format msgid "Number of karts: %d" msgstr "卡丁車數量:%d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:137 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:140 #, c-format msgid "Time target: %s" msgstr "時間目標:%s" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:139 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:142 #, c-format msgid "Laps: %d" msgstr "圈數:%d" -#: src/states_screens/dialogs/high_score_info_dialog.cpp:143 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:146 #, c-format msgid "Reverse: %s" msgstr "反向:%s" #. I18N: for empty highscores entries -#: src/states_screens/dialogs/high_score_info_dialog.cpp:226 -#: src/states_screens/gp_info_screen.cpp:549 -#: src/states_screens/track_info_screen.cpp:539 +#: src/states_screens/dialogs/high_score_info_dialog.cpp:229 +#: src/states_screens/gp_info_screen.cpp:547 +#: src/states_screens/track_info_screen.cpp:538 msgid "(Empty)" msgstr "(無)" @@ -4920,33 +5149,41 @@ msgid "Press any key..." msgstr "按下任何按鈕……" #: src/states_screens/dialogs/race_paused_dialog.cpp:117 -#: src/states_screens/online/networking_lobby.cpp:249 -#: src/states_screens/online/networking_lobby.cpp:1003 +#: src/states_screens/online/networking_lobby.cpp:250 +#: src/states_screens/online/networking_lobby.cpp:1044 msgid "Chat is disabled, enable in options menu." msgstr "聊天已停用,到選單中啟用。" -#: src/states_screens/dialogs/race_paused_dialog.cpp:132 +#: src/states_screens/dialogs/race_paused_dialog.cpp:134 +msgid "Back to the Performance Test" +msgstr "回到效能測試" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +msgid "Exit the Performance Test" +msgstr "離開效能測試" + +#: src/states_screens/dialogs/race_paused_dialog.cpp:139 msgid "Back to Battle" msgstr "回到戰鬥" -#: src/states_screens/dialogs/race_paused_dialog.cpp:135 +#: src/states_screens/dialogs/race_paused_dialog.cpp:142 msgid "Setup New Game" msgstr "安排新遊戲" -#: src/states_screens/dialogs/race_paused_dialog.cpp:137 +#: src/states_screens/dialogs/race_paused_dialog.cpp:144 msgid "Restart Battle" msgstr "重新開始戰鬥" -#: src/states_screens/dialogs/race_paused_dialog.cpp:139 +#: src/states_screens/dialogs/race_paused_dialog.cpp:146 msgid "Exit Battle" msgstr "離開戰鬥" -#: src/states_screens/dialogs/race_paused_dialog.cpp:146 -#: src/states_screens/race_result_gui.cpp:350 +#: src/states_screens/dialogs/race_paused_dialog.cpp:153 +#: src/states_screens/race_result_gui.cpp:370 msgid "Setup New Race" msgstr "安排新賽事" -#: src/states_screens/dialogs/race_paused_dialog.cpp:150 +#: src/states_screens/dialogs/race_paused_dialog.cpp:157 msgid "Exit Race" msgstr "退出比賽" @@ -4962,11 +5199,11 @@ msgstr "%s 尚未有排名。" msgid "%s is number %d in the rankings with a score of %f." msgstr "%s 是第 %d 名,在排位賽中的分數為 %f。" -#: src/states_screens/dialogs/recovery_dialog.cpp:120 +#: src/states_screens/dialogs/recovery_dialog.cpp:124 msgid "Username and/or email address invalid." msgstr "使用者名稱及/或電子郵件位置無效。" -#: src/states_screens/dialogs/registration_dialog.cpp:42 +#: src/states_screens/dialogs/registration_dialog.cpp:43 #, c-format msgid "" "Please read the terms and conditions for SuperTuxKart at '%s'. You must " @@ -4988,7 +5225,7 @@ msgstr "重播錄像比賽" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:72 -#: src/states_screens/race_result_gui.cpp:1962 +#: src/states_screens/race_result_gui.cpp:2074 #, c-format msgid "Laps: %i" msgstr "圈數:%i" @@ -5001,21 +5238,21 @@ msgstr "類型:%s" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:90 -#: src/states_screens/race_result_gui.cpp:2119 +#: src/states_screens/race_result_gui.cpp:2249 #, c-format msgid "Required Rank: %i" msgstr "所需名次:%i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:96 -#: src/states_screens/race_result_gui.cpp:2127 +#: src/states_screens/race_result_gui.cpp:2258 #, c-format msgid "Required Time: %i" msgstr "所需時間:%i" #. I18N: In the Select challenge dialog #: src/states_screens/dialogs/select_challenge.cpp:103 -#: src/states_screens/race_result_gui.cpp:2138 +#: src/states_screens/race_result_gui.cpp:2270 #, c-format msgid "Required Nitro Points: %i" msgstr "需要的氮氣點數:%i" @@ -5028,54 +5265,54 @@ msgstr "電腦操控的賽車數量:%i" #. I18N: In the create server screen, show various battle mode available #: src/states_screens/dialogs/server_configuration_dialog.cpp:158 -#: src/states_screens/online/create_server_screen.cpp:233 +#: src/states_screens/online/create_server_screen.cpp:238 msgid "Battle mode" msgstr "對戰模式" #. I18N: In the create server screen #: src/states_screens/dialogs/server_configuration_dialog.cpp:171 -#: src/states_screens/online/create_server_screen.cpp:249 -#: src/states_screens/track_info_screen.cpp:364 +#: src/states_screens/online/create_server_screen.cpp:254 +#: src/states_screens/track_info_screen.cpp:363 msgid "Soccer game type" msgstr "足球遊戲類型" #. I18N: In the server info dialog, show the server location with #. country name (based on IP geolocation) -#: src/states_screens/dialogs/server_info_dialog.cpp:110 +#: src/states_screens/dialogs/server_info_dialog.cpp:111 #, c-format msgid "Server location: %s" msgstr "伺服器位置:%s" #. I18N: In server info dialog, showing the current track playing in server -#: src/states_screens/dialogs/server_info_dialog.cpp:119 +#: src/states_screens/dialogs/server_info_dialog.cpp:120 #, c-format msgid "Current track: %s" msgstr "目前的賽道:%s" -#: src/states_screens/dialogs/server_info_dialog.cpp:129 +#: src/states_screens/dialogs/server_info_dialog.cpp:130 msgid "Rank" msgstr "排名" #. I18N: Show above the player list in server info dialog, tell #. the user name on server -#: src/states_screens/dialogs/server_info_dialog.cpp:132 +#: src/states_screens/dialogs/server_info_dialog.cpp:133 msgid "Player" msgstr "玩家" #. I18N: Show above the player list in server info dialog, tell #. the scores of user calculated by player rankings -#: src/states_screens/dialogs/server_info_dialog.cpp:135 +#: src/states_screens/dialogs/server_info_dialog.cpp:136 msgid "Scores" msgstr "分數" #. I18N: Show above the player list in server info dialog, tell #. the user time played on server -#: src/states_screens/dialogs/server_info_dialog.cpp:138 +#: src/states_screens/dialogs/server_info_dialog.cpp:139 msgid "Time played" msgstr "玩家時間" -#: src/states_screens/dialogs/server_info_dialog.cpp:281 -#: src/states_screens/dialogs/server_info_dialog.cpp:296 +#: src/states_screens/dialogs/server_info_dialog.cpp:282 +#: src/states_screens/dialogs/server_info_dialog.cpp:297 msgid "Remove from bookmarks" msgstr "從書籤中移除" @@ -5088,74 +5325,74 @@ msgid "No player available for connecting to server." msgstr "沒有連線到伺服器的玩家可用。" #. I18N: In the user info dialog -#: src/states_screens/dialogs/user_info_dialog.cpp:56 +#: src/states_screens/dialogs/user_info_dialog.cpp:61 #, c-format msgid "Username: %s" msgstr "使用者名稱:%s" -#: src/states_screens/dialogs/user_info_dialog.cpp:60 +#: src/states_screens/dialogs/user_info_dialog.cpp:65 msgid "Cancel Request" msgstr "取消請求" -#: src/states_screens/dialogs/user_info_dialog.cpp:160 -#: src/states_screens/dialogs/user_info_dialog.cpp:217 +#: src/states_screens/dialogs/user_info_dialog.cpp:165 +#: src/states_screens/dialogs/user_info_dialog.cpp:222 msgid "Today" msgstr "今日" -#: src/states_screens/dialogs/user_info_dialog.cpp:164 +#: src/states_screens/dialogs/user_info_dialog.cpp:169 msgid "Friend request sent!" msgstr "朋友請求已寄出!" -#: src/states_screens/dialogs/user_info_dialog.cpp:221 +#: src/states_screens/dialogs/user_info_dialog.cpp:226 msgid "Friend request accepted!" msgstr "已接受朋友請求!" -#: src/states_screens/dialogs/user_info_dialog.cpp:273 +#: src/states_screens/dialogs/user_info_dialog.cpp:278 msgid "Friend request declined!" msgstr "朋友請求已拒絕!" -#: src/states_screens/dialogs/user_info_dialog.cpp:319 +#: src/states_screens/dialogs/user_info_dialog.cpp:324 msgid "Friend removed!" msgstr "朋友已移除!" -#: src/states_screens/dialogs/user_info_dialog.cpp:370 +#: src/states_screens/dialogs/user_info_dialog.cpp:375 msgid "Friend request cancelled!" msgstr "朋友請求已取消!" -#: src/states_screens/dialogs/user_info_dialog.cpp:480 +#: src/states_screens/dialogs/user_info_dialog.cpp:485 msgid "Processing" msgstr "處理中" -#: src/states_screens/dialogs/vote_dialog.cpp:169 +#: src/states_screens/dialogs/vote_dialog.cpp:178 msgid "Fetching last vote" msgstr "正在擷取最後的投票" -#: src/states_screens/dialogs/vote_dialog.cpp:188 +#: src/states_screens/dialogs/vote_dialog.cpp:197 msgid "You can adapt your previous rating by clicking the stars beneath." msgstr "您可以點擊下方的星星以修改先前的評分等級。" -#: src/states_screens/dialogs/vote_dialog.cpp:193 +#: src/states_screens/dialogs/vote_dialog.cpp:202 msgid "" "You have not yet voted for this addon. Select your desired rating by " "clicking the stars beneath" msgstr "您尚未對此附加元件投票。您可以點擊下方的星星以選取您想要的評分等級" -#: src/states_screens/dialogs/vote_dialog.cpp:227 +#: src/states_screens/dialogs/vote_dialog.cpp:236 msgid "Vote successful! You can now close the window." msgstr "投票成功!您現在可以關掉視窗了。" -#: src/states_screens/dialogs/vote_dialog.cpp:243 +#: src/states_screens/dialogs/vote_dialog.cpp:253 msgid "Performing vote" msgstr "執行投票" -#: src/states_screens/easter_egg_screen.cpp:274 -#: src/states_screens/online/tracks_screen.cpp:640 -#: src/states_screens/tracks_and_gp_screen.cpp:310 +#: src/states_screens/easter_egg_screen.cpp:287 +#: src/states_screens/online/tracks_screen.cpp:696 +#: src/states_screens/tracks_and_gp_screen.cpp:368 msgid "Random Track" msgstr "隨機賽道" #: src/states_screens/edit_gp_screen.cpp:117 -#: src/states_screens/ghost_replay_selection.cpp:507 +#: src/states_screens/ghost_replay_selection.cpp:513 #: src/states_screens/grand_prix_editor_screen.cpp:111 #, c-format msgid "Are you sure you want to remove '%s'?" @@ -5184,7 +5421,7 @@ msgstr "%s(+)" msgid "An error occurred while trying to save your grand prix." msgstr "嘗試儲存您的大獎賽時發生錯誤。" -#: src/states_screens/edit_track_screen.cpp:255 +#: src/states_screens/edit_track_screen.cpp:317 msgid "Select a track" msgstr "選擇賽道" @@ -5228,12 +5465,12 @@ msgstr "你解鎖了 %0 賽道" msgid "You unlocked grand prix %0" msgstr "你解鎖了 %0 大獎賽" -#: src/states_screens/ghost_replay_selection.cpp:153 +#: src/states_screens/ghost_replay_selection.cpp:157 msgctxt "column_name" msgid "Track" msgstr "賽道" -#: src/states_screens/ghost_replay_selection.cpp:164 +#: src/states_screens/ghost_replay_selection.cpp:168 #: src/states_screens/online/server_selection.cpp:134 msgctxt "column_name" msgid "Players" @@ -5254,19 +5491,19 @@ msgstr "請輸入大獎賽的名稱" msgid "Please select a Grand Prix" msgstr "請選擇一個大獎賽" -#: src/states_screens/grand_prix_editor_screen.cpp:336 +#: src/states_screens/grand_prix_editor_screen.cpp:338 msgid "User defined" msgstr "使用者定義" -#: src/states_screens/grand_prix_editor_screen.cpp:349 +#: src/states_screens/grand_prix_editor_screen.cpp:351 msgid "Name is empty." msgstr "名稱是空的。" -#: src/states_screens/grand_prix_editor_screen.cpp:357 +#: src/states_screens/grand_prix_editor_screen.cpp:359 msgid "Another grand prix with this name already exists." msgstr "已有其他同名的大獎賽存在。" -#: src/states_screens/grand_prix_editor_screen.cpp:363 +#: src/states_screens/grand_prix_editor_screen.cpp:365 msgid "Name is too long." msgstr "名稱太長。" @@ -5275,19 +5512,19 @@ msgstr "名稱太長。" msgid "Better luck next time!" msgstr "下次運氣會更好!" -#: src/states_screens/grand_prix_win.cpp:168 +#: src/states_screens/grand_prix_win.cpp:169 msgid "You completed a challenge!" msgstr "你完成了一項挑戰!" -#: src/states_screens/grand_prix_win.cpp:324 +#: src/states_screens/grand_prix_win.cpp:325 msgid "You won the Grand Prix!" msgstr "您贏了大獎賽!" -#: src/states_screens/grand_prix_win.cpp:325 +#: src/states_screens/grand_prix_win.cpp:326 msgid "You completed the Grand Prix!" msgstr "您完成了大獎賽!" -#: src/states_screens/high_score_selection.cpp:144 +#: src/states_screens/high_score_selection.cpp:147 msgctxt "column_name" msgid "Number of karts" msgstr "卡丁車數量" @@ -5300,110 +5537,125 @@ msgstr "您確定要移除此高分項目嗎?" msgid "Are you sure you want to remove all of your high scores?" msgstr "您確定您想要移除您所有的高分嗎?" -#: src/states_screens/kart_selection.cpp:447 +#. I18N: kart group name +#: src/states_screens/kart_selection.cpp:329 +msgid "Favorite" +msgstr "最愛" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:335 +msgid "Light" +msgstr "輕" + +#. I18N: kart class name +#: src/states_screens/kart_selection.cpp:339 +msgid "Heavy" +msgstr "重" + +#: src/states_screens/kart_selection.cpp:490 msgid "Connect a keyboard or gamepad to play splitscreen multiplayer" msgstr "將鍵盤或遊戲手把連線到此裝置以遊玩分割畫面多人遊戲" -#: src/states_screens/kart_selection.cpp:933 -#: src/states_screens/kart_selection.cpp:1616 +#: src/states_screens/kart_selection.cpp:984 +#: src/states_screens/kart_selection.cpp:1697 msgid "Random Kart" msgstr "隨機賽車" -#: src/states_screens/kart_selection.cpp:952 +#: src/states_screens/kart_selection.cpp:1003 msgid "Locked" msgstr "未解鎖" -#: src/states_screens/kart_selection.cpp:1053 -#: src/states_screens/online/networking_lobby.cpp:678 +#: src/states_screens/kart_selection.cpp:1104 +#: src/states_screens/online/networking_lobby.cpp:707 msgid "" "Everyone:\n" "Press the 'Select' button to join the game" msgstr "各位玩家:\n現在按「選擇」鍵來加入遊戲!" -#: src/states_screens/main_menu_screen.cpp:267 +#: src/states_screens/main_menu_screen.cpp:343 msgid "Would you like to play the tutorial of the game?" msgstr "您想要玩遊戲教學嗎?" -#: src/states_screens/main_menu_screen.cpp:563 -#: src/states_screens/online/online_screen.cpp:211 +#: src/states_screens/main_menu_screen.cpp:604 +#: src/states_screens/online/online_screen.cpp:327 msgid "" "You can not play online without internet access. If you want to play online," " go in the options menu, and check \"Connect to the Internet\"." msgstr "您無法在沒有網路連線時玩線上遊戲。若您想要玩線上遊戲,到選項中勾選「連線到網際網路」。" -#: src/states_screens/main_menu_screen.cpp:578 +#: src/states_screens/main_menu_screen.cpp:619 msgid "" "You can not download addons without internet access. If you want to download" " addons, go in the options menu, and check \"Connect to the Internet\"." msgstr "您無法在沒有網路時下載附加元件。如果您想要下載附加元件,到選項中勾選「連線到網際網路」。" -#: src/states_screens/main_menu_screen.cpp:586 +#: src/states_screens/main_menu_screen.cpp:627 msgid "" "You can not download addons without internet access. If you want to download addons, go in the options menu, and check \"Connect to the Internet\".\n" "\n" "You can however delete already downloaded addons." msgstr "您無法在沒有網路時下載附加元件。如果您想要下載附加元件,到選項中勾選「連線到網際網路」。\n\n您可以刪除已下載的附加元件。" -#: src/states_screens/main_menu_screen.cpp:626 +#: src/states_screens/main_menu_screen.cpp:666 msgid "The add-ons module is currently disabled in the Options screen" msgstr "這個附加元件目前在選項畫面中被停用" -#: src/states_screens/main_menu_screen.cpp:638 +#: src/states_screens/main_menu_screen.cpp:678 msgid "Please wait while the add-ons are loading" msgstr "附加元件載入中請稍待" -#: src/states_screens/main_menu_screen.cpp:659 +#: src/states_screens/main_menu_screen.cpp:699 msgid "Are you sure you want to quit STK?" msgstr "您確定您想要離開 STK 嗎?" -#: src/states_screens/online/create_server_screen.cpp:102 +#: src/states_screens/online/create_server_screen.cpp:107 msgid "Create LAN Server" msgstr "建立本機伺服器" -#: src/states_screens/online/create_server_screen.cpp:107 +#: src/states_screens/online/create_server_screen.cpp:112 #, c-format msgid "%s's server" msgstr "%s 的伺服器" #. I18N: In the create server screen -#: src/states_screens/online/create_server_screen.cpp:215 +#: src/states_screens/online/create_server_screen.cpp:220 msgid "No. of grand prix track(s)" msgstr "大獎賽賽道數量" -#: src/states_screens/online/create_server_screen.cpp:298 +#: src/states_screens/online/create_server_screen.cpp:303 msgid "Name has to be between 4 and 30 characters long!" msgstr "名稱須為 4 至 30 個字元長!" -#: src/states_screens/online/create_server_screen.cpp:315 +#: src/states_screens/online/create_server_screen.cpp:320 msgid "Incorrect characters in password!" msgstr "密碼中的字元不正確!" #. I18N: In the networking lobby, ready button is to allow player to tell #. server that he is ready for next game for owner less server -#: src/states_screens/online/networking_lobby.cpp:195 +#: src/states_screens/online/networking_lobby.cpp:196 msgid "Ready" msgstr "準備" #. I18N: Live join is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:198 +#: src/states_screens/online/networking_lobby.cpp:199 msgid "Live join" msgstr "即時加入" #. I18N: Spectate is displayed in networking lobby to allow players #. to join the current started in-progress game -#: src/states_screens/online/networking_lobby.cpp:203 +#: src/states_screens/online/networking_lobby.cpp:204 msgid "Spectate" msgstr "觀賽" -#: src/states_screens/online/networking_lobby.cpp:204 +#: src/states_screens/online/networking_lobby.cpp:205 msgid "Install addon" msgstr "安裝附加元件" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish with remaining time, #. showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:543 +#: src/states_screens/online/networking_lobby.cpp:572 #, c-format msgid "" "Please wait for the current game's (%s) end, estimated remaining time: %s." @@ -5411,7 +5663,7 @@ msgstr "請等待目前的遊戲(%s)結束,預估剩餘時間:%s。" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with remaining time -#: src/states_screens/online/networking_lobby.cpp:551 +#: src/states_screens/online/networking_lobby.cpp:580 #, c-format msgid "Please wait for the current game's end, estimated remaining time: %s." msgstr "請等待目前的遊戲結束,預估剩餘時間:%s。" @@ -5419,24 +5671,24 @@ msgstr "請等待目前的遊戲結束,預估剩餘時間:%s。" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent, showing the current track name inside bracket -#: src/states_screens/online/networking_lobby.cpp:563 +#: src/states_screens/online/networking_lobby.cpp:592 msgid "Please wait for the current game's (%s) end, estimated progress: %s%." msgstr "請等待目前的遊戲(%s)結束,預估進度:%d%。" #. I18N: In the networking lobby, show when player is required #. to wait before the current game finish with progress in #. percent -#: src/states_screens/online/networking_lobby.cpp:572 +#: src/states_screens/online/networking_lobby.cpp:601 msgid "Please wait for the current game's end, estimated progress: %d%." msgstr "請等待目前的遊戲結束,預估進度:%d%。" #. I18N: In the networking lobby, show when player is required to #. wait before the current game finish -#: src/states_screens/online/networking_lobby.cpp:580 +#: src/states_screens/online/networking_lobby.cpp:609 msgid "Please wait for the current game's end." msgstr "請等待目前的遊戲結束。" -#: src/states_screens/online/networking_lobby.cpp:647 +#: src/states_screens/online/networking_lobby.cpp:676 #, c-format msgid "Game will start if there is more than %d player." msgid_plural "Game will start if there are more than %d players." @@ -5444,7 +5696,7 @@ msgstr[0] "如果有多於 %d 個玩家時,遊戲將會開始。" #. I18N: In the networking lobby, display the starting timeout #. for owner-less server to begin a game -#: src/states_screens/online/networking_lobby.cpp:661 +#: src/states_screens/online/networking_lobby.cpp:690 #, c-format msgid "" "Starting after %d second, or once everyone has pressed the 'Ready' button." @@ -5452,96 +5704,108 @@ msgid_plural "" "Starting after %d seconds, or once everyone has pressed the 'Ready' button." msgstr[0] "在 %d 秒後開始,或是在每個人都按下「準備」鈕時開始。" -#: src/states_screens/online/networking_lobby.cpp:698 +#: src/states_screens/online/networking_lobby.cpp:727 #, c-format msgid "Connecting to server %s" msgstr "正在連線至伺服器 %s" -#: src/states_screens/online/networking_lobby.cpp:703 +#: src/states_screens/online/networking_lobby.cpp:732 msgid "Finding a quick play server" msgstr "正在尋找快速遊玩伺服器" #. I18N: In kart screen, show before the voting period in network ends. #: src/states_screens/online/network_kart_selection.cpp:218 -#: src/states_screens/online/tracks_screen.cpp:896 +#: src/states_screens/online/tracks_screen.cpp:952 #, c-format msgid "Remaining time: %d" msgstr "剩餘時間:%d" #. I18N: Goals in achievement -#: src/states_screens/online/online_profile_achievements.cpp:83 +#: src/states_screens/online/online_profile_achievements.cpp:85 msgid "Goals" msgstr "目標" -#: src/states_screens/online/online_profile_achievements.cpp:116 -#: src/states_screens/online/online_profile_achievements.cpp:315 +#: src/states_screens/online/online_profile_achievements.cpp:118 +#: src/states_screens/online/online_profile_achievements.cpp:317 msgid "Fetching achievements" msgstr "正在擷取成就" -#: src/states_screens/online/online_profile_base.cpp:117 +#: src/states_screens/online/online_profile_base.cpp:121 #, c-format msgid "%s's profile" msgstr "%s 的個人檔案" -#: src/states_screens/online/online_profile_friends.cpp:75 +#: src/states_screens/online/online_profile_friends.cpp:80 msgid "Since" msgstr "自" -#: src/states_screens/online/online_profile_friends.cpp:76 +#: src/states_screens/online/online_profile_friends.cpp:81 msgid "Status" msgstr "狀態" -#: src/states_screens/online/online_profile_friends.cpp:94 -#: src/states_screens/online/online_profile_friends.cpp:274 +#: src/states_screens/online/online_profile_friends.cpp:99 +#: src/states_screens/online/online_profile_friends.cpp:279 msgid "Fetching friends" msgstr "正在擷取朋友" -#: src/states_screens/online/online_profile_friends.cpp:236 +#: src/states_screens/online/online_profile_friends.cpp:241 msgid "New Request" msgstr "新請求" -#: src/states_screens/online/online_profile_friends.cpp:237 +#: src/states_screens/online/online_profile_friends.cpp:242 msgid "Pending" msgstr "等待處理中" -#: src/states_screens/online/online_profile_friends.cpp:241 +#: src/states_screens/online/online_profile_friends.cpp:246 msgid "Offline" msgstr "離線" -#: src/states_screens/online/online_profile_settings.cpp:79 +#: src/states_screens/online/online_profile_settings.cpp:83 msgid "Enter new E-mail below" msgstr "在下方輸入新的電子郵件" -#: src/states_screens/online/online_profile_settings.cpp:84 +#: src/states_screens/online/online_profile_settings.cpp:88 msgid "New Email has to be between 5 and 254 characters long!" msgstr "新電子郵件的長度必須在 5 到 254 個字元間!" -#: src/states_screens/online/online_profile_settings.cpp:93 +#: src/states_screens/online/online_profile_settings.cpp:97 msgid "New Email is invalid!" msgstr "新電子郵件無效!" -#: src/states_screens/online/online_profile_settings.cpp:118 +#: src/states_screens/online/online_profile_settings.cpp:122 msgid "E-mail changed!" msgstr "電子郵件已變更!" -#: src/states_screens/online/online_profile_settings.cpp:120 +#: src/states_screens/online/online_profile_settings.cpp:124 #, c-format msgid "Failed to change E-mail: %s" msgstr "變更電子郵件失敗:%s" +#: src/states_screens/online/online_screen.cpp:109 +msgid "News from STK Blog" +msgstr "來自 STK 部落格的新聞" + +#: src/states_screens/online/online_screen.cpp:110 +msgid "Date" +msgstr "日期" + +#: src/states_screens/online/online_screen.cpp:166 +msgid "There are currently no news available." +msgstr "目前沒有新聞。" + #. I18N: Shown to players when he is not is not logged in -#: src/states_screens/online/online_screen.cpp:201 +#: src/states_screens/online/online_screen.cpp:317 msgid "" "You must be logged in to play Global networking. Click your username above." msgstr "您必須登入以遊玩全球網路。點選上面的使用者名稱。" -#: src/states_screens/online/online_user_search.cpp:179 -#: src/states_screens/online/online_user_search.cpp:242 +#: src/states_screens/online/online_user_search.cpp:184 +#: src/states_screens/online/online_user_search.cpp:247 msgid "Searching" msgstr "正在搜尋" #: src/states_screens/online/register_screen.cpp:169 -#: src/states_screens/options/user_screen.cpp:127 +#: src/states_screens/options/user_screen.cpp:114 msgid "Exit game" msgstr "離開遊戲" @@ -5619,34 +5883,34 @@ msgid "Distance (km)" msgstr "距離(公里)" #. I18N: In server selection screen, unknown distance to server -#: src/states_screens/online/server_selection.cpp:318 +#: src/states_screens/online/server_selection.cpp:316 msgid "Unknown" msgstr "未知" #. I18N: Message shown to user if no IPv4 detected by STK -#: src/states_screens/online/server_selection.cpp:363 +#: src/states_screens/online/server_selection.cpp:361 msgid "No IPv4 detected, you may not be able to join any servers." msgstr "未偵測到 IPv4,您可能無法加入任何伺服器。" #. I18N: Message shown to user if no IPv6 detected by STK -#: src/states_screens/online/server_selection.cpp:365 +#: src/states_screens/online/server_selection.cpp:363 msgid "No IPv6 detected, you may not be able to join any servers." msgstr "未偵測到 IPv6,您可能無法加入任何伺服器。" -#: src/states_screens/online/server_selection.cpp:504 +#: src/states_screens/online/server_selection.cpp:502 msgid "No server is available." msgstr "沒有可玩的伺服器" -#: src/states_screens/online/server_selection.cpp:512 +#: src/states_screens/online/server_selection.cpp:510 msgid "Fetching servers" msgstr "正在擷取伺服器" -#: src/states_screens/online/server_selection.cpp:578 +#: src/states_screens/online/server_selection.cpp:576 msgid "Server Bookmarks" msgstr "伺服器書籤" #. I18N: In track screen for networking, clarify voting phase -#: src/states_screens/online/tracks_screen.cpp:318 +#: src/states_screens/online/tracks_screen.cpp:322 msgid "" "If a majority of players all select the same track and race settings, voting" " will end early." @@ -5654,149 +5918,149 @@ msgstr "如果大多數的玩家選擇了相同的賽道與比賽設定,投票 #. I18N: In track screen #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:474 -#: src/states_screens/online/tracks_screen.cpp:522 -#: src/states_screens/track_info_screen.cpp:303 +#: src/states_screens/online/tracks_screen.cpp:479 +#: src/states_screens/online/tracks_screen.cpp:527 +#: src/states_screens/track_info_screen.cpp:305 msgid "Random item location" msgstr "隨機物品位置" #. I18N: In track screen -#: src/states_screens/online/tracks_screen.cpp:504 -#: src/states_screens/track_info_screen.cpp:455 +#: src/states_screens/online/tracks_screen.cpp:509 +#: src/states_screens/track_info_screen.cpp:454 msgid "Number of goals to win" msgstr "獲勝的得分數量" #. I18N: In the track info screen -#: src/states_screens/online/tracks_screen.cpp:552 -#: src/states_screens/track_info_screen.cpp:298 +#: src/states_screens/online/tracks_screen.cpp:557 +#: src/states_screens/track_info_screen.cpp:300 msgid "Drive in reverse" msgstr "反向駕駛" -#: src/states_screens/online/tracks_screen.cpp:626 -#: src/states_screens/tracks_and_gp_screen.cpp:296 +#: src/states_screens/online/tracks_screen.cpp:675 +#: src/states_screens/tracks_and_gp_screen.cpp:348 msgid "Locked: solve active challenges to gain access to more!" msgstr "已鎖定:您必須先通過其它挑戰才能掌握更多!" -#: src/states_screens/options/options_screen_device.cpp:76 +#: src/states_screens/options/options_screen_device.cpp:56 msgid "Action" msgstr "動作" -#: src/states_screens/options/options_screen_device.cpp:77 +#: src/states_screens/options/options_screen_device.cpp:57 msgid "Key binding" msgstr "按鍵設置" #. I18N: button to disable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:108 -#: src/states_screens/options/options_screen_device.cpp:627 +#: src/states_screens/options/options_screen_device.cpp:88 +#: src/states_screens/options/options_screen_device.cpp:592 msgid "Disable Device" msgstr "停用裝置" #. I18N: button to enable a gamepad configuration -#: src/states_screens/options/options_screen_device.cpp:110 -#: src/states_screens/options/options_screen_device.cpp:628 +#: src/states_screens/options/options_screen_device.cpp:90 +#: src/states_screens/options/options_screen_device.cpp:593 msgid "Enable Device" msgstr "啟用裝置" #. I18N: button to enable a keyboard configuration -#: src/states_screens/options/options_screen_device.cpp:127 -#: src/states_screens/options/options_screen_device.cpp:633 +#: src/states_screens/options/options_screen_device.cpp:107 +#: src/states_screens/options/options_screen_device.cpp:598 msgid "Enable Configuration" msgstr "啟用設定" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:176 +#: src/states_screens/options/options_screen_device.cpp:156 msgid "Game Keys" msgstr "遊戲按鍵" #. I18N: Key binding section -#: src/states_screens/options/options_screen_device.cpp:190 +#: src/states_screens/options/options_screen_device.cpp:170 msgid "Menu Keys" msgstr "選單按鍵" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:266 +#: src/states_screens/options/options_screen_device.cpp:246 msgid "Steer Left" msgstr "左轉" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:269 +#: src/states_screens/options/options_screen_device.cpp:249 msgid "Steer Right" msgstr "右轉" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:272 +#: src/states_screens/options/options_screen_device.cpp:252 msgid "Accelerate" msgstr "加速" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:275 +#: src/states_screens/options/options_screen_device.cpp:255 msgid "Brake / Reverse" msgstr "煞車/倒車" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:278 +#: src/states_screens/options/options_screen_device.cpp:258 msgid "Fire" msgstr "射擊" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:281 +#: src/states_screens/options/options_screen_device.cpp:261 msgid "Nitro" msgstr "氮氣" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:287 +#: src/states_screens/options/options_screen_device.cpp:267 msgid "Look Back" msgstr "向後看" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:290 +#: src/states_screens/options/options_screen_device.cpp:270 msgid "Rescue" msgstr "救援" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:293 +#: src/states_screens/options/options_screen_device.cpp:273 msgid "Pause Game" msgstr "遊戲暫停" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:298 +#: src/states_screens/options/options_screen_device.cpp:278 msgid "Up" msgstr "上" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:301 +#: src/states_screens/options/options_screen_device.cpp:281 msgid "Down" msgstr "下" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:304 +#: src/states_screens/options/options_screen_device.cpp:284 msgid "Left" msgstr "左" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:307 +#: src/states_screens/options/options_screen_device.cpp:287 msgid "Right" msgstr "右" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:310 +#: src/states_screens/options/options_screen_device.cpp:290 msgid "Select" msgstr "選擇" #. I18N: Key binding name -#: src/states_screens/options/options_screen_device.cpp:313 +#: src/states_screens/options/options_screen_device.cpp:293 msgid "Cancel/Back" msgstr "取消/返回" -#: src/states_screens/options/options_screen_device.cpp:404 +#: src/states_screens/options/options_screen_device.cpp:384 msgid "* A blue item means a conflict with another configuration" msgstr "※ 藍色的項目表示與另一個項目有衝突" -#: src/states_screens/options/options_screen_device.cpp:409 +#: src/states_screens/options/options_screen_device.cpp:389 msgid "* A red item means a conflict in the current configuration" msgstr "※ 紅色的項目表示與目前的設定衝突" -#: src/states_screens/options/options_screen_device.cpp:514 +#: src/states_screens/options/options_screen_device.cpp:494 msgid "" "Warning: The 'Shift' is not a recommended key. When 'Shift' is pressed down," " all keys that contain a character that is different in upper-case will stop" @@ -5804,17 +6068,27 @@ msgid "" msgstr "注意:不建議使用「Shift」鍵。當 Shift 按下時,所有字母鍵會變換大小寫,因而無法使用。" #. I18N: shown before deleting an input configuration -#: src/states_screens/options/options_screen_device.cpp:613 +#: src/states_screens/options/options_screen_device.cpp:578 msgid "Are you sure you want to permanently delete this configuration?" msgstr "您確定要永久刪除這個設定?" -#: src/states_screens/options/options_screen_device.cpp:641 +#: src/states_screens/options/options_screen_device.cpp:606 msgid "Enter new configuration name, leave empty to revert default value." msgstr "輸入新的設定名稱,留空以復原為預設值。" +#. I18N: In the UI options, splitscreen_method in the race UI +#: src/states_screens/options/options_screen_display.cpp:57 +msgid "Vertical" +msgstr "垂直" + +#. I18N: In the UI options, splitscreen_method position in the race UI +#: src/states_screens/options/options_screen_display.cpp:59 +msgid "Horizontal" +msgstr "水平" + #. I18N: Tooltip in the UI menu. Use enough linebreaks to make sure the text #. fits the screen in low resolutions. -#: src/states_screens/options/options_screen_general.cpp:103 +#: src/states_screens/options/options_screen_general.cpp:69 msgid "" "In multiplayer mode, players can select handicapped\n" "(more difficult) profiles on the kart selection screen" @@ -5822,89 +6096,74 @@ msgstr "在多人模式中,玩家可以在賽車選取\n畫面中選取讓賽 #. I18N: For mobile version for STK, install the full game assets which #. will download from stk server -#: src/states_screens/options/options_screen_general.cpp:119 +#: src/states_screens/options/options_screen_general.cpp:85 msgid "Install full game assets" msgstr "安裝完整遊戲資源" -#: src/states_screens/options/options_screen_general.cpp:238 +#: src/states_screens/options/options_screen_general.cpp:189 msgid "Are you sure to uninstall full game assets?" msgstr "您確定要解除安裝完整遊戲資源嗎?" -#: src/states_screens/options/options_screen_input.cpp:119 +#: src/states_screens/options/options_screen_input.cpp:98 #, c-format msgid "Keyboard %i" msgstr "鍵盤 %i" -#: src/states_screens/options/options_screen_input.cpp:170 +#: src/states_screens/options/options_screen_input.cpp:149 msgid "Touch Device" msgstr "觸控裝置" #. I18N: In the input configuration screen, help for touch device -#: src/states_screens/options/options_screen_input.cpp:207 +#: src/states_screens/options/options_screen_input.cpp:186 msgid "Tap on a device to configure it" msgstr "點擊裝置以設定" #. I18N: in the language choice, to select the same language as the OS -#: src/states_screens/options/options_screen_language.cpp:90 +#: src/states_screens/options/options_screen_language.cpp:62 msgid "System Language" msgstr "使用系統語系" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:95 +#: src/states_screens/options/options_screen_ui.cpp:67 msgid "In the bottom-left" msgstr "在左下角" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:97 +#: src/states_screens/options/options_screen_ui.cpp:69 msgid "On the right side" msgstr "在右邊" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:99 +#: src/states_screens/options/options_screen_ui.cpp:71 msgid "Hidden" msgstr "已隱藏" #. I18N: In the UI options, minimap position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:101 +#: src/states_screens/options/options_screen_ui.cpp:73 msgid "Centered" msgstr "置中" -#. I18N: In the UI options, splitscreen_method in the race UI -#: src/states_screens/options/options_screen_ui.cpp:119 -msgid "Vertical" -msgstr "垂直" - -#. I18N: In the UI options, splitscreen_method position in the race UI -#: src/states_screens/options/options_screen_ui.cpp:121 -msgid "Horizontal" -msgstr "水平" - #. I18N: In the UI options, Very small font size -#: src/states_screens/options/options_screen_ui.cpp:132 +#: src/states_screens/options/options_screen_ui.cpp:92 msgid "Very small" msgstr "非常小" #. I18N: In the UI options, Small font size -#: src/states_screens/options/options_screen_ui.cpp:134 +#: src/states_screens/options/options_screen_ui.cpp:94 msgid "Small" msgstr "小" -#. I18N: In the UI options, Medium font size -#: src/states_screens/options/options_screen_ui.cpp:136 -msgid "Medium" -msgstr "中" - #. I18N: In the UI options, Large font size -#: src/states_screens/options/options_screen_ui.cpp:138 +#: src/states_screens/options/options_screen_ui.cpp:98 msgid "Large" msgstr "大" #. I18N: In the UI options, Very large font size -#: src/states_screens/options/options_screen_ui.cpp:140 +#: src/states_screens/options/options_screen_ui.cpp:100 msgid "Very large" msgstr "非常大" -#: src/states_screens/options/options_screen_ui.cpp:502 +#: src/states_screens/options/options_screen_ui.cpp:537 msgid "" "Speedrun mode can only be enabled if the game has not been closed since the launch of the story mode.\n" "\n" @@ -5914,128 +6173,133 @@ msgid "" msgstr "競速模式已停用。它僅能在故事模式啟動後,遊戲尚未關閉前啟用。\n\n在故事模式完成前關閉遊戲會讓計時器無效。\n\n要使用競速模式,請使用新的設定檔。" #. I18N: In the video options -#: src/states_screens/options/options_screen_video.cpp:259 +#: src/states_screens/options/options_screen_video.cpp:249 msgid "Vertical Sync" msgstr "垂直同步" #. I18N: in graphical options. The \n is a newline character, place it where #. appropriate, two can be used if required. -#: src/states_screens/options/options_screen_video.cpp:276 +#: src/states_screens/options/options_screen_video.cpp:266 msgid "" "Vsync forces the graphics card to supply a new frame\n" "only when the monitor is ready to display it." msgstr "垂直同步強制顯示卡僅在顯示器\n準備好時才發送下一個畫面。" #. I18N: in graphical options. -#: src/states_screens/options/options_screen_video.cpp:279 +#: src/states_screens/options/options_screen_video.cpp:269 msgid "Vsync will not work if your drivers don't support it." msgstr "如果您的驅動程式不支援,垂直同步將無法運作。" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:681 +#: src/states_screens/options/options_screen_video.cpp:466 #, c-format msgid "Particles Effects: %s" msgstr "粒子特效:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:687 +#: src/states_screens/options/options_screen_video.cpp:472 #, c-format msgid "Animated Characters: %s" msgstr "角色動畫:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:690 +#: src/states_screens/options/options_screen_video.cpp:475 #, c-format msgid "Dynamic lights: %s" msgstr "動態燈光:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:693 +#: src/states_screens/options/options_screen_video.cpp:478 #, c-format msgid "Light scattering: %s" msgstr "光散射:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:696 +#: src/states_screens/options/options_screen_video.cpp:481 #, c-format msgid "Anti-aliasing: %s" msgstr "反鋸齒:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:699 +#: src/states_screens/options/options_screen_video.cpp:484 #, c-format msgid "Ambient occlusion: %s" msgstr "環境光遮蔽:%s" -#: src/states_screens/options/options_screen_video.cpp:703 +#: src/states_screens/options/options_screen_video.cpp:488 #, c-format msgid "Shadows: %s" msgstr "陰影:%s" -#: src/states_screens/options/options_screen_video.cpp:705 +#: src/states_screens/options/options_screen_video.cpp:490 #, c-format msgid "Shadows: %i" msgstr "陰影:%i" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:708 +#: src/states_screens/options/options_screen_video.cpp:493 #, c-format msgid "Bloom: %s" msgstr "光暈:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:712 +#: src/states_screens/options/options_screen_video.cpp:497 #, c-format msgid "Glow (outlines): %s" msgstr "光輝(外框):%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:716 +#: src/states_screens/options/options_screen_video.cpp:501 #, c-format msgid "Light shaft (God rays): %s" msgstr "一道光(上帝射線):%s" -#: src/states_screens/options/options_screen_video.cpp:721 +#: src/states_screens/options/options_screen_video.cpp:506 #, c-format msgid "Rendered image quality: %s" msgstr "彩現圖片品質:%s" +#: src/states_screens/options/options_screen_video.cpp:515 +#, c-format +msgid "Geometry detail: %s" +msgstr "幾何細節:%s" + #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:740 +#: src/states_screens/options/options_screen_video.cpp:538 #, c-format msgid "Motion blur: %s" msgstr "動態模糊:%s" #. I18N: in graphical options -#: src/states_screens/options/options_screen_video.cpp:744 +#: src/states_screens/options/options_screen_video.cpp:542 #, c-format msgid "Depth of field: %s" msgstr "景深:%s" -#: src/states_screens/options/user_screen.cpp:366 +#: src/states_screens/options/user_screen.cpp:353 msgid "Internet access is disabled. Do you want to enable it?" msgstr "網路存取已停用。您想要啟用它嗎?" -#: src/states_screens/options/user_screen.cpp:554 +#: src/states_screens/options/user_screen.cpp:541 msgid "You need to enter a password." msgstr "您必須輸入密碼。" -#: src/states_screens/options/user_screen.cpp:575 +#: src/states_screens/options/user_screen.cpp:562 #, c-format msgid "Logging out '%s'" msgstr "正在登出「%s」" -#: src/states_screens/options/user_screen.cpp:576 +#: src/states_screens/options/user_screen.cpp:563 #, c-format msgid "Logging in '%s'" msgstr "正在登入「%s」" -#: src/states_screens/options/user_screen.cpp:659 +#: src/states_screens/options/user_screen.cpp:646 msgid "You can't delete the only player." msgstr "您無法刪除僅有的玩家。" #. I18N: In the player info dialog (when deleting) -#: src/states_screens/options/user_screen.cpp:667 +#: src/states_screens/options/user_screen.cpp:654 #, c-format msgid "Do you really want to delete player '%s'?" msgstr "您確定要刪除玩家 %s 嗎?" @@ -6063,7 +6327,7 @@ msgstr "得分!" #. I18N: Shown waiting for other players in network to finish loading or #. waiting #: src/states_screens/race_gui_base.cpp:82 -#: src/states_screens/race_result_gui.cpp:409 +#: src/states_screens/race_result_gui.cpp:429 msgid "Waiting for others" msgstr "等待其他人中" @@ -6098,7 +6362,7 @@ msgstr "緊隨領隊!" msgid "Top %i" msgstr "前 %i 名" -#: src/states_screens/race_gui.cpp:447 +#: src/states_screens/race_gui.cpp:445 msgid "Challenge Failed" msgstr "挑戰失敗" @@ -6122,102 +6386,199 @@ msgstr "按頒獎臺圖示以開始挑戰" msgid "Press fire to start the challenge" msgstr "請按「射擊」開始這場挑戰" -#: src/states_screens/race_result_gui.cpp:269 +#: src/states_screens/race_result_gui.cpp:268 +msgid "Back to video settings" +msgstr "回到視訊設定" + +#: src/states_screens/race_result_gui.cpp:272 +msgid "Save the test results" +msgstr "儲存測試結果" + +#: src/states_screens/race_result_gui.cpp:275 +msgid "Back to main menu" +msgstr "回到主選單" + +#: src/states_screens/race_result_gui.cpp:289 msgid "Quit the server" msgstr "離開伺服器" -#: src/states_screens/race_result_gui.cpp:310 +#: src/states_screens/race_result_gui.cpp:330 msgid "Abort Grand Prix" msgstr "放棄大獎賽" -#: src/states_screens/race_result_gui.cpp:330 +#: src/states_screens/race_result_gui.cpp:350 msgid "Restart" msgstr "重新開始" -#: src/states_screens/race_result_gui.cpp:337 +#: src/states_screens/race_result_gui.cpp:357 msgid "Back to challenge selection" msgstr "回到挑戰選擇" -#: src/states_screens/race_result_gui.cpp:345 +#: src/states_screens/race_result_gui.cpp:365 msgid "Race against the new ghost replay" msgstr "與新的重播錄像一起比賽" -#: src/states_screens/race_result_gui.cpp:353 +#: src/states_screens/race_result_gui.cpp:373 msgid "Back to the menu" msgstr "回到選單" -#: src/states_screens/race_result_gui.cpp:536 +#: src/states_screens/race_result_gui.cpp:556 msgid "Do you really want to abort the Grand Prix?" msgstr "你真的想放棄大獎賽?" -#: src/states_screens/race_result_gui.cpp:636 -#: src/states_screens/race_result_gui.cpp:1529 +#: src/states_screens/race_result_gui.cpp:578 +#, c-format +msgid "Performance report saved in \"%s\"." +msgstr "效能測試已儲存在「%s」。" + +#: src/states_screens/race_result_gui.cpp:690 +#: src/states_screens/race_result_gui.cpp:1590 msgid "Red Team Wins" msgstr "紅隊贏了" -#: src/states_screens/race_result_gui.cpp:638 -#: src/states_screens/race_result_gui.cpp:1533 +#: src/states_screens/race_result_gui.cpp:692 +#: src/states_screens/race_result_gui.cpp:1592 msgid "Blue Team Wins" msgstr "藍隊贏了" -#: src/states_screens/race_result_gui.cpp:640 -#: src/states_screens/race_result_gui.cpp:1538 +#: src/states_screens/race_result_gui.cpp:694 +#: src/states_screens/race_result_gui.cpp:1594 msgid "It's a draw" msgstr "平手" -#: src/states_screens/race_result_gui.cpp:881 +#: src/states_screens/race_result_gui.cpp:935 #, c-format msgid "Eliminated after %s" msgstr "在 %s 後淘汰" -#: src/states_screens/race_result_gui.cpp:886 -#: src/states_screens/race_result_gui.cpp:1334 +#: src/states_screens/race_result_gui.cpp:940 +#: src/states_screens/race_result_gui.cpp:1396 msgid "Eliminated" msgstr "被淘汰" #. I18N: indicates a player that scored in their own goal in result screen -#: src/states_screens/race_result_gui.cpp:1608 -#: src/states_screens/race_result_gui.cpp:1670 +#: src/states_screens/race_result_gui.cpp:1681 msgid "(Own Goal)" msgstr "(烏龍球)" -#: src/states_screens/race_result_gui.cpp:1749 +#: src/states_screens/race_result_gui.cpp:1770 #, c-format msgid "Track %i/%i" msgstr "賽道 %i/%i" -#: src/states_screens/race_result_gui.cpp:1833 +#: src/states_screens/race_result_gui.cpp:1889 msgid "Grand Prix progress:" msgstr "大獎賽進度:" -#: src/states_screens/race_result_gui.cpp:1879 +#: src/states_screens/race_result_gui.cpp:1975 msgid "Highscores" msgstr "最高分數" -#: src/states_screens/race_result_gui.cpp:2028 +#: src/states_screens/race_result_gui.cpp:2142 #, c-format msgid "Best lap time: %s" msgstr "最佳單圈成績:%s" #. I18N: is used to indicate who has the bast laptime (best laptime "by #. kart_name") -#: src/states_screens/race_result_gui.cpp:2042 +#: src/states_screens/race_result_gui.cpp:2155 #, c-format msgid "by %s" msgstr "由 %s" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You completed the challenge!" msgstr "您完成了挑戰!" -#: src/states_screens/race_result_gui.cpp:2104 +#: src/states_screens/race_result_gui.cpp:2229 msgid "You failed the challenge!" msgstr "您挑戰失敗!" -#: src/states_screens/race_result_gui.cpp:2155 +#: src/states_screens/race_result_gui.cpp:2282 msgid "Reached Requirements of SuperTux" msgstr "達到 SuperTux 的要求" +#: src/states_screens/race_result_gui.cpp:2353 +msgid "Performance Test Results" +msgstr "效能測試結果" + +#: src/states_screens/race_result_gui.cpp:2369 +#, c-format +msgid "Test duration: %s" +msgstr "測試持續時間:%s" + +#: src/states_screens/race_result_gui.cpp:2371 +#, c-format +msgid "Number of frames: %s" +msgstr "畫面數量:%s" + +#: src/states_screens/race_result_gui.cpp:2373 +#, c-format +msgid "Steady FPS: %s" +msgstr "穩定的 FPS:%s" + +#: src/states_screens/race_result_gui.cpp:2375 +#, c-format +msgid "Mostly Steady FPS: %s" +msgstr "大致穩定的 FPS:%s" + +#: src/states_screens/race_result_gui.cpp:2377 +#, c-format +msgid "Typical FPS: %s" +msgstr "一般 FPS:%s" + +#: src/states_screens/race_result_gui.cpp:2391 +#, c-format +msgid "Horizontal resolution: %s" +msgstr "水平解析度:%s" + +#: src/states_screens/race_result_gui.cpp:2393 +#, c-format +msgid "Vertical resolution: %s" +msgstr "垂直解析度:%s" + +#: src/states_screens/race_result_gui.cpp:2394 +msgid "Dynamic lighting: ON" +msgstr "動態照明:開啟" + +#: src/states_screens/race_result_gui.cpp:2395 +msgid "Dynamic lighting: OFF" +msgstr "動態照明:關閉" + +#: src/states_screens/race_result_gui.cpp:2398 +#, c-format +msgid "Render resolution: %s%%" +msgstr "繪圖解析度:%s%%" + +#: src/states_screens/race_result_gui.cpp:2399 +msgid "Anti-aliasing: ON" +msgstr "反鋸齒:開啟" + +#: src/states_screens/race_result_gui.cpp:2400 +msgid "Anti-aliasing : OFF" +msgstr "反鋸齒:關閉" + +#: src/states_screens/race_result_gui.cpp:2401 +msgid "Image-based lighting: OFF" +msgstr "以影像為基礎的照明:關閉" + +#: src/states_screens/race_result_gui.cpp:2402 +msgid "Image-based lighting: ON" +msgstr "以影像為基礎的照明:開啟" + +#: src/states_screens/race_result_gui.cpp:2403 +msgid "Ambient occlusion: ON" +msgstr "環境光遮蔽:開啟" + +#: src/states_screens/race_result_gui.cpp:2404 +msgid "Ambient occlusion: OFF" +msgstr "環境光遮蔽:關閉" + +#: src/states_screens/race_result_gui.cpp:2406 +#, c-format +msgid "Shadow resolution: %s" +msgstr "陰影解析度:%s" + #: src/states_screens/race_setup_screen.cpp:89 msgid "All blows allowed, so catch weapons and make clever use of them!" msgstr "可以使用所有的攻擊手段,收集武器並巧妙的使用它們吧!" @@ -6258,28 +6619,28 @@ msgstr "按紅色或藍色足球按鈕圖示來變更隊伍" #. I18N: when showing who is the author of track '%s' #. I18N: (place %s where the name of the author should appear) -#: src/states_screens/track_info_screen.cpp:149 +#: src/states_screens/track_info_screen.cpp:151 #, c-format msgid "Track by %s" msgstr "賽道作者:%s" #. I18N: the max players supported by an arena. -#: src/states_screens/track_info_screen.cpp:157 +#: src/states_screens/track_info_screen.cpp:159 #, c-format msgid "Max players supported: %d" msgstr "最大玩家支持數目:%d" -#: src/states_screens/track_info_screen.cpp:390 +#: src/states_screens/track_info_screen.cpp:389 msgid "Number of red team AI karts" msgstr "紅隊的電腦玩家數量" -#: src/states_screens/tracks_and_gp_screen.cpp:109 +#: src/states_screens/tracks_and_gp_screen.cpp:124 msgid "" "You cannot play this Grand Prix because it contains tracks that aren't " "unlocked!" msgstr "您無法遊玩此大獎賽,因為其包含了尚未解鎖的賽道!" -#: src/states_screens/tracks_and_gp_screen.cpp:217 +#: src/states_screens/tracks_and_gp_screen.cpp:245 msgid "Locked!" msgstr "已鎖定!" @@ -6301,10 +6662,12 @@ msgid "%d/%m/%Y" msgstr "%d/%m/%Y" #: ../stk-assets/tracks/overworld/scripting.as:15 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:15 msgid "Complete all challenges to unlock the big door!" msgstr "完成所有挑戰以解開大門的鎖!" #: ../stk-assets/tracks/overworld/scripting.as:63 +#: ../supertuxkart-assets/tracks/overworld/scripting.as:63 msgid "" "You need more points\n" "to enter this challenge!\n" @@ -6313,41 +6676,48 @@ msgid "" msgstr "您需要更多的點數\n來進入這個挑戰!\n在小地圖上檢查\n可用的挑戰。" #: ../stk-assets/tracks/tutorial/scripting.as:8 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:8 #, c-format msgid "Accelerate with <%s>, and steer with <%s> and <%s>." msgstr "用 <%s> 加速,用 <%s> 和 <%s> 轉彎。" #: ../stk-assets/tracks/tutorial/scripting.as:17 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:17 msgid "" "Accelerate by touching the upper part of the wheel, and steer by moving left" " or right." msgstr "點擊方向盤的上方以加速,向左或向右移動以轉向。" #: ../stk-assets/tracks/tutorial/scripting.as:22 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:22 msgid "" "Accelerate by moving the accelerator upwards, and steer by tilting your " "device." msgstr "向上移動加速器以加速,傾斜您的裝置以轉向。" #: ../stk-assets/tracks/tutorial/scripting.as:27 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:27 msgid "" "Accelerate by moving the accelerator upwards, and steer by rotating your " "device." msgstr "向上移動加速器以加速,旋轉您的裝置以轉向。" #: ../stk-assets/tracks/tutorial/scripting.as:59 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:59 #, c-format msgid "" "Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!" msgstr "收集禮物盒,並用 <%s> 發射武器,來炸飛這些箱子!" #: ../stk-assets/tracks/tutorial/scripting.as:67 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:67 msgid "" "Collect gift boxes, and fire by pressing the bowling icon to blow away these" " boxes!" msgstr "蒐集禮物盒,並按下保齡球的圖示以將其他盒子吹走!" #: ../stk-assets/tracks/tutorial/scripting.as:78 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:78 #, c-format msgid "" "Press <%s> to look behind.\n" @@ -6355,34 +6725,41 @@ msgid "" msgstr "按下 <%s> 以向後看。\n並按下 <%s> 加上 <%s> 以向後開火!" #: ../stk-assets/tracks/tutorial/scripting.as:88 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:88 msgid "" "Press the mirror icon to look behind.\n" "Fire the weapon behind by holding the mirror icon and then swiping to the bowling icon!" msgstr "按鏡子的圖示來向後看。\n按住鏡子圖示,然後拖曳到保齡球的圖示上,向後開火!" #: ../stk-assets/tracks/tutorial/scripting.as:98 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:98 #, c-format msgid "Use the nitro you collected by pressing <%s>!" msgstr "按 <%s> 使用你收集的氮氣!" #: ../stk-assets/tracks/tutorial/scripting.as:104 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:104 msgid "Use the nitro you collected by pressing the nitro icon" msgstr "按下氮氣的圖示以使用您收集到的氮氣" #: ../stk-assets/tracks/tutorial/scripting.as:112 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:112 msgid "Collect nitro bottles (we will use them after the curve)." msgstr "收集氮氣罐(我們將在轉彎之後使用它們)。" #: ../stk-assets/tracks/tutorial/scripting.as:121 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:121 #, c-format msgid "Oops! When you're in trouble, press <%s> to be rescued." msgstr "糟糕!當你有麻煩時,按 <%s> 被救援。" #: ../stk-assets/tracks/tutorial/scripting.as:127 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:127 msgid "Oops! When you're in trouble, press the bird icon to be rescued." msgstr "喔喔!當您陷入麻煩時,按下鳥的圖示以回到賽道。" #: ../stk-assets/tracks/tutorial/scripting.as:137 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:137 #, c-format msgid "" "Accelerate and press the <%s> key while turning to skid.\n" @@ -6390,24 +6767,27 @@ msgid "" msgstr "轉彎時加速並按下 <%s> 鍵來甩尾。\n甩尾了一會兒可以幫助你更快地急轉彎。" #: ../stk-assets/tracks/tutorial/scripting.as:145 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:145 msgid "" "Accelerate and press the skid icon while turning to skid.\n" "Skidding for a short while can help you turn faster to take sharp turns." msgstr "加速並在轉彎時按下甩尾圖示。\n短時間的甩尾可以協助您更快地轉彎。" #: ../stk-assets/tracks/tutorial/scripting.as:156 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:156 msgid "" "Note that if you manage to skid for several seconds, you will receive a " "bonus speedup as a reward!" msgstr "請注意,如果你成功甩尾數秒鐘,你將獲得額外加速作為獎勵!" #: ../stk-assets/tracks/tutorial/scripting.as:164 +#: ../supertuxkart-assets/tracks/tutorial/scripting.as:164 msgid "You are now ready to race. Good luck!" msgstr "你現在已準備好比賽。祝你好運!" #. I18N: Generic name in desktop file entry, summary in AppData and short #. description in Google Play -#: supertuxkart.desktop:4 supertuxkart.appdata.xml:6 +#: supertuxkart.desktop:4 net.supertuxkart.SuperTuxKart.metainfo.xml:7 msgid "A 3D open-source kart racing game" msgstr "3D 開源卡丁車賽車遊戲" @@ -6417,7 +6797,7 @@ msgstr "3D 開源卡丁車賽車遊戲" msgid "tux;game;race;" msgstr "tux;game;race;" -#: supertuxkart.appdata.xml:8 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:9 msgid "" "Karts. Nitro. Action! SuperTuxKart is a 3D open-source arcade racer with a " "variety of characters, tracks, and modes to play. Our aim is to create a " @@ -6425,7 +6805,7 @@ msgid "" "for all ages." msgstr "卡丁車。氮氣。行動! SuperTuxKart 是一款 3D 開源卡丁車賽車遊戲,具有多種角色,賽道和遊戲模式。我們的目標是創造一款比逼真更有趣的遊戲,並為所有年齡層的用戶提供愉悅的體驗。" -#: supertuxkart.appdata.xml:11 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:12 msgid "" "We have several tracks with various themes for players to enjoy, from " "driving underwater, rural farmlands, jungles or even in space! Try your best" @@ -6434,7 +6814,7 @@ msgid "" "your opponents." msgstr "我們有幾條不同主題的賽道供玩家享受,從水下賽車、農村農田、叢林,甚至是在太空中!盡量避開其他卡丁車,因為他們可能會超過您,但不要吃香蕉!注意對手投擲的保齡球、活塞、泡泡糖與蛋糕。" -#: supertuxkart.appdata.xml:14 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:15 msgid "" "You can do a single race against other karts, compete in one of several " "Grand Prix, try to beat the high score in time trials on your own, play " @@ -6443,27 +6823,27 @@ msgid "" "your racing skills!" msgstr "您可以與其他卡丁車進行單場比賽,參加大獎賽,嘗試在計時賽中獨自擊敗高分玩家,與電腦或是您的朋友進行對戰模式等等!如果想要有更強的挑戰,請與世界各地的玩家進行線上遊戲以證明您的賽車技術!" -#: supertuxkart.appdata.xml:17 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:18 msgid "This game has no ads." msgstr "此遊戲無廣告。" -#: supertuxkart.appdata.xml:20 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:21 msgid "" "This is an unstable version of SuperTuxKart that contains latest " "improvements. It is released mainly for testing, to make stable STK as good " "as possible." msgstr "這是 SuperTuxKart 的不穩定版本,當中包含了最新的改進。它主要是為了測試而發布,使 STK 的穩定版本盡善盡美。" -#: supertuxkart.appdata.xml:23 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:24 msgid "" "This version can be installed in parallel with the stable version on the " "device." msgstr "此版本可與在設備上的穩定版本同時安裝。" -#: supertuxkart.appdata.xml:26 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:27 msgid "If you need more stability, consider using the stable version: %s" msgstr "如果需要更高的穩定性,請考慮使用穩定版本:%s" -#: supertuxkart.appdata.xml:44 +#: net.supertuxkart.SuperTuxKart.metainfo.xml:45 msgid "SuperTuxKart Team" msgstr "SuperTuxKart 團隊" From f4d39befff7744d91bdc45b5bc417b61108c0883 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 2 May 2025 14:12:12 +0200 Subject: [PATCH 687/830] Update the changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd5416a8129..f61ff08932e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ For similar reasons, and because some features are vastly more complex than othe ### User Interface * Allow users to select favorite karts/tracks/arenas, by Alayan and CodingJellyfish * Five new skin variants for Cartoon, and a new Desert skin variant for Classic, by Alayan and CrystalDaEevee +* Allow displaying more elements in kart and track selection, and ensure there is no need to scroll to pick a game mode, by Alayan * Improve the skin selection UX by separating "base theme" and "skin variant" selection, by Alayan * Add a new Display tab in the Settings, by Alayan * Allow users to search karts/arenas, by CodingJellyfish @@ -73,6 +74,7 @@ For similar reasons, and because some features are vastly more complex than othe * Implement a blog announcement system in the Online screen, by CodingJellyfish * Various UI layout improvements (especially for 'tall' resolutions), by CodingJellyfish * Generate higher resolution texture for scalable fonts, by CodingJellyfish +* Fix for multiple keyboard navigation issues, by Alayan * Various enhancements, by QwertyChouskie, Nomagno, Nstelt and others #### In-race UI @@ -90,6 +92,8 @@ For similar reasons, and because some features are vastly more complex than othe #### Tracks * Fix Northern Resort skybox, by CrystalDaEevee * Various cut/checkline fixes, by CrystalDaEevee +* Fix a cut in Hacienda, by Sven Andreas Belting +* Add egg hunts for Black Forest, Gran Paradisio Island and Old Mine, by Sven Andreas Belting and Alayan #### Karts * Update Godette face texture, by ZAQraven99 From 0d71d6b600787e8377dbba0fef651b9a4a94511d Mon Sep 17 00:00:00 2001 From: Deve Date: Fri, 2 May 2025 21:06:27 +0200 Subject: [PATCH 688/830] Apply bullet patch to support backface culling From https://github.com/bulletphysics/bullet3/commit/c2f9d927c2349ac91ec9fedce0a2cb45e8c3b82f --- .../CollisionDispatch/btCollisionWorld.cpp | 12 ++++++---- .../CollisionDispatch/btCollisionWorld.h | 13 +++++++---- .../btRaycastCallback.cpp | 23 ++++++++++--------- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/lib/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp b/lib/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp index ee64dc677f0..96631999f8c 100644 --- a/lib/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp +++ b/lib/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp @@ -207,6 +207,11 @@ void btCollisionWorld::updateAabbs() } +void btCollisionWorld::computeOverlappingPairs() +{ + BT_PROFILE("calculateOverlappingPairs"); + m_broadphasePairCache->calculateOverlappingPairs(m_dispatcher1); +} void btCollisionWorld::performDiscreteCollisionDetection() { @@ -216,11 +221,7 @@ void btCollisionWorld::performDiscreteCollisionDetection() updateAabbs(); - { - BT_PROFILE("calculateOverlappingPairs"); - m_broadphasePairCache->calculateOverlappingPairs(m_dispatcher1); - } - + computeOverlappingPairs(); btDispatcher* dispatcher = getDispatcher(); { @@ -446,6 +447,7 @@ void btCollisionWorld::rayTestSingle(const btTransform& rayFromTrans,const btTra : m_userCallback(user), m_i(i) { m_closestHitFraction = m_userCallback->m_closestHitFraction; + m_flags = m_userCallback->m_flags; } virtual bool needsCollision(btBroadphaseProxy* p) const { diff --git a/lib/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.h b/lib/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.h index 0a92d2d6e15..9830d774eae 100644 --- a/lib/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.h +++ b/lib/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.h @@ -144,6 +144,11 @@ class btCollisionWorld void updateSingleAabb(btCollisionObject* colObj); virtual void updateAabbs(); + + ///the computeOverlappingPairs is usually already called by performDiscreteCollisionDetection (or stepSimulation) + ///it can be useful to use if you perform ray tests without collision detection/simulation + virtual void computeOverlappingPairs(); + virtual void setDebugDrawer(btIDebugDraw* debugDrawer) { @@ -198,8 +203,8 @@ class btCollisionWorld btCollisionObject* m_collisionObject; short int m_collisionFilterGroup; short int m_collisionFilterMask; - //@BP Mod - Custom flags, currently used to enable backface culling on tri-meshes, see btRaycastCallback - unsigned int m_flags; + //@BP Mod - Custom flags, currently used to enable backface culling on tri-meshes, see btRaycastCallback.h. Apply any of the EFlags defined there on m_flags here to invoke. + unsigned int m_flags; virtual ~RayResultCallback() { @@ -214,8 +219,8 @@ class btCollisionWorld m_collisionObject(0), m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter), m_collisionFilterMask(btBroadphaseProxy::AllFilter), - //@BP Mod - m_flags(0) + //@BP Mod + m_flags(0) { } diff --git a/lib/bullet/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp b/lib/bullet/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp index fbe579ce1e5..786efd18200 100644 --- a/lib/bullet/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp +++ b/lib/bullet/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp @@ -57,12 +57,13 @@ void btTriangleRaycastCallback::processTriangle(btVector3* triangle,int partId, { return ; // same sign } - //@BP Mod - Backface filtering - if (((m_flags & kF_FilterBackfaces) != 0) && (dist_a > btScalar(0.0))) - { - // Backface, skip check - return; - } + + if (((m_flags & kF_FilterBackfaces) != 0) && (dist_a <= btScalar(0.0))) + { + // Backface, skip check + return; + } + const btScalar proj_length=dist_a-dist_b; const btScalar distance = (dist_a)/(proj_length); @@ -97,18 +98,18 @@ void btTriangleRaycastCallback::processTriangle(btVector3* triangle,int partId, if ( (btScalar)(cp2.dot(triangleNormal)) >=edge_tolerance) { - //@BP Mod - // Triangle normal isn't normalized + //@BP Mod + // Triangle normal isn't normalized triangleNormal.normalize(); - //@BP Mod - Allow for unflipped normal when raycasting against backfaces - if (((m_flags & kF_KeepUnflippedNormal) != 0) || (dist_a <= btScalar(0.0))) + //@BP Mod - Allow for unflipped normal when raycasting against backfaces + if (((m_flags & kF_KeepUnflippedNormal) == 0) && (dist_a <= btScalar(0.0))) { m_hitFraction = reportHit(-triangleNormal,distance,partId,triangleIndex); } else { - m_hitFraction = reportHit(triangleNormal,distance,partId,triangleIndex); + m_hitFraction = reportHit(triangleNormal,distance,partId,triangleIndex); } } } From ae83f1a0018d97cef8fc19da3f0c9496d4577c6d Mon Sep 17 00:00:00 2001 From: Deve Date: Fri, 2 May 2025 21:28:05 +0200 Subject: [PATCH 689/830] Apply bullet patch to fix undefined behaviour From https://github.com/bulletphysics/bullet3/commit/0d3940b8bd46cb32408ab626285491acf906b429 --- .../BroadphaseCollision/btOverlappingPairCache.h | 9 +++------ lib/bullet/src/LinearMath/btHashMap.h | 12 ++++++------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h b/lib/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h index aed8e745a6f..4b71c5a58ec 100644 --- a/lib/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h +++ b/lib/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h @@ -202,10 +202,9 @@ class btHashedOverlappingPairCache : public btOverlappingPairCache */ - - SIMD_FORCE_INLINE unsigned int getHash(unsigned int proxyId1, unsigned int proxyId2) + SIMD_FORCE_INLINE unsigned int getHash(unsigned int proxyId1, unsigned int proxyId2) { - int key = static_cast(((unsigned int)proxyId1) | (((unsigned int)proxyId2) <<16)); + unsigned int key = proxyId1 | (proxyId2 << 16); // Thomas Wang's hash key += ~(key << 15); @@ -214,13 +213,11 @@ class btHashedOverlappingPairCache : public btOverlappingPairCache key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); - return static_cast(key); + return key; } - - SIMD_FORCE_INLINE btBroadphasePair* internalFindPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1, int hash) { int proxyId1 = proxy0->getUid(); diff --git a/lib/bullet/src/LinearMath/btHashMap.h b/lib/bullet/src/LinearMath/btHashMap.h index ce07db3ac6b..d2b4317fcbf 100644 --- a/lib/bullet/src/LinearMath/btHashMap.h +++ b/lib/bullet/src/LinearMath/btHashMap.h @@ -100,9 +100,10 @@ class btHashInt //to our success SIMD_FORCE_INLINE unsigned int getHash()const { - int key = m_uid; + unsigned int key = m_uid; // Thomas Wang's hash key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); + return key; } }; @@ -115,7 +116,7 @@ class btHashPtr union { const void* m_pointer; - int m_hashValues[2]; + unsigned int m_hashValues[2]; }; public: @@ -140,8 +141,7 @@ class btHashPtr { const bool VOID_IS_8 = ((sizeof(void*)==8)); - int key = VOID_IS_8? m_hashValues[0]+m_hashValues[1] : m_hashValues[0]; - + unsigned int key = VOID_IS_8? m_hashValues[0]+m_hashValues[1] : m_hashValues[0]; // Thomas Wang's hash key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return key; @@ -174,7 +174,7 @@ class btHashKeyPtr //to our success SIMD_FORCE_INLINE unsigned int getHash()const { - int key = m_uid; + unsigned int key = m_uid; // Thomas Wang's hash key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return key; @@ -206,7 +206,7 @@ class btHashKey //to our success SIMD_FORCE_INLINE unsigned int getHash()const { - int key = m_uid; + unsigned int key = m_uid; // Thomas Wang's hash key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return key; From 4d4a4695ae6b94e938039bf334c40fc6d5050597 Mon Sep 17 00:00:00 2001 From: Deve Date: Fri, 2 May 2025 22:40:17 +0200 Subject: [PATCH 690/830] More undefined behaviour fixes --- .../source/Irrlicht/CGUIScrollBar.cpp | 3 +++ lib/irrlicht/source/Irrlicht/CSkinnedMesh.cpp | 1 + lib/irrlicht/source/Irrlicht/CSkinnedMesh.h | 22 ------------------- src/graphics/slip_stream.cpp | 2 ++ src/karts/controller/ai_properties.cpp | 2 +- src/race/race_manager.hpp | 2 +- src/utils/string_utils.cpp | 2 +- 7 files changed, 9 insertions(+), 25 deletions(-) diff --git a/lib/irrlicht/source/Irrlicht/CGUIScrollBar.cpp b/lib/irrlicht/source/Irrlicht/CGUIScrollBar.cpp index be153e6aeb6..6c46b9fe3a4 100644 --- a/lib/irrlicht/source/Irrlicht/CGUIScrollBar.cpp +++ b/lib/irrlicht/source/Irrlicht/CGUIScrollBar.cpp @@ -349,6 +349,9 @@ void CGUIScrollBar::setPos(s32 pos) { Pos = core::s32_clamp ( pos, Min, Max ); + if ( !core::isnotzero ( range() ) ) + return; + if (Horizontal) { f32 f = (RelativeRect.getWidth() - ((f32)RelativeRect.getHeight()*3.0f)) / range(); diff --git a/lib/irrlicht/source/Irrlicht/CSkinnedMesh.cpp b/lib/irrlicht/source/Irrlicht/CSkinnedMesh.cpp index 0c745530a55..868be740b36 100644 --- a/lib/irrlicht/source/Irrlicht/CSkinnedMesh.cpp +++ b/lib/irrlicht/source/Irrlicht/CSkinnedMesh.cpp @@ -938,6 +938,7 @@ void CSkinnedMesh::finalize() //Set array sizes... + Vertices_Moved.reallocate(LocalBuffers.size()); for (i=0; i() ); diff --git a/lib/irrlicht/source/Irrlicht/CSkinnedMesh.h b/lib/irrlicht/source/Irrlicht/CSkinnedMesh.h index 39580157e39..28b739b16ac 100644 --- a/lib/irrlicht/source/Irrlicht/CSkinnedMesh.h +++ b/lib/irrlicht/source/Irrlicht/CSkinnedMesh.h @@ -14,16 +14,6 @@ #include "matrix4.h" #include "quaternion.h" -class JointInfluence -{ -public: - int joint_idx; - float weight; -}; - -typedef irr::core::array > > WeightInfluence; - namespace irr { namespace scene @@ -166,10 +156,6 @@ namespace scene IAnimatedMeshSceneNode* node, ISceneManager* smgr); - void convertForSkinning(); - - void computeWeightInfluence(SJoint *joint, size_t &index, WeightInfluence& wi); - void buildAllGlobalAnimatedMatrices(SJoint *Joint=0, SJoint *ParentJoint=0); f32 AnimationFrames; @@ -196,14 +182,6 @@ namespace scene void skinJoint(SJoint *Joint, SJoint *ParentJoint, f32 strength=1.f); - void calculateTangents(core::vector3df& normal, - core::vector3df& tangent, core::vector3df& binormal, - core::vector3df& vt1, core::vector3df& vt2, core::vector3df& vt3, - core::vector2df& tc1, core::vector2df& tc2, core::vector2df& tc3); - - static bool sortJointInfluenceFunc(const JointInfluence& a, - const JointInfluence& b); - core::array *SkinningBuffers; //Meshbuffer to skin, default is to skin localBuffers core::array LocalBuffers; diff --git a/src/graphics/slip_stream.cpp b/src/graphics/slip_stream.cpp index 55c91d19e53..294a89744f2 100644 --- a/src/graphics/slip_stream.cpp +++ b/src/graphics/slip_stream.cpp @@ -644,6 +644,8 @@ void SlipStream::updateBonusTexture() if (!CVS->isGLSL()) { float a = m_bonus_time * 255.0f; + if (a < 0.0f) + a = 0.0f; if (a > 255.0f) a = 255.0f; m_bonus_node->getMaterial(0).getRenderInfo()->getVertexColor() diff --git a/src/karts/controller/ai_properties.cpp b/src/karts/controller/ai_properties.cpp index 99666c10970..d4ff1e80bd8 100644 --- a/src/karts/controller/ai_properties.cpp +++ b/src/karts/controller/ai_properties.cpp @@ -28,7 +28,7 @@ float AIProperties::UNDEFINED = -99.9f; */ AIProperties::AIProperties(RaceManager::Difficulty difficulty) { - m_ident = RaceManager::get()->getDifficultyAsString(difficulty); + m_ident = RaceManager::getDifficultyAsString(difficulty); m_max_item_angle = UNDEFINED; m_max_item_angle_high_speed = UNDEFINED; diff --git a/src/race/race_manager.hpp b/src/race/race_manager.hpp index 18870138048..58c7c85cca4 100644 --- a/src/race/race_manager.hpp +++ b/src/race/race_manager.hpp @@ -601,7 +601,7 @@ class RaceManager Difficulty getDifficulty() const { return m_difficulty; } // ---------------------------------------------------------------------------------------- /** Returns the specified difficulty as a string. */ - std::string getDifficultyAsString(Difficulty diff) const + static std::string getDifficultyAsString(Difficulty diff) { switch(diff) { diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index e963827006d..c561d8d7502 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -1093,7 +1093,7 @@ namespace StringUtils utf8::utf32to16(chars, chars + input.size(), back_inserter(wchar_line)); } - else if (sizeof(wchar_t) == sizeof(char32_t)) + else if (sizeof(wchar_t) == sizeof(char32_t) && !input.empty()) { wchar_line.resize(input.size()); memcpy(wchar_line.data(), input.c_str(), From 5efc6ac95970e3c0fc3f6bf913e8ab0d6827cdf5 Mon Sep 17 00:00:00 2001 From: Deve Date: Fri, 2 May 2025 23:11:05 +0200 Subject: [PATCH 691/830] Fix assertion when using favourite karts uninitialized --- src/karts/kart_properties_manager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/karts/kart_properties_manager.cpp b/src/karts/kart_properties_manager.cpp index 80af96f66bb..bb0d5523ea4 100644 --- a/src/karts/kart_properties_manager.cpp +++ b/src/karts/kart_properties_manager.cpp @@ -657,7 +657,8 @@ void KartPropertiesManager::getRandomKartList(int count, std::vector karts_in_group = getKartsInGroup(UserConfigParams::m_last_used_kart_group); - assert(karts_in_group.size() > 0); + if (karts_in_group.empty()) + karts_in_group = getKartsInGroup(DEFAULT_GROUP_NAME); // first try not to use a kart already used by a player for (unsigned int i=0; i Date: Sat, 3 May 2025 14:57:50 +0400 Subject: [PATCH 692/830] Allow non-bot clients to see chat messages Apparently, someone uses this code as client side fork too. They don't see messages while being present on the server. --- src/network/protocols/client_lobby.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp index 84cc5c38f37..71357e944ca 100644 --- a/src/network/protocols/client_lobby.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -940,6 +940,24 @@ void ClientLobby::handleChat(Event* event) SFXManager::get()->quickSound("plopp"); core::stringw message; event->data().decodeString16(&message); + + // === kimden's disclaimer about the message privacy === + // There is currently no peer to peer messaging in STK implemented. + // Clients' messages can be spied on, either by the server who has + // to have access to all messages in any case, or by the bots who are + // technically able to be not shown as present on the server in certain + // circumstances (or by players hiding as much as bots, but that will be + // prevented later). + // This code version does NOT log messages neither on the server side, + // nor on the bots' side. I am aware that anyone can copy, change, and + // do whatever with this code. I do not bear any responsibility if anyone + // starts to spy on your messages this way. + // === end of disclaimer === + + // Human client is supposed to see the messages, while bots are not. + if (!NetworkConfig::get()->isNetworkAIInstance()) + Log::info("ClientLobby", "%s", StringUtils::wideToUtf8(message).c_str()); + if (GUIEngine::isNoGraphics()) return; if (message.size() > 0) From aa2e94ef9b9db30510836786affc09e85a16bdef Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 3 May 2025 15:27:11 +0400 Subject: [PATCH 693/830] Show hours in displayed time, just in database, etc Caused by this code being used as a client --- README.md | 4 +++- src/states_screens/race_gui.cpp | 31 +++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1d197d1f7a4..4ea49ab1a0a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ [![Windows build status](https://github.com/kimden/stk-code/actions/workflows/windows.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/windows.yml) [![Switch build status](https://github.com/kimden/stk-code/actions/workflows/switch.yml/badge.svg)](https://github.com/kimden/stk-code/actions/workflows/switch.yml) -This repository contains a **modified** version of SuperTuxKart (STK), mainly intended for server-side usage. Most important changes are listed [here](/FORK_CHANGES.md). Standard version of STK can be found [here](https://github.com/supertuxkart/stk-code/), and the changes between it and latest commits of this repo can be found [here](https://github.com/supertuxkart/stk-code/compare/master...kimden:stk-code:master). +This repository contains a **modified** version of SuperTuxKart (STK), mainly intended for server-side usage, but you can also use it as a client. + +Most important changes are listed [here](/FORK_CHANGES.md). Standard version of STK can be found [here](https://github.com/supertuxkart/stk-code/), and the changes between it and latest commits of this repo can be found [here](https://github.com/supertuxkart/stk-code/compare/master...kimden:stk-code:master). ## Important branches diff --git a/src/states_screens/race_gui.cpp b/src/states_screens/race_gui.cpp index 0f692d78283..3519340a381 100644 --- a/src/states_screens/race_gui.cpp +++ b/src/states_screens/race_gui.cpp @@ -66,6 +66,25 @@ using namespace irr; #include +namespace +{ + const wchar_t* g_long_time = L"99:99:99.999"; + const wchar_t* g_medium_time = L"99:99:99.999"; + const wchar_t* g_long_laps = L"999/999"; + const wchar_t* g_medium_laps = L"9/9"; + const wchar_t* g_minus = L"-"; + + // standard values, if you change them you also have to change + // bool display_hours = true in string_utils.hpp + + // const wchar_t* g_long_time = L"99:99.999"; + // const wchar_t* g_medium_time = L"99.999"; + // const wchar_t* g_long_laps = L"99/99"; + // const wchar_t* g_medium_laps = L"9/9"; + // const wchar_t* g_minus = L"-"; + +} // namespace + /** The constructor is called before anything is attached to the scene node. * So rendering to a texture can be done here. But world is not yet fully * created, so only the race manager can be accessed safely. @@ -116,25 +135,25 @@ void RaceGUI::initSize() // Determine maximum length of the rank/lap text, in order to // align those texts properly on the right side of the viewport. gui::ScalableFont* font = GUIEngine::getHighresDigitFont(); - core::dimension2du area = font->getDimension(L"99:99.999"); + core::dimension2du area = font->getDimension(g_long_time); m_timer_width = area.Width; m_font_height = area.Height; - area = font->getDimension(L"99.999"); + area = font->getDimension(g_medium_time); m_small_precise_timer_width = area.Width; - area = font->getDimension(L"99:99.999"); + area = font->getDimension(g_long_time); m_big_precise_timer_width = area.Width; - area = font->getDimension(L"-"); + area = font->getDimension(g_minus); m_negative_timer_additional_width = area.Width; if (RaceManager::get()->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER || RaceManager::get()->isBattleMode() || RaceManager::get()->getNumLaps() > 9) - m_lap_width = font->getDimension(L"99/99").Width; + m_lap_width = font->getDimension(g_long_laps).Width; else - m_lap_width = font->getDimension(L"9/9").Width; + m_lap_width = font->getDimension(g_medium_laps).Width; } // initSize //----------------------------------------------------------------------------- From e2dea067d7f831683dc7215bfcde6643e11ca83e Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 3 May 2025 15:43:49 +0400 Subject: [PATCH 694/830] Fix compilation as STK still uses global pointers... --- src/graphics/stk_tex_manager.cpp | 1 + src/states_screens/credits.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/graphics/stk_tex_manager.cpp b/src/graphics/stk_tex_manager.cpp index cf83eeac4d9..17f0c7bff3a 100644 --- a/src/graphics/stk_tex_manager.cpp +++ b/src/graphics/stk_tex_manager.cpp @@ -292,6 +292,7 @@ void STKTexManager::reloadAllTextures(bool mesh_texture_only) if (mi) icons.insert(fs->getAbsolutePath(mi->getFullPath()).c_str()); } + auto track_manager = TrackManager::get(); for (auto d : *track_manager->getAllTrackDirs()) { if (!d.empty() && d.back() == '/') diff --git a/src/states_screens/credits.cpp b/src/states_screens/credits.cpp index ea530567cb5..742d6e42040 100644 --- a/src/states_screens/credits.cpp +++ b/src/states_screens/credits.cpp @@ -410,7 +410,7 @@ void CreditsScreen::eventCallback(GUIEngine::Widget* widget, if (name == "stk-website") { // Open stk website main page - Online::LinkHelper::openURL(stk_config->m_stk_website_url); + Online::LinkHelper::openURL(STKConfig::get()->m_stk_website_url); } } From e7fc33e48f371ab214802e9f2283ef8dff8ac305 Mon Sep 17 00:00:00 2001 From: Deve Date: Sat, 3 May 2025 23:50:16 +0200 Subject: [PATCH 695/830] Add point and spot lights rendering for vulkan --- .../ge_shaders/utils/global_light_data.glsl | 21 +++ data/shaders/ge_shaders/utils/handle_pbr.glsl | 14 +- data/shaders/ge_shaders/utils/pbr_light.glsl | 48 ++++++- data/shaders/ge_shaders/utils/spm_data.glsl | 2 +- .../ge_shaders/utils/sun_direction.glsl | 22 +-- lib/graphics_engine/CMakeLists.txt | 2 + lib/graphics_engine/include/ge_main.hpp | 4 + .../include/ge_occlusion_culling.hpp | 80 +++++++++++ .../include/ge_vulkan_driver.hpp | 2 +- lib/graphics_engine/src/ge_culling_tool.cpp | 12 ++ lib/graphics_engine/src/ge_culling_tool.hpp | 2 + lib/graphics_engine/src/ge_main.cpp | 25 ++++ .../src/ge_occlusion_culling.cpp | 129 ++++++++++++++++++ .../src/ge_vulkan_draw_call.cpp | 118 +++++++++++++--- .../src/ge_vulkan_draw_call.hpp | 9 +- .../src/ge_vulkan_dynamic_buffer.cpp | 3 +- .../src/ge_vulkan_light_handler.cpp | 126 +++++++++++++++++ .../src/ge_vulkan_light_handler.hpp | 85 ++++++++++++ .../src/ge_vulkan_scene_manager.cpp | 8 ++ .../src/ge_vulkan_skybox_renderer.cpp | 11 +- .../src/ge_vulkan_skybox_renderer.hpp | 12 ++ src/graphics/irr_driver.cpp | 25 +++- src/graphics/referee.cpp | 33 ++++- src/tracks/track.cpp | 53 ++++++- src/tracks/track.hpp | 4 +- src/tracks/track_object_presentation.cpp | 12 +- 26 files changed, 805 insertions(+), 57 deletions(-) create mode 100644 data/shaders/ge_shaders/utils/global_light_data.glsl create mode 100644 lib/graphics_engine/include/ge_occlusion_culling.hpp create mode 100644 lib/graphics_engine/src/ge_occlusion_culling.cpp create mode 100644 lib/graphics_engine/src/ge_vulkan_light_handler.cpp create mode 100644 lib/graphics_engine/src/ge_vulkan_light_handler.hpp diff --git a/data/shaders/ge_shaders/utils/global_light_data.glsl b/data/shaders/ge_shaders/utils/global_light_data.glsl new file mode 100644 index 00000000000..1c0c7f4343b --- /dev/null +++ b/data/shaders/ge_shaders/utils/global_light_data.glsl @@ -0,0 +1,21 @@ +struct LightData +{ + vec4 m_position_radius; + vec4 m_color_inverse_square_range; + vec4 m_direction_scale_offset; // Spotlight only +}; + +const int MAX_LIGHT = 32; +layout(std140, set = 1, binding = 3) uniform GlobalLightBuffer +{ + vec3 m_ambient_color; + float m_sun_scatter; + vec3 m_sun_color; + float m_sun_angle_tan_half; + vec3 m_sun_direction; + float m_fog_density; + vec4 m_fog_color; + vec3 m_skytop_color; + int m_light_count; + LightData m_lights[MAX_LIGHT]; +} u_global_light; diff --git a/data/shaders/ge_shaders/utils/handle_pbr.glsl b/data/shaders/ge_shaders/utils/handle_pbr.glsl index fdf47ee4497..5fa0acad6dc 100644 --- a/data/shaders/ge_shaders/utils/handle_pbr.glsl +++ b/data/shaders/ge_shaders/utils/handle_pbr.glsl @@ -3,7 +3,9 @@ layout (set = 2, binding = 1) uniform samplerCube u_specular; #include "camera.glsl" #include "constants_utils.glsl" +#include "spm_data.glsl" #include "pbr_utils.glsl" +#include "global_light_data.glsl" #include "get_pos_from_frag_coord.glsl" #include "pbr_light.glsl" @@ -29,16 +31,20 @@ vec3 handlePBR(vec3 diffuse_color, vec3 pbr, vec3 normal) radiance = textureLod(u_specular, world_reflection, radiance_level).rgb; } - vec3 sun = sunDirection(normal, eyedir, vec3(-642.22, 673.75, -219.26)); - vec3 lightdir = normalize(sun.xyz); + vec3 lightdir = sunDirection(reflection, + u_global_light.m_sun_direction, u_global_light.m_sun_angle_tan_half, + u_camera.m_inverse_view_matrix); vec3 mixed_color = PBRSunAmbientEmitLight( normal, eyedir, lightdir, diffuse_color, irradiance, radiance, - vec3(211./256., 235./256., 110./256.), - vec3(120./256., 120./256., 120./256.), + u_global_light.m_sun_color, + u_global_light.m_ambient_color, perceptual_roughness, pbr.y, pbr.z); + mixed_color += accumulateLights(diffuse_color, normal, xpos, eyedir, + perceptual_roughness, pbr.y); + float factor = (1.0 - exp(length(xpos) * -0.0001)); mixed_color = mixed_color + vec3(0.5) * factor; diff --git a/data/shaders/ge_shaders/utils/pbr_light.glsl b/data/shaders/ge_shaders/utils/pbr_light.glsl index 4283b0c7208..506ba309e00 100644 --- a/data/shaders/ge_shaders/utils/pbr_light.glsl +++ b/data/shaders/ge_shaders/utils/pbr_light.glsl @@ -81,12 +81,17 @@ vec3 PBRSunAmbientEmitLight( // Other 0.6 comes from skybox ambient_color *= 0.4; - vec3 environment = vec3(0.325, 0.35, 0.375) * ambient_color * diffuse_color; + vec3 environment; if (u_ibl) { environment = environmentLight(irradiance, radiance, roughness, diffuse_color, F_ab, F0, F90, NdotV); } + else + { + environment = u_global_light.m_skytop_color * ambient_color * + diffuse_color; + } vec3 emit = emissive * color * 4.0; @@ -94,3 +99,44 @@ vec3 PBRSunAmbientEmitLight( + environment + emit + (diffuse_ambient + specular_ambient) * ambient_color; } + +vec3 accumulateLights(vec3 diffuse_color, vec3 normal, vec3 xpos, vec3 eyedir, + float perceptual_roughness, float metallic) +{ + vec3 accumulated_color = vec3(0.0); + for (int i = 0; i < u_global_light.m_light_count; i++) + { + vec3 light_to_frag = (u_camera.m_view_matrix * + vec4(u_global_light.m_lights[i].m_position_radius.xyz, + 1.0)).xyz - xpos; + float invrange = u_global_light.m_lights[i].m_color_inverse_square_range.w; + float distance_sq = dot(light_to_frag, light_to_frag); + if (distance_sq * invrange > 1.) + continue; + float distance = sqrt(distance_sq); + float distance_inverse = 1. / distance; + vec3 L = light_to_frag * distance_inverse; + vec3 diffuse_specular = PBRLight(normal, eyedir, L, diffuse_color, + perceptual_roughness, metallic); + float attenuation = 20. / (1. + distance_sq); + float radius = u_global_light.m_lights[i].m_position_radius.w; + attenuation *= (radius - distance) / radius; + // SpotLight + float sscale = u_global_light.m_lights[i].m_direction_scale_offset.z; + if (sscale != 0.) + { + vec3 sdir = + vec3(u_global_light.m_lights[i].m_direction_scale_offset.xy, 0.); + sdir.z = sqrt(1. - dot(sdir, sdir)) * sign(sscale); + sdir = (u_camera.m_view_matrix * vec4(sdir, 0.0)).xyz; + float sattenuation = clamp(dot(-sdir, normalize(light_to_frag)) * + abs(sscale) + + u_global_light.m_lights[i].m_direction_scale_offset.w, 0.0, 1.0); + attenuation *= sattenuation * sattenuation; + } + vec3 light_color = + u_global_light.m_lights[i].m_color_inverse_square_range.xyz; + accumulated_color += light_color * attenuation * diffuse_specular; + } + return accumulated_color; +} diff --git a/data/shaders/ge_shaders/utils/spm_data.glsl b/data/shaders/ge_shaders/utils/spm_data.glsl index 2952206919c..1a7c67e1bb1 100644 --- a/data/shaders/ge_shaders/utils/spm_data.glsl +++ b/data/shaders/ge_shaders/utils/spm_data.glsl @@ -24,7 +24,7 @@ layout(std140, set = 1, binding = 2) readonly buffer SkinningMatrices } u_skinning_matrices; #ifdef BIND_MESH_TEXTURES_AT_ONCE -layout(std430, set = 1, binding = 3) readonly buffer MaterialIDs +layout(std430, set = 1, binding = 4) readonly buffer MaterialIDs { int m_material_id[]; } u_material_ids; diff --git a/data/shaders/ge_shaders/utils/sun_direction.glsl b/data/shaders/ge_shaders/utils/sun_direction.glsl index f52901c7ebb..ebeecb62d17 100644 --- a/data/shaders/ge_shaders/utils/sun_direction.glsl +++ b/data/shaders/ge_shaders/utils/sun_direction.glsl @@ -1,12 +1,14 @@ -vec3 sunDirection(vec3 normal, vec3 eyedir, vec3 sundirection) +// Sun Most Representative Point (used for MRP area lighting method) +// From "Frostbite going PBR" paper + +vec3 sunDirection(vec3 R, vec3 sun_direction, float sun_angle_tan_half, mat4 inverse_view_matrix) { - vec3 local_sundir = normalize((transpose(u_camera.m_inverse_view_matrix) * vec4(sundirection, 0.)).xyz); - vec3 R = reflect(-eyedir, normal); - float angularRadius = 3.14 * 5. / 180.; - vec3 D = local_sundir; - float d = cos(angularRadius); - float r = sin(angularRadius); - float DdotR = dot(D, R); - vec3 S = R - DdotR * D; - return (DdotR < d) ? normalize(d * D + normalize (S) * r) : R; + sun_direction = normalize((transpose(inverse_view_matrix) * vec4(sun_direction, 0.)).xyz); + float DdotR = dot(sun_direction, R); + vec3 S = normalize(R - DdotR * sun_direction); + float sun_angle_tan_half2 = 1 + sun_angle_tan_half * sun_angle_tan_half; + vec2 sun_angle_sin_cos = vec2(2 * sun_angle_tan_half, 2 - sun_angle_tan_half2) / sun_angle_tan_half2; + // Equivalent to DdotR < cos(sun_angle) + float factor = step(DdotR, sun_angle_sin_cos.y); + return mix(R, normalize(sun_direction * sun_angle_sin_cos.y + S * sun_angle_sin_cos.x), factor); } diff --git a/lib/graphics_engine/CMakeLists.txt b/lib/graphics_engine/CMakeLists.txt index ad13602c4db..9de9bb6732e 100644 --- a/lib/graphics_engine/CMakeLists.txt +++ b/lib/graphics_engine/CMakeLists.txt @@ -69,6 +69,7 @@ set(GE_SOURCES src/ge_culling_tool.cpp src/ge_dx9_texture.cpp src/ge_main.cpp + src/ge_occlusion_culling.cpp src/ge_texture.cpp src/ge_vma.cpp src/ge_vulkan_2d_renderer.cpp @@ -85,6 +86,7 @@ set(GE_SOURCES src/ge_vulkan_environment_map.cpp src/ge_vulkan_fbo_texture.cpp src/ge_vulkan_features.cpp + src/ge_vulkan_light_handler.cpp src/ge_vulkan_mesh_cache.cpp src/ge_vulkan_mesh_scene_node.cpp src/ge_vulkan_scene_manager.cpp diff --git a/lib/graphics_engine/include/ge_main.hpp b/lib/graphics_engine/include/ge_main.hpp index 8d1540de2ab..82b05e97d0e 100644 --- a/lib/graphics_engine/include/ge_main.hpp +++ b/lib/graphics_engine/include/ge_main.hpp @@ -19,6 +19,7 @@ namespace irr namespace GE { +class GEOcclusionCulling; class GESPMBuffer; class GEVulkanDriver; struct GEConfig @@ -98,6 +99,9 @@ inline irr::video::SColor srgb255ToLinearFromSColor(irr::video::SColor scolor_sr return out; } void copyToMappedBuffer(uint32_t* mapped, GESPMBuffer* spmb, size_t offset = 0); +GEOcclusionCulling* getOcclusionCulling(); +void resetOcclusionCulling(); +bool hasOcclusionCulling(); } #endif diff --git a/lib/graphics_engine/include/ge_occlusion_culling.hpp b/lib/graphics_engine/include/ge_occlusion_culling.hpp new file mode 100644 index 00000000000..364a5ef471b --- /dev/null +++ b/lib/graphics_engine/include/ge_occlusion_culling.hpp @@ -0,0 +1,80 @@ +#ifndef HEADER_GE_OCCLUSION_CULLING_HPP +#define HEADER_GE_OCCLUSION_CULLING_HPP + +#include +#include + +#include + +#include +#include + +class btCollisionShape; +class btCollisionObject; +class btTriangleMesh; + +namespace GE +{ +class GEOcclusionCulling +{ +private: + btTriangleMesh* m_triangle_mesh; + + btCollisionShape* m_occluder_shape; + + btCollisionObject* m_occluder_object; + + // Point generators that yield one point at a time + class PointGenerator + { + public: + virtual ~PointGenerator() {} + virtual bool getNextPoint(btVector3& point) = 0; + }; + + class SpherePointGenerator : public PointGenerator + { + private: + btVector3 m_center; + float m_radius; + int m_num_points; + int m_current_point; + public: + // -------------------------------------------------------------------- + SpherePointGenerator(const btVector3& center, float radius, + int num_points) + { + m_center = center; + m_radius = radius; + m_num_points = num_points; + m_current_point = 0; + } + // -------------------------------------------------------------------- + bool getNextPoint(btVector3& point); + }; + +public: + // ------------------------------------------------------------------------ + GEOcclusionCulling(); + // ------------------------------------------------------------------------ + ~GEOcclusionCulling(); + // ------------------------------------------------------------------------ + void addOccluderMesh(const std::vector >& tris); + // ------------------------------------------------------------------------ + bool isOccluded(const irr::core::vector3df& cam_pos, + const irr::core::aabbox3df& aabbox) + { + // Use sphere test for now, testing the aabbox against the frustum + // should be done first. + float radius = aabbox.getExtent().getLength() / 2.0f; + return isOccluded(cam_pos, aabbox.getCenter(), radius); + } + // ------------------------------------------------------------------------ + bool isOccluded(const irr::core::vector3df& cam_pos, + const irr::core::vector3df& irr_center, float radius); + +}; + +} + +#endif diff --git a/lib/graphics_engine/include/ge_vulkan_driver.hpp b/lib/graphics_engine/include/ge_vulkan_driver.hpp index fe8f64f7dae..39735d87c35 100644 --- a/lib/graphics_engine/include/ge_vulkan_driver.hpp +++ b/lib/graphics_engine/include/ge_vulkan_driver.hpp @@ -198,7 +198,7 @@ namespace GE //! Sets the dynamic ambient light color. The default color is //! (0,0,0,0) which means it is dark. //! \param color: New color of the ambient light. - virtual void setAmbientLight(const SColorf& color) {} + virtual void setAmbientLight(const SColorf& color) { CNullDriver::setAmbientLight(color); } //! Draws a shadow volume into the stencil buffer. virtual void drawStencilShadowVolume(const core::array& triangles, bool zfail=true, u32 debugDataVisible=0) {} diff --git a/lib/graphics_engine/src/ge_culling_tool.cpp b/lib/graphics_engine/src/ge_culling_tool.cpp index cd0bf7276b8..6dede346d13 100644 --- a/lib/graphics_engine/src/ge_culling_tool.cpp +++ b/lib/graphics_engine/src/ge_culling_tool.cpp @@ -15,6 +15,18 @@ void GECullingTool::init(GEVulkanCameraSceneNode* cam) m_cam_bbox = cam->getViewFrustum()->getBoundingBox(); } // init +// ---------------------------------------------------------------------------- +bool GECullingTool::isCulled(const irr::core::vector3df& center, float radius) +{ + for (int i = 0; i < 6; i++) + { + irr::core::quaternion q(center.X, center.Y, center.Z, 1.0f); + if (m_frustum[i].dotProduct(q) < -radius) + return true; + } + return false; +} // isCulled + // ---------------------------------------------------------------------------- bool GECullingTool::isCulled(irr::core::aabbox3df& bb) { diff --git a/lib/graphics_engine/src/ge_culling_tool.hpp b/lib/graphics_engine/src/ge_culling_tool.hpp index f056dd25df1..a25f08c165c 100644 --- a/lib/graphics_engine/src/ge_culling_tool.hpp +++ b/lib/graphics_engine/src/ge_culling_tool.hpp @@ -27,6 +27,8 @@ class GECullingTool // ------------------------------------------------------------------------ bool isCulled(irr::core::aabbox3df& bb); // ------------------------------------------------------------------------ + bool isCulled(const irr::core::vector3df& center, float radius); + // ------------------------------------------------------------------------ bool isCulled(GESPMBuffer* buffer, irr::scene::ISceneNode* node); }; // GECullingTool diff --git a/lib/graphics_engine/src/ge_main.cpp b/lib/graphics_engine/src/ge_main.cpp index fd767aa69b6..77711591c1d 100644 --- a/lib/graphics_engine/src/ge_main.cpp +++ b/lib/graphics_engine/src/ge_main.cpp @@ -1,4 +1,5 @@ #include "ge_main.hpp" +#include "ge_occlusion_culling.hpp" #include "ge_spm.hpp" #include "ge_spm_buffer.hpp" #include "ge_vulkan_driver.hpp" @@ -10,6 +11,7 @@ #include #include +#include namespace GE { @@ -29,6 +31,7 @@ GEConfig g_config = std::string g_shader_folder = ""; std::chrono::steady_clock::time_point g_mono_start = std::chrono::steady_clock::now(); +std::unique_ptr g_occulsion_culling; void setVideoDriver(irr::video::IVideoDriver* driver) { @@ -191,4 +194,26 @@ void copyToMappedBuffer(uint32_t* mapped, GESPMBuffer* spmb, size_t offset) } } +GEOcclusionCulling* getOcclusionCulling() +{ + if (!g_occulsion_culling) + { + g_occulsion_culling = std::unique_ptr( + new GEOcclusionCulling()); + } + return g_occulsion_culling.get(); +} + +void resetOcclusionCulling() +{ + g_occulsion_culling.reset(); +} + +bool hasOcclusionCulling() +{ + if (g_occulsion_culling) + return true; + return false; +} + } diff --git a/lib/graphics_engine/src/ge_occlusion_culling.cpp b/lib/graphics_engine/src/ge_occlusion_culling.cpp new file mode 100644 index 00000000000..0e6dacfc3a3 --- /dev/null +++ b/lib/graphics_engine/src/ge_occlusion_culling.cpp @@ -0,0 +1,129 @@ +#include "ge_occlusion_culling.hpp" + +#include +#include +#include +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +namespace GE +{ +// ============================================================================ +bool GEOcclusionCulling::SpherePointGenerator::getNextPoint(btVector3& point) +{ + if (m_current_point >= m_num_points) + return false; + + if (m_current_point == 0) + { + point = m_center; + m_current_point++; + return true; + } + + float golden_ratio = (1.0f + sqrtf(5.0f)) / 2.0f; + float angle_increment = 2.0f * M_PI * golden_ratio; + + float t = float(m_current_point) / float(m_num_points); + float inclination = acos(1.0f - 2.0f * t); + float azimuth = angle_increment * float(m_current_point); + + float x = sin(inclination) * cos(azimuth); + float y = sin(inclination) * sin(azimuth); + float z = cos(inclination); + + // Test points at 80% of the sphere's surface + float offset = 0.8f; + point = m_center + btVector3(x, y, z) * m_radius * offset; + m_current_point++; + return true; +} // GEOcclusionCulling::SpherePointGenerator::getNextPoint + +// ---------------------------------------------------------------------------- +GEOcclusionCulling::GEOcclusionCulling() +{ + m_triangle_mesh = NULL; + m_occluder_shape = NULL; + m_occluder_object = NULL; +} // GEOcclusionCulling + +// ---------------------------------------------------------------------------- +GEOcclusionCulling::~GEOcclusionCulling() +{ + delete m_occluder_object; + delete m_occluder_shape; + delete m_triangle_mesh; +} // ~GEOcclusionCulling + +// ---------------------------------------------------------------------------- +void GEOcclusionCulling::addOccluderMesh( + const std::vector >& tris) +{ + assert(m_triangle_mesh == NULL); + m_triangle_mesh = new btTriangleMesh(); + for (auto& t : tris) + m_triangle_mesh->addTriangle(t[0], t[1], t[2]); + m_occluder_shape = new btBvhTriangleMeshShape(m_triangle_mesh, + false/*useQuantizedAabbCompression*/); + m_occluder_object = new btCollisionObject(); + m_occluder_object->setCollisionShape(m_occluder_shape); +} // addOccluderMesh + +// ---------------------------------------------------------------------------- +bool GEOcclusionCulling::isOccluded(const irr::core::vector3df& cam_pos, + const irr::core::vector3df& irr_center, + float radius) +{ + if (!m_triangle_mesh) + return false; + float radius_2 = radius * radius; + float distance_2 = (cam_pos - irr_center).getLengthSQ(); + // Inside the sphere + if (distance_2 <= radius_2) + return false; + + // Calculate points using logarithmic scaling + float distance = sqrtf(distance_2); + // Formula: MAX_POINTS - log2(distance/MIN_DISTANCE) * SCALE_FACTOR + // Clamp between MIN_POINTS and MAX_POINTS + const float MIN_DISTANCE = 80.0f; // Distance at which maximum points are used + const int MAX_POINTS = 12; + const int MIN_POINTS = 3; + const float SCALE_FACTOR = 4.0f; // Controls how quickly the point count decreases + + int num_points = MAX_POINTS - + int(std::log2(std::max(distance / MIN_DISTANCE, 1.0f)) * SCALE_FACTOR); + num_points = std::min(MAX_POINTS, std::max(MIN_POINTS, num_points)); + + btVector3 center = btVector3(irr_center.X, irr_center.Y, irr_center.Z); + PointGenerator* generator = new SpherePointGenerator(center, radius, num_points); + + btVector3 test_point; + btVector3 cam_p(cam_pos.X, cam_pos.Y, cam_pos.Z); + bool culled = true; + while (generator->getNextPoint(test_point)) + { + btCollisionWorld::ClosestRayResultCallback cb(cam_p, test_point); + cb.m_flags |= btTriangleRaycastCallback::kF_FilterBackfaces; + btTransform from_trans, to_trans; + from_trans.setIdentity(); + from_trans.setOrigin(cam_p); + to_trans.setIdentity(); + to_trans.setOrigin(test_point); + btCollisionWorld::rayTestSingle(from_trans, to_trans, + m_occluder_object, m_occluder_shape, + m_occluder_object->getWorldTransform(), cb); + if (!cb.hasHit() || + (cb.m_hitPointWorld - test_point).length2() <= radius_2 || // Hit point inside the sphere + (cb.m_hitPointWorld - cam_p).length2() > (test_point - cam_p).length2()) // Hit point behind the sphere + { + culled = false; + break; + } + } + delete generator; + return culled; +} // isOccluded + +} diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index 7f511064b0d..dd9bf968c87 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -13,6 +13,7 @@ #include "ge_vulkan_environment_map.hpp" #include "ge_vulkan_fbo_texture.hpp" #include "ge_vulkan_features.hpp" +#include "ge_vulkan_light_handler.hpp" #include "ge_vulkan_mesh_cache.hpp" #include "ge_vulkan_mesh_scene_node.hpp" #include "ge_vulkan_shader_manager.hpp" @@ -21,6 +22,7 @@ #include "mini_glm.hpp" #include "IBillboardSceneNode.h" +#include "ILightSceneNode.h" #include "IParticleSystemSceneNode.h" #include @@ -203,6 +205,7 @@ GEVulkanDrawCall::GEVulkanDrawCall() : m_limits(getVKDriver()->getPhysicalDeviceProperties().limits) { m_culling_tool = new GECullingTool; + m_light_handler = NULL; m_dynamic_data = NULL; m_sbo_data = NULL; m_object_data_padded_size = 0; @@ -222,6 +225,7 @@ GEVulkanDrawCall::GEVulkanDrawCall() GEVulkanDrawCall::~GEVulkanDrawCall() { delete m_culling_tool; + delete m_light_handler; delete m_dynamic_data; delete m_sbo_data; for (auto& p : m_billboard_buffers) @@ -320,6 +324,9 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) if (!m_visible_nodes.empty() && m_data_layout == VK_NULL_HANDLE) createVulkanData(); + if (m_light_handler) + m_light_handler->generate(m_view_position, m_skybox_renderer); + using Nodes = std::pair, std::unordered_map< std::string, std::vector > > >; @@ -841,8 +848,12 @@ std::string GEVulkanDrawCall::getShader(const irr::video::SMaterial& m) void GEVulkanDrawCall::prepare(GEVulkanCameraSceneNode* cam) { reset(); + if (getGEConfig()->m_pbr && m_light_handler == NULL) + m_light_handler = new GEVulkanLightHandler(getVKDriver()); + if (m_light_handler) + m_light_handler->prepare(); m_culling_tool->init(cam); - m_view_position = cam->getPosition(); + m_view_position = cam->getAbsolutePosition(); m_billboard_rotation = MiniGLM::getBulletQuaternion(cam->getViewMatrix()); } // prepare @@ -1272,16 +1283,26 @@ void GEVulkanDrawCall::createVulkanData() skinning_layout_binding.pImmutableSamplers = NULL; skinning_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + VkDescriptorSetLayoutBinding light_layout_binding = {}; + light_layout_binding.binding = 3; + light_layout_binding.descriptorCount = 1; + light_layout_binding.descriptorType = + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + light_layout_binding.pImmutableSamplers = NULL; + light_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | + VK_SHADER_STAGE_FRAGMENT_BIT; + std::vector bindings = { camera_layout_binding, object_data_layout_binding, - skinning_layout_binding + skinning_layout_binding, + light_layout_binding }; if (GEVulkanFeatures::supportsBindMeshTexturesAtOnce()) { VkDescriptorSetLayoutBinding material_binding = {}; - material_binding.binding = 3; + material_binding.binding = 4; material_binding.descriptorCount = 1; material_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; @@ -1310,7 +1331,7 @@ void GEVulkanDrawCall::createVulkanData() { { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - vk->getMaxFrameInFlight() + 1 + (vk->getMaxFrameInFlight() + 1) * 2 }, { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, @@ -1318,7 +1339,7 @@ void GEVulkanDrawCall::createVulkanData() } }; if (GEVulkanFeatures::supportsBindMeshTexturesAtOnce()) - sizes.push_back(sizes.back()); + sizes.back().descriptorCount = (vk->getMaxFrameInFlight() + 1) * 3; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; @@ -1419,7 +1440,7 @@ void GEVulkanDrawCall::createVulkanData() // Use VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT // or a staging buffer when buffer is small m_dynamic_data = new GEVulkanDynamicBuffer(flags, - extra_size + sizeof(GEVulkanCameraUBO), + extra_size + sizeof(GEVulkanCameraUBO) + sizeof(GEGlobalLightBuffer), GEVulkanDriver::getMaxFrameInFlight() + 1, GEVulkanDynamicBuffer::supportsHostTransfer() ? 0 : GEVulkanDriver::getMaxFrameInFlight() + 1); @@ -1452,6 +1473,15 @@ void GEVulkanDrawCall::uploadDynamicData(GEVulkanDriver* vk, data_uploading.emplace_back((void*)cam->getUBOData(), sizeof(GEVulkanCameraUBO)); + size_t sbo_padding = getLightDataOffset() - sizeof(GEVulkanCameraUBO); + if (sbo_padding > 0) + data_uploading.emplace_back((void*)NULL, sbo_padding); + if (m_light_handler) + { + data_uploading.emplace_back(m_light_handler->getData(), + m_light_handler->getSize()); + } + const bool use_multidraw = GEVulkanFeatures::supportsBindMeshTexturesAtOnce(); if (use_multidraw) @@ -1567,6 +1597,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, 0u, 0u, 0u, + 0u, }; if (getGEConfig()->m_pbr) { @@ -1583,7 +1614,9 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, m_texture_descriptor->getDescriptorSet(), 0, NULL); bound_mesh_textures_once = true; } - size_t indirect_offset = sizeof(GEVulkanCameraUBO); + size_t indirect_offset = getLightDataOffset(); + if (m_light_handler) + indirect_offset += m_light_handler->getSize(); const size_t indirect_size = sizeof(VkDrawIndexedIndirectCommand); unsigned draw_count = 0; VkBuffer indirect_buffer = @@ -1623,7 +1656,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, if (bound) { dynamic_offsets[1] = m_dynamic_spm_padded_size; - dynamic_offsets[3] = m_materials_data[cur_pipeline].first; + dynamic_offsets[4] = m_materials_data[cur_pipeline].first; bindDataDescriptor(cmd, current_buffer_idx, dynamic_offsets); vkCmdDrawIndexedIndirect(cmd, indirect_buffer, @@ -1678,7 +1711,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, if (bound) { dynamic_offsets[1] = m_dynamic_spm_padded_size; - dynamic_offsets[3] = m_materials_data[m_cmds.back().m_shader].first; + dynamic_offsets[4] = m_materials_data[m_cmds.back().m_shader].first; bindDataDescriptor(cmd, current_buffer_idx, dynamic_offsets); vkCmdDrawIndexedIndirect(cmd, indirect_buffer, indirect_offset, draw_count, indirect_size); @@ -1686,7 +1719,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, } else { - dynamic_offsets.resize(3); + dynamic_offsets.resize(4); bool rebind_base_vertex = true; bound = bindPipeline(cmd, cur_pipeline, depth_only, &prev_dp); auto it = dynamic_spm_buffers.find( @@ -1946,6 +1979,26 @@ void GEVulkanDrawCall::updateDataDescriptorSets(GEVulkanDriver* vk) data_set[2].descriptorCount = 1; data_set[2].pBufferInfo = &sbo_info_skinning; + VkDescriptorBufferInfo sbo_info_light; + if (m_light_handler != NULL) + { + sbo_info_light.buffer = + GEVulkanDynamicBuffer::supportsHostTransfer() ? + m_dynamic_data->getHostBuffer()[i] : + m_dynamic_data->getLocalBuffer()[i]; + sbo_info_light.offset = getLightDataOffset(); + sbo_info_light.range = sizeof(GEGlobalLightBuffer); + data_set.push_back({}); + VkWriteDescriptorSet& ds = data_set.back(); + ds.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + ds.dstSet = m_data_descriptor_sets[i]; + ds.dstBinding = 3; + ds.dstArrayElement = 0; + ds.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + ds.descriptorCount = 1; + ds.pBufferInfo = &sbo_info_light; + } + VkDescriptorBufferInfo sbo_info_material; sbo_info_material.buffer = m_sbo_data->getHostBuffer()[i]; @@ -1954,15 +2007,15 @@ void GEVulkanDrawCall::updateDataDescriptorSets(GEVulkanDriver* vk) sbo_info_material.range = m_materials_padded_size; if (bind_mesh_textures) { - data_set.resize(4, {}); - data_set[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - data_set[3].dstSet = m_data_descriptor_sets[i]; - data_set[3].dstBinding = 3; - data_set[3].dstArrayElement = 0; - data_set[3].descriptorType = - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; - data_set[3].descriptorCount = 1; - data_set[3].pBufferInfo = &sbo_info_material; + data_set.push_back({}); + VkWriteDescriptorSet& ds = data_set.back(); + ds.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + ds.dstSet = m_data_descriptor_sets[i]; + ds.dstBinding = 4; + ds.dstArrayElement = 0; + ds.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; + ds.descriptorCount = 1; + ds.pBufferInfo = &sbo_info_material; } vkUpdateDescriptorSets(vk->getDevice(), data_set.size(), @@ -2109,4 +2162,31 @@ VertexDescription GEVulkanDrawCall::getDefaultVertexDescription() const return vertex_description; } // getDefaultVertexDescription +// ---------------------------------------------------------------------------- +void GEVulkanDrawCall::addLightNode(irr::scene::ILightSceneNode* node) +{ + if (!m_light_handler) + return; + if (node->getLightType() == irr::video::ELT_DIRECTIONAL) + { + // Sun node + m_light_handler->addLightNode(node); + } + else + { + const video::SLight& l = node->getLightData(); + if (m_culling_tool->isCulled(l.Position, l.Radius)) + return; + m_light_handler->addLightNode(node); + } +} // addLightNode + +// ---------------------------------------------------------------------------- +size_t GEVulkanDrawCall::getLightDataOffset() const +{ + size_t ubo_size = sizeof(GEVulkanCameraUBO); + return ubo_size + + getPadding(ubo_size, m_limits.minUniformBufferOffsetAlignment); +} // getLightDataOffset + } diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp index 3dfccca7fde..9f421eb6dd1 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp @@ -25,7 +25,7 @@ namespace irr namespace scene { class ISceneNode; class IBillboardSceneNode; struct SParticle; - class IMesh; + class IMesh; class ILightSceneNode; } } @@ -38,6 +38,7 @@ class GEVulkanCameraSceneNode; class GEVulkanDriver; class GEVulkanDynamicBuffer; class GEVulkanDynamicSPMBuffer; +class GEVulkanLightHandler; class GEVulkanSkyBoxRenderer; class GEVulkanTextureDescriptor; @@ -138,6 +139,8 @@ class GEVulkanDrawCall GECullingTool* m_culling_tool; + GEVulkanLightHandler* m_light_handler; + std::vector m_cmds; std::vector m_visible_objects; @@ -280,6 +283,8 @@ class GEVulkanDrawCall bool doDepthOnlyRenderingFirst(); // ------------------------------------------------------------------------ VertexDescription getDefaultVertexDescription() const; + // ------------------------------------------------------------------------ + size_t getLightDataOffset() const; public: // ------------------------------------------------------------------------ GEVulkanDrawCall(); @@ -323,6 +328,8 @@ class GEVulkanDrawCall } // ------------------------------------------------------------------------ void addSkyBox(irr::scene::ISceneNode* node); + // ------------------------------------------------------------------------ + void addLightNode(irr::scene::ILightSceneNode* node); }; // GEVulkanDrawCall } diff --git a/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp b/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp index 9d8cb076c04..5dd6f56cf91 100644 --- a/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp +++ b/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp @@ -165,7 +165,8 @@ bool GEVulkanDynamicBuffer::setCurrentData(const std::vector< uint8_t* addr = (uint8_t*)m_mapped_addr[cur_frame]; for (auto& p : data) { - memcpy(addr, p.first, p.second); + if (p.first != NULL) + memcpy(addr, p.first, p.second); addr += p.second; } vmaFlushAllocation(vk->getVmaAllocator(), m_host_memory[cur_frame], 0, diff --git a/lib/graphics_engine/src/ge_vulkan_light_handler.cpp b/lib/graphics_engine/src/ge_vulkan_light_handler.cpp new file mode 100644 index 00000000000..eeb0659003b --- /dev/null +++ b/lib/graphics_engine/src/ge_vulkan_light_handler.cpp @@ -0,0 +1,126 @@ +#include "ge_vulkan_light_handler.hpp" + +#include "ge_main.hpp" +#include "ge_occlusion_culling.hpp" +#include "ge_vulkan_driver.hpp" +#include "ge_vulkan_skybox_renderer.hpp" + +#include "ILightSceneNode.h" +#include "ISceneManager.h" +#include "IrrlichtDevice.h" + +#include +#include +#include + +namespace GE +{ +using namespace irr; +// ---------------------------------------------------------------------------- +void GEVulkanLightHandler::prepare() +{ + m_buffer = {}; + m_lights.clear(); + video::SColorf c = m_vk->getIrrlichtDevice()->getSceneManager() + ->getAmbientLight(); + m_buffer.m_ambient_color.X = c.r * c.a; + m_buffer.m_ambient_color.Y = c.g * c.a; + m_buffer.m_ambient_color.Z = c.b * c.a; + m_buffer.m_sun_scatter = 0.2f; + m_buffer.m_sun_color = core::vector3df(0.75f, 0.75f, 0.75f); + m_buffer.m_sun_angle_tan_half = 0.0022f; + m_buffer.m_sun_direction = core::vector3df(0.15f, 0.2f, 1.0f).normalize(); + m_buffer.m_skytop_color.X = 0.325f; + m_buffer.m_skytop_color.Y = 0.35f; + m_buffer.m_skytop_color.Z = 0.375f; +} // prepare + +// ---------------------------------------------------------------------------- +void GEVulkanLightHandler::generate(const irr::core::vector3df& cam_pos, + GEVulkanSkyBoxRenderer* skybox) +{ + if (skybox) + { + irr::video::SColorf c( + srgb255ToLinearFromSColor(skybox->getSkytopColor())); + m_buffer.m_skytop_color.X = c.r; + m_buffer.m_skytop_color.Y = c.g; + m_buffer.m_skytop_color.Z = c.b; + } + if (m_lights.size() > MAX_RENDERING_LIGHT) + { + std::sort(m_lights.begin(), m_lights.end(), + [cam_pos](GELight& a, GELight& b) + { + float al = a.m_position.getDistanceFromSQ(cam_pos); + float bl = b.m_position.getDistanceFromSQ(cam_pos); + return al < bl; + }); + m_lights.resize(MAX_RENDERING_LIGHT); + } + if (m_lights.empty()) + return; + + if (hasOcclusionCulling()) + { + auto l = m_lights.begin(); + auto rl = m_buffer.m_rendering_lights.begin(); + while (l != m_lights.end()) + { + if (getOcclusionCulling()->isOccluded(cam_pos, l->m_position, + l->m_radius)) + { + l++; + continue; + } + *rl = *l; + l++; + rl++; + } + m_buffer.m_light_count = rl - m_buffer.m_rendering_lights.begin(); + } + else + { + std::copy(m_lights.begin(), m_lights.end(), + m_buffer.m_rendering_lights.begin()); + m_buffer.m_light_count = m_lights.size(); + } +} // generate + +// ---------------------------------------------------------------------------- +void GEVulkanLightHandler::addLightNode(irr::scene::ILightSceneNode* node) +{ + const video::SLight& l = node->getLightData(); + if (node->getLightType() == irr::video::ELT_DIRECTIONAL) + { + m_buffer.m_sun_color.X = l.DiffuseColor.r; + m_buffer.m_sun_color.Y = l.DiffuseColor.g; + m_buffer.m_sun_color.Z = l.DiffuseColor.b; + m_buffer.m_sun_scatter = l.DiffuseColor.a; + core::vector3df dir = l.Direction; + m_buffer.m_sun_direction = -dir.normalize(); + m_buffer.m_sun_angle_tan_half = tanf(l.Radius * 0.5f); + } + else + { + GELight gl = {}; + gl.m_position = l.Position; + gl.m_radius = l.Radius; + gl.m_color.X = l.DiffuseColor.r * l.Attenuation.X; + gl.m_color.Y = l.DiffuseColor.g * l.Attenuation.X; + gl.m_color.Z = l.DiffuseColor.b * l.Attenuation.X; + gl.m_inverse_range_squared = l.Attenuation.Y * l.Attenuation.Y; + if (l.Type == irr::video::ELT_SPOT) + { + gl.m_direction.X = l.Direction.X; + gl.m_direction.Y = l.Direction.Y; + float cos_outer = cosf(l.OuterCone); + gl.m_scale = 1.0f / std::max(cosf(l.InnerCone) - cos_outer, 1e-4f); + gl.m_offset = -cos_outer * gl.m_scale; + gl.m_scale *= l.Direction.Z > 0.f ? 1.f : -1.f; + } + m_lights.push_back(gl); + } +} // addLightNode + +} diff --git a/lib/graphics_engine/src/ge_vulkan_light_handler.hpp b/lib/graphics_engine/src/ge_vulkan_light_handler.hpp new file mode 100644 index 00000000000..c16bdbc26d4 --- /dev/null +++ b/lib/graphics_engine/src/ge_vulkan_light_handler.hpp @@ -0,0 +1,85 @@ +#ifndef HEADER_GE_VULKAN_LIGHT_HANDLER_HPP +#define HEADER_GE_VULKAN_LIGHT_HANDLER_HPP + +#include "vector2d.h" +#include "vector3d.h" +#include "SColor.h" + +#include +#include + +namespace irr +{ + namespace scene + { + class ILightSceneNode; + } +} + +namespace GE +{ +class GEVulkanDriver; +class GEVulkanSkyBoxRenderer; +const irr::u32 MAX_RENDERING_LIGHT = 32; +struct GELight +{ + irr::core::vector3df m_position; + irr::f32 m_radius; + irr::core::vector3df m_color; + irr::f32 m_inverse_range_squared; + irr::core::vector2df m_direction; + irr::f32 m_scale; + irr::f32 m_offset; +}; + +struct GEGlobalLightBuffer +{ + irr::core::vector3df m_ambient_color; + irr::f32 m_sun_scatter; + irr::core::vector3df m_sun_color; + irr::f32 m_sun_angle_tan_half; + irr::core::vector3df m_sun_direction; + irr::f32 m_fog_density; + irr::video::SColorf m_fog_color; + irr::core::vector3df m_skytop_color; + irr::u32 m_light_count; + std::array m_rendering_lights; +}; + +class GEVulkanLightHandler +{ +private: + GEVulkanDriver* m_vk; + + GEGlobalLightBuffer m_buffer; + + std::vector m_lights; +public: + // ------------------------------------------------------------------------ + GEVulkanLightHandler(GEVulkanDriver* vk) + { + m_vk = vk; + prepare(); + } + // ------------------------------------------------------------------------ + ~GEVulkanLightHandler() {} + // ------------------------------------------------------------------------ + void prepare(); + // ------------------------------------------------------------------------ + void generate(const irr::core::vector3df& cam_pos, + GEVulkanSkyBoxRenderer* skybox); + // ------------------------------------------------------------------------ + void addLightNode(irr::scene::ILightSceneNode* node); + // ------------------------------------------------------------------------ + void* getData() { return &m_buffer; } + // ------------------------------------------------------------------------ + size_t getSize() const + { + return sizeof(GEGlobalLightBuffer) - + (sizeof(GELight) * (MAX_RENDERING_LIGHT - m_buffer.m_light_count)); + } +}; // GEVulkanLightHandler + +} + +#endif diff --git a/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp b/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp index 72b7bb55822..b0f14b081eb 100644 --- a/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp +++ b/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp @@ -15,6 +15,7 @@ #include "ge_vulkan_texture_descriptor.hpp" #include "IBillboardSceneNode.h" +#include "ILightSceneNode.h" #include namespace GE @@ -238,6 +239,13 @@ irr::u32 GEVulkanSceneManager::registerNodeForRendering( return 1; } + if (node->getType() == irr::scene::ESNT_LIGHT) + { + m_draw_calls.at(cam)->addLightNode( + static_cast(node)); + return 1; + } + if (node->getType() == irr::scene::ESNT_BILLBOARD || node->getType() == irr::scene::ESNT_PARTICLE_SYSTEM) { diff --git a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp index 7b03c049688..e1dd4831b7d 100644 --- a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp +++ b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp @@ -21,7 +21,8 @@ GEVulkanSkyBoxRenderer::GEVulkanSkyBoxRenderer() m_descriptor_layout(VK_NULL_HANDLE), m_env_descriptor_layout(VK_NULL_HANDLE), m_descriptor_pool(VK_NULL_HANDLE), - m_skybox_loading(false), m_env_cubemap_loading(false) + m_skybox_loading(false), m_env_cubemap_loading(false), + m_skytop_color(0) { m_dummy_env_cubemap = new GEVulkanArrayTexture(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_VIEW_TYPE_CUBE, core::dimension2du(4, 4), 6, @@ -230,6 +231,14 @@ void GEVulkanSkyBoxRenderer::addSkyBox(irr::scene::ISceneNode* skybox) { if (!(idx == 2 || idx == 3)) return; + if (idx == 2) + { + video::IImage* pixel = getDriver()->createImage( + video::ECF_A8R8G8B8, core::dimension2du(1, 1)); + img->copyToScaling(pixel); + m_sky->m_skytop_color.store(*(uint32_t*)pixel->lock()); + pixel->drop(); + } unsigned width = img->getDimension().Width; uint8_t* tmp = new uint8_t[width * width * 4]; uint32_t* tmp_array = (uint32_t*)tmp; diff --git a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp index 9d44a06e471..56176c33e2f 100644 --- a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp +++ b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp @@ -2,6 +2,7 @@ #define HEADER_GE_VULKAN_SKYBOX_RENDERER_HPP #include "vulkan_wrapper.h" +#include #include #include @@ -33,6 +34,8 @@ class GEVulkanSkyBoxRenderer std::array m_env_descriptor_set; std::atomic_bool m_skybox_loading, m_env_cubemap_loading; + + std::atomic m_skytop_color; public: // ------------------------------------------------------------------------ GEVulkanSkyBoxRenderer(); @@ -62,6 +65,15 @@ class GEVulkanSkyBoxRenderer while (m_env_cubemap_loading.load()); m_skybox = NULL; } + // ------------------------------------------------------------------------ + irr::video::SColor getSkytopColor() const + { + irr::video::SColor c(0); + if (m_skybox_loading.load() == true) + return c; + c.color = m_skytop_color.load(); + return c; + } }; // GEVulkanSkyBoxRenderer diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index a0d1480b810..eb19c87baa2 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -2385,9 +2385,9 @@ scene::ISceneNode *IrrDriver::addLight(const core::vector3df &pos, bool sun_, scene::ISceneNode* parent) { #ifndef SERVER_ONLY + if (parent == NULL) parent = m_scene_manager->getRootSceneNode(); if (CVS->isGLSL()) { - if (parent == NULL) parent = m_scene_manager->getRootSceneNode(); LightNode *light = NULL; if (!sun_) @@ -2409,10 +2409,25 @@ scene::ISceneNode *IrrDriver::addLight(const core::vector3df &pos, } else { - scene::ILightSceneNode* light = m_scene_manager - ->addLightSceneNode(m_scene_manager->getRootSceneNode(), - pos, video::SColorf(r, g, b, 1.0f)); - light->setRadius(radius); + scene::ILightSceneNode* light; + if (m_video_driver->getDriverType() == EDT_VULKAN && sun_) + { + light = m_scene_manager->addLightSceneNode(parent, pos, + video::SColorf(r, g, b, 0.2f), 0.26f * M_PI / 180.0f); + light->setRotation(-pos); + light->setLightType(video::ELT_DIRECTIONAL); + } + else + { + video::SColorf color(r, g, b, 1.0f); + light = m_scene_manager->addLightSceneNode(parent, pos, color); + light->setRadius(radius); + if (m_video_driver->getDriverType() == EDT_VULKAN) + { + video::SLight& data = light->getLightData(); + data.Attenuation.X = energy; + } + } return light; } #else diff --git a/src/graphics/referee.cpp b/src/graphics/referee.cpp index 18cc6dd0117..c1b0d15b264 100644 --- a/src/graphics/referee.cpp +++ b/src/graphics/referee.cpp @@ -34,7 +34,9 @@ #include "utils/string_utils.hpp" #include +#include #include +#include int Referee::m_st_first_start_frame = 1; int Referee::m_st_last_start_frame = 1; @@ -169,7 +171,8 @@ Referee::Referee() m_scene_node->setFrameLoop(m_st_first_start_frame, m_st_last_start_frame); #ifndef SERVER_ONLY - if (CVS->isGLSL() && CVS->isDeferredEnabled()) + if ((CVS->isGLSL() && CVS->isDeferredEnabled()) || + irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN) { m_light = irr_driver->addLight(core::vector3df(0.0f, 0.0f, 0.6f), 0.7f, 2.0f, 0.7f /* r */, 0.0 /* g */, 0.0f /* b */, false /* sun */, m_scene_node); @@ -268,19 +271,39 @@ void Referee::selectReadySetGo(int rsg) m.SpecularColor = video::SColor(255, 255, 255, 255); } - if (m_light != NULL) + LightNode* lnode = dynamic_cast(m_light); + if (lnode != NULL) + { + if (rsg == 0) + { + lnode->setColor(0.6f, 0.0f, 0.0f); + } + else if (rsg == 1) + { + lnode->setColor(0.7f, 0.23f, 0.0f); + } + else if (rsg == 2) + { + lnode->setColor(0.0f, 0.6f, 0.0f); + } + return; + } + scene::ILightSceneNode* irr_node = dynamic_cast( + m_light); + if (irr_node != NULL) { + video::SLight& data = irr_node->getLightData(); if (rsg == 0) { - ((LightNode*)m_light)->setColor(0.6f, 0.0f, 0.0f); + data.DiffuseColor = video::SColorf(0.6f, 0.0f, 0.0f); } else if (rsg == 1) { - ((LightNode*)m_light)->setColor(0.7f, 0.23f, 0.0f); + data.DiffuseColor = video::SColorf(0.7f, 0.23f, 0.0f); } else if (rsg == 2) { - ((LightNode*)m_light)->setColor(0.0f, 0.6f, 0.0f); + data.DiffuseColor = video::SColorf(0.0f, 0.6f, 0.0f); } } } // selectReadySetGo diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index bdb094a4479..1dbaeedcd01 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -102,6 +102,7 @@ #ifndef SERVER_ONLY #include +#include #include #endif @@ -332,6 +333,8 @@ void Track::cleanup() Graph::destroy(); m_item_manager = nullptr; #ifndef SERVER_ONLY + if (!GUIEngine::isNoGraphics()) + GE::resetOcclusionCulling(); if (CVS->isGLSL()) { if (!GUIEngine::isNoGraphics()) @@ -939,8 +942,10 @@ void Track::createPhysicsModel(unsigned int main_track_count, /** Convert the graphics track into its physics equivalents. * \param mesh The mesh to convert. * \param node The scene node. + * \param occluder Optional destination for storing occluder triangles */ -void Track::convertTrackToBullet(scene::ISceneNode *node) +void Track::convertTrackToBullet(scene::ISceneNode *node, + std::vector >* occluder) { if (node->getType() == scene::ESNT_TEXT) return; @@ -1039,7 +1044,12 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) vertices[k] = v; normals[k] = MiniGLM::decompressVector3(mbVertices[indx].m_normal); } // for k - if (tmesh) + if (occluder) + { + if (!material->isTransparent() && !material->isIgnore()) + occluder->push_back({vertices[0], vertices[1], vertices[2]}); + } + else if (tmesh) { tmesh->addTriangle(vertices[0], vertices[1], vertices[2], normals[0], @@ -1098,7 +1108,12 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) normals[k] = mbVertices[indx].Normal; } // for k - if (tmesh) + if (occluder) + { + if (!material->isTransparent() && !material->isIgnore()) + occluder->push_back({vertices[0], vertices[1], vertices[2]}); + } + else if (tmesh) { tmesh->addTriangle(vertices[0], vertices[1], vertices[2], normals[0], @@ -1124,7 +1139,12 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) normals[k] = mbVertices[indx].Normal; } // for k - if (tmesh) + if (occluder) + { + if (!material->isTransparent() && !material->isIgnore()) + occluder->push_back({vertices[0], vertices[1], vertices[2]}); + } + else if (tmesh) { tmesh->addTriangle(vertices[0], vertices[1], vertices[2], normals[0], @@ -1150,7 +1170,12 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) normals[k] = mbVertices[indx].Normal; } // for k - if (tmesh) + if (occluder) + { + if (!material->isTransparent() && !material->isIgnore()) + occluder->push_back({vertices[0], vertices[1], vertices[2]}); + } + else if (tmesh) { tmesh->addTriangle(vertices[0], vertices[1], vertices[2], normals[0], @@ -1176,7 +1201,12 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) normals[k] = MiniGLM::decompressVector3(mbVertices[indx].m_normal); } // for k - if (tmesh) + if (occluder) + { + if (!material->isTransparent() && !material->isIgnore()) + occluder->push_back({vertices[0], vertices[1], vertices[2]}); + } + else if (tmesh) { tmesh->addTriangle(vertices[0], vertices[1], vertices[2], normals[0], @@ -1320,6 +1350,15 @@ bool Track::loadMainTrack(const XMLNode &root) scene_node->setPosition(xyz); scene_node->setRotation(hpr); handleAnimatedTextures(scene_node, *track_node); +#ifndef SERVER_ONLY + if (!GUIEngine::isNoGraphics() && + GE::getDriver()->getDriverType() == video::EDT_VULKAN) + { + std::vector > tris; + convertTrackToBullet(scene_node, &tris); + GE::getOcclusionCulling()->addOccluderMesh(tris); + } +#endif m_all_nodes.push_back(scene_node); MeshTools::minMax3D(tangent_mesh, &m_aabb_min, &m_aabb_max); @@ -1886,6 +1925,8 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) main_loop->renderGUI(3100); #ifndef SERVER_ONLY + if (!GUIEngine::isNoGraphics()) + GE::resetOcclusionCulling(); if (CVS->isGLSL()) { SP::SPShaderManager::get()->loadSPShaders(m_root); diff --git a/src/tracks/track.hpp b/src/tracks/track.hpp index a417dd9af48..a55b2198af7 100644 --- a/src/tracks/track.hpp +++ b/src/tracks/track.hpp @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -742,7 +743,8 @@ class Track // ------------------------------------------------------------------------ bool isAddon() const { return m_is_addon; } // ------------------------------------------------------------------------ - void convertTrackToBullet(scene::ISceneNode *node); + void convertTrackToBullet(scene::ISceneNode *node, + std::vector >* occluder = NULL); // ------------------------------------------------------------------------ CheckManager* getCheckManager() const { return m_check_manager; } // ------------------------------------------------------------------------ diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index 789c0d8935b..b76f7d441c9 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -58,6 +58,7 @@ #include #include #include +#include // ---------------------------------------------------------------------------- TrackObjectPresentation::TrackObjectPresentation(const XMLNode& xml_node) @@ -1028,7 +1029,8 @@ TrackObjectPresentationLight::TrackObjectPresentationLight( m_distance = 20.f * m_energy; xml_node.get("distance", &m_distance); #ifndef SERVER_ONLY - if (CVS->isGLSL()) + if (CVS->isGLSL() || + irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN) { m_node = irr_driver->addLight(m_init_xyz, m_energy, m_distance, colorf.r, colorf.g, colorf.b, false, @@ -1053,6 +1055,14 @@ void TrackObjectPresentationLight::setEnergy(float energy) if (lnode != NULL) { lnode->setEnergy(energy); + return; + } + scene::ILightSceneNode* irr_node = dynamic_cast( + m_node); + if (irr_node != NULL) + { + video::SLight& data = irr_node->getLightData(); + data.Attenuation.X = energy; } } // ---------------------------------------------------------------------------- From f46ef1877f1194d28b9b825d624027b57f8b9423 Mon Sep 17 00:00:00 2001 From: Deve Date: Sun, 4 May 2025 20:34:24 +0200 Subject: [PATCH 696/830] Enable kart lighting effects on vulkan --- lib/graphics_engine/include/ge_spm.hpp | 2 + lib/graphics_engine/src/ge_spm.cpp | 10 ++++ lib/irrlicht/include/IMeshCache.h | 2 + src/karts/kart_gfx.cpp | 32 +++++++++---- src/karts/kart_gfx.hpp | 1 + src/karts/kart_model.cpp | 66 +++++++++++++++++++++++++- src/karts/kart_model.hpp | 14 +++++- 7 files changed, 113 insertions(+), 14 deletions(-) diff --git a/lib/graphics_engine/include/ge_spm.hpp b/lib/graphics_engine/include/ge_spm.hpp index df37c674f3a..e0f1e2ff2bb 100644 --- a/lib/graphics_engine/include/ge_spm.hpp +++ b/lib/graphics_engine/include/ge_spm.hpp @@ -83,6 +83,8 @@ friend class ::SPMeshLoader; unsigned getJointCount() const { return m_joint_using; } // ------------------------------------------------------------------------ void addMeshBuffer(GESPMBuffer* mb) { m_buffer.push_back(mb); } + // ------------------------------------------------------------------------ + void removeMeshBuffer(u32 nr); }; diff --git a/lib/graphics_engine/src/ge_spm.cpp b/lib/graphics_engine/src/ge_spm.cpp index f88715618dc..5c9c526095c 100644 --- a/lib/graphics_engine/src/ge_spm.cpp +++ b/lib/graphics_engine/src/ge_spm.cpp @@ -99,4 +99,14 @@ s32 GESPM::getJointIDWithArm(const c8* name, unsigned* arm_id) const return -1; } // getJointIDWithArm +// ---------------------------------------------------------------------------- +void GESPM::removeMeshBuffer(u32 nr) +{ + if (nr < m_buffer.size()) + { + m_buffer[nr]->drop(); + m_buffer.erase(m_buffer.begin() + nr); + } +} // removeMeshBuffer + } diff --git a/lib/irrlicht/include/IMeshCache.h b/lib/irrlicht/include/IMeshCache.h index 083fc5b75ca..ca7ea52d1c9 100644 --- a/lib/irrlicht/include/IMeshCache.h +++ b/lib/irrlicht/include/IMeshCache.h @@ -167,6 +167,8 @@ namespace scene /** Warning: If you have pointers to meshes that were loaded with ISceneManager::getMesh() and you did not grab them, then they may become invalid. */ virtual void clearUnusedMeshes() = 0; + + virtual void meshCacheChanged() {} }; diff --git a/src/karts/kart_gfx.cpp b/src/karts/kart_gfx.cpp index f0352f31a8c..153f034c880 100644 --- a/src/karts/kart_gfx.cpp +++ b/src/karts/kart_gfx.cpp @@ -37,6 +37,7 @@ #include "race/race_manager.hpp" #include +#include "IVideoDriver.h" KartGFX::KartGFX(const AbstractKart *kart, bool is_day) { @@ -54,7 +55,7 @@ KartGFX::KartGFX(const AbstractKart *kart, bool is_day) // Create nitro light core::vector3df location(0.0f, 0.5f, -0.5f*length - 0.05f); #ifndef SERVER_ONLY - if (!GUIEngine::isNoGraphics() && CVS->isGLSL()) + if (!GUIEngine::isNoGraphics() && supportsLight()) { m_nitro_light = irr_driver->addLight(location, /*force*/ 0.4f, /*radius*/ 5.0f, 0.0f, 0.4f, 1.0f, @@ -148,7 +149,7 @@ KartGFX::~KartGFX() delete m_all_emitters[i]; } // for i < KGFX_COUNT - if (!GUIEngine::isNoGraphics() && CVS->isGLSL()) + if (!GUIEngine::isNoGraphics() && supportsLight()) { m_nitro_light->drop(); m_skidding_light_1->drop(); @@ -472,7 +473,7 @@ void KartGFX::updateNitroGraphics(float nitro_frac) setCreationRateRelative(KartGFX::KGFX_NITROSMOKE1, nitro_frac); setCreationRateRelative(KartGFX::KGFX_NITROSMOKE2, nitro_frac); - if (CVS->isGLSL()) + if (supportsLight()) m_nitro_light->setVisible(true); } else @@ -482,7 +483,7 @@ void KartGFX::updateNitroGraphics(float nitro_frac) setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE1, 0); setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE2, 0); - if (CVS->isGLSL()) + if (supportsLight()) m_nitro_light->setVisible(false); } @@ -500,7 +501,7 @@ void KartGFX::updateNitroGraphics(float nitro_frac) void KartGFX::updateSkidLight(unsigned int level) { #ifndef SERVER_ONLY - if (!GUIEngine::isNoGraphics() && CVS->isGLSL()) + if (!GUIEngine::isNoGraphics() && supportsLight()) { m_skidding_light_1->setVisible(level == 1); m_skidding_light_2->setVisible(level > 1); @@ -559,7 +560,7 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper, setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE1, (float)nitro); setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE2, (float)nitro); - if (CVS->isGLSL()) + if (supportsLight()) m_nitro_light->setVisible(true); } else @@ -569,7 +570,7 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper, setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE1, 0.0f); setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE2, 0.0f); - if (CVS->isGLSL()) + if (supportsLight()) m_nitro_light->setVisible(false); } @@ -586,7 +587,7 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper, if (m_all_emitters[KGFX_SKID1R]) m_all_emitters[KGFX_SKID1R]->setParticleType(skid_kind); - if (CVS->isGLSL()) + if (supportsLight()) { m_skidding_light_1->setVisible(!red_skidding); m_skidding_light_2->setVisible(red_skidding); @@ -600,7 +601,7 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper, setCreationRateAbsolute(KartGFX::KGFX_SKIDL, 0.0f); setCreationRateAbsolute(KartGFX::KGFX_SKIDR, 0.0f); - if (CVS->isGLSL()) + if (supportsLight()) { m_skidding_light_1->setVisible(false); m_skidding_light_2->setVisible(false); @@ -613,7 +614,7 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper, void KartGFX::setGFXInvisible() { #ifndef SERVER_ONLY - if (!GUIEngine::isNoGraphics() && CVS->isGLSL()) + if (!GUIEngine::isNoGraphics() && supportsLight()) { m_nitro_light->setVisible(false); m_skidding_light_1->setVisible(false); @@ -622,3 +623,14 @@ void KartGFX::setGFXInvisible() } #endif } // setGFXInvisible + +// ---------------------------------------------------------------------------- +bool KartGFX::supportsLight() const +{ +#ifdef SERVER_ONLY + return false; +#else + return CVS->isGLSL() || + irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN; +#endif +} diff --git a/src/karts/kart_gfx.hpp b/src/karts/kart_gfx.hpp index f511f6485b1..6747ee1a4b7 100644 --- a/src/karts/kart_gfx.hpp +++ b/src/karts/kart_gfx.hpp @@ -103,6 +103,7 @@ class KartGFX const Vec3 &position, bool important); void resizeBox(const KartGFXType type, float new_size); + bool supportsLight() const; public: KartGFX(const AbstractKart *kart, bool is_day); ~KartGFX(); diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index e7e42bef294..bc605630b87 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -46,11 +46,16 @@ #include "utils/constants.hpp" #include "utils/log.hpp" +#include "IMeshCache.h" #include "IMeshManipulator.h" +#include "ILightSceneNode.h" +#include "IVideoDriver.h" + #include #include #include #include +#include #define SKELETON_DEBUG 0 @@ -529,7 +534,9 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool human_playe irr_driver->addMesh(obj.getModel(), "kart_headlight", parent, getRenderInfo()); #ifndef SERVER_ONLY - if (human_player && CVS->isGLSL() && CVS->isDeferredEnabled()) + bool supports_light = (CVS->isGLSL() && CVS->isDeferredEnabled()) || + irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN; + if (human_player && supports_light) { obj.setLight(headlight_model, each_energy, each_radius); } @@ -573,10 +580,21 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool human_playe void HeadlightObject::setLight(scene::ISceneNode* parent, float energy, float radius) { + bool is_vk = irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN; + if (is_vk && m_spotlight == 1) + energy *= 2.0f; m_node = irr_driver->addLight(core::vector3df(0.0f, 0.0f, 0.0f), energy, radius, m_headlight_color.getRed() / 255.f, m_headlight_color.getGreen() / 255.f, m_headlight_color.getBlue() / 255.f, false/*sun*/, parent); + if (is_vk && m_spotlight == 1) + { + scene::ILightSceneNode* ln = static_cast(m_node); + ln->setLightType(video::ELT_SPOT); + video::SLight& data = ln->getLightData(); + data.InnerCone = 30.0f / 180.0f * M_PI; + data.OuterCone = 45.0f / 180.0f * M_PI; + } m_node->grab(); } // setLight @@ -704,6 +722,7 @@ bool KartModel::loadModels(const KartProperties &kart_properties) mesh->freeMeshVertexBuffer(); } + std::set spotlight_meshes; for (unsigned int i = 0; i < m_headlight_objects.size(); i++) { HeadlightObject& obj = m_headlight_objects[i]; @@ -711,6 +730,19 @@ bool KartModel::loadModels(const KartProperties &kart_properties) scene::IMesh* mesh = irr_driver->getMesh(full_name); if (!mesh) continue; +#ifndef SERVER_ONLY + bool spotlight = spotlight_meshes.find(mesh) != spotlight_meshes.end(); + GE::GESPM* spm = dynamic_cast(mesh); + if (obj.getSpotlight() == -1) + { + if (!spotlight && spm && handleSpotlight(spm)) + { + spotlight_meshes.insert(spm); + spotlight = true; + } + obj.setSpotlight(spotlight); + } +#endif obj.setModel(mesh); #ifndef SERVER_ONLY SP::uploadSPM(obj.getModel()); @@ -888,8 +920,12 @@ void KartModel::loadHeadlights(const XMLNode &node) child->get("model", &model); video::SColor headlight_color(-1); child->get("color", &headlight_color); + bool is_spotlight = false; + int spotlight = -1; + if (child->get("spotlight", &is_spotlight)) + spotlight = is_spotlight; m_headlight_objects.push_back(HeadlightObject(model, location, - bone_name, headlight_color)); + bone_name, headlight_color, spotlight)); } else { @@ -1404,3 +1440,29 @@ const core::matrix4& KartModel::getInverseBoneMatrix return unused; return ret->second; } // getInverseBoneMatrix + +//----------------------------------------------------------------------------- +bool KartModel::handleSpotlight(GE::GESPM* spm) +{ +#ifndef SERVER_ONLY + unsigned count = spm->getMeshBufferCount(); + bool spotlight = false; + for (int i = count - 1; i >= 0; i--) + { + GE::GESPMBuffer* b = static_cast(spm->getMeshBuffer(i)); + b->destroyVertexIndexBuffer(); + video::SMaterial& m = b->getMaterial(); + std::string t; + if (m.getTexture(0)) + t = m.getTexture(0)->getFullPath().c_str(); + if (t.find("stk_conelight_a.png") != std::string::npos) + { + spotlight = true; + spm->removeMeshBuffer(i); + } + } + spm->finalize(); + irr_driver->getSceneManager()->getMeshCache()->meshCacheChanged(); + return spotlight; +#endif +} // handleSpotlight diff --git a/src/karts/kart_model.hpp b/src/karts/kart_model.hpp index cc38b40f1d0..b3c40c9deb9 100644 --- a/src/karts/kart_model.hpp +++ b/src/karts/kart_model.hpp @@ -31,7 +31,7 @@ namespace irr class ISceneNode; class IMeshSceneNode; } } using namespace irr; -namespace GE { class GERenderInfo; } +namespace GE { class GERenderInfo; class GESPM; } #include "utils/no_copy.hpp" #include "utils/vec3.hpp" @@ -113,16 +113,19 @@ class HeadlightObject /** Attach to which bone in kart model if not empty. */ std::string m_bone_name; + int m_spotlight; public: HeadlightObject() { m_model = NULL; m_node = NULL; + m_spotlight = -1; } // HeadlightObject // ------------------------------------------------------------------------ HeadlightObject(const std::string& filename, const core::matrix4& location, - const std::string& bone_name, const video::SColor& color) + const std::string& bone_name, const video::SColor& color, + int spotlight) { m_filename = filename; m_location = location; @@ -130,6 +133,7 @@ class HeadlightObject m_node = NULL; m_bone_name = bone_name; m_headlight_color = color; + m_spotlight = spotlight; } // HeadlightObjects // ------------------------------------------------------------------------ const std::string& getFilename() const { return m_filename; } @@ -151,6 +155,10 @@ class HeadlightObject // ------------------------------------------------------------------------ const std::string& getBoneName() const { return m_bone_name; } // ------------------------------------------------------------------------ + int getSpotlight() const { return m_spotlight; } + // ------------------------------------------------------------------------ + void setSpotlight(bool spot) { m_spotlight = spot; } + // ------------------------------------------------------------------------ }; // class HeadlightObject // ============================================================================ @@ -339,6 +347,8 @@ class KartModel : public scene::IAnimationEndCallBack, public NoCopy node->setRotation(rotation); node->setScale(scale); } + // ------------------------------------------------------------------------ + bool handleSpotlight(GE::GESPM* spm); public: KartModel(bool is_master); From 2403662c78c4a151f5d51c843f39d37464d447f6 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 6 May 2025 03:27:02 +0400 Subject: [PATCH 697/830] Various small refactors, mainly for string constants --- src/network/protocols/command_manager.cpp | 270 +++++++++++++--------- src/network/protocols/command_manager.hpp | 9 - src/utils/lobby_asset_manager.cpp | 4 +- src/utils/lobby_queues.cpp | 12 +- src/utils/tournament.cpp | 4 +- 5 files changed, 165 insertions(+), 134 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 2cafc5f61aa..351d073c364 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -60,6 +60,15 @@ namespace { + static const std::string g_addon_prefix = "addon_"; + + static const std::string g_type_kart = "kart"; + static const std::string g_type_map = "map"; + + static const std::string g_type_track = "track"; + static const std::string g_type_arena = "arena"; + static const std::string g_type_soccer = "soccer"; + const std::vector g_queue_names = { "", "mqueue", "mcyclic", "mboth", "kqueue", "qregular", "", "", @@ -113,6 +122,33 @@ namespace } // another_cyclic_queue // ==================================================================== + + // Auxiliary things, should be moved somewhere because they just help + // in commands but have nothing to do with CM itself + + static std::vector> g_aux_mode_aliases = { + {"m0"}, + {"m1"}, + {"m2"}, + {"m3", "normal", "normal-race", "race"}, + {"m4", "tt", "time-trial", "trial"}, + {"m5"}, + {"m6", "soccer", "football"}, + {"m7", "ffa", "free-for-all", "free", "for", "all"}, + {"m8", "ctf", "capture-the-flag", "capture", "the", "flag"} + }; + static std::vector> g_aux_difficulty_aliases = { + {"d0", "novice", "easy"}, + {"d1", "intermediate", "medium"}, + {"d2", "expert", "hard"}, + {"d3", "supertux", "super", "best"} + }; + static std::vector> g_aux_goal_aliases = { + {"tl", "time-limit", "time", "minutes"}, + {"gl", "goal-limit", "goal", "goals"} + }; + + // End of auxiliary things } // namespace EnumExtendedReader CommandManager::mode_scope_reader({ @@ -405,7 +441,7 @@ void CommandManager::initCommandsInfo() delete root; delete root2; } // initCommandsInfo -// ======================================================================== +//----------------------------------------------------------------------------- void CommandManager::initCommands() { @@ -415,13 +451,15 @@ void CommandManager::initCommands() initCommandsInfo(); - auto applyFunctionIfPossible = [&](std::string&& name, void (CommandManager::*f)(Context& context)) { - if (mp.count(name) == 0) + auto applyFunctionIfPossible = [&](std::string&& name, void (CM::*f)(Context& context)) { + auto it = mp.find(name); + if (it == mp.end()) return; - std::shared_ptr command = mp[name].lock(); - if (!command) { + + std::shared_ptr command = it->second.lock(); + if (!command) return; - } + command->changeFunction(f); }; // special permissions according to ServerConfig options @@ -592,8 +630,8 @@ void CommandManager::initAssets() std::map what_exists; for (std::string& s: all_t) { - if (StringUtils::startsWith(s, "addon_")) - what_exists[s.substr(6)] |= 2; + if (StringUtils::startsWith(s, g_addon_prefix)) + what_exists[s.substr(g_addon_prefix.size())] |= 2; else what_exists[s] |= 1; } @@ -602,21 +640,21 @@ void CommandManager::initAssets() if (p.second != 3) { bool is_addon = (p.second == 2); - std::string value = (is_addon ? "addon_" : "") + p.first; + std::string value = (is_addon ? g_addon_prefix : "") + p.first; m_stf_all_maps.add(p.first, value); - m_stf_all_maps.add("addon_" + p.first, value); + m_stf_all_maps.add(g_addon_prefix + p.first, value); if (is_addon) { m_stf_addon_maps.add(p.first, value); - m_stf_addon_maps.add("addon_" + p.first, value); + m_stf_addon_maps.add(g_addon_prefix + p.first, value); } } else { m_stf_all_maps.add(p.first, p.first); - m_stf_all_maps.add("addon_" + p.first, "addon_" + p.first); - m_stf_addon_maps.add(p.first, "addon_" + p.first); - m_stf_addon_maps.add("addon_" + p.first, "addon_" + p.first); + m_stf_all_maps.add(g_addon_prefix + p.first, g_addon_prefix + p.first); + m_stf_addon_maps.add(p.first, g_addon_prefix + p.first); + m_stf_addon_maps.add(g_addon_prefix + p.first, g_addon_prefix + p.first); } } } // initAssets @@ -626,28 +664,6 @@ void CommandManager::setupContextUser() { initCommands(); initAssets(); - - m_aux_mode_aliases = { - {"m0"}, - {"m1"}, - {"m2"}, - {"m3", "normal", "normal-race", "race"}, - {"m4", "tt", "time-trial", "trial"}, - {"m5"}, - {"m6", "soccer", "football"}, - {"m7", "ffa", "free-for-all", "free", "for", "all"}, - {"m8", "ctf", "capture-the-flag", "capture", "the", "flag"} - }; - m_aux_difficulty_aliases = { - {"d0", "novice", "easy"}, - {"d1", "intermediate", "medium"}, - {"d2", "expert", "hard"}, - {"d3", "supertux", "super", "best"} - }; - m_aux_goal_aliases = { - {"tl", "time-limit", "time", "minutes"}, - {"gl", "goal-limit", "goal", "goals"} - }; } // CommandManager // ======================================================================== @@ -904,7 +920,10 @@ void CommandManager::error(Context& context, bool is_error) } msg = command->getUsage(); if (msg.empty()) - msg = "An error occurred while invoking command \"" + command->getFullName() + "\"."; + msg = StringUtils::insertValues("An error occurred " + "while invoking command \"%s\".", + command->getFullName().c_str()); + if (is_error) msg += "\n/!\\ Please report this error to the server owner"; getLobby()->sendStringToPeer(peer, msg); @@ -1143,7 +1162,7 @@ void CommandManager::process_config(Context& context) int difficulty = getLobby()->getDifficulty(); int mode = getLobby()->getGameMode(); bool goal_target = (getGameSetupFromCtx()->hasExtraServerInfo() ? getLobby()->isSoccerGoalTarget() : false); -// m_aux_goal_aliases[goal_target ? 1 : 0][0] +// g_aux_goal_aliases[goal_target ? 1 : 0][0] std::string msg = "Current config: "; auto get_first_if_exists = [&](std::vector& v) -> std::string { if (v.size() < 2) @@ -1151,11 +1170,11 @@ void CommandManager::process_config(Context& context) return v[1]; }; msg += " "; - msg += get_first_if_exists(m_aux_mode_aliases[mode]); + msg += get_first_if_exists(g_aux_mode_aliases[mode]); msg += " "; - msg += get_first_if_exists(m_aux_difficulty_aliases[difficulty]); + msg += get_first_if_exists(g_aux_difficulty_aliases[difficulty]); msg += " "; - msg += get_first_if_exists(m_aux_goal_aliases[goal_target ? 1 : 0]); + msg += get_first_if_exists(g_aux_goal_aliases[goal_target ? 1 : 0]); if (!getSettings()->isServerConfigurable()) msg += " (not configurable)"; getLobby()->sendStringToPeer(peer, msg); @@ -1180,28 +1199,28 @@ void CommandManager::process_config_assign(Context& context) // bool gp = false; for (unsigned i = 1; i < argv.size(); i++) { - for (unsigned j = 0; j < m_aux_mode_aliases.size(); ++j) { + for (unsigned j = 0; j < g_aux_mode_aliases.size(); ++j) { if (j <= 2 || j == 5) { // Switching to GP or modes 2, 5 is not supported yet continue; } - for (std::string& alias: m_aux_mode_aliases[j]) { + for (std::string& alias: g_aux_mode_aliases[j]) { if (argv[i] == alias) { mode = j; user_chose_mode = true; } } } - for (unsigned j = 0; j < m_aux_difficulty_aliases.size(); ++j) { - for (std::string& alias: m_aux_difficulty_aliases[j]) { + for (unsigned j = 0; j < g_aux_difficulty_aliases.size(); ++j) { + for (std::string& alias: g_aux_difficulty_aliases[j]) { if (argv[i] == alias) { difficulty = j; user_chose_difficulty = true; } } } - for (unsigned j = 0; j < m_aux_goal_aliases.size(); ++j) { - for (std::string& alias: m_aux_goal_aliases[j]) { + for (unsigned j = 0; j < g_aux_goal_aliases.size(); ++j) { + for (std::string& alias: g_aux_goal_aliases[j]) { if (argv[i] == alias) { goal_target = (bool)j; user_chose_target = true; @@ -1224,11 +1243,11 @@ void CommandManager::process_config_assign(Context& context) // Definitely not the best format as there are extra words, // but I'll think how to resolve it if (user_chose_mode) - vote(context, "config mode", m_aux_mode_aliases[mode][0]); + vote(context, "config mode", g_aux_mode_aliases[mode][0]); if (user_chose_difficulty) - vote(context, "config difficulty", m_aux_difficulty_aliases[difficulty][0]); + vote(context, "config difficulty", g_aux_difficulty_aliases[difficulty][0]); if (user_chose_target) - vote(context, "config target", m_aux_goal_aliases[goal_target ? 1 : 0][0]); + vote(context, "config target", g_aux_goal_aliases[goal_target ? 1 : 0][0]); return; } getLobby()->handleServerConfiguration(peer, difficulty, mode, goal_target); @@ -1312,10 +1331,10 @@ void CommandManager::process_addons(Context& context) // removed const reference so that I can modify `from` // without changing the original container, we copy everything anyway std::set from = - (argv[1] == "kart" ? asset_manager->getAddonKarts() : - (argv[1] == "track" ? asset_manager->getAddonTracks() : - (argv[1] == "arena" ? asset_manager->getAddonArenas() : - /*argv[1] == "soccer" ?*/ asset_manager->getAddonSoccers() + (argv[1] == g_type_kart ? asset_manager->getAddonKarts() : + (argv[1] == g_type_track ? asset_manager->getAddonTracks() : + (argv[1] == g_type_arena ? asset_manager->getAddonArenas() : + /*argv[1] == g_type_soccer ?*/ asset_manager->getAddonSoccers() ))); if (apply_filters) getAssetManager()->applyAllFilters(from, false); // happily the type is never karts in this line @@ -1336,7 +1355,7 @@ void CommandManager::process_addons(Context& context) continue; ++num_players; const auto& kt = p->getClientAssets(); - const auto& container = (argv[1] == "kart" ? kt.first : kt.second); + const auto& container = (argv[1] == g_type_kart ? kt.first : kt.second); for (auto& pr: result) if (container.find(pr.first) == container.end()) pr.second.push_back(p->getMainProfile()); @@ -1391,12 +1410,13 @@ void CommandManager::process_addons(Context& context) bool nothing = true; for (const std::string& s: all_have) { - if (s.length() < 6 || s.substr(0, 6) != "addon_") + if (s.length() < g_addon_prefix.size() || + s.substr(0, g_addon_prefix.size()) != g_addon_prefix) continue; response.push_back(nothing ? ':' : ','); nothing = false; response.push_back(' '); - response += s.substr(6); + response += s.substr(g_addon_prefix.size()); } if (response.length() > 100) response += "\nTotal: " + std::to_string(all_have.size()); @@ -1410,9 +1430,13 @@ void CommandManager::process_addons(Context& context) response += ". More addons to install:"; for (unsigned i = 0; i < result.size(); ++i) { - response += "\n/installaddon " + result[i].first.substr(6) + " , missing for " - + std::to_string(result[i].second.size()) - + " player(s):"; + response += "\n"; + response += StringUtils::insertValues( + "/installaddon %s , missing for %d player(s):", + result[i].first.substr(g_addon_prefix.size()).c_str(), + result[i].second.size() + ); + std::sort(result[i].second.begin(), result[i].second.end()); for (unsigned j = 0; j < result[i].second.size(); ++j) { @@ -1422,8 +1446,10 @@ void CommandManager::process_addons(Context& context) } } } else { - response = "No one in the lobby can play. Found " - + std::to_string(all_have.size()) + " assets on the server."; + response = StringUtils::insertValues( + "No one in the lobby can play. " + "Found %d assets on the server.", + all_have.size()); } getLobby()->sendStringToPeer(peer, response); } // process_addons @@ -1482,8 +1508,8 @@ void CommandManager::process_checkaddon(Context& context) std::string response = ""; std::string item_name[3]; bool needed[3]; - item_name[HAS_KART] = "kart"; - item_name[HAS_MAP] = "map"; + item_name[HAS_KART] = g_type_kart; + item_name[HAS_MAP] = g_type_map; needed[HAS_KART] = (players[HAS_KART].size() + players[HAS_MAP | HAS_KART].size() > 0); needed[HAS_MAP] = (players[HAS_MAP].size() + players[HAS_MAP | HAS_KART].size() > 0); if (server_status & HAS_KART) @@ -1493,7 +1519,10 @@ void CommandManager::process_checkaddon(Context& context) if (!needed[HAS_KART] && !needed[HAS_MAP]) { - response = "Neither server nor clients have addon " + argv[1] + " installed"; + response = StringUtils::insertValues( + "Neither server nor clients have addon %s installed", + argv[1].c_str() + ); } else { @@ -1578,11 +1607,16 @@ void CommandManager::process_lsa(Context& context) } std::string response = ""; auto& argv = context.m_argv; - bool has_options = argv.size() > 1 && - (argv[1].compare("-track") == 0 || - argv[1].compare("-arena") == 0 || - argv[1].compare("-kart") == 0 || - argv[1].compare("-soccer") == 0); + + // "-" left from the 'vanilla' code. Not sure if it's worth it. + bool has_options = argv.size() > 1 && ( + argv[1].compare("-" + g_type_track) == 0 || + argv[1].compare("-" + g_type_arena) == 0 || + argv[1].compare("-" + g_type_kart) == 0 || + argv[1].compare("-" + g_type_soccer) == 0 + ); + + // kimden: what is this, remove if (argv.size() == 1 || argv.size() > 3 || argv[1].size() < 3 || (argv.size() == 2 && (argv[1].size() < 3 || has_options)) || (argv.size() == 3 && (!has_options || argv[2].size() < 3))) @@ -1594,10 +1628,10 @@ void CommandManager::process_lsa(Context& context) std::string text = ""; if (argv.size() > 1) { - if (argv[1].compare("-track") == 0 || - argv[1].compare("-arena") == 0 || - argv[1].compare("-kart") == 0 || - argv[1].compare("-soccer") == 0) + if (argv[1].compare("-" + g_type_track) == 0 || + argv[1].compare("-" + g_type_arena) == 0 || + argv[1].compare("-" + g_type_kart) == 0 || + argv[1].compare("-" + g_type_soccer) == 0) type = argv[1].substr(1); if ((argv.size() == 2 && type.empty()) || argv.size() == 3) text = argv[argv.size() - 1]; @@ -1605,26 +1639,22 @@ void CommandManager::process_lsa(Context& context) std::set total_addons; auto asset_manager = getAssetManager(); - if (type.empty() || // not specify addon type - (!type.empty() && type.compare("kart") == 0)) // list kart addon + if (type.empty() || type.compare(g_type_kart) == 0) { const auto& collection = asset_manager->getAddonKarts(); total_addons.insert(collection.begin(), collection.end()); } - if (type.empty() || // not specify addon type - (!type.empty() && type.compare("track") == 0)) + if (type.empty() || type.compare(g_type_track) == 0) { const auto& collection = asset_manager->getAddonTracks(); total_addons.insert(collection.begin(), collection.end()); } - if (type.empty() || // not specify addon type - (!type.empty() && type.compare("arena") == 0)) + if (type.empty() || type.compare(g_type_arena) == 0) { const auto& collection = asset_manager->getAddonArenas(); total_addons.insert(collection.begin(), collection.end()); } - if (type.empty() || // not specify addon type - (!type.empty() && type.compare("soccer") == 0)) + if (type.empty() || type.compare(g_type_soccer) == 0) { const auto& collection = asset_manager->getAddonSoccers(); total_addons.insert(collection.begin(), collection.end()); @@ -1632,11 +1662,10 @@ void CommandManager::process_lsa(Context& context) std::string msg = ""; for (auto& addon : total_addons) { - // addon_ (6 letters) - if (!text.empty() && addon.find(text, 6) == std::string::npos) + if (!text.empty() && addon.find(text, g_addon_prefix.size()) == std::string::npos) continue; - msg += addon.substr(6); + msg += addon.substr(g_addon_prefix.size()); msg += ", "; } if (msg.empty()) @@ -1672,8 +1701,8 @@ void CommandManager::process_pha(Context& context) return; std::string addon_id = argv[1]; - if (StringUtils::startsWith(addon_id, "addon_")) - addon_id = addon_id.substr(6); + if (StringUtils::startsWith(addon_id, g_addon_prefix)) + addon_id = addon_id.substr(g_addon_prefix.size()); std::string player_name = argv[2]; std::shared_ptr player_peer = STKHost::get()->findPeerByName( StringUtils::utf8ToWide(player_name)); @@ -1858,16 +1887,16 @@ void CommandManager::process_pas(Context& context) } else { - std::string msg = player_name; - msg += "'s addon score:"; + std::string msg = StringUtils::insertValues("%s's addon score:", + player_name.c_str()); if (scores[AS_KART] != -1) - msg += " karts: " + StringUtils::toString(scores[AS_KART]) + ","; + msg += StringUtils::insertValues(" karts: %d,", scores[AS_KART]); if (scores[AS_TRACK] != -1) - msg += " tracks: " + StringUtils::toString(scores[AS_TRACK]) + ","; + msg += StringUtils::insertValues(" tracks: %d,", scores[AS_TRACK]); if (scores[AS_ARENA] != -1) - msg += " arenas: " + StringUtils::toString(scores[AS_ARENA]) + ","; + msg += StringUtils::insertValues(" arenas: %d,", scores[AS_ARENA]); if (scores[AS_SOCCER] != -1) - msg += " fields: " + StringUtils::toString(scores[AS_SOCCER]) + ","; + msg += StringUtils::insertValues(" fields: %d,", scores[AS_SOCCER]); msg.pop_back(); response = msg; } @@ -1906,13 +1935,13 @@ void CommandManager::process_everypas(Context& context) result.emplace_back(p->getMainProfile(), overall); } int sorting_idx = -1; - if (sorting_type == "kart" || sorting_type == "karts") + if (sorting_type == g_type_kart || sorting_type == g_type_kart + "s") sorting_idx = 0; - if (sorting_type == "track" || sorting_type == "tracks") + if (sorting_type == g_type_track || sorting_type == g_type_track + "s") sorting_idx = 1; - if (sorting_type == "arena" || sorting_type == "arenas") + if (sorting_type == g_type_arena || sorting_type == g_type_arena + "s") sorting_idx = 2; - if (sorting_type == "soccer" || sorting_type == "soccers") + if (sorting_type == g_type_soccer || sorting_type == g_type_soccer + "s") sorting_idx = 3; if (sorting_idx != -1) { @@ -1938,21 +1967,23 @@ void CommandManager::process_everypas(Context& context) } // I don't really know if it should be soccer or field, both are used // in different situations - std::vector desc = { "karts", "tracks", "arenas", "fields" }; + std::vector desc = {g_type_kart, g_type_track, g_type_arena, g_type_soccer}; for (auto& row: result) { - response += "\n" + getLobby()->encodeProfileNameForPeer(row.first, peer.get()); + response += "\n"; + std::string decorated_name = getLobby()->encodeProfileNameForPeer(row.first, peer.get()); + bool negative = true; for (int item = 0; item < AS_TOTAL; item++) negative &= row.second[item] == -1; if (negative) - response += " has no addons"; + response += StringUtils::insertValues("%s has no addons", decorated_name.c_str()); else { - std::string msg = "'s addon score:"; + std::string msg = StringUtils::insertValues("%s's addon score:", decorated_name.c_str()); for (int i = 0; i < AS_TOTAL; i++) if (row.second[i] != -1) - msg += " " + desc[i] + ": " + StringUtils::toString(row.second[i]) + ","; + msg += StringUtils::insertValues(" %ss: %d,", desc[i].c_str(), row.second[i]); msg.pop_back(); response += msg; } @@ -2510,6 +2541,8 @@ void CommandManager::process_queue_push(Context& context) } auto& cell = context.m_argv[2 + p.index]; suffix_length = cell.length() - p.value.length() - prefix_length; + + // kimden: this looks horrendous but I remember it was worth it back then if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, 2 + p.index, m_stf_all_maps, 3, false, false, false, subidx, prefix_length, cell.length() - suffix_length)) @@ -2539,10 +2572,14 @@ void CommandManager::process_queue_push(Context& context) add_to_queue(x, mask, to_front, filter_text); } - msg += "Pushed { " + filter_text + " }" - + " to the " + (to_front ? "front" : "back") - + " of " + get_queue_name(x) + ", current queue size: " - + std::to_string(get_queue(x).size()) + "\n"; + msg += StringUtils::insertValues( + "Pushed { %s } to the %s of %s, current queue size: %d", + filter_text.c_str(), + (to_front ? "front" : "back"), + get_queue_name(x).c_str(), + get_queue(x).size() + ); + msg += "\n"; } } @@ -3564,8 +3601,9 @@ void CommandManager::process_slots(Context& context) return; } int current = getSettings()->getCurrentMaxPlayersInGame(); - getLobby()->sendStringToPeer(peer, "Number of slots is currently " + - std::to_string(current)); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "Number of slots is currently %d", + current)); } // process_slots // ======================================================================== @@ -3597,7 +3635,9 @@ void CommandManager::process_slots_assign(Context& context) } getSettings()->setCurrentMaxPlayersInGame((unsigned)number); getLobby()->updatePlayerList(); - getLobby()->sendStringToAllPeers("Number of playable slots is now " + argv[1]); + getLobby()->sendStringToAllPeers(StringUtils::insertValues( + "Number of playable slots is now %s", + number)); } // process_slots_assign // ======================================================================== @@ -3609,7 +3649,9 @@ void CommandManager::process_time(Context& context) error(context, true); return; } - getLobby()->sendStringToPeer(peer, "Server time: " + StkTime::getLogTime()); + getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + "Server time: %s", + StkTime::getLogTime().c_str())); } // process_time // ======================================================================== @@ -4144,12 +4186,12 @@ std::string CommandManager::getAddonPreferredType() const { int mode = getLobby()->getGameMode(); if (0 <= mode && mode <= 4) - return "track"; + return g_type_track; if (mode == 6) - return "soccer"; + return g_type_soccer; if (7 <= mode && mode <= 8) - return "arena"; - return "track"; // default choice + return g_type_arena; + return g_type_track; // default choice } // getAddonPreferredType // ======================================================================== diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 5a7f672f052..cecffecc8f4 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -245,15 +245,6 @@ class CommandManager: public LobbyContextComponent std::vector m_current_argv; - // Auxiliary things, should be moved somewhere because they just help - // in commands but have nothing to do with CM itself - - std::vector> m_aux_mode_aliases; - std::vector> m_aux_difficulty_aliases; - std::vector> m_aux_goal_aliases; - - // End of auxiliary things - void initCommandsInfo(); void initCommands(); diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp index a57c237770b..66a0968af72 100644 --- a/src/utils/lobby_asset_manager.cpp +++ b/src/utils/lobby_asset_manager.cpp @@ -634,10 +634,10 @@ void LobbyAssetManager::applyAllFilters(std::set& maps, bool use_hi { if (isTournament()) getTournament()->applyFiltersForThisGame(map_context); - map_context.wildcards = m_map_history; + getQueues()->applyFrontMapFilters(map_context); } - swap(maps, map_context.elements); + std::swap(maps, map_context.elements); } // applyAllFilters //----------------------------------------------------------------------------- diff --git a/src/utils/lobby_queues.cpp b/src/utils/lobby_queues.cpp index 839f90baddb..0ab79f7bfc2 100644 --- a/src/utils/lobby_queues.cpp +++ b/src/utils/lobby_queues.cpp @@ -113,26 +113,22 @@ void LobbyQueues::resetToDefaultSettings(const std::set& preserved_ void LobbyQueues::applyFrontMapFilters(FilterContext& context) { if (!m_onetime_tracks_queue.empty()) - { m_onetime_tracks_queue.front()->apply(context); - } + if (!m_cyclic_tracks_queue.empty()) - { m_cyclic_tracks_queue.front()->apply(context); - } + } // applyFrontMapFilters //----------------------------------------------------------------------------- void LobbyQueues::applyFrontKartFilters(FilterContext& context) { if (!m_onetime_karts_queue.empty()) - { m_onetime_karts_queue.front()->apply(context); - } + if (!m_cyclic_karts_queue.empty()) - { m_cyclic_karts_queue.front()->apply(context); - } + } // applyFrontKartFilters //----------------------------------------------------------------------------- diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp index 5c5e524facf..d432b0732b8 100644 --- a/src/utils/tournament.cpp +++ b/src/utils/tournament.cpp @@ -45,8 +45,10 @@ void Tournament::setupContextUser() void Tournament::applyFiltersForThisGame(FilterContext& track_context) { - track_context.wildcards = m_arenas; + std::vector prev_wildcards = m_arenas; + std::swap(track_context.wildcards, prev_wildcards); m_track_filters[m_game].apply(track_context); + std::swap(track_context.wildcards, prev_wildcards); } // applyFiltersForThisGame //----------------------------------------------------------------------------- From 7c72a531057f40a0c53c0c6555bd68064d8aea7f Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 6 May 2025 22:46:12 +0200 Subject: [PATCH 698/830] Update for latest MoltenVK --- lib/graphics_engine/include/glad/vulkan.h | 15728 +++++++++++++---- lib/graphics_engine/include/mvk_config.h | 1059 -- lib/graphics_engine/include/vk_platform.h | 30 +- lib/graphics_engine/include/vulkan_wrapper.h | 10 +- lib/graphics_engine/src/ge_vulkan_driver.cpp | 34 +- lib/graphics_engine/src/vulkan.c | 1744 +- lib/irrlicht/source/Irrlicht/MoltenVK.mm | 10 +- 7 files changed, 13800 insertions(+), 4815 deletions(-) delete mode 100644 lib/graphics_engine/include/mvk_config.h diff --git a/lib/graphics_engine/include/glad/vulkan.h b/lib/graphics_engine/include/glad/vulkan.h index 6a6123b7578..b59e27a68f8 100644 --- a/lib/graphics_engine/include/glad/vulkan.h +++ b/lib/graphics_engine/include/glad/vulkan.h @@ -1,27 +1,28 @@ /** - * Loader generated by glad 2.0.0-beta on Wed Nov 18 17:59:49 2020 + * Loader generated by glad 2.0.8 on Tue May 6 05:06:31 2025 + * + * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 * * Generator: C/C++ * Specification: vk - * Extensions: 211 + * Extensions: 392 * * APIs: - * - vulkan=1.2 + * - vulkan=1.4 * * Options: - * - MX_GLOBAL = False - * - ON_DEMAND = False - * - LOADER = False * - ALIAS = False - * - HEADER_ONLY = False * - DEBUG = False + * - HEADER_ONLY = False + * - LOADER = False * - MX = False + * - ON_DEMAND = False * * Commandline: - * --api='vulkan=1.2' --extensions='VK_AMD_buffer_marker,VK_AMD_device_coherent_memory,VK_AMD_display_native_hdr,VK_AMD_draw_indirect_count,VK_AMD_gcn_shader,VK_AMD_gpu_shader_half_float,VK_AMD_gpu_shader_int16,VK_AMD_memory_overallocation_behavior,VK_AMD_mixed_attachment_samples,VK_AMD_negative_viewport_height,VK_AMD_pipeline_compiler_control,VK_AMD_rasterization_order,VK_AMD_shader_ballot,VK_AMD_shader_core_properties,VK_AMD_shader_core_properties2,VK_AMD_shader_explicit_vertex_parameter,VK_AMD_shader_fragment_mask,VK_AMD_shader_image_load_store_lod,VK_AMD_shader_info,VK_AMD_shader_trinary_minmax,VK_AMD_texture_gather_bias_lod,VK_ANDROID_external_memory_android_hardware_buffer,VK_EXT_4444_formats,VK_EXT_acquire_xlib_display,VK_EXT_astc_decode_mode,VK_EXT_blend_operation_advanced,VK_EXT_buffer_device_address,VK_EXT_calibrated_timestamps,VK_EXT_conditional_rendering,VK_EXT_conservative_rasterization,VK_EXT_custom_border_color,VK_EXT_debug_marker,VK_EXT_debug_report,VK_EXT_debug_utils,VK_EXT_depth_clip_enable,VK_EXT_depth_range_unrestricted,VK_EXT_descriptor_indexing,VK_EXT_direct_mode_display,VK_EXT_directfb_surface,VK_EXT_discard_rectangles,VK_EXT_display_control,VK_EXT_display_surface_counter,VK_EXT_extended_dynamic_state,VK_EXT_external_memory_dma_buf,VK_EXT_external_memory_host,VK_EXT_filter_cubic,VK_EXT_fragment_density_map,VK_EXT_fragment_density_map2,VK_EXT_fragment_shader_interlock,VK_EXT_full_screen_exclusive,VK_EXT_global_priority,VK_EXT_hdr_metadata,VK_EXT_headless_surface,VK_EXT_host_query_reset,VK_EXT_image_drm_format_modifier,VK_EXT_image_robustness,VK_EXT_index_type_uint8,VK_EXT_inline_uniform_block,VK_EXT_line_rasterization,VK_EXT_memory_budget,VK_EXT_memory_priority,VK_EXT_metal_surface,VK_EXT_pci_bus_info,VK_EXT_pipeline_creation_cache_control,VK_EXT_pipeline_creation_feedback,VK_EXT_post_depth_coverage,VK_EXT_private_data,VK_EXT_queue_family_foreign,VK_EXT_robustness2,VK_EXT_sample_locations,VK_EXT_sampler_filter_minmax,VK_EXT_scalar_block_layout,VK_EXT_separate_stencil_usage,VK_EXT_shader_atomic_float,VK_EXT_shader_demote_to_helper_invocation,VK_EXT_shader_stencil_export,VK_EXT_shader_subgroup_ballot,VK_EXT_shader_subgroup_vote,VK_EXT_shader_viewport_index_layer,VK_EXT_subgroup_size_control,VK_EXT_swapchain_colorspace,VK_EXT_texel_buffer_alignment,VK_EXT_texture_compression_astc_hdr,VK_EXT_tooling_info,VK_EXT_transform_feedback,VK_EXT_validation_cache,VK_EXT_validation_features,VK_EXT_validation_flags,VK_EXT_vertex_attribute_divisor,VK_EXT_ycbcr_image_arrays,VK_FUCHSIA_imagepipe_surface,VK_GGP_frame_token,VK_GGP_stream_descriptor_surface,VK_GOOGLE_decorate_string,VK_GOOGLE_display_timing,VK_GOOGLE_hlsl_functionality1,VK_GOOGLE_user_type,VK_IMG_filter_cubic,VK_IMG_format_pvrtc,VK_INTEL_performance_query,VK_INTEL_shader_integer_functions2,VK_KHR_16bit_storage,VK_KHR_8bit_storage,VK_KHR_android_surface,VK_KHR_bind_memory2,VK_KHR_buffer_device_address,VK_KHR_create_renderpass2,VK_KHR_dedicated_allocation,VK_KHR_deferred_host_operations,VK_KHR_depth_stencil_resolve,VK_KHR_descriptor_update_template,VK_KHR_device_group,VK_KHR_device_group_creation,VK_KHR_display,VK_KHR_display_swapchain,VK_KHR_draw_indirect_count,VK_KHR_driver_properties,VK_KHR_external_fence,VK_KHR_external_fence_capabilities,VK_KHR_external_fence_fd,VK_KHR_external_fence_win32,VK_KHR_external_memory,VK_KHR_external_memory_capabilities,VK_KHR_external_memory_fd,VK_KHR_external_memory_win32,VK_KHR_external_semaphore,VK_KHR_external_semaphore_capabilities,VK_KHR_external_semaphore_fd,VK_KHR_external_semaphore_win32,VK_KHR_get_display_properties2,VK_KHR_get_memory_requirements2,VK_KHR_get_physical_device_properties2,VK_KHR_get_surface_capabilities2,VK_KHR_image_format_list,VK_KHR_imageless_framebuffer,VK_KHR_incremental_present,VK_KHR_maintenance1,VK_KHR_maintenance2,VK_KHR_maintenance3,VK_KHR_multiview,VK_KHR_performance_query,VK_KHR_pipeline_executable_properties,VK_KHR_pipeline_library,VK_KHR_push_descriptor,VK_KHR_ray_tracing,VK_KHR_relaxed_block_layout,VK_KHR_sampler_mirror_clamp_to_edge,VK_KHR_sampler_ycbcr_conversion,VK_KHR_separate_depth_stencil_layouts,VK_KHR_shader_atomic_int64,VK_KHR_shader_clock,VK_KHR_shader_draw_parameters,VK_KHR_shader_float16_int8,VK_KHR_shader_float_controls,VK_KHR_shader_non_semantic_info,VK_KHR_shader_subgroup_extended_types,VK_KHR_shared_presentable_image,VK_KHR_spirv_1_4,VK_KHR_storage_buffer_storage_class,VK_KHR_surface,VK_KHR_surface_protected_capabilities,VK_KHR_swapchain,VK_KHR_swapchain_mutable_format,VK_KHR_timeline_semaphore,VK_KHR_uniform_buffer_standard_layout,VK_KHR_variable_pointers,VK_KHR_vulkan_memory_model,VK_KHR_wayland_surface,VK_KHR_win32_keyed_mutex,VK_KHR_win32_surface,VK_KHR_xcb_surface,VK_KHR_xlib_surface,VK_MVK_ios_surface,VK_MVK_macos_surface,VK_NN_vi_surface,VK_NVX_image_view_handle,VK_NVX_multiview_per_view_attributes,VK_NV_clip_space_w_scaling,VK_NV_compute_shader_derivatives,VK_NV_cooperative_matrix,VK_NV_corner_sampled_image,VK_NV_coverage_reduction_mode,VK_NV_dedicated_allocation,VK_NV_dedicated_allocation_image_aliasing,VK_NV_device_diagnostic_checkpoints,VK_NV_device_diagnostics_config,VK_NV_device_generated_commands,VK_NV_external_memory,VK_NV_external_memory_capabilities,VK_NV_external_memory_win32,VK_NV_fill_rectangle,VK_NV_fragment_coverage_to_color,VK_NV_fragment_shader_barycentric,VK_NV_framebuffer_mixed_samples,VK_NV_geometry_shader_passthrough,VK_NV_glsl_shader,VK_NV_mesh_shader,VK_NV_ray_tracing,VK_NV_representative_fragment_test,VK_NV_sample_mask_override_coverage,VK_NV_scissor_exclusive,VK_NV_shader_image_footprint,VK_NV_shader_sm_builtins,VK_NV_shader_subgroup_partitioned,VK_NV_shading_rate_image,VK_NV_viewport_array2,VK_NV_viewport_swizzle,VK_NV_win32_keyed_mutex,VK_QCOM_render_pass_shader_resolve,VK_QCOM_render_pass_store_ops,VK_QCOM_render_pass_transform' c + * --api='vulkan=1.4' --extensions='VK_AMDX_shader_enqueue,VK_AMD_anti_lag,VK_AMD_buffer_marker,VK_AMD_device_coherent_memory,VK_AMD_display_native_hdr,VK_AMD_draw_indirect_count,VK_AMD_gcn_shader,VK_AMD_gpu_shader_half_float,VK_AMD_gpu_shader_int16,VK_AMD_memory_overallocation_behavior,VK_AMD_mixed_attachment_samples,VK_AMD_negative_viewport_height,VK_AMD_pipeline_compiler_control,VK_AMD_rasterization_order,VK_AMD_shader_ballot,VK_AMD_shader_core_properties,VK_AMD_shader_core_properties2,VK_AMD_shader_early_and_late_fragment_tests,VK_AMD_shader_explicit_vertex_parameter,VK_AMD_shader_fragment_mask,VK_AMD_shader_image_load_store_lod,VK_AMD_shader_info,VK_AMD_shader_trinary_minmax,VK_AMD_texture_gather_bias_lod,VK_ANDROID_external_format_resolve,VK_ANDROID_external_memory_android_hardware_buffer,VK_ARM_pipeline_opacity_micromap,VK_ARM_rasterization_order_attachment_access,VK_ARM_render_pass_striped,VK_ARM_scheduling_controls,VK_ARM_shader_core_builtins,VK_ARM_shader_core_properties,VK_EXT_4444_formats,VK_EXT_acquire_drm_display,VK_EXT_acquire_xlib_display,VK_EXT_astc_decode_mode,VK_EXT_attachment_feedback_loop_dynamic_state,VK_EXT_attachment_feedback_loop_layout,VK_EXT_blend_operation_advanced,VK_EXT_border_color_swizzle,VK_EXT_buffer_device_address,VK_EXT_calibrated_timestamps,VK_EXT_color_write_enable,VK_EXT_conditional_rendering,VK_EXT_conservative_rasterization,VK_EXT_custom_border_color,VK_EXT_debug_marker,VK_EXT_debug_report,VK_EXT_debug_utils,VK_EXT_depth_bias_control,VK_EXT_depth_clamp_control,VK_EXT_depth_clamp_zero_one,VK_EXT_depth_clip_control,VK_EXT_depth_clip_enable,VK_EXT_depth_range_unrestricted,VK_EXT_descriptor_buffer,VK_EXT_descriptor_indexing,VK_EXT_device_address_binding_report,VK_EXT_device_fault,VK_EXT_device_generated_commands,VK_EXT_device_memory_report,VK_EXT_direct_mode_display,VK_EXT_directfb_surface,VK_EXT_discard_rectangles,VK_EXT_display_control,VK_EXT_display_surface_counter,VK_EXT_dynamic_rendering_unused_attachments,VK_EXT_extended_dynamic_state,VK_EXT_extended_dynamic_state2,VK_EXT_extended_dynamic_state3,VK_EXT_external_memory_acquire_unmodified,VK_EXT_external_memory_dma_buf,VK_EXT_external_memory_host,VK_EXT_external_memory_metal,VK_EXT_filter_cubic,VK_EXT_fragment_density_map,VK_EXT_fragment_density_map2,VK_EXT_fragment_density_map_offset,VK_EXT_fragment_shader_interlock,VK_EXT_frame_boundary,VK_EXT_full_screen_exclusive,VK_EXT_global_priority,VK_EXT_global_priority_query,VK_EXT_graphics_pipeline_library,VK_EXT_hdr_metadata,VK_EXT_headless_surface,VK_EXT_host_image_copy,VK_EXT_host_query_reset,VK_EXT_image_2d_view_of_3d,VK_EXT_image_compression_control,VK_EXT_image_compression_control_swapchain,VK_EXT_image_drm_format_modifier,VK_EXT_image_robustness,VK_EXT_image_sliced_view_of_3d,VK_EXT_image_view_min_lod,VK_EXT_index_type_uint8,VK_EXT_inline_uniform_block,VK_EXT_layer_settings,VK_EXT_legacy_dithering,VK_EXT_legacy_vertex_attributes,VK_EXT_line_rasterization,VK_EXT_load_store_op_none,VK_EXT_map_memory_placed,VK_EXT_memory_budget,VK_EXT_memory_priority,VK_EXT_mesh_shader,VK_EXT_metal_objects,VK_EXT_metal_surface,VK_EXT_multi_draw,VK_EXT_multisampled_render_to_single_sampled,VK_EXT_mutable_descriptor_type,VK_EXT_nested_command_buffer,VK_EXT_non_seamless_cube_map,VK_EXT_opacity_micromap,VK_EXT_pageable_device_local_memory,VK_EXT_pci_bus_info,VK_EXT_physical_device_drm,VK_EXT_pipeline_creation_cache_control,VK_EXT_pipeline_creation_feedback,VK_EXT_pipeline_library_group_handles,VK_EXT_pipeline_properties,VK_EXT_pipeline_protected_access,VK_EXT_pipeline_robustness,VK_EXT_post_depth_coverage,VK_EXT_present_mode_fifo_latest_ready,VK_EXT_primitive_topology_list_restart,VK_EXT_primitives_generated_query,VK_EXT_private_data,VK_EXT_provoking_vertex,VK_EXT_queue_family_foreign,VK_EXT_rasterization_order_attachment_access,VK_EXT_rgba10x6_formats,VK_EXT_robustness2,VK_EXT_sample_locations,VK_EXT_sampler_filter_minmax,VK_EXT_scalar_block_layout,VK_EXT_separate_stencil_usage,VK_EXT_shader_atomic_float,VK_EXT_shader_atomic_float2,VK_EXT_shader_demote_to_helper_invocation,VK_EXT_shader_image_atomic_int64,VK_EXT_shader_module_identifier,VK_EXT_shader_object,VK_EXT_shader_replicated_composites,VK_EXT_shader_stencil_export,VK_EXT_shader_subgroup_ballot,VK_EXT_shader_subgroup_vote,VK_EXT_shader_tile_image,VK_EXT_shader_viewport_index_layer,VK_EXT_subgroup_size_control,VK_EXT_subpass_merge_feedback,VK_EXT_surface_maintenance1,VK_EXT_swapchain_colorspace,VK_EXT_swapchain_maintenance1,VK_EXT_texel_buffer_alignment,VK_EXT_texture_compression_astc_hdr,VK_EXT_tooling_info,VK_EXT_transform_feedback,VK_EXT_validation_cache,VK_EXT_validation_features,VK_EXT_validation_flags,VK_EXT_vertex_attribute_divisor,VK_EXT_vertex_attribute_robustness,VK_EXT_vertex_input_dynamic_state,VK_EXT_ycbcr_2plane_444_formats,VK_EXT_ycbcr_image_arrays,VK_FUCHSIA_buffer_collection,VK_FUCHSIA_external_memory,VK_FUCHSIA_external_semaphore,VK_FUCHSIA_imagepipe_surface,VK_GGP_frame_token,VK_GGP_stream_descriptor_surface,VK_GOOGLE_decorate_string,VK_GOOGLE_display_timing,VK_GOOGLE_hlsl_functionality1,VK_GOOGLE_surfaceless_query,VK_GOOGLE_user_type,VK_HUAWEI_cluster_culling_shader,VK_HUAWEI_hdr_vivid,VK_HUAWEI_invocation_mask,VK_HUAWEI_subpass_shading,VK_IMG_filter_cubic,VK_IMG_format_pvrtc,VK_IMG_relaxed_line_rasterization,VK_INTEL_performance_query,VK_INTEL_shader_integer_functions2,VK_KHR_16bit_storage,VK_KHR_8bit_storage,VK_KHR_acceleration_structure,VK_KHR_android_surface,VK_KHR_bind_memory2,VK_KHR_buffer_device_address,VK_KHR_calibrated_timestamps,VK_KHR_compute_shader_derivatives,VK_KHR_cooperative_matrix,VK_KHR_copy_commands2,VK_KHR_create_renderpass2,VK_KHR_dedicated_allocation,VK_KHR_deferred_host_operations,VK_KHR_depth_clamp_zero_one,VK_KHR_depth_stencil_resolve,VK_KHR_descriptor_update_template,VK_KHR_device_group,VK_KHR_device_group_creation,VK_KHR_display,VK_KHR_display_swapchain,VK_KHR_draw_indirect_count,VK_KHR_driver_properties,VK_KHR_dynamic_rendering,VK_KHR_dynamic_rendering_local_read,VK_KHR_external_fence,VK_KHR_external_fence_capabilities,VK_KHR_external_fence_fd,VK_KHR_external_fence_win32,VK_KHR_external_memory,VK_KHR_external_memory_capabilities,VK_KHR_external_memory_fd,VK_KHR_external_memory_win32,VK_KHR_external_semaphore,VK_KHR_external_semaphore_capabilities,VK_KHR_external_semaphore_fd,VK_KHR_external_semaphore_win32,VK_KHR_format_feature_flags2,VK_KHR_fragment_shader_barycentric,VK_KHR_fragment_shading_rate,VK_KHR_get_display_properties2,VK_KHR_get_memory_requirements2,VK_KHR_get_physical_device_properties2,VK_KHR_get_surface_capabilities2,VK_KHR_global_priority,VK_KHR_image_format_list,VK_KHR_imageless_framebuffer,VK_KHR_incremental_present,VK_KHR_index_type_uint8,VK_KHR_line_rasterization,VK_KHR_load_store_op_none,VK_KHR_maintenance1,VK_KHR_maintenance2,VK_KHR_maintenance3,VK_KHR_maintenance4,VK_KHR_maintenance5,VK_KHR_maintenance6,VK_KHR_maintenance7,VK_KHR_maintenance8,VK_KHR_map_memory2,VK_KHR_multiview,VK_KHR_performance_query,VK_KHR_pipeline_binary,VK_KHR_pipeline_executable_properties,VK_KHR_pipeline_library,VK_KHR_portability_enumeration,VK_KHR_portability_subset,VK_KHR_present_id,VK_KHR_present_wait,VK_KHR_push_descriptor,VK_KHR_ray_query,VK_KHR_ray_tracing_maintenance1,VK_KHR_ray_tracing_pipeline,VK_KHR_ray_tracing_position_fetch,VK_KHR_relaxed_block_layout,VK_KHR_robustness2,VK_KHR_sampler_mirror_clamp_to_edge,VK_KHR_sampler_ycbcr_conversion,VK_KHR_separate_depth_stencil_layouts,VK_KHR_shader_atomic_int64,VK_KHR_shader_bfloat16,VK_KHR_shader_clock,VK_KHR_shader_draw_parameters,VK_KHR_shader_expect_assume,VK_KHR_shader_float16_int8,VK_KHR_shader_float_controls,VK_KHR_shader_float_controls2,VK_KHR_shader_integer_dot_product,VK_KHR_shader_maximal_reconvergence,VK_KHR_shader_non_semantic_info,VK_KHR_shader_quad_control,VK_KHR_shader_relaxed_extended_instruction,VK_KHR_shader_subgroup_extended_types,VK_KHR_shader_subgroup_rotate,VK_KHR_shader_subgroup_uniform_control_flow,VK_KHR_shader_terminate_invocation,VK_KHR_shared_presentable_image,VK_KHR_spirv_1_4,VK_KHR_storage_buffer_storage_class,VK_KHR_surface,VK_KHR_surface_protected_capabilities,VK_KHR_swapchain,VK_KHR_swapchain_mutable_format,VK_KHR_synchronization2,VK_KHR_timeline_semaphore,VK_KHR_uniform_buffer_standard_layout,VK_KHR_variable_pointers,VK_KHR_vertex_attribute_divisor,VK_KHR_vulkan_memory_model,VK_KHR_wayland_surface,VK_KHR_win32_keyed_mutex,VK_KHR_win32_surface,VK_KHR_workgroup_memory_explicit_layout,VK_KHR_xcb_surface,VK_KHR_xlib_surface,VK_KHR_zero_initialize_workgroup_memory,VK_LUNARG_direct_driver_loading,VK_MESA_image_alignment_control,VK_MSFT_layered_driver,VK_MVK_ios_surface,VK_MVK_macos_surface,VK_NN_vi_surface,VK_NVX_binary_import,VK_NVX_image_view_handle,VK_NVX_multiview_per_view_attributes,VK_NV_acquire_winrt_display,VK_NV_clip_space_w_scaling,VK_NV_cluster_acceleration_structure,VK_NV_command_buffer_inheritance,VK_NV_compute_shader_derivatives,VK_NV_cooperative_matrix,VK_NV_cooperative_matrix2,VK_NV_cooperative_vector,VK_NV_copy_memory_indirect,VK_NV_corner_sampled_image,VK_NV_coverage_reduction_mode,VK_NV_cuda_kernel_launch,VK_NV_dedicated_allocation,VK_NV_dedicated_allocation_image_aliasing,VK_NV_descriptor_pool_overallocation,VK_NV_device_diagnostic_checkpoints,VK_NV_device_diagnostics_config,VK_NV_device_generated_commands,VK_NV_device_generated_commands_compute,VK_NV_displacement_micromap,VK_NV_display_stereo,VK_NV_extended_sparse_address_space,VK_NV_external_compute_queue,VK_NV_external_memory,VK_NV_external_memory_capabilities,VK_NV_external_memory_rdma,VK_NV_external_memory_win32,VK_NV_fill_rectangle,VK_NV_fragment_coverage_to_color,VK_NV_fragment_shader_barycentric,VK_NV_fragment_shading_rate_enums,VK_NV_framebuffer_mixed_samples,VK_NV_geometry_shader_passthrough,VK_NV_glsl_shader,VK_NV_inherited_viewport_scissor,VK_NV_linear_color_attachment,VK_NV_low_latency,VK_NV_low_latency2,VK_NV_memory_decompression,VK_NV_mesh_shader,VK_NV_optical_flow,VK_NV_partitioned_acceleration_structure,VK_NV_per_stage_descriptor_set,VK_NV_present_barrier,VK_NV_present_metering,VK_NV_raw_access_chains,VK_NV_ray_tracing,VK_NV_ray_tracing_invocation_reorder,VK_NV_ray_tracing_linear_swept_spheres,VK_NV_ray_tracing_motion_blur,VK_NV_ray_tracing_validation,VK_NV_representative_fragment_test,VK_NV_sample_mask_override_coverage,VK_NV_scissor_exclusive,VK_NV_shader_atomic_float16_vector,VK_NV_shader_image_footprint,VK_NV_shader_sm_builtins,VK_NV_shader_subgroup_partitioned,VK_NV_shading_rate_image,VK_NV_viewport_array2,VK_NV_viewport_swizzle,VK_NV_win32_keyed_mutex,VK_QCOM_filter_cubic_clamp,VK_QCOM_filter_cubic_weights,VK_QCOM_fragment_density_map_offset,VK_QCOM_image_processing,VK_QCOM_image_processing2,VK_QCOM_multiview_per_view_render_areas,VK_QCOM_multiview_per_view_viewports,VK_QCOM_render_pass_shader_resolve,VK_QCOM_render_pass_store_ops,VK_QCOM_render_pass_transform,VK_QCOM_rotated_copy_commands,VK_QCOM_tile_memory_heap,VK_QCOM_tile_properties,VK_QCOM_tile_shading,VK_QCOM_ycbcr_degamma,VK_QNX_external_memory_screen_buffer,VK_QNX_screen_surface,VK_SEC_amigo_profiling,VK_VALVE_descriptor_set_host_mapping,VK_VALVE_mutable_descriptor_type' c * * Online: - * http://glad.sh/#api=vulkan%3D1.2&generator=c&options= + * http://glad.sh/#api=vulkan%3D1.4&generator=c&options= * */ @@ -101,6 +102,8 @@ extern "C" { #define GLAD_GNUC_EXTENSION #endif +#define GLAD_UNUSED(x) (void)(x) + #ifndef GLAD_API_CALL #if defined(GLAD_API_CALL_EXPORT) #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) @@ -147,7 +150,7 @@ extern "C" { #define GLAD_VERSION_MAJOR(version) (version / 10000) #define GLAD_VERSION_MINOR(version) (version % 10000) -#define GLAD_GENERATOR_VERSION "2.0.0-beta" +#define GLAD_GENERATOR_VERSION "2.0.8" typedef void (*GLADapiproc)(void); @@ -159,6 +162,16 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #endif /* GLAD_PLATFORM_H_ */ +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_AMDX_SHADER_ENQUEUE_EXTENSION_NAME "VK_AMDX_shader_enqueue" + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_AMDX_SHADER_ENQUEUE_SPEC_VERSION 2 + +#endif +#define VK_AMD_ANTI_LAG_EXTENSION_NAME "VK_AMD_anti_lag" +#define VK_AMD_ANTI_LAG_SPEC_VERSION 1 #define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_AMD_buffer_marker" #define VK_AMD_BUFFER_MARKER_SPEC_VERSION 1 #define VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME "VK_AMD_device_coherent_memory" @@ -189,6 +202,8 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_AMD_SHADER_CORE_PROPERTIES_2_SPEC_VERSION 1 #define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties" #define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 2 +#define VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_EXTENSION_NAME "VK_AMD_shader_early_and_late_fragment_tests" +#define VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_SPEC_VERSION 1 #define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter" #define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1 #define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask" @@ -202,28 +217,62 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod" #define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_ANDROID_KHR) -#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer" +#define VK_ANDROID_EXTERNAL_FORMAT_RESOLVE_EXTENSION_NAME "VK_ANDROID_external_format_resolve" + #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) -#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 3 +#define VK_ANDROID_EXTERNAL_FORMAT_RESOLVE_SPEC_VERSION 1 + +#endif +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer" + #endif +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 5 + +#endif +#define VK_ARM_PIPELINE_OPACITY_MICROMAP_EXTENSION_NAME "VK_ARM_pipeline_opacity_micromap" +#define VK_ARM_PIPELINE_OPACITY_MICROMAP_SPEC_VERSION 1 +#define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME "VK_ARM_rasterization_order_attachment_access" +#define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION 1 +#define VK_ARM_RENDER_PASS_STRIPED_EXTENSION_NAME "VK_ARM_render_pass_striped" +#define VK_ARM_RENDER_PASS_STRIPED_SPEC_VERSION 1 +#define VK_ARM_SCHEDULING_CONTROLS_EXTENSION_NAME "VK_ARM_scheduling_controls" +#define VK_ARM_SCHEDULING_CONTROLS_SPEC_VERSION 1 +#define VK_ARM_SHADER_CORE_BUILTINS_EXTENSION_NAME "VK_ARM_shader_core_builtins" +#define VK_ARM_SHADER_CORE_BUILTINS_SPEC_VERSION 2 +#define VK_ARM_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_ARM_shader_core_properties" +#define VK_ARM_SHADER_CORE_PROPERTIES_SPEC_VERSION 1 #define VK_ATTACHMENT_UNUSED (~0U) #define VK_EXT_4444_FORMATS_EXTENSION_NAME "VK_EXT_4444_formats" #define VK_EXT_4444_FORMATS_SPEC_VERSION 1 +#define VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_drm_display" +#define VK_EXT_ACQUIRE_DRM_DISPLAY_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) #define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display" + #endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) #define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1 + #endif #define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode" #define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1 +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_attachment_feedback_loop_dynamic_state" +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_SPEC_VERSION 1 +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_EXTENSION_NAME "VK_EXT_attachment_feedback_loop_layout" +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_SPEC_VERSION 2 #define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced" #define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2 +#define VK_EXT_BORDER_COLOR_SWIZZLE_EXTENSION_NAME "VK_EXT_border_color_swizzle" +#define VK_EXT_BORDER_COLOR_SWIZZLE_SPEC_VERSION 1 #define VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_EXT_buffer_device_address" #define VK_EXT_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 2 #define VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_EXT_calibrated_timestamps" -#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 1 +#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 2 +#define VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME "VK_EXT_color_write_enable" +#define VK_EXT_COLOR_WRITE_ENABLE_SPEC_VERSION 1 #define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering" #define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 2 #define VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME "VK_EXT_conservative_rasterization" @@ -233,89 +282,205 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker" #define VK_EXT_DEBUG_MARKER_SPEC_VERSION 4 #define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" -#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 9 +#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 10 #define VK_EXT_DEBUG_UTILS_EXTENSION_NAME "VK_EXT_debug_utils" #define VK_EXT_DEBUG_UTILS_SPEC_VERSION 2 +#define VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME "VK_EXT_depth_bias_control" +#define VK_EXT_DEPTH_BIAS_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME "VK_EXT_depth_clamp_control" +#define VK_EXT_DEPTH_CLAMP_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLAMP_ZERO_ONE_EXTENSION_NAME "VK_EXT_depth_clamp_zero_one" +#define VK_EXT_DEPTH_CLAMP_ZERO_ONE_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME "VK_EXT_depth_clip_control" +#define VK_EXT_DEPTH_CLIP_CONTROL_SPEC_VERSION 1 #define VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME "VK_EXT_depth_clip_enable" #define VK_EXT_DEPTH_CLIP_ENABLE_SPEC_VERSION 1 #define VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME "VK_EXT_depth_range_unrestricted" #define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION 1 +#define VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME "VK_EXT_descriptor_buffer" +#define VK_EXT_DESCRIPTOR_BUFFER_SPEC_VERSION 1 #define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME "VK_EXT_descriptor_indexing" #define VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION 2 +#define VK_EXT_DEVICE_ADDRESS_BINDING_REPORT_EXTENSION_NAME "VK_EXT_device_address_binding_report" +#define VK_EXT_DEVICE_ADDRESS_BINDING_REPORT_SPEC_VERSION 1 +#define VK_EXT_DEVICE_FAULT_EXTENSION_NAME "VK_EXT_device_fault" +#define VK_EXT_DEVICE_FAULT_SPEC_VERSION 2 +#define VK_EXT_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_EXT_device_generated_commands" +#define VK_EXT_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1 +#define VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME "VK_EXT_device_memory_report" +#define VK_EXT_DEVICE_MEMORY_REPORT_SPEC_VERSION 2 #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) #define VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME "VK_EXT_directfb_surface" + #endif #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) #define VK_EXT_DIRECTFB_SURFACE_SPEC_VERSION 1 + #endif #define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display" #define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1 #define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles" -#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1 +#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 2 #define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME "VK_EXT_display_control" #define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1 #define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter" #define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1 +#define VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME "VK_EXT_dynamic_rendering_unused_attachments" +#define VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_SPEC_VERSION 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME "VK_EXT_extended_dynamic_state2" +#define VK_EXT_EXTENDED_DYNAMIC_STATE_2_SPEC_VERSION 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME "VK_EXT_extended_dynamic_state3" +#define VK_EXT_EXTENDED_DYNAMIC_STATE_3_SPEC_VERSION 2 #define VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_extended_dynamic_state" #define VK_EXT_EXTENDED_DYNAMIC_STATE_SPEC_VERSION 1 +#define VK_EXT_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_EXTENSION_NAME "VK_EXT_external_memory_acquire_unmodified" +#define VK_EXT_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_SPEC_VERSION 1 #define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME "VK_EXT_external_memory_dma_buf" #define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_SPEC_VERSION 1 #define VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME "VK_EXT_external_memory_host" #define VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION 1 +#if defined(VK_USE_PLATFORM_METAL_EXT) +#define VK_EXT_EXTERNAL_MEMORY_METAL_EXTENSION_NAME "VK_EXT_external_memory_metal" + +#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +#define VK_EXT_EXTERNAL_MEMORY_METAL_SPEC_VERSION 1 + +#endif #define VK_EXT_FILTER_CUBIC_EXTENSION_NAME "VK_EXT_filter_cubic" #define VK_EXT_FILTER_CUBIC_SPEC_VERSION 3 #define VK_EXT_FRAGMENT_DENSITY_MAP_2_EXTENSION_NAME "VK_EXT_fragment_density_map2" #define VK_EXT_FRAGMENT_DENSITY_MAP_2_SPEC_VERSION 1 #define VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME "VK_EXT_fragment_density_map" -#define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME "VK_EXT_fragment_density_map_offset" +#define VK_EXT_FRAGMENT_DENSITY_MAP_OFFSET_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 2 #define VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME "VK_EXT_fragment_shader_interlock" #define VK_EXT_FRAGMENT_SHADER_INTERLOCK_SPEC_VERSION 1 +#define VK_EXT_FRAME_BOUNDARY_EXTENSION_NAME "VK_EXT_frame_boundary" +#define VK_EXT_FRAME_BOUNDARY_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME "VK_EXT_full_screen_exclusive" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_EXT_FULL_SCREEN_EXCLUSIVE_SPEC_VERSION 4 + #endif #define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority" +#define VK_EXT_GLOBAL_PRIORITY_QUERY_EXTENSION_NAME "VK_EXT_global_priority_query" +#define VK_EXT_GLOBAL_PRIORITY_QUERY_SPEC_VERSION 1 #define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 2 +#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME "VK_EXT_graphics_pipeline_library" +#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_SPEC_VERSION 1 #define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata" -#define VK_EXT_HDR_METADATA_SPEC_VERSION 2 +#define VK_EXT_HDR_METADATA_SPEC_VERSION 3 #define VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME "VK_EXT_headless_surface" #define VK_EXT_HEADLESS_SURFACE_SPEC_VERSION 1 +#define VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME "VK_EXT_host_image_copy" +#define VK_EXT_HOST_IMAGE_COPY_SPEC_VERSION 1 #define VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME "VK_EXT_host_query_reset" #define VK_EXT_HOST_QUERY_RESET_SPEC_VERSION 1 +#define VK_EXT_IMAGE_2D_VIEW_OF_3D_EXTENSION_NAME "VK_EXT_image_2d_view_of_3d" +#define VK_EXT_IMAGE_2D_VIEW_OF_3D_SPEC_VERSION 1 +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME "VK_EXT_image_compression_control" +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SPEC_VERSION 1 +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME "VK_EXT_image_compression_control_swapchain" +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION 1 #define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier" -#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1 +#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 2 #define VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_image_robustness" #define VK_EXT_IMAGE_ROBUSTNESS_SPEC_VERSION 1 +#define VK_EXT_IMAGE_SLICED_VIEW_OF_3D_EXTENSION_NAME "VK_EXT_image_sliced_view_of_3d" +#define VK_EXT_IMAGE_SLICED_VIEW_OF_3D_SPEC_VERSION 1 +#define VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME "VK_EXT_image_view_min_lod" +#define VK_EXT_IMAGE_VIEW_MIN_LOD_SPEC_VERSION 1 #define VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME "VK_EXT_index_type_uint8" #define VK_EXT_INDEX_TYPE_UINT8_SPEC_VERSION 1 #define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block" #define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1 +#define VK_EXT_LAYER_SETTINGS_EXTENSION_NAME "VK_EXT_layer_settings" +#define VK_EXT_LAYER_SETTINGS_SPEC_VERSION 2 +#define VK_EXT_LEGACY_DITHERING_EXTENSION_NAME "VK_EXT_legacy_dithering" +#define VK_EXT_LEGACY_DITHERING_SPEC_VERSION 2 +#define VK_EXT_LEGACY_VERTEX_ATTRIBUTES_EXTENSION_NAME "VK_EXT_legacy_vertex_attributes" +#define VK_EXT_LEGACY_VERTEX_ATTRIBUTES_SPEC_VERSION 1 #define VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME "VK_EXT_line_rasterization" #define VK_EXT_LINE_RASTERIZATION_SPEC_VERSION 1 +#define VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME "VK_EXT_load_store_op_none" +#define VK_EXT_LOAD_STORE_OP_NONE_SPEC_VERSION 1 +#define VK_EXT_MAP_MEMORY_PLACED_EXTENSION_NAME "VK_EXT_map_memory_placed" +#define VK_EXT_MAP_MEMORY_PLACED_SPEC_VERSION 1 #define VK_EXT_MEMORY_BUDGET_EXTENSION_NAME "VK_EXT_memory_budget" #define VK_EXT_MEMORY_BUDGET_SPEC_VERSION 1 #define VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME "VK_EXT_memory_priority" #define VK_EXT_MEMORY_PRIORITY_SPEC_VERSION 1 +#define VK_EXT_MESH_SHADER_EXTENSION_NAME "VK_EXT_mesh_shader" +#define VK_EXT_MESH_SHADER_SPEC_VERSION 1 +#if defined(VK_USE_PLATFORM_METAL_EXT) +#define VK_EXT_METAL_OBJECTS_EXTENSION_NAME "VK_EXT_metal_objects" + +#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +#define VK_EXT_METAL_OBJECTS_SPEC_VERSION 2 + +#endif #if defined(VK_USE_PLATFORM_METAL_EXT) #define VK_EXT_METAL_SURFACE_EXTENSION_NAME "VK_EXT_metal_surface" + #endif #if defined(VK_USE_PLATFORM_METAL_EXT) #define VK_EXT_METAL_SURFACE_SPEC_VERSION 1 + #endif +#define VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXTENSION_NAME "VK_EXT_multisampled_render_to_single_sampled" +#define VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_SPEC_VERSION 1 +#define VK_EXT_MULTI_DRAW_EXTENSION_NAME "VK_EXT_multi_draw" +#define VK_EXT_MULTI_DRAW_SPEC_VERSION 1 +#define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_EXT_mutable_descriptor_type" +#define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1 +#define VK_EXT_NESTED_COMMAND_BUFFER_EXTENSION_NAME "VK_EXT_nested_command_buffer" +#define VK_EXT_NESTED_COMMAND_BUFFER_SPEC_VERSION 1 +#define VK_EXT_NON_SEAMLESS_CUBE_MAP_EXTENSION_NAME "VK_EXT_non_seamless_cube_map" +#define VK_EXT_NON_SEAMLESS_CUBE_MAP_SPEC_VERSION 1 +#define VK_EXT_OPACITY_MICROMAP_EXTENSION_NAME "VK_EXT_opacity_micromap" +#define VK_EXT_OPACITY_MICROMAP_SPEC_VERSION 2 +#define VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME "VK_EXT_pageable_device_local_memory" +#define VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_SPEC_VERSION 1 #define VK_EXT_PCI_BUS_INFO_EXTENSION_NAME "VK_EXT_pci_bus_info" #define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 2 +#define VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME "VK_EXT_physical_device_drm" +#define VK_EXT_PHYSICAL_DEVICE_DRM_SPEC_VERSION 1 #define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME "VK_EXT_pipeline_creation_cache_control" #define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_SPEC_VERSION 3 #define VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME "VK_EXT_pipeline_creation_feedback" #define VK_EXT_PIPELINE_CREATION_FEEDBACK_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_LIBRARY_GROUP_HANDLES_EXTENSION_NAME "VK_EXT_pipeline_library_group_handles" +#define VK_EXT_PIPELINE_LIBRARY_GROUP_HANDLES_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_PROPERTIES_EXTENSION_NAME "VK_EXT_pipeline_properties" +#define VK_EXT_PIPELINE_PROPERTIES_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_PROTECTED_ACCESS_EXTENSION_NAME "VK_EXT_pipeline_protected_access" +#define VK_EXT_PIPELINE_PROTECTED_ACCESS_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_pipeline_robustness" +#define VK_EXT_PIPELINE_ROBUSTNESS_SPEC_VERSION 1 #define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage" #define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1 +#define VK_EXT_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME "VK_EXT_present_mode_fifo_latest_ready" +#define VK_EXT_PRESENT_MODE_FIFO_LATEST_READY_SPEC_VERSION 1 +#define VK_EXT_PRIMITIVES_GENERATED_QUERY_EXTENSION_NAME "VK_EXT_primitives_generated_query" +#define VK_EXT_PRIMITIVES_GENERATED_QUERY_SPEC_VERSION 1 +#define VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME "VK_EXT_primitive_topology_list_restart" +#define VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_SPEC_VERSION 1 #define VK_EXT_PRIVATE_DATA_EXTENSION_NAME "VK_EXT_private_data" #define VK_EXT_PRIVATE_DATA_SPEC_VERSION 1 +#define VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME "VK_EXT_provoking_vertex" +#define VK_EXT_PROVOKING_VERTEX_SPEC_VERSION 1 #define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME "VK_EXT_queue_family_foreign" #define VK_EXT_QUEUE_FAMILY_FOREIGN_SPEC_VERSION 1 +#define VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME "VK_EXT_rasterization_order_attachment_access" +#define VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION 1 +#define VK_EXT_RGBA10X6_FORMATS_EXTENSION_NAME "VK_EXT_rgba10x6_formats" +#define VK_EXT_RGBA10X6_FORMATS_SPEC_VERSION 1 #define VK_EXT_ROBUSTNESS_2_EXTENSION_NAME "VK_EXT_robustness2" #define VK_EXT_ROBUSTNESS_2_SPEC_VERSION 1 #define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax" @@ -326,22 +491,40 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1 #define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage" #define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1 +#define VK_EXT_SHADER_ATOMIC_FLOAT_2_EXTENSION_NAME "VK_EXT_shader_atomic_float2" +#define VK_EXT_SHADER_ATOMIC_FLOAT_2_SPEC_VERSION 1 #define VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME "VK_EXT_shader_atomic_float" #define VK_EXT_SHADER_ATOMIC_FLOAT_SPEC_VERSION 1 #define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME "VK_EXT_shader_demote_to_helper_invocation" #define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_SPEC_VERSION 1 +#define VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME "VK_EXT_shader_image_atomic_int64" +#define VK_EXT_SHADER_IMAGE_ATOMIC_INT64_SPEC_VERSION 1 +#define VK_EXT_SHADER_MODULE_IDENTIFIER_EXTENSION_NAME "VK_EXT_shader_module_identifier" +#define VK_EXT_SHADER_MODULE_IDENTIFIER_SPEC_VERSION 1 +#define VK_EXT_SHADER_OBJECT_EXTENSION_NAME "VK_EXT_shader_object" +#define VK_EXT_SHADER_OBJECT_SPEC_VERSION 1 +#define VK_EXT_SHADER_REPLICATED_COMPOSITES_EXTENSION_NAME "VK_EXT_shader_replicated_composites" +#define VK_EXT_SHADER_REPLICATED_COMPOSITES_SPEC_VERSION 1 #define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export" #define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1 #define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot" #define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1 #define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote" #define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1 +#define VK_EXT_SHADER_TILE_IMAGE_EXTENSION_NAME "VK_EXT_shader_tile_image" +#define VK_EXT_SHADER_TILE_IMAGE_SPEC_VERSION 1 #define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer" #define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1 #define VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME "VK_EXT_subgroup_size_control" #define VK_EXT_SUBGROUP_SIZE_CONTROL_SPEC_VERSION 2 +#define VK_EXT_SUBPASS_MERGE_FEEDBACK_EXTENSION_NAME "VK_EXT_subpass_merge_feedback" +#define VK_EXT_SUBPASS_MERGE_FEEDBACK_SPEC_VERSION 2 +#define VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME "VK_EXT_surface_maintenance1" +#define VK_EXT_SURFACE_MAINTENANCE_1_SPEC_VERSION 1 #define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" -#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 4 +#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 5 +#define VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME "VK_EXT_swapchain_maintenance1" +#define VK_EXT_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION 1 #define VK_EXT_TEXEL_BUFFER_ALIGNMENT_EXTENSION_NAME "VK_EXT_texel_buffer_alignment" #define VK_EXT_TEXEL_BUFFER_ALIGNMENT_SPEC_VERSION 1 #define VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME "VK_EXT_texture_compression_astc_hdr" @@ -353,31 +536,67 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache" #define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1 #define VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME "VK_EXT_validation_features" -#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 4 +#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 6 #define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags" -#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 2 +#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 3 #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor" #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3 +#define VK_EXT_VERTEX_ATTRIBUTE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_vertex_attribute_robustness" +#define VK_EXT_VERTEX_ATTRIBUTE_ROBUSTNESS_SPEC_VERSION 1 +#define VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_vertex_input_dynamic_state" +#define VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_SPEC_VERSION 2 +#define VK_EXT_YCBCR_2PLANE_444_FORMATS_EXTENSION_NAME "VK_EXT_ycbcr_2plane_444_formats" +#define VK_EXT_YCBCR_2PLANE_444_FORMATS_SPEC_VERSION 1 #define VK_EXT_YCBCR_IMAGE_ARRAYS_EXTENSION_NAME "VK_EXT_ycbcr_image_arrays" #define VK_EXT_YCBCR_IMAGE_ARRAYS_SPEC_VERSION 1 #define VK_FALSE 0 #if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME "VK_FUCHSIA_buffer_collection" + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_BUFFER_COLLECTION_SPEC_VERSION 2 + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME "VK_FUCHSIA_external_memory" + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_EXTERNAL_MEMORY_SPEC_VERSION 1 + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_FUCHSIA_external_semaphore" + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) #define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface" + #endif #if defined(VK_USE_PLATFORM_FUCHSIA) #define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1 + #endif #if defined(VK_USE_PLATFORM_GGP) #define VK_GGP_FRAME_TOKEN_EXTENSION_NAME "VK_GGP_frame_token" + #endif #if defined(VK_USE_PLATFORM_GGP) #define VK_GGP_FRAME_TOKEN_SPEC_VERSION 1 + #endif #if defined(VK_USE_PLATFORM_GGP) #define VK_GGP_STREAM_DESCRIPTOR_SURFACE_EXTENSION_NAME "VK_GGP_stream_descriptor_surface" + #endif #if defined(VK_USE_PLATFORM_GGP) #define VK_GGP_STREAM_DESCRIPTOR_SURFACE_SPEC_VERSION 1 + #endif #define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string" #define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 1 @@ -385,12 +604,26 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1 #define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" #define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 1 +#define VK_GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" +#define VK_GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION 1 +#define VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME "VK_GOOGLE_surfaceless_query" +#define VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION 2 #define VK_GOOGLE_USER_TYPE_EXTENSION_NAME "VK_GOOGLE_user_type" #define VK_GOOGLE_USER_TYPE_SPEC_VERSION 1 +#define VK_HUAWEI_CLUSTER_CULLING_SHADER_EXTENSION_NAME "VK_HUAWEI_cluster_culling_shader" +#define VK_HUAWEI_CLUSTER_CULLING_SHADER_SPEC_VERSION 3 +#define VK_HUAWEI_HDR_VIVID_EXTENSION_NAME "VK_HUAWEI_hdr_vivid" +#define VK_HUAWEI_HDR_VIVID_SPEC_VERSION 1 +#define VK_HUAWEI_INVOCATION_MASK_EXTENSION_NAME "VK_HUAWEI_invocation_mask" +#define VK_HUAWEI_INVOCATION_MASK_SPEC_VERSION 1 +#define VK_HUAWEI_SUBPASS_SHADING_EXTENSION_NAME "VK_HUAWEI_subpass_shading" +#define VK_HUAWEI_SUBPASS_SHADING_SPEC_VERSION 3 #define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic" #define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 #define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" #define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 +#define VK_IMG_RELAXED_LINE_RASTERIZATION_EXTENSION_NAME "VK_IMG_relaxed_line_rasterization" +#define VK_IMG_RELAXED_LINE_RASTERIZATION_SPEC_VERSION 1 #define VK_INTEL_PERFORMANCE_QUERY_EXTENSION_NAME "VK_INTEL_performance_query" #define VK_INTEL_PERFORMANCE_QUERY_SPEC_VERSION 2 #define VK_INTEL_SHADER_INTEGER_FUNCTIONS_2_EXTENSION_NAME "VK_INTEL_shader_integer_functions2" @@ -399,26 +632,36 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1 #define VK_KHR_8BIT_STORAGE_EXTENSION_NAME "VK_KHR_8bit_storage" #define VK_KHR_8BIT_STORAGE_SPEC_VERSION 1 +#define VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_KHR_acceleration_structure" +#define VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION 13 #if defined(VK_USE_PLATFORM_ANDROID_KHR) #define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface" + #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) #define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 + #endif #define VK_KHR_BIND_MEMORY_2_EXTENSION_NAME "VK_KHR_bind_memory2" #define VK_KHR_BIND_MEMORY_2_SPEC_VERSION 1 #define VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_KHR_buffer_device_address" #define VK_KHR_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 1 +#define VK_KHR_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_KHR_calibrated_timestamps" +#define VK_KHR_CALIBRATED_TIMESTAMPS_SPEC_VERSION 1 +#define VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME "VK_KHR_compute_shader_derivatives" +#define VK_KHR_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION 1 +#define VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME "VK_KHR_cooperative_matrix" +#define VK_KHR_COOPERATIVE_MATRIX_SPEC_VERSION 2 +#define VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME "VK_KHR_copy_commands2" +#define VK_KHR_COPY_COMMANDS_2_SPEC_VERSION 1 #define VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME "VK_KHR_create_renderpass2" #define VK_KHR_CREATE_RENDERPASS_2_SPEC_VERSION 1 #define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation" #define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3 -#if defined(VK_ENABLE_BETA_EXTENSIONS) #define VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME "VK_KHR_deferred_host_operations" -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -#define VK_KHR_DEFERRED_HOST_OPERATIONS_SPEC_VERSION 3 -#endif +#define VK_KHR_DEFERRED_HOST_OPERATIONS_SPEC_VERSION 4 +#define VK_KHR_DEPTH_CLAMP_ZERO_ONE_EXTENSION_NAME "VK_KHR_depth_clamp_zero_one" +#define VK_KHR_DEPTH_CLAMP_ZERO_ONE_SPEC_VERSION 1 #define VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME "VK_KHR_depth_stencil_resolve" #define VK_KHR_DEPTH_STENCIL_RESOLVE_SPEC_VERSION 1 #define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template" @@ -435,6 +678,10 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 #define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties" #define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1 +#define VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME "VK_KHR_dynamic_rendering" +#define VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME "VK_KHR_dynamic_rendering_local_read" +#define VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_SPEC_VERSION 1 +#define VK_KHR_DYNAMIC_RENDERING_SPEC_VERSION 1 #define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities" #define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1 #define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence" @@ -443,9 +690,11 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME "VK_KHR_external_fence_win32" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION 1 + #endif #define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities" #define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 @@ -455,9 +704,11 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 + #endif #define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities" #define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1 @@ -467,10 +718,18 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHR_external_semaphore_win32" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1 + #endif +#define VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME "VK_KHR_format_feature_flags2" +#define VK_KHR_FORMAT_FEATURE_FLAGS_2_SPEC_VERSION 2 +#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_KHR_fragment_shader_barycentric" +#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 +#define VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME "VK_KHR_fragment_shading_rate" +#define VK_KHR_FRAGMENT_SHADING_RATE_SPEC_VERSION 2 #define VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_display_properties2" #define VK_KHR_GET_DISPLAY_PROPERTIES_2_SPEC_VERSION 1 #define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME "VK_KHR_get_memory_requirements2" @@ -479,40 +738,82 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 2 #define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2" #define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1 +#define VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME "VK_KHR_global_priority" +#define VK_KHR_GLOBAL_PRIORITY_SPEC_VERSION 1 #define VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME "VK_KHR_imageless_framebuffer" #define VK_KHR_IMAGELESS_FRAMEBUFFER_SPEC_VERSION 1 #define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list" #define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1 #define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present" -#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1 +#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 2 +#define VK_KHR_INDEX_TYPE_UINT8_EXTENSION_NAME "VK_KHR_index_type_uint8" +#define VK_KHR_INDEX_TYPE_UINT8_SPEC_VERSION 1 +#define VK_KHR_LINE_RASTERIZATION_EXTENSION_NAME "VK_KHR_line_rasterization" +#define VK_KHR_LINE_RASTERIZATION_SPEC_VERSION 1 +#define VK_KHR_LOAD_STORE_OP_NONE_EXTENSION_NAME "VK_KHR_load_store_op_none" +#define VK_KHR_LOAD_STORE_OP_NONE_SPEC_VERSION 1 #define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1" #define VK_KHR_MAINTENANCE1_SPEC_VERSION 2 #define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2" #define VK_KHR_MAINTENANCE2_SPEC_VERSION 1 #define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3" #define VK_KHR_MAINTENANCE3_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_maintenance1" +#define VK_KHR_MAINTENANCE_1_SPEC_VERSION 2 +#define VK_KHR_MAINTENANCE_2_EXTENSION_NAME "VK_KHR_maintenance2" +#define VK_KHR_MAINTENANCE_2_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_3_EXTENSION_NAME "VK_KHR_maintenance3" +#define VK_KHR_MAINTENANCE_3_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_4_EXTENSION_NAME "VK_KHR_maintenance4" +#define VK_KHR_MAINTENANCE_4_SPEC_VERSION 2 +#define VK_KHR_MAINTENANCE_5_EXTENSION_NAME "VK_KHR_maintenance5" +#define VK_KHR_MAINTENANCE_5_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_6_EXTENSION_NAME "VK_KHR_maintenance6" +#define VK_KHR_MAINTENANCE_6_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_7_EXTENSION_NAME "VK_KHR_maintenance7" +#define VK_KHR_MAINTENANCE_7_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_8_EXTENSION_NAME "VK_KHR_maintenance8" +#define VK_KHR_MAINTENANCE_8_SPEC_VERSION 1 +#define VK_KHR_MAP_MEMORY_2_EXTENSION_NAME "VK_KHR_map_memory2" +#define VK_KHR_MAP_MEMORY_2_SPEC_VERSION 1 #define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview" #define VK_KHR_MULTIVIEW_SPEC_VERSION 1 #define VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME "VK_KHR_performance_query" #define VK_KHR_PERFORMANCE_QUERY_SPEC_VERSION 1 +#define VK_KHR_PIPELINE_BINARY_EXTENSION_NAME "VK_KHR_pipeline_binary" +#define VK_KHR_PIPELINE_BINARY_SPEC_VERSION 1 #define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME "VK_KHR_pipeline_executable_properties" #define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_SPEC_VERSION 1 -#if defined(VK_ENABLE_BETA_EXTENSIONS) #define VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME "VK_KHR_pipeline_library" -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) #define VK_KHR_PIPELINE_LIBRARY_SPEC_VERSION 1 -#endif -#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor" -#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2 +#define VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME "VK_KHR_portability_enumeration" +#define VK_KHR_PORTABILITY_ENUMERATION_SPEC_VERSION 1 #if defined(VK_ENABLE_BETA_EXTENSIONS) -#define VK_KHR_RAY_TRACING_EXTENSION_NAME "VK_KHR_ray_tracing" +#define VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME "VK_KHR_portability_subset" + #endif #if defined(VK_ENABLE_BETA_EXTENSIONS) -#define VK_KHR_RAY_TRACING_SPEC_VERSION 8 +#define VK_KHR_PORTABILITY_SUBSET_SPEC_VERSION 1 + #endif +#define VK_KHR_PRESENT_ID_EXTENSION_NAME "VK_KHR_present_id" +#define VK_KHR_PRESENT_ID_SPEC_VERSION 1 +#define VK_KHR_PRESENT_WAIT_EXTENSION_NAME "VK_KHR_present_wait" +#define VK_KHR_PRESENT_WAIT_SPEC_VERSION 1 +#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor" +#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2 +#define VK_KHR_RAY_QUERY_EXTENSION_NAME "VK_KHR_ray_query" +#define VK_KHR_RAY_QUERY_SPEC_VERSION 1 +#define VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_ray_tracing_maintenance1" +#define VK_KHR_RAY_TRACING_MAINTENANCE_1_SPEC_VERSION 1 +#define VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME "VK_KHR_ray_tracing_pipeline" +#define VK_KHR_RAY_TRACING_PIPELINE_SPEC_VERSION 1 +#define VK_KHR_RAY_TRACING_POSITION_FETCH_EXTENSION_NAME "VK_KHR_ray_tracing_position_fetch" +#define VK_KHR_RAY_TRACING_POSITION_FETCH_SPEC_VERSION 1 #define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout" #define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1 +#define VK_KHR_ROBUSTNESS_2_EXTENSION_NAME "VK_KHR_robustness2" +#define VK_KHR_ROBUSTNESS_2_SPEC_VERSION 1 #define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" #define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 3 #define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion" @@ -521,18 +822,38 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_SPEC_VERSION 1 #define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64" #define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1 +#define VK_KHR_SHADER_BFLOAT16_EXTENSION_NAME "VK_KHR_shader_bfloat16" +#define VK_KHR_SHADER_BFLOAT16_SPEC_VERSION 1 #define VK_KHR_SHADER_CLOCK_EXTENSION_NAME "VK_KHR_shader_clock" #define VK_KHR_SHADER_CLOCK_SPEC_VERSION 1 #define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters" #define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1 +#define VK_KHR_SHADER_EXPECT_ASSUME_EXTENSION_NAME "VK_KHR_shader_expect_assume" +#define VK_KHR_SHADER_EXPECT_ASSUME_SPEC_VERSION 1 #define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME "VK_KHR_shader_float16_int8" #define VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION 1 +#define VK_KHR_SHADER_FLOAT_CONTROLS_2_EXTENSION_NAME "VK_KHR_shader_float_controls2" +#define VK_KHR_SHADER_FLOAT_CONTROLS_2_SPEC_VERSION 1 #define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME "VK_KHR_shader_float_controls" #define VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION 4 +#define VK_KHR_SHADER_INTEGER_DOT_PRODUCT_EXTENSION_NAME "VK_KHR_shader_integer_dot_product" +#define VK_KHR_SHADER_INTEGER_DOT_PRODUCT_SPEC_VERSION 1 +#define VK_KHR_SHADER_MAXIMAL_RECONVERGENCE_EXTENSION_NAME "VK_KHR_shader_maximal_reconvergence" +#define VK_KHR_SHADER_MAXIMAL_RECONVERGENCE_SPEC_VERSION 1 #define VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME "VK_KHR_shader_non_semantic_info" #define VK_KHR_SHADER_NON_SEMANTIC_INFO_SPEC_VERSION 1 +#define VK_KHR_SHADER_QUAD_CONTROL_EXTENSION_NAME "VK_KHR_shader_quad_control" +#define VK_KHR_SHADER_QUAD_CONTROL_SPEC_VERSION 1 +#define VK_KHR_SHADER_RELAXED_EXTENDED_INSTRUCTION_EXTENSION_NAME "VK_KHR_shader_relaxed_extended_instruction" +#define VK_KHR_SHADER_RELAXED_EXTENDED_INSTRUCTION_SPEC_VERSION 1 #define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME "VK_KHR_shader_subgroup_extended_types" #define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_SPEC_VERSION 1 +#define VK_KHR_SHADER_SUBGROUP_ROTATE_EXTENSION_NAME "VK_KHR_shader_subgroup_rotate" +#define VK_KHR_SHADER_SUBGROUP_ROTATE_SPEC_VERSION 2 +#define VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_EXTENSION_NAME "VK_KHR_shader_subgroup_uniform_control_flow" +#define VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_SPEC_VERSION 1 +#define VK_KHR_SHADER_TERMINATE_INVOCATION_EXTENSION_NAME "VK_KHR_shader_terminate_invocation" +#define VK_KHR_SHADER_TERMINATE_INVOCATION_SPEC_VERSION 1 #define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image" #define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1 #define VK_KHR_SPIRV_1_4_EXTENSION_NAME "VK_KHR_spirv_1_4" @@ -547,47 +868,67 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME "VK_KHR_swapchain_mutable_format" #define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION 1 #define VK_KHR_SWAPCHAIN_SPEC_VERSION 70 +#define VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME "VK_KHR_synchronization2" +#define VK_KHR_SYNCHRONIZATION_2_SPEC_VERSION 1 #define VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME "VK_KHR_timeline_semaphore" #define VK_KHR_TIMELINE_SEMAPHORE_SPEC_VERSION 2 #define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME "VK_KHR_uniform_buffer_standard_layout" #define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_SPEC_VERSION 1 #define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers" #define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1 +#define VK_KHR_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_KHR_vertex_attribute_divisor" +#define VK_KHR_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 1 #define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model" #define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 3 #if defined(VK_USE_PLATFORM_WAYLAND_KHR) #define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface" + #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) #define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6 + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHR_win32_keyed_mutex" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION 1 + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6 + #endif +#define VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME "VK_KHR_workgroup_memory_explicit_layout" +#define VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_XCB_KHR) #define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface" + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) #define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) #define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface" + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) #define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6 + #endif -#define VK_LOD_CLAMP_NONE 1000.0f +#define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_EXTENSION_NAME "VK_KHR_zero_initialize_workgroup_memory" +#define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_SPEC_VERSION 1 +#define VK_LOD_CLAMP_NONE 1000.0F #define VK_LUID_SIZE 8 #define VK_LUID_SIZE_KHR 8 +#define VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME "VK_LUNARG_direct_driver_loading" +#define VK_LUNARG_DIRECT_DRIVER_LOADING_SPEC_VERSION 1 #define VK_MAX_DESCRIPTION_SIZE 256 #define VK_MAX_DEVICE_GROUP_SIZE 32 #define VK_MAX_DEVICE_GROUP_SIZE_KHR 32 @@ -596,60 +937,125 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_MAX_DRIVER_NAME_SIZE 256 #define VK_MAX_DRIVER_NAME_SIZE_KHR 256 #define VK_MAX_EXTENSION_NAME_SIZE 256 +#define VK_MAX_GLOBAL_PRIORITY_SIZE 16 +#define VK_MAX_GLOBAL_PRIORITY_SIZE_EXT 16 +#define VK_MAX_GLOBAL_PRIORITY_SIZE_KHR 16 #define VK_MAX_MEMORY_HEAPS 16 #define VK_MAX_MEMORY_TYPES 32 #define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 +#define VK_MAX_PIPELINE_BINARY_KEY_SIZE_KHR 32 +#define VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT 32 +#define VK_MESA_IMAGE_ALIGNMENT_CONTROL_EXTENSION_NAME "VK_MESA_image_alignment_control" +#define VK_MESA_IMAGE_ALIGNMENT_CONTROL_SPEC_VERSION 1 +#define VK_MSFT_LAYERED_DRIVER_EXTENSION_NAME "VK_MSFT_layered_driver" +#define VK_MSFT_LAYERED_DRIVER_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_IOS_MVK) #define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface" + #endif #if defined(VK_USE_PLATFORM_IOS_MVK) #define VK_MVK_IOS_SURFACE_SPEC_VERSION 3 + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) #define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface" + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) #define VK_MVK_MACOS_SURFACE_SPEC_VERSION 3 + #endif #if defined(VK_USE_PLATFORM_VI_NN) #define VK_NN_VI_SURFACE_EXTENSION_NAME "VK_NN_vi_surface" + #endif #if defined(VK_USE_PLATFORM_VI_NN) #define VK_NN_VI_SURFACE_SPEC_VERSION 1 + #endif +#define VK_NVX_BINARY_IMPORT_EXTENSION_NAME "VK_NVX_binary_import" +#define VK_NVX_BINARY_IMPORT_SPEC_VERSION 2 #define VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME "VK_NVX_image_view_handle" -#define VK_NVX_IMAGE_VIEW_HANDLE_SPEC_VERSION 2 +#define VK_NVX_IMAGE_VIEW_HANDLE_SPEC_VERSION 3 #define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME "VK_NVX_multiview_per_view_attributes" #define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1 +#if defined(VK_USE_PLATFORM_WIN32_KHR) +#define VK_NV_ACQUIRE_WINRT_DISPLAY_EXTENSION_NAME "VK_NV_acquire_winrt_display" + +#endif +#if defined(VK_USE_PLATFORM_WIN32_KHR) +#define VK_NV_ACQUIRE_WINRT_DISPLAY_SPEC_VERSION 1 + +#endif #define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling" #define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1 +#define VK_NV_CLUSTER_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_NV_cluster_acceleration_structure" +#define VK_NV_CLUSTER_ACCELERATION_STRUCTURE_SPEC_VERSION 2 +#define VK_NV_COMMAND_BUFFER_INHERITANCE_EXTENSION_NAME "VK_NV_command_buffer_inheritance" +#define VK_NV_COMMAND_BUFFER_INHERITANCE_SPEC_VERSION 1 #define VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME "VK_NV_compute_shader_derivatives" #define VK_NV_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION 1 +#define VK_NV_COOPERATIVE_MATRIX_2_EXTENSION_NAME "VK_NV_cooperative_matrix2" +#define VK_NV_COOPERATIVE_MATRIX_2_SPEC_VERSION 1 #define VK_NV_COOPERATIVE_MATRIX_EXTENSION_NAME "VK_NV_cooperative_matrix" #define VK_NV_COOPERATIVE_MATRIX_SPEC_VERSION 1 +#define VK_NV_COOPERATIVE_VECTOR_EXTENSION_NAME "VK_NV_cooperative_vector" +#define VK_NV_COOPERATIVE_VECTOR_SPEC_VERSION 4 +#define VK_NV_COPY_MEMORY_INDIRECT_EXTENSION_NAME "VK_NV_copy_memory_indirect" +#define VK_NV_COPY_MEMORY_INDIRECT_SPEC_VERSION 1 #define VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME "VK_NV_corner_sampled_image" #define VK_NV_CORNER_SAMPLED_IMAGE_SPEC_VERSION 2 #define VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME "VK_NV_coverage_reduction_mode" #define VK_NV_COVERAGE_REDUCTION_MODE_SPEC_VERSION 1 +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_CUDA_KERNEL_LAUNCH_EXTENSION_NAME "VK_NV_cuda_kernel_launch" + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_CUDA_KERNEL_LAUNCH_SPEC_VERSION 2 + +#endif #define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation" #define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_EXTENSION_NAME "VK_NV_dedicated_allocation_image_aliasing" #define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_SPEC_VERSION 1 #define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1 +#define VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_EXTENSION_NAME "VK_NV_descriptor_pool_overallocation" +#define VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_SPEC_VERSION 1 #define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME "VK_NV_device_diagnostics_config" -#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION 1 +#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION 2 #define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints" #define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2 +#define VK_NV_DEVICE_GENERATED_COMMANDS_COMPUTE_EXTENSION_NAME "VK_NV_device_generated_commands_compute" +#define VK_NV_DEVICE_GENERATED_COMMANDS_COMPUTE_SPEC_VERSION 2 #define VK_NV_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NV_device_generated_commands" #define VK_NV_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3 +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_DISPLACEMENT_MICROMAP_EXTENSION_NAME "VK_NV_displacement_micromap" + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_DISPLACEMENT_MICROMAP_SPEC_VERSION 2 + +#endif +#define VK_NV_DISPLAY_STEREO_EXTENSION_NAME "VK_NV_display_stereo" +#define VK_NV_DISPLAY_STEREO_SPEC_VERSION 1 +#define VK_NV_EXTENDED_SPARSE_ADDRESS_SPACE_EXTENSION_NAME "VK_NV_extended_sparse_address_space" +#define VK_NV_EXTENDED_SPARSE_ADDRESS_SPACE_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_COMPUTE_QUEUE_EXTENSION_NAME "VK_NV_external_compute_queue" +#define VK_NV_EXTERNAL_COMPUTE_QUEUE_SPEC_VERSION 1 #define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities" #define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 #define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory" +#define VK_NV_EXTERNAL_MEMORY_RDMA_EXTENSION_NAME "VK_NV_external_memory_rdma" +#define VK_NV_EXTERNAL_MEMORY_RDMA_SPEC_VERSION 1 #define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 + #endif #define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle" #define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1 @@ -657,22 +1063,62 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1 #define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_NV_fragment_shader_barycentric" #define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 +#define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_EXTENSION_NAME "VK_NV_fragment_shading_rate_enums" +#define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_SPEC_VERSION 1 #define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples" #define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1 #define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough" #define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1 #define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader" #define VK_NV_GLSL_SHADER_SPEC_VERSION 1 +#define VK_NV_INHERITED_VIEWPORT_SCISSOR_EXTENSION_NAME "VK_NV_inherited_viewport_scissor" +#define VK_NV_INHERITED_VIEWPORT_SCISSOR_SPEC_VERSION 1 +#define VK_NV_LINEAR_COLOR_ATTACHMENT_EXTENSION_NAME "VK_NV_linear_color_attachment" +#define VK_NV_LINEAR_COLOR_ATTACHMENT_SPEC_VERSION 1 +#define VK_NV_LOW_LATENCY_2_EXTENSION_NAME "VK_NV_low_latency2" +#define VK_NV_LOW_LATENCY_2_SPEC_VERSION 2 +#define VK_NV_LOW_LATENCY_EXTENSION_NAME "VK_NV_low_latency" +#define VK_NV_LOW_LATENCY_SPEC_VERSION 1 +#define VK_NV_MEMORY_DECOMPRESSION_EXTENSION_NAME "VK_NV_memory_decompression" +#define VK_NV_MEMORY_DECOMPRESSION_SPEC_VERSION 1 #define VK_NV_MESH_SHADER_EXTENSION_NAME "VK_NV_mesh_shader" #define VK_NV_MESH_SHADER_SPEC_VERSION 1 +#define VK_NV_OPTICAL_FLOW_EXTENSION_NAME "VK_NV_optical_flow" +#define VK_NV_OPTICAL_FLOW_SPEC_VERSION 1 +#define VK_NV_PARTITIONED_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_NV_partitioned_acceleration_structure" +#define VK_NV_PARTITIONED_ACCELERATION_STRUCTURE_SPEC_VERSION 1 +#define VK_NV_PER_STAGE_DESCRIPTOR_SET_EXTENSION_NAME "VK_NV_per_stage_descriptor_set" +#define VK_NV_PER_STAGE_DESCRIPTOR_SET_SPEC_VERSION 1 +#define VK_NV_PRESENT_BARRIER_EXTENSION_NAME "VK_NV_present_barrier" +#define VK_NV_PRESENT_BARRIER_SPEC_VERSION 1 +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_PRESENT_METERING_EXTENSION_NAME "VK_NV_present_metering" + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_PRESENT_METERING_SPEC_VERSION 1 + +#endif +#define VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME "VK_NV_raw_access_chains" +#define VK_NV_RAW_ACCESS_CHAINS_SPEC_VERSION 1 #define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing" +#define VK_NV_RAY_TRACING_INVOCATION_REORDER_EXTENSION_NAME "VK_NV_ray_tracing_invocation_reorder" +#define VK_NV_RAY_TRACING_INVOCATION_REORDER_SPEC_VERSION 1 +#define VK_NV_RAY_TRACING_LINEAR_SWEPT_SPHERES_EXTENSION_NAME "VK_NV_ray_tracing_linear_swept_spheres" +#define VK_NV_RAY_TRACING_LINEAR_SWEPT_SPHERES_SPEC_VERSION 1 +#define VK_NV_RAY_TRACING_MOTION_BLUR_EXTENSION_NAME "VK_NV_ray_tracing_motion_blur" +#define VK_NV_RAY_TRACING_MOTION_BLUR_SPEC_VERSION 1 #define VK_NV_RAY_TRACING_SPEC_VERSION 3 +#define VK_NV_RAY_TRACING_VALIDATION_EXTENSION_NAME "VK_NV_ray_tracing_validation" +#define VK_NV_RAY_TRACING_VALIDATION_SPEC_VERSION 1 #define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME "VK_NV_representative_fragment_test" #define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 2 #define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage" #define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1 #define VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME "VK_NV_scissor_exclusive" -#define VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION 1 +#define VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION 2 +#define VK_NV_SHADER_ATOMIC_FLOAT16_VECTOR_EXTENSION_NAME "VK_NV_shader_atomic_float16_vector" +#define VK_NV_SHADER_ATOMIC_FLOAT16_VECTOR_SPEC_VERSION 1 #define VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME "VK_NV_shader_image_footprint" #define VK_NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION 2 #define VK_NV_SHADER_SM_BUILTINS_EXTENSION_NAME "VK_NV_shader_sm_builtins" @@ -683,162 +1129,281 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_NV_SHADING_RATE_IMAGE_SPEC_VERSION 3 #define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME "VK_NV_viewport_array2" #define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION 1 +#define VK_NV_VIEWPORT_ARRAY_2_EXTENSION_NAME "VK_NV_viewport_array2" +#define VK_NV_VIEWPORT_ARRAY_2_SPEC_VERSION 1 #define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle" #define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 2 + #endif +#define VK_PARTITIONED_ACCELERATION_STRUCTURE_PARTITION_INDEX_GLOBAL_NV (~0U) +#define VK_QCOM_FILTER_CUBIC_CLAMP_EXTENSION_NAME "VK_QCOM_filter_cubic_clamp" +#define VK_QCOM_FILTER_CUBIC_CLAMP_SPEC_VERSION 1 +#define VK_QCOM_FILTER_CUBIC_WEIGHTS_EXTENSION_NAME "VK_QCOM_filter_cubic_weights" +#define VK_QCOM_FILTER_CUBIC_WEIGHTS_SPEC_VERSION 1 +#define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME "VK_QCOM_fragment_density_map_offset" +#define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_SPEC_VERSION 3 +#define VK_QCOM_IMAGE_PROCESSING_2_EXTENSION_NAME "VK_QCOM_image_processing2" +#define VK_QCOM_IMAGE_PROCESSING_2_SPEC_VERSION 1 +#define VK_QCOM_IMAGE_PROCESSING_EXTENSION_NAME "VK_QCOM_image_processing" +#define VK_QCOM_IMAGE_PROCESSING_SPEC_VERSION 1 +#define VK_QCOM_MULTIVIEW_PER_VIEW_RENDER_AREAS_EXTENSION_NAME "VK_QCOM_multiview_per_view_render_areas" +#define VK_QCOM_MULTIVIEW_PER_VIEW_RENDER_AREAS_SPEC_VERSION 1 +#define VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_EXTENSION_NAME "VK_QCOM_multiview_per_view_viewports" +#define VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_SPEC_VERSION 1 #define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_EXTENSION_NAME "VK_QCOM_render_pass_shader_resolve" #define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_SPEC_VERSION 4 +#define VK_QCOM_RENDER_PASS_STORE_OPS_EXTENSION_NAME "VK_QCOM_render_pass_store_ops" +#define VK_QCOM_RENDER_PASS_STORE_OPS_SPEC_VERSION 2 #define VK_QCOM_RENDER_PASS_TRANSFORM_EXTENSION_NAME "VK_QCOM_render_pass_transform" -#define VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION 1 -#define VK_QCOM_render_pass_store_ops_EXTENSION_NAME "VK_QCOM_render_pass_store_ops" -#define VK_QCOM_render_pass_store_ops_SPEC_VERSION 2 -#define VK_QUEUE_FAMILY_EXTERNAL (~0U-1) -#define VK_QUEUE_FAMILY_EXTERNAL_KHR (~0U-1) -#define VK_QUEUE_FAMILY_FOREIGN_EXT (~0U-2) +#define VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION 4 +#define VK_QCOM_ROTATED_COPY_COMMANDS_EXTENSION_NAME "VK_QCOM_rotated_copy_commands" +#define VK_QCOM_ROTATED_COPY_COMMANDS_SPEC_VERSION 2 +#define VK_QCOM_TILE_MEMORY_HEAP_EXTENSION_NAME "VK_QCOM_tile_memory_heap" +#define VK_QCOM_TILE_MEMORY_HEAP_SPEC_VERSION 1 +#define VK_QCOM_TILE_PROPERTIES_EXTENSION_NAME "VK_QCOM_tile_properties" +#define VK_QCOM_TILE_PROPERTIES_SPEC_VERSION 1 +#define VK_QCOM_TILE_SHADING_EXTENSION_NAME "VK_QCOM_tile_shading" +#define VK_QCOM_TILE_SHADING_SPEC_VERSION 1 +#define VK_QCOM_YCBCR_DEGAMMA_EXTENSION_NAME "VK_QCOM_ycbcr_degamma" +#define VK_QCOM_YCBCR_DEGAMMA_SPEC_VERSION 1 +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +#define VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_EXTENSION_NAME "VK_QNX_external_memory_screen_buffer" + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +#define VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_SPEC_VERSION 1 + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +#define VK_QNX_SCREEN_SURFACE_EXTENSION_NAME "VK_QNX_screen_surface" + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +#define VK_QNX_SCREEN_SURFACE_SPEC_VERSION 1 + +#endif +#define VK_QUEUE_FAMILY_EXTERNAL (~1U) +#define VK_QUEUE_FAMILY_EXTERNAL_KHR (~1U) +#define VK_QUEUE_FAMILY_FOREIGN_EXT (~2U) #define VK_QUEUE_FAMILY_IGNORED (~0U) +#define VK_REMAINING_3D_SLICES_EXT (~0U) #define VK_REMAINING_ARRAY_LAYERS (~0U) #define VK_REMAINING_MIP_LEVELS (~0U) +#define VK_SEC_AMIGO_PROFILING_EXTENSION_NAME "VK_SEC_amigo_profiling" +#define VK_SEC_AMIGO_PROFILING_SPEC_VERSION 1 +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_SHADER_INDEX_UNUSED_AMDX (~0U) + +#endif #define VK_SHADER_UNUSED_KHR (~0U) #define VK_SHADER_UNUSED_NV (~0U) #define VK_SUBPASS_EXTERNAL (~0U) #define VK_TRUE 1 #define VK_UUID_SIZE 16 +#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_EXTENSION_NAME "VK_VALVE_descriptor_set_host_mapping" +#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_SPEC_VERSION 1 +#define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_VALVE_mutable_descriptor_type" +#define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1 #define VK_WHOLE_SIZE (~0ULL) #include "vk_platform.h" - #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) || defined(VK_USE_PLATFORM_XLIB_KHR) +#include #endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) +#include #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) +#include #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) +#include #endif #if defined(VK_USE_PLATFORM_XCB_KHR) +#include #endif #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) +#include #endif -#if defined(VK_USE_PLATFORM_FUCHSIA) +#if defined(VK_USE_PLATFORM_FUCHSIA) || defined(VK_USE_PLATFORM_FUCHSIA) || defined(VK_USE_PLATFORM_FUCHSIA) || defined(VK_USE_PLATFORM_FUCHSIA) +#include #endif #if defined(VK_USE_PLATFORM_GGP) || defined(VK_USE_PLATFORM_GGP) +#include +#endif + +#if defined(VK_USE_PLATFORM_SCREEN_QNX) || defined(VK_USE_PLATFORM_SCREEN_QNX) +#include #endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) || defined(VK_USE_PLATFORM_XLIB_KHR) + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) + #endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) + #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) + #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) + #endif #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) + #endif #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) + #endif -#if defined(VK_USE_PLATFORM_FUCHSIA) +#if defined(VK_USE_PLATFORM_FUCHSIA) || defined(VK_USE_PLATFORM_FUCHSIA) || defined(VK_USE_PLATFORM_FUCHSIA) || defined(VK_USE_PLATFORM_FUCHSIA) + #endif #if defined(VK_USE_PLATFORM_GGP) + #endif #if defined(VK_USE_PLATFORM_GGP) + #endif -#define VK_MAKE_VERSION(major, minor, patch) \ - ((((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch))) +#if defined(VK_USE_PLATFORM_SCREEN_QNX) -#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) +#endif -#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) +#if defined(VK_USE_PLATFORM_SCREEN_QNX) -#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) +#endif -/* DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. */ -/*#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) // Patch version should always be set to 0 */ +#if defined(VK_USE_PLATFORM_SCREEN_QNX) -/* Vulkan 1.0 version number */ -#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)/* Patch version should always be set to 0 */ +#endif +/* DEPRECATED: This define is deprecated. VK_MAKE_API_VERSION should be used instead. */ +#define VK_MAKE_VERSION(major, minor, patch) \ + ((((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch))) +/* DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead. */ +#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22U) +/* DEPRECATED: This define is deprecated. VK_API_VERSION_MINOR should be used instead. */ +#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12U) & 0x3FFU) +/* DEPRECATED: This define is deprecated. VK_API_VERSION_PATCH should be used instead. */ +#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) +#define VK_MAKE_API_VERSION(variant, major, minor, patch) \ + ((((uint32_t)(variant)) << 29U) | (((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch))) +#define VK_API_VERSION_VARIANT(version) ((uint32_t)(version) >> 29U) +#define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22U) & 0x7FU) +#define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12U) & 0x3FFU) +#define VK_API_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) +/* DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. */ +/*#define VK_API_VERSION VK_MAKE_API_VERSION(0, 1, 0, 0) // Patch version should always be set to 0 */ +/* Vulkan 1.0 version number */ +#define VK_API_VERSION_1_0 VK_MAKE_API_VERSION(0, 1, 0, 0)/* Patch version should always be set to 0 */ /* Vulkan 1.1 version number */ -#define VK_API_VERSION_1_1 VK_MAKE_VERSION(1, 1, 0)/* Patch version should always be set to 0 */ - +#define VK_API_VERSION_1_1 VK_MAKE_API_VERSION(0, 1, 1, 0)/* Patch version should always be set to 0 */ /* Vulkan 1.2 version number */ -#define VK_API_VERSION_1_2 VK_MAKE_VERSION(1, 2, 0)/* Patch version should always be set to 0 */ - +#define VK_API_VERSION_1_2 VK_MAKE_API_VERSION(0, 1, 2, 0)/* Patch version should always be set to 0 */ +/* Vulkan 1.3 version number */ +#define VK_API_VERSION_1_3 VK_MAKE_API_VERSION(0, 1, 3, 0)/* Patch version should always be set to 0 */ +/* Vulkan 1.4 version number */ +#define VK_API_VERSION_1_4 VK_MAKE_API_VERSION(0, 1, 4, 0)/* Patch version should always be set to 0 */ /* Version of this file */ -#define VK_HEADER_VERSION 152 - -/* Complete version of this file */ -#define VK_HEADER_VERSION_COMPLETE VK_MAKE_VERSION(1, 2, VK_HEADER_VERSION) - +#define VK_HEADER_VERSION 314 #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; - -#if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE) -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#ifndef VK_USE_64_BIT_PTR_DEFINES + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) || (defined(__riscv) && __riscv_xlen == 64) + #define VK_USE_64_BIT_PTR_DEFINES 1 + #else + #define VK_USE_64_BIT_PTR_DEFINES 0 + #endif +#endif +#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + #if (VK_USE_64_BIT_PTR_DEFINES==1) + #if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)) + #define VK_NULL_HANDLE nullptr + #else + #define VK_NULL_HANDLE ((void*)0) + #endif + #else + #define VK_NULL_HANDLE 0ULL + #endif +#endif +#ifndef VK_NULL_HANDLE + #define VK_NULL_HANDLE 0 +#endif +#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + #if (VK_USE_64_BIT_PTR_DEFINES==1) #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; -#else + #else #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; + #endif #endif -#endif - -#define VK_NULL_HANDLE 0 - #if defined(VK_USE_PLATFORM_ANDROID_KHR) struct ANativeWindow; #endif @@ -855,6 +1420,54 @@ typedef void CAMetalLayer; #endif #endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +#ifdef __OBJC__ +@protocol MTLDevice; +typedef __unsafe_unretained id MTLDevice_id; +#else +typedef void* MTLDevice_id; +#endif +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +#ifdef __OBJC__ +@protocol MTLCommandQueue; +typedef __unsafe_unretained id MTLCommandQueue_id; +#else +typedef void* MTLCommandQueue_id; +#endif +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +#ifdef __OBJC__ +@protocol MTLBuffer; +typedef __unsafe_unretained id MTLBuffer_id; +#else +typedef void* MTLBuffer_id; +#endif +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +#ifdef __OBJC__ +@protocol MTLTexture; +typedef __unsafe_unretained id MTLTexture_id; +#else +typedef void* MTLTexture_id; +#endif +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +#ifdef __OBJC__ +@protocol MTLSharedEvent; +typedef __unsafe_unretained id MTLSharedEvent_id; +#else +typedef void* MTLSharedEvent_id; +#endif +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct __IOSurface* IOSurfaceRef; +#endif @@ -867,104 +1480,80 @@ typedef void CAMetalLayer; -VK_DEFINE_HANDLE(VkInstance) +VK_DEFINE_HANDLE(VkInstance) VK_DEFINE_HANDLE(VkPhysicalDevice) - VK_DEFINE_HANDLE(VkDevice) - VK_DEFINE_HANDLE(VkQueue) - VK_DEFINE_HANDLE(VkCommandBuffer) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) - +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineBinaryKHR) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNV) - +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutEXT) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectExecutionSetEXT) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate) - #define VkDescriptorUpdateTemplateKHR VkDescriptorUpdateTemplate - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion) - #define VkSamplerYcbcrConversionKHR VkSamplerYcbcrConversion - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureKHR) - -#define VkAccelerationStructureNV VkAccelerationStructureKHR - +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPerformanceConfigurationINTEL) - -#if defined(VK_ENABLE_BETA_EXTENSIONS) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeferredOperationKHR) +#if defined(VK_USE_PLATFORM_FUCHSIA) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferCollectionFUCHSIA) #endif -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPrivateDataSlotEXT) - +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeferredOperationKHR) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPrivateDataSlot) +#define VkPrivateDataSlotEXT VkPrivateDataSlot +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCuModuleNVX) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCuFunctionNVX) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkOpticalFlowSessionNV) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkMicromapEXT) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderEXT) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT) - typedef enum VkAttachmentLoadOp { VK_ATTACHMENT_LOAD_OP_LOAD = 0, VK_ATTACHMENT_LOAD_OP_CLEAR = 1, - VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2 + VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, + VK_ATTACHMENT_LOAD_OP_NONE = 1000400000, + VK_ATTACHMENT_LOAD_OP_NONE_EXT = VK_ATTACHMENT_LOAD_OP_NONE, + VK_ATTACHMENT_LOAD_OP_NONE_KHR = VK_ATTACHMENT_LOAD_OP_NONE, + VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF } VkAttachmentLoadOp; - typedef enum VkAttachmentStoreOp { VK_ATTACHMENT_STORE_OP_STORE = 0, VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, - VK_ATTACHMENT_STORE_OP_NONE_QCOM = 1000301000 + VK_ATTACHMENT_STORE_OP_NONE = 1000301000, + VK_ATTACHMENT_STORE_OP_NONE_KHR = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_NONE_QCOM = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_NONE_EXT = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF } VkAttachmentStoreOp; - typedef enum VkBlendFactor { VK_BLEND_FACTOR_ZERO = 0, VK_BLEND_FACTOR_ONE = 1, @@ -984,9 +1573,9 @@ typedef enum VkBlendFactor { VK_BLEND_FACTOR_SRC1_COLOR = 15, VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16, VK_BLEND_FACTOR_SRC1_ALPHA = 17, - VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18 + VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18, + VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF } VkBlendFactor; - typedef enum VkBlendOp { VK_BLEND_OP_ADD = 0, VK_BLEND_OP_SUBTRACT = 1, @@ -1038,9 +1627,9 @@ typedef enum VkBlendOp { VK_BLEND_OP_INVERT_OVG_EXT = 1000148042, VK_BLEND_OP_RED_EXT = 1000148043, VK_BLEND_OP_GREEN_EXT = 1000148044, - VK_BLEND_OP_BLUE_EXT = 1000148045 + VK_BLEND_OP_BLUE_EXT = 1000148045, + VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF } VkBlendOp; - typedef enum VkBorderColor { VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0, VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1, @@ -1049,46 +1638,64 @@ typedef enum VkBorderColor { VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4, VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5, VK_BORDER_COLOR_FLOAT_CUSTOM_EXT = 1000287003, - VK_BORDER_COLOR_INT_CUSTOM_EXT = 1000287004 + VK_BORDER_COLOR_INT_CUSTOM_EXT = 1000287004, + VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF } VkBorderColor; - typedef enum VkFramebufferCreateFlagBits { VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT = 1, - VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT + VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, + VK_FRAMEBUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFramebufferCreateFlagBits; - typedef enum VkRenderPassCreateFlagBits { - VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM = 2 + VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM = 2, + VK_RENDER_PASS_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkRenderPassCreateFlagBits; - typedef enum VkSamplerCreateFlagBits { VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT = 1, - VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT = 2 + VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT = 2, + VK_SAMPLER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 8, + VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT = 4, + VK_SAMPLER_CREATE_IMAGE_PROCESSING_BIT_QCOM = 16, + VK_SAMPLER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSamplerCreateFlagBits; - typedef enum VkPipelineCacheHeaderVersion { - VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1 + VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, + VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF } VkPipelineCacheHeaderVersion; - typedef enum VkPipelineCacheCreateFlagBits { - VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT = 1 + VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 1, + VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT = VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT, + VK_PIPELINE_CACHE_CREATE_INTERNALLY_SYNCHRONIZED_MERGE_BIT_KHR = 8, + VK_PIPELINE_CACHE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineCacheCreateFlagBits; - typedef enum VkPipelineShaderStageCreateFlagBits { - VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = 1, - VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = 2 + VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT = 1, + VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT = 2, + VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT, + VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT, + VK_PIPELINE_SHADER_STAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineShaderStageCreateFlagBits; - typedef enum VkDescriptorSetLayoutCreateFlagBits { VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT = 2, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 1, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT = 1, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT = 16, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_EMBEDDED_IMMUTABLE_SAMPLERS_BIT_EXT = 32, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE = 4, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_INDIRECT_BINDABLE_BIT_NV = 128, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT = 4, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PER_STAGE_BIT_NV = 64, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDescriptorSetLayoutCreateFlagBits; - +typedef enum VkInstanceCreateFlagBits { + VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR = 1, + VK_INSTANCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkInstanceCreateFlagBits; typedef enum VkDeviceQueueCreateFlagBits { - VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 1 + VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 1, + VK_DEVICE_QUEUE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDeviceQueueCreateFlagBits; - typedef enum VkBufferCreateFlagBits { VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 1, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 2, @@ -1096,9 +1703,10 @@ typedef enum VkBufferCreateFlagBits { VK_BUFFER_CREATE_PROTECTED_BIT = 8, VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 16, VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, - VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_BUFFER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 32, + VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferCreateFlagBits; - typedef enum VkBufferUsageFlagBits { VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 1, VK_BUFFER_USAGE_TRANSFER_DST_BIT = 2, @@ -1113,19 +1721,28 @@ typedef enum VkBufferUsageFlagBits { VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 2048, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 4096, VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 512, - VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR = 1024, - VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR, + VK_BUFFER_USAGE_EXECUTION_GRAPH_SCRATCH_BIT_AMDX = 33554432, + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR = 524288, + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR = 1048576, + VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR = 1024, + VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT = 2097152, + VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT = 4194304, + VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT = 67108864, + VK_BUFFER_USAGE_MICROMAP_BUILD_INPUT_READ_ONLY_BIT_EXT = 8388608, + VK_BUFFER_USAGE_MICROMAP_STORAGE_BIT_EXT = 16777216, + VK_BUFFER_USAGE_TILE_MEMORY_QCOM = 134217728, + VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferUsageFlagBits; - typedef enum VkColorComponentFlagBits { VK_COLOR_COMPONENT_R_BIT = 1, VK_COLOR_COMPONENT_G_BIT = 2, VK_COLOR_COMPONENT_B_BIT = 4, - VK_COLOR_COMPONENT_A_BIT = 8 + VK_COLOR_COMPONENT_A_BIT = 8, + VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkColorComponentFlagBits; - typedef enum VkComponentSwizzle { VK_COMPONENT_SWIZZLE_IDENTITY = 0, VK_COMPONENT_SWIZZLE_ZERO = 1, @@ -1133,34 +1750,34 @@ typedef enum VkComponentSwizzle { VK_COMPONENT_SWIZZLE_R = 3, VK_COMPONENT_SWIZZLE_G = 4, VK_COMPONENT_SWIZZLE_B = 5, - VK_COMPONENT_SWIZZLE_A = 6 + VK_COMPONENT_SWIZZLE_A = 6, + VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF } VkComponentSwizzle; - typedef enum VkCommandPoolCreateFlagBits { VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 1, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 2, - VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 4 + VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 4, + VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandPoolCreateFlagBits; - typedef enum VkCommandPoolResetFlagBits { - VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 1 + VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 1, + VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandPoolResetFlagBits; - typedef enum VkCommandBufferResetFlagBits { - VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 1 + VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 1, + VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandBufferResetFlagBits; - typedef enum VkCommandBufferLevel { VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, - VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1 + VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1, + VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF } VkCommandBufferLevel; - typedef enum VkCommandBufferUsageFlagBits { VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 1, VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 2, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 4 + VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 4, + VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandBufferUsageFlagBits; - typedef enum VkCompareOp { VK_COMPARE_OP_NEVER = 0, VK_COMPARE_OP_LESS = 1, @@ -1169,16 +1786,16 @@ typedef enum VkCompareOp { VK_COMPARE_OP_GREATER = 4, VK_COMPARE_OP_NOT_EQUAL = 5, VK_COMPARE_OP_GREATER_OR_EQUAL = 6, - VK_COMPARE_OP_ALWAYS = 7 + VK_COMPARE_OP_ALWAYS = 7, + VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF } VkCompareOp; - typedef enum VkCullModeFlagBits { VK_CULL_MODE_NONE = 0, VK_CULL_MODE_FRONT_BIT = 1, VK_CULL_MODE_BACK_BIT = 2, - VK_CULL_MODE_FRONT_AND_BACK = 0x00000003 + VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, + VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCullModeFlagBits; - typedef enum VkDescriptorType { VK_DESCRIPTOR_TYPE_SAMPLER = 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1, @@ -1191,11 +1808,17 @@ typedef enum VkDescriptorType { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, - VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000, - VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR = 1000165000, - VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR + VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK = 1000138000, + VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000, + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, + VK_DESCRIPTOR_TYPE_MUTABLE_VALVE = 1000351000, + VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM = 1000440000, + VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM = 1000440001, + VK_DESCRIPTOR_TYPE_MUTABLE_EXT = 1000351000, + VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV = 1000570000, + VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF } VkDescriptorType; - typedef enum VkDynamicState { VK_DYNAMIC_STATE_VIEWPORT = 0, VK_DYNAMIC_STATE_SCISSOR = 1, @@ -1206,38 +1829,100 @@ typedef enum VkDynamicState { VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7, VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8, + VK_DYNAMIC_STATE_CULL_MODE = 1000267000, + VK_DYNAMIC_STATE_FRONT_FACE = 1000267001, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY = 1000267002, + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT = 1000267003, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT = 1000267004, + VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE = 1000267005, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE = 1000267006, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE = 1000267007, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP = 1000267008, + VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE = 1000267009, + VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE = 1000267010, + VK_DYNAMIC_STATE_STENCIL_OP = 1000267011, + VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE = 1000377001, + VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE = 1000377002, + VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE = 1000377004, + VK_DYNAMIC_STATE_LINE_STIPPLE = 1000259000, VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000, VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000, + VK_DYNAMIC_STATE_DISCARD_RECTANGLE_ENABLE_EXT = 1000099001, + VK_DYNAMIC_STATE_DISCARD_RECTANGLE_MODE_EXT = 1000099002, VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000, + VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR = 1000347000, VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV = 1000164004, VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV = 1000164006, + VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_ENABLE_NV = 1000205000, VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV = 1000205001, - VK_DYNAMIC_STATE_LINE_STIPPLE_EXT = 1000259000, - VK_DYNAMIC_STATE_CULL_MODE_EXT = 1000267000, - VK_DYNAMIC_STATE_FRONT_FACE_EXT = 1000267001, - VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT = 1000267002, - VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT = 1000267003, - VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT = 1000267004, - VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT = 1000267005, - VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT = 1000267006, - VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT = 1000267007, - VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT = 1000267008, - VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT = 1000267009, - VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT = 1000267010, - VK_DYNAMIC_STATE_STENCIL_OP_EXT = 1000267011 + VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR = 1000226000, + VK_DYNAMIC_STATE_LINE_STIPPLE_EXT = VK_DYNAMIC_STATE_LINE_STIPPLE, + VK_DYNAMIC_STATE_CULL_MODE_EXT = VK_DYNAMIC_STATE_CULL_MODE, + VK_DYNAMIC_STATE_FRONT_FACE_EXT = VK_DYNAMIC_STATE_FRONT_FACE, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT = VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY, + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT = VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT = VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT, + VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT = VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT = VK_DYNAMIC_STATE_DEPTH_COMPARE_OP, + VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE, + VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE, + VK_DYNAMIC_STATE_STENCIL_OP_EXT = VK_DYNAMIC_STATE_STENCIL_OP, + VK_DYNAMIC_STATE_VERTEX_INPUT_EXT = 1000352000, + VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT = 1000377000, + VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT = VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE, + VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE, + VK_DYNAMIC_STATE_LOGIC_OP_EXT = 1000377003, + VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT = VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE, + VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT = 1000381000, + VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT = 1000455003, + VK_DYNAMIC_STATE_POLYGON_MODE_EXT = 1000455004, + VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT = 1000455005, + VK_DYNAMIC_STATE_SAMPLE_MASK_EXT = 1000455006, + VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT = 1000455007, + VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT = 1000455008, + VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT = 1000455009, + VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT = 1000455010, + VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT = 1000455011, + VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT = 1000455012, + VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT = 1000455002, + VK_DYNAMIC_STATE_RASTERIZATION_STREAM_EXT = 1000455013, + VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT = 1000455014, + VK_DYNAMIC_STATE_EXTRA_PRIMITIVE_OVERESTIMATION_SIZE_EXT = 1000455015, + VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT = 1000455016, + VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_ENABLE_EXT = 1000455017, + VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT = 1000455018, + VK_DYNAMIC_STATE_PROVOKING_VERTEX_MODE_EXT = 1000455019, + VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT = 1000455020, + VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT = 1000455021, + VK_DYNAMIC_STATE_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT = 1000455022, + VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_ENABLE_NV = 1000455023, + VK_DYNAMIC_STATE_VIEWPORT_SWIZZLE_NV = 1000455024, + VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_ENABLE_NV = 1000455025, + VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_LOCATION_NV = 1000455026, + VK_DYNAMIC_STATE_COVERAGE_MODULATION_MODE_NV = 1000455027, + VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_ENABLE_NV = 1000455028, + VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_NV = 1000455029, + VK_DYNAMIC_STATE_SHADING_RATE_IMAGE_ENABLE_NV = 1000455030, + VK_DYNAMIC_STATE_REPRESENTATIVE_FRAGMENT_TEST_ENABLE_NV = 1000455031, + VK_DYNAMIC_STATE_COVERAGE_REDUCTION_MODE_NV = 1000455032, + VK_DYNAMIC_STATE_ATTACHMENT_FEEDBACK_LOOP_ENABLE_EXT = 1000524000, + VK_DYNAMIC_STATE_LINE_STIPPLE_KHR = VK_DYNAMIC_STATE_LINE_STIPPLE, + VK_DYNAMIC_STATE_DEPTH_CLAMP_RANGE_EXT = 1000582000, + VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF } VkDynamicState; - typedef enum VkFenceCreateFlagBits { - VK_FENCE_CREATE_SIGNALED_BIT = 1 + VK_FENCE_CREATE_SIGNALED_BIT = 1, + VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFenceCreateFlagBits; - typedef enum VkPolygonMode { VK_POLYGON_MODE_FILL = 0, VK_POLYGON_MODE_LINE = 1, VK_POLYGON_MODE_POINT = 2, - VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000 + VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000, + VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF } VkPolygonMode; - typedef enum VkFormat { VK_FORMAT_UNDEFINED = 0, VK_FORMAT_R4G4_UNORM_PACK8 = 1, @@ -1458,6 +2143,28 @@ typedef enum VkFormat { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033, + VK_FORMAT_G8_B8R8_2PLANE_444_UNORM = 1000330000, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 = 1000330001, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 = 1000330002, + VK_FORMAT_G16_B16R16_2PLANE_444_UNORM = 1000330003, + VK_FORMAT_A4R4G4B4_UNORM_PACK16 = 1000340000, + VK_FORMAT_A4B4G4R4_UNORM_PACK16 = 1000340001, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK = 1000066000, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK = 1000066001, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK = 1000066002, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK = 1000066003, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK = 1000066004, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK = 1000066005, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK = 1000066006, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK = 1000066007, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK = 1000066008, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK = 1000066009, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK = 1000066010, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK = 1000066011, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK = 1000066012, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK = 1000066013, + VK_FORMAT_A1B5G5R5_UNORM_PACK16 = 1000470000, + VK_FORMAT_A8_UNORM = 1000470001, VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, @@ -1466,20 +2173,20 @@ typedef enum VkFormat { VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, - VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = 1000066000, - VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = 1000066001, - VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = 1000066002, - VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = 1000066003, - VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = 1000066004, - VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = 1000066005, - VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = 1000066006, - VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = 1000066007, - VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = 1000066008, - VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = 1000066009, - VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = 1000066010, - VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = 1000066011, - VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = 1000066012, - VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = 1000066013, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK, VK_FORMAT_G8B8G8R8_422_UNORM_KHR = VK_FORMAT_G8B8G8R8_422_UNORM, VK_FORMAT_B8G8R8G8_422_UNORM_KHR = VK_FORMAT_B8G8R8G8_422_UNORM, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, @@ -1514,10 +2221,18 @@ typedef enum VkFormat { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, - VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = 1000340000, - VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = 1000340001 + VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16, + VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT = VK_FORMAT_G16_B16R16_2PLANE_444_UNORM, + VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = VK_FORMAT_A4R4G4B4_UNORM_PACK16, + VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = VK_FORMAT_A4B4G4R4_UNORM_PACK16, + VK_FORMAT_R16G16_SFIXED5_NV = 1000464000, + VK_FORMAT_R16G16_S10_5_NV = VK_FORMAT_R16G16_SFIXED5_NV, + VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR = VK_FORMAT_A1B5G5R5_UNORM_PACK16, + VK_FORMAT_A8_UNORM_KHR = VK_FORMAT_A8_UNORM, + VK_FORMAT_MAX_ENUM = 0x7FFFFFFF } VkFormat; - typedef enum VkFormatFeatureFlagBits { VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 1, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 2, @@ -1554,15 +2269,20 @@ typedef enum VkFormatFeatureFlagBits { VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT, VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = VK_FORMAT_FEATURE_DISJOINT_BIT, VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG, - VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT = 16777216 + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 8192, + VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT = 16777216, + VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 1073741824, + VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFormatFeatureFlagBits; - typedef enum VkFrontFace { VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, - VK_FRONT_FACE_CLOCKWISE = 1 + VK_FRONT_FACE_CLOCKWISE = 1, + VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF } VkFrontFace; - +typedef enum VkMemoryMapFlagBits { + VK_MEMORY_MAP_PLACED_BIT_EXT = 1, + VK_MEMORY_MAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryMapFlagBits; typedef enum VkImageAspectFlagBits { VK_IMAGE_ASPECT_COLOR_BIT = 1, VK_IMAGE_ASPECT_DEPTH_BIT = 2, @@ -1571,15 +2291,17 @@ typedef enum VkImageAspectFlagBits { VK_IMAGE_ASPECT_PLANE_0_BIT = 16, VK_IMAGE_ASPECT_PLANE_1_BIT = 32, VK_IMAGE_ASPECT_PLANE_2_BIT = 64, + VK_IMAGE_ASPECT_NONE = 0, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT, VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 128, VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 256, VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 512, - VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 1024 + VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 1024, + VK_IMAGE_ASPECT_NONE_KHR = VK_IMAGE_ASPECT_NONE, + VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageAspectFlagBits; - typedef enum VkImageCreateFlagBits { VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 1, VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 2, @@ -1601,9 +2323,14 @@ typedef enum VkImageCreateFlagBits { VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 4096, VK_IMAGE_CREATE_DISJOINT_BIT_KHR = VK_IMAGE_CREATE_DISJOINT_BIT, VK_IMAGE_CREATE_ALIAS_BIT_KHR = VK_IMAGE_CREATE_ALIAS_BIT, - VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 16384 + VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 16384, + VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 65536, + VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT = 262144, + VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT = 131072, + VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_QCOM = 32768, + VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_EXT = 32768, + VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageCreateFlagBits; - typedef enum VkImageLayout { VK_IMAGE_LAYOUT_UNDEFINED = 0, VK_IMAGE_LAYOUT_GENERAL = 1, @@ -1620,30 +2347,38 @@ typedef enum VkImageLayout { VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL = 1000241001, VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL = 1000241002, VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL = 1000241003, + VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL = 1000314000, + VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL = 1000314001, + VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ = 1000232000, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV = 1000164003, VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT = 1000218000, + VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR = 1000164003, + VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR = VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL + VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT = 1000339000, + VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF } VkImageLayout; - typedef enum VkImageTiling { VK_IMAGE_TILING_OPTIMAL = 0, VK_IMAGE_TILING_LINEAR = 1, - VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000 + VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000, + VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF } VkImageTiling; - typedef enum VkImageType { VK_IMAGE_TYPE_1D = 0, VK_IMAGE_TYPE_2D = 1, - VK_IMAGE_TYPE_3D = 2 + VK_IMAGE_TYPE_3D = 2, + VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkImageType; - typedef enum VkImageUsageFlagBits { VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 1, VK_IMAGE_USAGE_TRANSFER_DST_BIT = 2, @@ -1653,15 +2388,24 @@ typedef enum VkImageUsageFlagBits { VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 32, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 64, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 128, + VK_IMAGE_USAGE_HOST_TRANSFER_BIT = 4194304, VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV = 256, - VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 512 + VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 512, + VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 256, + VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT = VK_IMAGE_USAGE_HOST_TRANSFER_BIT, + VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 524288, + VK_IMAGE_USAGE_INVOCATION_MASK_BIT_HUAWEI = 262144, + VK_IMAGE_USAGE_SAMPLE_WEIGHT_BIT_QCOM = 1048576, + VK_IMAGE_USAGE_SAMPLE_BLOCK_MATCH_BIT_QCOM = 2097152, + VK_IMAGE_USAGE_TILE_MEMORY_QCOM = 134217728, + VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageUsageFlagBits; - typedef enum VkImageViewCreateFlagBits { VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT = 1, - VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT = 2 + VK_IMAGE_VIEW_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 4, + VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT = 2, + VK_IMAGE_VIEW_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageViewCreateFlagBits; - typedef enum VkImageViewType { VK_IMAGE_VIEW_TYPE_1D = 0, VK_IMAGE_VIEW_TYPE_2D = 1, @@ -1669,22 +2413,42 @@ typedef enum VkImageViewType { VK_IMAGE_VIEW_TYPE_CUBE = 3, VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4, VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5, - VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6 + VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6, + VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF } VkImageViewType; - +typedef enum VkIndirectCommandsTokenTypeEXT { + VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT = 0, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT = 1, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_SEQUENCE_INDEX_EXT = 2, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_EXT = 3, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_EXT = 4, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_EXT = 5, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT = 6, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_COUNT_EXT = 7, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_COUNT_EXT = 8, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_EXT = 9, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV_EXT = 1000202002, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_NV_EXT = 1000202003, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_EXT = 1000328000, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_EXT = 1000328001, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_TRACE_RAYS2_EXT = 1000386004, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkIndirectCommandsTokenTypeEXT; typedef enum VkSharingMode { VK_SHARING_MODE_EXCLUSIVE = 0, - VK_SHARING_MODE_CONCURRENT = 1 + VK_SHARING_MODE_CONCURRENT = 1, + VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF } VkSharingMode; - typedef enum VkIndexType { VK_INDEX_TYPE_UINT16 = 0, VK_INDEX_TYPE_UINT32 = 1, + VK_INDEX_TYPE_UINT8 = 1000265000, VK_INDEX_TYPE_NONE_KHR = 1000165000, VK_INDEX_TYPE_NONE_NV = VK_INDEX_TYPE_NONE_KHR, - VK_INDEX_TYPE_UINT8_EXT = 1000265000 + VK_INDEX_TYPE_UINT8_EXT = VK_INDEX_TYPE_UINT8, + VK_INDEX_TYPE_UINT8_KHR = VK_INDEX_TYPE_UINT8, + VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF } VkIndexType; - typedef enum VkLogicOp { VK_LOGIC_OP_CLEAR = 0, VK_LOGIC_OP_AND = 1, @@ -1701,15 +2465,16 @@ typedef enum VkLogicOp { VK_LOGIC_OP_COPY_INVERTED = 12, VK_LOGIC_OP_OR_INVERTED = 13, VK_LOGIC_OP_NAND = 14, - VK_LOGIC_OP_SET = 15 + VK_LOGIC_OP_SET = 15, + VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF } VkLogicOp; - typedef enum VkMemoryHeapFlagBits { VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 1, VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 2, - VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT + VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT, + VK_MEMORY_HEAP_TILE_MEMORY_BIT_QCOM = 8, + VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkMemoryHeapFlagBits; - typedef enum VkAccessFlagBits { VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 1, VK_ACCESS_INDEX_READ_BIT = 2, @@ -1728,6 +2493,7 @@ typedef enum VkAccessFlagBits { VK_ACCESS_HOST_WRITE_BIT = 16384, VK_ACCESS_MEMORY_READ_BIT = 32768, VK_ACCESS_MEMORY_WRITE_BIT = 65536, + VK_ACCESS_NONE = 0, VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 33554432, VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 67108864, VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 134217728, @@ -1739,10 +2505,14 @@ typedef enum VkAccessFlagBits { VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 16777216, + VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 8388608, VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV = 131072, - VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV = 262144 + VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV = 262144, + VK_ACCESS_NONE_KHR = VK_ACCESS_NONE, + VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_EXT = 131072, + VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_EXT = 262144, + VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkAccessFlagBits; - typedef enum VkMemoryPropertyFlagBits { VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 1, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 2, @@ -1751,24 +2521,27 @@ typedef enum VkMemoryPropertyFlagBits { VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 16, VK_MEMORY_PROPERTY_PROTECTED_BIT = 32, VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD = 64, - VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD = 128 + VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD = 128, + VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV = 256, + VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkMemoryPropertyFlagBits; - typedef enum VkPhysicalDeviceType { VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, - VK_PHYSICAL_DEVICE_TYPE_CPU = 4 + VK_PHYSICAL_DEVICE_TYPE_CPU = 4, + VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkPhysicalDeviceType; - typedef enum VkPipelineBindPoint { VK_PIPELINE_BIND_POINT_GRAPHICS = 0, VK_PIPELINE_BIND_POINT_COMPUTE = 1, + VK_PIPELINE_BIND_POINT_EXECUTION_GRAPH_AMDX = 1000134000, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR = 1000165000, - VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR + VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, + VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI = 1000369003, + VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF } VkPipelineBindPoint; - typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 1, VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 2, @@ -1776,6 +2549,10 @@ typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 8, VK_PIPELINE_CREATE_DISPATCH_BASE_BIT = 16, VK_PIPELINE_CREATE_DISPATCH_BASE = VK_PIPELINE_CREATE_DISPATCH_BASE_BIT, + VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT = 256, + VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT = 512, + VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT = 134217728, + VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT = 1073741824, VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT, VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR = 16384, @@ -1784,15 +2561,30 @@ typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR = 131072, VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR = 4096, VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR = 8192, + VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR = 524288, VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 32, + VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 4194304, + VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT, + VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 2097152, + VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR = 64, VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR = 128, VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV = 262144, VK_PIPELINE_CREATE_LIBRARY_BIT_KHR = 2048, - VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT = 256, - VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT = 512 + VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT = VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT, + VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT = VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT, + VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT = 536870912, + VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT = 8388608, + VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT = 1024, + VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV = 1048576, + VK_PIPELINE_CREATE_COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 33554432, + VK_PIPELINE_CREATE_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 67108864, + VK_PIPELINE_CREATE_RAY_TRACING_OPACITY_MICROMAP_BIT_EXT = 16777216, + VK_PIPELINE_CREATE_RAY_TRACING_DISPLACEMENT_MICROMAP_BIT_NV = 268435456, + VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT_EXT = VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT, + VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT_EXT = VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT, + VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineCreateFlagBits; - typedef enum VkPrimitiveTopology { VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0, VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1, @@ -1804,13 +2596,13 @@ typedef enum VkPrimitiveTopology { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9, - VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10 + VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10, + VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF } VkPrimitiveTopology; - typedef enum VkQueryControlFlagBits { - VK_QUERY_CONTROL_PRECISE_BIT = 1 + VK_QUERY_CONTROL_PRECISE_BIT = 1, + VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueryControlFlagBits; - typedef enum VkQueryPipelineStatisticFlagBits { VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 1, VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 2, @@ -1822,41 +2614,53 @@ typedef enum VkQueryPipelineStatisticFlagBits { VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 128, VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 256, VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 512, - VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 1024 + VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 1024, + VK_QUERY_PIPELINE_STATISTIC_TASK_SHADER_INVOCATIONS_BIT_EXT = 2048, + VK_QUERY_PIPELINE_STATISTIC_MESH_SHADER_INVOCATIONS_BIT_EXT = 4096, + VK_QUERY_PIPELINE_STATISTIC_CLUSTER_CULLING_SHADER_INVOCATIONS_BIT_HUAWEI = 8192, + VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueryPipelineStatisticFlagBits; - typedef enum VkQueryResultFlagBits { VK_QUERY_RESULT_64_BIT = 1, VK_QUERY_RESULT_WAIT_BIT = 2, VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 4, - VK_QUERY_RESULT_PARTIAL_BIT = 8 + VK_QUERY_RESULT_PARTIAL_BIT = 8, + VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueryResultFlagBits; - typedef enum VkQueryType { VK_QUERY_TYPE_OCCLUSION = 0, VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, VK_QUERY_TYPE_TIMESTAMP = 2, VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004, VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR = 1000116000, - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR = 1000165000, - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR = 1000150000, - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, - VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL = 1000210000 + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR = 1000150000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR = 1000150001, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, + VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL = 1000210000, + VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT = 1000328000, + VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT = 1000382000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR = 1000386000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR = 1000386001, + VK_QUERY_TYPE_MICROMAP_SERIALIZATION_SIZE_EXT = 1000396000, + VK_QUERY_TYPE_MICROMAP_COMPACTED_SIZE_EXT = 1000396001, + VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF } VkQueryType; - typedef enum VkQueueFlagBits { VK_QUEUE_GRAPHICS_BIT = 1, VK_QUEUE_COMPUTE_BIT = 2, VK_QUEUE_TRANSFER_BIT = 4, VK_QUEUE_SPARSE_BINDING_BIT = 8, - VK_QUEUE_PROTECTED_BIT = 16 + VK_QUEUE_PROTECTED_BIT = 16, + VK_QUEUE_OPTICAL_FLOW_BIT_NV = 256, + VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueueFlagBits; - typedef enum VkSubpassContents { VK_SUBPASS_CONTENTS_INLINE = 0, - VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1 + VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, + VK_SUBPASS_CONTENTS_INLINE_AND_SECONDARY_COMMAND_BUFFERS_EXT = 1000451000, + VK_SUBPASS_CONTENTS_INLINE_AND_SECONDARY_COMMAND_BUFFERS_KHR = 1000451000, + VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF } VkSubpassContents; - typedef enum VkResult { VK_SUCCESS = 0, VK_NOT_READY = 1, @@ -1881,6 +2685,8 @@ typedef enum VkResult { VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003, VK_ERROR_FRAGMENTATION = -1000161000, VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS = -1000257000, + VK_PIPELINE_COMPILE_REQUIRED = 1000297000, + VK_ERROR_NOT_PERMITTED = -1000174001, VK_ERROR_SURFACE_LOST_KHR = -1000000000, VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, VK_SUBOPTIMAL_KHR = 1000001003, @@ -1890,10 +2696,10 @@ typedef enum VkResult { VK_ERROR_INVALID_SHADER_NV = -1000012000, VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY, VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE, - VK_ERROR_INCOMPATIBLE_VERSION_KHR = -1000150000, VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000, VK_ERROR_FRAGMENTATION_EXT = VK_ERROR_FRAGMENTATION, - VK_ERROR_NOT_PERMITTED_EXT = -1000174001, + VK_ERROR_NOT_PERMITTED_EXT = VK_ERROR_NOT_PERMITTED, + VK_ERROR_NOT_PERMITTED_KHR = VK_ERROR_NOT_PERMITTED, VK_ERROR_INVALID_DEVICE_ADDRESS_EXT = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT = -1000255000, VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, @@ -1901,10 +2707,15 @@ typedef enum VkResult { VK_THREAD_DONE_KHR = 1000268001, VK_OPERATION_DEFERRED_KHR = 1000268002, VK_OPERATION_NOT_DEFERRED_KHR = 1000268003, - VK_PIPELINE_COMPILE_REQUIRED_EXT = 1000297000, - VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED_EXT + VK_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, + VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, + VK_ERROR_COMPRESSION_EXHAUSTED_EXT = -1000338000, + VK_INCOMPATIBLE_SHADER_BINARY_EXT = 1000482000, + VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT = VK_INCOMPATIBLE_SHADER_BINARY_EXT, + VK_PIPELINE_BINARY_MISSING_KHR = 1000483000, + VK_ERROR_NOT_ENOUGH_SPACE_KHR = -1000483000, + VK_RESULT_MAX_ENUM = 0x7FFFFFFF } VkResult; - typedef enum VkShaderStageFlagBits { VK_SHADER_STAGE_VERTEX_BIT = 1, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 2, @@ -1927,20 +2738,24 @@ typedef enum VkShaderStageFlagBits { VK_SHADER_STAGE_INTERSECTION_BIT_NV = VK_SHADER_STAGE_INTERSECTION_BIT_KHR, VK_SHADER_STAGE_CALLABLE_BIT_NV = VK_SHADER_STAGE_CALLABLE_BIT_KHR, VK_SHADER_STAGE_TASK_BIT_NV = 64, - VK_SHADER_STAGE_MESH_BIT_NV = 128 + VK_SHADER_STAGE_MESH_BIT_NV = 128, + VK_SHADER_STAGE_TASK_BIT_EXT = 64, + VK_SHADER_STAGE_MESH_BIT_EXT = 128, + VK_SHADER_STAGE_SUBPASS_SHADING_BIT_HUAWEI = 16384, + VK_SHADER_STAGE_CLUSTER_CULLING_BIT_HUAWEI = 524288, + VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkShaderStageFlagBits; - typedef enum VkSparseMemoryBindFlagBits { - VK_SPARSE_MEMORY_BIND_METADATA_BIT = 1 + VK_SPARSE_MEMORY_BIND_METADATA_BIT = 1, + VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSparseMemoryBindFlagBits; - typedef enum VkStencilFaceFlagBits { VK_STENCIL_FACE_FRONT_BIT = 1, VK_STENCIL_FACE_BACK_BIT = 2, VK_STENCIL_FACE_FRONT_AND_BACK = 0x00000003, - VK_STENCIL_FRONT_AND_BACK = VK_STENCIL_FACE_FRONT_AND_BACK + VK_STENCIL_FRONT_AND_BACK = VK_STENCIL_FACE_FRONT_AND_BACK, + VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkStencilFaceFlagBits; - typedef enum VkStencilOp { VK_STENCIL_OP_KEEP = 0, VK_STENCIL_OP_ZERO = 1, @@ -1949,9 +2764,9 @@ typedef enum VkStencilOp { VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4, VK_STENCIL_OP_INVERT = 5, VK_STENCIL_OP_INCREMENT_AND_WRAP = 6, - VK_STENCIL_OP_DECREMENT_AND_WRAP = 7 + VK_STENCIL_OP_DECREMENT_AND_WRAP = 7, + VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF } VkStencilOp; - typedef enum VkStructureType { VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, @@ -2119,6 +2934,108 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO = 1000257002, VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO = 1000257003, VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO = 1000257004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES = 53, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES = 54, + VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO = 1000192000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES = 1000215000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES = 1000245000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES = 1000276000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES = 1000295000, + VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO = 1000295001, + VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO = 1000295002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES = 1000297000, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_2 = 1000314000, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 = 1000314001, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 = 1000314002, + VK_STRUCTURE_TYPE_DEPENDENCY_INFO = 1000314003, + VK_STRUCTURE_TYPE_SUBMIT_INFO_2 = 1000314004, + VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO = 1000314005, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO = 1000314006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES = 1000314007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES = 1000325000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES = 1000335000, + VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2 = 1000337000, + VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2 = 1000337001, + VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2 = 1000337002, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2 = 1000337003, + VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2 = 1000337004, + VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2 = 1000337005, + VK_STRUCTURE_TYPE_BUFFER_COPY_2 = 1000337006, + VK_STRUCTURE_TYPE_IMAGE_COPY_2 = 1000337007, + VK_STRUCTURE_TYPE_IMAGE_BLIT_2 = 1000337008, + VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2 = 1000337009, + VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2 = 1000337010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES = 1000225000, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO = 1000225001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES = 1000225002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES = 1000138000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES = 1000138001, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK = 1000138002, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO = 1000138003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES = 1000066000, + VK_STRUCTURE_TYPE_RENDERING_INFO = 1000044000, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO = 1000044001, + VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO = 1000044002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES = 1000044003, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO = 1000044004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES = 1000280000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES = 1000280001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES = 1000281001, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3 = 1000360000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES = 1000413000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES = 1000413001, + VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS = 1000413002, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS = 1000413003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES = 55, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_PROPERTIES = 56, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO = 1000174000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES = 1000388000, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES = 1000388001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES = 1000416000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT_CONTROLS_2_FEATURES = 1000528000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES = 1000544000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES = 1000259000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO = 1000259001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES = 1000259002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES = 1000525000, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO = 1000190001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES = 1000190002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES = 1000265000, + VK_STRUCTURE_TYPE_MEMORY_MAP_INFO = 1000271000, + VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO = 1000271001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES = 1000470000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES = 1000470001, + VK_STRUCTURE_TYPE_RENDERING_AREA_INFO = 1000470003, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_SUBRESOURCE_INFO = 1000470004, + VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2 = 1000338002, + VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2 = 1000338003, + VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO = 1000470005, + VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO = 1000470006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES = 1000080000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES = 1000232000, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO = 1000232001, + VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO = 1000232002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_FEATURES = 1000545000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES = 1000545001, + VK_STRUCTURE_TYPE_BIND_MEMORY_STATUS = 1000545002, + VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_SETS_INFO = 1000545003, + VK_STRUCTURE_TYPE_PUSH_CONSTANTS_INFO = 1000545004, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_INFO = 1000545005, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE_INFO = 1000545006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES = 1000466000, + VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO = 1000068000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES = 1000068001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES = 1000068002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES = 1000270000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES = 1000270001, + VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY = 1000270002, + VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY = 1000270003, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO = 1000270004, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO = 1000270005, + VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO = 1000270006, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_IMAGE_INFO = 1000270007, + VK_STRUCTURE_TYPE_SUBRESOURCE_HOST_MEMCPY_SIZE = 1000270008, + VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY = 1000270009, VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, @@ -2147,9 +3064,18 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, + VK_STRUCTURE_TYPE_CU_MODULE_CREATE_INFO_NVX = 1000029000, + VK_STRUCTURE_TYPE_CU_FUNCTION_CREATE_INFO_NVX = 1000029001, + VK_STRUCTURE_TYPE_CU_LAUNCH_INFO_NVX = 1000029002, + VK_STRUCTURE_TYPE_CU_MODULE_TEXTURING_MODE_CREATE_INFO_NVX = 1000029004, VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX = 1000030000, VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX = 1000030001, VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, + VK_STRUCTURE_TYPE_RENDERING_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_INFO, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO, VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP = 1000049000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, @@ -2178,9 +3104,12 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO, VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT = 1000066000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES, VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001, + VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES, VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, @@ -2208,7 +3137,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR = 1000078003, VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000, VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES, VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001, VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002, @@ -2226,6 +3155,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003, VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000, + VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX = 1000044009, VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000, VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001, @@ -2245,6 +3175,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO, VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_END_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RELAXED_LINE_RASTERIZATION_FEATURES_IMG = 1000110000, VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, @@ -2261,6 +3192,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_ACQUIRE_PROFILING_LOCK_INFO_KHR = 1000116004, VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_KHR = 1000116005, VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_DESCRIPTION_KHR = 1000116006, + VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_RESERVATION_INFO_KHR = 1000116007, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES, VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO, VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, @@ -2290,12 +3222,20 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003, VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004, VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID = 1000129005, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_2_ANDROID = 1000129006, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES, VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = 1000138000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = 1000138001, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = 1000138002, - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = 1000138003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ENQUEUE_FEATURES_AMDX = 1000134000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ENQUEUE_PROPERTIES_AMDX = 1000134001, + VK_STRUCTURE_TYPE_EXECUTION_GRAPH_PIPELINE_SCRATCH_SIZE_AMDX = 1000134002, + VK_STRUCTURE_TYPE_EXECUTION_GRAPH_PIPELINE_CREATE_INFO_AMDX = 1000134003, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_NODE_CREATE_INFO_AMDX = 1000134004, + VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD = 1000044008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_BFLOAT16_FEATURES_KHR = 1000141000, VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000, VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001, VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, @@ -2311,27 +3251,29 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001, VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, - VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR = 1000165006, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR = 1000165007, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR = 1000150007, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR = 1000150000, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR = 1000150001, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR = 1000150002, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR = 1000150003, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR = 1000150004, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR = 1000150005, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR = 1000150006, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR = 1000150008, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_VERSION_KHR = 1000150009, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_VERSION_INFO_KHR = 1000150009, VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR = 1000150010, VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR = 1000150011, VK_STRUCTURE_TYPE_COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR = 1000150012, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR = 1000150013, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_KHR = 1000150014, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR = 1000150013, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR = 1000150014, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR = 1000150017, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR = 1000150020, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR = 1000347000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR = 1000347001, VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR = 1000150015, VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR = 1000150016, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR = 1000150017, VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR = 1000150018, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR = 1000348013, VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, + VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_NV = VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV = 1000154000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV = 1000154001, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, @@ -2343,11 +3285,11 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO, VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000, - VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002, VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003, VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004, VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT = 1000158006, VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, @@ -2355,6 +3297,8 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR = 1000163000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR = 1000163001, VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV = 1000164000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, @@ -2364,8 +3308,8 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003, VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004, VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005, - VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, + VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, @@ -2376,7 +3320,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT = 1000170000, VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT = 1000170001, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, @@ -2387,12 +3331,15 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD = 1000183000, VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES, VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES, VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP = 1000191000, - VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = 1000192000, + VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES, @@ -2406,6 +3353,8 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV = 1000205002, VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000, VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV = 1000314008, + VK_STRUCTURE_TYPE_CHECKPOINT_DATA_2_NV = 1000314009, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES, VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, @@ -2425,16 +3374,29 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD = 1000213000, VK_STRUCTURE_TYPE_SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD = 1000213001, VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES, VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001, VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002, + VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_INFO_EXT = 1000044007, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT = 1000225000, - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = 1000225001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT = 1000225002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES, + VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000226000, + VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR = 1000226001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR = 1000226002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR = 1000226003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR = 1000226004, + VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000044006, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD = 1000227000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD = 1000229000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO, + VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT = 1000234000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_QUAD_CONTROL_FEATURES_KHR = 1000235000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT = 1000237000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT = 1000238000, VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT = 1000238001, @@ -2447,9 +3409,10 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT = 1000244002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT = 1000245000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES, VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO, VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT = 1000247000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR = 1000248000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV = 1000249000, VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249002, @@ -2459,6 +3422,9 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT = 1000251000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT = 1000252000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT = 1000254000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT = 1000254001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT = 1000254002, VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT = 1000255000, VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT = 1000255002, VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT = 1000255001, @@ -2468,21 +3434,45 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO, VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO, VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT = 1000259000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT = 1000259001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT = 1000259002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT = 1000260000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT = 1000265000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT = 1000267000, - VK_STRUCTURE_TYPE_DEFERRED_OPERATION_INFO_KHR = 1000268000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR = 1000269000, VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR = 1000269001, VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR = 1000269002, VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR = 1000269003, VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR = 1000269004, VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR = 1000269005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = 1000276000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES, + VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY, + VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY_EXT = VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_EXT = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO, + VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_IMAGE_INFO_EXT = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_IMAGE_INFO, + VK_STRUCTURE_TYPE_SUBRESOURCE_HOST_MEMCPY_SIZE_EXT = VK_STRUCTURE_TYPE_SUBRESOURCE_HOST_MEMCPY_SIZE, + VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY_EXT = VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY, + VK_STRUCTURE_TYPE_MEMORY_MAP_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_MAP_INFO, + VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAP_MEMORY_PLACED_FEATURES_EXT = 1000272000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAP_MEMORY_PLACED_PROPERTIES_EXT = 1000272001, + VK_STRUCTURE_TYPE_MEMORY_MAP_PLACED_INFO_EXT = 1000272002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT = 1000273000, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT = 1000274000, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT = 1000274001, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT = 1000274002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT = 1000275000, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT = 1000275001, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT = 1000275002, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT = 1000275003, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT = 1000275004, + VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT = 1000275005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV = 1000277000, VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_CREATE_INFO_NV = 1000277001, VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV = 1000277002, @@ -2491,67 +3481,489 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_NV = 1000277005, VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_NV = 1000277006, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV = 1000277007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV = 1000278000, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV = 1000278001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT = 1000281000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = 1000281001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES, VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM = 1000282000, VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM = 1000282001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_BIAS_CONTROL_FEATURES_EXT = 1000283000, + VK_STRUCTURE_TYPE_DEPTH_BIAS_INFO_EXT = 1000283001, + VK_STRUCTURE_TYPE_DEPTH_BIAS_REPRESENTATION_INFO_EXT = 1000283002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT = 1000284000, + VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT = 1000284001, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_REPORT_CALLBACK_DATA_EXT = 1000284002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT = 1000286000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT = 1000286001, VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT = 1000287000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT = 1000287001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT = 1000287002, VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR = 1000290000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT = 1000295000, - VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT = 1000295001, - VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT = 1000295002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT = 1000297000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV = 1000292000, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_BARRIER_NV = 1000292001, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_BARRIER_CREATE_INFO_NV = 1000292002, + VK_STRUCTURE_TYPE_PRESENT_ID_KHR = 1000294000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR = 1000294001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES, + VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO, + VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV = 1000300000, VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV = 1000300001, + VK_STRUCTURE_TYPE_CUDA_MODULE_CREATE_INFO_NV = 1000307000, + VK_STRUCTURE_TYPE_CUDA_FUNCTION_CREATE_INFO_NV = 1000307001, + VK_STRUCTURE_TYPE_CUDA_LAUNCH_INFO_NV = 1000307002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUDA_KERNEL_LAUNCH_FEATURES_NV = 1000307003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUDA_KERNEL_LAUNCH_PROPERTIES_NV = 1000307004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_SHADING_FEATURES_QCOM = 1000309000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_SHADING_PROPERTIES_QCOM = 1000309001, + VK_STRUCTURE_TYPE_RENDER_PASS_TILE_SHADING_CREATE_INFO_QCOM = 1000309002, + VK_STRUCTURE_TYPE_PER_TILE_BEGIN_INFO_QCOM = 1000309003, + VK_STRUCTURE_TYPE_PER_TILE_END_INFO_QCOM = 1000309004, + VK_STRUCTURE_TYPE_DISPATCH_TILE_INFO_QCOM = 1000309005, + VK_STRUCTURE_TYPE_QUERY_LOW_LATENCY_SUPPORT_NV = 1000310000, + VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECT_CREATE_INFO_EXT = 1000311000, + VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECTS_INFO_EXT = 1000311001, + VK_STRUCTURE_TYPE_EXPORT_METAL_DEVICE_INFO_EXT = 1000311002, + VK_STRUCTURE_TYPE_EXPORT_METAL_COMMAND_QUEUE_INFO_EXT = 1000311003, + VK_STRUCTURE_TYPE_EXPORT_METAL_BUFFER_INFO_EXT = 1000311004, + VK_STRUCTURE_TYPE_IMPORT_METAL_BUFFER_INFO_EXT = 1000311005, + VK_STRUCTURE_TYPE_EXPORT_METAL_TEXTURE_INFO_EXT = 1000311006, + VK_STRUCTURE_TYPE_IMPORT_METAL_TEXTURE_INFO_EXT = 1000311007, + VK_STRUCTURE_TYPE_EXPORT_METAL_IO_SURFACE_INFO_EXT = 1000311008, + VK_STRUCTURE_TYPE_IMPORT_METAL_IO_SURFACE_INFO_EXT = 1000311009, + VK_STRUCTURE_TYPE_EXPORT_METAL_SHARED_EVENT_INFO_EXT = 1000311010, + VK_STRUCTURE_TYPE_IMPORT_METAL_SHARED_EVENT_INFO_EXT = 1000311011, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT = 1000316000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT = 1000316001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT = 1000316002, + VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT = 1000316003, + VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT = 1000316004, + VK_STRUCTURE_TYPE_BUFFER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316005, + VK_STRUCTURE_TYPE_IMAGE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316006, + VK_STRUCTURE_TYPE_IMAGE_VIEW_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316007, + VK_STRUCTURE_TYPE_SAMPLER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316008, + VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT = 1000316010, + VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT = 1000316011, + VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_PUSH_DESCRIPTOR_BUFFER_HANDLE_EXT = 1000316012, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT = 1000320000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT = 1000320001, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT = 1000320002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD = 1000321000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR = 1000203000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR = 1000322000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR = 1000323000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV = 1000326000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV = 1000326001, + VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV = 1000326002, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV = 1000327000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV = 1000327001, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MOTION_INFO_NV = 1000327002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT = 1000328000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT = 1000328001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT = 1000330000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT = 1000332000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT = 1000332001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT = 1000335000, + VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM = 1000333000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR = 1000336000, + VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2, + VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2, + VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR = VK_STRUCTURE_TYPE_BUFFER_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR = VK_STRUCTURE_TYPE_IMAGE_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR = VK_STRUCTURE_TYPE_IMAGE_BLIT_2, + VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR = VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR = VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT = 1000338000, + VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT = 1000338001, + VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_EXT = VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2, + VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_EXT = VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2, + VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT = 1000338004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT = 1000339000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT = 1000340000, - VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT = 1000346000 + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT = 1000341000, + VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT = 1000341001, + VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT = 1000341002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM = 1000342000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT = 1000344000, + VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT = 1000346000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE = 1000351000, + VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE = 1000351002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT = 1000352000, + VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT = 1000352001, + VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT = 1000352002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT = 1000353000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT = 1000354000, + VK_STRUCTURE_TYPE_DEVICE_ADDRESS_BINDING_CALLBACK_DATA_EXT = 1000354001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT = 1000355000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT = 1000355001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT = 1000356000, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_MODE_FIFO_LATEST_READY_FEATURES_EXT = 1000361000, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364000, + VK_STRUCTURE_TYPE_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA = 1000364001, + VK_STRUCTURE_TYPE_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364002, + VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365000, + VK_STRUCTURE_TYPE_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365001, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA = 1000366000, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA = 1000366001, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA = 1000366002, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA = 1000366003, + VK_STRUCTURE_TYPE_BUFFER_CONSTRAINTS_INFO_FUCHSIA = 1000366004, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_BUFFER_CREATE_INFO_FUCHSIA = 1000366005, + VK_STRUCTURE_TYPE_IMAGE_CONSTRAINTS_INFO_FUCHSIA = 1000366006, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_CONSTRAINTS_INFO_FUCHSIA = 1000366007, + VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA = 1000366008, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CONSTRAINTS_INFO_FUCHSIA = 1000366009, + VK_STRUCTURE_TYPE_SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI = 1000369000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI = 1000369001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI = 1000369002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI = 1000370000, + VK_STRUCTURE_TYPE_MEMORY_GET_REMOTE_ADDRESS_INFO_NV = 1000371000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV = 1000371001, + VK_STRUCTURE_TYPE_PIPELINE_PROPERTIES_IDENTIFIER_EXT = 1000372000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT = 1000372001, + VK_STRUCTURE_TYPE_PIPELINE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAME_BOUNDARY_FEATURES_EXT = 1000375000, + VK_STRUCTURE_TYPE_FRAME_BOUNDARY_EXT = 1000375001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT = 1000376000, + VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT = 1000376001, + VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT = 1000376002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT = 1000377000, + VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX = 1000378000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT = 1000381000, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT = 1000381001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT = 1000382000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR = 1000386000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT = 1000391000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT = 1000391001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT = 1000392000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT = 1000392001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT = 1000393000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_FEATURES_EXT = 1000395000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_PROPERTIES_EXT = 1000395001, + VK_STRUCTURE_TYPE_MICROMAP_BUILD_INFO_EXT = 1000396000, + VK_STRUCTURE_TYPE_MICROMAP_VERSION_INFO_EXT = 1000396001, + VK_STRUCTURE_TYPE_COPY_MICROMAP_INFO_EXT = 1000396002, + VK_STRUCTURE_TYPE_COPY_MICROMAP_TO_MEMORY_INFO_EXT = 1000396003, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_MICROMAP_INFO_EXT = 1000396004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT = 1000396005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT = 1000396006, + VK_STRUCTURE_TYPE_MICROMAP_CREATE_INFO_EXT = 1000396007, + VK_STRUCTURE_TYPE_MICROMAP_BUILD_SIZES_INFO_EXT = 1000396008, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_OPACITY_MICROMAP_EXT = 1000396009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISPLACEMENT_MICROMAP_FEATURES_NV = 1000397000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISPLACEMENT_MICROMAP_PROPERTIES_NV = 1000397001, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_DISPLACEMENT_MICROMAP_NV = 1000397002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_FEATURES_HUAWEI = 1000404000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI = 1000404001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_VRS_FEATURES_HUAWEI = 1000404002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT = 1000411000, + VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT = 1000411001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT = 1000412000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES, + VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_ARM = 1000415000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_SHADER_CORE_CONTROL_CREATE_INFO_ARM = 1000417000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_FEATURES_ARM = 1000417001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_PROPERTIES_ARM = 1000417002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_SLICED_VIEW_OF_3D_FEATURES_EXT = 1000418000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_SLICED_CREATE_INFO_EXT = 1000418001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE = 1000420000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_BINDING_REFERENCE_VALVE = 1000420001, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_HOST_MAPPING_INFO_VALVE = 1000420002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT = 1000421000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT = 1000422000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_FEATURES_ARM = 1000424000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_PROPERTIES_ARM = 1000424001, + VK_STRUCTURE_TYPE_RENDER_PASS_STRIPE_BEGIN_INFO_ARM = 1000424002, + VK_STRUCTURE_TYPE_RENDER_PASS_STRIPE_INFO_ARM = 1000424003, + VK_STRUCTURE_TYPE_RENDER_PASS_STRIPE_SUBMIT_INFO_ARM = 1000424004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM = 1000425000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM = 1000425001, + VK_STRUCTURE_TYPE_SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM = 1000425002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV = 1000426000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_NV = 1000426001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV = 1000427000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_NV = 1000427001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_COMPUTE_FEATURES_NV = 1000428000, + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_INDIRECT_BUFFER_INFO_NV = 1000428001, + VK_STRUCTURE_TYPE_PIPELINE_INDIRECT_DEVICE_ADDRESS_INFO_NV = 1000428002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_LINEAR_SWEPT_SPHERES_FEATURES_NV = 1000429008, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_LINEAR_SWEPT_SPHERES_DATA_NV = 1000429009, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_SPHERES_DATA_NV = 1000429010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV = 1000430000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MAXIMAL_RECONVERGENCE_FEATURES_KHR = 1000434000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT = 1000437000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM = 1000440000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM = 1000440001, + VK_STRUCTURE_TYPE_IMAGE_VIEW_SAMPLE_WEIGHT_CREATE_INFO_QCOM = 1000440002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_FEATURES_EXT = 1000451000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_PROPERTIES_EXT = 1000451001, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_EXT = 1000453000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT = 1000455000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT = 1000455001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT = 1000458000, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT = 1000458001, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_FEEDBACK_CREATE_INFO_EXT = 1000458002, + VK_STRUCTURE_TYPE_RENDER_PASS_SUBPASS_FEEDBACK_CREATE_INFO_EXT = 1000458003, + VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_INFO_LUNARG = 1000459000, + VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_LIST_LUNARG = 1000459001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT = 1000462000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT = 1000462001, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_MODULE_IDENTIFIER_CREATE_INFO_EXT = 1000462002, + VK_STRUCTURE_TYPE_SHADER_MODULE_IDENTIFIER_EXT = 1000462003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT = 1000342000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV = 1000464000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV = 1000464001, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_INFO_NV = 1000464002, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_PROPERTIES_NV = 1000464003, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_INFO_NV = 1000464004, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_EXECUTE_INFO_NV = 1000464005, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_PRIVATE_DATA_INFO_NV = 1000464010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT = 1000465000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FORMAT_RESOLVE_FEATURES_ANDROID = 1000468000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FORMAT_RESOLVE_PROPERTIES_ANDROID = 1000468001, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_RESOLVE_PROPERTIES_ANDROID = 1000468002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES, + VK_STRUCTURE_TYPE_RENDERING_AREA_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_AREA_INFO, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_SUBRESOURCE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_IMAGE_SUBRESOURCE_INFO, + VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_KHR = VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2, + VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_KHR = VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2, + VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO, + VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ANTI_LAG_FEATURES_AMD = 1000476000, + VK_STRUCTURE_TYPE_ANTI_LAG_DATA_AMD = 1000476001, + VK_STRUCTURE_TYPE_ANTI_LAG_PRESENTATION_INFO_AMD = 1000476002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_POSITION_FETCH_FEATURES_KHR = 1000481000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT = 1000482000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_PROPERTIES_EXT = 1000482001, + VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT = 1000482002, + VK_STRUCTURE_TYPE_SHADER_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_BINARY_FEATURES_KHR = 1000483000, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_CREATE_INFO_KHR = 1000483001, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_INFO_KHR = 1000483002, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_KEY_KHR = 1000483003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_BINARY_PROPERTIES_KHR = 1000483004, + VK_STRUCTURE_TYPE_RELEASE_CAPTURED_PIPELINE_DATA_INFO_KHR = 1000483005, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_DATA_INFO_KHR = 1000483006, + VK_STRUCTURE_TYPE_PIPELINE_CREATE_INFO_KHR = 1000483007, + VK_STRUCTURE_TYPE_DEVICE_PIPELINE_BINARY_INTERNAL_CACHE_CONTROL_KHR = 1000483008, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_HANDLES_INFO_KHR = 1000483009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM = 1000484000, + VK_STRUCTURE_TYPE_TILE_PROPERTIES_QCOM = 1000484001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_AMIGO_PROFILING_FEATURES_SEC = 1000485000, + VK_STRUCTURE_TYPE_AMIGO_PROFILING_SUBMIT_INFO_SEC = 1000485001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM = 1000488000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV = 1000490000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV = 1000490001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_FEATURES_NV = 1000491000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_PROPERTIES_NV = 1000491001, + VK_STRUCTURE_TYPE_COOPERATIVE_VECTOR_PROPERTIES_NV = 1000491002, + VK_STRUCTURE_TYPE_CONVERT_COOPERATIVE_VECTOR_MATRIX_INFO_NV = 1000491004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_FEATURES_NV = 1000492000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_PROPERTIES_NV = 1000492001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT = 1000351000, + VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT = 1000351002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_VERTEX_ATTRIBUTES_FEATURES_EXT = 1000495000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_VERTEX_ATTRIBUTES_PROPERTIES_EXT = 1000495001, + VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT = 1000496000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM = 1000497000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM = 1000497001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_LIBRARY_GROUP_HANDLES_FEATURES_EXT = 1000498000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_FEATURES_EXT = 1000499000, + VK_STRUCTURE_TYPE_LATENCY_SLEEP_MODE_INFO_NV = 1000505000, + VK_STRUCTURE_TYPE_LATENCY_SLEEP_INFO_NV = 1000505001, + VK_STRUCTURE_TYPE_SET_LATENCY_MARKER_INFO_NV = 1000505002, + VK_STRUCTURE_TYPE_GET_LATENCY_MARKER_INFO_NV = 1000505003, + VK_STRUCTURE_TYPE_LATENCY_TIMINGS_FRAME_REPORT_NV = 1000505004, + VK_STRUCTURE_TYPE_LATENCY_SUBMISSION_PRESENT_ID_NV = 1000505005, + VK_STRUCTURE_TYPE_OUT_OF_BAND_QUEUE_TYPE_INFO_NV = 1000505006, + VK_STRUCTURE_TYPE_SWAPCHAIN_LATENCY_CREATE_INFO_NV = 1000505007, + VK_STRUCTURE_TYPE_LATENCY_SURFACE_CAPABILITIES_NV = 1000505008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR = 1000506000, + VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_KHR = 1000506001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR = 1000506002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_RENDER_AREAS_FEATURES_QCOM = 1000510000, + VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_RENDER_AREAS_RENDER_PASS_BEGIN_INFO_QCOM = 1000510001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_KHR = 1000201000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_PROPERTIES_KHR = 1000511000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PER_STAGE_DESCRIPTOR_SET_FEATURES_NV = 1000516000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_FEATURES_QCOM = 1000518000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_PROPERTIES_QCOM = 1000518001, + VK_STRUCTURE_TYPE_SAMPLER_BLOCK_MATCH_WINDOW_CREATE_INFO_QCOM = 1000518002, + VK_STRUCTURE_TYPE_SAMPLER_CUBIC_WEIGHTS_CREATE_INFO_QCOM = 1000519000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUBIC_WEIGHTS_FEATURES_QCOM = 1000519001, + VK_STRUCTURE_TYPE_BLIT_IMAGE_CUBIC_WEIGHTS_INFO_QCOM = 1000519002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_DEGAMMA_FEATURES_QCOM = 1000520000, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_YCBCR_DEGAMMA_CREATE_INFO_QCOM = 1000520001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUBIC_CLAMP_FEATURES_QCOM = 1000521000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_FEATURES_EXT = 1000524000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT_CONTROLS_2_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT_CONTROLS_2_FEATURES, + VK_STRUCTURE_TYPE_SCREEN_BUFFER_PROPERTIES_QNX = 1000529000, + VK_STRUCTURE_TYPE_SCREEN_BUFFER_FORMAT_PROPERTIES_QNX = 1000529001, + VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX = 1000529002, + VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_QNX = 1000529003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_SCREEN_BUFFER_FEATURES_QNX = 1000529004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT = 1000530000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES, + VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_KHR = 1000184000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES, + VK_STRUCTURE_TYPE_BIND_MEMORY_STATUS_KHR = VK_STRUCTURE_TYPE_BIND_MEMORY_STATUS, + VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_SETS_INFO_KHR = VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_SETS_INFO, + VK_STRUCTURE_TYPE_PUSH_CONSTANTS_INFO_KHR = VK_STRUCTURE_TYPE_PUSH_CONSTANTS_INFO, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_INFO_KHR = VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_INFO, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE_INFO_KHR = VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE_INFO, + VK_STRUCTURE_TYPE_SET_DESCRIPTOR_BUFFER_OFFSETS_INFO_EXT = 1000545007, + VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_BUFFER_EMBEDDED_SAMPLERS_INFO_EXT = 1000545008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_POOL_OVERALLOCATION_FEATURES_NV = 1000546000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_FEATURES_QCOM = 1000547000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_PROPERTIES_QCOM = 1000547001, + VK_STRUCTURE_TYPE_TILE_MEMORY_REQUIREMENTS_QCOM = 1000547002, + VK_STRUCTURE_TYPE_TILE_MEMORY_BIND_INFO_QCOM = 1000547003, + VK_STRUCTURE_TYPE_TILE_MEMORY_SIZE_INFO_QCOM = 1000547004, + VK_STRUCTURE_TYPE_DISPLAY_SURFACE_STEREO_CREATE_INFO_NV = 1000551000, + VK_STRUCTURE_TYPE_DISPLAY_MODE_STEREO_PROPERTIES_NV = 1000551001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV = 1000555000, + VK_STRUCTURE_TYPE_EXTERNAL_COMPUTE_QUEUE_DEVICE_CREATE_INFO_NV = 1000556000, + VK_STRUCTURE_TYPE_EXTERNAL_COMPUTE_QUEUE_CREATE_INFO_NV = 1000556001, + VK_STRUCTURE_TYPE_EXTERNAL_COMPUTE_QUEUE_DATA_PARAMS_NV = 1000556002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_COMPUTE_QUEUE_PROPERTIES_NV = 1000556003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_RELAXED_EXTENDED_INSTRUCTION_FEATURES_KHR = 1000558000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMMAND_BUFFER_INHERITANCE_FEATURES_NV = 1000559000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_7_FEATURES_KHR = 1000562000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_7_PROPERTIES_KHR = 1000562001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_LIST_KHR = 1000562002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_KHR = 1000562003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR = 1000562004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT16_VECTOR_FEATURES_NV = 1000563000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_REPLICATED_COMPOSITES_FEATURES_EXT = 1000564000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_VALIDATION_FEATURES_NV = 1000568000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_FEATURES_NV = 1000569000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_PROPERTIES_NV = 1000569001, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_CLUSTERS_BOTTOM_LEVEL_INPUT_NV = 1000569002, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_TRIANGLE_CLUSTER_INPUT_NV = 1000569003, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_MOVE_OBJECTS_INPUT_NV = 1000569004, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_INPUT_INFO_NV = 1000569005, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_COMMANDS_INFO_NV = 1000569006, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CLUSTER_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000569007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PARTITIONED_ACCELERATION_STRUCTURE_FEATURES_NV = 1000570000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PARTITIONED_ACCELERATION_STRUCTURE_PROPERTIES_NV = 1000570001, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_PARTITIONED_ACCELERATION_STRUCTURE_NV = 1000570002, + VK_STRUCTURE_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCES_INPUT_NV = 1000570003, + VK_STRUCTURE_TYPE_BUILD_PARTITIONED_ACCELERATION_STRUCTURE_INFO_NV = 1000570004, + VK_STRUCTURE_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_FLAGS_NV = 1000570005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_EXT = 1000572000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_EXT = 1000572001, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_EXT = 1000572002, + VK_STRUCTURE_TYPE_INDIRECT_EXECUTION_SET_CREATE_INFO_EXT = 1000572003, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_EXT = 1000572004, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_EXT = 1000572006, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_TOKEN_EXT = 1000572007, + VK_STRUCTURE_TYPE_WRITE_INDIRECT_EXECUTION_SET_PIPELINE_EXT = 1000572008, + VK_STRUCTURE_TYPE_WRITE_INDIRECT_EXECUTION_SET_SHADER_EXT = 1000572009, + VK_STRUCTURE_TYPE_INDIRECT_EXECUTION_SET_PIPELINE_INFO_EXT = 1000572010, + VK_STRUCTURE_TYPE_INDIRECT_EXECUTION_SET_SHADER_INFO_EXT = 1000572011, + VK_STRUCTURE_TYPE_INDIRECT_EXECUTION_SET_SHADER_LAYOUT_INFO_EXT = 1000572012, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_PIPELINE_INFO_EXT = 1000572013, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_SHADER_INFO_EXT = 1000572014, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_8_FEATURES_KHR = 1000574000, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_ACCESS_FLAGS_3_KHR = 1000574002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ALIGNMENT_CONTROL_FEATURES_MESA = 1000575000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ALIGNMENT_CONTROL_PROPERTIES_MESA = 1000575001, + VK_STRUCTURE_TYPE_IMAGE_ALIGNMENT_CONTROL_CREATE_INFO_MESA = 1000575002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_CONTROL_FEATURES_EXT = 1000582000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLAMP_CONTROL_CREATE_INFO_EXT = 1000582001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HDR_VIVID_FEATURES_HUAWEI = 1000590000, + VK_STRUCTURE_TYPE_HDR_VIVID_DYNAMIC_METADATA_HUAWEI = 1000590001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_FEATURES_NV = 1000593000, + VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_FLEXIBLE_DIMENSIONS_PROPERTIES_NV = 1000593001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_PROPERTIES_NV = 1000593002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_OPACITY_MICROMAP_FEATURES_ARM = 1000596000, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_METAL_HANDLE_INFO_EXT = 1000602000, + VK_STRUCTURE_TYPE_MEMORY_METAL_HANDLE_PROPERTIES_EXT = 1000602001, + VK_STRUCTURE_TYPE_MEMORY_GET_METAL_HANDLE_INFO_EXT = 1000602002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_KHR = 1000421000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_ROBUSTNESS_FEATURES_EXT = 1000608000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_KHR = 1000286000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_KHR = 1000286001, + VK_STRUCTURE_TYPE_SET_PRESENT_CONFIG_NV = 1000613000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_METERING_FEATURES_NV = 1000613001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_EXT = 1000425000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_EXT = 1000425001, + VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_EXT = 1000425002, + VK_STRUCTURE_TYPE_RENDERING_END_INFO_EXT = 1000619003, + VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkStructureType; - typedef enum VkSystemAllocationScope { VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1, VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3, - VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4 + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4, + VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF } VkSystemAllocationScope; - typedef enum VkInternalAllocationType { - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0 + VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0, + VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF } VkInternalAllocationType; - typedef enum VkSamplerAddressMode { VK_SAMPLER_ADDRESS_MODE_REPEAT = 0, VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3, VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, - VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE + VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE, + VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF } VkSamplerAddressMode; - typedef enum VkFilter { VK_FILTER_NEAREST = 0, VK_FILTER_LINEAR = 1, VK_FILTER_CUBIC_IMG = 1000015000, - VK_FILTER_CUBIC_EXT = VK_FILTER_CUBIC_IMG + VK_FILTER_CUBIC_EXT = 1000015000, + VK_FILTER_MAX_ENUM = 0x7FFFFFFF } VkFilter; - typedef enum VkSamplerMipmapMode { VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, - VK_SAMPLER_MIPMAP_MODE_LINEAR = 1 + VK_SAMPLER_MIPMAP_MODE_LINEAR = 1, + VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF } VkSamplerMipmapMode; - typedef enum VkVertexInputRate { VK_VERTEX_INPUT_RATE_VERTEX = 0, - VK_VERTEX_INPUT_RATE_INSTANCE = 1 + VK_VERTEX_INPUT_RATE_INSTANCE = 1, + VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF } VkVertexInputRate; - typedef enum VkPipelineStageFlagBits { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 1, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 2, @@ -2570,25 +3982,57 @@ typedef enum VkPipelineStageFlagBits { VK_PIPELINE_STAGE_HOST_BIT = 16384, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 32768, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 65536, + VK_PIPELINE_STAGE_NONE = 0, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 16777216, VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 262144, - VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR = 2097152, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 33554432, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR = 2097152, VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 4194304, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 524288, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 1048576, VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 8388608, - VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV = 131072 + VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 4194304, + VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV = 131072, + VK_PIPELINE_STAGE_NONE_KHR = VK_PIPELINE_STAGE_NONE, + VK_PIPELINE_STAGE_TASK_SHADER_BIT_EXT = 524288, + VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT = 1048576, + VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_EXT = 131072, + VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineStageFlagBits; - typedef enum VkSparseImageFormatFlagBits { VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 1, VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 2, - VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 4 + VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 4, + VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSparseImageFormatFlagBits; - +typedef enum VkClusterAccelerationStructureIndexFormatFlagBitsNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_8BIT_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_16BIT_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_32BIT_NV = 4, + VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureIndexFormatFlagBitsNV; +typedef enum VkClusterAccelerationStructureTypeNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_CLUSTERS_BOTTOM_LEVEL_NV = 0, + VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_TRIANGLE_CLUSTER_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_TRIANGLE_CLUSTER_TEMPLATE_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureTypeNV; +typedef enum VkClusterAccelerationStructureOpTypeNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_MOVE_OBJECTS_NV = 0, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_CLUSTERS_BOTTOM_LEVEL_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_TEMPLATE_NV = 3, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_INSTANTIATE_TRIANGLE_CLUSTER_NV = 4, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureOpTypeNV; +typedef enum VkClusterAccelerationStructureOpModeNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_IMPLICIT_DESTINATIONS_NV = 0, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_EXPLICIT_DESTINATIONS_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_COMPUTE_SIZES_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureOpModeNV; typedef enum VkSampleCountFlagBits { VK_SAMPLE_COUNT_1_BIT = 1, VK_SAMPLE_COUNT_2_BIT = 2, @@ -2596,27 +4040,33 @@ typedef enum VkSampleCountFlagBits { VK_SAMPLE_COUNT_8_BIT = 8, VK_SAMPLE_COUNT_16_BIT = 16, VK_SAMPLE_COUNT_32_BIT = 32, - VK_SAMPLE_COUNT_64_BIT = 64 + VK_SAMPLE_COUNT_64_BIT = 64, + VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSampleCountFlagBits; - typedef enum VkAttachmentDescriptionFlagBits { - VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 1 + VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 1, + VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkAttachmentDescriptionFlagBits; - typedef enum VkDescriptorPoolCreateFlagBits { VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 1, VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT = 2, - VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT + VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT, + VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE = 4, + VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT = 4, + VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_SETS_BIT_NV = 8, + VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_POOLS_BIT_NV = 16, + VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDescriptorPoolCreateFlagBits; - typedef enum VkDependencyFlagBits { VK_DEPENDENCY_BY_REGION_BIT = 1, VK_DEPENDENCY_DEVICE_GROUP_BIT = 4, VK_DEPENDENCY_VIEW_LOCAL_BIT = 2, VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = VK_DEPENDENCY_VIEW_LOCAL_BIT, - VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = VK_DEPENDENCY_DEVICE_GROUP_BIT + VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = VK_DEPENDENCY_DEVICE_GROUP_BIT, + VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT = 8, + VK_DEPENDENCY_QUEUE_FAMILY_OWNERSHIP_TRANSFER_USE_ALL_STAGES_BIT_KHR = 32, + VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDependencyFlagBits; - typedef enum VkObjectType { VK_OBJECT_TYPE_UNKNOWN = 0, VK_OBJECT_TYPE_INSTANCE = 1, @@ -2646,29 +4096,56 @@ typedef enum VkObjectType { VK_OBJECT_TYPE_COMMAND_POOL = 25, VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000, VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000, + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT = 1000295000, VK_OBJECT_TYPE_SURFACE_KHR = 1000000000, VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000, VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000, VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001, VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000, + VK_OBJECT_TYPE_CU_MODULE_NVX = 1000029000, + VK_OBJECT_TYPE_CU_FUNCTION_NVX = 1000029001, VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000, - VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR = 1000165000, + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000, VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, - VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR, + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL = 1000210000, VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR = 1000268000, VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV = 1000277000, - VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT = 1000295000 + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT = VK_OBJECT_TYPE_PRIVATE_DATA_SLOT, + VK_OBJECT_TYPE_CUDA_MODULE_NV = 1000307000, + VK_OBJECT_TYPE_CUDA_FUNCTION_NV = 1000307001, + VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA = 1000366000, + VK_OBJECT_TYPE_MICROMAP_EXT = 1000396000, + VK_OBJECT_TYPE_OPTICAL_FLOW_SESSION_NV = 1000464000, + VK_OBJECT_TYPE_SHADER_EXT = 1000482000, + VK_OBJECT_TYPE_PIPELINE_BINARY_KHR = 1000483000, + VK_OBJECT_TYPE_EXTERNAL_COMPUTE_QUEUE_NV = 1000556000, + VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_EXT = 1000572000, + VK_OBJECT_TYPE_INDIRECT_EXECUTION_SET_EXT = 1000572001, + VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF } VkObjectType; - +typedef enum VkEventCreateFlagBits { + VK_EVENT_CREATE_DEVICE_ONLY_BIT = 1, + VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR = VK_EVENT_CREATE_DEVICE_ONLY_BIT, + VK_EVENT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkEventCreateFlagBits; +typedef enum VkPipelineLayoutCreateFlagBits { + VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT = 2, + VK_PIPELINE_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineLayoutCreateFlagBits; +typedef enum VkRayTracingInvocationReorderModeNV { + VK_RAY_TRACING_INVOCATION_REORDER_MODE_NONE_NV = 0, + VK_RAY_TRACING_INVOCATION_REORDER_MODE_REORDER_NV = 1, + VK_RAY_TRACING_INVOCATION_REORDER_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkRayTracingInvocationReorderModeNV; typedef enum VkIndirectCommandsLayoutUsageFlagBitsNV { VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_NV = 1, VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NV = 2, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV = 4 + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV = 4, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF } VkIndirectCommandsLayoutUsageFlagBitsNV; - typedef enum VkIndirectCommandsTokenTypeNV { VK_INDIRECT_COMMANDS_TOKEN_TYPE_SHADER_GROUP_NV = 0, VK_INDIRECT_COMMANDS_TOKEN_TYPE_STATE_FLAGS_NV = 1, @@ -2677,20 +4154,23 @@ typedef enum VkIndirectCommandsTokenTypeNV { VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NV = 4, VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NV = 5, VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NV = 6, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV = 7 + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV = 7, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV = 1000328000, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NV = 1000428003, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NV = 1000428004, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NV = 0x7FFFFFFF } VkIndirectCommandsTokenTypeNV; - typedef enum VkIndirectStateFlagBitsNV { - VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV = 1 + VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV = 1, + VK_INDIRECT_STATE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF } VkIndirectStateFlagBitsNV; - - typedef enum VkDescriptorUpdateTemplateType { VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS = 1, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkDescriptorUpdateTemplateType; - typedef enum VkDescriptorUpdateTemplateType VkDescriptorUpdateTemplateTypeKHR; typedef enum VkViewportCoordinateSwizzleNV { @@ -2701,72 +4181,98 @@ typedef enum VkViewportCoordinateSwizzleNV { VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4, VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5, VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7 + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7, + VK_VIEWPORT_COORDINATE_SWIZZLE_MAX_ENUM_NV = 0x7FFFFFFF } VkViewportCoordinateSwizzleNV; - typedef enum VkDiscardRectangleModeEXT { VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0, - VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1 + VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1, + VK_DISCARD_RECTANGLE_MODE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDiscardRectangleModeEXT; - typedef enum VkSubpassDescriptionFlagBits { VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 1, VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 2, VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM = 4, - VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM = 8 + VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM = 8, + VK_SUBPASS_DESCRIPTION_TILE_SHADING_APRON_BIT_QCOM = 256, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_ARM = 16, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = 32, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = 64, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT = 16, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT = 32, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT = 64, + VK_SUBPASS_DESCRIPTION_ENABLE_LEGACY_DITHERING_BIT_EXT = 128, + VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSubpassDescriptionFlagBits; - typedef enum VkPointClippingBehavior { VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0, VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1, VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, - VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY + VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY, + VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF } VkPointClippingBehavior; - typedef enum VkPointClippingBehavior VkPointClippingBehaviorKHR; typedef enum VkCoverageModulationModeNV { VK_COVERAGE_MODULATION_MODE_NONE_NV = 0, VK_COVERAGE_MODULATION_MODE_RGB_NV = 1, VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2, - VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3 + VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3, + VK_COVERAGE_MODULATION_MODE_MAX_ENUM_NV = 0x7FFFFFFF } VkCoverageModulationModeNV; - typedef enum VkCoverageReductionModeNV { VK_COVERAGE_REDUCTION_MODE_MERGE_NV = 0, - VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV = 1 + VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV = 1, + VK_COVERAGE_REDUCTION_MODE_MAX_ENUM_NV = 0x7FFFFFFF } VkCoverageReductionModeNV; - typedef enum VkValidationCacheHeaderVersionEXT { - VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1 + VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1, + VK_VALIDATION_CACHE_HEADER_VERSION_MAX_ENUM_EXT = 0x7FFFFFFF } VkValidationCacheHeaderVersionEXT; - typedef enum VkShaderInfoTypeAMD { VK_SHADER_INFO_TYPE_STATISTICS_AMD = 0, VK_SHADER_INFO_TYPE_BINARY_AMD = 1, - VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2 + VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2, + VK_SHADER_INFO_TYPE_MAX_ENUM_AMD = 0x7FFFFFFF } VkShaderInfoTypeAMD; - -typedef enum VkQueueGlobalPriorityEXT { - VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = 128, - VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = 256, - VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = 512, - VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = 1024 -} VkQueueGlobalPriorityEXT; - -typedef enum VkTimeDomainEXT { - VK_TIME_DOMAIN_DEVICE_EXT = 0, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2, - VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3 -} VkTimeDomainEXT; +typedef enum VkQueueGlobalPriority { + VK_QUEUE_GLOBAL_PRIORITY_LOW = 128, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM = 256, + VK_QUEUE_GLOBAL_PRIORITY_HIGH = 512, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME = 1024, + VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = VK_QUEUE_GLOBAL_PRIORITY_LOW, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM, + VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = VK_QUEUE_GLOBAL_PRIORITY_HIGH, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = VK_QUEUE_GLOBAL_PRIORITY_REALTIME, + VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR = VK_QUEUE_GLOBAL_PRIORITY_LOW, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM, + VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR = VK_QUEUE_GLOBAL_PRIORITY_HIGH, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR = VK_QUEUE_GLOBAL_PRIORITY_REALTIME, + VK_QUEUE_GLOBAL_PRIORITY_MAX_ENUM = 0x7FFFFFFF +} VkQueueGlobalPriority; +typedef enum VkQueueGlobalPriority VkQueueGlobalPriorityKHR; + +typedef enum VkQueueGlobalPriority VkQueueGlobalPriorityEXT; + +typedef enum VkTimeDomainKHR { + VK_TIME_DOMAIN_DEVICE_KHR = 0, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR = 1, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR = 2, + VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_KHR = 3, + VK_TIME_DOMAIN_DEVICE_EXT = VK_TIME_DOMAIN_DEVICE_KHR, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR, + VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_KHR, + VK_TIME_DOMAIN_MAX_ENUM_KHR = 0x7FFFFFFF +} VkTimeDomainKHR; +typedef enum VkTimeDomainKHR VkTimeDomainEXT; typedef enum VkConservativeRasterizationModeEXT { VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT = 0, VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT = 1, - VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2 + VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2, + VK_CONSERVATIVE_RASTERIZATION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF } VkConservativeRasterizationModeEXT; - typedef enum VkResolveModeFlagBits { VK_RESOLVE_MODE_NONE = 0, VK_RESOLVE_MODE_SAMPLE_ZERO_BIT = 1, @@ -2777,9 +4283,10 @@ typedef enum VkResolveModeFlagBits { VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT, VK_RESOLVE_MODE_AVERAGE_BIT_KHR = VK_RESOLVE_MODE_AVERAGE_BIT, VK_RESOLVE_MODE_MIN_BIT_KHR = VK_RESOLVE_MODE_MIN_BIT, - VK_RESOLVE_MODE_MAX_BIT_KHR = VK_RESOLVE_MODE_MAX_BIT + VK_RESOLVE_MODE_MAX_BIT_KHR = VK_RESOLVE_MODE_MAX_BIT, + VK_RESOLVE_MODE_EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID = 16, + VK_RESOLVE_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkResolveModeFlagBits; - typedef enum VkResolveModeFlagBits VkResolveModeFlagBitsKHR; typedef enum VkDescriptorBindingFlagBits { @@ -2790,46 +4297,68 @@ typedef enum VkDescriptorBindingFlagBits { VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, - VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT, + VK_DESCRIPTOR_BINDING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDescriptorBindingFlagBits; - typedef enum VkDescriptorBindingFlagBits VkDescriptorBindingFlagBitsEXT; typedef enum VkConditionalRenderingFlagBitsEXT { - VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT = 1 + VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT = 1, + VK_CONDITIONAL_RENDERING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkConditionalRenderingFlagBitsEXT; - typedef enum VkSemaphoreType { VK_SEMAPHORE_TYPE_BINARY = 0, VK_SEMAPHORE_TYPE_TIMELINE = 1, VK_SEMAPHORE_TYPE_BINARY_KHR = VK_SEMAPHORE_TYPE_BINARY, - VK_SEMAPHORE_TYPE_TIMELINE_KHR = VK_SEMAPHORE_TYPE_TIMELINE + VK_SEMAPHORE_TYPE_TIMELINE_KHR = VK_SEMAPHORE_TYPE_TIMELINE, + VK_SEMAPHORE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkSemaphoreType; - typedef enum VkSemaphoreType VkSemaphoreTypeKHR; typedef enum VkGeometryFlagBitsKHR { VK_GEOMETRY_OPAQUE_BIT_KHR = 1, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR = 2, VK_GEOMETRY_OPAQUE_BIT_NV = VK_GEOMETRY_OPAQUE_BIT_KHR, - VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR + VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR, + VK_GEOMETRY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkGeometryFlagBitsKHR; - typedef enum VkGeometryFlagBitsKHR VkGeometryFlagBitsNV; typedef enum VkGeometryInstanceFlagBitsKHR { VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR = 1, - VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR = 2, + VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR = 2, VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR = 4, VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR = 8, + VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR = VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR, VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR, VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR, VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, - VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR + VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FORCE_OPACITY_MICROMAP_2_STATE_EXT = 16, + VK_GEOMETRY_INSTANCE_DISABLE_OPACITY_MICROMAPS_EXT = 32, + VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkGeometryInstanceFlagBitsKHR; - typedef enum VkGeometryInstanceFlagBitsKHR VkGeometryInstanceFlagBitsNV; +typedef enum VkClusterAccelerationStructureAddressResolutionFlagBitsNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_DST_IMPLICIT_DATA_BIT_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_SCRATCH_DATA_BIT_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_DST_ADDRESS_ARRAY_BIT_NV = 4, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_DST_SIZES_ARRAY_BIT_NV = 8, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_SRC_INFOS_ARRAY_BIT_NV = 16, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_SRC_INFOS_COUNT_BIT_NV = 32, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureAddressResolutionFlagBitsNV; +typedef enum VkClusterAccelerationStructureGeometryFlagBitsNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_GEOMETRY_CULL_DISABLE_BIT_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_GEOMETRY_NO_DUPLICATE_ANYHIT_INVOCATION_BIT_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_GEOMETRY_OPAQUE_BIT_NV = 4, + VK_CLUSTER_ACCELERATION_STRUCTURE_GEOMETRY_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureGeometryFlagBitsNV; +typedef enum VkClusterAccelerationStructureClusterFlagBitsNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_CLUSTER_ALLOW_DISABLE_OPACITY_MICROMAPS_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_CLUSTER_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureClusterFlagBitsNV; typedef enum VkBuildAccelerationStructureFlagBitsKHR { VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR = 1, VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR = 2, @@ -2840,39 +4369,59 @@ typedef enum VkBuildAccelerationStructureFlagBitsKHR { VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR, - VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR + VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV = 32, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_UPDATE_EXT = 64, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISABLE_OPACITY_MICROMAPS_EXT = 128, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_DATA_UPDATE_EXT = 256, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISPLACEMENT_MICROMAP_UPDATE_NV = 512, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DATA_ACCESS_KHR = 2048, + VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkBuildAccelerationStructureFlagBitsKHR; - typedef enum VkBuildAccelerationStructureFlagBitsKHR VkBuildAccelerationStructureFlagBitsNV; +typedef enum VkAccelerationStructureCreateFlagBitsKHR { + VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = 1, + VK_ACCELERATION_STRUCTURE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 8, + VK_ACCELERATION_STRUCTURE_CREATE_MOTION_BIT_NV = 4, + VK_ACCELERATION_STRUCTURE_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureCreateFlagBitsKHR; +typedef enum VkBuildAccelerationStructureModeKHR { + VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR = 0, + VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR = 1, + VK_BUILD_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkBuildAccelerationStructureModeKHR; typedef enum VkCopyAccelerationStructureModeKHR { VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR = 0, VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR = 1, VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR = 2, VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR = 3, VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR, - VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR + VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR, + VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR = 0x7FFFFFFF } VkCopyAccelerationStructureModeKHR; - typedef enum VkCopyAccelerationStructureModeKHR VkCopyAccelerationStructureModeNV; typedef enum VkAccelerationStructureTypeKHR { VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR = 0, VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR = 1, + VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR = 2, VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, - VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR + VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, + VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF } VkAccelerationStructureTypeKHR; - typedef enum VkAccelerationStructureTypeKHR VkAccelerationStructureTypeNV; typedef enum VkGeometryTypeKHR { VK_GEOMETRY_TYPE_TRIANGLES_KHR = 0, VK_GEOMETRY_TYPE_AABBS_KHR = 1, - VK_GEOMETRY_TYPE_INSTANCES_KHR = 1000150000, + VK_GEOMETRY_TYPE_INSTANCES_KHR = 2, VK_GEOMETRY_TYPE_TRIANGLES_NV = VK_GEOMETRY_TYPE_TRIANGLES_KHR, - VK_GEOMETRY_TYPE_AABBS_NV = VK_GEOMETRY_TYPE_AABBS_KHR + VK_GEOMETRY_TYPE_AABBS_NV = VK_GEOMETRY_TYPE_AABBS_KHR, + VK_GEOMETRY_TYPE_SPHERES_NV = 1000429004, + VK_GEOMETRY_TYPE_LINEAR_SWEPT_SPHERES_NV = 1000429005, + VK_GEOMETRY_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF } VkGeometryTypeKHR; - typedef enum VkGeometryTypeKHR VkGeometryTypeNV; typedef enum VkRayTracingShaderGroupTypeKHR { @@ -2881,68 +4430,68 @@ typedef enum VkRayTracingShaderGroupTypeKHR { VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR = 2, VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR, VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR, - VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR + VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF } VkRayTracingShaderGroupTypeKHR; - typedef enum VkRayTracingShaderGroupTypeKHR VkRayTracingShaderGroupTypeNV; -typedef enum VkAccelerationStructureMemoryRequirementsTypeKHR { - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR = 0, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR = 1, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_KHR = 2, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_KHR -} VkAccelerationStructureMemoryRequirementsTypeKHR; - -typedef enum VkAccelerationStructureMemoryRequirementsTypeKHR VkAccelerationStructureMemoryRequirementsTypeNV; - -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef enum VkAccelerationStructureMemoryRequirementsTypeNV { + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkAccelerationStructureMemoryRequirementsTypeNV; typedef enum VkAccelerationStructureBuildTypeKHR { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR = 0, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR = 1, - VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR = 2 + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR = 2, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF } VkAccelerationStructureBuildTypeKHR; -#endif - +typedef enum VkAccelerationStructureCompatibilityKHR { + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_COMPATIBLE_KHR = 0, + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_INCOMPATIBLE_KHR = 1, + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureCompatibilityKHR; +typedef enum VkRayTracingLssIndexingModeNV { + VK_RAY_TRACING_LSS_INDEXING_MODE_LIST_NV = 0, + VK_RAY_TRACING_LSS_INDEXING_MODE_SUCCESSIVE_NV = 1, + VK_RAY_TRACING_LSS_INDEXING_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkRayTracingLssIndexingModeNV; +typedef enum VkRayTracingLssPrimitiveEndCapsModeNV { + VK_RAY_TRACING_LSS_PRIMITIVE_END_CAPS_MODE_NONE_NV = 0, + VK_RAY_TRACING_LSS_PRIMITIVE_END_CAPS_MODE_CHAINED_NV = 1, + VK_RAY_TRACING_LSS_PRIMITIVE_END_CAPS_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkRayTracingLssPrimitiveEndCapsModeNV; +typedef enum VkShaderGroupShaderKHR { + VK_SHADER_GROUP_SHADER_GENERAL_KHR = 0, + VK_SHADER_GROUP_SHADER_CLOSEST_HIT_KHR = 1, + VK_SHADER_GROUP_SHADER_ANY_HIT_KHR = 2, + VK_SHADER_GROUP_SHADER_INTERSECTION_KHR = 3, + VK_SHADER_GROUP_SHADER_MAX_ENUM_KHR = 0x7FFFFFFF +} VkShaderGroupShaderKHR; typedef enum VkMemoryOverallocationBehaviorAMD { VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0, VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2 + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_MAX_ENUM_AMD = 0x7FFFFFFF } VkMemoryOverallocationBehaviorAMD; - -typedef enum VkScopeNV { - VK_SCOPE_DEVICE_NV = 1, - VK_SCOPE_WORKGROUP_NV = 2, - VK_SCOPE_SUBGROUP_NV = 3, - VK_SCOPE_QUEUE_FAMILY_NV = 5 -} VkScopeNV; - -typedef enum VkComponentTypeNV { - VK_COMPONENT_TYPE_FLOAT16_NV = 0, - VK_COMPONENT_TYPE_FLOAT32_NV = 1, - VK_COMPONENT_TYPE_FLOAT64_NV = 2, - VK_COMPONENT_TYPE_SINT8_NV = 3, - VK_COMPONENT_TYPE_SINT16_NV = 4, - VK_COMPONENT_TYPE_SINT32_NV = 5, - VK_COMPONENT_TYPE_SINT64_NV = 6, - VK_COMPONENT_TYPE_UINT8_NV = 7, - VK_COMPONENT_TYPE_UINT16_NV = 8, - VK_COMPONENT_TYPE_UINT32_NV = 9, - VK_COMPONENT_TYPE_UINT64_NV = 10 -} VkComponentTypeNV; - typedef enum VkDeviceDiagnosticsConfigFlagBitsNV { VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV = 1, VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV = 2, - VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV = 4 + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV = 4, + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_ERROR_REPORTING_BIT_NV = 8, + VK_DEVICE_DIAGNOSTICS_CONFIG_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF } VkDeviceDiagnosticsConfigFlagBitsNV; - -typedef enum VkPipelineCreationFeedbackFlagBitsEXT { - VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT = 1, - VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT = 2, - VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT = 4 -} VkPipelineCreationFeedbackFlagBitsEXT; +typedef enum VkPipelineCreationFeedbackFlagBits { + VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT = 1, + VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT = 2, + VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT = 4, + VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT, + VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT, + VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT, + VK_PIPELINE_CREATION_FEEDBACK_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCreationFeedbackFlagBits; +typedef enum VkPipelineCreationFeedbackFlagBits VkPipelineCreationFeedbackFlagBitsEXT; typedef enum VkPerformanceCounterScopeKHR { VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR = 0, @@ -2950,9 +4499,9 @@ typedef enum VkPerformanceCounterScopeKHR { VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR = 2, VK_QUERY_SCOPE_COMMAND_BUFFER_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR, VK_QUERY_SCOPE_RENDER_PASS_KHR = VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR, - VK_QUERY_SCOPE_COMMAND_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR + VK_QUERY_SCOPE_COMMAND_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR, + VK_PERFORMANCE_COUNTER_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF } VkPerformanceCounterScopeKHR; - typedef enum VkPerformanceCounterUnitKHR { VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR = 0, VK_PERFORMANCE_COUNTER_UNIT_PERCENTAGE_KHR = 1, @@ -2964,77 +4513,791 @@ typedef enum VkPerformanceCounterUnitKHR { VK_PERFORMANCE_COUNTER_UNIT_VOLTS_KHR = 7, VK_PERFORMANCE_COUNTER_UNIT_AMPS_KHR = 8, VK_PERFORMANCE_COUNTER_UNIT_HERTZ_KHR = 9, - VK_PERFORMANCE_COUNTER_UNIT_CYCLES_KHR = 10 + VK_PERFORMANCE_COUNTER_UNIT_CYCLES_KHR = 10, + VK_PERFORMANCE_COUNTER_UNIT_MAX_ENUM_KHR = 0x7FFFFFFF } VkPerformanceCounterUnitKHR; - typedef enum VkPerformanceCounterStorageKHR { VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR = 0, VK_PERFORMANCE_COUNTER_STORAGE_INT64_KHR = 1, VK_PERFORMANCE_COUNTER_STORAGE_UINT32_KHR = 2, VK_PERFORMANCE_COUNTER_STORAGE_UINT64_KHR = 3, VK_PERFORMANCE_COUNTER_STORAGE_FLOAT32_KHR = 4, - VK_PERFORMANCE_COUNTER_STORAGE_FLOAT64_KHR = 5 + VK_PERFORMANCE_COUNTER_STORAGE_FLOAT64_KHR = 5, + VK_PERFORMANCE_COUNTER_STORAGE_MAX_ENUM_KHR = 0x7FFFFFFF } VkPerformanceCounterStorageKHR; - typedef enum VkPerformanceCounterDescriptionFlagBitsKHR { - VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_KHR = 1, - VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_KHR = 2 + VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR = 1, + VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_KHR = VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR, + VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR = 2, + VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_KHR = VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR, + VK_PERFORMANCE_COUNTER_DESCRIPTION_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkPerformanceCounterDescriptionFlagBitsKHR; - - typedef enum VkSemaphoreWaitFlagBits { VK_SEMAPHORE_WAIT_ANY_BIT = 1, - VK_SEMAPHORE_WAIT_ANY_BIT_KHR = VK_SEMAPHORE_WAIT_ANY_BIT + VK_SEMAPHORE_WAIT_ANY_BIT_KHR = VK_SEMAPHORE_WAIT_ANY_BIT, + VK_SEMAPHORE_WAIT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSemaphoreWaitFlagBits; - typedef enum VkSemaphoreWaitFlagBits VkSemaphoreWaitFlagBitsKHR; typedef enum VkPerformanceConfigurationTypeINTEL { - VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL = 0 + VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL = 0, + VK_PERFORMANCE_CONFIGURATION_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkPerformanceConfigurationTypeINTEL; - typedef enum VkQueryPoolSamplingModeINTEL { - VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL = 0 + VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL = 0, + VK_QUERY_POOL_SAMPLING_MODE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkQueryPoolSamplingModeINTEL; - typedef enum VkPerformanceOverrideTypeINTEL { VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL = 0, - VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL = 1 + VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL = 1, + VK_PERFORMANCE_OVERRIDE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkPerformanceOverrideTypeINTEL; - typedef enum VkPerformanceParameterTypeINTEL { VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL = 0, - VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL = 1 + VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL = 1, + VK_PERFORMANCE_PARAMETER_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkPerformanceParameterTypeINTEL; - typedef enum VkPerformanceValueTypeINTEL { VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL = 0, VK_PERFORMANCE_VALUE_TYPE_UINT64_INTEL = 1, VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL = 2, VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL = 3, - VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL = 4 + VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL = 4, + VK_PERFORMANCE_VALUE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkPerformanceValueTypeINTEL; - -typedef enum VkLineRasterizationModeEXT { - VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT = 0, - VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT = 1, - VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT = 2, - VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT = 3 -} VkLineRasterizationModeEXT; - - - - -typedef enum VkToolPurposeFlagBitsEXT { - VK_TOOL_PURPOSE_VALIDATION_BIT_EXT = 1, - VK_TOOL_PURPOSE_PROFILING_BIT_EXT = 2, - VK_TOOL_PURPOSE_TRACING_BIT_EXT = 4, - VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT = 8, - VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT = 16, +typedef enum VkLineRasterizationMode { + VK_LINE_RASTERIZATION_MODE_DEFAULT = 0, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR = 1, + VK_LINE_RASTERIZATION_MODE_BRESENHAM = 2, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH = 3, + VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT = VK_LINE_RASTERIZATION_MODE_DEFAULT, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT = VK_LINE_RASTERIZATION_MODE_RECTANGULAR, + VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT = VK_LINE_RASTERIZATION_MODE_BRESENHAM, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH, + VK_LINE_RASTERIZATION_MODE_DEFAULT_KHR = VK_LINE_RASTERIZATION_MODE_DEFAULT, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_KHR = VK_LINE_RASTERIZATION_MODE_RECTANGULAR, + VK_LINE_RASTERIZATION_MODE_BRESENHAM_KHR = VK_LINE_RASTERIZATION_MODE_BRESENHAM, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_KHR = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH, + VK_LINE_RASTERIZATION_MODE_MAX_ENUM = 0x7FFFFFFF +} VkLineRasterizationMode; +typedef enum VkLineRasterizationMode VkLineRasterizationModeKHR; + +typedef enum VkLineRasterizationMode VkLineRasterizationModeEXT; + +typedef enum VkToolPurposeFlagBits { + VK_TOOL_PURPOSE_VALIDATION_BIT = 1, + VK_TOOL_PURPOSE_PROFILING_BIT = 2, + VK_TOOL_PURPOSE_TRACING_BIT = 4, + VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT = 8, + VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT = 16, + VK_TOOL_PURPOSE_VALIDATION_BIT_EXT = VK_TOOL_PURPOSE_VALIDATION_BIT, + VK_TOOL_PURPOSE_PROFILING_BIT_EXT = VK_TOOL_PURPOSE_PROFILING_BIT, + VK_TOOL_PURPOSE_TRACING_BIT_EXT = VK_TOOL_PURPOSE_TRACING_BIT, + VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT, + VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT, VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT = 32, - VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT = 64 -} VkToolPurposeFlagBitsEXT; + VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT = 64, + VK_TOOL_PURPOSE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkToolPurposeFlagBits; +typedef enum VkToolPurposeFlagBits VkToolPurposeFlagBitsEXT; + +typedef enum VkFragmentShadingRateNV { + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV = 0, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV = 1, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV = 4, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV = 5, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV = 6, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV = 9, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV = 10, + VK_FRAGMENT_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV = 11, + VK_FRAGMENT_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV = 12, + VK_FRAGMENT_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV = 13, + VK_FRAGMENT_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV = 14, + VK_FRAGMENT_SHADING_RATE_NO_INVOCATIONS_NV = 15, + VK_FRAGMENT_SHADING_RATE_MAX_ENUM_NV = 0x7FFFFFFF +} VkFragmentShadingRateNV; +typedef enum VkFragmentShadingRateTypeNV { + VK_FRAGMENT_SHADING_RATE_TYPE_FRAGMENT_SIZE_NV = 0, + VK_FRAGMENT_SHADING_RATE_TYPE_ENUMS_NV = 1, + VK_FRAGMENT_SHADING_RATE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkFragmentShadingRateTypeNV; +typedef enum VkSubpassMergeStatusEXT { + VK_SUBPASS_MERGE_STATUS_MERGED_EXT = 0, + VK_SUBPASS_MERGE_STATUS_DISALLOWED_EXT = 1, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SIDE_EFFECTS_EXT = 2, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SAMPLES_MISMATCH_EXT = 3, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_VIEWS_MISMATCH_EXT = 4, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_ALIASING_EXT = 5, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPENDENCIES_EXT = 6, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INCOMPATIBLE_INPUT_ATTACHMENT_EXT = 7, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_TOO_MANY_ATTACHMENTS_EXT = 8, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INSUFFICIENT_STORAGE_EXT = 9, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPTH_STENCIL_COUNT_EXT = 10, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_RESOLVE_ATTACHMENT_REUSE_EXT = 11, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SINGLE_SUBPASS_EXT = 12, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_UNSPECIFIED_EXT = 13, + VK_SUBPASS_MERGE_STATUS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkSubpassMergeStatusEXT; +typedef uint64_t VkAccessFlagBits2; +static const VkAccessFlagBits2 VK_ACCESS_2_NONE = 0; +static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT = 1; +static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT = 2; +static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT = 4; +static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT = 8; +static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT = 16; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT = 32; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT = 64; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT = 128; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT = 256; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 512; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 1024; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT = 2048; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT = 4096; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT = 8192; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT = 16384; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT = 32768; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT = 65536; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT = 4294967296; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT = 8589934592; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT = 17179869184; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_TILE_ATTACHMENT_READ_BIT_QCOM = 2251799813685248; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_TILE_ATTACHMENT_WRITE_BIT_QCOM = 4503599627370496; +static const VkAccessFlagBits2 VK_ACCESS_2_NONE_KHR = 0; +static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR = 1; +static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT_KHR = 2; +static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR = 4; +static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT_KHR = 8; +static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR = 16; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT_KHR = 32; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT_KHR = 64; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR = 128; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR = 256; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR = 512; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR = 1024; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT_KHR = 2048; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR = 4096; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT_KHR = 8192; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT_KHR = 16384; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT_KHR = 32768; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT_KHR = 65536; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR = 4294967296; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR = 8589934592; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR = 17179869184; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 33554432; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 67108864; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 134217728; +static const VkAccessFlagBits2 VK_ACCESS_2_CONDITIONAL_RENDERING_READ_BIT_EXT = 1048576; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_NV = 131072; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_NV = 262144; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_EXT = 131072; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_EXT = 262144; +static const VkAccessFlagBits2 VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 8388608; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADING_RATE_IMAGE_READ_BIT_NV = 8388608; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR = 2097152; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 4194304; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_NV = 2097152; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 4194304; +static const VkAccessFlagBits2 VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 16777216; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 524288; +static const VkAccessFlagBits2 VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT = 2199023255552; +static const VkAccessFlagBits2 VK_ACCESS_2_INVOCATION_MASK_READ_BIT_HUAWEI = 549755813888; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_BINDING_TABLE_READ_BIT_KHR = 1099511627776; +static const VkAccessFlagBits2 VK_ACCESS_2_MICROMAP_READ_BIT_EXT = 17592186044416; +static const VkAccessFlagBits2 VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT = 35184372088832; +static const VkAccessFlagBits2 VK_ACCESS_2_OPTICAL_FLOW_READ_BIT_NV = 4398046511104; +static const VkAccessFlagBits2 VK_ACCESS_2_OPTICAL_FLOW_WRITE_BIT_NV = 8796093022208; + +typedef VkAccessFlagBits2 VkAccessFlagBits2KHR; + +typedef uint64_t VkPipelineStageFlagBits2; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE = 0; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT = 1; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT = 2; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT = 4; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT = 8; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT = 16; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT = 32; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT = 64; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT = 128; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT = 256; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT = 512; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT = 1024; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT = 2048; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT = 4096; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT = 4096; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT = 8192; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT = 16384; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT = 32768; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT = 65536; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT = 4294967296; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT = 8589934592; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT = 17179869184; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT = 34359738368; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT = 68719476736; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT = 137438953472; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT = 274877906944; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE_KHR = 0; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR = 1; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR = 2; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR = 4; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR = 8; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR = 16; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR = 32; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR = 64; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR = 128; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR = 256; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR = 512; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR = 1024; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR = 2048; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR = 4096; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR = 4096; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR = 8192; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT_KHR = 16384; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR = 32768; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR = 65536; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT_KHR = 4294967296; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR = 8589934592; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT_KHR = 17179869184; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR = 34359738368; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR = 68719476736; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR = 137438953472; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR = 274877906944; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT = 16777216; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT = 262144; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV = 131072; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_EXT = 131072; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 4194304; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SHADING_RATE_IMAGE_BIT_NV = 4194304; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 33554432; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR = 2097152; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_NV = 2097152; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 33554432; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 8388608; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_NV = 524288; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_NV = 1048576; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT = 524288; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT = 1048576; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SUBPASS_SHADER_BIT_HUAWEI = 549755813888; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI = 549755813888; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INVOCATION_MASK_BIT_HUAWEI = 1099511627776; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_COPY_BIT_KHR = 268435456; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT = 1073741824; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLUSTER_CULLING_SHADER_BIT_HUAWEI = 2199023255552; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_OPTICAL_FLOW_BIT_NV = 536870912; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CONVERT_COOPERATIVE_VECTOR_MATRIX_BIT_NV = 17592186044416; + +typedef VkPipelineStageFlagBits2 VkPipelineStageFlagBits2KHR; + +typedef enum VkProvokingVertexModeEXT { + VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT = 0, + VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT = 1, + VK_PROVOKING_VERTEX_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkProvokingVertexModeEXT; +typedef enum VkHostImageCopyFlagBits { + VK_HOST_IMAGE_COPY_MEMCPY = 1, + VK_HOST_IMAGE_COPY_MEMCPY_EXT = VK_HOST_IMAGE_COPY_MEMCPY, + VK_HOST_IMAGE_COPY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkHostImageCopyFlagBits; +typedef enum VkHostImageCopyFlagBits VkHostImageCopyFlagBitsEXT; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef enum VkImageConstraintsInfoFlagBitsFUCHSIA { + VK_IMAGE_CONSTRAINTS_INFO_CPU_READ_RARELY_FUCHSIA = 1, + VK_IMAGE_CONSTRAINTS_INFO_CPU_READ_OFTEN_FUCHSIA = 2, + VK_IMAGE_CONSTRAINTS_INFO_CPU_WRITE_RARELY_FUCHSIA = 4, + VK_IMAGE_CONSTRAINTS_INFO_CPU_WRITE_OFTEN_FUCHSIA = 8, + VK_IMAGE_CONSTRAINTS_INFO_PROTECTED_OPTIONAL_FUCHSIA = 16, + VK_IMAGE_CONSTRAINTS_INFO_FLAG_BITS_MAX_ENUM_FUCHSIA = 0x7FFFFFFF +} VkImageConstraintsInfoFlagBitsFUCHSIA; +#endif + +typedef uint64_t VkFormatFeatureFlagBits2; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT = 1; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT = 2; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT = 4; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT = 8; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT = 16; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 32; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT = 64; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT = 128; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT = 256; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT = 512; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT = 1024; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT = 2048; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 4096; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT = 16384; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT = 32768; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 65536; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT = 131072; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 262144; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 524288; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 1048576; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 2097152; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT = 4194304; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT = 8388608; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT = 2147483648; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT = 4294967296; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT = 8589934592; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT = 8192; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT = 70368744177664; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR = 536870912; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_DENSITY_MAP_BIT_EXT = 16777216; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 1073741824; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT = 70368744177664; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT_KHR = 1; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT_KHR = 2; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT_KHR = 4; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR = 8; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT_KHR = 16; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT_KHR = 32; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT_KHR = 64; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT_KHR = 128; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT_KHR = 256; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT_KHR = 512; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT_KHR = 1024; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT_KHR = 2048; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT_KHR = 4096; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT_KHR = 16384; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT_KHR = 32768; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = 131072; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = 262144; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = 524288; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = 1048576; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = 2097152; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT_KHR = 4194304; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT_KHR = 8388608; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT_KHR = 2147483648; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR = 4294967296; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT_KHR = 8589934592; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT_KHR = 65536; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 8192; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_ACCELERATION_STRUCTURE_RADIUS_BUFFER_BIT_NV = 2251799813685248; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_LINEAR_COLOR_ATTACHMENT_BIT_NV = 274877906944; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_IMAGE_BIT_QCOM = 17179869184; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_SAMPLED_IMAGE_BIT_QCOM = 34359738368; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLOCK_MATCHING_BIT_QCOM = 68719476736; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BOX_FILTER_SAMPLED_BIT_QCOM = 137438953472; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_IMAGE_BIT_NV = 1099511627776; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_VECTOR_BIT_NV = 2199023255552; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_COST_BIT_NV = 4398046511104; + +typedef VkFormatFeatureFlagBits2 VkFormatFeatureFlagBits2KHR; + +typedef enum VkRenderingFlagBits { + VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT = 1, + VK_RENDERING_SUSPENDING_BIT = 2, + VK_RENDERING_RESUMING_BIT = 4, + VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT, + VK_RENDERING_SUSPENDING_BIT_KHR = VK_RENDERING_SUSPENDING_BIT, + VK_RENDERING_RESUMING_BIT_KHR = VK_RENDERING_RESUMING_BIT, + VK_RENDERING_CONTENTS_INLINE_BIT_EXT = 16, + VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT = 8, + VK_RENDERING_CONTENTS_INLINE_BIT_KHR = 16, + VK_RENDERING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkRenderingFlagBits; +typedef enum VkRenderingFlagBits VkRenderingFlagBitsKHR; + +typedef enum VkPipelineDepthStencilStateCreateFlagBits { + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = 1, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = 2, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT = 1, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT = 2, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineDepthStencilStateCreateFlagBits; +typedef enum VkPipelineColorBlendStateCreateFlagBits { + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM = 1, + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT = 1, + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineColorBlendStateCreateFlagBits; +typedef enum VkImageCompressionFlagBitsEXT { + VK_IMAGE_COMPRESSION_DEFAULT_EXT = 0, + VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT = 1, + VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT = 2, + VK_IMAGE_COMPRESSION_DISABLED_EXT = 4, + VK_IMAGE_COMPRESSION_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkImageCompressionFlagBitsEXT; +typedef enum VkImageCompressionFixedRateFlagBitsEXT { + VK_IMAGE_COMPRESSION_FIXED_RATE_NONE_EXT = 0, + VK_IMAGE_COMPRESSION_FIXED_RATE_1BPC_BIT_EXT = 1, + VK_IMAGE_COMPRESSION_FIXED_RATE_2BPC_BIT_EXT = 2, + VK_IMAGE_COMPRESSION_FIXED_RATE_3BPC_BIT_EXT = 4, + VK_IMAGE_COMPRESSION_FIXED_RATE_4BPC_BIT_EXT = 8, + VK_IMAGE_COMPRESSION_FIXED_RATE_5BPC_BIT_EXT = 16, + VK_IMAGE_COMPRESSION_FIXED_RATE_6BPC_BIT_EXT = 32, + VK_IMAGE_COMPRESSION_FIXED_RATE_7BPC_BIT_EXT = 64, + VK_IMAGE_COMPRESSION_FIXED_RATE_8BPC_BIT_EXT = 128, + VK_IMAGE_COMPRESSION_FIXED_RATE_9BPC_BIT_EXT = 256, + VK_IMAGE_COMPRESSION_FIXED_RATE_10BPC_BIT_EXT = 512, + VK_IMAGE_COMPRESSION_FIXED_RATE_11BPC_BIT_EXT = 1024, + VK_IMAGE_COMPRESSION_FIXED_RATE_12BPC_BIT_EXT = 2048, + VK_IMAGE_COMPRESSION_FIXED_RATE_13BPC_BIT_EXT = 4096, + VK_IMAGE_COMPRESSION_FIXED_RATE_14BPC_BIT_EXT = 8192, + VK_IMAGE_COMPRESSION_FIXED_RATE_15BPC_BIT_EXT = 16384, + VK_IMAGE_COMPRESSION_FIXED_RATE_16BPC_BIT_EXT = 32768, + VK_IMAGE_COMPRESSION_FIXED_RATE_17BPC_BIT_EXT = 65536, + VK_IMAGE_COMPRESSION_FIXED_RATE_18BPC_BIT_EXT = 131072, + VK_IMAGE_COMPRESSION_FIXED_RATE_19BPC_BIT_EXT = 262144, + VK_IMAGE_COMPRESSION_FIXED_RATE_20BPC_BIT_EXT = 524288, + VK_IMAGE_COMPRESSION_FIXED_RATE_21BPC_BIT_EXT = 1048576, + VK_IMAGE_COMPRESSION_FIXED_RATE_22BPC_BIT_EXT = 2097152, + VK_IMAGE_COMPRESSION_FIXED_RATE_23BPC_BIT_EXT = 4194304, + VK_IMAGE_COMPRESSION_FIXED_RATE_24BPC_BIT_EXT = 8388608, + VK_IMAGE_COMPRESSION_FIXED_RATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkImageCompressionFixedRateFlagBitsEXT; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef enum VkExportMetalObjectTypeFlagBitsEXT { + VK_EXPORT_METAL_OBJECT_TYPE_METAL_DEVICE_BIT_EXT = 1, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_COMMAND_QUEUE_BIT_EXT = 2, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_BUFFER_BIT_EXT = 4, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT = 8, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT = 16, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT = 32, + VK_EXPORT_METAL_OBJECT_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkExportMetalObjectTypeFlagBitsEXT; +#endif + +typedef enum VkPipelineRobustnessBufferBehavior { + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT = 0, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED = 1, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS = 2, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2 = 3, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT_EXT = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED_EXT = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF +} VkPipelineRobustnessBufferBehavior; +typedef enum VkPipelineRobustnessBufferBehavior VkPipelineRobustnessBufferBehaviorEXT; + +typedef enum VkPipelineRobustnessImageBehavior { + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT = 0, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED = 1, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS = 2, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2 = 3, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED_EXT = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_EXT = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2_EXT = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF +} VkPipelineRobustnessImageBehavior; +typedef enum VkPipelineRobustnessImageBehavior VkPipelineRobustnessImageBehaviorEXT; + +typedef enum VkDeviceAddressBindingFlagBitsEXT { + VK_DEVICE_ADDRESS_BINDING_INTERNAL_OBJECT_BIT_EXT = 1, + VK_DEVICE_ADDRESS_BINDING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceAddressBindingFlagBitsEXT; +typedef enum VkDeviceAddressBindingTypeEXT { + VK_DEVICE_ADDRESS_BINDING_TYPE_BIND_EXT = 0, + VK_DEVICE_ADDRESS_BINDING_TYPE_UNBIND_EXT = 1, + VK_DEVICE_ADDRESS_BINDING_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceAddressBindingTypeEXT; +typedef enum VkMicromapTypeEXT { + VK_MICROMAP_TYPE_OPACITY_MICROMAP_EXT = 0, + VK_MICROMAP_TYPE_DISPLACEMENT_MICROMAP_NV = 1000397000, + VK_MICROMAP_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkMicromapTypeEXT; +typedef enum VkBuildMicromapModeEXT { + VK_BUILD_MICROMAP_MODE_BUILD_EXT = 0, + VK_BUILD_MICROMAP_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkBuildMicromapModeEXT; +typedef enum VkCopyMicromapModeEXT { + VK_COPY_MICROMAP_MODE_CLONE_EXT = 0, + VK_COPY_MICROMAP_MODE_SERIALIZE_EXT = 1, + VK_COPY_MICROMAP_MODE_DESERIALIZE_EXT = 2, + VK_COPY_MICROMAP_MODE_COMPACT_EXT = 3, + VK_COPY_MICROMAP_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkCopyMicromapModeEXT; +typedef enum VkBuildMicromapFlagBitsEXT { + VK_BUILD_MICROMAP_PREFER_FAST_TRACE_BIT_EXT = 1, + VK_BUILD_MICROMAP_PREFER_FAST_BUILD_BIT_EXT = 2, + VK_BUILD_MICROMAP_ALLOW_COMPACTION_BIT_EXT = 4, + VK_BUILD_MICROMAP_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkBuildMicromapFlagBitsEXT; +typedef enum VkMicromapCreateFlagBitsEXT { + VK_MICROMAP_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = 1, + VK_MICROMAP_CREATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkMicromapCreateFlagBitsEXT; +typedef enum VkOpacityMicromapFormatEXT { + VK_OPACITY_MICROMAP_FORMAT_2_STATE_EXT = 1, + VK_OPACITY_MICROMAP_FORMAT_4_STATE_EXT = 2, + VK_OPACITY_MICROMAP_FORMAT_MAX_ENUM_EXT = 0x7FFFFFFF +} VkOpacityMicromapFormatEXT; +typedef enum VkOpacityMicromapSpecialIndexEXT { + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_TRANSPARENT_EXT = -1, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_OPAQUE_EXT = -2, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_TRANSPARENT_EXT = -3, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_OPAQUE_EXT = -4, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_CLUSTER_GEOMETRY_DISABLE_OPACITY_MICROMAP_NV = -5, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_MAX_ENUM_EXT = 0x7FFFFFFF +} VkOpacityMicromapSpecialIndexEXT; +typedef enum VkDeviceFaultVendorBinaryHeaderVersionEXT { + VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT = 1, + VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceFaultVendorBinaryHeaderVersionEXT; +typedef enum VkIndirectCommandsLayoutUsageFlagBitsEXT { + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_EXT = 1, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_EXT = 2, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkIndirectCommandsLayoutUsageFlagBitsEXT; +typedef enum VkIndirectExecutionSetInfoTypeEXT { + VK_INDIRECT_EXECUTION_SET_INFO_TYPE_PIPELINES_EXT = 0, + VK_INDIRECT_EXECUTION_SET_INFO_TYPE_SHADER_OBJECTS_EXT = 1, + VK_INDIRECT_EXECUTION_SET_INFO_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkIndirectExecutionSetInfoTypeEXT; +typedef enum VkIndirectCommandsInputModeFlagBitsEXT { + VK_INDIRECT_COMMANDS_INPUT_MODE_VULKAN_INDEX_BUFFER_EXT = 1, + VK_INDIRECT_COMMANDS_INPUT_MODE_DXGI_INDEX_BUFFER_EXT = 2, + VK_INDIRECT_COMMANDS_INPUT_MODE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkIndirectCommandsInputModeFlagBitsEXT; +typedef enum VkFrameBoundaryFlagBitsEXT { + VK_FRAME_BOUNDARY_FRAME_END_BIT_EXT = 1, + VK_FRAME_BOUNDARY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkFrameBoundaryFlagBitsEXT; +typedef uint64_t VkMemoryDecompressionMethodFlagBitsNV; +static const VkMemoryDecompressionMethodFlagBitsNV VK_MEMORY_DECOMPRESSION_METHOD_GDEFLATE_1_0_BIT_NV = 1; + +typedef enum VkDepthBiasRepresentationEXT { + VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT = 0, + VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT = 1, + VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT = 2, + VK_DEPTH_BIAS_REPRESENTATION_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDepthBiasRepresentationEXT; +typedef enum VkDirectDriverLoadingModeLUNARG { + VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG = 0, + VK_DIRECT_DRIVER_LOADING_MODE_INCLUSIVE_LUNARG = 1, + VK_DIRECT_DRIVER_LOADING_MODE_MAX_ENUM_LUNARG = 0x7FFFFFFF +} VkDirectDriverLoadingModeLUNARG; +typedef uint64_t VkPipelineCreateFlagBits2; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISABLE_OPTIMIZATION_BIT = 1; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_ALLOW_DERIVATIVES_BIT = 2; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DERIVATIVE_BIT = 4; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 8; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISPATCH_BASE_BIT = 16; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT = 256; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_EARLY_RETURN_ON_FAILURE_BIT = 512; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_NO_PROTECTED_ACCESS_BIT = 134217728; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT = 1073741824; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_EXECUTION_GRAPH_BIT_AMDX = 4294967296; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_SKIP_BUILT_IN_PRIMITIVES_BIT_KHR = 4096; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_ALLOW_SPHERES_AND_LINEAR_SWEPT_SPHERES_BIT_NV = 8589934592; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_ENABLE_LEGACY_DITHERING_BIT_EXT = 17179869184; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISABLE_OPTIMIZATION_BIT_KHR = 1; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_ALLOW_DERIVATIVES_BIT_KHR = 2; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DERIVATIVE_BIT_KHR = 4; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = 8; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISPATCH_BASE_BIT_KHR = 16; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DEFER_COMPILE_BIT_NV = 32; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_CAPTURE_STATISTICS_BIT_KHR = 64; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR = 128; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_KHR = 256; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_EARLY_RETURN_ON_FAILURE_BIT_KHR = 512; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_LINK_TIME_OPTIMIZATION_BIT_EXT = 1024; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT = 8388608; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_LIBRARY_BIT_KHR = 2048; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR = 4096; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_SKIP_AABBS_BIT_KHR = 8192; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR = 16384; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR = 32768; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR = 65536; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR = 131072; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR = 524288; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_INDIRECT_BINDABLE_BIT_NV = 262144; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_ALLOW_MOTION_BIT_NV = 1048576; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 2097152; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 4194304; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_OPACITY_MICROMAP_BIT_EXT = 16777216; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 33554432; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 67108864; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_NO_PROTECTED_ACCESS_BIT_EXT = 134217728; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT_EXT = 1073741824; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_DISPLACEMENT_MICROMAP_BIT_NV = 268435456; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DESCRIPTOR_BUFFER_BIT_EXT = 536870912; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISALLOW_OPACITY_MICROMAP_BIT_ARM = 137438953472; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_CAPTURE_DATA_BIT_KHR = 2147483648; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_INDIRECT_BINDABLE_BIT_EXT = 274877906944; + +typedef VkPipelineCreateFlagBits2 VkPipelineCreateFlagBits2KHR; + +typedef uint64_t VkBufferUsageFlagBits2; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFER_SRC_BIT = 1; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFER_DST_BIT = 2; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_UNIFORM_TEXEL_BUFFER_BIT = 4; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_STORAGE_TEXEL_BUFFER_BIT = 8; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT = 16; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT = 32; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_INDEX_BUFFER_BIT = 64; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VERTEX_BUFFER_BIT = 128; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_INDIRECT_BUFFER_BIT = 256; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT = 131072; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_EXECUTION_GRAPH_SCRATCH_BIT_AMDX = 33554432; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFER_SRC_BIT_KHR = 1; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFER_DST_BIT_KHR = 2; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR = 4; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_STORAGE_TEXEL_BUFFER_BIT_KHR = 8; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT_KHR = 16; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR = 32; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_INDEX_BUFFER_BIT_KHR = 64; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VERTEX_BUFFER_BIT_KHR = 128; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_INDIRECT_BUFFER_BIT_KHR = 256; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_CONDITIONAL_RENDERING_BIT_EXT = 512; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_SHADER_BINDING_TABLE_BIT_KHR = 1024; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_RAY_TRACING_BIT_NV = 1024; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 2048; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 4096; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VIDEO_DECODE_SRC_BIT_KHR = 8192; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VIDEO_DECODE_DST_BIT_KHR = 16384; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VIDEO_ENCODE_DST_BIT_KHR = 32768; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VIDEO_ENCODE_SRC_BIT_KHR = 65536; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT_KHR = 131072; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR = 524288; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR = 1048576; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT = 2097152; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT = 4194304; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT = 67108864; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_MICROMAP_BUILD_INPUT_READ_ONLY_BIT_EXT = 8388608; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_MICROMAP_STORAGE_BIT_EXT = 16777216; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TILE_MEMORY_QCOM = 134217728; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_PREPROCESS_BUFFER_BIT_EXT = 2147483648; + +typedef VkBufferUsageFlagBits2 VkBufferUsageFlagBits2KHR; + +typedef enum VkPartitionedAccelerationStructureOpTypeNV { + VK_PARTITIONED_ACCELERATION_STRUCTURE_OP_TYPE_WRITE_INSTANCE_NV = 0, + VK_PARTITIONED_ACCELERATION_STRUCTURE_OP_TYPE_UPDATE_INSTANCE_NV = 1, + VK_PARTITIONED_ACCELERATION_STRUCTURE_OP_TYPE_WRITE_PARTITION_TRANSLATION_NV = 2, + VK_PARTITIONED_ACCELERATION_STRUCTURE_OP_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkPartitionedAccelerationStructureOpTypeNV; +typedef enum VkPartitionedAccelerationStructureInstanceFlagBitsNV { + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE_BIT_NV = 1, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FLIP_FACING_BIT_NV = 2, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE_BIT_NV = 4, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE_BIT_NV = 8, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_ENABLE_EXPLICIT_BOUNDING_BOX_NV = 16, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkPartitionedAccelerationStructureInstanceFlagBitsNV; +typedef enum VkAntiLagModeAMD { + VK_ANTI_LAG_MODE_DRIVER_CONTROL_AMD = 0, + VK_ANTI_LAG_MODE_ON_AMD = 1, + VK_ANTI_LAG_MODE_OFF_AMD = 2, + VK_ANTI_LAG_MODE_MAX_ENUM_AMD = 0x7FFFFFFF +} VkAntiLagModeAMD; +typedef enum VkAntiLagStageAMD { + VK_ANTI_LAG_STAGE_INPUT_AMD = 0, + VK_ANTI_LAG_STAGE_PRESENT_AMD = 1, + VK_ANTI_LAG_STAGE_MAX_ENUM_AMD = 0x7FFFFFFF +} VkAntiLagStageAMD; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef enum VkDisplacementMicromapFormatNV { + VK_DISPLACEMENT_MICROMAP_FORMAT_64_TRIANGLES_64_BYTES_NV = 1, + VK_DISPLACEMENT_MICROMAP_FORMAT_256_TRIANGLES_128_BYTES_NV = 2, + VK_DISPLACEMENT_MICROMAP_FORMAT_1024_TRIANGLES_128_BYTES_NV = 3, + VK_DISPLACEMENT_MICROMAP_FORMAT_MAX_ENUM_NV = 0x7FFFFFFF +} VkDisplacementMicromapFormatNV; +#endif + +typedef enum VkShaderCreateFlagBitsEXT { + VK_SHADER_CREATE_LINK_STAGE_BIT_EXT = 1, + VK_SHADER_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = 2, + VK_SHADER_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = 4, + VK_SHADER_CREATE_NO_TASK_SHADER_BIT_EXT = 8, + VK_SHADER_CREATE_DISPATCH_BASE_BIT_EXT = 16, + VK_SHADER_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_EXT = 32, + VK_SHADER_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 64, + VK_SHADER_CREATE_INDIRECT_BINDABLE_BIT_EXT = 128, + VK_SHADER_CREATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkShaderCreateFlagBitsEXT; +typedef enum VkShaderCodeTypeEXT { + VK_SHADER_CODE_TYPE_BINARY_EXT = 0, + VK_SHADER_CODE_TYPE_SPIRV_EXT = 1, + VK_SHADER_CODE_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkShaderCodeTypeEXT; +typedef enum VkScopeKHR { + VK_SCOPE_DEVICE_KHR = 1, + VK_SCOPE_WORKGROUP_KHR = 2, + VK_SCOPE_SUBGROUP_KHR = 3, + VK_SCOPE_QUEUE_FAMILY_KHR = 5, + VK_SCOPE_DEVICE_NV = VK_SCOPE_DEVICE_KHR, + VK_SCOPE_WORKGROUP_NV = VK_SCOPE_WORKGROUP_KHR, + VK_SCOPE_SUBGROUP_NV = VK_SCOPE_SUBGROUP_KHR, + VK_SCOPE_QUEUE_FAMILY_NV = VK_SCOPE_QUEUE_FAMILY_KHR, + VK_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkScopeKHR; +typedef enum VkComponentTypeKHR { + VK_COMPONENT_TYPE_FLOAT16_KHR = 0, + VK_COMPONENT_TYPE_FLOAT32_KHR = 1, + VK_COMPONENT_TYPE_FLOAT64_KHR = 2, + VK_COMPONENT_TYPE_SINT8_KHR = 3, + VK_COMPONENT_TYPE_SINT16_KHR = 4, + VK_COMPONENT_TYPE_SINT32_KHR = 5, + VK_COMPONENT_TYPE_SINT64_KHR = 6, + VK_COMPONENT_TYPE_UINT8_KHR = 7, + VK_COMPONENT_TYPE_UINT16_KHR = 8, + VK_COMPONENT_TYPE_UINT32_KHR = 9, + VK_COMPONENT_TYPE_UINT64_KHR = 10, + VK_COMPONENT_TYPE_BFLOAT16_KHR = 1000141000, + VK_COMPONENT_TYPE_FLOAT16_NV = VK_COMPONENT_TYPE_FLOAT16_KHR, + VK_COMPONENT_TYPE_FLOAT32_NV = VK_COMPONENT_TYPE_FLOAT32_KHR, + VK_COMPONENT_TYPE_FLOAT64_NV = VK_COMPONENT_TYPE_FLOAT64_KHR, + VK_COMPONENT_TYPE_SINT8_NV = VK_COMPONENT_TYPE_SINT8_KHR, + VK_COMPONENT_TYPE_SINT16_NV = VK_COMPONENT_TYPE_SINT16_KHR, + VK_COMPONENT_TYPE_SINT32_NV = VK_COMPONENT_TYPE_SINT32_KHR, + VK_COMPONENT_TYPE_SINT64_NV = VK_COMPONENT_TYPE_SINT64_KHR, + VK_COMPONENT_TYPE_UINT8_NV = VK_COMPONENT_TYPE_UINT8_KHR, + VK_COMPONENT_TYPE_UINT16_NV = VK_COMPONENT_TYPE_UINT16_KHR, + VK_COMPONENT_TYPE_UINT32_NV = VK_COMPONENT_TYPE_UINT32_KHR, + VK_COMPONENT_TYPE_UINT64_NV = VK_COMPONENT_TYPE_UINT64_KHR, + VK_COMPONENT_TYPE_SINT8_PACKED_NV = 1000491000, + VK_COMPONENT_TYPE_UINT8_PACKED_NV = 1000491001, + VK_COMPONENT_TYPE_FLOAT_E4M3_NV = 1000491002, + VK_COMPONENT_TYPE_FLOAT_E5M2_NV = 1000491003, + VK_COMPONENT_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkComponentTypeKHR; +typedef enum VkScopeKHR VkScopeNV; + +typedef enum VkComponentTypeKHR VkComponentTypeNV; + +typedef enum VkCubicFilterWeightsQCOM { + VK_CUBIC_FILTER_WEIGHTS_CATMULL_ROM_QCOM = 0, + VK_CUBIC_FILTER_WEIGHTS_ZERO_TANGENT_CARDINAL_QCOM = 1, + VK_CUBIC_FILTER_WEIGHTS_B_SPLINE_QCOM = 2, + VK_CUBIC_FILTER_WEIGHTS_MITCHELL_NETRAVALI_QCOM = 3, + VK_CUBIC_FILTER_WEIGHTS_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkCubicFilterWeightsQCOM; +typedef enum VkBlockMatchWindowCompareModeQCOM { + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MIN_QCOM = 0, + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MAX_QCOM = 1, + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkBlockMatchWindowCompareModeQCOM; +typedef enum VkLayeredDriverUnderlyingApiMSFT { + VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT = 0, + VK_LAYERED_DRIVER_UNDERLYING_API_D3D12_MSFT = 1, + VK_LAYERED_DRIVER_UNDERLYING_API_MAX_ENUM_MSFT = 0x7FFFFFFF +} VkLayeredDriverUnderlyingApiMSFT; +typedef enum VkPhysicalDeviceLayeredApiKHR { + VK_PHYSICAL_DEVICE_LAYERED_API_VULKAN_KHR = 0, + VK_PHYSICAL_DEVICE_LAYERED_API_D3D12_KHR = 1, + VK_PHYSICAL_DEVICE_LAYERED_API_METAL_KHR = 2, + VK_PHYSICAL_DEVICE_LAYERED_API_OPENGL_KHR = 3, + VK_PHYSICAL_DEVICE_LAYERED_API_OPENGLES_KHR = 4, + VK_PHYSICAL_DEVICE_LAYERED_API_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPhysicalDeviceLayeredApiKHR; +typedef enum VkDepthClampModeEXT { + VK_DEPTH_CLAMP_MODE_VIEWPORT_RANGE_EXT = 0, + VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT = 1, + VK_DEPTH_CLAMP_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDepthClampModeEXT; +typedef enum VkTileShadingRenderPassFlagBitsQCOM { + VK_TILE_SHADING_RENDER_PASS_ENABLE_BIT_QCOM = 1, + VK_TILE_SHADING_RENDER_PASS_PER_TILE_EXECUTION_BIT_QCOM = 2, + VK_TILE_SHADING_RENDER_PASS_FLAG_BITS_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkTileShadingRenderPassFlagBitsQCOM; +typedef enum VkCooperativeVectorMatrixLayoutNV { + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_ROW_MAJOR_NV = 0, + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_COLUMN_MAJOR_NV = 1, + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_INFERENCING_OPTIMAL_NV = 2, + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_TRAINING_OPTIMAL_NV = 3, + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_MAX_ENUM_NV = 0x7FFFFFFF +} VkCooperativeVectorMatrixLayoutNV; typedef enum VkColorSpaceKHR { VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, @@ -3053,32 +5316,33 @@ typedef enum VkColorSpaceKHR { VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014, VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT, - VK_COLOR_SPACE_DISPLAY_NATIVE_AMD = 1000213000 + VK_COLOR_SPACE_DISPLAY_NATIVE_AMD = 1000213000, + VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF } VkColorSpaceKHR; - typedef enum VkCompositeAlphaFlagBitsKHR { VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 1, VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 2, VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 4, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 8 + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 8, + VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkCompositeAlphaFlagBitsKHR; - typedef enum VkDisplayPlaneAlphaFlagBitsKHR { VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 1, VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 2, VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 4, - VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 8 + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 8, + VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkDisplayPlaneAlphaFlagBitsKHR; - typedef enum VkPresentModeKHR { VK_PRESENT_MODE_IMMEDIATE_KHR = 0, VK_PRESENT_MODE_MAILBOX_KHR = 1, VK_PRESENT_MODE_FIFO_KHR = 2, VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000, - VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001 + VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001, + VK_PRESENT_MODE_FIFO_LATEST_READY_EXT = 1000361000, + VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF } VkPresentModeKHR; - typedef enum VkSurfaceTransformFlagBitsKHR { VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 1, VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 2, @@ -3088,17 +5352,24 @@ typedef enum VkSurfaceTransformFlagBitsKHR { VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 32, VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 64, VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 128, - VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 256 + VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 256, + VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkSurfaceTransformFlagBitsKHR; - +typedef enum VkDisplaySurfaceStereoTypeNV { + VK_DISPLAY_SURFACE_STEREO_TYPE_NONE_NV = 0, + VK_DISPLAY_SURFACE_STEREO_TYPE_ONBOARD_DIN_NV = 1, + VK_DISPLAY_SURFACE_STEREO_TYPE_HDMI_3D_NV = 2, + VK_DISPLAY_SURFACE_STEREO_TYPE_INBAND_DISPLAYPORT_NV = 3, + VK_DISPLAY_SURFACE_STEREO_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkDisplaySurfaceStereoTypeNV; typedef enum VkDebugReportFlagBitsEXT { VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 1, VK_DEBUG_REPORT_WARNING_BIT_EXT = 2, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 4, VK_DEBUG_REPORT_ERROR_BIT_EXT = 8, - VK_DEBUG_REPORT_DEBUG_BIT_EXT = 16 + VK_DEBUG_REPORT_DEBUG_BIT_EXT = 16, + VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugReportFlagBitsEXT; - typedef enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, @@ -3136,43 +5407,56 @@ typedef enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000, + VK_DEBUG_REPORT_OBJECT_TYPE_CU_MODULE_NVX_EXT = 1000029000, + VK_DEBUG_REPORT_OBJECT_TYPE_CU_FUNCTION_NVX_EXT = 1000029001, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT = 1000165000, + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT = 1000150000, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, + VK_DEBUG_REPORT_OBJECT_TYPE_CUDA_MODULE_NV_EXT = 1000307000, + VK_DEBUG_REPORT_OBJECT_TYPE_CUDA_FUNCTION_NV_EXT = 1000307001, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA_EXT = 1000366000, + VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugReportObjectTypeEXT; - +typedef enum VkDeviceMemoryReportEventTypeEXT { + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT = 0, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT = 1, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_IMPORT_EXT = 2, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_UNIMPORT_EXT = 3, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT = 4, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceMemoryReportEventTypeEXT; typedef enum VkRasterizationOrderAMD { VK_RASTERIZATION_ORDER_STRICT_AMD = 0, - VK_RASTERIZATION_ORDER_RELAXED_AMD = 1 + VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, + VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF } VkRasterizationOrderAMD; - typedef enum VkExternalMemoryHandleTypeFlagBitsNV { VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 1, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 2, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 4, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 8 + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 8, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF } VkExternalMemoryHandleTypeFlagBitsNV; - typedef enum VkExternalMemoryFeatureFlagBitsNV { VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 1, VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 2, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 4 + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 4, + VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF } VkExternalMemoryFeatureFlagBitsNV; - typedef enum VkValidationCheckEXT { VK_VALIDATION_CHECK_ALL_EXT = 0, - VK_VALIDATION_CHECK_SHADERS_EXT = 1 + VK_VALIDATION_CHECK_SHADERS_EXT = 1, + VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF } VkValidationCheckEXT; - typedef enum VkValidationFeatureEnableEXT { VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT = 2, VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT = 3, - VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT = 4 + VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT = 4, + VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF } VkValidationFeatureEnableEXT; - typedef enum VkValidationFeatureDisableEXT { VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0, VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1, @@ -3180,9 +5464,10 @@ typedef enum VkValidationFeatureDisableEXT { VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3, VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, - VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6 + VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, + VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT = 7, + VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF } VkValidationFeatureDisableEXT; - typedef enum VkExternalMemoryHandleTypeFlagBits { VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 1, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 2, @@ -3201,9 +5486,15 @@ typedef enum VkExternalMemoryHandleTypeFlagBits { VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT = 512, VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID = 1024, VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT = 128, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 256 + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 256, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA = 2048, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_RDMA_ADDRESS_BIT_NV = 4096, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_SCREEN_BUFFER_BIT_QNX = 16384, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT = 65536, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT = 131072, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT = 262144, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkExternalMemoryHandleTypeFlagBits; - typedef enum VkExternalMemoryHandleTypeFlagBits VkExternalMemoryHandleTypeFlagBitsKHR; typedef enum VkExternalMemoryFeatureFlagBits { @@ -3212,9 +5503,9 @@ typedef enum VkExternalMemoryFeatureFlagBits { VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 4, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT, VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkExternalMemoryFeatureFlagBits; - typedef enum VkExternalMemoryFeatureFlagBits VkExternalMemoryFeatureFlagBitsKHR; typedef enum VkExternalSemaphoreHandleTypeFlagBits { @@ -3228,25 +5519,26 @@ typedef enum VkExternalSemaphoreHandleTypeFlagBits { VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA = 128, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkExternalSemaphoreHandleTypeFlagBits; - typedef enum VkExternalSemaphoreHandleTypeFlagBits VkExternalSemaphoreHandleTypeFlagBitsKHR; typedef enum VkExternalSemaphoreFeatureFlagBits { VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 1, VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 2, VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkExternalSemaphoreFeatureFlagBits; - typedef enum VkExternalSemaphoreFeatureFlagBits VkExternalSemaphoreFeatureFlagBitsKHR; typedef enum VkSemaphoreImportFlagBits { VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 1, - VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT + VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, + VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSemaphoreImportFlagBits; - typedef enum VkSemaphoreImportFlagBits VkSemaphoreImportFlagBitsKHR; typedef enum VkExternalFenceHandleTypeFlagBits { @@ -3257,45 +5549,46 @@ typedef enum VkExternalFenceHandleTypeFlagBits { VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT, VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT, VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkExternalFenceHandleTypeFlagBits; - typedef enum VkExternalFenceHandleTypeFlagBits VkExternalFenceHandleTypeFlagBitsKHR; typedef enum VkExternalFenceFeatureFlagBits { VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 1, VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 2, VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT + VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkExternalFenceFeatureFlagBits; - typedef enum VkExternalFenceFeatureFlagBits VkExternalFenceFeatureFlagBitsKHR; typedef enum VkFenceImportFlagBits { VK_FENCE_IMPORT_TEMPORARY_BIT = 1, - VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = VK_FENCE_IMPORT_TEMPORARY_BIT + VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = VK_FENCE_IMPORT_TEMPORARY_BIT, + VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFenceImportFlagBits; - typedef enum VkFenceImportFlagBits VkFenceImportFlagBitsKHR; typedef enum VkSurfaceCounterFlagBitsEXT { - VK_SURFACE_COUNTER_VBLANK_EXT = 1 + VK_SURFACE_COUNTER_VBLANK_BIT_EXT = 1, + VK_SURFACE_COUNTER_VBLANK_EXT = VK_SURFACE_COUNTER_VBLANK_BIT_EXT, + VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkSurfaceCounterFlagBitsEXT; - typedef enum VkDisplayPowerStateEXT { VK_DISPLAY_POWER_STATE_OFF_EXT = 0, VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1, - VK_DISPLAY_POWER_STATE_ON_EXT = 2 + VK_DISPLAY_POWER_STATE_ON_EXT = 2, + VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDisplayPowerStateEXT; - typedef enum VkDeviceEventTypeEXT { - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0 + VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0, + VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDeviceEventTypeEXT; - typedef enum VkDisplayEventTypeEXT { - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0 + VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0, + VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDisplayEventTypeEXT; - typedef enum VkPeerMemoryFeatureFlagBits { VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 1, VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 2, @@ -3304,9 +5597,9 @@ typedef enum VkPeerMemoryFeatureFlagBits { VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT, VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_DST_BIT, VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT, - VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT + VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT, + VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPeerMemoryFeatureFlagBits; - typedef enum VkPeerMemoryFeatureFlagBits VkPeerMemoryFeatureFlagBitsKHR; typedef enum VkMemoryAllocateFlagBits { @@ -3315,24 +5608,25 @@ typedef enum VkMemoryAllocateFlagBits { VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 4, VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT, VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, - VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkMemoryAllocateFlagBits; - typedef enum VkMemoryAllocateFlagBits VkMemoryAllocateFlagBitsKHR; typedef enum VkDeviceGroupPresentModeFlagBitsKHR { VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 1, VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 2, VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 4, - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 8 + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 8, + VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkDeviceGroupPresentModeFlagBitsKHR; - typedef enum VkSwapchainCreateFlagBitsKHR { VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 1, VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 2, - VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR = 4 + VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR = 4, + VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT = 8, + VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkSwapchainCreateFlagBitsKHR; - typedef enum VkSubgroupFeatureFlagBits { VK_SUBGROUP_FEATURE_BASIC_BIT = 1, VK_SUBGROUP_FEATURE_VOTE_BIT = 2, @@ -3342,16 +5636,20 @@ typedef enum VkSubgroupFeatureFlagBits { VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 32, VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 64, VK_SUBGROUP_FEATURE_QUAD_BIT = 128, - VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 256 + VK_SUBGROUP_FEATURE_ROTATE_BIT = 512, + VK_SUBGROUP_FEATURE_ROTATE_CLUSTERED_BIT = 1024, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 256, + VK_SUBGROUP_FEATURE_ROTATE_BIT_KHR = VK_SUBGROUP_FEATURE_ROTATE_BIT, + VK_SUBGROUP_FEATURE_ROTATE_CLUSTERED_BIT_KHR = VK_SUBGROUP_FEATURE_ROTATE_CLUSTERED_BIT, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSubgroupFeatureFlagBits; - typedef enum VkTessellationDomainOrigin { VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0, VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1, VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT + VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT, + VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM = 0x7FFFFFFF } VkTessellationDomainOrigin; - typedef enum VkTessellationDomainOrigin VkTessellationDomainOriginKHR; typedef enum VkSamplerYcbcrModelConversion { @@ -3364,27 +5662,27 @@ typedef enum VkSamplerYcbcrModelConversion { VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY, VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709, VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM = 0x7FFFFFFF } VkSamplerYcbcrModelConversion; - typedef enum VkSamplerYcbcrModelConversion VkSamplerYcbcrModelConversionKHR; typedef enum VkSamplerYcbcrRange { VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1, VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_FULL, - VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW + VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, + VK_SAMPLER_YCBCR_RANGE_MAX_ENUM = 0x7FFFFFFF } VkSamplerYcbcrRange; - typedef enum VkSamplerYcbcrRange VkSamplerYcbcrRangeKHR; typedef enum VkChromaLocation { VK_CHROMA_LOCATION_COSITED_EVEN = 0, VK_CHROMA_LOCATION_MIDPOINT = 1, VK_CHROMA_LOCATION_COSITED_EVEN_KHR = VK_CHROMA_LOCATION_COSITED_EVEN, - VK_CHROMA_LOCATION_MIDPOINT_KHR = VK_CHROMA_LOCATION_MIDPOINT + VK_CHROMA_LOCATION_MIDPOINT_KHR = VK_CHROMA_LOCATION_MIDPOINT, + VK_CHROMA_LOCATION_MAX_ENUM = 0x7FFFFFFF } VkChromaLocation; - typedef enum VkChromaLocation VkChromaLocationKHR; typedef enum VkSamplerReductionMode { @@ -3393,36 +5691,39 @@ typedef enum VkSamplerReductionMode { VK_SAMPLER_REDUCTION_MODE_MAX = 2, VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, VK_SAMPLER_REDUCTION_MODE_MIN_EXT = VK_SAMPLER_REDUCTION_MODE_MIN, - VK_SAMPLER_REDUCTION_MODE_MAX_EXT = VK_SAMPLER_REDUCTION_MODE_MAX + VK_SAMPLER_REDUCTION_MODE_MAX_EXT = VK_SAMPLER_REDUCTION_MODE_MAX, + VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_RANGECLAMP_QCOM = 1000521000, + VK_SAMPLER_REDUCTION_MODE_MAX_ENUM = 0x7FFFFFFF } VkSamplerReductionMode; - typedef enum VkSamplerReductionMode VkSamplerReductionModeEXT; typedef enum VkBlendOverlapEXT { VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0, VK_BLEND_OVERLAP_DISJOINT_EXT = 1, - VK_BLEND_OVERLAP_CONJOINT_EXT = 2 + VK_BLEND_OVERLAP_CONJOINT_EXT = 2, + VK_BLEND_OVERLAP_MAX_ENUM_EXT = 0x7FFFFFFF } VkBlendOverlapEXT; - typedef enum VkDebugUtilsMessageSeverityFlagBitsEXT { VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 1, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 16, VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 256, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 4096 + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 4096, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugUtilsMessageSeverityFlagBitsEXT; - typedef enum VkDebugUtilsMessageTypeFlagBitsEXT { VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 1, VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 2, - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 4 + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 4, + VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT = 8, + VK_DEBUG_UTILS_MESSAGE_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugUtilsMessageTypeFlagBitsEXT; - #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef enum VkFullScreenExclusiveEXT { VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT = 0, VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT = 1, VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT = 2, - VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT = 3 + VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT = 3, + VK_FULL_SCREEN_EXCLUSIVE_MAX_ENUM_EXT = 0x7FFFFFFF } VkFullScreenExclusiveEXT; #endif @@ -3432,19 +5733,154 @@ typedef enum VkShaderFloatControlsIndependence { VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE = 2, VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY, VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL, - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_MAX_ENUM = 0x7FFFFFFF } VkShaderFloatControlsIndependence; - typedef enum VkShaderFloatControlsIndependence VkShaderFloatControlsIndependenceKHR; +typedef enum VkFragmentShadingRateCombinerOpKHR { + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR = 0, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR = 1, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR = 2, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR = 3, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR = 4, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_ENUM_KHR = 0x7FFFFFFF +} VkFragmentShadingRateCombinerOpKHR; +typedef enum VkSubmitFlagBits { + VK_SUBMIT_PROTECTED_BIT = 1, + VK_SUBMIT_PROTECTED_BIT_KHR = VK_SUBMIT_PROTECTED_BIT, + VK_SUBMIT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubmitFlagBits; +typedef enum VkSubmitFlagBits VkSubmitFlagBitsKHR; + +typedef enum VkGraphicsPipelineLibraryFlagBitsEXT { + VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT = 1, + VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT = 2, + VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT = 4, + VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT = 8, + VK_GRAPHICS_PIPELINE_LIBRARY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkGraphicsPipelineLibraryFlagBitsEXT; +typedef enum VkOpticalFlowGridSizeFlagBitsNV { + VK_OPTICAL_FLOW_GRID_SIZE_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_GRID_SIZE_1X1_BIT_NV = 1, + VK_OPTICAL_FLOW_GRID_SIZE_2X2_BIT_NV = 2, + VK_OPTICAL_FLOW_GRID_SIZE_4X4_BIT_NV = 4, + VK_OPTICAL_FLOW_GRID_SIZE_8X8_BIT_NV = 8, + VK_OPTICAL_FLOW_GRID_SIZE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowGridSizeFlagBitsNV; +typedef enum VkOpticalFlowUsageFlagBitsNV { + VK_OPTICAL_FLOW_USAGE_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_USAGE_INPUT_BIT_NV = 1, + VK_OPTICAL_FLOW_USAGE_OUTPUT_BIT_NV = 2, + VK_OPTICAL_FLOW_USAGE_HINT_BIT_NV = 4, + VK_OPTICAL_FLOW_USAGE_COST_BIT_NV = 8, + VK_OPTICAL_FLOW_USAGE_GLOBAL_FLOW_BIT_NV = 16, + VK_OPTICAL_FLOW_USAGE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowUsageFlagBitsNV; +typedef enum VkOpticalFlowPerformanceLevelNV { + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_SLOW_NV = 1, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_MEDIUM_NV = 2, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_FAST_NV = 3, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowPerformanceLevelNV; +typedef enum VkOpticalFlowSessionBindingPointNV { + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_INPUT_NV = 1, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_REFERENCE_NV = 2, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_HINT_NV = 3, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_FLOW_VECTOR_NV = 4, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_BACKWARD_FLOW_VECTOR_NV = 5, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_COST_NV = 6, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_BACKWARD_COST_NV = 7, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_GLOBAL_FLOW_NV = 8, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowSessionBindingPointNV; +typedef enum VkOpticalFlowSessionCreateFlagBitsNV { + VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_HINT_BIT_NV = 1, + VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_COST_BIT_NV = 2, + VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_GLOBAL_FLOW_BIT_NV = 4, + VK_OPTICAL_FLOW_SESSION_CREATE_ALLOW_REGIONS_BIT_NV = 8, + VK_OPTICAL_FLOW_SESSION_CREATE_BOTH_DIRECTIONS_BIT_NV = 16, + VK_OPTICAL_FLOW_SESSION_CREATE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowSessionCreateFlagBitsNV; +typedef enum VkOpticalFlowExecuteFlagBitsNV { + VK_OPTICAL_FLOW_EXECUTE_DISABLE_TEMPORAL_HINTS_BIT_NV = 1, + VK_OPTICAL_FLOW_EXECUTE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowExecuteFlagBitsNV; +typedef enum VkDeviceFaultAddressTypeEXT { + VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT = 0, + VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT = 1, + VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT = 2, + VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT = 3, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT = 4, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT = 5, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT = 6, + VK_DEVICE_FAULT_ADDRESS_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceFaultAddressTypeEXT; +typedef enum VkPresentScalingFlagBitsEXT { + VK_PRESENT_SCALING_ONE_TO_ONE_BIT_EXT = 1, + VK_PRESENT_SCALING_ASPECT_RATIO_STRETCH_BIT_EXT = 2, + VK_PRESENT_SCALING_STRETCH_BIT_EXT = 4, + VK_PRESENT_SCALING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPresentScalingFlagBitsEXT; +typedef enum VkPresentGravityFlagBitsEXT { + VK_PRESENT_GRAVITY_MIN_BIT_EXT = 1, + VK_PRESENT_GRAVITY_MAX_BIT_EXT = 2, + VK_PRESENT_GRAVITY_CENTERED_BIT_EXT = 4, + VK_PRESENT_GRAVITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPresentGravityFlagBitsEXT; +typedef enum VkLayerSettingTypeEXT { + VK_LAYER_SETTING_TYPE_BOOL32_EXT = 0, + VK_LAYER_SETTING_TYPE_INT32_EXT = 1, + VK_LAYER_SETTING_TYPE_INT64_EXT = 2, + VK_LAYER_SETTING_TYPE_UINT32_EXT = 3, + VK_LAYER_SETTING_TYPE_UINT64_EXT = 4, + VK_LAYER_SETTING_TYPE_FLOAT32_EXT = 5, + VK_LAYER_SETTING_TYPE_FLOAT64_EXT = 6, + VK_LAYER_SETTING_TYPE_STRING_EXT = 7, + VK_LAYER_SETTING_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkLayerSettingTypeEXT; +typedef enum VkLatencyMarkerNV { + VK_LATENCY_MARKER_SIMULATION_START_NV = 0, + VK_LATENCY_MARKER_SIMULATION_END_NV = 1, + VK_LATENCY_MARKER_RENDERSUBMIT_START_NV = 2, + VK_LATENCY_MARKER_RENDERSUBMIT_END_NV = 3, + VK_LATENCY_MARKER_PRESENT_START_NV = 4, + VK_LATENCY_MARKER_PRESENT_END_NV = 5, + VK_LATENCY_MARKER_INPUT_SAMPLE_NV = 6, + VK_LATENCY_MARKER_TRIGGER_FLASH_NV = 7, + VK_LATENCY_MARKER_OUT_OF_BAND_RENDERSUBMIT_START_NV = 8, + VK_LATENCY_MARKER_OUT_OF_BAND_RENDERSUBMIT_END_NV = 9, + VK_LATENCY_MARKER_OUT_OF_BAND_PRESENT_START_NV = 10, + VK_LATENCY_MARKER_OUT_OF_BAND_PRESENT_END_NV = 11, + VK_LATENCY_MARKER_MAX_ENUM_NV = 0x7FFFFFFF +} VkLatencyMarkerNV; +typedef enum VkOutOfBandQueueTypeNV { + VK_OUT_OF_BAND_QUEUE_TYPE_RENDER_NV = 0, + VK_OUT_OF_BAND_QUEUE_TYPE_PRESENT_NV = 1, + VK_OUT_OF_BAND_QUEUE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkOutOfBandQueueTypeNV; +typedef uint64_t VkPhysicalDeviceSchedulingControlsFlagBitsARM; +static const VkPhysicalDeviceSchedulingControlsFlagBitsARM VK_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_SHADER_CORE_COUNT_ARM = 1; + +typedef enum VkMemoryUnmapFlagBits { + VK_MEMORY_UNMAP_RESERVE_BIT_EXT = 1, + VK_MEMORY_UNMAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryUnmapFlagBits; +typedef enum VkMemoryUnmapFlagBits VkMemoryUnmapFlagBitsKHR; + typedef enum VkVendorId { + VK_VENDOR_ID_KHRONOS = 0x10000, VK_VENDOR_ID_VIV = 0x10001, VK_VENDOR_ID_VSI = 0x10002, VK_VENDOR_ID_KAZAN = 0x10003, VK_VENDOR_ID_CODEPLAY = 0x10004, - VK_VENDOR_ID_MESA = 0x10005 + VK_VENDOR_ID_MESA = 0x10005, + VK_VENDOR_ID_POCL = 0x10006, + VK_VENDOR_ID_MOBILEYE = 0x10007, + VK_VENDOR_ID_MAX_ENUM = 0x7FFFFFFF } VkVendorId; - typedef enum VkDriverId { VK_DRIVER_ID_AMD_PROPRIETARY = 1, VK_DRIVER_ID_AMD_OPEN_SOURCE = 2, @@ -3460,6 +5896,19 @@ typedef enum VkDriverId { VK_DRIVER_ID_BROADCOM_PROPRIETARY = 12, VK_DRIVER_ID_MESA_LLVMPIPE = 13, VK_DRIVER_ID_MOLTENVK = 14, + VK_DRIVER_ID_COREAVI_PROPRIETARY = 15, + VK_DRIVER_ID_JUICE_PROPRIETARY = 16, + VK_DRIVER_ID_VERISILICON_PROPRIETARY = 17, + VK_DRIVER_ID_MESA_TURNIP = 18, + VK_DRIVER_ID_MESA_V3DV = 19, + VK_DRIVER_ID_MESA_PANVK = 20, + VK_DRIVER_ID_SAMSUNG_PROPRIETARY = 21, + VK_DRIVER_ID_MESA_VENUS = 22, + VK_DRIVER_ID_MESA_DOZEN = 23, + VK_DRIVER_ID_MESA_NVK = 24, + VK_DRIVER_ID_IMAGINATION_OPEN_SOURCE_MESA = 25, + VK_DRIVER_ID_MESA_HONEYKRISP = 26, + VK_DRIVER_ID_VULKAN_SC_EMULATION_ON_VULKAN = 27, VK_DRIVER_ID_AMD_PROPRIETARY_KHR = VK_DRIVER_ID_AMD_PROPRIETARY, VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = VK_DRIVER_ID_AMD_OPEN_SOURCE, VK_DRIVER_ID_MESA_RADV_KHR = VK_DRIVER_ID_MESA_RADV, @@ -3471,9 +5920,9 @@ typedef enum VkDriverId { VK_DRIVER_ID_ARM_PROPRIETARY_KHR = VK_DRIVER_ID_ARM_PROPRIETARY, VK_DRIVER_ID_GOOGLE_SWIFTSHADER_KHR = VK_DRIVER_ID_GOOGLE_SWIFTSHADER, VK_DRIVER_ID_GGP_PROPRIETARY_KHR = VK_DRIVER_ID_GGP_PROPRIETARY, - VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR = VK_DRIVER_ID_BROADCOM_PROPRIETARY + VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR = VK_DRIVER_ID_BROADCOM_PROPRIETARY, + VK_DRIVER_ID_MAX_ENUM = 0x7FFFFFFF } VkDriverId; - typedef enum VkDriverId VkDriverIdKHR; typedef enum VkShadingRatePaletteEntryNV { @@ -3488,54 +5937,53 @@ typedef enum VkShadingRatePaletteEntryNV { VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV = 8, VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV = 9, VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV = 10, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV = 11 + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV = 11, + VK_SHADING_RATE_PALETTE_ENTRY_MAX_ENUM_NV = 0x7FFFFFFF } VkShadingRatePaletteEntryNV; - typedef enum VkCoarseSampleOrderTypeNV { VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV = 0, VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV = 1, VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV = 2, - VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3 + VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3, + VK_COARSE_SAMPLE_ORDER_TYPE_MAX_ENUM_NV = 0x7FFFFFFF } VkCoarseSampleOrderTypeNV; - typedef enum VkPipelineExecutableStatisticFormatKHR { VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR = 0, VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR = 1, VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR = 2, - VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR = 3 + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR = 3, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_MAX_ENUM_KHR = 0x7FFFFFFF } VkPipelineExecutableStatisticFormatKHR; +typedef uint64_t VkAccessFlagBits3KHR; +static const VkAccessFlagBits3KHR VK_ACCESS_3_NONE_KHR = 0; typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( void* pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope); - typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)( void* pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope); - typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)( void* pUserData, void* pOriginal, size_t size, size_t alignment, VkSystemAllocationScope allocationScope); - typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)( void* pUserData, size_t size, size_t alignment, VkSystemAllocationScope allocationScope); - typedef void (VKAPI_PTR *PFN_vkFreeFunction)( void* pUserData, void* pMemory); - typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); - +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddrLUNARG)( + VkInstance instance, const char* pName); typedef struct VkBaseOutStructure { VkStructureType sType; struct VkBaseOutStructure * pNext; @@ -3596,15 +6044,15 @@ typedef struct VkComponentMapping { } VkComponentMapping; typedef struct VkExtensionProperties { - char extensionName [ VK_MAX_EXTENSION_NAME_SIZE ]; - uint32_t specVersion; + char extensionName [ VK_MAX_EXTENSION_NAME_SIZE ]; + uint32_t specVersion; } VkExtensionProperties; typedef struct VkLayerProperties { - char layerName [ VK_MAX_EXTENSION_NAME_SIZE ]; - uint32_t specVersion; - uint32_t implementationVersion; - char description [ VK_MAX_DESCRIPTION_SIZE ]; + char layerName [ VK_MAX_EXTENSION_NAME_SIZE ]; + uint32_t specVersion; + uint32_t implementationVersion; + char description [ VK_MAX_DESCRIPTION_SIZE ]; } VkLayerProperties; typedef struct VkApplicationInfo { @@ -3693,6 +6141,57 @@ typedef struct VkStencilOpState { uint32_t reference; } VkStencilOpState; +typedef struct VkPipelineCacheHeaderVersionOne { + uint32_t headerSize; + VkPipelineCacheHeaderVersion headerVersion; + uint32_t vendorID; + uint32_t deviceID; + uint8_t pipelineCacheUUID [ VK_UUID_SIZE ]; +} VkPipelineCacheHeaderVersionOne; + +typedef struct VkPipelineBinaryHandlesInfoKHR { + VkStructureType sType; + const void * pNext; + uint32_t pipelineBinaryCount; + VkPipelineBinaryKHR * pPipelineBinaries; +} VkPipelineBinaryHandlesInfoKHR; + +typedef struct VkPipelineBinaryDataKHR { + size_t dataSize; + void * pData; +} VkPipelineBinaryDataKHR; + +typedef struct VkPipelineBinaryKeyKHR { + VkStructureType sType; + void * pNext; + uint32_t keySize; + uint8_t key [ VK_MAX_PIPELINE_BINARY_KEY_SIZE_KHR ]; +} VkPipelineBinaryKeyKHR; + +typedef struct VkPipelineBinaryInfoKHR { + VkStructureType sType; + const void * pNext; + uint32_t binaryCount; + const VkPipelineBinaryKHR * pPipelineBinaries; +} VkPipelineBinaryInfoKHR; + +typedef struct VkReleaseCapturedPipelineDataInfoKHR { + VkStructureType sType; + void * pNext; + VkPipeline pipeline; +} VkReleaseCapturedPipelineDataInfoKHR; + +typedef struct VkPipelineBinaryDataInfoKHR { + VkStructureType sType; + void * pNext; + VkPipelineBinaryKHR pipelineBinary; +} VkPipelineBinaryDataInfoKHR; + +typedef struct VkPipelineCreateInfoKHR { + VkStructureType sType; + void * pNext; +} VkPipelineCreateInfoKHR; + typedef struct VkCommandBufferAllocateInfo { VkStructureType sType; const void * pNext; @@ -3743,6 +6242,17 @@ typedef struct VkDispatchIndirectCommand { uint32_t z; } VkDispatchIndirectCommand; +typedef struct VkMultiDrawInfoEXT { + uint32_t firstVertex; + uint32_t vertexCount; +} VkMultiDrawInfoEXT; + +typedef struct VkMultiDrawIndexedInfoEXT { + uint32_t firstIndex; + uint32_t indexCount; + int32_t vertexOffset; +} VkMultiDrawIndexedInfoEXT; + typedef struct VkDisplayPlanePropertiesKHR { VkDisplayKHR currentDisplay; uint32_t currentStackIndex; @@ -3758,6 +6268,12 @@ typedef struct VkDisplayModePropertiesKHR { VkDisplayModeParametersKHR parameters; } VkDisplayModePropertiesKHR; +typedef struct VkDisplaySurfaceStereoCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkDisplaySurfaceStereoTypeNV stereoType; +} VkDisplaySurfaceStereoCreateInfoNV; + typedef struct VkSurfaceFormatKHR { VkFormat format; VkColorSpaceKHR colorSpace; @@ -3790,6 +6306,14 @@ typedef struct VkValidationFeaturesEXT { const VkValidationFeatureDisableEXT * pDisabledValidationFeatures; } VkValidationFeaturesEXT; +typedef struct VkLayerSettingEXT { + const char * pLayerName; + const char * pSettingName; + VkLayerSettingTypeEXT type; + uint32_t valueCount; + const void * pValues; +} VkLayerSettingEXT; + typedef struct VkPipelineRasterizationStateRasterizationOrderAMD { VkStructureType sType; const void * pNext; @@ -3835,6 +6359,7 @@ typedef struct VkExportMemoryWin32HandleInfoNV { const SECURITY_ATTRIBUTES * pAttributes; DWORD dwAccess; } VkExportMemoryWin32HandleInfoNV; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -3849,13 +6374,16 @@ typedef struct VkWin32KeyedMutexAcquireReleaseInfoNV { const VkDeviceMemory * pReleaseSyncs; const uint64_t * pReleaseKeys; } VkWin32KeyedMutexAcquireReleaseInfoNV; + #endif -typedef struct VkDevicePrivateDataCreateInfoEXT { +typedef struct VkDevicePrivateDataCreateInfo { VkStructureType sType; const void * pNext; uint32_t privateDataSlotRequestCount; -} VkDevicePrivateDataCreateInfoEXT; +} VkDevicePrivateDataCreateInfo; + +typedef struct VkDevicePrivateDataCreateInfo VkDevicePrivateDataCreateInfoEXT; typedef struct VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV { VkStructureType sType; @@ -3871,6 +6399,51 @@ typedef struct VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV { uint32_t minIndirectCommandsBufferOffsetAlignment; } VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV; +typedef struct VkPhysicalDeviceClusterAccelerationStructurePropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t maxVerticesPerCluster; + uint32_t maxTrianglesPerCluster; + uint32_t clusterScratchByteAlignment; + uint32_t clusterByteAlignment; + uint32_t clusterTemplateByteAlignment; + uint32_t clusterBottomLevelByteAlignment; + uint32_t clusterTemplateBoundsByteAlignment; + uint32_t maxClusterGeometryIndex; +} VkPhysicalDeviceClusterAccelerationStructurePropertiesNV; + +typedef struct VkClusterAccelerationStructureGeometryIndexAndGeometryFlagsNV { + uint32_t geometryIndex :24; + uint32_t reserved :5; + uint32_t geometryFlags :3; +} VkClusterAccelerationStructureGeometryIndexAndGeometryFlagsNV; + +typedef struct VkClusterAccelerationStructureClustersBottomLevelInputNV { + VkStructureType sType; + void * pNext; + uint32_t maxTotalClusterCount; + uint32_t maxClusterCountPerAccelerationStructure; +} VkClusterAccelerationStructureClustersBottomLevelInputNV; + +typedef struct VkClusterAccelerationStructureTriangleClusterInputNV { + VkStructureType sType; + void * pNext; + VkFormat vertexFormat; + uint32_t maxGeometryIndexValue; + uint32_t maxClusterUniqueGeometryCount; + uint32_t maxClusterTriangleCount; + uint32_t maxClusterVertexCount; + uint32_t maxTotalTriangleCount; + uint32_t maxTotalVertexCount; + uint32_t minPositionTruncateBitCount; +} VkClusterAccelerationStructureTriangleClusterInputNV; + +typedef struct VkPhysicalDeviceMultiDrawPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t maxMultiDrawCount; +} VkPhysicalDeviceMultiDrawPropertiesEXT; + typedef struct VkBindShaderGroupIndirectCommandNV { uint32_t groupIndex; } VkBindShaderGroupIndirectCommandNV; @@ -3883,16 +6456,25 @@ typedef struct VkGeneratedCommandsMemoryRequirementsInfoNV { VkStructureType sType; const void * pNext; VkPipelineBindPoint pipelineBindPoint; - VkPipeline pipeline; + VkPipeline pipeline; VkIndirectCommandsLayoutNV indirectCommandsLayout; uint32_t maxSequencesCount; } VkGeneratedCommandsMemoryRequirementsInfoNV; -typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR { +typedef struct VkPipelineIndirectDeviceAddressInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; +} VkPipelineIndirectDeviceAddressInfoNV; + +typedef struct VkPhysicalDevicePushDescriptorProperties { VkStructureType sType; void * pNext; uint32_t maxPushDescriptors; -} VkPhysicalDevicePushDescriptorPropertiesKHR; +} VkPhysicalDevicePushDescriptorProperties; + +typedef struct VkPhysicalDevicePushDescriptorProperties VkPhysicalDevicePushDescriptorPropertiesKHR; typedef struct VkConformanceVersion { uint8_t major; @@ -3906,10 +6488,10 @@ typedef struct VkConformanceVersion VkConformanceVersionKHR; typedef struct VkPhysicalDeviceDriverProperties { VkStructureType sType; void * pNext; - VkDriverId driverID; - char driverName [ VK_MAX_DRIVER_NAME_SIZE ]; - char driverInfo [ VK_MAX_DRIVER_INFO_SIZE ]; - VkConformanceVersion conformanceVersion; + VkDriverId driverID; + char driverName [ VK_MAX_DRIVER_NAME_SIZE ]; + char driverInfo [ VK_MAX_DRIVER_INFO_SIZE ]; + VkConformanceVersion conformanceVersion; } VkPhysicalDeviceDriverProperties; typedef struct VkPhysicalDeviceDriverProperties VkPhysicalDeviceDriverPropertiesKHR; @@ -3936,6 +6518,7 @@ typedef struct VkImportMemoryWin32HandleInfoKHR { HANDLE handle; LPCWSTR name; } VkImportMemoryWin32HandleInfoKHR; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -3946,23 +6529,55 @@ typedef struct VkExportMemoryWin32HandleInfoKHR { DWORD dwAccess; LPCWSTR name; } VkExportMemoryWin32HandleInfoKHR; -#endif -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkMemoryWin32HandlePropertiesKHR { - VkStructureType sType; - void * pNext; - uint32_t memoryTypeBits; -} VkMemoryWin32HandlePropertiesKHR; #endif -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkMemoryGetWin32HandleInfoKHR { +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkImportMemoryZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + zx_handle_t handle; +} VkImportMemoryZirconHandleInfoFUCHSIA; + +#endif + +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkMemoryZirconHandlePropertiesFUCHSIA { + VkStructureType sType; + void * pNext; + uint32_t memoryTypeBits; +} VkMemoryZirconHandlePropertiesFUCHSIA; + +#endif + +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkMemoryGetZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetZirconHandleInfoFUCHSIA; + +#endif + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkMemoryWin32HandlePropertiesKHR { + VkStructureType sType; + void * pNext; + uint32_t memoryTypeBits; +} VkMemoryWin32HandlePropertiesKHR; + +#endif + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkMemoryGetWin32HandleInfoKHR { VkStructureType sType; const void * pNext; VkDeviceMemory memory; VkExternalMemoryHandleTypeFlagBits handleType; } VkMemoryGetWin32HandleInfoKHR; + #endif typedef struct VkImportMemoryFdInfoKHR { @@ -3997,6 +6612,36 @@ typedef struct VkWin32KeyedMutexAcquireReleaseInfoKHR { const VkDeviceMemory * pReleaseSyncs; const uint64_t * pReleaseKeys; } VkWin32KeyedMutexAcquireReleaseInfoKHR; + +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkImportMemoryMetalHandleInfoEXT { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + void * handle; +} VkImportMemoryMetalHandleInfoEXT; + +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkMemoryMetalHandlePropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t memoryTypeBits; +} VkMemoryMetalHandlePropertiesEXT; + +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkMemoryGetMetalHandleInfoEXT { + VkStructureType sType; + const void * pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetMetalHandleInfoEXT; + #endif typedef struct VkPhysicalDeviceExternalSemaphoreInfo { @@ -4015,6 +6660,7 @@ typedef struct VkExportSemaphoreWin32HandleInfoKHR { DWORD dwAccess; LPCWSTR name; } VkExportSemaphoreWin32HandleInfoKHR; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -4026,6 +6672,7 @@ typedef struct VkD3D12FenceSubmitInfoKHR { uint32_t signalSemaphoreValuesCount; const uint64_t * pSignalSemaphoreValues; } VkD3D12FenceSubmitInfoKHR; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -4035,6 +6682,7 @@ typedef struct VkSemaphoreGetWin32HandleInfoKHR { VkSemaphore semaphore; VkExternalSemaphoreHandleTypeFlagBits handleType; } VkSemaphoreGetWin32HandleInfoKHR; + #endif typedef struct VkSemaphoreGetFdInfoKHR { @@ -4044,6 +6692,16 @@ typedef struct VkSemaphoreGetFdInfoKHR { VkExternalSemaphoreHandleTypeFlagBits handleType; } VkSemaphoreGetFdInfoKHR; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkSemaphoreGetZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkSemaphore semaphore; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkSemaphoreGetZirconHandleInfoFUCHSIA; + +#endif + typedef struct VkPhysicalDeviceExternalFenceInfo { VkStructureType sType; const void * pNext; @@ -4060,6 +6718,7 @@ typedef struct VkExportFenceWin32HandleInfoKHR { DWORD dwAccess; LPCWSTR name; } VkExportFenceWin32HandleInfoKHR; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -4069,6 +6728,7 @@ typedef struct VkFenceGetWin32HandleInfoKHR { VkFence fence; VkExternalFenceHandleTypeFlagBits handleType; } VkFenceGetWin32HandleInfoKHR; + #endif typedef struct VkFenceGetFdInfoKHR { @@ -4234,6 +6894,13 @@ typedef struct VkXYColorEXT { float y; } VkXYColorEXT; +typedef struct VkPresentIdKHR { + VkStructureType sType; + const void * pNext; + uint32_t swapchainCount; + const uint64_t * pPresentIds; +} VkPresentIdKHR; + typedef struct VkHdrMetadataEXT { VkStructureType sType; const void * pNext; @@ -4247,6 +6914,13 @@ typedef struct VkHdrMetadataEXT { float maxFrameAverageLightLevel; } VkHdrMetadataEXT; +typedef struct VkHdrVividDynamicMetadataHUAWEI { + VkStructureType sType; + const void * pNext; + size_t dynamicMetadataSize; + const void * pDynamicMetadata; +} VkHdrVividDynamicMetadataHUAWEI; + typedef struct VkRefreshCycleDurationGOOGLE { uint64_t refreshDuration; } VkRefreshCycleDurationGOOGLE; @@ -4340,7 +7014,7 @@ typedef struct VkImageSparseMemoryRequirementsInfo2 VkImageSparseMemoryRequirem typedef struct VkPhysicalDevicePointClippingProperties { VkStructureType sType; void * pNext; - VkPointClippingBehavior pointClippingBehavior; + VkPointClippingBehavior pointClippingBehavior; } VkPhysicalDevicePointClippingProperties; typedef struct VkPhysicalDevicePointClippingProperties VkPhysicalDevicePointClippingPropertiesKHR; @@ -4354,6 +7028,13 @@ typedef struct VkMemoryDedicatedAllocateInfo { typedef struct VkMemoryDedicatedAllocateInfo VkMemoryDedicatedAllocateInfoKHR; +typedef struct VkImageViewSlicedCreateInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t sliceOffset; + uint32_t sliceCount; +} VkImageViewSlicedCreateInfoEXT; + typedef struct VkPipelineTessellationDomainOriginStateCreateInfo { VkStructureType sType; const void * pNext; @@ -4441,7 +7122,7 @@ typedef struct VkSamplerReductionModeCreateInfo { typedef struct VkSamplerReductionModeCreateInfo VkSamplerReductionModeCreateInfoEXT; -typedef struct VkPhysicalDeviceInlineUniformBlockPropertiesEXT { +typedef struct VkPhysicalDeviceInlineUniformBlockProperties { VkStructureType sType; void * pNext; uint32_t maxInlineUniformBlockSize; @@ -4449,20 +7130,26 @@ typedef struct VkPhysicalDeviceInlineUniformBlockPropertiesEXT { uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; uint32_t maxDescriptorSetInlineUniformBlocks; uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; -} VkPhysicalDeviceInlineUniformBlockPropertiesEXT; +} VkPhysicalDeviceInlineUniformBlockProperties; + +typedef struct VkPhysicalDeviceInlineUniformBlockProperties VkPhysicalDeviceInlineUniformBlockPropertiesEXT; -typedef struct VkWriteDescriptorSetInlineUniformBlockEXT { +typedef struct VkWriteDescriptorSetInlineUniformBlock { VkStructureType sType; - const void * pNext; - uint32_t dataSize; - const void * pData; -} VkWriteDescriptorSetInlineUniformBlockEXT; + const void * pNext; + uint32_t dataSize; + const void * pData; +} VkWriteDescriptorSetInlineUniformBlock; -typedef struct VkDescriptorPoolInlineUniformBlockCreateInfoEXT { +typedef struct VkWriteDescriptorSetInlineUniformBlock VkWriteDescriptorSetInlineUniformBlockEXT; + +typedef struct VkDescriptorPoolInlineUniformBlockCreateInfo { VkStructureType sType; - const void * pNext; - uint32_t maxInlineUniformBlockBindings; -} VkDescriptorPoolInlineUniformBlockCreateInfoEXT; + const void * pNext; + uint32_t maxInlineUniformBlockBindings; +} VkDescriptorPoolInlineUniformBlockCreateInfo; + +typedef struct VkDescriptorPoolInlineUniformBlockCreateInfo VkDescriptorPoolInlineUniformBlockCreateInfoEXT; typedef struct VkImageFormatListCreateInfo { VkStructureType sType; @@ -4479,6 +7166,27 @@ typedef struct VkShaderModuleValidationCacheCreateInfoEXT { VkValidationCacheEXT validationCache; } VkShaderModuleValidationCacheCreateInfoEXT; +typedef struct VkPhysicalDeviceLayeredApiPropertiesKHR { + VkStructureType sType; + void * pNext; + uint32_t vendorID; + uint32_t deviceID; + VkPhysicalDeviceLayeredApiKHR layeredAPI; + char deviceName [ VK_MAX_PHYSICAL_DEVICE_NAME_SIZE ]; +} VkPhysicalDeviceLayeredApiPropertiesKHR; + +typedef struct VkRenderingAreaInfo { + VkStructureType sType; + const void * pNext; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat * pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; +} VkRenderingAreaInfo; + +typedef struct VkRenderingAreaInfo VkRenderingAreaInfoKHR; + typedef struct VkShaderResourceUsageAMD { uint32_t numUsedVgprs; uint32_t numUsedSgprs; @@ -4487,17 +7195,32 @@ typedef struct VkShaderResourceUsageAMD { size_t scratchMemUsageInBytes; } VkShaderResourceUsageAMD; -typedef struct VkDeviceQueueGlobalPriorityCreateInfoEXT { +typedef struct VkDeviceQueueGlobalPriorityCreateInfo { VkStructureType sType; - const void * pNext; - VkQueueGlobalPriorityEXT globalPriority; -} VkDeviceQueueGlobalPriorityCreateInfoEXT; + const void * pNext; + VkQueueGlobalPriority globalPriority; +} VkDeviceQueueGlobalPriorityCreateInfo; + +typedef struct VkDeviceQueueGlobalPriorityCreateInfo VkDeviceQueueGlobalPriorityCreateInfoKHR; + +typedef struct VkDeviceQueueGlobalPriorityCreateInfo VkDeviceQueueGlobalPriorityCreateInfoEXT; + +typedef struct VkQueueFamilyGlobalPriorityProperties { + VkStructureType sType; + void * pNext; + uint32_t priorityCount; + VkQueueGlobalPriority priorities [ VK_MAX_GLOBAL_PRIORITY_SIZE ]; +} VkQueueFamilyGlobalPriorityProperties; + +typedef struct VkQueueFamilyGlobalPriorityProperties VkQueueFamilyGlobalPriorityPropertiesKHR; + +typedef struct VkQueueFamilyGlobalPriorityProperties VkQueueFamilyGlobalPriorityPropertiesEXT; typedef struct VkDebugUtilsObjectNameInfoEXT { VkStructureType sType; const void * pNext; VkObjectType objectType; - uint64_t objectHandle; + uint64_t objectHandle; const char * pObjectName; } VkDebugUtilsObjectNameInfoEXT; @@ -4531,11 +7254,13 @@ typedef struct VkMemoryHostPointerPropertiesEXT { uint32_t memoryTypeBits; } VkMemoryHostPointerPropertiesEXT; -typedef struct VkCalibratedTimestampInfoEXT { +typedef struct VkCalibratedTimestampInfoKHR { VkStructureType sType; const void * pNext; - VkTimeDomainEXT timeDomain; -} VkCalibratedTimestampInfoEXT; + VkTimeDomainKHR timeDomain; +} VkCalibratedTimestampInfoKHR; + +typedef struct VkCalibratedTimestampInfoKHR VkCalibratedTimestampInfoEXT; typedef struct VkPhysicalDeviceShaderCorePropertiesAMD { VkStructureType sType; @@ -4545,15 +7270,15 @@ typedef struct VkPhysicalDeviceShaderCorePropertiesAMD { uint32_t computeUnitsPerShaderArray; uint32_t simdPerComputeUnit; uint32_t wavefrontsPerSimd; - uint32_t wavefrontSize; + uint32_t wavefrontSize; uint32_t sgprsPerSimd; - uint32_t minSgprAllocation; - uint32_t maxSgprAllocation; - uint32_t sgprAllocationGranularity; + uint32_t minSgprAllocation; + uint32_t maxSgprAllocation; + uint32_t sgprAllocationGranularity; uint32_t vgprsPerSimd; - uint32_t minVgprAllocation; - uint32_t maxVgprAllocation; - uint32_t vgprAllocationGranularity; + uint32_t minVgprAllocation; + uint32_t maxVgprAllocation; + uint32_t vgprAllocationGranularity; } VkPhysicalDeviceShaderCorePropertiesAMD; typedef struct VkDescriptorSetVariableDescriptorCountAllocateInfo { @@ -4625,17 +7350,25 @@ typedef struct VkSemaphoreSignalInfo { typedef struct VkSemaphoreSignalInfo VkSemaphoreSignalInfoKHR; -typedef struct VkVertexInputBindingDivisorDescriptionEXT { +typedef struct VkVertexInputBindingDivisorDescription { uint32_t binding; uint32_t divisor; -} VkVertexInputBindingDivisorDescriptionEXT; +} VkVertexInputBindingDivisorDescription; + +typedef struct VkVertexInputBindingDivisorDescription VkVertexInputBindingDivisorDescriptionKHR; + +typedef struct VkVertexInputBindingDivisorDescription VkVertexInputBindingDivisorDescriptionEXT; -typedef struct VkPipelineVertexInputDivisorStateCreateInfoEXT { +typedef struct VkPipelineVertexInputDivisorStateCreateInfo { VkStructureType sType; const void * pNext; uint32_t vertexBindingDivisorCount; - const VkVertexInputBindingDivisorDescriptionEXT * pVertexBindingDivisors; -} VkPipelineVertexInputDivisorStateCreateInfoEXT; + const VkVertexInputBindingDivisorDescription * pVertexBindingDivisors; +} VkPipelineVertexInputDivisorStateCreateInfo; + +typedef struct VkPipelineVertexInputDivisorStateCreateInfo VkPipelineVertexInputDivisorStateCreateInfoKHR; + +typedef struct VkPipelineVertexInputDivisorStateCreateInfo VkPipelineVertexInputDivisorStateCreateInfoEXT; typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT { VkStructureType sType; @@ -4658,6 +7391,7 @@ typedef struct VkImportAndroidHardwareBufferInfoANDROID { const void * pNext; struct AHardwareBuffer * buffer; } VkImportAndroidHardwareBufferInfoANDROID; + #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) @@ -4666,6 +7400,7 @@ typedef struct VkAndroidHardwareBufferUsageANDROID { void * pNext; uint64_t androidHardwareBufferUsage; } VkAndroidHardwareBufferUsageANDROID; + #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) @@ -4674,6 +7409,7 @@ typedef struct VkMemoryGetAndroidHardwareBufferInfoANDROID { const void * pNext; VkDeviceMemory memory; } VkMemoryGetAndroidHardwareBufferInfoANDROID; + #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) @@ -4682,6 +7418,7 @@ typedef struct VkExternalFormatANDROID { void * pNext; uint64_t externalFormat; } VkExternalFormatANDROID; + #endif typedef struct VkCheckpointDataNV { @@ -4712,7 +7449,7 @@ typedef struct VkShadingRatePaletteNV { typedef struct VkPhysicalDeviceShadingRateImagePropertiesNV { VkStructureType sType; void * pNext; - VkExtent2D shadingRateTexelSize; + VkExtent2D shadingRateTexelSize; uint32_t shadingRatePaletteSize; uint32_t shadingRateMaxCoarseSamples; } VkPhysicalDeviceShadingRateImagePropertiesNV; @@ -4752,8 +7489,8 @@ typedef struct VkPhysicalDeviceMeshShaderPropertiesNV { uint32_t maxMeshOutputVertices; uint32_t maxMeshOutputPrimitives; uint32_t maxMeshMultiviewViewCount; - uint32_t meshOutputPerVertexGranularity; - uint32_t meshOutputPerPrimitiveGranularity; + uint32_t meshOutputPerVertexGranularity; + uint32_t meshOutputPerPrimitiveGranularity; } VkPhysicalDeviceMeshShaderPropertiesNV; typedef struct VkDrawMeshTasksIndirectCommandNV { @@ -4761,6 +7498,12 @@ typedef struct VkDrawMeshTasksIndirectCommandNV { uint32_t firstTask; } VkDrawMeshTasksIndirectCommandNV; +typedef struct VkDrawMeshTasksIndirectCommandEXT { + uint32_t groupCountX; + uint32_t groupCountY; + uint32_t groupCountZ; +} VkDrawMeshTasksIndirectCommandEXT; + typedef struct VkRayTracingShaderGroupCreateInfoNV { VkStructureType sType; const void * pNext; @@ -4771,7 +7514,6 @@ typedef struct VkRayTracingShaderGroupCreateInfoNV { uint32_t intersectionShader; } VkRayTracingShaderGroupCreateInfoNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef struct VkRayTracingShaderGroupCreateInfoKHR { VkStructureType sType; const void * pNext; @@ -4782,7 +7524,6 @@ typedef struct VkRayTracingShaderGroupCreateInfoKHR { uint32_t intersectionShader; const void * pShaderGroupCaptureReplayHandle; } VkRayTracingShaderGroupCreateInfoKHR; -#endif typedef struct VkWriteDescriptorSetAccelerationStructureKHR { VkStructureType sType; @@ -4791,17 +7532,12 @@ typedef struct VkWriteDescriptorSetAccelerationStructureKHR { const VkAccelerationStructureKHR * pAccelerationStructures; } VkWriteDescriptorSetAccelerationStructureKHR; -typedef struct VkWriteDescriptorSetAccelerationStructureKHR VkWriteDescriptorSetAccelerationStructureNV; - -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureMemoryRequirementsInfoKHR { +typedef struct VkWriteDescriptorSetAccelerationStructureNV { VkStructureType sType; - const void * pNext; - VkAccelerationStructureMemoryRequirementsTypeKHR type; - VkAccelerationStructureBuildTypeKHR buildType; - VkAccelerationStructureKHR accelerationStructure; -} VkAccelerationStructureMemoryRequirementsInfoKHR; -#endif + const void * pNext; + uint32_t accelerationStructureCount; + const VkAccelerationStructureNV * pAccelerationStructures; +} VkWriteDescriptorSetAccelerationStructureNV; typedef struct VkAccelerationStructureMemoryRequirementsInfoNV { VkStructureType sType; @@ -4810,42 +7546,50 @@ typedef struct VkAccelerationStructureMemoryRequirementsInfoNV { VkAccelerationStructureNV accelerationStructure; } VkAccelerationStructureMemoryRequirementsInfoNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkPhysicalDeviceRayTracingPropertiesKHR { +typedef struct VkPhysicalDeviceAccelerationStructurePropertiesKHR { VkStructureType sType; - void * pNext; - uint32_t shaderGroupHandleSize; - uint32_t maxRecursionDepth; - uint32_t maxShaderGroupStride; - uint32_t shaderGroupBaseAlignment; + void * pNext; uint64_t maxGeometryCount; uint64_t maxInstanceCount; uint64_t maxPrimitiveCount; + uint32_t maxPerStageDescriptorAccelerationStructures; + uint32_t maxPerStageDescriptorUpdateAfterBindAccelerationStructures; uint32_t maxDescriptorSetAccelerationStructures; - uint32_t shaderGroupHandleCaptureReplaySize; -} VkPhysicalDeviceRayTracingPropertiesKHR; -#endif + uint32_t maxDescriptorSetUpdateAfterBindAccelerationStructures; + uint32_t minAccelerationStructureScratchOffsetAlignment; +} VkPhysicalDeviceAccelerationStructurePropertiesKHR; + +typedef struct VkPhysicalDeviceRayTracingPipelinePropertiesKHR { + VkStructureType sType; + void * pNext; + uint32_t shaderGroupHandleSize; + uint32_t maxRayRecursionDepth; + uint32_t maxShaderGroupStride; + uint32_t shaderGroupBaseAlignment; + uint32_t shaderGroupHandleCaptureReplaySize; + uint32_t maxRayDispatchInvocationCount; + uint32_t shaderGroupHandleAlignment; + uint32_t maxRayHitAttributeSize; +} VkPhysicalDeviceRayTracingPipelinePropertiesKHR; typedef struct VkPhysicalDeviceRayTracingPropertiesNV { VkStructureType sType; void * pNext; - uint32_t shaderGroupHandleSize; + uint32_t shaderGroupHandleSize; uint32_t maxRecursionDepth; uint32_t maxShaderGroupStride; - uint32_t shaderGroupBaseAlignment; + uint32_t shaderGroupBaseAlignment; uint64_t maxGeometryCount; uint64_t maxInstanceCount; uint64_t maxTriangleCount; uint32_t maxDescriptorSetAccelerationStructures; } VkPhysicalDeviceRayTracingPropertiesNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef struct VkTraceRaysIndirectCommandKHR { uint32_t width; uint32_t height; uint32_t depth; } VkTraceRaysIndirectCommandKHR; -#endif typedef struct VkPhysicalDeviceImageDrmFormatModifierInfoEXT { VkStructureType sType; @@ -4875,12 +7619,29 @@ typedef struct VkDeviceMemoryOverallocationCreateInfoAMD { VkMemoryOverallocationBehaviorAMD overallocationBehavior; } VkDeviceMemoryOverallocationCreateInfoAMD; +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT { + VkStructureType sType; + void * pNext; + VkExtent2D fragmentDensityOffsetGranularity; +} VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM; + typedef struct VkRenderPassFragmentDensityMapCreateInfoEXT { VkStructureType sType; const void * pNext; VkAttachmentReference fragmentDensityMapAttachment; } VkRenderPassFragmentDensityMapCreateInfoEXT; +typedef struct VkRenderPassFragmentDensityMapOffsetEndInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t fragmentDensityOffsetCount; + const VkOffset2D * pFragmentDensityOffsets; +} VkRenderPassFragmentDensityMapOffsetEndInfoEXT; + +typedef struct VkRenderPassFragmentDensityMapOffsetEndInfoEXT VkSubpassFragmentDensityMapOffsetEndInfoQCOM; + typedef struct VkMemoryPriorityAllocateInfoEXT { VkStructureType sType; const void * pNext; @@ -4947,6 +7708,7 @@ typedef struct VkPresentFrameTokenGGP { const void * pNext; GgpFrameToken frameToken; } VkPresentFrameTokenGGP; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -4955,6 +7717,7 @@ typedef struct VkSurfaceFullScreenExclusiveInfoEXT { void * pNext; VkFullScreenExclusiveEXT fullScreenExclusive; } VkSurfaceFullScreenExclusiveInfoEXT; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -4963,11 +7726,12 @@ typedef struct VkSurfaceFullScreenExclusiveWin32InfoEXT { const void * pNext; HMONITOR hmonitor; } VkSurfaceFullScreenExclusiveWin32InfoEXT; + #endif typedef struct VkPerformanceCounterKHR { VkStructureType sType; - const void * pNext; + void * pNext; VkPerformanceCounterUnitKHR unit; VkPerformanceCounterScopeKHR scope; VkPerformanceCounterStorageKHR storage; @@ -5037,7 +7801,7 @@ typedef struct VkPhysicalDeviceShaderSMBuiltinsPropertiesNV { } VkPhysicalDeviceShaderSMBuiltinsPropertiesNV; typedef struct VkAttachmentReferenceStencilLayout { - VkStructureType sType; + VkStructureType sType; void * pNext; VkImageLayout stencilLayout; } VkAttachmentReferenceStencilLayout; @@ -5045,7 +7809,7 @@ typedef struct VkAttachmentReferenceStencilLayout { typedef struct VkAttachmentReferenceStencilLayout VkAttachmentReferenceStencilLayoutKHR; typedef struct VkAttachmentDescriptionStencilLayout { - VkStructureType sType; + VkStructureType sType; void * pNext; VkImageLayout stencilInitialLayout; VkImageLayout stencilFinalLayout; @@ -5059,6 +7823,8 @@ typedef struct VkPipelineInfoKHR { VkPipeline pipeline; } VkPipelineInfoKHR; +typedef struct VkPipelineInfoKHR VkPipelineInfoEXT; + typedef struct VkPipelineExecutableInfoKHR { VkStructureType sType; const void * pNext; @@ -5066,11 +7832,28 @@ typedef struct VkPipelineExecutableInfoKHR { uint32_t executableIndex; } VkPipelineExecutableInfoKHR; -typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT { +typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfo { VkStructureType sType; - void * pNext; + void * pNext; uint32_t requiredSubgroupSize; -} VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT; +} VkPipelineShaderStageRequiredSubgroupSizeCreateInfo; + +typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfo VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT; + +typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfo VkShaderRequiredSubgroupSizeCreateInfoEXT; + +typedef struct VkSubpassShadingPipelineCreateInfoHUAWEI { + VkStructureType sType; + void * pNext; + VkRenderPass renderPass; + uint32_t subpass; +} VkSubpassShadingPipelineCreateInfoHUAWEI; + +typedef struct VkPhysicalDeviceSubpassShadingPropertiesHUAWEI { + VkStructureType sType; + void * pNext; + uint32_t maxSubpassShadingWorkgroupSizeAspectRatio; +} VkPhysicalDeviceSubpassShadingPropertiesHUAWEI; typedef struct VkMemoryOpaqueCaptureAddressAllocateInfo { VkStructureType sType; @@ -5088,11 +7871,15 @@ typedef struct VkDeviceMemoryOpaqueCaptureAddressInfo { typedef struct VkDeviceMemoryOpaqueCaptureAddressInfo VkDeviceMemoryOpaqueCaptureAddressInfoKHR; -typedef struct VkPhysicalDeviceLineRasterizationPropertiesEXT { +typedef struct VkPhysicalDeviceLineRasterizationProperties { VkStructureType sType; void * pNext; uint32_t lineSubPixelPrecisionBits; -} VkPhysicalDeviceLineRasterizationPropertiesEXT; +} VkPhysicalDeviceLineRasterizationProperties; + +typedef struct VkPhysicalDeviceLineRasterizationProperties VkPhysicalDeviceLineRasterizationPropertiesKHR; + +typedef struct VkPhysicalDeviceLineRasterizationProperties VkPhysicalDeviceLineRasterizationPropertiesEXT; typedef struct VkSamplerCustomBorderColorCreateInfoEXT { VkStructureType sType; @@ -5107,14 +7894,12 @@ typedef struct VkPhysicalDeviceCustomBorderColorPropertiesEXT { uint32_t maxCustomBorderColorSamplers; } VkPhysicalDeviceCustomBorderColorPropertiesEXT; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureBuildOffsetInfoKHR { +typedef struct VkAccelerationStructureBuildRangeInfoKHR { uint32_t primitiveCount; uint32_t primitiveOffset; - uint32_t firstVertex; - uint32_t transformOffset; -} VkAccelerationStructureBuildOffsetInfoKHR; -#endif + uint32_t firstVertex; + uint32_t transformOffset; +} VkAccelerationStructureBuildRangeInfoKHR; typedef struct VkAabbPositionsKHR { float minX; @@ -5133,23 +7918,18 @@ typedef struct VkTransformMatrixKHR { typedef struct VkTransformMatrixKHR VkTransformMatrixNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef struct VkAccelerationStructureDeviceAddressInfoKHR { VkStructureType sType; const void * pNext; VkAccelerationStructureKHR accelerationStructure; } VkAccelerationStructureDeviceAddressInfoKHR; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureVersionKHR { +typedef struct VkAccelerationStructureVersionInfoKHR { VkStructureType sType; const void * pNext; - const uint8_t * versionData; -} VkAccelerationStructureVersionKHR; -#endif + const uint8_t * pVersionData; +} VkAccelerationStructureVersionInfoKHR; -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef struct VkCopyAccelerationStructureInfoKHR { VkStructureType sType; const void * pNext; @@ -5157,34 +7937,29 @@ typedef struct VkCopyAccelerationStructureInfoKHR { VkAccelerationStructureKHR dst; VkCopyAccelerationStructureModeKHR mode; } VkCopyAccelerationStructureInfoKHR; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef struct VkRayTracingPipelineInterfaceCreateInfoKHR { VkStructureType sType; - const void * pNext; - uint32_t maxPayloadSize; - uint32_t maxAttributeSize; - uint32_t maxCallableSize; + const void * pNext; + uint32_t maxPipelineRayPayloadSize; + uint32_t maxPipelineRayHitAttributeSize; } VkRayTracingPipelineInterfaceCreateInfoKHR; -#endif - -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkDeferredOperationInfoKHR { - VkStructureType sType; - const void * pNext; - VkDeferredOperationKHR operationHandle; -} VkDeferredOperationInfoKHR; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) || defined(VK_ENABLE_BETA_EXTENSIONS) typedef struct VkPipelineLibraryCreateInfoKHR { VkStructureType sType; const void * pNext; uint32_t libraryCount; const VkPipeline * pLibraries; } VkPipelineLibraryCreateInfoKHR; -#endif + +typedef struct VkColorBlendEquationEXT { + VkBlendFactor srcColorBlendFactor; + VkBlendFactor dstColorBlendFactor; + VkBlendOp colorBlendOp; + VkBlendFactor srcAlphaBlendFactor; + VkBlendFactor dstAlphaBlendFactor; + VkBlendOp alphaBlendOp; +} VkColorBlendEquationEXT; typedef struct VkRenderPassTransformBeginInfoQCOM { VkStructureType sType; @@ -5192,6 +7967,12 @@ typedef struct VkRenderPassTransformBeginInfoQCOM { VkSurfaceTransformFlagBitsKHR transform; } VkRenderPassTransformBeginInfoQCOM; +typedef struct VkCopyCommandTransformInfoQCOM { + VkStructureType sType; + const void * pNext; + VkSurfaceTransformFlagBitsKHR transform; +} VkCopyCommandTransformInfoQCOM; + typedef struct VkCommandBufferInheritanceRenderPassTransformInfoQCOM { VkStructureType sType; void * pNext; @@ -5199,914 +7980,2037 @@ typedef struct VkCommandBufferInheritanceRenderPassTransformInfoQCOM { VkRect2D renderArea; } VkCommandBufferInheritanceRenderPassTransformInfoQCOM; -typedef uint32_t VkSampleMask; +typedef struct VkPhysicalDevicePartitionedAccelerationStructurePropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t maxPartitionCount; +} VkPhysicalDevicePartitionedAccelerationStructurePropertiesNV; -typedef uint32_t VkBool32; +typedef struct VkPartitionedAccelerationStructureWritePartitionTranslationDataNV { + uint32_t partitionIndex; + float partitionTranslation [3]; +} VkPartitionedAccelerationStructureWritePartitionTranslationDataNV; -typedef uint32_t VkFlags; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDevicePortabilitySubsetPropertiesKHR { + VkStructureType sType; + void * pNext; + uint32_t minVertexInputBindingStrideAlignment; +} VkPhysicalDevicePortabilitySubsetPropertiesKHR; -typedef uint64_t VkDeviceSize; +#endif -typedef uint64_t VkDeviceAddress; +typedef struct VkPipelineFragmentShadingRateStateCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkExtent2D fragmentSize; + VkFragmentShadingRateCombinerOpKHR combinerOps [2]; +} VkPipelineFragmentShadingRateStateCreateInfoKHR; -typedef VkFlags VkFramebufferCreateFlags; +typedef struct VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV { + VkStructureType sType; + void * pNext; + VkSampleCountFlagBits maxFragmentShadingRateInvocationCount; +} VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV; -typedef VkFlags VkQueryPoolCreateFlags; +typedef struct VkPipelineFragmentShadingRateEnumStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkFragmentShadingRateTypeNV shadingRateType; + VkFragmentShadingRateNV shadingRate; + VkFragmentShadingRateCombinerOpKHR combinerOps [2]; +} VkPipelineFragmentShadingRateEnumStateCreateInfoNV; -typedef VkFlags VkRenderPassCreateFlags; +typedef struct VkMutableDescriptorTypeListEXT { + uint32_t descriptorTypeCount; + const VkDescriptorType * pDescriptorTypes; +} VkMutableDescriptorTypeListEXT; -typedef VkFlags VkSamplerCreateFlags; +typedef struct VkMutableDescriptorTypeListEXT VkMutableDescriptorTypeListVALVE; -typedef VkFlags VkPipelineLayoutCreateFlags; +typedef struct VkMutableDescriptorTypeCreateInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t mutableDescriptorTypeListCount; + const VkMutableDescriptorTypeListEXT * pMutableDescriptorTypeLists; +} VkMutableDescriptorTypeCreateInfoEXT; -typedef VkFlags VkPipelineCacheCreateFlags; +typedef struct VkMutableDescriptorTypeCreateInfoEXT VkMutableDescriptorTypeCreateInfoVALVE; -typedef VkFlags VkPipelineDepthStencilStateCreateFlags; +typedef struct VkGeneratedCommandsPipelineInfoEXT { + VkStructureType sType; + void * pNext; + VkPipeline pipeline; +} VkGeneratedCommandsPipelineInfoEXT; -typedef VkFlags VkPipelineDynamicStateCreateFlags; +typedef struct VkGeneratedCommandsShaderInfoEXT { + VkStructureType sType; + void * pNext; + uint32_t shaderCount; + const VkShaderEXT * pShaders; +} VkGeneratedCommandsShaderInfoEXT; -typedef VkFlags VkPipelineColorBlendStateCreateFlags; +typedef struct VkGeneratedCommandsMemoryRequirementsInfoEXT { + VkStructureType sType; + const void * pNext; + VkIndirectExecutionSetEXT indirectExecutionSet; + VkIndirectCommandsLayoutEXT indirectCommandsLayout; + uint32_t maxSequenceCount; + uint32_t maxDrawCount; +} VkGeneratedCommandsMemoryRequirementsInfoEXT; -typedef VkFlags VkPipelineMultisampleStateCreateFlags; +typedef struct VkIndirectExecutionSetPipelineInfoEXT { + VkStructureType sType; + const void * pNext; + VkPipeline initialPipeline; + uint32_t maxPipelineCount; +} VkIndirectExecutionSetPipelineInfoEXT; -typedef VkFlags VkPipelineRasterizationStateCreateFlags; +typedef struct VkIndirectExecutionSetShaderLayoutInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t setLayoutCount; + const VkDescriptorSetLayout * pSetLayouts; +} VkIndirectExecutionSetShaderLayoutInfoEXT; -typedef VkFlags VkPipelineViewportStateCreateFlags; +typedef struct VkWriteIndirectExecutionSetPipelineEXT { + VkStructureType sType; + const void * pNext; + uint32_t index; + VkPipeline pipeline; +} VkWriteIndirectExecutionSetPipelineEXT; -typedef VkFlags VkPipelineTessellationStateCreateFlags; +typedef struct VkWriteIndirectExecutionSetShaderEXT { + VkStructureType sType; + const void * pNext; + uint32_t index; + VkShaderEXT shader; +} VkWriteIndirectExecutionSetShaderEXT; -typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; +typedef struct VkIndirectCommandsVertexBufferTokenEXT { + uint32_t vertexBindingUnit; +} VkIndirectCommandsVertexBufferTokenEXT; -typedef VkFlags VkPipelineVertexInputStateCreateFlags; +typedef struct VkIndirectCommandsIndexBufferTokenEXT { + VkIndirectCommandsInputModeFlagBitsEXT mode; +} VkIndirectCommandsIndexBufferTokenEXT; -typedef VkFlags VkPipelineShaderStageCreateFlags; +typedef struct VkVertexInputBindingDescription2EXT { + VkStructureType sType; + void * pNext; + uint32_t binding; + uint32_t stride; + VkVertexInputRate inputRate; + uint32_t divisor; +} VkVertexInputBindingDescription2EXT; -typedef VkFlags VkDescriptorSetLayoutCreateFlags; +typedef struct VkVertexInputAttributeDescription2EXT { + VkStructureType sType; + void * pNext; + uint32_t location; + uint32_t binding; + VkFormat format; + uint32_t offset; +} VkVertexInputAttributeDescription2EXT; -typedef VkFlags VkBufferViewCreateFlags; +typedef struct VkCommandBufferSubmitInfo { + VkStructureType sType; + const void * pNext; + VkCommandBuffer commandBuffer; + uint32_t deviceMask; +} VkCommandBufferSubmitInfo; -typedef VkFlags VkInstanceCreateFlags; +typedef struct VkCommandBufferSubmitInfo VkCommandBufferSubmitInfoKHR; -typedef VkFlags VkDeviceCreateFlags; +typedef struct VkPipelineRasterizationProvokingVertexStateCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkProvokingVertexModeEXT provokingVertexMode; +} VkPipelineRasterizationProvokingVertexStateCreateInfoEXT; -typedef VkFlags VkDeviceQueueCreateFlags; +typedef struct VkCuModuleCreateInfoNVX { + VkStructureType sType; + const void * pNext; + size_t dataSize; + const void * pData; +} VkCuModuleCreateInfoNVX; -typedef VkFlags VkQueueFlags; +typedef struct VkCuFunctionCreateInfoNVX { + VkStructureType sType; + const void * pNext; + VkCuModuleNVX module; + const char * pName; +} VkCuFunctionCreateInfoNVX; -typedef VkFlags VkMemoryPropertyFlags; +typedef struct VkCuLaunchInfoNVX { + VkStructureType sType; + const void * pNext; + VkCuFunctionNVX function; + uint32_t gridDimX; + uint32_t gridDimY; + uint32_t gridDimZ; + uint32_t blockDimX; + uint32_t blockDimY; + uint32_t blockDimZ; + uint32_t sharedMemBytes; + size_t paramCount; + const void * const * pParams; + size_t extraCount; + const void * const * pExtras; +} VkCuLaunchInfoNVX; + +typedef struct VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT { + VkStructureType sType; + void * pNext; + size_t combinedImageSamplerDensityMapDescriptorSize; +} VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT; -typedef VkFlags VkMemoryHeapFlags; +typedef struct VkDescriptorBufferBindingPushDescriptorBufferHandleEXT { + VkStructureType sType; + const void * pNext; + VkBuffer buffer; +} VkDescriptorBufferBindingPushDescriptorBufferHandleEXT; -typedef VkFlags VkAccessFlags; - -typedef VkFlags VkBufferUsageFlags; +typedef struct VkBufferCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void * pNext; + VkBuffer buffer; +} VkBufferCaptureDescriptorDataInfoEXT; -typedef VkFlags VkBufferCreateFlags; +typedef struct VkImageCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void * pNext; + VkImage image; +} VkImageCaptureDescriptorDataInfoEXT; -typedef VkFlags VkShaderStageFlags; +typedef struct VkImageViewCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void * pNext; + VkImageView imageView; +} VkImageViewCaptureDescriptorDataInfoEXT; -typedef VkFlags VkImageUsageFlags; +typedef struct VkSamplerCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void * pNext; + VkSampler sampler; +} VkSamplerCaptureDescriptorDataInfoEXT; -typedef VkFlags VkImageCreateFlags; +typedef struct VkAccelerationStructureCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void * pNext; + VkAccelerationStructureKHR accelerationStructure; + VkAccelerationStructureNV accelerationStructureNV; +} VkAccelerationStructureCaptureDescriptorDataInfoEXT; -typedef VkFlags VkImageViewCreateFlags; +typedef struct VkOpaqueCaptureDescriptorDataCreateInfoEXT { + VkStructureType sType; + const void * pNext; + const void * opaqueCaptureDescriptorData; +} VkOpaqueCaptureDescriptorDataCreateInfoEXT; + +typedef enum VkAccelerationStructureMotionInstanceTypeNV { + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV = 0, + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MATRIX_MOTION_NV = 1, + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_SRT_MOTION_NV = 2, + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkAccelerationStructureMotionInstanceTypeNV; +typedef struct VkSRTDataNV { + float sx; + float a; + float b; + float pvx; + float sy; + float c; + float pvy; + float sz; + float pvz; + float qx; + float qy; + float qz; + float qw; + float tx; + float ty; + float tz; +} VkSRTDataNV; + +typedef void* VkRemoteAddressNV; +typedef struct VkMemoryGetRemoteAddressInfoNV { + VkStructureType sType; + const void * pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetRemoteAddressInfoNV; -typedef VkFlags VkPipelineCreateFlags; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkImportMemoryBufferCollectionFUCHSIA { + VkStructureType sType; + const void * pNext; + VkBufferCollectionFUCHSIA collection; + uint32_t index; +} VkImportMemoryBufferCollectionFUCHSIA; -typedef VkFlags VkColorComponentFlags; +#endif -typedef VkFlags VkFenceCreateFlags; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkBufferCollectionImageCreateInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkBufferCollectionFUCHSIA collection; + uint32_t index; +} VkBufferCollectionImageCreateInfoFUCHSIA; -typedef VkFlags VkSemaphoreCreateFlags; +#endif -typedef VkFlags VkFormatFeatureFlags; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkBufferCollectionBufferCreateInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkBufferCollectionFUCHSIA collection; + uint32_t index; +} VkBufferCollectionBufferCreateInfoFUCHSIA; -typedef VkFlags VkQueryControlFlags; +#endif -typedef VkFlags VkQueryResultFlags; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkBufferCollectionCreateInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + zx_handle_t collectionToken; +} VkBufferCollectionCreateInfoFUCHSIA; -typedef VkFlags VkShaderModuleCreateFlags; +#endif -typedef VkFlags VkEventCreateFlags; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkSysmemColorSpaceFUCHSIA { + VkStructureType sType; + const void * pNext; + uint32_t colorSpace; +} VkSysmemColorSpaceFUCHSIA; -typedef VkFlags VkCommandPoolCreateFlags; +#endif -typedef VkFlags VkCommandPoolResetFlags; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkBufferCollectionConstraintsInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + uint32_t minBufferCount; + uint32_t maxBufferCount; + uint32_t minBufferCountForCamping; + uint32_t minBufferCountForDedicatedSlack; + uint32_t minBufferCountForSharedSlack; +} VkBufferCollectionConstraintsInfoFUCHSIA; -typedef VkFlags VkCommandBufferResetFlags; +#endif -typedef VkFlags VkCommandBufferUsageFlags; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCudaModuleNV) +#endif -typedef VkFlags VkQueryPipelineStatisticFlags; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCudaFunctionNV) +#endif -typedef VkFlags VkMemoryMapFlags; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkCudaModuleCreateInfoNV { + VkStructureType sType; + const void * pNext; + size_t dataSize; + const void * pData; +} VkCudaModuleCreateInfoNV; -typedef VkFlags VkImageAspectFlags; +#endif -typedef VkFlags VkSparseMemoryBindFlags; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkCudaFunctionCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkCudaModuleNV module; + const char * pName; +} VkCudaFunctionCreateInfoNV; -typedef VkFlags VkSparseImageFormatFlags; +#endif -typedef VkFlags VkSubpassDescriptionFlags; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkCudaLaunchInfoNV { + VkStructureType sType; + const void * pNext; + VkCudaFunctionNV function; + uint32_t gridDimX; + uint32_t gridDimY; + uint32_t gridDimZ; + uint32_t blockDimX; + uint32_t blockDimY; + uint32_t blockDimZ; + uint32_t sharedMemBytes; + size_t paramCount; + const void * const * pParams; + size_t extraCount; + const void * const * pExtras; +} VkCudaLaunchInfoNV; -typedef VkFlags VkPipelineStageFlags; +#endif -typedef VkFlags VkSampleCountFlags; +typedef struct VkPipelineRenderingCreateInfo { + VkStructureType sType; + const void * pNext; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat * pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; +} VkPipelineRenderingCreateInfo; -typedef VkFlags VkAttachmentDescriptionFlags; +typedef struct VkPipelineRenderingCreateInfo VkPipelineRenderingCreateInfoKHR; -typedef VkFlags VkStencilFaceFlags; +typedef struct VkRenderingEndInfoEXT { + VkStructureType sType; + const void * pNext; +} VkRenderingEndInfoEXT; -typedef VkFlags VkCullModeFlags; +typedef struct VkRenderingAttachmentInfo { + VkStructureType sType; + const void * pNext; + VkImageView imageView; + VkImageLayout imageLayout; + VkResolveModeFlagBits resolveMode; + VkImageView resolveImageView; + VkImageLayout resolveImageLayout; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkClearValue clearValue; +} VkRenderingAttachmentInfo; -typedef VkFlags VkDescriptorPoolCreateFlags; +typedef struct VkRenderingAttachmentInfo VkRenderingAttachmentInfoKHR; -typedef VkFlags VkDescriptorPoolResetFlags; +typedef struct VkRenderingFragmentShadingRateAttachmentInfoKHR { + VkStructureType sType; + const void * pNext; + VkImageView imageView; + VkImageLayout imageLayout; + VkExtent2D shadingRateAttachmentTexelSize; +} VkRenderingFragmentShadingRateAttachmentInfoKHR; -typedef VkFlags VkDependencyFlags; +typedef struct VkRenderingFragmentDensityMapAttachmentInfoEXT { + VkStructureType sType; + const void * pNext; + VkImageView imageView; + VkImageLayout imageLayout; +} VkRenderingFragmentDensityMapAttachmentInfoEXT; -typedef VkFlags VkSubgroupFeatureFlags; +typedef struct VkAttachmentSampleCountInfoAMD { + VkStructureType sType; + const void * pNext; + uint32_t colorAttachmentCount; + const VkSampleCountFlagBits * pColorAttachmentSamples; + VkSampleCountFlagBits depthStencilAttachmentSamples; +} VkAttachmentSampleCountInfoAMD; -typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNV; +typedef struct VkAttachmentSampleCountInfoAMD VkAttachmentSampleCountInfoNV; -typedef VkFlags VkIndirectStateFlagsNV; +typedef struct VkImageViewMinLodCreateInfoEXT { + VkStructureType sType; + const void * pNext; + float minLod; +} VkImageViewMinLodCreateInfoEXT; -typedef VkFlags VkGeometryFlagsKHR; +typedef struct VkDescriptorSetBindingReferenceVALVE { + VkStructureType sType; + const void * pNext; + VkDescriptorSetLayout descriptorSetLayout; + uint32_t binding; +} VkDescriptorSetBindingReferenceVALVE; -#define VkGeometryFlagsNV VkGeometryFlagsKHR +typedef struct VkDescriptorSetLayoutHostMappingInfoVALVE { + VkStructureType sType; + void * pNext; + size_t descriptorOffset; + uint32_t descriptorSize; +} VkDescriptorSetLayoutHostMappingInfoVALVE; -typedef VkFlags VkGeometryInstanceFlagsKHR; +typedef struct VkPhysicalDeviceNestedCommandBufferPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t maxCommandBufferNestingLevel; +} VkPhysicalDeviceNestedCommandBufferPropertiesEXT; -#define VkGeometryInstanceFlagsNV VkGeometryInstanceFlagsKHR +typedef struct VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT { + VkStructureType sType; + void * pNext; + uint8_t shaderModuleIdentifierAlgorithmUUID [ VK_UUID_SIZE ]; +} VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT; -typedef VkFlags VkBuildAccelerationStructureFlagsKHR; +typedef struct VkPipelineShaderStageModuleIdentifierCreateInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t identifierSize; + const uint8_t * pIdentifier; +} VkPipelineShaderStageModuleIdentifierCreateInfoEXT; -#define VkBuildAccelerationStructureFlagsNV VkBuildAccelerationStructureFlagsKHR +typedef struct VkShaderModuleIdentifierEXT { + VkStructureType sType; + void * pNext; + uint32_t identifierSize; + uint8_t identifier [ VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT ]; +} VkShaderModuleIdentifierEXT; -typedef VkFlags VkPrivateDataSlotCreateFlagsEXT; +typedef struct VkRenderPassCreationFeedbackInfoEXT { + uint32_t postMergeSubpassCount; +} VkRenderPassCreationFeedbackInfoEXT; -typedef VkFlags VkDescriptorUpdateTemplateCreateFlags; +typedef struct VkRenderPassCreationFeedbackCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkRenderPassCreationFeedbackInfoEXT * pRenderPassFeedback; +} VkRenderPassCreationFeedbackCreateInfoEXT; -#define VkDescriptorUpdateTemplateCreateFlagsKHR VkDescriptorUpdateTemplateCreateFlags +typedef struct VkRenderPassSubpassFeedbackInfoEXT { + VkSubpassMergeStatusEXT subpassMergeStatus; + char description [ VK_MAX_DESCRIPTION_SIZE ]; + uint32_t postMergeIndex; +} VkRenderPassSubpassFeedbackInfoEXT; -typedef VkFlags VkPipelineCreationFeedbackFlagsEXT; +typedef struct VkRenderPassSubpassFeedbackCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkRenderPassSubpassFeedbackInfoEXT * pSubpassFeedback; +} VkRenderPassSubpassFeedbackCreateInfoEXT; -typedef VkFlags VkPerformanceCounterDescriptionFlagsKHR; +typedef struct VkMicromapVersionInfoEXT { + VkStructureType sType; + const void * pNext; + const uint8_t * pVersionData; +} VkMicromapVersionInfoEXT; -typedef VkFlags VkAcquireProfilingLockFlagsKHR; +typedef struct VkCopyMicromapInfoEXT { + VkStructureType sType; + const void * pNext; + VkMicromapEXT src; + VkMicromapEXT dst; + VkCopyMicromapModeEXT mode; +} VkCopyMicromapInfoEXT; -typedef VkFlags VkSemaphoreWaitFlags; +typedef struct VkMicromapUsageEXT { + uint32_t count; + uint32_t subdivisionLevel; + uint32_t format; +} VkMicromapUsageEXT; -#define VkSemaphoreWaitFlagsKHR VkSemaphoreWaitFlags +typedef struct VkMicromapTriangleEXT { + uint32_t dataOffset; + uint16_t subdivisionLevel; + uint16_t format; +} VkMicromapTriangleEXT; -typedef VkFlags VkPipelineCompilerControlFlagsAMD; +typedef struct VkPhysicalDeviceOpacityMicromapPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t maxOpacity2StateSubdivisionLevel; + uint32_t maxOpacity4StateSubdivisionLevel; +} VkPhysicalDeviceOpacityMicromapPropertiesEXT; -typedef VkFlags VkShaderCorePropertiesFlagsAMD; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDeviceDisplacementMicromapPropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t maxDisplacementMicromapSubdivisionLevel; +} VkPhysicalDeviceDisplacementMicromapPropertiesNV; -typedef VkFlags VkDeviceDiagnosticsConfigFlagsNV; +#endif -typedef VkFlags VkCompositeAlphaFlagsKHR; +typedef struct VkPipelinePropertiesIdentifierEXT { + VkStructureType sType; + void * pNext; + uint8_t pipelineIdentifier [ VK_UUID_SIZE ]; +} VkPipelinePropertiesIdentifierEXT; -typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalObjectCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkExportMetalObjectTypeFlagBitsEXT exportObjectType; +} VkExportMetalObjectCreateInfoEXT; -typedef VkFlags VkSurfaceTransformFlagsKHR; +#endif -typedef VkFlags VkSwapchainCreateFlagsKHR; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalObjectsInfoEXT { + VkStructureType sType; + const void * pNext; +} VkExportMetalObjectsInfoEXT; -typedef VkFlags VkDisplayModeCreateFlagsKHR; +#endif -typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalDeviceInfoEXT { + VkStructureType sType; + const void * pNext; + MTLDevice_id mtlDevice; +} VkExportMetalDeviceInfoEXT; -#if defined(VK_USE_PLATFORM_ANDROID_KHR) -typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; #endif -#if defined(VK_USE_PLATFORM_VI_NN) -typedef VkFlags VkViSurfaceCreateFlagsNN; -#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalCommandQueueInfoEXT { + VkStructureType sType; + const void * pNext; + VkQueue queue; + MTLCommandQueue_id mtlCommandQueue; +} VkExportMetalCommandQueueInfoEXT; -#if defined(VK_USE_PLATFORM_WAYLAND_KHR) -typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; #endif -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef VkFlags VkWin32SurfaceCreateFlagsKHR; -#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalBufferInfoEXT { + VkStructureType sType; + const void * pNext; + VkDeviceMemory memory; + MTLBuffer_id mtlBuffer; +} VkExportMetalBufferInfoEXT; -#if defined(VK_USE_PLATFORM_XLIB_KHR) -typedef VkFlags VkXlibSurfaceCreateFlagsKHR; #endif -#if defined(VK_USE_PLATFORM_XCB_KHR) -typedef VkFlags VkXcbSurfaceCreateFlagsKHR; -#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkImportMetalBufferInfoEXT { + VkStructureType sType; + const void * pNext; + MTLBuffer_id mtlBuffer; +} VkImportMetalBufferInfoEXT; -#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) -typedef VkFlags VkDirectFBSurfaceCreateFlagsEXT; #endif -#if defined(VK_USE_PLATFORM_IOS_MVK) -typedef VkFlags VkIOSSurfaceCreateFlagsMVK; -#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalTextureInfoEXT { + VkStructureType sType; + const void * pNext; + VkImage image; + VkImageView imageView; + VkBufferView bufferView; + VkImageAspectFlagBits plane; + MTLTexture_id mtlTexture; +} VkExportMetalTextureInfoEXT; -#if defined(VK_USE_PLATFORM_MACOS_MVK) -typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; #endif #if defined(VK_USE_PLATFORM_METAL_EXT) -typedef VkFlags VkMetalSurfaceCreateFlagsEXT; -#endif +typedef struct VkImportMetalTextureInfoEXT { + VkStructureType sType; + const void * pNext; + VkImageAspectFlagBits plane; + MTLTexture_id mtlTexture; +} VkImportMetalTextureInfoEXT; -#if defined(VK_USE_PLATFORM_FUCHSIA) -typedef VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA; #endif -#if defined(VK_USE_PLATFORM_GGP) -typedef VkFlags VkStreamDescriptorSurfaceCreateFlagsGGP; -#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalIOSurfaceInfoEXT { + VkStructureType sType; + const void * pNext; + VkImage image; + IOSurfaceRef ioSurface; +} VkExportMetalIOSurfaceInfoEXT; -typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT; +#endif -typedef VkFlags VkPeerMemoryFeatureFlags; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkImportMetalIOSurfaceInfoEXT { + VkStructureType sType; + const void * pNext; + IOSurfaceRef ioSurface; +} VkImportMetalIOSurfaceInfoEXT; -#define VkPeerMemoryFeatureFlagsKHR VkPeerMemoryFeatureFlags +#endif -typedef VkFlags VkMemoryAllocateFlags; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalSharedEventInfoEXT { + VkStructureType sType; + const void * pNext; + VkSemaphore semaphore; + VkEvent event; + MTLSharedEvent_id mtlSharedEvent; +} VkExportMetalSharedEventInfoEXT; -#define VkMemoryAllocateFlagsKHR VkMemoryAllocateFlags +#endif -typedef VkFlags VkDeviceGroupPresentModeFlagsKHR; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkImportMetalSharedEventInfoEXT { + VkStructureType sType; + const void * pNext; + MTLSharedEvent_id mtlSharedEvent; +} VkImportMetalSharedEventInfoEXT; -typedef VkFlags VkDebugReportFlagsEXT; +#endif -typedef VkFlags VkCommandPoolTrimFlags; +typedef struct VkPipelineRobustnessCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineRobustnessBufferBehavior storageBuffers; + VkPipelineRobustnessBufferBehavior uniformBuffers; + VkPipelineRobustnessBufferBehavior vertexInputs; + VkPipelineRobustnessImageBehavior images; +} VkPipelineRobustnessCreateInfo; -#define VkCommandPoolTrimFlagsKHR VkCommandPoolTrimFlags +typedef struct VkPipelineRobustnessCreateInfo VkPipelineRobustnessCreateInfoEXT; -typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; +typedef struct VkPhysicalDevicePipelineRobustnessProperties { + VkStructureType sType; + void * pNext; + VkPipelineRobustnessBufferBehavior defaultRobustnessStorageBuffers; + VkPipelineRobustnessBufferBehavior defaultRobustnessUniformBuffers; + VkPipelineRobustnessBufferBehavior defaultRobustnessVertexInputs; + VkPipelineRobustnessImageBehavior defaultRobustnessImages; +} VkPhysicalDevicePipelineRobustnessProperties; -typedef VkFlags VkExternalMemoryFeatureFlagsNV; +typedef struct VkPhysicalDevicePipelineRobustnessProperties VkPhysicalDevicePipelineRobustnessPropertiesEXT; -typedef VkFlags VkExternalMemoryHandleTypeFlags; +typedef struct VkImageViewSampleWeightCreateInfoQCOM { + VkStructureType sType; + const void * pNext; + VkOffset2D filterCenter; + VkExtent2D filterSize; + uint32_t numPhases; +} VkImageViewSampleWeightCreateInfoQCOM; -#define VkExternalMemoryHandleTypeFlagsKHR VkExternalMemoryHandleTypeFlags +typedef struct VkPhysicalDeviceImageProcessingPropertiesQCOM { + VkStructureType sType; + void * pNext; + uint32_t maxWeightFilterPhases; + VkExtent2D maxWeightFilterDimension; + VkExtent2D maxBlockMatchRegion; + VkExtent2D maxBoxFilterBlockSize; +} VkPhysicalDeviceImageProcessingPropertiesQCOM; -typedef VkFlags VkExternalMemoryFeatureFlags; +typedef struct VkTilePropertiesQCOM { + VkStructureType sType; + void * pNext; + VkExtent3D tileSize; + VkExtent2D apronSize; + VkOffset2D origin; +} VkTilePropertiesQCOM; -#define VkExternalMemoryFeatureFlagsKHR VkExternalMemoryFeatureFlags +typedef struct VkTileMemoryBindInfoQCOM { + VkStructureType sType; + const void * pNext; + VkDeviceMemory memory; +} VkTileMemoryBindInfoQCOM; -typedef VkFlags VkExternalSemaphoreHandleTypeFlags; +typedef struct VkAmigoProfilingSubmitInfoSEC { + VkStructureType sType; + const void * pNext; + uint64_t firstDrawTimestamp; + uint64_t swapBufferTimestamp; +} VkAmigoProfilingSubmitInfoSEC; -#define VkExternalSemaphoreHandleTypeFlagsKHR VkExternalSemaphoreHandleTypeFlags +typedef struct VkOpticalFlowImageFormatPropertiesNV { + VkStructureType sType; + const void * pNext; + VkFormat format; +} VkOpticalFlowImageFormatPropertiesNV; + +typedef struct VkOpticalFlowSessionCreatePrivateDataInfoNV { + VkStructureType sType; + void * pNext; + uint32_t id; + uint32_t size; + const void * pPrivateData; +} VkOpticalFlowSessionCreatePrivateDataInfoNV; + +typedef struct VkDeviceFaultVendorInfoEXT { + char description [ VK_MAX_DESCRIPTION_SIZE ]; + uint64_t vendorFaultCode; + uint64_t vendorFaultData; +} VkDeviceFaultVendorInfoEXT; + +typedef struct VkDeviceFaultVendorBinaryHeaderVersionOneEXT { + uint32_t headerSize; + VkDeviceFaultVendorBinaryHeaderVersionEXT headerVersion; + uint32_t vendorID; + uint32_t deviceID; + uint32_t driverVersion; + uint8_t pipelineCacheUUID [ VK_UUID_SIZE ]; + uint32_t applicationNameOffset; + uint32_t applicationVersion; + uint32_t engineNameOffset; + uint32_t engineVersion; + uint32_t apiVersion; +} VkDeviceFaultVendorBinaryHeaderVersionOneEXT; + +typedef struct VkDepthBiasInfoEXT { + VkStructureType sType; + const void * pNext; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; +} VkDepthBiasInfoEXT; -typedef VkFlags VkExternalSemaphoreFeatureFlags; +typedef struct VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM { + VkStructureType sType; + void * pNext; + uint64_t shaderCoreMask; + uint32_t shaderCoreCount; + uint32_t shaderWarpsPerCore; +} VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM; -#define VkExternalSemaphoreFeatureFlagsKHR VkExternalSemaphoreFeatureFlags +typedef struct VkSurfacePresentModeEXT { + VkStructureType sType; + void * pNext; + VkPresentModeKHR presentMode; +} VkSurfacePresentModeEXT; -typedef VkFlags VkSemaphoreImportFlags; +typedef struct VkSurfacePresentModeCompatibilityEXT { + VkStructureType sType; + void * pNext; + uint32_t presentModeCount; + VkPresentModeKHR * pPresentModes; +} VkSurfacePresentModeCompatibilityEXT; -#define VkSemaphoreImportFlagsKHR VkSemaphoreImportFlags +typedef struct VkSwapchainPresentFenceInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t swapchainCount; + const VkFence * pFences; +} VkSwapchainPresentFenceInfoEXT; -typedef VkFlags VkExternalFenceHandleTypeFlags; +typedef struct VkSwapchainPresentModesCreateInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t presentModeCount; + const VkPresentModeKHR * pPresentModes; +} VkSwapchainPresentModesCreateInfoEXT; -#define VkExternalFenceHandleTypeFlagsKHR VkExternalFenceHandleTypeFlags +typedef struct VkSwapchainPresentModeInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t swapchainCount; + const VkPresentModeKHR * pPresentModes; +} VkSwapchainPresentModeInfoEXT; -typedef VkFlags VkExternalFenceFeatureFlags; +typedef struct VkReleaseSwapchainImagesInfoEXT { + VkStructureType sType; + const void * pNext; + VkSwapchainKHR swapchain; + uint32_t imageIndexCount; + const uint32_t * pImageIndices; +} VkReleaseSwapchainImagesInfoEXT; -#define VkExternalFenceFeatureFlagsKHR VkExternalFenceFeatureFlags +typedef struct VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV { + VkStructureType sType; + void * pNext; + VkRayTracingInvocationReorderModeNV rayTracingInvocationReorderReorderingHint; +} VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV; -typedef VkFlags VkFenceImportFlags; +typedef struct VkPhysicalDeviceShaderCorePropertiesARM { + VkStructureType sType; + void * pNext; + uint32_t pixelRate; + uint32_t texelRate; + uint32_t fmaRate; +} VkPhysicalDeviceShaderCorePropertiesARM; -#define VkFenceImportFlagsKHR VkFenceImportFlags +typedef struct VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM { + VkStructureType sType; + const void * pNext; + uint32_t perViewRenderAreaCount; + const VkRect2D * pPerViewRenderAreas; +} VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM; -typedef VkFlags VkSurfaceCounterFlagsEXT; +typedef struct VkQueryLowLatencySupportNV { + VkStructureType sType; + const void * pNext; + void * pQueriedLowLatencyData; +} VkQueryLowLatencySupportNV; -typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV; +typedef struct VkPhysicalDeviceShaderObjectPropertiesEXT { + VkStructureType sType; + void * pNext; + uint8_t shaderBinaryUUID [ VK_UUID_SIZE ]; + uint32_t shaderBinaryVersion; +} VkPhysicalDeviceShaderObjectPropertiesEXT; -typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef struct VkImportScreenBufferInfoQNX { + VkStructureType sType; + const void * pNext; + struct _screen_buffer * buffer; +} VkImportScreenBufferInfoQNX; -typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV; +#endif -typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef struct VkExternalFormatQNX { + VkStructureType sType; + void * pNext; + uint64_t externalFormat; +} VkExternalFormatQNX; -typedef VkFlags VkPipelineCoverageReductionStateCreateFlagsNV; +#endif -typedef VkFlags VkValidationCacheCreateFlagsEXT; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDeviceShaderEnqueuePropertiesAMDX { + VkStructureType sType; + void * pNext; + uint32_t maxExecutionGraphDepth; + uint32_t maxExecutionGraphShaderOutputNodes; + uint32_t maxExecutionGraphShaderPayloadSize; + uint32_t maxExecutionGraphShaderPayloadCount; + uint32_t executionGraphDispatchAddressAlignment; + uint32_t maxExecutionGraphWorkgroupCount [3]; + uint32_t maxExecutionGraphWorkgroups; +} VkPhysicalDeviceShaderEnqueuePropertiesAMDX; -typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT; +#endif -typedef VkFlags VkDebugUtilsMessageTypeFlagsEXT; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPipelineShaderStageNodeCreateInfoAMDX { + VkStructureType sType; + const void * pNext; + const char * pName; + uint32_t index; +} VkPipelineShaderStageNodeCreateInfoAMDX; -typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT; +#endif -typedef VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT; +typedef struct VkAntiLagPresentationInfoAMD { + VkStructureType sType; + void * pNext; + VkAntiLagStageAMD stage; + uint64_t frameIndex; +} VkAntiLagPresentationInfoAMD; -typedef VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT; +typedef struct VkBindMemoryStatus { + VkStructureType sType; + const void * pNext; + VkResult * pResult; +} VkBindMemoryStatus; -typedef VkFlags VkDescriptorBindingFlags; +typedef struct VkBindMemoryStatus VkBindMemoryStatusKHR; -#define VkDescriptorBindingFlagsEXT VkDescriptorBindingFlags +typedef struct VkPushDescriptorSetWithTemplateInfo { + VkStructureType sType; + const void * pNext; + VkDescriptorUpdateTemplate descriptorUpdateTemplate; + VkPipelineLayout layout; + uint32_t set; + const void * pData; +} VkPushDescriptorSetWithTemplateInfo; -typedef VkFlags VkConditionalRenderingFlagsEXT; +typedef struct VkPushDescriptorSetWithTemplateInfo VkPushDescriptorSetWithTemplateInfoKHR; -typedef VkFlags VkResolveModeFlags; +typedef struct VkSamplerCubicWeightsCreateInfoQCOM { + VkStructureType sType; + const void * pNext; + VkCubicFilterWeightsQCOM cubicWeights; +} VkSamplerCubicWeightsCreateInfoQCOM; -#define VkResolveModeFlagsKHR VkResolveModeFlags +typedef struct VkBlitImageCubicWeightsInfoQCOM { + VkStructureType sType; + const void * pNext; + VkCubicFilterWeightsQCOM cubicWeights; +} VkBlitImageCubicWeightsInfoQCOM; -typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT; +typedef struct VkPhysicalDeviceImageProcessing2PropertiesQCOM { + VkStructureType sType; + void * pNext; + VkExtent2D maxBlockMatchWindow; +} VkPhysicalDeviceImageProcessing2PropertiesQCOM; -typedef VkFlags VkPipelineRasterizationDepthClipStateCreateFlagsEXT; +typedef struct VkSamplerBlockMatchWindowCreateInfoQCOM { + VkStructureType sType; + const void * pNext; + VkExtent2D windowExtent; + VkBlockMatchWindowCompareModeQCOM windowCompareMode; +} VkSamplerBlockMatchWindowCreateInfoQCOM; + +typedef struct VkPhysicalDeviceLayeredDriverPropertiesMSFT { + VkStructureType sType; + void * pNext; + VkLayeredDriverUnderlyingApiMSFT underlyingAPI; +} VkPhysicalDeviceLayeredDriverPropertiesMSFT; -typedef VkFlags VkToolPurposeFlagsEXT; +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef struct VkAndroidHardwareBufferFormatResolvePropertiesANDROID { + VkStructureType sType; + void * pNext; + VkFormat colorAttachmentFormat; +} VkAndroidHardwareBufferFormatResolvePropertiesANDROID; -typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char* pLayerPrefix, - const char* pMessage, - void* pUserData); +#endif -typedef struct VkDeviceQueueCreateInfo { +typedef struct VkLatencySleepInfoNV { VkStructureType sType; - const void * pNext; - VkDeviceQueueCreateFlags flags; - uint32_t queueFamilyIndex; - uint32_t queueCount; - const float * pQueuePriorities; -} VkDeviceQueueCreateInfo; + const void * pNext; + VkSemaphore signalSemaphore; + uint64_t value; +} VkLatencySleepInfoNV; -typedef struct VkInstanceCreateInfo { +typedef struct VkSetLatencyMarkerInfoNV { VkStructureType sType; - const void * pNext; - VkInstanceCreateFlags flags; - const VkApplicationInfo * pApplicationInfo; - uint32_t enabledLayerCount; - const char * const* ppEnabledLayerNames; - uint32_t enabledExtensionCount; - const char * const* ppEnabledExtensionNames; -} VkInstanceCreateInfo; + const void * pNext; + uint64_t presentID; + VkLatencyMarkerNV marker; +} VkSetLatencyMarkerInfoNV; -typedef struct VkQueueFamilyProperties { - VkQueueFlags queueFlags; - uint32_t queueCount; - uint32_t timestampValidBits; - VkExtent3D minImageTransferGranularity; -} VkQueueFamilyProperties; +typedef struct VkLatencyTimingsFrameReportNV { + VkStructureType sType; + const void * pNext; + uint64_t presentID; + uint64_t inputSampleTimeUs; + uint64_t simStartTimeUs; + uint64_t simEndTimeUs; + uint64_t renderSubmitStartTimeUs; + uint64_t renderSubmitEndTimeUs; + uint64_t presentStartTimeUs; + uint64_t presentEndTimeUs; + uint64_t driverStartTimeUs; + uint64_t driverEndTimeUs; + uint64_t osRenderQueueStartTimeUs; + uint64_t osRenderQueueEndTimeUs; + uint64_t gpuRenderStartTimeUs; + uint64_t gpuRenderEndTimeUs; +} VkLatencyTimingsFrameReportNV; + +typedef struct VkOutOfBandQueueTypeInfoNV { + VkStructureType sType; + const void * pNext; + VkOutOfBandQueueTypeNV queueType; +} VkOutOfBandQueueTypeInfoNV; -typedef struct VkMemoryAllocateInfo { +typedef struct VkLatencySubmissionPresentIdNV { VkStructureType sType; - const void * pNext; - VkDeviceSize allocationSize; - uint32_t memoryTypeIndex; -} VkMemoryAllocateInfo; + const void * pNext; + uint64_t presentID; +} VkLatencySubmissionPresentIdNV; -typedef struct VkMemoryRequirements { - VkDeviceSize size; - VkDeviceSize alignment; - uint32_t memoryTypeBits; -} VkMemoryRequirements; +typedef struct VkLatencySurfaceCapabilitiesNV { + VkStructureType sType; + const void * pNext; + uint32_t presentModeCount; + VkPresentModeKHR * pPresentModes; +} VkLatencySurfaceCapabilitiesNV; -typedef struct VkSparseImageFormatProperties { - VkImageAspectFlags aspectMask; - VkExtent3D imageGranularity; - VkSparseImageFormatFlags flags; -} VkSparseImageFormatProperties; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDeviceCudaKernelLaunchPropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t computeCapabilityMinor; + uint32_t computeCapabilityMajor; +} VkPhysicalDeviceCudaKernelLaunchPropertiesNV; -typedef struct VkSparseImageMemoryRequirements { - VkSparseImageFormatProperties formatProperties; - uint32_t imageMipTailFirstLod; - VkDeviceSize imageMipTailSize; - VkDeviceSize imageMipTailOffset; - VkDeviceSize imageMipTailStride; -} VkSparseImageMemoryRequirements; +#endif -typedef struct VkMemoryType { - VkMemoryPropertyFlags propertyFlags; - uint32_t heapIndex; -} VkMemoryType; +typedef struct VkDeviceQueueShaderCoreControlCreateInfoARM { + VkStructureType sType; + void * pNext; + uint32_t shaderCoreCount; +} VkDeviceQueueShaderCoreControlCreateInfoARM; -typedef struct VkMemoryHeap { - VkDeviceSize size; - VkMemoryHeapFlags flags; -} VkMemoryHeap; +typedef struct VkPhysicalDeviceRenderPassStripedPropertiesARM { + VkStructureType sType; + void * pNext; + VkExtent2D renderPassStripeGranularity; + uint32_t maxRenderPassStripes; +} VkPhysicalDeviceRenderPassStripedPropertiesARM; -typedef struct VkMappedMemoryRange { +typedef struct VkRenderPassStripeInfoARM { VkStructureType sType; - const void * pNext; - VkDeviceMemory memory; - VkDeviceSize offset; - VkDeviceSize size; -} VkMappedMemoryRange; + const void * pNext; + VkRect2D stripeArea; +} VkRenderPassStripeInfoARM; -typedef struct VkFormatProperties { - VkFormatFeatureFlags linearTilingFeatures; - VkFormatFeatureFlags optimalTilingFeatures; - VkFormatFeatureFlags bufferFeatures; -} VkFormatProperties; +typedef struct VkRenderPassStripeBeginInfoARM { + VkStructureType sType; + const void * pNext; + uint32_t stripeInfoCount; + const VkRenderPassStripeInfoARM * pStripeInfos; +} VkRenderPassStripeBeginInfoARM; -typedef struct VkImageFormatProperties { - VkExtent3D maxExtent; - uint32_t maxMipLevels; - uint32_t maxArrayLayers; - VkSampleCountFlags sampleCounts; - VkDeviceSize maxResourceSize; -} VkImageFormatProperties; +typedef struct VkRenderingAttachmentLocationInfo { + VkStructureType sType; + const void * pNext; + uint32_t colorAttachmentCount; + const uint32_t * pColorAttachmentLocations; +} VkRenderingAttachmentLocationInfo; -typedef struct VkDescriptorBufferInfo { - VkBuffer buffer; - VkDeviceSize offset; - VkDeviceSize range; -} VkDescriptorBufferInfo; +typedef struct VkRenderingAttachmentLocationInfo VkRenderingAttachmentLocationInfoKHR; -typedef struct VkWriteDescriptorSet { +typedef struct VkRenderingInputAttachmentIndexInfo { VkStructureType sType; - const void * pNext; - VkDescriptorSet dstSet; - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; - VkDescriptorType descriptorType; - const VkDescriptorImageInfo * pImageInfo; - const VkDescriptorBufferInfo * pBufferInfo; - const VkBufferView * pTexelBufferView; -} VkWriteDescriptorSet; + const void * pNext; + uint32_t colorAttachmentCount; + const uint32_t * pColorAttachmentInputIndices; + const uint32_t * pDepthInputAttachmentIndex; + const uint32_t * pStencilInputAttachmentIndex; +} VkRenderingInputAttachmentIndexInfo; -typedef struct VkBufferCreateInfo { +typedef struct VkRenderingInputAttachmentIndexInfo VkRenderingInputAttachmentIndexInfoKHR; + +typedef struct VkMemoryMapPlacedInfoEXT { VkStructureType sType; - const void * pNext; - VkBufferCreateFlags flags; - VkDeviceSize size; - VkBufferUsageFlags usage; - VkSharingMode sharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t * pQueueFamilyIndices; -} VkBufferCreateInfo; + const void * pNext; + void * pPlacedAddress; +} VkMemoryMapPlacedInfoEXT; -typedef struct VkBufferViewCreateInfo { +typedef struct VkPhysicalDeviceImageAlignmentControlPropertiesMESA { VkStructureType sType; - const void * pNext; - VkBufferViewCreateFlags flags; - VkBuffer buffer; - VkFormat format; - VkDeviceSize offset; - VkDeviceSize range; -} VkBufferViewCreateInfo; + void * pNext; + uint32_t supportedImageAlignmentMask; +} VkPhysicalDeviceImageAlignmentControlPropertiesMESA; -typedef struct VkImageSubresource { - VkImageAspectFlags aspectMask; - uint32_t mipLevel; - uint32_t arrayLayer; -} VkImageSubresource; +typedef struct VkImageAlignmentControlCreateInfoMESA { + VkStructureType sType; + const void * pNext; + uint32_t maximumRequestedAlignment; +} VkImageAlignmentControlCreateInfoMESA; -typedef struct VkImageSubresourceLayers { - VkImageAspectFlags aspectMask; - uint32_t mipLevel; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkImageSubresourceLayers; +typedef struct VkDepthClampRangeEXT { + float minDepthClamp; + float maxDepthClamp; +} VkDepthClampRangeEXT; -typedef struct VkImageSubresourceRange { - VkImageAspectFlags aspectMask; - uint32_t baseMipLevel; - uint32_t levelCount; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkImageSubresourceRange; +typedef struct VkPhysicalDeviceCooperativeMatrix2PropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t cooperativeMatrixWorkgroupScopeMaxWorkgroupSize; + uint32_t cooperativeMatrixFlexibleDimensionsMaxDimension; + uint32_t cooperativeMatrixWorkgroupScopeReservedSharedMemory; +} VkPhysicalDeviceCooperativeMatrix2PropertiesNV; -typedef struct VkMemoryBarrier { +typedef struct VkPerTileBeginInfoQCOM { VkStructureType sType; - const void * pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; -} VkMemoryBarrier; + const void * pNext; +} VkPerTileBeginInfoQCOM; -typedef struct VkBufferMemoryBarrier { +typedef struct VkPerTileEndInfoQCOM { VkStructureType sType; - const void * pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkBuffer buffer; - VkDeviceSize offset; - VkDeviceSize size; -} VkBufferMemoryBarrier; + const void * pNext; +} VkPerTileEndInfoQCOM; -typedef struct VkImageMemoryBarrier { +typedef struct VkDispatchTileInfoQCOM { VkStructureType sType; - const void * pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkImageLayout oldLayout; - VkImageLayout newLayout; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkImage image; - VkImageSubresourceRange subresourceRange; -} VkImageMemoryBarrier; + const void * pNext; +} VkDispatchTileInfoQCOM; -typedef struct VkImageCreateInfo { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkSetPresentConfigNV { VkStructureType sType; - const void * pNext; - VkImageCreateFlags flags; - VkImageType imageType; - VkFormat format; - VkExtent3D extent; - uint32_t mipLevels; - uint32_t arrayLayers; - VkSampleCountFlagBits samples; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkSharingMode sharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t * pQueueFamilyIndices; - VkImageLayout initialLayout; -} VkImageCreateInfo; + const void * pNext; + uint32_t numFramesPerBatch; + uint32_t presentConfigFeedback; +} VkSetPresentConfigNV; -typedef struct VkSubresourceLayout { - VkDeviceSize offset; - VkDeviceSize size; - VkDeviceSize rowPitch; - VkDeviceSize arrayPitch; - VkDeviceSize depthPitch; -} VkSubresourceLayout; +#endif -typedef struct VkImageViewCreateInfo { +typedef struct VkExternalComputeQueueDeviceCreateInfoNV { VkStructureType sType; - const void * pNext; - VkImageViewCreateFlags flags; - VkImage image; - VkImageViewType viewType; - VkFormat format; - VkComponentMapping components; - VkImageSubresourceRange subresourceRange; -} VkImageViewCreateInfo; + const void * pNext; + uint32_t reservedExternalQueues; +} VkExternalComputeQueueDeviceCreateInfoNV; -typedef struct VkBufferCopy { - VkDeviceSize srcOffset; - VkDeviceSize dstOffset; - VkDeviceSize size; -} VkBufferCopy; +typedef struct VkExternalComputeQueueCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkQueue preferredQueue; +} VkExternalComputeQueueCreateInfoNV; -typedef struct VkSparseMemoryBind { - VkDeviceSize resourceOffset; - VkDeviceSize size; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseMemoryBind; +typedef struct VkExternalComputeQueueDataParamsNV { + VkStructureType sType; + const void * pNext; + uint32_t deviceIndex; +} VkExternalComputeQueueDataParamsNV; -typedef struct VkSparseImageMemoryBind { - VkImageSubresource subresource; - VkOffset3D offset; - VkExtent3D extent; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseImageMemoryBind; +typedef struct VkPhysicalDeviceExternalComputeQueuePropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t externalDataSize; + uint32_t maxExternalQueues; +} VkPhysicalDeviceExternalComputeQueuePropertiesNV; -typedef struct VkSparseBufferMemoryBindInfo { - VkBuffer buffer; - uint32_t bindCount; - const VkSparseMemoryBind * pBinds; -} VkSparseBufferMemoryBindInfo; +VK_DEFINE_HANDLE(VkExternalComputeQueueNV) +/* Complete version of this file */ +#define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 4, VK_HEADER_VERSION) +typedef uint32_t VkSampleMask; +typedef uint32_t VkBool32; +typedef uint32_t VkFlags; +typedef uint64_t VkFlags64; +typedef uint64_t VkDeviceSize; +typedef uint64_t VkDeviceAddress; +typedef VkFlags VkFramebufferCreateFlags; +typedef VkFlags VkQueryPoolCreateFlags; +typedef VkFlags VkRenderPassCreateFlags; +typedef VkFlags VkSamplerCreateFlags; +typedef VkFlags VkPipelineLayoutCreateFlags; +typedef VkFlags VkPipelineCacheCreateFlags; +typedef VkFlags VkPipelineDepthStencilStateCreateFlags; +typedef VkFlags VkPipelineDynamicStateCreateFlags; +typedef VkFlags VkPipelineColorBlendStateCreateFlags; +typedef VkFlags VkPipelineMultisampleStateCreateFlags; +typedef VkFlags VkPipelineRasterizationStateCreateFlags; +typedef VkFlags VkPipelineViewportStateCreateFlags; +typedef VkFlags VkPipelineTessellationStateCreateFlags; +typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; +typedef VkFlags VkPipelineVertexInputStateCreateFlags; +typedef VkFlags VkPipelineShaderStageCreateFlags; +typedef VkFlags VkDescriptorSetLayoutCreateFlags; +typedef VkFlags VkBufferViewCreateFlags; +typedef VkFlags VkInstanceCreateFlags; +typedef VkFlags VkDeviceCreateFlags; +typedef VkFlags VkDeviceQueueCreateFlags; +typedef VkFlags VkQueueFlags; +typedef VkFlags VkMemoryPropertyFlags; +typedef VkFlags VkMemoryHeapFlags; +typedef VkFlags VkAccessFlags; +typedef VkFlags VkBufferUsageFlags; +typedef VkFlags VkBufferCreateFlags; +typedef VkFlags VkShaderStageFlags; +typedef VkFlags VkImageUsageFlags; +typedef VkFlags VkImageCreateFlags; +typedef VkFlags VkImageViewCreateFlags; +typedef VkFlags VkPipelineCreateFlags; +typedef VkFlags VkColorComponentFlags; +typedef VkFlags VkFenceCreateFlags; +typedef VkFlags VkSemaphoreCreateFlags; +typedef VkFlags VkFormatFeatureFlags; +typedef VkFlags VkQueryControlFlags; +typedef VkFlags VkQueryResultFlags; +typedef VkFlags VkShaderModuleCreateFlags; +typedef VkFlags VkEventCreateFlags; +typedef VkFlags VkCommandPoolCreateFlags; +typedef VkFlags VkCommandPoolResetFlags; +typedef VkFlags VkCommandBufferResetFlags; +typedef VkFlags VkCommandBufferUsageFlags; +typedef VkFlags VkQueryPipelineStatisticFlags; +typedef VkFlags VkMemoryMapFlags; +typedef VkFlags VkMemoryUnmapFlags; +#define VkMemoryUnmapFlagsKHR VkMemoryUnmapFlags +typedef VkFlags VkImageAspectFlags; +typedef VkFlags VkSparseMemoryBindFlags; +typedef VkFlags VkSparseImageFormatFlags; +typedef VkFlags VkSubpassDescriptionFlags; +typedef VkFlags VkPipelineStageFlags; +typedef VkFlags VkSampleCountFlags; +typedef VkFlags VkAttachmentDescriptionFlags; +typedef VkFlags VkStencilFaceFlags; +typedef VkFlags VkCullModeFlags; +typedef VkFlags VkDescriptorPoolCreateFlags; +typedef VkFlags VkDescriptorPoolResetFlags; +typedef VkFlags VkDependencyFlags; +typedef VkFlags VkSubgroupFeatureFlags; +typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNV; +typedef VkFlags VkIndirectStateFlagsNV; +typedef VkFlags VkGeometryFlagsKHR; +#define VkGeometryFlagsNV VkGeometryFlagsKHR +typedef VkFlags VkGeometryInstanceFlagsKHR; +#define VkGeometryInstanceFlagsNV VkGeometryInstanceFlagsKHR +typedef VkFlags VkClusterAccelerationStructureGeometryFlagsNV; +typedef VkFlags VkClusterAccelerationStructureClusterFlagsNV; +typedef VkFlags VkClusterAccelerationStructureAddressResolutionFlagsNV; +typedef VkFlags VkBuildAccelerationStructureFlagsKHR; +#define VkBuildAccelerationStructureFlagsNV VkBuildAccelerationStructureFlagsKHR +typedef VkFlags VkPrivateDataSlotCreateFlags; +#define VkPrivateDataSlotCreateFlagsEXT VkPrivateDataSlotCreateFlags +typedef VkFlags VkAccelerationStructureCreateFlagsKHR; +typedef VkFlags VkDescriptorUpdateTemplateCreateFlags; +#define VkDescriptorUpdateTemplateCreateFlagsKHR VkDescriptorUpdateTemplateCreateFlags +typedef VkFlags VkPipelineCreationFeedbackFlags; +#define VkPipelineCreationFeedbackFlagsEXT VkPipelineCreationFeedbackFlags +typedef VkFlags VkPerformanceCounterDescriptionFlagsKHR; +typedef VkFlags VkAcquireProfilingLockFlagsKHR; +typedef VkFlags VkSemaphoreWaitFlags; +#define VkSemaphoreWaitFlagsKHR VkSemaphoreWaitFlags +typedef VkFlags VkPipelineCompilerControlFlagsAMD; +typedef VkFlags VkShaderCorePropertiesFlagsAMD; +typedef VkFlags VkDeviceDiagnosticsConfigFlagsNV; +typedef VkFlags64 VkAccessFlags2; +#define VkAccessFlags2KHR VkAccessFlags2 +typedef VkFlags64 VkPipelineStageFlags2; +#define VkPipelineStageFlags2KHR VkPipelineStageFlags2 +typedef VkFlags VkAccelerationStructureMotionInfoFlagsNV; +typedef VkFlags VkAccelerationStructureMotionInstanceFlagsNV; +typedef VkFlags64 VkFormatFeatureFlags2; +#define VkFormatFeatureFlags2KHR VkFormatFeatureFlags2 +typedef VkFlags VkRenderingFlags; +typedef VkFlags64 VkMemoryDecompressionMethodFlagsNV; +#define VkRenderingFlagsKHR VkRenderingFlags +typedef VkFlags VkBuildMicromapFlagsEXT; +typedef VkFlags VkMicromapCreateFlagsEXT; +typedef VkFlags VkIndirectCommandsLayoutUsageFlagsEXT; +typedef VkFlags VkIndirectCommandsInputModeFlagsEXT; +typedef VkFlags VkDirectDriverLoadingFlagsLUNARG; +typedef VkFlags64 VkPipelineCreateFlags2; +#define VkPipelineCreateFlags2KHR VkPipelineCreateFlags2 +typedef VkFlags64 VkBufferUsageFlags2; +#define VkBufferUsageFlags2KHR VkBufferUsageFlags2 +typedef VkFlags VkCompositeAlphaFlagsKHR; +typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; +typedef VkFlags VkSurfaceTransformFlagsKHR; +typedef VkFlags VkSwapchainCreateFlagsKHR; +typedef VkFlags VkDisplayModeCreateFlagsKHR; +typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; +#endif -typedef struct VkSparseImageOpaqueMemoryBindInfo { - VkImage image; - uint32_t bindCount; - const VkSparseMemoryBind * pBinds; -} VkSparseImageOpaqueMemoryBindInfo; +#if defined(VK_USE_PLATFORM_VI_NN) +typedef VkFlags VkViSurfaceCreateFlagsNN; +#endif -typedef struct VkSparseImageMemoryBindInfo { - VkImage image; - uint32_t bindCount; - const VkSparseImageMemoryBind * pBinds; -} VkSparseImageMemoryBindInfo; +#if defined(VK_USE_PLATFORM_WAYLAND_KHR) +typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; +#endif -typedef struct VkBindSparseInfo { - VkStructureType sType; - const void * pNext; - uint32_t waitSemaphoreCount; - const VkSemaphore * pWaitSemaphores; - uint32_t bufferBindCount; - const VkSparseBufferMemoryBindInfo * pBufferBinds; - uint32_t imageOpaqueBindCount; - const VkSparseImageOpaqueMemoryBindInfo * pImageOpaqueBinds; - uint32_t imageBindCount; - const VkSparseImageMemoryBindInfo * pImageBinds; - uint32_t signalSemaphoreCount; - const VkSemaphore * pSignalSemaphores; -} VkBindSparseInfo; +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef VkFlags VkWin32SurfaceCreateFlagsKHR; +#endif -typedef struct VkImageCopy { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageCopy; +#if defined(VK_USE_PLATFORM_XLIB_KHR) +typedef VkFlags VkXlibSurfaceCreateFlagsKHR; +#endif -typedef struct VkImageBlit { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffsets [2]; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffsets [2]; -} VkImageBlit; +#if defined(VK_USE_PLATFORM_XCB_KHR) +typedef VkFlags VkXcbSurfaceCreateFlagsKHR; +#endif -typedef struct VkBufferImageCopy { - VkDeviceSize bufferOffset; - uint32_t bufferRowLength; - uint32_t bufferImageHeight; - VkImageSubresourceLayers imageSubresource; - VkOffset3D imageOffset; - VkExtent3D imageExtent; -} VkBufferImageCopy; +#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) +typedef VkFlags VkDirectFBSurfaceCreateFlagsEXT; +#endif -typedef struct VkImageResolve { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageResolve; +#if defined(VK_USE_PLATFORM_IOS_MVK) +typedef VkFlags VkIOSSurfaceCreateFlagsMVK; +#endif -typedef struct VkShaderModuleCreateInfo { - VkStructureType sType; - const void * pNext; - VkShaderModuleCreateFlags flags; - size_t codeSize; - const uint32_t * pCode; -} VkShaderModuleCreateInfo; +#if defined(VK_USE_PLATFORM_MACOS_MVK) +typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; +#endif -typedef struct VkDescriptorSetLayoutBinding { - uint32_t binding; - VkDescriptorType descriptorType; - uint32_t descriptorCount; - VkShaderStageFlags stageFlags; - const VkSampler * pImmutableSamplers; -} VkDescriptorSetLayoutBinding; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef VkFlags VkMetalSurfaceCreateFlagsEXT; +#endif -typedef struct VkDescriptorSetLayoutCreateInfo { +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA; +#endif + +#if defined(VK_USE_PLATFORM_GGP) +typedef VkFlags VkStreamDescriptorSurfaceCreateFlagsGGP; +#endif + +typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef VkFlags VkScreenSurfaceCreateFlagsQNX; +#endif + +typedef VkFlags VkPeerMemoryFeatureFlags; +#define VkPeerMemoryFeatureFlagsKHR VkPeerMemoryFeatureFlags +typedef VkFlags VkMemoryAllocateFlags; +#define VkMemoryAllocateFlagsKHR VkMemoryAllocateFlags +typedef VkFlags VkDeviceGroupPresentModeFlagsKHR; +typedef VkFlags VkDebugReportFlagsEXT; +typedef VkFlags VkCommandPoolTrimFlags; +#define VkCommandPoolTrimFlagsKHR VkCommandPoolTrimFlags +typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; +typedef VkFlags VkClusterAccelerationStructureIndexFormatFlagsNV; +typedef VkFlags VkExternalMemoryFeatureFlagsNV; +typedef VkFlags VkExternalMemoryHandleTypeFlags; +#define VkExternalMemoryHandleTypeFlagsKHR VkExternalMemoryHandleTypeFlags +typedef VkFlags VkExternalMemoryFeatureFlags; +#define VkExternalMemoryFeatureFlagsKHR VkExternalMemoryFeatureFlags +typedef VkFlags VkExternalSemaphoreHandleTypeFlags; +#define VkExternalSemaphoreHandleTypeFlagsKHR VkExternalSemaphoreHandleTypeFlags +typedef VkFlags VkExternalSemaphoreFeatureFlags; +#define VkExternalSemaphoreFeatureFlagsKHR VkExternalSemaphoreFeatureFlags +typedef VkFlags VkSemaphoreImportFlags; +#define VkSemaphoreImportFlagsKHR VkSemaphoreImportFlags +typedef VkFlags VkExternalFenceHandleTypeFlags; +#define VkExternalFenceHandleTypeFlagsKHR VkExternalFenceHandleTypeFlags +typedef VkFlags VkExternalFenceFeatureFlags; +#define VkExternalFenceFeatureFlagsKHR VkExternalFenceFeatureFlags +typedef VkFlags VkFenceImportFlags; +#define VkFenceImportFlagsKHR VkFenceImportFlags +typedef VkFlags VkSurfaceCounterFlagsEXT; +typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV; +typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT; +typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV; +typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV; +typedef VkFlags VkPipelineCoverageReductionStateCreateFlagsNV; +typedef VkFlags VkValidationCacheCreateFlagsEXT; +typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT; +typedef VkFlags VkDebugUtilsMessageTypeFlagsEXT; +typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT; +typedef VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT; +typedef VkFlags VkDeviceMemoryReportFlagsEXT; +typedef VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT; +typedef VkFlags VkDescriptorBindingFlags; +#define VkDescriptorBindingFlagsEXT VkDescriptorBindingFlags +typedef VkFlags VkConditionalRenderingFlagsEXT; +typedef VkFlags VkResolveModeFlags; +#define VkResolveModeFlagsKHR VkResolveModeFlags +typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT; +typedef VkFlags VkPipelineRasterizationDepthClipStateCreateFlagsEXT; +typedef VkFlags VkToolPurposeFlags; +#define VkToolPurposeFlagsEXT VkToolPurposeFlags +typedef VkFlags VkSubmitFlags; +#define VkSubmitFlagsKHR VkSubmitFlags +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkFlags VkImageFormatConstraintsFlagsFUCHSIA; +#endif + +typedef VkFlags VkHostImageCopyFlags; +#define VkHostImageCopyFlagsEXT VkHostImageCopyFlags +typedef VkFlags VkPartitionedAccelerationStructureInstanceFlagsNV; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkFlags VkImageConstraintsInfoFlagsFUCHSIA; +#endif + +typedef VkFlags VkGraphicsPipelineLibraryFlagsEXT; +typedef VkFlags VkImageCompressionFlagsEXT; +typedef VkFlags VkImageCompressionFixedRateFlagsEXT; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef VkFlags VkExportMetalObjectTypeFlagsEXT; +#endif + +typedef VkFlags VkDeviceAddressBindingFlagsEXT; +typedef VkFlags VkOpticalFlowGridSizeFlagsNV; +typedef VkFlags VkOpticalFlowUsageFlagsNV; +typedef VkFlags VkOpticalFlowSessionCreateFlagsNV; +typedef VkFlags VkOpticalFlowExecuteFlagsNV; +typedef VkFlags VkFrameBoundaryFlagsEXT; +typedef VkFlags VkPresentScalingFlagsEXT; +typedef VkFlags VkPresentGravityFlagsEXT; +typedef VkFlags VkShaderCreateFlagsEXT; +typedef VkFlags VkTileShadingRenderPassFlagsQCOM; +typedef VkFlags64 VkPhysicalDeviceSchedulingControlsFlagsARM; +typedef VkFlags64 VkAccessFlags3KHR; +typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* pUserData); +typedef struct VkDeviceQueueCreateInfo { VkStructureType sType; - const void * pNext; - VkDescriptorSetLayoutCreateFlags flags; - uint32_t bindingCount; - const VkDescriptorSetLayoutBinding * pBindings; -} VkDescriptorSetLayoutCreateInfo; + const void * pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueCount; + const float * pQueuePriorities; +} VkDeviceQueueCreateInfo; -typedef struct VkDescriptorPoolCreateInfo { +typedef struct VkInstanceCreateInfo { VkStructureType sType; - const void * pNext; - VkDescriptorPoolCreateFlags flags; - uint32_t maxSets; - uint32_t poolSizeCount; - const VkDescriptorPoolSize * pPoolSizes; -} VkDescriptorPoolCreateInfo; + const void * pNext; + VkInstanceCreateFlags flags; + const VkApplicationInfo * pApplicationInfo; + uint32_t enabledLayerCount; + const char * const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char * const* ppEnabledExtensionNames; +} VkInstanceCreateInfo; -typedef struct VkPipelineShaderStageCreateInfo { +typedef struct VkQueueFamilyProperties { + VkQueueFlags queueFlags; + uint32_t queueCount; + uint32_t timestampValidBits; + VkExtent3D minImageTransferGranularity; +} VkQueueFamilyProperties; + +typedef struct VkMemoryAllocateInfo { VkStructureType sType; const void * pNext; - VkPipelineShaderStageCreateFlags flags; - VkShaderStageFlagBits stage; - VkShaderModule module; - const char * pName; - const VkSpecializationInfo * pSpecializationInfo; -} VkPipelineShaderStageCreateInfo; + VkDeviceSize allocationSize; + uint32_t memoryTypeIndex; +} VkMemoryAllocateInfo; -typedef struct VkComputePipelineCreateInfo { +typedef struct VkMemoryRequirements { + VkDeviceSize size; + VkDeviceSize alignment; + uint32_t memoryTypeBits; +} VkMemoryRequirements; + +typedef struct VkSparseImageFormatProperties { + VkImageAspectFlags aspectMask; + VkExtent3D imageGranularity; + VkSparseImageFormatFlags flags; +} VkSparseImageFormatProperties; + +typedef struct VkSparseImageMemoryRequirements { + VkSparseImageFormatProperties formatProperties; + uint32_t imageMipTailFirstLod; + VkDeviceSize imageMipTailSize; + VkDeviceSize imageMipTailOffset; + VkDeviceSize imageMipTailStride; +} VkSparseImageMemoryRequirements; + +typedef struct VkMemoryType { + VkMemoryPropertyFlags propertyFlags; + uint32_t heapIndex; +} VkMemoryType; + +typedef struct VkMemoryHeap { + VkDeviceSize size; + VkMemoryHeapFlags flags; +} VkMemoryHeap; + +typedef struct VkMappedMemoryRange { VkStructureType sType; const void * pNext; - VkPipelineCreateFlags flags; - VkPipelineShaderStageCreateInfo stage; - VkPipelineLayout layout; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkComputePipelineCreateInfo; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; +} VkMappedMemoryRange; -typedef struct VkPipelineVertexInputStateCreateInfo { +typedef struct VkFormatProperties { + VkFormatFeatureFlags linearTilingFeatures; + VkFormatFeatureFlags optimalTilingFeatures; + VkFormatFeatureFlags bufferFeatures; +} VkFormatProperties; + +typedef struct VkImageFormatProperties { + VkExtent3D maxExtent; + uint32_t maxMipLevels; + uint32_t maxArrayLayers; + VkSampleCountFlags sampleCounts; + VkDeviceSize maxResourceSize; +} VkImageFormatProperties; + +typedef struct VkDescriptorBufferInfo { + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize range; +} VkDescriptorBufferInfo; + +typedef struct VkWriteDescriptorSet { VkStructureType sType; const void * pNext; - VkPipelineVertexInputStateCreateFlags flags; - uint32_t vertexBindingDescriptionCount; - const VkVertexInputBindingDescription * pVertexBindingDescriptions; - uint32_t vertexAttributeDescriptionCount; - const VkVertexInputAttributeDescription * pVertexAttributeDescriptions; -} VkPipelineVertexInputStateCreateInfo; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; + VkDescriptorType descriptorType; + const VkDescriptorImageInfo * pImageInfo; + const VkDescriptorBufferInfo * pBufferInfo; + const VkBufferView * pTexelBufferView; +} VkWriteDescriptorSet; -typedef struct VkPipelineInputAssemblyStateCreateInfo { +typedef struct VkBufferUsageFlags2CreateInfo { VkStructureType sType; - const void * pNext; - VkPipelineInputAssemblyStateCreateFlags flags; - VkPrimitiveTopology topology; - VkBool32 primitiveRestartEnable; -} VkPipelineInputAssemblyStateCreateInfo; + const void * pNext; + VkBufferUsageFlags2 usage; +} VkBufferUsageFlags2CreateInfo; -typedef struct VkPipelineTessellationStateCreateInfo { +typedef struct VkBufferUsageFlags2CreateInfo VkBufferUsageFlags2CreateInfoKHR; + +typedef struct VkBufferCreateInfo { VkStructureType sType; const void * pNext; - VkPipelineTessellationStateCreateFlags flags; - uint32_t patchControlPoints; -} VkPipelineTessellationStateCreateInfo; + VkBufferCreateFlags flags; + VkDeviceSize size; + VkBufferUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t * pQueueFamilyIndices; +} VkBufferCreateInfo; -typedef struct VkPipelineViewportStateCreateInfo { +typedef struct VkBufferViewCreateInfo { VkStructureType sType; const void * pNext; - VkPipelineViewportStateCreateFlags flags; - uint32_t viewportCount; - const VkViewport * pViewports; - uint32_t scissorCount; - const VkRect2D * pScissors; -} VkPipelineViewportStateCreateInfo; + VkBufferViewCreateFlags flags; + VkBuffer buffer; + VkFormat format; + VkDeviceSize offset; + VkDeviceSize range; +} VkBufferViewCreateInfo; -typedef struct VkPipelineRasterizationStateCreateInfo { - VkStructureType sType; - const void * pNext; - VkPipelineRasterizationStateCreateFlags flags; - VkBool32 depthClampEnable; - VkBool32 rasterizerDiscardEnable; - VkPolygonMode polygonMode; - VkCullModeFlags cullMode; - VkFrontFace frontFace; - VkBool32 depthBiasEnable; - float depthBiasConstantFactor; - float depthBiasClamp; - float depthBiasSlopeFactor; - float lineWidth; -} VkPipelineRasterizationStateCreateInfo; +typedef struct VkImageSubresource { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t arrayLayer; +} VkImageSubresource; -typedef struct VkPipelineMultisampleStateCreateInfo { - VkStructureType sType; - const void * pNext; - VkPipelineMultisampleStateCreateFlags flags; - VkSampleCountFlagBits rasterizationSamples; - VkBool32 sampleShadingEnable; - float minSampleShading; - const VkSampleMask * pSampleMask; - VkBool32 alphaToCoverageEnable; - VkBool32 alphaToOneEnable; -} VkPipelineMultisampleStateCreateInfo; +typedef struct VkImageSubresourceLayers { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceLayers; -typedef struct VkPipelineColorBlendAttachmentState { - VkBool32 blendEnable; - VkBlendFactor srcColorBlendFactor; - VkBlendFactor dstColorBlendFactor; - VkBlendOp colorBlendOp; - VkBlendFactor srcAlphaBlendFactor; - VkBlendFactor dstAlphaBlendFactor; - VkBlendOp alphaBlendOp; - VkColorComponentFlags colorWriteMask; -} VkPipelineColorBlendAttachmentState; +typedef struct VkImageSubresourceRange { + VkImageAspectFlags aspectMask; + uint32_t baseMipLevel; + uint32_t levelCount; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceRange; -typedef struct VkPipelineColorBlendStateCreateInfo { +typedef struct VkMemoryBarrier { VkStructureType sType; const void * pNext; - VkPipelineColorBlendStateCreateFlags flags; - VkBool32 logicOpEnable; - VkLogicOp logicOp; - uint32_t attachmentCount; - const VkPipelineColorBlendAttachmentState * pAttachments; - float blendConstants [4]; -} VkPipelineColorBlendStateCreateInfo; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; +} VkMemoryBarrier; -typedef struct VkPipelineDynamicStateCreateInfo { +typedef struct VkBufferMemoryBarrier { VkStructureType sType; const void * pNext; - VkPipelineDynamicStateCreateFlags flags; - uint32_t dynamicStateCount; - const VkDynamicState * pDynamicStates; -} VkPipelineDynamicStateCreateInfo; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier; -typedef struct VkPipelineDepthStencilStateCreateInfo { +typedef struct VkImageMemoryBarrier { VkStructureType sType; const void * pNext; - VkPipelineDepthStencilStateCreateFlags flags; - VkBool32 depthTestEnable; - VkBool32 depthWriteEnable; - VkCompareOp depthCompareOp; - VkBool32 depthBoundsTestEnable; - VkBool32 stencilTestEnable; - VkStencilOpState front; - VkStencilOpState back; - float minDepthBounds; - float maxDepthBounds; -} VkPipelineDepthStencilStateCreateInfo; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier; -typedef struct VkGraphicsPipelineCreateInfo { +typedef struct VkImageCreateInfo { VkStructureType sType; const void * pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo * pStages; - const VkPipelineVertexInputStateCreateInfo * pVertexInputState; - const VkPipelineInputAssemblyStateCreateInfo * pInputAssemblyState; - const VkPipelineTessellationStateCreateInfo * pTessellationState; - const VkPipelineViewportStateCreateInfo * pViewportState; - const VkPipelineRasterizationStateCreateInfo * pRasterizationState; - const VkPipelineMultisampleStateCreateInfo * pMultisampleState; - const VkPipelineDepthStencilStateCreateInfo * pDepthStencilState; - const VkPipelineColorBlendStateCreateInfo * pColorBlendState; - const VkPipelineDynamicStateCreateInfo * pDynamicState; - VkPipelineLayout layout; - VkRenderPass renderPass; - uint32_t subpass; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkGraphicsPipelineCreateInfo; + VkImageCreateFlags flags; + VkImageType imageType; + VkFormat format; + VkExtent3D extent; + uint32_t mipLevels; + uint32_t arrayLayers; + VkSampleCountFlagBits samples; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t * pQueueFamilyIndices; + VkImageLayout initialLayout; +} VkImageCreateInfo; -typedef struct VkPipelineCacheCreateInfo { +typedef struct VkSubresourceLayout { + VkDeviceSize offset; + VkDeviceSize size; + VkDeviceSize rowPitch; + VkDeviceSize arrayPitch; + VkDeviceSize depthPitch; +} VkSubresourceLayout; + +typedef struct VkImageViewCreateInfo { VkStructureType sType; const void * pNext; - VkPipelineCacheCreateFlags flags; - size_t initialDataSize; - const void * pInitialData; -} VkPipelineCacheCreateInfo; + VkImageViewCreateFlags flags; + VkImage image; + VkImageViewType viewType; + VkFormat format; + VkComponentMapping components; + VkImageSubresourceRange subresourceRange; +} VkImageViewCreateInfo; -typedef struct VkPushConstantRange { - VkShaderStageFlags stageFlags; - uint32_t offset; - uint32_t size; -} VkPushConstantRange; +typedef struct VkBufferCopy { + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy; -typedef struct VkPipelineLayoutCreateInfo { - VkStructureType sType; - const void * pNext; - VkPipelineLayoutCreateFlags flags; - uint32_t setLayoutCount; - const VkDescriptorSetLayout * pSetLayouts; - uint32_t pushConstantRangeCount; - const VkPushConstantRange * pPushConstantRanges; -} VkPipelineLayoutCreateInfo; +typedef struct VkSparseMemoryBind { + VkDeviceSize resourceOffset; + VkDeviceSize size; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseMemoryBind; -typedef struct VkSamplerCreateInfo { - VkStructureType sType; - const void * pNext; - VkSamplerCreateFlags flags; - VkFilter magFilter; - VkFilter minFilter; - VkSamplerMipmapMode mipmapMode; - VkSamplerAddressMode addressModeU; - VkSamplerAddressMode addressModeV; - VkSamplerAddressMode addressModeW; - float mipLodBias; - VkBool32 anisotropyEnable; - float maxAnisotropy; - VkBool32 compareEnable; - VkCompareOp compareOp; - float minLod; - float maxLod; - VkBorderColor borderColor; - VkBool32 unnormalizedCoordinates; -} VkSamplerCreateInfo; +typedef struct VkSparseImageMemoryBind { + VkImageSubresource subresource; + VkOffset3D offset; + VkExtent3D extent; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseImageMemoryBind; -typedef struct VkCommandPoolCreateInfo { - VkStructureType sType; - const void * pNext; - VkCommandPoolCreateFlags flags; - uint32_t queueFamilyIndex; -} VkCommandPoolCreateInfo; +typedef struct VkSparseBufferMemoryBindInfo { + VkBuffer buffer; + uint32_t bindCount; + const VkSparseMemoryBind * pBinds; +} VkSparseBufferMemoryBindInfo; -typedef struct VkCommandBufferInheritanceInfo { - VkStructureType sType; - const void * pNext; - VkRenderPass renderPass; - uint32_t subpass; - VkFramebuffer framebuffer; - VkBool32 occlusionQueryEnable; - VkQueryControlFlags queryFlags; - VkQueryPipelineStatisticFlags pipelineStatistics; -} VkCommandBufferInheritanceInfo; +typedef struct VkSparseImageOpaqueMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseMemoryBind * pBinds; +} VkSparseImageOpaqueMemoryBindInfo; -typedef struct VkCommandBufferBeginInfo { - VkStructureType sType; - const void * pNext; - VkCommandBufferUsageFlags flags; - const VkCommandBufferInheritanceInfo * pInheritanceInfo; -} VkCommandBufferBeginInfo; +typedef struct VkSparseImageMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseImageMemoryBind * pBinds; +} VkSparseImageMemoryBindInfo; -typedef struct VkRenderPassBeginInfo { +typedef struct VkBindSparseInfo { VkStructureType sType; const void * pNext; - VkRenderPass renderPass; - VkFramebuffer framebuffer; - VkRect2D renderArea; - uint32_t clearValueCount; - const VkClearValue * pClearValues; -} VkRenderPassBeginInfo; - -typedef struct VkClearAttachment { - VkImageAspectFlags aspectMask; - uint32_t colorAttachment; - VkClearValue clearValue; -} VkClearAttachment; + uint32_t waitSemaphoreCount; + const VkSemaphore * pWaitSemaphores; + uint32_t bufferBindCount; + const VkSparseBufferMemoryBindInfo * pBufferBinds; + uint32_t imageOpaqueBindCount; + const VkSparseImageOpaqueMemoryBindInfo * pImageOpaqueBinds; + uint32_t imageBindCount; + const VkSparseImageMemoryBindInfo * pImageBinds; + uint32_t signalSemaphoreCount; + const VkSemaphore * pSignalSemaphores; +} VkBindSparseInfo; -typedef struct VkAttachmentDescription { - VkAttachmentDescriptionFlags flags; - VkFormat format; - VkSampleCountFlagBits samples; - VkAttachmentLoadOp loadOp; +typedef struct VkImageCopy { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy; + +typedef struct VkImageBlit { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets [2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets [2]; +} VkImageBlit; + +typedef struct VkBufferImageCopy { + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy; + +typedef struct VkCopyMemoryIndirectCommandNV { + VkDeviceAddress srcAddress; + VkDeviceAddress dstAddress; + VkDeviceSize size; +} VkCopyMemoryIndirectCommandNV; + +typedef struct VkCopyMemoryToImageIndirectCommandNV { + VkDeviceAddress srcAddress; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkCopyMemoryToImageIndirectCommandNV; + +typedef struct VkImageResolve { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve; + +typedef struct VkShaderModuleCreateInfo { + VkStructureType sType; + const void * pNext; + VkShaderModuleCreateFlags flags; + size_t codeSize; + const uint32_t * pCode; +} VkShaderModuleCreateInfo; + +typedef struct VkDescriptorSetLayoutBinding { + uint32_t binding; + VkDescriptorType descriptorType; + uint32_t descriptorCount; + VkShaderStageFlags stageFlags; + const VkSampler * pImmutableSamplers; +} VkDescriptorSetLayoutBinding; + +typedef struct VkDescriptorSetLayoutCreateInfo { + VkStructureType sType; + const void * pNext; + VkDescriptorSetLayoutCreateFlags flags; + uint32_t bindingCount; + const VkDescriptorSetLayoutBinding * pBindings; +} VkDescriptorSetLayoutCreateInfo; + +typedef struct VkDescriptorPoolCreateInfo { + VkStructureType sType; + const void * pNext; + VkDescriptorPoolCreateFlags flags; + uint32_t maxSets; + uint32_t poolSizeCount; + const VkDescriptorPoolSize * pPoolSizes; +} VkDescriptorPoolCreateInfo; + +typedef struct VkPipelineShaderStageCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineShaderStageCreateFlags flags; + VkShaderStageFlagBits stage; + VkShaderModule module; + const char * pName; + const VkSpecializationInfo * pSpecializationInfo; +} VkPipelineShaderStageCreateInfo; + +typedef struct VkComputePipelineCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineCreateFlags flags; + VkPipelineShaderStageCreateInfo stage; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkComputePipelineCreateInfo; + +typedef struct VkComputePipelineIndirectBufferInfoNV { + VkStructureType sType; + const void * pNext; + VkDeviceAddress deviceAddress; + VkDeviceSize size; + VkDeviceAddress pipelineDeviceAddressCaptureReplay; +} VkComputePipelineIndirectBufferInfoNV; + +typedef struct VkPipelineCreateFlags2CreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineCreateFlags2 flags; +} VkPipelineCreateFlags2CreateInfo; + +typedef struct VkPipelineCreateFlags2CreateInfo VkPipelineCreateFlags2CreateInfoKHR; + +typedef struct VkPipelineVertexInputStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineVertexInputStateCreateFlags flags; + uint32_t vertexBindingDescriptionCount; + const VkVertexInputBindingDescription * pVertexBindingDescriptions; + uint32_t vertexAttributeDescriptionCount; + const VkVertexInputAttributeDescription * pVertexAttributeDescriptions; +} VkPipelineVertexInputStateCreateInfo; + +typedef struct VkPipelineInputAssemblyStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineInputAssemblyStateCreateFlags flags; + VkPrimitiveTopology topology; + VkBool32 primitiveRestartEnable; +} VkPipelineInputAssemblyStateCreateInfo; + +typedef struct VkPipelineTessellationStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineTessellationStateCreateFlags flags; + uint32_t patchControlPoints; +} VkPipelineTessellationStateCreateInfo; + +typedef struct VkPipelineViewportStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineViewportStateCreateFlags flags; + uint32_t viewportCount; + const VkViewport * pViewports; + uint32_t scissorCount; + const VkRect2D * pScissors; +} VkPipelineViewportStateCreateInfo; + +typedef struct VkPipelineRasterizationStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineRasterizationStateCreateFlags flags; + VkBool32 depthClampEnable; + VkBool32 rasterizerDiscardEnable; + VkPolygonMode polygonMode; + VkCullModeFlags cullMode; + VkFrontFace frontFace; + VkBool32 depthBiasEnable; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; + float lineWidth; +} VkPipelineRasterizationStateCreateInfo; + +typedef struct VkPipelineMultisampleStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineMultisampleStateCreateFlags flags; + VkSampleCountFlagBits rasterizationSamples; + VkBool32 sampleShadingEnable; + float minSampleShading; + const VkSampleMask * pSampleMask; + VkBool32 alphaToCoverageEnable; + VkBool32 alphaToOneEnable; +} VkPipelineMultisampleStateCreateInfo; + +typedef struct VkPipelineColorBlendAttachmentState { + VkBool32 blendEnable; + VkBlendFactor srcColorBlendFactor; + VkBlendFactor dstColorBlendFactor; + VkBlendOp colorBlendOp; + VkBlendFactor srcAlphaBlendFactor; + VkBlendFactor dstAlphaBlendFactor; + VkBlendOp alphaBlendOp; + VkColorComponentFlags colorWriteMask; +} VkPipelineColorBlendAttachmentState; + +typedef struct VkPipelineColorBlendStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineColorBlendStateCreateFlags flags; + VkBool32 logicOpEnable; + VkLogicOp logicOp; + uint32_t attachmentCount; + const VkPipelineColorBlendAttachmentState * pAttachments; + float blendConstants [4]; +} VkPipelineColorBlendStateCreateInfo; + +typedef struct VkPipelineDynamicStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineDynamicStateCreateFlags flags; + uint32_t dynamicStateCount; + const VkDynamicState * pDynamicStates; +} VkPipelineDynamicStateCreateInfo; + +typedef struct VkPipelineDepthStencilStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineDepthStencilStateCreateFlags flags; + VkBool32 depthTestEnable; + VkBool32 depthWriteEnable; + VkCompareOp depthCompareOp; + VkBool32 depthBoundsTestEnable; + VkBool32 stencilTestEnable; + VkStencilOpState front; + VkStencilOpState back; + float minDepthBounds; + float maxDepthBounds; +} VkPipelineDepthStencilStateCreateInfo; + +typedef struct VkGraphicsPipelineCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo * pStages; + const VkPipelineVertexInputStateCreateInfo * pVertexInputState; + const VkPipelineInputAssemblyStateCreateInfo * pInputAssemblyState; + const VkPipelineTessellationStateCreateInfo * pTessellationState; + const VkPipelineViewportStateCreateInfo * pViewportState; + const VkPipelineRasterizationStateCreateInfo * pRasterizationState; + const VkPipelineMultisampleStateCreateInfo * pMultisampleState; + const VkPipelineDepthStencilStateCreateInfo * pDepthStencilState; + const VkPipelineColorBlendStateCreateInfo * pColorBlendState; + const VkPipelineDynamicStateCreateInfo * pDynamicState; + VkPipelineLayout layout; + VkRenderPass renderPass; + uint32_t subpass; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkGraphicsPipelineCreateInfo; + +typedef struct VkPipelineCacheCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineCacheCreateFlags flags; + size_t initialDataSize; + const void * pInitialData; +} VkPipelineCacheCreateInfo; + +typedef struct VkPushConstantRange { + VkShaderStageFlags stageFlags; + uint32_t offset; + uint32_t size; +} VkPushConstantRange; + +typedef struct VkPipelineBinaryKeysAndDataKHR { + uint32_t binaryCount; + const VkPipelineBinaryKeyKHR * pPipelineBinaryKeys; + const VkPipelineBinaryDataKHR * pPipelineBinaryData; +} VkPipelineBinaryKeysAndDataKHR; + +typedef struct VkPipelineLayoutCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineLayoutCreateFlags flags; + uint32_t setLayoutCount; + const VkDescriptorSetLayout * pSetLayouts; + uint32_t pushConstantRangeCount; + const VkPushConstantRange * pPushConstantRanges; +} VkPipelineLayoutCreateInfo; + +typedef struct VkSamplerCreateInfo { + VkStructureType sType; + const void * pNext; + VkSamplerCreateFlags flags; + VkFilter magFilter; + VkFilter minFilter; + VkSamplerMipmapMode mipmapMode; + VkSamplerAddressMode addressModeU; + VkSamplerAddressMode addressModeV; + VkSamplerAddressMode addressModeW; + float mipLodBias; + VkBool32 anisotropyEnable; + float maxAnisotropy; + VkBool32 compareEnable; + VkCompareOp compareOp; + float minLod; + float maxLod; + VkBorderColor borderColor; + VkBool32 unnormalizedCoordinates; +} VkSamplerCreateInfo; + +typedef struct VkCommandPoolCreateInfo { + VkStructureType sType; + const void * pNext; + VkCommandPoolCreateFlags flags; + uint32_t queueFamilyIndex; +} VkCommandPoolCreateInfo; + +typedef struct VkCommandBufferInheritanceInfo { + VkStructureType sType; + const void * pNext; + VkRenderPass renderPass; + uint32_t subpass; + VkFramebuffer framebuffer; + VkBool32 occlusionQueryEnable; + VkQueryControlFlags queryFlags; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkCommandBufferInheritanceInfo; + +typedef struct VkCommandBufferBeginInfo { + VkStructureType sType; + const void * pNext; + VkCommandBufferUsageFlags flags; + const VkCommandBufferInheritanceInfo * pInheritanceInfo; +} VkCommandBufferBeginInfo; + +typedef struct VkRenderPassBeginInfo { + VkStructureType sType; + const void * pNext; + VkRenderPass renderPass; + VkFramebuffer framebuffer; + VkRect2D renderArea; + uint32_t clearValueCount; + const VkClearValue * pClearValues; +} VkRenderPassBeginInfo; + +typedef struct VkClearAttachment { + VkImageAspectFlags aspectMask; + uint32_t colorAttachment; + VkClearValue clearValue; +} VkClearAttachment; + +typedef struct VkAttachmentDescription { + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; VkAttachmentStoreOp storeOp; VkAttachmentLoadOp stencilLoadOp; VkAttachmentStoreOp stencilStoreOp; @@ -6114,2670 +10018,5789 @@ typedef struct VkAttachmentDescription { VkImageLayout finalLayout; } VkAttachmentDescription; -typedef struct VkSubpassDescription { - VkSubpassDescriptionFlags flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t inputAttachmentCount; - const VkAttachmentReference * pInputAttachments; - uint32_t colorAttachmentCount; - const VkAttachmentReference * pColorAttachments; - const VkAttachmentReference * pResolveAttachments; - const VkAttachmentReference * pDepthStencilAttachment; - uint32_t preserveAttachmentCount; - const uint32_t * pPreserveAttachments; -} VkSubpassDescription; +typedef struct VkSubpassDescription { + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t inputAttachmentCount; + const VkAttachmentReference * pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference * pColorAttachments; + const VkAttachmentReference * pResolveAttachments; + const VkAttachmentReference * pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t * pPreserveAttachments; +} VkSubpassDescription; + +typedef struct VkSubpassDependency { + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; +} VkSubpassDependency; + +typedef struct VkRenderPassCreateInfo { + VkStructureType sType; + const void * pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription * pAttachments; + uint32_t subpassCount; + const VkSubpassDescription * pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency * pDependencies; +} VkRenderPassCreateInfo; + +typedef struct VkEventCreateInfo { + VkStructureType sType; + const void * pNext; + VkEventCreateFlags flags; +} VkEventCreateInfo; + +typedef struct VkFenceCreateInfo { + VkStructureType sType; + const void * pNext; + VkFenceCreateFlags flags; +} VkFenceCreateInfo; + +typedef struct VkPhysicalDeviceFeatures { + VkBool32 robustBufferAccess; + VkBool32 fullDrawIndexUint32; + VkBool32 imageCubeArray; + VkBool32 independentBlend; + VkBool32 geometryShader; + VkBool32 tessellationShader; + VkBool32 sampleRateShading; + VkBool32 dualSrcBlend; + VkBool32 logicOp; + VkBool32 multiDrawIndirect; + VkBool32 drawIndirectFirstInstance; + VkBool32 depthClamp; + VkBool32 depthBiasClamp; + VkBool32 fillModeNonSolid; + VkBool32 depthBounds; + VkBool32 wideLines; + VkBool32 largePoints; + VkBool32 alphaToOne; + VkBool32 multiViewport; + VkBool32 samplerAnisotropy; + VkBool32 textureCompressionETC2; + VkBool32 textureCompressionASTC_LDR; + VkBool32 textureCompressionBC; + VkBool32 occlusionQueryPrecise; + VkBool32 pipelineStatisticsQuery; + VkBool32 vertexPipelineStoresAndAtomics; + VkBool32 fragmentStoresAndAtomics; + VkBool32 shaderTessellationAndGeometryPointSize; + VkBool32 shaderImageGatherExtended; + VkBool32 shaderStorageImageExtendedFormats; + VkBool32 shaderStorageImageMultisample; + VkBool32 shaderStorageImageReadWithoutFormat; + VkBool32 shaderStorageImageWriteWithoutFormat; + VkBool32 shaderUniformBufferArrayDynamicIndexing; + VkBool32 shaderSampledImageArrayDynamicIndexing; + VkBool32 shaderStorageBufferArrayDynamicIndexing; + VkBool32 shaderStorageImageArrayDynamicIndexing; + VkBool32 shaderClipDistance; + VkBool32 shaderCullDistance; + VkBool32 shaderFloat64; + VkBool32 shaderInt64; + VkBool32 shaderInt16; + VkBool32 shaderResourceResidency; + VkBool32 shaderResourceMinLod; + VkBool32 sparseBinding; + VkBool32 sparseResidencyBuffer; + VkBool32 sparseResidencyImage2D; + VkBool32 sparseResidencyImage3D; + VkBool32 sparseResidency2Samples; + VkBool32 sparseResidency4Samples; + VkBool32 sparseResidency8Samples; + VkBool32 sparseResidency16Samples; + VkBool32 sparseResidencyAliased; + VkBool32 variableMultisampleRate; + VkBool32 inheritedQueries; +} VkPhysicalDeviceFeatures; + +typedef struct VkPhysicalDeviceSparseProperties { + VkBool32 residencyStandard2DBlockShape; + VkBool32 residencyStandard2DMultisampleBlockShape; + VkBool32 residencyStandard3DBlockShape; + VkBool32 residencyAlignedMipSize; + VkBool32 residencyNonResidentStrict; +} VkPhysicalDeviceSparseProperties; + +typedef struct VkPhysicalDeviceLimits { + uint32_t maxImageDimension1D; + uint32_t maxImageDimension2D; + uint32_t maxImageDimension3D; + uint32_t maxImageDimensionCube; + uint32_t maxImageArrayLayers; + uint32_t maxTexelBufferElements; + uint32_t maxUniformBufferRange; + uint32_t maxStorageBufferRange; + uint32_t maxPushConstantsSize; + uint32_t maxMemoryAllocationCount; + uint32_t maxSamplerAllocationCount; + VkDeviceSize bufferImageGranularity; + VkDeviceSize sparseAddressSpaceSize; + uint32_t maxBoundDescriptorSets; + uint32_t maxPerStageDescriptorSamplers; + uint32_t maxPerStageDescriptorUniformBuffers; + uint32_t maxPerStageDescriptorStorageBuffers; + uint32_t maxPerStageDescriptorSampledImages; + uint32_t maxPerStageDescriptorStorageImages; + uint32_t maxPerStageDescriptorInputAttachments; + uint32_t maxPerStageResources; + uint32_t maxDescriptorSetSamplers; + uint32_t maxDescriptorSetUniformBuffers; + uint32_t maxDescriptorSetUniformBuffersDynamic; + uint32_t maxDescriptorSetStorageBuffers; + uint32_t maxDescriptorSetStorageBuffersDynamic; + uint32_t maxDescriptorSetSampledImages; + uint32_t maxDescriptorSetStorageImages; + uint32_t maxDescriptorSetInputAttachments; + uint32_t maxVertexInputAttributes; + uint32_t maxVertexInputBindings; + uint32_t maxVertexInputAttributeOffset; + uint32_t maxVertexInputBindingStride; + uint32_t maxVertexOutputComponents; + uint32_t maxTessellationGenerationLevel; + uint32_t maxTessellationPatchSize; + uint32_t maxTessellationControlPerVertexInputComponents; + uint32_t maxTessellationControlPerVertexOutputComponents; + uint32_t maxTessellationControlPerPatchOutputComponents; + uint32_t maxTessellationControlTotalOutputComponents; + uint32_t maxTessellationEvaluationInputComponents; + uint32_t maxTessellationEvaluationOutputComponents; + uint32_t maxGeometryShaderInvocations; + uint32_t maxGeometryInputComponents; + uint32_t maxGeometryOutputComponents; + uint32_t maxGeometryOutputVertices; + uint32_t maxGeometryTotalOutputComponents; + uint32_t maxFragmentInputComponents; + uint32_t maxFragmentOutputAttachments; + uint32_t maxFragmentDualSrcAttachments; + uint32_t maxFragmentCombinedOutputResources; + uint32_t maxComputeSharedMemorySize; + uint32_t maxComputeWorkGroupCount [3]; + uint32_t maxComputeWorkGroupInvocations; + uint32_t maxComputeWorkGroupSize [3]; + uint32_t subPixelPrecisionBits; + uint32_t subTexelPrecisionBits; + uint32_t mipmapPrecisionBits; + uint32_t maxDrawIndexedIndexValue; + uint32_t maxDrawIndirectCount; + float maxSamplerLodBias; + float maxSamplerAnisotropy; + uint32_t maxViewports; + uint32_t maxViewportDimensions [2]; + float viewportBoundsRange [2]; + uint32_t viewportSubPixelBits; + size_t minMemoryMapAlignment; + VkDeviceSize minTexelBufferOffsetAlignment; + VkDeviceSize minUniformBufferOffsetAlignment; + VkDeviceSize minStorageBufferOffsetAlignment; + int32_t minTexelOffset; + uint32_t maxTexelOffset; + int32_t minTexelGatherOffset; + uint32_t maxTexelGatherOffset; + float minInterpolationOffset; + float maxInterpolationOffset; + uint32_t subPixelInterpolationOffsetBits; + uint32_t maxFramebufferWidth; + uint32_t maxFramebufferHeight; + uint32_t maxFramebufferLayers; + VkSampleCountFlags framebufferColorSampleCounts; + VkSampleCountFlags framebufferDepthSampleCounts; + VkSampleCountFlags framebufferStencilSampleCounts; + VkSampleCountFlags framebufferNoAttachmentsSampleCounts; + uint32_t maxColorAttachments; + VkSampleCountFlags sampledImageColorSampleCounts; + VkSampleCountFlags sampledImageIntegerSampleCounts; + VkSampleCountFlags sampledImageDepthSampleCounts; + VkSampleCountFlags sampledImageStencilSampleCounts; + VkSampleCountFlags storageImageSampleCounts; + uint32_t maxSampleMaskWords; + VkBool32 timestampComputeAndGraphics; + float timestampPeriod; + uint32_t maxClipDistances; + uint32_t maxCullDistances; + uint32_t maxCombinedClipAndCullDistances; + uint32_t discreteQueuePriorities; + float pointSizeRange [2]; + float lineWidthRange [2]; + float pointSizeGranularity; + float lineWidthGranularity; + VkBool32 strictLines; + VkBool32 standardSampleLocations; + VkDeviceSize optimalBufferCopyOffsetAlignment; + VkDeviceSize optimalBufferCopyRowPitchAlignment; + VkDeviceSize nonCoherentAtomSize; +} VkPhysicalDeviceLimits; + +typedef struct VkSemaphoreCreateInfo { + VkStructureType sType; + const void * pNext; + VkSemaphoreCreateFlags flags; +} VkSemaphoreCreateInfo; + +typedef struct VkQueryPoolCreateInfo { + VkStructureType sType; + const void * pNext; + VkQueryPoolCreateFlags flags; + VkQueryType queryType; + uint32_t queryCount; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkQueryPoolCreateInfo; + +typedef struct VkFramebufferCreateInfo { + VkStructureType sType; + const void * pNext; + VkFramebufferCreateFlags flags; + VkRenderPass renderPass; + uint32_t attachmentCount; + const VkImageView * pAttachments; + uint32_t width; + uint32_t height; + uint32_t layers; +} VkFramebufferCreateInfo; + +typedef struct VkSubmitInfo { + VkStructureType sType; + const void * pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore * pWaitSemaphores; + const VkPipelineStageFlags * pWaitDstStageMask; + uint32_t commandBufferCount; + const VkCommandBuffer * pCommandBuffers; + uint32_t signalSemaphoreCount; + const VkSemaphore * pSignalSemaphores; +} VkSubmitInfo; + +typedef struct VkDisplayPropertiesKHR { + VkDisplayKHR display; + const char * displayName; + VkExtent2D physicalDimensions; + VkExtent2D physicalResolution; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkBool32 planeReorderPossible; + VkBool32 persistentContent; +} VkDisplayPropertiesKHR; + +typedef struct VkDisplayModeCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkDisplayModeCreateFlagsKHR flags; + VkDisplayModeParametersKHR parameters; +} VkDisplayModeCreateInfoKHR; + +typedef struct VkDisplayPlaneCapabilitiesKHR { + VkDisplayPlaneAlphaFlagsKHR supportedAlpha; + VkOffset2D minSrcPosition; + VkOffset2D maxSrcPosition; + VkExtent2D minSrcExtent; + VkExtent2D maxSrcExtent; + VkOffset2D minDstPosition; + VkOffset2D maxDstPosition; + VkExtent2D minDstExtent; + VkExtent2D maxDstExtent; +} VkDisplayPlaneCapabilitiesKHR; + +typedef struct VkDisplaySurfaceCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkDisplaySurfaceCreateFlagsKHR flags; + VkDisplayModeKHR displayMode; + uint32_t planeIndex; + uint32_t planeStackIndex; + VkSurfaceTransformFlagBitsKHR transform; + float globalAlpha; + VkDisplayPlaneAlphaFlagBitsKHR alphaMode; + VkExtent2D imageExtent; +} VkDisplaySurfaceCreateInfoKHR; + +typedef struct VkDisplayPresentInfoKHR { + VkStructureType sType; + const void * pNext; + VkRect2D srcRect; + VkRect2D dstRect; + VkBool32 persistent; +} VkDisplayPresentInfoKHR; + +typedef struct VkSurfaceCapabilitiesKHR { + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; +} VkSurfaceCapabilitiesKHR; + +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef struct VkAndroidSurfaceCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkAndroidSurfaceCreateFlagsKHR flags; + struct ANativeWindow * window; +} VkAndroidSurfaceCreateInfoKHR; + +#endif + +#if defined(VK_USE_PLATFORM_VI_NN) +typedef struct VkViSurfaceCreateInfoNN { + VkStructureType sType; + const void * pNext; + VkViSurfaceCreateFlagsNN flags; + void * window; +} VkViSurfaceCreateInfoNN; + +#endif + +#if defined(VK_USE_PLATFORM_WAYLAND_KHR) +typedef struct VkWaylandSurfaceCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + struct wl_display * display; + struct wl_surface * surface; +} VkWaylandSurfaceCreateInfoKHR; + +#endif + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkWin32SurfaceCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkWin32SurfaceCreateFlagsKHR flags; + HINSTANCE hinstance; + HWND hwnd; +} VkWin32SurfaceCreateInfoKHR; + +#endif + +#if defined(VK_USE_PLATFORM_XLIB_KHR) +typedef struct VkXlibSurfaceCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display * dpy; + Window window; +} VkXlibSurfaceCreateInfoKHR; + +#endif + +#if defined(VK_USE_PLATFORM_XCB_KHR) +typedef struct VkXcbSurfaceCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t * connection; + xcb_window_t window; +} VkXcbSurfaceCreateInfoKHR; + +#endif + +#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) +typedef struct VkDirectFBSurfaceCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkDirectFBSurfaceCreateFlagsEXT flags; + IDirectFB * dfb; + IDirectFBSurface * surface; +} VkDirectFBSurfaceCreateInfoEXT; + +#endif + +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkImagePipeSurfaceCreateInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkImagePipeSurfaceCreateFlagsFUCHSIA flags; + zx_handle_t imagePipeHandle; +} VkImagePipeSurfaceCreateInfoFUCHSIA; + +#endif + +#if defined(VK_USE_PLATFORM_GGP) +typedef struct VkStreamDescriptorSurfaceCreateInfoGGP { + VkStructureType sType; + const void * pNext; + VkStreamDescriptorSurfaceCreateFlagsGGP flags; + GgpStreamDescriptor streamDescriptor; +} VkStreamDescriptorSurfaceCreateInfoGGP; + +#endif + +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef struct VkScreenSurfaceCreateInfoQNX { + VkStructureType sType; + const void * pNext; + VkScreenSurfaceCreateFlagsQNX flags; + struct _screen_context * context; + struct _screen_window * window; +} VkScreenSurfaceCreateInfoQNX; + +#endif + +typedef struct VkSwapchainCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkSwapchainCreateFlagsKHR flags; + VkSurfaceKHR surface; + uint32_t minImageCount; + VkFormat imageFormat; + VkColorSpaceKHR imageColorSpace; + VkExtent2D imageExtent; + uint32_t imageArrayLayers; + VkImageUsageFlags imageUsage; + VkSharingMode imageSharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t * pQueueFamilyIndices; + VkSurfaceTransformFlagBitsKHR preTransform; + VkCompositeAlphaFlagBitsKHR compositeAlpha; + VkPresentModeKHR presentMode; + VkBool32 clipped; + VkSwapchainKHR oldSwapchain; +} VkSwapchainCreateInfoKHR; + +typedef struct VkDebugReportCallbackCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkDebugReportFlagsEXT flags; + PFN_vkDebugReportCallbackEXT pfnCallback; + void * pUserData; +} VkDebugReportCallbackCreateInfoEXT; + +typedef struct VkLayerSettingsCreateInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t settingCount; + const VkLayerSettingEXT * pSettings; +} VkLayerSettingsCreateInfoEXT; + +typedef struct VkDedicatedAllocationImageCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkBool32 dedicatedAllocation; +} VkDedicatedAllocationImageCreateInfoNV; + +typedef struct VkDedicatedAllocationBufferCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkBool32 dedicatedAllocation; +} VkDedicatedAllocationBufferCreateInfoNV; + +typedef struct VkExternalImageFormatPropertiesNV { + VkImageFormatProperties imageFormatProperties; + VkExternalMemoryFeatureFlagsNV externalMemoryFeatures; + VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes; + VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes; +} VkExternalImageFormatPropertiesNV; + +typedef struct VkExternalMemoryImageCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlagsNV handleTypes; +} VkExternalMemoryImageCreateInfoNV; + +typedef struct VkExportMemoryAllocateInfoNV { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlagsNV handleTypes; +} VkExportMemoryAllocateInfoNV; + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkImportMemoryWin32HandleInfoNV { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlagsNV handleType; + HANDLE handle; +} VkImportMemoryWin32HandleInfoNV; + +#endif + +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 deviceGeneratedCommands; +} VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV; + +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsComputeFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 deviceGeneratedCompute; + VkBool32 deviceGeneratedComputePipelines; + VkBool32 deviceGeneratedComputeCaptureReplay; +} VkPhysicalDeviceDeviceGeneratedCommandsComputeFeaturesNV; + +typedef struct VkPrivateDataSlotCreateInfo { + VkStructureType sType; + const void * pNext; + VkPrivateDataSlotCreateFlags flags; +} VkPrivateDataSlotCreateInfo; + +typedef struct VkPrivateDataSlotCreateInfo VkPrivateDataSlotCreateInfoEXT; + +typedef struct VkPhysicalDevicePrivateDataFeatures { + VkStructureType sType; + void * pNext; + VkBool32 privateData; +} VkPhysicalDevicePrivateDataFeatures; + +typedef struct VkPhysicalDevicePrivateDataFeatures VkPhysicalDevicePrivateDataFeaturesEXT; + +typedef struct VkPhysicalDeviceClusterAccelerationStructureFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 clusterAccelerationStructure; +} VkPhysicalDeviceClusterAccelerationStructureFeaturesNV; + +typedef struct VkStridedDeviceAddressNV { + VkDeviceAddress startAddress; + VkDeviceSize strideInBytes; +} VkStridedDeviceAddressNV; + +typedef struct VkRayTracingPipelineClusterAccelerationStructureCreateInfoNV { + VkStructureType sType; + void * pNext; + VkBool32 allowClusterAccelerationStructure; +} VkRayTracingPipelineClusterAccelerationStructureCreateInfoNV; + +typedef struct VkClusterAccelerationStructureMoveObjectsInfoNV { + VkDeviceAddress srcAccelerationStructure; +} VkClusterAccelerationStructureMoveObjectsInfoNV; + +typedef struct VkClusterAccelerationStructureBuildClustersBottomLevelInfoNV { + uint32_t clusterReferencesCount; + uint32_t clusterReferencesStride; + VkDeviceAddress clusterReferences; +} VkClusterAccelerationStructureBuildClustersBottomLevelInfoNV; + +typedef struct VkClusterAccelerationStructureBuildTriangleClusterInfoNV { + uint32_t clusterID; + VkClusterAccelerationStructureClusterFlagsNV clusterFlags; + uint32_t triangleCount :9; + uint32_t vertexCount :9; + uint32_t positionTruncateBitCount :6; + uint32_t indexType :4; + uint32_t opacityMicromapIndexType :4; + VkClusterAccelerationStructureGeometryIndexAndGeometryFlagsNV baseGeometryIndexAndGeometryFlags; + uint16_t indexBufferStride; + uint16_t vertexBufferStride; + uint16_t geometryIndexAndFlagsBufferStride; + uint16_t opacityMicromapIndexBufferStride; + VkDeviceAddress indexBuffer; + VkDeviceAddress vertexBuffer; + VkDeviceAddress geometryIndexAndFlagsBuffer; + VkDeviceAddress opacityMicromapArray; + VkDeviceAddress opacityMicromapIndexBuffer; +} VkClusterAccelerationStructureBuildTriangleClusterInfoNV; + +typedef struct VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV { + uint32_t clusterID; + VkClusterAccelerationStructureClusterFlagsNV clusterFlags; + uint32_t triangleCount :9; + uint32_t vertexCount :9; + uint32_t positionTruncateBitCount :6; + uint32_t indexType :4; + uint32_t opacityMicromapIndexType :4; + VkClusterAccelerationStructureGeometryIndexAndGeometryFlagsNV baseGeometryIndexAndGeometryFlags; + uint16_t indexBufferStride; + uint16_t vertexBufferStride; + uint16_t geometryIndexAndFlagsBufferStride; + uint16_t opacityMicromapIndexBufferStride; + VkDeviceAddress indexBuffer; + VkDeviceAddress vertexBuffer; + VkDeviceAddress geometryIndexAndFlagsBuffer; + VkDeviceAddress opacityMicromapArray; + VkDeviceAddress opacityMicromapIndexBuffer; + VkDeviceAddress instantiationBoundingBoxLimit; +} VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV; + +typedef struct VkClusterAccelerationStructureInstantiateClusterInfoNV { + uint32_t clusterIdOffset; + uint32_t geometryIndexOffset :24; + uint32_t reserved :8; + VkDeviceAddress clusterTemplateAddress; + VkStridedDeviceAddressNV vertexBuffer; +} VkClusterAccelerationStructureInstantiateClusterInfoNV; + +typedef struct VkClusterAccelerationStructureMoveObjectsInputNV { + VkStructureType sType; + void * pNext; + VkClusterAccelerationStructureTypeNV type; + VkBool32 noMoveOverlap; + VkDeviceSize maxMovedBytes; +} VkClusterAccelerationStructureMoveObjectsInputNV; + +typedef union VkClusterAccelerationStructureOpInputNV { + VkClusterAccelerationStructureClustersBottomLevelInputNV * pClustersBottomLevel; + VkClusterAccelerationStructureTriangleClusterInputNV * pTriangleClusters; + VkClusterAccelerationStructureMoveObjectsInputNV * pMoveObjects; +} VkClusterAccelerationStructureOpInputNV; + +typedef struct VkClusterAccelerationStructureInputInfoNV { + VkStructureType sType; + void * pNext; + uint32_t maxAccelerationStructureCount; + VkBuildAccelerationStructureFlagsKHR flags; + VkClusterAccelerationStructureOpTypeNV opType; + VkClusterAccelerationStructureOpModeNV opMode; + VkClusterAccelerationStructureOpInputNV opInput; +} VkClusterAccelerationStructureInputInfoNV; + +typedef struct VkGraphicsShaderGroupCreateInfoNV { + VkStructureType sType; + const void * pNext; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo * pStages; + const VkPipelineVertexInputStateCreateInfo * pVertexInputState; + const VkPipelineTessellationStateCreateInfo * pTessellationState; +} VkGraphicsShaderGroupCreateInfoNV; + +typedef struct VkGraphicsPipelineShaderGroupsCreateInfoNV { + VkStructureType sType; + const void * pNext; + uint32_t groupCount; + const VkGraphicsShaderGroupCreateInfoNV * pGroups; + uint32_t pipelineCount; + const VkPipeline * pPipelines; +} VkGraphicsPipelineShaderGroupsCreateInfoNV; + +typedef struct VkBindIndexBufferIndirectCommandNV { + VkDeviceAddress bufferAddress; + uint32_t size; + VkIndexType indexType; +} VkBindIndexBufferIndirectCommandNV; + +typedef struct VkBindVertexBufferIndirectCommandNV { + VkDeviceAddress bufferAddress; + uint32_t size; + uint32_t stride; +} VkBindVertexBufferIndirectCommandNV; + +typedef struct VkIndirectCommandsStreamNV { + VkBuffer buffer; + VkDeviceSize offset; +} VkIndirectCommandsStreamNV; + +typedef struct VkIndirectCommandsLayoutTokenNV { + VkStructureType sType; + const void * pNext; + VkIndirectCommandsTokenTypeNV tokenType; + uint32_t stream; + uint32_t offset; + uint32_t vertexBindingUnit; + VkBool32 vertexDynamicStride; + VkPipelineLayout pushconstantPipelineLayout; + VkShaderStageFlags pushconstantShaderStageFlags; + uint32_t pushconstantOffset; + uint32_t pushconstantSize; + VkIndirectStateFlagsNV indirectStateFlags; + uint32_t indexTypeCount; + const VkIndexType * pIndexTypes; + const uint32_t * pIndexTypeValues; +} VkIndirectCommandsLayoutTokenNV; + +typedef struct VkIndirectCommandsLayoutCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkIndirectCommandsLayoutUsageFlagsNV flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t tokenCount; + const VkIndirectCommandsLayoutTokenNV * pTokens; + uint32_t streamCount; + const uint32_t * pStreamStrides; +} VkIndirectCommandsLayoutCreateInfoNV; + +typedef struct VkGeneratedCommandsInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; + VkIndirectCommandsLayoutNV indirectCommandsLayout; + uint32_t streamCount; + const VkIndirectCommandsStreamNV * pStreams; + uint32_t sequencesCount; + VkBuffer preprocessBuffer; + VkDeviceSize preprocessOffset; + VkDeviceSize preprocessSize; + VkBuffer sequencesCountBuffer; + VkDeviceSize sequencesCountOffset; + VkBuffer sequencesIndexBuffer; + VkDeviceSize sequencesIndexOffset; +} VkGeneratedCommandsInfoNV; + +typedef struct VkBindPipelineIndirectCommandNV { + VkDeviceAddress pipelineAddress; +} VkBindPipelineIndirectCommandNV; + +typedef struct VkPhysicalDeviceFeatures2 { + VkStructureType sType; + void * pNext; + VkPhysicalDeviceFeatures features; +} VkPhysicalDeviceFeatures2; + +typedef struct VkPhysicalDeviceFeatures2 VkPhysicalDeviceFeatures2KHR; + +typedef struct VkFormatProperties2 { + VkStructureType sType; + void * pNext; + VkFormatProperties formatProperties; +} VkFormatProperties2; + +typedef struct VkFormatProperties2 VkFormatProperties2KHR; + +typedef struct VkImageFormatProperties2 { + VkStructureType sType; + void * pNext; + VkImageFormatProperties imageFormatProperties; +} VkImageFormatProperties2; + +typedef struct VkImageFormatProperties2 VkImageFormatProperties2KHR; + +typedef struct VkPhysicalDeviceImageFormatInfo2 { + VkStructureType sType; + const void * pNext; + VkFormat format; + VkImageType type; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkImageCreateFlags flags; +} VkPhysicalDeviceImageFormatInfo2; + +typedef struct VkPhysicalDeviceImageFormatInfo2 VkPhysicalDeviceImageFormatInfo2KHR; + +typedef struct VkQueueFamilyProperties2 { + VkStructureType sType; + void * pNext; + VkQueueFamilyProperties queueFamilyProperties; +} VkQueueFamilyProperties2; + +typedef struct VkQueueFamilyProperties2 VkQueueFamilyProperties2KHR; + +typedef struct VkSparseImageFormatProperties2 { + VkStructureType sType; + void * pNext; + VkSparseImageFormatProperties properties; +} VkSparseImageFormatProperties2; + +typedef struct VkSparseImageFormatProperties2 VkSparseImageFormatProperties2KHR; + +typedef struct VkPhysicalDeviceSparseImageFormatInfo2 { + VkStructureType sType; + const void * pNext; + VkFormat format; + VkImageType type; + VkSampleCountFlagBits samples; + VkImageUsageFlags usage; + VkImageTiling tiling; +} VkPhysicalDeviceSparseImageFormatInfo2; + +typedef struct VkPhysicalDeviceSparseImageFormatInfo2 VkPhysicalDeviceSparseImageFormatInfo2KHR; + +typedef struct VkPresentRegionKHR { + uint32_t rectangleCount; + const VkRectLayerKHR * pRectangles; +} VkPresentRegionKHR; + +typedef struct VkPhysicalDeviceVariablePointersFeatures { + VkStructureType sType; + void * pNext; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; +} VkPhysicalDeviceVariablePointersFeatures; + +typedef struct VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointersFeaturesKHR; + +typedef struct VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeaturesKHR; + +typedef struct VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeatures; + +typedef struct VkExternalMemoryProperties { + VkExternalMemoryFeatureFlags externalMemoryFeatures; + VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes; + VkExternalMemoryHandleTypeFlags compatibleHandleTypes; +} VkExternalMemoryProperties; + +typedef struct VkExternalMemoryProperties VkExternalMemoryPropertiesKHR; + +typedef struct VkExternalImageFormatProperties { + VkStructureType sType; + void * pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalImageFormatProperties; + +typedef struct VkExternalImageFormatProperties VkExternalImageFormatPropertiesKHR; + +typedef struct VkPhysicalDeviceExternalBufferInfo { + VkStructureType sType; + const void * pNext; + VkBufferCreateFlags flags; + VkBufferUsageFlags usage; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalBufferInfo; + +typedef struct VkPhysicalDeviceExternalBufferInfo VkPhysicalDeviceExternalBufferInfoKHR; + +typedef struct VkExternalBufferProperties { + VkStructureType sType; + void * pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalBufferProperties; + +typedef struct VkExternalBufferProperties VkExternalBufferPropertiesKHR; + +typedef struct VkPhysicalDeviceIDProperties { + VkStructureType sType; + void * pNext; + uint8_t deviceUUID [ VK_UUID_SIZE ]; + uint8_t driverUUID [ VK_UUID_SIZE ]; + uint8_t deviceLUID [ VK_LUID_SIZE ]; + uint32_t deviceNodeMask; + VkBool32 deviceLUIDValid; +} VkPhysicalDeviceIDProperties; + +typedef struct VkPhysicalDeviceIDProperties VkPhysicalDeviceIDPropertiesKHR; + +typedef struct VkExternalMemoryImageCreateInfo { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryImageCreateInfo; + +typedef struct VkExternalMemoryImageCreateInfo VkExternalMemoryImageCreateInfoKHR; + +typedef struct VkExternalMemoryBufferCreateInfo { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryBufferCreateInfo; + +typedef struct VkExternalMemoryBufferCreateInfo VkExternalMemoryBufferCreateInfoKHR; + +typedef struct VkExportMemoryAllocateInfo { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExportMemoryAllocateInfo; + +typedef struct VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR; + +typedef struct VkExternalSemaphoreProperties { + VkStructureType sType; + void * pNext; + VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes; + VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes; + VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures; +} VkExternalSemaphoreProperties; + +typedef struct VkExternalSemaphoreProperties VkExternalSemaphorePropertiesKHR; + +typedef struct VkExportSemaphoreCreateInfo { + VkStructureType sType; + const void * pNext; + VkExternalSemaphoreHandleTypeFlags handleTypes; +} VkExportSemaphoreCreateInfo; + +typedef struct VkExportSemaphoreCreateInfo VkExportSemaphoreCreateInfoKHR; + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkImportSemaphoreWin32HandleInfoKHR { + VkStructureType sType; + const void * pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + HANDLE handle; + LPCWSTR name; +} VkImportSemaphoreWin32HandleInfoKHR; + +#endif + +typedef struct VkImportSemaphoreFdInfoKHR { + VkStructureType sType; + const void * pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + int fd; +} VkImportSemaphoreFdInfoKHR; + +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkImportSemaphoreZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + zx_handle_t zirconHandle; +} VkImportSemaphoreZirconHandleInfoFUCHSIA; + +#endif + +typedef struct VkExternalFenceProperties { + VkStructureType sType; + void * pNext; + VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes; + VkExternalFenceHandleTypeFlags compatibleHandleTypes; + VkExternalFenceFeatureFlags externalFenceFeatures; +} VkExternalFenceProperties; + +typedef struct VkExternalFenceProperties VkExternalFencePropertiesKHR; + +typedef struct VkExportFenceCreateInfo { + VkStructureType sType; + const void * pNext; + VkExternalFenceHandleTypeFlags handleTypes; +} VkExportFenceCreateInfo; + +typedef struct VkExportFenceCreateInfo VkExportFenceCreateInfoKHR; + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkImportFenceWin32HandleInfoKHR { + VkStructureType sType; + const void * pNext; + VkFence fence; + VkFenceImportFlags flags; + VkExternalFenceHandleTypeFlagBits handleType; + HANDLE handle; + LPCWSTR name; +} VkImportFenceWin32HandleInfoKHR; + +#endif + +typedef struct VkImportFenceFdInfoKHR { + VkStructureType sType; + const void * pNext; + VkFence fence; + VkFenceImportFlags flags; + VkExternalFenceHandleTypeFlagBits handleType; + int fd; +} VkImportFenceFdInfoKHR; + +typedef struct VkPhysicalDeviceMultiviewFeatures { + VkStructureType sType; + void * pNext; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; +} VkPhysicalDeviceMultiviewFeatures; + +typedef struct VkPhysicalDeviceMultiviewFeatures VkPhysicalDeviceMultiviewFeaturesKHR; + +typedef struct VkSurfaceCapabilities2EXT { + VkStructureType sType; + void * pNext; + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; + VkSurfaceCounterFlagsEXT supportedSurfaceCounters; +} VkSurfaceCapabilities2EXT; + +typedef struct VkSwapchainCounterCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkSurfaceCounterFlagsEXT surfaceCounters; +} VkSwapchainCounterCreateInfoEXT; + +typedef struct VkPhysicalDeviceGroupProperties { + VkStructureType sType; + void * pNext; + uint32_t physicalDeviceCount; + VkPhysicalDevice physicalDevices [ VK_MAX_DEVICE_GROUP_SIZE ]; + VkBool32 subsetAllocation; +} VkPhysicalDeviceGroupProperties; + +typedef struct VkPhysicalDeviceGroupProperties VkPhysicalDeviceGroupPropertiesKHR; + +typedef struct VkMemoryAllocateFlagsInfo { + VkStructureType sType; + const void * pNext; + VkMemoryAllocateFlags flags; + uint32_t deviceMask; +} VkMemoryAllocateFlagsInfo; + +typedef struct VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR; + +typedef struct VkBindBufferMemoryInfo { + VkStructureType sType; + const void * pNext; + VkBuffer buffer; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindBufferMemoryInfo; + +typedef struct VkBindBufferMemoryInfo VkBindBufferMemoryInfoKHR; + +typedef struct VkBindImageMemoryInfo { + VkStructureType sType; + const void * pNext; + VkImage image; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindImageMemoryInfo; + +typedef struct VkBindImageMemoryInfo VkBindImageMemoryInfoKHR; + +typedef struct VkDeviceGroupPresentCapabilitiesKHR { + VkStructureType sType; + void * pNext; + uint32_t presentMask [ VK_MAX_DEVICE_GROUP_SIZE ]; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupPresentCapabilitiesKHR; + +typedef struct VkDeviceGroupSwapchainCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupSwapchainCreateInfoKHR; + +typedef struct VkDescriptorUpdateTemplateCreateInfo { + VkStructureType sType; + const void * pNext; + VkDescriptorUpdateTemplateCreateFlags flags; + uint32_t descriptorUpdateEntryCount; + const VkDescriptorUpdateTemplateEntry * pDescriptorUpdateEntries; + VkDescriptorUpdateTemplateType templateType; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineBindPoint pipelineBindPoint; + VkPipelineLayout pipelineLayout; + uint32_t set; +} VkDescriptorUpdateTemplateCreateInfo; + +typedef struct VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR; + +typedef struct VkPhysicalDevicePresentIdFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 presentId; +} VkPhysicalDevicePresentIdFeaturesKHR; + +typedef struct VkPhysicalDevicePresentWaitFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 presentWait; +} VkPhysicalDevicePresentWaitFeaturesKHR; + +typedef struct VkDisplayNativeHdrSurfaceCapabilitiesAMD { + VkStructureType sType; + void * pNext; + VkBool32 localDimmingSupport; +} VkDisplayNativeHdrSurfaceCapabilitiesAMD; + +typedef struct VkSwapchainDisplayNativeHdrCreateInfoAMD { + VkStructureType sType; + const void * pNext; + VkBool32 localDimmingEnable; +} VkSwapchainDisplayNativeHdrCreateInfoAMD; + +typedef struct VkPresentTimesInfoGOOGLE { + VkStructureType sType; + const void * pNext; + uint32_t swapchainCount; + const VkPresentTimeGOOGLE * pTimes; +} VkPresentTimesInfoGOOGLE; + +#if defined(VK_USE_PLATFORM_IOS_MVK) +typedef struct VkIOSSurfaceCreateInfoMVK { + VkStructureType sType; + const void * pNext; + VkIOSSurfaceCreateFlagsMVK flags; + const void * pView; +} VkIOSSurfaceCreateInfoMVK; + +#endif + +#if defined(VK_USE_PLATFORM_MACOS_MVK) +typedef struct VkMacOSSurfaceCreateInfoMVK { + VkStructureType sType; + const void * pNext; + VkMacOSSurfaceCreateFlagsMVK flags; + const void * pView; +} VkMacOSSurfaceCreateInfoMVK; + +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkMetalSurfaceCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkMetalSurfaceCreateFlagsEXT flags; + const CAMetalLayer * pLayer; +} VkMetalSurfaceCreateInfoEXT; + +#endif + +typedef struct VkPipelineViewportWScalingStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkBool32 viewportWScalingEnable; + uint32_t viewportCount; + const VkViewportWScalingNV * pViewportWScalings; +} VkPipelineViewportWScalingStateCreateInfoNV; + +typedef struct VkPipelineViewportSwizzleStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineViewportSwizzleStateCreateFlagsNV flags; + uint32_t viewportCount; + const VkViewportSwizzleNV * pViewportSwizzles; +} VkPipelineViewportSwizzleStateCreateInfoNV; + +typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkPipelineDiscardRectangleStateCreateFlagsEXT flags; + VkDiscardRectangleModeEXT discardRectangleMode; + uint32_t discardRectangleCount; + const VkRect2D * pDiscardRectangles; +} VkPipelineDiscardRectangleStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX { + VkStructureType sType; + void * pNext; + VkBool32 perViewPositionAllComponents; +} VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX; + +typedef struct VkInputAttachmentAspectReference { + uint32_t subpass; + uint32_t inputAttachmentIndex; + VkImageAspectFlags aspectMask; +} VkInputAttachmentAspectReference; + +typedef struct VkInputAttachmentAspectReference VkInputAttachmentAspectReferenceKHR; + +typedef struct VkRenderPassInputAttachmentAspectCreateInfo { + VkStructureType sType; + const void * pNext; + uint32_t aspectReferenceCount; + const VkInputAttachmentAspectReference * pAspectReferences; +} VkRenderPassInputAttachmentAspectCreateInfo; + +typedef struct VkRenderPassInputAttachmentAspectCreateInfo VkRenderPassInputAttachmentAspectCreateInfoKHR; + +typedef struct VkSurfaceCapabilities2KHR { + VkStructureType sType; + void * pNext; + VkSurfaceCapabilitiesKHR surfaceCapabilities; +} VkSurfaceCapabilities2KHR; + +typedef struct VkDisplayProperties2KHR { + VkStructureType sType; + void * pNext; + VkDisplayPropertiesKHR displayProperties; +} VkDisplayProperties2KHR; + +typedef struct VkDisplayModeStereoPropertiesNV { + VkStructureType sType; + const void * pNext; + VkBool32 hdmi3DSupported; +} VkDisplayModeStereoPropertiesNV; + +typedef struct VkDisplayPlaneCapabilities2KHR { + VkStructureType sType; + void * pNext; + VkDisplayPlaneCapabilitiesKHR capabilities; +} VkDisplayPlaneCapabilities2KHR; + +typedef struct VkSharedPresentSurfaceCapabilitiesKHR { + VkStructureType sType; + void * pNext; + VkImageUsageFlags sharedPresentSupportedUsageFlags; +} VkSharedPresentSurfaceCapabilitiesKHR; + +typedef struct VkPhysicalDevice16BitStorageFeatures { + VkStructureType sType; + void * pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; +} VkPhysicalDevice16BitStorageFeatures; + +typedef struct VkPhysicalDevice16BitStorageFeatures VkPhysicalDevice16BitStorageFeaturesKHR; + +typedef struct VkPhysicalDeviceSubgroupProperties { + VkStructureType sType; + void * pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; + +typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures { + VkStructureType sType; + void * pNext; + VkBool32 shaderSubgroupExtendedTypes; +} VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures; + +typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR; + +typedef struct VkDeviceBufferMemoryRequirements { + VkStructureType sType; + const void * pNext; + const VkBufferCreateInfo * pCreateInfo; +} VkDeviceBufferMemoryRequirements; + +typedef struct VkDeviceBufferMemoryRequirements VkDeviceBufferMemoryRequirementsKHR; + +typedef struct VkDeviceImageMemoryRequirements { + VkStructureType sType; + const void * pNext; + const VkImageCreateInfo * pCreateInfo; + VkImageAspectFlagBits planeAspect; +} VkDeviceImageMemoryRequirements; + +typedef struct VkDeviceImageMemoryRequirements VkDeviceImageMemoryRequirementsKHR; + +typedef struct VkMemoryRequirements2 { + VkStructureType sType; + void * pNext; + VkMemoryRequirements memoryRequirements; +} VkMemoryRequirements2; + +typedef struct VkMemoryRequirements2 VkMemoryRequirements2KHR; + +typedef struct VkSparseImageMemoryRequirements2 { + VkStructureType sType; + void * pNext; + VkSparseImageMemoryRequirements memoryRequirements; +} VkSparseImageMemoryRequirements2; + +typedef struct VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR; + +typedef struct VkMemoryDedicatedRequirements { + VkStructureType sType; + void * pNext; + VkBool32 prefersDedicatedAllocation; + VkBool32 requiresDedicatedAllocation; +} VkMemoryDedicatedRequirements; + +typedef struct VkMemoryDedicatedRequirements VkMemoryDedicatedRequirementsKHR; + +typedef struct VkImageViewUsageCreateInfo { + VkStructureType sType; + const void * pNext; + VkImageUsageFlags usage; +} VkImageViewUsageCreateInfo; + +typedef struct VkImageViewUsageCreateInfo VkImageViewUsageCreateInfoKHR; + +typedef struct VkSamplerYcbcrConversionCreateInfo { + VkStructureType sType; + const void * pNext; + VkFormat format; + VkSamplerYcbcrModelConversion ycbcrModel; + VkSamplerYcbcrRange ycbcrRange; + VkComponentMapping components; + VkChromaLocation xChromaOffset; + VkChromaLocation yChromaOffset; + VkFilter chromaFilter; + VkBool32 forceExplicitReconstruction; +} VkSamplerYcbcrConversionCreateInfo; + +typedef struct VkSamplerYcbcrConversionCreateInfo VkSamplerYcbcrConversionCreateInfoKHR; + +typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures { + VkStructureType sType; + void * pNext; + VkBool32 samplerYcbcrConversion; +} VkPhysicalDeviceSamplerYcbcrConversionFeatures; + +typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR; + +typedef struct VkTextureLODGatherFormatPropertiesAMD { + VkStructureType sType; + void * pNext; + VkBool32 supportsTextureGatherLODBiasAMD; +} VkTextureLODGatherFormatPropertiesAMD; + +typedef struct VkConditionalRenderingBeginInfoEXT { + VkStructureType sType; + const void * pNext; + VkBuffer buffer; + VkDeviceSize offset; + VkConditionalRenderingFlagsEXT flags; +} VkConditionalRenderingBeginInfoEXT; + +typedef struct VkProtectedSubmitInfo { + VkStructureType sType; + const void * pNext; + VkBool32 protectedSubmit; +} VkProtectedSubmitInfo; + +typedef struct VkPhysicalDeviceProtectedMemoryFeatures { + VkStructureType sType; + void * pNext; + VkBool32 protectedMemory; +} VkPhysicalDeviceProtectedMemoryFeatures; + +typedef struct VkPhysicalDeviceProtectedMemoryProperties { + VkStructureType sType; + void * pNext; + VkBool32 protectedNoFault; +} VkPhysicalDeviceProtectedMemoryProperties; + +typedef struct VkDeviceQueueInfo2 { + VkStructureType sType; + const void * pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueIndex; +} VkDeviceQueueInfo2; + +typedef struct VkPipelineCoverageToColorStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineCoverageToColorStateCreateFlagsNV flags; + VkBool32 coverageToColorEnable; + uint32_t coverageToColorLocation; +} VkPipelineCoverageToColorStateCreateInfoNV; + +typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties { + VkStructureType sType; + void * pNext; + VkBool32 filterMinmaxSingleComponentFormats; + VkBool32 filterMinmaxImageComponentMapping; +} VkPhysicalDeviceSamplerFilterMinmaxProperties; + +typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT; + +typedef struct VkPipelineSampleLocationsStateCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkBool32 sampleLocationsEnable; + VkSampleLocationsInfoEXT sampleLocationsInfo; +} VkPipelineSampleLocationsStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceSampleLocationsPropertiesEXT { + VkStructureType sType; + void * pNext; + VkSampleCountFlags sampleLocationSampleCounts; + VkExtent2D maxSampleLocationGridSize; + float sampleLocationCoordinateRange [2]; + uint32_t sampleLocationSubPixelBits; + VkBool32 variableSampleLocations; +} VkPhysicalDeviceSampleLocationsPropertiesEXT; + +typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 advancedBlendCoherentOperations; +} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT; + +typedef struct VkPhysicalDeviceMultiDrawFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 multiDraw; +} VkPhysicalDeviceMultiDrawFeaturesEXT; + +typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t advancedBlendMaxColorAttachments; + VkBool32 advancedBlendIndependentBlend; + VkBool32 advancedBlendNonPremultipliedSrcColor; + VkBool32 advancedBlendNonPremultipliedDstColor; + VkBool32 advancedBlendCorrelatedOverlap; + VkBool32 advancedBlendAllOperations; +} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT; + +typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkBool32 srcPremultiplied; + VkBool32 dstPremultiplied; + VkBlendOverlapEXT blendOverlap; +} VkPipelineColorBlendAdvancedStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceInlineUniformBlockFeatures { + VkStructureType sType; + void * pNext; + VkBool32 inlineUniformBlock; + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; +} VkPhysicalDeviceInlineUniformBlockFeatures; + +typedef struct VkPhysicalDeviceInlineUniformBlockFeatures VkPhysicalDeviceInlineUniformBlockFeaturesEXT; + +typedef struct VkPipelineCoverageModulationStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineCoverageModulationStateCreateFlagsNV flags; + VkCoverageModulationModeNV coverageModulationMode; + VkBool32 coverageModulationTableEnable; + uint32_t coverageModulationTableCount; + const float * pCoverageModulationTable; +} VkPipelineCoverageModulationStateCreateInfoNV; + +typedef struct VkValidationCacheCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkValidationCacheCreateFlagsEXT flags; + size_t initialDataSize; + const void * pInitialData; +} VkValidationCacheCreateInfoEXT; + +typedef struct VkPhysicalDeviceMaintenance3Properties { + VkStructureType sType; + void * pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; + +typedef struct VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; + +typedef struct VkPhysicalDeviceMaintenance4Features { + VkStructureType sType; + void * pNext; + VkBool32 maintenance4; +} VkPhysicalDeviceMaintenance4Features; + +typedef struct VkPhysicalDeviceMaintenance4Features VkPhysicalDeviceMaintenance4FeaturesKHR; + +typedef struct VkPhysicalDeviceMaintenance4Properties { + VkStructureType sType; + void * pNext; + VkDeviceSize maxBufferSize; +} VkPhysicalDeviceMaintenance4Properties; + +typedef struct VkPhysicalDeviceMaintenance4Properties VkPhysicalDeviceMaintenance4PropertiesKHR; + +typedef struct VkPhysicalDeviceMaintenance5Features { + VkStructureType sType; + void * pNext; + VkBool32 maintenance5; +} VkPhysicalDeviceMaintenance5Features; + +typedef struct VkPhysicalDeviceMaintenance5Features VkPhysicalDeviceMaintenance5FeaturesKHR; + +typedef struct VkPhysicalDeviceMaintenance5Properties { + VkStructureType sType; + void * pNext; + VkBool32 earlyFragmentMultisampleCoverageAfterSampleCounting; + VkBool32 earlyFragmentSampleMaskTestBeforeSampleCounting; + VkBool32 depthStencilSwizzleOneSupport; + VkBool32 polygonModePointSize; + VkBool32 nonStrictSinglePixelWideLinesUseParallelogram; + VkBool32 nonStrictWideLinesUseParallelogram; +} VkPhysicalDeviceMaintenance5Properties; + +typedef struct VkPhysicalDeviceMaintenance5Properties VkPhysicalDeviceMaintenance5PropertiesKHR; + +typedef struct VkPhysicalDeviceMaintenance6Features { + VkStructureType sType; + void * pNext; + VkBool32 maintenance6; +} VkPhysicalDeviceMaintenance6Features; + +typedef struct VkPhysicalDeviceMaintenance6Features VkPhysicalDeviceMaintenance6FeaturesKHR; + +typedef struct VkPhysicalDeviceMaintenance6Properties { + VkStructureType sType; + void * pNext; + VkBool32 blockTexelViewCompatibleMultipleLayers; + uint32_t maxCombinedImageSamplerDescriptorCount; + VkBool32 fragmentShadingRateClampCombinerInputs; +} VkPhysicalDeviceMaintenance6Properties; + +typedef struct VkPhysicalDeviceMaintenance6Properties VkPhysicalDeviceMaintenance6PropertiesKHR; + +typedef struct VkPhysicalDeviceMaintenance7FeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 maintenance7; +} VkPhysicalDeviceMaintenance7FeaturesKHR; + +typedef struct VkPhysicalDeviceMaintenance7PropertiesKHR { + VkStructureType sType; + void * pNext; + VkBool32 robustFragmentShadingRateAttachmentAccess; + VkBool32 separateDepthStencilAttachmentAccess; + uint32_t maxDescriptorSetTotalUniformBuffersDynamic; + uint32_t maxDescriptorSetTotalStorageBuffersDynamic; + uint32_t maxDescriptorSetTotalBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindTotalUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindTotalStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindTotalBuffersDynamic; +} VkPhysicalDeviceMaintenance7PropertiesKHR; + +typedef struct VkPhysicalDeviceLayeredApiPropertiesListKHR { + VkStructureType sType; + void * pNext; + uint32_t layeredApiCount; + VkPhysicalDeviceLayeredApiPropertiesKHR * pLayeredApis; +} VkPhysicalDeviceLayeredApiPropertiesListKHR; + +typedef struct VkPhysicalDeviceMaintenance8FeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 maintenance8; +} VkPhysicalDeviceMaintenance8FeaturesKHR; + +typedef struct VkDescriptorSetLayoutSupport { + VkStructureType sType; + void * pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; + +typedef struct VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; + +typedef struct VkPhysicalDeviceShaderDrawParametersFeatures { + VkStructureType sType; + void * pNext; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceShaderDrawParametersFeatures; + +typedef struct VkPhysicalDeviceShaderDrawParametersFeatures VkPhysicalDeviceShaderDrawParameterFeatures; + +typedef struct VkPhysicalDeviceShaderFloat16Int8Features { + VkStructureType sType; + void * pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceShaderFloat16Int8Features; + +typedef struct VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceShaderFloat16Int8FeaturesKHR; + +typedef struct VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceFloat16Int8FeaturesKHR; + +typedef struct VkPhysicalDeviceFloatControlsProperties { + VkStructureType sType; + void * pNext; + VkShaderFloatControlsIndependence denormBehaviorIndependence; + VkShaderFloatControlsIndependence roundingModeIndependence; + VkBool32 shaderSignedZeroInfNanPreserveFloat16; + VkBool32 shaderSignedZeroInfNanPreserveFloat32; + VkBool32 shaderSignedZeroInfNanPreserveFloat64; + VkBool32 shaderDenormPreserveFloat16; + VkBool32 shaderDenormPreserveFloat32; + VkBool32 shaderDenormPreserveFloat64; + VkBool32 shaderDenormFlushToZeroFloat16; + VkBool32 shaderDenormFlushToZeroFloat32; + VkBool32 shaderDenormFlushToZeroFloat64; + VkBool32 shaderRoundingModeRTEFloat16; + VkBool32 shaderRoundingModeRTEFloat32; + VkBool32 shaderRoundingModeRTEFloat64; + VkBool32 shaderRoundingModeRTZFloat16; + VkBool32 shaderRoundingModeRTZFloat32; + VkBool32 shaderRoundingModeRTZFloat64; +} VkPhysicalDeviceFloatControlsProperties; + +typedef struct VkPhysicalDeviceFloatControlsProperties VkPhysicalDeviceFloatControlsPropertiesKHR; + +typedef struct VkPhysicalDeviceHostQueryResetFeatures { + VkStructureType sType; + void * pNext; + VkBool32 hostQueryReset; +} VkPhysicalDeviceHostQueryResetFeatures; + +typedef struct VkPhysicalDeviceHostQueryResetFeatures VkPhysicalDeviceHostQueryResetFeaturesEXT; + +typedef struct VkShaderStatisticsInfoAMD { + VkShaderStageFlags shaderStageMask; + VkShaderResourceUsageAMD resourceUsage; + uint32_t numPhysicalVgprs; + uint32_t numPhysicalSgprs; + uint32_t numAvailableVgprs; + uint32_t numAvailableSgprs; + uint32_t computeWorkGroupSize [3]; +} VkShaderStatisticsInfoAMD; + +typedef struct VkPhysicalDeviceGlobalPriorityQueryFeatures { + VkStructureType sType; + void * pNext; + VkBool32 globalPriorityQuery; +} VkPhysicalDeviceGlobalPriorityQueryFeatures; + +typedef struct VkPhysicalDeviceGlobalPriorityQueryFeatures VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR; + +typedef struct VkPhysicalDeviceGlobalPriorityQueryFeatures VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT; + +typedef struct VkDebugUtilsMessengerCallbackDataEXT { + VkStructureType sType; + const void * pNext; + VkDebugUtilsMessengerCallbackDataFlagsEXT flags; + const char * pMessageIdName; + int32_t messageIdNumber; + const char * pMessage; + uint32_t queueLabelCount; + const VkDebugUtilsLabelEXT * pQueueLabels; + uint32_t cmdBufLabelCount; + const VkDebugUtilsLabelEXT * pCmdBufLabels; + uint32_t objectCount; + const VkDebugUtilsObjectNameInfoEXT * pObjects; +} VkDebugUtilsMessengerCallbackDataEXT; + +typedef struct VkPhysicalDeviceDeviceMemoryReportFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 deviceMemoryReport; +} VkPhysicalDeviceDeviceMemoryReportFeaturesEXT; + +typedef struct VkDeviceMemoryReportCallbackDataEXT { + VkStructureType sType; + void * pNext; + VkDeviceMemoryReportFlagsEXT flags; + VkDeviceMemoryReportEventTypeEXT type; + uint64_t memoryObjectId; + VkDeviceSize size; + VkObjectType objectType; + uint64_t objectHandle; + uint32_t heapIndex; +} VkDeviceMemoryReportCallbackDataEXT; + +typedef struct VkPhysicalDeviceExternalMemoryHostPropertiesEXT { + VkStructureType sType; + void * pNext; + VkDeviceSize minImportedHostPointerAlignment; +} VkPhysicalDeviceExternalMemoryHostPropertiesEXT; + +typedef struct VkPhysicalDeviceConservativeRasterizationPropertiesEXT { + VkStructureType sType; + void * pNext; + float primitiveOverestimationSize; + float maxExtraPrimitiveOverestimationSize; + float extraPrimitiveOverestimationSizeGranularity; + VkBool32 primitiveUnderestimation; + VkBool32 conservativePointAndLineRasterization; + VkBool32 degenerateTrianglesRasterized; + VkBool32 degenerateLinesRasterized; + VkBool32 fullyCoveredFragmentShaderInputVariable; + VkBool32 conservativeRasterizationPostDepthCoverage; +} VkPhysicalDeviceConservativeRasterizationPropertiesEXT; + +typedef struct VkPhysicalDeviceShaderCoreProperties2AMD { + VkStructureType sType; + void * pNext; + VkShaderCorePropertiesFlagsAMD shaderCoreFeatures; + uint32_t activeComputeUnitCount; +} VkPhysicalDeviceShaderCoreProperties2AMD; + +typedef struct VkPipelineRasterizationConservativeStateCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkPipelineRasterizationConservativeStateCreateFlagsEXT flags; + VkConservativeRasterizationModeEXT conservativeRasterizationMode; + float extraPrimitiveOverestimationSize; +} VkPipelineRasterizationConservativeStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceDescriptorIndexingFeatures { + VkStructureType sType; + void * pNext; + VkBool32 shaderInputAttachmentArrayDynamicIndexing; + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; + VkBool32 shaderUniformBufferArrayNonUniformIndexing; + VkBool32 shaderSampledImageArrayNonUniformIndexing; + VkBool32 shaderStorageBufferArrayNonUniformIndexing; + VkBool32 shaderStorageImageArrayNonUniformIndexing; + VkBool32 shaderInputAttachmentArrayNonUniformIndexing; + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; + VkBool32 descriptorBindingUniformBufferUpdateAfterBind; + VkBool32 descriptorBindingSampledImageUpdateAfterBind; + VkBool32 descriptorBindingStorageImageUpdateAfterBind; + VkBool32 descriptorBindingStorageBufferUpdateAfterBind; + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingUpdateUnusedWhilePending; + VkBool32 descriptorBindingPartiallyBound; + VkBool32 descriptorBindingVariableDescriptorCount; + VkBool32 runtimeDescriptorArray; +} VkPhysicalDeviceDescriptorIndexingFeatures; + +typedef struct VkPhysicalDeviceDescriptorIndexingFeatures VkPhysicalDeviceDescriptorIndexingFeaturesEXT; + +typedef struct VkPhysicalDeviceDescriptorIndexingProperties { + VkStructureType sType; + void * pNext; + uint32_t maxUpdateAfterBindDescriptorsInAllPools; + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; + VkBool32 shaderSampledImageArrayNonUniformIndexingNative; + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; + VkBool32 shaderStorageImageArrayNonUniformIndexingNative; + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; + VkBool32 robustBufferAccessUpdateAfterBind; + VkBool32 quadDivergentImplicitLod; + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; + uint32_t maxPerStageUpdateAfterBindResources; + uint32_t maxDescriptorSetUpdateAfterBindSamplers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindSampledImages; + uint32_t maxDescriptorSetUpdateAfterBindStorageImages; + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; +} VkPhysicalDeviceDescriptorIndexingProperties; + +typedef struct VkPhysicalDeviceDescriptorIndexingProperties VkPhysicalDeviceDescriptorIndexingPropertiesEXT; + +typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo { + VkStructureType sType; + const void * pNext; + uint32_t bindingCount; + const VkDescriptorBindingFlags * pBindingFlags; +} VkDescriptorSetLayoutBindingFlagsCreateInfo; + +typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo VkDescriptorSetLayoutBindingFlagsCreateInfoEXT; + +typedef struct VkAttachmentDescription2 { + VkStructureType sType; + const void * pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2; + +typedef struct VkAttachmentDescription2 VkAttachmentDescription2KHR; + +typedef struct VkAttachmentReference2 { + VkStructureType sType; + const void * pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2; + +typedef struct VkAttachmentReference2 VkAttachmentReference2KHR; + +typedef struct VkSubpassDescription2 { + VkStructureType sType; + const void * pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2 * pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2 * pColorAttachments; + const VkAttachmentReference2 * pResolveAttachments; + const VkAttachmentReference2 * pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t * pPreserveAttachments; +} VkSubpassDescription2; + +typedef struct VkSubpassDescription2 VkSubpassDescription2KHR; + +typedef struct VkSubpassDependency2 { + VkStructureType sType; + const void * pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2; + +typedef struct VkSubpassDependency2 VkSubpassDependency2KHR; + +typedef struct VkRenderPassCreateInfo2 { + VkStructureType sType; + const void * pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2 * pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2 * pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2 * pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t * pCorrelatedViewMasks; +} VkRenderPassCreateInfo2; + +typedef struct VkRenderPassCreateInfo2 VkRenderPassCreateInfo2KHR; + +typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures { + VkStructureType sType; + void * pNext; + VkBool32 timelineSemaphore; +} VkPhysicalDeviceTimelineSemaphoreFeatures; + +typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures VkPhysicalDeviceTimelineSemaphoreFeaturesKHR; + +typedef struct VkSemaphoreWaitInfo { + VkStructureType sType; + const void * pNext; + VkSemaphoreWaitFlags flags; + uint32_t semaphoreCount; + const VkSemaphore * pSemaphores; + const uint64_t * pValues; +} VkSemaphoreWaitInfo; + +typedef struct VkSemaphoreWaitInfo VkSemaphoreWaitInfoKHR; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorProperties { + VkStructureType sType; + void * pNext; + uint32_t maxVertexAttribDivisor; + VkBool32 supportsNonZeroFirstInstance; +} VkPhysicalDeviceVertexAttributeDivisorProperties; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorProperties VkPhysicalDeviceVertexAttributeDivisorPropertiesKHR; + +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef struct VkAndroidHardwareBufferPropertiesANDROID { + VkStructureType sType; + void * pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeBits; +} VkAndroidHardwareBufferPropertiesANDROID; + +#endif + +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID { + VkStructureType sType; + void * pNext; + VkFormat format; + uint64_t externalFormat; + VkFormatFeatureFlags formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkAndroidHardwareBufferFormatPropertiesANDROID; + +#endif + +typedef struct VkCommandBufferInheritanceConditionalRenderingInfoEXT { + VkStructureType sType; + const void * pNext; + VkBool32 conditionalRenderingEnable; +} VkCommandBufferInheritanceConditionalRenderingInfoEXT; + +typedef struct VkPhysicalDevice8BitStorageFeatures { + VkStructureType sType; + void * pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeatures; + +typedef struct VkPhysicalDevice8BitStorageFeatures VkPhysicalDevice8BitStorageFeaturesKHR; + +typedef struct VkPhysicalDeviceConditionalRenderingFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 conditionalRendering; + VkBool32 inheritedConditionalRendering; +} VkPhysicalDeviceConditionalRenderingFeaturesEXT; + +typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures { + VkStructureType sType; + void * pNext; + VkBool32 vulkanMemoryModel; + VkBool32 vulkanMemoryModelDeviceScope; + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; +} VkPhysicalDeviceVulkanMemoryModelFeatures; + +typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures VkPhysicalDeviceVulkanMemoryModelFeaturesKHR; + +typedef struct VkPhysicalDeviceShaderAtomicInt64Features { + VkStructureType sType; + void * pNext; + VkBool32 shaderBufferInt64Atomics; + VkBool32 shaderSharedInt64Atomics; +} VkPhysicalDeviceShaderAtomicInt64Features; + +typedef struct VkPhysicalDeviceShaderAtomicInt64Features VkPhysicalDeviceShaderAtomicInt64FeaturesKHR; + +typedef struct VkPhysicalDeviceShaderAtomicFloatFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 shaderBufferFloat32Atomics; + VkBool32 shaderBufferFloat32AtomicAdd; + VkBool32 shaderBufferFloat64Atomics; + VkBool32 shaderBufferFloat64AtomicAdd; + VkBool32 shaderSharedFloat32Atomics; + VkBool32 shaderSharedFloat32AtomicAdd; + VkBool32 shaderSharedFloat64Atomics; + VkBool32 shaderSharedFloat64AtomicAdd; + VkBool32 shaderImageFloat32Atomics; + VkBool32 shaderImageFloat32AtomicAdd; + VkBool32 sparseImageFloat32Atomics; + VkBool32 sparseImageFloat32AtomicAdd; +} VkPhysicalDeviceShaderAtomicFloatFeaturesEXT; + +typedef struct VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 shaderBufferFloat16Atomics; + VkBool32 shaderBufferFloat16AtomicAdd; + VkBool32 shaderBufferFloat16AtomicMinMax; + VkBool32 shaderBufferFloat32AtomicMinMax; + VkBool32 shaderBufferFloat64AtomicMinMax; + VkBool32 shaderSharedFloat16Atomics; + VkBool32 shaderSharedFloat16AtomicAdd; + VkBool32 shaderSharedFloat16AtomicMinMax; + VkBool32 shaderSharedFloat32AtomicMinMax; + VkBool32 shaderSharedFloat64AtomicMinMax; + VkBool32 shaderImageFloat32AtomicMinMax; + VkBool32 sparseImageFloat32AtomicMinMax; +} VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorFeatures { + VkStructureType sType; + void * pNext; + VkBool32 vertexAttributeInstanceRateDivisor; + VkBool32 vertexAttributeInstanceRateZeroDivisor; +} VkPhysicalDeviceVertexAttributeDivisorFeatures; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorFeatures VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorFeatures VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT; + +typedef struct VkQueueFamilyCheckpointPropertiesNV { + VkStructureType sType; + void * pNext; + VkPipelineStageFlags checkpointExecutionStageMask; +} VkQueueFamilyCheckpointPropertiesNV; + +typedef struct VkPhysicalDeviceDepthStencilResolveProperties { + VkStructureType sType; + void * pNext; + VkResolveModeFlags supportedDepthResolveModes; + VkResolveModeFlags supportedStencilResolveModes; + VkBool32 independentResolveNone; + VkBool32 independentResolve; +} VkPhysicalDeviceDepthStencilResolveProperties; + +typedef struct VkPhysicalDeviceDepthStencilResolveProperties VkPhysicalDeviceDepthStencilResolvePropertiesKHR; + +typedef struct VkSubpassDescriptionDepthStencilResolve { + VkStructureType sType; + const void * pNext; + VkResolveModeFlagBits depthResolveMode; + VkResolveModeFlagBits stencilResolveMode; + const VkAttachmentReference2 * pDepthStencilResolveAttachment; +} VkSubpassDescriptionDepthStencilResolve; + +typedef struct VkSubpassDescriptionDepthStencilResolve VkSubpassDescriptionDepthStencilResolveKHR; + +typedef struct VkPhysicalDeviceASTCDecodeFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 decodeModeSharedExponent; +} VkPhysicalDeviceASTCDecodeFeaturesEXT; + +typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 transformFeedback; + VkBool32 geometryStreams; +} VkPhysicalDeviceTransformFeedbackFeaturesEXT; + +typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t maxTransformFeedbackStreams; + uint32_t maxTransformFeedbackBuffers; + VkDeviceSize maxTransformFeedbackBufferSize; + uint32_t maxTransformFeedbackStreamDataSize; + uint32_t maxTransformFeedbackBufferDataSize; + uint32_t maxTransformFeedbackBufferDataStride; + VkBool32 transformFeedbackQueries; + VkBool32 transformFeedbackStreamsLinesTriangles; + VkBool32 transformFeedbackRasterizationStreamSelect; + VkBool32 transformFeedbackDraw; +} VkPhysicalDeviceTransformFeedbackPropertiesEXT; + +typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkPipelineRasterizationStateStreamCreateFlagsEXT flags; + uint32_t rasterizationStream; +} VkPipelineRasterizationStateStreamCreateInfoEXT; + +typedef struct VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 representativeFragmentTest; +} VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV; + +typedef struct VkPipelineRepresentativeFragmentTestStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkBool32 representativeFragmentTestEnable; +} VkPipelineRepresentativeFragmentTestStateCreateInfoNV; + +typedef struct VkPhysicalDeviceExclusiveScissorFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 exclusiveScissor; +} VkPhysicalDeviceExclusiveScissorFeaturesNV; + +typedef struct VkPhysicalDeviceCornerSampledImageFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 cornerSampledImage; +} VkPhysicalDeviceCornerSampledImageFeaturesNV; + +typedef struct VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 computeDerivativeGroupQuads; + VkBool32 computeDerivativeGroupLinear; +} VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR; + +typedef struct VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR VkPhysicalDeviceComputeShaderDerivativesFeaturesNV; + +typedef struct VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR { + VkStructureType sType; + void * pNext; + VkBool32 meshAndTaskShaderDerivatives; +} VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR; + +typedef struct VkPhysicalDeviceShaderImageFootprintFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 imageFootprint; +} VkPhysicalDeviceShaderImageFootprintFeaturesNV; + +typedef struct VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 dedicatedAllocationImageAliasing; +} VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV; + +typedef struct VkPhysicalDeviceCopyMemoryIndirectFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 indirectCopy; +} VkPhysicalDeviceCopyMemoryIndirectFeaturesNV; + +typedef struct VkPhysicalDeviceCopyMemoryIndirectPropertiesNV { + VkStructureType sType; + void * pNext; + VkQueueFlags supportedQueues; +} VkPhysicalDeviceCopyMemoryIndirectPropertiesNV; + +typedef struct VkPhysicalDeviceMemoryDecompressionFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 memoryDecompression; +} VkPhysicalDeviceMemoryDecompressionFeaturesNV; + +typedef struct VkPhysicalDeviceMemoryDecompressionPropertiesNV { + VkStructureType sType; + void * pNext; + VkMemoryDecompressionMethodFlagsNV decompressionMethods; + uint64_t maxDecompressionIndirectCount; +} VkPhysicalDeviceMemoryDecompressionPropertiesNV; + +typedef struct VkPipelineViewportShadingRateImageStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkBool32 shadingRateImageEnable; + uint32_t viewportCount; + const VkShadingRatePaletteNV * pShadingRatePalettes; +} VkPipelineViewportShadingRateImageStateCreateInfoNV; + +typedef struct VkPhysicalDeviceShadingRateImageFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 shadingRateImage; + VkBool32 shadingRateCoarseSampleOrder; +} VkPhysicalDeviceShadingRateImageFeaturesNV; + +typedef struct VkPhysicalDeviceInvocationMaskFeaturesHUAWEI { + VkStructureType sType; + void * pNext; + VkBool32 invocationMask; +} VkPhysicalDeviceInvocationMaskFeaturesHUAWEI; + +typedef struct VkPhysicalDeviceMeshShaderFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 taskShader; + VkBool32 meshShader; +} VkPhysicalDeviceMeshShaderFeaturesNV; + +typedef struct VkPhysicalDeviceMeshShaderFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 taskShader; + VkBool32 meshShader; + VkBool32 multiviewMeshShader; + VkBool32 primitiveFragmentShadingRateMeshShader; + VkBool32 meshShaderQueries; +} VkPhysicalDeviceMeshShaderFeaturesEXT; + +typedef struct VkPhysicalDeviceMeshShaderPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t maxTaskWorkGroupTotalCount; + uint32_t maxTaskWorkGroupCount [3]; + uint32_t maxTaskWorkGroupInvocations; + uint32_t maxTaskWorkGroupSize [3]; + uint32_t maxTaskPayloadSize; + uint32_t maxTaskSharedMemorySize; + uint32_t maxTaskPayloadAndSharedMemorySize; + uint32_t maxMeshWorkGroupTotalCount; + uint32_t maxMeshWorkGroupCount [3]; + uint32_t maxMeshWorkGroupInvocations; + uint32_t maxMeshWorkGroupSize [3]; + uint32_t maxMeshSharedMemorySize; + uint32_t maxMeshPayloadAndSharedMemorySize; + uint32_t maxMeshOutputMemorySize; + uint32_t maxMeshPayloadAndOutputMemorySize; + uint32_t maxMeshOutputComponents; + uint32_t maxMeshOutputVertices; + uint32_t maxMeshOutputPrimitives; + uint32_t maxMeshOutputLayers; + uint32_t maxMeshMultiviewViewCount; + uint32_t meshOutputPerVertexGranularity; + uint32_t meshOutputPerPrimitiveGranularity; + uint32_t maxPreferredTaskWorkGroupInvocations; + uint32_t maxPreferredMeshWorkGroupInvocations; + VkBool32 prefersLocalInvocationVertexOutput; + VkBool32 prefersLocalInvocationPrimitiveOutput; + VkBool32 prefersCompactVertexOutput; + VkBool32 prefersCompactPrimitiveOutput; +} VkPhysicalDeviceMeshShaderPropertiesEXT; + +typedef struct VkRayTracingPipelineCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo * pStages; + uint32_t groupCount; + const VkRayTracingShaderGroupCreateInfoNV * pGroups; + uint32_t maxRecursionDepth; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkRayTracingPipelineCreateInfoNV; + +typedef struct VkRayTracingPipelineCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo * pStages; + uint32_t groupCount; + const VkRayTracingShaderGroupCreateInfoKHR * pGroups; + uint32_t maxPipelineRayRecursionDepth; + const VkPipelineLibraryCreateInfoKHR * pLibraryInfo; + const VkRayTracingPipelineInterfaceCreateInfoKHR * pLibraryInterface; + const VkPipelineDynamicStateCreateInfo * pDynamicState; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkRayTracingPipelineCreateInfoKHR; + +typedef struct VkGeometryTrianglesNV { + VkStructureType sType; + const void * pNext; + VkBuffer vertexData; + VkDeviceSize vertexOffset; + uint32_t vertexCount; + VkDeviceSize vertexStride; + VkFormat vertexFormat; + VkBuffer indexData; + VkDeviceSize indexOffset; + uint32_t indexCount; + VkIndexType indexType; + VkBuffer transformData; + VkDeviceSize transformOffset; +} VkGeometryTrianglesNV; + +typedef struct VkGeometryAABBNV { + VkStructureType sType; + const void * pNext; + VkBuffer aabbData; + uint32_t numAABBs; + uint32_t stride; + VkDeviceSize offset; +} VkGeometryAABBNV; + +typedef struct VkGeometryDataNV { + VkGeometryTrianglesNV triangles; + VkGeometryAABBNV aabbs; +} VkGeometryDataNV; + +typedef struct VkGeometryNV { + VkStructureType sType; + const void * pNext; + VkGeometryTypeKHR geometryType; + VkGeometryDataNV geometry; + VkGeometryFlagsKHR flags; +} VkGeometryNV; + +typedef struct VkAccelerationStructureInfoNV { + VkStructureType sType; + const void * pNext; + VkAccelerationStructureTypeNV type; + VkBuildAccelerationStructureFlagsNV flags; + uint32_t instanceCount; + uint32_t geometryCount; + const VkGeometryNV * pGeometries; +} VkAccelerationStructureInfoNV; + +typedef struct VkAccelerationStructureCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkDeviceSize compactedSize; + VkAccelerationStructureInfoNV info; +} VkAccelerationStructureCreateInfoNV; + +typedef struct VkBindAccelerationStructureMemoryInfoNV { + VkStructureType sType; + const void * pNext; + VkAccelerationStructureNV accelerationStructure; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + uint32_t deviceIndexCount; + const uint32_t * pDeviceIndices; +} VkBindAccelerationStructureMemoryInfoNV; + +typedef struct VkPhysicalDeviceAccelerationStructureFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 accelerationStructure; + VkBool32 accelerationStructureCaptureReplay; + VkBool32 accelerationStructureIndirectBuild; + VkBool32 accelerationStructureHostCommands; + VkBool32 descriptorBindingAccelerationStructureUpdateAfterBind; +} VkPhysicalDeviceAccelerationStructureFeaturesKHR; + +typedef struct VkPhysicalDeviceRayTracingPipelineFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 rayTracingPipeline; + VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplay; + VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplayMixed; + VkBool32 rayTracingPipelineTraceRaysIndirect; + VkBool32 rayTraversalPrimitiveCulling; +} VkPhysicalDeviceRayTracingPipelineFeaturesKHR; + +typedef struct VkPhysicalDeviceRayQueryFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 rayQuery; +} VkPhysicalDeviceRayQueryFeaturesKHR; + +typedef struct VkStridedDeviceAddressRegionKHR { + VkDeviceAddress deviceAddress; + VkDeviceSize stride; + VkDeviceSize size; +} VkStridedDeviceAddressRegionKHR; + +typedef struct VkTraceRaysIndirectCommand2KHR { + VkDeviceAddress raygenShaderRecordAddress; + VkDeviceSize raygenShaderRecordSize; + VkDeviceAddress missShaderBindingTableAddress; + VkDeviceSize missShaderBindingTableSize; + VkDeviceSize missShaderBindingTableStride; + VkDeviceAddress hitShaderBindingTableAddress; + VkDeviceSize hitShaderBindingTableSize; + VkDeviceSize hitShaderBindingTableStride; + VkDeviceAddress callableShaderBindingTableAddress; + VkDeviceSize callableShaderBindingTableSize; + VkDeviceSize callableShaderBindingTableStride; + uint32_t width; + uint32_t height; + uint32_t depth; +} VkTraceRaysIndirectCommand2KHR; + +typedef struct VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 rayTracingMaintenance1; + VkBool32 rayTracingPipelineTraceRaysIndirect2; +} VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR; + +typedef struct VkDrmFormatModifierPropertiesEXT { + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + VkFormatFeatureFlags drmFormatModifierTilingFeatures; +} VkDrmFormatModifierPropertiesEXT; + +typedef struct VkImageDrmFormatModifierExplicitCreateInfoEXT { + VkStructureType sType; + const void * pNext; + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + const VkSubresourceLayout * pPlaneLayouts; +} VkImageDrmFormatModifierExplicitCreateInfoEXT; + +typedef struct VkImageStencilUsageCreateInfo { + VkStructureType sType; + const void * pNext; + VkImageUsageFlags stencilUsage; +} VkImageStencilUsageCreateInfo; + +typedef struct VkImageStencilUsageCreateInfo VkImageStencilUsageCreateInfoEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMapFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 fragmentDensityMap; + VkBool32 fragmentDensityMapDynamic; + VkBool32 fragmentDensityMapNonSubsampledImages; +} VkPhysicalDeviceFragmentDensityMapFeaturesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMap2FeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 fragmentDensityMapDeferred; +} VkPhysicalDeviceFragmentDensityMap2FeaturesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 fragmentDensityMapOffset; +} VkPhysicalDeviceFragmentDensityMapOffsetFeaturesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetFeaturesEXT VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM; + +typedef struct VkPhysicalDeviceFragmentDensityMapPropertiesEXT { + VkStructureType sType; + void * pNext; + VkExtent2D minFragmentDensityTexelSize; + VkExtent2D maxFragmentDensityTexelSize; + VkBool32 fragmentDensityInvocations; +} VkPhysicalDeviceFragmentDensityMapPropertiesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMap2PropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 subsampledLoads; + VkBool32 subsampledCoarseReconstructionEarlyAccess; + uint32_t maxSubsampledArrayLayers; + uint32_t maxDescriptorSetSubsampledSamplers; +} VkPhysicalDeviceFragmentDensityMap2PropertiesEXT; + +typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures { + VkStructureType sType; + void * pNext; + VkBool32 scalarBlockLayout; +} VkPhysicalDeviceScalarBlockLayoutFeatures; + +typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures VkPhysicalDeviceScalarBlockLayoutFeaturesEXT; + +typedef struct VkSurfaceProtectedCapabilitiesKHR { + VkStructureType sType; + const void * pNext; + VkBool32 supportsProtected; +} VkSurfaceProtectedCapabilitiesKHR; + +typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures { + VkStructureType sType; + void * pNext; + VkBool32 uniformBufferStandardLayout; +} VkPhysicalDeviceUniformBufferStandardLayoutFeatures; + +typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR; + +typedef struct VkPhysicalDeviceDepthClipEnableFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 depthClipEnable; +} VkPhysicalDeviceDepthClipEnableFeaturesEXT; + +typedef struct VkPipelineRasterizationDepthClipStateCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkPipelineRasterizationDepthClipStateCreateFlagsEXT flags; + VkBool32 depthClipEnable; +} VkPipelineRasterizationDepthClipStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT { + VkStructureType sType; + void * pNext; + VkDeviceSize heapBudget [ VK_MAX_MEMORY_HEAPS ]; + VkDeviceSize heapUsage [ VK_MAX_MEMORY_HEAPS ]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; + +typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 memoryPriority; +} VkPhysicalDeviceMemoryPriorityFeaturesEXT; + +typedef struct VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 pageableDeviceLocalMemory; +} VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT; + +typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures { + VkStructureType sType; + void * pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeatures; + +typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; + +typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeaturesEXT; + +typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT VkPhysicalDeviceBufferAddressFeaturesEXT; + +typedef struct VkBufferDeviceAddressCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkDeviceAddress deviceAddress; +} VkBufferDeviceAddressCreateInfoEXT; + +typedef struct VkFilterCubicImageViewImageFormatPropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 filterCubic; + VkBool32 filterCubicMinmax; +} VkFilterCubicImageViewImageFormatPropertiesEXT; + +typedef struct VkPhysicalDeviceImagelessFramebufferFeatures { + VkStructureType sType; + void * pNext; + VkBool32 imagelessFramebuffer; +} VkPhysicalDeviceImagelessFramebufferFeatures; + +typedef struct VkPhysicalDeviceImagelessFramebufferFeatures VkPhysicalDeviceImagelessFramebufferFeaturesKHR; + +typedef struct VkFramebufferAttachmentImageInfo { + VkStructureType sType; + const void * pNext; + VkImageCreateFlags flags; + VkImageUsageFlags usage; + uint32_t width; + uint32_t height; + uint32_t layerCount; + uint32_t viewFormatCount; + const VkFormat * pViewFormats; +} VkFramebufferAttachmentImageInfo; + +typedef struct VkFramebufferAttachmentImageInfo VkFramebufferAttachmentImageInfoKHR; + +typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeatures { + VkStructureType sType; + void * pNext; + VkBool32 textureCompressionASTC_HDR; +} VkPhysicalDeviceTextureCompressionASTCHDRFeatures; -typedef struct VkSubpassDependency { - uint32_t srcSubpass; - uint32_t dstSubpass; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkDependencyFlags dependencyFlags; -} VkSubpassDependency; +typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeatures VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT; -typedef struct VkRenderPassCreateInfo { +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV { VkStructureType sType; - const void * pNext; - VkRenderPassCreateFlags flags; - uint32_t attachmentCount; - const VkAttachmentDescription * pAttachments; - uint32_t subpassCount; - const VkSubpassDescription * pSubpasses; - uint32_t dependencyCount; - const VkSubpassDependency * pDependencies; -} VkRenderPassCreateInfo; + void * pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; -typedef struct VkEventCreateInfo { +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV { VkStructureType sType; - const void * pNext; - VkEventCreateFlags flags; -} VkEventCreateInfo; + void * pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; -typedef struct VkFenceCreateInfo { +typedef struct VkPhysicalDeviceYcbcrImageArraysFeaturesEXT { VkStructureType sType; - const void * pNext; - VkFenceCreateFlags flags; -} VkFenceCreateInfo; + void * pNext; + VkBool32 ycbcrImageArrays; +} VkPhysicalDeviceYcbcrImageArraysFeaturesEXT; -typedef struct VkPhysicalDeviceFeatures { - VkBool32 robustBufferAccess; - VkBool32 fullDrawIndexUint32; - VkBool32 imageCubeArray; - VkBool32 independentBlend; - VkBool32 geometryShader; - VkBool32 tessellationShader; - VkBool32 sampleRateShading; - VkBool32 dualSrcBlend; - VkBool32 logicOp; - VkBool32 multiDrawIndirect; - VkBool32 drawIndirectFirstInstance; - VkBool32 depthClamp; - VkBool32 depthBiasClamp; - VkBool32 fillModeNonSolid; - VkBool32 depthBounds; - VkBool32 wideLines; - VkBool32 largePoints; - VkBool32 alphaToOne; - VkBool32 multiViewport; - VkBool32 samplerAnisotropy; - VkBool32 textureCompressionETC2; - VkBool32 textureCompressionASTC_LDR; - VkBool32 textureCompressionBC; - VkBool32 occlusionQueryPrecise; - VkBool32 pipelineStatisticsQuery; - VkBool32 vertexPipelineStoresAndAtomics; - VkBool32 fragmentStoresAndAtomics; - VkBool32 shaderTessellationAndGeometryPointSize; - VkBool32 shaderImageGatherExtended; - VkBool32 shaderStorageImageExtendedFormats; - VkBool32 shaderStorageImageMultisample; - VkBool32 shaderStorageImageReadWithoutFormat; - VkBool32 shaderStorageImageWriteWithoutFormat; - VkBool32 shaderUniformBufferArrayDynamicIndexing; - VkBool32 shaderSampledImageArrayDynamicIndexing; - VkBool32 shaderStorageBufferArrayDynamicIndexing; - VkBool32 shaderStorageImageArrayDynamicIndexing; - VkBool32 shaderClipDistance; - VkBool32 shaderCullDistance; - VkBool32 shaderFloat64; - VkBool32 shaderInt64; - VkBool32 shaderInt16; - VkBool32 shaderResourceResidency; - VkBool32 shaderResourceMinLod; - VkBool32 sparseBinding; - VkBool32 sparseResidencyBuffer; - VkBool32 sparseResidencyImage2D; - VkBool32 sparseResidencyImage3D; - VkBool32 sparseResidency2Samples; - VkBool32 sparseResidency4Samples; - VkBool32 sparseResidency8Samples; - VkBool32 sparseResidency16Samples; - VkBool32 sparseResidencyAliased; - VkBool32 variableMultisampleRate; - VkBool32 inheritedQueries; -} VkPhysicalDeviceFeatures; +typedef struct VkImageViewAddressPropertiesNVX { + VkStructureType sType; + void * pNext; + VkDeviceAddress deviceAddress; + VkDeviceSize size; +} VkImageViewAddressPropertiesNVX; -typedef struct VkPhysicalDeviceSparseProperties { - VkBool32 residencyStandard2DBlockShape; - VkBool32 residencyStandard2DMultisampleBlockShape; - VkBool32 residencyStandard3DBlockShape; - VkBool32 residencyAlignedMipSize; - VkBool32 residencyNonResidentStrict; -} VkPhysicalDeviceSparseProperties; +typedef struct VkPipelineCreationFeedback { + VkPipelineCreationFeedbackFlags flags; + uint64_t duration; +} VkPipelineCreationFeedback; -typedef struct VkPhysicalDeviceLimits { - uint32_t maxImageDimension1D; - uint32_t maxImageDimension2D; - uint32_t maxImageDimension3D; - uint32_t maxImageDimensionCube; - uint32_t maxImageArrayLayers; - uint32_t maxTexelBufferElements; - uint32_t maxUniformBufferRange; - uint32_t maxStorageBufferRange; - uint32_t maxPushConstantsSize; - uint32_t maxMemoryAllocationCount; - uint32_t maxSamplerAllocationCount; - VkDeviceSize bufferImageGranularity; - VkDeviceSize sparseAddressSpaceSize; - uint32_t maxBoundDescriptorSets; - uint32_t maxPerStageDescriptorSamplers; - uint32_t maxPerStageDescriptorUniformBuffers; - uint32_t maxPerStageDescriptorStorageBuffers; - uint32_t maxPerStageDescriptorSampledImages; - uint32_t maxPerStageDescriptorStorageImages; - uint32_t maxPerStageDescriptorInputAttachments; - uint32_t maxPerStageResources; - uint32_t maxDescriptorSetSamplers; - uint32_t maxDescriptorSetUniformBuffers; - uint32_t maxDescriptorSetUniformBuffersDynamic; - uint32_t maxDescriptorSetStorageBuffers; - uint32_t maxDescriptorSetStorageBuffersDynamic; - uint32_t maxDescriptorSetSampledImages; - uint32_t maxDescriptorSetStorageImages; - uint32_t maxDescriptorSetInputAttachments; - uint32_t maxVertexInputAttributes; - uint32_t maxVertexInputBindings; - uint32_t maxVertexInputAttributeOffset; - uint32_t maxVertexInputBindingStride; - uint32_t maxVertexOutputComponents; - uint32_t maxTessellationGenerationLevel; - uint32_t maxTessellationPatchSize; - uint32_t maxTessellationControlPerVertexInputComponents; - uint32_t maxTessellationControlPerVertexOutputComponents; - uint32_t maxTessellationControlPerPatchOutputComponents; - uint32_t maxTessellationControlTotalOutputComponents; - uint32_t maxTessellationEvaluationInputComponents; - uint32_t maxTessellationEvaluationOutputComponents; - uint32_t maxGeometryShaderInvocations; - uint32_t maxGeometryInputComponents; - uint32_t maxGeometryOutputComponents; - uint32_t maxGeometryOutputVertices; - uint32_t maxGeometryTotalOutputComponents; - uint32_t maxFragmentInputComponents; - uint32_t maxFragmentOutputAttachments; - uint32_t maxFragmentDualSrcAttachments; - uint32_t maxFragmentCombinedOutputResources; - uint32_t maxComputeSharedMemorySize; - uint32_t maxComputeWorkGroupCount [3]; - uint32_t maxComputeWorkGroupInvocations; - uint32_t maxComputeWorkGroupSize [3]; - uint32_t subPixelPrecisionBits; - uint32_t subTexelPrecisionBits; - uint32_t mipmapPrecisionBits; - uint32_t maxDrawIndexedIndexValue; - uint32_t maxDrawIndirectCount; - float maxSamplerLodBias; - float maxSamplerAnisotropy; - uint32_t maxViewports; - uint32_t maxViewportDimensions [2]; - float viewportBoundsRange [2]; - uint32_t viewportSubPixelBits; - size_t minMemoryMapAlignment; - VkDeviceSize minTexelBufferOffsetAlignment; - VkDeviceSize minUniformBufferOffsetAlignment; - VkDeviceSize minStorageBufferOffsetAlignment; - int32_t minTexelOffset; - uint32_t maxTexelOffset; - int32_t minTexelGatherOffset; - uint32_t maxTexelGatherOffset; - float minInterpolationOffset; - float maxInterpolationOffset; - uint32_t subPixelInterpolationOffsetBits; - uint32_t maxFramebufferWidth; - uint32_t maxFramebufferHeight; - uint32_t maxFramebufferLayers; - VkSampleCountFlags framebufferColorSampleCounts; - VkSampleCountFlags framebufferDepthSampleCounts; - VkSampleCountFlags framebufferStencilSampleCounts; - VkSampleCountFlags framebufferNoAttachmentsSampleCounts; - uint32_t maxColorAttachments; - VkSampleCountFlags sampledImageColorSampleCounts; - VkSampleCountFlags sampledImageIntegerSampleCounts; - VkSampleCountFlags sampledImageDepthSampleCounts; - VkSampleCountFlags sampledImageStencilSampleCounts; - VkSampleCountFlags storageImageSampleCounts; - uint32_t maxSampleMaskWords; - VkBool32 timestampComputeAndGraphics; - float timestampPeriod; - uint32_t maxClipDistances; - uint32_t maxCullDistances; - uint32_t maxCombinedClipAndCullDistances; - uint32_t discreteQueuePriorities; - float pointSizeRange [2]; - float lineWidthRange [2]; - float pointSizeGranularity; - float lineWidthGranularity; - VkBool32 strictLines; - VkBool32 standardSampleLocations; - VkDeviceSize optimalBufferCopyOffsetAlignment; - VkDeviceSize optimalBufferCopyRowPitchAlignment; - VkDeviceSize nonCoherentAtomSize; -} VkPhysicalDeviceLimits; +typedef struct VkPipelineCreationFeedback VkPipelineCreationFeedbackEXT; -typedef struct VkSemaphoreCreateInfo { +typedef struct VkPipelineCreationFeedbackCreateInfo { VkStructureType sType; - const void * pNext; - VkSemaphoreCreateFlags flags; -} VkSemaphoreCreateInfo; + const void * pNext; + VkPipelineCreationFeedback * pPipelineCreationFeedback; + uint32_t pipelineStageCreationFeedbackCount; + VkPipelineCreationFeedback * pPipelineStageCreationFeedbacks; +} VkPipelineCreationFeedbackCreateInfo; -typedef struct VkQueryPoolCreateInfo { +typedef struct VkPipelineCreationFeedbackCreateInfo VkPipelineCreationFeedbackCreateInfoEXT; + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkSurfaceCapabilitiesFullScreenExclusiveEXT { VkStructureType sType; - const void * pNext; - VkQueryPoolCreateFlags flags; - VkQueryType queryType; - uint32_t queryCount; - VkQueryPipelineStatisticFlags pipelineStatistics; -} VkQueryPoolCreateInfo; + void * pNext; + VkBool32 fullScreenExclusiveSupported; +} VkSurfaceCapabilitiesFullScreenExclusiveEXT; -typedef struct VkFramebufferCreateInfo { +#endif + +typedef struct VkPhysicalDevicePresentBarrierFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 presentBarrier; +} VkPhysicalDevicePresentBarrierFeaturesNV; + +typedef struct VkSurfaceCapabilitiesPresentBarrierNV { + VkStructureType sType; + void * pNext; + VkBool32 presentBarrierSupported; +} VkSurfaceCapabilitiesPresentBarrierNV; + +typedef struct VkSwapchainPresentBarrierCreateInfoNV { + VkStructureType sType; + void * pNext; + VkBool32 presentBarrierEnable; +} VkSwapchainPresentBarrierCreateInfoNV; + +typedef struct VkPhysicalDevicePerformanceQueryFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 performanceCounterQueryPools; + VkBool32 performanceCounterMultipleQueryPools; +} VkPhysicalDevicePerformanceQueryFeaturesKHR; + +typedef struct VkPhysicalDevicePerformanceQueryPropertiesKHR { + VkStructureType sType; + void * pNext; + VkBool32 allowCommandBufferQueryCopies; +} VkPhysicalDevicePerformanceQueryPropertiesKHR; + +typedef struct VkPerformanceCounterDescriptionKHR { + VkStructureType sType; + void * pNext; + VkPerformanceCounterDescriptionFlagsKHR flags; + char name [ VK_MAX_DESCRIPTION_SIZE ]; + char category [ VK_MAX_DESCRIPTION_SIZE ]; + char description [ VK_MAX_DESCRIPTION_SIZE ]; +} VkPerformanceCounterDescriptionKHR; + +typedef struct VkAcquireProfilingLockInfoKHR { VkStructureType sType; const void * pNext; - VkFramebufferCreateFlags flags; - VkRenderPass renderPass; - uint32_t attachmentCount; - const VkImageView * pAttachments; - uint32_t width; - uint32_t height; - uint32_t layers; -} VkFramebufferCreateInfo; + VkAcquireProfilingLockFlagsKHR flags; + uint64_t timeout; +} VkAcquireProfilingLockInfoKHR; -typedef struct VkSubmitInfo { +typedef struct VkHeadlessSurfaceCreateInfoEXT { VkStructureType sType; - const void * pNext; - uint32_t waitSemaphoreCount; - const VkSemaphore * pWaitSemaphores; - const VkPipelineStageFlags * pWaitDstStageMask; - uint32_t commandBufferCount; - const VkCommandBuffer * pCommandBuffers; - uint32_t signalSemaphoreCount; - const VkSemaphore * pSignalSemaphores; -} VkSubmitInfo; - -typedef struct VkDisplayPropertiesKHR { - VkDisplayKHR display; - const char * displayName; - VkExtent2D physicalDimensions; - VkExtent2D physicalResolution; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkBool32 planeReorderPossible; - VkBool32 persistentContent; -} VkDisplayPropertiesKHR; + const void * pNext; + VkHeadlessSurfaceCreateFlagsEXT flags; +} VkHeadlessSurfaceCreateInfoEXT; -typedef struct VkDisplayModeCreateInfoKHR { +typedef struct VkPhysicalDeviceCoverageReductionModeFeaturesNV { VkStructureType sType; - const void * pNext; - VkDisplayModeCreateFlagsKHR flags; - VkDisplayModeParametersKHR parameters; -} VkDisplayModeCreateInfoKHR; + void * pNext; + VkBool32 coverageReductionMode; +} VkPhysicalDeviceCoverageReductionModeFeaturesNV; -typedef struct VkDisplayPlaneCapabilitiesKHR { - VkDisplayPlaneAlphaFlagsKHR supportedAlpha; - VkOffset2D minSrcPosition; - VkOffset2D maxSrcPosition; - VkExtent2D minSrcExtent; - VkExtent2D maxSrcExtent; - VkOffset2D minDstPosition; - VkOffset2D maxDstPosition; - VkExtent2D minDstExtent; - VkExtent2D maxDstExtent; -} VkDisplayPlaneCapabilitiesKHR; +typedef struct VkPipelineCoverageReductionStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineCoverageReductionStateCreateFlagsNV flags; + VkCoverageReductionModeNV coverageReductionMode; +} VkPipelineCoverageReductionStateCreateInfoNV; -typedef struct VkDisplaySurfaceCreateInfoKHR { +typedef struct VkFramebufferMixedSamplesCombinationNV { VkStructureType sType; - const void * pNext; - VkDisplaySurfaceCreateFlagsKHR flags; - VkDisplayModeKHR displayMode; - uint32_t planeIndex; - uint32_t planeStackIndex; - VkSurfaceTransformFlagBitsKHR transform; - float globalAlpha; - VkDisplayPlaneAlphaFlagBitsKHR alphaMode; - VkExtent2D imageExtent; -} VkDisplaySurfaceCreateInfoKHR; + void * pNext; + VkCoverageReductionModeNV coverageReductionMode; + VkSampleCountFlagBits rasterizationSamples; + VkSampleCountFlags depthStencilSamples; + VkSampleCountFlags colorSamples; +} VkFramebufferMixedSamplesCombinationNV; -typedef struct VkDisplayPresentInfoKHR { +typedef struct VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL { VkStructureType sType; - const void * pNext; - VkRect2D srcRect; - VkRect2D dstRect; - VkBool32 persistent; -} VkDisplayPresentInfoKHR; + void * pNext; + VkBool32 shaderIntegerFunctions2; +} VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL; -typedef struct VkSurfaceCapabilitiesKHR { - uint32_t minImageCount; - uint32_t maxImageCount; - VkExtent2D currentExtent; - VkExtent2D minImageExtent; - VkExtent2D maxImageExtent; - uint32_t maxImageArrayLayers; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkSurfaceTransformFlagBitsKHR currentTransform; - VkCompositeAlphaFlagsKHR supportedCompositeAlpha; - VkImageUsageFlags supportedUsageFlags; -} VkSurfaceCapabilitiesKHR; +typedef union VkPerformanceValueDataINTEL { + uint32_t value32; + uint64_t value64; + float valueFloat; + VkBool32 valueBool; + const char * valueString; +} VkPerformanceValueDataINTEL; -#if defined(VK_USE_PLATFORM_ANDROID_KHR) -typedef struct VkAndroidSurfaceCreateInfoKHR { - VkStructureType sType; - const void * pNext; - VkAndroidSurfaceCreateFlagsKHR flags; - struct ANativeWindow * window; -} VkAndroidSurfaceCreateInfoKHR; -#endif +typedef struct VkPerformanceValueINTEL { + VkPerformanceValueTypeINTEL type; + VkPerformanceValueDataINTEL data; +} VkPerformanceValueINTEL; -#if defined(VK_USE_PLATFORM_VI_NN) -typedef struct VkViSurfaceCreateInfoNN { +typedef struct VkPerformanceOverrideInfoINTEL { VkStructureType sType; - const void * pNext; - VkViSurfaceCreateFlagsNN flags; - void * window; -} VkViSurfaceCreateInfoNN; -#endif + const void * pNext; + VkPerformanceOverrideTypeINTEL type; + VkBool32 enable; + uint64_t parameter; +} VkPerformanceOverrideInfoINTEL; -#if defined(VK_USE_PLATFORM_WAYLAND_KHR) -typedef struct VkWaylandSurfaceCreateInfoKHR { +typedef struct VkPhysicalDeviceShaderClockFeaturesKHR { VkStructureType sType; - const void * pNext; - VkWaylandSurfaceCreateFlagsKHR flags; - struct wl_display * display; - struct wl_surface * surface; -} VkWaylandSurfaceCreateInfoKHR; -#endif + void * pNext; + VkBool32 shaderSubgroupClock; + VkBool32 shaderDeviceClock; +} VkPhysicalDeviceShaderClockFeaturesKHR; -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkWin32SurfaceCreateInfoKHR { +typedef struct VkPhysicalDeviceIndexTypeUint8Features { VkStructureType sType; - const void * pNext; - VkWin32SurfaceCreateFlagsKHR flags; - HINSTANCE hinstance; - HWND hwnd; -} VkWin32SurfaceCreateInfoKHR; -#endif + void * pNext; + VkBool32 indexTypeUint8; +} VkPhysicalDeviceIndexTypeUint8Features; -#if defined(VK_USE_PLATFORM_XLIB_KHR) -typedef struct VkXlibSurfaceCreateInfoKHR { +typedef struct VkPhysicalDeviceIndexTypeUint8Features VkPhysicalDeviceIndexTypeUint8FeaturesKHR; + +typedef struct VkPhysicalDeviceIndexTypeUint8Features VkPhysicalDeviceIndexTypeUint8FeaturesEXT; + +typedef struct VkPhysicalDeviceShaderSMBuiltinsFeaturesNV { VkStructureType sType; - const void * pNext; - VkXlibSurfaceCreateFlagsKHR flags; - Display * dpy; - Window window; -} VkXlibSurfaceCreateInfoKHR; -#endif + void * pNext; + VkBool32 shaderSMBuiltins; +} VkPhysicalDeviceShaderSMBuiltinsFeaturesNV; -#if defined(VK_USE_PLATFORM_XCB_KHR) -typedef struct VkXcbSurfaceCreateInfoKHR { +typedef struct VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT { VkStructureType sType; - const void * pNext; - VkXcbSurfaceCreateFlagsKHR flags; - xcb_connection_t * connection; - xcb_window_t window; -} VkXcbSurfaceCreateInfoKHR; -#endif + void * pNext; + VkBool32 fragmentShaderSampleInterlock; + VkBool32 fragmentShaderPixelInterlock; + VkBool32 fragmentShaderShadingRateInterlock; +} VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT; -#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) -typedef struct VkDirectFBSurfaceCreateInfoEXT { +typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures { VkStructureType sType; - const void * pNext; - VkDirectFBSurfaceCreateFlagsEXT flags; - IDirectFB * dfb; - IDirectFBSurface * surface; -} VkDirectFBSurfaceCreateInfoEXT; -#endif + void * pNext; + VkBool32 separateDepthStencilLayouts; +} VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures; -#if defined(VK_USE_PLATFORM_FUCHSIA) -typedef struct VkImagePipeSurfaceCreateInfoFUCHSIA { +typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR; + +typedef struct VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT { VkStructureType sType; - const void * pNext; - VkImagePipeSurfaceCreateFlagsFUCHSIA flags; - zx_handle_t imagePipeHandle; -} VkImagePipeSurfaceCreateInfoFUCHSIA; -#endif + void * pNext; + VkBool32 primitiveTopologyListRestart; + VkBool32 primitiveTopologyPatchListRestart; +} VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT; -#if defined(VK_USE_PLATFORM_GGP) -typedef struct VkStreamDescriptorSurfaceCreateInfoGGP { +typedef struct VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR { VkStructureType sType; - const void * pNext; - VkStreamDescriptorSurfaceCreateFlagsGGP flags; - GgpStreamDescriptor streamDescriptor; -} VkStreamDescriptorSurfaceCreateInfoGGP; -#endif + void * pNext; + VkBool32 pipelineExecutableInfo; +} VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR; -typedef struct VkSwapchainCreateInfoKHR { +typedef struct VkPipelineExecutablePropertiesKHR { VkStructureType sType; - const void * pNext; - VkSwapchainCreateFlagsKHR flags; - VkSurfaceKHR surface; - uint32_t minImageCount; - VkFormat imageFormat; - VkColorSpaceKHR imageColorSpace; - VkExtent2D imageExtent; - uint32_t imageArrayLayers; - VkImageUsageFlags imageUsage; - VkSharingMode imageSharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t * pQueueFamilyIndices; - VkSurfaceTransformFlagBitsKHR preTransform; - VkCompositeAlphaFlagBitsKHR compositeAlpha; - VkPresentModeKHR presentMode; - VkBool32 clipped; - VkSwapchainKHR oldSwapchain; -} VkSwapchainCreateInfoKHR; + void * pNext; + VkShaderStageFlags stages; + char name [ VK_MAX_DESCRIPTION_SIZE ]; + char description [ VK_MAX_DESCRIPTION_SIZE ]; + uint32_t subgroupSize; +} VkPipelineExecutablePropertiesKHR; -typedef struct VkDebugReportCallbackCreateInfoEXT { +typedef union VkPipelineExecutableStatisticValueKHR { + VkBool32 b32; + int64_t i64; + uint64_t u64; + double f64; +} VkPipelineExecutableStatisticValueKHR; + +typedef struct VkPipelineExecutableStatisticKHR { VkStructureType sType; - const void * pNext; - VkDebugReportFlagsEXT flags; - PFN_vkDebugReportCallbackEXT pfnCallback; - void * pUserData; -} VkDebugReportCallbackCreateInfoEXT; + void * pNext; + char name [ VK_MAX_DESCRIPTION_SIZE ]; + char description [ VK_MAX_DESCRIPTION_SIZE ]; + VkPipelineExecutableStatisticFormatKHR format; + VkPipelineExecutableStatisticValueKHR value; +} VkPipelineExecutableStatisticKHR; -typedef struct VkDedicatedAllocationImageCreateInfoNV { +typedef struct VkPipelineExecutableInternalRepresentationKHR { VkStructureType sType; - const void * pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationImageCreateInfoNV; + void * pNext; + char name [ VK_MAX_DESCRIPTION_SIZE ]; + char description [ VK_MAX_DESCRIPTION_SIZE ]; + VkBool32 isText; + size_t dataSize; + void * pData; +} VkPipelineExecutableInternalRepresentationKHR; -typedef struct VkDedicatedAllocationBufferCreateInfoNV { +typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures { VkStructureType sType; - const void * pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationBufferCreateInfoNV; + void * pNext; + VkBool32 shaderDemoteToHelperInvocation; +} VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures; -typedef struct VkExternalImageFormatPropertiesNV { - VkImageFormatProperties imageFormatProperties; - VkExternalMemoryFeatureFlagsNV externalMemoryFeatures; - VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes; - VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes; -} VkExternalImageFormatPropertiesNV; +typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT; -typedef struct VkExternalMemoryImageCreateInfoNV { +typedef struct VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT { VkStructureType sType; - const void * pNext; - VkExternalMemoryHandleTypeFlagsNV handleTypes; -} VkExternalMemoryImageCreateInfoNV; + void * pNext; + VkBool32 texelBufferAlignment; +} VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT; -typedef struct VkExportMemoryAllocateInfoNV { +typedef struct VkPhysicalDeviceTexelBufferAlignmentProperties { VkStructureType sType; - const void * pNext; - VkExternalMemoryHandleTypeFlagsNV handleTypes; -} VkExportMemoryAllocateInfoNV; + void * pNext; + VkDeviceSize storageTexelBufferOffsetAlignmentBytes; + VkBool32 storageTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; + VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; +} VkPhysicalDeviceTexelBufferAlignmentProperties; -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkImportMemoryWin32HandleInfoNV { +typedef struct VkPhysicalDeviceTexelBufferAlignmentProperties VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT; + +typedef struct VkPhysicalDeviceSubgroupSizeControlFeatures { VkStructureType sType; - const void * pNext; - VkExternalMemoryHandleTypeFlagsNV handleType; - HANDLE handle; -} VkImportMemoryWin32HandleInfoNV; -#endif + void * pNext; + VkBool32 subgroupSizeControl; + VkBool32 computeFullSubgroups; +} VkPhysicalDeviceSubgroupSizeControlFeatures; -typedef struct VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV { - VkStructureType sType; - void * pNext; - VkBool32 deviceGeneratedCommands; -} VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV; +typedef struct VkPhysicalDeviceSubgroupSizeControlFeatures VkPhysicalDeviceSubgroupSizeControlFeaturesEXT; -typedef struct VkPrivateDataSlotCreateInfoEXT { +typedef struct VkPhysicalDeviceSubgroupSizeControlProperties { VkStructureType sType; - const void * pNext; - VkPrivateDataSlotCreateFlagsEXT flags; -} VkPrivateDataSlotCreateInfoEXT; + void * pNext; + uint32_t minSubgroupSize; + uint32_t maxSubgroupSize; + uint32_t maxComputeWorkgroupSubgroups; + VkShaderStageFlags requiredSubgroupSizeStages; +} VkPhysicalDeviceSubgroupSizeControlProperties; -typedef struct VkPhysicalDevicePrivateDataFeaturesEXT { - VkStructureType sType; - void * pNext; - VkBool32 privateData; -} VkPhysicalDevicePrivateDataFeaturesEXT; +typedef struct VkPhysicalDeviceSubgroupSizeControlProperties VkPhysicalDeviceSubgroupSizeControlPropertiesEXT; -typedef struct VkGraphicsShaderGroupCreateInfoNV { +typedef struct VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI { VkStructureType sType; - const void * pNext; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo * pStages; - const VkPipelineVertexInputStateCreateInfo * pVertexInputState; - const VkPipelineTessellationStateCreateInfo * pTessellationState; -} VkGraphicsShaderGroupCreateInfoNV; + void * pNext; + uint32_t maxWorkGroupCount [3]; + uint32_t maxWorkGroupSize [3]; + uint32_t maxOutputClusterCount; + VkDeviceSize indirectBufferOffsetAlignment; +} VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI; -typedef struct VkGraphicsPipelineShaderGroupsCreateInfoNV { +typedef struct VkPhysicalDeviceLineRasterizationFeatures { VkStructureType sType; - const void * pNext; - uint32_t groupCount; - const VkGraphicsShaderGroupCreateInfoNV * pGroups; - uint32_t pipelineCount; - const VkPipeline * pPipelines; -} VkGraphicsPipelineShaderGroupsCreateInfoNV; - -typedef struct VkBindIndexBufferIndirectCommandNV { - VkDeviceAddress bufferAddress; - uint32_t size; - VkIndexType indexType; -} VkBindIndexBufferIndirectCommandNV; + void * pNext; + VkBool32 rectangularLines; + VkBool32 bresenhamLines; + VkBool32 smoothLines; + VkBool32 stippledRectangularLines; + VkBool32 stippledBresenhamLines; + VkBool32 stippledSmoothLines; +} VkPhysicalDeviceLineRasterizationFeatures; -typedef struct VkBindVertexBufferIndirectCommandNV { - VkDeviceAddress bufferAddress; - uint32_t size; - uint32_t stride; -} VkBindVertexBufferIndirectCommandNV; +typedef struct VkPhysicalDeviceLineRasterizationFeatures VkPhysicalDeviceLineRasterizationFeaturesKHR; -typedef struct VkIndirectCommandsStreamNV { - VkBuffer buffer; - VkDeviceSize offset; -} VkIndirectCommandsStreamNV; +typedef struct VkPhysicalDeviceLineRasterizationFeatures VkPhysicalDeviceLineRasterizationFeaturesEXT; -typedef struct VkIndirectCommandsLayoutTokenNV { +typedef struct VkPipelineRasterizationLineStateCreateInfo { VkStructureType sType; - const void * pNext; - VkIndirectCommandsTokenTypeNV tokenType; - uint32_t stream; - uint32_t offset; - uint32_t vertexBindingUnit; - VkBool32 vertexDynamicStride; - VkPipelineLayout pushconstantPipelineLayout; - VkShaderStageFlags pushconstantShaderStageFlags; - uint32_t pushconstantOffset; - uint32_t pushconstantSize; - VkIndirectStateFlagsNV indirectStateFlags; - uint32_t indexTypeCount; - const VkIndexType * pIndexTypes; - const uint32_t * pIndexTypeValues; -} VkIndirectCommandsLayoutTokenNV; + const void * pNext; + VkLineRasterizationMode lineRasterizationMode; + VkBool32 stippledLineEnable; + uint32_t lineStippleFactor; + uint16_t lineStipplePattern; +} VkPipelineRasterizationLineStateCreateInfo; -typedef struct VkIndirectCommandsLayoutCreateInfoNV { - VkStructureType sType; - const void * pNext; - VkIndirectCommandsLayoutUsageFlagsNV flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t tokenCount; - const VkIndirectCommandsLayoutTokenNV * pTokens; - uint32_t streamCount; - const uint32_t * pStreamStrides; -} VkIndirectCommandsLayoutCreateInfoNV; +typedef struct VkPipelineRasterizationLineStateCreateInfo VkPipelineRasterizationLineStateCreateInfoKHR; -typedef struct VkGeneratedCommandsInfoNV { - VkStructureType sType; - const void * pNext; - VkPipelineBindPoint pipelineBindPoint; - VkPipeline pipeline; - VkIndirectCommandsLayoutNV indirectCommandsLayout; - uint32_t streamCount; - const VkIndirectCommandsStreamNV * pStreams; - uint32_t sequencesCount; - VkBuffer preprocessBuffer; - VkDeviceSize preprocessOffset; - VkDeviceSize preprocessSize; - VkBuffer sequencesCountBuffer; - VkDeviceSize sequencesCountOffset; - VkBuffer sequencesIndexBuffer; - VkDeviceSize sequencesIndexOffset; -} VkGeneratedCommandsInfoNV; +typedef struct VkPipelineRasterizationLineStateCreateInfo VkPipelineRasterizationLineStateCreateInfoEXT; -typedef struct VkPhysicalDeviceFeatures2 { +typedef struct VkPhysicalDevicePipelineCreationCacheControlFeatures { VkStructureType sType; - void * pNext; - VkPhysicalDeviceFeatures features; -} VkPhysicalDeviceFeatures2; + void * pNext; + VkBool32 pipelineCreationCacheControl; +} VkPhysicalDevicePipelineCreationCacheControlFeatures; -typedef struct VkPhysicalDeviceFeatures2 VkPhysicalDeviceFeatures2KHR; +typedef struct VkPhysicalDevicePipelineCreationCacheControlFeatures VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT; -typedef struct VkFormatProperties2 { +typedef struct VkPhysicalDeviceVulkan11Features { VkStructureType sType; - void * pNext; - VkFormatProperties formatProperties; -} VkFormatProperties2; - -typedef struct VkFormatProperties2 VkFormatProperties2KHR; + void * pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; + VkBool32 protectedMemory; + VkBool32 samplerYcbcrConversion; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceVulkan11Features; -typedef struct VkImageFormatProperties2 { +typedef struct VkPhysicalDeviceVulkan11Properties { VkStructureType sType; - void * pNext; - VkImageFormatProperties imageFormatProperties; -} VkImageFormatProperties2; - -typedef struct VkImageFormatProperties2 VkImageFormatProperties2KHR; + void * pNext; + uint8_t deviceUUID [ VK_UUID_SIZE ]; + uint8_t driverUUID [ VK_UUID_SIZE ]; + uint8_t deviceLUID [ VK_LUID_SIZE ]; + uint32_t deviceNodeMask; + VkBool32 deviceLUIDValid; + uint32_t subgroupSize; + VkShaderStageFlags subgroupSupportedStages; + VkSubgroupFeatureFlags subgroupSupportedOperations; + VkBool32 subgroupQuadOperationsInAllStages; + VkPointClippingBehavior pointClippingBehavior; + uint32_t maxMultiviewViewCount; + uint32_t maxMultiviewInstanceIndex; + VkBool32 protectedNoFault; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceVulkan11Properties; -typedef struct VkPhysicalDeviceImageFormatInfo2 { +typedef struct VkPhysicalDeviceVulkan12Features { VkStructureType sType; - const void * pNext; - VkFormat format; - VkImageType type; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkImageCreateFlags flags; -} VkPhysicalDeviceImageFormatInfo2; + void * pNext; + VkBool32 samplerMirrorClampToEdge; + VkBool32 drawIndirectCount; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; + VkBool32 shaderBufferInt64Atomics; + VkBool32 shaderSharedInt64Atomics; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; + VkBool32 descriptorIndexing; + VkBool32 shaderInputAttachmentArrayDynamicIndexing; + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; + VkBool32 shaderUniformBufferArrayNonUniformIndexing; + VkBool32 shaderSampledImageArrayNonUniformIndexing; + VkBool32 shaderStorageBufferArrayNonUniformIndexing; + VkBool32 shaderStorageImageArrayNonUniformIndexing; + VkBool32 shaderInputAttachmentArrayNonUniformIndexing; + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; + VkBool32 descriptorBindingUniformBufferUpdateAfterBind; + VkBool32 descriptorBindingSampledImageUpdateAfterBind; + VkBool32 descriptorBindingStorageImageUpdateAfterBind; + VkBool32 descriptorBindingStorageBufferUpdateAfterBind; + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingUpdateUnusedWhilePending; + VkBool32 descriptorBindingPartiallyBound; + VkBool32 descriptorBindingVariableDescriptorCount; + VkBool32 runtimeDescriptorArray; + VkBool32 samplerFilterMinmax; + VkBool32 scalarBlockLayout; + VkBool32 imagelessFramebuffer; + VkBool32 uniformBufferStandardLayout; + VkBool32 shaderSubgroupExtendedTypes; + VkBool32 separateDepthStencilLayouts; + VkBool32 hostQueryReset; + VkBool32 timelineSemaphore; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; + VkBool32 vulkanMemoryModel; + VkBool32 vulkanMemoryModelDeviceScope; + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; + VkBool32 shaderOutputViewportIndex; + VkBool32 shaderOutputLayer; + VkBool32 subgroupBroadcastDynamicId; +} VkPhysicalDeviceVulkan12Features; -typedef struct VkPhysicalDeviceImageFormatInfo2 VkPhysicalDeviceImageFormatInfo2KHR; +typedef struct VkPhysicalDeviceVulkan12Properties { + VkStructureType sType; + void * pNext; + VkDriverId driverID; + char driverName [ VK_MAX_DRIVER_NAME_SIZE ]; + char driverInfo [ VK_MAX_DRIVER_INFO_SIZE ]; + VkConformanceVersion conformanceVersion; + VkShaderFloatControlsIndependence denormBehaviorIndependence; + VkShaderFloatControlsIndependence roundingModeIndependence; + VkBool32 shaderSignedZeroInfNanPreserveFloat16; + VkBool32 shaderSignedZeroInfNanPreserveFloat32; + VkBool32 shaderSignedZeroInfNanPreserveFloat64; + VkBool32 shaderDenormPreserveFloat16; + VkBool32 shaderDenormPreserveFloat32; + VkBool32 shaderDenormPreserveFloat64; + VkBool32 shaderDenormFlushToZeroFloat16; + VkBool32 shaderDenormFlushToZeroFloat32; + VkBool32 shaderDenormFlushToZeroFloat64; + VkBool32 shaderRoundingModeRTEFloat16; + VkBool32 shaderRoundingModeRTEFloat32; + VkBool32 shaderRoundingModeRTEFloat64; + VkBool32 shaderRoundingModeRTZFloat16; + VkBool32 shaderRoundingModeRTZFloat32; + VkBool32 shaderRoundingModeRTZFloat64; + uint32_t maxUpdateAfterBindDescriptorsInAllPools; + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; + VkBool32 shaderSampledImageArrayNonUniformIndexingNative; + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; + VkBool32 shaderStorageImageArrayNonUniformIndexingNative; + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; + VkBool32 robustBufferAccessUpdateAfterBind; + VkBool32 quadDivergentImplicitLod; + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; + uint32_t maxPerStageUpdateAfterBindResources; + uint32_t maxDescriptorSetUpdateAfterBindSamplers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindSampledImages; + uint32_t maxDescriptorSetUpdateAfterBindStorageImages; + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; + VkResolveModeFlags supportedDepthResolveModes; + VkResolveModeFlags supportedStencilResolveModes; + VkBool32 independentResolveNone; + VkBool32 independentResolve; + VkBool32 filterMinmaxSingleComponentFormats; + VkBool32 filterMinmaxImageComponentMapping; + uint64_t maxTimelineSemaphoreValueDifference; + VkSampleCountFlags framebufferIntegerColorSampleCounts; +} VkPhysicalDeviceVulkan12Properties; -typedef struct VkQueueFamilyProperties2 { +typedef struct VkPhysicalDeviceVulkan13Features { VkStructureType sType; - void * pNext; - VkQueueFamilyProperties queueFamilyProperties; -} VkQueueFamilyProperties2; + void * pNext; + VkBool32 robustImageAccess; + VkBool32 inlineUniformBlock; + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; + VkBool32 pipelineCreationCacheControl; + VkBool32 privateData; + VkBool32 shaderDemoteToHelperInvocation; + VkBool32 shaderTerminateInvocation; + VkBool32 subgroupSizeControl; + VkBool32 computeFullSubgroups; + VkBool32 synchronization2; + VkBool32 textureCompressionASTC_HDR; + VkBool32 shaderZeroInitializeWorkgroupMemory; + VkBool32 dynamicRendering; + VkBool32 shaderIntegerDotProduct; + VkBool32 maintenance4; +} VkPhysicalDeviceVulkan13Features; + +typedef struct VkPhysicalDeviceVulkan13Properties { + VkStructureType sType; + void * pNext; + uint32_t minSubgroupSize; + uint32_t maxSubgroupSize; + uint32_t maxComputeWorkgroupSubgroups; + VkShaderStageFlags requiredSubgroupSizeStages; + uint32_t maxInlineUniformBlockSize; + uint32_t maxPerStageDescriptorInlineUniformBlocks; + uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; + uint32_t maxDescriptorSetInlineUniformBlocks; + uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; + uint32_t maxInlineUniformTotalSize; + VkBool32 integerDotProduct8BitUnsignedAccelerated; + VkBool32 integerDotProduct8BitSignedAccelerated; + VkBool32 integerDotProduct8BitMixedSignednessAccelerated; + VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProduct16BitUnsignedAccelerated; + VkBool32 integerDotProduct16BitSignedAccelerated; + VkBool32 integerDotProduct16BitMixedSignednessAccelerated; + VkBool32 integerDotProduct32BitUnsignedAccelerated; + VkBool32 integerDotProduct32BitSignedAccelerated; + VkBool32 integerDotProduct32BitMixedSignednessAccelerated; + VkBool32 integerDotProduct64BitUnsignedAccelerated; + VkBool32 integerDotProduct64BitSignedAccelerated; + VkBool32 integerDotProduct64BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; + VkDeviceSize storageTexelBufferOffsetAlignmentBytes; + VkBool32 storageTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; + VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize maxBufferSize; +} VkPhysicalDeviceVulkan13Properties; + +typedef struct VkPhysicalDeviceVulkan14Features { + VkStructureType sType; + void * pNext; + VkBool32 globalPriorityQuery; + VkBool32 shaderSubgroupRotate; + VkBool32 shaderSubgroupRotateClustered; + VkBool32 shaderFloatControls2; + VkBool32 shaderExpectAssume; + VkBool32 rectangularLines; + VkBool32 bresenhamLines; + VkBool32 smoothLines; + VkBool32 stippledRectangularLines; + VkBool32 stippledBresenhamLines; + VkBool32 stippledSmoothLines; + VkBool32 vertexAttributeInstanceRateDivisor; + VkBool32 vertexAttributeInstanceRateZeroDivisor; + VkBool32 indexTypeUint8; + VkBool32 dynamicRenderingLocalRead; + VkBool32 maintenance5; + VkBool32 maintenance6; + VkBool32 pipelineProtectedAccess; + VkBool32 pipelineRobustness; + VkBool32 hostImageCopy; + VkBool32 pushDescriptor; +} VkPhysicalDeviceVulkan14Features; + +typedef struct VkPhysicalDeviceVulkan14Properties { + VkStructureType sType; + void * pNext; + uint32_t lineSubPixelPrecisionBits; + uint32_t maxVertexAttribDivisor; + VkBool32 supportsNonZeroFirstInstance; + uint32_t maxPushDescriptors; + VkBool32 dynamicRenderingLocalReadDepthStencilAttachments; + VkBool32 dynamicRenderingLocalReadMultisampledAttachments; + VkBool32 earlyFragmentMultisampleCoverageAfterSampleCounting; + VkBool32 earlyFragmentSampleMaskTestBeforeSampleCounting; + VkBool32 depthStencilSwizzleOneSupport; + VkBool32 polygonModePointSize; + VkBool32 nonStrictSinglePixelWideLinesUseParallelogram; + VkBool32 nonStrictWideLinesUseParallelogram; + VkBool32 blockTexelViewCompatibleMultipleLayers; + uint32_t maxCombinedImageSamplerDescriptorCount; + VkBool32 fragmentShadingRateClampCombinerInputs; + VkPipelineRobustnessBufferBehavior defaultRobustnessStorageBuffers; + VkPipelineRobustnessBufferBehavior defaultRobustnessUniformBuffers; + VkPipelineRobustnessBufferBehavior defaultRobustnessVertexInputs; + VkPipelineRobustnessImageBehavior defaultRobustnessImages; + uint32_t copySrcLayoutCount; + VkImageLayout * pCopySrcLayouts; + uint32_t copyDstLayoutCount; + VkImageLayout * pCopyDstLayouts; + uint8_t optimalTilingLayoutUUID [ VK_UUID_SIZE ]; + VkBool32 identicalMemoryTypeRequirements; +} VkPhysicalDeviceVulkan14Properties; -typedef struct VkQueueFamilyProperties2 VkQueueFamilyProperties2KHR; +typedef struct VkPipelineCompilerControlCreateInfoAMD { + VkStructureType sType; + const void * pNext; + VkPipelineCompilerControlFlagsAMD compilerControlFlags; +} VkPipelineCompilerControlCreateInfoAMD; -typedef struct VkSparseImageFormatProperties2 { +typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD { VkStructureType sType; - void * pNext; - VkSparseImageFormatProperties properties; -} VkSparseImageFormatProperties2; - -typedef struct VkSparseImageFormatProperties2 VkSparseImageFormatProperties2KHR; + void * pNext; + VkBool32 deviceCoherentMemory; +} VkPhysicalDeviceCoherentMemoryFeaturesAMD; -typedef struct VkPhysicalDeviceSparseImageFormatInfo2 { +typedef struct VkPhysicalDeviceToolProperties { VkStructureType sType; - const void * pNext; - VkFormat format; - VkImageType type; - VkSampleCountFlagBits samples; - VkImageUsageFlags usage; - VkImageTiling tiling; -} VkPhysicalDeviceSparseImageFormatInfo2; + void * pNext; + char name [ VK_MAX_EXTENSION_NAME_SIZE ]; + char version [ VK_MAX_EXTENSION_NAME_SIZE ]; + VkToolPurposeFlags purposes; + char description [ VK_MAX_DESCRIPTION_SIZE ]; + char layer [ VK_MAX_EXTENSION_NAME_SIZE ]; +} VkPhysicalDeviceToolProperties; -typedef struct VkPhysicalDeviceSparseImageFormatInfo2 VkPhysicalDeviceSparseImageFormatInfo2KHR; +typedef struct VkPhysicalDeviceToolProperties VkPhysicalDeviceToolPropertiesEXT; -typedef struct VkPresentRegionKHR { - uint32_t rectangleCount; - const VkRectLayerKHR * pRectangles; -} VkPresentRegionKHR; +typedef struct VkPhysicalDeviceCustomBorderColorFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 customBorderColors; + VkBool32 customBorderColorWithoutFormat; +} VkPhysicalDeviceCustomBorderColorFeaturesEXT; -typedef struct VkPhysicalDeviceVariablePointersFeatures { +typedef struct VkSamplerBorderColorComponentMappingCreateInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 variablePointersStorageBuffer; - VkBool32 variablePointers; -} VkPhysicalDeviceVariablePointersFeatures; + const void * pNext; + VkComponentMapping components; + VkBool32 srgb; +} VkSamplerBorderColorComponentMappingCreateInfoEXT; -typedef struct VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointersFeaturesKHR; +typedef struct VkPhysicalDeviceBorderColorSwizzleFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 borderColorSwizzle; + VkBool32 borderColorSwizzleFromImage; +} VkPhysicalDeviceBorderColorSwizzleFeaturesEXT; -typedef struct VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeaturesKHR; +typedef union VkDeviceOrHostAddressKHR { + VkDeviceAddress deviceAddress; + void * hostAddress; +} VkDeviceOrHostAddressKHR; -typedef struct VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeatures; +typedef union VkDeviceOrHostAddressConstKHR { + VkDeviceAddress deviceAddress; + const void * hostAddress; +} VkDeviceOrHostAddressConstKHR; -typedef struct VkExternalMemoryProperties { - VkExternalMemoryFeatureFlags externalMemoryFeatures; - VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes; - VkExternalMemoryHandleTypeFlags compatibleHandleTypes; -} VkExternalMemoryProperties; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef union VkDeviceOrHostAddressConstAMDX { + VkDeviceAddress deviceAddress; + const void * hostAddress; +} VkDeviceOrHostAddressConstAMDX; -typedef struct VkExternalMemoryProperties VkExternalMemoryPropertiesKHR; +#endif -typedef struct VkExternalImageFormatProperties { +typedef struct VkAccelerationStructureGeometryTrianglesDataKHR { VkStructureType sType; - void * pNext; - VkExternalMemoryProperties externalMemoryProperties; -} VkExternalImageFormatProperties; - -typedef struct VkExternalImageFormatProperties VkExternalImageFormatPropertiesKHR; + const void * pNext; + VkFormat vertexFormat; + VkDeviceOrHostAddressConstKHR vertexData; + VkDeviceSize vertexStride; + uint32_t maxVertex; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexData; + VkDeviceOrHostAddressConstKHR transformData; +} VkAccelerationStructureGeometryTrianglesDataKHR; -typedef struct VkPhysicalDeviceExternalBufferInfo { +typedef struct VkAccelerationStructureGeometryAabbsDataKHR { VkStructureType sType; - const void * pNext; - VkBufferCreateFlags flags; - VkBufferUsageFlags usage; - VkExternalMemoryHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalBufferInfo; + const void * pNext; + VkDeviceOrHostAddressConstKHR data; + VkDeviceSize stride; +} VkAccelerationStructureGeometryAabbsDataKHR; -typedef struct VkPhysicalDeviceExternalBufferInfo VkPhysicalDeviceExternalBufferInfoKHR; +typedef struct VkAccelerationStructureGeometryInstancesDataKHR { + VkStructureType sType; + const void * pNext; + VkBool32 arrayOfPointers; + VkDeviceOrHostAddressConstKHR data; +} VkAccelerationStructureGeometryInstancesDataKHR; -typedef struct VkExternalBufferProperties { +typedef struct VkAccelerationStructureGeometryLinearSweptSpheresDataNV { VkStructureType sType; - void * pNext; - VkExternalMemoryProperties externalMemoryProperties; -} VkExternalBufferProperties; + const void * pNext; + VkFormat vertexFormat; + VkDeviceOrHostAddressConstKHR vertexData; + VkDeviceSize vertexStride; + VkFormat radiusFormat; + VkDeviceOrHostAddressConstKHR radiusData; + VkDeviceSize radiusStride; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexData; + VkDeviceSize indexStride; + VkRayTracingLssIndexingModeNV indexingMode; + VkRayTracingLssPrimitiveEndCapsModeNV endCapsMode; +} VkAccelerationStructureGeometryLinearSweptSpheresDataNV; + +typedef struct VkAccelerationStructureGeometrySpheresDataNV { + VkStructureType sType; + const void * pNext; + VkFormat vertexFormat; + VkDeviceOrHostAddressConstKHR vertexData; + VkDeviceSize vertexStride; + VkFormat radiusFormat; + VkDeviceOrHostAddressConstKHR radiusData; + VkDeviceSize radiusStride; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexData; + VkDeviceSize indexStride; +} VkAccelerationStructureGeometrySpheresDataNV; -typedef struct VkExternalBufferProperties VkExternalBufferPropertiesKHR; +typedef union VkAccelerationStructureGeometryDataKHR { + VkAccelerationStructureGeometryTrianglesDataKHR triangles; + VkAccelerationStructureGeometryAabbsDataKHR aabbs; + VkAccelerationStructureGeometryInstancesDataKHR instances; +} VkAccelerationStructureGeometryDataKHR; -typedef struct VkPhysicalDeviceIDProperties { +typedef struct VkAccelerationStructureGeometryKHR { VkStructureType sType; - void * pNext; - uint8_t deviceUUID [ VK_UUID_SIZE ]; - uint8_t driverUUID [ VK_UUID_SIZE ]; - uint8_t deviceLUID [ VK_LUID_SIZE ]; - uint32_t deviceNodeMask; - VkBool32 deviceLUIDValid; -} VkPhysicalDeviceIDProperties; + const void * pNext; + VkGeometryTypeKHR geometryType; + VkAccelerationStructureGeometryDataKHR geometry; + VkGeometryFlagsKHR flags; +} VkAccelerationStructureGeometryKHR; -typedef struct VkPhysicalDeviceIDProperties VkPhysicalDeviceIDPropertiesKHR; +typedef struct VkAccelerationStructureBuildGeometryInfoKHR { + VkStructureType sType; + const void * pNext; + VkAccelerationStructureTypeKHR type; + VkBuildAccelerationStructureFlagsKHR flags; + VkBuildAccelerationStructureModeKHR mode; + VkAccelerationStructureKHR srcAccelerationStructure; + VkAccelerationStructureKHR dstAccelerationStructure; + uint32_t geometryCount; + const VkAccelerationStructureGeometryKHR * pGeometries; + const VkAccelerationStructureGeometryKHR * const* ppGeometries; + VkDeviceOrHostAddressKHR scratchData; +} VkAccelerationStructureBuildGeometryInfoKHR; -typedef struct VkExternalMemoryImageCreateInfo { +typedef struct VkAccelerationStructureCreateInfoKHR { VkStructureType sType; - const void * pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExternalMemoryImageCreateInfo; + const void * pNext; + VkAccelerationStructureCreateFlagsKHR createFlags; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; + VkAccelerationStructureTypeKHR type; + VkDeviceAddress deviceAddress; +} VkAccelerationStructureCreateInfoKHR; -typedef struct VkExternalMemoryImageCreateInfo VkExternalMemoryImageCreateInfoKHR; +typedef struct VkAccelerationStructureInstanceKHR { + VkTransformMatrixKHR transform; + uint32_t instanceCustomIndex :24; + uint32_t mask :8; + uint32_t instanceShaderBindingTableRecordOffset :24; + VkGeometryInstanceFlagsKHR flags :8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureInstanceKHR; -typedef struct VkExternalMemoryBufferCreateInfo { +typedef struct VkAccelerationStructureInstanceKHR VkAccelerationStructureInstanceNV; + +typedef struct VkCopyAccelerationStructureToMemoryInfoKHR { VkStructureType sType; - const void * pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExternalMemoryBufferCreateInfo; + const void * pNext; + VkAccelerationStructureKHR src; + VkDeviceOrHostAddressKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyAccelerationStructureToMemoryInfoKHR; -typedef struct VkExternalMemoryBufferCreateInfo VkExternalMemoryBufferCreateInfoKHR; +typedef struct VkCopyMemoryToAccelerationStructureInfoKHR { + VkStructureType sType; + const void * pNext; + VkDeviceOrHostAddressConstKHR src; + VkAccelerationStructureKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyMemoryToAccelerationStructureInfoKHR; -typedef struct VkExportMemoryAllocateInfo { +typedef struct VkPhysicalDeviceExtendedDynamicStateFeaturesEXT { VkStructureType sType; - const void * pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExportMemoryAllocateInfo; + void * pNext; + VkBool32 extendedDynamicState; +} VkPhysicalDeviceExtendedDynamicStateFeaturesEXT; -typedef struct VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR; +typedef struct VkPhysicalDeviceExtendedDynamicState2FeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 extendedDynamicState2; + VkBool32 extendedDynamicState2LogicOp; + VkBool32 extendedDynamicState2PatchControlPoints; +} VkPhysicalDeviceExtendedDynamicState2FeaturesEXT; -typedef struct VkExternalSemaphoreProperties { +typedef struct VkPhysicalDeviceExtendedDynamicState3FeaturesEXT { VkStructureType sType; - void * pNext; - VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes; - VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes; - VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures; -} VkExternalSemaphoreProperties; + void * pNext; + VkBool32 extendedDynamicState3TessellationDomainOrigin; + VkBool32 extendedDynamicState3DepthClampEnable; + VkBool32 extendedDynamicState3PolygonMode; + VkBool32 extendedDynamicState3RasterizationSamples; + VkBool32 extendedDynamicState3SampleMask; + VkBool32 extendedDynamicState3AlphaToCoverageEnable; + VkBool32 extendedDynamicState3AlphaToOneEnable; + VkBool32 extendedDynamicState3LogicOpEnable; + VkBool32 extendedDynamicState3ColorBlendEnable; + VkBool32 extendedDynamicState3ColorBlendEquation; + VkBool32 extendedDynamicState3ColorWriteMask; + VkBool32 extendedDynamicState3RasterizationStream; + VkBool32 extendedDynamicState3ConservativeRasterizationMode; + VkBool32 extendedDynamicState3ExtraPrimitiveOverestimationSize; + VkBool32 extendedDynamicState3DepthClipEnable; + VkBool32 extendedDynamicState3SampleLocationsEnable; + VkBool32 extendedDynamicState3ColorBlendAdvanced; + VkBool32 extendedDynamicState3ProvokingVertexMode; + VkBool32 extendedDynamicState3LineRasterizationMode; + VkBool32 extendedDynamicState3LineStippleEnable; + VkBool32 extendedDynamicState3DepthClipNegativeOneToOne; + VkBool32 extendedDynamicState3ViewportWScalingEnable; + VkBool32 extendedDynamicState3ViewportSwizzle; + VkBool32 extendedDynamicState3CoverageToColorEnable; + VkBool32 extendedDynamicState3CoverageToColorLocation; + VkBool32 extendedDynamicState3CoverageModulationMode; + VkBool32 extendedDynamicState3CoverageModulationTableEnable; + VkBool32 extendedDynamicState3CoverageModulationTable; + VkBool32 extendedDynamicState3CoverageReductionMode; + VkBool32 extendedDynamicState3RepresentativeFragmentTestEnable; + VkBool32 extendedDynamicState3ShadingRateImageEnable; +} VkPhysicalDeviceExtendedDynamicState3FeaturesEXT; + +typedef struct VkPhysicalDeviceExtendedDynamicState3PropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 dynamicPrimitiveTopologyUnrestricted; +} VkPhysicalDeviceExtendedDynamicState3PropertiesEXT; -typedef struct VkExternalSemaphoreProperties VkExternalSemaphorePropertiesKHR; +typedef struct VkColorBlendAdvancedEXT { + VkBlendOp advancedBlendOp; + VkBool32 srcPremultiplied; + VkBool32 dstPremultiplied; + VkBlendOverlapEXT blendOverlap; + VkBool32 clampResults; +} VkColorBlendAdvancedEXT; -typedef struct VkExportSemaphoreCreateInfo { +typedef struct VkPhysicalDevicePartitionedAccelerationStructureFeaturesNV { VkStructureType sType; - const void * pNext; - VkExternalSemaphoreHandleTypeFlags handleTypes; -} VkExportSemaphoreCreateInfo; + void * pNext; + VkBool32 partitionedAccelerationStructure; +} VkPhysicalDevicePartitionedAccelerationStructureFeaturesNV; -typedef struct VkExportSemaphoreCreateInfo VkExportSemaphoreCreateInfoKHR; +typedef struct VkBuildPartitionedAccelerationStructureIndirectCommandNV { + VkPartitionedAccelerationStructureOpTypeNV opType; + uint32_t argCount; + VkStridedDeviceAddressNV argData; +} VkBuildPartitionedAccelerationStructureIndirectCommandNV; -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkImportSemaphoreWin32HandleInfoKHR { +typedef struct VkPartitionedAccelerationStructureFlagsNV { VkStructureType sType; - const void * pNext; - VkSemaphore semaphore; - VkSemaphoreImportFlags flags; - VkExternalSemaphoreHandleTypeFlagBits handleType; - HANDLE handle; - LPCWSTR name; -} VkImportSemaphoreWin32HandleInfoKHR; -#endif - -typedef struct VkImportSemaphoreFdInfoKHR { + void * pNext; + VkBool32 enablePartitionTranslation; +} VkPartitionedAccelerationStructureFlagsNV; + +typedef struct VkPartitionedAccelerationStructureWriteInstanceDataNV { + VkTransformMatrixKHR transform; + float explicitAABB [6]; + uint32_t instanceID; + uint32_t instanceMask; + uint32_t instanceContributionToHitGroupIndex; + VkPartitionedAccelerationStructureInstanceFlagsNV instanceFlags; + uint32_t instanceIndex; + uint32_t partitionIndex; + VkDeviceAddress accelerationStructure; +} VkPartitionedAccelerationStructureWriteInstanceDataNV; + +typedef struct VkPartitionedAccelerationStructureUpdateInstanceDataNV { + uint32_t instanceIndex; + uint32_t instanceContributionToHitGroupIndex; + VkDeviceAddress accelerationStructure; +} VkPartitionedAccelerationStructureUpdateInstanceDataNV; + +typedef struct VkWriteDescriptorSetPartitionedAccelerationStructureNV { VkStructureType sType; - const void * pNext; - VkSemaphore semaphore; - VkSemaphoreImportFlags flags; - VkExternalSemaphoreHandleTypeFlagBits handleType; - int fd; -} VkImportSemaphoreFdInfoKHR; + void * pNext; + uint32_t accelerationStructureCount; + const VkDeviceAddress * pAccelerationStructures; +} VkWriteDescriptorSetPartitionedAccelerationStructureNV; -typedef struct VkExternalFenceProperties { +typedef struct VkPartitionedAccelerationStructureInstancesInputNV { VkStructureType sType; - void * pNext; - VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes; - VkExternalFenceHandleTypeFlags compatibleHandleTypes; - VkExternalFenceFeatureFlags externalFenceFeatures; -} VkExternalFenceProperties; - -typedef struct VkExternalFenceProperties VkExternalFencePropertiesKHR; + void * pNext; + VkBuildAccelerationStructureFlagsKHR flags; + uint32_t instanceCount; + uint32_t maxInstancePerPartitionCount; + uint32_t partitionCount; + uint32_t maxInstanceInGlobalPartitionCount; +} VkPartitionedAccelerationStructureInstancesInputNV; -typedef struct VkExportFenceCreateInfo { +typedef struct VkBuildPartitionedAccelerationStructureInfoNV { VkStructureType sType; - const void * pNext; - VkExternalFenceHandleTypeFlags handleTypes; -} VkExportFenceCreateInfo; - -typedef struct VkExportFenceCreateInfo VkExportFenceCreateInfoKHR; + void * pNext; + VkPartitionedAccelerationStructureInstancesInputNV input; + VkDeviceAddress srcAccelerationStructureData; + VkDeviceAddress dstAccelerationStructureData; + VkDeviceAddress scratchData; + VkDeviceAddress srcInfos; + VkDeviceAddress srcInfosCount; +} VkBuildPartitionedAccelerationStructureInfoNV; -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkImportFenceWin32HandleInfoKHR { +typedef struct VkPhysicalDeviceDiagnosticsConfigFeaturesNV { VkStructureType sType; - const void * pNext; - VkFence fence; - VkFenceImportFlags flags; - VkExternalFenceHandleTypeFlagBits handleType; - HANDLE handle; - LPCWSTR name; -} VkImportFenceWin32HandleInfoKHR; -#endif + void * pNext; + VkBool32 diagnosticsConfig; +} VkPhysicalDeviceDiagnosticsConfigFeaturesNV; -typedef struct VkImportFenceFdInfoKHR { - VkStructureType sType; - const void * pNext; - VkFence fence; - VkFenceImportFlags flags; - VkExternalFenceHandleTypeFlagBits handleType; - int fd; -} VkImportFenceFdInfoKHR; +typedef struct VkDeviceDiagnosticsConfigCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkDeviceDiagnosticsConfigFlagsNV flags; +} VkDeviceDiagnosticsConfigCreateInfoNV; -typedef struct VkPhysicalDeviceMultiviewFeatures { +typedef struct VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures { VkStructureType sType; - void * pNext; - VkBool32 multiview; - VkBool32 multiviewGeometryShader; - VkBool32 multiviewTessellationShader; -} VkPhysicalDeviceMultiviewFeatures; + void * pNext; + VkBool32 shaderZeroInitializeWorkgroupMemory; +} VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures; -typedef struct VkPhysicalDeviceMultiviewFeatures VkPhysicalDeviceMultiviewFeaturesKHR; +typedef struct VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR; -typedef struct VkSurfaceCapabilities2EXT { +typedef struct VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR { VkStructureType sType; - void * pNext; - uint32_t minImageCount; - uint32_t maxImageCount; - VkExtent2D currentExtent; - VkExtent2D minImageExtent; - VkExtent2D maxImageExtent; - uint32_t maxImageArrayLayers; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkSurfaceTransformFlagBitsKHR currentTransform; - VkCompositeAlphaFlagsKHR supportedCompositeAlpha; - VkImageUsageFlags supportedUsageFlags; - VkSurfaceCounterFlagsEXT supportedSurfaceCounters; -} VkSurfaceCapabilities2EXT; + void * pNext; + VkBool32 shaderSubgroupUniformControlFlow; +} VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR; -typedef struct VkSwapchainCounterCreateInfoEXT { +typedef struct VkPhysicalDeviceRobustness2FeaturesKHR { VkStructureType sType; - const void * pNext; - VkSurfaceCounterFlagsEXT surfaceCounters; -} VkSwapchainCounterCreateInfoEXT; + void * pNext; + VkBool32 robustBufferAccess2; + VkBool32 robustImageAccess2; + VkBool32 nullDescriptor; +} VkPhysicalDeviceRobustness2FeaturesKHR; -typedef struct VkPhysicalDeviceGroupProperties { +typedef struct VkPhysicalDeviceRobustness2FeaturesKHR VkPhysicalDeviceRobustness2FeaturesEXT; + +typedef struct VkPhysicalDeviceRobustness2PropertiesKHR { VkStructureType sType; - void * pNext; - uint32_t physicalDeviceCount; - VkPhysicalDevice physicalDevices [ VK_MAX_DEVICE_GROUP_SIZE ]; - VkBool32 subsetAllocation; -} VkPhysicalDeviceGroupProperties; + void * pNext; + VkDeviceSize robustStorageBufferAccessSizeAlignment; + VkDeviceSize robustUniformBufferAccessSizeAlignment; +} VkPhysicalDeviceRobustness2PropertiesKHR; -typedef struct VkPhysicalDeviceGroupProperties VkPhysicalDeviceGroupPropertiesKHR; +typedef struct VkPhysicalDeviceRobustness2PropertiesKHR VkPhysicalDeviceRobustness2PropertiesEXT; -typedef struct VkMemoryAllocateFlagsInfo { +typedef struct VkPhysicalDeviceImageRobustnessFeatures { VkStructureType sType; - const void * pNext; - VkMemoryAllocateFlags flags; - uint32_t deviceMask; -} VkMemoryAllocateFlagsInfo; + void * pNext; + VkBool32 robustImageAccess; +} VkPhysicalDeviceImageRobustnessFeatures; -typedef struct VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR; +typedef struct VkPhysicalDeviceImageRobustnessFeatures VkPhysicalDeviceImageRobustnessFeaturesEXT; -typedef struct VkBindBufferMemoryInfo { +typedef struct VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR { VkStructureType sType; - const void * pNext; - VkBuffer buffer; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; -} VkBindBufferMemoryInfo; - -typedef struct VkBindBufferMemoryInfo VkBindBufferMemoryInfoKHR; + void * pNext; + VkBool32 workgroupMemoryExplicitLayout; + VkBool32 workgroupMemoryExplicitLayoutScalarBlockLayout; + VkBool32 workgroupMemoryExplicitLayout8BitAccess; + VkBool32 workgroupMemoryExplicitLayout16BitAccess; +} VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR; -typedef struct VkBindImageMemoryInfo { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDevicePortabilitySubsetFeaturesKHR { VkStructureType sType; - const void * pNext; - VkImage image; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; -} VkBindImageMemoryInfo; + void * pNext; + VkBool32 constantAlphaColorBlendFactors; + VkBool32 events; + VkBool32 imageViewFormatReinterpretation; + VkBool32 imageViewFormatSwizzle; + VkBool32 imageView2DOn3DImage; + VkBool32 multisampleArrayImage; + VkBool32 mutableComparisonSamplers; + VkBool32 pointPolygons; + VkBool32 samplerMipLodBias; + VkBool32 separateStencilMaskRef; + VkBool32 shaderSampleRateInterpolationFunctions; + VkBool32 tessellationIsolines; + VkBool32 tessellationPointMode; + VkBool32 triangleFans; + VkBool32 vertexAttributeAccessBeyondStride; +} VkPhysicalDevicePortabilitySubsetFeaturesKHR; -typedef struct VkBindImageMemoryInfo VkBindImageMemoryInfoKHR; +#endif -typedef struct VkDeviceGroupPresentCapabilitiesKHR { +typedef struct VkPhysicalDevice4444FormatsFeaturesEXT { VkStructureType sType; - const void * pNext; - uint32_t presentMask [ VK_MAX_DEVICE_GROUP_SIZE ]; - VkDeviceGroupPresentModeFlagsKHR modes; -} VkDeviceGroupPresentCapabilitiesKHR; + void * pNext; + VkBool32 formatA4R4G4B4; + VkBool32 formatA4B4G4R4; +} VkPhysicalDevice4444FormatsFeaturesEXT; -typedef struct VkDeviceGroupSwapchainCreateInfoKHR { +typedef struct VkPhysicalDeviceSubpassShadingFeaturesHUAWEI { VkStructureType sType; - const void * pNext; - VkDeviceGroupPresentModeFlagsKHR modes; -} VkDeviceGroupSwapchainCreateInfoKHR; + void * pNext; + VkBool32 subpassShading; +} VkPhysicalDeviceSubpassShadingFeaturesHUAWEI; -typedef struct VkDescriptorUpdateTemplateCreateInfo { - VkStructureType sType; - const void * pNext; - VkDescriptorUpdateTemplateCreateFlags flags; - uint32_t descriptorUpdateEntryCount; - const VkDescriptorUpdateTemplateEntry * pDescriptorUpdateEntries; - VkDescriptorUpdateTemplateType templateType; - VkDescriptorSetLayout descriptorSetLayout; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout pipelineLayout; - uint32_t set; -} VkDescriptorUpdateTemplateCreateInfo; +typedef struct VkPhysicalDeviceClusterCullingShaderFeaturesHUAWEI { + VkStructureType sType; + void * pNext; + VkBool32 clustercullingShader; + VkBool32 multiviewClusterCullingShader; +} VkPhysicalDeviceClusterCullingShaderFeaturesHUAWEI; -typedef struct VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR; +typedef struct VkPhysicalDeviceClusterCullingShaderVrsFeaturesHUAWEI { + VkStructureType sType; + void * pNext; + VkBool32 clusterShadingRate; +} VkPhysicalDeviceClusterCullingShaderVrsFeaturesHUAWEI; -typedef struct VkDisplayNativeHdrSurfaceCapabilitiesAMD { +typedef struct VkBufferCopy2 { VkStructureType sType; - void * pNext; - VkBool32 localDimmingSupport; -} VkDisplayNativeHdrSurfaceCapabilitiesAMD; + const void * pNext; + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy2; -typedef struct VkSwapchainDisplayNativeHdrCreateInfoAMD { +typedef struct VkBufferCopy2 VkBufferCopy2KHR; + +typedef struct VkImageCopy2 { VkStructureType sType; - const void * pNext; - VkBool32 localDimmingEnable; -} VkSwapchainDisplayNativeHdrCreateInfoAMD; + const void * pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy2; -typedef struct VkPresentTimesInfoGOOGLE { +typedef struct VkImageCopy2 VkImageCopy2KHR; + +typedef struct VkImageBlit2 { VkStructureType sType; - const void * pNext; - uint32_t swapchainCount; - const VkPresentTimeGOOGLE * pTimes; -} VkPresentTimesInfoGOOGLE; + const void * pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets [2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets [2]; +} VkImageBlit2; -#if defined(VK_USE_PLATFORM_IOS_MVK) -typedef struct VkIOSSurfaceCreateInfoMVK { +typedef struct VkImageBlit2 VkImageBlit2KHR; + +typedef struct VkBufferImageCopy2 { VkStructureType sType; - const void * pNext; - VkIOSSurfaceCreateFlagsMVK flags; - const void * pView; -} VkIOSSurfaceCreateInfoMVK; -#endif + const void * pNext; + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy2; -#if defined(VK_USE_PLATFORM_MACOS_MVK) -typedef struct VkMacOSSurfaceCreateInfoMVK { +typedef struct VkBufferImageCopy2 VkBufferImageCopy2KHR; + +typedef struct VkImageResolve2 { VkStructureType sType; - const void * pNext; - VkMacOSSurfaceCreateFlagsMVK flags; - const void * pView; -} VkMacOSSurfaceCreateInfoMVK; -#endif + const void * pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve2; -#if defined(VK_USE_PLATFORM_METAL_EXT) -typedef struct VkMetalSurfaceCreateInfoEXT { +typedef struct VkImageResolve2 VkImageResolve2KHR; + +typedef struct VkCopyBufferInfo2 { VkStructureType sType; - const void * pNext; - VkMetalSurfaceCreateFlagsEXT flags; - const CAMetalLayer * pLayer; -} VkMetalSurfaceCreateInfoEXT; -#endif + const void * pNext; + VkBuffer srcBuffer; + VkBuffer dstBuffer; + uint32_t regionCount; + const VkBufferCopy2 * pRegions; +} VkCopyBufferInfo2; -typedef struct VkPipelineViewportWScalingStateCreateInfoNV { +typedef struct VkCopyBufferInfo2 VkCopyBufferInfo2KHR; + +typedef struct VkCopyImageInfo2 { VkStructureType sType; - const void * pNext; - VkBool32 viewportWScalingEnable; - uint32_t viewportCount; - const VkViewportWScalingNV * pViewportWScalings; -} VkPipelineViewportWScalingStateCreateInfoNV; + const void * pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageCopy2 * pRegions; +} VkCopyImageInfo2; -typedef struct VkPipelineViewportSwizzleStateCreateInfoNV { +typedef struct VkCopyImageInfo2 VkCopyImageInfo2KHR; + +typedef struct VkBlitImageInfo2 { VkStructureType sType; const void * pNext; - VkPipelineViewportSwizzleStateCreateFlagsNV flags; - uint32_t viewportCount; - const VkViewportSwizzleNV * pViewportSwizzles; -} VkPipelineViewportSwizzleStateCreateInfoNV; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageBlit2 * pRegions; + VkFilter filter; +} VkBlitImageInfo2; -typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT { - VkStructureType sType; - const void * pNext; - VkPipelineDiscardRectangleStateCreateFlagsEXT flags; - VkDiscardRectangleModeEXT discardRectangleMode; - uint32_t discardRectangleCount; - const VkRect2D * pDiscardRectangles; -} VkPipelineDiscardRectangleStateCreateInfoEXT; +typedef struct VkBlitImageInfo2 VkBlitImageInfo2KHR; -typedef struct VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX { +typedef struct VkCopyBufferToImageInfo2 { VkStructureType sType; - void * pNext; - VkBool32 perViewPositionAllComponents; -} VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX; + const void * pNext; + VkBuffer srcBuffer; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkBufferImageCopy2 * pRegions; +} VkCopyBufferToImageInfo2; -typedef struct VkInputAttachmentAspectReference { - uint32_t subpass; - uint32_t inputAttachmentIndex; - VkImageAspectFlags aspectMask; -} VkInputAttachmentAspectReference; +typedef struct VkCopyBufferToImageInfo2 VkCopyBufferToImageInfo2KHR; -typedef struct VkInputAttachmentAspectReference VkInputAttachmentAspectReferenceKHR; +typedef struct VkCopyImageToBufferInfo2 { + VkStructureType sType; + const void * pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkBuffer dstBuffer; + uint32_t regionCount; + const VkBufferImageCopy2 * pRegions; +} VkCopyImageToBufferInfo2; -typedef struct VkRenderPassInputAttachmentAspectCreateInfo { +typedef struct VkCopyImageToBufferInfo2 VkCopyImageToBufferInfo2KHR; + +typedef struct VkResolveImageInfo2 { VkStructureType sType; - const void * pNext; - uint32_t aspectReferenceCount; - const VkInputAttachmentAspectReference * pAspectReferences; -} VkRenderPassInputAttachmentAspectCreateInfo; + const void * pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageResolve2 * pRegions; +} VkResolveImageInfo2; -typedef struct VkRenderPassInputAttachmentAspectCreateInfo VkRenderPassInputAttachmentAspectCreateInfoKHR; +typedef struct VkResolveImageInfo2 VkResolveImageInfo2KHR; -typedef struct VkSurfaceCapabilities2KHR { +typedef struct VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT { VkStructureType sType; - void * pNext; - VkSurfaceCapabilitiesKHR surfaceCapabilities; -} VkSurfaceCapabilities2KHR; + void * pNext; + VkBool32 shaderImageInt64Atomics; + VkBool32 sparseImageInt64Atomics; +} VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT; -typedef struct VkDisplayProperties2KHR { +typedef struct VkFragmentShadingRateAttachmentInfoKHR { VkStructureType sType; - void * pNext; - VkDisplayPropertiesKHR displayProperties; -} VkDisplayProperties2KHR; + const void * pNext; + const VkAttachmentReference2 * pFragmentShadingRateAttachment; + VkExtent2D shadingRateAttachmentTexelSize; +} VkFragmentShadingRateAttachmentInfoKHR; -typedef struct VkDisplayPlaneCapabilities2KHR { +typedef struct VkPhysicalDeviceFragmentShadingRateFeaturesKHR { VkStructureType sType; - void * pNext; - VkDisplayPlaneCapabilitiesKHR capabilities; -} VkDisplayPlaneCapabilities2KHR; + void * pNext; + VkBool32 pipelineFragmentShadingRate; + VkBool32 primitiveFragmentShadingRate; + VkBool32 attachmentFragmentShadingRate; +} VkPhysicalDeviceFragmentShadingRateFeaturesKHR; -typedef struct VkSharedPresentSurfaceCapabilitiesKHR { +typedef struct VkPhysicalDeviceFragmentShadingRatePropertiesKHR { VkStructureType sType; - void * pNext; - VkImageUsageFlags sharedPresentSupportedUsageFlags; -} VkSharedPresentSurfaceCapabilitiesKHR; + void * pNext; + VkExtent2D minFragmentShadingRateAttachmentTexelSize; + VkExtent2D maxFragmentShadingRateAttachmentTexelSize; + uint32_t maxFragmentShadingRateAttachmentTexelSizeAspectRatio; + VkBool32 primitiveFragmentShadingRateWithMultipleViewports; + VkBool32 layeredShadingRateAttachments; + VkBool32 fragmentShadingRateNonTrivialCombinerOps; + VkExtent2D maxFragmentSize; + uint32_t maxFragmentSizeAspectRatio; + uint32_t maxFragmentShadingRateCoverageSamples; + VkSampleCountFlagBits maxFragmentShadingRateRasterizationSamples; + VkBool32 fragmentShadingRateWithShaderDepthStencilWrites; + VkBool32 fragmentShadingRateWithSampleMask; + VkBool32 fragmentShadingRateWithShaderSampleMask; + VkBool32 fragmentShadingRateWithConservativeRasterization; + VkBool32 fragmentShadingRateWithFragmentShaderInterlock; + VkBool32 fragmentShadingRateWithCustomSampleLocations; + VkBool32 fragmentShadingRateStrictMultiplyCombiner; +} VkPhysicalDeviceFragmentShadingRatePropertiesKHR; + +typedef struct VkPhysicalDeviceFragmentShadingRateKHR { + VkStructureType sType; + void * pNext; + VkSampleCountFlags sampleCounts; + VkExtent2D fragmentSize; +} VkPhysicalDeviceFragmentShadingRateKHR; -typedef struct VkPhysicalDevice16BitStorageFeatures { +typedef struct VkPhysicalDeviceShaderTerminateInvocationFeatures { VkStructureType sType; - void * pNext; - VkBool32 storageBuffer16BitAccess; - VkBool32 uniformAndStorageBuffer16BitAccess; - VkBool32 storagePushConstant16; - VkBool32 storageInputOutput16; -} VkPhysicalDevice16BitStorageFeatures; + void * pNext; + VkBool32 shaderTerminateInvocation; +} VkPhysicalDeviceShaderTerminateInvocationFeatures; -typedef struct VkPhysicalDevice16BitStorageFeatures VkPhysicalDevice16BitStorageFeaturesKHR; +typedef struct VkPhysicalDeviceShaderTerminateInvocationFeatures VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR; -typedef struct VkPhysicalDeviceSubgroupProperties { +typedef struct VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV { VkStructureType sType; - void * pNext; - uint32_t subgroupSize; - VkShaderStageFlags supportedStages; - VkSubgroupFeatureFlags supportedOperations; - VkBool32 quadOperationsInAllStages; -} VkPhysicalDeviceSubgroupProperties; + void * pNext; + VkBool32 fragmentShadingRateEnums; + VkBool32 supersampleFragmentShadingRates; + VkBool32 noInvocationFragmentShadingRates; +} VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV; -typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures { +typedef struct VkAccelerationStructureBuildSizesInfoKHR { VkStructureType sType; - void * pNext; - VkBool32 shaderSubgroupExtendedTypes; -} VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures; + const void * pNext; + VkDeviceSize accelerationStructureSize; + VkDeviceSize updateScratchSize; + VkDeviceSize buildScratchSize; +} VkAccelerationStructureBuildSizesInfoKHR; -typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR; +typedef struct VkPhysicalDeviceImage2DViewOf3DFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 image2DViewOf3D; + VkBool32 sampler2DViewOf3D; +} VkPhysicalDeviceImage2DViewOf3DFeaturesEXT; -typedef struct VkMemoryRequirements2 { +typedef struct VkPhysicalDeviceImageSlicedViewOf3DFeaturesEXT { VkStructureType sType; - void * pNext; - VkMemoryRequirements memoryRequirements; -} VkMemoryRequirements2; + void * pNext; + VkBool32 imageSlicedViewOf3D; +} VkPhysicalDeviceImageSlicedViewOf3DFeaturesEXT; -typedef struct VkMemoryRequirements2 VkMemoryRequirements2KHR; +typedef struct VkPhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 attachmentFeedbackLoopDynamicState; +} VkPhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT; -typedef struct VkSparseImageMemoryRequirements2 { +typedef struct VkPhysicalDeviceLegacyVertexAttributesFeaturesEXT { VkStructureType sType; - void * pNext; - VkSparseImageMemoryRequirements memoryRequirements; -} VkSparseImageMemoryRequirements2; + void * pNext; + VkBool32 legacyVertexAttributes; +} VkPhysicalDeviceLegacyVertexAttributesFeaturesEXT; -typedef struct VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR; +typedef struct VkPhysicalDeviceLegacyVertexAttributesPropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 nativeUnalignedPerformance; +} VkPhysicalDeviceLegacyVertexAttributesPropertiesEXT; -typedef struct VkMemoryDedicatedRequirements { +typedef struct VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 prefersDedicatedAllocation; - VkBool32 requiresDedicatedAllocation; -} VkMemoryDedicatedRequirements; + void * pNext; + VkBool32 mutableDescriptorType; +} VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT; + +typedef struct VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE; + +typedef struct VkPhysicalDeviceDepthClipControlFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 depthClipControl; +} VkPhysicalDeviceDepthClipControlFeaturesEXT; -typedef struct VkMemoryDedicatedRequirements VkMemoryDedicatedRequirementsKHR; +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 deviceGeneratedCommands; + VkBool32 dynamicGeneratedPipelineLayout; +} VkPhysicalDeviceDeviceGeneratedCommandsFeaturesEXT; -typedef struct VkImageViewUsageCreateInfo { +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t maxIndirectPipelineCount; + uint32_t maxIndirectShaderObjectCount; + uint32_t maxIndirectSequenceCount; + uint32_t maxIndirectCommandsTokenCount; + uint32_t maxIndirectCommandsTokenOffset; + uint32_t maxIndirectCommandsIndirectStride; + VkIndirectCommandsInputModeFlagsEXT supportedIndirectCommandsInputModes; + VkShaderStageFlags supportedIndirectCommandsShaderStages; + VkShaderStageFlags supportedIndirectCommandsShaderStagesPipelineBinding; + VkShaderStageFlags supportedIndirectCommandsShaderStagesShaderBinding; + VkBool32 deviceGeneratedCommandsTransformFeedback; + VkBool32 deviceGeneratedCommandsMultiDrawIndirectCount; +} VkPhysicalDeviceDeviceGeneratedCommandsPropertiesEXT; + +typedef struct VkIndirectExecutionSetShaderInfoEXT { VkStructureType sType; const void * pNext; - VkImageUsageFlags usage; -} VkImageViewUsageCreateInfo; + uint32_t shaderCount; + const VkShaderEXT * pInitialShaders; + const VkIndirectExecutionSetShaderLayoutInfoEXT * pSetLayoutInfos; + uint32_t maxShaderCount; + uint32_t pushConstantRangeCount; + const VkPushConstantRange * pPushConstantRanges; +} VkIndirectExecutionSetShaderInfoEXT; -typedef struct VkImageViewUsageCreateInfo VkImageViewUsageCreateInfoKHR; +typedef union VkIndirectExecutionSetInfoEXT { + const VkIndirectExecutionSetPipelineInfoEXT * pPipelineInfo; + const VkIndirectExecutionSetShaderInfoEXT * pShaderInfo; +} VkIndirectExecutionSetInfoEXT; -typedef struct VkSamplerYcbcrConversionCreateInfo { +typedef struct VkIndirectExecutionSetCreateInfoEXT { VkStructureType sType; - const void * pNext; - VkFormat format; - VkSamplerYcbcrModelConversion ycbcrModel; - VkSamplerYcbcrRange ycbcrRange; - VkComponentMapping components; - VkChromaLocation xChromaOffset; - VkChromaLocation yChromaOffset; - VkFilter chromaFilter; - VkBool32 forceExplicitReconstruction; -} VkSamplerYcbcrConversionCreateInfo; + const void * pNext; + VkIndirectExecutionSetInfoTypeEXT type; + VkIndirectExecutionSetInfoEXT info; +} VkIndirectExecutionSetCreateInfoEXT; -typedef struct VkSamplerYcbcrConversionCreateInfo VkSamplerYcbcrConversionCreateInfoKHR; +typedef struct VkGeneratedCommandsInfoEXT { + VkStructureType sType; + const void * pNext; + VkShaderStageFlags shaderStages; + VkIndirectExecutionSetEXT indirectExecutionSet; + VkIndirectCommandsLayoutEXT indirectCommandsLayout; + VkDeviceAddress indirectAddress; + VkDeviceSize indirectAddressSize; + VkDeviceAddress preprocessAddress; + VkDeviceSize preprocessSize; + uint32_t maxSequenceCount; + VkDeviceAddress sequenceCountAddress; + uint32_t maxDrawCount; +} VkGeneratedCommandsInfoEXT; + +typedef struct VkDrawIndirectCountIndirectCommandEXT { + VkDeviceAddress bufferAddress; + uint32_t stride; + uint32_t commandCount; +} VkDrawIndirectCountIndirectCommandEXT; + +typedef struct VkBindVertexBufferIndirectCommandEXT { + VkDeviceAddress bufferAddress; + uint32_t size; + uint32_t stride; +} VkBindVertexBufferIndirectCommandEXT; + +typedef struct VkBindIndexBufferIndirectCommandEXT { + VkDeviceAddress bufferAddress; + uint32_t size; + VkIndexType indexType; +} VkBindIndexBufferIndirectCommandEXT; + +typedef struct VkIndirectCommandsPushConstantTokenEXT { + VkPushConstantRange updateRange; +} VkIndirectCommandsPushConstantTokenEXT; + +typedef struct VkIndirectCommandsExecutionSetTokenEXT { + VkIndirectExecutionSetInfoTypeEXT type; + VkShaderStageFlags shaderStages; +} VkIndirectCommandsExecutionSetTokenEXT; + +typedef union VkIndirectCommandsTokenDataEXT { + const VkIndirectCommandsPushConstantTokenEXT * pPushConstant; + const VkIndirectCommandsVertexBufferTokenEXT * pVertexBuffer; + const VkIndirectCommandsIndexBufferTokenEXT * pIndexBuffer; + const VkIndirectCommandsExecutionSetTokenEXT * pExecutionSet; +} VkIndirectCommandsTokenDataEXT; + +typedef struct VkPipelineViewportDepthClipControlCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkBool32 negativeOneToOne; +} VkPipelineViewportDepthClipControlCreateInfoEXT; -typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures { +typedef struct VkPhysicalDeviceDepthClampControlFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 samplerYcbcrConversion; -} VkPhysicalDeviceSamplerYcbcrConversionFeatures; + void * pNext; + VkBool32 depthClampControl; +} VkPhysicalDeviceDepthClampControlFeaturesEXT; -typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR; +typedef struct VkPipelineViewportDepthClampControlCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkDepthClampModeEXT depthClampMode; + const VkDepthClampRangeEXT * pDepthClampRange; +} VkPipelineViewportDepthClampControlCreateInfoEXT; -typedef struct VkTextureLODGatherFormatPropertiesAMD { +typedef struct VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 supportsTextureGatherLODBiasAMD; -} VkTextureLODGatherFormatPropertiesAMD; + void * pNext; + VkBool32 vertexInputDynamicState; +} VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT; -typedef struct VkConditionalRenderingBeginInfoEXT { +typedef struct VkPhysicalDeviceExternalMemoryRDMAFeaturesNV { VkStructureType sType; - const void * pNext; - VkBuffer buffer; - VkDeviceSize offset; - VkConditionalRenderingFlagsEXT flags; -} VkConditionalRenderingBeginInfoEXT; + void * pNext; + VkBool32 externalMemoryRDMA; +} VkPhysicalDeviceExternalMemoryRDMAFeaturesNV; -typedef struct VkProtectedSubmitInfo { +typedef struct VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR { VkStructureType sType; - const void * pNext; - VkBool32 protectedSubmit; -} VkProtectedSubmitInfo; + void * pNext; + VkBool32 shaderRelaxedExtendedInstruction; +} VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR; -typedef struct VkPhysicalDeviceProtectedMemoryFeatures { +typedef struct VkPhysicalDeviceColorWriteEnableFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 protectedMemory; -} VkPhysicalDeviceProtectedMemoryFeatures; + void * pNext; + VkBool32 colorWriteEnable; +} VkPhysicalDeviceColorWriteEnableFeaturesEXT; -typedef struct VkPhysicalDeviceProtectedMemoryProperties { +typedef struct VkPipelineColorWriteCreateInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 protectedNoFault; -} VkPhysicalDeviceProtectedMemoryProperties; + const void * pNext; + uint32_t attachmentCount; + const VkBool32 * pColorWriteEnables; +} VkPipelineColorWriteCreateInfoEXT; -typedef struct VkDeviceQueueInfo2 { +typedef struct VkMemoryBarrier2 { VkStructureType sType; - const void * pNext; - VkDeviceQueueCreateFlags flags; - uint32_t queueFamilyIndex; - uint32_t queueIndex; -} VkDeviceQueueInfo2; + const void * pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; +} VkMemoryBarrier2; -typedef struct VkPipelineCoverageToColorStateCreateInfoNV { +typedef struct VkMemoryBarrier2 VkMemoryBarrier2KHR; + +typedef struct VkImageMemoryBarrier2 { VkStructureType sType; - const void * pNext; - VkPipelineCoverageToColorStateCreateFlagsNV flags; - VkBool32 coverageToColorEnable; - uint32_t coverageToColorLocation; -} VkPipelineCoverageToColorStateCreateInfoNV; + const void * pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier2; + +typedef struct VkImageMemoryBarrier2 VkImageMemoryBarrier2KHR; + +typedef struct VkBufferMemoryBarrier2 { + VkStructureType sType; + const void * pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier2; + +typedef struct VkBufferMemoryBarrier2 VkBufferMemoryBarrier2KHR; + +typedef struct VkMemoryBarrierAccessFlags3KHR { + VkStructureType sType; + const void * pNext; + VkAccessFlags3KHR srcAccessMask3; + VkAccessFlags3KHR dstAccessMask3; +} VkMemoryBarrierAccessFlags3KHR; + +typedef struct VkDependencyInfo { + VkStructureType sType; + const void * pNext; + VkDependencyFlags dependencyFlags; + uint32_t memoryBarrierCount; + const VkMemoryBarrier2 * pMemoryBarriers; + uint32_t bufferMemoryBarrierCount; + const VkBufferMemoryBarrier2 * pBufferMemoryBarriers; + uint32_t imageMemoryBarrierCount; + const VkImageMemoryBarrier2 * pImageMemoryBarriers; +} VkDependencyInfo; + +typedef struct VkDependencyInfo VkDependencyInfoKHR; + +typedef struct VkSemaphoreSubmitInfo { + VkStructureType sType; + const void * pNext; + VkSemaphore semaphore; + uint64_t value; + VkPipelineStageFlags2 stageMask; + uint32_t deviceIndex; +} VkSemaphoreSubmitInfo; + +typedef struct VkSemaphoreSubmitInfo VkSemaphoreSubmitInfoKHR; + +typedef struct VkSubmitInfo2 { + VkStructureType sType; + const void * pNext; + VkSubmitFlags flags; + uint32_t waitSemaphoreInfoCount; + const VkSemaphoreSubmitInfo * pWaitSemaphoreInfos; + uint32_t commandBufferInfoCount; + const VkCommandBufferSubmitInfo * pCommandBufferInfos; + uint32_t signalSemaphoreInfoCount; + const VkSemaphoreSubmitInfo * pSignalSemaphoreInfos; +} VkSubmitInfo2; + +typedef struct VkSubmitInfo2 VkSubmitInfo2KHR; + +typedef struct VkQueueFamilyCheckpointProperties2NV { + VkStructureType sType; + void * pNext; + VkPipelineStageFlags2 checkpointExecutionStageMask; +} VkQueueFamilyCheckpointProperties2NV; -typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties { +typedef struct VkCheckpointData2NV { VkStructureType sType; void * pNext; - VkBool32 filterMinmaxSingleComponentFormats; - VkBool32 filterMinmaxImageComponentMapping; -} VkPhysicalDeviceSamplerFilterMinmaxProperties; + VkPipelineStageFlags2 stage; + void * pCheckpointMarker; +} VkCheckpointData2NV; -typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT; +typedef struct VkPhysicalDeviceSynchronization2Features { + VkStructureType sType; + void * pNext; + VkBool32 synchronization2; +} VkPhysicalDeviceSynchronization2Features; -typedef struct VkPipelineSampleLocationsStateCreateInfoEXT { +typedef struct VkPhysicalDeviceSynchronization2Features VkPhysicalDeviceSynchronization2FeaturesKHR; + +typedef struct VkPhysicalDeviceHostImageCopyFeatures { VkStructureType sType; - const void * pNext; - VkBool32 sampleLocationsEnable; - VkSampleLocationsInfoEXT sampleLocationsInfo; -} VkPipelineSampleLocationsStateCreateInfoEXT; + void * pNext; + VkBool32 hostImageCopy; +} VkPhysicalDeviceHostImageCopyFeatures; -typedef struct VkPhysicalDeviceSampleLocationsPropertiesEXT { +typedef struct VkPhysicalDeviceHostImageCopyFeatures VkPhysicalDeviceHostImageCopyFeaturesEXT; + +typedef struct VkPhysicalDeviceHostImageCopyProperties { VkStructureType sType; - void * pNext; - VkSampleCountFlags sampleLocationSampleCounts; - VkExtent2D maxSampleLocationGridSize; - float sampleLocationCoordinateRange [2]; - uint32_t sampleLocationSubPixelBits; - VkBool32 variableSampleLocations; -} VkPhysicalDeviceSampleLocationsPropertiesEXT; + void * pNext; + uint32_t copySrcLayoutCount; + VkImageLayout * pCopySrcLayouts; + uint32_t copyDstLayoutCount; + VkImageLayout * pCopyDstLayouts; + uint8_t optimalTilingLayoutUUID [ VK_UUID_SIZE ]; + VkBool32 identicalMemoryTypeRequirements; +} VkPhysicalDeviceHostImageCopyProperties; -typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT { +typedef struct VkPhysicalDeviceHostImageCopyProperties VkPhysicalDeviceHostImageCopyPropertiesEXT; + +typedef struct VkMemoryToImageCopy { VkStructureType sType; - void * pNext; - VkBool32 advancedBlendCoherentOperations; -} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT; + const void * pNext; + const void * pHostPointer; + uint32_t memoryRowLength; + uint32_t memoryImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkMemoryToImageCopy; -typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT { +typedef struct VkMemoryToImageCopy VkMemoryToImageCopyEXT; + +typedef struct VkImageToMemoryCopy { VkStructureType sType; - void * pNext; - uint32_t advancedBlendMaxColorAttachments; - VkBool32 advancedBlendIndependentBlend; - VkBool32 advancedBlendNonPremultipliedSrcColor; - VkBool32 advancedBlendNonPremultipliedDstColor; - VkBool32 advancedBlendCorrelatedOverlap; - VkBool32 advancedBlendAllOperations; -} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT; + const void * pNext; + void * pHostPointer; + uint32_t memoryRowLength; + uint32_t memoryImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkImageToMemoryCopy; -typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT { +typedef struct VkImageToMemoryCopy VkImageToMemoryCopyEXT; + +typedef struct VkCopyMemoryToImageInfo { VkStructureType sType; - const void * pNext; - VkBool32 srcPremultiplied; - VkBool32 dstPremultiplied; - VkBlendOverlapEXT blendOverlap; -} VkPipelineColorBlendAdvancedStateCreateInfoEXT; + const void * pNext; + VkHostImageCopyFlags flags; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkMemoryToImageCopy * pRegions; +} VkCopyMemoryToImageInfo; -typedef struct VkPhysicalDeviceInlineUniformBlockFeaturesEXT { +typedef struct VkCopyMemoryToImageInfo VkCopyMemoryToImageInfoEXT; + +typedef struct VkCopyImageToMemoryInfo { VkStructureType sType; - void * pNext; - VkBool32 inlineUniformBlock; - VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; -} VkPhysicalDeviceInlineUniformBlockFeaturesEXT; + const void * pNext; + VkHostImageCopyFlags flags; + VkImage srcImage; + VkImageLayout srcImageLayout; + uint32_t regionCount; + const VkImageToMemoryCopy * pRegions; +} VkCopyImageToMemoryInfo; -typedef struct VkPipelineCoverageModulationStateCreateInfoNV { +typedef struct VkCopyImageToMemoryInfo VkCopyImageToMemoryInfoEXT; + +typedef struct VkCopyImageToImageInfo { VkStructureType sType; - const void * pNext; - VkPipelineCoverageModulationStateCreateFlagsNV flags; - VkCoverageModulationModeNV coverageModulationMode; - VkBool32 coverageModulationTableEnable; - uint32_t coverageModulationTableCount; - const float * pCoverageModulationTable; -} VkPipelineCoverageModulationStateCreateInfoNV; + const void * pNext; + VkHostImageCopyFlags flags; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageCopy2 * pRegions; +} VkCopyImageToImageInfo; -typedef struct VkValidationCacheCreateInfoEXT { +typedef struct VkCopyImageToImageInfo VkCopyImageToImageInfoEXT; + +typedef struct VkHostImageLayoutTransitionInfo { VkStructureType sType; - const void * pNext; - VkValidationCacheCreateFlagsEXT flags; - size_t initialDataSize; - const void * pInitialData; -} VkValidationCacheCreateInfoEXT; + const void * pNext; + VkImage image; + VkImageLayout oldLayout; + VkImageLayout newLayout; + VkImageSubresourceRange subresourceRange; +} VkHostImageLayoutTransitionInfo; -typedef struct VkPhysicalDeviceMaintenance3Properties { +typedef struct VkHostImageLayoutTransitionInfo VkHostImageLayoutTransitionInfoEXT; + +typedef struct VkSubresourceHostMemcpySize { VkStructureType sType; - void * pNext; - uint32_t maxPerSetDescriptors; - VkDeviceSize maxMemoryAllocationSize; -} VkPhysicalDeviceMaintenance3Properties; + void * pNext; + VkDeviceSize size; +} VkSubresourceHostMemcpySize; -typedef struct VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; +typedef struct VkSubresourceHostMemcpySize VkSubresourceHostMemcpySizeEXT; -typedef struct VkDescriptorSetLayoutSupport { +typedef struct VkHostImageCopyDevicePerformanceQuery { VkStructureType sType; - void * pNext; - VkBool32 supported; -} VkDescriptorSetLayoutSupport; + void * pNext; + VkBool32 optimalDeviceAccess; + VkBool32 identicalMemoryLayout; +} VkHostImageCopyDevicePerformanceQuery; -typedef struct VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; +typedef struct VkHostImageCopyDevicePerformanceQuery VkHostImageCopyDevicePerformanceQueryEXT; -typedef struct VkPhysicalDeviceShaderDrawParametersFeatures { +typedef struct VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 shaderDrawParameters; -} VkPhysicalDeviceShaderDrawParametersFeatures; + void * pNext; + VkBool32 primitivesGeneratedQuery; + VkBool32 primitivesGeneratedQueryWithRasterizerDiscard; + VkBool32 primitivesGeneratedQueryWithNonZeroStreams; +} VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT; -typedef struct VkPhysicalDeviceShaderDrawParametersFeatures VkPhysicalDeviceShaderDrawParameterFeatures; +typedef struct VkPhysicalDeviceLegacyDitheringFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 legacyDithering; +} VkPhysicalDeviceLegacyDitheringFeaturesEXT; -typedef struct VkPhysicalDeviceShaderFloat16Int8Features { +typedef struct VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 shaderFloat16; - VkBool32 shaderInt8; -} VkPhysicalDeviceShaderFloat16Int8Features; + void * pNext; + VkBool32 multisampledRenderToSingleSampled; +} VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT; -typedef struct VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceShaderFloat16Int8FeaturesKHR; +typedef struct VkSubpassResolvePerformanceQueryEXT { + VkStructureType sType; + void * pNext; + VkBool32 optimal; +} VkSubpassResolvePerformanceQueryEXT; -typedef struct VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceFloat16Int8FeaturesKHR; +typedef struct VkMultisampledRenderToSingleSampledInfoEXT { + VkStructureType sType; + const void * pNext; + VkBool32 multisampledRenderToSingleSampledEnable; + VkSampleCountFlagBits rasterizationSamples; +} VkMultisampledRenderToSingleSampledInfoEXT; -typedef struct VkPhysicalDeviceFloatControlsProperties { +typedef struct VkPhysicalDevicePipelineProtectedAccessFeatures { VkStructureType sType; - void * pNext; - VkShaderFloatControlsIndependence denormBehaviorIndependence; - VkShaderFloatControlsIndependence roundingModeIndependence; - VkBool32 shaderSignedZeroInfNanPreserveFloat16; - VkBool32 shaderSignedZeroInfNanPreserveFloat32; - VkBool32 shaderSignedZeroInfNanPreserveFloat64; - VkBool32 shaderDenormPreserveFloat16; - VkBool32 shaderDenormPreserveFloat32; - VkBool32 shaderDenormPreserveFloat64; - VkBool32 shaderDenormFlushToZeroFloat16; - VkBool32 shaderDenormFlushToZeroFloat32; - VkBool32 shaderDenormFlushToZeroFloat64; - VkBool32 shaderRoundingModeRTEFloat16; - VkBool32 shaderRoundingModeRTEFloat32; - VkBool32 shaderRoundingModeRTEFloat64; - VkBool32 shaderRoundingModeRTZFloat16; - VkBool32 shaderRoundingModeRTZFloat32; - VkBool32 shaderRoundingModeRTZFloat64; -} VkPhysicalDeviceFloatControlsProperties; + void * pNext; + VkBool32 pipelineProtectedAccess; +} VkPhysicalDevicePipelineProtectedAccessFeatures; -typedef struct VkPhysicalDeviceFloatControlsProperties VkPhysicalDeviceFloatControlsPropertiesKHR; +typedef struct VkPhysicalDevicePipelineProtectedAccessFeatures VkPhysicalDevicePipelineProtectedAccessFeaturesEXT; -typedef struct VkPhysicalDeviceHostQueryResetFeatures { +typedef struct VkPhysicalDeviceInheritedViewportScissorFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 inheritedViewportScissor2D; +} VkPhysicalDeviceInheritedViewportScissorFeaturesNV; + +typedef struct VkCommandBufferInheritanceViewportScissorInfoNV { + VkStructureType sType; + const void * pNext; + VkBool32 viewportScissor2D; + uint32_t viewportDepthCount; + const VkViewport * pViewportDepths; +} VkCommandBufferInheritanceViewportScissorInfoNV; + +typedef struct VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT { VkStructureType sType; void * pNext; - VkBool32 hostQueryReset; -} VkPhysicalDeviceHostQueryResetFeatures; + VkBool32 ycbcr2plane444Formats; +} VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT; -typedef struct VkPhysicalDeviceHostQueryResetFeatures VkPhysicalDeviceHostQueryResetFeaturesEXT; +typedef struct VkPhysicalDeviceProvokingVertexFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 provokingVertexLast; + VkBool32 transformFeedbackPreservesProvokingVertex; +} VkPhysicalDeviceProvokingVertexFeaturesEXT; -typedef struct VkShaderStatisticsInfoAMD { - VkShaderStageFlags shaderStageMask; - VkShaderResourceUsageAMD resourceUsage; - uint32_t numPhysicalVgprs; - uint32_t numPhysicalSgprs; - uint32_t numAvailableVgprs; - uint32_t numAvailableSgprs; - uint32_t computeWorkGroupSize [3]; -} VkShaderStatisticsInfoAMD; +typedef struct VkPhysicalDeviceProvokingVertexPropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 provokingVertexModePerPipeline; + VkBool32 transformFeedbackPreservesTriangleFanProvokingVertex; +} VkPhysicalDeviceProvokingVertexPropertiesEXT; -typedef struct VkDebugUtilsMessengerCallbackDataEXT { +typedef struct VkCuModuleTexturingModeCreateInfoNVX { VkStructureType sType; - const void * pNext; - VkDebugUtilsMessengerCallbackDataFlagsEXT flags; - const char * pMessageIdName; - int32_t messageIdNumber; - const char * pMessage; - uint32_t queueLabelCount; - const VkDebugUtilsLabelEXT * pQueueLabels; - uint32_t cmdBufLabelCount; - const VkDebugUtilsLabelEXT * pCmdBufLabels; - uint32_t objectCount; - const VkDebugUtilsObjectNameInfoEXT * pObjects; -} VkDebugUtilsMessengerCallbackDataEXT; + const void * pNext; + VkBool32 use64bitTexturing; +} VkCuModuleTexturingModeCreateInfoNVX; -typedef struct VkPhysicalDeviceExternalMemoryHostPropertiesEXT { +typedef struct VkPhysicalDeviceDescriptorBufferFeaturesEXT { VkStructureType sType; - void * pNext; - VkDeviceSize minImportedHostPointerAlignment; -} VkPhysicalDeviceExternalMemoryHostPropertiesEXT; + void * pNext; + VkBool32 descriptorBuffer; + VkBool32 descriptorBufferCaptureReplay; + VkBool32 descriptorBufferImageLayoutIgnored; + VkBool32 descriptorBufferPushDescriptors; +} VkPhysicalDeviceDescriptorBufferFeaturesEXT; -typedef struct VkPhysicalDeviceConservativeRasterizationPropertiesEXT { +typedef struct VkPhysicalDeviceDescriptorBufferPropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 combinedImageSamplerDescriptorSingleArray; + VkBool32 bufferlessPushDescriptors; + VkBool32 allowSamplerImageViewPostSubmitCreation; + VkDeviceSize descriptorBufferOffsetAlignment; + uint32_t maxDescriptorBufferBindings; + uint32_t maxResourceDescriptorBufferBindings; + uint32_t maxSamplerDescriptorBufferBindings; + uint32_t maxEmbeddedImmutableSamplerBindings; + uint32_t maxEmbeddedImmutableSamplers; + size_t bufferCaptureReplayDescriptorDataSize; + size_t imageCaptureReplayDescriptorDataSize; + size_t imageViewCaptureReplayDescriptorDataSize; + size_t samplerCaptureReplayDescriptorDataSize; + size_t accelerationStructureCaptureReplayDescriptorDataSize; + size_t samplerDescriptorSize; + size_t combinedImageSamplerDescriptorSize; + size_t sampledImageDescriptorSize; + size_t storageImageDescriptorSize; + size_t uniformTexelBufferDescriptorSize; + size_t robustUniformTexelBufferDescriptorSize; + size_t storageTexelBufferDescriptorSize; + size_t robustStorageTexelBufferDescriptorSize; + size_t uniformBufferDescriptorSize; + size_t robustUniformBufferDescriptorSize; + size_t storageBufferDescriptorSize; + size_t robustStorageBufferDescriptorSize; + size_t inputAttachmentDescriptorSize; + size_t accelerationStructureDescriptorSize; + VkDeviceSize maxSamplerDescriptorBufferRange; + VkDeviceSize maxResourceDescriptorBufferRange; + VkDeviceSize samplerDescriptorBufferAddressSpaceSize; + VkDeviceSize resourceDescriptorBufferAddressSpaceSize; + VkDeviceSize descriptorBufferAddressSpaceSize; +} VkPhysicalDeviceDescriptorBufferPropertiesEXT; + +typedef struct VkDescriptorAddressInfoEXT { + VkStructureType sType; + void * pNext; + VkDeviceAddress address; + VkDeviceSize range; + VkFormat format; +} VkDescriptorAddressInfoEXT; + +typedef struct VkDescriptorBufferBindingInfoEXT { + VkStructureType sType; + const void * pNext; + VkDeviceAddress address; + VkBufferUsageFlags usage; +} VkDescriptorBufferBindingInfoEXT; + +typedef union VkDescriptorDataEXT { + const VkSampler * pSampler; + const VkDescriptorImageInfo * pCombinedImageSampler; + const VkDescriptorImageInfo * pInputAttachmentImage; + const VkDescriptorImageInfo * pSampledImage; + const VkDescriptorImageInfo * pStorageImage; + const VkDescriptorAddressInfoEXT * pUniformTexelBuffer; + const VkDescriptorAddressInfoEXT * pStorageTexelBuffer; + const VkDescriptorAddressInfoEXT * pUniformBuffer; + const VkDescriptorAddressInfoEXT * pStorageBuffer; + VkDeviceAddress accelerationStructure; +} VkDescriptorDataEXT; + +typedef struct VkDescriptorGetInfoEXT { + VkStructureType sType; + const void * pNext; + VkDescriptorType type; + VkDescriptorDataEXT data; +} VkDescriptorGetInfoEXT; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductFeatures { + VkStructureType sType; + void * pNext; + VkBool32 shaderIntegerDotProduct; +} VkPhysicalDeviceShaderIntegerDotProductFeatures; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductFeatures VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductProperties { + VkStructureType sType; + void * pNext; + VkBool32 integerDotProduct8BitUnsignedAccelerated; + VkBool32 integerDotProduct8BitSignedAccelerated; + VkBool32 integerDotProduct8BitMixedSignednessAccelerated; + VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProduct16BitUnsignedAccelerated; + VkBool32 integerDotProduct16BitSignedAccelerated; + VkBool32 integerDotProduct16BitMixedSignednessAccelerated; + VkBool32 integerDotProduct32BitUnsignedAccelerated; + VkBool32 integerDotProduct32BitSignedAccelerated; + VkBool32 integerDotProduct32BitMixedSignednessAccelerated; + VkBool32 integerDotProduct64BitUnsignedAccelerated; + VkBool32 integerDotProduct64BitSignedAccelerated; + VkBool32 integerDotProduct64BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; +} VkPhysicalDeviceShaderIntegerDotProductProperties; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductProperties VkPhysicalDeviceShaderIntegerDotProductPropertiesKHR; + +typedef struct VkPhysicalDeviceDrmPropertiesEXT { VkStructureType sType; - void * pNext; - float primitiveOverestimationSize; - float maxExtraPrimitiveOverestimationSize; - float extraPrimitiveOverestimationSizeGranularity; - VkBool32 primitiveUnderestimation; - VkBool32 conservativePointAndLineRasterization; - VkBool32 degenerateTrianglesRasterized; - VkBool32 degenerateLinesRasterized; - VkBool32 fullyCoveredFragmentShaderInputVariable; - VkBool32 conservativeRasterizationPostDepthCoverage; -} VkPhysicalDeviceConservativeRasterizationPropertiesEXT; + void * pNext; + VkBool32 hasPrimary; + VkBool32 hasRender; + int64_t primaryMajor; + int64_t primaryMinor; + int64_t renderMajor; + int64_t renderMinor; +} VkPhysicalDeviceDrmPropertiesEXT; -typedef struct VkPhysicalDeviceShaderCoreProperties2AMD { +typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR { VkStructureType sType; - void * pNext; - VkShaderCorePropertiesFlagsAMD shaderCoreFeatures; - uint32_t activeComputeUnitCount; -} VkPhysicalDeviceShaderCoreProperties2AMD; + void * pNext; + VkBool32 fragmentShaderBarycentric; +} VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR; -typedef struct VkPipelineRasterizationConservativeStateCreateInfoEXT { +typedef struct VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR { VkStructureType sType; - const void * pNext; - VkPipelineRasterizationConservativeStateCreateFlagsEXT flags; - VkConservativeRasterizationModeEXT conservativeRasterizationMode; - float extraPrimitiveOverestimationSize; -} VkPipelineRasterizationConservativeStateCreateInfoEXT; + void * pNext; + VkBool32 triStripVertexOrderIndependentOfProvokingVertex; +} VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR; -typedef struct VkPhysicalDeviceDescriptorIndexingFeatures { +typedef struct VkPhysicalDeviceRayTracingMotionBlurFeaturesNV { VkStructureType sType; - void * pNext; - VkBool32 shaderInputAttachmentArrayDynamicIndexing; - VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; - VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; - VkBool32 shaderUniformBufferArrayNonUniformIndexing; - VkBool32 shaderSampledImageArrayNonUniformIndexing; - VkBool32 shaderStorageBufferArrayNonUniformIndexing; - VkBool32 shaderStorageImageArrayNonUniformIndexing; - VkBool32 shaderInputAttachmentArrayNonUniformIndexing; - VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; - VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; - VkBool32 descriptorBindingUniformBufferUpdateAfterBind; - VkBool32 descriptorBindingSampledImageUpdateAfterBind; - VkBool32 descriptorBindingStorageImageUpdateAfterBind; - VkBool32 descriptorBindingStorageBufferUpdateAfterBind; - VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingUpdateUnusedWhilePending; - VkBool32 descriptorBindingPartiallyBound; - VkBool32 descriptorBindingVariableDescriptorCount; - VkBool32 runtimeDescriptorArray; -} VkPhysicalDeviceDescriptorIndexingFeatures; + void * pNext; + VkBool32 rayTracingMotionBlur; + VkBool32 rayTracingMotionBlurPipelineTraceRaysIndirect; +} VkPhysicalDeviceRayTracingMotionBlurFeaturesNV; -typedef struct VkPhysicalDeviceDescriptorIndexingFeatures VkPhysicalDeviceDescriptorIndexingFeaturesEXT; +typedef struct VkPhysicalDeviceRayTracingValidationFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 rayTracingValidation; +} VkPhysicalDeviceRayTracingValidationFeaturesNV; -typedef struct VkPhysicalDeviceDescriptorIndexingProperties { +typedef struct VkPhysicalDeviceRayTracingLinearSweptSpheresFeaturesNV { VkStructureType sType; - void * pNext; - uint32_t maxUpdateAfterBindDescriptorsInAllPools; - VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; - VkBool32 shaderSampledImageArrayNonUniformIndexingNative; - VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; - VkBool32 shaderStorageImageArrayNonUniformIndexingNative; - VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; - VkBool32 robustBufferAccessUpdateAfterBind; - VkBool32 quadDivergentImplicitLod; - uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; - uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; - uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; - uint32_t maxPerStageUpdateAfterBindResources; - uint32_t maxDescriptorSetUpdateAfterBindSamplers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindSampledImages; - uint32_t maxDescriptorSetUpdateAfterBindStorageImages; - uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; -} VkPhysicalDeviceDescriptorIndexingProperties; + void * pNext; + VkBool32 spheres; + VkBool32 linearSweptSpheres; +} VkPhysicalDeviceRayTracingLinearSweptSpheresFeaturesNV; -typedef struct VkPhysicalDeviceDescriptorIndexingProperties VkPhysicalDeviceDescriptorIndexingPropertiesEXT; +typedef struct VkAccelerationStructureGeometryMotionTrianglesDataNV { + VkStructureType sType; + const void * pNext; + VkDeviceOrHostAddressConstKHR vertexData; +} VkAccelerationStructureGeometryMotionTrianglesDataNV; -typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo { +typedef struct VkAccelerationStructureMotionInfoNV { VkStructureType sType; - const void * pNext; - uint32_t bindingCount; - const VkDescriptorBindingFlags * pBindingFlags; -} VkDescriptorSetLayoutBindingFlagsCreateInfo; + const void * pNext; + uint32_t maxInstances; + VkAccelerationStructureMotionInfoFlagsNV flags; +} VkAccelerationStructureMotionInfoNV; -typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo VkDescriptorSetLayoutBindingFlagsCreateInfoEXT; +typedef struct VkAccelerationStructureSRTMotionInstanceNV { + VkSRTDataNV transformT0; + VkSRTDataNV transformT1; + uint32_t instanceCustomIndex :24; + uint32_t mask :8; + uint32_t instanceShaderBindingTableRecordOffset :24; + VkGeometryInstanceFlagsKHR flags :8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureSRTMotionInstanceNV; -typedef struct VkAttachmentDescription2 { - VkStructureType sType; - const void * pNext; - VkAttachmentDescriptionFlags flags; - VkFormat format; - VkSampleCountFlagBits samples; - VkAttachmentLoadOp loadOp; - VkAttachmentStoreOp storeOp; - VkAttachmentLoadOp stencilLoadOp; - VkAttachmentStoreOp stencilStoreOp; - VkImageLayout initialLayout; - VkImageLayout finalLayout; -} VkAttachmentDescription2; +typedef struct VkAccelerationStructureMatrixMotionInstanceNV { + VkTransformMatrixKHR transformT0; + VkTransformMatrixKHR transformT1; + uint32_t instanceCustomIndex :24; + uint32_t mask :8; + uint32_t instanceShaderBindingTableRecordOffset :24; + VkGeometryInstanceFlagsKHR flags :8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureMatrixMotionInstanceNV; -typedef struct VkAttachmentDescription2 VkAttachmentDescription2KHR; +typedef union VkAccelerationStructureMotionInstanceDataNV { + VkAccelerationStructureInstanceKHR staticInstance; + VkAccelerationStructureMatrixMotionInstanceNV matrixMotionInstance; + VkAccelerationStructureSRTMotionInstanceNV srtMotionInstance; +} VkAccelerationStructureMotionInstanceDataNV; -typedef struct VkAttachmentReference2 { +typedef struct VkAccelerationStructureMotionInstanceNV { + VkAccelerationStructureMotionInstanceTypeNV type; + VkAccelerationStructureMotionInstanceFlagsNV flags; + VkAccelerationStructureMotionInstanceDataNV data; +} VkAccelerationStructureMotionInstanceNV; + +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkBufferCollectionPropertiesFUCHSIA { VkStructureType sType; - const void * pNext; - uint32_t attachment; - VkImageLayout layout; - VkImageAspectFlags aspectMask; -} VkAttachmentReference2; + void * pNext; + uint32_t memoryTypeBits; + uint32_t bufferCount; + uint32_t createInfoIndex; + uint64_t sysmemPixelFormat; + VkFormatFeatureFlags formatFeatures; + VkSysmemColorSpaceFUCHSIA sysmemColorSpaceIndex; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkBufferCollectionPropertiesFUCHSIA; -typedef struct VkAttachmentReference2 VkAttachmentReference2KHR; +#endif -typedef struct VkSubpassDescription2 { +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkBufferConstraintsInfoFUCHSIA { VkStructureType sType; - const void * pNext; - VkSubpassDescriptionFlags flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t viewMask; - uint32_t inputAttachmentCount; - const VkAttachmentReference2 * pInputAttachments; - uint32_t colorAttachmentCount; - const VkAttachmentReference2 * pColorAttachments; - const VkAttachmentReference2 * pResolveAttachments; - const VkAttachmentReference2 * pDepthStencilAttachment; - uint32_t preserveAttachmentCount; - const uint32_t * pPreserveAttachments; -} VkSubpassDescription2; + const void * pNext; + VkBufferCreateInfo createInfo; + VkFormatFeatureFlags requiredFormatFeatures; + VkBufferCollectionConstraintsInfoFUCHSIA bufferCollectionConstraints; +} VkBufferConstraintsInfoFUCHSIA; -typedef struct VkSubpassDescription2 VkSubpassDescription2KHR; +#endif -typedef struct VkSubpassDependency2 { +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkImageFormatConstraintsInfoFUCHSIA { VkStructureType sType; - const void * pNext; - uint32_t srcSubpass; - uint32_t dstSubpass; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkDependencyFlags dependencyFlags; - int32_t viewOffset; -} VkSubpassDependency2; + const void * pNext; + VkImageCreateInfo imageCreateInfo; + VkFormatFeatureFlags requiredFormatFeatures; + VkImageFormatConstraintsFlagsFUCHSIA flags; + uint64_t sysmemPixelFormat; + uint32_t colorSpaceCount; + const VkSysmemColorSpaceFUCHSIA * pColorSpaces; +} VkImageFormatConstraintsInfoFUCHSIA; -typedef struct VkSubpassDependency2 VkSubpassDependency2KHR; +#endif -typedef struct VkRenderPassCreateInfo2 { +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkImageConstraintsInfoFUCHSIA { VkStructureType sType; - const void * pNext; - VkRenderPassCreateFlags flags; - uint32_t attachmentCount; - const VkAttachmentDescription2 * pAttachments; - uint32_t subpassCount; - const VkSubpassDescription2 * pSubpasses; - uint32_t dependencyCount; - const VkSubpassDependency2 * pDependencies; - uint32_t correlatedViewMaskCount; - const uint32_t * pCorrelatedViewMasks; -} VkRenderPassCreateInfo2; + const void * pNext; + uint32_t formatConstraintsCount; + const VkImageFormatConstraintsInfoFUCHSIA * pFormatConstraints; + VkBufferCollectionConstraintsInfoFUCHSIA bufferCollectionConstraints; + VkImageConstraintsInfoFlagsFUCHSIA flags; +} VkImageConstraintsInfoFUCHSIA; -typedef struct VkRenderPassCreateInfo2 VkRenderPassCreateInfo2KHR; +#endif -typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures { +typedef struct VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 timelineSemaphore; -} VkPhysicalDeviceTimelineSemaphoreFeatures; - -typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures VkPhysicalDeviceTimelineSemaphoreFeaturesKHR; + void * pNext; + VkBool32 formatRgba10x6WithoutYCbCrSampler; +} VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT; -typedef struct VkSemaphoreWaitInfo { +typedef struct VkFormatProperties3 { VkStructureType sType; - const void * pNext; - VkSemaphoreWaitFlags flags; - uint32_t semaphoreCount; - const VkSemaphore * pSemaphores; - const uint64_t * pValues; -} VkSemaphoreWaitInfo; + void * pNext; + VkFormatFeatureFlags2 linearTilingFeatures; + VkFormatFeatureFlags2 optimalTilingFeatures; + VkFormatFeatureFlags2 bufferFeatures; +} VkFormatProperties3; -typedef struct VkSemaphoreWaitInfo VkSemaphoreWaitInfoKHR; +typedef struct VkFormatProperties3 VkFormatProperties3KHR; -#if defined(VK_USE_PLATFORM_ANDROID_KHR) -typedef struct VkAndroidHardwareBufferPropertiesANDROID { - VkStructureType sType; - void * pNext; - VkDeviceSize allocationSize; - uint32_t memoryTypeBits; -} VkAndroidHardwareBufferPropertiesANDROID; -#endif +typedef struct VkDrmFormatModifierProperties2EXT { + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + VkFormatFeatureFlags2 drmFormatModifierTilingFeatures; +} VkDrmFormatModifierProperties2EXT; #if defined(VK_USE_PLATFORM_ANDROID_KHR) -typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID { +typedef struct VkAndroidHardwareBufferFormatProperties2ANDROID { VkStructureType sType; void * pNext; VkFormat format; uint64_t externalFormat; - VkFormatFeatureFlags formatFeatures; + VkFormatFeatureFlags2 formatFeatures; VkComponentMapping samplerYcbcrConversionComponents; VkSamplerYcbcrModelConversion suggestedYcbcrModel; VkSamplerYcbcrRange suggestedYcbcrRange; VkChromaLocation suggestedXChromaOffset; VkChromaLocation suggestedYChromaOffset; -} VkAndroidHardwareBufferFormatPropertiesANDROID; +} VkAndroidHardwareBufferFormatProperties2ANDROID; + #endif -typedef struct VkCommandBufferInheritanceConditionalRenderingInfoEXT { +typedef struct VkRenderingInfo { + VkStructureType sType; + const void * pNext; + VkRenderingFlags flags; + VkRect2D renderArea; + uint32_t layerCount; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkRenderingAttachmentInfo * pColorAttachments; + const VkRenderingAttachmentInfo * pDepthAttachment; + const VkRenderingAttachmentInfo * pStencilAttachment; +} VkRenderingInfo; + +typedef struct VkRenderingInfo VkRenderingInfoKHR; + +typedef struct VkPhysicalDeviceDynamicRenderingFeatures { VkStructureType sType; - const void * pNext; - VkBool32 conditionalRenderingEnable; -} VkCommandBufferInheritanceConditionalRenderingInfoEXT; + void * pNext; + VkBool32 dynamicRendering; +} VkPhysicalDeviceDynamicRenderingFeatures; -typedef struct VkPhysicalDevice8BitStorageFeatures { +typedef struct VkPhysicalDeviceDynamicRenderingFeatures VkPhysicalDeviceDynamicRenderingFeaturesKHR; + +typedef struct VkCommandBufferInheritanceRenderingInfo { VkStructureType sType; - void * pNext; - VkBool32 storageBuffer8BitAccess; - VkBool32 uniformAndStorageBuffer8BitAccess; - VkBool32 storagePushConstant8; -} VkPhysicalDevice8BitStorageFeatures; + const void * pNext; + VkRenderingFlags flags; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat * pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; + VkSampleCountFlagBits rasterizationSamples; +} VkCommandBufferInheritanceRenderingInfo; -typedef struct VkPhysicalDevice8BitStorageFeatures VkPhysicalDevice8BitStorageFeaturesKHR; +typedef struct VkCommandBufferInheritanceRenderingInfo VkCommandBufferInheritanceRenderingInfoKHR; -typedef struct VkPhysicalDeviceConditionalRenderingFeaturesEXT { +typedef struct VkMultiviewPerViewAttributesInfoNVX { + VkStructureType sType; + const void * pNext; + VkBool32 perViewAttributes; + VkBool32 perViewAttributesPositionXOnly; +} VkMultiviewPerViewAttributesInfoNVX; + +typedef struct VkPhysicalDeviceImageViewMinLodFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 minLod; +} VkPhysicalDeviceImageViewMinLodFeaturesEXT; + +typedef struct VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 rasterizationOrderColorAttachmentAccess; + VkBool32 rasterizationOrderDepthAttachmentAccess; + VkBool32 rasterizationOrderStencilAttachmentAccess; +} VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT; + +typedef struct VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM; + +typedef struct VkPhysicalDeviceLinearColorAttachmentFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 linearColorAttachment; +} VkPhysicalDeviceLinearColorAttachmentFeaturesNV; + +typedef struct VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT { VkStructureType sType; void * pNext; - VkBool32 conditionalRendering; - VkBool32 inheritedConditionalRendering; -} VkPhysicalDeviceConditionalRenderingFeaturesEXT; + VkBool32 graphicsPipelineLibrary; +} VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT; -typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures { +typedef struct VkPhysicalDevicePipelineBinaryFeaturesKHR { VkStructureType sType; - void * pNext; - VkBool32 vulkanMemoryModel; - VkBool32 vulkanMemoryModelDeviceScope; - VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; -} VkPhysicalDeviceVulkanMemoryModelFeatures; + void * pNext; + VkBool32 pipelineBinaries; +} VkPhysicalDevicePipelineBinaryFeaturesKHR; -typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures VkPhysicalDeviceVulkanMemoryModelFeaturesKHR; +typedef struct VkDevicePipelineBinaryInternalCacheControlKHR { + VkStructureType sType; + const void * pNext; + VkBool32 disableInternalCache; +} VkDevicePipelineBinaryInternalCacheControlKHR; -typedef struct VkPhysicalDeviceShaderAtomicInt64Features { +typedef struct VkPhysicalDevicePipelineBinaryPropertiesKHR { VkStructureType sType; - void * pNext; - VkBool32 shaderBufferInt64Atomics; - VkBool32 shaderSharedInt64Atomics; -} VkPhysicalDeviceShaderAtomicInt64Features; + void * pNext; + VkBool32 pipelineBinaryInternalCache; + VkBool32 pipelineBinaryInternalCacheControl; + VkBool32 pipelineBinaryPrefersInternalCache; + VkBool32 pipelineBinaryPrecompiledInternalCache; + VkBool32 pipelineBinaryCompressedData; +} VkPhysicalDevicePipelineBinaryPropertiesKHR; -typedef struct VkPhysicalDeviceShaderAtomicInt64Features VkPhysicalDeviceShaderAtomicInt64FeaturesKHR; +typedef struct VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 graphicsPipelineLibraryFastLinking; + VkBool32 graphicsPipelineLibraryIndependentInterpolationDecoration; +} VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT; -typedef struct VkPhysicalDeviceShaderAtomicFloatFeaturesEXT { +typedef struct VkGraphicsPipelineLibraryCreateInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 shaderBufferFloat32Atomics; - VkBool32 shaderBufferFloat32AtomicAdd; - VkBool32 shaderBufferFloat64Atomics; - VkBool32 shaderBufferFloat64AtomicAdd; - VkBool32 shaderSharedFloat32Atomics; - VkBool32 shaderSharedFloat32AtomicAdd; - VkBool32 shaderSharedFloat64Atomics; - VkBool32 shaderSharedFloat64AtomicAdd; - VkBool32 shaderImageFloat32Atomics; - VkBool32 shaderImageFloat32AtomicAdd; - VkBool32 sparseImageFloat32Atomics; - VkBool32 sparseImageFloat32AtomicAdd; -} VkPhysicalDeviceShaderAtomicFloatFeaturesEXT; + const void * pNext; + VkGraphicsPipelineLibraryFlagsEXT flags; +} VkGraphicsPipelineLibraryCreateInfoEXT; + +typedef struct VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE { + VkStructureType sType; + void * pNext; + VkBool32 descriptorSetHostMapping; +} VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE; -typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT { +typedef struct VkPhysicalDeviceNestedCommandBufferFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 vertexAttributeInstanceRateDivisor; - VkBool32 vertexAttributeInstanceRateZeroDivisor; -} VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT; + void * pNext; + VkBool32 nestedCommandBuffer; + VkBool32 nestedCommandBufferRendering; + VkBool32 nestedCommandBufferSimultaneousUse; +} VkPhysicalDeviceNestedCommandBufferFeaturesEXT; -typedef struct VkQueueFamilyCheckpointPropertiesNV { +typedef struct VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT { VkStructureType sType; - void * pNext; - VkPipelineStageFlags checkpointExecutionStageMask; -} VkQueueFamilyCheckpointPropertiesNV; + void * pNext; + VkBool32 shaderModuleIdentifier; +} VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT; -typedef struct VkPhysicalDeviceDepthStencilResolveProperties { +typedef struct VkImageCompressionControlEXT { VkStructureType sType; - void * pNext; - VkResolveModeFlags supportedDepthResolveModes; - VkResolveModeFlags supportedStencilResolveModes; - VkBool32 independentResolveNone; - VkBool32 independentResolve; -} VkPhysicalDeviceDepthStencilResolveProperties; + const void * pNext; + VkImageCompressionFlagsEXT flags; + uint32_t compressionControlPlaneCount; + VkImageCompressionFixedRateFlagsEXT * pFixedRateFlags; +} VkImageCompressionControlEXT; -typedef struct VkPhysicalDeviceDepthStencilResolveProperties VkPhysicalDeviceDepthStencilResolvePropertiesKHR; +typedef struct VkPhysicalDeviceImageCompressionControlFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 imageCompressionControl; +} VkPhysicalDeviceImageCompressionControlFeaturesEXT; -typedef struct VkSubpassDescriptionDepthStencilResolve { +typedef struct VkImageCompressionPropertiesEXT { VkStructureType sType; - const void * pNext; - VkResolveModeFlagBits depthResolveMode; - VkResolveModeFlagBits stencilResolveMode; - const VkAttachmentReference2 * pDepthStencilResolveAttachment; -} VkSubpassDescriptionDepthStencilResolve; + void * pNext; + VkImageCompressionFlagsEXT imageCompressionFlags; + VkImageCompressionFixedRateFlagsEXT imageCompressionFixedRateFlags; +} VkImageCompressionPropertiesEXT; -typedef struct VkSubpassDescriptionDepthStencilResolve VkSubpassDescriptionDepthStencilResolveKHR; +typedef struct VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 imageCompressionControlSwapchain; +} VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT; -typedef struct VkPhysicalDeviceASTCDecodeFeaturesEXT { +typedef struct VkImageSubresource2 { VkStructureType sType; - void * pNext; - VkBool32 decodeModeSharedExponent; -} VkPhysicalDeviceASTCDecodeFeaturesEXT; + void * pNext; + VkImageSubresource imageSubresource; +} VkImageSubresource2; -typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT { +typedef struct VkImageSubresource2 VkImageSubresource2KHR; + +typedef struct VkImageSubresource2 VkImageSubresource2EXT; + +typedef struct VkSubresourceLayout2 { VkStructureType sType; - void * pNext; - VkBool32 transformFeedback; - VkBool32 geometryStreams; -} VkPhysicalDeviceTransformFeedbackFeaturesEXT; + void * pNext; + VkSubresourceLayout subresourceLayout; +} VkSubresourceLayout2; -typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT { +typedef struct VkSubresourceLayout2 VkSubresourceLayout2KHR; + +typedef struct VkSubresourceLayout2 VkSubresourceLayout2EXT; + +typedef struct VkRenderPassCreationControlEXT { VkStructureType sType; - void * pNext; - uint32_t maxTransformFeedbackStreams; - uint32_t maxTransformFeedbackBuffers; - VkDeviceSize maxTransformFeedbackBufferSize; - uint32_t maxTransformFeedbackStreamDataSize; - uint32_t maxTransformFeedbackBufferDataSize; - uint32_t maxTransformFeedbackBufferDataStride; - VkBool32 transformFeedbackQueries; - VkBool32 transformFeedbackStreamsLinesTriangles; - VkBool32 transformFeedbackRasterizationStreamSelect; - VkBool32 transformFeedbackDraw; -} VkPhysicalDeviceTransformFeedbackPropertiesEXT; + const void * pNext; + VkBool32 disallowMerging; +} VkRenderPassCreationControlEXT; -typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT { +typedef struct VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT { VkStructureType sType; - const void * pNext; - VkPipelineRasterizationStateStreamCreateFlagsEXT flags; - uint32_t rasterizationStream; -} VkPipelineRasterizationStateStreamCreateInfoEXT; + void * pNext; + VkBool32 subpassMergeFeedback; +} VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT; -typedef struct VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV { - VkStructureType sType; - void * pNext; - VkBool32 representativeFragmentTest; -} VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV; +typedef struct VkMicromapBuildInfoEXT { + VkStructureType sType; + const void * pNext; + VkMicromapTypeEXT type; + VkBuildMicromapFlagsEXT flags; + VkBuildMicromapModeEXT mode; + VkMicromapEXT dstMicromap; + uint32_t usageCountsCount; + const VkMicromapUsageEXT * pUsageCounts; + const VkMicromapUsageEXT * const* ppUsageCounts; + VkDeviceOrHostAddressConstKHR data; + VkDeviceOrHostAddressKHR scratchData; + VkDeviceOrHostAddressConstKHR triangleArray; + VkDeviceSize triangleArrayStride; +} VkMicromapBuildInfoEXT; + +typedef struct VkMicromapCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkMicromapCreateFlagsEXT createFlags; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; + VkMicromapTypeEXT type; + VkDeviceAddress deviceAddress; +} VkMicromapCreateInfoEXT; -typedef struct VkPipelineRepresentativeFragmentTestStateCreateInfoNV { +typedef struct VkCopyMicromapToMemoryInfoEXT { VkStructureType sType; - const void * pNext; - VkBool32 representativeFragmentTestEnable; -} VkPipelineRepresentativeFragmentTestStateCreateInfoNV; + const void * pNext; + VkMicromapEXT src; + VkDeviceOrHostAddressKHR dst; + VkCopyMicromapModeEXT mode; +} VkCopyMicromapToMemoryInfoEXT; -typedef struct VkPhysicalDeviceExclusiveScissorFeaturesNV { +typedef struct VkCopyMemoryToMicromapInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 exclusiveScissor; -} VkPhysicalDeviceExclusiveScissorFeaturesNV; + const void * pNext; + VkDeviceOrHostAddressConstKHR src; + VkMicromapEXT dst; + VkCopyMicromapModeEXT mode; +} VkCopyMemoryToMicromapInfoEXT; -typedef struct VkPhysicalDeviceCornerSampledImageFeaturesNV { +typedef struct VkMicromapBuildSizesInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 cornerSampledImage; -} VkPhysicalDeviceCornerSampledImageFeaturesNV; + const void * pNext; + VkDeviceSize micromapSize; + VkDeviceSize buildScratchSize; + VkBool32 discardable; +} VkMicromapBuildSizesInfoEXT; -typedef struct VkPhysicalDeviceComputeShaderDerivativesFeaturesNV { +typedef struct VkPhysicalDeviceOpacityMicromapFeaturesEXT { VkStructureType sType; void * pNext; - VkBool32 computeDerivativeGroupQuads; - VkBool32 computeDerivativeGroupLinear; -} VkPhysicalDeviceComputeShaderDerivativesFeaturesNV; + VkBool32 micromap; + VkBool32 micromapCaptureReplay; + VkBool32 micromapHostCommands; +} VkPhysicalDeviceOpacityMicromapFeaturesEXT; + +typedef struct VkAccelerationStructureTrianglesOpacityMicromapEXT { + VkStructureType sType; + void * pNext; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexBuffer; + VkDeviceSize indexStride; + uint32_t baseTriangle; + uint32_t usageCountsCount; + const VkMicromapUsageEXT * pUsageCounts; + const VkMicromapUsageEXT * const* ppUsageCounts; + VkMicromapEXT micromap; +} VkAccelerationStructureTrianglesOpacityMicromapEXT; -typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDeviceDisplacementMicromapFeaturesNV { VkStructureType sType; void * pNext; - VkBool32 fragmentShaderBarycentric; -} VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV; + VkBool32 displacementMicromap; +} VkPhysicalDeviceDisplacementMicromapFeaturesNV; -typedef struct VkPhysicalDeviceShaderImageFootprintFeaturesNV { +#endif + +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkAccelerationStructureTrianglesDisplacementMicromapNV { VkStructureType sType; - void * pNext; - VkBool32 imageFootprint; -} VkPhysicalDeviceShaderImageFootprintFeaturesNV; + void * pNext; + VkFormat displacementBiasAndScaleFormat; + VkFormat displacementVectorFormat; + VkDeviceOrHostAddressConstKHR displacementBiasAndScaleBuffer; + VkDeviceSize displacementBiasAndScaleStride; + VkDeviceOrHostAddressConstKHR displacementVectorBuffer; + VkDeviceSize displacementVectorStride; + VkDeviceOrHostAddressConstKHR displacedMicromapPrimitiveFlags; + VkDeviceSize displacedMicromapPrimitiveFlagsStride; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexBuffer; + VkDeviceSize indexStride; + uint32_t baseTriangle; + uint32_t usageCountsCount; + const VkMicromapUsageEXT * pUsageCounts; + const VkMicromapUsageEXT * const* ppUsageCounts; + VkMicromapEXT micromap; +} VkAccelerationStructureTrianglesDisplacementMicromapNV; + +#endif + +typedef struct VkPhysicalDevicePipelinePropertiesFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 pipelinePropertiesIdentifier; +} VkPhysicalDevicePipelinePropertiesFeaturesEXT; -typedef struct VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV { +typedef struct VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD { VkStructureType sType; - void * pNext; - VkBool32 dedicatedAllocationImageAliasing; -} VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV; + void * pNext; + VkBool32 shaderEarlyAndLateFragmentTests; +} VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD; -typedef struct VkPipelineViewportShadingRateImageStateCreateInfoNV { +typedef struct VkExternalMemoryAcquireUnmodifiedEXT { VkStructureType sType; - const void * pNext; - VkBool32 shadingRateImageEnable; - uint32_t viewportCount; - const VkShadingRatePaletteNV * pShadingRatePalettes; -} VkPipelineViewportShadingRateImageStateCreateInfoNV; + const void * pNext; + VkBool32 acquireUnmodifiedMemory; +} VkExternalMemoryAcquireUnmodifiedEXT; -typedef struct VkPhysicalDeviceShadingRateImageFeaturesNV { +typedef struct VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 shadingRateImage; - VkBool32 shadingRateCoarseSampleOrder; -} VkPhysicalDeviceShadingRateImageFeaturesNV; + void * pNext; + VkBool32 nonSeamlessCubeMap; +} VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT; -typedef struct VkPhysicalDeviceMeshShaderFeaturesNV { +typedef struct VkPhysicalDevicePipelineRobustnessFeatures { VkStructureType sType; - void * pNext; - VkBool32 taskShader; - VkBool32 meshShader; -} VkPhysicalDeviceMeshShaderFeaturesNV; + void * pNext; + VkBool32 pipelineRobustness; +} VkPhysicalDevicePipelineRobustnessFeatures; -typedef struct VkRayTracingPipelineCreateInfoNV { +typedef struct VkPhysicalDevicePipelineRobustnessFeatures VkPhysicalDevicePipelineRobustnessFeaturesEXT; + +typedef struct VkPhysicalDeviceImageProcessingFeaturesQCOM { VkStructureType sType; - const void * pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo * pStages; - uint32_t groupCount; - const VkRayTracingShaderGroupCreateInfoNV * pGroups; - uint32_t maxRecursionDepth; - VkPipelineLayout layout; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkRayTracingPipelineCreateInfoNV; + void * pNext; + VkBool32 textureSampleWeighted; + VkBool32 textureBoxFilter; + VkBool32 textureBlockMatch; +} VkPhysicalDeviceImageProcessingFeaturesQCOM; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkRayTracingPipelineCreateInfoKHR { +typedef struct VkPhysicalDeviceTilePropertiesFeaturesQCOM { VkStructureType sType; - const void * pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo * pStages; - uint32_t groupCount; - const VkRayTracingShaderGroupCreateInfoKHR * pGroups; - uint32_t maxRecursionDepth; - VkPipelineLibraryCreateInfoKHR libraries; - const VkRayTracingPipelineInterfaceCreateInfoKHR * pLibraryInterface; - VkPipelineLayout layout; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkRayTracingPipelineCreateInfoKHR; -#endif + void * pNext; + VkBool32 tileProperties; +} VkPhysicalDeviceTilePropertiesFeaturesQCOM; -typedef struct VkGeometryTrianglesNV { +typedef struct VkPhysicalDeviceAmigoProfilingFeaturesSEC { VkStructureType sType; - const void * pNext; - VkBuffer vertexData; - VkDeviceSize vertexOffset; - uint32_t vertexCount; - VkDeviceSize vertexStride; - VkFormat vertexFormat; - VkBuffer indexData; - VkDeviceSize indexOffset; - uint32_t indexCount; - VkIndexType indexType; - VkBuffer transformData; - VkDeviceSize transformOffset; -} VkGeometryTrianglesNV; + void * pNext; + VkBool32 amigoProfiling; +} VkPhysicalDeviceAmigoProfilingFeaturesSEC; -typedef struct VkGeometryAABBNV { +typedef struct VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT { VkStructureType sType; - const void * pNext; - VkBuffer aabbData; - uint32_t numAABBs; - uint32_t stride; - VkDeviceSize offset; -} VkGeometryAABBNV; + void * pNext; + VkBool32 attachmentFeedbackLoopLayout; +} VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT; -typedef struct VkGeometryDataNV { - VkGeometryTrianglesNV triangles; - VkGeometryAABBNV aabbs; -} VkGeometryDataNV; +typedef struct VkPhysicalDeviceAddressBindingReportFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 reportAddressBinding; +} VkPhysicalDeviceAddressBindingReportFeaturesEXT; -typedef struct VkGeometryNV { +typedef struct VkDeviceAddressBindingCallbackDataEXT { VkStructureType sType; - const void * pNext; - VkGeometryTypeKHR geometryType; - VkGeometryDataNV geometry; - VkGeometryFlagsKHR flags; -} VkGeometryNV; + void * pNext; + VkDeviceAddressBindingFlagsEXT flags; + VkDeviceAddress baseAddress; + VkDeviceSize size; + VkDeviceAddressBindingTypeEXT bindingType; +} VkDeviceAddressBindingCallbackDataEXT; -typedef struct VkAccelerationStructureInfoNV { +typedef struct VkPhysicalDeviceOpticalFlowFeaturesNV { VkStructureType sType; - const void * pNext; - VkAccelerationStructureTypeNV type; - VkBuildAccelerationStructureFlagsNV flags; - uint32_t instanceCount; - uint32_t geometryCount; - const VkGeometryNV * pGeometries; -} VkAccelerationStructureInfoNV; + void * pNext; + VkBool32 opticalFlow; +} VkPhysicalDeviceOpticalFlowFeaturesNV; -typedef struct VkAccelerationStructureCreateInfoNV { +typedef struct VkPhysicalDeviceOpticalFlowPropertiesNV { VkStructureType sType; - const void * pNext; - VkDeviceSize compactedSize; - VkAccelerationStructureInfoNV info; -} VkAccelerationStructureCreateInfoNV; + void * pNext; + VkOpticalFlowGridSizeFlagsNV supportedOutputGridSizes; + VkOpticalFlowGridSizeFlagsNV supportedHintGridSizes; + VkBool32 hintSupported; + VkBool32 costSupported; + VkBool32 bidirectionalFlowSupported; + VkBool32 globalFlowSupported; + uint32_t minWidth; + uint32_t minHeight; + uint32_t maxWidth; + uint32_t maxHeight; + uint32_t maxNumRegionsOfInterest; +} VkPhysicalDeviceOpticalFlowPropertiesNV; + +typedef struct VkOpticalFlowImageFormatInfoNV { + VkStructureType sType; + const void * pNext; + VkOpticalFlowUsageFlagsNV usage; +} VkOpticalFlowImageFormatInfoNV; -typedef struct VkBindAccelerationStructureMemoryInfoKHR { +typedef struct VkOpticalFlowSessionCreateInfoNV { VkStructureType sType; - const void * pNext; - VkAccelerationStructureKHR accelerationStructure; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - uint32_t deviceIndexCount; - const uint32_t * pDeviceIndices; -} VkBindAccelerationStructureMemoryInfoKHR; + void * pNext; + uint32_t width; + uint32_t height; + VkFormat imageFormat; + VkFormat flowVectorFormat; + VkFormat costFormat; + VkOpticalFlowGridSizeFlagsNV outputGridSize; + VkOpticalFlowGridSizeFlagsNV hintGridSize; + VkOpticalFlowPerformanceLevelNV performanceLevel; + VkOpticalFlowSessionCreateFlagsNV flags; +} VkOpticalFlowSessionCreateInfoNV; -typedef struct VkBindAccelerationStructureMemoryInfoKHR VkBindAccelerationStructureMemoryInfoNV; +typedef struct VkOpticalFlowExecuteInfoNV { + VkStructureType sType; + void * pNext; + VkOpticalFlowExecuteFlagsNV flags; + uint32_t regionCount; + const VkRect2D * pRegions; +} VkOpticalFlowExecuteInfoNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkPhysicalDeviceRayTracingFeaturesKHR { +typedef struct VkPhysicalDeviceFaultFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 rayTracing; - VkBool32 rayTracingShaderGroupHandleCaptureReplay; - VkBool32 rayTracingShaderGroupHandleCaptureReplayMixed; - VkBool32 rayTracingAccelerationStructureCaptureReplay; - VkBool32 rayTracingIndirectTraceRays; - VkBool32 rayTracingIndirectAccelerationStructureBuild; - VkBool32 rayTracingHostAccelerationStructureCommands; - VkBool32 rayQuery; - VkBool32 rayTracingPrimitiveCulling; -} VkPhysicalDeviceRayTracingFeaturesKHR; -#endif + void * pNext; + VkBool32 deviceFault; + VkBool32 deviceFaultVendorBinary; +} VkPhysicalDeviceFaultFeaturesEXT; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkStridedBufferRegionKHR { - VkBuffer buffer; - VkDeviceSize offset; - VkDeviceSize stride; - VkDeviceSize size; -} VkStridedBufferRegionKHR; -#endif +typedef struct VkDeviceFaultAddressInfoEXT { + VkDeviceFaultAddressTypeEXT addressType; + VkDeviceAddress reportedAddress; + VkDeviceSize addressPrecision; +} VkDeviceFaultAddressInfoEXT; -typedef struct VkDrmFormatModifierPropertiesEXT { - uint64_t drmFormatModifier; - uint32_t drmFormatModifierPlaneCount; - VkFormatFeatureFlags drmFormatModifierTilingFeatures; -} VkDrmFormatModifierPropertiesEXT; +typedef struct VkDeviceFaultCountsEXT { + VkStructureType sType; + void * pNext; + uint32_t addressInfoCount; + uint32_t vendorInfoCount; + VkDeviceSize vendorBinarySize; +} VkDeviceFaultCountsEXT; -typedef struct VkImageDrmFormatModifierExplicitCreateInfoEXT { +typedef struct VkDeviceFaultInfoEXT { VkStructureType sType; - const void * pNext; - uint64_t drmFormatModifier; - uint32_t drmFormatModifierPlaneCount; - const VkSubresourceLayout * pPlaneLayouts; -} VkImageDrmFormatModifierExplicitCreateInfoEXT; + void * pNext; + char description [ VK_MAX_DESCRIPTION_SIZE ]; + VkDeviceFaultAddressInfoEXT * pAddressInfos; + VkDeviceFaultVendorInfoEXT * pVendorInfos; + void * pVendorBinaryData; +} VkDeviceFaultInfoEXT; -typedef struct VkImageStencilUsageCreateInfo { +typedef struct VkPhysicalDevicePipelineLibraryGroupHandlesFeaturesEXT { VkStructureType sType; - const void * pNext; - VkImageUsageFlags stencilUsage; -} VkImageStencilUsageCreateInfo; + void * pNext; + VkBool32 pipelineLibraryGroupHandles; +} VkPhysicalDevicePipelineLibraryGroupHandlesFeaturesEXT; -typedef struct VkImageStencilUsageCreateInfo VkImageStencilUsageCreateInfoEXT; +typedef struct VkDepthBiasRepresentationInfoEXT { + VkStructureType sType; + const void * pNext; + VkDepthBiasRepresentationEXT depthBiasRepresentation; + VkBool32 depthBiasExact; +} VkDepthBiasRepresentationInfoEXT; -typedef struct VkPhysicalDeviceFragmentDensityMapFeaturesEXT { +typedef struct VkDecompressMemoryRegionNV { + VkDeviceAddress srcAddress; + VkDeviceAddress dstAddress; + VkDeviceSize compressedSize; + VkDeviceSize decompressedSize; + VkMemoryDecompressionMethodFlagsNV decompressionMethod; +} VkDecompressMemoryRegionNV; + +typedef struct VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM { VkStructureType sType; - void * pNext; - VkBool32 fragmentDensityMap; - VkBool32 fragmentDensityMapDynamic; - VkBool32 fragmentDensityMapNonSubsampledImages; -} VkPhysicalDeviceFragmentDensityMapFeaturesEXT; + void * pNext; + VkBool32 shaderCoreBuiltins; +} VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM; + +typedef struct VkFrameBoundaryEXT { + VkStructureType sType; + const void * pNext; + VkFrameBoundaryFlagsEXT flags; + uint64_t frameID; + uint32_t imageCount; + const VkImage * pImages; + uint32_t bufferCount; + const VkBuffer * pBuffers; + uint64_t tagName; + size_t tagSize; + const void * pTag; +} VkFrameBoundaryEXT; + +typedef struct VkPhysicalDeviceFrameBoundaryFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 frameBoundary; +} VkPhysicalDeviceFrameBoundaryFeaturesEXT; + +typedef struct VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 dynamicRenderingUnusedAttachments; +} VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT; -typedef struct VkPhysicalDeviceFragmentDensityMap2FeaturesEXT { +typedef struct VkSurfacePresentScalingCapabilitiesEXT { VkStructureType sType; - void * pNext; - VkBool32 fragmentDensityMapDeferred; -} VkPhysicalDeviceFragmentDensityMap2FeaturesEXT; + void * pNext; + VkPresentScalingFlagsEXT supportedPresentScaling; + VkPresentGravityFlagsEXT supportedPresentGravityX; + VkPresentGravityFlagsEXT supportedPresentGravityY; + VkExtent2D minScaledImageExtent; + VkExtent2D maxScaledImageExtent; +} VkSurfacePresentScalingCapabilitiesEXT; -typedef struct VkPhysicalDeviceFragmentDensityMapPropertiesEXT { +typedef struct VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT { VkStructureType sType; - void * pNext; - VkExtent2D minFragmentDensityTexelSize; - VkExtent2D maxFragmentDensityTexelSize; - VkBool32 fragmentDensityInvocations; -} VkPhysicalDeviceFragmentDensityMapPropertiesEXT; + void * pNext; + VkBool32 swapchainMaintenance1; +} VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT; -typedef struct VkPhysicalDeviceFragmentDensityMap2PropertiesEXT { +typedef struct VkSwapchainPresentScalingCreateInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 subsampledLoads; - VkBool32 subsampledCoarseReconstructionEarlyAccess; - uint32_t maxSubsampledArrayLayers; - uint32_t maxDescriptorSetSubsampledSamplers; -} VkPhysicalDeviceFragmentDensityMap2PropertiesEXT; + const void * pNext; + VkPresentScalingFlagsEXT scalingBehavior; + VkPresentGravityFlagsEXT presentGravityX; + VkPresentGravityFlagsEXT presentGravityY; +} VkSwapchainPresentScalingCreateInfoEXT; -typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures { +typedef struct VkPhysicalDeviceDepthBiasControlFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 scalarBlockLayout; -} VkPhysicalDeviceScalarBlockLayoutFeatures; + void * pNext; + VkBool32 depthBiasControl; + VkBool32 leastRepresentableValueForceUnormRepresentation; + VkBool32 floatRepresentation; + VkBool32 depthBiasExact; +} VkPhysicalDeviceDepthBiasControlFeaturesEXT; -typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures VkPhysicalDeviceScalarBlockLayoutFeaturesEXT; +typedef struct VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 rayTracingInvocationReorder; +} VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV; -typedef struct VkSurfaceProtectedCapabilitiesKHR { +typedef struct VkPhysicalDeviceExtendedSparseAddressSpaceFeaturesNV { VkStructureType sType; - const void * pNext; - VkBool32 supportsProtected; -} VkSurfaceProtectedCapabilitiesKHR; + void * pNext; + VkBool32 extendedSparseAddressSpace; +} VkPhysicalDeviceExtendedSparseAddressSpaceFeaturesNV; -typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures { +typedef struct VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV { VkStructureType sType; - void * pNext; - VkBool32 uniformBufferStandardLayout; -} VkPhysicalDeviceUniformBufferStandardLayoutFeatures; + void * pNext; + VkDeviceSize extendedSparseAddressSpaceSize; + VkImageUsageFlags extendedSparseImageUsageFlags; + VkBufferUsageFlags extendedSparseBufferUsageFlags; +} VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV; -typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR; +typedef struct VkDirectDriverLoadingInfoLUNARG { + VkStructureType sType; + void * pNext; + VkDirectDriverLoadingFlagsLUNARG flags; + PFN_vkGetInstanceProcAddrLUNARG pfnGetInstanceProcAddr; +} VkDirectDriverLoadingInfoLUNARG; -typedef struct VkPhysicalDeviceDepthClipEnableFeaturesEXT { +typedef struct VkDirectDriverLoadingListLUNARG { VkStructureType sType; - void * pNext; - VkBool32 depthClipEnable; -} VkPhysicalDeviceDepthClipEnableFeaturesEXT; + const void * pNext; + VkDirectDriverLoadingModeLUNARG mode; + uint32_t driverCount; + const VkDirectDriverLoadingInfoLUNARG * pDrivers; +} VkDirectDriverLoadingListLUNARG; -typedef struct VkPipelineRasterizationDepthClipStateCreateInfoEXT { +typedef struct VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM { VkStructureType sType; - const void * pNext; - VkPipelineRasterizationDepthClipStateCreateFlagsEXT flags; - VkBool32 depthClipEnable; -} VkPipelineRasterizationDepthClipStateCreateInfoEXT; + void * pNext; + VkBool32 multiviewPerViewViewports; +} VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM; -typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT { +typedef struct VkPhysicalDeviceRayTracingPositionFetchFeaturesKHR { VkStructureType sType; void * pNext; - VkDeviceSize heapBudget [ VK_MAX_MEMORY_HEAPS ]; - VkDeviceSize heapUsage [ VK_MAX_MEMORY_HEAPS ]; -} VkPhysicalDeviceMemoryBudgetPropertiesEXT; + VkBool32 rayTracingPositionFetch; +} VkPhysicalDeviceRayTracingPositionFetchFeaturesKHR; -typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT { +typedef struct VkDeviceImageSubresourceInfo { VkStructureType sType; - void * pNext; - VkBool32 memoryPriority; -} VkPhysicalDeviceMemoryPriorityFeaturesEXT; + const void * pNext; + const VkImageCreateInfo * pCreateInfo; + const VkImageSubresource2 * pSubresource; +} VkDeviceImageSubresourceInfo; -typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures { +typedef struct VkDeviceImageSubresourceInfo VkDeviceImageSubresourceInfoKHR; + +typedef struct VkPhysicalDeviceMultiviewPerViewRenderAreasFeaturesQCOM { VkStructureType sType; - void * pNext; - VkBool32 bufferDeviceAddress; - VkBool32 bufferDeviceAddressCaptureReplay; - VkBool32 bufferDeviceAddressMultiDevice; -} VkPhysicalDeviceBufferDeviceAddressFeatures; + void * pNext; + VkBool32 multiviewPerViewRenderAreas; +} VkPhysicalDeviceMultiviewPerViewRenderAreasFeaturesQCOM; -typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; +typedef struct VkMemoryMapInfo { + VkStructureType sType; + const void * pNext; + VkMemoryMapFlags flags; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; +} VkMemoryMapInfo; -typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT { +typedef struct VkMemoryMapInfo VkMemoryMapInfoKHR; + +typedef struct VkMemoryUnmapInfo { VkStructureType sType; - void * pNext; - VkBool32 bufferDeviceAddress; - VkBool32 bufferDeviceAddressCaptureReplay; - VkBool32 bufferDeviceAddressMultiDevice; -} VkPhysicalDeviceBufferDeviceAddressFeaturesEXT; + const void * pNext; + VkMemoryUnmapFlags flags; + VkDeviceMemory memory; +} VkMemoryUnmapInfo; -typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT VkPhysicalDeviceBufferAddressFeaturesEXT; +typedef struct VkMemoryUnmapInfo VkMemoryUnmapInfoKHR; -typedef struct VkBufferDeviceAddressCreateInfoEXT { +typedef struct VkPhysicalDeviceShaderObjectFeaturesEXT { VkStructureType sType; - const void * pNext; - VkDeviceAddress deviceAddress; -} VkBufferDeviceAddressCreateInfoEXT; + void * pNext; + VkBool32 shaderObject; +} VkPhysicalDeviceShaderObjectFeaturesEXT; -typedef struct VkFilterCubicImageViewImageFormatPropertiesEXT { +typedef struct VkShaderCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkShaderCreateFlagsEXT flags; + VkShaderStageFlagBits stage; + VkShaderStageFlags nextStage; + VkShaderCodeTypeEXT codeType; + size_t codeSize; + const void * pCode; + const char * pName; + uint32_t setLayoutCount; + const VkDescriptorSetLayout * pSetLayouts; + uint32_t pushConstantRangeCount; + const VkPushConstantRange * pPushConstantRanges; + const VkSpecializationInfo * pSpecializationInfo; +} VkShaderCreateInfoEXT; + +typedef struct VkPhysicalDeviceShaderTileImageFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 filterCubic; - VkBool32 filterCubicMinmax; -} VkFilterCubicImageViewImageFormatPropertiesEXT; + void * pNext; + VkBool32 shaderTileImageColorReadAccess; + VkBool32 shaderTileImageDepthReadAccess; + VkBool32 shaderTileImageStencilReadAccess; +} VkPhysicalDeviceShaderTileImageFeaturesEXT; -typedef struct VkPhysicalDeviceImagelessFramebufferFeatures { +typedef struct VkPhysicalDeviceShaderTileImagePropertiesEXT { VkStructureType sType; - void * pNext; - VkBool32 imagelessFramebuffer; -} VkPhysicalDeviceImagelessFramebufferFeatures; + void * pNext; + VkBool32 shaderTileImageCoherentReadAccelerated; + VkBool32 shaderTileImageReadSampleFromPixelRateInvocation; + VkBool32 shaderTileImageReadFromHelperInvocation; +} VkPhysicalDeviceShaderTileImagePropertiesEXT; -typedef struct VkPhysicalDeviceImagelessFramebufferFeatures VkPhysicalDeviceImagelessFramebufferFeaturesKHR; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef struct VkScreenBufferPropertiesQNX { + VkStructureType sType; + void * pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeBits; +} VkScreenBufferPropertiesQNX; -typedef struct VkFramebufferAttachmentImageInfo { +#endif + +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef struct VkScreenBufferFormatPropertiesQNX { VkStructureType sType; - const void * pNext; - VkImageCreateFlags flags; - VkImageUsageFlags usage; - uint32_t width; - uint32_t height; - uint32_t layerCount; - uint32_t viewFormatCount; - const VkFormat * pViewFormats; -} VkFramebufferAttachmentImageInfo; + void * pNext; + VkFormat format; + uint64_t externalFormat; + uint64_t screenUsage; + VkFormatFeatureFlags formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkScreenBufferFormatPropertiesQNX; -typedef struct VkFramebufferAttachmentImageInfo VkFramebufferAttachmentImageInfoKHR; +#endif -typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT { +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef struct VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX { VkStructureType sType; - void * pNext; - VkBool32 textureCompressionASTC_HDR; -} VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT; + void * pNext; + VkBool32 screenBufferImport; +} VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX; -typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV { +#endif + +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesKHR { VkStructureType sType; - void * pNext; + void * pNext; VkBool32 cooperativeMatrix; VkBool32 cooperativeMatrixRobustBufferAccess; -} VkPhysicalDeviceCooperativeMatrixFeaturesNV; +} VkPhysicalDeviceCooperativeMatrixFeaturesKHR; -typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV { +typedef struct VkCooperativeMatrixPropertiesKHR { VkStructureType sType; void * pNext; - VkShaderStageFlags cooperativeMatrixSupportedStages; -} VkPhysicalDeviceCooperativeMatrixPropertiesNV; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeKHR AType; + VkComponentTypeKHR BType; + VkComponentTypeKHR CType; + VkComponentTypeKHR ResultType; + VkBool32 saturatingAccumulation; + VkScopeKHR scope; +} VkCooperativeMatrixPropertiesKHR; -typedef struct VkPhysicalDeviceYcbcrImageArraysFeaturesEXT { +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesKHR { VkStructureType sType; - void * pNext; - VkBool32 ycbcrImageArrays; -} VkPhysicalDeviceYcbcrImageArraysFeaturesEXT; + void * pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesKHR; -typedef struct VkImageViewAddressPropertiesNVX { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDeviceShaderEnqueueFeaturesAMDX { VkStructureType sType; - void * pNext; - VkDeviceAddress deviceAddress; - VkDeviceSize size; -} VkImageViewAddressPropertiesNVX; + void * pNext; + VkBool32 shaderEnqueue; + VkBool32 shaderMeshEnqueue; +} VkPhysicalDeviceShaderEnqueueFeaturesAMDX; -typedef struct VkPipelineCreationFeedbackEXT { - VkPipelineCreationFeedbackFlagsEXT flags; - uint64_t duration; -} VkPipelineCreationFeedbackEXT; +#endif -typedef struct VkPipelineCreationFeedbackCreateInfoEXT { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkExecutionGraphPipelineCreateInfoAMDX { VkStructureType sType; - const void * pNext; - VkPipelineCreationFeedbackEXT * pPipelineCreationFeedback; - uint32_t pipelineStageCreationFeedbackCount; - VkPipelineCreationFeedbackEXT * pPipelineStageCreationFeedbacks; -} VkPipelineCreationFeedbackCreateInfoEXT; + const void * pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo * pStages; + const VkPipelineLibraryCreateInfoKHR * pLibraryInfo; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkExecutionGraphPipelineCreateInfoAMDX; -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkSurfaceCapabilitiesFullScreenExclusiveEXT { - VkStructureType sType; - void * pNext; - VkBool32 fullScreenExclusiveSupported; -} VkSurfaceCapabilitiesFullScreenExclusiveEXT; #endif -typedef struct VkPhysicalDevicePerformanceQueryFeaturesKHR { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkExecutionGraphPipelineScratchSizeAMDX { VkStructureType sType; - void * pNext; - VkBool32 performanceCounterQueryPools; - VkBool32 performanceCounterMultipleQueryPools; -} VkPhysicalDevicePerformanceQueryFeaturesKHR; + void * pNext; + VkDeviceSize minSize; + VkDeviceSize maxSize; + VkDeviceSize sizeGranularity; +} VkExecutionGraphPipelineScratchSizeAMDX; -typedef struct VkPhysicalDevicePerformanceQueryPropertiesKHR { - VkStructureType sType; - void * pNext; - VkBool32 allowCommandBufferQueryCopies; -} VkPhysicalDevicePerformanceQueryPropertiesKHR; +#endif -typedef struct VkPerformanceCounterDescriptionKHR { - VkStructureType sType; - const void * pNext; - VkPerformanceCounterDescriptionFlagsKHR flags; - char name [ VK_MAX_DESCRIPTION_SIZE ]; - char category [ VK_MAX_DESCRIPTION_SIZE ]; - char description [ VK_MAX_DESCRIPTION_SIZE ]; -} VkPerformanceCounterDescriptionKHR; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkDispatchGraphInfoAMDX { + uint32_t nodeIndex; + uint32_t payloadCount; + VkDeviceOrHostAddressConstAMDX payloads; + uint64_t payloadStride; +} VkDispatchGraphInfoAMDX; -typedef struct VkAcquireProfilingLockInfoKHR { - VkStructureType sType; - const void * pNext; - VkAcquireProfilingLockFlagsKHR flags; - uint64_t timeout; -} VkAcquireProfilingLockInfoKHR; +#endif -typedef struct VkHeadlessSurfaceCreateInfoEXT { - VkStructureType sType; - const void * pNext; - VkHeadlessSurfaceCreateFlagsEXT flags; -} VkHeadlessSurfaceCreateInfoEXT; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkDispatchGraphCountInfoAMDX { + uint32_t count; + VkDeviceOrHostAddressConstAMDX infos; + uint64_t stride; +} VkDispatchGraphCountInfoAMDX; -typedef struct VkPhysicalDeviceCoverageReductionModeFeaturesNV { - VkStructureType sType; - void * pNext; - VkBool32 coverageReductionMode; -} VkPhysicalDeviceCoverageReductionModeFeaturesNV; +#endif -typedef struct VkPipelineCoverageReductionStateCreateInfoNV { +typedef struct VkPhysicalDeviceAntiLagFeaturesAMD { VkStructureType sType; - const void * pNext; - VkPipelineCoverageReductionStateCreateFlagsNV flags; - VkCoverageReductionModeNV coverageReductionMode; -} VkPipelineCoverageReductionStateCreateInfoNV; + void * pNext; + VkBool32 antiLag; +} VkPhysicalDeviceAntiLagFeaturesAMD; -typedef struct VkFramebufferMixedSamplesCombinationNV { +typedef struct VkAntiLagDataAMD { VkStructureType sType; - void * pNext; - VkCoverageReductionModeNV coverageReductionMode; - VkSampleCountFlagBits rasterizationSamples; - VkSampleCountFlags depthStencilSamples; - VkSampleCountFlags colorSamples; -} VkFramebufferMixedSamplesCombinationNV; + const void * pNext; + VkAntiLagModeAMD mode; + uint32_t maxFPS; + const VkAntiLagPresentationInfoAMD * pPresentationInfo; +} VkAntiLagDataAMD; -typedef struct VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL { +typedef struct VkPhysicalDeviceTileMemoryHeapFeaturesQCOM { VkStructureType sType; - void * pNext; - VkBool32 shaderIntegerFunctions2; -} VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL; - -typedef union VkPerformanceValueDataINTEL { - uint32_t value32; - uint64_t value64; - float valueFloat; - VkBool32 valueBool; - const char * valueString; -} VkPerformanceValueDataINTEL; + void * pNext; + VkBool32 tileMemoryHeap; +} VkPhysicalDeviceTileMemoryHeapFeaturesQCOM; -typedef struct VkPerformanceValueINTEL { - VkPerformanceValueTypeINTEL type; - VkPerformanceValueDataINTEL data; -} VkPerformanceValueINTEL; +typedef struct VkPhysicalDeviceTileMemoryHeapPropertiesQCOM { + VkStructureType sType; + void * pNext; + VkBool32 queueSubmitBoundary; + VkBool32 tileBufferTransfers; +} VkPhysicalDeviceTileMemoryHeapPropertiesQCOM; -typedef struct VkPerformanceOverrideInfoINTEL { +typedef struct VkTileMemorySizeInfoQCOM { VkStructureType sType; - const void * pNext; - VkPerformanceOverrideTypeINTEL type; - VkBool32 enable; - uint64_t parameter; -} VkPerformanceOverrideInfoINTEL; + const void * pNext; + VkDeviceSize size; +} VkTileMemorySizeInfoQCOM; -typedef struct VkPhysicalDeviceShaderClockFeaturesKHR { +typedef struct VkTileMemoryRequirementsQCOM { VkStructureType sType; - void * pNext; - VkBool32 shaderSubgroupClock; - VkBool32 shaderDeviceClock; -} VkPhysicalDeviceShaderClockFeaturesKHR; + void * pNext; + VkDeviceSize size; + VkDeviceSize alignment; +} VkTileMemoryRequirementsQCOM; -typedef struct VkPhysicalDeviceIndexTypeUint8FeaturesEXT { +typedef struct VkBindDescriptorSetsInfo { VkStructureType sType; - void * pNext; - VkBool32 indexTypeUint8; -} VkPhysicalDeviceIndexTypeUint8FeaturesEXT; + const void * pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t firstSet; + uint32_t descriptorSetCount; + const VkDescriptorSet * pDescriptorSets; + uint32_t dynamicOffsetCount; + const uint32_t * pDynamicOffsets; +} VkBindDescriptorSetsInfo; + +typedef struct VkBindDescriptorSetsInfo VkBindDescriptorSetsInfoKHR; + +typedef struct VkPushConstantsInfo { + VkStructureType sType; + const void * pNext; + VkPipelineLayout layout; + VkShaderStageFlags stageFlags; + uint32_t offset; + uint32_t size; + const void * pValues; +} VkPushConstantsInfo; + +typedef struct VkPushConstantsInfo VkPushConstantsInfoKHR; + +typedef struct VkPushDescriptorSetInfo { + VkStructureType sType; + const void * pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t set; + uint32_t descriptorWriteCount; + const VkWriteDescriptorSet * pDescriptorWrites; +} VkPushDescriptorSetInfo; -typedef struct VkPhysicalDeviceShaderSMBuiltinsFeaturesNV { - VkStructureType sType; - void * pNext; - VkBool32 shaderSMBuiltins; -} VkPhysicalDeviceShaderSMBuiltinsFeaturesNV; +typedef struct VkPushDescriptorSetInfo VkPushDescriptorSetInfoKHR; -typedef struct VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT { +typedef struct VkSetDescriptorBufferOffsetsInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 fragmentShaderSampleInterlock; - VkBool32 fragmentShaderPixelInterlock; - VkBool32 fragmentShaderShadingRateInterlock; -} VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT; - -typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures { - VkStructureType sType; - void * pNext; - VkBool32 separateDepthStencilLayouts; -} VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures; + const void * pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t firstSet; + uint32_t setCount; + const uint32_t * pBufferIndices; + const VkDeviceSize * pOffsets; +} VkSetDescriptorBufferOffsetsInfoEXT; -typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR; +typedef struct VkBindDescriptorBufferEmbeddedSamplersInfoEXT { + VkStructureType sType; + const void * pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t set; +} VkBindDescriptorBufferEmbeddedSamplersInfoEXT; -typedef struct VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR { +typedef struct VkPhysicalDeviceCubicClampFeaturesQCOM { VkStructureType sType; - void * pNext; - VkBool32 pipelineExecutableInfo; -} VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR; + void * pNext; + VkBool32 cubicRangeClamp; +} VkPhysicalDeviceCubicClampFeaturesQCOM; -typedef struct VkPipelineExecutablePropertiesKHR { +typedef struct VkPhysicalDeviceYcbcrDegammaFeaturesQCOM { + VkStructureType sType; + void * pNext; + VkBool32 ycbcrDegamma; +} VkPhysicalDeviceYcbcrDegammaFeaturesQCOM; + +typedef struct VkSamplerYcbcrConversionYcbcrDegammaCreateInfoQCOM { VkStructureType sType; void * pNext; - VkShaderStageFlags stages; - char name [ VK_MAX_DESCRIPTION_SIZE ]; - char description [ VK_MAX_DESCRIPTION_SIZE ]; - uint32_t subgroupSize; -} VkPipelineExecutablePropertiesKHR; + VkBool32 enableYDegamma; + VkBool32 enableCbCrDegamma; +} VkSamplerYcbcrConversionYcbcrDegammaCreateInfoQCOM; -typedef union VkPipelineExecutableStatisticValueKHR { - VkBool32 b32; - int64_t i64; - uint64_t u64; - double f64; -} VkPipelineExecutableStatisticValueKHR; +typedef struct VkPhysicalDeviceCubicWeightsFeaturesQCOM { + VkStructureType sType; + void * pNext; + VkBool32 selectableCubicWeights; +} VkPhysicalDeviceCubicWeightsFeaturesQCOM; -typedef struct VkPipelineExecutableStatisticKHR { +typedef struct VkPhysicalDeviceImageProcessing2FeaturesQCOM { VkStructureType sType; - void * pNext; - char name [ VK_MAX_DESCRIPTION_SIZE ]; - char description [ VK_MAX_DESCRIPTION_SIZE ]; - VkPipelineExecutableStatisticFormatKHR format; - VkPipelineExecutableStatisticValueKHR value; -} VkPipelineExecutableStatisticKHR; + void * pNext; + VkBool32 textureBlockMatch2; +} VkPhysicalDeviceImageProcessing2FeaturesQCOM; -typedef struct VkPipelineExecutableInternalRepresentationKHR { +typedef struct VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV { VkStructureType sType; - void * pNext; - char name [ VK_MAX_DESCRIPTION_SIZE ]; - char description [ VK_MAX_DESCRIPTION_SIZE ]; - VkBool32 isText; - size_t dataSize; - void * pData; -} VkPipelineExecutableInternalRepresentationKHR; + void * pNext; + VkBool32 descriptorPoolOverallocation; +} VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV; -typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT { +typedef struct VkPhysicalDevicePerStageDescriptorSetFeaturesNV { VkStructureType sType; - void * pNext; - VkBool32 shaderDemoteToHelperInvocation; -} VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT; + void * pNext; + VkBool32 perStageDescriptorSet; + VkBool32 dynamicPipelineLayout; +} VkPhysicalDevicePerStageDescriptorSetFeaturesNV; -typedef struct VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT { +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef struct VkPhysicalDeviceExternalFormatResolveFeaturesANDROID { VkStructureType sType; void * pNext; - VkBool32 texelBufferAlignment; -} VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT; + VkBool32 externalFormatResolve; +} VkPhysicalDeviceExternalFormatResolveFeaturesANDROID; + +#endif -typedef struct VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT { +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef struct VkPhysicalDeviceExternalFormatResolvePropertiesANDROID { VkStructureType sType; void * pNext; - VkDeviceSize storageTexelBufferOffsetAlignmentBytes; - VkBool32 storageTexelBufferOffsetSingleTexelAlignment; - VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; - VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; -} VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT; + VkBool32 nullColorAttachmentWithExternalFormatResolve; + VkChromaLocation externalFormatResolveChromaOffsetX; + VkChromaLocation externalFormatResolveChromaOffsetY; +} VkPhysicalDeviceExternalFormatResolvePropertiesANDROID; -typedef struct VkPhysicalDeviceSubgroupSizeControlFeaturesEXT { - VkStructureType sType; - void * pNext; - VkBool32 subgroupSizeControl; - VkBool32 computeFullSubgroups; -} VkPhysicalDeviceSubgroupSizeControlFeaturesEXT; +#endif -typedef struct VkPhysicalDeviceSubgroupSizeControlPropertiesEXT { +typedef struct VkLatencySleepModeInfoNV { VkStructureType sType; - void * pNext; - uint32_t minSubgroupSize; - uint32_t maxSubgroupSize; - uint32_t maxComputeWorkgroupSubgroups; - VkShaderStageFlags requiredSubgroupSizeStages; -} VkPhysicalDeviceSubgroupSizeControlPropertiesEXT; + const void * pNext; + VkBool32 lowLatencyMode; + VkBool32 lowLatencyBoost; + uint32_t minimumIntervalUs; +} VkLatencySleepModeInfoNV; -typedef struct VkPhysicalDeviceLineRasterizationFeaturesEXT { +typedef struct VkGetLatencyMarkerInfoNV { VkStructureType sType; - void * pNext; - VkBool32 rectangularLines; - VkBool32 bresenhamLines; - VkBool32 smoothLines; - VkBool32 stippledRectangularLines; - VkBool32 stippledBresenhamLines; - VkBool32 stippledSmoothLines; -} VkPhysicalDeviceLineRasterizationFeaturesEXT; + const void * pNext; + uint32_t timingCount; + VkLatencyTimingsFrameReportNV * pTimings; +} VkGetLatencyMarkerInfoNV; -typedef struct VkPipelineRasterizationLineStateCreateInfoEXT { +typedef struct VkSwapchainLatencyCreateInfoNV { VkStructureType sType; - const void * pNext; - VkLineRasterizationModeEXT lineRasterizationMode; - VkBool32 stippledLineEnable; - uint32_t lineStippleFactor; - uint16_t lineStipplePattern; -} VkPipelineRasterizationLineStateCreateInfoEXT; + const void * pNext; + VkBool32 latencyModeEnable; +} VkSwapchainLatencyCreateInfoNV; -typedef struct VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDeviceCudaKernelLaunchFeaturesNV { VkStructureType sType; - void * pNext; - VkBool32 pipelineCreationCacheControl; -} VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT; - -typedef struct VkPhysicalDeviceVulkan11Features { - VkStructureType sType; void * pNext; - VkBool32 storageBuffer16BitAccess; - VkBool32 uniformAndStorageBuffer16BitAccess; - VkBool32 storagePushConstant16; - VkBool32 storageInputOutput16; - VkBool32 multiview; - VkBool32 multiviewGeometryShader; - VkBool32 multiviewTessellationShader; - VkBool32 variablePointersStorageBuffer; - VkBool32 variablePointers; - VkBool32 protectedMemory; - VkBool32 samplerYcbcrConversion; - VkBool32 shaderDrawParameters; -} VkPhysicalDeviceVulkan11Features; - -typedef struct VkPhysicalDeviceVulkan11Properties { - VkStructureType sType; - void * pNext; - uint8_t deviceUUID [ VK_UUID_SIZE ]; - uint8_t driverUUID [ VK_UUID_SIZE ]; - uint8_t deviceLUID [ VK_LUID_SIZE ]; - uint32_t deviceNodeMask; - VkBool32 deviceLUIDValid; - uint32_t subgroupSize; - VkShaderStageFlags subgroupSupportedStages; - VkSubgroupFeatureFlags subgroupSupportedOperations; - VkBool32 subgroupQuadOperationsInAllStages; - VkPointClippingBehavior pointClippingBehavior; - uint32_t maxMultiviewViewCount; - uint32_t maxMultiviewInstanceIndex; - VkBool32 protectedNoFault; - uint32_t maxPerSetDescriptors; - VkDeviceSize maxMemoryAllocationSize; -} VkPhysicalDeviceVulkan11Properties; + VkBool32 cudaKernelLaunchFeatures; +} VkPhysicalDeviceCudaKernelLaunchFeaturesNV; -typedef struct VkPhysicalDeviceVulkan12Features { - VkStructureType sType; - void * pNext; - VkBool32 samplerMirrorClampToEdge; - VkBool32 drawIndirectCount; - VkBool32 storageBuffer8BitAccess; - VkBool32 uniformAndStorageBuffer8BitAccess; - VkBool32 storagePushConstant8; - VkBool32 shaderBufferInt64Atomics; - VkBool32 shaderSharedInt64Atomics; - VkBool32 shaderFloat16; - VkBool32 shaderInt8; - VkBool32 descriptorIndexing; - VkBool32 shaderInputAttachmentArrayDynamicIndexing; - VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; - VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; - VkBool32 shaderUniformBufferArrayNonUniformIndexing; - VkBool32 shaderSampledImageArrayNonUniformIndexing; - VkBool32 shaderStorageBufferArrayNonUniformIndexing; - VkBool32 shaderStorageImageArrayNonUniformIndexing; - VkBool32 shaderInputAttachmentArrayNonUniformIndexing; - VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; - VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; - VkBool32 descriptorBindingUniformBufferUpdateAfterBind; - VkBool32 descriptorBindingSampledImageUpdateAfterBind; - VkBool32 descriptorBindingStorageImageUpdateAfterBind; - VkBool32 descriptorBindingStorageBufferUpdateAfterBind; - VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingUpdateUnusedWhilePending; - VkBool32 descriptorBindingPartiallyBound; - VkBool32 descriptorBindingVariableDescriptorCount; - VkBool32 runtimeDescriptorArray; - VkBool32 samplerFilterMinmax; - VkBool32 scalarBlockLayout; - VkBool32 imagelessFramebuffer; - VkBool32 uniformBufferStandardLayout; - VkBool32 shaderSubgroupExtendedTypes; - VkBool32 separateDepthStencilLayouts; - VkBool32 hostQueryReset; - VkBool32 timelineSemaphore; - VkBool32 bufferDeviceAddress; - VkBool32 bufferDeviceAddressCaptureReplay; - VkBool32 bufferDeviceAddressMultiDevice; - VkBool32 vulkanMemoryModel; - VkBool32 vulkanMemoryModelDeviceScope; - VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; - VkBool32 shaderOutputViewportIndex; - VkBool32 shaderOutputLayer; - VkBool32 subgroupBroadcastDynamicId; -} VkPhysicalDeviceVulkan12Features; +#endif -typedef struct VkPhysicalDeviceVulkan12Properties { - VkStructureType sType; - void * pNext; - VkDriverId driverID; - char driverName [ VK_MAX_DRIVER_NAME_SIZE ]; - char driverInfo [ VK_MAX_DRIVER_INFO_SIZE ]; - VkConformanceVersion conformanceVersion; - VkShaderFloatControlsIndependence denormBehaviorIndependence; - VkShaderFloatControlsIndependence roundingModeIndependence; - VkBool32 shaderSignedZeroInfNanPreserveFloat16; - VkBool32 shaderSignedZeroInfNanPreserveFloat32; - VkBool32 shaderSignedZeroInfNanPreserveFloat64; - VkBool32 shaderDenormPreserveFloat16; - VkBool32 shaderDenormPreserveFloat32; - VkBool32 shaderDenormPreserveFloat64; - VkBool32 shaderDenormFlushToZeroFloat16; - VkBool32 shaderDenormFlushToZeroFloat32; - VkBool32 shaderDenormFlushToZeroFloat64; - VkBool32 shaderRoundingModeRTEFloat16; - VkBool32 shaderRoundingModeRTEFloat32; - VkBool32 shaderRoundingModeRTEFloat64; - VkBool32 shaderRoundingModeRTZFloat16; - VkBool32 shaderRoundingModeRTZFloat32; - VkBool32 shaderRoundingModeRTZFloat64; - uint32_t maxUpdateAfterBindDescriptorsInAllPools; - VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; - VkBool32 shaderSampledImageArrayNonUniformIndexingNative; - VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; - VkBool32 shaderStorageImageArrayNonUniformIndexingNative; - VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; - VkBool32 robustBufferAccessUpdateAfterBind; - VkBool32 quadDivergentImplicitLod; - uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; - uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; - uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; - uint32_t maxPerStageUpdateAfterBindResources; - uint32_t maxDescriptorSetUpdateAfterBindSamplers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindSampledImages; - uint32_t maxDescriptorSetUpdateAfterBindStorageImages; - uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; - VkResolveModeFlags supportedDepthResolveModes; - VkResolveModeFlags supportedStencilResolveModes; - VkBool32 independentResolveNone; - VkBool32 independentResolve; - VkBool32 filterMinmaxSingleComponentFormats; - VkBool32 filterMinmaxImageComponentMapping; - uint64_t maxTimelineSemaphoreValueDifference; - VkSampleCountFlags framebufferIntegerColorSampleCounts; -} VkPhysicalDeviceVulkan12Properties; +typedef struct VkPhysicalDeviceSchedulingControlsFeaturesARM { + VkStructureType sType; + void * pNext; + VkBool32 schedulingControls; +} VkPhysicalDeviceSchedulingControlsFeaturesARM; -typedef struct VkPipelineCompilerControlCreateInfoAMD { - VkStructureType sType; - const void * pNext; - VkPipelineCompilerControlFlagsAMD compilerControlFlags; -} VkPipelineCompilerControlCreateInfoAMD; +typedef struct VkPhysicalDeviceSchedulingControlsPropertiesARM { + VkStructureType sType; + void * pNext; + VkPhysicalDeviceSchedulingControlsFlagsARM schedulingControlsFlags; +} VkPhysicalDeviceSchedulingControlsPropertiesARM; -typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD { +typedef struct VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG { VkStructureType sType; void * pNext; - VkBool32 deviceCoherentMemory; -} VkPhysicalDeviceCoherentMemoryFeaturesAMD; + VkBool32 relaxedLineRasterization; +} VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG; -typedef struct VkPhysicalDeviceToolPropertiesEXT { +typedef struct VkPhysicalDeviceRenderPassStripedFeaturesARM { VkStructureType sType; - void * pNext; - char name [ VK_MAX_EXTENSION_NAME_SIZE ]; - char version [ VK_MAX_EXTENSION_NAME_SIZE ]; - VkToolPurposeFlagsEXT purposes; - char description [ VK_MAX_DESCRIPTION_SIZE ]; - char layer [ VK_MAX_EXTENSION_NAME_SIZE ]; -} VkPhysicalDeviceToolPropertiesEXT; + void * pNext; + VkBool32 renderPassStriped; +} VkPhysicalDeviceRenderPassStripedFeaturesARM; -typedef struct VkPhysicalDeviceCustomBorderColorFeaturesEXT { +typedef struct VkRenderPassStripeSubmitInfoARM { VkStructureType sType; - void * pNext; - VkBool32 customBorderColors; - VkBool32 customBorderColorWithoutFormat; -} VkPhysicalDeviceCustomBorderColorFeaturesEXT; + const void * pNext; + uint32_t stripeSemaphoreInfoCount; + const VkSemaphoreSubmitInfo * pStripeSemaphoreInfos; +} VkRenderPassStripeSubmitInfoARM; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef union VkDeviceOrHostAddressKHR { - VkDeviceAddress deviceAddress; - void * hostAddress; -} VkDeviceOrHostAddressKHR; -#endif +typedef struct VkPhysicalDevicePipelineOpacityMicromapFeaturesARM { + VkStructureType sType; + void * pNext; + VkBool32 pipelineOpacityMicromap; +} VkPhysicalDevicePipelineOpacityMicromapFeaturesARM; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef union VkDeviceOrHostAddressConstKHR { - VkDeviceAddress deviceAddress; - const void * hostAddress; -} VkDeviceOrHostAddressConstKHR; -#endif +typedef struct VkPhysicalDeviceShaderMaximalReconvergenceFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 shaderMaximalReconvergence; +} VkPhysicalDeviceShaderMaximalReconvergenceFeaturesKHR; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureGeometryTrianglesDataKHR { +typedef struct VkPhysicalDeviceShaderSubgroupRotateFeatures { VkStructureType sType; - const void * pNext; - VkFormat vertexFormat; - VkDeviceOrHostAddressConstKHR vertexData; - VkDeviceSize vertexStride; - VkIndexType indexType; - VkDeviceOrHostAddressConstKHR indexData; - VkDeviceOrHostAddressConstKHR transformData; -} VkAccelerationStructureGeometryTrianglesDataKHR; -#endif + void * pNext; + VkBool32 shaderSubgroupRotate; + VkBool32 shaderSubgroupRotateClustered; +} VkPhysicalDeviceShaderSubgroupRotateFeatures; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureGeometryAabbsDataKHR { +typedef struct VkPhysicalDeviceShaderSubgroupRotateFeatures VkPhysicalDeviceShaderSubgroupRotateFeaturesKHR; + +typedef struct VkPhysicalDeviceShaderExpectAssumeFeatures { VkStructureType sType; - const void * pNext; - VkDeviceOrHostAddressConstKHR data; - VkDeviceSize stride; -} VkAccelerationStructureGeometryAabbsDataKHR; -#endif + void * pNext; + VkBool32 shaderExpectAssume; +} VkPhysicalDeviceShaderExpectAssumeFeatures; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureGeometryInstancesDataKHR { +typedef struct VkPhysicalDeviceShaderExpectAssumeFeatures VkPhysicalDeviceShaderExpectAssumeFeaturesKHR; + +typedef struct VkPhysicalDeviceShaderFloatControls2Features { VkStructureType sType; - const void * pNext; - VkBool32 arrayOfPointers; - VkDeviceOrHostAddressConstKHR data; -} VkAccelerationStructureGeometryInstancesDataKHR; -#endif + void * pNext; + VkBool32 shaderFloatControls2; +} VkPhysicalDeviceShaderFloatControls2Features; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef union VkAccelerationStructureGeometryDataKHR { - VkAccelerationStructureGeometryTrianglesDataKHR triangles; - VkAccelerationStructureGeometryAabbsDataKHR aabbs; - VkAccelerationStructureGeometryInstancesDataKHR instances; -} VkAccelerationStructureGeometryDataKHR; -#endif +typedef struct VkPhysicalDeviceShaderFloatControls2Features VkPhysicalDeviceShaderFloatControls2FeaturesKHR; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureGeometryKHR { +typedef struct VkPhysicalDeviceDynamicRenderingLocalReadFeatures { VkStructureType sType; - const void * pNext; - VkGeometryTypeKHR geometryType; - VkAccelerationStructureGeometryDataKHR geometry; - VkGeometryFlagsKHR flags; -} VkAccelerationStructureGeometryKHR; -#endif + void * pNext; + VkBool32 dynamicRenderingLocalRead; +} VkPhysicalDeviceDynamicRenderingLocalReadFeatures; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureBuildGeometryInfoKHR { +typedef struct VkPhysicalDeviceDynamicRenderingLocalReadFeatures VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR; + +typedef struct VkPhysicalDeviceShaderQuadControlFeaturesKHR { VkStructureType sType; - const void * pNext; - VkAccelerationStructureTypeKHR type; - VkBuildAccelerationStructureFlagsKHR flags; - VkBool32 update; - VkAccelerationStructureKHR srcAccelerationStructure; - VkAccelerationStructureKHR dstAccelerationStructure; - VkBool32 geometryArrayOfPointers; - uint32_t geometryCount; - const VkAccelerationStructureGeometryKHR * const* ppGeometries; - VkDeviceOrHostAddressKHR scratchData; -} VkAccelerationStructureBuildGeometryInfoKHR; -#endif + void * pNext; + VkBool32 shaderQuadControl; +} VkPhysicalDeviceShaderQuadControlFeaturesKHR; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureCreateGeometryTypeInfoKHR { +typedef struct VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV { VkStructureType sType; - const void * pNext; - VkGeometryTypeKHR geometryType; - uint32_t maxPrimitiveCount; - VkIndexType indexType; - uint32_t maxVertexCount; - VkFormat vertexFormat; - VkBool32 allowsTransforms; -} VkAccelerationStructureCreateGeometryTypeInfoKHR; -#endif + void * pNext; + VkBool32 shaderFloat16VectorAtomics; +} VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV; + +typedef struct VkPhysicalDeviceMapMemoryPlacedFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 memoryMapPlaced; + VkBool32 memoryMapRangePlaced; + VkBool32 memoryUnmapReserve; +} VkPhysicalDeviceMapMemoryPlacedFeaturesEXT; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureCreateInfoKHR { +typedef struct VkPhysicalDeviceMapMemoryPlacedPropertiesEXT { VkStructureType sType; - const void * pNext; - VkDeviceSize compactedSize; - VkAccelerationStructureTypeKHR type; - VkBuildAccelerationStructureFlagsKHR flags; - uint32_t maxGeometryCount; - const VkAccelerationStructureCreateGeometryTypeInfoKHR * pGeometryInfos; - VkDeviceAddress deviceAddress; -} VkAccelerationStructureCreateInfoKHR; -#endif + void * pNext; + VkDeviceSize minPlacedMemoryMapAlignment; +} VkPhysicalDeviceMapMemoryPlacedPropertiesEXT; -typedef struct VkAccelerationStructureInstanceKHR { - VkTransformMatrixKHR transform; - uint32_t instanceCustomIndex :24; - uint32_t mask :8; - uint32_t instanceShaderBindingTableRecordOffset :24; - VkGeometryInstanceFlagsKHR flags :8; - uint64_t accelerationStructureReference; -} VkAccelerationStructureInstanceKHR; +typedef struct VkPhysicalDeviceShaderBfloat16FeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 shaderBFloat16Type; + VkBool32 shaderBFloat16DotProduct; + VkBool32 shaderBFloat16CooperativeMatrix; +} VkPhysicalDeviceShaderBfloat16FeaturesKHR; -typedef struct VkAccelerationStructureInstanceKHR VkAccelerationStructureInstanceNV; +typedef struct VkPhysicalDeviceRawAccessChainsFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 shaderRawAccessChains; +} VkPhysicalDeviceRawAccessChainsFeaturesNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkCopyAccelerationStructureToMemoryInfoKHR { +typedef struct VkPhysicalDeviceCommandBufferInheritanceFeaturesNV { VkStructureType sType; - const void * pNext; - VkAccelerationStructureKHR src; - VkDeviceOrHostAddressKHR dst; - VkCopyAccelerationStructureModeKHR mode; -} VkCopyAccelerationStructureToMemoryInfoKHR; -#endif + void * pNext; + VkBool32 commandBufferInheritance; +} VkPhysicalDeviceCommandBufferInheritanceFeaturesNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkCopyMemoryToAccelerationStructureInfoKHR { +typedef struct VkPhysicalDeviceImageAlignmentControlFeaturesMESA { VkStructureType sType; - const void * pNext; - VkDeviceOrHostAddressConstKHR src; - VkAccelerationStructureKHR dst; - VkCopyAccelerationStructureModeKHR mode; -} VkCopyMemoryToAccelerationStructureInfoKHR; -#endif + void * pNext; + VkBool32 imageAlignmentControl; +} VkPhysicalDeviceImageAlignmentControlFeaturesMESA; -typedef struct VkPhysicalDeviceExtendedDynamicStateFeaturesEXT { +typedef struct VkPhysicalDeviceShaderReplicatedCompositesFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 extendedDynamicState; -} VkPhysicalDeviceExtendedDynamicStateFeaturesEXT; + void * pNext; + VkBool32 shaderReplicatedComposites; +} VkPhysicalDeviceShaderReplicatedCompositesFeaturesEXT; -typedef struct VkPhysicalDeviceDiagnosticsConfigFeaturesNV { - VkStructureType sType; +typedef struct VkPhysicalDevicePresentModeFifoLatestReadyFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 presentModeFifoLatestReady; +} VkPhysicalDevicePresentModeFifoLatestReadyFeaturesEXT; + +typedef struct VkPhysicalDeviceCooperativeMatrix2FeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 cooperativeMatrixWorkgroupScope; + VkBool32 cooperativeMatrixFlexibleDimensions; + VkBool32 cooperativeMatrixReductions; + VkBool32 cooperativeMatrixConversions; + VkBool32 cooperativeMatrixPerElementOperations; + VkBool32 cooperativeMatrixTensorAddressing; + VkBool32 cooperativeMatrixBlockLoads; +} VkPhysicalDeviceCooperativeMatrix2FeaturesNV; + +typedef struct VkCooperativeMatrixFlexibleDimensionsPropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t MGranularity; + uint32_t NGranularity; + uint32_t KGranularity; + VkComponentTypeKHR AType; + VkComponentTypeKHR BType; + VkComponentTypeKHR CType; + VkComponentTypeKHR ResultType; + VkBool32 saturatingAccumulation; + VkScopeKHR scope; + uint32_t workgroupInvocations; +} VkCooperativeMatrixFlexibleDimensionsPropertiesNV; + +typedef struct VkPhysicalDeviceHdrVividFeaturesHUAWEI { + VkStructureType sType; void * pNext; - VkBool32 diagnosticsConfig; -} VkPhysicalDeviceDiagnosticsConfigFeaturesNV; + VkBool32 hdrVivid; +} VkPhysicalDeviceHdrVividFeaturesHUAWEI; -typedef struct VkDeviceDiagnosticsConfigCreateInfoNV { +typedef struct VkPhysicalDeviceVertexAttributeRobustnessFeaturesEXT { VkStructureType sType; - const void * pNext; - VkDeviceDiagnosticsConfigFlagsNV flags; -} VkDeviceDiagnosticsConfigCreateInfoNV; + void * pNext; + VkBool32 vertexAttributeRobustness; +} VkPhysicalDeviceVertexAttributeRobustnessFeaturesEXT; -typedef struct VkPhysicalDeviceRobustness2FeaturesEXT { +typedef struct VkPhysicalDeviceDepthClampZeroOneFeaturesKHR { VkStructureType sType; void * pNext; - VkBool32 robustBufferAccess2; - VkBool32 robustImageAccess2; - VkBool32 nullDescriptor; -} VkPhysicalDeviceRobustness2FeaturesEXT; + VkBool32 depthClampZeroOne; +} VkPhysicalDeviceDepthClampZeroOneFeaturesKHR; -typedef struct VkPhysicalDeviceRobustness2PropertiesEXT { +typedef struct VkPhysicalDeviceCooperativeVectorFeaturesNV { VkStructureType sType; - void * pNext; - VkDeviceSize robustStorageBufferAccessSizeAlignment; - VkDeviceSize robustUniformBufferAccessSizeAlignment; -} VkPhysicalDeviceRobustness2PropertiesEXT; + void * pNext; + VkBool32 cooperativeVector; + VkBool32 cooperativeVectorTraining; +} VkPhysicalDeviceCooperativeVectorFeaturesNV; -typedef struct VkPhysicalDeviceImageRobustnessFeaturesEXT { +typedef struct VkCooperativeVectorPropertiesNV { VkStructureType sType; - void * pNext; - VkBool32 robustImageAccess; -} VkPhysicalDeviceImageRobustnessFeaturesEXT; + void * pNext; + VkComponentTypeKHR inputType; + VkComponentTypeKHR inputInterpretation; + VkComponentTypeKHR matrixInterpretation; + VkComponentTypeKHR biasInterpretation; + VkComponentTypeKHR resultType; + VkBool32 transpose; +} VkCooperativeVectorPropertiesNV; -typedef struct VkPhysicalDevice4444FormatsFeaturesEXT { +typedef struct VkPhysicalDeviceCooperativeVectorPropertiesNV { + VkStructureType sType; + void * pNext; + VkShaderStageFlags cooperativeVectorSupportedStages; + VkBool32 cooperativeVectorTrainingFloat16Accumulation; + VkBool32 cooperativeVectorTrainingFloat32Accumulation; + uint32_t maxCooperativeVectorComponents; +} VkPhysicalDeviceCooperativeVectorPropertiesNV; + +typedef struct VkConvertCooperativeVectorMatrixInfoNV { + VkStructureType sType; + const void * pNext; + size_t srcSize; + VkDeviceOrHostAddressConstKHR srcData; + size_t * pDstSize; + VkDeviceOrHostAddressKHR dstData; + VkComponentTypeKHR srcComponentType; + VkComponentTypeKHR dstComponentType; + uint32_t numRows; + uint32_t numColumns; + VkCooperativeVectorMatrixLayoutNV srcLayout; + size_t srcStride; + VkCooperativeVectorMatrixLayoutNV dstLayout; + size_t dstStride; +} VkConvertCooperativeVectorMatrixInfoNV; + +typedef struct VkPhysicalDeviceTileShadingFeaturesQCOM { VkStructureType sType; void * pNext; - VkBool32 formatA4R4G4B4; - VkBool32 formatA4B4G4R4; -} VkPhysicalDevice4444FormatsFeaturesEXT; + VkBool32 tileShading; + VkBool32 tileShadingFragmentStage; + VkBool32 tileShadingColorAttachments; + VkBool32 tileShadingDepthAttachments; + VkBool32 tileShadingStencilAttachments; + VkBool32 tileShadingInputAttachments; + VkBool32 tileShadingSampledAttachments; + VkBool32 tileShadingPerTileDraw; + VkBool32 tileShadingPerTileDispatch; + VkBool32 tileShadingDispatchTile; + VkBool32 tileShadingApron; + VkBool32 tileShadingAnisotropicApron; + VkBool32 tileShadingAtomicOps; + VkBool32 tileShadingImageProcessing; +} VkPhysicalDeviceTileShadingFeaturesQCOM; + +typedef struct VkPhysicalDeviceTileShadingPropertiesQCOM { + VkStructureType sType; + void * pNext; + uint32_t maxApronSize; + VkBool32 preferNonCoherent; + VkExtent2D tileGranularity; + VkExtent2D maxTileShadingRate; +} VkPhysicalDeviceTileShadingPropertiesQCOM; + +typedef struct VkRenderPassTileShadingCreateInfoQCOM { + VkStructureType sType; + const void * pNext; + VkTileShadingRenderPassFlagsQCOM flags; + VkExtent2D tileApronSize; +} VkRenderPassTileShadingCreateInfoQCOM; + +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDevicePresentMeteringFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 presentMetering; +} VkPhysicalDevicePresentMeteringFeaturesNV; + +#endif typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData); - +typedef void (VKAPI_PTR *PFN_vkDeviceMemoryReportCallbackEXT)( + const VkDeviceMemoryReportCallbackDataEXT* pCallbackData, + void* pUserData); typedef struct VkPhysicalDeviceProperties { uint32_t apiVersion; uint32_t driverVersion; @@ -8804,12 +15827,33 @@ typedef struct VkDeviceCreateInfo { } VkDeviceCreateInfo; typedef struct VkPhysicalDeviceMemoryProperties { - uint32_t memoryTypeCount; + uint32_t memoryTypeCount; VkMemoryType memoryTypes [ VK_MAX_MEMORY_TYPES ]; - uint32_t memoryHeapCount; + uint32_t memoryHeapCount; VkMemoryHeap memoryHeaps [ VK_MAX_MEMORY_HEAPS ]; } VkPhysicalDeviceMemoryProperties; +typedef struct VkPipelineBinaryCreateInfoKHR { + VkStructureType sType; + const void * pNext; + const VkPipelineBinaryKeysAndDataKHR * pKeysAndDataInfo; + VkPipeline pipeline; + const VkPipelineCreateInfoKHR * pPipelineCreateInfo; +} VkPipelineBinaryCreateInfoKHR; + +typedef struct VkClusterAccelerationStructureCommandsInfoNV { + VkStructureType sType; + void * pNext; + VkClusterAccelerationStructureInputInfoNV input; + VkDeviceAddress dstImplicitData; + VkDeviceAddress scratchData; + VkStridedDeviceAddressRegionKHR dstAddressesArray; + VkStridedDeviceAddressRegionKHR dstSizesArray; + VkStridedDeviceAddressRegionKHR srcInfosArray; + VkDeviceAddress srcInfosCount; + VkClusterAccelerationStructureAddressResolutionFlagsNV addressResolutionFlags; +} VkClusterAccelerationStructureCommandsInfoNV; + typedef struct VkPhysicalDeviceProperties2 { VkStructureType sType; void * pNext; @@ -8833,6 +15877,12 @@ typedef struct VkPresentRegionsKHR { const VkPresentRegionKHR * pRegions; } VkPresentRegionsKHR; +typedef struct VkPhysicalDeviceLayeredApiVulkanPropertiesKHR { + VkStructureType sType; + void * pNext; + VkPhysicalDeviceProperties2 properties; +} VkPhysicalDeviceLayeredApiVulkanPropertiesKHR; + typedef struct VkDebugUtilsMessengerCreateInfoEXT { VkStructureType sType; const void * pNext; @@ -8843,6 +15893,16 @@ typedef struct VkDebugUtilsMessengerCreateInfoEXT { void * pUserData; } VkDebugUtilsMessengerCreateInfoEXT; +typedef struct VkDeviceDeviceMemoryReportCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkDeviceMemoryReportFlagsEXT flags; + PFN_vkDeviceMemoryReportCallbackEXT pfnUserCallback; + void * pUserData; +} VkDeviceDeviceMemoryReportCreateInfoEXT; + +typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV; + typedef struct VkDrmFormatModifierPropertiesListEXT { VkStructureType sType; void * pNext; @@ -8859,6 +15919,34 @@ typedef struct VkFramebufferAttachmentsCreateInfo { typedef struct VkFramebufferAttachmentsCreateInfo VkFramebufferAttachmentsCreateInfoKHR; +typedef struct VkIndirectCommandsLayoutTokenEXT { + VkStructureType sType; + const void * pNext; + VkIndirectCommandsTokenTypeEXT type; + VkIndirectCommandsTokenDataEXT data; + uint32_t offset; +} VkIndirectCommandsLayoutTokenEXT; + +typedef struct VkDrmFormatModifierPropertiesList2EXT { + VkStructureType sType; + void * pNext; + uint32_t drmFormatModifierCount; + VkDrmFormatModifierProperties2EXT * pDrmFormatModifierProperties; +} VkDrmFormatModifierPropertiesList2EXT; + +typedef struct VkPhysicalDeviceDepthClampZeroOneFeaturesKHR VkPhysicalDeviceDepthClampZeroOneFeaturesEXT; + +typedef struct VkIndirectCommandsLayoutCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkIndirectCommandsLayoutUsageFlagsEXT flags; + VkShaderStageFlags shaderStages; + uint32_t indirectStride; + VkPipelineLayout pipelineLayout; + uint32_t tokenCount; + const VkIndirectCommandsLayoutTokenEXT * pTokens; +} VkIndirectCommandsLayoutCreateInfoEXT; + #define VK_VERSION_1_0 1 @@ -8867,6 +15955,17 @@ GLAD_API_CALL int GLAD_VK_VERSION_1_0; GLAD_API_CALL int GLAD_VK_VERSION_1_1; #define VK_VERSION_1_2 1 GLAD_API_CALL int GLAD_VK_VERSION_1_2; +#define VK_VERSION_1_3 1 +GLAD_API_CALL int GLAD_VK_VERSION_1_3; +#define VK_VERSION_1_4 1 +GLAD_API_CALL int GLAD_VK_VERSION_1_4; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_AMDX_shader_enqueue 1 +GLAD_API_CALL int GLAD_VK_AMDX_shader_enqueue; + +#endif +#define VK_AMD_anti_lag 1 +GLAD_API_CALL int GLAD_VK_AMD_anti_lag; #define VK_AMD_buffer_marker 1 GLAD_API_CALL int GLAD_VK_AMD_buffer_marker; #define VK_AMD_device_coherent_memory 1 @@ -8897,6 +15996,8 @@ GLAD_API_CALL int GLAD_VK_AMD_shader_ballot; GLAD_API_CALL int GLAD_VK_AMD_shader_core_properties; #define VK_AMD_shader_core_properties2 1 GLAD_API_CALL int GLAD_VK_AMD_shader_core_properties2; +#define VK_AMD_shader_early_and_late_fragment_tests 1 +GLAD_API_CALL int GLAD_VK_AMD_shader_early_and_late_fragment_tests; #define VK_AMD_shader_explicit_vertex_parameter 1 GLAD_API_CALL int GLAD_VK_AMD_shader_explicit_vertex_parameter; #define VK_AMD_shader_fragment_mask 1 @@ -8910,23 +16011,52 @@ GLAD_API_CALL int GLAD_VK_AMD_shader_trinary_minmax; #define VK_AMD_texture_gather_bias_lod 1 GLAD_API_CALL int GLAD_VK_AMD_texture_gather_bias_lod; #if defined(VK_USE_PLATFORM_ANDROID_KHR) +#define VK_ANDROID_external_format_resolve 1 +GLAD_API_CALL int GLAD_VK_ANDROID_external_format_resolve; + +#endif +#if defined(VK_USE_PLATFORM_ANDROID_KHR) #define VK_ANDROID_external_memory_android_hardware_buffer 1 GLAD_API_CALL int GLAD_VK_ANDROID_external_memory_android_hardware_buffer; + #endif +#define VK_ARM_pipeline_opacity_micromap 1 +GLAD_API_CALL int GLAD_VK_ARM_pipeline_opacity_micromap; +#define VK_ARM_rasterization_order_attachment_access 1 +GLAD_API_CALL int GLAD_VK_ARM_rasterization_order_attachment_access; +#define VK_ARM_render_pass_striped 1 +GLAD_API_CALL int GLAD_VK_ARM_render_pass_striped; +#define VK_ARM_scheduling_controls 1 +GLAD_API_CALL int GLAD_VK_ARM_scheduling_controls; +#define VK_ARM_shader_core_builtins 1 +GLAD_API_CALL int GLAD_VK_ARM_shader_core_builtins; +#define VK_ARM_shader_core_properties 1 +GLAD_API_CALL int GLAD_VK_ARM_shader_core_properties; #define VK_EXT_4444_formats 1 GLAD_API_CALL int GLAD_VK_EXT_4444_formats; +#define VK_EXT_acquire_drm_display 1 +GLAD_API_CALL int GLAD_VK_EXT_acquire_drm_display; #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) #define VK_EXT_acquire_xlib_display 1 GLAD_API_CALL int GLAD_VK_EXT_acquire_xlib_display; + #endif #define VK_EXT_astc_decode_mode 1 GLAD_API_CALL int GLAD_VK_EXT_astc_decode_mode; +#define VK_EXT_attachment_feedback_loop_dynamic_state 1 +GLAD_API_CALL int GLAD_VK_EXT_attachment_feedback_loop_dynamic_state; +#define VK_EXT_attachment_feedback_loop_layout 1 +GLAD_API_CALL int GLAD_VK_EXT_attachment_feedback_loop_layout; #define VK_EXT_blend_operation_advanced 1 GLAD_API_CALL int GLAD_VK_EXT_blend_operation_advanced; +#define VK_EXT_border_color_swizzle 1 +GLAD_API_CALL int GLAD_VK_EXT_border_color_swizzle; #define VK_EXT_buffer_device_address 1 GLAD_API_CALL int GLAD_VK_EXT_buffer_device_address; #define VK_EXT_calibrated_timestamps 1 GLAD_API_CALL int GLAD_VK_EXT_calibrated_timestamps; +#define VK_EXT_color_write_enable 1 +GLAD_API_CALL int GLAD_VK_EXT_color_write_enable; #define VK_EXT_conditional_rendering 1 GLAD_API_CALL int GLAD_VK_EXT_conditional_rendering; #define VK_EXT_conservative_rasterization 1 @@ -8939,17 +16069,36 @@ GLAD_API_CALL int GLAD_VK_EXT_debug_marker; GLAD_API_CALL int GLAD_VK_EXT_debug_report; #define VK_EXT_debug_utils 1 GLAD_API_CALL int GLAD_VK_EXT_debug_utils; +#define VK_EXT_depth_bias_control 1 +GLAD_API_CALL int GLAD_VK_EXT_depth_bias_control; +#define VK_EXT_depth_clamp_control 1 +GLAD_API_CALL int GLAD_VK_EXT_depth_clamp_control; +#define VK_EXT_depth_clamp_zero_one 1 +GLAD_API_CALL int GLAD_VK_EXT_depth_clamp_zero_one; +#define VK_EXT_depth_clip_control 1 +GLAD_API_CALL int GLAD_VK_EXT_depth_clip_control; #define VK_EXT_depth_clip_enable 1 GLAD_API_CALL int GLAD_VK_EXT_depth_clip_enable; #define VK_EXT_depth_range_unrestricted 1 GLAD_API_CALL int GLAD_VK_EXT_depth_range_unrestricted; +#define VK_EXT_descriptor_buffer 1 +GLAD_API_CALL int GLAD_VK_EXT_descriptor_buffer; #define VK_EXT_descriptor_indexing 1 GLAD_API_CALL int GLAD_VK_EXT_descriptor_indexing; +#define VK_EXT_device_address_binding_report 1 +GLAD_API_CALL int GLAD_VK_EXT_device_address_binding_report; +#define VK_EXT_device_fault 1 +GLAD_API_CALL int GLAD_VK_EXT_device_fault; +#define VK_EXT_device_generated_commands 1 +GLAD_API_CALL int GLAD_VK_EXT_device_generated_commands; +#define VK_EXT_device_memory_report 1 +GLAD_API_CALL int GLAD_VK_EXT_device_memory_report; #define VK_EXT_direct_mode_display 1 GLAD_API_CALL int GLAD_VK_EXT_direct_mode_display; #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) #define VK_EXT_directfb_surface 1 GLAD_API_CALL int GLAD_VK_EXT_directfb_surface; + #endif #define VK_EXT_discard_rectangles 1 GLAD_API_CALL int GLAD_VK_EXT_discard_rectangles; @@ -8957,62 +16106,150 @@ GLAD_API_CALL int GLAD_VK_EXT_discard_rectangles; GLAD_API_CALL int GLAD_VK_EXT_display_control; #define VK_EXT_display_surface_counter 1 GLAD_API_CALL int GLAD_VK_EXT_display_surface_counter; +#define VK_EXT_dynamic_rendering_unused_attachments 1 +GLAD_API_CALL int GLAD_VK_EXT_dynamic_rendering_unused_attachments; #define VK_EXT_extended_dynamic_state 1 GLAD_API_CALL int GLAD_VK_EXT_extended_dynamic_state; +#define VK_EXT_extended_dynamic_state2 1 +GLAD_API_CALL int GLAD_VK_EXT_extended_dynamic_state2; +#define VK_EXT_extended_dynamic_state3 1 +GLAD_API_CALL int GLAD_VK_EXT_extended_dynamic_state3; +#define VK_EXT_external_memory_acquire_unmodified 1 +GLAD_API_CALL int GLAD_VK_EXT_external_memory_acquire_unmodified; #define VK_EXT_external_memory_dma_buf 1 GLAD_API_CALL int GLAD_VK_EXT_external_memory_dma_buf; #define VK_EXT_external_memory_host 1 GLAD_API_CALL int GLAD_VK_EXT_external_memory_host; +#if defined(VK_USE_PLATFORM_METAL_EXT) +#define VK_EXT_external_memory_metal 1 +GLAD_API_CALL int GLAD_VK_EXT_external_memory_metal; + +#endif #define VK_EXT_filter_cubic 1 GLAD_API_CALL int GLAD_VK_EXT_filter_cubic; #define VK_EXT_fragment_density_map 1 GLAD_API_CALL int GLAD_VK_EXT_fragment_density_map; #define VK_EXT_fragment_density_map2 1 GLAD_API_CALL int GLAD_VK_EXT_fragment_density_map2; +#define VK_EXT_fragment_density_map_offset 1 +GLAD_API_CALL int GLAD_VK_EXT_fragment_density_map_offset; #define VK_EXT_fragment_shader_interlock 1 GLAD_API_CALL int GLAD_VK_EXT_fragment_shader_interlock; +#define VK_EXT_frame_boundary 1 +GLAD_API_CALL int GLAD_VK_EXT_frame_boundary; #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_EXT_full_screen_exclusive 1 GLAD_API_CALL int GLAD_VK_EXT_full_screen_exclusive; + #endif #define VK_EXT_global_priority 1 GLAD_API_CALL int GLAD_VK_EXT_global_priority; +#define VK_EXT_global_priority_query 1 +GLAD_API_CALL int GLAD_VK_EXT_global_priority_query; +#define VK_EXT_graphics_pipeline_library 1 +GLAD_API_CALL int GLAD_VK_EXT_graphics_pipeline_library; #define VK_EXT_hdr_metadata 1 GLAD_API_CALL int GLAD_VK_EXT_hdr_metadata; #define VK_EXT_headless_surface 1 GLAD_API_CALL int GLAD_VK_EXT_headless_surface; +#define VK_EXT_host_image_copy 1 +GLAD_API_CALL int GLAD_VK_EXT_host_image_copy; #define VK_EXT_host_query_reset 1 GLAD_API_CALL int GLAD_VK_EXT_host_query_reset; +#define VK_EXT_image_2d_view_of_3d 1 +GLAD_API_CALL int GLAD_VK_EXT_image_2d_view_of_3d; +#define VK_EXT_image_compression_control 1 +GLAD_API_CALL int GLAD_VK_EXT_image_compression_control; +#define VK_EXT_image_compression_control_swapchain 1 +GLAD_API_CALL int GLAD_VK_EXT_image_compression_control_swapchain; #define VK_EXT_image_drm_format_modifier 1 GLAD_API_CALL int GLAD_VK_EXT_image_drm_format_modifier; #define VK_EXT_image_robustness 1 GLAD_API_CALL int GLAD_VK_EXT_image_robustness; +#define VK_EXT_image_sliced_view_of_3d 1 +GLAD_API_CALL int GLAD_VK_EXT_image_sliced_view_of_3d; +#define VK_EXT_image_view_min_lod 1 +GLAD_API_CALL int GLAD_VK_EXT_image_view_min_lod; #define VK_EXT_index_type_uint8 1 GLAD_API_CALL int GLAD_VK_EXT_index_type_uint8; #define VK_EXT_inline_uniform_block 1 GLAD_API_CALL int GLAD_VK_EXT_inline_uniform_block; +#define VK_EXT_layer_settings 1 +GLAD_API_CALL int GLAD_VK_EXT_layer_settings; +#define VK_EXT_legacy_dithering 1 +GLAD_API_CALL int GLAD_VK_EXT_legacy_dithering; +#define VK_EXT_legacy_vertex_attributes 1 +GLAD_API_CALL int GLAD_VK_EXT_legacy_vertex_attributes; #define VK_EXT_line_rasterization 1 GLAD_API_CALL int GLAD_VK_EXT_line_rasterization; +#define VK_EXT_load_store_op_none 1 +GLAD_API_CALL int GLAD_VK_EXT_load_store_op_none; +#define VK_EXT_map_memory_placed 1 +GLAD_API_CALL int GLAD_VK_EXT_map_memory_placed; #define VK_EXT_memory_budget 1 GLAD_API_CALL int GLAD_VK_EXT_memory_budget; #define VK_EXT_memory_priority 1 GLAD_API_CALL int GLAD_VK_EXT_memory_priority; +#define VK_EXT_mesh_shader 1 +GLAD_API_CALL int GLAD_VK_EXT_mesh_shader; +#if defined(VK_USE_PLATFORM_METAL_EXT) +#define VK_EXT_metal_objects 1 +GLAD_API_CALL int GLAD_VK_EXT_metal_objects; + +#endif #if defined(VK_USE_PLATFORM_METAL_EXT) #define VK_EXT_metal_surface 1 GLAD_API_CALL int GLAD_VK_EXT_metal_surface; + #endif +#define VK_EXT_multi_draw 1 +GLAD_API_CALL int GLAD_VK_EXT_multi_draw; +#define VK_EXT_multisampled_render_to_single_sampled 1 +GLAD_API_CALL int GLAD_VK_EXT_multisampled_render_to_single_sampled; +#define VK_EXT_mutable_descriptor_type 1 +GLAD_API_CALL int GLAD_VK_EXT_mutable_descriptor_type; +#define VK_EXT_nested_command_buffer 1 +GLAD_API_CALL int GLAD_VK_EXT_nested_command_buffer; +#define VK_EXT_non_seamless_cube_map 1 +GLAD_API_CALL int GLAD_VK_EXT_non_seamless_cube_map; +#define VK_EXT_opacity_micromap 1 +GLAD_API_CALL int GLAD_VK_EXT_opacity_micromap; +#define VK_EXT_pageable_device_local_memory 1 +GLAD_API_CALL int GLAD_VK_EXT_pageable_device_local_memory; #define VK_EXT_pci_bus_info 1 GLAD_API_CALL int GLAD_VK_EXT_pci_bus_info; +#define VK_EXT_physical_device_drm 1 +GLAD_API_CALL int GLAD_VK_EXT_physical_device_drm; #define VK_EXT_pipeline_creation_cache_control 1 GLAD_API_CALL int GLAD_VK_EXT_pipeline_creation_cache_control; #define VK_EXT_pipeline_creation_feedback 1 GLAD_API_CALL int GLAD_VK_EXT_pipeline_creation_feedback; +#define VK_EXT_pipeline_library_group_handles 1 +GLAD_API_CALL int GLAD_VK_EXT_pipeline_library_group_handles; +#define VK_EXT_pipeline_properties 1 +GLAD_API_CALL int GLAD_VK_EXT_pipeline_properties; +#define VK_EXT_pipeline_protected_access 1 +GLAD_API_CALL int GLAD_VK_EXT_pipeline_protected_access; +#define VK_EXT_pipeline_robustness 1 +GLAD_API_CALL int GLAD_VK_EXT_pipeline_robustness; #define VK_EXT_post_depth_coverage 1 GLAD_API_CALL int GLAD_VK_EXT_post_depth_coverage; +#define VK_EXT_present_mode_fifo_latest_ready 1 +GLAD_API_CALL int GLAD_VK_EXT_present_mode_fifo_latest_ready; +#define VK_EXT_primitive_topology_list_restart 1 +GLAD_API_CALL int GLAD_VK_EXT_primitive_topology_list_restart; +#define VK_EXT_primitives_generated_query 1 +GLAD_API_CALL int GLAD_VK_EXT_primitives_generated_query; #define VK_EXT_private_data 1 GLAD_API_CALL int GLAD_VK_EXT_private_data; +#define VK_EXT_provoking_vertex 1 +GLAD_API_CALL int GLAD_VK_EXT_provoking_vertex; #define VK_EXT_queue_family_foreign 1 GLAD_API_CALL int GLAD_VK_EXT_queue_family_foreign; +#define VK_EXT_rasterization_order_attachment_access 1 +GLAD_API_CALL int GLAD_VK_EXT_rasterization_order_attachment_access; +#define VK_EXT_rgba10x6_formats 1 +GLAD_API_CALL int GLAD_VK_EXT_rgba10x6_formats; #define VK_EXT_robustness2 1 GLAD_API_CALL int GLAD_VK_EXT_robustness2; #define VK_EXT_sample_locations 1 @@ -9025,20 +16262,38 @@ GLAD_API_CALL int GLAD_VK_EXT_scalar_block_layout; GLAD_API_CALL int GLAD_VK_EXT_separate_stencil_usage; #define VK_EXT_shader_atomic_float 1 GLAD_API_CALL int GLAD_VK_EXT_shader_atomic_float; +#define VK_EXT_shader_atomic_float2 1 +GLAD_API_CALL int GLAD_VK_EXT_shader_atomic_float2; #define VK_EXT_shader_demote_to_helper_invocation 1 GLAD_API_CALL int GLAD_VK_EXT_shader_demote_to_helper_invocation; +#define VK_EXT_shader_image_atomic_int64 1 +GLAD_API_CALL int GLAD_VK_EXT_shader_image_atomic_int64; +#define VK_EXT_shader_module_identifier 1 +GLAD_API_CALL int GLAD_VK_EXT_shader_module_identifier; +#define VK_EXT_shader_object 1 +GLAD_API_CALL int GLAD_VK_EXT_shader_object; +#define VK_EXT_shader_replicated_composites 1 +GLAD_API_CALL int GLAD_VK_EXT_shader_replicated_composites; #define VK_EXT_shader_stencil_export 1 GLAD_API_CALL int GLAD_VK_EXT_shader_stencil_export; #define VK_EXT_shader_subgroup_ballot 1 GLAD_API_CALL int GLAD_VK_EXT_shader_subgroup_ballot; #define VK_EXT_shader_subgroup_vote 1 GLAD_API_CALL int GLAD_VK_EXT_shader_subgroup_vote; +#define VK_EXT_shader_tile_image 1 +GLAD_API_CALL int GLAD_VK_EXT_shader_tile_image; #define VK_EXT_shader_viewport_index_layer 1 GLAD_API_CALL int GLAD_VK_EXT_shader_viewport_index_layer; #define VK_EXT_subgroup_size_control 1 GLAD_API_CALL int GLAD_VK_EXT_subgroup_size_control; +#define VK_EXT_subpass_merge_feedback 1 +GLAD_API_CALL int GLAD_VK_EXT_subpass_merge_feedback; +#define VK_EXT_surface_maintenance1 1 +GLAD_API_CALL int GLAD_VK_EXT_surface_maintenance1; #define VK_EXT_swapchain_colorspace 1 GLAD_API_CALL int GLAD_VK_EXT_swapchain_colorspace; +#define VK_EXT_swapchain_maintenance1 1 +GLAD_API_CALL int GLAD_VK_EXT_swapchain_maintenance1; #define VK_EXT_texel_buffer_alignment 1 GLAD_API_CALL int GLAD_VK_EXT_texel_buffer_alignment; #define VK_EXT_texture_compression_astc_hdr 1 @@ -9055,19 +16310,43 @@ GLAD_API_CALL int GLAD_VK_EXT_validation_features; GLAD_API_CALL int GLAD_VK_EXT_validation_flags; #define VK_EXT_vertex_attribute_divisor 1 GLAD_API_CALL int GLAD_VK_EXT_vertex_attribute_divisor; +#define VK_EXT_vertex_attribute_robustness 1 +GLAD_API_CALL int GLAD_VK_EXT_vertex_attribute_robustness; +#define VK_EXT_vertex_input_dynamic_state 1 +GLAD_API_CALL int GLAD_VK_EXT_vertex_input_dynamic_state; +#define VK_EXT_ycbcr_2plane_444_formats 1 +GLAD_API_CALL int GLAD_VK_EXT_ycbcr_2plane_444_formats; #define VK_EXT_ycbcr_image_arrays 1 GLAD_API_CALL int GLAD_VK_EXT_ycbcr_image_arrays; #if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_buffer_collection 1 +GLAD_API_CALL int GLAD_VK_FUCHSIA_buffer_collection; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_external_memory 1 +GLAD_API_CALL int GLAD_VK_FUCHSIA_external_memory; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_external_semaphore 1 +GLAD_API_CALL int GLAD_VK_FUCHSIA_external_semaphore; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) #define VK_FUCHSIA_imagepipe_surface 1 GLAD_API_CALL int GLAD_VK_FUCHSIA_imagepipe_surface; + #endif #if defined(VK_USE_PLATFORM_GGP) #define VK_GGP_frame_token 1 GLAD_API_CALL int GLAD_VK_GGP_frame_token; + #endif #if defined(VK_USE_PLATFORM_GGP) #define VK_GGP_stream_descriptor_surface 1 GLAD_API_CALL int GLAD_VK_GGP_stream_descriptor_surface; + #endif #define VK_GOOGLE_decorate_string 1 GLAD_API_CALL int GLAD_VK_GOOGLE_decorate_string; @@ -9075,12 +16354,24 @@ GLAD_API_CALL int GLAD_VK_GOOGLE_decorate_string; GLAD_API_CALL int GLAD_VK_GOOGLE_display_timing; #define VK_GOOGLE_hlsl_functionality1 1 GLAD_API_CALL int GLAD_VK_GOOGLE_hlsl_functionality1; +#define VK_GOOGLE_surfaceless_query 1 +GLAD_API_CALL int GLAD_VK_GOOGLE_surfaceless_query; #define VK_GOOGLE_user_type 1 GLAD_API_CALL int GLAD_VK_GOOGLE_user_type; +#define VK_HUAWEI_cluster_culling_shader 1 +GLAD_API_CALL int GLAD_VK_HUAWEI_cluster_culling_shader; +#define VK_HUAWEI_hdr_vivid 1 +GLAD_API_CALL int GLAD_VK_HUAWEI_hdr_vivid; +#define VK_HUAWEI_invocation_mask 1 +GLAD_API_CALL int GLAD_VK_HUAWEI_invocation_mask; +#define VK_HUAWEI_subpass_shading 1 +GLAD_API_CALL int GLAD_VK_HUAWEI_subpass_shading; #define VK_IMG_filter_cubic 1 GLAD_API_CALL int GLAD_VK_IMG_filter_cubic; #define VK_IMG_format_pvrtc 1 GLAD_API_CALL int GLAD_VK_IMG_format_pvrtc; +#define VK_IMG_relaxed_line_rasterization 1 +GLAD_API_CALL int GLAD_VK_IMG_relaxed_line_rasterization; #define VK_INTEL_performance_query 1 GLAD_API_CALL int GLAD_VK_INTEL_performance_query; #define VK_INTEL_shader_integer_functions2 1 @@ -9089,22 +16380,33 @@ GLAD_API_CALL int GLAD_VK_INTEL_shader_integer_functions2; GLAD_API_CALL int GLAD_VK_KHR_16bit_storage; #define VK_KHR_8bit_storage 1 GLAD_API_CALL int GLAD_VK_KHR_8bit_storage; +#define VK_KHR_acceleration_structure 1 +GLAD_API_CALL int GLAD_VK_KHR_acceleration_structure; #if defined(VK_USE_PLATFORM_ANDROID_KHR) #define VK_KHR_android_surface 1 GLAD_API_CALL int GLAD_VK_KHR_android_surface; + #endif #define VK_KHR_bind_memory2 1 GLAD_API_CALL int GLAD_VK_KHR_bind_memory2; #define VK_KHR_buffer_device_address 1 GLAD_API_CALL int GLAD_VK_KHR_buffer_device_address; +#define VK_KHR_calibrated_timestamps 1 +GLAD_API_CALL int GLAD_VK_KHR_calibrated_timestamps; +#define VK_KHR_compute_shader_derivatives 1 +GLAD_API_CALL int GLAD_VK_KHR_compute_shader_derivatives; +#define VK_KHR_cooperative_matrix 1 +GLAD_API_CALL int GLAD_VK_KHR_cooperative_matrix; +#define VK_KHR_copy_commands2 1 +GLAD_API_CALL int GLAD_VK_KHR_copy_commands2; #define VK_KHR_create_renderpass2 1 GLAD_API_CALL int GLAD_VK_KHR_create_renderpass2; #define VK_KHR_dedicated_allocation 1 GLAD_API_CALL int GLAD_VK_KHR_dedicated_allocation; -#if defined(VK_ENABLE_BETA_EXTENSIONS) #define VK_KHR_deferred_host_operations 1 GLAD_API_CALL int GLAD_VK_KHR_deferred_host_operations; -#endif +#define VK_KHR_depth_clamp_zero_one 1 +GLAD_API_CALL int GLAD_VK_KHR_depth_clamp_zero_one; #define VK_KHR_depth_stencil_resolve 1 GLAD_API_CALL int GLAD_VK_KHR_depth_stencil_resolve; #define VK_KHR_descriptor_update_template 1 @@ -9121,6 +16423,10 @@ GLAD_API_CALL int GLAD_VK_KHR_display_swapchain; GLAD_API_CALL int GLAD_VK_KHR_draw_indirect_count; #define VK_KHR_driver_properties 1 GLAD_API_CALL int GLAD_VK_KHR_driver_properties; +#define VK_KHR_dynamic_rendering 1 +GLAD_API_CALL int GLAD_VK_KHR_dynamic_rendering; +#define VK_KHR_dynamic_rendering_local_read 1 +GLAD_API_CALL int GLAD_VK_KHR_dynamic_rendering_local_read; #define VK_KHR_external_fence 1 GLAD_API_CALL int GLAD_VK_KHR_external_fence; #define VK_KHR_external_fence_capabilities 1 @@ -9130,6 +16436,7 @@ GLAD_API_CALL int GLAD_VK_KHR_external_fence_fd; #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_external_fence_win32 1 GLAD_API_CALL int GLAD_VK_KHR_external_fence_win32; + #endif #define VK_KHR_external_memory 1 GLAD_API_CALL int GLAD_VK_KHR_external_memory; @@ -9140,6 +16447,7 @@ GLAD_API_CALL int GLAD_VK_KHR_external_memory_fd; #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_external_memory_win32 1 GLAD_API_CALL int GLAD_VK_KHR_external_memory_win32; + #endif #define VK_KHR_external_semaphore 1 GLAD_API_CALL int GLAD_VK_KHR_external_semaphore; @@ -9150,7 +16458,14 @@ GLAD_API_CALL int GLAD_VK_KHR_external_semaphore_fd; #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_external_semaphore_win32 1 GLAD_API_CALL int GLAD_VK_KHR_external_semaphore_win32; + #endif +#define VK_KHR_format_feature_flags2 1 +GLAD_API_CALL int GLAD_VK_KHR_format_feature_flags2; +#define VK_KHR_fragment_shader_barycentric 1 +GLAD_API_CALL int GLAD_VK_KHR_fragment_shader_barycentric; +#define VK_KHR_fragment_shading_rate 1 +GLAD_API_CALL int GLAD_VK_KHR_fragment_shading_rate; #define VK_KHR_get_display_properties2 1 GLAD_API_CALL int GLAD_VK_KHR_get_display_properties2; #define VK_KHR_get_memory_requirements2 1 @@ -9159,36 +16474,73 @@ GLAD_API_CALL int GLAD_VK_KHR_get_memory_requirements2; GLAD_API_CALL int GLAD_VK_KHR_get_physical_device_properties2; #define VK_KHR_get_surface_capabilities2 1 GLAD_API_CALL int GLAD_VK_KHR_get_surface_capabilities2; +#define VK_KHR_global_priority 1 +GLAD_API_CALL int GLAD_VK_KHR_global_priority; #define VK_KHR_image_format_list 1 GLAD_API_CALL int GLAD_VK_KHR_image_format_list; #define VK_KHR_imageless_framebuffer 1 GLAD_API_CALL int GLAD_VK_KHR_imageless_framebuffer; #define VK_KHR_incremental_present 1 GLAD_API_CALL int GLAD_VK_KHR_incremental_present; +#define VK_KHR_index_type_uint8 1 +GLAD_API_CALL int GLAD_VK_KHR_index_type_uint8; +#define VK_KHR_line_rasterization 1 +GLAD_API_CALL int GLAD_VK_KHR_line_rasterization; +#define VK_KHR_load_store_op_none 1 +GLAD_API_CALL int GLAD_VK_KHR_load_store_op_none; #define VK_KHR_maintenance1 1 GLAD_API_CALL int GLAD_VK_KHR_maintenance1; #define VK_KHR_maintenance2 1 GLAD_API_CALL int GLAD_VK_KHR_maintenance2; #define VK_KHR_maintenance3 1 GLAD_API_CALL int GLAD_VK_KHR_maintenance3; +#define VK_KHR_maintenance4 1 +GLAD_API_CALL int GLAD_VK_KHR_maintenance4; +#define VK_KHR_maintenance5 1 +GLAD_API_CALL int GLAD_VK_KHR_maintenance5; +#define VK_KHR_maintenance6 1 +GLAD_API_CALL int GLAD_VK_KHR_maintenance6; +#define VK_KHR_maintenance7 1 +GLAD_API_CALL int GLAD_VK_KHR_maintenance7; +#define VK_KHR_maintenance8 1 +GLAD_API_CALL int GLAD_VK_KHR_maintenance8; +#define VK_KHR_map_memory2 1 +GLAD_API_CALL int GLAD_VK_KHR_map_memory2; #define VK_KHR_multiview 1 GLAD_API_CALL int GLAD_VK_KHR_multiview; #define VK_KHR_performance_query 1 GLAD_API_CALL int GLAD_VK_KHR_performance_query; +#define VK_KHR_pipeline_binary 1 +GLAD_API_CALL int GLAD_VK_KHR_pipeline_binary; #define VK_KHR_pipeline_executable_properties 1 GLAD_API_CALL int GLAD_VK_KHR_pipeline_executable_properties; -#if defined(VK_ENABLE_BETA_EXTENSIONS) #define VK_KHR_pipeline_library 1 GLAD_API_CALL int GLAD_VK_KHR_pipeline_library; +#define VK_KHR_portability_enumeration 1 +GLAD_API_CALL int GLAD_VK_KHR_portability_enumeration; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_KHR_portability_subset 1 +GLAD_API_CALL int GLAD_VK_KHR_portability_subset; + #endif +#define VK_KHR_present_id 1 +GLAD_API_CALL int GLAD_VK_KHR_present_id; +#define VK_KHR_present_wait 1 +GLAD_API_CALL int GLAD_VK_KHR_present_wait; #define VK_KHR_push_descriptor 1 GLAD_API_CALL int GLAD_VK_KHR_push_descriptor; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -#define VK_KHR_ray_tracing 1 -GLAD_API_CALL int GLAD_VK_KHR_ray_tracing; -#endif +#define VK_KHR_ray_query 1 +GLAD_API_CALL int GLAD_VK_KHR_ray_query; +#define VK_KHR_ray_tracing_maintenance1 1 +GLAD_API_CALL int GLAD_VK_KHR_ray_tracing_maintenance1; +#define VK_KHR_ray_tracing_pipeline 1 +GLAD_API_CALL int GLAD_VK_KHR_ray_tracing_pipeline; +#define VK_KHR_ray_tracing_position_fetch 1 +GLAD_API_CALL int GLAD_VK_KHR_ray_tracing_position_fetch; #define VK_KHR_relaxed_block_layout 1 GLAD_API_CALL int GLAD_VK_KHR_relaxed_block_layout; +#define VK_KHR_robustness2 1 +GLAD_API_CALL int GLAD_VK_KHR_robustness2; #define VK_KHR_sampler_mirror_clamp_to_edge 1 GLAD_API_CALL int GLAD_VK_KHR_sampler_mirror_clamp_to_edge; #define VK_KHR_sampler_ycbcr_conversion 1 @@ -9197,18 +16549,38 @@ GLAD_API_CALL int GLAD_VK_KHR_sampler_ycbcr_conversion; GLAD_API_CALL int GLAD_VK_KHR_separate_depth_stencil_layouts; #define VK_KHR_shader_atomic_int64 1 GLAD_API_CALL int GLAD_VK_KHR_shader_atomic_int64; +#define VK_KHR_shader_bfloat16 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_bfloat16; #define VK_KHR_shader_clock 1 GLAD_API_CALL int GLAD_VK_KHR_shader_clock; #define VK_KHR_shader_draw_parameters 1 GLAD_API_CALL int GLAD_VK_KHR_shader_draw_parameters; +#define VK_KHR_shader_expect_assume 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_expect_assume; #define VK_KHR_shader_float16_int8 1 GLAD_API_CALL int GLAD_VK_KHR_shader_float16_int8; #define VK_KHR_shader_float_controls 1 GLAD_API_CALL int GLAD_VK_KHR_shader_float_controls; +#define VK_KHR_shader_float_controls2 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_float_controls2; +#define VK_KHR_shader_integer_dot_product 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_integer_dot_product; +#define VK_KHR_shader_maximal_reconvergence 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_maximal_reconvergence; #define VK_KHR_shader_non_semantic_info 1 GLAD_API_CALL int GLAD_VK_KHR_shader_non_semantic_info; +#define VK_KHR_shader_quad_control 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_quad_control; +#define VK_KHR_shader_relaxed_extended_instruction 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_relaxed_extended_instruction; #define VK_KHR_shader_subgroup_extended_types 1 GLAD_API_CALL int GLAD_VK_KHR_shader_subgroup_extended_types; +#define VK_KHR_shader_subgroup_rotate 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_subgroup_rotate; +#define VK_KHR_shader_subgroup_uniform_control_flow 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_subgroup_uniform_control_flow; +#define VK_KHR_shader_terminate_invocation 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_terminate_invocation; #define VK_KHR_shared_presentable_image 1 GLAD_API_CALL int GLAD_VK_KHR_shared_presentable_image; #define VK_KHR_spirv_1_4 1 @@ -9223,77 +16595,139 @@ GLAD_API_CALL int GLAD_VK_KHR_surface_protected_capabilities; GLAD_API_CALL int GLAD_VK_KHR_swapchain; #define VK_KHR_swapchain_mutable_format 1 GLAD_API_CALL int GLAD_VK_KHR_swapchain_mutable_format; +#define VK_KHR_synchronization2 1 +GLAD_API_CALL int GLAD_VK_KHR_synchronization2; #define VK_KHR_timeline_semaphore 1 GLAD_API_CALL int GLAD_VK_KHR_timeline_semaphore; #define VK_KHR_uniform_buffer_standard_layout 1 GLAD_API_CALL int GLAD_VK_KHR_uniform_buffer_standard_layout; #define VK_KHR_variable_pointers 1 GLAD_API_CALL int GLAD_VK_KHR_variable_pointers; +#define VK_KHR_vertex_attribute_divisor 1 +GLAD_API_CALL int GLAD_VK_KHR_vertex_attribute_divisor; #define VK_KHR_vulkan_memory_model 1 GLAD_API_CALL int GLAD_VK_KHR_vulkan_memory_model; #if defined(VK_USE_PLATFORM_WAYLAND_KHR) #define VK_KHR_wayland_surface 1 GLAD_API_CALL int GLAD_VK_KHR_wayland_surface; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_win32_keyed_mutex 1 GLAD_API_CALL int GLAD_VK_KHR_win32_keyed_mutex; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_win32_surface 1 GLAD_API_CALL int GLAD_VK_KHR_win32_surface; + #endif +#define VK_KHR_workgroup_memory_explicit_layout 1 +GLAD_API_CALL int GLAD_VK_KHR_workgroup_memory_explicit_layout; #if defined(VK_USE_PLATFORM_XCB_KHR) #define VK_KHR_xcb_surface 1 GLAD_API_CALL int GLAD_VK_KHR_xcb_surface; + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) #define VK_KHR_xlib_surface 1 GLAD_API_CALL int GLAD_VK_KHR_xlib_surface; + #endif +#define VK_KHR_zero_initialize_workgroup_memory 1 +GLAD_API_CALL int GLAD_VK_KHR_zero_initialize_workgroup_memory; +#define VK_LUNARG_direct_driver_loading 1 +GLAD_API_CALL int GLAD_VK_LUNARG_direct_driver_loading; +#define VK_MESA_image_alignment_control 1 +GLAD_API_CALL int GLAD_VK_MESA_image_alignment_control; +#define VK_MSFT_layered_driver 1 +GLAD_API_CALL int GLAD_VK_MSFT_layered_driver; #if defined(VK_USE_PLATFORM_IOS_MVK) #define VK_MVK_ios_surface 1 GLAD_API_CALL int GLAD_VK_MVK_ios_surface; + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) #define VK_MVK_macos_surface 1 GLAD_API_CALL int GLAD_VK_MVK_macos_surface; + #endif #if defined(VK_USE_PLATFORM_VI_NN) #define VK_NN_vi_surface 1 GLAD_API_CALL int GLAD_VK_NN_vi_surface; + #endif +#define VK_NVX_binary_import 1 +GLAD_API_CALL int GLAD_VK_NVX_binary_import; #define VK_NVX_image_view_handle 1 GLAD_API_CALL int GLAD_VK_NVX_image_view_handle; #define VK_NVX_multiview_per_view_attributes 1 GLAD_API_CALL int GLAD_VK_NVX_multiview_per_view_attributes; +#if defined(VK_USE_PLATFORM_WIN32_KHR) +#define VK_NV_acquire_winrt_display 1 +GLAD_API_CALL int GLAD_VK_NV_acquire_winrt_display; + +#endif #define VK_NV_clip_space_w_scaling 1 GLAD_API_CALL int GLAD_VK_NV_clip_space_w_scaling; +#define VK_NV_cluster_acceleration_structure 1 +GLAD_API_CALL int GLAD_VK_NV_cluster_acceleration_structure; +#define VK_NV_command_buffer_inheritance 1 +GLAD_API_CALL int GLAD_VK_NV_command_buffer_inheritance; #define VK_NV_compute_shader_derivatives 1 GLAD_API_CALL int GLAD_VK_NV_compute_shader_derivatives; #define VK_NV_cooperative_matrix 1 GLAD_API_CALL int GLAD_VK_NV_cooperative_matrix; +#define VK_NV_cooperative_matrix2 1 +GLAD_API_CALL int GLAD_VK_NV_cooperative_matrix2; +#define VK_NV_cooperative_vector 1 +GLAD_API_CALL int GLAD_VK_NV_cooperative_vector; +#define VK_NV_copy_memory_indirect 1 +GLAD_API_CALL int GLAD_VK_NV_copy_memory_indirect; #define VK_NV_corner_sampled_image 1 GLAD_API_CALL int GLAD_VK_NV_corner_sampled_image; #define VK_NV_coverage_reduction_mode 1 GLAD_API_CALL int GLAD_VK_NV_coverage_reduction_mode; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_cuda_kernel_launch 1 +GLAD_API_CALL int GLAD_VK_NV_cuda_kernel_launch; + +#endif #define VK_NV_dedicated_allocation 1 GLAD_API_CALL int GLAD_VK_NV_dedicated_allocation; #define VK_NV_dedicated_allocation_image_aliasing 1 GLAD_API_CALL int GLAD_VK_NV_dedicated_allocation_image_aliasing; +#define VK_NV_descriptor_pool_overallocation 1 +GLAD_API_CALL int GLAD_VK_NV_descriptor_pool_overallocation; #define VK_NV_device_diagnostic_checkpoints 1 GLAD_API_CALL int GLAD_VK_NV_device_diagnostic_checkpoints; #define VK_NV_device_diagnostics_config 1 GLAD_API_CALL int GLAD_VK_NV_device_diagnostics_config; #define VK_NV_device_generated_commands 1 GLAD_API_CALL int GLAD_VK_NV_device_generated_commands; +#define VK_NV_device_generated_commands_compute 1 +GLAD_API_CALL int GLAD_VK_NV_device_generated_commands_compute; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_displacement_micromap 1 +GLAD_API_CALL int GLAD_VK_NV_displacement_micromap; + +#endif +#define VK_NV_display_stereo 1 +GLAD_API_CALL int GLAD_VK_NV_display_stereo; +#define VK_NV_extended_sparse_address_space 1 +GLAD_API_CALL int GLAD_VK_NV_extended_sparse_address_space; +#define VK_NV_external_compute_queue 1 +GLAD_API_CALL int GLAD_VK_NV_external_compute_queue; #define VK_NV_external_memory 1 GLAD_API_CALL int GLAD_VK_NV_external_memory; #define VK_NV_external_memory_capabilities 1 GLAD_API_CALL int GLAD_VK_NV_external_memory_capabilities; +#define VK_NV_external_memory_rdma 1 +GLAD_API_CALL int GLAD_VK_NV_external_memory_rdma; #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_NV_external_memory_win32 1 GLAD_API_CALL int GLAD_VK_NV_external_memory_win32; + #endif #define VK_NV_fill_rectangle 1 GLAD_API_CALL int GLAD_VK_NV_fill_rectangle; @@ -9301,22 +16735,59 @@ GLAD_API_CALL int GLAD_VK_NV_fill_rectangle; GLAD_API_CALL int GLAD_VK_NV_fragment_coverage_to_color; #define VK_NV_fragment_shader_barycentric 1 GLAD_API_CALL int GLAD_VK_NV_fragment_shader_barycentric; +#define VK_NV_fragment_shading_rate_enums 1 +GLAD_API_CALL int GLAD_VK_NV_fragment_shading_rate_enums; #define VK_NV_framebuffer_mixed_samples 1 GLAD_API_CALL int GLAD_VK_NV_framebuffer_mixed_samples; #define VK_NV_geometry_shader_passthrough 1 GLAD_API_CALL int GLAD_VK_NV_geometry_shader_passthrough; #define VK_NV_glsl_shader 1 GLAD_API_CALL int GLAD_VK_NV_glsl_shader; +#define VK_NV_inherited_viewport_scissor 1 +GLAD_API_CALL int GLAD_VK_NV_inherited_viewport_scissor; +#define VK_NV_linear_color_attachment 1 +GLAD_API_CALL int GLAD_VK_NV_linear_color_attachment; +#define VK_NV_low_latency 1 +GLAD_API_CALL int GLAD_VK_NV_low_latency; +#define VK_NV_low_latency2 1 +GLAD_API_CALL int GLAD_VK_NV_low_latency2; +#define VK_NV_memory_decompression 1 +GLAD_API_CALL int GLAD_VK_NV_memory_decompression; #define VK_NV_mesh_shader 1 GLAD_API_CALL int GLAD_VK_NV_mesh_shader; +#define VK_NV_optical_flow 1 +GLAD_API_CALL int GLAD_VK_NV_optical_flow; +#define VK_NV_partitioned_acceleration_structure 1 +GLAD_API_CALL int GLAD_VK_NV_partitioned_acceleration_structure; +#define VK_NV_per_stage_descriptor_set 1 +GLAD_API_CALL int GLAD_VK_NV_per_stage_descriptor_set; +#define VK_NV_present_barrier 1 +GLAD_API_CALL int GLAD_VK_NV_present_barrier; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_present_metering 1 +GLAD_API_CALL int GLAD_VK_NV_present_metering; + +#endif +#define VK_NV_raw_access_chains 1 +GLAD_API_CALL int GLAD_VK_NV_raw_access_chains; #define VK_NV_ray_tracing 1 GLAD_API_CALL int GLAD_VK_NV_ray_tracing; +#define VK_NV_ray_tracing_invocation_reorder 1 +GLAD_API_CALL int GLAD_VK_NV_ray_tracing_invocation_reorder; +#define VK_NV_ray_tracing_linear_swept_spheres 1 +GLAD_API_CALL int GLAD_VK_NV_ray_tracing_linear_swept_spheres; +#define VK_NV_ray_tracing_motion_blur 1 +GLAD_API_CALL int GLAD_VK_NV_ray_tracing_motion_blur; +#define VK_NV_ray_tracing_validation 1 +GLAD_API_CALL int GLAD_VK_NV_ray_tracing_validation; #define VK_NV_representative_fragment_test 1 GLAD_API_CALL int GLAD_VK_NV_representative_fragment_test; #define VK_NV_sample_mask_override_coverage 1 GLAD_API_CALL int GLAD_VK_NV_sample_mask_override_coverage; #define VK_NV_scissor_exclusive 1 GLAD_API_CALL int GLAD_VK_NV_scissor_exclusive; +#define VK_NV_shader_atomic_float16_vector 1 +GLAD_API_CALL int GLAD_VK_NV_shader_atomic_float16_vector; #define VK_NV_shader_image_footprint 1 GLAD_API_CALL int GLAD_VK_NV_shader_image_footprint; #define VK_NV_shader_sm_builtins 1 @@ -9332,92 +16803,183 @@ GLAD_API_CALL int GLAD_VK_NV_viewport_swizzle; #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_NV_win32_keyed_mutex 1 GLAD_API_CALL int GLAD_VK_NV_win32_keyed_mutex; + #endif +#define VK_QCOM_filter_cubic_clamp 1 +GLAD_API_CALL int GLAD_VK_QCOM_filter_cubic_clamp; +#define VK_QCOM_filter_cubic_weights 1 +GLAD_API_CALL int GLAD_VK_QCOM_filter_cubic_weights; +#define VK_QCOM_fragment_density_map_offset 1 +GLAD_API_CALL int GLAD_VK_QCOM_fragment_density_map_offset; +#define VK_QCOM_image_processing 1 +GLAD_API_CALL int GLAD_VK_QCOM_image_processing; +#define VK_QCOM_image_processing2 1 +GLAD_API_CALL int GLAD_VK_QCOM_image_processing2; +#define VK_QCOM_multiview_per_view_render_areas 1 +GLAD_API_CALL int GLAD_VK_QCOM_multiview_per_view_render_areas; +#define VK_QCOM_multiview_per_view_viewports 1 +GLAD_API_CALL int GLAD_VK_QCOM_multiview_per_view_viewports; #define VK_QCOM_render_pass_shader_resolve 1 GLAD_API_CALL int GLAD_VK_QCOM_render_pass_shader_resolve; #define VK_QCOM_render_pass_store_ops 1 GLAD_API_CALL int GLAD_VK_QCOM_render_pass_store_ops; #define VK_QCOM_render_pass_transform 1 GLAD_API_CALL int GLAD_VK_QCOM_render_pass_transform; - - +#define VK_QCOM_rotated_copy_commands 1 +GLAD_API_CALL int GLAD_VK_QCOM_rotated_copy_commands; +#define VK_QCOM_tile_memory_heap 1 +GLAD_API_CALL int GLAD_VK_QCOM_tile_memory_heap; +#define VK_QCOM_tile_properties 1 +GLAD_API_CALL int GLAD_VK_QCOM_tile_properties; +#define VK_QCOM_tile_shading 1 +GLAD_API_CALL int GLAD_VK_QCOM_tile_shading; +#define VK_QCOM_ycbcr_degamma 1 +GLAD_API_CALL int GLAD_VK_QCOM_ycbcr_degamma; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +#define VK_QNX_external_memory_screen_buffer 1 +GLAD_API_CALL int GLAD_VK_QNX_external_memory_screen_buffer; + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +#define VK_QNX_screen_surface 1 +GLAD_API_CALL int GLAD_VK_QNX_screen_surface; + +#endif +#define VK_SEC_amigo_profiling 1 +GLAD_API_CALL int GLAD_VK_SEC_amigo_profiling; +#define VK_VALVE_descriptor_set_host_mapping 1 +GLAD_API_CALL int GLAD_VK_VALVE_descriptor_set_host_mapping; +#define VK_VALVE_mutable_descriptor_type 1 +GLAD_API_CALL int GLAD_VK_VALVE_mutable_descriptor_type; + + +typedef VkResult (GLAD_API_PTR *PFN_vkAcquireDrmDisplayEXT)(VkPhysicalDevice physicalDevice, int32_t drmFd, VkDisplayKHR display); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkAcquireFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice device, const VkAcquireNextImageInfoKHR * pAcquireInfo, uint32_t * pImageIndex); typedef VkResult (GLAD_API_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t * pImageIndex); typedef VkResult (GLAD_API_PTR *PFN_vkAcquirePerformanceConfigurationINTEL)(VkDevice device, const VkPerformanceConfigurationAcquireInfoINTEL * pAcquireInfo, VkPerformanceConfigurationINTEL * pConfiguration); typedef VkResult (GLAD_API_PTR *PFN_vkAcquireProfilingLockKHR)(VkDevice device, const VkAcquireProfilingLockInfoKHR * pInfo); +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef VkResult (GLAD_API_PTR *PFN_vkAcquireWinrtDisplayNV)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); + +#endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) typedef VkResult (GLAD_API_PTR *PFN_vkAcquireXlibDisplayEXT)(VkPhysicalDevice physicalDevice, Display * dpy, VkDisplayKHR display); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo * pAllocateInfo, VkCommandBuffer * pCommandBuffers); typedef VkResult (GLAD_API_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo * pAllocateInfo, VkDescriptorSet * pDescriptorSets); typedef VkResult (GLAD_API_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo * pAllocateInfo, const VkAllocationCallbacks * pAllocator, VkDeviceMemory * pMemory); +typedef void (GLAD_API_PTR *PFN_vkAntiLagUpdateAMD)(VkDevice device, const VkAntiLagDataAMD * pData); typedef VkResult (GLAD_API_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo * pBeginInfo); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkBindAccelerationStructureMemoryKHR)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoKHR * pBindInfos); -#endif -typedef VkResult (GLAD_API_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoKHR * pBindInfos); +typedef VkResult (GLAD_API_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV * pBindInfos); typedef VkResult (GLAD_API_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); typedef VkResult (GLAD_API_PTR *PFN_vkBindBufferMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo * pBindInfos); typedef VkResult (GLAD_API_PTR *PFN_vkBindBufferMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo * pBindInfos); typedef VkResult (GLAD_API_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); typedef VkResult (GLAD_API_PTR *PFN_vkBindImageMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo * pBindInfos); typedef VkResult (GLAD_API_PTR *PFN_vkBindImageMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo * pBindInfos); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkBuildAccelerationStructureKHR)(VkDevice device, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR * pInfos, const VkAccelerationStructureBuildOffsetInfoKHR * const* ppOffsetInfos); -#endif +typedef VkResult (GLAD_API_PTR *PFN_vkBindOpticalFlowSessionImageNV)(VkDevice device, VkOpticalFlowSessionNV session, VkOpticalFlowSessionBindingPointNV bindingPoint, VkImageView view, VkImageLayout layout); +typedef VkResult (GLAD_API_PTR *PFN_vkBuildAccelerationStructuresKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR * pInfos, const VkAccelerationStructureBuildRangeInfoKHR * const* ppBuildRangeInfos); +typedef VkResult (GLAD_API_PTR *PFN_vkBuildMicromapsEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkMicromapBuildInfoEXT * pInfos); typedef void (GLAD_API_PTR *PFN_vkCmdBeginConditionalRenderingEXT)(VkCommandBuffer commandBuffer, const VkConditionalRenderingBeginInfoEXT * pConditionalRenderingBegin); typedef void (GLAD_API_PTR *PFN_vkCmdBeginDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT * pLabelInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBeginPerTileExecutionQCOM)(VkCommandBuffer commandBuffer, const VkPerTileBeginInfoQCOM * pPerTileBeginInfo); typedef void (GLAD_API_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); typedef void (GLAD_API_PTR *PFN_vkCmdBeginQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags, uint32_t index); typedef void (GLAD_API_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo * pRenderPassBegin, VkSubpassContents contents); typedef void (GLAD_API_PTR *PFN_vkCmdBeginRenderPass2)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo * pRenderPassBegin, const VkSubpassBeginInfo * pSubpassBeginInfo); typedef void (GLAD_API_PTR *PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo * pRenderPassBegin, const VkSubpassBeginInfo * pSubpassBeginInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBeginRendering)(VkCommandBuffer commandBuffer, const VkRenderingInfo * pRenderingInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBeginRenderingKHR)(VkCommandBuffer commandBuffer, const VkRenderingInfo * pRenderingInfo); typedef void (GLAD_API_PTR *PFN_vkCmdBeginTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer * pCounterBuffers, const VkDeviceSize * pCounterBufferOffsets); +typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT)(VkCommandBuffer commandBuffer, const VkBindDescriptorBufferEmbeddedSamplersInfoEXT * pBindDescriptorBufferEmbeddedSamplersInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set); +typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t bufferCount, const VkDescriptorBufferBindingInfoEXT * pBindingInfos); typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet * pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t * pDynamicOffsets); +typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorSets2)(VkCommandBuffer commandBuffer, const VkBindDescriptorSetsInfo * pBindDescriptorSetsInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorSets2KHR)(VkCommandBuffer commandBuffer, const VkBindDescriptorSetsInfo * pBindDescriptorSetsInfo); typedef void (GLAD_API_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); +typedef void (GLAD_API_PTR *PFN_vkCmdBindIndexBuffer2)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size, VkIndexType indexType); +typedef void (GLAD_API_PTR *PFN_vkCmdBindIndexBuffer2KHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size, VkIndexType indexType); +typedef void (GLAD_API_PTR *PFN_vkCmdBindInvocationMaskHUAWEI)(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout); typedef void (GLAD_API_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); typedef void (GLAD_API_PTR *PFN_vkCmdBindPipelineShaderGroupNV)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline, uint32_t groupIndex); +typedef void (GLAD_API_PTR *PFN_vkCmdBindShadersEXT)(VkCommandBuffer commandBuffer, uint32_t stageCount, const VkShaderStageFlagBits * pStages, const VkShaderEXT * pShaders); typedef void (GLAD_API_PTR *PFN_vkCmdBindShadingRateImageNV)(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout); +typedef void (GLAD_API_PTR *PFN_vkCmdBindTileMemoryQCOM)(VkCommandBuffer commandBuffer, const VkTileMemoryBindInfoQCOM * pTileMemoryBindInfo); typedef void (GLAD_API_PTR *PFN_vkCmdBindTransformFeedbackBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer * pBuffers, const VkDeviceSize * pOffsets, const VkDeviceSize * pSizes); typedef void (GLAD_API_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer * pBuffers, const VkDeviceSize * pOffsets); +typedef void (GLAD_API_PTR *PFN_vkCmdBindVertexBuffers2)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer * pBuffers, const VkDeviceSize * pOffsets, const VkDeviceSize * pSizes, const VkDeviceSize * pStrides); typedef void (GLAD_API_PTR *PFN_vkCmdBindVertexBuffers2EXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer * pBuffers, const VkDeviceSize * pOffsets, const VkDeviceSize * pSizes, const VkDeviceSize * pStrides); typedef void (GLAD_API_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit * pRegions, VkFilter filter); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef void (GLAD_API_PTR *PFN_vkCmdBuildAccelerationStructureIndirectKHR)(VkCommandBuffer commandBuffer, const VkAccelerationStructureBuildGeometryInfoKHR * pInfo, VkBuffer indirectBuffer, VkDeviceSize indirectOffset, uint32_t indirectStride); -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef void (GLAD_API_PTR *PFN_vkCmdBuildAccelerationStructureKHR)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR * pInfos, const VkAccelerationStructureBuildOffsetInfoKHR * const* ppOffsetInfos); -#endif -typedef void (GLAD_API_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV * pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureKHR dst, VkAccelerationStructureKHR src, VkBuffer scratch, VkDeviceSize scratchOffset); +typedef void (GLAD_API_PTR *PFN_vkCmdBlitImage2)(VkCommandBuffer commandBuffer, const VkBlitImageInfo2 * pBlitImageInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBlitImage2KHR)(VkCommandBuffer commandBuffer, const VkBlitImageInfo2 * pBlitImageInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV * pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset); +typedef void (GLAD_API_PTR *PFN_vkCmdBuildAccelerationStructuresIndirectKHR)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR * pInfos, const VkDeviceAddress * pIndirectDeviceAddresses, const uint32_t * pIndirectStrides, const uint32_t * const* ppMaxPrimitiveCounts); +typedef void (GLAD_API_PTR *PFN_vkCmdBuildAccelerationStructuresKHR)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR * pInfos, const VkAccelerationStructureBuildRangeInfoKHR * const* ppBuildRangeInfos); +typedef void (GLAD_API_PTR *PFN_vkCmdBuildClusterAccelerationStructureIndirectNV)(VkCommandBuffer commandBuffer, const VkClusterAccelerationStructureCommandsInfoNV * pCommandInfos); +typedef void (GLAD_API_PTR *PFN_vkCmdBuildMicromapsEXT)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkMicromapBuildInfoEXT * pInfos); +typedef void (GLAD_API_PTR *PFN_vkCmdBuildPartitionedAccelerationStructuresNV)(VkCommandBuffer commandBuffer, const VkBuildPartitionedAccelerationStructureInfoNV * pBuildInfo); typedef void (GLAD_API_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment * pAttachments, uint32_t rectCount, const VkClearRect * pRects); typedef void (GLAD_API_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue * pColor, uint32_t rangeCount, const VkImageSubresourceRange * pRanges); typedef void (GLAD_API_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue * pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange * pRanges); -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdConvertCooperativeVectorMatrixNV)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkConvertCooperativeVectorMatrixInfoNV * pInfos); typedef void (GLAD_API_PTR *PFN_vkCmdCopyAccelerationStructureKHR)(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureInfoKHR * pInfo); -#endif -typedef void (GLAD_API_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureKHR dst, VkAccelerationStructureKHR src, VkCopyAccelerationStructureModeKHR mode); -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeKHR mode); typedef void (GLAD_API_PTR *PFN_vkCmdCopyAccelerationStructureToMemoryKHR)(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureToMemoryInfoKHR * pInfo); -#endif typedef void (GLAD_API_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy * pRegions); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyBuffer2)(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2 * pCopyBufferInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2 * pCopyBufferInfo); typedef void (GLAD_API_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy * pRegions); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyBufferToImage2)(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2 * pCopyBufferToImageInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyBufferToImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2 * pCopyBufferToImageInfo); typedef void (GLAD_API_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy * pRegions); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyImage2)(VkCommandBuffer commandBuffer, const VkCopyImageInfo2 * pCopyImageInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageInfo2 * pCopyImageInfo); typedef void (GLAD_API_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy * pRegions); -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdCopyImageToBuffer2)(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2 * pCopyImageToBufferInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyImageToBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2 * pCopyImageToBufferInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyMemoryIndirectNV)(VkCommandBuffer commandBuffer, VkDeviceAddress copyBufferAddress, uint32_t copyCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdCopyMemoryToAccelerationStructureKHR)(VkCommandBuffer commandBuffer, const VkCopyMemoryToAccelerationStructureInfoKHR * pInfo); -#endif +typedef void (GLAD_API_PTR *PFN_vkCmdCopyMemoryToImageIndirectNV)(VkCommandBuffer commandBuffer, VkDeviceAddress copyBufferAddress, uint32_t copyCount, uint32_t stride, VkImage dstImage, VkImageLayout dstImageLayout, const VkImageSubresourceLayers * pImageSubresources); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyMemoryToMicromapEXT)(VkCommandBuffer commandBuffer, const VkCopyMemoryToMicromapInfoEXT * pInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyMicromapEXT)(VkCommandBuffer commandBuffer, const VkCopyMicromapInfoEXT * pInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyMicromapToMemoryEXT)(VkCommandBuffer commandBuffer, const VkCopyMicromapToMemoryInfoEXT * pInfo); typedef void (GLAD_API_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); +typedef void (GLAD_API_PTR *PFN_vkCmdCuLaunchKernelNVX)(VkCommandBuffer commandBuffer, const VkCuLaunchInfoNVX * pLaunchInfo); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdCudaLaunchKernelNV)(VkCommandBuffer commandBuffer, const VkCudaLaunchInfoNV * pLaunchInfo); + +#endif typedef void (GLAD_API_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT * pMarkerInfo); typedef void (GLAD_API_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer); typedef void (GLAD_API_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT * pMarkerInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdDecompressMemoryIndirectCountNV)(VkCommandBuffer commandBuffer, VkDeviceAddress indirectCommandsAddress, VkDeviceAddress indirectCommandsCountAddress, uint32_t stride); +typedef void (GLAD_API_PTR *PFN_vkCmdDecompressMemoryNV)(VkCommandBuffer commandBuffer, uint32_t decompressRegionCount, const VkDecompressMemoryRegionNV * pDecompressMemoryRegions); typedef void (GLAD_API_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); typedef void (GLAD_API_PTR *PFN_vkCmdDispatchBase)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); typedef void (GLAD_API_PTR *PFN_vkCmdDispatchBaseKHR)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdDispatchGraphAMDX)(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, VkDeviceSize scratchSize, const VkDispatchGraphCountInfoAMDX * pCountInfo); + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdDispatchGraphIndirectAMDX)(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, VkDeviceSize scratchSize, const VkDispatchGraphCountInfoAMDX * pCountInfo); + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdDispatchGraphIndirectCountAMDX)(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, VkDeviceSize scratchSize, VkDeviceAddress countInfo); + +#endif typedef void (GLAD_API_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); +typedef void (GLAD_API_PTR *PFN_vkCmdDispatchTileQCOM)(VkCommandBuffer commandBuffer); typedef void (GLAD_API_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawClusterHUAWEI)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawClusterIndirectHUAWEI)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndexedIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); @@ -9428,107 +16990,226 @@ typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndirectByteCountEXT)(VkCommandBuffer c typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndirectCountKHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawMeshTasksEXT)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawMeshTasksIndirectCountEXT)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdDrawMeshTasksIndirectCountNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawMeshTasksIndirectEXT)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdDrawMeshTasksIndirectNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdDrawMeshTasksNV)(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawMultiEXT)(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawInfoEXT * pVertexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawMultiIndexedEXT)(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawIndexedInfoEXT * pIndexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride, const int32_t * pVertexOffset); typedef void (GLAD_API_PTR *PFN_vkCmdEndConditionalRenderingEXT)(VkCommandBuffer commandBuffer); typedef void (GLAD_API_PTR *PFN_vkCmdEndDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer); +typedef void (GLAD_API_PTR *PFN_vkCmdEndPerTileExecutionQCOM)(VkCommandBuffer commandBuffer, const VkPerTileEndInfoQCOM * pPerTileEndInfo); typedef void (GLAD_API_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); typedef void (GLAD_API_PTR *PFN_vkCmdEndQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index); typedef void (GLAD_API_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer); typedef void (GLAD_API_PTR *PFN_vkCmdEndRenderPass2)(VkCommandBuffer commandBuffer, const VkSubpassEndInfo * pSubpassEndInfo); typedef void (GLAD_API_PTR *PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfo * pSubpassEndInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdEndRendering)(VkCommandBuffer commandBuffer); +typedef void (GLAD_API_PTR *PFN_vkCmdEndRendering2EXT)(VkCommandBuffer commandBuffer, const VkRenderingEndInfoEXT * pRenderingEndInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdEndRenderingKHR)(VkCommandBuffer commandBuffer); typedef void (GLAD_API_PTR *PFN_vkCmdEndTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer * pCounterBuffers, const VkDeviceSize * pCounterBufferOffsets); typedef void (GLAD_API_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer * pCommandBuffers); +typedef void (GLAD_API_PTR *PFN_vkCmdExecuteGeneratedCommandsEXT)(VkCommandBuffer commandBuffer, VkBool32 isPreprocessed, const VkGeneratedCommandsInfoEXT * pGeneratedCommandsInfo); typedef void (GLAD_API_PTR *PFN_vkCmdExecuteGeneratedCommandsNV)(VkCommandBuffer commandBuffer, VkBool32 isPreprocessed, const VkGeneratedCommandsInfoNV * pGeneratedCommandsInfo); typedef void (GLAD_API_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdInitializeGraphScratchMemoryAMDX)(VkCommandBuffer commandBuffer, VkPipeline executionGraph, VkDeviceAddress scratch, VkDeviceSize scratchSize); + +#endif typedef void (GLAD_API_PTR *PFN_vkCmdInsertDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT * pLabelInfo); typedef void (GLAD_API_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents); typedef void (GLAD_API_PTR *PFN_vkCmdNextSubpass2)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo * pSubpassBeginInfo, const VkSubpassEndInfo * pSubpassEndInfo); typedef void (GLAD_API_PTR *PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo * pSubpassBeginInfo, const VkSubpassEndInfo * pSubpassEndInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdOpticalFlowExecuteNV)(VkCommandBuffer commandBuffer, VkOpticalFlowSessionNV session, const VkOpticalFlowExecuteInfoNV * pExecuteInfo); typedef void (GLAD_API_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier * pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier * pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier * pImageMemoryBarriers); +typedef void (GLAD_API_PTR *PFN_vkCmdPipelineBarrier2)(VkCommandBuffer commandBuffer, const VkDependencyInfo * pDependencyInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdPipelineBarrier2KHR)(VkCommandBuffer commandBuffer, const VkDependencyInfo * pDependencyInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdPreprocessGeneratedCommandsEXT)(VkCommandBuffer commandBuffer, const VkGeneratedCommandsInfoEXT * pGeneratedCommandsInfo, VkCommandBuffer stateCommandBuffer); typedef void (GLAD_API_PTR *PFN_vkCmdPreprocessGeneratedCommandsNV)(VkCommandBuffer commandBuffer, const VkGeneratedCommandsInfoNV * pGeneratedCommandsInfo); typedef void (GLAD_API_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void * pValues); +typedef void (GLAD_API_PTR *PFN_vkCmdPushConstants2)(VkCommandBuffer commandBuffer, const VkPushConstantsInfo * pPushConstantsInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdPushConstants2KHR)(VkCommandBuffer commandBuffer, const VkPushConstantsInfo * pPushConstantsInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSet)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet * pDescriptorWrites); +typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSet2)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetInfo * pPushDescriptorSetInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSet2KHR)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetInfo * pPushDescriptorSetInfo); typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet * pDescriptorWrites); +typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSetWithTemplate)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void * pData); +typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSetWithTemplate2)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetWithTemplateInfo * pPushDescriptorSetWithTemplateInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSetWithTemplate2KHR)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetWithTemplateInfo * pPushDescriptorSetWithTemplateInfo); typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void * pData); typedef void (GLAD_API_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (GLAD_API_PTR *PFN_vkCmdResetEvent2)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask); +typedef void (GLAD_API_PTR *PFN_vkCmdResetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask); typedef void (GLAD_API_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); typedef void (GLAD_API_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve * pRegions); +typedef void (GLAD_API_PTR *PFN_vkCmdResolveImage2)(VkCommandBuffer commandBuffer, const VkResolveImageInfo2 * pResolveImageInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdResolveImage2KHR)(VkCommandBuffer commandBuffer, const VkResolveImageInfo2 * pResolveImageInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetAlphaToCoverageEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 alphaToCoverageEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetAlphaToOneEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 alphaToOneEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT)(VkCommandBuffer commandBuffer, VkImageAspectFlags aspectMask); typedef void (GLAD_API_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants [4]); typedef void (GLAD_API_PTR *PFN_vkCmdSetCheckpointNV)(VkCommandBuffer commandBuffer, const void * pCheckpointMarker); typedef void (GLAD_API_PTR *PFN_vkCmdSetCoarseSampleOrderNV)(VkCommandBuffer commandBuffer, VkCoarseSampleOrderTypeNV sampleOrderType, uint32_t customSampleOrderCount, const VkCoarseSampleOrderCustomNV * pCustomSampleOrders); +typedef void (GLAD_API_PTR *PFN_vkCmdSetColorBlendAdvancedEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendAdvancedEXT * pColorBlendAdvanced); +typedef void (GLAD_API_PTR *PFN_vkCmdSetColorBlendEnableEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkBool32 * pColorBlendEnables); +typedef void (GLAD_API_PTR *PFN_vkCmdSetColorBlendEquationEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendEquationEXT * pColorBlendEquations); +typedef void (GLAD_API_PTR *PFN_vkCmdSetColorWriteEnableEXT)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkBool32 * pColorWriteEnables); +typedef void (GLAD_API_PTR *PFN_vkCmdSetColorWriteMaskEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorComponentFlags * pColorWriteMasks); +typedef void (GLAD_API_PTR *PFN_vkCmdSetConservativeRasterizationModeEXT)(VkCommandBuffer commandBuffer, VkConservativeRasterizationModeEXT conservativeRasterizationMode); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCoverageModulationModeNV)(VkCommandBuffer commandBuffer, VkCoverageModulationModeNV coverageModulationMode); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCoverageModulationTableEnableNV)(VkCommandBuffer commandBuffer, VkBool32 coverageModulationTableEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCoverageModulationTableNV)(VkCommandBuffer commandBuffer, uint32_t coverageModulationTableCount, const float * pCoverageModulationTable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCoverageReductionModeNV)(VkCommandBuffer commandBuffer, VkCoverageReductionModeNV coverageReductionMode); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCoverageToColorEnableNV)(VkCommandBuffer commandBuffer, VkBool32 coverageToColorEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCoverageToColorLocationNV)(VkCommandBuffer commandBuffer, uint32_t coverageToColorLocation); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCullMode)(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode); typedef void (GLAD_API_PTR *PFN_vkCmdSetCullModeEXT)(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode); typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBias2EXT)(VkCommandBuffer commandBuffer, const VkDepthBiasInfoEXT * pDepthBiasInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBiasEnable)(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBiasEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBoundsTestEnable)(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBoundsTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthClampEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthClampEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthClampRangeEXT)(VkCommandBuffer commandBuffer, VkDepthClampModeEXT depthClampMode, const VkDepthClampRangeEXT * pDepthClampRange); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthClipEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthClipEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthClipNegativeOneToOneEXT)(VkCommandBuffer commandBuffer, VkBool32 negativeOneToOne); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthCompareOp)(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp); typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthCompareOpEXT)(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthTestEnable)(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthWriteEnable)(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthWriteEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDescriptorBufferOffsets2EXT)(VkCommandBuffer commandBuffer, const VkSetDescriptorBufferOffsetsInfoEXT * pSetDescriptorBufferOffsetsInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDescriptorBufferOffsetsEXT)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount, const uint32_t * pBufferIndices, const VkDeviceSize * pOffsets); typedef void (GLAD_API_PTR *PFN_vkCmdSetDeviceMask)(VkCommandBuffer commandBuffer, uint32_t deviceMask); typedef void (GLAD_API_PTR *PFN_vkCmdSetDeviceMaskKHR)(VkCommandBuffer commandBuffer, uint32_t deviceMask); typedef void (GLAD_API_PTR *PFN_vkCmdSetDiscardRectangleEXT)(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const VkRect2D * pDiscardRectangles); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDiscardRectangleEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 discardRectangleEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDiscardRectangleModeEXT)(VkCommandBuffer commandBuffer, VkDiscardRectangleModeEXT discardRectangleMode); typedef void (GLAD_API_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (GLAD_API_PTR *PFN_vkCmdSetEvent2)(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo * pDependencyInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo * pDependencyInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetExclusiveScissorEnableNV)(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount, const VkBool32 * pExclusiveScissorEnables); typedef void (GLAD_API_PTR *PFN_vkCmdSetExclusiveScissorNV)(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount, const VkRect2D * pExclusiveScissors); +typedef void (GLAD_API_PTR *PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT)(VkCommandBuffer commandBuffer, float extraPrimitiveOverestimationSize); +typedef void (GLAD_API_PTR *PFN_vkCmdSetFragmentShadingRateEnumNV)(VkCommandBuffer commandBuffer, VkFragmentShadingRateNV shadingRate, const VkFragmentShadingRateCombinerOpKHR combinerOps [2]); +typedef void (GLAD_API_PTR *PFN_vkCmdSetFragmentShadingRateKHR)(VkCommandBuffer commandBuffer, const VkExtent2D * pFragmentSize, const VkFragmentShadingRateCombinerOpKHR combinerOps [2]); +typedef void (GLAD_API_PTR *PFN_vkCmdSetFrontFace)(VkCommandBuffer commandBuffer, VkFrontFace frontFace); typedef void (GLAD_API_PTR *PFN_vkCmdSetFrontFaceEXT)(VkCommandBuffer commandBuffer, VkFrontFace frontFace); +typedef void (GLAD_API_PTR *PFN_vkCmdSetLineRasterizationModeEXT)(VkCommandBuffer commandBuffer, VkLineRasterizationModeEXT lineRasterizationMode); +typedef void (GLAD_API_PTR *PFN_vkCmdSetLineStipple)(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); typedef void (GLAD_API_PTR *PFN_vkCmdSetLineStippleEXT)(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); +typedef void (GLAD_API_PTR *PFN_vkCmdSetLineStippleEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 stippledLineEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetLineStippleKHR)(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); typedef void (GLAD_API_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth); +typedef void (GLAD_API_PTR *PFN_vkCmdSetLogicOpEXT)(VkCommandBuffer commandBuffer, VkLogicOp logicOp); +typedef void (GLAD_API_PTR *PFN_vkCmdSetLogicOpEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 logicOpEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetPatchControlPointsEXT)(VkCommandBuffer commandBuffer, uint32_t patchControlPoints); typedef VkResult (GLAD_API_PTR *PFN_vkCmdSetPerformanceMarkerINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceMarkerInfoINTEL * pMarkerInfo); typedef VkResult (GLAD_API_PTR *PFN_vkCmdSetPerformanceOverrideINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceOverrideInfoINTEL * pOverrideInfo); typedef VkResult (GLAD_API_PTR *PFN_vkCmdSetPerformanceStreamMarkerINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceStreamMarkerInfoINTEL * pMarkerInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetPolygonModeEXT)(VkCommandBuffer commandBuffer, VkPolygonMode polygonMode); +typedef void (GLAD_API_PTR *PFN_vkCmdSetPrimitiveRestartEnable)(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetPrimitiveRestartEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetPrimitiveTopology)(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology); typedef void (GLAD_API_PTR *PFN_vkCmdSetPrimitiveTopologyEXT)(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology); +typedef void (GLAD_API_PTR *PFN_vkCmdSetProvokingVertexModeEXT)(VkCommandBuffer commandBuffer, VkProvokingVertexModeEXT provokingVertexMode); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRasterizationSamplesEXT)(VkCommandBuffer commandBuffer, VkSampleCountFlagBits rasterizationSamples); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRasterizationStreamEXT)(VkCommandBuffer commandBuffer, uint32_t rasterizationStream); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRasterizerDiscardEnable)(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRasterizerDiscardEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRayTracingPipelineStackSizeKHR)(VkCommandBuffer commandBuffer, uint32_t pipelineStackSize); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRenderingAttachmentLocations)(VkCommandBuffer commandBuffer, const VkRenderingAttachmentLocationInfo * pLocationInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRenderingAttachmentLocationsKHR)(VkCommandBuffer commandBuffer, const VkRenderingAttachmentLocationInfo * pLocationInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRenderingInputAttachmentIndices)(VkCommandBuffer commandBuffer, const VkRenderingInputAttachmentIndexInfo * pInputAttachmentIndexInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRenderingInputAttachmentIndicesKHR)(VkCommandBuffer commandBuffer, const VkRenderingInputAttachmentIndexInfo * pInputAttachmentIndexInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRepresentativeFragmentTestEnableNV)(VkCommandBuffer commandBuffer, VkBool32 representativeFragmentTestEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetSampleLocationsEXT)(VkCommandBuffer commandBuffer, const VkSampleLocationsInfoEXT * pSampleLocationsInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetSampleLocationsEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 sampleLocationsEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetSampleMaskEXT)(VkCommandBuffer commandBuffer, VkSampleCountFlagBits samples, const VkSampleMask * pSampleMask); typedef void (GLAD_API_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D * pScissors); +typedef void (GLAD_API_PTR *PFN_vkCmdSetScissorWithCount)(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D * pScissors); typedef void (GLAD_API_PTR *PFN_vkCmdSetScissorWithCountEXT)(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D * pScissors); +typedef void (GLAD_API_PTR *PFN_vkCmdSetShadingRateImageEnableNV)(VkCommandBuffer commandBuffer, VkBool32 shadingRateImageEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); +typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilOp)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilOpEXT)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); +typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilTestEnable)(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); +typedef void (GLAD_API_PTR *PFN_vkCmdSetTessellationDomainOriginEXT)(VkCommandBuffer commandBuffer, VkTessellationDomainOrigin domainOrigin); +typedef void (GLAD_API_PTR *PFN_vkCmdSetVertexInputEXT)(VkCommandBuffer commandBuffer, uint32_t vertexBindingDescriptionCount, const VkVertexInputBindingDescription2EXT * pVertexBindingDescriptions, uint32_t vertexAttributeDescriptionCount, const VkVertexInputAttributeDescription2EXT * pVertexAttributeDescriptions); typedef void (GLAD_API_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport * pViewports); typedef void (GLAD_API_PTR *PFN_vkCmdSetViewportShadingRatePaletteNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkShadingRatePaletteNV * pShadingRatePalettes); +typedef void (GLAD_API_PTR *PFN_vkCmdSetViewportSwizzleNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportSwizzleNV * pViewportSwizzles); +typedef void (GLAD_API_PTR *PFN_vkCmdSetViewportWScalingEnableNV)(VkCommandBuffer commandBuffer, VkBool32 viewportWScalingEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetViewportWScalingNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV * pViewportWScalings); +typedef void (GLAD_API_PTR *PFN_vkCmdSetViewportWithCount)(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport * pViewports); typedef void (GLAD_API_PTR *PFN_vkCmdSetViewportWithCountEXT)(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport * pViewports); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef void (GLAD_API_PTR *PFN_vkCmdTraceRaysIndirectKHR)(VkCommandBuffer commandBuffer, const VkStridedBufferRegionKHR * pRaygenShaderBindingTable, const VkStridedBufferRegionKHR * pMissShaderBindingTable, const VkStridedBufferRegionKHR * pHitShaderBindingTable, const VkStridedBufferRegionKHR * pCallableShaderBindingTable, VkBuffer buffer, VkDeviceSize offset); -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef void (GLAD_API_PTR *PFN_vkCmdTraceRaysKHR)(VkCommandBuffer commandBuffer, const VkStridedBufferRegionKHR * pRaygenShaderBindingTable, const VkStridedBufferRegionKHR * pMissShaderBindingTable, const VkStridedBufferRegionKHR * pHitShaderBindingTable, const VkStridedBufferRegionKHR * pCallableShaderBindingTable, uint32_t width, uint32_t height, uint32_t depth); -#endif +typedef void (GLAD_API_PTR *PFN_vkCmdSubpassShadingHUAWEI)(VkCommandBuffer commandBuffer); +typedef void (GLAD_API_PTR *PFN_vkCmdTraceRaysIndirect2KHR)(VkCommandBuffer commandBuffer, VkDeviceAddress indirectDeviceAddress); +typedef void (GLAD_API_PTR *PFN_vkCmdTraceRaysIndirectKHR)(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR * pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR * pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR * pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR * pCallableShaderBindingTable, VkDeviceAddress indirectDeviceAddress); +typedef void (GLAD_API_PTR *PFN_vkCmdTraceRaysKHR)(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR * pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR * pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR * pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR * pCallableShaderBindingTable, uint32_t width, uint32_t height, uint32_t depth); typedef void (GLAD_API_PTR *PFN_vkCmdTraceRaysNV)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth); typedef void (GLAD_API_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void * pData); +typedef void (GLAD_API_PTR *PFN_vkCmdUpdatePipelineIndirectBufferNV)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); typedef void (GLAD_API_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent * pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier * pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier * pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier * pImageMemoryBarriers); -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdWaitEvents2)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent * pEvents, const VkDependencyInfo * pDependencyInfos); +typedef void (GLAD_API_PTR *PFN_vkCmdWaitEvents2KHR)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent * pEvents, const VkDependencyInfo * pDependencyInfos); typedef void (GLAD_API_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR * pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); -#endif -typedef void (GLAD_API_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR * pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef void (GLAD_API_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV * pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef void (GLAD_API_PTR *PFN_vkCmdWriteBufferMarker2AMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); typedef void (GLAD_API_PTR *PFN_vkCmdWriteBufferMarkerAMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); +typedef void (GLAD_API_PTR *PFN_vkCmdWriteMicromapsPropertiesEXT)(VkCommandBuffer commandBuffer, uint32_t micromapCount, const VkMicromapEXT * pMicromaps, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); typedef void (GLAD_API_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); +typedef void (GLAD_API_PTR *PFN_vkCmdWriteTimestamp2)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query); +typedef void (GLAD_API_PTR *PFN_vkCmdWriteTimestamp2KHR)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query); typedef VkResult (GLAD_API_PTR *PFN_vkCompileDeferredNV)(VkDevice device, VkPipeline pipeline, uint32_t shader); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkCopyAccelerationStructureKHR)(VkDevice device, const VkCopyAccelerationStructureInfoKHR * pInfo); -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkCopyAccelerationStructureToMemoryKHR)(VkDevice device, const VkCopyAccelerationStructureToMemoryInfoKHR * pInfo); -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkCopyMemoryToAccelerationStructureKHR)(VkDevice device, const VkCopyMemoryToAccelerationStructureInfoKHR * pInfo); -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef VkResult (GLAD_API_PTR *PFN_vkConvertCooperativeVectorMatrixNV)(VkDevice device, const VkConvertCooperativeVectorMatrixInfoNV * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyAccelerationStructureKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureInfoKHR * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyAccelerationStructureToMemoryKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureToMemoryInfoKHR * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyImageToImage)(VkDevice device, const VkCopyImageToImageInfo * pCopyImageToImageInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyImageToImageEXT)(VkDevice device, const VkCopyImageToImageInfo * pCopyImageToImageInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyImageToMemory)(VkDevice device, const VkCopyImageToMemoryInfo * pCopyImageToMemoryInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyImageToMemoryEXT)(VkDevice device, const VkCopyImageToMemoryInfo * pCopyImageToMemoryInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyMemoryToAccelerationStructureKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToAccelerationStructureInfoKHR * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyMemoryToImage)(VkDevice device, const VkCopyMemoryToImageInfo * pCopyMemoryToImageInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyMemoryToImageEXT)(VkDevice device, const VkCopyMemoryToImageInfo * pCopyMemoryToImageInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyMemoryToMicromapEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToMicromapInfoEXT * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyMicromapEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapInfoEXT * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyMicromapToMemoryEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapToMemoryInfoEXT * pInfo); typedef VkResult (GLAD_API_PTR *PFN_vkCreateAccelerationStructureKHR)(VkDevice device, const VkAccelerationStructureCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkAccelerationStructureKHR * pAccelerationStructure); -#endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateAccelerationStructureNV)(VkDevice device, const VkAccelerationStructureCreateInfoNV * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkAccelerationStructureNV * pAccelerationStructure); #if defined(VK_USE_PLATFORM_ANDROID_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkBuffer * pBuffer); +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkCreateBufferCollectionFUCHSIA)(VkDevice device, const VkBufferCollectionCreateInfoFUCHSIA * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkBufferCollectionFUCHSIA * pCollection); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkBufferView * pView); typedef VkResult (GLAD_API_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkCommandPool * pCommandPool); typedef VkResult (GLAD_API_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateCuFunctionNVX)(VkDevice device, const VkCuFunctionCreateInfoNVX * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkCuFunctionNVX * pFunction); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateCuModuleNVX)(VkDevice device, const VkCuModuleCreateInfoNVX * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkCuModuleNVX * pModule); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef VkResult (GLAD_API_PTR *PFN_vkCreateCudaFunctionNV)(VkDevice device, const VkCudaFunctionCreateInfoNV * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkCudaFunctionNV * pFunction); + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef VkResult (GLAD_API_PTR *PFN_vkCreateCudaModuleNV)(VkDevice device, const VkCudaModuleCreateInfoNV * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkCudaModuleNV * pModule); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDebugReportCallbackEXT * pCallback); typedef VkResult (GLAD_API_PTR *PFN_vkCreateDebugUtilsMessengerEXT)(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDebugUtilsMessengerEXT * pMessenger); -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef VkResult (GLAD_API_PTR *PFN_vkCreateDeferredOperationKHR)(VkDevice device, const VkAllocationCallbacks * pAllocator, VkDeferredOperationKHR * pDeferredOperation); -#endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDescriptorPool * pDescriptorPool); typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDescriptorSetLayout * pSetLayout); typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorUpdateTemplate)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDescriptorUpdateTemplate * pDescriptorUpdateTemplate); @@ -9536,37 +17217,51 @@ typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevic typedef VkResult (GLAD_API_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDevice * pDevice); #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) typedef VkResult (GLAD_API_PTR *PFN_vkCreateDirectFBSurfaceEXT)(VkInstance instance, const VkDirectFBSurfaceCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDisplayModeKHR * pMode); typedef VkResult (GLAD_API_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); typedef VkResult (GLAD_API_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkEvent * pEvent); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef VkResult (GLAD_API_PTR *PFN_vkCreateExecutionGraphPipelinesAMDX)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkExecutionGraphPipelineCreateInfoAMDX * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); + +#endif +typedef VkResult (GLAD_API_PTR *PFN_vkCreateExternalComputeQueueNV)(VkDevice device, const VkExternalComputeQueueCreateInfoNV * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkExternalComputeQueueNV * pExternalQueue); typedef VkResult (GLAD_API_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkFence * pFence); typedef VkResult (GLAD_API_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkFramebuffer * pFramebuffer); typedef VkResult (GLAD_API_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); typedef VkResult (GLAD_API_PTR *PFN_vkCreateHeadlessSurfaceEXT)(VkInstance instance, const VkHeadlessSurfaceCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); #if defined(VK_USE_PLATFORM_IOS_MVK) typedef VkResult (GLAD_API_PTR *PFN_vkCreateIOSSurfaceMVK)(VkInstance instance, const VkIOSSurfaceCreateInfoMVK * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkImage * pImage); #if defined(VK_USE_PLATFORM_FUCHSIA) typedef VkResult (GLAD_API_PTR *PFN_vkCreateImagePipeSurfaceFUCHSIA)(VkInstance instance, const VkImagePipeSurfaceCreateInfoFUCHSIA * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkImageView * pView); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateIndirectCommandsLayoutEXT)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkIndirectCommandsLayoutEXT * pIndirectCommandsLayout); typedef VkResult (GLAD_API_PTR *PFN_vkCreateIndirectCommandsLayoutNV)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNV * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkIndirectCommandsLayoutNV * pIndirectCommandsLayout); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateIndirectExecutionSetEXT)(VkDevice device, const VkIndirectExecutionSetCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkIndirectExecutionSetEXT * pIndirectExecutionSet); typedef VkResult (GLAD_API_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkInstance * pInstance); #if defined(VK_USE_PLATFORM_MACOS_MVK) typedef VkResult (GLAD_API_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif #if defined(VK_USE_PLATFORM_METAL_EXT) typedef VkResult (GLAD_API_PTR *PFN_vkCreateMetalSurfaceEXT)(VkInstance instance, const VkMetalSurfaceCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif +typedef VkResult (GLAD_API_PTR *PFN_vkCreateMicromapEXT)(VkDevice device, const VkMicromapCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkMicromapEXT * pMicromap); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateOpticalFlowSessionNV)(VkDevice device, const VkOpticalFlowSessionCreateInfoNV * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkOpticalFlowSessionNV * pSession); +typedef VkResult (GLAD_API_PTR *PFN_vkCreatePipelineBinariesKHR)(VkDevice device, const VkPipelineBinaryCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPipelineBinaryHandlesInfoKHR * pBinaries); typedef VkResult (GLAD_API_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPipelineCache * pPipelineCache); typedef VkResult (GLAD_API_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPipelineLayout * pPipelineLayout); -typedef VkResult (GLAD_API_PTR *PFN_vkCreatePrivateDataSlotEXT)(VkDevice device, const VkPrivateDataSlotCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPrivateDataSlotEXT * pPrivateDataSlot); +typedef VkResult (GLAD_API_PTR *PFN_vkCreatePrivateDataSlot)(VkDevice device, const VkPrivateDataSlotCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPrivateDataSlot * pPrivateDataSlot); +typedef VkResult (GLAD_API_PTR *PFN_vkCreatePrivateDataSlotEXT)(VkDevice device, const VkPrivateDataSlotCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPrivateDataSlot * pPrivateDataSlot); typedef VkResult (GLAD_API_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkQueryPool * pQueryPool); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkCreateRayTracingPipelinesKHR)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoKHR * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); -#endif +typedef VkResult (GLAD_API_PTR *PFN_vkCreateRayTracingPipelinesKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoKHR * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); typedef VkResult (GLAD_API_PTR *PFN_vkCreateRayTracingPipelinesNV)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); typedef VkResult (GLAD_API_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkRenderPass * pRenderPass); typedef VkResult (GLAD_API_PTR *PFN_vkCreateRenderPass2)(VkDevice device, const VkRenderPassCreateInfo2 * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkRenderPass * pRenderPass); @@ -9574,69 +17269,96 @@ typedef VkResult (GLAD_API_PTR *PFN_vkCreateRenderPass2KHR)(VkDevice device, con typedef VkResult (GLAD_API_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSampler * pSampler); typedef VkResult (GLAD_API_PTR *PFN_vkCreateSamplerYcbcrConversion)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSamplerYcbcrConversion * pYcbcrConversion); typedef VkResult (GLAD_API_PTR *PFN_vkCreateSamplerYcbcrConversionKHR)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSamplerYcbcrConversion * pYcbcrConversion); +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef VkResult (GLAD_API_PTR *PFN_vkCreateScreenSurfaceQNX)(VkInstance instance, const VkScreenSurfaceCreateInfoQNX * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSemaphore * pSemaphore); typedef VkResult (GLAD_API_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkShaderModule * pShaderModule); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateShadersEXT)(VkDevice device, uint32_t createInfoCount, const VkShaderCreateInfoEXT * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkShaderEXT * pShaders); typedef VkResult (GLAD_API_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkSwapchainKHR * pSwapchains); #if defined(VK_USE_PLATFORM_GGP) typedef VkResult (GLAD_API_PTR *PFN_vkCreateStreamDescriptorSurfaceGGP)(VkInstance instance, const VkStreamDescriptorSurfaceCreateInfoGGP * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSwapchainKHR * pSwapchain); typedef VkResult (GLAD_API_PTR *PFN_vkCreateValidationCacheEXT)(VkDevice device, const VkValidationCacheCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkValidationCacheEXT * pValidationCache); #if defined(VK_USE_PLATFORM_VI_NN) typedef VkResult (GLAD_API_PTR *PFN_vkCreateViSurfaceNN)(VkInstance instance, const VkViSurfaceCreateInfoNN * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkCreateWin32SurfaceKHR)(VkInstance instance, const VkWin32SurfaceCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, const VkDebugMarkerObjectNameInfoEXT * pNameInfo); typedef VkResult (GLAD_API_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, const VkDebugMarkerObjectTagInfoEXT * pTagInfo); typedef void (GLAD_API_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char * pLayerPrefix, const char * pMessage); -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef VkResult (GLAD_API_PTR *PFN_vkDeferredOperationJoinKHR)(VkDevice device, VkDeferredOperationKHR operation); +typedef void (GLAD_API_PTR *PFN_vkDestroyAccelerationStructureKHR)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks * pAllocator); +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef void (GLAD_API_PTR *PFN_vkDestroyBufferCollectionFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkAllocationCallbacks * pAllocator); + +#endif +typedef void (GLAD_API_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyCuFunctionNVX)(VkDevice device, VkCuFunctionNVX function, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyCuModuleNVX)(VkDevice device, VkCuModuleNVX module, const VkAllocationCallbacks * pAllocator); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkDestroyCudaFunctionNV)(VkDevice device, VkCudaFunctionNV function, const VkAllocationCallbacks * pAllocator); + #endif #if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef void (GLAD_API_PTR *PFN_vkDestroyAccelerationStructureKHR)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyCudaModuleNV)(VkDevice device, VkCudaModuleNV module, const VkAllocationCallbacks * pAllocator); + #endif -typedef void (GLAD_API_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks * pAllocator); -typedef void (GLAD_API_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks * pAllocator); -typedef void (GLAD_API_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks * pAllocator); -typedef void (GLAD_API_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyDebugUtilsMessengerEXT)(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks * pAllocator); -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef void (GLAD_API_PTR *PFN_vkDestroyDeferredOperationKHR)(VkDevice device, VkDeferredOperationKHR operation, const VkAllocationCallbacks * pAllocator); -#endif typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorUpdateTemplate)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyExternalComputeQueueNV)(VkDevice device, VkExternalComputeQueueNV externalQueue, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyIndirectCommandsLayoutEXT)(VkDevice device, VkIndirectCommandsLayoutEXT indirectCommandsLayout, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyIndirectCommandsLayoutNV)(VkDevice device, VkIndirectCommandsLayoutNV indirectCommandsLayout, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyIndirectExecutionSetEXT)(VkDevice device, VkIndirectExecutionSetEXT indirectExecutionSet, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyMicromapEXT)(VkDevice device, VkMicromapEXT micromap, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyOpticalFlowSessionNV)(VkDevice device, VkOpticalFlowSessionNV session, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyPipelineBinaryKHR)(VkDevice device, VkPipelineBinaryKHR pipelineBinary, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks * pAllocator); -typedef void (GLAD_API_PTR *PFN_vkDestroyPrivateDataSlotEXT)(VkDevice device, VkPrivateDataSlotEXT privateDataSlot, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyPrivateDataSlot)(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyPrivateDataSlotEXT)(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroySamplerYcbcrConversion)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroySamplerYcbcrConversionKHR)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyShaderEXT)(VkDevice device, VkShaderEXT shader, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks * pAllocator); @@ -9653,20 +17375,26 @@ typedef VkResult (GLAD_API_PTR *PFN_vkEnumeratePhysicalDeviceGroups)(VkInstance typedef VkResult (GLAD_API_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHR)(VkInstance instance, uint32_t * pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties * pPhysicalDeviceGroupProperties); typedef VkResult (GLAD_API_PTR *PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t * pCounterCount, VkPerformanceCounterKHR * pCounters, VkPerformanceCounterDescriptionKHR * pCounterDescriptions); typedef VkResult (GLAD_API_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t * pPhysicalDeviceCount, VkPhysicalDevice * pPhysicalDevices); +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef void (GLAD_API_PTR *PFN_vkExportMetalObjectsEXT)(VkDevice device, VkExportMetalObjectsInfoEXT * pMetalObjectsInfo); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange * pMemoryRanges); typedef void (GLAD_API_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer * pCommandBuffers); typedef VkResult (GLAD_API_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet * pDescriptorSets); typedef void (GLAD_API_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks * pAllocator); -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkGetAccelerationStructureBuildSizesKHR)(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkAccelerationStructureBuildGeometryInfoKHR * pBuildInfo, const uint32_t * pMaxPrimitiveCounts, VkAccelerationStructureBuildSizesInfoKHR * pSizeInfo); typedef VkDeviceAddress (GLAD_API_PTR *PFN_vkGetAccelerationStructureDeviceAddressKHR)(VkDevice device, const VkAccelerationStructureDeviceAddressInfoKHR * pInfo); -#endif -typedef VkResult (GLAD_API_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, size_t dataSize, void * pData); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef void (GLAD_API_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsKHR)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoKHR * pInfo, VkMemoryRequirements2 * pMemoryRequirements); -#endif +typedef VkResult (GLAD_API_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void * pData); typedef void (GLAD_API_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV * pInfo, VkMemoryRequirements2KHR * pMemoryRequirements); +typedef VkResult (GLAD_API_PTR *PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkAccelerationStructureCaptureDescriptorDataInfoEXT * pInfo, void * pData); #if defined(VK_USE_PLATFORM_ANDROID_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetAndroidHardwareBufferPropertiesANDROID)(VkDevice device, const struct AHardwareBuffer * buffer, VkAndroidHardwareBufferPropertiesANDROID * pProperties); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkGetBufferCollectionPropertiesFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, VkBufferCollectionPropertiesFUCHSIA * pProperties); + #endif typedef VkDeviceAddress (GLAD_API_PTR *PFN_vkGetBufferDeviceAddress)(VkDevice device, const VkBufferDeviceAddressInfo * pInfo); typedef VkDeviceAddress (GLAD_API_PTR *PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfo * pInfo); @@ -9676,75 +17404,142 @@ typedef void (GLAD_API_PTR *PFN_vkGetBufferMemoryRequirements2)(VkDevice device, typedef void (GLAD_API_PTR *PFN_vkGetBufferMemoryRequirements2KHR)(VkDevice device, const VkBufferMemoryRequirementsInfo2 * pInfo, VkMemoryRequirements2 * pMemoryRequirements); typedef uint64_t (GLAD_API_PTR *PFN_vkGetBufferOpaqueCaptureAddress)(VkDevice device, const VkBufferDeviceAddressInfo * pInfo); typedef uint64_t (GLAD_API_PTR *PFN_vkGetBufferOpaqueCaptureAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfo * pInfo); -typedef VkResult (GLAD_API_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT * pTimestampInfos, uint64_t * pTimestamps, uint64_t * pMaxDeviation); +typedef VkResult (GLAD_API_PTR *PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkBufferCaptureDescriptorDataInfoEXT * pInfo, void * pData); +typedef VkResult (GLAD_API_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoKHR * pTimestampInfos, uint64_t * pTimestamps, uint64_t * pMaxDeviation); +typedef VkResult (GLAD_API_PTR *PFN_vkGetCalibratedTimestampsKHR)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoKHR * pTimestampInfos, uint64_t * pTimestamps, uint64_t * pMaxDeviation); +typedef void (GLAD_API_PTR *PFN_vkGetClusterAccelerationStructureBuildSizesNV)(VkDevice device, const VkClusterAccelerationStructureInputInfoNV * pInfo, VkAccelerationStructureBuildSizesInfoKHR * pSizeInfo); #if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef uint32_t (GLAD_API_PTR *PFN_vkGetDeferredOperationMaxConcurrencyKHR)(VkDevice device, VkDeferredOperationKHR operation); +typedef VkResult (GLAD_API_PTR *PFN_vkGetCudaModuleCacheNV)(VkDevice device, VkCudaModuleNV module, size_t * pCacheSize, void * pCacheData); + #endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef uint32_t (GLAD_API_PTR *PFN_vkGetDeferredOperationMaxConcurrencyKHR)(VkDevice device, VkDeferredOperationKHR operation); typedef VkResult (GLAD_API_PTR *PFN_vkGetDeferredOperationResultKHR)(VkDevice device, VkDeferredOperationKHR operation); -#endif +typedef void (GLAD_API_PTR *PFN_vkGetDescriptorEXT)(VkDevice device, const VkDescriptorGetInfoEXT * pDescriptorInfo, size_t dataSize, void * pDescriptor); +typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetHostMappingVALVE)(VkDevice device, VkDescriptorSet descriptorSet, void ** ppData); +typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetLayoutBindingOffsetEXT)(VkDevice device, VkDescriptorSetLayout layout, uint32_t binding, VkDeviceSize * pOffset); +typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE)(VkDevice device, const VkDescriptorSetBindingReferenceVALVE * pBindingReference, VkDescriptorSetLayoutHostMappingInfoVALVE * pHostMapping); +typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetLayoutSizeEXT)(VkDevice device, VkDescriptorSetLayout layout, VkDeviceSize * pLayoutSizeInBytes); typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetLayoutSupport)(VkDevice device, const VkDescriptorSetLayoutCreateInfo * pCreateInfo, VkDescriptorSetLayoutSupport * pSupport); typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo * pCreateInfo, VkDescriptorSetLayoutSupport * pSupport); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)(VkDevice device, const VkAccelerationStructureVersionKHR * version); -#endif +typedef void (GLAD_API_PTR *PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)(VkDevice device, const VkAccelerationStructureVersionInfoKHR * pVersionInfo, VkAccelerationStructureCompatibilityKHR * pCompatibility); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceBufferMemoryRequirements)(VkDevice device, const VkDeviceBufferMemoryRequirements * pInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceBufferMemoryRequirementsKHR)(VkDevice device, const VkDeviceBufferMemoryRequirements * pInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceFaultInfoEXT)(VkDevice device, VkDeviceFaultCountsEXT * pFaultCounts, VkDeviceFaultInfoEXT * pFaultInfo); typedef void (GLAD_API_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags * pPeerMemoryFeatures); typedef void (GLAD_API_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags * pPeerMemoryFeatures); typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR * pDeviceGroupPresentCapabilities); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceGroupSurfacePresentModes2EXT)(VkDevice device, const VkPhysicalDeviceSurfaceInfo2KHR * pSurfaceInfo, VkDeviceGroupPresentModeFlagsKHR * pModes); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR * pModes); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageMemoryRequirements)(VkDevice device, const VkDeviceImageMemoryRequirements * pInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageMemoryRequirementsKHR)(VkDevice device, const VkDeviceImageMemoryRequirements * pInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageSparseMemoryRequirements)(VkDevice device, const VkDeviceImageMemoryRequirements * pInfo, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageSparseMemoryRequirementsKHR)(VkDevice device, const VkDeviceImageMemoryRequirements * pInfo, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageSubresourceLayout)(VkDevice device, const VkDeviceImageSubresourceInfo * pInfo, VkSubresourceLayout2 * pLayout); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageSubresourceLayoutKHR)(VkDevice device, const VkDeviceImageSubresourceInfo * pInfo, VkSubresourceLayout2 * pLayout); typedef void (GLAD_API_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize * pCommittedMemoryInBytes); typedef uint64_t (GLAD_API_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddress)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo * pInfo); typedef uint64_t (GLAD_API_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo * pInfo); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceMicromapCompatibilityEXT)(VkDevice device, const VkMicromapVersionInfoEXT * pVersionInfo, VkAccelerationStructureCompatibilityKHR * pCompatibility); typedef PFN_vkVoidFunction (GLAD_API_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char * pName); typedef void (GLAD_API_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue * pQueue); typedef void (GLAD_API_PTR *PFN_vkGetDeviceQueue2)(VkDevice device, const VkDeviceQueueInfo2 * pQueueInfo, VkQueue * pQueue); +typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI)(VkDevice device, VkRenderPass renderpass, VkExtent2D * pMaxWorkgroupSize); typedef VkResult (GLAD_API_PTR *PFN_vkGetDisplayModeProperties2KHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t * pPropertyCount, VkDisplayModeProperties2KHR * pProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t * pPropertyCount, VkDisplayModePropertiesKHR * pProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetDisplayPlaneCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkDisplayPlaneInfo2KHR * pDisplayPlaneInfo, VkDisplayPlaneCapabilities2KHR * pCapabilities); typedef VkResult (GLAD_API_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR * pCapabilities); typedef VkResult (GLAD_API_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t * pDisplayCount, VkDisplayKHR * pDisplays); +typedef VkResult (GLAD_API_PTR *PFN_vkGetDrmDisplayEXT)(VkPhysicalDevice physicalDevice, int32_t drmFd, uint32_t connectorId, VkDisplayKHR * display); +typedef VkResult (GLAD_API_PTR *PFN_vkGetDynamicRenderingTilePropertiesQCOM)(VkDevice device, const VkRenderingInfo * pRenderingInfo, VkTilePropertiesQCOM * pProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef VkResult (GLAD_API_PTR *PFN_vkGetExecutionGraphPipelineNodeIndexAMDX)(VkDevice device, VkPipeline executionGraph, const VkPipelineShaderStageNodeCreateInfoAMDX * pNodeInfo, uint32_t * pNodeIndex); + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef VkResult (GLAD_API_PTR *PFN_vkGetExecutionGraphPipelineScratchSizeAMDX)(VkDevice device, VkPipeline executionGraph, VkExecutionGraphPipelineScratchSizeAMDX * pSizeInfo); + +#endif +typedef void (GLAD_API_PTR *PFN_vkGetExternalComputeQueueDataNV)(VkExternalComputeQueueNV externalQueue, VkExternalComputeQueueDataParamsNV * params, void * pData); typedef VkResult (GLAD_API_PTR *PFN_vkGetFenceFdKHR)(VkDevice device, const VkFenceGetFdInfoKHR * pGetFdInfo, int * pFd); typedef VkResult (GLAD_API_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetFenceWin32HandleKHR)(VkDevice device, const VkFenceGetWin32HandleInfoKHR * pGetWin32HandleInfo, HANDLE * pHandle); + #endif +typedef VkResult (GLAD_API_PTR *PFN_vkGetFramebufferTilePropertiesQCOM)(VkDevice device, VkFramebuffer framebuffer, uint32_t * pPropertiesCount, VkTilePropertiesQCOM * pProperties); +typedef void (GLAD_API_PTR *PFN_vkGetGeneratedCommandsMemoryRequirementsEXT)(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoEXT * pInfo, VkMemoryRequirements2 * pMemoryRequirements); typedef void (GLAD_API_PTR *PFN_vkGetGeneratedCommandsMemoryRequirementsNV)(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoNV * pInfo, VkMemoryRequirements2 * pMemoryRequirements); typedef VkResult (GLAD_API_PTR *PFN_vkGetImageDrmFormatModifierPropertiesEXT)(VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT * pProperties); typedef void (GLAD_API_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements * pMemoryRequirements); typedef void (GLAD_API_PTR *PFN_vkGetImageMemoryRequirements2)(VkDevice device, const VkImageMemoryRequirementsInfo2 * pInfo, VkMemoryRequirements2 * pMemoryRequirements); typedef void (GLAD_API_PTR *PFN_vkGetImageMemoryRequirements2KHR)(VkDevice device, const VkImageMemoryRequirementsInfo2 * pInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef VkResult (GLAD_API_PTR *PFN_vkGetImageOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkImageCaptureDescriptorDataInfoEXT * pInfo, void * pData); typedef void (GLAD_API_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements * pSparseMemoryRequirements); typedef void (GLAD_API_PTR *PFN_vkGetImageSparseMemoryRequirements2)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2 * pInfo, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements); typedef void (GLAD_API_PTR *PFN_vkGetImageSparseMemoryRequirements2KHR)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2 * pInfo, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements); typedef void (GLAD_API_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource * pSubresource, VkSubresourceLayout * pLayout); +typedef void (GLAD_API_PTR *PFN_vkGetImageSubresourceLayout2)(VkDevice device, VkImage image, const VkImageSubresource2 * pSubresource, VkSubresourceLayout2 * pLayout); +typedef void (GLAD_API_PTR *PFN_vkGetImageSubresourceLayout2EXT)(VkDevice device, VkImage image, const VkImageSubresource2 * pSubresource, VkSubresourceLayout2 * pLayout); +typedef void (GLAD_API_PTR *PFN_vkGetImageSubresourceLayout2KHR)(VkDevice device, VkImage image, const VkImageSubresource2 * pSubresource, VkSubresourceLayout2 * pLayout); typedef VkResult (GLAD_API_PTR *PFN_vkGetImageViewAddressNVX)(VkDevice device, VkImageView imageView, VkImageViewAddressPropertiesNVX * pProperties); +typedef uint64_t (GLAD_API_PTR *PFN_vkGetImageViewHandle64NVX)(VkDevice device, const VkImageViewHandleInfoNVX * pInfo); typedef uint32_t (GLAD_API_PTR *PFN_vkGetImageViewHandleNVX)(VkDevice device, const VkImageViewHandleInfoNVX * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkImageViewCaptureDescriptorDataInfoEXT * pInfo, void * pData); typedef PFN_vkVoidFunction (GLAD_API_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char * pName); +typedef void (GLAD_API_PTR *PFN_vkGetLatencyTimingsNV)(VkDevice device, VkSwapchainKHR swapchain, VkGetLatencyMarkerInfoNV * pLatencyMarkerInfo); #if defined(VK_USE_PLATFORM_ANDROID_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryAndroidHardwareBufferANDROID)(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID * pInfo, struct AHardwareBuffer ** pBuffer); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryFdKHR)(VkDevice device, const VkMemoryGetFdInfoKHR * pGetFdInfo, int * pFd); typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryFdPropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR * pMemoryFdProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryHostPointerPropertiesEXT)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void * pHostPointer, VkMemoryHostPointerPropertiesEXT * pMemoryHostPointerProperties); +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryMetalHandleEXT)(VkDevice device, const VkMemoryGetMetalHandleInfoEXT * pGetMetalHandleInfo, void ** pHandle); + +#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryMetalHandlePropertiesEXT)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void * pHandle, VkMemoryMetalHandlePropertiesEXT * pMemoryMetalHandleProperties); + +#endif +typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryRemoteAddressNV)(VkDevice device, const VkMemoryGetRemoteAddressInfoNV * pMemoryGetRemoteAddressInfo, VkRemoteAddressNV * pAddress); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryWin32HandleKHR)(VkDevice device, const VkMemoryGetWin32HandleInfoKHR * pGetWin32HandleInfo, HANDLE * pHandle); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryWin32HandleNV)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagsNV handleType, HANDLE * pHandle); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR * pMemoryWin32HandleProperties); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryZirconHandleFUCHSIA)(VkDevice device, const VkMemoryGetZirconHandleInfoFUCHSIA * pGetZirconHandleInfo, zx_handle_t * pZirconHandle); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, zx_handle_t zirconHandle, VkMemoryZirconHandlePropertiesFUCHSIA * pMemoryZirconHandleProperties); + #endif +typedef void (GLAD_API_PTR *PFN_vkGetMicromapBuildSizesEXT)(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkMicromapBuildInfoEXT * pBuildInfo, VkMicromapBuildSizesInfoEXT * pSizeInfo); +typedef void (GLAD_API_PTR *PFN_vkGetPartitionedAccelerationStructuresBuildSizesNV)(VkDevice device, const VkPartitionedAccelerationStructureInstancesInputNV * pInfo, VkAccelerationStructureBuildSizesInfoKHR * pSizeInfo); typedef VkResult (GLAD_API_PTR *PFN_vkGetPastPresentationTimingGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, uint32_t * pPresentationTimingCount, VkPastPresentationTimingGOOGLE * pPresentationTimings); typedef VkResult (GLAD_API_PTR *PFN_vkGetPerformanceParameterINTEL)(VkDevice device, VkPerformanceParameterTypeINTEL parameter, VkPerformanceValueINTEL * pValue); -typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t * pTimeDomainCount, VkTimeDomainEXT * pTimeDomains); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t * pTimeDomainCount, VkTimeDomainKHR * pTimeDomains); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR)(VkPhysicalDevice physicalDevice, uint32_t * pTimeDomainCount, VkTimeDomainKHR * pTimeDomains); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkCooperativeMatrixFlexibleDimensionsPropertiesNV * pProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkCooperativeMatrixPropertiesKHR * pProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkCooperativeMatrixPropertiesNV * pProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCooperativeVectorPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkCooperativeVectorPropertiesNV * pProperties); #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) typedef VkBool32 (GLAD_API_PTR *PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, IDirectFB * dfb); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkDisplayPlaneProperties2KHR * pProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkDisplayPlanePropertiesKHR * pProperties); @@ -9763,6 +17558,7 @@ typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevic typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties * pFormatProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 * pFormatProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 * pFormatProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR)(VkPhysicalDevice physicalDevice, uint32_t * pFragmentShadingRateCount, VkPhysicalDeviceFragmentShadingRateKHR * pFragmentShadingRates); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties * pImageFormatProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo, VkImageFormatProperties2 * pImageFormatProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo, VkImageFormatProperties2 * pImageFormatProperties); @@ -9770,6 +17566,7 @@ typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalD typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 * pMemoryProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 * pMemoryProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)(VkPhysicalDevice physicalDevice, VkSampleCountFlagBits samples, VkMultisamplePropertiesEXT * pMultisampleProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV)(VkPhysicalDevice physicalDevice, const VkOpticalFlowImageFormatInfoNV * pOpticalFlowImageFormatInfo, uint32_t * pFormatCount, VkOpticalFlowImageFormatPropertiesNV * pImageFormatProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t * pRectCount, VkRect2D * pRects); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties * pProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 * pProperties); @@ -9778,6 +17575,10 @@ typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPa typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t * pQueueFamilyPropertyCount, VkQueueFamilyProperties * pQueueFamilyProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice physicalDevice, uint32_t * pQueueFamilyPropertyCount, VkQueueFamilyProperties2 * pQueueFamilyProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t * pQueueFamilyPropertyCount, VkQueueFamilyProperties2 * pQueueFamilyProperties); +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef VkBool32 (GLAD_API_PTR *PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct _screen_window * window); + +#endif typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t * pPropertyCount, VkSparseImageFormatProperties * pProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 * pFormatInfo, uint32_t * pPropertyCount, VkSparseImageFormatProperties2 * pProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 * pFormatInfo, uint32_t * pPropertyCount, VkSparseImageFormatProperties2 * pProperties); @@ -9789,81 +17590,126 @@ typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhy typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t * pSurfaceFormatCount, VkSurfaceFormatKHR * pSurfaceFormats); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR * pSurfaceInfo, uint32_t * pPresentModeCount, VkPresentModeKHR * pPresentModes); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t * pPresentModeCount, VkPresentModeKHR * pPresentModes); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32 * pSupported); -typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceToolPropertiesEXT)(VkPhysicalDevice physicalDevice, uint32_t * pToolCount, VkPhysicalDeviceToolPropertiesEXT * pToolProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceToolProperties)(VkPhysicalDevice physicalDevice, uint32_t * pToolCount, VkPhysicalDeviceToolProperties * pToolProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceToolPropertiesEXT)(VkPhysicalDevice physicalDevice, uint32_t * pToolCount, VkPhysicalDeviceToolProperties * pToolProperties); #if defined(VK_USE_PLATFORM_WAYLAND_KHR) typedef VkBool32 (GLAD_API_PTR *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display * display); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkBool32 (GLAD_API_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex); + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) typedef VkBool32 (GLAD_API_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t * connection, xcb_visualid_t visual_id); + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) typedef VkBool32 (GLAD_API_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display * dpy, VisualID visualID); + #endif +typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineBinaryDataKHR)(VkDevice device, const VkPipelineBinaryDataInfoKHR * pInfo, VkPipelineBinaryKeyKHR * pPipelineBinaryKey, size_t * pPipelineBinaryDataSize, void * pPipelineBinaryData); typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t * pDataSize, void * pData); typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineExecutableInternalRepresentationsKHR)(VkDevice device, const VkPipelineExecutableInfoKHR * pExecutableInfo, uint32_t * pInternalRepresentationCount, VkPipelineExecutableInternalRepresentationKHR * pInternalRepresentations); typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineExecutablePropertiesKHR)(VkDevice device, const VkPipelineInfoKHR * pPipelineInfo, uint32_t * pExecutableCount, VkPipelineExecutablePropertiesKHR * pProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineExecutableStatisticsKHR)(VkDevice device, const VkPipelineExecutableInfoKHR * pExecutableInfo, uint32_t * pStatisticCount, VkPipelineExecutableStatisticKHR * pStatistics); -typedef void (GLAD_API_PTR *PFN_vkGetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlotEXT privateDataSlot, uint64_t * pData); +typedef VkDeviceAddress (GLAD_API_PTR *PFN_vkGetPipelineIndirectDeviceAddressNV)(VkDevice device, const VkPipelineIndirectDeviceAddressInfoNV * pInfo); +typedef void (GLAD_API_PTR *PFN_vkGetPipelineIndirectMemoryRequirementsNV)(VkDevice device, const VkComputePipelineCreateInfo * pCreateInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineKeyKHR)(VkDevice device, const VkPipelineCreateInfoKHR * pPipelineCreateInfo, VkPipelineBinaryKeyKHR * pPipelineKey); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelinePropertiesEXT)(VkDevice device, const VkPipelineInfoEXT * pPipelineInfo, VkBaseOutStructure * pPipelineProperties); +typedef void (GLAD_API_PTR *PFN_vkGetPrivateData)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t * pData); +typedef void (GLAD_API_PTR *PFN_vkGetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t * pData); typedef VkResult (GLAD_API_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void * pData, VkDeviceSize stride, VkQueryResultFlags flags); +typedef void (GLAD_API_PTR *PFN_vkGetQueueCheckpointData2NV)(VkQueue queue, uint32_t * pCheckpointDataCount, VkCheckpointData2NV * pCheckpointData); typedef void (GLAD_API_PTR *PFN_vkGetQueueCheckpointDataNV)(VkQueue queue, uint32_t * pCheckpointDataCount, VkCheckpointDataNV * pCheckpointData); #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) typedef VkResult (GLAD_API_PTR *PFN_vkGetRandROutputDisplayEXT)(VkPhysicalDevice physicalDevice, Display * dpy, RROutput rrOutput, VkDisplayKHR * pDisplay); + #endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef VkResult (GLAD_API_PTR *PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void * pData); -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef VkResult (GLAD_API_PTR *PFN_vkGetRayTracingShaderGroupHandlesKHR)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void * pData); -#endif typedef VkResult (GLAD_API_PTR *PFN_vkGetRayTracingShaderGroupHandlesNV)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void * pData); +typedef VkDeviceSize (GLAD_API_PTR *PFN_vkGetRayTracingShaderGroupStackSizeKHR)(VkDevice device, VkPipeline pipeline, uint32_t group, VkShaderGroupShaderKHR groupShader); typedef VkResult (GLAD_API_PTR *PFN_vkGetRefreshCycleDurationGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE * pDisplayTimingProperties); typedef void (GLAD_API_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D * pGranularity); +typedef void (GLAD_API_PTR *PFN_vkGetRenderingAreaGranularity)(VkDevice device, const VkRenderingAreaInfo * pRenderingAreaInfo, VkExtent2D * pGranularity); +typedef void (GLAD_API_PTR *PFN_vkGetRenderingAreaGranularityKHR)(VkDevice device, const VkRenderingAreaInfo * pRenderingAreaInfo, VkExtent2D * pGranularity); +typedef VkResult (GLAD_API_PTR *PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkSamplerCaptureDescriptorDataInfoEXT * pInfo, void * pData); +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef VkResult (GLAD_API_PTR *PFN_vkGetScreenBufferPropertiesQNX)(VkDevice device, const struct _screen_buffer * buffer, VkScreenBufferPropertiesQNX * pProperties); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkGetSemaphoreCounterValue)(VkDevice device, VkSemaphore semaphore, uint64_t * pValue); typedef VkResult (GLAD_API_PTR *PFN_vkGetSemaphoreCounterValueKHR)(VkDevice device, VkSemaphore semaphore, uint64_t * pValue); typedef VkResult (GLAD_API_PTR *PFN_vkGetSemaphoreFdKHR)(VkDevice device, const VkSemaphoreGetFdInfoKHR * pGetFdInfo, int * pFd); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetSemaphoreWin32HandleKHR)(VkDevice device, const VkSemaphoreGetWin32HandleInfoKHR * pGetWin32HandleInfo, HANDLE * pHandle); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkGetSemaphoreZirconHandleFUCHSIA)(VkDevice device, const VkSemaphoreGetZirconHandleInfoFUCHSIA * pGetZirconHandleInfo, zx_handle_t * pZirconHandle); + #endif +typedef VkResult (GLAD_API_PTR *PFN_vkGetShaderBinaryDataEXT)(VkDevice device, VkShaderEXT shader, size_t * pDataSize, void * pData); typedef VkResult (GLAD_API_PTR *PFN_vkGetShaderInfoAMD)(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits shaderStage, VkShaderInfoTypeAMD infoType, size_t * pInfoSize, void * pInfo); +typedef void (GLAD_API_PTR *PFN_vkGetShaderModuleCreateInfoIdentifierEXT)(VkDevice device, const VkShaderModuleCreateInfo * pCreateInfo, VkShaderModuleIdentifierEXT * pIdentifier); +typedef void (GLAD_API_PTR *PFN_vkGetShaderModuleIdentifierEXT)(VkDevice device, VkShaderModule shaderModule, VkShaderModuleIdentifierEXT * pIdentifier); typedef VkResult (GLAD_API_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t * pCounterValue); typedef VkResult (GLAD_API_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t * pSwapchainImageCount, VkImage * pSwapchainImages); typedef VkResult (GLAD_API_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain); typedef VkResult (GLAD_API_PTR *PFN_vkGetValidationCacheDataEXT)(VkDevice device, VkValidationCacheEXT validationCache, size_t * pDataSize, void * pData); +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef VkResult (GLAD_API_PTR *PFN_vkGetWinrtDisplayNV)(VkPhysicalDevice physicalDevice, uint32_t deviceRelativeId, VkDisplayKHR * pDisplay); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkImportFenceFdKHR)(VkDevice device, const VkImportFenceFdInfoKHR * pImportFenceFdInfo); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkImportFenceWin32HandleKHR)(VkDevice device, const VkImportFenceWin32HandleInfoKHR * pImportFenceWin32HandleInfo); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkImportSemaphoreFdKHR)(VkDevice device, const VkImportSemaphoreFdInfoKHR * pImportSemaphoreFdInfo); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkImportSemaphoreWin32HandleKHR)(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR * pImportSemaphoreWin32HandleInfo); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkImportSemaphoreZirconHandleFUCHSIA)(VkDevice device, const VkImportSemaphoreZirconHandleInfoFUCHSIA * pImportSemaphoreZirconHandleInfo); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkInitializePerformanceApiINTEL)(VkDevice device, const VkInitializePerformanceApiInfoINTEL * pInitializeInfo); typedef VkResult (GLAD_API_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange * pMemoryRanges); +typedef VkResult (GLAD_API_PTR *PFN_vkLatencySleepNV)(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepInfoNV * pSleepInfo); typedef VkResult (GLAD_API_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void ** ppData); +typedef VkResult (GLAD_API_PTR *PFN_vkMapMemory2)(VkDevice device, const VkMemoryMapInfo * pMemoryMapInfo, void ** ppData); +typedef VkResult (GLAD_API_PTR *PFN_vkMapMemory2KHR)(VkDevice device, const VkMemoryMapInfo * pMemoryMapInfo, void ** ppData); typedef VkResult (GLAD_API_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache * pSrcCaches); typedef VkResult (GLAD_API_PTR *PFN_vkMergeValidationCachesEXT)(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount, const VkValidationCacheEXT * pSrcCaches); typedef void (GLAD_API_PTR *PFN_vkQueueBeginDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT * pLabelInfo); typedef VkResult (GLAD_API_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo * pBindInfo, VkFence fence); typedef void (GLAD_API_PTR *PFN_vkQueueEndDebugUtilsLabelEXT)(VkQueue queue); typedef void (GLAD_API_PTR *PFN_vkQueueInsertDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT * pLabelInfo); +typedef void (GLAD_API_PTR *PFN_vkQueueNotifyOutOfBandNV)(VkQueue queue, const VkOutOfBandQueueTypeInfoNV * pQueueTypeInfo); typedef VkResult (GLAD_API_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR * pPresentInfo); typedef VkResult (GLAD_API_PTR *PFN_vkQueueSetPerformanceConfigurationINTEL)(VkQueue queue, VkPerformanceConfigurationINTEL configuration); typedef VkResult (GLAD_API_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo * pSubmits, VkFence fence); +typedef VkResult (GLAD_API_PTR *PFN_vkQueueSubmit2)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 * pSubmits, VkFence fence); +typedef VkResult (GLAD_API_PTR *PFN_vkQueueSubmit2KHR)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 * pSubmits, VkFence fence); typedef VkResult (GLAD_API_PTR *PFN_vkQueueWaitIdle)(VkQueue queue); typedef VkResult (GLAD_API_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT * pDeviceEventInfo, const VkAllocationCallbacks * pAllocator, VkFence * pFence); typedef VkResult (GLAD_API_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT * pDisplayEventInfo, const VkAllocationCallbacks * pAllocator, VkFence * pFence); +typedef VkResult (GLAD_API_PTR *PFN_vkReleaseCapturedPipelineDataKHR)(VkDevice device, const VkReleaseCapturedPipelineDataInfoKHR * pInfo, const VkAllocationCallbacks * pAllocator); typedef VkResult (GLAD_API_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkReleaseFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkReleasePerformanceConfigurationINTEL)(VkDevice device, VkPerformanceConfigurationINTEL configuration); typedef void (GLAD_API_PTR *PFN_vkReleaseProfilingLockKHR)(VkDevice device); +typedef VkResult (GLAD_API_PTR *PFN_vkReleaseSwapchainImagesEXT)(VkDevice device, const VkReleaseSwapchainImagesInfoEXT * pReleaseInfo); typedef VkResult (GLAD_API_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); typedef VkResult (GLAD_API_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); typedef VkResult (GLAD_API_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); @@ -9871,32 +17717,53 @@ typedef VkResult (GLAD_API_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event typedef VkResult (GLAD_API_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence * pFences); typedef void (GLAD_API_PTR *PFN_vkResetQueryPool)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); typedef void (GLAD_API_PTR *PFN_vkResetQueryPoolEXT)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkBufferConstraintsInfoFUCHSIA * pBufferConstraintsInfo); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkSetBufferCollectionImageConstraintsFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkImageConstraintsInfoFUCHSIA * pImageConstraintsInfo); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkSetDebugUtilsObjectNameEXT)(VkDevice device, const VkDebugUtilsObjectNameInfoEXT * pNameInfo); typedef VkResult (GLAD_API_PTR *PFN_vkSetDebugUtilsObjectTagEXT)(VkDevice device, const VkDebugUtilsObjectTagInfoEXT * pTagInfo); +typedef void (GLAD_API_PTR *PFN_vkSetDeviceMemoryPriorityEXT)(VkDevice device, VkDeviceMemory memory, float priority); typedef VkResult (GLAD_API_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event); typedef void (GLAD_API_PTR *PFN_vkSetHdrMetadataEXT)(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR * pSwapchains, const VkHdrMetadataEXT * pMetadata); +typedef void (GLAD_API_PTR *PFN_vkSetLatencyMarkerNV)(VkDevice device, VkSwapchainKHR swapchain, const VkSetLatencyMarkerInfoNV * pLatencyMarkerInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkSetLatencySleepModeNV)(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepModeInfoNV * pSleepModeInfo); typedef void (GLAD_API_PTR *PFN_vkSetLocalDimmingAMD)(VkDevice device, VkSwapchainKHR swapChain, VkBool32 localDimmingEnable); -typedef VkResult (GLAD_API_PTR *PFN_vkSetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlotEXT privateDataSlot, uint64_t data); +typedef VkResult (GLAD_API_PTR *PFN_vkSetPrivateData)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data); +typedef VkResult (GLAD_API_PTR *PFN_vkSetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data); typedef VkResult (GLAD_API_PTR *PFN_vkSignalSemaphore)(VkDevice device, const VkSemaphoreSignalInfo * pSignalInfo); typedef VkResult (GLAD_API_PTR *PFN_vkSignalSemaphoreKHR)(VkDevice device, const VkSemaphoreSignalInfo * pSignalInfo); typedef void (GLAD_API_PTR *PFN_vkSubmitDebugUtilsMessageEXT)(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT * pCallbackData); +typedef VkResult (GLAD_API_PTR *PFN_vkTransitionImageLayout)(VkDevice device, uint32_t transitionCount, const VkHostImageLayoutTransitionInfo * pTransitions); +typedef VkResult (GLAD_API_PTR *PFN_vkTransitionImageLayoutEXT)(VkDevice device, uint32_t transitionCount, const VkHostImageLayoutTransitionInfo * pTransitions); typedef void (GLAD_API_PTR *PFN_vkTrimCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); typedef void (GLAD_API_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); typedef void (GLAD_API_PTR *PFN_vkUninitializePerformanceApiINTEL)(VkDevice device); typedef void (GLAD_API_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory); +typedef VkResult (GLAD_API_PTR *PFN_vkUnmapMemory2)(VkDevice device, const VkMemoryUnmapInfo * pMemoryUnmapInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkUnmapMemory2KHR)(VkDevice device, const VkMemoryUnmapInfo * pMemoryUnmapInfo); typedef void (GLAD_API_PTR *PFN_vkUpdateDescriptorSetWithTemplate)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void * pData); typedef void (GLAD_API_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void * pData); typedef void (GLAD_API_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet * pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet * pDescriptorCopies); +typedef void (GLAD_API_PTR *PFN_vkUpdateIndirectExecutionSetPipelineEXT)(VkDevice device, VkIndirectExecutionSetEXT indirectExecutionSet, uint32_t executionSetWriteCount, const VkWriteIndirectExecutionSetPipelineEXT * pExecutionSetWrites); +typedef void (GLAD_API_PTR *PFN_vkUpdateIndirectExecutionSetShaderEXT)(VkDevice device, VkIndirectExecutionSetEXT indirectExecutionSet, uint32_t executionSetWriteCount, const VkWriteIndirectExecutionSetShaderEXT * pExecutionSetWrites); typedef VkResult (GLAD_API_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence * pFences, VkBool32 waitAll, uint64_t timeout); +typedef VkResult (GLAD_API_PTR *PFN_vkWaitForPresentKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t presentId, uint64_t timeout); typedef VkResult (GLAD_API_PTR *PFN_vkWaitSemaphores)(VkDevice device, const VkSemaphoreWaitInfo * pWaitInfo, uint64_t timeout); typedef VkResult (GLAD_API_PTR *PFN_vkWaitSemaphoresKHR)(VkDevice device, const VkSemaphoreWaitInfo * pWaitInfo, uint64_t timeout); -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef VkResult (GLAD_API_PTR *PFN_vkWriteAccelerationStructuresPropertiesKHR)(VkDevice device, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR * pAccelerationStructures, VkQueryType queryType, size_t dataSize, void * pData, size_t stride); -#endif +typedef VkResult (GLAD_API_PTR *PFN_vkWriteMicromapsPropertiesEXT)(VkDevice device, uint32_t micromapCount, const VkMicromapEXT * pMicromaps, VkQueryType queryType, size_t dataSize, void * pData, size_t stride); +GLAD_API_CALL PFN_vkAcquireDrmDisplayEXT glad_vkAcquireDrmDisplayEXT; +#define vkAcquireDrmDisplayEXT glad_vkAcquireDrmDisplayEXT #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkAcquireFullScreenExclusiveModeEXT glad_vkAcquireFullScreenExclusiveModeEXT; #define vkAcquireFullScreenExclusiveModeEXT glad_vkAcquireFullScreenExclusiveModeEXT + #endif GLAD_API_CALL PFN_vkAcquireNextImage2KHR glad_vkAcquireNextImage2KHR; #define vkAcquireNextImage2KHR glad_vkAcquireNextImage2KHR @@ -9906,9 +17773,15 @@ GLAD_API_CALL PFN_vkAcquirePerformanceConfigurationINTEL glad_vkAcquirePerforman #define vkAcquirePerformanceConfigurationINTEL glad_vkAcquirePerformanceConfigurationINTEL GLAD_API_CALL PFN_vkAcquireProfilingLockKHR glad_vkAcquireProfilingLockKHR; #define vkAcquireProfilingLockKHR glad_vkAcquireProfilingLockKHR +#if defined(VK_USE_PLATFORM_WIN32_KHR) +GLAD_API_CALL PFN_vkAcquireWinrtDisplayNV glad_vkAcquireWinrtDisplayNV; +#define vkAcquireWinrtDisplayNV glad_vkAcquireWinrtDisplayNV + +#endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) GLAD_API_CALL PFN_vkAcquireXlibDisplayEXT glad_vkAcquireXlibDisplayEXT; #define vkAcquireXlibDisplayEXT glad_vkAcquireXlibDisplayEXT + #endif GLAD_API_CALL PFN_vkAllocateCommandBuffers glad_vkAllocateCommandBuffers; #define vkAllocateCommandBuffers glad_vkAllocateCommandBuffers @@ -9916,12 +17789,10 @@ GLAD_API_CALL PFN_vkAllocateDescriptorSets glad_vkAllocateDescriptorSets; #define vkAllocateDescriptorSets glad_vkAllocateDescriptorSets GLAD_API_CALL PFN_vkAllocateMemory glad_vkAllocateMemory; #define vkAllocateMemory glad_vkAllocateMemory +GLAD_API_CALL PFN_vkAntiLagUpdateAMD glad_vkAntiLagUpdateAMD; +#define vkAntiLagUpdateAMD glad_vkAntiLagUpdateAMD GLAD_API_CALL PFN_vkBeginCommandBuffer glad_vkBeginCommandBuffer; #define vkBeginCommandBuffer glad_vkBeginCommandBuffer -#if defined(VK_ENABLE_BETA_EXTENSIONS) -GLAD_API_CALL PFN_vkBindAccelerationStructureMemoryKHR glad_vkBindAccelerationStructureMemoryKHR; -#define vkBindAccelerationStructureMemoryKHR glad_vkBindAccelerationStructureMemoryKHR -#endif GLAD_API_CALL PFN_vkBindAccelerationStructureMemoryNV glad_vkBindAccelerationStructureMemoryNV; #define vkBindAccelerationStructureMemoryNV glad_vkBindAccelerationStructureMemoryNV GLAD_API_CALL PFN_vkBindBufferMemory glad_vkBindBufferMemory; @@ -9936,14 +17807,18 @@ GLAD_API_CALL PFN_vkBindImageMemory2 glad_vkBindImageMemory2; #define vkBindImageMemory2 glad_vkBindImageMemory2 GLAD_API_CALL PFN_vkBindImageMemory2KHR glad_vkBindImageMemory2KHR; #define vkBindImageMemory2KHR glad_vkBindImageMemory2KHR -#if defined(VK_ENABLE_BETA_EXTENSIONS) -GLAD_API_CALL PFN_vkBuildAccelerationStructureKHR glad_vkBuildAccelerationStructureKHR; -#define vkBuildAccelerationStructureKHR glad_vkBuildAccelerationStructureKHR -#endif +GLAD_API_CALL PFN_vkBindOpticalFlowSessionImageNV glad_vkBindOpticalFlowSessionImageNV; +#define vkBindOpticalFlowSessionImageNV glad_vkBindOpticalFlowSessionImageNV +GLAD_API_CALL PFN_vkBuildAccelerationStructuresKHR glad_vkBuildAccelerationStructuresKHR; +#define vkBuildAccelerationStructuresKHR glad_vkBuildAccelerationStructuresKHR +GLAD_API_CALL PFN_vkBuildMicromapsEXT glad_vkBuildMicromapsEXT; +#define vkBuildMicromapsEXT glad_vkBuildMicromapsEXT GLAD_API_CALL PFN_vkCmdBeginConditionalRenderingEXT glad_vkCmdBeginConditionalRenderingEXT; #define vkCmdBeginConditionalRenderingEXT glad_vkCmdBeginConditionalRenderingEXT GLAD_API_CALL PFN_vkCmdBeginDebugUtilsLabelEXT glad_vkCmdBeginDebugUtilsLabelEXT; #define vkCmdBeginDebugUtilsLabelEXT glad_vkCmdBeginDebugUtilsLabelEXT +GLAD_API_CALL PFN_vkCmdBeginPerTileExecutionQCOM glad_vkCmdBeginPerTileExecutionQCOM; +#define vkCmdBeginPerTileExecutionQCOM glad_vkCmdBeginPerTileExecutionQCOM GLAD_API_CALL PFN_vkCmdBeginQuery glad_vkCmdBeginQuery; #define vkCmdBeginQuery glad_vkCmdBeginQuery GLAD_API_CALL PFN_vkCmdBeginQueryIndexedEXT glad_vkCmdBeginQueryIndexedEXT; @@ -9954,82 +17829,168 @@ GLAD_API_CALL PFN_vkCmdBeginRenderPass2 glad_vkCmdBeginRenderPass2; #define vkCmdBeginRenderPass2 glad_vkCmdBeginRenderPass2 GLAD_API_CALL PFN_vkCmdBeginRenderPass2KHR glad_vkCmdBeginRenderPass2KHR; #define vkCmdBeginRenderPass2KHR glad_vkCmdBeginRenderPass2KHR +GLAD_API_CALL PFN_vkCmdBeginRendering glad_vkCmdBeginRendering; +#define vkCmdBeginRendering glad_vkCmdBeginRendering +GLAD_API_CALL PFN_vkCmdBeginRenderingKHR glad_vkCmdBeginRenderingKHR; +#define vkCmdBeginRenderingKHR glad_vkCmdBeginRenderingKHR GLAD_API_CALL PFN_vkCmdBeginTransformFeedbackEXT glad_vkCmdBeginTransformFeedbackEXT; #define vkCmdBeginTransformFeedbackEXT glad_vkCmdBeginTransformFeedbackEXT +GLAD_API_CALL PFN_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT glad_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT; +#define vkCmdBindDescriptorBufferEmbeddedSamplers2EXT glad_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT +GLAD_API_CALL PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT glad_vkCmdBindDescriptorBufferEmbeddedSamplersEXT; +#define vkCmdBindDescriptorBufferEmbeddedSamplersEXT glad_vkCmdBindDescriptorBufferEmbeddedSamplersEXT +GLAD_API_CALL PFN_vkCmdBindDescriptorBuffersEXT glad_vkCmdBindDescriptorBuffersEXT; +#define vkCmdBindDescriptorBuffersEXT glad_vkCmdBindDescriptorBuffersEXT GLAD_API_CALL PFN_vkCmdBindDescriptorSets glad_vkCmdBindDescriptorSets; #define vkCmdBindDescriptorSets glad_vkCmdBindDescriptorSets +GLAD_API_CALL PFN_vkCmdBindDescriptorSets2 glad_vkCmdBindDescriptorSets2; +#define vkCmdBindDescriptorSets2 glad_vkCmdBindDescriptorSets2 +GLAD_API_CALL PFN_vkCmdBindDescriptorSets2KHR glad_vkCmdBindDescriptorSets2KHR; +#define vkCmdBindDescriptorSets2KHR glad_vkCmdBindDescriptorSets2KHR GLAD_API_CALL PFN_vkCmdBindIndexBuffer glad_vkCmdBindIndexBuffer; #define vkCmdBindIndexBuffer glad_vkCmdBindIndexBuffer +GLAD_API_CALL PFN_vkCmdBindIndexBuffer2 glad_vkCmdBindIndexBuffer2; +#define vkCmdBindIndexBuffer2 glad_vkCmdBindIndexBuffer2 +GLAD_API_CALL PFN_vkCmdBindIndexBuffer2KHR glad_vkCmdBindIndexBuffer2KHR; +#define vkCmdBindIndexBuffer2KHR glad_vkCmdBindIndexBuffer2KHR +GLAD_API_CALL PFN_vkCmdBindInvocationMaskHUAWEI glad_vkCmdBindInvocationMaskHUAWEI; +#define vkCmdBindInvocationMaskHUAWEI glad_vkCmdBindInvocationMaskHUAWEI GLAD_API_CALL PFN_vkCmdBindPipeline glad_vkCmdBindPipeline; #define vkCmdBindPipeline glad_vkCmdBindPipeline GLAD_API_CALL PFN_vkCmdBindPipelineShaderGroupNV glad_vkCmdBindPipelineShaderGroupNV; #define vkCmdBindPipelineShaderGroupNV glad_vkCmdBindPipelineShaderGroupNV +GLAD_API_CALL PFN_vkCmdBindShadersEXT glad_vkCmdBindShadersEXT; +#define vkCmdBindShadersEXT glad_vkCmdBindShadersEXT GLAD_API_CALL PFN_vkCmdBindShadingRateImageNV glad_vkCmdBindShadingRateImageNV; #define vkCmdBindShadingRateImageNV glad_vkCmdBindShadingRateImageNV +GLAD_API_CALL PFN_vkCmdBindTileMemoryQCOM glad_vkCmdBindTileMemoryQCOM; +#define vkCmdBindTileMemoryQCOM glad_vkCmdBindTileMemoryQCOM GLAD_API_CALL PFN_vkCmdBindTransformFeedbackBuffersEXT glad_vkCmdBindTransformFeedbackBuffersEXT; #define vkCmdBindTransformFeedbackBuffersEXT glad_vkCmdBindTransformFeedbackBuffersEXT GLAD_API_CALL PFN_vkCmdBindVertexBuffers glad_vkCmdBindVertexBuffers; #define vkCmdBindVertexBuffers glad_vkCmdBindVertexBuffers +GLAD_API_CALL PFN_vkCmdBindVertexBuffers2 glad_vkCmdBindVertexBuffers2; +#define vkCmdBindVertexBuffers2 glad_vkCmdBindVertexBuffers2 GLAD_API_CALL PFN_vkCmdBindVertexBuffers2EXT glad_vkCmdBindVertexBuffers2EXT; #define vkCmdBindVertexBuffers2EXT glad_vkCmdBindVertexBuffers2EXT GLAD_API_CALL PFN_vkCmdBlitImage glad_vkCmdBlitImage; #define vkCmdBlitImage glad_vkCmdBlitImage -#if defined(VK_ENABLE_BETA_EXTENSIONS) -GLAD_API_CALL PFN_vkCmdBuildAccelerationStructureIndirectKHR glad_vkCmdBuildAccelerationStructureIndirectKHR; -#define vkCmdBuildAccelerationStructureIndirectKHR glad_vkCmdBuildAccelerationStructureIndirectKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -GLAD_API_CALL PFN_vkCmdBuildAccelerationStructureKHR glad_vkCmdBuildAccelerationStructureKHR; -#define vkCmdBuildAccelerationStructureKHR glad_vkCmdBuildAccelerationStructureKHR -#endif +GLAD_API_CALL PFN_vkCmdBlitImage2 glad_vkCmdBlitImage2; +#define vkCmdBlitImage2 glad_vkCmdBlitImage2 +GLAD_API_CALL PFN_vkCmdBlitImage2KHR glad_vkCmdBlitImage2KHR; +#define vkCmdBlitImage2KHR glad_vkCmdBlitImage2KHR GLAD_API_CALL PFN_vkCmdBuildAccelerationStructureNV glad_vkCmdBuildAccelerationStructureNV; #define vkCmdBuildAccelerationStructureNV glad_vkCmdBuildAccelerationStructureNV +GLAD_API_CALL PFN_vkCmdBuildAccelerationStructuresIndirectKHR glad_vkCmdBuildAccelerationStructuresIndirectKHR; +#define vkCmdBuildAccelerationStructuresIndirectKHR glad_vkCmdBuildAccelerationStructuresIndirectKHR +GLAD_API_CALL PFN_vkCmdBuildAccelerationStructuresKHR glad_vkCmdBuildAccelerationStructuresKHR; +#define vkCmdBuildAccelerationStructuresKHR glad_vkCmdBuildAccelerationStructuresKHR +GLAD_API_CALL PFN_vkCmdBuildClusterAccelerationStructureIndirectNV glad_vkCmdBuildClusterAccelerationStructureIndirectNV; +#define vkCmdBuildClusterAccelerationStructureIndirectNV glad_vkCmdBuildClusterAccelerationStructureIndirectNV +GLAD_API_CALL PFN_vkCmdBuildMicromapsEXT glad_vkCmdBuildMicromapsEXT; +#define vkCmdBuildMicromapsEXT glad_vkCmdBuildMicromapsEXT +GLAD_API_CALL PFN_vkCmdBuildPartitionedAccelerationStructuresNV glad_vkCmdBuildPartitionedAccelerationStructuresNV; +#define vkCmdBuildPartitionedAccelerationStructuresNV glad_vkCmdBuildPartitionedAccelerationStructuresNV GLAD_API_CALL PFN_vkCmdClearAttachments glad_vkCmdClearAttachments; #define vkCmdClearAttachments glad_vkCmdClearAttachments GLAD_API_CALL PFN_vkCmdClearColorImage glad_vkCmdClearColorImage; #define vkCmdClearColorImage glad_vkCmdClearColorImage GLAD_API_CALL PFN_vkCmdClearDepthStencilImage glad_vkCmdClearDepthStencilImage; #define vkCmdClearDepthStencilImage glad_vkCmdClearDepthStencilImage -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdConvertCooperativeVectorMatrixNV glad_vkCmdConvertCooperativeVectorMatrixNV; +#define vkCmdConvertCooperativeVectorMatrixNV glad_vkCmdConvertCooperativeVectorMatrixNV GLAD_API_CALL PFN_vkCmdCopyAccelerationStructureKHR glad_vkCmdCopyAccelerationStructureKHR; #define vkCmdCopyAccelerationStructureKHR glad_vkCmdCopyAccelerationStructureKHR -#endif GLAD_API_CALL PFN_vkCmdCopyAccelerationStructureNV glad_vkCmdCopyAccelerationStructureNV; #define vkCmdCopyAccelerationStructureNV glad_vkCmdCopyAccelerationStructureNV -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkCmdCopyAccelerationStructureToMemoryKHR glad_vkCmdCopyAccelerationStructureToMemoryKHR; #define vkCmdCopyAccelerationStructureToMemoryKHR glad_vkCmdCopyAccelerationStructureToMemoryKHR -#endif GLAD_API_CALL PFN_vkCmdCopyBuffer glad_vkCmdCopyBuffer; #define vkCmdCopyBuffer glad_vkCmdCopyBuffer +GLAD_API_CALL PFN_vkCmdCopyBuffer2 glad_vkCmdCopyBuffer2; +#define vkCmdCopyBuffer2 glad_vkCmdCopyBuffer2 +GLAD_API_CALL PFN_vkCmdCopyBuffer2KHR glad_vkCmdCopyBuffer2KHR; +#define vkCmdCopyBuffer2KHR glad_vkCmdCopyBuffer2KHR GLAD_API_CALL PFN_vkCmdCopyBufferToImage glad_vkCmdCopyBufferToImage; #define vkCmdCopyBufferToImage glad_vkCmdCopyBufferToImage +GLAD_API_CALL PFN_vkCmdCopyBufferToImage2 glad_vkCmdCopyBufferToImage2; +#define vkCmdCopyBufferToImage2 glad_vkCmdCopyBufferToImage2 +GLAD_API_CALL PFN_vkCmdCopyBufferToImage2KHR glad_vkCmdCopyBufferToImage2KHR; +#define vkCmdCopyBufferToImage2KHR glad_vkCmdCopyBufferToImage2KHR GLAD_API_CALL PFN_vkCmdCopyImage glad_vkCmdCopyImage; #define vkCmdCopyImage glad_vkCmdCopyImage +GLAD_API_CALL PFN_vkCmdCopyImage2 glad_vkCmdCopyImage2; +#define vkCmdCopyImage2 glad_vkCmdCopyImage2 +GLAD_API_CALL PFN_vkCmdCopyImage2KHR glad_vkCmdCopyImage2KHR; +#define vkCmdCopyImage2KHR glad_vkCmdCopyImage2KHR GLAD_API_CALL PFN_vkCmdCopyImageToBuffer glad_vkCmdCopyImageToBuffer; #define vkCmdCopyImageToBuffer glad_vkCmdCopyImageToBuffer -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdCopyImageToBuffer2 glad_vkCmdCopyImageToBuffer2; +#define vkCmdCopyImageToBuffer2 glad_vkCmdCopyImageToBuffer2 +GLAD_API_CALL PFN_vkCmdCopyImageToBuffer2KHR glad_vkCmdCopyImageToBuffer2KHR; +#define vkCmdCopyImageToBuffer2KHR glad_vkCmdCopyImageToBuffer2KHR +GLAD_API_CALL PFN_vkCmdCopyMemoryIndirectNV glad_vkCmdCopyMemoryIndirectNV; +#define vkCmdCopyMemoryIndirectNV glad_vkCmdCopyMemoryIndirectNV GLAD_API_CALL PFN_vkCmdCopyMemoryToAccelerationStructureKHR glad_vkCmdCopyMemoryToAccelerationStructureKHR; #define vkCmdCopyMemoryToAccelerationStructureKHR glad_vkCmdCopyMemoryToAccelerationStructureKHR -#endif +GLAD_API_CALL PFN_vkCmdCopyMemoryToImageIndirectNV glad_vkCmdCopyMemoryToImageIndirectNV; +#define vkCmdCopyMemoryToImageIndirectNV glad_vkCmdCopyMemoryToImageIndirectNV +GLAD_API_CALL PFN_vkCmdCopyMemoryToMicromapEXT glad_vkCmdCopyMemoryToMicromapEXT; +#define vkCmdCopyMemoryToMicromapEXT glad_vkCmdCopyMemoryToMicromapEXT +GLAD_API_CALL PFN_vkCmdCopyMicromapEXT glad_vkCmdCopyMicromapEXT; +#define vkCmdCopyMicromapEXT glad_vkCmdCopyMicromapEXT +GLAD_API_CALL PFN_vkCmdCopyMicromapToMemoryEXT glad_vkCmdCopyMicromapToMemoryEXT; +#define vkCmdCopyMicromapToMemoryEXT glad_vkCmdCopyMicromapToMemoryEXT GLAD_API_CALL PFN_vkCmdCopyQueryPoolResults glad_vkCmdCopyQueryPoolResults; #define vkCmdCopyQueryPoolResults glad_vkCmdCopyQueryPoolResults +GLAD_API_CALL PFN_vkCmdCuLaunchKernelNVX glad_vkCmdCuLaunchKernelNVX; +#define vkCmdCuLaunchKernelNVX glad_vkCmdCuLaunchKernelNVX +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdCudaLaunchKernelNV glad_vkCmdCudaLaunchKernelNV; +#define vkCmdCudaLaunchKernelNV glad_vkCmdCudaLaunchKernelNV + +#endif GLAD_API_CALL PFN_vkCmdDebugMarkerBeginEXT glad_vkCmdDebugMarkerBeginEXT; #define vkCmdDebugMarkerBeginEXT glad_vkCmdDebugMarkerBeginEXT GLAD_API_CALL PFN_vkCmdDebugMarkerEndEXT glad_vkCmdDebugMarkerEndEXT; #define vkCmdDebugMarkerEndEXT glad_vkCmdDebugMarkerEndEXT GLAD_API_CALL PFN_vkCmdDebugMarkerInsertEXT glad_vkCmdDebugMarkerInsertEXT; #define vkCmdDebugMarkerInsertEXT glad_vkCmdDebugMarkerInsertEXT +GLAD_API_CALL PFN_vkCmdDecompressMemoryIndirectCountNV glad_vkCmdDecompressMemoryIndirectCountNV; +#define vkCmdDecompressMemoryIndirectCountNV glad_vkCmdDecompressMemoryIndirectCountNV +GLAD_API_CALL PFN_vkCmdDecompressMemoryNV glad_vkCmdDecompressMemoryNV; +#define vkCmdDecompressMemoryNV glad_vkCmdDecompressMemoryNV GLAD_API_CALL PFN_vkCmdDispatch glad_vkCmdDispatch; #define vkCmdDispatch glad_vkCmdDispatch GLAD_API_CALL PFN_vkCmdDispatchBase glad_vkCmdDispatchBase; #define vkCmdDispatchBase glad_vkCmdDispatchBase GLAD_API_CALL PFN_vkCmdDispatchBaseKHR glad_vkCmdDispatchBaseKHR; #define vkCmdDispatchBaseKHR glad_vkCmdDispatchBaseKHR +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdDispatchGraphAMDX glad_vkCmdDispatchGraphAMDX; +#define vkCmdDispatchGraphAMDX glad_vkCmdDispatchGraphAMDX + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdDispatchGraphIndirectAMDX glad_vkCmdDispatchGraphIndirectAMDX; +#define vkCmdDispatchGraphIndirectAMDX glad_vkCmdDispatchGraphIndirectAMDX + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdDispatchGraphIndirectCountAMDX glad_vkCmdDispatchGraphIndirectCountAMDX; +#define vkCmdDispatchGraphIndirectCountAMDX glad_vkCmdDispatchGraphIndirectCountAMDX + +#endif GLAD_API_CALL PFN_vkCmdDispatchIndirect glad_vkCmdDispatchIndirect; #define vkCmdDispatchIndirect glad_vkCmdDispatchIndirect +GLAD_API_CALL PFN_vkCmdDispatchTileQCOM glad_vkCmdDispatchTileQCOM; +#define vkCmdDispatchTileQCOM glad_vkCmdDispatchTileQCOM GLAD_API_CALL PFN_vkCmdDraw glad_vkCmdDraw; #define vkCmdDraw glad_vkCmdDraw +GLAD_API_CALL PFN_vkCmdDrawClusterHUAWEI glad_vkCmdDrawClusterHUAWEI; +#define vkCmdDrawClusterHUAWEI glad_vkCmdDrawClusterHUAWEI +GLAD_API_CALL PFN_vkCmdDrawClusterIndirectHUAWEI glad_vkCmdDrawClusterIndirectHUAWEI; +#define vkCmdDrawClusterIndirectHUAWEI glad_vkCmdDrawClusterIndirectHUAWEI GLAD_API_CALL PFN_vkCmdDrawIndexed glad_vkCmdDrawIndexed; #define vkCmdDrawIndexed glad_vkCmdDrawIndexed GLAD_API_CALL PFN_vkCmdDrawIndexedIndirect glad_vkCmdDrawIndexedIndirect; @@ -10050,16 +18011,28 @@ GLAD_API_CALL PFN_vkCmdDrawIndirectCountAMD glad_vkCmdDrawIndirectCountAMD; #define vkCmdDrawIndirectCountAMD glad_vkCmdDrawIndirectCountAMD GLAD_API_CALL PFN_vkCmdDrawIndirectCountKHR glad_vkCmdDrawIndirectCountKHR; #define vkCmdDrawIndirectCountKHR glad_vkCmdDrawIndirectCountKHR +GLAD_API_CALL PFN_vkCmdDrawMeshTasksEXT glad_vkCmdDrawMeshTasksEXT; +#define vkCmdDrawMeshTasksEXT glad_vkCmdDrawMeshTasksEXT +GLAD_API_CALL PFN_vkCmdDrawMeshTasksIndirectCountEXT glad_vkCmdDrawMeshTasksIndirectCountEXT; +#define vkCmdDrawMeshTasksIndirectCountEXT glad_vkCmdDrawMeshTasksIndirectCountEXT GLAD_API_CALL PFN_vkCmdDrawMeshTasksIndirectCountNV glad_vkCmdDrawMeshTasksIndirectCountNV; #define vkCmdDrawMeshTasksIndirectCountNV glad_vkCmdDrawMeshTasksIndirectCountNV +GLAD_API_CALL PFN_vkCmdDrawMeshTasksIndirectEXT glad_vkCmdDrawMeshTasksIndirectEXT; +#define vkCmdDrawMeshTasksIndirectEXT glad_vkCmdDrawMeshTasksIndirectEXT GLAD_API_CALL PFN_vkCmdDrawMeshTasksIndirectNV glad_vkCmdDrawMeshTasksIndirectNV; #define vkCmdDrawMeshTasksIndirectNV glad_vkCmdDrawMeshTasksIndirectNV GLAD_API_CALL PFN_vkCmdDrawMeshTasksNV glad_vkCmdDrawMeshTasksNV; #define vkCmdDrawMeshTasksNV glad_vkCmdDrawMeshTasksNV +GLAD_API_CALL PFN_vkCmdDrawMultiEXT glad_vkCmdDrawMultiEXT; +#define vkCmdDrawMultiEXT glad_vkCmdDrawMultiEXT +GLAD_API_CALL PFN_vkCmdDrawMultiIndexedEXT glad_vkCmdDrawMultiIndexedEXT; +#define vkCmdDrawMultiIndexedEXT glad_vkCmdDrawMultiIndexedEXT GLAD_API_CALL PFN_vkCmdEndConditionalRenderingEXT glad_vkCmdEndConditionalRenderingEXT; #define vkCmdEndConditionalRenderingEXT glad_vkCmdEndConditionalRenderingEXT GLAD_API_CALL PFN_vkCmdEndDebugUtilsLabelEXT glad_vkCmdEndDebugUtilsLabelEXT; #define vkCmdEndDebugUtilsLabelEXT glad_vkCmdEndDebugUtilsLabelEXT +GLAD_API_CALL PFN_vkCmdEndPerTileExecutionQCOM glad_vkCmdEndPerTileExecutionQCOM; +#define vkCmdEndPerTileExecutionQCOM glad_vkCmdEndPerTileExecutionQCOM GLAD_API_CALL PFN_vkCmdEndQuery glad_vkCmdEndQuery; #define vkCmdEndQuery glad_vkCmdEndQuery GLAD_API_CALL PFN_vkCmdEndQueryIndexedEXT glad_vkCmdEndQueryIndexedEXT; @@ -10070,14 +18043,27 @@ GLAD_API_CALL PFN_vkCmdEndRenderPass2 glad_vkCmdEndRenderPass2; #define vkCmdEndRenderPass2 glad_vkCmdEndRenderPass2 GLAD_API_CALL PFN_vkCmdEndRenderPass2KHR glad_vkCmdEndRenderPass2KHR; #define vkCmdEndRenderPass2KHR glad_vkCmdEndRenderPass2KHR +GLAD_API_CALL PFN_vkCmdEndRendering glad_vkCmdEndRendering; +#define vkCmdEndRendering glad_vkCmdEndRendering +GLAD_API_CALL PFN_vkCmdEndRendering2EXT glad_vkCmdEndRendering2EXT; +#define vkCmdEndRendering2EXT glad_vkCmdEndRendering2EXT +GLAD_API_CALL PFN_vkCmdEndRenderingKHR glad_vkCmdEndRenderingKHR; +#define vkCmdEndRenderingKHR glad_vkCmdEndRenderingKHR GLAD_API_CALL PFN_vkCmdEndTransformFeedbackEXT glad_vkCmdEndTransformFeedbackEXT; #define vkCmdEndTransformFeedbackEXT glad_vkCmdEndTransformFeedbackEXT GLAD_API_CALL PFN_vkCmdExecuteCommands glad_vkCmdExecuteCommands; #define vkCmdExecuteCommands glad_vkCmdExecuteCommands +GLAD_API_CALL PFN_vkCmdExecuteGeneratedCommandsEXT glad_vkCmdExecuteGeneratedCommandsEXT; +#define vkCmdExecuteGeneratedCommandsEXT glad_vkCmdExecuteGeneratedCommandsEXT GLAD_API_CALL PFN_vkCmdExecuteGeneratedCommandsNV glad_vkCmdExecuteGeneratedCommandsNV; #define vkCmdExecuteGeneratedCommandsNV glad_vkCmdExecuteGeneratedCommandsNV GLAD_API_CALL PFN_vkCmdFillBuffer glad_vkCmdFillBuffer; #define vkCmdFillBuffer glad_vkCmdFillBuffer +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdInitializeGraphScratchMemoryAMDX glad_vkCmdInitializeGraphScratchMemoryAMDX; +#define vkCmdInitializeGraphScratchMemoryAMDX glad_vkCmdInitializeGraphScratchMemoryAMDX + +#endif GLAD_API_CALL PFN_vkCmdInsertDebugUtilsLabelEXT glad_vkCmdInsertDebugUtilsLabelEXT; #define vkCmdInsertDebugUtilsLabelEXT glad_vkCmdInsertDebugUtilsLabelEXT GLAD_API_CALL PFN_vkCmdNextSubpass glad_vkCmdNextSubpass; @@ -10086,154 +18072,370 @@ GLAD_API_CALL PFN_vkCmdNextSubpass2 glad_vkCmdNextSubpass2; #define vkCmdNextSubpass2 glad_vkCmdNextSubpass2 GLAD_API_CALL PFN_vkCmdNextSubpass2KHR glad_vkCmdNextSubpass2KHR; #define vkCmdNextSubpass2KHR glad_vkCmdNextSubpass2KHR +GLAD_API_CALL PFN_vkCmdOpticalFlowExecuteNV glad_vkCmdOpticalFlowExecuteNV; +#define vkCmdOpticalFlowExecuteNV glad_vkCmdOpticalFlowExecuteNV GLAD_API_CALL PFN_vkCmdPipelineBarrier glad_vkCmdPipelineBarrier; #define vkCmdPipelineBarrier glad_vkCmdPipelineBarrier +GLAD_API_CALL PFN_vkCmdPipelineBarrier2 glad_vkCmdPipelineBarrier2; +#define vkCmdPipelineBarrier2 glad_vkCmdPipelineBarrier2 +GLAD_API_CALL PFN_vkCmdPipelineBarrier2KHR glad_vkCmdPipelineBarrier2KHR; +#define vkCmdPipelineBarrier2KHR glad_vkCmdPipelineBarrier2KHR +GLAD_API_CALL PFN_vkCmdPreprocessGeneratedCommandsEXT glad_vkCmdPreprocessGeneratedCommandsEXT; +#define vkCmdPreprocessGeneratedCommandsEXT glad_vkCmdPreprocessGeneratedCommandsEXT GLAD_API_CALL PFN_vkCmdPreprocessGeneratedCommandsNV glad_vkCmdPreprocessGeneratedCommandsNV; #define vkCmdPreprocessGeneratedCommandsNV glad_vkCmdPreprocessGeneratedCommandsNV GLAD_API_CALL PFN_vkCmdPushConstants glad_vkCmdPushConstants; #define vkCmdPushConstants glad_vkCmdPushConstants +GLAD_API_CALL PFN_vkCmdPushConstants2 glad_vkCmdPushConstants2; +#define vkCmdPushConstants2 glad_vkCmdPushConstants2 +GLAD_API_CALL PFN_vkCmdPushConstants2KHR glad_vkCmdPushConstants2KHR; +#define vkCmdPushConstants2KHR glad_vkCmdPushConstants2KHR +GLAD_API_CALL PFN_vkCmdPushDescriptorSet glad_vkCmdPushDescriptorSet; +#define vkCmdPushDescriptorSet glad_vkCmdPushDescriptorSet +GLAD_API_CALL PFN_vkCmdPushDescriptorSet2 glad_vkCmdPushDescriptorSet2; +#define vkCmdPushDescriptorSet2 glad_vkCmdPushDescriptorSet2 +GLAD_API_CALL PFN_vkCmdPushDescriptorSet2KHR glad_vkCmdPushDescriptorSet2KHR; +#define vkCmdPushDescriptorSet2KHR glad_vkCmdPushDescriptorSet2KHR GLAD_API_CALL PFN_vkCmdPushDescriptorSetKHR glad_vkCmdPushDescriptorSetKHR; #define vkCmdPushDescriptorSetKHR glad_vkCmdPushDescriptorSetKHR +GLAD_API_CALL PFN_vkCmdPushDescriptorSetWithTemplate glad_vkCmdPushDescriptorSetWithTemplate; +#define vkCmdPushDescriptorSetWithTemplate glad_vkCmdPushDescriptorSetWithTemplate +GLAD_API_CALL PFN_vkCmdPushDescriptorSetWithTemplate2 glad_vkCmdPushDescriptorSetWithTemplate2; +#define vkCmdPushDescriptorSetWithTemplate2 glad_vkCmdPushDescriptorSetWithTemplate2 +GLAD_API_CALL PFN_vkCmdPushDescriptorSetWithTemplate2KHR glad_vkCmdPushDescriptorSetWithTemplate2KHR; +#define vkCmdPushDescriptorSetWithTemplate2KHR glad_vkCmdPushDescriptorSetWithTemplate2KHR GLAD_API_CALL PFN_vkCmdPushDescriptorSetWithTemplateKHR glad_vkCmdPushDescriptorSetWithTemplateKHR; #define vkCmdPushDescriptorSetWithTemplateKHR glad_vkCmdPushDescriptorSetWithTemplateKHR GLAD_API_CALL PFN_vkCmdResetEvent glad_vkCmdResetEvent; #define vkCmdResetEvent glad_vkCmdResetEvent +GLAD_API_CALL PFN_vkCmdResetEvent2 glad_vkCmdResetEvent2; +#define vkCmdResetEvent2 glad_vkCmdResetEvent2 +GLAD_API_CALL PFN_vkCmdResetEvent2KHR glad_vkCmdResetEvent2KHR; +#define vkCmdResetEvent2KHR glad_vkCmdResetEvent2KHR GLAD_API_CALL PFN_vkCmdResetQueryPool glad_vkCmdResetQueryPool; #define vkCmdResetQueryPool glad_vkCmdResetQueryPool GLAD_API_CALL PFN_vkCmdResolveImage glad_vkCmdResolveImage; #define vkCmdResolveImage glad_vkCmdResolveImage +GLAD_API_CALL PFN_vkCmdResolveImage2 glad_vkCmdResolveImage2; +#define vkCmdResolveImage2 glad_vkCmdResolveImage2 +GLAD_API_CALL PFN_vkCmdResolveImage2KHR glad_vkCmdResolveImage2KHR; +#define vkCmdResolveImage2KHR glad_vkCmdResolveImage2KHR +GLAD_API_CALL PFN_vkCmdSetAlphaToCoverageEnableEXT glad_vkCmdSetAlphaToCoverageEnableEXT; +#define vkCmdSetAlphaToCoverageEnableEXT glad_vkCmdSetAlphaToCoverageEnableEXT +GLAD_API_CALL PFN_vkCmdSetAlphaToOneEnableEXT glad_vkCmdSetAlphaToOneEnableEXT; +#define vkCmdSetAlphaToOneEnableEXT glad_vkCmdSetAlphaToOneEnableEXT +GLAD_API_CALL PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT glad_vkCmdSetAttachmentFeedbackLoopEnableEXT; +#define vkCmdSetAttachmentFeedbackLoopEnableEXT glad_vkCmdSetAttachmentFeedbackLoopEnableEXT GLAD_API_CALL PFN_vkCmdSetBlendConstants glad_vkCmdSetBlendConstants; #define vkCmdSetBlendConstants glad_vkCmdSetBlendConstants GLAD_API_CALL PFN_vkCmdSetCheckpointNV glad_vkCmdSetCheckpointNV; #define vkCmdSetCheckpointNV glad_vkCmdSetCheckpointNV GLAD_API_CALL PFN_vkCmdSetCoarseSampleOrderNV glad_vkCmdSetCoarseSampleOrderNV; #define vkCmdSetCoarseSampleOrderNV glad_vkCmdSetCoarseSampleOrderNV +GLAD_API_CALL PFN_vkCmdSetColorBlendAdvancedEXT glad_vkCmdSetColorBlendAdvancedEXT; +#define vkCmdSetColorBlendAdvancedEXT glad_vkCmdSetColorBlendAdvancedEXT +GLAD_API_CALL PFN_vkCmdSetColorBlendEnableEXT glad_vkCmdSetColorBlendEnableEXT; +#define vkCmdSetColorBlendEnableEXT glad_vkCmdSetColorBlendEnableEXT +GLAD_API_CALL PFN_vkCmdSetColorBlendEquationEXT glad_vkCmdSetColorBlendEquationEXT; +#define vkCmdSetColorBlendEquationEXT glad_vkCmdSetColorBlendEquationEXT +GLAD_API_CALL PFN_vkCmdSetColorWriteEnableEXT glad_vkCmdSetColorWriteEnableEXT; +#define vkCmdSetColorWriteEnableEXT glad_vkCmdSetColorWriteEnableEXT +GLAD_API_CALL PFN_vkCmdSetColorWriteMaskEXT glad_vkCmdSetColorWriteMaskEXT; +#define vkCmdSetColorWriteMaskEXT glad_vkCmdSetColorWriteMaskEXT +GLAD_API_CALL PFN_vkCmdSetConservativeRasterizationModeEXT glad_vkCmdSetConservativeRasterizationModeEXT; +#define vkCmdSetConservativeRasterizationModeEXT glad_vkCmdSetConservativeRasterizationModeEXT +GLAD_API_CALL PFN_vkCmdSetCoverageModulationModeNV glad_vkCmdSetCoverageModulationModeNV; +#define vkCmdSetCoverageModulationModeNV glad_vkCmdSetCoverageModulationModeNV +GLAD_API_CALL PFN_vkCmdSetCoverageModulationTableEnableNV glad_vkCmdSetCoverageModulationTableEnableNV; +#define vkCmdSetCoverageModulationTableEnableNV glad_vkCmdSetCoverageModulationTableEnableNV +GLAD_API_CALL PFN_vkCmdSetCoverageModulationTableNV glad_vkCmdSetCoverageModulationTableNV; +#define vkCmdSetCoverageModulationTableNV glad_vkCmdSetCoverageModulationTableNV +GLAD_API_CALL PFN_vkCmdSetCoverageReductionModeNV glad_vkCmdSetCoverageReductionModeNV; +#define vkCmdSetCoverageReductionModeNV glad_vkCmdSetCoverageReductionModeNV +GLAD_API_CALL PFN_vkCmdSetCoverageToColorEnableNV glad_vkCmdSetCoverageToColorEnableNV; +#define vkCmdSetCoverageToColorEnableNV glad_vkCmdSetCoverageToColorEnableNV +GLAD_API_CALL PFN_vkCmdSetCoverageToColorLocationNV glad_vkCmdSetCoverageToColorLocationNV; +#define vkCmdSetCoverageToColorLocationNV glad_vkCmdSetCoverageToColorLocationNV +GLAD_API_CALL PFN_vkCmdSetCullMode glad_vkCmdSetCullMode; +#define vkCmdSetCullMode glad_vkCmdSetCullMode GLAD_API_CALL PFN_vkCmdSetCullModeEXT glad_vkCmdSetCullModeEXT; #define vkCmdSetCullModeEXT glad_vkCmdSetCullModeEXT GLAD_API_CALL PFN_vkCmdSetDepthBias glad_vkCmdSetDepthBias; #define vkCmdSetDepthBias glad_vkCmdSetDepthBias +GLAD_API_CALL PFN_vkCmdSetDepthBias2EXT glad_vkCmdSetDepthBias2EXT; +#define vkCmdSetDepthBias2EXT glad_vkCmdSetDepthBias2EXT +GLAD_API_CALL PFN_vkCmdSetDepthBiasEnable glad_vkCmdSetDepthBiasEnable; +#define vkCmdSetDepthBiasEnable glad_vkCmdSetDepthBiasEnable +GLAD_API_CALL PFN_vkCmdSetDepthBiasEnableEXT glad_vkCmdSetDepthBiasEnableEXT; +#define vkCmdSetDepthBiasEnableEXT glad_vkCmdSetDepthBiasEnableEXT GLAD_API_CALL PFN_vkCmdSetDepthBounds glad_vkCmdSetDepthBounds; #define vkCmdSetDepthBounds glad_vkCmdSetDepthBounds +GLAD_API_CALL PFN_vkCmdSetDepthBoundsTestEnable glad_vkCmdSetDepthBoundsTestEnable; +#define vkCmdSetDepthBoundsTestEnable glad_vkCmdSetDepthBoundsTestEnable GLAD_API_CALL PFN_vkCmdSetDepthBoundsTestEnableEXT glad_vkCmdSetDepthBoundsTestEnableEXT; #define vkCmdSetDepthBoundsTestEnableEXT glad_vkCmdSetDepthBoundsTestEnableEXT +GLAD_API_CALL PFN_vkCmdSetDepthClampEnableEXT glad_vkCmdSetDepthClampEnableEXT; +#define vkCmdSetDepthClampEnableEXT glad_vkCmdSetDepthClampEnableEXT +GLAD_API_CALL PFN_vkCmdSetDepthClampRangeEXT glad_vkCmdSetDepthClampRangeEXT; +#define vkCmdSetDepthClampRangeEXT glad_vkCmdSetDepthClampRangeEXT +GLAD_API_CALL PFN_vkCmdSetDepthClipEnableEXT glad_vkCmdSetDepthClipEnableEXT; +#define vkCmdSetDepthClipEnableEXT glad_vkCmdSetDepthClipEnableEXT +GLAD_API_CALL PFN_vkCmdSetDepthClipNegativeOneToOneEXT glad_vkCmdSetDepthClipNegativeOneToOneEXT; +#define vkCmdSetDepthClipNegativeOneToOneEXT glad_vkCmdSetDepthClipNegativeOneToOneEXT +GLAD_API_CALL PFN_vkCmdSetDepthCompareOp glad_vkCmdSetDepthCompareOp; +#define vkCmdSetDepthCompareOp glad_vkCmdSetDepthCompareOp GLAD_API_CALL PFN_vkCmdSetDepthCompareOpEXT glad_vkCmdSetDepthCompareOpEXT; #define vkCmdSetDepthCompareOpEXT glad_vkCmdSetDepthCompareOpEXT +GLAD_API_CALL PFN_vkCmdSetDepthTestEnable glad_vkCmdSetDepthTestEnable; +#define vkCmdSetDepthTestEnable glad_vkCmdSetDepthTestEnable GLAD_API_CALL PFN_vkCmdSetDepthTestEnableEXT glad_vkCmdSetDepthTestEnableEXT; #define vkCmdSetDepthTestEnableEXT glad_vkCmdSetDepthTestEnableEXT +GLAD_API_CALL PFN_vkCmdSetDepthWriteEnable glad_vkCmdSetDepthWriteEnable; +#define vkCmdSetDepthWriteEnable glad_vkCmdSetDepthWriteEnable GLAD_API_CALL PFN_vkCmdSetDepthWriteEnableEXT glad_vkCmdSetDepthWriteEnableEXT; #define vkCmdSetDepthWriteEnableEXT glad_vkCmdSetDepthWriteEnableEXT +GLAD_API_CALL PFN_vkCmdSetDescriptorBufferOffsets2EXT glad_vkCmdSetDescriptorBufferOffsets2EXT; +#define vkCmdSetDescriptorBufferOffsets2EXT glad_vkCmdSetDescriptorBufferOffsets2EXT +GLAD_API_CALL PFN_vkCmdSetDescriptorBufferOffsetsEXT glad_vkCmdSetDescriptorBufferOffsetsEXT; +#define vkCmdSetDescriptorBufferOffsetsEXT glad_vkCmdSetDescriptorBufferOffsetsEXT GLAD_API_CALL PFN_vkCmdSetDeviceMask glad_vkCmdSetDeviceMask; #define vkCmdSetDeviceMask glad_vkCmdSetDeviceMask GLAD_API_CALL PFN_vkCmdSetDeviceMaskKHR glad_vkCmdSetDeviceMaskKHR; #define vkCmdSetDeviceMaskKHR glad_vkCmdSetDeviceMaskKHR GLAD_API_CALL PFN_vkCmdSetDiscardRectangleEXT glad_vkCmdSetDiscardRectangleEXT; #define vkCmdSetDiscardRectangleEXT glad_vkCmdSetDiscardRectangleEXT +GLAD_API_CALL PFN_vkCmdSetDiscardRectangleEnableEXT glad_vkCmdSetDiscardRectangleEnableEXT; +#define vkCmdSetDiscardRectangleEnableEXT glad_vkCmdSetDiscardRectangleEnableEXT +GLAD_API_CALL PFN_vkCmdSetDiscardRectangleModeEXT glad_vkCmdSetDiscardRectangleModeEXT; +#define vkCmdSetDiscardRectangleModeEXT glad_vkCmdSetDiscardRectangleModeEXT GLAD_API_CALL PFN_vkCmdSetEvent glad_vkCmdSetEvent; #define vkCmdSetEvent glad_vkCmdSetEvent +GLAD_API_CALL PFN_vkCmdSetEvent2 glad_vkCmdSetEvent2; +#define vkCmdSetEvent2 glad_vkCmdSetEvent2 +GLAD_API_CALL PFN_vkCmdSetEvent2KHR glad_vkCmdSetEvent2KHR; +#define vkCmdSetEvent2KHR glad_vkCmdSetEvent2KHR +GLAD_API_CALL PFN_vkCmdSetExclusiveScissorEnableNV glad_vkCmdSetExclusiveScissorEnableNV; +#define vkCmdSetExclusiveScissorEnableNV glad_vkCmdSetExclusiveScissorEnableNV GLAD_API_CALL PFN_vkCmdSetExclusiveScissorNV glad_vkCmdSetExclusiveScissorNV; #define vkCmdSetExclusiveScissorNV glad_vkCmdSetExclusiveScissorNV +GLAD_API_CALL PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT glad_vkCmdSetExtraPrimitiveOverestimationSizeEXT; +#define vkCmdSetExtraPrimitiveOverestimationSizeEXT glad_vkCmdSetExtraPrimitiveOverestimationSizeEXT +GLAD_API_CALL PFN_vkCmdSetFragmentShadingRateEnumNV glad_vkCmdSetFragmentShadingRateEnumNV; +#define vkCmdSetFragmentShadingRateEnumNV glad_vkCmdSetFragmentShadingRateEnumNV +GLAD_API_CALL PFN_vkCmdSetFragmentShadingRateKHR glad_vkCmdSetFragmentShadingRateKHR; +#define vkCmdSetFragmentShadingRateKHR glad_vkCmdSetFragmentShadingRateKHR +GLAD_API_CALL PFN_vkCmdSetFrontFace glad_vkCmdSetFrontFace; +#define vkCmdSetFrontFace glad_vkCmdSetFrontFace GLAD_API_CALL PFN_vkCmdSetFrontFaceEXT glad_vkCmdSetFrontFaceEXT; #define vkCmdSetFrontFaceEXT glad_vkCmdSetFrontFaceEXT +GLAD_API_CALL PFN_vkCmdSetLineRasterizationModeEXT glad_vkCmdSetLineRasterizationModeEXT; +#define vkCmdSetLineRasterizationModeEXT glad_vkCmdSetLineRasterizationModeEXT +GLAD_API_CALL PFN_vkCmdSetLineStipple glad_vkCmdSetLineStipple; +#define vkCmdSetLineStipple glad_vkCmdSetLineStipple GLAD_API_CALL PFN_vkCmdSetLineStippleEXT glad_vkCmdSetLineStippleEXT; #define vkCmdSetLineStippleEXT glad_vkCmdSetLineStippleEXT +GLAD_API_CALL PFN_vkCmdSetLineStippleEnableEXT glad_vkCmdSetLineStippleEnableEXT; +#define vkCmdSetLineStippleEnableEXT glad_vkCmdSetLineStippleEnableEXT +GLAD_API_CALL PFN_vkCmdSetLineStippleKHR glad_vkCmdSetLineStippleKHR; +#define vkCmdSetLineStippleKHR glad_vkCmdSetLineStippleKHR GLAD_API_CALL PFN_vkCmdSetLineWidth glad_vkCmdSetLineWidth; #define vkCmdSetLineWidth glad_vkCmdSetLineWidth +GLAD_API_CALL PFN_vkCmdSetLogicOpEXT glad_vkCmdSetLogicOpEXT; +#define vkCmdSetLogicOpEXT glad_vkCmdSetLogicOpEXT +GLAD_API_CALL PFN_vkCmdSetLogicOpEnableEXT glad_vkCmdSetLogicOpEnableEXT; +#define vkCmdSetLogicOpEnableEXT glad_vkCmdSetLogicOpEnableEXT +GLAD_API_CALL PFN_vkCmdSetPatchControlPointsEXT glad_vkCmdSetPatchControlPointsEXT; +#define vkCmdSetPatchControlPointsEXT glad_vkCmdSetPatchControlPointsEXT GLAD_API_CALL PFN_vkCmdSetPerformanceMarkerINTEL glad_vkCmdSetPerformanceMarkerINTEL; #define vkCmdSetPerformanceMarkerINTEL glad_vkCmdSetPerformanceMarkerINTEL GLAD_API_CALL PFN_vkCmdSetPerformanceOverrideINTEL glad_vkCmdSetPerformanceOverrideINTEL; #define vkCmdSetPerformanceOverrideINTEL glad_vkCmdSetPerformanceOverrideINTEL GLAD_API_CALL PFN_vkCmdSetPerformanceStreamMarkerINTEL glad_vkCmdSetPerformanceStreamMarkerINTEL; #define vkCmdSetPerformanceStreamMarkerINTEL glad_vkCmdSetPerformanceStreamMarkerINTEL +GLAD_API_CALL PFN_vkCmdSetPolygonModeEXT glad_vkCmdSetPolygonModeEXT; +#define vkCmdSetPolygonModeEXT glad_vkCmdSetPolygonModeEXT +GLAD_API_CALL PFN_vkCmdSetPrimitiveRestartEnable glad_vkCmdSetPrimitiveRestartEnable; +#define vkCmdSetPrimitiveRestartEnable glad_vkCmdSetPrimitiveRestartEnable +GLAD_API_CALL PFN_vkCmdSetPrimitiveRestartEnableEXT glad_vkCmdSetPrimitiveRestartEnableEXT; +#define vkCmdSetPrimitiveRestartEnableEXT glad_vkCmdSetPrimitiveRestartEnableEXT +GLAD_API_CALL PFN_vkCmdSetPrimitiveTopology glad_vkCmdSetPrimitiveTopology; +#define vkCmdSetPrimitiveTopology glad_vkCmdSetPrimitiveTopology GLAD_API_CALL PFN_vkCmdSetPrimitiveTopologyEXT glad_vkCmdSetPrimitiveTopologyEXT; #define vkCmdSetPrimitiveTopologyEXT glad_vkCmdSetPrimitiveTopologyEXT +GLAD_API_CALL PFN_vkCmdSetProvokingVertexModeEXT glad_vkCmdSetProvokingVertexModeEXT; +#define vkCmdSetProvokingVertexModeEXT glad_vkCmdSetProvokingVertexModeEXT +GLAD_API_CALL PFN_vkCmdSetRasterizationSamplesEXT glad_vkCmdSetRasterizationSamplesEXT; +#define vkCmdSetRasterizationSamplesEXT glad_vkCmdSetRasterizationSamplesEXT +GLAD_API_CALL PFN_vkCmdSetRasterizationStreamEXT glad_vkCmdSetRasterizationStreamEXT; +#define vkCmdSetRasterizationStreamEXT glad_vkCmdSetRasterizationStreamEXT +GLAD_API_CALL PFN_vkCmdSetRasterizerDiscardEnable glad_vkCmdSetRasterizerDiscardEnable; +#define vkCmdSetRasterizerDiscardEnable glad_vkCmdSetRasterizerDiscardEnable +GLAD_API_CALL PFN_vkCmdSetRasterizerDiscardEnableEXT glad_vkCmdSetRasterizerDiscardEnableEXT; +#define vkCmdSetRasterizerDiscardEnableEXT glad_vkCmdSetRasterizerDiscardEnableEXT +GLAD_API_CALL PFN_vkCmdSetRayTracingPipelineStackSizeKHR glad_vkCmdSetRayTracingPipelineStackSizeKHR; +#define vkCmdSetRayTracingPipelineStackSizeKHR glad_vkCmdSetRayTracingPipelineStackSizeKHR +GLAD_API_CALL PFN_vkCmdSetRenderingAttachmentLocations glad_vkCmdSetRenderingAttachmentLocations; +#define vkCmdSetRenderingAttachmentLocations glad_vkCmdSetRenderingAttachmentLocations +GLAD_API_CALL PFN_vkCmdSetRenderingAttachmentLocationsKHR glad_vkCmdSetRenderingAttachmentLocationsKHR; +#define vkCmdSetRenderingAttachmentLocationsKHR glad_vkCmdSetRenderingAttachmentLocationsKHR +GLAD_API_CALL PFN_vkCmdSetRenderingInputAttachmentIndices glad_vkCmdSetRenderingInputAttachmentIndices; +#define vkCmdSetRenderingInputAttachmentIndices glad_vkCmdSetRenderingInputAttachmentIndices +GLAD_API_CALL PFN_vkCmdSetRenderingInputAttachmentIndicesKHR glad_vkCmdSetRenderingInputAttachmentIndicesKHR; +#define vkCmdSetRenderingInputAttachmentIndicesKHR glad_vkCmdSetRenderingInputAttachmentIndicesKHR +GLAD_API_CALL PFN_vkCmdSetRepresentativeFragmentTestEnableNV glad_vkCmdSetRepresentativeFragmentTestEnableNV; +#define vkCmdSetRepresentativeFragmentTestEnableNV glad_vkCmdSetRepresentativeFragmentTestEnableNV GLAD_API_CALL PFN_vkCmdSetSampleLocationsEXT glad_vkCmdSetSampleLocationsEXT; #define vkCmdSetSampleLocationsEXT glad_vkCmdSetSampleLocationsEXT +GLAD_API_CALL PFN_vkCmdSetSampleLocationsEnableEXT glad_vkCmdSetSampleLocationsEnableEXT; +#define vkCmdSetSampleLocationsEnableEXT glad_vkCmdSetSampleLocationsEnableEXT +GLAD_API_CALL PFN_vkCmdSetSampleMaskEXT glad_vkCmdSetSampleMaskEXT; +#define vkCmdSetSampleMaskEXT glad_vkCmdSetSampleMaskEXT GLAD_API_CALL PFN_vkCmdSetScissor glad_vkCmdSetScissor; #define vkCmdSetScissor glad_vkCmdSetScissor +GLAD_API_CALL PFN_vkCmdSetScissorWithCount glad_vkCmdSetScissorWithCount; +#define vkCmdSetScissorWithCount glad_vkCmdSetScissorWithCount GLAD_API_CALL PFN_vkCmdSetScissorWithCountEXT glad_vkCmdSetScissorWithCountEXT; #define vkCmdSetScissorWithCountEXT glad_vkCmdSetScissorWithCountEXT +GLAD_API_CALL PFN_vkCmdSetShadingRateImageEnableNV glad_vkCmdSetShadingRateImageEnableNV; +#define vkCmdSetShadingRateImageEnableNV glad_vkCmdSetShadingRateImageEnableNV GLAD_API_CALL PFN_vkCmdSetStencilCompareMask glad_vkCmdSetStencilCompareMask; #define vkCmdSetStencilCompareMask glad_vkCmdSetStencilCompareMask +GLAD_API_CALL PFN_vkCmdSetStencilOp glad_vkCmdSetStencilOp; +#define vkCmdSetStencilOp glad_vkCmdSetStencilOp GLAD_API_CALL PFN_vkCmdSetStencilOpEXT glad_vkCmdSetStencilOpEXT; #define vkCmdSetStencilOpEXT glad_vkCmdSetStencilOpEXT GLAD_API_CALL PFN_vkCmdSetStencilReference glad_vkCmdSetStencilReference; #define vkCmdSetStencilReference glad_vkCmdSetStencilReference +GLAD_API_CALL PFN_vkCmdSetStencilTestEnable glad_vkCmdSetStencilTestEnable; +#define vkCmdSetStencilTestEnable glad_vkCmdSetStencilTestEnable GLAD_API_CALL PFN_vkCmdSetStencilTestEnableEXT glad_vkCmdSetStencilTestEnableEXT; #define vkCmdSetStencilTestEnableEXT glad_vkCmdSetStencilTestEnableEXT GLAD_API_CALL PFN_vkCmdSetStencilWriteMask glad_vkCmdSetStencilWriteMask; #define vkCmdSetStencilWriteMask glad_vkCmdSetStencilWriteMask +GLAD_API_CALL PFN_vkCmdSetTessellationDomainOriginEXT glad_vkCmdSetTessellationDomainOriginEXT; +#define vkCmdSetTessellationDomainOriginEXT glad_vkCmdSetTessellationDomainOriginEXT +GLAD_API_CALL PFN_vkCmdSetVertexInputEXT glad_vkCmdSetVertexInputEXT; +#define vkCmdSetVertexInputEXT glad_vkCmdSetVertexInputEXT GLAD_API_CALL PFN_vkCmdSetViewport glad_vkCmdSetViewport; #define vkCmdSetViewport glad_vkCmdSetViewport GLAD_API_CALL PFN_vkCmdSetViewportShadingRatePaletteNV glad_vkCmdSetViewportShadingRatePaletteNV; #define vkCmdSetViewportShadingRatePaletteNV glad_vkCmdSetViewportShadingRatePaletteNV +GLAD_API_CALL PFN_vkCmdSetViewportSwizzleNV glad_vkCmdSetViewportSwizzleNV; +#define vkCmdSetViewportSwizzleNV glad_vkCmdSetViewportSwizzleNV +GLAD_API_CALL PFN_vkCmdSetViewportWScalingEnableNV glad_vkCmdSetViewportWScalingEnableNV; +#define vkCmdSetViewportWScalingEnableNV glad_vkCmdSetViewportWScalingEnableNV GLAD_API_CALL PFN_vkCmdSetViewportWScalingNV glad_vkCmdSetViewportWScalingNV; #define vkCmdSetViewportWScalingNV glad_vkCmdSetViewportWScalingNV +GLAD_API_CALL PFN_vkCmdSetViewportWithCount glad_vkCmdSetViewportWithCount; +#define vkCmdSetViewportWithCount glad_vkCmdSetViewportWithCount GLAD_API_CALL PFN_vkCmdSetViewportWithCountEXT glad_vkCmdSetViewportWithCountEXT; #define vkCmdSetViewportWithCountEXT glad_vkCmdSetViewportWithCountEXT -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdSubpassShadingHUAWEI glad_vkCmdSubpassShadingHUAWEI; +#define vkCmdSubpassShadingHUAWEI glad_vkCmdSubpassShadingHUAWEI +GLAD_API_CALL PFN_vkCmdTraceRaysIndirect2KHR glad_vkCmdTraceRaysIndirect2KHR; +#define vkCmdTraceRaysIndirect2KHR glad_vkCmdTraceRaysIndirect2KHR GLAD_API_CALL PFN_vkCmdTraceRaysIndirectKHR glad_vkCmdTraceRaysIndirectKHR; #define vkCmdTraceRaysIndirectKHR glad_vkCmdTraceRaysIndirectKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkCmdTraceRaysKHR glad_vkCmdTraceRaysKHR; #define vkCmdTraceRaysKHR glad_vkCmdTraceRaysKHR -#endif GLAD_API_CALL PFN_vkCmdTraceRaysNV glad_vkCmdTraceRaysNV; #define vkCmdTraceRaysNV glad_vkCmdTraceRaysNV GLAD_API_CALL PFN_vkCmdUpdateBuffer glad_vkCmdUpdateBuffer; #define vkCmdUpdateBuffer glad_vkCmdUpdateBuffer +GLAD_API_CALL PFN_vkCmdUpdatePipelineIndirectBufferNV glad_vkCmdUpdatePipelineIndirectBufferNV; +#define vkCmdUpdatePipelineIndirectBufferNV glad_vkCmdUpdatePipelineIndirectBufferNV GLAD_API_CALL PFN_vkCmdWaitEvents glad_vkCmdWaitEvents; #define vkCmdWaitEvents glad_vkCmdWaitEvents -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdWaitEvents2 glad_vkCmdWaitEvents2; +#define vkCmdWaitEvents2 glad_vkCmdWaitEvents2 +GLAD_API_CALL PFN_vkCmdWaitEvents2KHR glad_vkCmdWaitEvents2KHR; +#define vkCmdWaitEvents2KHR glad_vkCmdWaitEvents2KHR GLAD_API_CALL PFN_vkCmdWriteAccelerationStructuresPropertiesKHR glad_vkCmdWriteAccelerationStructuresPropertiesKHR; #define vkCmdWriteAccelerationStructuresPropertiesKHR glad_vkCmdWriteAccelerationStructuresPropertiesKHR -#endif GLAD_API_CALL PFN_vkCmdWriteAccelerationStructuresPropertiesNV glad_vkCmdWriteAccelerationStructuresPropertiesNV; #define vkCmdWriteAccelerationStructuresPropertiesNV glad_vkCmdWriteAccelerationStructuresPropertiesNV +GLAD_API_CALL PFN_vkCmdWriteBufferMarker2AMD glad_vkCmdWriteBufferMarker2AMD; +#define vkCmdWriteBufferMarker2AMD glad_vkCmdWriteBufferMarker2AMD GLAD_API_CALL PFN_vkCmdWriteBufferMarkerAMD glad_vkCmdWriteBufferMarkerAMD; #define vkCmdWriteBufferMarkerAMD glad_vkCmdWriteBufferMarkerAMD +GLAD_API_CALL PFN_vkCmdWriteMicromapsPropertiesEXT glad_vkCmdWriteMicromapsPropertiesEXT; +#define vkCmdWriteMicromapsPropertiesEXT glad_vkCmdWriteMicromapsPropertiesEXT GLAD_API_CALL PFN_vkCmdWriteTimestamp glad_vkCmdWriteTimestamp; #define vkCmdWriteTimestamp glad_vkCmdWriteTimestamp +GLAD_API_CALL PFN_vkCmdWriteTimestamp2 glad_vkCmdWriteTimestamp2; +#define vkCmdWriteTimestamp2 glad_vkCmdWriteTimestamp2 +GLAD_API_CALL PFN_vkCmdWriteTimestamp2KHR glad_vkCmdWriteTimestamp2KHR; +#define vkCmdWriteTimestamp2KHR glad_vkCmdWriteTimestamp2KHR GLAD_API_CALL PFN_vkCompileDeferredNV glad_vkCompileDeferredNV; #define vkCompileDeferredNV glad_vkCompileDeferredNV -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkConvertCooperativeVectorMatrixNV glad_vkConvertCooperativeVectorMatrixNV; +#define vkConvertCooperativeVectorMatrixNV glad_vkConvertCooperativeVectorMatrixNV GLAD_API_CALL PFN_vkCopyAccelerationStructureKHR glad_vkCopyAccelerationStructureKHR; #define vkCopyAccelerationStructureKHR glad_vkCopyAccelerationStructureKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkCopyAccelerationStructureToMemoryKHR glad_vkCopyAccelerationStructureToMemoryKHR; #define vkCopyAccelerationStructureToMemoryKHR glad_vkCopyAccelerationStructureToMemoryKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCopyImageToImage glad_vkCopyImageToImage; +#define vkCopyImageToImage glad_vkCopyImageToImage +GLAD_API_CALL PFN_vkCopyImageToImageEXT glad_vkCopyImageToImageEXT; +#define vkCopyImageToImageEXT glad_vkCopyImageToImageEXT +GLAD_API_CALL PFN_vkCopyImageToMemory glad_vkCopyImageToMemory; +#define vkCopyImageToMemory glad_vkCopyImageToMemory +GLAD_API_CALL PFN_vkCopyImageToMemoryEXT glad_vkCopyImageToMemoryEXT; +#define vkCopyImageToMemoryEXT glad_vkCopyImageToMemoryEXT GLAD_API_CALL PFN_vkCopyMemoryToAccelerationStructureKHR glad_vkCopyMemoryToAccelerationStructureKHR; #define vkCopyMemoryToAccelerationStructureKHR glad_vkCopyMemoryToAccelerationStructureKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCopyMemoryToImage glad_vkCopyMemoryToImage; +#define vkCopyMemoryToImage glad_vkCopyMemoryToImage +GLAD_API_CALL PFN_vkCopyMemoryToImageEXT glad_vkCopyMemoryToImageEXT; +#define vkCopyMemoryToImageEXT glad_vkCopyMemoryToImageEXT +GLAD_API_CALL PFN_vkCopyMemoryToMicromapEXT glad_vkCopyMemoryToMicromapEXT; +#define vkCopyMemoryToMicromapEXT glad_vkCopyMemoryToMicromapEXT +GLAD_API_CALL PFN_vkCopyMicromapEXT glad_vkCopyMicromapEXT; +#define vkCopyMicromapEXT glad_vkCopyMicromapEXT +GLAD_API_CALL PFN_vkCopyMicromapToMemoryEXT glad_vkCopyMicromapToMemoryEXT; +#define vkCopyMicromapToMemoryEXT glad_vkCopyMicromapToMemoryEXT GLAD_API_CALL PFN_vkCreateAccelerationStructureKHR glad_vkCreateAccelerationStructureKHR; #define vkCreateAccelerationStructureKHR glad_vkCreateAccelerationStructureKHR -#endif GLAD_API_CALL PFN_vkCreateAccelerationStructureNV glad_vkCreateAccelerationStructureNV; #define vkCreateAccelerationStructureNV glad_vkCreateAccelerationStructureNV #if defined(VK_USE_PLATFORM_ANDROID_KHR) GLAD_API_CALL PFN_vkCreateAndroidSurfaceKHR glad_vkCreateAndroidSurfaceKHR; #define vkCreateAndroidSurfaceKHR glad_vkCreateAndroidSurfaceKHR + #endif GLAD_API_CALL PFN_vkCreateBuffer glad_vkCreateBuffer; #define vkCreateBuffer glad_vkCreateBuffer +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkCreateBufferCollectionFUCHSIA glad_vkCreateBufferCollectionFUCHSIA; +#define vkCreateBufferCollectionFUCHSIA glad_vkCreateBufferCollectionFUCHSIA + +#endif GLAD_API_CALL PFN_vkCreateBufferView glad_vkCreateBufferView; #define vkCreateBufferView glad_vkCreateBufferView GLAD_API_CALL PFN_vkCreateCommandPool glad_vkCreateCommandPool; #define vkCreateCommandPool glad_vkCreateCommandPool GLAD_API_CALL PFN_vkCreateComputePipelines glad_vkCreateComputePipelines; #define vkCreateComputePipelines glad_vkCreateComputePipelines +GLAD_API_CALL PFN_vkCreateCuFunctionNVX glad_vkCreateCuFunctionNVX; +#define vkCreateCuFunctionNVX glad_vkCreateCuFunctionNVX +GLAD_API_CALL PFN_vkCreateCuModuleNVX glad_vkCreateCuModuleNVX; +#define vkCreateCuModuleNVX glad_vkCreateCuModuleNVX +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCreateCudaFunctionNV glad_vkCreateCudaFunctionNV; +#define vkCreateCudaFunctionNV glad_vkCreateCudaFunctionNV + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCreateCudaModuleNV glad_vkCreateCudaModuleNV; +#define vkCreateCudaModuleNV glad_vkCreateCudaModuleNV + +#endif GLAD_API_CALL PFN_vkCreateDebugReportCallbackEXT glad_vkCreateDebugReportCallbackEXT; #define vkCreateDebugReportCallbackEXT glad_vkCreateDebugReportCallbackEXT GLAD_API_CALL PFN_vkCreateDebugUtilsMessengerEXT glad_vkCreateDebugUtilsMessengerEXT; #define vkCreateDebugUtilsMessengerEXT glad_vkCreateDebugUtilsMessengerEXT -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkCreateDeferredOperationKHR glad_vkCreateDeferredOperationKHR; #define vkCreateDeferredOperationKHR glad_vkCreateDeferredOperationKHR -#endif GLAD_API_CALL PFN_vkCreateDescriptorPool glad_vkCreateDescriptorPool; #define vkCreateDescriptorPool glad_vkCreateDescriptorPool GLAD_API_CALL PFN_vkCreateDescriptorSetLayout glad_vkCreateDescriptorSetLayout; @@ -10247,6 +18449,7 @@ GLAD_API_CALL PFN_vkCreateDevice glad_vkCreateDevice; #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) GLAD_API_CALL PFN_vkCreateDirectFBSurfaceEXT glad_vkCreateDirectFBSurfaceEXT; #define vkCreateDirectFBSurfaceEXT glad_vkCreateDirectFBSurfaceEXT + #endif GLAD_API_CALL PFN_vkCreateDisplayModeKHR glad_vkCreateDisplayModeKHR; #define vkCreateDisplayModeKHR glad_vkCreateDisplayModeKHR @@ -10254,6 +18457,13 @@ GLAD_API_CALL PFN_vkCreateDisplayPlaneSurfaceKHR glad_vkCreateDisplayPlaneSurfac #define vkCreateDisplayPlaneSurfaceKHR glad_vkCreateDisplayPlaneSurfaceKHR GLAD_API_CALL PFN_vkCreateEvent glad_vkCreateEvent; #define vkCreateEvent glad_vkCreateEvent +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCreateExecutionGraphPipelinesAMDX glad_vkCreateExecutionGraphPipelinesAMDX; +#define vkCreateExecutionGraphPipelinesAMDX glad_vkCreateExecutionGraphPipelinesAMDX + +#endif +GLAD_API_CALL PFN_vkCreateExternalComputeQueueNV glad_vkCreateExternalComputeQueueNV; +#define vkCreateExternalComputeQueueNV glad_vkCreateExternalComputeQueueNV GLAD_API_CALL PFN_vkCreateFence glad_vkCreateFence; #define vkCreateFence glad_vkCreateFence GLAD_API_CALL PFN_vkCreateFramebuffer glad_vkCreateFramebuffer; @@ -10265,39 +18475,53 @@ GLAD_API_CALL PFN_vkCreateHeadlessSurfaceEXT glad_vkCreateHeadlessSurfaceEXT; #if defined(VK_USE_PLATFORM_IOS_MVK) GLAD_API_CALL PFN_vkCreateIOSSurfaceMVK glad_vkCreateIOSSurfaceMVK; #define vkCreateIOSSurfaceMVK glad_vkCreateIOSSurfaceMVK + #endif GLAD_API_CALL PFN_vkCreateImage glad_vkCreateImage; #define vkCreateImage glad_vkCreateImage #if defined(VK_USE_PLATFORM_FUCHSIA) GLAD_API_CALL PFN_vkCreateImagePipeSurfaceFUCHSIA glad_vkCreateImagePipeSurfaceFUCHSIA; #define vkCreateImagePipeSurfaceFUCHSIA glad_vkCreateImagePipeSurfaceFUCHSIA + #endif GLAD_API_CALL PFN_vkCreateImageView glad_vkCreateImageView; #define vkCreateImageView glad_vkCreateImageView +GLAD_API_CALL PFN_vkCreateIndirectCommandsLayoutEXT glad_vkCreateIndirectCommandsLayoutEXT; +#define vkCreateIndirectCommandsLayoutEXT glad_vkCreateIndirectCommandsLayoutEXT GLAD_API_CALL PFN_vkCreateIndirectCommandsLayoutNV glad_vkCreateIndirectCommandsLayoutNV; #define vkCreateIndirectCommandsLayoutNV glad_vkCreateIndirectCommandsLayoutNV +GLAD_API_CALL PFN_vkCreateIndirectExecutionSetEXT glad_vkCreateIndirectExecutionSetEXT; +#define vkCreateIndirectExecutionSetEXT glad_vkCreateIndirectExecutionSetEXT GLAD_API_CALL PFN_vkCreateInstance glad_vkCreateInstance; #define vkCreateInstance glad_vkCreateInstance #if defined(VK_USE_PLATFORM_MACOS_MVK) GLAD_API_CALL PFN_vkCreateMacOSSurfaceMVK glad_vkCreateMacOSSurfaceMVK; #define vkCreateMacOSSurfaceMVK glad_vkCreateMacOSSurfaceMVK + #endif #if defined(VK_USE_PLATFORM_METAL_EXT) GLAD_API_CALL PFN_vkCreateMetalSurfaceEXT glad_vkCreateMetalSurfaceEXT; #define vkCreateMetalSurfaceEXT glad_vkCreateMetalSurfaceEXT + #endif +GLAD_API_CALL PFN_vkCreateMicromapEXT glad_vkCreateMicromapEXT; +#define vkCreateMicromapEXT glad_vkCreateMicromapEXT +GLAD_API_CALL PFN_vkCreateOpticalFlowSessionNV glad_vkCreateOpticalFlowSessionNV; +#define vkCreateOpticalFlowSessionNV glad_vkCreateOpticalFlowSessionNV +GLAD_API_CALL PFN_vkCreatePipelineBinariesKHR glad_vkCreatePipelineBinariesKHR; +#define vkCreatePipelineBinariesKHR glad_vkCreatePipelineBinariesKHR GLAD_API_CALL PFN_vkCreatePipelineCache glad_vkCreatePipelineCache; #define vkCreatePipelineCache glad_vkCreatePipelineCache GLAD_API_CALL PFN_vkCreatePipelineLayout glad_vkCreatePipelineLayout; #define vkCreatePipelineLayout glad_vkCreatePipelineLayout +GLAD_API_CALL PFN_vkCreatePrivateDataSlot glad_vkCreatePrivateDataSlot; +#define vkCreatePrivateDataSlot glad_vkCreatePrivateDataSlot GLAD_API_CALL PFN_vkCreatePrivateDataSlotEXT glad_vkCreatePrivateDataSlotEXT; #define vkCreatePrivateDataSlotEXT glad_vkCreatePrivateDataSlotEXT GLAD_API_CALL PFN_vkCreateQueryPool glad_vkCreateQueryPool; #define vkCreateQueryPool glad_vkCreateQueryPool -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkCreateRayTracingPipelinesKHR glad_vkCreateRayTracingPipelinesKHR; #define vkCreateRayTracingPipelinesKHR glad_vkCreateRayTracingPipelinesKHR -#endif GLAD_API_CALL PFN_vkCreateRayTracingPipelinesNV glad_vkCreateRayTracingPipelinesNV; #define vkCreateRayTracingPipelinesNV glad_vkCreateRayTracingPipelinesNV GLAD_API_CALL PFN_vkCreateRenderPass glad_vkCreateRenderPass; @@ -10312,15 +18536,23 @@ GLAD_API_CALL PFN_vkCreateSamplerYcbcrConversion glad_vkCreateSamplerYcbcrConver #define vkCreateSamplerYcbcrConversion glad_vkCreateSamplerYcbcrConversion GLAD_API_CALL PFN_vkCreateSamplerYcbcrConversionKHR glad_vkCreateSamplerYcbcrConversionKHR; #define vkCreateSamplerYcbcrConversionKHR glad_vkCreateSamplerYcbcrConversionKHR +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +GLAD_API_CALL PFN_vkCreateScreenSurfaceQNX glad_vkCreateScreenSurfaceQNX; +#define vkCreateScreenSurfaceQNX glad_vkCreateScreenSurfaceQNX + +#endif GLAD_API_CALL PFN_vkCreateSemaphore glad_vkCreateSemaphore; #define vkCreateSemaphore glad_vkCreateSemaphore GLAD_API_CALL PFN_vkCreateShaderModule glad_vkCreateShaderModule; #define vkCreateShaderModule glad_vkCreateShaderModule +GLAD_API_CALL PFN_vkCreateShadersEXT glad_vkCreateShadersEXT; +#define vkCreateShadersEXT glad_vkCreateShadersEXT GLAD_API_CALL PFN_vkCreateSharedSwapchainsKHR glad_vkCreateSharedSwapchainsKHR; #define vkCreateSharedSwapchainsKHR glad_vkCreateSharedSwapchainsKHR #if defined(VK_USE_PLATFORM_GGP) GLAD_API_CALL PFN_vkCreateStreamDescriptorSurfaceGGP glad_vkCreateStreamDescriptorSurfaceGGP; #define vkCreateStreamDescriptorSurfaceGGP glad_vkCreateStreamDescriptorSurfaceGGP + #endif GLAD_API_CALL PFN_vkCreateSwapchainKHR glad_vkCreateSwapchainKHR; #define vkCreateSwapchainKHR glad_vkCreateSwapchainKHR @@ -10329,22 +18561,27 @@ GLAD_API_CALL PFN_vkCreateValidationCacheEXT glad_vkCreateValidationCacheEXT; #if defined(VK_USE_PLATFORM_VI_NN) GLAD_API_CALL PFN_vkCreateViSurfaceNN glad_vkCreateViSurfaceNN; #define vkCreateViSurfaceNN glad_vkCreateViSurfaceNN + #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) GLAD_API_CALL PFN_vkCreateWaylandSurfaceKHR glad_vkCreateWaylandSurfaceKHR; #define vkCreateWaylandSurfaceKHR glad_vkCreateWaylandSurfaceKHR + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkCreateWin32SurfaceKHR glad_vkCreateWin32SurfaceKHR; #define vkCreateWin32SurfaceKHR glad_vkCreateWin32SurfaceKHR + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) GLAD_API_CALL PFN_vkCreateXcbSurfaceKHR glad_vkCreateXcbSurfaceKHR; #define vkCreateXcbSurfaceKHR glad_vkCreateXcbSurfaceKHR + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) GLAD_API_CALL PFN_vkCreateXlibSurfaceKHR glad_vkCreateXlibSurfaceKHR; #define vkCreateXlibSurfaceKHR glad_vkCreateXlibSurfaceKHR + #endif GLAD_API_CALL PFN_vkDebugMarkerSetObjectNameEXT glad_vkDebugMarkerSetObjectNameEXT; #define vkDebugMarkerSetObjectNameEXT glad_vkDebugMarkerSetObjectNameEXT @@ -10352,30 +18589,43 @@ GLAD_API_CALL PFN_vkDebugMarkerSetObjectTagEXT glad_vkDebugMarkerSetObjectTagEXT #define vkDebugMarkerSetObjectTagEXT glad_vkDebugMarkerSetObjectTagEXT GLAD_API_CALL PFN_vkDebugReportMessageEXT glad_vkDebugReportMessageEXT; #define vkDebugReportMessageEXT glad_vkDebugReportMessageEXT -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkDeferredOperationJoinKHR glad_vkDeferredOperationJoinKHR; #define vkDeferredOperationJoinKHR glad_vkDeferredOperationJoinKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkDestroyAccelerationStructureKHR glad_vkDestroyAccelerationStructureKHR; #define vkDestroyAccelerationStructureKHR glad_vkDestroyAccelerationStructureKHR -#endif GLAD_API_CALL PFN_vkDestroyAccelerationStructureNV glad_vkDestroyAccelerationStructureNV; #define vkDestroyAccelerationStructureNV glad_vkDestroyAccelerationStructureNV GLAD_API_CALL PFN_vkDestroyBuffer glad_vkDestroyBuffer; #define vkDestroyBuffer glad_vkDestroyBuffer +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkDestroyBufferCollectionFUCHSIA glad_vkDestroyBufferCollectionFUCHSIA; +#define vkDestroyBufferCollectionFUCHSIA glad_vkDestroyBufferCollectionFUCHSIA + +#endif GLAD_API_CALL PFN_vkDestroyBufferView glad_vkDestroyBufferView; #define vkDestroyBufferView glad_vkDestroyBufferView GLAD_API_CALL PFN_vkDestroyCommandPool glad_vkDestroyCommandPool; #define vkDestroyCommandPool glad_vkDestroyCommandPool +GLAD_API_CALL PFN_vkDestroyCuFunctionNVX glad_vkDestroyCuFunctionNVX; +#define vkDestroyCuFunctionNVX glad_vkDestroyCuFunctionNVX +GLAD_API_CALL PFN_vkDestroyCuModuleNVX glad_vkDestroyCuModuleNVX; +#define vkDestroyCuModuleNVX glad_vkDestroyCuModuleNVX +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkDestroyCudaFunctionNV glad_vkDestroyCudaFunctionNV; +#define vkDestroyCudaFunctionNV glad_vkDestroyCudaFunctionNV + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkDestroyCudaModuleNV glad_vkDestroyCudaModuleNV; +#define vkDestroyCudaModuleNV glad_vkDestroyCudaModuleNV + +#endif GLAD_API_CALL PFN_vkDestroyDebugReportCallbackEXT glad_vkDestroyDebugReportCallbackEXT; #define vkDestroyDebugReportCallbackEXT glad_vkDestroyDebugReportCallbackEXT GLAD_API_CALL PFN_vkDestroyDebugUtilsMessengerEXT glad_vkDestroyDebugUtilsMessengerEXT; #define vkDestroyDebugUtilsMessengerEXT glad_vkDestroyDebugUtilsMessengerEXT -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkDestroyDeferredOperationKHR glad_vkDestroyDeferredOperationKHR; #define vkDestroyDeferredOperationKHR glad_vkDestroyDeferredOperationKHR -#endif GLAD_API_CALL PFN_vkDestroyDescriptorPool glad_vkDestroyDescriptorPool; #define vkDestroyDescriptorPool glad_vkDestroyDescriptorPool GLAD_API_CALL PFN_vkDestroyDescriptorSetLayout glad_vkDestroyDescriptorSetLayout; @@ -10388,6 +18638,8 @@ GLAD_API_CALL PFN_vkDestroyDevice glad_vkDestroyDevice; #define vkDestroyDevice glad_vkDestroyDevice GLAD_API_CALL PFN_vkDestroyEvent glad_vkDestroyEvent; #define vkDestroyEvent glad_vkDestroyEvent +GLAD_API_CALL PFN_vkDestroyExternalComputeQueueNV glad_vkDestroyExternalComputeQueueNV; +#define vkDestroyExternalComputeQueueNV glad_vkDestroyExternalComputeQueueNV GLAD_API_CALL PFN_vkDestroyFence glad_vkDestroyFence; #define vkDestroyFence glad_vkDestroyFence GLAD_API_CALL PFN_vkDestroyFramebuffer glad_vkDestroyFramebuffer; @@ -10396,16 +18648,28 @@ GLAD_API_CALL PFN_vkDestroyImage glad_vkDestroyImage; #define vkDestroyImage glad_vkDestroyImage GLAD_API_CALL PFN_vkDestroyImageView glad_vkDestroyImageView; #define vkDestroyImageView glad_vkDestroyImageView +GLAD_API_CALL PFN_vkDestroyIndirectCommandsLayoutEXT glad_vkDestroyIndirectCommandsLayoutEXT; +#define vkDestroyIndirectCommandsLayoutEXT glad_vkDestroyIndirectCommandsLayoutEXT GLAD_API_CALL PFN_vkDestroyIndirectCommandsLayoutNV glad_vkDestroyIndirectCommandsLayoutNV; #define vkDestroyIndirectCommandsLayoutNV glad_vkDestroyIndirectCommandsLayoutNV +GLAD_API_CALL PFN_vkDestroyIndirectExecutionSetEXT glad_vkDestroyIndirectExecutionSetEXT; +#define vkDestroyIndirectExecutionSetEXT glad_vkDestroyIndirectExecutionSetEXT GLAD_API_CALL PFN_vkDestroyInstance glad_vkDestroyInstance; #define vkDestroyInstance glad_vkDestroyInstance +GLAD_API_CALL PFN_vkDestroyMicromapEXT glad_vkDestroyMicromapEXT; +#define vkDestroyMicromapEXT glad_vkDestroyMicromapEXT +GLAD_API_CALL PFN_vkDestroyOpticalFlowSessionNV glad_vkDestroyOpticalFlowSessionNV; +#define vkDestroyOpticalFlowSessionNV glad_vkDestroyOpticalFlowSessionNV GLAD_API_CALL PFN_vkDestroyPipeline glad_vkDestroyPipeline; #define vkDestroyPipeline glad_vkDestroyPipeline +GLAD_API_CALL PFN_vkDestroyPipelineBinaryKHR glad_vkDestroyPipelineBinaryKHR; +#define vkDestroyPipelineBinaryKHR glad_vkDestroyPipelineBinaryKHR GLAD_API_CALL PFN_vkDestroyPipelineCache glad_vkDestroyPipelineCache; #define vkDestroyPipelineCache glad_vkDestroyPipelineCache GLAD_API_CALL PFN_vkDestroyPipelineLayout glad_vkDestroyPipelineLayout; #define vkDestroyPipelineLayout glad_vkDestroyPipelineLayout +GLAD_API_CALL PFN_vkDestroyPrivateDataSlot glad_vkDestroyPrivateDataSlot; +#define vkDestroyPrivateDataSlot glad_vkDestroyPrivateDataSlot GLAD_API_CALL PFN_vkDestroyPrivateDataSlotEXT glad_vkDestroyPrivateDataSlotEXT; #define vkDestroyPrivateDataSlotEXT glad_vkDestroyPrivateDataSlotEXT GLAD_API_CALL PFN_vkDestroyQueryPool glad_vkDestroyQueryPool; @@ -10420,6 +18684,8 @@ GLAD_API_CALL PFN_vkDestroySamplerYcbcrConversionKHR glad_vkDestroySamplerYcbcrC #define vkDestroySamplerYcbcrConversionKHR glad_vkDestroySamplerYcbcrConversionKHR GLAD_API_CALL PFN_vkDestroySemaphore glad_vkDestroySemaphore; #define vkDestroySemaphore glad_vkDestroySemaphore +GLAD_API_CALL PFN_vkDestroyShaderEXT glad_vkDestroyShaderEXT; +#define vkDestroyShaderEXT glad_vkDestroyShaderEXT GLAD_API_CALL PFN_vkDestroyShaderModule glad_vkDestroyShaderModule; #define vkDestroyShaderModule glad_vkDestroyShaderModule GLAD_API_CALL PFN_vkDestroySurfaceKHR glad_vkDestroySurfaceKHR; @@ -10452,6 +18718,11 @@ GLAD_API_CALL PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKH #define vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR glad_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR GLAD_API_CALL PFN_vkEnumeratePhysicalDevices glad_vkEnumeratePhysicalDevices; #define vkEnumeratePhysicalDevices glad_vkEnumeratePhysicalDevices +#if defined(VK_USE_PLATFORM_METAL_EXT) +GLAD_API_CALL PFN_vkExportMetalObjectsEXT glad_vkExportMetalObjectsEXT; +#define vkExportMetalObjectsEXT glad_vkExportMetalObjectsEXT + +#endif GLAD_API_CALL PFN_vkFlushMappedMemoryRanges glad_vkFlushMappedMemoryRanges; #define vkFlushMappedMemoryRanges glad_vkFlushMappedMemoryRanges GLAD_API_CALL PFN_vkFreeCommandBuffers glad_vkFreeCommandBuffers; @@ -10460,21 +18731,25 @@ GLAD_API_CALL PFN_vkFreeDescriptorSets glad_vkFreeDescriptorSets; #define vkFreeDescriptorSets glad_vkFreeDescriptorSets GLAD_API_CALL PFN_vkFreeMemory glad_vkFreeMemory; #define vkFreeMemory glad_vkFreeMemory -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkGetAccelerationStructureBuildSizesKHR glad_vkGetAccelerationStructureBuildSizesKHR; +#define vkGetAccelerationStructureBuildSizesKHR glad_vkGetAccelerationStructureBuildSizesKHR GLAD_API_CALL PFN_vkGetAccelerationStructureDeviceAddressKHR glad_vkGetAccelerationStructureDeviceAddressKHR; #define vkGetAccelerationStructureDeviceAddressKHR glad_vkGetAccelerationStructureDeviceAddressKHR -#endif GLAD_API_CALL PFN_vkGetAccelerationStructureHandleNV glad_vkGetAccelerationStructureHandleNV; #define vkGetAccelerationStructureHandleNV glad_vkGetAccelerationStructureHandleNV -#if defined(VK_ENABLE_BETA_EXTENSIONS) -GLAD_API_CALL PFN_vkGetAccelerationStructureMemoryRequirementsKHR glad_vkGetAccelerationStructureMemoryRequirementsKHR; -#define vkGetAccelerationStructureMemoryRequirementsKHR glad_vkGetAccelerationStructureMemoryRequirementsKHR -#endif GLAD_API_CALL PFN_vkGetAccelerationStructureMemoryRequirementsNV glad_vkGetAccelerationStructureMemoryRequirementsNV; #define vkGetAccelerationStructureMemoryRequirementsNV glad_vkGetAccelerationStructureMemoryRequirementsNV +GLAD_API_CALL PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT glad_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT; +#define vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT glad_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT #if defined(VK_USE_PLATFORM_ANDROID_KHR) GLAD_API_CALL PFN_vkGetAndroidHardwareBufferPropertiesANDROID glad_vkGetAndroidHardwareBufferPropertiesANDROID; #define vkGetAndroidHardwareBufferPropertiesANDROID glad_vkGetAndroidHardwareBufferPropertiesANDROID + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkGetBufferCollectionPropertiesFUCHSIA glad_vkGetBufferCollectionPropertiesFUCHSIA; +#define vkGetBufferCollectionPropertiesFUCHSIA glad_vkGetBufferCollectionPropertiesFUCHSIA + #endif GLAD_API_CALL PFN_vkGetBufferDeviceAddress glad_vkGetBufferDeviceAddress; #define vkGetBufferDeviceAddress glad_vkGetBufferDeviceAddress @@ -10492,24 +18767,45 @@ GLAD_API_CALL PFN_vkGetBufferOpaqueCaptureAddress glad_vkGetBufferOpaqueCaptureA #define vkGetBufferOpaqueCaptureAddress glad_vkGetBufferOpaqueCaptureAddress GLAD_API_CALL PFN_vkGetBufferOpaqueCaptureAddressKHR glad_vkGetBufferOpaqueCaptureAddressKHR; #define vkGetBufferOpaqueCaptureAddressKHR glad_vkGetBufferOpaqueCaptureAddressKHR +GLAD_API_CALL PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT glad_vkGetBufferOpaqueCaptureDescriptorDataEXT; +#define vkGetBufferOpaqueCaptureDescriptorDataEXT glad_vkGetBufferOpaqueCaptureDescriptorDataEXT GLAD_API_CALL PFN_vkGetCalibratedTimestampsEXT glad_vkGetCalibratedTimestampsEXT; #define vkGetCalibratedTimestampsEXT glad_vkGetCalibratedTimestampsEXT +GLAD_API_CALL PFN_vkGetCalibratedTimestampsKHR glad_vkGetCalibratedTimestampsKHR; +#define vkGetCalibratedTimestampsKHR glad_vkGetCalibratedTimestampsKHR +GLAD_API_CALL PFN_vkGetClusterAccelerationStructureBuildSizesNV glad_vkGetClusterAccelerationStructureBuildSizesNV; +#define vkGetClusterAccelerationStructureBuildSizesNV glad_vkGetClusterAccelerationStructureBuildSizesNV #if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkGetCudaModuleCacheNV glad_vkGetCudaModuleCacheNV; +#define vkGetCudaModuleCacheNV glad_vkGetCudaModuleCacheNV + +#endif GLAD_API_CALL PFN_vkGetDeferredOperationMaxConcurrencyKHR glad_vkGetDeferredOperationMaxConcurrencyKHR; #define vkGetDeferredOperationMaxConcurrencyKHR glad_vkGetDeferredOperationMaxConcurrencyKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkGetDeferredOperationResultKHR glad_vkGetDeferredOperationResultKHR; #define vkGetDeferredOperationResultKHR glad_vkGetDeferredOperationResultKHR -#endif +GLAD_API_CALL PFN_vkGetDescriptorEXT glad_vkGetDescriptorEXT; +#define vkGetDescriptorEXT glad_vkGetDescriptorEXT +GLAD_API_CALL PFN_vkGetDescriptorSetHostMappingVALVE glad_vkGetDescriptorSetHostMappingVALVE; +#define vkGetDescriptorSetHostMappingVALVE glad_vkGetDescriptorSetHostMappingVALVE +GLAD_API_CALL PFN_vkGetDescriptorSetLayoutBindingOffsetEXT glad_vkGetDescriptorSetLayoutBindingOffsetEXT; +#define vkGetDescriptorSetLayoutBindingOffsetEXT glad_vkGetDescriptorSetLayoutBindingOffsetEXT +GLAD_API_CALL PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE glad_vkGetDescriptorSetLayoutHostMappingInfoVALVE; +#define vkGetDescriptorSetLayoutHostMappingInfoVALVE glad_vkGetDescriptorSetLayoutHostMappingInfoVALVE +GLAD_API_CALL PFN_vkGetDescriptorSetLayoutSizeEXT glad_vkGetDescriptorSetLayoutSizeEXT; +#define vkGetDescriptorSetLayoutSizeEXT glad_vkGetDescriptorSetLayoutSizeEXT GLAD_API_CALL PFN_vkGetDescriptorSetLayoutSupport glad_vkGetDescriptorSetLayoutSupport; #define vkGetDescriptorSetLayoutSupport glad_vkGetDescriptorSetLayoutSupport GLAD_API_CALL PFN_vkGetDescriptorSetLayoutSupportKHR glad_vkGetDescriptorSetLayoutSupportKHR; #define vkGetDescriptorSetLayoutSupportKHR glad_vkGetDescriptorSetLayoutSupportKHR -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkGetDeviceAccelerationStructureCompatibilityKHR glad_vkGetDeviceAccelerationStructureCompatibilityKHR; #define vkGetDeviceAccelerationStructureCompatibilityKHR glad_vkGetDeviceAccelerationStructureCompatibilityKHR -#endif +GLAD_API_CALL PFN_vkGetDeviceBufferMemoryRequirements glad_vkGetDeviceBufferMemoryRequirements; +#define vkGetDeviceBufferMemoryRequirements glad_vkGetDeviceBufferMemoryRequirements +GLAD_API_CALL PFN_vkGetDeviceBufferMemoryRequirementsKHR glad_vkGetDeviceBufferMemoryRequirementsKHR; +#define vkGetDeviceBufferMemoryRequirementsKHR glad_vkGetDeviceBufferMemoryRequirementsKHR +GLAD_API_CALL PFN_vkGetDeviceFaultInfoEXT glad_vkGetDeviceFaultInfoEXT; +#define vkGetDeviceFaultInfoEXT glad_vkGetDeviceFaultInfoEXT GLAD_API_CALL PFN_vkGetDeviceGroupPeerMemoryFeatures glad_vkGetDeviceGroupPeerMemoryFeatures; #define vkGetDeviceGroupPeerMemoryFeatures glad_vkGetDeviceGroupPeerMemoryFeatures GLAD_API_CALL PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR glad_vkGetDeviceGroupPeerMemoryFeaturesKHR; @@ -10519,21 +18815,38 @@ GLAD_API_CALL PFN_vkGetDeviceGroupPresentCapabilitiesKHR glad_vkGetDeviceGroupPr #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetDeviceGroupSurfacePresentModes2EXT glad_vkGetDeviceGroupSurfacePresentModes2EXT; #define vkGetDeviceGroupSurfacePresentModes2EXT glad_vkGetDeviceGroupSurfacePresentModes2EXT + #endif GLAD_API_CALL PFN_vkGetDeviceGroupSurfacePresentModesKHR glad_vkGetDeviceGroupSurfacePresentModesKHR; #define vkGetDeviceGroupSurfacePresentModesKHR glad_vkGetDeviceGroupSurfacePresentModesKHR +GLAD_API_CALL PFN_vkGetDeviceImageMemoryRequirements glad_vkGetDeviceImageMemoryRequirements; +#define vkGetDeviceImageMemoryRequirements glad_vkGetDeviceImageMemoryRequirements +GLAD_API_CALL PFN_vkGetDeviceImageMemoryRequirementsKHR glad_vkGetDeviceImageMemoryRequirementsKHR; +#define vkGetDeviceImageMemoryRequirementsKHR glad_vkGetDeviceImageMemoryRequirementsKHR +GLAD_API_CALL PFN_vkGetDeviceImageSparseMemoryRequirements glad_vkGetDeviceImageSparseMemoryRequirements; +#define vkGetDeviceImageSparseMemoryRequirements glad_vkGetDeviceImageSparseMemoryRequirements +GLAD_API_CALL PFN_vkGetDeviceImageSparseMemoryRequirementsKHR glad_vkGetDeviceImageSparseMemoryRequirementsKHR; +#define vkGetDeviceImageSparseMemoryRequirementsKHR glad_vkGetDeviceImageSparseMemoryRequirementsKHR +GLAD_API_CALL PFN_vkGetDeviceImageSubresourceLayout glad_vkGetDeviceImageSubresourceLayout; +#define vkGetDeviceImageSubresourceLayout glad_vkGetDeviceImageSubresourceLayout +GLAD_API_CALL PFN_vkGetDeviceImageSubresourceLayoutKHR glad_vkGetDeviceImageSubresourceLayoutKHR; +#define vkGetDeviceImageSubresourceLayoutKHR glad_vkGetDeviceImageSubresourceLayoutKHR GLAD_API_CALL PFN_vkGetDeviceMemoryCommitment glad_vkGetDeviceMemoryCommitment; #define vkGetDeviceMemoryCommitment glad_vkGetDeviceMemoryCommitment GLAD_API_CALL PFN_vkGetDeviceMemoryOpaqueCaptureAddress glad_vkGetDeviceMemoryOpaqueCaptureAddress; #define vkGetDeviceMemoryOpaqueCaptureAddress glad_vkGetDeviceMemoryOpaqueCaptureAddress GLAD_API_CALL PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR glad_vkGetDeviceMemoryOpaqueCaptureAddressKHR; #define vkGetDeviceMemoryOpaqueCaptureAddressKHR glad_vkGetDeviceMemoryOpaqueCaptureAddressKHR +GLAD_API_CALL PFN_vkGetDeviceMicromapCompatibilityEXT glad_vkGetDeviceMicromapCompatibilityEXT; +#define vkGetDeviceMicromapCompatibilityEXT glad_vkGetDeviceMicromapCompatibilityEXT GLAD_API_CALL PFN_vkGetDeviceProcAddr glad_vkGetDeviceProcAddr; #define vkGetDeviceProcAddr glad_vkGetDeviceProcAddr GLAD_API_CALL PFN_vkGetDeviceQueue glad_vkGetDeviceQueue; #define vkGetDeviceQueue glad_vkGetDeviceQueue GLAD_API_CALL PFN_vkGetDeviceQueue2 glad_vkGetDeviceQueue2; #define vkGetDeviceQueue2 glad_vkGetDeviceQueue2 +GLAD_API_CALL PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI glad_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI; +#define vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI glad_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI GLAD_API_CALL PFN_vkGetDisplayModeProperties2KHR glad_vkGetDisplayModeProperties2KHR; #define vkGetDisplayModeProperties2KHR glad_vkGetDisplayModeProperties2KHR GLAD_API_CALL PFN_vkGetDisplayModePropertiesKHR glad_vkGetDisplayModePropertiesKHR; @@ -10544,8 +18857,24 @@ GLAD_API_CALL PFN_vkGetDisplayPlaneCapabilitiesKHR glad_vkGetDisplayPlaneCapabil #define vkGetDisplayPlaneCapabilitiesKHR glad_vkGetDisplayPlaneCapabilitiesKHR GLAD_API_CALL PFN_vkGetDisplayPlaneSupportedDisplaysKHR glad_vkGetDisplayPlaneSupportedDisplaysKHR; #define vkGetDisplayPlaneSupportedDisplaysKHR glad_vkGetDisplayPlaneSupportedDisplaysKHR +GLAD_API_CALL PFN_vkGetDrmDisplayEXT glad_vkGetDrmDisplayEXT; +#define vkGetDrmDisplayEXT glad_vkGetDrmDisplayEXT +GLAD_API_CALL PFN_vkGetDynamicRenderingTilePropertiesQCOM glad_vkGetDynamicRenderingTilePropertiesQCOM; +#define vkGetDynamicRenderingTilePropertiesQCOM glad_vkGetDynamicRenderingTilePropertiesQCOM GLAD_API_CALL PFN_vkGetEventStatus glad_vkGetEventStatus; #define vkGetEventStatus glad_vkGetEventStatus +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkGetExecutionGraphPipelineNodeIndexAMDX glad_vkGetExecutionGraphPipelineNodeIndexAMDX; +#define vkGetExecutionGraphPipelineNodeIndexAMDX glad_vkGetExecutionGraphPipelineNodeIndexAMDX + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkGetExecutionGraphPipelineScratchSizeAMDX glad_vkGetExecutionGraphPipelineScratchSizeAMDX; +#define vkGetExecutionGraphPipelineScratchSizeAMDX glad_vkGetExecutionGraphPipelineScratchSizeAMDX + +#endif +GLAD_API_CALL PFN_vkGetExternalComputeQueueDataNV glad_vkGetExternalComputeQueueDataNV; +#define vkGetExternalComputeQueueDataNV glad_vkGetExternalComputeQueueDataNV GLAD_API_CALL PFN_vkGetFenceFdKHR glad_vkGetFenceFdKHR; #define vkGetFenceFdKHR glad_vkGetFenceFdKHR GLAD_API_CALL PFN_vkGetFenceStatus glad_vkGetFenceStatus; @@ -10553,7 +18882,12 @@ GLAD_API_CALL PFN_vkGetFenceStatus glad_vkGetFenceStatus; #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetFenceWin32HandleKHR glad_vkGetFenceWin32HandleKHR; #define vkGetFenceWin32HandleKHR glad_vkGetFenceWin32HandleKHR + #endif +GLAD_API_CALL PFN_vkGetFramebufferTilePropertiesQCOM glad_vkGetFramebufferTilePropertiesQCOM; +#define vkGetFramebufferTilePropertiesQCOM glad_vkGetFramebufferTilePropertiesQCOM +GLAD_API_CALL PFN_vkGetGeneratedCommandsMemoryRequirementsEXT glad_vkGetGeneratedCommandsMemoryRequirementsEXT; +#define vkGetGeneratedCommandsMemoryRequirementsEXT glad_vkGetGeneratedCommandsMemoryRequirementsEXT GLAD_API_CALL PFN_vkGetGeneratedCommandsMemoryRequirementsNV glad_vkGetGeneratedCommandsMemoryRequirementsNV; #define vkGetGeneratedCommandsMemoryRequirementsNV glad_vkGetGeneratedCommandsMemoryRequirementsNV GLAD_API_CALL PFN_vkGetImageDrmFormatModifierPropertiesEXT glad_vkGetImageDrmFormatModifierPropertiesEXT; @@ -10564,6 +18898,8 @@ GLAD_API_CALL PFN_vkGetImageMemoryRequirements2 glad_vkGetImageMemoryRequirement #define vkGetImageMemoryRequirements2 glad_vkGetImageMemoryRequirements2 GLAD_API_CALL PFN_vkGetImageMemoryRequirements2KHR glad_vkGetImageMemoryRequirements2KHR; #define vkGetImageMemoryRequirements2KHR glad_vkGetImageMemoryRequirements2KHR +GLAD_API_CALL PFN_vkGetImageOpaqueCaptureDescriptorDataEXT glad_vkGetImageOpaqueCaptureDescriptorDataEXT; +#define vkGetImageOpaqueCaptureDescriptorDataEXT glad_vkGetImageOpaqueCaptureDescriptorDataEXT GLAD_API_CALL PFN_vkGetImageSparseMemoryRequirements glad_vkGetImageSparseMemoryRequirements; #define vkGetImageSparseMemoryRequirements glad_vkGetImageSparseMemoryRequirements GLAD_API_CALL PFN_vkGetImageSparseMemoryRequirements2 glad_vkGetImageSparseMemoryRequirements2; @@ -10572,15 +18908,28 @@ GLAD_API_CALL PFN_vkGetImageSparseMemoryRequirements2KHR glad_vkGetImageSparseMe #define vkGetImageSparseMemoryRequirements2KHR glad_vkGetImageSparseMemoryRequirements2KHR GLAD_API_CALL PFN_vkGetImageSubresourceLayout glad_vkGetImageSubresourceLayout; #define vkGetImageSubresourceLayout glad_vkGetImageSubresourceLayout +GLAD_API_CALL PFN_vkGetImageSubresourceLayout2 glad_vkGetImageSubresourceLayout2; +#define vkGetImageSubresourceLayout2 glad_vkGetImageSubresourceLayout2 +GLAD_API_CALL PFN_vkGetImageSubresourceLayout2EXT glad_vkGetImageSubresourceLayout2EXT; +#define vkGetImageSubresourceLayout2EXT glad_vkGetImageSubresourceLayout2EXT +GLAD_API_CALL PFN_vkGetImageSubresourceLayout2KHR glad_vkGetImageSubresourceLayout2KHR; +#define vkGetImageSubresourceLayout2KHR glad_vkGetImageSubresourceLayout2KHR GLAD_API_CALL PFN_vkGetImageViewAddressNVX glad_vkGetImageViewAddressNVX; #define vkGetImageViewAddressNVX glad_vkGetImageViewAddressNVX +GLAD_API_CALL PFN_vkGetImageViewHandle64NVX glad_vkGetImageViewHandle64NVX; +#define vkGetImageViewHandle64NVX glad_vkGetImageViewHandle64NVX GLAD_API_CALL PFN_vkGetImageViewHandleNVX glad_vkGetImageViewHandleNVX; #define vkGetImageViewHandleNVX glad_vkGetImageViewHandleNVX +GLAD_API_CALL PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT glad_vkGetImageViewOpaqueCaptureDescriptorDataEXT; +#define vkGetImageViewOpaqueCaptureDescriptorDataEXT glad_vkGetImageViewOpaqueCaptureDescriptorDataEXT GLAD_API_CALL PFN_vkGetInstanceProcAddr glad_vkGetInstanceProcAddr; #define vkGetInstanceProcAddr glad_vkGetInstanceProcAddr +GLAD_API_CALL PFN_vkGetLatencyTimingsNV glad_vkGetLatencyTimingsNV; +#define vkGetLatencyTimingsNV glad_vkGetLatencyTimingsNV #if defined(VK_USE_PLATFORM_ANDROID_KHR) GLAD_API_CALL PFN_vkGetMemoryAndroidHardwareBufferANDROID glad_vkGetMemoryAndroidHardwareBufferANDROID; #define vkGetMemoryAndroidHardwareBufferANDROID glad_vkGetMemoryAndroidHardwareBufferANDROID + #endif GLAD_API_CALL PFN_vkGetMemoryFdKHR glad_vkGetMemoryFdKHR; #define vkGetMemoryFdKHR glad_vkGetMemoryFdKHR @@ -10588,29 +18937,67 @@ GLAD_API_CALL PFN_vkGetMemoryFdPropertiesKHR glad_vkGetMemoryFdPropertiesKHR; #define vkGetMemoryFdPropertiesKHR glad_vkGetMemoryFdPropertiesKHR GLAD_API_CALL PFN_vkGetMemoryHostPointerPropertiesEXT glad_vkGetMemoryHostPointerPropertiesEXT; #define vkGetMemoryHostPointerPropertiesEXT glad_vkGetMemoryHostPointerPropertiesEXT +#if defined(VK_USE_PLATFORM_METAL_EXT) +GLAD_API_CALL PFN_vkGetMemoryMetalHandleEXT glad_vkGetMemoryMetalHandleEXT; +#define vkGetMemoryMetalHandleEXT glad_vkGetMemoryMetalHandleEXT + +#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +GLAD_API_CALL PFN_vkGetMemoryMetalHandlePropertiesEXT glad_vkGetMemoryMetalHandlePropertiesEXT; +#define vkGetMemoryMetalHandlePropertiesEXT glad_vkGetMemoryMetalHandlePropertiesEXT + +#endif +GLAD_API_CALL PFN_vkGetMemoryRemoteAddressNV glad_vkGetMemoryRemoteAddressNV; +#define vkGetMemoryRemoteAddressNV glad_vkGetMemoryRemoteAddressNV #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetMemoryWin32HandleKHR glad_vkGetMemoryWin32HandleKHR; #define vkGetMemoryWin32HandleKHR glad_vkGetMemoryWin32HandleKHR + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetMemoryWin32HandleNV glad_vkGetMemoryWin32HandleNV; #define vkGetMemoryWin32HandleNV glad_vkGetMemoryWin32HandleNV + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetMemoryWin32HandlePropertiesKHR glad_vkGetMemoryWin32HandlePropertiesKHR; #define vkGetMemoryWin32HandlePropertiesKHR glad_vkGetMemoryWin32HandlePropertiesKHR + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkGetMemoryZirconHandleFUCHSIA glad_vkGetMemoryZirconHandleFUCHSIA; +#define vkGetMemoryZirconHandleFUCHSIA glad_vkGetMemoryZirconHandleFUCHSIA + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA glad_vkGetMemoryZirconHandlePropertiesFUCHSIA; +#define vkGetMemoryZirconHandlePropertiesFUCHSIA glad_vkGetMemoryZirconHandlePropertiesFUCHSIA + #endif +GLAD_API_CALL PFN_vkGetMicromapBuildSizesEXT glad_vkGetMicromapBuildSizesEXT; +#define vkGetMicromapBuildSizesEXT glad_vkGetMicromapBuildSizesEXT +GLAD_API_CALL PFN_vkGetPartitionedAccelerationStructuresBuildSizesNV glad_vkGetPartitionedAccelerationStructuresBuildSizesNV; +#define vkGetPartitionedAccelerationStructuresBuildSizesNV glad_vkGetPartitionedAccelerationStructuresBuildSizesNV GLAD_API_CALL PFN_vkGetPastPresentationTimingGOOGLE glad_vkGetPastPresentationTimingGOOGLE; #define vkGetPastPresentationTimingGOOGLE glad_vkGetPastPresentationTimingGOOGLE GLAD_API_CALL PFN_vkGetPerformanceParameterINTEL glad_vkGetPerformanceParameterINTEL; #define vkGetPerformanceParameterINTEL glad_vkGetPerformanceParameterINTEL GLAD_API_CALL PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT glad_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT; #define vkGetPhysicalDeviceCalibrateableTimeDomainsEXT glad_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT +GLAD_API_CALL PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR glad_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR; +#define vkGetPhysicalDeviceCalibrateableTimeDomainsKHR glad_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR +GLAD_API_CALL PFN_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV glad_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV; +#define vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV glad_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV +GLAD_API_CALL PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR; +#define vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR GLAD_API_CALL PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; #define vkGetPhysicalDeviceCooperativeMatrixPropertiesNV glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV +GLAD_API_CALL PFN_vkGetPhysicalDeviceCooperativeVectorPropertiesNV glad_vkGetPhysicalDeviceCooperativeVectorPropertiesNV; +#define vkGetPhysicalDeviceCooperativeVectorPropertiesNV glad_vkGetPhysicalDeviceCooperativeVectorPropertiesNV #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) GLAD_API_CALL PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT glad_vkGetPhysicalDeviceDirectFBPresentationSupportEXT; #define vkGetPhysicalDeviceDirectFBPresentationSupportEXT glad_vkGetPhysicalDeviceDirectFBPresentationSupportEXT + #endif GLAD_API_CALL PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR glad_vkGetPhysicalDeviceDisplayPlaneProperties2KHR; #define vkGetPhysicalDeviceDisplayPlaneProperties2KHR glad_vkGetPhysicalDeviceDisplayPlaneProperties2KHR @@ -10646,6 +19033,8 @@ GLAD_API_CALL PFN_vkGetPhysicalDeviceFormatProperties2 glad_vkGetPhysicalDeviceF #define vkGetPhysicalDeviceFormatProperties2 glad_vkGetPhysicalDeviceFormatProperties2 GLAD_API_CALL PFN_vkGetPhysicalDeviceFormatProperties2KHR glad_vkGetPhysicalDeviceFormatProperties2KHR; #define vkGetPhysicalDeviceFormatProperties2KHR glad_vkGetPhysicalDeviceFormatProperties2KHR +GLAD_API_CALL PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR glad_vkGetPhysicalDeviceFragmentShadingRatesKHR; +#define vkGetPhysicalDeviceFragmentShadingRatesKHR glad_vkGetPhysicalDeviceFragmentShadingRatesKHR GLAD_API_CALL PFN_vkGetPhysicalDeviceImageFormatProperties glad_vkGetPhysicalDeviceImageFormatProperties; #define vkGetPhysicalDeviceImageFormatProperties glad_vkGetPhysicalDeviceImageFormatProperties GLAD_API_CALL PFN_vkGetPhysicalDeviceImageFormatProperties2 glad_vkGetPhysicalDeviceImageFormatProperties2; @@ -10660,6 +19049,8 @@ GLAD_API_CALL PFN_vkGetPhysicalDeviceMemoryProperties2KHR glad_vkGetPhysicalDevi #define vkGetPhysicalDeviceMemoryProperties2KHR glad_vkGetPhysicalDeviceMemoryProperties2KHR GLAD_API_CALL PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT glad_vkGetPhysicalDeviceMultisamplePropertiesEXT; #define vkGetPhysicalDeviceMultisamplePropertiesEXT glad_vkGetPhysicalDeviceMultisamplePropertiesEXT +GLAD_API_CALL PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV glad_vkGetPhysicalDeviceOpticalFlowImageFormatsNV; +#define vkGetPhysicalDeviceOpticalFlowImageFormatsNV glad_vkGetPhysicalDeviceOpticalFlowImageFormatsNV GLAD_API_CALL PFN_vkGetPhysicalDevicePresentRectanglesKHR glad_vkGetPhysicalDevicePresentRectanglesKHR; #define vkGetPhysicalDevicePresentRectanglesKHR glad_vkGetPhysicalDevicePresentRectanglesKHR GLAD_API_CALL PFN_vkGetPhysicalDeviceProperties glad_vkGetPhysicalDeviceProperties; @@ -10676,6 +19067,11 @@ GLAD_API_CALL PFN_vkGetPhysicalDeviceQueueFamilyProperties2 glad_vkGetPhysicalDe #define vkGetPhysicalDeviceQueueFamilyProperties2 glad_vkGetPhysicalDeviceQueueFamilyProperties2 GLAD_API_CALL PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR glad_vkGetPhysicalDeviceQueueFamilyProperties2KHR; #define vkGetPhysicalDeviceQueueFamilyProperties2KHR glad_vkGetPhysicalDeviceQueueFamilyProperties2KHR +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +GLAD_API_CALL PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX glad_vkGetPhysicalDeviceScreenPresentationSupportQNX; +#define vkGetPhysicalDeviceScreenPresentationSupportQNX glad_vkGetPhysicalDeviceScreenPresentationSupportQNX + +#endif GLAD_API_CALL PFN_vkGetPhysicalDeviceSparseImageFormatProperties glad_vkGetPhysicalDeviceSparseImageFormatProperties; #define vkGetPhysicalDeviceSparseImageFormatProperties glad_vkGetPhysicalDeviceSparseImageFormatProperties GLAD_API_CALL PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 glad_vkGetPhysicalDeviceSparseImageFormatProperties2; @@ -10697,29 +19093,38 @@ GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfaceFormatsKHR glad_vkGetPhysicalDeviceS #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT glad_vkGetPhysicalDeviceSurfacePresentModes2EXT; #define vkGetPhysicalDeviceSurfacePresentModes2EXT glad_vkGetPhysicalDeviceSurfacePresentModes2EXT + #endif GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfacePresentModesKHR glad_vkGetPhysicalDeviceSurfacePresentModesKHR; #define vkGetPhysicalDeviceSurfacePresentModesKHR glad_vkGetPhysicalDeviceSurfacePresentModesKHR GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfaceSupportKHR glad_vkGetPhysicalDeviceSurfaceSupportKHR; #define vkGetPhysicalDeviceSurfaceSupportKHR glad_vkGetPhysicalDeviceSurfaceSupportKHR +GLAD_API_CALL PFN_vkGetPhysicalDeviceToolProperties glad_vkGetPhysicalDeviceToolProperties; +#define vkGetPhysicalDeviceToolProperties glad_vkGetPhysicalDeviceToolProperties GLAD_API_CALL PFN_vkGetPhysicalDeviceToolPropertiesEXT glad_vkGetPhysicalDeviceToolPropertiesEXT; #define vkGetPhysicalDeviceToolPropertiesEXT glad_vkGetPhysicalDeviceToolPropertiesEXT #if defined(VK_USE_PLATFORM_WAYLAND_KHR) GLAD_API_CALL PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR glad_vkGetPhysicalDeviceWaylandPresentationSupportKHR; #define vkGetPhysicalDeviceWaylandPresentationSupportKHR glad_vkGetPhysicalDeviceWaylandPresentationSupportKHR + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR glad_vkGetPhysicalDeviceWin32PresentationSupportKHR; #define vkGetPhysicalDeviceWin32PresentationSupportKHR glad_vkGetPhysicalDeviceWin32PresentationSupportKHR + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) GLAD_API_CALL PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR glad_vkGetPhysicalDeviceXcbPresentationSupportKHR; #define vkGetPhysicalDeviceXcbPresentationSupportKHR glad_vkGetPhysicalDeviceXcbPresentationSupportKHR + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) GLAD_API_CALL PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR glad_vkGetPhysicalDeviceXlibPresentationSupportKHR; #define vkGetPhysicalDeviceXlibPresentationSupportKHR glad_vkGetPhysicalDeviceXlibPresentationSupportKHR + #endif +GLAD_API_CALL PFN_vkGetPipelineBinaryDataKHR glad_vkGetPipelineBinaryDataKHR; +#define vkGetPipelineBinaryDataKHR glad_vkGetPipelineBinaryDataKHR GLAD_API_CALL PFN_vkGetPipelineCacheData glad_vkGetPipelineCacheData; #define vkGetPipelineCacheData glad_vkGetPipelineCacheData GLAD_API_CALL PFN_vkGetPipelineExecutableInternalRepresentationsKHR glad_vkGetPipelineExecutableInternalRepresentationsKHR; @@ -10728,30 +19133,52 @@ GLAD_API_CALL PFN_vkGetPipelineExecutablePropertiesKHR glad_vkGetPipelineExecuta #define vkGetPipelineExecutablePropertiesKHR glad_vkGetPipelineExecutablePropertiesKHR GLAD_API_CALL PFN_vkGetPipelineExecutableStatisticsKHR glad_vkGetPipelineExecutableStatisticsKHR; #define vkGetPipelineExecutableStatisticsKHR glad_vkGetPipelineExecutableStatisticsKHR +GLAD_API_CALL PFN_vkGetPipelineIndirectDeviceAddressNV glad_vkGetPipelineIndirectDeviceAddressNV; +#define vkGetPipelineIndirectDeviceAddressNV glad_vkGetPipelineIndirectDeviceAddressNV +GLAD_API_CALL PFN_vkGetPipelineIndirectMemoryRequirementsNV glad_vkGetPipelineIndirectMemoryRequirementsNV; +#define vkGetPipelineIndirectMemoryRequirementsNV glad_vkGetPipelineIndirectMemoryRequirementsNV +GLAD_API_CALL PFN_vkGetPipelineKeyKHR glad_vkGetPipelineKeyKHR; +#define vkGetPipelineKeyKHR glad_vkGetPipelineKeyKHR +GLAD_API_CALL PFN_vkGetPipelinePropertiesEXT glad_vkGetPipelinePropertiesEXT; +#define vkGetPipelinePropertiesEXT glad_vkGetPipelinePropertiesEXT +GLAD_API_CALL PFN_vkGetPrivateData glad_vkGetPrivateData; +#define vkGetPrivateData glad_vkGetPrivateData GLAD_API_CALL PFN_vkGetPrivateDataEXT glad_vkGetPrivateDataEXT; #define vkGetPrivateDataEXT glad_vkGetPrivateDataEXT GLAD_API_CALL PFN_vkGetQueryPoolResults glad_vkGetQueryPoolResults; #define vkGetQueryPoolResults glad_vkGetQueryPoolResults +GLAD_API_CALL PFN_vkGetQueueCheckpointData2NV glad_vkGetQueueCheckpointData2NV; +#define vkGetQueueCheckpointData2NV glad_vkGetQueueCheckpointData2NV GLAD_API_CALL PFN_vkGetQueueCheckpointDataNV glad_vkGetQueueCheckpointDataNV; #define vkGetQueueCheckpointDataNV glad_vkGetQueueCheckpointDataNV #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) GLAD_API_CALL PFN_vkGetRandROutputDisplayEXT glad_vkGetRandROutputDisplayEXT; #define vkGetRandROutputDisplayEXT glad_vkGetRandROutputDisplayEXT + #endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR glad_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR; #define vkGetRayTracingCaptureReplayShaderGroupHandlesKHR glad_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkGetRayTracingShaderGroupHandlesKHR glad_vkGetRayTracingShaderGroupHandlesKHR; #define vkGetRayTracingShaderGroupHandlesKHR glad_vkGetRayTracingShaderGroupHandlesKHR -#endif GLAD_API_CALL PFN_vkGetRayTracingShaderGroupHandlesNV glad_vkGetRayTracingShaderGroupHandlesNV; #define vkGetRayTracingShaderGroupHandlesNV glad_vkGetRayTracingShaderGroupHandlesNV +GLAD_API_CALL PFN_vkGetRayTracingShaderGroupStackSizeKHR glad_vkGetRayTracingShaderGroupStackSizeKHR; +#define vkGetRayTracingShaderGroupStackSizeKHR glad_vkGetRayTracingShaderGroupStackSizeKHR GLAD_API_CALL PFN_vkGetRefreshCycleDurationGOOGLE glad_vkGetRefreshCycleDurationGOOGLE; #define vkGetRefreshCycleDurationGOOGLE glad_vkGetRefreshCycleDurationGOOGLE GLAD_API_CALL PFN_vkGetRenderAreaGranularity glad_vkGetRenderAreaGranularity; #define vkGetRenderAreaGranularity glad_vkGetRenderAreaGranularity +GLAD_API_CALL PFN_vkGetRenderingAreaGranularity glad_vkGetRenderingAreaGranularity; +#define vkGetRenderingAreaGranularity glad_vkGetRenderingAreaGranularity +GLAD_API_CALL PFN_vkGetRenderingAreaGranularityKHR glad_vkGetRenderingAreaGranularityKHR; +#define vkGetRenderingAreaGranularityKHR glad_vkGetRenderingAreaGranularityKHR +GLAD_API_CALL PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT glad_vkGetSamplerOpaqueCaptureDescriptorDataEXT; +#define vkGetSamplerOpaqueCaptureDescriptorDataEXT glad_vkGetSamplerOpaqueCaptureDescriptorDataEXT +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +GLAD_API_CALL PFN_vkGetScreenBufferPropertiesQNX glad_vkGetScreenBufferPropertiesQNX; +#define vkGetScreenBufferPropertiesQNX glad_vkGetScreenBufferPropertiesQNX + +#endif GLAD_API_CALL PFN_vkGetSemaphoreCounterValue glad_vkGetSemaphoreCounterValue; #define vkGetSemaphoreCounterValue glad_vkGetSemaphoreCounterValue GLAD_API_CALL PFN_vkGetSemaphoreCounterValueKHR glad_vkGetSemaphoreCounterValueKHR; @@ -10761,9 +19188,21 @@ GLAD_API_CALL PFN_vkGetSemaphoreFdKHR glad_vkGetSemaphoreFdKHR; #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetSemaphoreWin32HandleKHR glad_vkGetSemaphoreWin32HandleKHR; #define vkGetSemaphoreWin32HandleKHR glad_vkGetSemaphoreWin32HandleKHR + #endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkGetSemaphoreZirconHandleFUCHSIA glad_vkGetSemaphoreZirconHandleFUCHSIA; +#define vkGetSemaphoreZirconHandleFUCHSIA glad_vkGetSemaphoreZirconHandleFUCHSIA + +#endif +GLAD_API_CALL PFN_vkGetShaderBinaryDataEXT glad_vkGetShaderBinaryDataEXT; +#define vkGetShaderBinaryDataEXT glad_vkGetShaderBinaryDataEXT GLAD_API_CALL PFN_vkGetShaderInfoAMD glad_vkGetShaderInfoAMD; #define vkGetShaderInfoAMD glad_vkGetShaderInfoAMD +GLAD_API_CALL PFN_vkGetShaderModuleCreateInfoIdentifierEXT glad_vkGetShaderModuleCreateInfoIdentifierEXT; +#define vkGetShaderModuleCreateInfoIdentifierEXT glad_vkGetShaderModuleCreateInfoIdentifierEXT +GLAD_API_CALL PFN_vkGetShaderModuleIdentifierEXT glad_vkGetShaderModuleIdentifierEXT; +#define vkGetShaderModuleIdentifierEXT glad_vkGetShaderModuleIdentifierEXT GLAD_API_CALL PFN_vkGetSwapchainCounterEXT glad_vkGetSwapchainCounterEXT; #define vkGetSwapchainCounterEXT glad_vkGetSwapchainCounterEXT GLAD_API_CALL PFN_vkGetSwapchainImagesKHR glad_vkGetSwapchainImagesKHR; @@ -10772,24 +19211,42 @@ GLAD_API_CALL PFN_vkGetSwapchainStatusKHR glad_vkGetSwapchainStatusKHR; #define vkGetSwapchainStatusKHR glad_vkGetSwapchainStatusKHR GLAD_API_CALL PFN_vkGetValidationCacheDataEXT glad_vkGetValidationCacheDataEXT; #define vkGetValidationCacheDataEXT glad_vkGetValidationCacheDataEXT +#if defined(VK_USE_PLATFORM_WIN32_KHR) +GLAD_API_CALL PFN_vkGetWinrtDisplayNV glad_vkGetWinrtDisplayNV; +#define vkGetWinrtDisplayNV glad_vkGetWinrtDisplayNV + +#endif GLAD_API_CALL PFN_vkImportFenceFdKHR glad_vkImportFenceFdKHR; #define vkImportFenceFdKHR glad_vkImportFenceFdKHR #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkImportFenceWin32HandleKHR glad_vkImportFenceWin32HandleKHR; #define vkImportFenceWin32HandleKHR glad_vkImportFenceWin32HandleKHR + #endif GLAD_API_CALL PFN_vkImportSemaphoreFdKHR glad_vkImportSemaphoreFdKHR; #define vkImportSemaphoreFdKHR glad_vkImportSemaphoreFdKHR #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkImportSemaphoreWin32HandleKHR glad_vkImportSemaphoreWin32HandleKHR; #define vkImportSemaphoreWin32HandleKHR glad_vkImportSemaphoreWin32HandleKHR + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkImportSemaphoreZirconHandleFUCHSIA glad_vkImportSemaphoreZirconHandleFUCHSIA; +#define vkImportSemaphoreZirconHandleFUCHSIA glad_vkImportSemaphoreZirconHandleFUCHSIA + #endif GLAD_API_CALL PFN_vkInitializePerformanceApiINTEL glad_vkInitializePerformanceApiINTEL; #define vkInitializePerformanceApiINTEL glad_vkInitializePerformanceApiINTEL GLAD_API_CALL PFN_vkInvalidateMappedMemoryRanges glad_vkInvalidateMappedMemoryRanges; #define vkInvalidateMappedMemoryRanges glad_vkInvalidateMappedMemoryRanges +GLAD_API_CALL PFN_vkLatencySleepNV glad_vkLatencySleepNV; +#define vkLatencySleepNV glad_vkLatencySleepNV GLAD_API_CALL PFN_vkMapMemory glad_vkMapMemory; #define vkMapMemory glad_vkMapMemory +GLAD_API_CALL PFN_vkMapMemory2 glad_vkMapMemory2; +#define vkMapMemory2 glad_vkMapMemory2 +GLAD_API_CALL PFN_vkMapMemory2KHR glad_vkMapMemory2KHR; +#define vkMapMemory2KHR glad_vkMapMemory2KHR GLAD_API_CALL PFN_vkMergePipelineCaches glad_vkMergePipelineCaches; #define vkMergePipelineCaches glad_vkMergePipelineCaches GLAD_API_CALL PFN_vkMergeValidationCachesEXT glad_vkMergeValidationCachesEXT; @@ -10802,28 +19259,39 @@ GLAD_API_CALL PFN_vkQueueEndDebugUtilsLabelEXT glad_vkQueueEndDebugUtilsLabelEXT #define vkQueueEndDebugUtilsLabelEXT glad_vkQueueEndDebugUtilsLabelEXT GLAD_API_CALL PFN_vkQueueInsertDebugUtilsLabelEXT glad_vkQueueInsertDebugUtilsLabelEXT; #define vkQueueInsertDebugUtilsLabelEXT glad_vkQueueInsertDebugUtilsLabelEXT +GLAD_API_CALL PFN_vkQueueNotifyOutOfBandNV glad_vkQueueNotifyOutOfBandNV; +#define vkQueueNotifyOutOfBandNV glad_vkQueueNotifyOutOfBandNV GLAD_API_CALL PFN_vkQueuePresentKHR glad_vkQueuePresentKHR; #define vkQueuePresentKHR glad_vkQueuePresentKHR GLAD_API_CALL PFN_vkQueueSetPerformanceConfigurationINTEL glad_vkQueueSetPerformanceConfigurationINTEL; #define vkQueueSetPerformanceConfigurationINTEL glad_vkQueueSetPerformanceConfigurationINTEL GLAD_API_CALL PFN_vkQueueSubmit glad_vkQueueSubmit; #define vkQueueSubmit glad_vkQueueSubmit +GLAD_API_CALL PFN_vkQueueSubmit2 glad_vkQueueSubmit2; +#define vkQueueSubmit2 glad_vkQueueSubmit2 +GLAD_API_CALL PFN_vkQueueSubmit2KHR glad_vkQueueSubmit2KHR; +#define vkQueueSubmit2KHR glad_vkQueueSubmit2KHR GLAD_API_CALL PFN_vkQueueWaitIdle glad_vkQueueWaitIdle; #define vkQueueWaitIdle glad_vkQueueWaitIdle GLAD_API_CALL PFN_vkRegisterDeviceEventEXT glad_vkRegisterDeviceEventEXT; #define vkRegisterDeviceEventEXT glad_vkRegisterDeviceEventEXT GLAD_API_CALL PFN_vkRegisterDisplayEventEXT glad_vkRegisterDisplayEventEXT; #define vkRegisterDisplayEventEXT glad_vkRegisterDisplayEventEXT +GLAD_API_CALL PFN_vkReleaseCapturedPipelineDataKHR glad_vkReleaseCapturedPipelineDataKHR; +#define vkReleaseCapturedPipelineDataKHR glad_vkReleaseCapturedPipelineDataKHR GLAD_API_CALL PFN_vkReleaseDisplayEXT glad_vkReleaseDisplayEXT; #define vkReleaseDisplayEXT glad_vkReleaseDisplayEXT #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkReleaseFullScreenExclusiveModeEXT glad_vkReleaseFullScreenExclusiveModeEXT; #define vkReleaseFullScreenExclusiveModeEXT glad_vkReleaseFullScreenExclusiveModeEXT + #endif GLAD_API_CALL PFN_vkReleasePerformanceConfigurationINTEL glad_vkReleasePerformanceConfigurationINTEL; #define vkReleasePerformanceConfigurationINTEL glad_vkReleasePerformanceConfigurationINTEL GLAD_API_CALL PFN_vkReleaseProfilingLockKHR glad_vkReleaseProfilingLockKHR; #define vkReleaseProfilingLockKHR glad_vkReleaseProfilingLockKHR +GLAD_API_CALL PFN_vkReleaseSwapchainImagesEXT glad_vkReleaseSwapchainImagesEXT; +#define vkReleaseSwapchainImagesEXT glad_vkReleaseSwapchainImagesEXT GLAD_API_CALL PFN_vkResetCommandBuffer glad_vkResetCommandBuffer; #define vkResetCommandBuffer glad_vkResetCommandBuffer GLAD_API_CALL PFN_vkResetCommandPool glad_vkResetCommandPool; @@ -10838,16 +19306,34 @@ GLAD_API_CALL PFN_vkResetQueryPool glad_vkResetQueryPool; #define vkResetQueryPool glad_vkResetQueryPool GLAD_API_CALL PFN_vkResetQueryPoolEXT glad_vkResetQueryPoolEXT; #define vkResetQueryPoolEXT glad_vkResetQueryPoolEXT +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA glad_vkSetBufferCollectionBufferConstraintsFUCHSIA; +#define vkSetBufferCollectionBufferConstraintsFUCHSIA glad_vkSetBufferCollectionBufferConstraintsFUCHSIA + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkSetBufferCollectionImageConstraintsFUCHSIA glad_vkSetBufferCollectionImageConstraintsFUCHSIA; +#define vkSetBufferCollectionImageConstraintsFUCHSIA glad_vkSetBufferCollectionImageConstraintsFUCHSIA + +#endif GLAD_API_CALL PFN_vkSetDebugUtilsObjectNameEXT glad_vkSetDebugUtilsObjectNameEXT; #define vkSetDebugUtilsObjectNameEXT glad_vkSetDebugUtilsObjectNameEXT GLAD_API_CALL PFN_vkSetDebugUtilsObjectTagEXT glad_vkSetDebugUtilsObjectTagEXT; #define vkSetDebugUtilsObjectTagEXT glad_vkSetDebugUtilsObjectTagEXT +GLAD_API_CALL PFN_vkSetDeviceMemoryPriorityEXT glad_vkSetDeviceMemoryPriorityEXT; +#define vkSetDeviceMemoryPriorityEXT glad_vkSetDeviceMemoryPriorityEXT GLAD_API_CALL PFN_vkSetEvent glad_vkSetEvent; #define vkSetEvent glad_vkSetEvent GLAD_API_CALL PFN_vkSetHdrMetadataEXT glad_vkSetHdrMetadataEXT; #define vkSetHdrMetadataEXT glad_vkSetHdrMetadataEXT +GLAD_API_CALL PFN_vkSetLatencyMarkerNV glad_vkSetLatencyMarkerNV; +#define vkSetLatencyMarkerNV glad_vkSetLatencyMarkerNV +GLAD_API_CALL PFN_vkSetLatencySleepModeNV glad_vkSetLatencySleepModeNV; +#define vkSetLatencySleepModeNV glad_vkSetLatencySleepModeNV GLAD_API_CALL PFN_vkSetLocalDimmingAMD glad_vkSetLocalDimmingAMD; #define vkSetLocalDimmingAMD glad_vkSetLocalDimmingAMD +GLAD_API_CALL PFN_vkSetPrivateData glad_vkSetPrivateData; +#define vkSetPrivateData glad_vkSetPrivateData GLAD_API_CALL PFN_vkSetPrivateDataEXT glad_vkSetPrivateDataEXT; #define vkSetPrivateDataEXT glad_vkSetPrivateDataEXT GLAD_API_CALL PFN_vkSignalSemaphore glad_vkSignalSemaphore; @@ -10856,6 +19342,10 @@ GLAD_API_CALL PFN_vkSignalSemaphoreKHR glad_vkSignalSemaphoreKHR; #define vkSignalSemaphoreKHR glad_vkSignalSemaphoreKHR GLAD_API_CALL PFN_vkSubmitDebugUtilsMessageEXT glad_vkSubmitDebugUtilsMessageEXT; #define vkSubmitDebugUtilsMessageEXT glad_vkSubmitDebugUtilsMessageEXT +GLAD_API_CALL PFN_vkTransitionImageLayout glad_vkTransitionImageLayout; +#define vkTransitionImageLayout glad_vkTransitionImageLayout +GLAD_API_CALL PFN_vkTransitionImageLayoutEXT glad_vkTransitionImageLayoutEXT; +#define vkTransitionImageLayoutEXT glad_vkTransitionImageLayoutEXT GLAD_API_CALL PFN_vkTrimCommandPool glad_vkTrimCommandPool; #define vkTrimCommandPool glad_vkTrimCommandPool GLAD_API_CALL PFN_vkTrimCommandPoolKHR glad_vkTrimCommandPoolKHR; @@ -10864,22 +19354,32 @@ GLAD_API_CALL PFN_vkUninitializePerformanceApiINTEL glad_vkUninitializePerforman #define vkUninitializePerformanceApiINTEL glad_vkUninitializePerformanceApiINTEL GLAD_API_CALL PFN_vkUnmapMemory glad_vkUnmapMemory; #define vkUnmapMemory glad_vkUnmapMemory +GLAD_API_CALL PFN_vkUnmapMemory2 glad_vkUnmapMemory2; +#define vkUnmapMemory2 glad_vkUnmapMemory2 +GLAD_API_CALL PFN_vkUnmapMemory2KHR glad_vkUnmapMemory2KHR; +#define vkUnmapMemory2KHR glad_vkUnmapMemory2KHR GLAD_API_CALL PFN_vkUpdateDescriptorSetWithTemplate glad_vkUpdateDescriptorSetWithTemplate; #define vkUpdateDescriptorSetWithTemplate glad_vkUpdateDescriptorSetWithTemplate GLAD_API_CALL PFN_vkUpdateDescriptorSetWithTemplateKHR glad_vkUpdateDescriptorSetWithTemplateKHR; #define vkUpdateDescriptorSetWithTemplateKHR glad_vkUpdateDescriptorSetWithTemplateKHR GLAD_API_CALL PFN_vkUpdateDescriptorSets glad_vkUpdateDescriptorSets; #define vkUpdateDescriptorSets glad_vkUpdateDescriptorSets +GLAD_API_CALL PFN_vkUpdateIndirectExecutionSetPipelineEXT glad_vkUpdateIndirectExecutionSetPipelineEXT; +#define vkUpdateIndirectExecutionSetPipelineEXT glad_vkUpdateIndirectExecutionSetPipelineEXT +GLAD_API_CALL PFN_vkUpdateIndirectExecutionSetShaderEXT glad_vkUpdateIndirectExecutionSetShaderEXT; +#define vkUpdateIndirectExecutionSetShaderEXT glad_vkUpdateIndirectExecutionSetShaderEXT GLAD_API_CALL PFN_vkWaitForFences glad_vkWaitForFences; #define vkWaitForFences glad_vkWaitForFences +GLAD_API_CALL PFN_vkWaitForPresentKHR glad_vkWaitForPresentKHR; +#define vkWaitForPresentKHR glad_vkWaitForPresentKHR GLAD_API_CALL PFN_vkWaitSemaphores glad_vkWaitSemaphores; #define vkWaitSemaphores glad_vkWaitSemaphores GLAD_API_CALL PFN_vkWaitSemaphoresKHR glad_vkWaitSemaphoresKHR; #define vkWaitSemaphoresKHR glad_vkWaitSemaphoresKHR -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkWriteAccelerationStructuresPropertiesKHR glad_vkWriteAccelerationStructuresPropertiesKHR; #define vkWriteAccelerationStructuresPropertiesKHR glad_vkWriteAccelerationStructuresPropertiesKHR -#endif +GLAD_API_CALL PFN_vkWriteMicromapsPropertiesEXT glad_vkWriteMicromapsPropertiesEXT; +#define vkWriteMicromapsPropertiesEXT glad_vkWriteMicromapsPropertiesEXT diff --git a/lib/graphics_engine/include/mvk_config.h b/lib/graphics_engine/include/mvk_config.h deleted file mode 100644 index 69c916d1679..00000000000 --- a/lib/graphics_engine/include/mvk_config.h +++ /dev/null @@ -1,1059 +0,0 @@ -/* - * mvk_config.h - * - * Copyright (c) 2015-2023 The Brenwill Workshop Ltd. (http://www.brenwill.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - - -#ifndef __mvk_config_h_ -#define __mvk_config_h_ 1 - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - - -/** This header contains the public configuration API for MoltenVK. */ - - -/** - * The version number of MoltenVK is a single integer value, derived from the Major, Minor, - * and Patch version values, where each of the Major, Minor, and Patch components is allocated - * two decimal digits, in the format MjMnPt. This creates a version number that is both human - * readable and allows efficient computational comparisons to a single integer number. - * - * The following examples illustrate how the MoltenVK version number is built from its components: - * - 002000 (version 0.20.0) - * - 010000 (version 1.0.0) - * - 030104 (version 3.1.4) - * - 401215 (version 4.12.15) - */ -#define MVK_VERSION_MAJOR 1 -#define MVK_VERSION_MINOR 2 -#define MVK_VERSION_PATCH 4 - -#define MVK_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch)) -#define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH) - - -#define MVK_CONFIGURATION_API_VERSION 37 - -/** Identifies the level of logging MoltenVK should be limited to outputting. */ -typedef enum MVKConfigLogLevel { - MVK_CONFIG_LOG_LEVEL_NONE = 0, /**< No logging. */ - MVK_CONFIG_LOG_LEVEL_ERROR = 1, /**< Log errors only. */ - MVK_CONFIG_LOG_LEVEL_WARNING = 2, /**< Log errors and warning messages. */ - MVK_CONFIG_LOG_LEVEL_INFO = 3, /**< Log errors, warnings and informational messages. */ - MVK_CONFIG_LOG_LEVEL_DEBUG = 4, /**< Log errors, warnings, infos and debug messages. */ - MVK_CONFIG_LOG_LEVEL_MAX_ENUM = 0x7FFFFFFF -} MVKConfigLogLevel; - -/** Identifies the level of Vulkan call trace logging MoltenVK should perform. */ -typedef enum MVKConfigTraceVulkanCalls { - MVK_CONFIG_TRACE_VULKAN_CALLS_NONE = 0, /**< No Vulkan call logging. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER = 1, /**< Log the name of each Vulkan call when the call is entered. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_THREAD_ID = 2, /**< Log the name and thread ID of each Vulkan call when the call is entered. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT = 3, /**< Log the name of each Vulkan call when the call is entered and exited. This effectively brackets any other logging activity within the scope of the Vulkan call. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT_THREAD_ID = 4, /**< Log the name and thread ID of each Vulkan call when the call is entered and name when exited. This effectively brackets any other logging activity within the scope of the Vulkan call. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_DURATION = 5, /**< Same as MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT, plus logs the time spent inside the Vulkan function. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_DURATION_THREAD_ID = 6, /**< Same as MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT_THREAD_ID, plus logs the time spent inside the Vulkan function. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_MAX_ENUM = 0x7FFFFFFF -} MVKConfigTraceVulkanCalls; - -/** Identifies the scope for Metal to run an automatic GPU capture for diagnostic debugging purposes. */ -typedef enum MVKConfigAutoGPUCaptureScope { - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_NONE = 0, /**< No automatic GPU capture. */ - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE = 1, /**< Automatically capture all GPU activity during the lifetime of a VkDevice. */ - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME = 2, /**< Automatically capture all GPU activity during the rendering and presentation of the first frame. */ - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_MAX_ENUM = 0x7FFFFFFF -} MVKConfigAutoGPUCaptureScope; - -/** Identifies extensions to advertise as part of MoltenVK configuration. */ -typedef enum MVKConfigAdvertiseExtensionBits { - MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL = 0x00000001, /**< All supported extensions. */ - MVK_CONFIG_ADVERTISE_EXTENSIONS_WSI = 0x00000002, /**< WSI extensions supported on the platform. */ - MVK_CONFIG_ADVERTISE_EXTENSIONS_PORTABILITY = 0x00000004, /**< Vulkan Portability Subset extensions. */ - MVK_CONFIG_ADVERTISE_EXTENSIONS_MAX_ENUM = 0x7FFFFFFF -} MVKConfigAdvertiseExtensionBits; -typedef VkFlags MVKConfigAdvertiseExtensions; - -/** Identifies the use of Metal Argument Buffers. */ -typedef enum MVKUseMetalArgumentBuffers { - MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER = 0, /**< Don't use Metal Argument Buffers. */ - MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_ALWAYS = 1, /**< Use Metal Argument Buffers for all pipelines. */ - MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_DESCRIPTOR_INDEXING = 2, /**< Use Metal Argument Buffers only if VK_EXT_descriptor_indexing extension is enabled. */ - MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_MAX_ENUM = 0x7FFFFFFF -} MVKUseMetalArgumentBuffers; - -/** Identifies the Metal functionality used to support Vulkan semaphore functionality (VkSemaphore). */ -typedef enum MVKVkSemaphoreSupportStyle { - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE = 0, /**< Limit Vulkan to a single queue, with no explicit semaphore synchronization, and use Metal's implicit guarantees that all operations submitted to a queue will give the same result as if they had been run in submission order. */ - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE = 1, /**< Use Metal events (MTLEvent) when available on the platform, and where safe. This will revert to same as MVK_CONFIG_VK_SEMAPHORE_USE_SINGLE_QUEUE on some NVIDIA GPUs and Rosetta2, due to potential challenges with MTLEvents on those platforms, or in older environments where MTLEvents are not supported. */ - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS = 2, /**< Always use Metal events (MTLEvent) when available on the platform. This will revert to same as MVK_CONFIG_VK_SEMAPHORE_USE_SINGLE_QUEUE in older environments where MTLEvents are not supported. */ - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK = 3, /**< Use CPU callbacks upon GPU submission completion. This is the slowest technique, but allows multiple queues, compared to MVK_CONFIG_VK_SEMAPHORE_USE_SINGLE_QUEUE. */ - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_MAX_ENUM = 0x7FFFFFFF -} MVKVkSemaphoreSupportStyle; - -/** Identifies the style of Metal command buffer pre-filling to be used. */ -typedef enum MVKPrefillMetalCommandBuffersStyle { - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL = 0, /**< During Vulkan command buffer filling, do not prefill a Metal command buffer for each Vulkan command buffer. A single Metal command buffer is created and encoded for all the Vulkan command buffers included when vkQueueSubmit() is called. MoltenVK automatically creates and drains a single Metal object autorelease pool when vkQueueSubmit() is called. This is the fastest option, but potentially has the largest memory footprint. */ - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_DEFERRED_ENCODING = 1, /**< During Vulkan command buffer filling, encode to the Metal command buffer when vkEndCommandBuffer() is called. MoltenVK automatically creates and drains a single Metal object autorelease pool when vkEndCommandBuffer() is called. This option has the fastest performance, and the largest memory footprint, of the prefilling options using autorelease pools. */ - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_IMMEDIATE_ENCODING = 2, /**< During Vulkan command buffer filling, immediately encode to the Metal command buffer, as each command is submitted to the Vulkan command buffer, and do not retain any command content in the Vulkan command buffer. MoltenVK automatically creates and drains a Metal object autorelease pool for each and every command added to the Vulkan command buffer. This option has the smallest memory footprint, and the slowest performance, of the prefilling options using autorelease pools. */ - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_IMMEDIATE_ENCODING_NO_AUTORELEASE = 3, /**< During Vulkan command buffer filling, immediately encode to the Metal command buffer, as each command is submitted to the Vulkan command buffer, do not retain any command content in the Vulkan command buffer, and assume the app will ensure that each thread that fills commands into a Vulkan command buffer has a Metal autorelease pool. MoltenVK will not create and drain any autorelease pools during encoding. This is the fastest prefilling option, and generally has a small memory footprint, depending on when the app-provided autorelease pool drains. */ - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_MAX_ENUM = 0x7FFFFFFF -} MVKPrefillMetalCommandBuffersStyle; - -/** Identifies when Metal shaders will be compiled with the fast math option. */ -typedef enum MVKConfigFastMath { - MVK_CONFIG_FAST_MATH_NEVER = 0, /**< Metal shaders will never be compiled with the fast math option. */ - MVK_CONFIG_FAST_MATH_ALWAYS = 1, /**< Metal shaders will always be compiled with the fast math option. */ - MVK_CONFIG_FAST_MATH_ON_DEMAND = 2, /**< Metal shaders will be compiled with the fast math option, unless the shader includes execution modes that require it to be compiled without fast math. */ - MVK_CONFIG_FAST_MATH_MAX_ENUM = 0x7FFFFFFF -} MVKConfigFastMath; - -/** Identifies available system data compression algorithms. */ -typedef enum MVKConfigCompressionAlgorithm { - MVK_CONFIG_COMPRESSION_ALGORITHM_NONE = 0, /**< No compression. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_LZFSE = 1, /**< Apple proprietary. Good balance of high performance and small compression size, particularly for larger data content. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_ZLIB = 2, /**< Open cross-platform ZLib format. For smaller data content, has better performance and smaller size than LZFSE. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_LZ4 = 3, /**< Fastest performance. Largest compression size. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_LZMA = 4, /**< Slowest performance. Smallest compression size, particular with larger content. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_MAX_ENUM = 0x7FFFFFFF, -} MVKConfigCompressionAlgorithm; - -/** Identifies the style of activity performance logging to use. */ -typedef enum MVKConfigActivityPerformanceLoggingStyle { - MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_FRAME_COUNT = 0, /**< Repeatedly log performance after a configured number of frames. */ - MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_IMMEDIATE = 1, /**< Log immediately after each performance measurement. */ - MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_DEVICE_LIFETIME = 2, /**< Log at the end of the VkDevice lifetime. This is useful for one-shot apps such as testing frameworks. */ - MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_MAX_ENUM = 0x7FFFFFFF, -} MVKConfigActivityPerformanceLoggingStyle; - -/** - * MoltenVK configuration settings. - * - * To be active, some configuration settings must be set before a VkDevice is created. - * See the description of the individual configuration structure members for more information. - * - * There are three mechanisms for setting the values of the MoltenVK configuration parameters: - * - Runtime API via the vkGetMoltenVKConfigurationMVK()/vkSetMoltenVKConfigurationMVK() functions. - * - Application runtime environment variables. - * - Build settings at MoltenVK build time. - * - * To change the MoltenVK configuration settings at runtime using a programmatic API, - * use the vkGetMoltenVKConfigurationMVK() and vkSetMoltenVKConfigurationMVK() functions - * to retrieve, modify, and set a copy of the MVKConfiguration structure. To be active, - * some configuration settings must be set before a VkInstance or VkDevice is created. - * See the description of each member for more information. - * - * The initial value of each of the configuration settings can established at runtime - * by a corresponding environment variable, or if the environment variable is not set, - * by a corresponding build setting at the time MoltenVK is compiled. The environment - * variable and build setting for each configuration parameter share the same name. - * - * For example, the initial value of the shaderConversionFlipVertexY configuration setting - * is set by the MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y at runtime, or by the - * MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y build setting when MoltenVK is compiled. - * - * This structure may be extended as new features are added to MoltenVK. If you are linking to - * an implementation of MoltenVK that was compiled from a different MVK_CONFIGURATION_API_VERSION - * than your app was, the size of this structure in your app may be larger or smaller than the - * struct in MoltenVK. See the description of the vkGetMoltenVKConfigurationMVK() and - * vkSetMoltenVKConfigurationMVK() functions for information about how to handle this. - * - * TO SUPPORT DYNAMIC LINKING TO THIS STRUCTURE AS DESCRIBED ABOVE, THIS STRUCTURE SHOULD NOT - * BE CHANGED EXCEPT TO ADD ADDITIONAL MEMBERS ON THE END. EXISTING MEMBERS, AND THEIR ORDER, - * SHOULD NOT BE CHANGED. - */ -typedef struct { - - /** - * If enabled, debugging capabilities will be enabled, including logging - * shader code during runtime shader conversion. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_DEBUG - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter is false if MoltenVK was - * built in Release mode, and true if MoltenVK was built in Debug mode. - */ - VkBool32 debugMode; - - /** - * If enabled, MSL vertex shader code created during runtime shader conversion will - * flip the Y-axis of each vertex, as the Vulkan Y-axis is the inverse of OpenGL. - * - * An alternate way to reverse the Y-axis is to employ a negative Y-axis value on - * the viewport, in which case this parameter can be disabled. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * Specifically, this parameter can be enabled when compiling some pipelines, - * and disabled when compiling others. Existing pipelines are not automatically - * re-compiled when this parameter is changed. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true. - */ - VkBool32 shaderConversionFlipVertexY; - - /** - * If enabled, queue command submissions (vkQueueSubmit() & vkQueuePresentKHR()) will be - * processed on the thread that called the submission function. If disabled, processing - * will be dispatched to a GCD dispatch_queue whose priority is determined by - * VkDeviceQueueCreateInfo::pQueuePriorities during vkCreateDevice(). - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true for macOS 10.14 - * and above or iOS 12 and above, and false otherwise. The reason for this distinction - * is that this feature should be disabled when emulation is required to support VkEvents - * because native support for events (MTLEvent) is not available. - */ - VkBool32 synchronousQueueSubmits; - - /** - * If set to MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL, a single Metal - * command buffer will be created and filled when the Vulkan command buffers are submitted - * to the Vulkan queue. This allows a single Metal command buffer to be used for all of the - * Vulkan command buffers in a queue submission. The Metal command buffer is filled on the - * thread that processes the command queue submission. - * - * If set to any value other than MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL, - * where possible, a Metal command buffer will be created and filled when each Vulkan - * command buffer is filled. For applications that parallelize the filling of Vulkan - * commmand buffers across multiple threads, this allows the Metal command buffers to also - * be filled on the same parallel thread. Because each command buffer is filled separately, - * this requires that each Vulkan command buffer have a dedicated Metal command buffer. - * - * See the definition of the MVKPrefillMetalCommandBuffersStyle enumeration above for - * descriptions of the various values that can be used for this setting. The differences - * are primarily distinguished by how memory recovery is handled for autoreleased Metal - * objects that are created under the covers as the commands added to the Vulkan command - * buffer are encoded into the corresponding Metal command buffer. You can decide whether - * your app will recover all autoreleased Metal objects, or how agressively MoltenVK should - * recover autoreleased Metal objects, based on your approach to command buffer filling. - * - * Depending on the nature of your application, you may find performance is improved by filling - * the Metal command buffers on parallel threads, or you may find that performance is improved by - * consolidating all Vulkan command buffers onto a single Metal command buffer during queue submission. - * - * When enabling this feature, be aware that one Metal command buffer is required for each Vulkan - * command buffer. Depending on the number of command buffers that you use, you may also need to - * change the value of the maxActiveMetalCommandBuffersPerQueue setting. - * - * If this feature is enabled, be aware that if you have recorded commands to a Vulkan command buffer, - * and then choose to reset that command buffer instead of submitting it, the corresponding prefilled - * Metal command buffer will still be submitted. This is because Metal command buffers do not support - * the concept of being reset after being filled. Depending on when and how often you do this, - * it may cause unexpected visual artifacts and unnecessary GPU load. - * - * Prefilling of a Metal command buffer will not occur during the filling of secondary command - * buffers (VK_COMMAND_BUFFER_LEVEL_SECONDARY), or for primary command buffers that are intended - * to be submitted to multiple queues concurrently (VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT). - * - * This feature is incompatible with updating descriptors after binding. If any of the - * *UpdateAfterBind feature flags of VkPhysicalDeviceDescriptorIndexingFeatures or - * VkPhysicalDeviceInlineUniformBlockFeatures have been enabled, the value of this - * setting will be ignored and treated as if it is false. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * Specifically, this parameter can be enabled when filling some command buffers, - * and disabled when later filling others. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to - * MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL. - */ - MVKPrefillMetalCommandBuffersStyle prefillMetalCommandBuffers; - - /** - * The maximum number of Metal command buffers that can be concurrently active per Vulkan queue. - * The number of active Metal command buffers required depends on the prefillMetalCommandBuffers - * setting. If prefillMetalCommandBuffers is enabled, one Metal command buffer is required per - * Vulkan command buffer. If prefillMetalCommandBuffers is disabled, one Metal command buffer - * is required per command buffer queue submission, which may be significantly less than the - * number of Vulkan command buffers. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to 64. - */ - uint32_t maxActiveMetalCommandBuffersPerQueue; - - /** - * Depending on the GPU, Metal allows 8192 or 32768 occlusion queries per MTLBuffer. - * If enabled, MoltenVK allocates a MTLBuffer for each query pool, allowing each query - * pool to support that permitted number of queries. This may slow performance or cause - * unexpected behaviour if the query pool is not established prior to a Metal renderpass, - * or if the query pool is changed within a renderpass. If disabled, one MTLBuffer will - * be shared by all query pools, which improves performance, but limits the total device - * queries to the permitted number. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * Specifically, this parameter can be enabled when creating some query pools, - * and disabled when creating others. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true. - */ - VkBool32 supportLargeQueryPools; - - /** Obsolete, ignored, and deprecated. All surface presentations are performed with a command buffer. */ - VkBool32 presentWithCommandBuffer; - - /** - * If enabled, swapchain images will use simple Nearest sampling when minifying or magnifying - * the swapchain image to fit a physical display surface. If disabled, swapchain images will - * use Linear sampling when magnifying the swapchain image to fit a physical display surface. - * Enabling this setting avoids smearing effects when swapchain images are simple interger - * multiples of display pixels (eg- macOS Retina, and typical of graphics apps and games), - * but may cause aliasing effects when using non-integer display scaling. - * - * The value of this parameter must be changed before creating a VkSwapchain, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SWAPCHAIN_MIN_MAG_FILTER_USE_NEAREST - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true. - */ - VkBool32 swapchainMinMagFilterUseNearest; -#define swapchainMagFilterUseNearest swapchainMinMagFilterUseNearest - - /** - * The maximum amount of time, in nanoseconds, to wait for a Metal library, function, or - * pipeline state object to be compiled and created by the Metal compiler. An internal error - * within the Metal compiler can stall the thread for up to 30 seconds. Setting this value - * limits that delay to a specified amount of time, allowing shader compilations to fail fast. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_METAL_COMPILE_TIMEOUT - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to infinite. - */ - uint64_t metalCompileTimeout; - - /** - * If enabled, performance statistics, as defined by the MVKPerformanceStatistics structure, - * are collected, and can be retrieved via the vkGetPerformanceStatisticsMVK() function. - * - * You can also use the activityPerformanceLoggingStyle and performanceLoggingFrameCount - * parameters to configure when to log the performance statistics collected by this parameter. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_PERFORMANCE_TRACKING - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to false. - */ - VkBool32 performanceTracking; - - /** - * If non-zero, performance statistics, frame-based statistics will be logged, on a - * repeating cycle, once per this many frames. The performanceTracking parameter must - * also be enabled. If this parameter is zero, or the performanceTracking parameter - * is disabled, no frame-based performance statistics will be logged. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to zero. - */ - uint32_t performanceLoggingFrameCount; - - /** - * If enabled, a MoltenVK logo watermark will be rendered on top of the scene. - * This can be enabled for publicity during demos. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_DISPLAY_WATERMARK - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to false. - */ - VkBool32 displayWatermark; - - /** - * Metal does not distinguish functionality between queues, which would normally mean only - * a single general-purpose queue family with multiple queues is needed. However, Vulkan - * associates command buffers with a queue family, whereas Metal associates command buffers - * with a specific Metal queue. In order to allow a Metal command buffer to be prefilled - * before is is formally submitted to a Vulkan queue, each Vulkan queue family can support - * only a single Metal queue. As a result, in order to provide parallel queue operations, - * MoltenVK provides multiple queue families, each with a single queue. - * - * If this parameter is disabled, all queue families will be advertised as having general-purpose - * graphics + compute + transfer functionality, which is how the actual Metal queues behave. - * - * If this parameter is enabled, one queue family will be advertised as having general-purpose - * graphics + compute + transfer functionality, and the remaining queue families will be advertised - * as having specialized graphics OR compute OR transfer functionality, to make it easier for some - * apps to select a queue family with the appropriate requirements. - * - * The value of this parameter must be changed before creating a VkDevice, and before - * querying a VkPhysicalDevice for queue family properties, for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to false. - */ - VkBool32 specializedQueueFamilies; - - /** - * If enabled, when the app creates a VkDevice from a VkPhysicalDevice (GPU) that is neither - * headless nor low-power, and is different than the GPU used by the windowing system, the - * windowing system will be forced to switch to use the GPU selected by the Vulkan app. - * When the Vulkan app is ended, the windowing system will automatically switch back to - * using the previous GPU, depending on the usage requirements of other running apps. - * - * If disabled, the Vulkan app will render using its selected GPU, and if the windowing - * system uses a different GPU, the windowing system compositor will automatically copy - * framebuffer content from the app GPU to the windowing system GPU. - * - * The value of this parmeter has no effect on systems with a single GPU, or when the - * Vulkan app creates a VkDevice from a low-power or headless VkPhysicalDevice (GPU). - * - * Switching the windowing system GPU to match the Vulkan app GPU maximizes app performance, - * because it avoids the windowing system compositor from having to copy framebuffer content - * between GPUs on each rendered frame. However, doing so forces the entire system to - * potentially switch to using a GPU that may consume more power while the app is running. - * - * Some Vulkan apps may want to render using a high-power GPU, but leave it up to the - * system window compositor to determine how best to blend content with the windowing - * system, and as a result, may want to disable this parameter. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SWITCH_SYSTEM_GPU - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true. - */ - VkBool32 switchSystemGPU; - - /** - * Older versions of Metal do not natively support per-texture swizzling. When running on - * such a system, and this parameter is enabled, arbitrary VkImageView component swizzles - * are supported, as defined in VkImageViewCreateInfo::components when creating a VkImageView. - * - * If disabled, and native Metal per-texture swizzling is not available on the platform, - * a very limited set of VkImageView component swizzles are supported via format substitutions. - * - * If Metal supports native per-texture swizzling, this parameter is ignored. - * - * When running on an older version of Metal that does not support native per-texture - * swizzling, if this parameter is enabled, both when a VkImageView is created, and - * when any pipeline that uses that VkImageView is compiled, VkImageView swizzling is - * automatically performed in the converted Metal shader code during all texture sampling - * and reading operations, regardless of whether a swizzle is required for the VkImageView - * associated with the Metal texture. This may result in reduced performance. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * Specifically, this parameter can be enabled when creating VkImageViews that need it, - * and compiling pipelines that use those VkImageViews, and can be disabled when creating - * VkImageViews that don't need it, and compiling pipelines that use those VkImageViews. - * - * Existing pipelines are not automatically re-compiled when this parameter is changed. - * - * An error is logged and returned during VkImageView creation if that VkImageView - * requires full image view swizzling and this feature is not enabled. An error is - * also logged when a pipeline that was not compiled with full image view swizzling - * is presented with a VkImageView that is expecting it. - * - * An error is also retuned and logged when a VkPhysicalDeviceImageFormatInfo2KHR is passed - * in a call to vkGetPhysicalDeviceImageFormatProperties2KHR() to query for an VkImageView - * format that will require full swizzling to be enabled, and this feature is not enabled. - * - * If this parameter is disabled, and native Metal per-texture swizzling is not available - * on the platform, the following limited set of VkImageView swizzles are supported by - * MoltenVK, via automatic format substitution: - * - * Texture format Swizzle - * -------------- ------- - * VK_FORMAT_R8_UNORM ZERO, ANY, ANY, RED - * VK_FORMAT_A8_UNORM ALPHA, ANY, ANY, ZERO - * VK_FORMAT_R8G8B8A8_UNORM BLUE, GREEN, RED, ALPHA - * VK_FORMAT_R8G8B8A8_SRGB BLUE, GREEN, RED, ALPHA - * VK_FORMAT_B8G8R8A8_UNORM BLUE, GREEN, RED, ALPHA - * VK_FORMAT_B8G8R8A8_SRGB BLUE, GREEN, RED, ALPHA - * VK_FORMAT_D32_SFLOAT_S8_UINT RED, ANY, ANY, ANY (stencil only) - * VK_FORMAT_D24_UNORM_S8_UINT RED, ANY, ANY, ANY (stencil only) - * - * The initial value or this parameter is set by the - * MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to false. - */ - VkBool32 fullImageViewSwizzle; - - /** - * The index of the queue family whose presentation submissions will - * be used as the default GPU Capture Scope during debugging in Xcode. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to zero (the first queue family). - */ - uint32_t defaultGPUCaptureScopeQueueFamilyIndex; - - /** - * The index of the queue, within the queue family identified by the - * defaultGPUCaptureScopeQueueFamilyIndex parameter, whose presentation submissions - * will be used as the default GPU Capture Scope during debugging in Xcode. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_INDEX - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to zero (the first queue). - */ - uint32_t defaultGPUCaptureScopeQueueIndex; - - /** - * Identifies when Metal shaders will be compiled with the Metal fastMathEnabled property - * enabled. For shaders compiled with the Metal fastMathEnabled property enabled, shader - * floating point math is significantly faster, but it may cause the Metal Compiler to - * optimize floating point operations in ways that may violate the IEEE 754 standard. - * - * Enabling Metal fast math can dramatically improve shader performance, and has little - * practical effect on the numerical accuracy of most shaders. As such, disabling fast - * math should be done carefully and deliberately. For most applications, always enabling - * fast math, by setting the value of this property to MVK_CONFIG_FAST_MATH_ALWAYS, - * is the preferred choice. - * - * Apps that have specific accuracy and handling needs for particular shaders, may elect to - * set the value of this property to MVK_CONFIG_FAST_MATH_ON_DEMAND, so that fast math will - * be disabled when compiling shaders that request capabilities such as SignedZeroInfNanPreserve. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will be applied to future Metal shader compilations. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_FAST_MATH_ENABLED - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to MVK_CONFIG_FAST_MATH_ALWAYS. - */ - MVKConfigFastMath fastMathEnabled; - - /** - * Controls the level of logging performned by MoltenVK. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_LOG_LEVEL - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, errors and informational messages are logged. - */ - MVKConfigLogLevel logLevel; - - /** - * Causes MoltenVK to log the name of each Vulkan call made by the application, - * along with the Mach thread ID, global system thread ID, and thread name. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_TRACE_VULKAN_CALLS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, no Vulkan call logging will occur. - */ - MVKConfigTraceVulkanCalls traceVulkanCalls; - - /** - * Force MoltenVK to use a low-power GPU, if one is availble on the device. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_FORCE_LOW_POWER_GPU - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is disabled by default, allowing both - * low-power and high-power GPU's to be used. - */ - VkBool32 forceLowPowerGPU; - - /** Deprecated. Vulkan sempphores using MTLFence are no longer supported. Use semaphoreSupportStyle instead. */ - VkBool32 semaphoreUseMTLFence; - - /** - * Determines the style used to implement Vulkan semaphore (VkSemaphore) functionality in Metal. - * See the documentation of the MVKVkSemaphoreSupportStyle for the options. - * - * In the special case of VK_SEMAPHORE_TYPE_TIMELINE semaphores, MoltenVK will always use - * MTLSharedEvent if it is available on the platform, regardless of the value of this parameter. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is set to - * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE by default, - * and MoltenVK will use MTLEvent, except on NVIDIA GPU and Rosetta2 environments, - * or where MTLEvents are not supported, where it will use a single queue with - * implicit synchronization (as if this parameter was set to - * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE). - * - * This parameter interacts with the deprecated legacy parameters semaphoreUseMTLEvent - * and semaphoreUseMTLFence. If semaphoreUseMTLEvent is enabled, this parameter will be - * set to MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE. - * If semaphoreUseMTLEvent is disabled, this parameter will be set to - * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE if semaphoreUseMTLFence is enabled, - * or MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK if semaphoreUseMTLFence is disabled. - * Structurally, this parameter replaces, and is aliased by, semaphoreUseMTLEvent. - */ - MVKVkSemaphoreSupportStyle semaphoreSupportStyle; -#define semaphoreUseMTLEvent semaphoreSupportStyle - - /** - * Controls whether Metal should run an automatic GPU capture without the user having to - * trigger it manually via the Xcode user interface, and controls the scope under which - * that GPU capture will occur. This is useful when trying to capture a one-shot GPU trace, - * such as when running a Vulkan CTS test case. For the automatic GPU capture to occur, the - * Xcode scheme under which the app is run must have the Metal GPU capture option enabled. - * This parameter should not be set to manually trigger a GPU capture via the Xcode user interface. - * - * When the value of this parameter is MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME, - * the queue for which the GPU activity is captured is identifed by the values of - * the defaultGPUCaptureScopeQueueFamilyIndex and defaultGPUCaptureScopeQueueIndex - * configuration parameters. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, no automatic GPU capture will occur. - */ - MVKConfigAutoGPUCaptureScope autoGPUCaptureScope; - - /** - * The path to a file where the automatic GPU capture should be saved, if autoGPUCaptureScope - * is enabled. In this case, the Xcode scheme need not have Metal GPU capture enabled, and in - * fact the app need not be run under Xcode's control at all. This is useful in case the app - * cannot be run under Xcode's control. A path starting with '~' can be used to place it in a - * user's home directory, as in the shell. This feature requires Metal 3.0 (macOS 10.15, iOS 13). - * - * If this parameter is NULL or an empty string, and autoGPUCaptureScope is enabled, automatic - * GPU capture will be handled by the Xcode user interface. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_AUTO_GPU_CAPTURE_OUTPUT_FILE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, automatic GPU capture will be handled by the Xcode user interface. - */ - const char* autoGPUCaptureOutputFilepath; - - /** - * Controls whether MoltenVK should use a Metal 2D texture with a height of 1 for a - * Vulkan 1D image, or use a native Metal 1D texture. Metal imposes significant restrictions - * on native 1D textures, including not being renderable, clearable, or permitting mipmaps. - * Using a Metal 2D texture allows Vulkan 1D textures to support this additional functionality. - * - * The value of this parameter should only be changed before creating the VkInstance. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_TEXTURE_1D_AS_2D - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is enabled by default, and MoltenVK will - * use a Metal 2D texture for each Vulkan 1D image. - */ - VkBool32 texture1DAs2D; - - /** - * Controls whether MoltenVK should preallocate memory in each VkDescriptorPool according - * to the values of the VkDescriptorPoolSize parameters. Doing so may improve descriptor set - * allocation performance and memory stability at a cost of preallocated application memory. - * If this setting is disabled, the descriptors required for a descriptor set will be individually - * dynamically allocated in application memory when the descriptor set itself is allocated. - * - * The value of this parameter may be changed at any time during application runtime, and the - * changed value will affect the behavior of VkDescriptorPools created after the value is changed. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_PREALLOCATE_DESCRIPTORS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is enabled by default, and MoltenVK will - * allocate a pool of descriptors when a VkDescriptorPool is created. - */ - VkBool32 preallocateDescriptors; - - /** - * Controls whether MoltenVK should use pools to manage memory used when adding commands - * to command buffers. If this setting is enabled, MoltenVK will use a pool to hold command - * resources for reuse during command execution. If this setting is disabled, command memory - * is allocated and destroyed each time a command is executed. This is a classic time-space - * trade off. When command pooling is active, the memory in the pool can be cleared via a - * call to the vkTrimCommandPoolKHR() command. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect behavior of VkCommandPools created - * after the setting is changed. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_USE_COMMAND_POOLING - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is enabled by default, and MoltenVK will pool command memory. - */ - VkBool32 useCommandPooling; - - /** - * Controls whether MoltenVK should use MTLHeaps for allocating textures and buffers - * from device memory. If this setting is enabled, and placement MTLHeaps are - * available on the platform, MoltenVK will allocate a placement MTLHeap for each VkDeviceMemory - * instance, and allocate textures and buffers from that placement heap. If this environment - * variable is disabled, MoltenVK will allocate textures and buffers from general device memory. - * - * Apple recommends that MTLHeaps should only be used for specific requirements such as aliasing - * or hazard tracking, and MoltenVK testing has shown that allocating multiple textures of - * different types or usages from one MTLHeap can occassionally cause corruption issues under - * certain circumstances. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_USE_MTLHEAP - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is disabled by default, and MoltenVK - * will allocate texures and buffers from general device memory. - */ - VkBool32 useMTLHeap; - - /** - * Controls when MoltenVK should log activity performance events. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is set to - * MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_FRAME_COUNT by default, - * and activity performance will be logged when frame activity is logged. - */ - MVKConfigActivityPerformanceLoggingStyle activityPerformanceLoggingStyle; -#define logActivityPerformanceInline activityPerformanceLoggingStyle - - /** - * Controls the Vulkan API version that MoltenVK should advertise in vkEnumerateInstanceVersion(). - * When reading this value, it will be one of the VK_API_VERSION_1_* values, including the latest - * VK_HEADER_VERSION component. When setting this value, it should be set to one of: - * - * VK_API_VERSION_1_2 (equivalent decimal number 4202496) - * VK_API_VERSION_1_1 (equivalent decimal number 4198400) - * VK_API_VERSION_1_0 (equivalent decimal number 4194304) - * - * MoltenVK will automatically add the VK_HEADER_VERSION component. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_API_VERSION_TO_ADVERTISE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to the highest API version - * currently supported by MoltenVK, including the latest VK_HEADER_VERSION component. - */ - uint32_t apiVersionToAdvertise; - - /** - * Controls which extensions MoltenVK should advertise it supports in - * vkEnumerateInstanceExtensionProperties() and vkEnumerateDeviceExtensionProperties(). - * The value of this parameter is a bitwise OR of values from the MVKConfigAdvertiseExtensionBits - * enumeration. Any prerequisite extensions are also advertised. - * If the flag MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL is included, all supported extensions - * will be advertised. A value of zero means no extensions will be advertised. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_ADVERTISE_EXTENSIONS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this setting defaults to - * MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL, and all supported extensions will be advertised. - */ - MVKConfigAdvertiseExtensions advertiseExtensions; - - /** - * Controls whether MoltenVK should treat a lost VkDevice as resumable, unless the - * corresponding VkPhysicalDevice has also been lost. The VK_ERROR_DEVICE_LOST error has - * a broad definitional range, and can mean anything from a GPU hiccup on the current - * command buffer submission, to a physically removed GPU. In the case where this error does - * not impact the VkPhysicalDevice, Vulkan requires that the app destroy and re-create a new - * VkDevice. However, not all apps (including CTS) respect that requirement, leading to what - * might be a transient command submission failure causing an unexpected catastrophic app failure. - * - * If this setting is enabled, in the case of a VK_ERROR_DEVICE_LOST error that does NOT impact - * the VkPhysicalDevice, MoltenVK will log the error, but will not mark the VkDevice as lost, - * allowing the VkDevice to continue to be used. If this setting is disabled, MoltenVK will - * mark the VkDevice as lost, and subsequent use of that VkDevice will be reduced or prohibited. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will affect the error behavior of subsequent command submissions. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_RESUME_LOST_DEVICE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is disabled by default, and MoltenVK - * will mark the VkDevice as lost when a command submission failure occurs. - */ - VkBool32 resumeLostDevice; - - /** - * Controls whether MoltenVK should use Metal argument buffers for resources defined in - * descriptor sets, if Metal argument buffers are supported on the platform. Using Metal - * argument buffers dramatically increases the number of buffers, textures and samplers - * that can be bound to a pipeline shader, and in most cases improves performance. - * This setting is an enumeration that specifies the conditions under which MoltenVK - * will use Metal argument buffers. - * - * NOTE: Currently, Metal argument buffer support is in beta stage, and is only supported - * on macOS 11.0 (Big Sur) or later, or on older versions of macOS using an Intel GPU. - * Metal argument buffers support is not available on iOS. Development to support iOS - * and a wider combination of GPU's on older macOS versions is under way. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is set to - * MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER by default, - * and MoltenVK will not use Metal argument buffers. - */ - MVKUseMetalArgumentBuffers useMetalArgumentBuffers; - - /** - * Controls the type of compression to use on the MSL source code that is stored in memory - * for use in a pipeline cache. After being converted from SPIR-V, or loaded directly into - * a VkShaderModule, and then compiled into a MTLLibrary, the MSL source code is no longer - * needed for operation, but it is retained so it can be written out as part of a pipeline - * cache export. When a large number of shaders are loaded, this can consume significant - * memory. In such a case, this parameter can be used to compress the MSL source code that - * is awaiting export as part of a pipeline cache. - * - * Pipeline cache compression is available for macOS 10.15 and above, and iOS/tvOS 13.0 and above. - * - * The value of this parameter can be changed at any time, and will affect the size of - * the cached MSL from subsequent shader compilations. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SHADER_COMPRESSION_ALGORITHM - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is set to - * MVK_CONFIG_COMPRESSION_ALGORITHM_NONE by default, - * and MoltenVK will not compress the MSL source code after compilation into a MTLLibrary. - */ - MVKConfigCompressionAlgorithm shaderSourceCompressionAlgorithm; - -} MVKConfiguration; - - - -#pragma mark - -#pragma mark Function types - - typedef VkResult (VKAPI_PTR *PFN_vkGetMoltenVKConfigurationMVK)(VkInstance ignored, MVKConfiguration* pConfiguration, size_t* pConfigurationSize); - typedef VkResult (VKAPI_PTR *PFN_vkSetMoltenVKConfigurationMVK)(VkInstance ignored, const MVKConfiguration* pConfiguration, size_t* pConfigurationSize); - - -#pragma mark - -#pragma mark Function prototypes - -#ifndef VK_NO_PROTOTYPES - -/** - * Populates the pConfiguration structure with the current MoltenVK configuration settings. - * - * To change a specific configuration value, call vkGetMoltenVKConfigurationMVK() to retrieve - * the current configuration, make changes, and call vkSetMoltenVKConfigurationMVK() to - * update all of the values. - * - * The VkInstance object you provide here is ignored, and a VK_NULL_HANDLE value can be provided. - * This function can be called before the VkInstance has been created. It is safe to call this function - * with a VkInstance retrieved from a different layer in the Vulkan SDK Loader and Layers framework. - * - * To be active, some configuration settings must be set before a VkInstance or VkDevice - * is created. See the description of the MVKConfiguration members for more information. - * - * If you are linking to an implementation of MoltenVK that was compiled from a different - * MVK_CONFIGURATION_API_VERSION than your app was, the size of the MVKConfiguration structure - * in your app may be larger or smaller than the same struct as expected by MoltenVK. - * - * When calling this function, set the value of *pConfigurationSize to sizeof(MVKConfiguration), - * to tell MoltenVK the limit of the size of your MVKConfiguration structure. Upon return from - * this function, the value of *pConfigurationSize will hold the actual number of bytes copied - * into your passed MVKConfiguration structure, which will be the smaller of what your app - * thinks is the size of MVKConfiguration, and what MoltenVK thinks it is. This represents the - * safe access area within the structure for both MoltenVK and your app. - * - * If the size that MoltenVK expects for MVKConfiguration is different than the value passed in - * *pConfigurationSize, this function will return VK_INCOMPLETE, otherwise it will return VK_SUCCESS. - * - * Although it is not necessary, you can use this function to determine in advance the value - * that MoltenVK expects the size of MVKConfiguration to be by setting the value of pConfiguration - * to NULL. In that case, this function will set *pConfigurationSize to the size that MoltenVK - * expects MVKConfiguration to be. - */ -VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfigurationMVK( - VkInstance ignored, - MVKConfiguration* pConfiguration, - size_t* pConfigurationSize); - -/** - * Sets the MoltenVK configuration settings to those found in the pConfiguration structure. - * - * To change a specific configuration value, call vkGetMoltenVKConfigurationMVK() - * to retrieve the current configuration, make changes, and call - * vkSetMoltenVKConfigurationMVK() to update all of the values. - * - * The VkInstance object you provide here is ignored, and a VK_NULL_HANDLE value can be provided. - * This function can be called before the VkInstance has been created. It is safe to call this function - * with a VkInstance retrieved from a different layer in the Vulkan SDK Loader and Layers framework. - * - * To be active, some configuration settings must be set before a VkInstance or VkDevice - * is created. See the description of the MVKConfiguration members for more information. - * - * If you are linking to an implementation of MoltenVK that was compiled from a different - * MVK_CONFIGURATION_API_VERSION than your app was, the size of the MVKConfiguration structure - * in your app may be larger or smaller than the same struct as expected by MoltenVK. - * - * When calling this function, set the value of *pConfigurationSize to sizeof(MVKConfiguration), - * to tell MoltenVK the limit of the size of your MVKConfiguration structure. Upon return from - * this function, the value of *pConfigurationSize will hold the actual number of bytes copied - * out of your passed MVKConfiguration structure, which will be the smaller of what your app - * thinks is the size of MVKConfiguration, and what MoltenVK thinks it is. This represents the - * safe access area within the structure for both MoltenVK and your app. - * - * If the size that MoltenVK expects for MVKConfiguration is different than the value passed in - * *pConfigurationSize, this function will return VK_INCOMPLETE, otherwise it will return VK_SUCCESS. - * - * Although it is not necessary, you can use this function to determine in advance the value - * that MoltenVK expects the size of MVKConfiguration to be by setting the value of pConfiguration - * to NULL. In that case, this function will set *pConfigurationSize to the size that MoltenVK - * expects MVKConfiguration to be. - */ -VKAPI_ATTR VkResult VKAPI_CALL vkSetMoltenVKConfigurationMVK( - VkInstance ignored, - const MVKConfiguration* pConfiguration, - size_t* pConfigurationSize); - - -#pragma mark - -#pragma mark Shaders - - /** - * NOTE: Shader code should be submitted as SPIR-V. Although some simple direct MSL shaders may work, - * direct loading of MSL source code or compiled MSL code is not officially supported at this time. - * Future versions of MoltenVK may support direct MSL submission again. - * - * Enumerates the magic number values to set in the MVKMSLSPIRVHeader when - * submitting a SPIR-V stream that contains either Metal Shading Language source - * code or Metal Shading Language compiled binary code in place of SPIR-V code. - */ - typedef enum { - kMVKMagicNumberSPIRVCode = 0x07230203, /**< SPIR-V stream contains standard SPIR-V code. */ - kMVKMagicNumberMSLSourceCode = 0x19960412, /**< SPIR-V stream contains Metal Shading Language source code. */ - kMVKMagicNumberMSLCompiledCode = 0x19981215, /**< SPIR-V stream contains Metal Shading Language compiled binary code. */ - } MVKMSLMagicNumber; - - /** - * NOTE: Shader code should be submitted as SPIR-V. Although some simple direct MSL shaders may work, - * direct loading of MSL source code or compiled MSL code is not officially supported at this time. - * Future versions of MoltenVK may support direct MSL submission again. - * - * Describes the header at the start of an SPIR-V stream, when it contains either - * Metal Shading Language source code or Metal Shading Language compiled binary code. - * - * To submit MSL source code to the vkCreateShaderModule() function in place of SPIR-V - * code, prepend a MVKMSLSPIRVHeader containing the kMVKMagicNumberMSLSourceCode magic - * number to the MSL source code. The MSL source code must be null-terminated. - * - * To submit MSL compiled binary code to the vkCreateShaderModule() function in place of - * SPIR-V code, prepend a MVKMSLSPIRVHeader containing the kMVKMagicNumberMSLCompiledCode - * magic number to the MSL compiled binary code. - * - * In both cases, the pCode element of VkShaderModuleCreateInfo should pointer to the - * location of the MVKMSLSPIRVHeader, and the MSL code should start at the byte immediately - * after the MVKMSLSPIRVHeader. - * - * The codeSize element of VkShaderModuleCreateInfo should be set to the entire size of - * the submitted code memory, including the additional sizeof(MVKMSLSPIRVHeader) bytes - * taken up by the MVKMSLSPIRVHeader, and, in the case of MSL source code, including - * the null-terminator byte. - */ - typedef uint32_t MVKMSLSPIRVHeader; - - -#endif // VK_NO_PROTOTYPES - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif diff --git a/lib/graphics_engine/include/vk_platform.h b/lib/graphics_engine/include/vk_platform.h index 3ff8c5d1467..f570181e33a 100644 --- a/lib/graphics_engine/include/vk_platform.h +++ b/lib/graphics_engine/include/vk_platform.h @@ -1,8 +1,8 @@ -// -// File: vk_platform.h -// +/* */ +/* File: vk_platform.h */ +/* */ /* -** Copyright 2014-2022 The Khronos Group Inc. +** Copyright 2014-2025 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ @@ -14,7 +14,7 @@ #ifdef __cplusplus extern "C" { -#endif // __cplusplus +#endif /* __cplusplus */ /* *************************************************************************************************** @@ -37,22 +37,22 @@ extern "C" * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); */ #if defined(_WIN32) - // On Windows, Vulkan commands use the stdcall convention + /* On Windows, Vulkan commands use the stdcall convention */ #define VKAPI_ATTR #define VKAPI_CALL __stdcall #define VKAPI_PTR VKAPI_CALL #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 #error "Vulkan is not supported for the 'armeabi' NDK ABI" #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) - // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" - // calling convention, i.e. float parameters are passed in registers. This - // is true even if the rest of the application passes floats on the stack, - // as it does by default when compiling for the armeabi-v7a NDK ABI. + /* On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" */ + /* calling convention, i.e. float parameters are passed in registers. This */ + /* is true even if the rest of the application passes floats on the stack, */ + /* as it does by default when compiling for the armeabi-v7a NDK ABI. */ #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) #define VKAPI_CALL #define VKAPI_PTR VKAPI_ATTR #else - // On other platforms, use the default calling convention + /* On other platforms, use the default calling convention */ #define VKAPI_ATTR #define VKAPI_CALL #define VKAPI_PTR @@ -60,7 +60,7 @@ extern "C" #if !defined(VK_NO_STDDEF_H) #include -#endif // !defined(VK_NO_STDDEF_H) +#endif /* !defined(VK_NO_STDDEF_H) */ #if !defined(VK_NO_STDINT_H) #if defined(_MSC_VER) && (_MSC_VER < 1600) @@ -75,10 +75,10 @@ extern "C" #else #include #endif -#endif // !defined(VK_NO_STDINT_H) +#endif /* !defined(VK_NO_STDINT_H) */ #ifdef __cplusplus -} // extern "C" -#endif // __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ #endif diff --git a/lib/graphics_engine/include/vulkan_wrapper.h b/lib/graphics_engine/include/vulkan_wrapper.h index a26ea62c637..9f83a637592 100644 --- a/lib/graphics_engine/include/vulkan_wrapper.h +++ b/lib/graphics_engine/include/vulkan_wrapper.h @@ -4,18 +4,11 @@ #if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK) #include -#define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22) & 0x7FU) -#define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU) -#define VK_API_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) - #ifdef DLOPEN_MOLTENVK #define VK_NO_PROTOTYPES 1 -// We copy mvk_config.h and mvk_private_api.h with #include +// We copy mvk_private_api.h with #include // removed -#include #include -extern PFN_vkGetMoltenVKConfigurationMVK vkGetMoltenVKConfigurationMVK; -extern PFN_vkSetMoltenVKConfigurationMVK vkSetMoltenVKConfigurationMVK; extern PFN_vkGetPhysicalDeviceMetalFeaturesMVK vkGetPhysicalDeviceMetalFeaturesMVK; #endif @@ -23,7 +16,6 @@ extern PFN_vkGetPhysicalDeviceMetalFeaturesMVK vkGetPhysicalDeviceMetalFeaturesM #include #if defined(__APPLE__) -#include #include #endif diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index af77da6fe4a..387d9dd17eb 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -532,15 +532,6 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params, g_paused_rendering.store(false); g_device_created.store(true); -#if defined(__APPLE__) - MVKConfiguration cfg = {}; - size_t cfg_size = sizeof(MVKConfiguration); - vkGetMoltenVKConfigurationMVK(VK_NULL_HANDLE, &cfg, &cfg_size); - // Enable to allow binding all textures at once - cfg.useMetalArgumentBuffers = MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_ALWAYS; - vkSetMoltenVKConfigurationMVK(VK_NULL_HANDLE, &cfg, &cfg_size); -#endif - createInstance(window); #if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK) @@ -789,8 +780,8 @@ void GEVulkanDriver::createInstance(SDL_Window* window) std::vector available_layers(layer_count); vkEnumerateInstanceLayerProperties(&layer_count, available_layers.data()); - VkInstanceCreateInfo create_info = {}; std::vector enabled_validation_layers; + void* next_chain = NULL; #ifdef ENABLE_VALIDATION g_debug_print = true; @@ -812,10 +803,29 @@ void GEVulkanDriver::createInstance(SDL_Window* window) validation_features.enabledValidationFeatureCount = enabled_validation_features.size(); - create_info.pNext = &validation_features; + next_chain = &validation_features; extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); #endif +#if defined(__APPLE__) + // We need these to persist until after vkCreateInstance + static VkLayerSettingsCreateInfoEXT layer_settings_create_info = {}; + static VkBool32 setting_false = VK_FALSE; + static VkLayerSettingEXT setting = {}; + setting.pLayerName = "MoltenVK"; + setting.pSettingName = "MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS"; + setting.type = VK_LAYER_SETTING_TYPE_BOOL32_EXT; + setting.pValues = &setting_false; + setting.valueCount = 1; + + layer_settings_create_info.sType = VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT; + layer_settings_create_info.settingCount = 1; + layer_settings_create_info.pSettings = &setting; + layer_settings_create_info.pNext = next_chain; + next_chain = &layer_settings_create_info; + extensions.push_back(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME); +#endif + VkApplicationInfo app_info = {}; if (vulkan_1_1) { @@ -823,9 +833,11 @@ void GEVulkanDriver::createInstance(SDL_Window* window) // Implementations that support Vulkan 1.1 or later must not return VK_ERROR_INCOMPATIBLE_DRIVER for any value of apiVersion. app_info.apiVersion = VK_API_VERSION_1_2; } + VkInstanceCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; create_info.enabledExtensionCount = extensions.size(); create_info.ppEnabledExtensionNames = extensions.data(); + create_info.pNext = next_chain; create_info.pApplicationInfo = &app_info; create_info.enabledLayerCount = enabled_validation_layers.size(); create_info.ppEnabledLayerNames = enabled_validation_layers.data(); diff --git a/lib/graphics_engine/src/vulkan.c b/lib/graphics_engine/src/vulkan.c index e8fbe6c178c..cd64f1e8b09 100644 --- a/lib/graphics_engine/src/vulkan.c +++ b/lib/graphics_engine/src/vulkan.c @@ -1,3 +1,6 @@ +/** + * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 + */ #include #include #include @@ -23,6 +26,13 @@ extern "C" { int GLAD_VK_VERSION_1_0 = 0; int GLAD_VK_VERSION_1_1 = 0; int GLAD_VK_VERSION_1_2 = 0; +int GLAD_VK_VERSION_1_3 = 0; +int GLAD_VK_VERSION_1_4 = 0; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +int GLAD_VK_AMDX_shader_enqueue = 0; + +#endif +int GLAD_VK_AMD_anti_lag = 0; int GLAD_VK_AMD_buffer_marker = 0; int GLAD_VK_AMD_device_coherent_memory = 0; int GLAD_VK_AMD_display_native_hdr = 0; @@ -38,6 +48,7 @@ int GLAD_VK_AMD_rasterization_order = 0; int GLAD_VK_AMD_shader_ballot = 0; int GLAD_VK_AMD_shader_core_properties = 0; int GLAD_VK_AMD_shader_core_properties2 = 0; +int GLAD_VK_AMD_shader_early_and_late_fragment_tests = 0; int GLAD_VK_AMD_shader_explicit_vertex_parameter = 0; int GLAD_VK_AMD_shader_fragment_mask = 0; int GLAD_VK_AMD_shader_image_load_store_lod = 0; @@ -45,75 +56,159 @@ int GLAD_VK_AMD_shader_info = 0; int GLAD_VK_AMD_shader_trinary_minmax = 0; int GLAD_VK_AMD_texture_gather_bias_lod = 0; #if defined(VK_USE_PLATFORM_ANDROID_KHR) +int GLAD_VK_ANDROID_external_format_resolve = 0; + +#endif +#if defined(VK_USE_PLATFORM_ANDROID_KHR) int GLAD_VK_ANDROID_external_memory_android_hardware_buffer = 0; + #endif +int GLAD_VK_ARM_pipeline_opacity_micromap = 0; +int GLAD_VK_ARM_rasterization_order_attachment_access = 0; +int GLAD_VK_ARM_render_pass_striped = 0; +int GLAD_VK_ARM_scheduling_controls = 0; +int GLAD_VK_ARM_shader_core_builtins = 0; +int GLAD_VK_ARM_shader_core_properties = 0; int GLAD_VK_EXT_4444_formats = 0; +int GLAD_VK_EXT_acquire_drm_display = 0; #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) int GLAD_VK_EXT_acquire_xlib_display = 0; + #endif int GLAD_VK_EXT_astc_decode_mode = 0; +int GLAD_VK_EXT_attachment_feedback_loop_dynamic_state = 0; +int GLAD_VK_EXT_attachment_feedback_loop_layout = 0; int GLAD_VK_EXT_blend_operation_advanced = 0; +int GLAD_VK_EXT_border_color_swizzle = 0; int GLAD_VK_EXT_buffer_device_address = 0; int GLAD_VK_EXT_calibrated_timestamps = 0; +int GLAD_VK_EXT_color_write_enable = 0; int GLAD_VK_EXT_conditional_rendering = 0; int GLAD_VK_EXT_conservative_rasterization = 0; int GLAD_VK_EXT_custom_border_color = 0; int GLAD_VK_EXT_debug_marker = 0; int GLAD_VK_EXT_debug_report = 0; int GLAD_VK_EXT_debug_utils = 0; +int GLAD_VK_EXT_depth_bias_control = 0; +int GLAD_VK_EXT_depth_clamp_control = 0; +int GLAD_VK_EXT_depth_clamp_zero_one = 0; +int GLAD_VK_EXT_depth_clip_control = 0; int GLAD_VK_EXT_depth_clip_enable = 0; int GLAD_VK_EXT_depth_range_unrestricted = 0; +int GLAD_VK_EXT_descriptor_buffer = 0; int GLAD_VK_EXT_descriptor_indexing = 0; +int GLAD_VK_EXT_device_address_binding_report = 0; +int GLAD_VK_EXT_device_fault = 0; +int GLAD_VK_EXT_device_generated_commands = 0; +int GLAD_VK_EXT_device_memory_report = 0; int GLAD_VK_EXT_direct_mode_display = 0; #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) int GLAD_VK_EXT_directfb_surface = 0; + #endif int GLAD_VK_EXT_discard_rectangles = 0; int GLAD_VK_EXT_display_control = 0; int GLAD_VK_EXT_display_surface_counter = 0; +int GLAD_VK_EXT_dynamic_rendering_unused_attachments = 0; int GLAD_VK_EXT_extended_dynamic_state = 0; +int GLAD_VK_EXT_extended_dynamic_state2 = 0; +int GLAD_VK_EXT_extended_dynamic_state3 = 0; +int GLAD_VK_EXT_external_memory_acquire_unmodified = 0; int GLAD_VK_EXT_external_memory_dma_buf = 0; int GLAD_VK_EXT_external_memory_host = 0; +#if defined(VK_USE_PLATFORM_METAL_EXT) +int GLAD_VK_EXT_external_memory_metal = 0; + +#endif int GLAD_VK_EXT_filter_cubic = 0; int GLAD_VK_EXT_fragment_density_map = 0; int GLAD_VK_EXT_fragment_density_map2 = 0; +int GLAD_VK_EXT_fragment_density_map_offset = 0; int GLAD_VK_EXT_fragment_shader_interlock = 0; +int GLAD_VK_EXT_frame_boundary = 0; #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_EXT_full_screen_exclusive = 0; + #endif int GLAD_VK_EXT_global_priority = 0; +int GLAD_VK_EXT_global_priority_query = 0; +int GLAD_VK_EXT_graphics_pipeline_library = 0; int GLAD_VK_EXT_hdr_metadata = 0; int GLAD_VK_EXT_headless_surface = 0; +int GLAD_VK_EXT_host_image_copy = 0; int GLAD_VK_EXT_host_query_reset = 0; +int GLAD_VK_EXT_image_2d_view_of_3d = 0; +int GLAD_VK_EXT_image_compression_control = 0; +int GLAD_VK_EXT_image_compression_control_swapchain = 0; int GLAD_VK_EXT_image_drm_format_modifier = 0; int GLAD_VK_EXT_image_robustness = 0; +int GLAD_VK_EXT_image_sliced_view_of_3d = 0; +int GLAD_VK_EXT_image_view_min_lod = 0; int GLAD_VK_EXT_index_type_uint8 = 0; int GLAD_VK_EXT_inline_uniform_block = 0; +int GLAD_VK_EXT_layer_settings = 0; +int GLAD_VK_EXT_legacy_dithering = 0; +int GLAD_VK_EXT_legacy_vertex_attributes = 0; int GLAD_VK_EXT_line_rasterization = 0; +int GLAD_VK_EXT_load_store_op_none = 0; +int GLAD_VK_EXT_map_memory_placed = 0; int GLAD_VK_EXT_memory_budget = 0; int GLAD_VK_EXT_memory_priority = 0; +int GLAD_VK_EXT_mesh_shader = 0; +#if defined(VK_USE_PLATFORM_METAL_EXT) +int GLAD_VK_EXT_metal_objects = 0; + +#endif #if defined(VK_USE_PLATFORM_METAL_EXT) int GLAD_VK_EXT_metal_surface = 0; + #endif +int GLAD_VK_EXT_multi_draw = 0; +int GLAD_VK_EXT_multisampled_render_to_single_sampled = 0; +int GLAD_VK_EXT_mutable_descriptor_type = 0; +int GLAD_VK_EXT_nested_command_buffer = 0; +int GLAD_VK_EXT_non_seamless_cube_map = 0; +int GLAD_VK_EXT_opacity_micromap = 0; +int GLAD_VK_EXT_pageable_device_local_memory = 0; int GLAD_VK_EXT_pci_bus_info = 0; +int GLAD_VK_EXT_physical_device_drm = 0; int GLAD_VK_EXT_pipeline_creation_cache_control = 0; int GLAD_VK_EXT_pipeline_creation_feedback = 0; +int GLAD_VK_EXT_pipeline_library_group_handles = 0; +int GLAD_VK_EXT_pipeline_properties = 0; +int GLAD_VK_EXT_pipeline_protected_access = 0; +int GLAD_VK_EXT_pipeline_robustness = 0; int GLAD_VK_EXT_post_depth_coverage = 0; +int GLAD_VK_EXT_present_mode_fifo_latest_ready = 0; +int GLAD_VK_EXT_primitive_topology_list_restart = 0; +int GLAD_VK_EXT_primitives_generated_query = 0; int GLAD_VK_EXT_private_data = 0; +int GLAD_VK_EXT_provoking_vertex = 0; int GLAD_VK_EXT_queue_family_foreign = 0; +int GLAD_VK_EXT_rasterization_order_attachment_access = 0; +int GLAD_VK_EXT_rgba10x6_formats = 0; int GLAD_VK_EXT_robustness2 = 0; int GLAD_VK_EXT_sample_locations = 0; int GLAD_VK_EXT_sampler_filter_minmax = 0; int GLAD_VK_EXT_scalar_block_layout = 0; int GLAD_VK_EXT_separate_stencil_usage = 0; int GLAD_VK_EXT_shader_atomic_float = 0; +int GLAD_VK_EXT_shader_atomic_float2 = 0; int GLAD_VK_EXT_shader_demote_to_helper_invocation = 0; +int GLAD_VK_EXT_shader_image_atomic_int64 = 0; +int GLAD_VK_EXT_shader_module_identifier = 0; +int GLAD_VK_EXT_shader_object = 0; +int GLAD_VK_EXT_shader_replicated_composites = 0; int GLAD_VK_EXT_shader_stencil_export = 0; int GLAD_VK_EXT_shader_subgroup_ballot = 0; int GLAD_VK_EXT_shader_subgroup_vote = 0; +int GLAD_VK_EXT_shader_tile_image = 0; int GLAD_VK_EXT_shader_viewport_index_layer = 0; int GLAD_VK_EXT_subgroup_size_control = 0; +int GLAD_VK_EXT_subpass_merge_feedback = 0; +int GLAD_VK_EXT_surface_maintenance1 = 0; int GLAD_VK_EXT_swapchain_colorspace = 0; +int GLAD_VK_EXT_swapchain_maintenance1 = 0; int GLAD_VK_EXT_texel_buffer_alignment = 0; int GLAD_VK_EXT_texture_compression_astc_hdr = 0; int GLAD_VK_EXT_tooling_info = 0; @@ -122,36 +217,65 @@ int GLAD_VK_EXT_validation_cache = 0; int GLAD_VK_EXT_validation_features = 0; int GLAD_VK_EXT_validation_flags = 0; int GLAD_VK_EXT_vertex_attribute_divisor = 0; +int GLAD_VK_EXT_vertex_attribute_robustness = 0; +int GLAD_VK_EXT_vertex_input_dynamic_state = 0; +int GLAD_VK_EXT_ycbcr_2plane_444_formats = 0; int GLAD_VK_EXT_ycbcr_image_arrays = 0; #if defined(VK_USE_PLATFORM_FUCHSIA) +int GLAD_VK_FUCHSIA_buffer_collection = 0; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +int GLAD_VK_FUCHSIA_external_memory = 0; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +int GLAD_VK_FUCHSIA_external_semaphore = 0; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) int GLAD_VK_FUCHSIA_imagepipe_surface = 0; + #endif #if defined(VK_USE_PLATFORM_GGP) int GLAD_VK_GGP_frame_token = 0; + #endif #if defined(VK_USE_PLATFORM_GGP) int GLAD_VK_GGP_stream_descriptor_surface = 0; + #endif int GLAD_VK_GOOGLE_decorate_string = 0; int GLAD_VK_GOOGLE_display_timing = 0; int GLAD_VK_GOOGLE_hlsl_functionality1 = 0; +int GLAD_VK_GOOGLE_surfaceless_query = 0; int GLAD_VK_GOOGLE_user_type = 0; +int GLAD_VK_HUAWEI_cluster_culling_shader = 0; +int GLAD_VK_HUAWEI_hdr_vivid = 0; +int GLAD_VK_HUAWEI_invocation_mask = 0; +int GLAD_VK_HUAWEI_subpass_shading = 0; int GLAD_VK_IMG_filter_cubic = 0; int GLAD_VK_IMG_format_pvrtc = 0; +int GLAD_VK_IMG_relaxed_line_rasterization = 0; int GLAD_VK_INTEL_performance_query = 0; int GLAD_VK_INTEL_shader_integer_functions2 = 0; int GLAD_VK_KHR_16bit_storage = 0; int GLAD_VK_KHR_8bit_storage = 0; +int GLAD_VK_KHR_acceleration_structure = 0; #if defined(VK_USE_PLATFORM_ANDROID_KHR) int GLAD_VK_KHR_android_surface = 0; + #endif int GLAD_VK_KHR_bind_memory2 = 0; int GLAD_VK_KHR_buffer_device_address = 0; +int GLAD_VK_KHR_calibrated_timestamps = 0; +int GLAD_VK_KHR_compute_shader_derivatives = 0; +int GLAD_VK_KHR_cooperative_matrix = 0; +int GLAD_VK_KHR_copy_commands2 = 0; int GLAD_VK_KHR_create_renderpass2 = 0; int GLAD_VK_KHR_dedicated_allocation = 0; -#if defined(VK_ENABLE_BETA_EXTENSIONS) int GLAD_VK_KHR_deferred_host_operations = 0; -#endif +int GLAD_VK_KHR_depth_clamp_zero_one = 0; int GLAD_VK_KHR_depth_stencil_resolve = 0; int GLAD_VK_KHR_descriptor_update_template = 0; int GLAD_VK_KHR_device_group = 0; @@ -160,55 +284,91 @@ int GLAD_VK_KHR_display = 0; int GLAD_VK_KHR_display_swapchain = 0; int GLAD_VK_KHR_draw_indirect_count = 0; int GLAD_VK_KHR_driver_properties = 0; +int GLAD_VK_KHR_dynamic_rendering = 0; +int GLAD_VK_KHR_dynamic_rendering_local_read = 0; int GLAD_VK_KHR_external_fence = 0; int GLAD_VK_KHR_external_fence_capabilities = 0; int GLAD_VK_KHR_external_fence_fd = 0; #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_KHR_external_fence_win32 = 0; + #endif int GLAD_VK_KHR_external_memory = 0; int GLAD_VK_KHR_external_memory_capabilities = 0; int GLAD_VK_KHR_external_memory_fd = 0; #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_KHR_external_memory_win32 = 0; + #endif int GLAD_VK_KHR_external_semaphore = 0; int GLAD_VK_KHR_external_semaphore_capabilities = 0; int GLAD_VK_KHR_external_semaphore_fd = 0; #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_KHR_external_semaphore_win32 = 0; + #endif +int GLAD_VK_KHR_format_feature_flags2 = 0; +int GLAD_VK_KHR_fragment_shader_barycentric = 0; +int GLAD_VK_KHR_fragment_shading_rate = 0; int GLAD_VK_KHR_get_display_properties2 = 0; int GLAD_VK_KHR_get_memory_requirements2 = 0; int GLAD_VK_KHR_get_physical_device_properties2 = 0; int GLAD_VK_KHR_get_surface_capabilities2 = 0; +int GLAD_VK_KHR_global_priority = 0; int GLAD_VK_KHR_image_format_list = 0; int GLAD_VK_KHR_imageless_framebuffer = 0; int GLAD_VK_KHR_incremental_present = 0; +int GLAD_VK_KHR_index_type_uint8 = 0; +int GLAD_VK_KHR_line_rasterization = 0; +int GLAD_VK_KHR_load_store_op_none = 0; int GLAD_VK_KHR_maintenance1 = 0; int GLAD_VK_KHR_maintenance2 = 0; int GLAD_VK_KHR_maintenance3 = 0; +int GLAD_VK_KHR_maintenance4 = 0; +int GLAD_VK_KHR_maintenance5 = 0; +int GLAD_VK_KHR_maintenance6 = 0; +int GLAD_VK_KHR_maintenance7 = 0; +int GLAD_VK_KHR_maintenance8 = 0; +int GLAD_VK_KHR_map_memory2 = 0; int GLAD_VK_KHR_multiview = 0; int GLAD_VK_KHR_performance_query = 0; +int GLAD_VK_KHR_pipeline_binary = 0; int GLAD_VK_KHR_pipeline_executable_properties = 0; -#if defined(VK_ENABLE_BETA_EXTENSIONS) int GLAD_VK_KHR_pipeline_library = 0; -#endif -int GLAD_VK_KHR_push_descriptor = 0; +int GLAD_VK_KHR_portability_enumeration = 0; #if defined(VK_ENABLE_BETA_EXTENSIONS) -int GLAD_VK_KHR_ray_tracing = 0; +int GLAD_VK_KHR_portability_subset = 0; + #endif +int GLAD_VK_KHR_present_id = 0; +int GLAD_VK_KHR_present_wait = 0; +int GLAD_VK_KHR_push_descriptor = 0; +int GLAD_VK_KHR_ray_query = 0; +int GLAD_VK_KHR_ray_tracing_maintenance1 = 0; +int GLAD_VK_KHR_ray_tracing_pipeline = 0; +int GLAD_VK_KHR_ray_tracing_position_fetch = 0; int GLAD_VK_KHR_relaxed_block_layout = 0; +int GLAD_VK_KHR_robustness2 = 0; int GLAD_VK_KHR_sampler_mirror_clamp_to_edge = 0; int GLAD_VK_KHR_sampler_ycbcr_conversion = 0; int GLAD_VK_KHR_separate_depth_stencil_layouts = 0; int GLAD_VK_KHR_shader_atomic_int64 = 0; +int GLAD_VK_KHR_shader_bfloat16 = 0; int GLAD_VK_KHR_shader_clock = 0; int GLAD_VK_KHR_shader_draw_parameters = 0; +int GLAD_VK_KHR_shader_expect_assume = 0; int GLAD_VK_KHR_shader_float16_int8 = 0; int GLAD_VK_KHR_shader_float_controls = 0; +int GLAD_VK_KHR_shader_float_controls2 = 0; +int GLAD_VK_KHR_shader_integer_dot_product = 0; +int GLAD_VK_KHR_shader_maximal_reconvergence = 0; int GLAD_VK_KHR_shader_non_semantic_info = 0; +int GLAD_VK_KHR_shader_quad_control = 0; +int GLAD_VK_KHR_shader_relaxed_extended_instruction = 0; int GLAD_VK_KHR_shader_subgroup_extended_types = 0; +int GLAD_VK_KHR_shader_subgroup_rotate = 0; +int GLAD_VK_KHR_shader_subgroup_uniform_control_flow = 0; +int GLAD_VK_KHR_shader_terminate_invocation = 0; int GLAD_VK_KHR_shared_presentable_image = 0; int GLAD_VK_KHR_spirv_1_4 = 0; int GLAD_VK_KHR_storage_buffer_storage_class = 0; @@ -216,62 +376,122 @@ int GLAD_VK_KHR_surface = 0; int GLAD_VK_KHR_surface_protected_capabilities = 0; int GLAD_VK_KHR_swapchain = 0; int GLAD_VK_KHR_swapchain_mutable_format = 0; +int GLAD_VK_KHR_synchronization2 = 0; int GLAD_VK_KHR_timeline_semaphore = 0; int GLAD_VK_KHR_uniform_buffer_standard_layout = 0; int GLAD_VK_KHR_variable_pointers = 0; +int GLAD_VK_KHR_vertex_attribute_divisor = 0; int GLAD_VK_KHR_vulkan_memory_model = 0; #if defined(VK_USE_PLATFORM_WAYLAND_KHR) int GLAD_VK_KHR_wayland_surface = 0; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_KHR_win32_keyed_mutex = 0; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_KHR_win32_surface = 0; + #endif +int GLAD_VK_KHR_workgroup_memory_explicit_layout = 0; #if defined(VK_USE_PLATFORM_XCB_KHR) int GLAD_VK_KHR_xcb_surface = 0; + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) int GLAD_VK_KHR_xlib_surface = 0; + #endif +int GLAD_VK_KHR_zero_initialize_workgroup_memory = 0; +int GLAD_VK_LUNARG_direct_driver_loading = 0; +int GLAD_VK_MESA_image_alignment_control = 0; +int GLAD_VK_MSFT_layered_driver = 0; #if defined(VK_USE_PLATFORM_IOS_MVK) int GLAD_VK_MVK_ios_surface = 0; + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) int GLAD_VK_MVK_macos_surface = 0; + #endif #if defined(VK_USE_PLATFORM_VI_NN) int GLAD_VK_NN_vi_surface = 0; + #endif +int GLAD_VK_NVX_binary_import = 0; int GLAD_VK_NVX_image_view_handle = 0; int GLAD_VK_NVX_multiview_per_view_attributes = 0; +#if defined(VK_USE_PLATFORM_WIN32_KHR) +int GLAD_VK_NV_acquire_winrt_display = 0; + +#endif int GLAD_VK_NV_clip_space_w_scaling = 0; +int GLAD_VK_NV_cluster_acceleration_structure = 0; +int GLAD_VK_NV_command_buffer_inheritance = 0; int GLAD_VK_NV_compute_shader_derivatives = 0; int GLAD_VK_NV_cooperative_matrix = 0; +int GLAD_VK_NV_cooperative_matrix2 = 0; +int GLAD_VK_NV_cooperative_vector = 0; +int GLAD_VK_NV_copy_memory_indirect = 0; int GLAD_VK_NV_corner_sampled_image = 0; int GLAD_VK_NV_coverage_reduction_mode = 0; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +int GLAD_VK_NV_cuda_kernel_launch = 0; + +#endif int GLAD_VK_NV_dedicated_allocation = 0; int GLAD_VK_NV_dedicated_allocation_image_aliasing = 0; +int GLAD_VK_NV_descriptor_pool_overallocation = 0; int GLAD_VK_NV_device_diagnostic_checkpoints = 0; int GLAD_VK_NV_device_diagnostics_config = 0; int GLAD_VK_NV_device_generated_commands = 0; +int GLAD_VK_NV_device_generated_commands_compute = 0; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +int GLAD_VK_NV_displacement_micromap = 0; + +#endif +int GLAD_VK_NV_display_stereo = 0; +int GLAD_VK_NV_extended_sparse_address_space = 0; +int GLAD_VK_NV_external_compute_queue = 0; int GLAD_VK_NV_external_memory = 0; int GLAD_VK_NV_external_memory_capabilities = 0; +int GLAD_VK_NV_external_memory_rdma = 0; #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_NV_external_memory_win32 = 0; + #endif int GLAD_VK_NV_fill_rectangle = 0; int GLAD_VK_NV_fragment_coverage_to_color = 0; int GLAD_VK_NV_fragment_shader_barycentric = 0; +int GLAD_VK_NV_fragment_shading_rate_enums = 0; int GLAD_VK_NV_framebuffer_mixed_samples = 0; int GLAD_VK_NV_geometry_shader_passthrough = 0; int GLAD_VK_NV_glsl_shader = 0; +int GLAD_VK_NV_inherited_viewport_scissor = 0; +int GLAD_VK_NV_linear_color_attachment = 0; +int GLAD_VK_NV_low_latency = 0; +int GLAD_VK_NV_low_latency2 = 0; +int GLAD_VK_NV_memory_decompression = 0; int GLAD_VK_NV_mesh_shader = 0; +int GLAD_VK_NV_optical_flow = 0; +int GLAD_VK_NV_partitioned_acceleration_structure = 0; +int GLAD_VK_NV_per_stage_descriptor_set = 0; +int GLAD_VK_NV_present_barrier = 0; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +int GLAD_VK_NV_present_metering = 0; + +#endif +int GLAD_VK_NV_raw_access_chains = 0; int GLAD_VK_NV_ray_tracing = 0; +int GLAD_VK_NV_ray_tracing_invocation_reorder = 0; +int GLAD_VK_NV_ray_tracing_linear_swept_spheres = 0; +int GLAD_VK_NV_ray_tracing_motion_blur = 0; +int GLAD_VK_NV_ray_tracing_validation = 0; int GLAD_VK_NV_representative_fragment_test = 0; int GLAD_VK_NV_sample_mask_override_coverage = 0; int GLAD_VK_NV_scissor_exclusive = 0; +int GLAD_VK_NV_shader_atomic_float16_vector = 0; int GLAD_VK_NV_shader_image_footprint = 0; int GLAD_VK_NV_shader_sm_builtins = 0; int GLAD_VK_NV_shader_subgroup_partitioned = 0; @@ -280,30 +500,59 @@ int GLAD_VK_NV_viewport_array2 = 0; int GLAD_VK_NV_viewport_swizzle = 0; #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_NV_win32_keyed_mutex = 0; + #endif +int GLAD_VK_QCOM_filter_cubic_clamp = 0; +int GLAD_VK_QCOM_filter_cubic_weights = 0; +int GLAD_VK_QCOM_fragment_density_map_offset = 0; +int GLAD_VK_QCOM_image_processing = 0; +int GLAD_VK_QCOM_image_processing2 = 0; +int GLAD_VK_QCOM_multiview_per_view_render_areas = 0; +int GLAD_VK_QCOM_multiview_per_view_viewports = 0; int GLAD_VK_QCOM_render_pass_shader_resolve = 0; int GLAD_VK_QCOM_render_pass_store_ops = 0; int GLAD_VK_QCOM_render_pass_transform = 0; +int GLAD_VK_QCOM_rotated_copy_commands = 0; +int GLAD_VK_QCOM_tile_memory_heap = 0; +int GLAD_VK_QCOM_tile_properties = 0; +int GLAD_VK_QCOM_tile_shading = 0; +int GLAD_VK_QCOM_ycbcr_degamma = 0; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +int GLAD_VK_QNX_external_memory_screen_buffer = 0; + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +int GLAD_VK_QNX_screen_surface = 0; + +#endif +int GLAD_VK_SEC_amigo_profiling = 0; +int GLAD_VK_VALVE_descriptor_set_host_mapping = 0; +int GLAD_VK_VALVE_mutable_descriptor_type = 0; +PFN_vkAcquireDrmDisplayEXT glad_vkAcquireDrmDisplayEXT = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkAcquireFullScreenExclusiveModeEXT glad_vkAcquireFullScreenExclusiveModeEXT = NULL; + #endif PFN_vkAcquireNextImage2KHR glad_vkAcquireNextImage2KHR = NULL; PFN_vkAcquireNextImageKHR glad_vkAcquireNextImageKHR = NULL; PFN_vkAcquirePerformanceConfigurationINTEL glad_vkAcquirePerformanceConfigurationINTEL = NULL; PFN_vkAcquireProfilingLockKHR glad_vkAcquireProfilingLockKHR = NULL; +#if defined(VK_USE_PLATFORM_WIN32_KHR) +PFN_vkAcquireWinrtDisplayNV glad_vkAcquireWinrtDisplayNV = NULL; + +#endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) PFN_vkAcquireXlibDisplayEXT glad_vkAcquireXlibDisplayEXT = NULL; + #endif PFN_vkAllocateCommandBuffers glad_vkAllocateCommandBuffers = NULL; PFN_vkAllocateDescriptorSets glad_vkAllocateDescriptorSets = NULL; PFN_vkAllocateMemory glad_vkAllocateMemory = NULL; +PFN_vkAntiLagUpdateAMD glad_vkAntiLagUpdateAMD = NULL; PFN_vkBeginCommandBuffer glad_vkBeginCommandBuffer = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -PFN_vkBindAccelerationStructureMemoryKHR glad_vkBindAccelerationStructureMemoryKHR = NULL; -#endif PFN_vkBindAccelerationStructureMemoryNV glad_vkBindAccelerationStructureMemoryNV = NULL; PFN_vkBindBufferMemory glad_vkBindBufferMemory = NULL; PFN_vkBindBufferMemory2 glad_vkBindBufferMemory2 = NULL; @@ -311,59 +560,104 @@ PFN_vkBindBufferMemory2KHR glad_vkBindBufferMemory2KHR = NULL; PFN_vkBindImageMemory glad_vkBindImageMemory = NULL; PFN_vkBindImageMemory2 glad_vkBindImageMemory2 = NULL; PFN_vkBindImageMemory2KHR glad_vkBindImageMemory2KHR = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -PFN_vkBuildAccelerationStructureKHR glad_vkBuildAccelerationStructureKHR = NULL; -#endif +PFN_vkBindOpticalFlowSessionImageNV glad_vkBindOpticalFlowSessionImageNV = NULL; +PFN_vkBuildAccelerationStructuresKHR glad_vkBuildAccelerationStructuresKHR = NULL; +PFN_vkBuildMicromapsEXT glad_vkBuildMicromapsEXT = NULL; PFN_vkCmdBeginConditionalRenderingEXT glad_vkCmdBeginConditionalRenderingEXT = NULL; PFN_vkCmdBeginDebugUtilsLabelEXT glad_vkCmdBeginDebugUtilsLabelEXT = NULL; +PFN_vkCmdBeginPerTileExecutionQCOM glad_vkCmdBeginPerTileExecutionQCOM = NULL; PFN_vkCmdBeginQuery glad_vkCmdBeginQuery = NULL; PFN_vkCmdBeginQueryIndexedEXT glad_vkCmdBeginQueryIndexedEXT = NULL; PFN_vkCmdBeginRenderPass glad_vkCmdBeginRenderPass = NULL; PFN_vkCmdBeginRenderPass2 glad_vkCmdBeginRenderPass2 = NULL; PFN_vkCmdBeginRenderPass2KHR glad_vkCmdBeginRenderPass2KHR = NULL; +PFN_vkCmdBeginRendering glad_vkCmdBeginRendering = NULL; +PFN_vkCmdBeginRenderingKHR glad_vkCmdBeginRenderingKHR = NULL; PFN_vkCmdBeginTransformFeedbackEXT glad_vkCmdBeginTransformFeedbackEXT = NULL; +PFN_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT glad_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT = NULL; +PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT glad_vkCmdBindDescriptorBufferEmbeddedSamplersEXT = NULL; +PFN_vkCmdBindDescriptorBuffersEXT glad_vkCmdBindDescriptorBuffersEXT = NULL; PFN_vkCmdBindDescriptorSets glad_vkCmdBindDescriptorSets = NULL; +PFN_vkCmdBindDescriptorSets2 glad_vkCmdBindDescriptorSets2 = NULL; +PFN_vkCmdBindDescriptorSets2KHR glad_vkCmdBindDescriptorSets2KHR = NULL; PFN_vkCmdBindIndexBuffer glad_vkCmdBindIndexBuffer = NULL; +PFN_vkCmdBindIndexBuffer2 glad_vkCmdBindIndexBuffer2 = NULL; +PFN_vkCmdBindIndexBuffer2KHR glad_vkCmdBindIndexBuffer2KHR = NULL; +PFN_vkCmdBindInvocationMaskHUAWEI glad_vkCmdBindInvocationMaskHUAWEI = NULL; PFN_vkCmdBindPipeline glad_vkCmdBindPipeline = NULL; PFN_vkCmdBindPipelineShaderGroupNV glad_vkCmdBindPipelineShaderGroupNV = NULL; +PFN_vkCmdBindShadersEXT glad_vkCmdBindShadersEXT = NULL; PFN_vkCmdBindShadingRateImageNV glad_vkCmdBindShadingRateImageNV = NULL; +PFN_vkCmdBindTileMemoryQCOM glad_vkCmdBindTileMemoryQCOM = NULL; PFN_vkCmdBindTransformFeedbackBuffersEXT glad_vkCmdBindTransformFeedbackBuffersEXT = NULL; PFN_vkCmdBindVertexBuffers glad_vkCmdBindVertexBuffers = NULL; +PFN_vkCmdBindVertexBuffers2 glad_vkCmdBindVertexBuffers2 = NULL; PFN_vkCmdBindVertexBuffers2EXT glad_vkCmdBindVertexBuffers2EXT = NULL; PFN_vkCmdBlitImage glad_vkCmdBlitImage = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -PFN_vkCmdBuildAccelerationStructureIndirectKHR glad_vkCmdBuildAccelerationStructureIndirectKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -PFN_vkCmdBuildAccelerationStructureKHR glad_vkCmdBuildAccelerationStructureKHR = NULL; -#endif +PFN_vkCmdBlitImage2 glad_vkCmdBlitImage2 = NULL; +PFN_vkCmdBlitImage2KHR glad_vkCmdBlitImage2KHR = NULL; PFN_vkCmdBuildAccelerationStructureNV glad_vkCmdBuildAccelerationStructureNV = NULL; +PFN_vkCmdBuildAccelerationStructuresIndirectKHR glad_vkCmdBuildAccelerationStructuresIndirectKHR = NULL; +PFN_vkCmdBuildAccelerationStructuresKHR glad_vkCmdBuildAccelerationStructuresKHR = NULL; +PFN_vkCmdBuildClusterAccelerationStructureIndirectNV glad_vkCmdBuildClusterAccelerationStructureIndirectNV = NULL; +PFN_vkCmdBuildMicromapsEXT glad_vkCmdBuildMicromapsEXT = NULL; +PFN_vkCmdBuildPartitionedAccelerationStructuresNV glad_vkCmdBuildPartitionedAccelerationStructuresNV = NULL; PFN_vkCmdClearAttachments glad_vkCmdClearAttachments = NULL; PFN_vkCmdClearColorImage glad_vkCmdClearColorImage = NULL; PFN_vkCmdClearDepthStencilImage glad_vkCmdClearDepthStencilImage = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdConvertCooperativeVectorMatrixNV glad_vkCmdConvertCooperativeVectorMatrixNV = NULL; PFN_vkCmdCopyAccelerationStructureKHR glad_vkCmdCopyAccelerationStructureKHR = NULL; -#endif PFN_vkCmdCopyAccelerationStructureNV glad_vkCmdCopyAccelerationStructureNV = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkCmdCopyAccelerationStructureToMemoryKHR glad_vkCmdCopyAccelerationStructureToMemoryKHR = NULL; -#endif PFN_vkCmdCopyBuffer glad_vkCmdCopyBuffer = NULL; +PFN_vkCmdCopyBuffer2 glad_vkCmdCopyBuffer2 = NULL; +PFN_vkCmdCopyBuffer2KHR glad_vkCmdCopyBuffer2KHR = NULL; PFN_vkCmdCopyBufferToImage glad_vkCmdCopyBufferToImage = NULL; +PFN_vkCmdCopyBufferToImage2 glad_vkCmdCopyBufferToImage2 = NULL; +PFN_vkCmdCopyBufferToImage2KHR glad_vkCmdCopyBufferToImage2KHR = NULL; PFN_vkCmdCopyImage glad_vkCmdCopyImage = NULL; +PFN_vkCmdCopyImage2 glad_vkCmdCopyImage2 = NULL; +PFN_vkCmdCopyImage2KHR glad_vkCmdCopyImage2KHR = NULL; PFN_vkCmdCopyImageToBuffer glad_vkCmdCopyImageToBuffer = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdCopyImageToBuffer2 glad_vkCmdCopyImageToBuffer2 = NULL; +PFN_vkCmdCopyImageToBuffer2KHR glad_vkCmdCopyImageToBuffer2KHR = NULL; +PFN_vkCmdCopyMemoryIndirectNV glad_vkCmdCopyMemoryIndirectNV = NULL; PFN_vkCmdCopyMemoryToAccelerationStructureKHR glad_vkCmdCopyMemoryToAccelerationStructureKHR = NULL; -#endif +PFN_vkCmdCopyMemoryToImageIndirectNV glad_vkCmdCopyMemoryToImageIndirectNV = NULL; +PFN_vkCmdCopyMemoryToMicromapEXT glad_vkCmdCopyMemoryToMicromapEXT = NULL; +PFN_vkCmdCopyMicromapEXT glad_vkCmdCopyMicromapEXT = NULL; +PFN_vkCmdCopyMicromapToMemoryEXT glad_vkCmdCopyMicromapToMemoryEXT = NULL; PFN_vkCmdCopyQueryPoolResults glad_vkCmdCopyQueryPoolResults = NULL; +PFN_vkCmdCuLaunchKernelNVX glad_vkCmdCuLaunchKernelNVX = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdCudaLaunchKernelNV glad_vkCmdCudaLaunchKernelNV = NULL; + +#endif PFN_vkCmdDebugMarkerBeginEXT glad_vkCmdDebugMarkerBeginEXT = NULL; PFN_vkCmdDebugMarkerEndEXT glad_vkCmdDebugMarkerEndEXT = NULL; PFN_vkCmdDebugMarkerInsertEXT glad_vkCmdDebugMarkerInsertEXT = NULL; +PFN_vkCmdDecompressMemoryIndirectCountNV glad_vkCmdDecompressMemoryIndirectCountNV = NULL; +PFN_vkCmdDecompressMemoryNV glad_vkCmdDecompressMemoryNV = NULL; PFN_vkCmdDispatch glad_vkCmdDispatch = NULL; PFN_vkCmdDispatchBase glad_vkCmdDispatchBase = NULL; PFN_vkCmdDispatchBaseKHR glad_vkCmdDispatchBaseKHR = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdDispatchGraphAMDX glad_vkCmdDispatchGraphAMDX = NULL; + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdDispatchGraphIndirectAMDX glad_vkCmdDispatchGraphIndirectAMDX = NULL; + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdDispatchGraphIndirectCountAMDX glad_vkCmdDispatchGraphIndirectCountAMDX = NULL; + +#endif PFN_vkCmdDispatchIndirect glad_vkCmdDispatchIndirect = NULL; +PFN_vkCmdDispatchTileQCOM glad_vkCmdDispatchTileQCOM = NULL; PFN_vkCmdDraw glad_vkCmdDraw = NULL; +PFN_vkCmdDrawClusterHUAWEI glad_vkCmdDrawClusterHUAWEI = NULL; +PFN_vkCmdDrawClusterIndirectHUAWEI glad_vkCmdDrawClusterIndirectHUAWEI = NULL; PFN_vkCmdDrawIndexed glad_vkCmdDrawIndexed = NULL; PFN_vkCmdDrawIndexedIndirect glad_vkCmdDrawIndexedIndirect = NULL; PFN_vkCmdDrawIndexedIndirectCount glad_vkCmdDrawIndexedIndirectCount = NULL; @@ -374,107 +668,226 @@ PFN_vkCmdDrawIndirectByteCountEXT glad_vkCmdDrawIndirectByteCountEXT = NULL; PFN_vkCmdDrawIndirectCount glad_vkCmdDrawIndirectCount = NULL; PFN_vkCmdDrawIndirectCountAMD glad_vkCmdDrawIndirectCountAMD = NULL; PFN_vkCmdDrawIndirectCountKHR glad_vkCmdDrawIndirectCountKHR = NULL; +PFN_vkCmdDrawMeshTasksEXT glad_vkCmdDrawMeshTasksEXT = NULL; +PFN_vkCmdDrawMeshTasksIndirectCountEXT glad_vkCmdDrawMeshTasksIndirectCountEXT = NULL; PFN_vkCmdDrawMeshTasksIndirectCountNV glad_vkCmdDrawMeshTasksIndirectCountNV = NULL; +PFN_vkCmdDrawMeshTasksIndirectEXT glad_vkCmdDrawMeshTasksIndirectEXT = NULL; PFN_vkCmdDrawMeshTasksIndirectNV glad_vkCmdDrawMeshTasksIndirectNV = NULL; PFN_vkCmdDrawMeshTasksNV glad_vkCmdDrawMeshTasksNV = NULL; +PFN_vkCmdDrawMultiEXT glad_vkCmdDrawMultiEXT = NULL; +PFN_vkCmdDrawMultiIndexedEXT glad_vkCmdDrawMultiIndexedEXT = NULL; PFN_vkCmdEndConditionalRenderingEXT glad_vkCmdEndConditionalRenderingEXT = NULL; PFN_vkCmdEndDebugUtilsLabelEXT glad_vkCmdEndDebugUtilsLabelEXT = NULL; +PFN_vkCmdEndPerTileExecutionQCOM glad_vkCmdEndPerTileExecutionQCOM = NULL; PFN_vkCmdEndQuery glad_vkCmdEndQuery = NULL; PFN_vkCmdEndQueryIndexedEXT glad_vkCmdEndQueryIndexedEXT = NULL; PFN_vkCmdEndRenderPass glad_vkCmdEndRenderPass = NULL; PFN_vkCmdEndRenderPass2 glad_vkCmdEndRenderPass2 = NULL; PFN_vkCmdEndRenderPass2KHR glad_vkCmdEndRenderPass2KHR = NULL; +PFN_vkCmdEndRendering glad_vkCmdEndRendering = NULL; +PFN_vkCmdEndRendering2EXT glad_vkCmdEndRendering2EXT = NULL; +PFN_vkCmdEndRenderingKHR glad_vkCmdEndRenderingKHR = NULL; PFN_vkCmdEndTransformFeedbackEXT glad_vkCmdEndTransformFeedbackEXT = NULL; PFN_vkCmdExecuteCommands glad_vkCmdExecuteCommands = NULL; +PFN_vkCmdExecuteGeneratedCommandsEXT glad_vkCmdExecuteGeneratedCommandsEXT = NULL; PFN_vkCmdExecuteGeneratedCommandsNV glad_vkCmdExecuteGeneratedCommandsNV = NULL; PFN_vkCmdFillBuffer glad_vkCmdFillBuffer = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdInitializeGraphScratchMemoryAMDX glad_vkCmdInitializeGraphScratchMemoryAMDX = NULL; + +#endif PFN_vkCmdInsertDebugUtilsLabelEXT glad_vkCmdInsertDebugUtilsLabelEXT = NULL; PFN_vkCmdNextSubpass glad_vkCmdNextSubpass = NULL; PFN_vkCmdNextSubpass2 glad_vkCmdNextSubpass2 = NULL; PFN_vkCmdNextSubpass2KHR glad_vkCmdNextSubpass2KHR = NULL; +PFN_vkCmdOpticalFlowExecuteNV glad_vkCmdOpticalFlowExecuteNV = NULL; PFN_vkCmdPipelineBarrier glad_vkCmdPipelineBarrier = NULL; +PFN_vkCmdPipelineBarrier2 glad_vkCmdPipelineBarrier2 = NULL; +PFN_vkCmdPipelineBarrier2KHR glad_vkCmdPipelineBarrier2KHR = NULL; +PFN_vkCmdPreprocessGeneratedCommandsEXT glad_vkCmdPreprocessGeneratedCommandsEXT = NULL; PFN_vkCmdPreprocessGeneratedCommandsNV glad_vkCmdPreprocessGeneratedCommandsNV = NULL; PFN_vkCmdPushConstants glad_vkCmdPushConstants = NULL; +PFN_vkCmdPushConstants2 glad_vkCmdPushConstants2 = NULL; +PFN_vkCmdPushConstants2KHR glad_vkCmdPushConstants2KHR = NULL; +PFN_vkCmdPushDescriptorSet glad_vkCmdPushDescriptorSet = NULL; +PFN_vkCmdPushDescriptorSet2 glad_vkCmdPushDescriptorSet2 = NULL; +PFN_vkCmdPushDescriptorSet2KHR glad_vkCmdPushDescriptorSet2KHR = NULL; PFN_vkCmdPushDescriptorSetKHR glad_vkCmdPushDescriptorSetKHR = NULL; +PFN_vkCmdPushDescriptorSetWithTemplate glad_vkCmdPushDescriptorSetWithTemplate = NULL; +PFN_vkCmdPushDescriptorSetWithTemplate2 glad_vkCmdPushDescriptorSetWithTemplate2 = NULL; +PFN_vkCmdPushDescriptorSetWithTemplate2KHR glad_vkCmdPushDescriptorSetWithTemplate2KHR = NULL; PFN_vkCmdPushDescriptorSetWithTemplateKHR glad_vkCmdPushDescriptorSetWithTemplateKHR = NULL; PFN_vkCmdResetEvent glad_vkCmdResetEvent = NULL; +PFN_vkCmdResetEvent2 glad_vkCmdResetEvent2 = NULL; +PFN_vkCmdResetEvent2KHR glad_vkCmdResetEvent2KHR = NULL; PFN_vkCmdResetQueryPool glad_vkCmdResetQueryPool = NULL; PFN_vkCmdResolveImage glad_vkCmdResolveImage = NULL; +PFN_vkCmdResolveImage2 glad_vkCmdResolveImage2 = NULL; +PFN_vkCmdResolveImage2KHR glad_vkCmdResolveImage2KHR = NULL; +PFN_vkCmdSetAlphaToCoverageEnableEXT glad_vkCmdSetAlphaToCoverageEnableEXT = NULL; +PFN_vkCmdSetAlphaToOneEnableEXT glad_vkCmdSetAlphaToOneEnableEXT = NULL; +PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT glad_vkCmdSetAttachmentFeedbackLoopEnableEXT = NULL; PFN_vkCmdSetBlendConstants glad_vkCmdSetBlendConstants = NULL; PFN_vkCmdSetCheckpointNV glad_vkCmdSetCheckpointNV = NULL; PFN_vkCmdSetCoarseSampleOrderNV glad_vkCmdSetCoarseSampleOrderNV = NULL; +PFN_vkCmdSetColorBlendAdvancedEXT glad_vkCmdSetColorBlendAdvancedEXT = NULL; +PFN_vkCmdSetColorBlendEnableEXT glad_vkCmdSetColorBlendEnableEXT = NULL; +PFN_vkCmdSetColorBlendEquationEXT glad_vkCmdSetColorBlendEquationEXT = NULL; +PFN_vkCmdSetColorWriteEnableEXT glad_vkCmdSetColorWriteEnableEXT = NULL; +PFN_vkCmdSetColorWriteMaskEXT glad_vkCmdSetColorWriteMaskEXT = NULL; +PFN_vkCmdSetConservativeRasterizationModeEXT glad_vkCmdSetConservativeRasterizationModeEXT = NULL; +PFN_vkCmdSetCoverageModulationModeNV glad_vkCmdSetCoverageModulationModeNV = NULL; +PFN_vkCmdSetCoverageModulationTableEnableNV glad_vkCmdSetCoverageModulationTableEnableNV = NULL; +PFN_vkCmdSetCoverageModulationTableNV glad_vkCmdSetCoverageModulationTableNV = NULL; +PFN_vkCmdSetCoverageReductionModeNV glad_vkCmdSetCoverageReductionModeNV = NULL; +PFN_vkCmdSetCoverageToColorEnableNV glad_vkCmdSetCoverageToColorEnableNV = NULL; +PFN_vkCmdSetCoverageToColorLocationNV glad_vkCmdSetCoverageToColorLocationNV = NULL; +PFN_vkCmdSetCullMode glad_vkCmdSetCullMode = NULL; PFN_vkCmdSetCullModeEXT glad_vkCmdSetCullModeEXT = NULL; PFN_vkCmdSetDepthBias glad_vkCmdSetDepthBias = NULL; +PFN_vkCmdSetDepthBias2EXT glad_vkCmdSetDepthBias2EXT = NULL; +PFN_vkCmdSetDepthBiasEnable glad_vkCmdSetDepthBiasEnable = NULL; +PFN_vkCmdSetDepthBiasEnableEXT glad_vkCmdSetDepthBiasEnableEXT = NULL; PFN_vkCmdSetDepthBounds glad_vkCmdSetDepthBounds = NULL; +PFN_vkCmdSetDepthBoundsTestEnable glad_vkCmdSetDepthBoundsTestEnable = NULL; PFN_vkCmdSetDepthBoundsTestEnableEXT glad_vkCmdSetDepthBoundsTestEnableEXT = NULL; +PFN_vkCmdSetDepthClampEnableEXT glad_vkCmdSetDepthClampEnableEXT = NULL; +PFN_vkCmdSetDepthClampRangeEXT glad_vkCmdSetDepthClampRangeEXT = NULL; +PFN_vkCmdSetDepthClipEnableEXT glad_vkCmdSetDepthClipEnableEXT = NULL; +PFN_vkCmdSetDepthClipNegativeOneToOneEXT glad_vkCmdSetDepthClipNegativeOneToOneEXT = NULL; +PFN_vkCmdSetDepthCompareOp glad_vkCmdSetDepthCompareOp = NULL; PFN_vkCmdSetDepthCompareOpEXT glad_vkCmdSetDepthCompareOpEXT = NULL; +PFN_vkCmdSetDepthTestEnable glad_vkCmdSetDepthTestEnable = NULL; PFN_vkCmdSetDepthTestEnableEXT glad_vkCmdSetDepthTestEnableEXT = NULL; +PFN_vkCmdSetDepthWriteEnable glad_vkCmdSetDepthWriteEnable = NULL; PFN_vkCmdSetDepthWriteEnableEXT glad_vkCmdSetDepthWriteEnableEXT = NULL; +PFN_vkCmdSetDescriptorBufferOffsets2EXT glad_vkCmdSetDescriptorBufferOffsets2EXT = NULL; +PFN_vkCmdSetDescriptorBufferOffsetsEXT glad_vkCmdSetDescriptorBufferOffsetsEXT = NULL; PFN_vkCmdSetDeviceMask glad_vkCmdSetDeviceMask = NULL; PFN_vkCmdSetDeviceMaskKHR glad_vkCmdSetDeviceMaskKHR = NULL; PFN_vkCmdSetDiscardRectangleEXT glad_vkCmdSetDiscardRectangleEXT = NULL; +PFN_vkCmdSetDiscardRectangleEnableEXT glad_vkCmdSetDiscardRectangleEnableEXT = NULL; +PFN_vkCmdSetDiscardRectangleModeEXT glad_vkCmdSetDiscardRectangleModeEXT = NULL; PFN_vkCmdSetEvent glad_vkCmdSetEvent = NULL; +PFN_vkCmdSetEvent2 glad_vkCmdSetEvent2 = NULL; +PFN_vkCmdSetEvent2KHR glad_vkCmdSetEvent2KHR = NULL; +PFN_vkCmdSetExclusiveScissorEnableNV glad_vkCmdSetExclusiveScissorEnableNV = NULL; PFN_vkCmdSetExclusiveScissorNV glad_vkCmdSetExclusiveScissorNV = NULL; +PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT glad_vkCmdSetExtraPrimitiveOverestimationSizeEXT = NULL; +PFN_vkCmdSetFragmentShadingRateEnumNV glad_vkCmdSetFragmentShadingRateEnumNV = NULL; +PFN_vkCmdSetFragmentShadingRateKHR glad_vkCmdSetFragmentShadingRateKHR = NULL; +PFN_vkCmdSetFrontFace glad_vkCmdSetFrontFace = NULL; PFN_vkCmdSetFrontFaceEXT glad_vkCmdSetFrontFaceEXT = NULL; +PFN_vkCmdSetLineRasterizationModeEXT glad_vkCmdSetLineRasterizationModeEXT = NULL; +PFN_vkCmdSetLineStipple glad_vkCmdSetLineStipple = NULL; PFN_vkCmdSetLineStippleEXT glad_vkCmdSetLineStippleEXT = NULL; +PFN_vkCmdSetLineStippleEnableEXT glad_vkCmdSetLineStippleEnableEXT = NULL; +PFN_vkCmdSetLineStippleKHR glad_vkCmdSetLineStippleKHR = NULL; PFN_vkCmdSetLineWidth glad_vkCmdSetLineWidth = NULL; +PFN_vkCmdSetLogicOpEXT glad_vkCmdSetLogicOpEXT = NULL; +PFN_vkCmdSetLogicOpEnableEXT glad_vkCmdSetLogicOpEnableEXT = NULL; +PFN_vkCmdSetPatchControlPointsEXT glad_vkCmdSetPatchControlPointsEXT = NULL; PFN_vkCmdSetPerformanceMarkerINTEL glad_vkCmdSetPerformanceMarkerINTEL = NULL; PFN_vkCmdSetPerformanceOverrideINTEL glad_vkCmdSetPerformanceOverrideINTEL = NULL; PFN_vkCmdSetPerformanceStreamMarkerINTEL glad_vkCmdSetPerformanceStreamMarkerINTEL = NULL; +PFN_vkCmdSetPolygonModeEXT glad_vkCmdSetPolygonModeEXT = NULL; +PFN_vkCmdSetPrimitiveRestartEnable glad_vkCmdSetPrimitiveRestartEnable = NULL; +PFN_vkCmdSetPrimitiveRestartEnableEXT glad_vkCmdSetPrimitiveRestartEnableEXT = NULL; +PFN_vkCmdSetPrimitiveTopology glad_vkCmdSetPrimitiveTopology = NULL; PFN_vkCmdSetPrimitiveTopologyEXT glad_vkCmdSetPrimitiveTopologyEXT = NULL; +PFN_vkCmdSetProvokingVertexModeEXT glad_vkCmdSetProvokingVertexModeEXT = NULL; +PFN_vkCmdSetRasterizationSamplesEXT glad_vkCmdSetRasterizationSamplesEXT = NULL; +PFN_vkCmdSetRasterizationStreamEXT glad_vkCmdSetRasterizationStreamEXT = NULL; +PFN_vkCmdSetRasterizerDiscardEnable glad_vkCmdSetRasterizerDiscardEnable = NULL; +PFN_vkCmdSetRasterizerDiscardEnableEXT glad_vkCmdSetRasterizerDiscardEnableEXT = NULL; +PFN_vkCmdSetRayTracingPipelineStackSizeKHR glad_vkCmdSetRayTracingPipelineStackSizeKHR = NULL; +PFN_vkCmdSetRenderingAttachmentLocations glad_vkCmdSetRenderingAttachmentLocations = NULL; +PFN_vkCmdSetRenderingAttachmentLocationsKHR glad_vkCmdSetRenderingAttachmentLocationsKHR = NULL; +PFN_vkCmdSetRenderingInputAttachmentIndices glad_vkCmdSetRenderingInputAttachmentIndices = NULL; +PFN_vkCmdSetRenderingInputAttachmentIndicesKHR glad_vkCmdSetRenderingInputAttachmentIndicesKHR = NULL; +PFN_vkCmdSetRepresentativeFragmentTestEnableNV glad_vkCmdSetRepresentativeFragmentTestEnableNV = NULL; PFN_vkCmdSetSampleLocationsEXT glad_vkCmdSetSampleLocationsEXT = NULL; +PFN_vkCmdSetSampleLocationsEnableEXT glad_vkCmdSetSampleLocationsEnableEXT = NULL; +PFN_vkCmdSetSampleMaskEXT glad_vkCmdSetSampleMaskEXT = NULL; PFN_vkCmdSetScissor glad_vkCmdSetScissor = NULL; +PFN_vkCmdSetScissorWithCount glad_vkCmdSetScissorWithCount = NULL; PFN_vkCmdSetScissorWithCountEXT glad_vkCmdSetScissorWithCountEXT = NULL; +PFN_vkCmdSetShadingRateImageEnableNV glad_vkCmdSetShadingRateImageEnableNV = NULL; PFN_vkCmdSetStencilCompareMask glad_vkCmdSetStencilCompareMask = NULL; +PFN_vkCmdSetStencilOp glad_vkCmdSetStencilOp = NULL; PFN_vkCmdSetStencilOpEXT glad_vkCmdSetStencilOpEXT = NULL; PFN_vkCmdSetStencilReference glad_vkCmdSetStencilReference = NULL; +PFN_vkCmdSetStencilTestEnable glad_vkCmdSetStencilTestEnable = NULL; PFN_vkCmdSetStencilTestEnableEXT glad_vkCmdSetStencilTestEnableEXT = NULL; PFN_vkCmdSetStencilWriteMask glad_vkCmdSetStencilWriteMask = NULL; +PFN_vkCmdSetTessellationDomainOriginEXT glad_vkCmdSetTessellationDomainOriginEXT = NULL; +PFN_vkCmdSetVertexInputEXT glad_vkCmdSetVertexInputEXT = NULL; PFN_vkCmdSetViewport glad_vkCmdSetViewport = NULL; PFN_vkCmdSetViewportShadingRatePaletteNV glad_vkCmdSetViewportShadingRatePaletteNV = NULL; +PFN_vkCmdSetViewportSwizzleNV glad_vkCmdSetViewportSwizzleNV = NULL; +PFN_vkCmdSetViewportWScalingEnableNV glad_vkCmdSetViewportWScalingEnableNV = NULL; PFN_vkCmdSetViewportWScalingNV glad_vkCmdSetViewportWScalingNV = NULL; +PFN_vkCmdSetViewportWithCount glad_vkCmdSetViewportWithCount = NULL; PFN_vkCmdSetViewportWithCountEXT glad_vkCmdSetViewportWithCountEXT = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdSubpassShadingHUAWEI glad_vkCmdSubpassShadingHUAWEI = NULL; +PFN_vkCmdTraceRaysIndirect2KHR glad_vkCmdTraceRaysIndirect2KHR = NULL; PFN_vkCmdTraceRaysIndirectKHR glad_vkCmdTraceRaysIndirectKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkCmdTraceRaysKHR glad_vkCmdTraceRaysKHR = NULL; -#endif PFN_vkCmdTraceRaysNV glad_vkCmdTraceRaysNV = NULL; PFN_vkCmdUpdateBuffer glad_vkCmdUpdateBuffer = NULL; +PFN_vkCmdUpdatePipelineIndirectBufferNV glad_vkCmdUpdatePipelineIndirectBufferNV = NULL; PFN_vkCmdWaitEvents glad_vkCmdWaitEvents = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdWaitEvents2 glad_vkCmdWaitEvents2 = NULL; +PFN_vkCmdWaitEvents2KHR glad_vkCmdWaitEvents2KHR = NULL; PFN_vkCmdWriteAccelerationStructuresPropertiesKHR glad_vkCmdWriteAccelerationStructuresPropertiesKHR = NULL; -#endif PFN_vkCmdWriteAccelerationStructuresPropertiesNV glad_vkCmdWriteAccelerationStructuresPropertiesNV = NULL; +PFN_vkCmdWriteBufferMarker2AMD glad_vkCmdWriteBufferMarker2AMD = NULL; PFN_vkCmdWriteBufferMarkerAMD glad_vkCmdWriteBufferMarkerAMD = NULL; +PFN_vkCmdWriteMicromapsPropertiesEXT glad_vkCmdWriteMicromapsPropertiesEXT = NULL; PFN_vkCmdWriteTimestamp glad_vkCmdWriteTimestamp = NULL; +PFN_vkCmdWriteTimestamp2 glad_vkCmdWriteTimestamp2 = NULL; +PFN_vkCmdWriteTimestamp2KHR glad_vkCmdWriteTimestamp2KHR = NULL; PFN_vkCompileDeferredNV glad_vkCompileDeferredNV = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkConvertCooperativeVectorMatrixNV glad_vkConvertCooperativeVectorMatrixNV = NULL; PFN_vkCopyAccelerationStructureKHR glad_vkCopyAccelerationStructureKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkCopyAccelerationStructureToMemoryKHR glad_vkCopyAccelerationStructureToMemoryKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCopyImageToImage glad_vkCopyImageToImage = NULL; +PFN_vkCopyImageToImageEXT glad_vkCopyImageToImageEXT = NULL; +PFN_vkCopyImageToMemory glad_vkCopyImageToMemory = NULL; +PFN_vkCopyImageToMemoryEXT glad_vkCopyImageToMemoryEXT = NULL; PFN_vkCopyMemoryToAccelerationStructureKHR glad_vkCopyMemoryToAccelerationStructureKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCopyMemoryToImage glad_vkCopyMemoryToImage = NULL; +PFN_vkCopyMemoryToImageEXT glad_vkCopyMemoryToImageEXT = NULL; +PFN_vkCopyMemoryToMicromapEXT glad_vkCopyMemoryToMicromapEXT = NULL; +PFN_vkCopyMicromapEXT glad_vkCopyMicromapEXT = NULL; +PFN_vkCopyMicromapToMemoryEXT glad_vkCopyMicromapToMemoryEXT = NULL; PFN_vkCreateAccelerationStructureKHR glad_vkCreateAccelerationStructureKHR = NULL; -#endif PFN_vkCreateAccelerationStructureNV glad_vkCreateAccelerationStructureNV = NULL; #if defined(VK_USE_PLATFORM_ANDROID_KHR) PFN_vkCreateAndroidSurfaceKHR glad_vkCreateAndroidSurfaceKHR = NULL; + #endif PFN_vkCreateBuffer glad_vkCreateBuffer = NULL; +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkCreateBufferCollectionFUCHSIA glad_vkCreateBufferCollectionFUCHSIA = NULL; + +#endif PFN_vkCreateBufferView glad_vkCreateBufferView = NULL; PFN_vkCreateCommandPool glad_vkCreateCommandPool = NULL; PFN_vkCreateComputePipelines glad_vkCreateComputePipelines = NULL; +PFN_vkCreateCuFunctionNVX glad_vkCreateCuFunctionNVX = NULL; +PFN_vkCreateCuModuleNVX glad_vkCreateCuModuleNVX = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCreateCudaFunctionNV glad_vkCreateCudaFunctionNV = NULL; + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCreateCudaModuleNV glad_vkCreateCudaModuleNV = NULL; + +#endif PFN_vkCreateDebugReportCallbackEXT glad_vkCreateDebugReportCallbackEXT = NULL; PFN_vkCreateDebugUtilsMessengerEXT glad_vkCreateDebugUtilsMessengerEXT = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkCreateDeferredOperationKHR glad_vkCreateDeferredOperationKHR = NULL; -#endif PFN_vkCreateDescriptorPool glad_vkCreateDescriptorPool = NULL; PFN_vkCreateDescriptorSetLayout glad_vkCreateDescriptorSetLayout = NULL; PFN_vkCreateDescriptorUpdateTemplate glad_vkCreateDescriptorUpdateTemplate = NULL; @@ -482,37 +895,51 @@ PFN_vkCreateDescriptorUpdateTemplateKHR glad_vkCreateDescriptorUpdateTemplateKHR PFN_vkCreateDevice glad_vkCreateDevice = NULL; #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) PFN_vkCreateDirectFBSurfaceEXT glad_vkCreateDirectFBSurfaceEXT = NULL; + #endif PFN_vkCreateDisplayModeKHR glad_vkCreateDisplayModeKHR = NULL; PFN_vkCreateDisplayPlaneSurfaceKHR glad_vkCreateDisplayPlaneSurfaceKHR = NULL; PFN_vkCreateEvent glad_vkCreateEvent = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCreateExecutionGraphPipelinesAMDX glad_vkCreateExecutionGraphPipelinesAMDX = NULL; + +#endif +PFN_vkCreateExternalComputeQueueNV glad_vkCreateExternalComputeQueueNV = NULL; PFN_vkCreateFence glad_vkCreateFence = NULL; PFN_vkCreateFramebuffer glad_vkCreateFramebuffer = NULL; PFN_vkCreateGraphicsPipelines glad_vkCreateGraphicsPipelines = NULL; PFN_vkCreateHeadlessSurfaceEXT glad_vkCreateHeadlessSurfaceEXT = NULL; #if defined(VK_USE_PLATFORM_IOS_MVK) PFN_vkCreateIOSSurfaceMVK glad_vkCreateIOSSurfaceMVK = NULL; + #endif PFN_vkCreateImage glad_vkCreateImage = NULL; #if defined(VK_USE_PLATFORM_FUCHSIA) PFN_vkCreateImagePipeSurfaceFUCHSIA glad_vkCreateImagePipeSurfaceFUCHSIA = NULL; + #endif PFN_vkCreateImageView glad_vkCreateImageView = NULL; +PFN_vkCreateIndirectCommandsLayoutEXT glad_vkCreateIndirectCommandsLayoutEXT = NULL; PFN_vkCreateIndirectCommandsLayoutNV glad_vkCreateIndirectCommandsLayoutNV = NULL; +PFN_vkCreateIndirectExecutionSetEXT glad_vkCreateIndirectExecutionSetEXT = NULL; PFN_vkCreateInstance glad_vkCreateInstance = NULL; #if defined(VK_USE_PLATFORM_MACOS_MVK) PFN_vkCreateMacOSSurfaceMVK glad_vkCreateMacOSSurfaceMVK = NULL; + #endif #if defined(VK_USE_PLATFORM_METAL_EXT) PFN_vkCreateMetalSurfaceEXT glad_vkCreateMetalSurfaceEXT = NULL; + #endif +PFN_vkCreateMicromapEXT glad_vkCreateMicromapEXT = NULL; +PFN_vkCreateOpticalFlowSessionNV glad_vkCreateOpticalFlowSessionNV = NULL; +PFN_vkCreatePipelineBinariesKHR glad_vkCreatePipelineBinariesKHR = NULL; PFN_vkCreatePipelineCache glad_vkCreatePipelineCache = NULL; PFN_vkCreatePipelineLayout glad_vkCreatePipelineLayout = NULL; +PFN_vkCreatePrivateDataSlot glad_vkCreatePrivateDataSlot = NULL; PFN_vkCreatePrivateDataSlotEXT glad_vkCreatePrivateDataSlotEXT = NULL; PFN_vkCreateQueryPool glad_vkCreateQueryPool = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkCreateRayTracingPipelinesKHR glad_vkCreateRayTracingPipelinesKHR = NULL; -#endif PFN_vkCreateRayTracingPipelinesNV glad_vkCreateRayTracingPipelinesNV = NULL; PFN_vkCreateRenderPass glad_vkCreateRenderPass = NULL; PFN_vkCreateRenderPass2 glad_vkCreateRenderPass2 = NULL; @@ -520,62 +947,88 @@ PFN_vkCreateRenderPass2KHR glad_vkCreateRenderPass2KHR = NULL; PFN_vkCreateSampler glad_vkCreateSampler = NULL; PFN_vkCreateSamplerYcbcrConversion glad_vkCreateSamplerYcbcrConversion = NULL; PFN_vkCreateSamplerYcbcrConversionKHR glad_vkCreateSamplerYcbcrConversionKHR = NULL; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +PFN_vkCreateScreenSurfaceQNX glad_vkCreateScreenSurfaceQNX = NULL; + +#endif PFN_vkCreateSemaphore glad_vkCreateSemaphore = NULL; PFN_vkCreateShaderModule glad_vkCreateShaderModule = NULL; +PFN_vkCreateShadersEXT glad_vkCreateShadersEXT = NULL; PFN_vkCreateSharedSwapchainsKHR glad_vkCreateSharedSwapchainsKHR = NULL; #if defined(VK_USE_PLATFORM_GGP) PFN_vkCreateStreamDescriptorSurfaceGGP glad_vkCreateStreamDescriptorSurfaceGGP = NULL; + #endif PFN_vkCreateSwapchainKHR glad_vkCreateSwapchainKHR = NULL; PFN_vkCreateValidationCacheEXT glad_vkCreateValidationCacheEXT = NULL; #if defined(VK_USE_PLATFORM_VI_NN) PFN_vkCreateViSurfaceNN glad_vkCreateViSurfaceNN = NULL; + #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) PFN_vkCreateWaylandSurfaceKHR glad_vkCreateWaylandSurfaceKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkCreateWin32SurfaceKHR glad_vkCreateWin32SurfaceKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) PFN_vkCreateXcbSurfaceKHR glad_vkCreateXcbSurfaceKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) PFN_vkCreateXlibSurfaceKHR glad_vkCreateXlibSurfaceKHR = NULL; + #endif PFN_vkDebugMarkerSetObjectNameEXT glad_vkDebugMarkerSetObjectNameEXT = NULL; PFN_vkDebugMarkerSetObjectTagEXT glad_vkDebugMarkerSetObjectTagEXT = NULL; PFN_vkDebugReportMessageEXT glad_vkDebugReportMessageEXT = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkDeferredOperationJoinKHR glad_vkDeferredOperationJoinKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkDestroyAccelerationStructureKHR glad_vkDestroyAccelerationStructureKHR = NULL; -#endif PFN_vkDestroyAccelerationStructureNV glad_vkDestroyAccelerationStructureNV = NULL; PFN_vkDestroyBuffer glad_vkDestroyBuffer = NULL; +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkDestroyBufferCollectionFUCHSIA glad_vkDestroyBufferCollectionFUCHSIA = NULL; + +#endif PFN_vkDestroyBufferView glad_vkDestroyBufferView = NULL; PFN_vkDestroyCommandPool glad_vkDestroyCommandPool = NULL; +PFN_vkDestroyCuFunctionNVX glad_vkDestroyCuFunctionNVX = NULL; +PFN_vkDestroyCuModuleNVX glad_vkDestroyCuModuleNVX = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkDestroyCudaFunctionNV glad_vkDestroyCudaFunctionNV = NULL; + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkDestroyCudaModuleNV glad_vkDestroyCudaModuleNV = NULL; + +#endif PFN_vkDestroyDebugReportCallbackEXT glad_vkDestroyDebugReportCallbackEXT = NULL; PFN_vkDestroyDebugUtilsMessengerEXT glad_vkDestroyDebugUtilsMessengerEXT = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkDestroyDeferredOperationKHR glad_vkDestroyDeferredOperationKHR = NULL; -#endif PFN_vkDestroyDescriptorPool glad_vkDestroyDescriptorPool = NULL; PFN_vkDestroyDescriptorSetLayout glad_vkDestroyDescriptorSetLayout = NULL; PFN_vkDestroyDescriptorUpdateTemplate glad_vkDestroyDescriptorUpdateTemplate = NULL; PFN_vkDestroyDescriptorUpdateTemplateKHR glad_vkDestroyDescriptorUpdateTemplateKHR = NULL; PFN_vkDestroyDevice glad_vkDestroyDevice = NULL; PFN_vkDestroyEvent glad_vkDestroyEvent = NULL; +PFN_vkDestroyExternalComputeQueueNV glad_vkDestroyExternalComputeQueueNV = NULL; PFN_vkDestroyFence glad_vkDestroyFence = NULL; PFN_vkDestroyFramebuffer glad_vkDestroyFramebuffer = NULL; PFN_vkDestroyImage glad_vkDestroyImage = NULL; PFN_vkDestroyImageView glad_vkDestroyImageView = NULL; +PFN_vkDestroyIndirectCommandsLayoutEXT glad_vkDestroyIndirectCommandsLayoutEXT = NULL; PFN_vkDestroyIndirectCommandsLayoutNV glad_vkDestroyIndirectCommandsLayoutNV = NULL; +PFN_vkDestroyIndirectExecutionSetEXT glad_vkDestroyIndirectExecutionSetEXT = NULL; PFN_vkDestroyInstance glad_vkDestroyInstance = NULL; +PFN_vkDestroyMicromapEXT glad_vkDestroyMicromapEXT = NULL; +PFN_vkDestroyOpticalFlowSessionNV glad_vkDestroyOpticalFlowSessionNV = NULL; PFN_vkDestroyPipeline glad_vkDestroyPipeline = NULL; +PFN_vkDestroyPipelineBinaryKHR glad_vkDestroyPipelineBinaryKHR = NULL; PFN_vkDestroyPipelineCache glad_vkDestroyPipelineCache = NULL; PFN_vkDestroyPipelineLayout glad_vkDestroyPipelineLayout = NULL; +PFN_vkDestroyPrivateDataSlot glad_vkDestroyPrivateDataSlot = NULL; PFN_vkDestroyPrivateDataSlotEXT glad_vkDestroyPrivateDataSlotEXT = NULL; PFN_vkDestroyQueryPool glad_vkDestroyQueryPool = NULL; PFN_vkDestroyRenderPass glad_vkDestroyRenderPass = NULL; @@ -583,6 +1036,7 @@ PFN_vkDestroySampler glad_vkDestroySampler = NULL; PFN_vkDestroySamplerYcbcrConversion glad_vkDestroySamplerYcbcrConversion = NULL; PFN_vkDestroySamplerYcbcrConversionKHR glad_vkDestroySamplerYcbcrConversionKHR = NULL; PFN_vkDestroySemaphore glad_vkDestroySemaphore = NULL; +PFN_vkDestroyShaderEXT glad_vkDestroyShaderEXT = NULL; PFN_vkDestroyShaderModule glad_vkDestroyShaderModule = NULL; PFN_vkDestroySurfaceKHR glad_vkDestroySurfaceKHR = NULL; PFN_vkDestroySwapchainKHR glad_vkDestroySwapchainKHR = NULL; @@ -599,20 +1053,26 @@ PFN_vkEnumeratePhysicalDeviceGroups glad_vkEnumeratePhysicalDeviceGroups = NULL; PFN_vkEnumeratePhysicalDeviceGroupsKHR glad_vkEnumeratePhysicalDeviceGroupsKHR = NULL; PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR glad_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR = NULL; PFN_vkEnumeratePhysicalDevices glad_vkEnumeratePhysicalDevices = NULL; +#if defined(VK_USE_PLATFORM_METAL_EXT) +PFN_vkExportMetalObjectsEXT glad_vkExportMetalObjectsEXT = NULL; + +#endif PFN_vkFlushMappedMemoryRanges glad_vkFlushMappedMemoryRanges = NULL; PFN_vkFreeCommandBuffers glad_vkFreeCommandBuffers = NULL; PFN_vkFreeDescriptorSets glad_vkFreeDescriptorSets = NULL; PFN_vkFreeMemory glad_vkFreeMemory = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkGetAccelerationStructureBuildSizesKHR glad_vkGetAccelerationStructureBuildSizesKHR = NULL; PFN_vkGetAccelerationStructureDeviceAddressKHR glad_vkGetAccelerationStructureDeviceAddressKHR = NULL; -#endif PFN_vkGetAccelerationStructureHandleNV glad_vkGetAccelerationStructureHandleNV = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -PFN_vkGetAccelerationStructureMemoryRequirementsKHR glad_vkGetAccelerationStructureMemoryRequirementsKHR = NULL; -#endif PFN_vkGetAccelerationStructureMemoryRequirementsNV glad_vkGetAccelerationStructureMemoryRequirementsNV = NULL; +PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT glad_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT = NULL; #if defined(VK_USE_PLATFORM_ANDROID_KHR) PFN_vkGetAndroidHardwareBufferPropertiesANDROID glad_vkGetAndroidHardwareBufferPropertiesANDROID = NULL; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkGetBufferCollectionPropertiesFUCHSIA glad_vkGetBufferCollectionPropertiesFUCHSIA = NULL; + #endif PFN_vkGetBufferDeviceAddress glad_vkGetBufferDeviceAddress = NULL; PFN_vkGetBufferDeviceAddressEXT glad_vkGetBufferDeviceAddressEXT = NULL; @@ -622,75 +1082,142 @@ PFN_vkGetBufferMemoryRequirements2 glad_vkGetBufferMemoryRequirements2 = NULL; PFN_vkGetBufferMemoryRequirements2KHR glad_vkGetBufferMemoryRequirements2KHR = NULL; PFN_vkGetBufferOpaqueCaptureAddress glad_vkGetBufferOpaqueCaptureAddress = NULL; PFN_vkGetBufferOpaqueCaptureAddressKHR glad_vkGetBufferOpaqueCaptureAddressKHR = NULL; +PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT glad_vkGetBufferOpaqueCaptureDescriptorDataEXT = NULL; PFN_vkGetCalibratedTimestampsEXT glad_vkGetCalibratedTimestampsEXT = NULL; +PFN_vkGetCalibratedTimestampsKHR glad_vkGetCalibratedTimestampsKHR = NULL; +PFN_vkGetClusterAccelerationStructureBuildSizesNV glad_vkGetClusterAccelerationStructureBuildSizesNV = NULL; #if defined(VK_ENABLE_BETA_EXTENSIONS) -PFN_vkGetDeferredOperationMaxConcurrencyKHR glad_vkGetDeferredOperationMaxConcurrencyKHR = NULL; +PFN_vkGetCudaModuleCacheNV glad_vkGetCudaModuleCacheNV = NULL; + #endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkGetDeferredOperationMaxConcurrencyKHR glad_vkGetDeferredOperationMaxConcurrencyKHR = NULL; PFN_vkGetDeferredOperationResultKHR glad_vkGetDeferredOperationResultKHR = NULL; -#endif +PFN_vkGetDescriptorEXT glad_vkGetDescriptorEXT = NULL; +PFN_vkGetDescriptorSetHostMappingVALVE glad_vkGetDescriptorSetHostMappingVALVE = NULL; +PFN_vkGetDescriptorSetLayoutBindingOffsetEXT glad_vkGetDescriptorSetLayoutBindingOffsetEXT = NULL; +PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE glad_vkGetDescriptorSetLayoutHostMappingInfoVALVE = NULL; +PFN_vkGetDescriptorSetLayoutSizeEXT glad_vkGetDescriptorSetLayoutSizeEXT = NULL; PFN_vkGetDescriptorSetLayoutSupport glad_vkGetDescriptorSetLayoutSupport = NULL; PFN_vkGetDescriptorSetLayoutSupportKHR glad_vkGetDescriptorSetLayoutSupportKHR = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkGetDeviceAccelerationStructureCompatibilityKHR glad_vkGetDeviceAccelerationStructureCompatibilityKHR = NULL; -#endif +PFN_vkGetDeviceBufferMemoryRequirements glad_vkGetDeviceBufferMemoryRequirements = NULL; +PFN_vkGetDeviceBufferMemoryRequirementsKHR glad_vkGetDeviceBufferMemoryRequirementsKHR = NULL; +PFN_vkGetDeviceFaultInfoEXT glad_vkGetDeviceFaultInfoEXT = NULL; PFN_vkGetDeviceGroupPeerMemoryFeatures glad_vkGetDeviceGroupPeerMemoryFeatures = NULL; PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR glad_vkGetDeviceGroupPeerMemoryFeaturesKHR = NULL; PFN_vkGetDeviceGroupPresentCapabilitiesKHR glad_vkGetDeviceGroupPresentCapabilitiesKHR = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetDeviceGroupSurfacePresentModes2EXT glad_vkGetDeviceGroupSurfacePresentModes2EXT = NULL; + #endif PFN_vkGetDeviceGroupSurfacePresentModesKHR glad_vkGetDeviceGroupSurfacePresentModesKHR = NULL; +PFN_vkGetDeviceImageMemoryRequirements glad_vkGetDeviceImageMemoryRequirements = NULL; +PFN_vkGetDeviceImageMemoryRequirementsKHR glad_vkGetDeviceImageMemoryRequirementsKHR = NULL; +PFN_vkGetDeviceImageSparseMemoryRequirements glad_vkGetDeviceImageSparseMemoryRequirements = NULL; +PFN_vkGetDeviceImageSparseMemoryRequirementsKHR glad_vkGetDeviceImageSparseMemoryRequirementsKHR = NULL; +PFN_vkGetDeviceImageSubresourceLayout glad_vkGetDeviceImageSubresourceLayout = NULL; +PFN_vkGetDeviceImageSubresourceLayoutKHR glad_vkGetDeviceImageSubresourceLayoutKHR = NULL; PFN_vkGetDeviceMemoryCommitment glad_vkGetDeviceMemoryCommitment = NULL; PFN_vkGetDeviceMemoryOpaqueCaptureAddress glad_vkGetDeviceMemoryOpaqueCaptureAddress = NULL; PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR glad_vkGetDeviceMemoryOpaqueCaptureAddressKHR = NULL; +PFN_vkGetDeviceMicromapCompatibilityEXT glad_vkGetDeviceMicromapCompatibilityEXT = NULL; PFN_vkGetDeviceProcAddr glad_vkGetDeviceProcAddr = NULL; PFN_vkGetDeviceQueue glad_vkGetDeviceQueue = NULL; PFN_vkGetDeviceQueue2 glad_vkGetDeviceQueue2 = NULL; +PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI glad_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI = NULL; PFN_vkGetDisplayModeProperties2KHR glad_vkGetDisplayModeProperties2KHR = NULL; PFN_vkGetDisplayModePropertiesKHR glad_vkGetDisplayModePropertiesKHR = NULL; PFN_vkGetDisplayPlaneCapabilities2KHR glad_vkGetDisplayPlaneCapabilities2KHR = NULL; PFN_vkGetDisplayPlaneCapabilitiesKHR glad_vkGetDisplayPlaneCapabilitiesKHR = NULL; PFN_vkGetDisplayPlaneSupportedDisplaysKHR glad_vkGetDisplayPlaneSupportedDisplaysKHR = NULL; +PFN_vkGetDrmDisplayEXT glad_vkGetDrmDisplayEXT = NULL; +PFN_vkGetDynamicRenderingTilePropertiesQCOM glad_vkGetDynamicRenderingTilePropertiesQCOM = NULL; PFN_vkGetEventStatus glad_vkGetEventStatus = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkGetExecutionGraphPipelineNodeIndexAMDX glad_vkGetExecutionGraphPipelineNodeIndexAMDX = NULL; + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkGetExecutionGraphPipelineScratchSizeAMDX glad_vkGetExecutionGraphPipelineScratchSizeAMDX = NULL; + +#endif +PFN_vkGetExternalComputeQueueDataNV glad_vkGetExternalComputeQueueDataNV = NULL; PFN_vkGetFenceFdKHR glad_vkGetFenceFdKHR = NULL; PFN_vkGetFenceStatus glad_vkGetFenceStatus = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetFenceWin32HandleKHR glad_vkGetFenceWin32HandleKHR = NULL; + #endif +PFN_vkGetFramebufferTilePropertiesQCOM glad_vkGetFramebufferTilePropertiesQCOM = NULL; +PFN_vkGetGeneratedCommandsMemoryRequirementsEXT glad_vkGetGeneratedCommandsMemoryRequirementsEXT = NULL; PFN_vkGetGeneratedCommandsMemoryRequirementsNV glad_vkGetGeneratedCommandsMemoryRequirementsNV = NULL; PFN_vkGetImageDrmFormatModifierPropertiesEXT glad_vkGetImageDrmFormatModifierPropertiesEXT = NULL; PFN_vkGetImageMemoryRequirements glad_vkGetImageMemoryRequirements = NULL; PFN_vkGetImageMemoryRequirements2 glad_vkGetImageMemoryRequirements2 = NULL; PFN_vkGetImageMemoryRequirements2KHR glad_vkGetImageMemoryRequirements2KHR = NULL; +PFN_vkGetImageOpaqueCaptureDescriptorDataEXT glad_vkGetImageOpaqueCaptureDescriptorDataEXT = NULL; PFN_vkGetImageSparseMemoryRequirements glad_vkGetImageSparseMemoryRequirements = NULL; PFN_vkGetImageSparseMemoryRequirements2 glad_vkGetImageSparseMemoryRequirements2 = NULL; PFN_vkGetImageSparseMemoryRequirements2KHR glad_vkGetImageSparseMemoryRequirements2KHR = NULL; PFN_vkGetImageSubresourceLayout glad_vkGetImageSubresourceLayout = NULL; +PFN_vkGetImageSubresourceLayout2 glad_vkGetImageSubresourceLayout2 = NULL; +PFN_vkGetImageSubresourceLayout2EXT glad_vkGetImageSubresourceLayout2EXT = NULL; +PFN_vkGetImageSubresourceLayout2KHR glad_vkGetImageSubresourceLayout2KHR = NULL; PFN_vkGetImageViewAddressNVX glad_vkGetImageViewAddressNVX = NULL; +PFN_vkGetImageViewHandle64NVX glad_vkGetImageViewHandle64NVX = NULL; PFN_vkGetImageViewHandleNVX glad_vkGetImageViewHandleNVX = NULL; +PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT glad_vkGetImageViewOpaqueCaptureDescriptorDataEXT = NULL; PFN_vkGetInstanceProcAddr glad_vkGetInstanceProcAddr = NULL; +PFN_vkGetLatencyTimingsNV glad_vkGetLatencyTimingsNV = NULL; #if defined(VK_USE_PLATFORM_ANDROID_KHR) PFN_vkGetMemoryAndroidHardwareBufferANDROID glad_vkGetMemoryAndroidHardwareBufferANDROID = NULL; + #endif PFN_vkGetMemoryFdKHR glad_vkGetMemoryFdKHR = NULL; PFN_vkGetMemoryFdPropertiesKHR glad_vkGetMemoryFdPropertiesKHR = NULL; PFN_vkGetMemoryHostPointerPropertiesEXT glad_vkGetMemoryHostPointerPropertiesEXT = NULL; +#if defined(VK_USE_PLATFORM_METAL_EXT) +PFN_vkGetMemoryMetalHandleEXT glad_vkGetMemoryMetalHandleEXT = NULL; + +#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +PFN_vkGetMemoryMetalHandlePropertiesEXT glad_vkGetMemoryMetalHandlePropertiesEXT = NULL; + +#endif +PFN_vkGetMemoryRemoteAddressNV glad_vkGetMemoryRemoteAddressNV = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetMemoryWin32HandleKHR glad_vkGetMemoryWin32HandleKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetMemoryWin32HandleNV glad_vkGetMemoryWin32HandleNV = NULL; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetMemoryWin32HandlePropertiesKHR glad_vkGetMemoryWin32HandlePropertiesKHR = NULL; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkGetMemoryZirconHandleFUCHSIA glad_vkGetMemoryZirconHandleFUCHSIA = NULL; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA glad_vkGetMemoryZirconHandlePropertiesFUCHSIA = NULL; + #endif +PFN_vkGetMicromapBuildSizesEXT glad_vkGetMicromapBuildSizesEXT = NULL; +PFN_vkGetPartitionedAccelerationStructuresBuildSizesNV glad_vkGetPartitionedAccelerationStructuresBuildSizesNV = NULL; PFN_vkGetPastPresentationTimingGOOGLE glad_vkGetPastPresentationTimingGOOGLE = NULL; PFN_vkGetPerformanceParameterINTEL glad_vkGetPerformanceParameterINTEL = NULL; PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT glad_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT = NULL; +PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR glad_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR = NULL; +PFN_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV glad_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV = NULL; +PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR = NULL; PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV = NULL; +PFN_vkGetPhysicalDeviceCooperativeVectorPropertiesNV glad_vkGetPhysicalDeviceCooperativeVectorPropertiesNV = NULL; #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT glad_vkGetPhysicalDeviceDirectFBPresentationSupportEXT = NULL; + #endif PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR glad_vkGetPhysicalDeviceDisplayPlaneProperties2KHR = NULL; PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR glad_vkGetPhysicalDeviceDisplayPlanePropertiesKHR = NULL; @@ -709,6 +1236,7 @@ PFN_vkGetPhysicalDeviceFeatures2KHR glad_vkGetPhysicalDeviceFeatures2KHR = NULL; PFN_vkGetPhysicalDeviceFormatProperties glad_vkGetPhysicalDeviceFormatProperties = NULL; PFN_vkGetPhysicalDeviceFormatProperties2 glad_vkGetPhysicalDeviceFormatProperties2 = NULL; PFN_vkGetPhysicalDeviceFormatProperties2KHR glad_vkGetPhysicalDeviceFormatProperties2KHR = NULL; +PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR glad_vkGetPhysicalDeviceFragmentShadingRatesKHR = NULL; PFN_vkGetPhysicalDeviceImageFormatProperties glad_vkGetPhysicalDeviceImageFormatProperties = NULL; PFN_vkGetPhysicalDeviceImageFormatProperties2 glad_vkGetPhysicalDeviceImageFormatProperties2 = NULL; PFN_vkGetPhysicalDeviceImageFormatProperties2KHR glad_vkGetPhysicalDeviceImageFormatProperties2KHR = NULL; @@ -716,6 +1244,7 @@ PFN_vkGetPhysicalDeviceMemoryProperties glad_vkGetPhysicalDeviceMemoryProperties PFN_vkGetPhysicalDeviceMemoryProperties2 glad_vkGetPhysicalDeviceMemoryProperties2 = NULL; PFN_vkGetPhysicalDeviceMemoryProperties2KHR glad_vkGetPhysicalDeviceMemoryProperties2KHR = NULL; PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT glad_vkGetPhysicalDeviceMultisamplePropertiesEXT = NULL; +PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV glad_vkGetPhysicalDeviceOpticalFlowImageFormatsNV = NULL; PFN_vkGetPhysicalDevicePresentRectanglesKHR glad_vkGetPhysicalDevicePresentRectanglesKHR = NULL; PFN_vkGetPhysicalDeviceProperties glad_vkGetPhysicalDeviceProperties = NULL; PFN_vkGetPhysicalDeviceProperties2 glad_vkGetPhysicalDeviceProperties2 = NULL; @@ -724,6 +1253,10 @@ PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR glad_vkGetPhysicalDe PFN_vkGetPhysicalDeviceQueueFamilyProperties glad_vkGetPhysicalDeviceQueueFamilyProperties = NULL; PFN_vkGetPhysicalDeviceQueueFamilyProperties2 glad_vkGetPhysicalDeviceQueueFamilyProperties2 = NULL; PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR glad_vkGetPhysicalDeviceQueueFamilyProperties2KHR = NULL; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX glad_vkGetPhysicalDeviceScreenPresentationSupportQNX = NULL; + +#endif PFN_vkGetPhysicalDeviceSparseImageFormatProperties glad_vkGetPhysicalDeviceSparseImageFormatProperties = NULL; PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 glad_vkGetPhysicalDeviceSparseImageFormatProperties2 = NULL; PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR glad_vkGetPhysicalDeviceSparseImageFormatProperties2KHR = NULL; @@ -735,81 +1268,126 @@ PFN_vkGetPhysicalDeviceSurfaceFormats2KHR glad_vkGetPhysicalDeviceSurfaceFormats PFN_vkGetPhysicalDeviceSurfaceFormatsKHR glad_vkGetPhysicalDeviceSurfaceFormatsKHR = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT glad_vkGetPhysicalDeviceSurfacePresentModes2EXT = NULL; + #endif PFN_vkGetPhysicalDeviceSurfacePresentModesKHR glad_vkGetPhysicalDeviceSurfacePresentModesKHR = NULL; PFN_vkGetPhysicalDeviceSurfaceSupportKHR glad_vkGetPhysicalDeviceSurfaceSupportKHR = NULL; +PFN_vkGetPhysicalDeviceToolProperties glad_vkGetPhysicalDeviceToolProperties = NULL; PFN_vkGetPhysicalDeviceToolPropertiesEXT glad_vkGetPhysicalDeviceToolPropertiesEXT = NULL; #if defined(VK_USE_PLATFORM_WAYLAND_KHR) PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR glad_vkGetPhysicalDeviceWaylandPresentationSupportKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR glad_vkGetPhysicalDeviceWin32PresentationSupportKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR glad_vkGetPhysicalDeviceXcbPresentationSupportKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR glad_vkGetPhysicalDeviceXlibPresentationSupportKHR = NULL; + #endif +PFN_vkGetPipelineBinaryDataKHR glad_vkGetPipelineBinaryDataKHR = NULL; PFN_vkGetPipelineCacheData glad_vkGetPipelineCacheData = NULL; PFN_vkGetPipelineExecutableInternalRepresentationsKHR glad_vkGetPipelineExecutableInternalRepresentationsKHR = NULL; PFN_vkGetPipelineExecutablePropertiesKHR glad_vkGetPipelineExecutablePropertiesKHR = NULL; PFN_vkGetPipelineExecutableStatisticsKHR glad_vkGetPipelineExecutableStatisticsKHR = NULL; +PFN_vkGetPipelineIndirectDeviceAddressNV glad_vkGetPipelineIndirectDeviceAddressNV = NULL; +PFN_vkGetPipelineIndirectMemoryRequirementsNV glad_vkGetPipelineIndirectMemoryRequirementsNV = NULL; +PFN_vkGetPipelineKeyKHR glad_vkGetPipelineKeyKHR = NULL; +PFN_vkGetPipelinePropertiesEXT glad_vkGetPipelinePropertiesEXT = NULL; +PFN_vkGetPrivateData glad_vkGetPrivateData = NULL; PFN_vkGetPrivateDataEXT glad_vkGetPrivateDataEXT = NULL; PFN_vkGetQueryPoolResults glad_vkGetQueryPoolResults = NULL; +PFN_vkGetQueueCheckpointData2NV glad_vkGetQueueCheckpointData2NV = NULL; PFN_vkGetQueueCheckpointDataNV glad_vkGetQueueCheckpointDataNV = NULL; #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) PFN_vkGetRandROutputDisplayEXT glad_vkGetRandROutputDisplayEXT = NULL; + #endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR glad_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkGetRayTracingShaderGroupHandlesKHR glad_vkGetRayTracingShaderGroupHandlesKHR = NULL; -#endif PFN_vkGetRayTracingShaderGroupHandlesNV glad_vkGetRayTracingShaderGroupHandlesNV = NULL; +PFN_vkGetRayTracingShaderGroupStackSizeKHR glad_vkGetRayTracingShaderGroupStackSizeKHR = NULL; PFN_vkGetRefreshCycleDurationGOOGLE glad_vkGetRefreshCycleDurationGOOGLE = NULL; PFN_vkGetRenderAreaGranularity glad_vkGetRenderAreaGranularity = NULL; +PFN_vkGetRenderingAreaGranularity glad_vkGetRenderingAreaGranularity = NULL; +PFN_vkGetRenderingAreaGranularityKHR glad_vkGetRenderingAreaGranularityKHR = NULL; +PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT glad_vkGetSamplerOpaqueCaptureDescriptorDataEXT = NULL; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +PFN_vkGetScreenBufferPropertiesQNX glad_vkGetScreenBufferPropertiesQNX = NULL; + +#endif PFN_vkGetSemaphoreCounterValue glad_vkGetSemaphoreCounterValue = NULL; PFN_vkGetSemaphoreCounterValueKHR glad_vkGetSemaphoreCounterValueKHR = NULL; PFN_vkGetSemaphoreFdKHR glad_vkGetSemaphoreFdKHR = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetSemaphoreWin32HandleKHR glad_vkGetSemaphoreWin32HandleKHR = NULL; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkGetSemaphoreZirconHandleFUCHSIA glad_vkGetSemaphoreZirconHandleFUCHSIA = NULL; + #endif +PFN_vkGetShaderBinaryDataEXT glad_vkGetShaderBinaryDataEXT = NULL; PFN_vkGetShaderInfoAMD glad_vkGetShaderInfoAMD = NULL; +PFN_vkGetShaderModuleCreateInfoIdentifierEXT glad_vkGetShaderModuleCreateInfoIdentifierEXT = NULL; +PFN_vkGetShaderModuleIdentifierEXT glad_vkGetShaderModuleIdentifierEXT = NULL; PFN_vkGetSwapchainCounterEXT glad_vkGetSwapchainCounterEXT = NULL; PFN_vkGetSwapchainImagesKHR glad_vkGetSwapchainImagesKHR = NULL; PFN_vkGetSwapchainStatusKHR glad_vkGetSwapchainStatusKHR = NULL; PFN_vkGetValidationCacheDataEXT glad_vkGetValidationCacheDataEXT = NULL; +#if defined(VK_USE_PLATFORM_WIN32_KHR) +PFN_vkGetWinrtDisplayNV glad_vkGetWinrtDisplayNV = NULL; + +#endif PFN_vkImportFenceFdKHR glad_vkImportFenceFdKHR = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkImportFenceWin32HandleKHR glad_vkImportFenceWin32HandleKHR = NULL; + #endif PFN_vkImportSemaphoreFdKHR glad_vkImportSemaphoreFdKHR = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkImportSemaphoreWin32HandleKHR glad_vkImportSemaphoreWin32HandleKHR = NULL; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkImportSemaphoreZirconHandleFUCHSIA glad_vkImportSemaphoreZirconHandleFUCHSIA = NULL; + #endif PFN_vkInitializePerformanceApiINTEL glad_vkInitializePerformanceApiINTEL = NULL; PFN_vkInvalidateMappedMemoryRanges glad_vkInvalidateMappedMemoryRanges = NULL; +PFN_vkLatencySleepNV glad_vkLatencySleepNV = NULL; PFN_vkMapMemory glad_vkMapMemory = NULL; +PFN_vkMapMemory2 glad_vkMapMemory2 = NULL; +PFN_vkMapMemory2KHR glad_vkMapMemory2KHR = NULL; PFN_vkMergePipelineCaches glad_vkMergePipelineCaches = NULL; PFN_vkMergeValidationCachesEXT glad_vkMergeValidationCachesEXT = NULL; PFN_vkQueueBeginDebugUtilsLabelEXT glad_vkQueueBeginDebugUtilsLabelEXT = NULL; PFN_vkQueueBindSparse glad_vkQueueBindSparse = NULL; PFN_vkQueueEndDebugUtilsLabelEXT glad_vkQueueEndDebugUtilsLabelEXT = NULL; PFN_vkQueueInsertDebugUtilsLabelEXT glad_vkQueueInsertDebugUtilsLabelEXT = NULL; +PFN_vkQueueNotifyOutOfBandNV glad_vkQueueNotifyOutOfBandNV = NULL; PFN_vkQueuePresentKHR glad_vkQueuePresentKHR = NULL; PFN_vkQueueSetPerformanceConfigurationINTEL glad_vkQueueSetPerformanceConfigurationINTEL = NULL; PFN_vkQueueSubmit glad_vkQueueSubmit = NULL; +PFN_vkQueueSubmit2 glad_vkQueueSubmit2 = NULL; +PFN_vkQueueSubmit2KHR glad_vkQueueSubmit2KHR = NULL; PFN_vkQueueWaitIdle glad_vkQueueWaitIdle = NULL; PFN_vkRegisterDeviceEventEXT glad_vkRegisterDeviceEventEXT = NULL; PFN_vkRegisterDisplayEventEXT glad_vkRegisterDisplayEventEXT = NULL; +PFN_vkReleaseCapturedPipelineDataKHR glad_vkReleaseCapturedPipelineDataKHR = NULL; PFN_vkReleaseDisplayEXT glad_vkReleaseDisplayEXT = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkReleaseFullScreenExclusiveModeEXT glad_vkReleaseFullScreenExclusiveModeEXT = NULL; + #endif PFN_vkReleasePerformanceConfigurationINTEL glad_vkReleasePerformanceConfigurationINTEL = NULL; PFN_vkReleaseProfilingLockKHR glad_vkReleaseProfilingLockKHR = NULL; +PFN_vkReleaseSwapchainImagesEXT glad_vkReleaseSwapchainImagesEXT = NULL; PFN_vkResetCommandBuffer glad_vkResetCommandBuffer = NULL; PFN_vkResetCommandPool glad_vkResetCommandPool = NULL; PFN_vkResetDescriptorPool glad_vkResetDescriptorPool = NULL; @@ -817,28 +1395,46 @@ PFN_vkResetEvent glad_vkResetEvent = NULL; PFN_vkResetFences glad_vkResetFences = NULL; PFN_vkResetQueryPool glad_vkResetQueryPool = NULL; PFN_vkResetQueryPoolEXT glad_vkResetQueryPoolEXT = NULL; +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA glad_vkSetBufferCollectionBufferConstraintsFUCHSIA = NULL; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkSetBufferCollectionImageConstraintsFUCHSIA glad_vkSetBufferCollectionImageConstraintsFUCHSIA = NULL; + +#endif PFN_vkSetDebugUtilsObjectNameEXT glad_vkSetDebugUtilsObjectNameEXT = NULL; PFN_vkSetDebugUtilsObjectTagEXT glad_vkSetDebugUtilsObjectTagEXT = NULL; +PFN_vkSetDeviceMemoryPriorityEXT glad_vkSetDeviceMemoryPriorityEXT = NULL; PFN_vkSetEvent glad_vkSetEvent = NULL; PFN_vkSetHdrMetadataEXT glad_vkSetHdrMetadataEXT = NULL; +PFN_vkSetLatencyMarkerNV glad_vkSetLatencyMarkerNV = NULL; +PFN_vkSetLatencySleepModeNV glad_vkSetLatencySleepModeNV = NULL; PFN_vkSetLocalDimmingAMD glad_vkSetLocalDimmingAMD = NULL; +PFN_vkSetPrivateData glad_vkSetPrivateData = NULL; PFN_vkSetPrivateDataEXT glad_vkSetPrivateDataEXT = NULL; PFN_vkSignalSemaphore glad_vkSignalSemaphore = NULL; PFN_vkSignalSemaphoreKHR glad_vkSignalSemaphoreKHR = NULL; PFN_vkSubmitDebugUtilsMessageEXT glad_vkSubmitDebugUtilsMessageEXT = NULL; +PFN_vkTransitionImageLayout glad_vkTransitionImageLayout = NULL; +PFN_vkTransitionImageLayoutEXT glad_vkTransitionImageLayoutEXT = NULL; PFN_vkTrimCommandPool glad_vkTrimCommandPool = NULL; PFN_vkTrimCommandPoolKHR glad_vkTrimCommandPoolKHR = NULL; PFN_vkUninitializePerformanceApiINTEL glad_vkUninitializePerformanceApiINTEL = NULL; PFN_vkUnmapMemory glad_vkUnmapMemory = NULL; +PFN_vkUnmapMemory2 glad_vkUnmapMemory2 = NULL; +PFN_vkUnmapMemory2KHR glad_vkUnmapMemory2KHR = NULL; PFN_vkUpdateDescriptorSetWithTemplate glad_vkUpdateDescriptorSetWithTemplate = NULL; PFN_vkUpdateDescriptorSetWithTemplateKHR glad_vkUpdateDescriptorSetWithTemplateKHR = NULL; PFN_vkUpdateDescriptorSets glad_vkUpdateDescriptorSets = NULL; +PFN_vkUpdateIndirectExecutionSetPipelineEXT glad_vkUpdateIndirectExecutionSetPipelineEXT = NULL; +PFN_vkUpdateIndirectExecutionSetShaderEXT glad_vkUpdateIndirectExecutionSetShaderEXT = NULL; PFN_vkWaitForFences glad_vkWaitForFences = NULL; +PFN_vkWaitForPresentKHR glad_vkWaitForPresentKHR = NULL; PFN_vkWaitSemaphores glad_vkWaitSemaphores = NULL; PFN_vkWaitSemaphoresKHR glad_vkWaitSemaphoresKHR = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkWriteAccelerationStructuresPropertiesKHR glad_vkWriteAccelerationStructuresPropertiesKHR = NULL; -#endif +PFN_vkWriteMicromapsPropertiesEXT glad_vkWriteMicromapsPropertiesEXT = NULL; static void glad_vk_load_VK_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) { @@ -1028,8 +1624,88 @@ static void glad_vk_load_VK_VERSION_1_2( GLADuserptrloadfunc load, void* userptr glad_vkSignalSemaphore = (PFN_vkSignalSemaphore) load(userptr, "vkSignalSemaphore"); glad_vkWaitSemaphores = (PFN_vkWaitSemaphores) load(userptr, "vkWaitSemaphores"); } +static void glad_vk_load_VK_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_VERSION_1_3) return; + glad_vkCmdBeginRendering = (PFN_vkCmdBeginRendering) load(userptr, "vkCmdBeginRendering"); + glad_vkCmdBindVertexBuffers2 = (PFN_vkCmdBindVertexBuffers2) load(userptr, "vkCmdBindVertexBuffers2"); + glad_vkCmdBlitImage2 = (PFN_vkCmdBlitImage2) load(userptr, "vkCmdBlitImage2"); + glad_vkCmdCopyBuffer2 = (PFN_vkCmdCopyBuffer2) load(userptr, "vkCmdCopyBuffer2"); + glad_vkCmdCopyBufferToImage2 = (PFN_vkCmdCopyBufferToImage2) load(userptr, "vkCmdCopyBufferToImage2"); + glad_vkCmdCopyImage2 = (PFN_vkCmdCopyImage2) load(userptr, "vkCmdCopyImage2"); + glad_vkCmdCopyImageToBuffer2 = (PFN_vkCmdCopyImageToBuffer2) load(userptr, "vkCmdCopyImageToBuffer2"); + glad_vkCmdEndRendering = (PFN_vkCmdEndRendering) load(userptr, "vkCmdEndRendering"); + glad_vkCmdPipelineBarrier2 = (PFN_vkCmdPipelineBarrier2) load(userptr, "vkCmdPipelineBarrier2"); + glad_vkCmdResetEvent2 = (PFN_vkCmdResetEvent2) load(userptr, "vkCmdResetEvent2"); + glad_vkCmdResolveImage2 = (PFN_vkCmdResolveImage2) load(userptr, "vkCmdResolveImage2"); + glad_vkCmdSetCullMode = (PFN_vkCmdSetCullMode) load(userptr, "vkCmdSetCullMode"); + glad_vkCmdSetDepthBiasEnable = (PFN_vkCmdSetDepthBiasEnable) load(userptr, "vkCmdSetDepthBiasEnable"); + glad_vkCmdSetDepthBoundsTestEnable = (PFN_vkCmdSetDepthBoundsTestEnable) load(userptr, "vkCmdSetDepthBoundsTestEnable"); + glad_vkCmdSetDepthCompareOp = (PFN_vkCmdSetDepthCompareOp) load(userptr, "vkCmdSetDepthCompareOp"); + glad_vkCmdSetDepthTestEnable = (PFN_vkCmdSetDepthTestEnable) load(userptr, "vkCmdSetDepthTestEnable"); + glad_vkCmdSetDepthWriteEnable = (PFN_vkCmdSetDepthWriteEnable) load(userptr, "vkCmdSetDepthWriteEnable"); + glad_vkCmdSetEvent2 = (PFN_vkCmdSetEvent2) load(userptr, "vkCmdSetEvent2"); + glad_vkCmdSetFrontFace = (PFN_vkCmdSetFrontFace) load(userptr, "vkCmdSetFrontFace"); + glad_vkCmdSetPrimitiveRestartEnable = (PFN_vkCmdSetPrimitiveRestartEnable) load(userptr, "vkCmdSetPrimitiveRestartEnable"); + glad_vkCmdSetPrimitiveTopology = (PFN_vkCmdSetPrimitiveTopology) load(userptr, "vkCmdSetPrimitiveTopology"); + glad_vkCmdSetRasterizerDiscardEnable = (PFN_vkCmdSetRasterizerDiscardEnable) load(userptr, "vkCmdSetRasterizerDiscardEnable"); + glad_vkCmdSetScissorWithCount = (PFN_vkCmdSetScissorWithCount) load(userptr, "vkCmdSetScissorWithCount"); + glad_vkCmdSetStencilOp = (PFN_vkCmdSetStencilOp) load(userptr, "vkCmdSetStencilOp"); + glad_vkCmdSetStencilTestEnable = (PFN_vkCmdSetStencilTestEnable) load(userptr, "vkCmdSetStencilTestEnable"); + glad_vkCmdSetViewportWithCount = (PFN_vkCmdSetViewportWithCount) load(userptr, "vkCmdSetViewportWithCount"); + glad_vkCmdWaitEvents2 = (PFN_vkCmdWaitEvents2) load(userptr, "vkCmdWaitEvents2"); + glad_vkCmdWriteTimestamp2 = (PFN_vkCmdWriteTimestamp2) load(userptr, "vkCmdWriteTimestamp2"); + glad_vkCreatePrivateDataSlot = (PFN_vkCreatePrivateDataSlot) load(userptr, "vkCreatePrivateDataSlot"); + glad_vkDestroyPrivateDataSlot = (PFN_vkDestroyPrivateDataSlot) load(userptr, "vkDestroyPrivateDataSlot"); + glad_vkGetDeviceBufferMemoryRequirements = (PFN_vkGetDeviceBufferMemoryRequirements) load(userptr, "vkGetDeviceBufferMemoryRequirements"); + glad_vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements) load(userptr, "vkGetDeviceImageMemoryRequirements"); + glad_vkGetDeviceImageSparseMemoryRequirements = (PFN_vkGetDeviceImageSparseMemoryRequirements) load(userptr, "vkGetDeviceImageSparseMemoryRequirements"); + glad_vkGetPhysicalDeviceToolProperties = (PFN_vkGetPhysicalDeviceToolProperties) load(userptr, "vkGetPhysicalDeviceToolProperties"); + glad_vkGetPrivateData = (PFN_vkGetPrivateData) load(userptr, "vkGetPrivateData"); + glad_vkQueueSubmit2 = (PFN_vkQueueSubmit2) load(userptr, "vkQueueSubmit2"); + glad_vkSetPrivateData = (PFN_vkSetPrivateData) load(userptr, "vkSetPrivateData"); +} +static void glad_vk_load_VK_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_VERSION_1_4) return; + glad_vkCmdBindDescriptorSets2 = (PFN_vkCmdBindDescriptorSets2) load(userptr, "vkCmdBindDescriptorSets2"); + glad_vkCmdBindIndexBuffer2 = (PFN_vkCmdBindIndexBuffer2) load(userptr, "vkCmdBindIndexBuffer2"); + glad_vkCmdPushConstants2 = (PFN_vkCmdPushConstants2) load(userptr, "vkCmdPushConstants2"); + glad_vkCmdPushDescriptorSet = (PFN_vkCmdPushDescriptorSet) load(userptr, "vkCmdPushDescriptorSet"); + glad_vkCmdPushDescriptorSet2 = (PFN_vkCmdPushDescriptorSet2) load(userptr, "vkCmdPushDescriptorSet2"); + glad_vkCmdPushDescriptorSetWithTemplate = (PFN_vkCmdPushDescriptorSetWithTemplate) load(userptr, "vkCmdPushDescriptorSetWithTemplate"); + glad_vkCmdPushDescriptorSetWithTemplate2 = (PFN_vkCmdPushDescriptorSetWithTemplate2) load(userptr, "vkCmdPushDescriptorSetWithTemplate2"); + glad_vkCmdSetLineStipple = (PFN_vkCmdSetLineStipple) load(userptr, "vkCmdSetLineStipple"); + glad_vkCmdSetRenderingAttachmentLocations = (PFN_vkCmdSetRenderingAttachmentLocations) load(userptr, "vkCmdSetRenderingAttachmentLocations"); + glad_vkCmdSetRenderingInputAttachmentIndices = (PFN_vkCmdSetRenderingInputAttachmentIndices) load(userptr, "vkCmdSetRenderingInputAttachmentIndices"); + glad_vkCopyImageToImage = (PFN_vkCopyImageToImage) load(userptr, "vkCopyImageToImage"); + glad_vkCopyImageToMemory = (PFN_vkCopyImageToMemory) load(userptr, "vkCopyImageToMemory"); + glad_vkCopyMemoryToImage = (PFN_vkCopyMemoryToImage) load(userptr, "vkCopyMemoryToImage"); + glad_vkGetDeviceImageSubresourceLayout = (PFN_vkGetDeviceImageSubresourceLayout) load(userptr, "vkGetDeviceImageSubresourceLayout"); + glad_vkGetImageSubresourceLayout2 = (PFN_vkGetImageSubresourceLayout2) load(userptr, "vkGetImageSubresourceLayout2"); + glad_vkGetRenderingAreaGranularity = (PFN_vkGetRenderingAreaGranularity) load(userptr, "vkGetRenderingAreaGranularity"); + glad_vkMapMemory2 = (PFN_vkMapMemory2) load(userptr, "vkMapMemory2"); + glad_vkTransitionImageLayout = (PFN_vkTransitionImageLayout) load(userptr, "vkTransitionImageLayout"); + glad_vkUnmapMemory2 = (PFN_vkUnmapMemory2) load(userptr, "vkUnmapMemory2"); +} +#if defined(VK_ENABLE_BETA_EXTENSIONS) +static void glad_vk_load_VK_AMDX_shader_enqueue( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_AMDX_shader_enqueue) return; + glad_vkCmdDispatchGraphAMDX = (PFN_vkCmdDispatchGraphAMDX) load(userptr, "vkCmdDispatchGraphAMDX"); + glad_vkCmdDispatchGraphIndirectAMDX = (PFN_vkCmdDispatchGraphIndirectAMDX) load(userptr, "vkCmdDispatchGraphIndirectAMDX"); + glad_vkCmdDispatchGraphIndirectCountAMDX = (PFN_vkCmdDispatchGraphIndirectCountAMDX) load(userptr, "vkCmdDispatchGraphIndirectCountAMDX"); + glad_vkCmdInitializeGraphScratchMemoryAMDX = (PFN_vkCmdInitializeGraphScratchMemoryAMDX) load(userptr, "vkCmdInitializeGraphScratchMemoryAMDX"); + glad_vkCreateExecutionGraphPipelinesAMDX = (PFN_vkCreateExecutionGraphPipelinesAMDX) load(userptr, "vkCreateExecutionGraphPipelinesAMDX"); + glad_vkGetExecutionGraphPipelineNodeIndexAMDX = (PFN_vkGetExecutionGraphPipelineNodeIndexAMDX) load(userptr, "vkGetExecutionGraphPipelineNodeIndexAMDX"); + glad_vkGetExecutionGraphPipelineScratchSizeAMDX = (PFN_vkGetExecutionGraphPipelineScratchSizeAMDX) load(userptr, "vkGetExecutionGraphPipelineScratchSizeAMDX"); +} + +#endif +static void glad_vk_load_VK_AMD_anti_lag( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_AMD_anti_lag) return; + glad_vkAntiLagUpdateAMD = (PFN_vkAntiLagUpdateAMD) load(userptr, "vkAntiLagUpdateAMD"); +} static void glad_vk_load_VK_AMD_buffer_marker( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_AMD_buffer_marker) return; + glad_vkCmdWriteBufferMarker2AMD = (PFN_vkCmdWriteBufferMarker2AMD) load(userptr, "vkCmdWriteBufferMarker2AMD"); glad_vkCmdWriteBufferMarkerAMD = (PFN_vkCmdWriteBufferMarkerAMD) load(userptr, "vkCmdWriteBufferMarkerAMD"); } static void glad_vk_load_VK_AMD_display_native_hdr( GLADuserptrloadfunc load, void* userptr) { @@ -1051,14 +1727,25 @@ static void glad_vk_load_VK_ANDROID_external_memory_android_hardware_buffer( GLA glad_vkGetAndroidHardwareBufferPropertiesANDROID = (PFN_vkGetAndroidHardwareBufferPropertiesANDROID) load(userptr, "vkGetAndroidHardwareBufferPropertiesANDROID"); glad_vkGetMemoryAndroidHardwareBufferANDROID = (PFN_vkGetMemoryAndroidHardwareBufferANDROID) load(userptr, "vkGetMemoryAndroidHardwareBufferANDROID"); } + #endif +static void glad_vk_load_VK_EXT_acquire_drm_display( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_acquire_drm_display) return; + glad_vkAcquireDrmDisplayEXT = (PFN_vkAcquireDrmDisplayEXT) load(userptr, "vkAcquireDrmDisplayEXT"); + glad_vkGetDrmDisplayEXT = (PFN_vkGetDrmDisplayEXT) load(userptr, "vkGetDrmDisplayEXT"); +} #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) static void glad_vk_load_VK_EXT_acquire_xlib_display( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_acquire_xlib_display) return; glad_vkAcquireXlibDisplayEXT = (PFN_vkAcquireXlibDisplayEXT) load(userptr, "vkAcquireXlibDisplayEXT"); glad_vkGetRandROutputDisplayEXT = (PFN_vkGetRandROutputDisplayEXT) load(userptr, "vkGetRandROutputDisplayEXT"); } + #endif +static void glad_vk_load_VK_EXT_attachment_feedback_loop_dynamic_state( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_attachment_feedback_loop_dynamic_state) return; + glad_vkCmdSetAttachmentFeedbackLoopEnableEXT = (PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT) load(userptr, "vkCmdSetAttachmentFeedbackLoopEnableEXT"); +} static void glad_vk_load_VK_EXT_buffer_device_address( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_buffer_device_address) return; glad_vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT) load(userptr, "vkGetBufferDeviceAddressEXT"); @@ -1068,6 +1755,10 @@ static void glad_vk_load_VK_EXT_calibrated_timestamps( GLADuserptrloadfunc load, glad_vkGetCalibratedTimestampsEXT = (PFN_vkGetCalibratedTimestampsEXT) load(userptr, "vkGetCalibratedTimestampsEXT"); glad_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT = (PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT) load(userptr, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT"); } +static void glad_vk_load_VK_EXT_color_write_enable( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_color_write_enable) return; + glad_vkCmdSetColorWriteEnableEXT = (PFN_vkCmdSetColorWriteEnableEXT) load(userptr, "vkCmdSetColorWriteEnableEXT"); +} static void glad_vk_load_VK_EXT_conditional_rendering( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_conditional_rendering) return; glad_vkCmdBeginConditionalRenderingEXT = (PFN_vkCmdBeginConditionalRenderingEXT) load(userptr, "vkCmdBeginConditionalRenderingEXT"); @@ -1101,6 +1792,44 @@ static void glad_vk_load_VK_EXT_debug_utils( GLADuserptrloadfunc load, void* use glad_vkSetDebugUtilsObjectTagEXT = (PFN_vkSetDebugUtilsObjectTagEXT) load(userptr, "vkSetDebugUtilsObjectTagEXT"); glad_vkSubmitDebugUtilsMessageEXT = (PFN_vkSubmitDebugUtilsMessageEXT) load(userptr, "vkSubmitDebugUtilsMessageEXT"); } +static void glad_vk_load_VK_EXT_depth_bias_control( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_depth_bias_control) return; + glad_vkCmdSetDepthBias2EXT = (PFN_vkCmdSetDepthBias2EXT) load(userptr, "vkCmdSetDepthBias2EXT"); +} +static void glad_vk_load_VK_EXT_depth_clamp_control( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_depth_clamp_control) return; + glad_vkCmdSetDepthClampRangeEXT = (PFN_vkCmdSetDepthClampRangeEXT) load(userptr, "vkCmdSetDepthClampRangeEXT"); +} +static void glad_vk_load_VK_EXT_descriptor_buffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_descriptor_buffer) return; + glad_vkCmdBindDescriptorBufferEmbeddedSamplersEXT = (PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT) load(userptr, "vkCmdBindDescriptorBufferEmbeddedSamplersEXT"); + glad_vkCmdBindDescriptorBuffersEXT = (PFN_vkCmdBindDescriptorBuffersEXT) load(userptr, "vkCmdBindDescriptorBuffersEXT"); + glad_vkCmdSetDescriptorBufferOffsetsEXT = (PFN_vkCmdSetDescriptorBufferOffsetsEXT) load(userptr, "vkCmdSetDescriptorBufferOffsetsEXT"); + glad_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT = (PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT) load(userptr, "vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT"); + glad_vkGetBufferOpaqueCaptureDescriptorDataEXT = (PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT) load(userptr, "vkGetBufferOpaqueCaptureDescriptorDataEXT"); + glad_vkGetDescriptorEXT = (PFN_vkGetDescriptorEXT) load(userptr, "vkGetDescriptorEXT"); + glad_vkGetDescriptorSetLayoutBindingOffsetEXT = (PFN_vkGetDescriptorSetLayoutBindingOffsetEXT) load(userptr, "vkGetDescriptorSetLayoutBindingOffsetEXT"); + glad_vkGetDescriptorSetLayoutSizeEXT = (PFN_vkGetDescriptorSetLayoutSizeEXT) load(userptr, "vkGetDescriptorSetLayoutSizeEXT"); + glad_vkGetImageOpaqueCaptureDescriptorDataEXT = (PFN_vkGetImageOpaqueCaptureDescriptorDataEXT) load(userptr, "vkGetImageOpaqueCaptureDescriptorDataEXT"); + glad_vkGetImageViewOpaqueCaptureDescriptorDataEXT = (PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT) load(userptr, "vkGetImageViewOpaqueCaptureDescriptorDataEXT"); + glad_vkGetSamplerOpaqueCaptureDescriptorDataEXT = (PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT) load(userptr, "vkGetSamplerOpaqueCaptureDescriptorDataEXT"); +} +static void glad_vk_load_VK_EXT_device_fault( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_device_fault) return; + glad_vkGetDeviceFaultInfoEXT = (PFN_vkGetDeviceFaultInfoEXT) load(userptr, "vkGetDeviceFaultInfoEXT"); +} +static void glad_vk_load_VK_EXT_device_generated_commands( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_device_generated_commands) return; + glad_vkCmdExecuteGeneratedCommandsEXT = (PFN_vkCmdExecuteGeneratedCommandsEXT) load(userptr, "vkCmdExecuteGeneratedCommandsEXT"); + glad_vkCmdPreprocessGeneratedCommandsEXT = (PFN_vkCmdPreprocessGeneratedCommandsEXT) load(userptr, "vkCmdPreprocessGeneratedCommandsEXT"); + glad_vkCreateIndirectCommandsLayoutEXT = (PFN_vkCreateIndirectCommandsLayoutEXT) load(userptr, "vkCreateIndirectCommandsLayoutEXT"); + glad_vkCreateIndirectExecutionSetEXT = (PFN_vkCreateIndirectExecutionSetEXT) load(userptr, "vkCreateIndirectExecutionSetEXT"); + glad_vkDestroyIndirectCommandsLayoutEXT = (PFN_vkDestroyIndirectCommandsLayoutEXT) load(userptr, "vkDestroyIndirectCommandsLayoutEXT"); + glad_vkDestroyIndirectExecutionSetEXT = (PFN_vkDestroyIndirectExecutionSetEXT) load(userptr, "vkDestroyIndirectExecutionSetEXT"); + glad_vkGetGeneratedCommandsMemoryRequirementsEXT = (PFN_vkGetGeneratedCommandsMemoryRequirementsEXT) load(userptr, "vkGetGeneratedCommandsMemoryRequirementsEXT"); + glad_vkUpdateIndirectExecutionSetPipelineEXT = (PFN_vkUpdateIndirectExecutionSetPipelineEXT) load(userptr, "vkUpdateIndirectExecutionSetPipelineEXT"); + glad_vkUpdateIndirectExecutionSetShaderEXT = (PFN_vkUpdateIndirectExecutionSetShaderEXT) load(userptr, "vkUpdateIndirectExecutionSetShaderEXT"); +} static void glad_vk_load_VK_EXT_direct_mode_display( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_direct_mode_display) return; glad_vkReleaseDisplayEXT = (PFN_vkReleaseDisplayEXT) load(userptr, "vkReleaseDisplayEXT"); @@ -1111,10 +1840,13 @@ static void glad_vk_load_VK_EXT_directfb_surface( GLADuserptrloadfunc load, void glad_vkCreateDirectFBSurfaceEXT = (PFN_vkCreateDirectFBSurfaceEXT) load(userptr, "vkCreateDirectFBSurfaceEXT"); glad_vkGetPhysicalDeviceDirectFBPresentationSupportEXT = (PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT) load(userptr, "vkGetPhysicalDeviceDirectFBPresentationSupportEXT"); } + #endif static void glad_vk_load_VK_EXT_discard_rectangles( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_discard_rectangles) return; glad_vkCmdSetDiscardRectangleEXT = (PFN_vkCmdSetDiscardRectangleEXT) load(userptr, "vkCmdSetDiscardRectangleEXT"); + glad_vkCmdSetDiscardRectangleEnableEXT = (PFN_vkCmdSetDiscardRectangleEnableEXT) load(userptr, "vkCmdSetDiscardRectangleEnableEXT"); + glad_vkCmdSetDiscardRectangleModeEXT = (PFN_vkCmdSetDiscardRectangleModeEXT) load(userptr, "vkCmdSetDiscardRectangleModeEXT"); } static void glad_vk_load_VK_EXT_display_control( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_display_control) return; @@ -1142,10 +1874,64 @@ static void glad_vk_load_VK_EXT_extended_dynamic_state( GLADuserptrloadfunc load glad_vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT) load(userptr, "vkCmdSetStencilTestEnableEXT"); glad_vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT) load(userptr, "vkCmdSetViewportWithCountEXT"); } +static void glad_vk_load_VK_EXT_extended_dynamic_state2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_extended_dynamic_state2) return; + glad_vkCmdSetDepthBiasEnableEXT = (PFN_vkCmdSetDepthBiasEnableEXT) load(userptr, "vkCmdSetDepthBiasEnableEXT"); + glad_vkCmdSetLogicOpEXT = (PFN_vkCmdSetLogicOpEXT) load(userptr, "vkCmdSetLogicOpEXT"); + glad_vkCmdSetPatchControlPointsEXT = (PFN_vkCmdSetPatchControlPointsEXT) load(userptr, "vkCmdSetPatchControlPointsEXT"); + glad_vkCmdSetPrimitiveRestartEnableEXT = (PFN_vkCmdSetPrimitiveRestartEnableEXT) load(userptr, "vkCmdSetPrimitiveRestartEnableEXT"); + glad_vkCmdSetRasterizerDiscardEnableEXT = (PFN_vkCmdSetRasterizerDiscardEnableEXT) load(userptr, "vkCmdSetRasterizerDiscardEnableEXT"); +} +static void glad_vk_load_VK_EXT_extended_dynamic_state3( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_extended_dynamic_state3) return; + glad_vkCmdSetAlphaToCoverageEnableEXT = (PFN_vkCmdSetAlphaToCoverageEnableEXT) load(userptr, "vkCmdSetAlphaToCoverageEnableEXT"); + glad_vkCmdSetAlphaToOneEnableEXT = (PFN_vkCmdSetAlphaToOneEnableEXT) load(userptr, "vkCmdSetAlphaToOneEnableEXT"); + glad_vkCmdSetColorBlendAdvancedEXT = (PFN_vkCmdSetColorBlendAdvancedEXT) load(userptr, "vkCmdSetColorBlendAdvancedEXT"); + glad_vkCmdSetColorBlendEnableEXT = (PFN_vkCmdSetColorBlendEnableEXT) load(userptr, "vkCmdSetColorBlendEnableEXT"); + glad_vkCmdSetColorBlendEquationEXT = (PFN_vkCmdSetColorBlendEquationEXT) load(userptr, "vkCmdSetColorBlendEquationEXT"); + glad_vkCmdSetColorWriteMaskEXT = (PFN_vkCmdSetColorWriteMaskEXT) load(userptr, "vkCmdSetColorWriteMaskEXT"); + glad_vkCmdSetConservativeRasterizationModeEXT = (PFN_vkCmdSetConservativeRasterizationModeEXT) load(userptr, "vkCmdSetConservativeRasterizationModeEXT"); + glad_vkCmdSetCoverageModulationModeNV = (PFN_vkCmdSetCoverageModulationModeNV) load(userptr, "vkCmdSetCoverageModulationModeNV"); + glad_vkCmdSetCoverageModulationTableEnableNV = (PFN_vkCmdSetCoverageModulationTableEnableNV) load(userptr, "vkCmdSetCoverageModulationTableEnableNV"); + glad_vkCmdSetCoverageModulationTableNV = (PFN_vkCmdSetCoverageModulationTableNV) load(userptr, "vkCmdSetCoverageModulationTableNV"); + glad_vkCmdSetCoverageReductionModeNV = (PFN_vkCmdSetCoverageReductionModeNV) load(userptr, "vkCmdSetCoverageReductionModeNV"); + glad_vkCmdSetCoverageToColorEnableNV = (PFN_vkCmdSetCoverageToColorEnableNV) load(userptr, "vkCmdSetCoverageToColorEnableNV"); + glad_vkCmdSetCoverageToColorLocationNV = (PFN_vkCmdSetCoverageToColorLocationNV) load(userptr, "vkCmdSetCoverageToColorLocationNV"); + glad_vkCmdSetDepthClampEnableEXT = (PFN_vkCmdSetDepthClampEnableEXT) load(userptr, "vkCmdSetDepthClampEnableEXT"); + glad_vkCmdSetDepthClipEnableEXT = (PFN_vkCmdSetDepthClipEnableEXT) load(userptr, "vkCmdSetDepthClipEnableEXT"); + glad_vkCmdSetDepthClipNegativeOneToOneEXT = (PFN_vkCmdSetDepthClipNegativeOneToOneEXT) load(userptr, "vkCmdSetDepthClipNegativeOneToOneEXT"); + glad_vkCmdSetExtraPrimitiveOverestimationSizeEXT = (PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT) load(userptr, "vkCmdSetExtraPrimitiveOverestimationSizeEXT"); + glad_vkCmdSetLineRasterizationModeEXT = (PFN_vkCmdSetLineRasterizationModeEXT) load(userptr, "vkCmdSetLineRasterizationModeEXT"); + glad_vkCmdSetLineStippleEnableEXT = (PFN_vkCmdSetLineStippleEnableEXT) load(userptr, "vkCmdSetLineStippleEnableEXT"); + glad_vkCmdSetLogicOpEnableEXT = (PFN_vkCmdSetLogicOpEnableEXT) load(userptr, "vkCmdSetLogicOpEnableEXT"); + glad_vkCmdSetPolygonModeEXT = (PFN_vkCmdSetPolygonModeEXT) load(userptr, "vkCmdSetPolygonModeEXT"); + glad_vkCmdSetProvokingVertexModeEXT = (PFN_vkCmdSetProvokingVertexModeEXT) load(userptr, "vkCmdSetProvokingVertexModeEXT"); + glad_vkCmdSetRasterizationSamplesEXT = (PFN_vkCmdSetRasterizationSamplesEXT) load(userptr, "vkCmdSetRasterizationSamplesEXT"); + glad_vkCmdSetRasterizationStreamEXT = (PFN_vkCmdSetRasterizationStreamEXT) load(userptr, "vkCmdSetRasterizationStreamEXT"); + glad_vkCmdSetRepresentativeFragmentTestEnableNV = (PFN_vkCmdSetRepresentativeFragmentTestEnableNV) load(userptr, "vkCmdSetRepresentativeFragmentTestEnableNV"); + glad_vkCmdSetSampleLocationsEnableEXT = (PFN_vkCmdSetSampleLocationsEnableEXT) load(userptr, "vkCmdSetSampleLocationsEnableEXT"); + glad_vkCmdSetSampleMaskEXT = (PFN_vkCmdSetSampleMaskEXT) load(userptr, "vkCmdSetSampleMaskEXT"); + glad_vkCmdSetShadingRateImageEnableNV = (PFN_vkCmdSetShadingRateImageEnableNV) load(userptr, "vkCmdSetShadingRateImageEnableNV"); + glad_vkCmdSetTessellationDomainOriginEXT = (PFN_vkCmdSetTessellationDomainOriginEXT) load(userptr, "vkCmdSetTessellationDomainOriginEXT"); + glad_vkCmdSetViewportSwizzleNV = (PFN_vkCmdSetViewportSwizzleNV) load(userptr, "vkCmdSetViewportSwizzleNV"); + glad_vkCmdSetViewportWScalingEnableNV = (PFN_vkCmdSetViewportWScalingEnableNV) load(userptr, "vkCmdSetViewportWScalingEnableNV"); +} static void glad_vk_load_VK_EXT_external_memory_host( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_external_memory_host) return; glad_vkGetMemoryHostPointerPropertiesEXT = (PFN_vkGetMemoryHostPointerPropertiesEXT) load(userptr, "vkGetMemoryHostPointerPropertiesEXT"); } +#if defined(VK_USE_PLATFORM_METAL_EXT) +static void glad_vk_load_VK_EXT_external_memory_metal( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_external_memory_metal) return; + glad_vkGetMemoryMetalHandleEXT = (PFN_vkGetMemoryMetalHandleEXT) load(userptr, "vkGetMemoryMetalHandleEXT"); + glad_vkGetMemoryMetalHandlePropertiesEXT = (PFN_vkGetMemoryMetalHandlePropertiesEXT) load(userptr, "vkGetMemoryMetalHandlePropertiesEXT"); +} + +#endif +static void glad_vk_load_VK_EXT_fragment_density_map_offset( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_fragment_density_map_offset) return; + glad_vkCmdEndRendering2EXT = (PFN_vkCmdEndRendering2EXT) load(userptr, "vkCmdEndRendering2EXT"); +} #if defined(VK_USE_PLATFORM_WIN32_KHR) static void glad_vk_load_VK_EXT_full_screen_exclusive( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_full_screen_exclusive) return; @@ -1154,6 +1940,7 @@ static void glad_vk_load_VK_EXT_full_screen_exclusive( GLADuserptrloadfunc load, glad_vkGetPhysicalDeviceSurfacePresentModes2EXT = (PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT) load(userptr, "vkGetPhysicalDeviceSurfacePresentModes2EXT"); glad_vkReleaseFullScreenExclusiveModeEXT = (PFN_vkReleaseFullScreenExclusiveModeEXT) load(userptr, "vkReleaseFullScreenExclusiveModeEXT"); } + #endif static void glad_vk_load_VK_EXT_hdr_metadata( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_hdr_metadata) return; @@ -1163,10 +1950,22 @@ static void glad_vk_load_VK_EXT_headless_surface( GLADuserptrloadfunc load, void if(!GLAD_VK_EXT_headless_surface) return; glad_vkCreateHeadlessSurfaceEXT = (PFN_vkCreateHeadlessSurfaceEXT) load(userptr, "vkCreateHeadlessSurfaceEXT"); } +static void glad_vk_load_VK_EXT_host_image_copy( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_host_image_copy) return; + glad_vkCopyImageToImageEXT = (PFN_vkCopyImageToImageEXT) load(userptr, "vkCopyImageToImageEXT"); + glad_vkCopyImageToMemoryEXT = (PFN_vkCopyImageToMemoryEXT) load(userptr, "vkCopyImageToMemoryEXT"); + glad_vkCopyMemoryToImageEXT = (PFN_vkCopyMemoryToImageEXT) load(userptr, "vkCopyMemoryToImageEXT"); + glad_vkGetImageSubresourceLayout2EXT = (PFN_vkGetImageSubresourceLayout2EXT) load(userptr, "vkGetImageSubresourceLayout2EXT"); + glad_vkTransitionImageLayoutEXT = (PFN_vkTransitionImageLayoutEXT) load(userptr, "vkTransitionImageLayoutEXT"); +} static void glad_vk_load_VK_EXT_host_query_reset( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_host_query_reset) return; glad_vkResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT) load(userptr, "vkResetQueryPoolEXT"); } +static void glad_vk_load_VK_EXT_image_compression_control( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_image_compression_control) return; + glad_vkGetImageSubresourceLayout2EXT = (PFN_vkGetImageSubresourceLayout2EXT) load(userptr, "vkGetImageSubresourceLayout2EXT"); +} static void glad_vk_load_VK_EXT_image_drm_format_modifier( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_image_drm_format_modifier) return; glad_vkGetImageDrmFormatModifierPropertiesEXT = (PFN_vkGetImageDrmFormatModifierPropertiesEXT) load(userptr, "vkGetImageDrmFormatModifierPropertiesEXT"); @@ -1175,12 +1974,56 @@ static void glad_vk_load_VK_EXT_line_rasterization( GLADuserptrloadfunc load, vo if(!GLAD_VK_EXT_line_rasterization) return; glad_vkCmdSetLineStippleEXT = (PFN_vkCmdSetLineStippleEXT) load(userptr, "vkCmdSetLineStippleEXT"); } +static void glad_vk_load_VK_EXT_mesh_shader( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_mesh_shader) return; + glad_vkCmdDrawMeshTasksEXT = (PFN_vkCmdDrawMeshTasksEXT) load(userptr, "vkCmdDrawMeshTasksEXT"); + glad_vkCmdDrawMeshTasksIndirectCountEXT = (PFN_vkCmdDrawMeshTasksIndirectCountEXT) load(userptr, "vkCmdDrawMeshTasksIndirectCountEXT"); + glad_vkCmdDrawMeshTasksIndirectEXT = (PFN_vkCmdDrawMeshTasksIndirectEXT) load(userptr, "vkCmdDrawMeshTasksIndirectEXT"); +} +#if defined(VK_USE_PLATFORM_METAL_EXT) +static void glad_vk_load_VK_EXT_metal_objects( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_metal_objects) return; + glad_vkExportMetalObjectsEXT = (PFN_vkExportMetalObjectsEXT) load(userptr, "vkExportMetalObjectsEXT"); +} + +#endif #if defined(VK_USE_PLATFORM_METAL_EXT) static void glad_vk_load_VK_EXT_metal_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_metal_surface) return; glad_vkCreateMetalSurfaceEXT = (PFN_vkCreateMetalSurfaceEXT) load(userptr, "vkCreateMetalSurfaceEXT"); } + #endif +static void glad_vk_load_VK_EXT_multi_draw( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_multi_draw) return; + glad_vkCmdDrawMultiEXT = (PFN_vkCmdDrawMultiEXT) load(userptr, "vkCmdDrawMultiEXT"); + glad_vkCmdDrawMultiIndexedEXT = (PFN_vkCmdDrawMultiIndexedEXT) load(userptr, "vkCmdDrawMultiIndexedEXT"); +} +static void glad_vk_load_VK_EXT_opacity_micromap( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_opacity_micromap) return; + glad_vkBuildMicromapsEXT = (PFN_vkBuildMicromapsEXT) load(userptr, "vkBuildMicromapsEXT"); + glad_vkCmdBuildMicromapsEXT = (PFN_vkCmdBuildMicromapsEXT) load(userptr, "vkCmdBuildMicromapsEXT"); + glad_vkCmdCopyMemoryToMicromapEXT = (PFN_vkCmdCopyMemoryToMicromapEXT) load(userptr, "vkCmdCopyMemoryToMicromapEXT"); + glad_vkCmdCopyMicromapEXT = (PFN_vkCmdCopyMicromapEXT) load(userptr, "vkCmdCopyMicromapEXT"); + glad_vkCmdCopyMicromapToMemoryEXT = (PFN_vkCmdCopyMicromapToMemoryEXT) load(userptr, "vkCmdCopyMicromapToMemoryEXT"); + glad_vkCmdWriteMicromapsPropertiesEXT = (PFN_vkCmdWriteMicromapsPropertiesEXT) load(userptr, "vkCmdWriteMicromapsPropertiesEXT"); + glad_vkCopyMemoryToMicromapEXT = (PFN_vkCopyMemoryToMicromapEXT) load(userptr, "vkCopyMemoryToMicromapEXT"); + glad_vkCopyMicromapEXT = (PFN_vkCopyMicromapEXT) load(userptr, "vkCopyMicromapEXT"); + glad_vkCopyMicromapToMemoryEXT = (PFN_vkCopyMicromapToMemoryEXT) load(userptr, "vkCopyMicromapToMemoryEXT"); + glad_vkCreateMicromapEXT = (PFN_vkCreateMicromapEXT) load(userptr, "vkCreateMicromapEXT"); + glad_vkDestroyMicromapEXT = (PFN_vkDestroyMicromapEXT) load(userptr, "vkDestroyMicromapEXT"); + glad_vkGetDeviceMicromapCompatibilityEXT = (PFN_vkGetDeviceMicromapCompatibilityEXT) load(userptr, "vkGetDeviceMicromapCompatibilityEXT"); + glad_vkGetMicromapBuildSizesEXT = (PFN_vkGetMicromapBuildSizesEXT) load(userptr, "vkGetMicromapBuildSizesEXT"); + glad_vkWriteMicromapsPropertiesEXT = (PFN_vkWriteMicromapsPropertiesEXT) load(userptr, "vkWriteMicromapsPropertiesEXT"); +} +static void glad_vk_load_VK_EXT_pageable_device_local_memory( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_pageable_device_local_memory) return; + glad_vkSetDeviceMemoryPriorityEXT = (PFN_vkSetDeviceMemoryPriorityEXT) load(userptr, "vkSetDeviceMemoryPriorityEXT"); +} +static void glad_vk_load_VK_EXT_pipeline_properties( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_pipeline_properties) return; + glad_vkGetPipelinePropertiesEXT = (PFN_vkGetPipelinePropertiesEXT) load(userptr, "vkGetPipelinePropertiesEXT"); +} static void glad_vk_load_VK_EXT_private_data( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_private_data) return; glad_vkCreatePrivateDataSlotEXT = (PFN_vkCreatePrivateDataSlotEXT) load(userptr, "vkCreatePrivateDataSlotEXT"); @@ -1193,6 +2036,72 @@ static void glad_vk_load_VK_EXT_sample_locations( GLADuserptrloadfunc load, void glad_vkCmdSetSampleLocationsEXT = (PFN_vkCmdSetSampleLocationsEXT) load(userptr, "vkCmdSetSampleLocationsEXT"); glad_vkGetPhysicalDeviceMultisamplePropertiesEXT = (PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT) load(userptr, "vkGetPhysicalDeviceMultisamplePropertiesEXT"); } +static void glad_vk_load_VK_EXT_shader_module_identifier( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_shader_module_identifier) return; + glad_vkGetShaderModuleCreateInfoIdentifierEXT = (PFN_vkGetShaderModuleCreateInfoIdentifierEXT) load(userptr, "vkGetShaderModuleCreateInfoIdentifierEXT"); + glad_vkGetShaderModuleIdentifierEXT = (PFN_vkGetShaderModuleIdentifierEXT) load(userptr, "vkGetShaderModuleIdentifierEXT"); +} +static void glad_vk_load_VK_EXT_shader_object( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_shader_object) return; + glad_vkCmdBindShadersEXT = (PFN_vkCmdBindShadersEXT) load(userptr, "vkCmdBindShadersEXT"); + glad_vkCmdBindVertexBuffers2EXT = (PFN_vkCmdBindVertexBuffers2EXT) load(userptr, "vkCmdBindVertexBuffers2EXT"); + glad_vkCmdSetAlphaToCoverageEnableEXT = (PFN_vkCmdSetAlphaToCoverageEnableEXT) load(userptr, "vkCmdSetAlphaToCoverageEnableEXT"); + glad_vkCmdSetAlphaToOneEnableEXT = (PFN_vkCmdSetAlphaToOneEnableEXT) load(userptr, "vkCmdSetAlphaToOneEnableEXT"); + glad_vkCmdSetColorBlendAdvancedEXT = (PFN_vkCmdSetColorBlendAdvancedEXT) load(userptr, "vkCmdSetColorBlendAdvancedEXT"); + glad_vkCmdSetColorBlendEnableEXT = (PFN_vkCmdSetColorBlendEnableEXT) load(userptr, "vkCmdSetColorBlendEnableEXT"); + glad_vkCmdSetColorBlendEquationEXT = (PFN_vkCmdSetColorBlendEquationEXT) load(userptr, "vkCmdSetColorBlendEquationEXT"); + glad_vkCmdSetColorWriteMaskEXT = (PFN_vkCmdSetColorWriteMaskEXT) load(userptr, "vkCmdSetColorWriteMaskEXT"); + glad_vkCmdSetConservativeRasterizationModeEXT = (PFN_vkCmdSetConservativeRasterizationModeEXT) load(userptr, "vkCmdSetConservativeRasterizationModeEXT"); + glad_vkCmdSetCoverageModulationModeNV = (PFN_vkCmdSetCoverageModulationModeNV) load(userptr, "vkCmdSetCoverageModulationModeNV"); + glad_vkCmdSetCoverageModulationTableEnableNV = (PFN_vkCmdSetCoverageModulationTableEnableNV) load(userptr, "vkCmdSetCoverageModulationTableEnableNV"); + glad_vkCmdSetCoverageModulationTableNV = (PFN_vkCmdSetCoverageModulationTableNV) load(userptr, "vkCmdSetCoverageModulationTableNV"); + glad_vkCmdSetCoverageReductionModeNV = (PFN_vkCmdSetCoverageReductionModeNV) load(userptr, "vkCmdSetCoverageReductionModeNV"); + glad_vkCmdSetCoverageToColorEnableNV = (PFN_vkCmdSetCoverageToColorEnableNV) load(userptr, "vkCmdSetCoverageToColorEnableNV"); + glad_vkCmdSetCoverageToColorLocationNV = (PFN_vkCmdSetCoverageToColorLocationNV) load(userptr, "vkCmdSetCoverageToColorLocationNV"); + glad_vkCmdSetCullModeEXT = (PFN_vkCmdSetCullModeEXT) load(userptr, "vkCmdSetCullModeEXT"); + glad_vkCmdSetDepthBiasEnableEXT = (PFN_vkCmdSetDepthBiasEnableEXT) load(userptr, "vkCmdSetDepthBiasEnableEXT"); + glad_vkCmdSetDepthBoundsTestEnableEXT = (PFN_vkCmdSetDepthBoundsTestEnableEXT) load(userptr, "vkCmdSetDepthBoundsTestEnableEXT"); + glad_vkCmdSetDepthClampEnableEXT = (PFN_vkCmdSetDepthClampEnableEXT) load(userptr, "vkCmdSetDepthClampEnableEXT"); + glad_vkCmdSetDepthClampRangeEXT = (PFN_vkCmdSetDepthClampRangeEXT) load(userptr, "vkCmdSetDepthClampRangeEXT"); + glad_vkCmdSetDepthClipEnableEXT = (PFN_vkCmdSetDepthClipEnableEXT) load(userptr, "vkCmdSetDepthClipEnableEXT"); + glad_vkCmdSetDepthClipNegativeOneToOneEXT = (PFN_vkCmdSetDepthClipNegativeOneToOneEXT) load(userptr, "vkCmdSetDepthClipNegativeOneToOneEXT"); + glad_vkCmdSetDepthCompareOpEXT = (PFN_vkCmdSetDepthCompareOpEXT) load(userptr, "vkCmdSetDepthCompareOpEXT"); + glad_vkCmdSetDepthTestEnableEXT = (PFN_vkCmdSetDepthTestEnableEXT) load(userptr, "vkCmdSetDepthTestEnableEXT"); + glad_vkCmdSetDepthWriteEnableEXT = (PFN_vkCmdSetDepthWriteEnableEXT) load(userptr, "vkCmdSetDepthWriteEnableEXT"); + glad_vkCmdSetExtraPrimitiveOverestimationSizeEXT = (PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT) load(userptr, "vkCmdSetExtraPrimitiveOverestimationSizeEXT"); + glad_vkCmdSetFrontFaceEXT = (PFN_vkCmdSetFrontFaceEXT) load(userptr, "vkCmdSetFrontFaceEXT"); + glad_vkCmdSetLineRasterizationModeEXT = (PFN_vkCmdSetLineRasterizationModeEXT) load(userptr, "vkCmdSetLineRasterizationModeEXT"); + glad_vkCmdSetLineStippleEnableEXT = (PFN_vkCmdSetLineStippleEnableEXT) load(userptr, "vkCmdSetLineStippleEnableEXT"); + glad_vkCmdSetLogicOpEXT = (PFN_vkCmdSetLogicOpEXT) load(userptr, "vkCmdSetLogicOpEXT"); + glad_vkCmdSetLogicOpEnableEXT = (PFN_vkCmdSetLogicOpEnableEXT) load(userptr, "vkCmdSetLogicOpEnableEXT"); + glad_vkCmdSetPatchControlPointsEXT = (PFN_vkCmdSetPatchControlPointsEXT) load(userptr, "vkCmdSetPatchControlPointsEXT"); + glad_vkCmdSetPolygonModeEXT = (PFN_vkCmdSetPolygonModeEXT) load(userptr, "vkCmdSetPolygonModeEXT"); + glad_vkCmdSetPrimitiveRestartEnableEXT = (PFN_vkCmdSetPrimitiveRestartEnableEXT) load(userptr, "vkCmdSetPrimitiveRestartEnableEXT"); + glad_vkCmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT) load(userptr, "vkCmdSetPrimitiveTopologyEXT"); + glad_vkCmdSetProvokingVertexModeEXT = (PFN_vkCmdSetProvokingVertexModeEXT) load(userptr, "vkCmdSetProvokingVertexModeEXT"); + glad_vkCmdSetRasterizationSamplesEXT = (PFN_vkCmdSetRasterizationSamplesEXT) load(userptr, "vkCmdSetRasterizationSamplesEXT"); + glad_vkCmdSetRasterizationStreamEXT = (PFN_vkCmdSetRasterizationStreamEXT) load(userptr, "vkCmdSetRasterizationStreamEXT"); + glad_vkCmdSetRasterizerDiscardEnableEXT = (PFN_vkCmdSetRasterizerDiscardEnableEXT) load(userptr, "vkCmdSetRasterizerDiscardEnableEXT"); + glad_vkCmdSetRepresentativeFragmentTestEnableNV = (PFN_vkCmdSetRepresentativeFragmentTestEnableNV) load(userptr, "vkCmdSetRepresentativeFragmentTestEnableNV"); + glad_vkCmdSetSampleLocationsEnableEXT = (PFN_vkCmdSetSampleLocationsEnableEXT) load(userptr, "vkCmdSetSampleLocationsEnableEXT"); + glad_vkCmdSetSampleMaskEXT = (PFN_vkCmdSetSampleMaskEXT) load(userptr, "vkCmdSetSampleMaskEXT"); + glad_vkCmdSetScissorWithCountEXT = (PFN_vkCmdSetScissorWithCountEXT) load(userptr, "vkCmdSetScissorWithCountEXT"); + glad_vkCmdSetShadingRateImageEnableNV = (PFN_vkCmdSetShadingRateImageEnableNV) load(userptr, "vkCmdSetShadingRateImageEnableNV"); + glad_vkCmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT) load(userptr, "vkCmdSetStencilOpEXT"); + glad_vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT) load(userptr, "vkCmdSetStencilTestEnableEXT"); + glad_vkCmdSetTessellationDomainOriginEXT = (PFN_vkCmdSetTessellationDomainOriginEXT) load(userptr, "vkCmdSetTessellationDomainOriginEXT"); + glad_vkCmdSetVertexInputEXT = (PFN_vkCmdSetVertexInputEXT) load(userptr, "vkCmdSetVertexInputEXT"); + glad_vkCmdSetViewportSwizzleNV = (PFN_vkCmdSetViewportSwizzleNV) load(userptr, "vkCmdSetViewportSwizzleNV"); + glad_vkCmdSetViewportWScalingEnableNV = (PFN_vkCmdSetViewportWScalingEnableNV) load(userptr, "vkCmdSetViewportWScalingEnableNV"); + glad_vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT) load(userptr, "vkCmdSetViewportWithCountEXT"); + glad_vkCreateShadersEXT = (PFN_vkCreateShadersEXT) load(userptr, "vkCreateShadersEXT"); + glad_vkDestroyShaderEXT = (PFN_vkDestroyShaderEXT) load(userptr, "vkDestroyShaderEXT"); + glad_vkGetShaderBinaryDataEXT = (PFN_vkGetShaderBinaryDataEXT) load(userptr, "vkGetShaderBinaryDataEXT"); +} +static void glad_vk_load_VK_EXT_swapchain_maintenance1( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_swapchain_maintenance1) return; + glad_vkReleaseSwapchainImagesEXT = (PFN_vkReleaseSwapchainImagesEXT) load(userptr, "vkReleaseSwapchainImagesEXT"); +} static void glad_vk_load_VK_EXT_tooling_info( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_tooling_info) return; glad_vkGetPhysicalDeviceToolPropertiesEXT = (PFN_vkGetPhysicalDeviceToolPropertiesEXT) load(userptr, "vkGetPhysicalDeviceToolPropertiesEXT"); @@ -1213,23 +2122,70 @@ static void glad_vk_load_VK_EXT_validation_cache( GLADuserptrloadfunc load, void glad_vkGetValidationCacheDataEXT = (PFN_vkGetValidationCacheDataEXT) load(userptr, "vkGetValidationCacheDataEXT"); glad_vkMergeValidationCachesEXT = (PFN_vkMergeValidationCachesEXT) load(userptr, "vkMergeValidationCachesEXT"); } +static void glad_vk_load_VK_EXT_vertex_input_dynamic_state( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_vertex_input_dynamic_state) return; + glad_vkCmdSetVertexInputEXT = (PFN_vkCmdSetVertexInputEXT) load(userptr, "vkCmdSetVertexInputEXT"); +} +#if defined(VK_USE_PLATFORM_FUCHSIA) +static void glad_vk_load_VK_FUCHSIA_buffer_collection( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_FUCHSIA_buffer_collection) return; + glad_vkCreateBufferCollectionFUCHSIA = (PFN_vkCreateBufferCollectionFUCHSIA) load(userptr, "vkCreateBufferCollectionFUCHSIA"); + glad_vkDestroyBufferCollectionFUCHSIA = (PFN_vkDestroyBufferCollectionFUCHSIA) load(userptr, "vkDestroyBufferCollectionFUCHSIA"); + glad_vkGetBufferCollectionPropertiesFUCHSIA = (PFN_vkGetBufferCollectionPropertiesFUCHSIA) load(userptr, "vkGetBufferCollectionPropertiesFUCHSIA"); + glad_vkSetBufferCollectionBufferConstraintsFUCHSIA = (PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA) load(userptr, "vkSetBufferCollectionBufferConstraintsFUCHSIA"); + glad_vkSetBufferCollectionImageConstraintsFUCHSIA = (PFN_vkSetBufferCollectionImageConstraintsFUCHSIA) load(userptr, "vkSetBufferCollectionImageConstraintsFUCHSIA"); +} + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +static void glad_vk_load_VK_FUCHSIA_external_memory( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_FUCHSIA_external_memory) return; + glad_vkGetMemoryZirconHandleFUCHSIA = (PFN_vkGetMemoryZirconHandleFUCHSIA) load(userptr, "vkGetMemoryZirconHandleFUCHSIA"); + glad_vkGetMemoryZirconHandlePropertiesFUCHSIA = (PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA) load(userptr, "vkGetMemoryZirconHandlePropertiesFUCHSIA"); +} + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +static void glad_vk_load_VK_FUCHSIA_external_semaphore( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_FUCHSIA_external_semaphore) return; + glad_vkGetSemaphoreZirconHandleFUCHSIA = (PFN_vkGetSemaphoreZirconHandleFUCHSIA) load(userptr, "vkGetSemaphoreZirconHandleFUCHSIA"); + glad_vkImportSemaphoreZirconHandleFUCHSIA = (PFN_vkImportSemaphoreZirconHandleFUCHSIA) load(userptr, "vkImportSemaphoreZirconHandleFUCHSIA"); +} + +#endif #if defined(VK_USE_PLATFORM_FUCHSIA) static void glad_vk_load_VK_FUCHSIA_imagepipe_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_FUCHSIA_imagepipe_surface) return; glad_vkCreateImagePipeSurfaceFUCHSIA = (PFN_vkCreateImagePipeSurfaceFUCHSIA) load(userptr, "vkCreateImagePipeSurfaceFUCHSIA"); } + #endif #if defined(VK_USE_PLATFORM_GGP) static void glad_vk_load_VK_GGP_stream_descriptor_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_GGP_stream_descriptor_surface) return; glad_vkCreateStreamDescriptorSurfaceGGP = (PFN_vkCreateStreamDescriptorSurfaceGGP) load(userptr, "vkCreateStreamDescriptorSurfaceGGP"); } + #endif static void glad_vk_load_VK_GOOGLE_display_timing( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_GOOGLE_display_timing) return; glad_vkGetPastPresentationTimingGOOGLE = (PFN_vkGetPastPresentationTimingGOOGLE) load(userptr, "vkGetPastPresentationTimingGOOGLE"); glad_vkGetRefreshCycleDurationGOOGLE = (PFN_vkGetRefreshCycleDurationGOOGLE) load(userptr, "vkGetRefreshCycleDurationGOOGLE"); } +static void glad_vk_load_VK_HUAWEI_cluster_culling_shader( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_HUAWEI_cluster_culling_shader) return; + glad_vkCmdDrawClusterHUAWEI = (PFN_vkCmdDrawClusterHUAWEI) load(userptr, "vkCmdDrawClusterHUAWEI"); + glad_vkCmdDrawClusterIndirectHUAWEI = (PFN_vkCmdDrawClusterIndirectHUAWEI) load(userptr, "vkCmdDrawClusterIndirectHUAWEI"); +} +static void glad_vk_load_VK_HUAWEI_invocation_mask( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_HUAWEI_invocation_mask) return; + glad_vkCmdBindInvocationMaskHUAWEI = (PFN_vkCmdBindInvocationMaskHUAWEI) load(userptr, "vkCmdBindInvocationMaskHUAWEI"); +} +static void glad_vk_load_VK_HUAWEI_subpass_shading( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_HUAWEI_subpass_shading) return; + glad_vkCmdSubpassShadingHUAWEI = (PFN_vkCmdSubpassShadingHUAWEI) load(userptr, "vkCmdSubpassShadingHUAWEI"); + glad_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI = (PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI) load(userptr, "vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI"); +} static void glad_vk_load_VK_INTEL_performance_query( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_INTEL_performance_query) return; glad_vkAcquirePerformanceConfigurationINTEL = (PFN_vkAcquirePerformanceConfigurationINTEL) load(userptr, "vkAcquirePerformanceConfigurationINTEL"); @@ -1242,11 +2198,31 @@ static void glad_vk_load_VK_INTEL_performance_query( GLADuserptrloadfunc load, v glad_vkReleasePerformanceConfigurationINTEL = (PFN_vkReleasePerformanceConfigurationINTEL) load(userptr, "vkReleasePerformanceConfigurationINTEL"); glad_vkUninitializePerformanceApiINTEL = (PFN_vkUninitializePerformanceApiINTEL) load(userptr, "vkUninitializePerformanceApiINTEL"); } +static void glad_vk_load_VK_KHR_acceleration_structure( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_acceleration_structure) return; + glad_vkBuildAccelerationStructuresKHR = (PFN_vkBuildAccelerationStructuresKHR) load(userptr, "vkBuildAccelerationStructuresKHR"); + glad_vkCmdBuildAccelerationStructuresIndirectKHR = (PFN_vkCmdBuildAccelerationStructuresIndirectKHR) load(userptr, "vkCmdBuildAccelerationStructuresIndirectKHR"); + glad_vkCmdBuildAccelerationStructuresKHR = (PFN_vkCmdBuildAccelerationStructuresKHR) load(userptr, "vkCmdBuildAccelerationStructuresKHR"); + glad_vkCmdCopyAccelerationStructureKHR = (PFN_vkCmdCopyAccelerationStructureKHR) load(userptr, "vkCmdCopyAccelerationStructureKHR"); + glad_vkCmdCopyAccelerationStructureToMemoryKHR = (PFN_vkCmdCopyAccelerationStructureToMemoryKHR) load(userptr, "vkCmdCopyAccelerationStructureToMemoryKHR"); + glad_vkCmdCopyMemoryToAccelerationStructureKHR = (PFN_vkCmdCopyMemoryToAccelerationStructureKHR) load(userptr, "vkCmdCopyMemoryToAccelerationStructureKHR"); + glad_vkCmdWriteAccelerationStructuresPropertiesKHR = (PFN_vkCmdWriteAccelerationStructuresPropertiesKHR) load(userptr, "vkCmdWriteAccelerationStructuresPropertiesKHR"); + glad_vkCopyAccelerationStructureKHR = (PFN_vkCopyAccelerationStructureKHR) load(userptr, "vkCopyAccelerationStructureKHR"); + glad_vkCopyAccelerationStructureToMemoryKHR = (PFN_vkCopyAccelerationStructureToMemoryKHR) load(userptr, "vkCopyAccelerationStructureToMemoryKHR"); + glad_vkCopyMemoryToAccelerationStructureKHR = (PFN_vkCopyMemoryToAccelerationStructureKHR) load(userptr, "vkCopyMemoryToAccelerationStructureKHR"); + glad_vkCreateAccelerationStructureKHR = (PFN_vkCreateAccelerationStructureKHR) load(userptr, "vkCreateAccelerationStructureKHR"); + glad_vkDestroyAccelerationStructureKHR = (PFN_vkDestroyAccelerationStructureKHR) load(userptr, "vkDestroyAccelerationStructureKHR"); + glad_vkGetAccelerationStructureBuildSizesKHR = (PFN_vkGetAccelerationStructureBuildSizesKHR) load(userptr, "vkGetAccelerationStructureBuildSizesKHR"); + glad_vkGetAccelerationStructureDeviceAddressKHR = (PFN_vkGetAccelerationStructureDeviceAddressKHR) load(userptr, "vkGetAccelerationStructureDeviceAddressKHR"); + glad_vkGetDeviceAccelerationStructureCompatibilityKHR = (PFN_vkGetDeviceAccelerationStructureCompatibilityKHR) load(userptr, "vkGetDeviceAccelerationStructureCompatibilityKHR"); + glad_vkWriteAccelerationStructuresPropertiesKHR = (PFN_vkWriteAccelerationStructuresPropertiesKHR) load(userptr, "vkWriteAccelerationStructuresPropertiesKHR"); +} #if defined(VK_USE_PLATFORM_ANDROID_KHR) static void glad_vk_load_VK_KHR_android_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_android_surface) return; glad_vkCreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR) load(userptr, "vkCreateAndroidSurfaceKHR"); } + #endif static void glad_vk_load_VK_KHR_bind_memory2( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_bind_memory2) return; @@ -1259,6 +2235,24 @@ static void glad_vk_load_VK_KHR_buffer_device_address( GLADuserptrloadfunc load, glad_vkGetBufferOpaqueCaptureAddressKHR = (PFN_vkGetBufferOpaqueCaptureAddressKHR) load(userptr, "vkGetBufferOpaqueCaptureAddressKHR"); glad_vkGetDeviceMemoryOpaqueCaptureAddressKHR = (PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR) load(userptr, "vkGetDeviceMemoryOpaqueCaptureAddressKHR"); } +static void glad_vk_load_VK_KHR_calibrated_timestamps( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_calibrated_timestamps) return; + glad_vkGetCalibratedTimestampsKHR = (PFN_vkGetCalibratedTimestampsKHR) load(userptr, "vkGetCalibratedTimestampsKHR"); + glad_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR = (PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR) load(userptr, "vkGetPhysicalDeviceCalibrateableTimeDomainsKHR"); +} +static void glad_vk_load_VK_KHR_cooperative_matrix( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_cooperative_matrix) return; + glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR = (PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR) load(userptr, "vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR"); +} +static void glad_vk_load_VK_KHR_copy_commands2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_copy_commands2) return; + glad_vkCmdBlitImage2KHR = (PFN_vkCmdBlitImage2KHR) load(userptr, "vkCmdBlitImage2KHR"); + glad_vkCmdCopyBuffer2KHR = (PFN_vkCmdCopyBuffer2KHR) load(userptr, "vkCmdCopyBuffer2KHR"); + glad_vkCmdCopyBufferToImage2KHR = (PFN_vkCmdCopyBufferToImage2KHR) load(userptr, "vkCmdCopyBufferToImage2KHR"); + glad_vkCmdCopyImage2KHR = (PFN_vkCmdCopyImage2KHR) load(userptr, "vkCmdCopyImage2KHR"); + glad_vkCmdCopyImageToBuffer2KHR = (PFN_vkCmdCopyImageToBuffer2KHR) load(userptr, "vkCmdCopyImageToBuffer2KHR"); + glad_vkCmdResolveImage2KHR = (PFN_vkCmdResolveImage2KHR) load(userptr, "vkCmdResolveImage2KHR"); +} static void glad_vk_load_VK_KHR_create_renderpass2( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_create_renderpass2) return; glad_vkCmdBeginRenderPass2KHR = (PFN_vkCmdBeginRenderPass2KHR) load(userptr, "vkCmdBeginRenderPass2KHR"); @@ -1266,7 +2260,6 @@ static void glad_vk_load_VK_KHR_create_renderpass2( GLADuserptrloadfunc load, vo glad_vkCmdNextSubpass2KHR = (PFN_vkCmdNextSubpass2KHR) load(userptr, "vkCmdNextSubpass2KHR"); glad_vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR) load(userptr, "vkCreateRenderPass2KHR"); } -#if defined(VK_ENABLE_BETA_EXTENSIONS) static void glad_vk_load_VK_KHR_deferred_host_operations( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_deferred_host_operations) return; glad_vkCreateDeferredOperationKHR = (PFN_vkCreateDeferredOperationKHR) load(userptr, "vkCreateDeferredOperationKHR"); @@ -1275,7 +2268,6 @@ static void glad_vk_load_VK_KHR_deferred_host_operations( GLADuserptrloadfunc lo glad_vkGetDeferredOperationMaxConcurrencyKHR = (PFN_vkGetDeferredOperationMaxConcurrencyKHR) load(userptr, "vkGetDeferredOperationMaxConcurrencyKHR"); glad_vkGetDeferredOperationResultKHR = (PFN_vkGetDeferredOperationResultKHR) load(userptr, "vkGetDeferredOperationResultKHR"); } -#endif static void glad_vk_load_VK_KHR_descriptor_update_template( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_descriptor_update_template) return; glad_vkCmdPushDescriptorSetWithTemplateKHR = (PFN_vkCmdPushDescriptorSetWithTemplateKHR) load(userptr, "vkCmdPushDescriptorSetWithTemplateKHR"); @@ -1316,6 +2308,16 @@ static void glad_vk_load_VK_KHR_draw_indirect_count( GLADuserptrloadfunc load, v glad_vkCmdDrawIndexedIndirectCountKHR = (PFN_vkCmdDrawIndexedIndirectCountKHR) load(userptr, "vkCmdDrawIndexedIndirectCountKHR"); glad_vkCmdDrawIndirectCountKHR = (PFN_vkCmdDrawIndirectCountKHR) load(userptr, "vkCmdDrawIndirectCountKHR"); } +static void glad_vk_load_VK_KHR_dynamic_rendering( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_dynamic_rendering) return; + glad_vkCmdBeginRenderingKHR = (PFN_vkCmdBeginRenderingKHR) load(userptr, "vkCmdBeginRenderingKHR"); + glad_vkCmdEndRenderingKHR = (PFN_vkCmdEndRenderingKHR) load(userptr, "vkCmdEndRenderingKHR"); +} +static void glad_vk_load_VK_KHR_dynamic_rendering_local_read( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_dynamic_rendering_local_read) return; + glad_vkCmdSetRenderingAttachmentLocationsKHR = (PFN_vkCmdSetRenderingAttachmentLocationsKHR) load(userptr, "vkCmdSetRenderingAttachmentLocationsKHR"); + glad_vkCmdSetRenderingInputAttachmentIndicesKHR = (PFN_vkCmdSetRenderingInputAttachmentIndicesKHR) load(userptr, "vkCmdSetRenderingInputAttachmentIndicesKHR"); +} static void glad_vk_load_VK_KHR_external_fence_capabilities( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_external_fence_capabilities) return; glad_vkGetPhysicalDeviceExternalFencePropertiesKHR = (PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR) load(userptr, "vkGetPhysicalDeviceExternalFencePropertiesKHR"); @@ -1331,6 +2333,7 @@ static void glad_vk_load_VK_KHR_external_fence_win32( GLADuserptrloadfunc load, glad_vkGetFenceWin32HandleKHR = (PFN_vkGetFenceWin32HandleKHR) load(userptr, "vkGetFenceWin32HandleKHR"); glad_vkImportFenceWin32HandleKHR = (PFN_vkImportFenceWin32HandleKHR) load(userptr, "vkImportFenceWin32HandleKHR"); } + #endif static void glad_vk_load_VK_KHR_external_memory_capabilities( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_external_memory_capabilities) return; @@ -1347,6 +2350,7 @@ static void glad_vk_load_VK_KHR_external_memory_win32( GLADuserptrloadfunc load, glad_vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR) load(userptr, "vkGetMemoryWin32HandleKHR"); glad_vkGetMemoryWin32HandlePropertiesKHR = (PFN_vkGetMemoryWin32HandlePropertiesKHR) load(userptr, "vkGetMemoryWin32HandlePropertiesKHR"); } + #endif static void glad_vk_load_VK_KHR_external_semaphore_capabilities( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_external_semaphore_capabilities) return; @@ -1363,7 +2367,13 @@ static void glad_vk_load_VK_KHR_external_semaphore_win32( GLADuserptrloadfunc lo glad_vkGetSemaphoreWin32HandleKHR = (PFN_vkGetSemaphoreWin32HandleKHR) load(userptr, "vkGetSemaphoreWin32HandleKHR"); glad_vkImportSemaphoreWin32HandleKHR = (PFN_vkImportSemaphoreWin32HandleKHR) load(userptr, "vkImportSemaphoreWin32HandleKHR"); } + #endif +static void glad_vk_load_VK_KHR_fragment_shading_rate( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_fragment_shading_rate) return; + glad_vkCmdSetFragmentShadingRateKHR = (PFN_vkCmdSetFragmentShadingRateKHR) load(userptr, "vkCmdSetFragmentShadingRateKHR"); + glad_vkGetPhysicalDeviceFragmentShadingRatesKHR = (PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR) load(userptr, "vkGetPhysicalDeviceFragmentShadingRatesKHR"); +} static void glad_vk_load_VK_KHR_get_display_properties2( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_get_display_properties2) return; glad_vkGetDisplayModeProperties2KHR = (PFN_vkGetDisplayModeProperties2KHR) load(userptr, "vkGetDisplayModeProperties2KHR"); @@ -1392,6 +2402,10 @@ static void glad_vk_load_VK_KHR_get_surface_capabilities2( GLADuserptrloadfunc l glad_vkGetPhysicalDeviceSurfaceCapabilities2KHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR) load(userptr, "vkGetPhysicalDeviceSurfaceCapabilities2KHR"); glad_vkGetPhysicalDeviceSurfaceFormats2KHR = (PFN_vkGetPhysicalDeviceSurfaceFormats2KHR) load(userptr, "vkGetPhysicalDeviceSurfaceFormats2KHR"); } +static void glad_vk_load_VK_KHR_line_rasterization( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_line_rasterization) return; + glad_vkCmdSetLineStippleKHR = (PFN_vkCmdSetLineStippleKHR) load(userptr, "vkCmdSetLineStippleKHR"); +} static void glad_vk_load_VK_KHR_maintenance1( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_maintenance1) return; glad_vkTrimCommandPoolKHR = (PFN_vkTrimCommandPoolKHR) load(userptr, "vkTrimCommandPoolKHR"); @@ -1400,6 +2414,33 @@ static void glad_vk_load_VK_KHR_maintenance3( GLADuserptrloadfunc load, void* us if(!GLAD_VK_KHR_maintenance3) return; glad_vkGetDescriptorSetLayoutSupportKHR = (PFN_vkGetDescriptorSetLayoutSupportKHR) load(userptr, "vkGetDescriptorSetLayoutSupportKHR"); } +static void glad_vk_load_VK_KHR_maintenance4( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_maintenance4) return; + glad_vkGetDeviceBufferMemoryRequirementsKHR = (PFN_vkGetDeviceBufferMemoryRequirementsKHR) load(userptr, "vkGetDeviceBufferMemoryRequirementsKHR"); + glad_vkGetDeviceImageMemoryRequirementsKHR = (PFN_vkGetDeviceImageMemoryRequirementsKHR) load(userptr, "vkGetDeviceImageMemoryRequirementsKHR"); + glad_vkGetDeviceImageSparseMemoryRequirementsKHR = (PFN_vkGetDeviceImageSparseMemoryRequirementsKHR) load(userptr, "vkGetDeviceImageSparseMemoryRequirementsKHR"); +} +static void glad_vk_load_VK_KHR_maintenance5( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_maintenance5) return; + glad_vkCmdBindIndexBuffer2KHR = (PFN_vkCmdBindIndexBuffer2KHR) load(userptr, "vkCmdBindIndexBuffer2KHR"); + glad_vkGetDeviceImageSubresourceLayoutKHR = (PFN_vkGetDeviceImageSubresourceLayoutKHR) load(userptr, "vkGetDeviceImageSubresourceLayoutKHR"); + glad_vkGetImageSubresourceLayout2KHR = (PFN_vkGetImageSubresourceLayout2KHR) load(userptr, "vkGetImageSubresourceLayout2KHR"); + glad_vkGetRenderingAreaGranularityKHR = (PFN_vkGetRenderingAreaGranularityKHR) load(userptr, "vkGetRenderingAreaGranularityKHR"); +} +static void glad_vk_load_VK_KHR_maintenance6( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_maintenance6) return; + glad_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT = (PFN_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT) load(userptr, "vkCmdBindDescriptorBufferEmbeddedSamplers2EXT"); + glad_vkCmdBindDescriptorSets2KHR = (PFN_vkCmdBindDescriptorSets2KHR) load(userptr, "vkCmdBindDescriptorSets2KHR"); + glad_vkCmdPushConstants2KHR = (PFN_vkCmdPushConstants2KHR) load(userptr, "vkCmdPushConstants2KHR"); + glad_vkCmdPushDescriptorSet2KHR = (PFN_vkCmdPushDescriptorSet2KHR) load(userptr, "vkCmdPushDescriptorSet2KHR"); + glad_vkCmdPushDescriptorSetWithTemplate2KHR = (PFN_vkCmdPushDescriptorSetWithTemplate2KHR) load(userptr, "vkCmdPushDescriptorSetWithTemplate2KHR"); + glad_vkCmdSetDescriptorBufferOffsets2EXT = (PFN_vkCmdSetDescriptorBufferOffsets2EXT) load(userptr, "vkCmdSetDescriptorBufferOffsets2EXT"); +} +static void glad_vk_load_VK_KHR_map_memory2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_map_memory2) return; + glad_vkMapMemory2KHR = (PFN_vkMapMemory2KHR) load(userptr, "vkMapMemory2KHR"); + glad_vkUnmapMemory2KHR = (PFN_vkUnmapMemory2KHR) load(userptr, "vkUnmapMemory2KHR"); +} static void glad_vk_load_VK_KHR_performance_query( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_performance_query) return; glad_vkAcquireProfilingLockKHR = (PFN_vkAcquireProfilingLockKHR) load(userptr, "vkAcquireProfilingLockKHR"); @@ -1407,44 +2448,43 @@ static void glad_vk_load_VK_KHR_performance_query( GLADuserptrloadfunc load, voi glad_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR = (PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR) load(userptr, "vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR"); glad_vkReleaseProfilingLockKHR = (PFN_vkReleaseProfilingLockKHR) load(userptr, "vkReleaseProfilingLockKHR"); } +static void glad_vk_load_VK_KHR_pipeline_binary( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_pipeline_binary) return; + glad_vkCreatePipelineBinariesKHR = (PFN_vkCreatePipelineBinariesKHR) load(userptr, "vkCreatePipelineBinariesKHR"); + glad_vkDestroyPipelineBinaryKHR = (PFN_vkDestroyPipelineBinaryKHR) load(userptr, "vkDestroyPipelineBinaryKHR"); + glad_vkGetPipelineBinaryDataKHR = (PFN_vkGetPipelineBinaryDataKHR) load(userptr, "vkGetPipelineBinaryDataKHR"); + glad_vkGetPipelineKeyKHR = (PFN_vkGetPipelineKeyKHR) load(userptr, "vkGetPipelineKeyKHR"); + glad_vkReleaseCapturedPipelineDataKHR = (PFN_vkReleaseCapturedPipelineDataKHR) load(userptr, "vkReleaseCapturedPipelineDataKHR"); +} static void glad_vk_load_VK_KHR_pipeline_executable_properties( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_pipeline_executable_properties) return; glad_vkGetPipelineExecutableInternalRepresentationsKHR = (PFN_vkGetPipelineExecutableInternalRepresentationsKHR) load(userptr, "vkGetPipelineExecutableInternalRepresentationsKHR"); glad_vkGetPipelineExecutablePropertiesKHR = (PFN_vkGetPipelineExecutablePropertiesKHR) load(userptr, "vkGetPipelineExecutablePropertiesKHR"); glad_vkGetPipelineExecutableStatisticsKHR = (PFN_vkGetPipelineExecutableStatisticsKHR) load(userptr, "vkGetPipelineExecutableStatisticsKHR"); } +static void glad_vk_load_VK_KHR_present_wait( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_present_wait) return; + glad_vkWaitForPresentKHR = (PFN_vkWaitForPresentKHR) load(userptr, "vkWaitForPresentKHR"); +} static void glad_vk_load_VK_KHR_push_descriptor( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_push_descriptor) return; glad_vkCmdPushDescriptorSetKHR = (PFN_vkCmdPushDescriptorSetKHR) load(userptr, "vkCmdPushDescriptorSetKHR"); glad_vkCmdPushDescriptorSetWithTemplateKHR = (PFN_vkCmdPushDescriptorSetWithTemplateKHR) load(userptr, "vkCmdPushDescriptorSetWithTemplateKHR"); } -#if defined(VK_ENABLE_BETA_EXTENSIONS) -static void glad_vk_load_VK_KHR_ray_tracing( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_VK_KHR_ray_tracing) return; - glad_vkBindAccelerationStructureMemoryKHR = (PFN_vkBindAccelerationStructureMemoryKHR) load(userptr, "vkBindAccelerationStructureMemoryKHR"); - glad_vkBuildAccelerationStructureKHR = (PFN_vkBuildAccelerationStructureKHR) load(userptr, "vkBuildAccelerationStructureKHR"); - glad_vkCmdBuildAccelerationStructureIndirectKHR = (PFN_vkCmdBuildAccelerationStructureIndirectKHR) load(userptr, "vkCmdBuildAccelerationStructureIndirectKHR"); - glad_vkCmdBuildAccelerationStructureKHR = (PFN_vkCmdBuildAccelerationStructureKHR) load(userptr, "vkCmdBuildAccelerationStructureKHR"); - glad_vkCmdCopyAccelerationStructureKHR = (PFN_vkCmdCopyAccelerationStructureKHR) load(userptr, "vkCmdCopyAccelerationStructureKHR"); - glad_vkCmdCopyAccelerationStructureToMemoryKHR = (PFN_vkCmdCopyAccelerationStructureToMemoryKHR) load(userptr, "vkCmdCopyAccelerationStructureToMemoryKHR"); - glad_vkCmdCopyMemoryToAccelerationStructureKHR = (PFN_vkCmdCopyMemoryToAccelerationStructureKHR) load(userptr, "vkCmdCopyMemoryToAccelerationStructureKHR"); +static void glad_vk_load_VK_KHR_ray_tracing_maintenance1( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_ray_tracing_maintenance1) return; + glad_vkCmdTraceRaysIndirect2KHR = (PFN_vkCmdTraceRaysIndirect2KHR) load(userptr, "vkCmdTraceRaysIndirect2KHR"); +} +static void glad_vk_load_VK_KHR_ray_tracing_pipeline( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_ray_tracing_pipeline) return; + glad_vkCmdSetRayTracingPipelineStackSizeKHR = (PFN_vkCmdSetRayTracingPipelineStackSizeKHR) load(userptr, "vkCmdSetRayTracingPipelineStackSizeKHR"); glad_vkCmdTraceRaysIndirectKHR = (PFN_vkCmdTraceRaysIndirectKHR) load(userptr, "vkCmdTraceRaysIndirectKHR"); glad_vkCmdTraceRaysKHR = (PFN_vkCmdTraceRaysKHR) load(userptr, "vkCmdTraceRaysKHR"); - glad_vkCmdWriteAccelerationStructuresPropertiesKHR = (PFN_vkCmdWriteAccelerationStructuresPropertiesKHR) load(userptr, "vkCmdWriteAccelerationStructuresPropertiesKHR"); - glad_vkCopyAccelerationStructureKHR = (PFN_vkCopyAccelerationStructureKHR) load(userptr, "vkCopyAccelerationStructureKHR"); - glad_vkCopyAccelerationStructureToMemoryKHR = (PFN_vkCopyAccelerationStructureToMemoryKHR) load(userptr, "vkCopyAccelerationStructureToMemoryKHR"); - glad_vkCopyMemoryToAccelerationStructureKHR = (PFN_vkCopyMemoryToAccelerationStructureKHR) load(userptr, "vkCopyMemoryToAccelerationStructureKHR"); - glad_vkCreateAccelerationStructureKHR = (PFN_vkCreateAccelerationStructureKHR) load(userptr, "vkCreateAccelerationStructureKHR"); glad_vkCreateRayTracingPipelinesKHR = (PFN_vkCreateRayTracingPipelinesKHR) load(userptr, "vkCreateRayTracingPipelinesKHR"); - glad_vkDestroyAccelerationStructureKHR = (PFN_vkDestroyAccelerationStructureKHR) load(userptr, "vkDestroyAccelerationStructureKHR"); - glad_vkGetAccelerationStructureDeviceAddressKHR = (PFN_vkGetAccelerationStructureDeviceAddressKHR) load(userptr, "vkGetAccelerationStructureDeviceAddressKHR"); - glad_vkGetAccelerationStructureMemoryRequirementsKHR = (PFN_vkGetAccelerationStructureMemoryRequirementsKHR) load(userptr, "vkGetAccelerationStructureMemoryRequirementsKHR"); - glad_vkGetDeviceAccelerationStructureCompatibilityKHR = (PFN_vkGetDeviceAccelerationStructureCompatibilityKHR) load(userptr, "vkGetDeviceAccelerationStructureCompatibilityKHR"); glad_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR = (PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR) load(userptr, "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR"); glad_vkGetRayTracingShaderGroupHandlesKHR = (PFN_vkGetRayTracingShaderGroupHandlesKHR) load(userptr, "vkGetRayTracingShaderGroupHandlesKHR"); - glad_vkWriteAccelerationStructuresPropertiesKHR = (PFN_vkWriteAccelerationStructuresPropertiesKHR) load(userptr, "vkWriteAccelerationStructuresPropertiesKHR"); + glad_vkGetRayTracingShaderGroupStackSizeKHR = (PFN_vkGetRayTracingShaderGroupStackSizeKHR) load(userptr, "vkGetRayTracingShaderGroupStackSizeKHR"); } -#endif static void glad_vk_load_VK_KHR_sampler_ycbcr_conversion( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_sampler_ycbcr_conversion) return; glad_vkCreateSamplerYcbcrConversionKHR = (PFN_vkCreateSamplerYcbcrConversionKHR) load(userptr, "vkCreateSamplerYcbcrConversionKHR"); @@ -1474,6 +2514,15 @@ static void glad_vk_load_VK_KHR_swapchain( GLADuserptrloadfunc load, void* userp glad_vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR) load(userptr, "vkGetSwapchainImagesKHR"); glad_vkQueuePresentKHR = (PFN_vkQueuePresentKHR) load(userptr, "vkQueuePresentKHR"); } +static void glad_vk_load_VK_KHR_synchronization2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_synchronization2) return; + glad_vkCmdPipelineBarrier2KHR = (PFN_vkCmdPipelineBarrier2KHR) load(userptr, "vkCmdPipelineBarrier2KHR"); + glad_vkCmdResetEvent2KHR = (PFN_vkCmdResetEvent2KHR) load(userptr, "vkCmdResetEvent2KHR"); + glad_vkCmdSetEvent2KHR = (PFN_vkCmdSetEvent2KHR) load(userptr, "vkCmdSetEvent2KHR"); + glad_vkCmdWaitEvents2KHR = (PFN_vkCmdWaitEvents2KHR) load(userptr, "vkCmdWaitEvents2KHR"); + glad_vkCmdWriteTimestamp2KHR = (PFN_vkCmdWriteTimestamp2KHR) load(userptr, "vkCmdWriteTimestamp2KHR"); + glad_vkQueueSubmit2KHR = (PFN_vkQueueSubmit2KHR) load(userptr, "vkQueueSubmit2KHR"); +} static void glad_vk_load_VK_KHR_timeline_semaphore( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_timeline_semaphore) return; glad_vkGetSemaphoreCounterValueKHR = (PFN_vkGetSemaphoreCounterValueKHR) load(userptr, "vkGetSemaphoreCounterValueKHR"); @@ -1486,6 +2535,7 @@ static void glad_vk_load_VK_KHR_wayland_surface( GLADuserptrloadfunc load, void* glad_vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR) load(userptr, "vkCreateWaylandSurfaceKHR"); glad_vkGetPhysicalDeviceWaylandPresentationSupportKHR = (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR) load(userptr, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); } + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) static void glad_vk_load_VK_KHR_win32_surface( GLADuserptrloadfunc load, void* userptr) { @@ -1493,6 +2543,7 @@ static void glad_vk_load_VK_KHR_win32_surface( GLADuserptrloadfunc load, void* u glad_vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) load(userptr, "vkCreateWin32SurfaceKHR"); glad_vkGetPhysicalDeviceWin32PresentationSupportKHR = (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR) load(userptr, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); } + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) static void glad_vk_load_VK_KHR_xcb_surface( GLADuserptrloadfunc load, void* userptr) { @@ -1500,6 +2551,7 @@ static void glad_vk_load_VK_KHR_xcb_surface( GLADuserptrloadfunc load, void* use glad_vkCreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR) load(userptr, "vkCreateXcbSurfaceKHR"); glad_vkGetPhysicalDeviceXcbPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) load(userptr, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); } + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) static void glad_vk_load_VK_KHR_xlib_surface( GLADuserptrloadfunc load, void* userptr) { @@ -1507,45 +2559,99 @@ static void glad_vk_load_VK_KHR_xlib_surface( GLADuserptrloadfunc load, void* us glad_vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR) load(userptr, "vkCreateXlibSurfaceKHR"); glad_vkGetPhysicalDeviceXlibPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR) load(userptr, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); } + #endif #if defined(VK_USE_PLATFORM_IOS_MVK) static void glad_vk_load_VK_MVK_ios_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_MVK_ios_surface) return; glad_vkCreateIOSSurfaceMVK = (PFN_vkCreateIOSSurfaceMVK) load(userptr, "vkCreateIOSSurfaceMVK"); } + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) static void glad_vk_load_VK_MVK_macos_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_MVK_macos_surface) return; glad_vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK) load(userptr, "vkCreateMacOSSurfaceMVK"); } + #endif #if defined(VK_USE_PLATFORM_VI_NN) static void glad_vk_load_VK_NN_vi_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NN_vi_surface) return; glad_vkCreateViSurfaceNN = (PFN_vkCreateViSurfaceNN) load(userptr, "vkCreateViSurfaceNN"); } + #endif +static void glad_vk_load_VK_NVX_binary_import( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NVX_binary_import) return; + glad_vkCmdCuLaunchKernelNVX = (PFN_vkCmdCuLaunchKernelNVX) load(userptr, "vkCmdCuLaunchKernelNVX"); + glad_vkCreateCuFunctionNVX = (PFN_vkCreateCuFunctionNVX) load(userptr, "vkCreateCuFunctionNVX"); + glad_vkCreateCuModuleNVX = (PFN_vkCreateCuModuleNVX) load(userptr, "vkCreateCuModuleNVX"); + glad_vkDestroyCuFunctionNVX = (PFN_vkDestroyCuFunctionNVX) load(userptr, "vkDestroyCuFunctionNVX"); + glad_vkDestroyCuModuleNVX = (PFN_vkDestroyCuModuleNVX) load(userptr, "vkDestroyCuModuleNVX"); +} static void glad_vk_load_VK_NVX_image_view_handle( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NVX_image_view_handle) return; glad_vkGetImageViewAddressNVX = (PFN_vkGetImageViewAddressNVX) load(userptr, "vkGetImageViewAddressNVX"); + glad_vkGetImageViewHandle64NVX = (PFN_vkGetImageViewHandle64NVX) load(userptr, "vkGetImageViewHandle64NVX"); glad_vkGetImageViewHandleNVX = (PFN_vkGetImageViewHandleNVX) load(userptr, "vkGetImageViewHandleNVX"); } +#if defined(VK_USE_PLATFORM_WIN32_KHR) +static void glad_vk_load_VK_NV_acquire_winrt_display( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_acquire_winrt_display) return; + glad_vkAcquireWinrtDisplayNV = (PFN_vkAcquireWinrtDisplayNV) load(userptr, "vkAcquireWinrtDisplayNV"); + glad_vkGetWinrtDisplayNV = (PFN_vkGetWinrtDisplayNV) load(userptr, "vkGetWinrtDisplayNV"); +} + +#endif static void glad_vk_load_VK_NV_clip_space_w_scaling( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_clip_space_w_scaling) return; glad_vkCmdSetViewportWScalingNV = (PFN_vkCmdSetViewportWScalingNV) load(userptr, "vkCmdSetViewportWScalingNV"); } +static void glad_vk_load_VK_NV_cluster_acceleration_structure( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_cluster_acceleration_structure) return; + glad_vkCmdBuildClusterAccelerationStructureIndirectNV = (PFN_vkCmdBuildClusterAccelerationStructureIndirectNV) load(userptr, "vkCmdBuildClusterAccelerationStructureIndirectNV"); + glad_vkGetClusterAccelerationStructureBuildSizesNV = (PFN_vkGetClusterAccelerationStructureBuildSizesNV) load(userptr, "vkGetClusterAccelerationStructureBuildSizesNV"); +} static void glad_vk_load_VK_NV_cooperative_matrix( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_cooperative_matrix) return; glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV = (PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV) load(userptr, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV"); } +static void glad_vk_load_VK_NV_cooperative_matrix2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_cooperative_matrix2) return; + glad_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV = (PFN_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV) load(userptr, "vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV"); +} +static void glad_vk_load_VK_NV_cooperative_vector( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_cooperative_vector) return; + glad_vkCmdConvertCooperativeVectorMatrixNV = (PFN_vkCmdConvertCooperativeVectorMatrixNV) load(userptr, "vkCmdConvertCooperativeVectorMatrixNV"); + glad_vkConvertCooperativeVectorMatrixNV = (PFN_vkConvertCooperativeVectorMatrixNV) load(userptr, "vkConvertCooperativeVectorMatrixNV"); + glad_vkGetPhysicalDeviceCooperativeVectorPropertiesNV = (PFN_vkGetPhysicalDeviceCooperativeVectorPropertiesNV) load(userptr, "vkGetPhysicalDeviceCooperativeVectorPropertiesNV"); +} +static void glad_vk_load_VK_NV_copy_memory_indirect( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_copy_memory_indirect) return; + glad_vkCmdCopyMemoryIndirectNV = (PFN_vkCmdCopyMemoryIndirectNV) load(userptr, "vkCmdCopyMemoryIndirectNV"); + glad_vkCmdCopyMemoryToImageIndirectNV = (PFN_vkCmdCopyMemoryToImageIndirectNV) load(userptr, "vkCmdCopyMemoryToImageIndirectNV"); +} static void glad_vk_load_VK_NV_coverage_reduction_mode( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_coverage_reduction_mode) return; glad_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV = (PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV) load(userptr, "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV"); } +#if defined(VK_ENABLE_BETA_EXTENSIONS) +static void glad_vk_load_VK_NV_cuda_kernel_launch( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_cuda_kernel_launch) return; + glad_vkCmdCudaLaunchKernelNV = (PFN_vkCmdCudaLaunchKernelNV) load(userptr, "vkCmdCudaLaunchKernelNV"); + glad_vkCreateCudaFunctionNV = (PFN_vkCreateCudaFunctionNV) load(userptr, "vkCreateCudaFunctionNV"); + glad_vkCreateCudaModuleNV = (PFN_vkCreateCudaModuleNV) load(userptr, "vkCreateCudaModuleNV"); + glad_vkDestroyCudaFunctionNV = (PFN_vkDestroyCudaFunctionNV) load(userptr, "vkDestroyCudaFunctionNV"); + glad_vkDestroyCudaModuleNV = (PFN_vkDestroyCudaModuleNV) load(userptr, "vkDestroyCudaModuleNV"); + glad_vkGetCudaModuleCacheNV = (PFN_vkGetCudaModuleCacheNV) load(userptr, "vkGetCudaModuleCacheNV"); +} + +#endif static void glad_vk_load_VK_NV_device_diagnostic_checkpoints( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_device_diagnostic_checkpoints) return; glad_vkCmdSetCheckpointNV = (PFN_vkCmdSetCheckpointNV) load(userptr, "vkCmdSetCheckpointNV"); + glad_vkGetQueueCheckpointData2NV = (PFN_vkGetQueueCheckpointData2NV) load(userptr, "vkGetQueueCheckpointData2NV"); glad_vkGetQueueCheckpointDataNV = (PFN_vkGetQueueCheckpointDataNV) load(userptr, "vkGetQueueCheckpointDataNV"); } static void glad_vk_load_VK_NV_device_generated_commands( GLADuserptrloadfunc load, void* userptr) { @@ -1557,22 +2663,69 @@ static void glad_vk_load_VK_NV_device_generated_commands( GLADuserptrloadfunc lo glad_vkDestroyIndirectCommandsLayoutNV = (PFN_vkDestroyIndirectCommandsLayoutNV) load(userptr, "vkDestroyIndirectCommandsLayoutNV"); glad_vkGetGeneratedCommandsMemoryRequirementsNV = (PFN_vkGetGeneratedCommandsMemoryRequirementsNV) load(userptr, "vkGetGeneratedCommandsMemoryRequirementsNV"); } +static void glad_vk_load_VK_NV_device_generated_commands_compute( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_device_generated_commands_compute) return; + glad_vkCmdUpdatePipelineIndirectBufferNV = (PFN_vkCmdUpdatePipelineIndirectBufferNV) load(userptr, "vkCmdUpdatePipelineIndirectBufferNV"); + glad_vkGetPipelineIndirectDeviceAddressNV = (PFN_vkGetPipelineIndirectDeviceAddressNV) load(userptr, "vkGetPipelineIndirectDeviceAddressNV"); + glad_vkGetPipelineIndirectMemoryRequirementsNV = (PFN_vkGetPipelineIndirectMemoryRequirementsNV) load(userptr, "vkGetPipelineIndirectMemoryRequirementsNV"); +} +static void glad_vk_load_VK_NV_external_compute_queue( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_external_compute_queue) return; + glad_vkCreateExternalComputeQueueNV = (PFN_vkCreateExternalComputeQueueNV) load(userptr, "vkCreateExternalComputeQueueNV"); + glad_vkDestroyExternalComputeQueueNV = (PFN_vkDestroyExternalComputeQueueNV) load(userptr, "vkDestroyExternalComputeQueueNV"); + glad_vkGetExternalComputeQueueDataNV = (PFN_vkGetExternalComputeQueueDataNV) load(userptr, "vkGetExternalComputeQueueDataNV"); +} static void glad_vk_load_VK_NV_external_memory_capabilities( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_external_memory_capabilities) return; glad_vkGetPhysicalDeviceExternalImageFormatPropertiesNV = (PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV) load(userptr, "vkGetPhysicalDeviceExternalImageFormatPropertiesNV"); } +static void glad_vk_load_VK_NV_external_memory_rdma( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_external_memory_rdma) return; + glad_vkGetMemoryRemoteAddressNV = (PFN_vkGetMemoryRemoteAddressNV) load(userptr, "vkGetMemoryRemoteAddressNV"); +} #if defined(VK_USE_PLATFORM_WIN32_KHR) static void glad_vk_load_VK_NV_external_memory_win32( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_external_memory_win32) return; glad_vkGetMemoryWin32HandleNV = (PFN_vkGetMemoryWin32HandleNV) load(userptr, "vkGetMemoryWin32HandleNV"); } + #endif +static void glad_vk_load_VK_NV_fragment_shading_rate_enums( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_fragment_shading_rate_enums) return; + glad_vkCmdSetFragmentShadingRateEnumNV = (PFN_vkCmdSetFragmentShadingRateEnumNV) load(userptr, "vkCmdSetFragmentShadingRateEnumNV"); +} +static void glad_vk_load_VK_NV_low_latency2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_low_latency2) return; + glad_vkGetLatencyTimingsNV = (PFN_vkGetLatencyTimingsNV) load(userptr, "vkGetLatencyTimingsNV"); + glad_vkLatencySleepNV = (PFN_vkLatencySleepNV) load(userptr, "vkLatencySleepNV"); + glad_vkQueueNotifyOutOfBandNV = (PFN_vkQueueNotifyOutOfBandNV) load(userptr, "vkQueueNotifyOutOfBandNV"); + glad_vkSetLatencyMarkerNV = (PFN_vkSetLatencyMarkerNV) load(userptr, "vkSetLatencyMarkerNV"); + glad_vkSetLatencySleepModeNV = (PFN_vkSetLatencySleepModeNV) load(userptr, "vkSetLatencySleepModeNV"); +} +static void glad_vk_load_VK_NV_memory_decompression( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_memory_decompression) return; + glad_vkCmdDecompressMemoryIndirectCountNV = (PFN_vkCmdDecompressMemoryIndirectCountNV) load(userptr, "vkCmdDecompressMemoryIndirectCountNV"); + glad_vkCmdDecompressMemoryNV = (PFN_vkCmdDecompressMemoryNV) load(userptr, "vkCmdDecompressMemoryNV"); +} static void glad_vk_load_VK_NV_mesh_shader( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_mesh_shader) return; glad_vkCmdDrawMeshTasksIndirectCountNV = (PFN_vkCmdDrawMeshTasksIndirectCountNV) load(userptr, "vkCmdDrawMeshTasksIndirectCountNV"); glad_vkCmdDrawMeshTasksIndirectNV = (PFN_vkCmdDrawMeshTasksIndirectNV) load(userptr, "vkCmdDrawMeshTasksIndirectNV"); glad_vkCmdDrawMeshTasksNV = (PFN_vkCmdDrawMeshTasksNV) load(userptr, "vkCmdDrawMeshTasksNV"); } +static void glad_vk_load_VK_NV_optical_flow( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_optical_flow) return; + glad_vkBindOpticalFlowSessionImageNV = (PFN_vkBindOpticalFlowSessionImageNV) load(userptr, "vkBindOpticalFlowSessionImageNV"); + glad_vkCmdOpticalFlowExecuteNV = (PFN_vkCmdOpticalFlowExecuteNV) load(userptr, "vkCmdOpticalFlowExecuteNV"); + glad_vkCreateOpticalFlowSessionNV = (PFN_vkCreateOpticalFlowSessionNV) load(userptr, "vkCreateOpticalFlowSessionNV"); + glad_vkDestroyOpticalFlowSessionNV = (PFN_vkDestroyOpticalFlowSessionNV) load(userptr, "vkDestroyOpticalFlowSessionNV"); + glad_vkGetPhysicalDeviceOpticalFlowImageFormatsNV = (PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV) load(userptr, "vkGetPhysicalDeviceOpticalFlowImageFormatsNV"); +} +static void glad_vk_load_VK_NV_partitioned_acceleration_structure( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_partitioned_acceleration_structure) return; + glad_vkCmdBuildPartitionedAccelerationStructuresNV = (PFN_vkCmdBuildPartitionedAccelerationStructuresNV) load(userptr, "vkCmdBuildPartitionedAccelerationStructuresNV"); + glad_vkGetPartitionedAccelerationStructuresBuildSizesNV = (PFN_vkGetPartitionedAccelerationStructuresBuildSizesNV) load(userptr, "vkGetPartitionedAccelerationStructuresBuildSizesNV"); +} static void glad_vk_load_VK_NV_ray_tracing( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_ray_tracing) return; glad_vkBindAccelerationStructureMemoryNV = (PFN_vkBindAccelerationStructureMemoryNV) load(userptr, "vkBindAccelerationStructureMemoryNV"); @@ -1590,6 +2743,7 @@ static void glad_vk_load_VK_NV_ray_tracing( GLADuserptrloadfunc load, void* user } static void glad_vk_load_VK_NV_scissor_exclusive( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_scissor_exclusive) return; + glad_vkCmdSetExclusiveScissorEnableNV = (PFN_vkCmdSetExclusiveScissorEnableNV) load(userptr, "vkCmdSetExclusiveScissorEnableNV"); glad_vkCmdSetExclusiveScissorNV = (PFN_vkCmdSetExclusiveScissorNV) load(userptr, "vkCmdSetExclusiveScissorNV"); } static void glad_vk_load_VK_NV_shading_rate_image( GLADuserptrloadfunc load, void* userptr) { @@ -1598,6 +2752,41 @@ static void glad_vk_load_VK_NV_shading_rate_image( GLADuserptrloadfunc load, voi glad_vkCmdSetCoarseSampleOrderNV = (PFN_vkCmdSetCoarseSampleOrderNV) load(userptr, "vkCmdSetCoarseSampleOrderNV"); glad_vkCmdSetViewportShadingRatePaletteNV = (PFN_vkCmdSetViewportShadingRatePaletteNV) load(userptr, "vkCmdSetViewportShadingRatePaletteNV"); } +static void glad_vk_load_VK_QCOM_tile_memory_heap( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_QCOM_tile_memory_heap) return; + glad_vkCmdBindTileMemoryQCOM = (PFN_vkCmdBindTileMemoryQCOM) load(userptr, "vkCmdBindTileMemoryQCOM"); +} +static void glad_vk_load_VK_QCOM_tile_properties( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_QCOM_tile_properties) return; + glad_vkGetDynamicRenderingTilePropertiesQCOM = (PFN_vkGetDynamicRenderingTilePropertiesQCOM) load(userptr, "vkGetDynamicRenderingTilePropertiesQCOM"); + glad_vkGetFramebufferTilePropertiesQCOM = (PFN_vkGetFramebufferTilePropertiesQCOM) load(userptr, "vkGetFramebufferTilePropertiesQCOM"); +} +static void glad_vk_load_VK_QCOM_tile_shading( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_QCOM_tile_shading) return; + glad_vkCmdBeginPerTileExecutionQCOM = (PFN_vkCmdBeginPerTileExecutionQCOM) load(userptr, "vkCmdBeginPerTileExecutionQCOM"); + glad_vkCmdDispatchTileQCOM = (PFN_vkCmdDispatchTileQCOM) load(userptr, "vkCmdDispatchTileQCOM"); + glad_vkCmdEndPerTileExecutionQCOM = (PFN_vkCmdEndPerTileExecutionQCOM) load(userptr, "vkCmdEndPerTileExecutionQCOM"); +} +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +static void glad_vk_load_VK_QNX_external_memory_screen_buffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_QNX_external_memory_screen_buffer) return; + glad_vkGetScreenBufferPropertiesQNX = (PFN_vkGetScreenBufferPropertiesQNX) load(userptr, "vkGetScreenBufferPropertiesQNX"); +} + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +static void glad_vk_load_VK_QNX_screen_surface( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_QNX_screen_surface) return; + glad_vkCreateScreenSurfaceQNX = (PFN_vkCreateScreenSurfaceQNX) load(userptr, "vkCreateScreenSurfaceQNX"); + glad_vkGetPhysicalDeviceScreenPresentationSupportQNX = (PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX) load(userptr, "vkGetPhysicalDeviceScreenPresentationSupportQNX"); +} + +#endif +static void glad_vk_load_VK_VALVE_descriptor_set_host_mapping( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_VALVE_descriptor_set_host_mapping) return; + glad_vkGetDescriptorSetHostMappingVALVE = (PFN_vkGetDescriptorSetHostMappingVALVE) load(userptr, "vkGetDescriptorSetHostMappingVALVE"); + glad_vkGetDescriptorSetLayoutHostMappingInfoVALVE = (PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE) load(userptr, "vkGetDescriptorSetLayoutHostMappingInfoVALVE"); +} @@ -1728,6 +2917,11 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { char **extensions = NULL; if (!glad_vk_get_extensions(physical_device, &extension_count, &extensions)) return 0; +#if defined(VK_ENABLE_BETA_EXTENSIONS) + GLAD_VK_AMDX_shader_enqueue = glad_vk_has_extension("VK_AMDX_shader_enqueue", extension_count, extensions); + +#endif + GLAD_VK_AMD_anti_lag = glad_vk_has_extension("VK_AMD_anti_lag", extension_count, extensions); GLAD_VK_AMD_buffer_marker = glad_vk_has_extension("VK_AMD_buffer_marker", extension_count, extensions); GLAD_VK_AMD_device_coherent_memory = glad_vk_has_extension("VK_AMD_device_coherent_memory", extension_count, extensions); GLAD_VK_AMD_display_native_hdr = glad_vk_has_extension("VK_AMD_display_native_hdr", extension_count, extensions); @@ -1743,82 +2937,167 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { GLAD_VK_AMD_shader_ballot = glad_vk_has_extension("VK_AMD_shader_ballot", extension_count, extensions); GLAD_VK_AMD_shader_core_properties = glad_vk_has_extension("VK_AMD_shader_core_properties", extension_count, extensions); GLAD_VK_AMD_shader_core_properties2 = glad_vk_has_extension("VK_AMD_shader_core_properties2", extension_count, extensions); + GLAD_VK_AMD_shader_early_and_late_fragment_tests = glad_vk_has_extension("VK_AMD_shader_early_and_late_fragment_tests", extension_count, extensions); GLAD_VK_AMD_shader_explicit_vertex_parameter = glad_vk_has_extension("VK_AMD_shader_explicit_vertex_parameter", extension_count, extensions); GLAD_VK_AMD_shader_fragment_mask = glad_vk_has_extension("VK_AMD_shader_fragment_mask", extension_count, extensions); GLAD_VK_AMD_shader_image_load_store_lod = glad_vk_has_extension("VK_AMD_shader_image_load_store_lod", extension_count, extensions); GLAD_VK_AMD_shader_info = glad_vk_has_extension("VK_AMD_shader_info", extension_count, extensions); GLAD_VK_AMD_shader_trinary_minmax = glad_vk_has_extension("VK_AMD_shader_trinary_minmax", extension_count, extensions); GLAD_VK_AMD_texture_gather_bias_lod = glad_vk_has_extension("VK_AMD_texture_gather_bias_lod", extension_count, extensions); +#if defined(VK_USE_PLATFORM_ANDROID_KHR) + GLAD_VK_ANDROID_external_format_resolve = glad_vk_has_extension("VK_ANDROID_external_format_resolve", extension_count, extensions); + +#endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) GLAD_VK_ANDROID_external_memory_android_hardware_buffer = glad_vk_has_extension("VK_ANDROID_external_memory_android_hardware_buffer", extension_count, extensions); + #endif + GLAD_VK_ARM_pipeline_opacity_micromap = glad_vk_has_extension("VK_ARM_pipeline_opacity_micromap", extension_count, extensions); + GLAD_VK_ARM_rasterization_order_attachment_access = glad_vk_has_extension("VK_ARM_rasterization_order_attachment_access", extension_count, extensions); + GLAD_VK_ARM_render_pass_striped = glad_vk_has_extension("VK_ARM_render_pass_striped", extension_count, extensions); + GLAD_VK_ARM_scheduling_controls = glad_vk_has_extension("VK_ARM_scheduling_controls", extension_count, extensions); + GLAD_VK_ARM_shader_core_builtins = glad_vk_has_extension("VK_ARM_shader_core_builtins", extension_count, extensions); + GLAD_VK_ARM_shader_core_properties = glad_vk_has_extension("VK_ARM_shader_core_properties", extension_count, extensions); GLAD_VK_EXT_4444_formats = glad_vk_has_extension("VK_EXT_4444_formats", extension_count, extensions); + GLAD_VK_EXT_acquire_drm_display = glad_vk_has_extension("VK_EXT_acquire_drm_display", extension_count, extensions); #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) GLAD_VK_EXT_acquire_xlib_display = glad_vk_has_extension("VK_EXT_acquire_xlib_display", extension_count, extensions); + #endif GLAD_VK_EXT_astc_decode_mode = glad_vk_has_extension("VK_EXT_astc_decode_mode", extension_count, extensions); + GLAD_VK_EXT_attachment_feedback_loop_dynamic_state = glad_vk_has_extension("VK_EXT_attachment_feedback_loop_dynamic_state", extension_count, extensions); + GLAD_VK_EXT_attachment_feedback_loop_layout = glad_vk_has_extension("VK_EXT_attachment_feedback_loop_layout", extension_count, extensions); GLAD_VK_EXT_blend_operation_advanced = glad_vk_has_extension("VK_EXT_blend_operation_advanced", extension_count, extensions); + GLAD_VK_EXT_border_color_swizzle = glad_vk_has_extension("VK_EXT_border_color_swizzle", extension_count, extensions); GLAD_VK_EXT_buffer_device_address = glad_vk_has_extension("VK_EXT_buffer_device_address", extension_count, extensions); GLAD_VK_EXT_calibrated_timestamps = glad_vk_has_extension("VK_EXT_calibrated_timestamps", extension_count, extensions); + GLAD_VK_EXT_color_write_enable = glad_vk_has_extension("VK_EXT_color_write_enable", extension_count, extensions); GLAD_VK_EXT_conditional_rendering = glad_vk_has_extension("VK_EXT_conditional_rendering", extension_count, extensions); GLAD_VK_EXT_conservative_rasterization = glad_vk_has_extension("VK_EXT_conservative_rasterization", extension_count, extensions); GLAD_VK_EXT_custom_border_color = glad_vk_has_extension("VK_EXT_custom_border_color", extension_count, extensions); GLAD_VK_EXT_debug_marker = glad_vk_has_extension("VK_EXT_debug_marker", extension_count, extensions); GLAD_VK_EXT_debug_report = glad_vk_has_extension("VK_EXT_debug_report", extension_count, extensions); GLAD_VK_EXT_debug_utils = glad_vk_has_extension("VK_EXT_debug_utils", extension_count, extensions); + GLAD_VK_EXT_depth_bias_control = glad_vk_has_extension("VK_EXT_depth_bias_control", extension_count, extensions); + GLAD_VK_EXT_depth_clamp_control = glad_vk_has_extension("VK_EXT_depth_clamp_control", extension_count, extensions); + GLAD_VK_EXT_depth_clamp_zero_one = glad_vk_has_extension("VK_EXT_depth_clamp_zero_one", extension_count, extensions); + GLAD_VK_EXT_depth_clip_control = glad_vk_has_extension("VK_EXT_depth_clip_control", extension_count, extensions); GLAD_VK_EXT_depth_clip_enable = glad_vk_has_extension("VK_EXT_depth_clip_enable", extension_count, extensions); GLAD_VK_EXT_depth_range_unrestricted = glad_vk_has_extension("VK_EXT_depth_range_unrestricted", extension_count, extensions); + GLAD_VK_EXT_descriptor_buffer = glad_vk_has_extension("VK_EXT_descriptor_buffer", extension_count, extensions); GLAD_VK_EXT_descriptor_indexing = glad_vk_has_extension("VK_EXT_descriptor_indexing", extension_count, extensions); + GLAD_VK_EXT_device_address_binding_report = glad_vk_has_extension("VK_EXT_device_address_binding_report", extension_count, extensions); + GLAD_VK_EXT_device_fault = glad_vk_has_extension("VK_EXT_device_fault", extension_count, extensions); + GLAD_VK_EXT_device_generated_commands = glad_vk_has_extension("VK_EXT_device_generated_commands", extension_count, extensions); + GLAD_VK_EXT_device_memory_report = glad_vk_has_extension("VK_EXT_device_memory_report", extension_count, extensions); GLAD_VK_EXT_direct_mode_display = glad_vk_has_extension("VK_EXT_direct_mode_display", extension_count, extensions); #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) GLAD_VK_EXT_directfb_surface = glad_vk_has_extension("VK_EXT_directfb_surface", extension_count, extensions); + #endif GLAD_VK_EXT_discard_rectangles = glad_vk_has_extension("VK_EXT_discard_rectangles", extension_count, extensions); GLAD_VK_EXT_display_control = glad_vk_has_extension("VK_EXT_display_control", extension_count, extensions); GLAD_VK_EXT_display_surface_counter = glad_vk_has_extension("VK_EXT_display_surface_counter", extension_count, extensions); + GLAD_VK_EXT_dynamic_rendering_unused_attachments = glad_vk_has_extension("VK_EXT_dynamic_rendering_unused_attachments", extension_count, extensions); GLAD_VK_EXT_extended_dynamic_state = glad_vk_has_extension("VK_EXT_extended_dynamic_state", extension_count, extensions); + GLAD_VK_EXT_extended_dynamic_state2 = glad_vk_has_extension("VK_EXT_extended_dynamic_state2", extension_count, extensions); + GLAD_VK_EXT_extended_dynamic_state3 = glad_vk_has_extension("VK_EXT_extended_dynamic_state3", extension_count, extensions); + GLAD_VK_EXT_external_memory_acquire_unmodified = glad_vk_has_extension("VK_EXT_external_memory_acquire_unmodified", extension_count, extensions); GLAD_VK_EXT_external_memory_dma_buf = glad_vk_has_extension("VK_EXT_external_memory_dma_buf", extension_count, extensions); GLAD_VK_EXT_external_memory_host = glad_vk_has_extension("VK_EXT_external_memory_host", extension_count, extensions); +#if defined(VK_USE_PLATFORM_METAL_EXT) + GLAD_VK_EXT_external_memory_metal = glad_vk_has_extension("VK_EXT_external_memory_metal", extension_count, extensions); + +#endif GLAD_VK_EXT_filter_cubic = glad_vk_has_extension("VK_EXT_filter_cubic", extension_count, extensions); GLAD_VK_EXT_fragment_density_map = glad_vk_has_extension("VK_EXT_fragment_density_map", extension_count, extensions); GLAD_VK_EXT_fragment_density_map2 = glad_vk_has_extension("VK_EXT_fragment_density_map2", extension_count, extensions); + GLAD_VK_EXT_fragment_density_map_offset = glad_vk_has_extension("VK_EXT_fragment_density_map_offset", extension_count, extensions); GLAD_VK_EXT_fragment_shader_interlock = glad_vk_has_extension("VK_EXT_fragment_shader_interlock", extension_count, extensions); + GLAD_VK_EXT_frame_boundary = glad_vk_has_extension("VK_EXT_frame_boundary", extension_count, extensions); #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_EXT_full_screen_exclusive = glad_vk_has_extension("VK_EXT_full_screen_exclusive", extension_count, extensions); + #endif GLAD_VK_EXT_global_priority = glad_vk_has_extension("VK_EXT_global_priority", extension_count, extensions); + GLAD_VK_EXT_global_priority_query = glad_vk_has_extension("VK_EXT_global_priority_query", extension_count, extensions); + GLAD_VK_EXT_graphics_pipeline_library = glad_vk_has_extension("VK_EXT_graphics_pipeline_library", extension_count, extensions); GLAD_VK_EXT_hdr_metadata = glad_vk_has_extension("VK_EXT_hdr_metadata", extension_count, extensions); GLAD_VK_EXT_headless_surface = glad_vk_has_extension("VK_EXT_headless_surface", extension_count, extensions); + GLAD_VK_EXT_host_image_copy = glad_vk_has_extension("VK_EXT_host_image_copy", extension_count, extensions); GLAD_VK_EXT_host_query_reset = glad_vk_has_extension("VK_EXT_host_query_reset", extension_count, extensions); + GLAD_VK_EXT_image_2d_view_of_3d = glad_vk_has_extension("VK_EXT_image_2d_view_of_3d", extension_count, extensions); + GLAD_VK_EXT_image_compression_control = glad_vk_has_extension("VK_EXT_image_compression_control", extension_count, extensions); + GLAD_VK_EXT_image_compression_control_swapchain = glad_vk_has_extension("VK_EXT_image_compression_control_swapchain", extension_count, extensions); GLAD_VK_EXT_image_drm_format_modifier = glad_vk_has_extension("VK_EXT_image_drm_format_modifier", extension_count, extensions); GLAD_VK_EXT_image_robustness = glad_vk_has_extension("VK_EXT_image_robustness", extension_count, extensions); + GLAD_VK_EXT_image_sliced_view_of_3d = glad_vk_has_extension("VK_EXT_image_sliced_view_of_3d", extension_count, extensions); + GLAD_VK_EXT_image_view_min_lod = glad_vk_has_extension("VK_EXT_image_view_min_lod", extension_count, extensions); GLAD_VK_EXT_index_type_uint8 = glad_vk_has_extension("VK_EXT_index_type_uint8", extension_count, extensions); GLAD_VK_EXT_inline_uniform_block = glad_vk_has_extension("VK_EXT_inline_uniform_block", extension_count, extensions); + GLAD_VK_EXT_layer_settings = glad_vk_has_extension("VK_EXT_layer_settings", extension_count, extensions); + GLAD_VK_EXT_legacy_dithering = glad_vk_has_extension("VK_EXT_legacy_dithering", extension_count, extensions); + GLAD_VK_EXT_legacy_vertex_attributes = glad_vk_has_extension("VK_EXT_legacy_vertex_attributes", extension_count, extensions); GLAD_VK_EXT_line_rasterization = glad_vk_has_extension("VK_EXT_line_rasterization", extension_count, extensions); + GLAD_VK_EXT_load_store_op_none = glad_vk_has_extension("VK_EXT_load_store_op_none", extension_count, extensions); + GLAD_VK_EXT_map_memory_placed = glad_vk_has_extension("VK_EXT_map_memory_placed", extension_count, extensions); GLAD_VK_EXT_memory_budget = glad_vk_has_extension("VK_EXT_memory_budget", extension_count, extensions); GLAD_VK_EXT_memory_priority = glad_vk_has_extension("VK_EXT_memory_priority", extension_count, extensions); + GLAD_VK_EXT_mesh_shader = glad_vk_has_extension("VK_EXT_mesh_shader", extension_count, extensions); +#if defined(VK_USE_PLATFORM_METAL_EXT) + GLAD_VK_EXT_metal_objects = glad_vk_has_extension("VK_EXT_metal_objects", extension_count, extensions); + +#endif #if defined(VK_USE_PLATFORM_METAL_EXT) GLAD_VK_EXT_metal_surface = glad_vk_has_extension("VK_EXT_metal_surface", extension_count, extensions); + #endif + GLAD_VK_EXT_multi_draw = glad_vk_has_extension("VK_EXT_multi_draw", extension_count, extensions); + GLAD_VK_EXT_multisampled_render_to_single_sampled = glad_vk_has_extension("VK_EXT_multisampled_render_to_single_sampled", extension_count, extensions); + GLAD_VK_EXT_mutable_descriptor_type = glad_vk_has_extension("VK_EXT_mutable_descriptor_type", extension_count, extensions); + GLAD_VK_EXT_nested_command_buffer = glad_vk_has_extension("VK_EXT_nested_command_buffer", extension_count, extensions); + GLAD_VK_EXT_non_seamless_cube_map = glad_vk_has_extension("VK_EXT_non_seamless_cube_map", extension_count, extensions); + GLAD_VK_EXT_opacity_micromap = glad_vk_has_extension("VK_EXT_opacity_micromap", extension_count, extensions); + GLAD_VK_EXT_pageable_device_local_memory = glad_vk_has_extension("VK_EXT_pageable_device_local_memory", extension_count, extensions); GLAD_VK_EXT_pci_bus_info = glad_vk_has_extension("VK_EXT_pci_bus_info", extension_count, extensions); + GLAD_VK_EXT_physical_device_drm = glad_vk_has_extension("VK_EXT_physical_device_drm", extension_count, extensions); GLAD_VK_EXT_pipeline_creation_cache_control = glad_vk_has_extension("VK_EXT_pipeline_creation_cache_control", extension_count, extensions); GLAD_VK_EXT_pipeline_creation_feedback = glad_vk_has_extension("VK_EXT_pipeline_creation_feedback", extension_count, extensions); + GLAD_VK_EXT_pipeline_library_group_handles = glad_vk_has_extension("VK_EXT_pipeline_library_group_handles", extension_count, extensions); + GLAD_VK_EXT_pipeline_properties = glad_vk_has_extension("VK_EXT_pipeline_properties", extension_count, extensions); + GLAD_VK_EXT_pipeline_protected_access = glad_vk_has_extension("VK_EXT_pipeline_protected_access", extension_count, extensions); + GLAD_VK_EXT_pipeline_robustness = glad_vk_has_extension("VK_EXT_pipeline_robustness", extension_count, extensions); GLAD_VK_EXT_post_depth_coverage = glad_vk_has_extension("VK_EXT_post_depth_coverage", extension_count, extensions); + GLAD_VK_EXT_present_mode_fifo_latest_ready = glad_vk_has_extension("VK_EXT_present_mode_fifo_latest_ready", extension_count, extensions); + GLAD_VK_EXT_primitive_topology_list_restart = glad_vk_has_extension("VK_EXT_primitive_topology_list_restart", extension_count, extensions); + GLAD_VK_EXT_primitives_generated_query = glad_vk_has_extension("VK_EXT_primitives_generated_query", extension_count, extensions); GLAD_VK_EXT_private_data = glad_vk_has_extension("VK_EXT_private_data", extension_count, extensions); + GLAD_VK_EXT_provoking_vertex = glad_vk_has_extension("VK_EXT_provoking_vertex", extension_count, extensions); GLAD_VK_EXT_queue_family_foreign = glad_vk_has_extension("VK_EXT_queue_family_foreign", extension_count, extensions); + GLAD_VK_EXT_rasterization_order_attachment_access = glad_vk_has_extension("VK_EXT_rasterization_order_attachment_access", extension_count, extensions); + GLAD_VK_EXT_rgba10x6_formats = glad_vk_has_extension("VK_EXT_rgba10x6_formats", extension_count, extensions); GLAD_VK_EXT_robustness2 = glad_vk_has_extension("VK_EXT_robustness2", extension_count, extensions); GLAD_VK_EXT_sample_locations = glad_vk_has_extension("VK_EXT_sample_locations", extension_count, extensions); GLAD_VK_EXT_sampler_filter_minmax = glad_vk_has_extension("VK_EXT_sampler_filter_minmax", extension_count, extensions); GLAD_VK_EXT_scalar_block_layout = glad_vk_has_extension("VK_EXT_scalar_block_layout", extension_count, extensions); GLAD_VK_EXT_separate_stencil_usage = glad_vk_has_extension("VK_EXT_separate_stencil_usage", extension_count, extensions); GLAD_VK_EXT_shader_atomic_float = glad_vk_has_extension("VK_EXT_shader_atomic_float", extension_count, extensions); + GLAD_VK_EXT_shader_atomic_float2 = glad_vk_has_extension("VK_EXT_shader_atomic_float2", extension_count, extensions); GLAD_VK_EXT_shader_demote_to_helper_invocation = glad_vk_has_extension("VK_EXT_shader_demote_to_helper_invocation", extension_count, extensions); + GLAD_VK_EXT_shader_image_atomic_int64 = glad_vk_has_extension("VK_EXT_shader_image_atomic_int64", extension_count, extensions); + GLAD_VK_EXT_shader_module_identifier = glad_vk_has_extension("VK_EXT_shader_module_identifier", extension_count, extensions); + GLAD_VK_EXT_shader_object = glad_vk_has_extension("VK_EXT_shader_object", extension_count, extensions); + GLAD_VK_EXT_shader_replicated_composites = glad_vk_has_extension("VK_EXT_shader_replicated_composites", extension_count, extensions); GLAD_VK_EXT_shader_stencil_export = glad_vk_has_extension("VK_EXT_shader_stencil_export", extension_count, extensions); GLAD_VK_EXT_shader_subgroup_ballot = glad_vk_has_extension("VK_EXT_shader_subgroup_ballot", extension_count, extensions); GLAD_VK_EXT_shader_subgroup_vote = glad_vk_has_extension("VK_EXT_shader_subgroup_vote", extension_count, extensions); + GLAD_VK_EXT_shader_tile_image = glad_vk_has_extension("VK_EXT_shader_tile_image", extension_count, extensions); GLAD_VK_EXT_shader_viewport_index_layer = glad_vk_has_extension("VK_EXT_shader_viewport_index_layer", extension_count, extensions); GLAD_VK_EXT_subgroup_size_control = glad_vk_has_extension("VK_EXT_subgroup_size_control", extension_count, extensions); + GLAD_VK_EXT_subpass_merge_feedback = glad_vk_has_extension("VK_EXT_subpass_merge_feedback", extension_count, extensions); + GLAD_VK_EXT_surface_maintenance1 = glad_vk_has_extension("VK_EXT_surface_maintenance1", extension_count, extensions); GLAD_VK_EXT_swapchain_colorspace = glad_vk_has_extension("VK_EXT_swapchain_colorspace", extension_count, extensions); + GLAD_VK_EXT_swapchain_maintenance1 = glad_vk_has_extension("VK_EXT_swapchain_maintenance1", extension_count, extensions); GLAD_VK_EXT_texel_buffer_alignment = glad_vk_has_extension("VK_EXT_texel_buffer_alignment", extension_count, extensions); GLAD_VK_EXT_texture_compression_astc_hdr = glad_vk_has_extension("VK_EXT_texture_compression_astc_hdr", extension_count, extensions); GLAD_VK_EXT_tooling_info = glad_vk_has_extension("VK_EXT_tooling_info", extension_count, extensions); @@ -1827,36 +3106,65 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { GLAD_VK_EXT_validation_features = glad_vk_has_extension("VK_EXT_validation_features", extension_count, extensions); GLAD_VK_EXT_validation_flags = glad_vk_has_extension("VK_EXT_validation_flags", extension_count, extensions); GLAD_VK_EXT_vertex_attribute_divisor = glad_vk_has_extension("VK_EXT_vertex_attribute_divisor", extension_count, extensions); + GLAD_VK_EXT_vertex_attribute_robustness = glad_vk_has_extension("VK_EXT_vertex_attribute_robustness", extension_count, extensions); + GLAD_VK_EXT_vertex_input_dynamic_state = glad_vk_has_extension("VK_EXT_vertex_input_dynamic_state", extension_count, extensions); + GLAD_VK_EXT_ycbcr_2plane_444_formats = glad_vk_has_extension("VK_EXT_ycbcr_2plane_444_formats", extension_count, extensions); GLAD_VK_EXT_ycbcr_image_arrays = glad_vk_has_extension("VK_EXT_ycbcr_image_arrays", extension_count, extensions); +#if defined(VK_USE_PLATFORM_FUCHSIA) + GLAD_VK_FUCHSIA_buffer_collection = glad_vk_has_extension("VK_FUCHSIA_buffer_collection", extension_count, extensions); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) + GLAD_VK_FUCHSIA_external_memory = glad_vk_has_extension("VK_FUCHSIA_external_memory", extension_count, extensions); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) + GLAD_VK_FUCHSIA_external_semaphore = glad_vk_has_extension("VK_FUCHSIA_external_semaphore", extension_count, extensions); + +#endif #if defined(VK_USE_PLATFORM_FUCHSIA) GLAD_VK_FUCHSIA_imagepipe_surface = glad_vk_has_extension("VK_FUCHSIA_imagepipe_surface", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_GGP) GLAD_VK_GGP_frame_token = glad_vk_has_extension("VK_GGP_frame_token", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_GGP) GLAD_VK_GGP_stream_descriptor_surface = glad_vk_has_extension("VK_GGP_stream_descriptor_surface", extension_count, extensions); + #endif GLAD_VK_GOOGLE_decorate_string = glad_vk_has_extension("VK_GOOGLE_decorate_string", extension_count, extensions); GLAD_VK_GOOGLE_display_timing = glad_vk_has_extension("VK_GOOGLE_display_timing", extension_count, extensions); GLAD_VK_GOOGLE_hlsl_functionality1 = glad_vk_has_extension("VK_GOOGLE_hlsl_functionality1", extension_count, extensions); + GLAD_VK_GOOGLE_surfaceless_query = glad_vk_has_extension("VK_GOOGLE_surfaceless_query", extension_count, extensions); GLAD_VK_GOOGLE_user_type = glad_vk_has_extension("VK_GOOGLE_user_type", extension_count, extensions); + GLAD_VK_HUAWEI_cluster_culling_shader = glad_vk_has_extension("VK_HUAWEI_cluster_culling_shader", extension_count, extensions); + GLAD_VK_HUAWEI_hdr_vivid = glad_vk_has_extension("VK_HUAWEI_hdr_vivid", extension_count, extensions); + GLAD_VK_HUAWEI_invocation_mask = glad_vk_has_extension("VK_HUAWEI_invocation_mask", extension_count, extensions); + GLAD_VK_HUAWEI_subpass_shading = glad_vk_has_extension("VK_HUAWEI_subpass_shading", extension_count, extensions); GLAD_VK_IMG_filter_cubic = glad_vk_has_extension("VK_IMG_filter_cubic", extension_count, extensions); GLAD_VK_IMG_format_pvrtc = glad_vk_has_extension("VK_IMG_format_pvrtc", extension_count, extensions); + GLAD_VK_IMG_relaxed_line_rasterization = glad_vk_has_extension("VK_IMG_relaxed_line_rasterization", extension_count, extensions); GLAD_VK_INTEL_performance_query = glad_vk_has_extension("VK_INTEL_performance_query", extension_count, extensions); GLAD_VK_INTEL_shader_integer_functions2 = glad_vk_has_extension("VK_INTEL_shader_integer_functions2", extension_count, extensions); GLAD_VK_KHR_16bit_storage = glad_vk_has_extension("VK_KHR_16bit_storage", extension_count, extensions); GLAD_VK_KHR_8bit_storage = glad_vk_has_extension("VK_KHR_8bit_storage", extension_count, extensions); + GLAD_VK_KHR_acceleration_structure = glad_vk_has_extension("VK_KHR_acceleration_structure", extension_count, extensions); #if defined(VK_USE_PLATFORM_ANDROID_KHR) GLAD_VK_KHR_android_surface = glad_vk_has_extension("VK_KHR_android_surface", extension_count, extensions); + #endif GLAD_VK_KHR_bind_memory2 = glad_vk_has_extension("VK_KHR_bind_memory2", extension_count, extensions); GLAD_VK_KHR_buffer_device_address = glad_vk_has_extension("VK_KHR_buffer_device_address", extension_count, extensions); + GLAD_VK_KHR_calibrated_timestamps = glad_vk_has_extension("VK_KHR_calibrated_timestamps", extension_count, extensions); + GLAD_VK_KHR_compute_shader_derivatives = glad_vk_has_extension("VK_KHR_compute_shader_derivatives", extension_count, extensions); + GLAD_VK_KHR_cooperative_matrix = glad_vk_has_extension("VK_KHR_cooperative_matrix", extension_count, extensions); + GLAD_VK_KHR_copy_commands2 = glad_vk_has_extension("VK_KHR_copy_commands2", extension_count, extensions); GLAD_VK_KHR_create_renderpass2 = glad_vk_has_extension("VK_KHR_create_renderpass2", extension_count, extensions); GLAD_VK_KHR_dedicated_allocation = glad_vk_has_extension("VK_KHR_dedicated_allocation", extension_count, extensions); -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_VK_KHR_deferred_host_operations = glad_vk_has_extension("VK_KHR_deferred_host_operations", extension_count, extensions); -#endif + GLAD_VK_KHR_depth_clamp_zero_one = glad_vk_has_extension("VK_KHR_depth_clamp_zero_one", extension_count, extensions); GLAD_VK_KHR_depth_stencil_resolve = glad_vk_has_extension("VK_KHR_depth_stencil_resolve", extension_count, extensions); GLAD_VK_KHR_descriptor_update_template = glad_vk_has_extension("VK_KHR_descriptor_update_template", extension_count, extensions); GLAD_VK_KHR_device_group = glad_vk_has_extension("VK_KHR_device_group", extension_count, extensions); @@ -1865,55 +3173,91 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { GLAD_VK_KHR_display_swapchain = glad_vk_has_extension("VK_KHR_display_swapchain", extension_count, extensions); GLAD_VK_KHR_draw_indirect_count = glad_vk_has_extension("VK_KHR_draw_indirect_count", extension_count, extensions); GLAD_VK_KHR_driver_properties = glad_vk_has_extension("VK_KHR_driver_properties", extension_count, extensions); + GLAD_VK_KHR_dynamic_rendering = glad_vk_has_extension("VK_KHR_dynamic_rendering", extension_count, extensions); + GLAD_VK_KHR_dynamic_rendering_local_read = glad_vk_has_extension("VK_KHR_dynamic_rendering_local_read", extension_count, extensions); GLAD_VK_KHR_external_fence = glad_vk_has_extension("VK_KHR_external_fence", extension_count, extensions); GLAD_VK_KHR_external_fence_capabilities = glad_vk_has_extension("VK_KHR_external_fence_capabilities", extension_count, extensions); GLAD_VK_KHR_external_fence_fd = glad_vk_has_extension("VK_KHR_external_fence_fd", extension_count, extensions); #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_KHR_external_fence_win32 = glad_vk_has_extension("VK_KHR_external_fence_win32", extension_count, extensions); + #endif GLAD_VK_KHR_external_memory = glad_vk_has_extension("VK_KHR_external_memory", extension_count, extensions); GLAD_VK_KHR_external_memory_capabilities = glad_vk_has_extension("VK_KHR_external_memory_capabilities", extension_count, extensions); GLAD_VK_KHR_external_memory_fd = glad_vk_has_extension("VK_KHR_external_memory_fd", extension_count, extensions); #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_KHR_external_memory_win32 = glad_vk_has_extension("VK_KHR_external_memory_win32", extension_count, extensions); + #endif GLAD_VK_KHR_external_semaphore = glad_vk_has_extension("VK_KHR_external_semaphore", extension_count, extensions); GLAD_VK_KHR_external_semaphore_capabilities = glad_vk_has_extension("VK_KHR_external_semaphore_capabilities", extension_count, extensions); GLAD_VK_KHR_external_semaphore_fd = glad_vk_has_extension("VK_KHR_external_semaphore_fd", extension_count, extensions); #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_KHR_external_semaphore_win32 = glad_vk_has_extension("VK_KHR_external_semaphore_win32", extension_count, extensions); + #endif + GLAD_VK_KHR_format_feature_flags2 = glad_vk_has_extension("VK_KHR_format_feature_flags2", extension_count, extensions); + GLAD_VK_KHR_fragment_shader_barycentric = glad_vk_has_extension("VK_KHR_fragment_shader_barycentric", extension_count, extensions); + GLAD_VK_KHR_fragment_shading_rate = glad_vk_has_extension("VK_KHR_fragment_shading_rate", extension_count, extensions); GLAD_VK_KHR_get_display_properties2 = glad_vk_has_extension("VK_KHR_get_display_properties2", extension_count, extensions); GLAD_VK_KHR_get_memory_requirements2 = glad_vk_has_extension("VK_KHR_get_memory_requirements2", extension_count, extensions); GLAD_VK_KHR_get_physical_device_properties2 = glad_vk_has_extension("VK_KHR_get_physical_device_properties2", extension_count, extensions); GLAD_VK_KHR_get_surface_capabilities2 = glad_vk_has_extension("VK_KHR_get_surface_capabilities2", extension_count, extensions); + GLAD_VK_KHR_global_priority = glad_vk_has_extension("VK_KHR_global_priority", extension_count, extensions); GLAD_VK_KHR_image_format_list = glad_vk_has_extension("VK_KHR_image_format_list", extension_count, extensions); GLAD_VK_KHR_imageless_framebuffer = glad_vk_has_extension("VK_KHR_imageless_framebuffer", extension_count, extensions); GLAD_VK_KHR_incremental_present = glad_vk_has_extension("VK_KHR_incremental_present", extension_count, extensions); + GLAD_VK_KHR_index_type_uint8 = glad_vk_has_extension("VK_KHR_index_type_uint8", extension_count, extensions); + GLAD_VK_KHR_line_rasterization = glad_vk_has_extension("VK_KHR_line_rasterization", extension_count, extensions); + GLAD_VK_KHR_load_store_op_none = glad_vk_has_extension("VK_KHR_load_store_op_none", extension_count, extensions); GLAD_VK_KHR_maintenance1 = glad_vk_has_extension("VK_KHR_maintenance1", extension_count, extensions); GLAD_VK_KHR_maintenance2 = glad_vk_has_extension("VK_KHR_maintenance2", extension_count, extensions); GLAD_VK_KHR_maintenance3 = glad_vk_has_extension("VK_KHR_maintenance3", extension_count, extensions); + GLAD_VK_KHR_maintenance4 = glad_vk_has_extension("VK_KHR_maintenance4", extension_count, extensions); + GLAD_VK_KHR_maintenance5 = glad_vk_has_extension("VK_KHR_maintenance5", extension_count, extensions); + GLAD_VK_KHR_maintenance6 = glad_vk_has_extension("VK_KHR_maintenance6", extension_count, extensions); + GLAD_VK_KHR_maintenance7 = glad_vk_has_extension("VK_KHR_maintenance7", extension_count, extensions); + GLAD_VK_KHR_maintenance8 = glad_vk_has_extension("VK_KHR_maintenance8", extension_count, extensions); + GLAD_VK_KHR_map_memory2 = glad_vk_has_extension("VK_KHR_map_memory2", extension_count, extensions); GLAD_VK_KHR_multiview = glad_vk_has_extension("VK_KHR_multiview", extension_count, extensions); GLAD_VK_KHR_performance_query = glad_vk_has_extension("VK_KHR_performance_query", extension_count, extensions); + GLAD_VK_KHR_pipeline_binary = glad_vk_has_extension("VK_KHR_pipeline_binary", extension_count, extensions); GLAD_VK_KHR_pipeline_executable_properties = glad_vk_has_extension("VK_KHR_pipeline_executable_properties", extension_count, extensions); -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_VK_KHR_pipeline_library = glad_vk_has_extension("VK_KHR_pipeline_library", extension_count, extensions); -#endif - GLAD_VK_KHR_push_descriptor = glad_vk_has_extension("VK_KHR_push_descriptor", extension_count, extensions); + GLAD_VK_KHR_portability_enumeration = glad_vk_has_extension("VK_KHR_portability_enumeration", extension_count, extensions); #if defined(VK_ENABLE_BETA_EXTENSIONS) - GLAD_VK_KHR_ray_tracing = glad_vk_has_extension("VK_KHR_ray_tracing", extension_count, extensions); + GLAD_VK_KHR_portability_subset = glad_vk_has_extension("VK_KHR_portability_subset", extension_count, extensions); + #endif + GLAD_VK_KHR_present_id = glad_vk_has_extension("VK_KHR_present_id", extension_count, extensions); + GLAD_VK_KHR_present_wait = glad_vk_has_extension("VK_KHR_present_wait", extension_count, extensions); + GLAD_VK_KHR_push_descriptor = glad_vk_has_extension("VK_KHR_push_descriptor", extension_count, extensions); + GLAD_VK_KHR_ray_query = glad_vk_has_extension("VK_KHR_ray_query", extension_count, extensions); + GLAD_VK_KHR_ray_tracing_maintenance1 = glad_vk_has_extension("VK_KHR_ray_tracing_maintenance1", extension_count, extensions); + GLAD_VK_KHR_ray_tracing_pipeline = glad_vk_has_extension("VK_KHR_ray_tracing_pipeline", extension_count, extensions); + GLAD_VK_KHR_ray_tracing_position_fetch = glad_vk_has_extension("VK_KHR_ray_tracing_position_fetch", extension_count, extensions); GLAD_VK_KHR_relaxed_block_layout = glad_vk_has_extension("VK_KHR_relaxed_block_layout", extension_count, extensions); + GLAD_VK_KHR_robustness2 = glad_vk_has_extension("VK_KHR_robustness2", extension_count, extensions); GLAD_VK_KHR_sampler_mirror_clamp_to_edge = glad_vk_has_extension("VK_KHR_sampler_mirror_clamp_to_edge", extension_count, extensions); GLAD_VK_KHR_sampler_ycbcr_conversion = glad_vk_has_extension("VK_KHR_sampler_ycbcr_conversion", extension_count, extensions); GLAD_VK_KHR_separate_depth_stencil_layouts = glad_vk_has_extension("VK_KHR_separate_depth_stencil_layouts", extension_count, extensions); GLAD_VK_KHR_shader_atomic_int64 = glad_vk_has_extension("VK_KHR_shader_atomic_int64", extension_count, extensions); + GLAD_VK_KHR_shader_bfloat16 = glad_vk_has_extension("VK_KHR_shader_bfloat16", extension_count, extensions); GLAD_VK_KHR_shader_clock = glad_vk_has_extension("VK_KHR_shader_clock", extension_count, extensions); GLAD_VK_KHR_shader_draw_parameters = glad_vk_has_extension("VK_KHR_shader_draw_parameters", extension_count, extensions); + GLAD_VK_KHR_shader_expect_assume = glad_vk_has_extension("VK_KHR_shader_expect_assume", extension_count, extensions); GLAD_VK_KHR_shader_float16_int8 = glad_vk_has_extension("VK_KHR_shader_float16_int8", extension_count, extensions); GLAD_VK_KHR_shader_float_controls = glad_vk_has_extension("VK_KHR_shader_float_controls", extension_count, extensions); + GLAD_VK_KHR_shader_float_controls2 = glad_vk_has_extension("VK_KHR_shader_float_controls2", extension_count, extensions); + GLAD_VK_KHR_shader_integer_dot_product = glad_vk_has_extension("VK_KHR_shader_integer_dot_product", extension_count, extensions); + GLAD_VK_KHR_shader_maximal_reconvergence = glad_vk_has_extension("VK_KHR_shader_maximal_reconvergence", extension_count, extensions); GLAD_VK_KHR_shader_non_semantic_info = glad_vk_has_extension("VK_KHR_shader_non_semantic_info", extension_count, extensions); + GLAD_VK_KHR_shader_quad_control = glad_vk_has_extension("VK_KHR_shader_quad_control", extension_count, extensions); + GLAD_VK_KHR_shader_relaxed_extended_instruction = glad_vk_has_extension("VK_KHR_shader_relaxed_extended_instruction", extension_count, extensions); GLAD_VK_KHR_shader_subgroup_extended_types = glad_vk_has_extension("VK_KHR_shader_subgroup_extended_types", extension_count, extensions); + GLAD_VK_KHR_shader_subgroup_rotate = glad_vk_has_extension("VK_KHR_shader_subgroup_rotate", extension_count, extensions); + GLAD_VK_KHR_shader_subgroup_uniform_control_flow = glad_vk_has_extension("VK_KHR_shader_subgroup_uniform_control_flow", extension_count, extensions); + GLAD_VK_KHR_shader_terminate_invocation = glad_vk_has_extension("VK_KHR_shader_terminate_invocation", extension_count, extensions); GLAD_VK_KHR_shared_presentable_image = glad_vk_has_extension("VK_KHR_shared_presentable_image", extension_count, extensions); GLAD_VK_KHR_spirv_1_4 = glad_vk_has_extension("VK_KHR_spirv_1_4", extension_count, extensions); GLAD_VK_KHR_storage_buffer_storage_class = glad_vk_has_extension("VK_KHR_storage_buffer_storage_class", extension_count, extensions); @@ -1921,62 +3265,122 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { GLAD_VK_KHR_surface_protected_capabilities = glad_vk_has_extension("VK_KHR_surface_protected_capabilities", extension_count, extensions); GLAD_VK_KHR_swapchain = glad_vk_has_extension("VK_KHR_swapchain", extension_count, extensions); GLAD_VK_KHR_swapchain_mutable_format = glad_vk_has_extension("VK_KHR_swapchain_mutable_format", extension_count, extensions); + GLAD_VK_KHR_synchronization2 = glad_vk_has_extension("VK_KHR_synchronization2", extension_count, extensions); GLAD_VK_KHR_timeline_semaphore = glad_vk_has_extension("VK_KHR_timeline_semaphore", extension_count, extensions); GLAD_VK_KHR_uniform_buffer_standard_layout = glad_vk_has_extension("VK_KHR_uniform_buffer_standard_layout", extension_count, extensions); GLAD_VK_KHR_variable_pointers = glad_vk_has_extension("VK_KHR_variable_pointers", extension_count, extensions); + GLAD_VK_KHR_vertex_attribute_divisor = glad_vk_has_extension("VK_KHR_vertex_attribute_divisor", extension_count, extensions); GLAD_VK_KHR_vulkan_memory_model = glad_vk_has_extension("VK_KHR_vulkan_memory_model", extension_count, extensions); #if defined(VK_USE_PLATFORM_WAYLAND_KHR) GLAD_VK_KHR_wayland_surface = glad_vk_has_extension("VK_KHR_wayland_surface", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_KHR_win32_keyed_mutex = glad_vk_has_extension("VK_KHR_win32_keyed_mutex", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_KHR_win32_surface = glad_vk_has_extension("VK_KHR_win32_surface", extension_count, extensions); + #endif + GLAD_VK_KHR_workgroup_memory_explicit_layout = glad_vk_has_extension("VK_KHR_workgroup_memory_explicit_layout", extension_count, extensions); #if defined(VK_USE_PLATFORM_XCB_KHR) GLAD_VK_KHR_xcb_surface = glad_vk_has_extension("VK_KHR_xcb_surface", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) GLAD_VK_KHR_xlib_surface = glad_vk_has_extension("VK_KHR_xlib_surface", extension_count, extensions); + #endif + GLAD_VK_KHR_zero_initialize_workgroup_memory = glad_vk_has_extension("VK_KHR_zero_initialize_workgroup_memory", extension_count, extensions); + GLAD_VK_LUNARG_direct_driver_loading = glad_vk_has_extension("VK_LUNARG_direct_driver_loading", extension_count, extensions); + GLAD_VK_MESA_image_alignment_control = glad_vk_has_extension("VK_MESA_image_alignment_control", extension_count, extensions); + GLAD_VK_MSFT_layered_driver = glad_vk_has_extension("VK_MSFT_layered_driver", extension_count, extensions); #if defined(VK_USE_PLATFORM_IOS_MVK) GLAD_VK_MVK_ios_surface = glad_vk_has_extension("VK_MVK_ios_surface", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) GLAD_VK_MVK_macos_surface = glad_vk_has_extension("VK_MVK_macos_surface", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_VI_NN) GLAD_VK_NN_vi_surface = glad_vk_has_extension("VK_NN_vi_surface", extension_count, extensions); + #endif + GLAD_VK_NVX_binary_import = glad_vk_has_extension("VK_NVX_binary_import", extension_count, extensions); GLAD_VK_NVX_image_view_handle = glad_vk_has_extension("VK_NVX_image_view_handle", extension_count, extensions); GLAD_VK_NVX_multiview_per_view_attributes = glad_vk_has_extension("VK_NVX_multiview_per_view_attributes", extension_count, extensions); +#if defined(VK_USE_PLATFORM_WIN32_KHR) + GLAD_VK_NV_acquire_winrt_display = glad_vk_has_extension("VK_NV_acquire_winrt_display", extension_count, extensions); + +#endif GLAD_VK_NV_clip_space_w_scaling = glad_vk_has_extension("VK_NV_clip_space_w_scaling", extension_count, extensions); + GLAD_VK_NV_cluster_acceleration_structure = glad_vk_has_extension("VK_NV_cluster_acceleration_structure", extension_count, extensions); + GLAD_VK_NV_command_buffer_inheritance = glad_vk_has_extension("VK_NV_command_buffer_inheritance", extension_count, extensions); GLAD_VK_NV_compute_shader_derivatives = glad_vk_has_extension("VK_NV_compute_shader_derivatives", extension_count, extensions); GLAD_VK_NV_cooperative_matrix = glad_vk_has_extension("VK_NV_cooperative_matrix", extension_count, extensions); + GLAD_VK_NV_cooperative_matrix2 = glad_vk_has_extension("VK_NV_cooperative_matrix2", extension_count, extensions); + GLAD_VK_NV_cooperative_vector = glad_vk_has_extension("VK_NV_cooperative_vector", extension_count, extensions); + GLAD_VK_NV_copy_memory_indirect = glad_vk_has_extension("VK_NV_copy_memory_indirect", extension_count, extensions); GLAD_VK_NV_corner_sampled_image = glad_vk_has_extension("VK_NV_corner_sampled_image", extension_count, extensions); GLAD_VK_NV_coverage_reduction_mode = glad_vk_has_extension("VK_NV_coverage_reduction_mode", extension_count, extensions); +#if defined(VK_ENABLE_BETA_EXTENSIONS) + GLAD_VK_NV_cuda_kernel_launch = glad_vk_has_extension("VK_NV_cuda_kernel_launch", extension_count, extensions); + +#endif GLAD_VK_NV_dedicated_allocation = glad_vk_has_extension("VK_NV_dedicated_allocation", extension_count, extensions); GLAD_VK_NV_dedicated_allocation_image_aliasing = glad_vk_has_extension("VK_NV_dedicated_allocation_image_aliasing", extension_count, extensions); + GLAD_VK_NV_descriptor_pool_overallocation = glad_vk_has_extension("VK_NV_descriptor_pool_overallocation", extension_count, extensions); GLAD_VK_NV_device_diagnostic_checkpoints = glad_vk_has_extension("VK_NV_device_diagnostic_checkpoints", extension_count, extensions); GLAD_VK_NV_device_diagnostics_config = glad_vk_has_extension("VK_NV_device_diagnostics_config", extension_count, extensions); GLAD_VK_NV_device_generated_commands = glad_vk_has_extension("VK_NV_device_generated_commands", extension_count, extensions); + GLAD_VK_NV_device_generated_commands_compute = glad_vk_has_extension("VK_NV_device_generated_commands_compute", extension_count, extensions); +#if defined(VK_ENABLE_BETA_EXTENSIONS) + GLAD_VK_NV_displacement_micromap = glad_vk_has_extension("VK_NV_displacement_micromap", extension_count, extensions); + +#endif + GLAD_VK_NV_display_stereo = glad_vk_has_extension("VK_NV_display_stereo", extension_count, extensions); + GLAD_VK_NV_extended_sparse_address_space = glad_vk_has_extension("VK_NV_extended_sparse_address_space", extension_count, extensions); + GLAD_VK_NV_external_compute_queue = glad_vk_has_extension("VK_NV_external_compute_queue", extension_count, extensions); GLAD_VK_NV_external_memory = glad_vk_has_extension("VK_NV_external_memory", extension_count, extensions); GLAD_VK_NV_external_memory_capabilities = glad_vk_has_extension("VK_NV_external_memory_capabilities", extension_count, extensions); + GLAD_VK_NV_external_memory_rdma = glad_vk_has_extension("VK_NV_external_memory_rdma", extension_count, extensions); #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_NV_external_memory_win32 = glad_vk_has_extension("VK_NV_external_memory_win32", extension_count, extensions); + #endif GLAD_VK_NV_fill_rectangle = glad_vk_has_extension("VK_NV_fill_rectangle", extension_count, extensions); GLAD_VK_NV_fragment_coverage_to_color = glad_vk_has_extension("VK_NV_fragment_coverage_to_color", extension_count, extensions); GLAD_VK_NV_fragment_shader_barycentric = glad_vk_has_extension("VK_NV_fragment_shader_barycentric", extension_count, extensions); + GLAD_VK_NV_fragment_shading_rate_enums = glad_vk_has_extension("VK_NV_fragment_shading_rate_enums", extension_count, extensions); GLAD_VK_NV_framebuffer_mixed_samples = glad_vk_has_extension("VK_NV_framebuffer_mixed_samples", extension_count, extensions); GLAD_VK_NV_geometry_shader_passthrough = glad_vk_has_extension("VK_NV_geometry_shader_passthrough", extension_count, extensions); GLAD_VK_NV_glsl_shader = glad_vk_has_extension("VK_NV_glsl_shader", extension_count, extensions); + GLAD_VK_NV_inherited_viewport_scissor = glad_vk_has_extension("VK_NV_inherited_viewport_scissor", extension_count, extensions); + GLAD_VK_NV_linear_color_attachment = glad_vk_has_extension("VK_NV_linear_color_attachment", extension_count, extensions); + GLAD_VK_NV_low_latency = glad_vk_has_extension("VK_NV_low_latency", extension_count, extensions); + GLAD_VK_NV_low_latency2 = glad_vk_has_extension("VK_NV_low_latency2", extension_count, extensions); + GLAD_VK_NV_memory_decompression = glad_vk_has_extension("VK_NV_memory_decompression", extension_count, extensions); GLAD_VK_NV_mesh_shader = glad_vk_has_extension("VK_NV_mesh_shader", extension_count, extensions); + GLAD_VK_NV_optical_flow = glad_vk_has_extension("VK_NV_optical_flow", extension_count, extensions); + GLAD_VK_NV_partitioned_acceleration_structure = glad_vk_has_extension("VK_NV_partitioned_acceleration_structure", extension_count, extensions); + GLAD_VK_NV_per_stage_descriptor_set = glad_vk_has_extension("VK_NV_per_stage_descriptor_set", extension_count, extensions); + GLAD_VK_NV_present_barrier = glad_vk_has_extension("VK_NV_present_barrier", extension_count, extensions); +#if defined(VK_ENABLE_BETA_EXTENSIONS) + GLAD_VK_NV_present_metering = glad_vk_has_extension("VK_NV_present_metering", extension_count, extensions); + +#endif + GLAD_VK_NV_raw_access_chains = glad_vk_has_extension("VK_NV_raw_access_chains", extension_count, extensions); GLAD_VK_NV_ray_tracing = glad_vk_has_extension("VK_NV_ray_tracing", extension_count, extensions); + GLAD_VK_NV_ray_tracing_invocation_reorder = glad_vk_has_extension("VK_NV_ray_tracing_invocation_reorder", extension_count, extensions); + GLAD_VK_NV_ray_tracing_linear_swept_spheres = glad_vk_has_extension("VK_NV_ray_tracing_linear_swept_spheres", extension_count, extensions); + GLAD_VK_NV_ray_tracing_motion_blur = glad_vk_has_extension("VK_NV_ray_tracing_motion_blur", extension_count, extensions); + GLAD_VK_NV_ray_tracing_validation = glad_vk_has_extension("VK_NV_ray_tracing_validation", extension_count, extensions); GLAD_VK_NV_representative_fragment_test = glad_vk_has_extension("VK_NV_representative_fragment_test", extension_count, extensions); GLAD_VK_NV_sample_mask_override_coverage = glad_vk_has_extension("VK_NV_sample_mask_override_coverage", extension_count, extensions); GLAD_VK_NV_scissor_exclusive = glad_vk_has_extension("VK_NV_scissor_exclusive", extension_count, extensions); + GLAD_VK_NV_shader_atomic_float16_vector = glad_vk_has_extension("VK_NV_shader_atomic_float16_vector", extension_count, extensions); GLAD_VK_NV_shader_image_footprint = glad_vk_has_extension("VK_NV_shader_image_footprint", extension_count, extensions); GLAD_VK_NV_shader_sm_builtins = glad_vk_has_extension("VK_NV_shader_sm_builtins", extension_count, extensions); GLAD_VK_NV_shader_subgroup_partitioned = glad_vk_has_extension("VK_NV_shader_subgroup_partitioned", extension_count, extensions); @@ -1985,10 +3389,36 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { GLAD_VK_NV_viewport_swizzle = glad_vk_has_extension("VK_NV_viewport_swizzle", extension_count, extensions); #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_NV_win32_keyed_mutex = glad_vk_has_extension("VK_NV_win32_keyed_mutex", extension_count, extensions); + #endif + GLAD_VK_QCOM_filter_cubic_clamp = glad_vk_has_extension("VK_QCOM_filter_cubic_clamp", extension_count, extensions); + GLAD_VK_QCOM_filter_cubic_weights = glad_vk_has_extension("VK_QCOM_filter_cubic_weights", extension_count, extensions); + GLAD_VK_QCOM_fragment_density_map_offset = glad_vk_has_extension("VK_QCOM_fragment_density_map_offset", extension_count, extensions); + GLAD_VK_QCOM_image_processing = glad_vk_has_extension("VK_QCOM_image_processing", extension_count, extensions); + GLAD_VK_QCOM_image_processing2 = glad_vk_has_extension("VK_QCOM_image_processing2", extension_count, extensions); + GLAD_VK_QCOM_multiview_per_view_render_areas = glad_vk_has_extension("VK_QCOM_multiview_per_view_render_areas", extension_count, extensions); + GLAD_VK_QCOM_multiview_per_view_viewports = glad_vk_has_extension("VK_QCOM_multiview_per_view_viewports", extension_count, extensions); GLAD_VK_QCOM_render_pass_shader_resolve = glad_vk_has_extension("VK_QCOM_render_pass_shader_resolve", extension_count, extensions); GLAD_VK_QCOM_render_pass_store_ops = glad_vk_has_extension("VK_QCOM_render_pass_store_ops", extension_count, extensions); GLAD_VK_QCOM_render_pass_transform = glad_vk_has_extension("VK_QCOM_render_pass_transform", extension_count, extensions); + GLAD_VK_QCOM_rotated_copy_commands = glad_vk_has_extension("VK_QCOM_rotated_copy_commands", extension_count, extensions); + GLAD_VK_QCOM_tile_memory_heap = glad_vk_has_extension("VK_QCOM_tile_memory_heap", extension_count, extensions); + GLAD_VK_QCOM_tile_properties = glad_vk_has_extension("VK_QCOM_tile_properties", extension_count, extensions); + GLAD_VK_QCOM_tile_shading = glad_vk_has_extension("VK_QCOM_tile_shading", extension_count, extensions); + GLAD_VK_QCOM_ycbcr_degamma = glad_vk_has_extension("VK_QCOM_ycbcr_degamma", extension_count, extensions); +#if defined(VK_USE_PLATFORM_SCREEN_QNX) + GLAD_VK_QNX_external_memory_screen_buffer = glad_vk_has_extension("VK_QNX_external_memory_screen_buffer", extension_count, extensions); + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) + GLAD_VK_QNX_screen_surface = glad_vk_has_extension("VK_QNX_screen_surface", extension_count, extensions); + +#endif + GLAD_VK_SEC_amigo_profiling = glad_vk_has_extension("VK_SEC_amigo_profiling", extension_count, extensions); + GLAD_VK_VALVE_descriptor_set_host_mapping = glad_vk_has_extension("VK_VALVE_descriptor_set_host_mapping", extension_count, extensions); + GLAD_VK_VALVE_mutable_descriptor_type = glad_vk_has_extension("VK_VALVE_mutable_descriptor_type", extension_count, extensions); + + GLAD_UNUSED(&glad_vk_has_extension); glad_vk_free_extensions(extension_count, extensions); @@ -2023,6 +3453,8 @@ static int glad_vk_find_core_vulkan( VkPhysicalDevice physical_device) { GLAD_VK_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; GLAD_VK_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; GLAD_VK_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GLAD_VK_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GLAD_VK_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; return GLAD_MAKE_VERSION(major, minor); } @@ -2041,139 +3473,255 @@ int gladLoadVulkanUserPtr( VkPhysicalDevice physical_device, GLADuserptrloadfunc glad_vk_load_VK_VERSION_1_0(load, userptr); glad_vk_load_VK_VERSION_1_1(load, userptr); glad_vk_load_VK_VERSION_1_2(load, userptr); + glad_vk_load_VK_VERSION_1_3(load, userptr); + glad_vk_load_VK_VERSION_1_4(load, userptr); if (!glad_vk_find_extensions_vulkan( physical_device)) return 0; +#if defined(VK_ENABLE_BETA_EXTENSIONS) + glad_vk_load_VK_AMDX_shader_enqueue(load, userptr); + +#endif + glad_vk_load_VK_AMD_anti_lag(load, userptr); glad_vk_load_VK_AMD_buffer_marker(load, userptr); glad_vk_load_VK_AMD_display_native_hdr(load, userptr); glad_vk_load_VK_AMD_draw_indirect_count(load, userptr); glad_vk_load_VK_AMD_shader_info(load, userptr); #if defined(VK_USE_PLATFORM_ANDROID_KHR) glad_vk_load_VK_ANDROID_external_memory_android_hardware_buffer(load, userptr); + #endif + glad_vk_load_VK_EXT_acquire_drm_display(load, userptr); #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) glad_vk_load_VK_EXT_acquire_xlib_display(load, userptr); + #endif + glad_vk_load_VK_EXT_attachment_feedback_loop_dynamic_state(load, userptr); glad_vk_load_VK_EXT_buffer_device_address(load, userptr); glad_vk_load_VK_EXT_calibrated_timestamps(load, userptr); + glad_vk_load_VK_EXT_color_write_enable(load, userptr); glad_vk_load_VK_EXT_conditional_rendering(load, userptr); glad_vk_load_VK_EXT_debug_marker(load, userptr); glad_vk_load_VK_EXT_debug_report(load, userptr); glad_vk_load_VK_EXT_debug_utils(load, userptr); + glad_vk_load_VK_EXT_depth_bias_control(load, userptr); + glad_vk_load_VK_EXT_depth_clamp_control(load, userptr); + glad_vk_load_VK_EXT_descriptor_buffer(load, userptr); + glad_vk_load_VK_EXT_device_fault(load, userptr); + glad_vk_load_VK_EXT_device_generated_commands(load, userptr); glad_vk_load_VK_EXT_direct_mode_display(load, userptr); #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) glad_vk_load_VK_EXT_directfb_surface(load, userptr); + #endif glad_vk_load_VK_EXT_discard_rectangles(load, userptr); glad_vk_load_VK_EXT_display_control(load, userptr); glad_vk_load_VK_EXT_display_surface_counter(load, userptr); glad_vk_load_VK_EXT_extended_dynamic_state(load, userptr); + glad_vk_load_VK_EXT_extended_dynamic_state2(load, userptr); + glad_vk_load_VK_EXT_extended_dynamic_state3(load, userptr); glad_vk_load_VK_EXT_external_memory_host(load, userptr); +#if defined(VK_USE_PLATFORM_METAL_EXT) + glad_vk_load_VK_EXT_external_memory_metal(load, userptr); + +#endif + glad_vk_load_VK_EXT_fragment_density_map_offset(load, userptr); #if defined(VK_USE_PLATFORM_WIN32_KHR) glad_vk_load_VK_EXT_full_screen_exclusive(load, userptr); + #endif glad_vk_load_VK_EXT_hdr_metadata(load, userptr); glad_vk_load_VK_EXT_headless_surface(load, userptr); + glad_vk_load_VK_EXT_host_image_copy(load, userptr); glad_vk_load_VK_EXT_host_query_reset(load, userptr); + glad_vk_load_VK_EXT_image_compression_control(load, userptr); glad_vk_load_VK_EXT_image_drm_format_modifier(load, userptr); glad_vk_load_VK_EXT_line_rasterization(load, userptr); + glad_vk_load_VK_EXT_mesh_shader(load, userptr); +#if defined(VK_USE_PLATFORM_METAL_EXT) + glad_vk_load_VK_EXT_metal_objects(load, userptr); + +#endif #if defined(VK_USE_PLATFORM_METAL_EXT) glad_vk_load_VK_EXT_metal_surface(load, userptr); + #endif + glad_vk_load_VK_EXT_multi_draw(load, userptr); + glad_vk_load_VK_EXT_opacity_micromap(load, userptr); + glad_vk_load_VK_EXT_pageable_device_local_memory(load, userptr); + glad_vk_load_VK_EXT_pipeline_properties(load, userptr); glad_vk_load_VK_EXT_private_data(load, userptr); glad_vk_load_VK_EXT_sample_locations(load, userptr); + glad_vk_load_VK_EXT_shader_module_identifier(load, userptr); + glad_vk_load_VK_EXT_shader_object(load, userptr); + glad_vk_load_VK_EXT_swapchain_maintenance1(load, userptr); glad_vk_load_VK_EXT_tooling_info(load, userptr); glad_vk_load_VK_EXT_transform_feedback(load, userptr); glad_vk_load_VK_EXT_validation_cache(load, userptr); + glad_vk_load_VK_EXT_vertex_input_dynamic_state(load, userptr); +#if defined(VK_USE_PLATFORM_FUCHSIA) + glad_vk_load_VK_FUCHSIA_buffer_collection(load, userptr); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) + glad_vk_load_VK_FUCHSIA_external_memory(load, userptr); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) + glad_vk_load_VK_FUCHSIA_external_semaphore(load, userptr); + +#endif #if defined(VK_USE_PLATFORM_FUCHSIA) glad_vk_load_VK_FUCHSIA_imagepipe_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_GGP) glad_vk_load_VK_GGP_stream_descriptor_surface(load, userptr); + #endif glad_vk_load_VK_GOOGLE_display_timing(load, userptr); + glad_vk_load_VK_HUAWEI_cluster_culling_shader(load, userptr); + glad_vk_load_VK_HUAWEI_invocation_mask(load, userptr); + glad_vk_load_VK_HUAWEI_subpass_shading(load, userptr); glad_vk_load_VK_INTEL_performance_query(load, userptr); + glad_vk_load_VK_KHR_acceleration_structure(load, userptr); #if defined(VK_USE_PLATFORM_ANDROID_KHR) glad_vk_load_VK_KHR_android_surface(load, userptr); + #endif glad_vk_load_VK_KHR_bind_memory2(load, userptr); glad_vk_load_VK_KHR_buffer_device_address(load, userptr); + glad_vk_load_VK_KHR_calibrated_timestamps(load, userptr); + glad_vk_load_VK_KHR_cooperative_matrix(load, userptr); + glad_vk_load_VK_KHR_copy_commands2(load, userptr); glad_vk_load_VK_KHR_create_renderpass2(load, userptr); -#if defined(VK_ENABLE_BETA_EXTENSIONS) glad_vk_load_VK_KHR_deferred_host_operations(load, userptr); -#endif glad_vk_load_VK_KHR_descriptor_update_template(load, userptr); glad_vk_load_VK_KHR_device_group(load, userptr); glad_vk_load_VK_KHR_device_group_creation(load, userptr); glad_vk_load_VK_KHR_display(load, userptr); glad_vk_load_VK_KHR_display_swapchain(load, userptr); glad_vk_load_VK_KHR_draw_indirect_count(load, userptr); + glad_vk_load_VK_KHR_dynamic_rendering(load, userptr); + glad_vk_load_VK_KHR_dynamic_rendering_local_read(load, userptr); glad_vk_load_VK_KHR_external_fence_capabilities(load, userptr); glad_vk_load_VK_KHR_external_fence_fd(load, userptr); #if defined(VK_USE_PLATFORM_WIN32_KHR) glad_vk_load_VK_KHR_external_fence_win32(load, userptr); + #endif glad_vk_load_VK_KHR_external_memory_capabilities(load, userptr); glad_vk_load_VK_KHR_external_memory_fd(load, userptr); #if defined(VK_USE_PLATFORM_WIN32_KHR) glad_vk_load_VK_KHR_external_memory_win32(load, userptr); + #endif glad_vk_load_VK_KHR_external_semaphore_capabilities(load, userptr); glad_vk_load_VK_KHR_external_semaphore_fd(load, userptr); #if defined(VK_USE_PLATFORM_WIN32_KHR) glad_vk_load_VK_KHR_external_semaphore_win32(load, userptr); + #endif + glad_vk_load_VK_KHR_fragment_shading_rate(load, userptr); glad_vk_load_VK_KHR_get_display_properties2(load, userptr); glad_vk_load_VK_KHR_get_memory_requirements2(load, userptr); glad_vk_load_VK_KHR_get_physical_device_properties2(load, userptr); glad_vk_load_VK_KHR_get_surface_capabilities2(load, userptr); + glad_vk_load_VK_KHR_line_rasterization(load, userptr); glad_vk_load_VK_KHR_maintenance1(load, userptr); glad_vk_load_VK_KHR_maintenance3(load, userptr); + glad_vk_load_VK_KHR_maintenance4(load, userptr); + glad_vk_load_VK_KHR_maintenance5(load, userptr); + glad_vk_load_VK_KHR_maintenance6(load, userptr); + glad_vk_load_VK_KHR_map_memory2(load, userptr); glad_vk_load_VK_KHR_performance_query(load, userptr); + glad_vk_load_VK_KHR_pipeline_binary(load, userptr); glad_vk_load_VK_KHR_pipeline_executable_properties(load, userptr); + glad_vk_load_VK_KHR_present_wait(load, userptr); glad_vk_load_VK_KHR_push_descriptor(load, userptr); -#if defined(VK_ENABLE_BETA_EXTENSIONS) - glad_vk_load_VK_KHR_ray_tracing(load, userptr); -#endif + glad_vk_load_VK_KHR_ray_tracing_maintenance1(load, userptr); + glad_vk_load_VK_KHR_ray_tracing_pipeline(load, userptr); glad_vk_load_VK_KHR_sampler_ycbcr_conversion(load, userptr); glad_vk_load_VK_KHR_shared_presentable_image(load, userptr); glad_vk_load_VK_KHR_surface(load, userptr); glad_vk_load_VK_KHR_swapchain(load, userptr); + glad_vk_load_VK_KHR_synchronization2(load, userptr); glad_vk_load_VK_KHR_timeline_semaphore(load, userptr); #if defined(VK_USE_PLATFORM_WAYLAND_KHR) glad_vk_load_VK_KHR_wayland_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) glad_vk_load_VK_KHR_win32_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) glad_vk_load_VK_KHR_xcb_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) glad_vk_load_VK_KHR_xlib_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_IOS_MVK) glad_vk_load_VK_MVK_ios_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) glad_vk_load_VK_MVK_macos_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_VI_NN) glad_vk_load_VK_NN_vi_surface(load, userptr); + #endif + glad_vk_load_VK_NVX_binary_import(load, userptr); glad_vk_load_VK_NVX_image_view_handle(load, userptr); +#if defined(VK_USE_PLATFORM_WIN32_KHR) + glad_vk_load_VK_NV_acquire_winrt_display(load, userptr); + +#endif glad_vk_load_VK_NV_clip_space_w_scaling(load, userptr); + glad_vk_load_VK_NV_cluster_acceleration_structure(load, userptr); glad_vk_load_VK_NV_cooperative_matrix(load, userptr); + glad_vk_load_VK_NV_cooperative_matrix2(load, userptr); + glad_vk_load_VK_NV_cooperative_vector(load, userptr); + glad_vk_load_VK_NV_copy_memory_indirect(load, userptr); glad_vk_load_VK_NV_coverage_reduction_mode(load, userptr); +#if defined(VK_ENABLE_BETA_EXTENSIONS) + glad_vk_load_VK_NV_cuda_kernel_launch(load, userptr); + +#endif glad_vk_load_VK_NV_device_diagnostic_checkpoints(load, userptr); glad_vk_load_VK_NV_device_generated_commands(load, userptr); + glad_vk_load_VK_NV_device_generated_commands_compute(load, userptr); + glad_vk_load_VK_NV_external_compute_queue(load, userptr); glad_vk_load_VK_NV_external_memory_capabilities(load, userptr); + glad_vk_load_VK_NV_external_memory_rdma(load, userptr); #if defined(VK_USE_PLATFORM_WIN32_KHR) glad_vk_load_VK_NV_external_memory_win32(load, userptr); + #endif + glad_vk_load_VK_NV_fragment_shading_rate_enums(load, userptr); + glad_vk_load_VK_NV_low_latency2(load, userptr); + glad_vk_load_VK_NV_memory_decompression(load, userptr); glad_vk_load_VK_NV_mesh_shader(load, userptr); + glad_vk_load_VK_NV_optical_flow(load, userptr); + glad_vk_load_VK_NV_partitioned_acceleration_structure(load, userptr); glad_vk_load_VK_NV_ray_tracing(load, userptr); glad_vk_load_VK_NV_scissor_exclusive(load, userptr); glad_vk_load_VK_NV_shading_rate_image(load, userptr); + glad_vk_load_VK_QCOM_tile_memory_heap(load, userptr); + glad_vk_load_VK_QCOM_tile_properties(load, userptr); + glad_vk_load_VK_QCOM_tile_shading(load, userptr); +#if defined(VK_USE_PLATFORM_SCREEN_QNX) + glad_vk_load_VK_QNX_external_memory_screen_buffer(load, userptr); + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) + glad_vk_load_VK_QNX_screen_surface(load, userptr); + +#endif + glad_vk_load_VK_VALVE_descriptor_set_host_mapping(load, userptr); return version; diff --git a/lib/irrlicht/source/Irrlicht/MoltenVK.mm b/lib/irrlicht/source/Irrlicht/MoltenVK.mm index b8aa130cc8b..9bbb8b19039 100644 --- a/lib/irrlicht/source/Irrlicht/MoltenVK.mm +++ b/lib/irrlicht/source/Irrlicht/MoltenVK.mm @@ -6,8 +6,6 @@ #import #ifdef DLOPEN_MOLTENVK -PFN_vkGetMoltenVKConfigurationMVK vkGetMoltenVKConfigurationMVK = NULL; -PFN_vkSetMoltenVKConfigurationMVK vkSetMoltenVKConfigurationMVK = NULL; PFN_vkGetPhysicalDeviceMetalFeaturesMVK vkGetPhysicalDeviceMetalFeaturesMVK = NULL; namespace irr @@ -39,15 +37,9 @@ SDL_Vulkan_UnloadLibrary(); return; } - vkGetMoltenVKConfigurationMVK = (PFN_vkGetMoltenVKConfigurationMVK) - dlsym(m_handle, "vkGetMoltenVKConfigurationMVK"); - vkSetMoltenVKConfigurationMVK = (PFN_vkSetMoltenVKConfigurationMVK) - dlsym(m_handle, "vkSetMoltenVKConfigurationMVK"); vkGetPhysicalDeviceMetalFeaturesMVK = (PFN_vkGetPhysicalDeviceMetalFeaturesMVK) dlsym(m_handle, "vkGetPhysicalDeviceMetalFeaturesMVK"); - if (!vkGetMoltenVKConfigurationMVK || - !vkSetMoltenVKConfigurationMVK || - !vkGetPhysicalDeviceMetalFeaturesMVK) + if (!vkGetPhysicalDeviceMetalFeaturesMVK) { SDL_Vulkan_UnloadLibrary(); return; From 63af3c2b57665b80b93f557cee3b12db2e5a1742 Mon Sep 17 00:00:00 2001 From: Deve Date: Wed, 7 May 2025 23:28:04 +0200 Subject: [PATCH 699/830] Add spot lights rendering for opengl --- data/shaders/pointlight.frag | 16 +++++++++ data/shaders/pointlight.vert | 3 ++ data/shaders/pointlightscatter.frag | 27 ++++++++++++++-- src/graphics/light.cpp | 1 + src/graphics/light.hpp | 9 ++++++ src/graphics/lighting_passes.cpp | 35 ++++++++++++++++++++ src/graphics/sp/sp_mesh_buffer.hpp | 7 +++- src/karts/kart_model.cpp | 50 ++++++++++++++++++++++++++--- src/karts/kart_model.hpp | 3 ++ 9 files changed, 144 insertions(+), 7 deletions(-) diff --git a/data/shaders/pointlight.frag b/data/shaders/pointlight.frag index cef44536ad3..834dcaa6f06 100644 --- a/data/shaders/pointlight.frag +++ b/data/shaders/pointlight.frag @@ -9,6 +9,7 @@ flat in vec3 center; flat in float energy; flat in vec3 col; flat in float radius; +flat in vec4 direction_scale_offset; #ifdef GL_ES layout (location = 0) out vec4 Diff; @@ -42,6 +43,21 @@ void main() att *= (radius - d) / radius; if (att <= 0.) discard; + // Spotlight + float sscale = direction_scale_offset.z; + if (sscale != 0.) + { + vec3 sdir = vec3(direction_scale_offset.xy, 0.); + sdir.z = sqrt(1. - dot(sdir, sdir)) * sign(sscale); + sdir = (u_view_matrix * vec4(sdir, 0.0)).xyz; + vec3 light_to_frag = light_pos - xpos.xyz; + float offset = direction_scale_offset.w; + float sattenuation = clamp(dot(-sdir, normalize(light_to_frag)) * + abs(sscale) + offset, 0.0, 1.0); + att *= sattenuation * sattenuation; + } + if (att <= 0.) discard; + // Light Direction vec3 L = (light_pos - xpos.xyz) / d; diff --git a/data/shaders/pointlight.vert b/data/shaders/pointlight.vert index c324eb1f7d3..9f1f61f01e1 100644 --- a/data/shaders/pointlight.vert +++ b/data/shaders/pointlight.vert @@ -2,11 +2,13 @@ in vec3 Position; in float Energy; in vec3 Color; in float Radius; +in vec4 Direction_scale_offset; flat out vec3 center; flat out float energy; flat out vec3 col; flat out float radius; +flat out vec4 direction_scale_offset; const float zNear = 1.; @@ -105,4 +107,5 @@ void main(void) center = Position; energy = Energy; radius = Radius; + direction_scale_offset = Direction_scale_offset; } diff --git a/data/shaders/pointlightscatter.frag b/data/shaders/pointlightscatter.frag index 631067ad623..0d66b539dfb 100644 --- a/data/shaders/pointlightscatter.frag +++ b/data/shaders/pointlightscatter.frag @@ -6,6 +6,7 @@ flat in vec3 center; flat in float energy; flat in vec3 col; flat in float radius; +flat in vec4 direction_scale_offset; out vec4 Fog; @@ -34,11 +35,33 @@ void main() vec3 fog_factor = light_col * density * stepsize * energy * 20.; vec3 xpos_step = eyedir * stepsize; + // Spotlight direction calculation + float sscale = direction_scale_offset.z; + vec3 sdir; + if (sscale != 0.) + { + sdir = vec3(direction_scale_offset.xy, 0.); + sdir.z = sqrt(1. - dot(sdir, sdir)) * sign(sscale); + sdir = (u_view_matrix * vec4(sdir, 0.0)).xyz; + } + for (int i = 0; i < 16; i++) { - float d = distance(light_pos, xpos); + vec3 light_to_pos = light_pos - xpos; + float d = length(light_to_pos); float l = (16. - float(i)) * stepsize; - fog += fog_factor / (1. + d * d) * max((radius - d) / radius, 0.) * exp(- density * d) * exp(- density * l); + vec3 base_att = fog_factor / (1. + d * d) * max((radius - d) / radius, 0.) * exp(- density * d) * exp(- density * l); + + // Apply spotlight attenuation + if (sscale != 0.) + { + float offset = direction_scale_offset.w; + float sattenuation = clamp(dot(-sdir, normalize(light_to_pos)) * + abs(sscale) + offset, 0.0, 1.0); + base_att *= sattenuation * sattenuation; + } + + fog += base_att; xpos += xpos_step; } diff --git a/src/graphics/light.cpp b/src/graphics/light.cpp index bd81fc87cfb..73a8abf330b 100644 --- a/src/graphics/light.cpp +++ b/src/graphics/light.cpp @@ -31,6 +31,7 @@ LightNode::LightNode(scene::ISceneManager* mgr, scene::ISceneNode* parent, float m_color[0] = r; m_color[1] = g; m_color[2] = b; + m_spotlight = {}; #ifdef __LIGHT_NODE_VISUALISATION__ m_viz_added = false; diff --git a/src/graphics/light.hpp b/src/graphics/light.hpp index c27cdff5708..ce6023ea497 100644 --- a/src/graphics/light.hpp +++ b/src/graphics/light.hpp @@ -21,6 +21,7 @@ #include #include +#include #include using namespace irr; @@ -30,11 +31,18 @@ namespace irr namespace scene { class IMesh; } } +struct Spotlight +{ + irr::f32 m_outer_cone; + irr::f32 m_inner_cone; +}; + //#define __LIGHT_NODE_VISUALISATION__ // The actual node class LightNode: public scene::ISceneNode { + Spotlight m_spotlight; #ifdef __LIGHT_NODE_VISUALISATION__ bool m_viz_added; #endif @@ -67,6 +75,7 @@ class LightNode: public scene::ISceneNode // For the debug menu void setEnergy(float energy) { m_energy = energy; } void setRadius(float radius) { m_radius = radius; } + Spotlight& getSpotlightData() { return m_spotlight; } protected: static core::aabbox3df box; diff --git a/src/graphics/lighting_passes.cpp b/src/graphics/lighting_passes.cpp index 6f0b507d11d..ea82e35969c 100644 --- a/src/graphics/lighting_passes.cpp +++ b/src/graphics/lighting_passes.cpp @@ -33,6 +33,7 @@ #include "utils/profiler.hpp" #include +#include class LightBaseClass { @@ -47,6 +48,10 @@ class LightBaseClass float green; float blue; float radius; + float direction_x; + float direction_y; + float scale; + float offset; }; public: static const unsigned int MAXLIGHT = 32; @@ -86,6 +91,7 @@ class PointLightShader : public TextureShader < PointLightShader, 2 > GLuint attrib_Color = glGetAttribLocation(m_program, "Color"); GLuint attrib_Energy = glGetAttribLocation(m_program, "Energy"); GLuint attrib_Radius = glGetAttribLocation(m_program, "Radius"); + GLuint attrib_DSO = glGetAttribLocation(m_program, "Direction_scale_offset"); glEnableVertexAttribArray(attrib_Position); glVertexAttribPointer(attrib_Position, 3, GL_FLOAT, GL_FALSE, @@ -102,11 +108,16 @@ class PointLightShader : public TextureShader < PointLightShader, 2 > glVertexAttribPointer(attrib_Radius, 1, GL_FLOAT, GL_FALSE, sizeof(LightBaseClass::PointLightInfo), (GLvoid*)(7 * sizeof(float))); + glEnableVertexAttribArray(attrib_DSO); + glVertexAttribPointer(attrib_DSO, 4, GL_FLOAT, GL_FALSE, + sizeof(LightBaseClass::PointLightInfo), + (GLvoid*)(8 * sizeof(float))); glVertexAttribDivisor(attrib_Position, 1); glVertexAttribDivisor(attrib_Energy, 1); glVertexAttribDivisor(attrib_Color, 1); glVertexAttribDivisor(attrib_Radius, 1); + glVertexAttribDivisor(attrib_DSO, 1); } // PointLightShader ~PointLightShader() { @@ -141,6 +152,7 @@ class PointLightScatterShader : public TextureShadergetRadius(); + float ic = light_node->getSpotlightData().m_inner_cone; + float oc = light_node->getSpotlightData().m_outer_cone; + if (ic != 0.0f && oc != 0.0f) + { + core::vector3df dir(0.0f, 0.0f, 1.0f); + light_node->getAbsoluteTransformation().rotateVect(dir); + dir.normalize(); + m_point_lights_info[m_point_light_count].direction_x = dir.X; + m_point_lights_info[m_point_light_count].direction_y = dir.Y; + float cos_outer = cosf(oc); + m_point_lights_info[m_point_light_count].scale = 1.0f / std::max(cosf(ic) - cos_outer, 1e-4f); + m_point_lights_info[m_point_light_count].offset = -cos_outer * m_point_lights_info[m_point_light_count].scale; + m_point_lights_info[m_point_light_count].scale *= dir.Z > 0.f ? 1.f : -1.f; + } + else + { + m_point_lights_info[m_point_light_count].scale = 0.0f; + } } } if (m_point_light_count > LightBaseClass::MAXLIGHT) diff --git a/src/graphics/sp/sp_mesh_buffer.hpp b/src/graphics/sp/sp_mesh_buffer.hpp index e0ae65d116e..3fb98c9c561 100644 --- a/src/graphics/sp/sp_mesh_buffer.hpp +++ b/src/graphics/sp/sp_mesh_buffer.hpp @@ -124,8 +124,11 @@ class SPMeshBuffer : public IMeshBuffer, public SPPerObjectUniform } else { + unsigned idx_count = std::get<1>(m_stk_material[material_id]); + if (idx_count == 0) + return; glDrawElementsInstanced(GL_TRIANGLES, - std::get<1>(m_stk_material[material_id]), + idx_count, GL_UNSIGNED_SHORT, (void*)(std::get<0>(m_stk_material[material_id]) << 1), (unsigned)m_ins_dat[dct].size()); @@ -436,6 +439,8 @@ class SPMeshBuffer : public IMeshBuffer, public SPPerObjectUniform virtual u32 getChangedID_Vertex() const { return 0; } // ------------------------------------------------------------------------ virtual u32 getChangedID_Index() const { return 0; } + // ------------------------------------------------------------------------ + void disableForMaterial(u32 idx) { std::get<1>(m_stk_material[idx]) = 0; } }; diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index bc605630b87..0083c924011 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -28,6 +28,7 @@ #include "graphics/b3d_mesh_loader.hpp" #include "graphics/irr_driver.hpp" #include "graphics/lod_node.hpp" +#include "graphics/light.hpp" #include "graphics/material.hpp" #include "graphics/material_manager.hpp" #include "graphics/mesh_tools.hpp" @@ -581,7 +582,7 @@ void HeadlightObject::setLight(scene::ISceneNode* parent, float energy, float radius) { bool is_vk = irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN; - if (is_vk && m_spotlight == 1) + if (m_spotlight == 1) energy *= 2.0f; m_node = irr_driver->addLight(core::vector3df(0.0f, 0.0f, 0.0f), energy, radius, m_headlight_color.getRed() / 255.f, @@ -595,6 +596,13 @@ void HeadlightObject::setLight(scene::ISceneNode* parent, data.InnerCone = 30.0f / 180.0f * M_PI; data.OuterCone = 45.0f / 180.0f * M_PI; } + else if (m_spotlight == 1) + { + LightNode* ln = static_cast(m_node); + Spotlight& sl = ln->getSpotlightData(); + sl.m_inner_cone = 30.0f / 180.0f * M_PI; + sl.m_outer_cone = 45.0f / 180.0f * M_PI; + } m_node->grab(); } // setLight @@ -733,12 +741,24 @@ bool KartModel::loadModels(const KartProperties &kart_properties) #ifndef SERVER_ONLY bool spotlight = spotlight_meshes.find(mesh) != spotlight_meshes.end(); GE::GESPM* spm = dynamic_cast(mesh); + SP::SPMesh* spspm = dynamic_cast(mesh); if (obj.getSpotlight() == -1) { - if (!spotlight && spm && handleSpotlight(spm)) + if (spm) { - spotlight_meshes.insert(spm); - spotlight = true; + if (!spotlight && handleSpotlight(spm)) + { + spotlight_meshes.insert(spm); + spotlight = true; + } + } + else if (spspm) + { + if (!spotlight && handleSPSpotlight(spspm)) + { + spotlight_meshes.insert(spspm); + spotlight = true; + } } obj.setSpotlight(spotlight); } @@ -1466,3 +1486,25 @@ bool KartModel::handleSpotlight(GE::GESPM* spm) return spotlight; #endif } // handleSpotlight + +// ---------------------------------------------------------------------------- +bool KartModel::handleSPSpotlight(SP::SPMesh* spm) +{ + unsigned count = spm->getMeshBufferCount(); + bool spotlight = false; + for (int i = count - 1; i >= 0; i--) + { + SP::SPMeshBuffer* b = static_cast(spm->getMeshBuffer(i)); + const auto& materials = b->getAllSTKMaterials(); + for (unsigned i = 0; i < materials.size(); i++) + { + Material* m = materials[i]; + if (m && m->getSamplerPath(0).find("stk_conelight_a.png") != std::string::npos) + { + spotlight = true; + b->disableForMaterial(i); + } + } + } + return spotlight; +} // handleSPSpotlight diff --git a/src/karts/kart_model.hpp b/src/karts/kart_model.hpp index b3c40c9deb9..77d86135568 100644 --- a/src/karts/kart_model.hpp +++ b/src/karts/kart_model.hpp @@ -32,6 +32,7 @@ namespace irr } using namespace irr; namespace GE { class GERenderInfo; class GESPM; } +namespace SP { class SPMesh; } #include "utils/no_copy.hpp" #include "utils/vec3.hpp" @@ -349,6 +350,8 @@ class KartModel : public scene::IAnimationEndCallBack, public NoCopy } // ------------------------------------------------------------------------ bool handleSpotlight(GE::GESPM* spm); + // ------------------------------------------------------------------------ + bool handleSPSpotlight(SP::SPMesh* spm); public: KartModel(bool is_master); From cc8d79d4e73f7641e769e9edb024ba530ca4b7ad Mon Sep 17 00:00:00 2001 From: Deve Date: Wed, 7 May 2025 23:31:14 +0200 Subject: [PATCH 700/830] Fix vulkan skinning shader v_tangent.w is bitangent sign --- data/shaders/ge_shaders/spm_skinning.vert | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/shaders/ge_shaders/spm_skinning.vert b/data/shaders/ge_shaders/spm_skinning.vert index 7be9bb4f1ff..5237db34154 100644 --- a/data/shaders/ge_shaders/spm_skinning.vert +++ b/data/shaders/ge_shaders/spm_skinning.vert @@ -31,7 +31,7 @@ void main() f_hue_change = u_object_buffer.m_objects[gl_InstanceIndex].m_hue_change; #ifdef PBR_ENABLED vec4 skinned_normal = joint_matrix * v_normal; - vec4 skinned_tangent = joint_matrix * v_tangent; + vec4 skinned_tangent = joint_matrix * vec4(v_tangent.xyz, 0.0); vec3 world_normal = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, skinned_normal.xyz); vec3 world_tangent = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, skinned_tangent.xyz); From 1ac91f7554d72266198f4e8d73bc6ed9f6b52819 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 9 May 2025 14:23:21 +0200 Subject: [PATCH 701/830] Fix #5408 --- src/guiengine/widgets/ribbon_widget.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/guiengine/widgets/ribbon_widget.cpp b/src/guiengine/widgets/ribbon_widget.cpp index a4342c9b42e..79373adaee7 100644 --- a/src/guiengine/widgets/ribbon_widget.cpp +++ b/src/guiengine/widgets/ribbon_widget.cpp @@ -859,12 +859,16 @@ void RibbonWidget::resize() tab_contents_rect.UpperLeftCorner.Y + tab_contents_rect.getHeight()); } - // Define the label area and ensure the label doesn't overlap with the icon - rect label_part = rect(icon_part.LowerRightCorner.X + 5, + // Define the label area + rect label_part = rect(tab_contents_rect.UpperLeftCorner.X, tab_contents_rect.UpperLeftCorner.Y, tab_contents_rect.LowerRightCorner.X, tab_contents_rect.LowerRightCorner.Y); + // Ensure the label doesn't overlap with the icon + if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) + label_part.UpperLeftCorner.X += icon_part.getWidth() + 5; + m_active_children[i].m_element->setRelativePosition(tab_rect_abs); if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) m_child_data.at(i).second->setRelativePosition(icon_part); From 984b8c9d87fc53afd27107c04a8800d9c201aabe Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 9 May 2025 16:44:16 +0200 Subject: [PATCH 702/830] Fix #5411 For the instant speed increase to work, the game applies a speed floor that gets reset the next frame. This speed floor is now also adjusted by the adjustSpeed() function. --- src/karts/kart.cpp | 12 ++++++++---- src/karts/max_speed.cpp | 7 +++++-- src/physics/btKart.hpp | 8 ++++++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index a113f3625a4..338b95dc695 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -859,14 +859,17 @@ bool Kart::isInRest() const } // isInRest //----------------------------------------------------------------------------- -/** Multiplies the velocity of the kart by a factor f (both linear - * and angular). This is used by anvils, which suddenly slow down the kart - * when they are attached. +/** Multiplies the velocity of the kart by a factor f (both linear and angular). + * This is used by anchors, which suddenly slow down the kart when they are attached. */ void Kart::adjustSpeed(float f) { m_body->setLinearVelocity(m_body->getLinearVelocity()*f); m_body->setAngularVelocity(m_body->getAngularVelocity()*f); + // Avoid instant speed increase on the same frame ignoring the adjustment, see #5411 + float new_min_speed = m_vehicle->getMinSpeed()*f; + m_vehicle->resetMinSpeed(); // setMinSpeed only update if the new one is greater... See btKart.hpp + m_vehicle->setMinSpeed(new_min_speed); } // adjustSpeed //----------------------------------------------------------------------------- @@ -1375,8 +1378,9 @@ void Kart::update(int ticks) m_powerup->update(ticks); - // Reset any instant speed increase in the bullet kart + // Reset any instant speed increase or speed floor in the bullet kart m_vehicle->resetMaxSpeed(); + m_vehicle->resetMinSpeed(); if (m_bubblegum_ticks > 0) m_bubblegum_ticks -= ticks; diff --git a/src/karts/max_speed.cpp b/src/karts/max_speed.cpp index f586a84cb38..34a3fc10ed8 100644 --- a/src/karts/max_speed.cpp +++ b/src/karts/max_speed.cpp @@ -173,7 +173,7 @@ void MaxSpeed::instantSpeedIncrease(unsigned int category, // This will result in all max speed settings updated, but no // changes to any slow downs since dt=0 update(0); - float speed = std::min(m_kart->getSpeed()+ speed_boost, + float speed = std::min(m_kart->getSpeed() + speed_boost, getCurrentMaxSpeed() ); // If there is a min_speed defined, make sure that the kart is still @@ -182,7 +182,6 @@ void MaxSpeed::instantSpeedIncrease(unsigned int category, if(speed < m_min_speed) speed = m_min_speed; m_kart->getVehicle()->setMinSpeed(speed); - } // instantSpeedIncrease // ---------------------------------------------------------------------------- @@ -441,6 +440,10 @@ void MaxSpeed::update(int ticks) { m_kart->getVehicle()->setMinSpeed(m_min_speed); } + // FIXME: setMinSpeed only updates the value if the new value is greater, + // so the following code doesn't really do anything? + // There is probably a reason for the behavior of setMinSpeed, but the code + // should be redesigned to make it less confusing... else m_kart->getVehicle()->setMinSpeed(0); // no additional acceleration diff --git a/src/physics/btKart.hpp b/src/physics/btKart.hpp index 65ecdd28286..e4c2dfe5812 100644 --- a/src/physics/btKart.hpp +++ b/src/physics/btKart.hpp @@ -274,9 +274,13 @@ class btKart : public btActionInterface // ------------------------------------------------------------------------ /** Resets the maximum so any new maximum value from the application will * be accepted. */ - virtual void resetMaxSpeed() { m_max_speed = -1.0f; m_min_speed = 0.0f; } + virtual void resetMaxSpeed() { m_max_speed = -1.0f; } // ------------------------------------------------------------------------ - /** Sets the minimum speed for this kart. */ + virtual void resetMinSpeed() { m_min_speed = 0.0f; } + // ------------------------------------------------------------------------ + /** Sets the minimum speed for this kart, only if the new value is higher. + * FIXME The name of this function doesn't match its real behavior, it's confusing + * Determine why it needs to work that way and make it cleaner */ void setMinSpeed(float s) { if(s > m_min_speed) m_min_speed = s; From eb6f304ad2402733df85a2985328eec5325490af Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sat, 10 May 2025 16:22:57 +0200 Subject: [PATCH 703/830] Fix #5417 --- src/states_screens/race_result_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 52efc25fd34..d4f7478db50 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -1945,7 +1945,7 @@ int RaceResultGUI::displayHighscores(int x, int y, bool increase_density) scores->getEntry(i, kart_name, player_name, &time); if (player_name.size() > max_characters) { - int begin = (int(m_timer / 0.4f)) % (player_name.size() - max_characters); + int begin = (int(m_timer / 0.4f)) % (player_name.size() - max_characters + 1); player_name = player_name.subString(begin, max_characters, false); } From 14b356ac133195142559f9da5e8b356dc39c7e06 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sat, 10 May 2025 18:29:57 +0200 Subject: [PATCH 704/830] Fix #5419 - Increase the character limit for the name before forced scrolling from 15 to 30. Beyond 30, many parts of the GUI become problematic anyways, and while many reasonable usernames exceed 15, none exceed 30. - Use the actual rendered width of the player name to compute how many characters can be shown at once if scrolling is needed. -- Also check the width of substrings to avoid overflows from uneven character lengths - Add a short pause at the beginning and the end of the name scrolling, as otherwise there is little time to see the first and last characters compared to others --- src/states_screens/race_result_gui.cpp | 47 +++++++++++++++++++++----- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index d4f7478db50..c1c73d5e453 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -1931,21 +1931,50 @@ int RaceResultGUI::displayHighscores(int x, int y, bool increase_density) std::string kart_name; irr::core::stringw player_name; - // prevent excessive long name - unsigned int max_characters = 15; - unsigned int max_width = (UserConfigParams::m_width / 2 - 200) / 10; - if (max_width < 15) - max_characters = max_width; - + const float SCORE_X_RATIO = 0.85f; int width_icon_adjusted = increase_density ? m_width_icon * 0.8f : m_width_icon; + // Used to prevent excessively long names + unsigned int max_width = (int)((float)UserConfigParams::m_width * (SCORE_X_RATIO - 0.65f)) + - width_icon_adjusted - 20; + float time; for (int i = 0; i < scores->getNumberEntries(); i++) { scores->getEntry(i, kart_name, player_name, &time); - if (player_name.size() > max_characters) + float width_ratio = (float)GUIEngine::getSmallFont()->getDimension(player_name.c_str()).Width / (float)max_width; + unsigned int max_characters = 30; + if (player_name.size() > max_characters || width_ratio >= 1.0f) { - int begin = (int(m_timer / 0.4f)) % (player_name.size() - max_characters + 1); + // Different parts of a name can have different width properties: + // - We could assume all the characters are large, but that can waste a lot of space + // - Instead, we do some extra computations to use more space while avoiding overflows + find_length_start: + int substring_test_length = (int)((float)player_name.size() / width_ratio); + unsigned int max_substring_width = 0; + for (uint i=0; i<(player_name.size() - substring_test_length + 1); i++) + { + irr::core::stringw test_substring = player_name.subString(i, substring_test_length, false); + max_substring_width = std::max(max_substring_width, + GUIEngine::getSmallFont()->getDimension(test_substring.c_str()).Width); + } + float substring_overflow_factor = ((float)max_substring_width / (float)max_width); + // If the initial estimate was really off, we refine our estimate + if (substring_overflow_factor > 1.1f) + { + width_ratio *= substring_overflow_factor; + goto find_length_start; + } + + float overflow_factor = substring_overflow_factor * width_ratio * 1.01f; + max_characters = (unsigned int)((float)player_name.size() / overflow_factor); + int overflow_chars = player_name.size() - max_characters; + + // Add 1 to the divisor to ensure the last character is displayed, and add 2 for pauses + int begin = (int(m_timer / 0.4f)) % (overflow_chars + 3) - 1; + if (begin == -1) begin = 0; // Pause at the start + if (begin == overflow_chars + 1) begin = overflow_chars; // Pause at the end + player_name = player_name.subString(begin, max_characters, false); } @@ -1986,7 +2015,7 @@ int RaceResultGUI::displayHighscores(int x, int y, bool increase_density) core::recti(current_x, current_y, current_x + 150, current_y + 10), text_color, false, false, NULL, true /* ignoreRTL */); - current_x = (int)(UserConfigParams::m_width * 0.85f); + current_x = (int)(UserConfigParams::m_width * SCORE_X_RATIO); // Finally draw the time std::string highscore_string; From f77f88782181c4a3a1d123b2992b86281394106c Mon Sep 17 00:00:00 2001 From: Piotr Danecki Date: Sat, 10 May 2025 16:32:46 +0000 Subject: [PATCH 705/830] Add a random track button outside of the track chooser (#5399) Signed-off-by: Piotr Danecki --- data/gui/screens/tracks_and_gp.stkgui | 5 +-- src/states_screens/tracks_and_gp_screen.cpp | 44 +++++++++++---------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/data/gui/screens/tracks_and_gp.stkgui b/data/gui/screens/tracks_and_gp.stkgui index 40f1f647d16..65f4e186656 100644 --- a/data/gui/screens/tracks_and_gp.stkgui +++ b/data/gui/screens/tracks_and_gp.stkgui @@ -24,11 +24,10 @@

- - + +
-
diff --git a/src/states_screens/tracks_and_gp_screen.cpp b/src/states_screens/tracks_and_gp_screen.cpp index 72861f6de50..3c4f03b08ff 100644 --- a/src/states_screens/tracks_and_gp_screen.cpp +++ b/src/states_screens/tracks_and_gp_screen.cpp @@ -51,31 +51,35 @@ static const char ALL_TRACK_GROUPS_ID[] = "all"; void TracksAndGPScreen::eventCallback(Widget* widget, const std::string& name, const int playerID) { - // -- track selection screen - if (name == "tracks") + // -- track selection screen / random track button + if (name == "tracks" || name == "random_track") { - DynamicRibbonWidget* w2 = dynamic_cast(widget); - if(!w2) return; - - std::string selection = w2->getSelectionIDString(PLAYER_ID_GAME_MASTER); - if (UserConfigParams::logGUI()) + std::string selection; + if (name == "tracks") { - Log::info("TracksAndGPScreen", "Clicked on track '%s'.", - selection.c_str()); - } + DynamicRibbonWidget* w2 = dynamic_cast(widget); + if(!w2) return; - UserConfigParams::m_last_track = selection; - if (selection == "locked" && RaceManager::get()->getNumLocalPlayers() == 1) - { - unlock_manager->playLockSound(); - return; - } - else if (selection == RibbonWidget::NO_ITEM_ID) - { - return; + selection = w2->getSelectionIDString(PLAYER_ID_GAME_MASTER); + if (UserConfigParams::logGUI()) + { + Log::info("TracksAndGPScreen", "Clicked on track '%s'.", + selection.c_str()); + } + + UserConfigParams::m_last_track = selection; + if (selection == "locked" && RaceManager::get()->getNumLocalPlayers() == 1) + { + unlock_manager->playLockSound(); + return; + } + else if (selection == RibbonWidget::NO_ITEM_ID) + { + return; + } } - if (selection == "random_track") + if (selection == "random_track" || name == "random_track") { if (m_random_track_list.empty()) return; From 9d9c74f447af566f7ac47cd4d890d1b25a068c14 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sat, 10 May 2025 18:40:04 +0200 Subject: [PATCH 706/830] Adjust the Tracks and GPs screen to better fit the random track button Also fix the portability issue from uint introduced in 14b356a --- data/gui/screens/tracks_and_gp.stkgui | 73 +++++++++++++++++--------- src/states_screens/race_result_gui.cpp | 2 +- 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/data/gui/screens/tracks_and_gp.stkgui b/data/gui/screens/tracks_and_gp.stkgui index 65f4e186656..d68f2355ca7 100644 --- a/data/gui/screens/tracks_and_gp.stkgui +++ b/data/gui/screens/tracks_and_gp.stkgui @@ -3,38 +3,61 @@
-
- -
- - - - - - - - -
+
+
+
- + + + + + + + + +
+
+ + + + +
+ + + +
+
+
+ + -
-
- - -
- - +
+ + + + + + + + + + +
- + diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index c1c73d5e453..79a0f5a4be9 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -1952,7 +1952,7 @@ int RaceResultGUI::displayHighscores(int x, int y, bool increase_density) find_length_start: int substring_test_length = (int)((float)player_name.size() / width_ratio); unsigned int max_substring_width = 0; - for (uint i=0; i<(player_name.size() - substring_test_length + 1); i++) + for (unsigned int i=0; i<(player_name.size() - substring_test_length + 1); i++) { irr::core::stringw test_substring = player_name.subString(i, substring_test_length, false); max_substring_width = std::max(max_substring_width, From ff4087483070a15344bc9d4abddf3e0ab5267f38 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 10 May 2025 20:48:55 +0400 Subject: [PATCH 707/830] Some renames, also string and permission refactors --- src/network/protocols/command_manager.cpp | 31 +++++++++++++++-------- src/network/protocols/server_lobby.cpp | 13 +++++++--- src/network/stk_peer.hpp | 6 ++--- src/utils/crown_manager.cpp | 22 +++++++++++----- src/utils/crown_manager.hpp | 5 +++- src/utils/lobby_asset_manager.cpp | 10 ++++---- src/utils/lobby_asset_manager.hpp | 2 +- src/utils/lobby_settings.cpp | 4 +-- 8 files changed, 60 insertions(+), 33 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 351d073c364..45d330ac22e 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -696,6 +696,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) { if (argv.size() == 1 || argv[1] == "vote") { + // kimden: all error strings in this function should be done in error(context) way getLobby()->sendStringToPeer(peer, "Usage: /vote (a command with arguments)"); return; } @@ -706,6 +707,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) voting = true; action = "vote for"; } + bool restored = false; for (int i = 0; i <= 5; ++i) { if (argv[0] == std::to_string(i)) { @@ -822,7 +824,9 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) std::string new_cmd = p.first + " " + p.second; auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '"', '\\'); CommandManager::restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); - std::string msg2 = "Command \"/" + new_cmd + "\" has been successfully voted"; + std::string msg2 = StringUtils::insertValues( + "Command \"/%s\" has been successfully voted", + new_cmd.c_str()); getLobby()->sendStringToAllPeers(msg2); Context new_context(event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); execute(executed_command, new_context); @@ -884,7 +888,9 @@ void CommandManager::update() std::string new_cmd = p.first + " " + p.second; auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '"', '\\'); CommandManager::restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); - std::string msg = "Command \"/" + new_cmd + "\" has been successfully voted"; + std::string msg = StringUtils::insertValues( + "Command \"/%s\" has been successfully voted", + new_cmd.c_str()); getLobby()->sendStringToAllPeers(msg); // Happily the name of the votable coincides with the command full name std::shared_ptr command = m_full_name_to_command[votable_pairs.first].lock(); @@ -981,8 +987,9 @@ void CommandManager::process_text(Context& context) } auto it = m_text_response.find(command->getFullName()); if (it == m_text_response.end()) - response = "Error: a text command " + command->getFullName() - + " is defined without text"; + response = StringUtils::insertValues( + "Error: a text command %s is defined without text", + command->getFullName().c_str()); else response = it->second; getLobby()->sendStringToPeer(peer, response); @@ -1001,8 +1008,9 @@ void CommandManager::process_file(Context& context) } auto it = m_file_resources.find(command->getFullName()); if (it == m_file_resources.end()) - response = "Error: file not found for a file command " - + command->getFullName(); + response = StringUtils::insertValues( + "Error: file not found for a file command %s", + command->getFullName().c_str()); else response = it->second.get(); getLobby()->sendStringToPeer(peer, response); @@ -1021,8 +1029,9 @@ void CommandManager::process_auth(Context& context) } auto it = m_auth_resources.find(command->getFullName()); if (it == m_auth_resources.end()) - response = "Error: auth method not found for a command " - + command->getFullName(); + response = StringUtils::insertValues( + "Error: auth method not found for a command %s", + command->getFullName().c_str()); else { auto profile = peer->getMainProfile(); @@ -1337,7 +1346,7 @@ void CommandManager::process_addons(Context& context) /*argv[1] == g_type_soccer ?*/ asset_manager->getAddonSoccers() ))); if (apply_filters) - getAssetManager()->applyAllFilters(from, false); // happily the type is never karts in this line + getAssetManager()->applyAllMapFilters(from, false); // happily the type is never karts in this line std::vector>>> result; for (const std::string& s: from) result.push_back({s, {}}); @@ -1761,7 +1770,7 @@ void CommandManager::process_kick(Context& context) error(context); return; } - if (player_peer->isAngryHost()) + if (player_peer->hammerLevel() > 0) { getLobby()->sendStringToPeer(peer, "This player is the owner of " "this server, and is protected from your actions now"); @@ -2360,7 +2369,7 @@ void CommandManager::process_power(Context& context) error(context, true); return; } - if (peer->isAngryHost()) + if (peer->hammerLevel() > 0) { peer->setAngryHost(false); getLobby()->sendStringToPeer(peer, "You are now a normal player"); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 8c065ecf6e4..8d02655f3c5 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2830,9 +2830,10 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) // get OS information auto version_os = StringUtils::extractVersionOS(profile->getPeer()->getUserVersion()); - bool angry_host = profile->getPeer()->isAngryHost(); + int angry_host = profile->getPeer()->hammerLevel(); std::string os_type_str = version_os.second; std::string utf8_profile_name = StringUtils::wideToUtf8(profile_name); + // Add a Mobile emoji for mobile OS if (getSettings()->isExposingMobile() && (os_type_str == "iOS" || os_type_str == "Android")) @@ -2843,7 +2844,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) profile_name = StringUtils::utf32ToWide({ 0x231B }) + profile_name; // Add a hammer emoji for angry host - if (angry_host) + for (int i = angry_host; i > 0; --i) profile_name = StringUtils::utf32ToWide({0x1F528}) + profile_name; std::string prefix = ""; @@ -4262,10 +4263,13 @@ bool ServerLobby::hasHostRights(std::shared_ptr peer) const { if (!peer || peer->getPlayerProfiles().empty()) return false; + if (peer == m_server_owner.lock()) return true; - if (peer->isAngryHost()) + + if (peer->hammerLevel() > 0) return true; + if (isTournament()) return getTournament()->hasHostRights(peer); @@ -4295,7 +4299,8 @@ int ServerLobby::getPermissions(std::shared_ptr peer) const if (getCrownManager()->hasOnlyHostRiding()) mask |= CommandPermissions::PE_SINGLE; } - if (peer->isAngryHost()) + int hammer_level = peer->hammerLevel(); + if (hammer_level >= 1) { mask |= CommandPermissions::PE_HAMMER; } diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index 17a3a3bd8a3..0fb04680792 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -139,7 +139,7 @@ class STKPeer : public NoCopy std::array m_addons_scores; - std::atomic_bool m_angry_host; + std::atomic_int m_angry_host; public: STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id); // ------------------------------------------------------------------------ @@ -379,9 +379,9 @@ class STKPeer : public NoCopy m_always_spectate.store(ASM_NONE); } // ------------------------------------------------------------------------ - bool isAngryHost() const { return m_angry_host.load(); } + int hammerLevel() const { return m_angry_host.load(); } // ------------------------------------------------------------------------ - void setAngryHost(bool val) { m_angry_host.store(val); } + void setAngryHost(int val) { m_angry_host.store(val); } // ------------------------------------------------------------------------ std::shared_ptr getMainProfile(); // ------------------------------------------------------------------------ diff --git a/src/utils/crown_manager.cpp b/src/utils/crown_manager.cpp index 65da8cd3f70..6dc1663c4e1 100644 --- a/src/utils/crown_manager.cpp +++ b/src/utils/crown_manager.cpp @@ -104,9 +104,11 @@ std::set>& CrownManager::getSpectatorsByLimit(bool upda } std::sort(peers.begin(), peers.end(), - [](const std::shared_ptr& a, - const std::shared_ptr& b) - { return a->getRejoinTime() < b->getRejoinTime(); }); + [](const std::shared_ptr& a, const std::shared_ptr& b) + { + return defaultOrderComparator(a, b); + } + ); unsigned player_count = 0; @@ -220,7 +222,7 @@ bool CrownManager::canRace(std::shared_ptr peer) return false; } - getAssetManager()->applyAllFilters(maps, true); + getAssetManager()->applyAllMapFilters(maps, true); getAssetManager()->applyAllKartFilters(username, karts, false); if (karts.empty()) @@ -291,20 +293,28 @@ std::shared_ptr CrownManager::getFirstInCrownOrder( unsigned best = 0; for (unsigned i = 1; i < peers.size(); ++i) - if (defaultOrderComparator(peers[i], peers[best])) + if (defaultCrownComparator(peers[i], peers[best])) best = i; return peers[best]; } // getFirstInCrownOrder //----------------------------------------------------------------------------- -bool CrownManager::defaultOrderComparator( +bool CrownManager::defaultCrownComparator( const std::shared_ptr a, const std::shared_ptr b) { if (a->isCommandSpectator() ^ b->isCommandSpectator()) return b->isCommandSpectator(); + return defaultOrderComparator(a, b); +} // defaultCrownComparator +//----------------------------------------------------------------------------- + +bool CrownManager::defaultOrderComparator( + const std::shared_ptr a, + const std::shared_ptr b) +{ return a->getRejoinTime() < b->getRejoinTime(); } // defaultOrderComparator //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/crown_manager.hpp b/src/utils/crown_manager.hpp index e1731a16971..aae0f5cb25a 100644 --- a/src/utils/crown_manager.hpp +++ b/src/utils/crown_manager.hpp @@ -53,7 +53,10 @@ class CrownManager: public LobbyContextComponent std::shared_ptr getFirstInCrownOrder( const std::vector>& peers); - bool defaultOrderComparator(const std::shared_ptr a, + static bool defaultCrownComparator(const std::shared_ptr a, + const std::shared_ptr b); + + static bool defaultOrderComparator(const std::shared_ptr a, const std::shared_ptr b); private: diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp index 66a0968af72..041076a8105 100644 --- a/src/utils/lobby_asset_manager.cpp +++ b/src/utils/lobby_asset_manager.cpp @@ -264,7 +264,7 @@ void LobbyAssetManager::eraseAssetsWithPeers( bool LobbyAssetManager::tryApplyingMapFilters() { std::set available_tracks_fallback = m_available_kts.second; - applyAllFilters(m_available_kts.second, true); + applyAllMapFilters(m_available_kts.second, true); /* auto iter = m_available_kts.second.begin(); while (iter != m_available_kts.second.end()) @@ -561,7 +561,7 @@ std::string LobbyAssetManager::getRandomMap() const for (const std::string& s: m_entering_kts.second) { items.insert(s); } - applyAllFilters(items, false); + applyAllMapFilters(items, false); if (items.empty()) return ""; RandomGenerator rg; @@ -579,7 +579,7 @@ std::string LobbyAssetManager::getRandomAddonMap() const if (t->isAddon()) items.insert(s); } - applyAllFilters(items, false); + applyAllMapFilters(items, false); if (items.empty()) return ""; RandomGenerator rg; @@ -601,7 +601,7 @@ void LobbyAssetManager::gameFinishedOn(const std::string& map_name) } // gameFinishedOn //----------------------------------------------------------------------------- -void LobbyAssetManager::applyAllFilters(std::set& maps, bool use_history) const +void LobbyAssetManager::applyAllMapFilters(std::set& maps, bool use_history) const { unsigned max_player = 0; STKHost::get()->updatePlayers(&max_player); @@ -638,7 +638,7 @@ void LobbyAssetManager::applyAllFilters(std::set& maps, bool use_hi getQueues()->applyFrontMapFilters(map_context); } std::swap(maps, map_context.elements); -} // applyAllFilters +} // applyAllMapFilters //----------------------------------------------------------------------------- void LobbyAssetManager::applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection) const diff --git a/src/utils/lobby_asset_manager.hpp b/src/utils/lobby_asset_manager.hpp index 75dc0386889..78390df9aa3 100644 --- a/src/utils/lobby_asset_manager.hpp +++ b/src/utils/lobby_asset_manager.hpp @@ -77,7 +77,7 @@ class LobbyAssetManager: public LobbyContextComponent void setMustHaveMaps(const std::string& input); void gameFinishedOn(const std::string& map_name); - void applyAllFilters(std::set& maps, bool use_history) const; + void applyAllMapFilters(std::set& maps, bool use_history) const; void applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection = false) const; void applyGlobalFilter(FilterContext& map_context) const; diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index 0a669a17ad2..37ed7f9088a 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -626,9 +626,9 @@ void LobbySettings::tryKickingAnotherPeer(std::shared_ptr initiator, // Ignore kicking ai peer if ai handling is on if (target && (!hasAiHandling() || !target->isAIPeer())) { - if (target->isAngryHost()) + if (target->hammerLevel() > 0) { - getLobby()->sendStringToPeer(initiator, "This player is the owner of this server, " + getLobby()->sendStringToPeer(initiator, "This player holds admin rights of this server, " "and is protected from your actions now"); return; } From 48b6daf77f7b813da76ae5d32e97d480a281fcfd Mon Sep 17 00:00:00 2001 From: Deve Date: Sat, 3 May 2025 23:50:16 +0200 Subject: [PATCH 708/830] Add point and spot lights rendering for vulkan --- .../ge_shaders/utils/global_light_data.glsl | 21 +++ data/shaders/ge_shaders/utils/handle_pbr.glsl | 14 +- data/shaders/ge_shaders/utils/pbr_light.glsl | 48 ++++++- data/shaders/ge_shaders/utils/spm_data.glsl | 2 +- .../ge_shaders/utils/sun_direction.glsl | 22 +-- lib/graphics_engine/CMakeLists.txt | 2 + lib/graphics_engine/include/ge_main.hpp | 4 + .../include/ge_occlusion_culling.hpp | 80 +++++++++++ .../include/ge_vulkan_driver.hpp | 2 +- lib/graphics_engine/src/ge_culling_tool.cpp | 12 ++ lib/graphics_engine/src/ge_culling_tool.hpp | 2 + lib/graphics_engine/src/ge_main.cpp | 25 ++++ .../src/ge_occlusion_culling.cpp | 129 ++++++++++++++++++ .../src/ge_vulkan_draw_call.cpp | 118 +++++++++++++--- .../src/ge_vulkan_draw_call.hpp | 9 +- .../src/ge_vulkan_dynamic_buffer.cpp | 3 +- .../src/ge_vulkan_light_handler.cpp | 126 +++++++++++++++++ .../src/ge_vulkan_light_handler.hpp | 85 ++++++++++++ .../src/ge_vulkan_scene_manager.cpp | 8 ++ .../src/ge_vulkan_skybox_renderer.cpp | 11 +- .../src/ge_vulkan_skybox_renderer.hpp | 12 ++ src/graphics/irr_driver.cpp | 25 +++- src/graphics/referee.cpp | 33 ++++- src/tracks/track.cpp | 53 ++++++- src/tracks/track.hpp | 4 +- src/tracks/track_object_presentation.cpp | 12 +- 26 files changed, 805 insertions(+), 57 deletions(-) create mode 100644 data/shaders/ge_shaders/utils/global_light_data.glsl create mode 100644 lib/graphics_engine/include/ge_occlusion_culling.hpp create mode 100644 lib/graphics_engine/src/ge_occlusion_culling.cpp create mode 100644 lib/graphics_engine/src/ge_vulkan_light_handler.cpp create mode 100644 lib/graphics_engine/src/ge_vulkan_light_handler.hpp diff --git a/data/shaders/ge_shaders/utils/global_light_data.glsl b/data/shaders/ge_shaders/utils/global_light_data.glsl new file mode 100644 index 00000000000..1c0c7f4343b --- /dev/null +++ b/data/shaders/ge_shaders/utils/global_light_data.glsl @@ -0,0 +1,21 @@ +struct LightData +{ + vec4 m_position_radius; + vec4 m_color_inverse_square_range; + vec4 m_direction_scale_offset; // Spotlight only +}; + +const int MAX_LIGHT = 32; +layout(std140, set = 1, binding = 3) uniform GlobalLightBuffer +{ + vec3 m_ambient_color; + float m_sun_scatter; + vec3 m_sun_color; + float m_sun_angle_tan_half; + vec3 m_sun_direction; + float m_fog_density; + vec4 m_fog_color; + vec3 m_skytop_color; + int m_light_count; + LightData m_lights[MAX_LIGHT]; +} u_global_light; diff --git a/data/shaders/ge_shaders/utils/handle_pbr.glsl b/data/shaders/ge_shaders/utils/handle_pbr.glsl index fdf47ee4497..5fa0acad6dc 100644 --- a/data/shaders/ge_shaders/utils/handle_pbr.glsl +++ b/data/shaders/ge_shaders/utils/handle_pbr.glsl @@ -3,7 +3,9 @@ layout (set = 2, binding = 1) uniform samplerCube u_specular; #include "camera.glsl" #include "constants_utils.glsl" +#include "spm_data.glsl" #include "pbr_utils.glsl" +#include "global_light_data.glsl" #include "get_pos_from_frag_coord.glsl" #include "pbr_light.glsl" @@ -29,16 +31,20 @@ vec3 handlePBR(vec3 diffuse_color, vec3 pbr, vec3 normal) radiance = textureLod(u_specular, world_reflection, radiance_level).rgb; } - vec3 sun = sunDirection(normal, eyedir, vec3(-642.22, 673.75, -219.26)); - vec3 lightdir = normalize(sun.xyz); + vec3 lightdir = sunDirection(reflection, + u_global_light.m_sun_direction, u_global_light.m_sun_angle_tan_half, + u_camera.m_inverse_view_matrix); vec3 mixed_color = PBRSunAmbientEmitLight( normal, eyedir, lightdir, diffuse_color, irradiance, radiance, - vec3(211./256., 235./256., 110./256.), - vec3(120./256., 120./256., 120./256.), + u_global_light.m_sun_color, + u_global_light.m_ambient_color, perceptual_roughness, pbr.y, pbr.z); + mixed_color += accumulateLights(diffuse_color, normal, xpos, eyedir, + perceptual_roughness, pbr.y); + float factor = (1.0 - exp(length(xpos) * -0.0001)); mixed_color = mixed_color + vec3(0.5) * factor; diff --git a/data/shaders/ge_shaders/utils/pbr_light.glsl b/data/shaders/ge_shaders/utils/pbr_light.glsl index 4283b0c7208..506ba309e00 100644 --- a/data/shaders/ge_shaders/utils/pbr_light.glsl +++ b/data/shaders/ge_shaders/utils/pbr_light.glsl @@ -81,12 +81,17 @@ vec3 PBRSunAmbientEmitLight( // Other 0.6 comes from skybox ambient_color *= 0.4; - vec3 environment = vec3(0.325, 0.35, 0.375) * ambient_color * diffuse_color; + vec3 environment; if (u_ibl) { environment = environmentLight(irradiance, radiance, roughness, diffuse_color, F_ab, F0, F90, NdotV); } + else + { + environment = u_global_light.m_skytop_color * ambient_color * + diffuse_color; + } vec3 emit = emissive * color * 4.0; @@ -94,3 +99,44 @@ vec3 PBRSunAmbientEmitLight( + environment + emit + (diffuse_ambient + specular_ambient) * ambient_color; } + +vec3 accumulateLights(vec3 diffuse_color, vec3 normal, vec3 xpos, vec3 eyedir, + float perceptual_roughness, float metallic) +{ + vec3 accumulated_color = vec3(0.0); + for (int i = 0; i < u_global_light.m_light_count; i++) + { + vec3 light_to_frag = (u_camera.m_view_matrix * + vec4(u_global_light.m_lights[i].m_position_radius.xyz, + 1.0)).xyz - xpos; + float invrange = u_global_light.m_lights[i].m_color_inverse_square_range.w; + float distance_sq = dot(light_to_frag, light_to_frag); + if (distance_sq * invrange > 1.) + continue; + float distance = sqrt(distance_sq); + float distance_inverse = 1. / distance; + vec3 L = light_to_frag * distance_inverse; + vec3 diffuse_specular = PBRLight(normal, eyedir, L, diffuse_color, + perceptual_roughness, metallic); + float attenuation = 20. / (1. + distance_sq); + float radius = u_global_light.m_lights[i].m_position_radius.w; + attenuation *= (radius - distance) / radius; + // SpotLight + float sscale = u_global_light.m_lights[i].m_direction_scale_offset.z; + if (sscale != 0.) + { + vec3 sdir = + vec3(u_global_light.m_lights[i].m_direction_scale_offset.xy, 0.); + sdir.z = sqrt(1. - dot(sdir, sdir)) * sign(sscale); + sdir = (u_camera.m_view_matrix * vec4(sdir, 0.0)).xyz; + float sattenuation = clamp(dot(-sdir, normalize(light_to_frag)) * + abs(sscale) + + u_global_light.m_lights[i].m_direction_scale_offset.w, 0.0, 1.0); + attenuation *= sattenuation * sattenuation; + } + vec3 light_color = + u_global_light.m_lights[i].m_color_inverse_square_range.xyz; + accumulated_color += light_color * attenuation * diffuse_specular; + } + return accumulated_color; +} diff --git a/data/shaders/ge_shaders/utils/spm_data.glsl b/data/shaders/ge_shaders/utils/spm_data.glsl index 2952206919c..1a7c67e1bb1 100644 --- a/data/shaders/ge_shaders/utils/spm_data.glsl +++ b/data/shaders/ge_shaders/utils/spm_data.glsl @@ -24,7 +24,7 @@ layout(std140, set = 1, binding = 2) readonly buffer SkinningMatrices } u_skinning_matrices; #ifdef BIND_MESH_TEXTURES_AT_ONCE -layout(std430, set = 1, binding = 3) readonly buffer MaterialIDs +layout(std430, set = 1, binding = 4) readonly buffer MaterialIDs { int m_material_id[]; } u_material_ids; diff --git a/data/shaders/ge_shaders/utils/sun_direction.glsl b/data/shaders/ge_shaders/utils/sun_direction.glsl index f52901c7ebb..ebeecb62d17 100644 --- a/data/shaders/ge_shaders/utils/sun_direction.glsl +++ b/data/shaders/ge_shaders/utils/sun_direction.glsl @@ -1,12 +1,14 @@ -vec3 sunDirection(vec3 normal, vec3 eyedir, vec3 sundirection) +// Sun Most Representative Point (used for MRP area lighting method) +// From "Frostbite going PBR" paper + +vec3 sunDirection(vec3 R, vec3 sun_direction, float sun_angle_tan_half, mat4 inverse_view_matrix) { - vec3 local_sundir = normalize((transpose(u_camera.m_inverse_view_matrix) * vec4(sundirection, 0.)).xyz); - vec3 R = reflect(-eyedir, normal); - float angularRadius = 3.14 * 5. / 180.; - vec3 D = local_sundir; - float d = cos(angularRadius); - float r = sin(angularRadius); - float DdotR = dot(D, R); - vec3 S = R - DdotR * D; - return (DdotR < d) ? normalize(d * D + normalize (S) * r) : R; + sun_direction = normalize((transpose(inverse_view_matrix) * vec4(sun_direction, 0.)).xyz); + float DdotR = dot(sun_direction, R); + vec3 S = normalize(R - DdotR * sun_direction); + float sun_angle_tan_half2 = 1 + sun_angle_tan_half * sun_angle_tan_half; + vec2 sun_angle_sin_cos = vec2(2 * sun_angle_tan_half, 2 - sun_angle_tan_half2) / sun_angle_tan_half2; + // Equivalent to DdotR < cos(sun_angle) + float factor = step(DdotR, sun_angle_sin_cos.y); + return mix(R, normalize(sun_direction * sun_angle_sin_cos.y + S * sun_angle_sin_cos.x), factor); } diff --git a/lib/graphics_engine/CMakeLists.txt b/lib/graphics_engine/CMakeLists.txt index ad13602c4db..9de9bb6732e 100644 --- a/lib/graphics_engine/CMakeLists.txt +++ b/lib/graphics_engine/CMakeLists.txt @@ -69,6 +69,7 @@ set(GE_SOURCES src/ge_culling_tool.cpp src/ge_dx9_texture.cpp src/ge_main.cpp + src/ge_occlusion_culling.cpp src/ge_texture.cpp src/ge_vma.cpp src/ge_vulkan_2d_renderer.cpp @@ -85,6 +86,7 @@ set(GE_SOURCES src/ge_vulkan_environment_map.cpp src/ge_vulkan_fbo_texture.cpp src/ge_vulkan_features.cpp + src/ge_vulkan_light_handler.cpp src/ge_vulkan_mesh_cache.cpp src/ge_vulkan_mesh_scene_node.cpp src/ge_vulkan_scene_manager.cpp diff --git a/lib/graphics_engine/include/ge_main.hpp b/lib/graphics_engine/include/ge_main.hpp index 8d1540de2ab..82b05e97d0e 100644 --- a/lib/graphics_engine/include/ge_main.hpp +++ b/lib/graphics_engine/include/ge_main.hpp @@ -19,6 +19,7 @@ namespace irr namespace GE { +class GEOcclusionCulling; class GESPMBuffer; class GEVulkanDriver; struct GEConfig @@ -98,6 +99,9 @@ inline irr::video::SColor srgb255ToLinearFromSColor(irr::video::SColor scolor_sr return out; } void copyToMappedBuffer(uint32_t* mapped, GESPMBuffer* spmb, size_t offset = 0); +GEOcclusionCulling* getOcclusionCulling(); +void resetOcclusionCulling(); +bool hasOcclusionCulling(); } #endif diff --git a/lib/graphics_engine/include/ge_occlusion_culling.hpp b/lib/graphics_engine/include/ge_occlusion_culling.hpp new file mode 100644 index 00000000000..364a5ef471b --- /dev/null +++ b/lib/graphics_engine/include/ge_occlusion_culling.hpp @@ -0,0 +1,80 @@ +#ifndef HEADER_GE_OCCLUSION_CULLING_HPP +#define HEADER_GE_OCCLUSION_CULLING_HPP + +#include +#include + +#include + +#include +#include + +class btCollisionShape; +class btCollisionObject; +class btTriangleMesh; + +namespace GE +{ +class GEOcclusionCulling +{ +private: + btTriangleMesh* m_triangle_mesh; + + btCollisionShape* m_occluder_shape; + + btCollisionObject* m_occluder_object; + + // Point generators that yield one point at a time + class PointGenerator + { + public: + virtual ~PointGenerator() {} + virtual bool getNextPoint(btVector3& point) = 0; + }; + + class SpherePointGenerator : public PointGenerator + { + private: + btVector3 m_center; + float m_radius; + int m_num_points; + int m_current_point; + public: + // -------------------------------------------------------------------- + SpherePointGenerator(const btVector3& center, float radius, + int num_points) + { + m_center = center; + m_radius = radius; + m_num_points = num_points; + m_current_point = 0; + } + // -------------------------------------------------------------------- + bool getNextPoint(btVector3& point); + }; + +public: + // ------------------------------------------------------------------------ + GEOcclusionCulling(); + // ------------------------------------------------------------------------ + ~GEOcclusionCulling(); + // ------------------------------------------------------------------------ + void addOccluderMesh(const std::vector >& tris); + // ------------------------------------------------------------------------ + bool isOccluded(const irr::core::vector3df& cam_pos, + const irr::core::aabbox3df& aabbox) + { + // Use sphere test for now, testing the aabbox against the frustum + // should be done first. + float radius = aabbox.getExtent().getLength() / 2.0f; + return isOccluded(cam_pos, aabbox.getCenter(), radius); + } + // ------------------------------------------------------------------------ + bool isOccluded(const irr::core::vector3df& cam_pos, + const irr::core::vector3df& irr_center, float radius); + +}; + +} + +#endif diff --git a/lib/graphics_engine/include/ge_vulkan_driver.hpp b/lib/graphics_engine/include/ge_vulkan_driver.hpp index fe8f64f7dae..39735d87c35 100644 --- a/lib/graphics_engine/include/ge_vulkan_driver.hpp +++ b/lib/graphics_engine/include/ge_vulkan_driver.hpp @@ -198,7 +198,7 @@ namespace GE //! Sets the dynamic ambient light color. The default color is //! (0,0,0,0) which means it is dark. //! \param color: New color of the ambient light. - virtual void setAmbientLight(const SColorf& color) {} + virtual void setAmbientLight(const SColorf& color) { CNullDriver::setAmbientLight(color); } //! Draws a shadow volume into the stencil buffer. virtual void drawStencilShadowVolume(const core::array& triangles, bool zfail=true, u32 debugDataVisible=0) {} diff --git a/lib/graphics_engine/src/ge_culling_tool.cpp b/lib/graphics_engine/src/ge_culling_tool.cpp index cd0bf7276b8..6dede346d13 100644 --- a/lib/graphics_engine/src/ge_culling_tool.cpp +++ b/lib/graphics_engine/src/ge_culling_tool.cpp @@ -15,6 +15,18 @@ void GECullingTool::init(GEVulkanCameraSceneNode* cam) m_cam_bbox = cam->getViewFrustum()->getBoundingBox(); } // init +// ---------------------------------------------------------------------------- +bool GECullingTool::isCulled(const irr::core::vector3df& center, float radius) +{ + for (int i = 0; i < 6; i++) + { + irr::core::quaternion q(center.X, center.Y, center.Z, 1.0f); + if (m_frustum[i].dotProduct(q) < -radius) + return true; + } + return false; +} // isCulled + // ---------------------------------------------------------------------------- bool GECullingTool::isCulled(irr::core::aabbox3df& bb) { diff --git a/lib/graphics_engine/src/ge_culling_tool.hpp b/lib/graphics_engine/src/ge_culling_tool.hpp index f056dd25df1..a25f08c165c 100644 --- a/lib/graphics_engine/src/ge_culling_tool.hpp +++ b/lib/graphics_engine/src/ge_culling_tool.hpp @@ -27,6 +27,8 @@ class GECullingTool // ------------------------------------------------------------------------ bool isCulled(irr::core::aabbox3df& bb); // ------------------------------------------------------------------------ + bool isCulled(const irr::core::vector3df& center, float radius); + // ------------------------------------------------------------------------ bool isCulled(GESPMBuffer* buffer, irr::scene::ISceneNode* node); }; // GECullingTool diff --git a/lib/graphics_engine/src/ge_main.cpp b/lib/graphics_engine/src/ge_main.cpp index fd767aa69b6..77711591c1d 100644 --- a/lib/graphics_engine/src/ge_main.cpp +++ b/lib/graphics_engine/src/ge_main.cpp @@ -1,4 +1,5 @@ #include "ge_main.hpp" +#include "ge_occlusion_culling.hpp" #include "ge_spm.hpp" #include "ge_spm_buffer.hpp" #include "ge_vulkan_driver.hpp" @@ -10,6 +11,7 @@ #include #include +#include namespace GE { @@ -29,6 +31,7 @@ GEConfig g_config = std::string g_shader_folder = ""; std::chrono::steady_clock::time_point g_mono_start = std::chrono::steady_clock::now(); +std::unique_ptr g_occulsion_culling; void setVideoDriver(irr::video::IVideoDriver* driver) { @@ -191,4 +194,26 @@ void copyToMappedBuffer(uint32_t* mapped, GESPMBuffer* spmb, size_t offset) } } +GEOcclusionCulling* getOcclusionCulling() +{ + if (!g_occulsion_culling) + { + g_occulsion_culling = std::unique_ptr( + new GEOcclusionCulling()); + } + return g_occulsion_culling.get(); +} + +void resetOcclusionCulling() +{ + g_occulsion_culling.reset(); +} + +bool hasOcclusionCulling() +{ + if (g_occulsion_culling) + return true; + return false; +} + } diff --git a/lib/graphics_engine/src/ge_occlusion_culling.cpp b/lib/graphics_engine/src/ge_occlusion_culling.cpp new file mode 100644 index 00000000000..0e6dacfc3a3 --- /dev/null +++ b/lib/graphics_engine/src/ge_occlusion_culling.cpp @@ -0,0 +1,129 @@ +#include "ge_occlusion_culling.hpp" + +#include +#include +#include +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +namespace GE +{ +// ============================================================================ +bool GEOcclusionCulling::SpherePointGenerator::getNextPoint(btVector3& point) +{ + if (m_current_point >= m_num_points) + return false; + + if (m_current_point == 0) + { + point = m_center; + m_current_point++; + return true; + } + + float golden_ratio = (1.0f + sqrtf(5.0f)) / 2.0f; + float angle_increment = 2.0f * M_PI * golden_ratio; + + float t = float(m_current_point) / float(m_num_points); + float inclination = acos(1.0f - 2.0f * t); + float azimuth = angle_increment * float(m_current_point); + + float x = sin(inclination) * cos(azimuth); + float y = sin(inclination) * sin(azimuth); + float z = cos(inclination); + + // Test points at 80% of the sphere's surface + float offset = 0.8f; + point = m_center + btVector3(x, y, z) * m_radius * offset; + m_current_point++; + return true; +} // GEOcclusionCulling::SpherePointGenerator::getNextPoint + +// ---------------------------------------------------------------------------- +GEOcclusionCulling::GEOcclusionCulling() +{ + m_triangle_mesh = NULL; + m_occluder_shape = NULL; + m_occluder_object = NULL; +} // GEOcclusionCulling + +// ---------------------------------------------------------------------------- +GEOcclusionCulling::~GEOcclusionCulling() +{ + delete m_occluder_object; + delete m_occluder_shape; + delete m_triangle_mesh; +} // ~GEOcclusionCulling + +// ---------------------------------------------------------------------------- +void GEOcclusionCulling::addOccluderMesh( + const std::vector >& tris) +{ + assert(m_triangle_mesh == NULL); + m_triangle_mesh = new btTriangleMesh(); + for (auto& t : tris) + m_triangle_mesh->addTriangle(t[0], t[1], t[2]); + m_occluder_shape = new btBvhTriangleMeshShape(m_triangle_mesh, + false/*useQuantizedAabbCompression*/); + m_occluder_object = new btCollisionObject(); + m_occluder_object->setCollisionShape(m_occluder_shape); +} // addOccluderMesh + +// ---------------------------------------------------------------------------- +bool GEOcclusionCulling::isOccluded(const irr::core::vector3df& cam_pos, + const irr::core::vector3df& irr_center, + float radius) +{ + if (!m_triangle_mesh) + return false; + float radius_2 = radius * radius; + float distance_2 = (cam_pos - irr_center).getLengthSQ(); + // Inside the sphere + if (distance_2 <= radius_2) + return false; + + // Calculate points using logarithmic scaling + float distance = sqrtf(distance_2); + // Formula: MAX_POINTS - log2(distance/MIN_DISTANCE) * SCALE_FACTOR + // Clamp between MIN_POINTS and MAX_POINTS + const float MIN_DISTANCE = 80.0f; // Distance at which maximum points are used + const int MAX_POINTS = 12; + const int MIN_POINTS = 3; + const float SCALE_FACTOR = 4.0f; // Controls how quickly the point count decreases + + int num_points = MAX_POINTS - + int(std::log2(std::max(distance / MIN_DISTANCE, 1.0f)) * SCALE_FACTOR); + num_points = std::min(MAX_POINTS, std::max(MIN_POINTS, num_points)); + + btVector3 center = btVector3(irr_center.X, irr_center.Y, irr_center.Z); + PointGenerator* generator = new SpherePointGenerator(center, radius, num_points); + + btVector3 test_point; + btVector3 cam_p(cam_pos.X, cam_pos.Y, cam_pos.Z); + bool culled = true; + while (generator->getNextPoint(test_point)) + { + btCollisionWorld::ClosestRayResultCallback cb(cam_p, test_point); + cb.m_flags |= btTriangleRaycastCallback::kF_FilterBackfaces; + btTransform from_trans, to_trans; + from_trans.setIdentity(); + from_trans.setOrigin(cam_p); + to_trans.setIdentity(); + to_trans.setOrigin(test_point); + btCollisionWorld::rayTestSingle(from_trans, to_trans, + m_occluder_object, m_occluder_shape, + m_occluder_object->getWorldTransform(), cb); + if (!cb.hasHit() || + (cb.m_hitPointWorld - test_point).length2() <= radius_2 || // Hit point inside the sphere + (cb.m_hitPointWorld - cam_p).length2() > (test_point - cam_p).length2()) // Hit point behind the sphere + { + culled = false; + break; + } + } + delete generator; + return culled; +} // isOccluded + +} diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index 7f511064b0d..dd9bf968c87 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -13,6 +13,7 @@ #include "ge_vulkan_environment_map.hpp" #include "ge_vulkan_fbo_texture.hpp" #include "ge_vulkan_features.hpp" +#include "ge_vulkan_light_handler.hpp" #include "ge_vulkan_mesh_cache.hpp" #include "ge_vulkan_mesh_scene_node.hpp" #include "ge_vulkan_shader_manager.hpp" @@ -21,6 +22,7 @@ #include "mini_glm.hpp" #include "IBillboardSceneNode.h" +#include "ILightSceneNode.h" #include "IParticleSystemSceneNode.h" #include @@ -203,6 +205,7 @@ GEVulkanDrawCall::GEVulkanDrawCall() : m_limits(getVKDriver()->getPhysicalDeviceProperties().limits) { m_culling_tool = new GECullingTool; + m_light_handler = NULL; m_dynamic_data = NULL; m_sbo_data = NULL; m_object_data_padded_size = 0; @@ -222,6 +225,7 @@ GEVulkanDrawCall::GEVulkanDrawCall() GEVulkanDrawCall::~GEVulkanDrawCall() { delete m_culling_tool; + delete m_light_handler; delete m_dynamic_data; delete m_sbo_data; for (auto& p : m_billboard_buffers) @@ -320,6 +324,9 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) if (!m_visible_nodes.empty() && m_data_layout == VK_NULL_HANDLE) createVulkanData(); + if (m_light_handler) + m_light_handler->generate(m_view_position, m_skybox_renderer); + using Nodes = std::pair, std::unordered_map< std::string, std::vector > > >; @@ -841,8 +848,12 @@ std::string GEVulkanDrawCall::getShader(const irr::video::SMaterial& m) void GEVulkanDrawCall::prepare(GEVulkanCameraSceneNode* cam) { reset(); + if (getGEConfig()->m_pbr && m_light_handler == NULL) + m_light_handler = new GEVulkanLightHandler(getVKDriver()); + if (m_light_handler) + m_light_handler->prepare(); m_culling_tool->init(cam); - m_view_position = cam->getPosition(); + m_view_position = cam->getAbsolutePosition(); m_billboard_rotation = MiniGLM::getBulletQuaternion(cam->getViewMatrix()); } // prepare @@ -1272,16 +1283,26 @@ void GEVulkanDrawCall::createVulkanData() skinning_layout_binding.pImmutableSamplers = NULL; skinning_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + VkDescriptorSetLayoutBinding light_layout_binding = {}; + light_layout_binding.binding = 3; + light_layout_binding.descriptorCount = 1; + light_layout_binding.descriptorType = + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + light_layout_binding.pImmutableSamplers = NULL; + light_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | + VK_SHADER_STAGE_FRAGMENT_BIT; + std::vector bindings = { camera_layout_binding, object_data_layout_binding, - skinning_layout_binding + skinning_layout_binding, + light_layout_binding }; if (GEVulkanFeatures::supportsBindMeshTexturesAtOnce()) { VkDescriptorSetLayoutBinding material_binding = {}; - material_binding.binding = 3; + material_binding.binding = 4; material_binding.descriptorCount = 1; material_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; @@ -1310,7 +1331,7 @@ void GEVulkanDrawCall::createVulkanData() { { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - vk->getMaxFrameInFlight() + 1 + (vk->getMaxFrameInFlight() + 1) * 2 }, { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, @@ -1318,7 +1339,7 @@ void GEVulkanDrawCall::createVulkanData() } }; if (GEVulkanFeatures::supportsBindMeshTexturesAtOnce()) - sizes.push_back(sizes.back()); + sizes.back().descriptorCount = (vk->getMaxFrameInFlight() + 1) * 3; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; @@ -1419,7 +1440,7 @@ void GEVulkanDrawCall::createVulkanData() // Use VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT // or a staging buffer when buffer is small m_dynamic_data = new GEVulkanDynamicBuffer(flags, - extra_size + sizeof(GEVulkanCameraUBO), + extra_size + sizeof(GEVulkanCameraUBO) + sizeof(GEGlobalLightBuffer), GEVulkanDriver::getMaxFrameInFlight() + 1, GEVulkanDynamicBuffer::supportsHostTransfer() ? 0 : GEVulkanDriver::getMaxFrameInFlight() + 1); @@ -1452,6 +1473,15 @@ void GEVulkanDrawCall::uploadDynamicData(GEVulkanDriver* vk, data_uploading.emplace_back((void*)cam->getUBOData(), sizeof(GEVulkanCameraUBO)); + size_t sbo_padding = getLightDataOffset() - sizeof(GEVulkanCameraUBO); + if (sbo_padding > 0) + data_uploading.emplace_back((void*)NULL, sbo_padding); + if (m_light_handler) + { + data_uploading.emplace_back(m_light_handler->getData(), + m_light_handler->getSize()); + } + const bool use_multidraw = GEVulkanFeatures::supportsBindMeshTexturesAtOnce(); if (use_multidraw) @@ -1567,6 +1597,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, 0u, 0u, 0u, + 0u, }; if (getGEConfig()->m_pbr) { @@ -1583,7 +1614,9 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, m_texture_descriptor->getDescriptorSet(), 0, NULL); bound_mesh_textures_once = true; } - size_t indirect_offset = sizeof(GEVulkanCameraUBO); + size_t indirect_offset = getLightDataOffset(); + if (m_light_handler) + indirect_offset += m_light_handler->getSize(); const size_t indirect_size = sizeof(VkDrawIndexedIndirectCommand); unsigned draw_count = 0; VkBuffer indirect_buffer = @@ -1623,7 +1656,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, if (bound) { dynamic_offsets[1] = m_dynamic_spm_padded_size; - dynamic_offsets[3] = m_materials_data[cur_pipeline].first; + dynamic_offsets[4] = m_materials_data[cur_pipeline].first; bindDataDescriptor(cmd, current_buffer_idx, dynamic_offsets); vkCmdDrawIndexedIndirect(cmd, indirect_buffer, @@ -1678,7 +1711,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, if (bound) { dynamic_offsets[1] = m_dynamic_spm_padded_size; - dynamic_offsets[3] = m_materials_data[m_cmds.back().m_shader].first; + dynamic_offsets[4] = m_materials_data[m_cmds.back().m_shader].first; bindDataDescriptor(cmd, current_buffer_idx, dynamic_offsets); vkCmdDrawIndexedIndirect(cmd, indirect_buffer, indirect_offset, draw_count, indirect_size); @@ -1686,7 +1719,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, } else { - dynamic_offsets.resize(3); + dynamic_offsets.resize(4); bool rebind_base_vertex = true; bound = bindPipeline(cmd, cur_pipeline, depth_only, &prev_dp); auto it = dynamic_spm_buffers.find( @@ -1946,6 +1979,26 @@ void GEVulkanDrawCall::updateDataDescriptorSets(GEVulkanDriver* vk) data_set[2].descriptorCount = 1; data_set[2].pBufferInfo = &sbo_info_skinning; + VkDescriptorBufferInfo sbo_info_light; + if (m_light_handler != NULL) + { + sbo_info_light.buffer = + GEVulkanDynamicBuffer::supportsHostTransfer() ? + m_dynamic_data->getHostBuffer()[i] : + m_dynamic_data->getLocalBuffer()[i]; + sbo_info_light.offset = getLightDataOffset(); + sbo_info_light.range = sizeof(GEGlobalLightBuffer); + data_set.push_back({}); + VkWriteDescriptorSet& ds = data_set.back(); + ds.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + ds.dstSet = m_data_descriptor_sets[i]; + ds.dstBinding = 3; + ds.dstArrayElement = 0; + ds.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + ds.descriptorCount = 1; + ds.pBufferInfo = &sbo_info_light; + } + VkDescriptorBufferInfo sbo_info_material; sbo_info_material.buffer = m_sbo_data->getHostBuffer()[i]; @@ -1954,15 +2007,15 @@ void GEVulkanDrawCall::updateDataDescriptorSets(GEVulkanDriver* vk) sbo_info_material.range = m_materials_padded_size; if (bind_mesh_textures) { - data_set.resize(4, {}); - data_set[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - data_set[3].dstSet = m_data_descriptor_sets[i]; - data_set[3].dstBinding = 3; - data_set[3].dstArrayElement = 0; - data_set[3].descriptorType = - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; - data_set[3].descriptorCount = 1; - data_set[3].pBufferInfo = &sbo_info_material; + data_set.push_back({}); + VkWriteDescriptorSet& ds = data_set.back(); + ds.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + ds.dstSet = m_data_descriptor_sets[i]; + ds.dstBinding = 4; + ds.dstArrayElement = 0; + ds.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; + ds.descriptorCount = 1; + ds.pBufferInfo = &sbo_info_material; } vkUpdateDescriptorSets(vk->getDevice(), data_set.size(), @@ -2109,4 +2162,31 @@ VertexDescription GEVulkanDrawCall::getDefaultVertexDescription() const return vertex_description; } // getDefaultVertexDescription +// ---------------------------------------------------------------------------- +void GEVulkanDrawCall::addLightNode(irr::scene::ILightSceneNode* node) +{ + if (!m_light_handler) + return; + if (node->getLightType() == irr::video::ELT_DIRECTIONAL) + { + // Sun node + m_light_handler->addLightNode(node); + } + else + { + const video::SLight& l = node->getLightData(); + if (m_culling_tool->isCulled(l.Position, l.Radius)) + return; + m_light_handler->addLightNode(node); + } +} // addLightNode + +// ---------------------------------------------------------------------------- +size_t GEVulkanDrawCall::getLightDataOffset() const +{ + size_t ubo_size = sizeof(GEVulkanCameraUBO); + return ubo_size + + getPadding(ubo_size, m_limits.minUniformBufferOffsetAlignment); +} // getLightDataOffset + } diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp index 3dfccca7fde..9f421eb6dd1 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp @@ -25,7 +25,7 @@ namespace irr namespace scene { class ISceneNode; class IBillboardSceneNode; struct SParticle; - class IMesh; + class IMesh; class ILightSceneNode; } } @@ -38,6 +38,7 @@ class GEVulkanCameraSceneNode; class GEVulkanDriver; class GEVulkanDynamicBuffer; class GEVulkanDynamicSPMBuffer; +class GEVulkanLightHandler; class GEVulkanSkyBoxRenderer; class GEVulkanTextureDescriptor; @@ -138,6 +139,8 @@ class GEVulkanDrawCall GECullingTool* m_culling_tool; + GEVulkanLightHandler* m_light_handler; + std::vector m_cmds; std::vector m_visible_objects; @@ -280,6 +283,8 @@ class GEVulkanDrawCall bool doDepthOnlyRenderingFirst(); // ------------------------------------------------------------------------ VertexDescription getDefaultVertexDescription() const; + // ------------------------------------------------------------------------ + size_t getLightDataOffset() const; public: // ------------------------------------------------------------------------ GEVulkanDrawCall(); @@ -323,6 +328,8 @@ class GEVulkanDrawCall } // ------------------------------------------------------------------------ void addSkyBox(irr::scene::ISceneNode* node); + // ------------------------------------------------------------------------ + void addLightNode(irr::scene::ILightSceneNode* node); }; // GEVulkanDrawCall } diff --git a/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp b/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp index 9d8cb076c04..5dd6f56cf91 100644 --- a/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp +++ b/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp @@ -165,7 +165,8 @@ bool GEVulkanDynamicBuffer::setCurrentData(const std::vector< uint8_t* addr = (uint8_t*)m_mapped_addr[cur_frame]; for (auto& p : data) { - memcpy(addr, p.first, p.second); + if (p.first != NULL) + memcpy(addr, p.first, p.second); addr += p.second; } vmaFlushAllocation(vk->getVmaAllocator(), m_host_memory[cur_frame], 0, diff --git a/lib/graphics_engine/src/ge_vulkan_light_handler.cpp b/lib/graphics_engine/src/ge_vulkan_light_handler.cpp new file mode 100644 index 00000000000..eeb0659003b --- /dev/null +++ b/lib/graphics_engine/src/ge_vulkan_light_handler.cpp @@ -0,0 +1,126 @@ +#include "ge_vulkan_light_handler.hpp" + +#include "ge_main.hpp" +#include "ge_occlusion_culling.hpp" +#include "ge_vulkan_driver.hpp" +#include "ge_vulkan_skybox_renderer.hpp" + +#include "ILightSceneNode.h" +#include "ISceneManager.h" +#include "IrrlichtDevice.h" + +#include +#include +#include + +namespace GE +{ +using namespace irr; +// ---------------------------------------------------------------------------- +void GEVulkanLightHandler::prepare() +{ + m_buffer = {}; + m_lights.clear(); + video::SColorf c = m_vk->getIrrlichtDevice()->getSceneManager() + ->getAmbientLight(); + m_buffer.m_ambient_color.X = c.r * c.a; + m_buffer.m_ambient_color.Y = c.g * c.a; + m_buffer.m_ambient_color.Z = c.b * c.a; + m_buffer.m_sun_scatter = 0.2f; + m_buffer.m_sun_color = core::vector3df(0.75f, 0.75f, 0.75f); + m_buffer.m_sun_angle_tan_half = 0.0022f; + m_buffer.m_sun_direction = core::vector3df(0.15f, 0.2f, 1.0f).normalize(); + m_buffer.m_skytop_color.X = 0.325f; + m_buffer.m_skytop_color.Y = 0.35f; + m_buffer.m_skytop_color.Z = 0.375f; +} // prepare + +// ---------------------------------------------------------------------------- +void GEVulkanLightHandler::generate(const irr::core::vector3df& cam_pos, + GEVulkanSkyBoxRenderer* skybox) +{ + if (skybox) + { + irr::video::SColorf c( + srgb255ToLinearFromSColor(skybox->getSkytopColor())); + m_buffer.m_skytop_color.X = c.r; + m_buffer.m_skytop_color.Y = c.g; + m_buffer.m_skytop_color.Z = c.b; + } + if (m_lights.size() > MAX_RENDERING_LIGHT) + { + std::sort(m_lights.begin(), m_lights.end(), + [cam_pos](GELight& a, GELight& b) + { + float al = a.m_position.getDistanceFromSQ(cam_pos); + float bl = b.m_position.getDistanceFromSQ(cam_pos); + return al < bl; + }); + m_lights.resize(MAX_RENDERING_LIGHT); + } + if (m_lights.empty()) + return; + + if (hasOcclusionCulling()) + { + auto l = m_lights.begin(); + auto rl = m_buffer.m_rendering_lights.begin(); + while (l != m_lights.end()) + { + if (getOcclusionCulling()->isOccluded(cam_pos, l->m_position, + l->m_radius)) + { + l++; + continue; + } + *rl = *l; + l++; + rl++; + } + m_buffer.m_light_count = rl - m_buffer.m_rendering_lights.begin(); + } + else + { + std::copy(m_lights.begin(), m_lights.end(), + m_buffer.m_rendering_lights.begin()); + m_buffer.m_light_count = m_lights.size(); + } +} // generate + +// ---------------------------------------------------------------------------- +void GEVulkanLightHandler::addLightNode(irr::scene::ILightSceneNode* node) +{ + const video::SLight& l = node->getLightData(); + if (node->getLightType() == irr::video::ELT_DIRECTIONAL) + { + m_buffer.m_sun_color.X = l.DiffuseColor.r; + m_buffer.m_sun_color.Y = l.DiffuseColor.g; + m_buffer.m_sun_color.Z = l.DiffuseColor.b; + m_buffer.m_sun_scatter = l.DiffuseColor.a; + core::vector3df dir = l.Direction; + m_buffer.m_sun_direction = -dir.normalize(); + m_buffer.m_sun_angle_tan_half = tanf(l.Radius * 0.5f); + } + else + { + GELight gl = {}; + gl.m_position = l.Position; + gl.m_radius = l.Radius; + gl.m_color.X = l.DiffuseColor.r * l.Attenuation.X; + gl.m_color.Y = l.DiffuseColor.g * l.Attenuation.X; + gl.m_color.Z = l.DiffuseColor.b * l.Attenuation.X; + gl.m_inverse_range_squared = l.Attenuation.Y * l.Attenuation.Y; + if (l.Type == irr::video::ELT_SPOT) + { + gl.m_direction.X = l.Direction.X; + gl.m_direction.Y = l.Direction.Y; + float cos_outer = cosf(l.OuterCone); + gl.m_scale = 1.0f / std::max(cosf(l.InnerCone) - cos_outer, 1e-4f); + gl.m_offset = -cos_outer * gl.m_scale; + gl.m_scale *= l.Direction.Z > 0.f ? 1.f : -1.f; + } + m_lights.push_back(gl); + } +} // addLightNode + +} diff --git a/lib/graphics_engine/src/ge_vulkan_light_handler.hpp b/lib/graphics_engine/src/ge_vulkan_light_handler.hpp new file mode 100644 index 00000000000..c16bdbc26d4 --- /dev/null +++ b/lib/graphics_engine/src/ge_vulkan_light_handler.hpp @@ -0,0 +1,85 @@ +#ifndef HEADER_GE_VULKAN_LIGHT_HANDLER_HPP +#define HEADER_GE_VULKAN_LIGHT_HANDLER_HPP + +#include "vector2d.h" +#include "vector3d.h" +#include "SColor.h" + +#include +#include + +namespace irr +{ + namespace scene + { + class ILightSceneNode; + } +} + +namespace GE +{ +class GEVulkanDriver; +class GEVulkanSkyBoxRenderer; +const irr::u32 MAX_RENDERING_LIGHT = 32; +struct GELight +{ + irr::core::vector3df m_position; + irr::f32 m_radius; + irr::core::vector3df m_color; + irr::f32 m_inverse_range_squared; + irr::core::vector2df m_direction; + irr::f32 m_scale; + irr::f32 m_offset; +}; + +struct GEGlobalLightBuffer +{ + irr::core::vector3df m_ambient_color; + irr::f32 m_sun_scatter; + irr::core::vector3df m_sun_color; + irr::f32 m_sun_angle_tan_half; + irr::core::vector3df m_sun_direction; + irr::f32 m_fog_density; + irr::video::SColorf m_fog_color; + irr::core::vector3df m_skytop_color; + irr::u32 m_light_count; + std::array m_rendering_lights; +}; + +class GEVulkanLightHandler +{ +private: + GEVulkanDriver* m_vk; + + GEGlobalLightBuffer m_buffer; + + std::vector m_lights; +public: + // ------------------------------------------------------------------------ + GEVulkanLightHandler(GEVulkanDriver* vk) + { + m_vk = vk; + prepare(); + } + // ------------------------------------------------------------------------ + ~GEVulkanLightHandler() {} + // ------------------------------------------------------------------------ + void prepare(); + // ------------------------------------------------------------------------ + void generate(const irr::core::vector3df& cam_pos, + GEVulkanSkyBoxRenderer* skybox); + // ------------------------------------------------------------------------ + void addLightNode(irr::scene::ILightSceneNode* node); + // ------------------------------------------------------------------------ + void* getData() { return &m_buffer; } + // ------------------------------------------------------------------------ + size_t getSize() const + { + return sizeof(GEGlobalLightBuffer) - + (sizeof(GELight) * (MAX_RENDERING_LIGHT - m_buffer.m_light_count)); + } +}; // GEVulkanLightHandler + +} + +#endif diff --git a/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp b/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp index 72b7bb55822..b0f14b081eb 100644 --- a/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp +++ b/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp @@ -15,6 +15,7 @@ #include "ge_vulkan_texture_descriptor.hpp" #include "IBillboardSceneNode.h" +#include "ILightSceneNode.h" #include namespace GE @@ -238,6 +239,13 @@ irr::u32 GEVulkanSceneManager::registerNodeForRendering( return 1; } + if (node->getType() == irr::scene::ESNT_LIGHT) + { + m_draw_calls.at(cam)->addLightNode( + static_cast(node)); + return 1; + } + if (node->getType() == irr::scene::ESNT_BILLBOARD || node->getType() == irr::scene::ESNT_PARTICLE_SYSTEM) { diff --git a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp index 7b03c049688..e1dd4831b7d 100644 --- a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp +++ b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.cpp @@ -21,7 +21,8 @@ GEVulkanSkyBoxRenderer::GEVulkanSkyBoxRenderer() m_descriptor_layout(VK_NULL_HANDLE), m_env_descriptor_layout(VK_NULL_HANDLE), m_descriptor_pool(VK_NULL_HANDLE), - m_skybox_loading(false), m_env_cubemap_loading(false) + m_skybox_loading(false), m_env_cubemap_loading(false), + m_skytop_color(0) { m_dummy_env_cubemap = new GEVulkanArrayTexture(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_VIEW_TYPE_CUBE, core::dimension2du(4, 4), 6, @@ -230,6 +231,14 @@ void GEVulkanSkyBoxRenderer::addSkyBox(irr::scene::ISceneNode* skybox) { if (!(idx == 2 || idx == 3)) return; + if (idx == 2) + { + video::IImage* pixel = getDriver()->createImage( + video::ECF_A8R8G8B8, core::dimension2du(1, 1)); + img->copyToScaling(pixel); + m_sky->m_skytop_color.store(*(uint32_t*)pixel->lock()); + pixel->drop(); + } unsigned width = img->getDimension().Width; uint8_t* tmp = new uint8_t[width * width * 4]; uint32_t* tmp_array = (uint32_t*)tmp; diff --git a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp index 9d44a06e471..56176c33e2f 100644 --- a/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp +++ b/lib/graphics_engine/src/ge_vulkan_skybox_renderer.hpp @@ -2,6 +2,7 @@ #define HEADER_GE_VULKAN_SKYBOX_RENDERER_HPP #include "vulkan_wrapper.h" +#include #include #include @@ -33,6 +34,8 @@ class GEVulkanSkyBoxRenderer std::array m_env_descriptor_set; std::atomic_bool m_skybox_loading, m_env_cubemap_loading; + + std::atomic m_skytop_color; public: // ------------------------------------------------------------------------ GEVulkanSkyBoxRenderer(); @@ -62,6 +65,15 @@ class GEVulkanSkyBoxRenderer while (m_env_cubemap_loading.load()); m_skybox = NULL; } + // ------------------------------------------------------------------------ + irr::video::SColor getSkytopColor() const + { + irr::video::SColor c(0); + if (m_skybox_loading.load() == true) + return c; + c.color = m_skytop_color.load(); + return c; + } }; // GEVulkanSkyBoxRenderer diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 470e296a3cb..d57a9f8e191 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -2385,9 +2385,9 @@ scene::ISceneNode *IrrDriver::addLight(const core::vector3df &pos, bool sun_, scene::ISceneNode* parent) { #ifndef SERVER_ONLY + if (parent == NULL) parent = m_scene_manager->getRootSceneNode(); if (CVS->isGLSL()) { - if (parent == NULL) parent = m_scene_manager->getRootSceneNode(); LightNode *light = NULL; if (!sun_) @@ -2409,10 +2409,25 @@ scene::ISceneNode *IrrDriver::addLight(const core::vector3df &pos, } else { - scene::ILightSceneNode* light = m_scene_manager - ->addLightSceneNode(m_scene_manager->getRootSceneNode(), - pos, video::SColorf(r, g, b, 1.0f)); - light->setRadius(radius); + scene::ILightSceneNode* light; + if (m_video_driver->getDriverType() == EDT_VULKAN && sun_) + { + light = m_scene_manager->addLightSceneNode(parent, pos, + video::SColorf(r, g, b, 0.2f), 0.26f * M_PI / 180.0f); + light->setRotation(-pos); + light->setLightType(video::ELT_DIRECTIONAL); + } + else + { + video::SColorf color(r, g, b, 1.0f); + light = m_scene_manager->addLightSceneNode(parent, pos, color); + light->setRadius(radius); + if (m_video_driver->getDriverType() == EDT_VULKAN) + { + video::SLight& data = light->getLightData(); + data.Attenuation.X = energy; + } + } return light; } #else diff --git a/src/graphics/referee.cpp b/src/graphics/referee.cpp index 328e83ae3b6..110b5bdd505 100644 --- a/src/graphics/referee.cpp +++ b/src/graphics/referee.cpp @@ -34,7 +34,9 @@ #include "utils/string_utils.hpp" #include +#include #include +#include int Referee::m_st_first_start_frame = 1; int Referee::m_st_last_start_frame = 1; @@ -169,7 +171,8 @@ Referee::Referee() m_scene_node->setFrameLoop(m_st_first_start_frame, m_st_last_start_frame); #ifndef SERVER_ONLY - if (CVS->isGLSL() && CVS->isDeferredEnabled()) + if ((CVS->isGLSL() && CVS->isDeferredEnabled()) || + irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN) { m_light = irr_driver->addLight(core::vector3df(0.0f, 0.0f, 0.6f), 0.7f, 2.0f, 0.7f /* r */, 0.0 /* g */, 0.0f /* b */, false /* sun */, m_scene_node); @@ -268,19 +271,39 @@ void Referee::selectReadySetGo(int rsg) m.SpecularColor = video::SColor(255, 255, 255, 255); } - if (m_light != NULL) + LightNode* lnode = dynamic_cast(m_light); + if (lnode != NULL) + { + if (rsg == 0) + { + lnode->setColor(0.6f, 0.0f, 0.0f); + } + else if (rsg == 1) + { + lnode->setColor(0.7f, 0.23f, 0.0f); + } + else if (rsg == 2) + { + lnode->setColor(0.0f, 0.6f, 0.0f); + } + return; + } + scene::ILightSceneNode* irr_node = dynamic_cast( + m_light); + if (irr_node != NULL) { + video::SLight& data = irr_node->getLightData(); if (rsg == 0) { - ((LightNode*)m_light)->setColor(0.6f, 0.0f, 0.0f); + data.DiffuseColor = video::SColorf(0.6f, 0.0f, 0.0f); } else if (rsg == 1) { - ((LightNode*)m_light)->setColor(0.7f, 0.23f, 0.0f); + data.DiffuseColor = video::SColorf(0.7f, 0.23f, 0.0f); } else if (rsg == 2) { - ((LightNode*)m_light)->setColor(0.0f, 0.6f, 0.0f); + data.DiffuseColor = video::SColorf(0.0f, 0.6f, 0.0f); } } } // selectReadySetGo diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index e5b70d35952..1bc8e2c28d3 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -102,6 +102,7 @@ #ifndef SERVER_ONLY #include +#include #include #endif @@ -332,6 +333,8 @@ void Track::cleanup() Graph::destroy(); m_item_manager = nullptr; #ifndef SERVER_ONLY + if (!GUIEngine::isNoGraphics()) + GE::resetOcclusionCulling(); if (CVS->isGLSL()) { if (!GUIEngine::isNoGraphics()) @@ -939,8 +942,10 @@ void Track::createPhysicsModel(unsigned int main_track_count, /** Convert the graphics track into its physics equivalents. * \param mesh The mesh to convert. * \param node The scene node. + * \param occluder Optional destination for storing occluder triangles */ -void Track::convertTrackToBullet(scene::ISceneNode *node) +void Track::convertTrackToBullet(scene::ISceneNode *node, + std::vector >* occluder) { if (node->getType() == scene::ESNT_TEXT) return; @@ -1039,7 +1044,12 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) vertices[k] = v; normals[k] = MiniGLM::decompressVector3(mbVertices[indx].m_normal); } // for k - if (tmesh) + if (occluder) + { + if (!material->isTransparent() && !material->isIgnore()) + occluder->push_back({vertices[0], vertices[1], vertices[2]}); + } + else if (tmesh) { tmesh->addTriangle(vertices[0], vertices[1], vertices[2], normals[0], @@ -1098,7 +1108,12 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) normals[k] = mbVertices[indx].Normal; } // for k - if (tmesh) + if (occluder) + { + if (!material->isTransparent() && !material->isIgnore()) + occluder->push_back({vertices[0], vertices[1], vertices[2]}); + } + else if (tmesh) { tmesh->addTriangle(vertices[0], vertices[1], vertices[2], normals[0], @@ -1124,7 +1139,12 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) normals[k] = mbVertices[indx].Normal; } // for k - if (tmesh) + if (occluder) + { + if (!material->isTransparent() && !material->isIgnore()) + occluder->push_back({vertices[0], vertices[1], vertices[2]}); + } + else if (tmesh) { tmesh->addTriangle(vertices[0], vertices[1], vertices[2], normals[0], @@ -1150,7 +1170,12 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) normals[k] = mbVertices[indx].Normal; } // for k - if (tmesh) + if (occluder) + { + if (!material->isTransparent() && !material->isIgnore()) + occluder->push_back({vertices[0], vertices[1], vertices[2]}); + } + else if (tmesh) { tmesh->addTriangle(vertices[0], vertices[1], vertices[2], normals[0], @@ -1176,7 +1201,12 @@ void Track::convertTrackToBullet(scene::ISceneNode *node) normals[k] = MiniGLM::decompressVector3(mbVertices[indx].m_normal); } // for k - if (tmesh) + if (occluder) + { + if (!material->isTransparent() && !material->isIgnore()) + occluder->push_back({vertices[0], vertices[1], vertices[2]}); + } + else if (tmesh) { tmesh->addTriangle(vertices[0], vertices[1], vertices[2], normals[0], @@ -1320,6 +1350,15 @@ bool Track::loadMainTrack(const XMLNode &root) scene_node->setPosition(xyz); scene_node->setRotation(hpr); handleAnimatedTextures(scene_node, *track_node); +#ifndef SERVER_ONLY + if (!GUIEngine::isNoGraphics() && + GE::getDriver()->getDriverType() == video::EDT_VULKAN) + { + std::vector > tris; + convertTrackToBullet(scene_node, &tris); + GE::getOcclusionCulling()->addOccluderMesh(tris); + } +#endif m_all_nodes.push_back(scene_node); MeshTools::minMax3D(tangent_mesh, &m_aabb_min, &m_aabb_max); @@ -1886,6 +1925,8 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) main_loop->renderGUI(3100); #ifndef SERVER_ONLY + if (!GUIEngine::isNoGraphics()) + GE::resetOcclusionCulling(); if (CVS->isGLSL()) { SP::SPShaderManager::get()->loadSPShaders(m_root); diff --git a/src/tracks/track.hpp b/src/tracks/track.hpp index a417dd9af48..a55b2198af7 100644 --- a/src/tracks/track.hpp +++ b/src/tracks/track.hpp @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -742,7 +743,8 @@ class Track // ------------------------------------------------------------------------ bool isAddon() const { return m_is_addon; } // ------------------------------------------------------------------------ - void convertTrackToBullet(scene::ISceneNode *node); + void convertTrackToBullet(scene::ISceneNode *node, + std::vector >* occluder = NULL); // ------------------------------------------------------------------------ CheckManager* getCheckManager() const { return m_check_manager; } // ------------------------------------------------------------------------ diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index 7d77b33ab8c..96ca28b001f 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -58,6 +58,7 @@ #include #include #include +#include // ---------------------------------------------------------------------------- TrackObjectPresentation::TrackObjectPresentation(const XMLNode& xml_node) @@ -1028,7 +1029,8 @@ TrackObjectPresentationLight::TrackObjectPresentationLight( m_distance = 20.f * m_energy; xml_node.get("distance", &m_distance); #ifndef SERVER_ONLY - if (CVS->isGLSL()) + if (CVS->isGLSL() || + irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN) { m_node = irr_driver->addLight(m_init_xyz, m_energy, m_distance, colorf.r, colorf.g, colorf.b, false, @@ -1053,6 +1055,14 @@ void TrackObjectPresentationLight::setEnergy(float energy) if (lnode != NULL) { lnode->setEnergy(energy); + return; + } + scene::ILightSceneNode* irr_node = dynamic_cast( + m_node); + if (irr_node != NULL) + { + video::SLight& data = irr_node->getLightData(); + data.Attenuation.X = energy; } } // ---------------------------------------------------------------------------- From ab4379902a6ba4bc428e3b63f6df77933d4a4cfa Mon Sep 17 00:00:00 2001 From: Deve Date: Sun, 4 May 2025 20:34:24 +0200 Subject: [PATCH 709/830] Enable kart lighting effects on vulkan --- lib/graphics_engine/include/ge_spm.hpp | 2 + lib/graphics_engine/src/ge_spm.cpp | 10 ++++ lib/irrlicht/include/IMeshCache.h | 2 + src/karts/kart_gfx.cpp | 32 +++++++++---- src/karts/kart_gfx.hpp | 1 + src/karts/kart_model.cpp | 66 +++++++++++++++++++++++++- src/karts/kart_model.hpp | 14 +++++- 7 files changed, 113 insertions(+), 14 deletions(-) diff --git a/lib/graphics_engine/include/ge_spm.hpp b/lib/graphics_engine/include/ge_spm.hpp index df37c674f3a..e0f1e2ff2bb 100644 --- a/lib/graphics_engine/include/ge_spm.hpp +++ b/lib/graphics_engine/include/ge_spm.hpp @@ -83,6 +83,8 @@ friend class ::SPMeshLoader; unsigned getJointCount() const { return m_joint_using; } // ------------------------------------------------------------------------ void addMeshBuffer(GESPMBuffer* mb) { m_buffer.push_back(mb); } + // ------------------------------------------------------------------------ + void removeMeshBuffer(u32 nr); }; diff --git a/lib/graphics_engine/src/ge_spm.cpp b/lib/graphics_engine/src/ge_spm.cpp index f88715618dc..5c9c526095c 100644 --- a/lib/graphics_engine/src/ge_spm.cpp +++ b/lib/graphics_engine/src/ge_spm.cpp @@ -99,4 +99,14 @@ s32 GESPM::getJointIDWithArm(const c8* name, unsigned* arm_id) const return -1; } // getJointIDWithArm +// ---------------------------------------------------------------------------- +void GESPM::removeMeshBuffer(u32 nr) +{ + if (nr < m_buffer.size()) + { + m_buffer[nr]->drop(); + m_buffer.erase(m_buffer.begin() + nr); + } +} // removeMeshBuffer + } diff --git a/lib/irrlicht/include/IMeshCache.h b/lib/irrlicht/include/IMeshCache.h index 083fc5b75ca..ca7ea52d1c9 100644 --- a/lib/irrlicht/include/IMeshCache.h +++ b/lib/irrlicht/include/IMeshCache.h @@ -167,6 +167,8 @@ namespace scene /** Warning: If you have pointers to meshes that were loaded with ISceneManager::getMesh() and you did not grab them, then they may become invalid. */ virtual void clearUnusedMeshes() = 0; + + virtual void meshCacheChanged() {} }; diff --git a/src/karts/kart_gfx.cpp b/src/karts/kart_gfx.cpp index f0352f31a8c..153f034c880 100644 --- a/src/karts/kart_gfx.cpp +++ b/src/karts/kart_gfx.cpp @@ -37,6 +37,7 @@ #include "race/race_manager.hpp" #include +#include "IVideoDriver.h" KartGFX::KartGFX(const AbstractKart *kart, bool is_day) { @@ -54,7 +55,7 @@ KartGFX::KartGFX(const AbstractKart *kart, bool is_day) // Create nitro light core::vector3df location(0.0f, 0.5f, -0.5f*length - 0.05f); #ifndef SERVER_ONLY - if (!GUIEngine::isNoGraphics() && CVS->isGLSL()) + if (!GUIEngine::isNoGraphics() && supportsLight()) { m_nitro_light = irr_driver->addLight(location, /*force*/ 0.4f, /*radius*/ 5.0f, 0.0f, 0.4f, 1.0f, @@ -148,7 +149,7 @@ KartGFX::~KartGFX() delete m_all_emitters[i]; } // for i < KGFX_COUNT - if (!GUIEngine::isNoGraphics() && CVS->isGLSL()) + if (!GUIEngine::isNoGraphics() && supportsLight()) { m_nitro_light->drop(); m_skidding_light_1->drop(); @@ -472,7 +473,7 @@ void KartGFX::updateNitroGraphics(float nitro_frac) setCreationRateRelative(KartGFX::KGFX_NITROSMOKE1, nitro_frac); setCreationRateRelative(KartGFX::KGFX_NITROSMOKE2, nitro_frac); - if (CVS->isGLSL()) + if (supportsLight()) m_nitro_light->setVisible(true); } else @@ -482,7 +483,7 @@ void KartGFX::updateNitroGraphics(float nitro_frac) setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE1, 0); setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE2, 0); - if (CVS->isGLSL()) + if (supportsLight()) m_nitro_light->setVisible(false); } @@ -500,7 +501,7 @@ void KartGFX::updateNitroGraphics(float nitro_frac) void KartGFX::updateSkidLight(unsigned int level) { #ifndef SERVER_ONLY - if (!GUIEngine::isNoGraphics() && CVS->isGLSL()) + if (!GUIEngine::isNoGraphics() && supportsLight()) { m_skidding_light_1->setVisible(level == 1); m_skidding_light_2->setVisible(level > 1); @@ -559,7 +560,7 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper, setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE1, (float)nitro); setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE2, (float)nitro); - if (CVS->isGLSL()) + if (supportsLight()) m_nitro_light->setVisible(true); } else @@ -569,7 +570,7 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper, setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE1, 0.0f); setCreationRateAbsolute(KartGFX::KGFX_NITROSMOKE2, 0.0f); - if (CVS->isGLSL()) + if (supportsLight()) m_nitro_light->setVisible(false); } @@ -586,7 +587,7 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper, if (m_all_emitters[KGFX_SKID1R]) m_all_emitters[KGFX_SKID1R]->setParticleType(skid_kind); - if (CVS->isGLSL()) + if (supportsLight()) { m_skidding_light_1->setVisible(!red_skidding); m_skidding_light_2->setVisible(red_skidding); @@ -600,7 +601,7 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper, setCreationRateAbsolute(KartGFX::KGFX_SKIDL, 0.0f); setCreationRateAbsolute(KartGFX::KGFX_SKIDR, 0.0f); - if (CVS->isGLSL()) + if (supportsLight()) { m_skidding_light_1->setVisible(false); m_skidding_light_2->setVisible(false); @@ -613,7 +614,7 @@ void KartGFX::setGFXFromReplay(int nitro, bool zipper, void KartGFX::setGFXInvisible() { #ifndef SERVER_ONLY - if (!GUIEngine::isNoGraphics() && CVS->isGLSL()) + if (!GUIEngine::isNoGraphics() && supportsLight()) { m_nitro_light->setVisible(false); m_skidding_light_1->setVisible(false); @@ -622,3 +623,14 @@ void KartGFX::setGFXInvisible() } #endif } // setGFXInvisible + +// ---------------------------------------------------------------------------- +bool KartGFX::supportsLight() const +{ +#ifdef SERVER_ONLY + return false; +#else + return CVS->isGLSL() || + irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN; +#endif +} diff --git a/src/karts/kart_gfx.hpp b/src/karts/kart_gfx.hpp index f511f6485b1..6747ee1a4b7 100644 --- a/src/karts/kart_gfx.hpp +++ b/src/karts/kart_gfx.hpp @@ -103,6 +103,7 @@ class KartGFX const Vec3 &position, bool important); void resizeBox(const KartGFXType type, float new_size); + bool supportsLight() const; public: KartGFX(const AbstractKart *kart, bool is_day); ~KartGFX(); diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index e7e42bef294..bc605630b87 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -46,11 +46,16 @@ #include "utils/constants.hpp" #include "utils/log.hpp" +#include "IMeshCache.h" #include "IMeshManipulator.h" +#include "ILightSceneNode.h" +#include "IVideoDriver.h" + #include #include #include #include +#include #define SKELETON_DEBUG 0 @@ -529,7 +534,9 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool human_playe irr_driver->addMesh(obj.getModel(), "kart_headlight", parent, getRenderInfo()); #ifndef SERVER_ONLY - if (human_player && CVS->isGLSL() && CVS->isDeferredEnabled()) + bool supports_light = (CVS->isGLSL() && CVS->isDeferredEnabled()) || + irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN; + if (human_player && supports_light) { obj.setLight(headlight_model, each_energy, each_radius); } @@ -573,10 +580,21 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool human_playe void HeadlightObject::setLight(scene::ISceneNode* parent, float energy, float radius) { + bool is_vk = irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN; + if (is_vk && m_spotlight == 1) + energy *= 2.0f; m_node = irr_driver->addLight(core::vector3df(0.0f, 0.0f, 0.0f), energy, radius, m_headlight_color.getRed() / 255.f, m_headlight_color.getGreen() / 255.f, m_headlight_color.getBlue() / 255.f, false/*sun*/, parent); + if (is_vk && m_spotlight == 1) + { + scene::ILightSceneNode* ln = static_cast(m_node); + ln->setLightType(video::ELT_SPOT); + video::SLight& data = ln->getLightData(); + data.InnerCone = 30.0f / 180.0f * M_PI; + data.OuterCone = 45.0f / 180.0f * M_PI; + } m_node->grab(); } // setLight @@ -704,6 +722,7 @@ bool KartModel::loadModels(const KartProperties &kart_properties) mesh->freeMeshVertexBuffer(); } + std::set spotlight_meshes; for (unsigned int i = 0; i < m_headlight_objects.size(); i++) { HeadlightObject& obj = m_headlight_objects[i]; @@ -711,6 +730,19 @@ bool KartModel::loadModels(const KartProperties &kart_properties) scene::IMesh* mesh = irr_driver->getMesh(full_name); if (!mesh) continue; +#ifndef SERVER_ONLY + bool spotlight = spotlight_meshes.find(mesh) != spotlight_meshes.end(); + GE::GESPM* spm = dynamic_cast(mesh); + if (obj.getSpotlight() == -1) + { + if (!spotlight && spm && handleSpotlight(spm)) + { + spotlight_meshes.insert(spm); + spotlight = true; + } + obj.setSpotlight(spotlight); + } +#endif obj.setModel(mesh); #ifndef SERVER_ONLY SP::uploadSPM(obj.getModel()); @@ -888,8 +920,12 @@ void KartModel::loadHeadlights(const XMLNode &node) child->get("model", &model); video::SColor headlight_color(-1); child->get("color", &headlight_color); + bool is_spotlight = false; + int spotlight = -1; + if (child->get("spotlight", &is_spotlight)) + spotlight = is_spotlight; m_headlight_objects.push_back(HeadlightObject(model, location, - bone_name, headlight_color)); + bone_name, headlight_color, spotlight)); } else { @@ -1404,3 +1440,29 @@ const core::matrix4& KartModel::getInverseBoneMatrix return unused; return ret->second; } // getInverseBoneMatrix + +//----------------------------------------------------------------------------- +bool KartModel::handleSpotlight(GE::GESPM* spm) +{ +#ifndef SERVER_ONLY + unsigned count = spm->getMeshBufferCount(); + bool spotlight = false; + for (int i = count - 1; i >= 0; i--) + { + GE::GESPMBuffer* b = static_cast(spm->getMeshBuffer(i)); + b->destroyVertexIndexBuffer(); + video::SMaterial& m = b->getMaterial(); + std::string t; + if (m.getTexture(0)) + t = m.getTexture(0)->getFullPath().c_str(); + if (t.find("stk_conelight_a.png") != std::string::npos) + { + spotlight = true; + spm->removeMeshBuffer(i); + } + } + spm->finalize(); + irr_driver->getSceneManager()->getMeshCache()->meshCacheChanged(); + return spotlight; +#endif +} // handleSpotlight diff --git a/src/karts/kart_model.hpp b/src/karts/kart_model.hpp index cc38b40f1d0..b3c40c9deb9 100644 --- a/src/karts/kart_model.hpp +++ b/src/karts/kart_model.hpp @@ -31,7 +31,7 @@ namespace irr class ISceneNode; class IMeshSceneNode; } } using namespace irr; -namespace GE { class GERenderInfo; } +namespace GE { class GERenderInfo; class GESPM; } #include "utils/no_copy.hpp" #include "utils/vec3.hpp" @@ -113,16 +113,19 @@ class HeadlightObject /** Attach to which bone in kart model if not empty. */ std::string m_bone_name; + int m_spotlight; public: HeadlightObject() { m_model = NULL; m_node = NULL; + m_spotlight = -1; } // HeadlightObject // ------------------------------------------------------------------------ HeadlightObject(const std::string& filename, const core::matrix4& location, - const std::string& bone_name, const video::SColor& color) + const std::string& bone_name, const video::SColor& color, + int spotlight) { m_filename = filename; m_location = location; @@ -130,6 +133,7 @@ class HeadlightObject m_node = NULL; m_bone_name = bone_name; m_headlight_color = color; + m_spotlight = spotlight; } // HeadlightObjects // ------------------------------------------------------------------------ const std::string& getFilename() const { return m_filename; } @@ -151,6 +155,10 @@ class HeadlightObject // ------------------------------------------------------------------------ const std::string& getBoneName() const { return m_bone_name; } // ------------------------------------------------------------------------ + int getSpotlight() const { return m_spotlight; } + // ------------------------------------------------------------------------ + void setSpotlight(bool spot) { m_spotlight = spot; } + // ------------------------------------------------------------------------ }; // class HeadlightObject // ============================================================================ @@ -339,6 +347,8 @@ class KartModel : public scene::IAnimationEndCallBack, public NoCopy node->setRotation(rotation); node->setScale(scale); } + // ------------------------------------------------------------------------ + bool handleSpotlight(GE::GESPM* spm); public: KartModel(bool is_master); From e6d48038e462c2aaaa5d78b339335db9f73b002b Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 6 May 2025 22:46:12 +0200 Subject: [PATCH 710/830] Update for latest MoltenVK --- lib/graphics_engine/include/glad/vulkan.h | 15728 +++++++++++++---- lib/graphics_engine/include/mvk_config.h | 1059 -- lib/graphics_engine/include/vk_platform.h | 30 +- lib/graphics_engine/include/vulkan_wrapper.h | 10 +- lib/graphics_engine/src/ge_vulkan_driver.cpp | 34 +- lib/graphics_engine/src/vulkan.c | 1744 +- lib/irrlicht/source/Irrlicht/MoltenVK.mm | 10 +- 7 files changed, 13800 insertions(+), 4815 deletions(-) delete mode 100644 lib/graphics_engine/include/mvk_config.h diff --git a/lib/graphics_engine/include/glad/vulkan.h b/lib/graphics_engine/include/glad/vulkan.h index 6a6123b7578..b59e27a68f8 100644 --- a/lib/graphics_engine/include/glad/vulkan.h +++ b/lib/graphics_engine/include/glad/vulkan.h @@ -1,27 +1,28 @@ /** - * Loader generated by glad 2.0.0-beta on Wed Nov 18 17:59:49 2020 + * Loader generated by glad 2.0.8 on Tue May 6 05:06:31 2025 + * + * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 * * Generator: C/C++ * Specification: vk - * Extensions: 211 + * Extensions: 392 * * APIs: - * - vulkan=1.2 + * - vulkan=1.4 * * Options: - * - MX_GLOBAL = False - * - ON_DEMAND = False - * - LOADER = False * - ALIAS = False - * - HEADER_ONLY = False * - DEBUG = False + * - HEADER_ONLY = False + * - LOADER = False * - MX = False + * - ON_DEMAND = False * * Commandline: - * --api='vulkan=1.2' --extensions='VK_AMD_buffer_marker,VK_AMD_device_coherent_memory,VK_AMD_display_native_hdr,VK_AMD_draw_indirect_count,VK_AMD_gcn_shader,VK_AMD_gpu_shader_half_float,VK_AMD_gpu_shader_int16,VK_AMD_memory_overallocation_behavior,VK_AMD_mixed_attachment_samples,VK_AMD_negative_viewport_height,VK_AMD_pipeline_compiler_control,VK_AMD_rasterization_order,VK_AMD_shader_ballot,VK_AMD_shader_core_properties,VK_AMD_shader_core_properties2,VK_AMD_shader_explicit_vertex_parameter,VK_AMD_shader_fragment_mask,VK_AMD_shader_image_load_store_lod,VK_AMD_shader_info,VK_AMD_shader_trinary_minmax,VK_AMD_texture_gather_bias_lod,VK_ANDROID_external_memory_android_hardware_buffer,VK_EXT_4444_formats,VK_EXT_acquire_xlib_display,VK_EXT_astc_decode_mode,VK_EXT_blend_operation_advanced,VK_EXT_buffer_device_address,VK_EXT_calibrated_timestamps,VK_EXT_conditional_rendering,VK_EXT_conservative_rasterization,VK_EXT_custom_border_color,VK_EXT_debug_marker,VK_EXT_debug_report,VK_EXT_debug_utils,VK_EXT_depth_clip_enable,VK_EXT_depth_range_unrestricted,VK_EXT_descriptor_indexing,VK_EXT_direct_mode_display,VK_EXT_directfb_surface,VK_EXT_discard_rectangles,VK_EXT_display_control,VK_EXT_display_surface_counter,VK_EXT_extended_dynamic_state,VK_EXT_external_memory_dma_buf,VK_EXT_external_memory_host,VK_EXT_filter_cubic,VK_EXT_fragment_density_map,VK_EXT_fragment_density_map2,VK_EXT_fragment_shader_interlock,VK_EXT_full_screen_exclusive,VK_EXT_global_priority,VK_EXT_hdr_metadata,VK_EXT_headless_surface,VK_EXT_host_query_reset,VK_EXT_image_drm_format_modifier,VK_EXT_image_robustness,VK_EXT_index_type_uint8,VK_EXT_inline_uniform_block,VK_EXT_line_rasterization,VK_EXT_memory_budget,VK_EXT_memory_priority,VK_EXT_metal_surface,VK_EXT_pci_bus_info,VK_EXT_pipeline_creation_cache_control,VK_EXT_pipeline_creation_feedback,VK_EXT_post_depth_coverage,VK_EXT_private_data,VK_EXT_queue_family_foreign,VK_EXT_robustness2,VK_EXT_sample_locations,VK_EXT_sampler_filter_minmax,VK_EXT_scalar_block_layout,VK_EXT_separate_stencil_usage,VK_EXT_shader_atomic_float,VK_EXT_shader_demote_to_helper_invocation,VK_EXT_shader_stencil_export,VK_EXT_shader_subgroup_ballot,VK_EXT_shader_subgroup_vote,VK_EXT_shader_viewport_index_layer,VK_EXT_subgroup_size_control,VK_EXT_swapchain_colorspace,VK_EXT_texel_buffer_alignment,VK_EXT_texture_compression_astc_hdr,VK_EXT_tooling_info,VK_EXT_transform_feedback,VK_EXT_validation_cache,VK_EXT_validation_features,VK_EXT_validation_flags,VK_EXT_vertex_attribute_divisor,VK_EXT_ycbcr_image_arrays,VK_FUCHSIA_imagepipe_surface,VK_GGP_frame_token,VK_GGP_stream_descriptor_surface,VK_GOOGLE_decorate_string,VK_GOOGLE_display_timing,VK_GOOGLE_hlsl_functionality1,VK_GOOGLE_user_type,VK_IMG_filter_cubic,VK_IMG_format_pvrtc,VK_INTEL_performance_query,VK_INTEL_shader_integer_functions2,VK_KHR_16bit_storage,VK_KHR_8bit_storage,VK_KHR_android_surface,VK_KHR_bind_memory2,VK_KHR_buffer_device_address,VK_KHR_create_renderpass2,VK_KHR_dedicated_allocation,VK_KHR_deferred_host_operations,VK_KHR_depth_stencil_resolve,VK_KHR_descriptor_update_template,VK_KHR_device_group,VK_KHR_device_group_creation,VK_KHR_display,VK_KHR_display_swapchain,VK_KHR_draw_indirect_count,VK_KHR_driver_properties,VK_KHR_external_fence,VK_KHR_external_fence_capabilities,VK_KHR_external_fence_fd,VK_KHR_external_fence_win32,VK_KHR_external_memory,VK_KHR_external_memory_capabilities,VK_KHR_external_memory_fd,VK_KHR_external_memory_win32,VK_KHR_external_semaphore,VK_KHR_external_semaphore_capabilities,VK_KHR_external_semaphore_fd,VK_KHR_external_semaphore_win32,VK_KHR_get_display_properties2,VK_KHR_get_memory_requirements2,VK_KHR_get_physical_device_properties2,VK_KHR_get_surface_capabilities2,VK_KHR_image_format_list,VK_KHR_imageless_framebuffer,VK_KHR_incremental_present,VK_KHR_maintenance1,VK_KHR_maintenance2,VK_KHR_maintenance3,VK_KHR_multiview,VK_KHR_performance_query,VK_KHR_pipeline_executable_properties,VK_KHR_pipeline_library,VK_KHR_push_descriptor,VK_KHR_ray_tracing,VK_KHR_relaxed_block_layout,VK_KHR_sampler_mirror_clamp_to_edge,VK_KHR_sampler_ycbcr_conversion,VK_KHR_separate_depth_stencil_layouts,VK_KHR_shader_atomic_int64,VK_KHR_shader_clock,VK_KHR_shader_draw_parameters,VK_KHR_shader_float16_int8,VK_KHR_shader_float_controls,VK_KHR_shader_non_semantic_info,VK_KHR_shader_subgroup_extended_types,VK_KHR_shared_presentable_image,VK_KHR_spirv_1_4,VK_KHR_storage_buffer_storage_class,VK_KHR_surface,VK_KHR_surface_protected_capabilities,VK_KHR_swapchain,VK_KHR_swapchain_mutable_format,VK_KHR_timeline_semaphore,VK_KHR_uniform_buffer_standard_layout,VK_KHR_variable_pointers,VK_KHR_vulkan_memory_model,VK_KHR_wayland_surface,VK_KHR_win32_keyed_mutex,VK_KHR_win32_surface,VK_KHR_xcb_surface,VK_KHR_xlib_surface,VK_MVK_ios_surface,VK_MVK_macos_surface,VK_NN_vi_surface,VK_NVX_image_view_handle,VK_NVX_multiview_per_view_attributes,VK_NV_clip_space_w_scaling,VK_NV_compute_shader_derivatives,VK_NV_cooperative_matrix,VK_NV_corner_sampled_image,VK_NV_coverage_reduction_mode,VK_NV_dedicated_allocation,VK_NV_dedicated_allocation_image_aliasing,VK_NV_device_diagnostic_checkpoints,VK_NV_device_diagnostics_config,VK_NV_device_generated_commands,VK_NV_external_memory,VK_NV_external_memory_capabilities,VK_NV_external_memory_win32,VK_NV_fill_rectangle,VK_NV_fragment_coverage_to_color,VK_NV_fragment_shader_barycentric,VK_NV_framebuffer_mixed_samples,VK_NV_geometry_shader_passthrough,VK_NV_glsl_shader,VK_NV_mesh_shader,VK_NV_ray_tracing,VK_NV_representative_fragment_test,VK_NV_sample_mask_override_coverage,VK_NV_scissor_exclusive,VK_NV_shader_image_footprint,VK_NV_shader_sm_builtins,VK_NV_shader_subgroup_partitioned,VK_NV_shading_rate_image,VK_NV_viewport_array2,VK_NV_viewport_swizzle,VK_NV_win32_keyed_mutex,VK_QCOM_render_pass_shader_resolve,VK_QCOM_render_pass_store_ops,VK_QCOM_render_pass_transform' c + * --api='vulkan=1.4' --extensions='VK_AMDX_shader_enqueue,VK_AMD_anti_lag,VK_AMD_buffer_marker,VK_AMD_device_coherent_memory,VK_AMD_display_native_hdr,VK_AMD_draw_indirect_count,VK_AMD_gcn_shader,VK_AMD_gpu_shader_half_float,VK_AMD_gpu_shader_int16,VK_AMD_memory_overallocation_behavior,VK_AMD_mixed_attachment_samples,VK_AMD_negative_viewport_height,VK_AMD_pipeline_compiler_control,VK_AMD_rasterization_order,VK_AMD_shader_ballot,VK_AMD_shader_core_properties,VK_AMD_shader_core_properties2,VK_AMD_shader_early_and_late_fragment_tests,VK_AMD_shader_explicit_vertex_parameter,VK_AMD_shader_fragment_mask,VK_AMD_shader_image_load_store_lod,VK_AMD_shader_info,VK_AMD_shader_trinary_minmax,VK_AMD_texture_gather_bias_lod,VK_ANDROID_external_format_resolve,VK_ANDROID_external_memory_android_hardware_buffer,VK_ARM_pipeline_opacity_micromap,VK_ARM_rasterization_order_attachment_access,VK_ARM_render_pass_striped,VK_ARM_scheduling_controls,VK_ARM_shader_core_builtins,VK_ARM_shader_core_properties,VK_EXT_4444_formats,VK_EXT_acquire_drm_display,VK_EXT_acquire_xlib_display,VK_EXT_astc_decode_mode,VK_EXT_attachment_feedback_loop_dynamic_state,VK_EXT_attachment_feedback_loop_layout,VK_EXT_blend_operation_advanced,VK_EXT_border_color_swizzle,VK_EXT_buffer_device_address,VK_EXT_calibrated_timestamps,VK_EXT_color_write_enable,VK_EXT_conditional_rendering,VK_EXT_conservative_rasterization,VK_EXT_custom_border_color,VK_EXT_debug_marker,VK_EXT_debug_report,VK_EXT_debug_utils,VK_EXT_depth_bias_control,VK_EXT_depth_clamp_control,VK_EXT_depth_clamp_zero_one,VK_EXT_depth_clip_control,VK_EXT_depth_clip_enable,VK_EXT_depth_range_unrestricted,VK_EXT_descriptor_buffer,VK_EXT_descriptor_indexing,VK_EXT_device_address_binding_report,VK_EXT_device_fault,VK_EXT_device_generated_commands,VK_EXT_device_memory_report,VK_EXT_direct_mode_display,VK_EXT_directfb_surface,VK_EXT_discard_rectangles,VK_EXT_display_control,VK_EXT_display_surface_counter,VK_EXT_dynamic_rendering_unused_attachments,VK_EXT_extended_dynamic_state,VK_EXT_extended_dynamic_state2,VK_EXT_extended_dynamic_state3,VK_EXT_external_memory_acquire_unmodified,VK_EXT_external_memory_dma_buf,VK_EXT_external_memory_host,VK_EXT_external_memory_metal,VK_EXT_filter_cubic,VK_EXT_fragment_density_map,VK_EXT_fragment_density_map2,VK_EXT_fragment_density_map_offset,VK_EXT_fragment_shader_interlock,VK_EXT_frame_boundary,VK_EXT_full_screen_exclusive,VK_EXT_global_priority,VK_EXT_global_priority_query,VK_EXT_graphics_pipeline_library,VK_EXT_hdr_metadata,VK_EXT_headless_surface,VK_EXT_host_image_copy,VK_EXT_host_query_reset,VK_EXT_image_2d_view_of_3d,VK_EXT_image_compression_control,VK_EXT_image_compression_control_swapchain,VK_EXT_image_drm_format_modifier,VK_EXT_image_robustness,VK_EXT_image_sliced_view_of_3d,VK_EXT_image_view_min_lod,VK_EXT_index_type_uint8,VK_EXT_inline_uniform_block,VK_EXT_layer_settings,VK_EXT_legacy_dithering,VK_EXT_legacy_vertex_attributes,VK_EXT_line_rasterization,VK_EXT_load_store_op_none,VK_EXT_map_memory_placed,VK_EXT_memory_budget,VK_EXT_memory_priority,VK_EXT_mesh_shader,VK_EXT_metal_objects,VK_EXT_metal_surface,VK_EXT_multi_draw,VK_EXT_multisampled_render_to_single_sampled,VK_EXT_mutable_descriptor_type,VK_EXT_nested_command_buffer,VK_EXT_non_seamless_cube_map,VK_EXT_opacity_micromap,VK_EXT_pageable_device_local_memory,VK_EXT_pci_bus_info,VK_EXT_physical_device_drm,VK_EXT_pipeline_creation_cache_control,VK_EXT_pipeline_creation_feedback,VK_EXT_pipeline_library_group_handles,VK_EXT_pipeline_properties,VK_EXT_pipeline_protected_access,VK_EXT_pipeline_robustness,VK_EXT_post_depth_coverage,VK_EXT_present_mode_fifo_latest_ready,VK_EXT_primitive_topology_list_restart,VK_EXT_primitives_generated_query,VK_EXT_private_data,VK_EXT_provoking_vertex,VK_EXT_queue_family_foreign,VK_EXT_rasterization_order_attachment_access,VK_EXT_rgba10x6_formats,VK_EXT_robustness2,VK_EXT_sample_locations,VK_EXT_sampler_filter_minmax,VK_EXT_scalar_block_layout,VK_EXT_separate_stencil_usage,VK_EXT_shader_atomic_float,VK_EXT_shader_atomic_float2,VK_EXT_shader_demote_to_helper_invocation,VK_EXT_shader_image_atomic_int64,VK_EXT_shader_module_identifier,VK_EXT_shader_object,VK_EXT_shader_replicated_composites,VK_EXT_shader_stencil_export,VK_EXT_shader_subgroup_ballot,VK_EXT_shader_subgroup_vote,VK_EXT_shader_tile_image,VK_EXT_shader_viewport_index_layer,VK_EXT_subgroup_size_control,VK_EXT_subpass_merge_feedback,VK_EXT_surface_maintenance1,VK_EXT_swapchain_colorspace,VK_EXT_swapchain_maintenance1,VK_EXT_texel_buffer_alignment,VK_EXT_texture_compression_astc_hdr,VK_EXT_tooling_info,VK_EXT_transform_feedback,VK_EXT_validation_cache,VK_EXT_validation_features,VK_EXT_validation_flags,VK_EXT_vertex_attribute_divisor,VK_EXT_vertex_attribute_robustness,VK_EXT_vertex_input_dynamic_state,VK_EXT_ycbcr_2plane_444_formats,VK_EXT_ycbcr_image_arrays,VK_FUCHSIA_buffer_collection,VK_FUCHSIA_external_memory,VK_FUCHSIA_external_semaphore,VK_FUCHSIA_imagepipe_surface,VK_GGP_frame_token,VK_GGP_stream_descriptor_surface,VK_GOOGLE_decorate_string,VK_GOOGLE_display_timing,VK_GOOGLE_hlsl_functionality1,VK_GOOGLE_surfaceless_query,VK_GOOGLE_user_type,VK_HUAWEI_cluster_culling_shader,VK_HUAWEI_hdr_vivid,VK_HUAWEI_invocation_mask,VK_HUAWEI_subpass_shading,VK_IMG_filter_cubic,VK_IMG_format_pvrtc,VK_IMG_relaxed_line_rasterization,VK_INTEL_performance_query,VK_INTEL_shader_integer_functions2,VK_KHR_16bit_storage,VK_KHR_8bit_storage,VK_KHR_acceleration_structure,VK_KHR_android_surface,VK_KHR_bind_memory2,VK_KHR_buffer_device_address,VK_KHR_calibrated_timestamps,VK_KHR_compute_shader_derivatives,VK_KHR_cooperative_matrix,VK_KHR_copy_commands2,VK_KHR_create_renderpass2,VK_KHR_dedicated_allocation,VK_KHR_deferred_host_operations,VK_KHR_depth_clamp_zero_one,VK_KHR_depth_stencil_resolve,VK_KHR_descriptor_update_template,VK_KHR_device_group,VK_KHR_device_group_creation,VK_KHR_display,VK_KHR_display_swapchain,VK_KHR_draw_indirect_count,VK_KHR_driver_properties,VK_KHR_dynamic_rendering,VK_KHR_dynamic_rendering_local_read,VK_KHR_external_fence,VK_KHR_external_fence_capabilities,VK_KHR_external_fence_fd,VK_KHR_external_fence_win32,VK_KHR_external_memory,VK_KHR_external_memory_capabilities,VK_KHR_external_memory_fd,VK_KHR_external_memory_win32,VK_KHR_external_semaphore,VK_KHR_external_semaphore_capabilities,VK_KHR_external_semaphore_fd,VK_KHR_external_semaphore_win32,VK_KHR_format_feature_flags2,VK_KHR_fragment_shader_barycentric,VK_KHR_fragment_shading_rate,VK_KHR_get_display_properties2,VK_KHR_get_memory_requirements2,VK_KHR_get_physical_device_properties2,VK_KHR_get_surface_capabilities2,VK_KHR_global_priority,VK_KHR_image_format_list,VK_KHR_imageless_framebuffer,VK_KHR_incremental_present,VK_KHR_index_type_uint8,VK_KHR_line_rasterization,VK_KHR_load_store_op_none,VK_KHR_maintenance1,VK_KHR_maintenance2,VK_KHR_maintenance3,VK_KHR_maintenance4,VK_KHR_maintenance5,VK_KHR_maintenance6,VK_KHR_maintenance7,VK_KHR_maintenance8,VK_KHR_map_memory2,VK_KHR_multiview,VK_KHR_performance_query,VK_KHR_pipeline_binary,VK_KHR_pipeline_executable_properties,VK_KHR_pipeline_library,VK_KHR_portability_enumeration,VK_KHR_portability_subset,VK_KHR_present_id,VK_KHR_present_wait,VK_KHR_push_descriptor,VK_KHR_ray_query,VK_KHR_ray_tracing_maintenance1,VK_KHR_ray_tracing_pipeline,VK_KHR_ray_tracing_position_fetch,VK_KHR_relaxed_block_layout,VK_KHR_robustness2,VK_KHR_sampler_mirror_clamp_to_edge,VK_KHR_sampler_ycbcr_conversion,VK_KHR_separate_depth_stencil_layouts,VK_KHR_shader_atomic_int64,VK_KHR_shader_bfloat16,VK_KHR_shader_clock,VK_KHR_shader_draw_parameters,VK_KHR_shader_expect_assume,VK_KHR_shader_float16_int8,VK_KHR_shader_float_controls,VK_KHR_shader_float_controls2,VK_KHR_shader_integer_dot_product,VK_KHR_shader_maximal_reconvergence,VK_KHR_shader_non_semantic_info,VK_KHR_shader_quad_control,VK_KHR_shader_relaxed_extended_instruction,VK_KHR_shader_subgroup_extended_types,VK_KHR_shader_subgroup_rotate,VK_KHR_shader_subgroup_uniform_control_flow,VK_KHR_shader_terminate_invocation,VK_KHR_shared_presentable_image,VK_KHR_spirv_1_4,VK_KHR_storage_buffer_storage_class,VK_KHR_surface,VK_KHR_surface_protected_capabilities,VK_KHR_swapchain,VK_KHR_swapchain_mutable_format,VK_KHR_synchronization2,VK_KHR_timeline_semaphore,VK_KHR_uniform_buffer_standard_layout,VK_KHR_variable_pointers,VK_KHR_vertex_attribute_divisor,VK_KHR_vulkan_memory_model,VK_KHR_wayland_surface,VK_KHR_win32_keyed_mutex,VK_KHR_win32_surface,VK_KHR_workgroup_memory_explicit_layout,VK_KHR_xcb_surface,VK_KHR_xlib_surface,VK_KHR_zero_initialize_workgroup_memory,VK_LUNARG_direct_driver_loading,VK_MESA_image_alignment_control,VK_MSFT_layered_driver,VK_MVK_ios_surface,VK_MVK_macos_surface,VK_NN_vi_surface,VK_NVX_binary_import,VK_NVX_image_view_handle,VK_NVX_multiview_per_view_attributes,VK_NV_acquire_winrt_display,VK_NV_clip_space_w_scaling,VK_NV_cluster_acceleration_structure,VK_NV_command_buffer_inheritance,VK_NV_compute_shader_derivatives,VK_NV_cooperative_matrix,VK_NV_cooperative_matrix2,VK_NV_cooperative_vector,VK_NV_copy_memory_indirect,VK_NV_corner_sampled_image,VK_NV_coverage_reduction_mode,VK_NV_cuda_kernel_launch,VK_NV_dedicated_allocation,VK_NV_dedicated_allocation_image_aliasing,VK_NV_descriptor_pool_overallocation,VK_NV_device_diagnostic_checkpoints,VK_NV_device_diagnostics_config,VK_NV_device_generated_commands,VK_NV_device_generated_commands_compute,VK_NV_displacement_micromap,VK_NV_display_stereo,VK_NV_extended_sparse_address_space,VK_NV_external_compute_queue,VK_NV_external_memory,VK_NV_external_memory_capabilities,VK_NV_external_memory_rdma,VK_NV_external_memory_win32,VK_NV_fill_rectangle,VK_NV_fragment_coverage_to_color,VK_NV_fragment_shader_barycentric,VK_NV_fragment_shading_rate_enums,VK_NV_framebuffer_mixed_samples,VK_NV_geometry_shader_passthrough,VK_NV_glsl_shader,VK_NV_inherited_viewport_scissor,VK_NV_linear_color_attachment,VK_NV_low_latency,VK_NV_low_latency2,VK_NV_memory_decompression,VK_NV_mesh_shader,VK_NV_optical_flow,VK_NV_partitioned_acceleration_structure,VK_NV_per_stage_descriptor_set,VK_NV_present_barrier,VK_NV_present_metering,VK_NV_raw_access_chains,VK_NV_ray_tracing,VK_NV_ray_tracing_invocation_reorder,VK_NV_ray_tracing_linear_swept_spheres,VK_NV_ray_tracing_motion_blur,VK_NV_ray_tracing_validation,VK_NV_representative_fragment_test,VK_NV_sample_mask_override_coverage,VK_NV_scissor_exclusive,VK_NV_shader_atomic_float16_vector,VK_NV_shader_image_footprint,VK_NV_shader_sm_builtins,VK_NV_shader_subgroup_partitioned,VK_NV_shading_rate_image,VK_NV_viewport_array2,VK_NV_viewport_swizzle,VK_NV_win32_keyed_mutex,VK_QCOM_filter_cubic_clamp,VK_QCOM_filter_cubic_weights,VK_QCOM_fragment_density_map_offset,VK_QCOM_image_processing,VK_QCOM_image_processing2,VK_QCOM_multiview_per_view_render_areas,VK_QCOM_multiview_per_view_viewports,VK_QCOM_render_pass_shader_resolve,VK_QCOM_render_pass_store_ops,VK_QCOM_render_pass_transform,VK_QCOM_rotated_copy_commands,VK_QCOM_tile_memory_heap,VK_QCOM_tile_properties,VK_QCOM_tile_shading,VK_QCOM_ycbcr_degamma,VK_QNX_external_memory_screen_buffer,VK_QNX_screen_surface,VK_SEC_amigo_profiling,VK_VALVE_descriptor_set_host_mapping,VK_VALVE_mutable_descriptor_type' c * * Online: - * http://glad.sh/#api=vulkan%3D1.2&generator=c&options= + * http://glad.sh/#api=vulkan%3D1.4&generator=c&options= * */ @@ -101,6 +102,8 @@ extern "C" { #define GLAD_GNUC_EXTENSION #endif +#define GLAD_UNUSED(x) (void)(x) + #ifndef GLAD_API_CALL #if defined(GLAD_API_CALL_EXPORT) #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) @@ -147,7 +150,7 @@ extern "C" { #define GLAD_VERSION_MAJOR(version) (version / 10000) #define GLAD_VERSION_MINOR(version) (version % 10000) -#define GLAD_GENERATOR_VERSION "2.0.0-beta" +#define GLAD_GENERATOR_VERSION "2.0.8" typedef void (*GLADapiproc)(void); @@ -159,6 +162,16 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #endif /* GLAD_PLATFORM_H_ */ +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_AMDX_SHADER_ENQUEUE_EXTENSION_NAME "VK_AMDX_shader_enqueue" + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_AMDX_SHADER_ENQUEUE_SPEC_VERSION 2 + +#endif +#define VK_AMD_ANTI_LAG_EXTENSION_NAME "VK_AMD_anti_lag" +#define VK_AMD_ANTI_LAG_SPEC_VERSION 1 #define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_AMD_buffer_marker" #define VK_AMD_BUFFER_MARKER_SPEC_VERSION 1 #define VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME "VK_AMD_device_coherent_memory" @@ -189,6 +202,8 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_AMD_SHADER_CORE_PROPERTIES_2_SPEC_VERSION 1 #define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties" #define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 2 +#define VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_EXTENSION_NAME "VK_AMD_shader_early_and_late_fragment_tests" +#define VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_SPEC_VERSION 1 #define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter" #define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1 #define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask" @@ -202,28 +217,62 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod" #define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_ANDROID_KHR) -#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer" +#define VK_ANDROID_EXTERNAL_FORMAT_RESOLVE_EXTENSION_NAME "VK_ANDROID_external_format_resolve" + #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) -#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 3 +#define VK_ANDROID_EXTERNAL_FORMAT_RESOLVE_SPEC_VERSION 1 + +#endif +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer" + #endif +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +#define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 5 + +#endif +#define VK_ARM_PIPELINE_OPACITY_MICROMAP_EXTENSION_NAME "VK_ARM_pipeline_opacity_micromap" +#define VK_ARM_PIPELINE_OPACITY_MICROMAP_SPEC_VERSION 1 +#define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME "VK_ARM_rasterization_order_attachment_access" +#define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION 1 +#define VK_ARM_RENDER_PASS_STRIPED_EXTENSION_NAME "VK_ARM_render_pass_striped" +#define VK_ARM_RENDER_PASS_STRIPED_SPEC_VERSION 1 +#define VK_ARM_SCHEDULING_CONTROLS_EXTENSION_NAME "VK_ARM_scheduling_controls" +#define VK_ARM_SCHEDULING_CONTROLS_SPEC_VERSION 1 +#define VK_ARM_SHADER_CORE_BUILTINS_EXTENSION_NAME "VK_ARM_shader_core_builtins" +#define VK_ARM_SHADER_CORE_BUILTINS_SPEC_VERSION 2 +#define VK_ARM_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_ARM_shader_core_properties" +#define VK_ARM_SHADER_CORE_PROPERTIES_SPEC_VERSION 1 #define VK_ATTACHMENT_UNUSED (~0U) #define VK_EXT_4444_FORMATS_EXTENSION_NAME "VK_EXT_4444_formats" #define VK_EXT_4444_FORMATS_SPEC_VERSION 1 +#define VK_EXT_ACQUIRE_DRM_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_drm_display" +#define VK_EXT_ACQUIRE_DRM_DISPLAY_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) #define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display" + #endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) #define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1 + #endif #define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode" #define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1 +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_attachment_feedback_loop_dynamic_state" +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_SPEC_VERSION 1 +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_EXTENSION_NAME "VK_EXT_attachment_feedback_loop_layout" +#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_SPEC_VERSION 2 #define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced" #define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2 +#define VK_EXT_BORDER_COLOR_SWIZZLE_EXTENSION_NAME "VK_EXT_border_color_swizzle" +#define VK_EXT_BORDER_COLOR_SWIZZLE_SPEC_VERSION 1 #define VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_EXT_buffer_device_address" #define VK_EXT_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 2 #define VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_EXT_calibrated_timestamps" -#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 1 +#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 2 +#define VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME "VK_EXT_color_write_enable" +#define VK_EXT_COLOR_WRITE_ENABLE_SPEC_VERSION 1 #define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering" #define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 2 #define VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME "VK_EXT_conservative_rasterization" @@ -233,89 +282,205 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker" #define VK_EXT_DEBUG_MARKER_SPEC_VERSION 4 #define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" -#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 9 +#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 10 #define VK_EXT_DEBUG_UTILS_EXTENSION_NAME "VK_EXT_debug_utils" #define VK_EXT_DEBUG_UTILS_SPEC_VERSION 2 +#define VK_EXT_DEPTH_BIAS_CONTROL_EXTENSION_NAME "VK_EXT_depth_bias_control" +#define VK_EXT_DEPTH_BIAS_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME "VK_EXT_depth_clamp_control" +#define VK_EXT_DEPTH_CLAMP_CONTROL_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLAMP_ZERO_ONE_EXTENSION_NAME "VK_EXT_depth_clamp_zero_one" +#define VK_EXT_DEPTH_CLAMP_ZERO_ONE_SPEC_VERSION 1 +#define VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME "VK_EXT_depth_clip_control" +#define VK_EXT_DEPTH_CLIP_CONTROL_SPEC_VERSION 1 #define VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME "VK_EXT_depth_clip_enable" #define VK_EXT_DEPTH_CLIP_ENABLE_SPEC_VERSION 1 #define VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME "VK_EXT_depth_range_unrestricted" #define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION 1 +#define VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME "VK_EXT_descriptor_buffer" +#define VK_EXT_DESCRIPTOR_BUFFER_SPEC_VERSION 1 #define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME "VK_EXT_descriptor_indexing" #define VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION 2 +#define VK_EXT_DEVICE_ADDRESS_BINDING_REPORT_EXTENSION_NAME "VK_EXT_device_address_binding_report" +#define VK_EXT_DEVICE_ADDRESS_BINDING_REPORT_SPEC_VERSION 1 +#define VK_EXT_DEVICE_FAULT_EXTENSION_NAME "VK_EXT_device_fault" +#define VK_EXT_DEVICE_FAULT_SPEC_VERSION 2 +#define VK_EXT_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_EXT_device_generated_commands" +#define VK_EXT_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1 +#define VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME "VK_EXT_device_memory_report" +#define VK_EXT_DEVICE_MEMORY_REPORT_SPEC_VERSION 2 #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) #define VK_EXT_DIRECTFB_SURFACE_EXTENSION_NAME "VK_EXT_directfb_surface" + #endif #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) #define VK_EXT_DIRECTFB_SURFACE_SPEC_VERSION 1 + #endif #define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display" #define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1 #define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles" -#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1 +#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 2 #define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME "VK_EXT_display_control" #define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1 #define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter" #define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1 +#define VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME "VK_EXT_dynamic_rendering_unused_attachments" +#define VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_SPEC_VERSION 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME "VK_EXT_extended_dynamic_state2" +#define VK_EXT_EXTENDED_DYNAMIC_STATE_2_SPEC_VERSION 1 +#define VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME "VK_EXT_extended_dynamic_state3" +#define VK_EXT_EXTENDED_DYNAMIC_STATE_3_SPEC_VERSION 2 #define VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_extended_dynamic_state" #define VK_EXT_EXTENDED_DYNAMIC_STATE_SPEC_VERSION 1 +#define VK_EXT_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_EXTENSION_NAME "VK_EXT_external_memory_acquire_unmodified" +#define VK_EXT_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_SPEC_VERSION 1 #define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME "VK_EXT_external_memory_dma_buf" #define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_SPEC_VERSION 1 #define VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME "VK_EXT_external_memory_host" #define VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION 1 +#if defined(VK_USE_PLATFORM_METAL_EXT) +#define VK_EXT_EXTERNAL_MEMORY_METAL_EXTENSION_NAME "VK_EXT_external_memory_metal" + +#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +#define VK_EXT_EXTERNAL_MEMORY_METAL_SPEC_VERSION 1 + +#endif #define VK_EXT_FILTER_CUBIC_EXTENSION_NAME "VK_EXT_filter_cubic" #define VK_EXT_FILTER_CUBIC_SPEC_VERSION 3 #define VK_EXT_FRAGMENT_DENSITY_MAP_2_EXTENSION_NAME "VK_EXT_fragment_density_map2" #define VK_EXT_FRAGMENT_DENSITY_MAP_2_SPEC_VERSION 1 #define VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME "VK_EXT_fragment_density_map" -#define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME "VK_EXT_fragment_density_map_offset" +#define VK_EXT_FRAGMENT_DENSITY_MAP_OFFSET_SPEC_VERSION 1 +#define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 2 #define VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME "VK_EXT_fragment_shader_interlock" #define VK_EXT_FRAGMENT_SHADER_INTERLOCK_SPEC_VERSION 1 +#define VK_EXT_FRAME_BOUNDARY_EXTENSION_NAME "VK_EXT_frame_boundary" +#define VK_EXT_FRAME_BOUNDARY_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME "VK_EXT_full_screen_exclusive" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_EXT_FULL_SCREEN_EXCLUSIVE_SPEC_VERSION 4 + #endif #define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority" +#define VK_EXT_GLOBAL_PRIORITY_QUERY_EXTENSION_NAME "VK_EXT_global_priority_query" +#define VK_EXT_GLOBAL_PRIORITY_QUERY_SPEC_VERSION 1 #define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 2 +#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME "VK_EXT_graphics_pipeline_library" +#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_SPEC_VERSION 1 #define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata" -#define VK_EXT_HDR_METADATA_SPEC_VERSION 2 +#define VK_EXT_HDR_METADATA_SPEC_VERSION 3 #define VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME "VK_EXT_headless_surface" #define VK_EXT_HEADLESS_SURFACE_SPEC_VERSION 1 +#define VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME "VK_EXT_host_image_copy" +#define VK_EXT_HOST_IMAGE_COPY_SPEC_VERSION 1 #define VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME "VK_EXT_host_query_reset" #define VK_EXT_HOST_QUERY_RESET_SPEC_VERSION 1 +#define VK_EXT_IMAGE_2D_VIEW_OF_3D_EXTENSION_NAME "VK_EXT_image_2d_view_of_3d" +#define VK_EXT_IMAGE_2D_VIEW_OF_3D_SPEC_VERSION 1 +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME "VK_EXT_image_compression_control" +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SPEC_VERSION 1 +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME "VK_EXT_image_compression_control_swapchain" +#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION 1 #define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier" -#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1 +#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 2 #define VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_image_robustness" #define VK_EXT_IMAGE_ROBUSTNESS_SPEC_VERSION 1 +#define VK_EXT_IMAGE_SLICED_VIEW_OF_3D_EXTENSION_NAME "VK_EXT_image_sliced_view_of_3d" +#define VK_EXT_IMAGE_SLICED_VIEW_OF_3D_SPEC_VERSION 1 +#define VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME "VK_EXT_image_view_min_lod" +#define VK_EXT_IMAGE_VIEW_MIN_LOD_SPEC_VERSION 1 #define VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME "VK_EXT_index_type_uint8" #define VK_EXT_INDEX_TYPE_UINT8_SPEC_VERSION 1 #define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block" #define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1 +#define VK_EXT_LAYER_SETTINGS_EXTENSION_NAME "VK_EXT_layer_settings" +#define VK_EXT_LAYER_SETTINGS_SPEC_VERSION 2 +#define VK_EXT_LEGACY_DITHERING_EXTENSION_NAME "VK_EXT_legacy_dithering" +#define VK_EXT_LEGACY_DITHERING_SPEC_VERSION 2 +#define VK_EXT_LEGACY_VERTEX_ATTRIBUTES_EXTENSION_NAME "VK_EXT_legacy_vertex_attributes" +#define VK_EXT_LEGACY_VERTEX_ATTRIBUTES_SPEC_VERSION 1 #define VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME "VK_EXT_line_rasterization" #define VK_EXT_LINE_RASTERIZATION_SPEC_VERSION 1 +#define VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME "VK_EXT_load_store_op_none" +#define VK_EXT_LOAD_STORE_OP_NONE_SPEC_VERSION 1 +#define VK_EXT_MAP_MEMORY_PLACED_EXTENSION_NAME "VK_EXT_map_memory_placed" +#define VK_EXT_MAP_MEMORY_PLACED_SPEC_VERSION 1 #define VK_EXT_MEMORY_BUDGET_EXTENSION_NAME "VK_EXT_memory_budget" #define VK_EXT_MEMORY_BUDGET_SPEC_VERSION 1 #define VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME "VK_EXT_memory_priority" #define VK_EXT_MEMORY_PRIORITY_SPEC_VERSION 1 +#define VK_EXT_MESH_SHADER_EXTENSION_NAME "VK_EXT_mesh_shader" +#define VK_EXT_MESH_SHADER_SPEC_VERSION 1 +#if defined(VK_USE_PLATFORM_METAL_EXT) +#define VK_EXT_METAL_OBJECTS_EXTENSION_NAME "VK_EXT_metal_objects" + +#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +#define VK_EXT_METAL_OBJECTS_SPEC_VERSION 2 + +#endif #if defined(VK_USE_PLATFORM_METAL_EXT) #define VK_EXT_METAL_SURFACE_EXTENSION_NAME "VK_EXT_metal_surface" + #endif #if defined(VK_USE_PLATFORM_METAL_EXT) #define VK_EXT_METAL_SURFACE_SPEC_VERSION 1 + #endif +#define VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXTENSION_NAME "VK_EXT_multisampled_render_to_single_sampled" +#define VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_SPEC_VERSION 1 +#define VK_EXT_MULTI_DRAW_EXTENSION_NAME "VK_EXT_multi_draw" +#define VK_EXT_MULTI_DRAW_SPEC_VERSION 1 +#define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_EXT_mutable_descriptor_type" +#define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1 +#define VK_EXT_NESTED_COMMAND_BUFFER_EXTENSION_NAME "VK_EXT_nested_command_buffer" +#define VK_EXT_NESTED_COMMAND_BUFFER_SPEC_VERSION 1 +#define VK_EXT_NON_SEAMLESS_CUBE_MAP_EXTENSION_NAME "VK_EXT_non_seamless_cube_map" +#define VK_EXT_NON_SEAMLESS_CUBE_MAP_SPEC_VERSION 1 +#define VK_EXT_OPACITY_MICROMAP_EXTENSION_NAME "VK_EXT_opacity_micromap" +#define VK_EXT_OPACITY_MICROMAP_SPEC_VERSION 2 +#define VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME "VK_EXT_pageable_device_local_memory" +#define VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_SPEC_VERSION 1 #define VK_EXT_PCI_BUS_INFO_EXTENSION_NAME "VK_EXT_pci_bus_info" #define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 2 +#define VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME "VK_EXT_physical_device_drm" +#define VK_EXT_PHYSICAL_DEVICE_DRM_SPEC_VERSION 1 #define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME "VK_EXT_pipeline_creation_cache_control" #define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_SPEC_VERSION 3 #define VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME "VK_EXT_pipeline_creation_feedback" #define VK_EXT_PIPELINE_CREATION_FEEDBACK_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_LIBRARY_GROUP_HANDLES_EXTENSION_NAME "VK_EXT_pipeline_library_group_handles" +#define VK_EXT_PIPELINE_LIBRARY_GROUP_HANDLES_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_PROPERTIES_EXTENSION_NAME "VK_EXT_pipeline_properties" +#define VK_EXT_PIPELINE_PROPERTIES_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_PROTECTED_ACCESS_EXTENSION_NAME "VK_EXT_pipeline_protected_access" +#define VK_EXT_PIPELINE_PROTECTED_ACCESS_SPEC_VERSION 1 +#define VK_EXT_PIPELINE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_pipeline_robustness" +#define VK_EXT_PIPELINE_ROBUSTNESS_SPEC_VERSION 1 #define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage" #define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1 +#define VK_EXT_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME "VK_EXT_present_mode_fifo_latest_ready" +#define VK_EXT_PRESENT_MODE_FIFO_LATEST_READY_SPEC_VERSION 1 +#define VK_EXT_PRIMITIVES_GENERATED_QUERY_EXTENSION_NAME "VK_EXT_primitives_generated_query" +#define VK_EXT_PRIMITIVES_GENERATED_QUERY_SPEC_VERSION 1 +#define VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME "VK_EXT_primitive_topology_list_restart" +#define VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_SPEC_VERSION 1 #define VK_EXT_PRIVATE_DATA_EXTENSION_NAME "VK_EXT_private_data" #define VK_EXT_PRIVATE_DATA_SPEC_VERSION 1 +#define VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME "VK_EXT_provoking_vertex" +#define VK_EXT_PROVOKING_VERTEX_SPEC_VERSION 1 #define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME "VK_EXT_queue_family_foreign" #define VK_EXT_QUEUE_FAMILY_FOREIGN_SPEC_VERSION 1 +#define VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME "VK_EXT_rasterization_order_attachment_access" +#define VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION 1 +#define VK_EXT_RGBA10X6_FORMATS_EXTENSION_NAME "VK_EXT_rgba10x6_formats" +#define VK_EXT_RGBA10X6_FORMATS_SPEC_VERSION 1 #define VK_EXT_ROBUSTNESS_2_EXTENSION_NAME "VK_EXT_robustness2" #define VK_EXT_ROBUSTNESS_2_SPEC_VERSION 1 #define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax" @@ -326,22 +491,40 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1 #define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage" #define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1 +#define VK_EXT_SHADER_ATOMIC_FLOAT_2_EXTENSION_NAME "VK_EXT_shader_atomic_float2" +#define VK_EXT_SHADER_ATOMIC_FLOAT_2_SPEC_VERSION 1 #define VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME "VK_EXT_shader_atomic_float" #define VK_EXT_SHADER_ATOMIC_FLOAT_SPEC_VERSION 1 #define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME "VK_EXT_shader_demote_to_helper_invocation" #define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_SPEC_VERSION 1 +#define VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME "VK_EXT_shader_image_atomic_int64" +#define VK_EXT_SHADER_IMAGE_ATOMIC_INT64_SPEC_VERSION 1 +#define VK_EXT_SHADER_MODULE_IDENTIFIER_EXTENSION_NAME "VK_EXT_shader_module_identifier" +#define VK_EXT_SHADER_MODULE_IDENTIFIER_SPEC_VERSION 1 +#define VK_EXT_SHADER_OBJECT_EXTENSION_NAME "VK_EXT_shader_object" +#define VK_EXT_SHADER_OBJECT_SPEC_VERSION 1 +#define VK_EXT_SHADER_REPLICATED_COMPOSITES_EXTENSION_NAME "VK_EXT_shader_replicated_composites" +#define VK_EXT_SHADER_REPLICATED_COMPOSITES_SPEC_VERSION 1 #define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export" #define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1 #define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot" #define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1 #define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote" #define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1 +#define VK_EXT_SHADER_TILE_IMAGE_EXTENSION_NAME "VK_EXT_shader_tile_image" +#define VK_EXT_SHADER_TILE_IMAGE_SPEC_VERSION 1 #define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer" #define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1 #define VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME "VK_EXT_subgroup_size_control" #define VK_EXT_SUBGROUP_SIZE_CONTROL_SPEC_VERSION 2 +#define VK_EXT_SUBPASS_MERGE_FEEDBACK_EXTENSION_NAME "VK_EXT_subpass_merge_feedback" +#define VK_EXT_SUBPASS_MERGE_FEEDBACK_SPEC_VERSION 2 +#define VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME "VK_EXT_surface_maintenance1" +#define VK_EXT_SURFACE_MAINTENANCE_1_SPEC_VERSION 1 #define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" -#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 4 +#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 5 +#define VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME "VK_EXT_swapchain_maintenance1" +#define VK_EXT_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION 1 #define VK_EXT_TEXEL_BUFFER_ALIGNMENT_EXTENSION_NAME "VK_EXT_texel_buffer_alignment" #define VK_EXT_TEXEL_BUFFER_ALIGNMENT_SPEC_VERSION 1 #define VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME "VK_EXT_texture_compression_astc_hdr" @@ -353,31 +536,67 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache" #define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1 #define VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME "VK_EXT_validation_features" -#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 4 +#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 6 #define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags" -#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 2 +#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 3 #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor" #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3 +#define VK_EXT_VERTEX_ATTRIBUTE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_vertex_attribute_robustness" +#define VK_EXT_VERTEX_ATTRIBUTE_ROBUSTNESS_SPEC_VERSION 1 +#define VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_vertex_input_dynamic_state" +#define VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_SPEC_VERSION 2 +#define VK_EXT_YCBCR_2PLANE_444_FORMATS_EXTENSION_NAME "VK_EXT_ycbcr_2plane_444_formats" +#define VK_EXT_YCBCR_2PLANE_444_FORMATS_SPEC_VERSION 1 #define VK_EXT_YCBCR_IMAGE_ARRAYS_EXTENSION_NAME "VK_EXT_ycbcr_image_arrays" #define VK_EXT_YCBCR_IMAGE_ARRAYS_SPEC_VERSION 1 #define VK_FALSE 0 #if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME "VK_FUCHSIA_buffer_collection" + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_BUFFER_COLLECTION_SPEC_VERSION 2 + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME "VK_FUCHSIA_external_memory" + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_EXTERNAL_MEMORY_SPEC_VERSION 1 + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_FUCHSIA_external_semaphore" + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) #define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface" + #endif #if defined(VK_USE_PLATFORM_FUCHSIA) #define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1 + #endif #if defined(VK_USE_PLATFORM_GGP) #define VK_GGP_FRAME_TOKEN_EXTENSION_NAME "VK_GGP_frame_token" + #endif #if defined(VK_USE_PLATFORM_GGP) #define VK_GGP_FRAME_TOKEN_SPEC_VERSION 1 + #endif #if defined(VK_USE_PLATFORM_GGP) #define VK_GGP_STREAM_DESCRIPTOR_SURFACE_EXTENSION_NAME "VK_GGP_stream_descriptor_surface" + #endif #if defined(VK_USE_PLATFORM_GGP) #define VK_GGP_STREAM_DESCRIPTOR_SURFACE_SPEC_VERSION 1 + #endif #define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string" #define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 1 @@ -385,12 +604,26 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1 #define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" #define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 1 +#define VK_GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" +#define VK_GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION 1 +#define VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME "VK_GOOGLE_surfaceless_query" +#define VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION 2 #define VK_GOOGLE_USER_TYPE_EXTENSION_NAME "VK_GOOGLE_user_type" #define VK_GOOGLE_USER_TYPE_SPEC_VERSION 1 +#define VK_HUAWEI_CLUSTER_CULLING_SHADER_EXTENSION_NAME "VK_HUAWEI_cluster_culling_shader" +#define VK_HUAWEI_CLUSTER_CULLING_SHADER_SPEC_VERSION 3 +#define VK_HUAWEI_HDR_VIVID_EXTENSION_NAME "VK_HUAWEI_hdr_vivid" +#define VK_HUAWEI_HDR_VIVID_SPEC_VERSION 1 +#define VK_HUAWEI_INVOCATION_MASK_EXTENSION_NAME "VK_HUAWEI_invocation_mask" +#define VK_HUAWEI_INVOCATION_MASK_SPEC_VERSION 1 +#define VK_HUAWEI_SUBPASS_SHADING_EXTENSION_NAME "VK_HUAWEI_subpass_shading" +#define VK_HUAWEI_SUBPASS_SHADING_SPEC_VERSION 3 #define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic" #define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 #define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" #define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 +#define VK_IMG_RELAXED_LINE_RASTERIZATION_EXTENSION_NAME "VK_IMG_relaxed_line_rasterization" +#define VK_IMG_RELAXED_LINE_RASTERIZATION_SPEC_VERSION 1 #define VK_INTEL_PERFORMANCE_QUERY_EXTENSION_NAME "VK_INTEL_performance_query" #define VK_INTEL_PERFORMANCE_QUERY_SPEC_VERSION 2 #define VK_INTEL_SHADER_INTEGER_FUNCTIONS_2_EXTENSION_NAME "VK_INTEL_shader_integer_functions2" @@ -399,26 +632,36 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1 #define VK_KHR_8BIT_STORAGE_EXTENSION_NAME "VK_KHR_8bit_storage" #define VK_KHR_8BIT_STORAGE_SPEC_VERSION 1 +#define VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_KHR_acceleration_structure" +#define VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION 13 #if defined(VK_USE_PLATFORM_ANDROID_KHR) #define VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "VK_KHR_android_surface" + #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) #define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 + #endif #define VK_KHR_BIND_MEMORY_2_EXTENSION_NAME "VK_KHR_bind_memory2" #define VK_KHR_BIND_MEMORY_2_SPEC_VERSION 1 #define VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_KHR_buffer_device_address" #define VK_KHR_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 1 +#define VK_KHR_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_KHR_calibrated_timestamps" +#define VK_KHR_CALIBRATED_TIMESTAMPS_SPEC_VERSION 1 +#define VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME "VK_KHR_compute_shader_derivatives" +#define VK_KHR_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION 1 +#define VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME "VK_KHR_cooperative_matrix" +#define VK_KHR_COOPERATIVE_MATRIX_SPEC_VERSION 2 +#define VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME "VK_KHR_copy_commands2" +#define VK_KHR_COPY_COMMANDS_2_SPEC_VERSION 1 #define VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME "VK_KHR_create_renderpass2" #define VK_KHR_CREATE_RENDERPASS_2_SPEC_VERSION 1 #define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation" #define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3 -#if defined(VK_ENABLE_BETA_EXTENSIONS) #define VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME "VK_KHR_deferred_host_operations" -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -#define VK_KHR_DEFERRED_HOST_OPERATIONS_SPEC_VERSION 3 -#endif +#define VK_KHR_DEFERRED_HOST_OPERATIONS_SPEC_VERSION 4 +#define VK_KHR_DEPTH_CLAMP_ZERO_ONE_EXTENSION_NAME "VK_KHR_depth_clamp_zero_one" +#define VK_KHR_DEPTH_CLAMP_ZERO_ONE_SPEC_VERSION 1 #define VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME "VK_KHR_depth_stencil_resolve" #define VK_KHR_DEPTH_STENCIL_RESOLVE_SPEC_VERSION 1 #define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template" @@ -435,6 +678,10 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 #define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties" #define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1 +#define VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME "VK_KHR_dynamic_rendering" +#define VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME "VK_KHR_dynamic_rendering_local_read" +#define VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_SPEC_VERSION 1 +#define VK_KHR_DYNAMIC_RENDERING_SPEC_VERSION 1 #define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities" #define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1 #define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence" @@ -443,9 +690,11 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME "VK_KHR_external_fence_win32" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION 1 + #endif #define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities" #define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 @@ -455,9 +704,11 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 + #endif #define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities" #define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1 @@ -467,10 +718,18 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHR_external_semaphore_win32" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1 + #endif +#define VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME "VK_KHR_format_feature_flags2" +#define VK_KHR_FORMAT_FEATURE_FLAGS_2_SPEC_VERSION 2 +#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_KHR_fragment_shader_barycentric" +#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 +#define VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME "VK_KHR_fragment_shading_rate" +#define VK_KHR_FRAGMENT_SHADING_RATE_SPEC_VERSION 2 #define VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_display_properties2" #define VK_KHR_GET_DISPLAY_PROPERTIES_2_SPEC_VERSION 1 #define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME "VK_KHR_get_memory_requirements2" @@ -479,40 +738,82 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 2 #define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2" #define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1 +#define VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME "VK_KHR_global_priority" +#define VK_KHR_GLOBAL_PRIORITY_SPEC_VERSION 1 #define VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME "VK_KHR_imageless_framebuffer" #define VK_KHR_IMAGELESS_FRAMEBUFFER_SPEC_VERSION 1 #define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list" #define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1 #define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present" -#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1 +#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 2 +#define VK_KHR_INDEX_TYPE_UINT8_EXTENSION_NAME "VK_KHR_index_type_uint8" +#define VK_KHR_INDEX_TYPE_UINT8_SPEC_VERSION 1 +#define VK_KHR_LINE_RASTERIZATION_EXTENSION_NAME "VK_KHR_line_rasterization" +#define VK_KHR_LINE_RASTERIZATION_SPEC_VERSION 1 +#define VK_KHR_LOAD_STORE_OP_NONE_EXTENSION_NAME "VK_KHR_load_store_op_none" +#define VK_KHR_LOAD_STORE_OP_NONE_SPEC_VERSION 1 #define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1" #define VK_KHR_MAINTENANCE1_SPEC_VERSION 2 #define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2" #define VK_KHR_MAINTENANCE2_SPEC_VERSION 1 #define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3" #define VK_KHR_MAINTENANCE3_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_maintenance1" +#define VK_KHR_MAINTENANCE_1_SPEC_VERSION 2 +#define VK_KHR_MAINTENANCE_2_EXTENSION_NAME "VK_KHR_maintenance2" +#define VK_KHR_MAINTENANCE_2_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_3_EXTENSION_NAME "VK_KHR_maintenance3" +#define VK_KHR_MAINTENANCE_3_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_4_EXTENSION_NAME "VK_KHR_maintenance4" +#define VK_KHR_MAINTENANCE_4_SPEC_VERSION 2 +#define VK_KHR_MAINTENANCE_5_EXTENSION_NAME "VK_KHR_maintenance5" +#define VK_KHR_MAINTENANCE_5_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_6_EXTENSION_NAME "VK_KHR_maintenance6" +#define VK_KHR_MAINTENANCE_6_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_7_EXTENSION_NAME "VK_KHR_maintenance7" +#define VK_KHR_MAINTENANCE_7_SPEC_VERSION 1 +#define VK_KHR_MAINTENANCE_8_EXTENSION_NAME "VK_KHR_maintenance8" +#define VK_KHR_MAINTENANCE_8_SPEC_VERSION 1 +#define VK_KHR_MAP_MEMORY_2_EXTENSION_NAME "VK_KHR_map_memory2" +#define VK_KHR_MAP_MEMORY_2_SPEC_VERSION 1 #define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview" #define VK_KHR_MULTIVIEW_SPEC_VERSION 1 #define VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME "VK_KHR_performance_query" #define VK_KHR_PERFORMANCE_QUERY_SPEC_VERSION 1 +#define VK_KHR_PIPELINE_BINARY_EXTENSION_NAME "VK_KHR_pipeline_binary" +#define VK_KHR_PIPELINE_BINARY_SPEC_VERSION 1 #define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME "VK_KHR_pipeline_executable_properties" #define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_SPEC_VERSION 1 -#if defined(VK_ENABLE_BETA_EXTENSIONS) #define VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME "VK_KHR_pipeline_library" -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) #define VK_KHR_PIPELINE_LIBRARY_SPEC_VERSION 1 -#endif -#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor" -#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2 +#define VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME "VK_KHR_portability_enumeration" +#define VK_KHR_PORTABILITY_ENUMERATION_SPEC_VERSION 1 #if defined(VK_ENABLE_BETA_EXTENSIONS) -#define VK_KHR_RAY_TRACING_EXTENSION_NAME "VK_KHR_ray_tracing" +#define VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME "VK_KHR_portability_subset" + #endif #if defined(VK_ENABLE_BETA_EXTENSIONS) -#define VK_KHR_RAY_TRACING_SPEC_VERSION 8 +#define VK_KHR_PORTABILITY_SUBSET_SPEC_VERSION 1 + #endif +#define VK_KHR_PRESENT_ID_EXTENSION_NAME "VK_KHR_present_id" +#define VK_KHR_PRESENT_ID_SPEC_VERSION 1 +#define VK_KHR_PRESENT_WAIT_EXTENSION_NAME "VK_KHR_present_wait" +#define VK_KHR_PRESENT_WAIT_SPEC_VERSION 1 +#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor" +#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2 +#define VK_KHR_RAY_QUERY_EXTENSION_NAME "VK_KHR_ray_query" +#define VK_KHR_RAY_QUERY_SPEC_VERSION 1 +#define VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_ray_tracing_maintenance1" +#define VK_KHR_RAY_TRACING_MAINTENANCE_1_SPEC_VERSION 1 +#define VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME "VK_KHR_ray_tracing_pipeline" +#define VK_KHR_RAY_TRACING_PIPELINE_SPEC_VERSION 1 +#define VK_KHR_RAY_TRACING_POSITION_FETCH_EXTENSION_NAME "VK_KHR_ray_tracing_position_fetch" +#define VK_KHR_RAY_TRACING_POSITION_FETCH_SPEC_VERSION 1 #define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout" #define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1 +#define VK_KHR_ROBUSTNESS_2_EXTENSION_NAME "VK_KHR_robustness2" +#define VK_KHR_ROBUSTNESS_2_SPEC_VERSION 1 #define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" #define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 3 #define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion" @@ -521,18 +822,38 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_SPEC_VERSION 1 #define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64" #define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1 +#define VK_KHR_SHADER_BFLOAT16_EXTENSION_NAME "VK_KHR_shader_bfloat16" +#define VK_KHR_SHADER_BFLOAT16_SPEC_VERSION 1 #define VK_KHR_SHADER_CLOCK_EXTENSION_NAME "VK_KHR_shader_clock" #define VK_KHR_SHADER_CLOCK_SPEC_VERSION 1 #define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters" #define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1 +#define VK_KHR_SHADER_EXPECT_ASSUME_EXTENSION_NAME "VK_KHR_shader_expect_assume" +#define VK_KHR_SHADER_EXPECT_ASSUME_SPEC_VERSION 1 #define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME "VK_KHR_shader_float16_int8" #define VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION 1 +#define VK_KHR_SHADER_FLOAT_CONTROLS_2_EXTENSION_NAME "VK_KHR_shader_float_controls2" +#define VK_KHR_SHADER_FLOAT_CONTROLS_2_SPEC_VERSION 1 #define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME "VK_KHR_shader_float_controls" #define VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION 4 +#define VK_KHR_SHADER_INTEGER_DOT_PRODUCT_EXTENSION_NAME "VK_KHR_shader_integer_dot_product" +#define VK_KHR_SHADER_INTEGER_DOT_PRODUCT_SPEC_VERSION 1 +#define VK_KHR_SHADER_MAXIMAL_RECONVERGENCE_EXTENSION_NAME "VK_KHR_shader_maximal_reconvergence" +#define VK_KHR_SHADER_MAXIMAL_RECONVERGENCE_SPEC_VERSION 1 #define VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME "VK_KHR_shader_non_semantic_info" #define VK_KHR_SHADER_NON_SEMANTIC_INFO_SPEC_VERSION 1 +#define VK_KHR_SHADER_QUAD_CONTROL_EXTENSION_NAME "VK_KHR_shader_quad_control" +#define VK_KHR_SHADER_QUAD_CONTROL_SPEC_VERSION 1 +#define VK_KHR_SHADER_RELAXED_EXTENDED_INSTRUCTION_EXTENSION_NAME "VK_KHR_shader_relaxed_extended_instruction" +#define VK_KHR_SHADER_RELAXED_EXTENDED_INSTRUCTION_SPEC_VERSION 1 #define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME "VK_KHR_shader_subgroup_extended_types" #define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_SPEC_VERSION 1 +#define VK_KHR_SHADER_SUBGROUP_ROTATE_EXTENSION_NAME "VK_KHR_shader_subgroup_rotate" +#define VK_KHR_SHADER_SUBGROUP_ROTATE_SPEC_VERSION 2 +#define VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_EXTENSION_NAME "VK_KHR_shader_subgroup_uniform_control_flow" +#define VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_SPEC_VERSION 1 +#define VK_KHR_SHADER_TERMINATE_INVOCATION_EXTENSION_NAME "VK_KHR_shader_terminate_invocation" +#define VK_KHR_SHADER_TERMINATE_INVOCATION_SPEC_VERSION 1 #define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image" #define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1 #define VK_KHR_SPIRV_1_4_EXTENSION_NAME "VK_KHR_spirv_1_4" @@ -547,47 +868,67 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME "VK_KHR_swapchain_mutable_format" #define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION 1 #define VK_KHR_SWAPCHAIN_SPEC_VERSION 70 +#define VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME "VK_KHR_synchronization2" +#define VK_KHR_SYNCHRONIZATION_2_SPEC_VERSION 1 #define VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME "VK_KHR_timeline_semaphore" #define VK_KHR_TIMELINE_SEMAPHORE_SPEC_VERSION 2 #define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME "VK_KHR_uniform_buffer_standard_layout" #define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_SPEC_VERSION 1 #define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers" #define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1 +#define VK_KHR_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_KHR_vertex_attribute_divisor" +#define VK_KHR_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 1 #define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model" #define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 3 #if defined(VK_USE_PLATFORM_WAYLAND_KHR) #define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface" + #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) #define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6 + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHR_win32_keyed_mutex" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION 1 + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6 + #endif +#define VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME "VK_KHR_workgroup_memory_explicit_layout" +#define VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_XCB_KHR) #define VK_KHR_XCB_SURFACE_EXTENSION_NAME "VK_KHR_xcb_surface" + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) #define VK_KHR_XCB_SURFACE_SPEC_VERSION 6 + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) #define VK_KHR_XLIB_SURFACE_EXTENSION_NAME "VK_KHR_xlib_surface" + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) #define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6 + #endif -#define VK_LOD_CLAMP_NONE 1000.0f +#define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_EXTENSION_NAME "VK_KHR_zero_initialize_workgroup_memory" +#define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_SPEC_VERSION 1 +#define VK_LOD_CLAMP_NONE 1000.0F #define VK_LUID_SIZE 8 #define VK_LUID_SIZE_KHR 8 +#define VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME "VK_LUNARG_direct_driver_loading" +#define VK_LUNARG_DIRECT_DRIVER_LOADING_SPEC_VERSION 1 #define VK_MAX_DESCRIPTION_SIZE 256 #define VK_MAX_DEVICE_GROUP_SIZE 32 #define VK_MAX_DEVICE_GROUP_SIZE_KHR 32 @@ -596,60 +937,125 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_MAX_DRIVER_NAME_SIZE 256 #define VK_MAX_DRIVER_NAME_SIZE_KHR 256 #define VK_MAX_EXTENSION_NAME_SIZE 256 +#define VK_MAX_GLOBAL_PRIORITY_SIZE 16 +#define VK_MAX_GLOBAL_PRIORITY_SIZE_EXT 16 +#define VK_MAX_GLOBAL_PRIORITY_SIZE_KHR 16 #define VK_MAX_MEMORY_HEAPS 16 #define VK_MAX_MEMORY_TYPES 32 #define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 +#define VK_MAX_PIPELINE_BINARY_KEY_SIZE_KHR 32 +#define VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT 32 +#define VK_MESA_IMAGE_ALIGNMENT_CONTROL_EXTENSION_NAME "VK_MESA_image_alignment_control" +#define VK_MESA_IMAGE_ALIGNMENT_CONTROL_SPEC_VERSION 1 +#define VK_MSFT_LAYERED_DRIVER_EXTENSION_NAME "VK_MSFT_layered_driver" +#define VK_MSFT_LAYERED_DRIVER_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_IOS_MVK) #define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface" + #endif #if defined(VK_USE_PLATFORM_IOS_MVK) #define VK_MVK_IOS_SURFACE_SPEC_VERSION 3 + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) #define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface" + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) #define VK_MVK_MACOS_SURFACE_SPEC_VERSION 3 + #endif #if defined(VK_USE_PLATFORM_VI_NN) #define VK_NN_VI_SURFACE_EXTENSION_NAME "VK_NN_vi_surface" + #endif #if defined(VK_USE_PLATFORM_VI_NN) #define VK_NN_VI_SURFACE_SPEC_VERSION 1 + #endif +#define VK_NVX_BINARY_IMPORT_EXTENSION_NAME "VK_NVX_binary_import" +#define VK_NVX_BINARY_IMPORT_SPEC_VERSION 2 #define VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME "VK_NVX_image_view_handle" -#define VK_NVX_IMAGE_VIEW_HANDLE_SPEC_VERSION 2 +#define VK_NVX_IMAGE_VIEW_HANDLE_SPEC_VERSION 3 #define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME "VK_NVX_multiview_per_view_attributes" #define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1 +#if defined(VK_USE_PLATFORM_WIN32_KHR) +#define VK_NV_ACQUIRE_WINRT_DISPLAY_EXTENSION_NAME "VK_NV_acquire_winrt_display" + +#endif +#if defined(VK_USE_PLATFORM_WIN32_KHR) +#define VK_NV_ACQUIRE_WINRT_DISPLAY_SPEC_VERSION 1 + +#endif #define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling" #define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1 +#define VK_NV_CLUSTER_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_NV_cluster_acceleration_structure" +#define VK_NV_CLUSTER_ACCELERATION_STRUCTURE_SPEC_VERSION 2 +#define VK_NV_COMMAND_BUFFER_INHERITANCE_EXTENSION_NAME "VK_NV_command_buffer_inheritance" +#define VK_NV_COMMAND_BUFFER_INHERITANCE_SPEC_VERSION 1 #define VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME "VK_NV_compute_shader_derivatives" #define VK_NV_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION 1 +#define VK_NV_COOPERATIVE_MATRIX_2_EXTENSION_NAME "VK_NV_cooperative_matrix2" +#define VK_NV_COOPERATIVE_MATRIX_2_SPEC_VERSION 1 #define VK_NV_COOPERATIVE_MATRIX_EXTENSION_NAME "VK_NV_cooperative_matrix" #define VK_NV_COOPERATIVE_MATRIX_SPEC_VERSION 1 +#define VK_NV_COOPERATIVE_VECTOR_EXTENSION_NAME "VK_NV_cooperative_vector" +#define VK_NV_COOPERATIVE_VECTOR_SPEC_VERSION 4 +#define VK_NV_COPY_MEMORY_INDIRECT_EXTENSION_NAME "VK_NV_copy_memory_indirect" +#define VK_NV_COPY_MEMORY_INDIRECT_SPEC_VERSION 1 #define VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME "VK_NV_corner_sampled_image" #define VK_NV_CORNER_SAMPLED_IMAGE_SPEC_VERSION 2 #define VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME "VK_NV_coverage_reduction_mode" #define VK_NV_COVERAGE_REDUCTION_MODE_SPEC_VERSION 1 +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_CUDA_KERNEL_LAUNCH_EXTENSION_NAME "VK_NV_cuda_kernel_launch" + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_CUDA_KERNEL_LAUNCH_SPEC_VERSION 2 + +#endif #define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation" #define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_EXTENSION_NAME "VK_NV_dedicated_allocation_image_aliasing" #define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_SPEC_VERSION 1 #define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1 +#define VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_EXTENSION_NAME "VK_NV_descriptor_pool_overallocation" +#define VK_NV_DESCRIPTOR_POOL_OVERALLOCATION_SPEC_VERSION 1 #define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME "VK_NV_device_diagnostics_config" -#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION 1 +#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION 2 #define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints" #define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2 +#define VK_NV_DEVICE_GENERATED_COMMANDS_COMPUTE_EXTENSION_NAME "VK_NV_device_generated_commands_compute" +#define VK_NV_DEVICE_GENERATED_COMMANDS_COMPUTE_SPEC_VERSION 2 #define VK_NV_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NV_device_generated_commands" #define VK_NV_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3 +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_DISPLACEMENT_MICROMAP_EXTENSION_NAME "VK_NV_displacement_micromap" + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_DISPLACEMENT_MICROMAP_SPEC_VERSION 2 + +#endif +#define VK_NV_DISPLAY_STEREO_EXTENSION_NAME "VK_NV_display_stereo" +#define VK_NV_DISPLAY_STEREO_SPEC_VERSION 1 +#define VK_NV_EXTENDED_SPARSE_ADDRESS_SPACE_EXTENSION_NAME "VK_NV_extended_sparse_address_space" +#define VK_NV_EXTENDED_SPARSE_ADDRESS_SPACE_SPEC_VERSION 1 +#define VK_NV_EXTERNAL_COMPUTE_QUEUE_EXTENSION_NAME "VK_NV_external_compute_queue" +#define VK_NV_EXTERNAL_COMPUTE_QUEUE_SPEC_VERSION 1 #define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities" #define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 #define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory" +#define VK_NV_EXTERNAL_MEMORY_RDMA_EXTENSION_NAME "VK_NV_external_memory_rdma" +#define VK_NV_EXTERNAL_MEMORY_RDMA_SPEC_VERSION 1 #define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 + #endif #define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle" #define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1 @@ -657,22 +1063,62 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1 #define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_NV_fragment_shader_barycentric" #define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 +#define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_EXTENSION_NAME "VK_NV_fragment_shading_rate_enums" +#define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_SPEC_VERSION 1 #define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples" #define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1 #define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough" #define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1 #define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader" #define VK_NV_GLSL_SHADER_SPEC_VERSION 1 +#define VK_NV_INHERITED_VIEWPORT_SCISSOR_EXTENSION_NAME "VK_NV_inherited_viewport_scissor" +#define VK_NV_INHERITED_VIEWPORT_SCISSOR_SPEC_VERSION 1 +#define VK_NV_LINEAR_COLOR_ATTACHMENT_EXTENSION_NAME "VK_NV_linear_color_attachment" +#define VK_NV_LINEAR_COLOR_ATTACHMENT_SPEC_VERSION 1 +#define VK_NV_LOW_LATENCY_2_EXTENSION_NAME "VK_NV_low_latency2" +#define VK_NV_LOW_LATENCY_2_SPEC_VERSION 2 +#define VK_NV_LOW_LATENCY_EXTENSION_NAME "VK_NV_low_latency" +#define VK_NV_LOW_LATENCY_SPEC_VERSION 1 +#define VK_NV_MEMORY_DECOMPRESSION_EXTENSION_NAME "VK_NV_memory_decompression" +#define VK_NV_MEMORY_DECOMPRESSION_SPEC_VERSION 1 #define VK_NV_MESH_SHADER_EXTENSION_NAME "VK_NV_mesh_shader" #define VK_NV_MESH_SHADER_SPEC_VERSION 1 +#define VK_NV_OPTICAL_FLOW_EXTENSION_NAME "VK_NV_optical_flow" +#define VK_NV_OPTICAL_FLOW_SPEC_VERSION 1 +#define VK_NV_PARTITIONED_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_NV_partitioned_acceleration_structure" +#define VK_NV_PARTITIONED_ACCELERATION_STRUCTURE_SPEC_VERSION 1 +#define VK_NV_PER_STAGE_DESCRIPTOR_SET_EXTENSION_NAME "VK_NV_per_stage_descriptor_set" +#define VK_NV_PER_STAGE_DESCRIPTOR_SET_SPEC_VERSION 1 +#define VK_NV_PRESENT_BARRIER_EXTENSION_NAME "VK_NV_present_barrier" +#define VK_NV_PRESENT_BARRIER_SPEC_VERSION 1 +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_PRESENT_METERING_EXTENSION_NAME "VK_NV_present_metering" + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_PRESENT_METERING_SPEC_VERSION 1 + +#endif +#define VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME "VK_NV_raw_access_chains" +#define VK_NV_RAW_ACCESS_CHAINS_SPEC_VERSION 1 #define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing" +#define VK_NV_RAY_TRACING_INVOCATION_REORDER_EXTENSION_NAME "VK_NV_ray_tracing_invocation_reorder" +#define VK_NV_RAY_TRACING_INVOCATION_REORDER_SPEC_VERSION 1 +#define VK_NV_RAY_TRACING_LINEAR_SWEPT_SPHERES_EXTENSION_NAME "VK_NV_ray_tracing_linear_swept_spheres" +#define VK_NV_RAY_TRACING_LINEAR_SWEPT_SPHERES_SPEC_VERSION 1 +#define VK_NV_RAY_TRACING_MOTION_BLUR_EXTENSION_NAME "VK_NV_ray_tracing_motion_blur" +#define VK_NV_RAY_TRACING_MOTION_BLUR_SPEC_VERSION 1 #define VK_NV_RAY_TRACING_SPEC_VERSION 3 +#define VK_NV_RAY_TRACING_VALIDATION_EXTENSION_NAME "VK_NV_ray_tracing_validation" +#define VK_NV_RAY_TRACING_VALIDATION_SPEC_VERSION 1 #define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME "VK_NV_representative_fragment_test" #define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 2 #define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage" #define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1 #define VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME "VK_NV_scissor_exclusive" -#define VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION 1 +#define VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION 2 +#define VK_NV_SHADER_ATOMIC_FLOAT16_VECTOR_EXTENSION_NAME "VK_NV_shader_atomic_float16_vector" +#define VK_NV_SHADER_ATOMIC_FLOAT16_VECTOR_SPEC_VERSION 1 #define VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME "VK_NV_shader_image_footprint" #define VK_NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION 2 #define VK_NV_SHADER_SM_BUILTINS_EXTENSION_NAME "VK_NV_shader_sm_builtins" @@ -683,162 +1129,281 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define VK_NV_SHADING_RATE_IMAGE_SPEC_VERSION 3 #define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME "VK_NV_viewport_array2" #define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION 1 +#define VK_NV_VIEWPORT_ARRAY_2_EXTENSION_NAME "VK_NV_viewport_array2" +#define VK_NV_VIEWPORT_ARRAY_2_SPEC_VERSION 1 #define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle" #define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1 #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex" + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 2 + #endif +#define VK_PARTITIONED_ACCELERATION_STRUCTURE_PARTITION_INDEX_GLOBAL_NV (~0U) +#define VK_QCOM_FILTER_CUBIC_CLAMP_EXTENSION_NAME "VK_QCOM_filter_cubic_clamp" +#define VK_QCOM_FILTER_CUBIC_CLAMP_SPEC_VERSION 1 +#define VK_QCOM_FILTER_CUBIC_WEIGHTS_EXTENSION_NAME "VK_QCOM_filter_cubic_weights" +#define VK_QCOM_FILTER_CUBIC_WEIGHTS_SPEC_VERSION 1 +#define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME "VK_QCOM_fragment_density_map_offset" +#define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_SPEC_VERSION 3 +#define VK_QCOM_IMAGE_PROCESSING_2_EXTENSION_NAME "VK_QCOM_image_processing2" +#define VK_QCOM_IMAGE_PROCESSING_2_SPEC_VERSION 1 +#define VK_QCOM_IMAGE_PROCESSING_EXTENSION_NAME "VK_QCOM_image_processing" +#define VK_QCOM_IMAGE_PROCESSING_SPEC_VERSION 1 +#define VK_QCOM_MULTIVIEW_PER_VIEW_RENDER_AREAS_EXTENSION_NAME "VK_QCOM_multiview_per_view_render_areas" +#define VK_QCOM_MULTIVIEW_PER_VIEW_RENDER_AREAS_SPEC_VERSION 1 +#define VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_EXTENSION_NAME "VK_QCOM_multiview_per_view_viewports" +#define VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_SPEC_VERSION 1 #define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_EXTENSION_NAME "VK_QCOM_render_pass_shader_resolve" #define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_SPEC_VERSION 4 +#define VK_QCOM_RENDER_PASS_STORE_OPS_EXTENSION_NAME "VK_QCOM_render_pass_store_ops" +#define VK_QCOM_RENDER_PASS_STORE_OPS_SPEC_VERSION 2 #define VK_QCOM_RENDER_PASS_TRANSFORM_EXTENSION_NAME "VK_QCOM_render_pass_transform" -#define VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION 1 -#define VK_QCOM_render_pass_store_ops_EXTENSION_NAME "VK_QCOM_render_pass_store_ops" -#define VK_QCOM_render_pass_store_ops_SPEC_VERSION 2 -#define VK_QUEUE_FAMILY_EXTERNAL (~0U-1) -#define VK_QUEUE_FAMILY_EXTERNAL_KHR (~0U-1) -#define VK_QUEUE_FAMILY_FOREIGN_EXT (~0U-2) +#define VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION 4 +#define VK_QCOM_ROTATED_COPY_COMMANDS_EXTENSION_NAME "VK_QCOM_rotated_copy_commands" +#define VK_QCOM_ROTATED_COPY_COMMANDS_SPEC_VERSION 2 +#define VK_QCOM_TILE_MEMORY_HEAP_EXTENSION_NAME "VK_QCOM_tile_memory_heap" +#define VK_QCOM_TILE_MEMORY_HEAP_SPEC_VERSION 1 +#define VK_QCOM_TILE_PROPERTIES_EXTENSION_NAME "VK_QCOM_tile_properties" +#define VK_QCOM_TILE_PROPERTIES_SPEC_VERSION 1 +#define VK_QCOM_TILE_SHADING_EXTENSION_NAME "VK_QCOM_tile_shading" +#define VK_QCOM_TILE_SHADING_SPEC_VERSION 1 +#define VK_QCOM_YCBCR_DEGAMMA_EXTENSION_NAME "VK_QCOM_ycbcr_degamma" +#define VK_QCOM_YCBCR_DEGAMMA_SPEC_VERSION 1 +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +#define VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_EXTENSION_NAME "VK_QNX_external_memory_screen_buffer" + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +#define VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_SPEC_VERSION 1 + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +#define VK_QNX_SCREEN_SURFACE_EXTENSION_NAME "VK_QNX_screen_surface" + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +#define VK_QNX_SCREEN_SURFACE_SPEC_VERSION 1 + +#endif +#define VK_QUEUE_FAMILY_EXTERNAL (~1U) +#define VK_QUEUE_FAMILY_EXTERNAL_KHR (~1U) +#define VK_QUEUE_FAMILY_FOREIGN_EXT (~2U) #define VK_QUEUE_FAMILY_IGNORED (~0U) +#define VK_REMAINING_3D_SLICES_EXT (~0U) #define VK_REMAINING_ARRAY_LAYERS (~0U) #define VK_REMAINING_MIP_LEVELS (~0U) +#define VK_SEC_AMIGO_PROFILING_EXTENSION_NAME "VK_SEC_amigo_profiling" +#define VK_SEC_AMIGO_PROFILING_SPEC_VERSION 1 +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_SHADER_INDEX_UNUSED_AMDX (~0U) + +#endif #define VK_SHADER_UNUSED_KHR (~0U) #define VK_SHADER_UNUSED_NV (~0U) #define VK_SUBPASS_EXTERNAL (~0U) #define VK_TRUE 1 #define VK_UUID_SIZE 16 +#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_EXTENSION_NAME "VK_VALVE_descriptor_set_host_mapping" +#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_SPEC_VERSION 1 +#define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_VALVE_mutable_descriptor_type" +#define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1 #define VK_WHOLE_SIZE (~0ULL) #include "vk_platform.h" - #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) || defined(VK_USE_PLATFORM_XLIB_KHR) +#include #endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) +#include #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) +#include #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) +#include #endif #if defined(VK_USE_PLATFORM_XCB_KHR) +#include #endif #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) +#include #endif -#if defined(VK_USE_PLATFORM_FUCHSIA) +#if defined(VK_USE_PLATFORM_FUCHSIA) || defined(VK_USE_PLATFORM_FUCHSIA) || defined(VK_USE_PLATFORM_FUCHSIA) || defined(VK_USE_PLATFORM_FUCHSIA) +#include #endif #if defined(VK_USE_PLATFORM_GGP) || defined(VK_USE_PLATFORM_GGP) +#include +#endif + +#if defined(VK_USE_PLATFORM_SCREEN_QNX) || defined(VK_USE_PLATFORM_SCREEN_QNX) +#include #endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) || defined(VK_USE_PLATFORM_XLIB_KHR) + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) + #endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) + #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) + #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) + #endif #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) + #endif #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) + #endif -#if defined(VK_USE_PLATFORM_FUCHSIA) +#if defined(VK_USE_PLATFORM_FUCHSIA) || defined(VK_USE_PLATFORM_FUCHSIA) || defined(VK_USE_PLATFORM_FUCHSIA) || defined(VK_USE_PLATFORM_FUCHSIA) + #endif #if defined(VK_USE_PLATFORM_GGP) + #endif #if defined(VK_USE_PLATFORM_GGP) + #endif -#define VK_MAKE_VERSION(major, minor, patch) \ - ((((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch))) +#if defined(VK_USE_PLATFORM_SCREEN_QNX) -#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) +#endif -#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) +#if defined(VK_USE_PLATFORM_SCREEN_QNX) -#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) +#endif -/* DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. */ -/*#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) // Patch version should always be set to 0 */ +#if defined(VK_USE_PLATFORM_SCREEN_QNX) -/* Vulkan 1.0 version number */ -#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)/* Patch version should always be set to 0 */ +#endif +/* DEPRECATED: This define is deprecated. VK_MAKE_API_VERSION should be used instead. */ +#define VK_MAKE_VERSION(major, minor, patch) \ + ((((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch))) +/* DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead. */ +#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22U) +/* DEPRECATED: This define is deprecated. VK_API_VERSION_MINOR should be used instead. */ +#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12U) & 0x3FFU) +/* DEPRECATED: This define is deprecated. VK_API_VERSION_PATCH should be used instead. */ +#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) +#define VK_MAKE_API_VERSION(variant, major, minor, patch) \ + ((((uint32_t)(variant)) << 29U) | (((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch))) +#define VK_API_VERSION_VARIANT(version) ((uint32_t)(version) >> 29U) +#define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22U) & 0x7FU) +#define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12U) & 0x3FFU) +#define VK_API_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) +/* DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. */ +/*#define VK_API_VERSION VK_MAKE_API_VERSION(0, 1, 0, 0) // Patch version should always be set to 0 */ +/* Vulkan 1.0 version number */ +#define VK_API_VERSION_1_0 VK_MAKE_API_VERSION(0, 1, 0, 0)/* Patch version should always be set to 0 */ /* Vulkan 1.1 version number */ -#define VK_API_VERSION_1_1 VK_MAKE_VERSION(1, 1, 0)/* Patch version should always be set to 0 */ - +#define VK_API_VERSION_1_1 VK_MAKE_API_VERSION(0, 1, 1, 0)/* Patch version should always be set to 0 */ /* Vulkan 1.2 version number */ -#define VK_API_VERSION_1_2 VK_MAKE_VERSION(1, 2, 0)/* Patch version should always be set to 0 */ - +#define VK_API_VERSION_1_2 VK_MAKE_API_VERSION(0, 1, 2, 0)/* Patch version should always be set to 0 */ +/* Vulkan 1.3 version number */ +#define VK_API_VERSION_1_3 VK_MAKE_API_VERSION(0, 1, 3, 0)/* Patch version should always be set to 0 */ +/* Vulkan 1.4 version number */ +#define VK_API_VERSION_1_4 VK_MAKE_API_VERSION(0, 1, 4, 0)/* Patch version should always be set to 0 */ /* Version of this file */ -#define VK_HEADER_VERSION 152 - -/* Complete version of this file */ -#define VK_HEADER_VERSION_COMPLETE VK_MAKE_VERSION(1, 2, VK_HEADER_VERSION) - +#define VK_HEADER_VERSION 314 #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; - -#if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE) -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#ifndef VK_USE_64_BIT_PTR_DEFINES + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) || (defined(__riscv) && __riscv_xlen == 64) + #define VK_USE_64_BIT_PTR_DEFINES 1 + #else + #define VK_USE_64_BIT_PTR_DEFINES 0 + #endif +#endif +#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + #if (VK_USE_64_BIT_PTR_DEFINES==1) + #if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)) + #define VK_NULL_HANDLE nullptr + #else + #define VK_NULL_HANDLE ((void*)0) + #endif + #else + #define VK_NULL_HANDLE 0ULL + #endif +#endif +#ifndef VK_NULL_HANDLE + #define VK_NULL_HANDLE 0 +#endif +#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + #if (VK_USE_64_BIT_PTR_DEFINES==1) #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; -#else + #else #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; + #endif #endif -#endif - -#define VK_NULL_HANDLE 0 - #if defined(VK_USE_PLATFORM_ANDROID_KHR) struct ANativeWindow; #endif @@ -855,6 +1420,54 @@ typedef void CAMetalLayer; #endif #endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +#ifdef __OBJC__ +@protocol MTLDevice; +typedef __unsafe_unretained id MTLDevice_id; +#else +typedef void* MTLDevice_id; +#endif +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +#ifdef __OBJC__ +@protocol MTLCommandQueue; +typedef __unsafe_unretained id MTLCommandQueue_id; +#else +typedef void* MTLCommandQueue_id; +#endif +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +#ifdef __OBJC__ +@protocol MTLBuffer; +typedef __unsafe_unretained id MTLBuffer_id; +#else +typedef void* MTLBuffer_id; +#endif +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +#ifdef __OBJC__ +@protocol MTLTexture; +typedef __unsafe_unretained id MTLTexture_id; +#else +typedef void* MTLTexture_id; +#endif +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +#ifdef __OBJC__ +@protocol MTLSharedEvent; +typedef __unsafe_unretained id MTLSharedEvent_id; +#else +typedef void* MTLSharedEvent_id; +#endif +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct __IOSurface* IOSurfaceRef; +#endif @@ -867,104 +1480,80 @@ typedef void CAMetalLayer; -VK_DEFINE_HANDLE(VkInstance) +VK_DEFINE_HANDLE(VkInstance) VK_DEFINE_HANDLE(VkPhysicalDevice) - VK_DEFINE_HANDLE(VkDevice) - VK_DEFINE_HANDLE(VkQueue) - VK_DEFINE_HANDLE(VkCommandBuffer) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) - +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineBinaryKHR) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNV) - +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutEXT) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectExecutionSetEXT) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate) - #define VkDescriptorUpdateTemplateKHR VkDescriptorUpdateTemplate - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion) - #define VkSamplerYcbcrConversionKHR VkSamplerYcbcrConversion - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureKHR) - -#define VkAccelerationStructureNV VkAccelerationStructureKHR - +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPerformanceConfigurationINTEL) - -#if defined(VK_ENABLE_BETA_EXTENSIONS) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeferredOperationKHR) +#if defined(VK_USE_PLATFORM_FUCHSIA) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferCollectionFUCHSIA) #endif -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPrivateDataSlotEXT) - +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeferredOperationKHR) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPrivateDataSlot) +#define VkPrivateDataSlotEXT VkPrivateDataSlot +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCuModuleNVX) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCuFunctionNVX) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkOpticalFlowSessionNV) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkMicromapEXT) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderEXT) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT) - typedef enum VkAttachmentLoadOp { VK_ATTACHMENT_LOAD_OP_LOAD = 0, VK_ATTACHMENT_LOAD_OP_CLEAR = 1, - VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2 + VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, + VK_ATTACHMENT_LOAD_OP_NONE = 1000400000, + VK_ATTACHMENT_LOAD_OP_NONE_EXT = VK_ATTACHMENT_LOAD_OP_NONE, + VK_ATTACHMENT_LOAD_OP_NONE_KHR = VK_ATTACHMENT_LOAD_OP_NONE, + VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7FFFFFFF } VkAttachmentLoadOp; - typedef enum VkAttachmentStoreOp { VK_ATTACHMENT_STORE_OP_STORE = 0, VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, - VK_ATTACHMENT_STORE_OP_NONE_QCOM = 1000301000 + VK_ATTACHMENT_STORE_OP_NONE = 1000301000, + VK_ATTACHMENT_STORE_OP_NONE_KHR = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_NONE_QCOM = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_NONE_EXT = VK_ATTACHMENT_STORE_OP_NONE, + VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7FFFFFFF } VkAttachmentStoreOp; - typedef enum VkBlendFactor { VK_BLEND_FACTOR_ZERO = 0, VK_BLEND_FACTOR_ONE = 1, @@ -984,9 +1573,9 @@ typedef enum VkBlendFactor { VK_BLEND_FACTOR_SRC1_COLOR = 15, VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16, VK_BLEND_FACTOR_SRC1_ALPHA = 17, - VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18 + VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18, + VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF } VkBlendFactor; - typedef enum VkBlendOp { VK_BLEND_OP_ADD = 0, VK_BLEND_OP_SUBTRACT = 1, @@ -1038,9 +1627,9 @@ typedef enum VkBlendOp { VK_BLEND_OP_INVERT_OVG_EXT = 1000148042, VK_BLEND_OP_RED_EXT = 1000148043, VK_BLEND_OP_GREEN_EXT = 1000148044, - VK_BLEND_OP_BLUE_EXT = 1000148045 + VK_BLEND_OP_BLUE_EXT = 1000148045, + VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF } VkBlendOp; - typedef enum VkBorderColor { VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0, VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1, @@ -1049,46 +1638,64 @@ typedef enum VkBorderColor { VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4, VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5, VK_BORDER_COLOR_FLOAT_CUSTOM_EXT = 1000287003, - VK_BORDER_COLOR_INT_CUSTOM_EXT = 1000287004 + VK_BORDER_COLOR_INT_CUSTOM_EXT = 1000287004, + VK_BORDER_COLOR_MAX_ENUM = 0x7FFFFFFF } VkBorderColor; - typedef enum VkFramebufferCreateFlagBits { VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT = 1, - VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT + VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, + VK_FRAMEBUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFramebufferCreateFlagBits; - typedef enum VkRenderPassCreateFlagBits { - VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM = 2 + VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM = 2, + VK_RENDER_PASS_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkRenderPassCreateFlagBits; - typedef enum VkSamplerCreateFlagBits { VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT = 1, - VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT = 2 + VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT = 2, + VK_SAMPLER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 8, + VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT = 4, + VK_SAMPLER_CREATE_IMAGE_PROCESSING_BIT_QCOM = 16, + VK_SAMPLER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSamplerCreateFlagBits; - typedef enum VkPipelineCacheHeaderVersion { - VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1 + VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, + VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF } VkPipelineCacheHeaderVersion; - typedef enum VkPipelineCacheCreateFlagBits { - VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT = 1 + VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 1, + VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT = VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT, + VK_PIPELINE_CACHE_CREATE_INTERNALLY_SYNCHRONIZED_MERGE_BIT_KHR = 8, + VK_PIPELINE_CACHE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineCacheCreateFlagBits; - typedef enum VkPipelineShaderStageCreateFlagBits { - VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = 1, - VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = 2 + VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT = 1, + VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT = 2, + VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT, + VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT, + VK_PIPELINE_SHADER_STAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineShaderStageCreateFlagBits; - typedef enum VkDescriptorSetLayoutCreateFlagBits { VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT = 2, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 1, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT = 1, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT = 16, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_EMBEDDED_IMMUTABLE_SAMPLERS_BIT_EXT = 32, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE = 4, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_INDIRECT_BINDABLE_BIT_NV = 128, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT = 4, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PER_STAGE_BIT_NV = 64, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDescriptorSetLayoutCreateFlagBits; - +typedef enum VkInstanceCreateFlagBits { + VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR = 1, + VK_INSTANCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkInstanceCreateFlagBits; typedef enum VkDeviceQueueCreateFlagBits { - VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 1 + VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 1, + VK_DEVICE_QUEUE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDeviceQueueCreateFlagBits; - typedef enum VkBufferCreateFlagBits { VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 1, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 2, @@ -1096,9 +1703,10 @@ typedef enum VkBufferCreateFlagBits { VK_BUFFER_CREATE_PROTECTED_BIT = 8, VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 16, VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, - VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT + VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_BUFFER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 32, + VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferCreateFlagBits; - typedef enum VkBufferUsageFlagBits { VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 1, VK_BUFFER_USAGE_TRANSFER_DST_BIT = 2, @@ -1113,19 +1721,28 @@ typedef enum VkBufferUsageFlagBits { VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 2048, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 4096, VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 512, - VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR = 1024, - VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = VK_BUFFER_USAGE_RAY_TRACING_BIT_KHR, + VK_BUFFER_USAGE_EXECUTION_GRAPH_SCRATCH_BIT_AMDX = 33554432, + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR = 524288, + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR = 1048576, + VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR = 1024, + VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT = 2097152, + VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT = 4194304, + VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT = 67108864, + VK_BUFFER_USAGE_MICROMAP_BUILD_INPUT_READ_ONLY_BIT_EXT = 8388608, + VK_BUFFER_USAGE_MICROMAP_STORAGE_BIT_EXT = 16777216, + VK_BUFFER_USAGE_TILE_MEMORY_QCOM = 134217728, + VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferUsageFlagBits; - typedef enum VkColorComponentFlagBits { VK_COLOR_COMPONENT_R_BIT = 1, VK_COLOR_COMPONENT_G_BIT = 2, VK_COLOR_COMPONENT_B_BIT = 4, - VK_COLOR_COMPONENT_A_BIT = 8 + VK_COLOR_COMPONENT_A_BIT = 8, + VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkColorComponentFlagBits; - typedef enum VkComponentSwizzle { VK_COMPONENT_SWIZZLE_IDENTITY = 0, VK_COMPONENT_SWIZZLE_ZERO = 1, @@ -1133,34 +1750,34 @@ typedef enum VkComponentSwizzle { VK_COMPONENT_SWIZZLE_R = 3, VK_COMPONENT_SWIZZLE_G = 4, VK_COMPONENT_SWIZZLE_B = 5, - VK_COMPONENT_SWIZZLE_A = 6 + VK_COMPONENT_SWIZZLE_A = 6, + VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7FFFFFFF } VkComponentSwizzle; - typedef enum VkCommandPoolCreateFlagBits { VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 1, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 2, - VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 4 + VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 4, + VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandPoolCreateFlagBits; - typedef enum VkCommandPoolResetFlagBits { - VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 1 + VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 1, + VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandPoolResetFlagBits; - typedef enum VkCommandBufferResetFlagBits { - VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 1 + VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 1, + VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandBufferResetFlagBits; - typedef enum VkCommandBufferLevel { VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, - VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1 + VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1, + VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7FFFFFFF } VkCommandBufferLevel; - typedef enum VkCommandBufferUsageFlagBits { VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 1, VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 2, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 4 + VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 4, + VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCommandBufferUsageFlagBits; - typedef enum VkCompareOp { VK_COMPARE_OP_NEVER = 0, VK_COMPARE_OP_LESS = 1, @@ -1169,16 +1786,16 @@ typedef enum VkCompareOp { VK_COMPARE_OP_GREATER = 4, VK_COMPARE_OP_NOT_EQUAL = 5, VK_COMPARE_OP_GREATER_OR_EQUAL = 6, - VK_COMPARE_OP_ALWAYS = 7 + VK_COMPARE_OP_ALWAYS = 7, + VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF } VkCompareOp; - typedef enum VkCullModeFlagBits { VK_CULL_MODE_NONE = 0, VK_CULL_MODE_FRONT_BIT = 1, VK_CULL_MODE_BACK_BIT = 2, - VK_CULL_MODE_FRONT_AND_BACK = 0x00000003 + VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, + VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkCullModeFlagBits; - typedef enum VkDescriptorType { VK_DESCRIPTOR_TYPE_SAMPLER = 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1, @@ -1191,11 +1808,17 @@ typedef enum VkDescriptorType { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, - VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000, - VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR = 1000165000, - VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR + VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK = 1000138000, + VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000, + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, + VK_DESCRIPTOR_TYPE_MUTABLE_VALVE = 1000351000, + VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM = 1000440000, + VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM = 1000440001, + VK_DESCRIPTOR_TYPE_MUTABLE_EXT = 1000351000, + VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV = 1000570000, + VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF } VkDescriptorType; - typedef enum VkDynamicState { VK_DYNAMIC_STATE_VIEWPORT = 0, VK_DYNAMIC_STATE_SCISSOR = 1, @@ -1206,38 +1829,100 @@ typedef enum VkDynamicState { VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7, VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8, + VK_DYNAMIC_STATE_CULL_MODE = 1000267000, + VK_DYNAMIC_STATE_FRONT_FACE = 1000267001, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY = 1000267002, + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT = 1000267003, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT = 1000267004, + VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE = 1000267005, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE = 1000267006, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE = 1000267007, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP = 1000267008, + VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE = 1000267009, + VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE = 1000267010, + VK_DYNAMIC_STATE_STENCIL_OP = 1000267011, + VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE = 1000377001, + VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE = 1000377002, + VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE = 1000377004, + VK_DYNAMIC_STATE_LINE_STIPPLE = 1000259000, VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000, VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000, + VK_DYNAMIC_STATE_DISCARD_RECTANGLE_ENABLE_EXT = 1000099001, + VK_DYNAMIC_STATE_DISCARD_RECTANGLE_MODE_EXT = 1000099002, VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000, + VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR = 1000347000, VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV = 1000164004, VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV = 1000164006, + VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_ENABLE_NV = 1000205000, VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV = 1000205001, - VK_DYNAMIC_STATE_LINE_STIPPLE_EXT = 1000259000, - VK_DYNAMIC_STATE_CULL_MODE_EXT = 1000267000, - VK_DYNAMIC_STATE_FRONT_FACE_EXT = 1000267001, - VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT = 1000267002, - VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT = 1000267003, - VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT = 1000267004, - VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT = 1000267005, - VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT = 1000267006, - VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT = 1000267007, - VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT = 1000267008, - VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT = 1000267009, - VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT = 1000267010, - VK_DYNAMIC_STATE_STENCIL_OP_EXT = 1000267011 + VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR = 1000226000, + VK_DYNAMIC_STATE_LINE_STIPPLE_EXT = VK_DYNAMIC_STATE_LINE_STIPPLE, + VK_DYNAMIC_STATE_CULL_MODE_EXT = VK_DYNAMIC_STATE_CULL_MODE, + VK_DYNAMIC_STATE_FRONT_FACE_EXT = VK_DYNAMIC_STATE_FRONT_FACE, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT = VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY, + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT = VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT = VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT, + VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT = VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT = VK_DYNAMIC_STATE_DEPTH_COMPARE_OP, + VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE, + VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE, + VK_DYNAMIC_STATE_STENCIL_OP_EXT = VK_DYNAMIC_STATE_STENCIL_OP, + VK_DYNAMIC_STATE_VERTEX_INPUT_EXT = 1000352000, + VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT = 1000377000, + VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT = VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE, + VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE, + VK_DYNAMIC_STATE_LOGIC_OP_EXT = 1000377003, + VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT = VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE, + VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT = 1000381000, + VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT = 1000455003, + VK_DYNAMIC_STATE_POLYGON_MODE_EXT = 1000455004, + VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT = 1000455005, + VK_DYNAMIC_STATE_SAMPLE_MASK_EXT = 1000455006, + VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT = 1000455007, + VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT = 1000455008, + VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT = 1000455009, + VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT = 1000455010, + VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT = 1000455011, + VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT = 1000455012, + VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT = 1000455002, + VK_DYNAMIC_STATE_RASTERIZATION_STREAM_EXT = 1000455013, + VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT = 1000455014, + VK_DYNAMIC_STATE_EXTRA_PRIMITIVE_OVERESTIMATION_SIZE_EXT = 1000455015, + VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT = 1000455016, + VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_ENABLE_EXT = 1000455017, + VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT = 1000455018, + VK_DYNAMIC_STATE_PROVOKING_VERTEX_MODE_EXT = 1000455019, + VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT = 1000455020, + VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT = 1000455021, + VK_DYNAMIC_STATE_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT = 1000455022, + VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_ENABLE_NV = 1000455023, + VK_DYNAMIC_STATE_VIEWPORT_SWIZZLE_NV = 1000455024, + VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_ENABLE_NV = 1000455025, + VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_LOCATION_NV = 1000455026, + VK_DYNAMIC_STATE_COVERAGE_MODULATION_MODE_NV = 1000455027, + VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_ENABLE_NV = 1000455028, + VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_NV = 1000455029, + VK_DYNAMIC_STATE_SHADING_RATE_IMAGE_ENABLE_NV = 1000455030, + VK_DYNAMIC_STATE_REPRESENTATIVE_FRAGMENT_TEST_ENABLE_NV = 1000455031, + VK_DYNAMIC_STATE_COVERAGE_REDUCTION_MODE_NV = 1000455032, + VK_DYNAMIC_STATE_ATTACHMENT_FEEDBACK_LOOP_ENABLE_EXT = 1000524000, + VK_DYNAMIC_STATE_LINE_STIPPLE_KHR = VK_DYNAMIC_STATE_LINE_STIPPLE, + VK_DYNAMIC_STATE_DEPTH_CLAMP_RANGE_EXT = 1000582000, + VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF } VkDynamicState; - typedef enum VkFenceCreateFlagBits { - VK_FENCE_CREATE_SIGNALED_BIT = 1 + VK_FENCE_CREATE_SIGNALED_BIT = 1, + VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFenceCreateFlagBits; - typedef enum VkPolygonMode { VK_POLYGON_MODE_FILL = 0, VK_POLYGON_MODE_LINE = 1, VK_POLYGON_MODE_POINT = 2, - VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000 + VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000, + VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF } VkPolygonMode; - typedef enum VkFormat { VK_FORMAT_UNDEFINED = 0, VK_FORMAT_R4G4_UNORM_PACK8 = 1, @@ -1458,6 +2143,28 @@ typedef enum VkFormat { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033, + VK_FORMAT_G8_B8R8_2PLANE_444_UNORM = 1000330000, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 = 1000330001, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 = 1000330002, + VK_FORMAT_G16_B16R16_2PLANE_444_UNORM = 1000330003, + VK_FORMAT_A4R4G4B4_UNORM_PACK16 = 1000340000, + VK_FORMAT_A4B4G4R4_UNORM_PACK16 = 1000340001, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK = 1000066000, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK = 1000066001, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK = 1000066002, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK = 1000066003, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK = 1000066004, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK = 1000066005, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK = 1000066006, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK = 1000066007, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK = 1000066008, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK = 1000066009, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK = 1000066010, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK = 1000066011, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK = 1000066012, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK = 1000066013, + VK_FORMAT_A1B5G5R5_UNORM_PACK16 = 1000470000, + VK_FORMAT_A8_UNORM = 1000470001, VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, @@ -1466,20 +2173,20 @@ typedef enum VkFormat { VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, - VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = 1000066000, - VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = 1000066001, - VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = 1000066002, - VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = 1000066003, - VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = 1000066004, - VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = 1000066005, - VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = 1000066006, - VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = 1000066007, - VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = 1000066008, - VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = 1000066009, - VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = 1000066010, - VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = 1000066011, - VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = 1000066012, - VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = 1000066013, + VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK, + VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK, + VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK, + VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK, + VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK, + VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK, VK_FORMAT_G8B8G8R8_422_UNORM_KHR = VK_FORMAT_G8B8G8R8_422_UNORM, VK_FORMAT_B8G8R8G8_422_UNORM_KHR = VK_FORMAT_B8G8R8G8_422_UNORM, VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, @@ -1514,10 +2221,18 @@ typedef enum VkFormat { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, - VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = 1000340000, - VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = 1000340001 + VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, + VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16, + VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16, + VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT = VK_FORMAT_G16_B16R16_2PLANE_444_UNORM, + VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = VK_FORMAT_A4R4G4B4_UNORM_PACK16, + VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = VK_FORMAT_A4B4G4R4_UNORM_PACK16, + VK_FORMAT_R16G16_SFIXED5_NV = 1000464000, + VK_FORMAT_R16G16_S10_5_NV = VK_FORMAT_R16G16_SFIXED5_NV, + VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR = VK_FORMAT_A1B5G5R5_UNORM_PACK16, + VK_FORMAT_A8_UNORM_KHR = VK_FORMAT_A8_UNORM, + VK_FORMAT_MAX_ENUM = 0x7FFFFFFF } VkFormat; - typedef enum VkFormatFeatureFlagBits { VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 1, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 2, @@ -1554,15 +2269,20 @@ typedef enum VkFormatFeatureFlagBits { VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT, VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = VK_FORMAT_FEATURE_DISJOINT_BIT, VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG, - VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT = 16777216 + VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 8192, + VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT = 16777216, + VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 1073741824, + VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFormatFeatureFlagBits; - typedef enum VkFrontFace { VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, - VK_FRONT_FACE_CLOCKWISE = 1 + VK_FRONT_FACE_CLOCKWISE = 1, + VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF } VkFrontFace; - +typedef enum VkMemoryMapFlagBits { + VK_MEMORY_MAP_PLACED_BIT_EXT = 1, + VK_MEMORY_MAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryMapFlagBits; typedef enum VkImageAspectFlagBits { VK_IMAGE_ASPECT_COLOR_BIT = 1, VK_IMAGE_ASPECT_DEPTH_BIT = 2, @@ -1571,15 +2291,17 @@ typedef enum VkImageAspectFlagBits { VK_IMAGE_ASPECT_PLANE_0_BIT = 16, VK_IMAGE_ASPECT_PLANE_1_BIT = 32, VK_IMAGE_ASPECT_PLANE_2_BIT = 64, + VK_IMAGE_ASPECT_NONE = 0, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT, VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 128, VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 256, VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 512, - VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 1024 + VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 1024, + VK_IMAGE_ASPECT_NONE_KHR = VK_IMAGE_ASPECT_NONE, + VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageAspectFlagBits; - typedef enum VkImageCreateFlagBits { VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 1, VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 2, @@ -1601,9 +2323,14 @@ typedef enum VkImageCreateFlagBits { VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 4096, VK_IMAGE_CREATE_DISJOINT_BIT_KHR = VK_IMAGE_CREATE_DISJOINT_BIT, VK_IMAGE_CREATE_ALIAS_BIT_KHR = VK_IMAGE_CREATE_ALIAS_BIT, - VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 16384 + VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 16384, + VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 65536, + VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT = 262144, + VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT = 131072, + VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_QCOM = 32768, + VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_EXT = 32768, + VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageCreateFlagBits; - typedef enum VkImageLayout { VK_IMAGE_LAYOUT_UNDEFINED = 0, VK_IMAGE_LAYOUT_GENERAL = 1, @@ -1620,30 +2347,38 @@ typedef enum VkImageLayout { VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL = 1000241001, VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL = 1000241002, VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL = 1000241003, + VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL = 1000314000, + VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL = 1000314001, + VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ = 1000232000, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV = 1000164003, VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT = 1000218000, + VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR = 1000164003, + VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR = VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL + VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT = 1000339000, + VK_IMAGE_LAYOUT_MAX_ENUM = 0x7FFFFFFF } VkImageLayout; - typedef enum VkImageTiling { VK_IMAGE_TILING_OPTIMAL = 0, VK_IMAGE_TILING_LINEAR = 1, - VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000 + VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000, + VK_IMAGE_TILING_MAX_ENUM = 0x7FFFFFFF } VkImageTiling; - typedef enum VkImageType { VK_IMAGE_TYPE_1D = 0, VK_IMAGE_TYPE_2D = 1, - VK_IMAGE_TYPE_3D = 2 + VK_IMAGE_TYPE_3D = 2, + VK_IMAGE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkImageType; - typedef enum VkImageUsageFlagBits { VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 1, VK_IMAGE_USAGE_TRANSFER_DST_BIT = 2, @@ -1653,15 +2388,24 @@ typedef enum VkImageUsageFlagBits { VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 32, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 64, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 128, + VK_IMAGE_USAGE_HOST_TRANSFER_BIT = 4194304, VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV = 256, - VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 512 + VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 512, + VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 256, + VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT = VK_IMAGE_USAGE_HOST_TRANSFER_BIT, + VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 524288, + VK_IMAGE_USAGE_INVOCATION_MASK_BIT_HUAWEI = 262144, + VK_IMAGE_USAGE_SAMPLE_WEIGHT_BIT_QCOM = 1048576, + VK_IMAGE_USAGE_SAMPLE_BLOCK_MATCH_BIT_QCOM = 2097152, + VK_IMAGE_USAGE_TILE_MEMORY_QCOM = 134217728, + VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageUsageFlagBits; - typedef enum VkImageViewCreateFlagBits { VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT = 1, - VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT = 2 + VK_IMAGE_VIEW_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 4, + VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT = 2, + VK_IMAGE_VIEW_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkImageViewCreateFlagBits; - typedef enum VkImageViewType { VK_IMAGE_VIEW_TYPE_1D = 0, VK_IMAGE_VIEW_TYPE_2D = 1, @@ -1669,22 +2413,42 @@ typedef enum VkImageViewType { VK_IMAGE_VIEW_TYPE_CUBE = 3, VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4, VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5, - VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6 + VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6, + VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7FFFFFFF } VkImageViewType; - +typedef enum VkIndirectCommandsTokenTypeEXT { + VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT = 0, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT = 1, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_SEQUENCE_INDEX_EXT = 2, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_EXT = 3, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_EXT = 4, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_EXT = 5, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT = 6, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_COUNT_EXT = 7, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_COUNT_EXT = 8, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_EXT = 9, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV_EXT = 1000202002, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_NV_EXT = 1000202003, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_EXT = 1000328000, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_EXT = 1000328001, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_TRACE_RAYS2_EXT = 1000386004, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkIndirectCommandsTokenTypeEXT; typedef enum VkSharingMode { VK_SHARING_MODE_EXCLUSIVE = 0, - VK_SHARING_MODE_CONCURRENT = 1 + VK_SHARING_MODE_CONCURRENT = 1, + VK_SHARING_MODE_MAX_ENUM = 0x7FFFFFFF } VkSharingMode; - typedef enum VkIndexType { VK_INDEX_TYPE_UINT16 = 0, VK_INDEX_TYPE_UINT32 = 1, + VK_INDEX_TYPE_UINT8 = 1000265000, VK_INDEX_TYPE_NONE_KHR = 1000165000, VK_INDEX_TYPE_NONE_NV = VK_INDEX_TYPE_NONE_KHR, - VK_INDEX_TYPE_UINT8_EXT = 1000265000 + VK_INDEX_TYPE_UINT8_EXT = VK_INDEX_TYPE_UINT8, + VK_INDEX_TYPE_UINT8_KHR = VK_INDEX_TYPE_UINT8, + VK_INDEX_TYPE_MAX_ENUM = 0x7FFFFFFF } VkIndexType; - typedef enum VkLogicOp { VK_LOGIC_OP_CLEAR = 0, VK_LOGIC_OP_AND = 1, @@ -1701,15 +2465,16 @@ typedef enum VkLogicOp { VK_LOGIC_OP_COPY_INVERTED = 12, VK_LOGIC_OP_OR_INVERTED = 13, VK_LOGIC_OP_NAND = 14, - VK_LOGIC_OP_SET = 15 + VK_LOGIC_OP_SET = 15, + VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF } VkLogicOp; - typedef enum VkMemoryHeapFlagBits { VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 1, VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 2, - VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT + VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT, + VK_MEMORY_HEAP_TILE_MEMORY_BIT_QCOM = 8, + VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkMemoryHeapFlagBits; - typedef enum VkAccessFlagBits { VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 1, VK_ACCESS_INDEX_READ_BIT = 2, @@ -1728,6 +2493,7 @@ typedef enum VkAccessFlagBits { VK_ACCESS_HOST_WRITE_BIT = 16384, VK_ACCESS_MEMORY_READ_BIT = 32768, VK_ACCESS_MEMORY_WRITE_BIT = 65536, + VK_ACCESS_NONE = 0, VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 33554432, VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 67108864, VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 134217728, @@ -1739,10 +2505,14 @@ typedef enum VkAccessFlagBits { VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 16777216, + VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 8388608, VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV = 131072, - VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV = 262144 + VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV = 262144, + VK_ACCESS_NONE_KHR = VK_ACCESS_NONE, + VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_EXT = 131072, + VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_EXT = 262144, + VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkAccessFlagBits; - typedef enum VkMemoryPropertyFlagBits { VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 1, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 2, @@ -1751,24 +2521,27 @@ typedef enum VkMemoryPropertyFlagBits { VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 16, VK_MEMORY_PROPERTY_PROTECTED_BIT = 32, VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD = 64, - VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD = 128 + VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD = 128, + VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV = 256, + VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkMemoryPropertyFlagBits; - typedef enum VkPhysicalDeviceType { VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, - VK_PHYSICAL_DEVICE_TYPE_CPU = 4 + VK_PHYSICAL_DEVICE_TYPE_CPU = 4, + VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkPhysicalDeviceType; - typedef enum VkPipelineBindPoint { VK_PIPELINE_BIND_POINT_GRAPHICS = 0, VK_PIPELINE_BIND_POINT_COMPUTE = 1, + VK_PIPELINE_BIND_POINT_EXECUTION_GRAPH_AMDX = 1000134000, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR = 1000165000, - VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR + VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, + VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI = 1000369003, + VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7FFFFFFF } VkPipelineBindPoint; - typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 1, VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 2, @@ -1776,6 +2549,10 @@ typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 8, VK_PIPELINE_CREATE_DISPATCH_BASE_BIT = 16, VK_PIPELINE_CREATE_DISPATCH_BASE = VK_PIPELINE_CREATE_DISPATCH_BASE_BIT, + VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT = 256, + VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT = 512, + VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT = 134217728, + VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT = 1073741824, VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT, VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE, VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR = 16384, @@ -1784,15 +2561,30 @@ typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR = 131072, VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR = 4096, VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR = 8192, + VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR = 524288, VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 32, + VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 4194304, + VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT, + VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 2097152, + VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR = 64, VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR = 128, VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV = 262144, VK_PIPELINE_CREATE_LIBRARY_BIT_KHR = 2048, - VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT = 256, - VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT = 512 + VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT = VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT, + VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT = VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT, + VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT = 536870912, + VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT = 8388608, + VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT = 1024, + VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV = 1048576, + VK_PIPELINE_CREATE_COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 33554432, + VK_PIPELINE_CREATE_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 67108864, + VK_PIPELINE_CREATE_RAY_TRACING_OPACITY_MICROMAP_BIT_EXT = 16777216, + VK_PIPELINE_CREATE_RAY_TRACING_DISPLACEMENT_MICROMAP_BIT_NV = 268435456, + VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT_EXT = VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT, + VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT_EXT = VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT, + VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineCreateFlagBits; - typedef enum VkPrimitiveTopology { VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0, VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1, @@ -1804,13 +2596,13 @@ typedef enum VkPrimitiveTopology { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9, - VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10 + VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10, + VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF } VkPrimitiveTopology; - typedef enum VkQueryControlFlagBits { - VK_QUERY_CONTROL_PRECISE_BIT = 1 + VK_QUERY_CONTROL_PRECISE_BIT = 1, + VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueryControlFlagBits; - typedef enum VkQueryPipelineStatisticFlagBits { VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 1, VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 2, @@ -1822,41 +2614,53 @@ typedef enum VkQueryPipelineStatisticFlagBits { VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 128, VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 256, VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 512, - VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 1024 + VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 1024, + VK_QUERY_PIPELINE_STATISTIC_TASK_SHADER_INVOCATIONS_BIT_EXT = 2048, + VK_QUERY_PIPELINE_STATISTIC_MESH_SHADER_INVOCATIONS_BIT_EXT = 4096, + VK_QUERY_PIPELINE_STATISTIC_CLUSTER_CULLING_SHADER_INVOCATIONS_BIT_HUAWEI = 8192, + VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueryPipelineStatisticFlagBits; - typedef enum VkQueryResultFlagBits { VK_QUERY_RESULT_64_BIT = 1, VK_QUERY_RESULT_WAIT_BIT = 2, VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 4, - VK_QUERY_RESULT_PARTIAL_BIT = 8 + VK_QUERY_RESULT_PARTIAL_BIT = 8, + VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueryResultFlagBits; - typedef enum VkQueryType { VK_QUERY_TYPE_OCCLUSION = 0, VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, VK_QUERY_TYPE_TIMESTAMP = 2, VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004, VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR = 1000116000, - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR = 1000165000, - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR = 1000150000, - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR, - VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL = 1000210000 + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR = 1000150000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR = 1000150001, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, + VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL = 1000210000, + VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT = 1000328000, + VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT = 1000382000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR = 1000386000, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR = 1000386001, + VK_QUERY_TYPE_MICROMAP_SERIALIZATION_SIZE_EXT = 1000396000, + VK_QUERY_TYPE_MICROMAP_COMPACTED_SIZE_EXT = 1000396001, + VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF } VkQueryType; - typedef enum VkQueueFlagBits { VK_QUEUE_GRAPHICS_BIT = 1, VK_QUEUE_COMPUTE_BIT = 2, VK_QUEUE_TRANSFER_BIT = 4, VK_QUEUE_SPARSE_BINDING_BIT = 8, - VK_QUEUE_PROTECTED_BIT = 16 + VK_QUEUE_PROTECTED_BIT = 16, + VK_QUEUE_OPTICAL_FLOW_BIT_NV = 256, + VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkQueueFlagBits; - typedef enum VkSubpassContents { VK_SUBPASS_CONTENTS_INLINE = 0, - VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1 + VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, + VK_SUBPASS_CONTENTS_INLINE_AND_SECONDARY_COMMAND_BUFFERS_EXT = 1000451000, + VK_SUBPASS_CONTENTS_INLINE_AND_SECONDARY_COMMAND_BUFFERS_KHR = 1000451000, + VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7FFFFFFF } VkSubpassContents; - typedef enum VkResult { VK_SUCCESS = 0, VK_NOT_READY = 1, @@ -1881,6 +2685,8 @@ typedef enum VkResult { VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003, VK_ERROR_FRAGMENTATION = -1000161000, VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS = -1000257000, + VK_PIPELINE_COMPILE_REQUIRED = 1000297000, + VK_ERROR_NOT_PERMITTED = -1000174001, VK_ERROR_SURFACE_LOST_KHR = -1000000000, VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, VK_SUBOPTIMAL_KHR = 1000001003, @@ -1890,10 +2696,10 @@ typedef enum VkResult { VK_ERROR_INVALID_SHADER_NV = -1000012000, VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY, VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE, - VK_ERROR_INCOMPATIBLE_VERSION_KHR = -1000150000, VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000, VK_ERROR_FRAGMENTATION_EXT = VK_ERROR_FRAGMENTATION, - VK_ERROR_NOT_PERMITTED_EXT = -1000174001, + VK_ERROR_NOT_PERMITTED_EXT = VK_ERROR_NOT_PERMITTED, + VK_ERROR_NOT_PERMITTED_KHR = VK_ERROR_NOT_PERMITTED, VK_ERROR_INVALID_DEVICE_ADDRESS_EXT = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT = -1000255000, VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, @@ -1901,10 +2707,15 @@ typedef enum VkResult { VK_THREAD_DONE_KHR = 1000268001, VK_OPERATION_DEFERRED_KHR = 1000268002, VK_OPERATION_NOT_DEFERRED_KHR = 1000268003, - VK_PIPELINE_COMPILE_REQUIRED_EXT = 1000297000, - VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED_EXT + VK_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, + VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, + VK_ERROR_COMPRESSION_EXHAUSTED_EXT = -1000338000, + VK_INCOMPATIBLE_SHADER_BINARY_EXT = 1000482000, + VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT = VK_INCOMPATIBLE_SHADER_BINARY_EXT, + VK_PIPELINE_BINARY_MISSING_KHR = 1000483000, + VK_ERROR_NOT_ENOUGH_SPACE_KHR = -1000483000, + VK_RESULT_MAX_ENUM = 0x7FFFFFFF } VkResult; - typedef enum VkShaderStageFlagBits { VK_SHADER_STAGE_VERTEX_BIT = 1, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 2, @@ -1927,20 +2738,24 @@ typedef enum VkShaderStageFlagBits { VK_SHADER_STAGE_INTERSECTION_BIT_NV = VK_SHADER_STAGE_INTERSECTION_BIT_KHR, VK_SHADER_STAGE_CALLABLE_BIT_NV = VK_SHADER_STAGE_CALLABLE_BIT_KHR, VK_SHADER_STAGE_TASK_BIT_NV = 64, - VK_SHADER_STAGE_MESH_BIT_NV = 128 + VK_SHADER_STAGE_MESH_BIT_NV = 128, + VK_SHADER_STAGE_TASK_BIT_EXT = 64, + VK_SHADER_STAGE_MESH_BIT_EXT = 128, + VK_SHADER_STAGE_SUBPASS_SHADING_BIT_HUAWEI = 16384, + VK_SHADER_STAGE_CLUSTER_CULLING_BIT_HUAWEI = 524288, + VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkShaderStageFlagBits; - typedef enum VkSparseMemoryBindFlagBits { - VK_SPARSE_MEMORY_BIND_METADATA_BIT = 1 + VK_SPARSE_MEMORY_BIND_METADATA_BIT = 1, + VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSparseMemoryBindFlagBits; - typedef enum VkStencilFaceFlagBits { VK_STENCIL_FACE_FRONT_BIT = 1, VK_STENCIL_FACE_BACK_BIT = 2, VK_STENCIL_FACE_FRONT_AND_BACK = 0x00000003, - VK_STENCIL_FRONT_AND_BACK = VK_STENCIL_FACE_FRONT_AND_BACK + VK_STENCIL_FRONT_AND_BACK = VK_STENCIL_FACE_FRONT_AND_BACK, + VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkStencilFaceFlagBits; - typedef enum VkStencilOp { VK_STENCIL_OP_KEEP = 0, VK_STENCIL_OP_ZERO = 1, @@ -1949,9 +2764,9 @@ typedef enum VkStencilOp { VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4, VK_STENCIL_OP_INVERT = 5, VK_STENCIL_OP_INCREMENT_AND_WRAP = 6, - VK_STENCIL_OP_DECREMENT_AND_WRAP = 7 + VK_STENCIL_OP_DECREMENT_AND_WRAP = 7, + VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF } VkStencilOp; - typedef enum VkStructureType { VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, @@ -2119,6 +2934,108 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO = 1000257002, VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO = 1000257003, VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO = 1000257004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES = 53, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES = 54, + VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO = 1000192000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES = 1000215000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES = 1000245000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES = 1000276000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES = 1000295000, + VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO = 1000295001, + VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO = 1000295002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES = 1000297000, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_2 = 1000314000, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 = 1000314001, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 = 1000314002, + VK_STRUCTURE_TYPE_DEPENDENCY_INFO = 1000314003, + VK_STRUCTURE_TYPE_SUBMIT_INFO_2 = 1000314004, + VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO = 1000314005, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO = 1000314006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES = 1000314007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES = 1000325000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES = 1000335000, + VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2 = 1000337000, + VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2 = 1000337001, + VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2 = 1000337002, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2 = 1000337003, + VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2 = 1000337004, + VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2 = 1000337005, + VK_STRUCTURE_TYPE_BUFFER_COPY_2 = 1000337006, + VK_STRUCTURE_TYPE_IMAGE_COPY_2 = 1000337007, + VK_STRUCTURE_TYPE_IMAGE_BLIT_2 = 1000337008, + VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2 = 1000337009, + VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2 = 1000337010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES = 1000225000, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO = 1000225001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES = 1000225002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES = 1000138000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES = 1000138001, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK = 1000138002, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO = 1000138003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES = 1000066000, + VK_STRUCTURE_TYPE_RENDERING_INFO = 1000044000, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO = 1000044001, + VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO = 1000044002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES = 1000044003, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO = 1000044004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES = 1000280000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES = 1000280001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES = 1000281001, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3 = 1000360000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES = 1000413000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES = 1000413001, + VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS = 1000413002, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS = 1000413003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES = 55, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_PROPERTIES = 56, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO = 1000174000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES = 1000388000, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES = 1000388001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES = 1000416000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT_CONTROLS_2_FEATURES = 1000528000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES = 1000544000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES = 1000259000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO = 1000259001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES = 1000259002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES = 1000525000, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO = 1000190001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES = 1000190002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES = 1000265000, + VK_STRUCTURE_TYPE_MEMORY_MAP_INFO = 1000271000, + VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO = 1000271001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES = 1000470000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES = 1000470001, + VK_STRUCTURE_TYPE_RENDERING_AREA_INFO = 1000470003, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_SUBRESOURCE_INFO = 1000470004, + VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2 = 1000338002, + VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2 = 1000338003, + VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO = 1000470005, + VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO = 1000470006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES = 1000080000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES = 1000232000, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO = 1000232001, + VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO = 1000232002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_FEATURES = 1000545000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES = 1000545001, + VK_STRUCTURE_TYPE_BIND_MEMORY_STATUS = 1000545002, + VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_SETS_INFO = 1000545003, + VK_STRUCTURE_TYPE_PUSH_CONSTANTS_INFO = 1000545004, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_INFO = 1000545005, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE_INFO = 1000545006, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES = 1000466000, + VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO = 1000068000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES = 1000068001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES = 1000068002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES = 1000270000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES = 1000270001, + VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY = 1000270002, + VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY = 1000270003, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO = 1000270004, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO = 1000270005, + VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO = 1000270006, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_IMAGE_INFO = 1000270007, + VK_STRUCTURE_TYPE_SUBRESOURCE_HOST_MEMCPY_SIZE = 1000270008, + VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY = 1000270009, VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, @@ -2147,9 +3064,18 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, + VK_STRUCTURE_TYPE_CU_MODULE_CREATE_INFO_NVX = 1000029000, + VK_STRUCTURE_TYPE_CU_FUNCTION_CREATE_INFO_NVX = 1000029001, + VK_STRUCTURE_TYPE_CU_LAUNCH_INFO_NVX = 1000029002, + VK_STRUCTURE_TYPE_CU_MODULE_TEXTURING_MODE_CREATE_INFO_NVX = 1000029004, VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX = 1000030000, VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX = 1000030001, VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, + VK_STRUCTURE_TYPE_RENDERING_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_INFO, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO, VK_STRUCTURE_TYPE_STREAM_DESCRIPTOR_SURFACE_CREATE_INFO_GGP = 1000049000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, @@ -2178,9 +3104,12 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO, VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT = 1000066000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES, VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001, + VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES, VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, @@ -2208,7 +3137,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR = 1000078003, VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000, VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES, VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001, VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002, @@ -2226,6 +3155,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003, VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000, + VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX = 1000044009, VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000, VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001, @@ -2245,6 +3175,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO, VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_END_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RELAXED_LINE_RASTERIZATION_FEATURES_IMG = 1000110000, VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, @@ -2261,6 +3192,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_ACQUIRE_PROFILING_LOCK_INFO_KHR = 1000116004, VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_KHR = 1000116005, VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_DESCRIPTION_KHR = 1000116006, + VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_RESERVATION_INFO_KHR = 1000116007, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES, VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO, VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, @@ -2290,12 +3222,20 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003, VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004, VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID = 1000129005, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_2_ANDROID = 1000129006, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES, VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = 1000138000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = 1000138001, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = 1000138002, - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = 1000138003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ENQUEUE_FEATURES_AMDX = 1000134000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ENQUEUE_PROPERTIES_AMDX = 1000134001, + VK_STRUCTURE_TYPE_EXECUTION_GRAPH_PIPELINE_SCRATCH_SIZE_AMDX = 1000134002, + VK_STRUCTURE_TYPE_EXECUTION_GRAPH_PIPELINE_CREATE_INFO_AMDX = 1000134003, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_NODE_CREATE_INFO_AMDX = 1000134004, + VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD = 1000044008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK, + VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_BFLOAT16_FEATURES_KHR = 1000141000, VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000, VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001, VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, @@ -2311,27 +3251,29 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001, VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, - VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR = 1000165006, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR = 1000165007, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR = 1000150007, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR = 1000150000, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_GEOMETRY_TYPE_INFO_KHR = 1000150001, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR = 1000150002, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR = 1000150003, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR = 1000150004, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR = 1000150005, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR = 1000150006, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_KHR = 1000150008, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_VERSION_KHR = 1000150009, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_VERSION_INFO_KHR = 1000150009, VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR = 1000150010, VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR = 1000150011, VK_STRUCTURE_TYPE_COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR = 1000150012, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_FEATURES_KHR = 1000150013, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_KHR = 1000150014, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR = 1000150013, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR = 1000150014, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR = 1000150017, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR = 1000150020, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR = 1000347000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR = 1000347001, VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR = 1000150015, VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR = 1000150016, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR = 1000150017, VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR = 1000150018, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR = 1000348013, VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, + VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_NV = VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV = 1000154000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV = 1000154001, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, @@ -2343,11 +3285,11 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO, VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000, - VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002, VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003, VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004, VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT = 1000158006, VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, @@ -2355,6 +3297,8 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR = 1000163000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR = 1000163001, VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV = 1000164000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, @@ -2364,8 +3308,8 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003, VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004, VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005, - VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_KHR, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR, + VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, @@ -2376,7 +3320,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT = 1000170000, VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT = 1000170001, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, @@ -2387,12 +3331,15 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD = 1000183000, VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES, VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES, VK_STRUCTURE_TYPE_PRESENT_FRAME_TOKEN_GGP = 1000191000, - VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = 1000192000, + VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES, @@ -2406,6 +3353,8 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV = 1000205002, VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000, VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV = 1000314008, + VK_STRUCTURE_TYPE_CHECKPOINT_DATA_2_NV = 1000314009, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES, VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, @@ -2425,16 +3374,29 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_DISPLAY_NATIVE_HDR_SURFACE_CAPABILITIES_AMD = 1000213000, VK_STRUCTURE_TYPE_SWAPCHAIN_DISPLAY_NATIVE_HDR_CREATE_INFO_AMD = 1000213001, VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES, VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001, VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002, + VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_INFO_EXT = 1000044007, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT = 1000225000, - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = 1000225001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT = 1000225002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES, + VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000226000, + VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR = 1000226001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR = 1000226002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR = 1000226003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR = 1000226004, + VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000044006, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD = 1000227000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD = 1000229000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO, + VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT = 1000234000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_QUAD_CONTROL_FEATURES_KHR = 1000235000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT = 1000237000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT = 1000238000, VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT = 1000238001, @@ -2447,9 +3409,10 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT = 1000244002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT = 1000245000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES, VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO, VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT = 1000247000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR = 1000248000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV = 1000249000, VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249002, @@ -2459,6 +3422,9 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT = 1000251000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT = 1000252000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT = 1000254000, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT = 1000254001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT = 1000254002, VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT = 1000255000, VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT = 1000255002, VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT = 1000255001, @@ -2468,21 +3434,45 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO, VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO, VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT = 1000259000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT = 1000259001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT = 1000259002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT = 1000260000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT = 1000265000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT = 1000267000, - VK_STRUCTURE_TYPE_DEFERRED_OPERATION_INFO_KHR = 1000268000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR = 1000269000, VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR = 1000269001, VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR = 1000269002, VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR = 1000269003, VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR = 1000269004, VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR = 1000269005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = 1000276000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES, + VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY, + VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY_EXT = VK_STRUCTURE_TYPE_IMAGE_TO_MEMORY_COPY, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO_EXT = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_MEMORY_INFO, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO, + VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_IMAGE_INFO_EXT = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_IMAGE_INFO, + VK_STRUCTURE_TYPE_SUBRESOURCE_HOST_MEMCPY_SIZE_EXT = VK_STRUCTURE_TYPE_SUBRESOURCE_HOST_MEMCPY_SIZE, + VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY_EXT = VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY, + VK_STRUCTURE_TYPE_MEMORY_MAP_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_MAP_INFO, + VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAP_MEMORY_PLACED_FEATURES_EXT = 1000272000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAP_MEMORY_PLACED_PROPERTIES_EXT = 1000272001, + VK_STRUCTURE_TYPE_MEMORY_MAP_PLACED_INFO_EXT = 1000272002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT = 1000273000, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT = 1000274000, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT = 1000274001, + VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT = 1000274002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT = 1000275000, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT = 1000275001, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT = 1000275002, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT = 1000275003, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT = 1000275004, + VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT = 1000275005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV = 1000277000, VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_CREATE_INFO_NV = 1000277001, VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV = 1000277002, @@ -2491,67 +3481,489 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_NV = 1000277005, VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_NV = 1000277006, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV = 1000277007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV = 1000278000, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV = 1000278001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT = 1000281000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = 1000281001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES, VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM = 1000282000, VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM = 1000282001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_BIAS_CONTROL_FEATURES_EXT = 1000283000, + VK_STRUCTURE_TYPE_DEPTH_BIAS_INFO_EXT = 1000283001, + VK_STRUCTURE_TYPE_DEPTH_BIAS_REPRESENTATION_INFO_EXT = 1000283002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT = 1000284000, + VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT = 1000284001, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_REPORT_CALLBACK_DATA_EXT = 1000284002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT = 1000286000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT = 1000286001, VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT = 1000287000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT = 1000287001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT = 1000287002, VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR = 1000290000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT = 1000295000, - VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT = 1000295001, - VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT = 1000295002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT = 1000297000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV = 1000292000, + VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_BARRIER_NV = 1000292001, + VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_BARRIER_CREATE_INFO_NV = 1000292002, + VK_STRUCTURE_TYPE_PRESENT_ID_KHR = 1000294000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR = 1000294001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES, + VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO, + VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV = 1000300000, VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV = 1000300001, + VK_STRUCTURE_TYPE_CUDA_MODULE_CREATE_INFO_NV = 1000307000, + VK_STRUCTURE_TYPE_CUDA_FUNCTION_CREATE_INFO_NV = 1000307001, + VK_STRUCTURE_TYPE_CUDA_LAUNCH_INFO_NV = 1000307002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUDA_KERNEL_LAUNCH_FEATURES_NV = 1000307003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUDA_KERNEL_LAUNCH_PROPERTIES_NV = 1000307004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_SHADING_FEATURES_QCOM = 1000309000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_SHADING_PROPERTIES_QCOM = 1000309001, + VK_STRUCTURE_TYPE_RENDER_PASS_TILE_SHADING_CREATE_INFO_QCOM = 1000309002, + VK_STRUCTURE_TYPE_PER_TILE_BEGIN_INFO_QCOM = 1000309003, + VK_STRUCTURE_TYPE_PER_TILE_END_INFO_QCOM = 1000309004, + VK_STRUCTURE_TYPE_DISPATCH_TILE_INFO_QCOM = 1000309005, + VK_STRUCTURE_TYPE_QUERY_LOW_LATENCY_SUPPORT_NV = 1000310000, + VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECT_CREATE_INFO_EXT = 1000311000, + VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECTS_INFO_EXT = 1000311001, + VK_STRUCTURE_TYPE_EXPORT_METAL_DEVICE_INFO_EXT = 1000311002, + VK_STRUCTURE_TYPE_EXPORT_METAL_COMMAND_QUEUE_INFO_EXT = 1000311003, + VK_STRUCTURE_TYPE_EXPORT_METAL_BUFFER_INFO_EXT = 1000311004, + VK_STRUCTURE_TYPE_IMPORT_METAL_BUFFER_INFO_EXT = 1000311005, + VK_STRUCTURE_TYPE_EXPORT_METAL_TEXTURE_INFO_EXT = 1000311006, + VK_STRUCTURE_TYPE_IMPORT_METAL_TEXTURE_INFO_EXT = 1000311007, + VK_STRUCTURE_TYPE_EXPORT_METAL_IO_SURFACE_INFO_EXT = 1000311008, + VK_STRUCTURE_TYPE_IMPORT_METAL_IO_SURFACE_INFO_EXT = 1000311009, + VK_STRUCTURE_TYPE_EXPORT_METAL_SHARED_EVENT_INFO_EXT = 1000311010, + VK_STRUCTURE_TYPE_IMPORT_METAL_SHARED_EVENT_INFO_EXT = 1000311011, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT = 1000316000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT = 1000316001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT = 1000316002, + VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT = 1000316003, + VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT = 1000316004, + VK_STRUCTURE_TYPE_BUFFER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316005, + VK_STRUCTURE_TYPE_IMAGE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316006, + VK_STRUCTURE_TYPE_IMAGE_VIEW_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316007, + VK_STRUCTURE_TYPE_SAMPLER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316008, + VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT = 1000316010, + VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT = 1000316011, + VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_PUSH_DESCRIPTOR_BUFFER_HANDLE_EXT = 1000316012, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT = 1000320000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT = 1000320001, + VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT = 1000320002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD = 1000321000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR = 1000203000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR = 1000322000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR = 1000323000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV = 1000326000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV = 1000326001, + VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV = 1000326002, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV = 1000327000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV = 1000327001, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MOTION_INFO_NV = 1000327002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT = 1000328000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT = 1000328001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT = 1000330000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT = 1000332000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT = 1000332001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT = 1000335000, + VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM = 1000333000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR = 1000336000, + VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2, + VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2, + VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2, + VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR = VK_STRUCTURE_TYPE_BUFFER_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR = VK_STRUCTURE_TYPE_IMAGE_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR = VK_STRUCTURE_TYPE_IMAGE_BLIT_2, + VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR = VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2, + VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR = VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT = 1000338000, + VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT = 1000338001, + VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_EXT = VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2, + VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_EXT = VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2, + VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT = 1000338004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT = 1000339000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT = 1000340000, - VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT = 1000346000 + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT = 1000341000, + VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT = 1000341001, + VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT = 1000341002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM = 1000342000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT = 1000344000, + VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT = 1000346000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE = 1000351000, + VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE = 1000351002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT = 1000352000, + VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT = 1000352001, + VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT = 1000352002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT = 1000353000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT = 1000354000, + VK_STRUCTURE_TYPE_DEVICE_ADDRESS_BINDING_CALLBACK_DATA_EXT = 1000354001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT = 1000355000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT = 1000355001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT = 1000356000, + VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_MODE_FIFO_LATEST_READY_FEATURES_EXT = 1000361000, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364000, + VK_STRUCTURE_TYPE_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA = 1000364001, + VK_STRUCTURE_TYPE_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000364002, + VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365000, + VK_STRUCTURE_TYPE_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA = 1000365001, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA = 1000366000, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA = 1000366001, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA = 1000366002, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA = 1000366003, + VK_STRUCTURE_TYPE_BUFFER_CONSTRAINTS_INFO_FUCHSIA = 1000366004, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_BUFFER_CREATE_INFO_FUCHSIA = 1000366005, + VK_STRUCTURE_TYPE_IMAGE_CONSTRAINTS_INFO_FUCHSIA = 1000366006, + VK_STRUCTURE_TYPE_IMAGE_FORMAT_CONSTRAINTS_INFO_FUCHSIA = 1000366007, + VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA = 1000366008, + VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CONSTRAINTS_INFO_FUCHSIA = 1000366009, + VK_STRUCTURE_TYPE_SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI = 1000369000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI = 1000369001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI = 1000369002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI = 1000370000, + VK_STRUCTURE_TYPE_MEMORY_GET_REMOTE_ADDRESS_INFO_NV = 1000371000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV = 1000371001, + VK_STRUCTURE_TYPE_PIPELINE_PROPERTIES_IDENTIFIER_EXT = 1000372000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT = 1000372001, + VK_STRUCTURE_TYPE_PIPELINE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAME_BOUNDARY_FEATURES_EXT = 1000375000, + VK_STRUCTURE_TYPE_FRAME_BOUNDARY_EXT = 1000375001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT = 1000376000, + VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT = 1000376001, + VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT = 1000376002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT = 1000377000, + VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX = 1000378000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT = 1000381000, + VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT = 1000381001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT = 1000382000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR = 1000386000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES, + VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT = 1000391000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT = 1000391001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT = 1000392000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT = 1000392001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT = 1000393000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_FEATURES_EXT = 1000395000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_PROPERTIES_EXT = 1000395001, + VK_STRUCTURE_TYPE_MICROMAP_BUILD_INFO_EXT = 1000396000, + VK_STRUCTURE_TYPE_MICROMAP_VERSION_INFO_EXT = 1000396001, + VK_STRUCTURE_TYPE_COPY_MICROMAP_INFO_EXT = 1000396002, + VK_STRUCTURE_TYPE_COPY_MICROMAP_TO_MEMORY_INFO_EXT = 1000396003, + VK_STRUCTURE_TYPE_COPY_MEMORY_TO_MICROMAP_INFO_EXT = 1000396004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT = 1000396005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT = 1000396006, + VK_STRUCTURE_TYPE_MICROMAP_CREATE_INFO_EXT = 1000396007, + VK_STRUCTURE_TYPE_MICROMAP_BUILD_SIZES_INFO_EXT = 1000396008, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_OPACITY_MICROMAP_EXT = 1000396009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISPLACEMENT_MICROMAP_FEATURES_NV = 1000397000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISPLACEMENT_MICROMAP_PROPERTIES_NV = 1000397001, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_DISPLACEMENT_MICROMAP_NV = 1000397002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_FEATURES_HUAWEI = 1000404000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI = 1000404001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_VRS_FEATURES_HUAWEI = 1000404002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT = 1000411000, + VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT = 1000411001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT = 1000412000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES, + VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_ARM = 1000415000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES, + VK_STRUCTURE_TYPE_DEVICE_QUEUE_SHADER_CORE_CONTROL_CREATE_INFO_ARM = 1000417000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_FEATURES_ARM = 1000417001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_PROPERTIES_ARM = 1000417002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_SLICED_VIEW_OF_3D_FEATURES_EXT = 1000418000, + VK_STRUCTURE_TYPE_IMAGE_VIEW_SLICED_CREATE_INFO_EXT = 1000418001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE = 1000420000, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_BINDING_REFERENCE_VALVE = 1000420001, + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_HOST_MAPPING_INFO_VALVE = 1000420002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT = 1000421000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT = 1000422000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_FEATURES_ARM = 1000424000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_PROPERTIES_ARM = 1000424001, + VK_STRUCTURE_TYPE_RENDER_PASS_STRIPE_BEGIN_INFO_ARM = 1000424002, + VK_STRUCTURE_TYPE_RENDER_PASS_STRIPE_INFO_ARM = 1000424003, + VK_STRUCTURE_TYPE_RENDER_PASS_STRIPE_SUBMIT_INFO_ARM = 1000424004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM = 1000425000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM = 1000425001, + VK_STRUCTURE_TYPE_SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM = 1000425002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV = 1000426000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_NV = 1000426001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV = 1000427000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_NV = 1000427001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_COMPUTE_FEATURES_NV = 1000428000, + VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_INDIRECT_BUFFER_INFO_NV = 1000428001, + VK_STRUCTURE_TYPE_PIPELINE_INDIRECT_DEVICE_ADDRESS_INFO_NV = 1000428002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_LINEAR_SWEPT_SPHERES_FEATURES_NV = 1000429008, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_LINEAR_SWEPT_SPHERES_DATA_NV = 1000429009, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_SPHERES_DATA_NV = 1000429010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV = 1000430000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MAXIMAL_RECONVERGENCE_FEATURES_KHR = 1000434000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT = 1000437000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM = 1000440000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM = 1000440001, + VK_STRUCTURE_TYPE_IMAGE_VIEW_SAMPLE_WEIGHT_CREATE_INFO_QCOM = 1000440002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_FEATURES_EXT = 1000451000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_PROPERTIES_EXT = 1000451001, + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_EXT = 1000453000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT = 1000455000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT = 1000455001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT = 1000458000, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT = 1000458001, + VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_FEEDBACK_CREATE_INFO_EXT = 1000458002, + VK_STRUCTURE_TYPE_RENDER_PASS_SUBPASS_FEEDBACK_CREATE_INFO_EXT = 1000458003, + VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_INFO_LUNARG = 1000459000, + VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_LIST_LUNARG = 1000459001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT = 1000462000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT = 1000462001, + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_MODULE_IDENTIFIER_CREATE_INFO_EXT = 1000462002, + VK_STRUCTURE_TYPE_SHADER_MODULE_IDENTIFIER_EXT = 1000462003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT = 1000342000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV = 1000464000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV = 1000464001, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_INFO_NV = 1000464002, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_PROPERTIES_NV = 1000464003, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_INFO_NV = 1000464004, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_EXECUTE_INFO_NV = 1000464005, + VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_PRIVATE_DATA_INFO_NV = 1000464010, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT = 1000465000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FORMAT_RESOLVE_FEATURES_ANDROID = 1000468000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FORMAT_RESOLVE_PROPERTIES_ANDROID = 1000468001, + VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_RESOLVE_PROPERTIES_ANDROID = 1000468002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES, + VK_STRUCTURE_TYPE_RENDERING_AREA_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_AREA_INFO, + VK_STRUCTURE_TYPE_DEVICE_IMAGE_SUBRESOURCE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_IMAGE_SUBRESOURCE_INFO, + VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_KHR = VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2, + VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_KHR = VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2, + VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO, + VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ANTI_LAG_FEATURES_AMD = 1000476000, + VK_STRUCTURE_TYPE_ANTI_LAG_DATA_AMD = 1000476001, + VK_STRUCTURE_TYPE_ANTI_LAG_PRESENTATION_INFO_AMD = 1000476002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_POSITION_FETCH_FEATURES_KHR = 1000481000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT = 1000482000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_PROPERTIES_EXT = 1000482001, + VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT = 1000482002, + VK_STRUCTURE_TYPE_SHADER_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_BINARY_FEATURES_KHR = 1000483000, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_CREATE_INFO_KHR = 1000483001, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_INFO_KHR = 1000483002, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_KEY_KHR = 1000483003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_BINARY_PROPERTIES_KHR = 1000483004, + VK_STRUCTURE_TYPE_RELEASE_CAPTURED_PIPELINE_DATA_INFO_KHR = 1000483005, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_DATA_INFO_KHR = 1000483006, + VK_STRUCTURE_TYPE_PIPELINE_CREATE_INFO_KHR = 1000483007, + VK_STRUCTURE_TYPE_DEVICE_PIPELINE_BINARY_INTERNAL_CACHE_CONTROL_KHR = 1000483008, + VK_STRUCTURE_TYPE_PIPELINE_BINARY_HANDLES_INFO_KHR = 1000483009, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM = 1000484000, + VK_STRUCTURE_TYPE_TILE_PROPERTIES_QCOM = 1000484001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_AMIGO_PROFILING_FEATURES_SEC = 1000485000, + VK_STRUCTURE_TYPE_AMIGO_PROFILING_SUBMIT_INFO_SEC = 1000485001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM = 1000488000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV = 1000490000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV = 1000490001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_FEATURES_NV = 1000491000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_PROPERTIES_NV = 1000491001, + VK_STRUCTURE_TYPE_COOPERATIVE_VECTOR_PROPERTIES_NV = 1000491002, + VK_STRUCTURE_TYPE_CONVERT_COOPERATIVE_VECTOR_MATRIX_INFO_NV = 1000491004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_FEATURES_NV = 1000492000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_PROPERTIES_NV = 1000492001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT = 1000351000, + VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT = 1000351002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_VERTEX_ATTRIBUTES_FEATURES_EXT = 1000495000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_VERTEX_ATTRIBUTES_PROPERTIES_EXT = 1000495001, + VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT = 1000496000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM = 1000497000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM = 1000497001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_LIBRARY_GROUP_HANDLES_FEATURES_EXT = 1000498000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_FEATURES_EXT = 1000499000, + VK_STRUCTURE_TYPE_LATENCY_SLEEP_MODE_INFO_NV = 1000505000, + VK_STRUCTURE_TYPE_LATENCY_SLEEP_INFO_NV = 1000505001, + VK_STRUCTURE_TYPE_SET_LATENCY_MARKER_INFO_NV = 1000505002, + VK_STRUCTURE_TYPE_GET_LATENCY_MARKER_INFO_NV = 1000505003, + VK_STRUCTURE_TYPE_LATENCY_TIMINGS_FRAME_REPORT_NV = 1000505004, + VK_STRUCTURE_TYPE_LATENCY_SUBMISSION_PRESENT_ID_NV = 1000505005, + VK_STRUCTURE_TYPE_OUT_OF_BAND_QUEUE_TYPE_INFO_NV = 1000505006, + VK_STRUCTURE_TYPE_SWAPCHAIN_LATENCY_CREATE_INFO_NV = 1000505007, + VK_STRUCTURE_TYPE_LATENCY_SURFACE_CAPABILITIES_NV = 1000505008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR = 1000506000, + VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_KHR = 1000506001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR = 1000506002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_RENDER_AREAS_FEATURES_QCOM = 1000510000, + VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_RENDER_AREAS_RENDER_PASS_BEGIN_INFO_QCOM = 1000510001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_KHR = 1000201000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_PROPERTIES_KHR = 1000511000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PER_STAGE_DESCRIPTOR_SET_FEATURES_NV = 1000516000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_FEATURES_QCOM = 1000518000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_PROPERTIES_QCOM = 1000518001, + VK_STRUCTURE_TYPE_SAMPLER_BLOCK_MATCH_WINDOW_CREATE_INFO_QCOM = 1000518002, + VK_STRUCTURE_TYPE_SAMPLER_CUBIC_WEIGHTS_CREATE_INFO_QCOM = 1000519000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUBIC_WEIGHTS_FEATURES_QCOM = 1000519001, + VK_STRUCTURE_TYPE_BLIT_IMAGE_CUBIC_WEIGHTS_INFO_QCOM = 1000519002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_DEGAMMA_FEATURES_QCOM = 1000520000, + VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_YCBCR_DEGAMMA_CREATE_INFO_QCOM = 1000520001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUBIC_CLAMP_FEATURES_QCOM = 1000521000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_FEATURES_EXT = 1000524000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES, + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT_CONTROLS_2_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT_CONTROLS_2_FEATURES, + VK_STRUCTURE_TYPE_SCREEN_BUFFER_PROPERTIES_QNX = 1000529000, + VK_STRUCTURE_TYPE_SCREEN_BUFFER_FORMAT_PROPERTIES_QNX = 1000529001, + VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX = 1000529002, + VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_QNX = 1000529003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_SCREEN_BUFFER_FEATURES_QNX = 1000529004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT = 1000530000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES, + VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_KHR = 1000184000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_FEATURES, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES, + VK_STRUCTURE_TYPE_BIND_MEMORY_STATUS_KHR = VK_STRUCTURE_TYPE_BIND_MEMORY_STATUS, + VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_SETS_INFO_KHR = VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_SETS_INFO, + VK_STRUCTURE_TYPE_PUSH_CONSTANTS_INFO_KHR = VK_STRUCTURE_TYPE_PUSH_CONSTANTS_INFO, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_INFO_KHR = VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_INFO, + VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE_INFO_KHR = VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE_INFO, + VK_STRUCTURE_TYPE_SET_DESCRIPTOR_BUFFER_OFFSETS_INFO_EXT = 1000545007, + VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_BUFFER_EMBEDDED_SAMPLERS_INFO_EXT = 1000545008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_POOL_OVERALLOCATION_FEATURES_NV = 1000546000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_FEATURES_QCOM = 1000547000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_PROPERTIES_QCOM = 1000547001, + VK_STRUCTURE_TYPE_TILE_MEMORY_REQUIREMENTS_QCOM = 1000547002, + VK_STRUCTURE_TYPE_TILE_MEMORY_BIND_INFO_QCOM = 1000547003, + VK_STRUCTURE_TYPE_TILE_MEMORY_SIZE_INFO_QCOM = 1000547004, + VK_STRUCTURE_TYPE_DISPLAY_SURFACE_STEREO_CREATE_INFO_NV = 1000551000, + VK_STRUCTURE_TYPE_DISPLAY_MODE_STEREO_PROPERTIES_NV = 1000551001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV = 1000555000, + VK_STRUCTURE_TYPE_EXTERNAL_COMPUTE_QUEUE_DEVICE_CREATE_INFO_NV = 1000556000, + VK_STRUCTURE_TYPE_EXTERNAL_COMPUTE_QUEUE_CREATE_INFO_NV = 1000556001, + VK_STRUCTURE_TYPE_EXTERNAL_COMPUTE_QUEUE_DATA_PARAMS_NV = 1000556002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_COMPUTE_QUEUE_PROPERTIES_NV = 1000556003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_RELAXED_EXTENDED_INSTRUCTION_FEATURES_KHR = 1000558000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMMAND_BUFFER_INHERITANCE_FEATURES_NV = 1000559000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_7_FEATURES_KHR = 1000562000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_7_PROPERTIES_KHR = 1000562001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_LIST_KHR = 1000562002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_KHR = 1000562003, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR = 1000562004, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT16_VECTOR_FEATURES_NV = 1000563000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_REPLICATED_COMPOSITES_FEATURES_EXT = 1000564000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_VALIDATION_FEATURES_NV = 1000568000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_FEATURES_NV = 1000569000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_PROPERTIES_NV = 1000569001, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_CLUSTERS_BOTTOM_LEVEL_INPUT_NV = 1000569002, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_TRIANGLE_CLUSTER_INPUT_NV = 1000569003, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_MOVE_OBJECTS_INPUT_NV = 1000569004, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_INPUT_INFO_NV = 1000569005, + VK_STRUCTURE_TYPE_CLUSTER_ACCELERATION_STRUCTURE_COMMANDS_INFO_NV = 1000569006, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CLUSTER_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000569007, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PARTITIONED_ACCELERATION_STRUCTURE_FEATURES_NV = 1000570000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PARTITIONED_ACCELERATION_STRUCTURE_PROPERTIES_NV = 1000570001, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_PARTITIONED_ACCELERATION_STRUCTURE_NV = 1000570002, + VK_STRUCTURE_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCES_INPUT_NV = 1000570003, + VK_STRUCTURE_TYPE_BUILD_PARTITIONED_ACCELERATION_STRUCTURE_INFO_NV = 1000570004, + VK_STRUCTURE_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_FLAGS_NV = 1000570005, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_EXT = 1000572000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_EXT = 1000572001, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_EXT = 1000572002, + VK_STRUCTURE_TYPE_INDIRECT_EXECUTION_SET_CREATE_INFO_EXT = 1000572003, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_EXT = 1000572004, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_EXT = 1000572006, + VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_TOKEN_EXT = 1000572007, + VK_STRUCTURE_TYPE_WRITE_INDIRECT_EXECUTION_SET_PIPELINE_EXT = 1000572008, + VK_STRUCTURE_TYPE_WRITE_INDIRECT_EXECUTION_SET_SHADER_EXT = 1000572009, + VK_STRUCTURE_TYPE_INDIRECT_EXECUTION_SET_PIPELINE_INFO_EXT = 1000572010, + VK_STRUCTURE_TYPE_INDIRECT_EXECUTION_SET_SHADER_INFO_EXT = 1000572011, + VK_STRUCTURE_TYPE_INDIRECT_EXECUTION_SET_SHADER_LAYOUT_INFO_EXT = 1000572012, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_PIPELINE_INFO_EXT = 1000572013, + VK_STRUCTURE_TYPE_GENERATED_COMMANDS_SHADER_INFO_EXT = 1000572014, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_8_FEATURES_KHR = 1000574000, + VK_STRUCTURE_TYPE_MEMORY_BARRIER_ACCESS_FLAGS_3_KHR = 1000574002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ALIGNMENT_CONTROL_FEATURES_MESA = 1000575000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ALIGNMENT_CONTROL_PROPERTIES_MESA = 1000575001, + VK_STRUCTURE_TYPE_IMAGE_ALIGNMENT_CONTROL_CREATE_INFO_MESA = 1000575002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_CONTROL_FEATURES_EXT = 1000582000, + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLAMP_CONTROL_CREATE_INFO_EXT = 1000582001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HDR_VIVID_FEATURES_HUAWEI = 1000590000, + VK_STRUCTURE_TYPE_HDR_VIVID_DYNAMIC_METADATA_HUAWEI = 1000590001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_FEATURES_NV = 1000593000, + VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_FLEXIBLE_DIMENSIONS_PROPERTIES_NV = 1000593001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_PROPERTIES_NV = 1000593002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_OPACITY_MICROMAP_FEATURES_ARM = 1000596000, + VK_STRUCTURE_TYPE_IMPORT_MEMORY_METAL_HANDLE_INFO_EXT = 1000602000, + VK_STRUCTURE_TYPE_MEMORY_METAL_HANDLE_PROPERTIES_EXT = 1000602001, + VK_STRUCTURE_TYPE_MEMORY_GET_METAL_HANDLE_INFO_EXT = 1000602002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_KHR = 1000421000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_ROBUSTNESS_FEATURES_EXT = 1000608000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_KHR = 1000286000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_KHR = 1000286001, + VK_STRUCTURE_TYPE_SET_PRESENT_CONFIG_NV = 1000613000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_METERING_FEATURES_NV = 1000613001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_EXT = 1000425000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_EXT = 1000425001, + VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_EXT = 1000425002, + VK_STRUCTURE_TYPE_RENDERING_END_INFO_EXT = 1000619003, + VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkStructureType; - typedef enum VkSystemAllocationScope { VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1, VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3, - VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4 + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4, + VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7FFFFFFF } VkSystemAllocationScope; - typedef enum VkInternalAllocationType { - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0 + VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0, + VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF } VkInternalAllocationType; - typedef enum VkSamplerAddressMode { VK_SAMPLER_ADDRESS_MODE_REPEAT = 0, VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3, VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, - VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE + VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE, + VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7FFFFFFF } VkSamplerAddressMode; - typedef enum VkFilter { VK_FILTER_NEAREST = 0, VK_FILTER_LINEAR = 1, VK_FILTER_CUBIC_IMG = 1000015000, - VK_FILTER_CUBIC_EXT = VK_FILTER_CUBIC_IMG + VK_FILTER_CUBIC_EXT = 1000015000, + VK_FILTER_MAX_ENUM = 0x7FFFFFFF } VkFilter; - typedef enum VkSamplerMipmapMode { VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, - VK_SAMPLER_MIPMAP_MODE_LINEAR = 1 + VK_SAMPLER_MIPMAP_MODE_LINEAR = 1, + VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7FFFFFFF } VkSamplerMipmapMode; - typedef enum VkVertexInputRate { VK_VERTEX_INPUT_RATE_VERTEX = 0, - VK_VERTEX_INPUT_RATE_INSTANCE = 1 + VK_VERTEX_INPUT_RATE_INSTANCE = 1, + VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7FFFFFFF } VkVertexInputRate; - typedef enum VkPipelineStageFlagBits { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 1, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 2, @@ -2570,25 +3982,57 @@ typedef enum VkPipelineStageFlagBits { VK_PIPELINE_STAGE_HOST_BIT = 16384, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 32768, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 65536, + VK_PIPELINE_STAGE_NONE = 0, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 16777216, VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 262144, - VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR = 2097152, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 33554432, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR = 2097152, VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 4194304, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 524288, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 1048576, VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 8388608, - VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV = 131072 + VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 4194304, + VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV = 131072, + VK_PIPELINE_STAGE_NONE_KHR = VK_PIPELINE_STAGE_NONE, + VK_PIPELINE_STAGE_TASK_SHADER_BIT_EXT = 524288, + VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT = 1048576, + VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_EXT = 131072, + VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPipelineStageFlagBits; - typedef enum VkSparseImageFormatFlagBits { VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 1, VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 2, - VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 4 + VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 4, + VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSparseImageFormatFlagBits; - +typedef enum VkClusterAccelerationStructureIndexFormatFlagBitsNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_8BIT_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_16BIT_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_32BIT_NV = 4, + VK_CLUSTER_ACCELERATION_STRUCTURE_INDEX_FORMAT_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureIndexFormatFlagBitsNV; +typedef enum VkClusterAccelerationStructureTypeNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_CLUSTERS_BOTTOM_LEVEL_NV = 0, + VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_TRIANGLE_CLUSTER_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_TRIANGLE_CLUSTER_TEMPLATE_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureTypeNV; +typedef enum VkClusterAccelerationStructureOpTypeNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_MOVE_OBJECTS_NV = 0, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_CLUSTERS_BOTTOM_LEVEL_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_BUILD_TRIANGLE_CLUSTER_TEMPLATE_NV = 3, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_INSTANTIATE_TRIANGLE_CLUSTER_NV = 4, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureOpTypeNV; +typedef enum VkClusterAccelerationStructureOpModeNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_IMPLICIT_DESTINATIONS_NV = 0, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_EXPLICIT_DESTINATIONS_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_COMPUTE_SIZES_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_OP_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureOpModeNV; typedef enum VkSampleCountFlagBits { VK_SAMPLE_COUNT_1_BIT = 1, VK_SAMPLE_COUNT_2_BIT = 2, @@ -2596,27 +4040,33 @@ typedef enum VkSampleCountFlagBits { VK_SAMPLE_COUNT_8_BIT = 8, VK_SAMPLE_COUNT_16_BIT = 16, VK_SAMPLE_COUNT_32_BIT = 32, - VK_SAMPLE_COUNT_64_BIT = 64 + VK_SAMPLE_COUNT_64_BIT = 64, + VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSampleCountFlagBits; - typedef enum VkAttachmentDescriptionFlagBits { - VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 1 + VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 1, + VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkAttachmentDescriptionFlagBits; - typedef enum VkDescriptorPoolCreateFlagBits { VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 1, VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT = 2, - VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT + VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT, + VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE = 4, + VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT = 4, + VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_SETS_BIT_NV = 8, + VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_POOLS_BIT_NV = 16, + VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDescriptorPoolCreateFlagBits; - typedef enum VkDependencyFlagBits { VK_DEPENDENCY_BY_REGION_BIT = 1, VK_DEPENDENCY_DEVICE_GROUP_BIT = 4, VK_DEPENDENCY_VIEW_LOCAL_BIT = 2, VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = VK_DEPENDENCY_VIEW_LOCAL_BIT, - VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = VK_DEPENDENCY_DEVICE_GROUP_BIT + VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = VK_DEPENDENCY_DEVICE_GROUP_BIT, + VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT = 8, + VK_DEPENDENCY_QUEUE_FAMILY_OWNERSHIP_TRANSFER_USE_ALL_STAGES_BIT_KHR = 32, + VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDependencyFlagBits; - typedef enum VkObjectType { VK_OBJECT_TYPE_UNKNOWN = 0, VK_OBJECT_TYPE_INSTANCE = 1, @@ -2646,29 +4096,56 @@ typedef enum VkObjectType { VK_OBJECT_TYPE_COMMAND_POOL = 25, VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000, VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000, + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT = 1000295000, VK_OBJECT_TYPE_SURFACE_KHR = 1000000000, VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000, VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000, VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001, VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000, + VK_OBJECT_TYPE_CU_MODULE_NVX = 1000029000, + VK_OBJECT_TYPE_CU_FUNCTION_NVX = 1000029001, VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000, - VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR = 1000165000, + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000, VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, - VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR, + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL = 1000210000, VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR = 1000268000, VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV = 1000277000, - VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT = 1000295000 + VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT = VK_OBJECT_TYPE_PRIVATE_DATA_SLOT, + VK_OBJECT_TYPE_CUDA_MODULE_NV = 1000307000, + VK_OBJECT_TYPE_CUDA_FUNCTION_NV = 1000307001, + VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA = 1000366000, + VK_OBJECT_TYPE_MICROMAP_EXT = 1000396000, + VK_OBJECT_TYPE_OPTICAL_FLOW_SESSION_NV = 1000464000, + VK_OBJECT_TYPE_SHADER_EXT = 1000482000, + VK_OBJECT_TYPE_PIPELINE_BINARY_KHR = 1000483000, + VK_OBJECT_TYPE_EXTERNAL_COMPUTE_QUEUE_NV = 1000556000, + VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_EXT = 1000572000, + VK_OBJECT_TYPE_INDIRECT_EXECUTION_SET_EXT = 1000572001, + VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF } VkObjectType; - +typedef enum VkEventCreateFlagBits { + VK_EVENT_CREATE_DEVICE_ONLY_BIT = 1, + VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR = VK_EVENT_CREATE_DEVICE_ONLY_BIT, + VK_EVENT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkEventCreateFlagBits; +typedef enum VkPipelineLayoutCreateFlagBits { + VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT = 2, + VK_PIPELINE_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineLayoutCreateFlagBits; +typedef enum VkRayTracingInvocationReorderModeNV { + VK_RAY_TRACING_INVOCATION_REORDER_MODE_NONE_NV = 0, + VK_RAY_TRACING_INVOCATION_REORDER_MODE_REORDER_NV = 1, + VK_RAY_TRACING_INVOCATION_REORDER_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkRayTracingInvocationReorderModeNV; typedef enum VkIndirectCommandsLayoutUsageFlagBitsNV { VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_NV = 1, VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NV = 2, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV = 4 + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV = 4, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF } VkIndirectCommandsLayoutUsageFlagBitsNV; - typedef enum VkIndirectCommandsTokenTypeNV { VK_INDIRECT_COMMANDS_TOKEN_TYPE_SHADER_GROUP_NV = 0, VK_INDIRECT_COMMANDS_TOKEN_TYPE_STATE_FLAGS_NV = 1, @@ -2677,20 +4154,23 @@ typedef enum VkIndirectCommandsTokenTypeNV { VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NV = 4, VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NV = 5, VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NV = 6, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV = 7 + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV = 7, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV = 1000328000, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NV = 1000428003, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NV = 1000428004, + VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NV = 0x7FFFFFFF } VkIndirectCommandsTokenTypeNV; - typedef enum VkIndirectStateFlagBitsNV { - VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV = 1 + VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV = 1, + VK_INDIRECT_STATE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF } VkIndirectStateFlagBitsNV; - - typedef enum VkDescriptorUpdateTemplateType { VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS = 1, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, + VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkDescriptorUpdateTemplateType; - typedef enum VkDescriptorUpdateTemplateType VkDescriptorUpdateTemplateTypeKHR; typedef enum VkViewportCoordinateSwizzleNV { @@ -2701,72 +4181,98 @@ typedef enum VkViewportCoordinateSwizzleNV { VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4, VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5, VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7 + VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7, + VK_VIEWPORT_COORDINATE_SWIZZLE_MAX_ENUM_NV = 0x7FFFFFFF } VkViewportCoordinateSwizzleNV; - typedef enum VkDiscardRectangleModeEXT { VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0, - VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1 + VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1, + VK_DISCARD_RECTANGLE_MODE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDiscardRectangleModeEXT; - typedef enum VkSubpassDescriptionFlagBits { VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 1, VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 2, VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM = 4, - VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM = 8 + VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM = 8, + VK_SUBPASS_DESCRIPTION_TILE_SHADING_APRON_BIT_QCOM = 256, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_ARM = 16, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = 32, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = 64, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT = 16, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT = 32, + VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT = 64, + VK_SUBPASS_DESCRIPTION_ENABLE_LEGACY_DITHERING_BIT_EXT = 128, + VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSubpassDescriptionFlagBits; - typedef enum VkPointClippingBehavior { VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0, VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1, VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, - VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY + VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY, + VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF } VkPointClippingBehavior; - typedef enum VkPointClippingBehavior VkPointClippingBehaviorKHR; typedef enum VkCoverageModulationModeNV { VK_COVERAGE_MODULATION_MODE_NONE_NV = 0, VK_COVERAGE_MODULATION_MODE_RGB_NV = 1, VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2, - VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3 + VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3, + VK_COVERAGE_MODULATION_MODE_MAX_ENUM_NV = 0x7FFFFFFF } VkCoverageModulationModeNV; - typedef enum VkCoverageReductionModeNV { VK_COVERAGE_REDUCTION_MODE_MERGE_NV = 0, - VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV = 1 + VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV = 1, + VK_COVERAGE_REDUCTION_MODE_MAX_ENUM_NV = 0x7FFFFFFF } VkCoverageReductionModeNV; - typedef enum VkValidationCacheHeaderVersionEXT { - VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1 + VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1, + VK_VALIDATION_CACHE_HEADER_VERSION_MAX_ENUM_EXT = 0x7FFFFFFF } VkValidationCacheHeaderVersionEXT; - typedef enum VkShaderInfoTypeAMD { VK_SHADER_INFO_TYPE_STATISTICS_AMD = 0, VK_SHADER_INFO_TYPE_BINARY_AMD = 1, - VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2 + VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2, + VK_SHADER_INFO_TYPE_MAX_ENUM_AMD = 0x7FFFFFFF } VkShaderInfoTypeAMD; - -typedef enum VkQueueGlobalPriorityEXT { - VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = 128, - VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = 256, - VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = 512, - VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = 1024 -} VkQueueGlobalPriorityEXT; - -typedef enum VkTimeDomainEXT { - VK_TIME_DOMAIN_DEVICE_EXT = 0, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2, - VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3 -} VkTimeDomainEXT; +typedef enum VkQueueGlobalPriority { + VK_QUEUE_GLOBAL_PRIORITY_LOW = 128, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM = 256, + VK_QUEUE_GLOBAL_PRIORITY_HIGH = 512, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME = 1024, + VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = VK_QUEUE_GLOBAL_PRIORITY_LOW, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM, + VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = VK_QUEUE_GLOBAL_PRIORITY_HIGH, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = VK_QUEUE_GLOBAL_PRIORITY_REALTIME, + VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR = VK_QUEUE_GLOBAL_PRIORITY_LOW, + VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM, + VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR = VK_QUEUE_GLOBAL_PRIORITY_HIGH, + VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR = VK_QUEUE_GLOBAL_PRIORITY_REALTIME, + VK_QUEUE_GLOBAL_PRIORITY_MAX_ENUM = 0x7FFFFFFF +} VkQueueGlobalPriority; +typedef enum VkQueueGlobalPriority VkQueueGlobalPriorityKHR; + +typedef enum VkQueueGlobalPriority VkQueueGlobalPriorityEXT; + +typedef enum VkTimeDomainKHR { + VK_TIME_DOMAIN_DEVICE_KHR = 0, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR = 1, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR = 2, + VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_KHR = 3, + VK_TIME_DOMAIN_DEVICE_EXT = VK_TIME_DOMAIN_DEVICE_KHR, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR, + VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_KHR, + VK_TIME_DOMAIN_MAX_ENUM_KHR = 0x7FFFFFFF +} VkTimeDomainKHR; +typedef enum VkTimeDomainKHR VkTimeDomainEXT; typedef enum VkConservativeRasterizationModeEXT { VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT = 0, VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT = 1, - VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2 + VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2, + VK_CONSERVATIVE_RASTERIZATION_MODE_MAX_ENUM_EXT = 0x7FFFFFFF } VkConservativeRasterizationModeEXT; - typedef enum VkResolveModeFlagBits { VK_RESOLVE_MODE_NONE = 0, VK_RESOLVE_MODE_SAMPLE_ZERO_BIT = 1, @@ -2777,9 +4283,10 @@ typedef enum VkResolveModeFlagBits { VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT, VK_RESOLVE_MODE_AVERAGE_BIT_KHR = VK_RESOLVE_MODE_AVERAGE_BIT, VK_RESOLVE_MODE_MIN_BIT_KHR = VK_RESOLVE_MODE_MIN_BIT, - VK_RESOLVE_MODE_MAX_BIT_KHR = VK_RESOLVE_MODE_MAX_BIT + VK_RESOLVE_MODE_MAX_BIT_KHR = VK_RESOLVE_MODE_MAX_BIT, + VK_RESOLVE_MODE_EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID = 16, + VK_RESOLVE_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkResolveModeFlagBits; - typedef enum VkResolveModeFlagBits VkResolveModeFlagBitsKHR; typedef enum VkDescriptorBindingFlagBits { @@ -2790,46 +4297,68 @@ typedef enum VkDescriptorBindingFlagBits { VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, - VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT, + VK_DESCRIPTOR_BINDING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkDescriptorBindingFlagBits; - typedef enum VkDescriptorBindingFlagBits VkDescriptorBindingFlagBitsEXT; typedef enum VkConditionalRenderingFlagBitsEXT { - VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT = 1 + VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT = 1, + VK_CONDITIONAL_RENDERING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkConditionalRenderingFlagBitsEXT; - typedef enum VkSemaphoreType { VK_SEMAPHORE_TYPE_BINARY = 0, VK_SEMAPHORE_TYPE_TIMELINE = 1, VK_SEMAPHORE_TYPE_BINARY_KHR = VK_SEMAPHORE_TYPE_BINARY, - VK_SEMAPHORE_TYPE_TIMELINE_KHR = VK_SEMAPHORE_TYPE_TIMELINE + VK_SEMAPHORE_TYPE_TIMELINE_KHR = VK_SEMAPHORE_TYPE_TIMELINE, + VK_SEMAPHORE_TYPE_MAX_ENUM = 0x7FFFFFFF } VkSemaphoreType; - typedef enum VkSemaphoreType VkSemaphoreTypeKHR; typedef enum VkGeometryFlagBitsKHR { VK_GEOMETRY_OPAQUE_BIT_KHR = 1, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR = 2, VK_GEOMETRY_OPAQUE_BIT_NV = VK_GEOMETRY_OPAQUE_BIT_KHR, - VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR + VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR, + VK_GEOMETRY_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkGeometryFlagBitsKHR; - typedef enum VkGeometryFlagBitsKHR VkGeometryFlagBitsNV; typedef enum VkGeometryInstanceFlagBitsKHR { VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR = 1, - VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR = 2, + VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR = 2, VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR = 4, VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR = 8, + VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR = VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR, VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR, VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR, VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, - VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR + VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR, + VK_GEOMETRY_INSTANCE_FORCE_OPACITY_MICROMAP_2_STATE_EXT = 16, + VK_GEOMETRY_INSTANCE_DISABLE_OPACITY_MICROMAPS_EXT = 32, + VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkGeometryInstanceFlagBitsKHR; - typedef enum VkGeometryInstanceFlagBitsKHR VkGeometryInstanceFlagBitsNV; +typedef enum VkClusterAccelerationStructureAddressResolutionFlagBitsNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_DST_IMPLICIT_DATA_BIT_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_SCRATCH_DATA_BIT_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_DST_ADDRESS_ARRAY_BIT_NV = 4, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_DST_SIZES_ARRAY_BIT_NV = 8, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_SRC_INFOS_ARRAY_BIT_NV = 16, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_INDIRECTED_SRC_INFOS_COUNT_BIT_NV = 32, + VK_CLUSTER_ACCELERATION_STRUCTURE_ADDRESS_RESOLUTION_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureAddressResolutionFlagBitsNV; +typedef enum VkClusterAccelerationStructureGeometryFlagBitsNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_GEOMETRY_CULL_DISABLE_BIT_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_GEOMETRY_NO_DUPLICATE_ANYHIT_INVOCATION_BIT_NV = 2, + VK_CLUSTER_ACCELERATION_STRUCTURE_GEOMETRY_OPAQUE_BIT_NV = 4, + VK_CLUSTER_ACCELERATION_STRUCTURE_GEOMETRY_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureGeometryFlagBitsNV; +typedef enum VkClusterAccelerationStructureClusterFlagBitsNV { + VK_CLUSTER_ACCELERATION_STRUCTURE_CLUSTER_ALLOW_DISABLE_OPACITY_MICROMAPS_NV = 1, + VK_CLUSTER_ACCELERATION_STRUCTURE_CLUSTER_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkClusterAccelerationStructureClusterFlagBitsNV; typedef enum VkBuildAccelerationStructureFlagBitsKHR { VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR = 1, VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR = 2, @@ -2840,39 +4369,59 @@ typedef enum VkBuildAccelerationStructureFlagBitsKHR { VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR, VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR, - VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR + VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR, + VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV = 32, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_UPDATE_EXT = 64, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISABLE_OPACITY_MICROMAPS_EXT = 128, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_DATA_UPDATE_EXT = 256, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISPLACEMENT_MICROMAP_UPDATE_NV = 512, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DATA_ACCESS_KHR = 2048, + VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkBuildAccelerationStructureFlagBitsKHR; - typedef enum VkBuildAccelerationStructureFlagBitsKHR VkBuildAccelerationStructureFlagBitsNV; +typedef enum VkAccelerationStructureCreateFlagBitsKHR { + VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = 1, + VK_ACCELERATION_STRUCTURE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 8, + VK_ACCELERATION_STRUCTURE_CREATE_MOTION_BIT_NV = 4, + VK_ACCELERATION_STRUCTURE_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureCreateFlagBitsKHR; +typedef enum VkBuildAccelerationStructureModeKHR { + VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR = 0, + VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR = 1, + VK_BUILD_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkBuildAccelerationStructureModeKHR; typedef enum VkCopyAccelerationStructureModeKHR { VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR = 0, VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR = 1, VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR = 2, VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR = 3, VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR, - VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR + VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR, + VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_KHR = 0x7FFFFFFF } VkCopyAccelerationStructureModeKHR; - typedef enum VkCopyAccelerationStructureModeKHR VkCopyAccelerationStructureModeNV; typedef enum VkAccelerationStructureTypeKHR { VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR = 0, VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR = 1, + VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR = 2, VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, - VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR + VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, + VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF } VkAccelerationStructureTypeKHR; - typedef enum VkAccelerationStructureTypeKHR VkAccelerationStructureTypeNV; typedef enum VkGeometryTypeKHR { VK_GEOMETRY_TYPE_TRIANGLES_KHR = 0, VK_GEOMETRY_TYPE_AABBS_KHR = 1, - VK_GEOMETRY_TYPE_INSTANCES_KHR = 1000150000, + VK_GEOMETRY_TYPE_INSTANCES_KHR = 2, VK_GEOMETRY_TYPE_TRIANGLES_NV = VK_GEOMETRY_TYPE_TRIANGLES_KHR, - VK_GEOMETRY_TYPE_AABBS_NV = VK_GEOMETRY_TYPE_AABBS_KHR + VK_GEOMETRY_TYPE_AABBS_NV = VK_GEOMETRY_TYPE_AABBS_KHR, + VK_GEOMETRY_TYPE_SPHERES_NV = 1000429004, + VK_GEOMETRY_TYPE_LINEAR_SWEPT_SPHERES_NV = 1000429005, + VK_GEOMETRY_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF } VkGeometryTypeKHR; - typedef enum VkGeometryTypeKHR VkGeometryTypeNV; typedef enum VkRayTracingShaderGroupTypeKHR { @@ -2881,68 +4430,68 @@ typedef enum VkRayTracingShaderGroupTypeKHR { VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR = 2, VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR, VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR, - VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR + VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR, + VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF } VkRayTracingShaderGroupTypeKHR; - typedef enum VkRayTracingShaderGroupTypeKHR VkRayTracingShaderGroupTypeNV; -typedef enum VkAccelerationStructureMemoryRequirementsTypeKHR { - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR = 0, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR = 1, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_KHR = 2, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_KHR, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_KHR, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_KHR -} VkAccelerationStructureMemoryRequirementsTypeKHR; - -typedef enum VkAccelerationStructureMemoryRequirementsTypeKHR VkAccelerationStructureMemoryRequirementsTypeNV; - -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef enum VkAccelerationStructureMemoryRequirementsTypeNV { + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkAccelerationStructureMemoryRequirementsTypeNV; typedef enum VkAccelerationStructureBuildTypeKHR { VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR = 0, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR = 1, - VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR = 2 + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR = 2, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF } VkAccelerationStructureBuildTypeKHR; -#endif - +typedef enum VkAccelerationStructureCompatibilityKHR { + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_COMPATIBLE_KHR = 0, + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_INCOMPATIBLE_KHR = 1, + VK_ACCELERATION_STRUCTURE_COMPATIBILITY_MAX_ENUM_KHR = 0x7FFFFFFF +} VkAccelerationStructureCompatibilityKHR; +typedef enum VkRayTracingLssIndexingModeNV { + VK_RAY_TRACING_LSS_INDEXING_MODE_LIST_NV = 0, + VK_RAY_TRACING_LSS_INDEXING_MODE_SUCCESSIVE_NV = 1, + VK_RAY_TRACING_LSS_INDEXING_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkRayTracingLssIndexingModeNV; +typedef enum VkRayTracingLssPrimitiveEndCapsModeNV { + VK_RAY_TRACING_LSS_PRIMITIVE_END_CAPS_MODE_NONE_NV = 0, + VK_RAY_TRACING_LSS_PRIMITIVE_END_CAPS_MODE_CHAINED_NV = 1, + VK_RAY_TRACING_LSS_PRIMITIVE_END_CAPS_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkRayTracingLssPrimitiveEndCapsModeNV; +typedef enum VkShaderGroupShaderKHR { + VK_SHADER_GROUP_SHADER_GENERAL_KHR = 0, + VK_SHADER_GROUP_SHADER_CLOSEST_HIT_KHR = 1, + VK_SHADER_GROUP_SHADER_ANY_HIT_KHR = 2, + VK_SHADER_GROUP_SHADER_INTERSECTION_KHR = 3, + VK_SHADER_GROUP_SHADER_MAX_ENUM_KHR = 0x7FFFFFFF +} VkShaderGroupShaderKHR; typedef enum VkMemoryOverallocationBehaviorAMD { VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0, VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2 + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_MAX_ENUM_AMD = 0x7FFFFFFF } VkMemoryOverallocationBehaviorAMD; - -typedef enum VkScopeNV { - VK_SCOPE_DEVICE_NV = 1, - VK_SCOPE_WORKGROUP_NV = 2, - VK_SCOPE_SUBGROUP_NV = 3, - VK_SCOPE_QUEUE_FAMILY_NV = 5 -} VkScopeNV; - -typedef enum VkComponentTypeNV { - VK_COMPONENT_TYPE_FLOAT16_NV = 0, - VK_COMPONENT_TYPE_FLOAT32_NV = 1, - VK_COMPONENT_TYPE_FLOAT64_NV = 2, - VK_COMPONENT_TYPE_SINT8_NV = 3, - VK_COMPONENT_TYPE_SINT16_NV = 4, - VK_COMPONENT_TYPE_SINT32_NV = 5, - VK_COMPONENT_TYPE_SINT64_NV = 6, - VK_COMPONENT_TYPE_UINT8_NV = 7, - VK_COMPONENT_TYPE_UINT16_NV = 8, - VK_COMPONENT_TYPE_UINT32_NV = 9, - VK_COMPONENT_TYPE_UINT64_NV = 10 -} VkComponentTypeNV; - typedef enum VkDeviceDiagnosticsConfigFlagBitsNV { VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV = 1, VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV = 2, - VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV = 4 + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV = 4, + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_ERROR_REPORTING_BIT_NV = 8, + VK_DEVICE_DIAGNOSTICS_CONFIG_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF } VkDeviceDiagnosticsConfigFlagBitsNV; - -typedef enum VkPipelineCreationFeedbackFlagBitsEXT { - VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT = 1, - VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT = 2, - VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT = 4 -} VkPipelineCreationFeedbackFlagBitsEXT; +typedef enum VkPipelineCreationFeedbackFlagBits { + VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT = 1, + VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT = 2, + VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT = 4, + VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT, + VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT, + VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT, + VK_PIPELINE_CREATION_FEEDBACK_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineCreationFeedbackFlagBits; +typedef enum VkPipelineCreationFeedbackFlagBits VkPipelineCreationFeedbackFlagBitsEXT; typedef enum VkPerformanceCounterScopeKHR { VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR = 0, @@ -2950,9 +4499,9 @@ typedef enum VkPerformanceCounterScopeKHR { VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR = 2, VK_QUERY_SCOPE_COMMAND_BUFFER_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR, VK_QUERY_SCOPE_RENDER_PASS_KHR = VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR, - VK_QUERY_SCOPE_COMMAND_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR + VK_QUERY_SCOPE_COMMAND_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR, + VK_PERFORMANCE_COUNTER_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF } VkPerformanceCounterScopeKHR; - typedef enum VkPerformanceCounterUnitKHR { VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR = 0, VK_PERFORMANCE_COUNTER_UNIT_PERCENTAGE_KHR = 1, @@ -2964,77 +4513,791 @@ typedef enum VkPerformanceCounterUnitKHR { VK_PERFORMANCE_COUNTER_UNIT_VOLTS_KHR = 7, VK_PERFORMANCE_COUNTER_UNIT_AMPS_KHR = 8, VK_PERFORMANCE_COUNTER_UNIT_HERTZ_KHR = 9, - VK_PERFORMANCE_COUNTER_UNIT_CYCLES_KHR = 10 + VK_PERFORMANCE_COUNTER_UNIT_CYCLES_KHR = 10, + VK_PERFORMANCE_COUNTER_UNIT_MAX_ENUM_KHR = 0x7FFFFFFF } VkPerformanceCounterUnitKHR; - typedef enum VkPerformanceCounterStorageKHR { VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR = 0, VK_PERFORMANCE_COUNTER_STORAGE_INT64_KHR = 1, VK_PERFORMANCE_COUNTER_STORAGE_UINT32_KHR = 2, VK_PERFORMANCE_COUNTER_STORAGE_UINT64_KHR = 3, VK_PERFORMANCE_COUNTER_STORAGE_FLOAT32_KHR = 4, - VK_PERFORMANCE_COUNTER_STORAGE_FLOAT64_KHR = 5 + VK_PERFORMANCE_COUNTER_STORAGE_FLOAT64_KHR = 5, + VK_PERFORMANCE_COUNTER_STORAGE_MAX_ENUM_KHR = 0x7FFFFFFF } VkPerformanceCounterStorageKHR; - typedef enum VkPerformanceCounterDescriptionFlagBitsKHR { - VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_KHR = 1, - VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_KHR = 2 + VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR = 1, + VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_KHR = VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR, + VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR = 2, + VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_KHR = VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR, + VK_PERFORMANCE_COUNTER_DESCRIPTION_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkPerformanceCounterDescriptionFlagBitsKHR; - - typedef enum VkSemaphoreWaitFlagBits { VK_SEMAPHORE_WAIT_ANY_BIT = 1, - VK_SEMAPHORE_WAIT_ANY_BIT_KHR = VK_SEMAPHORE_WAIT_ANY_BIT + VK_SEMAPHORE_WAIT_ANY_BIT_KHR = VK_SEMAPHORE_WAIT_ANY_BIT, + VK_SEMAPHORE_WAIT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSemaphoreWaitFlagBits; - typedef enum VkSemaphoreWaitFlagBits VkSemaphoreWaitFlagBitsKHR; typedef enum VkPerformanceConfigurationTypeINTEL { - VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL = 0 + VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL = 0, + VK_PERFORMANCE_CONFIGURATION_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkPerformanceConfigurationTypeINTEL; - typedef enum VkQueryPoolSamplingModeINTEL { - VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL = 0 + VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL = 0, + VK_QUERY_POOL_SAMPLING_MODE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkQueryPoolSamplingModeINTEL; - typedef enum VkPerformanceOverrideTypeINTEL { VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL = 0, - VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL = 1 + VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL = 1, + VK_PERFORMANCE_OVERRIDE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkPerformanceOverrideTypeINTEL; - typedef enum VkPerformanceParameterTypeINTEL { VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL = 0, - VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL = 1 + VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL = 1, + VK_PERFORMANCE_PARAMETER_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkPerformanceParameterTypeINTEL; - typedef enum VkPerformanceValueTypeINTEL { VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL = 0, VK_PERFORMANCE_VALUE_TYPE_UINT64_INTEL = 1, VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL = 2, VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL = 3, - VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL = 4 + VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL = 4, + VK_PERFORMANCE_VALUE_TYPE_MAX_ENUM_INTEL = 0x7FFFFFFF } VkPerformanceValueTypeINTEL; - -typedef enum VkLineRasterizationModeEXT { - VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT = 0, - VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT = 1, - VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT = 2, - VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT = 3 -} VkLineRasterizationModeEXT; - - - - -typedef enum VkToolPurposeFlagBitsEXT { - VK_TOOL_PURPOSE_VALIDATION_BIT_EXT = 1, - VK_TOOL_PURPOSE_PROFILING_BIT_EXT = 2, - VK_TOOL_PURPOSE_TRACING_BIT_EXT = 4, - VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT = 8, - VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT = 16, +typedef enum VkLineRasterizationMode { + VK_LINE_RASTERIZATION_MODE_DEFAULT = 0, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR = 1, + VK_LINE_RASTERIZATION_MODE_BRESENHAM = 2, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH = 3, + VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT = VK_LINE_RASTERIZATION_MODE_DEFAULT, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT = VK_LINE_RASTERIZATION_MODE_RECTANGULAR, + VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT = VK_LINE_RASTERIZATION_MODE_BRESENHAM, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH, + VK_LINE_RASTERIZATION_MODE_DEFAULT_KHR = VK_LINE_RASTERIZATION_MODE_DEFAULT, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_KHR = VK_LINE_RASTERIZATION_MODE_RECTANGULAR, + VK_LINE_RASTERIZATION_MODE_BRESENHAM_KHR = VK_LINE_RASTERIZATION_MODE_BRESENHAM, + VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_KHR = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH, + VK_LINE_RASTERIZATION_MODE_MAX_ENUM = 0x7FFFFFFF +} VkLineRasterizationMode; +typedef enum VkLineRasterizationMode VkLineRasterizationModeKHR; + +typedef enum VkLineRasterizationMode VkLineRasterizationModeEXT; + +typedef enum VkToolPurposeFlagBits { + VK_TOOL_PURPOSE_VALIDATION_BIT = 1, + VK_TOOL_PURPOSE_PROFILING_BIT = 2, + VK_TOOL_PURPOSE_TRACING_BIT = 4, + VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT = 8, + VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT = 16, + VK_TOOL_PURPOSE_VALIDATION_BIT_EXT = VK_TOOL_PURPOSE_VALIDATION_BIT, + VK_TOOL_PURPOSE_PROFILING_BIT_EXT = VK_TOOL_PURPOSE_PROFILING_BIT, + VK_TOOL_PURPOSE_TRACING_BIT_EXT = VK_TOOL_PURPOSE_TRACING_BIT, + VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT, + VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT, VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT = 32, - VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT = 64 -} VkToolPurposeFlagBitsEXT; + VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT = 64, + VK_TOOL_PURPOSE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkToolPurposeFlagBits; +typedef enum VkToolPurposeFlagBits VkToolPurposeFlagBitsEXT; + +typedef enum VkFragmentShadingRateNV { + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV = 0, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV = 1, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV = 4, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV = 5, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV = 6, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV = 9, + VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV = 10, + VK_FRAGMENT_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV = 11, + VK_FRAGMENT_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV = 12, + VK_FRAGMENT_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV = 13, + VK_FRAGMENT_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV = 14, + VK_FRAGMENT_SHADING_RATE_NO_INVOCATIONS_NV = 15, + VK_FRAGMENT_SHADING_RATE_MAX_ENUM_NV = 0x7FFFFFFF +} VkFragmentShadingRateNV; +typedef enum VkFragmentShadingRateTypeNV { + VK_FRAGMENT_SHADING_RATE_TYPE_FRAGMENT_SIZE_NV = 0, + VK_FRAGMENT_SHADING_RATE_TYPE_ENUMS_NV = 1, + VK_FRAGMENT_SHADING_RATE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkFragmentShadingRateTypeNV; +typedef enum VkSubpassMergeStatusEXT { + VK_SUBPASS_MERGE_STATUS_MERGED_EXT = 0, + VK_SUBPASS_MERGE_STATUS_DISALLOWED_EXT = 1, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SIDE_EFFECTS_EXT = 2, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SAMPLES_MISMATCH_EXT = 3, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_VIEWS_MISMATCH_EXT = 4, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_ALIASING_EXT = 5, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPENDENCIES_EXT = 6, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INCOMPATIBLE_INPUT_ATTACHMENT_EXT = 7, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_TOO_MANY_ATTACHMENTS_EXT = 8, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INSUFFICIENT_STORAGE_EXT = 9, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPTH_STENCIL_COUNT_EXT = 10, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_RESOLVE_ATTACHMENT_REUSE_EXT = 11, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SINGLE_SUBPASS_EXT = 12, + VK_SUBPASS_MERGE_STATUS_NOT_MERGED_UNSPECIFIED_EXT = 13, + VK_SUBPASS_MERGE_STATUS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkSubpassMergeStatusEXT; +typedef uint64_t VkAccessFlagBits2; +static const VkAccessFlagBits2 VK_ACCESS_2_NONE = 0; +static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT = 1; +static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT = 2; +static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT = 4; +static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT = 8; +static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT = 16; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT = 32; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT = 64; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT = 128; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT = 256; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 512; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 1024; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT = 2048; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT = 4096; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT = 8192; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT = 16384; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT = 32768; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT = 65536; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT = 4294967296; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT = 8589934592; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT = 17179869184; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_TILE_ATTACHMENT_READ_BIT_QCOM = 2251799813685248; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_TILE_ATTACHMENT_WRITE_BIT_QCOM = 4503599627370496; +static const VkAccessFlagBits2 VK_ACCESS_2_NONE_KHR = 0; +static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR = 1; +static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT_KHR = 2; +static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR = 4; +static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT_KHR = 8; +static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR = 16; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT_KHR = 32; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT_KHR = 64; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR = 128; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR = 256; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR = 512; +static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR = 1024; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT_KHR = 2048; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR = 4096; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT_KHR = 8192; +static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT_KHR = 16384; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT_KHR = 32768; +static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT_KHR = 65536; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR = 4294967296; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR = 8589934592; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR = 17179869184; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 33554432; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 67108864; +static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 134217728; +static const VkAccessFlagBits2 VK_ACCESS_2_CONDITIONAL_RENDERING_READ_BIT_EXT = 1048576; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_NV = 131072; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_NV = 262144; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_EXT = 131072; +static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_EXT = 262144; +static const VkAccessFlagBits2 VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 8388608; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADING_RATE_IMAGE_READ_BIT_NV = 8388608; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR = 2097152; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 4194304; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_NV = 2097152; +static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 4194304; +static const VkAccessFlagBits2 VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 16777216; +static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 524288; +static const VkAccessFlagBits2 VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT = 2199023255552; +static const VkAccessFlagBits2 VK_ACCESS_2_INVOCATION_MASK_READ_BIT_HUAWEI = 549755813888; +static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_BINDING_TABLE_READ_BIT_KHR = 1099511627776; +static const VkAccessFlagBits2 VK_ACCESS_2_MICROMAP_READ_BIT_EXT = 17592186044416; +static const VkAccessFlagBits2 VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT = 35184372088832; +static const VkAccessFlagBits2 VK_ACCESS_2_OPTICAL_FLOW_READ_BIT_NV = 4398046511104; +static const VkAccessFlagBits2 VK_ACCESS_2_OPTICAL_FLOW_WRITE_BIT_NV = 8796093022208; + +typedef VkAccessFlagBits2 VkAccessFlagBits2KHR; + +typedef uint64_t VkPipelineStageFlagBits2; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE = 0; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT = 1; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT = 2; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT = 4; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT = 8; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT = 16; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT = 32; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT = 64; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT = 128; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT = 256; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT = 512; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT = 1024; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT = 2048; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT = 4096; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT = 4096; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT = 8192; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT = 16384; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT = 32768; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT = 65536; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT = 4294967296; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT = 8589934592; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT = 17179869184; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT = 34359738368; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT = 68719476736; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT = 137438953472; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT = 274877906944; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE_KHR = 0; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR = 1; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR = 2; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR = 4; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR = 8; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR = 16; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR = 32; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR = 64; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR = 128; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR = 256; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR = 512; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR = 1024; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR = 2048; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR = 4096; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR = 4096; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR = 8192; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT_KHR = 16384; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR = 32768; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR = 65536; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT_KHR = 4294967296; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR = 8589934592; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT_KHR = 17179869184; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR = 34359738368; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR = 68719476736; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR = 137438953472; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR = 274877906944; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT = 16777216; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT = 262144; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV = 131072; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_EXT = 131072; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 4194304; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SHADING_RATE_IMAGE_BIT_NV = 4194304; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 33554432; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR = 2097152; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_NV = 2097152; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 33554432; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 8388608; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_NV = 524288; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_NV = 1048576; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT = 524288; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT = 1048576; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SUBPASS_SHADER_BIT_HUAWEI = 549755813888; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI = 549755813888; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INVOCATION_MASK_BIT_HUAWEI = 1099511627776; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_COPY_BIT_KHR = 268435456; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT = 1073741824; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLUSTER_CULLING_SHADER_BIT_HUAWEI = 2199023255552; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_OPTICAL_FLOW_BIT_NV = 536870912; +static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CONVERT_COOPERATIVE_VECTOR_MATRIX_BIT_NV = 17592186044416; + +typedef VkPipelineStageFlagBits2 VkPipelineStageFlagBits2KHR; + +typedef enum VkProvokingVertexModeEXT { + VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT = 0, + VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT = 1, + VK_PROVOKING_VERTEX_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkProvokingVertexModeEXT; +typedef enum VkHostImageCopyFlagBits { + VK_HOST_IMAGE_COPY_MEMCPY = 1, + VK_HOST_IMAGE_COPY_MEMCPY_EXT = VK_HOST_IMAGE_COPY_MEMCPY, + VK_HOST_IMAGE_COPY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkHostImageCopyFlagBits; +typedef enum VkHostImageCopyFlagBits VkHostImageCopyFlagBitsEXT; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef enum VkImageConstraintsInfoFlagBitsFUCHSIA { + VK_IMAGE_CONSTRAINTS_INFO_CPU_READ_RARELY_FUCHSIA = 1, + VK_IMAGE_CONSTRAINTS_INFO_CPU_READ_OFTEN_FUCHSIA = 2, + VK_IMAGE_CONSTRAINTS_INFO_CPU_WRITE_RARELY_FUCHSIA = 4, + VK_IMAGE_CONSTRAINTS_INFO_CPU_WRITE_OFTEN_FUCHSIA = 8, + VK_IMAGE_CONSTRAINTS_INFO_PROTECTED_OPTIONAL_FUCHSIA = 16, + VK_IMAGE_CONSTRAINTS_INFO_FLAG_BITS_MAX_ENUM_FUCHSIA = 0x7FFFFFFF +} VkImageConstraintsInfoFlagBitsFUCHSIA; +#endif + +typedef uint64_t VkFormatFeatureFlagBits2; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT = 1; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT = 2; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT = 4; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT = 8; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT = 16; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 32; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT = 64; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT = 128; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT = 256; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT = 512; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT = 1024; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT = 2048; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 4096; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT = 16384; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT = 32768; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 65536; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT = 131072; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 262144; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 524288; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 1048576; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 2097152; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT = 4194304; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT = 8388608; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT = 2147483648; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT = 4294967296; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT = 8589934592; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT = 8192; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT = 70368744177664; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR = 536870912; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_DENSITY_MAP_BIT_EXT = 16777216; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 1073741824; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT = 70368744177664; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT_KHR = 1; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT_KHR = 2; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT_KHR = 4; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR = 8; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT_KHR = 16; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT_KHR = 32; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT_KHR = 64; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT_KHR = 128; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT_KHR = 256; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT_KHR = 512; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT_KHR = 1024; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT_KHR = 2048; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT_KHR = 4096; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT_KHR = 16384; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT_KHR = 32768; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = 131072; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = 262144; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = 524288; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = 1048576; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = 2097152; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT_KHR = 4194304; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT_KHR = 8388608; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT_KHR = 2147483648; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR = 4294967296; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT_KHR = 8589934592; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT_KHR = 65536; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 8192; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_ACCELERATION_STRUCTURE_RADIUS_BUFFER_BIT_NV = 2251799813685248; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_LINEAR_COLOR_ATTACHMENT_BIT_NV = 274877906944; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_IMAGE_BIT_QCOM = 17179869184; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_SAMPLED_IMAGE_BIT_QCOM = 34359738368; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLOCK_MATCHING_BIT_QCOM = 68719476736; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BOX_FILTER_SAMPLED_BIT_QCOM = 137438953472; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_IMAGE_BIT_NV = 1099511627776; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_VECTOR_BIT_NV = 2199023255552; +static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_COST_BIT_NV = 4398046511104; + +typedef VkFormatFeatureFlagBits2 VkFormatFeatureFlagBits2KHR; + +typedef enum VkRenderingFlagBits { + VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT = 1, + VK_RENDERING_SUSPENDING_BIT = 2, + VK_RENDERING_RESUMING_BIT = 4, + VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT, + VK_RENDERING_SUSPENDING_BIT_KHR = VK_RENDERING_SUSPENDING_BIT, + VK_RENDERING_RESUMING_BIT_KHR = VK_RENDERING_RESUMING_BIT, + VK_RENDERING_CONTENTS_INLINE_BIT_EXT = 16, + VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT = 8, + VK_RENDERING_CONTENTS_INLINE_BIT_KHR = 16, + VK_RENDERING_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkRenderingFlagBits; +typedef enum VkRenderingFlagBits VkRenderingFlagBitsKHR; + +typedef enum VkPipelineDepthStencilStateCreateFlagBits { + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = 1, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = 2, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT = 1, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT = 2, + VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineDepthStencilStateCreateFlagBits; +typedef enum VkPipelineColorBlendStateCreateFlagBits { + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM = 1, + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT = 1, + VK_PIPELINE_COLOR_BLEND_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkPipelineColorBlendStateCreateFlagBits; +typedef enum VkImageCompressionFlagBitsEXT { + VK_IMAGE_COMPRESSION_DEFAULT_EXT = 0, + VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT = 1, + VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT = 2, + VK_IMAGE_COMPRESSION_DISABLED_EXT = 4, + VK_IMAGE_COMPRESSION_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkImageCompressionFlagBitsEXT; +typedef enum VkImageCompressionFixedRateFlagBitsEXT { + VK_IMAGE_COMPRESSION_FIXED_RATE_NONE_EXT = 0, + VK_IMAGE_COMPRESSION_FIXED_RATE_1BPC_BIT_EXT = 1, + VK_IMAGE_COMPRESSION_FIXED_RATE_2BPC_BIT_EXT = 2, + VK_IMAGE_COMPRESSION_FIXED_RATE_3BPC_BIT_EXT = 4, + VK_IMAGE_COMPRESSION_FIXED_RATE_4BPC_BIT_EXT = 8, + VK_IMAGE_COMPRESSION_FIXED_RATE_5BPC_BIT_EXT = 16, + VK_IMAGE_COMPRESSION_FIXED_RATE_6BPC_BIT_EXT = 32, + VK_IMAGE_COMPRESSION_FIXED_RATE_7BPC_BIT_EXT = 64, + VK_IMAGE_COMPRESSION_FIXED_RATE_8BPC_BIT_EXT = 128, + VK_IMAGE_COMPRESSION_FIXED_RATE_9BPC_BIT_EXT = 256, + VK_IMAGE_COMPRESSION_FIXED_RATE_10BPC_BIT_EXT = 512, + VK_IMAGE_COMPRESSION_FIXED_RATE_11BPC_BIT_EXT = 1024, + VK_IMAGE_COMPRESSION_FIXED_RATE_12BPC_BIT_EXT = 2048, + VK_IMAGE_COMPRESSION_FIXED_RATE_13BPC_BIT_EXT = 4096, + VK_IMAGE_COMPRESSION_FIXED_RATE_14BPC_BIT_EXT = 8192, + VK_IMAGE_COMPRESSION_FIXED_RATE_15BPC_BIT_EXT = 16384, + VK_IMAGE_COMPRESSION_FIXED_RATE_16BPC_BIT_EXT = 32768, + VK_IMAGE_COMPRESSION_FIXED_RATE_17BPC_BIT_EXT = 65536, + VK_IMAGE_COMPRESSION_FIXED_RATE_18BPC_BIT_EXT = 131072, + VK_IMAGE_COMPRESSION_FIXED_RATE_19BPC_BIT_EXT = 262144, + VK_IMAGE_COMPRESSION_FIXED_RATE_20BPC_BIT_EXT = 524288, + VK_IMAGE_COMPRESSION_FIXED_RATE_21BPC_BIT_EXT = 1048576, + VK_IMAGE_COMPRESSION_FIXED_RATE_22BPC_BIT_EXT = 2097152, + VK_IMAGE_COMPRESSION_FIXED_RATE_23BPC_BIT_EXT = 4194304, + VK_IMAGE_COMPRESSION_FIXED_RATE_24BPC_BIT_EXT = 8388608, + VK_IMAGE_COMPRESSION_FIXED_RATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkImageCompressionFixedRateFlagBitsEXT; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef enum VkExportMetalObjectTypeFlagBitsEXT { + VK_EXPORT_METAL_OBJECT_TYPE_METAL_DEVICE_BIT_EXT = 1, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_COMMAND_QUEUE_BIT_EXT = 2, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_BUFFER_BIT_EXT = 4, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT = 8, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT = 16, + VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT = 32, + VK_EXPORT_METAL_OBJECT_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkExportMetalObjectTypeFlagBitsEXT; +#endif + +typedef enum VkPipelineRobustnessBufferBehavior { + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT = 0, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED = 1, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS = 2, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2 = 3, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT_EXT = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED_EXT = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2, + VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF +} VkPipelineRobustnessBufferBehavior; +typedef enum VkPipelineRobustnessBufferBehavior VkPipelineRobustnessBufferBehaviorEXT; + +typedef enum VkPipelineRobustnessImageBehavior { + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT = 0, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED = 1, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS = 2, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2 = 3, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED_EXT = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_EXT = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2_EXT = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2, + VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_MAX_ENUM = 0x7FFFFFFF +} VkPipelineRobustnessImageBehavior; +typedef enum VkPipelineRobustnessImageBehavior VkPipelineRobustnessImageBehaviorEXT; + +typedef enum VkDeviceAddressBindingFlagBitsEXT { + VK_DEVICE_ADDRESS_BINDING_INTERNAL_OBJECT_BIT_EXT = 1, + VK_DEVICE_ADDRESS_BINDING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceAddressBindingFlagBitsEXT; +typedef enum VkDeviceAddressBindingTypeEXT { + VK_DEVICE_ADDRESS_BINDING_TYPE_BIND_EXT = 0, + VK_DEVICE_ADDRESS_BINDING_TYPE_UNBIND_EXT = 1, + VK_DEVICE_ADDRESS_BINDING_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceAddressBindingTypeEXT; +typedef enum VkMicromapTypeEXT { + VK_MICROMAP_TYPE_OPACITY_MICROMAP_EXT = 0, + VK_MICROMAP_TYPE_DISPLACEMENT_MICROMAP_NV = 1000397000, + VK_MICROMAP_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkMicromapTypeEXT; +typedef enum VkBuildMicromapModeEXT { + VK_BUILD_MICROMAP_MODE_BUILD_EXT = 0, + VK_BUILD_MICROMAP_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkBuildMicromapModeEXT; +typedef enum VkCopyMicromapModeEXT { + VK_COPY_MICROMAP_MODE_CLONE_EXT = 0, + VK_COPY_MICROMAP_MODE_SERIALIZE_EXT = 1, + VK_COPY_MICROMAP_MODE_DESERIALIZE_EXT = 2, + VK_COPY_MICROMAP_MODE_COMPACT_EXT = 3, + VK_COPY_MICROMAP_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkCopyMicromapModeEXT; +typedef enum VkBuildMicromapFlagBitsEXT { + VK_BUILD_MICROMAP_PREFER_FAST_TRACE_BIT_EXT = 1, + VK_BUILD_MICROMAP_PREFER_FAST_BUILD_BIT_EXT = 2, + VK_BUILD_MICROMAP_ALLOW_COMPACTION_BIT_EXT = 4, + VK_BUILD_MICROMAP_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkBuildMicromapFlagBitsEXT; +typedef enum VkMicromapCreateFlagBitsEXT { + VK_MICROMAP_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = 1, + VK_MICROMAP_CREATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkMicromapCreateFlagBitsEXT; +typedef enum VkOpacityMicromapFormatEXT { + VK_OPACITY_MICROMAP_FORMAT_2_STATE_EXT = 1, + VK_OPACITY_MICROMAP_FORMAT_4_STATE_EXT = 2, + VK_OPACITY_MICROMAP_FORMAT_MAX_ENUM_EXT = 0x7FFFFFFF +} VkOpacityMicromapFormatEXT; +typedef enum VkOpacityMicromapSpecialIndexEXT { + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_TRANSPARENT_EXT = -1, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_OPAQUE_EXT = -2, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_TRANSPARENT_EXT = -3, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_OPAQUE_EXT = -4, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_CLUSTER_GEOMETRY_DISABLE_OPACITY_MICROMAP_NV = -5, + VK_OPACITY_MICROMAP_SPECIAL_INDEX_MAX_ENUM_EXT = 0x7FFFFFFF +} VkOpacityMicromapSpecialIndexEXT; +typedef enum VkDeviceFaultVendorBinaryHeaderVersionEXT { + VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT = 1, + VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceFaultVendorBinaryHeaderVersionEXT; +typedef enum VkIndirectCommandsLayoutUsageFlagBitsEXT { + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_EXT = 1, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_EXT = 2, + VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkIndirectCommandsLayoutUsageFlagBitsEXT; +typedef enum VkIndirectExecutionSetInfoTypeEXT { + VK_INDIRECT_EXECUTION_SET_INFO_TYPE_PIPELINES_EXT = 0, + VK_INDIRECT_EXECUTION_SET_INFO_TYPE_SHADER_OBJECTS_EXT = 1, + VK_INDIRECT_EXECUTION_SET_INFO_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkIndirectExecutionSetInfoTypeEXT; +typedef enum VkIndirectCommandsInputModeFlagBitsEXT { + VK_INDIRECT_COMMANDS_INPUT_MODE_VULKAN_INDEX_BUFFER_EXT = 1, + VK_INDIRECT_COMMANDS_INPUT_MODE_DXGI_INDEX_BUFFER_EXT = 2, + VK_INDIRECT_COMMANDS_INPUT_MODE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkIndirectCommandsInputModeFlagBitsEXT; +typedef enum VkFrameBoundaryFlagBitsEXT { + VK_FRAME_BOUNDARY_FRAME_END_BIT_EXT = 1, + VK_FRAME_BOUNDARY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkFrameBoundaryFlagBitsEXT; +typedef uint64_t VkMemoryDecompressionMethodFlagBitsNV; +static const VkMemoryDecompressionMethodFlagBitsNV VK_MEMORY_DECOMPRESSION_METHOD_GDEFLATE_1_0_BIT_NV = 1; + +typedef enum VkDepthBiasRepresentationEXT { + VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORMAT_EXT = 0, + VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT = 1, + VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT = 2, + VK_DEPTH_BIAS_REPRESENTATION_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDepthBiasRepresentationEXT; +typedef enum VkDirectDriverLoadingModeLUNARG { + VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG = 0, + VK_DIRECT_DRIVER_LOADING_MODE_INCLUSIVE_LUNARG = 1, + VK_DIRECT_DRIVER_LOADING_MODE_MAX_ENUM_LUNARG = 0x7FFFFFFF +} VkDirectDriverLoadingModeLUNARG; +typedef uint64_t VkPipelineCreateFlagBits2; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISABLE_OPTIMIZATION_BIT = 1; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_ALLOW_DERIVATIVES_BIT = 2; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DERIVATIVE_BIT = 4; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 8; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISPATCH_BASE_BIT = 16; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT = 256; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_EARLY_RETURN_ON_FAILURE_BIT = 512; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_NO_PROTECTED_ACCESS_BIT = 134217728; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT = 1073741824; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_EXECUTION_GRAPH_BIT_AMDX = 4294967296; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_SKIP_BUILT_IN_PRIMITIVES_BIT_KHR = 4096; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_ALLOW_SPHERES_AND_LINEAR_SWEPT_SPHERES_BIT_NV = 8589934592; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_ENABLE_LEGACY_DITHERING_BIT_EXT = 17179869184; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISABLE_OPTIMIZATION_BIT_KHR = 1; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_ALLOW_DERIVATIVES_BIT_KHR = 2; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DERIVATIVE_BIT_KHR = 4; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = 8; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISPATCH_BASE_BIT_KHR = 16; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DEFER_COMPILE_BIT_NV = 32; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_CAPTURE_STATISTICS_BIT_KHR = 64; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR = 128; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_KHR = 256; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_EARLY_RETURN_ON_FAILURE_BIT_KHR = 512; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_LINK_TIME_OPTIMIZATION_BIT_EXT = 1024; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT = 8388608; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_LIBRARY_BIT_KHR = 2048; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR = 4096; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_SKIP_AABBS_BIT_KHR = 8192; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR = 16384; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR = 32768; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR = 65536; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR = 131072; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR = 524288; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_INDIRECT_BINDABLE_BIT_NV = 262144; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_ALLOW_MOTION_BIT_NV = 1048576; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 2097152; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 4194304; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_OPACITY_MICROMAP_BIT_EXT = 16777216; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 33554432; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 67108864; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_NO_PROTECTED_ACCESS_BIT_EXT = 134217728; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_PROTECTED_ACCESS_ONLY_BIT_EXT = 1073741824; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_RAY_TRACING_DISPLACEMENT_MICROMAP_BIT_NV = 268435456; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DESCRIPTOR_BUFFER_BIT_EXT = 536870912; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_DISALLOW_OPACITY_MICROMAP_BIT_ARM = 137438953472; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_CAPTURE_DATA_BIT_KHR = 2147483648; +static const VkPipelineCreateFlagBits2 VK_PIPELINE_CREATE_2_INDIRECT_BINDABLE_BIT_EXT = 274877906944; + +typedef VkPipelineCreateFlagBits2 VkPipelineCreateFlagBits2KHR; + +typedef uint64_t VkBufferUsageFlagBits2; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFER_SRC_BIT = 1; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFER_DST_BIT = 2; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_UNIFORM_TEXEL_BUFFER_BIT = 4; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_STORAGE_TEXEL_BUFFER_BIT = 8; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT = 16; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT = 32; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_INDEX_BUFFER_BIT = 64; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VERTEX_BUFFER_BIT = 128; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_INDIRECT_BUFFER_BIT = 256; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT = 131072; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_EXECUTION_GRAPH_SCRATCH_BIT_AMDX = 33554432; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFER_SRC_BIT_KHR = 1; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFER_DST_BIT_KHR = 2; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR = 4; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_STORAGE_TEXEL_BUFFER_BIT_KHR = 8; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT_KHR = 16; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT_KHR = 32; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_INDEX_BUFFER_BIT_KHR = 64; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VERTEX_BUFFER_BIT_KHR = 128; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_INDIRECT_BUFFER_BIT_KHR = 256; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_CONDITIONAL_RENDERING_BIT_EXT = 512; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_SHADER_BINDING_TABLE_BIT_KHR = 1024; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_RAY_TRACING_BIT_NV = 1024; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 2048; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 4096; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VIDEO_DECODE_SRC_BIT_KHR = 8192; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VIDEO_DECODE_DST_BIT_KHR = 16384; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VIDEO_ENCODE_DST_BIT_KHR = 32768; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_VIDEO_ENCODE_SRC_BIT_KHR = 65536; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT_KHR = 131072; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR = 524288; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR = 1048576; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT = 2097152; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT = 4194304; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT = 67108864; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_MICROMAP_BUILD_INPUT_READ_ONLY_BIT_EXT = 8388608; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_MICROMAP_STORAGE_BIT_EXT = 16777216; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_TILE_MEMORY_QCOM = 134217728; +static const VkBufferUsageFlagBits2 VK_BUFFER_USAGE_2_PREPROCESS_BUFFER_BIT_EXT = 2147483648; + +typedef VkBufferUsageFlagBits2 VkBufferUsageFlagBits2KHR; + +typedef enum VkPartitionedAccelerationStructureOpTypeNV { + VK_PARTITIONED_ACCELERATION_STRUCTURE_OP_TYPE_WRITE_INSTANCE_NV = 0, + VK_PARTITIONED_ACCELERATION_STRUCTURE_OP_TYPE_UPDATE_INSTANCE_NV = 1, + VK_PARTITIONED_ACCELERATION_STRUCTURE_OP_TYPE_WRITE_PARTITION_TRANSLATION_NV = 2, + VK_PARTITIONED_ACCELERATION_STRUCTURE_OP_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkPartitionedAccelerationStructureOpTypeNV; +typedef enum VkPartitionedAccelerationStructureInstanceFlagBitsNV { + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE_BIT_NV = 1, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FLIP_FACING_BIT_NV = 2, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE_BIT_NV = 4, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE_BIT_NV = 8, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_ENABLE_EXPLICIT_BOUNDING_BOX_NV = 16, + VK_PARTITIONED_ACCELERATION_STRUCTURE_INSTANCE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkPartitionedAccelerationStructureInstanceFlagBitsNV; +typedef enum VkAntiLagModeAMD { + VK_ANTI_LAG_MODE_DRIVER_CONTROL_AMD = 0, + VK_ANTI_LAG_MODE_ON_AMD = 1, + VK_ANTI_LAG_MODE_OFF_AMD = 2, + VK_ANTI_LAG_MODE_MAX_ENUM_AMD = 0x7FFFFFFF +} VkAntiLagModeAMD; +typedef enum VkAntiLagStageAMD { + VK_ANTI_LAG_STAGE_INPUT_AMD = 0, + VK_ANTI_LAG_STAGE_PRESENT_AMD = 1, + VK_ANTI_LAG_STAGE_MAX_ENUM_AMD = 0x7FFFFFFF +} VkAntiLagStageAMD; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef enum VkDisplacementMicromapFormatNV { + VK_DISPLACEMENT_MICROMAP_FORMAT_64_TRIANGLES_64_BYTES_NV = 1, + VK_DISPLACEMENT_MICROMAP_FORMAT_256_TRIANGLES_128_BYTES_NV = 2, + VK_DISPLACEMENT_MICROMAP_FORMAT_1024_TRIANGLES_128_BYTES_NV = 3, + VK_DISPLACEMENT_MICROMAP_FORMAT_MAX_ENUM_NV = 0x7FFFFFFF +} VkDisplacementMicromapFormatNV; +#endif + +typedef enum VkShaderCreateFlagBitsEXT { + VK_SHADER_CREATE_LINK_STAGE_BIT_EXT = 1, + VK_SHADER_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = 2, + VK_SHADER_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = 4, + VK_SHADER_CREATE_NO_TASK_SHADER_BIT_EXT = 8, + VK_SHADER_CREATE_DISPATCH_BASE_BIT_EXT = 16, + VK_SHADER_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_EXT = 32, + VK_SHADER_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 64, + VK_SHADER_CREATE_INDIRECT_BINDABLE_BIT_EXT = 128, + VK_SHADER_CREATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkShaderCreateFlagBitsEXT; +typedef enum VkShaderCodeTypeEXT { + VK_SHADER_CODE_TYPE_BINARY_EXT = 0, + VK_SHADER_CODE_TYPE_SPIRV_EXT = 1, + VK_SHADER_CODE_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkShaderCodeTypeEXT; +typedef enum VkScopeKHR { + VK_SCOPE_DEVICE_KHR = 1, + VK_SCOPE_WORKGROUP_KHR = 2, + VK_SCOPE_SUBGROUP_KHR = 3, + VK_SCOPE_QUEUE_FAMILY_KHR = 5, + VK_SCOPE_DEVICE_NV = VK_SCOPE_DEVICE_KHR, + VK_SCOPE_WORKGROUP_NV = VK_SCOPE_WORKGROUP_KHR, + VK_SCOPE_SUBGROUP_NV = VK_SCOPE_SUBGROUP_KHR, + VK_SCOPE_QUEUE_FAMILY_NV = VK_SCOPE_QUEUE_FAMILY_KHR, + VK_SCOPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkScopeKHR; +typedef enum VkComponentTypeKHR { + VK_COMPONENT_TYPE_FLOAT16_KHR = 0, + VK_COMPONENT_TYPE_FLOAT32_KHR = 1, + VK_COMPONENT_TYPE_FLOAT64_KHR = 2, + VK_COMPONENT_TYPE_SINT8_KHR = 3, + VK_COMPONENT_TYPE_SINT16_KHR = 4, + VK_COMPONENT_TYPE_SINT32_KHR = 5, + VK_COMPONENT_TYPE_SINT64_KHR = 6, + VK_COMPONENT_TYPE_UINT8_KHR = 7, + VK_COMPONENT_TYPE_UINT16_KHR = 8, + VK_COMPONENT_TYPE_UINT32_KHR = 9, + VK_COMPONENT_TYPE_UINT64_KHR = 10, + VK_COMPONENT_TYPE_BFLOAT16_KHR = 1000141000, + VK_COMPONENT_TYPE_FLOAT16_NV = VK_COMPONENT_TYPE_FLOAT16_KHR, + VK_COMPONENT_TYPE_FLOAT32_NV = VK_COMPONENT_TYPE_FLOAT32_KHR, + VK_COMPONENT_TYPE_FLOAT64_NV = VK_COMPONENT_TYPE_FLOAT64_KHR, + VK_COMPONENT_TYPE_SINT8_NV = VK_COMPONENT_TYPE_SINT8_KHR, + VK_COMPONENT_TYPE_SINT16_NV = VK_COMPONENT_TYPE_SINT16_KHR, + VK_COMPONENT_TYPE_SINT32_NV = VK_COMPONENT_TYPE_SINT32_KHR, + VK_COMPONENT_TYPE_SINT64_NV = VK_COMPONENT_TYPE_SINT64_KHR, + VK_COMPONENT_TYPE_UINT8_NV = VK_COMPONENT_TYPE_UINT8_KHR, + VK_COMPONENT_TYPE_UINT16_NV = VK_COMPONENT_TYPE_UINT16_KHR, + VK_COMPONENT_TYPE_UINT32_NV = VK_COMPONENT_TYPE_UINT32_KHR, + VK_COMPONENT_TYPE_UINT64_NV = VK_COMPONENT_TYPE_UINT64_KHR, + VK_COMPONENT_TYPE_SINT8_PACKED_NV = 1000491000, + VK_COMPONENT_TYPE_UINT8_PACKED_NV = 1000491001, + VK_COMPONENT_TYPE_FLOAT_E4M3_NV = 1000491002, + VK_COMPONENT_TYPE_FLOAT_E5M2_NV = 1000491003, + VK_COMPONENT_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} VkComponentTypeKHR; +typedef enum VkScopeKHR VkScopeNV; + +typedef enum VkComponentTypeKHR VkComponentTypeNV; + +typedef enum VkCubicFilterWeightsQCOM { + VK_CUBIC_FILTER_WEIGHTS_CATMULL_ROM_QCOM = 0, + VK_CUBIC_FILTER_WEIGHTS_ZERO_TANGENT_CARDINAL_QCOM = 1, + VK_CUBIC_FILTER_WEIGHTS_B_SPLINE_QCOM = 2, + VK_CUBIC_FILTER_WEIGHTS_MITCHELL_NETRAVALI_QCOM = 3, + VK_CUBIC_FILTER_WEIGHTS_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkCubicFilterWeightsQCOM; +typedef enum VkBlockMatchWindowCompareModeQCOM { + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MIN_QCOM = 0, + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MAX_QCOM = 1, + VK_BLOCK_MATCH_WINDOW_COMPARE_MODE_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkBlockMatchWindowCompareModeQCOM; +typedef enum VkLayeredDriverUnderlyingApiMSFT { + VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT = 0, + VK_LAYERED_DRIVER_UNDERLYING_API_D3D12_MSFT = 1, + VK_LAYERED_DRIVER_UNDERLYING_API_MAX_ENUM_MSFT = 0x7FFFFFFF +} VkLayeredDriverUnderlyingApiMSFT; +typedef enum VkPhysicalDeviceLayeredApiKHR { + VK_PHYSICAL_DEVICE_LAYERED_API_VULKAN_KHR = 0, + VK_PHYSICAL_DEVICE_LAYERED_API_D3D12_KHR = 1, + VK_PHYSICAL_DEVICE_LAYERED_API_METAL_KHR = 2, + VK_PHYSICAL_DEVICE_LAYERED_API_OPENGL_KHR = 3, + VK_PHYSICAL_DEVICE_LAYERED_API_OPENGLES_KHR = 4, + VK_PHYSICAL_DEVICE_LAYERED_API_MAX_ENUM_KHR = 0x7FFFFFFF +} VkPhysicalDeviceLayeredApiKHR; +typedef enum VkDepthClampModeEXT { + VK_DEPTH_CLAMP_MODE_VIEWPORT_RANGE_EXT = 0, + VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT = 1, + VK_DEPTH_CLAMP_MODE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDepthClampModeEXT; +typedef enum VkTileShadingRenderPassFlagBitsQCOM { + VK_TILE_SHADING_RENDER_PASS_ENABLE_BIT_QCOM = 1, + VK_TILE_SHADING_RENDER_PASS_PER_TILE_EXECUTION_BIT_QCOM = 2, + VK_TILE_SHADING_RENDER_PASS_FLAG_BITS_MAX_ENUM_QCOM = 0x7FFFFFFF +} VkTileShadingRenderPassFlagBitsQCOM; +typedef enum VkCooperativeVectorMatrixLayoutNV { + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_ROW_MAJOR_NV = 0, + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_COLUMN_MAJOR_NV = 1, + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_INFERENCING_OPTIMAL_NV = 2, + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_TRAINING_OPTIMAL_NV = 3, + VK_COOPERATIVE_VECTOR_MATRIX_LAYOUT_MAX_ENUM_NV = 0x7FFFFFFF +} VkCooperativeVectorMatrixLayoutNV; typedef enum VkColorSpaceKHR { VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, @@ -3053,32 +5316,33 @@ typedef enum VkColorSpaceKHR { VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014, VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT, - VK_COLOR_SPACE_DISPLAY_NATIVE_AMD = 1000213000 + VK_COLOR_SPACE_DISPLAY_NATIVE_AMD = 1000213000, + VK_COLOR_SPACE_MAX_ENUM_KHR = 0x7FFFFFFF } VkColorSpaceKHR; - typedef enum VkCompositeAlphaFlagBitsKHR { VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 1, VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 2, VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 4, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 8 + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 8, + VK_COMPOSITE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkCompositeAlphaFlagBitsKHR; - typedef enum VkDisplayPlaneAlphaFlagBitsKHR { VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 1, VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 2, VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 4, - VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 8 + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 8, + VK_DISPLAY_PLANE_ALPHA_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkDisplayPlaneAlphaFlagBitsKHR; - typedef enum VkPresentModeKHR { VK_PRESENT_MODE_IMMEDIATE_KHR = 0, VK_PRESENT_MODE_MAILBOX_KHR = 1, VK_PRESENT_MODE_FIFO_KHR = 2, VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000, - VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001 + VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001, + VK_PRESENT_MODE_FIFO_LATEST_READY_EXT = 1000361000, + VK_PRESENT_MODE_MAX_ENUM_KHR = 0x7FFFFFFF } VkPresentModeKHR; - typedef enum VkSurfaceTransformFlagBitsKHR { VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 1, VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 2, @@ -3088,17 +5352,24 @@ typedef enum VkSurfaceTransformFlagBitsKHR { VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 32, VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 64, VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 128, - VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 256 + VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 256, + VK_SURFACE_TRANSFORM_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkSurfaceTransformFlagBitsKHR; - +typedef enum VkDisplaySurfaceStereoTypeNV { + VK_DISPLAY_SURFACE_STEREO_TYPE_NONE_NV = 0, + VK_DISPLAY_SURFACE_STEREO_TYPE_ONBOARD_DIN_NV = 1, + VK_DISPLAY_SURFACE_STEREO_TYPE_HDMI_3D_NV = 2, + VK_DISPLAY_SURFACE_STEREO_TYPE_INBAND_DISPLAYPORT_NV = 3, + VK_DISPLAY_SURFACE_STEREO_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkDisplaySurfaceStereoTypeNV; typedef enum VkDebugReportFlagBitsEXT { VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 1, VK_DEBUG_REPORT_WARNING_BIT_EXT = 2, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 4, VK_DEBUG_REPORT_ERROR_BIT_EXT = 8, - VK_DEBUG_REPORT_DEBUG_BIT_EXT = 16 + VK_DEBUG_REPORT_DEBUG_BIT_EXT = 16, + VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugReportFlagBitsEXT; - typedef enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, @@ -3136,43 +5407,56 @@ typedef enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000, + VK_DEBUG_REPORT_OBJECT_TYPE_CU_MODULE_NVX_EXT = 1000029000, + VK_DEBUG_REPORT_OBJECT_TYPE_CU_FUNCTION_NVX_EXT = 1000029001, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT = 1000165000, + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT = 1000150000, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, + VK_DEBUG_REPORT_OBJECT_TYPE_CUDA_MODULE_NV_EXT = 1000307000, + VK_DEBUG_REPORT_OBJECT_TYPE_CUDA_FUNCTION_NV_EXT = 1000307001, + VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA_EXT = 1000366000, + VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugReportObjectTypeEXT; - +typedef enum VkDeviceMemoryReportEventTypeEXT { + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT = 0, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT = 1, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_IMPORT_EXT = 2, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_UNIMPORT_EXT = 3, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT = 4, + VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceMemoryReportEventTypeEXT; typedef enum VkRasterizationOrderAMD { VK_RASTERIZATION_ORDER_STRICT_AMD = 0, - VK_RASTERIZATION_ORDER_RELAXED_AMD = 1 + VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, + VK_RASTERIZATION_ORDER_MAX_ENUM_AMD = 0x7FFFFFFF } VkRasterizationOrderAMD; - typedef enum VkExternalMemoryHandleTypeFlagBitsNV { VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 1, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 2, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 4, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 8 + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 8, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF } VkExternalMemoryHandleTypeFlagBitsNV; - typedef enum VkExternalMemoryFeatureFlagBitsNV { VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 1, VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 2, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 4 + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 4, + VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF } VkExternalMemoryFeatureFlagBitsNV; - typedef enum VkValidationCheckEXT { VK_VALIDATION_CHECK_ALL_EXT = 0, - VK_VALIDATION_CHECK_SHADERS_EXT = 1 + VK_VALIDATION_CHECK_SHADERS_EXT = 1, + VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF } VkValidationCheckEXT; - typedef enum VkValidationFeatureEnableEXT { VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT = 2, VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT = 3, - VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT = 4 + VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT = 4, + VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF } VkValidationFeatureEnableEXT; - typedef enum VkValidationFeatureDisableEXT { VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0, VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1, @@ -3180,9 +5464,10 @@ typedef enum VkValidationFeatureDisableEXT { VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3, VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, - VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6 + VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, + VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT = 7, + VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF } VkValidationFeatureDisableEXT; - typedef enum VkExternalMemoryHandleTypeFlagBits { VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 1, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 2, @@ -3201,9 +5486,15 @@ typedef enum VkExternalMemoryHandleTypeFlagBits { VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT = 512, VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID = 1024, VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT = 128, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 256 + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 256, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA = 2048, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_RDMA_ADDRESS_BIT_NV = 4096, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_SCREEN_BUFFER_BIT_QNX = 16384, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT = 65536, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_EXT = 131072, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT = 262144, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkExternalMemoryHandleTypeFlagBits; - typedef enum VkExternalMemoryHandleTypeFlagBits VkExternalMemoryHandleTypeFlagBitsKHR; typedef enum VkExternalMemoryFeatureFlagBits { @@ -3212,9 +5503,9 @@ typedef enum VkExternalMemoryFeatureFlagBits { VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 4, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT, VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT + VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkExternalMemoryFeatureFlagBits; - typedef enum VkExternalMemoryFeatureFlagBits VkExternalMemoryFeatureFlagBitsKHR; typedef enum VkExternalSemaphoreHandleTypeFlagBits { @@ -3228,25 +5519,26 @@ typedef enum VkExternalSemaphoreHandleTypeFlagBits { VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA = 128, + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkExternalSemaphoreHandleTypeFlagBits; - typedef enum VkExternalSemaphoreHandleTypeFlagBits VkExternalSemaphoreHandleTypeFlagBitsKHR; typedef enum VkExternalSemaphoreFeatureFlagBits { VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 1, VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 2, VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT + VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkExternalSemaphoreFeatureFlagBits; - typedef enum VkExternalSemaphoreFeatureFlagBits VkExternalSemaphoreFeatureFlagBitsKHR; typedef enum VkSemaphoreImportFlagBits { VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 1, - VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT + VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, + VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSemaphoreImportFlagBits; - typedef enum VkSemaphoreImportFlagBits VkSemaphoreImportFlagBitsKHR; typedef enum VkExternalFenceHandleTypeFlagBits { @@ -3257,45 +5549,46 @@ typedef enum VkExternalFenceHandleTypeFlagBits { VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT, VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT, VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT + VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, + VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkExternalFenceHandleTypeFlagBits; - typedef enum VkExternalFenceHandleTypeFlagBits VkExternalFenceHandleTypeFlagBitsKHR; typedef enum VkExternalFenceFeatureFlagBits { VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 1, VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 2, VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT + VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT, + VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkExternalFenceFeatureFlagBits; - typedef enum VkExternalFenceFeatureFlagBits VkExternalFenceFeatureFlagBitsKHR; typedef enum VkFenceImportFlagBits { VK_FENCE_IMPORT_TEMPORARY_BIT = 1, - VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = VK_FENCE_IMPORT_TEMPORARY_BIT + VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = VK_FENCE_IMPORT_TEMPORARY_BIT, + VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkFenceImportFlagBits; - typedef enum VkFenceImportFlagBits VkFenceImportFlagBitsKHR; typedef enum VkSurfaceCounterFlagBitsEXT { - VK_SURFACE_COUNTER_VBLANK_EXT = 1 + VK_SURFACE_COUNTER_VBLANK_BIT_EXT = 1, + VK_SURFACE_COUNTER_VBLANK_EXT = VK_SURFACE_COUNTER_VBLANK_BIT_EXT, + VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkSurfaceCounterFlagBitsEXT; - typedef enum VkDisplayPowerStateEXT { VK_DISPLAY_POWER_STATE_OFF_EXT = 0, VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1, - VK_DISPLAY_POWER_STATE_ON_EXT = 2 + VK_DISPLAY_POWER_STATE_ON_EXT = 2, + VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDisplayPowerStateEXT; - typedef enum VkDeviceEventTypeEXT { - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0 + VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0, + VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDeviceEventTypeEXT; - typedef enum VkDisplayEventTypeEXT { - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0 + VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0, + VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF } VkDisplayEventTypeEXT; - typedef enum VkPeerMemoryFeatureFlagBits { VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 1, VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 2, @@ -3304,9 +5597,9 @@ typedef enum VkPeerMemoryFeatureFlagBits { VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT, VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_DST_BIT, VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT, - VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT + VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT, + VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkPeerMemoryFeatureFlagBits; - typedef enum VkPeerMemoryFeatureFlagBits VkPeerMemoryFeatureFlagBitsKHR; typedef enum VkMemoryAllocateFlagBits { @@ -3315,24 +5608,25 @@ typedef enum VkMemoryAllocateFlagBits { VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 4, VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT, VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, - VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT + VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, + VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkMemoryAllocateFlagBits; - typedef enum VkMemoryAllocateFlagBits VkMemoryAllocateFlagBitsKHR; typedef enum VkDeviceGroupPresentModeFlagBitsKHR { VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 1, VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 2, VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 4, - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 8 + VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 8, + VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkDeviceGroupPresentModeFlagBitsKHR; - typedef enum VkSwapchainCreateFlagBitsKHR { VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 1, VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 2, - VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR = 4 + VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR = 4, + VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT = 8, + VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF } VkSwapchainCreateFlagBitsKHR; - typedef enum VkSubgroupFeatureFlagBits { VK_SUBGROUP_FEATURE_BASIC_BIT = 1, VK_SUBGROUP_FEATURE_VOTE_BIT = 2, @@ -3342,16 +5636,20 @@ typedef enum VkSubgroupFeatureFlagBits { VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 32, VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 64, VK_SUBGROUP_FEATURE_QUAD_BIT = 128, - VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 256 + VK_SUBGROUP_FEATURE_ROTATE_BIT = 512, + VK_SUBGROUP_FEATURE_ROTATE_CLUSTERED_BIT = 1024, + VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 256, + VK_SUBGROUP_FEATURE_ROTATE_BIT_KHR = VK_SUBGROUP_FEATURE_ROTATE_BIT, + VK_SUBGROUP_FEATURE_ROTATE_CLUSTERED_BIT_KHR = VK_SUBGROUP_FEATURE_ROTATE_CLUSTERED_BIT, + VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkSubgroupFeatureFlagBits; - typedef enum VkTessellationDomainOrigin { VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0, VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1, VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT + VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT, + VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM = 0x7FFFFFFF } VkTessellationDomainOrigin; - typedef enum VkTessellationDomainOrigin VkTessellationDomainOriginKHR; typedef enum VkSamplerYcbcrModelConversion { @@ -3364,27 +5662,27 @@ typedef enum VkSamplerYcbcrModelConversion { VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY, VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709, VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 + VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020, + VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM = 0x7FFFFFFF } VkSamplerYcbcrModelConversion; - typedef enum VkSamplerYcbcrModelConversion VkSamplerYcbcrModelConversionKHR; typedef enum VkSamplerYcbcrRange { VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1, VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_FULL, - VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW + VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, + VK_SAMPLER_YCBCR_RANGE_MAX_ENUM = 0x7FFFFFFF } VkSamplerYcbcrRange; - typedef enum VkSamplerYcbcrRange VkSamplerYcbcrRangeKHR; typedef enum VkChromaLocation { VK_CHROMA_LOCATION_COSITED_EVEN = 0, VK_CHROMA_LOCATION_MIDPOINT = 1, VK_CHROMA_LOCATION_COSITED_EVEN_KHR = VK_CHROMA_LOCATION_COSITED_EVEN, - VK_CHROMA_LOCATION_MIDPOINT_KHR = VK_CHROMA_LOCATION_MIDPOINT + VK_CHROMA_LOCATION_MIDPOINT_KHR = VK_CHROMA_LOCATION_MIDPOINT, + VK_CHROMA_LOCATION_MAX_ENUM = 0x7FFFFFFF } VkChromaLocation; - typedef enum VkChromaLocation VkChromaLocationKHR; typedef enum VkSamplerReductionMode { @@ -3393,36 +5691,39 @@ typedef enum VkSamplerReductionMode { VK_SAMPLER_REDUCTION_MODE_MAX = 2, VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, VK_SAMPLER_REDUCTION_MODE_MIN_EXT = VK_SAMPLER_REDUCTION_MODE_MIN, - VK_SAMPLER_REDUCTION_MODE_MAX_EXT = VK_SAMPLER_REDUCTION_MODE_MAX + VK_SAMPLER_REDUCTION_MODE_MAX_EXT = VK_SAMPLER_REDUCTION_MODE_MAX, + VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_RANGECLAMP_QCOM = 1000521000, + VK_SAMPLER_REDUCTION_MODE_MAX_ENUM = 0x7FFFFFFF } VkSamplerReductionMode; - typedef enum VkSamplerReductionMode VkSamplerReductionModeEXT; typedef enum VkBlendOverlapEXT { VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0, VK_BLEND_OVERLAP_DISJOINT_EXT = 1, - VK_BLEND_OVERLAP_CONJOINT_EXT = 2 + VK_BLEND_OVERLAP_CONJOINT_EXT = 2, + VK_BLEND_OVERLAP_MAX_ENUM_EXT = 0x7FFFFFFF } VkBlendOverlapEXT; - typedef enum VkDebugUtilsMessageSeverityFlagBitsEXT { VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 1, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 16, VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 256, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 4096 + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 4096, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugUtilsMessageSeverityFlagBitsEXT; - typedef enum VkDebugUtilsMessageTypeFlagBitsEXT { VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 1, VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 2, - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 4 + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 4, + VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT = 8, + VK_DEBUG_UTILS_MESSAGE_TYPE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF } VkDebugUtilsMessageTypeFlagBitsEXT; - #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef enum VkFullScreenExclusiveEXT { VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT = 0, VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT = 1, VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT = 2, - VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT = 3 + VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT = 3, + VK_FULL_SCREEN_EXCLUSIVE_MAX_ENUM_EXT = 0x7FFFFFFF } VkFullScreenExclusiveEXT; #endif @@ -3432,19 +5733,154 @@ typedef enum VkShaderFloatControlsIndependence { VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE = 2, VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY, VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL, - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE, + VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_MAX_ENUM = 0x7FFFFFFF } VkShaderFloatControlsIndependence; - typedef enum VkShaderFloatControlsIndependence VkShaderFloatControlsIndependenceKHR; +typedef enum VkFragmentShadingRateCombinerOpKHR { + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR = 0, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR = 1, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR = 2, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR = 3, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR = 4, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_ENUM_KHR = 0x7FFFFFFF +} VkFragmentShadingRateCombinerOpKHR; +typedef enum VkSubmitFlagBits { + VK_SUBMIT_PROTECTED_BIT = 1, + VK_SUBMIT_PROTECTED_BIT_KHR = VK_SUBMIT_PROTECTED_BIT, + VK_SUBMIT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkSubmitFlagBits; +typedef enum VkSubmitFlagBits VkSubmitFlagBitsKHR; + +typedef enum VkGraphicsPipelineLibraryFlagBitsEXT { + VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT = 1, + VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT = 2, + VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT = 4, + VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT = 8, + VK_GRAPHICS_PIPELINE_LIBRARY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkGraphicsPipelineLibraryFlagBitsEXT; +typedef enum VkOpticalFlowGridSizeFlagBitsNV { + VK_OPTICAL_FLOW_GRID_SIZE_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_GRID_SIZE_1X1_BIT_NV = 1, + VK_OPTICAL_FLOW_GRID_SIZE_2X2_BIT_NV = 2, + VK_OPTICAL_FLOW_GRID_SIZE_4X4_BIT_NV = 4, + VK_OPTICAL_FLOW_GRID_SIZE_8X8_BIT_NV = 8, + VK_OPTICAL_FLOW_GRID_SIZE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowGridSizeFlagBitsNV; +typedef enum VkOpticalFlowUsageFlagBitsNV { + VK_OPTICAL_FLOW_USAGE_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_USAGE_INPUT_BIT_NV = 1, + VK_OPTICAL_FLOW_USAGE_OUTPUT_BIT_NV = 2, + VK_OPTICAL_FLOW_USAGE_HINT_BIT_NV = 4, + VK_OPTICAL_FLOW_USAGE_COST_BIT_NV = 8, + VK_OPTICAL_FLOW_USAGE_GLOBAL_FLOW_BIT_NV = 16, + VK_OPTICAL_FLOW_USAGE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowUsageFlagBitsNV; +typedef enum VkOpticalFlowPerformanceLevelNV { + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_SLOW_NV = 1, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_MEDIUM_NV = 2, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_FAST_NV = 3, + VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowPerformanceLevelNV; +typedef enum VkOpticalFlowSessionBindingPointNV { + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_UNKNOWN_NV = 0, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_INPUT_NV = 1, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_REFERENCE_NV = 2, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_HINT_NV = 3, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_FLOW_VECTOR_NV = 4, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_BACKWARD_FLOW_VECTOR_NV = 5, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_COST_NV = 6, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_BACKWARD_COST_NV = 7, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_GLOBAL_FLOW_NV = 8, + VK_OPTICAL_FLOW_SESSION_BINDING_POINT_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowSessionBindingPointNV; +typedef enum VkOpticalFlowSessionCreateFlagBitsNV { + VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_HINT_BIT_NV = 1, + VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_COST_BIT_NV = 2, + VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_GLOBAL_FLOW_BIT_NV = 4, + VK_OPTICAL_FLOW_SESSION_CREATE_ALLOW_REGIONS_BIT_NV = 8, + VK_OPTICAL_FLOW_SESSION_CREATE_BOTH_DIRECTIONS_BIT_NV = 16, + VK_OPTICAL_FLOW_SESSION_CREATE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowSessionCreateFlagBitsNV; +typedef enum VkOpticalFlowExecuteFlagBitsNV { + VK_OPTICAL_FLOW_EXECUTE_DISABLE_TEMPORAL_HINTS_BIT_NV = 1, + VK_OPTICAL_FLOW_EXECUTE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkOpticalFlowExecuteFlagBitsNV; +typedef enum VkDeviceFaultAddressTypeEXT { + VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT = 0, + VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT = 1, + VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT = 2, + VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT = 3, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT = 4, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT = 5, + VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT = 6, + VK_DEVICE_FAULT_ADDRESS_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkDeviceFaultAddressTypeEXT; +typedef enum VkPresentScalingFlagBitsEXT { + VK_PRESENT_SCALING_ONE_TO_ONE_BIT_EXT = 1, + VK_PRESENT_SCALING_ASPECT_RATIO_STRETCH_BIT_EXT = 2, + VK_PRESENT_SCALING_STRETCH_BIT_EXT = 4, + VK_PRESENT_SCALING_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPresentScalingFlagBitsEXT; +typedef enum VkPresentGravityFlagBitsEXT { + VK_PRESENT_GRAVITY_MIN_BIT_EXT = 1, + VK_PRESENT_GRAVITY_MAX_BIT_EXT = 2, + VK_PRESENT_GRAVITY_CENTERED_BIT_EXT = 4, + VK_PRESENT_GRAVITY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF +} VkPresentGravityFlagBitsEXT; +typedef enum VkLayerSettingTypeEXT { + VK_LAYER_SETTING_TYPE_BOOL32_EXT = 0, + VK_LAYER_SETTING_TYPE_INT32_EXT = 1, + VK_LAYER_SETTING_TYPE_INT64_EXT = 2, + VK_LAYER_SETTING_TYPE_UINT32_EXT = 3, + VK_LAYER_SETTING_TYPE_UINT64_EXT = 4, + VK_LAYER_SETTING_TYPE_FLOAT32_EXT = 5, + VK_LAYER_SETTING_TYPE_FLOAT64_EXT = 6, + VK_LAYER_SETTING_TYPE_STRING_EXT = 7, + VK_LAYER_SETTING_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} VkLayerSettingTypeEXT; +typedef enum VkLatencyMarkerNV { + VK_LATENCY_MARKER_SIMULATION_START_NV = 0, + VK_LATENCY_MARKER_SIMULATION_END_NV = 1, + VK_LATENCY_MARKER_RENDERSUBMIT_START_NV = 2, + VK_LATENCY_MARKER_RENDERSUBMIT_END_NV = 3, + VK_LATENCY_MARKER_PRESENT_START_NV = 4, + VK_LATENCY_MARKER_PRESENT_END_NV = 5, + VK_LATENCY_MARKER_INPUT_SAMPLE_NV = 6, + VK_LATENCY_MARKER_TRIGGER_FLASH_NV = 7, + VK_LATENCY_MARKER_OUT_OF_BAND_RENDERSUBMIT_START_NV = 8, + VK_LATENCY_MARKER_OUT_OF_BAND_RENDERSUBMIT_END_NV = 9, + VK_LATENCY_MARKER_OUT_OF_BAND_PRESENT_START_NV = 10, + VK_LATENCY_MARKER_OUT_OF_BAND_PRESENT_END_NV = 11, + VK_LATENCY_MARKER_MAX_ENUM_NV = 0x7FFFFFFF +} VkLatencyMarkerNV; +typedef enum VkOutOfBandQueueTypeNV { + VK_OUT_OF_BAND_QUEUE_TYPE_RENDER_NV = 0, + VK_OUT_OF_BAND_QUEUE_TYPE_PRESENT_NV = 1, + VK_OUT_OF_BAND_QUEUE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkOutOfBandQueueTypeNV; +typedef uint64_t VkPhysicalDeviceSchedulingControlsFlagBitsARM; +static const VkPhysicalDeviceSchedulingControlsFlagBitsARM VK_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_SHADER_CORE_COUNT_ARM = 1; + +typedef enum VkMemoryUnmapFlagBits { + VK_MEMORY_UNMAP_RESERVE_BIT_EXT = 1, + VK_MEMORY_UNMAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VkMemoryUnmapFlagBits; +typedef enum VkMemoryUnmapFlagBits VkMemoryUnmapFlagBitsKHR; + typedef enum VkVendorId { + VK_VENDOR_ID_KHRONOS = 0x10000, VK_VENDOR_ID_VIV = 0x10001, VK_VENDOR_ID_VSI = 0x10002, VK_VENDOR_ID_KAZAN = 0x10003, VK_VENDOR_ID_CODEPLAY = 0x10004, - VK_VENDOR_ID_MESA = 0x10005 + VK_VENDOR_ID_MESA = 0x10005, + VK_VENDOR_ID_POCL = 0x10006, + VK_VENDOR_ID_MOBILEYE = 0x10007, + VK_VENDOR_ID_MAX_ENUM = 0x7FFFFFFF } VkVendorId; - typedef enum VkDriverId { VK_DRIVER_ID_AMD_PROPRIETARY = 1, VK_DRIVER_ID_AMD_OPEN_SOURCE = 2, @@ -3460,6 +5896,19 @@ typedef enum VkDriverId { VK_DRIVER_ID_BROADCOM_PROPRIETARY = 12, VK_DRIVER_ID_MESA_LLVMPIPE = 13, VK_DRIVER_ID_MOLTENVK = 14, + VK_DRIVER_ID_COREAVI_PROPRIETARY = 15, + VK_DRIVER_ID_JUICE_PROPRIETARY = 16, + VK_DRIVER_ID_VERISILICON_PROPRIETARY = 17, + VK_DRIVER_ID_MESA_TURNIP = 18, + VK_DRIVER_ID_MESA_V3DV = 19, + VK_DRIVER_ID_MESA_PANVK = 20, + VK_DRIVER_ID_SAMSUNG_PROPRIETARY = 21, + VK_DRIVER_ID_MESA_VENUS = 22, + VK_DRIVER_ID_MESA_DOZEN = 23, + VK_DRIVER_ID_MESA_NVK = 24, + VK_DRIVER_ID_IMAGINATION_OPEN_SOURCE_MESA = 25, + VK_DRIVER_ID_MESA_HONEYKRISP = 26, + VK_DRIVER_ID_VULKAN_SC_EMULATION_ON_VULKAN = 27, VK_DRIVER_ID_AMD_PROPRIETARY_KHR = VK_DRIVER_ID_AMD_PROPRIETARY, VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = VK_DRIVER_ID_AMD_OPEN_SOURCE, VK_DRIVER_ID_MESA_RADV_KHR = VK_DRIVER_ID_MESA_RADV, @@ -3471,9 +5920,9 @@ typedef enum VkDriverId { VK_DRIVER_ID_ARM_PROPRIETARY_KHR = VK_DRIVER_ID_ARM_PROPRIETARY, VK_DRIVER_ID_GOOGLE_SWIFTSHADER_KHR = VK_DRIVER_ID_GOOGLE_SWIFTSHADER, VK_DRIVER_ID_GGP_PROPRIETARY_KHR = VK_DRIVER_ID_GGP_PROPRIETARY, - VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR = VK_DRIVER_ID_BROADCOM_PROPRIETARY + VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR = VK_DRIVER_ID_BROADCOM_PROPRIETARY, + VK_DRIVER_ID_MAX_ENUM = 0x7FFFFFFF } VkDriverId; - typedef enum VkDriverId VkDriverIdKHR; typedef enum VkShadingRatePaletteEntryNV { @@ -3488,54 +5937,53 @@ typedef enum VkShadingRatePaletteEntryNV { VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV = 8, VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV = 9, VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV = 10, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV = 11 + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV = 11, + VK_SHADING_RATE_PALETTE_ENTRY_MAX_ENUM_NV = 0x7FFFFFFF } VkShadingRatePaletteEntryNV; - typedef enum VkCoarseSampleOrderTypeNV { VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV = 0, VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV = 1, VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV = 2, - VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3 + VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3, + VK_COARSE_SAMPLE_ORDER_TYPE_MAX_ENUM_NV = 0x7FFFFFFF } VkCoarseSampleOrderTypeNV; - typedef enum VkPipelineExecutableStatisticFormatKHR { VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR = 0, VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR = 1, VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR = 2, - VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR = 3 + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR = 3, + VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_MAX_ENUM_KHR = 0x7FFFFFFF } VkPipelineExecutableStatisticFormatKHR; +typedef uint64_t VkAccessFlagBits3KHR; +static const VkAccessFlagBits3KHR VK_ACCESS_3_NONE_KHR = 0; typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( void* pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope); - typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)( void* pUserData, size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope); - typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)( void* pUserData, void* pOriginal, size_t size, size_t alignment, VkSystemAllocationScope allocationScope); - typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)( void* pUserData, size_t size, size_t alignment, VkSystemAllocationScope allocationScope); - typedef void (VKAPI_PTR *PFN_vkFreeFunction)( void* pUserData, void* pMemory); - typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); - +typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddrLUNARG)( + VkInstance instance, const char* pName); typedef struct VkBaseOutStructure { VkStructureType sType; struct VkBaseOutStructure * pNext; @@ -3596,15 +6044,15 @@ typedef struct VkComponentMapping { } VkComponentMapping; typedef struct VkExtensionProperties { - char extensionName [ VK_MAX_EXTENSION_NAME_SIZE ]; - uint32_t specVersion; + char extensionName [ VK_MAX_EXTENSION_NAME_SIZE ]; + uint32_t specVersion; } VkExtensionProperties; typedef struct VkLayerProperties { - char layerName [ VK_MAX_EXTENSION_NAME_SIZE ]; - uint32_t specVersion; - uint32_t implementationVersion; - char description [ VK_MAX_DESCRIPTION_SIZE ]; + char layerName [ VK_MAX_EXTENSION_NAME_SIZE ]; + uint32_t specVersion; + uint32_t implementationVersion; + char description [ VK_MAX_DESCRIPTION_SIZE ]; } VkLayerProperties; typedef struct VkApplicationInfo { @@ -3693,6 +6141,57 @@ typedef struct VkStencilOpState { uint32_t reference; } VkStencilOpState; +typedef struct VkPipelineCacheHeaderVersionOne { + uint32_t headerSize; + VkPipelineCacheHeaderVersion headerVersion; + uint32_t vendorID; + uint32_t deviceID; + uint8_t pipelineCacheUUID [ VK_UUID_SIZE ]; +} VkPipelineCacheHeaderVersionOne; + +typedef struct VkPipelineBinaryHandlesInfoKHR { + VkStructureType sType; + const void * pNext; + uint32_t pipelineBinaryCount; + VkPipelineBinaryKHR * pPipelineBinaries; +} VkPipelineBinaryHandlesInfoKHR; + +typedef struct VkPipelineBinaryDataKHR { + size_t dataSize; + void * pData; +} VkPipelineBinaryDataKHR; + +typedef struct VkPipelineBinaryKeyKHR { + VkStructureType sType; + void * pNext; + uint32_t keySize; + uint8_t key [ VK_MAX_PIPELINE_BINARY_KEY_SIZE_KHR ]; +} VkPipelineBinaryKeyKHR; + +typedef struct VkPipelineBinaryInfoKHR { + VkStructureType sType; + const void * pNext; + uint32_t binaryCount; + const VkPipelineBinaryKHR * pPipelineBinaries; +} VkPipelineBinaryInfoKHR; + +typedef struct VkReleaseCapturedPipelineDataInfoKHR { + VkStructureType sType; + void * pNext; + VkPipeline pipeline; +} VkReleaseCapturedPipelineDataInfoKHR; + +typedef struct VkPipelineBinaryDataInfoKHR { + VkStructureType sType; + void * pNext; + VkPipelineBinaryKHR pipelineBinary; +} VkPipelineBinaryDataInfoKHR; + +typedef struct VkPipelineCreateInfoKHR { + VkStructureType sType; + void * pNext; +} VkPipelineCreateInfoKHR; + typedef struct VkCommandBufferAllocateInfo { VkStructureType sType; const void * pNext; @@ -3743,6 +6242,17 @@ typedef struct VkDispatchIndirectCommand { uint32_t z; } VkDispatchIndirectCommand; +typedef struct VkMultiDrawInfoEXT { + uint32_t firstVertex; + uint32_t vertexCount; +} VkMultiDrawInfoEXT; + +typedef struct VkMultiDrawIndexedInfoEXT { + uint32_t firstIndex; + uint32_t indexCount; + int32_t vertexOffset; +} VkMultiDrawIndexedInfoEXT; + typedef struct VkDisplayPlanePropertiesKHR { VkDisplayKHR currentDisplay; uint32_t currentStackIndex; @@ -3758,6 +6268,12 @@ typedef struct VkDisplayModePropertiesKHR { VkDisplayModeParametersKHR parameters; } VkDisplayModePropertiesKHR; +typedef struct VkDisplaySurfaceStereoCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkDisplaySurfaceStereoTypeNV stereoType; +} VkDisplaySurfaceStereoCreateInfoNV; + typedef struct VkSurfaceFormatKHR { VkFormat format; VkColorSpaceKHR colorSpace; @@ -3790,6 +6306,14 @@ typedef struct VkValidationFeaturesEXT { const VkValidationFeatureDisableEXT * pDisabledValidationFeatures; } VkValidationFeaturesEXT; +typedef struct VkLayerSettingEXT { + const char * pLayerName; + const char * pSettingName; + VkLayerSettingTypeEXT type; + uint32_t valueCount; + const void * pValues; +} VkLayerSettingEXT; + typedef struct VkPipelineRasterizationStateRasterizationOrderAMD { VkStructureType sType; const void * pNext; @@ -3835,6 +6359,7 @@ typedef struct VkExportMemoryWin32HandleInfoNV { const SECURITY_ATTRIBUTES * pAttributes; DWORD dwAccess; } VkExportMemoryWin32HandleInfoNV; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -3849,13 +6374,16 @@ typedef struct VkWin32KeyedMutexAcquireReleaseInfoNV { const VkDeviceMemory * pReleaseSyncs; const uint64_t * pReleaseKeys; } VkWin32KeyedMutexAcquireReleaseInfoNV; + #endif -typedef struct VkDevicePrivateDataCreateInfoEXT { +typedef struct VkDevicePrivateDataCreateInfo { VkStructureType sType; const void * pNext; uint32_t privateDataSlotRequestCount; -} VkDevicePrivateDataCreateInfoEXT; +} VkDevicePrivateDataCreateInfo; + +typedef struct VkDevicePrivateDataCreateInfo VkDevicePrivateDataCreateInfoEXT; typedef struct VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV { VkStructureType sType; @@ -3871,6 +6399,51 @@ typedef struct VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV { uint32_t minIndirectCommandsBufferOffsetAlignment; } VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV; +typedef struct VkPhysicalDeviceClusterAccelerationStructurePropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t maxVerticesPerCluster; + uint32_t maxTrianglesPerCluster; + uint32_t clusterScratchByteAlignment; + uint32_t clusterByteAlignment; + uint32_t clusterTemplateByteAlignment; + uint32_t clusterBottomLevelByteAlignment; + uint32_t clusterTemplateBoundsByteAlignment; + uint32_t maxClusterGeometryIndex; +} VkPhysicalDeviceClusterAccelerationStructurePropertiesNV; + +typedef struct VkClusterAccelerationStructureGeometryIndexAndGeometryFlagsNV { + uint32_t geometryIndex :24; + uint32_t reserved :5; + uint32_t geometryFlags :3; +} VkClusterAccelerationStructureGeometryIndexAndGeometryFlagsNV; + +typedef struct VkClusterAccelerationStructureClustersBottomLevelInputNV { + VkStructureType sType; + void * pNext; + uint32_t maxTotalClusterCount; + uint32_t maxClusterCountPerAccelerationStructure; +} VkClusterAccelerationStructureClustersBottomLevelInputNV; + +typedef struct VkClusterAccelerationStructureTriangleClusterInputNV { + VkStructureType sType; + void * pNext; + VkFormat vertexFormat; + uint32_t maxGeometryIndexValue; + uint32_t maxClusterUniqueGeometryCount; + uint32_t maxClusterTriangleCount; + uint32_t maxClusterVertexCount; + uint32_t maxTotalTriangleCount; + uint32_t maxTotalVertexCount; + uint32_t minPositionTruncateBitCount; +} VkClusterAccelerationStructureTriangleClusterInputNV; + +typedef struct VkPhysicalDeviceMultiDrawPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t maxMultiDrawCount; +} VkPhysicalDeviceMultiDrawPropertiesEXT; + typedef struct VkBindShaderGroupIndirectCommandNV { uint32_t groupIndex; } VkBindShaderGroupIndirectCommandNV; @@ -3883,16 +6456,25 @@ typedef struct VkGeneratedCommandsMemoryRequirementsInfoNV { VkStructureType sType; const void * pNext; VkPipelineBindPoint pipelineBindPoint; - VkPipeline pipeline; + VkPipeline pipeline; VkIndirectCommandsLayoutNV indirectCommandsLayout; uint32_t maxSequencesCount; } VkGeneratedCommandsMemoryRequirementsInfoNV; -typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR { +typedef struct VkPipelineIndirectDeviceAddressInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; +} VkPipelineIndirectDeviceAddressInfoNV; + +typedef struct VkPhysicalDevicePushDescriptorProperties { VkStructureType sType; void * pNext; uint32_t maxPushDescriptors; -} VkPhysicalDevicePushDescriptorPropertiesKHR; +} VkPhysicalDevicePushDescriptorProperties; + +typedef struct VkPhysicalDevicePushDescriptorProperties VkPhysicalDevicePushDescriptorPropertiesKHR; typedef struct VkConformanceVersion { uint8_t major; @@ -3906,10 +6488,10 @@ typedef struct VkConformanceVersion VkConformanceVersionKHR; typedef struct VkPhysicalDeviceDriverProperties { VkStructureType sType; void * pNext; - VkDriverId driverID; - char driverName [ VK_MAX_DRIVER_NAME_SIZE ]; - char driverInfo [ VK_MAX_DRIVER_INFO_SIZE ]; - VkConformanceVersion conformanceVersion; + VkDriverId driverID; + char driverName [ VK_MAX_DRIVER_NAME_SIZE ]; + char driverInfo [ VK_MAX_DRIVER_INFO_SIZE ]; + VkConformanceVersion conformanceVersion; } VkPhysicalDeviceDriverProperties; typedef struct VkPhysicalDeviceDriverProperties VkPhysicalDeviceDriverPropertiesKHR; @@ -3936,6 +6518,7 @@ typedef struct VkImportMemoryWin32HandleInfoKHR { HANDLE handle; LPCWSTR name; } VkImportMemoryWin32HandleInfoKHR; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -3946,23 +6529,55 @@ typedef struct VkExportMemoryWin32HandleInfoKHR { DWORD dwAccess; LPCWSTR name; } VkExportMemoryWin32HandleInfoKHR; -#endif -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkMemoryWin32HandlePropertiesKHR { - VkStructureType sType; - void * pNext; - uint32_t memoryTypeBits; -} VkMemoryWin32HandlePropertiesKHR; #endif -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkMemoryGetWin32HandleInfoKHR { +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkImportMemoryZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + zx_handle_t handle; +} VkImportMemoryZirconHandleInfoFUCHSIA; + +#endif + +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkMemoryZirconHandlePropertiesFUCHSIA { + VkStructureType sType; + void * pNext; + uint32_t memoryTypeBits; +} VkMemoryZirconHandlePropertiesFUCHSIA; + +#endif + +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkMemoryGetZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetZirconHandleInfoFUCHSIA; + +#endif + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkMemoryWin32HandlePropertiesKHR { + VkStructureType sType; + void * pNext; + uint32_t memoryTypeBits; +} VkMemoryWin32HandlePropertiesKHR; + +#endif + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkMemoryGetWin32HandleInfoKHR { VkStructureType sType; const void * pNext; VkDeviceMemory memory; VkExternalMemoryHandleTypeFlagBits handleType; } VkMemoryGetWin32HandleInfoKHR; + #endif typedef struct VkImportMemoryFdInfoKHR { @@ -3997,6 +6612,36 @@ typedef struct VkWin32KeyedMutexAcquireReleaseInfoKHR { const VkDeviceMemory * pReleaseSyncs; const uint64_t * pReleaseKeys; } VkWin32KeyedMutexAcquireReleaseInfoKHR; + +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkImportMemoryMetalHandleInfoEXT { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlagBits handleType; + void * handle; +} VkImportMemoryMetalHandleInfoEXT; + +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkMemoryMetalHandlePropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t memoryTypeBits; +} VkMemoryMetalHandlePropertiesEXT; + +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkMemoryGetMetalHandleInfoEXT { + VkStructureType sType; + const void * pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetMetalHandleInfoEXT; + #endif typedef struct VkPhysicalDeviceExternalSemaphoreInfo { @@ -4015,6 +6660,7 @@ typedef struct VkExportSemaphoreWin32HandleInfoKHR { DWORD dwAccess; LPCWSTR name; } VkExportSemaphoreWin32HandleInfoKHR; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -4026,6 +6672,7 @@ typedef struct VkD3D12FenceSubmitInfoKHR { uint32_t signalSemaphoreValuesCount; const uint64_t * pSignalSemaphoreValues; } VkD3D12FenceSubmitInfoKHR; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -4035,6 +6682,7 @@ typedef struct VkSemaphoreGetWin32HandleInfoKHR { VkSemaphore semaphore; VkExternalSemaphoreHandleTypeFlagBits handleType; } VkSemaphoreGetWin32HandleInfoKHR; + #endif typedef struct VkSemaphoreGetFdInfoKHR { @@ -4044,6 +6692,16 @@ typedef struct VkSemaphoreGetFdInfoKHR { VkExternalSemaphoreHandleTypeFlagBits handleType; } VkSemaphoreGetFdInfoKHR; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkSemaphoreGetZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkSemaphore semaphore; + VkExternalSemaphoreHandleTypeFlagBits handleType; +} VkSemaphoreGetZirconHandleInfoFUCHSIA; + +#endif + typedef struct VkPhysicalDeviceExternalFenceInfo { VkStructureType sType; const void * pNext; @@ -4060,6 +6718,7 @@ typedef struct VkExportFenceWin32HandleInfoKHR { DWORD dwAccess; LPCWSTR name; } VkExportFenceWin32HandleInfoKHR; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -4069,6 +6728,7 @@ typedef struct VkFenceGetWin32HandleInfoKHR { VkFence fence; VkExternalFenceHandleTypeFlagBits handleType; } VkFenceGetWin32HandleInfoKHR; + #endif typedef struct VkFenceGetFdInfoKHR { @@ -4234,6 +6894,13 @@ typedef struct VkXYColorEXT { float y; } VkXYColorEXT; +typedef struct VkPresentIdKHR { + VkStructureType sType; + const void * pNext; + uint32_t swapchainCount; + const uint64_t * pPresentIds; +} VkPresentIdKHR; + typedef struct VkHdrMetadataEXT { VkStructureType sType; const void * pNext; @@ -4247,6 +6914,13 @@ typedef struct VkHdrMetadataEXT { float maxFrameAverageLightLevel; } VkHdrMetadataEXT; +typedef struct VkHdrVividDynamicMetadataHUAWEI { + VkStructureType sType; + const void * pNext; + size_t dynamicMetadataSize; + const void * pDynamicMetadata; +} VkHdrVividDynamicMetadataHUAWEI; + typedef struct VkRefreshCycleDurationGOOGLE { uint64_t refreshDuration; } VkRefreshCycleDurationGOOGLE; @@ -4340,7 +7014,7 @@ typedef struct VkImageSparseMemoryRequirementsInfo2 VkImageSparseMemoryRequirem typedef struct VkPhysicalDevicePointClippingProperties { VkStructureType sType; void * pNext; - VkPointClippingBehavior pointClippingBehavior; + VkPointClippingBehavior pointClippingBehavior; } VkPhysicalDevicePointClippingProperties; typedef struct VkPhysicalDevicePointClippingProperties VkPhysicalDevicePointClippingPropertiesKHR; @@ -4354,6 +7028,13 @@ typedef struct VkMemoryDedicatedAllocateInfo { typedef struct VkMemoryDedicatedAllocateInfo VkMemoryDedicatedAllocateInfoKHR; +typedef struct VkImageViewSlicedCreateInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t sliceOffset; + uint32_t sliceCount; +} VkImageViewSlicedCreateInfoEXT; + typedef struct VkPipelineTessellationDomainOriginStateCreateInfo { VkStructureType sType; const void * pNext; @@ -4441,7 +7122,7 @@ typedef struct VkSamplerReductionModeCreateInfo { typedef struct VkSamplerReductionModeCreateInfo VkSamplerReductionModeCreateInfoEXT; -typedef struct VkPhysicalDeviceInlineUniformBlockPropertiesEXT { +typedef struct VkPhysicalDeviceInlineUniformBlockProperties { VkStructureType sType; void * pNext; uint32_t maxInlineUniformBlockSize; @@ -4449,20 +7130,26 @@ typedef struct VkPhysicalDeviceInlineUniformBlockPropertiesEXT { uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; uint32_t maxDescriptorSetInlineUniformBlocks; uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; -} VkPhysicalDeviceInlineUniformBlockPropertiesEXT; +} VkPhysicalDeviceInlineUniformBlockProperties; + +typedef struct VkPhysicalDeviceInlineUniformBlockProperties VkPhysicalDeviceInlineUniformBlockPropertiesEXT; -typedef struct VkWriteDescriptorSetInlineUniformBlockEXT { +typedef struct VkWriteDescriptorSetInlineUniformBlock { VkStructureType sType; - const void * pNext; - uint32_t dataSize; - const void * pData; -} VkWriteDescriptorSetInlineUniformBlockEXT; + const void * pNext; + uint32_t dataSize; + const void * pData; +} VkWriteDescriptorSetInlineUniformBlock; -typedef struct VkDescriptorPoolInlineUniformBlockCreateInfoEXT { +typedef struct VkWriteDescriptorSetInlineUniformBlock VkWriteDescriptorSetInlineUniformBlockEXT; + +typedef struct VkDescriptorPoolInlineUniformBlockCreateInfo { VkStructureType sType; - const void * pNext; - uint32_t maxInlineUniformBlockBindings; -} VkDescriptorPoolInlineUniformBlockCreateInfoEXT; + const void * pNext; + uint32_t maxInlineUniformBlockBindings; +} VkDescriptorPoolInlineUniformBlockCreateInfo; + +typedef struct VkDescriptorPoolInlineUniformBlockCreateInfo VkDescriptorPoolInlineUniformBlockCreateInfoEXT; typedef struct VkImageFormatListCreateInfo { VkStructureType sType; @@ -4479,6 +7166,27 @@ typedef struct VkShaderModuleValidationCacheCreateInfoEXT { VkValidationCacheEXT validationCache; } VkShaderModuleValidationCacheCreateInfoEXT; +typedef struct VkPhysicalDeviceLayeredApiPropertiesKHR { + VkStructureType sType; + void * pNext; + uint32_t vendorID; + uint32_t deviceID; + VkPhysicalDeviceLayeredApiKHR layeredAPI; + char deviceName [ VK_MAX_PHYSICAL_DEVICE_NAME_SIZE ]; +} VkPhysicalDeviceLayeredApiPropertiesKHR; + +typedef struct VkRenderingAreaInfo { + VkStructureType sType; + const void * pNext; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat * pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; +} VkRenderingAreaInfo; + +typedef struct VkRenderingAreaInfo VkRenderingAreaInfoKHR; + typedef struct VkShaderResourceUsageAMD { uint32_t numUsedVgprs; uint32_t numUsedSgprs; @@ -4487,17 +7195,32 @@ typedef struct VkShaderResourceUsageAMD { size_t scratchMemUsageInBytes; } VkShaderResourceUsageAMD; -typedef struct VkDeviceQueueGlobalPriorityCreateInfoEXT { +typedef struct VkDeviceQueueGlobalPriorityCreateInfo { VkStructureType sType; - const void * pNext; - VkQueueGlobalPriorityEXT globalPriority; -} VkDeviceQueueGlobalPriorityCreateInfoEXT; + const void * pNext; + VkQueueGlobalPriority globalPriority; +} VkDeviceQueueGlobalPriorityCreateInfo; + +typedef struct VkDeviceQueueGlobalPriorityCreateInfo VkDeviceQueueGlobalPriorityCreateInfoKHR; + +typedef struct VkDeviceQueueGlobalPriorityCreateInfo VkDeviceQueueGlobalPriorityCreateInfoEXT; + +typedef struct VkQueueFamilyGlobalPriorityProperties { + VkStructureType sType; + void * pNext; + uint32_t priorityCount; + VkQueueGlobalPriority priorities [ VK_MAX_GLOBAL_PRIORITY_SIZE ]; +} VkQueueFamilyGlobalPriorityProperties; + +typedef struct VkQueueFamilyGlobalPriorityProperties VkQueueFamilyGlobalPriorityPropertiesKHR; + +typedef struct VkQueueFamilyGlobalPriorityProperties VkQueueFamilyGlobalPriorityPropertiesEXT; typedef struct VkDebugUtilsObjectNameInfoEXT { VkStructureType sType; const void * pNext; VkObjectType objectType; - uint64_t objectHandle; + uint64_t objectHandle; const char * pObjectName; } VkDebugUtilsObjectNameInfoEXT; @@ -4531,11 +7254,13 @@ typedef struct VkMemoryHostPointerPropertiesEXT { uint32_t memoryTypeBits; } VkMemoryHostPointerPropertiesEXT; -typedef struct VkCalibratedTimestampInfoEXT { +typedef struct VkCalibratedTimestampInfoKHR { VkStructureType sType; const void * pNext; - VkTimeDomainEXT timeDomain; -} VkCalibratedTimestampInfoEXT; + VkTimeDomainKHR timeDomain; +} VkCalibratedTimestampInfoKHR; + +typedef struct VkCalibratedTimestampInfoKHR VkCalibratedTimestampInfoEXT; typedef struct VkPhysicalDeviceShaderCorePropertiesAMD { VkStructureType sType; @@ -4545,15 +7270,15 @@ typedef struct VkPhysicalDeviceShaderCorePropertiesAMD { uint32_t computeUnitsPerShaderArray; uint32_t simdPerComputeUnit; uint32_t wavefrontsPerSimd; - uint32_t wavefrontSize; + uint32_t wavefrontSize; uint32_t sgprsPerSimd; - uint32_t minSgprAllocation; - uint32_t maxSgprAllocation; - uint32_t sgprAllocationGranularity; + uint32_t minSgprAllocation; + uint32_t maxSgprAllocation; + uint32_t sgprAllocationGranularity; uint32_t vgprsPerSimd; - uint32_t minVgprAllocation; - uint32_t maxVgprAllocation; - uint32_t vgprAllocationGranularity; + uint32_t minVgprAllocation; + uint32_t maxVgprAllocation; + uint32_t vgprAllocationGranularity; } VkPhysicalDeviceShaderCorePropertiesAMD; typedef struct VkDescriptorSetVariableDescriptorCountAllocateInfo { @@ -4625,17 +7350,25 @@ typedef struct VkSemaphoreSignalInfo { typedef struct VkSemaphoreSignalInfo VkSemaphoreSignalInfoKHR; -typedef struct VkVertexInputBindingDivisorDescriptionEXT { +typedef struct VkVertexInputBindingDivisorDescription { uint32_t binding; uint32_t divisor; -} VkVertexInputBindingDivisorDescriptionEXT; +} VkVertexInputBindingDivisorDescription; + +typedef struct VkVertexInputBindingDivisorDescription VkVertexInputBindingDivisorDescriptionKHR; + +typedef struct VkVertexInputBindingDivisorDescription VkVertexInputBindingDivisorDescriptionEXT; -typedef struct VkPipelineVertexInputDivisorStateCreateInfoEXT { +typedef struct VkPipelineVertexInputDivisorStateCreateInfo { VkStructureType sType; const void * pNext; uint32_t vertexBindingDivisorCount; - const VkVertexInputBindingDivisorDescriptionEXT * pVertexBindingDivisors; -} VkPipelineVertexInputDivisorStateCreateInfoEXT; + const VkVertexInputBindingDivisorDescription * pVertexBindingDivisors; +} VkPipelineVertexInputDivisorStateCreateInfo; + +typedef struct VkPipelineVertexInputDivisorStateCreateInfo VkPipelineVertexInputDivisorStateCreateInfoKHR; + +typedef struct VkPipelineVertexInputDivisorStateCreateInfo VkPipelineVertexInputDivisorStateCreateInfoEXT; typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT { VkStructureType sType; @@ -4658,6 +7391,7 @@ typedef struct VkImportAndroidHardwareBufferInfoANDROID { const void * pNext; struct AHardwareBuffer * buffer; } VkImportAndroidHardwareBufferInfoANDROID; + #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) @@ -4666,6 +7400,7 @@ typedef struct VkAndroidHardwareBufferUsageANDROID { void * pNext; uint64_t androidHardwareBufferUsage; } VkAndroidHardwareBufferUsageANDROID; + #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) @@ -4674,6 +7409,7 @@ typedef struct VkMemoryGetAndroidHardwareBufferInfoANDROID { const void * pNext; VkDeviceMemory memory; } VkMemoryGetAndroidHardwareBufferInfoANDROID; + #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) @@ -4682,6 +7418,7 @@ typedef struct VkExternalFormatANDROID { void * pNext; uint64_t externalFormat; } VkExternalFormatANDROID; + #endif typedef struct VkCheckpointDataNV { @@ -4712,7 +7449,7 @@ typedef struct VkShadingRatePaletteNV { typedef struct VkPhysicalDeviceShadingRateImagePropertiesNV { VkStructureType sType; void * pNext; - VkExtent2D shadingRateTexelSize; + VkExtent2D shadingRateTexelSize; uint32_t shadingRatePaletteSize; uint32_t shadingRateMaxCoarseSamples; } VkPhysicalDeviceShadingRateImagePropertiesNV; @@ -4752,8 +7489,8 @@ typedef struct VkPhysicalDeviceMeshShaderPropertiesNV { uint32_t maxMeshOutputVertices; uint32_t maxMeshOutputPrimitives; uint32_t maxMeshMultiviewViewCount; - uint32_t meshOutputPerVertexGranularity; - uint32_t meshOutputPerPrimitiveGranularity; + uint32_t meshOutputPerVertexGranularity; + uint32_t meshOutputPerPrimitiveGranularity; } VkPhysicalDeviceMeshShaderPropertiesNV; typedef struct VkDrawMeshTasksIndirectCommandNV { @@ -4761,6 +7498,12 @@ typedef struct VkDrawMeshTasksIndirectCommandNV { uint32_t firstTask; } VkDrawMeshTasksIndirectCommandNV; +typedef struct VkDrawMeshTasksIndirectCommandEXT { + uint32_t groupCountX; + uint32_t groupCountY; + uint32_t groupCountZ; +} VkDrawMeshTasksIndirectCommandEXT; + typedef struct VkRayTracingShaderGroupCreateInfoNV { VkStructureType sType; const void * pNext; @@ -4771,7 +7514,6 @@ typedef struct VkRayTracingShaderGroupCreateInfoNV { uint32_t intersectionShader; } VkRayTracingShaderGroupCreateInfoNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef struct VkRayTracingShaderGroupCreateInfoKHR { VkStructureType sType; const void * pNext; @@ -4782,7 +7524,6 @@ typedef struct VkRayTracingShaderGroupCreateInfoKHR { uint32_t intersectionShader; const void * pShaderGroupCaptureReplayHandle; } VkRayTracingShaderGroupCreateInfoKHR; -#endif typedef struct VkWriteDescriptorSetAccelerationStructureKHR { VkStructureType sType; @@ -4791,17 +7532,12 @@ typedef struct VkWriteDescriptorSetAccelerationStructureKHR { const VkAccelerationStructureKHR * pAccelerationStructures; } VkWriteDescriptorSetAccelerationStructureKHR; -typedef struct VkWriteDescriptorSetAccelerationStructureKHR VkWriteDescriptorSetAccelerationStructureNV; - -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureMemoryRequirementsInfoKHR { +typedef struct VkWriteDescriptorSetAccelerationStructureNV { VkStructureType sType; - const void * pNext; - VkAccelerationStructureMemoryRequirementsTypeKHR type; - VkAccelerationStructureBuildTypeKHR buildType; - VkAccelerationStructureKHR accelerationStructure; -} VkAccelerationStructureMemoryRequirementsInfoKHR; -#endif + const void * pNext; + uint32_t accelerationStructureCount; + const VkAccelerationStructureNV * pAccelerationStructures; +} VkWriteDescriptorSetAccelerationStructureNV; typedef struct VkAccelerationStructureMemoryRequirementsInfoNV { VkStructureType sType; @@ -4810,42 +7546,50 @@ typedef struct VkAccelerationStructureMemoryRequirementsInfoNV { VkAccelerationStructureNV accelerationStructure; } VkAccelerationStructureMemoryRequirementsInfoNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkPhysicalDeviceRayTracingPropertiesKHR { +typedef struct VkPhysicalDeviceAccelerationStructurePropertiesKHR { VkStructureType sType; - void * pNext; - uint32_t shaderGroupHandleSize; - uint32_t maxRecursionDepth; - uint32_t maxShaderGroupStride; - uint32_t shaderGroupBaseAlignment; + void * pNext; uint64_t maxGeometryCount; uint64_t maxInstanceCount; uint64_t maxPrimitiveCount; + uint32_t maxPerStageDescriptorAccelerationStructures; + uint32_t maxPerStageDescriptorUpdateAfterBindAccelerationStructures; uint32_t maxDescriptorSetAccelerationStructures; - uint32_t shaderGroupHandleCaptureReplaySize; -} VkPhysicalDeviceRayTracingPropertiesKHR; -#endif + uint32_t maxDescriptorSetUpdateAfterBindAccelerationStructures; + uint32_t minAccelerationStructureScratchOffsetAlignment; +} VkPhysicalDeviceAccelerationStructurePropertiesKHR; + +typedef struct VkPhysicalDeviceRayTracingPipelinePropertiesKHR { + VkStructureType sType; + void * pNext; + uint32_t shaderGroupHandleSize; + uint32_t maxRayRecursionDepth; + uint32_t maxShaderGroupStride; + uint32_t shaderGroupBaseAlignment; + uint32_t shaderGroupHandleCaptureReplaySize; + uint32_t maxRayDispatchInvocationCount; + uint32_t shaderGroupHandleAlignment; + uint32_t maxRayHitAttributeSize; +} VkPhysicalDeviceRayTracingPipelinePropertiesKHR; typedef struct VkPhysicalDeviceRayTracingPropertiesNV { VkStructureType sType; void * pNext; - uint32_t shaderGroupHandleSize; + uint32_t shaderGroupHandleSize; uint32_t maxRecursionDepth; uint32_t maxShaderGroupStride; - uint32_t shaderGroupBaseAlignment; + uint32_t shaderGroupBaseAlignment; uint64_t maxGeometryCount; uint64_t maxInstanceCount; uint64_t maxTriangleCount; uint32_t maxDescriptorSetAccelerationStructures; } VkPhysicalDeviceRayTracingPropertiesNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef struct VkTraceRaysIndirectCommandKHR { uint32_t width; uint32_t height; uint32_t depth; } VkTraceRaysIndirectCommandKHR; -#endif typedef struct VkPhysicalDeviceImageDrmFormatModifierInfoEXT { VkStructureType sType; @@ -4875,12 +7619,29 @@ typedef struct VkDeviceMemoryOverallocationCreateInfoAMD { VkMemoryOverallocationBehaviorAMD overallocationBehavior; } VkDeviceMemoryOverallocationCreateInfoAMD; +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT { + VkStructureType sType; + void * pNext; + VkExtent2D fragmentDensityOffsetGranularity; +} VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM; + typedef struct VkRenderPassFragmentDensityMapCreateInfoEXT { VkStructureType sType; const void * pNext; VkAttachmentReference fragmentDensityMapAttachment; } VkRenderPassFragmentDensityMapCreateInfoEXT; +typedef struct VkRenderPassFragmentDensityMapOffsetEndInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t fragmentDensityOffsetCount; + const VkOffset2D * pFragmentDensityOffsets; +} VkRenderPassFragmentDensityMapOffsetEndInfoEXT; + +typedef struct VkRenderPassFragmentDensityMapOffsetEndInfoEXT VkSubpassFragmentDensityMapOffsetEndInfoQCOM; + typedef struct VkMemoryPriorityAllocateInfoEXT { VkStructureType sType; const void * pNext; @@ -4947,6 +7708,7 @@ typedef struct VkPresentFrameTokenGGP { const void * pNext; GgpFrameToken frameToken; } VkPresentFrameTokenGGP; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -4955,6 +7717,7 @@ typedef struct VkSurfaceFullScreenExclusiveInfoEXT { void * pNext; VkFullScreenExclusiveEXT fullScreenExclusive; } VkSurfaceFullScreenExclusiveInfoEXT; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) @@ -4963,11 +7726,12 @@ typedef struct VkSurfaceFullScreenExclusiveWin32InfoEXT { const void * pNext; HMONITOR hmonitor; } VkSurfaceFullScreenExclusiveWin32InfoEXT; + #endif typedef struct VkPerformanceCounterKHR { VkStructureType sType; - const void * pNext; + void * pNext; VkPerformanceCounterUnitKHR unit; VkPerformanceCounterScopeKHR scope; VkPerformanceCounterStorageKHR storage; @@ -5037,7 +7801,7 @@ typedef struct VkPhysicalDeviceShaderSMBuiltinsPropertiesNV { } VkPhysicalDeviceShaderSMBuiltinsPropertiesNV; typedef struct VkAttachmentReferenceStencilLayout { - VkStructureType sType; + VkStructureType sType; void * pNext; VkImageLayout stencilLayout; } VkAttachmentReferenceStencilLayout; @@ -5045,7 +7809,7 @@ typedef struct VkAttachmentReferenceStencilLayout { typedef struct VkAttachmentReferenceStencilLayout VkAttachmentReferenceStencilLayoutKHR; typedef struct VkAttachmentDescriptionStencilLayout { - VkStructureType sType; + VkStructureType sType; void * pNext; VkImageLayout stencilInitialLayout; VkImageLayout stencilFinalLayout; @@ -5059,6 +7823,8 @@ typedef struct VkPipelineInfoKHR { VkPipeline pipeline; } VkPipelineInfoKHR; +typedef struct VkPipelineInfoKHR VkPipelineInfoEXT; + typedef struct VkPipelineExecutableInfoKHR { VkStructureType sType; const void * pNext; @@ -5066,11 +7832,28 @@ typedef struct VkPipelineExecutableInfoKHR { uint32_t executableIndex; } VkPipelineExecutableInfoKHR; -typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT { +typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfo { VkStructureType sType; - void * pNext; + void * pNext; uint32_t requiredSubgroupSize; -} VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT; +} VkPipelineShaderStageRequiredSubgroupSizeCreateInfo; + +typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfo VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT; + +typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfo VkShaderRequiredSubgroupSizeCreateInfoEXT; + +typedef struct VkSubpassShadingPipelineCreateInfoHUAWEI { + VkStructureType sType; + void * pNext; + VkRenderPass renderPass; + uint32_t subpass; +} VkSubpassShadingPipelineCreateInfoHUAWEI; + +typedef struct VkPhysicalDeviceSubpassShadingPropertiesHUAWEI { + VkStructureType sType; + void * pNext; + uint32_t maxSubpassShadingWorkgroupSizeAspectRatio; +} VkPhysicalDeviceSubpassShadingPropertiesHUAWEI; typedef struct VkMemoryOpaqueCaptureAddressAllocateInfo { VkStructureType sType; @@ -5088,11 +7871,15 @@ typedef struct VkDeviceMemoryOpaqueCaptureAddressInfo { typedef struct VkDeviceMemoryOpaqueCaptureAddressInfo VkDeviceMemoryOpaqueCaptureAddressInfoKHR; -typedef struct VkPhysicalDeviceLineRasterizationPropertiesEXT { +typedef struct VkPhysicalDeviceLineRasterizationProperties { VkStructureType sType; void * pNext; uint32_t lineSubPixelPrecisionBits; -} VkPhysicalDeviceLineRasterizationPropertiesEXT; +} VkPhysicalDeviceLineRasterizationProperties; + +typedef struct VkPhysicalDeviceLineRasterizationProperties VkPhysicalDeviceLineRasterizationPropertiesKHR; + +typedef struct VkPhysicalDeviceLineRasterizationProperties VkPhysicalDeviceLineRasterizationPropertiesEXT; typedef struct VkSamplerCustomBorderColorCreateInfoEXT { VkStructureType sType; @@ -5107,14 +7894,12 @@ typedef struct VkPhysicalDeviceCustomBorderColorPropertiesEXT { uint32_t maxCustomBorderColorSamplers; } VkPhysicalDeviceCustomBorderColorPropertiesEXT; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureBuildOffsetInfoKHR { +typedef struct VkAccelerationStructureBuildRangeInfoKHR { uint32_t primitiveCount; uint32_t primitiveOffset; - uint32_t firstVertex; - uint32_t transformOffset; -} VkAccelerationStructureBuildOffsetInfoKHR; -#endif + uint32_t firstVertex; + uint32_t transformOffset; +} VkAccelerationStructureBuildRangeInfoKHR; typedef struct VkAabbPositionsKHR { float minX; @@ -5133,23 +7918,18 @@ typedef struct VkTransformMatrixKHR { typedef struct VkTransformMatrixKHR VkTransformMatrixNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef struct VkAccelerationStructureDeviceAddressInfoKHR { VkStructureType sType; const void * pNext; VkAccelerationStructureKHR accelerationStructure; } VkAccelerationStructureDeviceAddressInfoKHR; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureVersionKHR { +typedef struct VkAccelerationStructureVersionInfoKHR { VkStructureType sType; const void * pNext; - const uint8_t * versionData; -} VkAccelerationStructureVersionKHR; -#endif + const uint8_t * pVersionData; +} VkAccelerationStructureVersionInfoKHR; -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef struct VkCopyAccelerationStructureInfoKHR { VkStructureType sType; const void * pNext; @@ -5157,34 +7937,29 @@ typedef struct VkCopyAccelerationStructureInfoKHR { VkAccelerationStructureKHR dst; VkCopyAccelerationStructureModeKHR mode; } VkCopyAccelerationStructureInfoKHR; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef struct VkRayTracingPipelineInterfaceCreateInfoKHR { VkStructureType sType; - const void * pNext; - uint32_t maxPayloadSize; - uint32_t maxAttributeSize; - uint32_t maxCallableSize; + const void * pNext; + uint32_t maxPipelineRayPayloadSize; + uint32_t maxPipelineRayHitAttributeSize; } VkRayTracingPipelineInterfaceCreateInfoKHR; -#endif - -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkDeferredOperationInfoKHR { - VkStructureType sType; - const void * pNext; - VkDeferredOperationKHR operationHandle; -} VkDeferredOperationInfoKHR; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) || defined(VK_ENABLE_BETA_EXTENSIONS) typedef struct VkPipelineLibraryCreateInfoKHR { VkStructureType sType; const void * pNext; uint32_t libraryCount; const VkPipeline * pLibraries; } VkPipelineLibraryCreateInfoKHR; -#endif + +typedef struct VkColorBlendEquationEXT { + VkBlendFactor srcColorBlendFactor; + VkBlendFactor dstColorBlendFactor; + VkBlendOp colorBlendOp; + VkBlendFactor srcAlphaBlendFactor; + VkBlendFactor dstAlphaBlendFactor; + VkBlendOp alphaBlendOp; +} VkColorBlendEquationEXT; typedef struct VkRenderPassTransformBeginInfoQCOM { VkStructureType sType; @@ -5192,6 +7967,12 @@ typedef struct VkRenderPassTransformBeginInfoQCOM { VkSurfaceTransformFlagBitsKHR transform; } VkRenderPassTransformBeginInfoQCOM; +typedef struct VkCopyCommandTransformInfoQCOM { + VkStructureType sType; + const void * pNext; + VkSurfaceTransformFlagBitsKHR transform; +} VkCopyCommandTransformInfoQCOM; + typedef struct VkCommandBufferInheritanceRenderPassTransformInfoQCOM { VkStructureType sType; void * pNext; @@ -5199,914 +7980,2037 @@ typedef struct VkCommandBufferInheritanceRenderPassTransformInfoQCOM { VkRect2D renderArea; } VkCommandBufferInheritanceRenderPassTransformInfoQCOM; -typedef uint32_t VkSampleMask; +typedef struct VkPhysicalDevicePartitionedAccelerationStructurePropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t maxPartitionCount; +} VkPhysicalDevicePartitionedAccelerationStructurePropertiesNV; -typedef uint32_t VkBool32; +typedef struct VkPartitionedAccelerationStructureWritePartitionTranslationDataNV { + uint32_t partitionIndex; + float partitionTranslation [3]; +} VkPartitionedAccelerationStructureWritePartitionTranslationDataNV; -typedef uint32_t VkFlags; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDevicePortabilitySubsetPropertiesKHR { + VkStructureType sType; + void * pNext; + uint32_t minVertexInputBindingStrideAlignment; +} VkPhysicalDevicePortabilitySubsetPropertiesKHR; -typedef uint64_t VkDeviceSize; +#endif -typedef uint64_t VkDeviceAddress; +typedef struct VkPipelineFragmentShadingRateStateCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkExtent2D fragmentSize; + VkFragmentShadingRateCombinerOpKHR combinerOps [2]; +} VkPipelineFragmentShadingRateStateCreateInfoKHR; -typedef VkFlags VkFramebufferCreateFlags; +typedef struct VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV { + VkStructureType sType; + void * pNext; + VkSampleCountFlagBits maxFragmentShadingRateInvocationCount; +} VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV; -typedef VkFlags VkQueryPoolCreateFlags; +typedef struct VkPipelineFragmentShadingRateEnumStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkFragmentShadingRateTypeNV shadingRateType; + VkFragmentShadingRateNV shadingRate; + VkFragmentShadingRateCombinerOpKHR combinerOps [2]; +} VkPipelineFragmentShadingRateEnumStateCreateInfoNV; -typedef VkFlags VkRenderPassCreateFlags; +typedef struct VkMutableDescriptorTypeListEXT { + uint32_t descriptorTypeCount; + const VkDescriptorType * pDescriptorTypes; +} VkMutableDescriptorTypeListEXT; -typedef VkFlags VkSamplerCreateFlags; +typedef struct VkMutableDescriptorTypeListEXT VkMutableDescriptorTypeListVALVE; -typedef VkFlags VkPipelineLayoutCreateFlags; +typedef struct VkMutableDescriptorTypeCreateInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t mutableDescriptorTypeListCount; + const VkMutableDescriptorTypeListEXT * pMutableDescriptorTypeLists; +} VkMutableDescriptorTypeCreateInfoEXT; -typedef VkFlags VkPipelineCacheCreateFlags; +typedef struct VkMutableDescriptorTypeCreateInfoEXT VkMutableDescriptorTypeCreateInfoVALVE; -typedef VkFlags VkPipelineDepthStencilStateCreateFlags; +typedef struct VkGeneratedCommandsPipelineInfoEXT { + VkStructureType sType; + void * pNext; + VkPipeline pipeline; +} VkGeneratedCommandsPipelineInfoEXT; -typedef VkFlags VkPipelineDynamicStateCreateFlags; +typedef struct VkGeneratedCommandsShaderInfoEXT { + VkStructureType sType; + void * pNext; + uint32_t shaderCount; + const VkShaderEXT * pShaders; +} VkGeneratedCommandsShaderInfoEXT; -typedef VkFlags VkPipelineColorBlendStateCreateFlags; +typedef struct VkGeneratedCommandsMemoryRequirementsInfoEXT { + VkStructureType sType; + const void * pNext; + VkIndirectExecutionSetEXT indirectExecutionSet; + VkIndirectCommandsLayoutEXT indirectCommandsLayout; + uint32_t maxSequenceCount; + uint32_t maxDrawCount; +} VkGeneratedCommandsMemoryRequirementsInfoEXT; -typedef VkFlags VkPipelineMultisampleStateCreateFlags; +typedef struct VkIndirectExecutionSetPipelineInfoEXT { + VkStructureType sType; + const void * pNext; + VkPipeline initialPipeline; + uint32_t maxPipelineCount; +} VkIndirectExecutionSetPipelineInfoEXT; -typedef VkFlags VkPipelineRasterizationStateCreateFlags; +typedef struct VkIndirectExecutionSetShaderLayoutInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t setLayoutCount; + const VkDescriptorSetLayout * pSetLayouts; +} VkIndirectExecutionSetShaderLayoutInfoEXT; -typedef VkFlags VkPipelineViewportStateCreateFlags; +typedef struct VkWriteIndirectExecutionSetPipelineEXT { + VkStructureType sType; + const void * pNext; + uint32_t index; + VkPipeline pipeline; +} VkWriteIndirectExecutionSetPipelineEXT; -typedef VkFlags VkPipelineTessellationStateCreateFlags; +typedef struct VkWriteIndirectExecutionSetShaderEXT { + VkStructureType sType; + const void * pNext; + uint32_t index; + VkShaderEXT shader; +} VkWriteIndirectExecutionSetShaderEXT; -typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; +typedef struct VkIndirectCommandsVertexBufferTokenEXT { + uint32_t vertexBindingUnit; +} VkIndirectCommandsVertexBufferTokenEXT; -typedef VkFlags VkPipelineVertexInputStateCreateFlags; +typedef struct VkIndirectCommandsIndexBufferTokenEXT { + VkIndirectCommandsInputModeFlagBitsEXT mode; +} VkIndirectCommandsIndexBufferTokenEXT; -typedef VkFlags VkPipelineShaderStageCreateFlags; +typedef struct VkVertexInputBindingDescription2EXT { + VkStructureType sType; + void * pNext; + uint32_t binding; + uint32_t stride; + VkVertexInputRate inputRate; + uint32_t divisor; +} VkVertexInputBindingDescription2EXT; -typedef VkFlags VkDescriptorSetLayoutCreateFlags; +typedef struct VkVertexInputAttributeDescription2EXT { + VkStructureType sType; + void * pNext; + uint32_t location; + uint32_t binding; + VkFormat format; + uint32_t offset; +} VkVertexInputAttributeDescription2EXT; -typedef VkFlags VkBufferViewCreateFlags; +typedef struct VkCommandBufferSubmitInfo { + VkStructureType sType; + const void * pNext; + VkCommandBuffer commandBuffer; + uint32_t deviceMask; +} VkCommandBufferSubmitInfo; -typedef VkFlags VkInstanceCreateFlags; +typedef struct VkCommandBufferSubmitInfo VkCommandBufferSubmitInfoKHR; -typedef VkFlags VkDeviceCreateFlags; +typedef struct VkPipelineRasterizationProvokingVertexStateCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkProvokingVertexModeEXT provokingVertexMode; +} VkPipelineRasterizationProvokingVertexStateCreateInfoEXT; -typedef VkFlags VkDeviceQueueCreateFlags; +typedef struct VkCuModuleCreateInfoNVX { + VkStructureType sType; + const void * pNext; + size_t dataSize; + const void * pData; +} VkCuModuleCreateInfoNVX; -typedef VkFlags VkQueueFlags; +typedef struct VkCuFunctionCreateInfoNVX { + VkStructureType sType; + const void * pNext; + VkCuModuleNVX module; + const char * pName; +} VkCuFunctionCreateInfoNVX; -typedef VkFlags VkMemoryPropertyFlags; +typedef struct VkCuLaunchInfoNVX { + VkStructureType sType; + const void * pNext; + VkCuFunctionNVX function; + uint32_t gridDimX; + uint32_t gridDimY; + uint32_t gridDimZ; + uint32_t blockDimX; + uint32_t blockDimY; + uint32_t blockDimZ; + uint32_t sharedMemBytes; + size_t paramCount; + const void * const * pParams; + size_t extraCount; + const void * const * pExtras; +} VkCuLaunchInfoNVX; + +typedef struct VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT { + VkStructureType sType; + void * pNext; + size_t combinedImageSamplerDensityMapDescriptorSize; +} VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT; -typedef VkFlags VkMemoryHeapFlags; +typedef struct VkDescriptorBufferBindingPushDescriptorBufferHandleEXT { + VkStructureType sType; + const void * pNext; + VkBuffer buffer; +} VkDescriptorBufferBindingPushDescriptorBufferHandleEXT; -typedef VkFlags VkAccessFlags; - -typedef VkFlags VkBufferUsageFlags; +typedef struct VkBufferCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void * pNext; + VkBuffer buffer; +} VkBufferCaptureDescriptorDataInfoEXT; -typedef VkFlags VkBufferCreateFlags; +typedef struct VkImageCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void * pNext; + VkImage image; +} VkImageCaptureDescriptorDataInfoEXT; -typedef VkFlags VkShaderStageFlags; +typedef struct VkImageViewCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void * pNext; + VkImageView imageView; +} VkImageViewCaptureDescriptorDataInfoEXT; -typedef VkFlags VkImageUsageFlags; +typedef struct VkSamplerCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void * pNext; + VkSampler sampler; +} VkSamplerCaptureDescriptorDataInfoEXT; -typedef VkFlags VkImageCreateFlags; +typedef struct VkAccelerationStructureCaptureDescriptorDataInfoEXT { + VkStructureType sType; + const void * pNext; + VkAccelerationStructureKHR accelerationStructure; + VkAccelerationStructureNV accelerationStructureNV; +} VkAccelerationStructureCaptureDescriptorDataInfoEXT; -typedef VkFlags VkImageViewCreateFlags; +typedef struct VkOpaqueCaptureDescriptorDataCreateInfoEXT { + VkStructureType sType; + const void * pNext; + const void * opaqueCaptureDescriptorData; +} VkOpaqueCaptureDescriptorDataCreateInfoEXT; + +typedef enum VkAccelerationStructureMotionInstanceTypeNV { + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV = 0, + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MATRIX_MOTION_NV = 1, + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_SRT_MOTION_NV = 2, + VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkAccelerationStructureMotionInstanceTypeNV; +typedef struct VkSRTDataNV { + float sx; + float a; + float b; + float pvx; + float sy; + float c; + float pvy; + float sz; + float pvz; + float qx; + float qy; + float qz; + float qw; + float tx; + float ty; + float tz; +} VkSRTDataNV; + +typedef void* VkRemoteAddressNV; +typedef struct VkMemoryGetRemoteAddressInfoNV { + VkStructureType sType; + const void * pNext; + VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkMemoryGetRemoteAddressInfoNV; -typedef VkFlags VkPipelineCreateFlags; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkImportMemoryBufferCollectionFUCHSIA { + VkStructureType sType; + const void * pNext; + VkBufferCollectionFUCHSIA collection; + uint32_t index; +} VkImportMemoryBufferCollectionFUCHSIA; -typedef VkFlags VkColorComponentFlags; +#endif -typedef VkFlags VkFenceCreateFlags; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkBufferCollectionImageCreateInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkBufferCollectionFUCHSIA collection; + uint32_t index; +} VkBufferCollectionImageCreateInfoFUCHSIA; -typedef VkFlags VkSemaphoreCreateFlags; +#endif -typedef VkFlags VkFormatFeatureFlags; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkBufferCollectionBufferCreateInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkBufferCollectionFUCHSIA collection; + uint32_t index; +} VkBufferCollectionBufferCreateInfoFUCHSIA; -typedef VkFlags VkQueryControlFlags; +#endif -typedef VkFlags VkQueryResultFlags; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkBufferCollectionCreateInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + zx_handle_t collectionToken; +} VkBufferCollectionCreateInfoFUCHSIA; -typedef VkFlags VkShaderModuleCreateFlags; +#endif -typedef VkFlags VkEventCreateFlags; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkSysmemColorSpaceFUCHSIA { + VkStructureType sType; + const void * pNext; + uint32_t colorSpace; +} VkSysmemColorSpaceFUCHSIA; -typedef VkFlags VkCommandPoolCreateFlags; +#endif -typedef VkFlags VkCommandPoolResetFlags; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkBufferCollectionConstraintsInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + uint32_t minBufferCount; + uint32_t maxBufferCount; + uint32_t minBufferCountForCamping; + uint32_t minBufferCountForDedicatedSlack; + uint32_t minBufferCountForSharedSlack; +} VkBufferCollectionConstraintsInfoFUCHSIA; -typedef VkFlags VkCommandBufferResetFlags; +#endif -typedef VkFlags VkCommandBufferUsageFlags; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCudaModuleNV) +#endif -typedef VkFlags VkQueryPipelineStatisticFlags; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCudaFunctionNV) +#endif -typedef VkFlags VkMemoryMapFlags; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkCudaModuleCreateInfoNV { + VkStructureType sType; + const void * pNext; + size_t dataSize; + const void * pData; +} VkCudaModuleCreateInfoNV; -typedef VkFlags VkImageAspectFlags; +#endif -typedef VkFlags VkSparseMemoryBindFlags; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkCudaFunctionCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkCudaModuleNV module; + const char * pName; +} VkCudaFunctionCreateInfoNV; -typedef VkFlags VkSparseImageFormatFlags; +#endif -typedef VkFlags VkSubpassDescriptionFlags; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkCudaLaunchInfoNV { + VkStructureType sType; + const void * pNext; + VkCudaFunctionNV function; + uint32_t gridDimX; + uint32_t gridDimY; + uint32_t gridDimZ; + uint32_t blockDimX; + uint32_t blockDimY; + uint32_t blockDimZ; + uint32_t sharedMemBytes; + size_t paramCount; + const void * const * pParams; + size_t extraCount; + const void * const * pExtras; +} VkCudaLaunchInfoNV; -typedef VkFlags VkPipelineStageFlags; +#endif -typedef VkFlags VkSampleCountFlags; +typedef struct VkPipelineRenderingCreateInfo { + VkStructureType sType; + const void * pNext; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat * pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; +} VkPipelineRenderingCreateInfo; -typedef VkFlags VkAttachmentDescriptionFlags; +typedef struct VkPipelineRenderingCreateInfo VkPipelineRenderingCreateInfoKHR; -typedef VkFlags VkStencilFaceFlags; +typedef struct VkRenderingEndInfoEXT { + VkStructureType sType; + const void * pNext; +} VkRenderingEndInfoEXT; -typedef VkFlags VkCullModeFlags; +typedef struct VkRenderingAttachmentInfo { + VkStructureType sType; + const void * pNext; + VkImageView imageView; + VkImageLayout imageLayout; + VkResolveModeFlagBits resolveMode; + VkImageView resolveImageView; + VkImageLayout resolveImageLayout; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkClearValue clearValue; +} VkRenderingAttachmentInfo; -typedef VkFlags VkDescriptorPoolCreateFlags; +typedef struct VkRenderingAttachmentInfo VkRenderingAttachmentInfoKHR; -typedef VkFlags VkDescriptorPoolResetFlags; +typedef struct VkRenderingFragmentShadingRateAttachmentInfoKHR { + VkStructureType sType; + const void * pNext; + VkImageView imageView; + VkImageLayout imageLayout; + VkExtent2D shadingRateAttachmentTexelSize; +} VkRenderingFragmentShadingRateAttachmentInfoKHR; -typedef VkFlags VkDependencyFlags; +typedef struct VkRenderingFragmentDensityMapAttachmentInfoEXT { + VkStructureType sType; + const void * pNext; + VkImageView imageView; + VkImageLayout imageLayout; +} VkRenderingFragmentDensityMapAttachmentInfoEXT; -typedef VkFlags VkSubgroupFeatureFlags; +typedef struct VkAttachmentSampleCountInfoAMD { + VkStructureType sType; + const void * pNext; + uint32_t colorAttachmentCount; + const VkSampleCountFlagBits * pColorAttachmentSamples; + VkSampleCountFlagBits depthStencilAttachmentSamples; +} VkAttachmentSampleCountInfoAMD; -typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNV; +typedef struct VkAttachmentSampleCountInfoAMD VkAttachmentSampleCountInfoNV; -typedef VkFlags VkIndirectStateFlagsNV; +typedef struct VkImageViewMinLodCreateInfoEXT { + VkStructureType sType; + const void * pNext; + float minLod; +} VkImageViewMinLodCreateInfoEXT; -typedef VkFlags VkGeometryFlagsKHR; +typedef struct VkDescriptorSetBindingReferenceVALVE { + VkStructureType sType; + const void * pNext; + VkDescriptorSetLayout descriptorSetLayout; + uint32_t binding; +} VkDescriptorSetBindingReferenceVALVE; -#define VkGeometryFlagsNV VkGeometryFlagsKHR +typedef struct VkDescriptorSetLayoutHostMappingInfoVALVE { + VkStructureType sType; + void * pNext; + size_t descriptorOffset; + uint32_t descriptorSize; +} VkDescriptorSetLayoutHostMappingInfoVALVE; -typedef VkFlags VkGeometryInstanceFlagsKHR; +typedef struct VkPhysicalDeviceNestedCommandBufferPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t maxCommandBufferNestingLevel; +} VkPhysicalDeviceNestedCommandBufferPropertiesEXT; -#define VkGeometryInstanceFlagsNV VkGeometryInstanceFlagsKHR +typedef struct VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT { + VkStructureType sType; + void * pNext; + uint8_t shaderModuleIdentifierAlgorithmUUID [ VK_UUID_SIZE ]; +} VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT; -typedef VkFlags VkBuildAccelerationStructureFlagsKHR; +typedef struct VkPipelineShaderStageModuleIdentifierCreateInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t identifierSize; + const uint8_t * pIdentifier; +} VkPipelineShaderStageModuleIdentifierCreateInfoEXT; -#define VkBuildAccelerationStructureFlagsNV VkBuildAccelerationStructureFlagsKHR +typedef struct VkShaderModuleIdentifierEXT { + VkStructureType sType; + void * pNext; + uint32_t identifierSize; + uint8_t identifier [ VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT ]; +} VkShaderModuleIdentifierEXT; -typedef VkFlags VkPrivateDataSlotCreateFlagsEXT; +typedef struct VkRenderPassCreationFeedbackInfoEXT { + uint32_t postMergeSubpassCount; +} VkRenderPassCreationFeedbackInfoEXT; -typedef VkFlags VkDescriptorUpdateTemplateCreateFlags; +typedef struct VkRenderPassCreationFeedbackCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkRenderPassCreationFeedbackInfoEXT * pRenderPassFeedback; +} VkRenderPassCreationFeedbackCreateInfoEXT; -#define VkDescriptorUpdateTemplateCreateFlagsKHR VkDescriptorUpdateTemplateCreateFlags +typedef struct VkRenderPassSubpassFeedbackInfoEXT { + VkSubpassMergeStatusEXT subpassMergeStatus; + char description [ VK_MAX_DESCRIPTION_SIZE ]; + uint32_t postMergeIndex; +} VkRenderPassSubpassFeedbackInfoEXT; -typedef VkFlags VkPipelineCreationFeedbackFlagsEXT; +typedef struct VkRenderPassSubpassFeedbackCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkRenderPassSubpassFeedbackInfoEXT * pSubpassFeedback; +} VkRenderPassSubpassFeedbackCreateInfoEXT; -typedef VkFlags VkPerformanceCounterDescriptionFlagsKHR; +typedef struct VkMicromapVersionInfoEXT { + VkStructureType sType; + const void * pNext; + const uint8_t * pVersionData; +} VkMicromapVersionInfoEXT; -typedef VkFlags VkAcquireProfilingLockFlagsKHR; +typedef struct VkCopyMicromapInfoEXT { + VkStructureType sType; + const void * pNext; + VkMicromapEXT src; + VkMicromapEXT dst; + VkCopyMicromapModeEXT mode; +} VkCopyMicromapInfoEXT; -typedef VkFlags VkSemaphoreWaitFlags; +typedef struct VkMicromapUsageEXT { + uint32_t count; + uint32_t subdivisionLevel; + uint32_t format; +} VkMicromapUsageEXT; -#define VkSemaphoreWaitFlagsKHR VkSemaphoreWaitFlags +typedef struct VkMicromapTriangleEXT { + uint32_t dataOffset; + uint16_t subdivisionLevel; + uint16_t format; +} VkMicromapTriangleEXT; -typedef VkFlags VkPipelineCompilerControlFlagsAMD; +typedef struct VkPhysicalDeviceOpacityMicromapPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t maxOpacity2StateSubdivisionLevel; + uint32_t maxOpacity4StateSubdivisionLevel; +} VkPhysicalDeviceOpacityMicromapPropertiesEXT; -typedef VkFlags VkShaderCorePropertiesFlagsAMD; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDeviceDisplacementMicromapPropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t maxDisplacementMicromapSubdivisionLevel; +} VkPhysicalDeviceDisplacementMicromapPropertiesNV; -typedef VkFlags VkDeviceDiagnosticsConfigFlagsNV; +#endif -typedef VkFlags VkCompositeAlphaFlagsKHR; +typedef struct VkPipelinePropertiesIdentifierEXT { + VkStructureType sType; + void * pNext; + uint8_t pipelineIdentifier [ VK_UUID_SIZE ]; +} VkPipelinePropertiesIdentifierEXT; -typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalObjectCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkExportMetalObjectTypeFlagBitsEXT exportObjectType; +} VkExportMetalObjectCreateInfoEXT; -typedef VkFlags VkSurfaceTransformFlagsKHR; +#endif -typedef VkFlags VkSwapchainCreateFlagsKHR; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalObjectsInfoEXT { + VkStructureType sType; + const void * pNext; +} VkExportMetalObjectsInfoEXT; -typedef VkFlags VkDisplayModeCreateFlagsKHR; +#endif -typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalDeviceInfoEXT { + VkStructureType sType; + const void * pNext; + MTLDevice_id mtlDevice; +} VkExportMetalDeviceInfoEXT; -#if defined(VK_USE_PLATFORM_ANDROID_KHR) -typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; #endif -#if defined(VK_USE_PLATFORM_VI_NN) -typedef VkFlags VkViSurfaceCreateFlagsNN; -#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalCommandQueueInfoEXT { + VkStructureType sType; + const void * pNext; + VkQueue queue; + MTLCommandQueue_id mtlCommandQueue; +} VkExportMetalCommandQueueInfoEXT; -#if defined(VK_USE_PLATFORM_WAYLAND_KHR) -typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; #endif -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef VkFlags VkWin32SurfaceCreateFlagsKHR; -#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalBufferInfoEXT { + VkStructureType sType; + const void * pNext; + VkDeviceMemory memory; + MTLBuffer_id mtlBuffer; +} VkExportMetalBufferInfoEXT; -#if defined(VK_USE_PLATFORM_XLIB_KHR) -typedef VkFlags VkXlibSurfaceCreateFlagsKHR; #endif -#if defined(VK_USE_PLATFORM_XCB_KHR) -typedef VkFlags VkXcbSurfaceCreateFlagsKHR; -#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkImportMetalBufferInfoEXT { + VkStructureType sType; + const void * pNext; + MTLBuffer_id mtlBuffer; +} VkImportMetalBufferInfoEXT; -#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) -typedef VkFlags VkDirectFBSurfaceCreateFlagsEXT; #endif -#if defined(VK_USE_PLATFORM_IOS_MVK) -typedef VkFlags VkIOSSurfaceCreateFlagsMVK; -#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalTextureInfoEXT { + VkStructureType sType; + const void * pNext; + VkImage image; + VkImageView imageView; + VkBufferView bufferView; + VkImageAspectFlagBits plane; + MTLTexture_id mtlTexture; +} VkExportMetalTextureInfoEXT; -#if defined(VK_USE_PLATFORM_MACOS_MVK) -typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; #endif #if defined(VK_USE_PLATFORM_METAL_EXT) -typedef VkFlags VkMetalSurfaceCreateFlagsEXT; -#endif +typedef struct VkImportMetalTextureInfoEXT { + VkStructureType sType; + const void * pNext; + VkImageAspectFlagBits plane; + MTLTexture_id mtlTexture; +} VkImportMetalTextureInfoEXT; -#if defined(VK_USE_PLATFORM_FUCHSIA) -typedef VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA; #endif -#if defined(VK_USE_PLATFORM_GGP) -typedef VkFlags VkStreamDescriptorSurfaceCreateFlagsGGP; -#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalIOSurfaceInfoEXT { + VkStructureType sType; + const void * pNext; + VkImage image; + IOSurfaceRef ioSurface; +} VkExportMetalIOSurfaceInfoEXT; -typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT; +#endif -typedef VkFlags VkPeerMemoryFeatureFlags; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkImportMetalIOSurfaceInfoEXT { + VkStructureType sType; + const void * pNext; + IOSurfaceRef ioSurface; +} VkImportMetalIOSurfaceInfoEXT; -#define VkPeerMemoryFeatureFlagsKHR VkPeerMemoryFeatureFlags +#endif -typedef VkFlags VkMemoryAllocateFlags; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkExportMetalSharedEventInfoEXT { + VkStructureType sType; + const void * pNext; + VkSemaphore semaphore; + VkEvent event; + MTLSharedEvent_id mtlSharedEvent; +} VkExportMetalSharedEventInfoEXT; -#define VkMemoryAllocateFlagsKHR VkMemoryAllocateFlags +#endif -typedef VkFlags VkDeviceGroupPresentModeFlagsKHR; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkImportMetalSharedEventInfoEXT { + VkStructureType sType; + const void * pNext; + MTLSharedEvent_id mtlSharedEvent; +} VkImportMetalSharedEventInfoEXT; -typedef VkFlags VkDebugReportFlagsEXT; +#endif -typedef VkFlags VkCommandPoolTrimFlags; +typedef struct VkPipelineRobustnessCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineRobustnessBufferBehavior storageBuffers; + VkPipelineRobustnessBufferBehavior uniformBuffers; + VkPipelineRobustnessBufferBehavior vertexInputs; + VkPipelineRobustnessImageBehavior images; +} VkPipelineRobustnessCreateInfo; -#define VkCommandPoolTrimFlagsKHR VkCommandPoolTrimFlags +typedef struct VkPipelineRobustnessCreateInfo VkPipelineRobustnessCreateInfoEXT; -typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; +typedef struct VkPhysicalDevicePipelineRobustnessProperties { + VkStructureType sType; + void * pNext; + VkPipelineRobustnessBufferBehavior defaultRobustnessStorageBuffers; + VkPipelineRobustnessBufferBehavior defaultRobustnessUniformBuffers; + VkPipelineRobustnessBufferBehavior defaultRobustnessVertexInputs; + VkPipelineRobustnessImageBehavior defaultRobustnessImages; +} VkPhysicalDevicePipelineRobustnessProperties; -typedef VkFlags VkExternalMemoryFeatureFlagsNV; +typedef struct VkPhysicalDevicePipelineRobustnessProperties VkPhysicalDevicePipelineRobustnessPropertiesEXT; -typedef VkFlags VkExternalMemoryHandleTypeFlags; +typedef struct VkImageViewSampleWeightCreateInfoQCOM { + VkStructureType sType; + const void * pNext; + VkOffset2D filterCenter; + VkExtent2D filterSize; + uint32_t numPhases; +} VkImageViewSampleWeightCreateInfoQCOM; -#define VkExternalMemoryHandleTypeFlagsKHR VkExternalMemoryHandleTypeFlags +typedef struct VkPhysicalDeviceImageProcessingPropertiesQCOM { + VkStructureType sType; + void * pNext; + uint32_t maxWeightFilterPhases; + VkExtent2D maxWeightFilterDimension; + VkExtent2D maxBlockMatchRegion; + VkExtent2D maxBoxFilterBlockSize; +} VkPhysicalDeviceImageProcessingPropertiesQCOM; -typedef VkFlags VkExternalMemoryFeatureFlags; +typedef struct VkTilePropertiesQCOM { + VkStructureType sType; + void * pNext; + VkExtent3D tileSize; + VkExtent2D apronSize; + VkOffset2D origin; +} VkTilePropertiesQCOM; -#define VkExternalMemoryFeatureFlagsKHR VkExternalMemoryFeatureFlags +typedef struct VkTileMemoryBindInfoQCOM { + VkStructureType sType; + const void * pNext; + VkDeviceMemory memory; +} VkTileMemoryBindInfoQCOM; -typedef VkFlags VkExternalSemaphoreHandleTypeFlags; +typedef struct VkAmigoProfilingSubmitInfoSEC { + VkStructureType sType; + const void * pNext; + uint64_t firstDrawTimestamp; + uint64_t swapBufferTimestamp; +} VkAmigoProfilingSubmitInfoSEC; -#define VkExternalSemaphoreHandleTypeFlagsKHR VkExternalSemaphoreHandleTypeFlags +typedef struct VkOpticalFlowImageFormatPropertiesNV { + VkStructureType sType; + const void * pNext; + VkFormat format; +} VkOpticalFlowImageFormatPropertiesNV; + +typedef struct VkOpticalFlowSessionCreatePrivateDataInfoNV { + VkStructureType sType; + void * pNext; + uint32_t id; + uint32_t size; + const void * pPrivateData; +} VkOpticalFlowSessionCreatePrivateDataInfoNV; + +typedef struct VkDeviceFaultVendorInfoEXT { + char description [ VK_MAX_DESCRIPTION_SIZE ]; + uint64_t vendorFaultCode; + uint64_t vendorFaultData; +} VkDeviceFaultVendorInfoEXT; + +typedef struct VkDeviceFaultVendorBinaryHeaderVersionOneEXT { + uint32_t headerSize; + VkDeviceFaultVendorBinaryHeaderVersionEXT headerVersion; + uint32_t vendorID; + uint32_t deviceID; + uint32_t driverVersion; + uint8_t pipelineCacheUUID [ VK_UUID_SIZE ]; + uint32_t applicationNameOffset; + uint32_t applicationVersion; + uint32_t engineNameOffset; + uint32_t engineVersion; + uint32_t apiVersion; +} VkDeviceFaultVendorBinaryHeaderVersionOneEXT; + +typedef struct VkDepthBiasInfoEXT { + VkStructureType sType; + const void * pNext; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; +} VkDepthBiasInfoEXT; -typedef VkFlags VkExternalSemaphoreFeatureFlags; +typedef struct VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM { + VkStructureType sType; + void * pNext; + uint64_t shaderCoreMask; + uint32_t shaderCoreCount; + uint32_t shaderWarpsPerCore; +} VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM; -#define VkExternalSemaphoreFeatureFlagsKHR VkExternalSemaphoreFeatureFlags +typedef struct VkSurfacePresentModeEXT { + VkStructureType sType; + void * pNext; + VkPresentModeKHR presentMode; +} VkSurfacePresentModeEXT; -typedef VkFlags VkSemaphoreImportFlags; +typedef struct VkSurfacePresentModeCompatibilityEXT { + VkStructureType sType; + void * pNext; + uint32_t presentModeCount; + VkPresentModeKHR * pPresentModes; +} VkSurfacePresentModeCompatibilityEXT; -#define VkSemaphoreImportFlagsKHR VkSemaphoreImportFlags +typedef struct VkSwapchainPresentFenceInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t swapchainCount; + const VkFence * pFences; +} VkSwapchainPresentFenceInfoEXT; -typedef VkFlags VkExternalFenceHandleTypeFlags; +typedef struct VkSwapchainPresentModesCreateInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t presentModeCount; + const VkPresentModeKHR * pPresentModes; +} VkSwapchainPresentModesCreateInfoEXT; -#define VkExternalFenceHandleTypeFlagsKHR VkExternalFenceHandleTypeFlags +typedef struct VkSwapchainPresentModeInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t swapchainCount; + const VkPresentModeKHR * pPresentModes; +} VkSwapchainPresentModeInfoEXT; -typedef VkFlags VkExternalFenceFeatureFlags; +typedef struct VkReleaseSwapchainImagesInfoEXT { + VkStructureType sType; + const void * pNext; + VkSwapchainKHR swapchain; + uint32_t imageIndexCount; + const uint32_t * pImageIndices; +} VkReleaseSwapchainImagesInfoEXT; -#define VkExternalFenceFeatureFlagsKHR VkExternalFenceFeatureFlags +typedef struct VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV { + VkStructureType sType; + void * pNext; + VkRayTracingInvocationReorderModeNV rayTracingInvocationReorderReorderingHint; +} VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV; -typedef VkFlags VkFenceImportFlags; +typedef struct VkPhysicalDeviceShaderCorePropertiesARM { + VkStructureType sType; + void * pNext; + uint32_t pixelRate; + uint32_t texelRate; + uint32_t fmaRate; +} VkPhysicalDeviceShaderCorePropertiesARM; -#define VkFenceImportFlagsKHR VkFenceImportFlags +typedef struct VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM { + VkStructureType sType; + const void * pNext; + uint32_t perViewRenderAreaCount; + const VkRect2D * pPerViewRenderAreas; +} VkMultiviewPerViewRenderAreasRenderPassBeginInfoQCOM; -typedef VkFlags VkSurfaceCounterFlagsEXT; +typedef struct VkQueryLowLatencySupportNV { + VkStructureType sType; + const void * pNext; + void * pQueriedLowLatencyData; +} VkQueryLowLatencySupportNV; -typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV; +typedef struct VkPhysicalDeviceShaderObjectPropertiesEXT { + VkStructureType sType; + void * pNext; + uint8_t shaderBinaryUUID [ VK_UUID_SIZE ]; + uint32_t shaderBinaryVersion; +} VkPhysicalDeviceShaderObjectPropertiesEXT; -typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef struct VkImportScreenBufferInfoQNX { + VkStructureType sType; + const void * pNext; + struct _screen_buffer * buffer; +} VkImportScreenBufferInfoQNX; -typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV; +#endif -typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef struct VkExternalFormatQNX { + VkStructureType sType; + void * pNext; + uint64_t externalFormat; +} VkExternalFormatQNX; -typedef VkFlags VkPipelineCoverageReductionStateCreateFlagsNV; +#endif -typedef VkFlags VkValidationCacheCreateFlagsEXT; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDeviceShaderEnqueuePropertiesAMDX { + VkStructureType sType; + void * pNext; + uint32_t maxExecutionGraphDepth; + uint32_t maxExecutionGraphShaderOutputNodes; + uint32_t maxExecutionGraphShaderPayloadSize; + uint32_t maxExecutionGraphShaderPayloadCount; + uint32_t executionGraphDispatchAddressAlignment; + uint32_t maxExecutionGraphWorkgroupCount [3]; + uint32_t maxExecutionGraphWorkgroups; +} VkPhysicalDeviceShaderEnqueuePropertiesAMDX; -typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT; +#endif -typedef VkFlags VkDebugUtilsMessageTypeFlagsEXT; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPipelineShaderStageNodeCreateInfoAMDX { + VkStructureType sType; + const void * pNext; + const char * pName; + uint32_t index; +} VkPipelineShaderStageNodeCreateInfoAMDX; -typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT; +#endif -typedef VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT; +typedef struct VkAntiLagPresentationInfoAMD { + VkStructureType sType; + void * pNext; + VkAntiLagStageAMD stage; + uint64_t frameIndex; +} VkAntiLagPresentationInfoAMD; -typedef VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT; +typedef struct VkBindMemoryStatus { + VkStructureType sType; + const void * pNext; + VkResult * pResult; +} VkBindMemoryStatus; -typedef VkFlags VkDescriptorBindingFlags; +typedef struct VkBindMemoryStatus VkBindMemoryStatusKHR; -#define VkDescriptorBindingFlagsEXT VkDescriptorBindingFlags +typedef struct VkPushDescriptorSetWithTemplateInfo { + VkStructureType sType; + const void * pNext; + VkDescriptorUpdateTemplate descriptorUpdateTemplate; + VkPipelineLayout layout; + uint32_t set; + const void * pData; +} VkPushDescriptorSetWithTemplateInfo; -typedef VkFlags VkConditionalRenderingFlagsEXT; +typedef struct VkPushDescriptorSetWithTemplateInfo VkPushDescriptorSetWithTemplateInfoKHR; -typedef VkFlags VkResolveModeFlags; +typedef struct VkSamplerCubicWeightsCreateInfoQCOM { + VkStructureType sType; + const void * pNext; + VkCubicFilterWeightsQCOM cubicWeights; +} VkSamplerCubicWeightsCreateInfoQCOM; -#define VkResolveModeFlagsKHR VkResolveModeFlags +typedef struct VkBlitImageCubicWeightsInfoQCOM { + VkStructureType sType; + const void * pNext; + VkCubicFilterWeightsQCOM cubicWeights; +} VkBlitImageCubicWeightsInfoQCOM; -typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT; +typedef struct VkPhysicalDeviceImageProcessing2PropertiesQCOM { + VkStructureType sType; + void * pNext; + VkExtent2D maxBlockMatchWindow; +} VkPhysicalDeviceImageProcessing2PropertiesQCOM; -typedef VkFlags VkPipelineRasterizationDepthClipStateCreateFlagsEXT; +typedef struct VkSamplerBlockMatchWindowCreateInfoQCOM { + VkStructureType sType; + const void * pNext; + VkExtent2D windowExtent; + VkBlockMatchWindowCompareModeQCOM windowCompareMode; +} VkSamplerBlockMatchWindowCreateInfoQCOM; + +typedef struct VkPhysicalDeviceLayeredDriverPropertiesMSFT { + VkStructureType sType; + void * pNext; + VkLayeredDriverUnderlyingApiMSFT underlyingAPI; +} VkPhysicalDeviceLayeredDriverPropertiesMSFT; -typedef VkFlags VkToolPurposeFlagsEXT; +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef struct VkAndroidHardwareBufferFormatResolvePropertiesANDROID { + VkStructureType sType; + void * pNext; + VkFormat colorAttachmentFormat; +} VkAndroidHardwareBufferFormatResolvePropertiesANDROID; -typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char* pLayerPrefix, - const char* pMessage, - void* pUserData); +#endif -typedef struct VkDeviceQueueCreateInfo { +typedef struct VkLatencySleepInfoNV { VkStructureType sType; - const void * pNext; - VkDeviceQueueCreateFlags flags; - uint32_t queueFamilyIndex; - uint32_t queueCount; - const float * pQueuePriorities; -} VkDeviceQueueCreateInfo; + const void * pNext; + VkSemaphore signalSemaphore; + uint64_t value; +} VkLatencySleepInfoNV; -typedef struct VkInstanceCreateInfo { +typedef struct VkSetLatencyMarkerInfoNV { VkStructureType sType; - const void * pNext; - VkInstanceCreateFlags flags; - const VkApplicationInfo * pApplicationInfo; - uint32_t enabledLayerCount; - const char * const* ppEnabledLayerNames; - uint32_t enabledExtensionCount; - const char * const* ppEnabledExtensionNames; -} VkInstanceCreateInfo; + const void * pNext; + uint64_t presentID; + VkLatencyMarkerNV marker; +} VkSetLatencyMarkerInfoNV; -typedef struct VkQueueFamilyProperties { - VkQueueFlags queueFlags; - uint32_t queueCount; - uint32_t timestampValidBits; - VkExtent3D minImageTransferGranularity; -} VkQueueFamilyProperties; +typedef struct VkLatencyTimingsFrameReportNV { + VkStructureType sType; + const void * pNext; + uint64_t presentID; + uint64_t inputSampleTimeUs; + uint64_t simStartTimeUs; + uint64_t simEndTimeUs; + uint64_t renderSubmitStartTimeUs; + uint64_t renderSubmitEndTimeUs; + uint64_t presentStartTimeUs; + uint64_t presentEndTimeUs; + uint64_t driverStartTimeUs; + uint64_t driverEndTimeUs; + uint64_t osRenderQueueStartTimeUs; + uint64_t osRenderQueueEndTimeUs; + uint64_t gpuRenderStartTimeUs; + uint64_t gpuRenderEndTimeUs; +} VkLatencyTimingsFrameReportNV; + +typedef struct VkOutOfBandQueueTypeInfoNV { + VkStructureType sType; + const void * pNext; + VkOutOfBandQueueTypeNV queueType; +} VkOutOfBandQueueTypeInfoNV; -typedef struct VkMemoryAllocateInfo { +typedef struct VkLatencySubmissionPresentIdNV { VkStructureType sType; - const void * pNext; - VkDeviceSize allocationSize; - uint32_t memoryTypeIndex; -} VkMemoryAllocateInfo; + const void * pNext; + uint64_t presentID; +} VkLatencySubmissionPresentIdNV; -typedef struct VkMemoryRequirements { - VkDeviceSize size; - VkDeviceSize alignment; - uint32_t memoryTypeBits; -} VkMemoryRequirements; +typedef struct VkLatencySurfaceCapabilitiesNV { + VkStructureType sType; + const void * pNext; + uint32_t presentModeCount; + VkPresentModeKHR * pPresentModes; +} VkLatencySurfaceCapabilitiesNV; -typedef struct VkSparseImageFormatProperties { - VkImageAspectFlags aspectMask; - VkExtent3D imageGranularity; - VkSparseImageFormatFlags flags; -} VkSparseImageFormatProperties; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDeviceCudaKernelLaunchPropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t computeCapabilityMinor; + uint32_t computeCapabilityMajor; +} VkPhysicalDeviceCudaKernelLaunchPropertiesNV; -typedef struct VkSparseImageMemoryRequirements { - VkSparseImageFormatProperties formatProperties; - uint32_t imageMipTailFirstLod; - VkDeviceSize imageMipTailSize; - VkDeviceSize imageMipTailOffset; - VkDeviceSize imageMipTailStride; -} VkSparseImageMemoryRequirements; +#endif -typedef struct VkMemoryType { - VkMemoryPropertyFlags propertyFlags; - uint32_t heapIndex; -} VkMemoryType; +typedef struct VkDeviceQueueShaderCoreControlCreateInfoARM { + VkStructureType sType; + void * pNext; + uint32_t shaderCoreCount; +} VkDeviceQueueShaderCoreControlCreateInfoARM; -typedef struct VkMemoryHeap { - VkDeviceSize size; - VkMemoryHeapFlags flags; -} VkMemoryHeap; +typedef struct VkPhysicalDeviceRenderPassStripedPropertiesARM { + VkStructureType sType; + void * pNext; + VkExtent2D renderPassStripeGranularity; + uint32_t maxRenderPassStripes; +} VkPhysicalDeviceRenderPassStripedPropertiesARM; -typedef struct VkMappedMemoryRange { +typedef struct VkRenderPassStripeInfoARM { VkStructureType sType; - const void * pNext; - VkDeviceMemory memory; - VkDeviceSize offset; - VkDeviceSize size; -} VkMappedMemoryRange; + const void * pNext; + VkRect2D stripeArea; +} VkRenderPassStripeInfoARM; -typedef struct VkFormatProperties { - VkFormatFeatureFlags linearTilingFeatures; - VkFormatFeatureFlags optimalTilingFeatures; - VkFormatFeatureFlags bufferFeatures; -} VkFormatProperties; +typedef struct VkRenderPassStripeBeginInfoARM { + VkStructureType sType; + const void * pNext; + uint32_t stripeInfoCount; + const VkRenderPassStripeInfoARM * pStripeInfos; +} VkRenderPassStripeBeginInfoARM; -typedef struct VkImageFormatProperties { - VkExtent3D maxExtent; - uint32_t maxMipLevels; - uint32_t maxArrayLayers; - VkSampleCountFlags sampleCounts; - VkDeviceSize maxResourceSize; -} VkImageFormatProperties; +typedef struct VkRenderingAttachmentLocationInfo { + VkStructureType sType; + const void * pNext; + uint32_t colorAttachmentCount; + const uint32_t * pColorAttachmentLocations; +} VkRenderingAttachmentLocationInfo; -typedef struct VkDescriptorBufferInfo { - VkBuffer buffer; - VkDeviceSize offset; - VkDeviceSize range; -} VkDescriptorBufferInfo; +typedef struct VkRenderingAttachmentLocationInfo VkRenderingAttachmentLocationInfoKHR; -typedef struct VkWriteDescriptorSet { +typedef struct VkRenderingInputAttachmentIndexInfo { VkStructureType sType; - const void * pNext; - VkDescriptorSet dstSet; - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; - VkDescriptorType descriptorType; - const VkDescriptorImageInfo * pImageInfo; - const VkDescriptorBufferInfo * pBufferInfo; - const VkBufferView * pTexelBufferView; -} VkWriteDescriptorSet; + const void * pNext; + uint32_t colorAttachmentCount; + const uint32_t * pColorAttachmentInputIndices; + const uint32_t * pDepthInputAttachmentIndex; + const uint32_t * pStencilInputAttachmentIndex; +} VkRenderingInputAttachmentIndexInfo; -typedef struct VkBufferCreateInfo { +typedef struct VkRenderingInputAttachmentIndexInfo VkRenderingInputAttachmentIndexInfoKHR; + +typedef struct VkMemoryMapPlacedInfoEXT { VkStructureType sType; - const void * pNext; - VkBufferCreateFlags flags; - VkDeviceSize size; - VkBufferUsageFlags usage; - VkSharingMode sharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t * pQueueFamilyIndices; -} VkBufferCreateInfo; + const void * pNext; + void * pPlacedAddress; +} VkMemoryMapPlacedInfoEXT; -typedef struct VkBufferViewCreateInfo { +typedef struct VkPhysicalDeviceImageAlignmentControlPropertiesMESA { VkStructureType sType; - const void * pNext; - VkBufferViewCreateFlags flags; - VkBuffer buffer; - VkFormat format; - VkDeviceSize offset; - VkDeviceSize range; -} VkBufferViewCreateInfo; + void * pNext; + uint32_t supportedImageAlignmentMask; +} VkPhysicalDeviceImageAlignmentControlPropertiesMESA; -typedef struct VkImageSubresource { - VkImageAspectFlags aspectMask; - uint32_t mipLevel; - uint32_t arrayLayer; -} VkImageSubresource; +typedef struct VkImageAlignmentControlCreateInfoMESA { + VkStructureType sType; + const void * pNext; + uint32_t maximumRequestedAlignment; +} VkImageAlignmentControlCreateInfoMESA; -typedef struct VkImageSubresourceLayers { - VkImageAspectFlags aspectMask; - uint32_t mipLevel; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkImageSubresourceLayers; +typedef struct VkDepthClampRangeEXT { + float minDepthClamp; + float maxDepthClamp; +} VkDepthClampRangeEXT; -typedef struct VkImageSubresourceRange { - VkImageAspectFlags aspectMask; - uint32_t baseMipLevel; - uint32_t levelCount; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkImageSubresourceRange; +typedef struct VkPhysicalDeviceCooperativeMatrix2PropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t cooperativeMatrixWorkgroupScopeMaxWorkgroupSize; + uint32_t cooperativeMatrixFlexibleDimensionsMaxDimension; + uint32_t cooperativeMatrixWorkgroupScopeReservedSharedMemory; +} VkPhysicalDeviceCooperativeMatrix2PropertiesNV; -typedef struct VkMemoryBarrier { +typedef struct VkPerTileBeginInfoQCOM { VkStructureType sType; - const void * pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; -} VkMemoryBarrier; + const void * pNext; +} VkPerTileBeginInfoQCOM; -typedef struct VkBufferMemoryBarrier { +typedef struct VkPerTileEndInfoQCOM { VkStructureType sType; - const void * pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkBuffer buffer; - VkDeviceSize offset; - VkDeviceSize size; -} VkBufferMemoryBarrier; + const void * pNext; +} VkPerTileEndInfoQCOM; -typedef struct VkImageMemoryBarrier { +typedef struct VkDispatchTileInfoQCOM { VkStructureType sType; - const void * pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkImageLayout oldLayout; - VkImageLayout newLayout; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkImage image; - VkImageSubresourceRange subresourceRange; -} VkImageMemoryBarrier; + const void * pNext; +} VkDispatchTileInfoQCOM; -typedef struct VkImageCreateInfo { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkSetPresentConfigNV { VkStructureType sType; - const void * pNext; - VkImageCreateFlags flags; - VkImageType imageType; - VkFormat format; - VkExtent3D extent; - uint32_t mipLevels; - uint32_t arrayLayers; - VkSampleCountFlagBits samples; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkSharingMode sharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t * pQueueFamilyIndices; - VkImageLayout initialLayout; -} VkImageCreateInfo; + const void * pNext; + uint32_t numFramesPerBatch; + uint32_t presentConfigFeedback; +} VkSetPresentConfigNV; -typedef struct VkSubresourceLayout { - VkDeviceSize offset; - VkDeviceSize size; - VkDeviceSize rowPitch; - VkDeviceSize arrayPitch; - VkDeviceSize depthPitch; -} VkSubresourceLayout; +#endif -typedef struct VkImageViewCreateInfo { +typedef struct VkExternalComputeQueueDeviceCreateInfoNV { VkStructureType sType; - const void * pNext; - VkImageViewCreateFlags flags; - VkImage image; - VkImageViewType viewType; - VkFormat format; - VkComponentMapping components; - VkImageSubresourceRange subresourceRange; -} VkImageViewCreateInfo; + const void * pNext; + uint32_t reservedExternalQueues; +} VkExternalComputeQueueDeviceCreateInfoNV; -typedef struct VkBufferCopy { - VkDeviceSize srcOffset; - VkDeviceSize dstOffset; - VkDeviceSize size; -} VkBufferCopy; +typedef struct VkExternalComputeQueueCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkQueue preferredQueue; +} VkExternalComputeQueueCreateInfoNV; -typedef struct VkSparseMemoryBind { - VkDeviceSize resourceOffset; - VkDeviceSize size; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseMemoryBind; +typedef struct VkExternalComputeQueueDataParamsNV { + VkStructureType sType; + const void * pNext; + uint32_t deviceIndex; +} VkExternalComputeQueueDataParamsNV; -typedef struct VkSparseImageMemoryBind { - VkImageSubresource subresource; - VkOffset3D offset; - VkExtent3D extent; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseImageMemoryBind; +typedef struct VkPhysicalDeviceExternalComputeQueuePropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t externalDataSize; + uint32_t maxExternalQueues; +} VkPhysicalDeviceExternalComputeQueuePropertiesNV; -typedef struct VkSparseBufferMemoryBindInfo { - VkBuffer buffer; - uint32_t bindCount; - const VkSparseMemoryBind * pBinds; -} VkSparseBufferMemoryBindInfo; +VK_DEFINE_HANDLE(VkExternalComputeQueueNV) +/* Complete version of this file */ +#define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 4, VK_HEADER_VERSION) +typedef uint32_t VkSampleMask; +typedef uint32_t VkBool32; +typedef uint32_t VkFlags; +typedef uint64_t VkFlags64; +typedef uint64_t VkDeviceSize; +typedef uint64_t VkDeviceAddress; +typedef VkFlags VkFramebufferCreateFlags; +typedef VkFlags VkQueryPoolCreateFlags; +typedef VkFlags VkRenderPassCreateFlags; +typedef VkFlags VkSamplerCreateFlags; +typedef VkFlags VkPipelineLayoutCreateFlags; +typedef VkFlags VkPipelineCacheCreateFlags; +typedef VkFlags VkPipelineDepthStencilStateCreateFlags; +typedef VkFlags VkPipelineDynamicStateCreateFlags; +typedef VkFlags VkPipelineColorBlendStateCreateFlags; +typedef VkFlags VkPipelineMultisampleStateCreateFlags; +typedef VkFlags VkPipelineRasterizationStateCreateFlags; +typedef VkFlags VkPipelineViewportStateCreateFlags; +typedef VkFlags VkPipelineTessellationStateCreateFlags; +typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; +typedef VkFlags VkPipelineVertexInputStateCreateFlags; +typedef VkFlags VkPipelineShaderStageCreateFlags; +typedef VkFlags VkDescriptorSetLayoutCreateFlags; +typedef VkFlags VkBufferViewCreateFlags; +typedef VkFlags VkInstanceCreateFlags; +typedef VkFlags VkDeviceCreateFlags; +typedef VkFlags VkDeviceQueueCreateFlags; +typedef VkFlags VkQueueFlags; +typedef VkFlags VkMemoryPropertyFlags; +typedef VkFlags VkMemoryHeapFlags; +typedef VkFlags VkAccessFlags; +typedef VkFlags VkBufferUsageFlags; +typedef VkFlags VkBufferCreateFlags; +typedef VkFlags VkShaderStageFlags; +typedef VkFlags VkImageUsageFlags; +typedef VkFlags VkImageCreateFlags; +typedef VkFlags VkImageViewCreateFlags; +typedef VkFlags VkPipelineCreateFlags; +typedef VkFlags VkColorComponentFlags; +typedef VkFlags VkFenceCreateFlags; +typedef VkFlags VkSemaphoreCreateFlags; +typedef VkFlags VkFormatFeatureFlags; +typedef VkFlags VkQueryControlFlags; +typedef VkFlags VkQueryResultFlags; +typedef VkFlags VkShaderModuleCreateFlags; +typedef VkFlags VkEventCreateFlags; +typedef VkFlags VkCommandPoolCreateFlags; +typedef VkFlags VkCommandPoolResetFlags; +typedef VkFlags VkCommandBufferResetFlags; +typedef VkFlags VkCommandBufferUsageFlags; +typedef VkFlags VkQueryPipelineStatisticFlags; +typedef VkFlags VkMemoryMapFlags; +typedef VkFlags VkMemoryUnmapFlags; +#define VkMemoryUnmapFlagsKHR VkMemoryUnmapFlags +typedef VkFlags VkImageAspectFlags; +typedef VkFlags VkSparseMemoryBindFlags; +typedef VkFlags VkSparseImageFormatFlags; +typedef VkFlags VkSubpassDescriptionFlags; +typedef VkFlags VkPipelineStageFlags; +typedef VkFlags VkSampleCountFlags; +typedef VkFlags VkAttachmentDescriptionFlags; +typedef VkFlags VkStencilFaceFlags; +typedef VkFlags VkCullModeFlags; +typedef VkFlags VkDescriptorPoolCreateFlags; +typedef VkFlags VkDescriptorPoolResetFlags; +typedef VkFlags VkDependencyFlags; +typedef VkFlags VkSubgroupFeatureFlags; +typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNV; +typedef VkFlags VkIndirectStateFlagsNV; +typedef VkFlags VkGeometryFlagsKHR; +#define VkGeometryFlagsNV VkGeometryFlagsKHR +typedef VkFlags VkGeometryInstanceFlagsKHR; +#define VkGeometryInstanceFlagsNV VkGeometryInstanceFlagsKHR +typedef VkFlags VkClusterAccelerationStructureGeometryFlagsNV; +typedef VkFlags VkClusterAccelerationStructureClusterFlagsNV; +typedef VkFlags VkClusterAccelerationStructureAddressResolutionFlagsNV; +typedef VkFlags VkBuildAccelerationStructureFlagsKHR; +#define VkBuildAccelerationStructureFlagsNV VkBuildAccelerationStructureFlagsKHR +typedef VkFlags VkPrivateDataSlotCreateFlags; +#define VkPrivateDataSlotCreateFlagsEXT VkPrivateDataSlotCreateFlags +typedef VkFlags VkAccelerationStructureCreateFlagsKHR; +typedef VkFlags VkDescriptorUpdateTemplateCreateFlags; +#define VkDescriptorUpdateTemplateCreateFlagsKHR VkDescriptorUpdateTemplateCreateFlags +typedef VkFlags VkPipelineCreationFeedbackFlags; +#define VkPipelineCreationFeedbackFlagsEXT VkPipelineCreationFeedbackFlags +typedef VkFlags VkPerformanceCounterDescriptionFlagsKHR; +typedef VkFlags VkAcquireProfilingLockFlagsKHR; +typedef VkFlags VkSemaphoreWaitFlags; +#define VkSemaphoreWaitFlagsKHR VkSemaphoreWaitFlags +typedef VkFlags VkPipelineCompilerControlFlagsAMD; +typedef VkFlags VkShaderCorePropertiesFlagsAMD; +typedef VkFlags VkDeviceDiagnosticsConfigFlagsNV; +typedef VkFlags64 VkAccessFlags2; +#define VkAccessFlags2KHR VkAccessFlags2 +typedef VkFlags64 VkPipelineStageFlags2; +#define VkPipelineStageFlags2KHR VkPipelineStageFlags2 +typedef VkFlags VkAccelerationStructureMotionInfoFlagsNV; +typedef VkFlags VkAccelerationStructureMotionInstanceFlagsNV; +typedef VkFlags64 VkFormatFeatureFlags2; +#define VkFormatFeatureFlags2KHR VkFormatFeatureFlags2 +typedef VkFlags VkRenderingFlags; +typedef VkFlags64 VkMemoryDecompressionMethodFlagsNV; +#define VkRenderingFlagsKHR VkRenderingFlags +typedef VkFlags VkBuildMicromapFlagsEXT; +typedef VkFlags VkMicromapCreateFlagsEXT; +typedef VkFlags VkIndirectCommandsLayoutUsageFlagsEXT; +typedef VkFlags VkIndirectCommandsInputModeFlagsEXT; +typedef VkFlags VkDirectDriverLoadingFlagsLUNARG; +typedef VkFlags64 VkPipelineCreateFlags2; +#define VkPipelineCreateFlags2KHR VkPipelineCreateFlags2 +typedef VkFlags64 VkBufferUsageFlags2; +#define VkBufferUsageFlags2KHR VkBufferUsageFlags2 +typedef VkFlags VkCompositeAlphaFlagsKHR; +typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; +typedef VkFlags VkSurfaceTransformFlagsKHR; +typedef VkFlags VkSwapchainCreateFlagsKHR; +typedef VkFlags VkDisplayModeCreateFlagsKHR; +typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; +#endif -typedef struct VkSparseImageOpaqueMemoryBindInfo { - VkImage image; - uint32_t bindCount; - const VkSparseMemoryBind * pBinds; -} VkSparseImageOpaqueMemoryBindInfo; +#if defined(VK_USE_PLATFORM_VI_NN) +typedef VkFlags VkViSurfaceCreateFlagsNN; +#endif -typedef struct VkSparseImageMemoryBindInfo { - VkImage image; - uint32_t bindCount; - const VkSparseImageMemoryBind * pBinds; -} VkSparseImageMemoryBindInfo; +#if defined(VK_USE_PLATFORM_WAYLAND_KHR) +typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; +#endif -typedef struct VkBindSparseInfo { - VkStructureType sType; - const void * pNext; - uint32_t waitSemaphoreCount; - const VkSemaphore * pWaitSemaphores; - uint32_t bufferBindCount; - const VkSparseBufferMemoryBindInfo * pBufferBinds; - uint32_t imageOpaqueBindCount; - const VkSparseImageOpaqueMemoryBindInfo * pImageOpaqueBinds; - uint32_t imageBindCount; - const VkSparseImageMemoryBindInfo * pImageBinds; - uint32_t signalSemaphoreCount; - const VkSemaphore * pSignalSemaphores; -} VkBindSparseInfo; +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef VkFlags VkWin32SurfaceCreateFlagsKHR; +#endif -typedef struct VkImageCopy { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageCopy; +#if defined(VK_USE_PLATFORM_XLIB_KHR) +typedef VkFlags VkXlibSurfaceCreateFlagsKHR; +#endif -typedef struct VkImageBlit { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffsets [2]; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffsets [2]; -} VkImageBlit; +#if defined(VK_USE_PLATFORM_XCB_KHR) +typedef VkFlags VkXcbSurfaceCreateFlagsKHR; +#endif -typedef struct VkBufferImageCopy { - VkDeviceSize bufferOffset; - uint32_t bufferRowLength; - uint32_t bufferImageHeight; - VkImageSubresourceLayers imageSubresource; - VkOffset3D imageOffset; - VkExtent3D imageExtent; -} VkBufferImageCopy; +#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) +typedef VkFlags VkDirectFBSurfaceCreateFlagsEXT; +#endif -typedef struct VkImageResolve { - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageResolve; +#if defined(VK_USE_PLATFORM_IOS_MVK) +typedef VkFlags VkIOSSurfaceCreateFlagsMVK; +#endif -typedef struct VkShaderModuleCreateInfo { - VkStructureType sType; - const void * pNext; - VkShaderModuleCreateFlags flags; - size_t codeSize; - const uint32_t * pCode; -} VkShaderModuleCreateInfo; +#if defined(VK_USE_PLATFORM_MACOS_MVK) +typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; +#endif -typedef struct VkDescriptorSetLayoutBinding { - uint32_t binding; - VkDescriptorType descriptorType; - uint32_t descriptorCount; - VkShaderStageFlags stageFlags; - const VkSampler * pImmutableSamplers; -} VkDescriptorSetLayoutBinding; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef VkFlags VkMetalSurfaceCreateFlagsEXT; +#endif -typedef struct VkDescriptorSetLayoutCreateInfo { +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA; +#endif + +#if defined(VK_USE_PLATFORM_GGP) +typedef VkFlags VkStreamDescriptorSurfaceCreateFlagsGGP; +#endif + +typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef VkFlags VkScreenSurfaceCreateFlagsQNX; +#endif + +typedef VkFlags VkPeerMemoryFeatureFlags; +#define VkPeerMemoryFeatureFlagsKHR VkPeerMemoryFeatureFlags +typedef VkFlags VkMemoryAllocateFlags; +#define VkMemoryAllocateFlagsKHR VkMemoryAllocateFlags +typedef VkFlags VkDeviceGroupPresentModeFlagsKHR; +typedef VkFlags VkDebugReportFlagsEXT; +typedef VkFlags VkCommandPoolTrimFlags; +#define VkCommandPoolTrimFlagsKHR VkCommandPoolTrimFlags +typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; +typedef VkFlags VkClusterAccelerationStructureIndexFormatFlagsNV; +typedef VkFlags VkExternalMemoryFeatureFlagsNV; +typedef VkFlags VkExternalMemoryHandleTypeFlags; +#define VkExternalMemoryHandleTypeFlagsKHR VkExternalMemoryHandleTypeFlags +typedef VkFlags VkExternalMemoryFeatureFlags; +#define VkExternalMemoryFeatureFlagsKHR VkExternalMemoryFeatureFlags +typedef VkFlags VkExternalSemaphoreHandleTypeFlags; +#define VkExternalSemaphoreHandleTypeFlagsKHR VkExternalSemaphoreHandleTypeFlags +typedef VkFlags VkExternalSemaphoreFeatureFlags; +#define VkExternalSemaphoreFeatureFlagsKHR VkExternalSemaphoreFeatureFlags +typedef VkFlags VkSemaphoreImportFlags; +#define VkSemaphoreImportFlagsKHR VkSemaphoreImportFlags +typedef VkFlags VkExternalFenceHandleTypeFlags; +#define VkExternalFenceHandleTypeFlagsKHR VkExternalFenceHandleTypeFlags +typedef VkFlags VkExternalFenceFeatureFlags; +#define VkExternalFenceFeatureFlagsKHR VkExternalFenceFeatureFlags +typedef VkFlags VkFenceImportFlags; +#define VkFenceImportFlagsKHR VkFenceImportFlags +typedef VkFlags VkSurfaceCounterFlagsEXT; +typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV; +typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT; +typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV; +typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV; +typedef VkFlags VkPipelineCoverageReductionStateCreateFlagsNV; +typedef VkFlags VkValidationCacheCreateFlagsEXT; +typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT; +typedef VkFlags VkDebugUtilsMessageTypeFlagsEXT; +typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT; +typedef VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT; +typedef VkFlags VkDeviceMemoryReportFlagsEXT; +typedef VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT; +typedef VkFlags VkDescriptorBindingFlags; +#define VkDescriptorBindingFlagsEXT VkDescriptorBindingFlags +typedef VkFlags VkConditionalRenderingFlagsEXT; +typedef VkFlags VkResolveModeFlags; +#define VkResolveModeFlagsKHR VkResolveModeFlags +typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT; +typedef VkFlags VkPipelineRasterizationDepthClipStateCreateFlagsEXT; +typedef VkFlags VkToolPurposeFlags; +#define VkToolPurposeFlagsEXT VkToolPurposeFlags +typedef VkFlags VkSubmitFlags; +#define VkSubmitFlagsKHR VkSubmitFlags +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkFlags VkImageFormatConstraintsFlagsFUCHSIA; +#endif + +typedef VkFlags VkHostImageCopyFlags; +#define VkHostImageCopyFlagsEXT VkHostImageCopyFlags +typedef VkFlags VkPartitionedAccelerationStructureInstanceFlagsNV; +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkFlags VkImageConstraintsInfoFlagsFUCHSIA; +#endif + +typedef VkFlags VkGraphicsPipelineLibraryFlagsEXT; +typedef VkFlags VkImageCompressionFlagsEXT; +typedef VkFlags VkImageCompressionFixedRateFlagsEXT; +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef VkFlags VkExportMetalObjectTypeFlagsEXT; +#endif + +typedef VkFlags VkDeviceAddressBindingFlagsEXT; +typedef VkFlags VkOpticalFlowGridSizeFlagsNV; +typedef VkFlags VkOpticalFlowUsageFlagsNV; +typedef VkFlags VkOpticalFlowSessionCreateFlagsNV; +typedef VkFlags VkOpticalFlowExecuteFlagsNV; +typedef VkFlags VkFrameBoundaryFlagsEXT; +typedef VkFlags VkPresentScalingFlagsEXT; +typedef VkFlags VkPresentGravityFlagsEXT; +typedef VkFlags VkShaderCreateFlagsEXT; +typedef VkFlags VkTileShadingRenderPassFlagsQCOM; +typedef VkFlags64 VkPhysicalDeviceSchedulingControlsFlagsARM; +typedef VkFlags64 VkAccessFlags3KHR; +typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* pUserData); +typedef struct VkDeviceQueueCreateInfo { VkStructureType sType; - const void * pNext; - VkDescriptorSetLayoutCreateFlags flags; - uint32_t bindingCount; - const VkDescriptorSetLayoutBinding * pBindings; -} VkDescriptorSetLayoutCreateInfo; + const void * pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueCount; + const float * pQueuePriorities; +} VkDeviceQueueCreateInfo; -typedef struct VkDescriptorPoolCreateInfo { +typedef struct VkInstanceCreateInfo { VkStructureType sType; - const void * pNext; - VkDescriptorPoolCreateFlags flags; - uint32_t maxSets; - uint32_t poolSizeCount; - const VkDescriptorPoolSize * pPoolSizes; -} VkDescriptorPoolCreateInfo; + const void * pNext; + VkInstanceCreateFlags flags; + const VkApplicationInfo * pApplicationInfo; + uint32_t enabledLayerCount; + const char * const* ppEnabledLayerNames; + uint32_t enabledExtensionCount; + const char * const* ppEnabledExtensionNames; +} VkInstanceCreateInfo; -typedef struct VkPipelineShaderStageCreateInfo { +typedef struct VkQueueFamilyProperties { + VkQueueFlags queueFlags; + uint32_t queueCount; + uint32_t timestampValidBits; + VkExtent3D minImageTransferGranularity; +} VkQueueFamilyProperties; + +typedef struct VkMemoryAllocateInfo { VkStructureType sType; const void * pNext; - VkPipelineShaderStageCreateFlags flags; - VkShaderStageFlagBits stage; - VkShaderModule module; - const char * pName; - const VkSpecializationInfo * pSpecializationInfo; -} VkPipelineShaderStageCreateInfo; + VkDeviceSize allocationSize; + uint32_t memoryTypeIndex; +} VkMemoryAllocateInfo; -typedef struct VkComputePipelineCreateInfo { +typedef struct VkMemoryRequirements { + VkDeviceSize size; + VkDeviceSize alignment; + uint32_t memoryTypeBits; +} VkMemoryRequirements; + +typedef struct VkSparseImageFormatProperties { + VkImageAspectFlags aspectMask; + VkExtent3D imageGranularity; + VkSparseImageFormatFlags flags; +} VkSparseImageFormatProperties; + +typedef struct VkSparseImageMemoryRequirements { + VkSparseImageFormatProperties formatProperties; + uint32_t imageMipTailFirstLod; + VkDeviceSize imageMipTailSize; + VkDeviceSize imageMipTailOffset; + VkDeviceSize imageMipTailStride; +} VkSparseImageMemoryRequirements; + +typedef struct VkMemoryType { + VkMemoryPropertyFlags propertyFlags; + uint32_t heapIndex; +} VkMemoryType; + +typedef struct VkMemoryHeap { + VkDeviceSize size; + VkMemoryHeapFlags flags; +} VkMemoryHeap; + +typedef struct VkMappedMemoryRange { VkStructureType sType; const void * pNext; - VkPipelineCreateFlags flags; - VkPipelineShaderStageCreateInfo stage; - VkPipelineLayout layout; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkComputePipelineCreateInfo; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; +} VkMappedMemoryRange; -typedef struct VkPipelineVertexInputStateCreateInfo { +typedef struct VkFormatProperties { + VkFormatFeatureFlags linearTilingFeatures; + VkFormatFeatureFlags optimalTilingFeatures; + VkFormatFeatureFlags bufferFeatures; +} VkFormatProperties; + +typedef struct VkImageFormatProperties { + VkExtent3D maxExtent; + uint32_t maxMipLevels; + uint32_t maxArrayLayers; + VkSampleCountFlags sampleCounts; + VkDeviceSize maxResourceSize; +} VkImageFormatProperties; + +typedef struct VkDescriptorBufferInfo { + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize range; +} VkDescriptorBufferInfo; + +typedef struct VkWriteDescriptorSet { VkStructureType sType; const void * pNext; - VkPipelineVertexInputStateCreateFlags flags; - uint32_t vertexBindingDescriptionCount; - const VkVertexInputBindingDescription * pVertexBindingDescriptions; - uint32_t vertexAttributeDescriptionCount; - const VkVertexInputAttributeDescription * pVertexAttributeDescriptions; -} VkPipelineVertexInputStateCreateInfo; + VkDescriptorSet dstSet; + uint32_t dstBinding; + uint32_t dstArrayElement; + uint32_t descriptorCount; + VkDescriptorType descriptorType; + const VkDescriptorImageInfo * pImageInfo; + const VkDescriptorBufferInfo * pBufferInfo; + const VkBufferView * pTexelBufferView; +} VkWriteDescriptorSet; -typedef struct VkPipelineInputAssemblyStateCreateInfo { +typedef struct VkBufferUsageFlags2CreateInfo { VkStructureType sType; - const void * pNext; - VkPipelineInputAssemblyStateCreateFlags flags; - VkPrimitiveTopology topology; - VkBool32 primitiveRestartEnable; -} VkPipelineInputAssemblyStateCreateInfo; + const void * pNext; + VkBufferUsageFlags2 usage; +} VkBufferUsageFlags2CreateInfo; -typedef struct VkPipelineTessellationStateCreateInfo { +typedef struct VkBufferUsageFlags2CreateInfo VkBufferUsageFlags2CreateInfoKHR; + +typedef struct VkBufferCreateInfo { VkStructureType sType; const void * pNext; - VkPipelineTessellationStateCreateFlags flags; - uint32_t patchControlPoints; -} VkPipelineTessellationStateCreateInfo; + VkBufferCreateFlags flags; + VkDeviceSize size; + VkBufferUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t * pQueueFamilyIndices; +} VkBufferCreateInfo; -typedef struct VkPipelineViewportStateCreateInfo { +typedef struct VkBufferViewCreateInfo { VkStructureType sType; const void * pNext; - VkPipelineViewportStateCreateFlags flags; - uint32_t viewportCount; - const VkViewport * pViewports; - uint32_t scissorCount; - const VkRect2D * pScissors; -} VkPipelineViewportStateCreateInfo; + VkBufferViewCreateFlags flags; + VkBuffer buffer; + VkFormat format; + VkDeviceSize offset; + VkDeviceSize range; +} VkBufferViewCreateInfo; -typedef struct VkPipelineRasterizationStateCreateInfo { - VkStructureType sType; - const void * pNext; - VkPipelineRasterizationStateCreateFlags flags; - VkBool32 depthClampEnable; - VkBool32 rasterizerDiscardEnable; - VkPolygonMode polygonMode; - VkCullModeFlags cullMode; - VkFrontFace frontFace; - VkBool32 depthBiasEnable; - float depthBiasConstantFactor; - float depthBiasClamp; - float depthBiasSlopeFactor; - float lineWidth; -} VkPipelineRasterizationStateCreateInfo; +typedef struct VkImageSubresource { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t arrayLayer; +} VkImageSubresource; -typedef struct VkPipelineMultisampleStateCreateInfo { - VkStructureType sType; - const void * pNext; - VkPipelineMultisampleStateCreateFlags flags; - VkSampleCountFlagBits rasterizationSamples; - VkBool32 sampleShadingEnable; - float minSampleShading; - const VkSampleMask * pSampleMask; - VkBool32 alphaToCoverageEnable; - VkBool32 alphaToOneEnable; -} VkPipelineMultisampleStateCreateInfo; +typedef struct VkImageSubresourceLayers { + VkImageAspectFlags aspectMask; + uint32_t mipLevel; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceLayers; -typedef struct VkPipelineColorBlendAttachmentState { - VkBool32 blendEnable; - VkBlendFactor srcColorBlendFactor; - VkBlendFactor dstColorBlendFactor; - VkBlendOp colorBlendOp; - VkBlendFactor srcAlphaBlendFactor; - VkBlendFactor dstAlphaBlendFactor; - VkBlendOp alphaBlendOp; - VkColorComponentFlags colorWriteMask; -} VkPipelineColorBlendAttachmentState; +typedef struct VkImageSubresourceRange { + VkImageAspectFlags aspectMask; + uint32_t baseMipLevel; + uint32_t levelCount; + uint32_t baseArrayLayer; + uint32_t layerCount; +} VkImageSubresourceRange; -typedef struct VkPipelineColorBlendStateCreateInfo { +typedef struct VkMemoryBarrier { VkStructureType sType; const void * pNext; - VkPipelineColorBlendStateCreateFlags flags; - VkBool32 logicOpEnable; - VkLogicOp logicOp; - uint32_t attachmentCount; - const VkPipelineColorBlendAttachmentState * pAttachments; - float blendConstants [4]; -} VkPipelineColorBlendStateCreateInfo; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; +} VkMemoryBarrier; -typedef struct VkPipelineDynamicStateCreateInfo { +typedef struct VkBufferMemoryBarrier { VkStructureType sType; const void * pNext; - VkPipelineDynamicStateCreateFlags flags; - uint32_t dynamicStateCount; - const VkDynamicState * pDynamicStates; -} VkPipelineDynamicStateCreateInfo; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier; -typedef struct VkPipelineDepthStencilStateCreateInfo { +typedef struct VkImageMemoryBarrier { VkStructureType sType; const void * pNext; - VkPipelineDepthStencilStateCreateFlags flags; - VkBool32 depthTestEnable; - VkBool32 depthWriteEnable; - VkCompareOp depthCompareOp; - VkBool32 depthBoundsTestEnable; - VkBool32 stencilTestEnable; - VkStencilOpState front; - VkStencilOpState back; - float minDepthBounds; - float maxDepthBounds; -} VkPipelineDepthStencilStateCreateInfo; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier; -typedef struct VkGraphicsPipelineCreateInfo { +typedef struct VkImageCreateInfo { VkStructureType sType; const void * pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo * pStages; - const VkPipelineVertexInputStateCreateInfo * pVertexInputState; - const VkPipelineInputAssemblyStateCreateInfo * pInputAssemblyState; - const VkPipelineTessellationStateCreateInfo * pTessellationState; - const VkPipelineViewportStateCreateInfo * pViewportState; - const VkPipelineRasterizationStateCreateInfo * pRasterizationState; - const VkPipelineMultisampleStateCreateInfo * pMultisampleState; - const VkPipelineDepthStencilStateCreateInfo * pDepthStencilState; - const VkPipelineColorBlendStateCreateInfo * pColorBlendState; - const VkPipelineDynamicStateCreateInfo * pDynamicState; - VkPipelineLayout layout; - VkRenderPass renderPass; - uint32_t subpass; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkGraphicsPipelineCreateInfo; + VkImageCreateFlags flags; + VkImageType imageType; + VkFormat format; + VkExtent3D extent; + uint32_t mipLevels; + uint32_t arrayLayers; + VkSampleCountFlagBits samples; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t * pQueueFamilyIndices; + VkImageLayout initialLayout; +} VkImageCreateInfo; -typedef struct VkPipelineCacheCreateInfo { +typedef struct VkSubresourceLayout { + VkDeviceSize offset; + VkDeviceSize size; + VkDeviceSize rowPitch; + VkDeviceSize arrayPitch; + VkDeviceSize depthPitch; +} VkSubresourceLayout; + +typedef struct VkImageViewCreateInfo { VkStructureType sType; const void * pNext; - VkPipelineCacheCreateFlags flags; - size_t initialDataSize; - const void * pInitialData; -} VkPipelineCacheCreateInfo; + VkImageViewCreateFlags flags; + VkImage image; + VkImageViewType viewType; + VkFormat format; + VkComponentMapping components; + VkImageSubresourceRange subresourceRange; +} VkImageViewCreateInfo; -typedef struct VkPushConstantRange { - VkShaderStageFlags stageFlags; - uint32_t offset; - uint32_t size; -} VkPushConstantRange; +typedef struct VkBufferCopy { + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy; -typedef struct VkPipelineLayoutCreateInfo { - VkStructureType sType; - const void * pNext; - VkPipelineLayoutCreateFlags flags; - uint32_t setLayoutCount; - const VkDescriptorSetLayout * pSetLayouts; - uint32_t pushConstantRangeCount; - const VkPushConstantRange * pPushConstantRanges; -} VkPipelineLayoutCreateInfo; +typedef struct VkSparseMemoryBind { + VkDeviceSize resourceOffset; + VkDeviceSize size; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseMemoryBind; -typedef struct VkSamplerCreateInfo { - VkStructureType sType; - const void * pNext; - VkSamplerCreateFlags flags; - VkFilter magFilter; - VkFilter minFilter; - VkSamplerMipmapMode mipmapMode; - VkSamplerAddressMode addressModeU; - VkSamplerAddressMode addressModeV; - VkSamplerAddressMode addressModeW; - float mipLodBias; - VkBool32 anisotropyEnable; - float maxAnisotropy; - VkBool32 compareEnable; - VkCompareOp compareOp; - float minLod; - float maxLod; - VkBorderColor borderColor; - VkBool32 unnormalizedCoordinates; -} VkSamplerCreateInfo; +typedef struct VkSparseImageMemoryBind { + VkImageSubresource subresource; + VkOffset3D offset; + VkExtent3D extent; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + VkSparseMemoryBindFlags flags; +} VkSparseImageMemoryBind; -typedef struct VkCommandPoolCreateInfo { - VkStructureType sType; - const void * pNext; - VkCommandPoolCreateFlags flags; - uint32_t queueFamilyIndex; -} VkCommandPoolCreateInfo; +typedef struct VkSparseBufferMemoryBindInfo { + VkBuffer buffer; + uint32_t bindCount; + const VkSparseMemoryBind * pBinds; +} VkSparseBufferMemoryBindInfo; -typedef struct VkCommandBufferInheritanceInfo { - VkStructureType sType; - const void * pNext; - VkRenderPass renderPass; - uint32_t subpass; - VkFramebuffer framebuffer; - VkBool32 occlusionQueryEnable; - VkQueryControlFlags queryFlags; - VkQueryPipelineStatisticFlags pipelineStatistics; -} VkCommandBufferInheritanceInfo; +typedef struct VkSparseImageOpaqueMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseMemoryBind * pBinds; +} VkSparseImageOpaqueMemoryBindInfo; -typedef struct VkCommandBufferBeginInfo { - VkStructureType sType; - const void * pNext; - VkCommandBufferUsageFlags flags; - const VkCommandBufferInheritanceInfo * pInheritanceInfo; -} VkCommandBufferBeginInfo; +typedef struct VkSparseImageMemoryBindInfo { + VkImage image; + uint32_t bindCount; + const VkSparseImageMemoryBind * pBinds; +} VkSparseImageMemoryBindInfo; -typedef struct VkRenderPassBeginInfo { +typedef struct VkBindSparseInfo { VkStructureType sType; const void * pNext; - VkRenderPass renderPass; - VkFramebuffer framebuffer; - VkRect2D renderArea; - uint32_t clearValueCount; - const VkClearValue * pClearValues; -} VkRenderPassBeginInfo; - -typedef struct VkClearAttachment { - VkImageAspectFlags aspectMask; - uint32_t colorAttachment; - VkClearValue clearValue; -} VkClearAttachment; + uint32_t waitSemaphoreCount; + const VkSemaphore * pWaitSemaphores; + uint32_t bufferBindCount; + const VkSparseBufferMemoryBindInfo * pBufferBinds; + uint32_t imageOpaqueBindCount; + const VkSparseImageOpaqueMemoryBindInfo * pImageOpaqueBinds; + uint32_t imageBindCount; + const VkSparseImageMemoryBindInfo * pImageBinds; + uint32_t signalSemaphoreCount; + const VkSemaphore * pSignalSemaphores; +} VkBindSparseInfo; -typedef struct VkAttachmentDescription { - VkAttachmentDescriptionFlags flags; - VkFormat format; - VkSampleCountFlagBits samples; - VkAttachmentLoadOp loadOp; +typedef struct VkImageCopy { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy; + +typedef struct VkImageBlit { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets [2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets [2]; +} VkImageBlit; + +typedef struct VkBufferImageCopy { + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy; + +typedef struct VkCopyMemoryIndirectCommandNV { + VkDeviceAddress srcAddress; + VkDeviceAddress dstAddress; + VkDeviceSize size; +} VkCopyMemoryIndirectCommandNV; + +typedef struct VkCopyMemoryToImageIndirectCommandNV { + VkDeviceAddress srcAddress; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkCopyMemoryToImageIndirectCommandNV; + +typedef struct VkImageResolve { + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve; + +typedef struct VkShaderModuleCreateInfo { + VkStructureType sType; + const void * pNext; + VkShaderModuleCreateFlags flags; + size_t codeSize; + const uint32_t * pCode; +} VkShaderModuleCreateInfo; + +typedef struct VkDescriptorSetLayoutBinding { + uint32_t binding; + VkDescriptorType descriptorType; + uint32_t descriptorCount; + VkShaderStageFlags stageFlags; + const VkSampler * pImmutableSamplers; +} VkDescriptorSetLayoutBinding; + +typedef struct VkDescriptorSetLayoutCreateInfo { + VkStructureType sType; + const void * pNext; + VkDescriptorSetLayoutCreateFlags flags; + uint32_t bindingCount; + const VkDescriptorSetLayoutBinding * pBindings; +} VkDescriptorSetLayoutCreateInfo; + +typedef struct VkDescriptorPoolCreateInfo { + VkStructureType sType; + const void * pNext; + VkDescriptorPoolCreateFlags flags; + uint32_t maxSets; + uint32_t poolSizeCount; + const VkDescriptorPoolSize * pPoolSizes; +} VkDescriptorPoolCreateInfo; + +typedef struct VkPipelineShaderStageCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineShaderStageCreateFlags flags; + VkShaderStageFlagBits stage; + VkShaderModule module; + const char * pName; + const VkSpecializationInfo * pSpecializationInfo; +} VkPipelineShaderStageCreateInfo; + +typedef struct VkComputePipelineCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineCreateFlags flags; + VkPipelineShaderStageCreateInfo stage; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkComputePipelineCreateInfo; + +typedef struct VkComputePipelineIndirectBufferInfoNV { + VkStructureType sType; + const void * pNext; + VkDeviceAddress deviceAddress; + VkDeviceSize size; + VkDeviceAddress pipelineDeviceAddressCaptureReplay; +} VkComputePipelineIndirectBufferInfoNV; + +typedef struct VkPipelineCreateFlags2CreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineCreateFlags2 flags; +} VkPipelineCreateFlags2CreateInfo; + +typedef struct VkPipelineCreateFlags2CreateInfo VkPipelineCreateFlags2CreateInfoKHR; + +typedef struct VkPipelineVertexInputStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineVertexInputStateCreateFlags flags; + uint32_t vertexBindingDescriptionCount; + const VkVertexInputBindingDescription * pVertexBindingDescriptions; + uint32_t vertexAttributeDescriptionCount; + const VkVertexInputAttributeDescription * pVertexAttributeDescriptions; +} VkPipelineVertexInputStateCreateInfo; + +typedef struct VkPipelineInputAssemblyStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineInputAssemblyStateCreateFlags flags; + VkPrimitiveTopology topology; + VkBool32 primitiveRestartEnable; +} VkPipelineInputAssemblyStateCreateInfo; + +typedef struct VkPipelineTessellationStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineTessellationStateCreateFlags flags; + uint32_t patchControlPoints; +} VkPipelineTessellationStateCreateInfo; + +typedef struct VkPipelineViewportStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineViewportStateCreateFlags flags; + uint32_t viewportCount; + const VkViewport * pViewports; + uint32_t scissorCount; + const VkRect2D * pScissors; +} VkPipelineViewportStateCreateInfo; + +typedef struct VkPipelineRasterizationStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineRasterizationStateCreateFlags flags; + VkBool32 depthClampEnable; + VkBool32 rasterizerDiscardEnable; + VkPolygonMode polygonMode; + VkCullModeFlags cullMode; + VkFrontFace frontFace; + VkBool32 depthBiasEnable; + float depthBiasConstantFactor; + float depthBiasClamp; + float depthBiasSlopeFactor; + float lineWidth; +} VkPipelineRasterizationStateCreateInfo; + +typedef struct VkPipelineMultisampleStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineMultisampleStateCreateFlags flags; + VkSampleCountFlagBits rasterizationSamples; + VkBool32 sampleShadingEnable; + float minSampleShading; + const VkSampleMask * pSampleMask; + VkBool32 alphaToCoverageEnable; + VkBool32 alphaToOneEnable; +} VkPipelineMultisampleStateCreateInfo; + +typedef struct VkPipelineColorBlendAttachmentState { + VkBool32 blendEnable; + VkBlendFactor srcColorBlendFactor; + VkBlendFactor dstColorBlendFactor; + VkBlendOp colorBlendOp; + VkBlendFactor srcAlphaBlendFactor; + VkBlendFactor dstAlphaBlendFactor; + VkBlendOp alphaBlendOp; + VkColorComponentFlags colorWriteMask; +} VkPipelineColorBlendAttachmentState; + +typedef struct VkPipelineColorBlendStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineColorBlendStateCreateFlags flags; + VkBool32 logicOpEnable; + VkLogicOp logicOp; + uint32_t attachmentCount; + const VkPipelineColorBlendAttachmentState * pAttachments; + float blendConstants [4]; +} VkPipelineColorBlendStateCreateInfo; + +typedef struct VkPipelineDynamicStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineDynamicStateCreateFlags flags; + uint32_t dynamicStateCount; + const VkDynamicState * pDynamicStates; +} VkPipelineDynamicStateCreateInfo; + +typedef struct VkPipelineDepthStencilStateCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineDepthStencilStateCreateFlags flags; + VkBool32 depthTestEnable; + VkBool32 depthWriteEnable; + VkCompareOp depthCompareOp; + VkBool32 depthBoundsTestEnable; + VkBool32 stencilTestEnable; + VkStencilOpState front; + VkStencilOpState back; + float minDepthBounds; + float maxDepthBounds; +} VkPipelineDepthStencilStateCreateInfo; + +typedef struct VkGraphicsPipelineCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo * pStages; + const VkPipelineVertexInputStateCreateInfo * pVertexInputState; + const VkPipelineInputAssemblyStateCreateInfo * pInputAssemblyState; + const VkPipelineTessellationStateCreateInfo * pTessellationState; + const VkPipelineViewportStateCreateInfo * pViewportState; + const VkPipelineRasterizationStateCreateInfo * pRasterizationState; + const VkPipelineMultisampleStateCreateInfo * pMultisampleState; + const VkPipelineDepthStencilStateCreateInfo * pDepthStencilState; + const VkPipelineColorBlendStateCreateInfo * pColorBlendState; + const VkPipelineDynamicStateCreateInfo * pDynamicState; + VkPipelineLayout layout; + VkRenderPass renderPass; + uint32_t subpass; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkGraphicsPipelineCreateInfo; + +typedef struct VkPipelineCacheCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineCacheCreateFlags flags; + size_t initialDataSize; + const void * pInitialData; +} VkPipelineCacheCreateInfo; + +typedef struct VkPushConstantRange { + VkShaderStageFlags stageFlags; + uint32_t offset; + uint32_t size; +} VkPushConstantRange; + +typedef struct VkPipelineBinaryKeysAndDataKHR { + uint32_t binaryCount; + const VkPipelineBinaryKeyKHR * pPipelineBinaryKeys; + const VkPipelineBinaryDataKHR * pPipelineBinaryData; +} VkPipelineBinaryKeysAndDataKHR; + +typedef struct VkPipelineLayoutCreateInfo { + VkStructureType sType; + const void * pNext; + VkPipelineLayoutCreateFlags flags; + uint32_t setLayoutCount; + const VkDescriptorSetLayout * pSetLayouts; + uint32_t pushConstantRangeCount; + const VkPushConstantRange * pPushConstantRanges; +} VkPipelineLayoutCreateInfo; + +typedef struct VkSamplerCreateInfo { + VkStructureType sType; + const void * pNext; + VkSamplerCreateFlags flags; + VkFilter magFilter; + VkFilter minFilter; + VkSamplerMipmapMode mipmapMode; + VkSamplerAddressMode addressModeU; + VkSamplerAddressMode addressModeV; + VkSamplerAddressMode addressModeW; + float mipLodBias; + VkBool32 anisotropyEnable; + float maxAnisotropy; + VkBool32 compareEnable; + VkCompareOp compareOp; + float minLod; + float maxLod; + VkBorderColor borderColor; + VkBool32 unnormalizedCoordinates; +} VkSamplerCreateInfo; + +typedef struct VkCommandPoolCreateInfo { + VkStructureType sType; + const void * pNext; + VkCommandPoolCreateFlags flags; + uint32_t queueFamilyIndex; +} VkCommandPoolCreateInfo; + +typedef struct VkCommandBufferInheritanceInfo { + VkStructureType sType; + const void * pNext; + VkRenderPass renderPass; + uint32_t subpass; + VkFramebuffer framebuffer; + VkBool32 occlusionQueryEnable; + VkQueryControlFlags queryFlags; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkCommandBufferInheritanceInfo; + +typedef struct VkCommandBufferBeginInfo { + VkStructureType sType; + const void * pNext; + VkCommandBufferUsageFlags flags; + const VkCommandBufferInheritanceInfo * pInheritanceInfo; +} VkCommandBufferBeginInfo; + +typedef struct VkRenderPassBeginInfo { + VkStructureType sType; + const void * pNext; + VkRenderPass renderPass; + VkFramebuffer framebuffer; + VkRect2D renderArea; + uint32_t clearValueCount; + const VkClearValue * pClearValues; +} VkRenderPassBeginInfo; + +typedef struct VkClearAttachment { + VkImageAspectFlags aspectMask; + uint32_t colorAttachment; + VkClearValue clearValue; +} VkClearAttachment; + +typedef struct VkAttachmentDescription { + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; VkAttachmentStoreOp storeOp; VkAttachmentLoadOp stencilLoadOp; VkAttachmentStoreOp stencilStoreOp; @@ -6114,2670 +10018,5789 @@ typedef struct VkAttachmentDescription { VkImageLayout finalLayout; } VkAttachmentDescription; -typedef struct VkSubpassDescription { - VkSubpassDescriptionFlags flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t inputAttachmentCount; - const VkAttachmentReference * pInputAttachments; - uint32_t colorAttachmentCount; - const VkAttachmentReference * pColorAttachments; - const VkAttachmentReference * pResolveAttachments; - const VkAttachmentReference * pDepthStencilAttachment; - uint32_t preserveAttachmentCount; - const uint32_t * pPreserveAttachments; -} VkSubpassDescription; +typedef struct VkSubpassDescription { + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t inputAttachmentCount; + const VkAttachmentReference * pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference * pColorAttachments; + const VkAttachmentReference * pResolveAttachments; + const VkAttachmentReference * pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t * pPreserveAttachments; +} VkSubpassDescription; + +typedef struct VkSubpassDependency { + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; +} VkSubpassDependency; + +typedef struct VkRenderPassCreateInfo { + VkStructureType sType; + const void * pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription * pAttachments; + uint32_t subpassCount; + const VkSubpassDescription * pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency * pDependencies; +} VkRenderPassCreateInfo; + +typedef struct VkEventCreateInfo { + VkStructureType sType; + const void * pNext; + VkEventCreateFlags flags; +} VkEventCreateInfo; + +typedef struct VkFenceCreateInfo { + VkStructureType sType; + const void * pNext; + VkFenceCreateFlags flags; +} VkFenceCreateInfo; + +typedef struct VkPhysicalDeviceFeatures { + VkBool32 robustBufferAccess; + VkBool32 fullDrawIndexUint32; + VkBool32 imageCubeArray; + VkBool32 independentBlend; + VkBool32 geometryShader; + VkBool32 tessellationShader; + VkBool32 sampleRateShading; + VkBool32 dualSrcBlend; + VkBool32 logicOp; + VkBool32 multiDrawIndirect; + VkBool32 drawIndirectFirstInstance; + VkBool32 depthClamp; + VkBool32 depthBiasClamp; + VkBool32 fillModeNonSolid; + VkBool32 depthBounds; + VkBool32 wideLines; + VkBool32 largePoints; + VkBool32 alphaToOne; + VkBool32 multiViewport; + VkBool32 samplerAnisotropy; + VkBool32 textureCompressionETC2; + VkBool32 textureCompressionASTC_LDR; + VkBool32 textureCompressionBC; + VkBool32 occlusionQueryPrecise; + VkBool32 pipelineStatisticsQuery; + VkBool32 vertexPipelineStoresAndAtomics; + VkBool32 fragmentStoresAndAtomics; + VkBool32 shaderTessellationAndGeometryPointSize; + VkBool32 shaderImageGatherExtended; + VkBool32 shaderStorageImageExtendedFormats; + VkBool32 shaderStorageImageMultisample; + VkBool32 shaderStorageImageReadWithoutFormat; + VkBool32 shaderStorageImageWriteWithoutFormat; + VkBool32 shaderUniformBufferArrayDynamicIndexing; + VkBool32 shaderSampledImageArrayDynamicIndexing; + VkBool32 shaderStorageBufferArrayDynamicIndexing; + VkBool32 shaderStorageImageArrayDynamicIndexing; + VkBool32 shaderClipDistance; + VkBool32 shaderCullDistance; + VkBool32 shaderFloat64; + VkBool32 shaderInt64; + VkBool32 shaderInt16; + VkBool32 shaderResourceResidency; + VkBool32 shaderResourceMinLod; + VkBool32 sparseBinding; + VkBool32 sparseResidencyBuffer; + VkBool32 sparseResidencyImage2D; + VkBool32 sparseResidencyImage3D; + VkBool32 sparseResidency2Samples; + VkBool32 sparseResidency4Samples; + VkBool32 sparseResidency8Samples; + VkBool32 sparseResidency16Samples; + VkBool32 sparseResidencyAliased; + VkBool32 variableMultisampleRate; + VkBool32 inheritedQueries; +} VkPhysicalDeviceFeatures; + +typedef struct VkPhysicalDeviceSparseProperties { + VkBool32 residencyStandard2DBlockShape; + VkBool32 residencyStandard2DMultisampleBlockShape; + VkBool32 residencyStandard3DBlockShape; + VkBool32 residencyAlignedMipSize; + VkBool32 residencyNonResidentStrict; +} VkPhysicalDeviceSparseProperties; + +typedef struct VkPhysicalDeviceLimits { + uint32_t maxImageDimension1D; + uint32_t maxImageDimension2D; + uint32_t maxImageDimension3D; + uint32_t maxImageDimensionCube; + uint32_t maxImageArrayLayers; + uint32_t maxTexelBufferElements; + uint32_t maxUniformBufferRange; + uint32_t maxStorageBufferRange; + uint32_t maxPushConstantsSize; + uint32_t maxMemoryAllocationCount; + uint32_t maxSamplerAllocationCount; + VkDeviceSize bufferImageGranularity; + VkDeviceSize sparseAddressSpaceSize; + uint32_t maxBoundDescriptorSets; + uint32_t maxPerStageDescriptorSamplers; + uint32_t maxPerStageDescriptorUniformBuffers; + uint32_t maxPerStageDescriptorStorageBuffers; + uint32_t maxPerStageDescriptorSampledImages; + uint32_t maxPerStageDescriptorStorageImages; + uint32_t maxPerStageDescriptorInputAttachments; + uint32_t maxPerStageResources; + uint32_t maxDescriptorSetSamplers; + uint32_t maxDescriptorSetUniformBuffers; + uint32_t maxDescriptorSetUniformBuffersDynamic; + uint32_t maxDescriptorSetStorageBuffers; + uint32_t maxDescriptorSetStorageBuffersDynamic; + uint32_t maxDescriptorSetSampledImages; + uint32_t maxDescriptorSetStorageImages; + uint32_t maxDescriptorSetInputAttachments; + uint32_t maxVertexInputAttributes; + uint32_t maxVertexInputBindings; + uint32_t maxVertexInputAttributeOffset; + uint32_t maxVertexInputBindingStride; + uint32_t maxVertexOutputComponents; + uint32_t maxTessellationGenerationLevel; + uint32_t maxTessellationPatchSize; + uint32_t maxTessellationControlPerVertexInputComponents; + uint32_t maxTessellationControlPerVertexOutputComponents; + uint32_t maxTessellationControlPerPatchOutputComponents; + uint32_t maxTessellationControlTotalOutputComponents; + uint32_t maxTessellationEvaluationInputComponents; + uint32_t maxTessellationEvaluationOutputComponents; + uint32_t maxGeometryShaderInvocations; + uint32_t maxGeometryInputComponents; + uint32_t maxGeometryOutputComponents; + uint32_t maxGeometryOutputVertices; + uint32_t maxGeometryTotalOutputComponents; + uint32_t maxFragmentInputComponents; + uint32_t maxFragmentOutputAttachments; + uint32_t maxFragmentDualSrcAttachments; + uint32_t maxFragmentCombinedOutputResources; + uint32_t maxComputeSharedMemorySize; + uint32_t maxComputeWorkGroupCount [3]; + uint32_t maxComputeWorkGroupInvocations; + uint32_t maxComputeWorkGroupSize [3]; + uint32_t subPixelPrecisionBits; + uint32_t subTexelPrecisionBits; + uint32_t mipmapPrecisionBits; + uint32_t maxDrawIndexedIndexValue; + uint32_t maxDrawIndirectCount; + float maxSamplerLodBias; + float maxSamplerAnisotropy; + uint32_t maxViewports; + uint32_t maxViewportDimensions [2]; + float viewportBoundsRange [2]; + uint32_t viewportSubPixelBits; + size_t minMemoryMapAlignment; + VkDeviceSize minTexelBufferOffsetAlignment; + VkDeviceSize minUniformBufferOffsetAlignment; + VkDeviceSize minStorageBufferOffsetAlignment; + int32_t minTexelOffset; + uint32_t maxTexelOffset; + int32_t minTexelGatherOffset; + uint32_t maxTexelGatherOffset; + float minInterpolationOffset; + float maxInterpolationOffset; + uint32_t subPixelInterpolationOffsetBits; + uint32_t maxFramebufferWidth; + uint32_t maxFramebufferHeight; + uint32_t maxFramebufferLayers; + VkSampleCountFlags framebufferColorSampleCounts; + VkSampleCountFlags framebufferDepthSampleCounts; + VkSampleCountFlags framebufferStencilSampleCounts; + VkSampleCountFlags framebufferNoAttachmentsSampleCounts; + uint32_t maxColorAttachments; + VkSampleCountFlags sampledImageColorSampleCounts; + VkSampleCountFlags sampledImageIntegerSampleCounts; + VkSampleCountFlags sampledImageDepthSampleCounts; + VkSampleCountFlags sampledImageStencilSampleCounts; + VkSampleCountFlags storageImageSampleCounts; + uint32_t maxSampleMaskWords; + VkBool32 timestampComputeAndGraphics; + float timestampPeriod; + uint32_t maxClipDistances; + uint32_t maxCullDistances; + uint32_t maxCombinedClipAndCullDistances; + uint32_t discreteQueuePriorities; + float pointSizeRange [2]; + float lineWidthRange [2]; + float pointSizeGranularity; + float lineWidthGranularity; + VkBool32 strictLines; + VkBool32 standardSampleLocations; + VkDeviceSize optimalBufferCopyOffsetAlignment; + VkDeviceSize optimalBufferCopyRowPitchAlignment; + VkDeviceSize nonCoherentAtomSize; +} VkPhysicalDeviceLimits; + +typedef struct VkSemaphoreCreateInfo { + VkStructureType sType; + const void * pNext; + VkSemaphoreCreateFlags flags; +} VkSemaphoreCreateInfo; + +typedef struct VkQueryPoolCreateInfo { + VkStructureType sType; + const void * pNext; + VkQueryPoolCreateFlags flags; + VkQueryType queryType; + uint32_t queryCount; + VkQueryPipelineStatisticFlags pipelineStatistics; +} VkQueryPoolCreateInfo; + +typedef struct VkFramebufferCreateInfo { + VkStructureType sType; + const void * pNext; + VkFramebufferCreateFlags flags; + VkRenderPass renderPass; + uint32_t attachmentCount; + const VkImageView * pAttachments; + uint32_t width; + uint32_t height; + uint32_t layers; +} VkFramebufferCreateInfo; + +typedef struct VkSubmitInfo { + VkStructureType sType; + const void * pNext; + uint32_t waitSemaphoreCount; + const VkSemaphore * pWaitSemaphores; + const VkPipelineStageFlags * pWaitDstStageMask; + uint32_t commandBufferCount; + const VkCommandBuffer * pCommandBuffers; + uint32_t signalSemaphoreCount; + const VkSemaphore * pSignalSemaphores; +} VkSubmitInfo; + +typedef struct VkDisplayPropertiesKHR { + VkDisplayKHR display; + const char * displayName; + VkExtent2D physicalDimensions; + VkExtent2D physicalResolution; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkBool32 planeReorderPossible; + VkBool32 persistentContent; +} VkDisplayPropertiesKHR; + +typedef struct VkDisplayModeCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkDisplayModeCreateFlagsKHR flags; + VkDisplayModeParametersKHR parameters; +} VkDisplayModeCreateInfoKHR; + +typedef struct VkDisplayPlaneCapabilitiesKHR { + VkDisplayPlaneAlphaFlagsKHR supportedAlpha; + VkOffset2D minSrcPosition; + VkOffset2D maxSrcPosition; + VkExtent2D minSrcExtent; + VkExtent2D maxSrcExtent; + VkOffset2D minDstPosition; + VkOffset2D maxDstPosition; + VkExtent2D minDstExtent; + VkExtent2D maxDstExtent; +} VkDisplayPlaneCapabilitiesKHR; + +typedef struct VkDisplaySurfaceCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkDisplaySurfaceCreateFlagsKHR flags; + VkDisplayModeKHR displayMode; + uint32_t planeIndex; + uint32_t planeStackIndex; + VkSurfaceTransformFlagBitsKHR transform; + float globalAlpha; + VkDisplayPlaneAlphaFlagBitsKHR alphaMode; + VkExtent2D imageExtent; +} VkDisplaySurfaceCreateInfoKHR; + +typedef struct VkDisplayPresentInfoKHR { + VkStructureType sType; + const void * pNext; + VkRect2D srcRect; + VkRect2D dstRect; + VkBool32 persistent; +} VkDisplayPresentInfoKHR; + +typedef struct VkSurfaceCapabilitiesKHR { + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; +} VkSurfaceCapabilitiesKHR; + +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef struct VkAndroidSurfaceCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkAndroidSurfaceCreateFlagsKHR flags; + struct ANativeWindow * window; +} VkAndroidSurfaceCreateInfoKHR; + +#endif + +#if defined(VK_USE_PLATFORM_VI_NN) +typedef struct VkViSurfaceCreateInfoNN { + VkStructureType sType; + const void * pNext; + VkViSurfaceCreateFlagsNN flags; + void * window; +} VkViSurfaceCreateInfoNN; + +#endif + +#if defined(VK_USE_PLATFORM_WAYLAND_KHR) +typedef struct VkWaylandSurfaceCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + struct wl_display * display; + struct wl_surface * surface; +} VkWaylandSurfaceCreateInfoKHR; + +#endif + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkWin32SurfaceCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkWin32SurfaceCreateFlagsKHR flags; + HINSTANCE hinstance; + HWND hwnd; +} VkWin32SurfaceCreateInfoKHR; + +#endif + +#if defined(VK_USE_PLATFORM_XLIB_KHR) +typedef struct VkXlibSurfaceCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display * dpy; + Window window; +} VkXlibSurfaceCreateInfoKHR; + +#endif + +#if defined(VK_USE_PLATFORM_XCB_KHR) +typedef struct VkXcbSurfaceCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t * connection; + xcb_window_t window; +} VkXcbSurfaceCreateInfoKHR; + +#endif + +#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) +typedef struct VkDirectFBSurfaceCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkDirectFBSurfaceCreateFlagsEXT flags; + IDirectFB * dfb; + IDirectFBSurface * surface; +} VkDirectFBSurfaceCreateInfoEXT; + +#endif + +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkImagePipeSurfaceCreateInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkImagePipeSurfaceCreateFlagsFUCHSIA flags; + zx_handle_t imagePipeHandle; +} VkImagePipeSurfaceCreateInfoFUCHSIA; + +#endif + +#if defined(VK_USE_PLATFORM_GGP) +typedef struct VkStreamDescriptorSurfaceCreateInfoGGP { + VkStructureType sType; + const void * pNext; + VkStreamDescriptorSurfaceCreateFlagsGGP flags; + GgpStreamDescriptor streamDescriptor; +} VkStreamDescriptorSurfaceCreateInfoGGP; + +#endif + +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef struct VkScreenSurfaceCreateInfoQNX { + VkStructureType sType; + const void * pNext; + VkScreenSurfaceCreateFlagsQNX flags; + struct _screen_context * context; + struct _screen_window * window; +} VkScreenSurfaceCreateInfoQNX; + +#endif + +typedef struct VkSwapchainCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkSwapchainCreateFlagsKHR flags; + VkSurfaceKHR surface; + uint32_t minImageCount; + VkFormat imageFormat; + VkColorSpaceKHR imageColorSpace; + VkExtent2D imageExtent; + uint32_t imageArrayLayers; + VkImageUsageFlags imageUsage; + VkSharingMode imageSharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t * pQueueFamilyIndices; + VkSurfaceTransformFlagBitsKHR preTransform; + VkCompositeAlphaFlagBitsKHR compositeAlpha; + VkPresentModeKHR presentMode; + VkBool32 clipped; + VkSwapchainKHR oldSwapchain; +} VkSwapchainCreateInfoKHR; + +typedef struct VkDebugReportCallbackCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkDebugReportFlagsEXT flags; + PFN_vkDebugReportCallbackEXT pfnCallback; + void * pUserData; +} VkDebugReportCallbackCreateInfoEXT; + +typedef struct VkLayerSettingsCreateInfoEXT { + VkStructureType sType; + const void * pNext; + uint32_t settingCount; + const VkLayerSettingEXT * pSettings; +} VkLayerSettingsCreateInfoEXT; + +typedef struct VkDedicatedAllocationImageCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkBool32 dedicatedAllocation; +} VkDedicatedAllocationImageCreateInfoNV; + +typedef struct VkDedicatedAllocationBufferCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkBool32 dedicatedAllocation; +} VkDedicatedAllocationBufferCreateInfoNV; + +typedef struct VkExternalImageFormatPropertiesNV { + VkImageFormatProperties imageFormatProperties; + VkExternalMemoryFeatureFlagsNV externalMemoryFeatures; + VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes; + VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes; +} VkExternalImageFormatPropertiesNV; + +typedef struct VkExternalMemoryImageCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlagsNV handleTypes; +} VkExternalMemoryImageCreateInfoNV; + +typedef struct VkExportMemoryAllocateInfoNV { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlagsNV handleTypes; +} VkExportMemoryAllocateInfoNV; + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkImportMemoryWin32HandleInfoNV { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlagsNV handleType; + HANDLE handle; +} VkImportMemoryWin32HandleInfoNV; + +#endif + +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 deviceGeneratedCommands; +} VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV; + +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsComputeFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 deviceGeneratedCompute; + VkBool32 deviceGeneratedComputePipelines; + VkBool32 deviceGeneratedComputeCaptureReplay; +} VkPhysicalDeviceDeviceGeneratedCommandsComputeFeaturesNV; + +typedef struct VkPrivateDataSlotCreateInfo { + VkStructureType sType; + const void * pNext; + VkPrivateDataSlotCreateFlags flags; +} VkPrivateDataSlotCreateInfo; + +typedef struct VkPrivateDataSlotCreateInfo VkPrivateDataSlotCreateInfoEXT; + +typedef struct VkPhysicalDevicePrivateDataFeatures { + VkStructureType sType; + void * pNext; + VkBool32 privateData; +} VkPhysicalDevicePrivateDataFeatures; + +typedef struct VkPhysicalDevicePrivateDataFeatures VkPhysicalDevicePrivateDataFeaturesEXT; + +typedef struct VkPhysicalDeviceClusterAccelerationStructureFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 clusterAccelerationStructure; +} VkPhysicalDeviceClusterAccelerationStructureFeaturesNV; + +typedef struct VkStridedDeviceAddressNV { + VkDeviceAddress startAddress; + VkDeviceSize strideInBytes; +} VkStridedDeviceAddressNV; + +typedef struct VkRayTracingPipelineClusterAccelerationStructureCreateInfoNV { + VkStructureType sType; + void * pNext; + VkBool32 allowClusterAccelerationStructure; +} VkRayTracingPipelineClusterAccelerationStructureCreateInfoNV; + +typedef struct VkClusterAccelerationStructureMoveObjectsInfoNV { + VkDeviceAddress srcAccelerationStructure; +} VkClusterAccelerationStructureMoveObjectsInfoNV; + +typedef struct VkClusterAccelerationStructureBuildClustersBottomLevelInfoNV { + uint32_t clusterReferencesCount; + uint32_t clusterReferencesStride; + VkDeviceAddress clusterReferences; +} VkClusterAccelerationStructureBuildClustersBottomLevelInfoNV; + +typedef struct VkClusterAccelerationStructureBuildTriangleClusterInfoNV { + uint32_t clusterID; + VkClusterAccelerationStructureClusterFlagsNV clusterFlags; + uint32_t triangleCount :9; + uint32_t vertexCount :9; + uint32_t positionTruncateBitCount :6; + uint32_t indexType :4; + uint32_t opacityMicromapIndexType :4; + VkClusterAccelerationStructureGeometryIndexAndGeometryFlagsNV baseGeometryIndexAndGeometryFlags; + uint16_t indexBufferStride; + uint16_t vertexBufferStride; + uint16_t geometryIndexAndFlagsBufferStride; + uint16_t opacityMicromapIndexBufferStride; + VkDeviceAddress indexBuffer; + VkDeviceAddress vertexBuffer; + VkDeviceAddress geometryIndexAndFlagsBuffer; + VkDeviceAddress opacityMicromapArray; + VkDeviceAddress opacityMicromapIndexBuffer; +} VkClusterAccelerationStructureBuildTriangleClusterInfoNV; + +typedef struct VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV { + uint32_t clusterID; + VkClusterAccelerationStructureClusterFlagsNV clusterFlags; + uint32_t triangleCount :9; + uint32_t vertexCount :9; + uint32_t positionTruncateBitCount :6; + uint32_t indexType :4; + uint32_t opacityMicromapIndexType :4; + VkClusterAccelerationStructureGeometryIndexAndGeometryFlagsNV baseGeometryIndexAndGeometryFlags; + uint16_t indexBufferStride; + uint16_t vertexBufferStride; + uint16_t geometryIndexAndFlagsBufferStride; + uint16_t opacityMicromapIndexBufferStride; + VkDeviceAddress indexBuffer; + VkDeviceAddress vertexBuffer; + VkDeviceAddress geometryIndexAndFlagsBuffer; + VkDeviceAddress opacityMicromapArray; + VkDeviceAddress opacityMicromapIndexBuffer; + VkDeviceAddress instantiationBoundingBoxLimit; +} VkClusterAccelerationStructureBuildTriangleClusterTemplateInfoNV; + +typedef struct VkClusterAccelerationStructureInstantiateClusterInfoNV { + uint32_t clusterIdOffset; + uint32_t geometryIndexOffset :24; + uint32_t reserved :8; + VkDeviceAddress clusterTemplateAddress; + VkStridedDeviceAddressNV vertexBuffer; +} VkClusterAccelerationStructureInstantiateClusterInfoNV; + +typedef struct VkClusterAccelerationStructureMoveObjectsInputNV { + VkStructureType sType; + void * pNext; + VkClusterAccelerationStructureTypeNV type; + VkBool32 noMoveOverlap; + VkDeviceSize maxMovedBytes; +} VkClusterAccelerationStructureMoveObjectsInputNV; + +typedef union VkClusterAccelerationStructureOpInputNV { + VkClusterAccelerationStructureClustersBottomLevelInputNV * pClustersBottomLevel; + VkClusterAccelerationStructureTriangleClusterInputNV * pTriangleClusters; + VkClusterAccelerationStructureMoveObjectsInputNV * pMoveObjects; +} VkClusterAccelerationStructureOpInputNV; + +typedef struct VkClusterAccelerationStructureInputInfoNV { + VkStructureType sType; + void * pNext; + uint32_t maxAccelerationStructureCount; + VkBuildAccelerationStructureFlagsKHR flags; + VkClusterAccelerationStructureOpTypeNV opType; + VkClusterAccelerationStructureOpModeNV opMode; + VkClusterAccelerationStructureOpInputNV opInput; +} VkClusterAccelerationStructureInputInfoNV; + +typedef struct VkGraphicsShaderGroupCreateInfoNV { + VkStructureType sType; + const void * pNext; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo * pStages; + const VkPipelineVertexInputStateCreateInfo * pVertexInputState; + const VkPipelineTessellationStateCreateInfo * pTessellationState; +} VkGraphicsShaderGroupCreateInfoNV; + +typedef struct VkGraphicsPipelineShaderGroupsCreateInfoNV { + VkStructureType sType; + const void * pNext; + uint32_t groupCount; + const VkGraphicsShaderGroupCreateInfoNV * pGroups; + uint32_t pipelineCount; + const VkPipeline * pPipelines; +} VkGraphicsPipelineShaderGroupsCreateInfoNV; + +typedef struct VkBindIndexBufferIndirectCommandNV { + VkDeviceAddress bufferAddress; + uint32_t size; + VkIndexType indexType; +} VkBindIndexBufferIndirectCommandNV; + +typedef struct VkBindVertexBufferIndirectCommandNV { + VkDeviceAddress bufferAddress; + uint32_t size; + uint32_t stride; +} VkBindVertexBufferIndirectCommandNV; + +typedef struct VkIndirectCommandsStreamNV { + VkBuffer buffer; + VkDeviceSize offset; +} VkIndirectCommandsStreamNV; + +typedef struct VkIndirectCommandsLayoutTokenNV { + VkStructureType sType; + const void * pNext; + VkIndirectCommandsTokenTypeNV tokenType; + uint32_t stream; + uint32_t offset; + uint32_t vertexBindingUnit; + VkBool32 vertexDynamicStride; + VkPipelineLayout pushconstantPipelineLayout; + VkShaderStageFlags pushconstantShaderStageFlags; + uint32_t pushconstantOffset; + uint32_t pushconstantSize; + VkIndirectStateFlagsNV indirectStateFlags; + uint32_t indexTypeCount; + const VkIndexType * pIndexTypes; + const uint32_t * pIndexTypeValues; +} VkIndirectCommandsLayoutTokenNV; + +typedef struct VkIndirectCommandsLayoutCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkIndirectCommandsLayoutUsageFlagsNV flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t tokenCount; + const VkIndirectCommandsLayoutTokenNV * pTokens; + uint32_t streamCount; + const uint32_t * pStreamStrides; +} VkIndirectCommandsLayoutCreateInfoNV; + +typedef struct VkGeneratedCommandsInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineBindPoint pipelineBindPoint; + VkPipeline pipeline; + VkIndirectCommandsLayoutNV indirectCommandsLayout; + uint32_t streamCount; + const VkIndirectCommandsStreamNV * pStreams; + uint32_t sequencesCount; + VkBuffer preprocessBuffer; + VkDeviceSize preprocessOffset; + VkDeviceSize preprocessSize; + VkBuffer sequencesCountBuffer; + VkDeviceSize sequencesCountOffset; + VkBuffer sequencesIndexBuffer; + VkDeviceSize sequencesIndexOffset; +} VkGeneratedCommandsInfoNV; + +typedef struct VkBindPipelineIndirectCommandNV { + VkDeviceAddress pipelineAddress; +} VkBindPipelineIndirectCommandNV; + +typedef struct VkPhysicalDeviceFeatures2 { + VkStructureType sType; + void * pNext; + VkPhysicalDeviceFeatures features; +} VkPhysicalDeviceFeatures2; + +typedef struct VkPhysicalDeviceFeatures2 VkPhysicalDeviceFeatures2KHR; + +typedef struct VkFormatProperties2 { + VkStructureType sType; + void * pNext; + VkFormatProperties formatProperties; +} VkFormatProperties2; + +typedef struct VkFormatProperties2 VkFormatProperties2KHR; + +typedef struct VkImageFormatProperties2 { + VkStructureType sType; + void * pNext; + VkImageFormatProperties imageFormatProperties; +} VkImageFormatProperties2; + +typedef struct VkImageFormatProperties2 VkImageFormatProperties2KHR; + +typedef struct VkPhysicalDeviceImageFormatInfo2 { + VkStructureType sType; + const void * pNext; + VkFormat format; + VkImageType type; + VkImageTiling tiling; + VkImageUsageFlags usage; + VkImageCreateFlags flags; +} VkPhysicalDeviceImageFormatInfo2; + +typedef struct VkPhysicalDeviceImageFormatInfo2 VkPhysicalDeviceImageFormatInfo2KHR; + +typedef struct VkQueueFamilyProperties2 { + VkStructureType sType; + void * pNext; + VkQueueFamilyProperties queueFamilyProperties; +} VkQueueFamilyProperties2; + +typedef struct VkQueueFamilyProperties2 VkQueueFamilyProperties2KHR; + +typedef struct VkSparseImageFormatProperties2 { + VkStructureType sType; + void * pNext; + VkSparseImageFormatProperties properties; +} VkSparseImageFormatProperties2; + +typedef struct VkSparseImageFormatProperties2 VkSparseImageFormatProperties2KHR; + +typedef struct VkPhysicalDeviceSparseImageFormatInfo2 { + VkStructureType sType; + const void * pNext; + VkFormat format; + VkImageType type; + VkSampleCountFlagBits samples; + VkImageUsageFlags usage; + VkImageTiling tiling; +} VkPhysicalDeviceSparseImageFormatInfo2; + +typedef struct VkPhysicalDeviceSparseImageFormatInfo2 VkPhysicalDeviceSparseImageFormatInfo2KHR; + +typedef struct VkPresentRegionKHR { + uint32_t rectangleCount; + const VkRectLayerKHR * pRectangles; +} VkPresentRegionKHR; + +typedef struct VkPhysicalDeviceVariablePointersFeatures { + VkStructureType sType; + void * pNext; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; +} VkPhysicalDeviceVariablePointersFeatures; + +typedef struct VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointersFeaturesKHR; + +typedef struct VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeaturesKHR; + +typedef struct VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeatures; + +typedef struct VkExternalMemoryProperties { + VkExternalMemoryFeatureFlags externalMemoryFeatures; + VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes; + VkExternalMemoryHandleTypeFlags compatibleHandleTypes; +} VkExternalMemoryProperties; + +typedef struct VkExternalMemoryProperties VkExternalMemoryPropertiesKHR; + +typedef struct VkExternalImageFormatProperties { + VkStructureType sType; + void * pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalImageFormatProperties; + +typedef struct VkExternalImageFormatProperties VkExternalImageFormatPropertiesKHR; + +typedef struct VkPhysicalDeviceExternalBufferInfo { + VkStructureType sType; + const void * pNext; + VkBufferCreateFlags flags; + VkBufferUsageFlags usage; + VkExternalMemoryHandleTypeFlagBits handleType; +} VkPhysicalDeviceExternalBufferInfo; + +typedef struct VkPhysicalDeviceExternalBufferInfo VkPhysicalDeviceExternalBufferInfoKHR; + +typedef struct VkExternalBufferProperties { + VkStructureType sType; + void * pNext; + VkExternalMemoryProperties externalMemoryProperties; +} VkExternalBufferProperties; + +typedef struct VkExternalBufferProperties VkExternalBufferPropertiesKHR; + +typedef struct VkPhysicalDeviceIDProperties { + VkStructureType sType; + void * pNext; + uint8_t deviceUUID [ VK_UUID_SIZE ]; + uint8_t driverUUID [ VK_UUID_SIZE ]; + uint8_t deviceLUID [ VK_LUID_SIZE ]; + uint32_t deviceNodeMask; + VkBool32 deviceLUIDValid; +} VkPhysicalDeviceIDProperties; + +typedef struct VkPhysicalDeviceIDProperties VkPhysicalDeviceIDPropertiesKHR; + +typedef struct VkExternalMemoryImageCreateInfo { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryImageCreateInfo; + +typedef struct VkExternalMemoryImageCreateInfo VkExternalMemoryImageCreateInfoKHR; + +typedef struct VkExternalMemoryBufferCreateInfo { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExternalMemoryBufferCreateInfo; + +typedef struct VkExternalMemoryBufferCreateInfo VkExternalMemoryBufferCreateInfoKHR; + +typedef struct VkExportMemoryAllocateInfo { + VkStructureType sType; + const void * pNext; + VkExternalMemoryHandleTypeFlags handleTypes; +} VkExportMemoryAllocateInfo; + +typedef struct VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR; + +typedef struct VkExternalSemaphoreProperties { + VkStructureType sType; + void * pNext; + VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes; + VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes; + VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures; +} VkExternalSemaphoreProperties; + +typedef struct VkExternalSemaphoreProperties VkExternalSemaphorePropertiesKHR; + +typedef struct VkExportSemaphoreCreateInfo { + VkStructureType sType; + const void * pNext; + VkExternalSemaphoreHandleTypeFlags handleTypes; +} VkExportSemaphoreCreateInfo; + +typedef struct VkExportSemaphoreCreateInfo VkExportSemaphoreCreateInfoKHR; + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkImportSemaphoreWin32HandleInfoKHR { + VkStructureType sType; + const void * pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + HANDLE handle; + LPCWSTR name; +} VkImportSemaphoreWin32HandleInfoKHR; + +#endif + +typedef struct VkImportSemaphoreFdInfoKHR { + VkStructureType sType; + const void * pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + int fd; +} VkImportSemaphoreFdInfoKHR; + +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkImportSemaphoreZirconHandleInfoFUCHSIA { + VkStructureType sType; + const void * pNext; + VkSemaphore semaphore; + VkSemaphoreImportFlags flags; + VkExternalSemaphoreHandleTypeFlagBits handleType; + zx_handle_t zirconHandle; +} VkImportSemaphoreZirconHandleInfoFUCHSIA; + +#endif + +typedef struct VkExternalFenceProperties { + VkStructureType sType; + void * pNext; + VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes; + VkExternalFenceHandleTypeFlags compatibleHandleTypes; + VkExternalFenceFeatureFlags externalFenceFeatures; +} VkExternalFenceProperties; + +typedef struct VkExternalFenceProperties VkExternalFencePropertiesKHR; + +typedef struct VkExportFenceCreateInfo { + VkStructureType sType; + const void * pNext; + VkExternalFenceHandleTypeFlags handleTypes; +} VkExportFenceCreateInfo; + +typedef struct VkExportFenceCreateInfo VkExportFenceCreateInfoKHR; + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkImportFenceWin32HandleInfoKHR { + VkStructureType sType; + const void * pNext; + VkFence fence; + VkFenceImportFlags flags; + VkExternalFenceHandleTypeFlagBits handleType; + HANDLE handle; + LPCWSTR name; +} VkImportFenceWin32HandleInfoKHR; + +#endif + +typedef struct VkImportFenceFdInfoKHR { + VkStructureType sType; + const void * pNext; + VkFence fence; + VkFenceImportFlags flags; + VkExternalFenceHandleTypeFlagBits handleType; + int fd; +} VkImportFenceFdInfoKHR; + +typedef struct VkPhysicalDeviceMultiviewFeatures { + VkStructureType sType; + void * pNext; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; +} VkPhysicalDeviceMultiviewFeatures; + +typedef struct VkPhysicalDeviceMultiviewFeatures VkPhysicalDeviceMultiviewFeaturesKHR; + +typedef struct VkSurfaceCapabilities2EXT { + VkStructureType sType; + void * pNext; + uint32_t minImageCount; + uint32_t maxImageCount; + VkExtent2D currentExtent; + VkExtent2D minImageExtent; + VkExtent2D maxImageExtent; + uint32_t maxImageArrayLayers; + VkSurfaceTransformFlagsKHR supportedTransforms; + VkSurfaceTransformFlagBitsKHR currentTransform; + VkCompositeAlphaFlagsKHR supportedCompositeAlpha; + VkImageUsageFlags supportedUsageFlags; + VkSurfaceCounterFlagsEXT supportedSurfaceCounters; +} VkSurfaceCapabilities2EXT; + +typedef struct VkSwapchainCounterCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkSurfaceCounterFlagsEXT surfaceCounters; +} VkSwapchainCounterCreateInfoEXT; + +typedef struct VkPhysicalDeviceGroupProperties { + VkStructureType sType; + void * pNext; + uint32_t physicalDeviceCount; + VkPhysicalDevice physicalDevices [ VK_MAX_DEVICE_GROUP_SIZE ]; + VkBool32 subsetAllocation; +} VkPhysicalDeviceGroupProperties; + +typedef struct VkPhysicalDeviceGroupProperties VkPhysicalDeviceGroupPropertiesKHR; + +typedef struct VkMemoryAllocateFlagsInfo { + VkStructureType sType; + const void * pNext; + VkMemoryAllocateFlags flags; + uint32_t deviceMask; +} VkMemoryAllocateFlagsInfo; + +typedef struct VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR; + +typedef struct VkBindBufferMemoryInfo { + VkStructureType sType; + const void * pNext; + VkBuffer buffer; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindBufferMemoryInfo; + +typedef struct VkBindBufferMemoryInfo VkBindBufferMemoryInfoKHR; + +typedef struct VkBindImageMemoryInfo { + VkStructureType sType; + const void * pNext; + VkImage image; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; +} VkBindImageMemoryInfo; + +typedef struct VkBindImageMemoryInfo VkBindImageMemoryInfoKHR; + +typedef struct VkDeviceGroupPresentCapabilitiesKHR { + VkStructureType sType; + void * pNext; + uint32_t presentMask [ VK_MAX_DEVICE_GROUP_SIZE ]; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupPresentCapabilitiesKHR; + +typedef struct VkDeviceGroupSwapchainCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkDeviceGroupPresentModeFlagsKHR modes; +} VkDeviceGroupSwapchainCreateInfoKHR; + +typedef struct VkDescriptorUpdateTemplateCreateInfo { + VkStructureType sType; + const void * pNext; + VkDescriptorUpdateTemplateCreateFlags flags; + uint32_t descriptorUpdateEntryCount; + const VkDescriptorUpdateTemplateEntry * pDescriptorUpdateEntries; + VkDescriptorUpdateTemplateType templateType; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineBindPoint pipelineBindPoint; + VkPipelineLayout pipelineLayout; + uint32_t set; +} VkDescriptorUpdateTemplateCreateInfo; + +typedef struct VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR; + +typedef struct VkPhysicalDevicePresentIdFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 presentId; +} VkPhysicalDevicePresentIdFeaturesKHR; + +typedef struct VkPhysicalDevicePresentWaitFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 presentWait; +} VkPhysicalDevicePresentWaitFeaturesKHR; + +typedef struct VkDisplayNativeHdrSurfaceCapabilitiesAMD { + VkStructureType sType; + void * pNext; + VkBool32 localDimmingSupport; +} VkDisplayNativeHdrSurfaceCapabilitiesAMD; + +typedef struct VkSwapchainDisplayNativeHdrCreateInfoAMD { + VkStructureType sType; + const void * pNext; + VkBool32 localDimmingEnable; +} VkSwapchainDisplayNativeHdrCreateInfoAMD; + +typedef struct VkPresentTimesInfoGOOGLE { + VkStructureType sType; + const void * pNext; + uint32_t swapchainCount; + const VkPresentTimeGOOGLE * pTimes; +} VkPresentTimesInfoGOOGLE; + +#if defined(VK_USE_PLATFORM_IOS_MVK) +typedef struct VkIOSSurfaceCreateInfoMVK { + VkStructureType sType; + const void * pNext; + VkIOSSurfaceCreateFlagsMVK flags; + const void * pView; +} VkIOSSurfaceCreateInfoMVK; + +#endif + +#if defined(VK_USE_PLATFORM_MACOS_MVK) +typedef struct VkMacOSSurfaceCreateInfoMVK { + VkStructureType sType; + const void * pNext; + VkMacOSSurfaceCreateFlagsMVK flags; + const void * pView; +} VkMacOSSurfaceCreateInfoMVK; + +#endif + +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef struct VkMetalSurfaceCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkMetalSurfaceCreateFlagsEXT flags; + const CAMetalLayer * pLayer; +} VkMetalSurfaceCreateInfoEXT; + +#endif + +typedef struct VkPipelineViewportWScalingStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkBool32 viewportWScalingEnable; + uint32_t viewportCount; + const VkViewportWScalingNV * pViewportWScalings; +} VkPipelineViewportWScalingStateCreateInfoNV; + +typedef struct VkPipelineViewportSwizzleStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineViewportSwizzleStateCreateFlagsNV flags; + uint32_t viewportCount; + const VkViewportSwizzleNV * pViewportSwizzles; +} VkPipelineViewportSwizzleStateCreateInfoNV; + +typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkPipelineDiscardRectangleStateCreateFlagsEXT flags; + VkDiscardRectangleModeEXT discardRectangleMode; + uint32_t discardRectangleCount; + const VkRect2D * pDiscardRectangles; +} VkPipelineDiscardRectangleStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX { + VkStructureType sType; + void * pNext; + VkBool32 perViewPositionAllComponents; +} VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX; + +typedef struct VkInputAttachmentAspectReference { + uint32_t subpass; + uint32_t inputAttachmentIndex; + VkImageAspectFlags aspectMask; +} VkInputAttachmentAspectReference; + +typedef struct VkInputAttachmentAspectReference VkInputAttachmentAspectReferenceKHR; + +typedef struct VkRenderPassInputAttachmentAspectCreateInfo { + VkStructureType sType; + const void * pNext; + uint32_t aspectReferenceCount; + const VkInputAttachmentAspectReference * pAspectReferences; +} VkRenderPassInputAttachmentAspectCreateInfo; + +typedef struct VkRenderPassInputAttachmentAspectCreateInfo VkRenderPassInputAttachmentAspectCreateInfoKHR; + +typedef struct VkSurfaceCapabilities2KHR { + VkStructureType sType; + void * pNext; + VkSurfaceCapabilitiesKHR surfaceCapabilities; +} VkSurfaceCapabilities2KHR; + +typedef struct VkDisplayProperties2KHR { + VkStructureType sType; + void * pNext; + VkDisplayPropertiesKHR displayProperties; +} VkDisplayProperties2KHR; + +typedef struct VkDisplayModeStereoPropertiesNV { + VkStructureType sType; + const void * pNext; + VkBool32 hdmi3DSupported; +} VkDisplayModeStereoPropertiesNV; + +typedef struct VkDisplayPlaneCapabilities2KHR { + VkStructureType sType; + void * pNext; + VkDisplayPlaneCapabilitiesKHR capabilities; +} VkDisplayPlaneCapabilities2KHR; + +typedef struct VkSharedPresentSurfaceCapabilitiesKHR { + VkStructureType sType; + void * pNext; + VkImageUsageFlags sharedPresentSupportedUsageFlags; +} VkSharedPresentSurfaceCapabilitiesKHR; + +typedef struct VkPhysicalDevice16BitStorageFeatures { + VkStructureType sType; + void * pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; +} VkPhysicalDevice16BitStorageFeatures; + +typedef struct VkPhysicalDevice16BitStorageFeatures VkPhysicalDevice16BitStorageFeaturesKHR; + +typedef struct VkPhysicalDeviceSubgroupProperties { + VkStructureType sType; + void * pNext; + uint32_t subgroupSize; + VkShaderStageFlags supportedStages; + VkSubgroupFeatureFlags supportedOperations; + VkBool32 quadOperationsInAllStages; +} VkPhysicalDeviceSubgroupProperties; + +typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures { + VkStructureType sType; + void * pNext; + VkBool32 shaderSubgroupExtendedTypes; +} VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures; + +typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR; + +typedef struct VkDeviceBufferMemoryRequirements { + VkStructureType sType; + const void * pNext; + const VkBufferCreateInfo * pCreateInfo; +} VkDeviceBufferMemoryRequirements; + +typedef struct VkDeviceBufferMemoryRequirements VkDeviceBufferMemoryRequirementsKHR; + +typedef struct VkDeviceImageMemoryRequirements { + VkStructureType sType; + const void * pNext; + const VkImageCreateInfo * pCreateInfo; + VkImageAspectFlagBits planeAspect; +} VkDeviceImageMemoryRequirements; + +typedef struct VkDeviceImageMemoryRequirements VkDeviceImageMemoryRequirementsKHR; + +typedef struct VkMemoryRequirements2 { + VkStructureType sType; + void * pNext; + VkMemoryRequirements memoryRequirements; +} VkMemoryRequirements2; + +typedef struct VkMemoryRequirements2 VkMemoryRequirements2KHR; + +typedef struct VkSparseImageMemoryRequirements2 { + VkStructureType sType; + void * pNext; + VkSparseImageMemoryRequirements memoryRequirements; +} VkSparseImageMemoryRequirements2; + +typedef struct VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR; + +typedef struct VkMemoryDedicatedRequirements { + VkStructureType sType; + void * pNext; + VkBool32 prefersDedicatedAllocation; + VkBool32 requiresDedicatedAllocation; +} VkMemoryDedicatedRequirements; + +typedef struct VkMemoryDedicatedRequirements VkMemoryDedicatedRequirementsKHR; + +typedef struct VkImageViewUsageCreateInfo { + VkStructureType sType; + const void * pNext; + VkImageUsageFlags usage; +} VkImageViewUsageCreateInfo; + +typedef struct VkImageViewUsageCreateInfo VkImageViewUsageCreateInfoKHR; + +typedef struct VkSamplerYcbcrConversionCreateInfo { + VkStructureType sType; + const void * pNext; + VkFormat format; + VkSamplerYcbcrModelConversion ycbcrModel; + VkSamplerYcbcrRange ycbcrRange; + VkComponentMapping components; + VkChromaLocation xChromaOffset; + VkChromaLocation yChromaOffset; + VkFilter chromaFilter; + VkBool32 forceExplicitReconstruction; +} VkSamplerYcbcrConversionCreateInfo; + +typedef struct VkSamplerYcbcrConversionCreateInfo VkSamplerYcbcrConversionCreateInfoKHR; + +typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures { + VkStructureType sType; + void * pNext; + VkBool32 samplerYcbcrConversion; +} VkPhysicalDeviceSamplerYcbcrConversionFeatures; + +typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR; + +typedef struct VkTextureLODGatherFormatPropertiesAMD { + VkStructureType sType; + void * pNext; + VkBool32 supportsTextureGatherLODBiasAMD; +} VkTextureLODGatherFormatPropertiesAMD; + +typedef struct VkConditionalRenderingBeginInfoEXT { + VkStructureType sType; + const void * pNext; + VkBuffer buffer; + VkDeviceSize offset; + VkConditionalRenderingFlagsEXT flags; +} VkConditionalRenderingBeginInfoEXT; + +typedef struct VkProtectedSubmitInfo { + VkStructureType sType; + const void * pNext; + VkBool32 protectedSubmit; +} VkProtectedSubmitInfo; + +typedef struct VkPhysicalDeviceProtectedMemoryFeatures { + VkStructureType sType; + void * pNext; + VkBool32 protectedMemory; +} VkPhysicalDeviceProtectedMemoryFeatures; + +typedef struct VkPhysicalDeviceProtectedMemoryProperties { + VkStructureType sType; + void * pNext; + VkBool32 protectedNoFault; +} VkPhysicalDeviceProtectedMemoryProperties; + +typedef struct VkDeviceQueueInfo2 { + VkStructureType sType; + const void * pNext; + VkDeviceQueueCreateFlags flags; + uint32_t queueFamilyIndex; + uint32_t queueIndex; +} VkDeviceQueueInfo2; + +typedef struct VkPipelineCoverageToColorStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineCoverageToColorStateCreateFlagsNV flags; + VkBool32 coverageToColorEnable; + uint32_t coverageToColorLocation; +} VkPipelineCoverageToColorStateCreateInfoNV; + +typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties { + VkStructureType sType; + void * pNext; + VkBool32 filterMinmaxSingleComponentFormats; + VkBool32 filterMinmaxImageComponentMapping; +} VkPhysicalDeviceSamplerFilterMinmaxProperties; + +typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT; + +typedef struct VkPipelineSampleLocationsStateCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkBool32 sampleLocationsEnable; + VkSampleLocationsInfoEXT sampleLocationsInfo; +} VkPipelineSampleLocationsStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceSampleLocationsPropertiesEXT { + VkStructureType sType; + void * pNext; + VkSampleCountFlags sampleLocationSampleCounts; + VkExtent2D maxSampleLocationGridSize; + float sampleLocationCoordinateRange [2]; + uint32_t sampleLocationSubPixelBits; + VkBool32 variableSampleLocations; +} VkPhysicalDeviceSampleLocationsPropertiesEXT; + +typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 advancedBlendCoherentOperations; +} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT; + +typedef struct VkPhysicalDeviceMultiDrawFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 multiDraw; +} VkPhysicalDeviceMultiDrawFeaturesEXT; + +typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t advancedBlendMaxColorAttachments; + VkBool32 advancedBlendIndependentBlend; + VkBool32 advancedBlendNonPremultipliedSrcColor; + VkBool32 advancedBlendNonPremultipliedDstColor; + VkBool32 advancedBlendCorrelatedOverlap; + VkBool32 advancedBlendAllOperations; +} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT; + +typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkBool32 srcPremultiplied; + VkBool32 dstPremultiplied; + VkBlendOverlapEXT blendOverlap; +} VkPipelineColorBlendAdvancedStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceInlineUniformBlockFeatures { + VkStructureType sType; + void * pNext; + VkBool32 inlineUniformBlock; + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; +} VkPhysicalDeviceInlineUniformBlockFeatures; + +typedef struct VkPhysicalDeviceInlineUniformBlockFeatures VkPhysicalDeviceInlineUniformBlockFeaturesEXT; + +typedef struct VkPipelineCoverageModulationStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineCoverageModulationStateCreateFlagsNV flags; + VkCoverageModulationModeNV coverageModulationMode; + VkBool32 coverageModulationTableEnable; + uint32_t coverageModulationTableCount; + const float * pCoverageModulationTable; +} VkPipelineCoverageModulationStateCreateInfoNV; + +typedef struct VkValidationCacheCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkValidationCacheCreateFlagsEXT flags; + size_t initialDataSize; + const void * pInitialData; +} VkValidationCacheCreateInfoEXT; + +typedef struct VkPhysicalDeviceMaintenance3Properties { + VkStructureType sType; + void * pNext; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceMaintenance3Properties; + +typedef struct VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; + +typedef struct VkPhysicalDeviceMaintenance4Features { + VkStructureType sType; + void * pNext; + VkBool32 maintenance4; +} VkPhysicalDeviceMaintenance4Features; + +typedef struct VkPhysicalDeviceMaintenance4Features VkPhysicalDeviceMaintenance4FeaturesKHR; + +typedef struct VkPhysicalDeviceMaintenance4Properties { + VkStructureType sType; + void * pNext; + VkDeviceSize maxBufferSize; +} VkPhysicalDeviceMaintenance4Properties; + +typedef struct VkPhysicalDeviceMaintenance4Properties VkPhysicalDeviceMaintenance4PropertiesKHR; + +typedef struct VkPhysicalDeviceMaintenance5Features { + VkStructureType sType; + void * pNext; + VkBool32 maintenance5; +} VkPhysicalDeviceMaintenance5Features; + +typedef struct VkPhysicalDeviceMaintenance5Features VkPhysicalDeviceMaintenance5FeaturesKHR; + +typedef struct VkPhysicalDeviceMaintenance5Properties { + VkStructureType sType; + void * pNext; + VkBool32 earlyFragmentMultisampleCoverageAfterSampleCounting; + VkBool32 earlyFragmentSampleMaskTestBeforeSampleCounting; + VkBool32 depthStencilSwizzleOneSupport; + VkBool32 polygonModePointSize; + VkBool32 nonStrictSinglePixelWideLinesUseParallelogram; + VkBool32 nonStrictWideLinesUseParallelogram; +} VkPhysicalDeviceMaintenance5Properties; + +typedef struct VkPhysicalDeviceMaintenance5Properties VkPhysicalDeviceMaintenance5PropertiesKHR; + +typedef struct VkPhysicalDeviceMaintenance6Features { + VkStructureType sType; + void * pNext; + VkBool32 maintenance6; +} VkPhysicalDeviceMaintenance6Features; + +typedef struct VkPhysicalDeviceMaintenance6Features VkPhysicalDeviceMaintenance6FeaturesKHR; + +typedef struct VkPhysicalDeviceMaintenance6Properties { + VkStructureType sType; + void * pNext; + VkBool32 blockTexelViewCompatibleMultipleLayers; + uint32_t maxCombinedImageSamplerDescriptorCount; + VkBool32 fragmentShadingRateClampCombinerInputs; +} VkPhysicalDeviceMaintenance6Properties; + +typedef struct VkPhysicalDeviceMaintenance6Properties VkPhysicalDeviceMaintenance6PropertiesKHR; + +typedef struct VkPhysicalDeviceMaintenance7FeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 maintenance7; +} VkPhysicalDeviceMaintenance7FeaturesKHR; + +typedef struct VkPhysicalDeviceMaintenance7PropertiesKHR { + VkStructureType sType; + void * pNext; + VkBool32 robustFragmentShadingRateAttachmentAccess; + VkBool32 separateDepthStencilAttachmentAccess; + uint32_t maxDescriptorSetTotalUniformBuffersDynamic; + uint32_t maxDescriptorSetTotalStorageBuffersDynamic; + uint32_t maxDescriptorSetTotalBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindTotalUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindTotalStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindTotalBuffersDynamic; +} VkPhysicalDeviceMaintenance7PropertiesKHR; + +typedef struct VkPhysicalDeviceLayeredApiPropertiesListKHR { + VkStructureType sType; + void * pNext; + uint32_t layeredApiCount; + VkPhysicalDeviceLayeredApiPropertiesKHR * pLayeredApis; +} VkPhysicalDeviceLayeredApiPropertiesListKHR; + +typedef struct VkPhysicalDeviceMaintenance8FeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 maintenance8; +} VkPhysicalDeviceMaintenance8FeaturesKHR; + +typedef struct VkDescriptorSetLayoutSupport { + VkStructureType sType; + void * pNext; + VkBool32 supported; +} VkDescriptorSetLayoutSupport; + +typedef struct VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; + +typedef struct VkPhysicalDeviceShaderDrawParametersFeatures { + VkStructureType sType; + void * pNext; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceShaderDrawParametersFeatures; + +typedef struct VkPhysicalDeviceShaderDrawParametersFeatures VkPhysicalDeviceShaderDrawParameterFeatures; + +typedef struct VkPhysicalDeviceShaderFloat16Int8Features { + VkStructureType sType; + void * pNext; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; +} VkPhysicalDeviceShaderFloat16Int8Features; + +typedef struct VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceShaderFloat16Int8FeaturesKHR; + +typedef struct VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceFloat16Int8FeaturesKHR; + +typedef struct VkPhysicalDeviceFloatControlsProperties { + VkStructureType sType; + void * pNext; + VkShaderFloatControlsIndependence denormBehaviorIndependence; + VkShaderFloatControlsIndependence roundingModeIndependence; + VkBool32 shaderSignedZeroInfNanPreserveFloat16; + VkBool32 shaderSignedZeroInfNanPreserveFloat32; + VkBool32 shaderSignedZeroInfNanPreserveFloat64; + VkBool32 shaderDenormPreserveFloat16; + VkBool32 shaderDenormPreserveFloat32; + VkBool32 shaderDenormPreserveFloat64; + VkBool32 shaderDenormFlushToZeroFloat16; + VkBool32 shaderDenormFlushToZeroFloat32; + VkBool32 shaderDenormFlushToZeroFloat64; + VkBool32 shaderRoundingModeRTEFloat16; + VkBool32 shaderRoundingModeRTEFloat32; + VkBool32 shaderRoundingModeRTEFloat64; + VkBool32 shaderRoundingModeRTZFloat16; + VkBool32 shaderRoundingModeRTZFloat32; + VkBool32 shaderRoundingModeRTZFloat64; +} VkPhysicalDeviceFloatControlsProperties; + +typedef struct VkPhysicalDeviceFloatControlsProperties VkPhysicalDeviceFloatControlsPropertiesKHR; + +typedef struct VkPhysicalDeviceHostQueryResetFeatures { + VkStructureType sType; + void * pNext; + VkBool32 hostQueryReset; +} VkPhysicalDeviceHostQueryResetFeatures; + +typedef struct VkPhysicalDeviceHostQueryResetFeatures VkPhysicalDeviceHostQueryResetFeaturesEXT; + +typedef struct VkShaderStatisticsInfoAMD { + VkShaderStageFlags shaderStageMask; + VkShaderResourceUsageAMD resourceUsage; + uint32_t numPhysicalVgprs; + uint32_t numPhysicalSgprs; + uint32_t numAvailableVgprs; + uint32_t numAvailableSgprs; + uint32_t computeWorkGroupSize [3]; +} VkShaderStatisticsInfoAMD; + +typedef struct VkPhysicalDeviceGlobalPriorityQueryFeatures { + VkStructureType sType; + void * pNext; + VkBool32 globalPriorityQuery; +} VkPhysicalDeviceGlobalPriorityQueryFeatures; + +typedef struct VkPhysicalDeviceGlobalPriorityQueryFeatures VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR; + +typedef struct VkPhysicalDeviceGlobalPriorityQueryFeatures VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT; + +typedef struct VkDebugUtilsMessengerCallbackDataEXT { + VkStructureType sType; + const void * pNext; + VkDebugUtilsMessengerCallbackDataFlagsEXT flags; + const char * pMessageIdName; + int32_t messageIdNumber; + const char * pMessage; + uint32_t queueLabelCount; + const VkDebugUtilsLabelEXT * pQueueLabels; + uint32_t cmdBufLabelCount; + const VkDebugUtilsLabelEXT * pCmdBufLabels; + uint32_t objectCount; + const VkDebugUtilsObjectNameInfoEXT * pObjects; +} VkDebugUtilsMessengerCallbackDataEXT; + +typedef struct VkPhysicalDeviceDeviceMemoryReportFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 deviceMemoryReport; +} VkPhysicalDeviceDeviceMemoryReportFeaturesEXT; + +typedef struct VkDeviceMemoryReportCallbackDataEXT { + VkStructureType sType; + void * pNext; + VkDeviceMemoryReportFlagsEXT flags; + VkDeviceMemoryReportEventTypeEXT type; + uint64_t memoryObjectId; + VkDeviceSize size; + VkObjectType objectType; + uint64_t objectHandle; + uint32_t heapIndex; +} VkDeviceMemoryReportCallbackDataEXT; + +typedef struct VkPhysicalDeviceExternalMemoryHostPropertiesEXT { + VkStructureType sType; + void * pNext; + VkDeviceSize minImportedHostPointerAlignment; +} VkPhysicalDeviceExternalMemoryHostPropertiesEXT; + +typedef struct VkPhysicalDeviceConservativeRasterizationPropertiesEXT { + VkStructureType sType; + void * pNext; + float primitiveOverestimationSize; + float maxExtraPrimitiveOverestimationSize; + float extraPrimitiveOverestimationSizeGranularity; + VkBool32 primitiveUnderestimation; + VkBool32 conservativePointAndLineRasterization; + VkBool32 degenerateTrianglesRasterized; + VkBool32 degenerateLinesRasterized; + VkBool32 fullyCoveredFragmentShaderInputVariable; + VkBool32 conservativeRasterizationPostDepthCoverage; +} VkPhysicalDeviceConservativeRasterizationPropertiesEXT; + +typedef struct VkPhysicalDeviceShaderCoreProperties2AMD { + VkStructureType sType; + void * pNext; + VkShaderCorePropertiesFlagsAMD shaderCoreFeatures; + uint32_t activeComputeUnitCount; +} VkPhysicalDeviceShaderCoreProperties2AMD; + +typedef struct VkPipelineRasterizationConservativeStateCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkPipelineRasterizationConservativeStateCreateFlagsEXT flags; + VkConservativeRasterizationModeEXT conservativeRasterizationMode; + float extraPrimitiveOverestimationSize; +} VkPipelineRasterizationConservativeStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceDescriptorIndexingFeatures { + VkStructureType sType; + void * pNext; + VkBool32 shaderInputAttachmentArrayDynamicIndexing; + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; + VkBool32 shaderUniformBufferArrayNonUniformIndexing; + VkBool32 shaderSampledImageArrayNonUniformIndexing; + VkBool32 shaderStorageBufferArrayNonUniformIndexing; + VkBool32 shaderStorageImageArrayNonUniformIndexing; + VkBool32 shaderInputAttachmentArrayNonUniformIndexing; + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; + VkBool32 descriptorBindingUniformBufferUpdateAfterBind; + VkBool32 descriptorBindingSampledImageUpdateAfterBind; + VkBool32 descriptorBindingStorageImageUpdateAfterBind; + VkBool32 descriptorBindingStorageBufferUpdateAfterBind; + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingUpdateUnusedWhilePending; + VkBool32 descriptorBindingPartiallyBound; + VkBool32 descriptorBindingVariableDescriptorCount; + VkBool32 runtimeDescriptorArray; +} VkPhysicalDeviceDescriptorIndexingFeatures; + +typedef struct VkPhysicalDeviceDescriptorIndexingFeatures VkPhysicalDeviceDescriptorIndexingFeaturesEXT; + +typedef struct VkPhysicalDeviceDescriptorIndexingProperties { + VkStructureType sType; + void * pNext; + uint32_t maxUpdateAfterBindDescriptorsInAllPools; + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; + VkBool32 shaderSampledImageArrayNonUniformIndexingNative; + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; + VkBool32 shaderStorageImageArrayNonUniformIndexingNative; + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; + VkBool32 robustBufferAccessUpdateAfterBind; + VkBool32 quadDivergentImplicitLod; + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; + uint32_t maxPerStageUpdateAfterBindResources; + uint32_t maxDescriptorSetUpdateAfterBindSamplers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindSampledImages; + uint32_t maxDescriptorSetUpdateAfterBindStorageImages; + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; +} VkPhysicalDeviceDescriptorIndexingProperties; + +typedef struct VkPhysicalDeviceDescriptorIndexingProperties VkPhysicalDeviceDescriptorIndexingPropertiesEXT; + +typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo { + VkStructureType sType; + const void * pNext; + uint32_t bindingCount; + const VkDescriptorBindingFlags * pBindingFlags; +} VkDescriptorSetLayoutBindingFlagsCreateInfo; + +typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo VkDescriptorSetLayoutBindingFlagsCreateInfoEXT; + +typedef struct VkAttachmentDescription2 { + VkStructureType sType; + const void * pNext; + VkAttachmentDescriptionFlags flags; + VkFormat format; + VkSampleCountFlagBits samples; + VkAttachmentLoadOp loadOp; + VkAttachmentStoreOp storeOp; + VkAttachmentLoadOp stencilLoadOp; + VkAttachmentStoreOp stencilStoreOp; + VkImageLayout initialLayout; + VkImageLayout finalLayout; +} VkAttachmentDescription2; + +typedef struct VkAttachmentDescription2 VkAttachmentDescription2KHR; + +typedef struct VkAttachmentReference2 { + VkStructureType sType; + const void * pNext; + uint32_t attachment; + VkImageLayout layout; + VkImageAspectFlags aspectMask; +} VkAttachmentReference2; + +typedef struct VkAttachmentReference2 VkAttachmentReference2KHR; + +typedef struct VkSubpassDescription2 { + VkStructureType sType; + const void * pNext; + VkSubpassDescriptionFlags flags; + VkPipelineBindPoint pipelineBindPoint; + uint32_t viewMask; + uint32_t inputAttachmentCount; + const VkAttachmentReference2 * pInputAttachments; + uint32_t colorAttachmentCount; + const VkAttachmentReference2 * pColorAttachments; + const VkAttachmentReference2 * pResolveAttachments; + const VkAttachmentReference2 * pDepthStencilAttachment; + uint32_t preserveAttachmentCount; + const uint32_t * pPreserveAttachments; +} VkSubpassDescription2; + +typedef struct VkSubpassDescription2 VkSubpassDescription2KHR; + +typedef struct VkSubpassDependency2 { + VkStructureType sType; + const void * pNext; + uint32_t srcSubpass; + uint32_t dstSubpass; + VkPipelineStageFlags srcStageMask; + VkPipelineStageFlags dstStageMask; + VkAccessFlags srcAccessMask; + VkAccessFlags dstAccessMask; + VkDependencyFlags dependencyFlags; + int32_t viewOffset; +} VkSubpassDependency2; + +typedef struct VkSubpassDependency2 VkSubpassDependency2KHR; + +typedef struct VkRenderPassCreateInfo2 { + VkStructureType sType; + const void * pNext; + VkRenderPassCreateFlags flags; + uint32_t attachmentCount; + const VkAttachmentDescription2 * pAttachments; + uint32_t subpassCount; + const VkSubpassDescription2 * pSubpasses; + uint32_t dependencyCount; + const VkSubpassDependency2 * pDependencies; + uint32_t correlatedViewMaskCount; + const uint32_t * pCorrelatedViewMasks; +} VkRenderPassCreateInfo2; + +typedef struct VkRenderPassCreateInfo2 VkRenderPassCreateInfo2KHR; + +typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures { + VkStructureType sType; + void * pNext; + VkBool32 timelineSemaphore; +} VkPhysicalDeviceTimelineSemaphoreFeatures; + +typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures VkPhysicalDeviceTimelineSemaphoreFeaturesKHR; + +typedef struct VkSemaphoreWaitInfo { + VkStructureType sType; + const void * pNext; + VkSemaphoreWaitFlags flags; + uint32_t semaphoreCount; + const VkSemaphore * pSemaphores; + const uint64_t * pValues; +} VkSemaphoreWaitInfo; + +typedef struct VkSemaphoreWaitInfo VkSemaphoreWaitInfoKHR; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorProperties { + VkStructureType sType; + void * pNext; + uint32_t maxVertexAttribDivisor; + VkBool32 supportsNonZeroFirstInstance; +} VkPhysicalDeviceVertexAttributeDivisorProperties; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorProperties VkPhysicalDeviceVertexAttributeDivisorPropertiesKHR; + +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef struct VkAndroidHardwareBufferPropertiesANDROID { + VkStructureType sType; + void * pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeBits; +} VkAndroidHardwareBufferPropertiesANDROID; + +#endif + +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID { + VkStructureType sType; + void * pNext; + VkFormat format; + uint64_t externalFormat; + VkFormatFeatureFlags formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkAndroidHardwareBufferFormatPropertiesANDROID; + +#endif + +typedef struct VkCommandBufferInheritanceConditionalRenderingInfoEXT { + VkStructureType sType; + const void * pNext; + VkBool32 conditionalRenderingEnable; +} VkCommandBufferInheritanceConditionalRenderingInfoEXT; + +typedef struct VkPhysicalDevice8BitStorageFeatures { + VkStructureType sType; + void * pNext; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; +} VkPhysicalDevice8BitStorageFeatures; + +typedef struct VkPhysicalDevice8BitStorageFeatures VkPhysicalDevice8BitStorageFeaturesKHR; + +typedef struct VkPhysicalDeviceConditionalRenderingFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 conditionalRendering; + VkBool32 inheritedConditionalRendering; +} VkPhysicalDeviceConditionalRenderingFeaturesEXT; + +typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures { + VkStructureType sType; + void * pNext; + VkBool32 vulkanMemoryModel; + VkBool32 vulkanMemoryModelDeviceScope; + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; +} VkPhysicalDeviceVulkanMemoryModelFeatures; + +typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures VkPhysicalDeviceVulkanMemoryModelFeaturesKHR; + +typedef struct VkPhysicalDeviceShaderAtomicInt64Features { + VkStructureType sType; + void * pNext; + VkBool32 shaderBufferInt64Atomics; + VkBool32 shaderSharedInt64Atomics; +} VkPhysicalDeviceShaderAtomicInt64Features; + +typedef struct VkPhysicalDeviceShaderAtomicInt64Features VkPhysicalDeviceShaderAtomicInt64FeaturesKHR; + +typedef struct VkPhysicalDeviceShaderAtomicFloatFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 shaderBufferFloat32Atomics; + VkBool32 shaderBufferFloat32AtomicAdd; + VkBool32 shaderBufferFloat64Atomics; + VkBool32 shaderBufferFloat64AtomicAdd; + VkBool32 shaderSharedFloat32Atomics; + VkBool32 shaderSharedFloat32AtomicAdd; + VkBool32 shaderSharedFloat64Atomics; + VkBool32 shaderSharedFloat64AtomicAdd; + VkBool32 shaderImageFloat32Atomics; + VkBool32 shaderImageFloat32AtomicAdd; + VkBool32 sparseImageFloat32Atomics; + VkBool32 sparseImageFloat32AtomicAdd; +} VkPhysicalDeviceShaderAtomicFloatFeaturesEXT; + +typedef struct VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 shaderBufferFloat16Atomics; + VkBool32 shaderBufferFloat16AtomicAdd; + VkBool32 shaderBufferFloat16AtomicMinMax; + VkBool32 shaderBufferFloat32AtomicMinMax; + VkBool32 shaderBufferFloat64AtomicMinMax; + VkBool32 shaderSharedFloat16Atomics; + VkBool32 shaderSharedFloat16AtomicAdd; + VkBool32 shaderSharedFloat16AtomicMinMax; + VkBool32 shaderSharedFloat32AtomicMinMax; + VkBool32 shaderSharedFloat64AtomicMinMax; + VkBool32 shaderImageFloat32AtomicMinMax; + VkBool32 sparseImageFloat32AtomicMinMax; +} VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorFeatures { + VkStructureType sType; + void * pNext; + VkBool32 vertexAttributeInstanceRateDivisor; + VkBool32 vertexAttributeInstanceRateZeroDivisor; +} VkPhysicalDeviceVertexAttributeDivisorFeatures; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorFeatures VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR; + +typedef struct VkPhysicalDeviceVertexAttributeDivisorFeatures VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT; + +typedef struct VkQueueFamilyCheckpointPropertiesNV { + VkStructureType sType; + void * pNext; + VkPipelineStageFlags checkpointExecutionStageMask; +} VkQueueFamilyCheckpointPropertiesNV; + +typedef struct VkPhysicalDeviceDepthStencilResolveProperties { + VkStructureType sType; + void * pNext; + VkResolveModeFlags supportedDepthResolveModes; + VkResolveModeFlags supportedStencilResolveModes; + VkBool32 independentResolveNone; + VkBool32 independentResolve; +} VkPhysicalDeviceDepthStencilResolveProperties; + +typedef struct VkPhysicalDeviceDepthStencilResolveProperties VkPhysicalDeviceDepthStencilResolvePropertiesKHR; + +typedef struct VkSubpassDescriptionDepthStencilResolve { + VkStructureType sType; + const void * pNext; + VkResolveModeFlagBits depthResolveMode; + VkResolveModeFlagBits stencilResolveMode; + const VkAttachmentReference2 * pDepthStencilResolveAttachment; +} VkSubpassDescriptionDepthStencilResolve; + +typedef struct VkSubpassDescriptionDepthStencilResolve VkSubpassDescriptionDepthStencilResolveKHR; + +typedef struct VkPhysicalDeviceASTCDecodeFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 decodeModeSharedExponent; +} VkPhysicalDeviceASTCDecodeFeaturesEXT; + +typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 transformFeedback; + VkBool32 geometryStreams; +} VkPhysicalDeviceTransformFeedbackFeaturesEXT; + +typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t maxTransformFeedbackStreams; + uint32_t maxTransformFeedbackBuffers; + VkDeviceSize maxTransformFeedbackBufferSize; + uint32_t maxTransformFeedbackStreamDataSize; + uint32_t maxTransformFeedbackBufferDataSize; + uint32_t maxTransformFeedbackBufferDataStride; + VkBool32 transformFeedbackQueries; + VkBool32 transformFeedbackStreamsLinesTriangles; + VkBool32 transformFeedbackRasterizationStreamSelect; + VkBool32 transformFeedbackDraw; +} VkPhysicalDeviceTransformFeedbackPropertiesEXT; + +typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkPipelineRasterizationStateStreamCreateFlagsEXT flags; + uint32_t rasterizationStream; +} VkPipelineRasterizationStateStreamCreateInfoEXT; + +typedef struct VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 representativeFragmentTest; +} VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV; + +typedef struct VkPipelineRepresentativeFragmentTestStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkBool32 representativeFragmentTestEnable; +} VkPipelineRepresentativeFragmentTestStateCreateInfoNV; + +typedef struct VkPhysicalDeviceExclusiveScissorFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 exclusiveScissor; +} VkPhysicalDeviceExclusiveScissorFeaturesNV; + +typedef struct VkPhysicalDeviceCornerSampledImageFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 cornerSampledImage; +} VkPhysicalDeviceCornerSampledImageFeaturesNV; + +typedef struct VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 computeDerivativeGroupQuads; + VkBool32 computeDerivativeGroupLinear; +} VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR; + +typedef struct VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR VkPhysicalDeviceComputeShaderDerivativesFeaturesNV; + +typedef struct VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR { + VkStructureType sType; + void * pNext; + VkBool32 meshAndTaskShaderDerivatives; +} VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR; + +typedef struct VkPhysicalDeviceShaderImageFootprintFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 imageFootprint; +} VkPhysicalDeviceShaderImageFootprintFeaturesNV; + +typedef struct VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 dedicatedAllocationImageAliasing; +} VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV; + +typedef struct VkPhysicalDeviceCopyMemoryIndirectFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 indirectCopy; +} VkPhysicalDeviceCopyMemoryIndirectFeaturesNV; + +typedef struct VkPhysicalDeviceCopyMemoryIndirectPropertiesNV { + VkStructureType sType; + void * pNext; + VkQueueFlags supportedQueues; +} VkPhysicalDeviceCopyMemoryIndirectPropertiesNV; + +typedef struct VkPhysicalDeviceMemoryDecompressionFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 memoryDecompression; +} VkPhysicalDeviceMemoryDecompressionFeaturesNV; + +typedef struct VkPhysicalDeviceMemoryDecompressionPropertiesNV { + VkStructureType sType; + void * pNext; + VkMemoryDecompressionMethodFlagsNV decompressionMethods; + uint64_t maxDecompressionIndirectCount; +} VkPhysicalDeviceMemoryDecompressionPropertiesNV; + +typedef struct VkPipelineViewportShadingRateImageStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkBool32 shadingRateImageEnable; + uint32_t viewportCount; + const VkShadingRatePaletteNV * pShadingRatePalettes; +} VkPipelineViewportShadingRateImageStateCreateInfoNV; + +typedef struct VkPhysicalDeviceShadingRateImageFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 shadingRateImage; + VkBool32 shadingRateCoarseSampleOrder; +} VkPhysicalDeviceShadingRateImageFeaturesNV; + +typedef struct VkPhysicalDeviceInvocationMaskFeaturesHUAWEI { + VkStructureType sType; + void * pNext; + VkBool32 invocationMask; +} VkPhysicalDeviceInvocationMaskFeaturesHUAWEI; + +typedef struct VkPhysicalDeviceMeshShaderFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 taskShader; + VkBool32 meshShader; +} VkPhysicalDeviceMeshShaderFeaturesNV; + +typedef struct VkPhysicalDeviceMeshShaderFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 taskShader; + VkBool32 meshShader; + VkBool32 multiviewMeshShader; + VkBool32 primitiveFragmentShadingRateMeshShader; + VkBool32 meshShaderQueries; +} VkPhysicalDeviceMeshShaderFeaturesEXT; + +typedef struct VkPhysicalDeviceMeshShaderPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t maxTaskWorkGroupTotalCount; + uint32_t maxTaskWorkGroupCount [3]; + uint32_t maxTaskWorkGroupInvocations; + uint32_t maxTaskWorkGroupSize [3]; + uint32_t maxTaskPayloadSize; + uint32_t maxTaskSharedMemorySize; + uint32_t maxTaskPayloadAndSharedMemorySize; + uint32_t maxMeshWorkGroupTotalCount; + uint32_t maxMeshWorkGroupCount [3]; + uint32_t maxMeshWorkGroupInvocations; + uint32_t maxMeshWorkGroupSize [3]; + uint32_t maxMeshSharedMemorySize; + uint32_t maxMeshPayloadAndSharedMemorySize; + uint32_t maxMeshOutputMemorySize; + uint32_t maxMeshPayloadAndOutputMemorySize; + uint32_t maxMeshOutputComponents; + uint32_t maxMeshOutputVertices; + uint32_t maxMeshOutputPrimitives; + uint32_t maxMeshOutputLayers; + uint32_t maxMeshMultiviewViewCount; + uint32_t meshOutputPerVertexGranularity; + uint32_t meshOutputPerPrimitiveGranularity; + uint32_t maxPreferredTaskWorkGroupInvocations; + uint32_t maxPreferredMeshWorkGroupInvocations; + VkBool32 prefersLocalInvocationVertexOutput; + VkBool32 prefersLocalInvocationPrimitiveOutput; + VkBool32 prefersCompactVertexOutput; + VkBool32 prefersCompactPrimitiveOutput; +} VkPhysicalDeviceMeshShaderPropertiesEXT; + +typedef struct VkRayTracingPipelineCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo * pStages; + uint32_t groupCount; + const VkRayTracingShaderGroupCreateInfoNV * pGroups; + uint32_t maxRecursionDepth; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkRayTracingPipelineCreateInfoNV; + +typedef struct VkRayTracingPipelineCreateInfoKHR { + VkStructureType sType; + const void * pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo * pStages; + uint32_t groupCount; + const VkRayTracingShaderGroupCreateInfoKHR * pGroups; + uint32_t maxPipelineRayRecursionDepth; + const VkPipelineLibraryCreateInfoKHR * pLibraryInfo; + const VkRayTracingPipelineInterfaceCreateInfoKHR * pLibraryInterface; + const VkPipelineDynamicStateCreateInfo * pDynamicState; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkRayTracingPipelineCreateInfoKHR; + +typedef struct VkGeometryTrianglesNV { + VkStructureType sType; + const void * pNext; + VkBuffer vertexData; + VkDeviceSize vertexOffset; + uint32_t vertexCount; + VkDeviceSize vertexStride; + VkFormat vertexFormat; + VkBuffer indexData; + VkDeviceSize indexOffset; + uint32_t indexCount; + VkIndexType indexType; + VkBuffer transformData; + VkDeviceSize transformOffset; +} VkGeometryTrianglesNV; + +typedef struct VkGeometryAABBNV { + VkStructureType sType; + const void * pNext; + VkBuffer aabbData; + uint32_t numAABBs; + uint32_t stride; + VkDeviceSize offset; +} VkGeometryAABBNV; + +typedef struct VkGeometryDataNV { + VkGeometryTrianglesNV triangles; + VkGeometryAABBNV aabbs; +} VkGeometryDataNV; + +typedef struct VkGeometryNV { + VkStructureType sType; + const void * pNext; + VkGeometryTypeKHR geometryType; + VkGeometryDataNV geometry; + VkGeometryFlagsKHR flags; +} VkGeometryNV; + +typedef struct VkAccelerationStructureInfoNV { + VkStructureType sType; + const void * pNext; + VkAccelerationStructureTypeNV type; + VkBuildAccelerationStructureFlagsNV flags; + uint32_t instanceCount; + uint32_t geometryCount; + const VkGeometryNV * pGeometries; +} VkAccelerationStructureInfoNV; + +typedef struct VkAccelerationStructureCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkDeviceSize compactedSize; + VkAccelerationStructureInfoNV info; +} VkAccelerationStructureCreateInfoNV; + +typedef struct VkBindAccelerationStructureMemoryInfoNV { + VkStructureType sType; + const void * pNext; + VkAccelerationStructureNV accelerationStructure; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + uint32_t deviceIndexCount; + const uint32_t * pDeviceIndices; +} VkBindAccelerationStructureMemoryInfoNV; + +typedef struct VkPhysicalDeviceAccelerationStructureFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 accelerationStructure; + VkBool32 accelerationStructureCaptureReplay; + VkBool32 accelerationStructureIndirectBuild; + VkBool32 accelerationStructureHostCommands; + VkBool32 descriptorBindingAccelerationStructureUpdateAfterBind; +} VkPhysicalDeviceAccelerationStructureFeaturesKHR; + +typedef struct VkPhysicalDeviceRayTracingPipelineFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 rayTracingPipeline; + VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplay; + VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplayMixed; + VkBool32 rayTracingPipelineTraceRaysIndirect; + VkBool32 rayTraversalPrimitiveCulling; +} VkPhysicalDeviceRayTracingPipelineFeaturesKHR; + +typedef struct VkPhysicalDeviceRayQueryFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 rayQuery; +} VkPhysicalDeviceRayQueryFeaturesKHR; + +typedef struct VkStridedDeviceAddressRegionKHR { + VkDeviceAddress deviceAddress; + VkDeviceSize stride; + VkDeviceSize size; +} VkStridedDeviceAddressRegionKHR; + +typedef struct VkTraceRaysIndirectCommand2KHR { + VkDeviceAddress raygenShaderRecordAddress; + VkDeviceSize raygenShaderRecordSize; + VkDeviceAddress missShaderBindingTableAddress; + VkDeviceSize missShaderBindingTableSize; + VkDeviceSize missShaderBindingTableStride; + VkDeviceAddress hitShaderBindingTableAddress; + VkDeviceSize hitShaderBindingTableSize; + VkDeviceSize hitShaderBindingTableStride; + VkDeviceAddress callableShaderBindingTableAddress; + VkDeviceSize callableShaderBindingTableSize; + VkDeviceSize callableShaderBindingTableStride; + uint32_t width; + uint32_t height; + uint32_t depth; +} VkTraceRaysIndirectCommand2KHR; + +typedef struct VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 rayTracingMaintenance1; + VkBool32 rayTracingPipelineTraceRaysIndirect2; +} VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR; + +typedef struct VkDrmFormatModifierPropertiesEXT { + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + VkFormatFeatureFlags drmFormatModifierTilingFeatures; +} VkDrmFormatModifierPropertiesEXT; + +typedef struct VkImageDrmFormatModifierExplicitCreateInfoEXT { + VkStructureType sType; + const void * pNext; + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + const VkSubresourceLayout * pPlaneLayouts; +} VkImageDrmFormatModifierExplicitCreateInfoEXT; + +typedef struct VkImageStencilUsageCreateInfo { + VkStructureType sType; + const void * pNext; + VkImageUsageFlags stencilUsage; +} VkImageStencilUsageCreateInfo; + +typedef struct VkImageStencilUsageCreateInfo VkImageStencilUsageCreateInfoEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMapFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 fragmentDensityMap; + VkBool32 fragmentDensityMapDynamic; + VkBool32 fragmentDensityMapNonSubsampledImages; +} VkPhysicalDeviceFragmentDensityMapFeaturesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMap2FeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 fragmentDensityMapDeferred; +} VkPhysicalDeviceFragmentDensityMap2FeaturesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 fragmentDensityMapOffset; +} VkPhysicalDeviceFragmentDensityMapOffsetFeaturesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMapOffsetFeaturesEXT VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM; + +typedef struct VkPhysicalDeviceFragmentDensityMapPropertiesEXT { + VkStructureType sType; + void * pNext; + VkExtent2D minFragmentDensityTexelSize; + VkExtent2D maxFragmentDensityTexelSize; + VkBool32 fragmentDensityInvocations; +} VkPhysicalDeviceFragmentDensityMapPropertiesEXT; + +typedef struct VkPhysicalDeviceFragmentDensityMap2PropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 subsampledLoads; + VkBool32 subsampledCoarseReconstructionEarlyAccess; + uint32_t maxSubsampledArrayLayers; + uint32_t maxDescriptorSetSubsampledSamplers; +} VkPhysicalDeviceFragmentDensityMap2PropertiesEXT; + +typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures { + VkStructureType sType; + void * pNext; + VkBool32 scalarBlockLayout; +} VkPhysicalDeviceScalarBlockLayoutFeatures; + +typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures VkPhysicalDeviceScalarBlockLayoutFeaturesEXT; + +typedef struct VkSurfaceProtectedCapabilitiesKHR { + VkStructureType sType; + const void * pNext; + VkBool32 supportsProtected; +} VkSurfaceProtectedCapabilitiesKHR; + +typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures { + VkStructureType sType; + void * pNext; + VkBool32 uniformBufferStandardLayout; +} VkPhysicalDeviceUniformBufferStandardLayoutFeatures; + +typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR; + +typedef struct VkPhysicalDeviceDepthClipEnableFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 depthClipEnable; +} VkPhysicalDeviceDepthClipEnableFeaturesEXT; + +typedef struct VkPipelineRasterizationDepthClipStateCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkPipelineRasterizationDepthClipStateCreateFlagsEXT flags; + VkBool32 depthClipEnable; +} VkPipelineRasterizationDepthClipStateCreateInfoEXT; + +typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT { + VkStructureType sType; + void * pNext; + VkDeviceSize heapBudget [ VK_MAX_MEMORY_HEAPS ]; + VkDeviceSize heapUsage [ VK_MAX_MEMORY_HEAPS ]; +} VkPhysicalDeviceMemoryBudgetPropertiesEXT; + +typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 memoryPriority; +} VkPhysicalDeviceMemoryPriorityFeaturesEXT; + +typedef struct VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 pageableDeviceLocalMemory; +} VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT; + +typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures { + VkStructureType sType; + void * pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeatures; + +typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; + +typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; +} VkPhysicalDeviceBufferDeviceAddressFeaturesEXT; + +typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT VkPhysicalDeviceBufferAddressFeaturesEXT; + +typedef struct VkBufferDeviceAddressCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkDeviceAddress deviceAddress; +} VkBufferDeviceAddressCreateInfoEXT; + +typedef struct VkFilterCubicImageViewImageFormatPropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 filterCubic; + VkBool32 filterCubicMinmax; +} VkFilterCubicImageViewImageFormatPropertiesEXT; + +typedef struct VkPhysicalDeviceImagelessFramebufferFeatures { + VkStructureType sType; + void * pNext; + VkBool32 imagelessFramebuffer; +} VkPhysicalDeviceImagelessFramebufferFeatures; + +typedef struct VkPhysicalDeviceImagelessFramebufferFeatures VkPhysicalDeviceImagelessFramebufferFeaturesKHR; + +typedef struct VkFramebufferAttachmentImageInfo { + VkStructureType sType; + const void * pNext; + VkImageCreateFlags flags; + VkImageUsageFlags usage; + uint32_t width; + uint32_t height; + uint32_t layerCount; + uint32_t viewFormatCount; + const VkFormat * pViewFormats; +} VkFramebufferAttachmentImageInfo; + +typedef struct VkFramebufferAttachmentImageInfo VkFramebufferAttachmentImageInfoKHR; + +typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeatures { + VkStructureType sType; + void * pNext; + VkBool32 textureCompressionASTC_HDR; +} VkPhysicalDeviceTextureCompressionASTCHDRFeatures; -typedef struct VkSubpassDependency { - uint32_t srcSubpass; - uint32_t dstSubpass; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkDependencyFlags dependencyFlags; -} VkSubpassDependency; +typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeatures VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT; -typedef struct VkRenderPassCreateInfo { +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV { VkStructureType sType; - const void * pNext; - VkRenderPassCreateFlags flags; - uint32_t attachmentCount; - const VkAttachmentDescription * pAttachments; - uint32_t subpassCount; - const VkSubpassDescription * pSubpasses; - uint32_t dependencyCount; - const VkSubpassDependency * pDependencies; -} VkRenderPassCreateInfo; + void * pNext; + VkBool32 cooperativeMatrix; + VkBool32 cooperativeMatrixRobustBufferAccess; +} VkPhysicalDeviceCooperativeMatrixFeaturesNV; -typedef struct VkEventCreateInfo { +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV { VkStructureType sType; - const void * pNext; - VkEventCreateFlags flags; -} VkEventCreateInfo; + void * pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesNV; -typedef struct VkFenceCreateInfo { +typedef struct VkPhysicalDeviceYcbcrImageArraysFeaturesEXT { VkStructureType sType; - const void * pNext; - VkFenceCreateFlags flags; -} VkFenceCreateInfo; + void * pNext; + VkBool32 ycbcrImageArrays; +} VkPhysicalDeviceYcbcrImageArraysFeaturesEXT; -typedef struct VkPhysicalDeviceFeatures { - VkBool32 robustBufferAccess; - VkBool32 fullDrawIndexUint32; - VkBool32 imageCubeArray; - VkBool32 independentBlend; - VkBool32 geometryShader; - VkBool32 tessellationShader; - VkBool32 sampleRateShading; - VkBool32 dualSrcBlend; - VkBool32 logicOp; - VkBool32 multiDrawIndirect; - VkBool32 drawIndirectFirstInstance; - VkBool32 depthClamp; - VkBool32 depthBiasClamp; - VkBool32 fillModeNonSolid; - VkBool32 depthBounds; - VkBool32 wideLines; - VkBool32 largePoints; - VkBool32 alphaToOne; - VkBool32 multiViewport; - VkBool32 samplerAnisotropy; - VkBool32 textureCompressionETC2; - VkBool32 textureCompressionASTC_LDR; - VkBool32 textureCompressionBC; - VkBool32 occlusionQueryPrecise; - VkBool32 pipelineStatisticsQuery; - VkBool32 vertexPipelineStoresAndAtomics; - VkBool32 fragmentStoresAndAtomics; - VkBool32 shaderTessellationAndGeometryPointSize; - VkBool32 shaderImageGatherExtended; - VkBool32 shaderStorageImageExtendedFormats; - VkBool32 shaderStorageImageMultisample; - VkBool32 shaderStorageImageReadWithoutFormat; - VkBool32 shaderStorageImageWriteWithoutFormat; - VkBool32 shaderUniformBufferArrayDynamicIndexing; - VkBool32 shaderSampledImageArrayDynamicIndexing; - VkBool32 shaderStorageBufferArrayDynamicIndexing; - VkBool32 shaderStorageImageArrayDynamicIndexing; - VkBool32 shaderClipDistance; - VkBool32 shaderCullDistance; - VkBool32 shaderFloat64; - VkBool32 shaderInt64; - VkBool32 shaderInt16; - VkBool32 shaderResourceResidency; - VkBool32 shaderResourceMinLod; - VkBool32 sparseBinding; - VkBool32 sparseResidencyBuffer; - VkBool32 sparseResidencyImage2D; - VkBool32 sparseResidencyImage3D; - VkBool32 sparseResidency2Samples; - VkBool32 sparseResidency4Samples; - VkBool32 sparseResidency8Samples; - VkBool32 sparseResidency16Samples; - VkBool32 sparseResidencyAliased; - VkBool32 variableMultisampleRate; - VkBool32 inheritedQueries; -} VkPhysicalDeviceFeatures; +typedef struct VkImageViewAddressPropertiesNVX { + VkStructureType sType; + void * pNext; + VkDeviceAddress deviceAddress; + VkDeviceSize size; +} VkImageViewAddressPropertiesNVX; -typedef struct VkPhysicalDeviceSparseProperties { - VkBool32 residencyStandard2DBlockShape; - VkBool32 residencyStandard2DMultisampleBlockShape; - VkBool32 residencyStandard3DBlockShape; - VkBool32 residencyAlignedMipSize; - VkBool32 residencyNonResidentStrict; -} VkPhysicalDeviceSparseProperties; +typedef struct VkPipelineCreationFeedback { + VkPipelineCreationFeedbackFlags flags; + uint64_t duration; +} VkPipelineCreationFeedback; -typedef struct VkPhysicalDeviceLimits { - uint32_t maxImageDimension1D; - uint32_t maxImageDimension2D; - uint32_t maxImageDimension3D; - uint32_t maxImageDimensionCube; - uint32_t maxImageArrayLayers; - uint32_t maxTexelBufferElements; - uint32_t maxUniformBufferRange; - uint32_t maxStorageBufferRange; - uint32_t maxPushConstantsSize; - uint32_t maxMemoryAllocationCount; - uint32_t maxSamplerAllocationCount; - VkDeviceSize bufferImageGranularity; - VkDeviceSize sparseAddressSpaceSize; - uint32_t maxBoundDescriptorSets; - uint32_t maxPerStageDescriptorSamplers; - uint32_t maxPerStageDescriptorUniformBuffers; - uint32_t maxPerStageDescriptorStorageBuffers; - uint32_t maxPerStageDescriptorSampledImages; - uint32_t maxPerStageDescriptorStorageImages; - uint32_t maxPerStageDescriptorInputAttachments; - uint32_t maxPerStageResources; - uint32_t maxDescriptorSetSamplers; - uint32_t maxDescriptorSetUniformBuffers; - uint32_t maxDescriptorSetUniformBuffersDynamic; - uint32_t maxDescriptorSetStorageBuffers; - uint32_t maxDescriptorSetStorageBuffersDynamic; - uint32_t maxDescriptorSetSampledImages; - uint32_t maxDescriptorSetStorageImages; - uint32_t maxDescriptorSetInputAttachments; - uint32_t maxVertexInputAttributes; - uint32_t maxVertexInputBindings; - uint32_t maxVertexInputAttributeOffset; - uint32_t maxVertexInputBindingStride; - uint32_t maxVertexOutputComponents; - uint32_t maxTessellationGenerationLevel; - uint32_t maxTessellationPatchSize; - uint32_t maxTessellationControlPerVertexInputComponents; - uint32_t maxTessellationControlPerVertexOutputComponents; - uint32_t maxTessellationControlPerPatchOutputComponents; - uint32_t maxTessellationControlTotalOutputComponents; - uint32_t maxTessellationEvaluationInputComponents; - uint32_t maxTessellationEvaluationOutputComponents; - uint32_t maxGeometryShaderInvocations; - uint32_t maxGeometryInputComponents; - uint32_t maxGeometryOutputComponents; - uint32_t maxGeometryOutputVertices; - uint32_t maxGeometryTotalOutputComponents; - uint32_t maxFragmentInputComponents; - uint32_t maxFragmentOutputAttachments; - uint32_t maxFragmentDualSrcAttachments; - uint32_t maxFragmentCombinedOutputResources; - uint32_t maxComputeSharedMemorySize; - uint32_t maxComputeWorkGroupCount [3]; - uint32_t maxComputeWorkGroupInvocations; - uint32_t maxComputeWorkGroupSize [3]; - uint32_t subPixelPrecisionBits; - uint32_t subTexelPrecisionBits; - uint32_t mipmapPrecisionBits; - uint32_t maxDrawIndexedIndexValue; - uint32_t maxDrawIndirectCount; - float maxSamplerLodBias; - float maxSamplerAnisotropy; - uint32_t maxViewports; - uint32_t maxViewportDimensions [2]; - float viewportBoundsRange [2]; - uint32_t viewportSubPixelBits; - size_t minMemoryMapAlignment; - VkDeviceSize minTexelBufferOffsetAlignment; - VkDeviceSize minUniformBufferOffsetAlignment; - VkDeviceSize minStorageBufferOffsetAlignment; - int32_t minTexelOffset; - uint32_t maxTexelOffset; - int32_t minTexelGatherOffset; - uint32_t maxTexelGatherOffset; - float minInterpolationOffset; - float maxInterpolationOffset; - uint32_t subPixelInterpolationOffsetBits; - uint32_t maxFramebufferWidth; - uint32_t maxFramebufferHeight; - uint32_t maxFramebufferLayers; - VkSampleCountFlags framebufferColorSampleCounts; - VkSampleCountFlags framebufferDepthSampleCounts; - VkSampleCountFlags framebufferStencilSampleCounts; - VkSampleCountFlags framebufferNoAttachmentsSampleCounts; - uint32_t maxColorAttachments; - VkSampleCountFlags sampledImageColorSampleCounts; - VkSampleCountFlags sampledImageIntegerSampleCounts; - VkSampleCountFlags sampledImageDepthSampleCounts; - VkSampleCountFlags sampledImageStencilSampleCounts; - VkSampleCountFlags storageImageSampleCounts; - uint32_t maxSampleMaskWords; - VkBool32 timestampComputeAndGraphics; - float timestampPeriod; - uint32_t maxClipDistances; - uint32_t maxCullDistances; - uint32_t maxCombinedClipAndCullDistances; - uint32_t discreteQueuePriorities; - float pointSizeRange [2]; - float lineWidthRange [2]; - float pointSizeGranularity; - float lineWidthGranularity; - VkBool32 strictLines; - VkBool32 standardSampleLocations; - VkDeviceSize optimalBufferCopyOffsetAlignment; - VkDeviceSize optimalBufferCopyRowPitchAlignment; - VkDeviceSize nonCoherentAtomSize; -} VkPhysicalDeviceLimits; +typedef struct VkPipelineCreationFeedback VkPipelineCreationFeedbackEXT; -typedef struct VkSemaphoreCreateInfo { +typedef struct VkPipelineCreationFeedbackCreateInfo { VkStructureType sType; - const void * pNext; - VkSemaphoreCreateFlags flags; -} VkSemaphoreCreateInfo; + const void * pNext; + VkPipelineCreationFeedback * pPipelineCreationFeedback; + uint32_t pipelineStageCreationFeedbackCount; + VkPipelineCreationFeedback * pPipelineStageCreationFeedbacks; +} VkPipelineCreationFeedbackCreateInfo; -typedef struct VkQueryPoolCreateInfo { +typedef struct VkPipelineCreationFeedbackCreateInfo VkPipelineCreationFeedbackCreateInfoEXT; + +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef struct VkSurfaceCapabilitiesFullScreenExclusiveEXT { VkStructureType sType; - const void * pNext; - VkQueryPoolCreateFlags flags; - VkQueryType queryType; - uint32_t queryCount; - VkQueryPipelineStatisticFlags pipelineStatistics; -} VkQueryPoolCreateInfo; + void * pNext; + VkBool32 fullScreenExclusiveSupported; +} VkSurfaceCapabilitiesFullScreenExclusiveEXT; -typedef struct VkFramebufferCreateInfo { +#endif + +typedef struct VkPhysicalDevicePresentBarrierFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 presentBarrier; +} VkPhysicalDevicePresentBarrierFeaturesNV; + +typedef struct VkSurfaceCapabilitiesPresentBarrierNV { + VkStructureType sType; + void * pNext; + VkBool32 presentBarrierSupported; +} VkSurfaceCapabilitiesPresentBarrierNV; + +typedef struct VkSwapchainPresentBarrierCreateInfoNV { + VkStructureType sType; + void * pNext; + VkBool32 presentBarrierEnable; +} VkSwapchainPresentBarrierCreateInfoNV; + +typedef struct VkPhysicalDevicePerformanceQueryFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 performanceCounterQueryPools; + VkBool32 performanceCounterMultipleQueryPools; +} VkPhysicalDevicePerformanceQueryFeaturesKHR; + +typedef struct VkPhysicalDevicePerformanceQueryPropertiesKHR { + VkStructureType sType; + void * pNext; + VkBool32 allowCommandBufferQueryCopies; +} VkPhysicalDevicePerformanceQueryPropertiesKHR; + +typedef struct VkPerformanceCounterDescriptionKHR { + VkStructureType sType; + void * pNext; + VkPerformanceCounterDescriptionFlagsKHR flags; + char name [ VK_MAX_DESCRIPTION_SIZE ]; + char category [ VK_MAX_DESCRIPTION_SIZE ]; + char description [ VK_MAX_DESCRIPTION_SIZE ]; +} VkPerformanceCounterDescriptionKHR; + +typedef struct VkAcquireProfilingLockInfoKHR { VkStructureType sType; const void * pNext; - VkFramebufferCreateFlags flags; - VkRenderPass renderPass; - uint32_t attachmentCount; - const VkImageView * pAttachments; - uint32_t width; - uint32_t height; - uint32_t layers; -} VkFramebufferCreateInfo; + VkAcquireProfilingLockFlagsKHR flags; + uint64_t timeout; +} VkAcquireProfilingLockInfoKHR; -typedef struct VkSubmitInfo { +typedef struct VkHeadlessSurfaceCreateInfoEXT { VkStructureType sType; - const void * pNext; - uint32_t waitSemaphoreCount; - const VkSemaphore * pWaitSemaphores; - const VkPipelineStageFlags * pWaitDstStageMask; - uint32_t commandBufferCount; - const VkCommandBuffer * pCommandBuffers; - uint32_t signalSemaphoreCount; - const VkSemaphore * pSignalSemaphores; -} VkSubmitInfo; - -typedef struct VkDisplayPropertiesKHR { - VkDisplayKHR display; - const char * displayName; - VkExtent2D physicalDimensions; - VkExtent2D physicalResolution; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkBool32 planeReorderPossible; - VkBool32 persistentContent; -} VkDisplayPropertiesKHR; + const void * pNext; + VkHeadlessSurfaceCreateFlagsEXT flags; +} VkHeadlessSurfaceCreateInfoEXT; -typedef struct VkDisplayModeCreateInfoKHR { +typedef struct VkPhysicalDeviceCoverageReductionModeFeaturesNV { VkStructureType sType; - const void * pNext; - VkDisplayModeCreateFlagsKHR flags; - VkDisplayModeParametersKHR parameters; -} VkDisplayModeCreateInfoKHR; + void * pNext; + VkBool32 coverageReductionMode; +} VkPhysicalDeviceCoverageReductionModeFeaturesNV; -typedef struct VkDisplayPlaneCapabilitiesKHR { - VkDisplayPlaneAlphaFlagsKHR supportedAlpha; - VkOffset2D minSrcPosition; - VkOffset2D maxSrcPosition; - VkExtent2D minSrcExtent; - VkExtent2D maxSrcExtent; - VkOffset2D minDstPosition; - VkOffset2D maxDstPosition; - VkExtent2D minDstExtent; - VkExtent2D maxDstExtent; -} VkDisplayPlaneCapabilitiesKHR; +typedef struct VkPipelineCoverageReductionStateCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkPipelineCoverageReductionStateCreateFlagsNV flags; + VkCoverageReductionModeNV coverageReductionMode; +} VkPipelineCoverageReductionStateCreateInfoNV; -typedef struct VkDisplaySurfaceCreateInfoKHR { +typedef struct VkFramebufferMixedSamplesCombinationNV { VkStructureType sType; - const void * pNext; - VkDisplaySurfaceCreateFlagsKHR flags; - VkDisplayModeKHR displayMode; - uint32_t planeIndex; - uint32_t planeStackIndex; - VkSurfaceTransformFlagBitsKHR transform; - float globalAlpha; - VkDisplayPlaneAlphaFlagBitsKHR alphaMode; - VkExtent2D imageExtent; -} VkDisplaySurfaceCreateInfoKHR; + void * pNext; + VkCoverageReductionModeNV coverageReductionMode; + VkSampleCountFlagBits rasterizationSamples; + VkSampleCountFlags depthStencilSamples; + VkSampleCountFlags colorSamples; +} VkFramebufferMixedSamplesCombinationNV; -typedef struct VkDisplayPresentInfoKHR { +typedef struct VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL { VkStructureType sType; - const void * pNext; - VkRect2D srcRect; - VkRect2D dstRect; - VkBool32 persistent; -} VkDisplayPresentInfoKHR; + void * pNext; + VkBool32 shaderIntegerFunctions2; +} VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL; -typedef struct VkSurfaceCapabilitiesKHR { - uint32_t minImageCount; - uint32_t maxImageCount; - VkExtent2D currentExtent; - VkExtent2D minImageExtent; - VkExtent2D maxImageExtent; - uint32_t maxImageArrayLayers; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkSurfaceTransformFlagBitsKHR currentTransform; - VkCompositeAlphaFlagsKHR supportedCompositeAlpha; - VkImageUsageFlags supportedUsageFlags; -} VkSurfaceCapabilitiesKHR; +typedef union VkPerformanceValueDataINTEL { + uint32_t value32; + uint64_t value64; + float valueFloat; + VkBool32 valueBool; + const char * valueString; +} VkPerformanceValueDataINTEL; -#if defined(VK_USE_PLATFORM_ANDROID_KHR) -typedef struct VkAndroidSurfaceCreateInfoKHR { - VkStructureType sType; - const void * pNext; - VkAndroidSurfaceCreateFlagsKHR flags; - struct ANativeWindow * window; -} VkAndroidSurfaceCreateInfoKHR; -#endif +typedef struct VkPerformanceValueINTEL { + VkPerformanceValueTypeINTEL type; + VkPerformanceValueDataINTEL data; +} VkPerformanceValueINTEL; -#if defined(VK_USE_PLATFORM_VI_NN) -typedef struct VkViSurfaceCreateInfoNN { +typedef struct VkPerformanceOverrideInfoINTEL { VkStructureType sType; - const void * pNext; - VkViSurfaceCreateFlagsNN flags; - void * window; -} VkViSurfaceCreateInfoNN; -#endif + const void * pNext; + VkPerformanceOverrideTypeINTEL type; + VkBool32 enable; + uint64_t parameter; +} VkPerformanceOverrideInfoINTEL; -#if defined(VK_USE_PLATFORM_WAYLAND_KHR) -typedef struct VkWaylandSurfaceCreateInfoKHR { +typedef struct VkPhysicalDeviceShaderClockFeaturesKHR { VkStructureType sType; - const void * pNext; - VkWaylandSurfaceCreateFlagsKHR flags; - struct wl_display * display; - struct wl_surface * surface; -} VkWaylandSurfaceCreateInfoKHR; -#endif + void * pNext; + VkBool32 shaderSubgroupClock; + VkBool32 shaderDeviceClock; +} VkPhysicalDeviceShaderClockFeaturesKHR; -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkWin32SurfaceCreateInfoKHR { +typedef struct VkPhysicalDeviceIndexTypeUint8Features { VkStructureType sType; - const void * pNext; - VkWin32SurfaceCreateFlagsKHR flags; - HINSTANCE hinstance; - HWND hwnd; -} VkWin32SurfaceCreateInfoKHR; -#endif + void * pNext; + VkBool32 indexTypeUint8; +} VkPhysicalDeviceIndexTypeUint8Features; -#if defined(VK_USE_PLATFORM_XLIB_KHR) -typedef struct VkXlibSurfaceCreateInfoKHR { +typedef struct VkPhysicalDeviceIndexTypeUint8Features VkPhysicalDeviceIndexTypeUint8FeaturesKHR; + +typedef struct VkPhysicalDeviceIndexTypeUint8Features VkPhysicalDeviceIndexTypeUint8FeaturesEXT; + +typedef struct VkPhysicalDeviceShaderSMBuiltinsFeaturesNV { VkStructureType sType; - const void * pNext; - VkXlibSurfaceCreateFlagsKHR flags; - Display * dpy; - Window window; -} VkXlibSurfaceCreateInfoKHR; -#endif + void * pNext; + VkBool32 shaderSMBuiltins; +} VkPhysicalDeviceShaderSMBuiltinsFeaturesNV; -#if defined(VK_USE_PLATFORM_XCB_KHR) -typedef struct VkXcbSurfaceCreateInfoKHR { +typedef struct VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT { VkStructureType sType; - const void * pNext; - VkXcbSurfaceCreateFlagsKHR flags; - xcb_connection_t * connection; - xcb_window_t window; -} VkXcbSurfaceCreateInfoKHR; -#endif + void * pNext; + VkBool32 fragmentShaderSampleInterlock; + VkBool32 fragmentShaderPixelInterlock; + VkBool32 fragmentShaderShadingRateInterlock; +} VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT; -#if defined(VK_USE_PLATFORM_DIRECTFB_EXT) -typedef struct VkDirectFBSurfaceCreateInfoEXT { +typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures { VkStructureType sType; - const void * pNext; - VkDirectFBSurfaceCreateFlagsEXT flags; - IDirectFB * dfb; - IDirectFBSurface * surface; -} VkDirectFBSurfaceCreateInfoEXT; -#endif + void * pNext; + VkBool32 separateDepthStencilLayouts; +} VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures; -#if defined(VK_USE_PLATFORM_FUCHSIA) -typedef struct VkImagePipeSurfaceCreateInfoFUCHSIA { +typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR; + +typedef struct VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT { VkStructureType sType; - const void * pNext; - VkImagePipeSurfaceCreateFlagsFUCHSIA flags; - zx_handle_t imagePipeHandle; -} VkImagePipeSurfaceCreateInfoFUCHSIA; -#endif + void * pNext; + VkBool32 primitiveTopologyListRestart; + VkBool32 primitiveTopologyPatchListRestart; +} VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT; -#if defined(VK_USE_PLATFORM_GGP) -typedef struct VkStreamDescriptorSurfaceCreateInfoGGP { +typedef struct VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR { VkStructureType sType; - const void * pNext; - VkStreamDescriptorSurfaceCreateFlagsGGP flags; - GgpStreamDescriptor streamDescriptor; -} VkStreamDescriptorSurfaceCreateInfoGGP; -#endif + void * pNext; + VkBool32 pipelineExecutableInfo; +} VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR; -typedef struct VkSwapchainCreateInfoKHR { +typedef struct VkPipelineExecutablePropertiesKHR { VkStructureType sType; - const void * pNext; - VkSwapchainCreateFlagsKHR flags; - VkSurfaceKHR surface; - uint32_t minImageCount; - VkFormat imageFormat; - VkColorSpaceKHR imageColorSpace; - VkExtent2D imageExtent; - uint32_t imageArrayLayers; - VkImageUsageFlags imageUsage; - VkSharingMode imageSharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t * pQueueFamilyIndices; - VkSurfaceTransformFlagBitsKHR preTransform; - VkCompositeAlphaFlagBitsKHR compositeAlpha; - VkPresentModeKHR presentMode; - VkBool32 clipped; - VkSwapchainKHR oldSwapchain; -} VkSwapchainCreateInfoKHR; + void * pNext; + VkShaderStageFlags stages; + char name [ VK_MAX_DESCRIPTION_SIZE ]; + char description [ VK_MAX_DESCRIPTION_SIZE ]; + uint32_t subgroupSize; +} VkPipelineExecutablePropertiesKHR; -typedef struct VkDebugReportCallbackCreateInfoEXT { +typedef union VkPipelineExecutableStatisticValueKHR { + VkBool32 b32; + int64_t i64; + uint64_t u64; + double f64; +} VkPipelineExecutableStatisticValueKHR; + +typedef struct VkPipelineExecutableStatisticKHR { VkStructureType sType; - const void * pNext; - VkDebugReportFlagsEXT flags; - PFN_vkDebugReportCallbackEXT pfnCallback; - void * pUserData; -} VkDebugReportCallbackCreateInfoEXT; + void * pNext; + char name [ VK_MAX_DESCRIPTION_SIZE ]; + char description [ VK_MAX_DESCRIPTION_SIZE ]; + VkPipelineExecutableStatisticFormatKHR format; + VkPipelineExecutableStatisticValueKHR value; +} VkPipelineExecutableStatisticKHR; -typedef struct VkDedicatedAllocationImageCreateInfoNV { +typedef struct VkPipelineExecutableInternalRepresentationKHR { VkStructureType sType; - const void * pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationImageCreateInfoNV; + void * pNext; + char name [ VK_MAX_DESCRIPTION_SIZE ]; + char description [ VK_MAX_DESCRIPTION_SIZE ]; + VkBool32 isText; + size_t dataSize; + void * pData; +} VkPipelineExecutableInternalRepresentationKHR; -typedef struct VkDedicatedAllocationBufferCreateInfoNV { +typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures { VkStructureType sType; - const void * pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationBufferCreateInfoNV; + void * pNext; + VkBool32 shaderDemoteToHelperInvocation; +} VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures; -typedef struct VkExternalImageFormatPropertiesNV { - VkImageFormatProperties imageFormatProperties; - VkExternalMemoryFeatureFlagsNV externalMemoryFeatures; - VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes; - VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes; -} VkExternalImageFormatPropertiesNV; +typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT; -typedef struct VkExternalMemoryImageCreateInfoNV { +typedef struct VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT { VkStructureType sType; - const void * pNext; - VkExternalMemoryHandleTypeFlagsNV handleTypes; -} VkExternalMemoryImageCreateInfoNV; + void * pNext; + VkBool32 texelBufferAlignment; +} VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT; -typedef struct VkExportMemoryAllocateInfoNV { +typedef struct VkPhysicalDeviceTexelBufferAlignmentProperties { VkStructureType sType; - const void * pNext; - VkExternalMemoryHandleTypeFlagsNV handleTypes; -} VkExportMemoryAllocateInfoNV; + void * pNext; + VkDeviceSize storageTexelBufferOffsetAlignmentBytes; + VkBool32 storageTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; + VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; +} VkPhysicalDeviceTexelBufferAlignmentProperties; -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkImportMemoryWin32HandleInfoNV { +typedef struct VkPhysicalDeviceTexelBufferAlignmentProperties VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT; + +typedef struct VkPhysicalDeviceSubgroupSizeControlFeatures { VkStructureType sType; - const void * pNext; - VkExternalMemoryHandleTypeFlagsNV handleType; - HANDLE handle; -} VkImportMemoryWin32HandleInfoNV; -#endif + void * pNext; + VkBool32 subgroupSizeControl; + VkBool32 computeFullSubgroups; +} VkPhysicalDeviceSubgroupSizeControlFeatures; -typedef struct VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV { - VkStructureType sType; - void * pNext; - VkBool32 deviceGeneratedCommands; -} VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV; +typedef struct VkPhysicalDeviceSubgroupSizeControlFeatures VkPhysicalDeviceSubgroupSizeControlFeaturesEXT; -typedef struct VkPrivateDataSlotCreateInfoEXT { +typedef struct VkPhysicalDeviceSubgroupSizeControlProperties { VkStructureType sType; - const void * pNext; - VkPrivateDataSlotCreateFlagsEXT flags; -} VkPrivateDataSlotCreateInfoEXT; + void * pNext; + uint32_t minSubgroupSize; + uint32_t maxSubgroupSize; + uint32_t maxComputeWorkgroupSubgroups; + VkShaderStageFlags requiredSubgroupSizeStages; +} VkPhysicalDeviceSubgroupSizeControlProperties; -typedef struct VkPhysicalDevicePrivateDataFeaturesEXT { - VkStructureType sType; - void * pNext; - VkBool32 privateData; -} VkPhysicalDevicePrivateDataFeaturesEXT; +typedef struct VkPhysicalDeviceSubgroupSizeControlProperties VkPhysicalDeviceSubgroupSizeControlPropertiesEXT; -typedef struct VkGraphicsShaderGroupCreateInfoNV { +typedef struct VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI { VkStructureType sType; - const void * pNext; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo * pStages; - const VkPipelineVertexInputStateCreateInfo * pVertexInputState; - const VkPipelineTessellationStateCreateInfo * pTessellationState; -} VkGraphicsShaderGroupCreateInfoNV; + void * pNext; + uint32_t maxWorkGroupCount [3]; + uint32_t maxWorkGroupSize [3]; + uint32_t maxOutputClusterCount; + VkDeviceSize indirectBufferOffsetAlignment; +} VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI; -typedef struct VkGraphicsPipelineShaderGroupsCreateInfoNV { +typedef struct VkPhysicalDeviceLineRasterizationFeatures { VkStructureType sType; - const void * pNext; - uint32_t groupCount; - const VkGraphicsShaderGroupCreateInfoNV * pGroups; - uint32_t pipelineCount; - const VkPipeline * pPipelines; -} VkGraphicsPipelineShaderGroupsCreateInfoNV; - -typedef struct VkBindIndexBufferIndirectCommandNV { - VkDeviceAddress bufferAddress; - uint32_t size; - VkIndexType indexType; -} VkBindIndexBufferIndirectCommandNV; + void * pNext; + VkBool32 rectangularLines; + VkBool32 bresenhamLines; + VkBool32 smoothLines; + VkBool32 stippledRectangularLines; + VkBool32 stippledBresenhamLines; + VkBool32 stippledSmoothLines; +} VkPhysicalDeviceLineRasterizationFeatures; -typedef struct VkBindVertexBufferIndirectCommandNV { - VkDeviceAddress bufferAddress; - uint32_t size; - uint32_t stride; -} VkBindVertexBufferIndirectCommandNV; +typedef struct VkPhysicalDeviceLineRasterizationFeatures VkPhysicalDeviceLineRasterizationFeaturesKHR; -typedef struct VkIndirectCommandsStreamNV { - VkBuffer buffer; - VkDeviceSize offset; -} VkIndirectCommandsStreamNV; +typedef struct VkPhysicalDeviceLineRasterizationFeatures VkPhysicalDeviceLineRasterizationFeaturesEXT; -typedef struct VkIndirectCommandsLayoutTokenNV { +typedef struct VkPipelineRasterizationLineStateCreateInfo { VkStructureType sType; - const void * pNext; - VkIndirectCommandsTokenTypeNV tokenType; - uint32_t stream; - uint32_t offset; - uint32_t vertexBindingUnit; - VkBool32 vertexDynamicStride; - VkPipelineLayout pushconstantPipelineLayout; - VkShaderStageFlags pushconstantShaderStageFlags; - uint32_t pushconstantOffset; - uint32_t pushconstantSize; - VkIndirectStateFlagsNV indirectStateFlags; - uint32_t indexTypeCount; - const VkIndexType * pIndexTypes; - const uint32_t * pIndexTypeValues; -} VkIndirectCommandsLayoutTokenNV; + const void * pNext; + VkLineRasterizationMode lineRasterizationMode; + VkBool32 stippledLineEnable; + uint32_t lineStippleFactor; + uint16_t lineStipplePattern; +} VkPipelineRasterizationLineStateCreateInfo; -typedef struct VkIndirectCommandsLayoutCreateInfoNV { - VkStructureType sType; - const void * pNext; - VkIndirectCommandsLayoutUsageFlagsNV flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t tokenCount; - const VkIndirectCommandsLayoutTokenNV * pTokens; - uint32_t streamCount; - const uint32_t * pStreamStrides; -} VkIndirectCommandsLayoutCreateInfoNV; +typedef struct VkPipelineRasterizationLineStateCreateInfo VkPipelineRasterizationLineStateCreateInfoKHR; -typedef struct VkGeneratedCommandsInfoNV { - VkStructureType sType; - const void * pNext; - VkPipelineBindPoint pipelineBindPoint; - VkPipeline pipeline; - VkIndirectCommandsLayoutNV indirectCommandsLayout; - uint32_t streamCount; - const VkIndirectCommandsStreamNV * pStreams; - uint32_t sequencesCount; - VkBuffer preprocessBuffer; - VkDeviceSize preprocessOffset; - VkDeviceSize preprocessSize; - VkBuffer sequencesCountBuffer; - VkDeviceSize sequencesCountOffset; - VkBuffer sequencesIndexBuffer; - VkDeviceSize sequencesIndexOffset; -} VkGeneratedCommandsInfoNV; +typedef struct VkPipelineRasterizationLineStateCreateInfo VkPipelineRasterizationLineStateCreateInfoEXT; -typedef struct VkPhysicalDeviceFeatures2 { +typedef struct VkPhysicalDevicePipelineCreationCacheControlFeatures { VkStructureType sType; - void * pNext; - VkPhysicalDeviceFeatures features; -} VkPhysicalDeviceFeatures2; + void * pNext; + VkBool32 pipelineCreationCacheControl; +} VkPhysicalDevicePipelineCreationCacheControlFeatures; -typedef struct VkPhysicalDeviceFeatures2 VkPhysicalDeviceFeatures2KHR; +typedef struct VkPhysicalDevicePipelineCreationCacheControlFeatures VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT; -typedef struct VkFormatProperties2 { +typedef struct VkPhysicalDeviceVulkan11Features { VkStructureType sType; - void * pNext; - VkFormatProperties formatProperties; -} VkFormatProperties2; - -typedef struct VkFormatProperties2 VkFormatProperties2KHR; + void * pNext; + VkBool32 storageBuffer16BitAccess; + VkBool32 uniformAndStorageBuffer16BitAccess; + VkBool32 storagePushConstant16; + VkBool32 storageInputOutput16; + VkBool32 multiview; + VkBool32 multiviewGeometryShader; + VkBool32 multiviewTessellationShader; + VkBool32 variablePointersStorageBuffer; + VkBool32 variablePointers; + VkBool32 protectedMemory; + VkBool32 samplerYcbcrConversion; + VkBool32 shaderDrawParameters; +} VkPhysicalDeviceVulkan11Features; -typedef struct VkImageFormatProperties2 { +typedef struct VkPhysicalDeviceVulkan11Properties { VkStructureType sType; - void * pNext; - VkImageFormatProperties imageFormatProperties; -} VkImageFormatProperties2; - -typedef struct VkImageFormatProperties2 VkImageFormatProperties2KHR; + void * pNext; + uint8_t deviceUUID [ VK_UUID_SIZE ]; + uint8_t driverUUID [ VK_UUID_SIZE ]; + uint8_t deviceLUID [ VK_LUID_SIZE ]; + uint32_t deviceNodeMask; + VkBool32 deviceLUIDValid; + uint32_t subgroupSize; + VkShaderStageFlags subgroupSupportedStages; + VkSubgroupFeatureFlags subgroupSupportedOperations; + VkBool32 subgroupQuadOperationsInAllStages; + VkPointClippingBehavior pointClippingBehavior; + uint32_t maxMultiviewViewCount; + uint32_t maxMultiviewInstanceIndex; + VkBool32 protectedNoFault; + uint32_t maxPerSetDescriptors; + VkDeviceSize maxMemoryAllocationSize; +} VkPhysicalDeviceVulkan11Properties; -typedef struct VkPhysicalDeviceImageFormatInfo2 { +typedef struct VkPhysicalDeviceVulkan12Features { VkStructureType sType; - const void * pNext; - VkFormat format; - VkImageType type; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkImageCreateFlags flags; -} VkPhysicalDeviceImageFormatInfo2; + void * pNext; + VkBool32 samplerMirrorClampToEdge; + VkBool32 drawIndirectCount; + VkBool32 storageBuffer8BitAccess; + VkBool32 uniformAndStorageBuffer8BitAccess; + VkBool32 storagePushConstant8; + VkBool32 shaderBufferInt64Atomics; + VkBool32 shaderSharedInt64Atomics; + VkBool32 shaderFloat16; + VkBool32 shaderInt8; + VkBool32 descriptorIndexing; + VkBool32 shaderInputAttachmentArrayDynamicIndexing; + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; + VkBool32 shaderUniformBufferArrayNonUniformIndexing; + VkBool32 shaderSampledImageArrayNonUniformIndexing; + VkBool32 shaderStorageBufferArrayNonUniformIndexing; + VkBool32 shaderStorageImageArrayNonUniformIndexing; + VkBool32 shaderInputAttachmentArrayNonUniformIndexing; + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; + VkBool32 descriptorBindingUniformBufferUpdateAfterBind; + VkBool32 descriptorBindingSampledImageUpdateAfterBind; + VkBool32 descriptorBindingStorageImageUpdateAfterBind; + VkBool32 descriptorBindingStorageBufferUpdateAfterBind; + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; + VkBool32 descriptorBindingUpdateUnusedWhilePending; + VkBool32 descriptorBindingPartiallyBound; + VkBool32 descriptorBindingVariableDescriptorCount; + VkBool32 runtimeDescriptorArray; + VkBool32 samplerFilterMinmax; + VkBool32 scalarBlockLayout; + VkBool32 imagelessFramebuffer; + VkBool32 uniformBufferStandardLayout; + VkBool32 shaderSubgroupExtendedTypes; + VkBool32 separateDepthStencilLayouts; + VkBool32 hostQueryReset; + VkBool32 timelineSemaphore; + VkBool32 bufferDeviceAddress; + VkBool32 bufferDeviceAddressCaptureReplay; + VkBool32 bufferDeviceAddressMultiDevice; + VkBool32 vulkanMemoryModel; + VkBool32 vulkanMemoryModelDeviceScope; + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; + VkBool32 shaderOutputViewportIndex; + VkBool32 shaderOutputLayer; + VkBool32 subgroupBroadcastDynamicId; +} VkPhysicalDeviceVulkan12Features; -typedef struct VkPhysicalDeviceImageFormatInfo2 VkPhysicalDeviceImageFormatInfo2KHR; +typedef struct VkPhysicalDeviceVulkan12Properties { + VkStructureType sType; + void * pNext; + VkDriverId driverID; + char driverName [ VK_MAX_DRIVER_NAME_SIZE ]; + char driverInfo [ VK_MAX_DRIVER_INFO_SIZE ]; + VkConformanceVersion conformanceVersion; + VkShaderFloatControlsIndependence denormBehaviorIndependence; + VkShaderFloatControlsIndependence roundingModeIndependence; + VkBool32 shaderSignedZeroInfNanPreserveFloat16; + VkBool32 shaderSignedZeroInfNanPreserveFloat32; + VkBool32 shaderSignedZeroInfNanPreserveFloat64; + VkBool32 shaderDenormPreserveFloat16; + VkBool32 shaderDenormPreserveFloat32; + VkBool32 shaderDenormPreserveFloat64; + VkBool32 shaderDenormFlushToZeroFloat16; + VkBool32 shaderDenormFlushToZeroFloat32; + VkBool32 shaderDenormFlushToZeroFloat64; + VkBool32 shaderRoundingModeRTEFloat16; + VkBool32 shaderRoundingModeRTEFloat32; + VkBool32 shaderRoundingModeRTEFloat64; + VkBool32 shaderRoundingModeRTZFloat16; + VkBool32 shaderRoundingModeRTZFloat32; + VkBool32 shaderRoundingModeRTZFloat64; + uint32_t maxUpdateAfterBindDescriptorsInAllPools; + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; + VkBool32 shaderSampledImageArrayNonUniformIndexingNative; + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; + VkBool32 shaderStorageImageArrayNonUniformIndexingNative; + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; + VkBool32 robustBufferAccessUpdateAfterBind; + VkBool32 quadDivergentImplicitLod; + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; + uint32_t maxPerStageUpdateAfterBindResources; + uint32_t maxDescriptorSetUpdateAfterBindSamplers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + uint32_t maxDescriptorSetUpdateAfterBindSampledImages; + uint32_t maxDescriptorSetUpdateAfterBindStorageImages; + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; + VkResolveModeFlags supportedDepthResolveModes; + VkResolveModeFlags supportedStencilResolveModes; + VkBool32 independentResolveNone; + VkBool32 independentResolve; + VkBool32 filterMinmaxSingleComponentFormats; + VkBool32 filterMinmaxImageComponentMapping; + uint64_t maxTimelineSemaphoreValueDifference; + VkSampleCountFlags framebufferIntegerColorSampleCounts; +} VkPhysicalDeviceVulkan12Properties; -typedef struct VkQueueFamilyProperties2 { +typedef struct VkPhysicalDeviceVulkan13Features { VkStructureType sType; - void * pNext; - VkQueueFamilyProperties queueFamilyProperties; -} VkQueueFamilyProperties2; + void * pNext; + VkBool32 robustImageAccess; + VkBool32 inlineUniformBlock; + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; + VkBool32 pipelineCreationCacheControl; + VkBool32 privateData; + VkBool32 shaderDemoteToHelperInvocation; + VkBool32 shaderTerminateInvocation; + VkBool32 subgroupSizeControl; + VkBool32 computeFullSubgroups; + VkBool32 synchronization2; + VkBool32 textureCompressionASTC_HDR; + VkBool32 shaderZeroInitializeWorkgroupMemory; + VkBool32 dynamicRendering; + VkBool32 shaderIntegerDotProduct; + VkBool32 maintenance4; +} VkPhysicalDeviceVulkan13Features; + +typedef struct VkPhysicalDeviceVulkan13Properties { + VkStructureType sType; + void * pNext; + uint32_t minSubgroupSize; + uint32_t maxSubgroupSize; + uint32_t maxComputeWorkgroupSubgroups; + VkShaderStageFlags requiredSubgroupSizeStages; + uint32_t maxInlineUniformBlockSize; + uint32_t maxPerStageDescriptorInlineUniformBlocks; + uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; + uint32_t maxDescriptorSetInlineUniformBlocks; + uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; + uint32_t maxInlineUniformTotalSize; + VkBool32 integerDotProduct8BitUnsignedAccelerated; + VkBool32 integerDotProduct8BitSignedAccelerated; + VkBool32 integerDotProduct8BitMixedSignednessAccelerated; + VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProduct16BitUnsignedAccelerated; + VkBool32 integerDotProduct16BitSignedAccelerated; + VkBool32 integerDotProduct16BitMixedSignednessAccelerated; + VkBool32 integerDotProduct32BitUnsignedAccelerated; + VkBool32 integerDotProduct32BitSignedAccelerated; + VkBool32 integerDotProduct32BitMixedSignednessAccelerated; + VkBool32 integerDotProduct64BitUnsignedAccelerated; + VkBool32 integerDotProduct64BitSignedAccelerated; + VkBool32 integerDotProduct64BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; + VkDeviceSize storageTexelBufferOffsetAlignmentBytes; + VkBool32 storageTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; + VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; + VkDeviceSize maxBufferSize; +} VkPhysicalDeviceVulkan13Properties; + +typedef struct VkPhysicalDeviceVulkan14Features { + VkStructureType sType; + void * pNext; + VkBool32 globalPriorityQuery; + VkBool32 shaderSubgroupRotate; + VkBool32 shaderSubgroupRotateClustered; + VkBool32 shaderFloatControls2; + VkBool32 shaderExpectAssume; + VkBool32 rectangularLines; + VkBool32 bresenhamLines; + VkBool32 smoothLines; + VkBool32 stippledRectangularLines; + VkBool32 stippledBresenhamLines; + VkBool32 stippledSmoothLines; + VkBool32 vertexAttributeInstanceRateDivisor; + VkBool32 vertexAttributeInstanceRateZeroDivisor; + VkBool32 indexTypeUint8; + VkBool32 dynamicRenderingLocalRead; + VkBool32 maintenance5; + VkBool32 maintenance6; + VkBool32 pipelineProtectedAccess; + VkBool32 pipelineRobustness; + VkBool32 hostImageCopy; + VkBool32 pushDescriptor; +} VkPhysicalDeviceVulkan14Features; + +typedef struct VkPhysicalDeviceVulkan14Properties { + VkStructureType sType; + void * pNext; + uint32_t lineSubPixelPrecisionBits; + uint32_t maxVertexAttribDivisor; + VkBool32 supportsNonZeroFirstInstance; + uint32_t maxPushDescriptors; + VkBool32 dynamicRenderingLocalReadDepthStencilAttachments; + VkBool32 dynamicRenderingLocalReadMultisampledAttachments; + VkBool32 earlyFragmentMultisampleCoverageAfterSampleCounting; + VkBool32 earlyFragmentSampleMaskTestBeforeSampleCounting; + VkBool32 depthStencilSwizzleOneSupport; + VkBool32 polygonModePointSize; + VkBool32 nonStrictSinglePixelWideLinesUseParallelogram; + VkBool32 nonStrictWideLinesUseParallelogram; + VkBool32 blockTexelViewCompatibleMultipleLayers; + uint32_t maxCombinedImageSamplerDescriptorCount; + VkBool32 fragmentShadingRateClampCombinerInputs; + VkPipelineRobustnessBufferBehavior defaultRobustnessStorageBuffers; + VkPipelineRobustnessBufferBehavior defaultRobustnessUniformBuffers; + VkPipelineRobustnessBufferBehavior defaultRobustnessVertexInputs; + VkPipelineRobustnessImageBehavior defaultRobustnessImages; + uint32_t copySrcLayoutCount; + VkImageLayout * pCopySrcLayouts; + uint32_t copyDstLayoutCount; + VkImageLayout * pCopyDstLayouts; + uint8_t optimalTilingLayoutUUID [ VK_UUID_SIZE ]; + VkBool32 identicalMemoryTypeRequirements; +} VkPhysicalDeviceVulkan14Properties; -typedef struct VkQueueFamilyProperties2 VkQueueFamilyProperties2KHR; +typedef struct VkPipelineCompilerControlCreateInfoAMD { + VkStructureType sType; + const void * pNext; + VkPipelineCompilerControlFlagsAMD compilerControlFlags; +} VkPipelineCompilerControlCreateInfoAMD; -typedef struct VkSparseImageFormatProperties2 { +typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD { VkStructureType sType; - void * pNext; - VkSparseImageFormatProperties properties; -} VkSparseImageFormatProperties2; - -typedef struct VkSparseImageFormatProperties2 VkSparseImageFormatProperties2KHR; + void * pNext; + VkBool32 deviceCoherentMemory; +} VkPhysicalDeviceCoherentMemoryFeaturesAMD; -typedef struct VkPhysicalDeviceSparseImageFormatInfo2 { +typedef struct VkPhysicalDeviceToolProperties { VkStructureType sType; - const void * pNext; - VkFormat format; - VkImageType type; - VkSampleCountFlagBits samples; - VkImageUsageFlags usage; - VkImageTiling tiling; -} VkPhysicalDeviceSparseImageFormatInfo2; + void * pNext; + char name [ VK_MAX_EXTENSION_NAME_SIZE ]; + char version [ VK_MAX_EXTENSION_NAME_SIZE ]; + VkToolPurposeFlags purposes; + char description [ VK_MAX_DESCRIPTION_SIZE ]; + char layer [ VK_MAX_EXTENSION_NAME_SIZE ]; +} VkPhysicalDeviceToolProperties; -typedef struct VkPhysicalDeviceSparseImageFormatInfo2 VkPhysicalDeviceSparseImageFormatInfo2KHR; +typedef struct VkPhysicalDeviceToolProperties VkPhysicalDeviceToolPropertiesEXT; -typedef struct VkPresentRegionKHR { - uint32_t rectangleCount; - const VkRectLayerKHR * pRectangles; -} VkPresentRegionKHR; +typedef struct VkPhysicalDeviceCustomBorderColorFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 customBorderColors; + VkBool32 customBorderColorWithoutFormat; +} VkPhysicalDeviceCustomBorderColorFeaturesEXT; -typedef struct VkPhysicalDeviceVariablePointersFeatures { +typedef struct VkSamplerBorderColorComponentMappingCreateInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 variablePointersStorageBuffer; - VkBool32 variablePointers; -} VkPhysicalDeviceVariablePointersFeatures; + const void * pNext; + VkComponentMapping components; + VkBool32 srgb; +} VkSamplerBorderColorComponentMappingCreateInfoEXT; -typedef struct VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointersFeaturesKHR; +typedef struct VkPhysicalDeviceBorderColorSwizzleFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 borderColorSwizzle; + VkBool32 borderColorSwizzleFromImage; +} VkPhysicalDeviceBorderColorSwizzleFeaturesEXT; -typedef struct VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeaturesKHR; +typedef union VkDeviceOrHostAddressKHR { + VkDeviceAddress deviceAddress; + void * hostAddress; +} VkDeviceOrHostAddressKHR; -typedef struct VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeatures; +typedef union VkDeviceOrHostAddressConstKHR { + VkDeviceAddress deviceAddress; + const void * hostAddress; +} VkDeviceOrHostAddressConstKHR; -typedef struct VkExternalMemoryProperties { - VkExternalMemoryFeatureFlags externalMemoryFeatures; - VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes; - VkExternalMemoryHandleTypeFlags compatibleHandleTypes; -} VkExternalMemoryProperties; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef union VkDeviceOrHostAddressConstAMDX { + VkDeviceAddress deviceAddress; + const void * hostAddress; +} VkDeviceOrHostAddressConstAMDX; -typedef struct VkExternalMemoryProperties VkExternalMemoryPropertiesKHR; +#endif -typedef struct VkExternalImageFormatProperties { +typedef struct VkAccelerationStructureGeometryTrianglesDataKHR { VkStructureType sType; - void * pNext; - VkExternalMemoryProperties externalMemoryProperties; -} VkExternalImageFormatProperties; - -typedef struct VkExternalImageFormatProperties VkExternalImageFormatPropertiesKHR; + const void * pNext; + VkFormat vertexFormat; + VkDeviceOrHostAddressConstKHR vertexData; + VkDeviceSize vertexStride; + uint32_t maxVertex; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexData; + VkDeviceOrHostAddressConstKHR transformData; +} VkAccelerationStructureGeometryTrianglesDataKHR; -typedef struct VkPhysicalDeviceExternalBufferInfo { +typedef struct VkAccelerationStructureGeometryAabbsDataKHR { VkStructureType sType; - const void * pNext; - VkBufferCreateFlags flags; - VkBufferUsageFlags usage; - VkExternalMemoryHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalBufferInfo; + const void * pNext; + VkDeviceOrHostAddressConstKHR data; + VkDeviceSize stride; +} VkAccelerationStructureGeometryAabbsDataKHR; -typedef struct VkPhysicalDeviceExternalBufferInfo VkPhysicalDeviceExternalBufferInfoKHR; +typedef struct VkAccelerationStructureGeometryInstancesDataKHR { + VkStructureType sType; + const void * pNext; + VkBool32 arrayOfPointers; + VkDeviceOrHostAddressConstKHR data; +} VkAccelerationStructureGeometryInstancesDataKHR; -typedef struct VkExternalBufferProperties { +typedef struct VkAccelerationStructureGeometryLinearSweptSpheresDataNV { VkStructureType sType; - void * pNext; - VkExternalMemoryProperties externalMemoryProperties; -} VkExternalBufferProperties; + const void * pNext; + VkFormat vertexFormat; + VkDeviceOrHostAddressConstKHR vertexData; + VkDeviceSize vertexStride; + VkFormat radiusFormat; + VkDeviceOrHostAddressConstKHR radiusData; + VkDeviceSize radiusStride; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexData; + VkDeviceSize indexStride; + VkRayTracingLssIndexingModeNV indexingMode; + VkRayTracingLssPrimitiveEndCapsModeNV endCapsMode; +} VkAccelerationStructureGeometryLinearSweptSpheresDataNV; + +typedef struct VkAccelerationStructureGeometrySpheresDataNV { + VkStructureType sType; + const void * pNext; + VkFormat vertexFormat; + VkDeviceOrHostAddressConstKHR vertexData; + VkDeviceSize vertexStride; + VkFormat radiusFormat; + VkDeviceOrHostAddressConstKHR radiusData; + VkDeviceSize radiusStride; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexData; + VkDeviceSize indexStride; +} VkAccelerationStructureGeometrySpheresDataNV; -typedef struct VkExternalBufferProperties VkExternalBufferPropertiesKHR; +typedef union VkAccelerationStructureGeometryDataKHR { + VkAccelerationStructureGeometryTrianglesDataKHR triangles; + VkAccelerationStructureGeometryAabbsDataKHR aabbs; + VkAccelerationStructureGeometryInstancesDataKHR instances; +} VkAccelerationStructureGeometryDataKHR; -typedef struct VkPhysicalDeviceIDProperties { +typedef struct VkAccelerationStructureGeometryKHR { VkStructureType sType; - void * pNext; - uint8_t deviceUUID [ VK_UUID_SIZE ]; - uint8_t driverUUID [ VK_UUID_SIZE ]; - uint8_t deviceLUID [ VK_LUID_SIZE ]; - uint32_t deviceNodeMask; - VkBool32 deviceLUIDValid; -} VkPhysicalDeviceIDProperties; + const void * pNext; + VkGeometryTypeKHR geometryType; + VkAccelerationStructureGeometryDataKHR geometry; + VkGeometryFlagsKHR flags; +} VkAccelerationStructureGeometryKHR; -typedef struct VkPhysicalDeviceIDProperties VkPhysicalDeviceIDPropertiesKHR; +typedef struct VkAccelerationStructureBuildGeometryInfoKHR { + VkStructureType sType; + const void * pNext; + VkAccelerationStructureTypeKHR type; + VkBuildAccelerationStructureFlagsKHR flags; + VkBuildAccelerationStructureModeKHR mode; + VkAccelerationStructureKHR srcAccelerationStructure; + VkAccelerationStructureKHR dstAccelerationStructure; + uint32_t geometryCount; + const VkAccelerationStructureGeometryKHR * pGeometries; + const VkAccelerationStructureGeometryKHR * const* ppGeometries; + VkDeviceOrHostAddressKHR scratchData; +} VkAccelerationStructureBuildGeometryInfoKHR; -typedef struct VkExternalMemoryImageCreateInfo { +typedef struct VkAccelerationStructureCreateInfoKHR { VkStructureType sType; - const void * pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExternalMemoryImageCreateInfo; + const void * pNext; + VkAccelerationStructureCreateFlagsKHR createFlags; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; + VkAccelerationStructureTypeKHR type; + VkDeviceAddress deviceAddress; +} VkAccelerationStructureCreateInfoKHR; -typedef struct VkExternalMemoryImageCreateInfo VkExternalMemoryImageCreateInfoKHR; +typedef struct VkAccelerationStructureInstanceKHR { + VkTransformMatrixKHR transform; + uint32_t instanceCustomIndex :24; + uint32_t mask :8; + uint32_t instanceShaderBindingTableRecordOffset :24; + VkGeometryInstanceFlagsKHR flags :8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureInstanceKHR; -typedef struct VkExternalMemoryBufferCreateInfo { +typedef struct VkAccelerationStructureInstanceKHR VkAccelerationStructureInstanceNV; + +typedef struct VkCopyAccelerationStructureToMemoryInfoKHR { VkStructureType sType; - const void * pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExternalMemoryBufferCreateInfo; + const void * pNext; + VkAccelerationStructureKHR src; + VkDeviceOrHostAddressKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyAccelerationStructureToMemoryInfoKHR; -typedef struct VkExternalMemoryBufferCreateInfo VkExternalMemoryBufferCreateInfoKHR; +typedef struct VkCopyMemoryToAccelerationStructureInfoKHR { + VkStructureType sType; + const void * pNext; + VkDeviceOrHostAddressConstKHR src; + VkAccelerationStructureKHR dst; + VkCopyAccelerationStructureModeKHR mode; +} VkCopyMemoryToAccelerationStructureInfoKHR; -typedef struct VkExportMemoryAllocateInfo { +typedef struct VkPhysicalDeviceExtendedDynamicStateFeaturesEXT { VkStructureType sType; - const void * pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExportMemoryAllocateInfo; + void * pNext; + VkBool32 extendedDynamicState; +} VkPhysicalDeviceExtendedDynamicStateFeaturesEXT; -typedef struct VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR; +typedef struct VkPhysicalDeviceExtendedDynamicState2FeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 extendedDynamicState2; + VkBool32 extendedDynamicState2LogicOp; + VkBool32 extendedDynamicState2PatchControlPoints; +} VkPhysicalDeviceExtendedDynamicState2FeaturesEXT; -typedef struct VkExternalSemaphoreProperties { +typedef struct VkPhysicalDeviceExtendedDynamicState3FeaturesEXT { VkStructureType sType; - void * pNext; - VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes; - VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes; - VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures; -} VkExternalSemaphoreProperties; + void * pNext; + VkBool32 extendedDynamicState3TessellationDomainOrigin; + VkBool32 extendedDynamicState3DepthClampEnable; + VkBool32 extendedDynamicState3PolygonMode; + VkBool32 extendedDynamicState3RasterizationSamples; + VkBool32 extendedDynamicState3SampleMask; + VkBool32 extendedDynamicState3AlphaToCoverageEnable; + VkBool32 extendedDynamicState3AlphaToOneEnable; + VkBool32 extendedDynamicState3LogicOpEnable; + VkBool32 extendedDynamicState3ColorBlendEnable; + VkBool32 extendedDynamicState3ColorBlendEquation; + VkBool32 extendedDynamicState3ColorWriteMask; + VkBool32 extendedDynamicState3RasterizationStream; + VkBool32 extendedDynamicState3ConservativeRasterizationMode; + VkBool32 extendedDynamicState3ExtraPrimitiveOverestimationSize; + VkBool32 extendedDynamicState3DepthClipEnable; + VkBool32 extendedDynamicState3SampleLocationsEnable; + VkBool32 extendedDynamicState3ColorBlendAdvanced; + VkBool32 extendedDynamicState3ProvokingVertexMode; + VkBool32 extendedDynamicState3LineRasterizationMode; + VkBool32 extendedDynamicState3LineStippleEnable; + VkBool32 extendedDynamicState3DepthClipNegativeOneToOne; + VkBool32 extendedDynamicState3ViewportWScalingEnable; + VkBool32 extendedDynamicState3ViewportSwizzle; + VkBool32 extendedDynamicState3CoverageToColorEnable; + VkBool32 extendedDynamicState3CoverageToColorLocation; + VkBool32 extendedDynamicState3CoverageModulationMode; + VkBool32 extendedDynamicState3CoverageModulationTableEnable; + VkBool32 extendedDynamicState3CoverageModulationTable; + VkBool32 extendedDynamicState3CoverageReductionMode; + VkBool32 extendedDynamicState3RepresentativeFragmentTestEnable; + VkBool32 extendedDynamicState3ShadingRateImageEnable; +} VkPhysicalDeviceExtendedDynamicState3FeaturesEXT; + +typedef struct VkPhysicalDeviceExtendedDynamicState3PropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 dynamicPrimitiveTopologyUnrestricted; +} VkPhysicalDeviceExtendedDynamicState3PropertiesEXT; -typedef struct VkExternalSemaphoreProperties VkExternalSemaphorePropertiesKHR; +typedef struct VkColorBlendAdvancedEXT { + VkBlendOp advancedBlendOp; + VkBool32 srcPremultiplied; + VkBool32 dstPremultiplied; + VkBlendOverlapEXT blendOverlap; + VkBool32 clampResults; +} VkColorBlendAdvancedEXT; -typedef struct VkExportSemaphoreCreateInfo { +typedef struct VkPhysicalDevicePartitionedAccelerationStructureFeaturesNV { VkStructureType sType; - const void * pNext; - VkExternalSemaphoreHandleTypeFlags handleTypes; -} VkExportSemaphoreCreateInfo; + void * pNext; + VkBool32 partitionedAccelerationStructure; +} VkPhysicalDevicePartitionedAccelerationStructureFeaturesNV; -typedef struct VkExportSemaphoreCreateInfo VkExportSemaphoreCreateInfoKHR; +typedef struct VkBuildPartitionedAccelerationStructureIndirectCommandNV { + VkPartitionedAccelerationStructureOpTypeNV opType; + uint32_t argCount; + VkStridedDeviceAddressNV argData; +} VkBuildPartitionedAccelerationStructureIndirectCommandNV; -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkImportSemaphoreWin32HandleInfoKHR { +typedef struct VkPartitionedAccelerationStructureFlagsNV { VkStructureType sType; - const void * pNext; - VkSemaphore semaphore; - VkSemaphoreImportFlags flags; - VkExternalSemaphoreHandleTypeFlagBits handleType; - HANDLE handle; - LPCWSTR name; -} VkImportSemaphoreWin32HandleInfoKHR; -#endif - -typedef struct VkImportSemaphoreFdInfoKHR { + void * pNext; + VkBool32 enablePartitionTranslation; +} VkPartitionedAccelerationStructureFlagsNV; + +typedef struct VkPartitionedAccelerationStructureWriteInstanceDataNV { + VkTransformMatrixKHR transform; + float explicitAABB [6]; + uint32_t instanceID; + uint32_t instanceMask; + uint32_t instanceContributionToHitGroupIndex; + VkPartitionedAccelerationStructureInstanceFlagsNV instanceFlags; + uint32_t instanceIndex; + uint32_t partitionIndex; + VkDeviceAddress accelerationStructure; +} VkPartitionedAccelerationStructureWriteInstanceDataNV; + +typedef struct VkPartitionedAccelerationStructureUpdateInstanceDataNV { + uint32_t instanceIndex; + uint32_t instanceContributionToHitGroupIndex; + VkDeviceAddress accelerationStructure; +} VkPartitionedAccelerationStructureUpdateInstanceDataNV; + +typedef struct VkWriteDescriptorSetPartitionedAccelerationStructureNV { VkStructureType sType; - const void * pNext; - VkSemaphore semaphore; - VkSemaphoreImportFlags flags; - VkExternalSemaphoreHandleTypeFlagBits handleType; - int fd; -} VkImportSemaphoreFdInfoKHR; + void * pNext; + uint32_t accelerationStructureCount; + const VkDeviceAddress * pAccelerationStructures; +} VkWriteDescriptorSetPartitionedAccelerationStructureNV; -typedef struct VkExternalFenceProperties { +typedef struct VkPartitionedAccelerationStructureInstancesInputNV { VkStructureType sType; - void * pNext; - VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes; - VkExternalFenceHandleTypeFlags compatibleHandleTypes; - VkExternalFenceFeatureFlags externalFenceFeatures; -} VkExternalFenceProperties; - -typedef struct VkExternalFenceProperties VkExternalFencePropertiesKHR; + void * pNext; + VkBuildAccelerationStructureFlagsKHR flags; + uint32_t instanceCount; + uint32_t maxInstancePerPartitionCount; + uint32_t partitionCount; + uint32_t maxInstanceInGlobalPartitionCount; +} VkPartitionedAccelerationStructureInstancesInputNV; -typedef struct VkExportFenceCreateInfo { +typedef struct VkBuildPartitionedAccelerationStructureInfoNV { VkStructureType sType; - const void * pNext; - VkExternalFenceHandleTypeFlags handleTypes; -} VkExportFenceCreateInfo; - -typedef struct VkExportFenceCreateInfo VkExportFenceCreateInfoKHR; + void * pNext; + VkPartitionedAccelerationStructureInstancesInputNV input; + VkDeviceAddress srcAccelerationStructureData; + VkDeviceAddress dstAccelerationStructureData; + VkDeviceAddress scratchData; + VkDeviceAddress srcInfos; + VkDeviceAddress srcInfosCount; +} VkBuildPartitionedAccelerationStructureInfoNV; -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkImportFenceWin32HandleInfoKHR { +typedef struct VkPhysicalDeviceDiagnosticsConfigFeaturesNV { VkStructureType sType; - const void * pNext; - VkFence fence; - VkFenceImportFlags flags; - VkExternalFenceHandleTypeFlagBits handleType; - HANDLE handle; - LPCWSTR name; -} VkImportFenceWin32HandleInfoKHR; -#endif + void * pNext; + VkBool32 diagnosticsConfig; +} VkPhysicalDeviceDiagnosticsConfigFeaturesNV; -typedef struct VkImportFenceFdInfoKHR { - VkStructureType sType; - const void * pNext; - VkFence fence; - VkFenceImportFlags flags; - VkExternalFenceHandleTypeFlagBits handleType; - int fd; -} VkImportFenceFdInfoKHR; +typedef struct VkDeviceDiagnosticsConfigCreateInfoNV { + VkStructureType sType; + const void * pNext; + VkDeviceDiagnosticsConfigFlagsNV flags; +} VkDeviceDiagnosticsConfigCreateInfoNV; -typedef struct VkPhysicalDeviceMultiviewFeatures { +typedef struct VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures { VkStructureType sType; - void * pNext; - VkBool32 multiview; - VkBool32 multiviewGeometryShader; - VkBool32 multiviewTessellationShader; -} VkPhysicalDeviceMultiviewFeatures; + void * pNext; + VkBool32 shaderZeroInitializeWorkgroupMemory; +} VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures; -typedef struct VkPhysicalDeviceMultiviewFeatures VkPhysicalDeviceMultiviewFeaturesKHR; +typedef struct VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR; -typedef struct VkSurfaceCapabilities2EXT { +typedef struct VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR { VkStructureType sType; - void * pNext; - uint32_t minImageCount; - uint32_t maxImageCount; - VkExtent2D currentExtent; - VkExtent2D minImageExtent; - VkExtent2D maxImageExtent; - uint32_t maxImageArrayLayers; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkSurfaceTransformFlagBitsKHR currentTransform; - VkCompositeAlphaFlagsKHR supportedCompositeAlpha; - VkImageUsageFlags supportedUsageFlags; - VkSurfaceCounterFlagsEXT supportedSurfaceCounters; -} VkSurfaceCapabilities2EXT; + void * pNext; + VkBool32 shaderSubgroupUniformControlFlow; +} VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR; -typedef struct VkSwapchainCounterCreateInfoEXT { +typedef struct VkPhysicalDeviceRobustness2FeaturesKHR { VkStructureType sType; - const void * pNext; - VkSurfaceCounterFlagsEXT surfaceCounters; -} VkSwapchainCounterCreateInfoEXT; + void * pNext; + VkBool32 robustBufferAccess2; + VkBool32 robustImageAccess2; + VkBool32 nullDescriptor; +} VkPhysicalDeviceRobustness2FeaturesKHR; -typedef struct VkPhysicalDeviceGroupProperties { +typedef struct VkPhysicalDeviceRobustness2FeaturesKHR VkPhysicalDeviceRobustness2FeaturesEXT; + +typedef struct VkPhysicalDeviceRobustness2PropertiesKHR { VkStructureType sType; - void * pNext; - uint32_t physicalDeviceCount; - VkPhysicalDevice physicalDevices [ VK_MAX_DEVICE_GROUP_SIZE ]; - VkBool32 subsetAllocation; -} VkPhysicalDeviceGroupProperties; + void * pNext; + VkDeviceSize robustStorageBufferAccessSizeAlignment; + VkDeviceSize robustUniformBufferAccessSizeAlignment; +} VkPhysicalDeviceRobustness2PropertiesKHR; -typedef struct VkPhysicalDeviceGroupProperties VkPhysicalDeviceGroupPropertiesKHR; +typedef struct VkPhysicalDeviceRobustness2PropertiesKHR VkPhysicalDeviceRobustness2PropertiesEXT; -typedef struct VkMemoryAllocateFlagsInfo { +typedef struct VkPhysicalDeviceImageRobustnessFeatures { VkStructureType sType; - const void * pNext; - VkMemoryAllocateFlags flags; - uint32_t deviceMask; -} VkMemoryAllocateFlagsInfo; + void * pNext; + VkBool32 robustImageAccess; +} VkPhysicalDeviceImageRobustnessFeatures; -typedef struct VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR; +typedef struct VkPhysicalDeviceImageRobustnessFeatures VkPhysicalDeviceImageRobustnessFeaturesEXT; -typedef struct VkBindBufferMemoryInfo { +typedef struct VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR { VkStructureType sType; - const void * pNext; - VkBuffer buffer; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; -} VkBindBufferMemoryInfo; - -typedef struct VkBindBufferMemoryInfo VkBindBufferMemoryInfoKHR; + void * pNext; + VkBool32 workgroupMemoryExplicitLayout; + VkBool32 workgroupMemoryExplicitLayoutScalarBlockLayout; + VkBool32 workgroupMemoryExplicitLayout8BitAccess; + VkBool32 workgroupMemoryExplicitLayout16BitAccess; +} VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR; -typedef struct VkBindImageMemoryInfo { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDevicePortabilitySubsetFeaturesKHR { VkStructureType sType; - const void * pNext; - VkImage image; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; -} VkBindImageMemoryInfo; + void * pNext; + VkBool32 constantAlphaColorBlendFactors; + VkBool32 events; + VkBool32 imageViewFormatReinterpretation; + VkBool32 imageViewFormatSwizzle; + VkBool32 imageView2DOn3DImage; + VkBool32 multisampleArrayImage; + VkBool32 mutableComparisonSamplers; + VkBool32 pointPolygons; + VkBool32 samplerMipLodBias; + VkBool32 separateStencilMaskRef; + VkBool32 shaderSampleRateInterpolationFunctions; + VkBool32 tessellationIsolines; + VkBool32 tessellationPointMode; + VkBool32 triangleFans; + VkBool32 vertexAttributeAccessBeyondStride; +} VkPhysicalDevicePortabilitySubsetFeaturesKHR; -typedef struct VkBindImageMemoryInfo VkBindImageMemoryInfoKHR; +#endif -typedef struct VkDeviceGroupPresentCapabilitiesKHR { +typedef struct VkPhysicalDevice4444FormatsFeaturesEXT { VkStructureType sType; - const void * pNext; - uint32_t presentMask [ VK_MAX_DEVICE_GROUP_SIZE ]; - VkDeviceGroupPresentModeFlagsKHR modes; -} VkDeviceGroupPresentCapabilitiesKHR; + void * pNext; + VkBool32 formatA4R4G4B4; + VkBool32 formatA4B4G4R4; +} VkPhysicalDevice4444FormatsFeaturesEXT; -typedef struct VkDeviceGroupSwapchainCreateInfoKHR { +typedef struct VkPhysicalDeviceSubpassShadingFeaturesHUAWEI { VkStructureType sType; - const void * pNext; - VkDeviceGroupPresentModeFlagsKHR modes; -} VkDeviceGroupSwapchainCreateInfoKHR; + void * pNext; + VkBool32 subpassShading; +} VkPhysicalDeviceSubpassShadingFeaturesHUAWEI; -typedef struct VkDescriptorUpdateTemplateCreateInfo { - VkStructureType sType; - const void * pNext; - VkDescriptorUpdateTemplateCreateFlags flags; - uint32_t descriptorUpdateEntryCount; - const VkDescriptorUpdateTemplateEntry * pDescriptorUpdateEntries; - VkDescriptorUpdateTemplateType templateType; - VkDescriptorSetLayout descriptorSetLayout; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout pipelineLayout; - uint32_t set; -} VkDescriptorUpdateTemplateCreateInfo; +typedef struct VkPhysicalDeviceClusterCullingShaderFeaturesHUAWEI { + VkStructureType sType; + void * pNext; + VkBool32 clustercullingShader; + VkBool32 multiviewClusterCullingShader; +} VkPhysicalDeviceClusterCullingShaderFeaturesHUAWEI; -typedef struct VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR; +typedef struct VkPhysicalDeviceClusterCullingShaderVrsFeaturesHUAWEI { + VkStructureType sType; + void * pNext; + VkBool32 clusterShadingRate; +} VkPhysicalDeviceClusterCullingShaderVrsFeaturesHUAWEI; -typedef struct VkDisplayNativeHdrSurfaceCapabilitiesAMD { +typedef struct VkBufferCopy2 { VkStructureType sType; - void * pNext; - VkBool32 localDimmingSupport; -} VkDisplayNativeHdrSurfaceCapabilitiesAMD; + const void * pNext; + VkDeviceSize srcOffset; + VkDeviceSize dstOffset; + VkDeviceSize size; +} VkBufferCopy2; -typedef struct VkSwapchainDisplayNativeHdrCreateInfoAMD { +typedef struct VkBufferCopy2 VkBufferCopy2KHR; + +typedef struct VkImageCopy2 { VkStructureType sType; - const void * pNext; - VkBool32 localDimmingEnable; -} VkSwapchainDisplayNativeHdrCreateInfoAMD; + const void * pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageCopy2; -typedef struct VkPresentTimesInfoGOOGLE { +typedef struct VkImageCopy2 VkImageCopy2KHR; + +typedef struct VkImageBlit2 { VkStructureType sType; - const void * pNext; - uint32_t swapchainCount; - const VkPresentTimeGOOGLE * pTimes; -} VkPresentTimesInfoGOOGLE; + const void * pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffsets [2]; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffsets [2]; +} VkImageBlit2; -#if defined(VK_USE_PLATFORM_IOS_MVK) -typedef struct VkIOSSurfaceCreateInfoMVK { +typedef struct VkImageBlit2 VkImageBlit2KHR; + +typedef struct VkBufferImageCopy2 { VkStructureType sType; - const void * pNext; - VkIOSSurfaceCreateFlagsMVK flags; - const void * pView; -} VkIOSSurfaceCreateInfoMVK; -#endif + const void * pNext; + VkDeviceSize bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkBufferImageCopy2; -#if defined(VK_USE_PLATFORM_MACOS_MVK) -typedef struct VkMacOSSurfaceCreateInfoMVK { +typedef struct VkBufferImageCopy2 VkBufferImageCopy2KHR; + +typedef struct VkImageResolve2 { VkStructureType sType; - const void * pNext; - VkMacOSSurfaceCreateFlagsMVK flags; - const void * pView; -} VkMacOSSurfaceCreateInfoMVK; -#endif + const void * pNext; + VkImageSubresourceLayers srcSubresource; + VkOffset3D srcOffset; + VkImageSubresourceLayers dstSubresource; + VkOffset3D dstOffset; + VkExtent3D extent; +} VkImageResolve2; -#if defined(VK_USE_PLATFORM_METAL_EXT) -typedef struct VkMetalSurfaceCreateInfoEXT { +typedef struct VkImageResolve2 VkImageResolve2KHR; + +typedef struct VkCopyBufferInfo2 { VkStructureType sType; - const void * pNext; - VkMetalSurfaceCreateFlagsEXT flags; - const CAMetalLayer * pLayer; -} VkMetalSurfaceCreateInfoEXT; -#endif + const void * pNext; + VkBuffer srcBuffer; + VkBuffer dstBuffer; + uint32_t regionCount; + const VkBufferCopy2 * pRegions; +} VkCopyBufferInfo2; -typedef struct VkPipelineViewportWScalingStateCreateInfoNV { +typedef struct VkCopyBufferInfo2 VkCopyBufferInfo2KHR; + +typedef struct VkCopyImageInfo2 { VkStructureType sType; - const void * pNext; - VkBool32 viewportWScalingEnable; - uint32_t viewportCount; - const VkViewportWScalingNV * pViewportWScalings; -} VkPipelineViewportWScalingStateCreateInfoNV; + const void * pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageCopy2 * pRegions; +} VkCopyImageInfo2; -typedef struct VkPipelineViewportSwizzleStateCreateInfoNV { +typedef struct VkCopyImageInfo2 VkCopyImageInfo2KHR; + +typedef struct VkBlitImageInfo2 { VkStructureType sType; const void * pNext; - VkPipelineViewportSwizzleStateCreateFlagsNV flags; - uint32_t viewportCount; - const VkViewportSwizzleNV * pViewportSwizzles; -} VkPipelineViewportSwizzleStateCreateInfoNV; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageBlit2 * pRegions; + VkFilter filter; +} VkBlitImageInfo2; -typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT { - VkStructureType sType; - const void * pNext; - VkPipelineDiscardRectangleStateCreateFlagsEXT flags; - VkDiscardRectangleModeEXT discardRectangleMode; - uint32_t discardRectangleCount; - const VkRect2D * pDiscardRectangles; -} VkPipelineDiscardRectangleStateCreateInfoEXT; +typedef struct VkBlitImageInfo2 VkBlitImageInfo2KHR; -typedef struct VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX { +typedef struct VkCopyBufferToImageInfo2 { VkStructureType sType; - void * pNext; - VkBool32 perViewPositionAllComponents; -} VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX; + const void * pNext; + VkBuffer srcBuffer; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkBufferImageCopy2 * pRegions; +} VkCopyBufferToImageInfo2; -typedef struct VkInputAttachmentAspectReference { - uint32_t subpass; - uint32_t inputAttachmentIndex; - VkImageAspectFlags aspectMask; -} VkInputAttachmentAspectReference; +typedef struct VkCopyBufferToImageInfo2 VkCopyBufferToImageInfo2KHR; -typedef struct VkInputAttachmentAspectReference VkInputAttachmentAspectReferenceKHR; +typedef struct VkCopyImageToBufferInfo2 { + VkStructureType sType; + const void * pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkBuffer dstBuffer; + uint32_t regionCount; + const VkBufferImageCopy2 * pRegions; +} VkCopyImageToBufferInfo2; -typedef struct VkRenderPassInputAttachmentAspectCreateInfo { +typedef struct VkCopyImageToBufferInfo2 VkCopyImageToBufferInfo2KHR; + +typedef struct VkResolveImageInfo2 { VkStructureType sType; - const void * pNext; - uint32_t aspectReferenceCount; - const VkInputAttachmentAspectReference * pAspectReferences; -} VkRenderPassInputAttachmentAspectCreateInfo; + const void * pNext; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageResolve2 * pRegions; +} VkResolveImageInfo2; -typedef struct VkRenderPassInputAttachmentAspectCreateInfo VkRenderPassInputAttachmentAspectCreateInfoKHR; +typedef struct VkResolveImageInfo2 VkResolveImageInfo2KHR; -typedef struct VkSurfaceCapabilities2KHR { +typedef struct VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT { VkStructureType sType; - void * pNext; - VkSurfaceCapabilitiesKHR surfaceCapabilities; -} VkSurfaceCapabilities2KHR; + void * pNext; + VkBool32 shaderImageInt64Atomics; + VkBool32 sparseImageInt64Atomics; +} VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT; -typedef struct VkDisplayProperties2KHR { +typedef struct VkFragmentShadingRateAttachmentInfoKHR { VkStructureType sType; - void * pNext; - VkDisplayPropertiesKHR displayProperties; -} VkDisplayProperties2KHR; + const void * pNext; + const VkAttachmentReference2 * pFragmentShadingRateAttachment; + VkExtent2D shadingRateAttachmentTexelSize; +} VkFragmentShadingRateAttachmentInfoKHR; -typedef struct VkDisplayPlaneCapabilities2KHR { +typedef struct VkPhysicalDeviceFragmentShadingRateFeaturesKHR { VkStructureType sType; - void * pNext; - VkDisplayPlaneCapabilitiesKHR capabilities; -} VkDisplayPlaneCapabilities2KHR; + void * pNext; + VkBool32 pipelineFragmentShadingRate; + VkBool32 primitiveFragmentShadingRate; + VkBool32 attachmentFragmentShadingRate; +} VkPhysicalDeviceFragmentShadingRateFeaturesKHR; -typedef struct VkSharedPresentSurfaceCapabilitiesKHR { +typedef struct VkPhysicalDeviceFragmentShadingRatePropertiesKHR { VkStructureType sType; - void * pNext; - VkImageUsageFlags sharedPresentSupportedUsageFlags; -} VkSharedPresentSurfaceCapabilitiesKHR; + void * pNext; + VkExtent2D minFragmentShadingRateAttachmentTexelSize; + VkExtent2D maxFragmentShadingRateAttachmentTexelSize; + uint32_t maxFragmentShadingRateAttachmentTexelSizeAspectRatio; + VkBool32 primitiveFragmentShadingRateWithMultipleViewports; + VkBool32 layeredShadingRateAttachments; + VkBool32 fragmentShadingRateNonTrivialCombinerOps; + VkExtent2D maxFragmentSize; + uint32_t maxFragmentSizeAspectRatio; + uint32_t maxFragmentShadingRateCoverageSamples; + VkSampleCountFlagBits maxFragmentShadingRateRasterizationSamples; + VkBool32 fragmentShadingRateWithShaderDepthStencilWrites; + VkBool32 fragmentShadingRateWithSampleMask; + VkBool32 fragmentShadingRateWithShaderSampleMask; + VkBool32 fragmentShadingRateWithConservativeRasterization; + VkBool32 fragmentShadingRateWithFragmentShaderInterlock; + VkBool32 fragmentShadingRateWithCustomSampleLocations; + VkBool32 fragmentShadingRateStrictMultiplyCombiner; +} VkPhysicalDeviceFragmentShadingRatePropertiesKHR; + +typedef struct VkPhysicalDeviceFragmentShadingRateKHR { + VkStructureType sType; + void * pNext; + VkSampleCountFlags sampleCounts; + VkExtent2D fragmentSize; +} VkPhysicalDeviceFragmentShadingRateKHR; -typedef struct VkPhysicalDevice16BitStorageFeatures { +typedef struct VkPhysicalDeviceShaderTerminateInvocationFeatures { VkStructureType sType; - void * pNext; - VkBool32 storageBuffer16BitAccess; - VkBool32 uniformAndStorageBuffer16BitAccess; - VkBool32 storagePushConstant16; - VkBool32 storageInputOutput16; -} VkPhysicalDevice16BitStorageFeatures; + void * pNext; + VkBool32 shaderTerminateInvocation; +} VkPhysicalDeviceShaderTerminateInvocationFeatures; -typedef struct VkPhysicalDevice16BitStorageFeatures VkPhysicalDevice16BitStorageFeaturesKHR; +typedef struct VkPhysicalDeviceShaderTerminateInvocationFeatures VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR; -typedef struct VkPhysicalDeviceSubgroupProperties { +typedef struct VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV { VkStructureType sType; - void * pNext; - uint32_t subgroupSize; - VkShaderStageFlags supportedStages; - VkSubgroupFeatureFlags supportedOperations; - VkBool32 quadOperationsInAllStages; -} VkPhysicalDeviceSubgroupProperties; + void * pNext; + VkBool32 fragmentShadingRateEnums; + VkBool32 supersampleFragmentShadingRates; + VkBool32 noInvocationFragmentShadingRates; +} VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV; -typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures { +typedef struct VkAccelerationStructureBuildSizesInfoKHR { VkStructureType sType; - void * pNext; - VkBool32 shaderSubgroupExtendedTypes; -} VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures; + const void * pNext; + VkDeviceSize accelerationStructureSize; + VkDeviceSize updateScratchSize; + VkDeviceSize buildScratchSize; +} VkAccelerationStructureBuildSizesInfoKHR; -typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR; +typedef struct VkPhysicalDeviceImage2DViewOf3DFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 image2DViewOf3D; + VkBool32 sampler2DViewOf3D; +} VkPhysicalDeviceImage2DViewOf3DFeaturesEXT; -typedef struct VkMemoryRequirements2 { +typedef struct VkPhysicalDeviceImageSlicedViewOf3DFeaturesEXT { VkStructureType sType; - void * pNext; - VkMemoryRequirements memoryRequirements; -} VkMemoryRequirements2; + void * pNext; + VkBool32 imageSlicedViewOf3D; +} VkPhysicalDeviceImageSlicedViewOf3DFeaturesEXT; -typedef struct VkMemoryRequirements2 VkMemoryRequirements2KHR; +typedef struct VkPhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 attachmentFeedbackLoopDynamicState; +} VkPhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT; -typedef struct VkSparseImageMemoryRequirements2 { +typedef struct VkPhysicalDeviceLegacyVertexAttributesFeaturesEXT { VkStructureType sType; - void * pNext; - VkSparseImageMemoryRequirements memoryRequirements; -} VkSparseImageMemoryRequirements2; + void * pNext; + VkBool32 legacyVertexAttributes; +} VkPhysicalDeviceLegacyVertexAttributesFeaturesEXT; -typedef struct VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR; +typedef struct VkPhysicalDeviceLegacyVertexAttributesPropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 nativeUnalignedPerformance; +} VkPhysicalDeviceLegacyVertexAttributesPropertiesEXT; -typedef struct VkMemoryDedicatedRequirements { +typedef struct VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 prefersDedicatedAllocation; - VkBool32 requiresDedicatedAllocation; -} VkMemoryDedicatedRequirements; + void * pNext; + VkBool32 mutableDescriptorType; +} VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT; + +typedef struct VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE; + +typedef struct VkPhysicalDeviceDepthClipControlFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 depthClipControl; +} VkPhysicalDeviceDepthClipControlFeaturesEXT; -typedef struct VkMemoryDedicatedRequirements VkMemoryDedicatedRequirementsKHR; +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 deviceGeneratedCommands; + VkBool32 dynamicGeneratedPipelineLayout; +} VkPhysicalDeviceDeviceGeneratedCommandsFeaturesEXT; -typedef struct VkImageViewUsageCreateInfo { +typedef struct VkPhysicalDeviceDeviceGeneratedCommandsPropertiesEXT { + VkStructureType sType; + void * pNext; + uint32_t maxIndirectPipelineCount; + uint32_t maxIndirectShaderObjectCount; + uint32_t maxIndirectSequenceCount; + uint32_t maxIndirectCommandsTokenCount; + uint32_t maxIndirectCommandsTokenOffset; + uint32_t maxIndirectCommandsIndirectStride; + VkIndirectCommandsInputModeFlagsEXT supportedIndirectCommandsInputModes; + VkShaderStageFlags supportedIndirectCommandsShaderStages; + VkShaderStageFlags supportedIndirectCommandsShaderStagesPipelineBinding; + VkShaderStageFlags supportedIndirectCommandsShaderStagesShaderBinding; + VkBool32 deviceGeneratedCommandsTransformFeedback; + VkBool32 deviceGeneratedCommandsMultiDrawIndirectCount; +} VkPhysicalDeviceDeviceGeneratedCommandsPropertiesEXT; + +typedef struct VkIndirectExecutionSetShaderInfoEXT { VkStructureType sType; const void * pNext; - VkImageUsageFlags usage; -} VkImageViewUsageCreateInfo; + uint32_t shaderCount; + const VkShaderEXT * pInitialShaders; + const VkIndirectExecutionSetShaderLayoutInfoEXT * pSetLayoutInfos; + uint32_t maxShaderCount; + uint32_t pushConstantRangeCount; + const VkPushConstantRange * pPushConstantRanges; +} VkIndirectExecutionSetShaderInfoEXT; -typedef struct VkImageViewUsageCreateInfo VkImageViewUsageCreateInfoKHR; +typedef union VkIndirectExecutionSetInfoEXT { + const VkIndirectExecutionSetPipelineInfoEXT * pPipelineInfo; + const VkIndirectExecutionSetShaderInfoEXT * pShaderInfo; +} VkIndirectExecutionSetInfoEXT; -typedef struct VkSamplerYcbcrConversionCreateInfo { +typedef struct VkIndirectExecutionSetCreateInfoEXT { VkStructureType sType; - const void * pNext; - VkFormat format; - VkSamplerYcbcrModelConversion ycbcrModel; - VkSamplerYcbcrRange ycbcrRange; - VkComponentMapping components; - VkChromaLocation xChromaOffset; - VkChromaLocation yChromaOffset; - VkFilter chromaFilter; - VkBool32 forceExplicitReconstruction; -} VkSamplerYcbcrConversionCreateInfo; + const void * pNext; + VkIndirectExecutionSetInfoTypeEXT type; + VkIndirectExecutionSetInfoEXT info; +} VkIndirectExecutionSetCreateInfoEXT; -typedef struct VkSamplerYcbcrConversionCreateInfo VkSamplerYcbcrConversionCreateInfoKHR; +typedef struct VkGeneratedCommandsInfoEXT { + VkStructureType sType; + const void * pNext; + VkShaderStageFlags shaderStages; + VkIndirectExecutionSetEXT indirectExecutionSet; + VkIndirectCommandsLayoutEXT indirectCommandsLayout; + VkDeviceAddress indirectAddress; + VkDeviceSize indirectAddressSize; + VkDeviceAddress preprocessAddress; + VkDeviceSize preprocessSize; + uint32_t maxSequenceCount; + VkDeviceAddress sequenceCountAddress; + uint32_t maxDrawCount; +} VkGeneratedCommandsInfoEXT; + +typedef struct VkDrawIndirectCountIndirectCommandEXT { + VkDeviceAddress bufferAddress; + uint32_t stride; + uint32_t commandCount; +} VkDrawIndirectCountIndirectCommandEXT; + +typedef struct VkBindVertexBufferIndirectCommandEXT { + VkDeviceAddress bufferAddress; + uint32_t size; + uint32_t stride; +} VkBindVertexBufferIndirectCommandEXT; + +typedef struct VkBindIndexBufferIndirectCommandEXT { + VkDeviceAddress bufferAddress; + uint32_t size; + VkIndexType indexType; +} VkBindIndexBufferIndirectCommandEXT; + +typedef struct VkIndirectCommandsPushConstantTokenEXT { + VkPushConstantRange updateRange; +} VkIndirectCommandsPushConstantTokenEXT; + +typedef struct VkIndirectCommandsExecutionSetTokenEXT { + VkIndirectExecutionSetInfoTypeEXT type; + VkShaderStageFlags shaderStages; +} VkIndirectCommandsExecutionSetTokenEXT; + +typedef union VkIndirectCommandsTokenDataEXT { + const VkIndirectCommandsPushConstantTokenEXT * pPushConstant; + const VkIndirectCommandsVertexBufferTokenEXT * pVertexBuffer; + const VkIndirectCommandsIndexBufferTokenEXT * pIndexBuffer; + const VkIndirectCommandsExecutionSetTokenEXT * pExecutionSet; +} VkIndirectCommandsTokenDataEXT; + +typedef struct VkPipelineViewportDepthClipControlCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkBool32 negativeOneToOne; +} VkPipelineViewportDepthClipControlCreateInfoEXT; -typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures { +typedef struct VkPhysicalDeviceDepthClampControlFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 samplerYcbcrConversion; -} VkPhysicalDeviceSamplerYcbcrConversionFeatures; + void * pNext; + VkBool32 depthClampControl; +} VkPhysicalDeviceDepthClampControlFeaturesEXT; -typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR; +typedef struct VkPipelineViewportDepthClampControlCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkDepthClampModeEXT depthClampMode; + const VkDepthClampRangeEXT * pDepthClampRange; +} VkPipelineViewportDepthClampControlCreateInfoEXT; -typedef struct VkTextureLODGatherFormatPropertiesAMD { +typedef struct VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 supportsTextureGatherLODBiasAMD; -} VkTextureLODGatherFormatPropertiesAMD; + void * pNext; + VkBool32 vertexInputDynamicState; +} VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT; -typedef struct VkConditionalRenderingBeginInfoEXT { +typedef struct VkPhysicalDeviceExternalMemoryRDMAFeaturesNV { VkStructureType sType; - const void * pNext; - VkBuffer buffer; - VkDeviceSize offset; - VkConditionalRenderingFlagsEXT flags; -} VkConditionalRenderingBeginInfoEXT; + void * pNext; + VkBool32 externalMemoryRDMA; +} VkPhysicalDeviceExternalMemoryRDMAFeaturesNV; -typedef struct VkProtectedSubmitInfo { +typedef struct VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR { VkStructureType sType; - const void * pNext; - VkBool32 protectedSubmit; -} VkProtectedSubmitInfo; + void * pNext; + VkBool32 shaderRelaxedExtendedInstruction; +} VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR; -typedef struct VkPhysicalDeviceProtectedMemoryFeatures { +typedef struct VkPhysicalDeviceColorWriteEnableFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 protectedMemory; -} VkPhysicalDeviceProtectedMemoryFeatures; + void * pNext; + VkBool32 colorWriteEnable; +} VkPhysicalDeviceColorWriteEnableFeaturesEXT; -typedef struct VkPhysicalDeviceProtectedMemoryProperties { +typedef struct VkPipelineColorWriteCreateInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 protectedNoFault; -} VkPhysicalDeviceProtectedMemoryProperties; + const void * pNext; + uint32_t attachmentCount; + const VkBool32 * pColorWriteEnables; +} VkPipelineColorWriteCreateInfoEXT; -typedef struct VkDeviceQueueInfo2 { +typedef struct VkMemoryBarrier2 { VkStructureType sType; - const void * pNext; - VkDeviceQueueCreateFlags flags; - uint32_t queueFamilyIndex; - uint32_t queueIndex; -} VkDeviceQueueInfo2; + const void * pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; +} VkMemoryBarrier2; -typedef struct VkPipelineCoverageToColorStateCreateInfoNV { +typedef struct VkMemoryBarrier2 VkMemoryBarrier2KHR; + +typedef struct VkImageMemoryBarrier2 { VkStructureType sType; - const void * pNext; - VkPipelineCoverageToColorStateCreateFlagsNV flags; - VkBool32 coverageToColorEnable; - uint32_t coverageToColorLocation; -} VkPipelineCoverageToColorStateCreateInfoNV; + const void * pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; + VkImageLayout oldLayout; + VkImageLayout newLayout; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkImage image; + VkImageSubresourceRange subresourceRange; +} VkImageMemoryBarrier2; + +typedef struct VkImageMemoryBarrier2 VkImageMemoryBarrier2KHR; + +typedef struct VkBufferMemoryBarrier2 { + VkStructureType sType; + const void * pNext; + VkPipelineStageFlags2 srcStageMask; + VkAccessFlags2 srcAccessMask; + VkPipelineStageFlags2 dstStageMask; + VkAccessFlags2 dstAccessMask; + uint32_t srcQueueFamilyIndex; + uint32_t dstQueueFamilyIndex; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; +} VkBufferMemoryBarrier2; + +typedef struct VkBufferMemoryBarrier2 VkBufferMemoryBarrier2KHR; + +typedef struct VkMemoryBarrierAccessFlags3KHR { + VkStructureType sType; + const void * pNext; + VkAccessFlags3KHR srcAccessMask3; + VkAccessFlags3KHR dstAccessMask3; +} VkMemoryBarrierAccessFlags3KHR; + +typedef struct VkDependencyInfo { + VkStructureType sType; + const void * pNext; + VkDependencyFlags dependencyFlags; + uint32_t memoryBarrierCount; + const VkMemoryBarrier2 * pMemoryBarriers; + uint32_t bufferMemoryBarrierCount; + const VkBufferMemoryBarrier2 * pBufferMemoryBarriers; + uint32_t imageMemoryBarrierCount; + const VkImageMemoryBarrier2 * pImageMemoryBarriers; +} VkDependencyInfo; + +typedef struct VkDependencyInfo VkDependencyInfoKHR; + +typedef struct VkSemaphoreSubmitInfo { + VkStructureType sType; + const void * pNext; + VkSemaphore semaphore; + uint64_t value; + VkPipelineStageFlags2 stageMask; + uint32_t deviceIndex; +} VkSemaphoreSubmitInfo; + +typedef struct VkSemaphoreSubmitInfo VkSemaphoreSubmitInfoKHR; + +typedef struct VkSubmitInfo2 { + VkStructureType sType; + const void * pNext; + VkSubmitFlags flags; + uint32_t waitSemaphoreInfoCount; + const VkSemaphoreSubmitInfo * pWaitSemaphoreInfos; + uint32_t commandBufferInfoCount; + const VkCommandBufferSubmitInfo * pCommandBufferInfos; + uint32_t signalSemaphoreInfoCount; + const VkSemaphoreSubmitInfo * pSignalSemaphoreInfos; +} VkSubmitInfo2; + +typedef struct VkSubmitInfo2 VkSubmitInfo2KHR; + +typedef struct VkQueueFamilyCheckpointProperties2NV { + VkStructureType sType; + void * pNext; + VkPipelineStageFlags2 checkpointExecutionStageMask; +} VkQueueFamilyCheckpointProperties2NV; -typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties { +typedef struct VkCheckpointData2NV { VkStructureType sType; void * pNext; - VkBool32 filterMinmaxSingleComponentFormats; - VkBool32 filterMinmaxImageComponentMapping; -} VkPhysicalDeviceSamplerFilterMinmaxProperties; + VkPipelineStageFlags2 stage; + void * pCheckpointMarker; +} VkCheckpointData2NV; -typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT; +typedef struct VkPhysicalDeviceSynchronization2Features { + VkStructureType sType; + void * pNext; + VkBool32 synchronization2; +} VkPhysicalDeviceSynchronization2Features; -typedef struct VkPipelineSampleLocationsStateCreateInfoEXT { +typedef struct VkPhysicalDeviceSynchronization2Features VkPhysicalDeviceSynchronization2FeaturesKHR; + +typedef struct VkPhysicalDeviceHostImageCopyFeatures { VkStructureType sType; - const void * pNext; - VkBool32 sampleLocationsEnable; - VkSampleLocationsInfoEXT sampleLocationsInfo; -} VkPipelineSampleLocationsStateCreateInfoEXT; + void * pNext; + VkBool32 hostImageCopy; +} VkPhysicalDeviceHostImageCopyFeatures; -typedef struct VkPhysicalDeviceSampleLocationsPropertiesEXT { +typedef struct VkPhysicalDeviceHostImageCopyFeatures VkPhysicalDeviceHostImageCopyFeaturesEXT; + +typedef struct VkPhysicalDeviceHostImageCopyProperties { VkStructureType sType; - void * pNext; - VkSampleCountFlags sampleLocationSampleCounts; - VkExtent2D maxSampleLocationGridSize; - float sampleLocationCoordinateRange [2]; - uint32_t sampleLocationSubPixelBits; - VkBool32 variableSampleLocations; -} VkPhysicalDeviceSampleLocationsPropertiesEXT; + void * pNext; + uint32_t copySrcLayoutCount; + VkImageLayout * pCopySrcLayouts; + uint32_t copyDstLayoutCount; + VkImageLayout * pCopyDstLayouts; + uint8_t optimalTilingLayoutUUID [ VK_UUID_SIZE ]; + VkBool32 identicalMemoryTypeRequirements; +} VkPhysicalDeviceHostImageCopyProperties; -typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT { +typedef struct VkPhysicalDeviceHostImageCopyProperties VkPhysicalDeviceHostImageCopyPropertiesEXT; + +typedef struct VkMemoryToImageCopy { VkStructureType sType; - void * pNext; - VkBool32 advancedBlendCoherentOperations; -} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT; + const void * pNext; + const void * pHostPointer; + uint32_t memoryRowLength; + uint32_t memoryImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkMemoryToImageCopy; -typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT { +typedef struct VkMemoryToImageCopy VkMemoryToImageCopyEXT; + +typedef struct VkImageToMemoryCopy { VkStructureType sType; - void * pNext; - uint32_t advancedBlendMaxColorAttachments; - VkBool32 advancedBlendIndependentBlend; - VkBool32 advancedBlendNonPremultipliedSrcColor; - VkBool32 advancedBlendNonPremultipliedDstColor; - VkBool32 advancedBlendCorrelatedOverlap; - VkBool32 advancedBlendAllOperations; -} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT; + const void * pNext; + void * pHostPointer; + uint32_t memoryRowLength; + uint32_t memoryImageHeight; + VkImageSubresourceLayers imageSubresource; + VkOffset3D imageOffset; + VkExtent3D imageExtent; +} VkImageToMemoryCopy; -typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT { +typedef struct VkImageToMemoryCopy VkImageToMemoryCopyEXT; + +typedef struct VkCopyMemoryToImageInfo { VkStructureType sType; - const void * pNext; - VkBool32 srcPremultiplied; - VkBool32 dstPremultiplied; - VkBlendOverlapEXT blendOverlap; -} VkPipelineColorBlendAdvancedStateCreateInfoEXT; + const void * pNext; + VkHostImageCopyFlags flags; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkMemoryToImageCopy * pRegions; +} VkCopyMemoryToImageInfo; -typedef struct VkPhysicalDeviceInlineUniformBlockFeaturesEXT { +typedef struct VkCopyMemoryToImageInfo VkCopyMemoryToImageInfoEXT; + +typedef struct VkCopyImageToMemoryInfo { VkStructureType sType; - void * pNext; - VkBool32 inlineUniformBlock; - VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; -} VkPhysicalDeviceInlineUniformBlockFeaturesEXT; + const void * pNext; + VkHostImageCopyFlags flags; + VkImage srcImage; + VkImageLayout srcImageLayout; + uint32_t regionCount; + const VkImageToMemoryCopy * pRegions; +} VkCopyImageToMemoryInfo; -typedef struct VkPipelineCoverageModulationStateCreateInfoNV { +typedef struct VkCopyImageToMemoryInfo VkCopyImageToMemoryInfoEXT; + +typedef struct VkCopyImageToImageInfo { VkStructureType sType; - const void * pNext; - VkPipelineCoverageModulationStateCreateFlagsNV flags; - VkCoverageModulationModeNV coverageModulationMode; - VkBool32 coverageModulationTableEnable; - uint32_t coverageModulationTableCount; - const float * pCoverageModulationTable; -} VkPipelineCoverageModulationStateCreateInfoNV; + const void * pNext; + VkHostImageCopyFlags flags; + VkImage srcImage; + VkImageLayout srcImageLayout; + VkImage dstImage; + VkImageLayout dstImageLayout; + uint32_t regionCount; + const VkImageCopy2 * pRegions; +} VkCopyImageToImageInfo; -typedef struct VkValidationCacheCreateInfoEXT { +typedef struct VkCopyImageToImageInfo VkCopyImageToImageInfoEXT; + +typedef struct VkHostImageLayoutTransitionInfo { VkStructureType sType; - const void * pNext; - VkValidationCacheCreateFlagsEXT flags; - size_t initialDataSize; - const void * pInitialData; -} VkValidationCacheCreateInfoEXT; + const void * pNext; + VkImage image; + VkImageLayout oldLayout; + VkImageLayout newLayout; + VkImageSubresourceRange subresourceRange; +} VkHostImageLayoutTransitionInfo; -typedef struct VkPhysicalDeviceMaintenance3Properties { +typedef struct VkHostImageLayoutTransitionInfo VkHostImageLayoutTransitionInfoEXT; + +typedef struct VkSubresourceHostMemcpySize { VkStructureType sType; - void * pNext; - uint32_t maxPerSetDescriptors; - VkDeviceSize maxMemoryAllocationSize; -} VkPhysicalDeviceMaintenance3Properties; + void * pNext; + VkDeviceSize size; +} VkSubresourceHostMemcpySize; -typedef struct VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; +typedef struct VkSubresourceHostMemcpySize VkSubresourceHostMemcpySizeEXT; -typedef struct VkDescriptorSetLayoutSupport { +typedef struct VkHostImageCopyDevicePerformanceQuery { VkStructureType sType; - void * pNext; - VkBool32 supported; -} VkDescriptorSetLayoutSupport; + void * pNext; + VkBool32 optimalDeviceAccess; + VkBool32 identicalMemoryLayout; +} VkHostImageCopyDevicePerformanceQuery; -typedef struct VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; +typedef struct VkHostImageCopyDevicePerformanceQuery VkHostImageCopyDevicePerformanceQueryEXT; -typedef struct VkPhysicalDeviceShaderDrawParametersFeatures { +typedef struct VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 shaderDrawParameters; -} VkPhysicalDeviceShaderDrawParametersFeatures; + void * pNext; + VkBool32 primitivesGeneratedQuery; + VkBool32 primitivesGeneratedQueryWithRasterizerDiscard; + VkBool32 primitivesGeneratedQueryWithNonZeroStreams; +} VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT; -typedef struct VkPhysicalDeviceShaderDrawParametersFeatures VkPhysicalDeviceShaderDrawParameterFeatures; +typedef struct VkPhysicalDeviceLegacyDitheringFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 legacyDithering; +} VkPhysicalDeviceLegacyDitheringFeaturesEXT; -typedef struct VkPhysicalDeviceShaderFloat16Int8Features { +typedef struct VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 shaderFloat16; - VkBool32 shaderInt8; -} VkPhysicalDeviceShaderFloat16Int8Features; + void * pNext; + VkBool32 multisampledRenderToSingleSampled; +} VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT; -typedef struct VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceShaderFloat16Int8FeaturesKHR; +typedef struct VkSubpassResolvePerformanceQueryEXT { + VkStructureType sType; + void * pNext; + VkBool32 optimal; +} VkSubpassResolvePerformanceQueryEXT; -typedef struct VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceFloat16Int8FeaturesKHR; +typedef struct VkMultisampledRenderToSingleSampledInfoEXT { + VkStructureType sType; + const void * pNext; + VkBool32 multisampledRenderToSingleSampledEnable; + VkSampleCountFlagBits rasterizationSamples; +} VkMultisampledRenderToSingleSampledInfoEXT; -typedef struct VkPhysicalDeviceFloatControlsProperties { +typedef struct VkPhysicalDevicePipelineProtectedAccessFeatures { VkStructureType sType; - void * pNext; - VkShaderFloatControlsIndependence denormBehaviorIndependence; - VkShaderFloatControlsIndependence roundingModeIndependence; - VkBool32 shaderSignedZeroInfNanPreserveFloat16; - VkBool32 shaderSignedZeroInfNanPreserveFloat32; - VkBool32 shaderSignedZeroInfNanPreserveFloat64; - VkBool32 shaderDenormPreserveFloat16; - VkBool32 shaderDenormPreserveFloat32; - VkBool32 shaderDenormPreserveFloat64; - VkBool32 shaderDenormFlushToZeroFloat16; - VkBool32 shaderDenormFlushToZeroFloat32; - VkBool32 shaderDenormFlushToZeroFloat64; - VkBool32 shaderRoundingModeRTEFloat16; - VkBool32 shaderRoundingModeRTEFloat32; - VkBool32 shaderRoundingModeRTEFloat64; - VkBool32 shaderRoundingModeRTZFloat16; - VkBool32 shaderRoundingModeRTZFloat32; - VkBool32 shaderRoundingModeRTZFloat64; -} VkPhysicalDeviceFloatControlsProperties; + void * pNext; + VkBool32 pipelineProtectedAccess; +} VkPhysicalDevicePipelineProtectedAccessFeatures; -typedef struct VkPhysicalDeviceFloatControlsProperties VkPhysicalDeviceFloatControlsPropertiesKHR; +typedef struct VkPhysicalDevicePipelineProtectedAccessFeatures VkPhysicalDevicePipelineProtectedAccessFeaturesEXT; -typedef struct VkPhysicalDeviceHostQueryResetFeatures { +typedef struct VkPhysicalDeviceInheritedViewportScissorFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 inheritedViewportScissor2D; +} VkPhysicalDeviceInheritedViewportScissorFeaturesNV; + +typedef struct VkCommandBufferInheritanceViewportScissorInfoNV { + VkStructureType sType; + const void * pNext; + VkBool32 viewportScissor2D; + uint32_t viewportDepthCount; + const VkViewport * pViewportDepths; +} VkCommandBufferInheritanceViewportScissorInfoNV; + +typedef struct VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT { VkStructureType sType; void * pNext; - VkBool32 hostQueryReset; -} VkPhysicalDeviceHostQueryResetFeatures; + VkBool32 ycbcr2plane444Formats; +} VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT; -typedef struct VkPhysicalDeviceHostQueryResetFeatures VkPhysicalDeviceHostQueryResetFeaturesEXT; +typedef struct VkPhysicalDeviceProvokingVertexFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 provokingVertexLast; + VkBool32 transformFeedbackPreservesProvokingVertex; +} VkPhysicalDeviceProvokingVertexFeaturesEXT; -typedef struct VkShaderStatisticsInfoAMD { - VkShaderStageFlags shaderStageMask; - VkShaderResourceUsageAMD resourceUsage; - uint32_t numPhysicalVgprs; - uint32_t numPhysicalSgprs; - uint32_t numAvailableVgprs; - uint32_t numAvailableSgprs; - uint32_t computeWorkGroupSize [3]; -} VkShaderStatisticsInfoAMD; +typedef struct VkPhysicalDeviceProvokingVertexPropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 provokingVertexModePerPipeline; + VkBool32 transformFeedbackPreservesTriangleFanProvokingVertex; +} VkPhysicalDeviceProvokingVertexPropertiesEXT; -typedef struct VkDebugUtilsMessengerCallbackDataEXT { +typedef struct VkCuModuleTexturingModeCreateInfoNVX { VkStructureType sType; - const void * pNext; - VkDebugUtilsMessengerCallbackDataFlagsEXT flags; - const char * pMessageIdName; - int32_t messageIdNumber; - const char * pMessage; - uint32_t queueLabelCount; - const VkDebugUtilsLabelEXT * pQueueLabels; - uint32_t cmdBufLabelCount; - const VkDebugUtilsLabelEXT * pCmdBufLabels; - uint32_t objectCount; - const VkDebugUtilsObjectNameInfoEXT * pObjects; -} VkDebugUtilsMessengerCallbackDataEXT; + const void * pNext; + VkBool32 use64bitTexturing; +} VkCuModuleTexturingModeCreateInfoNVX; -typedef struct VkPhysicalDeviceExternalMemoryHostPropertiesEXT { +typedef struct VkPhysicalDeviceDescriptorBufferFeaturesEXT { VkStructureType sType; - void * pNext; - VkDeviceSize minImportedHostPointerAlignment; -} VkPhysicalDeviceExternalMemoryHostPropertiesEXT; + void * pNext; + VkBool32 descriptorBuffer; + VkBool32 descriptorBufferCaptureReplay; + VkBool32 descriptorBufferImageLayoutIgnored; + VkBool32 descriptorBufferPushDescriptors; +} VkPhysicalDeviceDescriptorBufferFeaturesEXT; -typedef struct VkPhysicalDeviceConservativeRasterizationPropertiesEXT { +typedef struct VkPhysicalDeviceDescriptorBufferPropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 combinedImageSamplerDescriptorSingleArray; + VkBool32 bufferlessPushDescriptors; + VkBool32 allowSamplerImageViewPostSubmitCreation; + VkDeviceSize descriptorBufferOffsetAlignment; + uint32_t maxDescriptorBufferBindings; + uint32_t maxResourceDescriptorBufferBindings; + uint32_t maxSamplerDescriptorBufferBindings; + uint32_t maxEmbeddedImmutableSamplerBindings; + uint32_t maxEmbeddedImmutableSamplers; + size_t bufferCaptureReplayDescriptorDataSize; + size_t imageCaptureReplayDescriptorDataSize; + size_t imageViewCaptureReplayDescriptorDataSize; + size_t samplerCaptureReplayDescriptorDataSize; + size_t accelerationStructureCaptureReplayDescriptorDataSize; + size_t samplerDescriptorSize; + size_t combinedImageSamplerDescriptorSize; + size_t sampledImageDescriptorSize; + size_t storageImageDescriptorSize; + size_t uniformTexelBufferDescriptorSize; + size_t robustUniformTexelBufferDescriptorSize; + size_t storageTexelBufferDescriptorSize; + size_t robustStorageTexelBufferDescriptorSize; + size_t uniformBufferDescriptorSize; + size_t robustUniformBufferDescriptorSize; + size_t storageBufferDescriptorSize; + size_t robustStorageBufferDescriptorSize; + size_t inputAttachmentDescriptorSize; + size_t accelerationStructureDescriptorSize; + VkDeviceSize maxSamplerDescriptorBufferRange; + VkDeviceSize maxResourceDescriptorBufferRange; + VkDeviceSize samplerDescriptorBufferAddressSpaceSize; + VkDeviceSize resourceDescriptorBufferAddressSpaceSize; + VkDeviceSize descriptorBufferAddressSpaceSize; +} VkPhysicalDeviceDescriptorBufferPropertiesEXT; + +typedef struct VkDescriptorAddressInfoEXT { + VkStructureType sType; + void * pNext; + VkDeviceAddress address; + VkDeviceSize range; + VkFormat format; +} VkDescriptorAddressInfoEXT; + +typedef struct VkDescriptorBufferBindingInfoEXT { + VkStructureType sType; + const void * pNext; + VkDeviceAddress address; + VkBufferUsageFlags usage; +} VkDescriptorBufferBindingInfoEXT; + +typedef union VkDescriptorDataEXT { + const VkSampler * pSampler; + const VkDescriptorImageInfo * pCombinedImageSampler; + const VkDescriptorImageInfo * pInputAttachmentImage; + const VkDescriptorImageInfo * pSampledImage; + const VkDescriptorImageInfo * pStorageImage; + const VkDescriptorAddressInfoEXT * pUniformTexelBuffer; + const VkDescriptorAddressInfoEXT * pStorageTexelBuffer; + const VkDescriptorAddressInfoEXT * pUniformBuffer; + const VkDescriptorAddressInfoEXT * pStorageBuffer; + VkDeviceAddress accelerationStructure; +} VkDescriptorDataEXT; + +typedef struct VkDescriptorGetInfoEXT { + VkStructureType sType; + const void * pNext; + VkDescriptorType type; + VkDescriptorDataEXT data; +} VkDescriptorGetInfoEXT; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductFeatures { + VkStructureType sType; + void * pNext; + VkBool32 shaderIntegerDotProduct; +} VkPhysicalDeviceShaderIntegerDotProductFeatures; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductFeatures VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductProperties { + VkStructureType sType; + void * pNext; + VkBool32 integerDotProduct8BitUnsignedAccelerated; + VkBool32 integerDotProduct8BitSignedAccelerated; + VkBool32 integerDotProduct8BitMixedSignednessAccelerated; + VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; + VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProduct16BitUnsignedAccelerated; + VkBool32 integerDotProduct16BitSignedAccelerated; + VkBool32 integerDotProduct16BitMixedSignednessAccelerated; + VkBool32 integerDotProduct32BitUnsignedAccelerated; + VkBool32 integerDotProduct32BitSignedAccelerated; + VkBool32 integerDotProduct32BitMixedSignednessAccelerated; + VkBool32 integerDotProduct64BitUnsignedAccelerated; + VkBool32 integerDotProduct64BitSignedAccelerated; + VkBool32 integerDotProduct64BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; + VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; +} VkPhysicalDeviceShaderIntegerDotProductProperties; + +typedef struct VkPhysicalDeviceShaderIntegerDotProductProperties VkPhysicalDeviceShaderIntegerDotProductPropertiesKHR; + +typedef struct VkPhysicalDeviceDrmPropertiesEXT { VkStructureType sType; - void * pNext; - float primitiveOverestimationSize; - float maxExtraPrimitiveOverestimationSize; - float extraPrimitiveOverestimationSizeGranularity; - VkBool32 primitiveUnderestimation; - VkBool32 conservativePointAndLineRasterization; - VkBool32 degenerateTrianglesRasterized; - VkBool32 degenerateLinesRasterized; - VkBool32 fullyCoveredFragmentShaderInputVariable; - VkBool32 conservativeRasterizationPostDepthCoverage; -} VkPhysicalDeviceConservativeRasterizationPropertiesEXT; + void * pNext; + VkBool32 hasPrimary; + VkBool32 hasRender; + int64_t primaryMajor; + int64_t primaryMinor; + int64_t renderMajor; + int64_t renderMinor; +} VkPhysicalDeviceDrmPropertiesEXT; -typedef struct VkPhysicalDeviceShaderCoreProperties2AMD { +typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR { VkStructureType sType; - void * pNext; - VkShaderCorePropertiesFlagsAMD shaderCoreFeatures; - uint32_t activeComputeUnitCount; -} VkPhysicalDeviceShaderCoreProperties2AMD; + void * pNext; + VkBool32 fragmentShaderBarycentric; +} VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR; -typedef struct VkPipelineRasterizationConservativeStateCreateInfoEXT { +typedef struct VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR { VkStructureType sType; - const void * pNext; - VkPipelineRasterizationConservativeStateCreateFlagsEXT flags; - VkConservativeRasterizationModeEXT conservativeRasterizationMode; - float extraPrimitiveOverestimationSize; -} VkPipelineRasterizationConservativeStateCreateInfoEXT; + void * pNext; + VkBool32 triStripVertexOrderIndependentOfProvokingVertex; +} VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR; -typedef struct VkPhysicalDeviceDescriptorIndexingFeatures { +typedef struct VkPhysicalDeviceRayTracingMotionBlurFeaturesNV { VkStructureType sType; - void * pNext; - VkBool32 shaderInputAttachmentArrayDynamicIndexing; - VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; - VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; - VkBool32 shaderUniformBufferArrayNonUniformIndexing; - VkBool32 shaderSampledImageArrayNonUniformIndexing; - VkBool32 shaderStorageBufferArrayNonUniformIndexing; - VkBool32 shaderStorageImageArrayNonUniformIndexing; - VkBool32 shaderInputAttachmentArrayNonUniformIndexing; - VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; - VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; - VkBool32 descriptorBindingUniformBufferUpdateAfterBind; - VkBool32 descriptorBindingSampledImageUpdateAfterBind; - VkBool32 descriptorBindingStorageImageUpdateAfterBind; - VkBool32 descriptorBindingStorageBufferUpdateAfterBind; - VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingUpdateUnusedWhilePending; - VkBool32 descriptorBindingPartiallyBound; - VkBool32 descriptorBindingVariableDescriptorCount; - VkBool32 runtimeDescriptorArray; -} VkPhysicalDeviceDescriptorIndexingFeatures; + void * pNext; + VkBool32 rayTracingMotionBlur; + VkBool32 rayTracingMotionBlurPipelineTraceRaysIndirect; +} VkPhysicalDeviceRayTracingMotionBlurFeaturesNV; -typedef struct VkPhysicalDeviceDescriptorIndexingFeatures VkPhysicalDeviceDescriptorIndexingFeaturesEXT; +typedef struct VkPhysicalDeviceRayTracingValidationFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 rayTracingValidation; +} VkPhysicalDeviceRayTracingValidationFeaturesNV; -typedef struct VkPhysicalDeviceDescriptorIndexingProperties { +typedef struct VkPhysicalDeviceRayTracingLinearSweptSpheresFeaturesNV { VkStructureType sType; - void * pNext; - uint32_t maxUpdateAfterBindDescriptorsInAllPools; - VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; - VkBool32 shaderSampledImageArrayNonUniformIndexingNative; - VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; - VkBool32 shaderStorageImageArrayNonUniformIndexingNative; - VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; - VkBool32 robustBufferAccessUpdateAfterBind; - VkBool32 quadDivergentImplicitLod; - uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; - uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; - uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; - uint32_t maxPerStageUpdateAfterBindResources; - uint32_t maxDescriptorSetUpdateAfterBindSamplers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindSampledImages; - uint32_t maxDescriptorSetUpdateAfterBindStorageImages; - uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; -} VkPhysicalDeviceDescriptorIndexingProperties; + void * pNext; + VkBool32 spheres; + VkBool32 linearSweptSpheres; +} VkPhysicalDeviceRayTracingLinearSweptSpheresFeaturesNV; -typedef struct VkPhysicalDeviceDescriptorIndexingProperties VkPhysicalDeviceDescriptorIndexingPropertiesEXT; +typedef struct VkAccelerationStructureGeometryMotionTrianglesDataNV { + VkStructureType sType; + const void * pNext; + VkDeviceOrHostAddressConstKHR vertexData; +} VkAccelerationStructureGeometryMotionTrianglesDataNV; -typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo { +typedef struct VkAccelerationStructureMotionInfoNV { VkStructureType sType; - const void * pNext; - uint32_t bindingCount; - const VkDescriptorBindingFlags * pBindingFlags; -} VkDescriptorSetLayoutBindingFlagsCreateInfo; + const void * pNext; + uint32_t maxInstances; + VkAccelerationStructureMotionInfoFlagsNV flags; +} VkAccelerationStructureMotionInfoNV; -typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo VkDescriptorSetLayoutBindingFlagsCreateInfoEXT; +typedef struct VkAccelerationStructureSRTMotionInstanceNV { + VkSRTDataNV transformT0; + VkSRTDataNV transformT1; + uint32_t instanceCustomIndex :24; + uint32_t mask :8; + uint32_t instanceShaderBindingTableRecordOffset :24; + VkGeometryInstanceFlagsKHR flags :8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureSRTMotionInstanceNV; -typedef struct VkAttachmentDescription2 { - VkStructureType sType; - const void * pNext; - VkAttachmentDescriptionFlags flags; - VkFormat format; - VkSampleCountFlagBits samples; - VkAttachmentLoadOp loadOp; - VkAttachmentStoreOp storeOp; - VkAttachmentLoadOp stencilLoadOp; - VkAttachmentStoreOp stencilStoreOp; - VkImageLayout initialLayout; - VkImageLayout finalLayout; -} VkAttachmentDescription2; +typedef struct VkAccelerationStructureMatrixMotionInstanceNV { + VkTransformMatrixKHR transformT0; + VkTransformMatrixKHR transformT1; + uint32_t instanceCustomIndex :24; + uint32_t mask :8; + uint32_t instanceShaderBindingTableRecordOffset :24; + VkGeometryInstanceFlagsKHR flags :8; + uint64_t accelerationStructureReference; +} VkAccelerationStructureMatrixMotionInstanceNV; -typedef struct VkAttachmentDescription2 VkAttachmentDescription2KHR; +typedef union VkAccelerationStructureMotionInstanceDataNV { + VkAccelerationStructureInstanceKHR staticInstance; + VkAccelerationStructureMatrixMotionInstanceNV matrixMotionInstance; + VkAccelerationStructureSRTMotionInstanceNV srtMotionInstance; +} VkAccelerationStructureMotionInstanceDataNV; -typedef struct VkAttachmentReference2 { +typedef struct VkAccelerationStructureMotionInstanceNV { + VkAccelerationStructureMotionInstanceTypeNV type; + VkAccelerationStructureMotionInstanceFlagsNV flags; + VkAccelerationStructureMotionInstanceDataNV data; +} VkAccelerationStructureMotionInstanceNV; + +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkBufferCollectionPropertiesFUCHSIA { VkStructureType sType; - const void * pNext; - uint32_t attachment; - VkImageLayout layout; - VkImageAspectFlags aspectMask; -} VkAttachmentReference2; + void * pNext; + uint32_t memoryTypeBits; + uint32_t bufferCount; + uint32_t createInfoIndex; + uint64_t sysmemPixelFormat; + VkFormatFeatureFlags formatFeatures; + VkSysmemColorSpaceFUCHSIA sysmemColorSpaceIndex; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkBufferCollectionPropertiesFUCHSIA; -typedef struct VkAttachmentReference2 VkAttachmentReference2KHR; +#endif -typedef struct VkSubpassDescription2 { +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkBufferConstraintsInfoFUCHSIA { VkStructureType sType; - const void * pNext; - VkSubpassDescriptionFlags flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t viewMask; - uint32_t inputAttachmentCount; - const VkAttachmentReference2 * pInputAttachments; - uint32_t colorAttachmentCount; - const VkAttachmentReference2 * pColorAttachments; - const VkAttachmentReference2 * pResolveAttachments; - const VkAttachmentReference2 * pDepthStencilAttachment; - uint32_t preserveAttachmentCount; - const uint32_t * pPreserveAttachments; -} VkSubpassDescription2; + const void * pNext; + VkBufferCreateInfo createInfo; + VkFormatFeatureFlags requiredFormatFeatures; + VkBufferCollectionConstraintsInfoFUCHSIA bufferCollectionConstraints; +} VkBufferConstraintsInfoFUCHSIA; -typedef struct VkSubpassDescription2 VkSubpassDescription2KHR; +#endif -typedef struct VkSubpassDependency2 { +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkImageFormatConstraintsInfoFUCHSIA { VkStructureType sType; - const void * pNext; - uint32_t srcSubpass; - uint32_t dstSubpass; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkDependencyFlags dependencyFlags; - int32_t viewOffset; -} VkSubpassDependency2; + const void * pNext; + VkImageCreateInfo imageCreateInfo; + VkFormatFeatureFlags requiredFormatFeatures; + VkImageFormatConstraintsFlagsFUCHSIA flags; + uint64_t sysmemPixelFormat; + uint32_t colorSpaceCount; + const VkSysmemColorSpaceFUCHSIA * pColorSpaces; +} VkImageFormatConstraintsInfoFUCHSIA; -typedef struct VkSubpassDependency2 VkSubpassDependency2KHR; +#endif -typedef struct VkRenderPassCreateInfo2 { +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef struct VkImageConstraintsInfoFUCHSIA { VkStructureType sType; - const void * pNext; - VkRenderPassCreateFlags flags; - uint32_t attachmentCount; - const VkAttachmentDescription2 * pAttachments; - uint32_t subpassCount; - const VkSubpassDescription2 * pSubpasses; - uint32_t dependencyCount; - const VkSubpassDependency2 * pDependencies; - uint32_t correlatedViewMaskCount; - const uint32_t * pCorrelatedViewMasks; -} VkRenderPassCreateInfo2; + const void * pNext; + uint32_t formatConstraintsCount; + const VkImageFormatConstraintsInfoFUCHSIA * pFormatConstraints; + VkBufferCollectionConstraintsInfoFUCHSIA bufferCollectionConstraints; + VkImageConstraintsInfoFlagsFUCHSIA flags; +} VkImageConstraintsInfoFUCHSIA; -typedef struct VkRenderPassCreateInfo2 VkRenderPassCreateInfo2KHR; +#endif -typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures { +typedef struct VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 timelineSemaphore; -} VkPhysicalDeviceTimelineSemaphoreFeatures; - -typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures VkPhysicalDeviceTimelineSemaphoreFeaturesKHR; + void * pNext; + VkBool32 formatRgba10x6WithoutYCbCrSampler; +} VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT; -typedef struct VkSemaphoreWaitInfo { +typedef struct VkFormatProperties3 { VkStructureType sType; - const void * pNext; - VkSemaphoreWaitFlags flags; - uint32_t semaphoreCount; - const VkSemaphore * pSemaphores; - const uint64_t * pValues; -} VkSemaphoreWaitInfo; + void * pNext; + VkFormatFeatureFlags2 linearTilingFeatures; + VkFormatFeatureFlags2 optimalTilingFeatures; + VkFormatFeatureFlags2 bufferFeatures; +} VkFormatProperties3; -typedef struct VkSemaphoreWaitInfo VkSemaphoreWaitInfoKHR; +typedef struct VkFormatProperties3 VkFormatProperties3KHR; -#if defined(VK_USE_PLATFORM_ANDROID_KHR) -typedef struct VkAndroidHardwareBufferPropertiesANDROID { - VkStructureType sType; - void * pNext; - VkDeviceSize allocationSize; - uint32_t memoryTypeBits; -} VkAndroidHardwareBufferPropertiesANDROID; -#endif +typedef struct VkDrmFormatModifierProperties2EXT { + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + VkFormatFeatureFlags2 drmFormatModifierTilingFeatures; +} VkDrmFormatModifierProperties2EXT; #if defined(VK_USE_PLATFORM_ANDROID_KHR) -typedef struct VkAndroidHardwareBufferFormatPropertiesANDROID { +typedef struct VkAndroidHardwareBufferFormatProperties2ANDROID { VkStructureType sType; void * pNext; VkFormat format; uint64_t externalFormat; - VkFormatFeatureFlags formatFeatures; + VkFormatFeatureFlags2 formatFeatures; VkComponentMapping samplerYcbcrConversionComponents; VkSamplerYcbcrModelConversion suggestedYcbcrModel; VkSamplerYcbcrRange suggestedYcbcrRange; VkChromaLocation suggestedXChromaOffset; VkChromaLocation suggestedYChromaOffset; -} VkAndroidHardwareBufferFormatPropertiesANDROID; +} VkAndroidHardwareBufferFormatProperties2ANDROID; + #endif -typedef struct VkCommandBufferInheritanceConditionalRenderingInfoEXT { +typedef struct VkRenderingInfo { + VkStructureType sType; + const void * pNext; + VkRenderingFlags flags; + VkRect2D renderArea; + uint32_t layerCount; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkRenderingAttachmentInfo * pColorAttachments; + const VkRenderingAttachmentInfo * pDepthAttachment; + const VkRenderingAttachmentInfo * pStencilAttachment; +} VkRenderingInfo; + +typedef struct VkRenderingInfo VkRenderingInfoKHR; + +typedef struct VkPhysicalDeviceDynamicRenderingFeatures { VkStructureType sType; - const void * pNext; - VkBool32 conditionalRenderingEnable; -} VkCommandBufferInheritanceConditionalRenderingInfoEXT; + void * pNext; + VkBool32 dynamicRendering; +} VkPhysicalDeviceDynamicRenderingFeatures; -typedef struct VkPhysicalDevice8BitStorageFeatures { +typedef struct VkPhysicalDeviceDynamicRenderingFeatures VkPhysicalDeviceDynamicRenderingFeaturesKHR; + +typedef struct VkCommandBufferInheritanceRenderingInfo { VkStructureType sType; - void * pNext; - VkBool32 storageBuffer8BitAccess; - VkBool32 uniformAndStorageBuffer8BitAccess; - VkBool32 storagePushConstant8; -} VkPhysicalDevice8BitStorageFeatures; + const void * pNext; + VkRenderingFlags flags; + uint32_t viewMask; + uint32_t colorAttachmentCount; + const VkFormat * pColorAttachmentFormats; + VkFormat depthAttachmentFormat; + VkFormat stencilAttachmentFormat; + VkSampleCountFlagBits rasterizationSamples; +} VkCommandBufferInheritanceRenderingInfo; -typedef struct VkPhysicalDevice8BitStorageFeatures VkPhysicalDevice8BitStorageFeaturesKHR; +typedef struct VkCommandBufferInheritanceRenderingInfo VkCommandBufferInheritanceRenderingInfoKHR; -typedef struct VkPhysicalDeviceConditionalRenderingFeaturesEXT { +typedef struct VkMultiviewPerViewAttributesInfoNVX { + VkStructureType sType; + const void * pNext; + VkBool32 perViewAttributes; + VkBool32 perViewAttributesPositionXOnly; +} VkMultiviewPerViewAttributesInfoNVX; + +typedef struct VkPhysicalDeviceImageViewMinLodFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 minLod; +} VkPhysicalDeviceImageViewMinLodFeaturesEXT; + +typedef struct VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 rasterizationOrderColorAttachmentAccess; + VkBool32 rasterizationOrderDepthAttachmentAccess; + VkBool32 rasterizationOrderStencilAttachmentAccess; +} VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT; + +typedef struct VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM; + +typedef struct VkPhysicalDeviceLinearColorAttachmentFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 linearColorAttachment; +} VkPhysicalDeviceLinearColorAttachmentFeaturesNV; + +typedef struct VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT { VkStructureType sType; void * pNext; - VkBool32 conditionalRendering; - VkBool32 inheritedConditionalRendering; -} VkPhysicalDeviceConditionalRenderingFeaturesEXT; + VkBool32 graphicsPipelineLibrary; +} VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT; -typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures { +typedef struct VkPhysicalDevicePipelineBinaryFeaturesKHR { VkStructureType sType; - void * pNext; - VkBool32 vulkanMemoryModel; - VkBool32 vulkanMemoryModelDeviceScope; - VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; -} VkPhysicalDeviceVulkanMemoryModelFeatures; + void * pNext; + VkBool32 pipelineBinaries; +} VkPhysicalDevicePipelineBinaryFeaturesKHR; -typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures VkPhysicalDeviceVulkanMemoryModelFeaturesKHR; +typedef struct VkDevicePipelineBinaryInternalCacheControlKHR { + VkStructureType sType; + const void * pNext; + VkBool32 disableInternalCache; +} VkDevicePipelineBinaryInternalCacheControlKHR; -typedef struct VkPhysicalDeviceShaderAtomicInt64Features { +typedef struct VkPhysicalDevicePipelineBinaryPropertiesKHR { VkStructureType sType; - void * pNext; - VkBool32 shaderBufferInt64Atomics; - VkBool32 shaderSharedInt64Atomics; -} VkPhysicalDeviceShaderAtomicInt64Features; + void * pNext; + VkBool32 pipelineBinaryInternalCache; + VkBool32 pipelineBinaryInternalCacheControl; + VkBool32 pipelineBinaryPrefersInternalCache; + VkBool32 pipelineBinaryPrecompiledInternalCache; + VkBool32 pipelineBinaryCompressedData; +} VkPhysicalDevicePipelineBinaryPropertiesKHR; -typedef struct VkPhysicalDeviceShaderAtomicInt64Features VkPhysicalDeviceShaderAtomicInt64FeaturesKHR; +typedef struct VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT { + VkStructureType sType; + void * pNext; + VkBool32 graphicsPipelineLibraryFastLinking; + VkBool32 graphicsPipelineLibraryIndependentInterpolationDecoration; +} VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT; -typedef struct VkPhysicalDeviceShaderAtomicFloatFeaturesEXT { +typedef struct VkGraphicsPipelineLibraryCreateInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 shaderBufferFloat32Atomics; - VkBool32 shaderBufferFloat32AtomicAdd; - VkBool32 shaderBufferFloat64Atomics; - VkBool32 shaderBufferFloat64AtomicAdd; - VkBool32 shaderSharedFloat32Atomics; - VkBool32 shaderSharedFloat32AtomicAdd; - VkBool32 shaderSharedFloat64Atomics; - VkBool32 shaderSharedFloat64AtomicAdd; - VkBool32 shaderImageFloat32Atomics; - VkBool32 shaderImageFloat32AtomicAdd; - VkBool32 sparseImageFloat32Atomics; - VkBool32 sparseImageFloat32AtomicAdd; -} VkPhysicalDeviceShaderAtomicFloatFeaturesEXT; + const void * pNext; + VkGraphicsPipelineLibraryFlagsEXT flags; +} VkGraphicsPipelineLibraryCreateInfoEXT; + +typedef struct VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE { + VkStructureType sType; + void * pNext; + VkBool32 descriptorSetHostMapping; +} VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE; -typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT { +typedef struct VkPhysicalDeviceNestedCommandBufferFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 vertexAttributeInstanceRateDivisor; - VkBool32 vertexAttributeInstanceRateZeroDivisor; -} VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT; + void * pNext; + VkBool32 nestedCommandBuffer; + VkBool32 nestedCommandBufferRendering; + VkBool32 nestedCommandBufferSimultaneousUse; +} VkPhysicalDeviceNestedCommandBufferFeaturesEXT; -typedef struct VkQueueFamilyCheckpointPropertiesNV { +typedef struct VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT { VkStructureType sType; - void * pNext; - VkPipelineStageFlags checkpointExecutionStageMask; -} VkQueueFamilyCheckpointPropertiesNV; + void * pNext; + VkBool32 shaderModuleIdentifier; +} VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT; -typedef struct VkPhysicalDeviceDepthStencilResolveProperties { +typedef struct VkImageCompressionControlEXT { VkStructureType sType; - void * pNext; - VkResolveModeFlags supportedDepthResolveModes; - VkResolveModeFlags supportedStencilResolveModes; - VkBool32 independentResolveNone; - VkBool32 independentResolve; -} VkPhysicalDeviceDepthStencilResolveProperties; + const void * pNext; + VkImageCompressionFlagsEXT flags; + uint32_t compressionControlPlaneCount; + VkImageCompressionFixedRateFlagsEXT * pFixedRateFlags; +} VkImageCompressionControlEXT; -typedef struct VkPhysicalDeviceDepthStencilResolveProperties VkPhysicalDeviceDepthStencilResolvePropertiesKHR; +typedef struct VkPhysicalDeviceImageCompressionControlFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 imageCompressionControl; +} VkPhysicalDeviceImageCompressionControlFeaturesEXT; -typedef struct VkSubpassDescriptionDepthStencilResolve { +typedef struct VkImageCompressionPropertiesEXT { VkStructureType sType; - const void * pNext; - VkResolveModeFlagBits depthResolveMode; - VkResolveModeFlagBits stencilResolveMode; - const VkAttachmentReference2 * pDepthStencilResolveAttachment; -} VkSubpassDescriptionDepthStencilResolve; + void * pNext; + VkImageCompressionFlagsEXT imageCompressionFlags; + VkImageCompressionFixedRateFlagsEXT imageCompressionFixedRateFlags; +} VkImageCompressionPropertiesEXT; -typedef struct VkSubpassDescriptionDepthStencilResolve VkSubpassDescriptionDepthStencilResolveKHR; +typedef struct VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 imageCompressionControlSwapchain; +} VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT; -typedef struct VkPhysicalDeviceASTCDecodeFeaturesEXT { +typedef struct VkImageSubresource2 { VkStructureType sType; - void * pNext; - VkBool32 decodeModeSharedExponent; -} VkPhysicalDeviceASTCDecodeFeaturesEXT; + void * pNext; + VkImageSubresource imageSubresource; +} VkImageSubresource2; -typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT { +typedef struct VkImageSubresource2 VkImageSubresource2KHR; + +typedef struct VkImageSubresource2 VkImageSubresource2EXT; + +typedef struct VkSubresourceLayout2 { VkStructureType sType; - void * pNext; - VkBool32 transformFeedback; - VkBool32 geometryStreams; -} VkPhysicalDeviceTransformFeedbackFeaturesEXT; + void * pNext; + VkSubresourceLayout subresourceLayout; +} VkSubresourceLayout2; -typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT { +typedef struct VkSubresourceLayout2 VkSubresourceLayout2KHR; + +typedef struct VkSubresourceLayout2 VkSubresourceLayout2EXT; + +typedef struct VkRenderPassCreationControlEXT { VkStructureType sType; - void * pNext; - uint32_t maxTransformFeedbackStreams; - uint32_t maxTransformFeedbackBuffers; - VkDeviceSize maxTransformFeedbackBufferSize; - uint32_t maxTransformFeedbackStreamDataSize; - uint32_t maxTransformFeedbackBufferDataSize; - uint32_t maxTransformFeedbackBufferDataStride; - VkBool32 transformFeedbackQueries; - VkBool32 transformFeedbackStreamsLinesTriangles; - VkBool32 transformFeedbackRasterizationStreamSelect; - VkBool32 transformFeedbackDraw; -} VkPhysicalDeviceTransformFeedbackPropertiesEXT; + const void * pNext; + VkBool32 disallowMerging; +} VkRenderPassCreationControlEXT; -typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT { +typedef struct VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT { VkStructureType sType; - const void * pNext; - VkPipelineRasterizationStateStreamCreateFlagsEXT flags; - uint32_t rasterizationStream; -} VkPipelineRasterizationStateStreamCreateInfoEXT; + void * pNext; + VkBool32 subpassMergeFeedback; +} VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT; -typedef struct VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV { - VkStructureType sType; - void * pNext; - VkBool32 representativeFragmentTest; -} VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV; +typedef struct VkMicromapBuildInfoEXT { + VkStructureType sType; + const void * pNext; + VkMicromapTypeEXT type; + VkBuildMicromapFlagsEXT flags; + VkBuildMicromapModeEXT mode; + VkMicromapEXT dstMicromap; + uint32_t usageCountsCount; + const VkMicromapUsageEXT * pUsageCounts; + const VkMicromapUsageEXT * const* ppUsageCounts; + VkDeviceOrHostAddressConstKHR data; + VkDeviceOrHostAddressKHR scratchData; + VkDeviceOrHostAddressConstKHR triangleArray; + VkDeviceSize triangleArrayStride; +} VkMicromapBuildInfoEXT; + +typedef struct VkMicromapCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkMicromapCreateFlagsEXT createFlags; + VkBuffer buffer; + VkDeviceSize offset; + VkDeviceSize size; + VkMicromapTypeEXT type; + VkDeviceAddress deviceAddress; +} VkMicromapCreateInfoEXT; -typedef struct VkPipelineRepresentativeFragmentTestStateCreateInfoNV { +typedef struct VkCopyMicromapToMemoryInfoEXT { VkStructureType sType; - const void * pNext; - VkBool32 representativeFragmentTestEnable; -} VkPipelineRepresentativeFragmentTestStateCreateInfoNV; + const void * pNext; + VkMicromapEXT src; + VkDeviceOrHostAddressKHR dst; + VkCopyMicromapModeEXT mode; +} VkCopyMicromapToMemoryInfoEXT; -typedef struct VkPhysicalDeviceExclusiveScissorFeaturesNV { +typedef struct VkCopyMemoryToMicromapInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 exclusiveScissor; -} VkPhysicalDeviceExclusiveScissorFeaturesNV; + const void * pNext; + VkDeviceOrHostAddressConstKHR src; + VkMicromapEXT dst; + VkCopyMicromapModeEXT mode; +} VkCopyMemoryToMicromapInfoEXT; -typedef struct VkPhysicalDeviceCornerSampledImageFeaturesNV { +typedef struct VkMicromapBuildSizesInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 cornerSampledImage; -} VkPhysicalDeviceCornerSampledImageFeaturesNV; + const void * pNext; + VkDeviceSize micromapSize; + VkDeviceSize buildScratchSize; + VkBool32 discardable; +} VkMicromapBuildSizesInfoEXT; -typedef struct VkPhysicalDeviceComputeShaderDerivativesFeaturesNV { +typedef struct VkPhysicalDeviceOpacityMicromapFeaturesEXT { VkStructureType sType; void * pNext; - VkBool32 computeDerivativeGroupQuads; - VkBool32 computeDerivativeGroupLinear; -} VkPhysicalDeviceComputeShaderDerivativesFeaturesNV; + VkBool32 micromap; + VkBool32 micromapCaptureReplay; + VkBool32 micromapHostCommands; +} VkPhysicalDeviceOpacityMicromapFeaturesEXT; + +typedef struct VkAccelerationStructureTrianglesOpacityMicromapEXT { + VkStructureType sType; + void * pNext; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexBuffer; + VkDeviceSize indexStride; + uint32_t baseTriangle; + uint32_t usageCountsCount; + const VkMicromapUsageEXT * pUsageCounts; + const VkMicromapUsageEXT * const* ppUsageCounts; + VkMicromapEXT micromap; +} VkAccelerationStructureTrianglesOpacityMicromapEXT; -typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDeviceDisplacementMicromapFeaturesNV { VkStructureType sType; void * pNext; - VkBool32 fragmentShaderBarycentric; -} VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV; + VkBool32 displacementMicromap; +} VkPhysicalDeviceDisplacementMicromapFeaturesNV; -typedef struct VkPhysicalDeviceShaderImageFootprintFeaturesNV { +#endif + +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkAccelerationStructureTrianglesDisplacementMicromapNV { VkStructureType sType; - void * pNext; - VkBool32 imageFootprint; -} VkPhysicalDeviceShaderImageFootprintFeaturesNV; + void * pNext; + VkFormat displacementBiasAndScaleFormat; + VkFormat displacementVectorFormat; + VkDeviceOrHostAddressConstKHR displacementBiasAndScaleBuffer; + VkDeviceSize displacementBiasAndScaleStride; + VkDeviceOrHostAddressConstKHR displacementVectorBuffer; + VkDeviceSize displacementVectorStride; + VkDeviceOrHostAddressConstKHR displacedMicromapPrimitiveFlags; + VkDeviceSize displacedMicromapPrimitiveFlagsStride; + VkIndexType indexType; + VkDeviceOrHostAddressConstKHR indexBuffer; + VkDeviceSize indexStride; + uint32_t baseTriangle; + uint32_t usageCountsCount; + const VkMicromapUsageEXT * pUsageCounts; + const VkMicromapUsageEXT * const* ppUsageCounts; + VkMicromapEXT micromap; +} VkAccelerationStructureTrianglesDisplacementMicromapNV; + +#endif + +typedef struct VkPhysicalDevicePipelinePropertiesFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 pipelinePropertiesIdentifier; +} VkPhysicalDevicePipelinePropertiesFeaturesEXT; -typedef struct VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV { +typedef struct VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD { VkStructureType sType; - void * pNext; - VkBool32 dedicatedAllocationImageAliasing; -} VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV; + void * pNext; + VkBool32 shaderEarlyAndLateFragmentTests; +} VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD; -typedef struct VkPipelineViewportShadingRateImageStateCreateInfoNV { +typedef struct VkExternalMemoryAcquireUnmodifiedEXT { VkStructureType sType; - const void * pNext; - VkBool32 shadingRateImageEnable; - uint32_t viewportCount; - const VkShadingRatePaletteNV * pShadingRatePalettes; -} VkPipelineViewportShadingRateImageStateCreateInfoNV; + const void * pNext; + VkBool32 acquireUnmodifiedMemory; +} VkExternalMemoryAcquireUnmodifiedEXT; -typedef struct VkPhysicalDeviceShadingRateImageFeaturesNV { +typedef struct VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 shadingRateImage; - VkBool32 shadingRateCoarseSampleOrder; -} VkPhysicalDeviceShadingRateImageFeaturesNV; + void * pNext; + VkBool32 nonSeamlessCubeMap; +} VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT; -typedef struct VkPhysicalDeviceMeshShaderFeaturesNV { +typedef struct VkPhysicalDevicePipelineRobustnessFeatures { VkStructureType sType; - void * pNext; - VkBool32 taskShader; - VkBool32 meshShader; -} VkPhysicalDeviceMeshShaderFeaturesNV; + void * pNext; + VkBool32 pipelineRobustness; +} VkPhysicalDevicePipelineRobustnessFeatures; -typedef struct VkRayTracingPipelineCreateInfoNV { +typedef struct VkPhysicalDevicePipelineRobustnessFeatures VkPhysicalDevicePipelineRobustnessFeaturesEXT; + +typedef struct VkPhysicalDeviceImageProcessingFeaturesQCOM { VkStructureType sType; - const void * pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo * pStages; - uint32_t groupCount; - const VkRayTracingShaderGroupCreateInfoNV * pGroups; - uint32_t maxRecursionDepth; - VkPipelineLayout layout; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkRayTracingPipelineCreateInfoNV; + void * pNext; + VkBool32 textureSampleWeighted; + VkBool32 textureBoxFilter; + VkBool32 textureBlockMatch; +} VkPhysicalDeviceImageProcessingFeaturesQCOM; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkRayTracingPipelineCreateInfoKHR { +typedef struct VkPhysicalDeviceTilePropertiesFeaturesQCOM { VkStructureType sType; - const void * pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo * pStages; - uint32_t groupCount; - const VkRayTracingShaderGroupCreateInfoKHR * pGroups; - uint32_t maxRecursionDepth; - VkPipelineLibraryCreateInfoKHR libraries; - const VkRayTracingPipelineInterfaceCreateInfoKHR * pLibraryInterface; - VkPipelineLayout layout; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkRayTracingPipelineCreateInfoKHR; -#endif + void * pNext; + VkBool32 tileProperties; +} VkPhysicalDeviceTilePropertiesFeaturesQCOM; -typedef struct VkGeometryTrianglesNV { +typedef struct VkPhysicalDeviceAmigoProfilingFeaturesSEC { VkStructureType sType; - const void * pNext; - VkBuffer vertexData; - VkDeviceSize vertexOffset; - uint32_t vertexCount; - VkDeviceSize vertexStride; - VkFormat vertexFormat; - VkBuffer indexData; - VkDeviceSize indexOffset; - uint32_t indexCount; - VkIndexType indexType; - VkBuffer transformData; - VkDeviceSize transformOffset; -} VkGeometryTrianglesNV; + void * pNext; + VkBool32 amigoProfiling; +} VkPhysicalDeviceAmigoProfilingFeaturesSEC; -typedef struct VkGeometryAABBNV { +typedef struct VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT { VkStructureType sType; - const void * pNext; - VkBuffer aabbData; - uint32_t numAABBs; - uint32_t stride; - VkDeviceSize offset; -} VkGeometryAABBNV; + void * pNext; + VkBool32 attachmentFeedbackLoopLayout; +} VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT; -typedef struct VkGeometryDataNV { - VkGeometryTrianglesNV triangles; - VkGeometryAABBNV aabbs; -} VkGeometryDataNV; +typedef struct VkPhysicalDeviceAddressBindingReportFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 reportAddressBinding; +} VkPhysicalDeviceAddressBindingReportFeaturesEXT; -typedef struct VkGeometryNV { +typedef struct VkDeviceAddressBindingCallbackDataEXT { VkStructureType sType; - const void * pNext; - VkGeometryTypeKHR geometryType; - VkGeometryDataNV geometry; - VkGeometryFlagsKHR flags; -} VkGeometryNV; + void * pNext; + VkDeviceAddressBindingFlagsEXT flags; + VkDeviceAddress baseAddress; + VkDeviceSize size; + VkDeviceAddressBindingTypeEXT bindingType; +} VkDeviceAddressBindingCallbackDataEXT; -typedef struct VkAccelerationStructureInfoNV { +typedef struct VkPhysicalDeviceOpticalFlowFeaturesNV { VkStructureType sType; - const void * pNext; - VkAccelerationStructureTypeNV type; - VkBuildAccelerationStructureFlagsNV flags; - uint32_t instanceCount; - uint32_t geometryCount; - const VkGeometryNV * pGeometries; -} VkAccelerationStructureInfoNV; + void * pNext; + VkBool32 opticalFlow; +} VkPhysicalDeviceOpticalFlowFeaturesNV; -typedef struct VkAccelerationStructureCreateInfoNV { +typedef struct VkPhysicalDeviceOpticalFlowPropertiesNV { VkStructureType sType; - const void * pNext; - VkDeviceSize compactedSize; - VkAccelerationStructureInfoNV info; -} VkAccelerationStructureCreateInfoNV; + void * pNext; + VkOpticalFlowGridSizeFlagsNV supportedOutputGridSizes; + VkOpticalFlowGridSizeFlagsNV supportedHintGridSizes; + VkBool32 hintSupported; + VkBool32 costSupported; + VkBool32 bidirectionalFlowSupported; + VkBool32 globalFlowSupported; + uint32_t minWidth; + uint32_t minHeight; + uint32_t maxWidth; + uint32_t maxHeight; + uint32_t maxNumRegionsOfInterest; +} VkPhysicalDeviceOpticalFlowPropertiesNV; + +typedef struct VkOpticalFlowImageFormatInfoNV { + VkStructureType sType; + const void * pNext; + VkOpticalFlowUsageFlagsNV usage; +} VkOpticalFlowImageFormatInfoNV; -typedef struct VkBindAccelerationStructureMemoryInfoKHR { +typedef struct VkOpticalFlowSessionCreateInfoNV { VkStructureType sType; - const void * pNext; - VkAccelerationStructureKHR accelerationStructure; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - uint32_t deviceIndexCount; - const uint32_t * pDeviceIndices; -} VkBindAccelerationStructureMemoryInfoKHR; + void * pNext; + uint32_t width; + uint32_t height; + VkFormat imageFormat; + VkFormat flowVectorFormat; + VkFormat costFormat; + VkOpticalFlowGridSizeFlagsNV outputGridSize; + VkOpticalFlowGridSizeFlagsNV hintGridSize; + VkOpticalFlowPerformanceLevelNV performanceLevel; + VkOpticalFlowSessionCreateFlagsNV flags; +} VkOpticalFlowSessionCreateInfoNV; -typedef struct VkBindAccelerationStructureMemoryInfoKHR VkBindAccelerationStructureMemoryInfoNV; +typedef struct VkOpticalFlowExecuteInfoNV { + VkStructureType sType; + void * pNext; + VkOpticalFlowExecuteFlagsNV flags; + uint32_t regionCount; + const VkRect2D * pRegions; +} VkOpticalFlowExecuteInfoNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkPhysicalDeviceRayTracingFeaturesKHR { +typedef struct VkPhysicalDeviceFaultFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 rayTracing; - VkBool32 rayTracingShaderGroupHandleCaptureReplay; - VkBool32 rayTracingShaderGroupHandleCaptureReplayMixed; - VkBool32 rayTracingAccelerationStructureCaptureReplay; - VkBool32 rayTracingIndirectTraceRays; - VkBool32 rayTracingIndirectAccelerationStructureBuild; - VkBool32 rayTracingHostAccelerationStructureCommands; - VkBool32 rayQuery; - VkBool32 rayTracingPrimitiveCulling; -} VkPhysicalDeviceRayTracingFeaturesKHR; -#endif + void * pNext; + VkBool32 deviceFault; + VkBool32 deviceFaultVendorBinary; +} VkPhysicalDeviceFaultFeaturesEXT; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkStridedBufferRegionKHR { - VkBuffer buffer; - VkDeviceSize offset; - VkDeviceSize stride; - VkDeviceSize size; -} VkStridedBufferRegionKHR; -#endif +typedef struct VkDeviceFaultAddressInfoEXT { + VkDeviceFaultAddressTypeEXT addressType; + VkDeviceAddress reportedAddress; + VkDeviceSize addressPrecision; +} VkDeviceFaultAddressInfoEXT; -typedef struct VkDrmFormatModifierPropertiesEXT { - uint64_t drmFormatModifier; - uint32_t drmFormatModifierPlaneCount; - VkFormatFeatureFlags drmFormatModifierTilingFeatures; -} VkDrmFormatModifierPropertiesEXT; +typedef struct VkDeviceFaultCountsEXT { + VkStructureType sType; + void * pNext; + uint32_t addressInfoCount; + uint32_t vendorInfoCount; + VkDeviceSize vendorBinarySize; +} VkDeviceFaultCountsEXT; -typedef struct VkImageDrmFormatModifierExplicitCreateInfoEXT { +typedef struct VkDeviceFaultInfoEXT { VkStructureType sType; - const void * pNext; - uint64_t drmFormatModifier; - uint32_t drmFormatModifierPlaneCount; - const VkSubresourceLayout * pPlaneLayouts; -} VkImageDrmFormatModifierExplicitCreateInfoEXT; + void * pNext; + char description [ VK_MAX_DESCRIPTION_SIZE ]; + VkDeviceFaultAddressInfoEXT * pAddressInfos; + VkDeviceFaultVendorInfoEXT * pVendorInfos; + void * pVendorBinaryData; +} VkDeviceFaultInfoEXT; -typedef struct VkImageStencilUsageCreateInfo { +typedef struct VkPhysicalDevicePipelineLibraryGroupHandlesFeaturesEXT { VkStructureType sType; - const void * pNext; - VkImageUsageFlags stencilUsage; -} VkImageStencilUsageCreateInfo; + void * pNext; + VkBool32 pipelineLibraryGroupHandles; +} VkPhysicalDevicePipelineLibraryGroupHandlesFeaturesEXT; -typedef struct VkImageStencilUsageCreateInfo VkImageStencilUsageCreateInfoEXT; +typedef struct VkDepthBiasRepresentationInfoEXT { + VkStructureType sType; + const void * pNext; + VkDepthBiasRepresentationEXT depthBiasRepresentation; + VkBool32 depthBiasExact; +} VkDepthBiasRepresentationInfoEXT; -typedef struct VkPhysicalDeviceFragmentDensityMapFeaturesEXT { +typedef struct VkDecompressMemoryRegionNV { + VkDeviceAddress srcAddress; + VkDeviceAddress dstAddress; + VkDeviceSize compressedSize; + VkDeviceSize decompressedSize; + VkMemoryDecompressionMethodFlagsNV decompressionMethod; +} VkDecompressMemoryRegionNV; + +typedef struct VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM { VkStructureType sType; - void * pNext; - VkBool32 fragmentDensityMap; - VkBool32 fragmentDensityMapDynamic; - VkBool32 fragmentDensityMapNonSubsampledImages; -} VkPhysicalDeviceFragmentDensityMapFeaturesEXT; + void * pNext; + VkBool32 shaderCoreBuiltins; +} VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM; + +typedef struct VkFrameBoundaryEXT { + VkStructureType sType; + const void * pNext; + VkFrameBoundaryFlagsEXT flags; + uint64_t frameID; + uint32_t imageCount; + const VkImage * pImages; + uint32_t bufferCount; + const VkBuffer * pBuffers; + uint64_t tagName; + size_t tagSize; + const void * pTag; +} VkFrameBoundaryEXT; + +typedef struct VkPhysicalDeviceFrameBoundaryFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 frameBoundary; +} VkPhysicalDeviceFrameBoundaryFeaturesEXT; + +typedef struct VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 dynamicRenderingUnusedAttachments; +} VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT; -typedef struct VkPhysicalDeviceFragmentDensityMap2FeaturesEXT { +typedef struct VkSurfacePresentScalingCapabilitiesEXT { VkStructureType sType; - void * pNext; - VkBool32 fragmentDensityMapDeferred; -} VkPhysicalDeviceFragmentDensityMap2FeaturesEXT; + void * pNext; + VkPresentScalingFlagsEXT supportedPresentScaling; + VkPresentGravityFlagsEXT supportedPresentGravityX; + VkPresentGravityFlagsEXT supportedPresentGravityY; + VkExtent2D minScaledImageExtent; + VkExtent2D maxScaledImageExtent; +} VkSurfacePresentScalingCapabilitiesEXT; -typedef struct VkPhysicalDeviceFragmentDensityMapPropertiesEXT { +typedef struct VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT { VkStructureType sType; - void * pNext; - VkExtent2D minFragmentDensityTexelSize; - VkExtent2D maxFragmentDensityTexelSize; - VkBool32 fragmentDensityInvocations; -} VkPhysicalDeviceFragmentDensityMapPropertiesEXT; + void * pNext; + VkBool32 swapchainMaintenance1; +} VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT; -typedef struct VkPhysicalDeviceFragmentDensityMap2PropertiesEXT { +typedef struct VkSwapchainPresentScalingCreateInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 subsampledLoads; - VkBool32 subsampledCoarseReconstructionEarlyAccess; - uint32_t maxSubsampledArrayLayers; - uint32_t maxDescriptorSetSubsampledSamplers; -} VkPhysicalDeviceFragmentDensityMap2PropertiesEXT; + const void * pNext; + VkPresentScalingFlagsEXT scalingBehavior; + VkPresentGravityFlagsEXT presentGravityX; + VkPresentGravityFlagsEXT presentGravityY; +} VkSwapchainPresentScalingCreateInfoEXT; -typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures { +typedef struct VkPhysicalDeviceDepthBiasControlFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 scalarBlockLayout; -} VkPhysicalDeviceScalarBlockLayoutFeatures; + void * pNext; + VkBool32 depthBiasControl; + VkBool32 leastRepresentableValueForceUnormRepresentation; + VkBool32 floatRepresentation; + VkBool32 depthBiasExact; +} VkPhysicalDeviceDepthBiasControlFeaturesEXT; -typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures VkPhysicalDeviceScalarBlockLayoutFeaturesEXT; +typedef struct VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 rayTracingInvocationReorder; +} VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV; -typedef struct VkSurfaceProtectedCapabilitiesKHR { +typedef struct VkPhysicalDeviceExtendedSparseAddressSpaceFeaturesNV { VkStructureType sType; - const void * pNext; - VkBool32 supportsProtected; -} VkSurfaceProtectedCapabilitiesKHR; + void * pNext; + VkBool32 extendedSparseAddressSpace; +} VkPhysicalDeviceExtendedSparseAddressSpaceFeaturesNV; -typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures { +typedef struct VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV { VkStructureType sType; - void * pNext; - VkBool32 uniformBufferStandardLayout; -} VkPhysicalDeviceUniformBufferStandardLayoutFeatures; + void * pNext; + VkDeviceSize extendedSparseAddressSpaceSize; + VkImageUsageFlags extendedSparseImageUsageFlags; + VkBufferUsageFlags extendedSparseBufferUsageFlags; +} VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV; -typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR; +typedef struct VkDirectDriverLoadingInfoLUNARG { + VkStructureType sType; + void * pNext; + VkDirectDriverLoadingFlagsLUNARG flags; + PFN_vkGetInstanceProcAddrLUNARG pfnGetInstanceProcAddr; +} VkDirectDriverLoadingInfoLUNARG; -typedef struct VkPhysicalDeviceDepthClipEnableFeaturesEXT { +typedef struct VkDirectDriverLoadingListLUNARG { VkStructureType sType; - void * pNext; - VkBool32 depthClipEnable; -} VkPhysicalDeviceDepthClipEnableFeaturesEXT; + const void * pNext; + VkDirectDriverLoadingModeLUNARG mode; + uint32_t driverCount; + const VkDirectDriverLoadingInfoLUNARG * pDrivers; +} VkDirectDriverLoadingListLUNARG; -typedef struct VkPipelineRasterizationDepthClipStateCreateInfoEXT { +typedef struct VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM { VkStructureType sType; - const void * pNext; - VkPipelineRasterizationDepthClipStateCreateFlagsEXT flags; - VkBool32 depthClipEnable; -} VkPipelineRasterizationDepthClipStateCreateInfoEXT; + void * pNext; + VkBool32 multiviewPerViewViewports; +} VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM; -typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT { +typedef struct VkPhysicalDeviceRayTracingPositionFetchFeaturesKHR { VkStructureType sType; void * pNext; - VkDeviceSize heapBudget [ VK_MAX_MEMORY_HEAPS ]; - VkDeviceSize heapUsage [ VK_MAX_MEMORY_HEAPS ]; -} VkPhysicalDeviceMemoryBudgetPropertiesEXT; + VkBool32 rayTracingPositionFetch; +} VkPhysicalDeviceRayTracingPositionFetchFeaturesKHR; -typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT { +typedef struct VkDeviceImageSubresourceInfo { VkStructureType sType; - void * pNext; - VkBool32 memoryPriority; -} VkPhysicalDeviceMemoryPriorityFeaturesEXT; + const void * pNext; + const VkImageCreateInfo * pCreateInfo; + const VkImageSubresource2 * pSubresource; +} VkDeviceImageSubresourceInfo; -typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures { +typedef struct VkDeviceImageSubresourceInfo VkDeviceImageSubresourceInfoKHR; + +typedef struct VkPhysicalDeviceMultiviewPerViewRenderAreasFeaturesQCOM { VkStructureType sType; - void * pNext; - VkBool32 bufferDeviceAddress; - VkBool32 bufferDeviceAddressCaptureReplay; - VkBool32 bufferDeviceAddressMultiDevice; -} VkPhysicalDeviceBufferDeviceAddressFeatures; + void * pNext; + VkBool32 multiviewPerViewRenderAreas; +} VkPhysicalDeviceMultiviewPerViewRenderAreasFeaturesQCOM; -typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; +typedef struct VkMemoryMapInfo { + VkStructureType sType; + const void * pNext; + VkMemoryMapFlags flags; + VkDeviceMemory memory; + VkDeviceSize offset; + VkDeviceSize size; +} VkMemoryMapInfo; -typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT { +typedef struct VkMemoryMapInfo VkMemoryMapInfoKHR; + +typedef struct VkMemoryUnmapInfo { VkStructureType sType; - void * pNext; - VkBool32 bufferDeviceAddress; - VkBool32 bufferDeviceAddressCaptureReplay; - VkBool32 bufferDeviceAddressMultiDevice; -} VkPhysicalDeviceBufferDeviceAddressFeaturesEXT; + const void * pNext; + VkMemoryUnmapFlags flags; + VkDeviceMemory memory; +} VkMemoryUnmapInfo; -typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT VkPhysicalDeviceBufferAddressFeaturesEXT; +typedef struct VkMemoryUnmapInfo VkMemoryUnmapInfoKHR; -typedef struct VkBufferDeviceAddressCreateInfoEXT { +typedef struct VkPhysicalDeviceShaderObjectFeaturesEXT { VkStructureType sType; - const void * pNext; - VkDeviceAddress deviceAddress; -} VkBufferDeviceAddressCreateInfoEXT; + void * pNext; + VkBool32 shaderObject; +} VkPhysicalDeviceShaderObjectFeaturesEXT; -typedef struct VkFilterCubicImageViewImageFormatPropertiesEXT { +typedef struct VkShaderCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkShaderCreateFlagsEXT flags; + VkShaderStageFlagBits stage; + VkShaderStageFlags nextStage; + VkShaderCodeTypeEXT codeType; + size_t codeSize; + const void * pCode; + const char * pName; + uint32_t setLayoutCount; + const VkDescriptorSetLayout * pSetLayouts; + uint32_t pushConstantRangeCount; + const VkPushConstantRange * pPushConstantRanges; + const VkSpecializationInfo * pSpecializationInfo; +} VkShaderCreateInfoEXT; + +typedef struct VkPhysicalDeviceShaderTileImageFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 filterCubic; - VkBool32 filterCubicMinmax; -} VkFilterCubicImageViewImageFormatPropertiesEXT; + void * pNext; + VkBool32 shaderTileImageColorReadAccess; + VkBool32 shaderTileImageDepthReadAccess; + VkBool32 shaderTileImageStencilReadAccess; +} VkPhysicalDeviceShaderTileImageFeaturesEXT; -typedef struct VkPhysicalDeviceImagelessFramebufferFeatures { +typedef struct VkPhysicalDeviceShaderTileImagePropertiesEXT { VkStructureType sType; - void * pNext; - VkBool32 imagelessFramebuffer; -} VkPhysicalDeviceImagelessFramebufferFeatures; + void * pNext; + VkBool32 shaderTileImageCoherentReadAccelerated; + VkBool32 shaderTileImageReadSampleFromPixelRateInvocation; + VkBool32 shaderTileImageReadFromHelperInvocation; +} VkPhysicalDeviceShaderTileImagePropertiesEXT; -typedef struct VkPhysicalDeviceImagelessFramebufferFeatures VkPhysicalDeviceImagelessFramebufferFeaturesKHR; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef struct VkScreenBufferPropertiesQNX { + VkStructureType sType; + void * pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeBits; +} VkScreenBufferPropertiesQNX; -typedef struct VkFramebufferAttachmentImageInfo { +#endif + +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef struct VkScreenBufferFormatPropertiesQNX { VkStructureType sType; - const void * pNext; - VkImageCreateFlags flags; - VkImageUsageFlags usage; - uint32_t width; - uint32_t height; - uint32_t layerCount; - uint32_t viewFormatCount; - const VkFormat * pViewFormats; -} VkFramebufferAttachmentImageInfo; + void * pNext; + VkFormat format; + uint64_t externalFormat; + uint64_t screenUsage; + VkFormatFeatureFlags formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkScreenBufferFormatPropertiesQNX; -typedef struct VkFramebufferAttachmentImageInfo VkFramebufferAttachmentImageInfoKHR; +#endif -typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT { +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef struct VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX { VkStructureType sType; - void * pNext; - VkBool32 textureCompressionASTC_HDR; -} VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT; + void * pNext; + VkBool32 screenBufferImport; +} VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX; -typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV { +#endif + +typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesKHR { VkStructureType sType; - void * pNext; + void * pNext; VkBool32 cooperativeMatrix; VkBool32 cooperativeMatrixRobustBufferAccess; -} VkPhysicalDeviceCooperativeMatrixFeaturesNV; +} VkPhysicalDeviceCooperativeMatrixFeaturesKHR; -typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV { +typedef struct VkCooperativeMatrixPropertiesKHR { VkStructureType sType; void * pNext; - VkShaderStageFlags cooperativeMatrixSupportedStages; -} VkPhysicalDeviceCooperativeMatrixPropertiesNV; + uint32_t MSize; + uint32_t NSize; + uint32_t KSize; + VkComponentTypeKHR AType; + VkComponentTypeKHR BType; + VkComponentTypeKHR CType; + VkComponentTypeKHR ResultType; + VkBool32 saturatingAccumulation; + VkScopeKHR scope; +} VkCooperativeMatrixPropertiesKHR; -typedef struct VkPhysicalDeviceYcbcrImageArraysFeaturesEXT { +typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesKHR { VkStructureType sType; - void * pNext; - VkBool32 ycbcrImageArrays; -} VkPhysicalDeviceYcbcrImageArraysFeaturesEXT; + void * pNext; + VkShaderStageFlags cooperativeMatrixSupportedStages; +} VkPhysicalDeviceCooperativeMatrixPropertiesKHR; -typedef struct VkImageViewAddressPropertiesNVX { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDeviceShaderEnqueueFeaturesAMDX { VkStructureType sType; - void * pNext; - VkDeviceAddress deviceAddress; - VkDeviceSize size; -} VkImageViewAddressPropertiesNVX; + void * pNext; + VkBool32 shaderEnqueue; + VkBool32 shaderMeshEnqueue; +} VkPhysicalDeviceShaderEnqueueFeaturesAMDX; -typedef struct VkPipelineCreationFeedbackEXT { - VkPipelineCreationFeedbackFlagsEXT flags; - uint64_t duration; -} VkPipelineCreationFeedbackEXT; +#endif -typedef struct VkPipelineCreationFeedbackCreateInfoEXT { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkExecutionGraphPipelineCreateInfoAMDX { VkStructureType sType; - const void * pNext; - VkPipelineCreationFeedbackEXT * pPipelineCreationFeedback; - uint32_t pipelineStageCreationFeedbackCount; - VkPipelineCreationFeedbackEXT * pPipelineStageCreationFeedbacks; -} VkPipelineCreationFeedbackCreateInfoEXT; + const void * pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo * pStages; + const VkPipelineLibraryCreateInfoKHR * pLibraryInfo; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkExecutionGraphPipelineCreateInfoAMDX; -#if defined(VK_USE_PLATFORM_WIN32_KHR) -typedef struct VkSurfaceCapabilitiesFullScreenExclusiveEXT { - VkStructureType sType; - void * pNext; - VkBool32 fullScreenExclusiveSupported; -} VkSurfaceCapabilitiesFullScreenExclusiveEXT; #endif -typedef struct VkPhysicalDevicePerformanceQueryFeaturesKHR { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkExecutionGraphPipelineScratchSizeAMDX { VkStructureType sType; - void * pNext; - VkBool32 performanceCounterQueryPools; - VkBool32 performanceCounterMultipleQueryPools; -} VkPhysicalDevicePerformanceQueryFeaturesKHR; + void * pNext; + VkDeviceSize minSize; + VkDeviceSize maxSize; + VkDeviceSize sizeGranularity; +} VkExecutionGraphPipelineScratchSizeAMDX; -typedef struct VkPhysicalDevicePerformanceQueryPropertiesKHR { - VkStructureType sType; - void * pNext; - VkBool32 allowCommandBufferQueryCopies; -} VkPhysicalDevicePerformanceQueryPropertiesKHR; +#endif -typedef struct VkPerformanceCounterDescriptionKHR { - VkStructureType sType; - const void * pNext; - VkPerformanceCounterDescriptionFlagsKHR flags; - char name [ VK_MAX_DESCRIPTION_SIZE ]; - char category [ VK_MAX_DESCRIPTION_SIZE ]; - char description [ VK_MAX_DESCRIPTION_SIZE ]; -} VkPerformanceCounterDescriptionKHR; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkDispatchGraphInfoAMDX { + uint32_t nodeIndex; + uint32_t payloadCount; + VkDeviceOrHostAddressConstAMDX payloads; + uint64_t payloadStride; +} VkDispatchGraphInfoAMDX; -typedef struct VkAcquireProfilingLockInfoKHR { - VkStructureType sType; - const void * pNext; - VkAcquireProfilingLockFlagsKHR flags; - uint64_t timeout; -} VkAcquireProfilingLockInfoKHR; +#endif -typedef struct VkHeadlessSurfaceCreateInfoEXT { - VkStructureType sType; - const void * pNext; - VkHeadlessSurfaceCreateFlagsEXT flags; -} VkHeadlessSurfaceCreateInfoEXT; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkDispatchGraphCountInfoAMDX { + uint32_t count; + VkDeviceOrHostAddressConstAMDX infos; + uint64_t stride; +} VkDispatchGraphCountInfoAMDX; -typedef struct VkPhysicalDeviceCoverageReductionModeFeaturesNV { - VkStructureType sType; - void * pNext; - VkBool32 coverageReductionMode; -} VkPhysicalDeviceCoverageReductionModeFeaturesNV; +#endif -typedef struct VkPipelineCoverageReductionStateCreateInfoNV { +typedef struct VkPhysicalDeviceAntiLagFeaturesAMD { VkStructureType sType; - const void * pNext; - VkPipelineCoverageReductionStateCreateFlagsNV flags; - VkCoverageReductionModeNV coverageReductionMode; -} VkPipelineCoverageReductionStateCreateInfoNV; + void * pNext; + VkBool32 antiLag; +} VkPhysicalDeviceAntiLagFeaturesAMD; -typedef struct VkFramebufferMixedSamplesCombinationNV { +typedef struct VkAntiLagDataAMD { VkStructureType sType; - void * pNext; - VkCoverageReductionModeNV coverageReductionMode; - VkSampleCountFlagBits rasterizationSamples; - VkSampleCountFlags depthStencilSamples; - VkSampleCountFlags colorSamples; -} VkFramebufferMixedSamplesCombinationNV; + const void * pNext; + VkAntiLagModeAMD mode; + uint32_t maxFPS; + const VkAntiLagPresentationInfoAMD * pPresentationInfo; +} VkAntiLagDataAMD; -typedef struct VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL { +typedef struct VkPhysicalDeviceTileMemoryHeapFeaturesQCOM { VkStructureType sType; - void * pNext; - VkBool32 shaderIntegerFunctions2; -} VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL; - -typedef union VkPerformanceValueDataINTEL { - uint32_t value32; - uint64_t value64; - float valueFloat; - VkBool32 valueBool; - const char * valueString; -} VkPerformanceValueDataINTEL; + void * pNext; + VkBool32 tileMemoryHeap; +} VkPhysicalDeviceTileMemoryHeapFeaturesQCOM; -typedef struct VkPerformanceValueINTEL { - VkPerformanceValueTypeINTEL type; - VkPerformanceValueDataINTEL data; -} VkPerformanceValueINTEL; +typedef struct VkPhysicalDeviceTileMemoryHeapPropertiesQCOM { + VkStructureType sType; + void * pNext; + VkBool32 queueSubmitBoundary; + VkBool32 tileBufferTransfers; +} VkPhysicalDeviceTileMemoryHeapPropertiesQCOM; -typedef struct VkPerformanceOverrideInfoINTEL { +typedef struct VkTileMemorySizeInfoQCOM { VkStructureType sType; - const void * pNext; - VkPerformanceOverrideTypeINTEL type; - VkBool32 enable; - uint64_t parameter; -} VkPerformanceOverrideInfoINTEL; + const void * pNext; + VkDeviceSize size; +} VkTileMemorySizeInfoQCOM; -typedef struct VkPhysicalDeviceShaderClockFeaturesKHR { +typedef struct VkTileMemoryRequirementsQCOM { VkStructureType sType; - void * pNext; - VkBool32 shaderSubgroupClock; - VkBool32 shaderDeviceClock; -} VkPhysicalDeviceShaderClockFeaturesKHR; + void * pNext; + VkDeviceSize size; + VkDeviceSize alignment; +} VkTileMemoryRequirementsQCOM; -typedef struct VkPhysicalDeviceIndexTypeUint8FeaturesEXT { +typedef struct VkBindDescriptorSetsInfo { VkStructureType sType; - void * pNext; - VkBool32 indexTypeUint8; -} VkPhysicalDeviceIndexTypeUint8FeaturesEXT; + const void * pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t firstSet; + uint32_t descriptorSetCount; + const VkDescriptorSet * pDescriptorSets; + uint32_t dynamicOffsetCount; + const uint32_t * pDynamicOffsets; +} VkBindDescriptorSetsInfo; + +typedef struct VkBindDescriptorSetsInfo VkBindDescriptorSetsInfoKHR; + +typedef struct VkPushConstantsInfo { + VkStructureType sType; + const void * pNext; + VkPipelineLayout layout; + VkShaderStageFlags stageFlags; + uint32_t offset; + uint32_t size; + const void * pValues; +} VkPushConstantsInfo; + +typedef struct VkPushConstantsInfo VkPushConstantsInfoKHR; + +typedef struct VkPushDescriptorSetInfo { + VkStructureType sType; + const void * pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t set; + uint32_t descriptorWriteCount; + const VkWriteDescriptorSet * pDescriptorWrites; +} VkPushDescriptorSetInfo; -typedef struct VkPhysicalDeviceShaderSMBuiltinsFeaturesNV { - VkStructureType sType; - void * pNext; - VkBool32 shaderSMBuiltins; -} VkPhysicalDeviceShaderSMBuiltinsFeaturesNV; +typedef struct VkPushDescriptorSetInfo VkPushDescriptorSetInfoKHR; -typedef struct VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT { +typedef struct VkSetDescriptorBufferOffsetsInfoEXT { VkStructureType sType; - void * pNext; - VkBool32 fragmentShaderSampleInterlock; - VkBool32 fragmentShaderPixelInterlock; - VkBool32 fragmentShaderShadingRateInterlock; -} VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT; - -typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures { - VkStructureType sType; - void * pNext; - VkBool32 separateDepthStencilLayouts; -} VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures; + const void * pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t firstSet; + uint32_t setCount; + const uint32_t * pBufferIndices; + const VkDeviceSize * pOffsets; +} VkSetDescriptorBufferOffsetsInfoEXT; -typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR; +typedef struct VkBindDescriptorBufferEmbeddedSamplersInfoEXT { + VkStructureType sType; + const void * pNext; + VkShaderStageFlags stageFlags; + VkPipelineLayout layout; + uint32_t set; +} VkBindDescriptorBufferEmbeddedSamplersInfoEXT; -typedef struct VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR { +typedef struct VkPhysicalDeviceCubicClampFeaturesQCOM { VkStructureType sType; - void * pNext; - VkBool32 pipelineExecutableInfo; -} VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR; + void * pNext; + VkBool32 cubicRangeClamp; +} VkPhysicalDeviceCubicClampFeaturesQCOM; -typedef struct VkPipelineExecutablePropertiesKHR { +typedef struct VkPhysicalDeviceYcbcrDegammaFeaturesQCOM { + VkStructureType sType; + void * pNext; + VkBool32 ycbcrDegamma; +} VkPhysicalDeviceYcbcrDegammaFeaturesQCOM; + +typedef struct VkSamplerYcbcrConversionYcbcrDegammaCreateInfoQCOM { VkStructureType sType; void * pNext; - VkShaderStageFlags stages; - char name [ VK_MAX_DESCRIPTION_SIZE ]; - char description [ VK_MAX_DESCRIPTION_SIZE ]; - uint32_t subgroupSize; -} VkPipelineExecutablePropertiesKHR; + VkBool32 enableYDegamma; + VkBool32 enableCbCrDegamma; +} VkSamplerYcbcrConversionYcbcrDegammaCreateInfoQCOM; -typedef union VkPipelineExecutableStatisticValueKHR { - VkBool32 b32; - int64_t i64; - uint64_t u64; - double f64; -} VkPipelineExecutableStatisticValueKHR; +typedef struct VkPhysicalDeviceCubicWeightsFeaturesQCOM { + VkStructureType sType; + void * pNext; + VkBool32 selectableCubicWeights; +} VkPhysicalDeviceCubicWeightsFeaturesQCOM; -typedef struct VkPipelineExecutableStatisticKHR { +typedef struct VkPhysicalDeviceImageProcessing2FeaturesQCOM { VkStructureType sType; - void * pNext; - char name [ VK_MAX_DESCRIPTION_SIZE ]; - char description [ VK_MAX_DESCRIPTION_SIZE ]; - VkPipelineExecutableStatisticFormatKHR format; - VkPipelineExecutableStatisticValueKHR value; -} VkPipelineExecutableStatisticKHR; + void * pNext; + VkBool32 textureBlockMatch2; +} VkPhysicalDeviceImageProcessing2FeaturesQCOM; -typedef struct VkPipelineExecutableInternalRepresentationKHR { +typedef struct VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV { VkStructureType sType; - void * pNext; - char name [ VK_MAX_DESCRIPTION_SIZE ]; - char description [ VK_MAX_DESCRIPTION_SIZE ]; - VkBool32 isText; - size_t dataSize; - void * pData; -} VkPipelineExecutableInternalRepresentationKHR; + void * pNext; + VkBool32 descriptorPoolOverallocation; +} VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV; -typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT { +typedef struct VkPhysicalDevicePerStageDescriptorSetFeaturesNV { VkStructureType sType; - void * pNext; - VkBool32 shaderDemoteToHelperInvocation; -} VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT; + void * pNext; + VkBool32 perStageDescriptorSet; + VkBool32 dynamicPipelineLayout; +} VkPhysicalDevicePerStageDescriptorSetFeaturesNV; -typedef struct VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT { +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef struct VkPhysicalDeviceExternalFormatResolveFeaturesANDROID { VkStructureType sType; void * pNext; - VkBool32 texelBufferAlignment; -} VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT; + VkBool32 externalFormatResolve; +} VkPhysicalDeviceExternalFormatResolveFeaturesANDROID; + +#endif -typedef struct VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT { +#if defined(VK_USE_PLATFORM_ANDROID_KHR) +typedef struct VkPhysicalDeviceExternalFormatResolvePropertiesANDROID { VkStructureType sType; void * pNext; - VkDeviceSize storageTexelBufferOffsetAlignmentBytes; - VkBool32 storageTexelBufferOffsetSingleTexelAlignment; - VkDeviceSize uniformTexelBufferOffsetAlignmentBytes; - VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; -} VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT; + VkBool32 nullColorAttachmentWithExternalFormatResolve; + VkChromaLocation externalFormatResolveChromaOffsetX; + VkChromaLocation externalFormatResolveChromaOffsetY; +} VkPhysicalDeviceExternalFormatResolvePropertiesANDROID; -typedef struct VkPhysicalDeviceSubgroupSizeControlFeaturesEXT { - VkStructureType sType; - void * pNext; - VkBool32 subgroupSizeControl; - VkBool32 computeFullSubgroups; -} VkPhysicalDeviceSubgroupSizeControlFeaturesEXT; +#endif -typedef struct VkPhysicalDeviceSubgroupSizeControlPropertiesEXT { +typedef struct VkLatencySleepModeInfoNV { VkStructureType sType; - void * pNext; - uint32_t minSubgroupSize; - uint32_t maxSubgroupSize; - uint32_t maxComputeWorkgroupSubgroups; - VkShaderStageFlags requiredSubgroupSizeStages; -} VkPhysicalDeviceSubgroupSizeControlPropertiesEXT; + const void * pNext; + VkBool32 lowLatencyMode; + VkBool32 lowLatencyBoost; + uint32_t minimumIntervalUs; +} VkLatencySleepModeInfoNV; -typedef struct VkPhysicalDeviceLineRasterizationFeaturesEXT { +typedef struct VkGetLatencyMarkerInfoNV { VkStructureType sType; - void * pNext; - VkBool32 rectangularLines; - VkBool32 bresenhamLines; - VkBool32 smoothLines; - VkBool32 stippledRectangularLines; - VkBool32 stippledBresenhamLines; - VkBool32 stippledSmoothLines; -} VkPhysicalDeviceLineRasterizationFeaturesEXT; + const void * pNext; + uint32_t timingCount; + VkLatencyTimingsFrameReportNV * pTimings; +} VkGetLatencyMarkerInfoNV; -typedef struct VkPipelineRasterizationLineStateCreateInfoEXT { +typedef struct VkSwapchainLatencyCreateInfoNV { VkStructureType sType; - const void * pNext; - VkLineRasterizationModeEXT lineRasterizationMode; - VkBool32 stippledLineEnable; - uint32_t lineStippleFactor; - uint16_t lineStipplePattern; -} VkPipelineRasterizationLineStateCreateInfoEXT; + const void * pNext; + VkBool32 latencyModeEnable; +} VkSwapchainLatencyCreateInfoNV; -typedef struct VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT { +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDeviceCudaKernelLaunchFeaturesNV { VkStructureType sType; - void * pNext; - VkBool32 pipelineCreationCacheControl; -} VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT; - -typedef struct VkPhysicalDeviceVulkan11Features { - VkStructureType sType; void * pNext; - VkBool32 storageBuffer16BitAccess; - VkBool32 uniformAndStorageBuffer16BitAccess; - VkBool32 storagePushConstant16; - VkBool32 storageInputOutput16; - VkBool32 multiview; - VkBool32 multiviewGeometryShader; - VkBool32 multiviewTessellationShader; - VkBool32 variablePointersStorageBuffer; - VkBool32 variablePointers; - VkBool32 protectedMemory; - VkBool32 samplerYcbcrConversion; - VkBool32 shaderDrawParameters; -} VkPhysicalDeviceVulkan11Features; - -typedef struct VkPhysicalDeviceVulkan11Properties { - VkStructureType sType; - void * pNext; - uint8_t deviceUUID [ VK_UUID_SIZE ]; - uint8_t driverUUID [ VK_UUID_SIZE ]; - uint8_t deviceLUID [ VK_LUID_SIZE ]; - uint32_t deviceNodeMask; - VkBool32 deviceLUIDValid; - uint32_t subgroupSize; - VkShaderStageFlags subgroupSupportedStages; - VkSubgroupFeatureFlags subgroupSupportedOperations; - VkBool32 subgroupQuadOperationsInAllStages; - VkPointClippingBehavior pointClippingBehavior; - uint32_t maxMultiviewViewCount; - uint32_t maxMultiviewInstanceIndex; - VkBool32 protectedNoFault; - uint32_t maxPerSetDescriptors; - VkDeviceSize maxMemoryAllocationSize; -} VkPhysicalDeviceVulkan11Properties; + VkBool32 cudaKernelLaunchFeatures; +} VkPhysicalDeviceCudaKernelLaunchFeaturesNV; -typedef struct VkPhysicalDeviceVulkan12Features { - VkStructureType sType; - void * pNext; - VkBool32 samplerMirrorClampToEdge; - VkBool32 drawIndirectCount; - VkBool32 storageBuffer8BitAccess; - VkBool32 uniformAndStorageBuffer8BitAccess; - VkBool32 storagePushConstant8; - VkBool32 shaderBufferInt64Atomics; - VkBool32 shaderSharedInt64Atomics; - VkBool32 shaderFloat16; - VkBool32 shaderInt8; - VkBool32 descriptorIndexing; - VkBool32 shaderInputAttachmentArrayDynamicIndexing; - VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; - VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; - VkBool32 shaderUniformBufferArrayNonUniformIndexing; - VkBool32 shaderSampledImageArrayNonUniformIndexing; - VkBool32 shaderStorageBufferArrayNonUniformIndexing; - VkBool32 shaderStorageImageArrayNonUniformIndexing; - VkBool32 shaderInputAttachmentArrayNonUniformIndexing; - VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; - VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; - VkBool32 descriptorBindingUniformBufferUpdateAfterBind; - VkBool32 descriptorBindingSampledImageUpdateAfterBind; - VkBool32 descriptorBindingStorageImageUpdateAfterBind; - VkBool32 descriptorBindingStorageBufferUpdateAfterBind; - VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingUpdateUnusedWhilePending; - VkBool32 descriptorBindingPartiallyBound; - VkBool32 descriptorBindingVariableDescriptorCount; - VkBool32 runtimeDescriptorArray; - VkBool32 samplerFilterMinmax; - VkBool32 scalarBlockLayout; - VkBool32 imagelessFramebuffer; - VkBool32 uniformBufferStandardLayout; - VkBool32 shaderSubgroupExtendedTypes; - VkBool32 separateDepthStencilLayouts; - VkBool32 hostQueryReset; - VkBool32 timelineSemaphore; - VkBool32 bufferDeviceAddress; - VkBool32 bufferDeviceAddressCaptureReplay; - VkBool32 bufferDeviceAddressMultiDevice; - VkBool32 vulkanMemoryModel; - VkBool32 vulkanMemoryModelDeviceScope; - VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; - VkBool32 shaderOutputViewportIndex; - VkBool32 shaderOutputLayer; - VkBool32 subgroupBroadcastDynamicId; -} VkPhysicalDeviceVulkan12Features; +#endif -typedef struct VkPhysicalDeviceVulkan12Properties { - VkStructureType sType; - void * pNext; - VkDriverId driverID; - char driverName [ VK_MAX_DRIVER_NAME_SIZE ]; - char driverInfo [ VK_MAX_DRIVER_INFO_SIZE ]; - VkConformanceVersion conformanceVersion; - VkShaderFloatControlsIndependence denormBehaviorIndependence; - VkShaderFloatControlsIndependence roundingModeIndependence; - VkBool32 shaderSignedZeroInfNanPreserveFloat16; - VkBool32 shaderSignedZeroInfNanPreserveFloat32; - VkBool32 shaderSignedZeroInfNanPreserveFloat64; - VkBool32 shaderDenormPreserveFloat16; - VkBool32 shaderDenormPreserveFloat32; - VkBool32 shaderDenormPreserveFloat64; - VkBool32 shaderDenormFlushToZeroFloat16; - VkBool32 shaderDenormFlushToZeroFloat32; - VkBool32 shaderDenormFlushToZeroFloat64; - VkBool32 shaderRoundingModeRTEFloat16; - VkBool32 shaderRoundingModeRTEFloat32; - VkBool32 shaderRoundingModeRTEFloat64; - VkBool32 shaderRoundingModeRTZFloat16; - VkBool32 shaderRoundingModeRTZFloat32; - VkBool32 shaderRoundingModeRTZFloat64; - uint32_t maxUpdateAfterBindDescriptorsInAllPools; - VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; - VkBool32 shaderSampledImageArrayNonUniformIndexingNative; - VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; - VkBool32 shaderStorageImageArrayNonUniformIndexingNative; - VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; - VkBool32 robustBufferAccessUpdateAfterBind; - VkBool32 quadDivergentImplicitLod; - uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; - uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; - uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; - uint32_t maxPerStageUpdateAfterBindResources; - uint32_t maxDescriptorSetUpdateAfterBindSamplers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindSampledImages; - uint32_t maxDescriptorSetUpdateAfterBindStorageImages; - uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; - VkResolveModeFlags supportedDepthResolveModes; - VkResolveModeFlags supportedStencilResolveModes; - VkBool32 independentResolveNone; - VkBool32 independentResolve; - VkBool32 filterMinmaxSingleComponentFormats; - VkBool32 filterMinmaxImageComponentMapping; - uint64_t maxTimelineSemaphoreValueDifference; - VkSampleCountFlags framebufferIntegerColorSampleCounts; -} VkPhysicalDeviceVulkan12Properties; +typedef struct VkPhysicalDeviceSchedulingControlsFeaturesARM { + VkStructureType sType; + void * pNext; + VkBool32 schedulingControls; +} VkPhysicalDeviceSchedulingControlsFeaturesARM; -typedef struct VkPipelineCompilerControlCreateInfoAMD { - VkStructureType sType; - const void * pNext; - VkPipelineCompilerControlFlagsAMD compilerControlFlags; -} VkPipelineCompilerControlCreateInfoAMD; +typedef struct VkPhysicalDeviceSchedulingControlsPropertiesARM { + VkStructureType sType; + void * pNext; + VkPhysicalDeviceSchedulingControlsFlagsARM schedulingControlsFlags; +} VkPhysicalDeviceSchedulingControlsPropertiesARM; -typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD { +typedef struct VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG { VkStructureType sType; void * pNext; - VkBool32 deviceCoherentMemory; -} VkPhysicalDeviceCoherentMemoryFeaturesAMD; + VkBool32 relaxedLineRasterization; +} VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG; -typedef struct VkPhysicalDeviceToolPropertiesEXT { +typedef struct VkPhysicalDeviceRenderPassStripedFeaturesARM { VkStructureType sType; - void * pNext; - char name [ VK_MAX_EXTENSION_NAME_SIZE ]; - char version [ VK_MAX_EXTENSION_NAME_SIZE ]; - VkToolPurposeFlagsEXT purposes; - char description [ VK_MAX_DESCRIPTION_SIZE ]; - char layer [ VK_MAX_EXTENSION_NAME_SIZE ]; -} VkPhysicalDeviceToolPropertiesEXT; + void * pNext; + VkBool32 renderPassStriped; +} VkPhysicalDeviceRenderPassStripedFeaturesARM; -typedef struct VkPhysicalDeviceCustomBorderColorFeaturesEXT { +typedef struct VkRenderPassStripeSubmitInfoARM { VkStructureType sType; - void * pNext; - VkBool32 customBorderColors; - VkBool32 customBorderColorWithoutFormat; -} VkPhysicalDeviceCustomBorderColorFeaturesEXT; + const void * pNext; + uint32_t stripeSemaphoreInfoCount; + const VkSemaphoreSubmitInfo * pStripeSemaphoreInfos; +} VkRenderPassStripeSubmitInfoARM; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef union VkDeviceOrHostAddressKHR { - VkDeviceAddress deviceAddress; - void * hostAddress; -} VkDeviceOrHostAddressKHR; -#endif +typedef struct VkPhysicalDevicePipelineOpacityMicromapFeaturesARM { + VkStructureType sType; + void * pNext; + VkBool32 pipelineOpacityMicromap; +} VkPhysicalDevicePipelineOpacityMicromapFeaturesARM; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef union VkDeviceOrHostAddressConstKHR { - VkDeviceAddress deviceAddress; - const void * hostAddress; -} VkDeviceOrHostAddressConstKHR; -#endif +typedef struct VkPhysicalDeviceShaderMaximalReconvergenceFeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 shaderMaximalReconvergence; +} VkPhysicalDeviceShaderMaximalReconvergenceFeaturesKHR; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureGeometryTrianglesDataKHR { +typedef struct VkPhysicalDeviceShaderSubgroupRotateFeatures { VkStructureType sType; - const void * pNext; - VkFormat vertexFormat; - VkDeviceOrHostAddressConstKHR vertexData; - VkDeviceSize vertexStride; - VkIndexType indexType; - VkDeviceOrHostAddressConstKHR indexData; - VkDeviceOrHostAddressConstKHR transformData; -} VkAccelerationStructureGeometryTrianglesDataKHR; -#endif + void * pNext; + VkBool32 shaderSubgroupRotate; + VkBool32 shaderSubgroupRotateClustered; +} VkPhysicalDeviceShaderSubgroupRotateFeatures; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureGeometryAabbsDataKHR { +typedef struct VkPhysicalDeviceShaderSubgroupRotateFeatures VkPhysicalDeviceShaderSubgroupRotateFeaturesKHR; + +typedef struct VkPhysicalDeviceShaderExpectAssumeFeatures { VkStructureType sType; - const void * pNext; - VkDeviceOrHostAddressConstKHR data; - VkDeviceSize stride; -} VkAccelerationStructureGeometryAabbsDataKHR; -#endif + void * pNext; + VkBool32 shaderExpectAssume; +} VkPhysicalDeviceShaderExpectAssumeFeatures; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureGeometryInstancesDataKHR { +typedef struct VkPhysicalDeviceShaderExpectAssumeFeatures VkPhysicalDeviceShaderExpectAssumeFeaturesKHR; + +typedef struct VkPhysicalDeviceShaderFloatControls2Features { VkStructureType sType; - const void * pNext; - VkBool32 arrayOfPointers; - VkDeviceOrHostAddressConstKHR data; -} VkAccelerationStructureGeometryInstancesDataKHR; -#endif + void * pNext; + VkBool32 shaderFloatControls2; +} VkPhysicalDeviceShaderFloatControls2Features; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef union VkAccelerationStructureGeometryDataKHR { - VkAccelerationStructureGeometryTrianglesDataKHR triangles; - VkAccelerationStructureGeometryAabbsDataKHR aabbs; - VkAccelerationStructureGeometryInstancesDataKHR instances; -} VkAccelerationStructureGeometryDataKHR; -#endif +typedef struct VkPhysicalDeviceShaderFloatControls2Features VkPhysicalDeviceShaderFloatControls2FeaturesKHR; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureGeometryKHR { +typedef struct VkPhysicalDeviceDynamicRenderingLocalReadFeatures { VkStructureType sType; - const void * pNext; - VkGeometryTypeKHR geometryType; - VkAccelerationStructureGeometryDataKHR geometry; - VkGeometryFlagsKHR flags; -} VkAccelerationStructureGeometryKHR; -#endif + void * pNext; + VkBool32 dynamicRenderingLocalRead; +} VkPhysicalDeviceDynamicRenderingLocalReadFeatures; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureBuildGeometryInfoKHR { +typedef struct VkPhysicalDeviceDynamicRenderingLocalReadFeatures VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR; + +typedef struct VkPhysicalDeviceShaderQuadControlFeaturesKHR { VkStructureType sType; - const void * pNext; - VkAccelerationStructureTypeKHR type; - VkBuildAccelerationStructureFlagsKHR flags; - VkBool32 update; - VkAccelerationStructureKHR srcAccelerationStructure; - VkAccelerationStructureKHR dstAccelerationStructure; - VkBool32 geometryArrayOfPointers; - uint32_t geometryCount; - const VkAccelerationStructureGeometryKHR * const* ppGeometries; - VkDeviceOrHostAddressKHR scratchData; -} VkAccelerationStructureBuildGeometryInfoKHR; -#endif + void * pNext; + VkBool32 shaderQuadControl; +} VkPhysicalDeviceShaderQuadControlFeaturesKHR; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureCreateGeometryTypeInfoKHR { +typedef struct VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV { VkStructureType sType; - const void * pNext; - VkGeometryTypeKHR geometryType; - uint32_t maxPrimitiveCount; - VkIndexType indexType; - uint32_t maxVertexCount; - VkFormat vertexFormat; - VkBool32 allowsTransforms; -} VkAccelerationStructureCreateGeometryTypeInfoKHR; -#endif + void * pNext; + VkBool32 shaderFloat16VectorAtomics; +} VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV; + +typedef struct VkPhysicalDeviceMapMemoryPlacedFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 memoryMapPlaced; + VkBool32 memoryMapRangePlaced; + VkBool32 memoryUnmapReserve; +} VkPhysicalDeviceMapMemoryPlacedFeaturesEXT; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkAccelerationStructureCreateInfoKHR { +typedef struct VkPhysicalDeviceMapMemoryPlacedPropertiesEXT { VkStructureType sType; - const void * pNext; - VkDeviceSize compactedSize; - VkAccelerationStructureTypeKHR type; - VkBuildAccelerationStructureFlagsKHR flags; - uint32_t maxGeometryCount; - const VkAccelerationStructureCreateGeometryTypeInfoKHR * pGeometryInfos; - VkDeviceAddress deviceAddress; -} VkAccelerationStructureCreateInfoKHR; -#endif + void * pNext; + VkDeviceSize minPlacedMemoryMapAlignment; +} VkPhysicalDeviceMapMemoryPlacedPropertiesEXT; -typedef struct VkAccelerationStructureInstanceKHR { - VkTransformMatrixKHR transform; - uint32_t instanceCustomIndex :24; - uint32_t mask :8; - uint32_t instanceShaderBindingTableRecordOffset :24; - VkGeometryInstanceFlagsKHR flags :8; - uint64_t accelerationStructureReference; -} VkAccelerationStructureInstanceKHR; +typedef struct VkPhysicalDeviceShaderBfloat16FeaturesKHR { + VkStructureType sType; + void * pNext; + VkBool32 shaderBFloat16Type; + VkBool32 shaderBFloat16DotProduct; + VkBool32 shaderBFloat16CooperativeMatrix; +} VkPhysicalDeviceShaderBfloat16FeaturesKHR; -typedef struct VkAccelerationStructureInstanceKHR VkAccelerationStructureInstanceNV; +typedef struct VkPhysicalDeviceRawAccessChainsFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 shaderRawAccessChains; +} VkPhysicalDeviceRawAccessChainsFeaturesNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkCopyAccelerationStructureToMemoryInfoKHR { +typedef struct VkPhysicalDeviceCommandBufferInheritanceFeaturesNV { VkStructureType sType; - const void * pNext; - VkAccelerationStructureKHR src; - VkDeviceOrHostAddressKHR dst; - VkCopyAccelerationStructureModeKHR mode; -} VkCopyAccelerationStructureToMemoryInfoKHR; -#endif + void * pNext; + VkBool32 commandBufferInheritance; +} VkPhysicalDeviceCommandBufferInheritanceFeaturesNV; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef struct VkCopyMemoryToAccelerationStructureInfoKHR { +typedef struct VkPhysicalDeviceImageAlignmentControlFeaturesMESA { VkStructureType sType; - const void * pNext; - VkDeviceOrHostAddressConstKHR src; - VkAccelerationStructureKHR dst; - VkCopyAccelerationStructureModeKHR mode; -} VkCopyMemoryToAccelerationStructureInfoKHR; -#endif + void * pNext; + VkBool32 imageAlignmentControl; +} VkPhysicalDeviceImageAlignmentControlFeaturesMESA; -typedef struct VkPhysicalDeviceExtendedDynamicStateFeaturesEXT { +typedef struct VkPhysicalDeviceShaderReplicatedCompositesFeaturesEXT { VkStructureType sType; - void * pNext; - VkBool32 extendedDynamicState; -} VkPhysicalDeviceExtendedDynamicStateFeaturesEXT; + void * pNext; + VkBool32 shaderReplicatedComposites; +} VkPhysicalDeviceShaderReplicatedCompositesFeaturesEXT; -typedef struct VkPhysicalDeviceDiagnosticsConfigFeaturesNV { - VkStructureType sType; +typedef struct VkPhysicalDevicePresentModeFifoLatestReadyFeaturesEXT { + VkStructureType sType; + void * pNext; + VkBool32 presentModeFifoLatestReady; +} VkPhysicalDevicePresentModeFifoLatestReadyFeaturesEXT; + +typedef struct VkPhysicalDeviceCooperativeMatrix2FeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 cooperativeMatrixWorkgroupScope; + VkBool32 cooperativeMatrixFlexibleDimensions; + VkBool32 cooperativeMatrixReductions; + VkBool32 cooperativeMatrixConversions; + VkBool32 cooperativeMatrixPerElementOperations; + VkBool32 cooperativeMatrixTensorAddressing; + VkBool32 cooperativeMatrixBlockLoads; +} VkPhysicalDeviceCooperativeMatrix2FeaturesNV; + +typedef struct VkCooperativeMatrixFlexibleDimensionsPropertiesNV { + VkStructureType sType; + void * pNext; + uint32_t MGranularity; + uint32_t NGranularity; + uint32_t KGranularity; + VkComponentTypeKHR AType; + VkComponentTypeKHR BType; + VkComponentTypeKHR CType; + VkComponentTypeKHR ResultType; + VkBool32 saturatingAccumulation; + VkScopeKHR scope; + uint32_t workgroupInvocations; +} VkCooperativeMatrixFlexibleDimensionsPropertiesNV; + +typedef struct VkPhysicalDeviceHdrVividFeaturesHUAWEI { + VkStructureType sType; void * pNext; - VkBool32 diagnosticsConfig; -} VkPhysicalDeviceDiagnosticsConfigFeaturesNV; + VkBool32 hdrVivid; +} VkPhysicalDeviceHdrVividFeaturesHUAWEI; -typedef struct VkDeviceDiagnosticsConfigCreateInfoNV { +typedef struct VkPhysicalDeviceVertexAttributeRobustnessFeaturesEXT { VkStructureType sType; - const void * pNext; - VkDeviceDiagnosticsConfigFlagsNV flags; -} VkDeviceDiagnosticsConfigCreateInfoNV; + void * pNext; + VkBool32 vertexAttributeRobustness; +} VkPhysicalDeviceVertexAttributeRobustnessFeaturesEXT; -typedef struct VkPhysicalDeviceRobustness2FeaturesEXT { +typedef struct VkPhysicalDeviceDepthClampZeroOneFeaturesKHR { VkStructureType sType; void * pNext; - VkBool32 robustBufferAccess2; - VkBool32 robustImageAccess2; - VkBool32 nullDescriptor; -} VkPhysicalDeviceRobustness2FeaturesEXT; + VkBool32 depthClampZeroOne; +} VkPhysicalDeviceDepthClampZeroOneFeaturesKHR; -typedef struct VkPhysicalDeviceRobustness2PropertiesEXT { +typedef struct VkPhysicalDeviceCooperativeVectorFeaturesNV { VkStructureType sType; - void * pNext; - VkDeviceSize robustStorageBufferAccessSizeAlignment; - VkDeviceSize robustUniformBufferAccessSizeAlignment; -} VkPhysicalDeviceRobustness2PropertiesEXT; + void * pNext; + VkBool32 cooperativeVector; + VkBool32 cooperativeVectorTraining; +} VkPhysicalDeviceCooperativeVectorFeaturesNV; -typedef struct VkPhysicalDeviceImageRobustnessFeaturesEXT { +typedef struct VkCooperativeVectorPropertiesNV { VkStructureType sType; - void * pNext; - VkBool32 robustImageAccess; -} VkPhysicalDeviceImageRobustnessFeaturesEXT; + void * pNext; + VkComponentTypeKHR inputType; + VkComponentTypeKHR inputInterpretation; + VkComponentTypeKHR matrixInterpretation; + VkComponentTypeKHR biasInterpretation; + VkComponentTypeKHR resultType; + VkBool32 transpose; +} VkCooperativeVectorPropertiesNV; -typedef struct VkPhysicalDevice4444FormatsFeaturesEXT { +typedef struct VkPhysicalDeviceCooperativeVectorPropertiesNV { + VkStructureType sType; + void * pNext; + VkShaderStageFlags cooperativeVectorSupportedStages; + VkBool32 cooperativeVectorTrainingFloat16Accumulation; + VkBool32 cooperativeVectorTrainingFloat32Accumulation; + uint32_t maxCooperativeVectorComponents; +} VkPhysicalDeviceCooperativeVectorPropertiesNV; + +typedef struct VkConvertCooperativeVectorMatrixInfoNV { + VkStructureType sType; + const void * pNext; + size_t srcSize; + VkDeviceOrHostAddressConstKHR srcData; + size_t * pDstSize; + VkDeviceOrHostAddressKHR dstData; + VkComponentTypeKHR srcComponentType; + VkComponentTypeKHR dstComponentType; + uint32_t numRows; + uint32_t numColumns; + VkCooperativeVectorMatrixLayoutNV srcLayout; + size_t srcStride; + VkCooperativeVectorMatrixLayoutNV dstLayout; + size_t dstStride; +} VkConvertCooperativeVectorMatrixInfoNV; + +typedef struct VkPhysicalDeviceTileShadingFeaturesQCOM { VkStructureType sType; void * pNext; - VkBool32 formatA4R4G4B4; - VkBool32 formatA4B4G4R4; -} VkPhysicalDevice4444FormatsFeaturesEXT; + VkBool32 tileShading; + VkBool32 tileShadingFragmentStage; + VkBool32 tileShadingColorAttachments; + VkBool32 tileShadingDepthAttachments; + VkBool32 tileShadingStencilAttachments; + VkBool32 tileShadingInputAttachments; + VkBool32 tileShadingSampledAttachments; + VkBool32 tileShadingPerTileDraw; + VkBool32 tileShadingPerTileDispatch; + VkBool32 tileShadingDispatchTile; + VkBool32 tileShadingApron; + VkBool32 tileShadingAnisotropicApron; + VkBool32 tileShadingAtomicOps; + VkBool32 tileShadingImageProcessing; +} VkPhysicalDeviceTileShadingFeaturesQCOM; + +typedef struct VkPhysicalDeviceTileShadingPropertiesQCOM { + VkStructureType sType; + void * pNext; + uint32_t maxApronSize; + VkBool32 preferNonCoherent; + VkExtent2D tileGranularity; + VkExtent2D maxTileShadingRate; +} VkPhysicalDeviceTileShadingPropertiesQCOM; + +typedef struct VkRenderPassTileShadingCreateInfoQCOM { + VkStructureType sType; + const void * pNext; + VkTileShadingRenderPassFlagsQCOM flags; + VkExtent2D tileApronSize; +} VkRenderPassTileShadingCreateInfoQCOM; + +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef struct VkPhysicalDevicePresentMeteringFeaturesNV { + VkStructureType sType; + void * pNext; + VkBool32 presentMetering; +} VkPhysicalDevicePresentMeteringFeaturesNV; + +#endif typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData); - +typedef void (VKAPI_PTR *PFN_vkDeviceMemoryReportCallbackEXT)( + const VkDeviceMemoryReportCallbackDataEXT* pCallbackData, + void* pUserData); typedef struct VkPhysicalDeviceProperties { uint32_t apiVersion; uint32_t driverVersion; @@ -8804,12 +15827,33 @@ typedef struct VkDeviceCreateInfo { } VkDeviceCreateInfo; typedef struct VkPhysicalDeviceMemoryProperties { - uint32_t memoryTypeCount; + uint32_t memoryTypeCount; VkMemoryType memoryTypes [ VK_MAX_MEMORY_TYPES ]; - uint32_t memoryHeapCount; + uint32_t memoryHeapCount; VkMemoryHeap memoryHeaps [ VK_MAX_MEMORY_HEAPS ]; } VkPhysicalDeviceMemoryProperties; +typedef struct VkPipelineBinaryCreateInfoKHR { + VkStructureType sType; + const void * pNext; + const VkPipelineBinaryKeysAndDataKHR * pKeysAndDataInfo; + VkPipeline pipeline; + const VkPipelineCreateInfoKHR * pPipelineCreateInfo; +} VkPipelineBinaryCreateInfoKHR; + +typedef struct VkClusterAccelerationStructureCommandsInfoNV { + VkStructureType sType; + void * pNext; + VkClusterAccelerationStructureInputInfoNV input; + VkDeviceAddress dstImplicitData; + VkDeviceAddress scratchData; + VkStridedDeviceAddressRegionKHR dstAddressesArray; + VkStridedDeviceAddressRegionKHR dstSizesArray; + VkStridedDeviceAddressRegionKHR srcInfosArray; + VkDeviceAddress srcInfosCount; + VkClusterAccelerationStructureAddressResolutionFlagsNV addressResolutionFlags; +} VkClusterAccelerationStructureCommandsInfoNV; + typedef struct VkPhysicalDeviceProperties2 { VkStructureType sType; void * pNext; @@ -8833,6 +15877,12 @@ typedef struct VkPresentRegionsKHR { const VkPresentRegionKHR * pRegions; } VkPresentRegionsKHR; +typedef struct VkPhysicalDeviceLayeredApiVulkanPropertiesKHR { + VkStructureType sType; + void * pNext; + VkPhysicalDeviceProperties2 properties; +} VkPhysicalDeviceLayeredApiVulkanPropertiesKHR; + typedef struct VkDebugUtilsMessengerCreateInfoEXT { VkStructureType sType; const void * pNext; @@ -8843,6 +15893,16 @@ typedef struct VkDebugUtilsMessengerCreateInfoEXT { void * pUserData; } VkDebugUtilsMessengerCreateInfoEXT; +typedef struct VkDeviceDeviceMemoryReportCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkDeviceMemoryReportFlagsEXT flags; + PFN_vkDeviceMemoryReportCallbackEXT pfnUserCallback; + void * pUserData; +} VkDeviceDeviceMemoryReportCreateInfoEXT; + +typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV; + typedef struct VkDrmFormatModifierPropertiesListEXT { VkStructureType sType; void * pNext; @@ -8859,6 +15919,34 @@ typedef struct VkFramebufferAttachmentsCreateInfo { typedef struct VkFramebufferAttachmentsCreateInfo VkFramebufferAttachmentsCreateInfoKHR; +typedef struct VkIndirectCommandsLayoutTokenEXT { + VkStructureType sType; + const void * pNext; + VkIndirectCommandsTokenTypeEXT type; + VkIndirectCommandsTokenDataEXT data; + uint32_t offset; +} VkIndirectCommandsLayoutTokenEXT; + +typedef struct VkDrmFormatModifierPropertiesList2EXT { + VkStructureType sType; + void * pNext; + uint32_t drmFormatModifierCount; + VkDrmFormatModifierProperties2EXT * pDrmFormatModifierProperties; +} VkDrmFormatModifierPropertiesList2EXT; + +typedef struct VkPhysicalDeviceDepthClampZeroOneFeaturesKHR VkPhysicalDeviceDepthClampZeroOneFeaturesEXT; + +typedef struct VkIndirectCommandsLayoutCreateInfoEXT { + VkStructureType sType; + const void * pNext; + VkIndirectCommandsLayoutUsageFlagsEXT flags; + VkShaderStageFlags shaderStages; + uint32_t indirectStride; + VkPipelineLayout pipelineLayout; + uint32_t tokenCount; + const VkIndirectCommandsLayoutTokenEXT * pTokens; +} VkIndirectCommandsLayoutCreateInfoEXT; + #define VK_VERSION_1_0 1 @@ -8867,6 +15955,17 @@ GLAD_API_CALL int GLAD_VK_VERSION_1_0; GLAD_API_CALL int GLAD_VK_VERSION_1_1; #define VK_VERSION_1_2 1 GLAD_API_CALL int GLAD_VK_VERSION_1_2; +#define VK_VERSION_1_3 1 +GLAD_API_CALL int GLAD_VK_VERSION_1_3; +#define VK_VERSION_1_4 1 +GLAD_API_CALL int GLAD_VK_VERSION_1_4; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_AMDX_shader_enqueue 1 +GLAD_API_CALL int GLAD_VK_AMDX_shader_enqueue; + +#endif +#define VK_AMD_anti_lag 1 +GLAD_API_CALL int GLAD_VK_AMD_anti_lag; #define VK_AMD_buffer_marker 1 GLAD_API_CALL int GLAD_VK_AMD_buffer_marker; #define VK_AMD_device_coherent_memory 1 @@ -8897,6 +15996,8 @@ GLAD_API_CALL int GLAD_VK_AMD_shader_ballot; GLAD_API_CALL int GLAD_VK_AMD_shader_core_properties; #define VK_AMD_shader_core_properties2 1 GLAD_API_CALL int GLAD_VK_AMD_shader_core_properties2; +#define VK_AMD_shader_early_and_late_fragment_tests 1 +GLAD_API_CALL int GLAD_VK_AMD_shader_early_and_late_fragment_tests; #define VK_AMD_shader_explicit_vertex_parameter 1 GLAD_API_CALL int GLAD_VK_AMD_shader_explicit_vertex_parameter; #define VK_AMD_shader_fragment_mask 1 @@ -8910,23 +16011,52 @@ GLAD_API_CALL int GLAD_VK_AMD_shader_trinary_minmax; #define VK_AMD_texture_gather_bias_lod 1 GLAD_API_CALL int GLAD_VK_AMD_texture_gather_bias_lod; #if defined(VK_USE_PLATFORM_ANDROID_KHR) +#define VK_ANDROID_external_format_resolve 1 +GLAD_API_CALL int GLAD_VK_ANDROID_external_format_resolve; + +#endif +#if defined(VK_USE_PLATFORM_ANDROID_KHR) #define VK_ANDROID_external_memory_android_hardware_buffer 1 GLAD_API_CALL int GLAD_VK_ANDROID_external_memory_android_hardware_buffer; + #endif +#define VK_ARM_pipeline_opacity_micromap 1 +GLAD_API_CALL int GLAD_VK_ARM_pipeline_opacity_micromap; +#define VK_ARM_rasterization_order_attachment_access 1 +GLAD_API_CALL int GLAD_VK_ARM_rasterization_order_attachment_access; +#define VK_ARM_render_pass_striped 1 +GLAD_API_CALL int GLAD_VK_ARM_render_pass_striped; +#define VK_ARM_scheduling_controls 1 +GLAD_API_CALL int GLAD_VK_ARM_scheduling_controls; +#define VK_ARM_shader_core_builtins 1 +GLAD_API_CALL int GLAD_VK_ARM_shader_core_builtins; +#define VK_ARM_shader_core_properties 1 +GLAD_API_CALL int GLAD_VK_ARM_shader_core_properties; #define VK_EXT_4444_formats 1 GLAD_API_CALL int GLAD_VK_EXT_4444_formats; +#define VK_EXT_acquire_drm_display 1 +GLAD_API_CALL int GLAD_VK_EXT_acquire_drm_display; #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) #define VK_EXT_acquire_xlib_display 1 GLAD_API_CALL int GLAD_VK_EXT_acquire_xlib_display; + #endif #define VK_EXT_astc_decode_mode 1 GLAD_API_CALL int GLAD_VK_EXT_astc_decode_mode; +#define VK_EXT_attachment_feedback_loop_dynamic_state 1 +GLAD_API_CALL int GLAD_VK_EXT_attachment_feedback_loop_dynamic_state; +#define VK_EXT_attachment_feedback_loop_layout 1 +GLAD_API_CALL int GLAD_VK_EXT_attachment_feedback_loop_layout; #define VK_EXT_blend_operation_advanced 1 GLAD_API_CALL int GLAD_VK_EXT_blend_operation_advanced; +#define VK_EXT_border_color_swizzle 1 +GLAD_API_CALL int GLAD_VK_EXT_border_color_swizzle; #define VK_EXT_buffer_device_address 1 GLAD_API_CALL int GLAD_VK_EXT_buffer_device_address; #define VK_EXT_calibrated_timestamps 1 GLAD_API_CALL int GLAD_VK_EXT_calibrated_timestamps; +#define VK_EXT_color_write_enable 1 +GLAD_API_CALL int GLAD_VK_EXT_color_write_enable; #define VK_EXT_conditional_rendering 1 GLAD_API_CALL int GLAD_VK_EXT_conditional_rendering; #define VK_EXT_conservative_rasterization 1 @@ -8939,17 +16069,36 @@ GLAD_API_CALL int GLAD_VK_EXT_debug_marker; GLAD_API_CALL int GLAD_VK_EXT_debug_report; #define VK_EXT_debug_utils 1 GLAD_API_CALL int GLAD_VK_EXT_debug_utils; +#define VK_EXT_depth_bias_control 1 +GLAD_API_CALL int GLAD_VK_EXT_depth_bias_control; +#define VK_EXT_depth_clamp_control 1 +GLAD_API_CALL int GLAD_VK_EXT_depth_clamp_control; +#define VK_EXT_depth_clamp_zero_one 1 +GLAD_API_CALL int GLAD_VK_EXT_depth_clamp_zero_one; +#define VK_EXT_depth_clip_control 1 +GLAD_API_CALL int GLAD_VK_EXT_depth_clip_control; #define VK_EXT_depth_clip_enable 1 GLAD_API_CALL int GLAD_VK_EXT_depth_clip_enable; #define VK_EXT_depth_range_unrestricted 1 GLAD_API_CALL int GLAD_VK_EXT_depth_range_unrestricted; +#define VK_EXT_descriptor_buffer 1 +GLAD_API_CALL int GLAD_VK_EXT_descriptor_buffer; #define VK_EXT_descriptor_indexing 1 GLAD_API_CALL int GLAD_VK_EXT_descriptor_indexing; +#define VK_EXT_device_address_binding_report 1 +GLAD_API_CALL int GLAD_VK_EXT_device_address_binding_report; +#define VK_EXT_device_fault 1 +GLAD_API_CALL int GLAD_VK_EXT_device_fault; +#define VK_EXT_device_generated_commands 1 +GLAD_API_CALL int GLAD_VK_EXT_device_generated_commands; +#define VK_EXT_device_memory_report 1 +GLAD_API_CALL int GLAD_VK_EXT_device_memory_report; #define VK_EXT_direct_mode_display 1 GLAD_API_CALL int GLAD_VK_EXT_direct_mode_display; #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) #define VK_EXT_directfb_surface 1 GLAD_API_CALL int GLAD_VK_EXT_directfb_surface; + #endif #define VK_EXT_discard_rectangles 1 GLAD_API_CALL int GLAD_VK_EXT_discard_rectangles; @@ -8957,62 +16106,150 @@ GLAD_API_CALL int GLAD_VK_EXT_discard_rectangles; GLAD_API_CALL int GLAD_VK_EXT_display_control; #define VK_EXT_display_surface_counter 1 GLAD_API_CALL int GLAD_VK_EXT_display_surface_counter; +#define VK_EXT_dynamic_rendering_unused_attachments 1 +GLAD_API_CALL int GLAD_VK_EXT_dynamic_rendering_unused_attachments; #define VK_EXT_extended_dynamic_state 1 GLAD_API_CALL int GLAD_VK_EXT_extended_dynamic_state; +#define VK_EXT_extended_dynamic_state2 1 +GLAD_API_CALL int GLAD_VK_EXT_extended_dynamic_state2; +#define VK_EXT_extended_dynamic_state3 1 +GLAD_API_CALL int GLAD_VK_EXT_extended_dynamic_state3; +#define VK_EXT_external_memory_acquire_unmodified 1 +GLAD_API_CALL int GLAD_VK_EXT_external_memory_acquire_unmodified; #define VK_EXT_external_memory_dma_buf 1 GLAD_API_CALL int GLAD_VK_EXT_external_memory_dma_buf; #define VK_EXT_external_memory_host 1 GLAD_API_CALL int GLAD_VK_EXT_external_memory_host; +#if defined(VK_USE_PLATFORM_METAL_EXT) +#define VK_EXT_external_memory_metal 1 +GLAD_API_CALL int GLAD_VK_EXT_external_memory_metal; + +#endif #define VK_EXT_filter_cubic 1 GLAD_API_CALL int GLAD_VK_EXT_filter_cubic; #define VK_EXT_fragment_density_map 1 GLAD_API_CALL int GLAD_VK_EXT_fragment_density_map; #define VK_EXT_fragment_density_map2 1 GLAD_API_CALL int GLAD_VK_EXT_fragment_density_map2; +#define VK_EXT_fragment_density_map_offset 1 +GLAD_API_CALL int GLAD_VK_EXT_fragment_density_map_offset; #define VK_EXT_fragment_shader_interlock 1 GLAD_API_CALL int GLAD_VK_EXT_fragment_shader_interlock; +#define VK_EXT_frame_boundary 1 +GLAD_API_CALL int GLAD_VK_EXT_frame_boundary; #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_EXT_full_screen_exclusive 1 GLAD_API_CALL int GLAD_VK_EXT_full_screen_exclusive; + #endif #define VK_EXT_global_priority 1 GLAD_API_CALL int GLAD_VK_EXT_global_priority; +#define VK_EXT_global_priority_query 1 +GLAD_API_CALL int GLAD_VK_EXT_global_priority_query; +#define VK_EXT_graphics_pipeline_library 1 +GLAD_API_CALL int GLAD_VK_EXT_graphics_pipeline_library; #define VK_EXT_hdr_metadata 1 GLAD_API_CALL int GLAD_VK_EXT_hdr_metadata; #define VK_EXT_headless_surface 1 GLAD_API_CALL int GLAD_VK_EXT_headless_surface; +#define VK_EXT_host_image_copy 1 +GLAD_API_CALL int GLAD_VK_EXT_host_image_copy; #define VK_EXT_host_query_reset 1 GLAD_API_CALL int GLAD_VK_EXT_host_query_reset; +#define VK_EXT_image_2d_view_of_3d 1 +GLAD_API_CALL int GLAD_VK_EXT_image_2d_view_of_3d; +#define VK_EXT_image_compression_control 1 +GLAD_API_CALL int GLAD_VK_EXT_image_compression_control; +#define VK_EXT_image_compression_control_swapchain 1 +GLAD_API_CALL int GLAD_VK_EXT_image_compression_control_swapchain; #define VK_EXT_image_drm_format_modifier 1 GLAD_API_CALL int GLAD_VK_EXT_image_drm_format_modifier; #define VK_EXT_image_robustness 1 GLAD_API_CALL int GLAD_VK_EXT_image_robustness; +#define VK_EXT_image_sliced_view_of_3d 1 +GLAD_API_CALL int GLAD_VK_EXT_image_sliced_view_of_3d; +#define VK_EXT_image_view_min_lod 1 +GLAD_API_CALL int GLAD_VK_EXT_image_view_min_lod; #define VK_EXT_index_type_uint8 1 GLAD_API_CALL int GLAD_VK_EXT_index_type_uint8; #define VK_EXT_inline_uniform_block 1 GLAD_API_CALL int GLAD_VK_EXT_inline_uniform_block; +#define VK_EXT_layer_settings 1 +GLAD_API_CALL int GLAD_VK_EXT_layer_settings; +#define VK_EXT_legacy_dithering 1 +GLAD_API_CALL int GLAD_VK_EXT_legacy_dithering; +#define VK_EXT_legacy_vertex_attributes 1 +GLAD_API_CALL int GLAD_VK_EXT_legacy_vertex_attributes; #define VK_EXT_line_rasterization 1 GLAD_API_CALL int GLAD_VK_EXT_line_rasterization; +#define VK_EXT_load_store_op_none 1 +GLAD_API_CALL int GLAD_VK_EXT_load_store_op_none; +#define VK_EXT_map_memory_placed 1 +GLAD_API_CALL int GLAD_VK_EXT_map_memory_placed; #define VK_EXT_memory_budget 1 GLAD_API_CALL int GLAD_VK_EXT_memory_budget; #define VK_EXT_memory_priority 1 GLAD_API_CALL int GLAD_VK_EXT_memory_priority; +#define VK_EXT_mesh_shader 1 +GLAD_API_CALL int GLAD_VK_EXT_mesh_shader; +#if defined(VK_USE_PLATFORM_METAL_EXT) +#define VK_EXT_metal_objects 1 +GLAD_API_CALL int GLAD_VK_EXT_metal_objects; + +#endif #if defined(VK_USE_PLATFORM_METAL_EXT) #define VK_EXT_metal_surface 1 GLAD_API_CALL int GLAD_VK_EXT_metal_surface; + #endif +#define VK_EXT_multi_draw 1 +GLAD_API_CALL int GLAD_VK_EXT_multi_draw; +#define VK_EXT_multisampled_render_to_single_sampled 1 +GLAD_API_CALL int GLAD_VK_EXT_multisampled_render_to_single_sampled; +#define VK_EXT_mutable_descriptor_type 1 +GLAD_API_CALL int GLAD_VK_EXT_mutable_descriptor_type; +#define VK_EXT_nested_command_buffer 1 +GLAD_API_CALL int GLAD_VK_EXT_nested_command_buffer; +#define VK_EXT_non_seamless_cube_map 1 +GLAD_API_CALL int GLAD_VK_EXT_non_seamless_cube_map; +#define VK_EXT_opacity_micromap 1 +GLAD_API_CALL int GLAD_VK_EXT_opacity_micromap; +#define VK_EXT_pageable_device_local_memory 1 +GLAD_API_CALL int GLAD_VK_EXT_pageable_device_local_memory; #define VK_EXT_pci_bus_info 1 GLAD_API_CALL int GLAD_VK_EXT_pci_bus_info; +#define VK_EXT_physical_device_drm 1 +GLAD_API_CALL int GLAD_VK_EXT_physical_device_drm; #define VK_EXT_pipeline_creation_cache_control 1 GLAD_API_CALL int GLAD_VK_EXT_pipeline_creation_cache_control; #define VK_EXT_pipeline_creation_feedback 1 GLAD_API_CALL int GLAD_VK_EXT_pipeline_creation_feedback; +#define VK_EXT_pipeline_library_group_handles 1 +GLAD_API_CALL int GLAD_VK_EXT_pipeline_library_group_handles; +#define VK_EXT_pipeline_properties 1 +GLAD_API_CALL int GLAD_VK_EXT_pipeline_properties; +#define VK_EXT_pipeline_protected_access 1 +GLAD_API_CALL int GLAD_VK_EXT_pipeline_protected_access; +#define VK_EXT_pipeline_robustness 1 +GLAD_API_CALL int GLAD_VK_EXT_pipeline_robustness; #define VK_EXT_post_depth_coverage 1 GLAD_API_CALL int GLAD_VK_EXT_post_depth_coverage; +#define VK_EXT_present_mode_fifo_latest_ready 1 +GLAD_API_CALL int GLAD_VK_EXT_present_mode_fifo_latest_ready; +#define VK_EXT_primitive_topology_list_restart 1 +GLAD_API_CALL int GLAD_VK_EXT_primitive_topology_list_restart; +#define VK_EXT_primitives_generated_query 1 +GLAD_API_CALL int GLAD_VK_EXT_primitives_generated_query; #define VK_EXT_private_data 1 GLAD_API_CALL int GLAD_VK_EXT_private_data; +#define VK_EXT_provoking_vertex 1 +GLAD_API_CALL int GLAD_VK_EXT_provoking_vertex; #define VK_EXT_queue_family_foreign 1 GLAD_API_CALL int GLAD_VK_EXT_queue_family_foreign; +#define VK_EXT_rasterization_order_attachment_access 1 +GLAD_API_CALL int GLAD_VK_EXT_rasterization_order_attachment_access; +#define VK_EXT_rgba10x6_formats 1 +GLAD_API_CALL int GLAD_VK_EXT_rgba10x6_formats; #define VK_EXT_robustness2 1 GLAD_API_CALL int GLAD_VK_EXT_robustness2; #define VK_EXT_sample_locations 1 @@ -9025,20 +16262,38 @@ GLAD_API_CALL int GLAD_VK_EXT_scalar_block_layout; GLAD_API_CALL int GLAD_VK_EXT_separate_stencil_usage; #define VK_EXT_shader_atomic_float 1 GLAD_API_CALL int GLAD_VK_EXT_shader_atomic_float; +#define VK_EXT_shader_atomic_float2 1 +GLAD_API_CALL int GLAD_VK_EXT_shader_atomic_float2; #define VK_EXT_shader_demote_to_helper_invocation 1 GLAD_API_CALL int GLAD_VK_EXT_shader_demote_to_helper_invocation; +#define VK_EXT_shader_image_atomic_int64 1 +GLAD_API_CALL int GLAD_VK_EXT_shader_image_atomic_int64; +#define VK_EXT_shader_module_identifier 1 +GLAD_API_CALL int GLAD_VK_EXT_shader_module_identifier; +#define VK_EXT_shader_object 1 +GLAD_API_CALL int GLAD_VK_EXT_shader_object; +#define VK_EXT_shader_replicated_composites 1 +GLAD_API_CALL int GLAD_VK_EXT_shader_replicated_composites; #define VK_EXT_shader_stencil_export 1 GLAD_API_CALL int GLAD_VK_EXT_shader_stencil_export; #define VK_EXT_shader_subgroup_ballot 1 GLAD_API_CALL int GLAD_VK_EXT_shader_subgroup_ballot; #define VK_EXT_shader_subgroup_vote 1 GLAD_API_CALL int GLAD_VK_EXT_shader_subgroup_vote; +#define VK_EXT_shader_tile_image 1 +GLAD_API_CALL int GLAD_VK_EXT_shader_tile_image; #define VK_EXT_shader_viewport_index_layer 1 GLAD_API_CALL int GLAD_VK_EXT_shader_viewport_index_layer; #define VK_EXT_subgroup_size_control 1 GLAD_API_CALL int GLAD_VK_EXT_subgroup_size_control; +#define VK_EXT_subpass_merge_feedback 1 +GLAD_API_CALL int GLAD_VK_EXT_subpass_merge_feedback; +#define VK_EXT_surface_maintenance1 1 +GLAD_API_CALL int GLAD_VK_EXT_surface_maintenance1; #define VK_EXT_swapchain_colorspace 1 GLAD_API_CALL int GLAD_VK_EXT_swapchain_colorspace; +#define VK_EXT_swapchain_maintenance1 1 +GLAD_API_CALL int GLAD_VK_EXT_swapchain_maintenance1; #define VK_EXT_texel_buffer_alignment 1 GLAD_API_CALL int GLAD_VK_EXT_texel_buffer_alignment; #define VK_EXT_texture_compression_astc_hdr 1 @@ -9055,19 +16310,43 @@ GLAD_API_CALL int GLAD_VK_EXT_validation_features; GLAD_API_CALL int GLAD_VK_EXT_validation_flags; #define VK_EXT_vertex_attribute_divisor 1 GLAD_API_CALL int GLAD_VK_EXT_vertex_attribute_divisor; +#define VK_EXT_vertex_attribute_robustness 1 +GLAD_API_CALL int GLAD_VK_EXT_vertex_attribute_robustness; +#define VK_EXT_vertex_input_dynamic_state 1 +GLAD_API_CALL int GLAD_VK_EXT_vertex_input_dynamic_state; +#define VK_EXT_ycbcr_2plane_444_formats 1 +GLAD_API_CALL int GLAD_VK_EXT_ycbcr_2plane_444_formats; #define VK_EXT_ycbcr_image_arrays 1 GLAD_API_CALL int GLAD_VK_EXT_ycbcr_image_arrays; #if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_buffer_collection 1 +GLAD_API_CALL int GLAD_VK_FUCHSIA_buffer_collection; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_external_memory 1 +GLAD_API_CALL int GLAD_VK_FUCHSIA_external_memory; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +#define VK_FUCHSIA_external_semaphore 1 +GLAD_API_CALL int GLAD_VK_FUCHSIA_external_semaphore; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) #define VK_FUCHSIA_imagepipe_surface 1 GLAD_API_CALL int GLAD_VK_FUCHSIA_imagepipe_surface; + #endif #if defined(VK_USE_PLATFORM_GGP) #define VK_GGP_frame_token 1 GLAD_API_CALL int GLAD_VK_GGP_frame_token; + #endif #if defined(VK_USE_PLATFORM_GGP) #define VK_GGP_stream_descriptor_surface 1 GLAD_API_CALL int GLAD_VK_GGP_stream_descriptor_surface; + #endif #define VK_GOOGLE_decorate_string 1 GLAD_API_CALL int GLAD_VK_GOOGLE_decorate_string; @@ -9075,12 +16354,24 @@ GLAD_API_CALL int GLAD_VK_GOOGLE_decorate_string; GLAD_API_CALL int GLAD_VK_GOOGLE_display_timing; #define VK_GOOGLE_hlsl_functionality1 1 GLAD_API_CALL int GLAD_VK_GOOGLE_hlsl_functionality1; +#define VK_GOOGLE_surfaceless_query 1 +GLAD_API_CALL int GLAD_VK_GOOGLE_surfaceless_query; #define VK_GOOGLE_user_type 1 GLAD_API_CALL int GLAD_VK_GOOGLE_user_type; +#define VK_HUAWEI_cluster_culling_shader 1 +GLAD_API_CALL int GLAD_VK_HUAWEI_cluster_culling_shader; +#define VK_HUAWEI_hdr_vivid 1 +GLAD_API_CALL int GLAD_VK_HUAWEI_hdr_vivid; +#define VK_HUAWEI_invocation_mask 1 +GLAD_API_CALL int GLAD_VK_HUAWEI_invocation_mask; +#define VK_HUAWEI_subpass_shading 1 +GLAD_API_CALL int GLAD_VK_HUAWEI_subpass_shading; #define VK_IMG_filter_cubic 1 GLAD_API_CALL int GLAD_VK_IMG_filter_cubic; #define VK_IMG_format_pvrtc 1 GLAD_API_CALL int GLAD_VK_IMG_format_pvrtc; +#define VK_IMG_relaxed_line_rasterization 1 +GLAD_API_CALL int GLAD_VK_IMG_relaxed_line_rasterization; #define VK_INTEL_performance_query 1 GLAD_API_CALL int GLAD_VK_INTEL_performance_query; #define VK_INTEL_shader_integer_functions2 1 @@ -9089,22 +16380,33 @@ GLAD_API_CALL int GLAD_VK_INTEL_shader_integer_functions2; GLAD_API_CALL int GLAD_VK_KHR_16bit_storage; #define VK_KHR_8bit_storage 1 GLAD_API_CALL int GLAD_VK_KHR_8bit_storage; +#define VK_KHR_acceleration_structure 1 +GLAD_API_CALL int GLAD_VK_KHR_acceleration_structure; #if defined(VK_USE_PLATFORM_ANDROID_KHR) #define VK_KHR_android_surface 1 GLAD_API_CALL int GLAD_VK_KHR_android_surface; + #endif #define VK_KHR_bind_memory2 1 GLAD_API_CALL int GLAD_VK_KHR_bind_memory2; #define VK_KHR_buffer_device_address 1 GLAD_API_CALL int GLAD_VK_KHR_buffer_device_address; +#define VK_KHR_calibrated_timestamps 1 +GLAD_API_CALL int GLAD_VK_KHR_calibrated_timestamps; +#define VK_KHR_compute_shader_derivatives 1 +GLAD_API_CALL int GLAD_VK_KHR_compute_shader_derivatives; +#define VK_KHR_cooperative_matrix 1 +GLAD_API_CALL int GLAD_VK_KHR_cooperative_matrix; +#define VK_KHR_copy_commands2 1 +GLAD_API_CALL int GLAD_VK_KHR_copy_commands2; #define VK_KHR_create_renderpass2 1 GLAD_API_CALL int GLAD_VK_KHR_create_renderpass2; #define VK_KHR_dedicated_allocation 1 GLAD_API_CALL int GLAD_VK_KHR_dedicated_allocation; -#if defined(VK_ENABLE_BETA_EXTENSIONS) #define VK_KHR_deferred_host_operations 1 GLAD_API_CALL int GLAD_VK_KHR_deferred_host_operations; -#endif +#define VK_KHR_depth_clamp_zero_one 1 +GLAD_API_CALL int GLAD_VK_KHR_depth_clamp_zero_one; #define VK_KHR_depth_stencil_resolve 1 GLAD_API_CALL int GLAD_VK_KHR_depth_stencil_resolve; #define VK_KHR_descriptor_update_template 1 @@ -9121,6 +16423,10 @@ GLAD_API_CALL int GLAD_VK_KHR_display_swapchain; GLAD_API_CALL int GLAD_VK_KHR_draw_indirect_count; #define VK_KHR_driver_properties 1 GLAD_API_CALL int GLAD_VK_KHR_driver_properties; +#define VK_KHR_dynamic_rendering 1 +GLAD_API_CALL int GLAD_VK_KHR_dynamic_rendering; +#define VK_KHR_dynamic_rendering_local_read 1 +GLAD_API_CALL int GLAD_VK_KHR_dynamic_rendering_local_read; #define VK_KHR_external_fence 1 GLAD_API_CALL int GLAD_VK_KHR_external_fence; #define VK_KHR_external_fence_capabilities 1 @@ -9130,6 +16436,7 @@ GLAD_API_CALL int GLAD_VK_KHR_external_fence_fd; #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_external_fence_win32 1 GLAD_API_CALL int GLAD_VK_KHR_external_fence_win32; + #endif #define VK_KHR_external_memory 1 GLAD_API_CALL int GLAD_VK_KHR_external_memory; @@ -9140,6 +16447,7 @@ GLAD_API_CALL int GLAD_VK_KHR_external_memory_fd; #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_external_memory_win32 1 GLAD_API_CALL int GLAD_VK_KHR_external_memory_win32; + #endif #define VK_KHR_external_semaphore 1 GLAD_API_CALL int GLAD_VK_KHR_external_semaphore; @@ -9150,7 +16458,14 @@ GLAD_API_CALL int GLAD_VK_KHR_external_semaphore_fd; #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_external_semaphore_win32 1 GLAD_API_CALL int GLAD_VK_KHR_external_semaphore_win32; + #endif +#define VK_KHR_format_feature_flags2 1 +GLAD_API_CALL int GLAD_VK_KHR_format_feature_flags2; +#define VK_KHR_fragment_shader_barycentric 1 +GLAD_API_CALL int GLAD_VK_KHR_fragment_shader_barycentric; +#define VK_KHR_fragment_shading_rate 1 +GLAD_API_CALL int GLAD_VK_KHR_fragment_shading_rate; #define VK_KHR_get_display_properties2 1 GLAD_API_CALL int GLAD_VK_KHR_get_display_properties2; #define VK_KHR_get_memory_requirements2 1 @@ -9159,36 +16474,73 @@ GLAD_API_CALL int GLAD_VK_KHR_get_memory_requirements2; GLAD_API_CALL int GLAD_VK_KHR_get_physical_device_properties2; #define VK_KHR_get_surface_capabilities2 1 GLAD_API_CALL int GLAD_VK_KHR_get_surface_capabilities2; +#define VK_KHR_global_priority 1 +GLAD_API_CALL int GLAD_VK_KHR_global_priority; #define VK_KHR_image_format_list 1 GLAD_API_CALL int GLAD_VK_KHR_image_format_list; #define VK_KHR_imageless_framebuffer 1 GLAD_API_CALL int GLAD_VK_KHR_imageless_framebuffer; #define VK_KHR_incremental_present 1 GLAD_API_CALL int GLAD_VK_KHR_incremental_present; +#define VK_KHR_index_type_uint8 1 +GLAD_API_CALL int GLAD_VK_KHR_index_type_uint8; +#define VK_KHR_line_rasterization 1 +GLAD_API_CALL int GLAD_VK_KHR_line_rasterization; +#define VK_KHR_load_store_op_none 1 +GLAD_API_CALL int GLAD_VK_KHR_load_store_op_none; #define VK_KHR_maintenance1 1 GLAD_API_CALL int GLAD_VK_KHR_maintenance1; #define VK_KHR_maintenance2 1 GLAD_API_CALL int GLAD_VK_KHR_maintenance2; #define VK_KHR_maintenance3 1 GLAD_API_CALL int GLAD_VK_KHR_maintenance3; +#define VK_KHR_maintenance4 1 +GLAD_API_CALL int GLAD_VK_KHR_maintenance4; +#define VK_KHR_maintenance5 1 +GLAD_API_CALL int GLAD_VK_KHR_maintenance5; +#define VK_KHR_maintenance6 1 +GLAD_API_CALL int GLAD_VK_KHR_maintenance6; +#define VK_KHR_maintenance7 1 +GLAD_API_CALL int GLAD_VK_KHR_maintenance7; +#define VK_KHR_maintenance8 1 +GLAD_API_CALL int GLAD_VK_KHR_maintenance8; +#define VK_KHR_map_memory2 1 +GLAD_API_CALL int GLAD_VK_KHR_map_memory2; #define VK_KHR_multiview 1 GLAD_API_CALL int GLAD_VK_KHR_multiview; #define VK_KHR_performance_query 1 GLAD_API_CALL int GLAD_VK_KHR_performance_query; +#define VK_KHR_pipeline_binary 1 +GLAD_API_CALL int GLAD_VK_KHR_pipeline_binary; #define VK_KHR_pipeline_executable_properties 1 GLAD_API_CALL int GLAD_VK_KHR_pipeline_executable_properties; -#if defined(VK_ENABLE_BETA_EXTENSIONS) #define VK_KHR_pipeline_library 1 GLAD_API_CALL int GLAD_VK_KHR_pipeline_library; +#define VK_KHR_portability_enumeration 1 +GLAD_API_CALL int GLAD_VK_KHR_portability_enumeration; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_KHR_portability_subset 1 +GLAD_API_CALL int GLAD_VK_KHR_portability_subset; + #endif +#define VK_KHR_present_id 1 +GLAD_API_CALL int GLAD_VK_KHR_present_id; +#define VK_KHR_present_wait 1 +GLAD_API_CALL int GLAD_VK_KHR_present_wait; #define VK_KHR_push_descriptor 1 GLAD_API_CALL int GLAD_VK_KHR_push_descriptor; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -#define VK_KHR_ray_tracing 1 -GLAD_API_CALL int GLAD_VK_KHR_ray_tracing; -#endif +#define VK_KHR_ray_query 1 +GLAD_API_CALL int GLAD_VK_KHR_ray_query; +#define VK_KHR_ray_tracing_maintenance1 1 +GLAD_API_CALL int GLAD_VK_KHR_ray_tracing_maintenance1; +#define VK_KHR_ray_tracing_pipeline 1 +GLAD_API_CALL int GLAD_VK_KHR_ray_tracing_pipeline; +#define VK_KHR_ray_tracing_position_fetch 1 +GLAD_API_CALL int GLAD_VK_KHR_ray_tracing_position_fetch; #define VK_KHR_relaxed_block_layout 1 GLAD_API_CALL int GLAD_VK_KHR_relaxed_block_layout; +#define VK_KHR_robustness2 1 +GLAD_API_CALL int GLAD_VK_KHR_robustness2; #define VK_KHR_sampler_mirror_clamp_to_edge 1 GLAD_API_CALL int GLAD_VK_KHR_sampler_mirror_clamp_to_edge; #define VK_KHR_sampler_ycbcr_conversion 1 @@ -9197,18 +16549,38 @@ GLAD_API_CALL int GLAD_VK_KHR_sampler_ycbcr_conversion; GLAD_API_CALL int GLAD_VK_KHR_separate_depth_stencil_layouts; #define VK_KHR_shader_atomic_int64 1 GLAD_API_CALL int GLAD_VK_KHR_shader_atomic_int64; +#define VK_KHR_shader_bfloat16 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_bfloat16; #define VK_KHR_shader_clock 1 GLAD_API_CALL int GLAD_VK_KHR_shader_clock; #define VK_KHR_shader_draw_parameters 1 GLAD_API_CALL int GLAD_VK_KHR_shader_draw_parameters; +#define VK_KHR_shader_expect_assume 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_expect_assume; #define VK_KHR_shader_float16_int8 1 GLAD_API_CALL int GLAD_VK_KHR_shader_float16_int8; #define VK_KHR_shader_float_controls 1 GLAD_API_CALL int GLAD_VK_KHR_shader_float_controls; +#define VK_KHR_shader_float_controls2 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_float_controls2; +#define VK_KHR_shader_integer_dot_product 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_integer_dot_product; +#define VK_KHR_shader_maximal_reconvergence 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_maximal_reconvergence; #define VK_KHR_shader_non_semantic_info 1 GLAD_API_CALL int GLAD_VK_KHR_shader_non_semantic_info; +#define VK_KHR_shader_quad_control 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_quad_control; +#define VK_KHR_shader_relaxed_extended_instruction 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_relaxed_extended_instruction; #define VK_KHR_shader_subgroup_extended_types 1 GLAD_API_CALL int GLAD_VK_KHR_shader_subgroup_extended_types; +#define VK_KHR_shader_subgroup_rotate 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_subgroup_rotate; +#define VK_KHR_shader_subgroup_uniform_control_flow 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_subgroup_uniform_control_flow; +#define VK_KHR_shader_terminate_invocation 1 +GLAD_API_CALL int GLAD_VK_KHR_shader_terminate_invocation; #define VK_KHR_shared_presentable_image 1 GLAD_API_CALL int GLAD_VK_KHR_shared_presentable_image; #define VK_KHR_spirv_1_4 1 @@ -9223,77 +16595,139 @@ GLAD_API_CALL int GLAD_VK_KHR_surface_protected_capabilities; GLAD_API_CALL int GLAD_VK_KHR_swapchain; #define VK_KHR_swapchain_mutable_format 1 GLAD_API_CALL int GLAD_VK_KHR_swapchain_mutable_format; +#define VK_KHR_synchronization2 1 +GLAD_API_CALL int GLAD_VK_KHR_synchronization2; #define VK_KHR_timeline_semaphore 1 GLAD_API_CALL int GLAD_VK_KHR_timeline_semaphore; #define VK_KHR_uniform_buffer_standard_layout 1 GLAD_API_CALL int GLAD_VK_KHR_uniform_buffer_standard_layout; #define VK_KHR_variable_pointers 1 GLAD_API_CALL int GLAD_VK_KHR_variable_pointers; +#define VK_KHR_vertex_attribute_divisor 1 +GLAD_API_CALL int GLAD_VK_KHR_vertex_attribute_divisor; #define VK_KHR_vulkan_memory_model 1 GLAD_API_CALL int GLAD_VK_KHR_vulkan_memory_model; #if defined(VK_USE_PLATFORM_WAYLAND_KHR) #define VK_KHR_wayland_surface 1 GLAD_API_CALL int GLAD_VK_KHR_wayland_surface; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_win32_keyed_mutex 1 GLAD_API_CALL int GLAD_VK_KHR_win32_keyed_mutex; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_KHR_win32_surface 1 GLAD_API_CALL int GLAD_VK_KHR_win32_surface; + #endif +#define VK_KHR_workgroup_memory_explicit_layout 1 +GLAD_API_CALL int GLAD_VK_KHR_workgroup_memory_explicit_layout; #if defined(VK_USE_PLATFORM_XCB_KHR) #define VK_KHR_xcb_surface 1 GLAD_API_CALL int GLAD_VK_KHR_xcb_surface; + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) #define VK_KHR_xlib_surface 1 GLAD_API_CALL int GLAD_VK_KHR_xlib_surface; + #endif +#define VK_KHR_zero_initialize_workgroup_memory 1 +GLAD_API_CALL int GLAD_VK_KHR_zero_initialize_workgroup_memory; +#define VK_LUNARG_direct_driver_loading 1 +GLAD_API_CALL int GLAD_VK_LUNARG_direct_driver_loading; +#define VK_MESA_image_alignment_control 1 +GLAD_API_CALL int GLAD_VK_MESA_image_alignment_control; +#define VK_MSFT_layered_driver 1 +GLAD_API_CALL int GLAD_VK_MSFT_layered_driver; #if defined(VK_USE_PLATFORM_IOS_MVK) #define VK_MVK_ios_surface 1 GLAD_API_CALL int GLAD_VK_MVK_ios_surface; + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) #define VK_MVK_macos_surface 1 GLAD_API_CALL int GLAD_VK_MVK_macos_surface; + #endif #if defined(VK_USE_PLATFORM_VI_NN) #define VK_NN_vi_surface 1 GLAD_API_CALL int GLAD_VK_NN_vi_surface; + #endif +#define VK_NVX_binary_import 1 +GLAD_API_CALL int GLAD_VK_NVX_binary_import; #define VK_NVX_image_view_handle 1 GLAD_API_CALL int GLAD_VK_NVX_image_view_handle; #define VK_NVX_multiview_per_view_attributes 1 GLAD_API_CALL int GLAD_VK_NVX_multiview_per_view_attributes; +#if defined(VK_USE_PLATFORM_WIN32_KHR) +#define VK_NV_acquire_winrt_display 1 +GLAD_API_CALL int GLAD_VK_NV_acquire_winrt_display; + +#endif #define VK_NV_clip_space_w_scaling 1 GLAD_API_CALL int GLAD_VK_NV_clip_space_w_scaling; +#define VK_NV_cluster_acceleration_structure 1 +GLAD_API_CALL int GLAD_VK_NV_cluster_acceleration_structure; +#define VK_NV_command_buffer_inheritance 1 +GLAD_API_CALL int GLAD_VK_NV_command_buffer_inheritance; #define VK_NV_compute_shader_derivatives 1 GLAD_API_CALL int GLAD_VK_NV_compute_shader_derivatives; #define VK_NV_cooperative_matrix 1 GLAD_API_CALL int GLAD_VK_NV_cooperative_matrix; +#define VK_NV_cooperative_matrix2 1 +GLAD_API_CALL int GLAD_VK_NV_cooperative_matrix2; +#define VK_NV_cooperative_vector 1 +GLAD_API_CALL int GLAD_VK_NV_cooperative_vector; +#define VK_NV_copy_memory_indirect 1 +GLAD_API_CALL int GLAD_VK_NV_copy_memory_indirect; #define VK_NV_corner_sampled_image 1 GLAD_API_CALL int GLAD_VK_NV_corner_sampled_image; #define VK_NV_coverage_reduction_mode 1 GLAD_API_CALL int GLAD_VK_NV_coverage_reduction_mode; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_cuda_kernel_launch 1 +GLAD_API_CALL int GLAD_VK_NV_cuda_kernel_launch; + +#endif #define VK_NV_dedicated_allocation 1 GLAD_API_CALL int GLAD_VK_NV_dedicated_allocation; #define VK_NV_dedicated_allocation_image_aliasing 1 GLAD_API_CALL int GLAD_VK_NV_dedicated_allocation_image_aliasing; +#define VK_NV_descriptor_pool_overallocation 1 +GLAD_API_CALL int GLAD_VK_NV_descriptor_pool_overallocation; #define VK_NV_device_diagnostic_checkpoints 1 GLAD_API_CALL int GLAD_VK_NV_device_diagnostic_checkpoints; #define VK_NV_device_diagnostics_config 1 GLAD_API_CALL int GLAD_VK_NV_device_diagnostics_config; #define VK_NV_device_generated_commands 1 GLAD_API_CALL int GLAD_VK_NV_device_generated_commands; +#define VK_NV_device_generated_commands_compute 1 +GLAD_API_CALL int GLAD_VK_NV_device_generated_commands_compute; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_displacement_micromap 1 +GLAD_API_CALL int GLAD_VK_NV_displacement_micromap; + +#endif +#define VK_NV_display_stereo 1 +GLAD_API_CALL int GLAD_VK_NV_display_stereo; +#define VK_NV_extended_sparse_address_space 1 +GLAD_API_CALL int GLAD_VK_NV_extended_sparse_address_space; +#define VK_NV_external_compute_queue 1 +GLAD_API_CALL int GLAD_VK_NV_external_compute_queue; #define VK_NV_external_memory 1 GLAD_API_CALL int GLAD_VK_NV_external_memory; #define VK_NV_external_memory_capabilities 1 GLAD_API_CALL int GLAD_VK_NV_external_memory_capabilities; +#define VK_NV_external_memory_rdma 1 +GLAD_API_CALL int GLAD_VK_NV_external_memory_rdma; #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_NV_external_memory_win32 1 GLAD_API_CALL int GLAD_VK_NV_external_memory_win32; + #endif #define VK_NV_fill_rectangle 1 GLAD_API_CALL int GLAD_VK_NV_fill_rectangle; @@ -9301,22 +16735,59 @@ GLAD_API_CALL int GLAD_VK_NV_fill_rectangle; GLAD_API_CALL int GLAD_VK_NV_fragment_coverage_to_color; #define VK_NV_fragment_shader_barycentric 1 GLAD_API_CALL int GLAD_VK_NV_fragment_shader_barycentric; +#define VK_NV_fragment_shading_rate_enums 1 +GLAD_API_CALL int GLAD_VK_NV_fragment_shading_rate_enums; #define VK_NV_framebuffer_mixed_samples 1 GLAD_API_CALL int GLAD_VK_NV_framebuffer_mixed_samples; #define VK_NV_geometry_shader_passthrough 1 GLAD_API_CALL int GLAD_VK_NV_geometry_shader_passthrough; #define VK_NV_glsl_shader 1 GLAD_API_CALL int GLAD_VK_NV_glsl_shader; +#define VK_NV_inherited_viewport_scissor 1 +GLAD_API_CALL int GLAD_VK_NV_inherited_viewport_scissor; +#define VK_NV_linear_color_attachment 1 +GLAD_API_CALL int GLAD_VK_NV_linear_color_attachment; +#define VK_NV_low_latency 1 +GLAD_API_CALL int GLAD_VK_NV_low_latency; +#define VK_NV_low_latency2 1 +GLAD_API_CALL int GLAD_VK_NV_low_latency2; +#define VK_NV_memory_decompression 1 +GLAD_API_CALL int GLAD_VK_NV_memory_decompression; #define VK_NV_mesh_shader 1 GLAD_API_CALL int GLAD_VK_NV_mesh_shader; +#define VK_NV_optical_flow 1 +GLAD_API_CALL int GLAD_VK_NV_optical_flow; +#define VK_NV_partitioned_acceleration_structure 1 +GLAD_API_CALL int GLAD_VK_NV_partitioned_acceleration_structure; +#define VK_NV_per_stage_descriptor_set 1 +GLAD_API_CALL int GLAD_VK_NV_per_stage_descriptor_set; +#define VK_NV_present_barrier 1 +GLAD_API_CALL int GLAD_VK_NV_present_barrier; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +#define VK_NV_present_metering 1 +GLAD_API_CALL int GLAD_VK_NV_present_metering; + +#endif +#define VK_NV_raw_access_chains 1 +GLAD_API_CALL int GLAD_VK_NV_raw_access_chains; #define VK_NV_ray_tracing 1 GLAD_API_CALL int GLAD_VK_NV_ray_tracing; +#define VK_NV_ray_tracing_invocation_reorder 1 +GLAD_API_CALL int GLAD_VK_NV_ray_tracing_invocation_reorder; +#define VK_NV_ray_tracing_linear_swept_spheres 1 +GLAD_API_CALL int GLAD_VK_NV_ray_tracing_linear_swept_spheres; +#define VK_NV_ray_tracing_motion_blur 1 +GLAD_API_CALL int GLAD_VK_NV_ray_tracing_motion_blur; +#define VK_NV_ray_tracing_validation 1 +GLAD_API_CALL int GLAD_VK_NV_ray_tracing_validation; #define VK_NV_representative_fragment_test 1 GLAD_API_CALL int GLAD_VK_NV_representative_fragment_test; #define VK_NV_sample_mask_override_coverage 1 GLAD_API_CALL int GLAD_VK_NV_sample_mask_override_coverage; #define VK_NV_scissor_exclusive 1 GLAD_API_CALL int GLAD_VK_NV_scissor_exclusive; +#define VK_NV_shader_atomic_float16_vector 1 +GLAD_API_CALL int GLAD_VK_NV_shader_atomic_float16_vector; #define VK_NV_shader_image_footprint 1 GLAD_API_CALL int GLAD_VK_NV_shader_image_footprint; #define VK_NV_shader_sm_builtins 1 @@ -9332,92 +16803,183 @@ GLAD_API_CALL int GLAD_VK_NV_viewport_swizzle; #if defined(VK_USE_PLATFORM_WIN32_KHR) #define VK_NV_win32_keyed_mutex 1 GLAD_API_CALL int GLAD_VK_NV_win32_keyed_mutex; + #endif +#define VK_QCOM_filter_cubic_clamp 1 +GLAD_API_CALL int GLAD_VK_QCOM_filter_cubic_clamp; +#define VK_QCOM_filter_cubic_weights 1 +GLAD_API_CALL int GLAD_VK_QCOM_filter_cubic_weights; +#define VK_QCOM_fragment_density_map_offset 1 +GLAD_API_CALL int GLAD_VK_QCOM_fragment_density_map_offset; +#define VK_QCOM_image_processing 1 +GLAD_API_CALL int GLAD_VK_QCOM_image_processing; +#define VK_QCOM_image_processing2 1 +GLAD_API_CALL int GLAD_VK_QCOM_image_processing2; +#define VK_QCOM_multiview_per_view_render_areas 1 +GLAD_API_CALL int GLAD_VK_QCOM_multiview_per_view_render_areas; +#define VK_QCOM_multiview_per_view_viewports 1 +GLAD_API_CALL int GLAD_VK_QCOM_multiview_per_view_viewports; #define VK_QCOM_render_pass_shader_resolve 1 GLAD_API_CALL int GLAD_VK_QCOM_render_pass_shader_resolve; #define VK_QCOM_render_pass_store_ops 1 GLAD_API_CALL int GLAD_VK_QCOM_render_pass_store_ops; #define VK_QCOM_render_pass_transform 1 GLAD_API_CALL int GLAD_VK_QCOM_render_pass_transform; - - +#define VK_QCOM_rotated_copy_commands 1 +GLAD_API_CALL int GLAD_VK_QCOM_rotated_copy_commands; +#define VK_QCOM_tile_memory_heap 1 +GLAD_API_CALL int GLAD_VK_QCOM_tile_memory_heap; +#define VK_QCOM_tile_properties 1 +GLAD_API_CALL int GLAD_VK_QCOM_tile_properties; +#define VK_QCOM_tile_shading 1 +GLAD_API_CALL int GLAD_VK_QCOM_tile_shading; +#define VK_QCOM_ycbcr_degamma 1 +GLAD_API_CALL int GLAD_VK_QCOM_ycbcr_degamma; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +#define VK_QNX_external_memory_screen_buffer 1 +GLAD_API_CALL int GLAD_VK_QNX_external_memory_screen_buffer; + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +#define VK_QNX_screen_surface 1 +GLAD_API_CALL int GLAD_VK_QNX_screen_surface; + +#endif +#define VK_SEC_amigo_profiling 1 +GLAD_API_CALL int GLAD_VK_SEC_amigo_profiling; +#define VK_VALVE_descriptor_set_host_mapping 1 +GLAD_API_CALL int GLAD_VK_VALVE_descriptor_set_host_mapping; +#define VK_VALVE_mutable_descriptor_type 1 +GLAD_API_CALL int GLAD_VK_VALVE_mutable_descriptor_type; + + +typedef VkResult (GLAD_API_PTR *PFN_vkAcquireDrmDisplayEXT)(VkPhysicalDevice physicalDevice, int32_t drmFd, VkDisplayKHR display); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkAcquireFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice device, const VkAcquireNextImageInfoKHR * pAcquireInfo, uint32_t * pImageIndex); typedef VkResult (GLAD_API_PTR *PFN_vkAcquireNextImageKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t * pImageIndex); typedef VkResult (GLAD_API_PTR *PFN_vkAcquirePerformanceConfigurationINTEL)(VkDevice device, const VkPerformanceConfigurationAcquireInfoINTEL * pAcquireInfo, VkPerformanceConfigurationINTEL * pConfiguration); typedef VkResult (GLAD_API_PTR *PFN_vkAcquireProfilingLockKHR)(VkDevice device, const VkAcquireProfilingLockInfoKHR * pInfo); +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef VkResult (GLAD_API_PTR *PFN_vkAcquireWinrtDisplayNV)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); + +#endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) typedef VkResult (GLAD_API_PTR *PFN_vkAcquireXlibDisplayEXT)(VkPhysicalDevice physicalDevice, Display * dpy, VkDisplayKHR display); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkAllocateCommandBuffers)(VkDevice device, const VkCommandBufferAllocateInfo * pAllocateInfo, VkCommandBuffer * pCommandBuffers); typedef VkResult (GLAD_API_PTR *PFN_vkAllocateDescriptorSets)(VkDevice device, const VkDescriptorSetAllocateInfo * pAllocateInfo, VkDescriptorSet * pDescriptorSets); typedef VkResult (GLAD_API_PTR *PFN_vkAllocateMemory)(VkDevice device, const VkMemoryAllocateInfo * pAllocateInfo, const VkAllocationCallbacks * pAllocator, VkDeviceMemory * pMemory); +typedef void (GLAD_API_PTR *PFN_vkAntiLagUpdateAMD)(VkDevice device, const VkAntiLagDataAMD * pData); typedef VkResult (GLAD_API_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo * pBeginInfo); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkBindAccelerationStructureMemoryKHR)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoKHR * pBindInfos); -#endif -typedef VkResult (GLAD_API_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoKHR * pBindInfos); +typedef VkResult (GLAD_API_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV * pBindInfos); typedef VkResult (GLAD_API_PTR *PFN_vkBindBufferMemory)(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); typedef VkResult (GLAD_API_PTR *PFN_vkBindBufferMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo * pBindInfos); typedef VkResult (GLAD_API_PTR *PFN_vkBindBufferMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo * pBindInfos); typedef VkResult (GLAD_API_PTR *PFN_vkBindImageMemory)(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); typedef VkResult (GLAD_API_PTR *PFN_vkBindImageMemory2)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo * pBindInfos); typedef VkResult (GLAD_API_PTR *PFN_vkBindImageMemory2KHR)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo * pBindInfos); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkBuildAccelerationStructureKHR)(VkDevice device, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR * pInfos, const VkAccelerationStructureBuildOffsetInfoKHR * const* ppOffsetInfos); -#endif +typedef VkResult (GLAD_API_PTR *PFN_vkBindOpticalFlowSessionImageNV)(VkDevice device, VkOpticalFlowSessionNV session, VkOpticalFlowSessionBindingPointNV bindingPoint, VkImageView view, VkImageLayout layout); +typedef VkResult (GLAD_API_PTR *PFN_vkBuildAccelerationStructuresKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR * pInfos, const VkAccelerationStructureBuildRangeInfoKHR * const* ppBuildRangeInfos); +typedef VkResult (GLAD_API_PTR *PFN_vkBuildMicromapsEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkMicromapBuildInfoEXT * pInfos); typedef void (GLAD_API_PTR *PFN_vkCmdBeginConditionalRenderingEXT)(VkCommandBuffer commandBuffer, const VkConditionalRenderingBeginInfoEXT * pConditionalRenderingBegin); typedef void (GLAD_API_PTR *PFN_vkCmdBeginDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT * pLabelInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBeginPerTileExecutionQCOM)(VkCommandBuffer commandBuffer, const VkPerTileBeginInfoQCOM * pPerTileBeginInfo); typedef void (GLAD_API_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); typedef void (GLAD_API_PTR *PFN_vkCmdBeginQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags, uint32_t index); typedef void (GLAD_API_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo * pRenderPassBegin, VkSubpassContents contents); typedef void (GLAD_API_PTR *PFN_vkCmdBeginRenderPass2)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo * pRenderPassBegin, const VkSubpassBeginInfo * pSubpassBeginInfo); typedef void (GLAD_API_PTR *PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo * pRenderPassBegin, const VkSubpassBeginInfo * pSubpassBeginInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBeginRendering)(VkCommandBuffer commandBuffer, const VkRenderingInfo * pRenderingInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBeginRenderingKHR)(VkCommandBuffer commandBuffer, const VkRenderingInfo * pRenderingInfo); typedef void (GLAD_API_PTR *PFN_vkCmdBeginTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer * pCounterBuffers, const VkDeviceSize * pCounterBufferOffsets); +typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT)(VkCommandBuffer commandBuffer, const VkBindDescriptorBufferEmbeddedSamplersInfoEXT * pBindDescriptorBufferEmbeddedSamplersInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set); +typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t bufferCount, const VkDescriptorBufferBindingInfoEXT * pBindingInfos); typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet * pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t * pDynamicOffsets); +typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorSets2)(VkCommandBuffer commandBuffer, const VkBindDescriptorSetsInfo * pBindDescriptorSetsInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBindDescriptorSets2KHR)(VkCommandBuffer commandBuffer, const VkBindDescriptorSetsInfo * pBindDescriptorSetsInfo); typedef void (GLAD_API_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); +typedef void (GLAD_API_PTR *PFN_vkCmdBindIndexBuffer2)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size, VkIndexType indexType); +typedef void (GLAD_API_PTR *PFN_vkCmdBindIndexBuffer2KHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size, VkIndexType indexType); +typedef void (GLAD_API_PTR *PFN_vkCmdBindInvocationMaskHUAWEI)(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout); typedef void (GLAD_API_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); typedef void (GLAD_API_PTR *PFN_vkCmdBindPipelineShaderGroupNV)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline, uint32_t groupIndex); +typedef void (GLAD_API_PTR *PFN_vkCmdBindShadersEXT)(VkCommandBuffer commandBuffer, uint32_t stageCount, const VkShaderStageFlagBits * pStages, const VkShaderEXT * pShaders); typedef void (GLAD_API_PTR *PFN_vkCmdBindShadingRateImageNV)(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout); +typedef void (GLAD_API_PTR *PFN_vkCmdBindTileMemoryQCOM)(VkCommandBuffer commandBuffer, const VkTileMemoryBindInfoQCOM * pTileMemoryBindInfo); typedef void (GLAD_API_PTR *PFN_vkCmdBindTransformFeedbackBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer * pBuffers, const VkDeviceSize * pOffsets, const VkDeviceSize * pSizes); typedef void (GLAD_API_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer * pBuffers, const VkDeviceSize * pOffsets); +typedef void (GLAD_API_PTR *PFN_vkCmdBindVertexBuffers2)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer * pBuffers, const VkDeviceSize * pOffsets, const VkDeviceSize * pSizes, const VkDeviceSize * pStrides); typedef void (GLAD_API_PTR *PFN_vkCmdBindVertexBuffers2EXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer * pBuffers, const VkDeviceSize * pOffsets, const VkDeviceSize * pSizes, const VkDeviceSize * pStrides); typedef void (GLAD_API_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit * pRegions, VkFilter filter); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef void (GLAD_API_PTR *PFN_vkCmdBuildAccelerationStructureIndirectKHR)(VkCommandBuffer commandBuffer, const VkAccelerationStructureBuildGeometryInfoKHR * pInfo, VkBuffer indirectBuffer, VkDeviceSize indirectOffset, uint32_t indirectStride); -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef void (GLAD_API_PTR *PFN_vkCmdBuildAccelerationStructureKHR)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR * pInfos, const VkAccelerationStructureBuildOffsetInfoKHR * const* ppOffsetInfos); -#endif -typedef void (GLAD_API_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV * pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureKHR dst, VkAccelerationStructureKHR src, VkBuffer scratch, VkDeviceSize scratchOffset); +typedef void (GLAD_API_PTR *PFN_vkCmdBlitImage2)(VkCommandBuffer commandBuffer, const VkBlitImageInfo2 * pBlitImageInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBlitImage2KHR)(VkCommandBuffer commandBuffer, const VkBlitImageInfo2 * pBlitImageInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV * pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset); +typedef void (GLAD_API_PTR *PFN_vkCmdBuildAccelerationStructuresIndirectKHR)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR * pInfos, const VkDeviceAddress * pIndirectDeviceAddresses, const uint32_t * pIndirectStrides, const uint32_t * const* ppMaxPrimitiveCounts); +typedef void (GLAD_API_PTR *PFN_vkCmdBuildAccelerationStructuresKHR)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR * pInfos, const VkAccelerationStructureBuildRangeInfoKHR * const* ppBuildRangeInfos); +typedef void (GLAD_API_PTR *PFN_vkCmdBuildClusterAccelerationStructureIndirectNV)(VkCommandBuffer commandBuffer, const VkClusterAccelerationStructureCommandsInfoNV * pCommandInfos); +typedef void (GLAD_API_PTR *PFN_vkCmdBuildMicromapsEXT)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkMicromapBuildInfoEXT * pInfos); +typedef void (GLAD_API_PTR *PFN_vkCmdBuildPartitionedAccelerationStructuresNV)(VkCommandBuffer commandBuffer, const VkBuildPartitionedAccelerationStructureInfoNV * pBuildInfo); typedef void (GLAD_API_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment * pAttachments, uint32_t rectCount, const VkClearRect * pRects); typedef void (GLAD_API_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue * pColor, uint32_t rangeCount, const VkImageSubresourceRange * pRanges); typedef void (GLAD_API_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue * pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange * pRanges); -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdConvertCooperativeVectorMatrixNV)(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkConvertCooperativeVectorMatrixInfoNV * pInfos); typedef void (GLAD_API_PTR *PFN_vkCmdCopyAccelerationStructureKHR)(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureInfoKHR * pInfo); -#endif -typedef void (GLAD_API_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureKHR dst, VkAccelerationStructureKHR src, VkCopyAccelerationStructureModeKHR mode); -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeKHR mode); typedef void (GLAD_API_PTR *PFN_vkCmdCopyAccelerationStructureToMemoryKHR)(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureToMemoryInfoKHR * pInfo); -#endif typedef void (GLAD_API_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy * pRegions); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyBuffer2)(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2 * pCopyBufferInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2 * pCopyBufferInfo); typedef void (GLAD_API_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy * pRegions); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyBufferToImage2)(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2 * pCopyBufferToImageInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyBufferToImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2 * pCopyBufferToImageInfo); typedef void (GLAD_API_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy * pRegions); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyImage2)(VkCommandBuffer commandBuffer, const VkCopyImageInfo2 * pCopyImageInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyImage2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageInfo2 * pCopyImageInfo); typedef void (GLAD_API_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy * pRegions); -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdCopyImageToBuffer2)(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2 * pCopyImageToBufferInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyImageToBuffer2KHR)(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2 * pCopyImageToBufferInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyMemoryIndirectNV)(VkCommandBuffer commandBuffer, VkDeviceAddress copyBufferAddress, uint32_t copyCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdCopyMemoryToAccelerationStructureKHR)(VkCommandBuffer commandBuffer, const VkCopyMemoryToAccelerationStructureInfoKHR * pInfo); -#endif +typedef void (GLAD_API_PTR *PFN_vkCmdCopyMemoryToImageIndirectNV)(VkCommandBuffer commandBuffer, VkDeviceAddress copyBufferAddress, uint32_t copyCount, uint32_t stride, VkImage dstImage, VkImageLayout dstImageLayout, const VkImageSubresourceLayers * pImageSubresources); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyMemoryToMicromapEXT)(VkCommandBuffer commandBuffer, const VkCopyMemoryToMicromapInfoEXT * pInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyMicromapEXT)(VkCommandBuffer commandBuffer, const VkCopyMicromapInfoEXT * pInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdCopyMicromapToMemoryEXT)(VkCommandBuffer commandBuffer, const VkCopyMicromapToMemoryInfoEXT * pInfo); typedef void (GLAD_API_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); +typedef void (GLAD_API_PTR *PFN_vkCmdCuLaunchKernelNVX)(VkCommandBuffer commandBuffer, const VkCuLaunchInfoNVX * pLaunchInfo); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdCudaLaunchKernelNV)(VkCommandBuffer commandBuffer, const VkCudaLaunchInfoNV * pLaunchInfo); + +#endif typedef void (GLAD_API_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT * pMarkerInfo); typedef void (GLAD_API_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer commandBuffer); typedef void (GLAD_API_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT * pMarkerInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdDecompressMemoryIndirectCountNV)(VkCommandBuffer commandBuffer, VkDeviceAddress indirectCommandsAddress, VkDeviceAddress indirectCommandsCountAddress, uint32_t stride); +typedef void (GLAD_API_PTR *PFN_vkCmdDecompressMemoryNV)(VkCommandBuffer commandBuffer, uint32_t decompressRegionCount, const VkDecompressMemoryRegionNV * pDecompressMemoryRegions); typedef void (GLAD_API_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); typedef void (GLAD_API_PTR *PFN_vkCmdDispatchBase)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); typedef void (GLAD_API_PTR *PFN_vkCmdDispatchBaseKHR)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdDispatchGraphAMDX)(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, VkDeviceSize scratchSize, const VkDispatchGraphCountInfoAMDX * pCountInfo); + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdDispatchGraphIndirectAMDX)(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, VkDeviceSize scratchSize, const VkDispatchGraphCountInfoAMDX * pCountInfo); + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdDispatchGraphIndirectCountAMDX)(VkCommandBuffer commandBuffer, VkDeviceAddress scratch, VkDeviceSize scratchSize, VkDeviceAddress countInfo); + +#endif typedef void (GLAD_API_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); +typedef void (GLAD_API_PTR *PFN_vkCmdDispatchTileQCOM)(VkCommandBuffer commandBuffer); typedef void (GLAD_API_PTR *PFN_vkCmdDraw)(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawClusterHUAWEI)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawClusterIndirectHUAWEI)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndexedIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); @@ -9428,107 +16990,226 @@ typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndirectByteCountEXT)(VkCommandBuffer c typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndirectCount)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdDrawIndirectCountKHR)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawMeshTasksEXT)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawMeshTasksIndirectCountEXT)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdDrawMeshTasksIndirectCountNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawMeshTasksIndirectEXT)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdDrawMeshTasksIndirectNV)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); typedef void (GLAD_API_PTR *PFN_vkCmdDrawMeshTasksNV)(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawMultiEXT)(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawInfoEXT * pVertexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride); +typedef void (GLAD_API_PTR *PFN_vkCmdDrawMultiIndexedEXT)(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawIndexedInfoEXT * pIndexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride, const int32_t * pVertexOffset); typedef void (GLAD_API_PTR *PFN_vkCmdEndConditionalRenderingEXT)(VkCommandBuffer commandBuffer); typedef void (GLAD_API_PTR *PFN_vkCmdEndDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer); +typedef void (GLAD_API_PTR *PFN_vkCmdEndPerTileExecutionQCOM)(VkCommandBuffer commandBuffer, const VkPerTileEndInfoQCOM * pPerTileEndInfo); typedef void (GLAD_API_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); typedef void (GLAD_API_PTR *PFN_vkCmdEndQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index); typedef void (GLAD_API_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer commandBuffer); typedef void (GLAD_API_PTR *PFN_vkCmdEndRenderPass2)(VkCommandBuffer commandBuffer, const VkSubpassEndInfo * pSubpassEndInfo); typedef void (GLAD_API_PTR *PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassEndInfo * pSubpassEndInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdEndRendering)(VkCommandBuffer commandBuffer); +typedef void (GLAD_API_PTR *PFN_vkCmdEndRendering2EXT)(VkCommandBuffer commandBuffer, const VkRenderingEndInfoEXT * pRenderingEndInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdEndRenderingKHR)(VkCommandBuffer commandBuffer); typedef void (GLAD_API_PTR *PFN_vkCmdEndTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer * pCounterBuffers, const VkDeviceSize * pCounterBufferOffsets); typedef void (GLAD_API_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer * pCommandBuffers); +typedef void (GLAD_API_PTR *PFN_vkCmdExecuteGeneratedCommandsEXT)(VkCommandBuffer commandBuffer, VkBool32 isPreprocessed, const VkGeneratedCommandsInfoEXT * pGeneratedCommandsInfo); typedef void (GLAD_API_PTR *PFN_vkCmdExecuteGeneratedCommandsNV)(VkCommandBuffer commandBuffer, VkBool32 isPreprocessed, const VkGeneratedCommandsInfoNV * pGeneratedCommandsInfo); typedef void (GLAD_API_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdInitializeGraphScratchMemoryAMDX)(VkCommandBuffer commandBuffer, VkPipeline executionGraph, VkDeviceAddress scratch, VkDeviceSize scratchSize); + +#endif typedef void (GLAD_API_PTR *PFN_vkCmdInsertDebugUtilsLabelEXT)(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT * pLabelInfo); typedef void (GLAD_API_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer commandBuffer, VkSubpassContents contents); typedef void (GLAD_API_PTR *PFN_vkCmdNextSubpass2)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo * pSubpassBeginInfo, const VkSubpassEndInfo * pSubpassEndInfo); typedef void (GLAD_API_PTR *PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo * pSubpassBeginInfo, const VkSubpassEndInfo * pSubpassEndInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdOpticalFlowExecuteNV)(VkCommandBuffer commandBuffer, VkOpticalFlowSessionNV session, const VkOpticalFlowExecuteInfoNV * pExecuteInfo); typedef void (GLAD_API_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier * pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier * pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier * pImageMemoryBarriers); +typedef void (GLAD_API_PTR *PFN_vkCmdPipelineBarrier2)(VkCommandBuffer commandBuffer, const VkDependencyInfo * pDependencyInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdPipelineBarrier2KHR)(VkCommandBuffer commandBuffer, const VkDependencyInfo * pDependencyInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdPreprocessGeneratedCommandsEXT)(VkCommandBuffer commandBuffer, const VkGeneratedCommandsInfoEXT * pGeneratedCommandsInfo, VkCommandBuffer stateCommandBuffer); typedef void (GLAD_API_PTR *PFN_vkCmdPreprocessGeneratedCommandsNV)(VkCommandBuffer commandBuffer, const VkGeneratedCommandsInfoNV * pGeneratedCommandsInfo); typedef void (GLAD_API_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void * pValues); +typedef void (GLAD_API_PTR *PFN_vkCmdPushConstants2)(VkCommandBuffer commandBuffer, const VkPushConstantsInfo * pPushConstantsInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdPushConstants2KHR)(VkCommandBuffer commandBuffer, const VkPushConstantsInfo * pPushConstantsInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSet)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet * pDescriptorWrites); +typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSet2)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetInfo * pPushDescriptorSetInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSet2KHR)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetInfo * pPushDescriptorSetInfo); typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet * pDescriptorWrites); +typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSetWithTemplate)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void * pData); +typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSetWithTemplate2)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetWithTemplateInfo * pPushDescriptorSetWithTemplateInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSetWithTemplate2KHR)(VkCommandBuffer commandBuffer, const VkPushDescriptorSetWithTemplateInfo * pPushDescriptorSetWithTemplateInfo); typedef void (GLAD_API_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void * pData); typedef void (GLAD_API_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (GLAD_API_PTR *PFN_vkCmdResetEvent2)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask); +typedef void (GLAD_API_PTR *PFN_vkCmdResetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask); typedef void (GLAD_API_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); typedef void (GLAD_API_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve * pRegions); +typedef void (GLAD_API_PTR *PFN_vkCmdResolveImage2)(VkCommandBuffer commandBuffer, const VkResolveImageInfo2 * pResolveImageInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdResolveImage2KHR)(VkCommandBuffer commandBuffer, const VkResolveImageInfo2 * pResolveImageInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetAlphaToCoverageEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 alphaToCoverageEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetAlphaToOneEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 alphaToOneEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT)(VkCommandBuffer commandBuffer, VkImageAspectFlags aspectMask); typedef void (GLAD_API_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer commandBuffer, const float blendConstants [4]); typedef void (GLAD_API_PTR *PFN_vkCmdSetCheckpointNV)(VkCommandBuffer commandBuffer, const void * pCheckpointMarker); typedef void (GLAD_API_PTR *PFN_vkCmdSetCoarseSampleOrderNV)(VkCommandBuffer commandBuffer, VkCoarseSampleOrderTypeNV sampleOrderType, uint32_t customSampleOrderCount, const VkCoarseSampleOrderCustomNV * pCustomSampleOrders); +typedef void (GLAD_API_PTR *PFN_vkCmdSetColorBlendAdvancedEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendAdvancedEXT * pColorBlendAdvanced); +typedef void (GLAD_API_PTR *PFN_vkCmdSetColorBlendEnableEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkBool32 * pColorBlendEnables); +typedef void (GLAD_API_PTR *PFN_vkCmdSetColorBlendEquationEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendEquationEXT * pColorBlendEquations); +typedef void (GLAD_API_PTR *PFN_vkCmdSetColorWriteEnableEXT)(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkBool32 * pColorWriteEnables); +typedef void (GLAD_API_PTR *PFN_vkCmdSetColorWriteMaskEXT)(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorComponentFlags * pColorWriteMasks); +typedef void (GLAD_API_PTR *PFN_vkCmdSetConservativeRasterizationModeEXT)(VkCommandBuffer commandBuffer, VkConservativeRasterizationModeEXT conservativeRasterizationMode); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCoverageModulationModeNV)(VkCommandBuffer commandBuffer, VkCoverageModulationModeNV coverageModulationMode); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCoverageModulationTableEnableNV)(VkCommandBuffer commandBuffer, VkBool32 coverageModulationTableEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCoverageModulationTableNV)(VkCommandBuffer commandBuffer, uint32_t coverageModulationTableCount, const float * pCoverageModulationTable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCoverageReductionModeNV)(VkCommandBuffer commandBuffer, VkCoverageReductionModeNV coverageReductionMode); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCoverageToColorEnableNV)(VkCommandBuffer commandBuffer, VkBool32 coverageToColorEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCoverageToColorLocationNV)(VkCommandBuffer commandBuffer, uint32_t coverageToColorLocation); +typedef void (GLAD_API_PTR *PFN_vkCmdSetCullMode)(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode); typedef void (GLAD_API_PTR *PFN_vkCmdSetCullModeEXT)(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode); typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBias2EXT)(VkCommandBuffer commandBuffer, const VkDepthBiasInfoEXT * pDepthBiasInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBiasEnable)(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBiasEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBoundsTestEnable)(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthBoundsTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthClampEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthClampEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthClampRangeEXT)(VkCommandBuffer commandBuffer, VkDepthClampModeEXT depthClampMode, const VkDepthClampRangeEXT * pDepthClampRange); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthClipEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthClipEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthClipNegativeOneToOneEXT)(VkCommandBuffer commandBuffer, VkBool32 negativeOneToOne); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthCompareOp)(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp); typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthCompareOpEXT)(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthTestEnable)(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthWriteEnable)(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetDepthWriteEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDescriptorBufferOffsets2EXT)(VkCommandBuffer commandBuffer, const VkSetDescriptorBufferOffsetsInfoEXT * pSetDescriptorBufferOffsetsInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDescriptorBufferOffsetsEXT)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount, const uint32_t * pBufferIndices, const VkDeviceSize * pOffsets); typedef void (GLAD_API_PTR *PFN_vkCmdSetDeviceMask)(VkCommandBuffer commandBuffer, uint32_t deviceMask); typedef void (GLAD_API_PTR *PFN_vkCmdSetDeviceMaskKHR)(VkCommandBuffer commandBuffer, uint32_t deviceMask); typedef void (GLAD_API_PTR *PFN_vkCmdSetDiscardRectangleEXT)(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const VkRect2D * pDiscardRectangles); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDiscardRectangleEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 discardRectangleEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetDiscardRectangleModeEXT)(VkCommandBuffer commandBuffer, VkDiscardRectangleModeEXT discardRectangleMode); typedef void (GLAD_API_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); +typedef void (GLAD_API_PTR *PFN_vkCmdSetEvent2)(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo * pDependencyInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetEvent2KHR)(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo * pDependencyInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetExclusiveScissorEnableNV)(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount, const VkBool32 * pExclusiveScissorEnables); typedef void (GLAD_API_PTR *PFN_vkCmdSetExclusiveScissorNV)(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount, const VkRect2D * pExclusiveScissors); +typedef void (GLAD_API_PTR *PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT)(VkCommandBuffer commandBuffer, float extraPrimitiveOverestimationSize); +typedef void (GLAD_API_PTR *PFN_vkCmdSetFragmentShadingRateEnumNV)(VkCommandBuffer commandBuffer, VkFragmentShadingRateNV shadingRate, const VkFragmentShadingRateCombinerOpKHR combinerOps [2]); +typedef void (GLAD_API_PTR *PFN_vkCmdSetFragmentShadingRateKHR)(VkCommandBuffer commandBuffer, const VkExtent2D * pFragmentSize, const VkFragmentShadingRateCombinerOpKHR combinerOps [2]); +typedef void (GLAD_API_PTR *PFN_vkCmdSetFrontFace)(VkCommandBuffer commandBuffer, VkFrontFace frontFace); typedef void (GLAD_API_PTR *PFN_vkCmdSetFrontFaceEXT)(VkCommandBuffer commandBuffer, VkFrontFace frontFace); +typedef void (GLAD_API_PTR *PFN_vkCmdSetLineRasterizationModeEXT)(VkCommandBuffer commandBuffer, VkLineRasterizationModeEXT lineRasterizationMode); +typedef void (GLAD_API_PTR *PFN_vkCmdSetLineStipple)(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); typedef void (GLAD_API_PTR *PFN_vkCmdSetLineStippleEXT)(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); +typedef void (GLAD_API_PTR *PFN_vkCmdSetLineStippleEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 stippledLineEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetLineStippleKHR)(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); typedef void (GLAD_API_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer commandBuffer, float lineWidth); +typedef void (GLAD_API_PTR *PFN_vkCmdSetLogicOpEXT)(VkCommandBuffer commandBuffer, VkLogicOp logicOp); +typedef void (GLAD_API_PTR *PFN_vkCmdSetLogicOpEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 logicOpEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetPatchControlPointsEXT)(VkCommandBuffer commandBuffer, uint32_t patchControlPoints); typedef VkResult (GLAD_API_PTR *PFN_vkCmdSetPerformanceMarkerINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceMarkerInfoINTEL * pMarkerInfo); typedef VkResult (GLAD_API_PTR *PFN_vkCmdSetPerformanceOverrideINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceOverrideInfoINTEL * pOverrideInfo); typedef VkResult (GLAD_API_PTR *PFN_vkCmdSetPerformanceStreamMarkerINTEL)(VkCommandBuffer commandBuffer, const VkPerformanceStreamMarkerInfoINTEL * pMarkerInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetPolygonModeEXT)(VkCommandBuffer commandBuffer, VkPolygonMode polygonMode); +typedef void (GLAD_API_PTR *PFN_vkCmdSetPrimitiveRestartEnable)(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetPrimitiveRestartEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetPrimitiveTopology)(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology); typedef void (GLAD_API_PTR *PFN_vkCmdSetPrimitiveTopologyEXT)(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology); +typedef void (GLAD_API_PTR *PFN_vkCmdSetProvokingVertexModeEXT)(VkCommandBuffer commandBuffer, VkProvokingVertexModeEXT provokingVertexMode); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRasterizationSamplesEXT)(VkCommandBuffer commandBuffer, VkSampleCountFlagBits rasterizationSamples); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRasterizationStreamEXT)(VkCommandBuffer commandBuffer, uint32_t rasterizationStream); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRasterizerDiscardEnable)(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRasterizerDiscardEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRayTracingPipelineStackSizeKHR)(VkCommandBuffer commandBuffer, uint32_t pipelineStackSize); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRenderingAttachmentLocations)(VkCommandBuffer commandBuffer, const VkRenderingAttachmentLocationInfo * pLocationInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRenderingAttachmentLocationsKHR)(VkCommandBuffer commandBuffer, const VkRenderingAttachmentLocationInfo * pLocationInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRenderingInputAttachmentIndices)(VkCommandBuffer commandBuffer, const VkRenderingInputAttachmentIndexInfo * pInputAttachmentIndexInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRenderingInputAttachmentIndicesKHR)(VkCommandBuffer commandBuffer, const VkRenderingInputAttachmentIndexInfo * pInputAttachmentIndexInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetRepresentativeFragmentTestEnableNV)(VkCommandBuffer commandBuffer, VkBool32 representativeFragmentTestEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetSampleLocationsEXT)(VkCommandBuffer commandBuffer, const VkSampleLocationsInfoEXT * pSampleLocationsInfo); +typedef void (GLAD_API_PTR *PFN_vkCmdSetSampleLocationsEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 sampleLocationsEnable); +typedef void (GLAD_API_PTR *PFN_vkCmdSetSampleMaskEXT)(VkCommandBuffer commandBuffer, VkSampleCountFlagBits samples, const VkSampleMask * pSampleMask); typedef void (GLAD_API_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D * pScissors); +typedef void (GLAD_API_PTR *PFN_vkCmdSetScissorWithCount)(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D * pScissors); typedef void (GLAD_API_PTR *PFN_vkCmdSetScissorWithCountEXT)(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D * pScissors); +typedef void (GLAD_API_PTR *PFN_vkCmdSetShadingRateImageEnableNV)(VkCommandBuffer commandBuffer, VkBool32 shadingRateImageEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); +typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilOp)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilOpEXT)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); +typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilTestEnable)(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilTestEnableEXT)(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); +typedef void (GLAD_API_PTR *PFN_vkCmdSetTessellationDomainOriginEXT)(VkCommandBuffer commandBuffer, VkTessellationDomainOrigin domainOrigin); +typedef void (GLAD_API_PTR *PFN_vkCmdSetVertexInputEXT)(VkCommandBuffer commandBuffer, uint32_t vertexBindingDescriptionCount, const VkVertexInputBindingDescription2EXT * pVertexBindingDescriptions, uint32_t vertexAttributeDescriptionCount, const VkVertexInputAttributeDescription2EXT * pVertexAttributeDescriptions); typedef void (GLAD_API_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport * pViewports); typedef void (GLAD_API_PTR *PFN_vkCmdSetViewportShadingRatePaletteNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkShadingRatePaletteNV * pShadingRatePalettes); +typedef void (GLAD_API_PTR *PFN_vkCmdSetViewportSwizzleNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportSwizzleNV * pViewportSwizzles); +typedef void (GLAD_API_PTR *PFN_vkCmdSetViewportWScalingEnableNV)(VkCommandBuffer commandBuffer, VkBool32 viewportWScalingEnable); typedef void (GLAD_API_PTR *PFN_vkCmdSetViewportWScalingNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV * pViewportWScalings); +typedef void (GLAD_API_PTR *PFN_vkCmdSetViewportWithCount)(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport * pViewports); typedef void (GLAD_API_PTR *PFN_vkCmdSetViewportWithCountEXT)(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport * pViewports); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef void (GLAD_API_PTR *PFN_vkCmdTraceRaysIndirectKHR)(VkCommandBuffer commandBuffer, const VkStridedBufferRegionKHR * pRaygenShaderBindingTable, const VkStridedBufferRegionKHR * pMissShaderBindingTable, const VkStridedBufferRegionKHR * pHitShaderBindingTable, const VkStridedBufferRegionKHR * pCallableShaderBindingTable, VkBuffer buffer, VkDeviceSize offset); -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef void (GLAD_API_PTR *PFN_vkCmdTraceRaysKHR)(VkCommandBuffer commandBuffer, const VkStridedBufferRegionKHR * pRaygenShaderBindingTable, const VkStridedBufferRegionKHR * pMissShaderBindingTable, const VkStridedBufferRegionKHR * pHitShaderBindingTable, const VkStridedBufferRegionKHR * pCallableShaderBindingTable, uint32_t width, uint32_t height, uint32_t depth); -#endif +typedef void (GLAD_API_PTR *PFN_vkCmdSubpassShadingHUAWEI)(VkCommandBuffer commandBuffer); +typedef void (GLAD_API_PTR *PFN_vkCmdTraceRaysIndirect2KHR)(VkCommandBuffer commandBuffer, VkDeviceAddress indirectDeviceAddress); +typedef void (GLAD_API_PTR *PFN_vkCmdTraceRaysIndirectKHR)(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR * pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR * pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR * pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR * pCallableShaderBindingTable, VkDeviceAddress indirectDeviceAddress); +typedef void (GLAD_API_PTR *PFN_vkCmdTraceRaysKHR)(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR * pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR * pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR * pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR * pCallableShaderBindingTable, uint32_t width, uint32_t height, uint32_t depth); typedef void (GLAD_API_PTR *PFN_vkCmdTraceRaysNV)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth); typedef void (GLAD_API_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void * pData); +typedef void (GLAD_API_PTR *PFN_vkCmdUpdatePipelineIndirectBufferNV)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); typedef void (GLAD_API_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent * pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier * pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier * pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier * pImageMemoryBarriers); -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkCmdWaitEvents2)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent * pEvents, const VkDependencyInfo * pDependencyInfos); +typedef void (GLAD_API_PTR *PFN_vkCmdWaitEvents2KHR)(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent * pEvents, const VkDependencyInfo * pDependencyInfos); typedef void (GLAD_API_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR * pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); -#endif -typedef void (GLAD_API_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR * pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef void (GLAD_API_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV * pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef void (GLAD_API_PTR *PFN_vkCmdWriteBufferMarker2AMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); typedef void (GLAD_API_PTR *PFN_vkCmdWriteBufferMarkerAMD)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); +typedef void (GLAD_API_PTR *PFN_vkCmdWriteMicromapsPropertiesEXT)(VkCommandBuffer commandBuffer, uint32_t micromapCount, const VkMicromapEXT * pMicromaps, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); typedef void (GLAD_API_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); +typedef void (GLAD_API_PTR *PFN_vkCmdWriteTimestamp2)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query); +typedef void (GLAD_API_PTR *PFN_vkCmdWriteTimestamp2KHR)(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query); typedef VkResult (GLAD_API_PTR *PFN_vkCompileDeferredNV)(VkDevice device, VkPipeline pipeline, uint32_t shader); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkCopyAccelerationStructureKHR)(VkDevice device, const VkCopyAccelerationStructureInfoKHR * pInfo); -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkCopyAccelerationStructureToMemoryKHR)(VkDevice device, const VkCopyAccelerationStructureToMemoryInfoKHR * pInfo); -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkCopyMemoryToAccelerationStructureKHR)(VkDevice device, const VkCopyMemoryToAccelerationStructureInfoKHR * pInfo); -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef VkResult (GLAD_API_PTR *PFN_vkConvertCooperativeVectorMatrixNV)(VkDevice device, const VkConvertCooperativeVectorMatrixInfoNV * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyAccelerationStructureKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureInfoKHR * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyAccelerationStructureToMemoryKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureToMemoryInfoKHR * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyImageToImage)(VkDevice device, const VkCopyImageToImageInfo * pCopyImageToImageInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyImageToImageEXT)(VkDevice device, const VkCopyImageToImageInfo * pCopyImageToImageInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyImageToMemory)(VkDevice device, const VkCopyImageToMemoryInfo * pCopyImageToMemoryInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyImageToMemoryEXT)(VkDevice device, const VkCopyImageToMemoryInfo * pCopyImageToMemoryInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyMemoryToAccelerationStructureKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToAccelerationStructureInfoKHR * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyMemoryToImage)(VkDevice device, const VkCopyMemoryToImageInfo * pCopyMemoryToImageInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyMemoryToImageEXT)(VkDevice device, const VkCopyMemoryToImageInfo * pCopyMemoryToImageInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyMemoryToMicromapEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToMicromapInfoEXT * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyMicromapEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapInfoEXT * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkCopyMicromapToMemoryEXT)(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapToMemoryInfoEXT * pInfo); typedef VkResult (GLAD_API_PTR *PFN_vkCreateAccelerationStructureKHR)(VkDevice device, const VkAccelerationStructureCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkAccelerationStructureKHR * pAccelerationStructure); -#endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateAccelerationStructureNV)(VkDevice device, const VkAccelerationStructureCreateInfoNV * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkAccelerationStructureNV * pAccelerationStructure); #if defined(VK_USE_PLATFORM_ANDROID_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkCreateAndroidSurfaceKHR)(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateBuffer)(VkDevice device, const VkBufferCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkBuffer * pBuffer); +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkCreateBufferCollectionFUCHSIA)(VkDevice device, const VkBufferCollectionCreateInfoFUCHSIA * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkBufferCollectionFUCHSIA * pCollection); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateBufferView)(VkDevice device, const VkBufferViewCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkBufferView * pView); typedef VkResult (GLAD_API_PTR *PFN_vkCreateCommandPool)(VkDevice device, const VkCommandPoolCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkCommandPool * pCommandPool); typedef VkResult (GLAD_API_PTR *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateCuFunctionNVX)(VkDevice device, const VkCuFunctionCreateInfoNVX * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkCuFunctionNVX * pFunction); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateCuModuleNVX)(VkDevice device, const VkCuModuleCreateInfoNVX * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkCuModuleNVX * pModule); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef VkResult (GLAD_API_PTR *PFN_vkCreateCudaFunctionNV)(VkDevice device, const VkCudaFunctionCreateInfoNV * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkCudaFunctionNV * pFunction); + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef VkResult (GLAD_API_PTR *PFN_vkCreateCudaModuleNV)(VkDevice device, const VkCudaModuleCreateInfoNV * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkCudaModuleNV * pModule); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDebugReportCallbackEXT * pCallback); typedef VkResult (GLAD_API_PTR *PFN_vkCreateDebugUtilsMessengerEXT)(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDebugUtilsMessengerEXT * pMessenger); -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef VkResult (GLAD_API_PTR *PFN_vkCreateDeferredOperationKHR)(VkDevice device, const VkAllocationCallbacks * pAllocator, VkDeferredOperationKHR * pDeferredOperation); -#endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorPool)(VkDevice device, const VkDescriptorPoolCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDescriptorPool * pDescriptorPool); typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDescriptorSetLayout * pSetLayout); typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorUpdateTemplate)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDescriptorUpdateTemplate * pDescriptorUpdateTemplate); @@ -9536,37 +17217,51 @@ typedef VkResult (GLAD_API_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevic typedef VkResult (GLAD_API_PTR *PFN_vkCreateDevice)(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDevice * pDevice); #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) typedef VkResult (GLAD_API_PTR *PFN_vkCreateDirectFBSurfaceEXT)(VkInstance instance, const VkDirectFBSurfaceCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateDisplayModeKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, const VkDisplayModeCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkDisplayModeKHR * pMode); typedef VkResult (GLAD_API_PTR *PFN_vkCreateDisplayPlaneSurfaceKHR)(VkInstance instance, const VkDisplaySurfaceCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); typedef VkResult (GLAD_API_PTR *PFN_vkCreateEvent)(VkDevice device, const VkEventCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkEvent * pEvent); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef VkResult (GLAD_API_PTR *PFN_vkCreateExecutionGraphPipelinesAMDX)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkExecutionGraphPipelineCreateInfoAMDX * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); + +#endif +typedef VkResult (GLAD_API_PTR *PFN_vkCreateExternalComputeQueueNV)(VkDevice device, const VkExternalComputeQueueCreateInfoNV * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkExternalComputeQueueNV * pExternalQueue); typedef VkResult (GLAD_API_PTR *PFN_vkCreateFence)(VkDevice device, const VkFenceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkFence * pFence); typedef VkResult (GLAD_API_PTR *PFN_vkCreateFramebuffer)(VkDevice device, const VkFramebufferCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkFramebuffer * pFramebuffer); typedef VkResult (GLAD_API_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); typedef VkResult (GLAD_API_PTR *PFN_vkCreateHeadlessSurfaceEXT)(VkInstance instance, const VkHeadlessSurfaceCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); #if defined(VK_USE_PLATFORM_IOS_MVK) typedef VkResult (GLAD_API_PTR *PFN_vkCreateIOSSurfaceMVK)(VkInstance instance, const VkIOSSurfaceCreateInfoMVK * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateImage)(VkDevice device, const VkImageCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkImage * pImage); #if defined(VK_USE_PLATFORM_FUCHSIA) typedef VkResult (GLAD_API_PTR *PFN_vkCreateImagePipeSurfaceFUCHSIA)(VkInstance instance, const VkImagePipeSurfaceCreateInfoFUCHSIA * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateImageView)(VkDevice device, const VkImageViewCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkImageView * pView); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateIndirectCommandsLayoutEXT)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkIndirectCommandsLayoutEXT * pIndirectCommandsLayout); typedef VkResult (GLAD_API_PTR *PFN_vkCreateIndirectCommandsLayoutNV)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNV * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkIndirectCommandsLayoutNV * pIndirectCommandsLayout); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateIndirectExecutionSetEXT)(VkDevice device, const VkIndirectExecutionSetCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkIndirectExecutionSetEXT * pIndirectExecutionSet); typedef VkResult (GLAD_API_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkInstance * pInstance); #if defined(VK_USE_PLATFORM_MACOS_MVK) typedef VkResult (GLAD_API_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif #if defined(VK_USE_PLATFORM_METAL_EXT) typedef VkResult (GLAD_API_PTR *PFN_vkCreateMetalSurfaceEXT)(VkInstance instance, const VkMetalSurfaceCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif +typedef VkResult (GLAD_API_PTR *PFN_vkCreateMicromapEXT)(VkDevice device, const VkMicromapCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkMicromapEXT * pMicromap); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateOpticalFlowSessionNV)(VkDevice device, const VkOpticalFlowSessionCreateInfoNV * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkOpticalFlowSessionNV * pSession); +typedef VkResult (GLAD_API_PTR *PFN_vkCreatePipelineBinariesKHR)(VkDevice device, const VkPipelineBinaryCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPipelineBinaryHandlesInfoKHR * pBinaries); typedef VkResult (GLAD_API_PTR *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPipelineCache * pPipelineCache); typedef VkResult (GLAD_API_PTR *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPipelineLayout * pPipelineLayout); -typedef VkResult (GLAD_API_PTR *PFN_vkCreatePrivateDataSlotEXT)(VkDevice device, const VkPrivateDataSlotCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPrivateDataSlotEXT * pPrivateDataSlot); +typedef VkResult (GLAD_API_PTR *PFN_vkCreatePrivateDataSlot)(VkDevice device, const VkPrivateDataSlotCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPrivateDataSlot * pPrivateDataSlot); +typedef VkResult (GLAD_API_PTR *PFN_vkCreatePrivateDataSlotEXT)(VkDevice device, const VkPrivateDataSlotCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkPrivateDataSlot * pPrivateDataSlot); typedef VkResult (GLAD_API_PTR *PFN_vkCreateQueryPool)(VkDevice device, const VkQueryPoolCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkQueryPool * pQueryPool); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkCreateRayTracingPipelinesKHR)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoKHR * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); -#endif +typedef VkResult (GLAD_API_PTR *PFN_vkCreateRayTracingPipelinesKHR)(VkDevice device, VkDeferredOperationKHR deferredOperation, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoKHR * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); typedef VkResult (GLAD_API_PTR *PFN_vkCreateRayTracingPipelinesNV)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkPipeline * pPipelines); typedef VkResult (GLAD_API_PTR *PFN_vkCreateRenderPass)(VkDevice device, const VkRenderPassCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkRenderPass * pRenderPass); typedef VkResult (GLAD_API_PTR *PFN_vkCreateRenderPass2)(VkDevice device, const VkRenderPassCreateInfo2 * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkRenderPass * pRenderPass); @@ -9574,69 +17269,96 @@ typedef VkResult (GLAD_API_PTR *PFN_vkCreateRenderPass2KHR)(VkDevice device, con typedef VkResult (GLAD_API_PTR *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSampler * pSampler); typedef VkResult (GLAD_API_PTR *PFN_vkCreateSamplerYcbcrConversion)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSamplerYcbcrConversion * pYcbcrConversion); typedef VkResult (GLAD_API_PTR *PFN_vkCreateSamplerYcbcrConversionKHR)(VkDevice device, const VkSamplerYcbcrConversionCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSamplerYcbcrConversion * pYcbcrConversion); +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef VkResult (GLAD_API_PTR *PFN_vkCreateScreenSurfaceQNX)(VkInstance instance, const VkScreenSurfaceCreateInfoQNX * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateSemaphore)(VkDevice device, const VkSemaphoreCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSemaphore * pSemaphore); typedef VkResult (GLAD_API_PTR *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkShaderModule * pShaderModule); +typedef VkResult (GLAD_API_PTR *PFN_vkCreateShadersEXT)(VkDevice device, uint32_t createInfoCount, const VkShaderCreateInfoEXT * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkShaderEXT * pShaders); typedef VkResult (GLAD_API_PTR *PFN_vkCreateSharedSwapchainsKHR)(VkDevice device, uint32_t swapchainCount, const VkSwapchainCreateInfoKHR * pCreateInfos, const VkAllocationCallbacks * pAllocator, VkSwapchainKHR * pSwapchains); #if defined(VK_USE_PLATFORM_GGP) typedef VkResult (GLAD_API_PTR *PFN_vkCreateStreamDescriptorSurfaceGGP)(VkInstance instance, const VkStreamDescriptorSurfaceCreateInfoGGP * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkCreateSwapchainKHR)(VkDevice device, const VkSwapchainCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSwapchainKHR * pSwapchain); typedef VkResult (GLAD_API_PTR *PFN_vkCreateValidationCacheEXT)(VkDevice device, const VkValidationCacheCreateInfoEXT * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkValidationCacheEXT * pValidationCache); #if defined(VK_USE_PLATFORM_VI_NN) typedef VkResult (GLAD_API_PTR *PFN_vkCreateViSurfaceNN)(VkInstance instance, const VkViSurfaceCreateInfoNN * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkCreateWin32SurfaceKHR)(VkInstance instance, const VkWin32SurfaceCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkCreateXcbSurfaceKHR)(VkInstance instance, const VkXcbSurfaceCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkCreateXlibSurfaceKHR)(VkInstance instance, const VkXlibSurfaceCreateInfoKHR * pCreateInfo, const VkAllocationCallbacks * pAllocator, VkSurfaceKHR * pSurface); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice device, const VkDebugMarkerObjectNameInfoEXT * pNameInfo); typedef VkResult (GLAD_API_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice device, const VkDebugMarkerObjectTagInfoEXT * pTagInfo); typedef void (GLAD_API_PTR *PFN_vkDebugReportMessageEXT)(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char * pLayerPrefix, const char * pMessage); -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef VkResult (GLAD_API_PTR *PFN_vkDeferredOperationJoinKHR)(VkDevice device, VkDeferredOperationKHR operation); +typedef void (GLAD_API_PTR *PFN_vkDestroyAccelerationStructureKHR)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks * pAllocator); +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef void (GLAD_API_PTR *PFN_vkDestroyBufferCollectionFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkAllocationCallbacks * pAllocator); + +#endif +typedef void (GLAD_API_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyCuFunctionNVX)(VkDevice device, VkCuFunctionNVX function, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyCuModuleNVX)(VkDevice device, VkCuModuleNVX module, const VkAllocationCallbacks * pAllocator); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkDestroyCudaFunctionNV)(VkDevice device, VkCudaFunctionNV function, const VkAllocationCallbacks * pAllocator); + #endif #if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef void (GLAD_API_PTR *PFN_vkDestroyAccelerationStructureKHR)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyCudaModuleNV)(VkDevice device, VkCudaModuleNV module, const VkAllocationCallbacks * pAllocator); + #endif -typedef void (GLAD_API_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks * pAllocator); -typedef void (GLAD_API_PTR *PFN_vkDestroyBuffer)(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks * pAllocator); -typedef void (GLAD_API_PTR *PFN_vkDestroyBufferView)(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks * pAllocator); -typedef void (GLAD_API_PTR *PFN_vkDestroyCommandPool)(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyDebugUtilsMessengerEXT)(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks * pAllocator); -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef void (GLAD_API_PTR *PFN_vkDestroyDeferredOperationKHR)(VkDevice device, VkDeferredOperationKHR operation, const VkAllocationCallbacks * pAllocator); -#endif typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorUpdateTemplate)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyDevice)(VkDevice device, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyEvent)(VkDevice device, VkEvent event, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyExternalComputeQueueNV)(VkDevice device, VkExternalComputeQueueNV externalQueue, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyFramebuffer)(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyImageView)(VkDevice device, VkImageView imageView, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyIndirectCommandsLayoutEXT)(VkDevice device, VkIndirectCommandsLayoutEXT indirectCommandsLayout, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyIndirectCommandsLayoutNV)(VkDevice device, VkIndirectCommandsLayoutNV indirectCommandsLayout, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyIndirectExecutionSetEXT)(VkDevice device, VkIndirectExecutionSetEXT indirectExecutionSet, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyInstance)(VkInstance instance, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyMicromapEXT)(VkDevice device, VkMicromapEXT micromap, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyOpticalFlowSessionNV)(VkDevice device, VkOpticalFlowSessionNV session, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyPipeline)(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyPipelineBinaryKHR)(VkDevice device, VkPipelineBinaryKHR pipelineBinary, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyPipelineLayout)(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks * pAllocator); -typedef void (GLAD_API_PTR *PFN_vkDestroyPrivateDataSlotEXT)(VkDevice device, VkPrivateDataSlotEXT privateDataSlot, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyPrivateDataSlot)(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyPrivateDataSlotEXT)(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyQueryPool)(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyRenderPass)(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroySampler)(VkDevice device, VkSampler sampler, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroySamplerYcbcrConversion)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroySamplerYcbcrConversionKHR)(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroySemaphore)(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks * pAllocator); +typedef void (GLAD_API_PTR *PFN_vkDestroyShaderEXT)(VkDevice device, VkShaderEXT shader, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroyShaderModule)(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroySurfaceKHR)(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks * pAllocator); typedef void (GLAD_API_PTR *PFN_vkDestroySwapchainKHR)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks * pAllocator); @@ -9653,20 +17375,26 @@ typedef VkResult (GLAD_API_PTR *PFN_vkEnumeratePhysicalDeviceGroups)(VkInstance typedef VkResult (GLAD_API_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHR)(VkInstance instance, uint32_t * pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties * pPhysicalDeviceGroupProperties); typedef VkResult (GLAD_API_PTR *PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t * pCounterCount, VkPerformanceCounterKHR * pCounters, VkPerformanceCounterDescriptionKHR * pCounterDescriptions); typedef VkResult (GLAD_API_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance instance, uint32_t * pPhysicalDeviceCount, VkPhysicalDevice * pPhysicalDevices); +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef void (GLAD_API_PTR *PFN_vkExportMetalObjectsEXT)(VkDevice device, VkExportMetalObjectsInfoEXT * pMetalObjectsInfo); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange * pMemoryRanges); typedef void (GLAD_API_PTR *PFN_vkFreeCommandBuffers)(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer * pCommandBuffers); typedef VkResult (GLAD_API_PTR *PFN_vkFreeDescriptorSets)(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet * pDescriptorSets); typedef void (GLAD_API_PTR *PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks * pAllocator); -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef void (GLAD_API_PTR *PFN_vkGetAccelerationStructureBuildSizesKHR)(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkAccelerationStructureBuildGeometryInfoKHR * pBuildInfo, const uint32_t * pMaxPrimitiveCounts, VkAccelerationStructureBuildSizesInfoKHR * pSizeInfo); typedef VkDeviceAddress (GLAD_API_PTR *PFN_vkGetAccelerationStructureDeviceAddressKHR)(VkDevice device, const VkAccelerationStructureDeviceAddressInfoKHR * pInfo); -#endif -typedef VkResult (GLAD_API_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureKHR accelerationStructure, size_t dataSize, void * pData); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef void (GLAD_API_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsKHR)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoKHR * pInfo, VkMemoryRequirements2 * pMemoryRequirements); -#endif +typedef VkResult (GLAD_API_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void * pData); typedef void (GLAD_API_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV * pInfo, VkMemoryRequirements2KHR * pMemoryRequirements); +typedef VkResult (GLAD_API_PTR *PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkAccelerationStructureCaptureDescriptorDataInfoEXT * pInfo, void * pData); #if defined(VK_USE_PLATFORM_ANDROID_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetAndroidHardwareBufferPropertiesANDROID)(VkDevice device, const struct AHardwareBuffer * buffer, VkAndroidHardwareBufferPropertiesANDROID * pProperties); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkGetBufferCollectionPropertiesFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, VkBufferCollectionPropertiesFUCHSIA * pProperties); + #endif typedef VkDeviceAddress (GLAD_API_PTR *PFN_vkGetBufferDeviceAddress)(VkDevice device, const VkBufferDeviceAddressInfo * pInfo); typedef VkDeviceAddress (GLAD_API_PTR *PFN_vkGetBufferDeviceAddressEXT)(VkDevice device, const VkBufferDeviceAddressInfo * pInfo); @@ -9676,75 +17404,142 @@ typedef void (GLAD_API_PTR *PFN_vkGetBufferMemoryRequirements2)(VkDevice device, typedef void (GLAD_API_PTR *PFN_vkGetBufferMemoryRequirements2KHR)(VkDevice device, const VkBufferMemoryRequirementsInfo2 * pInfo, VkMemoryRequirements2 * pMemoryRequirements); typedef uint64_t (GLAD_API_PTR *PFN_vkGetBufferOpaqueCaptureAddress)(VkDevice device, const VkBufferDeviceAddressInfo * pInfo); typedef uint64_t (GLAD_API_PTR *PFN_vkGetBufferOpaqueCaptureAddressKHR)(VkDevice device, const VkBufferDeviceAddressInfo * pInfo); -typedef VkResult (GLAD_API_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT * pTimestampInfos, uint64_t * pTimestamps, uint64_t * pMaxDeviation); +typedef VkResult (GLAD_API_PTR *PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkBufferCaptureDescriptorDataInfoEXT * pInfo, void * pData); +typedef VkResult (GLAD_API_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoKHR * pTimestampInfos, uint64_t * pTimestamps, uint64_t * pMaxDeviation); +typedef VkResult (GLAD_API_PTR *PFN_vkGetCalibratedTimestampsKHR)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoKHR * pTimestampInfos, uint64_t * pTimestamps, uint64_t * pMaxDeviation); +typedef void (GLAD_API_PTR *PFN_vkGetClusterAccelerationStructureBuildSizesNV)(VkDevice device, const VkClusterAccelerationStructureInputInfoNV * pInfo, VkAccelerationStructureBuildSizesInfoKHR * pSizeInfo); #if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef uint32_t (GLAD_API_PTR *PFN_vkGetDeferredOperationMaxConcurrencyKHR)(VkDevice device, VkDeferredOperationKHR operation); +typedef VkResult (GLAD_API_PTR *PFN_vkGetCudaModuleCacheNV)(VkDevice device, VkCudaModuleNV module, size_t * pCacheSize, void * pCacheData); + #endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef uint32_t (GLAD_API_PTR *PFN_vkGetDeferredOperationMaxConcurrencyKHR)(VkDevice device, VkDeferredOperationKHR operation); typedef VkResult (GLAD_API_PTR *PFN_vkGetDeferredOperationResultKHR)(VkDevice device, VkDeferredOperationKHR operation); -#endif +typedef void (GLAD_API_PTR *PFN_vkGetDescriptorEXT)(VkDevice device, const VkDescriptorGetInfoEXT * pDescriptorInfo, size_t dataSize, void * pDescriptor); +typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetHostMappingVALVE)(VkDevice device, VkDescriptorSet descriptorSet, void ** ppData); +typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetLayoutBindingOffsetEXT)(VkDevice device, VkDescriptorSetLayout layout, uint32_t binding, VkDeviceSize * pOffset); +typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE)(VkDevice device, const VkDescriptorSetBindingReferenceVALVE * pBindingReference, VkDescriptorSetLayoutHostMappingInfoVALVE * pHostMapping); +typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetLayoutSizeEXT)(VkDevice device, VkDescriptorSetLayout layout, VkDeviceSize * pLayoutSizeInBytes); typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetLayoutSupport)(VkDevice device, const VkDescriptorSetLayoutCreateInfo * pCreateInfo, VkDescriptorSetLayoutSupport * pSupport); typedef void (GLAD_API_PTR *PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice device, const VkDescriptorSetLayoutCreateInfo * pCreateInfo, VkDescriptorSetLayoutSupport * pSupport); -#if defined(VK_ENABLE_BETA_EXTENSIONS) -typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)(VkDevice device, const VkAccelerationStructureVersionKHR * version); -#endif +typedef void (GLAD_API_PTR *PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)(VkDevice device, const VkAccelerationStructureVersionInfoKHR * pVersionInfo, VkAccelerationStructureCompatibilityKHR * pCompatibility); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceBufferMemoryRequirements)(VkDevice device, const VkDeviceBufferMemoryRequirements * pInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceBufferMemoryRequirementsKHR)(VkDevice device, const VkDeviceBufferMemoryRequirements * pInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceFaultInfoEXT)(VkDevice device, VkDeviceFaultCountsEXT * pFaultCounts, VkDeviceFaultInfoEXT * pFaultInfo); typedef void (GLAD_API_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags * pPeerMemoryFeatures); typedef void (GLAD_API_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags * pPeerMemoryFeatures); typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR * pDeviceGroupPresentCapabilities); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceGroupSurfacePresentModes2EXT)(VkDevice device, const VkPhysicalDeviceSurfaceInfo2KHR * pSurfaceInfo, VkDeviceGroupPresentModeFlagsKHR * pModes); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR * pModes); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageMemoryRequirements)(VkDevice device, const VkDeviceImageMemoryRequirements * pInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageMemoryRequirementsKHR)(VkDevice device, const VkDeviceImageMemoryRequirements * pInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageSparseMemoryRequirements)(VkDevice device, const VkDeviceImageMemoryRequirements * pInfo, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageSparseMemoryRequirementsKHR)(VkDevice device, const VkDeviceImageMemoryRequirements * pInfo, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageSubresourceLayout)(VkDevice device, const VkDeviceImageSubresourceInfo * pInfo, VkSubresourceLayout2 * pLayout); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceImageSubresourceLayoutKHR)(VkDevice device, const VkDeviceImageSubresourceInfo * pInfo, VkSubresourceLayout2 * pLayout); typedef void (GLAD_API_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice device, VkDeviceMemory memory, VkDeviceSize * pCommittedMemoryInBytes); typedef uint64_t (GLAD_API_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddress)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo * pInfo); typedef uint64_t (GLAD_API_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo * pInfo); +typedef void (GLAD_API_PTR *PFN_vkGetDeviceMicromapCompatibilityEXT)(VkDevice device, const VkMicromapVersionInfoEXT * pVersionInfo, VkAccelerationStructureCompatibilityKHR * pCompatibility); typedef PFN_vkVoidFunction (GLAD_API_PTR *PFN_vkGetDeviceProcAddr)(VkDevice device, const char * pName); typedef void (GLAD_API_PTR *PFN_vkGetDeviceQueue)(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue * pQueue); typedef void (GLAD_API_PTR *PFN_vkGetDeviceQueue2)(VkDevice device, const VkDeviceQueueInfo2 * pQueueInfo, VkQueue * pQueue); +typedef VkResult (GLAD_API_PTR *PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI)(VkDevice device, VkRenderPass renderpass, VkExtent2D * pMaxWorkgroupSize); typedef VkResult (GLAD_API_PTR *PFN_vkGetDisplayModeProperties2KHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t * pPropertyCount, VkDisplayModeProperties2KHR * pProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetDisplayModePropertiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t * pPropertyCount, VkDisplayModePropertiesKHR * pProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetDisplayPlaneCapabilities2KHR)(VkPhysicalDevice physicalDevice, const VkDisplayPlaneInfo2KHR * pDisplayPlaneInfo, VkDisplayPlaneCapabilities2KHR * pCapabilities); typedef VkResult (GLAD_API_PTR *PFN_vkGetDisplayPlaneCapabilitiesKHR)(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR * pCapabilities); typedef VkResult (GLAD_API_PTR *PFN_vkGetDisplayPlaneSupportedDisplaysKHR)(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t * pDisplayCount, VkDisplayKHR * pDisplays); +typedef VkResult (GLAD_API_PTR *PFN_vkGetDrmDisplayEXT)(VkPhysicalDevice physicalDevice, int32_t drmFd, uint32_t connectorId, VkDisplayKHR * display); +typedef VkResult (GLAD_API_PTR *PFN_vkGetDynamicRenderingTilePropertiesQCOM)(VkDevice device, const VkRenderingInfo * pRenderingInfo, VkTilePropertiesQCOM * pProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetEventStatus)(VkDevice device, VkEvent event); +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef VkResult (GLAD_API_PTR *PFN_vkGetExecutionGraphPipelineNodeIndexAMDX)(VkDevice device, VkPipeline executionGraph, const VkPipelineShaderStageNodeCreateInfoAMDX * pNodeInfo, uint32_t * pNodeIndex); + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +typedef VkResult (GLAD_API_PTR *PFN_vkGetExecutionGraphPipelineScratchSizeAMDX)(VkDevice device, VkPipeline executionGraph, VkExecutionGraphPipelineScratchSizeAMDX * pSizeInfo); + +#endif +typedef void (GLAD_API_PTR *PFN_vkGetExternalComputeQueueDataNV)(VkExternalComputeQueueNV externalQueue, VkExternalComputeQueueDataParamsNV * params, void * pData); typedef VkResult (GLAD_API_PTR *PFN_vkGetFenceFdKHR)(VkDevice device, const VkFenceGetFdInfoKHR * pGetFdInfo, int * pFd); typedef VkResult (GLAD_API_PTR *PFN_vkGetFenceStatus)(VkDevice device, VkFence fence); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetFenceWin32HandleKHR)(VkDevice device, const VkFenceGetWin32HandleInfoKHR * pGetWin32HandleInfo, HANDLE * pHandle); + #endif +typedef VkResult (GLAD_API_PTR *PFN_vkGetFramebufferTilePropertiesQCOM)(VkDevice device, VkFramebuffer framebuffer, uint32_t * pPropertiesCount, VkTilePropertiesQCOM * pProperties); +typedef void (GLAD_API_PTR *PFN_vkGetGeneratedCommandsMemoryRequirementsEXT)(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoEXT * pInfo, VkMemoryRequirements2 * pMemoryRequirements); typedef void (GLAD_API_PTR *PFN_vkGetGeneratedCommandsMemoryRequirementsNV)(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoNV * pInfo, VkMemoryRequirements2 * pMemoryRequirements); typedef VkResult (GLAD_API_PTR *PFN_vkGetImageDrmFormatModifierPropertiesEXT)(VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT * pProperties); typedef void (GLAD_API_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice device, VkImage image, VkMemoryRequirements * pMemoryRequirements); typedef void (GLAD_API_PTR *PFN_vkGetImageMemoryRequirements2)(VkDevice device, const VkImageMemoryRequirementsInfo2 * pInfo, VkMemoryRequirements2 * pMemoryRequirements); typedef void (GLAD_API_PTR *PFN_vkGetImageMemoryRequirements2KHR)(VkDevice device, const VkImageMemoryRequirementsInfo2 * pInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef VkResult (GLAD_API_PTR *PFN_vkGetImageOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkImageCaptureDescriptorDataInfoEXT * pInfo, void * pData); typedef void (GLAD_API_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice device, VkImage image, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements * pSparseMemoryRequirements); typedef void (GLAD_API_PTR *PFN_vkGetImageSparseMemoryRequirements2)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2 * pInfo, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements); typedef void (GLAD_API_PTR *PFN_vkGetImageSparseMemoryRequirements2KHR)(VkDevice device, const VkImageSparseMemoryRequirementsInfo2 * pInfo, uint32_t * pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements); typedef void (GLAD_API_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice device, VkImage image, const VkImageSubresource * pSubresource, VkSubresourceLayout * pLayout); +typedef void (GLAD_API_PTR *PFN_vkGetImageSubresourceLayout2)(VkDevice device, VkImage image, const VkImageSubresource2 * pSubresource, VkSubresourceLayout2 * pLayout); +typedef void (GLAD_API_PTR *PFN_vkGetImageSubresourceLayout2EXT)(VkDevice device, VkImage image, const VkImageSubresource2 * pSubresource, VkSubresourceLayout2 * pLayout); +typedef void (GLAD_API_PTR *PFN_vkGetImageSubresourceLayout2KHR)(VkDevice device, VkImage image, const VkImageSubresource2 * pSubresource, VkSubresourceLayout2 * pLayout); typedef VkResult (GLAD_API_PTR *PFN_vkGetImageViewAddressNVX)(VkDevice device, VkImageView imageView, VkImageViewAddressPropertiesNVX * pProperties); +typedef uint64_t (GLAD_API_PTR *PFN_vkGetImageViewHandle64NVX)(VkDevice device, const VkImageViewHandleInfoNVX * pInfo); typedef uint32_t (GLAD_API_PTR *PFN_vkGetImageViewHandleNVX)(VkDevice device, const VkImageViewHandleInfoNVX * pInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkImageViewCaptureDescriptorDataInfoEXT * pInfo, void * pData); typedef PFN_vkVoidFunction (GLAD_API_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char * pName); +typedef void (GLAD_API_PTR *PFN_vkGetLatencyTimingsNV)(VkDevice device, VkSwapchainKHR swapchain, VkGetLatencyMarkerInfoNV * pLatencyMarkerInfo); #if defined(VK_USE_PLATFORM_ANDROID_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryAndroidHardwareBufferANDROID)(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID * pInfo, struct AHardwareBuffer ** pBuffer); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryFdKHR)(VkDevice device, const VkMemoryGetFdInfoKHR * pGetFdInfo, int * pFd); typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryFdPropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR * pMemoryFdProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryHostPointerPropertiesEXT)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void * pHostPointer, VkMemoryHostPointerPropertiesEXT * pMemoryHostPointerProperties); +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryMetalHandleEXT)(VkDevice device, const VkMemoryGetMetalHandleInfoEXT * pGetMetalHandleInfo, void ** pHandle); + +#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryMetalHandlePropertiesEXT)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void * pHandle, VkMemoryMetalHandlePropertiesEXT * pMemoryMetalHandleProperties); + +#endif +typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryRemoteAddressNV)(VkDevice device, const VkMemoryGetRemoteAddressInfoNV * pMemoryGetRemoteAddressInfo, VkRemoteAddressNV * pAddress); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryWin32HandleKHR)(VkDevice device, const VkMemoryGetWin32HandleInfoKHR * pGetWin32HandleInfo, HANDLE * pHandle); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryWin32HandleNV)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagsNV handleType, HANDLE * pHandle); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR * pMemoryWin32HandleProperties); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryZirconHandleFUCHSIA)(VkDevice device, const VkMemoryGetZirconHandleInfoFUCHSIA * pGetZirconHandleInfo, zx_handle_t * pZirconHandle); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, zx_handle_t zirconHandle, VkMemoryZirconHandlePropertiesFUCHSIA * pMemoryZirconHandleProperties); + #endif +typedef void (GLAD_API_PTR *PFN_vkGetMicromapBuildSizesEXT)(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkMicromapBuildInfoEXT * pBuildInfo, VkMicromapBuildSizesInfoEXT * pSizeInfo); +typedef void (GLAD_API_PTR *PFN_vkGetPartitionedAccelerationStructuresBuildSizesNV)(VkDevice device, const VkPartitionedAccelerationStructureInstancesInputNV * pInfo, VkAccelerationStructureBuildSizesInfoKHR * pSizeInfo); typedef VkResult (GLAD_API_PTR *PFN_vkGetPastPresentationTimingGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, uint32_t * pPresentationTimingCount, VkPastPresentationTimingGOOGLE * pPresentationTimings); typedef VkResult (GLAD_API_PTR *PFN_vkGetPerformanceParameterINTEL)(VkDevice device, VkPerformanceParameterTypeINTEL parameter, VkPerformanceValueINTEL * pValue); -typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t * pTimeDomainCount, VkTimeDomainEXT * pTimeDomains); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t * pTimeDomainCount, VkTimeDomainKHR * pTimeDomains); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR)(VkPhysicalDevice physicalDevice, uint32_t * pTimeDomainCount, VkTimeDomainKHR * pTimeDomains); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkCooperativeMatrixFlexibleDimensionsPropertiesNV * pProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkCooperativeMatrixPropertiesKHR * pProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkCooperativeMatrixPropertiesNV * pProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceCooperativeVectorPropertiesNV)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkCooperativeVectorPropertiesNV * pProperties); #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) typedef VkBool32 (GLAD_API_PTR *PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, IDirectFB * dfb); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkDisplayPlaneProperties2KHR * pProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)(VkPhysicalDevice physicalDevice, uint32_t * pPropertyCount, VkDisplayPlanePropertiesKHR * pProperties); @@ -9763,6 +17558,7 @@ typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevic typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties * pFormatProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 * pFormatProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 * pFormatProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR)(VkPhysicalDevice physicalDevice, uint32_t * pFragmentShadingRateCount, VkPhysicalDeviceFragmentShadingRateKHR * pFragmentShadingRates); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties * pImageFormatProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo, VkImageFormatProperties2 * pImageFormatProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo, VkImageFormatProperties2 * pImageFormatProperties); @@ -9770,6 +17566,7 @@ typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalD typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 * pMemoryProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 * pMemoryProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)(VkPhysicalDevice physicalDevice, VkSampleCountFlagBits samples, VkMultisamplePropertiesEXT * pMultisampleProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV)(VkPhysicalDevice physicalDevice, const VkOpticalFlowImageFormatInfoNV * pOpticalFlowImageFormatInfo, uint32_t * pFormatCount, VkOpticalFlowImageFormatPropertiesNV * pImageFormatProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t * pRectCount, VkRect2D * pRects); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties * pProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 * pProperties); @@ -9778,6 +17575,10 @@ typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPa typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice physicalDevice, uint32_t * pQueueFamilyPropertyCount, VkQueueFamilyProperties * pQueueFamilyProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice physicalDevice, uint32_t * pQueueFamilyPropertyCount, VkQueueFamilyProperties2 * pQueueFamilyProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t * pQueueFamilyPropertyCount, VkQueueFamilyProperties2 * pQueueFamilyProperties); +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef VkBool32 (GLAD_API_PTR *PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct _screen_window * window); + +#endif typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t * pPropertyCount, VkSparseImageFormatProperties * pProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 * pFormatInfo, uint32_t * pPropertyCount, VkSparseImageFormatProperties2 * pProperties); typedef void (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 * pFormatInfo, uint32_t * pPropertyCount, VkSparseImageFormatProperties2 * pProperties); @@ -9789,81 +17590,126 @@ typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhy typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t * pSurfaceFormatCount, VkSurfaceFormatKHR * pSurfaceFormats); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR * pSurfaceInfo, uint32_t * pPresentModeCount, VkPresentModeKHR * pPresentModes); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t * pPresentModeCount, VkPresentModeKHR * pPresentModes); typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32 * pSupported); -typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceToolPropertiesEXT)(VkPhysicalDevice physicalDevice, uint32_t * pToolCount, VkPhysicalDeviceToolPropertiesEXT * pToolProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceToolProperties)(VkPhysicalDevice physicalDevice, uint32_t * pToolCount, VkPhysicalDeviceToolProperties * pToolProperties); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPhysicalDeviceToolPropertiesEXT)(VkPhysicalDevice physicalDevice, uint32_t * pToolCount, VkPhysicalDeviceToolProperties * pToolProperties); #if defined(VK_USE_PLATFORM_WAYLAND_KHR) typedef VkBool32 (GLAD_API_PTR *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, struct wl_display * display); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkBool32 (GLAD_API_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex); + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) typedef VkBool32 (GLAD_API_PTR *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, xcb_connection_t * connection, xcb_visualid_t visual_id); + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) typedef VkBool32 (GLAD_API_PTR *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, Display * dpy, VisualID visualID); + #endif +typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineBinaryDataKHR)(VkDevice device, const VkPipelineBinaryDataInfoKHR * pInfo, VkPipelineBinaryKeyKHR * pPipelineBinaryKey, size_t * pPipelineBinaryDataSize, void * pPipelineBinaryData); typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, size_t * pDataSize, void * pData); typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineExecutableInternalRepresentationsKHR)(VkDevice device, const VkPipelineExecutableInfoKHR * pExecutableInfo, uint32_t * pInternalRepresentationCount, VkPipelineExecutableInternalRepresentationKHR * pInternalRepresentations); typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineExecutablePropertiesKHR)(VkDevice device, const VkPipelineInfoKHR * pPipelineInfo, uint32_t * pExecutableCount, VkPipelineExecutablePropertiesKHR * pProperties); typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineExecutableStatisticsKHR)(VkDevice device, const VkPipelineExecutableInfoKHR * pExecutableInfo, uint32_t * pStatisticCount, VkPipelineExecutableStatisticKHR * pStatistics); -typedef void (GLAD_API_PTR *PFN_vkGetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlotEXT privateDataSlot, uint64_t * pData); +typedef VkDeviceAddress (GLAD_API_PTR *PFN_vkGetPipelineIndirectDeviceAddressNV)(VkDevice device, const VkPipelineIndirectDeviceAddressInfoNV * pInfo); +typedef void (GLAD_API_PTR *PFN_vkGetPipelineIndirectMemoryRequirementsNV)(VkDevice device, const VkComputePipelineCreateInfo * pCreateInfo, VkMemoryRequirements2 * pMemoryRequirements); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelineKeyKHR)(VkDevice device, const VkPipelineCreateInfoKHR * pPipelineCreateInfo, VkPipelineBinaryKeyKHR * pPipelineKey); +typedef VkResult (GLAD_API_PTR *PFN_vkGetPipelinePropertiesEXT)(VkDevice device, const VkPipelineInfoEXT * pPipelineInfo, VkBaseOutStructure * pPipelineProperties); +typedef void (GLAD_API_PTR *PFN_vkGetPrivateData)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t * pData); +typedef void (GLAD_API_PTR *PFN_vkGetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t * pData); typedef VkResult (GLAD_API_PTR *PFN_vkGetQueryPoolResults)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void * pData, VkDeviceSize stride, VkQueryResultFlags flags); +typedef void (GLAD_API_PTR *PFN_vkGetQueueCheckpointData2NV)(VkQueue queue, uint32_t * pCheckpointDataCount, VkCheckpointData2NV * pCheckpointData); typedef void (GLAD_API_PTR *PFN_vkGetQueueCheckpointDataNV)(VkQueue queue, uint32_t * pCheckpointDataCount, VkCheckpointDataNV * pCheckpointData); #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) typedef VkResult (GLAD_API_PTR *PFN_vkGetRandROutputDisplayEXT)(VkPhysicalDevice physicalDevice, Display * dpy, RROutput rrOutput, VkDisplayKHR * pDisplay); + #endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef VkResult (GLAD_API_PTR *PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void * pData); -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef VkResult (GLAD_API_PTR *PFN_vkGetRayTracingShaderGroupHandlesKHR)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void * pData); -#endif typedef VkResult (GLAD_API_PTR *PFN_vkGetRayTracingShaderGroupHandlesNV)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void * pData); +typedef VkDeviceSize (GLAD_API_PTR *PFN_vkGetRayTracingShaderGroupStackSizeKHR)(VkDevice device, VkPipeline pipeline, uint32_t group, VkShaderGroupShaderKHR groupShader); typedef VkResult (GLAD_API_PTR *PFN_vkGetRefreshCycleDurationGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE * pDisplayTimingProperties); typedef void (GLAD_API_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice device, VkRenderPass renderPass, VkExtent2D * pGranularity); +typedef void (GLAD_API_PTR *PFN_vkGetRenderingAreaGranularity)(VkDevice device, const VkRenderingAreaInfo * pRenderingAreaInfo, VkExtent2D * pGranularity); +typedef void (GLAD_API_PTR *PFN_vkGetRenderingAreaGranularityKHR)(VkDevice device, const VkRenderingAreaInfo * pRenderingAreaInfo, VkExtent2D * pGranularity); +typedef VkResult (GLAD_API_PTR *PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkSamplerCaptureDescriptorDataInfoEXT * pInfo, void * pData); +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +typedef VkResult (GLAD_API_PTR *PFN_vkGetScreenBufferPropertiesQNX)(VkDevice device, const struct _screen_buffer * buffer, VkScreenBufferPropertiesQNX * pProperties); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkGetSemaphoreCounterValue)(VkDevice device, VkSemaphore semaphore, uint64_t * pValue); typedef VkResult (GLAD_API_PTR *PFN_vkGetSemaphoreCounterValueKHR)(VkDevice device, VkSemaphore semaphore, uint64_t * pValue); typedef VkResult (GLAD_API_PTR *PFN_vkGetSemaphoreFdKHR)(VkDevice device, const VkSemaphoreGetFdInfoKHR * pGetFdInfo, int * pFd); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkGetSemaphoreWin32HandleKHR)(VkDevice device, const VkSemaphoreGetWin32HandleInfoKHR * pGetWin32HandleInfo, HANDLE * pHandle); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkGetSemaphoreZirconHandleFUCHSIA)(VkDevice device, const VkSemaphoreGetZirconHandleInfoFUCHSIA * pGetZirconHandleInfo, zx_handle_t * pZirconHandle); + #endif +typedef VkResult (GLAD_API_PTR *PFN_vkGetShaderBinaryDataEXT)(VkDevice device, VkShaderEXT shader, size_t * pDataSize, void * pData); typedef VkResult (GLAD_API_PTR *PFN_vkGetShaderInfoAMD)(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits shaderStage, VkShaderInfoTypeAMD infoType, size_t * pInfoSize, void * pInfo); +typedef void (GLAD_API_PTR *PFN_vkGetShaderModuleCreateInfoIdentifierEXT)(VkDevice device, const VkShaderModuleCreateInfo * pCreateInfo, VkShaderModuleIdentifierEXT * pIdentifier); +typedef void (GLAD_API_PTR *PFN_vkGetShaderModuleIdentifierEXT)(VkDevice device, VkShaderModule shaderModule, VkShaderModuleIdentifierEXT * pIdentifier); typedef VkResult (GLAD_API_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t * pCounterValue); typedef VkResult (GLAD_API_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t * pSwapchainImageCount, VkImage * pSwapchainImages); typedef VkResult (GLAD_API_PTR *PFN_vkGetSwapchainStatusKHR)(VkDevice device, VkSwapchainKHR swapchain); typedef VkResult (GLAD_API_PTR *PFN_vkGetValidationCacheDataEXT)(VkDevice device, VkValidationCacheEXT validationCache, size_t * pDataSize, void * pData); +#if defined(VK_USE_PLATFORM_WIN32_KHR) +typedef VkResult (GLAD_API_PTR *PFN_vkGetWinrtDisplayNV)(VkPhysicalDevice physicalDevice, uint32_t deviceRelativeId, VkDisplayKHR * pDisplay); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkImportFenceFdKHR)(VkDevice device, const VkImportFenceFdInfoKHR * pImportFenceFdInfo); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkImportFenceWin32HandleKHR)(VkDevice device, const VkImportFenceWin32HandleInfoKHR * pImportFenceWin32HandleInfo); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkImportSemaphoreFdKHR)(VkDevice device, const VkImportSemaphoreFdInfoKHR * pImportSemaphoreFdInfo); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkImportSemaphoreWin32HandleKHR)(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR * pImportSemaphoreWin32HandleInfo); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkImportSemaphoreZirconHandleFUCHSIA)(VkDevice device, const VkImportSemaphoreZirconHandleInfoFUCHSIA * pImportSemaphoreZirconHandleInfo); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkInitializePerformanceApiINTEL)(VkDevice device, const VkInitializePerformanceApiInfoINTEL * pInitializeInfo); typedef VkResult (GLAD_API_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange * pMemoryRanges); +typedef VkResult (GLAD_API_PTR *PFN_vkLatencySleepNV)(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepInfoNV * pSleepInfo); typedef VkResult (GLAD_API_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void ** ppData); +typedef VkResult (GLAD_API_PTR *PFN_vkMapMemory2)(VkDevice device, const VkMemoryMapInfo * pMemoryMapInfo, void ** ppData); +typedef VkResult (GLAD_API_PTR *PFN_vkMapMemory2KHR)(VkDevice device, const VkMemoryMapInfo * pMemoryMapInfo, void ** ppData); typedef VkResult (GLAD_API_PTR *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache * pSrcCaches); typedef VkResult (GLAD_API_PTR *PFN_vkMergeValidationCachesEXT)(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount, const VkValidationCacheEXT * pSrcCaches); typedef void (GLAD_API_PTR *PFN_vkQueueBeginDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT * pLabelInfo); typedef VkResult (GLAD_API_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo * pBindInfo, VkFence fence); typedef void (GLAD_API_PTR *PFN_vkQueueEndDebugUtilsLabelEXT)(VkQueue queue); typedef void (GLAD_API_PTR *PFN_vkQueueInsertDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT * pLabelInfo); +typedef void (GLAD_API_PTR *PFN_vkQueueNotifyOutOfBandNV)(VkQueue queue, const VkOutOfBandQueueTypeInfoNV * pQueueTypeInfo); typedef VkResult (GLAD_API_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR * pPresentInfo); typedef VkResult (GLAD_API_PTR *PFN_vkQueueSetPerformanceConfigurationINTEL)(VkQueue queue, VkPerformanceConfigurationINTEL configuration); typedef VkResult (GLAD_API_PTR *PFN_vkQueueSubmit)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo * pSubmits, VkFence fence); +typedef VkResult (GLAD_API_PTR *PFN_vkQueueSubmit2)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 * pSubmits, VkFence fence); +typedef VkResult (GLAD_API_PTR *PFN_vkQueueSubmit2KHR)(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 * pSubmits, VkFence fence); typedef VkResult (GLAD_API_PTR *PFN_vkQueueWaitIdle)(VkQueue queue); typedef VkResult (GLAD_API_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT * pDeviceEventInfo, const VkAllocationCallbacks * pAllocator, VkFence * pFence); typedef VkResult (GLAD_API_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT * pDisplayEventInfo, const VkAllocationCallbacks * pAllocator, VkFence * pFence); +typedef VkResult (GLAD_API_PTR *PFN_vkReleaseCapturedPipelineDataKHR)(VkDevice device, const VkReleaseCapturedPipelineDataInfoKHR * pInfo, const VkAllocationCallbacks * pAllocator); typedef VkResult (GLAD_API_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display); #if defined(VK_USE_PLATFORM_WIN32_KHR) typedef VkResult (GLAD_API_PTR *PFN_vkReleaseFullScreenExclusiveModeEXT)(VkDevice device, VkSwapchainKHR swapchain); + #endif typedef VkResult (GLAD_API_PTR *PFN_vkReleasePerformanceConfigurationINTEL)(VkDevice device, VkPerformanceConfigurationINTEL configuration); typedef void (GLAD_API_PTR *PFN_vkReleaseProfilingLockKHR)(VkDevice device); +typedef VkResult (GLAD_API_PTR *PFN_vkReleaseSwapchainImagesEXT)(VkDevice device, const VkReleaseSwapchainImagesInfoEXT * pReleaseInfo); typedef VkResult (GLAD_API_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); typedef VkResult (GLAD_API_PTR *PFN_vkResetCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); typedef VkResult (GLAD_API_PTR *PFN_vkResetDescriptorPool)(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); @@ -9871,32 +17717,53 @@ typedef VkResult (GLAD_API_PTR *PFN_vkResetEvent)(VkDevice device, VkEvent event typedef VkResult (GLAD_API_PTR *PFN_vkResetFences)(VkDevice device, uint32_t fenceCount, const VkFence * pFences); typedef void (GLAD_API_PTR *PFN_vkResetQueryPool)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); typedef void (GLAD_API_PTR *PFN_vkResetQueryPoolEXT)(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkBufferConstraintsInfoFUCHSIA * pBufferConstraintsInfo); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +typedef VkResult (GLAD_API_PTR *PFN_vkSetBufferCollectionImageConstraintsFUCHSIA)(VkDevice device, VkBufferCollectionFUCHSIA collection, const VkImageConstraintsInfoFUCHSIA * pImageConstraintsInfo); + +#endif typedef VkResult (GLAD_API_PTR *PFN_vkSetDebugUtilsObjectNameEXT)(VkDevice device, const VkDebugUtilsObjectNameInfoEXT * pNameInfo); typedef VkResult (GLAD_API_PTR *PFN_vkSetDebugUtilsObjectTagEXT)(VkDevice device, const VkDebugUtilsObjectTagInfoEXT * pTagInfo); +typedef void (GLAD_API_PTR *PFN_vkSetDeviceMemoryPriorityEXT)(VkDevice device, VkDeviceMemory memory, float priority); typedef VkResult (GLAD_API_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event); typedef void (GLAD_API_PTR *PFN_vkSetHdrMetadataEXT)(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR * pSwapchains, const VkHdrMetadataEXT * pMetadata); +typedef void (GLAD_API_PTR *PFN_vkSetLatencyMarkerNV)(VkDevice device, VkSwapchainKHR swapchain, const VkSetLatencyMarkerInfoNV * pLatencyMarkerInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkSetLatencySleepModeNV)(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepModeInfoNV * pSleepModeInfo); typedef void (GLAD_API_PTR *PFN_vkSetLocalDimmingAMD)(VkDevice device, VkSwapchainKHR swapChain, VkBool32 localDimmingEnable); -typedef VkResult (GLAD_API_PTR *PFN_vkSetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlotEXT privateDataSlot, uint64_t data); +typedef VkResult (GLAD_API_PTR *PFN_vkSetPrivateData)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data); +typedef VkResult (GLAD_API_PTR *PFN_vkSetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data); typedef VkResult (GLAD_API_PTR *PFN_vkSignalSemaphore)(VkDevice device, const VkSemaphoreSignalInfo * pSignalInfo); typedef VkResult (GLAD_API_PTR *PFN_vkSignalSemaphoreKHR)(VkDevice device, const VkSemaphoreSignalInfo * pSignalInfo); typedef void (GLAD_API_PTR *PFN_vkSubmitDebugUtilsMessageEXT)(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT * pCallbackData); +typedef VkResult (GLAD_API_PTR *PFN_vkTransitionImageLayout)(VkDevice device, uint32_t transitionCount, const VkHostImageLayoutTransitionInfo * pTransitions); +typedef VkResult (GLAD_API_PTR *PFN_vkTransitionImageLayoutEXT)(VkDevice device, uint32_t transitionCount, const VkHostImageLayoutTransitionInfo * pTransitions); typedef void (GLAD_API_PTR *PFN_vkTrimCommandPool)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); typedef void (GLAD_API_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); typedef void (GLAD_API_PTR *PFN_vkUninitializePerformanceApiINTEL)(VkDevice device); typedef void (GLAD_API_PTR *PFN_vkUnmapMemory)(VkDevice device, VkDeviceMemory memory); +typedef VkResult (GLAD_API_PTR *PFN_vkUnmapMemory2)(VkDevice device, const VkMemoryUnmapInfo * pMemoryUnmapInfo); +typedef VkResult (GLAD_API_PTR *PFN_vkUnmapMemory2KHR)(VkDevice device, const VkMemoryUnmapInfo * pMemoryUnmapInfo); typedef void (GLAD_API_PTR *PFN_vkUpdateDescriptorSetWithTemplate)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void * pData); typedef void (GLAD_API_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void * pData); typedef void (GLAD_API_PTR *PFN_vkUpdateDescriptorSets)(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet * pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet * pDescriptorCopies); +typedef void (GLAD_API_PTR *PFN_vkUpdateIndirectExecutionSetPipelineEXT)(VkDevice device, VkIndirectExecutionSetEXT indirectExecutionSet, uint32_t executionSetWriteCount, const VkWriteIndirectExecutionSetPipelineEXT * pExecutionSetWrites); +typedef void (GLAD_API_PTR *PFN_vkUpdateIndirectExecutionSetShaderEXT)(VkDevice device, VkIndirectExecutionSetEXT indirectExecutionSet, uint32_t executionSetWriteCount, const VkWriteIndirectExecutionSetShaderEXT * pExecutionSetWrites); typedef VkResult (GLAD_API_PTR *PFN_vkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence * pFences, VkBool32 waitAll, uint64_t timeout); +typedef VkResult (GLAD_API_PTR *PFN_vkWaitForPresentKHR)(VkDevice device, VkSwapchainKHR swapchain, uint64_t presentId, uint64_t timeout); typedef VkResult (GLAD_API_PTR *PFN_vkWaitSemaphores)(VkDevice device, const VkSemaphoreWaitInfo * pWaitInfo, uint64_t timeout); typedef VkResult (GLAD_API_PTR *PFN_vkWaitSemaphoresKHR)(VkDevice device, const VkSemaphoreWaitInfo * pWaitInfo, uint64_t timeout); -#if defined(VK_ENABLE_BETA_EXTENSIONS) typedef VkResult (GLAD_API_PTR *PFN_vkWriteAccelerationStructuresPropertiesKHR)(VkDevice device, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR * pAccelerationStructures, VkQueryType queryType, size_t dataSize, void * pData, size_t stride); -#endif +typedef VkResult (GLAD_API_PTR *PFN_vkWriteMicromapsPropertiesEXT)(VkDevice device, uint32_t micromapCount, const VkMicromapEXT * pMicromaps, VkQueryType queryType, size_t dataSize, void * pData, size_t stride); +GLAD_API_CALL PFN_vkAcquireDrmDisplayEXT glad_vkAcquireDrmDisplayEXT; +#define vkAcquireDrmDisplayEXT glad_vkAcquireDrmDisplayEXT #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkAcquireFullScreenExclusiveModeEXT glad_vkAcquireFullScreenExclusiveModeEXT; #define vkAcquireFullScreenExclusiveModeEXT glad_vkAcquireFullScreenExclusiveModeEXT + #endif GLAD_API_CALL PFN_vkAcquireNextImage2KHR glad_vkAcquireNextImage2KHR; #define vkAcquireNextImage2KHR glad_vkAcquireNextImage2KHR @@ -9906,9 +17773,15 @@ GLAD_API_CALL PFN_vkAcquirePerformanceConfigurationINTEL glad_vkAcquirePerforman #define vkAcquirePerformanceConfigurationINTEL glad_vkAcquirePerformanceConfigurationINTEL GLAD_API_CALL PFN_vkAcquireProfilingLockKHR glad_vkAcquireProfilingLockKHR; #define vkAcquireProfilingLockKHR glad_vkAcquireProfilingLockKHR +#if defined(VK_USE_PLATFORM_WIN32_KHR) +GLAD_API_CALL PFN_vkAcquireWinrtDisplayNV glad_vkAcquireWinrtDisplayNV; +#define vkAcquireWinrtDisplayNV glad_vkAcquireWinrtDisplayNV + +#endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) GLAD_API_CALL PFN_vkAcquireXlibDisplayEXT glad_vkAcquireXlibDisplayEXT; #define vkAcquireXlibDisplayEXT glad_vkAcquireXlibDisplayEXT + #endif GLAD_API_CALL PFN_vkAllocateCommandBuffers glad_vkAllocateCommandBuffers; #define vkAllocateCommandBuffers glad_vkAllocateCommandBuffers @@ -9916,12 +17789,10 @@ GLAD_API_CALL PFN_vkAllocateDescriptorSets glad_vkAllocateDescriptorSets; #define vkAllocateDescriptorSets glad_vkAllocateDescriptorSets GLAD_API_CALL PFN_vkAllocateMemory glad_vkAllocateMemory; #define vkAllocateMemory glad_vkAllocateMemory +GLAD_API_CALL PFN_vkAntiLagUpdateAMD glad_vkAntiLagUpdateAMD; +#define vkAntiLagUpdateAMD glad_vkAntiLagUpdateAMD GLAD_API_CALL PFN_vkBeginCommandBuffer glad_vkBeginCommandBuffer; #define vkBeginCommandBuffer glad_vkBeginCommandBuffer -#if defined(VK_ENABLE_BETA_EXTENSIONS) -GLAD_API_CALL PFN_vkBindAccelerationStructureMemoryKHR glad_vkBindAccelerationStructureMemoryKHR; -#define vkBindAccelerationStructureMemoryKHR glad_vkBindAccelerationStructureMemoryKHR -#endif GLAD_API_CALL PFN_vkBindAccelerationStructureMemoryNV glad_vkBindAccelerationStructureMemoryNV; #define vkBindAccelerationStructureMemoryNV glad_vkBindAccelerationStructureMemoryNV GLAD_API_CALL PFN_vkBindBufferMemory glad_vkBindBufferMemory; @@ -9936,14 +17807,18 @@ GLAD_API_CALL PFN_vkBindImageMemory2 glad_vkBindImageMemory2; #define vkBindImageMemory2 glad_vkBindImageMemory2 GLAD_API_CALL PFN_vkBindImageMemory2KHR glad_vkBindImageMemory2KHR; #define vkBindImageMemory2KHR glad_vkBindImageMemory2KHR -#if defined(VK_ENABLE_BETA_EXTENSIONS) -GLAD_API_CALL PFN_vkBuildAccelerationStructureKHR glad_vkBuildAccelerationStructureKHR; -#define vkBuildAccelerationStructureKHR glad_vkBuildAccelerationStructureKHR -#endif +GLAD_API_CALL PFN_vkBindOpticalFlowSessionImageNV glad_vkBindOpticalFlowSessionImageNV; +#define vkBindOpticalFlowSessionImageNV glad_vkBindOpticalFlowSessionImageNV +GLAD_API_CALL PFN_vkBuildAccelerationStructuresKHR glad_vkBuildAccelerationStructuresKHR; +#define vkBuildAccelerationStructuresKHR glad_vkBuildAccelerationStructuresKHR +GLAD_API_CALL PFN_vkBuildMicromapsEXT glad_vkBuildMicromapsEXT; +#define vkBuildMicromapsEXT glad_vkBuildMicromapsEXT GLAD_API_CALL PFN_vkCmdBeginConditionalRenderingEXT glad_vkCmdBeginConditionalRenderingEXT; #define vkCmdBeginConditionalRenderingEXT glad_vkCmdBeginConditionalRenderingEXT GLAD_API_CALL PFN_vkCmdBeginDebugUtilsLabelEXT glad_vkCmdBeginDebugUtilsLabelEXT; #define vkCmdBeginDebugUtilsLabelEXT glad_vkCmdBeginDebugUtilsLabelEXT +GLAD_API_CALL PFN_vkCmdBeginPerTileExecutionQCOM glad_vkCmdBeginPerTileExecutionQCOM; +#define vkCmdBeginPerTileExecutionQCOM glad_vkCmdBeginPerTileExecutionQCOM GLAD_API_CALL PFN_vkCmdBeginQuery glad_vkCmdBeginQuery; #define vkCmdBeginQuery glad_vkCmdBeginQuery GLAD_API_CALL PFN_vkCmdBeginQueryIndexedEXT glad_vkCmdBeginQueryIndexedEXT; @@ -9954,82 +17829,168 @@ GLAD_API_CALL PFN_vkCmdBeginRenderPass2 glad_vkCmdBeginRenderPass2; #define vkCmdBeginRenderPass2 glad_vkCmdBeginRenderPass2 GLAD_API_CALL PFN_vkCmdBeginRenderPass2KHR glad_vkCmdBeginRenderPass2KHR; #define vkCmdBeginRenderPass2KHR glad_vkCmdBeginRenderPass2KHR +GLAD_API_CALL PFN_vkCmdBeginRendering glad_vkCmdBeginRendering; +#define vkCmdBeginRendering glad_vkCmdBeginRendering +GLAD_API_CALL PFN_vkCmdBeginRenderingKHR glad_vkCmdBeginRenderingKHR; +#define vkCmdBeginRenderingKHR glad_vkCmdBeginRenderingKHR GLAD_API_CALL PFN_vkCmdBeginTransformFeedbackEXT glad_vkCmdBeginTransformFeedbackEXT; #define vkCmdBeginTransformFeedbackEXT glad_vkCmdBeginTransformFeedbackEXT +GLAD_API_CALL PFN_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT glad_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT; +#define vkCmdBindDescriptorBufferEmbeddedSamplers2EXT glad_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT +GLAD_API_CALL PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT glad_vkCmdBindDescriptorBufferEmbeddedSamplersEXT; +#define vkCmdBindDescriptorBufferEmbeddedSamplersEXT glad_vkCmdBindDescriptorBufferEmbeddedSamplersEXT +GLAD_API_CALL PFN_vkCmdBindDescriptorBuffersEXT glad_vkCmdBindDescriptorBuffersEXT; +#define vkCmdBindDescriptorBuffersEXT glad_vkCmdBindDescriptorBuffersEXT GLAD_API_CALL PFN_vkCmdBindDescriptorSets glad_vkCmdBindDescriptorSets; #define vkCmdBindDescriptorSets glad_vkCmdBindDescriptorSets +GLAD_API_CALL PFN_vkCmdBindDescriptorSets2 glad_vkCmdBindDescriptorSets2; +#define vkCmdBindDescriptorSets2 glad_vkCmdBindDescriptorSets2 +GLAD_API_CALL PFN_vkCmdBindDescriptorSets2KHR glad_vkCmdBindDescriptorSets2KHR; +#define vkCmdBindDescriptorSets2KHR glad_vkCmdBindDescriptorSets2KHR GLAD_API_CALL PFN_vkCmdBindIndexBuffer glad_vkCmdBindIndexBuffer; #define vkCmdBindIndexBuffer glad_vkCmdBindIndexBuffer +GLAD_API_CALL PFN_vkCmdBindIndexBuffer2 glad_vkCmdBindIndexBuffer2; +#define vkCmdBindIndexBuffer2 glad_vkCmdBindIndexBuffer2 +GLAD_API_CALL PFN_vkCmdBindIndexBuffer2KHR glad_vkCmdBindIndexBuffer2KHR; +#define vkCmdBindIndexBuffer2KHR glad_vkCmdBindIndexBuffer2KHR +GLAD_API_CALL PFN_vkCmdBindInvocationMaskHUAWEI glad_vkCmdBindInvocationMaskHUAWEI; +#define vkCmdBindInvocationMaskHUAWEI glad_vkCmdBindInvocationMaskHUAWEI GLAD_API_CALL PFN_vkCmdBindPipeline glad_vkCmdBindPipeline; #define vkCmdBindPipeline glad_vkCmdBindPipeline GLAD_API_CALL PFN_vkCmdBindPipelineShaderGroupNV glad_vkCmdBindPipelineShaderGroupNV; #define vkCmdBindPipelineShaderGroupNV glad_vkCmdBindPipelineShaderGroupNV +GLAD_API_CALL PFN_vkCmdBindShadersEXT glad_vkCmdBindShadersEXT; +#define vkCmdBindShadersEXT glad_vkCmdBindShadersEXT GLAD_API_CALL PFN_vkCmdBindShadingRateImageNV glad_vkCmdBindShadingRateImageNV; #define vkCmdBindShadingRateImageNV glad_vkCmdBindShadingRateImageNV +GLAD_API_CALL PFN_vkCmdBindTileMemoryQCOM glad_vkCmdBindTileMemoryQCOM; +#define vkCmdBindTileMemoryQCOM glad_vkCmdBindTileMemoryQCOM GLAD_API_CALL PFN_vkCmdBindTransformFeedbackBuffersEXT glad_vkCmdBindTransformFeedbackBuffersEXT; #define vkCmdBindTransformFeedbackBuffersEXT glad_vkCmdBindTransformFeedbackBuffersEXT GLAD_API_CALL PFN_vkCmdBindVertexBuffers glad_vkCmdBindVertexBuffers; #define vkCmdBindVertexBuffers glad_vkCmdBindVertexBuffers +GLAD_API_CALL PFN_vkCmdBindVertexBuffers2 glad_vkCmdBindVertexBuffers2; +#define vkCmdBindVertexBuffers2 glad_vkCmdBindVertexBuffers2 GLAD_API_CALL PFN_vkCmdBindVertexBuffers2EXT glad_vkCmdBindVertexBuffers2EXT; #define vkCmdBindVertexBuffers2EXT glad_vkCmdBindVertexBuffers2EXT GLAD_API_CALL PFN_vkCmdBlitImage glad_vkCmdBlitImage; #define vkCmdBlitImage glad_vkCmdBlitImage -#if defined(VK_ENABLE_BETA_EXTENSIONS) -GLAD_API_CALL PFN_vkCmdBuildAccelerationStructureIndirectKHR glad_vkCmdBuildAccelerationStructureIndirectKHR; -#define vkCmdBuildAccelerationStructureIndirectKHR glad_vkCmdBuildAccelerationStructureIndirectKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -GLAD_API_CALL PFN_vkCmdBuildAccelerationStructureKHR glad_vkCmdBuildAccelerationStructureKHR; -#define vkCmdBuildAccelerationStructureKHR glad_vkCmdBuildAccelerationStructureKHR -#endif +GLAD_API_CALL PFN_vkCmdBlitImage2 glad_vkCmdBlitImage2; +#define vkCmdBlitImage2 glad_vkCmdBlitImage2 +GLAD_API_CALL PFN_vkCmdBlitImage2KHR glad_vkCmdBlitImage2KHR; +#define vkCmdBlitImage2KHR glad_vkCmdBlitImage2KHR GLAD_API_CALL PFN_vkCmdBuildAccelerationStructureNV glad_vkCmdBuildAccelerationStructureNV; #define vkCmdBuildAccelerationStructureNV glad_vkCmdBuildAccelerationStructureNV +GLAD_API_CALL PFN_vkCmdBuildAccelerationStructuresIndirectKHR glad_vkCmdBuildAccelerationStructuresIndirectKHR; +#define vkCmdBuildAccelerationStructuresIndirectKHR glad_vkCmdBuildAccelerationStructuresIndirectKHR +GLAD_API_CALL PFN_vkCmdBuildAccelerationStructuresKHR glad_vkCmdBuildAccelerationStructuresKHR; +#define vkCmdBuildAccelerationStructuresKHR glad_vkCmdBuildAccelerationStructuresKHR +GLAD_API_CALL PFN_vkCmdBuildClusterAccelerationStructureIndirectNV glad_vkCmdBuildClusterAccelerationStructureIndirectNV; +#define vkCmdBuildClusterAccelerationStructureIndirectNV glad_vkCmdBuildClusterAccelerationStructureIndirectNV +GLAD_API_CALL PFN_vkCmdBuildMicromapsEXT glad_vkCmdBuildMicromapsEXT; +#define vkCmdBuildMicromapsEXT glad_vkCmdBuildMicromapsEXT +GLAD_API_CALL PFN_vkCmdBuildPartitionedAccelerationStructuresNV glad_vkCmdBuildPartitionedAccelerationStructuresNV; +#define vkCmdBuildPartitionedAccelerationStructuresNV glad_vkCmdBuildPartitionedAccelerationStructuresNV GLAD_API_CALL PFN_vkCmdClearAttachments glad_vkCmdClearAttachments; #define vkCmdClearAttachments glad_vkCmdClearAttachments GLAD_API_CALL PFN_vkCmdClearColorImage glad_vkCmdClearColorImage; #define vkCmdClearColorImage glad_vkCmdClearColorImage GLAD_API_CALL PFN_vkCmdClearDepthStencilImage glad_vkCmdClearDepthStencilImage; #define vkCmdClearDepthStencilImage glad_vkCmdClearDepthStencilImage -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdConvertCooperativeVectorMatrixNV glad_vkCmdConvertCooperativeVectorMatrixNV; +#define vkCmdConvertCooperativeVectorMatrixNV glad_vkCmdConvertCooperativeVectorMatrixNV GLAD_API_CALL PFN_vkCmdCopyAccelerationStructureKHR glad_vkCmdCopyAccelerationStructureKHR; #define vkCmdCopyAccelerationStructureKHR glad_vkCmdCopyAccelerationStructureKHR -#endif GLAD_API_CALL PFN_vkCmdCopyAccelerationStructureNV glad_vkCmdCopyAccelerationStructureNV; #define vkCmdCopyAccelerationStructureNV glad_vkCmdCopyAccelerationStructureNV -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkCmdCopyAccelerationStructureToMemoryKHR glad_vkCmdCopyAccelerationStructureToMemoryKHR; #define vkCmdCopyAccelerationStructureToMemoryKHR glad_vkCmdCopyAccelerationStructureToMemoryKHR -#endif GLAD_API_CALL PFN_vkCmdCopyBuffer glad_vkCmdCopyBuffer; #define vkCmdCopyBuffer glad_vkCmdCopyBuffer +GLAD_API_CALL PFN_vkCmdCopyBuffer2 glad_vkCmdCopyBuffer2; +#define vkCmdCopyBuffer2 glad_vkCmdCopyBuffer2 +GLAD_API_CALL PFN_vkCmdCopyBuffer2KHR glad_vkCmdCopyBuffer2KHR; +#define vkCmdCopyBuffer2KHR glad_vkCmdCopyBuffer2KHR GLAD_API_CALL PFN_vkCmdCopyBufferToImage glad_vkCmdCopyBufferToImage; #define vkCmdCopyBufferToImage glad_vkCmdCopyBufferToImage +GLAD_API_CALL PFN_vkCmdCopyBufferToImage2 glad_vkCmdCopyBufferToImage2; +#define vkCmdCopyBufferToImage2 glad_vkCmdCopyBufferToImage2 +GLAD_API_CALL PFN_vkCmdCopyBufferToImage2KHR glad_vkCmdCopyBufferToImage2KHR; +#define vkCmdCopyBufferToImage2KHR glad_vkCmdCopyBufferToImage2KHR GLAD_API_CALL PFN_vkCmdCopyImage glad_vkCmdCopyImage; #define vkCmdCopyImage glad_vkCmdCopyImage +GLAD_API_CALL PFN_vkCmdCopyImage2 glad_vkCmdCopyImage2; +#define vkCmdCopyImage2 glad_vkCmdCopyImage2 +GLAD_API_CALL PFN_vkCmdCopyImage2KHR glad_vkCmdCopyImage2KHR; +#define vkCmdCopyImage2KHR glad_vkCmdCopyImage2KHR GLAD_API_CALL PFN_vkCmdCopyImageToBuffer glad_vkCmdCopyImageToBuffer; #define vkCmdCopyImageToBuffer glad_vkCmdCopyImageToBuffer -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdCopyImageToBuffer2 glad_vkCmdCopyImageToBuffer2; +#define vkCmdCopyImageToBuffer2 glad_vkCmdCopyImageToBuffer2 +GLAD_API_CALL PFN_vkCmdCopyImageToBuffer2KHR glad_vkCmdCopyImageToBuffer2KHR; +#define vkCmdCopyImageToBuffer2KHR glad_vkCmdCopyImageToBuffer2KHR +GLAD_API_CALL PFN_vkCmdCopyMemoryIndirectNV glad_vkCmdCopyMemoryIndirectNV; +#define vkCmdCopyMemoryIndirectNV glad_vkCmdCopyMemoryIndirectNV GLAD_API_CALL PFN_vkCmdCopyMemoryToAccelerationStructureKHR glad_vkCmdCopyMemoryToAccelerationStructureKHR; #define vkCmdCopyMemoryToAccelerationStructureKHR glad_vkCmdCopyMemoryToAccelerationStructureKHR -#endif +GLAD_API_CALL PFN_vkCmdCopyMemoryToImageIndirectNV glad_vkCmdCopyMemoryToImageIndirectNV; +#define vkCmdCopyMemoryToImageIndirectNV glad_vkCmdCopyMemoryToImageIndirectNV +GLAD_API_CALL PFN_vkCmdCopyMemoryToMicromapEXT glad_vkCmdCopyMemoryToMicromapEXT; +#define vkCmdCopyMemoryToMicromapEXT glad_vkCmdCopyMemoryToMicromapEXT +GLAD_API_CALL PFN_vkCmdCopyMicromapEXT glad_vkCmdCopyMicromapEXT; +#define vkCmdCopyMicromapEXT glad_vkCmdCopyMicromapEXT +GLAD_API_CALL PFN_vkCmdCopyMicromapToMemoryEXT glad_vkCmdCopyMicromapToMemoryEXT; +#define vkCmdCopyMicromapToMemoryEXT glad_vkCmdCopyMicromapToMemoryEXT GLAD_API_CALL PFN_vkCmdCopyQueryPoolResults glad_vkCmdCopyQueryPoolResults; #define vkCmdCopyQueryPoolResults glad_vkCmdCopyQueryPoolResults +GLAD_API_CALL PFN_vkCmdCuLaunchKernelNVX glad_vkCmdCuLaunchKernelNVX; +#define vkCmdCuLaunchKernelNVX glad_vkCmdCuLaunchKernelNVX +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdCudaLaunchKernelNV glad_vkCmdCudaLaunchKernelNV; +#define vkCmdCudaLaunchKernelNV glad_vkCmdCudaLaunchKernelNV + +#endif GLAD_API_CALL PFN_vkCmdDebugMarkerBeginEXT glad_vkCmdDebugMarkerBeginEXT; #define vkCmdDebugMarkerBeginEXT glad_vkCmdDebugMarkerBeginEXT GLAD_API_CALL PFN_vkCmdDebugMarkerEndEXT glad_vkCmdDebugMarkerEndEXT; #define vkCmdDebugMarkerEndEXT glad_vkCmdDebugMarkerEndEXT GLAD_API_CALL PFN_vkCmdDebugMarkerInsertEXT glad_vkCmdDebugMarkerInsertEXT; #define vkCmdDebugMarkerInsertEXT glad_vkCmdDebugMarkerInsertEXT +GLAD_API_CALL PFN_vkCmdDecompressMemoryIndirectCountNV glad_vkCmdDecompressMemoryIndirectCountNV; +#define vkCmdDecompressMemoryIndirectCountNV glad_vkCmdDecompressMemoryIndirectCountNV +GLAD_API_CALL PFN_vkCmdDecompressMemoryNV glad_vkCmdDecompressMemoryNV; +#define vkCmdDecompressMemoryNV glad_vkCmdDecompressMemoryNV GLAD_API_CALL PFN_vkCmdDispatch glad_vkCmdDispatch; #define vkCmdDispatch glad_vkCmdDispatch GLAD_API_CALL PFN_vkCmdDispatchBase glad_vkCmdDispatchBase; #define vkCmdDispatchBase glad_vkCmdDispatchBase GLAD_API_CALL PFN_vkCmdDispatchBaseKHR glad_vkCmdDispatchBaseKHR; #define vkCmdDispatchBaseKHR glad_vkCmdDispatchBaseKHR +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdDispatchGraphAMDX glad_vkCmdDispatchGraphAMDX; +#define vkCmdDispatchGraphAMDX glad_vkCmdDispatchGraphAMDX + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdDispatchGraphIndirectAMDX glad_vkCmdDispatchGraphIndirectAMDX; +#define vkCmdDispatchGraphIndirectAMDX glad_vkCmdDispatchGraphIndirectAMDX + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdDispatchGraphIndirectCountAMDX glad_vkCmdDispatchGraphIndirectCountAMDX; +#define vkCmdDispatchGraphIndirectCountAMDX glad_vkCmdDispatchGraphIndirectCountAMDX + +#endif GLAD_API_CALL PFN_vkCmdDispatchIndirect glad_vkCmdDispatchIndirect; #define vkCmdDispatchIndirect glad_vkCmdDispatchIndirect +GLAD_API_CALL PFN_vkCmdDispatchTileQCOM glad_vkCmdDispatchTileQCOM; +#define vkCmdDispatchTileQCOM glad_vkCmdDispatchTileQCOM GLAD_API_CALL PFN_vkCmdDraw glad_vkCmdDraw; #define vkCmdDraw glad_vkCmdDraw +GLAD_API_CALL PFN_vkCmdDrawClusterHUAWEI glad_vkCmdDrawClusterHUAWEI; +#define vkCmdDrawClusterHUAWEI glad_vkCmdDrawClusterHUAWEI +GLAD_API_CALL PFN_vkCmdDrawClusterIndirectHUAWEI glad_vkCmdDrawClusterIndirectHUAWEI; +#define vkCmdDrawClusterIndirectHUAWEI glad_vkCmdDrawClusterIndirectHUAWEI GLAD_API_CALL PFN_vkCmdDrawIndexed glad_vkCmdDrawIndexed; #define vkCmdDrawIndexed glad_vkCmdDrawIndexed GLAD_API_CALL PFN_vkCmdDrawIndexedIndirect glad_vkCmdDrawIndexedIndirect; @@ -10050,16 +18011,28 @@ GLAD_API_CALL PFN_vkCmdDrawIndirectCountAMD glad_vkCmdDrawIndirectCountAMD; #define vkCmdDrawIndirectCountAMD glad_vkCmdDrawIndirectCountAMD GLAD_API_CALL PFN_vkCmdDrawIndirectCountKHR glad_vkCmdDrawIndirectCountKHR; #define vkCmdDrawIndirectCountKHR glad_vkCmdDrawIndirectCountKHR +GLAD_API_CALL PFN_vkCmdDrawMeshTasksEXT glad_vkCmdDrawMeshTasksEXT; +#define vkCmdDrawMeshTasksEXT glad_vkCmdDrawMeshTasksEXT +GLAD_API_CALL PFN_vkCmdDrawMeshTasksIndirectCountEXT glad_vkCmdDrawMeshTasksIndirectCountEXT; +#define vkCmdDrawMeshTasksIndirectCountEXT glad_vkCmdDrawMeshTasksIndirectCountEXT GLAD_API_CALL PFN_vkCmdDrawMeshTasksIndirectCountNV glad_vkCmdDrawMeshTasksIndirectCountNV; #define vkCmdDrawMeshTasksIndirectCountNV glad_vkCmdDrawMeshTasksIndirectCountNV +GLAD_API_CALL PFN_vkCmdDrawMeshTasksIndirectEXT glad_vkCmdDrawMeshTasksIndirectEXT; +#define vkCmdDrawMeshTasksIndirectEXT glad_vkCmdDrawMeshTasksIndirectEXT GLAD_API_CALL PFN_vkCmdDrawMeshTasksIndirectNV glad_vkCmdDrawMeshTasksIndirectNV; #define vkCmdDrawMeshTasksIndirectNV glad_vkCmdDrawMeshTasksIndirectNV GLAD_API_CALL PFN_vkCmdDrawMeshTasksNV glad_vkCmdDrawMeshTasksNV; #define vkCmdDrawMeshTasksNV glad_vkCmdDrawMeshTasksNV +GLAD_API_CALL PFN_vkCmdDrawMultiEXT glad_vkCmdDrawMultiEXT; +#define vkCmdDrawMultiEXT glad_vkCmdDrawMultiEXT +GLAD_API_CALL PFN_vkCmdDrawMultiIndexedEXT glad_vkCmdDrawMultiIndexedEXT; +#define vkCmdDrawMultiIndexedEXT glad_vkCmdDrawMultiIndexedEXT GLAD_API_CALL PFN_vkCmdEndConditionalRenderingEXT glad_vkCmdEndConditionalRenderingEXT; #define vkCmdEndConditionalRenderingEXT glad_vkCmdEndConditionalRenderingEXT GLAD_API_CALL PFN_vkCmdEndDebugUtilsLabelEXT glad_vkCmdEndDebugUtilsLabelEXT; #define vkCmdEndDebugUtilsLabelEXT glad_vkCmdEndDebugUtilsLabelEXT +GLAD_API_CALL PFN_vkCmdEndPerTileExecutionQCOM glad_vkCmdEndPerTileExecutionQCOM; +#define vkCmdEndPerTileExecutionQCOM glad_vkCmdEndPerTileExecutionQCOM GLAD_API_CALL PFN_vkCmdEndQuery glad_vkCmdEndQuery; #define vkCmdEndQuery glad_vkCmdEndQuery GLAD_API_CALL PFN_vkCmdEndQueryIndexedEXT glad_vkCmdEndQueryIndexedEXT; @@ -10070,14 +18043,27 @@ GLAD_API_CALL PFN_vkCmdEndRenderPass2 glad_vkCmdEndRenderPass2; #define vkCmdEndRenderPass2 glad_vkCmdEndRenderPass2 GLAD_API_CALL PFN_vkCmdEndRenderPass2KHR glad_vkCmdEndRenderPass2KHR; #define vkCmdEndRenderPass2KHR glad_vkCmdEndRenderPass2KHR +GLAD_API_CALL PFN_vkCmdEndRendering glad_vkCmdEndRendering; +#define vkCmdEndRendering glad_vkCmdEndRendering +GLAD_API_CALL PFN_vkCmdEndRendering2EXT glad_vkCmdEndRendering2EXT; +#define vkCmdEndRendering2EXT glad_vkCmdEndRendering2EXT +GLAD_API_CALL PFN_vkCmdEndRenderingKHR glad_vkCmdEndRenderingKHR; +#define vkCmdEndRenderingKHR glad_vkCmdEndRenderingKHR GLAD_API_CALL PFN_vkCmdEndTransformFeedbackEXT glad_vkCmdEndTransformFeedbackEXT; #define vkCmdEndTransformFeedbackEXT glad_vkCmdEndTransformFeedbackEXT GLAD_API_CALL PFN_vkCmdExecuteCommands glad_vkCmdExecuteCommands; #define vkCmdExecuteCommands glad_vkCmdExecuteCommands +GLAD_API_CALL PFN_vkCmdExecuteGeneratedCommandsEXT glad_vkCmdExecuteGeneratedCommandsEXT; +#define vkCmdExecuteGeneratedCommandsEXT glad_vkCmdExecuteGeneratedCommandsEXT GLAD_API_CALL PFN_vkCmdExecuteGeneratedCommandsNV glad_vkCmdExecuteGeneratedCommandsNV; #define vkCmdExecuteGeneratedCommandsNV glad_vkCmdExecuteGeneratedCommandsNV GLAD_API_CALL PFN_vkCmdFillBuffer glad_vkCmdFillBuffer; #define vkCmdFillBuffer glad_vkCmdFillBuffer +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdInitializeGraphScratchMemoryAMDX glad_vkCmdInitializeGraphScratchMemoryAMDX; +#define vkCmdInitializeGraphScratchMemoryAMDX glad_vkCmdInitializeGraphScratchMemoryAMDX + +#endif GLAD_API_CALL PFN_vkCmdInsertDebugUtilsLabelEXT glad_vkCmdInsertDebugUtilsLabelEXT; #define vkCmdInsertDebugUtilsLabelEXT glad_vkCmdInsertDebugUtilsLabelEXT GLAD_API_CALL PFN_vkCmdNextSubpass glad_vkCmdNextSubpass; @@ -10086,154 +18072,370 @@ GLAD_API_CALL PFN_vkCmdNextSubpass2 glad_vkCmdNextSubpass2; #define vkCmdNextSubpass2 glad_vkCmdNextSubpass2 GLAD_API_CALL PFN_vkCmdNextSubpass2KHR glad_vkCmdNextSubpass2KHR; #define vkCmdNextSubpass2KHR glad_vkCmdNextSubpass2KHR +GLAD_API_CALL PFN_vkCmdOpticalFlowExecuteNV glad_vkCmdOpticalFlowExecuteNV; +#define vkCmdOpticalFlowExecuteNV glad_vkCmdOpticalFlowExecuteNV GLAD_API_CALL PFN_vkCmdPipelineBarrier glad_vkCmdPipelineBarrier; #define vkCmdPipelineBarrier glad_vkCmdPipelineBarrier +GLAD_API_CALL PFN_vkCmdPipelineBarrier2 glad_vkCmdPipelineBarrier2; +#define vkCmdPipelineBarrier2 glad_vkCmdPipelineBarrier2 +GLAD_API_CALL PFN_vkCmdPipelineBarrier2KHR glad_vkCmdPipelineBarrier2KHR; +#define vkCmdPipelineBarrier2KHR glad_vkCmdPipelineBarrier2KHR +GLAD_API_CALL PFN_vkCmdPreprocessGeneratedCommandsEXT glad_vkCmdPreprocessGeneratedCommandsEXT; +#define vkCmdPreprocessGeneratedCommandsEXT glad_vkCmdPreprocessGeneratedCommandsEXT GLAD_API_CALL PFN_vkCmdPreprocessGeneratedCommandsNV glad_vkCmdPreprocessGeneratedCommandsNV; #define vkCmdPreprocessGeneratedCommandsNV glad_vkCmdPreprocessGeneratedCommandsNV GLAD_API_CALL PFN_vkCmdPushConstants glad_vkCmdPushConstants; #define vkCmdPushConstants glad_vkCmdPushConstants +GLAD_API_CALL PFN_vkCmdPushConstants2 glad_vkCmdPushConstants2; +#define vkCmdPushConstants2 glad_vkCmdPushConstants2 +GLAD_API_CALL PFN_vkCmdPushConstants2KHR glad_vkCmdPushConstants2KHR; +#define vkCmdPushConstants2KHR glad_vkCmdPushConstants2KHR +GLAD_API_CALL PFN_vkCmdPushDescriptorSet glad_vkCmdPushDescriptorSet; +#define vkCmdPushDescriptorSet glad_vkCmdPushDescriptorSet +GLAD_API_CALL PFN_vkCmdPushDescriptorSet2 glad_vkCmdPushDescriptorSet2; +#define vkCmdPushDescriptorSet2 glad_vkCmdPushDescriptorSet2 +GLAD_API_CALL PFN_vkCmdPushDescriptorSet2KHR glad_vkCmdPushDescriptorSet2KHR; +#define vkCmdPushDescriptorSet2KHR glad_vkCmdPushDescriptorSet2KHR GLAD_API_CALL PFN_vkCmdPushDescriptorSetKHR glad_vkCmdPushDescriptorSetKHR; #define vkCmdPushDescriptorSetKHR glad_vkCmdPushDescriptorSetKHR +GLAD_API_CALL PFN_vkCmdPushDescriptorSetWithTemplate glad_vkCmdPushDescriptorSetWithTemplate; +#define vkCmdPushDescriptorSetWithTemplate glad_vkCmdPushDescriptorSetWithTemplate +GLAD_API_CALL PFN_vkCmdPushDescriptorSetWithTemplate2 glad_vkCmdPushDescriptorSetWithTemplate2; +#define vkCmdPushDescriptorSetWithTemplate2 glad_vkCmdPushDescriptorSetWithTemplate2 +GLAD_API_CALL PFN_vkCmdPushDescriptorSetWithTemplate2KHR glad_vkCmdPushDescriptorSetWithTemplate2KHR; +#define vkCmdPushDescriptorSetWithTemplate2KHR glad_vkCmdPushDescriptorSetWithTemplate2KHR GLAD_API_CALL PFN_vkCmdPushDescriptorSetWithTemplateKHR glad_vkCmdPushDescriptorSetWithTemplateKHR; #define vkCmdPushDescriptorSetWithTemplateKHR glad_vkCmdPushDescriptorSetWithTemplateKHR GLAD_API_CALL PFN_vkCmdResetEvent glad_vkCmdResetEvent; #define vkCmdResetEvent glad_vkCmdResetEvent +GLAD_API_CALL PFN_vkCmdResetEvent2 glad_vkCmdResetEvent2; +#define vkCmdResetEvent2 glad_vkCmdResetEvent2 +GLAD_API_CALL PFN_vkCmdResetEvent2KHR glad_vkCmdResetEvent2KHR; +#define vkCmdResetEvent2KHR glad_vkCmdResetEvent2KHR GLAD_API_CALL PFN_vkCmdResetQueryPool glad_vkCmdResetQueryPool; #define vkCmdResetQueryPool glad_vkCmdResetQueryPool GLAD_API_CALL PFN_vkCmdResolveImage glad_vkCmdResolveImage; #define vkCmdResolveImage glad_vkCmdResolveImage +GLAD_API_CALL PFN_vkCmdResolveImage2 glad_vkCmdResolveImage2; +#define vkCmdResolveImage2 glad_vkCmdResolveImage2 +GLAD_API_CALL PFN_vkCmdResolveImage2KHR glad_vkCmdResolveImage2KHR; +#define vkCmdResolveImage2KHR glad_vkCmdResolveImage2KHR +GLAD_API_CALL PFN_vkCmdSetAlphaToCoverageEnableEXT glad_vkCmdSetAlphaToCoverageEnableEXT; +#define vkCmdSetAlphaToCoverageEnableEXT glad_vkCmdSetAlphaToCoverageEnableEXT +GLAD_API_CALL PFN_vkCmdSetAlphaToOneEnableEXT glad_vkCmdSetAlphaToOneEnableEXT; +#define vkCmdSetAlphaToOneEnableEXT glad_vkCmdSetAlphaToOneEnableEXT +GLAD_API_CALL PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT glad_vkCmdSetAttachmentFeedbackLoopEnableEXT; +#define vkCmdSetAttachmentFeedbackLoopEnableEXT glad_vkCmdSetAttachmentFeedbackLoopEnableEXT GLAD_API_CALL PFN_vkCmdSetBlendConstants glad_vkCmdSetBlendConstants; #define vkCmdSetBlendConstants glad_vkCmdSetBlendConstants GLAD_API_CALL PFN_vkCmdSetCheckpointNV glad_vkCmdSetCheckpointNV; #define vkCmdSetCheckpointNV glad_vkCmdSetCheckpointNV GLAD_API_CALL PFN_vkCmdSetCoarseSampleOrderNV glad_vkCmdSetCoarseSampleOrderNV; #define vkCmdSetCoarseSampleOrderNV glad_vkCmdSetCoarseSampleOrderNV +GLAD_API_CALL PFN_vkCmdSetColorBlendAdvancedEXT glad_vkCmdSetColorBlendAdvancedEXT; +#define vkCmdSetColorBlendAdvancedEXT glad_vkCmdSetColorBlendAdvancedEXT +GLAD_API_CALL PFN_vkCmdSetColorBlendEnableEXT glad_vkCmdSetColorBlendEnableEXT; +#define vkCmdSetColorBlendEnableEXT glad_vkCmdSetColorBlendEnableEXT +GLAD_API_CALL PFN_vkCmdSetColorBlendEquationEXT glad_vkCmdSetColorBlendEquationEXT; +#define vkCmdSetColorBlendEquationEXT glad_vkCmdSetColorBlendEquationEXT +GLAD_API_CALL PFN_vkCmdSetColorWriteEnableEXT glad_vkCmdSetColorWriteEnableEXT; +#define vkCmdSetColorWriteEnableEXT glad_vkCmdSetColorWriteEnableEXT +GLAD_API_CALL PFN_vkCmdSetColorWriteMaskEXT glad_vkCmdSetColorWriteMaskEXT; +#define vkCmdSetColorWriteMaskEXT glad_vkCmdSetColorWriteMaskEXT +GLAD_API_CALL PFN_vkCmdSetConservativeRasterizationModeEXT glad_vkCmdSetConservativeRasterizationModeEXT; +#define vkCmdSetConservativeRasterizationModeEXT glad_vkCmdSetConservativeRasterizationModeEXT +GLAD_API_CALL PFN_vkCmdSetCoverageModulationModeNV glad_vkCmdSetCoverageModulationModeNV; +#define vkCmdSetCoverageModulationModeNV glad_vkCmdSetCoverageModulationModeNV +GLAD_API_CALL PFN_vkCmdSetCoverageModulationTableEnableNV glad_vkCmdSetCoverageModulationTableEnableNV; +#define vkCmdSetCoverageModulationTableEnableNV glad_vkCmdSetCoverageModulationTableEnableNV +GLAD_API_CALL PFN_vkCmdSetCoverageModulationTableNV glad_vkCmdSetCoverageModulationTableNV; +#define vkCmdSetCoverageModulationTableNV glad_vkCmdSetCoverageModulationTableNV +GLAD_API_CALL PFN_vkCmdSetCoverageReductionModeNV glad_vkCmdSetCoverageReductionModeNV; +#define vkCmdSetCoverageReductionModeNV glad_vkCmdSetCoverageReductionModeNV +GLAD_API_CALL PFN_vkCmdSetCoverageToColorEnableNV glad_vkCmdSetCoverageToColorEnableNV; +#define vkCmdSetCoverageToColorEnableNV glad_vkCmdSetCoverageToColorEnableNV +GLAD_API_CALL PFN_vkCmdSetCoverageToColorLocationNV glad_vkCmdSetCoverageToColorLocationNV; +#define vkCmdSetCoverageToColorLocationNV glad_vkCmdSetCoverageToColorLocationNV +GLAD_API_CALL PFN_vkCmdSetCullMode glad_vkCmdSetCullMode; +#define vkCmdSetCullMode glad_vkCmdSetCullMode GLAD_API_CALL PFN_vkCmdSetCullModeEXT glad_vkCmdSetCullModeEXT; #define vkCmdSetCullModeEXT glad_vkCmdSetCullModeEXT GLAD_API_CALL PFN_vkCmdSetDepthBias glad_vkCmdSetDepthBias; #define vkCmdSetDepthBias glad_vkCmdSetDepthBias +GLAD_API_CALL PFN_vkCmdSetDepthBias2EXT glad_vkCmdSetDepthBias2EXT; +#define vkCmdSetDepthBias2EXT glad_vkCmdSetDepthBias2EXT +GLAD_API_CALL PFN_vkCmdSetDepthBiasEnable glad_vkCmdSetDepthBiasEnable; +#define vkCmdSetDepthBiasEnable glad_vkCmdSetDepthBiasEnable +GLAD_API_CALL PFN_vkCmdSetDepthBiasEnableEXT glad_vkCmdSetDepthBiasEnableEXT; +#define vkCmdSetDepthBiasEnableEXT glad_vkCmdSetDepthBiasEnableEXT GLAD_API_CALL PFN_vkCmdSetDepthBounds glad_vkCmdSetDepthBounds; #define vkCmdSetDepthBounds glad_vkCmdSetDepthBounds +GLAD_API_CALL PFN_vkCmdSetDepthBoundsTestEnable glad_vkCmdSetDepthBoundsTestEnable; +#define vkCmdSetDepthBoundsTestEnable glad_vkCmdSetDepthBoundsTestEnable GLAD_API_CALL PFN_vkCmdSetDepthBoundsTestEnableEXT glad_vkCmdSetDepthBoundsTestEnableEXT; #define vkCmdSetDepthBoundsTestEnableEXT glad_vkCmdSetDepthBoundsTestEnableEXT +GLAD_API_CALL PFN_vkCmdSetDepthClampEnableEXT glad_vkCmdSetDepthClampEnableEXT; +#define vkCmdSetDepthClampEnableEXT glad_vkCmdSetDepthClampEnableEXT +GLAD_API_CALL PFN_vkCmdSetDepthClampRangeEXT glad_vkCmdSetDepthClampRangeEXT; +#define vkCmdSetDepthClampRangeEXT glad_vkCmdSetDepthClampRangeEXT +GLAD_API_CALL PFN_vkCmdSetDepthClipEnableEXT glad_vkCmdSetDepthClipEnableEXT; +#define vkCmdSetDepthClipEnableEXT glad_vkCmdSetDepthClipEnableEXT +GLAD_API_CALL PFN_vkCmdSetDepthClipNegativeOneToOneEXT glad_vkCmdSetDepthClipNegativeOneToOneEXT; +#define vkCmdSetDepthClipNegativeOneToOneEXT glad_vkCmdSetDepthClipNegativeOneToOneEXT +GLAD_API_CALL PFN_vkCmdSetDepthCompareOp glad_vkCmdSetDepthCompareOp; +#define vkCmdSetDepthCompareOp glad_vkCmdSetDepthCompareOp GLAD_API_CALL PFN_vkCmdSetDepthCompareOpEXT glad_vkCmdSetDepthCompareOpEXT; #define vkCmdSetDepthCompareOpEXT glad_vkCmdSetDepthCompareOpEXT +GLAD_API_CALL PFN_vkCmdSetDepthTestEnable glad_vkCmdSetDepthTestEnable; +#define vkCmdSetDepthTestEnable glad_vkCmdSetDepthTestEnable GLAD_API_CALL PFN_vkCmdSetDepthTestEnableEXT glad_vkCmdSetDepthTestEnableEXT; #define vkCmdSetDepthTestEnableEXT glad_vkCmdSetDepthTestEnableEXT +GLAD_API_CALL PFN_vkCmdSetDepthWriteEnable glad_vkCmdSetDepthWriteEnable; +#define vkCmdSetDepthWriteEnable glad_vkCmdSetDepthWriteEnable GLAD_API_CALL PFN_vkCmdSetDepthWriteEnableEXT glad_vkCmdSetDepthWriteEnableEXT; #define vkCmdSetDepthWriteEnableEXT glad_vkCmdSetDepthWriteEnableEXT +GLAD_API_CALL PFN_vkCmdSetDescriptorBufferOffsets2EXT glad_vkCmdSetDescriptorBufferOffsets2EXT; +#define vkCmdSetDescriptorBufferOffsets2EXT glad_vkCmdSetDescriptorBufferOffsets2EXT +GLAD_API_CALL PFN_vkCmdSetDescriptorBufferOffsetsEXT glad_vkCmdSetDescriptorBufferOffsetsEXT; +#define vkCmdSetDescriptorBufferOffsetsEXT glad_vkCmdSetDescriptorBufferOffsetsEXT GLAD_API_CALL PFN_vkCmdSetDeviceMask glad_vkCmdSetDeviceMask; #define vkCmdSetDeviceMask glad_vkCmdSetDeviceMask GLAD_API_CALL PFN_vkCmdSetDeviceMaskKHR glad_vkCmdSetDeviceMaskKHR; #define vkCmdSetDeviceMaskKHR glad_vkCmdSetDeviceMaskKHR GLAD_API_CALL PFN_vkCmdSetDiscardRectangleEXT glad_vkCmdSetDiscardRectangleEXT; #define vkCmdSetDiscardRectangleEXT glad_vkCmdSetDiscardRectangleEXT +GLAD_API_CALL PFN_vkCmdSetDiscardRectangleEnableEXT glad_vkCmdSetDiscardRectangleEnableEXT; +#define vkCmdSetDiscardRectangleEnableEXT glad_vkCmdSetDiscardRectangleEnableEXT +GLAD_API_CALL PFN_vkCmdSetDiscardRectangleModeEXT glad_vkCmdSetDiscardRectangleModeEXT; +#define vkCmdSetDiscardRectangleModeEXT glad_vkCmdSetDiscardRectangleModeEXT GLAD_API_CALL PFN_vkCmdSetEvent glad_vkCmdSetEvent; #define vkCmdSetEvent glad_vkCmdSetEvent +GLAD_API_CALL PFN_vkCmdSetEvent2 glad_vkCmdSetEvent2; +#define vkCmdSetEvent2 glad_vkCmdSetEvent2 +GLAD_API_CALL PFN_vkCmdSetEvent2KHR glad_vkCmdSetEvent2KHR; +#define vkCmdSetEvent2KHR glad_vkCmdSetEvent2KHR +GLAD_API_CALL PFN_vkCmdSetExclusiveScissorEnableNV glad_vkCmdSetExclusiveScissorEnableNV; +#define vkCmdSetExclusiveScissorEnableNV glad_vkCmdSetExclusiveScissorEnableNV GLAD_API_CALL PFN_vkCmdSetExclusiveScissorNV glad_vkCmdSetExclusiveScissorNV; #define vkCmdSetExclusiveScissorNV glad_vkCmdSetExclusiveScissorNV +GLAD_API_CALL PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT glad_vkCmdSetExtraPrimitiveOverestimationSizeEXT; +#define vkCmdSetExtraPrimitiveOverestimationSizeEXT glad_vkCmdSetExtraPrimitiveOverestimationSizeEXT +GLAD_API_CALL PFN_vkCmdSetFragmentShadingRateEnumNV glad_vkCmdSetFragmentShadingRateEnumNV; +#define vkCmdSetFragmentShadingRateEnumNV glad_vkCmdSetFragmentShadingRateEnumNV +GLAD_API_CALL PFN_vkCmdSetFragmentShadingRateKHR glad_vkCmdSetFragmentShadingRateKHR; +#define vkCmdSetFragmentShadingRateKHR glad_vkCmdSetFragmentShadingRateKHR +GLAD_API_CALL PFN_vkCmdSetFrontFace glad_vkCmdSetFrontFace; +#define vkCmdSetFrontFace glad_vkCmdSetFrontFace GLAD_API_CALL PFN_vkCmdSetFrontFaceEXT glad_vkCmdSetFrontFaceEXT; #define vkCmdSetFrontFaceEXT glad_vkCmdSetFrontFaceEXT +GLAD_API_CALL PFN_vkCmdSetLineRasterizationModeEXT glad_vkCmdSetLineRasterizationModeEXT; +#define vkCmdSetLineRasterizationModeEXT glad_vkCmdSetLineRasterizationModeEXT +GLAD_API_CALL PFN_vkCmdSetLineStipple glad_vkCmdSetLineStipple; +#define vkCmdSetLineStipple glad_vkCmdSetLineStipple GLAD_API_CALL PFN_vkCmdSetLineStippleEXT glad_vkCmdSetLineStippleEXT; #define vkCmdSetLineStippleEXT glad_vkCmdSetLineStippleEXT +GLAD_API_CALL PFN_vkCmdSetLineStippleEnableEXT glad_vkCmdSetLineStippleEnableEXT; +#define vkCmdSetLineStippleEnableEXT glad_vkCmdSetLineStippleEnableEXT +GLAD_API_CALL PFN_vkCmdSetLineStippleKHR glad_vkCmdSetLineStippleKHR; +#define vkCmdSetLineStippleKHR glad_vkCmdSetLineStippleKHR GLAD_API_CALL PFN_vkCmdSetLineWidth glad_vkCmdSetLineWidth; #define vkCmdSetLineWidth glad_vkCmdSetLineWidth +GLAD_API_CALL PFN_vkCmdSetLogicOpEXT glad_vkCmdSetLogicOpEXT; +#define vkCmdSetLogicOpEXT glad_vkCmdSetLogicOpEXT +GLAD_API_CALL PFN_vkCmdSetLogicOpEnableEXT glad_vkCmdSetLogicOpEnableEXT; +#define vkCmdSetLogicOpEnableEXT glad_vkCmdSetLogicOpEnableEXT +GLAD_API_CALL PFN_vkCmdSetPatchControlPointsEXT glad_vkCmdSetPatchControlPointsEXT; +#define vkCmdSetPatchControlPointsEXT glad_vkCmdSetPatchControlPointsEXT GLAD_API_CALL PFN_vkCmdSetPerformanceMarkerINTEL glad_vkCmdSetPerformanceMarkerINTEL; #define vkCmdSetPerformanceMarkerINTEL glad_vkCmdSetPerformanceMarkerINTEL GLAD_API_CALL PFN_vkCmdSetPerformanceOverrideINTEL glad_vkCmdSetPerformanceOverrideINTEL; #define vkCmdSetPerformanceOverrideINTEL glad_vkCmdSetPerformanceOverrideINTEL GLAD_API_CALL PFN_vkCmdSetPerformanceStreamMarkerINTEL glad_vkCmdSetPerformanceStreamMarkerINTEL; #define vkCmdSetPerformanceStreamMarkerINTEL glad_vkCmdSetPerformanceStreamMarkerINTEL +GLAD_API_CALL PFN_vkCmdSetPolygonModeEXT glad_vkCmdSetPolygonModeEXT; +#define vkCmdSetPolygonModeEXT glad_vkCmdSetPolygonModeEXT +GLAD_API_CALL PFN_vkCmdSetPrimitiveRestartEnable glad_vkCmdSetPrimitiveRestartEnable; +#define vkCmdSetPrimitiveRestartEnable glad_vkCmdSetPrimitiveRestartEnable +GLAD_API_CALL PFN_vkCmdSetPrimitiveRestartEnableEXT glad_vkCmdSetPrimitiveRestartEnableEXT; +#define vkCmdSetPrimitiveRestartEnableEXT glad_vkCmdSetPrimitiveRestartEnableEXT +GLAD_API_CALL PFN_vkCmdSetPrimitiveTopology glad_vkCmdSetPrimitiveTopology; +#define vkCmdSetPrimitiveTopology glad_vkCmdSetPrimitiveTopology GLAD_API_CALL PFN_vkCmdSetPrimitiveTopologyEXT glad_vkCmdSetPrimitiveTopologyEXT; #define vkCmdSetPrimitiveTopologyEXT glad_vkCmdSetPrimitiveTopologyEXT +GLAD_API_CALL PFN_vkCmdSetProvokingVertexModeEXT glad_vkCmdSetProvokingVertexModeEXT; +#define vkCmdSetProvokingVertexModeEXT glad_vkCmdSetProvokingVertexModeEXT +GLAD_API_CALL PFN_vkCmdSetRasterizationSamplesEXT glad_vkCmdSetRasterizationSamplesEXT; +#define vkCmdSetRasterizationSamplesEXT glad_vkCmdSetRasterizationSamplesEXT +GLAD_API_CALL PFN_vkCmdSetRasterizationStreamEXT glad_vkCmdSetRasterizationStreamEXT; +#define vkCmdSetRasterizationStreamEXT glad_vkCmdSetRasterizationStreamEXT +GLAD_API_CALL PFN_vkCmdSetRasterizerDiscardEnable glad_vkCmdSetRasterizerDiscardEnable; +#define vkCmdSetRasterizerDiscardEnable glad_vkCmdSetRasterizerDiscardEnable +GLAD_API_CALL PFN_vkCmdSetRasterizerDiscardEnableEXT glad_vkCmdSetRasterizerDiscardEnableEXT; +#define vkCmdSetRasterizerDiscardEnableEXT glad_vkCmdSetRasterizerDiscardEnableEXT +GLAD_API_CALL PFN_vkCmdSetRayTracingPipelineStackSizeKHR glad_vkCmdSetRayTracingPipelineStackSizeKHR; +#define vkCmdSetRayTracingPipelineStackSizeKHR glad_vkCmdSetRayTracingPipelineStackSizeKHR +GLAD_API_CALL PFN_vkCmdSetRenderingAttachmentLocations glad_vkCmdSetRenderingAttachmentLocations; +#define vkCmdSetRenderingAttachmentLocations glad_vkCmdSetRenderingAttachmentLocations +GLAD_API_CALL PFN_vkCmdSetRenderingAttachmentLocationsKHR glad_vkCmdSetRenderingAttachmentLocationsKHR; +#define vkCmdSetRenderingAttachmentLocationsKHR glad_vkCmdSetRenderingAttachmentLocationsKHR +GLAD_API_CALL PFN_vkCmdSetRenderingInputAttachmentIndices glad_vkCmdSetRenderingInputAttachmentIndices; +#define vkCmdSetRenderingInputAttachmentIndices glad_vkCmdSetRenderingInputAttachmentIndices +GLAD_API_CALL PFN_vkCmdSetRenderingInputAttachmentIndicesKHR glad_vkCmdSetRenderingInputAttachmentIndicesKHR; +#define vkCmdSetRenderingInputAttachmentIndicesKHR glad_vkCmdSetRenderingInputAttachmentIndicesKHR +GLAD_API_CALL PFN_vkCmdSetRepresentativeFragmentTestEnableNV glad_vkCmdSetRepresentativeFragmentTestEnableNV; +#define vkCmdSetRepresentativeFragmentTestEnableNV glad_vkCmdSetRepresentativeFragmentTestEnableNV GLAD_API_CALL PFN_vkCmdSetSampleLocationsEXT glad_vkCmdSetSampleLocationsEXT; #define vkCmdSetSampleLocationsEXT glad_vkCmdSetSampleLocationsEXT +GLAD_API_CALL PFN_vkCmdSetSampleLocationsEnableEXT glad_vkCmdSetSampleLocationsEnableEXT; +#define vkCmdSetSampleLocationsEnableEXT glad_vkCmdSetSampleLocationsEnableEXT +GLAD_API_CALL PFN_vkCmdSetSampleMaskEXT glad_vkCmdSetSampleMaskEXT; +#define vkCmdSetSampleMaskEXT glad_vkCmdSetSampleMaskEXT GLAD_API_CALL PFN_vkCmdSetScissor glad_vkCmdSetScissor; #define vkCmdSetScissor glad_vkCmdSetScissor +GLAD_API_CALL PFN_vkCmdSetScissorWithCount glad_vkCmdSetScissorWithCount; +#define vkCmdSetScissorWithCount glad_vkCmdSetScissorWithCount GLAD_API_CALL PFN_vkCmdSetScissorWithCountEXT glad_vkCmdSetScissorWithCountEXT; #define vkCmdSetScissorWithCountEXT glad_vkCmdSetScissorWithCountEXT +GLAD_API_CALL PFN_vkCmdSetShadingRateImageEnableNV glad_vkCmdSetShadingRateImageEnableNV; +#define vkCmdSetShadingRateImageEnableNV glad_vkCmdSetShadingRateImageEnableNV GLAD_API_CALL PFN_vkCmdSetStencilCompareMask glad_vkCmdSetStencilCompareMask; #define vkCmdSetStencilCompareMask glad_vkCmdSetStencilCompareMask +GLAD_API_CALL PFN_vkCmdSetStencilOp glad_vkCmdSetStencilOp; +#define vkCmdSetStencilOp glad_vkCmdSetStencilOp GLAD_API_CALL PFN_vkCmdSetStencilOpEXT glad_vkCmdSetStencilOpEXT; #define vkCmdSetStencilOpEXT glad_vkCmdSetStencilOpEXT GLAD_API_CALL PFN_vkCmdSetStencilReference glad_vkCmdSetStencilReference; #define vkCmdSetStencilReference glad_vkCmdSetStencilReference +GLAD_API_CALL PFN_vkCmdSetStencilTestEnable glad_vkCmdSetStencilTestEnable; +#define vkCmdSetStencilTestEnable glad_vkCmdSetStencilTestEnable GLAD_API_CALL PFN_vkCmdSetStencilTestEnableEXT glad_vkCmdSetStencilTestEnableEXT; #define vkCmdSetStencilTestEnableEXT glad_vkCmdSetStencilTestEnableEXT GLAD_API_CALL PFN_vkCmdSetStencilWriteMask glad_vkCmdSetStencilWriteMask; #define vkCmdSetStencilWriteMask glad_vkCmdSetStencilWriteMask +GLAD_API_CALL PFN_vkCmdSetTessellationDomainOriginEXT glad_vkCmdSetTessellationDomainOriginEXT; +#define vkCmdSetTessellationDomainOriginEXT glad_vkCmdSetTessellationDomainOriginEXT +GLAD_API_CALL PFN_vkCmdSetVertexInputEXT glad_vkCmdSetVertexInputEXT; +#define vkCmdSetVertexInputEXT glad_vkCmdSetVertexInputEXT GLAD_API_CALL PFN_vkCmdSetViewport glad_vkCmdSetViewport; #define vkCmdSetViewport glad_vkCmdSetViewport GLAD_API_CALL PFN_vkCmdSetViewportShadingRatePaletteNV glad_vkCmdSetViewportShadingRatePaletteNV; #define vkCmdSetViewportShadingRatePaletteNV glad_vkCmdSetViewportShadingRatePaletteNV +GLAD_API_CALL PFN_vkCmdSetViewportSwizzleNV glad_vkCmdSetViewportSwizzleNV; +#define vkCmdSetViewportSwizzleNV glad_vkCmdSetViewportSwizzleNV +GLAD_API_CALL PFN_vkCmdSetViewportWScalingEnableNV glad_vkCmdSetViewportWScalingEnableNV; +#define vkCmdSetViewportWScalingEnableNV glad_vkCmdSetViewportWScalingEnableNV GLAD_API_CALL PFN_vkCmdSetViewportWScalingNV glad_vkCmdSetViewportWScalingNV; #define vkCmdSetViewportWScalingNV glad_vkCmdSetViewportWScalingNV +GLAD_API_CALL PFN_vkCmdSetViewportWithCount glad_vkCmdSetViewportWithCount; +#define vkCmdSetViewportWithCount glad_vkCmdSetViewportWithCount GLAD_API_CALL PFN_vkCmdSetViewportWithCountEXT glad_vkCmdSetViewportWithCountEXT; #define vkCmdSetViewportWithCountEXT glad_vkCmdSetViewportWithCountEXT -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdSubpassShadingHUAWEI glad_vkCmdSubpassShadingHUAWEI; +#define vkCmdSubpassShadingHUAWEI glad_vkCmdSubpassShadingHUAWEI +GLAD_API_CALL PFN_vkCmdTraceRaysIndirect2KHR glad_vkCmdTraceRaysIndirect2KHR; +#define vkCmdTraceRaysIndirect2KHR glad_vkCmdTraceRaysIndirect2KHR GLAD_API_CALL PFN_vkCmdTraceRaysIndirectKHR glad_vkCmdTraceRaysIndirectKHR; #define vkCmdTraceRaysIndirectKHR glad_vkCmdTraceRaysIndirectKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkCmdTraceRaysKHR glad_vkCmdTraceRaysKHR; #define vkCmdTraceRaysKHR glad_vkCmdTraceRaysKHR -#endif GLAD_API_CALL PFN_vkCmdTraceRaysNV glad_vkCmdTraceRaysNV; #define vkCmdTraceRaysNV glad_vkCmdTraceRaysNV GLAD_API_CALL PFN_vkCmdUpdateBuffer glad_vkCmdUpdateBuffer; #define vkCmdUpdateBuffer glad_vkCmdUpdateBuffer +GLAD_API_CALL PFN_vkCmdUpdatePipelineIndirectBufferNV glad_vkCmdUpdatePipelineIndirectBufferNV; +#define vkCmdUpdatePipelineIndirectBufferNV glad_vkCmdUpdatePipelineIndirectBufferNV GLAD_API_CALL PFN_vkCmdWaitEvents glad_vkCmdWaitEvents; #define vkCmdWaitEvents glad_vkCmdWaitEvents -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCmdWaitEvents2 glad_vkCmdWaitEvents2; +#define vkCmdWaitEvents2 glad_vkCmdWaitEvents2 +GLAD_API_CALL PFN_vkCmdWaitEvents2KHR glad_vkCmdWaitEvents2KHR; +#define vkCmdWaitEvents2KHR glad_vkCmdWaitEvents2KHR GLAD_API_CALL PFN_vkCmdWriteAccelerationStructuresPropertiesKHR glad_vkCmdWriteAccelerationStructuresPropertiesKHR; #define vkCmdWriteAccelerationStructuresPropertiesKHR glad_vkCmdWriteAccelerationStructuresPropertiesKHR -#endif GLAD_API_CALL PFN_vkCmdWriteAccelerationStructuresPropertiesNV glad_vkCmdWriteAccelerationStructuresPropertiesNV; #define vkCmdWriteAccelerationStructuresPropertiesNV glad_vkCmdWriteAccelerationStructuresPropertiesNV +GLAD_API_CALL PFN_vkCmdWriteBufferMarker2AMD glad_vkCmdWriteBufferMarker2AMD; +#define vkCmdWriteBufferMarker2AMD glad_vkCmdWriteBufferMarker2AMD GLAD_API_CALL PFN_vkCmdWriteBufferMarkerAMD glad_vkCmdWriteBufferMarkerAMD; #define vkCmdWriteBufferMarkerAMD glad_vkCmdWriteBufferMarkerAMD +GLAD_API_CALL PFN_vkCmdWriteMicromapsPropertiesEXT glad_vkCmdWriteMicromapsPropertiesEXT; +#define vkCmdWriteMicromapsPropertiesEXT glad_vkCmdWriteMicromapsPropertiesEXT GLAD_API_CALL PFN_vkCmdWriteTimestamp glad_vkCmdWriteTimestamp; #define vkCmdWriteTimestamp glad_vkCmdWriteTimestamp +GLAD_API_CALL PFN_vkCmdWriteTimestamp2 glad_vkCmdWriteTimestamp2; +#define vkCmdWriteTimestamp2 glad_vkCmdWriteTimestamp2 +GLAD_API_CALL PFN_vkCmdWriteTimestamp2KHR glad_vkCmdWriteTimestamp2KHR; +#define vkCmdWriteTimestamp2KHR glad_vkCmdWriteTimestamp2KHR GLAD_API_CALL PFN_vkCompileDeferredNV glad_vkCompileDeferredNV; #define vkCompileDeferredNV glad_vkCompileDeferredNV -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkConvertCooperativeVectorMatrixNV glad_vkConvertCooperativeVectorMatrixNV; +#define vkConvertCooperativeVectorMatrixNV glad_vkConvertCooperativeVectorMatrixNV GLAD_API_CALL PFN_vkCopyAccelerationStructureKHR glad_vkCopyAccelerationStructureKHR; #define vkCopyAccelerationStructureKHR glad_vkCopyAccelerationStructureKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkCopyAccelerationStructureToMemoryKHR glad_vkCopyAccelerationStructureToMemoryKHR; #define vkCopyAccelerationStructureToMemoryKHR glad_vkCopyAccelerationStructureToMemoryKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCopyImageToImage glad_vkCopyImageToImage; +#define vkCopyImageToImage glad_vkCopyImageToImage +GLAD_API_CALL PFN_vkCopyImageToImageEXT glad_vkCopyImageToImageEXT; +#define vkCopyImageToImageEXT glad_vkCopyImageToImageEXT +GLAD_API_CALL PFN_vkCopyImageToMemory glad_vkCopyImageToMemory; +#define vkCopyImageToMemory glad_vkCopyImageToMemory +GLAD_API_CALL PFN_vkCopyImageToMemoryEXT glad_vkCopyImageToMemoryEXT; +#define vkCopyImageToMemoryEXT glad_vkCopyImageToMemoryEXT GLAD_API_CALL PFN_vkCopyMemoryToAccelerationStructureKHR glad_vkCopyMemoryToAccelerationStructureKHR; #define vkCopyMemoryToAccelerationStructureKHR glad_vkCopyMemoryToAccelerationStructureKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCopyMemoryToImage glad_vkCopyMemoryToImage; +#define vkCopyMemoryToImage glad_vkCopyMemoryToImage +GLAD_API_CALL PFN_vkCopyMemoryToImageEXT glad_vkCopyMemoryToImageEXT; +#define vkCopyMemoryToImageEXT glad_vkCopyMemoryToImageEXT +GLAD_API_CALL PFN_vkCopyMemoryToMicromapEXT glad_vkCopyMemoryToMicromapEXT; +#define vkCopyMemoryToMicromapEXT glad_vkCopyMemoryToMicromapEXT +GLAD_API_CALL PFN_vkCopyMicromapEXT glad_vkCopyMicromapEXT; +#define vkCopyMicromapEXT glad_vkCopyMicromapEXT +GLAD_API_CALL PFN_vkCopyMicromapToMemoryEXT glad_vkCopyMicromapToMemoryEXT; +#define vkCopyMicromapToMemoryEXT glad_vkCopyMicromapToMemoryEXT GLAD_API_CALL PFN_vkCreateAccelerationStructureKHR glad_vkCreateAccelerationStructureKHR; #define vkCreateAccelerationStructureKHR glad_vkCreateAccelerationStructureKHR -#endif GLAD_API_CALL PFN_vkCreateAccelerationStructureNV glad_vkCreateAccelerationStructureNV; #define vkCreateAccelerationStructureNV glad_vkCreateAccelerationStructureNV #if defined(VK_USE_PLATFORM_ANDROID_KHR) GLAD_API_CALL PFN_vkCreateAndroidSurfaceKHR glad_vkCreateAndroidSurfaceKHR; #define vkCreateAndroidSurfaceKHR glad_vkCreateAndroidSurfaceKHR + #endif GLAD_API_CALL PFN_vkCreateBuffer glad_vkCreateBuffer; #define vkCreateBuffer glad_vkCreateBuffer +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkCreateBufferCollectionFUCHSIA glad_vkCreateBufferCollectionFUCHSIA; +#define vkCreateBufferCollectionFUCHSIA glad_vkCreateBufferCollectionFUCHSIA + +#endif GLAD_API_CALL PFN_vkCreateBufferView glad_vkCreateBufferView; #define vkCreateBufferView glad_vkCreateBufferView GLAD_API_CALL PFN_vkCreateCommandPool glad_vkCreateCommandPool; #define vkCreateCommandPool glad_vkCreateCommandPool GLAD_API_CALL PFN_vkCreateComputePipelines glad_vkCreateComputePipelines; #define vkCreateComputePipelines glad_vkCreateComputePipelines +GLAD_API_CALL PFN_vkCreateCuFunctionNVX glad_vkCreateCuFunctionNVX; +#define vkCreateCuFunctionNVX glad_vkCreateCuFunctionNVX +GLAD_API_CALL PFN_vkCreateCuModuleNVX glad_vkCreateCuModuleNVX; +#define vkCreateCuModuleNVX glad_vkCreateCuModuleNVX +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCreateCudaFunctionNV glad_vkCreateCudaFunctionNV; +#define vkCreateCudaFunctionNV glad_vkCreateCudaFunctionNV + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCreateCudaModuleNV glad_vkCreateCudaModuleNV; +#define vkCreateCudaModuleNV glad_vkCreateCudaModuleNV + +#endif GLAD_API_CALL PFN_vkCreateDebugReportCallbackEXT glad_vkCreateDebugReportCallbackEXT; #define vkCreateDebugReportCallbackEXT glad_vkCreateDebugReportCallbackEXT GLAD_API_CALL PFN_vkCreateDebugUtilsMessengerEXT glad_vkCreateDebugUtilsMessengerEXT; #define vkCreateDebugUtilsMessengerEXT glad_vkCreateDebugUtilsMessengerEXT -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkCreateDeferredOperationKHR glad_vkCreateDeferredOperationKHR; #define vkCreateDeferredOperationKHR glad_vkCreateDeferredOperationKHR -#endif GLAD_API_CALL PFN_vkCreateDescriptorPool glad_vkCreateDescriptorPool; #define vkCreateDescriptorPool glad_vkCreateDescriptorPool GLAD_API_CALL PFN_vkCreateDescriptorSetLayout glad_vkCreateDescriptorSetLayout; @@ -10247,6 +18449,7 @@ GLAD_API_CALL PFN_vkCreateDevice glad_vkCreateDevice; #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) GLAD_API_CALL PFN_vkCreateDirectFBSurfaceEXT glad_vkCreateDirectFBSurfaceEXT; #define vkCreateDirectFBSurfaceEXT glad_vkCreateDirectFBSurfaceEXT + #endif GLAD_API_CALL PFN_vkCreateDisplayModeKHR glad_vkCreateDisplayModeKHR; #define vkCreateDisplayModeKHR glad_vkCreateDisplayModeKHR @@ -10254,6 +18457,13 @@ GLAD_API_CALL PFN_vkCreateDisplayPlaneSurfaceKHR glad_vkCreateDisplayPlaneSurfac #define vkCreateDisplayPlaneSurfaceKHR glad_vkCreateDisplayPlaneSurfaceKHR GLAD_API_CALL PFN_vkCreateEvent glad_vkCreateEvent; #define vkCreateEvent glad_vkCreateEvent +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkCreateExecutionGraphPipelinesAMDX glad_vkCreateExecutionGraphPipelinesAMDX; +#define vkCreateExecutionGraphPipelinesAMDX glad_vkCreateExecutionGraphPipelinesAMDX + +#endif +GLAD_API_CALL PFN_vkCreateExternalComputeQueueNV glad_vkCreateExternalComputeQueueNV; +#define vkCreateExternalComputeQueueNV glad_vkCreateExternalComputeQueueNV GLAD_API_CALL PFN_vkCreateFence glad_vkCreateFence; #define vkCreateFence glad_vkCreateFence GLAD_API_CALL PFN_vkCreateFramebuffer glad_vkCreateFramebuffer; @@ -10265,39 +18475,53 @@ GLAD_API_CALL PFN_vkCreateHeadlessSurfaceEXT glad_vkCreateHeadlessSurfaceEXT; #if defined(VK_USE_PLATFORM_IOS_MVK) GLAD_API_CALL PFN_vkCreateIOSSurfaceMVK glad_vkCreateIOSSurfaceMVK; #define vkCreateIOSSurfaceMVK glad_vkCreateIOSSurfaceMVK + #endif GLAD_API_CALL PFN_vkCreateImage glad_vkCreateImage; #define vkCreateImage glad_vkCreateImage #if defined(VK_USE_PLATFORM_FUCHSIA) GLAD_API_CALL PFN_vkCreateImagePipeSurfaceFUCHSIA glad_vkCreateImagePipeSurfaceFUCHSIA; #define vkCreateImagePipeSurfaceFUCHSIA glad_vkCreateImagePipeSurfaceFUCHSIA + #endif GLAD_API_CALL PFN_vkCreateImageView glad_vkCreateImageView; #define vkCreateImageView glad_vkCreateImageView +GLAD_API_CALL PFN_vkCreateIndirectCommandsLayoutEXT glad_vkCreateIndirectCommandsLayoutEXT; +#define vkCreateIndirectCommandsLayoutEXT glad_vkCreateIndirectCommandsLayoutEXT GLAD_API_CALL PFN_vkCreateIndirectCommandsLayoutNV glad_vkCreateIndirectCommandsLayoutNV; #define vkCreateIndirectCommandsLayoutNV glad_vkCreateIndirectCommandsLayoutNV +GLAD_API_CALL PFN_vkCreateIndirectExecutionSetEXT glad_vkCreateIndirectExecutionSetEXT; +#define vkCreateIndirectExecutionSetEXT glad_vkCreateIndirectExecutionSetEXT GLAD_API_CALL PFN_vkCreateInstance glad_vkCreateInstance; #define vkCreateInstance glad_vkCreateInstance #if defined(VK_USE_PLATFORM_MACOS_MVK) GLAD_API_CALL PFN_vkCreateMacOSSurfaceMVK glad_vkCreateMacOSSurfaceMVK; #define vkCreateMacOSSurfaceMVK glad_vkCreateMacOSSurfaceMVK + #endif #if defined(VK_USE_PLATFORM_METAL_EXT) GLAD_API_CALL PFN_vkCreateMetalSurfaceEXT glad_vkCreateMetalSurfaceEXT; #define vkCreateMetalSurfaceEXT glad_vkCreateMetalSurfaceEXT + #endif +GLAD_API_CALL PFN_vkCreateMicromapEXT glad_vkCreateMicromapEXT; +#define vkCreateMicromapEXT glad_vkCreateMicromapEXT +GLAD_API_CALL PFN_vkCreateOpticalFlowSessionNV glad_vkCreateOpticalFlowSessionNV; +#define vkCreateOpticalFlowSessionNV glad_vkCreateOpticalFlowSessionNV +GLAD_API_CALL PFN_vkCreatePipelineBinariesKHR glad_vkCreatePipelineBinariesKHR; +#define vkCreatePipelineBinariesKHR glad_vkCreatePipelineBinariesKHR GLAD_API_CALL PFN_vkCreatePipelineCache glad_vkCreatePipelineCache; #define vkCreatePipelineCache glad_vkCreatePipelineCache GLAD_API_CALL PFN_vkCreatePipelineLayout glad_vkCreatePipelineLayout; #define vkCreatePipelineLayout glad_vkCreatePipelineLayout +GLAD_API_CALL PFN_vkCreatePrivateDataSlot glad_vkCreatePrivateDataSlot; +#define vkCreatePrivateDataSlot glad_vkCreatePrivateDataSlot GLAD_API_CALL PFN_vkCreatePrivateDataSlotEXT glad_vkCreatePrivateDataSlotEXT; #define vkCreatePrivateDataSlotEXT glad_vkCreatePrivateDataSlotEXT GLAD_API_CALL PFN_vkCreateQueryPool glad_vkCreateQueryPool; #define vkCreateQueryPool glad_vkCreateQueryPool -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkCreateRayTracingPipelinesKHR glad_vkCreateRayTracingPipelinesKHR; #define vkCreateRayTracingPipelinesKHR glad_vkCreateRayTracingPipelinesKHR -#endif GLAD_API_CALL PFN_vkCreateRayTracingPipelinesNV glad_vkCreateRayTracingPipelinesNV; #define vkCreateRayTracingPipelinesNV glad_vkCreateRayTracingPipelinesNV GLAD_API_CALL PFN_vkCreateRenderPass glad_vkCreateRenderPass; @@ -10312,15 +18536,23 @@ GLAD_API_CALL PFN_vkCreateSamplerYcbcrConversion glad_vkCreateSamplerYcbcrConver #define vkCreateSamplerYcbcrConversion glad_vkCreateSamplerYcbcrConversion GLAD_API_CALL PFN_vkCreateSamplerYcbcrConversionKHR glad_vkCreateSamplerYcbcrConversionKHR; #define vkCreateSamplerYcbcrConversionKHR glad_vkCreateSamplerYcbcrConversionKHR +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +GLAD_API_CALL PFN_vkCreateScreenSurfaceQNX glad_vkCreateScreenSurfaceQNX; +#define vkCreateScreenSurfaceQNX glad_vkCreateScreenSurfaceQNX + +#endif GLAD_API_CALL PFN_vkCreateSemaphore glad_vkCreateSemaphore; #define vkCreateSemaphore glad_vkCreateSemaphore GLAD_API_CALL PFN_vkCreateShaderModule glad_vkCreateShaderModule; #define vkCreateShaderModule glad_vkCreateShaderModule +GLAD_API_CALL PFN_vkCreateShadersEXT glad_vkCreateShadersEXT; +#define vkCreateShadersEXT glad_vkCreateShadersEXT GLAD_API_CALL PFN_vkCreateSharedSwapchainsKHR glad_vkCreateSharedSwapchainsKHR; #define vkCreateSharedSwapchainsKHR glad_vkCreateSharedSwapchainsKHR #if defined(VK_USE_PLATFORM_GGP) GLAD_API_CALL PFN_vkCreateStreamDescriptorSurfaceGGP glad_vkCreateStreamDescriptorSurfaceGGP; #define vkCreateStreamDescriptorSurfaceGGP glad_vkCreateStreamDescriptorSurfaceGGP + #endif GLAD_API_CALL PFN_vkCreateSwapchainKHR glad_vkCreateSwapchainKHR; #define vkCreateSwapchainKHR glad_vkCreateSwapchainKHR @@ -10329,22 +18561,27 @@ GLAD_API_CALL PFN_vkCreateValidationCacheEXT glad_vkCreateValidationCacheEXT; #if defined(VK_USE_PLATFORM_VI_NN) GLAD_API_CALL PFN_vkCreateViSurfaceNN glad_vkCreateViSurfaceNN; #define vkCreateViSurfaceNN glad_vkCreateViSurfaceNN + #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) GLAD_API_CALL PFN_vkCreateWaylandSurfaceKHR glad_vkCreateWaylandSurfaceKHR; #define vkCreateWaylandSurfaceKHR glad_vkCreateWaylandSurfaceKHR + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkCreateWin32SurfaceKHR glad_vkCreateWin32SurfaceKHR; #define vkCreateWin32SurfaceKHR glad_vkCreateWin32SurfaceKHR + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) GLAD_API_CALL PFN_vkCreateXcbSurfaceKHR glad_vkCreateXcbSurfaceKHR; #define vkCreateXcbSurfaceKHR glad_vkCreateXcbSurfaceKHR + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) GLAD_API_CALL PFN_vkCreateXlibSurfaceKHR glad_vkCreateXlibSurfaceKHR; #define vkCreateXlibSurfaceKHR glad_vkCreateXlibSurfaceKHR + #endif GLAD_API_CALL PFN_vkDebugMarkerSetObjectNameEXT glad_vkDebugMarkerSetObjectNameEXT; #define vkDebugMarkerSetObjectNameEXT glad_vkDebugMarkerSetObjectNameEXT @@ -10352,30 +18589,43 @@ GLAD_API_CALL PFN_vkDebugMarkerSetObjectTagEXT glad_vkDebugMarkerSetObjectTagEXT #define vkDebugMarkerSetObjectTagEXT glad_vkDebugMarkerSetObjectTagEXT GLAD_API_CALL PFN_vkDebugReportMessageEXT glad_vkDebugReportMessageEXT; #define vkDebugReportMessageEXT glad_vkDebugReportMessageEXT -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkDeferredOperationJoinKHR glad_vkDeferredOperationJoinKHR; #define vkDeferredOperationJoinKHR glad_vkDeferredOperationJoinKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkDestroyAccelerationStructureKHR glad_vkDestroyAccelerationStructureKHR; #define vkDestroyAccelerationStructureKHR glad_vkDestroyAccelerationStructureKHR -#endif GLAD_API_CALL PFN_vkDestroyAccelerationStructureNV glad_vkDestroyAccelerationStructureNV; #define vkDestroyAccelerationStructureNV glad_vkDestroyAccelerationStructureNV GLAD_API_CALL PFN_vkDestroyBuffer glad_vkDestroyBuffer; #define vkDestroyBuffer glad_vkDestroyBuffer +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkDestroyBufferCollectionFUCHSIA glad_vkDestroyBufferCollectionFUCHSIA; +#define vkDestroyBufferCollectionFUCHSIA glad_vkDestroyBufferCollectionFUCHSIA + +#endif GLAD_API_CALL PFN_vkDestroyBufferView glad_vkDestroyBufferView; #define vkDestroyBufferView glad_vkDestroyBufferView GLAD_API_CALL PFN_vkDestroyCommandPool glad_vkDestroyCommandPool; #define vkDestroyCommandPool glad_vkDestroyCommandPool +GLAD_API_CALL PFN_vkDestroyCuFunctionNVX glad_vkDestroyCuFunctionNVX; +#define vkDestroyCuFunctionNVX glad_vkDestroyCuFunctionNVX +GLAD_API_CALL PFN_vkDestroyCuModuleNVX glad_vkDestroyCuModuleNVX; +#define vkDestroyCuModuleNVX glad_vkDestroyCuModuleNVX +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkDestroyCudaFunctionNV glad_vkDestroyCudaFunctionNV; +#define vkDestroyCudaFunctionNV glad_vkDestroyCudaFunctionNV + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkDestroyCudaModuleNV glad_vkDestroyCudaModuleNV; +#define vkDestroyCudaModuleNV glad_vkDestroyCudaModuleNV + +#endif GLAD_API_CALL PFN_vkDestroyDebugReportCallbackEXT glad_vkDestroyDebugReportCallbackEXT; #define vkDestroyDebugReportCallbackEXT glad_vkDestroyDebugReportCallbackEXT GLAD_API_CALL PFN_vkDestroyDebugUtilsMessengerEXT glad_vkDestroyDebugUtilsMessengerEXT; #define vkDestroyDebugUtilsMessengerEXT glad_vkDestroyDebugUtilsMessengerEXT -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkDestroyDeferredOperationKHR glad_vkDestroyDeferredOperationKHR; #define vkDestroyDeferredOperationKHR glad_vkDestroyDeferredOperationKHR -#endif GLAD_API_CALL PFN_vkDestroyDescriptorPool glad_vkDestroyDescriptorPool; #define vkDestroyDescriptorPool glad_vkDestroyDescriptorPool GLAD_API_CALL PFN_vkDestroyDescriptorSetLayout glad_vkDestroyDescriptorSetLayout; @@ -10388,6 +18638,8 @@ GLAD_API_CALL PFN_vkDestroyDevice glad_vkDestroyDevice; #define vkDestroyDevice glad_vkDestroyDevice GLAD_API_CALL PFN_vkDestroyEvent glad_vkDestroyEvent; #define vkDestroyEvent glad_vkDestroyEvent +GLAD_API_CALL PFN_vkDestroyExternalComputeQueueNV glad_vkDestroyExternalComputeQueueNV; +#define vkDestroyExternalComputeQueueNV glad_vkDestroyExternalComputeQueueNV GLAD_API_CALL PFN_vkDestroyFence glad_vkDestroyFence; #define vkDestroyFence glad_vkDestroyFence GLAD_API_CALL PFN_vkDestroyFramebuffer glad_vkDestroyFramebuffer; @@ -10396,16 +18648,28 @@ GLAD_API_CALL PFN_vkDestroyImage glad_vkDestroyImage; #define vkDestroyImage glad_vkDestroyImage GLAD_API_CALL PFN_vkDestroyImageView glad_vkDestroyImageView; #define vkDestroyImageView glad_vkDestroyImageView +GLAD_API_CALL PFN_vkDestroyIndirectCommandsLayoutEXT glad_vkDestroyIndirectCommandsLayoutEXT; +#define vkDestroyIndirectCommandsLayoutEXT glad_vkDestroyIndirectCommandsLayoutEXT GLAD_API_CALL PFN_vkDestroyIndirectCommandsLayoutNV glad_vkDestroyIndirectCommandsLayoutNV; #define vkDestroyIndirectCommandsLayoutNV glad_vkDestroyIndirectCommandsLayoutNV +GLAD_API_CALL PFN_vkDestroyIndirectExecutionSetEXT glad_vkDestroyIndirectExecutionSetEXT; +#define vkDestroyIndirectExecutionSetEXT glad_vkDestroyIndirectExecutionSetEXT GLAD_API_CALL PFN_vkDestroyInstance glad_vkDestroyInstance; #define vkDestroyInstance glad_vkDestroyInstance +GLAD_API_CALL PFN_vkDestroyMicromapEXT glad_vkDestroyMicromapEXT; +#define vkDestroyMicromapEXT glad_vkDestroyMicromapEXT +GLAD_API_CALL PFN_vkDestroyOpticalFlowSessionNV glad_vkDestroyOpticalFlowSessionNV; +#define vkDestroyOpticalFlowSessionNV glad_vkDestroyOpticalFlowSessionNV GLAD_API_CALL PFN_vkDestroyPipeline glad_vkDestroyPipeline; #define vkDestroyPipeline glad_vkDestroyPipeline +GLAD_API_CALL PFN_vkDestroyPipelineBinaryKHR glad_vkDestroyPipelineBinaryKHR; +#define vkDestroyPipelineBinaryKHR glad_vkDestroyPipelineBinaryKHR GLAD_API_CALL PFN_vkDestroyPipelineCache glad_vkDestroyPipelineCache; #define vkDestroyPipelineCache glad_vkDestroyPipelineCache GLAD_API_CALL PFN_vkDestroyPipelineLayout glad_vkDestroyPipelineLayout; #define vkDestroyPipelineLayout glad_vkDestroyPipelineLayout +GLAD_API_CALL PFN_vkDestroyPrivateDataSlot glad_vkDestroyPrivateDataSlot; +#define vkDestroyPrivateDataSlot glad_vkDestroyPrivateDataSlot GLAD_API_CALL PFN_vkDestroyPrivateDataSlotEXT glad_vkDestroyPrivateDataSlotEXT; #define vkDestroyPrivateDataSlotEXT glad_vkDestroyPrivateDataSlotEXT GLAD_API_CALL PFN_vkDestroyQueryPool glad_vkDestroyQueryPool; @@ -10420,6 +18684,8 @@ GLAD_API_CALL PFN_vkDestroySamplerYcbcrConversionKHR glad_vkDestroySamplerYcbcrC #define vkDestroySamplerYcbcrConversionKHR glad_vkDestroySamplerYcbcrConversionKHR GLAD_API_CALL PFN_vkDestroySemaphore glad_vkDestroySemaphore; #define vkDestroySemaphore glad_vkDestroySemaphore +GLAD_API_CALL PFN_vkDestroyShaderEXT glad_vkDestroyShaderEXT; +#define vkDestroyShaderEXT glad_vkDestroyShaderEXT GLAD_API_CALL PFN_vkDestroyShaderModule glad_vkDestroyShaderModule; #define vkDestroyShaderModule glad_vkDestroyShaderModule GLAD_API_CALL PFN_vkDestroySurfaceKHR glad_vkDestroySurfaceKHR; @@ -10452,6 +18718,11 @@ GLAD_API_CALL PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKH #define vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR glad_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR GLAD_API_CALL PFN_vkEnumeratePhysicalDevices glad_vkEnumeratePhysicalDevices; #define vkEnumeratePhysicalDevices glad_vkEnumeratePhysicalDevices +#if defined(VK_USE_PLATFORM_METAL_EXT) +GLAD_API_CALL PFN_vkExportMetalObjectsEXT glad_vkExportMetalObjectsEXT; +#define vkExportMetalObjectsEXT glad_vkExportMetalObjectsEXT + +#endif GLAD_API_CALL PFN_vkFlushMappedMemoryRanges glad_vkFlushMappedMemoryRanges; #define vkFlushMappedMemoryRanges glad_vkFlushMappedMemoryRanges GLAD_API_CALL PFN_vkFreeCommandBuffers glad_vkFreeCommandBuffers; @@ -10460,21 +18731,25 @@ GLAD_API_CALL PFN_vkFreeDescriptorSets glad_vkFreeDescriptorSets; #define vkFreeDescriptorSets glad_vkFreeDescriptorSets GLAD_API_CALL PFN_vkFreeMemory glad_vkFreeMemory; #define vkFreeMemory glad_vkFreeMemory -#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkGetAccelerationStructureBuildSizesKHR glad_vkGetAccelerationStructureBuildSizesKHR; +#define vkGetAccelerationStructureBuildSizesKHR glad_vkGetAccelerationStructureBuildSizesKHR GLAD_API_CALL PFN_vkGetAccelerationStructureDeviceAddressKHR glad_vkGetAccelerationStructureDeviceAddressKHR; #define vkGetAccelerationStructureDeviceAddressKHR glad_vkGetAccelerationStructureDeviceAddressKHR -#endif GLAD_API_CALL PFN_vkGetAccelerationStructureHandleNV glad_vkGetAccelerationStructureHandleNV; #define vkGetAccelerationStructureHandleNV glad_vkGetAccelerationStructureHandleNV -#if defined(VK_ENABLE_BETA_EXTENSIONS) -GLAD_API_CALL PFN_vkGetAccelerationStructureMemoryRequirementsKHR glad_vkGetAccelerationStructureMemoryRequirementsKHR; -#define vkGetAccelerationStructureMemoryRequirementsKHR glad_vkGetAccelerationStructureMemoryRequirementsKHR -#endif GLAD_API_CALL PFN_vkGetAccelerationStructureMemoryRequirementsNV glad_vkGetAccelerationStructureMemoryRequirementsNV; #define vkGetAccelerationStructureMemoryRequirementsNV glad_vkGetAccelerationStructureMemoryRequirementsNV +GLAD_API_CALL PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT glad_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT; +#define vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT glad_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT #if defined(VK_USE_PLATFORM_ANDROID_KHR) GLAD_API_CALL PFN_vkGetAndroidHardwareBufferPropertiesANDROID glad_vkGetAndroidHardwareBufferPropertiesANDROID; #define vkGetAndroidHardwareBufferPropertiesANDROID glad_vkGetAndroidHardwareBufferPropertiesANDROID + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkGetBufferCollectionPropertiesFUCHSIA glad_vkGetBufferCollectionPropertiesFUCHSIA; +#define vkGetBufferCollectionPropertiesFUCHSIA glad_vkGetBufferCollectionPropertiesFUCHSIA + #endif GLAD_API_CALL PFN_vkGetBufferDeviceAddress glad_vkGetBufferDeviceAddress; #define vkGetBufferDeviceAddress glad_vkGetBufferDeviceAddress @@ -10492,24 +18767,45 @@ GLAD_API_CALL PFN_vkGetBufferOpaqueCaptureAddress glad_vkGetBufferOpaqueCaptureA #define vkGetBufferOpaqueCaptureAddress glad_vkGetBufferOpaqueCaptureAddress GLAD_API_CALL PFN_vkGetBufferOpaqueCaptureAddressKHR glad_vkGetBufferOpaqueCaptureAddressKHR; #define vkGetBufferOpaqueCaptureAddressKHR glad_vkGetBufferOpaqueCaptureAddressKHR +GLAD_API_CALL PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT glad_vkGetBufferOpaqueCaptureDescriptorDataEXT; +#define vkGetBufferOpaqueCaptureDescriptorDataEXT glad_vkGetBufferOpaqueCaptureDescriptorDataEXT GLAD_API_CALL PFN_vkGetCalibratedTimestampsEXT glad_vkGetCalibratedTimestampsEXT; #define vkGetCalibratedTimestampsEXT glad_vkGetCalibratedTimestampsEXT +GLAD_API_CALL PFN_vkGetCalibratedTimestampsKHR glad_vkGetCalibratedTimestampsKHR; +#define vkGetCalibratedTimestampsKHR glad_vkGetCalibratedTimestampsKHR +GLAD_API_CALL PFN_vkGetClusterAccelerationStructureBuildSizesNV glad_vkGetClusterAccelerationStructureBuildSizesNV; +#define vkGetClusterAccelerationStructureBuildSizesNV glad_vkGetClusterAccelerationStructureBuildSizesNV #if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkGetCudaModuleCacheNV glad_vkGetCudaModuleCacheNV; +#define vkGetCudaModuleCacheNV glad_vkGetCudaModuleCacheNV + +#endif GLAD_API_CALL PFN_vkGetDeferredOperationMaxConcurrencyKHR glad_vkGetDeferredOperationMaxConcurrencyKHR; #define vkGetDeferredOperationMaxConcurrencyKHR glad_vkGetDeferredOperationMaxConcurrencyKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkGetDeferredOperationResultKHR glad_vkGetDeferredOperationResultKHR; #define vkGetDeferredOperationResultKHR glad_vkGetDeferredOperationResultKHR -#endif +GLAD_API_CALL PFN_vkGetDescriptorEXT glad_vkGetDescriptorEXT; +#define vkGetDescriptorEXT glad_vkGetDescriptorEXT +GLAD_API_CALL PFN_vkGetDescriptorSetHostMappingVALVE glad_vkGetDescriptorSetHostMappingVALVE; +#define vkGetDescriptorSetHostMappingVALVE glad_vkGetDescriptorSetHostMappingVALVE +GLAD_API_CALL PFN_vkGetDescriptorSetLayoutBindingOffsetEXT glad_vkGetDescriptorSetLayoutBindingOffsetEXT; +#define vkGetDescriptorSetLayoutBindingOffsetEXT glad_vkGetDescriptorSetLayoutBindingOffsetEXT +GLAD_API_CALL PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE glad_vkGetDescriptorSetLayoutHostMappingInfoVALVE; +#define vkGetDescriptorSetLayoutHostMappingInfoVALVE glad_vkGetDescriptorSetLayoutHostMappingInfoVALVE +GLAD_API_CALL PFN_vkGetDescriptorSetLayoutSizeEXT glad_vkGetDescriptorSetLayoutSizeEXT; +#define vkGetDescriptorSetLayoutSizeEXT glad_vkGetDescriptorSetLayoutSizeEXT GLAD_API_CALL PFN_vkGetDescriptorSetLayoutSupport glad_vkGetDescriptorSetLayoutSupport; #define vkGetDescriptorSetLayoutSupport glad_vkGetDescriptorSetLayoutSupport GLAD_API_CALL PFN_vkGetDescriptorSetLayoutSupportKHR glad_vkGetDescriptorSetLayoutSupportKHR; #define vkGetDescriptorSetLayoutSupportKHR glad_vkGetDescriptorSetLayoutSupportKHR -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkGetDeviceAccelerationStructureCompatibilityKHR glad_vkGetDeviceAccelerationStructureCompatibilityKHR; #define vkGetDeviceAccelerationStructureCompatibilityKHR glad_vkGetDeviceAccelerationStructureCompatibilityKHR -#endif +GLAD_API_CALL PFN_vkGetDeviceBufferMemoryRequirements glad_vkGetDeviceBufferMemoryRequirements; +#define vkGetDeviceBufferMemoryRequirements glad_vkGetDeviceBufferMemoryRequirements +GLAD_API_CALL PFN_vkGetDeviceBufferMemoryRequirementsKHR glad_vkGetDeviceBufferMemoryRequirementsKHR; +#define vkGetDeviceBufferMemoryRequirementsKHR glad_vkGetDeviceBufferMemoryRequirementsKHR +GLAD_API_CALL PFN_vkGetDeviceFaultInfoEXT glad_vkGetDeviceFaultInfoEXT; +#define vkGetDeviceFaultInfoEXT glad_vkGetDeviceFaultInfoEXT GLAD_API_CALL PFN_vkGetDeviceGroupPeerMemoryFeatures glad_vkGetDeviceGroupPeerMemoryFeatures; #define vkGetDeviceGroupPeerMemoryFeatures glad_vkGetDeviceGroupPeerMemoryFeatures GLAD_API_CALL PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR glad_vkGetDeviceGroupPeerMemoryFeaturesKHR; @@ -10519,21 +18815,38 @@ GLAD_API_CALL PFN_vkGetDeviceGroupPresentCapabilitiesKHR glad_vkGetDeviceGroupPr #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetDeviceGroupSurfacePresentModes2EXT glad_vkGetDeviceGroupSurfacePresentModes2EXT; #define vkGetDeviceGroupSurfacePresentModes2EXT glad_vkGetDeviceGroupSurfacePresentModes2EXT + #endif GLAD_API_CALL PFN_vkGetDeviceGroupSurfacePresentModesKHR glad_vkGetDeviceGroupSurfacePresentModesKHR; #define vkGetDeviceGroupSurfacePresentModesKHR glad_vkGetDeviceGroupSurfacePresentModesKHR +GLAD_API_CALL PFN_vkGetDeviceImageMemoryRequirements glad_vkGetDeviceImageMemoryRequirements; +#define vkGetDeviceImageMemoryRequirements glad_vkGetDeviceImageMemoryRequirements +GLAD_API_CALL PFN_vkGetDeviceImageMemoryRequirementsKHR glad_vkGetDeviceImageMemoryRequirementsKHR; +#define vkGetDeviceImageMemoryRequirementsKHR glad_vkGetDeviceImageMemoryRequirementsKHR +GLAD_API_CALL PFN_vkGetDeviceImageSparseMemoryRequirements glad_vkGetDeviceImageSparseMemoryRequirements; +#define vkGetDeviceImageSparseMemoryRequirements glad_vkGetDeviceImageSparseMemoryRequirements +GLAD_API_CALL PFN_vkGetDeviceImageSparseMemoryRequirementsKHR glad_vkGetDeviceImageSparseMemoryRequirementsKHR; +#define vkGetDeviceImageSparseMemoryRequirementsKHR glad_vkGetDeviceImageSparseMemoryRequirementsKHR +GLAD_API_CALL PFN_vkGetDeviceImageSubresourceLayout glad_vkGetDeviceImageSubresourceLayout; +#define vkGetDeviceImageSubresourceLayout glad_vkGetDeviceImageSubresourceLayout +GLAD_API_CALL PFN_vkGetDeviceImageSubresourceLayoutKHR glad_vkGetDeviceImageSubresourceLayoutKHR; +#define vkGetDeviceImageSubresourceLayoutKHR glad_vkGetDeviceImageSubresourceLayoutKHR GLAD_API_CALL PFN_vkGetDeviceMemoryCommitment glad_vkGetDeviceMemoryCommitment; #define vkGetDeviceMemoryCommitment glad_vkGetDeviceMemoryCommitment GLAD_API_CALL PFN_vkGetDeviceMemoryOpaqueCaptureAddress glad_vkGetDeviceMemoryOpaqueCaptureAddress; #define vkGetDeviceMemoryOpaqueCaptureAddress glad_vkGetDeviceMemoryOpaqueCaptureAddress GLAD_API_CALL PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR glad_vkGetDeviceMemoryOpaqueCaptureAddressKHR; #define vkGetDeviceMemoryOpaqueCaptureAddressKHR glad_vkGetDeviceMemoryOpaqueCaptureAddressKHR +GLAD_API_CALL PFN_vkGetDeviceMicromapCompatibilityEXT glad_vkGetDeviceMicromapCompatibilityEXT; +#define vkGetDeviceMicromapCompatibilityEXT glad_vkGetDeviceMicromapCompatibilityEXT GLAD_API_CALL PFN_vkGetDeviceProcAddr glad_vkGetDeviceProcAddr; #define vkGetDeviceProcAddr glad_vkGetDeviceProcAddr GLAD_API_CALL PFN_vkGetDeviceQueue glad_vkGetDeviceQueue; #define vkGetDeviceQueue glad_vkGetDeviceQueue GLAD_API_CALL PFN_vkGetDeviceQueue2 glad_vkGetDeviceQueue2; #define vkGetDeviceQueue2 glad_vkGetDeviceQueue2 +GLAD_API_CALL PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI glad_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI; +#define vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI glad_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI GLAD_API_CALL PFN_vkGetDisplayModeProperties2KHR glad_vkGetDisplayModeProperties2KHR; #define vkGetDisplayModeProperties2KHR glad_vkGetDisplayModeProperties2KHR GLAD_API_CALL PFN_vkGetDisplayModePropertiesKHR glad_vkGetDisplayModePropertiesKHR; @@ -10544,8 +18857,24 @@ GLAD_API_CALL PFN_vkGetDisplayPlaneCapabilitiesKHR glad_vkGetDisplayPlaneCapabil #define vkGetDisplayPlaneCapabilitiesKHR glad_vkGetDisplayPlaneCapabilitiesKHR GLAD_API_CALL PFN_vkGetDisplayPlaneSupportedDisplaysKHR glad_vkGetDisplayPlaneSupportedDisplaysKHR; #define vkGetDisplayPlaneSupportedDisplaysKHR glad_vkGetDisplayPlaneSupportedDisplaysKHR +GLAD_API_CALL PFN_vkGetDrmDisplayEXT glad_vkGetDrmDisplayEXT; +#define vkGetDrmDisplayEXT glad_vkGetDrmDisplayEXT +GLAD_API_CALL PFN_vkGetDynamicRenderingTilePropertiesQCOM glad_vkGetDynamicRenderingTilePropertiesQCOM; +#define vkGetDynamicRenderingTilePropertiesQCOM glad_vkGetDynamicRenderingTilePropertiesQCOM GLAD_API_CALL PFN_vkGetEventStatus glad_vkGetEventStatus; #define vkGetEventStatus glad_vkGetEventStatus +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkGetExecutionGraphPipelineNodeIndexAMDX glad_vkGetExecutionGraphPipelineNodeIndexAMDX; +#define vkGetExecutionGraphPipelineNodeIndexAMDX glad_vkGetExecutionGraphPipelineNodeIndexAMDX + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +GLAD_API_CALL PFN_vkGetExecutionGraphPipelineScratchSizeAMDX glad_vkGetExecutionGraphPipelineScratchSizeAMDX; +#define vkGetExecutionGraphPipelineScratchSizeAMDX glad_vkGetExecutionGraphPipelineScratchSizeAMDX + +#endif +GLAD_API_CALL PFN_vkGetExternalComputeQueueDataNV glad_vkGetExternalComputeQueueDataNV; +#define vkGetExternalComputeQueueDataNV glad_vkGetExternalComputeQueueDataNV GLAD_API_CALL PFN_vkGetFenceFdKHR glad_vkGetFenceFdKHR; #define vkGetFenceFdKHR glad_vkGetFenceFdKHR GLAD_API_CALL PFN_vkGetFenceStatus glad_vkGetFenceStatus; @@ -10553,7 +18882,12 @@ GLAD_API_CALL PFN_vkGetFenceStatus glad_vkGetFenceStatus; #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetFenceWin32HandleKHR glad_vkGetFenceWin32HandleKHR; #define vkGetFenceWin32HandleKHR glad_vkGetFenceWin32HandleKHR + #endif +GLAD_API_CALL PFN_vkGetFramebufferTilePropertiesQCOM glad_vkGetFramebufferTilePropertiesQCOM; +#define vkGetFramebufferTilePropertiesQCOM glad_vkGetFramebufferTilePropertiesQCOM +GLAD_API_CALL PFN_vkGetGeneratedCommandsMemoryRequirementsEXT glad_vkGetGeneratedCommandsMemoryRequirementsEXT; +#define vkGetGeneratedCommandsMemoryRequirementsEXT glad_vkGetGeneratedCommandsMemoryRequirementsEXT GLAD_API_CALL PFN_vkGetGeneratedCommandsMemoryRequirementsNV glad_vkGetGeneratedCommandsMemoryRequirementsNV; #define vkGetGeneratedCommandsMemoryRequirementsNV glad_vkGetGeneratedCommandsMemoryRequirementsNV GLAD_API_CALL PFN_vkGetImageDrmFormatModifierPropertiesEXT glad_vkGetImageDrmFormatModifierPropertiesEXT; @@ -10564,6 +18898,8 @@ GLAD_API_CALL PFN_vkGetImageMemoryRequirements2 glad_vkGetImageMemoryRequirement #define vkGetImageMemoryRequirements2 glad_vkGetImageMemoryRequirements2 GLAD_API_CALL PFN_vkGetImageMemoryRequirements2KHR glad_vkGetImageMemoryRequirements2KHR; #define vkGetImageMemoryRequirements2KHR glad_vkGetImageMemoryRequirements2KHR +GLAD_API_CALL PFN_vkGetImageOpaqueCaptureDescriptorDataEXT glad_vkGetImageOpaqueCaptureDescriptorDataEXT; +#define vkGetImageOpaqueCaptureDescriptorDataEXT glad_vkGetImageOpaqueCaptureDescriptorDataEXT GLAD_API_CALL PFN_vkGetImageSparseMemoryRequirements glad_vkGetImageSparseMemoryRequirements; #define vkGetImageSparseMemoryRequirements glad_vkGetImageSparseMemoryRequirements GLAD_API_CALL PFN_vkGetImageSparseMemoryRequirements2 glad_vkGetImageSparseMemoryRequirements2; @@ -10572,15 +18908,28 @@ GLAD_API_CALL PFN_vkGetImageSparseMemoryRequirements2KHR glad_vkGetImageSparseMe #define vkGetImageSparseMemoryRequirements2KHR glad_vkGetImageSparseMemoryRequirements2KHR GLAD_API_CALL PFN_vkGetImageSubresourceLayout glad_vkGetImageSubresourceLayout; #define vkGetImageSubresourceLayout glad_vkGetImageSubresourceLayout +GLAD_API_CALL PFN_vkGetImageSubresourceLayout2 glad_vkGetImageSubresourceLayout2; +#define vkGetImageSubresourceLayout2 glad_vkGetImageSubresourceLayout2 +GLAD_API_CALL PFN_vkGetImageSubresourceLayout2EXT glad_vkGetImageSubresourceLayout2EXT; +#define vkGetImageSubresourceLayout2EXT glad_vkGetImageSubresourceLayout2EXT +GLAD_API_CALL PFN_vkGetImageSubresourceLayout2KHR glad_vkGetImageSubresourceLayout2KHR; +#define vkGetImageSubresourceLayout2KHR glad_vkGetImageSubresourceLayout2KHR GLAD_API_CALL PFN_vkGetImageViewAddressNVX glad_vkGetImageViewAddressNVX; #define vkGetImageViewAddressNVX glad_vkGetImageViewAddressNVX +GLAD_API_CALL PFN_vkGetImageViewHandle64NVX glad_vkGetImageViewHandle64NVX; +#define vkGetImageViewHandle64NVX glad_vkGetImageViewHandle64NVX GLAD_API_CALL PFN_vkGetImageViewHandleNVX glad_vkGetImageViewHandleNVX; #define vkGetImageViewHandleNVX glad_vkGetImageViewHandleNVX +GLAD_API_CALL PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT glad_vkGetImageViewOpaqueCaptureDescriptorDataEXT; +#define vkGetImageViewOpaqueCaptureDescriptorDataEXT glad_vkGetImageViewOpaqueCaptureDescriptorDataEXT GLAD_API_CALL PFN_vkGetInstanceProcAddr glad_vkGetInstanceProcAddr; #define vkGetInstanceProcAddr glad_vkGetInstanceProcAddr +GLAD_API_CALL PFN_vkGetLatencyTimingsNV glad_vkGetLatencyTimingsNV; +#define vkGetLatencyTimingsNV glad_vkGetLatencyTimingsNV #if defined(VK_USE_PLATFORM_ANDROID_KHR) GLAD_API_CALL PFN_vkGetMemoryAndroidHardwareBufferANDROID glad_vkGetMemoryAndroidHardwareBufferANDROID; #define vkGetMemoryAndroidHardwareBufferANDROID glad_vkGetMemoryAndroidHardwareBufferANDROID + #endif GLAD_API_CALL PFN_vkGetMemoryFdKHR glad_vkGetMemoryFdKHR; #define vkGetMemoryFdKHR glad_vkGetMemoryFdKHR @@ -10588,29 +18937,67 @@ GLAD_API_CALL PFN_vkGetMemoryFdPropertiesKHR glad_vkGetMemoryFdPropertiesKHR; #define vkGetMemoryFdPropertiesKHR glad_vkGetMemoryFdPropertiesKHR GLAD_API_CALL PFN_vkGetMemoryHostPointerPropertiesEXT glad_vkGetMemoryHostPointerPropertiesEXT; #define vkGetMemoryHostPointerPropertiesEXT glad_vkGetMemoryHostPointerPropertiesEXT +#if defined(VK_USE_PLATFORM_METAL_EXT) +GLAD_API_CALL PFN_vkGetMemoryMetalHandleEXT glad_vkGetMemoryMetalHandleEXT; +#define vkGetMemoryMetalHandleEXT glad_vkGetMemoryMetalHandleEXT + +#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +GLAD_API_CALL PFN_vkGetMemoryMetalHandlePropertiesEXT glad_vkGetMemoryMetalHandlePropertiesEXT; +#define vkGetMemoryMetalHandlePropertiesEXT glad_vkGetMemoryMetalHandlePropertiesEXT + +#endif +GLAD_API_CALL PFN_vkGetMemoryRemoteAddressNV glad_vkGetMemoryRemoteAddressNV; +#define vkGetMemoryRemoteAddressNV glad_vkGetMemoryRemoteAddressNV #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetMemoryWin32HandleKHR glad_vkGetMemoryWin32HandleKHR; #define vkGetMemoryWin32HandleKHR glad_vkGetMemoryWin32HandleKHR + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetMemoryWin32HandleNV glad_vkGetMemoryWin32HandleNV; #define vkGetMemoryWin32HandleNV glad_vkGetMemoryWin32HandleNV + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetMemoryWin32HandlePropertiesKHR glad_vkGetMemoryWin32HandlePropertiesKHR; #define vkGetMemoryWin32HandlePropertiesKHR glad_vkGetMemoryWin32HandlePropertiesKHR + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkGetMemoryZirconHandleFUCHSIA glad_vkGetMemoryZirconHandleFUCHSIA; +#define vkGetMemoryZirconHandleFUCHSIA glad_vkGetMemoryZirconHandleFUCHSIA + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA glad_vkGetMemoryZirconHandlePropertiesFUCHSIA; +#define vkGetMemoryZirconHandlePropertiesFUCHSIA glad_vkGetMemoryZirconHandlePropertiesFUCHSIA + #endif +GLAD_API_CALL PFN_vkGetMicromapBuildSizesEXT glad_vkGetMicromapBuildSizesEXT; +#define vkGetMicromapBuildSizesEXT glad_vkGetMicromapBuildSizesEXT +GLAD_API_CALL PFN_vkGetPartitionedAccelerationStructuresBuildSizesNV glad_vkGetPartitionedAccelerationStructuresBuildSizesNV; +#define vkGetPartitionedAccelerationStructuresBuildSizesNV glad_vkGetPartitionedAccelerationStructuresBuildSizesNV GLAD_API_CALL PFN_vkGetPastPresentationTimingGOOGLE glad_vkGetPastPresentationTimingGOOGLE; #define vkGetPastPresentationTimingGOOGLE glad_vkGetPastPresentationTimingGOOGLE GLAD_API_CALL PFN_vkGetPerformanceParameterINTEL glad_vkGetPerformanceParameterINTEL; #define vkGetPerformanceParameterINTEL glad_vkGetPerformanceParameterINTEL GLAD_API_CALL PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT glad_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT; #define vkGetPhysicalDeviceCalibrateableTimeDomainsEXT glad_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT +GLAD_API_CALL PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR glad_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR; +#define vkGetPhysicalDeviceCalibrateableTimeDomainsKHR glad_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR +GLAD_API_CALL PFN_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV glad_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV; +#define vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV glad_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV +GLAD_API_CALL PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR; +#define vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR GLAD_API_CALL PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV; #define vkGetPhysicalDeviceCooperativeMatrixPropertiesNV glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV +GLAD_API_CALL PFN_vkGetPhysicalDeviceCooperativeVectorPropertiesNV glad_vkGetPhysicalDeviceCooperativeVectorPropertiesNV; +#define vkGetPhysicalDeviceCooperativeVectorPropertiesNV glad_vkGetPhysicalDeviceCooperativeVectorPropertiesNV #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) GLAD_API_CALL PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT glad_vkGetPhysicalDeviceDirectFBPresentationSupportEXT; #define vkGetPhysicalDeviceDirectFBPresentationSupportEXT glad_vkGetPhysicalDeviceDirectFBPresentationSupportEXT + #endif GLAD_API_CALL PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR glad_vkGetPhysicalDeviceDisplayPlaneProperties2KHR; #define vkGetPhysicalDeviceDisplayPlaneProperties2KHR glad_vkGetPhysicalDeviceDisplayPlaneProperties2KHR @@ -10646,6 +19033,8 @@ GLAD_API_CALL PFN_vkGetPhysicalDeviceFormatProperties2 glad_vkGetPhysicalDeviceF #define vkGetPhysicalDeviceFormatProperties2 glad_vkGetPhysicalDeviceFormatProperties2 GLAD_API_CALL PFN_vkGetPhysicalDeviceFormatProperties2KHR glad_vkGetPhysicalDeviceFormatProperties2KHR; #define vkGetPhysicalDeviceFormatProperties2KHR glad_vkGetPhysicalDeviceFormatProperties2KHR +GLAD_API_CALL PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR glad_vkGetPhysicalDeviceFragmentShadingRatesKHR; +#define vkGetPhysicalDeviceFragmentShadingRatesKHR glad_vkGetPhysicalDeviceFragmentShadingRatesKHR GLAD_API_CALL PFN_vkGetPhysicalDeviceImageFormatProperties glad_vkGetPhysicalDeviceImageFormatProperties; #define vkGetPhysicalDeviceImageFormatProperties glad_vkGetPhysicalDeviceImageFormatProperties GLAD_API_CALL PFN_vkGetPhysicalDeviceImageFormatProperties2 glad_vkGetPhysicalDeviceImageFormatProperties2; @@ -10660,6 +19049,8 @@ GLAD_API_CALL PFN_vkGetPhysicalDeviceMemoryProperties2KHR glad_vkGetPhysicalDevi #define vkGetPhysicalDeviceMemoryProperties2KHR glad_vkGetPhysicalDeviceMemoryProperties2KHR GLAD_API_CALL PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT glad_vkGetPhysicalDeviceMultisamplePropertiesEXT; #define vkGetPhysicalDeviceMultisamplePropertiesEXT glad_vkGetPhysicalDeviceMultisamplePropertiesEXT +GLAD_API_CALL PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV glad_vkGetPhysicalDeviceOpticalFlowImageFormatsNV; +#define vkGetPhysicalDeviceOpticalFlowImageFormatsNV glad_vkGetPhysicalDeviceOpticalFlowImageFormatsNV GLAD_API_CALL PFN_vkGetPhysicalDevicePresentRectanglesKHR glad_vkGetPhysicalDevicePresentRectanglesKHR; #define vkGetPhysicalDevicePresentRectanglesKHR glad_vkGetPhysicalDevicePresentRectanglesKHR GLAD_API_CALL PFN_vkGetPhysicalDeviceProperties glad_vkGetPhysicalDeviceProperties; @@ -10676,6 +19067,11 @@ GLAD_API_CALL PFN_vkGetPhysicalDeviceQueueFamilyProperties2 glad_vkGetPhysicalDe #define vkGetPhysicalDeviceQueueFamilyProperties2 glad_vkGetPhysicalDeviceQueueFamilyProperties2 GLAD_API_CALL PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR glad_vkGetPhysicalDeviceQueueFamilyProperties2KHR; #define vkGetPhysicalDeviceQueueFamilyProperties2KHR glad_vkGetPhysicalDeviceQueueFamilyProperties2KHR +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +GLAD_API_CALL PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX glad_vkGetPhysicalDeviceScreenPresentationSupportQNX; +#define vkGetPhysicalDeviceScreenPresentationSupportQNX glad_vkGetPhysicalDeviceScreenPresentationSupportQNX + +#endif GLAD_API_CALL PFN_vkGetPhysicalDeviceSparseImageFormatProperties glad_vkGetPhysicalDeviceSparseImageFormatProperties; #define vkGetPhysicalDeviceSparseImageFormatProperties glad_vkGetPhysicalDeviceSparseImageFormatProperties GLAD_API_CALL PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 glad_vkGetPhysicalDeviceSparseImageFormatProperties2; @@ -10697,29 +19093,38 @@ GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfaceFormatsKHR glad_vkGetPhysicalDeviceS #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT glad_vkGetPhysicalDeviceSurfacePresentModes2EXT; #define vkGetPhysicalDeviceSurfacePresentModes2EXT glad_vkGetPhysicalDeviceSurfacePresentModes2EXT + #endif GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfacePresentModesKHR glad_vkGetPhysicalDeviceSurfacePresentModesKHR; #define vkGetPhysicalDeviceSurfacePresentModesKHR glad_vkGetPhysicalDeviceSurfacePresentModesKHR GLAD_API_CALL PFN_vkGetPhysicalDeviceSurfaceSupportKHR glad_vkGetPhysicalDeviceSurfaceSupportKHR; #define vkGetPhysicalDeviceSurfaceSupportKHR glad_vkGetPhysicalDeviceSurfaceSupportKHR +GLAD_API_CALL PFN_vkGetPhysicalDeviceToolProperties glad_vkGetPhysicalDeviceToolProperties; +#define vkGetPhysicalDeviceToolProperties glad_vkGetPhysicalDeviceToolProperties GLAD_API_CALL PFN_vkGetPhysicalDeviceToolPropertiesEXT glad_vkGetPhysicalDeviceToolPropertiesEXT; #define vkGetPhysicalDeviceToolPropertiesEXT glad_vkGetPhysicalDeviceToolPropertiesEXT #if defined(VK_USE_PLATFORM_WAYLAND_KHR) GLAD_API_CALL PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR glad_vkGetPhysicalDeviceWaylandPresentationSupportKHR; #define vkGetPhysicalDeviceWaylandPresentationSupportKHR glad_vkGetPhysicalDeviceWaylandPresentationSupportKHR + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR glad_vkGetPhysicalDeviceWin32PresentationSupportKHR; #define vkGetPhysicalDeviceWin32PresentationSupportKHR glad_vkGetPhysicalDeviceWin32PresentationSupportKHR + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) GLAD_API_CALL PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR glad_vkGetPhysicalDeviceXcbPresentationSupportKHR; #define vkGetPhysicalDeviceXcbPresentationSupportKHR glad_vkGetPhysicalDeviceXcbPresentationSupportKHR + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) GLAD_API_CALL PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR glad_vkGetPhysicalDeviceXlibPresentationSupportKHR; #define vkGetPhysicalDeviceXlibPresentationSupportKHR glad_vkGetPhysicalDeviceXlibPresentationSupportKHR + #endif +GLAD_API_CALL PFN_vkGetPipelineBinaryDataKHR glad_vkGetPipelineBinaryDataKHR; +#define vkGetPipelineBinaryDataKHR glad_vkGetPipelineBinaryDataKHR GLAD_API_CALL PFN_vkGetPipelineCacheData glad_vkGetPipelineCacheData; #define vkGetPipelineCacheData glad_vkGetPipelineCacheData GLAD_API_CALL PFN_vkGetPipelineExecutableInternalRepresentationsKHR glad_vkGetPipelineExecutableInternalRepresentationsKHR; @@ -10728,30 +19133,52 @@ GLAD_API_CALL PFN_vkGetPipelineExecutablePropertiesKHR glad_vkGetPipelineExecuta #define vkGetPipelineExecutablePropertiesKHR glad_vkGetPipelineExecutablePropertiesKHR GLAD_API_CALL PFN_vkGetPipelineExecutableStatisticsKHR glad_vkGetPipelineExecutableStatisticsKHR; #define vkGetPipelineExecutableStatisticsKHR glad_vkGetPipelineExecutableStatisticsKHR +GLAD_API_CALL PFN_vkGetPipelineIndirectDeviceAddressNV glad_vkGetPipelineIndirectDeviceAddressNV; +#define vkGetPipelineIndirectDeviceAddressNV glad_vkGetPipelineIndirectDeviceAddressNV +GLAD_API_CALL PFN_vkGetPipelineIndirectMemoryRequirementsNV glad_vkGetPipelineIndirectMemoryRequirementsNV; +#define vkGetPipelineIndirectMemoryRequirementsNV glad_vkGetPipelineIndirectMemoryRequirementsNV +GLAD_API_CALL PFN_vkGetPipelineKeyKHR glad_vkGetPipelineKeyKHR; +#define vkGetPipelineKeyKHR glad_vkGetPipelineKeyKHR +GLAD_API_CALL PFN_vkGetPipelinePropertiesEXT glad_vkGetPipelinePropertiesEXT; +#define vkGetPipelinePropertiesEXT glad_vkGetPipelinePropertiesEXT +GLAD_API_CALL PFN_vkGetPrivateData glad_vkGetPrivateData; +#define vkGetPrivateData glad_vkGetPrivateData GLAD_API_CALL PFN_vkGetPrivateDataEXT glad_vkGetPrivateDataEXT; #define vkGetPrivateDataEXT glad_vkGetPrivateDataEXT GLAD_API_CALL PFN_vkGetQueryPoolResults glad_vkGetQueryPoolResults; #define vkGetQueryPoolResults glad_vkGetQueryPoolResults +GLAD_API_CALL PFN_vkGetQueueCheckpointData2NV glad_vkGetQueueCheckpointData2NV; +#define vkGetQueueCheckpointData2NV glad_vkGetQueueCheckpointData2NV GLAD_API_CALL PFN_vkGetQueueCheckpointDataNV glad_vkGetQueueCheckpointDataNV; #define vkGetQueueCheckpointDataNV glad_vkGetQueueCheckpointDataNV #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) GLAD_API_CALL PFN_vkGetRandROutputDisplayEXT glad_vkGetRandROutputDisplayEXT; #define vkGetRandROutputDisplayEXT glad_vkGetRandROutputDisplayEXT + #endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR glad_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR; #define vkGetRayTracingCaptureReplayShaderGroupHandlesKHR glad_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkGetRayTracingShaderGroupHandlesKHR glad_vkGetRayTracingShaderGroupHandlesKHR; #define vkGetRayTracingShaderGroupHandlesKHR glad_vkGetRayTracingShaderGroupHandlesKHR -#endif GLAD_API_CALL PFN_vkGetRayTracingShaderGroupHandlesNV glad_vkGetRayTracingShaderGroupHandlesNV; #define vkGetRayTracingShaderGroupHandlesNV glad_vkGetRayTracingShaderGroupHandlesNV +GLAD_API_CALL PFN_vkGetRayTracingShaderGroupStackSizeKHR glad_vkGetRayTracingShaderGroupStackSizeKHR; +#define vkGetRayTracingShaderGroupStackSizeKHR glad_vkGetRayTracingShaderGroupStackSizeKHR GLAD_API_CALL PFN_vkGetRefreshCycleDurationGOOGLE glad_vkGetRefreshCycleDurationGOOGLE; #define vkGetRefreshCycleDurationGOOGLE glad_vkGetRefreshCycleDurationGOOGLE GLAD_API_CALL PFN_vkGetRenderAreaGranularity glad_vkGetRenderAreaGranularity; #define vkGetRenderAreaGranularity glad_vkGetRenderAreaGranularity +GLAD_API_CALL PFN_vkGetRenderingAreaGranularity glad_vkGetRenderingAreaGranularity; +#define vkGetRenderingAreaGranularity glad_vkGetRenderingAreaGranularity +GLAD_API_CALL PFN_vkGetRenderingAreaGranularityKHR glad_vkGetRenderingAreaGranularityKHR; +#define vkGetRenderingAreaGranularityKHR glad_vkGetRenderingAreaGranularityKHR +GLAD_API_CALL PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT glad_vkGetSamplerOpaqueCaptureDescriptorDataEXT; +#define vkGetSamplerOpaqueCaptureDescriptorDataEXT glad_vkGetSamplerOpaqueCaptureDescriptorDataEXT +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +GLAD_API_CALL PFN_vkGetScreenBufferPropertiesQNX glad_vkGetScreenBufferPropertiesQNX; +#define vkGetScreenBufferPropertiesQNX glad_vkGetScreenBufferPropertiesQNX + +#endif GLAD_API_CALL PFN_vkGetSemaphoreCounterValue glad_vkGetSemaphoreCounterValue; #define vkGetSemaphoreCounterValue glad_vkGetSemaphoreCounterValue GLAD_API_CALL PFN_vkGetSemaphoreCounterValueKHR glad_vkGetSemaphoreCounterValueKHR; @@ -10761,9 +19188,21 @@ GLAD_API_CALL PFN_vkGetSemaphoreFdKHR glad_vkGetSemaphoreFdKHR; #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkGetSemaphoreWin32HandleKHR glad_vkGetSemaphoreWin32HandleKHR; #define vkGetSemaphoreWin32HandleKHR glad_vkGetSemaphoreWin32HandleKHR + #endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkGetSemaphoreZirconHandleFUCHSIA glad_vkGetSemaphoreZirconHandleFUCHSIA; +#define vkGetSemaphoreZirconHandleFUCHSIA glad_vkGetSemaphoreZirconHandleFUCHSIA + +#endif +GLAD_API_CALL PFN_vkGetShaderBinaryDataEXT glad_vkGetShaderBinaryDataEXT; +#define vkGetShaderBinaryDataEXT glad_vkGetShaderBinaryDataEXT GLAD_API_CALL PFN_vkGetShaderInfoAMD glad_vkGetShaderInfoAMD; #define vkGetShaderInfoAMD glad_vkGetShaderInfoAMD +GLAD_API_CALL PFN_vkGetShaderModuleCreateInfoIdentifierEXT glad_vkGetShaderModuleCreateInfoIdentifierEXT; +#define vkGetShaderModuleCreateInfoIdentifierEXT glad_vkGetShaderModuleCreateInfoIdentifierEXT +GLAD_API_CALL PFN_vkGetShaderModuleIdentifierEXT glad_vkGetShaderModuleIdentifierEXT; +#define vkGetShaderModuleIdentifierEXT glad_vkGetShaderModuleIdentifierEXT GLAD_API_CALL PFN_vkGetSwapchainCounterEXT glad_vkGetSwapchainCounterEXT; #define vkGetSwapchainCounterEXT glad_vkGetSwapchainCounterEXT GLAD_API_CALL PFN_vkGetSwapchainImagesKHR glad_vkGetSwapchainImagesKHR; @@ -10772,24 +19211,42 @@ GLAD_API_CALL PFN_vkGetSwapchainStatusKHR glad_vkGetSwapchainStatusKHR; #define vkGetSwapchainStatusKHR glad_vkGetSwapchainStatusKHR GLAD_API_CALL PFN_vkGetValidationCacheDataEXT glad_vkGetValidationCacheDataEXT; #define vkGetValidationCacheDataEXT glad_vkGetValidationCacheDataEXT +#if defined(VK_USE_PLATFORM_WIN32_KHR) +GLAD_API_CALL PFN_vkGetWinrtDisplayNV glad_vkGetWinrtDisplayNV; +#define vkGetWinrtDisplayNV glad_vkGetWinrtDisplayNV + +#endif GLAD_API_CALL PFN_vkImportFenceFdKHR glad_vkImportFenceFdKHR; #define vkImportFenceFdKHR glad_vkImportFenceFdKHR #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkImportFenceWin32HandleKHR glad_vkImportFenceWin32HandleKHR; #define vkImportFenceWin32HandleKHR glad_vkImportFenceWin32HandleKHR + #endif GLAD_API_CALL PFN_vkImportSemaphoreFdKHR glad_vkImportSemaphoreFdKHR; #define vkImportSemaphoreFdKHR glad_vkImportSemaphoreFdKHR #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkImportSemaphoreWin32HandleKHR glad_vkImportSemaphoreWin32HandleKHR; #define vkImportSemaphoreWin32HandleKHR glad_vkImportSemaphoreWin32HandleKHR + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkImportSemaphoreZirconHandleFUCHSIA glad_vkImportSemaphoreZirconHandleFUCHSIA; +#define vkImportSemaphoreZirconHandleFUCHSIA glad_vkImportSemaphoreZirconHandleFUCHSIA + #endif GLAD_API_CALL PFN_vkInitializePerformanceApiINTEL glad_vkInitializePerformanceApiINTEL; #define vkInitializePerformanceApiINTEL glad_vkInitializePerformanceApiINTEL GLAD_API_CALL PFN_vkInvalidateMappedMemoryRanges glad_vkInvalidateMappedMemoryRanges; #define vkInvalidateMappedMemoryRanges glad_vkInvalidateMappedMemoryRanges +GLAD_API_CALL PFN_vkLatencySleepNV glad_vkLatencySleepNV; +#define vkLatencySleepNV glad_vkLatencySleepNV GLAD_API_CALL PFN_vkMapMemory glad_vkMapMemory; #define vkMapMemory glad_vkMapMemory +GLAD_API_CALL PFN_vkMapMemory2 glad_vkMapMemory2; +#define vkMapMemory2 glad_vkMapMemory2 +GLAD_API_CALL PFN_vkMapMemory2KHR glad_vkMapMemory2KHR; +#define vkMapMemory2KHR glad_vkMapMemory2KHR GLAD_API_CALL PFN_vkMergePipelineCaches glad_vkMergePipelineCaches; #define vkMergePipelineCaches glad_vkMergePipelineCaches GLAD_API_CALL PFN_vkMergeValidationCachesEXT glad_vkMergeValidationCachesEXT; @@ -10802,28 +19259,39 @@ GLAD_API_CALL PFN_vkQueueEndDebugUtilsLabelEXT glad_vkQueueEndDebugUtilsLabelEXT #define vkQueueEndDebugUtilsLabelEXT glad_vkQueueEndDebugUtilsLabelEXT GLAD_API_CALL PFN_vkQueueInsertDebugUtilsLabelEXT glad_vkQueueInsertDebugUtilsLabelEXT; #define vkQueueInsertDebugUtilsLabelEXT glad_vkQueueInsertDebugUtilsLabelEXT +GLAD_API_CALL PFN_vkQueueNotifyOutOfBandNV glad_vkQueueNotifyOutOfBandNV; +#define vkQueueNotifyOutOfBandNV glad_vkQueueNotifyOutOfBandNV GLAD_API_CALL PFN_vkQueuePresentKHR glad_vkQueuePresentKHR; #define vkQueuePresentKHR glad_vkQueuePresentKHR GLAD_API_CALL PFN_vkQueueSetPerformanceConfigurationINTEL glad_vkQueueSetPerformanceConfigurationINTEL; #define vkQueueSetPerformanceConfigurationINTEL glad_vkQueueSetPerformanceConfigurationINTEL GLAD_API_CALL PFN_vkQueueSubmit glad_vkQueueSubmit; #define vkQueueSubmit glad_vkQueueSubmit +GLAD_API_CALL PFN_vkQueueSubmit2 glad_vkQueueSubmit2; +#define vkQueueSubmit2 glad_vkQueueSubmit2 +GLAD_API_CALL PFN_vkQueueSubmit2KHR glad_vkQueueSubmit2KHR; +#define vkQueueSubmit2KHR glad_vkQueueSubmit2KHR GLAD_API_CALL PFN_vkQueueWaitIdle glad_vkQueueWaitIdle; #define vkQueueWaitIdle glad_vkQueueWaitIdle GLAD_API_CALL PFN_vkRegisterDeviceEventEXT glad_vkRegisterDeviceEventEXT; #define vkRegisterDeviceEventEXT glad_vkRegisterDeviceEventEXT GLAD_API_CALL PFN_vkRegisterDisplayEventEXT glad_vkRegisterDisplayEventEXT; #define vkRegisterDisplayEventEXT glad_vkRegisterDisplayEventEXT +GLAD_API_CALL PFN_vkReleaseCapturedPipelineDataKHR glad_vkReleaseCapturedPipelineDataKHR; +#define vkReleaseCapturedPipelineDataKHR glad_vkReleaseCapturedPipelineDataKHR GLAD_API_CALL PFN_vkReleaseDisplayEXT glad_vkReleaseDisplayEXT; #define vkReleaseDisplayEXT glad_vkReleaseDisplayEXT #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_API_CALL PFN_vkReleaseFullScreenExclusiveModeEXT glad_vkReleaseFullScreenExclusiveModeEXT; #define vkReleaseFullScreenExclusiveModeEXT glad_vkReleaseFullScreenExclusiveModeEXT + #endif GLAD_API_CALL PFN_vkReleasePerformanceConfigurationINTEL glad_vkReleasePerformanceConfigurationINTEL; #define vkReleasePerformanceConfigurationINTEL glad_vkReleasePerformanceConfigurationINTEL GLAD_API_CALL PFN_vkReleaseProfilingLockKHR glad_vkReleaseProfilingLockKHR; #define vkReleaseProfilingLockKHR glad_vkReleaseProfilingLockKHR +GLAD_API_CALL PFN_vkReleaseSwapchainImagesEXT glad_vkReleaseSwapchainImagesEXT; +#define vkReleaseSwapchainImagesEXT glad_vkReleaseSwapchainImagesEXT GLAD_API_CALL PFN_vkResetCommandBuffer glad_vkResetCommandBuffer; #define vkResetCommandBuffer glad_vkResetCommandBuffer GLAD_API_CALL PFN_vkResetCommandPool glad_vkResetCommandPool; @@ -10838,16 +19306,34 @@ GLAD_API_CALL PFN_vkResetQueryPool glad_vkResetQueryPool; #define vkResetQueryPool glad_vkResetQueryPool GLAD_API_CALL PFN_vkResetQueryPoolEXT glad_vkResetQueryPoolEXT; #define vkResetQueryPoolEXT glad_vkResetQueryPoolEXT +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA glad_vkSetBufferCollectionBufferConstraintsFUCHSIA; +#define vkSetBufferCollectionBufferConstraintsFUCHSIA glad_vkSetBufferCollectionBufferConstraintsFUCHSIA + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +GLAD_API_CALL PFN_vkSetBufferCollectionImageConstraintsFUCHSIA glad_vkSetBufferCollectionImageConstraintsFUCHSIA; +#define vkSetBufferCollectionImageConstraintsFUCHSIA glad_vkSetBufferCollectionImageConstraintsFUCHSIA + +#endif GLAD_API_CALL PFN_vkSetDebugUtilsObjectNameEXT glad_vkSetDebugUtilsObjectNameEXT; #define vkSetDebugUtilsObjectNameEXT glad_vkSetDebugUtilsObjectNameEXT GLAD_API_CALL PFN_vkSetDebugUtilsObjectTagEXT glad_vkSetDebugUtilsObjectTagEXT; #define vkSetDebugUtilsObjectTagEXT glad_vkSetDebugUtilsObjectTagEXT +GLAD_API_CALL PFN_vkSetDeviceMemoryPriorityEXT glad_vkSetDeviceMemoryPriorityEXT; +#define vkSetDeviceMemoryPriorityEXT glad_vkSetDeviceMemoryPriorityEXT GLAD_API_CALL PFN_vkSetEvent glad_vkSetEvent; #define vkSetEvent glad_vkSetEvent GLAD_API_CALL PFN_vkSetHdrMetadataEXT glad_vkSetHdrMetadataEXT; #define vkSetHdrMetadataEXT glad_vkSetHdrMetadataEXT +GLAD_API_CALL PFN_vkSetLatencyMarkerNV glad_vkSetLatencyMarkerNV; +#define vkSetLatencyMarkerNV glad_vkSetLatencyMarkerNV +GLAD_API_CALL PFN_vkSetLatencySleepModeNV glad_vkSetLatencySleepModeNV; +#define vkSetLatencySleepModeNV glad_vkSetLatencySleepModeNV GLAD_API_CALL PFN_vkSetLocalDimmingAMD glad_vkSetLocalDimmingAMD; #define vkSetLocalDimmingAMD glad_vkSetLocalDimmingAMD +GLAD_API_CALL PFN_vkSetPrivateData glad_vkSetPrivateData; +#define vkSetPrivateData glad_vkSetPrivateData GLAD_API_CALL PFN_vkSetPrivateDataEXT glad_vkSetPrivateDataEXT; #define vkSetPrivateDataEXT glad_vkSetPrivateDataEXT GLAD_API_CALL PFN_vkSignalSemaphore glad_vkSignalSemaphore; @@ -10856,6 +19342,10 @@ GLAD_API_CALL PFN_vkSignalSemaphoreKHR glad_vkSignalSemaphoreKHR; #define vkSignalSemaphoreKHR glad_vkSignalSemaphoreKHR GLAD_API_CALL PFN_vkSubmitDebugUtilsMessageEXT glad_vkSubmitDebugUtilsMessageEXT; #define vkSubmitDebugUtilsMessageEXT glad_vkSubmitDebugUtilsMessageEXT +GLAD_API_CALL PFN_vkTransitionImageLayout glad_vkTransitionImageLayout; +#define vkTransitionImageLayout glad_vkTransitionImageLayout +GLAD_API_CALL PFN_vkTransitionImageLayoutEXT glad_vkTransitionImageLayoutEXT; +#define vkTransitionImageLayoutEXT glad_vkTransitionImageLayoutEXT GLAD_API_CALL PFN_vkTrimCommandPool glad_vkTrimCommandPool; #define vkTrimCommandPool glad_vkTrimCommandPool GLAD_API_CALL PFN_vkTrimCommandPoolKHR glad_vkTrimCommandPoolKHR; @@ -10864,22 +19354,32 @@ GLAD_API_CALL PFN_vkUninitializePerformanceApiINTEL glad_vkUninitializePerforman #define vkUninitializePerformanceApiINTEL glad_vkUninitializePerformanceApiINTEL GLAD_API_CALL PFN_vkUnmapMemory glad_vkUnmapMemory; #define vkUnmapMemory glad_vkUnmapMemory +GLAD_API_CALL PFN_vkUnmapMemory2 glad_vkUnmapMemory2; +#define vkUnmapMemory2 glad_vkUnmapMemory2 +GLAD_API_CALL PFN_vkUnmapMemory2KHR glad_vkUnmapMemory2KHR; +#define vkUnmapMemory2KHR glad_vkUnmapMemory2KHR GLAD_API_CALL PFN_vkUpdateDescriptorSetWithTemplate glad_vkUpdateDescriptorSetWithTemplate; #define vkUpdateDescriptorSetWithTemplate glad_vkUpdateDescriptorSetWithTemplate GLAD_API_CALL PFN_vkUpdateDescriptorSetWithTemplateKHR glad_vkUpdateDescriptorSetWithTemplateKHR; #define vkUpdateDescriptorSetWithTemplateKHR glad_vkUpdateDescriptorSetWithTemplateKHR GLAD_API_CALL PFN_vkUpdateDescriptorSets glad_vkUpdateDescriptorSets; #define vkUpdateDescriptorSets glad_vkUpdateDescriptorSets +GLAD_API_CALL PFN_vkUpdateIndirectExecutionSetPipelineEXT glad_vkUpdateIndirectExecutionSetPipelineEXT; +#define vkUpdateIndirectExecutionSetPipelineEXT glad_vkUpdateIndirectExecutionSetPipelineEXT +GLAD_API_CALL PFN_vkUpdateIndirectExecutionSetShaderEXT glad_vkUpdateIndirectExecutionSetShaderEXT; +#define vkUpdateIndirectExecutionSetShaderEXT glad_vkUpdateIndirectExecutionSetShaderEXT GLAD_API_CALL PFN_vkWaitForFences glad_vkWaitForFences; #define vkWaitForFences glad_vkWaitForFences +GLAD_API_CALL PFN_vkWaitForPresentKHR glad_vkWaitForPresentKHR; +#define vkWaitForPresentKHR glad_vkWaitForPresentKHR GLAD_API_CALL PFN_vkWaitSemaphores glad_vkWaitSemaphores; #define vkWaitSemaphores glad_vkWaitSemaphores GLAD_API_CALL PFN_vkWaitSemaphoresKHR glad_vkWaitSemaphoresKHR; #define vkWaitSemaphoresKHR glad_vkWaitSemaphoresKHR -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_API_CALL PFN_vkWriteAccelerationStructuresPropertiesKHR glad_vkWriteAccelerationStructuresPropertiesKHR; #define vkWriteAccelerationStructuresPropertiesKHR glad_vkWriteAccelerationStructuresPropertiesKHR -#endif +GLAD_API_CALL PFN_vkWriteMicromapsPropertiesEXT glad_vkWriteMicromapsPropertiesEXT; +#define vkWriteMicromapsPropertiesEXT glad_vkWriteMicromapsPropertiesEXT diff --git a/lib/graphics_engine/include/mvk_config.h b/lib/graphics_engine/include/mvk_config.h deleted file mode 100644 index 69c916d1679..00000000000 --- a/lib/graphics_engine/include/mvk_config.h +++ /dev/null @@ -1,1059 +0,0 @@ -/* - * mvk_config.h - * - * Copyright (c) 2015-2023 The Brenwill Workshop Ltd. (http://www.brenwill.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - - -#ifndef __mvk_config_h_ -#define __mvk_config_h_ 1 - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - - -/** This header contains the public configuration API for MoltenVK. */ - - -/** - * The version number of MoltenVK is a single integer value, derived from the Major, Minor, - * and Patch version values, where each of the Major, Minor, and Patch components is allocated - * two decimal digits, in the format MjMnPt. This creates a version number that is both human - * readable and allows efficient computational comparisons to a single integer number. - * - * The following examples illustrate how the MoltenVK version number is built from its components: - * - 002000 (version 0.20.0) - * - 010000 (version 1.0.0) - * - 030104 (version 3.1.4) - * - 401215 (version 4.12.15) - */ -#define MVK_VERSION_MAJOR 1 -#define MVK_VERSION_MINOR 2 -#define MVK_VERSION_PATCH 4 - -#define MVK_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch)) -#define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH) - - -#define MVK_CONFIGURATION_API_VERSION 37 - -/** Identifies the level of logging MoltenVK should be limited to outputting. */ -typedef enum MVKConfigLogLevel { - MVK_CONFIG_LOG_LEVEL_NONE = 0, /**< No logging. */ - MVK_CONFIG_LOG_LEVEL_ERROR = 1, /**< Log errors only. */ - MVK_CONFIG_LOG_LEVEL_WARNING = 2, /**< Log errors and warning messages. */ - MVK_CONFIG_LOG_LEVEL_INFO = 3, /**< Log errors, warnings and informational messages. */ - MVK_CONFIG_LOG_LEVEL_DEBUG = 4, /**< Log errors, warnings, infos and debug messages. */ - MVK_CONFIG_LOG_LEVEL_MAX_ENUM = 0x7FFFFFFF -} MVKConfigLogLevel; - -/** Identifies the level of Vulkan call trace logging MoltenVK should perform. */ -typedef enum MVKConfigTraceVulkanCalls { - MVK_CONFIG_TRACE_VULKAN_CALLS_NONE = 0, /**< No Vulkan call logging. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER = 1, /**< Log the name of each Vulkan call when the call is entered. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_THREAD_ID = 2, /**< Log the name and thread ID of each Vulkan call when the call is entered. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT = 3, /**< Log the name of each Vulkan call when the call is entered and exited. This effectively brackets any other logging activity within the scope of the Vulkan call. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT_THREAD_ID = 4, /**< Log the name and thread ID of each Vulkan call when the call is entered and name when exited. This effectively brackets any other logging activity within the scope of the Vulkan call. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_DURATION = 5, /**< Same as MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT, plus logs the time spent inside the Vulkan function. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_DURATION_THREAD_ID = 6, /**< Same as MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT_THREAD_ID, plus logs the time spent inside the Vulkan function. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_MAX_ENUM = 0x7FFFFFFF -} MVKConfigTraceVulkanCalls; - -/** Identifies the scope for Metal to run an automatic GPU capture for diagnostic debugging purposes. */ -typedef enum MVKConfigAutoGPUCaptureScope { - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_NONE = 0, /**< No automatic GPU capture. */ - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE = 1, /**< Automatically capture all GPU activity during the lifetime of a VkDevice. */ - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME = 2, /**< Automatically capture all GPU activity during the rendering and presentation of the first frame. */ - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_MAX_ENUM = 0x7FFFFFFF -} MVKConfigAutoGPUCaptureScope; - -/** Identifies extensions to advertise as part of MoltenVK configuration. */ -typedef enum MVKConfigAdvertiseExtensionBits { - MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL = 0x00000001, /**< All supported extensions. */ - MVK_CONFIG_ADVERTISE_EXTENSIONS_WSI = 0x00000002, /**< WSI extensions supported on the platform. */ - MVK_CONFIG_ADVERTISE_EXTENSIONS_PORTABILITY = 0x00000004, /**< Vulkan Portability Subset extensions. */ - MVK_CONFIG_ADVERTISE_EXTENSIONS_MAX_ENUM = 0x7FFFFFFF -} MVKConfigAdvertiseExtensionBits; -typedef VkFlags MVKConfigAdvertiseExtensions; - -/** Identifies the use of Metal Argument Buffers. */ -typedef enum MVKUseMetalArgumentBuffers { - MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER = 0, /**< Don't use Metal Argument Buffers. */ - MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_ALWAYS = 1, /**< Use Metal Argument Buffers for all pipelines. */ - MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_DESCRIPTOR_INDEXING = 2, /**< Use Metal Argument Buffers only if VK_EXT_descriptor_indexing extension is enabled. */ - MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_MAX_ENUM = 0x7FFFFFFF -} MVKUseMetalArgumentBuffers; - -/** Identifies the Metal functionality used to support Vulkan semaphore functionality (VkSemaphore). */ -typedef enum MVKVkSemaphoreSupportStyle { - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE = 0, /**< Limit Vulkan to a single queue, with no explicit semaphore synchronization, and use Metal's implicit guarantees that all operations submitted to a queue will give the same result as if they had been run in submission order. */ - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE = 1, /**< Use Metal events (MTLEvent) when available on the platform, and where safe. This will revert to same as MVK_CONFIG_VK_SEMAPHORE_USE_SINGLE_QUEUE on some NVIDIA GPUs and Rosetta2, due to potential challenges with MTLEvents on those platforms, or in older environments where MTLEvents are not supported. */ - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS = 2, /**< Always use Metal events (MTLEvent) when available on the platform. This will revert to same as MVK_CONFIG_VK_SEMAPHORE_USE_SINGLE_QUEUE in older environments where MTLEvents are not supported. */ - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK = 3, /**< Use CPU callbacks upon GPU submission completion. This is the slowest technique, but allows multiple queues, compared to MVK_CONFIG_VK_SEMAPHORE_USE_SINGLE_QUEUE. */ - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_MAX_ENUM = 0x7FFFFFFF -} MVKVkSemaphoreSupportStyle; - -/** Identifies the style of Metal command buffer pre-filling to be used. */ -typedef enum MVKPrefillMetalCommandBuffersStyle { - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL = 0, /**< During Vulkan command buffer filling, do not prefill a Metal command buffer for each Vulkan command buffer. A single Metal command buffer is created and encoded for all the Vulkan command buffers included when vkQueueSubmit() is called. MoltenVK automatically creates and drains a single Metal object autorelease pool when vkQueueSubmit() is called. This is the fastest option, but potentially has the largest memory footprint. */ - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_DEFERRED_ENCODING = 1, /**< During Vulkan command buffer filling, encode to the Metal command buffer when vkEndCommandBuffer() is called. MoltenVK automatically creates and drains a single Metal object autorelease pool when vkEndCommandBuffer() is called. This option has the fastest performance, and the largest memory footprint, of the prefilling options using autorelease pools. */ - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_IMMEDIATE_ENCODING = 2, /**< During Vulkan command buffer filling, immediately encode to the Metal command buffer, as each command is submitted to the Vulkan command buffer, and do not retain any command content in the Vulkan command buffer. MoltenVK automatically creates and drains a Metal object autorelease pool for each and every command added to the Vulkan command buffer. This option has the smallest memory footprint, and the slowest performance, of the prefilling options using autorelease pools. */ - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_IMMEDIATE_ENCODING_NO_AUTORELEASE = 3, /**< During Vulkan command buffer filling, immediately encode to the Metal command buffer, as each command is submitted to the Vulkan command buffer, do not retain any command content in the Vulkan command buffer, and assume the app will ensure that each thread that fills commands into a Vulkan command buffer has a Metal autorelease pool. MoltenVK will not create and drain any autorelease pools during encoding. This is the fastest prefilling option, and generally has a small memory footprint, depending on when the app-provided autorelease pool drains. */ - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_MAX_ENUM = 0x7FFFFFFF -} MVKPrefillMetalCommandBuffersStyle; - -/** Identifies when Metal shaders will be compiled with the fast math option. */ -typedef enum MVKConfigFastMath { - MVK_CONFIG_FAST_MATH_NEVER = 0, /**< Metal shaders will never be compiled with the fast math option. */ - MVK_CONFIG_FAST_MATH_ALWAYS = 1, /**< Metal shaders will always be compiled with the fast math option. */ - MVK_CONFIG_FAST_MATH_ON_DEMAND = 2, /**< Metal shaders will be compiled with the fast math option, unless the shader includes execution modes that require it to be compiled without fast math. */ - MVK_CONFIG_FAST_MATH_MAX_ENUM = 0x7FFFFFFF -} MVKConfigFastMath; - -/** Identifies available system data compression algorithms. */ -typedef enum MVKConfigCompressionAlgorithm { - MVK_CONFIG_COMPRESSION_ALGORITHM_NONE = 0, /**< No compression. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_LZFSE = 1, /**< Apple proprietary. Good balance of high performance and small compression size, particularly for larger data content. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_ZLIB = 2, /**< Open cross-platform ZLib format. For smaller data content, has better performance and smaller size than LZFSE. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_LZ4 = 3, /**< Fastest performance. Largest compression size. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_LZMA = 4, /**< Slowest performance. Smallest compression size, particular with larger content. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_MAX_ENUM = 0x7FFFFFFF, -} MVKConfigCompressionAlgorithm; - -/** Identifies the style of activity performance logging to use. */ -typedef enum MVKConfigActivityPerformanceLoggingStyle { - MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_FRAME_COUNT = 0, /**< Repeatedly log performance after a configured number of frames. */ - MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_IMMEDIATE = 1, /**< Log immediately after each performance measurement. */ - MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_DEVICE_LIFETIME = 2, /**< Log at the end of the VkDevice lifetime. This is useful for one-shot apps such as testing frameworks. */ - MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_MAX_ENUM = 0x7FFFFFFF, -} MVKConfigActivityPerformanceLoggingStyle; - -/** - * MoltenVK configuration settings. - * - * To be active, some configuration settings must be set before a VkDevice is created. - * See the description of the individual configuration structure members for more information. - * - * There are three mechanisms for setting the values of the MoltenVK configuration parameters: - * - Runtime API via the vkGetMoltenVKConfigurationMVK()/vkSetMoltenVKConfigurationMVK() functions. - * - Application runtime environment variables. - * - Build settings at MoltenVK build time. - * - * To change the MoltenVK configuration settings at runtime using a programmatic API, - * use the vkGetMoltenVKConfigurationMVK() and vkSetMoltenVKConfigurationMVK() functions - * to retrieve, modify, and set a copy of the MVKConfiguration structure. To be active, - * some configuration settings must be set before a VkInstance or VkDevice is created. - * See the description of each member for more information. - * - * The initial value of each of the configuration settings can established at runtime - * by a corresponding environment variable, or if the environment variable is not set, - * by a corresponding build setting at the time MoltenVK is compiled. The environment - * variable and build setting for each configuration parameter share the same name. - * - * For example, the initial value of the shaderConversionFlipVertexY configuration setting - * is set by the MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y at runtime, or by the - * MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y build setting when MoltenVK is compiled. - * - * This structure may be extended as new features are added to MoltenVK. If you are linking to - * an implementation of MoltenVK that was compiled from a different MVK_CONFIGURATION_API_VERSION - * than your app was, the size of this structure in your app may be larger or smaller than the - * struct in MoltenVK. See the description of the vkGetMoltenVKConfigurationMVK() and - * vkSetMoltenVKConfigurationMVK() functions for information about how to handle this. - * - * TO SUPPORT DYNAMIC LINKING TO THIS STRUCTURE AS DESCRIBED ABOVE, THIS STRUCTURE SHOULD NOT - * BE CHANGED EXCEPT TO ADD ADDITIONAL MEMBERS ON THE END. EXISTING MEMBERS, AND THEIR ORDER, - * SHOULD NOT BE CHANGED. - */ -typedef struct { - - /** - * If enabled, debugging capabilities will be enabled, including logging - * shader code during runtime shader conversion. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_DEBUG - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter is false if MoltenVK was - * built in Release mode, and true if MoltenVK was built in Debug mode. - */ - VkBool32 debugMode; - - /** - * If enabled, MSL vertex shader code created during runtime shader conversion will - * flip the Y-axis of each vertex, as the Vulkan Y-axis is the inverse of OpenGL. - * - * An alternate way to reverse the Y-axis is to employ a negative Y-axis value on - * the viewport, in which case this parameter can be disabled. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * Specifically, this parameter can be enabled when compiling some pipelines, - * and disabled when compiling others. Existing pipelines are not automatically - * re-compiled when this parameter is changed. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true. - */ - VkBool32 shaderConversionFlipVertexY; - - /** - * If enabled, queue command submissions (vkQueueSubmit() & vkQueuePresentKHR()) will be - * processed on the thread that called the submission function. If disabled, processing - * will be dispatched to a GCD dispatch_queue whose priority is determined by - * VkDeviceQueueCreateInfo::pQueuePriorities during vkCreateDevice(). - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true for macOS 10.14 - * and above or iOS 12 and above, and false otherwise. The reason for this distinction - * is that this feature should be disabled when emulation is required to support VkEvents - * because native support for events (MTLEvent) is not available. - */ - VkBool32 synchronousQueueSubmits; - - /** - * If set to MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL, a single Metal - * command buffer will be created and filled when the Vulkan command buffers are submitted - * to the Vulkan queue. This allows a single Metal command buffer to be used for all of the - * Vulkan command buffers in a queue submission. The Metal command buffer is filled on the - * thread that processes the command queue submission. - * - * If set to any value other than MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL, - * where possible, a Metal command buffer will be created and filled when each Vulkan - * command buffer is filled. For applications that parallelize the filling of Vulkan - * commmand buffers across multiple threads, this allows the Metal command buffers to also - * be filled on the same parallel thread. Because each command buffer is filled separately, - * this requires that each Vulkan command buffer have a dedicated Metal command buffer. - * - * See the definition of the MVKPrefillMetalCommandBuffersStyle enumeration above for - * descriptions of the various values that can be used for this setting. The differences - * are primarily distinguished by how memory recovery is handled for autoreleased Metal - * objects that are created under the covers as the commands added to the Vulkan command - * buffer are encoded into the corresponding Metal command buffer. You can decide whether - * your app will recover all autoreleased Metal objects, or how agressively MoltenVK should - * recover autoreleased Metal objects, based on your approach to command buffer filling. - * - * Depending on the nature of your application, you may find performance is improved by filling - * the Metal command buffers on parallel threads, or you may find that performance is improved by - * consolidating all Vulkan command buffers onto a single Metal command buffer during queue submission. - * - * When enabling this feature, be aware that one Metal command buffer is required for each Vulkan - * command buffer. Depending on the number of command buffers that you use, you may also need to - * change the value of the maxActiveMetalCommandBuffersPerQueue setting. - * - * If this feature is enabled, be aware that if you have recorded commands to a Vulkan command buffer, - * and then choose to reset that command buffer instead of submitting it, the corresponding prefilled - * Metal command buffer will still be submitted. This is because Metal command buffers do not support - * the concept of being reset after being filled. Depending on when and how often you do this, - * it may cause unexpected visual artifacts and unnecessary GPU load. - * - * Prefilling of a Metal command buffer will not occur during the filling of secondary command - * buffers (VK_COMMAND_BUFFER_LEVEL_SECONDARY), or for primary command buffers that are intended - * to be submitted to multiple queues concurrently (VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT). - * - * This feature is incompatible with updating descriptors after binding. If any of the - * *UpdateAfterBind feature flags of VkPhysicalDeviceDescriptorIndexingFeatures or - * VkPhysicalDeviceInlineUniformBlockFeatures have been enabled, the value of this - * setting will be ignored and treated as if it is false. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * Specifically, this parameter can be enabled when filling some command buffers, - * and disabled when later filling others. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to - * MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL. - */ - MVKPrefillMetalCommandBuffersStyle prefillMetalCommandBuffers; - - /** - * The maximum number of Metal command buffers that can be concurrently active per Vulkan queue. - * The number of active Metal command buffers required depends on the prefillMetalCommandBuffers - * setting. If prefillMetalCommandBuffers is enabled, one Metal command buffer is required per - * Vulkan command buffer. If prefillMetalCommandBuffers is disabled, one Metal command buffer - * is required per command buffer queue submission, which may be significantly less than the - * number of Vulkan command buffers. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to 64. - */ - uint32_t maxActiveMetalCommandBuffersPerQueue; - - /** - * Depending on the GPU, Metal allows 8192 or 32768 occlusion queries per MTLBuffer. - * If enabled, MoltenVK allocates a MTLBuffer for each query pool, allowing each query - * pool to support that permitted number of queries. This may slow performance or cause - * unexpected behaviour if the query pool is not established prior to a Metal renderpass, - * or if the query pool is changed within a renderpass. If disabled, one MTLBuffer will - * be shared by all query pools, which improves performance, but limits the total device - * queries to the permitted number. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * Specifically, this parameter can be enabled when creating some query pools, - * and disabled when creating others. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true. - */ - VkBool32 supportLargeQueryPools; - - /** Obsolete, ignored, and deprecated. All surface presentations are performed with a command buffer. */ - VkBool32 presentWithCommandBuffer; - - /** - * If enabled, swapchain images will use simple Nearest sampling when minifying or magnifying - * the swapchain image to fit a physical display surface. If disabled, swapchain images will - * use Linear sampling when magnifying the swapchain image to fit a physical display surface. - * Enabling this setting avoids smearing effects when swapchain images are simple interger - * multiples of display pixels (eg- macOS Retina, and typical of graphics apps and games), - * but may cause aliasing effects when using non-integer display scaling. - * - * The value of this parameter must be changed before creating a VkSwapchain, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SWAPCHAIN_MIN_MAG_FILTER_USE_NEAREST - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true. - */ - VkBool32 swapchainMinMagFilterUseNearest; -#define swapchainMagFilterUseNearest swapchainMinMagFilterUseNearest - - /** - * The maximum amount of time, in nanoseconds, to wait for a Metal library, function, or - * pipeline state object to be compiled and created by the Metal compiler. An internal error - * within the Metal compiler can stall the thread for up to 30 seconds. Setting this value - * limits that delay to a specified amount of time, allowing shader compilations to fail fast. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_METAL_COMPILE_TIMEOUT - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to infinite. - */ - uint64_t metalCompileTimeout; - - /** - * If enabled, performance statistics, as defined by the MVKPerformanceStatistics structure, - * are collected, and can be retrieved via the vkGetPerformanceStatisticsMVK() function. - * - * You can also use the activityPerformanceLoggingStyle and performanceLoggingFrameCount - * parameters to configure when to log the performance statistics collected by this parameter. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_PERFORMANCE_TRACKING - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to false. - */ - VkBool32 performanceTracking; - - /** - * If non-zero, performance statistics, frame-based statistics will be logged, on a - * repeating cycle, once per this many frames. The performanceTracking parameter must - * also be enabled. If this parameter is zero, or the performanceTracking parameter - * is disabled, no frame-based performance statistics will be logged. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to zero. - */ - uint32_t performanceLoggingFrameCount; - - /** - * If enabled, a MoltenVK logo watermark will be rendered on top of the scene. - * This can be enabled for publicity during demos. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_DISPLAY_WATERMARK - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to false. - */ - VkBool32 displayWatermark; - - /** - * Metal does not distinguish functionality between queues, which would normally mean only - * a single general-purpose queue family with multiple queues is needed. However, Vulkan - * associates command buffers with a queue family, whereas Metal associates command buffers - * with a specific Metal queue. In order to allow a Metal command buffer to be prefilled - * before is is formally submitted to a Vulkan queue, each Vulkan queue family can support - * only a single Metal queue. As a result, in order to provide parallel queue operations, - * MoltenVK provides multiple queue families, each with a single queue. - * - * If this parameter is disabled, all queue families will be advertised as having general-purpose - * graphics + compute + transfer functionality, which is how the actual Metal queues behave. - * - * If this parameter is enabled, one queue family will be advertised as having general-purpose - * graphics + compute + transfer functionality, and the remaining queue families will be advertised - * as having specialized graphics OR compute OR transfer functionality, to make it easier for some - * apps to select a queue family with the appropriate requirements. - * - * The value of this parameter must be changed before creating a VkDevice, and before - * querying a VkPhysicalDevice for queue family properties, for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to false. - */ - VkBool32 specializedQueueFamilies; - - /** - * If enabled, when the app creates a VkDevice from a VkPhysicalDevice (GPU) that is neither - * headless nor low-power, and is different than the GPU used by the windowing system, the - * windowing system will be forced to switch to use the GPU selected by the Vulkan app. - * When the Vulkan app is ended, the windowing system will automatically switch back to - * using the previous GPU, depending on the usage requirements of other running apps. - * - * If disabled, the Vulkan app will render using its selected GPU, and if the windowing - * system uses a different GPU, the windowing system compositor will automatically copy - * framebuffer content from the app GPU to the windowing system GPU. - * - * The value of this parmeter has no effect on systems with a single GPU, or when the - * Vulkan app creates a VkDevice from a low-power or headless VkPhysicalDevice (GPU). - * - * Switching the windowing system GPU to match the Vulkan app GPU maximizes app performance, - * because it avoids the windowing system compositor from having to copy framebuffer content - * between GPUs on each rendered frame. However, doing so forces the entire system to - * potentially switch to using a GPU that may consume more power while the app is running. - * - * Some Vulkan apps may want to render using a high-power GPU, but leave it up to the - * system window compositor to determine how best to blend content with the windowing - * system, and as a result, may want to disable this parameter. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SWITCH_SYSTEM_GPU - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true. - */ - VkBool32 switchSystemGPU; - - /** - * Older versions of Metal do not natively support per-texture swizzling. When running on - * such a system, and this parameter is enabled, arbitrary VkImageView component swizzles - * are supported, as defined in VkImageViewCreateInfo::components when creating a VkImageView. - * - * If disabled, and native Metal per-texture swizzling is not available on the platform, - * a very limited set of VkImageView component swizzles are supported via format substitutions. - * - * If Metal supports native per-texture swizzling, this parameter is ignored. - * - * When running on an older version of Metal that does not support native per-texture - * swizzling, if this parameter is enabled, both when a VkImageView is created, and - * when any pipeline that uses that VkImageView is compiled, VkImageView swizzling is - * automatically performed in the converted Metal shader code during all texture sampling - * and reading operations, regardless of whether a swizzle is required for the VkImageView - * associated with the Metal texture. This may result in reduced performance. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * Specifically, this parameter can be enabled when creating VkImageViews that need it, - * and compiling pipelines that use those VkImageViews, and can be disabled when creating - * VkImageViews that don't need it, and compiling pipelines that use those VkImageViews. - * - * Existing pipelines are not automatically re-compiled when this parameter is changed. - * - * An error is logged and returned during VkImageView creation if that VkImageView - * requires full image view swizzling and this feature is not enabled. An error is - * also logged when a pipeline that was not compiled with full image view swizzling - * is presented with a VkImageView that is expecting it. - * - * An error is also retuned and logged when a VkPhysicalDeviceImageFormatInfo2KHR is passed - * in a call to vkGetPhysicalDeviceImageFormatProperties2KHR() to query for an VkImageView - * format that will require full swizzling to be enabled, and this feature is not enabled. - * - * If this parameter is disabled, and native Metal per-texture swizzling is not available - * on the platform, the following limited set of VkImageView swizzles are supported by - * MoltenVK, via automatic format substitution: - * - * Texture format Swizzle - * -------------- ------- - * VK_FORMAT_R8_UNORM ZERO, ANY, ANY, RED - * VK_FORMAT_A8_UNORM ALPHA, ANY, ANY, ZERO - * VK_FORMAT_R8G8B8A8_UNORM BLUE, GREEN, RED, ALPHA - * VK_FORMAT_R8G8B8A8_SRGB BLUE, GREEN, RED, ALPHA - * VK_FORMAT_B8G8R8A8_UNORM BLUE, GREEN, RED, ALPHA - * VK_FORMAT_B8G8R8A8_SRGB BLUE, GREEN, RED, ALPHA - * VK_FORMAT_D32_SFLOAT_S8_UINT RED, ANY, ANY, ANY (stencil only) - * VK_FORMAT_D24_UNORM_S8_UINT RED, ANY, ANY, ANY (stencil only) - * - * The initial value or this parameter is set by the - * MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to false. - */ - VkBool32 fullImageViewSwizzle; - - /** - * The index of the queue family whose presentation submissions will - * be used as the default GPU Capture Scope during debugging in Xcode. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to zero (the first queue family). - */ - uint32_t defaultGPUCaptureScopeQueueFamilyIndex; - - /** - * The index of the queue, within the queue family identified by the - * defaultGPUCaptureScopeQueueFamilyIndex parameter, whose presentation submissions - * will be used as the default GPU Capture Scope during debugging in Xcode. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_INDEX - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to zero (the first queue). - */ - uint32_t defaultGPUCaptureScopeQueueIndex; - - /** - * Identifies when Metal shaders will be compiled with the Metal fastMathEnabled property - * enabled. For shaders compiled with the Metal fastMathEnabled property enabled, shader - * floating point math is significantly faster, but it may cause the Metal Compiler to - * optimize floating point operations in ways that may violate the IEEE 754 standard. - * - * Enabling Metal fast math can dramatically improve shader performance, and has little - * practical effect on the numerical accuracy of most shaders. As such, disabling fast - * math should be done carefully and deliberately. For most applications, always enabling - * fast math, by setting the value of this property to MVK_CONFIG_FAST_MATH_ALWAYS, - * is the preferred choice. - * - * Apps that have specific accuracy and handling needs for particular shaders, may elect to - * set the value of this property to MVK_CONFIG_FAST_MATH_ON_DEMAND, so that fast math will - * be disabled when compiling shaders that request capabilities such as SignedZeroInfNanPreserve. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will be applied to future Metal shader compilations. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_FAST_MATH_ENABLED - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to MVK_CONFIG_FAST_MATH_ALWAYS. - */ - MVKConfigFastMath fastMathEnabled; - - /** - * Controls the level of logging performned by MoltenVK. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_LOG_LEVEL - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, errors and informational messages are logged. - */ - MVKConfigLogLevel logLevel; - - /** - * Causes MoltenVK to log the name of each Vulkan call made by the application, - * along with the Mach thread ID, global system thread ID, and thread name. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_TRACE_VULKAN_CALLS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, no Vulkan call logging will occur. - */ - MVKConfigTraceVulkanCalls traceVulkanCalls; - - /** - * Force MoltenVK to use a low-power GPU, if one is availble on the device. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_FORCE_LOW_POWER_GPU - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is disabled by default, allowing both - * low-power and high-power GPU's to be used. - */ - VkBool32 forceLowPowerGPU; - - /** Deprecated. Vulkan sempphores using MTLFence are no longer supported. Use semaphoreSupportStyle instead. */ - VkBool32 semaphoreUseMTLFence; - - /** - * Determines the style used to implement Vulkan semaphore (VkSemaphore) functionality in Metal. - * See the documentation of the MVKVkSemaphoreSupportStyle for the options. - * - * In the special case of VK_SEMAPHORE_TYPE_TIMELINE semaphores, MoltenVK will always use - * MTLSharedEvent if it is available on the platform, regardless of the value of this parameter. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is set to - * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE by default, - * and MoltenVK will use MTLEvent, except on NVIDIA GPU and Rosetta2 environments, - * or where MTLEvents are not supported, where it will use a single queue with - * implicit synchronization (as if this parameter was set to - * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE). - * - * This parameter interacts with the deprecated legacy parameters semaphoreUseMTLEvent - * and semaphoreUseMTLFence. If semaphoreUseMTLEvent is enabled, this parameter will be - * set to MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE. - * If semaphoreUseMTLEvent is disabled, this parameter will be set to - * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE if semaphoreUseMTLFence is enabled, - * or MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK if semaphoreUseMTLFence is disabled. - * Structurally, this parameter replaces, and is aliased by, semaphoreUseMTLEvent. - */ - MVKVkSemaphoreSupportStyle semaphoreSupportStyle; -#define semaphoreUseMTLEvent semaphoreSupportStyle - - /** - * Controls whether Metal should run an automatic GPU capture without the user having to - * trigger it manually via the Xcode user interface, and controls the scope under which - * that GPU capture will occur. This is useful when trying to capture a one-shot GPU trace, - * such as when running a Vulkan CTS test case. For the automatic GPU capture to occur, the - * Xcode scheme under which the app is run must have the Metal GPU capture option enabled. - * This parameter should not be set to manually trigger a GPU capture via the Xcode user interface. - * - * When the value of this parameter is MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME, - * the queue for which the GPU activity is captured is identifed by the values of - * the defaultGPUCaptureScopeQueueFamilyIndex and defaultGPUCaptureScopeQueueIndex - * configuration parameters. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, no automatic GPU capture will occur. - */ - MVKConfigAutoGPUCaptureScope autoGPUCaptureScope; - - /** - * The path to a file where the automatic GPU capture should be saved, if autoGPUCaptureScope - * is enabled. In this case, the Xcode scheme need not have Metal GPU capture enabled, and in - * fact the app need not be run under Xcode's control at all. This is useful in case the app - * cannot be run under Xcode's control. A path starting with '~' can be used to place it in a - * user's home directory, as in the shell. This feature requires Metal 3.0 (macOS 10.15, iOS 13). - * - * If this parameter is NULL or an empty string, and autoGPUCaptureScope is enabled, automatic - * GPU capture will be handled by the Xcode user interface. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_AUTO_GPU_CAPTURE_OUTPUT_FILE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, automatic GPU capture will be handled by the Xcode user interface. - */ - const char* autoGPUCaptureOutputFilepath; - - /** - * Controls whether MoltenVK should use a Metal 2D texture with a height of 1 for a - * Vulkan 1D image, or use a native Metal 1D texture. Metal imposes significant restrictions - * on native 1D textures, including not being renderable, clearable, or permitting mipmaps. - * Using a Metal 2D texture allows Vulkan 1D textures to support this additional functionality. - * - * The value of this parameter should only be changed before creating the VkInstance. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_TEXTURE_1D_AS_2D - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is enabled by default, and MoltenVK will - * use a Metal 2D texture for each Vulkan 1D image. - */ - VkBool32 texture1DAs2D; - - /** - * Controls whether MoltenVK should preallocate memory in each VkDescriptorPool according - * to the values of the VkDescriptorPoolSize parameters. Doing so may improve descriptor set - * allocation performance and memory stability at a cost of preallocated application memory. - * If this setting is disabled, the descriptors required for a descriptor set will be individually - * dynamically allocated in application memory when the descriptor set itself is allocated. - * - * The value of this parameter may be changed at any time during application runtime, and the - * changed value will affect the behavior of VkDescriptorPools created after the value is changed. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_PREALLOCATE_DESCRIPTORS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is enabled by default, and MoltenVK will - * allocate a pool of descriptors when a VkDescriptorPool is created. - */ - VkBool32 preallocateDescriptors; - - /** - * Controls whether MoltenVK should use pools to manage memory used when adding commands - * to command buffers. If this setting is enabled, MoltenVK will use a pool to hold command - * resources for reuse during command execution. If this setting is disabled, command memory - * is allocated and destroyed each time a command is executed. This is a classic time-space - * trade off. When command pooling is active, the memory in the pool can be cleared via a - * call to the vkTrimCommandPoolKHR() command. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect behavior of VkCommandPools created - * after the setting is changed. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_USE_COMMAND_POOLING - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is enabled by default, and MoltenVK will pool command memory. - */ - VkBool32 useCommandPooling; - - /** - * Controls whether MoltenVK should use MTLHeaps for allocating textures and buffers - * from device memory. If this setting is enabled, and placement MTLHeaps are - * available on the platform, MoltenVK will allocate a placement MTLHeap for each VkDeviceMemory - * instance, and allocate textures and buffers from that placement heap. If this environment - * variable is disabled, MoltenVK will allocate textures and buffers from general device memory. - * - * Apple recommends that MTLHeaps should only be used for specific requirements such as aliasing - * or hazard tracking, and MoltenVK testing has shown that allocating multiple textures of - * different types or usages from one MTLHeap can occassionally cause corruption issues under - * certain circumstances. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_USE_MTLHEAP - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is disabled by default, and MoltenVK - * will allocate texures and buffers from general device memory. - */ - VkBool32 useMTLHeap; - - /** - * Controls when MoltenVK should log activity performance events. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is set to - * MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_FRAME_COUNT by default, - * and activity performance will be logged when frame activity is logged. - */ - MVKConfigActivityPerformanceLoggingStyle activityPerformanceLoggingStyle; -#define logActivityPerformanceInline activityPerformanceLoggingStyle - - /** - * Controls the Vulkan API version that MoltenVK should advertise in vkEnumerateInstanceVersion(). - * When reading this value, it will be one of the VK_API_VERSION_1_* values, including the latest - * VK_HEADER_VERSION component. When setting this value, it should be set to one of: - * - * VK_API_VERSION_1_2 (equivalent decimal number 4202496) - * VK_API_VERSION_1_1 (equivalent decimal number 4198400) - * VK_API_VERSION_1_0 (equivalent decimal number 4194304) - * - * MoltenVK will automatically add the VK_HEADER_VERSION component. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_API_VERSION_TO_ADVERTISE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to the highest API version - * currently supported by MoltenVK, including the latest VK_HEADER_VERSION component. - */ - uint32_t apiVersionToAdvertise; - - /** - * Controls which extensions MoltenVK should advertise it supports in - * vkEnumerateInstanceExtensionProperties() and vkEnumerateDeviceExtensionProperties(). - * The value of this parameter is a bitwise OR of values from the MVKConfigAdvertiseExtensionBits - * enumeration. Any prerequisite extensions are also advertised. - * If the flag MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL is included, all supported extensions - * will be advertised. A value of zero means no extensions will be advertised. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_ADVERTISE_EXTENSIONS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this setting defaults to - * MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL, and all supported extensions will be advertised. - */ - MVKConfigAdvertiseExtensions advertiseExtensions; - - /** - * Controls whether MoltenVK should treat a lost VkDevice as resumable, unless the - * corresponding VkPhysicalDevice has also been lost. The VK_ERROR_DEVICE_LOST error has - * a broad definitional range, and can mean anything from a GPU hiccup on the current - * command buffer submission, to a physically removed GPU. In the case where this error does - * not impact the VkPhysicalDevice, Vulkan requires that the app destroy and re-create a new - * VkDevice. However, not all apps (including CTS) respect that requirement, leading to what - * might be a transient command submission failure causing an unexpected catastrophic app failure. - * - * If this setting is enabled, in the case of a VK_ERROR_DEVICE_LOST error that does NOT impact - * the VkPhysicalDevice, MoltenVK will log the error, but will not mark the VkDevice as lost, - * allowing the VkDevice to continue to be used. If this setting is disabled, MoltenVK will - * mark the VkDevice as lost, and subsequent use of that VkDevice will be reduced or prohibited. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will affect the error behavior of subsequent command submissions. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_RESUME_LOST_DEVICE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is disabled by default, and MoltenVK - * will mark the VkDevice as lost when a command submission failure occurs. - */ - VkBool32 resumeLostDevice; - - /** - * Controls whether MoltenVK should use Metal argument buffers for resources defined in - * descriptor sets, if Metal argument buffers are supported on the platform. Using Metal - * argument buffers dramatically increases the number of buffers, textures and samplers - * that can be bound to a pipeline shader, and in most cases improves performance. - * This setting is an enumeration that specifies the conditions under which MoltenVK - * will use Metal argument buffers. - * - * NOTE: Currently, Metal argument buffer support is in beta stage, and is only supported - * on macOS 11.0 (Big Sur) or later, or on older versions of macOS using an Intel GPU. - * Metal argument buffers support is not available on iOS. Development to support iOS - * and a wider combination of GPU's on older macOS versions is under way. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is set to - * MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER by default, - * and MoltenVK will not use Metal argument buffers. - */ - MVKUseMetalArgumentBuffers useMetalArgumentBuffers; - - /** - * Controls the type of compression to use on the MSL source code that is stored in memory - * for use in a pipeline cache. After being converted from SPIR-V, or loaded directly into - * a VkShaderModule, and then compiled into a MTLLibrary, the MSL source code is no longer - * needed for operation, but it is retained so it can be written out as part of a pipeline - * cache export. When a large number of shaders are loaded, this can consume significant - * memory. In such a case, this parameter can be used to compress the MSL source code that - * is awaiting export as part of a pipeline cache. - * - * Pipeline cache compression is available for macOS 10.15 and above, and iOS/tvOS 13.0 and above. - * - * The value of this parameter can be changed at any time, and will affect the size of - * the cached MSL from subsequent shader compilations. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SHADER_COMPRESSION_ALGORITHM - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is set to - * MVK_CONFIG_COMPRESSION_ALGORITHM_NONE by default, - * and MoltenVK will not compress the MSL source code after compilation into a MTLLibrary. - */ - MVKConfigCompressionAlgorithm shaderSourceCompressionAlgorithm; - -} MVKConfiguration; - - - -#pragma mark - -#pragma mark Function types - - typedef VkResult (VKAPI_PTR *PFN_vkGetMoltenVKConfigurationMVK)(VkInstance ignored, MVKConfiguration* pConfiguration, size_t* pConfigurationSize); - typedef VkResult (VKAPI_PTR *PFN_vkSetMoltenVKConfigurationMVK)(VkInstance ignored, const MVKConfiguration* pConfiguration, size_t* pConfigurationSize); - - -#pragma mark - -#pragma mark Function prototypes - -#ifndef VK_NO_PROTOTYPES - -/** - * Populates the pConfiguration structure with the current MoltenVK configuration settings. - * - * To change a specific configuration value, call vkGetMoltenVKConfigurationMVK() to retrieve - * the current configuration, make changes, and call vkSetMoltenVKConfigurationMVK() to - * update all of the values. - * - * The VkInstance object you provide here is ignored, and a VK_NULL_HANDLE value can be provided. - * This function can be called before the VkInstance has been created. It is safe to call this function - * with a VkInstance retrieved from a different layer in the Vulkan SDK Loader and Layers framework. - * - * To be active, some configuration settings must be set before a VkInstance or VkDevice - * is created. See the description of the MVKConfiguration members for more information. - * - * If you are linking to an implementation of MoltenVK that was compiled from a different - * MVK_CONFIGURATION_API_VERSION than your app was, the size of the MVKConfiguration structure - * in your app may be larger or smaller than the same struct as expected by MoltenVK. - * - * When calling this function, set the value of *pConfigurationSize to sizeof(MVKConfiguration), - * to tell MoltenVK the limit of the size of your MVKConfiguration structure. Upon return from - * this function, the value of *pConfigurationSize will hold the actual number of bytes copied - * into your passed MVKConfiguration structure, which will be the smaller of what your app - * thinks is the size of MVKConfiguration, and what MoltenVK thinks it is. This represents the - * safe access area within the structure for both MoltenVK and your app. - * - * If the size that MoltenVK expects for MVKConfiguration is different than the value passed in - * *pConfigurationSize, this function will return VK_INCOMPLETE, otherwise it will return VK_SUCCESS. - * - * Although it is not necessary, you can use this function to determine in advance the value - * that MoltenVK expects the size of MVKConfiguration to be by setting the value of pConfiguration - * to NULL. In that case, this function will set *pConfigurationSize to the size that MoltenVK - * expects MVKConfiguration to be. - */ -VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfigurationMVK( - VkInstance ignored, - MVKConfiguration* pConfiguration, - size_t* pConfigurationSize); - -/** - * Sets the MoltenVK configuration settings to those found in the pConfiguration structure. - * - * To change a specific configuration value, call vkGetMoltenVKConfigurationMVK() - * to retrieve the current configuration, make changes, and call - * vkSetMoltenVKConfigurationMVK() to update all of the values. - * - * The VkInstance object you provide here is ignored, and a VK_NULL_HANDLE value can be provided. - * This function can be called before the VkInstance has been created. It is safe to call this function - * with a VkInstance retrieved from a different layer in the Vulkan SDK Loader and Layers framework. - * - * To be active, some configuration settings must be set before a VkInstance or VkDevice - * is created. See the description of the MVKConfiguration members for more information. - * - * If you are linking to an implementation of MoltenVK that was compiled from a different - * MVK_CONFIGURATION_API_VERSION than your app was, the size of the MVKConfiguration structure - * in your app may be larger or smaller than the same struct as expected by MoltenVK. - * - * When calling this function, set the value of *pConfigurationSize to sizeof(MVKConfiguration), - * to tell MoltenVK the limit of the size of your MVKConfiguration structure. Upon return from - * this function, the value of *pConfigurationSize will hold the actual number of bytes copied - * out of your passed MVKConfiguration structure, which will be the smaller of what your app - * thinks is the size of MVKConfiguration, and what MoltenVK thinks it is. This represents the - * safe access area within the structure for both MoltenVK and your app. - * - * If the size that MoltenVK expects for MVKConfiguration is different than the value passed in - * *pConfigurationSize, this function will return VK_INCOMPLETE, otherwise it will return VK_SUCCESS. - * - * Although it is not necessary, you can use this function to determine in advance the value - * that MoltenVK expects the size of MVKConfiguration to be by setting the value of pConfiguration - * to NULL. In that case, this function will set *pConfigurationSize to the size that MoltenVK - * expects MVKConfiguration to be. - */ -VKAPI_ATTR VkResult VKAPI_CALL vkSetMoltenVKConfigurationMVK( - VkInstance ignored, - const MVKConfiguration* pConfiguration, - size_t* pConfigurationSize); - - -#pragma mark - -#pragma mark Shaders - - /** - * NOTE: Shader code should be submitted as SPIR-V. Although some simple direct MSL shaders may work, - * direct loading of MSL source code or compiled MSL code is not officially supported at this time. - * Future versions of MoltenVK may support direct MSL submission again. - * - * Enumerates the magic number values to set in the MVKMSLSPIRVHeader when - * submitting a SPIR-V stream that contains either Metal Shading Language source - * code or Metal Shading Language compiled binary code in place of SPIR-V code. - */ - typedef enum { - kMVKMagicNumberSPIRVCode = 0x07230203, /**< SPIR-V stream contains standard SPIR-V code. */ - kMVKMagicNumberMSLSourceCode = 0x19960412, /**< SPIR-V stream contains Metal Shading Language source code. */ - kMVKMagicNumberMSLCompiledCode = 0x19981215, /**< SPIR-V stream contains Metal Shading Language compiled binary code. */ - } MVKMSLMagicNumber; - - /** - * NOTE: Shader code should be submitted as SPIR-V. Although some simple direct MSL shaders may work, - * direct loading of MSL source code or compiled MSL code is not officially supported at this time. - * Future versions of MoltenVK may support direct MSL submission again. - * - * Describes the header at the start of an SPIR-V stream, when it contains either - * Metal Shading Language source code or Metal Shading Language compiled binary code. - * - * To submit MSL source code to the vkCreateShaderModule() function in place of SPIR-V - * code, prepend a MVKMSLSPIRVHeader containing the kMVKMagicNumberMSLSourceCode magic - * number to the MSL source code. The MSL source code must be null-terminated. - * - * To submit MSL compiled binary code to the vkCreateShaderModule() function in place of - * SPIR-V code, prepend a MVKMSLSPIRVHeader containing the kMVKMagicNumberMSLCompiledCode - * magic number to the MSL compiled binary code. - * - * In both cases, the pCode element of VkShaderModuleCreateInfo should pointer to the - * location of the MVKMSLSPIRVHeader, and the MSL code should start at the byte immediately - * after the MVKMSLSPIRVHeader. - * - * The codeSize element of VkShaderModuleCreateInfo should be set to the entire size of - * the submitted code memory, including the additional sizeof(MVKMSLSPIRVHeader) bytes - * taken up by the MVKMSLSPIRVHeader, and, in the case of MSL source code, including - * the null-terminator byte. - */ - typedef uint32_t MVKMSLSPIRVHeader; - - -#endif // VK_NO_PROTOTYPES - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif diff --git a/lib/graphics_engine/include/vk_platform.h b/lib/graphics_engine/include/vk_platform.h index 3ff8c5d1467..f570181e33a 100644 --- a/lib/graphics_engine/include/vk_platform.h +++ b/lib/graphics_engine/include/vk_platform.h @@ -1,8 +1,8 @@ -// -// File: vk_platform.h -// +/* */ +/* File: vk_platform.h */ +/* */ /* -** Copyright 2014-2022 The Khronos Group Inc. +** Copyright 2014-2025 The Khronos Group Inc. ** ** SPDX-License-Identifier: Apache-2.0 */ @@ -14,7 +14,7 @@ #ifdef __cplusplus extern "C" { -#endif // __cplusplus +#endif /* __cplusplus */ /* *************************************************************************************************** @@ -37,22 +37,22 @@ extern "C" * Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void); */ #if defined(_WIN32) - // On Windows, Vulkan commands use the stdcall convention + /* On Windows, Vulkan commands use the stdcall convention */ #define VKAPI_ATTR #define VKAPI_CALL __stdcall #define VKAPI_PTR VKAPI_CALL #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 #error "Vulkan is not supported for the 'armeabi' NDK ABI" #elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) - // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" - // calling convention, i.e. float parameters are passed in registers. This - // is true even if the rest of the application passes floats on the stack, - // as it does by default when compiling for the armeabi-v7a NDK ABI. + /* On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" */ + /* calling convention, i.e. float parameters are passed in registers. This */ + /* is true even if the rest of the application passes floats on the stack, */ + /* as it does by default when compiling for the armeabi-v7a NDK ABI. */ #define VKAPI_ATTR __attribute__((pcs("aapcs-vfp"))) #define VKAPI_CALL #define VKAPI_PTR VKAPI_ATTR #else - // On other platforms, use the default calling convention + /* On other platforms, use the default calling convention */ #define VKAPI_ATTR #define VKAPI_CALL #define VKAPI_PTR @@ -60,7 +60,7 @@ extern "C" #if !defined(VK_NO_STDDEF_H) #include -#endif // !defined(VK_NO_STDDEF_H) +#endif /* !defined(VK_NO_STDDEF_H) */ #if !defined(VK_NO_STDINT_H) #if defined(_MSC_VER) && (_MSC_VER < 1600) @@ -75,10 +75,10 @@ extern "C" #else #include #endif -#endif // !defined(VK_NO_STDINT_H) +#endif /* !defined(VK_NO_STDINT_H) */ #ifdef __cplusplus -} // extern "C" -#endif // __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ #endif diff --git a/lib/graphics_engine/include/vulkan_wrapper.h b/lib/graphics_engine/include/vulkan_wrapper.h index a26ea62c637..9f83a637592 100644 --- a/lib/graphics_engine/include/vulkan_wrapper.h +++ b/lib/graphics_engine/include/vulkan_wrapper.h @@ -4,18 +4,11 @@ #if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK) #include -#define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22) & 0x7FU) -#define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU) -#define VK_API_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) - #ifdef DLOPEN_MOLTENVK #define VK_NO_PROTOTYPES 1 -// We copy mvk_config.h and mvk_private_api.h with #include +// We copy mvk_private_api.h with #include // removed -#include #include -extern PFN_vkGetMoltenVKConfigurationMVK vkGetMoltenVKConfigurationMVK; -extern PFN_vkSetMoltenVKConfigurationMVK vkSetMoltenVKConfigurationMVK; extern PFN_vkGetPhysicalDeviceMetalFeaturesMVK vkGetPhysicalDeviceMetalFeaturesMVK; #endif @@ -23,7 +16,6 @@ extern PFN_vkGetPhysicalDeviceMetalFeaturesMVK vkGetPhysicalDeviceMetalFeaturesM #include #if defined(__APPLE__) -#include #include #endif diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index af77da6fe4a..387d9dd17eb 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -532,15 +532,6 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params, g_paused_rendering.store(false); g_device_created.store(true); -#if defined(__APPLE__) - MVKConfiguration cfg = {}; - size_t cfg_size = sizeof(MVKConfiguration); - vkGetMoltenVKConfigurationMVK(VK_NULL_HANDLE, &cfg, &cfg_size); - // Enable to allow binding all textures at once - cfg.useMetalArgumentBuffers = MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_ALWAYS; - vkSetMoltenVKConfigurationMVK(VK_NULL_HANDLE, &cfg, &cfg_size); -#endif - createInstance(window); #if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK) @@ -789,8 +780,8 @@ void GEVulkanDriver::createInstance(SDL_Window* window) std::vector available_layers(layer_count); vkEnumerateInstanceLayerProperties(&layer_count, available_layers.data()); - VkInstanceCreateInfo create_info = {}; std::vector enabled_validation_layers; + void* next_chain = NULL; #ifdef ENABLE_VALIDATION g_debug_print = true; @@ -812,10 +803,29 @@ void GEVulkanDriver::createInstance(SDL_Window* window) validation_features.enabledValidationFeatureCount = enabled_validation_features.size(); - create_info.pNext = &validation_features; + next_chain = &validation_features; extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); #endif +#if defined(__APPLE__) + // We need these to persist until after vkCreateInstance + static VkLayerSettingsCreateInfoEXT layer_settings_create_info = {}; + static VkBool32 setting_false = VK_FALSE; + static VkLayerSettingEXT setting = {}; + setting.pLayerName = "MoltenVK"; + setting.pSettingName = "MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS"; + setting.type = VK_LAYER_SETTING_TYPE_BOOL32_EXT; + setting.pValues = &setting_false; + setting.valueCount = 1; + + layer_settings_create_info.sType = VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT; + layer_settings_create_info.settingCount = 1; + layer_settings_create_info.pSettings = &setting; + layer_settings_create_info.pNext = next_chain; + next_chain = &layer_settings_create_info; + extensions.push_back(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME); +#endif + VkApplicationInfo app_info = {}; if (vulkan_1_1) { @@ -823,9 +833,11 @@ void GEVulkanDriver::createInstance(SDL_Window* window) // Implementations that support Vulkan 1.1 or later must not return VK_ERROR_INCOMPATIBLE_DRIVER for any value of apiVersion. app_info.apiVersion = VK_API_VERSION_1_2; } + VkInstanceCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; create_info.enabledExtensionCount = extensions.size(); create_info.ppEnabledExtensionNames = extensions.data(); + create_info.pNext = next_chain; create_info.pApplicationInfo = &app_info; create_info.enabledLayerCount = enabled_validation_layers.size(); create_info.ppEnabledLayerNames = enabled_validation_layers.data(); diff --git a/lib/graphics_engine/src/vulkan.c b/lib/graphics_engine/src/vulkan.c index e8fbe6c178c..cd64f1e8b09 100644 --- a/lib/graphics_engine/src/vulkan.c +++ b/lib/graphics_engine/src/vulkan.c @@ -1,3 +1,6 @@ +/** + * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 + */ #include #include #include @@ -23,6 +26,13 @@ extern "C" { int GLAD_VK_VERSION_1_0 = 0; int GLAD_VK_VERSION_1_1 = 0; int GLAD_VK_VERSION_1_2 = 0; +int GLAD_VK_VERSION_1_3 = 0; +int GLAD_VK_VERSION_1_4 = 0; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +int GLAD_VK_AMDX_shader_enqueue = 0; + +#endif +int GLAD_VK_AMD_anti_lag = 0; int GLAD_VK_AMD_buffer_marker = 0; int GLAD_VK_AMD_device_coherent_memory = 0; int GLAD_VK_AMD_display_native_hdr = 0; @@ -38,6 +48,7 @@ int GLAD_VK_AMD_rasterization_order = 0; int GLAD_VK_AMD_shader_ballot = 0; int GLAD_VK_AMD_shader_core_properties = 0; int GLAD_VK_AMD_shader_core_properties2 = 0; +int GLAD_VK_AMD_shader_early_and_late_fragment_tests = 0; int GLAD_VK_AMD_shader_explicit_vertex_parameter = 0; int GLAD_VK_AMD_shader_fragment_mask = 0; int GLAD_VK_AMD_shader_image_load_store_lod = 0; @@ -45,75 +56,159 @@ int GLAD_VK_AMD_shader_info = 0; int GLAD_VK_AMD_shader_trinary_minmax = 0; int GLAD_VK_AMD_texture_gather_bias_lod = 0; #if defined(VK_USE_PLATFORM_ANDROID_KHR) +int GLAD_VK_ANDROID_external_format_resolve = 0; + +#endif +#if defined(VK_USE_PLATFORM_ANDROID_KHR) int GLAD_VK_ANDROID_external_memory_android_hardware_buffer = 0; + #endif +int GLAD_VK_ARM_pipeline_opacity_micromap = 0; +int GLAD_VK_ARM_rasterization_order_attachment_access = 0; +int GLAD_VK_ARM_render_pass_striped = 0; +int GLAD_VK_ARM_scheduling_controls = 0; +int GLAD_VK_ARM_shader_core_builtins = 0; +int GLAD_VK_ARM_shader_core_properties = 0; int GLAD_VK_EXT_4444_formats = 0; +int GLAD_VK_EXT_acquire_drm_display = 0; #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) int GLAD_VK_EXT_acquire_xlib_display = 0; + #endif int GLAD_VK_EXT_astc_decode_mode = 0; +int GLAD_VK_EXT_attachment_feedback_loop_dynamic_state = 0; +int GLAD_VK_EXT_attachment_feedback_loop_layout = 0; int GLAD_VK_EXT_blend_operation_advanced = 0; +int GLAD_VK_EXT_border_color_swizzle = 0; int GLAD_VK_EXT_buffer_device_address = 0; int GLAD_VK_EXT_calibrated_timestamps = 0; +int GLAD_VK_EXT_color_write_enable = 0; int GLAD_VK_EXT_conditional_rendering = 0; int GLAD_VK_EXT_conservative_rasterization = 0; int GLAD_VK_EXT_custom_border_color = 0; int GLAD_VK_EXT_debug_marker = 0; int GLAD_VK_EXT_debug_report = 0; int GLAD_VK_EXT_debug_utils = 0; +int GLAD_VK_EXT_depth_bias_control = 0; +int GLAD_VK_EXT_depth_clamp_control = 0; +int GLAD_VK_EXT_depth_clamp_zero_one = 0; +int GLAD_VK_EXT_depth_clip_control = 0; int GLAD_VK_EXT_depth_clip_enable = 0; int GLAD_VK_EXT_depth_range_unrestricted = 0; +int GLAD_VK_EXT_descriptor_buffer = 0; int GLAD_VK_EXT_descriptor_indexing = 0; +int GLAD_VK_EXT_device_address_binding_report = 0; +int GLAD_VK_EXT_device_fault = 0; +int GLAD_VK_EXT_device_generated_commands = 0; +int GLAD_VK_EXT_device_memory_report = 0; int GLAD_VK_EXT_direct_mode_display = 0; #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) int GLAD_VK_EXT_directfb_surface = 0; + #endif int GLAD_VK_EXT_discard_rectangles = 0; int GLAD_VK_EXT_display_control = 0; int GLAD_VK_EXT_display_surface_counter = 0; +int GLAD_VK_EXT_dynamic_rendering_unused_attachments = 0; int GLAD_VK_EXT_extended_dynamic_state = 0; +int GLAD_VK_EXT_extended_dynamic_state2 = 0; +int GLAD_VK_EXT_extended_dynamic_state3 = 0; +int GLAD_VK_EXT_external_memory_acquire_unmodified = 0; int GLAD_VK_EXT_external_memory_dma_buf = 0; int GLAD_VK_EXT_external_memory_host = 0; +#if defined(VK_USE_PLATFORM_METAL_EXT) +int GLAD_VK_EXT_external_memory_metal = 0; + +#endif int GLAD_VK_EXT_filter_cubic = 0; int GLAD_VK_EXT_fragment_density_map = 0; int GLAD_VK_EXT_fragment_density_map2 = 0; +int GLAD_VK_EXT_fragment_density_map_offset = 0; int GLAD_VK_EXT_fragment_shader_interlock = 0; +int GLAD_VK_EXT_frame_boundary = 0; #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_EXT_full_screen_exclusive = 0; + #endif int GLAD_VK_EXT_global_priority = 0; +int GLAD_VK_EXT_global_priority_query = 0; +int GLAD_VK_EXT_graphics_pipeline_library = 0; int GLAD_VK_EXT_hdr_metadata = 0; int GLAD_VK_EXT_headless_surface = 0; +int GLAD_VK_EXT_host_image_copy = 0; int GLAD_VK_EXT_host_query_reset = 0; +int GLAD_VK_EXT_image_2d_view_of_3d = 0; +int GLAD_VK_EXT_image_compression_control = 0; +int GLAD_VK_EXT_image_compression_control_swapchain = 0; int GLAD_VK_EXT_image_drm_format_modifier = 0; int GLAD_VK_EXT_image_robustness = 0; +int GLAD_VK_EXT_image_sliced_view_of_3d = 0; +int GLAD_VK_EXT_image_view_min_lod = 0; int GLAD_VK_EXT_index_type_uint8 = 0; int GLAD_VK_EXT_inline_uniform_block = 0; +int GLAD_VK_EXT_layer_settings = 0; +int GLAD_VK_EXT_legacy_dithering = 0; +int GLAD_VK_EXT_legacy_vertex_attributes = 0; int GLAD_VK_EXT_line_rasterization = 0; +int GLAD_VK_EXT_load_store_op_none = 0; +int GLAD_VK_EXT_map_memory_placed = 0; int GLAD_VK_EXT_memory_budget = 0; int GLAD_VK_EXT_memory_priority = 0; +int GLAD_VK_EXT_mesh_shader = 0; +#if defined(VK_USE_PLATFORM_METAL_EXT) +int GLAD_VK_EXT_metal_objects = 0; + +#endif #if defined(VK_USE_PLATFORM_METAL_EXT) int GLAD_VK_EXT_metal_surface = 0; + #endif +int GLAD_VK_EXT_multi_draw = 0; +int GLAD_VK_EXT_multisampled_render_to_single_sampled = 0; +int GLAD_VK_EXT_mutable_descriptor_type = 0; +int GLAD_VK_EXT_nested_command_buffer = 0; +int GLAD_VK_EXT_non_seamless_cube_map = 0; +int GLAD_VK_EXT_opacity_micromap = 0; +int GLAD_VK_EXT_pageable_device_local_memory = 0; int GLAD_VK_EXT_pci_bus_info = 0; +int GLAD_VK_EXT_physical_device_drm = 0; int GLAD_VK_EXT_pipeline_creation_cache_control = 0; int GLAD_VK_EXT_pipeline_creation_feedback = 0; +int GLAD_VK_EXT_pipeline_library_group_handles = 0; +int GLAD_VK_EXT_pipeline_properties = 0; +int GLAD_VK_EXT_pipeline_protected_access = 0; +int GLAD_VK_EXT_pipeline_robustness = 0; int GLAD_VK_EXT_post_depth_coverage = 0; +int GLAD_VK_EXT_present_mode_fifo_latest_ready = 0; +int GLAD_VK_EXT_primitive_topology_list_restart = 0; +int GLAD_VK_EXT_primitives_generated_query = 0; int GLAD_VK_EXT_private_data = 0; +int GLAD_VK_EXT_provoking_vertex = 0; int GLAD_VK_EXT_queue_family_foreign = 0; +int GLAD_VK_EXT_rasterization_order_attachment_access = 0; +int GLAD_VK_EXT_rgba10x6_formats = 0; int GLAD_VK_EXT_robustness2 = 0; int GLAD_VK_EXT_sample_locations = 0; int GLAD_VK_EXT_sampler_filter_minmax = 0; int GLAD_VK_EXT_scalar_block_layout = 0; int GLAD_VK_EXT_separate_stencil_usage = 0; int GLAD_VK_EXT_shader_atomic_float = 0; +int GLAD_VK_EXT_shader_atomic_float2 = 0; int GLAD_VK_EXT_shader_demote_to_helper_invocation = 0; +int GLAD_VK_EXT_shader_image_atomic_int64 = 0; +int GLAD_VK_EXT_shader_module_identifier = 0; +int GLAD_VK_EXT_shader_object = 0; +int GLAD_VK_EXT_shader_replicated_composites = 0; int GLAD_VK_EXT_shader_stencil_export = 0; int GLAD_VK_EXT_shader_subgroup_ballot = 0; int GLAD_VK_EXT_shader_subgroup_vote = 0; +int GLAD_VK_EXT_shader_tile_image = 0; int GLAD_VK_EXT_shader_viewport_index_layer = 0; int GLAD_VK_EXT_subgroup_size_control = 0; +int GLAD_VK_EXT_subpass_merge_feedback = 0; +int GLAD_VK_EXT_surface_maintenance1 = 0; int GLAD_VK_EXT_swapchain_colorspace = 0; +int GLAD_VK_EXT_swapchain_maintenance1 = 0; int GLAD_VK_EXT_texel_buffer_alignment = 0; int GLAD_VK_EXT_texture_compression_astc_hdr = 0; int GLAD_VK_EXT_tooling_info = 0; @@ -122,36 +217,65 @@ int GLAD_VK_EXT_validation_cache = 0; int GLAD_VK_EXT_validation_features = 0; int GLAD_VK_EXT_validation_flags = 0; int GLAD_VK_EXT_vertex_attribute_divisor = 0; +int GLAD_VK_EXT_vertex_attribute_robustness = 0; +int GLAD_VK_EXT_vertex_input_dynamic_state = 0; +int GLAD_VK_EXT_ycbcr_2plane_444_formats = 0; int GLAD_VK_EXT_ycbcr_image_arrays = 0; #if defined(VK_USE_PLATFORM_FUCHSIA) +int GLAD_VK_FUCHSIA_buffer_collection = 0; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +int GLAD_VK_FUCHSIA_external_memory = 0; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +int GLAD_VK_FUCHSIA_external_semaphore = 0; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) int GLAD_VK_FUCHSIA_imagepipe_surface = 0; + #endif #if defined(VK_USE_PLATFORM_GGP) int GLAD_VK_GGP_frame_token = 0; + #endif #if defined(VK_USE_PLATFORM_GGP) int GLAD_VK_GGP_stream_descriptor_surface = 0; + #endif int GLAD_VK_GOOGLE_decorate_string = 0; int GLAD_VK_GOOGLE_display_timing = 0; int GLAD_VK_GOOGLE_hlsl_functionality1 = 0; +int GLAD_VK_GOOGLE_surfaceless_query = 0; int GLAD_VK_GOOGLE_user_type = 0; +int GLAD_VK_HUAWEI_cluster_culling_shader = 0; +int GLAD_VK_HUAWEI_hdr_vivid = 0; +int GLAD_VK_HUAWEI_invocation_mask = 0; +int GLAD_VK_HUAWEI_subpass_shading = 0; int GLAD_VK_IMG_filter_cubic = 0; int GLAD_VK_IMG_format_pvrtc = 0; +int GLAD_VK_IMG_relaxed_line_rasterization = 0; int GLAD_VK_INTEL_performance_query = 0; int GLAD_VK_INTEL_shader_integer_functions2 = 0; int GLAD_VK_KHR_16bit_storage = 0; int GLAD_VK_KHR_8bit_storage = 0; +int GLAD_VK_KHR_acceleration_structure = 0; #if defined(VK_USE_PLATFORM_ANDROID_KHR) int GLAD_VK_KHR_android_surface = 0; + #endif int GLAD_VK_KHR_bind_memory2 = 0; int GLAD_VK_KHR_buffer_device_address = 0; +int GLAD_VK_KHR_calibrated_timestamps = 0; +int GLAD_VK_KHR_compute_shader_derivatives = 0; +int GLAD_VK_KHR_cooperative_matrix = 0; +int GLAD_VK_KHR_copy_commands2 = 0; int GLAD_VK_KHR_create_renderpass2 = 0; int GLAD_VK_KHR_dedicated_allocation = 0; -#if defined(VK_ENABLE_BETA_EXTENSIONS) int GLAD_VK_KHR_deferred_host_operations = 0; -#endif +int GLAD_VK_KHR_depth_clamp_zero_one = 0; int GLAD_VK_KHR_depth_stencil_resolve = 0; int GLAD_VK_KHR_descriptor_update_template = 0; int GLAD_VK_KHR_device_group = 0; @@ -160,55 +284,91 @@ int GLAD_VK_KHR_display = 0; int GLAD_VK_KHR_display_swapchain = 0; int GLAD_VK_KHR_draw_indirect_count = 0; int GLAD_VK_KHR_driver_properties = 0; +int GLAD_VK_KHR_dynamic_rendering = 0; +int GLAD_VK_KHR_dynamic_rendering_local_read = 0; int GLAD_VK_KHR_external_fence = 0; int GLAD_VK_KHR_external_fence_capabilities = 0; int GLAD_VK_KHR_external_fence_fd = 0; #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_KHR_external_fence_win32 = 0; + #endif int GLAD_VK_KHR_external_memory = 0; int GLAD_VK_KHR_external_memory_capabilities = 0; int GLAD_VK_KHR_external_memory_fd = 0; #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_KHR_external_memory_win32 = 0; + #endif int GLAD_VK_KHR_external_semaphore = 0; int GLAD_VK_KHR_external_semaphore_capabilities = 0; int GLAD_VK_KHR_external_semaphore_fd = 0; #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_KHR_external_semaphore_win32 = 0; + #endif +int GLAD_VK_KHR_format_feature_flags2 = 0; +int GLAD_VK_KHR_fragment_shader_barycentric = 0; +int GLAD_VK_KHR_fragment_shading_rate = 0; int GLAD_VK_KHR_get_display_properties2 = 0; int GLAD_VK_KHR_get_memory_requirements2 = 0; int GLAD_VK_KHR_get_physical_device_properties2 = 0; int GLAD_VK_KHR_get_surface_capabilities2 = 0; +int GLAD_VK_KHR_global_priority = 0; int GLAD_VK_KHR_image_format_list = 0; int GLAD_VK_KHR_imageless_framebuffer = 0; int GLAD_VK_KHR_incremental_present = 0; +int GLAD_VK_KHR_index_type_uint8 = 0; +int GLAD_VK_KHR_line_rasterization = 0; +int GLAD_VK_KHR_load_store_op_none = 0; int GLAD_VK_KHR_maintenance1 = 0; int GLAD_VK_KHR_maintenance2 = 0; int GLAD_VK_KHR_maintenance3 = 0; +int GLAD_VK_KHR_maintenance4 = 0; +int GLAD_VK_KHR_maintenance5 = 0; +int GLAD_VK_KHR_maintenance6 = 0; +int GLAD_VK_KHR_maintenance7 = 0; +int GLAD_VK_KHR_maintenance8 = 0; +int GLAD_VK_KHR_map_memory2 = 0; int GLAD_VK_KHR_multiview = 0; int GLAD_VK_KHR_performance_query = 0; +int GLAD_VK_KHR_pipeline_binary = 0; int GLAD_VK_KHR_pipeline_executable_properties = 0; -#if defined(VK_ENABLE_BETA_EXTENSIONS) int GLAD_VK_KHR_pipeline_library = 0; -#endif -int GLAD_VK_KHR_push_descriptor = 0; +int GLAD_VK_KHR_portability_enumeration = 0; #if defined(VK_ENABLE_BETA_EXTENSIONS) -int GLAD_VK_KHR_ray_tracing = 0; +int GLAD_VK_KHR_portability_subset = 0; + #endif +int GLAD_VK_KHR_present_id = 0; +int GLAD_VK_KHR_present_wait = 0; +int GLAD_VK_KHR_push_descriptor = 0; +int GLAD_VK_KHR_ray_query = 0; +int GLAD_VK_KHR_ray_tracing_maintenance1 = 0; +int GLAD_VK_KHR_ray_tracing_pipeline = 0; +int GLAD_VK_KHR_ray_tracing_position_fetch = 0; int GLAD_VK_KHR_relaxed_block_layout = 0; +int GLAD_VK_KHR_robustness2 = 0; int GLAD_VK_KHR_sampler_mirror_clamp_to_edge = 0; int GLAD_VK_KHR_sampler_ycbcr_conversion = 0; int GLAD_VK_KHR_separate_depth_stencil_layouts = 0; int GLAD_VK_KHR_shader_atomic_int64 = 0; +int GLAD_VK_KHR_shader_bfloat16 = 0; int GLAD_VK_KHR_shader_clock = 0; int GLAD_VK_KHR_shader_draw_parameters = 0; +int GLAD_VK_KHR_shader_expect_assume = 0; int GLAD_VK_KHR_shader_float16_int8 = 0; int GLAD_VK_KHR_shader_float_controls = 0; +int GLAD_VK_KHR_shader_float_controls2 = 0; +int GLAD_VK_KHR_shader_integer_dot_product = 0; +int GLAD_VK_KHR_shader_maximal_reconvergence = 0; int GLAD_VK_KHR_shader_non_semantic_info = 0; +int GLAD_VK_KHR_shader_quad_control = 0; +int GLAD_VK_KHR_shader_relaxed_extended_instruction = 0; int GLAD_VK_KHR_shader_subgroup_extended_types = 0; +int GLAD_VK_KHR_shader_subgroup_rotate = 0; +int GLAD_VK_KHR_shader_subgroup_uniform_control_flow = 0; +int GLAD_VK_KHR_shader_terminate_invocation = 0; int GLAD_VK_KHR_shared_presentable_image = 0; int GLAD_VK_KHR_spirv_1_4 = 0; int GLAD_VK_KHR_storage_buffer_storage_class = 0; @@ -216,62 +376,122 @@ int GLAD_VK_KHR_surface = 0; int GLAD_VK_KHR_surface_protected_capabilities = 0; int GLAD_VK_KHR_swapchain = 0; int GLAD_VK_KHR_swapchain_mutable_format = 0; +int GLAD_VK_KHR_synchronization2 = 0; int GLAD_VK_KHR_timeline_semaphore = 0; int GLAD_VK_KHR_uniform_buffer_standard_layout = 0; int GLAD_VK_KHR_variable_pointers = 0; +int GLAD_VK_KHR_vertex_attribute_divisor = 0; int GLAD_VK_KHR_vulkan_memory_model = 0; #if defined(VK_USE_PLATFORM_WAYLAND_KHR) int GLAD_VK_KHR_wayland_surface = 0; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_KHR_win32_keyed_mutex = 0; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_KHR_win32_surface = 0; + #endif +int GLAD_VK_KHR_workgroup_memory_explicit_layout = 0; #if defined(VK_USE_PLATFORM_XCB_KHR) int GLAD_VK_KHR_xcb_surface = 0; + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) int GLAD_VK_KHR_xlib_surface = 0; + #endif +int GLAD_VK_KHR_zero_initialize_workgroup_memory = 0; +int GLAD_VK_LUNARG_direct_driver_loading = 0; +int GLAD_VK_MESA_image_alignment_control = 0; +int GLAD_VK_MSFT_layered_driver = 0; #if defined(VK_USE_PLATFORM_IOS_MVK) int GLAD_VK_MVK_ios_surface = 0; + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) int GLAD_VK_MVK_macos_surface = 0; + #endif #if defined(VK_USE_PLATFORM_VI_NN) int GLAD_VK_NN_vi_surface = 0; + #endif +int GLAD_VK_NVX_binary_import = 0; int GLAD_VK_NVX_image_view_handle = 0; int GLAD_VK_NVX_multiview_per_view_attributes = 0; +#if defined(VK_USE_PLATFORM_WIN32_KHR) +int GLAD_VK_NV_acquire_winrt_display = 0; + +#endif int GLAD_VK_NV_clip_space_w_scaling = 0; +int GLAD_VK_NV_cluster_acceleration_structure = 0; +int GLAD_VK_NV_command_buffer_inheritance = 0; int GLAD_VK_NV_compute_shader_derivatives = 0; int GLAD_VK_NV_cooperative_matrix = 0; +int GLAD_VK_NV_cooperative_matrix2 = 0; +int GLAD_VK_NV_cooperative_vector = 0; +int GLAD_VK_NV_copy_memory_indirect = 0; int GLAD_VK_NV_corner_sampled_image = 0; int GLAD_VK_NV_coverage_reduction_mode = 0; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +int GLAD_VK_NV_cuda_kernel_launch = 0; + +#endif int GLAD_VK_NV_dedicated_allocation = 0; int GLAD_VK_NV_dedicated_allocation_image_aliasing = 0; +int GLAD_VK_NV_descriptor_pool_overallocation = 0; int GLAD_VK_NV_device_diagnostic_checkpoints = 0; int GLAD_VK_NV_device_diagnostics_config = 0; int GLAD_VK_NV_device_generated_commands = 0; +int GLAD_VK_NV_device_generated_commands_compute = 0; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +int GLAD_VK_NV_displacement_micromap = 0; + +#endif +int GLAD_VK_NV_display_stereo = 0; +int GLAD_VK_NV_extended_sparse_address_space = 0; +int GLAD_VK_NV_external_compute_queue = 0; int GLAD_VK_NV_external_memory = 0; int GLAD_VK_NV_external_memory_capabilities = 0; +int GLAD_VK_NV_external_memory_rdma = 0; #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_NV_external_memory_win32 = 0; + #endif int GLAD_VK_NV_fill_rectangle = 0; int GLAD_VK_NV_fragment_coverage_to_color = 0; int GLAD_VK_NV_fragment_shader_barycentric = 0; +int GLAD_VK_NV_fragment_shading_rate_enums = 0; int GLAD_VK_NV_framebuffer_mixed_samples = 0; int GLAD_VK_NV_geometry_shader_passthrough = 0; int GLAD_VK_NV_glsl_shader = 0; +int GLAD_VK_NV_inherited_viewport_scissor = 0; +int GLAD_VK_NV_linear_color_attachment = 0; +int GLAD_VK_NV_low_latency = 0; +int GLAD_VK_NV_low_latency2 = 0; +int GLAD_VK_NV_memory_decompression = 0; int GLAD_VK_NV_mesh_shader = 0; +int GLAD_VK_NV_optical_flow = 0; +int GLAD_VK_NV_partitioned_acceleration_structure = 0; +int GLAD_VK_NV_per_stage_descriptor_set = 0; +int GLAD_VK_NV_present_barrier = 0; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +int GLAD_VK_NV_present_metering = 0; + +#endif +int GLAD_VK_NV_raw_access_chains = 0; int GLAD_VK_NV_ray_tracing = 0; +int GLAD_VK_NV_ray_tracing_invocation_reorder = 0; +int GLAD_VK_NV_ray_tracing_linear_swept_spheres = 0; +int GLAD_VK_NV_ray_tracing_motion_blur = 0; +int GLAD_VK_NV_ray_tracing_validation = 0; int GLAD_VK_NV_representative_fragment_test = 0; int GLAD_VK_NV_sample_mask_override_coverage = 0; int GLAD_VK_NV_scissor_exclusive = 0; +int GLAD_VK_NV_shader_atomic_float16_vector = 0; int GLAD_VK_NV_shader_image_footprint = 0; int GLAD_VK_NV_shader_sm_builtins = 0; int GLAD_VK_NV_shader_subgroup_partitioned = 0; @@ -280,30 +500,59 @@ int GLAD_VK_NV_viewport_array2 = 0; int GLAD_VK_NV_viewport_swizzle = 0; #if defined(VK_USE_PLATFORM_WIN32_KHR) int GLAD_VK_NV_win32_keyed_mutex = 0; + #endif +int GLAD_VK_QCOM_filter_cubic_clamp = 0; +int GLAD_VK_QCOM_filter_cubic_weights = 0; +int GLAD_VK_QCOM_fragment_density_map_offset = 0; +int GLAD_VK_QCOM_image_processing = 0; +int GLAD_VK_QCOM_image_processing2 = 0; +int GLAD_VK_QCOM_multiview_per_view_render_areas = 0; +int GLAD_VK_QCOM_multiview_per_view_viewports = 0; int GLAD_VK_QCOM_render_pass_shader_resolve = 0; int GLAD_VK_QCOM_render_pass_store_ops = 0; int GLAD_VK_QCOM_render_pass_transform = 0; +int GLAD_VK_QCOM_rotated_copy_commands = 0; +int GLAD_VK_QCOM_tile_memory_heap = 0; +int GLAD_VK_QCOM_tile_properties = 0; +int GLAD_VK_QCOM_tile_shading = 0; +int GLAD_VK_QCOM_ycbcr_degamma = 0; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +int GLAD_VK_QNX_external_memory_screen_buffer = 0; + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +int GLAD_VK_QNX_screen_surface = 0; + +#endif +int GLAD_VK_SEC_amigo_profiling = 0; +int GLAD_VK_VALVE_descriptor_set_host_mapping = 0; +int GLAD_VK_VALVE_mutable_descriptor_type = 0; +PFN_vkAcquireDrmDisplayEXT glad_vkAcquireDrmDisplayEXT = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkAcquireFullScreenExclusiveModeEXT glad_vkAcquireFullScreenExclusiveModeEXT = NULL; + #endif PFN_vkAcquireNextImage2KHR glad_vkAcquireNextImage2KHR = NULL; PFN_vkAcquireNextImageKHR glad_vkAcquireNextImageKHR = NULL; PFN_vkAcquirePerformanceConfigurationINTEL glad_vkAcquirePerformanceConfigurationINTEL = NULL; PFN_vkAcquireProfilingLockKHR glad_vkAcquireProfilingLockKHR = NULL; +#if defined(VK_USE_PLATFORM_WIN32_KHR) +PFN_vkAcquireWinrtDisplayNV glad_vkAcquireWinrtDisplayNV = NULL; + +#endif #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) PFN_vkAcquireXlibDisplayEXT glad_vkAcquireXlibDisplayEXT = NULL; + #endif PFN_vkAllocateCommandBuffers glad_vkAllocateCommandBuffers = NULL; PFN_vkAllocateDescriptorSets glad_vkAllocateDescriptorSets = NULL; PFN_vkAllocateMemory glad_vkAllocateMemory = NULL; +PFN_vkAntiLagUpdateAMD glad_vkAntiLagUpdateAMD = NULL; PFN_vkBeginCommandBuffer glad_vkBeginCommandBuffer = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -PFN_vkBindAccelerationStructureMemoryKHR glad_vkBindAccelerationStructureMemoryKHR = NULL; -#endif PFN_vkBindAccelerationStructureMemoryNV glad_vkBindAccelerationStructureMemoryNV = NULL; PFN_vkBindBufferMemory glad_vkBindBufferMemory = NULL; PFN_vkBindBufferMemory2 glad_vkBindBufferMemory2 = NULL; @@ -311,59 +560,104 @@ PFN_vkBindBufferMemory2KHR glad_vkBindBufferMemory2KHR = NULL; PFN_vkBindImageMemory glad_vkBindImageMemory = NULL; PFN_vkBindImageMemory2 glad_vkBindImageMemory2 = NULL; PFN_vkBindImageMemory2KHR glad_vkBindImageMemory2KHR = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -PFN_vkBuildAccelerationStructureKHR glad_vkBuildAccelerationStructureKHR = NULL; -#endif +PFN_vkBindOpticalFlowSessionImageNV glad_vkBindOpticalFlowSessionImageNV = NULL; +PFN_vkBuildAccelerationStructuresKHR glad_vkBuildAccelerationStructuresKHR = NULL; +PFN_vkBuildMicromapsEXT glad_vkBuildMicromapsEXT = NULL; PFN_vkCmdBeginConditionalRenderingEXT glad_vkCmdBeginConditionalRenderingEXT = NULL; PFN_vkCmdBeginDebugUtilsLabelEXT glad_vkCmdBeginDebugUtilsLabelEXT = NULL; +PFN_vkCmdBeginPerTileExecutionQCOM glad_vkCmdBeginPerTileExecutionQCOM = NULL; PFN_vkCmdBeginQuery glad_vkCmdBeginQuery = NULL; PFN_vkCmdBeginQueryIndexedEXT glad_vkCmdBeginQueryIndexedEXT = NULL; PFN_vkCmdBeginRenderPass glad_vkCmdBeginRenderPass = NULL; PFN_vkCmdBeginRenderPass2 glad_vkCmdBeginRenderPass2 = NULL; PFN_vkCmdBeginRenderPass2KHR glad_vkCmdBeginRenderPass2KHR = NULL; +PFN_vkCmdBeginRendering glad_vkCmdBeginRendering = NULL; +PFN_vkCmdBeginRenderingKHR glad_vkCmdBeginRenderingKHR = NULL; PFN_vkCmdBeginTransformFeedbackEXT glad_vkCmdBeginTransformFeedbackEXT = NULL; +PFN_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT glad_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT = NULL; +PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT glad_vkCmdBindDescriptorBufferEmbeddedSamplersEXT = NULL; +PFN_vkCmdBindDescriptorBuffersEXT glad_vkCmdBindDescriptorBuffersEXT = NULL; PFN_vkCmdBindDescriptorSets glad_vkCmdBindDescriptorSets = NULL; +PFN_vkCmdBindDescriptorSets2 glad_vkCmdBindDescriptorSets2 = NULL; +PFN_vkCmdBindDescriptorSets2KHR glad_vkCmdBindDescriptorSets2KHR = NULL; PFN_vkCmdBindIndexBuffer glad_vkCmdBindIndexBuffer = NULL; +PFN_vkCmdBindIndexBuffer2 glad_vkCmdBindIndexBuffer2 = NULL; +PFN_vkCmdBindIndexBuffer2KHR glad_vkCmdBindIndexBuffer2KHR = NULL; +PFN_vkCmdBindInvocationMaskHUAWEI glad_vkCmdBindInvocationMaskHUAWEI = NULL; PFN_vkCmdBindPipeline glad_vkCmdBindPipeline = NULL; PFN_vkCmdBindPipelineShaderGroupNV glad_vkCmdBindPipelineShaderGroupNV = NULL; +PFN_vkCmdBindShadersEXT glad_vkCmdBindShadersEXT = NULL; PFN_vkCmdBindShadingRateImageNV glad_vkCmdBindShadingRateImageNV = NULL; +PFN_vkCmdBindTileMemoryQCOM glad_vkCmdBindTileMemoryQCOM = NULL; PFN_vkCmdBindTransformFeedbackBuffersEXT glad_vkCmdBindTransformFeedbackBuffersEXT = NULL; PFN_vkCmdBindVertexBuffers glad_vkCmdBindVertexBuffers = NULL; +PFN_vkCmdBindVertexBuffers2 glad_vkCmdBindVertexBuffers2 = NULL; PFN_vkCmdBindVertexBuffers2EXT glad_vkCmdBindVertexBuffers2EXT = NULL; PFN_vkCmdBlitImage glad_vkCmdBlitImage = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -PFN_vkCmdBuildAccelerationStructureIndirectKHR glad_vkCmdBuildAccelerationStructureIndirectKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) -PFN_vkCmdBuildAccelerationStructureKHR glad_vkCmdBuildAccelerationStructureKHR = NULL; -#endif +PFN_vkCmdBlitImage2 glad_vkCmdBlitImage2 = NULL; +PFN_vkCmdBlitImage2KHR glad_vkCmdBlitImage2KHR = NULL; PFN_vkCmdBuildAccelerationStructureNV glad_vkCmdBuildAccelerationStructureNV = NULL; +PFN_vkCmdBuildAccelerationStructuresIndirectKHR glad_vkCmdBuildAccelerationStructuresIndirectKHR = NULL; +PFN_vkCmdBuildAccelerationStructuresKHR glad_vkCmdBuildAccelerationStructuresKHR = NULL; +PFN_vkCmdBuildClusterAccelerationStructureIndirectNV glad_vkCmdBuildClusterAccelerationStructureIndirectNV = NULL; +PFN_vkCmdBuildMicromapsEXT glad_vkCmdBuildMicromapsEXT = NULL; +PFN_vkCmdBuildPartitionedAccelerationStructuresNV glad_vkCmdBuildPartitionedAccelerationStructuresNV = NULL; PFN_vkCmdClearAttachments glad_vkCmdClearAttachments = NULL; PFN_vkCmdClearColorImage glad_vkCmdClearColorImage = NULL; PFN_vkCmdClearDepthStencilImage glad_vkCmdClearDepthStencilImage = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdConvertCooperativeVectorMatrixNV glad_vkCmdConvertCooperativeVectorMatrixNV = NULL; PFN_vkCmdCopyAccelerationStructureKHR glad_vkCmdCopyAccelerationStructureKHR = NULL; -#endif PFN_vkCmdCopyAccelerationStructureNV glad_vkCmdCopyAccelerationStructureNV = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkCmdCopyAccelerationStructureToMemoryKHR glad_vkCmdCopyAccelerationStructureToMemoryKHR = NULL; -#endif PFN_vkCmdCopyBuffer glad_vkCmdCopyBuffer = NULL; +PFN_vkCmdCopyBuffer2 glad_vkCmdCopyBuffer2 = NULL; +PFN_vkCmdCopyBuffer2KHR glad_vkCmdCopyBuffer2KHR = NULL; PFN_vkCmdCopyBufferToImage glad_vkCmdCopyBufferToImage = NULL; +PFN_vkCmdCopyBufferToImage2 glad_vkCmdCopyBufferToImage2 = NULL; +PFN_vkCmdCopyBufferToImage2KHR glad_vkCmdCopyBufferToImage2KHR = NULL; PFN_vkCmdCopyImage glad_vkCmdCopyImage = NULL; +PFN_vkCmdCopyImage2 glad_vkCmdCopyImage2 = NULL; +PFN_vkCmdCopyImage2KHR glad_vkCmdCopyImage2KHR = NULL; PFN_vkCmdCopyImageToBuffer glad_vkCmdCopyImageToBuffer = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdCopyImageToBuffer2 glad_vkCmdCopyImageToBuffer2 = NULL; +PFN_vkCmdCopyImageToBuffer2KHR glad_vkCmdCopyImageToBuffer2KHR = NULL; +PFN_vkCmdCopyMemoryIndirectNV glad_vkCmdCopyMemoryIndirectNV = NULL; PFN_vkCmdCopyMemoryToAccelerationStructureKHR glad_vkCmdCopyMemoryToAccelerationStructureKHR = NULL; -#endif +PFN_vkCmdCopyMemoryToImageIndirectNV glad_vkCmdCopyMemoryToImageIndirectNV = NULL; +PFN_vkCmdCopyMemoryToMicromapEXT glad_vkCmdCopyMemoryToMicromapEXT = NULL; +PFN_vkCmdCopyMicromapEXT glad_vkCmdCopyMicromapEXT = NULL; +PFN_vkCmdCopyMicromapToMemoryEXT glad_vkCmdCopyMicromapToMemoryEXT = NULL; PFN_vkCmdCopyQueryPoolResults glad_vkCmdCopyQueryPoolResults = NULL; +PFN_vkCmdCuLaunchKernelNVX glad_vkCmdCuLaunchKernelNVX = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdCudaLaunchKernelNV glad_vkCmdCudaLaunchKernelNV = NULL; + +#endif PFN_vkCmdDebugMarkerBeginEXT glad_vkCmdDebugMarkerBeginEXT = NULL; PFN_vkCmdDebugMarkerEndEXT glad_vkCmdDebugMarkerEndEXT = NULL; PFN_vkCmdDebugMarkerInsertEXT glad_vkCmdDebugMarkerInsertEXT = NULL; +PFN_vkCmdDecompressMemoryIndirectCountNV glad_vkCmdDecompressMemoryIndirectCountNV = NULL; +PFN_vkCmdDecompressMemoryNV glad_vkCmdDecompressMemoryNV = NULL; PFN_vkCmdDispatch glad_vkCmdDispatch = NULL; PFN_vkCmdDispatchBase glad_vkCmdDispatchBase = NULL; PFN_vkCmdDispatchBaseKHR glad_vkCmdDispatchBaseKHR = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdDispatchGraphAMDX glad_vkCmdDispatchGraphAMDX = NULL; + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdDispatchGraphIndirectAMDX glad_vkCmdDispatchGraphIndirectAMDX = NULL; + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdDispatchGraphIndirectCountAMDX glad_vkCmdDispatchGraphIndirectCountAMDX = NULL; + +#endif PFN_vkCmdDispatchIndirect glad_vkCmdDispatchIndirect = NULL; +PFN_vkCmdDispatchTileQCOM glad_vkCmdDispatchTileQCOM = NULL; PFN_vkCmdDraw glad_vkCmdDraw = NULL; +PFN_vkCmdDrawClusterHUAWEI glad_vkCmdDrawClusterHUAWEI = NULL; +PFN_vkCmdDrawClusterIndirectHUAWEI glad_vkCmdDrawClusterIndirectHUAWEI = NULL; PFN_vkCmdDrawIndexed glad_vkCmdDrawIndexed = NULL; PFN_vkCmdDrawIndexedIndirect glad_vkCmdDrawIndexedIndirect = NULL; PFN_vkCmdDrawIndexedIndirectCount glad_vkCmdDrawIndexedIndirectCount = NULL; @@ -374,107 +668,226 @@ PFN_vkCmdDrawIndirectByteCountEXT glad_vkCmdDrawIndirectByteCountEXT = NULL; PFN_vkCmdDrawIndirectCount glad_vkCmdDrawIndirectCount = NULL; PFN_vkCmdDrawIndirectCountAMD glad_vkCmdDrawIndirectCountAMD = NULL; PFN_vkCmdDrawIndirectCountKHR glad_vkCmdDrawIndirectCountKHR = NULL; +PFN_vkCmdDrawMeshTasksEXT glad_vkCmdDrawMeshTasksEXT = NULL; +PFN_vkCmdDrawMeshTasksIndirectCountEXT glad_vkCmdDrawMeshTasksIndirectCountEXT = NULL; PFN_vkCmdDrawMeshTasksIndirectCountNV glad_vkCmdDrawMeshTasksIndirectCountNV = NULL; +PFN_vkCmdDrawMeshTasksIndirectEXT glad_vkCmdDrawMeshTasksIndirectEXT = NULL; PFN_vkCmdDrawMeshTasksIndirectNV glad_vkCmdDrawMeshTasksIndirectNV = NULL; PFN_vkCmdDrawMeshTasksNV glad_vkCmdDrawMeshTasksNV = NULL; +PFN_vkCmdDrawMultiEXT glad_vkCmdDrawMultiEXT = NULL; +PFN_vkCmdDrawMultiIndexedEXT glad_vkCmdDrawMultiIndexedEXT = NULL; PFN_vkCmdEndConditionalRenderingEXT glad_vkCmdEndConditionalRenderingEXT = NULL; PFN_vkCmdEndDebugUtilsLabelEXT glad_vkCmdEndDebugUtilsLabelEXT = NULL; +PFN_vkCmdEndPerTileExecutionQCOM glad_vkCmdEndPerTileExecutionQCOM = NULL; PFN_vkCmdEndQuery glad_vkCmdEndQuery = NULL; PFN_vkCmdEndQueryIndexedEXT glad_vkCmdEndQueryIndexedEXT = NULL; PFN_vkCmdEndRenderPass glad_vkCmdEndRenderPass = NULL; PFN_vkCmdEndRenderPass2 glad_vkCmdEndRenderPass2 = NULL; PFN_vkCmdEndRenderPass2KHR glad_vkCmdEndRenderPass2KHR = NULL; +PFN_vkCmdEndRendering glad_vkCmdEndRendering = NULL; +PFN_vkCmdEndRendering2EXT glad_vkCmdEndRendering2EXT = NULL; +PFN_vkCmdEndRenderingKHR glad_vkCmdEndRenderingKHR = NULL; PFN_vkCmdEndTransformFeedbackEXT glad_vkCmdEndTransformFeedbackEXT = NULL; PFN_vkCmdExecuteCommands glad_vkCmdExecuteCommands = NULL; +PFN_vkCmdExecuteGeneratedCommandsEXT glad_vkCmdExecuteGeneratedCommandsEXT = NULL; PFN_vkCmdExecuteGeneratedCommandsNV glad_vkCmdExecuteGeneratedCommandsNV = NULL; PFN_vkCmdFillBuffer glad_vkCmdFillBuffer = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdInitializeGraphScratchMemoryAMDX glad_vkCmdInitializeGraphScratchMemoryAMDX = NULL; + +#endif PFN_vkCmdInsertDebugUtilsLabelEXT glad_vkCmdInsertDebugUtilsLabelEXT = NULL; PFN_vkCmdNextSubpass glad_vkCmdNextSubpass = NULL; PFN_vkCmdNextSubpass2 glad_vkCmdNextSubpass2 = NULL; PFN_vkCmdNextSubpass2KHR glad_vkCmdNextSubpass2KHR = NULL; +PFN_vkCmdOpticalFlowExecuteNV glad_vkCmdOpticalFlowExecuteNV = NULL; PFN_vkCmdPipelineBarrier glad_vkCmdPipelineBarrier = NULL; +PFN_vkCmdPipelineBarrier2 glad_vkCmdPipelineBarrier2 = NULL; +PFN_vkCmdPipelineBarrier2KHR glad_vkCmdPipelineBarrier2KHR = NULL; +PFN_vkCmdPreprocessGeneratedCommandsEXT glad_vkCmdPreprocessGeneratedCommandsEXT = NULL; PFN_vkCmdPreprocessGeneratedCommandsNV glad_vkCmdPreprocessGeneratedCommandsNV = NULL; PFN_vkCmdPushConstants glad_vkCmdPushConstants = NULL; +PFN_vkCmdPushConstants2 glad_vkCmdPushConstants2 = NULL; +PFN_vkCmdPushConstants2KHR glad_vkCmdPushConstants2KHR = NULL; +PFN_vkCmdPushDescriptorSet glad_vkCmdPushDescriptorSet = NULL; +PFN_vkCmdPushDescriptorSet2 glad_vkCmdPushDescriptorSet2 = NULL; +PFN_vkCmdPushDescriptorSet2KHR glad_vkCmdPushDescriptorSet2KHR = NULL; PFN_vkCmdPushDescriptorSetKHR glad_vkCmdPushDescriptorSetKHR = NULL; +PFN_vkCmdPushDescriptorSetWithTemplate glad_vkCmdPushDescriptorSetWithTemplate = NULL; +PFN_vkCmdPushDescriptorSetWithTemplate2 glad_vkCmdPushDescriptorSetWithTemplate2 = NULL; +PFN_vkCmdPushDescriptorSetWithTemplate2KHR glad_vkCmdPushDescriptorSetWithTemplate2KHR = NULL; PFN_vkCmdPushDescriptorSetWithTemplateKHR glad_vkCmdPushDescriptorSetWithTemplateKHR = NULL; PFN_vkCmdResetEvent glad_vkCmdResetEvent = NULL; +PFN_vkCmdResetEvent2 glad_vkCmdResetEvent2 = NULL; +PFN_vkCmdResetEvent2KHR glad_vkCmdResetEvent2KHR = NULL; PFN_vkCmdResetQueryPool glad_vkCmdResetQueryPool = NULL; PFN_vkCmdResolveImage glad_vkCmdResolveImage = NULL; +PFN_vkCmdResolveImage2 glad_vkCmdResolveImage2 = NULL; +PFN_vkCmdResolveImage2KHR glad_vkCmdResolveImage2KHR = NULL; +PFN_vkCmdSetAlphaToCoverageEnableEXT glad_vkCmdSetAlphaToCoverageEnableEXT = NULL; +PFN_vkCmdSetAlphaToOneEnableEXT glad_vkCmdSetAlphaToOneEnableEXT = NULL; +PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT glad_vkCmdSetAttachmentFeedbackLoopEnableEXT = NULL; PFN_vkCmdSetBlendConstants glad_vkCmdSetBlendConstants = NULL; PFN_vkCmdSetCheckpointNV glad_vkCmdSetCheckpointNV = NULL; PFN_vkCmdSetCoarseSampleOrderNV glad_vkCmdSetCoarseSampleOrderNV = NULL; +PFN_vkCmdSetColorBlendAdvancedEXT glad_vkCmdSetColorBlendAdvancedEXT = NULL; +PFN_vkCmdSetColorBlendEnableEXT glad_vkCmdSetColorBlendEnableEXT = NULL; +PFN_vkCmdSetColorBlendEquationEXT glad_vkCmdSetColorBlendEquationEXT = NULL; +PFN_vkCmdSetColorWriteEnableEXT glad_vkCmdSetColorWriteEnableEXT = NULL; +PFN_vkCmdSetColorWriteMaskEXT glad_vkCmdSetColorWriteMaskEXT = NULL; +PFN_vkCmdSetConservativeRasterizationModeEXT glad_vkCmdSetConservativeRasterizationModeEXT = NULL; +PFN_vkCmdSetCoverageModulationModeNV glad_vkCmdSetCoverageModulationModeNV = NULL; +PFN_vkCmdSetCoverageModulationTableEnableNV glad_vkCmdSetCoverageModulationTableEnableNV = NULL; +PFN_vkCmdSetCoverageModulationTableNV glad_vkCmdSetCoverageModulationTableNV = NULL; +PFN_vkCmdSetCoverageReductionModeNV glad_vkCmdSetCoverageReductionModeNV = NULL; +PFN_vkCmdSetCoverageToColorEnableNV glad_vkCmdSetCoverageToColorEnableNV = NULL; +PFN_vkCmdSetCoverageToColorLocationNV glad_vkCmdSetCoverageToColorLocationNV = NULL; +PFN_vkCmdSetCullMode glad_vkCmdSetCullMode = NULL; PFN_vkCmdSetCullModeEXT glad_vkCmdSetCullModeEXT = NULL; PFN_vkCmdSetDepthBias glad_vkCmdSetDepthBias = NULL; +PFN_vkCmdSetDepthBias2EXT glad_vkCmdSetDepthBias2EXT = NULL; +PFN_vkCmdSetDepthBiasEnable glad_vkCmdSetDepthBiasEnable = NULL; +PFN_vkCmdSetDepthBiasEnableEXT glad_vkCmdSetDepthBiasEnableEXT = NULL; PFN_vkCmdSetDepthBounds glad_vkCmdSetDepthBounds = NULL; +PFN_vkCmdSetDepthBoundsTestEnable glad_vkCmdSetDepthBoundsTestEnable = NULL; PFN_vkCmdSetDepthBoundsTestEnableEXT glad_vkCmdSetDepthBoundsTestEnableEXT = NULL; +PFN_vkCmdSetDepthClampEnableEXT glad_vkCmdSetDepthClampEnableEXT = NULL; +PFN_vkCmdSetDepthClampRangeEXT glad_vkCmdSetDepthClampRangeEXT = NULL; +PFN_vkCmdSetDepthClipEnableEXT glad_vkCmdSetDepthClipEnableEXT = NULL; +PFN_vkCmdSetDepthClipNegativeOneToOneEXT glad_vkCmdSetDepthClipNegativeOneToOneEXT = NULL; +PFN_vkCmdSetDepthCompareOp glad_vkCmdSetDepthCompareOp = NULL; PFN_vkCmdSetDepthCompareOpEXT glad_vkCmdSetDepthCompareOpEXT = NULL; +PFN_vkCmdSetDepthTestEnable glad_vkCmdSetDepthTestEnable = NULL; PFN_vkCmdSetDepthTestEnableEXT glad_vkCmdSetDepthTestEnableEXT = NULL; +PFN_vkCmdSetDepthWriteEnable glad_vkCmdSetDepthWriteEnable = NULL; PFN_vkCmdSetDepthWriteEnableEXT glad_vkCmdSetDepthWriteEnableEXT = NULL; +PFN_vkCmdSetDescriptorBufferOffsets2EXT glad_vkCmdSetDescriptorBufferOffsets2EXT = NULL; +PFN_vkCmdSetDescriptorBufferOffsetsEXT glad_vkCmdSetDescriptorBufferOffsetsEXT = NULL; PFN_vkCmdSetDeviceMask glad_vkCmdSetDeviceMask = NULL; PFN_vkCmdSetDeviceMaskKHR glad_vkCmdSetDeviceMaskKHR = NULL; PFN_vkCmdSetDiscardRectangleEXT glad_vkCmdSetDiscardRectangleEXT = NULL; +PFN_vkCmdSetDiscardRectangleEnableEXT glad_vkCmdSetDiscardRectangleEnableEXT = NULL; +PFN_vkCmdSetDiscardRectangleModeEXT glad_vkCmdSetDiscardRectangleModeEXT = NULL; PFN_vkCmdSetEvent glad_vkCmdSetEvent = NULL; +PFN_vkCmdSetEvent2 glad_vkCmdSetEvent2 = NULL; +PFN_vkCmdSetEvent2KHR glad_vkCmdSetEvent2KHR = NULL; +PFN_vkCmdSetExclusiveScissorEnableNV glad_vkCmdSetExclusiveScissorEnableNV = NULL; PFN_vkCmdSetExclusiveScissorNV glad_vkCmdSetExclusiveScissorNV = NULL; +PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT glad_vkCmdSetExtraPrimitiveOverestimationSizeEXT = NULL; +PFN_vkCmdSetFragmentShadingRateEnumNV glad_vkCmdSetFragmentShadingRateEnumNV = NULL; +PFN_vkCmdSetFragmentShadingRateKHR glad_vkCmdSetFragmentShadingRateKHR = NULL; +PFN_vkCmdSetFrontFace glad_vkCmdSetFrontFace = NULL; PFN_vkCmdSetFrontFaceEXT glad_vkCmdSetFrontFaceEXT = NULL; +PFN_vkCmdSetLineRasterizationModeEXT glad_vkCmdSetLineRasterizationModeEXT = NULL; +PFN_vkCmdSetLineStipple glad_vkCmdSetLineStipple = NULL; PFN_vkCmdSetLineStippleEXT glad_vkCmdSetLineStippleEXT = NULL; +PFN_vkCmdSetLineStippleEnableEXT glad_vkCmdSetLineStippleEnableEXT = NULL; +PFN_vkCmdSetLineStippleKHR glad_vkCmdSetLineStippleKHR = NULL; PFN_vkCmdSetLineWidth glad_vkCmdSetLineWidth = NULL; +PFN_vkCmdSetLogicOpEXT glad_vkCmdSetLogicOpEXT = NULL; +PFN_vkCmdSetLogicOpEnableEXT glad_vkCmdSetLogicOpEnableEXT = NULL; +PFN_vkCmdSetPatchControlPointsEXT glad_vkCmdSetPatchControlPointsEXT = NULL; PFN_vkCmdSetPerformanceMarkerINTEL glad_vkCmdSetPerformanceMarkerINTEL = NULL; PFN_vkCmdSetPerformanceOverrideINTEL glad_vkCmdSetPerformanceOverrideINTEL = NULL; PFN_vkCmdSetPerformanceStreamMarkerINTEL glad_vkCmdSetPerformanceStreamMarkerINTEL = NULL; +PFN_vkCmdSetPolygonModeEXT glad_vkCmdSetPolygonModeEXT = NULL; +PFN_vkCmdSetPrimitiveRestartEnable glad_vkCmdSetPrimitiveRestartEnable = NULL; +PFN_vkCmdSetPrimitiveRestartEnableEXT glad_vkCmdSetPrimitiveRestartEnableEXT = NULL; +PFN_vkCmdSetPrimitiveTopology glad_vkCmdSetPrimitiveTopology = NULL; PFN_vkCmdSetPrimitiveTopologyEXT glad_vkCmdSetPrimitiveTopologyEXT = NULL; +PFN_vkCmdSetProvokingVertexModeEXT glad_vkCmdSetProvokingVertexModeEXT = NULL; +PFN_vkCmdSetRasterizationSamplesEXT glad_vkCmdSetRasterizationSamplesEXT = NULL; +PFN_vkCmdSetRasterizationStreamEXT glad_vkCmdSetRasterizationStreamEXT = NULL; +PFN_vkCmdSetRasterizerDiscardEnable glad_vkCmdSetRasterizerDiscardEnable = NULL; +PFN_vkCmdSetRasterizerDiscardEnableEXT glad_vkCmdSetRasterizerDiscardEnableEXT = NULL; +PFN_vkCmdSetRayTracingPipelineStackSizeKHR glad_vkCmdSetRayTracingPipelineStackSizeKHR = NULL; +PFN_vkCmdSetRenderingAttachmentLocations glad_vkCmdSetRenderingAttachmentLocations = NULL; +PFN_vkCmdSetRenderingAttachmentLocationsKHR glad_vkCmdSetRenderingAttachmentLocationsKHR = NULL; +PFN_vkCmdSetRenderingInputAttachmentIndices glad_vkCmdSetRenderingInputAttachmentIndices = NULL; +PFN_vkCmdSetRenderingInputAttachmentIndicesKHR glad_vkCmdSetRenderingInputAttachmentIndicesKHR = NULL; +PFN_vkCmdSetRepresentativeFragmentTestEnableNV glad_vkCmdSetRepresentativeFragmentTestEnableNV = NULL; PFN_vkCmdSetSampleLocationsEXT glad_vkCmdSetSampleLocationsEXT = NULL; +PFN_vkCmdSetSampleLocationsEnableEXT glad_vkCmdSetSampleLocationsEnableEXT = NULL; +PFN_vkCmdSetSampleMaskEXT glad_vkCmdSetSampleMaskEXT = NULL; PFN_vkCmdSetScissor glad_vkCmdSetScissor = NULL; +PFN_vkCmdSetScissorWithCount glad_vkCmdSetScissorWithCount = NULL; PFN_vkCmdSetScissorWithCountEXT glad_vkCmdSetScissorWithCountEXT = NULL; +PFN_vkCmdSetShadingRateImageEnableNV glad_vkCmdSetShadingRateImageEnableNV = NULL; PFN_vkCmdSetStencilCompareMask glad_vkCmdSetStencilCompareMask = NULL; +PFN_vkCmdSetStencilOp glad_vkCmdSetStencilOp = NULL; PFN_vkCmdSetStencilOpEXT glad_vkCmdSetStencilOpEXT = NULL; PFN_vkCmdSetStencilReference glad_vkCmdSetStencilReference = NULL; +PFN_vkCmdSetStencilTestEnable glad_vkCmdSetStencilTestEnable = NULL; PFN_vkCmdSetStencilTestEnableEXT glad_vkCmdSetStencilTestEnableEXT = NULL; PFN_vkCmdSetStencilWriteMask glad_vkCmdSetStencilWriteMask = NULL; +PFN_vkCmdSetTessellationDomainOriginEXT glad_vkCmdSetTessellationDomainOriginEXT = NULL; +PFN_vkCmdSetVertexInputEXT glad_vkCmdSetVertexInputEXT = NULL; PFN_vkCmdSetViewport glad_vkCmdSetViewport = NULL; PFN_vkCmdSetViewportShadingRatePaletteNV glad_vkCmdSetViewportShadingRatePaletteNV = NULL; +PFN_vkCmdSetViewportSwizzleNV glad_vkCmdSetViewportSwizzleNV = NULL; +PFN_vkCmdSetViewportWScalingEnableNV glad_vkCmdSetViewportWScalingEnableNV = NULL; PFN_vkCmdSetViewportWScalingNV glad_vkCmdSetViewportWScalingNV = NULL; +PFN_vkCmdSetViewportWithCount glad_vkCmdSetViewportWithCount = NULL; PFN_vkCmdSetViewportWithCountEXT glad_vkCmdSetViewportWithCountEXT = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdSubpassShadingHUAWEI glad_vkCmdSubpassShadingHUAWEI = NULL; +PFN_vkCmdTraceRaysIndirect2KHR glad_vkCmdTraceRaysIndirect2KHR = NULL; PFN_vkCmdTraceRaysIndirectKHR glad_vkCmdTraceRaysIndirectKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkCmdTraceRaysKHR glad_vkCmdTraceRaysKHR = NULL; -#endif PFN_vkCmdTraceRaysNV glad_vkCmdTraceRaysNV = NULL; PFN_vkCmdUpdateBuffer glad_vkCmdUpdateBuffer = NULL; +PFN_vkCmdUpdatePipelineIndirectBufferNV glad_vkCmdUpdatePipelineIndirectBufferNV = NULL; PFN_vkCmdWaitEvents glad_vkCmdWaitEvents = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCmdWaitEvents2 glad_vkCmdWaitEvents2 = NULL; +PFN_vkCmdWaitEvents2KHR glad_vkCmdWaitEvents2KHR = NULL; PFN_vkCmdWriteAccelerationStructuresPropertiesKHR glad_vkCmdWriteAccelerationStructuresPropertiesKHR = NULL; -#endif PFN_vkCmdWriteAccelerationStructuresPropertiesNV glad_vkCmdWriteAccelerationStructuresPropertiesNV = NULL; +PFN_vkCmdWriteBufferMarker2AMD glad_vkCmdWriteBufferMarker2AMD = NULL; PFN_vkCmdWriteBufferMarkerAMD glad_vkCmdWriteBufferMarkerAMD = NULL; +PFN_vkCmdWriteMicromapsPropertiesEXT glad_vkCmdWriteMicromapsPropertiesEXT = NULL; PFN_vkCmdWriteTimestamp glad_vkCmdWriteTimestamp = NULL; +PFN_vkCmdWriteTimestamp2 glad_vkCmdWriteTimestamp2 = NULL; +PFN_vkCmdWriteTimestamp2KHR glad_vkCmdWriteTimestamp2KHR = NULL; PFN_vkCompileDeferredNV glad_vkCompileDeferredNV = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkConvertCooperativeVectorMatrixNV glad_vkConvertCooperativeVectorMatrixNV = NULL; PFN_vkCopyAccelerationStructureKHR glad_vkCopyAccelerationStructureKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkCopyAccelerationStructureToMemoryKHR glad_vkCopyAccelerationStructureToMemoryKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCopyImageToImage glad_vkCopyImageToImage = NULL; +PFN_vkCopyImageToImageEXT glad_vkCopyImageToImageEXT = NULL; +PFN_vkCopyImageToMemory glad_vkCopyImageToMemory = NULL; +PFN_vkCopyImageToMemoryEXT glad_vkCopyImageToMemoryEXT = NULL; PFN_vkCopyMemoryToAccelerationStructureKHR glad_vkCopyMemoryToAccelerationStructureKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCopyMemoryToImage glad_vkCopyMemoryToImage = NULL; +PFN_vkCopyMemoryToImageEXT glad_vkCopyMemoryToImageEXT = NULL; +PFN_vkCopyMemoryToMicromapEXT glad_vkCopyMemoryToMicromapEXT = NULL; +PFN_vkCopyMicromapEXT glad_vkCopyMicromapEXT = NULL; +PFN_vkCopyMicromapToMemoryEXT glad_vkCopyMicromapToMemoryEXT = NULL; PFN_vkCreateAccelerationStructureKHR glad_vkCreateAccelerationStructureKHR = NULL; -#endif PFN_vkCreateAccelerationStructureNV glad_vkCreateAccelerationStructureNV = NULL; #if defined(VK_USE_PLATFORM_ANDROID_KHR) PFN_vkCreateAndroidSurfaceKHR glad_vkCreateAndroidSurfaceKHR = NULL; + #endif PFN_vkCreateBuffer glad_vkCreateBuffer = NULL; +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkCreateBufferCollectionFUCHSIA glad_vkCreateBufferCollectionFUCHSIA = NULL; + +#endif PFN_vkCreateBufferView glad_vkCreateBufferView = NULL; PFN_vkCreateCommandPool glad_vkCreateCommandPool = NULL; PFN_vkCreateComputePipelines glad_vkCreateComputePipelines = NULL; +PFN_vkCreateCuFunctionNVX glad_vkCreateCuFunctionNVX = NULL; +PFN_vkCreateCuModuleNVX glad_vkCreateCuModuleNVX = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCreateCudaFunctionNV glad_vkCreateCudaFunctionNV = NULL; + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCreateCudaModuleNV glad_vkCreateCudaModuleNV = NULL; + +#endif PFN_vkCreateDebugReportCallbackEXT glad_vkCreateDebugReportCallbackEXT = NULL; PFN_vkCreateDebugUtilsMessengerEXT glad_vkCreateDebugUtilsMessengerEXT = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkCreateDeferredOperationKHR glad_vkCreateDeferredOperationKHR = NULL; -#endif PFN_vkCreateDescriptorPool glad_vkCreateDescriptorPool = NULL; PFN_vkCreateDescriptorSetLayout glad_vkCreateDescriptorSetLayout = NULL; PFN_vkCreateDescriptorUpdateTemplate glad_vkCreateDescriptorUpdateTemplate = NULL; @@ -482,37 +895,51 @@ PFN_vkCreateDescriptorUpdateTemplateKHR glad_vkCreateDescriptorUpdateTemplateKHR PFN_vkCreateDevice glad_vkCreateDevice = NULL; #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) PFN_vkCreateDirectFBSurfaceEXT glad_vkCreateDirectFBSurfaceEXT = NULL; + #endif PFN_vkCreateDisplayModeKHR glad_vkCreateDisplayModeKHR = NULL; PFN_vkCreateDisplayPlaneSurfaceKHR glad_vkCreateDisplayPlaneSurfaceKHR = NULL; PFN_vkCreateEvent glad_vkCreateEvent = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkCreateExecutionGraphPipelinesAMDX glad_vkCreateExecutionGraphPipelinesAMDX = NULL; + +#endif +PFN_vkCreateExternalComputeQueueNV glad_vkCreateExternalComputeQueueNV = NULL; PFN_vkCreateFence glad_vkCreateFence = NULL; PFN_vkCreateFramebuffer glad_vkCreateFramebuffer = NULL; PFN_vkCreateGraphicsPipelines glad_vkCreateGraphicsPipelines = NULL; PFN_vkCreateHeadlessSurfaceEXT glad_vkCreateHeadlessSurfaceEXT = NULL; #if defined(VK_USE_PLATFORM_IOS_MVK) PFN_vkCreateIOSSurfaceMVK glad_vkCreateIOSSurfaceMVK = NULL; + #endif PFN_vkCreateImage glad_vkCreateImage = NULL; #if defined(VK_USE_PLATFORM_FUCHSIA) PFN_vkCreateImagePipeSurfaceFUCHSIA glad_vkCreateImagePipeSurfaceFUCHSIA = NULL; + #endif PFN_vkCreateImageView glad_vkCreateImageView = NULL; +PFN_vkCreateIndirectCommandsLayoutEXT glad_vkCreateIndirectCommandsLayoutEXT = NULL; PFN_vkCreateIndirectCommandsLayoutNV glad_vkCreateIndirectCommandsLayoutNV = NULL; +PFN_vkCreateIndirectExecutionSetEXT glad_vkCreateIndirectExecutionSetEXT = NULL; PFN_vkCreateInstance glad_vkCreateInstance = NULL; #if defined(VK_USE_PLATFORM_MACOS_MVK) PFN_vkCreateMacOSSurfaceMVK glad_vkCreateMacOSSurfaceMVK = NULL; + #endif #if defined(VK_USE_PLATFORM_METAL_EXT) PFN_vkCreateMetalSurfaceEXT glad_vkCreateMetalSurfaceEXT = NULL; + #endif +PFN_vkCreateMicromapEXT glad_vkCreateMicromapEXT = NULL; +PFN_vkCreateOpticalFlowSessionNV glad_vkCreateOpticalFlowSessionNV = NULL; +PFN_vkCreatePipelineBinariesKHR glad_vkCreatePipelineBinariesKHR = NULL; PFN_vkCreatePipelineCache glad_vkCreatePipelineCache = NULL; PFN_vkCreatePipelineLayout glad_vkCreatePipelineLayout = NULL; +PFN_vkCreatePrivateDataSlot glad_vkCreatePrivateDataSlot = NULL; PFN_vkCreatePrivateDataSlotEXT glad_vkCreatePrivateDataSlotEXT = NULL; PFN_vkCreateQueryPool glad_vkCreateQueryPool = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkCreateRayTracingPipelinesKHR glad_vkCreateRayTracingPipelinesKHR = NULL; -#endif PFN_vkCreateRayTracingPipelinesNV glad_vkCreateRayTracingPipelinesNV = NULL; PFN_vkCreateRenderPass glad_vkCreateRenderPass = NULL; PFN_vkCreateRenderPass2 glad_vkCreateRenderPass2 = NULL; @@ -520,62 +947,88 @@ PFN_vkCreateRenderPass2KHR glad_vkCreateRenderPass2KHR = NULL; PFN_vkCreateSampler glad_vkCreateSampler = NULL; PFN_vkCreateSamplerYcbcrConversion glad_vkCreateSamplerYcbcrConversion = NULL; PFN_vkCreateSamplerYcbcrConversionKHR glad_vkCreateSamplerYcbcrConversionKHR = NULL; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +PFN_vkCreateScreenSurfaceQNX glad_vkCreateScreenSurfaceQNX = NULL; + +#endif PFN_vkCreateSemaphore glad_vkCreateSemaphore = NULL; PFN_vkCreateShaderModule glad_vkCreateShaderModule = NULL; +PFN_vkCreateShadersEXT glad_vkCreateShadersEXT = NULL; PFN_vkCreateSharedSwapchainsKHR glad_vkCreateSharedSwapchainsKHR = NULL; #if defined(VK_USE_PLATFORM_GGP) PFN_vkCreateStreamDescriptorSurfaceGGP glad_vkCreateStreamDescriptorSurfaceGGP = NULL; + #endif PFN_vkCreateSwapchainKHR glad_vkCreateSwapchainKHR = NULL; PFN_vkCreateValidationCacheEXT glad_vkCreateValidationCacheEXT = NULL; #if defined(VK_USE_PLATFORM_VI_NN) PFN_vkCreateViSurfaceNN glad_vkCreateViSurfaceNN = NULL; + #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) PFN_vkCreateWaylandSurfaceKHR glad_vkCreateWaylandSurfaceKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkCreateWin32SurfaceKHR glad_vkCreateWin32SurfaceKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) PFN_vkCreateXcbSurfaceKHR glad_vkCreateXcbSurfaceKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) PFN_vkCreateXlibSurfaceKHR glad_vkCreateXlibSurfaceKHR = NULL; + #endif PFN_vkDebugMarkerSetObjectNameEXT glad_vkDebugMarkerSetObjectNameEXT = NULL; PFN_vkDebugMarkerSetObjectTagEXT glad_vkDebugMarkerSetObjectTagEXT = NULL; PFN_vkDebugReportMessageEXT glad_vkDebugReportMessageEXT = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkDeferredOperationJoinKHR glad_vkDeferredOperationJoinKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkDestroyAccelerationStructureKHR glad_vkDestroyAccelerationStructureKHR = NULL; -#endif PFN_vkDestroyAccelerationStructureNV glad_vkDestroyAccelerationStructureNV = NULL; PFN_vkDestroyBuffer glad_vkDestroyBuffer = NULL; +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkDestroyBufferCollectionFUCHSIA glad_vkDestroyBufferCollectionFUCHSIA = NULL; + +#endif PFN_vkDestroyBufferView glad_vkDestroyBufferView = NULL; PFN_vkDestroyCommandPool glad_vkDestroyCommandPool = NULL; +PFN_vkDestroyCuFunctionNVX glad_vkDestroyCuFunctionNVX = NULL; +PFN_vkDestroyCuModuleNVX glad_vkDestroyCuModuleNVX = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkDestroyCudaFunctionNV glad_vkDestroyCudaFunctionNV = NULL; + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkDestroyCudaModuleNV glad_vkDestroyCudaModuleNV = NULL; + +#endif PFN_vkDestroyDebugReportCallbackEXT glad_vkDestroyDebugReportCallbackEXT = NULL; PFN_vkDestroyDebugUtilsMessengerEXT glad_vkDestroyDebugUtilsMessengerEXT = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkDestroyDeferredOperationKHR glad_vkDestroyDeferredOperationKHR = NULL; -#endif PFN_vkDestroyDescriptorPool glad_vkDestroyDescriptorPool = NULL; PFN_vkDestroyDescriptorSetLayout glad_vkDestroyDescriptorSetLayout = NULL; PFN_vkDestroyDescriptorUpdateTemplate glad_vkDestroyDescriptorUpdateTemplate = NULL; PFN_vkDestroyDescriptorUpdateTemplateKHR glad_vkDestroyDescriptorUpdateTemplateKHR = NULL; PFN_vkDestroyDevice glad_vkDestroyDevice = NULL; PFN_vkDestroyEvent glad_vkDestroyEvent = NULL; +PFN_vkDestroyExternalComputeQueueNV glad_vkDestroyExternalComputeQueueNV = NULL; PFN_vkDestroyFence glad_vkDestroyFence = NULL; PFN_vkDestroyFramebuffer glad_vkDestroyFramebuffer = NULL; PFN_vkDestroyImage glad_vkDestroyImage = NULL; PFN_vkDestroyImageView glad_vkDestroyImageView = NULL; +PFN_vkDestroyIndirectCommandsLayoutEXT glad_vkDestroyIndirectCommandsLayoutEXT = NULL; PFN_vkDestroyIndirectCommandsLayoutNV glad_vkDestroyIndirectCommandsLayoutNV = NULL; +PFN_vkDestroyIndirectExecutionSetEXT glad_vkDestroyIndirectExecutionSetEXT = NULL; PFN_vkDestroyInstance glad_vkDestroyInstance = NULL; +PFN_vkDestroyMicromapEXT glad_vkDestroyMicromapEXT = NULL; +PFN_vkDestroyOpticalFlowSessionNV glad_vkDestroyOpticalFlowSessionNV = NULL; PFN_vkDestroyPipeline glad_vkDestroyPipeline = NULL; +PFN_vkDestroyPipelineBinaryKHR glad_vkDestroyPipelineBinaryKHR = NULL; PFN_vkDestroyPipelineCache glad_vkDestroyPipelineCache = NULL; PFN_vkDestroyPipelineLayout glad_vkDestroyPipelineLayout = NULL; +PFN_vkDestroyPrivateDataSlot glad_vkDestroyPrivateDataSlot = NULL; PFN_vkDestroyPrivateDataSlotEXT glad_vkDestroyPrivateDataSlotEXT = NULL; PFN_vkDestroyQueryPool glad_vkDestroyQueryPool = NULL; PFN_vkDestroyRenderPass glad_vkDestroyRenderPass = NULL; @@ -583,6 +1036,7 @@ PFN_vkDestroySampler glad_vkDestroySampler = NULL; PFN_vkDestroySamplerYcbcrConversion glad_vkDestroySamplerYcbcrConversion = NULL; PFN_vkDestroySamplerYcbcrConversionKHR glad_vkDestroySamplerYcbcrConversionKHR = NULL; PFN_vkDestroySemaphore glad_vkDestroySemaphore = NULL; +PFN_vkDestroyShaderEXT glad_vkDestroyShaderEXT = NULL; PFN_vkDestroyShaderModule glad_vkDestroyShaderModule = NULL; PFN_vkDestroySurfaceKHR glad_vkDestroySurfaceKHR = NULL; PFN_vkDestroySwapchainKHR glad_vkDestroySwapchainKHR = NULL; @@ -599,20 +1053,26 @@ PFN_vkEnumeratePhysicalDeviceGroups glad_vkEnumeratePhysicalDeviceGroups = NULL; PFN_vkEnumeratePhysicalDeviceGroupsKHR glad_vkEnumeratePhysicalDeviceGroupsKHR = NULL; PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR glad_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR = NULL; PFN_vkEnumeratePhysicalDevices glad_vkEnumeratePhysicalDevices = NULL; +#if defined(VK_USE_PLATFORM_METAL_EXT) +PFN_vkExportMetalObjectsEXT glad_vkExportMetalObjectsEXT = NULL; + +#endif PFN_vkFlushMappedMemoryRanges glad_vkFlushMappedMemoryRanges = NULL; PFN_vkFreeCommandBuffers glad_vkFreeCommandBuffers = NULL; PFN_vkFreeDescriptorSets glad_vkFreeDescriptorSets = NULL; PFN_vkFreeMemory glad_vkFreeMemory = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkGetAccelerationStructureBuildSizesKHR glad_vkGetAccelerationStructureBuildSizesKHR = NULL; PFN_vkGetAccelerationStructureDeviceAddressKHR glad_vkGetAccelerationStructureDeviceAddressKHR = NULL; -#endif PFN_vkGetAccelerationStructureHandleNV glad_vkGetAccelerationStructureHandleNV = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) -PFN_vkGetAccelerationStructureMemoryRequirementsKHR glad_vkGetAccelerationStructureMemoryRequirementsKHR = NULL; -#endif PFN_vkGetAccelerationStructureMemoryRequirementsNV glad_vkGetAccelerationStructureMemoryRequirementsNV = NULL; +PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT glad_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT = NULL; #if defined(VK_USE_PLATFORM_ANDROID_KHR) PFN_vkGetAndroidHardwareBufferPropertiesANDROID glad_vkGetAndroidHardwareBufferPropertiesANDROID = NULL; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkGetBufferCollectionPropertiesFUCHSIA glad_vkGetBufferCollectionPropertiesFUCHSIA = NULL; + #endif PFN_vkGetBufferDeviceAddress glad_vkGetBufferDeviceAddress = NULL; PFN_vkGetBufferDeviceAddressEXT glad_vkGetBufferDeviceAddressEXT = NULL; @@ -622,75 +1082,142 @@ PFN_vkGetBufferMemoryRequirements2 glad_vkGetBufferMemoryRequirements2 = NULL; PFN_vkGetBufferMemoryRequirements2KHR glad_vkGetBufferMemoryRequirements2KHR = NULL; PFN_vkGetBufferOpaqueCaptureAddress glad_vkGetBufferOpaqueCaptureAddress = NULL; PFN_vkGetBufferOpaqueCaptureAddressKHR glad_vkGetBufferOpaqueCaptureAddressKHR = NULL; +PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT glad_vkGetBufferOpaqueCaptureDescriptorDataEXT = NULL; PFN_vkGetCalibratedTimestampsEXT glad_vkGetCalibratedTimestampsEXT = NULL; +PFN_vkGetCalibratedTimestampsKHR glad_vkGetCalibratedTimestampsKHR = NULL; +PFN_vkGetClusterAccelerationStructureBuildSizesNV glad_vkGetClusterAccelerationStructureBuildSizesNV = NULL; #if defined(VK_ENABLE_BETA_EXTENSIONS) -PFN_vkGetDeferredOperationMaxConcurrencyKHR glad_vkGetDeferredOperationMaxConcurrencyKHR = NULL; +PFN_vkGetCudaModuleCacheNV glad_vkGetCudaModuleCacheNV = NULL; + #endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkGetDeferredOperationMaxConcurrencyKHR glad_vkGetDeferredOperationMaxConcurrencyKHR = NULL; PFN_vkGetDeferredOperationResultKHR glad_vkGetDeferredOperationResultKHR = NULL; -#endif +PFN_vkGetDescriptorEXT glad_vkGetDescriptorEXT = NULL; +PFN_vkGetDescriptorSetHostMappingVALVE glad_vkGetDescriptorSetHostMappingVALVE = NULL; +PFN_vkGetDescriptorSetLayoutBindingOffsetEXT glad_vkGetDescriptorSetLayoutBindingOffsetEXT = NULL; +PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE glad_vkGetDescriptorSetLayoutHostMappingInfoVALVE = NULL; +PFN_vkGetDescriptorSetLayoutSizeEXT glad_vkGetDescriptorSetLayoutSizeEXT = NULL; PFN_vkGetDescriptorSetLayoutSupport glad_vkGetDescriptorSetLayoutSupport = NULL; PFN_vkGetDescriptorSetLayoutSupportKHR glad_vkGetDescriptorSetLayoutSupportKHR = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkGetDeviceAccelerationStructureCompatibilityKHR glad_vkGetDeviceAccelerationStructureCompatibilityKHR = NULL; -#endif +PFN_vkGetDeviceBufferMemoryRequirements glad_vkGetDeviceBufferMemoryRequirements = NULL; +PFN_vkGetDeviceBufferMemoryRequirementsKHR glad_vkGetDeviceBufferMemoryRequirementsKHR = NULL; +PFN_vkGetDeviceFaultInfoEXT glad_vkGetDeviceFaultInfoEXT = NULL; PFN_vkGetDeviceGroupPeerMemoryFeatures glad_vkGetDeviceGroupPeerMemoryFeatures = NULL; PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR glad_vkGetDeviceGroupPeerMemoryFeaturesKHR = NULL; PFN_vkGetDeviceGroupPresentCapabilitiesKHR glad_vkGetDeviceGroupPresentCapabilitiesKHR = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetDeviceGroupSurfacePresentModes2EXT glad_vkGetDeviceGroupSurfacePresentModes2EXT = NULL; + #endif PFN_vkGetDeviceGroupSurfacePresentModesKHR glad_vkGetDeviceGroupSurfacePresentModesKHR = NULL; +PFN_vkGetDeviceImageMemoryRequirements glad_vkGetDeviceImageMemoryRequirements = NULL; +PFN_vkGetDeviceImageMemoryRequirementsKHR glad_vkGetDeviceImageMemoryRequirementsKHR = NULL; +PFN_vkGetDeviceImageSparseMemoryRequirements glad_vkGetDeviceImageSparseMemoryRequirements = NULL; +PFN_vkGetDeviceImageSparseMemoryRequirementsKHR glad_vkGetDeviceImageSparseMemoryRequirementsKHR = NULL; +PFN_vkGetDeviceImageSubresourceLayout glad_vkGetDeviceImageSubresourceLayout = NULL; +PFN_vkGetDeviceImageSubresourceLayoutKHR glad_vkGetDeviceImageSubresourceLayoutKHR = NULL; PFN_vkGetDeviceMemoryCommitment glad_vkGetDeviceMemoryCommitment = NULL; PFN_vkGetDeviceMemoryOpaqueCaptureAddress glad_vkGetDeviceMemoryOpaqueCaptureAddress = NULL; PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR glad_vkGetDeviceMemoryOpaqueCaptureAddressKHR = NULL; +PFN_vkGetDeviceMicromapCompatibilityEXT glad_vkGetDeviceMicromapCompatibilityEXT = NULL; PFN_vkGetDeviceProcAddr glad_vkGetDeviceProcAddr = NULL; PFN_vkGetDeviceQueue glad_vkGetDeviceQueue = NULL; PFN_vkGetDeviceQueue2 glad_vkGetDeviceQueue2 = NULL; +PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI glad_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI = NULL; PFN_vkGetDisplayModeProperties2KHR glad_vkGetDisplayModeProperties2KHR = NULL; PFN_vkGetDisplayModePropertiesKHR glad_vkGetDisplayModePropertiesKHR = NULL; PFN_vkGetDisplayPlaneCapabilities2KHR glad_vkGetDisplayPlaneCapabilities2KHR = NULL; PFN_vkGetDisplayPlaneCapabilitiesKHR glad_vkGetDisplayPlaneCapabilitiesKHR = NULL; PFN_vkGetDisplayPlaneSupportedDisplaysKHR glad_vkGetDisplayPlaneSupportedDisplaysKHR = NULL; +PFN_vkGetDrmDisplayEXT glad_vkGetDrmDisplayEXT = NULL; +PFN_vkGetDynamicRenderingTilePropertiesQCOM glad_vkGetDynamicRenderingTilePropertiesQCOM = NULL; PFN_vkGetEventStatus glad_vkGetEventStatus = NULL; +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkGetExecutionGraphPipelineNodeIndexAMDX glad_vkGetExecutionGraphPipelineNodeIndexAMDX = NULL; + +#endif +#if defined(VK_ENABLE_BETA_EXTENSIONS) +PFN_vkGetExecutionGraphPipelineScratchSizeAMDX glad_vkGetExecutionGraphPipelineScratchSizeAMDX = NULL; + +#endif +PFN_vkGetExternalComputeQueueDataNV glad_vkGetExternalComputeQueueDataNV = NULL; PFN_vkGetFenceFdKHR glad_vkGetFenceFdKHR = NULL; PFN_vkGetFenceStatus glad_vkGetFenceStatus = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetFenceWin32HandleKHR glad_vkGetFenceWin32HandleKHR = NULL; + #endif +PFN_vkGetFramebufferTilePropertiesQCOM glad_vkGetFramebufferTilePropertiesQCOM = NULL; +PFN_vkGetGeneratedCommandsMemoryRequirementsEXT glad_vkGetGeneratedCommandsMemoryRequirementsEXT = NULL; PFN_vkGetGeneratedCommandsMemoryRequirementsNV glad_vkGetGeneratedCommandsMemoryRequirementsNV = NULL; PFN_vkGetImageDrmFormatModifierPropertiesEXT glad_vkGetImageDrmFormatModifierPropertiesEXT = NULL; PFN_vkGetImageMemoryRequirements glad_vkGetImageMemoryRequirements = NULL; PFN_vkGetImageMemoryRequirements2 glad_vkGetImageMemoryRequirements2 = NULL; PFN_vkGetImageMemoryRequirements2KHR glad_vkGetImageMemoryRequirements2KHR = NULL; +PFN_vkGetImageOpaqueCaptureDescriptorDataEXT glad_vkGetImageOpaqueCaptureDescriptorDataEXT = NULL; PFN_vkGetImageSparseMemoryRequirements glad_vkGetImageSparseMemoryRequirements = NULL; PFN_vkGetImageSparseMemoryRequirements2 glad_vkGetImageSparseMemoryRequirements2 = NULL; PFN_vkGetImageSparseMemoryRequirements2KHR glad_vkGetImageSparseMemoryRequirements2KHR = NULL; PFN_vkGetImageSubresourceLayout glad_vkGetImageSubresourceLayout = NULL; +PFN_vkGetImageSubresourceLayout2 glad_vkGetImageSubresourceLayout2 = NULL; +PFN_vkGetImageSubresourceLayout2EXT glad_vkGetImageSubresourceLayout2EXT = NULL; +PFN_vkGetImageSubresourceLayout2KHR glad_vkGetImageSubresourceLayout2KHR = NULL; PFN_vkGetImageViewAddressNVX glad_vkGetImageViewAddressNVX = NULL; +PFN_vkGetImageViewHandle64NVX glad_vkGetImageViewHandle64NVX = NULL; PFN_vkGetImageViewHandleNVX glad_vkGetImageViewHandleNVX = NULL; +PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT glad_vkGetImageViewOpaqueCaptureDescriptorDataEXT = NULL; PFN_vkGetInstanceProcAddr glad_vkGetInstanceProcAddr = NULL; +PFN_vkGetLatencyTimingsNV glad_vkGetLatencyTimingsNV = NULL; #if defined(VK_USE_PLATFORM_ANDROID_KHR) PFN_vkGetMemoryAndroidHardwareBufferANDROID glad_vkGetMemoryAndroidHardwareBufferANDROID = NULL; + #endif PFN_vkGetMemoryFdKHR glad_vkGetMemoryFdKHR = NULL; PFN_vkGetMemoryFdPropertiesKHR glad_vkGetMemoryFdPropertiesKHR = NULL; PFN_vkGetMemoryHostPointerPropertiesEXT glad_vkGetMemoryHostPointerPropertiesEXT = NULL; +#if defined(VK_USE_PLATFORM_METAL_EXT) +PFN_vkGetMemoryMetalHandleEXT glad_vkGetMemoryMetalHandleEXT = NULL; + +#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +PFN_vkGetMemoryMetalHandlePropertiesEXT glad_vkGetMemoryMetalHandlePropertiesEXT = NULL; + +#endif +PFN_vkGetMemoryRemoteAddressNV glad_vkGetMemoryRemoteAddressNV = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetMemoryWin32HandleKHR glad_vkGetMemoryWin32HandleKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetMemoryWin32HandleNV glad_vkGetMemoryWin32HandleNV = NULL; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetMemoryWin32HandlePropertiesKHR glad_vkGetMemoryWin32HandlePropertiesKHR = NULL; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkGetMemoryZirconHandleFUCHSIA glad_vkGetMemoryZirconHandleFUCHSIA = NULL; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA glad_vkGetMemoryZirconHandlePropertiesFUCHSIA = NULL; + #endif +PFN_vkGetMicromapBuildSizesEXT glad_vkGetMicromapBuildSizesEXT = NULL; +PFN_vkGetPartitionedAccelerationStructuresBuildSizesNV glad_vkGetPartitionedAccelerationStructuresBuildSizesNV = NULL; PFN_vkGetPastPresentationTimingGOOGLE glad_vkGetPastPresentationTimingGOOGLE = NULL; PFN_vkGetPerformanceParameterINTEL glad_vkGetPerformanceParameterINTEL = NULL; PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT glad_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT = NULL; +PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR glad_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR = NULL; +PFN_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV glad_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV = NULL; +PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR = NULL; PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV = NULL; +PFN_vkGetPhysicalDeviceCooperativeVectorPropertiesNV glad_vkGetPhysicalDeviceCooperativeVectorPropertiesNV = NULL; #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT glad_vkGetPhysicalDeviceDirectFBPresentationSupportEXT = NULL; + #endif PFN_vkGetPhysicalDeviceDisplayPlaneProperties2KHR glad_vkGetPhysicalDeviceDisplayPlaneProperties2KHR = NULL; PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR glad_vkGetPhysicalDeviceDisplayPlanePropertiesKHR = NULL; @@ -709,6 +1236,7 @@ PFN_vkGetPhysicalDeviceFeatures2KHR glad_vkGetPhysicalDeviceFeatures2KHR = NULL; PFN_vkGetPhysicalDeviceFormatProperties glad_vkGetPhysicalDeviceFormatProperties = NULL; PFN_vkGetPhysicalDeviceFormatProperties2 glad_vkGetPhysicalDeviceFormatProperties2 = NULL; PFN_vkGetPhysicalDeviceFormatProperties2KHR glad_vkGetPhysicalDeviceFormatProperties2KHR = NULL; +PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR glad_vkGetPhysicalDeviceFragmentShadingRatesKHR = NULL; PFN_vkGetPhysicalDeviceImageFormatProperties glad_vkGetPhysicalDeviceImageFormatProperties = NULL; PFN_vkGetPhysicalDeviceImageFormatProperties2 glad_vkGetPhysicalDeviceImageFormatProperties2 = NULL; PFN_vkGetPhysicalDeviceImageFormatProperties2KHR glad_vkGetPhysicalDeviceImageFormatProperties2KHR = NULL; @@ -716,6 +1244,7 @@ PFN_vkGetPhysicalDeviceMemoryProperties glad_vkGetPhysicalDeviceMemoryProperties PFN_vkGetPhysicalDeviceMemoryProperties2 glad_vkGetPhysicalDeviceMemoryProperties2 = NULL; PFN_vkGetPhysicalDeviceMemoryProperties2KHR glad_vkGetPhysicalDeviceMemoryProperties2KHR = NULL; PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT glad_vkGetPhysicalDeviceMultisamplePropertiesEXT = NULL; +PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV glad_vkGetPhysicalDeviceOpticalFlowImageFormatsNV = NULL; PFN_vkGetPhysicalDevicePresentRectanglesKHR glad_vkGetPhysicalDevicePresentRectanglesKHR = NULL; PFN_vkGetPhysicalDeviceProperties glad_vkGetPhysicalDeviceProperties = NULL; PFN_vkGetPhysicalDeviceProperties2 glad_vkGetPhysicalDeviceProperties2 = NULL; @@ -724,6 +1253,10 @@ PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR glad_vkGetPhysicalDe PFN_vkGetPhysicalDeviceQueueFamilyProperties glad_vkGetPhysicalDeviceQueueFamilyProperties = NULL; PFN_vkGetPhysicalDeviceQueueFamilyProperties2 glad_vkGetPhysicalDeviceQueueFamilyProperties2 = NULL; PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR glad_vkGetPhysicalDeviceQueueFamilyProperties2KHR = NULL; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX glad_vkGetPhysicalDeviceScreenPresentationSupportQNX = NULL; + +#endif PFN_vkGetPhysicalDeviceSparseImageFormatProperties glad_vkGetPhysicalDeviceSparseImageFormatProperties = NULL; PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 glad_vkGetPhysicalDeviceSparseImageFormatProperties2 = NULL; PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR glad_vkGetPhysicalDeviceSparseImageFormatProperties2KHR = NULL; @@ -735,81 +1268,126 @@ PFN_vkGetPhysicalDeviceSurfaceFormats2KHR glad_vkGetPhysicalDeviceSurfaceFormats PFN_vkGetPhysicalDeviceSurfaceFormatsKHR glad_vkGetPhysicalDeviceSurfaceFormatsKHR = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT glad_vkGetPhysicalDeviceSurfacePresentModes2EXT = NULL; + #endif PFN_vkGetPhysicalDeviceSurfacePresentModesKHR glad_vkGetPhysicalDeviceSurfacePresentModesKHR = NULL; PFN_vkGetPhysicalDeviceSurfaceSupportKHR glad_vkGetPhysicalDeviceSurfaceSupportKHR = NULL; +PFN_vkGetPhysicalDeviceToolProperties glad_vkGetPhysicalDeviceToolProperties = NULL; PFN_vkGetPhysicalDeviceToolPropertiesEXT glad_vkGetPhysicalDeviceToolPropertiesEXT = NULL; #if defined(VK_USE_PLATFORM_WAYLAND_KHR) PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR glad_vkGetPhysicalDeviceWaylandPresentationSupportKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR glad_vkGetPhysicalDeviceWin32PresentationSupportKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR glad_vkGetPhysicalDeviceXcbPresentationSupportKHR = NULL; + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR glad_vkGetPhysicalDeviceXlibPresentationSupportKHR = NULL; + #endif +PFN_vkGetPipelineBinaryDataKHR glad_vkGetPipelineBinaryDataKHR = NULL; PFN_vkGetPipelineCacheData glad_vkGetPipelineCacheData = NULL; PFN_vkGetPipelineExecutableInternalRepresentationsKHR glad_vkGetPipelineExecutableInternalRepresentationsKHR = NULL; PFN_vkGetPipelineExecutablePropertiesKHR glad_vkGetPipelineExecutablePropertiesKHR = NULL; PFN_vkGetPipelineExecutableStatisticsKHR glad_vkGetPipelineExecutableStatisticsKHR = NULL; +PFN_vkGetPipelineIndirectDeviceAddressNV glad_vkGetPipelineIndirectDeviceAddressNV = NULL; +PFN_vkGetPipelineIndirectMemoryRequirementsNV glad_vkGetPipelineIndirectMemoryRequirementsNV = NULL; +PFN_vkGetPipelineKeyKHR glad_vkGetPipelineKeyKHR = NULL; +PFN_vkGetPipelinePropertiesEXT glad_vkGetPipelinePropertiesEXT = NULL; +PFN_vkGetPrivateData glad_vkGetPrivateData = NULL; PFN_vkGetPrivateDataEXT glad_vkGetPrivateDataEXT = NULL; PFN_vkGetQueryPoolResults glad_vkGetQueryPoolResults = NULL; +PFN_vkGetQueueCheckpointData2NV glad_vkGetQueueCheckpointData2NV = NULL; PFN_vkGetQueueCheckpointDataNV glad_vkGetQueueCheckpointDataNV = NULL; #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) PFN_vkGetRandROutputDisplayEXT glad_vkGetRandROutputDisplayEXT = NULL; + #endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR glad_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR = NULL; -#endif -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkGetRayTracingShaderGroupHandlesKHR glad_vkGetRayTracingShaderGroupHandlesKHR = NULL; -#endif PFN_vkGetRayTracingShaderGroupHandlesNV glad_vkGetRayTracingShaderGroupHandlesNV = NULL; +PFN_vkGetRayTracingShaderGroupStackSizeKHR glad_vkGetRayTracingShaderGroupStackSizeKHR = NULL; PFN_vkGetRefreshCycleDurationGOOGLE glad_vkGetRefreshCycleDurationGOOGLE = NULL; PFN_vkGetRenderAreaGranularity glad_vkGetRenderAreaGranularity = NULL; +PFN_vkGetRenderingAreaGranularity glad_vkGetRenderingAreaGranularity = NULL; +PFN_vkGetRenderingAreaGranularityKHR glad_vkGetRenderingAreaGranularityKHR = NULL; +PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT glad_vkGetSamplerOpaqueCaptureDescriptorDataEXT = NULL; +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +PFN_vkGetScreenBufferPropertiesQNX glad_vkGetScreenBufferPropertiesQNX = NULL; + +#endif PFN_vkGetSemaphoreCounterValue glad_vkGetSemaphoreCounterValue = NULL; PFN_vkGetSemaphoreCounterValueKHR glad_vkGetSemaphoreCounterValueKHR = NULL; PFN_vkGetSemaphoreFdKHR glad_vkGetSemaphoreFdKHR = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkGetSemaphoreWin32HandleKHR glad_vkGetSemaphoreWin32HandleKHR = NULL; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkGetSemaphoreZirconHandleFUCHSIA glad_vkGetSemaphoreZirconHandleFUCHSIA = NULL; + #endif +PFN_vkGetShaderBinaryDataEXT glad_vkGetShaderBinaryDataEXT = NULL; PFN_vkGetShaderInfoAMD glad_vkGetShaderInfoAMD = NULL; +PFN_vkGetShaderModuleCreateInfoIdentifierEXT glad_vkGetShaderModuleCreateInfoIdentifierEXT = NULL; +PFN_vkGetShaderModuleIdentifierEXT glad_vkGetShaderModuleIdentifierEXT = NULL; PFN_vkGetSwapchainCounterEXT glad_vkGetSwapchainCounterEXT = NULL; PFN_vkGetSwapchainImagesKHR glad_vkGetSwapchainImagesKHR = NULL; PFN_vkGetSwapchainStatusKHR glad_vkGetSwapchainStatusKHR = NULL; PFN_vkGetValidationCacheDataEXT glad_vkGetValidationCacheDataEXT = NULL; +#if defined(VK_USE_PLATFORM_WIN32_KHR) +PFN_vkGetWinrtDisplayNV glad_vkGetWinrtDisplayNV = NULL; + +#endif PFN_vkImportFenceFdKHR glad_vkImportFenceFdKHR = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkImportFenceWin32HandleKHR glad_vkImportFenceWin32HandleKHR = NULL; + #endif PFN_vkImportSemaphoreFdKHR glad_vkImportSemaphoreFdKHR = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkImportSemaphoreWin32HandleKHR glad_vkImportSemaphoreWin32HandleKHR = NULL; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkImportSemaphoreZirconHandleFUCHSIA glad_vkImportSemaphoreZirconHandleFUCHSIA = NULL; + #endif PFN_vkInitializePerformanceApiINTEL glad_vkInitializePerformanceApiINTEL = NULL; PFN_vkInvalidateMappedMemoryRanges glad_vkInvalidateMappedMemoryRanges = NULL; +PFN_vkLatencySleepNV glad_vkLatencySleepNV = NULL; PFN_vkMapMemory glad_vkMapMemory = NULL; +PFN_vkMapMemory2 glad_vkMapMemory2 = NULL; +PFN_vkMapMemory2KHR glad_vkMapMemory2KHR = NULL; PFN_vkMergePipelineCaches glad_vkMergePipelineCaches = NULL; PFN_vkMergeValidationCachesEXT glad_vkMergeValidationCachesEXT = NULL; PFN_vkQueueBeginDebugUtilsLabelEXT glad_vkQueueBeginDebugUtilsLabelEXT = NULL; PFN_vkQueueBindSparse glad_vkQueueBindSparse = NULL; PFN_vkQueueEndDebugUtilsLabelEXT glad_vkQueueEndDebugUtilsLabelEXT = NULL; PFN_vkQueueInsertDebugUtilsLabelEXT glad_vkQueueInsertDebugUtilsLabelEXT = NULL; +PFN_vkQueueNotifyOutOfBandNV glad_vkQueueNotifyOutOfBandNV = NULL; PFN_vkQueuePresentKHR glad_vkQueuePresentKHR = NULL; PFN_vkQueueSetPerformanceConfigurationINTEL glad_vkQueueSetPerformanceConfigurationINTEL = NULL; PFN_vkQueueSubmit glad_vkQueueSubmit = NULL; +PFN_vkQueueSubmit2 glad_vkQueueSubmit2 = NULL; +PFN_vkQueueSubmit2KHR glad_vkQueueSubmit2KHR = NULL; PFN_vkQueueWaitIdle glad_vkQueueWaitIdle = NULL; PFN_vkRegisterDeviceEventEXT glad_vkRegisterDeviceEventEXT = NULL; PFN_vkRegisterDisplayEventEXT glad_vkRegisterDisplayEventEXT = NULL; +PFN_vkReleaseCapturedPipelineDataKHR glad_vkReleaseCapturedPipelineDataKHR = NULL; PFN_vkReleaseDisplayEXT glad_vkReleaseDisplayEXT = NULL; #if defined(VK_USE_PLATFORM_WIN32_KHR) PFN_vkReleaseFullScreenExclusiveModeEXT glad_vkReleaseFullScreenExclusiveModeEXT = NULL; + #endif PFN_vkReleasePerformanceConfigurationINTEL glad_vkReleasePerformanceConfigurationINTEL = NULL; PFN_vkReleaseProfilingLockKHR glad_vkReleaseProfilingLockKHR = NULL; +PFN_vkReleaseSwapchainImagesEXT glad_vkReleaseSwapchainImagesEXT = NULL; PFN_vkResetCommandBuffer glad_vkResetCommandBuffer = NULL; PFN_vkResetCommandPool glad_vkResetCommandPool = NULL; PFN_vkResetDescriptorPool glad_vkResetDescriptorPool = NULL; @@ -817,28 +1395,46 @@ PFN_vkResetEvent glad_vkResetEvent = NULL; PFN_vkResetFences glad_vkResetFences = NULL; PFN_vkResetQueryPool glad_vkResetQueryPool = NULL; PFN_vkResetQueryPoolEXT glad_vkResetQueryPoolEXT = NULL; +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA glad_vkSetBufferCollectionBufferConstraintsFUCHSIA = NULL; + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +PFN_vkSetBufferCollectionImageConstraintsFUCHSIA glad_vkSetBufferCollectionImageConstraintsFUCHSIA = NULL; + +#endif PFN_vkSetDebugUtilsObjectNameEXT glad_vkSetDebugUtilsObjectNameEXT = NULL; PFN_vkSetDebugUtilsObjectTagEXT glad_vkSetDebugUtilsObjectTagEXT = NULL; +PFN_vkSetDeviceMemoryPriorityEXT glad_vkSetDeviceMemoryPriorityEXT = NULL; PFN_vkSetEvent glad_vkSetEvent = NULL; PFN_vkSetHdrMetadataEXT glad_vkSetHdrMetadataEXT = NULL; +PFN_vkSetLatencyMarkerNV glad_vkSetLatencyMarkerNV = NULL; +PFN_vkSetLatencySleepModeNV glad_vkSetLatencySleepModeNV = NULL; PFN_vkSetLocalDimmingAMD glad_vkSetLocalDimmingAMD = NULL; +PFN_vkSetPrivateData glad_vkSetPrivateData = NULL; PFN_vkSetPrivateDataEXT glad_vkSetPrivateDataEXT = NULL; PFN_vkSignalSemaphore glad_vkSignalSemaphore = NULL; PFN_vkSignalSemaphoreKHR glad_vkSignalSemaphoreKHR = NULL; PFN_vkSubmitDebugUtilsMessageEXT glad_vkSubmitDebugUtilsMessageEXT = NULL; +PFN_vkTransitionImageLayout glad_vkTransitionImageLayout = NULL; +PFN_vkTransitionImageLayoutEXT glad_vkTransitionImageLayoutEXT = NULL; PFN_vkTrimCommandPool glad_vkTrimCommandPool = NULL; PFN_vkTrimCommandPoolKHR glad_vkTrimCommandPoolKHR = NULL; PFN_vkUninitializePerformanceApiINTEL glad_vkUninitializePerformanceApiINTEL = NULL; PFN_vkUnmapMemory glad_vkUnmapMemory = NULL; +PFN_vkUnmapMemory2 glad_vkUnmapMemory2 = NULL; +PFN_vkUnmapMemory2KHR glad_vkUnmapMemory2KHR = NULL; PFN_vkUpdateDescriptorSetWithTemplate glad_vkUpdateDescriptorSetWithTemplate = NULL; PFN_vkUpdateDescriptorSetWithTemplateKHR glad_vkUpdateDescriptorSetWithTemplateKHR = NULL; PFN_vkUpdateDescriptorSets glad_vkUpdateDescriptorSets = NULL; +PFN_vkUpdateIndirectExecutionSetPipelineEXT glad_vkUpdateIndirectExecutionSetPipelineEXT = NULL; +PFN_vkUpdateIndirectExecutionSetShaderEXT glad_vkUpdateIndirectExecutionSetShaderEXT = NULL; PFN_vkWaitForFences glad_vkWaitForFences = NULL; +PFN_vkWaitForPresentKHR glad_vkWaitForPresentKHR = NULL; PFN_vkWaitSemaphores glad_vkWaitSemaphores = NULL; PFN_vkWaitSemaphoresKHR glad_vkWaitSemaphoresKHR = NULL; -#if defined(VK_ENABLE_BETA_EXTENSIONS) PFN_vkWriteAccelerationStructuresPropertiesKHR glad_vkWriteAccelerationStructuresPropertiesKHR = NULL; -#endif +PFN_vkWriteMicromapsPropertiesEXT glad_vkWriteMicromapsPropertiesEXT = NULL; static void glad_vk_load_VK_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) { @@ -1028,8 +1624,88 @@ static void glad_vk_load_VK_VERSION_1_2( GLADuserptrloadfunc load, void* userptr glad_vkSignalSemaphore = (PFN_vkSignalSemaphore) load(userptr, "vkSignalSemaphore"); glad_vkWaitSemaphores = (PFN_vkWaitSemaphores) load(userptr, "vkWaitSemaphores"); } +static void glad_vk_load_VK_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_VERSION_1_3) return; + glad_vkCmdBeginRendering = (PFN_vkCmdBeginRendering) load(userptr, "vkCmdBeginRendering"); + glad_vkCmdBindVertexBuffers2 = (PFN_vkCmdBindVertexBuffers2) load(userptr, "vkCmdBindVertexBuffers2"); + glad_vkCmdBlitImage2 = (PFN_vkCmdBlitImage2) load(userptr, "vkCmdBlitImage2"); + glad_vkCmdCopyBuffer2 = (PFN_vkCmdCopyBuffer2) load(userptr, "vkCmdCopyBuffer2"); + glad_vkCmdCopyBufferToImage2 = (PFN_vkCmdCopyBufferToImage2) load(userptr, "vkCmdCopyBufferToImage2"); + glad_vkCmdCopyImage2 = (PFN_vkCmdCopyImage2) load(userptr, "vkCmdCopyImage2"); + glad_vkCmdCopyImageToBuffer2 = (PFN_vkCmdCopyImageToBuffer2) load(userptr, "vkCmdCopyImageToBuffer2"); + glad_vkCmdEndRendering = (PFN_vkCmdEndRendering) load(userptr, "vkCmdEndRendering"); + glad_vkCmdPipelineBarrier2 = (PFN_vkCmdPipelineBarrier2) load(userptr, "vkCmdPipelineBarrier2"); + glad_vkCmdResetEvent2 = (PFN_vkCmdResetEvent2) load(userptr, "vkCmdResetEvent2"); + glad_vkCmdResolveImage2 = (PFN_vkCmdResolveImage2) load(userptr, "vkCmdResolveImage2"); + glad_vkCmdSetCullMode = (PFN_vkCmdSetCullMode) load(userptr, "vkCmdSetCullMode"); + glad_vkCmdSetDepthBiasEnable = (PFN_vkCmdSetDepthBiasEnable) load(userptr, "vkCmdSetDepthBiasEnable"); + glad_vkCmdSetDepthBoundsTestEnable = (PFN_vkCmdSetDepthBoundsTestEnable) load(userptr, "vkCmdSetDepthBoundsTestEnable"); + glad_vkCmdSetDepthCompareOp = (PFN_vkCmdSetDepthCompareOp) load(userptr, "vkCmdSetDepthCompareOp"); + glad_vkCmdSetDepthTestEnable = (PFN_vkCmdSetDepthTestEnable) load(userptr, "vkCmdSetDepthTestEnable"); + glad_vkCmdSetDepthWriteEnable = (PFN_vkCmdSetDepthWriteEnable) load(userptr, "vkCmdSetDepthWriteEnable"); + glad_vkCmdSetEvent2 = (PFN_vkCmdSetEvent2) load(userptr, "vkCmdSetEvent2"); + glad_vkCmdSetFrontFace = (PFN_vkCmdSetFrontFace) load(userptr, "vkCmdSetFrontFace"); + glad_vkCmdSetPrimitiveRestartEnable = (PFN_vkCmdSetPrimitiveRestartEnable) load(userptr, "vkCmdSetPrimitiveRestartEnable"); + glad_vkCmdSetPrimitiveTopology = (PFN_vkCmdSetPrimitiveTopology) load(userptr, "vkCmdSetPrimitiveTopology"); + glad_vkCmdSetRasterizerDiscardEnable = (PFN_vkCmdSetRasterizerDiscardEnable) load(userptr, "vkCmdSetRasterizerDiscardEnable"); + glad_vkCmdSetScissorWithCount = (PFN_vkCmdSetScissorWithCount) load(userptr, "vkCmdSetScissorWithCount"); + glad_vkCmdSetStencilOp = (PFN_vkCmdSetStencilOp) load(userptr, "vkCmdSetStencilOp"); + glad_vkCmdSetStencilTestEnable = (PFN_vkCmdSetStencilTestEnable) load(userptr, "vkCmdSetStencilTestEnable"); + glad_vkCmdSetViewportWithCount = (PFN_vkCmdSetViewportWithCount) load(userptr, "vkCmdSetViewportWithCount"); + glad_vkCmdWaitEvents2 = (PFN_vkCmdWaitEvents2) load(userptr, "vkCmdWaitEvents2"); + glad_vkCmdWriteTimestamp2 = (PFN_vkCmdWriteTimestamp2) load(userptr, "vkCmdWriteTimestamp2"); + glad_vkCreatePrivateDataSlot = (PFN_vkCreatePrivateDataSlot) load(userptr, "vkCreatePrivateDataSlot"); + glad_vkDestroyPrivateDataSlot = (PFN_vkDestroyPrivateDataSlot) load(userptr, "vkDestroyPrivateDataSlot"); + glad_vkGetDeviceBufferMemoryRequirements = (PFN_vkGetDeviceBufferMemoryRequirements) load(userptr, "vkGetDeviceBufferMemoryRequirements"); + glad_vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements) load(userptr, "vkGetDeviceImageMemoryRequirements"); + glad_vkGetDeviceImageSparseMemoryRequirements = (PFN_vkGetDeviceImageSparseMemoryRequirements) load(userptr, "vkGetDeviceImageSparseMemoryRequirements"); + glad_vkGetPhysicalDeviceToolProperties = (PFN_vkGetPhysicalDeviceToolProperties) load(userptr, "vkGetPhysicalDeviceToolProperties"); + glad_vkGetPrivateData = (PFN_vkGetPrivateData) load(userptr, "vkGetPrivateData"); + glad_vkQueueSubmit2 = (PFN_vkQueueSubmit2) load(userptr, "vkQueueSubmit2"); + glad_vkSetPrivateData = (PFN_vkSetPrivateData) load(userptr, "vkSetPrivateData"); +} +static void glad_vk_load_VK_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_VERSION_1_4) return; + glad_vkCmdBindDescriptorSets2 = (PFN_vkCmdBindDescriptorSets2) load(userptr, "vkCmdBindDescriptorSets2"); + glad_vkCmdBindIndexBuffer2 = (PFN_vkCmdBindIndexBuffer2) load(userptr, "vkCmdBindIndexBuffer2"); + glad_vkCmdPushConstants2 = (PFN_vkCmdPushConstants2) load(userptr, "vkCmdPushConstants2"); + glad_vkCmdPushDescriptorSet = (PFN_vkCmdPushDescriptorSet) load(userptr, "vkCmdPushDescriptorSet"); + glad_vkCmdPushDescriptorSet2 = (PFN_vkCmdPushDescriptorSet2) load(userptr, "vkCmdPushDescriptorSet2"); + glad_vkCmdPushDescriptorSetWithTemplate = (PFN_vkCmdPushDescriptorSetWithTemplate) load(userptr, "vkCmdPushDescriptorSetWithTemplate"); + glad_vkCmdPushDescriptorSetWithTemplate2 = (PFN_vkCmdPushDescriptorSetWithTemplate2) load(userptr, "vkCmdPushDescriptorSetWithTemplate2"); + glad_vkCmdSetLineStipple = (PFN_vkCmdSetLineStipple) load(userptr, "vkCmdSetLineStipple"); + glad_vkCmdSetRenderingAttachmentLocations = (PFN_vkCmdSetRenderingAttachmentLocations) load(userptr, "vkCmdSetRenderingAttachmentLocations"); + glad_vkCmdSetRenderingInputAttachmentIndices = (PFN_vkCmdSetRenderingInputAttachmentIndices) load(userptr, "vkCmdSetRenderingInputAttachmentIndices"); + glad_vkCopyImageToImage = (PFN_vkCopyImageToImage) load(userptr, "vkCopyImageToImage"); + glad_vkCopyImageToMemory = (PFN_vkCopyImageToMemory) load(userptr, "vkCopyImageToMemory"); + glad_vkCopyMemoryToImage = (PFN_vkCopyMemoryToImage) load(userptr, "vkCopyMemoryToImage"); + glad_vkGetDeviceImageSubresourceLayout = (PFN_vkGetDeviceImageSubresourceLayout) load(userptr, "vkGetDeviceImageSubresourceLayout"); + glad_vkGetImageSubresourceLayout2 = (PFN_vkGetImageSubresourceLayout2) load(userptr, "vkGetImageSubresourceLayout2"); + glad_vkGetRenderingAreaGranularity = (PFN_vkGetRenderingAreaGranularity) load(userptr, "vkGetRenderingAreaGranularity"); + glad_vkMapMemory2 = (PFN_vkMapMemory2) load(userptr, "vkMapMemory2"); + glad_vkTransitionImageLayout = (PFN_vkTransitionImageLayout) load(userptr, "vkTransitionImageLayout"); + glad_vkUnmapMemory2 = (PFN_vkUnmapMemory2) load(userptr, "vkUnmapMemory2"); +} +#if defined(VK_ENABLE_BETA_EXTENSIONS) +static void glad_vk_load_VK_AMDX_shader_enqueue( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_AMDX_shader_enqueue) return; + glad_vkCmdDispatchGraphAMDX = (PFN_vkCmdDispatchGraphAMDX) load(userptr, "vkCmdDispatchGraphAMDX"); + glad_vkCmdDispatchGraphIndirectAMDX = (PFN_vkCmdDispatchGraphIndirectAMDX) load(userptr, "vkCmdDispatchGraphIndirectAMDX"); + glad_vkCmdDispatchGraphIndirectCountAMDX = (PFN_vkCmdDispatchGraphIndirectCountAMDX) load(userptr, "vkCmdDispatchGraphIndirectCountAMDX"); + glad_vkCmdInitializeGraphScratchMemoryAMDX = (PFN_vkCmdInitializeGraphScratchMemoryAMDX) load(userptr, "vkCmdInitializeGraphScratchMemoryAMDX"); + glad_vkCreateExecutionGraphPipelinesAMDX = (PFN_vkCreateExecutionGraphPipelinesAMDX) load(userptr, "vkCreateExecutionGraphPipelinesAMDX"); + glad_vkGetExecutionGraphPipelineNodeIndexAMDX = (PFN_vkGetExecutionGraphPipelineNodeIndexAMDX) load(userptr, "vkGetExecutionGraphPipelineNodeIndexAMDX"); + glad_vkGetExecutionGraphPipelineScratchSizeAMDX = (PFN_vkGetExecutionGraphPipelineScratchSizeAMDX) load(userptr, "vkGetExecutionGraphPipelineScratchSizeAMDX"); +} + +#endif +static void glad_vk_load_VK_AMD_anti_lag( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_AMD_anti_lag) return; + glad_vkAntiLagUpdateAMD = (PFN_vkAntiLagUpdateAMD) load(userptr, "vkAntiLagUpdateAMD"); +} static void glad_vk_load_VK_AMD_buffer_marker( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_AMD_buffer_marker) return; + glad_vkCmdWriteBufferMarker2AMD = (PFN_vkCmdWriteBufferMarker2AMD) load(userptr, "vkCmdWriteBufferMarker2AMD"); glad_vkCmdWriteBufferMarkerAMD = (PFN_vkCmdWriteBufferMarkerAMD) load(userptr, "vkCmdWriteBufferMarkerAMD"); } static void glad_vk_load_VK_AMD_display_native_hdr( GLADuserptrloadfunc load, void* userptr) { @@ -1051,14 +1727,25 @@ static void glad_vk_load_VK_ANDROID_external_memory_android_hardware_buffer( GLA glad_vkGetAndroidHardwareBufferPropertiesANDROID = (PFN_vkGetAndroidHardwareBufferPropertiesANDROID) load(userptr, "vkGetAndroidHardwareBufferPropertiesANDROID"); glad_vkGetMemoryAndroidHardwareBufferANDROID = (PFN_vkGetMemoryAndroidHardwareBufferANDROID) load(userptr, "vkGetMemoryAndroidHardwareBufferANDROID"); } + #endif +static void glad_vk_load_VK_EXT_acquire_drm_display( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_acquire_drm_display) return; + glad_vkAcquireDrmDisplayEXT = (PFN_vkAcquireDrmDisplayEXT) load(userptr, "vkAcquireDrmDisplayEXT"); + glad_vkGetDrmDisplayEXT = (PFN_vkGetDrmDisplayEXT) load(userptr, "vkGetDrmDisplayEXT"); +} #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) static void glad_vk_load_VK_EXT_acquire_xlib_display( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_acquire_xlib_display) return; glad_vkAcquireXlibDisplayEXT = (PFN_vkAcquireXlibDisplayEXT) load(userptr, "vkAcquireXlibDisplayEXT"); glad_vkGetRandROutputDisplayEXT = (PFN_vkGetRandROutputDisplayEXT) load(userptr, "vkGetRandROutputDisplayEXT"); } + #endif +static void glad_vk_load_VK_EXT_attachment_feedback_loop_dynamic_state( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_attachment_feedback_loop_dynamic_state) return; + glad_vkCmdSetAttachmentFeedbackLoopEnableEXT = (PFN_vkCmdSetAttachmentFeedbackLoopEnableEXT) load(userptr, "vkCmdSetAttachmentFeedbackLoopEnableEXT"); +} static void glad_vk_load_VK_EXT_buffer_device_address( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_buffer_device_address) return; glad_vkGetBufferDeviceAddressEXT = (PFN_vkGetBufferDeviceAddressEXT) load(userptr, "vkGetBufferDeviceAddressEXT"); @@ -1068,6 +1755,10 @@ static void glad_vk_load_VK_EXT_calibrated_timestamps( GLADuserptrloadfunc load, glad_vkGetCalibratedTimestampsEXT = (PFN_vkGetCalibratedTimestampsEXT) load(userptr, "vkGetCalibratedTimestampsEXT"); glad_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT = (PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT) load(userptr, "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT"); } +static void glad_vk_load_VK_EXT_color_write_enable( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_color_write_enable) return; + glad_vkCmdSetColorWriteEnableEXT = (PFN_vkCmdSetColorWriteEnableEXT) load(userptr, "vkCmdSetColorWriteEnableEXT"); +} static void glad_vk_load_VK_EXT_conditional_rendering( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_conditional_rendering) return; glad_vkCmdBeginConditionalRenderingEXT = (PFN_vkCmdBeginConditionalRenderingEXT) load(userptr, "vkCmdBeginConditionalRenderingEXT"); @@ -1101,6 +1792,44 @@ static void glad_vk_load_VK_EXT_debug_utils( GLADuserptrloadfunc load, void* use glad_vkSetDebugUtilsObjectTagEXT = (PFN_vkSetDebugUtilsObjectTagEXT) load(userptr, "vkSetDebugUtilsObjectTagEXT"); glad_vkSubmitDebugUtilsMessageEXT = (PFN_vkSubmitDebugUtilsMessageEXT) load(userptr, "vkSubmitDebugUtilsMessageEXT"); } +static void glad_vk_load_VK_EXT_depth_bias_control( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_depth_bias_control) return; + glad_vkCmdSetDepthBias2EXT = (PFN_vkCmdSetDepthBias2EXT) load(userptr, "vkCmdSetDepthBias2EXT"); +} +static void glad_vk_load_VK_EXT_depth_clamp_control( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_depth_clamp_control) return; + glad_vkCmdSetDepthClampRangeEXT = (PFN_vkCmdSetDepthClampRangeEXT) load(userptr, "vkCmdSetDepthClampRangeEXT"); +} +static void glad_vk_load_VK_EXT_descriptor_buffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_descriptor_buffer) return; + glad_vkCmdBindDescriptorBufferEmbeddedSamplersEXT = (PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT) load(userptr, "vkCmdBindDescriptorBufferEmbeddedSamplersEXT"); + glad_vkCmdBindDescriptorBuffersEXT = (PFN_vkCmdBindDescriptorBuffersEXT) load(userptr, "vkCmdBindDescriptorBuffersEXT"); + glad_vkCmdSetDescriptorBufferOffsetsEXT = (PFN_vkCmdSetDescriptorBufferOffsetsEXT) load(userptr, "vkCmdSetDescriptorBufferOffsetsEXT"); + glad_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT = (PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT) load(userptr, "vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT"); + glad_vkGetBufferOpaqueCaptureDescriptorDataEXT = (PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT) load(userptr, "vkGetBufferOpaqueCaptureDescriptorDataEXT"); + glad_vkGetDescriptorEXT = (PFN_vkGetDescriptorEXT) load(userptr, "vkGetDescriptorEXT"); + glad_vkGetDescriptorSetLayoutBindingOffsetEXT = (PFN_vkGetDescriptorSetLayoutBindingOffsetEXT) load(userptr, "vkGetDescriptorSetLayoutBindingOffsetEXT"); + glad_vkGetDescriptorSetLayoutSizeEXT = (PFN_vkGetDescriptorSetLayoutSizeEXT) load(userptr, "vkGetDescriptorSetLayoutSizeEXT"); + glad_vkGetImageOpaqueCaptureDescriptorDataEXT = (PFN_vkGetImageOpaqueCaptureDescriptorDataEXT) load(userptr, "vkGetImageOpaqueCaptureDescriptorDataEXT"); + glad_vkGetImageViewOpaqueCaptureDescriptorDataEXT = (PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT) load(userptr, "vkGetImageViewOpaqueCaptureDescriptorDataEXT"); + glad_vkGetSamplerOpaqueCaptureDescriptorDataEXT = (PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT) load(userptr, "vkGetSamplerOpaqueCaptureDescriptorDataEXT"); +} +static void glad_vk_load_VK_EXT_device_fault( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_device_fault) return; + glad_vkGetDeviceFaultInfoEXT = (PFN_vkGetDeviceFaultInfoEXT) load(userptr, "vkGetDeviceFaultInfoEXT"); +} +static void glad_vk_load_VK_EXT_device_generated_commands( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_device_generated_commands) return; + glad_vkCmdExecuteGeneratedCommandsEXT = (PFN_vkCmdExecuteGeneratedCommandsEXT) load(userptr, "vkCmdExecuteGeneratedCommandsEXT"); + glad_vkCmdPreprocessGeneratedCommandsEXT = (PFN_vkCmdPreprocessGeneratedCommandsEXT) load(userptr, "vkCmdPreprocessGeneratedCommandsEXT"); + glad_vkCreateIndirectCommandsLayoutEXT = (PFN_vkCreateIndirectCommandsLayoutEXT) load(userptr, "vkCreateIndirectCommandsLayoutEXT"); + glad_vkCreateIndirectExecutionSetEXT = (PFN_vkCreateIndirectExecutionSetEXT) load(userptr, "vkCreateIndirectExecutionSetEXT"); + glad_vkDestroyIndirectCommandsLayoutEXT = (PFN_vkDestroyIndirectCommandsLayoutEXT) load(userptr, "vkDestroyIndirectCommandsLayoutEXT"); + glad_vkDestroyIndirectExecutionSetEXT = (PFN_vkDestroyIndirectExecutionSetEXT) load(userptr, "vkDestroyIndirectExecutionSetEXT"); + glad_vkGetGeneratedCommandsMemoryRequirementsEXT = (PFN_vkGetGeneratedCommandsMemoryRequirementsEXT) load(userptr, "vkGetGeneratedCommandsMemoryRequirementsEXT"); + glad_vkUpdateIndirectExecutionSetPipelineEXT = (PFN_vkUpdateIndirectExecutionSetPipelineEXT) load(userptr, "vkUpdateIndirectExecutionSetPipelineEXT"); + glad_vkUpdateIndirectExecutionSetShaderEXT = (PFN_vkUpdateIndirectExecutionSetShaderEXT) load(userptr, "vkUpdateIndirectExecutionSetShaderEXT"); +} static void glad_vk_load_VK_EXT_direct_mode_display( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_direct_mode_display) return; glad_vkReleaseDisplayEXT = (PFN_vkReleaseDisplayEXT) load(userptr, "vkReleaseDisplayEXT"); @@ -1111,10 +1840,13 @@ static void glad_vk_load_VK_EXT_directfb_surface( GLADuserptrloadfunc load, void glad_vkCreateDirectFBSurfaceEXT = (PFN_vkCreateDirectFBSurfaceEXT) load(userptr, "vkCreateDirectFBSurfaceEXT"); glad_vkGetPhysicalDeviceDirectFBPresentationSupportEXT = (PFN_vkGetPhysicalDeviceDirectFBPresentationSupportEXT) load(userptr, "vkGetPhysicalDeviceDirectFBPresentationSupportEXT"); } + #endif static void glad_vk_load_VK_EXT_discard_rectangles( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_discard_rectangles) return; glad_vkCmdSetDiscardRectangleEXT = (PFN_vkCmdSetDiscardRectangleEXT) load(userptr, "vkCmdSetDiscardRectangleEXT"); + glad_vkCmdSetDiscardRectangleEnableEXT = (PFN_vkCmdSetDiscardRectangleEnableEXT) load(userptr, "vkCmdSetDiscardRectangleEnableEXT"); + glad_vkCmdSetDiscardRectangleModeEXT = (PFN_vkCmdSetDiscardRectangleModeEXT) load(userptr, "vkCmdSetDiscardRectangleModeEXT"); } static void glad_vk_load_VK_EXT_display_control( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_display_control) return; @@ -1142,10 +1874,64 @@ static void glad_vk_load_VK_EXT_extended_dynamic_state( GLADuserptrloadfunc load glad_vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT) load(userptr, "vkCmdSetStencilTestEnableEXT"); glad_vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT) load(userptr, "vkCmdSetViewportWithCountEXT"); } +static void glad_vk_load_VK_EXT_extended_dynamic_state2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_extended_dynamic_state2) return; + glad_vkCmdSetDepthBiasEnableEXT = (PFN_vkCmdSetDepthBiasEnableEXT) load(userptr, "vkCmdSetDepthBiasEnableEXT"); + glad_vkCmdSetLogicOpEXT = (PFN_vkCmdSetLogicOpEXT) load(userptr, "vkCmdSetLogicOpEXT"); + glad_vkCmdSetPatchControlPointsEXT = (PFN_vkCmdSetPatchControlPointsEXT) load(userptr, "vkCmdSetPatchControlPointsEXT"); + glad_vkCmdSetPrimitiveRestartEnableEXT = (PFN_vkCmdSetPrimitiveRestartEnableEXT) load(userptr, "vkCmdSetPrimitiveRestartEnableEXT"); + glad_vkCmdSetRasterizerDiscardEnableEXT = (PFN_vkCmdSetRasterizerDiscardEnableEXT) load(userptr, "vkCmdSetRasterizerDiscardEnableEXT"); +} +static void glad_vk_load_VK_EXT_extended_dynamic_state3( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_extended_dynamic_state3) return; + glad_vkCmdSetAlphaToCoverageEnableEXT = (PFN_vkCmdSetAlphaToCoverageEnableEXT) load(userptr, "vkCmdSetAlphaToCoverageEnableEXT"); + glad_vkCmdSetAlphaToOneEnableEXT = (PFN_vkCmdSetAlphaToOneEnableEXT) load(userptr, "vkCmdSetAlphaToOneEnableEXT"); + glad_vkCmdSetColorBlendAdvancedEXT = (PFN_vkCmdSetColorBlendAdvancedEXT) load(userptr, "vkCmdSetColorBlendAdvancedEXT"); + glad_vkCmdSetColorBlendEnableEXT = (PFN_vkCmdSetColorBlendEnableEXT) load(userptr, "vkCmdSetColorBlendEnableEXT"); + glad_vkCmdSetColorBlendEquationEXT = (PFN_vkCmdSetColorBlendEquationEXT) load(userptr, "vkCmdSetColorBlendEquationEXT"); + glad_vkCmdSetColorWriteMaskEXT = (PFN_vkCmdSetColorWriteMaskEXT) load(userptr, "vkCmdSetColorWriteMaskEXT"); + glad_vkCmdSetConservativeRasterizationModeEXT = (PFN_vkCmdSetConservativeRasterizationModeEXT) load(userptr, "vkCmdSetConservativeRasterizationModeEXT"); + glad_vkCmdSetCoverageModulationModeNV = (PFN_vkCmdSetCoverageModulationModeNV) load(userptr, "vkCmdSetCoverageModulationModeNV"); + glad_vkCmdSetCoverageModulationTableEnableNV = (PFN_vkCmdSetCoverageModulationTableEnableNV) load(userptr, "vkCmdSetCoverageModulationTableEnableNV"); + glad_vkCmdSetCoverageModulationTableNV = (PFN_vkCmdSetCoverageModulationTableNV) load(userptr, "vkCmdSetCoverageModulationTableNV"); + glad_vkCmdSetCoverageReductionModeNV = (PFN_vkCmdSetCoverageReductionModeNV) load(userptr, "vkCmdSetCoverageReductionModeNV"); + glad_vkCmdSetCoverageToColorEnableNV = (PFN_vkCmdSetCoverageToColorEnableNV) load(userptr, "vkCmdSetCoverageToColorEnableNV"); + glad_vkCmdSetCoverageToColorLocationNV = (PFN_vkCmdSetCoverageToColorLocationNV) load(userptr, "vkCmdSetCoverageToColorLocationNV"); + glad_vkCmdSetDepthClampEnableEXT = (PFN_vkCmdSetDepthClampEnableEXT) load(userptr, "vkCmdSetDepthClampEnableEXT"); + glad_vkCmdSetDepthClipEnableEXT = (PFN_vkCmdSetDepthClipEnableEXT) load(userptr, "vkCmdSetDepthClipEnableEXT"); + glad_vkCmdSetDepthClipNegativeOneToOneEXT = (PFN_vkCmdSetDepthClipNegativeOneToOneEXT) load(userptr, "vkCmdSetDepthClipNegativeOneToOneEXT"); + glad_vkCmdSetExtraPrimitiveOverestimationSizeEXT = (PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT) load(userptr, "vkCmdSetExtraPrimitiveOverestimationSizeEXT"); + glad_vkCmdSetLineRasterizationModeEXT = (PFN_vkCmdSetLineRasterizationModeEXT) load(userptr, "vkCmdSetLineRasterizationModeEXT"); + glad_vkCmdSetLineStippleEnableEXT = (PFN_vkCmdSetLineStippleEnableEXT) load(userptr, "vkCmdSetLineStippleEnableEXT"); + glad_vkCmdSetLogicOpEnableEXT = (PFN_vkCmdSetLogicOpEnableEXT) load(userptr, "vkCmdSetLogicOpEnableEXT"); + glad_vkCmdSetPolygonModeEXT = (PFN_vkCmdSetPolygonModeEXT) load(userptr, "vkCmdSetPolygonModeEXT"); + glad_vkCmdSetProvokingVertexModeEXT = (PFN_vkCmdSetProvokingVertexModeEXT) load(userptr, "vkCmdSetProvokingVertexModeEXT"); + glad_vkCmdSetRasterizationSamplesEXT = (PFN_vkCmdSetRasterizationSamplesEXT) load(userptr, "vkCmdSetRasterizationSamplesEXT"); + glad_vkCmdSetRasterizationStreamEXT = (PFN_vkCmdSetRasterizationStreamEXT) load(userptr, "vkCmdSetRasterizationStreamEXT"); + glad_vkCmdSetRepresentativeFragmentTestEnableNV = (PFN_vkCmdSetRepresentativeFragmentTestEnableNV) load(userptr, "vkCmdSetRepresentativeFragmentTestEnableNV"); + glad_vkCmdSetSampleLocationsEnableEXT = (PFN_vkCmdSetSampleLocationsEnableEXT) load(userptr, "vkCmdSetSampleLocationsEnableEXT"); + glad_vkCmdSetSampleMaskEXT = (PFN_vkCmdSetSampleMaskEXT) load(userptr, "vkCmdSetSampleMaskEXT"); + glad_vkCmdSetShadingRateImageEnableNV = (PFN_vkCmdSetShadingRateImageEnableNV) load(userptr, "vkCmdSetShadingRateImageEnableNV"); + glad_vkCmdSetTessellationDomainOriginEXT = (PFN_vkCmdSetTessellationDomainOriginEXT) load(userptr, "vkCmdSetTessellationDomainOriginEXT"); + glad_vkCmdSetViewportSwizzleNV = (PFN_vkCmdSetViewportSwizzleNV) load(userptr, "vkCmdSetViewportSwizzleNV"); + glad_vkCmdSetViewportWScalingEnableNV = (PFN_vkCmdSetViewportWScalingEnableNV) load(userptr, "vkCmdSetViewportWScalingEnableNV"); +} static void glad_vk_load_VK_EXT_external_memory_host( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_external_memory_host) return; glad_vkGetMemoryHostPointerPropertiesEXT = (PFN_vkGetMemoryHostPointerPropertiesEXT) load(userptr, "vkGetMemoryHostPointerPropertiesEXT"); } +#if defined(VK_USE_PLATFORM_METAL_EXT) +static void glad_vk_load_VK_EXT_external_memory_metal( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_external_memory_metal) return; + glad_vkGetMemoryMetalHandleEXT = (PFN_vkGetMemoryMetalHandleEXT) load(userptr, "vkGetMemoryMetalHandleEXT"); + glad_vkGetMemoryMetalHandlePropertiesEXT = (PFN_vkGetMemoryMetalHandlePropertiesEXT) load(userptr, "vkGetMemoryMetalHandlePropertiesEXT"); +} + +#endif +static void glad_vk_load_VK_EXT_fragment_density_map_offset( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_fragment_density_map_offset) return; + glad_vkCmdEndRendering2EXT = (PFN_vkCmdEndRendering2EXT) load(userptr, "vkCmdEndRendering2EXT"); +} #if defined(VK_USE_PLATFORM_WIN32_KHR) static void glad_vk_load_VK_EXT_full_screen_exclusive( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_full_screen_exclusive) return; @@ -1154,6 +1940,7 @@ static void glad_vk_load_VK_EXT_full_screen_exclusive( GLADuserptrloadfunc load, glad_vkGetPhysicalDeviceSurfacePresentModes2EXT = (PFN_vkGetPhysicalDeviceSurfacePresentModes2EXT) load(userptr, "vkGetPhysicalDeviceSurfacePresentModes2EXT"); glad_vkReleaseFullScreenExclusiveModeEXT = (PFN_vkReleaseFullScreenExclusiveModeEXT) load(userptr, "vkReleaseFullScreenExclusiveModeEXT"); } + #endif static void glad_vk_load_VK_EXT_hdr_metadata( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_hdr_metadata) return; @@ -1163,10 +1950,22 @@ static void glad_vk_load_VK_EXT_headless_surface( GLADuserptrloadfunc load, void if(!GLAD_VK_EXT_headless_surface) return; glad_vkCreateHeadlessSurfaceEXT = (PFN_vkCreateHeadlessSurfaceEXT) load(userptr, "vkCreateHeadlessSurfaceEXT"); } +static void glad_vk_load_VK_EXT_host_image_copy( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_host_image_copy) return; + glad_vkCopyImageToImageEXT = (PFN_vkCopyImageToImageEXT) load(userptr, "vkCopyImageToImageEXT"); + glad_vkCopyImageToMemoryEXT = (PFN_vkCopyImageToMemoryEXT) load(userptr, "vkCopyImageToMemoryEXT"); + glad_vkCopyMemoryToImageEXT = (PFN_vkCopyMemoryToImageEXT) load(userptr, "vkCopyMemoryToImageEXT"); + glad_vkGetImageSubresourceLayout2EXT = (PFN_vkGetImageSubresourceLayout2EXT) load(userptr, "vkGetImageSubresourceLayout2EXT"); + glad_vkTransitionImageLayoutEXT = (PFN_vkTransitionImageLayoutEXT) load(userptr, "vkTransitionImageLayoutEXT"); +} static void glad_vk_load_VK_EXT_host_query_reset( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_host_query_reset) return; glad_vkResetQueryPoolEXT = (PFN_vkResetQueryPoolEXT) load(userptr, "vkResetQueryPoolEXT"); } +static void glad_vk_load_VK_EXT_image_compression_control( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_image_compression_control) return; + glad_vkGetImageSubresourceLayout2EXT = (PFN_vkGetImageSubresourceLayout2EXT) load(userptr, "vkGetImageSubresourceLayout2EXT"); +} static void glad_vk_load_VK_EXT_image_drm_format_modifier( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_image_drm_format_modifier) return; glad_vkGetImageDrmFormatModifierPropertiesEXT = (PFN_vkGetImageDrmFormatModifierPropertiesEXT) load(userptr, "vkGetImageDrmFormatModifierPropertiesEXT"); @@ -1175,12 +1974,56 @@ static void glad_vk_load_VK_EXT_line_rasterization( GLADuserptrloadfunc load, vo if(!GLAD_VK_EXT_line_rasterization) return; glad_vkCmdSetLineStippleEXT = (PFN_vkCmdSetLineStippleEXT) load(userptr, "vkCmdSetLineStippleEXT"); } +static void glad_vk_load_VK_EXT_mesh_shader( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_mesh_shader) return; + glad_vkCmdDrawMeshTasksEXT = (PFN_vkCmdDrawMeshTasksEXT) load(userptr, "vkCmdDrawMeshTasksEXT"); + glad_vkCmdDrawMeshTasksIndirectCountEXT = (PFN_vkCmdDrawMeshTasksIndirectCountEXT) load(userptr, "vkCmdDrawMeshTasksIndirectCountEXT"); + glad_vkCmdDrawMeshTasksIndirectEXT = (PFN_vkCmdDrawMeshTasksIndirectEXT) load(userptr, "vkCmdDrawMeshTasksIndirectEXT"); +} +#if defined(VK_USE_PLATFORM_METAL_EXT) +static void glad_vk_load_VK_EXT_metal_objects( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_metal_objects) return; + glad_vkExportMetalObjectsEXT = (PFN_vkExportMetalObjectsEXT) load(userptr, "vkExportMetalObjectsEXT"); +} + +#endif #if defined(VK_USE_PLATFORM_METAL_EXT) static void glad_vk_load_VK_EXT_metal_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_metal_surface) return; glad_vkCreateMetalSurfaceEXT = (PFN_vkCreateMetalSurfaceEXT) load(userptr, "vkCreateMetalSurfaceEXT"); } + #endif +static void glad_vk_load_VK_EXT_multi_draw( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_multi_draw) return; + glad_vkCmdDrawMultiEXT = (PFN_vkCmdDrawMultiEXT) load(userptr, "vkCmdDrawMultiEXT"); + glad_vkCmdDrawMultiIndexedEXT = (PFN_vkCmdDrawMultiIndexedEXT) load(userptr, "vkCmdDrawMultiIndexedEXT"); +} +static void glad_vk_load_VK_EXT_opacity_micromap( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_opacity_micromap) return; + glad_vkBuildMicromapsEXT = (PFN_vkBuildMicromapsEXT) load(userptr, "vkBuildMicromapsEXT"); + glad_vkCmdBuildMicromapsEXT = (PFN_vkCmdBuildMicromapsEXT) load(userptr, "vkCmdBuildMicromapsEXT"); + glad_vkCmdCopyMemoryToMicromapEXT = (PFN_vkCmdCopyMemoryToMicromapEXT) load(userptr, "vkCmdCopyMemoryToMicromapEXT"); + glad_vkCmdCopyMicromapEXT = (PFN_vkCmdCopyMicromapEXT) load(userptr, "vkCmdCopyMicromapEXT"); + glad_vkCmdCopyMicromapToMemoryEXT = (PFN_vkCmdCopyMicromapToMemoryEXT) load(userptr, "vkCmdCopyMicromapToMemoryEXT"); + glad_vkCmdWriteMicromapsPropertiesEXT = (PFN_vkCmdWriteMicromapsPropertiesEXT) load(userptr, "vkCmdWriteMicromapsPropertiesEXT"); + glad_vkCopyMemoryToMicromapEXT = (PFN_vkCopyMemoryToMicromapEXT) load(userptr, "vkCopyMemoryToMicromapEXT"); + glad_vkCopyMicromapEXT = (PFN_vkCopyMicromapEXT) load(userptr, "vkCopyMicromapEXT"); + glad_vkCopyMicromapToMemoryEXT = (PFN_vkCopyMicromapToMemoryEXT) load(userptr, "vkCopyMicromapToMemoryEXT"); + glad_vkCreateMicromapEXT = (PFN_vkCreateMicromapEXT) load(userptr, "vkCreateMicromapEXT"); + glad_vkDestroyMicromapEXT = (PFN_vkDestroyMicromapEXT) load(userptr, "vkDestroyMicromapEXT"); + glad_vkGetDeviceMicromapCompatibilityEXT = (PFN_vkGetDeviceMicromapCompatibilityEXT) load(userptr, "vkGetDeviceMicromapCompatibilityEXT"); + glad_vkGetMicromapBuildSizesEXT = (PFN_vkGetMicromapBuildSizesEXT) load(userptr, "vkGetMicromapBuildSizesEXT"); + glad_vkWriteMicromapsPropertiesEXT = (PFN_vkWriteMicromapsPropertiesEXT) load(userptr, "vkWriteMicromapsPropertiesEXT"); +} +static void glad_vk_load_VK_EXT_pageable_device_local_memory( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_pageable_device_local_memory) return; + glad_vkSetDeviceMemoryPriorityEXT = (PFN_vkSetDeviceMemoryPriorityEXT) load(userptr, "vkSetDeviceMemoryPriorityEXT"); +} +static void glad_vk_load_VK_EXT_pipeline_properties( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_pipeline_properties) return; + glad_vkGetPipelinePropertiesEXT = (PFN_vkGetPipelinePropertiesEXT) load(userptr, "vkGetPipelinePropertiesEXT"); +} static void glad_vk_load_VK_EXT_private_data( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_private_data) return; glad_vkCreatePrivateDataSlotEXT = (PFN_vkCreatePrivateDataSlotEXT) load(userptr, "vkCreatePrivateDataSlotEXT"); @@ -1193,6 +2036,72 @@ static void glad_vk_load_VK_EXT_sample_locations( GLADuserptrloadfunc load, void glad_vkCmdSetSampleLocationsEXT = (PFN_vkCmdSetSampleLocationsEXT) load(userptr, "vkCmdSetSampleLocationsEXT"); glad_vkGetPhysicalDeviceMultisamplePropertiesEXT = (PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT) load(userptr, "vkGetPhysicalDeviceMultisamplePropertiesEXT"); } +static void glad_vk_load_VK_EXT_shader_module_identifier( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_shader_module_identifier) return; + glad_vkGetShaderModuleCreateInfoIdentifierEXT = (PFN_vkGetShaderModuleCreateInfoIdentifierEXT) load(userptr, "vkGetShaderModuleCreateInfoIdentifierEXT"); + glad_vkGetShaderModuleIdentifierEXT = (PFN_vkGetShaderModuleIdentifierEXT) load(userptr, "vkGetShaderModuleIdentifierEXT"); +} +static void glad_vk_load_VK_EXT_shader_object( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_shader_object) return; + glad_vkCmdBindShadersEXT = (PFN_vkCmdBindShadersEXT) load(userptr, "vkCmdBindShadersEXT"); + glad_vkCmdBindVertexBuffers2EXT = (PFN_vkCmdBindVertexBuffers2EXT) load(userptr, "vkCmdBindVertexBuffers2EXT"); + glad_vkCmdSetAlphaToCoverageEnableEXT = (PFN_vkCmdSetAlphaToCoverageEnableEXT) load(userptr, "vkCmdSetAlphaToCoverageEnableEXT"); + glad_vkCmdSetAlphaToOneEnableEXT = (PFN_vkCmdSetAlphaToOneEnableEXT) load(userptr, "vkCmdSetAlphaToOneEnableEXT"); + glad_vkCmdSetColorBlendAdvancedEXT = (PFN_vkCmdSetColorBlendAdvancedEXT) load(userptr, "vkCmdSetColorBlendAdvancedEXT"); + glad_vkCmdSetColorBlendEnableEXT = (PFN_vkCmdSetColorBlendEnableEXT) load(userptr, "vkCmdSetColorBlendEnableEXT"); + glad_vkCmdSetColorBlendEquationEXT = (PFN_vkCmdSetColorBlendEquationEXT) load(userptr, "vkCmdSetColorBlendEquationEXT"); + glad_vkCmdSetColorWriteMaskEXT = (PFN_vkCmdSetColorWriteMaskEXT) load(userptr, "vkCmdSetColorWriteMaskEXT"); + glad_vkCmdSetConservativeRasterizationModeEXT = (PFN_vkCmdSetConservativeRasterizationModeEXT) load(userptr, "vkCmdSetConservativeRasterizationModeEXT"); + glad_vkCmdSetCoverageModulationModeNV = (PFN_vkCmdSetCoverageModulationModeNV) load(userptr, "vkCmdSetCoverageModulationModeNV"); + glad_vkCmdSetCoverageModulationTableEnableNV = (PFN_vkCmdSetCoverageModulationTableEnableNV) load(userptr, "vkCmdSetCoverageModulationTableEnableNV"); + glad_vkCmdSetCoverageModulationTableNV = (PFN_vkCmdSetCoverageModulationTableNV) load(userptr, "vkCmdSetCoverageModulationTableNV"); + glad_vkCmdSetCoverageReductionModeNV = (PFN_vkCmdSetCoverageReductionModeNV) load(userptr, "vkCmdSetCoverageReductionModeNV"); + glad_vkCmdSetCoverageToColorEnableNV = (PFN_vkCmdSetCoverageToColorEnableNV) load(userptr, "vkCmdSetCoverageToColorEnableNV"); + glad_vkCmdSetCoverageToColorLocationNV = (PFN_vkCmdSetCoverageToColorLocationNV) load(userptr, "vkCmdSetCoverageToColorLocationNV"); + glad_vkCmdSetCullModeEXT = (PFN_vkCmdSetCullModeEXT) load(userptr, "vkCmdSetCullModeEXT"); + glad_vkCmdSetDepthBiasEnableEXT = (PFN_vkCmdSetDepthBiasEnableEXT) load(userptr, "vkCmdSetDepthBiasEnableEXT"); + glad_vkCmdSetDepthBoundsTestEnableEXT = (PFN_vkCmdSetDepthBoundsTestEnableEXT) load(userptr, "vkCmdSetDepthBoundsTestEnableEXT"); + glad_vkCmdSetDepthClampEnableEXT = (PFN_vkCmdSetDepthClampEnableEXT) load(userptr, "vkCmdSetDepthClampEnableEXT"); + glad_vkCmdSetDepthClampRangeEXT = (PFN_vkCmdSetDepthClampRangeEXT) load(userptr, "vkCmdSetDepthClampRangeEXT"); + glad_vkCmdSetDepthClipEnableEXT = (PFN_vkCmdSetDepthClipEnableEXT) load(userptr, "vkCmdSetDepthClipEnableEXT"); + glad_vkCmdSetDepthClipNegativeOneToOneEXT = (PFN_vkCmdSetDepthClipNegativeOneToOneEXT) load(userptr, "vkCmdSetDepthClipNegativeOneToOneEXT"); + glad_vkCmdSetDepthCompareOpEXT = (PFN_vkCmdSetDepthCompareOpEXT) load(userptr, "vkCmdSetDepthCompareOpEXT"); + glad_vkCmdSetDepthTestEnableEXT = (PFN_vkCmdSetDepthTestEnableEXT) load(userptr, "vkCmdSetDepthTestEnableEXT"); + glad_vkCmdSetDepthWriteEnableEXT = (PFN_vkCmdSetDepthWriteEnableEXT) load(userptr, "vkCmdSetDepthWriteEnableEXT"); + glad_vkCmdSetExtraPrimitiveOverestimationSizeEXT = (PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT) load(userptr, "vkCmdSetExtraPrimitiveOverestimationSizeEXT"); + glad_vkCmdSetFrontFaceEXT = (PFN_vkCmdSetFrontFaceEXT) load(userptr, "vkCmdSetFrontFaceEXT"); + glad_vkCmdSetLineRasterizationModeEXT = (PFN_vkCmdSetLineRasterizationModeEXT) load(userptr, "vkCmdSetLineRasterizationModeEXT"); + glad_vkCmdSetLineStippleEnableEXT = (PFN_vkCmdSetLineStippleEnableEXT) load(userptr, "vkCmdSetLineStippleEnableEXT"); + glad_vkCmdSetLogicOpEXT = (PFN_vkCmdSetLogicOpEXT) load(userptr, "vkCmdSetLogicOpEXT"); + glad_vkCmdSetLogicOpEnableEXT = (PFN_vkCmdSetLogicOpEnableEXT) load(userptr, "vkCmdSetLogicOpEnableEXT"); + glad_vkCmdSetPatchControlPointsEXT = (PFN_vkCmdSetPatchControlPointsEXT) load(userptr, "vkCmdSetPatchControlPointsEXT"); + glad_vkCmdSetPolygonModeEXT = (PFN_vkCmdSetPolygonModeEXT) load(userptr, "vkCmdSetPolygonModeEXT"); + glad_vkCmdSetPrimitiveRestartEnableEXT = (PFN_vkCmdSetPrimitiveRestartEnableEXT) load(userptr, "vkCmdSetPrimitiveRestartEnableEXT"); + glad_vkCmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT) load(userptr, "vkCmdSetPrimitiveTopologyEXT"); + glad_vkCmdSetProvokingVertexModeEXT = (PFN_vkCmdSetProvokingVertexModeEXT) load(userptr, "vkCmdSetProvokingVertexModeEXT"); + glad_vkCmdSetRasterizationSamplesEXT = (PFN_vkCmdSetRasterizationSamplesEXT) load(userptr, "vkCmdSetRasterizationSamplesEXT"); + glad_vkCmdSetRasterizationStreamEXT = (PFN_vkCmdSetRasterizationStreamEXT) load(userptr, "vkCmdSetRasterizationStreamEXT"); + glad_vkCmdSetRasterizerDiscardEnableEXT = (PFN_vkCmdSetRasterizerDiscardEnableEXT) load(userptr, "vkCmdSetRasterizerDiscardEnableEXT"); + glad_vkCmdSetRepresentativeFragmentTestEnableNV = (PFN_vkCmdSetRepresentativeFragmentTestEnableNV) load(userptr, "vkCmdSetRepresentativeFragmentTestEnableNV"); + glad_vkCmdSetSampleLocationsEnableEXT = (PFN_vkCmdSetSampleLocationsEnableEXT) load(userptr, "vkCmdSetSampleLocationsEnableEXT"); + glad_vkCmdSetSampleMaskEXT = (PFN_vkCmdSetSampleMaskEXT) load(userptr, "vkCmdSetSampleMaskEXT"); + glad_vkCmdSetScissorWithCountEXT = (PFN_vkCmdSetScissorWithCountEXT) load(userptr, "vkCmdSetScissorWithCountEXT"); + glad_vkCmdSetShadingRateImageEnableNV = (PFN_vkCmdSetShadingRateImageEnableNV) load(userptr, "vkCmdSetShadingRateImageEnableNV"); + glad_vkCmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT) load(userptr, "vkCmdSetStencilOpEXT"); + glad_vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT) load(userptr, "vkCmdSetStencilTestEnableEXT"); + glad_vkCmdSetTessellationDomainOriginEXT = (PFN_vkCmdSetTessellationDomainOriginEXT) load(userptr, "vkCmdSetTessellationDomainOriginEXT"); + glad_vkCmdSetVertexInputEXT = (PFN_vkCmdSetVertexInputEXT) load(userptr, "vkCmdSetVertexInputEXT"); + glad_vkCmdSetViewportSwizzleNV = (PFN_vkCmdSetViewportSwizzleNV) load(userptr, "vkCmdSetViewportSwizzleNV"); + glad_vkCmdSetViewportWScalingEnableNV = (PFN_vkCmdSetViewportWScalingEnableNV) load(userptr, "vkCmdSetViewportWScalingEnableNV"); + glad_vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT) load(userptr, "vkCmdSetViewportWithCountEXT"); + glad_vkCreateShadersEXT = (PFN_vkCreateShadersEXT) load(userptr, "vkCreateShadersEXT"); + glad_vkDestroyShaderEXT = (PFN_vkDestroyShaderEXT) load(userptr, "vkDestroyShaderEXT"); + glad_vkGetShaderBinaryDataEXT = (PFN_vkGetShaderBinaryDataEXT) load(userptr, "vkGetShaderBinaryDataEXT"); +} +static void glad_vk_load_VK_EXT_swapchain_maintenance1( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_swapchain_maintenance1) return; + glad_vkReleaseSwapchainImagesEXT = (PFN_vkReleaseSwapchainImagesEXT) load(userptr, "vkReleaseSwapchainImagesEXT"); +} static void glad_vk_load_VK_EXT_tooling_info( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_EXT_tooling_info) return; glad_vkGetPhysicalDeviceToolPropertiesEXT = (PFN_vkGetPhysicalDeviceToolPropertiesEXT) load(userptr, "vkGetPhysicalDeviceToolPropertiesEXT"); @@ -1213,23 +2122,70 @@ static void glad_vk_load_VK_EXT_validation_cache( GLADuserptrloadfunc load, void glad_vkGetValidationCacheDataEXT = (PFN_vkGetValidationCacheDataEXT) load(userptr, "vkGetValidationCacheDataEXT"); glad_vkMergeValidationCachesEXT = (PFN_vkMergeValidationCachesEXT) load(userptr, "vkMergeValidationCachesEXT"); } +static void glad_vk_load_VK_EXT_vertex_input_dynamic_state( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_EXT_vertex_input_dynamic_state) return; + glad_vkCmdSetVertexInputEXT = (PFN_vkCmdSetVertexInputEXT) load(userptr, "vkCmdSetVertexInputEXT"); +} +#if defined(VK_USE_PLATFORM_FUCHSIA) +static void glad_vk_load_VK_FUCHSIA_buffer_collection( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_FUCHSIA_buffer_collection) return; + glad_vkCreateBufferCollectionFUCHSIA = (PFN_vkCreateBufferCollectionFUCHSIA) load(userptr, "vkCreateBufferCollectionFUCHSIA"); + glad_vkDestroyBufferCollectionFUCHSIA = (PFN_vkDestroyBufferCollectionFUCHSIA) load(userptr, "vkDestroyBufferCollectionFUCHSIA"); + glad_vkGetBufferCollectionPropertiesFUCHSIA = (PFN_vkGetBufferCollectionPropertiesFUCHSIA) load(userptr, "vkGetBufferCollectionPropertiesFUCHSIA"); + glad_vkSetBufferCollectionBufferConstraintsFUCHSIA = (PFN_vkSetBufferCollectionBufferConstraintsFUCHSIA) load(userptr, "vkSetBufferCollectionBufferConstraintsFUCHSIA"); + glad_vkSetBufferCollectionImageConstraintsFUCHSIA = (PFN_vkSetBufferCollectionImageConstraintsFUCHSIA) load(userptr, "vkSetBufferCollectionImageConstraintsFUCHSIA"); +} + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +static void glad_vk_load_VK_FUCHSIA_external_memory( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_FUCHSIA_external_memory) return; + glad_vkGetMemoryZirconHandleFUCHSIA = (PFN_vkGetMemoryZirconHandleFUCHSIA) load(userptr, "vkGetMemoryZirconHandleFUCHSIA"); + glad_vkGetMemoryZirconHandlePropertiesFUCHSIA = (PFN_vkGetMemoryZirconHandlePropertiesFUCHSIA) load(userptr, "vkGetMemoryZirconHandlePropertiesFUCHSIA"); +} + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) +static void glad_vk_load_VK_FUCHSIA_external_semaphore( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_FUCHSIA_external_semaphore) return; + glad_vkGetSemaphoreZirconHandleFUCHSIA = (PFN_vkGetSemaphoreZirconHandleFUCHSIA) load(userptr, "vkGetSemaphoreZirconHandleFUCHSIA"); + glad_vkImportSemaphoreZirconHandleFUCHSIA = (PFN_vkImportSemaphoreZirconHandleFUCHSIA) load(userptr, "vkImportSemaphoreZirconHandleFUCHSIA"); +} + +#endif #if defined(VK_USE_PLATFORM_FUCHSIA) static void glad_vk_load_VK_FUCHSIA_imagepipe_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_FUCHSIA_imagepipe_surface) return; glad_vkCreateImagePipeSurfaceFUCHSIA = (PFN_vkCreateImagePipeSurfaceFUCHSIA) load(userptr, "vkCreateImagePipeSurfaceFUCHSIA"); } + #endif #if defined(VK_USE_PLATFORM_GGP) static void glad_vk_load_VK_GGP_stream_descriptor_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_GGP_stream_descriptor_surface) return; glad_vkCreateStreamDescriptorSurfaceGGP = (PFN_vkCreateStreamDescriptorSurfaceGGP) load(userptr, "vkCreateStreamDescriptorSurfaceGGP"); } + #endif static void glad_vk_load_VK_GOOGLE_display_timing( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_GOOGLE_display_timing) return; glad_vkGetPastPresentationTimingGOOGLE = (PFN_vkGetPastPresentationTimingGOOGLE) load(userptr, "vkGetPastPresentationTimingGOOGLE"); glad_vkGetRefreshCycleDurationGOOGLE = (PFN_vkGetRefreshCycleDurationGOOGLE) load(userptr, "vkGetRefreshCycleDurationGOOGLE"); } +static void glad_vk_load_VK_HUAWEI_cluster_culling_shader( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_HUAWEI_cluster_culling_shader) return; + glad_vkCmdDrawClusterHUAWEI = (PFN_vkCmdDrawClusterHUAWEI) load(userptr, "vkCmdDrawClusterHUAWEI"); + glad_vkCmdDrawClusterIndirectHUAWEI = (PFN_vkCmdDrawClusterIndirectHUAWEI) load(userptr, "vkCmdDrawClusterIndirectHUAWEI"); +} +static void glad_vk_load_VK_HUAWEI_invocation_mask( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_HUAWEI_invocation_mask) return; + glad_vkCmdBindInvocationMaskHUAWEI = (PFN_vkCmdBindInvocationMaskHUAWEI) load(userptr, "vkCmdBindInvocationMaskHUAWEI"); +} +static void glad_vk_load_VK_HUAWEI_subpass_shading( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_HUAWEI_subpass_shading) return; + glad_vkCmdSubpassShadingHUAWEI = (PFN_vkCmdSubpassShadingHUAWEI) load(userptr, "vkCmdSubpassShadingHUAWEI"); + glad_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI = (PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI) load(userptr, "vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI"); +} static void glad_vk_load_VK_INTEL_performance_query( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_INTEL_performance_query) return; glad_vkAcquirePerformanceConfigurationINTEL = (PFN_vkAcquirePerformanceConfigurationINTEL) load(userptr, "vkAcquirePerformanceConfigurationINTEL"); @@ -1242,11 +2198,31 @@ static void glad_vk_load_VK_INTEL_performance_query( GLADuserptrloadfunc load, v glad_vkReleasePerformanceConfigurationINTEL = (PFN_vkReleasePerformanceConfigurationINTEL) load(userptr, "vkReleasePerformanceConfigurationINTEL"); glad_vkUninitializePerformanceApiINTEL = (PFN_vkUninitializePerformanceApiINTEL) load(userptr, "vkUninitializePerformanceApiINTEL"); } +static void glad_vk_load_VK_KHR_acceleration_structure( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_acceleration_structure) return; + glad_vkBuildAccelerationStructuresKHR = (PFN_vkBuildAccelerationStructuresKHR) load(userptr, "vkBuildAccelerationStructuresKHR"); + glad_vkCmdBuildAccelerationStructuresIndirectKHR = (PFN_vkCmdBuildAccelerationStructuresIndirectKHR) load(userptr, "vkCmdBuildAccelerationStructuresIndirectKHR"); + glad_vkCmdBuildAccelerationStructuresKHR = (PFN_vkCmdBuildAccelerationStructuresKHR) load(userptr, "vkCmdBuildAccelerationStructuresKHR"); + glad_vkCmdCopyAccelerationStructureKHR = (PFN_vkCmdCopyAccelerationStructureKHR) load(userptr, "vkCmdCopyAccelerationStructureKHR"); + glad_vkCmdCopyAccelerationStructureToMemoryKHR = (PFN_vkCmdCopyAccelerationStructureToMemoryKHR) load(userptr, "vkCmdCopyAccelerationStructureToMemoryKHR"); + glad_vkCmdCopyMemoryToAccelerationStructureKHR = (PFN_vkCmdCopyMemoryToAccelerationStructureKHR) load(userptr, "vkCmdCopyMemoryToAccelerationStructureKHR"); + glad_vkCmdWriteAccelerationStructuresPropertiesKHR = (PFN_vkCmdWriteAccelerationStructuresPropertiesKHR) load(userptr, "vkCmdWriteAccelerationStructuresPropertiesKHR"); + glad_vkCopyAccelerationStructureKHR = (PFN_vkCopyAccelerationStructureKHR) load(userptr, "vkCopyAccelerationStructureKHR"); + glad_vkCopyAccelerationStructureToMemoryKHR = (PFN_vkCopyAccelerationStructureToMemoryKHR) load(userptr, "vkCopyAccelerationStructureToMemoryKHR"); + glad_vkCopyMemoryToAccelerationStructureKHR = (PFN_vkCopyMemoryToAccelerationStructureKHR) load(userptr, "vkCopyMemoryToAccelerationStructureKHR"); + glad_vkCreateAccelerationStructureKHR = (PFN_vkCreateAccelerationStructureKHR) load(userptr, "vkCreateAccelerationStructureKHR"); + glad_vkDestroyAccelerationStructureKHR = (PFN_vkDestroyAccelerationStructureKHR) load(userptr, "vkDestroyAccelerationStructureKHR"); + glad_vkGetAccelerationStructureBuildSizesKHR = (PFN_vkGetAccelerationStructureBuildSizesKHR) load(userptr, "vkGetAccelerationStructureBuildSizesKHR"); + glad_vkGetAccelerationStructureDeviceAddressKHR = (PFN_vkGetAccelerationStructureDeviceAddressKHR) load(userptr, "vkGetAccelerationStructureDeviceAddressKHR"); + glad_vkGetDeviceAccelerationStructureCompatibilityKHR = (PFN_vkGetDeviceAccelerationStructureCompatibilityKHR) load(userptr, "vkGetDeviceAccelerationStructureCompatibilityKHR"); + glad_vkWriteAccelerationStructuresPropertiesKHR = (PFN_vkWriteAccelerationStructuresPropertiesKHR) load(userptr, "vkWriteAccelerationStructuresPropertiesKHR"); +} #if defined(VK_USE_PLATFORM_ANDROID_KHR) static void glad_vk_load_VK_KHR_android_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_android_surface) return; glad_vkCreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR) load(userptr, "vkCreateAndroidSurfaceKHR"); } + #endif static void glad_vk_load_VK_KHR_bind_memory2( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_bind_memory2) return; @@ -1259,6 +2235,24 @@ static void glad_vk_load_VK_KHR_buffer_device_address( GLADuserptrloadfunc load, glad_vkGetBufferOpaqueCaptureAddressKHR = (PFN_vkGetBufferOpaqueCaptureAddressKHR) load(userptr, "vkGetBufferOpaqueCaptureAddressKHR"); glad_vkGetDeviceMemoryOpaqueCaptureAddressKHR = (PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR) load(userptr, "vkGetDeviceMemoryOpaqueCaptureAddressKHR"); } +static void glad_vk_load_VK_KHR_calibrated_timestamps( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_calibrated_timestamps) return; + glad_vkGetCalibratedTimestampsKHR = (PFN_vkGetCalibratedTimestampsKHR) load(userptr, "vkGetCalibratedTimestampsKHR"); + glad_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR = (PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR) load(userptr, "vkGetPhysicalDeviceCalibrateableTimeDomainsKHR"); +} +static void glad_vk_load_VK_KHR_cooperative_matrix( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_cooperative_matrix) return; + glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR = (PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR) load(userptr, "vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR"); +} +static void glad_vk_load_VK_KHR_copy_commands2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_copy_commands2) return; + glad_vkCmdBlitImage2KHR = (PFN_vkCmdBlitImage2KHR) load(userptr, "vkCmdBlitImage2KHR"); + glad_vkCmdCopyBuffer2KHR = (PFN_vkCmdCopyBuffer2KHR) load(userptr, "vkCmdCopyBuffer2KHR"); + glad_vkCmdCopyBufferToImage2KHR = (PFN_vkCmdCopyBufferToImage2KHR) load(userptr, "vkCmdCopyBufferToImage2KHR"); + glad_vkCmdCopyImage2KHR = (PFN_vkCmdCopyImage2KHR) load(userptr, "vkCmdCopyImage2KHR"); + glad_vkCmdCopyImageToBuffer2KHR = (PFN_vkCmdCopyImageToBuffer2KHR) load(userptr, "vkCmdCopyImageToBuffer2KHR"); + glad_vkCmdResolveImage2KHR = (PFN_vkCmdResolveImage2KHR) load(userptr, "vkCmdResolveImage2KHR"); +} static void glad_vk_load_VK_KHR_create_renderpass2( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_create_renderpass2) return; glad_vkCmdBeginRenderPass2KHR = (PFN_vkCmdBeginRenderPass2KHR) load(userptr, "vkCmdBeginRenderPass2KHR"); @@ -1266,7 +2260,6 @@ static void glad_vk_load_VK_KHR_create_renderpass2( GLADuserptrloadfunc load, vo glad_vkCmdNextSubpass2KHR = (PFN_vkCmdNextSubpass2KHR) load(userptr, "vkCmdNextSubpass2KHR"); glad_vkCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR) load(userptr, "vkCreateRenderPass2KHR"); } -#if defined(VK_ENABLE_BETA_EXTENSIONS) static void glad_vk_load_VK_KHR_deferred_host_operations( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_deferred_host_operations) return; glad_vkCreateDeferredOperationKHR = (PFN_vkCreateDeferredOperationKHR) load(userptr, "vkCreateDeferredOperationKHR"); @@ -1275,7 +2268,6 @@ static void glad_vk_load_VK_KHR_deferred_host_operations( GLADuserptrloadfunc lo glad_vkGetDeferredOperationMaxConcurrencyKHR = (PFN_vkGetDeferredOperationMaxConcurrencyKHR) load(userptr, "vkGetDeferredOperationMaxConcurrencyKHR"); glad_vkGetDeferredOperationResultKHR = (PFN_vkGetDeferredOperationResultKHR) load(userptr, "vkGetDeferredOperationResultKHR"); } -#endif static void glad_vk_load_VK_KHR_descriptor_update_template( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_descriptor_update_template) return; glad_vkCmdPushDescriptorSetWithTemplateKHR = (PFN_vkCmdPushDescriptorSetWithTemplateKHR) load(userptr, "vkCmdPushDescriptorSetWithTemplateKHR"); @@ -1316,6 +2308,16 @@ static void glad_vk_load_VK_KHR_draw_indirect_count( GLADuserptrloadfunc load, v glad_vkCmdDrawIndexedIndirectCountKHR = (PFN_vkCmdDrawIndexedIndirectCountKHR) load(userptr, "vkCmdDrawIndexedIndirectCountKHR"); glad_vkCmdDrawIndirectCountKHR = (PFN_vkCmdDrawIndirectCountKHR) load(userptr, "vkCmdDrawIndirectCountKHR"); } +static void glad_vk_load_VK_KHR_dynamic_rendering( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_dynamic_rendering) return; + glad_vkCmdBeginRenderingKHR = (PFN_vkCmdBeginRenderingKHR) load(userptr, "vkCmdBeginRenderingKHR"); + glad_vkCmdEndRenderingKHR = (PFN_vkCmdEndRenderingKHR) load(userptr, "vkCmdEndRenderingKHR"); +} +static void glad_vk_load_VK_KHR_dynamic_rendering_local_read( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_dynamic_rendering_local_read) return; + glad_vkCmdSetRenderingAttachmentLocationsKHR = (PFN_vkCmdSetRenderingAttachmentLocationsKHR) load(userptr, "vkCmdSetRenderingAttachmentLocationsKHR"); + glad_vkCmdSetRenderingInputAttachmentIndicesKHR = (PFN_vkCmdSetRenderingInputAttachmentIndicesKHR) load(userptr, "vkCmdSetRenderingInputAttachmentIndicesKHR"); +} static void glad_vk_load_VK_KHR_external_fence_capabilities( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_external_fence_capabilities) return; glad_vkGetPhysicalDeviceExternalFencePropertiesKHR = (PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR) load(userptr, "vkGetPhysicalDeviceExternalFencePropertiesKHR"); @@ -1331,6 +2333,7 @@ static void glad_vk_load_VK_KHR_external_fence_win32( GLADuserptrloadfunc load, glad_vkGetFenceWin32HandleKHR = (PFN_vkGetFenceWin32HandleKHR) load(userptr, "vkGetFenceWin32HandleKHR"); glad_vkImportFenceWin32HandleKHR = (PFN_vkImportFenceWin32HandleKHR) load(userptr, "vkImportFenceWin32HandleKHR"); } + #endif static void glad_vk_load_VK_KHR_external_memory_capabilities( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_external_memory_capabilities) return; @@ -1347,6 +2350,7 @@ static void glad_vk_load_VK_KHR_external_memory_win32( GLADuserptrloadfunc load, glad_vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR) load(userptr, "vkGetMemoryWin32HandleKHR"); glad_vkGetMemoryWin32HandlePropertiesKHR = (PFN_vkGetMemoryWin32HandlePropertiesKHR) load(userptr, "vkGetMemoryWin32HandlePropertiesKHR"); } + #endif static void glad_vk_load_VK_KHR_external_semaphore_capabilities( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_external_semaphore_capabilities) return; @@ -1363,7 +2367,13 @@ static void glad_vk_load_VK_KHR_external_semaphore_win32( GLADuserptrloadfunc lo glad_vkGetSemaphoreWin32HandleKHR = (PFN_vkGetSemaphoreWin32HandleKHR) load(userptr, "vkGetSemaphoreWin32HandleKHR"); glad_vkImportSemaphoreWin32HandleKHR = (PFN_vkImportSemaphoreWin32HandleKHR) load(userptr, "vkImportSemaphoreWin32HandleKHR"); } + #endif +static void glad_vk_load_VK_KHR_fragment_shading_rate( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_fragment_shading_rate) return; + glad_vkCmdSetFragmentShadingRateKHR = (PFN_vkCmdSetFragmentShadingRateKHR) load(userptr, "vkCmdSetFragmentShadingRateKHR"); + glad_vkGetPhysicalDeviceFragmentShadingRatesKHR = (PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR) load(userptr, "vkGetPhysicalDeviceFragmentShadingRatesKHR"); +} static void glad_vk_load_VK_KHR_get_display_properties2( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_get_display_properties2) return; glad_vkGetDisplayModeProperties2KHR = (PFN_vkGetDisplayModeProperties2KHR) load(userptr, "vkGetDisplayModeProperties2KHR"); @@ -1392,6 +2402,10 @@ static void glad_vk_load_VK_KHR_get_surface_capabilities2( GLADuserptrloadfunc l glad_vkGetPhysicalDeviceSurfaceCapabilities2KHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR) load(userptr, "vkGetPhysicalDeviceSurfaceCapabilities2KHR"); glad_vkGetPhysicalDeviceSurfaceFormats2KHR = (PFN_vkGetPhysicalDeviceSurfaceFormats2KHR) load(userptr, "vkGetPhysicalDeviceSurfaceFormats2KHR"); } +static void glad_vk_load_VK_KHR_line_rasterization( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_line_rasterization) return; + glad_vkCmdSetLineStippleKHR = (PFN_vkCmdSetLineStippleKHR) load(userptr, "vkCmdSetLineStippleKHR"); +} static void glad_vk_load_VK_KHR_maintenance1( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_maintenance1) return; glad_vkTrimCommandPoolKHR = (PFN_vkTrimCommandPoolKHR) load(userptr, "vkTrimCommandPoolKHR"); @@ -1400,6 +2414,33 @@ static void glad_vk_load_VK_KHR_maintenance3( GLADuserptrloadfunc load, void* us if(!GLAD_VK_KHR_maintenance3) return; glad_vkGetDescriptorSetLayoutSupportKHR = (PFN_vkGetDescriptorSetLayoutSupportKHR) load(userptr, "vkGetDescriptorSetLayoutSupportKHR"); } +static void glad_vk_load_VK_KHR_maintenance4( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_maintenance4) return; + glad_vkGetDeviceBufferMemoryRequirementsKHR = (PFN_vkGetDeviceBufferMemoryRequirementsKHR) load(userptr, "vkGetDeviceBufferMemoryRequirementsKHR"); + glad_vkGetDeviceImageMemoryRequirementsKHR = (PFN_vkGetDeviceImageMemoryRequirementsKHR) load(userptr, "vkGetDeviceImageMemoryRequirementsKHR"); + glad_vkGetDeviceImageSparseMemoryRequirementsKHR = (PFN_vkGetDeviceImageSparseMemoryRequirementsKHR) load(userptr, "vkGetDeviceImageSparseMemoryRequirementsKHR"); +} +static void glad_vk_load_VK_KHR_maintenance5( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_maintenance5) return; + glad_vkCmdBindIndexBuffer2KHR = (PFN_vkCmdBindIndexBuffer2KHR) load(userptr, "vkCmdBindIndexBuffer2KHR"); + glad_vkGetDeviceImageSubresourceLayoutKHR = (PFN_vkGetDeviceImageSubresourceLayoutKHR) load(userptr, "vkGetDeviceImageSubresourceLayoutKHR"); + glad_vkGetImageSubresourceLayout2KHR = (PFN_vkGetImageSubresourceLayout2KHR) load(userptr, "vkGetImageSubresourceLayout2KHR"); + glad_vkGetRenderingAreaGranularityKHR = (PFN_vkGetRenderingAreaGranularityKHR) load(userptr, "vkGetRenderingAreaGranularityKHR"); +} +static void glad_vk_load_VK_KHR_maintenance6( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_maintenance6) return; + glad_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT = (PFN_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT) load(userptr, "vkCmdBindDescriptorBufferEmbeddedSamplers2EXT"); + glad_vkCmdBindDescriptorSets2KHR = (PFN_vkCmdBindDescriptorSets2KHR) load(userptr, "vkCmdBindDescriptorSets2KHR"); + glad_vkCmdPushConstants2KHR = (PFN_vkCmdPushConstants2KHR) load(userptr, "vkCmdPushConstants2KHR"); + glad_vkCmdPushDescriptorSet2KHR = (PFN_vkCmdPushDescriptorSet2KHR) load(userptr, "vkCmdPushDescriptorSet2KHR"); + glad_vkCmdPushDescriptorSetWithTemplate2KHR = (PFN_vkCmdPushDescriptorSetWithTemplate2KHR) load(userptr, "vkCmdPushDescriptorSetWithTemplate2KHR"); + glad_vkCmdSetDescriptorBufferOffsets2EXT = (PFN_vkCmdSetDescriptorBufferOffsets2EXT) load(userptr, "vkCmdSetDescriptorBufferOffsets2EXT"); +} +static void glad_vk_load_VK_KHR_map_memory2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_map_memory2) return; + glad_vkMapMemory2KHR = (PFN_vkMapMemory2KHR) load(userptr, "vkMapMemory2KHR"); + glad_vkUnmapMemory2KHR = (PFN_vkUnmapMemory2KHR) load(userptr, "vkUnmapMemory2KHR"); +} static void glad_vk_load_VK_KHR_performance_query( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_performance_query) return; glad_vkAcquireProfilingLockKHR = (PFN_vkAcquireProfilingLockKHR) load(userptr, "vkAcquireProfilingLockKHR"); @@ -1407,44 +2448,43 @@ static void glad_vk_load_VK_KHR_performance_query( GLADuserptrloadfunc load, voi glad_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR = (PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR) load(userptr, "vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR"); glad_vkReleaseProfilingLockKHR = (PFN_vkReleaseProfilingLockKHR) load(userptr, "vkReleaseProfilingLockKHR"); } +static void glad_vk_load_VK_KHR_pipeline_binary( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_pipeline_binary) return; + glad_vkCreatePipelineBinariesKHR = (PFN_vkCreatePipelineBinariesKHR) load(userptr, "vkCreatePipelineBinariesKHR"); + glad_vkDestroyPipelineBinaryKHR = (PFN_vkDestroyPipelineBinaryKHR) load(userptr, "vkDestroyPipelineBinaryKHR"); + glad_vkGetPipelineBinaryDataKHR = (PFN_vkGetPipelineBinaryDataKHR) load(userptr, "vkGetPipelineBinaryDataKHR"); + glad_vkGetPipelineKeyKHR = (PFN_vkGetPipelineKeyKHR) load(userptr, "vkGetPipelineKeyKHR"); + glad_vkReleaseCapturedPipelineDataKHR = (PFN_vkReleaseCapturedPipelineDataKHR) load(userptr, "vkReleaseCapturedPipelineDataKHR"); +} static void glad_vk_load_VK_KHR_pipeline_executable_properties( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_pipeline_executable_properties) return; glad_vkGetPipelineExecutableInternalRepresentationsKHR = (PFN_vkGetPipelineExecutableInternalRepresentationsKHR) load(userptr, "vkGetPipelineExecutableInternalRepresentationsKHR"); glad_vkGetPipelineExecutablePropertiesKHR = (PFN_vkGetPipelineExecutablePropertiesKHR) load(userptr, "vkGetPipelineExecutablePropertiesKHR"); glad_vkGetPipelineExecutableStatisticsKHR = (PFN_vkGetPipelineExecutableStatisticsKHR) load(userptr, "vkGetPipelineExecutableStatisticsKHR"); } +static void glad_vk_load_VK_KHR_present_wait( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_present_wait) return; + glad_vkWaitForPresentKHR = (PFN_vkWaitForPresentKHR) load(userptr, "vkWaitForPresentKHR"); +} static void glad_vk_load_VK_KHR_push_descriptor( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_push_descriptor) return; glad_vkCmdPushDescriptorSetKHR = (PFN_vkCmdPushDescriptorSetKHR) load(userptr, "vkCmdPushDescriptorSetKHR"); glad_vkCmdPushDescriptorSetWithTemplateKHR = (PFN_vkCmdPushDescriptorSetWithTemplateKHR) load(userptr, "vkCmdPushDescriptorSetWithTemplateKHR"); } -#if defined(VK_ENABLE_BETA_EXTENSIONS) -static void glad_vk_load_VK_KHR_ray_tracing( GLADuserptrloadfunc load, void* userptr) { - if(!GLAD_VK_KHR_ray_tracing) return; - glad_vkBindAccelerationStructureMemoryKHR = (PFN_vkBindAccelerationStructureMemoryKHR) load(userptr, "vkBindAccelerationStructureMemoryKHR"); - glad_vkBuildAccelerationStructureKHR = (PFN_vkBuildAccelerationStructureKHR) load(userptr, "vkBuildAccelerationStructureKHR"); - glad_vkCmdBuildAccelerationStructureIndirectKHR = (PFN_vkCmdBuildAccelerationStructureIndirectKHR) load(userptr, "vkCmdBuildAccelerationStructureIndirectKHR"); - glad_vkCmdBuildAccelerationStructureKHR = (PFN_vkCmdBuildAccelerationStructureKHR) load(userptr, "vkCmdBuildAccelerationStructureKHR"); - glad_vkCmdCopyAccelerationStructureKHR = (PFN_vkCmdCopyAccelerationStructureKHR) load(userptr, "vkCmdCopyAccelerationStructureKHR"); - glad_vkCmdCopyAccelerationStructureToMemoryKHR = (PFN_vkCmdCopyAccelerationStructureToMemoryKHR) load(userptr, "vkCmdCopyAccelerationStructureToMemoryKHR"); - glad_vkCmdCopyMemoryToAccelerationStructureKHR = (PFN_vkCmdCopyMemoryToAccelerationStructureKHR) load(userptr, "vkCmdCopyMemoryToAccelerationStructureKHR"); +static void glad_vk_load_VK_KHR_ray_tracing_maintenance1( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_ray_tracing_maintenance1) return; + glad_vkCmdTraceRaysIndirect2KHR = (PFN_vkCmdTraceRaysIndirect2KHR) load(userptr, "vkCmdTraceRaysIndirect2KHR"); +} +static void glad_vk_load_VK_KHR_ray_tracing_pipeline( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_ray_tracing_pipeline) return; + glad_vkCmdSetRayTracingPipelineStackSizeKHR = (PFN_vkCmdSetRayTracingPipelineStackSizeKHR) load(userptr, "vkCmdSetRayTracingPipelineStackSizeKHR"); glad_vkCmdTraceRaysIndirectKHR = (PFN_vkCmdTraceRaysIndirectKHR) load(userptr, "vkCmdTraceRaysIndirectKHR"); glad_vkCmdTraceRaysKHR = (PFN_vkCmdTraceRaysKHR) load(userptr, "vkCmdTraceRaysKHR"); - glad_vkCmdWriteAccelerationStructuresPropertiesKHR = (PFN_vkCmdWriteAccelerationStructuresPropertiesKHR) load(userptr, "vkCmdWriteAccelerationStructuresPropertiesKHR"); - glad_vkCopyAccelerationStructureKHR = (PFN_vkCopyAccelerationStructureKHR) load(userptr, "vkCopyAccelerationStructureKHR"); - glad_vkCopyAccelerationStructureToMemoryKHR = (PFN_vkCopyAccelerationStructureToMemoryKHR) load(userptr, "vkCopyAccelerationStructureToMemoryKHR"); - glad_vkCopyMemoryToAccelerationStructureKHR = (PFN_vkCopyMemoryToAccelerationStructureKHR) load(userptr, "vkCopyMemoryToAccelerationStructureKHR"); - glad_vkCreateAccelerationStructureKHR = (PFN_vkCreateAccelerationStructureKHR) load(userptr, "vkCreateAccelerationStructureKHR"); glad_vkCreateRayTracingPipelinesKHR = (PFN_vkCreateRayTracingPipelinesKHR) load(userptr, "vkCreateRayTracingPipelinesKHR"); - glad_vkDestroyAccelerationStructureKHR = (PFN_vkDestroyAccelerationStructureKHR) load(userptr, "vkDestroyAccelerationStructureKHR"); - glad_vkGetAccelerationStructureDeviceAddressKHR = (PFN_vkGetAccelerationStructureDeviceAddressKHR) load(userptr, "vkGetAccelerationStructureDeviceAddressKHR"); - glad_vkGetAccelerationStructureMemoryRequirementsKHR = (PFN_vkGetAccelerationStructureMemoryRequirementsKHR) load(userptr, "vkGetAccelerationStructureMemoryRequirementsKHR"); - glad_vkGetDeviceAccelerationStructureCompatibilityKHR = (PFN_vkGetDeviceAccelerationStructureCompatibilityKHR) load(userptr, "vkGetDeviceAccelerationStructureCompatibilityKHR"); glad_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR = (PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR) load(userptr, "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR"); glad_vkGetRayTracingShaderGroupHandlesKHR = (PFN_vkGetRayTracingShaderGroupHandlesKHR) load(userptr, "vkGetRayTracingShaderGroupHandlesKHR"); - glad_vkWriteAccelerationStructuresPropertiesKHR = (PFN_vkWriteAccelerationStructuresPropertiesKHR) load(userptr, "vkWriteAccelerationStructuresPropertiesKHR"); + glad_vkGetRayTracingShaderGroupStackSizeKHR = (PFN_vkGetRayTracingShaderGroupStackSizeKHR) load(userptr, "vkGetRayTracingShaderGroupStackSizeKHR"); } -#endif static void glad_vk_load_VK_KHR_sampler_ycbcr_conversion( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_sampler_ycbcr_conversion) return; glad_vkCreateSamplerYcbcrConversionKHR = (PFN_vkCreateSamplerYcbcrConversionKHR) load(userptr, "vkCreateSamplerYcbcrConversionKHR"); @@ -1474,6 +2514,15 @@ static void glad_vk_load_VK_KHR_swapchain( GLADuserptrloadfunc load, void* userp glad_vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR) load(userptr, "vkGetSwapchainImagesKHR"); glad_vkQueuePresentKHR = (PFN_vkQueuePresentKHR) load(userptr, "vkQueuePresentKHR"); } +static void glad_vk_load_VK_KHR_synchronization2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_KHR_synchronization2) return; + glad_vkCmdPipelineBarrier2KHR = (PFN_vkCmdPipelineBarrier2KHR) load(userptr, "vkCmdPipelineBarrier2KHR"); + glad_vkCmdResetEvent2KHR = (PFN_vkCmdResetEvent2KHR) load(userptr, "vkCmdResetEvent2KHR"); + glad_vkCmdSetEvent2KHR = (PFN_vkCmdSetEvent2KHR) load(userptr, "vkCmdSetEvent2KHR"); + glad_vkCmdWaitEvents2KHR = (PFN_vkCmdWaitEvents2KHR) load(userptr, "vkCmdWaitEvents2KHR"); + glad_vkCmdWriteTimestamp2KHR = (PFN_vkCmdWriteTimestamp2KHR) load(userptr, "vkCmdWriteTimestamp2KHR"); + glad_vkQueueSubmit2KHR = (PFN_vkQueueSubmit2KHR) load(userptr, "vkQueueSubmit2KHR"); +} static void glad_vk_load_VK_KHR_timeline_semaphore( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_KHR_timeline_semaphore) return; glad_vkGetSemaphoreCounterValueKHR = (PFN_vkGetSemaphoreCounterValueKHR) load(userptr, "vkGetSemaphoreCounterValueKHR"); @@ -1486,6 +2535,7 @@ static void glad_vk_load_VK_KHR_wayland_surface( GLADuserptrloadfunc load, void* glad_vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR) load(userptr, "vkCreateWaylandSurfaceKHR"); glad_vkGetPhysicalDeviceWaylandPresentationSupportKHR = (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR) load(userptr, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); } + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) static void glad_vk_load_VK_KHR_win32_surface( GLADuserptrloadfunc load, void* userptr) { @@ -1493,6 +2543,7 @@ static void glad_vk_load_VK_KHR_win32_surface( GLADuserptrloadfunc load, void* u glad_vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) load(userptr, "vkCreateWin32SurfaceKHR"); glad_vkGetPhysicalDeviceWin32PresentationSupportKHR = (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR) load(userptr, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); } + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) static void glad_vk_load_VK_KHR_xcb_surface( GLADuserptrloadfunc load, void* userptr) { @@ -1500,6 +2551,7 @@ static void glad_vk_load_VK_KHR_xcb_surface( GLADuserptrloadfunc load, void* use glad_vkCreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR) load(userptr, "vkCreateXcbSurfaceKHR"); glad_vkGetPhysicalDeviceXcbPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) load(userptr, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); } + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) static void glad_vk_load_VK_KHR_xlib_surface( GLADuserptrloadfunc load, void* userptr) { @@ -1507,45 +2559,99 @@ static void glad_vk_load_VK_KHR_xlib_surface( GLADuserptrloadfunc load, void* us glad_vkCreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR) load(userptr, "vkCreateXlibSurfaceKHR"); glad_vkGetPhysicalDeviceXlibPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR) load(userptr, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); } + #endif #if defined(VK_USE_PLATFORM_IOS_MVK) static void glad_vk_load_VK_MVK_ios_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_MVK_ios_surface) return; glad_vkCreateIOSSurfaceMVK = (PFN_vkCreateIOSSurfaceMVK) load(userptr, "vkCreateIOSSurfaceMVK"); } + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) static void glad_vk_load_VK_MVK_macos_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_MVK_macos_surface) return; glad_vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK) load(userptr, "vkCreateMacOSSurfaceMVK"); } + #endif #if defined(VK_USE_PLATFORM_VI_NN) static void glad_vk_load_VK_NN_vi_surface( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NN_vi_surface) return; glad_vkCreateViSurfaceNN = (PFN_vkCreateViSurfaceNN) load(userptr, "vkCreateViSurfaceNN"); } + #endif +static void glad_vk_load_VK_NVX_binary_import( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NVX_binary_import) return; + glad_vkCmdCuLaunchKernelNVX = (PFN_vkCmdCuLaunchKernelNVX) load(userptr, "vkCmdCuLaunchKernelNVX"); + glad_vkCreateCuFunctionNVX = (PFN_vkCreateCuFunctionNVX) load(userptr, "vkCreateCuFunctionNVX"); + glad_vkCreateCuModuleNVX = (PFN_vkCreateCuModuleNVX) load(userptr, "vkCreateCuModuleNVX"); + glad_vkDestroyCuFunctionNVX = (PFN_vkDestroyCuFunctionNVX) load(userptr, "vkDestroyCuFunctionNVX"); + glad_vkDestroyCuModuleNVX = (PFN_vkDestroyCuModuleNVX) load(userptr, "vkDestroyCuModuleNVX"); +} static void glad_vk_load_VK_NVX_image_view_handle( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NVX_image_view_handle) return; glad_vkGetImageViewAddressNVX = (PFN_vkGetImageViewAddressNVX) load(userptr, "vkGetImageViewAddressNVX"); + glad_vkGetImageViewHandle64NVX = (PFN_vkGetImageViewHandle64NVX) load(userptr, "vkGetImageViewHandle64NVX"); glad_vkGetImageViewHandleNVX = (PFN_vkGetImageViewHandleNVX) load(userptr, "vkGetImageViewHandleNVX"); } +#if defined(VK_USE_PLATFORM_WIN32_KHR) +static void glad_vk_load_VK_NV_acquire_winrt_display( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_acquire_winrt_display) return; + glad_vkAcquireWinrtDisplayNV = (PFN_vkAcquireWinrtDisplayNV) load(userptr, "vkAcquireWinrtDisplayNV"); + glad_vkGetWinrtDisplayNV = (PFN_vkGetWinrtDisplayNV) load(userptr, "vkGetWinrtDisplayNV"); +} + +#endif static void glad_vk_load_VK_NV_clip_space_w_scaling( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_clip_space_w_scaling) return; glad_vkCmdSetViewportWScalingNV = (PFN_vkCmdSetViewportWScalingNV) load(userptr, "vkCmdSetViewportWScalingNV"); } +static void glad_vk_load_VK_NV_cluster_acceleration_structure( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_cluster_acceleration_structure) return; + glad_vkCmdBuildClusterAccelerationStructureIndirectNV = (PFN_vkCmdBuildClusterAccelerationStructureIndirectNV) load(userptr, "vkCmdBuildClusterAccelerationStructureIndirectNV"); + glad_vkGetClusterAccelerationStructureBuildSizesNV = (PFN_vkGetClusterAccelerationStructureBuildSizesNV) load(userptr, "vkGetClusterAccelerationStructureBuildSizesNV"); +} static void glad_vk_load_VK_NV_cooperative_matrix( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_cooperative_matrix) return; glad_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV = (PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV) load(userptr, "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV"); } +static void glad_vk_load_VK_NV_cooperative_matrix2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_cooperative_matrix2) return; + glad_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV = (PFN_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV) load(userptr, "vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV"); +} +static void glad_vk_load_VK_NV_cooperative_vector( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_cooperative_vector) return; + glad_vkCmdConvertCooperativeVectorMatrixNV = (PFN_vkCmdConvertCooperativeVectorMatrixNV) load(userptr, "vkCmdConvertCooperativeVectorMatrixNV"); + glad_vkConvertCooperativeVectorMatrixNV = (PFN_vkConvertCooperativeVectorMatrixNV) load(userptr, "vkConvertCooperativeVectorMatrixNV"); + glad_vkGetPhysicalDeviceCooperativeVectorPropertiesNV = (PFN_vkGetPhysicalDeviceCooperativeVectorPropertiesNV) load(userptr, "vkGetPhysicalDeviceCooperativeVectorPropertiesNV"); +} +static void glad_vk_load_VK_NV_copy_memory_indirect( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_copy_memory_indirect) return; + glad_vkCmdCopyMemoryIndirectNV = (PFN_vkCmdCopyMemoryIndirectNV) load(userptr, "vkCmdCopyMemoryIndirectNV"); + glad_vkCmdCopyMemoryToImageIndirectNV = (PFN_vkCmdCopyMemoryToImageIndirectNV) load(userptr, "vkCmdCopyMemoryToImageIndirectNV"); +} static void glad_vk_load_VK_NV_coverage_reduction_mode( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_coverage_reduction_mode) return; glad_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV = (PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV) load(userptr, "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV"); } +#if defined(VK_ENABLE_BETA_EXTENSIONS) +static void glad_vk_load_VK_NV_cuda_kernel_launch( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_cuda_kernel_launch) return; + glad_vkCmdCudaLaunchKernelNV = (PFN_vkCmdCudaLaunchKernelNV) load(userptr, "vkCmdCudaLaunchKernelNV"); + glad_vkCreateCudaFunctionNV = (PFN_vkCreateCudaFunctionNV) load(userptr, "vkCreateCudaFunctionNV"); + glad_vkCreateCudaModuleNV = (PFN_vkCreateCudaModuleNV) load(userptr, "vkCreateCudaModuleNV"); + glad_vkDestroyCudaFunctionNV = (PFN_vkDestroyCudaFunctionNV) load(userptr, "vkDestroyCudaFunctionNV"); + glad_vkDestroyCudaModuleNV = (PFN_vkDestroyCudaModuleNV) load(userptr, "vkDestroyCudaModuleNV"); + glad_vkGetCudaModuleCacheNV = (PFN_vkGetCudaModuleCacheNV) load(userptr, "vkGetCudaModuleCacheNV"); +} + +#endif static void glad_vk_load_VK_NV_device_diagnostic_checkpoints( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_device_diagnostic_checkpoints) return; glad_vkCmdSetCheckpointNV = (PFN_vkCmdSetCheckpointNV) load(userptr, "vkCmdSetCheckpointNV"); + glad_vkGetQueueCheckpointData2NV = (PFN_vkGetQueueCheckpointData2NV) load(userptr, "vkGetQueueCheckpointData2NV"); glad_vkGetQueueCheckpointDataNV = (PFN_vkGetQueueCheckpointDataNV) load(userptr, "vkGetQueueCheckpointDataNV"); } static void glad_vk_load_VK_NV_device_generated_commands( GLADuserptrloadfunc load, void* userptr) { @@ -1557,22 +2663,69 @@ static void glad_vk_load_VK_NV_device_generated_commands( GLADuserptrloadfunc lo glad_vkDestroyIndirectCommandsLayoutNV = (PFN_vkDestroyIndirectCommandsLayoutNV) load(userptr, "vkDestroyIndirectCommandsLayoutNV"); glad_vkGetGeneratedCommandsMemoryRequirementsNV = (PFN_vkGetGeneratedCommandsMemoryRequirementsNV) load(userptr, "vkGetGeneratedCommandsMemoryRequirementsNV"); } +static void glad_vk_load_VK_NV_device_generated_commands_compute( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_device_generated_commands_compute) return; + glad_vkCmdUpdatePipelineIndirectBufferNV = (PFN_vkCmdUpdatePipelineIndirectBufferNV) load(userptr, "vkCmdUpdatePipelineIndirectBufferNV"); + glad_vkGetPipelineIndirectDeviceAddressNV = (PFN_vkGetPipelineIndirectDeviceAddressNV) load(userptr, "vkGetPipelineIndirectDeviceAddressNV"); + glad_vkGetPipelineIndirectMemoryRequirementsNV = (PFN_vkGetPipelineIndirectMemoryRequirementsNV) load(userptr, "vkGetPipelineIndirectMemoryRequirementsNV"); +} +static void glad_vk_load_VK_NV_external_compute_queue( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_external_compute_queue) return; + glad_vkCreateExternalComputeQueueNV = (PFN_vkCreateExternalComputeQueueNV) load(userptr, "vkCreateExternalComputeQueueNV"); + glad_vkDestroyExternalComputeQueueNV = (PFN_vkDestroyExternalComputeQueueNV) load(userptr, "vkDestroyExternalComputeQueueNV"); + glad_vkGetExternalComputeQueueDataNV = (PFN_vkGetExternalComputeQueueDataNV) load(userptr, "vkGetExternalComputeQueueDataNV"); +} static void glad_vk_load_VK_NV_external_memory_capabilities( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_external_memory_capabilities) return; glad_vkGetPhysicalDeviceExternalImageFormatPropertiesNV = (PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV) load(userptr, "vkGetPhysicalDeviceExternalImageFormatPropertiesNV"); } +static void glad_vk_load_VK_NV_external_memory_rdma( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_external_memory_rdma) return; + glad_vkGetMemoryRemoteAddressNV = (PFN_vkGetMemoryRemoteAddressNV) load(userptr, "vkGetMemoryRemoteAddressNV"); +} #if defined(VK_USE_PLATFORM_WIN32_KHR) static void glad_vk_load_VK_NV_external_memory_win32( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_external_memory_win32) return; glad_vkGetMemoryWin32HandleNV = (PFN_vkGetMemoryWin32HandleNV) load(userptr, "vkGetMemoryWin32HandleNV"); } + #endif +static void glad_vk_load_VK_NV_fragment_shading_rate_enums( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_fragment_shading_rate_enums) return; + glad_vkCmdSetFragmentShadingRateEnumNV = (PFN_vkCmdSetFragmentShadingRateEnumNV) load(userptr, "vkCmdSetFragmentShadingRateEnumNV"); +} +static void glad_vk_load_VK_NV_low_latency2( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_low_latency2) return; + glad_vkGetLatencyTimingsNV = (PFN_vkGetLatencyTimingsNV) load(userptr, "vkGetLatencyTimingsNV"); + glad_vkLatencySleepNV = (PFN_vkLatencySleepNV) load(userptr, "vkLatencySleepNV"); + glad_vkQueueNotifyOutOfBandNV = (PFN_vkQueueNotifyOutOfBandNV) load(userptr, "vkQueueNotifyOutOfBandNV"); + glad_vkSetLatencyMarkerNV = (PFN_vkSetLatencyMarkerNV) load(userptr, "vkSetLatencyMarkerNV"); + glad_vkSetLatencySleepModeNV = (PFN_vkSetLatencySleepModeNV) load(userptr, "vkSetLatencySleepModeNV"); +} +static void glad_vk_load_VK_NV_memory_decompression( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_memory_decompression) return; + glad_vkCmdDecompressMemoryIndirectCountNV = (PFN_vkCmdDecompressMemoryIndirectCountNV) load(userptr, "vkCmdDecompressMemoryIndirectCountNV"); + glad_vkCmdDecompressMemoryNV = (PFN_vkCmdDecompressMemoryNV) load(userptr, "vkCmdDecompressMemoryNV"); +} static void glad_vk_load_VK_NV_mesh_shader( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_mesh_shader) return; glad_vkCmdDrawMeshTasksIndirectCountNV = (PFN_vkCmdDrawMeshTasksIndirectCountNV) load(userptr, "vkCmdDrawMeshTasksIndirectCountNV"); glad_vkCmdDrawMeshTasksIndirectNV = (PFN_vkCmdDrawMeshTasksIndirectNV) load(userptr, "vkCmdDrawMeshTasksIndirectNV"); glad_vkCmdDrawMeshTasksNV = (PFN_vkCmdDrawMeshTasksNV) load(userptr, "vkCmdDrawMeshTasksNV"); } +static void glad_vk_load_VK_NV_optical_flow( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_optical_flow) return; + glad_vkBindOpticalFlowSessionImageNV = (PFN_vkBindOpticalFlowSessionImageNV) load(userptr, "vkBindOpticalFlowSessionImageNV"); + glad_vkCmdOpticalFlowExecuteNV = (PFN_vkCmdOpticalFlowExecuteNV) load(userptr, "vkCmdOpticalFlowExecuteNV"); + glad_vkCreateOpticalFlowSessionNV = (PFN_vkCreateOpticalFlowSessionNV) load(userptr, "vkCreateOpticalFlowSessionNV"); + glad_vkDestroyOpticalFlowSessionNV = (PFN_vkDestroyOpticalFlowSessionNV) load(userptr, "vkDestroyOpticalFlowSessionNV"); + glad_vkGetPhysicalDeviceOpticalFlowImageFormatsNV = (PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV) load(userptr, "vkGetPhysicalDeviceOpticalFlowImageFormatsNV"); +} +static void glad_vk_load_VK_NV_partitioned_acceleration_structure( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_NV_partitioned_acceleration_structure) return; + glad_vkCmdBuildPartitionedAccelerationStructuresNV = (PFN_vkCmdBuildPartitionedAccelerationStructuresNV) load(userptr, "vkCmdBuildPartitionedAccelerationStructuresNV"); + glad_vkGetPartitionedAccelerationStructuresBuildSizesNV = (PFN_vkGetPartitionedAccelerationStructuresBuildSizesNV) load(userptr, "vkGetPartitionedAccelerationStructuresBuildSizesNV"); +} static void glad_vk_load_VK_NV_ray_tracing( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_ray_tracing) return; glad_vkBindAccelerationStructureMemoryNV = (PFN_vkBindAccelerationStructureMemoryNV) load(userptr, "vkBindAccelerationStructureMemoryNV"); @@ -1590,6 +2743,7 @@ static void glad_vk_load_VK_NV_ray_tracing( GLADuserptrloadfunc load, void* user } static void glad_vk_load_VK_NV_scissor_exclusive( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_VK_NV_scissor_exclusive) return; + glad_vkCmdSetExclusiveScissorEnableNV = (PFN_vkCmdSetExclusiveScissorEnableNV) load(userptr, "vkCmdSetExclusiveScissorEnableNV"); glad_vkCmdSetExclusiveScissorNV = (PFN_vkCmdSetExclusiveScissorNV) load(userptr, "vkCmdSetExclusiveScissorNV"); } static void glad_vk_load_VK_NV_shading_rate_image( GLADuserptrloadfunc load, void* userptr) { @@ -1598,6 +2752,41 @@ static void glad_vk_load_VK_NV_shading_rate_image( GLADuserptrloadfunc load, voi glad_vkCmdSetCoarseSampleOrderNV = (PFN_vkCmdSetCoarseSampleOrderNV) load(userptr, "vkCmdSetCoarseSampleOrderNV"); glad_vkCmdSetViewportShadingRatePaletteNV = (PFN_vkCmdSetViewportShadingRatePaletteNV) load(userptr, "vkCmdSetViewportShadingRatePaletteNV"); } +static void glad_vk_load_VK_QCOM_tile_memory_heap( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_QCOM_tile_memory_heap) return; + glad_vkCmdBindTileMemoryQCOM = (PFN_vkCmdBindTileMemoryQCOM) load(userptr, "vkCmdBindTileMemoryQCOM"); +} +static void glad_vk_load_VK_QCOM_tile_properties( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_QCOM_tile_properties) return; + glad_vkGetDynamicRenderingTilePropertiesQCOM = (PFN_vkGetDynamicRenderingTilePropertiesQCOM) load(userptr, "vkGetDynamicRenderingTilePropertiesQCOM"); + glad_vkGetFramebufferTilePropertiesQCOM = (PFN_vkGetFramebufferTilePropertiesQCOM) load(userptr, "vkGetFramebufferTilePropertiesQCOM"); +} +static void glad_vk_load_VK_QCOM_tile_shading( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_QCOM_tile_shading) return; + glad_vkCmdBeginPerTileExecutionQCOM = (PFN_vkCmdBeginPerTileExecutionQCOM) load(userptr, "vkCmdBeginPerTileExecutionQCOM"); + glad_vkCmdDispatchTileQCOM = (PFN_vkCmdDispatchTileQCOM) load(userptr, "vkCmdDispatchTileQCOM"); + glad_vkCmdEndPerTileExecutionQCOM = (PFN_vkCmdEndPerTileExecutionQCOM) load(userptr, "vkCmdEndPerTileExecutionQCOM"); +} +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +static void glad_vk_load_VK_QNX_external_memory_screen_buffer( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_QNX_external_memory_screen_buffer) return; + glad_vkGetScreenBufferPropertiesQNX = (PFN_vkGetScreenBufferPropertiesQNX) load(userptr, "vkGetScreenBufferPropertiesQNX"); +} + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) +static void glad_vk_load_VK_QNX_screen_surface( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_QNX_screen_surface) return; + glad_vkCreateScreenSurfaceQNX = (PFN_vkCreateScreenSurfaceQNX) load(userptr, "vkCreateScreenSurfaceQNX"); + glad_vkGetPhysicalDeviceScreenPresentationSupportQNX = (PFN_vkGetPhysicalDeviceScreenPresentationSupportQNX) load(userptr, "vkGetPhysicalDeviceScreenPresentationSupportQNX"); +} + +#endif +static void glad_vk_load_VK_VALVE_descriptor_set_host_mapping( GLADuserptrloadfunc load, void* userptr) { + if(!GLAD_VK_VALVE_descriptor_set_host_mapping) return; + glad_vkGetDescriptorSetHostMappingVALVE = (PFN_vkGetDescriptorSetHostMappingVALVE) load(userptr, "vkGetDescriptorSetHostMappingVALVE"); + glad_vkGetDescriptorSetLayoutHostMappingInfoVALVE = (PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE) load(userptr, "vkGetDescriptorSetLayoutHostMappingInfoVALVE"); +} @@ -1728,6 +2917,11 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { char **extensions = NULL; if (!glad_vk_get_extensions(physical_device, &extension_count, &extensions)) return 0; +#if defined(VK_ENABLE_BETA_EXTENSIONS) + GLAD_VK_AMDX_shader_enqueue = glad_vk_has_extension("VK_AMDX_shader_enqueue", extension_count, extensions); + +#endif + GLAD_VK_AMD_anti_lag = glad_vk_has_extension("VK_AMD_anti_lag", extension_count, extensions); GLAD_VK_AMD_buffer_marker = glad_vk_has_extension("VK_AMD_buffer_marker", extension_count, extensions); GLAD_VK_AMD_device_coherent_memory = glad_vk_has_extension("VK_AMD_device_coherent_memory", extension_count, extensions); GLAD_VK_AMD_display_native_hdr = glad_vk_has_extension("VK_AMD_display_native_hdr", extension_count, extensions); @@ -1743,82 +2937,167 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { GLAD_VK_AMD_shader_ballot = glad_vk_has_extension("VK_AMD_shader_ballot", extension_count, extensions); GLAD_VK_AMD_shader_core_properties = glad_vk_has_extension("VK_AMD_shader_core_properties", extension_count, extensions); GLAD_VK_AMD_shader_core_properties2 = glad_vk_has_extension("VK_AMD_shader_core_properties2", extension_count, extensions); + GLAD_VK_AMD_shader_early_and_late_fragment_tests = glad_vk_has_extension("VK_AMD_shader_early_and_late_fragment_tests", extension_count, extensions); GLAD_VK_AMD_shader_explicit_vertex_parameter = glad_vk_has_extension("VK_AMD_shader_explicit_vertex_parameter", extension_count, extensions); GLAD_VK_AMD_shader_fragment_mask = glad_vk_has_extension("VK_AMD_shader_fragment_mask", extension_count, extensions); GLAD_VK_AMD_shader_image_load_store_lod = glad_vk_has_extension("VK_AMD_shader_image_load_store_lod", extension_count, extensions); GLAD_VK_AMD_shader_info = glad_vk_has_extension("VK_AMD_shader_info", extension_count, extensions); GLAD_VK_AMD_shader_trinary_minmax = glad_vk_has_extension("VK_AMD_shader_trinary_minmax", extension_count, extensions); GLAD_VK_AMD_texture_gather_bias_lod = glad_vk_has_extension("VK_AMD_texture_gather_bias_lod", extension_count, extensions); +#if defined(VK_USE_PLATFORM_ANDROID_KHR) + GLAD_VK_ANDROID_external_format_resolve = glad_vk_has_extension("VK_ANDROID_external_format_resolve", extension_count, extensions); + +#endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) GLAD_VK_ANDROID_external_memory_android_hardware_buffer = glad_vk_has_extension("VK_ANDROID_external_memory_android_hardware_buffer", extension_count, extensions); + #endif + GLAD_VK_ARM_pipeline_opacity_micromap = glad_vk_has_extension("VK_ARM_pipeline_opacity_micromap", extension_count, extensions); + GLAD_VK_ARM_rasterization_order_attachment_access = glad_vk_has_extension("VK_ARM_rasterization_order_attachment_access", extension_count, extensions); + GLAD_VK_ARM_render_pass_striped = glad_vk_has_extension("VK_ARM_render_pass_striped", extension_count, extensions); + GLAD_VK_ARM_scheduling_controls = glad_vk_has_extension("VK_ARM_scheduling_controls", extension_count, extensions); + GLAD_VK_ARM_shader_core_builtins = glad_vk_has_extension("VK_ARM_shader_core_builtins", extension_count, extensions); + GLAD_VK_ARM_shader_core_properties = glad_vk_has_extension("VK_ARM_shader_core_properties", extension_count, extensions); GLAD_VK_EXT_4444_formats = glad_vk_has_extension("VK_EXT_4444_formats", extension_count, extensions); + GLAD_VK_EXT_acquire_drm_display = glad_vk_has_extension("VK_EXT_acquire_drm_display", extension_count, extensions); #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) GLAD_VK_EXT_acquire_xlib_display = glad_vk_has_extension("VK_EXT_acquire_xlib_display", extension_count, extensions); + #endif GLAD_VK_EXT_astc_decode_mode = glad_vk_has_extension("VK_EXT_astc_decode_mode", extension_count, extensions); + GLAD_VK_EXT_attachment_feedback_loop_dynamic_state = glad_vk_has_extension("VK_EXT_attachment_feedback_loop_dynamic_state", extension_count, extensions); + GLAD_VK_EXT_attachment_feedback_loop_layout = glad_vk_has_extension("VK_EXT_attachment_feedback_loop_layout", extension_count, extensions); GLAD_VK_EXT_blend_operation_advanced = glad_vk_has_extension("VK_EXT_blend_operation_advanced", extension_count, extensions); + GLAD_VK_EXT_border_color_swizzle = glad_vk_has_extension("VK_EXT_border_color_swizzle", extension_count, extensions); GLAD_VK_EXT_buffer_device_address = glad_vk_has_extension("VK_EXT_buffer_device_address", extension_count, extensions); GLAD_VK_EXT_calibrated_timestamps = glad_vk_has_extension("VK_EXT_calibrated_timestamps", extension_count, extensions); + GLAD_VK_EXT_color_write_enable = glad_vk_has_extension("VK_EXT_color_write_enable", extension_count, extensions); GLAD_VK_EXT_conditional_rendering = glad_vk_has_extension("VK_EXT_conditional_rendering", extension_count, extensions); GLAD_VK_EXT_conservative_rasterization = glad_vk_has_extension("VK_EXT_conservative_rasterization", extension_count, extensions); GLAD_VK_EXT_custom_border_color = glad_vk_has_extension("VK_EXT_custom_border_color", extension_count, extensions); GLAD_VK_EXT_debug_marker = glad_vk_has_extension("VK_EXT_debug_marker", extension_count, extensions); GLAD_VK_EXT_debug_report = glad_vk_has_extension("VK_EXT_debug_report", extension_count, extensions); GLAD_VK_EXT_debug_utils = glad_vk_has_extension("VK_EXT_debug_utils", extension_count, extensions); + GLAD_VK_EXT_depth_bias_control = glad_vk_has_extension("VK_EXT_depth_bias_control", extension_count, extensions); + GLAD_VK_EXT_depth_clamp_control = glad_vk_has_extension("VK_EXT_depth_clamp_control", extension_count, extensions); + GLAD_VK_EXT_depth_clamp_zero_one = glad_vk_has_extension("VK_EXT_depth_clamp_zero_one", extension_count, extensions); + GLAD_VK_EXT_depth_clip_control = glad_vk_has_extension("VK_EXT_depth_clip_control", extension_count, extensions); GLAD_VK_EXT_depth_clip_enable = glad_vk_has_extension("VK_EXT_depth_clip_enable", extension_count, extensions); GLAD_VK_EXT_depth_range_unrestricted = glad_vk_has_extension("VK_EXT_depth_range_unrestricted", extension_count, extensions); + GLAD_VK_EXT_descriptor_buffer = glad_vk_has_extension("VK_EXT_descriptor_buffer", extension_count, extensions); GLAD_VK_EXT_descriptor_indexing = glad_vk_has_extension("VK_EXT_descriptor_indexing", extension_count, extensions); + GLAD_VK_EXT_device_address_binding_report = glad_vk_has_extension("VK_EXT_device_address_binding_report", extension_count, extensions); + GLAD_VK_EXT_device_fault = glad_vk_has_extension("VK_EXT_device_fault", extension_count, extensions); + GLAD_VK_EXT_device_generated_commands = glad_vk_has_extension("VK_EXT_device_generated_commands", extension_count, extensions); + GLAD_VK_EXT_device_memory_report = glad_vk_has_extension("VK_EXT_device_memory_report", extension_count, extensions); GLAD_VK_EXT_direct_mode_display = glad_vk_has_extension("VK_EXT_direct_mode_display", extension_count, extensions); #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) GLAD_VK_EXT_directfb_surface = glad_vk_has_extension("VK_EXT_directfb_surface", extension_count, extensions); + #endif GLAD_VK_EXT_discard_rectangles = glad_vk_has_extension("VK_EXT_discard_rectangles", extension_count, extensions); GLAD_VK_EXT_display_control = glad_vk_has_extension("VK_EXT_display_control", extension_count, extensions); GLAD_VK_EXT_display_surface_counter = glad_vk_has_extension("VK_EXT_display_surface_counter", extension_count, extensions); + GLAD_VK_EXT_dynamic_rendering_unused_attachments = glad_vk_has_extension("VK_EXT_dynamic_rendering_unused_attachments", extension_count, extensions); GLAD_VK_EXT_extended_dynamic_state = glad_vk_has_extension("VK_EXT_extended_dynamic_state", extension_count, extensions); + GLAD_VK_EXT_extended_dynamic_state2 = glad_vk_has_extension("VK_EXT_extended_dynamic_state2", extension_count, extensions); + GLAD_VK_EXT_extended_dynamic_state3 = glad_vk_has_extension("VK_EXT_extended_dynamic_state3", extension_count, extensions); + GLAD_VK_EXT_external_memory_acquire_unmodified = glad_vk_has_extension("VK_EXT_external_memory_acquire_unmodified", extension_count, extensions); GLAD_VK_EXT_external_memory_dma_buf = glad_vk_has_extension("VK_EXT_external_memory_dma_buf", extension_count, extensions); GLAD_VK_EXT_external_memory_host = glad_vk_has_extension("VK_EXT_external_memory_host", extension_count, extensions); +#if defined(VK_USE_PLATFORM_METAL_EXT) + GLAD_VK_EXT_external_memory_metal = glad_vk_has_extension("VK_EXT_external_memory_metal", extension_count, extensions); + +#endif GLAD_VK_EXT_filter_cubic = glad_vk_has_extension("VK_EXT_filter_cubic", extension_count, extensions); GLAD_VK_EXT_fragment_density_map = glad_vk_has_extension("VK_EXT_fragment_density_map", extension_count, extensions); GLAD_VK_EXT_fragment_density_map2 = glad_vk_has_extension("VK_EXT_fragment_density_map2", extension_count, extensions); + GLAD_VK_EXT_fragment_density_map_offset = glad_vk_has_extension("VK_EXT_fragment_density_map_offset", extension_count, extensions); GLAD_VK_EXT_fragment_shader_interlock = glad_vk_has_extension("VK_EXT_fragment_shader_interlock", extension_count, extensions); + GLAD_VK_EXT_frame_boundary = glad_vk_has_extension("VK_EXT_frame_boundary", extension_count, extensions); #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_EXT_full_screen_exclusive = glad_vk_has_extension("VK_EXT_full_screen_exclusive", extension_count, extensions); + #endif GLAD_VK_EXT_global_priority = glad_vk_has_extension("VK_EXT_global_priority", extension_count, extensions); + GLAD_VK_EXT_global_priority_query = glad_vk_has_extension("VK_EXT_global_priority_query", extension_count, extensions); + GLAD_VK_EXT_graphics_pipeline_library = glad_vk_has_extension("VK_EXT_graphics_pipeline_library", extension_count, extensions); GLAD_VK_EXT_hdr_metadata = glad_vk_has_extension("VK_EXT_hdr_metadata", extension_count, extensions); GLAD_VK_EXT_headless_surface = glad_vk_has_extension("VK_EXT_headless_surface", extension_count, extensions); + GLAD_VK_EXT_host_image_copy = glad_vk_has_extension("VK_EXT_host_image_copy", extension_count, extensions); GLAD_VK_EXT_host_query_reset = glad_vk_has_extension("VK_EXT_host_query_reset", extension_count, extensions); + GLAD_VK_EXT_image_2d_view_of_3d = glad_vk_has_extension("VK_EXT_image_2d_view_of_3d", extension_count, extensions); + GLAD_VK_EXT_image_compression_control = glad_vk_has_extension("VK_EXT_image_compression_control", extension_count, extensions); + GLAD_VK_EXT_image_compression_control_swapchain = glad_vk_has_extension("VK_EXT_image_compression_control_swapchain", extension_count, extensions); GLAD_VK_EXT_image_drm_format_modifier = glad_vk_has_extension("VK_EXT_image_drm_format_modifier", extension_count, extensions); GLAD_VK_EXT_image_robustness = glad_vk_has_extension("VK_EXT_image_robustness", extension_count, extensions); + GLAD_VK_EXT_image_sliced_view_of_3d = glad_vk_has_extension("VK_EXT_image_sliced_view_of_3d", extension_count, extensions); + GLAD_VK_EXT_image_view_min_lod = glad_vk_has_extension("VK_EXT_image_view_min_lod", extension_count, extensions); GLAD_VK_EXT_index_type_uint8 = glad_vk_has_extension("VK_EXT_index_type_uint8", extension_count, extensions); GLAD_VK_EXT_inline_uniform_block = glad_vk_has_extension("VK_EXT_inline_uniform_block", extension_count, extensions); + GLAD_VK_EXT_layer_settings = glad_vk_has_extension("VK_EXT_layer_settings", extension_count, extensions); + GLAD_VK_EXT_legacy_dithering = glad_vk_has_extension("VK_EXT_legacy_dithering", extension_count, extensions); + GLAD_VK_EXT_legacy_vertex_attributes = glad_vk_has_extension("VK_EXT_legacy_vertex_attributes", extension_count, extensions); GLAD_VK_EXT_line_rasterization = glad_vk_has_extension("VK_EXT_line_rasterization", extension_count, extensions); + GLAD_VK_EXT_load_store_op_none = glad_vk_has_extension("VK_EXT_load_store_op_none", extension_count, extensions); + GLAD_VK_EXT_map_memory_placed = glad_vk_has_extension("VK_EXT_map_memory_placed", extension_count, extensions); GLAD_VK_EXT_memory_budget = glad_vk_has_extension("VK_EXT_memory_budget", extension_count, extensions); GLAD_VK_EXT_memory_priority = glad_vk_has_extension("VK_EXT_memory_priority", extension_count, extensions); + GLAD_VK_EXT_mesh_shader = glad_vk_has_extension("VK_EXT_mesh_shader", extension_count, extensions); +#if defined(VK_USE_PLATFORM_METAL_EXT) + GLAD_VK_EXT_metal_objects = glad_vk_has_extension("VK_EXT_metal_objects", extension_count, extensions); + +#endif #if defined(VK_USE_PLATFORM_METAL_EXT) GLAD_VK_EXT_metal_surface = glad_vk_has_extension("VK_EXT_metal_surface", extension_count, extensions); + #endif + GLAD_VK_EXT_multi_draw = glad_vk_has_extension("VK_EXT_multi_draw", extension_count, extensions); + GLAD_VK_EXT_multisampled_render_to_single_sampled = glad_vk_has_extension("VK_EXT_multisampled_render_to_single_sampled", extension_count, extensions); + GLAD_VK_EXT_mutable_descriptor_type = glad_vk_has_extension("VK_EXT_mutable_descriptor_type", extension_count, extensions); + GLAD_VK_EXT_nested_command_buffer = glad_vk_has_extension("VK_EXT_nested_command_buffer", extension_count, extensions); + GLAD_VK_EXT_non_seamless_cube_map = glad_vk_has_extension("VK_EXT_non_seamless_cube_map", extension_count, extensions); + GLAD_VK_EXT_opacity_micromap = glad_vk_has_extension("VK_EXT_opacity_micromap", extension_count, extensions); + GLAD_VK_EXT_pageable_device_local_memory = glad_vk_has_extension("VK_EXT_pageable_device_local_memory", extension_count, extensions); GLAD_VK_EXT_pci_bus_info = glad_vk_has_extension("VK_EXT_pci_bus_info", extension_count, extensions); + GLAD_VK_EXT_physical_device_drm = glad_vk_has_extension("VK_EXT_physical_device_drm", extension_count, extensions); GLAD_VK_EXT_pipeline_creation_cache_control = glad_vk_has_extension("VK_EXT_pipeline_creation_cache_control", extension_count, extensions); GLAD_VK_EXT_pipeline_creation_feedback = glad_vk_has_extension("VK_EXT_pipeline_creation_feedback", extension_count, extensions); + GLAD_VK_EXT_pipeline_library_group_handles = glad_vk_has_extension("VK_EXT_pipeline_library_group_handles", extension_count, extensions); + GLAD_VK_EXT_pipeline_properties = glad_vk_has_extension("VK_EXT_pipeline_properties", extension_count, extensions); + GLAD_VK_EXT_pipeline_protected_access = glad_vk_has_extension("VK_EXT_pipeline_protected_access", extension_count, extensions); + GLAD_VK_EXT_pipeline_robustness = glad_vk_has_extension("VK_EXT_pipeline_robustness", extension_count, extensions); GLAD_VK_EXT_post_depth_coverage = glad_vk_has_extension("VK_EXT_post_depth_coverage", extension_count, extensions); + GLAD_VK_EXT_present_mode_fifo_latest_ready = glad_vk_has_extension("VK_EXT_present_mode_fifo_latest_ready", extension_count, extensions); + GLAD_VK_EXT_primitive_topology_list_restart = glad_vk_has_extension("VK_EXT_primitive_topology_list_restart", extension_count, extensions); + GLAD_VK_EXT_primitives_generated_query = glad_vk_has_extension("VK_EXT_primitives_generated_query", extension_count, extensions); GLAD_VK_EXT_private_data = glad_vk_has_extension("VK_EXT_private_data", extension_count, extensions); + GLAD_VK_EXT_provoking_vertex = glad_vk_has_extension("VK_EXT_provoking_vertex", extension_count, extensions); GLAD_VK_EXT_queue_family_foreign = glad_vk_has_extension("VK_EXT_queue_family_foreign", extension_count, extensions); + GLAD_VK_EXT_rasterization_order_attachment_access = glad_vk_has_extension("VK_EXT_rasterization_order_attachment_access", extension_count, extensions); + GLAD_VK_EXT_rgba10x6_formats = glad_vk_has_extension("VK_EXT_rgba10x6_formats", extension_count, extensions); GLAD_VK_EXT_robustness2 = glad_vk_has_extension("VK_EXT_robustness2", extension_count, extensions); GLAD_VK_EXT_sample_locations = glad_vk_has_extension("VK_EXT_sample_locations", extension_count, extensions); GLAD_VK_EXT_sampler_filter_minmax = glad_vk_has_extension("VK_EXT_sampler_filter_minmax", extension_count, extensions); GLAD_VK_EXT_scalar_block_layout = glad_vk_has_extension("VK_EXT_scalar_block_layout", extension_count, extensions); GLAD_VK_EXT_separate_stencil_usage = glad_vk_has_extension("VK_EXT_separate_stencil_usage", extension_count, extensions); GLAD_VK_EXT_shader_atomic_float = glad_vk_has_extension("VK_EXT_shader_atomic_float", extension_count, extensions); + GLAD_VK_EXT_shader_atomic_float2 = glad_vk_has_extension("VK_EXT_shader_atomic_float2", extension_count, extensions); GLAD_VK_EXT_shader_demote_to_helper_invocation = glad_vk_has_extension("VK_EXT_shader_demote_to_helper_invocation", extension_count, extensions); + GLAD_VK_EXT_shader_image_atomic_int64 = glad_vk_has_extension("VK_EXT_shader_image_atomic_int64", extension_count, extensions); + GLAD_VK_EXT_shader_module_identifier = glad_vk_has_extension("VK_EXT_shader_module_identifier", extension_count, extensions); + GLAD_VK_EXT_shader_object = glad_vk_has_extension("VK_EXT_shader_object", extension_count, extensions); + GLAD_VK_EXT_shader_replicated_composites = glad_vk_has_extension("VK_EXT_shader_replicated_composites", extension_count, extensions); GLAD_VK_EXT_shader_stencil_export = glad_vk_has_extension("VK_EXT_shader_stencil_export", extension_count, extensions); GLAD_VK_EXT_shader_subgroup_ballot = glad_vk_has_extension("VK_EXT_shader_subgroup_ballot", extension_count, extensions); GLAD_VK_EXT_shader_subgroup_vote = glad_vk_has_extension("VK_EXT_shader_subgroup_vote", extension_count, extensions); + GLAD_VK_EXT_shader_tile_image = glad_vk_has_extension("VK_EXT_shader_tile_image", extension_count, extensions); GLAD_VK_EXT_shader_viewport_index_layer = glad_vk_has_extension("VK_EXT_shader_viewport_index_layer", extension_count, extensions); GLAD_VK_EXT_subgroup_size_control = glad_vk_has_extension("VK_EXT_subgroup_size_control", extension_count, extensions); + GLAD_VK_EXT_subpass_merge_feedback = glad_vk_has_extension("VK_EXT_subpass_merge_feedback", extension_count, extensions); + GLAD_VK_EXT_surface_maintenance1 = glad_vk_has_extension("VK_EXT_surface_maintenance1", extension_count, extensions); GLAD_VK_EXT_swapchain_colorspace = glad_vk_has_extension("VK_EXT_swapchain_colorspace", extension_count, extensions); + GLAD_VK_EXT_swapchain_maintenance1 = glad_vk_has_extension("VK_EXT_swapchain_maintenance1", extension_count, extensions); GLAD_VK_EXT_texel_buffer_alignment = glad_vk_has_extension("VK_EXT_texel_buffer_alignment", extension_count, extensions); GLAD_VK_EXT_texture_compression_astc_hdr = glad_vk_has_extension("VK_EXT_texture_compression_astc_hdr", extension_count, extensions); GLAD_VK_EXT_tooling_info = glad_vk_has_extension("VK_EXT_tooling_info", extension_count, extensions); @@ -1827,36 +3106,65 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { GLAD_VK_EXT_validation_features = glad_vk_has_extension("VK_EXT_validation_features", extension_count, extensions); GLAD_VK_EXT_validation_flags = glad_vk_has_extension("VK_EXT_validation_flags", extension_count, extensions); GLAD_VK_EXT_vertex_attribute_divisor = glad_vk_has_extension("VK_EXT_vertex_attribute_divisor", extension_count, extensions); + GLAD_VK_EXT_vertex_attribute_robustness = glad_vk_has_extension("VK_EXT_vertex_attribute_robustness", extension_count, extensions); + GLAD_VK_EXT_vertex_input_dynamic_state = glad_vk_has_extension("VK_EXT_vertex_input_dynamic_state", extension_count, extensions); + GLAD_VK_EXT_ycbcr_2plane_444_formats = glad_vk_has_extension("VK_EXT_ycbcr_2plane_444_formats", extension_count, extensions); GLAD_VK_EXT_ycbcr_image_arrays = glad_vk_has_extension("VK_EXT_ycbcr_image_arrays", extension_count, extensions); +#if defined(VK_USE_PLATFORM_FUCHSIA) + GLAD_VK_FUCHSIA_buffer_collection = glad_vk_has_extension("VK_FUCHSIA_buffer_collection", extension_count, extensions); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) + GLAD_VK_FUCHSIA_external_memory = glad_vk_has_extension("VK_FUCHSIA_external_memory", extension_count, extensions); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) + GLAD_VK_FUCHSIA_external_semaphore = glad_vk_has_extension("VK_FUCHSIA_external_semaphore", extension_count, extensions); + +#endif #if defined(VK_USE_PLATFORM_FUCHSIA) GLAD_VK_FUCHSIA_imagepipe_surface = glad_vk_has_extension("VK_FUCHSIA_imagepipe_surface", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_GGP) GLAD_VK_GGP_frame_token = glad_vk_has_extension("VK_GGP_frame_token", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_GGP) GLAD_VK_GGP_stream_descriptor_surface = glad_vk_has_extension("VK_GGP_stream_descriptor_surface", extension_count, extensions); + #endif GLAD_VK_GOOGLE_decorate_string = glad_vk_has_extension("VK_GOOGLE_decorate_string", extension_count, extensions); GLAD_VK_GOOGLE_display_timing = glad_vk_has_extension("VK_GOOGLE_display_timing", extension_count, extensions); GLAD_VK_GOOGLE_hlsl_functionality1 = glad_vk_has_extension("VK_GOOGLE_hlsl_functionality1", extension_count, extensions); + GLAD_VK_GOOGLE_surfaceless_query = glad_vk_has_extension("VK_GOOGLE_surfaceless_query", extension_count, extensions); GLAD_VK_GOOGLE_user_type = glad_vk_has_extension("VK_GOOGLE_user_type", extension_count, extensions); + GLAD_VK_HUAWEI_cluster_culling_shader = glad_vk_has_extension("VK_HUAWEI_cluster_culling_shader", extension_count, extensions); + GLAD_VK_HUAWEI_hdr_vivid = glad_vk_has_extension("VK_HUAWEI_hdr_vivid", extension_count, extensions); + GLAD_VK_HUAWEI_invocation_mask = glad_vk_has_extension("VK_HUAWEI_invocation_mask", extension_count, extensions); + GLAD_VK_HUAWEI_subpass_shading = glad_vk_has_extension("VK_HUAWEI_subpass_shading", extension_count, extensions); GLAD_VK_IMG_filter_cubic = glad_vk_has_extension("VK_IMG_filter_cubic", extension_count, extensions); GLAD_VK_IMG_format_pvrtc = glad_vk_has_extension("VK_IMG_format_pvrtc", extension_count, extensions); + GLAD_VK_IMG_relaxed_line_rasterization = glad_vk_has_extension("VK_IMG_relaxed_line_rasterization", extension_count, extensions); GLAD_VK_INTEL_performance_query = glad_vk_has_extension("VK_INTEL_performance_query", extension_count, extensions); GLAD_VK_INTEL_shader_integer_functions2 = glad_vk_has_extension("VK_INTEL_shader_integer_functions2", extension_count, extensions); GLAD_VK_KHR_16bit_storage = glad_vk_has_extension("VK_KHR_16bit_storage", extension_count, extensions); GLAD_VK_KHR_8bit_storage = glad_vk_has_extension("VK_KHR_8bit_storage", extension_count, extensions); + GLAD_VK_KHR_acceleration_structure = glad_vk_has_extension("VK_KHR_acceleration_structure", extension_count, extensions); #if defined(VK_USE_PLATFORM_ANDROID_KHR) GLAD_VK_KHR_android_surface = glad_vk_has_extension("VK_KHR_android_surface", extension_count, extensions); + #endif GLAD_VK_KHR_bind_memory2 = glad_vk_has_extension("VK_KHR_bind_memory2", extension_count, extensions); GLAD_VK_KHR_buffer_device_address = glad_vk_has_extension("VK_KHR_buffer_device_address", extension_count, extensions); + GLAD_VK_KHR_calibrated_timestamps = glad_vk_has_extension("VK_KHR_calibrated_timestamps", extension_count, extensions); + GLAD_VK_KHR_compute_shader_derivatives = glad_vk_has_extension("VK_KHR_compute_shader_derivatives", extension_count, extensions); + GLAD_VK_KHR_cooperative_matrix = glad_vk_has_extension("VK_KHR_cooperative_matrix", extension_count, extensions); + GLAD_VK_KHR_copy_commands2 = glad_vk_has_extension("VK_KHR_copy_commands2", extension_count, extensions); GLAD_VK_KHR_create_renderpass2 = glad_vk_has_extension("VK_KHR_create_renderpass2", extension_count, extensions); GLAD_VK_KHR_dedicated_allocation = glad_vk_has_extension("VK_KHR_dedicated_allocation", extension_count, extensions); -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_VK_KHR_deferred_host_operations = glad_vk_has_extension("VK_KHR_deferred_host_operations", extension_count, extensions); -#endif + GLAD_VK_KHR_depth_clamp_zero_one = glad_vk_has_extension("VK_KHR_depth_clamp_zero_one", extension_count, extensions); GLAD_VK_KHR_depth_stencil_resolve = glad_vk_has_extension("VK_KHR_depth_stencil_resolve", extension_count, extensions); GLAD_VK_KHR_descriptor_update_template = glad_vk_has_extension("VK_KHR_descriptor_update_template", extension_count, extensions); GLAD_VK_KHR_device_group = glad_vk_has_extension("VK_KHR_device_group", extension_count, extensions); @@ -1865,55 +3173,91 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { GLAD_VK_KHR_display_swapchain = glad_vk_has_extension("VK_KHR_display_swapchain", extension_count, extensions); GLAD_VK_KHR_draw_indirect_count = glad_vk_has_extension("VK_KHR_draw_indirect_count", extension_count, extensions); GLAD_VK_KHR_driver_properties = glad_vk_has_extension("VK_KHR_driver_properties", extension_count, extensions); + GLAD_VK_KHR_dynamic_rendering = glad_vk_has_extension("VK_KHR_dynamic_rendering", extension_count, extensions); + GLAD_VK_KHR_dynamic_rendering_local_read = glad_vk_has_extension("VK_KHR_dynamic_rendering_local_read", extension_count, extensions); GLAD_VK_KHR_external_fence = glad_vk_has_extension("VK_KHR_external_fence", extension_count, extensions); GLAD_VK_KHR_external_fence_capabilities = glad_vk_has_extension("VK_KHR_external_fence_capabilities", extension_count, extensions); GLAD_VK_KHR_external_fence_fd = glad_vk_has_extension("VK_KHR_external_fence_fd", extension_count, extensions); #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_KHR_external_fence_win32 = glad_vk_has_extension("VK_KHR_external_fence_win32", extension_count, extensions); + #endif GLAD_VK_KHR_external_memory = glad_vk_has_extension("VK_KHR_external_memory", extension_count, extensions); GLAD_VK_KHR_external_memory_capabilities = glad_vk_has_extension("VK_KHR_external_memory_capabilities", extension_count, extensions); GLAD_VK_KHR_external_memory_fd = glad_vk_has_extension("VK_KHR_external_memory_fd", extension_count, extensions); #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_KHR_external_memory_win32 = glad_vk_has_extension("VK_KHR_external_memory_win32", extension_count, extensions); + #endif GLAD_VK_KHR_external_semaphore = glad_vk_has_extension("VK_KHR_external_semaphore", extension_count, extensions); GLAD_VK_KHR_external_semaphore_capabilities = glad_vk_has_extension("VK_KHR_external_semaphore_capabilities", extension_count, extensions); GLAD_VK_KHR_external_semaphore_fd = glad_vk_has_extension("VK_KHR_external_semaphore_fd", extension_count, extensions); #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_KHR_external_semaphore_win32 = glad_vk_has_extension("VK_KHR_external_semaphore_win32", extension_count, extensions); + #endif + GLAD_VK_KHR_format_feature_flags2 = glad_vk_has_extension("VK_KHR_format_feature_flags2", extension_count, extensions); + GLAD_VK_KHR_fragment_shader_barycentric = glad_vk_has_extension("VK_KHR_fragment_shader_barycentric", extension_count, extensions); + GLAD_VK_KHR_fragment_shading_rate = glad_vk_has_extension("VK_KHR_fragment_shading_rate", extension_count, extensions); GLAD_VK_KHR_get_display_properties2 = glad_vk_has_extension("VK_KHR_get_display_properties2", extension_count, extensions); GLAD_VK_KHR_get_memory_requirements2 = glad_vk_has_extension("VK_KHR_get_memory_requirements2", extension_count, extensions); GLAD_VK_KHR_get_physical_device_properties2 = glad_vk_has_extension("VK_KHR_get_physical_device_properties2", extension_count, extensions); GLAD_VK_KHR_get_surface_capabilities2 = glad_vk_has_extension("VK_KHR_get_surface_capabilities2", extension_count, extensions); + GLAD_VK_KHR_global_priority = glad_vk_has_extension("VK_KHR_global_priority", extension_count, extensions); GLAD_VK_KHR_image_format_list = glad_vk_has_extension("VK_KHR_image_format_list", extension_count, extensions); GLAD_VK_KHR_imageless_framebuffer = glad_vk_has_extension("VK_KHR_imageless_framebuffer", extension_count, extensions); GLAD_VK_KHR_incremental_present = glad_vk_has_extension("VK_KHR_incremental_present", extension_count, extensions); + GLAD_VK_KHR_index_type_uint8 = glad_vk_has_extension("VK_KHR_index_type_uint8", extension_count, extensions); + GLAD_VK_KHR_line_rasterization = glad_vk_has_extension("VK_KHR_line_rasterization", extension_count, extensions); + GLAD_VK_KHR_load_store_op_none = glad_vk_has_extension("VK_KHR_load_store_op_none", extension_count, extensions); GLAD_VK_KHR_maintenance1 = glad_vk_has_extension("VK_KHR_maintenance1", extension_count, extensions); GLAD_VK_KHR_maintenance2 = glad_vk_has_extension("VK_KHR_maintenance2", extension_count, extensions); GLAD_VK_KHR_maintenance3 = glad_vk_has_extension("VK_KHR_maintenance3", extension_count, extensions); + GLAD_VK_KHR_maintenance4 = glad_vk_has_extension("VK_KHR_maintenance4", extension_count, extensions); + GLAD_VK_KHR_maintenance5 = glad_vk_has_extension("VK_KHR_maintenance5", extension_count, extensions); + GLAD_VK_KHR_maintenance6 = glad_vk_has_extension("VK_KHR_maintenance6", extension_count, extensions); + GLAD_VK_KHR_maintenance7 = glad_vk_has_extension("VK_KHR_maintenance7", extension_count, extensions); + GLAD_VK_KHR_maintenance8 = glad_vk_has_extension("VK_KHR_maintenance8", extension_count, extensions); + GLAD_VK_KHR_map_memory2 = glad_vk_has_extension("VK_KHR_map_memory2", extension_count, extensions); GLAD_VK_KHR_multiview = glad_vk_has_extension("VK_KHR_multiview", extension_count, extensions); GLAD_VK_KHR_performance_query = glad_vk_has_extension("VK_KHR_performance_query", extension_count, extensions); + GLAD_VK_KHR_pipeline_binary = glad_vk_has_extension("VK_KHR_pipeline_binary", extension_count, extensions); GLAD_VK_KHR_pipeline_executable_properties = glad_vk_has_extension("VK_KHR_pipeline_executable_properties", extension_count, extensions); -#if defined(VK_ENABLE_BETA_EXTENSIONS) GLAD_VK_KHR_pipeline_library = glad_vk_has_extension("VK_KHR_pipeline_library", extension_count, extensions); -#endif - GLAD_VK_KHR_push_descriptor = glad_vk_has_extension("VK_KHR_push_descriptor", extension_count, extensions); + GLAD_VK_KHR_portability_enumeration = glad_vk_has_extension("VK_KHR_portability_enumeration", extension_count, extensions); #if defined(VK_ENABLE_BETA_EXTENSIONS) - GLAD_VK_KHR_ray_tracing = glad_vk_has_extension("VK_KHR_ray_tracing", extension_count, extensions); + GLAD_VK_KHR_portability_subset = glad_vk_has_extension("VK_KHR_portability_subset", extension_count, extensions); + #endif + GLAD_VK_KHR_present_id = glad_vk_has_extension("VK_KHR_present_id", extension_count, extensions); + GLAD_VK_KHR_present_wait = glad_vk_has_extension("VK_KHR_present_wait", extension_count, extensions); + GLAD_VK_KHR_push_descriptor = glad_vk_has_extension("VK_KHR_push_descriptor", extension_count, extensions); + GLAD_VK_KHR_ray_query = glad_vk_has_extension("VK_KHR_ray_query", extension_count, extensions); + GLAD_VK_KHR_ray_tracing_maintenance1 = glad_vk_has_extension("VK_KHR_ray_tracing_maintenance1", extension_count, extensions); + GLAD_VK_KHR_ray_tracing_pipeline = glad_vk_has_extension("VK_KHR_ray_tracing_pipeline", extension_count, extensions); + GLAD_VK_KHR_ray_tracing_position_fetch = glad_vk_has_extension("VK_KHR_ray_tracing_position_fetch", extension_count, extensions); GLAD_VK_KHR_relaxed_block_layout = glad_vk_has_extension("VK_KHR_relaxed_block_layout", extension_count, extensions); + GLAD_VK_KHR_robustness2 = glad_vk_has_extension("VK_KHR_robustness2", extension_count, extensions); GLAD_VK_KHR_sampler_mirror_clamp_to_edge = glad_vk_has_extension("VK_KHR_sampler_mirror_clamp_to_edge", extension_count, extensions); GLAD_VK_KHR_sampler_ycbcr_conversion = glad_vk_has_extension("VK_KHR_sampler_ycbcr_conversion", extension_count, extensions); GLAD_VK_KHR_separate_depth_stencil_layouts = glad_vk_has_extension("VK_KHR_separate_depth_stencil_layouts", extension_count, extensions); GLAD_VK_KHR_shader_atomic_int64 = glad_vk_has_extension("VK_KHR_shader_atomic_int64", extension_count, extensions); + GLAD_VK_KHR_shader_bfloat16 = glad_vk_has_extension("VK_KHR_shader_bfloat16", extension_count, extensions); GLAD_VK_KHR_shader_clock = glad_vk_has_extension("VK_KHR_shader_clock", extension_count, extensions); GLAD_VK_KHR_shader_draw_parameters = glad_vk_has_extension("VK_KHR_shader_draw_parameters", extension_count, extensions); + GLAD_VK_KHR_shader_expect_assume = glad_vk_has_extension("VK_KHR_shader_expect_assume", extension_count, extensions); GLAD_VK_KHR_shader_float16_int8 = glad_vk_has_extension("VK_KHR_shader_float16_int8", extension_count, extensions); GLAD_VK_KHR_shader_float_controls = glad_vk_has_extension("VK_KHR_shader_float_controls", extension_count, extensions); + GLAD_VK_KHR_shader_float_controls2 = glad_vk_has_extension("VK_KHR_shader_float_controls2", extension_count, extensions); + GLAD_VK_KHR_shader_integer_dot_product = glad_vk_has_extension("VK_KHR_shader_integer_dot_product", extension_count, extensions); + GLAD_VK_KHR_shader_maximal_reconvergence = glad_vk_has_extension("VK_KHR_shader_maximal_reconvergence", extension_count, extensions); GLAD_VK_KHR_shader_non_semantic_info = glad_vk_has_extension("VK_KHR_shader_non_semantic_info", extension_count, extensions); + GLAD_VK_KHR_shader_quad_control = glad_vk_has_extension("VK_KHR_shader_quad_control", extension_count, extensions); + GLAD_VK_KHR_shader_relaxed_extended_instruction = glad_vk_has_extension("VK_KHR_shader_relaxed_extended_instruction", extension_count, extensions); GLAD_VK_KHR_shader_subgroup_extended_types = glad_vk_has_extension("VK_KHR_shader_subgroup_extended_types", extension_count, extensions); + GLAD_VK_KHR_shader_subgroup_rotate = glad_vk_has_extension("VK_KHR_shader_subgroup_rotate", extension_count, extensions); + GLAD_VK_KHR_shader_subgroup_uniform_control_flow = glad_vk_has_extension("VK_KHR_shader_subgroup_uniform_control_flow", extension_count, extensions); + GLAD_VK_KHR_shader_terminate_invocation = glad_vk_has_extension("VK_KHR_shader_terminate_invocation", extension_count, extensions); GLAD_VK_KHR_shared_presentable_image = glad_vk_has_extension("VK_KHR_shared_presentable_image", extension_count, extensions); GLAD_VK_KHR_spirv_1_4 = glad_vk_has_extension("VK_KHR_spirv_1_4", extension_count, extensions); GLAD_VK_KHR_storage_buffer_storage_class = glad_vk_has_extension("VK_KHR_storage_buffer_storage_class", extension_count, extensions); @@ -1921,62 +3265,122 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { GLAD_VK_KHR_surface_protected_capabilities = glad_vk_has_extension("VK_KHR_surface_protected_capabilities", extension_count, extensions); GLAD_VK_KHR_swapchain = glad_vk_has_extension("VK_KHR_swapchain", extension_count, extensions); GLAD_VK_KHR_swapchain_mutable_format = glad_vk_has_extension("VK_KHR_swapchain_mutable_format", extension_count, extensions); + GLAD_VK_KHR_synchronization2 = glad_vk_has_extension("VK_KHR_synchronization2", extension_count, extensions); GLAD_VK_KHR_timeline_semaphore = glad_vk_has_extension("VK_KHR_timeline_semaphore", extension_count, extensions); GLAD_VK_KHR_uniform_buffer_standard_layout = glad_vk_has_extension("VK_KHR_uniform_buffer_standard_layout", extension_count, extensions); GLAD_VK_KHR_variable_pointers = glad_vk_has_extension("VK_KHR_variable_pointers", extension_count, extensions); + GLAD_VK_KHR_vertex_attribute_divisor = glad_vk_has_extension("VK_KHR_vertex_attribute_divisor", extension_count, extensions); GLAD_VK_KHR_vulkan_memory_model = glad_vk_has_extension("VK_KHR_vulkan_memory_model", extension_count, extensions); #if defined(VK_USE_PLATFORM_WAYLAND_KHR) GLAD_VK_KHR_wayland_surface = glad_vk_has_extension("VK_KHR_wayland_surface", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_KHR_win32_keyed_mutex = glad_vk_has_extension("VK_KHR_win32_keyed_mutex", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_KHR_win32_surface = glad_vk_has_extension("VK_KHR_win32_surface", extension_count, extensions); + #endif + GLAD_VK_KHR_workgroup_memory_explicit_layout = glad_vk_has_extension("VK_KHR_workgroup_memory_explicit_layout", extension_count, extensions); #if defined(VK_USE_PLATFORM_XCB_KHR) GLAD_VK_KHR_xcb_surface = glad_vk_has_extension("VK_KHR_xcb_surface", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) GLAD_VK_KHR_xlib_surface = glad_vk_has_extension("VK_KHR_xlib_surface", extension_count, extensions); + #endif + GLAD_VK_KHR_zero_initialize_workgroup_memory = glad_vk_has_extension("VK_KHR_zero_initialize_workgroup_memory", extension_count, extensions); + GLAD_VK_LUNARG_direct_driver_loading = glad_vk_has_extension("VK_LUNARG_direct_driver_loading", extension_count, extensions); + GLAD_VK_MESA_image_alignment_control = glad_vk_has_extension("VK_MESA_image_alignment_control", extension_count, extensions); + GLAD_VK_MSFT_layered_driver = glad_vk_has_extension("VK_MSFT_layered_driver", extension_count, extensions); #if defined(VK_USE_PLATFORM_IOS_MVK) GLAD_VK_MVK_ios_surface = glad_vk_has_extension("VK_MVK_ios_surface", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) GLAD_VK_MVK_macos_surface = glad_vk_has_extension("VK_MVK_macos_surface", extension_count, extensions); + #endif #if defined(VK_USE_PLATFORM_VI_NN) GLAD_VK_NN_vi_surface = glad_vk_has_extension("VK_NN_vi_surface", extension_count, extensions); + #endif + GLAD_VK_NVX_binary_import = glad_vk_has_extension("VK_NVX_binary_import", extension_count, extensions); GLAD_VK_NVX_image_view_handle = glad_vk_has_extension("VK_NVX_image_view_handle", extension_count, extensions); GLAD_VK_NVX_multiview_per_view_attributes = glad_vk_has_extension("VK_NVX_multiview_per_view_attributes", extension_count, extensions); +#if defined(VK_USE_PLATFORM_WIN32_KHR) + GLAD_VK_NV_acquire_winrt_display = glad_vk_has_extension("VK_NV_acquire_winrt_display", extension_count, extensions); + +#endif GLAD_VK_NV_clip_space_w_scaling = glad_vk_has_extension("VK_NV_clip_space_w_scaling", extension_count, extensions); + GLAD_VK_NV_cluster_acceleration_structure = glad_vk_has_extension("VK_NV_cluster_acceleration_structure", extension_count, extensions); + GLAD_VK_NV_command_buffer_inheritance = glad_vk_has_extension("VK_NV_command_buffer_inheritance", extension_count, extensions); GLAD_VK_NV_compute_shader_derivatives = glad_vk_has_extension("VK_NV_compute_shader_derivatives", extension_count, extensions); GLAD_VK_NV_cooperative_matrix = glad_vk_has_extension("VK_NV_cooperative_matrix", extension_count, extensions); + GLAD_VK_NV_cooperative_matrix2 = glad_vk_has_extension("VK_NV_cooperative_matrix2", extension_count, extensions); + GLAD_VK_NV_cooperative_vector = glad_vk_has_extension("VK_NV_cooperative_vector", extension_count, extensions); + GLAD_VK_NV_copy_memory_indirect = glad_vk_has_extension("VK_NV_copy_memory_indirect", extension_count, extensions); GLAD_VK_NV_corner_sampled_image = glad_vk_has_extension("VK_NV_corner_sampled_image", extension_count, extensions); GLAD_VK_NV_coverage_reduction_mode = glad_vk_has_extension("VK_NV_coverage_reduction_mode", extension_count, extensions); +#if defined(VK_ENABLE_BETA_EXTENSIONS) + GLAD_VK_NV_cuda_kernel_launch = glad_vk_has_extension("VK_NV_cuda_kernel_launch", extension_count, extensions); + +#endif GLAD_VK_NV_dedicated_allocation = glad_vk_has_extension("VK_NV_dedicated_allocation", extension_count, extensions); GLAD_VK_NV_dedicated_allocation_image_aliasing = glad_vk_has_extension("VK_NV_dedicated_allocation_image_aliasing", extension_count, extensions); + GLAD_VK_NV_descriptor_pool_overallocation = glad_vk_has_extension("VK_NV_descriptor_pool_overallocation", extension_count, extensions); GLAD_VK_NV_device_diagnostic_checkpoints = glad_vk_has_extension("VK_NV_device_diagnostic_checkpoints", extension_count, extensions); GLAD_VK_NV_device_diagnostics_config = glad_vk_has_extension("VK_NV_device_diagnostics_config", extension_count, extensions); GLAD_VK_NV_device_generated_commands = glad_vk_has_extension("VK_NV_device_generated_commands", extension_count, extensions); + GLAD_VK_NV_device_generated_commands_compute = glad_vk_has_extension("VK_NV_device_generated_commands_compute", extension_count, extensions); +#if defined(VK_ENABLE_BETA_EXTENSIONS) + GLAD_VK_NV_displacement_micromap = glad_vk_has_extension("VK_NV_displacement_micromap", extension_count, extensions); + +#endif + GLAD_VK_NV_display_stereo = glad_vk_has_extension("VK_NV_display_stereo", extension_count, extensions); + GLAD_VK_NV_extended_sparse_address_space = glad_vk_has_extension("VK_NV_extended_sparse_address_space", extension_count, extensions); + GLAD_VK_NV_external_compute_queue = glad_vk_has_extension("VK_NV_external_compute_queue", extension_count, extensions); GLAD_VK_NV_external_memory = glad_vk_has_extension("VK_NV_external_memory", extension_count, extensions); GLAD_VK_NV_external_memory_capabilities = glad_vk_has_extension("VK_NV_external_memory_capabilities", extension_count, extensions); + GLAD_VK_NV_external_memory_rdma = glad_vk_has_extension("VK_NV_external_memory_rdma", extension_count, extensions); #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_NV_external_memory_win32 = glad_vk_has_extension("VK_NV_external_memory_win32", extension_count, extensions); + #endif GLAD_VK_NV_fill_rectangle = glad_vk_has_extension("VK_NV_fill_rectangle", extension_count, extensions); GLAD_VK_NV_fragment_coverage_to_color = glad_vk_has_extension("VK_NV_fragment_coverage_to_color", extension_count, extensions); GLAD_VK_NV_fragment_shader_barycentric = glad_vk_has_extension("VK_NV_fragment_shader_barycentric", extension_count, extensions); + GLAD_VK_NV_fragment_shading_rate_enums = glad_vk_has_extension("VK_NV_fragment_shading_rate_enums", extension_count, extensions); GLAD_VK_NV_framebuffer_mixed_samples = glad_vk_has_extension("VK_NV_framebuffer_mixed_samples", extension_count, extensions); GLAD_VK_NV_geometry_shader_passthrough = glad_vk_has_extension("VK_NV_geometry_shader_passthrough", extension_count, extensions); GLAD_VK_NV_glsl_shader = glad_vk_has_extension("VK_NV_glsl_shader", extension_count, extensions); + GLAD_VK_NV_inherited_viewport_scissor = glad_vk_has_extension("VK_NV_inherited_viewport_scissor", extension_count, extensions); + GLAD_VK_NV_linear_color_attachment = glad_vk_has_extension("VK_NV_linear_color_attachment", extension_count, extensions); + GLAD_VK_NV_low_latency = glad_vk_has_extension("VK_NV_low_latency", extension_count, extensions); + GLAD_VK_NV_low_latency2 = glad_vk_has_extension("VK_NV_low_latency2", extension_count, extensions); + GLAD_VK_NV_memory_decompression = glad_vk_has_extension("VK_NV_memory_decompression", extension_count, extensions); GLAD_VK_NV_mesh_shader = glad_vk_has_extension("VK_NV_mesh_shader", extension_count, extensions); + GLAD_VK_NV_optical_flow = glad_vk_has_extension("VK_NV_optical_flow", extension_count, extensions); + GLAD_VK_NV_partitioned_acceleration_structure = glad_vk_has_extension("VK_NV_partitioned_acceleration_structure", extension_count, extensions); + GLAD_VK_NV_per_stage_descriptor_set = glad_vk_has_extension("VK_NV_per_stage_descriptor_set", extension_count, extensions); + GLAD_VK_NV_present_barrier = glad_vk_has_extension("VK_NV_present_barrier", extension_count, extensions); +#if defined(VK_ENABLE_BETA_EXTENSIONS) + GLAD_VK_NV_present_metering = glad_vk_has_extension("VK_NV_present_metering", extension_count, extensions); + +#endif + GLAD_VK_NV_raw_access_chains = glad_vk_has_extension("VK_NV_raw_access_chains", extension_count, extensions); GLAD_VK_NV_ray_tracing = glad_vk_has_extension("VK_NV_ray_tracing", extension_count, extensions); + GLAD_VK_NV_ray_tracing_invocation_reorder = glad_vk_has_extension("VK_NV_ray_tracing_invocation_reorder", extension_count, extensions); + GLAD_VK_NV_ray_tracing_linear_swept_spheres = glad_vk_has_extension("VK_NV_ray_tracing_linear_swept_spheres", extension_count, extensions); + GLAD_VK_NV_ray_tracing_motion_blur = glad_vk_has_extension("VK_NV_ray_tracing_motion_blur", extension_count, extensions); + GLAD_VK_NV_ray_tracing_validation = glad_vk_has_extension("VK_NV_ray_tracing_validation", extension_count, extensions); GLAD_VK_NV_representative_fragment_test = glad_vk_has_extension("VK_NV_representative_fragment_test", extension_count, extensions); GLAD_VK_NV_sample_mask_override_coverage = glad_vk_has_extension("VK_NV_sample_mask_override_coverage", extension_count, extensions); GLAD_VK_NV_scissor_exclusive = glad_vk_has_extension("VK_NV_scissor_exclusive", extension_count, extensions); + GLAD_VK_NV_shader_atomic_float16_vector = glad_vk_has_extension("VK_NV_shader_atomic_float16_vector", extension_count, extensions); GLAD_VK_NV_shader_image_footprint = glad_vk_has_extension("VK_NV_shader_image_footprint", extension_count, extensions); GLAD_VK_NV_shader_sm_builtins = glad_vk_has_extension("VK_NV_shader_sm_builtins", extension_count, extensions); GLAD_VK_NV_shader_subgroup_partitioned = glad_vk_has_extension("VK_NV_shader_subgroup_partitioned", extension_count, extensions); @@ -1985,10 +3389,36 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { GLAD_VK_NV_viewport_swizzle = glad_vk_has_extension("VK_NV_viewport_swizzle", extension_count, extensions); #if defined(VK_USE_PLATFORM_WIN32_KHR) GLAD_VK_NV_win32_keyed_mutex = glad_vk_has_extension("VK_NV_win32_keyed_mutex", extension_count, extensions); + #endif + GLAD_VK_QCOM_filter_cubic_clamp = glad_vk_has_extension("VK_QCOM_filter_cubic_clamp", extension_count, extensions); + GLAD_VK_QCOM_filter_cubic_weights = glad_vk_has_extension("VK_QCOM_filter_cubic_weights", extension_count, extensions); + GLAD_VK_QCOM_fragment_density_map_offset = glad_vk_has_extension("VK_QCOM_fragment_density_map_offset", extension_count, extensions); + GLAD_VK_QCOM_image_processing = glad_vk_has_extension("VK_QCOM_image_processing", extension_count, extensions); + GLAD_VK_QCOM_image_processing2 = glad_vk_has_extension("VK_QCOM_image_processing2", extension_count, extensions); + GLAD_VK_QCOM_multiview_per_view_render_areas = glad_vk_has_extension("VK_QCOM_multiview_per_view_render_areas", extension_count, extensions); + GLAD_VK_QCOM_multiview_per_view_viewports = glad_vk_has_extension("VK_QCOM_multiview_per_view_viewports", extension_count, extensions); GLAD_VK_QCOM_render_pass_shader_resolve = glad_vk_has_extension("VK_QCOM_render_pass_shader_resolve", extension_count, extensions); GLAD_VK_QCOM_render_pass_store_ops = glad_vk_has_extension("VK_QCOM_render_pass_store_ops", extension_count, extensions); GLAD_VK_QCOM_render_pass_transform = glad_vk_has_extension("VK_QCOM_render_pass_transform", extension_count, extensions); + GLAD_VK_QCOM_rotated_copy_commands = glad_vk_has_extension("VK_QCOM_rotated_copy_commands", extension_count, extensions); + GLAD_VK_QCOM_tile_memory_heap = glad_vk_has_extension("VK_QCOM_tile_memory_heap", extension_count, extensions); + GLAD_VK_QCOM_tile_properties = glad_vk_has_extension("VK_QCOM_tile_properties", extension_count, extensions); + GLAD_VK_QCOM_tile_shading = glad_vk_has_extension("VK_QCOM_tile_shading", extension_count, extensions); + GLAD_VK_QCOM_ycbcr_degamma = glad_vk_has_extension("VK_QCOM_ycbcr_degamma", extension_count, extensions); +#if defined(VK_USE_PLATFORM_SCREEN_QNX) + GLAD_VK_QNX_external_memory_screen_buffer = glad_vk_has_extension("VK_QNX_external_memory_screen_buffer", extension_count, extensions); + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) + GLAD_VK_QNX_screen_surface = glad_vk_has_extension("VK_QNX_screen_surface", extension_count, extensions); + +#endif + GLAD_VK_SEC_amigo_profiling = glad_vk_has_extension("VK_SEC_amigo_profiling", extension_count, extensions); + GLAD_VK_VALVE_descriptor_set_host_mapping = glad_vk_has_extension("VK_VALVE_descriptor_set_host_mapping", extension_count, extensions); + GLAD_VK_VALVE_mutable_descriptor_type = glad_vk_has_extension("VK_VALVE_mutable_descriptor_type", extension_count, extensions); + + GLAD_UNUSED(&glad_vk_has_extension); glad_vk_free_extensions(extension_count, extensions); @@ -2023,6 +3453,8 @@ static int glad_vk_find_core_vulkan( VkPhysicalDevice physical_device) { GLAD_VK_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; GLAD_VK_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; GLAD_VK_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GLAD_VK_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GLAD_VK_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; return GLAD_MAKE_VERSION(major, minor); } @@ -2041,139 +3473,255 @@ int gladLoadVulkanUserPtr( VkPhysicalDevice physical_device, GLADuserptrloadfunc glad_vk_load_VK_VERSION_1_0(load, userptr); glad_vk_load_VK_VERSION_1_1(load, userptr); glad_vk_load_VK_VERSION_1_2(load, userptr); + glad_vk_load_VK_VERSION_1_3(load, userptr); + glad_vk_load_VK_VERSION_1_4(load, userptr); if (!glad_vk_find_extensions_vulkan( physical_device)) return 0; +#if defined(VK_ENABLE_BETA_EXTENSIONS) + glad_vk_load_VK_AMDX_shader_enqueue(load, userptr); + +#endif + glad_vk_load_VK_AMD_anti_lag(load, userptr); glad_vk_load_VK_AMD_buffer_marker(load, userptr); glad_vk_load_VK_AMD_display_native_hdr(load, userptr); glad_vk_load_VK_AMD_draw_indirect_count(load, userptr); glad_vk_load_VK_AMD_shader_info(load, userptr); #if defined(VK_USE_PLATFORM_ANDROID_KHR) glad_vk_load_VK_ANDROID_external_memory_android_hardware_buffer(load, userptr); + #endif + glad_vk_load_VK_EXT_acquire_drm_display(load, userptr); #if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) glad_vk_load_VK_EXT_acquire_xlib_display(load, userptr); + #endif + glad_vk_load_VK_EXT_attachment_feedback_loop_dynamic_state(load, userptr); glad_vk_load_VK_EXT_buffer_device_address(load, userptr); glad_vk_load_VK_EXT_calibrated_timestamps(load, userptr); + glad_vk_load_VK_EXT_color_write_enable(load, userptr); glad_vk_load_VK_EXT_conditional_rendering(load, userptr); glad_vk_load_VK_EXT_debug_marker(load, userptr); glad_vk_load_VK_EXT_debug_report(load, userptr); glad_vk_load_VK_EXT_debug_utils(load, userptr); + glad_vk_load_VK_EXT_depth_bias_control(load, userptr); + glad_vk_load_VK_EXT_depth_clamp_control(load, userptr); + glad_vk_load_VK_EXT_descriptor_buffer(load, userptr); + glad_vk_load_VK_EXT_device_fault(load, userptr); + glad_vk_load_VK_EXT_device_generated_commands(load, userptr); glad_vk_load_VK_EXT_direct_mode_display(load, userptr); #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) glad_vk_load_VK_EXT_directfb_surface(load, userptr); + #endif glad_vk_load_VK_EXT_discard_rectangles(load, userptr); glad_vk_load_VK_EXT_display_control(load, userptr); glad_vk_load_VK_EXT_display_surface_counter(load, userptr); glad_vk_load_VK_EXT_extended_dynamic_state(load, userptr); + glad_vk_load_VK_EXT_extended_dynamic_state2(load, userptr); + glad_vk_load_VK_EXT_extended_dynamic_state3(load, userptr); glad_vk_load_VK_EXT_external_memory_host(load, userptr); +#if defined(VK_USE_PLATFORM_METAL_EXT) + glad_vk_load_VK_EXT_external_memory_metal(load, userptr); + +#endif + glad_vk_load_VK_EXT_fragment_density_map_offset(load, userptr); #if defined(VK_USE_PLATFORM_WIN32_KHR) glad_vk_load_VK_EXT_full_screen_exclusive(load, userptr); + #endif glad_vk_load_VK_EXT_hdr_metadata(load, userptr); glad_vk_load_VK_EXT_headless_surface(load, userptr); + glad_vk_load_VK_EXT_host_image_copy(load, userptr); glad_vk_load_VK_EXT_host_query_reset(load, userptr); + glad_vk_load_VK_EXT_image_compression_control(load, userptr); glad_vk_load_VK_EXT_image_drm_format_modifier(load, userptr); glad_vk_load_VK_EXT_line_rasterization(load, userptr); + glad_vk_load_VK_EXT_mesh_shader(load, userptr); +#if defined(VK_USE_PLATFORM_METAL_EXT) + glad_vk_load_VK_EXT_metal_objects(load, userptr); + +#endif #if defined(VK_USE_PLATFORM_METAL_EXT) glad_vk_load_VK_EXT_metal_surface(load, userptr); + #endif + glad_vk_load_VK_EXT_multi_draw(load, userptr); + glad_vk_load_VK_EXT_opacity_micromap(load, userptr); + glad_vk_load_VK_EXT_pageable_device_local_memory(load, userptr); + glad_vk_load_VK_EXT_pipeline_properties(load, userptr); glad_vk_load_VK_EXT_private_data(load, userptr); glad_vk_load_VK_EXT_sample_locations(load, userptr); + glad_vk_load_VK_EXT_shader_module_identifier(load, userptr); + glad_vk_load_VK_EXT_shader_object(load, userptr); + glad_vk_load_VK_EXT_swapchain_maintenance1(load, userptr); glad_vk_load_VK_EXT_tooling_info(load, userptr); glad_vk_load_VK_EXT_transform_feedback(load, userptr); glad_vk_load_VK_EXT_validation_cache(load, userptr); + glad_vk_load_VK_EXT_vertex_input_dynamic_state(load, userptr); +#if defined(VK_USE_PLATFORM_FUCHSIA) + glad_vk_load_VK_FUCHSIA_buffer_collection(load, userptr); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) + glad_vk_load_VK_FUCHSIA_external_memory(load, userptr); + +#endif +#if defined(VK_USE_PLATFORM_FUCHSIA) + glad_vk_load_VK_FUCHSIA_external_semaphore(load, userptr); + +#endif #if defined(VK_USE_PLATFORM_FUCHSIA) glad_vk_load_VK_FUCHSIA_imagepipe_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_GGP) glad_vk_load_VK_GGP_stream_descriptor_surface(load, userptr); + #endif glad_vk_load_VK_GOOGLE_display_timing(load, userptr); + glad_vk_load_VK_HUAWEI_cluster_culling_shader(load, userptr); + glad_vk_load_VK_HUAWEI_invocation_mask(load, userptr); + glad_vk_load_VK_HUAWEI_subpass_shading(load, userptr); glad_vk_load_VK_INTEL_performance_query(load, userptr); + glad_vk_load_VK_KHR_acceleration_structure(load, userptr); #if defined(VK_USE_PLATFORM_ANDROID_KHR) glad_vk_load_VK_KHR_android_surface(load, userptr); + #endif glad_vk_load_VK_KHR_bind_memory2(load, userptr); glad_vk_load_VK_KHR_buffer_device_address(load, userptr); + glad_vk_load_VK_KHR_calibrated_timestamps(load, userptr); + glad_vk_load_VK_KHR_cooperative_matrix(load, userptr); + glad_vk_load_VK_KHR_copy_commands2(load, userptr); glad_vk_load_VK_KHR_create_renderpass2(load, userptr); -#if defined(VK_ENABLE_BETA_EXTENSIONS) glad_vk_load_VK_KHR_deferred_host_operations(load, userptr); -#endif glad_vk_load_VK_KHR_descriptor_update_template(load, userptr); glad_vk_load_VK_KHR_device_group(load, userptr); glad_vk_load_VK_KHR_device_group_creation(load, userptr); glad_vk_load_VK_KHR_display(load, userptr); glad_vk_load_VK_KHR_display_swapchain(load, userptr); glad_vk_load_VK_KHR_draw_indirect_count(load, userptr); + glad_vk_load_VK_KHR_dynamic_rendering(load, userptr); + glad_vk_load_VK_KHR_dynamic_rendering_local_read(load, userptr); glad_vk_load_VK_KHR_external_fence_capabilities(load, userptr); glad_vk_load_VK_KHR_external_fence_fd(load, userptr); #if defined(VK_USE_PLATFORM_WIN32_KHR) glad_vk_load_VK_KHR_external_fence_win32(load, userptr); + #endif glad_vk_load_VK_KHR_external_memory_capabilities(load, userptr); glad_vk_load_VK_KHR_external_memory_fd(load, userptr); #if defined(VK_USE_PLATFORM_WIN32_KHR) glad_vk_load_VK_KHR_external_memory_win32(load, userptr); + #endif glad_vk_load_VK_KHR_external_semaphore_capabilities(load, userptr); glad_vk_load_VK_KHR_external_semaphore_fd(load, userptr); #if defined(VK_USE_PLATFORM_WIN32_KHR) glad_vk_load_VK_KHR_external_semaphore_win32(load, userptr); + #endif + glad_vk_load_VK_KHR_fragment_shading_rate(load, userptr); glad_vk_load_VK_KHR_get_display_properties2(load, userptr); glad_vk_load_VK_KHR_get_memory_requirements2(load, userptr); glad_vk_load_VK_KHR_get_physical_device_properties2(load, userptr); glad_vk_load_VK_KHR_get_surface_capabilities2(load, userptr); + glad_vk_load_VK_KHR_line_rasterization(load, userptr); glad_vk_load_VK_KHR_maintenance1(load, userptr); glad_vk_load_VK_KHR_maintenance3(load, userptr); + glad_vk_load_VK_KHR_maintenance4(load, userptr); + glad_vk_load_VK_KHR_maintenance5(load, userptr); + glad_vk_load_VK_KHR_maintenance6(load, userptr); + glad_vk_load_VK_KHR_map_memory2(load, userptr); glad_vk_load_VK_KHR_performance_query(load, userptr); + glad_vk_load_VK_KHR_pipeline_binary(load, userptr); glad_vk_load_VK_KHR_pipeline_executable_properties(load, userptr); + glad_vk_load_VK_KHR_present_wait(load, userptr); glad_vk_load_VK_KHR_push_descriptor(load, userptr); -#if defined(VK_ENABLE_BETA_EXTENSIONS) - glad_vk_load_VK_KHR_ray_tracing(load, userptr); -#endif + glad_vk_load_VK_KHR_ray_tracing_maintenance1(load, userptr); + glad_vk_load_VK_KHR_ray_tracing_pipeline(load, userptr); glad_vk_load_VK_KHR_sampler_ycbcr_conversion(load, userptr); glad_vk_load_VK_KHR_shared_presentable_image(load, userptr); glad_vk_load_VK_KHR_surface(load, userptr); glad_vk_load_VK_KHR_swapchain(load, userptr); + glad_vk_load_VK_KHR_synchronization2(load, userptr); glad_vk_load_VK_KHR_timeline_semaphore(load, userptr); #if defined(VK_USE_PLATFORM_WAYLAND_KHR) glad_vk_load_VK_KHR_wayland_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_WIN32_KHR) glad_vk_load_VK_KHR_win32_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_XCB_KHR) glad_vk_load_VK_KHR_xcb_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) glad_vk_load_VK_KHR_xlib_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_IOS_MVK) glad_vk_load_VK_MVK_ios_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_MACOS_MVK) glad_vk_load_VK_MVK_macos_surface(load, userptr); + #endif #if defined(VK_USE_PLATFORM_VI_NN) glad_vk_load_VK_NN_vi_surface(load, userptr); + #endif + glad_vk_load_VK_NVX_binary_import(load, userptr); glad_vk_load_VK_NVX_image_view_handle(load, userptr); +#if defined(VK_USE_PLATFORM_WIN32_KHR) + glad_vk_load_VK_NV_acquire_winrt_display(load, userptr); + +#endif glad_vk_load_VK_NV_clip_space_w_scaling(load, userptr); + glad_vk_load_VK_NV_cluster_acceleration_structure(load, userptr); glad_vk_load_VK_NV_cooperative_matrix(load, userptr); + glad_vk_load_VK_NV_cooperative_matrix2(load, userptr); + glad_vk_load_VK_NV_cooperative_vector(load, userptr); + glad_vk_load_VK_NV_copy_memory_indirect(load, userptr); glad_vk_load_VK_NV_coverage_reduction_mode(load, userptr); +#if defined(VK_ENABLE_BETA_EXTENSIONS) + glad_vk_load_VK_NV_cuda_kernel_launch(load, userptr); + +#endif glad_vk_load_VK_NV_device_diagnostic_checkpoints(load, userptr); glad_vk_load_VK_NV_device_generated_commands(load, userptr); + glad_vk_load_VK_NV_device_generated_commands_compute(load, userptr); + glad_vk_load_VK_NV_external_compute_queue(load, userptr); glad_vk_load_VK_NV_external_memory_capabilities(load, userptr); + glad_vk_load_VK_NV_external_memory_rdma(load, userptr); #if defined(VK_USE_PLATFORM_WIN32_KHR) glad_vk_load_VK_NV_external_memory_win32(load, userptr); + #endif + glad_vk_load_VK_NV_fragment_shading_rate_enums(load, userptr); + glad_vk_load_VK_NV_low_latency2(load, userptr); + glad_vk_load_VK_NV_memory_decompression(load, userptr); glad_vk_load_VK_NV_mesh_shader(load, userptr); + glad_vk_load_VK_NV_optical_flow(load, userptr); + glad_vk_load_VK_NV_partitioned_acceleration_structure(load, userptr); glad_vk_load_VK_NV_ray_tracing(load, userptr); glad_vk_load_VK_NV_scissor_exclusive(load, userptr); glad_vk_load_VK_NV_shading_rate_image(load, userptr); + glad_vk_load_VK_QCOM_tile_memory_heap(load, userptr); + glad_vk_load_VK_QCOM_tile_properties(load, userptr); + glad_vk_load_VK_QCOM_tile_shading(load, userptr); +#if defined(VK_USE_PLATFORM_SCREEN_QNX) + glad_vk_load_VK_QNX_external_memory_screen_buffer(load, userptr); + +#endif +#if defined(VK_USE_PLATFORM_SCREEN_QNX) + glad_vk_load_VK_QNX_screen_surface(load, userptr); + +#endif + glad_vk_load_VK_VALVE_descriptor_set_host_mapping(load, userptr); return version; diff --git a/lib/irrlicht/source/Irrlicht/MoltenVK.mm b/lib/irrlicht/source/Irrlicht/MoltenVK.mm index b8aa130cc8b..9bbb8b19039 100644 --- a/lib/irrlicht/source/Irrlicht/MoltenVK.mm +++ b/lib/irrlicht/source/Irrlicht/MoltenVK.mm @@ -6,8 +6,6 @@ #import #ifdef DLOPEN_MOLTENVK -PFN_vkGetMoltenVKConfigurationMVK vkGetMoltenVKConfigurationMVK = NULL; -PFN_vkSetMoltenVKConfigurationMVK vkSetMoltenVKConfigurationMVK = NULL; PFN_vkGetPhysicalDeviceMetalFeaturesMVK vkGetPhysicalDeviceMetalFeaturesMVK = NULL; namespace irr @@ -39,15 +37,9 @@ SDL_Vulkan_UnloadLibrary(); return; } - vkGetMoltenVKConfigurationMVK = (PFN_vkGetMoltenVKConfigurationMVK) - dlsym(m_handle, "vkGetMoltenVKConfigurationMVK"); - vkSetMoltenVKConfigurationMVK = (PFN_vkSetMoltenVKConfigurationMVK) - dlsym(m_handle, "vkSetMoltenVKConfigurationMVK"); vkGetPhysicalDeviceMetalFeaturesMVK = (PFN_vkGetPhysicalDeviceMetalFeaturesMVK) dlsym(m_handle, "vkGetPhysicalDeviceMetalFeaturesMVK"); - if (!vkGetMoltenVKConfigurationMVK || - !vkSetMoltenVKConfigurationMVK || - !vkGetPhysicalDeviceMetalFeaturesMVK) + if (!vkGetPhysicalDeviceMetalFeaturesMVK) { SDL_Vulkan_UnloadLibrary(); return; From 5b301c1820fd6609efa7b930b1f4a769e6253eac Mon Sep 17 00:00:00 2001 From: Deve Date: Wed, 7 May 2025 23:28:04 +0200 Subject: [PATCH 711/830] Add spot lights rendering for opengl --- data/shaders/pointlight.frag | 16 +++++++++ data/shaders/pointlight.vert | 3 ++ data/shaders/pointlightscatter.frag | 27 ++++++++++++++-- src/graphics/light.cpp | 1 + src/graphics/light.hpp | 9 ++++++ src/graphics/lighting_passes.cpp | 35 ++++++++++++++++++++ src/graphics/sp/sp_mesh_buffer.hpp | 7 +++- src/karts/kart_model.cpp | 50 ++++++++++++++++++++++++++--- src/karts/kart_model.hpp | 3 ++ 9 files changed, 144 insertions(+), 7 deletions(-) diff --git a/data/shaders/pointlight.frag b/data/shaders/pointlight.frag index cef44536ad3..834dcaa6f06 100644 --- a/data/shaders/pointlight.frag +++ b/data/shaders/pointlight.frag @@ -9,6 +9,7 @@ flat in vec3 center; flat in float energy; flat in vec3 col; flat in float radius; +flat in vec4 direction_scale_offset; #ifdef GL_ES layout (location = 0) out vec4 Diff; @@ -42,6 +43,21 @@ void main() att *= (radius - d) / radius; if (att <= 0.) discard; + // Spotlight + float sscale = direction_scale_offset.z; + if (sscale != 0.) + { + vec3 sdir = vec3(direction_scale_offset.xy, 0.); + sdir.z = sqrt(1. - dot(sdir, sdir)) * sign(sscale); + sdir = (u_view_matrix * vec4(sdir, 0.0)).xyz; + vec3 light_to_frag = light_pos - xpos.xyz; + float offset = direction_scale_offset.w; + float sattenuation = clamp(dot(-sdir, normalize(light_to_frag)) * + abs(sscale) + offset, 0.0, 1.0); + att *= sattenuation * sattenuation; + } + if (att <= 0.) discard; + // Light Direction vec3 L = (light_pos - xpos.xyz) / d; diff --git a/data/shaders/pointlight.vert b/data/shaders/pointlight.vert index c324eb1f7d3..9f1f61f01e1 100644 --- a/data/shaders/pointlight.vert +++ b/data/shaders/pointlight.vert @@ -2,11 +2,13 @@ in vec3 Position; in float Energy; in vec3 Color; in float Radius; +in vec4 Direction_scale_offset; flat out vec3 center; flat out float energy; flat out vec3 col; flat out float radius; +flat out vec4 direction_scale_offset; const float zNear = 1.; @@ -105,4 +107,5 @@ void main(void) center = Position; energy = Energy; radius = Radius; + direction_scale_offset = Direction_scale_offset; } diff --git a/data/shaders/pointlightscatter.frag b/data/shaders/pointlightscatter.frag index 631067ad623..0d66b539dfb 100644 --- a/data/shaders/pointlightscatter.frag +++ b/data/shaders/pointlightscatter.frag @@ -6,6 +6,7 @@ flat in vec3 center; flat in float energy; flat in vec3 col; flat in float radius; +flat in vec4 direction_scale_offset; out vec4 Fog; @@ -34,11 +35,33 @@ void main() vec3 fog_factor = light_col * density * stepsize * energy * 20.; vec3 xpos_step = eyedir * stepsize; + // Spotlight direction calculation + float sscale = direction_scale_offset.z; + vec3 sdir; + if (sscale != 0.) + { + sdir = vec3(direction_scale_offset.xy, 0.); + sdir.z = sqrt(1. - dot(sdir, sdir)) * sign(sscale); + sdir = (u_view_matrix * vec4(sdir, 0.0)).xyz; + } + for (int i = 0; i < 16; i++) { - float d = distance(light_pos, xpos); + vec3 light_to_pos = light_pos - xpos; + float d = length(light_to_pos); float l = (16. - float(i)) * stepsize; - fog += fog_factor / (1. + d * d) * max((radius - d) / radius, 0.) * exp(- density * d) * exp(- density * l); + vec3 base_att = fog_factor / (1. + d * d) * max((radius - d) / radius, 0.) * exp(- density * d) * exp(- density * l); + + // Apply spotlight attenuation + if (sscale != 0.) + { + float offset = direction_scale_offset.w; + float sattenuation = clamp(dot(-sdir, normalize(light_to_pos)) * + abs(sscale) + offset, 0.0, 1.0); + base_att *= sattenuation * sattenuation; + } + + fog += base_att; xpos += xpos_step; } diff --git a/src/graphics/light.cpp b/src/graphics/light.cpp index bd81fc87cfb..73a8abf330b 100644 --- a/src/graphics/light.cpp +++ b/src/graphics/light.cpp @@ -31,6 +31,7 @@ LightNode::LightNode(scene::ISceneManager* mgr, scene::ISceneNode* parent, float m_color[0] = r; m_color[1] = g; m_color[2] = b; + m_spotlight = {}; #ifdef __LIGHT_NODE_VISUALISATION__ m_viz_added = false; diff --git a/src/graphics/light.hpp b/src/graphics/light.hpp index c27cdff5708..ce6023ea497 100644 --- a/src/graphics/light.hpp +++ b/src/graphics/light.hpp @@ -21,6 +21,7 @@ #include #include +#include #include using namespace irr; @@ -30,11 +31,18 @@ namespace irr namespace scene { class IMesh; } } +struct Spotlight +{ + irr::f32 m_outer_cone; + irr::f32 m_inner_cone; +}; + //#define __LIGHT_NODE_VISUALISATION__ // The actual node class LightNode: public scene::ISceneNode { + Spotlight m_spotlight; #ifdef __LIGHT_NODE_VISUALISATION__ bool m_viz_added; #endif @@ -67,6 +75,7 @@ class LightNode: public scene::ISceneNode // For the debug menu void setEnergy(float energy) { m_energy = energy; } void setRadius(float radius) { m_radius = radius; } + Spotlight& getSpotlightData() { return m_spotlight; } protected: static core::aabbox3df box; diff --git a/src/graphics/lighting_passes.cpp b/src/graphics/lighting_passes.cpp index 6f0b507d11d..ea82e35969c 100644 --- a/src/graphics/lighting_passes.cpp +++ b/src/graphics/lighting_passes.cpp @@ -33,6 +33,7 @@ #include "utils/profiler.hpp" #include +#include class LightBaseClass { @@ -47,6 +48,10 @@ class LightBaseClass float green; float blue; float radius; + float direction_x; + float direction_y; + float scale; + float offset; }; public: static const unsigned int MAXLIGHT = 32; @@ -86,6 +91,7 @@ class PointLightShader : public TextureShader < PointLightShader, 2 > GLuint attrib_Color = glGetAttribLocation(m_program, "Color"); GLuint attrib_Energy = glGetAttribLocation(m_program, "Energy"); GLuint attrib_Radius = glGetAttribLocation(m_program, "Radius"); + GLuint attrib_DSO = glGetAttribLocation(m_program, "Direction_scale_offset"); glEnableVertexAttribArray(attrib_Position); glVertexAttribPointer(attrib_Position, 3, GL_FLOAT, GL_FALSE, @@ -102,11 +108,16 @@ class PointLightShader : public TextureShader < PointLightShader, 2 > glVertexAttribPointer(attrib_Radius, 1, GL_FLOAT, GL_FALSE, sizeof(LightBaseClass::PointLightInfo), (GLvoid*)(7 * sizeof(float))); + glEnableVertexAttribArray(attrib_DSO); + glVertexAttribPointer(attrib_DSO, 4, GL_FLOAT, GL_FALSE, + sizeof(LightBaseClass::PointLightInfo), + (GLvoid*)(8 * sizeof(float))); glVertexAttribDivisor(attrib_Position, 1); glVertexAttribDivisor(attrib_Energy, 1); glVertexAttribDivisor(attrib_Color, 1); glVertexAttribDivisor(attrib_Radius, 1); + glVertexAttribDivisor(attrib_DSO, 1); } // PointLightShader ~PointLightShader() { @@ -141,6 +152,7 @@ class PointLightScatterShader : public TextureShadergetRadius(); + float ic = light_node->getSpotlightData().m_inner_cone; + float oc = light_node->getSpotlightData().m_outer_cone; + if (ic != 0.0f && oc != 0.0f) + { + core::vector3df dir(0.0f, 0.0f, 1.0f); + light_node->getAbsoluteTransformation().rotateVect(dir); + dir.normalize(); + m_point_lights_info[m_point_light_count].direction_x = dir.X; + m_point_lights_info[m_point_light_count].direction_y = dir.Y; + float cos_outer = cosf(oc); + m_point_lights_info[m_point_light_count].scale = 1.0f / std::max(cosf(ic) - cos_outer, 1e-4f); + m_point_lights_info[m_point_light_count].offset = -cos_outer * m_point_lights_info[m_point_light_count].scale; + m_point_lights_info[m_point_light_count].scale *= dir.Z > 0.f ? 1.f : -1.f; + } + else + { + m_point_lights_info[m_point_light_count].scale = 0.0f; + } } } if (m_point_light_count > LightBaseClass::MAXLIGHT) diff --git a/src/graphics/sp/sp_mesh_buffer.hpp b/src/graphics/sp/sp_mesh_buffer.hpp index e0ae65d116e..3fb98c9c561 100644 --- a/src/graphics/sp/sp_mesh_buffer.hpp +++ b/src/graphics/sp/sp_mesh_buffer.hpp @@ -124,8 +124,11 @@ class SPMeshBuffer : public IMeshBuffer, public SPPerObjectUniform } else { + unsigned idx_count = std::get<1>(m_stk_material[material_id]); + if (idx_count == 0) + return; glDrawElementsInstanced(GL_TRIANGLES, - std::get<1>(m_stk_material[material_id]), + idx_count, GL_UNSIGNED_SHORT, (void*)(std::get<0>(m_stk_material[material_id]) << 1), (unsigned)m_ins_dat[dct].size()); @@ -436,6 +439,8 @@ class SPMeshBuffer : public IMeshBuffer, public SPPerObjectUniform virtual u32 getChangedID_Vertex() const { return 0; } // ------------------------------------------------------------------------ virtual u32 getChangedID_Index() const { return 0; } + // ------------------------------------------------------------------------ + void disableForMaterial(u32 idx) { std::get<1>(m_stk_material[idx]) = 0; } }; diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index bc605630b87..0083c924011 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -28,6 +28,7 @@ #include "graphics/b3d_mesh_loader.hpp" #include "graphics/irr_driver.hpp" #include "graphics/lod_node.hpp" +#include "graphics/light.hpp" #include "graphics/material.hpp" #include "graphics/material_manager.hpp" #include "graphics/mesh_tools.hpp" @@ -581,7 +582,7 @@ void HeadlightObject::setLight(scene::ISceneNode* parent, float energy, float radius) { bool is_vk = irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN; - if (is_vk && m_spotlight == 1) + if (m_spotlight == 1) energy *= 2.0f; m_node = irr_driver->addLight(core::vector3df(0.0f, 0.0f, 0.0f), energy, radius, m_headlight_color.getRed() / 255.f, @@ -595,6 +596,13 @@ void HeadlightObject::setLight(scene::ISceneNode* parent, data.InnerCone = 30.0f / 180.0f * M_PI; data.OuterCone = 45.0f / 180.0f * M_PI; } + else if (m_spotlight == 1) + { + LightNode* ln = static_cast(m_node); + Spotlight& sl = ln->getSpotlightData(); + sl.m_inner_cone = 30.0f / 180.0f * M_PI; + sl.m_outer_cone = 45.0f / 180.0f * M_PI; + } m_node->grab(); } // setLight @@ -733,12 +741,24 @@ bool KartModel::loadModels(const KartProperties &kart_properties) #ifndef SERVER_ONLY bool spotlight = spotlight_meshes.find(mesh) != spotlight_meshes.end(); GE::GESPM* spm = dynamic_cast(mesh); + SP::SPMesh* spspm = dynamic_cast(mesh); if (obj.getSpotlight() == -1) { - if (!spotlight && spm && handleSpotlight(spm)) + if (spm) { - spotlight_meshes.insert(spm); - spotlight = true; + if (!spotlight && handleSpotlight(spm)) + { + spotlight_meshes.insert(spm); + spotlight = true; + } + } + else if (spspm) + { + if (!spotlight && handleSPSpotlight(spspm)) + { + spotlight_meshes.insert(spspm); + spotlight = true; + } } obj.setSpotlight(spotlight); } @@ -1466,3 +1486,25 @@ bool KartModel::handleSpotlight(GE::GESPM* spm) return spotlight; #endif } // handleSpotlight + +// ---------------------------------------------------------------------------- +bool KartModel::handleSPSpotlight(SP::SPMesh* spm) +{ + unsigned count = spm->getMeshBufferCount(); + bool spotlight = false; + for (int i = count - 1; i >= 0; i--) + { + SP::SPMeshBuffer* b = static_cast(spm->getMeshBuffer(i)); + const auto& materials = b->getAllSTKMaterials(); + for (unsigned i = 0; i < materials.size(); i++) + { + Material* m = materials[i]; + if (m && m->getSamplerPath(0).find("stk_conelight_a.png") != std::string::npos) + { + spotlight = true; + b->disableForMaterial(i); + } + } + } + return spotlight; +} // handleSPSpotlight diff --git a/src/karts/kart_model.hpp b/src/karts/kart_model.hpp index b3c40c9deb9..77d86135568 100644 --- a/src/karts/kart_model.hpp +++ b/src/karts/kart_model.hpp @@ -32,6 +32,7 @@ namespace irr } using namespace irr; namespace GE { class GERenderInfo; class GESPM; } +namespace SP { class SPMesh; } #include "utils/no_copy.hpp" #include "utils/vec3.hpp" @@ -349,6 +350,8 @@ class KartModel : public scene::IAnimationEndCallBack, public NoCopy } // ------------------------------------------------------------------------ bool handleSpotlight(GE::GESPM* spm); + // ------------------------------------------------------------------------ + bool handleSPSpotlight(SP::SPMesh* spm); public: KartModel(bool is_master); From dc32aefa1b396fe51385803f9c39a44d439a135d Mon Sep 17 00:00:00 2001 From: Deve Date: Wed, 7 May 2025 23:31:14 +0200 Subject: [PATCH 712/830] Fix vulkan skinning shader v_tangent.w is bitangent sign --- data/shaders/ge_shaders/spm_skinning.vert | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/shaders/ge_shaders/spm_skinning.vert b/data/shaders/ge_shaders/spm_skinning.vert index 7be9bb4f1ff..5237db34154 100644 --- a/data/shaders/ge_shaders/spm_skinning.vert +++ b/data/shaders/ge_shaders/spm_skinning.vert @@ -31,7 +31,7 @@ void main() f_hue_change = u_object_buffer.m_objects[gl_InstanceIndex].m_hue_change; #ifdef PBR_ENABLED vec4 skinned_normal = joint_matrix * v_normal; - vec4 skinned_tangent = joint_matrix * v_tangent; + vec4 skinned_tangent = joint_matrix * vec4(v_tangent.xyz, 0.0); vec3 world_normal = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, skinned_normal.xyz); vec3 world_tangent = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, skinned_tangent.xyz); From d4806f16860ca6e6cf71aec7741ac19afbbd1350 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 9 May 2025 14:23:21 +0200 Subject: [PATCH 713/830] Fix #5408 --- src/guiengine/widgets/ribbon_widget.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/guiengine/widgets/ribbon_widget.cpp b/src/guiengine/widgets/ribbon_widget.cpp index a4342c9b42e..79373adaee7 100644 --- a/src/guiengine/widgets/ribbon_widget.cpp +++ b/src/guiengine/widgets/ribbon_widget.cpp @@ -859,12 +859,16 @@ void RibbonWidget::resize() tab_contents_rect.UpperLeftCorner.Y + tab_contents_rect.getHeight()); } - // Define the label area and ensure the label doesn't overlap with the icon - rect label_part = rect(icon_part.LowerRightCorner.X + 5, + // Define the label area + rect label_part = rect(tab_contents_rect.UpperLeftCorner.X, tab_contents_rect.UpperLeftCorner.Y, tab_contents_rect.LowerRightCorner.X, tab_contents_rect.LowerRightCorner.Y); + // Ensure the label doesn't overlap with the icon + if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) + label_part.UpperLeftCorner.X += icon_part.getWidth() + 5; + m_active_children[i].m_element->setRelativePosition(tab_rect_abs); if (m_active_children[i].m_type == WTYPE_ICON_BUTTON) m_child_data.at(i).second->setRelativePosition(icon_part); From 97288d2030c79e9140cb0d4d043bd2077a36cfda Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 9 May 2025 16:44:16 +0200 Subject: [PATCH 714/830] Fix #5411 For the instant speed increase to work, the game applies a speed floor that gets reset the next frame. This speed floor is now also adjusted by the adjustSpeed() function. --- src/karts/kart.cpp | 12 ++++++++---- src/karts/max_speed.cpp | 7 +++++-- src/physics/btKart.hpp | 8 ++++++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 7a9b2f10b50..e6ee4eec51d 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -861,14 +861,17 @@ bool Kart::isInRest() const } // isInRest //----------------------------------------------------------------------------- -/** Multiplies the velocity of the kart by a factor f (both linear - * and angular). This is used by anvils, which suddenly slow down the kart - * when they are attached. +/** Multiplies the velocity of the kart by a factor f (both linear and angular). + * This is used by anchors, which suddenly slow down the kart when they are attached. */ void Kart::adjustSpeed(float f) { m_body->setLinearVelocity(m_body->getLinearVelocity()*f); m_body->setAngularVelocity(m_body->getAngularVelocity()*f); + // Avoid instant speed increase on the same frame ignoring the adjustment, see #5411 + float new_min_speed = m_vehicle->getMinSpeed()*f; + m_vehicle->resetMinSpeed(); // setMinSpeed only update if the new one is greater... See btKart.hpp + m_vehicle->setMinSpeed(new_min_speed); } // adjustSpeed //----------------------------------------------------------------------------- @@ -1382,8 +1385,9 @@ void Kart::update(int ticks) m_powerup->update(ticks); - // Reset any instant speed increase in the bullet kart + // Reset any instant speed increase or speed floor in the bullet kart m_vehicle->resetMaxSpeed(); + m_vehicle->resetMinSpeed(); if (m_bubblegum_ticks > 0) m_bubblegum_ticks -= ticks; diff --git a/src/karts/max_speed.cpp b/src/karts/max_speed.cpp index f586a84cb38..34a3fc10ed8 100644 --- a/src/karts/max_speed.cpp +++ b/src/karts/max_speed.cpp @@ -173,7 +173,7 @@ void MaxSpeed::instantSpeedIncrease(unsigned int category, // This will result in all max speed settings updated, but no // changes to any slow downs since dt=0 update(0); - float speed = std::min(m_kart->getSpeed()+ speed_boost, + float speed = std::min(m_kart->getSpeed() + speed_boost, getCurrentMaxSpeed() ); // If there is a min_speed defined, make sure that the kart is still @@ -182,7 +182,6 @@ void MaxSpeed::instantSpeedIncrease(unsigned int category, if(speed < m_min_speed) speed = m_min_speed; m_kart->getVehicle()->setMinSpeed(speed); - } // instantSpeedIncrease // ---------------------------------------------------------------------------- @@ -441,6 +440,10 @@ void MaxSpeed::update(int ticks) { m_kart->getVehicle()->setMinSpeed(m_min_speed); } + // FIXME: setMinSpeed only updates the value if the new value is greater, + // so the following code doesn't really do anything? + // There is probably a reason for the behavior of setMinSpeed, but the code + // should be redesigned to make it less confusing... else m_kart->getVehicle()->setMinSpeed(0); // no additional acceleration diff --git a/src/physics/btKart.hpp b/src/physics/btKart.hpp index 5b84b408710..e8438f71b91 100644 --- a/src/physics/btKart.hpp +++ b/src/physics/btKart.hpp @@ -274,9 +274,13 @@ class btKart : public btActionInterface // ------------------------------------------------------------------------ /** Resets the maximum so any new maximum value from the application will * be accepted. */ - virtual void resetMaxSpeed() { m_max_speed = -1.0f; m_min_speed = 0.0f; } + virtual void resetMaxSpeed() { m_max_speed = -1.0f; } // ------------------------------------------------------------------------ - /** Sets the minimum speed for this kart. */ + virtual void resetMinSpeed() { m_min_speed = 0.0f; } + // ------------------------------------------------------------------------ + /** Sets the minimum speed for this kart, only if the new value is higher. + * FIXME The name of this function doesn't match its real behavior, it's confusing + * Determine why it needs to work that way and make it cleaner */ void setMinSpeed(float s) { if(s > m_min_speed) m_min_speed = s; From 6c0d60a2d52e3bd8cc915a9596389591f7c6b3a8 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sat, 10 May 2025 16:22:57 +0200 Subject: [PATCH 715/830] Fix #5417 --- src/states_screens/race_result_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 53674f2c47a..4b065d30485 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -1947,7 +1947,7 @@ int RaceResultGUI::displayHighscores(int x, int y, bool increase_density) scores->getEntry(i, kart_name, player_name, &time); if (player_name.size() > max_characters) { - int begin = (int(m_timer / 0.4f)) % (player_name.size() - max_characters); + int begin = (int(m_timer / 0.4f)) % (player_name.size() - max_characters + 1); player_name = player_name.subString(begin, max_characters, false); } From 6e9d21f4f22ad5b0803597225dbef67db4bb897c Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sat, 10 May 2025 18:29:57 +0200 Subject: [PATCH 716/830] Fix #5419 - Increase the character limit for the name before forced scrolling from 15 to 30. Beyond 30, many parts of the GUI become problematic anyways, and while many reasonable usernames exceed 15, none exceed 30. - Use the actual rendered width of the player name to compute how many characters can be shown at once if scrolling is needed. -- Also check the width of substrings to avoid overflows from uneven character lengths - Add a short pause at the beginning and the end of the name scrolling, as otherwise there is little time to see the first and last characters compared to others --- src/states_screens/race_result_gui.cpp | 47 +++++++++++++++++++++----- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 4b065d30485..30b2cc7138f 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -1933,21 +1933,50 @@ int RaceResultGUI::displayHighscores(int x, int y, bool increase_density) std::string kart_name; irr::core::stringw player_name; - // prevent excessive long name - unsigned int max_characters = 15; - unsigned int max_width = (UserConfigParams::m_width / 2 - 200) / 10; - if (max_width < 15) - max_characters = max_width; - + const float SCORE_X_RATIO = 0.85f; int width_icon_adjusted = increase_density ? m_width_icon * 0.8f : m_width_icon; + // Used to prevent excessively long names + unsigned int max_width = (int)((float)UserConfigParams::m_width * (SCORE_X_RATIO - 0.65f)) + - width_icon_adjusted - 20; + float time; for (int i = 0; i < scores->getNumberEntries(); i++) { scores->getEntry(i, kart_name, player_name, &time); - if (player_name.size() > max_characters) + float width_ratio = (float)GUIEngine::getSmallFont()->getDimension(player_name.c_str()).Width / (float)max_width; + unsigned int max_characters = 30; + if (player_name.size() > max_characters || width_ratio >= 1.0f) { - int begin = (int(m_timer / 0.4f)) % (player_name.size() - max_characters + 1); + // Different parts of a name can have different width properties: + // - We could assume all the characters are large, but that can waste a lot of space + // - Instead, we do some extra computations to use more space while avoiding overflows + find_length_start: + int substring_test_length = (int)((float)player_name.size() / width_ratio); + unsigned int max_substring_width = 0; + for (uint i=0; i<(player_name.size() - substring_test_length + 1); i++) + { + irr::core::stringw test_substring = player_name.subString(i, substring_test_length, false); + max_substring_width = std::max(max_substring_width, + GUIEngine::getSmallFont()->getDimension(test_substring.c_str()).Width); + } + float substring_overflow_factor = ((float)max_substring_width / (float)max_width); + // If the initial estimate was really off, we refine our estimate + if (substring_overflow_factor > 1.1f) + { + width_ratio *= substring_overflow_factor; + goto find_length_start; + } + + float overflow_factor = substring_overflow_factor * width_ratio * 1.01f; + max_characters = (unsigned int)((float)player_name.size() / overflow_factor); + int overflow_chars = player_name.size() - max_characters; + + // Add 1 to the divisor to ensure the last character is displayed, and add 2 for pauses + int begin = (int(m_timer / 0.4f)) % (overflow_chars + 3) - 1; + if (begin == -1) begin = 0; // Pause at the start + if (begin == overflow_chars + 1) begin = overflow_chars; // Pause at the end + player_name = player_name.subString(begin, max_characters, false); } @@ -1988,7 +2017,7 @@ int RaceResultGUI::displayHighscores(int x, int y, bool increase_density) core::recti(current_x, current_y, current_x + 150, current_y + 10), text_color, false, false, NULL, true /* ignoreRTL */); - current_x = (int)(UserConfigParams::m_width * 0.85f); + current_x = (int)(UserConfigParams::m_width * SCORE_X_RATIO); // Finally draw the time std::string highscore_string; From ea470dd0484a28b49c539c788c34e68a2eb6764a Mon Sep 17 00:00:00 2001 From: Piotr Danecki Date: Sat, 10 May 2025 16:32:46 +0000 Subject: [PATCH 717/830] Add a random track button outside of the track chooser (#5399) Signed-off-by: Piotr Danecki --- data/gui/screens/tracks_and_gp.stkgui | 5 +-- src/states_screens/tracks_and_gp_screen.cpp | 44 +++++++++++---------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/data/gui/screens/tracks_and_gp.stkgui b/data/gui/screens/tracks_and_gp.stkgui index 40f1f647d16..65f4e186656 100644 --- a/data/gui/screens/tracks_and_gp.stkgui +++ b/data/gui/screens/tracks_and_gp.stkgui @@ -24,11 +24,10 @@
- - + +
-
diff --git a/src/states_screens/tracks_and_gp_screen.cpp b/src/states_screens/tracks_and_gp_screen.cpp index f658928a19c..298581d1207 100644 --- a/src/states_screens/tracks_and_gp_screen.cpp +++ b/src/states_screens/tracks_and_gp_screen.cpp @@ -51,31 +51,35 @@ static const char ALL_TRACK_GROUPS_ID[] = "all"; void TracksAndGPScreen::eventCallback(Widget* widget, const std::string& name, const int playerID) { - // -- track selection screen - if (name == "tracks") + // -- track selection screen / random track button + if (name == "tracks" || name == "random_track") { - DynamicRibbonWidget* w2 = dynamic_cast(widget); - if(!w2) return; - - std::string selection = w2->getSelectionIDString(PLAYER_ID_GAME_MASTER); - if (UserConfigParams::logGUI()) + std::string selection; + if (name == "tracks") { - Log::info("TracksAndGPScreen", "Clicked on track '%s'.", - selection.c_str()); - } + DynamicRibbonWidget* w2 = dynamic_cast(widget); + if(!w2) return; - UserConfigParams::m_last_track = selection; - if (selection == "locked" && RaceManager::get()->getNumLocalPlayers() == 1) - { - unlock_manager->playLockSound(); - return; - } - else if (selection == RibbonWidget::NO_ITEM_ID) - { - return; + selection = w2->getSelectionIDString(PLAYER_ID_GAME_MASTER); + if (UserConfigParams::logGUI()) + { + Log::info("TracksAndGPScreen", "Clicked on track '%s'.", + selection.c_str()); + } + + UserConfigParams::m_last_track = selection; + if (selection == "locked" && RaceManager::get()->getNumLocalPlayers() == 1) + { + unlock_manager->playLockSound(); + return; + } + else if (selection == RibbonWidget::NO_ITEM_ID) + { + return; + } } - if (selection == "random_track") + if (selection == "random_track" || name == "random_track") { if (m_random_track_list.empty()) return; From 09f3de820df3388bedb66c8670cecfab234dd028 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sat, 10 May 2025 18:40:04 +0200 Subject: [PATCH 718/830] Adjust the Tracks and GPs screen to better fit the random track button Also fix the portability issue from uint introduced in 14b356a --- data/gui/screens/tracks_and_gp.stkgui | 73 +++++++++++++++++--------- src/states_screens/race_result_gui.cpp | 2 +- 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/data/gui/screens/tracks_and_gp.stkgui b/data/gui/screens/tracks_and_gp.stkgui index 65f4e186656..d68f2355ca7 100644 --- a/data/gui/screens/tracks_and_gp.stkgui +++ b/data/gui/screens/tracks_and_gp.stkgui @@ -3,38 +3,61 @@
-
- -
- - - - - - - - -
+
+
+
- + + + + + + + + +
+
+ + + + +
+ + + +
+
+
+ + -
-
- - -
- - +
+ + + + + + + + + + +
- + diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 30b2cc7138f..a8a5229896d 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -1954,7 +1954,7 @@ int RaceResultGUI::displayHighscores(int x, int y, bool increase_density) find_length_start: int substring_test_length = (int)((float)player_name.size() / width_ratio); unsigned int max_substring_width = 0; - for (uint i=0; i<(player_name.size() - substring_test_length + 1); i++) + for (unsigned int i=0; i<(player_name.size() - substring_test_length + 1); i++) { irr::core::stringw test_substring = player_name.subString(i, substring_test_length, false); max_substring_width = std::max(max_substring_width, From 489af5214ea484892b5f182b8ec0811694636940 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 11 May 2025 03:10:20 +0400 Subject: [PATCH 719/830] Add RelWithDebInfo to pipeline --- .github/workflows/linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 94e573a44d4..a20c4c58218 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -28,7 +28,7 @@ jobs: matrix: os: [ubuntu-latest] compiler: [gcc, clang] - build_type: [Debug, Release] + build_type: [Debug, RelWithDebInfo, Release] server_only: [ON, OFF] exclude: - os: macos-latest From 05d5997b4529f2981e3a59385a9d6edf680e276f Mon Sep 17 00:00:00 2001 From: QwertyChouskie Date: Mon, 12 May 2025 02:46:09 -0700 Subject: [PATCH 720/830] Update mojoAL to latest version, fixes #5418 (#5421) --- lib/mojoal/LICENSE.txt | 38 ++++++++++++++++---------------------- lib/mojoal/mojoal.c | 39 +++++++++++++++++++++++++++------------ 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/lib/mojoal/LICENSE.txt b/lib/mojoal/LICENSE.txt index 8c9693e81de..9566441c36d 100644 --- a/lib/mojoal/LICENSE.txt +++ b/lib/mojoal/LICENSE.txt @@ -1,23 +1,17 @@ - - Copyright (c) 2018-2019 Ryan C. Gordon and others. - - This software is provided 'as-is', without any express or implied warranty. - In no event will the authors be held liable for any damages arising from - the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software in a - product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be +Copyright (c) 2018-2023 Ryan C. Gordon + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source distribution. - - Ryan C. Gordon - +3. This notice may not be removed or altered from any source distribution. diff --git a/lib/mojoal/mojoal.c b/lib/mojoal/mojoal.c index d0a63fd2032..4a4d9b8a59b 100644 --- a/lib/mojoal/mojoal.c +++ b/lib/mojoal/mojoal.c @@ -1432,12 +1432,15 @@ static ALboolean mix_source_buffer(ALCcontext *ctx, ALsource *src, BufferQueueIt if (src->stream) { /* resampling? */ int mixframes, mixlen, remainingmixframes; while ( (((mixlen = SDL_AudioStreamAvailable(src->stream)) / bufferframesize) < framesneeded) && (src->offset < buffer->len) ) { - const int framesput = (buffer->len - src->offset) / bufferframesize; - const int bytesput = SDL_min(framesput, 1024) * bufferframesize; + const int bytesleft = (buffer->len - src->offset); + /* workaround in case remains are less than bufferframesize */ + const int framesput = (bytesleft + (bufferframesize - 1)) / bufferframesize; + const int bytesput = SDL_min(SDL_min(framesput, 1024) * bufferframesize, bytesleft); FIXME("dynamically adjust frames here?"); /* we hardcode 1024 samples when opening the audio device, too. */ SDL_AudioStreamPut(src->stream, data, bytesput); src->offset += bytesput; - data += bytesput / sizeof (float); + /* workaround in case remains are not evenly divided by sizeof (float) */ + data += (bytesput + (sizeof (float) - 1)) / sizeof (float); } mixframes = SDL_min(mixlen / bufferframesize, framesneeded); @@ -1812,9 +1815,13 @@ static void calculate_channel_gains(const ALCcontext *ctx, const ALsource *src, V_sse = _mm_sub_ps(position_sse, _mm_mul_ps(_mm_set1_ps(a), up_sse)); mags = magnitude_sse(at_sse) * magnitude_sse(V_sse); - cosangle = (mags == 0.0f) ? 0.0f : (dotproduct_sse(at_sse, V_sse) / mags); - cosangle = SDL_clamp(cosangle, -1.0f, 1.0f); - radians = SDL_acosf(cosangle); + if (mags == 0.0f) { + radians = 0.0f; + } else { + cosangle = dotproduct_sse(at_sse, V_sse) / mags; + cosangle = SDL_clamp(cosangle, -1.0f, 1.0f); + radians = SDL_acosf(cosangle); + } R_sse = xyzzy_sse(at_sse, up_sse); @@ -1838,9 +1845,13 @@ static void calculate_channel_gains(const ALCcontext *ctx, const ALsource *src, V_neon = vsubq_f32(position_neon, vmulq_f32(vdupq_n_f32(a), up_neon)); mags = magnitude_neon(at_neon) * magnitude_neon(V_neon); - cosangle = (mags == 0.0f) ? 0.0f : (dotproduct_neon(at_neon, V_neon) / mags); - cosangle = SDL_clamp(cosangle, -1.0f, 1.0f); - radians = SDL_acosf(cosangle); + if (mags == 0.0f) { + radians = 0.0f; + } else { + cosangle = dotproduct_neon(at_neon, V_neon) / mags; + cosangle = SDL_clamp(cosangle, -1.0f, 1.0f); + radians = SDL_acosf(cosangle); + } R_neon = xyzzy_neon(at_neon, up_neon); @@ -1867,9 +1878,13 @@ static void calculate_channel_gains(const ALCcontext *ctx, const ALsource *src, /* Calculate angle */ mags = magnitude(at) * magnitude(V); - cosangle = (mags == 0.0f) ? 0.0f : (dotproduct(at, V) / mags); - cosangle = SDL_clamp(cosangle, -1.0f, 1.0f); - radians = SDL_acosf(cosangle); + if (mags == 0.0f) { + radians = 0.0f; + } else { + cosangle = dotproduct(at, V) / mags; + cosangle = SDL_clamp(cosangle, -1.0f, 1.0f); + radians = SDL_acosf(cosangle); + } /* Get "right" vector */ xyzzy(R, at, up); From df513f0c8178f5861770964e6009d83ec40f5b6a Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 12 May 2025 13:09:22 +0200 Subject: [PATCH 721/830] Fix #5420 This only applies to normal fonts, not to title fonts --- src/guiengine/widgets/label_widget.cpp | 26 +++++++++++++++++++++++--- src/guiengine/widgets/label_widget.hpp | 1 + 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/guiengine/widgets/label_widget.cpp b/src/guiengine/widgets/label_widget.cpp index 0ffbafbe191..97ff5c7770a 100644 --- a/src/guiengine/widgets/label_widget.cpp +++ b/src/guiengine/widgets/label_widget.cpp @@ -43,6 +43,7 @@ LabelWidget::LabelWidget(LabelType type) : Widget(WTYPE_LABEL) m_per_character_size = 0; m_scroll_offset = 0; m_expand_if_needed = false; + m_word_wrap = false; if (m_type == BRIGHT) { @@ -61,7 +62,7 @@ LabelWidget::LabelWidget(LabelType type) : Widget(WTYPE_LABEL) void LabelWidget::add() { rect widget_size = rect(m_x, m_y, m_x + m_w, m_y + m_h); - const bool word_wrap = m_properties[PROP_WORD_WRAP] == "true"; + m_word_wrap = m_properties[PROP_WORD_WRAP] == "true"; stringw message = getText(); EGUI_ALIGNMENT align = EGUIA_UPPERLEFT; @@ -78,12 +79,12 @@ void LabelWidget::add() IGUIElement* container = GUIEngine::getGUIEnv()->addButton(widget_size, m_parent, -1); core::rect r(core::position2di(0,0), widget_size.getSize()); irrwidget = GUIEngine::getGUIEnv()->addStaticText(message.c_str(), r, - false, word_wrap, /*m_parent*/ container, -1); + false, m_word_wrap, /*m_parent*/ container, -1); } else { irrwidget = GUIEngine::getGUIEnv()->addStaticText(message.c_str(), widget_size, - false, word_wrap, m_parent, -1); + false, m_word_wrap, m_parent, -1); irrwidget->setTextRestrainedInside(false); } @@ -126,6 +127,8 @@ void LabelWidget::add() if (!m_is_visible) m_element->setVisible(false); + + resize(); } // add // ---------------------------------------------------------------------------- @@ -200,7 +203,24 @@ void LabelWidget::setScrollSpeed(float speed) void LabelWidget::resize() { + // Reduce the font size of normal text if it overflows + if ((m_type != TITLE && m_type != SMALL_TITLE && m_type != TINY_TITLE)) + { + if( ((int)GUIEngine::getFont()->getDimension(m_text.c_str()).Width > + this->m_w) && + ((int)GUIEngine::getFont()->getDimension(m_text.c_str()).Height * 2 > + this->m_h || !m_word_wrap) ) + { + ((IGUIStaticText*)m_element)->setOverrideFont(GUIEngine::getSmallFont()); + } + else + { + ((IGUIStaticText*)m_element)->setOverrideFont(NULL); + } + } + m_per_character_size = getCurrentFont()->getDimension(L"X").Height; + if (m_scroll_speed != 0) { rect widget_size = rect(m_x, m_y, m_x + m_w, m_y + m_h); diff --git a/src/guiengine/widgets/label_widget.hpp b/src/guiengine/widgets/label_widget.hpp index 9f6a8c8156d..8208c26ff75 100644 --- a/src/guiengine/widgets/label_widget.hpp +++ b/src/guiengine/widgets/label_widget.hpp @@ -57,6 +57,7 @@ namespace GUIEngine irr::video::SColor m_color; bool m_has_color; bool m_expand_if_needed; + bool m_word_wrap; irr::gui::IGUIFont* getCurrentFont() const; void updateExpandedText(const irr::core::stringw& text); From 6aa1a9ea37f71f0343671e26c658a8624b57216f Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 12 May 2025 15:05:05 +0200 Subject: [PATCH 722/830] Make spinner widgets use the small font size if the label doesn't fit --- src/guiengine/widgets/spinner_widget.cpp | 41 +++++++++++++++++------- src/guiengine/widgets/spinner_widget.hpp | 3 ++ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/guiengine/widgets/spinner_widget.cpp b/src/guiengine/widgets/spinner_widget.cpp index 1ac88c25331..207cad80565 100644 --- a/src/guiengine/widgets/spinner_widget.cpp +++ b/src/guiengine/widgets/spinner_widget.cpp @@ -306,22 +306,34 @@ void SpinnerWidget::resize() } else { - rect subsize_label = rect(m_h, 0, m_w-m_h, m_h); - IGUIStaticText* label = static_cast(m_children[1].m_element); - label->setRelativePosition(subsize_label); - if (m_h < GUIEngine::getFontHeight()) - { - label->setOverrideFont(GUIEngine::getSmallFont()); - } - else - { - label->setOverrideFont(NULL); - } + resizeLabel(); } rect subsize_right_arrow = rect(m_w-m_h, 0, m_w, m_h); m_children[2].m_element->setRelativePosition(subsize_right_arrow); -} +} // resize + +// ----------------------------------------------------------------------------- + +/** Pick the appropriate font size to display the current spinner label */ +void SpinnerWidget::resizeLabel() +{ + if (m_graphical) // Don't proceed further if this spinner doesn't use labels + return; + + rect subsize_label = rect(m_h, 0, m_w - m_h, m_h); + IGUIStaticText* label = static_cast(m_children[1].m_element); + label->setRelativePosition(subsize_label); + if ( (m_h < GUIEngine::getFontHeight()) || + ((int)GUIEngine::getFont()->getDimension(label->getText()).Width > (m_w - 2 * m_h)) ) + { + label->setOverrideFont(GUIEngine::getSmallFont()); + } + else + { + label->setOverrideFont(NULL); + } +} // resizeLabel // ----------------------------------------------------------------------------- @@ -383,6 +395,9 @@ void SpinnerWidget::activateSelectedButton() setValue(m_max); } } + + // Update the label font size if needed + resizeLabel(); } // activateSelectedButton // ----------------------------------------------------------------------------- @@ -461,6 +476,7 @@ void SpinnerWidget::setValue(const int new_value) assert(new_value < (int)m_labels.size()); m_children[1].m_element->setText(m_labels[new_value].c_str()); + resizeLabel(); } else if (m_text.size() > 0 && m_children.size() > 0) { @@ -510,6 +526,7 @@ void SpinnerWidget::setValue(irr::core::stringw new_value) if (m_labels[n] == new_value) { setValue(n); + resizeLabel(); return; } } diff --git a/src/guiengine/widgets/spinner_widget.hpp b/src/guiengine/widgets/spinner_widget.hpp index 2334def3556..641798be088 100644 --- a/src/guiengine/widgets/spinner_widget.hpp +++ b/src/guiengine/widgets/spinner_widget.hpp @@ -118,6 +118,9 @@ namespace GUIEngine /** Call only if this spinner is graphical. Returns the current texture to display */ irr::video::ITexture* getTexture(); + + /** Pick the appropriate font size to display the current spinner label */ + void resizeLabel(); public: From 700991c55288da13a4ad6877522d41a45b13632d Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 12 May 2025 15:29:15 +0200 Subject: [PATCH 723/830] Remove the random track option within the tracks ribbon widget It's not needed anymore now that the screen has a dedicated random track button --- src/states_screens/tracks_and_gp_screen.cpp | 30 ++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/states_screens/tracks_and_gp_screen.cpp b/src/states_screens/tracks_and_gp_screen.cpp index 3c4f03b08ff..26b0616fb99 100644 --- a/src/states_screens/tracks_and_gp_screen.cpp +++ b/src/states_screens/tracks_and_gp_screen.cpp @@ -51,8 +51,21 @@ static const char ALL_TRACK_GROUPS_ID[] = "all"; void TracksAndGPScreen::eventCallback(Widget* widget, const std::string& name, const int playerID) { - // -- track selection screen / random track button - if (name == "tracks" || name == "random_track") + // random track button + if (name == "random_track") + { + if (m_random_track_list.empty()) return; + + std::string selection = m_random_track_list.front(); + m_random_track_list.pop_front(); + m_random_track_list.push_back(selection); + + TrackInfoScreen::getInstance()->setTrack(track_manager->getTrack(selection)); + TrackInfoScreen::getInstance()->push(); + } // name=="random_track" + + // -- track selection screen + else if (name == "tracks") { std::string selection; if (name == "tracks") @@ -79,15 +92,6 @@ void TracksAndGPScreen::eventCallback(Widget* widget, const std::string& name, } } - if (selection == "random_track" || name == "random_track") - { - if (m_random_track_list.empty()) return; - - selection = m_random_track_list.front(); - m_random_track_list.pop_front(); - m_random_track_list.push_back(selection); - - } // selection=="random_track" Track *track = track_manager->getTrack(selection); if (track) @@ -366,10 +370,6 @@ void TracksAndGPScreen::buildTrackList() } } - tracks_widget->addItem(_("Random Track"), "random_track", - "/gui/icons/track_random.png", 0 /* no badge */, - IconButtonWidget::ICON_PATH_TYPE_RELATIVE); - tracks_widget->updateItemDisplay(); std::random_shuffle( m_random_track_list.begin(), m_random_track_list.end() ); } // buildTrackList From 44acb8df860a204b17e3f3988a6ea08b7a8ef36d Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 12 May 2025 16:11:59 +0200 Subject: [PATCH 724/830] Tweaks to the kart and track selection screens Mostly to make it harder for labels to overflow --- data/gui/screens/karts.stkgui | 10 ++++---- data/gui/screens/tracks_and_gp.stkgui | 36 +++++++++++++-------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/data/gui/screens/karts.stkgui b/data/gui/screens/karts.stkgui index c448ca398a7..bffad55fdb5 100644 --- a/data/gui/screens/karts.stkgui +++ b/data/gui/screens/karts.stkgui @@ -18,13 +18,13 @@
diff --git a/data/gui/screens/tracks_and_gp.stkgui b/data/gui/screens/tracks_and_gp.stkgui index d68f2355ca7..b298f050a36 100644 --- a/data/gui/screens/tracks_and_gp.stkgui +++ b/data/gui/screens/tracks_and_gp.stkgui @@ -18,39 +18,39 @@
-
- + - + -
- - - -
+ + +
- + -
+
+ - - - - - -
From 95bcc156b1b3dcbeebd843e4e687868428c0e8db Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 12 May 2025 21:49:34 +0400 Subject: [PATCH 725/830] Don't crash if unable to print the log properly --- src/network/protocol_manager.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/network/protocol_manager.cpp b/src/network/protocol_manager.cpp index 58bf8b1ae14..708a4208693 100644 --- a/src/network/protocol_manager.cpp +++ b/src/network/protocol_manager.cpp @@ -453,8 +453,16 @@ void ProtocolManager::asynchronousUpdate() const std::string& name = (*i)->getPeer()->getAddress().toString(); Log::error("ProtocolManager", "Asynchronous event " "error from %s: %s", name.c_str(), e.what()); - Log::error("ProtocolManager", - (*i)->data().getLogMessage().c_str()); + + if (*i != nullptr) + { + // kimden: make sure you don't cause it to be nullptr yourself + Log::error("ProtocolManager", (*i)->data().getLogMessage().c_str()); + } + else + { + Log::error("ProtocolManager", "data is null, cannot get log message!"); + } } m_async_events_to_process.lock(); From 0f6977c6a8fe903e251247a87aadab0f3047804d Mon Sep 17 00:00:00 2001 From: Deve Date: Mon, 12 May 2025 23:35:08 +0200 Subject: [PATCH 726/830] Load spot lights data from exporter settings --- src/io/xml_node.hpp | 1 + src/karts/kart_model.cpp | 214 ++++++++++++++++------- src/karts/kart_model.hpp | 73 +++++++- src/tracks/track_object_presentation.cpp | 27 +++ 4 files changed, 239 insertions(+), 76 deletions(-) diff --git a/src/io/xml_node.hpp b/src/io/xml_node.hpp index e1287d2a7d8..dae70eb0215 100644 --- a/src/io/xml_node.hpp +++ b/src/io/xml_node.hpp @@ -99,6 +99,7 @@ class XMLNode : public NoCopy int getHPR(Vec3 *value) const; bool hasChildNamed(const char* name) const; + const std::string& getFilename() const { return m_file_name; } /** Handy functions to test the bit pattern returned by get(vector3df*).*/ static bool hasX(int b) { return (b&1)==1; } diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index 0083c924011..6f9793dbe40 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -44,8 +44,8 @@ #include "karts/kart_properties.hpp" #include "physics/btKart.hpp" #include "tracks/track.hpp" -#include "utils/constants.hpp" #include "utils/log.hpp" +#include "utils/string_utils.hpp" #include "IMeshCache.h" #include "IMeshManipulator.h" @@ -228,7 +228,8 @@ void KartModel::loadInfo(const XMLNode &node) } if (const XMLNode* headlights_node = node.getNode("headlights")) { - loadHeadlights(*headlights_node); + std::string kart_dir = StringUtils::getPath(node.getFilename())+"/"; + loadHeadlights(*headlights_node, kart_dir); } if (const XMLNode* hat_node = node.getNode("hat")) { @@ -519,30 +520,43 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool human_playe } } - const float each_energy = 0.5f / m_headlight_objects.size(); - const float each_radius = 5.0f / m_headlight_objects.size(); +#ifdef SERVER_ONLY + bool supports_light = false; +#else + bool supports_light = (CVS->isGLSL() && CVS->isDeferredEnabled()) || + irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN; +#endif + for (unsigned int i = 0; i < m_headlight_objects.size(); i++) { - HeadlightObject& obj = m_headlight_objects[i]; Track* track = Track::getCurrentTrack(); - if (obj.getModel() && !(track == NULL || track->getIsDuringDay())) + if (track == NULL || track->getIsDuringDay()) + break; + HeadlightObject& obj = m_headlight_objects[i]; + const bool bone_attachment = + m_animated_node && !obj.getBoneName().empty(); + scene::ISceneNode* parent = bone_attachment ? + m_animated_node->getJointNode(obj.getBoneName().c_str()) : node; + scene::ISceneNode* node = NULL; + if (obj.getHeadlightType() == HLT_MESH) { - const bool bone_attachment = - m_animated_node && !obj.getBoneName().empty(); - scene::ISceneNode* parent = bone_attachment ? - m_animated_node->getJointNode(obj.getBoneName().c_str()) : node; - scene::ISceneNode* headlight_model = - irr_driver->addMesh(obj.getModel(), "kart_headlight", + if (!obj.getModel()) + continue; + node = irr_driver->addMesh(obj.getModel(), "kart_headlight", parent, getRenderInfo()); -#ifndef SERVER_ONLY - bool supports_light = (CVS->isGLSL() && CVS->isDeferredEnabled()) || - irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN; - if (human_player && supports_light) - { - obj.setLight(headlight_model, each_energy, each_radius); - } -#endif - configNode(headlight_model, obj.getLocation(), bone_attachment ? + obj.setLightNode(node); + node->grab(); + } + else + { + if (!human_player || !supports_light) + continue; + obj.setLight(parent); + node = obj.getLightNode(); + } + if (node) + { + configNode(node, obj.getLocation(), bone_attachment ? getInverseBoneMatrix(obj.getBoneName()) : core::matrix4()); } } @@ -578,30 +592,28 @@ scene::ISceneNode* KartModel::attachModel(bool animated_models, bool human_playe // ---------------------------------------------------------------------------- /** Add a light node emitted from the center mass the headlight. */ -void HeadlightObject::setLight(scene::ISceneNode* parent, - float energy, float radius) +void HeadlightObject::setLight(scene::ISceneNode* parent) { bool is_vk = irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN; - if (m_spotlight == 1) - energy *= 2.0f; m_node = irr_driver->addLight(core::vector3df(0.0f, 0.0f, 0.0f), - energy, radius, m_headlight_color.getRed() / 255.f, + m_energy, m_radius, m_headlight_color.getRed() / 255.f, m_headlight_color.getGreen() / 255.f, m_headlight_color.getBlue() / 255.f, false/*sun*/, parent); - if (is_vk && m_spotlight == 1) + + if (is_vk && m_headlight_type == HLT_SPOT) { scene::ILightSceneNode* ln = static_cast(m_node); ln->setLightType(video::ELT_SPOT); video::SLight& data = ln->getLightData(); - data.InnerCone = 30.0f / 180.0f * M_PI; - data.OuterCone = 45.0f / 180.0f * M_PI; + data.InnerCone = m_inner_cone; + data.OuterCone = m_outer_cone; } - else if (m_spotlight == 1) + else if (m_headlight_type == HLT_SPOT) { LightNode* ln = static_cast(m_node); Spotlight& sl = ln->getSpotlightData(); - sl.m_inner_cone = 30.0f / 180.0f * M_PI; - sl.m_outer_cone = 45.0f / 180.0f * M_PI; + sl.m_inner_cone = m_inner_cone; + sl.m_outer_cone = m_outer_cone; } m_node->grab(); } // setLight @@ -734,35 +746,13 @@ bool KartModel::loadModels(const KartProperties &kart_properties) for (unsigned int i = 0; i < m_headlight_objects.size(); i++) { HeadlightObject& obj = m_headlight_objects[i]; - std::string full_name = kart_properties.getKartDir() + obj.getFilename(); + const std::string& fn = obj.getFilename(); + if (fn.empty()) + continue; + std::string full_name = kart_properties.getKartDir() + fn; scene::IMesh* mesh = irr_driver->getMesh(full_name); if (!mesh) continue; -#ifndef SERVER_ONLY - bool spotlight = spotlight_meshes.find(mesh) != spotlight_meshes.end(); - GE::GESPM* spm = dynamic_cast(mesh); - SP::SPMesh* spspm = dynamic_cast(mesh); - if (obj.getSpotlight() == -1) - { - if (spm) - { - if (!spotlight && handleSpotlight(spm)) - { - spotlight_meshes.insert(spm); - spotlight = true; - } - } - else if (spspm) - { - if (!spotlight && handleSPSpotlight(spspm)) - { - spotlight_meshes.insert(spspm); - spotlight = true; - } - } - obj.setSpotlight(spotlight); - } -#endif obj.setModel(mesh); #ifndef SERVER_ONLY SP::uploadSPM(obj.getModel()); @@ -917,8 +907,10 @@ void KartModel::loadWheelInfo(const XMLNode &node, // ---------------------------------------------------------------------------- -void KartModel::loadHeadlights(const XMLNode &node) +void KartModel::loadHeadlights(const XMLNode &node, const std::string& kart_dir) { + std::set spotlight_meshes; + unsigned light_count = 0; int children = node.getNumNodes(); for (int i = 0; i < children; i++) { @@ -940,18 +932,106 @@ void KartModel::loadHeadlights(const XMLNode &node) child->get("model", &model); video::SColor headlight_color(-1); child->get("color", &headlight_color); - bool is_spotlight = false; - int spotlight = -1; - if (child->get("spotlight", &is_spotlight)) - spotlight = is_spotlight; - m_headlight_objects.push_back(HeadlightObject(model, location, - bone_name, headlight_color, spotlight)); + float radius = 0.0f; + child->get("radius", &radius); + float energy = 0.0f; + child->get("energy", &energy); + float inner_cone = 0.0f; + child->get("inner-cone", &inner_cone); + float outer_cone = 0.0f; + child->get("outer-cone", &outer_cone); + std::string type; + if (!child->get("type", &type)) + { + HeadlightType hlt = HLT_UNKNOWN; +#ifndef SERVER_ONLY + // Auto detection code for old karts + std::string full_name = kart_dir + model; + scene::IMesh* mesh = irr_driver->getMesh(full_name); + if (!mesh) + continue; + bool spotlight = + spotlight_meshes.find(mesh) != spotlight_meshes.end(); + GE::GESPM* spm = dynamic_cast(mesh); + SP::SPMesh* spspm = dynamic_cast(mesh); + if (spm) + { + if (!spotlight && handleSpotlight(spm)) + { + spotlight_meshes.insert(spm); + spotlight = true; + } + } + else if (spspm) + { + if (!spotlight && handleSPSpotlight(spspm)) + { + spotlight_meshes.insert(spspm); + spotlight = true; + } + } + if (spotlight) + hlt = HLT_SPOT; + else if (!(headlight_color.getRed() == 0 && + headlight_color.getGreen() == 0 && + headlight_color.getBlue() == 0)) + hlt = HLT_POINT; + if (hlt == HLT_SPOT || hlt == HLT_POINT) + { + m_headlight_objects.push_back(HeadlightObject("", location, + bone_name, headlight_color, hlt, radius, energy, + inner_cone, outer_cone)); + light_count++; + } +#endif + hlt = HLT_MESH; + m_headlight_objects.push_back(HeadlightObject(model, location, + bone_name, headlight_color, hlt, radius, energy, + inner_cone, outer_cone)); + } + else + { + auto hlt = HeadlightObject::getHeadlightTypeFromString(type); + if (hlt == HLT_UNKNOWN) + continue; + m_headlight_objects.push_back(HeadlightObject(model, location, + bone_name, headlight_color, hlt, radius, energy, + inner_cone, outer_cone)); + if (hlt == HLT_SPOT || hlt == HLT_POINT) + light_count++; + } } else { Log::warn("KartModel", "Unknown XML node in the headlights section"); } } + const float init_energy = 1.5f; + const float init_radius = 5.0f; + for (HeadlightObject& obj : m_headlight_objects) + { + if (light_count == 0) + break; + if (obj.getHeadlightType() == HLT_MESH || !obj.useDefaultSettings()) + continue; + float each_energy = init_energy / light_count; + float each_radius = init_radius / light_count; + if (obj.getHeadlightType() == HLT_SPOT) + { + btClamp(each_energy, init_energy / 2.0f, init_energy); + btClamp(each_radius, init_radius / 2.0f, init_radius); + obj.setDefaultConeValues(light_count); + } + else + { + each_energy /= 3.6f; + each_radius /= 1.8f; + each_energy = std::min(each_energy, 0.4f); + each_radius = std::min(each_radius, 2.0f); + } + obj.setEnergy(each_energy); + obj.setRadius(each_radius); + } } // loadHeadlights // ---------------------------------------------------------------------------- @@ -1464,9 +1544,9 @@ const core::matrix4& KartModel::getInverseBoneMatrix //----------------------------------------------------------------------------- bool KartModel::handleSpotlight(GE::GESPM* spm) { + bool spotlight = false; #ifndef SERVER_ONLY unsigned count = spm->getMeshBufferCount(); - bool spotlight = false; for (int i = count - 1; i >= 0; i--) { GE::GESPMBuffer* b = static_cast(spm->getMeshBuffer(i)); @@ -1483,8 +1563,8 @@ bool KartModel::handleSpotlight(GE::GESPM* spm) } spm->finalize(); irr_driver->getSceneManager()->getMeshCache()->meshCacheChanged(); - return spotlight; #endif + return spotlight; } // handleSpotlight // ---------------------------------------------------------------------------- diff --git a/src/karts/kart_model.hpp b/src/karts/kart_model.hpp index 77d86135568..4440e3cf2a7 100644 --- a/src/karts/kart_model.hpp +++ b/src/karts/kart_model.hpp @@ -34,6 +34,7 @@ using namespace irr; namespace GE { class GERenderInfo; class GESPM; } namespace SP { class SPMesh; } +#include "utils/constants.hpp" #include "utils/no_copy.hpp" #include "utils/vec3.hpp" @@ -89,6 +90,16 @@ struct SpeedWeightedObject }; typedef std::vector SpeedWeightedObjectList; + +// ============================================================================ +enum HeadlightType : int +{ + HLT_UNKNOWN = -1, + HLT_POINT = 0, + HLT_SPOT, + HLT_MESH, + HLT_COUNT, +}; // ============================================================================ /** A class to store the headlights of a kart. */ @@ -114,19 +125,43 @@ class HeadlightObject /** Attach to which bone in kart model if not empty. */ std::string m_bone_name; - int m_spotlight; -public: + HeadlightType m_headlight_type; + float m_radius; + + float m_energy; + + float m_inner_cone; + + float m_outer_cone; +public: + // ------------------------------------------------------------------------ + static HeadlightType getHeadlightTypeFromString(const std::string& s) + { + if (s == "point") + return HLT_POINT; + if (s == "spot") + return HLT_SPOT; + if (s == "mesh") + return HLT_MESH; + return HLT_UNKNOWN; + } + // ------------------------------------------------------------------------ HeadlightObject() { m_model = NULL; m_node = NULL; - m_spotlight = -1; + m_headlight_type = HLT_POINT; + m_radius = 0.0f; + m_energy = 0.0f; + m_inner_cone = 0.0f; + m_outer_cone = 0.0f; } // HeadlightObject // ------------------------------------------------------------------------ HeadlightObject(const std::string& filename, const core::matrix4& location, const std::string& bone_name, const video::SColor& color, - int spotlight) + HeadlightType headlight_type, float radius, float energy, + float inner_cone, float outer_cone) { m_filename = filename; m_location = location; @@ -134,7 +169,11 @@ class HeadlightObject m_node = NULL; m_bone_name = bone_name; m_headlight_color = color; - m_spotlight = spotlight; + m_headlight_type = headlight_type; + m_radius = radius; + m_energy = energy; + m_inner_cone = inner_cone; + m_outer_cone = outer_cone; } // HeadlightObjects // ------------------------------------------------------------------------ const std::string& getFilename() const { return m_filename; } @@ -142,7 +181,9 @@ class HeadlightObject /** Sets the mesh for this headlight object. */ void setModel(scene::IMesh *mesh) { m_model = mesh; } // ------------------------------------------------------------------------ - void setLight(scene::ISceneNode* parent, float energy, float radius); + void setLight(scene::ISceneNode* parent); + // ------------------------------------------------------------------------ + void setLightNode(scene::ISceneNode* node) { m_node = node; } // ------------------------------------------------------------------------ const scene::ISceneNode *getLightNode() const { return m_node; } // ------------------------------------------------------------------------ @@ -156,10 +197,24 @@ class HeadlightObject // ------------------------------------------------------------------------ const std::string& getBoneName() const { return m_bone_name; } // ------------------------------------------------------------------------ - int getSpotlight() const { return m_spotlight; } + HeadlightType getHeadlightType() const { return m_headlight_type; } + // ------------------------------------------------------------------------ + void setRadius(float radius) { m_radius = radius; } // ------------------------------------------------------------------------ - void setSpotlight(bool spot) { m_spotlight = spot; } + void setEnergy(float energy) { m_energy = energy; } // ------------------------------------------------------------------------ + void setDefaultConeValues(unsigned light_count) + { + float outer_cone_angle = (light_count == 1 ? 45.0f : 50.0f); + m_outer_cone = outer_cone_angle / 180.0f * M_PI; + m_inner_cone = m_outer_cone / 1.5f; + } + // ------------------------------------------------------------------------ + bool useDefaultSettings() const + { + return m_radius == 0.0f && m_energy == 0.0f && m_inner_cone == 0.0f && + m_outer_cone == 0.0f; + } }; // class HeadlightObject // ============================================================================ @@ -309,7 +364,7 @@ class KartModel : public scene::IAnimationEndCallBack, public NoCopy void loadSpeedWeightedInfo(const XMLNode* speed_weighted_node, int index); - void loadHeadlights(const XMLNode &node); + void loadHeadlights(const XMLNode &node, const std::string& kart_dir); void OnAnimationEnd(scene::IAnimatedMeshSceneNode *node); diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index b76f7d441c9..864a27ed806 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -1041,6 +1041,33 @@ TrackObjectPresentationLight::TrackObjectPresentationLight( { m_node = NULL; // lights require shaders to work } + + std::string type = "point"; + xml_node.get("type", &type); + float inner_cone = 0.0f; + float outer_cone = 0.0f; + xml_node.get("inner-cone", &inner_cone); + xml_node.get("outer-cone", &outer_cone); + if (type != "spot" || (inner_cone == 0.0f && outer_cone == 0.0f)) + return; + + LightNode* lnode = dynamic_cast(m_node); + if (lnode != NULL) + { + Spotlight& sl = lnode->getSpotlightData(); + sl.m_inner_cone = inner_cone; + sl.m_outer_cone = outer_cone; + return; + } + scene::ILightSceneNode* irr_node = dynamic_cast( + m_node); + if (irr_node != NULL) + { + irr_node->setLightType(video::ELT_SPOT); + video::SLight& data = irr_node->getLightData(); + data.InnerCone = inner_cone; + data.OuterCone = outer_cone; + } } // TrackObjectPresentationLight // ---------------------------------------------------------------------------- From 02df7edf66cc0cbc88a1feb7bf198c3bf17aba63 Mon Sep 17 00:00:00 2001 From: Deve Date: Mon, 12 May 2025 23:49:37 +0200 Subject: [PATCH 727/830] Optimize spot lights shaders --- data/shaders/ge_shaders/utils/pbr_light.glsl | 21 +++++++++++--------- data/shaders/pointlight.frag | 14 ++++++------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/data/shaders/ge_shaders/utils/pbr_light.glsl b/data/shaders/ge_shaders/utils/pbr_light.glsl index 506ba309e00..96ae60c9b64 100644 --- a/data/shaders/ge_shaders/utils/pbr_light.glsl +++ b/data/shaders/ge_shaders/utils/pbr_light.glsl @@ -113,27 +113,30 @@ vec3 accumulateLights(vec3 diffuse_color, vec3 normal, vec3 xpos, vec3 eyedir, float distance_sq = dot(light_to_frag, light_to_frag); if (distance_sq * invrange > 1.) continue; + // SpotLight + float sattenuation = 1.; + float sscale = u_global_light.m_lights[i].m_direction_scale_offset.z; float distance = sqrt(distance_sq); float distance_inverse = 1. / distance; vec3 L = light_to_frag * distance_inverse; - vec3 diffuse_specular = PBRLight(normal, eyedir, L, diffuse_color, - perceptual_roughness, metallic); - float attenuation = 20. / (1. + distance_sq); - float radius = u_global_light.m_lights[i].m_position_radius.w; - attenuation *= (radius - distance) / radius; - // SpotLight - float sscale = u_global_light.m_lights[i].m_direction_scale_offset.z; if (sscale != 0.) { vec3 sdir = vec3(u_global_light.m_lights[i].m_direction_scale_offset.xy, 0.); sdir.z = sqrt(1. - dot(sdir, sdir)) * sign(sscale); sdir = (u_camera.m_view_matrix * vec4(sdir, 0.0)).xyz; - float sattenuation = clamp(dot(-sdir, normalize(light_to_frag)) * + sattenuation = clamp(dot(-sdir, L) * abs(sscale) + u_global_light.m_lights[i].m_direction_scale_offset.w, 0.0, 1.0); - attenuation *= sattenuation * sattenuation; + if (sattenuation == 0.) + continue; } + vec3 diffuse_specular = PBRLight(normal, eyedir, L, diffuse_color, + perceptual_roughness, metallic); + float attenuation = 20. / (1. + distance_sq); + float radius = u_global_light.m_lights[i].m_position_radius.w; + attenuation *= (radius - distance) / radius; + attenuation *= sattenuation * sattenuation; vec3 light_color = u_global_light.m_lights[i].m_color_inverse_square_range.xyz; accumulated_color += light_color * attenuation * diffuse_specular; diff --git a/data/shaders/pointlight.frag b/data/shaders/pointlight.frag index 834dcaa6f06..381a1fbb4e5 100644 --- a/data/shaders/pointlight.frag +++ b/data/shaders/pointlight.frag @@ -38,11 +38,14 @@ void main() pseudocenter /= pseudocenter.w; vec3 light_pos = pseudocenter.xyz; vec3 light_col = col.xyz; - float d = distance(light_pos, xpos.xyz); + vec3 light_to_frag = light_pos - xpos.xyz; + float d = length(light_to_frag); float att = energy * 20. / (1. + d * d); att *= (radius - d) / radius; if (att <= 0.) discard; + // Light Direction + vec3 L = light_to_frag / d; // Spotlight float sscale = direction_scale_offset.z; if (sscale != 0.) @@ -50,16 +53,13 @@ void main() vec3 sdir = vec3(direction_scale_offset.xy, 0.); sdir.z = sqrt(1. - dot(sdir, sdir)) * sign(sscale); sdir = (u_view_matrix * vec4(sdir, 0.0)).xyz; - vec3 light_to_frag = light_pos - xpos.xyz; float offset = direction_scale_offset.w; - float sattenuation = clamp(dot(-sdir, normalize(light_to_frag)) * + float sattenuation = clamp(dot(-sdir, L) * abs(sscale) + offset, 0.0, 1.0); + if (sattenuation == 0.) + discard; att *= sattenuation * sattenuation; } - if (att <= 0.) discard; - - // Light Direction - vec3 L = (light_pos - xpos.xyz) / d; float NdotL = clamp(dot(norm, L), 0., 1.); vec3 Specular = SpecularBRDF(norm, eyedir, L, vec3(1.), roughness); From 889cb807d92d1cd5b6880b16f88cf6546fe4eacb Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 13 May 2025 00:18:22 +0200 Subject: [PATCH 728/830] Fix server only build --- src/guiengine/widgets/CGUIEditBox.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/guiengine/widgets/CGUIEditBox.hpp b/src/guiengine/widgets/CGUIEditBox.hpp index a0c3644d1ba..e325d99baf1 100644 --- a/src/guiengine/widgets/CGUIEditBox.hpp +++ b/src/guiengine/widgets/CGUIEditBox.hpp @@ -13,6 +13,7 @@ #include "GlyphLayout.h" +#include #include #include From 3b340d6c7469c0bdc78f6abe88a158ef0ed0d236 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 13 May 2025 02:29:34 +0400 Subject: [PATCH 729/830] Take into account the crown order inside FFA filters Use case: when there are 11+ players and only standard FFA maps, they all require at most 10 players, and so none were available after filters, and so all players got an hourglass before this commit - even though clearly some of those would get an hourglass. --- src/utils/crown_manager.cpp | 8 ++++---- src/utils/crown_manager.hpp | 2 +- src/utils/lobby_asset_manager.cpp | 8 ++++++-- src/utils/lobby_asset_manager.hpp | 3 ++- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/utils/crown_manager.cpp b/src/utils/crown_manager.cpp index 6dc1663c4e1..b0ab6c369de 100644 --- a/src/utils/crown_manager.cpp +++ b/src/utils/crown_manager.cpp @@ -61,7 +61,7 @@ void CrownManager::setupContextUser() std::set>& CrownManager::getSpectatorsByLimit(bool update) { - if (!update) + if (!update) return m_spectators_by_limit; m_why_peer_cannot_play.clear(); @@ -132,7 +132,7 @@ std::set>& CrownManager::getSpectatorsByLimit(bool upda { if (peer->alwaysSpectate() || peer->isWaitingForGame()) ignore = true; - else if (!canRace(peer)) + else if (!canRace(peer, player_count + (unsigned)peer->getPlayerProfiles().size())) { m_spectators_by_limit.insert(peer); ignore = true; @@ -155,7 +155,7 @@ std::set>& CrownManager::getSpectatorsByLimit(bool upda //----------------------------------------------------------------------------- -bool CrownManager::canRace(std::shared_ptr peer) +bool CrownManager::canRace(std::shared_ptr peer, int known_number) { auto it = m_why_peer_cannot_play.find(peer); if (it != m_why_peer_cannot_play.end()) @@ -222,7 +222,7 @@ bool CrownManager::canRace(std::shared_ptr peer) return false; } - getAssetManager()->applyAllMapFilters(maps, true); + getAssetManager()->applyAllMapFilters(maps, true, known_number); getAssetManager()->applyAllKartFilters(username, karts, false); if (karts.empty()) diff --git a/src/utils/crown_manager.hpp b/src/utils/crown_manager.hpp index aae0f5cb25a..6815fc7d554 100644 --- a/src/utils/crown_manager.hpp +++ b/src/utils/crown_manager.hpp @@ -40,7 +40,7 @@ class CrownManager: public LobbyContextComponent std::set>& getSpectatorsByLimit(bool update = false); - bool canRace(std::shared_ptr peer); + bool canRace(std::shared_ptr peer, int known_number = -1); bool hasOnlyHostRiding() const { return m_only_host_riding; } bool isOwnerLess() const { return m_owner_less; } bool isSleepingServer() const { return m_sleeping_server; } diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp index 041076a8105..075a4717195 100644 --- a/src/utils/lobby_asset_manager.cpp +++ b/src/utils/lobby_asset_manager.cpp @@ -601,10 +601,14 @@ void LobbyAssetManager::gameFinishedOn(const std::string& map_name) } // gameFinishedOn //----------------------------------------------------------------------------- -void LobbyAssetManager::applyAllMapFilters(std::set& maps, bool use_history) const +void LobbyAssetManager::applyAllMapFilters(std::set& maps, bool use_history, int known_number) const { unsigned max_player = 0; - STKHost::get()->updatePlayers(&max_player); + if (known_number >= 0) // Careful with unsigned if you edit + max_player = known_number; + else + STKHost::get()->updatePlayers(&max_player); + if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) { auto it = maps.begin(); diff --git a/src/utils/lobby_asset_manager.hpp b/src/utils/lobby_asset_manager.hpp index 78390df9aa3..cefffc1c3e1 100644 --- a/src/utils/lobby_asset_manager.hpp +++ b/src/utils/lobby_asset_manager.hpp @@ -77,7 +77,8 @@ class LobbyAssetManager: public LobbyContextComponent void setMustHaveMaps(const std::string& input); void gameFinishedOn(const std::string& map_name); - void applyAllMapFilters(std::set& maps, bool use_history) const; + // kimden: default -1 should be called by its own name + void applyAllMapFilters(std::set& maps, bool use_history, int known_number = -1) const; void applyAllKartFilters(const std::string& username, std::set& karts, bool afterSelection = false) const; void applyGlobalFilter(FilterContext& map_context) const; From 925241884248783b2f2243c083afb179082f0e06 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Tue, 13 May 2025 17:19:58 +0200 Subject: [PATCH 730/830] Fix #5424 --- src/states_screens/kart_selection.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index ca4d9a70721..ead587304e0 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -1162,19 +1162,27 @@ void KartSelectionScreen::eventCallback(Widget* widget, player_id == PLAYER_ID_GAME_MASTER && !m_game_master_confirmed && selection != RANDOM_KART_ID && !selection.empty()) { - const KartProperties *kp = kart_properties_manager->getKart(selection); - - if (PlayerManager::getCurrentPlayer()->isFavoriteKart(kp->getIdent())) + // Locked karts can't be set as favorites + if (StringUtils::startsWith(selection, ID_LOCKED)) { - PlayerManager::getCurrentPlayer()->removeFavoriteKart(kp->getIdent()); + unlock_manager->playLockSound(); } else { - PlayerManager::getCurrentPlayer()->addFavoriteKart(kp->getIdent()); - } - setKartsFromCurrentGroup(); + const KartProperties *kp = kart_properties_manager->getKart(selection); - handleKartListFocus(); + if (PlayerManager::getCurrentPlayer()->isFavoriteKart(kp->getIdent())) + { + PlayerManager::getCurrentPlayer()->removeFavoriteKart(kp->getIdent()); + } + else + { + PlayerManager::getCurrentPlayer()->addFavoriteKart(kp->getIdent()); + } + setKartsFromCurrentGroup(); + + handleKartListFocus(); + } } else if (m_kart_widgets.size() > unsigned(player_id) && !useContinueButton()) playerConfirm(player_id); @@ -1250,7 +1258,7 @@ void KartSelectionScreen::onFocusChanged(GUIEngine::Widget* previous, if (GUIEngine::isFocusedForPlayer(kart_class, playerID)) { - for (int i = 0; i < m_kart_widgets.size(); i++) + for (unsigned int i = 0; i < m_kart_widgets.size(); i++) { if (m_kart_widgets[i].getPlayerID() == playerID) { From 4eaddca6ff0f49b42d117133f8be07c48060ddbf Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Tue, 13 May 2025 18:45:07 +0200 Subject: [PATCH 731/830] Allow single-row ribbons to be smaller to show more elements - Reuse the scoring and resizing logic developped for multi-ribbon widgets - Set a cap so that the smallest resize factor is 0.7 - Slightly recenter vertically the icons (avoids having a lot of empty space below while scrapping the ribbon border above) --- .../widgets/dynamic_ribbon_widget.cpp | 44 +++++++++++++------ .../widgets/dynamic_ribbon_widget.hpp | 3 +- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.cpp b/src/guiengine/widgets/dynamic_ribbon_widget.cpp index f6d4952bbeb..e22825788f8 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.cpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.cpp @@ -241,7 +241,7 @@ void DynamicRibbonWidget::updateForResizing() * \param[out] heightRatio the proportion of max height that should be used */ float DynamicRibbonWidget::estimateRowScore(const int rowCount, const int width, const int height, - const float iconAspectRatio, const int maxIcons, float* heightRatio) + const float iconAspectRatio, const int maxIcons, float* heightRatio, float capSize) { assert(height > 0); @@ -307,6 +307,8 @@ float DynamicRibbonWidget::estimateRowScore(const int rowCount, const int width, } test_height_ratio -= 0.05f; + if (test_height_ratio < capSize) + break; } // while icon height > greatest icon height possible with another row return max_score_so_far; @@ -319,6 +321,11 @@ void DynamicRibbonWidget::buildInternalStructure() // FIXME: The height of the tabs that are associated with a ribbon widget // don't change smoothly, as a result the available areas for the ribbon // icons may decrease when increasing screen height + int item_shown_target = m_item_count_hint; + + if (item_shown_target < 1) + item_shown_target = (int) m_items.size(); + if (m_multi_row) { // determine row amount @@ -333,21 +340,17 @@ void DynamicRibbonWidget::buildInternalStructure() else { float max_score_so_far = -1; - int item_count = m_item_count_hint; - - if (item_count < 1) - item_count = (int) m_items.size(); // No hint or actual number, so make assumptions - if (item_count < 1) - item_count = 20; + if (item_shown_target < 1) + item_shown_target = 20; for (int row_count = 1; row_count < 10; row_count++) { float height_ratio; // Get the best score for this number of rows float score = estimateRowScore(row_count, m_w, m_h - m_label_height, - aspect_ratio, item_count, &height_ratio); + aspect_ratio, item_shown_target, &height_ratio); if (score > max_score_so_far) { @@ -374,9 +377,16 @@ void DynamicRibbonWidget::buildInternalStructure() } } } - else + else // single-row { - // TODO: use the estimateRowScore logic to potentially downscale slightly the ribbon elements + // No hint or actual number, so make assumptions + if (item_shown_target < 1) + item_shown_target = 5; + + // Get the best score for this number of rows + estimateRowScore(1, m_w, m_h - m_label_height, + aspect_ratio, item_shown_target, &m_size_ratio, 0.68f /* min size ratio */); + //Log::info("DynamicRibbonWidget", "The size ratio of the best score is %f.", m_size_ratio); m_row_amount = 1; } @@ -411,8 +421,7 @@ void DynamicRibbonWidget::buildInternalStructure() // ---- determine column amount const float row_height = (float)(m_h - m_label_height)/(float)m_row_amount; float col_width = (float)(row_height * m_child_width / m_child_height); - if (m_multi_row) // not properly defined otherwise - col_width *= m_size_ratio; + col_width *= m_size_ratio; float target_width = col_width; @@ -473,6 +482,14 @@ void DynamicRibbonWidget::buildInternalStructure() ribbon->m_h = (int)(row_height); ribbon->m_type = WTYPE_RIBBON; + // Do partial vertical centering for single-row ribbon icons + if (!m_multi_row) + { + float vertical_shift_factor = (1.0f - m_size_ratio) / 5.0f; + int vertical_shift = (int)(vertical_shift_factor * (float)row_height); + ribbon->m_y += vertical_shift; + } + std::stringstream name; name << this->m_properties[PROP_ID] << "_row" << n; ribbon->m_properties[PROP_ID] = name.str(); @@ -489,8 +506,7 @@ void DynamicRibbonWidget::buildInternalStructure() // set size to get proper ratio (as most textures are saved scaled down to 256x256) icon->m_properties[PROP_WIDTH] = m_properties[PROP_CHILD_WIDTH]; icon->m_properties[PROP_HEIGHT] = m_properties[PROP_CHILD_HEIGHT]; - if (m_multi_row) // not properly defined otherwise - icon->setTargetSize(target_width, target_height); + icon->setTargetSize(target_width, target_height); // If we want each icon to have its own label, we must make it non-empty, otherwise // it will assume there is no label and none will be created (FIXME: that's ugly) diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.hpp b/src/guiengine/widgets/dynamic_ribbon_widget.hpp index c70a68f52ee..738ce58187b 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.hpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.hpp @@ -170,7 +170,8 @@ namespace GUIEngine /** Computes a score based on multiple icon properties (used to estimate the best number of rows) */ float estimateRowScore(const int rowCount, const int width, const int height, - const float iconAspectRatio, const int maxIcons, float* heightRatio); + const float iconAspectRatio, const int maxIcons, float* heightRatio, + float capSize = 0.5f); /** Removes all previously added contents icons, and re-adds them (calculating the new amount) */ void buildInternalStructure(); From e38f32a8c4681a513ab1afc41f859af859ffea6c Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Tue, 13 May 2025 18:59:51 +0200 Subject: [PATCH 732/830] Account more accurately for scrolling arrows size in dynamic ribbon widgets It ensures that the defined spacing between icons is respected when the scrolling arrows are huge, and when the scrolling arrows are quite small, it frees up some additional space to make icons larger. --- src/guiengine/widgets/dynamic_ribbon_widget.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.cpp b/src/guiengine/widgets/dynamic_ribbon_widget.cpp index e22825788f8..bb6fbe0c0a6 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.cpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.cpp @@ -455,7 +455,12 @@ void DynamicRibbonWidget::buildInternalStructure() m_left_widget->m_element->setVisible(true); m_right_widget->m_element->setVisible(true); // Reserve space for the scrolling arrows - target_width = target_width * 0.92f; + float arrows_width_ratio = 2.0f * ((float)m_arrows_w / col_width) / (float)m_col_amount; + if (arrows_width_ratio < 0.05f) + arrows_width_ratio = 0.05f; + if (arrows_width_ratio > 0.3f) + arrows_width_ratio = 0.3f; + target_width = target_width * (1.0f - arrows_width_ratio); } float target_height = target_width / aspect_ratio; From 6cb843e2782c29148c821ad2dec3aca7b9a7e0bf Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 13 May 2025 23:20:22 +0200 Subject: [PATCH 733/830] Try to fix switch build --- lib/dnsc/dns.c | 136 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 123 insertions(+), 13 deletions(-) diff --git a/lib/dnsc/dns.c b/lib/dnsc/dns.c index 39f0c6ee2a2..34915e892ff 100644 --- a/lib/dnsc/dns.c +++ b/lib/dnsc/dns.c @@ -4063,19 +4063,129 @@ static const struct dns_rrtype { size_t (*print)(); size_t (*cname)(); } dns_rrtypes[] = { - { DNS_T_A, "A", 0, &dns_a_parse, &dns_a_push, &dns_a_cmp, &dns_a_print, 0, }, - { DNS_T_AAAA, "AAAA", 0, &dns_aaaa_parse, &dns_aaaa_push, &dns_aaaa_cmp, &dns_aaaa_print, 0, }, - { DNS_T_MX, "MX", 0, &dns_mx_parse, &dns_mx_push, &dns_mx_cmp, &dns_mx_print, &dns_mx_cname, }, - { DNS_T_NS, "NS", 0, &dns_ns_parse, &dns_ns_push, &dns_ns_cmp, &dns_ns_print, &dns_ns_cname, }, - { DNS_T_CNAME, "CNAME", 0, &dns_cname_parse, &dns_cname_push, &dns_cname_cmp, &dns_cname_print, &dns_cname_cname, }, - { DNS_T_SOA, "SOA", 0, &dns_soa_parse, &dns_soa_push, &dns_soa_cmp, &dns_soa_print, 0, }, - { DNS_T_SRV, "SRV", 0, &dns_srv_parse, &dns_srv_push, &dns_srv_cmp, &dns_srv_print, &dns_srv_cname, }, - { DNS_T_OPT, "OPT", &dns_opt_initany, &dns_opt_parse, &dns_opt_push, &dns_opt_cmp, &dns_opt_print, 0, }, - { DNS_T_PTR, "PTR", 0, &dns_ptr_parse, &dns_ptr_push, &dns_ptr_cmp, &dns_ptr_print, &dns_ptr_cname, }, - { DNS_T_TXT, "TXT", &dns_txt_initany, &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0, }, - { DNS_T_SPF, "SPF", &dns_txt_initany, &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0, }, - { DNS_T_SSHFP, "SSHFP", 0, &dns_sshfp_parse, &dns_sshfp_push, &dns_sshfp_cmp, &dns_sshfp_print, 0, }, - { DNS_T_AXFR, "AXFR", 0, 0, 0, 0, 0, 0, }, + { + DNS_T_A, + "A", + 0, + (int (*)(void))&dns_a_parse, + (int (*)(void))&dns_a_push, + (int (*)(void))&dns_a_cmp, + (size_t (*)(void))&dns_a_print, + 0 + }, + { + DNS_T_AAAA, + "AAAA", + 0, + (int (*)(void))&dns_aaaa_parse, + (int (*)(void))&dns_aaaa_push, + (int (*)(void))&dns_aaaa_cmp, + (size_t (*)(void))&dns_aaaa_print, + 0 + }, + { + DNS_T_MX, + "MX", + 0, + (int (*)(void))&dns_mx_parse, + (int (*)(void))&dns_mx_push, + (int (*)(void))&dns_mx_cmp, + (size_t (*)(void))&dns_mx_print, + (size_t (*)(void))&dns_mx_cname + }, + { + DNS_T_NS, + "NS", + 0, + (int (*)(void))&dns_ns_parse, + (int (*)(void))&dns_ns_push, + (int (*)(void))&dns_ns_cmp, + (size_t (*)(void))&dns_ns_print, + (size_t (*)(void))&dns_ns_cname + }, + { + DNS_T_CNAME, + "CNAME", + 0, + (int (*)(void))&dns_cname_parse, + (int (*)(void))&dns_cname_push, + (int (*)(void))&dns_cname_cmp, + (size_t (*)(void))&dns_cname_print, + (size_t (*)(void))&dns_cname_cname + }, + { + DNS_T_SOA, + "SOA", + 0, + (int (*)(void))&dns_soa_parse, + (int (*)(void))&dns_soa_push, + (int (*)(void))&dns_soa_cmp, + (size_t (*)(void))&dns_soa_print, + 0 + }, + { + DNS_T_SRV, + "SRV", + 0, + (int (*)(void))&dns_srv_parse, + (int (*)(void))&dns_srv_push, + (int (*)(void))&dns_srv_cmp, + (size_t (*)(void))&dns_srv_print, + (size_t (*)(void))&dns_srv_cname + }, + { + DNS_T_OPT, + "OPT", + &dns_opt_initany, + (int (*)(void))&dns_opt_parse, + (int (*)(void))&dns_opt_push, + (int (*)(void))&dns_opt_cmp, + (size_t (*)(void))&dns_opt_print, + 0 + }, + { + DNS_T_PTR, + "PTR", + 0, + (int (*)(void))&dns_ptr_parse, + (int (*)(void))&dns_ptr_push, + (int (*)(void))&dns_ptr_cmp, + (size_t (*)(void))&dns_ptr_print, + (size_t (*)(void))&dns_ptr_cname + }, + { + DNS_T_TXT, + "TXT", + &dns_txt_initany, + (int (*)(void))&dns_txt_parse, + (int (*)(void))&dns_txt_push, + (int (*)(void))&dns_txt_cmp, + (size_t (*)(void))&dns_txt_print, + 0 + }, + { + DNS_T_SPF, + "SPF", + &dns_txt_initany, + (int (*)(void))&dns_txt_parse, + (int (*)(void))&dns_txt_push, + (int (*)(void))&dns_txt_cmp, + (size_t (*)(void))&dns_txt_print, + 0 + }, + { + DNS_T_SSHFP, + "SSHFP", + 0, + (int (*)(void))&dns_sshfp_parse, + (int (*)(void))&dns_sshfp_push, + (int (*)(void))&dns_sshfp_cmp, + (size_t (*)(void))&dns_sshfp_print, + 0 + }, + { + DNS_T_AXFR, "AXFR", 0, 0, 0, 0, 0, 0 + } }; /* dns_rrtypes[] */ static const struct dns_rrtype *dns_rrtype(enum dns_type type) { From 68c395a685456e37709426b71d5f2c1e5edbe4a4 Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 13 May 2025 23:51:15 +0200 Subject: [PATCH 734/830] Another try to fix switch build --- lib/dnsc/CMakeLists.txt | 6 ++ lib/dnsc/dns.c | 136 ++++------------------------------------ 2 files changed, 19 insertions(+), 123 deletions(-) diff --git a/lib/dnsc/CMakeLists.txt b/lib/dnsc/CMakeLists.txt index fd966b52a70..ba94fa55f0e 100644 --- a/lib/dnsc/CMakeLists.txt +++ b/lib/dnsc/CMakeLists.txt @@ -1 +1,7 @@ add_library(dnsc STATIC dns.c) + +set_target_properties(dnsc PROPERTIES + C_STANDARD 99 + C_STANDARD_REQUIRED ON + C_EXTENSIONS OFF +) diff --git a/lib/dnsc/dns.c b/lib/dnsc/dns.c index 34915e892ff..39f0c6ee2a2 100644 --- a/lib/dnsc/dns.c +++ b/lib/dnsc/dns.c @@ -4063,129 +4063,19 @@ static const struct dns_rrtype { size_t (*print)(); size_t (*cname)(); } dns_rrtypes[] = { - { - DNS_T_A, - "A", - 0, - (int (*)(void))&dns_a_parse, - (int (*)(void))&dns_a_push, - (int (*)(void))&dns_a_cmp, - (size_t (*)(void))&dns_a_print, - 0 - }, - { - DNS_T_AAAA, - "AAAA", - 0, - (int (*)(void))&dns_aaaa_parse, - (int (*)(void))&dns_aaaa_push, - (int (*)(void))&dns_aaaa_cmp, - (size_t (*)(void))&dns_aaaa_print, - 0 - }, - { - DNS_T_MX, - "MX", - 0, - (int (*)(void))&dns_mx_parse, - (int (*)(void))&dns_mx_push, - (int (*)(void))&dns_mx_cmp, - (size_t (*)(void))&dns_mx_print, - (size_t (*)(void))&dns_mx_cname - }, - { - DNS_T_NS, - "NS", - 0, - (int (*)(void))&dns_ns_parse, - (int (*)(void))&dns_ns_push, - (int (*)(void))&dns_ns_cmp, - (size_t (*)(void))&dns_ns_print, - (size_t (*)(void))&dns_ns_cname - }, - { - DNS_T_CNAME, - "CNAME", - 0, - (int (*)(void))&dns_cname_parse, - (int (*)(void))&dns_cname_push, - (int (*)(void))&dns_cname_cmp, - (size_t (*)(void))&dns_cname_print, - (size_t (*)(void))&dns_cname_cname - }, - { - DNS_T_SOA, - "SOA", - 0, - (int (*)(void))&dns_soa_parse, - (int (*)(void))&dns_soa_push, - (int (*)(void))&dns_soa_cmp, - (size_t (*)(void))&dns_soa_print, - 0 - }, - { - DNS_T_SRV, - "SRV", - 0, - (int (*)(void))&dns_srv_parse, - (int (*)(void))&dns_srv_push, - (int (*)(void))&dns_srv_cmp, - (size_t (*)(void))&dns_srv_print, - (size_t (*)(void))&dns_srv_cname - }, - { - DNS_T_OPT, - "OPT", - &dns_opt_initany, - (int (*)(void))&dns_opt_parse, - (int (*)(void))&dns_opt_push, - (int (*)(void))&dns_opt_cmp, - (size_t (*)(void))&dns_opt_print, - 0 - }, - { - DNS_T_PTR, - "PTR", - 0, - (int (*)(void))&dns_ptr_parse, - (int (*)(void))&dns_ptr_push, - (int (*)(void))&dns_ptr_cmp, - (size_t (*)(void))&dns_ptr_print, - (size_t (*)(void))&dns_ptr_cname - }, - { - DNS_T_TXT, - "TXT", - &dns_txt_initany, - (int (*)(void))&dns_txt_parse, - (int (*)(void))&dns_txt_push, - (int (*)(void))&dns_txt_cmp, - (size_t (*)(void))&dns_txt_print, - 0 - }, - { - DNS_T_SPF, - "SPF", - &dns_txt_initany, - (int (*)(void))&dns_txt_parse, - (int (*)(void))&dns_txt_push, - (int (*)(void))&dns_txt_cmp, - (size_t (*)(void))&dns_txt_print, - 0 - }, - { - DNS_T_SSHFP, - "SSHFP", - 0, - (int (*)(void))&dns_sshfp_parse, - (int (*)(void))&dns_sshfp_push, - (int (*)(void))&dns_sshfp_cmp, - (size_t (*)(void))&dns_sshfp_print, - 0 - }, - { - DNS_T_AXFR, "AXFR", 0, 0, 0, 0, 0, 0 - } + { DNS_T_A, "A", 0, &dns_a_parse, &dns_a_push, &dns_a_cmp, &dns_a_print, 0, }, + { DNS_T_AAAA, "AAAA", 0, &dns_aaaa_parse, &dns_aaaa_push, &dns_aaaa_cmp, &dns_aaaa_print, 0, }, + { DNS_T_MX, "MX", 0, &dns_mx_parse, &dns_mx_push, &dns_mx_cmp, &dns_mx_print, &dns_mx_cname, }, + { DNS_T_NS, "NS", 0, &dns_ns_parse, &dns_ns_push, &dns_ns_cmp, &dns_ns_print, &dns_ns_cname, }, + { DNS_T_CNAME, "CNAME", 0, &dns_cname_parse, &dns_cname_push, &dns_cname_cmp, &dns_cname_print, &dns_cname_cname, }, + { DNS_T_SOA, "SOA", 0, &dns_soa_parse, &dns_soa_push, &dns_soa_cmp, &dns_soa_print, 0, }, + { DNS_T_SRV, "SRV", 0, &dns_srv_parse, &dns_srv_push, &dns_srv_cmp, &dns_srv_print, &dns_srv_cname, }, + { DNS_T_OPT, "OPT", &dns_opt_initany, &dns_opt_parse, &dns_opt_push, &dns_opt_cmp, &dns_opt_print, 0, }, + { DNS_T_PTR, "PTR", 0, &dns_ptr_parse, &dns_ptr_push, &dns_ptr_cmp, &dns_ptr_print, &dns_ptr_cname, }, + { DNS_T_TXT, "TXT", &dns_txt_initany, &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0, }, + { DNS_T_SPF, "SPF", &dns_txt_initany, &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0, }, + { DNS_T_SSHFP, "SSHFP", 0, &dns_sshfp_parse, &dns_sshfp_push, &dns_sshfp_cmp, &dns_sshfp_print, 0, }, + { DNS_T_AXFR, "AXFR", 0, 0, 0, 0, 0, 0, }, }; /* dns_rrtypes[] */ static const struct dns_rrtype *dns_rrtype(enum dns_type type) { From 184c80138faf5232c33ff99ffe7706e821be70c2 Mon Sep 17 00:00:00 2001 From: Deve Date: Thu, 15 May 2025 17:54:28 +0200 Subject: [PATCH 735/830] Fixed cmake 4.0 warnings --- CMakeLists.txt | 2 +- lib/angelscript/projects/cmake/CMakeLists.txt | 2 +- lib/enet/CMakeLists.txt | 2 +- lib/graphics_utils/CMakeLists.txt | 2 +- lib/libsquish/CMakeLists.txt | 2 +- lib/mcpp/CMakeLists.txt | 2 +- lib/tinygettext/CMakeLists.txt | 2 +- lib/wiiuse/CMakeLists.txt | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7037c35609b..d7cbe73b7fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.6.0) +cmake_minimum_required(VERSION 3.6.0...4.0) # root CMakeLists for the SuperTuxKart project project(SuperTuxKart) diff --git a/lib/angelscript/projects/cmake/CMakeLists.txt b/lib/angelscript/projects/cmake/CMakeLists.txt index 42883d5e3ab..baa26832c6a 100644 --- a/lib/angelscript/projects/cmake/CMakeLists.txt +++ b/lib/angelscript/projects/cmake/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.5...4.0) # STK Fix llvm mingw crashes if (MINGW AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_SIZEOF_VOID_P EQUAL 4) diff --git a/lib/enet/CMakeLists.txt b/lib/enet/CMakeLists.txt index 41cd842f5e8..860ad5cc313 100644 --- a/lib/enet/CMakeLists.txt +++ b/lib/enet/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.6.0) +cmake_minimum_required(VERSION 3.6.0...4.0) project(enet) diff --git a/lib/graphics_utils/CMakeLists.txt b/lib/graphics_utils/CMakeLists.txt index 11230060a02..7e6d558e602 100644 --- a/lib/graphics_utils/CMakeLists.txt +++ b/lib/graphics_utils/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.6.0) +cmake_minimum_required(VERSION 3.6.0...4.0) include_directories("${PROJECT_SOURCE_DIR}/lib/simd_wrapper") if (UNIX OR MINGW) add_definitions(-O3) diff --git a/lib/libsquish/CMakeLists.txt b/lib/libsquish/CMakeLists.txt index 6b5541e38fe..f3673a4a6e6 100644 --- a/lib/libsquish/CMakeLists.txt +++ b/lib/libsquish/CMakeLists.txt @@ -8,7 +8,7 @@ # Unix and VS: SSE2 support is enabled by default # use BUILD_SQUISH_WITH_SSE2 and BUILD_SQUISH_WITH_ALTIVEC to override -CMAKE_MINIMUM_REQUIRED(VERSION 3.6.0) +CMAKE_MINIMUM_REQUIRED(VERSION 3.6.0...4.0) OPTION(BUILD_SQUISH_WITH_OPENMP "Build with OpenMP." OFF) diff --git a/lib/mcpp/CMakeLists.txt b/lib/mcpp/CMakeLists.txt index d73810c8eec..acd1c7db6b7 100644 --- a/lib/mcpp/CMakeLists.txt +++ b/lib/mcpp/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.6.0) +cmake_minimum_required(VERSION 3.6.0...4.0) if (UNIX OR MINGW) add_definitions(-O3) if (APPLE) diff --git a/lib/tinygettext/CMakeLists.txt b/lib/tinygettext/CMakeLists.txt index 52d581fefa2..3bbbc322e21 100644 --- a/lib/tinygettext/CMakeLists.txt +++ b/lib/tinygettext/CMakeLists.txt @@ -39,7 +39,7 @@ set(VERSION "0.1.0") ### CMake configuration -cmake_minimum_required(VERSION 3.6.0) +cmake_minimum_required(VERSION 3.6.0...4.0) if(COMMAND cmake_policy) CMAKE_POLICY(SET CMP0003 NEW) endif(COMMAND cmake_policy) diff --git a/lib/wiiuse/CMakeLists.txt b/lib/wiiuse/CMakeLists.txt index 61160361d6b..9a2fb5339c5 100644 --- a/lib/wiiuse/CMakeLists.txt +++ b/lib/wiiuse/CMakeLists.txt @@ -2,7 +2,7 @@ # http://academic.cleardefinition.com/ # Iowa State University HCI Graduate Program/VRAC -cmake_minimum_required(VERSION 3.6.0) +cmake_minimum_required(VERSION 3.6.0...4.0) # Set package properties project(WiiUse) From 12c194d337b6d49166eabb2131855555b0212c61 Mon Sep 17 00:00:00 2001 From: Deve Date: Thu, 15 May 2025 22:31:06 +0200 Subject: [PATCH 736/830] Fixed DEBUG flag for Visual Studio and also add missing libraries for MinGW build. --- CMakeLists.txt | 11 +++++------ cmake/Toolchain-mingw-64bit.cmake | 2 +- cmake/Toolchain-mingw.cmake | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d7cbe73b7fd..bb5e81cf8ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.6.0...4.0) +cmake_minimum_required(VERSION 3.12...4.0) # root CMakeLists for the SuperTuxKart project project(SuperTuxKart) @@ -525,8 +525,7 @@ endif() if(MSVC) # VS will automatically add NDEBUG for release mode, but only _DEBUG in debug mode. # Since STK uses DEBUG, this is added for debug compilation only: - cmake_policy(SET CMP0043 OLD) - set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUG) + add_compile_definitions($<$:DEBUG>) else() # All non VS generators used create only a single compile mode, so # compile flags can be simplye be added @@ -853,15 +852,15 @@ if(MINGW) if (NOT CMAKE_BUILD_TYPE MATCHES Debug) target_link_libraries(supertuxkart -mwindows) endif() - find_library(LIBGCC NAMES "libgcc_s_dw2-1.dll" "libgcc_s_sjlj-1.dll" "libgcc_s_seh-1.dll" PATHS ${CMAKE_FIND_ROOT_PATH}) + find_file(LIBGCC NAMES "libgcc_s_dw2-1.dll" "libgcc_s_sjlj-1.dll" "libgcc_s_seh-1.dll" PATHS ${CMAKE_FIND_ROOT_PATH}) if (LIBGCC) file(COPY ${LIBGCC} DESTINATION ${CMAKE_BINARY_DIR}/bin/) endif() - find_library(LIBSTDCPP NAMES "libstdc++-6.dll" PATHS ${CMAKE_FIND_ROOT_PATH}) + find_file(LIBSTDCPP NAMES "libstdc++-6.dll" PATHS ${CMAKE_FIND_ROOT_PATH}) if (LIBSTDCPP) file(COPY ${LIBSTDCPP} DESTINATION ${CMAKE_BINARY_DIR}/bin/) endif() - find_library(LIBPTHREAD NAMES "winpthread-1.dll" "libwinpthread-1.dll" "pthreadGC2.dll" PATHS ${CMAKE_FIND_ROOT_PATH}) + find_file(LIBPTHREAD NAMES "winpthread-1.dll" "libwinpthread-1.dll" "pthreadGC2.dll" PATHS ${CMAKE_FIND_ROOT_PATH}) if(LIBPTHREAD) file(COPY ${LIBPTHREAD} DESTINATION ${CMAKE_BINARY_DIR}/bin/) endif() diff --git a/cmake/Toolchain-mingw-64bit.cmake b/cmake/Toolchain-mingw-64bit.cmake index c0be9b5ed49..73dab973463 100644 --- a/cmake/Toolchain-mingw-64bit.cmake +++ b/cmake/Toolchain-mingw-64bit.cmake @@ -13,7 +13,7 @@ SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) execute_process(COMMAND sh -c "ls /usr/lib/gcc/x86_64-w64-mingw32/ | grep posix | tr -d '\n'" OUTPUT_VARIABLE MINGW_DEPS_FOLDER) # here is the target environment located -SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32 /usr/lib/gcc/x86_64-w64-mingw32/${MINGW_DEPS_FOLDER}/ ${PROJECT_SOURCE_DIR}/dependencies-win-x86_64) +SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32 /usr/x86_64-w64-mingw32/lib /usr/lib/gcc/x86_64-w64-mingw32/${MINGW_DEPS_FOLDER}/ ${PROJECT_SOURCE_DIR}/dependencies-win-x86_64) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search diff --git a/cmake/Toolchain-mingw.cmake b/cmake/Toolchain-mingw.cmake index 6184ba7e1ed..47e35d26d4e 100644 --- a/cmake/Toolchain-mingw.cmake +++ b/cmake/Toolchain-mingw.cmake @@ -13,7 +13,7 @@ SET(CMAKE_RC_COMPILER i686-w64-mingw32-windres) execute_process(COMMAND sh -c "ls /usr/lib/gcc/i686-w64-mingw32/ | grep posix | tr -d '\n'" OUTPUT_VARIABLE MINGW_DEPS_FOLDER) # here is the target environment located -SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32 /usr/lib/gcc/i686-w64-mingw32/${MINGW_DEPS_FOLDER}/ ${PROJECT_SOURCE_DIR}/dependencies-win-i686) +SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32 /usr/i686-w64-mingw32/lib /usr/lib/gcc/i686-w64-mingw32/${MINGW_DEPS_FOLDER}/ ${PROJECT_SOURCE_DIR}/dependencies-win-i686) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search From f34d98d071a5f811d789ee58501349b4f7fb0a07 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 16 May 2025 22:11:14 +0400 Subject: [PATCH 737/830] Try to eliminate log crash once again --- src/network/event.hpp | 4 ++++ src/network/protocol_manager.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/network/event.hpp b/src/network/event.hpp index 7b56d9a9452..2dab2701c81 100644 --- a/src/network/event.hpp +++ b/src/network/event.hpp @@ -103,6 +103,10 @@ class Event /** Returns the peer of this event. */ STKPeer* getPeer() const { return m_peer.get(); } // ------------------------------------------------------------------------ + /** \brief Checks if data is not nullptr + */ + bool hasValidData() const { return m_data != nullptr; } + // ------------------------------------------------------------------------ /** \brief Get a const reference to the received data. * This is empty for events like connection or disconnections. */ diff --git a/src/network/protocol_manager.cpp b/src/network/protocol_manager.cpp index 708a4208693..61d1a258d10 100644 --- a/src/network/protocol_manager.cpp +++ b/src/network/protocol_manager.cpp @@ -454,7 +454,7 @@ void ProtocolManager::asynchronousUpdate() Log::error("ProtocolManager", "Asynchronous event " "error from %s: %s", name.c_str(), e.what()); - if (*i != nullptr) + if (*i != nullptr && (*i)->hasValidData()) { // kimden: make sure you don't cause it to be nullptr yourself Log::error("ProtocolManager", (*i)->data().getLogMessage().c_str()); From 4e1554db5d07dfa58be90d53030556a92df27e4a Mon Sep 17 00:00:00 2001 From: Deve Date: Sun, 18 May 2025 11:22:00 +0200 Subject: [PATCH 738/830] Try to fix macos build --- .github/workflows/apple.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml index 7ba161194b7..311cfd2ced4 100644 --- a/.github/workflows/apple.yml +++ b/.github/workflows/apple.yml @@ -152,6 +152,8 @@ jobs: lipo -create ./macosx-x86_64/supertuxkart.app/Contents/MacOS/supertuxkart ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -output ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart chmod 755 ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart install_name_tool -change libcurl.4.dylib @rpath/libcurl.4.dylib ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart + install_name_tool -delete_rpath @loader_path/Frameworks ./dependencies-macosx/lib/libSDL2.dylib + install_name_tool -delete_rpath @executable_path/Frameworks ./dependencies-macosx/lib/libSDL2.dylib dylibbundler -od -b -x ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -d ./macosx-arm64/supertuxkart.app/Contents/libs/ -p @executable_path/../libs/ -s ./dependencies-macosx/lib -ns # We use SDL_Vulkan_LoadLibrary for 10.9 compatibility, so otool -L supertuxkart has no libMoltenVK.dylib cp ./dependencies-macosx/lib/libMoltenVK.dylib ./macosx-arm64/supertuxkart.app/Contents/libs/ From 536ab510188c8c1d23c9132a7014745fa3fbf125 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 12 May 2025 01:59:41 +0400 Subject: [PATCH 739/830] Simplify CM, initial impl of /as For now too many bugs --- src/network/protocols/command_manager.cpp | 895 +++++++----------- src/network/protocols/command_manager.hpp | 23 +- src/network/protocols/command_permissions.hpp | 51 +- src/network/stk_peer.hpp | 4 +- 4 files changed, 398 insertions(+), 575 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 45d330ac22e..7a53da78983 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -58,6 +58,8 @@ #include #include +// TODO: kimden: should decorators use acting_peer? + namespace { static const std::string g_addon_prefix = "addon_"; @@ -164,12 +166,23 @@ EnumExtendedReader CommandManager::state_scope_reader({ EnumExtendedReader CommandManager::permission_reader({ {"PE_NONE", PE_NONE}, + {"UU_SPECTATOR", UU_SPECTATOR}, + {"UU_USUAL", UU_USUAL}, + {"UU_CROWNED", UU_CROWNED}, + {"UU_SINGLE", UU_SINGLE}, + {"UU_HAMMER", UU_HAMMER}, + {"UU_MANIPULATOR", UU_MANIPULATOR}, + {"UU_CONSOLE", UU_CONSOLE}, {"PE_SPECTATOR", PE_SPECTATOR}, {"PE_USUAL", PE_USUAL}, {"PE_CROWNED", PE_CROWNED}, {"PE_SINGLE", PE_SINGLE}, {"PE_HAMMER", PE_HAMMER}, + {"PE_MANIPULATOR", PE_MANIPULATOR}, {"PE_CONSOLE", PE_CONSOLE}, + {"UU_OWN_COMMANDS", UU_OWN_COMMANDS}, + {"UU_OTHERS_COMMANDS", UU_OTHERS_COMMANDS}, + {"PE_ALLOW_ANYONE", PE_ALLOW_ANYONE}, {"PE_VOTED_SPECTATOR", PE_VOTED_SPECTATOR}, {"PE_VOTED_NORMAL", PE_VOTED_NORMAL}, {"PE_VOTED", PE_VOTED}, @@ -264,6 +277,8 @@ CommandManager::Command::Command(std::string name, m_mode_scope(mode_scope), m_state_scope(state_scope), m_omit_name(false) { + // Handling players who are allowed to run for anyone in any case + m_permissions |= UU_OTHERS_COMMANDS; } // Command::Command(5) // ======================================================================== @@ -466,9 +481,9 @@ void CommandManager::initCommands() std::shared_ptr kick_command = mp["kick"].lock(); if (kick_command) { if (getSettings()->hasKicksAllowed()) - kick_command->m_permissions |= PE_CROWNED; + kick_command->m_permissions |= UU_CROWNED; else - kick_command->m_permissions &= ~PE_CROWNED; + kick_command->m_permissions &= ~UU_CROWNED; } applyFunctionIfPossible("commands", &CM::process_commands); @@ -505,6 +520,7 @@ void CommandManager::initCommands() applyFunctionIfPossible("public", &CM::process_public); applyFunctionIfPossible("record", &CM::process_record); applyFunctionIfPossible("power", &CM::process_power); + applyFunctionIfPossible("power2", &CM::process_power); applyFunctionIfPossible("length", &CM::process_length); applyFunctionIfPossible("length clear", &CM::process_length_clear); applyFunctionIfPossible("length =", &CM::process_length_fixed); @@ -563,6 +579,7 @@ void CommandManager::initCommands() applyFunctionIfPossible("lobby", &CM::process_lobby); applyFunctionIfPossible("init", &CM::process_init); applyFunctionIfPossible("vote", &CM::special); + applyFunctionIfPossible("as", &CM::special); applyFunctionIfPossible("mimiz", &CM::process_mimiz); applyFunctionIfPossible("test", &CM::process_test); applyFunctionIfPossible("test test2", &CM::process_test); @@ -673,11 +690,13 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) std::string language; data.decodeString(&language); - Context context(event, peer); + Context context(getLobby(), event, peer); auto& argv = context.m_argv; auto& cmd = context.m_cmd; auto& permissions = context.m_user_permissions; auto& voting = context.m_voting; + auto& target_peer = context.m_target_peer; + std::shared_ptr target_peer_strong = context.m_target_peer.lock(); data.decodeString(&cmd); argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); @@ -692,12 +711,37 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) if (peer->hasPlayerProfiles()) username = peer->getMainName(); + if (argv[0] == "as") + { + std::shared_ptr new_target_peer = {}; + if (argv.size() >= 2) + { + if (hasTypo(peer, peer, voting, argv, cmd, 1, getFixer(TFT_PRESENT_USERS), 3, false, false)) + return; + + new_target_peer = STKHost::get()->findPeerByName(StringUtils::utf8ToWide(argv[1])); + } + + if (!new_target_peer || argv.size() <= 2) + { + context.say("Usage: /as (username) (another command with arguments)"); + return; + } + target_peer = new_target_peer; + target_peer_strong = new_target_peer; + std::reverse(argv.begin(), argv.end()); + argv.pop_back(); + argv.pop_back(); + std::reverse(argv.begin(), argv.end()); + CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + } + if (argv[0] == "vote") { if (argv.size() == 1 || argv[1] == "vote") { // kimden: all error strings in this function should be done in error(context) way - getLobby()->sendStringToPeer(peer, "Usage: /vote (a command with arguments)"); + context.say("Usage: /vote (a command with arguments)"); return; } std::reverse(argv.begin(), argv.end()); @@ -729,7 +773,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) msg = "Pick one of " + std::to_string(-1 + (int)m_user_command_replacements[username].size()) + " options using /1, etc., or use /0, or type a different command"; - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); return; } } @@ -752,7 +796,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) } else { - if (hasTypo(peer, voting, argv, cmd, idx, current_command->m_stf_subcommand_names, 3, false, false)) + if (hasTypo(target_peer_strong, peer, voting, argv, cmd, idx, current_command->m_stf_subcommand_names, 3, false, false)) return; auto command_iterator = current_command->m_name_to_subcommand.find(argv[idx]); command = command_iterator->second.lock(); @@ -761,21 +805,18 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) if (!command) { // todo change message - getLobby()->sendStringToPeer(peer, - "There is no such command but there should be. Very strange. Please report it."); + context.say("There is no such command but there should be. Very strange. Please report it."); return; } else if (!isAvailable(command)) { - getLobby()->sendStringToPeer(peer, - "You don't have permissions to " + action + " this command"); + context.say("You don't have permissions to " + action + " this command"); return; } int mask = (permissions & command->m_permissions); if (mask == 0) { - getLobby()->sendStringToPeer(peer, - "You don't have permissions to " + action + " this command"); + context.say("You don't have permissions to " + action + " this command"); return; } int mask_without_voting = (mask & ~PE_VOTED); @@ -828,7 +869,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) "Command \"/%s\" has been successfully voted", new_cmd.c_str()); getLobby()->sendStringToAllPeers(msg2); - Context new_context(event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); + Context new_context(getLobby(), event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); execute(executed_command, new_context); } } @@ -856,16 +897,13 @@ bool CommandManager::isAvailable(std::shared_ptr c) void CommandManager::vote(Context& context, std::string category, std::string value) { - auto peer = context.m_peer.lock(); - auto command = context.m_command.lock(); - if (!peer || !command) - { - error(context, true); - return; - } - if (!peer->hasPlayerProfiles()) + auto peer = context.peer(); + auto acting_peer = context.actingPeer(); + auto command = context.command(); + + if (!acting_peer->hasPlayerProfiles()) return; - std::string username = peer->getMainName(); + std::string username = acting_peer->getMainName(); auto& votable = m_votables[command->m_prefix_name]; bool neededCheck = votable.needsCheck(); votable.castVote(username, category, value); @@ -901,7 +939,7 @@ void CommandManager::update() } // We don't know the event though it is only needed in // ServerLobby::startSelection where it is nullptr when they vote - Context new_context(nullptr, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); + Context new_context(getLobby(), nullptr, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); execute(command, new_context); } } @@ -921,7 +959,7 @@ void CommandManager::error(Context& context, bool is_error) return; } if (!peer) { - Log::error("CommandManager", "CM::error: cannot load peer"); + Log::error("CommandManager", "CM::error: cannot load peer to send error"); return; } msg = command->getUsage(); @@ -932,7 +970,7 @@ void CommandManager::error(Context& context, bool is_error) if (is_error) msg += "\n/!\\ Please report this error to the server owner"; - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); } // error // ======================================================================== @@ -940,7 +978,21 @@ void CommandManager::execute(std::shared_ptr command, Context& context) { m_current_argv = context.m_argv; context.m_command = command; - (this->*(command->m_action))(context); + try + { + (this->*(command->m_action))(context); + } + catch (std::exception& ex) + { + // auto peer = context.m_peer.lock(); + error(context, true); + + // // kimden: make error message better + add log + // context.say(StringUtils::insertValues( + // "An error happened: %s", + // ex.what() + // )); + } m_current_argv = {}; } // execute // ======================================================================== @@ -948,15 +1000,12 @@ void CommandManager::execute(std::shared_ptr command, Context& context) void CommandManager::process_help(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto acting_peer = context.actingPeer(); + auto peer = context.peer(); + std::shared_ptr command = m_root_command; for (int i = 1; i < (int)argv.size(); ++i) { - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, i, command->m_stf_subcommand_names, 3, false, false)) + if (hasTypo(acting_peer, peer, context.m_voting, context.m_argv, context.m_cmd, i, command->m_stf_subcommand_names, 3, false, false)) return; auto ptr = command->m_name_to_subcommand[argv[i]].lock(); if (ptr) @@ -971,20 +1020,14 @@ void CommandManager::process_help(Context& context) error(context); return; } - getLobby()->sendStringToPeer(peer, command->getHelp()); + context.say(command->getHelp()); } // process_help // ======================================================================== void CommandManager::process_text(Context& context) { std::string response; - auto peer = context.m_peer.lock(); - auto command = context.m_command.lock(); - if (!peer || !command) - { - error(context, true); - return; - } + auto command = context.command(); auto it = m_text_response.find(command->getFullName()); if (it == m_text_response.end()) response = StringUtils::insertValues( @@ -992,20 +1035,15 @@ void CommandManager::process_text(Context& context) command->getFullName().c_str()); else response = it->second; - getLobby()->sendStringToPeer(peer, response); + context.say(response); } // process_text // ======================================================================== void CommandManager::process_file(Context& context) { std::string response; - auto peer = context.m_peer.lock(); - auto command = context.m_command.lock(); - if (!peer || !command) - { - error(context, true); - return; - } + auto command = context.command(); + auto it = m_file_resources.find(command->getFullName()); if (it == m_file_resources.end()) response = StringUtils::insertValues( @@ -1013,20 +1051,16 @@ void CommandManager::process_file(Context& context) command->getFullName().c_str()); else response = it->second.get(); - getLobby()->sendStringToPeer(peer, response); + context.say(response); } // process_text // ======================================================================== void CommandManager::process_auth(Context& context) { std::string response; - auto peer = context.m_peer.lock(); - auto command = context.m_command.lock(); - if (!peer || !command) - { - error(context, true); - return; - } + auto acting_peer = context.actingPeer(); + auto command = context.command(); + auto it = m_auth_resources.find(command->getFullName()); if (it == m_auth_resources.end()) response = StringUtils::insertValues( @@ -1034,7 +1068,7 @@ void CommandManager::process_auth(Context& context) command->getFullName().c_str()); else { - auto profile = peer->getMainProfile(); + auto profile = acting_peer->getMainProfile(); std::string username = StringUtils::wideToUtf8(profile->getName()); int online_id = profile->getOnlineId(); if (online_id == 0) @@ -1043,24 +1077,21 @@ void CommandManager::process_auth(Context& context) else response = it->second.get(username, online_id); } - getLobby()->sendStringToPeer(peer, response); + context.say(response); } // process_text // ======================================================================== void CommandManager::process_commands(Context& context) { std::string result; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto acting_peer = context.actingPeer(); + auto peer = context.peer(); + auto& argv = context.m_argv; std::shared_ptr command = m_root_command; bool valid_prefix = true; for (int i = 1; i < (int)argv.size(); ++i) { - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, i, command->m_stf_subcommand_names, 3, false, false)) + if (hasTypo(acting_peer, peer, context.m_voting, context.m_argv, context.m_cmd, i, command->m_stf_subcommand_names, 3, false, false)) return; auto ptr = command->m_name_to_subcommand[argv[i]].lock(); if (!ptr) @@ -1078,7 +1109,7 @@ void CommandManager::process_commands(Context& context) } if (!valid_prefix) { - getLobby()->sendStringToPeer(peer, "There are no available commands with such prefix"); + context.say("There are no available commands with such prefix"); return; } result = (command == m_root_command ? "Available commands" @@ -1111,19 +1142,14 @@ void CommandManager::process_commands(Context& context) } if (had_any_subcommands) result += "\n* has subcommands"; - getLobby()->sendStringToPeer(peer, result); + context.say(result); } // process_commands // ======================================================================== void CommandManager::process_replay(Context& context) { const auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + if (getSettings()->isRecordingReplays()) { bool current_state = getSettings()->hasConsentOnReplays(); @@ -1140,7 +1166,7 @@ void CommandManager::process_replay(Context& context) } else { - getLobby()->sendStringToPeer(peer, "This server doesn't allow recording replays"); + context.say("This server doesn't allow recording replays"); } } // process_replay // ======================================================================== @@ -1162,12 +1188,6 @@ void CommandManager::process_start(Context& context) void CommandManager::process_config(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } int difficulty = getLobby()->getDifficulty(); int mode = getLobby()->getGameMode(); bool goal_target = (getGameSetupFromCtx()->hasExtraServerInfo() ? getLobby()->isSoccerGoalTarget() : false); @@ -1186,16 +1206,16 @@ void CommandManager::process_config(Context& context) msg += get_first_if_exists(g_aux_goal_aliases[goal_target ? 1 : 0]); if (!getSettings()->isServerConfigurable()) msg += " (not configurable)"; - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); } // process_config // ======================================================================== void CommandManager::process_config_assign(Context& context) { - auto peer = context.m_peer.lock(); + auto acting_peer = context.actingPeer(); if (!getSettings()->isServerConfigurable()) { - getLobby()->sendStringToPeer(peer, "Server is not configurable, this command cannot be invoked."); + context.say("Server is not configurable, this command cannot be invoked."); return; } const auto& argv = context.m_argv; @@ -1243,8 +1263,7 @@ void CommandManager::process_config_assign(Context& context) if (!getSettings()->isDifficultyAvailable(difficulty) || !getSettings()->isModeAvailable(mode)) { - getLobby()->sendStringToPeer(peer, - "Mode or difficulty are not permitted on this server"); + context.say("Mode or difficulty are not permitted on this server"); return; } if (context.m_voting) @@ -1259,7 +1278,7 @@ void CommandManager::process_config_assign(Context& context) vote(context, "config target", g_aux_goal_aliases[goal_target ? 1 : 0][0]); return; } - getLobby()->handleServerConfiguration(peer, difficulty, mode, goal_target); + getLobby()->handleServerConfiguration(acting_peer, difficulty, mode, goal_target); } // process_config_assign // ======================================================================== @@ -1267,25 +1286,20 @@ void CommandManager::process_spectate(Context& context) { std::string response = ""; auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto acting_peer = context.actingPeer(); if (getSettings()->isLegacyGPMode() || !getSettings()->isLivePlayers()) response = "Server doesn't support spectating"; if (!response.empty()) { - getLobby()->sendStringToPeer(peer, response); + context.say(response); return; } if (argv.size() == 1) { - if (peer->isCommandSpectator()) + if (acting_peer->isCommandSpectator()) argv.push_back("0"); else argv.push_back("1"); @@ -1301,17 +1315,17 @@ void CommandManager::process_spectate(Context& context) if (value >= 1) { if (getLobby()->isChildProcess() && - getLobby()->isClientServerHost(peer)) + getLobby()->isClientServerHost(acting_peer)) { - getLobby()->sendStringToPeer(peer, "Graphical client server cannot spectate"); + context.say("Graphical client server cannot spectate"); return; } AlwaysSpectateMode type = (value == 2 ? ASM_COMMAND_ABSENT : ASM_COMMAND); - getCrownManager()->setSpectateModeProperly(peer, type); + getCrownManager()->setSpectateModeProperly(acting_peer, type); } else { - getCrownManager()->setSpectateModeProperly(peer, ASM_NONE); + getCrownManager()->setSpectateModeProperly(acting_peer, ASM_NONE); } getLobby()->updateServerOwner(true); getLobby()->updatePlayerList(); @@ -1321,12 +1335,8 @@ void CommandManager::process_spectate(Context& context) void CommandManager::process_addons(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto acting_peer = context.actingPeer(); + bool more = (argv[0] == "moreaddons"); bool more_own = (argv[0] == "getaddons"); bool apply_filters = false; @@ -1357,7 +1367,7 @@ void CommandManager::process_addons(Context& context) { if (!p || !p->isValidated()) continue; - if ((!more_own || p != peer) && (p->isWaitingForGame() + if ((!more_own || p != acting_peer) && (p->isWaitingForGame() || !getCrownManager()->canRace(p) || p->isCommandSpectator())) continue; if (!p->hasPlayerProfiles()) @@ -1395,8 +1405,8 @@ void CommandManager::process_addons(Context& context) auto result2 = result; result.clear(); std::shared_ptr asker = {}; - if (peer->hasPlayerProfiles()) - asker = peer->getMainProfile(); + if (acting_peer->hasPlayerProfiles()) + asker = acting_peer->getMainProfile(); for (unsigned i = 0; i < result2.size(); ++i) { bool present = false; @@ -1449,7 +1459,7 @@ void CommandManager::process_addons(Context& context) std::sort(result[i].second.begin(), result[i].second.end()); for (unsigned j = 0; j < result[i].second.size(); ++j) { - response += " " + getLobby()->encodeProfileNameForPeer(result[i].second[j], peer.get()); + response += " " + getLobby()->encodeProfileNameForPeer(result[i].second[j], acting_peer.get()); } } } @@ -1460,19 +1470,15 @@ void CommandManager::process_addons(Context& context) "Found %d assets on the server.", all_have.size()); } - getLobby()->sendStringToPeer(peer, response); + context.say(response); } // process_addons // ======================================================================== void CommandManager::process_checkaddon(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto acting_peer = context.actingPeer(); + if (argv.size() < 2) { error(context); @@ -1571,7 +1577,7 @@ void CommandManager::process_checkaddon(Context& context) { if (j) response += ", "; - response += getLobby()->encodeProfileNameForPeer(categories[i][j], peer.get()); + response += getLobby()->encodeProfileNameForPeer(categories[i][j], acting_peer.get()); } if (categories[i].size() > 5) response += ", ..."; @@ -1581,19 +1587,14 @@ void CommandManager::process_checkaddon(Context& context) } response.pop_back(); } - getLobby()->sendStringToPeer(peer, response); + context.say(response); } // process_checkaddon // ======================================================================== void CommandManager::process_id(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + if (argv.size() < 2) { error(context); @@ -1602,18 +1603,12 @@ void CommandManager::process_id(Context& context) if (!validate(context, 1, TFT_ALL_MAPS, false, true)) return; - getLobby()->sendStringToPeer(peer, "Server knows this map, copy it below:\n" + argv[1]); + context.say("Server knows this map, copy it below:\n" + argv[1]); } // process_id // ======================================================================== void CommandManager::process_lsa(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } std::string response = ""; auto& argv = context.m_argv; @@ -1684,18 +1679,12 @@ void CommandManager::process_lsa(Context& context) msg = msg.substr(0, msg.size() - 2); response = "Server's addons: " + msg; } - getLobby()->sendStringToPeer(peer, response); + context.say(response); } // process_lsa // ======================================================================== void CommandManager::process_pha(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } std::string response = ""; auto& argv = context.m_argv; if (argv.size() < 3) @@ -1743,7 +1732,7 @@ void CommandManager::process_pha(Context& context) } } } - getLobby()->sendStringToPeer(peer, player_name + + context.say(player_name + " has " + (found ? "" : "no ") + "addon " + addon_id); } // process_pha // ============================================================================ @@ -1751,7 +1740,7 @@ void CommandManager::process_pha(Context& context) void CommandManager::process_kick(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); + auto acting_peer = context.actingPeer(); if (argv.size() < 2) { error(context); @@ -1772,7 +1761,7 @@ void CommandManager::process_kick(Context& context) } if (player_peer->hammerLevel() > 0) { - getLobby()->sendStringToPeer(peer, "This player is the owner of " + context.say("This player is the owner of " "this server, and is protected from your actions now"); return; } @@ -1781,18 +1770,18 @@ void CommandManager::process_kick(Context& context) vote(context, argv[0] + " " + player_name, ""); return; } - Log::info("CommandManager", "%s kicks %s", (peer.get() ? "Crown player" : "Vote"), player_name.c_str()); + Log::info("CommandManager", "%s kicks %s", (acting_peer.get() ? "Crown player" : "Vote"), player_name.c_str()); player_peer->kick(); if (getSettings()->isTrackingKicks()) { std::string auto_report = "[ Auto report caused by kick ]"; - getLobby()->writeOwnReport(player_peer, peer, auto_report); + getLobby()->writeOwnReport(player_peer, acting_peer, auto_report); } if (argv[0] == "kickban") { Log::info("CommandManager", "%s is now banned", player_name.c_str()); getSettings()->tempBan(player_name); - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "%s is now banned", player_name.c_str())); } } // process_kick @@ -1801,12 +1790,7 @@ void CommandManager::process_kick(Context& context) void CommandManager::process_unban(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + if (argv.size() < 2) { error(context); @@ -1820,19 +1804,13 @@ void CommandManager::process_unban(Context& context) } Log::info("CommandManager", "%s is now unbanned", player_name.c_str()); getSettings()->tempUnban(player_name); - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "%s is now unbanned", player_name.c_str())); } // process_unban // ======================================================================== void CommandManager::process_ban(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } std::string player_name; auto& argv = context.m_argv; if (argv.size() < 2) @@ -1848,7 +1826,7 @@ void CommandManager::process_ban(Context& context) } Log::info("CommandManager", "%s is now banned", player_name.c_str()); getSettings()->tempBan(player_name); - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "%s is now banned", player_name.c_str())); } // process_ban // ======================================================================== @@ -1858,22 +1836,17 @@ void CommandManager::process_pas(Context& context) std::string response; std::string player_name; auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto acting_peer = context.actingPeer(); if (argv.size() < 2) { - if (peer->getPlayerProfiles().empty()) + if (acting_peer->getPlayerProfiles().empty()) { Log::warn("CommandManager", "pas: no existing player profiles??"); error(context); return; } - player_name = peer->getMainName(); + player_name = acting_peer->getMainName(); } else { @@ -1909,19 +1882,15 @@ void CommandManager::process_pas(Context& context) msg.pop_back(); response = msg; } - getLobby()->sendStringToPeer(peer, response); + context.say(response); } // process_pas // ======================================================================== void CommandManager::process_everypas(Context& context) { - auto peer = context.m_peer.lock(); + auto acting_peer = context.actingPeer(); auto argv = context.m_argv; - if (!peer) - { - error(context, true); - return; - } + std::string sorting_type = getAddonPreferredType(); std::string sorting_direction = "desc"; if (argv.size() > 1) @@ -1957,9 +1926,9 @@ void CommandManager::process_everypas(Context& context) // Sorting order for equal players WILL DEPEND ON NAME DECORATOR! // This sorting is clearly bad because we ask lobby every time. Change it later. auto lobby = getLobby(); - std::stable_sort(result.begin(), result.end(), [lobby, peer](const Pair& lhs, const Pair& rhs) -> bool { - return lobby->encodeProfileNameForPeer(lhs.first, peer.get()) - < lobby->encodeProfileNameForPeer(rhs.first, peer.get()); + std::stable_sort(result.begin(), result.end(), [lobby, acting_peer](const Pair& lhs, const Pair& rhs) -> bool { + return lobby->encodeProfileNameForPeer(lhs.first, acting_peer.get()) + < lobby->encodeProfileNameForPeer(rhs.first, acting_peer.get()); }); if (sorting_direction == "asc") std::sort(result.begin(), result.end(), [sorting_idx] @@ -1980,7 +1949,7 @@ void CommandManager::process_everypas(Context& context) for (auto& row: result) { response += "\n"; - std::string decorated_name = getLobby()->encodeProfileNameForPeer(row.first, peer.get()); + std::string decorated_name = getLobby()->encodeProfileNameForPeer(row.first, acting_peer.get()); bool negative = true; for (int item = 0; item < AS_TOTAL; item++) @@ -1997,18 +1966,12 @@ void CommandManager::process_everypas(Context& context) response += msg; } } - getLobby()->sendStringToPeer(peer, response); + context.say(response); } // process_everypas // ======================================================================== void CommandManager::process_sha(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } auto& argv = context.m_argv; if (argv.size() != 2) { @@ -2028,7 +1991,7 @@ void CommandManager::process_sha(Context& context) total_addons.insert(all_soccers.begin(), all_soccers.end()); std::string addon_id_test = Addon::createAddonId(argv[1]); bool found = total_addons.find(addon_id_test) != total_addons.end(); - getLobby()->sendStringToPeer(peer, std::string("Server has ") + + context.say(std::string("Server has ") + (found ? "" : "no ") + "addon " + argv[1]); } // process_sha // ======================================================================== @@ -2037,12 +2000,8 @@ void CommandManager::process_mute(Context& context) { std::shared_ptr player_peer; auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto acting_peer = context.actingPeer(); + std::string result_msg; if (argv.size() != 2 || argv[1].empty()) @@ -2055,8 +2014,8 @@ void CommandManager::process_mute(Context& context) return; std::string player_name = argv[1]; - getChatManager()->addMutedPlayerFor(peer, player_name); - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + getChatManager()->addMutedPlayerFor(acting_peer, player_name); + context.say(StringUtils::insertValues( "Muted player %s", player_name.c_str())); } // process_mute // ======================================================================== @@ -2065,12 +2024,7 @@ void CommandManager::process_unmute(Context& context) { std::shared_ptr player_peer; auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto acting_peer = context.actingPeer(); if (argv.size() != 2 || argv[1].empty()) { @@ -2085,34 +2039,27 @@ void CommandManager::process_unmute(Context& context) std::string player_name = argv[1]; std::string msg; - if (getChatManager()->removeMutedPlayerFor(peer, player_name)) + if (getChatManager()->removeMutedPlayerFor(acting_peer, player_name)) msg = "Unmuted player %s"; else msg = "Player %s was already unmuted"; - getLobby()->sendStringToPeer(peer, + context.say( StringUtils::insertValues(msg, player_name.c_str())); } // process_unmute // ======================================================================== void CommandManager::process_listmute(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - - getLobby()->sendStringToPeer(peer, - getChatManager()->getMutedPlayersAsString(peer)); + auto acting_peer = context.actingPeer(); + context.say(getChatManager()->getMutedPlayersAsString(acting_peer)); } // process_listmute // ======================================================================== void CommandManager::process_gnu(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); + auto acting_peer = context.actingPeer(); if (argv[0] != "gnu") { argv[0] = "gnu"; @@ -2126,19 +2073,19 @@ void CommandManager::process_gnu(Context& context) auto kart_elimination = getKartElimination(); if (turn_on && kart_elimination->isEnabled()) { - getLobby()->sendStringToPeer(peer, "Gnu Elimination mode was already enabled!"); + context.say("Gnu Elimination mode was already enabled!"); return; } if (!turn_on && !kart_elimination->isEnabled()) { - getLobby()->sendStringToPeer(peer, "Gnu Elimination mode was already off!"); + context.say("Gnu Elimination mode was already off!"); return; } if (turn_on && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_NORMAL_RACE && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) { - getLobby()->sendStringToPeer(peer, "Gnu Elimination is available only with racing modes"); + context.say("Gnu Elimination is available only with racing modes"); return; } std::string kart; @@ -2148,7 +2095,7 @@ void CommandManager::process_gnu(Context& context) } else { - if (peer) + if (acting_peer) { kart = "gnu"; if (argv.size() > 1 && getAssetManager()->isKartAvailable(argv[1])) @@ -2191,12 +2138,8 @@ void CommandManager::process_gnu(Context& context) void CommandManager::process_tell(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto acting_peer = context.actingPeer(); + if (argv.size() == 1) { error(context); @@ -2209,18 +2152,12 @@ void CommandManager::process_tell(Context& context) ans.push_back(' '); ans += argv[i]; } - getLobby()->writeOwnReport(peer, peer, ans); + getLobby()->writeOwnReport(acting_peer, acting_peer, ans); } // process_tell // ======================================================================== void CommandManager::process_standings(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } std::string msg; auto& argv = context.m_argv; bool isGP = false; @@ -2255,32 +2192,24 @@ void CommandManager::process_standings(Context& context) } else if (isGnu) msg = getKartElimination()->getStandings(); - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); } // process_standings // ======================================================================== void CommandManager::process_teamchat(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - getChatManager()->addTeamSpeaker(peer); - getLobby()->sendStringToPeer(peer, "Your messages are now addressed to team only"); + auto acting_peer = context.actingPeer(); + + getChatManager()->addTeamSpeaker(acting_peer); + context.say("Your messages are now addressed to team only"); } // process_teamchat // ======================================================================== void CommandManager::process_to(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto acting_peer = context.actingPeer(); + if (argv.size() == 1) { error(context); @@ -2293,21 +2222,17 @@ void CommandManager::process_to(Context& context) return; receivers.push_back(argv[i]); } - getChatManager()->setMessageReceiversFor(peer, receivers); - getLobby()->sendStringToPeer(peer, "Successfully changed chat settings"); + getChatManager()->setMessageReceiversFor(acting_peer, receivers); + context.say("Successfully changed chat settings"); } // process_to // ======================================================================== void CommandManager::process_public(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - getChatManager()->makeChatPublicFor(peer); - getLobby()->sendStringToPeer(peer, "Your messages are now public"); + auto acting_peer = context.actingPeer(); + + getChatManager()->makeChatPublicFor(acting_peer); + context.say("Your messages are now public"); } // process_public // ======================================================================== @@ -2315,12 +2240,7 @@ void CommandManager::process_record(Context& context) { std::string response; auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + #ifdef ENABLE_SQLITE3 if (argv.size() < 5) { @@ -2356,29 +2276,29 @@ void CommandManager::process_record(Context& context) #else response = "This command is not supported."; #endif - getLobby()->sendStringToPeer(peer, response); + context.say(response); } // process_record // ======================================================================== void CommandManager::process_power(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - if (peer->hammerLevel() > 0) + auto acting_peer = context.actingPeer(); + + if (acting_peer->hammerLevel() > 0) { - peer->setAngryHost(false); - getLobby()->sendStringToPeer(peer, "You are now a normal player"); + acting_peer->setHammerLevel(0); + context.say("You are now a normal player"); getLobby()->updatePlayerList(); return; } + int new_level = 1; + if (argv[0] == "power2") + new_level = 2; + std::string username = ""; uint32_t online_id = 0; - const auto& profiles = peer->getPlayerProfiles(); + const auto& profiles = acting_peer->getPlayerProfiles(); if (!profiles.empty()) { username = StringUtils::wideToUtf8(profiles[0]->getName()); @@ -2391,23 +2311,17 @@ void CommandManager::process_power(Context& context) && online_id != 0); if (bad_password && !good_player) { - getLobby()->sendStringToPeer(peer, "You need to provide the password to have the power"); + context.say("You need to provide the password to have the power"); return; } - peer->setAngryHost(true); - getLobby()->sendStringToPeer(peer, "Now you finally have the power!"); + acting_peer->setHammerLevel(new_level); + context.say("Now you finally have the power!"); getLobby()->updatePlayerList(); } // process_power // ======================================================================== void CommandManager::process_length(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - getLobby()->sendStringToPeer(peer, getSettings()->getLapRestrictionsAsString()); + context.say(getSettings()->getLapRestrictionsAsString()); } // process_length // ======================================================================== void CommandManager::process_length_multi(Context& context) @@ -2475,12 +2389,6 @@ void CommandManager::process_direction_assign(Context& context) void CommandManager::process_queue(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } std::string msg = ""; int mask = get_queue_mask(context.m_argv[0]); for (int x = QM_START; x < QM_END; x <<= 1) @@ -2496,19 +2404,15 @@ void CommandManager::process_queue(Context& context) } } msg.pop_back(); - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); } // process_queue // ======================================================================== void CommandManager::process_queue_push(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto acting_peer = context.actingPeer(); + auto peer = context.peer(); if (argv.size() < 3) { @@ -2552,7 +2456,7 @@ void CommandManager::process_queue_push(Context& context) suffix_length = cell.length() - p.value.length() - prefix_length; // kimden: this looks horrendous but I remember it was worth it back then - if (hasTypo(peer, context.m_voting, context.m_argv, context.m_cmd, + if (hasTypo(acting_peer, peer, context.m_voting, context.m_argv, context.m_cmd, 2 + p.index, m_stf_all_maps, 3, false, false, false, subidx, prefix_length, cell.length() - suffix_length)) return; @@ -2602,12 +2506,7 @@ void CommandManager::process_queue_pop(Context& context) { std::string msg = ""; auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + int mask = get_queue_mask(argv[0]); bool from_back = (argv[1] == "pop_back"); @@ -2723,14 +2622,7 @@ void CommandManager::process_queue_shuffle(Context& context) void CommandManager::process_allowstart(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - - getLobby()->sendStringToPeer(peer, getSettings()->getAllowedToStartAsString()); + context.say(getSettings()->getAllowedToStartAsString()); } // process_allowstart // ======================================================================== @@ -2752,13 +2644,7 @@ void CommandManager::process_allowstart_assign(Context& context) void CommandManager::process_shuffle(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - getLobby()->sendStringToPeer(peer, getSettings()->getWhetherShuffledGPGridAsString()); + context.say(getSettings()->getWhetherShuffledGPGridAsString()); } // process_shuffle // ======================================================================== @@ -2778,12 +2664,6 @@ void CommandManager::process_shuffle_assign(Context& context) void CommandManager::process_timeout(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } int seconds; auto& argv = context.m_argv; if (argv.size() < 2 || !StringUtils::parseString(argv[1], &seconds) || seconds <= 0) @@ -2793,7 +2673,7 @@ void CommandManager::process_timeout(Context& context) } getLobby()->setTimeoutFromNow(seconds); getLobby()->updatePlayerList(); - getLobby()->sendStringToPeer(peer, "Successfully changed timeout"); + context.say("Successfully changed timeout"); } // process_timeout // ======================================================================== @@ -2801,12 +2681,6 @@ void CommandManager::process_team(Context& context) { std::string msg; auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } if (argv.size() != 3) { error(context); @@ -2827,7 +2701,7 @@ void CommandManager::process_team(Context& context) // Resetting should be allowed anyway if (!allowed_color && team != TeamUtils::NO_TEAM) { - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "Color %s is not allowed", argv[1])); return; } @@ -2840,12 +2714,7 @@ void CommandManager::process_team(Context& context) void CommandManager::process_swapteams(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + if (argv.size() != 2) { error(context); @@ -2892,21 +2761,15 @@ void CommandManager::process_swapteams(Context& context) permutation_map_int[from] = to; } getTeamManager()->shuffleTemporaryTeams(permutation_map_int); - getLobby()->sendStringToPeer(peer, msg); // todo make public? + context.say(msg); // todo make public? getLobby()->updatePlayerList(); } // process_swapteams // ======================================================================== void CommandManager::process_resetteams(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } getTeamManager()->clearTemporaryTeams(); - getLobby()->sendStringToPeer(peer, "Teams are reset now"); + context.say("Teams are reset now"); getLobby()->updatePlayerList(); } // process_resetteams // ======================================================================== @@ -2914,7 +2777,6 @@ void CommandManager::process_resetteams(Context& context) void CommandManager::process_randomteams(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); int teams_number = -1; int final_number = -1; int players_number = -1; @@ -2935,10 +2797,10 @@ void CommandManager::process_randomteams(Context& context) msg = "No one can play!"; else msg = "Teams are currently not allowed"; - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); return; } - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "Created %d teams for %d players", final_number, players_number)); getLobby()->updatePlayerList(); } // process_randomteams @@ -2966,12 +2828,7 @@ void CommandManager::process_cat(Context& context) { std::string msg; auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + if (argv[0] == "cat+") { if (argv.size() != 3) @@ -3027,18 +2884,13 @@ void CommandManager::process_cat(Context& context) void CommandManager::process_troll(Context& context) { std::string msg; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto hit_processor = getHitProcessor(); if (hit_processor->isAntiTrollActive()) msg = "Trolls will be kicked"; else msg = "Trolls can stay"; - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); } // process_troll // ======================================================================== @@ -3067,18 +2919,13 @@ void CommandManager::process_troll_assign(Context& context) void CommandManager::process_hitmsg(Context& context) { std::string msg; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto hit_processor = getHitProcessor(); if (hit_processor->showTeammateHits()) msg = "Teammate hits are sent to all players"; else msg = "Teammate hits are not sent"; - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); } // process_hitmsg // ======================================================================== @@ -3107,18 +2954,13 @@ void CommandManager::process_hitmsg_assign(Context& context) void CommandManager::process_teamhit(Context& context) { std::string msg; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto hit_processor = getHitProcessor(); if (hit_processor->isTeammateHitMode()) msg = "Teammate hits are punished"; else msg = "Teammate hits are not punished"; - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); } // process_teamhit // ======================================================================== @@ -3148,13 +2990,7 @@ void CommandManager::process_teamhit_assign(Context& context) void CommandManager::process_scoring(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - getLobby()->sendStringToPeer(peer, getGPManager()->getScoringAsString()); + context.say(getGPManager()->getScoringAsString()); } // process_scoring // ======================================================================== @@ -3162,36 +2998,27 @@ void CommandManager::process_scoring_assign(Context& context) { std::string msg; auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + std::string cmd2; CommandManager::restoreCmdByArgv(cmd2, argv, ' ', '"', '"', '\\', 1); if (getGPManager()->trySettingGPScoring(cmd2)) getLobby()->sendStringToAllPeers("Scoring set to \"" + cmd2 + "\""); else - getLobby()->sendStringToPeer(peer, "Scoring could not be parsed from \"" + cmd2 + "\""); + context.say("Scoring could not be parsed from \"" + cmd2 + "\""); } // process_scoring_assign // ======================================================================== void CommandManager::process_register(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - if (!peer->hasPlayerProfiles()) + auto acting_peer = context.actingPeer(); + + if (!acting_peer->hasPlayerProfiles()) return; - int online_id = peer->getMainProfile()->getOnlineId(); + int online_id = acting_peer->getMainProfile()->getOnlineId(); if (online_id <= 0) { - getLobby()->sendStringToPeer(peer, "Please join with a valid online STK account."); + context.say("Please join with a valid online STK account."); return; } std::string ans = ""; @@ -3201,27 +3028,27 @@ void CommandManager::process_register(Context& context) ans.push_back(' '); ans += argv[i]; } - if (getLobby()->writeOnePlayerReport(peer, getSettings()->getRegisterTableName(), + if (getLobby()->writeOnePlayerReport(acting_peer, getSettings()->getRegisterTableName(), ans)) - getLobby()->sendStringToPeer(peer, "Your registration request is being processed"); + context.say("Your registration request is being processed"); else - getLobby()->sendStringToPeer(peer, "Sorry, an error occurred. Please try again."); + context.say("Sorry, an error occurred. Please try again."); } // process_register // ======================================================================== void CommandManager::process_muteall(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); + auto acting_peer = context.actingPeer(); auto tournament = getTournament(); - if (!peer || !tournament) + if (!tournament) { error(context, true); return; } - if (!peer->hasPlayerProfiles()) + if (!acting_peer->hasPlayerProfiles()) return; - std::string peer_username = peer->getMainName(); + std::string peer_username = acting_peer->getMainName(); int op = SWF_OP_FLIP; if (argv.size() >= 2 && argv[1] == "0") @@ -3236,23 +3063,19 @@ void CommandManager::process_muteall(Context& context) msg = "You are now receiving messages only from players and referees"; else msg = "You are now receiving messages from spectators too"; - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); } // process_muteall // ======================================================================== void CommandManager::process_game(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); auto tournament = getTournament(); - if (!peer || !tournament) + if (!tournament) { error(context, true); return; } - if (!peer->hasPlayerProfiles()) - return; - std::string peer_username = peer->getMainName(); int old_game_number; int old_duration; @@ -3284,7 +3107,7 @@ void CommandManager::process_game(Context& context) if (bad) { // error(context) ? - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "Please specify a correct number. " "Format: /game [number %d..%d] [length in minutes] [0..59 additional seconds]", tournament->minGameNumber(), @@ -3322,16 +3145,12 @@ void CommandManager::process_game(Context& context) void CommandManager::process_role(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); auto tournament = getTournament(); - if (!peer || !tournament) + if (!tournament) { error(context, true); return; } - if (!peer->hasPlayerProfiles()) - return; - std::string peer_username = peer->getMainName(); if (argv.size() < 3) { error(context); @@ -3460,7 +3279,7 @@ void CommandManager::process_role(Context& context) msg += " " + missing_assets[i]; } } - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); } getLobby()->updatePlayerList(); } // process_role @@ -3519,15 +3338,11 @@ void CommandManager::process_lobby(Context& context) void CommandManager::process_init(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer || !getTournament()) + if (!getTournament()) { error(context, true); return; } - if (!peer->hasPlayerProfiles()) - return; - std::string peer_username = peer->getMainName(); int red, blue; if (argv.size() < 3 || !StringUtils::parseString(argv[1], &red) || @@ -3539,7 +3354,7 @@ void CommandManager::process_init(Context& context) World* w = World::getWorld(); if (!w) { - getLobby()->sendStringToPeer(peer, "Please set the count " + context.say("Please set the count " "when the karts are ready. Setting the initial count " "in the lobby is not implemented yet, sorry."); return; @@ -3552,12 +3367,6 @@ void CommandManager::process_init(Context& context) void CommandManager::process_mimiz(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } auto& argv = context.m_argv; auto& cmd = context.m_cmd; std::string msg; @@ -3565,18 +3374,17 @@ void CommandManager::process_mimiz(Context& context) msg = "please provide text"; else msg = cmd.substr(argv[0].length() + 1); - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); } // process_mimiz // ======================================================================== void CommandManager::process_test(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); + auto acting_peer = context.actingPeer(); if (argv.size() == 1) { - getLobby()->sendStringToPeer(peer, - "/test is now deprecated. Use /test *2 [something] [something]"); + context.say("/test is now deprecated. Use /test *2 [something] [something]"); return; } argv.resize(4, ""); @@ -3591,10 +3399,10 @@ void CommandManager::process_test(Context& context) return; } std::string username = "Vote"; - if (peer.get() && peer->hasPlayerProfiles()) + if (acting_peer.get() && acting_peer->hasPlayerProfiles()) { username = getLobby()->encodeProfileNameForPeer( - peer->getMainProfile(), peer.get()); + acting_peer->getMainProfile(), acting_peer.get()); } username = "{" + argv[1].substr(4) + "} " + username; getLobby()->sendStringToAllPeers(username + ", " + argv[2] + ", " + argv[3]); @@ -3603,14 +3411,8 @@ void CommandManager::process_test(Context& context) void CommandManager::process_slots(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } int current = getSettings()->getCurrentMaxPlayersInGame(); - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "Number of slots is currently %d", current)); } // process_slots @@ -3620,9 +3422,7 @@ void CommandManager::process_slots_assign(Context& context) { if (getCrownManager()->hasOnlyHostRiding()) { - auto peer = context.m_peer.lock(); // may be nullptr, here we don't care - getLobby()->sendStringToPeer(peer, - "Changing slots is not possible in the singleplayer mode"); + context.say("Changing slots is not possible in the singleplayer mode"); return; } auto& argv = context.m_argv; @@ -3652,13 +3452,7 @@ void CommandManager::process_slots_assign(Context& context) void CommandManager::process_time(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "Server time: %s", StkTime::getLogTime().c_str())); } // process_time @@ -3666,12 +3460,10 @@ void CommandManager::process_time(Context& context) void CommandManager::process_result(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + // Note that for soccer world we need the peer that used the command, + // not the one under whose name it's done + auto peer = context.peer(); + std::string msg = ""; if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) { @@ -3686,31 +3478,20 @@ void CommandManager::process_result(Context& context) } else msg = "This command is not yet supported for this game mode"; - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); } // process_result // ======================================================================== void CommandManager::process_preserve(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - getLobby()->sendStringToPeer(peer, getSettings()->getPreservedSettingsAsString()); + context.say(getSettings()->getPreservedSettingsAsString()); } // process_preserve // ======================================================================== void CommandManager::process_preserve_assign(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + std::string msg = ""; if (argv.size() != 3) { @@ -3735,9 +3516,8 @@ void CommandManager::process_preserve_assign(Context& context) void CommandManager::process_history(Context& context) { - auto peer = context.m_peer.lock(); auto tournament = getTournament(); - if (!peer || !tournament) + if (!tournament) { error(context, true); return; @@ -3746,16 +3526,15 @@ void CommandManager::process_history(Context& context) std::vector arenas = tournament->getMapHistory(); for (unsigned i = 0; i < arenas.size(); i++) msg += StringUtils::insertValues(" [%d]: %s", i, arenas[i].c_str()); - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); } // process_history // ======================================================================== void CommandManager::process_history_assign(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); auto tournament = getTournament(); - if (!peer || !tournament) + if (!tournament) { error(context, true); return; @@ -3781,21 +3560,14 @@ void CommandManager::process_history_assign(Context& context) return; } - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "Assigned [%d] to %s in the map history", index, id.c_str())); } // process_history_assign // ======================================================================== void CommandManager::process_voting(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - - getLobby()->sendStringToPeer(peer, StringUtils::insertValues("Voting method: %d", + context.say(StringUtils::insertValues("Voting method: %d", getMapVoteHandler()->getAlgorithm())); } // process_voting // ======================================================================== @@ -3803,12 +3575,7 @@ void CommandManager::process_voting(Context& context) void CommandManager::process_voting_assign(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + std::string msg = ""; if (argv.size() < 2) { @@ -3822,7 +3589,7 @@ void CommandManager::process_voting_assign(Context& context) return; } getMapVoteHandler()->setAlgorithm(value); - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "Set voting method to %s", value)); } // process_voting_assign // ======================================================================== @@ -3832,21 +3599,17 @@ void CommandManager::process_why_hourglass(Context& context) std::string response; std::string player_name; auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + auto acting_peer = context.actingPeer(); + if (argv.size() < 2) { - if (peer->getPlayerProfiles().empty()) + if (acting_peer->getPlayerProfiles().empty()) { Log::warn("CommandManager", "whyhourglass: no existing player profiles??"); error(context); return; } - player_name = peer->getMainName(); + player_name = acting_peer->getMainName(); } else { @@ -3863,9 +3626,9 @@ void CommandManager::process_why_hourglass(Context& context) } std::string encoded_name = getLobby()->encodeProfileNameForPeer( - player_peer->getMainProfile(), peer.get()); + player_peer->getMainProfile(), acting_peer.get()); - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( getCrownManager()->getWhyPeerCannotPlayAsString(player_peer), encoded_name)); } // process_why_hourglass @@ -3873,13 +3636,7 @@ void CommandManager::process_why_hourglass(Context& context) void CommandManager::process_available_teams(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "Currently available teams: \"%s\"", getTeamManager()->getInternalAvailableTeams().c_str())); } // process_available_teams @@ -3888,12 +3645,7 @@ void CommandManager::process_available_teams(Context& context) void CommandManager::process_available_teams_assign(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + if (argv.size() < 2) { error(context); @@ -3929,19 +3681,13 @@ void CommandManager::process_available_teams_assign(Context& context) if (!ignored.empty()) msg += StringUtils::insertValues( ", but teams \"%s\" were not recognized", ignored); - getLobby()->sendStringToPeer(peer, msg); + context.say(msg); } // process_available_teams_assign // ======================================================================== void CommandManager::process_cooldown(Context& context) { - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "Cooldown for starting the game: %d", getSettings()->getLobbyCooldown())); } // process_cooldown @@ -3950,12 +3696,7 @@ void CommandManager::process_cooldown(Context& context) void CommandManager::process_cooldown_assign(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + if (argv.size() < 2) { error(context); @@ -3970,7 +3711,7 @@ void CommandManager::process_cooldown_assign(Context& context) } getSettings()->setLobbyCooldown(new_cooldown); - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "Set cooldown for starting the game to %d", new_cooldown)); } // process_cooldown_assign @@ -3979,12 +3720,7 @@ void CommandManager::process_cooldown_assign(Context& context) void CommandManager::process_temp250318(Context& context) { auto& argv = context.m_argv; - auto peer = context.m_peer.lock(); - if (!peer) - { - error(context, true); - return; - } + int value = 0; if (argv.size() < 2 || !StringUtils::parseString(argv[1], &value)) { @@ -3994,21 +3730,16 @@ void CommandManager::process_temp250318(Context& context) auto settings = getSettings(); settings->m_legacy_gp_mode = ((value >> 1) & 1); settings->m_legacy_gp_mode_started = ((value >> 0) & 1); - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "ok value = %d", value)); } // process_temp250318 // ======================================================================== void CommandManager::special(Context& context) { - auto peer = context.m_peer.lock(); - auto command = context.m_command.lock(); + auto command = context.command(); auto cmd = context.m_cmd; - if (!peer || !command) - { - error(context, true); - return; - } + // This function is used as a function for /vote and possibly several // other future special functions that are never executed "as usual" // but need to be displayed in /commands output. So, in fact, this @@ -4017,7 +3748,7 @@ void CommandManager::special(Context& context) "but not implemented or unavailable for this server", command->getFullName().c_str()); - getLobby()->sendStringToPeer(peer, StringUtils::insertValues( + context.say(StringUtils::insertValues( "This command (%s) is not implemented, or " "not available for this server. " "If you believe that is a bug, please report it. Full input:\n" @@ -4064,25 +3795,24 @@ void CommandManager::restoreCmdByArgv(std::string& cmd, bool CommandManager::validate(Context& ctx, int idx, TypoFixerType fixer_type, bool case_sensitive, bool allow_as_is) { - auto peer = ctx.m_peer.lock(); const SetTypoFixer& stf = getFixer(fixer_type); // We show 3 options by default - return !hasTypo(peer, ctx.m_voting, ctx.m_argv, ctx.m_cmd, idx, + return !hasTypo(ctx.actingPeer(), ctx.peer(), ctx.m_voting, ctx.m_argv, ctx.m_cmd, idx, stf, 3, case_sensitive, allow_as_is); } // validate //----------------------------------------------------------------------------- -bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, +bool CommandManager::hasTypo(std::shared_ptr acting_peer, std::shared_ptr peer, bool voting, std::vector& argv, std::string& cmd, int idx, const SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is, bool dont_replace, int subidx, int substr_l, int substr_r) { - if (!peer.get()) // voted + if (!acting_peer.get()) // voted return false; std::string username = ""; - if (peer->hasPlayerProfiles()) - username = peer->getMainName(); + if (acting_peer->hasPlayerProfiles()) + username = acting_peer->getMainName(); auto it = m_user_last_correct_argument.find(username); if (it != m_user_last_correct_argument.end() && std::make_pair(idx, subidx) <= it->second) @@ -4099,6 +3829,7 @@ bool CommandManager::hasTypo(std::shared_ptr peer, bool voting, auto closest_commands = stf.getClosest(text, top, case_sensitive); if (closest_commands.empty()) { + // kimden: HERE IT SHOULD BE SENT TO ANOTHER PEER getLobby()->sendStringToPeer(peer, "Command " + cmd + " not found"); return true; } @@ -4182,10 +3913,70 @@ std::shared_ptr CommandManager::addChildCommand(std::sh } // addChildCommand // ======================================================================== +std::shared_ptr CommandManager::Context::peer() +{ + if (m_peer.expired()) + throw std::logic_error("Peer is expired"); + + auto peer = m_peer.lock(); + if (!peer) + throw std::logic_error("Peer is invalid"); + + return peer; +} // peer +//----------------------------------------------------------------------------- + +std::shared_ptr CommandManager::Context::peerMaybeNull() +{ + if (m_peer.expired()) + throw std::logic_error("Peer is expired"); + + auto peer = m_peer.lock(); + return peer; +} // peerMaybeNull +//----------------------------------------------------------------------------- + +std::shared_ptr CommandManager::Context::actingPeer() +{ + if (m_target_peer.expired()) + throw std::logic_error("Target peer is expired"); + + auto acting_peer = m_target_peer.lock(); + if (!acting_peer) + throw std::logic_error("Target peer is invalid"); + + return acting_peer; +} // actingPeer +//----------------------------------------------------------------------------- + +std::shared_ptr CommandManager::Context::command() +{ + if (m_command.expired()) + throw std::logic_error("Command is expired"); + + auto command = m_command.lock(); + if (!command) + throw std::logic_error("Command is invalid"); + + return command; +} // command +//----------------------------------------------------------------------------- + +void CommandManager::Context::say(const std::string& s) +{ + if (m_peer.expired()) + throw std::logic_error("Context::say: Peer has expired"); + + auto peer = m_peer.lock(); + m_lobby->sendStringToPeer(peer, s); +} // say +//----------------------------------------------------------------------------- + void CommandManager::Command::changePermissions(int permissions, int mode_scope, int state_scope) { - m_permissions = permissions; + // Handling players who are allowed to run for anyone in any case + m_permissions = permissions | UU_OTHERS_COMMANDS; m_mode_scope = mode_scope; m_state_scope = state_scope; } // changePermissions diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index cecffecc8f4..2d5ce7f9ced 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -110,10 +110,14 @@ class CommandManager: public LobbyContextComponent struct Context { + ServerLobby* m_lobby; + Event* m_event; std::weak_ptr m_peer; + std::weak_ptr m_target_peer; + std::vector m_argv; std::string m_cmd; @@ -124,15 +128,24 @@ class CommandManager: public LobbyContextComponent bool m_voting; - Context(Event* event, std::shared_ptr peer): - m_event(event), m_peer(peer), m_argv(), + Context(ServerLobby* lobby, Event* event, std::shared_ptr peer): + m_lobby(lobby), + m_event(event), m_peer(peer), m_target_peer(peer), m_argv(), m_cmd(""), m_user_permissions(0), m_voting(false) {} - Context(Event* event, std::shared_ptr peer, + Context(ServerLobby* lobby, Event* event, std::shared_ptr peer, std::vector& argv, std::string& cmd, int user_permissions, bool voting): - m_event(event), m_peer(peer), m_argv(argv), + m_lobby(lobby), + m_event(event), m_peer(peer), m_target_peer(peer), m_argv(argv), m_cmd(cmd), m_user_permissions(user_permissions), m_voting(voting) {} + + std::shared_ptr peer(); + std::shared_ptr peerMaybeNull(); + std::shared_ptr actingPeer(); + std::shared_ptr command(); + + void say(const std::string& s); }; struct CommandDescription @@ -384,7 +397,7 @@ class CommandManager: public LobbyContextComponent bool validate(Context& ctx, int idx, TypoFixerType fixer_type, bool case_sensitive, bool allow_as_is); - bool hasTypo(std::shared_ptr peer, bool voting, + bool hasTypo(std::shared_ptr acting_peer, std::shared_ptr peer, bool voting, std::vector& argv, std::string& cmd, int idx, const SetTypoFixer& stf, int top, bool case_sensitive, bool allow_as_is, bool dont_replace = false, int subidx = 0, int substr_l = -1, int substr_r = -1); diff --git a/src/network/protocols/command_permissions.hpp b/src/network/protocols/command_permissions.hpp index caeebe75f07..19cf3a47ca7 100644 --- a/src/network/protocols/command_permissions.hpp +++ b/src/network/protocols/command_permissions.hpp @@ -21,22 +21,41 @@ enum CommandPermissions : unsigned int { - PE_NONE = 0, - PE_SPECTATOR = 1, - PE_USUAL = 2, - PE_CROWNED = 4, - PE_SINGLE = 8, - PE_HAMMER = 16, - PE_CONSOLE = 32, - PE_VOTED_SPECTATOR = 1024, - PE_VOTED_NORMAL = 2048, - PE_VOTED = PE_VOTED_SPECTATOR | PE_VOTED_NORMAL, - UP_CONSOLE = PE_CONSOLE, - UP_HAMMER = UP_CONSOLE | PE_HAMMER, - UP_SINGLE = UP_HAMMER | PE_SINGLE, - UP_CROWNED = UP_SINGLE | PE_CROWNED, - UP_NORMAL = UP_CROWNED | PE_USUAL, - UP_EVERYONE = UP_NORMAL | PE_SPECTATOR + PE_NONE = 0, + UU_SPECTATOR = (1 << 0), + UU_USUAL = (1 << 1), + UU_CROWNED = (1 << 2), + UU_SINGLE = (1 << 3), + UU_HAMMER = (1 << 4), + UU_MANIPULATOR = (1 << 5), + UU_CONSOLE = (1 << 6), + PE_VOTED_SPECTATOR = (1 << 10), + PE_VOTED_NORMAL = (1 << 11), + + UU_OWN_COMMANDS = (1 << 15), + UU_OTHERS_COMMANDS = (1 << 16), + + // If the command allows anyone to invoke it for others, + // even people with only own commands permission can do it + PE_ALLOW_ANYONE = UU_OWN_COMMANDS, + + PE_SPECTATOR = UU_SPECTATOR | UU_OWN_COMMANDS, + PE_USUAL = UU_USUAL | UU_OWN_COMMANDS, + PE_CROWNED = UU_CROWNED | UU_OWN_COMMANDS, + PE_SINGLE = UU_SINGLE | UU_OWN_COMMANDS, + PE_HAMMER = UU_HAMMER | UU_OWN_COMMANDS, + PE_MANIPULATOR = UU_MANIPULATOR | UU_OWN_COMMANDS | UU_OTHERS_COMMANDS, + PE_CONSOLE = UU_CONSOLE | UU_OWN_COMMANDS | UU_OTHERS_COMMANDS, + + PE_VOTED = PE_VOTED_SPECTATOR | PE_VOTED_NORMAL, + UP_CONSOLE = PE_CONSOLE, + UP_HAMMER = UP_CONSOLE | PE_HAMMER, + UP_SINGLE = UP_HAMMER | PE_SINGLE, + UP_CROWNED = UP_SINGLE | PE_CROWNED, + UP_NORMAL = UP_CROWNED | PE_USUAL, + UP_EVERYONE = UP_NORMAL | PE_SPECTATOR, + + MASK_MANIPULATION = UU_OWN_COMMANDS | UU_OTHERS_COMMANDS, }; #endif // COMMAND_PERMISSIONS_HPP \ No newline at end of file diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index 0fb04680792..ebed54e3d92 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -379,9 +379,9 @@ class STKPeer : public NoCopy m_always_spectate.store(ASM_NONE); } // ------------------------------------------------------------------------ - int hammerLevel() const { return m_angry_host.load(); } + int hammerLevel() const { return m_angry_host.load(); } // ------------------------------------------------------------------------ - void setAngryHost(int val) { m_angry_host.store(val); } + void setHammerLevel(int val) { m_angry_host.store(val); } // ------------------------------------------------------------------------ std::shared_ptr getMainProfile(); // ------------------------------------------------------------------------ From f55ac44e7818a81447c12f9a23c3356a41c2e28e Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 13 May 2025 04:51:07 +0400 Subject: [PATCH 740/830] Some fixes for /as --- data/commands.xml | 10 ++++++++++ src/network/protocols/command_manager.cpp | 21 +++++++++++++++++++-- src/network/protocols/command_manager.hpp | 2 ++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index 48f14f47944..efb4beb17c4 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -197,6 +197,11 @@ here later. For now, please refer to the code for the strings being used. --> permissions-verbose="everyone" description="Enters the hammer mode if the password is correct." /> + permissions-verbose="everyone" description="Casts a vote for the provided command, if it can be voted. Only useful for those players who can enforce their command but opt to vote instead of forcing; for those players who cannot invoke the command alone, /(command) is equivalent to /vote (command)." /> + peer) CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); } + std::string acting_username = ""; + if (target_peer_strong->hasPlayerProfiles()) + acting_username = target_peer_strong->getMainName(); + if (argv[0] == "vote") { if (argv.size() == 1 || argv[1] == "vote") @@ -763,6 +767,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) return; CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); voting = m_user_saved_voting[username]; + target_peer = m_user_saved_acting_peer[username]; restored = true; break; } else { @@ -813,12 +818,23 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) context.say("You don't have permissions to " + action + " this command"); return; } - int mask = (permissions & command->m_permissions); + int mask = ((permissions & command->m_permissions) & (~MASK_MANIPULATION)); if (mask == 0) { context.say("You don't have permissions to " + action + " this command"); return; } + // kimden: both might be nullptr, which means different things + if (target_peer.lock() != peer) + { + int mask_manip = (permissions & command->m_permissions & MASK_MANIPULATION); + if (mask_manip == 0) + { + context.say("You don't have permissions to " + action + + " this command for another person"); + return; + } + } int mask_without_voting = (mask & ~PE_VOTED); if (mask != PE_NONE && mask_without_voting == PE_NONE) voting = true; @@ -842,7 +858,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) { auto response = it->second.process(m_users); std::map counts = response.first; - std::string msg = username + " voted \"/" + cmd + "\", there are"; + std::string msg = acting_username + " voted \"/" + cmd + "\", there are"; if (counts.size() == 1) msg += " " + std::to_string(counts.begin()->second) + " such votes"; else @@ -3848,6 +3864,7 @@ bool CommandManager::hasTypo(std::shared_ptr acting_peer, std::shared_p response += "Argument \"" + text + "\" may be invalid"; m_user_saved_voting[username] = voting; + m_user_saved_acting_peer[username] = acting_peer; if (allow_as_is) { diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 2d5ce7f9ced..9d8645b350d 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -235,6 +235,8 @@ class CommandManager: public LobbyContextComponent std::map m_user_saved_voting; + std::map> m_user_saved_acting_peer; + std::map> m_user_last_correct_argument; std::map m_config_descriptions; From a5ab4e539f3d5381a8228694e4689f4ea89d6a53 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 13 May 2025 12:35:09 +0400 Subject: [PATCH 741/830] Seemingly restore the ability to have null peer when needed (for voting) --- src/network/protocols/command_manager.cpp | 16 +++++++++++++--- src/network/protocols/command_manager.hpp | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 8e85210255d..c483fc3adb9 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -1228,7 +1228,7 @@ void CommandManager::process_config(Context& context) void CommandManager::process_config_assign(Context& context) { - auto acting_peer = context.actingPeer(); + auto acting_peer = context.actingPeerMaybeNull(); if (!getSettings()->isServerConfigurable()) { context.say("Server is not configurable, this command cannot be invoked."); @@ -1756,7 +1756,7 @@ void CommandManager::process_pha(Context& context) void CommandManager::process_kick(Context& context) { auto& argv = context.m_argv; - auto acting_peer = context.actingPeer(); + auto acting_peer = context.actingPeerMaybeNull(); if (argv.size() < 2) { error(context); @@ -2075,7 +2075,7 @@ void CommandManager::process_listmute(Context& context) void CommandManager::process_gnu(Context& context) { auto& argv = context.m_argv; - auto acting_peer = context.actingPeer(); + auto acting_peer = context.actingPeerMaybeNull(); if (argv[0] != "gnu") { argv[0] = "gnu"; @@ -3966,6 +3966,16 @@ std::shared_ptr CommandManager::Context::actingPeer() } // actingPeer //----------------------------------------------------------------------------- +std::shared_ptr CommandManager::Context::actingPeerMaybeNull() +{ + if (m_target_peer.expired()) + throw std::logic_error("Target peer is expired"); + + auto acting_peer = m_target_peer.lock(); + return acting_peer; +} // actingPeerMaybeNull +//----------------------------------------------------------------------------- + std::shared_ptr CommandManager::Context::command() { if (m_command.expired()) diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 9d8645b350d..2f43c8a698e 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -143,6 +143,7 @@ class CommandManager: public LobbyContextComponent std::shared_ptr peer(); std::shared_ptr peerMaybeNull(); std::shared_ptr actingPeer(); + std::shared_ptr actingPeerMaybeNull(); std::shared_ptr command(); void say(const std::string& s); From 75e69dd0e4bb8d4780b96dcc7269cd6446fc4ebd Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 13 May 2025 15:24:44 +0400 Subject: [PATCH 742/830] Get rid of most bugs Remaining stuff: - pass acting permissions to /commands and similar - edit commands.xml to allow invoking some commands under another name - better testing - possibly improving m_user_ stuff --- src/network/protocols/command_manager.cpp | 136 +++++++++++------- src/network/protocols/command_manager.hpp | 3 + src/network/protocols/command_permissions.hpp | 16 ++- src/network/protocols/server_lobby.cpp | 2 + 4 files changed, 97 insertions(+), 60 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index c483fc3adb9..297c27ca8fd 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -187,6 +187,7 @@ EnumExtendedReader CommandManager::permission_reader({ {"PE_VOTED_NORMAL", PE_VOTED_NORMAL}, {"PE_VOTED", PE_VOTED}, {"UP_CONSOLE", UP_CONSOLE}, + {"UP_MANIPULATOR", UP_MANIPULATOR}, {"UP_HAMMER", UP_HAMMER}, {"UP_SINGLE", UP_SINGLE}, {"UP_CROWNED", UP_CROWNED}, @@ -707,54 +708,12 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) permissions = getLobby()->getPermissions(peer); voting = false; std::string action = "invoke"; - std::string username = ""; - if (peer->hasPlayerProfiles()) - username = peer->getMainName(); - - if (argv[0] == "as") - { - std::shared_ptr new_target_peer = {}; - if (argv.size() >= 2) - { - if (hasTypo(peer, peer, voting, argv, cmd, 1, getFixer(TFT_PRESENT_USERS), 3, false, false)) - return; - - new_target_peer = STKHost::get()->findPeerByName(StringUtils::utf8ToWide(argv[1])); - } - - if (!new_target_peer || argv.size() <= 2) - { - context.say("Usage: /as (username) (another command with arguments)"); - return; - } - target_peer = new_target_peer; - target_peer_strong = new_target_peer; - std::reverse(argv.begin(), argv.end()); - argv.pop_back(); - argv.pop_back(); - std::reverse(argv.begin(), argv.end()); - CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); - } + std::string username = ""; std::string acting_username = ""; - if (target_peer_strong->hasPlayerProfiles()) - acting_username = target_peer_strong->getMainName(); - if (argv[0] == "vote") - { - if (argv.size() == 1 || argv[1] == "vote") - { - // kimden: all error strings in this function should be done in error(context) way - context.say("Usage: /vote (a command with arguments)"); - return; - } - std::reverse(argv.begin(), argv.end()); - argv.pop_back(); - std::reverse(argv.begin(), argv.end()); - CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); - voting = true; - action = "vote for"; - } + username = (peer->hasPlayerProfiles() ? peer->getMainName() : ""); + acting_username = (target_peer_strong && target_peer_strong->hasPlayerProfiles() ? target_peer_strong->getMainName() : ""); bool restored = false; for (int i = 0; i <= 5; ++i) { @@ -768,6 +727,8 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); voting = m_user_saved_voting[username]; target_peer = m_user_saved_acting_peer[username]; + target_peer_strong = target_peer.lock(); + acting_username = (target_peer_strong && target_peer_strong->hasPlayerProfiles() ? target_peer_strong->getMainName() : ""); restored = true; break; } else { @@ -783,10 +744,62 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) } } } + m_user_command_replacements.erase(username); if (!restored) m_user_last_correct_argument.erase(username); + while (!argv.empty()) + { + if (argv[0] == "as") + { + std::shared_ptr new_target_peer = {}; + if (argv.size() >= 2) + { + if (hasTypo(target_peer.lock(), peer, voting, argv, cmd, 1, getFixer(TFT_PRESENT_USERS), 3, false, false)) + return; + + new_target_peer = STKHost::get()->findPeerByName(StringUtils::utf8ToWide(argv[1])); + } + + if (!new_target_peer || argv.size() <= 2) + { + context.say("Usage: /as (username) (another command with arguments)"); + return; + } + target_peer = new_target_peer; + target_peer_strong = new_target_peer; + acting_username = (target_peer_strong && target_peer_strong->hasPlayerProfiles() ? target_peer_strong->getMainName() : ""); + shift(cmd, argv, username, 2); + continue; + } + else if (argv[0] == "vote") + { + if (argv.size() == 1 || argv[1] == "vote") + { + // kimden: all error strings in this function should be done in error(context) way + context.say("Usage: /vote (a command with arguments)"); + return; + } + shift(cmd, argv, username, 1); + voting = true; + action = "vote for"; + continue; + } + break; + } + + if (peer && target_peer.expired()) + { + // kimden: save username before player leaves? + context.say(StringUtils::insertValues( + "The person from whose name you tried to invoke " + "the command has left or rejoined. The command was:\n/%s", + cmd.c_str() + )); + return; + } + std::shared_ptr current_command = m_root_command; std::shared_ptr executed_command; for (int idx = 0; ; idx++) @@ -3397,7 +3410,7 @@ void CommandManager::process_mimiz(Context& context) void CommandManager::process_test(Context& context) { auto& argv = context.m_argv; - auto acting_peer = context.actingPeer(); + auto acting_peer = context.actingPeerMaybeNull(); if (argv.size() == 1) { context.say("/test is now deprecated. Use /test *2 [something] [something]"); @@ -3814,7 +3827,7 @@ bool CommandManager::validate(Context& ctx, int idx, const SetTypoFixer& stf = getFixer(fixer_type); // We show 3 options by default - return !hasTypo(ctx.actingPeer(), ctx.peer(), ctx.m_voting, ctx.m_argv, ctx.m_cmd, idx, + return !hasTypo(ctx.actingPeerMaybeNull(), ctx.peerMaybeNull(), ctx.m_voting, ctx.m_argv, ctx.m_cmd, idx, stf, 3, case_sensitive, allow_as_is); } // validate //----------------------------------------------------------------------------- @@ -3827,8 +3840,8 @@ bool CommandManager::hasTypo(std::shared_ptr acting_peer, std::shared_p if (!acting_peer.get()) // voted return false; std::string username = ""; - if (acting_peer->hasPlayerProfiles()) - username = acting_peer->getMainName(); + if (peer->hasPlayerProfiles()) + username = peer->getMainName(); auto it = m_user_last_correct_argument.find(username); if (it != m_user_last_correct_argument.end() && std::make_pair(idx, subidx) <= it->second) @@ -3945,8 +3958,8 @@ std::shared_ptr CommandManager::Context::peer() std::shared_ptr CommandManager::Context::peerMaybeNull() { - if (m_peer.expired()) - throw std::logic_error("Peer is expired"); + // if (m_peer.expired()) + // throw std::logic_error("Peer is expired"); auto peer = m_peer.lock(); return peer; @@ -3968,8 +3981,8 @@ std::shared_ptr CommandManager::Context::actingPeer() std::shared_ptr CommandManager::Context::actingPeerMaybeNull() { - if (m_target_peer.expired()) - throw std::logic_error("Target peer is expired"); + // if (m_target_peer.expired()) + // throw std::logic_error("Target peer is expired"); auto acting_peer = m_target_peer.lock(); return acting_peer; @@ -4064,3 +4077,20 @@ void CommandManager::add_to_queue(int x, int mask, bool to_front, std::string& s } } // add_to_queue // ======================================================================== + +void CommandManager::shift(std::string& cmd, std::vector& argv, + const std::string& username, int count) +{ + std::reverse(argv.begin(), argv.end()); + argv.resize(argv.size() - count); + std::reverse(argv.begin(), argv.end()); + + // auto it = m_user_last_correct_argument.find(username); + // if (it != m_user_last_correct_argument.end()) + // it->second.first -= count; + + m_user_last_correct_argument[username].first -= count; + + CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); +} // shift +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 2f43c8a698e..64d70a3d9cc 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -418,6 +418,9 @@ class CommandManager: public LobbyContextComponent // Helper functions, unrelated to CommandManager inner structure std::string getAddonPreferredType() const; + void shift(std::string& cmd, std::vector& argv, + const std::string& username, int count); + }; #endif // COMMAND_MANAGER_HPP diff --git a/src/network/protocols/command_permissions.hpp b/src/network/protocols/command_permissions.hpp index 19cf3a47ca7..857fa09881a 100644 --- a/src/network/protocols/command_permissions.hpp +++ b/src/network/protocols/command_permissions.hpp @@ -47,13 +47,15 @@ enum CommandPermissions : unsigned int PE_MANIPULATOR = UU_MANIPULATOR | UU_OWN_COMMANDS | UU_OTHERS_COMMANDS, PE_CONSOLE = UU_CONSOLE | UU_OWN_COMMANDS | UU_OTHERS_COMMANDS, - PE_VOTED = PE_VOTED_SPECTATOR | PE_VOTED_NORMAL, - UP_CONSOLE = PE_CONSOLE, - UP_HAMMER = UP_CONSOLE | PE_HAMMER, - UP_SINGLE = UP_HAMMER | PE_SINGLE, - UP_CROWNED = UP_SINGLE | PE_CROWNED, - UP_NORMAL = UP_CROWNED | PE_USUAL, - UP_EVERYONE = UP_NORMAL | PE_SPECTATOR, + // By default, commands cannot be invoked by other people (who can only invoke OWN commands) + PE_VOTED = (PE_VOTED_SPECTATOR | PE_VOTED_NORMAL) & (~UU_OWN_COMMANDS), + UP_CONSOLE = (PE_CONSOLE) & (~UU_OWN_COMMANDS), + UP_MANIPULATOR = (UP_CONSOLE | PE_MANIPULATOR) & (~UU_OWN_COMMANDS), + UP_HAMMER = (UP_MANIPULATOR | PE_HAMMER) & (~UU_OWN_COMMANDS), + UP_SINGLE = (UP_HAMMER | PE_SINGLE) & (~UU_OWN_COMMANDS), + UP_CROWNED = (UP_SINGLE | PE_CROWNED) & (~UU_OWN_COMMANDS), + UP_NORMAL = (UP_CROWNED | PE_USUAL) & (~UU_OWN_COMMANDS), + UP_EVERYONE = (UP_NORMAL | PE_SPECTATOR) & (~UU_OWN_COMMANDS), MASK_MANIPULATION = UU_OWN_COMMANDS | UU_OTHERS_COMMANDS, }; diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 8d02655f3c5..630cec8963f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4303,6 +4303,8 @@ int ServerLobby::getPermissions(std::shared_ptr peer) const if (hammer_level >= 1) { mask |= CommandPermissions::PE_HAMMER; + if (hammer_level >= 2) + mask |= CommandPermissions::PE_MANIPULATOR; } else if (getTournament() && getTournament()->hasHammerRights(peer)) { From fe7c561e611980a99de774785ec6f9d0122d0fe8 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 18 May 2025 17:31:13 +0400 Subject: [PATCH 743/830] Proper permissions in xml, proper power2 --- NETWORKING.md | 3 + data/commands.xml | 144 +++++++++++++--------- src/network/protocols/command_manager.cpp | 6 +- src/network/server_config.hpp | 6 + src/utils/lobby_settings.cpp | 14 ++- src/utils/lobby_settings.hpp | 3 +- src/utils/team_manager.cpp | 17 +++ src/utils/team_manager.hpp | 5 +- 8 files changed, 135 insertions(+), 63 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index 168bff117d8..153981c25a0 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -367,6 +367,9 @@ A typical current server configuration xml that fits the current code version is + + + diff --git a/data/commands.xml b/data/commands.xml index efb4beb17c4..5e727c045a7 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -5,7 +5,8 @@ here later. For now, please refer to the code for the strings being used. --> /> @@ -107,18 +115,21 @@ here later. For now, please refer to the code for the strings being used. --> /> @@ -139,13 +150,15 @@ here later. For now, please refer to the code for the strings being used. --> /> /> /> usage="/length" permissions-verbose="everyone" description="Contains functions related to length of the game. Without arguments, shows the current setting. Arguments can be used only with permissions, check /commands length and /help length (argument) for more details." - permissions="UP_EVERYONE" + permissions="UP_EVERYONE | PE_ALLOW_ANYONE" + permissions-verbose="everyone; invokable for another player" state-scope="SS_ALWAYS" > usage="/direction" permissions-verbose="everyone" description="Prints the currently set direction of the game. Arguments can be used only with permissions, check /commands direction and /help direction = for more details." - permissions="UP_EVERYONE" + permissions="UP_EVERYONE | PE_ALLOW_ANYONE" + permissions-verbose="everyone; invokable for another player" state-scope="SS_ALWAYS" > usage="/mqueue" permissions-verbose="everyone" description="Contains functions related to map queue (regular one). Without arguments, shows the current queue. Arguments can be used only with permissions, check /commands queue and /help queue (argument) for more details." - permissions="UP_EVERYONE" + permissions="UP_EVERYONE | PE_ALLOW_ANYONE" + permissions-verbose="everyone; invokable for another player" state-scope="SS_ALWAYS" aliases="queue" > @@ -316,7 +334,8 @@ here later. For now, please refer to the code for the strings being used. --> usage="/mcyclic" permissions-verbose="everyone" description="Contains functions related to map queue (cyclic one). Without arguments, shows the current queue. Arguments can be used only with permissions, check /commands queue and /help queue (argument) for more details." - permissions="UP_EVERYONE" + permissions="UP_EVERYONE | PE_ALLOW_ANYONE" + permissions-verbose="everyone; invokable for another player" state-scope="SS_ALWAYS" > usage="/mboth" permissions-verbose="everyone" description="Contains functions related to map queue (both regular and cyclic). Without arguments, shows the current queue. Arguments can be used only with permissions, check /commands queue and /help queue (argument) for more details." - permissions="UP_EVERYONE" + permissions="UP_EVERYONE | PE_ALLOW_ANYONE" + permissions-verbose="everyone; invokable for another player" state-scope="SS_ALWAYS" > usage="/kqueue" permissions-verbose="everyone" description="Contains functions related to kart queue (regular one). Without arguments, shows the current queue. Arguments can be used only with permissions, check /commands queue and /help queue (argument) for more details." - permissions="UP_EVERYONE" + permissions="UP_EVERYONE | PE_ALLOW_ANYONE" + permissions-verbose="everyone; invokable for another player" state-scope="SS_ALWAYS" > usage="/kcyclic" permissions-verbose="everyone" description="Contains functions related to kart queue (cyclic one). Without arguments, shows the current queue. Arguments can be used only with permissions, check /commands queue and /help queue (argument) for more details." - permissions="UP_EVERYONE" + permissions="UP_EVERYONE | PE_ALLOW_ANYONE" + permissions-verbose="everyone; invokable for another player" state-scope="SS_ALWAYS" > usage="/kboth" permissions-verbose="everyone" description="Contains functions related to kart queue (both regular and cyclic). Without arguments, shows the current queue. Arguments can be used only with permissions, check /commands queue and /help queue (argument) for more details." - permissions="UP_EVERYONE" + permissions="UP_EVERYONE | PE_ALLOW_ANYONE" + permissions-verbose="everyone; invokable for another player" state-scope="SS_ALWAYS" > usage="/qregular" permissions-verbose="everyone" description="Contains functions related to kart+map queue (regular one). Without arguments, shows the current queue. Arguments can be used only with permissions, check /commands queue and /help queue (argument) for more details." - permissions="UP_EVERYONE" + permissions="UP_EVERYONE | PE_ALLOW_ANYONE" + permissions-verbose="everyone; invokable for another player" state-scope="SS_ALWAYS" > usage="/qcyclic" permissions-verbose="everyone" description="Contains functions related to kart+map queue (cyclic one). Without arguments, shows the current queue. Arguments can be used only with permissions, check /commands queue and /help queue (argument) for more details." - permissions="UP_EVERYONE" + permissions="UP_EVERYONE | PE_ALLOW_ANYONE" + permissions-verbose="everyone; invokable for another player" state-scope="SS_ALWAYS" > usage="/qboth" permissions-verbose="everyone" description="Contains functions related to kart+map queue (both regular and cyclic). Without arguments, shows the current queue. Arguments can be used only with permissions, check /commands queue and /help queue (argument) for more details." - permissions="UP_EVERYONE" + permissions="UP_EVERYONE | PE_ALLOW_ANYONE" + permissions-verbose="everyone; invokable for another player" state-scope="SS_ALWAYS" > usage="/allowstart" permissions-verbose="everyone" description="Shows if the game can start right now." - permissions="UP_EVERYONE" + permissions="UP_EVERYONE | PE_ALLOW_ANYONE" + permissions-verbose="everyone; invokable for another player" > usage="/troll" permissions-verbose="everyone" description="Shows whether anti-troll system is enabled." - permissions="UP_EVERYONE" + permissions="UP_EVERYONE | PE_ALLOW_ANYONE" + permissions-verbose="everyone; invokable for another player" state-scope="SS_ALWAYS" > /> + permissions="UP_EVERYONE | PE_VOTED | PE_ALLOW_ANYONE"> --> getOnlineId(); } - std::string password = getSettings()->getPowerPassword(); + std::string password = getSettings()->getPowerPassword(new_level); bool bad_password = (password.empty() || argv.size() <= 1 || argv[1] != password); - bool good_player = (getTeamManager()->isInHammerWhitelist(username) + bool good_player = (getTeamManager()->isInHammerWhitelist(username, new_level) && online_id != 0); if (bad_password && !good_player) { @@ -2344,7 +2344,7 @@ void CommandManager::process_power(Context& context) return; } acting_peer->setHammerLevel(new_level); - context.say("Now you finally have the power!"); + context.say("Now you have the power!"); getLobby()->updatePlayerList(); } // process_power // ======================================================================== diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 40535eeb471..34f6be92405 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -739,6 +739,12 @@ namespace ServerConfig "Allows server owner (not crowned player!) to go to power mode " "to kick players using GUI and not be kicked, empty to disable.")); + SERVER_CFG_PREFIX StringServerConfigParam m_power_password_level_2 + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "power-password-level-2", + "Allows server owner (not crowned player!) to use power commands, " + "and also invoke any command as any other user, empty to disable.")); + SERVER_CFG_PREFIX BoolServerConfigParam m_ai_anywhere SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "ai-anywhere", "If true this server will allow AI instance to be connected from " diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index 37ed7f9088a..926f7970b24 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -121,6 +121,7 @@ void LobbySettings::setupContextUser() m_voting_timeout = ServerConfig::m_voting_timeout; m_commands_file = ServerConfig::m_commands_file; m_power_password = ServerConfig::m_power_password; + m_power_password_level_2 = ServerConfig::m_power_password_level_2; m_register_table_name = ServerConfig::m_register_table_name; m_lobby_cooldown = ServerConfig::m_lobby_cooldown; } // setupContextUser @@ -680,4 +681,15 @@ void LobbySettings::getLobbyHitCaptureLimit() m_battle_hit_capture_limit = hit_capture_limit; m_battle_time_limit = time_limit; } // getLobbyHitCaptureLimit -// ---------------------------------------------------------------------------- \ No newline at end of file +// ---------------------------------------------------------------------------- + +std::string LobbySettings::getPowerPassword(int level) const +{ + if (level == 1) + return m_power_password; + if (level == 2) + return m_power_password_level_2; + + Log::error("LobbySettings", "Invoked getPowerPassword with level = %d", level); + return ""; +} \ No newline at end of file diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 4b857358f09..23e0ad39ce3 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -166,7 +166,7 @@ class LobbySettings: public LobbyContextComponent bool isValidatingPlayer() const { return m_validating_player; } float getVotingTimeout() const { return m_voting_timeout; } std::string getCommandsFile() const { return m_commands_file; } - std::string getPowerPassword() const { return m_power_password; } + std::string getPowerPassword(int level) const; std::string getRegisterTableName() const { return m_register_table_name; } int getLobbyCooldown() const { return m_lobby_cooldown; } @@ -256,6 +256,7 @@ class LobbySettings: public LobbyContextComponent float m_voting_timeout; std::string m_commands_file; std::string m_power_password; + std::string m_power_password_level_2; std::string m_register_table_name; int m_lobby_cooldown; diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp index c78a9e71ce9..bcd1688a9ea 100644 --- a/src/utils/team_manager.cpp +++ b/src/utils/team_manager.cpp @@ -127,6 +127,7 @@ void TeamManager::initCategories() std::string category = ""; bool isTeam = false; bool isHammerWhitelisted = false; + int level; // Used only when isHammerWhitelisted for (std::string& s: tokens) { if (s.empty()) @@ -152,12 +153,17 @@ void TeamManager::initCategories() else if (s[0] == '^') { isHammerWhitelisted = true; + level = 1; + if (s.length() >= 2 && s[1] == '^') + level = 2; } else { if (isHammerWhitelisted) { m_hammer_whitelist.insert(s); + if (level >= 2) + m_hammer_whitelist_level_2.insert(s); } else { @@ -252,6 +258,17 @@ int TeamManager::getTeamForUsername(const std::string& name) } // getTeamForUsername //----------------------------------------------------------------------------- +bool TeamManager::isInHammerWhitelist(const std::string& str, int level) const +{ + if (level == 1) + return m_hammer_whitelist.find(str) != m_hammer_whitelist.end(); + else if (level == 2) + return m_hammer_whitelist_level_2.find(str) != m_hammer_whitelist_level_2.end(); + + return false; +} // isInHammerWhitelist +//----------------------------------------------------------------------------- + void TeamManager::clearTemporaryTeams() { clearTeams(); diff --git a/src/utils/team_manager.hpp b/src/utils/team_manager.hpp index 03db3a96473..d72de111b88 100644 --- a/src/utils/team_manager.hpp +++ b/src/utils/team_manager.hpp @@ -71,8 +71,7 @@ class TeamManager: public LobbyContextComponent bool hasTeam(const std::string& name) { return m_team_for_player.find(name) != m_team_for_player.end(); } - bool isInHammerWhitelist(const std::string& str) const - { return m_hammer_whitelist.find(str) != m_hammer_whitelist.end(); } + bool isInHammerWhitelist(const std::string& str, int level) const; void clearTemporaryTeams(); void shuffleTemporaryTeams(const std::map& permutation); @@ -98,6 +97,8 @@ class TeamManager: public LobbyContextComponent std::set m_hammer_whitelist; + std::set m_hammer_whitelist_level_2; + }; #endif // TEAM_MANAGER_HPP \ No newline at end of file From 55d80775596ccf1b7d57d4c107d4ec979b18721a Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 18 May 2025 18:37:19 +0400 Subject: [PATCH 744/830] Use acting permissions for /commands --- src/network/protocols/command_manager.cpp | 20 ++++++++++++++------ src/network/protocols/command_manager.hpp | 9 ++++++--- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 8408e46d7a8..87d282497ba 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -695,6 +695,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) auto& argv = context.m_argv; auto& cmd = context.m_cmd; auto& permissions = context.m_user_permissions; + auto& acting_permissions = context.m_acting_user_permissions; auto& voting = context.m_voting; auto& target_peer = context.m_target_peer; std::shared_ptr target_peer_strong = context.m_target_peer.lock(); @@ -709,6 +710,8 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) voting = false; std::string action = "invoke"; + acting_permissions = getLobby()->getPermissions(target_peer_strong); + std::string username = ""; std::string acting_username = ""; @@ -729,6 +732,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) target_peer = m_user_saved_acting_peer[username]; target_peer_strong = target_peer.lock(); acting_username = (target_peer_strong && target_peer_strong->hasPlayerProfiles() ? target_peer_strong->getMainName() : ""); + acting_permissions = getLobby()->getPermissions(target_peer_strong); restored = true; break; } else { @@ -770,6 +774,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) target_peer = new_target_peer; target_peer_strong = new_target_peer; acting_username = (target_peer_strong && target_peer_strong->hasPlayerProfiles() ? target_peer_strong->getMainName() : ""); + acting_permissions = getLobby()->getPermissions(target_peer_strong); shift(cmd, argv, username, 2); continue; } @@ -831,6 +836,9 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) context.say("You don't have permissions to " + action + " this command"); return; } + + // Note that we use caller's permissions to determine if the command can be invoked, + // and during its invocation, we use acting peer's permissions. int mask = ((permissions & command->m_permissions) & (~MASK_MANIPULATION)); if (mask == 0) { @@ -898,7 +906,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) "Command \"/%s\" has been successfully voted", new_cmd.c_str()); getLobby()->sendStringToAllPeers(msg2); - Context new_context(getLobby(), event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); + Context new_context(getLobby(), event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, UP_EVERYONE, false); execute(executed_command, new_context); } } @@ -968,7 +976,7 @@ void CommandManager::update() } // We don't know the event though it is only needed in // ServerLobby::startSelection where it is nullptr when they vote - Context new_context(getLobby(), nullptr, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, false); + Context new_context(getLobby(), nullptr, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, UP_EVERYONE, false); execute(command, new_context); } } @@ -1125,7 +1133,7 @@ void CommandManager::process_commands(Context& context) auto ptr = command->m_name_to_subcommand[argv[i]].lock(); if (!ptr) break; - if ((context.m_user_permissions & ptr->m_permissions) != 0 + if ((context.m_acting_user_permissions & ptr->m_permissions) != 0 && isAvailable(ptr)) command = ptr; else @@ -1148,13 +1156,13 @@ void CommandManager::process_commands(Context& context) std::map res; for (std::shared_ptr& subcommand: command->m_subcommands) { - if ((context.m_user_permissions & subcommand->m_permissions) != 0 + if ((context.m_acting_user_permissions & subcommand->m_permissions) != 0 && isAvailable(subcommand)) { bool subcommands_available = false; for (auto& c: subcommand->m_subcommands) { - if ((context.m_user_permissions & c->m_permissions) != 0 + if ((context.m_acting_user_permissions & c->m_permissions) != 0 && isAvailable(c)) subcommands_available = true; } @@ -1202,7 +1210,7 @@ void CommandManager::process_replay(Context& context) void CommandManager::process_start(Context& context) { - if (!getCrownManager()->isOwnerLess() && (context.m_user_permissions & UP_CROWNED) == 0) + if (!getCrownManager()->isOwnerLess() && (context.m_acting_user_permissions & UP_CROWNED) == 0) { context.m_voting = true; } diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 64d70a3d9cc..a6043a5d336 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -126,19 +126,22 @@ class CommandManager: public LobbyContextComponent int m_user_permissions; + int m_acting_user_permissions; + bool m_voting; Context(ServerLobby* lobby, Event* event, std::shared_ptr peer): m_lobby(lobby), m_event(event), m_peer(peer), m_target_peer(peer), m_argv(), - m_cmd(""), m_user_permissions(0), m_voting(false) {} + m_cmd(""), m_user_permissions(0), m_acting_user_permissions(0), m_voting(false) {} Context(ServerLobby* lobby, Event* event, std::shared_ptr peer, std::vector& argv, std::string& cmd, - int user_permissions, bool voting): + int user_permissions, int acting_user_permissions, bool voting): m_lobby(lobby), m_event(event), m_peer(peer), m_target_peer(peer), m_argv(argv), - m_cmd(cmd), m_user_permissions(user_permissions), m_voting(voting) {} + m_cmd(cmd), m_user_permissions(user_permissions), + m_acting_user_permissions(acting_user_permissions), m_voting(voting) {} std::shared_ptr peer(); std::shared_ptr peerMaybeNull(); From 728ef389222c863c0e14dc9fb613e309feb596c9 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Wed, 21 May 2025 14:31:52 +0200 Subject: [PATCH 745/830] Fix #5429 - Don't show tips after game modes without relevant tips - Only show tips relevant to time-trial after a time-trial race - Ensure both tips about powerups during races and general driving tips from time-trial tips are shown in racing modes with powerups --- data/tips.xml | 12 ++++++----- src/states_screens/race_result_gui.cpp | 28 ++++++++++++++++++++++++-- src/tips/tips_manager.cpp | 16 +++++++++++++-- src/tips/tips_manager.hpp | 5 ++++- 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/data/tips.xml b/data/tips.xml index 7ea71550bdf..60424bc10eb 100644 --- a/data/tips.xml +++ b/data/tips.xml @@ -8,19 +8,21 @@ - + + + + + + + - - - - diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 79a0f5a4be9..d05ebd21cce 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -68,6 +68,7 @@ #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/profiler.hpp" +#include "utils/random_generator.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" #include "main_loop.hpp" @@ -199,9 +200,32 @@ void RaceResultGUI::init() if (!human_win && !NetworkConfig::get()->isNetworking() && !TipsManager::get()->isEmpty()) { - std::string tipset = "race"; - if (RaceManager::get()->isSoccerMode()) + std::string tipset; + // For races with powerups, pick at random + // between the race-powerup and time-trial tipsets. + if (RaceManager::get()->isLinearRaceMode() && + !RaceManager::get()->isTimeTrialMode()) + { + RandomGenerator randgen; + randgen.seed((int)StkTime::getTimeSinceEpoch()); + unsigned int racePowerupTipCount = TipsManager::get()->getTipCount("race-powerup"); + unsigned int raceTipCount = racePowerupTipCount + TipsManager::get()->getTipCount("time-trial"); + unsigned int randvalue = randgen.get(raceTipCount); + tipset = (randvalue <= racePowerupTipCount) ? "race-powerup" : "time-trial"; + } + else if (RaceManager::get()->isSoccerMode()) + { tipset = "soccer"; + } + else if (RaceManager::get()->isTimeTrialMode()) + { + tipset = "time-trial"; + } + else + { + return; // Don't show irrelevant tips + } + core::stringw tip = TipsManager::get()->getTip(tipset); core::stringw tips_string = _("Tip: %s", tip); MessageQueue::add(MessageQueue::MT_GENERIC, tips_string); diff --git a/src/tips/tips_manager.cpp b/src/tips/tips_manager.cpp index 700155ff494..b015ab18964 100644 --- a/src/tips/tips_manager.cpp +++ b/src/tips/tips_manager.cpp @@ -87,7 +87,7 @@ void TipsManager::addTipSet(const XMLNode *input) Log::error("TipSet", "Incorrect tips for the entries of tipset \"%s\".", id.c_str()); } -} +} // addTipSet // ---------------------------------------------------------------------------- const irr::core::stringw& TipsManager::getTip(const std::string& id) const @@ -102,6 +102,18 @@ const irr::core::stringw& TipsManager::getTip(const std::string& id) const RandomGenerator randgen; unsigned pos = randgen.get(ret->second.size()); return ret->second.at(pos); -} // getTipSet +} // getTip + +// ---------------------------------------------------------------------------- +const unsigned int TipsManager::getTipCount(const std::string& id) const +{ + auto ret = m_all_tip_sets.find(id); + if (ret == m_all_tip_sets.end()) + { + // Should not happen + return 0; + } + return ret->second.size(); +} // getTipCount #endif diff --git a/src/tips/tips_manager.hpp b/src/tips/tips_manager.hpp index de38e8e73ef..f283c428ec7 100644 --- a/src/tips/tips_manager.hpp +++ b/src/tips/tips_manager.hpp @@ -67,9 +67,12 @@ class TipsManager m_tips_manager = NULL; } // destroy // ======================================================================== - /** Get a tip by ID. */ + /** Get a tip by tipset ID. */ const irr::core::stringw& getTip(const std::string& id) const; // ------------------------------------------------------------------------ + /** Get the number of tips by tipset ID. */ + const unsigned int getTipCount(const std::string& id) const; + // ------------------------------------------------------------------------ bool isEmpty() const { return m_all_tip_sets.empty(); } // ------------------------------------------------------------------------ }; // class TipsManager From d3c68a1c1aca2af513db7d90ffb8fd13dc8e391d Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Wed, 21 May 2025 18:10:52 +0200 Subject: [PATCH 746/830] Improve IconButton behavior and fix #5413 - Make the font size smaller for icon buttons with word wrap if the text is set to not fit in 2 lines (accounting for text break logic) - Reserve more width for the race result GUI buttonbar (75% instead of 65%) - Make the icon-buttons in the buttonbar use all of the reserved width instead of being limited to a square shape. This allows to properly use available width at wide resolutions without introducing issues at tall resolutions. - Also fix a minor comparison issue in the previous commit --- data/gui/screens/race_result.stkgui | 8 +++--- src/font/font_manager.hpp | 1 + src/guiengine/widgets/icon_button_widget.cpp | 29 +++++++++++++++----- src/states_screens/race_result_gui.cpp | 2 +- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/data/gui/screens/race_result.stkgui b/data/gui/screens/race_result.stkgui index e9005ac3bb7..097f9e20f9f 100644 --- a/data/gui/screens/race_result.stkgui +++ b/data/gui/screens/race_result.stkgui @@ -15,10 +15,10 @@ left: 'Abort GP', 'Back to the menu' (or invisible) Setting text=" " is important, otherwise the height of the widget is incorrect. --> - - - - + + + +
diff --git a/src/font/font_manager.hpp b/src/font/font_manager.hpp index 604d1d88695..b23159b40cf 100644 --- a/src/font/font_manager.hpp +++ b/src/font/font_manager.hpp @@ -156,6 +156,7 @@ extern FontManager *font_manager; namespace LineBreakingRules { bool endSentence(char32_t c); + bool breakable(char32_t c); } #endif diff --git a/src/guiengine/widgets/icon_button_widget.cpp b/src/guiengine/widgets/icon_button_widget.cpp index 01436e82fff..1e8430e100c 100644 --- a/src/guiengine/widgets/icon_button_widget.cpp +++ b/src/guiengine/widgets/icon_button_widget.cpp @@ -15,6 +15,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#include "font/font_manager.hpp" #include "guiengine/widgets/icon_button_widget.hpp" #include "graphics/central_settings.hpp" #include "graphics/irr_driver.hpp" @@ -334,18 +335,32 @@ void IconButtonWidget::setLabelFont() const bool word_wrap = (m_properties[PROP_WORD_WRAP] == "true"); const int max_w = m_label->getAbsolutePosition().getWidth(); - if (!word_wrap && - (int)GUIEngine::getFont()->getDimension(m_label->getText()).Width - > max_w + 4) // arbitrarily allow for 4 pixels + if (!word_wrap) { - m_label->setOverrideFont( GUIEngine::getSmallFont() ); + if (max_w < (int)GUIEngine::getFont()->getDimension(m_label->getText()).Width) + m_label->setOverrideFont( GUIEngine::getSmallFont() ); } - else + // If the string doesn't fit in 2 lines after word-wrap is applied, use the small font + else if (max_w < (int)GUIEngine::getFont()->getDimension(m_label->getText()).Width) { - m_label->setOverrideFont( NULL ); + core::stringw test_string = m_label->getText(); + core::stringw temp_string = test_string; + while (temp_string.size() > 0) + { + temp_string.erase(temp_string.size() - 1); + if ((unsigned int)max_w > GUIEngine::getFont()->getDimension(temp_string.c_str()).Width + && LineBreakingRules::breakable((char32_t) temp_string.lastChar())) + break; + } + test_string = test_string.subString(temp_string.size(), test_string.size() - temp_string.size()); + + if (max_w < (int)GUIEngine::getFont()->getDimension(test_string.c_str()).Width) + m_label->setOverrideFont( GUIEngine::getSmallFont() ); + else + m_label->setOverrideFont( NULL ); } } -} +} // setLabelFont // ----------------------------------------------------------------------------- void IconButtonWidget::setVisible(bool visible) diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index d05ebd21cce..8353b986a28 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -211,7 +211,7 @@ void RaceResultGUI::init() unsigned int racePowerupTipCount = TipsManager::get()->getTipCount("race-powerup"); unsigned int raceTipCount = racePowerupTipCount + TipsManager::get()->getTipCount("time-trial"); unsigned int randvalue = randgen.get(raceTipCount); - tipset = (randvalue <= racePowerupTipCount) ? "race-powerup" : "time-trial"; + tipset = (randvalue < racePowerupTipCount) ? "race-powerup" : "time-trial"; } else if (RaceManager::get()->isSoccerMode()) { From bdf0282730faad0c6d334e96ec837f3ac0d9f23d Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Wed, 21 May 2025 18:34:19 +0200 Subject: [PATCH 747/830] Fix server-only build --- src/guiengine/widgets/icon_button_widget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/guiengine/widgets/icon_button_widget.cpp b/src/guiengine/widgets/icon_button_widget.cpp index 1e8430e100c..13e288e4cce 100644 --- a/src/guiengine/widgets/icon_button_widget.cpp +++ b/src/guiengine/widgets/icon_button_widget.cpp @@ -326,6 +326,7 @@ void IconButtonWidget::setTexture(video::ITexture* texture) // ----------------------------------------------------------------------------- void IconButtonWidget::setLabelFont() { +#ifndef SERVER_ONLY if (m_font != NULL) { m_label->setOverrideFont( m_font ); @@ -360,6 +361,7 @@ void IconButtonWidget::setLabelFont() m_label->setOverrideFont( NULL ); } } +#endif } // setLabelFont // ----------------------------------------------------------------------------- From 5d299e3f5ff44a1ef39c82fe5018c241549fb229 Mon Sep 17 00:00:00 2001 From: SvenAndreasBelting Date: Wed, 21 May 2025 18:41:33 +0200 Subject: [PATCH 748/830] Updated Cartoon focus icons. Main menu and online icons are brighter and have a different border now, to increase visual difference to the normal icons. --- .../data/gui/icons/menu_addons_focus.png | Bin 5538 -> 16983 bytes .../data/gui/icons/menu_multi_focus.png | Bin 6742 -> 21602 bytes .../data/gui/icons/menu_online_focus.png | Bin 4950 -> 14398 bytes .../data/gui/icons/menu_race_focus.png | Bin 6079 -> 18114 bytes .../data/gui/icons/menu_story_focus.png | Bin 6442 -> 15435 bytes .../gui/icons/online/menu_create_server.png | Bin 6090 -> 15178 bytes .../icons/online/menu_create_server_hover.png | Bin 6070 -> 20571 bytes .../gui/icons/online/menu_find_server.png | Bin 6073 -> 16639 bytes .../icons/online/menu_find_server_hover.png | Bin 6046 -> 21832 bytes .../icons/online/menu_online_player_focus.png | Bin 15698 -> 22092 bytes .../data/gui/icons/online/menu_quick_play.png | Bin 5344 -> 14024 bytes .../icons/online/menu_quick_play_hover.png | Bin 5280 -> 19440 bytes 12 files changed, 0 insertions(+), 0 deletions(-) diff --git a/data/skins/cartoon/data/gui/icons/menu_addons_focus.png b/data/skins/cartoon/data/gui/icons/menu_addons_focus.png index 7b668059d72ecb9799113b41de50a72e5dda23dd..5c7fc03b22aedbedc60e237f9205a5a2789d4179 100644 GIT binary patch literal 16983 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 diff --git a/data/skins/cartoon/data/gui/icons/menu_multi_focus.png b/data/skins/cartoon/data/gui/icons/menu_multi_focus.png index 1a2106fc40747089cbc01659c4520e04f329c81c..ef3e574397ef71212ae25d3ed142738b537b50d7 100644 GIT binary patch literal 21602 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 GjQt-8FTm~q literal 6742 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 DPC8-w diff --git a/data/skins/cartoon/data/gui/icons/menu_online_focus.png b/data/skins/cartoon/data/gui/icons/menu_online_focus.png index e5060ae1be320efb0835e4b6ef62f26624ff1c5f..78e246f4fe97967add3f997a2bf5798dace68324 100644 GIT binary patch literal 14398 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 literal 4950 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 Lu3LZ8HU9qr$<_*8 diff --git a/data/skins/cartoon/data/gui/icons/menu_race_focus.png b/data/skins/cartoon/data/gui/icons/menu_race_focus.png index d7fec32815514f540aeb5c70985531621c530b18..e13bbef9a6e1d22ba65a5e59e6f63b5f8dfeb149 100644 GIT binary patch literal 18114 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 Bugm}d diff --git a/data/skins/cartoon/data/gui/icons/online/menu_create_server.png b/data/skins/cartoon/data/gui/icons/online/menu_create_server.png index 5c702268305626ddb194a4f2ef775caa5ddd86ce..8cd9943204b3cf434b154fb15f965064df5ba6bd 100644 GIT binary patch literal 15178 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 literal 6090 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 diff --git a/data/skins/cartoon/data/gui/icons/online/menu_create_server_hover.png b/data/skins/cartoon/data/gui/icons/online/menu_create_server_hover.png index f5282ab0fca857850b8c68284357c7574b14963e..57148dfba1fbebb900736a5db448d2659fb2bbe0 100644 GIT binary patch literal 20571 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 literal 6070 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

_ zaYllaVS>Mgt3?U#zR0%ORZ=Ji2-kHmO8Q6km+#XBv_QKt2T%}5@wNkS(Sw}@>+hTt zgRa=+J#7Xpho$07BHvv{UIhbr7Jq5pYTm$<2uMb?)y# z*A+iQ$n|SzEYnJHTCa)1Yx;B&Fw_LOHcB?+^oB6p0EUp2bZLkM2;=(%r38W^=!;r`Kwl!lraKhd!zonDo)pZsZ3=~gOpsFx*b z*{+^(v#MWi#@X_Na7jDl%b@@!=P>Yk;b6!5)%eKf#z-$x+9JN{5tu-$9NyQAK9lI- zFDGiYt82d?c^0xY*g~`tDaidgo1;tcw~Wn<%;0WXA2%C_7W|!ne$11y*J4-pE_uqa zd>mPoFet?EYqGY3lY^a82qaaV*BNJ$UN^ z(52iX-QWi-Bkl&_EdkTm&lCLmfx5sI5NiAJE(Ks2(5Ijwai@19ItNe$#eV+FHTA_% z`QHBDcN4yEBqkqPA$Ld}#uNRAW5u2l{cS;K%&b5sjT-~FIL+svxX>pA+1=<`nNzXP z4ytn9L4V$KF9w`0ovK{y%i#M%f8HIPOL{a=cfgu+liKT#z{n%AXAYlNETP8&3P)?h zr%NR0f*v%Qim%7@S6A1`$&1R#mKLc#f86{Kn0_96gC5--JpEMdXn(2OzAq^3(>hfO znx!pm!tvPrx&ea-IQuqL!tG2i(Qj<&qyKQLbI3VBGgz#L6QqNOI%_|+cYeE)^{cCah}axV6L zGWVLi)gw;n3d99A#}qtsFIwWsUxW_e0+JQb+lyK$Ogb}Pq<6(^X33W z2>Lx2)F0#ehtvoSXg+)3m>`H$BTjz41j}f)A>IBw%nj*FZ=F*CIzI`EABtpB{HDLH zIok}MO$gB(X!NO)(%sgst9&0gqa0inL{}KpX+AF`mXqm`{gV7a2~)M!?VL6}<~wk* z0mvO09>zo|&_G*hw1Q_H%Z3xMh+gcp2Qo>qPBd zEt|*(L<-FCmH-48Cp&UYd}!FO69h57>?W=fFv%JZGyUA9c?Q83lgfv`P55P*nGCSD zj+VK$HNE&M2wWMXLkYxC-F46q1+EC$B5p9ouy&&58DkEp_^P9M$$fQ!X<7^*2WEEi zNG;ep^Rs;Yj$iGkk0vzO_?eNDG@<6l`*Kh;?l92!Y zpkj6}O&~7`oJ7=}lx$6%Tn!vd09RMnFBUeIjz$J{CSPnF%+k+z2myc`kPsGBcFQ=; zboJ7nO}+2jmsP0?r&+0qs_BBAu@r)z(GnLzq)rb6x!@sOn%2=j@2#GkjXYx_3PL#XPd2vA}m*^!2?&+cOb%Wm6ROtVI`TcOs3l(!Eh@b$a4Ba5${60VX`d%q{ z&5L{h%jK7(IDG4#;vzxyw-iizh~J}r{M6a_+^)Ienc?Z54fRe@c;dpD44(xgf-E8% zO5f$UevRIE8VbE*-Gu_{v5I_&=V92~S%5V2YriI}H1tn#0)4Ju_1En}-{-Wi*fvz@ z3zH!uK4k$5!U$8KQTV+$kDt+|gZTvRErgbpZiEksiL9xR5mZ@#u^)OKX){za636$6 znM?d3WUz_iuv-VMqLmvoGn^0t*@Y|k9q!}4I~S=@9cHt-5yJK<4NfM0R3x`87VO;=$=nY^tw|>3y z44@oc={)8afL$dg5N2N8A4EML4>lCWL?kH|R;Z_q2D3jb5*bKB`ZQ z)Vqk%6ZgVM1Wa%M0tJJAu^-zNPf~4BQDvNbbGW?8H#)&quDgWLGiUA-(+w;7-7H4w znjJb%sDp{oXJk9oj(tVxz-|>#Pf}oalJdN4QIQL4mwbvoo%C#hhfo)DmmRFiY{H+? zRAFX(YIFnz6&)FJbZYz$iW(Y0Tgd2#N{2F%Tx}{#`Sz5&5|r%>)2!yY&iuS%=gpaC zvWk?|tFP~W>**|^(1k$$V*be2yuY>MKO0q)my@GkV4()dV|$hjtTl^zQVV*1mDQpa ztY;c}8|SDg;M;Rn)U5yeMn08Uw)%nqxWJf6&^NV^{7IzKf;wP-FK{Cixh*>@OKqiw#f+ z0}oVoCF%A*i@zx@%8Q9ufBP2YtURZJRarvLLoY3}N-dN`5s*Z|VA&nmBN(s=dg0M2)e(FJ@MRc zaS(ZR3aD98#Q_dYd0G~V>{g9C

AFpNb&!jApo~sDDqt|~6OXf4 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 U69-Q9|9#(0jVukH>*Hho2h^wj?EnA( diff --git a/data/skins/cartoon/data/gui/icons/online/menu_find_server_hover.png b/data/skins/cartoon/data/gui/icons/online/menu_find_server_hover.png index 973f00aca359d6b5f01996cea87d7badb0777ea8..4d278a1667ee48f8abda8adb02c6b89034102db1 100644 GIT binary patch literal 21832 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 DuJ=v+ literal 6046 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

  • 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 diff --git a/data/skins/cartoon/data/gui/icons/online/menu_quick_play.png b/data/skins/cartoon/data/gui/icons/online/menu_quick_play.png index d620c688ef66c0ea8b58dfeb3f1121ffa98e0678..f9fdddd18e48f3d1436ec037ad3628c6d91ac73a 100644 GIT binary patch literal 14024 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 D+3-NS literal 5280 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 Date: Wed, 21 May 2025 22:06:49 +0200 Subject: [PATCH 749/830] Add RISC-V to linux build script + some small fixes --- CMakeLists.txt | 7 +++++-- tools/linux_builder.sh | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb5e81cf8ed..c0dd4227302 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ option(SERVER_ONLY "Create a server only (i.e. no graphics or sound)" OFF) option(CHECK_ASSETS "Check if assets are installed in ../stk-assets" ON) option(USE_SYSTEM_ANGELSCRIPT "Use system angelscript instead of built-in angelscript. If you enable this option, make sure to use a compatible version." OFF) option(USE_SYSTEM_ENET "Use system ENet instead of the built-in version, when available." ON) +option(USE_SYSTEM_MCPP "Use system mcpp instead of the built-in version, when available." ON) CMAKE_DEPENDENT_OPTION(USE_IPV6 "Allow create or connect to game server with IPv6 address, system enet will not be used." ON "NOT USE_SWITCH" OFF) option(USE_SYSTEM_WIIUSE "Use system WiiUse instead of the built-in version, when available." OFF) @@ -320,8 +321,10 @@ if(NOT SERVER_ONLY) endif() # Libmcpp -find_library(MCPP_LIBRARY NAMES mcpp libmcpp) -find_path(MCPP_INCLUDEDIR NAMES mcpp_lib.h PATHS) +if (USE_SYSTEM_MCPP) + find_library(MCPP_LIBRARY NAMES mcpp libmcpp) + find_path(MCPP_INCLUDEDIR NAMES mcpp_lib.h PATHS) +endif() if (NOT MCPP_LIBRARY OR NOT MCPP_INCLUDEDIR) add_subdirectory("${PROJECT_SOURCE_DIR}/lib/mcpp") include_directories(BEFORE "${PROJECT_SOURCE_DIR}/lib/mcpp") diff --git a/tools/linux_builder.sh b/tools/linux_builder.sh index 9c511fdf247..3b2fae4cb88 100755 --- a/tools/linux_builder.sh +++ b/tools/linux_builder.sh @@ -55,6 +55,7 @@ export SCHROOT_32BIT_NAME="chroot-buster32" export SCHROOT_64BIT_NAME="chroot-buster64" export SCHROOT_ARMV7_NAME="chroot-buster-armhf" export SCHROOT_ARM64_NAME="chroot-buster-arm64" +export SCHROOT_RISCV_NAME="chroot-trixie-riscv64" export STKCODE_DIR="$DIRNAME/.." export STKASSETS_DIR="$STKCODE_DIR/../supertuxkart-assets" @@ -483,7 +484,7 @@ build_stk() cp -a -f "$DEPENDENCIES_DIR/../lib/sdl2/"* "$DEPENDENCIES_DIR/sdl2" cd "$DEPENDENCIES_DIR/sdl2" - ./configure --prefix="$INSTALL_DIR" && + ./configure --prefix="$INSTALL_DIR" --disable-audio && make -j$THREADS_NUMBER && make install check_error @@ -578,6 +579,8 @@ build_stk() -DUSE_SYSTEM_ANGELSCRIPT=0 \ -DUSE_SYSTEM_ENET=0 \ -DUSE_SYSTEM_WIIUSE=0 \ + -DUSE_SYSTEM_SQUISH=0 \ + -DUSE_SYSTEM_MCPP=0 \ -DUSE_CRYPTO_OPENSSL=0 \ -DENABLE_WAYLAND_DEVICE=0 \ -DBC7_ISPC=$HAS_ISPC \ @@ -786,5 +789,6 @@ create_package "$SCHROOT_32BIT_NAME" "x86" "elf32-i386" create_package "$SCHROOT_64BIT_NAME" "x86_64" "elf64-x86-64" create_package "$SCHROOT_ARMV7_NAME" "armv7" "elf32-littlearm" create_package "$SCHROOT_ARM64_NAME" "arm64" "elf64-littleaarch64" +create_package "$SCHROOT_RISCV_NAME" "riscv64" "elf64-littleriscv" echo "Success." From cc3ae93137ca80692f73a4e9fe29b39464a61dcf Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Wed, 21 May 2025 23:20:09 +0200 Subject: [PATCH 750/830] Improve textbox highlight for the cartoon coal skin --- data/skins/cartoon-coal/stkskin.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/skins/cartoon-coal/stkskin.xml b/data/skins/cartoon-coal/stkskin.xml index bbf7f6318b5..7d46bedd630 100644 --- a/data/skins/cartoon-coal/stkskin.xml +++ b/data/skins/cartoon-coal/stkskin.xml @@ -281,12 +281,12 @@ Here you can configure advanced theming rules for this skin - + - + - - + + From 05a0fb3a647f972243c57e4c1dd4b4fa66ae0543 Mon Sep 17 00:00:00 2001 From: Deve Date: Fri, 23 May 2025 23:06:01 +0200 Subject: [PATCH 751/830] Fix regressions from recent widget changes --- src/guiengine/widgets/icon_button_widget.cpp | 1 + src/guiengine/widgets/label_widget.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/guiengine/widgets/icon_button_widget.cpp b/src/guiengine/widgets/icon_button_widget.cpp index 13e288e4cce..0da25356c46 100644 --- a/src/guiengine/widgets/icon_button_widget.cpp +++ b/src/guiengine/widgets/icon_button_widget.cpp @@ -333,6 +333,7 @@ void IconButtonWidget::setLabelFont() } else { + m_label->setOverrideFont(NULL); const bool word_wrap = (m_properties[PROP_WORD_WRAP] == "true"); const int max_w = m_label->getAbsolutePosition().getWidth(); diff --git a/src/guiengine/widgets/label_widget.cpp b/src/guiengine/widgets/label_widget.cpp index 97ff5c7770a..9cd30f6541c 100644 --- a/src/guiengine/widgets/label_widget.cpp +++ b/src/guiengine/widgets/label_widget.cpp @@ -204,7 +204,7 @@ void LabelWidget::setScrollSpeed(float speed) void LabelWidget::resize() { // Reduce the font size of normal text if it overflows - if ((m_type != TITLE && m_type != SMALL_TITLE && m_type != TINY_TITLE)) + if (m_scroll_speed == 0 && m_type != TITLE && m_type != SMALL_TITLE && m_type != TINY_TITLE) { if( ((int)GUIEngine::getFont()->getDimension(m_text.c_str()).Width > this->m_w) && From bedfcba1e12c9240c4e9e4813b6aa12aac4cb5c7 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sun, 25 May 2025 13:28:25 +0200 Subject: [PATCH 752/830] Allow a skin to fetch textures from its base theme This is useful when the same texture is needed but not used by the same element (multiplayer name spinners). Also move some duplicated code in a function. --- src/guiengine/skin.cpp | 75 +++++++++++++++++++++++------------------- src/guiengine/skin.hpp | 5 ++- 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index 40464026c22..61f26df7e0d 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -72,12 +72,12 @@ namespace SkinConfig static std::vector m_icon_theme_paths; static bool m_font; - static void parseElement(const XMLNode* node) + static void parseElement(const XMLNode* node, std::vector& skin_paths) { std::string type; std::string state = "neutral"; std::string image; - bool common_img = false; + bool common_img = false, parent_img = false; int leftborder = 0, rightborder=0, topborder=0, bottomborder=0; float hborder_out_portion = 0.5f, vborder_out_portion = 1.0f; float horizontal_inner_padding = 0.0f, vertical_inner_padding = 0.0f; @@ -116,6 +116,7 @@ namespace SkinConfig node->get("areas", &areas); node->get("common", &common_img); + node->get("parent", &parent_img); BoxRenderParams new_param; new_param.m_left_border = leftborder; @@ -130,12 +131,23 @@ namespace SkinConfig new_param.m_vertical_margin = vertical_margin; new_param.m_preserve_h_aspect_ratios = preserve_h_aspect_ratios; - // call last since it calculates coords considering all other - // parameters + // The call to an image in the parent folder only allows to go one level higher. + // Having a child skin rely on how many levels deeper it is in a chain of base themes + // to fetch a texture would bring its own issues, although this code could be + // easily adapted to allow it if truly needed. + if (parent_img && skin_paths.size() == 1) + { + parent_img = false; + Log::error("skin", "Requesting images from the base theme folder without a base theme\n"); + } + new_param.setTexture(common_img ? irr_driver->getTexture(FileManager::SKIN, std::string("common/") + image) : + parent_img ? irr_driver->getTexture(skin_paths[skin_paths.size() - 2] + "/" + image) : irr_driver->getTexture(m_data_path + image)); + // call last since it calculates coords considering all other + // parameters if (areas.size() > 0) { new_param.areas = 0; @@ -184,7 +196,7 @@ namespace SkinConfig * \brief loads skin information from a STK skin file * \throw std::runtime_error if file cannot be read */ - static void loadFromFile(std::string file, bool clear_prev_params) + static void loadFromFile(std::string file, bool clear_prev_params, std::vector& skin_paths) { m_data_path.clear(); if (clear_prev_params) @@ -231,7 +243,7 @@ namespace SkinConfig if (node->getName() == "element") { - parseElement(node); + parseElement(node, skin_paths); } else if (node->getName() == "color") { @@ -559,42 +571,18 @@ Skin::Skin(IGUISkin* fallback_skin) try { - std::vector load_chain = SkinConfig::getDependencyChain(skin_id); - - bool reset = true; - for (auto skin_id : load_chain) - { - std::string skin_name = skin_id.find("addon_") != std::string::npos ? - file_manager->getAddonsFile( - std::string("skins/") + skin_id.substr(6) + "/stkskin.xml") : - file_manager->getAsset(FileManager::SKIN, skin_id + "/stkskin.xml"); - - Log::info("GUI", "Loading skin data from file: %s", skin_name.c_str()); - SkinConfig::loadFromFile(skin_name, reset); - reset = false; - } + chainLoad(skin_id); } catch (std::runtime_error& e) { (void)e; // avoid compiler warning // couldn't load skin. Try to revert to default + Log::error("GUI", "Could not load skin, reverting to default."); UserConfigParams::m_skin_file.revertToDefaults(); skin_id = UserConfigParams::m_skin_file; - std::vector load_chain = SkinConfig::getDependencyChain(skin_id); - - bool reset = true; - for (auto skin_id : load_chain) - { - std::string skin_name = skin_id.find("addon_") != std::string::npos ? - file_manager->getAddonsFile( - std::string("skins/") + skin_id.substr(6) + "/stkskin.xml") : - file_manager->getAsset(FileManager::SKIN, skin_id + "/stkskin.xml"); - Log::info("GUI", "Loading skin data from file: %s", skin_name.c_str()); - SkinConfig::loadFromFile(skin_name, reset); - reset = false; - } + chainLoad(skin_id); } m_bg_image = NULL; @@ -614,6 +602,27 @@ Skin::~Skin() m_fallback_skin->drop(); } // ~Skin +void Skin::chainLoad(std::string skin_id) +{ + m_skin_paths.clear(); + std::vector load_chain = SkinConfig::getDependencyChain(skin_id); + + bool reset = true; + for (auto skin_id : load_chain) + { + std::string skin_path = skin_id.find("addon_") != std::string::npos ? + file_manager->getAddonsFile(std::string("skins/") + skin_id.substr(6)) : + file_manager->getAsset(FileManager::SKIN, skin_id); + m_skin_paths.push_back(skin_path); + + skin_path += "/stkskin.xml"; + + Log::info("GUI", "Loading skin data from file: %s", skin_path.c_str()); + SkinConfig::loadFromFile(skin_path, reset, m_skin_paths); + reset = false; + } +} // chainLoad + // ---------------------------------------------------------------------------- void Skin::drawBgImage() { diff --git a/src/guiengine/skin.hpp b/src/guiengine/skin.hpp index b7c7f0db741..412e65ea608 100644 --- a/src/guiengine/skin.hpp +++ b/src/guiengine/skin.hpp @@ -280,11 +280,13 @@ namespace GUIEngine { gui::IGUISkin* m_fallback_skin; - video::ITexture* m_bg_image; std::vector m_tooltips; std::vector m_tooltip_at_mouse; + // The paths to the folder of the active skin and its base themes + std::vector m_skin_paths; + LEAK_CHECK() void drawBoxFromStretchableTexture(SkinWidgetContainer* w, @@ -345,6 +347,7 @@ namespace GUIEngine ~Skin(); + void chainLoad(std::string skin_id); void resetBackgroundImage() { m_bg_image = NULL; } static video::SColor getColor(const std::string &name); void renderSections(PtrVector* within_vector=NULL); From afa147a63dd3b189a48bc7c7beda84d17cfc7506 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Sun, 25 May 2025 13:42:44 +0200 Subject: [PATCH 753/830] Correct colors for the player name spinners in cartoon themes (fix #5432) --- data/skins/cartoon-coal/stkskin.xml | 15 +++++++-------- data/skins/cartoon-desert/stkskin.xml | 15 +++++++-------- data/skins/cartoon-forest/stkskin.xml | 15 +++++++-------- data/skins/cartoon-ocean/stkskin.xml | 15 +++++++-------- data/skins/cartoon-ruby/stkskin.xml | 15 +++++++-------- data/skins/cartoon/spinner_black.png | Bin 0 -> 3620 bytes 6 files changed, 35 insertions(+), 40 deletions(-) create mode 100644 data/skins/cartoon/spinner_black.png diff --git a/data/skins/cartoon-coal/stkskin.xml b/data/skins/cartoon-coal/stkskin.xml index 7d46bedd630..a5dbd973845 100644 --- a/data/skins/cartoon-coal/stkskin.xml +++ b/data/skins/cartoon-coal/stkskin.xml @@ -155,23 +155,22 @@ Here you can configure advanced theming rules for this skin left_border="104" right_border="104" top_border="0" bottom_border="36" preserve_h_aspect_ratios="true" hborder_out_portion="0.0"/>--> - - + - - - ---> + preserve_h_aspect_ratios="true" hborder_out_portion="0.0" /> diff --git a/data/skins/cartoon-desert/stkskin.xml b/data/skins/cartoon-desert/stkskin.xml index eeadeff4efb..22efa1ca639 100644 --- a/data/skins/cartoon-desert/stkskin.xml +++ b/data/skins/cartoon-desert/stkskin.xml @@ -155,23 +155,22 @@ Here you can configure advanced theming rules for this skin left_border="104" right_border="104" top_border="0" bottom_border="36" preserve_h_aspect_ratios="true" hborder_out_portion="0.0"/>--> - - + - - - ---> + preserve_h_aspect_ratios="true" hborder_out_portion="0.0" /> diff --git a/data/skins/cartoon-forest/stkskin.xml b/data/skins/cartoon-forest/stkskin.xml index a742a4a0404..eda747b48e1 100644 --- a/data/skins/cartoon-forest/stkskin.xml +++ b/data/skins/cartoon-forest/stkskin.xml @@ -155,23 +155,22 @@ Here you can configure advanced theming rules for this skin left_border="104" right_border="104" top_border="0" bottom_border="36" preserve_h_aspect_ratios="true" hborder_out_portion="0.0"/>--> - - + - - - ---> + preserve_h_aspect_ratios="true" hborder_out_portion="0.0" /> diff --git a/data/skins/cartoon-ocean/stkskin.xml b/data/skins/cartoon-ocean/stkskin.xml index a0781e3ae36..62531729c32 100644 --- a/data/skins/cartoon-ocean/stkskin.xml +++ b/data/skins/cartoon-ocean/stkskin.xml @@ -155,23 +155,22 @@ Here you can configure advanced theming rules for this skin left_border="104" right_border="104" top_border="0" bottom_border="36" preserve_h_aspect_ratios="true" hborder_out_portion="0.0"/>--> - - + - - - ---> + preserve_h_aspect_ratios="true" hborder_out_portion="0.0" /> diff --git a/data/skins/cartoon-ruby/stkskin.xml b/data/skins/cartoon-ruby/stkskin.xml index 05cbc381f50..15249f5f2d0 100644 --- a/data/skins/cartoon-ruby/stkskin.xml +++ b/data/skins/cartoon-ruby/stkskin.xml @@ -156,23 +156,22 @@ Here you can configure advanced theming rules for this skin left_border="104" right_border="104" top_border="0" bottom_border="36" preserve_h_aspect_ratios="true" hborder_out_portion="0.0"/>--> - - + - - - ---> + preserve_h_aspect_ratios="true" hborder_out_portion="0.0" /> diff --git a/data/skins/cartoon/spinner_black.png b/data/skins/cartoon/spinner_black.png new file mode 100644 index 0000000000000000000000000000000000000000..d15df9b35f0037c6c6af75d01154c98a84071ba1 GIT binary patch literal 3620 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 MYozmD+v(|l0jE{Tt^fc4 literal 0 HcmV?d00001 From db8be22467854fdf8420895c5e29ab2af09cdb93 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 25 May 2025 16:36:12 +0400 Subject: [PATCH 754/830] Movements from crown to asset manager, minor edits --- src/utils/crown_manager.cpp | 122 +++++------------------------- src/utils/hourglass_reason.cpp | 65 ++++++++++++++++ src/utils/hourglass_reason.hpp | 12 ++- src/utils/lobby_asset_manager.cpp | 89 ++++++++++++++-------- src/utils/lobby_asset_manager.hpp | 2 + src/utils/lobby_settings.cpp | 2 +- src/utils/tournament.cpp | 15 ++-- 7 files changed, 166 insertions(+), 141 deletions(-) create mode 100644 src/utils/hourglass_reason.cpp diff --git a/src/utils/crown_manager.cpp b/src/utils/crown_manager.cpp index b0ab6c369de..d72121c1880 100644 --- a/src/utils/crown_manager.cpp +++ b/src/utils/crown_manager.cpp @@ -30,27 +30,6 @@ #include - -namespace -{ - const std::string g_hr_unknown = "For some reason, server doesn't know about the hourglass status of player %s."; - const std::string g_hr_none = "%s can play (but if hourglass is present, there are not enough slots on the server)."; - const std::string g_hr_absent_peer = "Player %s is not present on the server."; - const std::string g_hr_not_tournament = "%s is not a tournament player for this game."; - const std::string g_hr_limit_spectator = "Not enough slots to fit %s."; - const std::string g_hr_no_karts_after = "After applying all kart filters, %s doesn't have karts to play."; - const std::string g_hr_no_maps_after = "After applying all map filters, %s doesn't have maps to play."; - const std::string g_hr_lack_required_maps = "%s lacks required maps."; - const std::string g_hr_addon_karts_thr = "Player %s doesn't have enough addon karts."; - const std::string g_hr_addon_tracks_thr = "Player %s doesn't have enough addon tracks."; - const std::string g_hr_addon_arenas_thr = "Player %s doesn't have enough addon arenas."; - const std::string g_hr_addon_fields_thr = "Player %s doesn't have enough addon fields."; - const std::string g_hr_off_karts_thr = "The number of official karts for %s is lower than the threshold."; - const std::string g_hr_off_tracks_thr = "The number of official tracks for %s is lower than the threshold."; - const std::string g_hr_empty = ""; -} // namespace -//----------------------------------------------------------------------------- - void CrownManager::setupContextUser() { m_only_host_riding = ServerConfig::m_only_host_riding; @@ -78,16 +57,15 @@ std::set>& CrownManager::getSpectatorsByLimit(bool upda player_limit = std::min(player_limit, current_max_players_in_game); // only 10 players allowed for FFA and 14 for CTF and soccer - if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_FREE_FOR_ALL) + auto minor_mode = RaceManager::get()->getMinorMode(); + + if (minor_mode == RaceManager::MINOR_MODE_FREE_FOR_ALL) player_limit = std::min(player_limit, 10u); - if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) + if (minor_mode == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG) player_limit = std::min(player_limit, 14u); - if (RaceManager::get()->getMinorMode() == - RaceManager::MINOR_MODE_SOCCER) + if (minor_mode == RaceManager::MINOR_MODE_SOCCER) player_limit = std::min(player_limit, 14u); unsigned ingame_players = 0, waiting_players = 0, total_players = 0; @@ -161,82 +139,34 @@ bool CrownManager::canRace(std::shared_ptr peer, int known_number) if (it != m_why_peer_cannot_play.end()) return it->second == 0; + auto& value = m_why_peer_cannot_play[peer]; + if (!peer || peer->getPlayerProfiles().empty()) { - m_why_peer_cannot_play[peer] = HR_ABSENT_PEER; + value = HR_ABSENT_PEER; return false; } - std::string username = peer->getMainName(); - if (getTournament() && !getTournament()->canPlay(username)) + if (getTournament() && !getTournament()->canPlay(peer->getMainName())) { - m_why_peer_cannot_play[peer] = HR_NOT_A_TOURNAMENT_PLAYER; + value = HR_NOT_A_TOURNAMENT_PLAYER; return false; } else if (m_spectators_by_limit.find(peer) != m_spectators_by_limit.end()) { - m_why_peer_cannot_play[peer] = HR_SPECTATOR_BY_LIMIT; + value = HR_SPECTATOR_BY_LIMIT; return false; } - if (!getAssetManager()->getMissingAssets(peer).empty()) - { - m_why_peer_cannot_play[peer] = HR_LACKING_REQUIRED_MAPS; - return false; - } + int new_value = HR_NONE; - if (peer->addon_karts_count < getAssetManager()->getAddonKartsPlayThreshold()) + new_value = getAssetManager()->checkCanPlay(peer, known_number); + if (new_value != HR_NONE) { - m_why_peer_cannot_play[peer] = HR_ADDON_KARTS_PLAY_THRESHOLD; + value = new_value; return false; } - if (peer->addon_tracks_count < getAssetManager()->getAddonTracksPlayThreshold()) - { - m_why_peer_cannot_play[peer] = HR_ADDON_TRACKS_PLAY_THRESHOLD; - return false; - } - if (peer->addon_arenas_count < getAssetManager()->getAddonArenasPlayThreshold()) - { - m_why_peer_cannot_play[peer] = HR_ADDON_ARENAS_PLAY_THRESHOLD; - return false; - } - if (peer->addon_soccers_count < getAssetManager()->getAddonSoccersPlayThreshold()) - { - m_why_peer_cannot_play[peer] = HR_ADDON_FIELDS_PLAY_THRESHOLD; - return false; - } - - std::set maps = peer->getClientAssets().second; - std::set karts = peer->getClientAssets().first; - float karts_fraction = getAssetManager()->officialKartsFraction(karts); - float maps_fraction = getAssetManager()->officialMapsFraction(maps); - - if (karts_fraction < getAssetManager()->getOfficialKartsPlayThreshold()) - { - m_why_peer_cannot_play[peer] = HR_OFFICIAL_KARTS_PLAY_THRESHOLD; - return false; - } - if (maps_fraction < getAssetManager()->getOfficialTracksPlayThreshold()) - { - m_why_peer_cannot_play[peer] = HR_OFFICIAL_TRACKS_PLAY_THRESHOLD; - return false; - } - - getAssetManager()->applyAllMapFilters(maps, true, known_number); - getAssetManager()->applyAllKartFilters(username, karts, false); - - if (karts.empty()) - { - m_why_peer_cannot_play[peer] = HR_NO_KARTS_AFTER_FILTER; - return false; - } - if (maps.empty()) - { - m_why_peer_cannot_play[peer] = HR_NO_MAPS_AFTER_FILTER; - return false; - } - - m_why_peer_cannot_play[peer] = 0; + value = HR_NONE; return true; } // canRace //----------------------------------------------------------------------------- @@ -249,26 +179,10 @@ std::string CrownManager::getWhyPeerCannotPlayAsString( if (it == m_why_peer_cannot_play.end()) { Log::error("LobbySettings", "Hourglass status undefined for a player!"); - return g_hr_unknown; + return Conversions::hourglassReasonToString(HR_UNKNOWN); } - switch (it->second) - { - case HR_NONE: return g_hr_none; - case HR_ABSENT_PEER: return g_hr_absent_peer; - case HR_NOT_A_TOURNAMENT_PLAYER: return g_hr_not_tournament; - case HR_SPECTATOR_BY_LIMIT: return g_hr_limit_spectator; - case HR_NO_KARTS_AFTER_FILTER: return g_hr_no_karts_after; - case HR_NO_MAPS_AFTER_FILTER: return g_hr_no_maps_after; - case HR_LACKING_REQUIRED_MAPS: return g_hr_lack_required_maps; - case HR_ADDON_KARTS_PLAY_THRESHOLD: return g_hr_addon_karts_thr; - case HR_ADDON_TRACKS_PLAY_THRESHOLD: return g_hr_addon_tracks_thr; - case HR_ADDON_ARENAS_PLAY_THRESHOLD: return g_hr_addon_arenas_thr; - case HR_ADDON_FIELDS_PLAY_THRESHOLD: return g_hr_addon_fields_thr; - case HR_OFFICIAL_KARTS_PLAY_THRESHOLD: return g_hr_off_karts_thr; - case HR_OFFICIAL_TRACKS_PLAY_THRESHOLD: return g_hr_off_tracks_thr; - default: return g_hr_empty; - } + return Conversions::hourglassReasonToString((HourglassReason)it->second); } // getWhyPeerCannotPlayAsString //----------------------------------------------------------------------------- diff --git a/src/utils/hourglass_reason.cpp b/src/utils/hourglass_reason.cpp new file mode 100644 index 00000000000..a246fe6e9f6 --- /dev/null +++ b/src/utils/hourglass_reason.cpp @@ -0,0 +1,65 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2024-2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/hourglass_reason.hpp" + + +namespace +{ + const std::string g_hr_unknown = "For some reason, server doesn't know about the hourglass status of player %s."; + const std::string g_hr_none = "%s can play (but if hourglass is present, there are not enough slots on the server)."; + const std::string g_hr_absent_peer = "Player %s is not present on the server."; + const std::string g_hr_not_tournament = "%s is not a tournament player for this game."; + const std::string g_hr_limit_spectator = "Not enough slots to fit %s."; + const std::string g_hr_no_karts_after = "After applying all kart filters, %s doesn't have karts to play."; + const std::string g_hr_no_maps_after = "After applying all map filters, %s doesn't have maps to play."; + const std::string g_hr_lack_required_maps = "%s lacks required maps."; + const std::string g_hr_addon_karts_thr = "Player %s doesn't have enough addon karts."; + const std::string g_hr_addon_tracks_thr = "Player %s doesn't have enough addon tracks."; + const std::string g_hr_addon_arenas_thr = "Player %s doesn't have enough addon arenas."; + const std::string g_hr_addon_fields_thr = "Player %s doesn't have enough addon fields."; + const std::string g_hr_off_karts_thr = "The number of official karts for %s is lower than the threshold."; + const std::string g_hr_off_tracks_thr = "The number of official tracks for %s is lower than the threshold."; + const std::string g_hr_empty = ""; +} // namespace +//----------------------------------------------------------------------------- + +namespace Conversions +{ + std::string hourglassReasonToString(HourglassReason reason) + { + switch (reason) + { + case HR_UNKNOWN: return g_hr_unknown; + case HR_NONE: return g_hr_none; + case HR_ABSENT_PEER: return g_hr_absent_peer; + case HR_NOT_A_TOURNAMENT_PLAYER: return g_hr_not_tournament; + case HR_SPECTATOR_BY_LIMIT: return g_hr_limit_spectator; + case HR_NO_KARTS_AFTER_FILTER: return g_hr_no_karts_after; + case HR_NO_MAPS_AFTER_FILTER: return g_hr_no_maps_after; + case HR_LACKING_REQUIRED_MAPS: return g_hr_lack_required_maps; + case HR_ADDON_KARTS_PLAY_THRESHOLD: return g_hr_addon_karts_thr; + case HR_ADDON_TRACKS_PLAY_THRESHOLD: return g_hr_addon_tracks_thr; + case HR_ADDON_ARENAS_PLAY_THRESHOLD: return g_hr_addon_arenas_thr; + case HR_ADDON_FIELDS_PLAY_THRESHOLD: return g_hr_addon_fields_thr; + case HR_OFFICIAL_KARTS_PLAY_THRESHOLD: return g_hr_off_karts_thr; + case HR_OFFICIAL_TRACKS_PLAY_THRESHOLD: return g_hr_off_tracks_thr; + default: return g_hr_empty; + } + } +} \ No newline at end of file diff --git a/src/utils/hourglass_reason.hpp b/src/utils/hourglass_reason.hpp index a5d6238603f..8de4d023ef9 100644 --- a/src/utils/hourglass_reason.hpp +++ b/src/utils/hourglass_reason.hpp @@ -19,6 +19,8 @@ #ifndef HOURGLASS_REASON_HPP #define HOURGLASS_REASON_HPP +#include + enum HourglassReason : int32_t { HR_NONE = 0, @@ -33,7 +35,15 @@ enum HourglassReason : int32_t HR_ADDON_ARENAS_PLAY_THRESHOLD = (1 << 8), HR_ADDON_FIELDS_PLAY_THRESHOLD = (1 << 9), HR_OFFICIAL_KARTS_PLAY_THRESHOLD = (1 << 10), - HR_OFFICIAL_TRACKS_PLAY_THRESHOLD = (1 << 11) + HR_OFFICIAL_TRACKS_PLAY_THRESHOLD = (1 << 11), + + + HR_UNKNOWN = 0xEA7BEEF, }; +namespace Conversions +{ + std::string hourglassReasonToString(HourglassReason reason); +} + #endif // HOURGLASS_REASON_HPP diff --git a/src/utils/lobby_asset_manager.cpp b/src/utils/lobby_asset_manager.cpp index 075a4717195..5bf11455736 100644 --- a/src/utils/lobby_asset_manager.cpp +++ b/src/utils/lobby_asset_manager.cpp @@ -241,23 +241,21 @@ void LobbyAssetManager::onServerSetup() void LobbyAssetManager::eraseAssetsWithPeers( const std::vector>& peers) { - std::set karts_erase, tracks_erase; + std::set karts_erase, maps_erase; for (const auto& peer: peers) { if (peer) { peer->eraseServerKarts(m_available_kts.first, karts_erase); - peer->eraseServerTracks(m_available_kts.second, tracks_erase); + peer->eraseServerTracks(m_available_kts.second, maps_erase); } } for (const std::string& kart_erase : karts_erase) - { m_available_kts.first.erase(kart_erase); - } - for (const std::string& track_erase : tracks_erase) - { - m_available_kts.second.erase(track_erase); - } + + for (const std::string& map_erase : maps_erase) + m_available_kts.second.erase(map_erase); + } // eraseAssetsWithPeers //----------------------------------------------------------------------------- @@ -347,7 +345,7 @@ bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer, } ott = ott / (float)m_official_kts.second.size(); - std::set karts_erase, tracks_erase; + std::set karts_erase, maps_erase; for (const std::string& server_kart : m_entering_kts.first) { if (client_karts.find(server_kart) == client_karts.end()) @@ -359,7 +357,7 @@ bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer, { if (client_tracks.find(server_track) == client_tracks.end()) { - tracks_erase.insert(server_track); + maps_erase.insert(server_track); } } @@ -401,7 +399,7 @@ bool LobbyAssetManager::handleAssetsForPeer(std::shared_ptr peer, bad = true; } - if (tracks_erase.size() == m_entering_kts.second.size()) + if (maps_erase.size() == m_entering_kts.second.size()) { Log::verbose("LobbyAssetManager", "Bad player: no common tracks with server"); bad = true; @@ -464,42 +462,33 @@ std::array LobbyAssetManager::getAddonScores( size_t addon_soccer = 0; for (auto& kart : m_addon_kts.first) - { if (client_karts.find(kart) != client_karts.end()) addon_kart++; - } + for (auto& track : m_addon_kts.second) - { if (client_tracks.find(track) != client_tracks.end()) addon_track++; - } + for (auto& arena : m_addon_arenas) - { if (client_tracks.find(arena) != client_tracks.end()) addon_arena++; - } + for (auto& soccer : m_addon_soccers) - { if (client_tracks.find(soccer) != client_tracks.end()) addon_soccer++; - } if (!m_addon_kts.first.empty()) - { addons_scores[AS_KART] = addon_kart; - } + if (!m_addon_kts.second.empty()) - { addons_scores[AS_TRACK] = addon_track; - } + if (!m_addon_arenas.empty()) - { addons_scores[AS_ARENA] = addon_arena; - } + if (!m_addon_soccers.empty()) - { addons_scores[AS_SOCCER] = addon_soccer; - } + return addons_scores; } // getAddonScores //----------------------------------------------------------------------------- @@ -513,15 +502,15 @@ std::string LobbyAssetManager::getAnyMapForVote() bool LobbyAssetManager::checkIfNoCommonMaps( const std::pair, std::set>& assets) { - std::set tracks_erase; + std::set maps_erase; for (const std::string& server_track : m_available_kts.second) { if (assets.second.find(server_track) == assets.second.end()) { - tracks_erase.insert(server_track); + maps_erase.insert(server_track); } } - return tracks_erase.size() == m_available_kts.second.size(); + return maps_erase.size() == m_available_kts.second.size(); } // checkIfNoCommonMaps //----------------------------------------------------------------------------- @@ -703,6 +692,46 @@ void LobbyAssetManager::applyGlobalKartsFilter(FilterContext& kart_context) cons } // applyGlobalKartsFilter //----------------------------------------------------------------------------- +int LobbyAssetManager::checkCanPlay(std::shared_ptr peer, int known_number) +{ + if (!getMissingAssets(peer).empty()) + return HR_LACKING_REQUIRED_MAPS; + + if (peer->addon_karts_count < getAddonKartsPlayThreshold()) + return HR_ADDON_KARTS_PLAY_THRESHOLD; + + if (peer->addon_tracks_count < getAddonTracksPlayThreshold()) + return HR_ADDON_TRACKS_PLAY_THRESHOLD; + + if (peer->addon_arenas_count < getAddonArenasPlayThreshold()) + return HR_ADDON_ARENAS_PLAY_THRESHOLD; + + if (peer->addon_soccers_count < getAddonSoccersPlayThreshold()) + return HR_ADDON_FIELDS_PLAY_THRESHOLD; + + std::set karts = peer->getClientAssets().first; + std::set maps = peer->getClientAssets().second; + + float karts_fraction = officialKartsFraction(karts); + if (karts_fraction < getOfficialKartsPlayThreshold()) + return HR_OFFICIAL_KARTS_PLAY_THRESHOLD; + + float maps_fraction = officialMapsFraction(maps); + if (maps_fraction < getOfficialTracksPlayThreshold()) + return HR_OFFICIAL_TRACKS_PLAY_THRESHOLD; + + applyAllKartFilters(peer->getMainName(), karts, false); + if (karts.empty()) + return HR_NO_KARTS_AFTER_FILTER; + + applyAllMapFilters(maps, true, known_number); + if (maps.empty()) + return HR_NO_MAPS_AFTER_FILTER; + + return HR_NONE; +} // checkCanPlay +//----------------------------------------------------------------------------- + void LobbyAssetManager::initAvailableTracks() { m_global_filter = TrackFilter(ServerConfig::m_only_played_tracks_string); diff --git a/src/utils/lobby_asset_manager.hpp b/src/utils/lobby_asset_manager.hpp index cefffc1c3e1..6844ac4a1b6 100644 --- a/src/utils/lobby_asset_manager.hpp +++ b/src/utils/lobby_asset_manager.hpp @@ -84,6 +84,8 @@ class LobbyAssetManager: public LobbyContextComponent void applyGlobalFilter(FilterContext& map_context) const; void applyGlobalKartsFilter(FilterContext& kart_context) const; + int checkCanPlay(std::shared_ptr peer, int known_number); + std::string getKartForBadKartChoice( std::shared_ptr peer, const std::string& username, diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index 926f7970b24..cbe8182f3c5 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -692,4 +692,4 @@ std::string LobbySettings::getPowerPassword(int level) const Log::error("LobbySettings", "Invoked getPowerPassword with level = %d", level); return ""; -} \ No newline at end of file +} diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp index d432b0732b8..0839584d624 100644 --- a/src/utils/tournament.cpp +++ b/src/utils/tournament.cpp @@ -135,23 +135,28 @@ void Tournament::updateTournamentRole(std::shared_ptr peer) { if (peer->getPlayerProfiles().empty()) return; + std::string utf8_online_name = peer->getMainName(); + auto team_manager = getTeamManager(); + for (auto& player: peer->getPlayerProfiles()) { core::stringw name = player->getName(); std::string utf8_name = StringUtils::wideToUtf8(name); + if (m_red_players.count(utf8_online_name)) - getTeamManager()->setTeamInLobby(player, KART_TEAM_RED); + team_manager->setTeamInLobby(player, KART_TEAM_RED); else if (m_blue_players.count(utf8_online_name)) - getTeamManager()->setTeamInLobby(player, KART_TEAM_BLUE); + team_manager->setTeamInLobby(player, KART_TEAM_BLUE); else - getTeamManager()->setTeamInLobby(player, KART_TEAM_NONE); + team_manager->setTeamInLobby(player, KART_TEAM_NONE); + if (hasColorsSwapped()) { if (player->getTeam() == KART_TEAM_BLUE) - getTeamManager()->setTeamInLobby(player, KART_TEAM_RED); + team_manager->setTeamInLobby(player, KART_TEAM_RED); else if (player->getTeam() == KART_TEAM_RED) - getTeamManager()->setTeamInLobby(player, KART_TEAM_BLUE); + team_manager->setTeamInLobby(player, KART_TEAM_BLUE); } } } // updateTournamentRole From 87239d8f939fb681dbfd82117489a1101ff5b0fe Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 26 May 2025 15:37:17 +0200 Subject: [PATCH 755/830] Update the changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f61ff08932e..1ddc92df90c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ For similar reasons, and because some features are vastly more complex than othe ### Gameplay * Fix start positions for negative sideward distances, by kimden * Make the rescue bird place the kart towards the ball in soccer mode, by Snoker101 +* Fix a very rare bug where the anchor slowdown was ignored if triggering an instant speed boost on the same physics frame, by Alayan ### General * Make the game's window resizable in all menu screens, by Benau and CodingJellyfish @@ -37,6 +38,7 @@ For similar reasons, and because some features are vastly more complex than othe * Various build system updates, by deveee, tobbi, ognevny and others * Various compiler fixes, by heirecka, limburgher, nyllet and others * Substantial changes improving code quality, by Alayan and kimden +* Ensure proper compilation with newer build environments, especially with cmake 4.0, by deveee * Update Wiiuse library to 0.15.6, SIMD-e to 0.8.2, MojoAL to latest (a9e2f30) * Various tweaks, bugfixes and code-quality improvements @@ -45,6 +47,7 @@ For similar reasons, and because some features are vastly more complex than othe * Add more maximum framerate options to the built-in framerate limiter, by Benau * Add some graphical effects for legacy video drivers, by Benau * Improved animations for the parachute and bubblegum shield, by Semphris +* Add spotlights, by CodingJellyfish * Replace inaccurate normal compression algorithm with Octahedron Normal Vector, by CodingJellyfish * Fix the Screen-Space Reflection shader, by CodingJellyfish * Fix and improve the Screen-Space Ambiant Occlusion shader, by CodingJellyfish @@ -73,6 +76,8 @@ For similar reasons, and because some features are vastly more complex than othe * Improve the typing bars, especially for the coal theme, by Alayan * Implement a blog announcement system in the Online screen, by CodingJellyfish * Various UI layout improvements (especially for 'tall' resolutions), by CodingJellyfish +* Improve the spinner, label and icon-button text-sizing logic to avoid overflows with some language/font size combinations, by Alayan +* Add an always visible random track button in track selection, by Hanuko33 and Alayan * Generate higher resolution texture for scalable fonts, by CodingJellyfish * Fix for multiple keyboard navigation issues, by Alayan * Various enhancements, by QwertyChouskie, Nomagno, Nstelt and others @@ -97,6 +102,7 @@ For similar reasons, and because some features are vastly more complex than othe #### Karts * Update Godette face texture, by ZAQraven99 +* Update karts with headlights to use spotlights, by Benau and CodingJellyfish #### Arenas * XR-4R3N4 (soccer field), by CrystalDaEevee From 58fac34904e976a8e993fc4ce12c201c0666e2ec Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 26 May 2025 16:27:45 +0200 Subject: [PATCH 756/830] Fix #5434 The factor used to ensure wrapping around is considered worse than a distant element in the correct direction simply needed to be updated to match the increased factor from commit ebbbaa6. --- src/guiengine/event_handler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/guiengine/event_handler.cpp b/src/guiengine/event_handler.cpp index d38c6f697ef..f0673b52d03 100644 --- a/src/guiengine/event_handler.cpp +++ b/src/guiengine/event_handler.cpp @@ -518,7 +518,7 @@ int EventHandler::findIDClosestWidget(const NavigationDirection nav, const int p int closest_widget_id = -1; int distance = 0; // So that the UI behavior doesn't change when it is upscaled - const int BIG_DISTANCE = irr_driver->getActualScreenSize().Width*100; + const int BIG_DISTANCE = irr_driver->getActualScreenSize().Width*500; int smallest_distance = BIG_DISTANCE; // Used when there is no suitable widget in the requested direction int closest_wrapping_widget_id = -1; From e9763867bba8ad83480412f991676ea81edeef2a Mon Sep 17 00:00:00 2001 From: Wilmaster734 Date: Mon, 26 May 2025 10:39:44 -0400 Subject: [PATCH 757/830] Add a crown icon to the game master in splitscreen kart selection (Fix #5352) --- src/guiengine/widgets/player_kart_widget.cpp | 50 +++++++++++++++++++- src/guiengine/widgets/player_kart_widget.hpp | 4 ++ src/guiengine/widgets/spinner_widget.cpp | 4 +- src/guiengine/widgets/spinner_widget.hpp | 6 +++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/guiengine/widgets/player_kart_widget.cpp b/src/guiengine/widgets/player_kart_widget.cpp index ee8768ce178..295ccfaf08d 100644 --- a/src/guiengine/widgets/player_kart_widget.cpp +++ b/src/guiengine/widgets/player_kart_widget.cpp @@ -78,6 +78,16 @@ PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent, m_player_ident_spinner->m_w = player_name_w; m_player_ident_spinner->m_h = player_name_h; + // --- Kart Player Icone (Only for GameMaster) + m_icon_player = new IconButtonWidget(IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, false, false, IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); + m_icon_player->setImage(file_manager->getAsset(FileManager::GUI_ICON, "crown.png"), IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); + + m_icon_player->m_x = m_icon_player_x; + m_icon_player->m_y = m_icon_player_y; + m_icon_player->m_w = m_icon_player_w; + m_icon_player->m_h = m_icon_player_h; + m_children.push_back(m_icon_player); + // ---- KartStatsWidget m_kart_stats = NULL; @@ -277,6 +287,9 @@ PlayerKartWidget::~PlayerKartWidget() if (m_kart_name->getIrrlichtElement() != NULL) m_kart_name->getIrrlichtElement()->remove(); + + if (m_icon_player->getIrrlichtElement() != NULL) + m_icon_player->getIrrlichtElement()->remove(); if (getCurrentScreen() != NULL) getCurrentScreen()->manualRemoveWidget(this); @@ -366,6 +379,7 @@ void PlayerKartWidget::add() m_kart_stats->add(); m_model_view->add(); m_kart_name->add(); + m_icon_player->add(); m_model_view->update(0); @@ -379,7 +393,7 @@ void PlayerKartWidget::add() if (m_parent_screen->m_multiplayer) { const int player_amount = PlayerManager::get()->getNumPlayers(); - for (int n=0; ngetPlayer(n)->getName(); core::stringw label = name; @@ -395,11 +409,17 @@ void PlayerKartWidget::add() // select the right player profile in the spinner m_player_ident_spinner->setValue(label); + + if (m_associated_player->getID() != PLAYER_ID_GAME_MASTER) + { + m_icon_player->setVisible(false); + } } else { m_player_ident_spinner->addLabel(label); m_player_ident_spinner->setVisible(false); + m_icon_player->setVisible(false); } assert(m_player_ident_spinner->getStringValue() == label); @@ -439,6 +459,13 @@ void PlayerKartWidget::markAsReady() m_ready = true; + // Correctly replace the game master icon as the spinner arrow is no longer there (the player is ready) + m_icon_player_x += m_left_arrow_width; + m_icon_player->move(m_icon_player_x, + m_icon_player_y, + m_icon_player_w, + m_icon_player_h); + stringw playerNameString = m_player_ident_spinner->getStringValue(); core::rect rect(core::position2di(m_player_ident_spinner->m_x, m_player_ident_spinner->m_y), @@ -567,6 +594,7 @@ void PlayerKartWidget::updateSize() player_name_y, player_name_w, player_name_h ); + m_left_arrow_width = m_player_ident_spinner->getLeftArrow().getWidth(); } if (m_ready_text != NULL) { @@ -597,6 +625,11 @@ void PlayerKartWidget::updateSize() kart_name_y, kart_name_w, kart_name_h); + + m_icon_player->move(m_icon_player_x, + m_icon_player_y, + m_icon_player_w, + m_icon_player_h); } // updateSize // ------------------------------------------------------------------------- @@ -678,6 +711,9 @@ void PlayerKartWidget::setSize(const int x, const int y, const int w, const int else player_name_w = std::min(GUIEngine::getFontHeight() * 10, w); + m_icon_player_w = w; + m_icon_player_h = GUIEngine::getFontHeight(); + kart_name_w = w; kart_name_h = GUIEngine::getFontHeight(); @@ -693,6 +729,18 @@ void PlayerKartWidget::setSize(const int x, const int y, const int w, const int player_name_x = x + w/2 - player_name_w/2; player_name_y = y; + m_icon_player_x = x + w / 2 - (player_name_w / 2) - (m_icon_player_w / 2); + if (!m_ready && m_left_arrow_width != NULL) + { + m_icon_player_x -= m_left_arrow_width / 2; + } + else + { + m_icon_player_x += m_left_arrow_width / 2; + } + + m_icon_player_y = player_name_y; + if (m_parent_screen->m_multiplayer) { const int modelMaxHeight = (h - kart_name_h - player_name_h) / 2; diff --git a/src/guiengine/widgets/player_kart_widget.hpp b/src/guiengine/widgets/player_kart_widget.hpp index ae81652799a..490e381b4ab 100644 --- a/src/guiengine/widgets/player_kart_widget.hpp +++ b/src/guiengine/widgets/player_kart_widget.hpp @@ -34,6 +34,7 @@ namespace GUIEngine class ModelViewWidget; class LabelWidget; class SpinnerWidget; + class IconButtonWidget; /** A widget representing the kart selection for a player (i.e. the player's * number, name, the kart view, the kart's name) */ @@ -49,7 +50,9 @@ namespace GUIEngine int player_name_x, player_name_y, player_name_w, player_name_h; int model_x, model_y, model_w, model_h; int kart_name_x, kart_name_y, kart_name_w, kart_name_h; + int m_icon_player_x, m_icon_player_y, m_icon_player_w, m_icon_player_h; int m_kart_stats_x, m_kart_stats_y, m_kart_stats_w, m_kart_stats_h; + int m_left_arrow_width; /** A reserved ID for this widget if any, -1 otherwise. (If no ID is * reserved, widget will not be in the regular tabbing order */ @@ -83,6 +86,7 @@ namespace GUIEngine KartStatsWidget* m_kart_stats; ModelViewWidget* m_model_view; LabelWidget* m_kart_name; + IconButtonWidget* m_icon_player; KartSelectionScreen* m_parent_screen; diff --git a/src/guiengine/widgets/spinner_widget.cpp b/src/guiengine/widgets/spinner_widget.cpp index 207cad80565..beb1344cc7c 100644 --- a/src/guiengine/widgets/spinner_widget.cpp +++ b/src/guiengine/widgets/spinner_widget.cpp @@ -17,7 +17,7 @@ #include -#include "graphics/irr_driver.hpp" +// #include "graphics/irr_driver.hpp" #include "guiengine/engine.hpp" #include "guiengine/scalable_font.hpp" #include "guiengine/widgets/spinner_widget.hpp" @@ -107,6 +107,7 @@ SpinnerWidget::SpinnerWidget(const bool gauge) : Widget(WTYPE_SPINNER) m_right_selected = false; m_incorrect = false; m_red_mark_widget = NULL; + m_left_arrow = rect(0, 0, m_h, m_h); } // ------------------------------------------------------------------------ @@ -290,6 +291,7 @@ void SpinnerWidget::resize() Widget::resize(); rect subsize_left_arrow = rect(0 ,0, m_h, m_h); + m_left_arrow = subsize_left_arrow; m_children[0].m_element->setRelativePosition(subsize_left_arrow); m_badge_x_shift = subsize_left_arrow.getWidth(); diff --git a/src/guiengine/widgets/spinner_widget.hpp b/src/guiengine/widgets/spinner_widget.hpp index 641798be088..7db2278ef18 100644 --- a/src/guiengine/widgets/spinner_widget.hpp +++ b/src/guiengine/widgets/spinner_widget.hpp @@ -30,6 +30,7 @@ namespace irr #include "guiengine/widget.hpp" #include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" +#include "graphics/irr_driver.hpp" #include @@ -92,6 +93,9 @@ namespace GUIEngine /** \brief Whether the right arrow is the currently selected one */ bool m_right_selected; + /** \the arrow of the spinner */ + core::rect m_left_arrow; + /** \brief Keeps track of the custom text in spinner (a text which isn't related to a value) * to remember it and set it back (example : when we deactivate the widget) */ @@ -273,6 +277,8 @@ namespace GUIEngine if(getValue() getLeftArrow() const { return m_left_arrow; } + // ------------------------------------------------------------------------ /** Add a red mark on the spinner to mean "invalid choice" */ void markAsIncorrect(); From d1efab875321f6445454127a60284252d00b67bc Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 26 May 2025 17:06:44 +0200 Subject: [PATCH 758/830] Minor improvements - Improve variable names in the last merged PR - Remove an integer to NULL comparison in the last merged PR - Consistently write 'Egg Hunts' instead of sometimes 'Egg hunts' in achievement strings, to avoid near-duplicated strings showing as different for translation --- src/guiengine/widgets/player_kart_widget.cpp | 63 +++++++++---------- src/guiengine/widgets/player_kart_widget.hpp | 4 +- .../dialogs/achievement_progress_dialog.cpp | 15 ++--- 3 files changed, 37 insertions(+), 45 deletions(-) diff --git a/src/guiengine/widgets/player_kart_widget.cpp b/src/guiengine/widgets/player_kart_widget.cpp index 295ccfaf08d..55530d30140 100644 --- a/src/guiengine/widgets/player_kart_widget.cpp +++ b/src/guiengine/widgets/player_kart_widget.cpp @@ -78,15 +78,15 @@ PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent, m_player_ident_spinner->m_w = player_name_w; m_player_ident_spinner->m_h = player_name_h; - // --- Kart Player Icone (Only for GameMaster) - m_icon_player = new IconButtonWidget(IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, false, false, IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); - m_icon_player->setImage(file_manager->getAsset(FileManager::GUI_ICON, "crown.png"), IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); + // --- Crown icon (Only for the game master) + m_crown_icon = new IconButtonWidget(IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO, false, false, IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); + m_crown_icon->setImage(file_manager->getAsset(FileManager::GUI_ICON, "crown.png"), IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE); - m_icon_player->m_x = m_icon_player_x; - m_icon_player->m_y = m_icon_player_y; - m_icon_player->m_w = m_icon_player_w; - m_icon_player->m_h = m_icon_player_h; - m_children.push_back(m_icon_player); + m_crown_icon->m_x = m_crown_icon_x; + m_crown_icon->m_y = m_crown_icon_y; + m_crown_icon->m_w = m_crown_icon_w; + m_crown_icon->m_h = m_crown_icon_h; + m_children.push_back(m_crown_icon); // ---- KartStatsWidget m_kart_stats = NULL; @@ -288,8 +288,8 @@ PlayerKartWidget::~PlayerKartWidget() if (m_kart_name->getIrrlichtElement() != NULL) m_kart_name->getIrrlichtElement()->remove(); - if (m_icon_player->getIrrlichtElement() != NULL) - m_icon_player->getIrrlichtElement()->remove(); + if (m_crown_icon->getIrrlichtElement() != NULL) + m_crown_icon->getIrrlichtElement()->remove(); if (getCurrentScreen() != NULL) getCurrentScreen()->manualRemoveWidget(this); @@ -379,7 +379,7 @@ void PlayerKartWidget::add() m_kart_stats->add(); m_model_view->add(); m_kart_name->add(); - m_icon_player->add(); + m_crown_icon->add(); m_model_view->update(0); @@ -412,14 +412,14 @@ void PlayerKartWidget::add() if (m_associated_player->getID() != PLAYER_ID_GAME_MASTER) { - m_icon_player->setVisible(false); + m_crown_icon->setVisible(false); } } else { m_player_ident_spinner->addLabel(label); m_player_ident_spinner->setVisible(false); - m_icon_player->setVisible(false); + m_crown_icon->setVisible(false); } assert(m_player_ident_spinner->getStringValue() == label); @@ -460,11 +460,11 @@ void PlayerKartWidget::markAsReady() m_ready = true; // Correctly replace the game master icon as the spinner arrow is no longer there (the player is ready) - m_icon_player_x += m_left_arrow_width; - m_icon_player->move(m_icon_player_x, - m_icon_player_y, - m_icon_player_w, - m_icon_player_h); + m_crown_icon_x += m_left_arrow_width; + m_crown_icon->move(m_crown_icon_x, + m_crown_icon_y, + m_crown_icon_w, + m_crown_icon_h); stringw playerNameString = m_player_ident_spinner->getStringValue(); core::rect rect(core::position2di(m_player_ident_spinner->m_x, @@ -626,10 +626,10 @@ void PlayerKartWidget::updateSize() kart_name_w, kart_name_h); - m_icon_player->move(m_icon_player_x, - m_icon_player_y, - m_icon_player_w, - m_icon_player_h); + m_crown_icon->move(m_crown_icon_x, + m_crown_icon_y, + m_crown_icon_w, + m_crown_icon_h); } // updateSize // ------------------------------------------------------------------------- @@ -711,8 +711,8 @@ void PlayerKartWidget::setSize(const int x, const int y, const int w, const int else player_name_w = std::min(GUIEngine::getFontHeight() * 10, w); - m_icon_player_w = w; - m_icon_player_h = GUIEngine::getFontHeight(); + m_crown_icon_w = w; + m_crown_icon_h = GUIEngine::getFontHeight(); kart_name_w = w; kart_name_h = GUIEngine::getFontHeight(); @@ -729,17 +729,14 @@ void PlayerKartWidget::setSize(const int x, const int y, const int w, const int player_name_x = x + w/2 - player_name_w/2; player_name_y = y; - m_icon_player_x = x + w / 2 - (player_name_w / 2) - (m_icon_player_w / 2); - if (!m_ready && m_left_arrow_width != NULL) - { - m_icon_player_x -= m_left_arrow_width / 2; - } + m_crown_icon_x = x + w / 2 - (player_name_w / 2) - (m_crown_icon_w / 2); + + if (!m_ready && m_left_arrow_width > 0) + m_crown_icon_x -= m_left_arrow_width / 2; else - { - m_icon_player_x += m_left_arrow_width / 2; - } + m_crown_icon_x += m_left_arrow_width / 2; - m_icon_player_y = player_name_y; + m_crown_icon_y = player_name_y; if (m_parent_screen->m_multiplayer) { diff --git a/src/guiengine/widgets/player_kart_widget.hpp b/src/guiengine/widgets/player_kart_widget.hpp index 490e381b4ab..d0dae00f2c5 100644 --- a/src/guiengine/widgets/player_kart_widget.hpp +++ b/src/guiengine/widgets/player_kart_widget.hpp @@ -50,7 +50,7 @@ namespace GUIEngine int player_name_x, player_name_y, player_name_w, player_name_h; int model_x, model_y, model_w, model_h; int kart_name_x, kart_name_y, kart_name_w, kart_name_h; - int m_icon_player_x, m_icon_player_y, m_icon_player_w, m_icon_player_h; + int m_crown_icon_x, m_crown_icon_y, m_crown_icon_w, m_crown_icon_h; int m_kart_stats_x, m_kart_stats_y, m_kart_stats_w, m_kart_stats_h; int m_left_arrow_width; @@ -86,7 +86,7 @@ namespace GUIEngine KartStatsWidget* m_kart_stats; ModelViewWidget* m_model_view; LabelWidget* m_kart_name; - IconButtonWidget* m_icon_player; + IconButtonWidget* m_crown_icon; KartSelectionScreen* m_parent_screen; diff --git a/src/states_screens/dialogs/achievement_progress_dialog.cpp b/src/states_screens/dialogs/achievement_progress_dialog.cpp index 086c0afd04b..70ecc1b09fc 100644 --- a/src/states_screens/dialogs/achievement_progress_dialog.cpp +++ b/src/states_screens/dialogs/achievement_progress_dialog.cpp @@ -285,14 +285,9 @@ core::stringw AchievementProgressDialog::niceGoalName(std::string internal_name) // I18N: A goal for achievements. If this text is in (), it's a precision added to multiple different goals. if(internal_name=="twice-laps") { nice_name =_("Races with at least twice as much as the default lap number"); nice_name += _(" (maximum on one official track)"); } // I18N: A goal for achievements. If this text is in (), it's a precision added to multiple different goals. - if(internal_name=="egg-hunt-started") { nice_name =_("Egg hunts started"); nice_name += _(" (maximum on one official track)"); } - if (internal_name=="egg-hunt-finished") - { - // I18N: A goal for achievements. If this text is in (), it's a precision added to multiple different goals. - nice_name =_("Egg hunts finished"); - // I18N: A goal for achievements. If this text is in (), it's a precision added to multiple different goals. - nice_name += _(" (maximum on one official track)"); - } + if(internal_name=="egg-hunt-started") { nice_name =_("Egg Hunts started"); nice_name += _(" (maximum on one official track)"); } + // I18N: A goal for achievements. If this text is in (), it's a precision added to multiple different goals. + if (internal_name=="egg-hunt-finished") { nice_name =_("Egg Hunts finished"); nice_name += _(" (maximum on one official track)"); } // I18N: A goal for achievements. If this text is in (), it's a precision added to multiple different goals. if(internal_name=="race-started-all") { nice_name =_("Races started"); nice_name += _(" (official tracks matching the goal)"); } // I18N: A goal for achievements. If this text is in (), it's a precision added to multiple different goals. @@ -310,11 +305,11 @@ core::stringw AchievementProgressDialog::niceGoalName(std::string internal_name) // I18N: A goal for achievements. If this text is in (), it's a precision added to multiple different goals. if(internal_name=="twice-laps-all") { nice_name =_("Races with at least twice as much as the default lap number"); nice_name += _(" (official tracks matching the goal)"); } // I18N: A goal for achievements. If this text is in (), it's a precision added to multiple different goals. - if(internal_name=="egg-hunt-started-all") { nice_name =_("Egg hunts started"); nice_name += _(" (official tracks matching the goal)"); } + if(internal_name=="egg-hunt-started-all") { nice_name =_("Egg Hunts started"); nice_name += _(" (official tracks matching the goal)"); } if(internal_name=="egg-hunt-finished-all") { // I18N: A goal for achievements. If this text is in (), it's a precision added to multiple different goals. - nice_name =_("Egg hunts finished"); + nice_name =_("Egg Hunts finished"); // I18N: A goal for achievements. If this text is in (), it's a precision added to multiple different goals. nice_name += _(" (official tracks matching the goal)"); } From cc60e223c0d6674761f505ec5014b1f70b319862 Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 27 May 2025 17:51:30 +0200 Subject: [PATCH 759/830] Try to fix macos wiiuse build --- lib/wiiuse/src/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/wiiuse/src/CMakeLists.txt b/lib/wiiuse/src/CMakeLists.txt index 9bec8a0dd0e..0bf4e87fc4b 100644 --- a/lib/wiiuse/src/CMakeLists.txt +++ b/lib/wiiuse/src/CMakeLists.txt @@ -46,9 +46,7 @@ elseif(APPLE) os_mac/os_mac.c ${MAC_OBJC_SOURCES}) list(APPEND SOURCES ${MAC_SOURCES}) - # make sure we use the gcc for Objective-C files as well so that the - # sysroot and deployment target arguments are correctly passed to the compiler - set_source_files_properties(${MAC_OBJC_SOURCES} PROPERTIES LANGUAGE C) + set_source_files_properties(${MAC_OBJC_SOURCES} PROPERTIES COMPILE_FLAGS "-x objective-c") else() list(APPEND SOURCES os_nix.c) endif() From 4dbe097195054c5e785e77e19f6d9ff8b735699f Mon Sep 17 00:00:00 2001 From: Deve Date: Wed, 28 May 2025 10:35:16 +0200 Subject: [PATCH 760/830] Update Android target SDK --- android/build.gradle | 2 +- android/make.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 8241548db24..a5b94f88e23 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -11,7 +11,7 @@ buildscript // 4.1.2 is the minimum version to support native debug symbols file // https://developer.android.com/studio/build/shrink-code#android_gradle_plugin_version_41_or_later // 7.0.0 to fix https://stackoverflow.com/questions/68387270/android-studio-error-installed-build-tools-revision-31-0-0-is-corrupted - classpath 'com.android.tools.build:gradle:8.5.1' + classpath 'com.android.tools.build:gradle:8.7.3' } } diff --git a/android/make.sh b/android/make.sh index 11d2e59cdca..4ae559ad4ba 100755 --- a/android/make.sh +++ b/android/make.sh @@ -20,7 +20,7 @@ if [ -z "$STK_MIN_ANDROID_SDK" ]; then fi if [ -z "$STK_TARGET_ANDROID_SDK" ]; then - export STK_TARGET_ANDROID_SDK=34 + export STK_TARGET_ANDROID_SDK=35 fi if [ -z "$STK_NDK_VERSION" ]; then From c9d6b7df81012f28cbd2920eeb01fe55798f544c Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 30 May 2025 03:12:26 +0400 Subject: [PATCH 761/830] Don't count handled AI in gSBL Costed quite a few players being hourglasses in the past... --- src/utils/crown_manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/crown_manager.cpp b/src/utils/crown_manager.cpp index d72121c1880..39adf214200 100644 --- a/src/utils/crown_manager.cpp +++ b/src/utils/crown_manager.cpp @@ -40,7 +40,7 @@ void CrownManager::setupContextUser() std::set>& CrownManager::getSpectatorsByLimit(bool update) { - if (!update) + if (!update) return m_spectators_by_limit; m_why_peer_cannot_play.clear(); @@ -73,7 +73,7 @@ std::set>& CrownManager::getSpectatorsByLimit(bool upda for (int i = 0; i < (int)peers.size(); ++i) { - if (!peers[i]->isValidated()) + if (!peers[i]->isValidated() || (ServerConfig::m_ai_handling && peers[i]->isAIPeer())) { std::swap(peers[i], peers.back()); peers.pop_back(); From c1ead9ee42efd7d613ae828796841ef57404353d Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 30 May 2025 14:21:35 +0200 Subject: [PATCH 762/830] Fix #5443 --- src/network/protocols/server_lobby.cpp | 5 +++++ src/utils/string_utils.cpp | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3cd2dc8f6cd..e10540822a5 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -488,6 +488,11 @@ void ServerLobby::handleChat(Event* event) { NetworkString* chat = getNetworkString(); chat->setSynchronous(true); + // This string is not set to be translatable, because it is + // currently written by the server. The server would have + // to send a warning for interpretation by the client to + // allow proper translation. Also, this string can only be + // triggered with modified STK clients anyways. core::stringw warn = "Don't try to impersonate others!"; chat->addUInt8(LE_CHAT).encodeString16(warn); event->getPeer()->sendPacket(chat, true/*reliable*/); diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index c561d8d7502..49f6117d713 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -59,8 +59,15 @@ namespace StringUtils { if (str.length() < prefix.length()) return false; + else if (strncmp(str.c_str(), prefix.c_str(), prefix.size())==0) + return true; + // Ignore left-to-right markers for the purpose of string comparison + else if (strncmp(str.c_str(), ("\u200F" + prefix).c_str(), prefix.size() + 1)==0) + return true; + else if (strncmp(str.c_str(), ("\u200E" + prefix).c_str(), prefix.size() + 1)==0) + return true; else - return strncmp(str.c_str(), prefix.c_str(), prefix.size())==0; + return false; } //------------------------------------------------------------------------- From bc21570fbe03038b43f779f6e71f5b4f360972f6 Mon Sep 17 00:00:00 2001 From: martin Date: Fri, 30 May 2025 14:32:08 +0200 Subject: [PATCH 763/830] Replace deprecated std::iterator (#5147) Also fix two lambdas with deprecated capture syntax --- .../online/online_profile_achievements.cpp | 2 +- src/tracks/track_object_presentation.cpp | 2 +- src/utils/utf8/checked.h | 89 +++++++++------ src/utils/utf8/unchecked.h | 104 +++++++++++------- 4 files changed, 118 insertions(+), 79 deletions(-) diff --git a/src/states_screens/online/online_profile_achievements.cpp b/src/states_screens/online/online_profile_achievements.cpp index 4822c24998c..43eee137a1f 100644 --- a/src/states_screens/online/online_profile_achievements.cpp +++ b/src/states_screens/online/online_profile_achievements.cpp @@ -198,7 +198,7 @@ void BaseOnlineProfileAchievements::displayResults() all_achievements_list.push_back(it->second); } - auto compAchievement = [=](Achievement *a, Achievement *b) + auto compAchievement = [this](Achievement *a, Achievement *b) { // Sort by name if (m_sort_column == 0) diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index 864a27ed806..55f94a16fe7 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -1209,7 +1209,7 @@ void TrackObjectPresentationActionTrigger::onTriggerItemApproached(int kart_id) { Scripting::ScriptEngine::getInstance()->runFunction(true, "void " + m_library_name + "::" + m_action + - "(int, const string, const string)", [=](asIScriptContext* ctx) + "(int, const string, const string)", [this, kart_id](asIScriptContext* ctx) { ctx->SetArgDWord(0, kart_id); ctx->SetArgObject(1, &m_library_id); diff --git a/src/utils/utf8/checked.h b/src/utils/utf8/checked.h index a301685de63..0416f83104c 100644 --- a/src/utils/utf8/checked.h +++ b/src/utils/utf8/checked.h @@ -29,6 +29,8 @@ DEALINGS IN THE SOFTWARE. #define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include "core.h" +#include +#include #include namespace utf8 @@ -326,59 +328,76 @@ namespace utf8 // The iterator class template - class iterator : public std::iterator { + class iterator { + public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = uint32_t; + using difference_type = std::ptrdiff_t; + using pointer = const uint32_t*; + using reference = const uint32_t&; + + private: octet_iterator it; octet_iterator range_start; octet_iterator range_end; - public: - iterator () {}; - explicit iterator (const octet_iterator& octet_it, + + public: + iterator() = default; + + explicit iterator(const octet_iterator& octet_it, const octet_iterator& range_start, - const octet_iterator& range_end) : - it(octet_it), range_start(range_start), range_end(range_end) - { + const octet_iterator& range_end) + : it(octet_it), range_start(range_start), range_end(range_end) + { if (it < range_start || it > range_end) - throw std::out_of_range("Invalid utf-8 iterator position"); - } - // the default "big three" are OK - octet_iterator base () const { return it; } - uint32_t operator * () const - { + throw std::out_of_range("Invalid utf-8 iterator position"); + } + + octet_iterator base() const { return it; } + + uint32_t operator * () const + { octet_iterator temp = it; return next(temp, range_end); - } - bool operator == (const iterator& rhs) const - { + } + + bool operator == (const iterator& rhs) const + { if (range_start != rhs.range_start || range_end != rhs.range_end) - throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); - return (it == rhs.it); - } - bool operator != (const iterator& rhs) const - { - return !(operator == (rhs)); - } - iterator& operator ++ () - { + throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); + return it == rhs.it; + } + + bool operator != (const iterator& rhs) const + { + return !(*this == rhs); + } + + iterator& operator ++ () + { next(it, range_end); return *this; - } - iterator operator ++ (int) - { + } + + iterator operator ++ (int) + { iterator temp = *this; next(it, range_end); return temp; - } - iterator& operator -- () - { + } + + iterator& operator--() + { prior(it, range_start); return *this; - } - iterator operator -- (int) - { + } + + iterator operator--(int) + { iterator temp = *this; prior(it, range_start); return temp; - } + } }; // class iterator } // namespace utf8 diff --git a/src/utils/utf8/unchecked.h b/src/utils/utf8/unchecked.h index dcc57a7b0e8..6611d42d914 100644 --- a/src/utils/utf8/unchecked.h +++ b/src/utils/utf8/unchecked.h @@ -28,6 +28,8 @@ DEALINGS IN THE SOFTWARE. #ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#include +#include #include "core.h" namespace utf8 @@ -222,49 +224,67 @@ namespace utf8 // The iterator class template - class iterator : public std::iterator { - octet_iterator it; + class iterator { public: - iterator () {}; - explicit iterator (const octet_iterator& octet_it): it(octet_it) {} - // the default "big three" are OK - octet_iterator base () const { return it; } - uint32_t operator * () const - { - octet_iterator temp = it; - return next(temp); - } - bool operator == (const iterator& rhs) const - { - return (it == rhs.it); - } - bool operator != (const iterator& rhs) const - { - return !(operator == (rhs)); - } - iterator& operator ++ () - { - std::advance(it, internal::sequence_length(it)); - return *this; - } - iterator operator ++ (int) - { - iterator temp = *this; - std::advance(it, internal::sequence_length(it)); - return temp; - } - iterator& operator -- () - { - prior(it); - return *this; - } - iterator operator -- (int) - { - iterator temp = *this; - prior(it); - return temp; - } - }; // class iterator + using iterator_category = std::bidirectional_iterator_tag; + using value_type = uint32_t; + using difference_type = std::ptrdiff_t; + using pointer = const uint32_t*; + using reference = const uint32_t&; + + private: + octet_iterator it; + + public: + iterator() = default; + + explicit iterator(const octet_iterator& octet_it) + : it(octet_it) {} + + octet_iterator base() const { return it; } + + uint32_t operator * () const + { + octet_iterator temp = it; + return next(temp); + } + + bool operator == (const iterator& rhs) const + { + return it == rhs.it; + } + + bool operator != (const iterator& rhs) const + { + return !(*this == rhs); + } + + iterator& operator ++ () + { + std::advance(it, internal::sequence_length(it)); + return *this; + } + + iterator operator ++ (int) + { + iterator temp = *this; + std::advance(it, internal::sequence_length(it)); + return temp; + } + + iterator& operator -- () + { + prior(it); + return *this; + } + + iterator operator -- (int) + { + iterator temp = *this; + prior(it); + return temp; + } + }; // class iterator } // namespace utf8::unchecked } // namespace utf8 From 6aea989e6d3eb64d90f6c05362c42b829c508081 Mon Sep 17 00:00:00 2001 From: Deve Date: Fri, 30 May 2025 22:16:04 +0200 Subject: [PATCH 764/830] Remove unneeded header files --- src/guiengine/widgets/spinner_widget.cpp | 2 +- src/guiengine/widgets/spinner_widget.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/guiengine/widgets/spinner_widget.cpp b/src/guiengine/widgets/spinner_widget.cpp index beb1344cc7c..c9004ce967a 100644 --- a/src/guiengine/widgets/spinner_widget.cpp +++ b/src/guiengine/widgets/spinner_widget.cpp @@ -17,7 +17,7 @@ #include -// #include "graphics/irr_driver.hpp" +#include "graphics/irr_driver.hpp" #include "guiengine/engine.hpp" #include "guiengine/scalable_font.hpp" #include "guiengine/widgets/spinner_widget.hpp" diff --git a/src/guiengine/widgets/spinner_widget.hpp b/src/guiengine/widgets/spinner_widget.hpp index 7db2278ef18..de0e81a8c3a 100644 --- a/src/guiengine/widgets/spinner_widget.hpp +++ b/src/guiengine/widgets/spinner_widget.hpp @@ -25,14 +25,14 @@ namespace irr { namespace video { class ITexture; } + namespace gui { class IGUIImage; } } #include "guiengine/widget.hpp" #include "utils/leak_check.hpp" #include "utils/ptr_vector.hpp" -#include "graphics/irr_driver.hpp" -#include +#include namespace GUIEngine { From 57406988287f66a0edfdc4d95e4876d6bda71f0b Mon Sep 17 00:00:00 2001 From: Deve Date: Fri, 30 May 2025 22:49:18 +0200 Subject: [PATCH 765/830] Fix memory leak --- src/utils/time.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/time.cpp b/src/utils/time.cpp index 8f87cde7d8a..1c91f4f4eec 100644 --- a/src/utils/time.cpp +++ b/src/utils/time.cpp @@ -92,6 +92,7 @@ std::string StkTime::toString(int year, int month, int day) char s[64]; strftime(s, 64, date_format.c_str(), t); + delete t; return s; } // toString(3) From 1ca2cf3e888d446bab627980ce86f0f03967f3e0 Mon Sep 17 00:00:00 2001 From: Deve Date: Sat, 31 May 2025 23:09:47 +0200 Subject: [PATCH 766/830] Remove duplicated code --- .../src/ge_vulkan_draw_call.cpp | 73 ++++++------------- 1 file changed, 23 insertions(+), 50 deletions(-) diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index dd9bf968c87..1c552ccb951 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -1626,7 +1626,26 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, bool rebind_base_vertex = true; for (unsigned i = 0; i < m_cmds.size(); i++) { - if (m_cmds[i].m_shader != cur_pipeline) + if (m_cmds[i].m_transparent && !drawn_skybox) + { + drawn_skybox = true; + if (!depth_only) + { + drawSkyBox(cmd, current_buffer_idx, dynamic_offsets); + + bindDataDescriptor(cmd, current_buffer_idx, + dynamic_offsets); + vkCmdBindDescriptorSets(cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, + 0, 1, m_texture_descriptor->getDescriptorSet(), 0, + NULL); + } + } + bool is_last_cmd = (i == m_cmds.size() - 1); + bool pipeline_change = + !is_last_cmd && m_cmds[i + 1].m_shader != cur_pipeline; + draw_count++; + if (pipeline_change || is_last_cmd) { bound = bindPipeline(cmd, cur_pipeline, depth_only, &prev_dp); auto it = dynamic_spm_buffers.find( @@ -1663,58 +1682,12 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, indirect_offset, draw_count, indirect_size); } indirect_offset += draw_count * indirect_size; - draw_count = 1; - cur_pipeline = m_cmds[i].m_shader; - - if (m_cmds[i].m_transparent && !drawn_skybox) - { - drawn_skybox = true; - if (!depth_only) - { - drawSkyBox(cmd, current_buffer_idx, dynamic_offsets); - - bindDataDescriptor(cmd, current_buffer_idx, - dynamic_offsets); - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, - 0, 1, m_texture_descriptor->getDescriptorSet(), 0, - NULL); - } - } - continue; - } - draw_count++; - } - bound = bindPipeline(cmd, m_cmds.back().m_shader, depth_only, - &prev_dp); - auto it = dynamic_spm_buffers.find( - getDynamicBufferKey(m_cmds.back().m_shader)); - if (it != dynamic_spm_buffers.end()) - { - for (auto& buf : it->second) - { - if (bound) + if (!is_last_cmd) { - dynamic_offsets[1] = dynamic_spm_offset; - rebind_base_vertex = true; - bindDataDescriptor(cmd, current_buffer_idx, - dynamic_offsets); - buf.first->drawDynamicVertexIndexBuffer(cmd, - current_buffer_idx); + draw_count = 0; + cur_pipeline = m_cmds[i + 1].m_shader; } - dynamic_spm_offset += dynamic_spm_size; } - dynamic_spm_buffers.erase(it); - } - if (rebind_base_vertex) - bindBaseVertex(vk, cmd); - if (bound) - { - dynamic_offsets[1] = m_dynamic_spm_padded_size; - dynamic_offsets[4] = m_materials_data[m_cmds.back().m_shader].first; - bindDataDescriptor(cmd, current_buffer_idx, dynamic_offsets); - vkCmdDrawIndexedIndirect(cmd, indirect_buffer, indirect_offset, - draw_count, indirect_size); } } else From 30df62788effec17a0aed2880c23fb496b0aba50 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 1 Jun 2025 15:07:21 +0400 Subject: [PATCH 767/830] Add /countteams --- data/commands.xml | 7 +++ src/network/protocols/command_manager.cpp | 8 ++++ src/network/protocols/command_manager.hpp | 1 + src/utils/team_manager.cpp | 52 ++++++++++++++++++++++- src/utils/team_manager.hpp | 1 + 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/data/commands.xml b/data/commands.xml index 5e727c045a7..8e800c31f26 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -1196,6 +1196,13 @@ here later. For now, please refer to the code for the strings being used. --> permissions="UP_HAMMER" /> + countTeamsAsString().c_str())); +} // process_cooldown +// ======================================================================== + void CommandManager::process_temp250318(Context& context) { auto& argv = context.m_argv; diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index a6043a5d336..33c077ce2aa 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -367,6 +367,7 @@ class CommandManager: public LobbyContextComponent void process_available_teams_assign(Context& context); void process_cooldown(Context& context); void process_cooldown_assign(Context& context); + void process_countteams(Context& context); // Temporary command void process_temp250318(Context& context); diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp index bcd1688a9ea..5b358aad76b 100644 --- a/src/utils/team_manager.cpp +++ b/src/utils/team_manager.cpp @@ -420,7 +420,8 @@ bool TeamManager::assignRandomTeams(int intended_number, continue; if (p->alwaysSpectateButNotNeutral()) continue; - for (auto& profile : p->getPlayerProfiles()) { + for (auto& profile : p->getPlayerProfiles()) + { setTemporaryTeamInLobby(profile, profile_colors.back()); if (profile_colors.size() > 1) // prevent crash just in case profile_colors.pop_back(); @@ -430,6 +431,55 @@ bool TeamManager::assignRandomTeams(int intended_number, } // assignRandomTeams //----------------------------------------------------------------------------- +std::string TeamManager::countTeamsAsString() +{ + std::vector counts(TeamUtils::getNumberOfTeams() + 1, 0); + int cant_play = 0; + for (auto& p : STKHost::get()->getPeers()) + { + if (!getCrownManager()->canRace(p)) + { + ++cant_play; + continue; + } + if (p->alwaysSpectateButNotNeutral()) + { + ++cant_play; + continue; + } + for (auto& profile : p->getPlayerProfiles()) + ++counts[profile->getTemporaryTeam()]; + } + std::vector> sorted; + for (int i = 0; i < counts.size(); ++i) + if (counts[i] > 0) + sorted.emplace_back(-counts[i], i); + + std::sort(sorted.begin(), sorted.end()); + std::string res = ""; + + for (int i = 0; i < sorted.size(); ++i) + { + if (i) + res += ", "; + + std::string emoji = TeamUtils::getTeamByIndex(sorted[i].second).getEmoji(); + if (emoji.empty()) + emoji = "_"; + + res += StringUtils::insertValues("%s\u00d7%s", emoji.c_str(), -sorted[i].first); + } + + if (cant_play > 0) + { + res += ", can't play "; + res += StringUtils::insertValues("\u00d7%s", cant_play); + } + + return res; +} // countTeamsAsString +//----------------------------------------------------------------------------- + void TeamManager::changeColors() { // We assume here that it's soccer, as it's only called diff --git a/src/utils/team_manager.hpp b/src/utils/team_manager.hpp index d72de111b88..77b370e7d57 100644 --- a/src/utils/team_manager.hpp +++ b/src/utils/team_manager.hpp @@ -81,6 +81,7 @@ class TeamManager: public LobbyContextComponent void checkNoTeamSpectator(std::shared_ptr peer); bool assignRandomTeams(int intended_number, int* final_number, int* player_number); + std::string countTeamsAsString(); void changeColors(); private: From 9ccb4c88b251cb714d154bfb6f905d869c66247c Mon Sep 17 00:00:00 2001 From: Deve Date: Sun, 1 Jun 2025 21:03:38 +0200 Subject: [PATCH 768/830] Use world normal in vertex shaders --- data/shaders/ge_shaders/grass.vert | 3 +-- data/shaders/ge_shaders/spm.vert | 8 +++----- data/shaders/ge_shaders/spm_skinning.vert | 8 +++----- data/shaders/ge_shaders/utils/handle_pbr.glsl | 4 ++-- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/data/shaders/ge_shaders/grass.vert b/data/shaders/ge_shaders/grass.vert index 3337b7a43f2..e1137f81e25 100644 --- a/data/shaders/ge_shaders/grass.vert +++ b/data/shaders/ge_shaders/grass.vert @@ -29,7 +29,6 @@ void main() #endif f_hue_change = u_object_buffer.m_objects[gl_InstanceIndex].m_hue_change; #ifdef PBR_ENABLED - vec3 world_normal = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, v_normal.xyz); - f_normal = (u_camera.m_view_matrix * vec4(world_normal, 0.0)).xyz; + f_normal = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, v_normal.xyz); #endif } diff --git a/data/shaders/ge_shaders/spm.vert b/data/shaders/ge_shaders/spm.vert index db092185cb7..077552b747f 100644 --- a/data/shaders/ge_shaders/spm.vert +++ b/data/shaders/ge_shaders/spm.vert @@ -24,10 +24,8 @@ void main() #ifdef PBR_ENABLED vec3 world_normal = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, v_normal.xyz); vec3 world_tangent = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, v_tangent.xyz); - - f_tangent = (u_camera.m_view_matrix * vec4(world_tangent, 0.0)).xyz; - f_bitangent = normalize((u_camera.m_view_matrix * - vec4(cross(world_normal, world_tangent) * v_tangent.w, 0.0)).xyz); - f_normal = (u_camera.m_view_matrix * vec4(world_normal, 0.0)).xyz; + f_bitangent = cross(world_normal, world_tangent) * v_tangent.w; + f_tangent = world_tangent; + f_normal = world_normal; #endif } diff --git a/data/shaders/ge_shaders/spm_skinning.vert b/data/shaders/ge_shaders/spm_skinning.vert index 5237db34154..3c4477bafaf 100644 --- a/data/shaders/ge_shaders/spm_skinning.vert +++ b/data/shaders/ge_shaders/spm_skinning.vert @@ -34,10 +34,8 @@ void main() vec4 skinned_tangent = joint_matrix * vec4(v_tangent.xyz, 0.0); vec3 world_normal = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, skinned_normal.xyz); vec3 world_tangent = rotateVector(u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, skinned_tangent.xyz); - - f_tangent = (u_camera.m_view_matrix * vec4(world_tangent, 0.0)).xyz; - f_bitangent = (u_camera.m_view_matrix * - vec4(cross(world_normal, world_tangent) * v_tangent.w, 0.0)).xyz; - f_normal = (u_camera.m_view_matrix * vec4(world_normal, 0.0)).xyz; + f_bitangent = cross(world_normal, world_tangent) * v_tangent.w; + f_tangent = world_tangent; + f_normal = world_normal; #endif } diff --git a/data/shaders/ge_shaders/utils/handle_pbr.glsl b/data/shaders/ge_shaders/utils/handle_pbr.glsl index 5fa0acad6dc..364e0ef6378 100644 --- a/data/shaders/ge_shaders/utils/handle_pbr.glsl +++ b/data/shaders/ge_shaders/utils/handle_pbr.glsl @@ -11,16 +11,16 @@ layout (set = 2, binding = 1) uniform samplerCube u_specular; #include "pbr_light.glsl" #include "sun_direction.glsl" -vec3 handlePBR(vec3 diffuse_color, vec3 pbr, vec3 normal) +vec3 handlePBR(vec3 diffuse_color, vec3 pbr, vec3 world_normal) { vec3 xpos = getPosFromFragCoord(gl_FragCoord, u_camera.m_viewport, u_camera.m_inverse_projection_matrix); vec3 eyedir = -normalize(xpos); + vec3 normal = (u_camera.m_view_matrix * vec4(world_normal, 0.0)).xyz; vec3 reflection = reflect(-eyedir, normal); float perceptual_roughness = 1.0 - pbr.x; float radiance_level = perceptual_roughness * u_specular_levels_minus_one; - vec3 world_normal = (u_camera.m_inverse_view_matrix * vec4(normal, 0.0)).xyz; vec3 world_reflection = (u_camera.m_inverse_view_matrix * vec4(reflection, 0.0)).xyz; vec3 irradiance = vec3(0.0); From 829873f52cfce76875df5b72f843a81fc780391c Mon Sep 17 00:00:00 2001 From: Deve Date: Sun, 1 Jun 2025 22:14:09 +0200 Subject: [PATCH 769/830] Fix uninitialized variable in CameraFPS --- src/graphics/camera/camera_fps.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/graphics/camera/camera_fps.cpp b/src/graphics/camera/camera_fps.cpp index 7ac6639b8c4..6b2b087d8b3 100644 --- a/src/graphics/camera/camera_fps.cpp +++ b/src/graphics/camera/camera_fps.cpp @@ -33,6 +33,7 @@ CameraFPS::CameraFPS(int camera_index, AbstractKart* kart) : Camera(Camera::CM_TYPE_FPS, camera_index, kart) { m_attached = false; + m_smooth = false; // TODO: Put these values into a config file // Global or per split screen zone? From ce3564b9b3704b54b6554e77fd82a49f1ca1cbf5 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 2 Jun 2025 21:55:21 +0400 Subject: [PATCH 770/830] Reset to default mode only in WAITING... state --- src/network/protocols/server_lobby.cpp | 22 +++++++++++++++++++++- src/network/protocols/server_lobby.hpp | 2 ++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 630cec8963f..b564f18b343 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -246,6 +246,7 @@ ServerLobby::ServerLobby() : LobbyProtocol() m_server_id_online.store(0); m_difficulty.store(ServerConfig::m_server_difficulty); m_game_mode.store(ServerConfig::m_server_mode); + m_reset_to_default_mode_later.store(false); m_game_info = {}; } // ServerLobby @@ -638,6 +639,9 @@ void ServerLobby::asynchronousUpdate() if (NetworkConfig::get()->isLAN()) { m_state = WAITING_FOR_START_GAME; + if (m_reset_to_default_mode_later.exchange(false)) + handleServerConfiguration(NULL); + updatePlayerList(); STKHost::get()->startListening(); return; @@ -670,6 +674,9 @@ void ServerLobby::asynchronousUpdate() if (m_game_setup->isGrandPrixStarted() || m_registered_for_once_only) { m_state = WAITING_FOR_START_GAME; + if (m_reset_to_default_mode_later.exchange(false)) + handleServerConfiguration(NULL); + updatePlayerList(); break; } @@ -689,6 +696,9 @@ void ServerLobby::asynchronousUpdate() if (!getSettings()->isLegacyGPMode()) m_registered_for_once_only = true; m_state = WAITING_FOR_START_GAME; + if (m_reset_to_default_mode_later.exchange(false)) + handleServerConfiguration(NULL); + updatePlayerList(); } } @@ -3396,6 +3406,11 @@ void ServerLobby::resetServer() setup(); m_state = NetworkConfig::get()->isLAN() ? WAITING_FOR_START_GAME : REGISTER_SELF_ADDRESS; + + if (m_state.load() == WAITING_FOR_START_GAME) + if (m_reset_to_default_mode_later.exchange(false)) + handleServerConfiguration(NULL); + updatePlayerList(); } // resetServer @@ -4165,7 +4180,12 @@ void ServerLobby::handleServerCommand(Event* event) void ServerLobby::resetToDefaultSettings() { if (getSettings()->isServerConfigurable() && !getSettings()->isPreservingMode()) - handleServerConfiguration(NULL); + { + if (m_state == WAITING_FOR_START_GAME) + handleServerConfiguration(NULL); + else + m_reset_to_default_mode_later.store(true); + } getSettings()->onResetToDefaultSettings(); } // resetToDefaultSettings diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 5f0d1b01423..a97cf0f755c 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -186,6 +186,8 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser std::shared_ptr m_game_info; + std::atomic m_reset_to_default_mode_later; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); From b77c580c6e31c881f5a5ea41737fb71e4c831c8d Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 3 Jun 2025 01:22:37 +0400 Subject: [PATCH 771/830] Move chat functions out of server lobby Big but I feel like pushing it immediately, especially that those are mostly renames --- src/challenges/challenge_status.cpp | 1 - src/config/player_profile.cpp | 1 - src/items/bowling.cpp | 1 - src/karts/kart.cpp | 1 - src/network/network_console.cpp | 3 +- src/network/protocol.cpp | 32 ------- src/network/protocol.hpp | 6 +- src/network/protocols/client_lobby.cpp | 19 ++-- src/network/protocols/command_manager.cpp | 73 +++++++------- .../protocols/game_events_protocol.cpp | 7 +- src/network/protocols/game_protocol.cpp | 7 +- src/network/protocols/server_lobby.cpp | 79 +++++---------- src/network/protocols/server_lobby.hpp | 3 - .../dialogs/network_player_dialog.cpp | 9 +- .../dialogs/race_paused_dialog.cpp | 3 +- .../dialogs/server_configuration_dialog.cpp | 3 +- .../online/network_kart_selection.cpp | 5 +- .../online/networking_lobby.cpp | 5 +- src/states_screens/online/tracks_screen.cpp | 3 +- src/states_screens/track_info_screen.cpp | 1 - src/tracks/terrain_info.cpp | 1 - src/tracks/track_object_presentation.cpp | 1 - src/utils/chat_manager.cpp | 19 ++-- src/utils/communication.cpp | 96 +++++++++++++++++++ src/utils/communication.hpp | 47 +++++++++ src/utils/game_info.cpp | 3 +- src/utils/hit_processor.cpp | 4 +- src/utils/lobby_settings.cpp | 5 +- src/utils/team_manager.cpp | 4 +- 29 files changed, 263 insertions(+), 179 deletions(-) create mode 100644 src/utils/communication.cpp create mode 100644 src/utils/communication.hpp diff --git a/src/challenges/challenge_status.cpp b/src/challenges/challenge_status.cpp index 8062bd2e72d..71cd39242cd 100644 --- a/src/challenges/challenge_status.cpp +++ b/src/challenges/challenge_status.cpp @@ -26,7 +26,6 @@ #include "race/grand_prix_manager.hpp" #include "race/race_manager.hpp" #include "tracks/track.hpp" -// #include "tracks/track_manager.hpp" #include "utils/translation.hpp" #include "utils/string_utils.hpp" diff --git a/src/config/player_profile.cpp b/src/config/player_profile.cpp index 2451ed69f8d..c070b40a1fa 100644 --- a/src/config/player_profile.cpp +++ b/src/config/player_profile.cpp @@ -27,7 +27,6 @@ #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" #include "online/online_player_profile.hpp" -// #include "tracks/track_manager.hpp" #include "utils/string_utils.hpp" //------------------------------------------------------------------------------ diff --git a/src/items/bowling.cpp b/src/items/bowling.cpp index eb3d6b05675..3a485d56666 100644 --- a/src/items/bowling.cpp +++ b/src/items/bowling.cpp @@ -26,7 +26,6 @@ #include "karts/abstract_kart.hpp" #include "guiengine/engine.hpp" #include "config/stk_config.hpp" -// #include "modes/linear_world.hpp" #include "utils/hit_processor.hpp" #include "utils/log.hpp" //TODO: remove after debugging is done diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index e6ee4eec51d..be3cd4316e9 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -80,7 +80,6 @@ #include "tracks/drive_graph.hpp" #include "tracks/drive_node.hpp" #include "tracks/track.hpp" -// #include "tracks/track_manager.hpp" #include "tracks/track_sector.hpp" #include "utils/constants.hpp" #include "utils/helpers.hpp" diff --git a/src/network/network_console.cpp b/src/network/network_console.cpp index 50bbff5036f..2ea5dfdfcea 100644 --- a/src/network/network_console.cpp +++ b/src/network/network_console.cpp @@ -23,6 +23,7 @@ #include "network/stk_host.hpp" #include "network/stk_peer.hpp" #include "network/protocols/server_lobby.hpp" +#include "utils/communication.hpp" #include "utils/time.hpp" #include "utils/vs.hpp" #include "main_loop.hpp" @@ -209,7 +210,7 @@ void mainLoop(STKHost* host) message.pop_back(); auto sl = LobbyProtocol::get(); if (sl && !message.empty()) - sl->sendStringToAllPeers(message); + Comm::sendStringToAllPeers(message); } else { diff --git a/src/network/protocol.cpp b/src/network/protocol.cpp index a5d32ce279b..67cb744ca88 100644 --- a/src/network/protocol.cpp +++ b/src/network/protocol.cpp @@ -21,7 +21,6 @@ #include "network/event.hpp" #include "network/network_string.hpp" #include "network/protocol_manager.hpp" -#include "network/stk_host.hpp" #include "network/stk_peer.hpp" /** \brief Constructor @@ -89,34 +88,3 @@ void Protocol::requestTerminate() if (auto pm = ProtocolManager::lock()) pm->requestTerminate(shared_from_this()); } // requestTerminate - -// ---------------------------------------------------------------------------- -/** Sends a message to all validated peers in game, encrypt the message if - * needed. The message is composed of a 1-byte message (usually the message - * type) followed by the actual message. - * \param message The actual message content. -*/ -void Protocol::sendMessageToPeers(NetworkString *message, PacketReliabilityMode reliable) const -{ - STKHost::get()->sendPacketToAllPeers(message, reliable); -} // sendMessageToPeers - -// ---------------------------------------------------------------------------- -/** Sends a message to all validated peers in server, encrypt the message if - * needed. The message is composed of a 1-byte message (usually the message - * type) followed by the actual message. - * \param message The actual message content. -*/ -void Protocol::sendMessageToPeersInServer(NetworkString* message, - PacketReliabilityMode reliable) const -{ - STKHost::get()->sendPacketToAllPeersInServer(message, reliable); -} // sendMessageToPeersInServer - -// ---------------------------------------------------------------------------- -/** Sends a message from a client to the server. - */ -void Protocol::sendToServer(NetworkString *message, PacketReliabilityMode reliable) -{ - STKHost::get()->sendToServer(message, reliable); -} // sendMessage diff --git a/src/network/protocol.hpp b/src/network/protocol.hpp index 6f827fd1df0..aed9b98b468 100644 --- a/src/network/protocol.hpp +++ b/src/network/protocol.hpp @@ -24,7 +24,6 @@ #define PROTOCOL_HPP #include "utils/no_copy.hpp" -#include "utils/constants.hpp" #include #include @@ -119,10 +118,7 @@ class Protocol : public std::enable_shared_from_this, /// functions to check incoming data easily NetworkString* getNetworkString(size_t capacity = 16) const; bool checkDataSize(Event* event, unsigned int minimum_size); - void sendMessageToPeers(NetworkString *message, PacketReliabilityMode reliable = PRM_RELIABLE) const; - void sendMessageToPeersInServer(NetworkString *message, - PacketReliabilityMode reliable = PRM_RELIABLE) const; - void sendToServer(NetworkString *message, PacketReliabilityMode reliable = PRM_RELIABLE); + virtual void requestStart(); virtual void requestTerminate(); // ------------------------------------------------------------------------ diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp index 71357e944ca..db0f415f1d1 100644 --- a/src/network/protocols/client_lobby.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -68,6 +68,7 @@ #include "states_screens/online/tracks_screen.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" +#include "utils/communication.hpp" #include "utils/log.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -179,7 +180,7 @@ void ClientLobby::doneWithResults() NetworkString* done = getNetworkString(1); done->setSynchronous(true); done->addUInt8(LE_RACE_FINISHED_ACK); - sendToServer(done, PRM_RELIABLE); + Comm::sendToServer(done, PRM_RELIABLE); delete done; } // doneWithResults @@ -516,7 +517,7 @@ void ClientLobby::update(int ticks) m_auto_started = true; NetworkString start(PROTOCOL_LOBBY_ROOM); start.addUInt8(LobbyEvent::LE_REQUEST_BEGIN); - STKHost::get()->sendToServer(&start, PRM_RELIABLE); + Comm::sendToServer(&start, PRM_RELIABLE); } if (m_background_download.joinable()) { @@ -563,7 +564,7 @@ void ClientLobby::finalizeConnectionRequest(NetworkString* header, delete rest; *header += *result; delete result; - sendToServer(header); + Comm::sendToServer(header); delete header; if (encrypt) { @@ -575,7 +576,7 @@ void ClientLobby::finalizeConnectionRequest(NetworkString* header, { *header += *rest; delete rest; - sendToServer(header); + Comm::sendToServer(header); delete header; } } // finalizeConnectionRequest @@ -1307,7 +1308,7 @@ void ClientLobby::finishedLoadingWorld() NetworkString* ns = getNetworkString(1); ns->setSynchronous(m_server_send_live_load_world); ns->addUInt8(LE_CLIENT_LOADED_WORLD); - sendToServer(ns, PRM_RELIABLE); + Comm::sendToServer(ns, PRM_RELIABLE); delete ns; } // finishedLoadingWorld @@ -1406,7 +1407,7 @@ void ClientLobby::requestKartInfo(uint8_t kart_id) NetworkString* ns = getNetworkString(1); ns->setSynchronous(true); ns->addUInt8(LE_KART_INFO).addUInt8(kart_id); - sendToServer(ns, PRM_RELIABLE); + Comm::sendToServer(ns, PRM_RELIABLE); delete ns; } // requestKartInfo @@ -1550,7 +1551,7 @@ void ClientLobby::sendChat(irr::core::stringw text, KartTeam team) if (team != KART_TEAM_NONE) chat->addUInt8(team); - STKHost::get()->sendToServer(chat, PRM_RELIABLE); + Comm::sendToServer(chat, PRM_RELIABLE); delete chat; } } // sendChat @@ -1897,7 +1898,7 @@ void ClientLobby::handleClientCommand(const std::string& cmd) NetworkString* cmd_ns = getNetworkString(1); const std::string& language = UserConfigParams::m_language; cmd_ns->addUInt8(LE_COMMAND).encodeString(language).encodeString(cmd); - sendToServer(cmd_ns, PRM_RELIABLE); + Comm::sendToServer(cmd_ns, PRM_RELIABLE); delete cmd_ns; } #endif @@ -1939,7 +1940,7 @@ void ClientLobby::updateAssetsToServer() NetworkString* ns = getNetworkString(1); ns->addUInt8(LE_ASSETS_UPDATE); getKartsTracksNetworkString(ns); - sendToServer(ns, PRM_RELIABLE); + Comm::sendToServer(ns, PRM_RELIABLE); delete ns; } // updateAssetsToServer diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 4183f8dfd41..cebf4afa5a1 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -33,6 +33,7 @@ #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/chat_manager.hpp" +#include "utils/communication.hpp" #include "utils/crown_manager.hpp" #include "utils/file_utils.hpp" #include "utils/hit_processor.hpp" @@ -894,7 +895,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) first_time = false; } } - getLobby()->sendStringToAllPeers(msg); + Comm::sendStringToAllPeers(msg); auto res = response.second; if (!res.empty()) { @@ -906,7 +907,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) std::string msg2 = StringUtils::insertValues( "Command \"/%s\" has been successfully voted", new_cmd.c_str()); - getLobby()->sendStringToAllPeers(msg2); + Comm::sendStringToAllPeers(msg2); Context new_context(getLobby(), event, std::shared_ptr(nullptr), new_argv, new_cmd, UP_EVERYONE, UP_EVERYONE, false); execute(executed_command, new_context); } @@ -967,7 +968,7 @@ void CommandManager::update() std::string msg = StringUtils::insertValues( "Command \"/%s\" has been successfully voted", new_cmd.c_str()); - getLobby()->sendStringToAllPeers(msg); + Comm::sendStringToAllPeers(msg); // Happily the name of the votable coincides with the command full name std::shared_ptr command = m_full_name_to_command[votable_pairs.first].lock(); if (!command) @@ -1199,7 +1200,7 @@ void CommandManager::process_replay(Context& context) current_state ^= 1; getSettings()->setConsentOnReplays(current_state); - getLobby()->sendStringToAllPeers(std::string("Recording ghost replays is now ") + Comm::sendStringToAllPeers(std::string("Recording ghost replays is now ") + (current_state ? "on" : "off")); } else @@ -2163,12 +2164,12 @@ void CommandManager::process_gnu(Context& context) if (kart == "off") { kart_elimination->disable(); - getLobby()->sendStringToAllPeers("Gnu Elimination is now off"); + Comm::sendStringToAllPeers("Gnu Elimination is now off"); } else { kart_elimination->enable(kart); - getLobby()->sendStringToAllPeers(kart_elimination->getStartingMessage()); + Comm::sendStringToAllPeers(kart_elimination->getStartingMessage()); } } // process_gnu // ======================================================================== @@ -2374,7 +2375,7 @@ void CommandManager::process_length_multi(Context& context) } double value = std::max(0.0, temp_double); getSettings()->setMultiplier(value); - getLobby()->sendStringToAllPeers(StringUtils::insertValues( + Comm::sendStringToAllPeers(StringUtils::insertValues( "Game length is now %f x default", value)); } // process_length_multi // ======================================================================== @@ -2390,20 +2391,20 @@ void CommandManager::process_length_fixed(Context& context) } int value = std::max(0, temp_int); getSettings()->setFixedLapCount(value); - getLobby()->sendStringToAllPeers(StringUtils::insertValues( + Comm::sendStringToAllPeers(StringUtils::insertValues( "Game length is now %d", value)); } // process_length_fixed // ======================================================================== void CommandManager::process_length_clear(Context& context) { getSettings()->resetLapRestrictions(); - getLobby()->sendStringToAllPeers("Game length will be chosen by players"); + Comm::sendStringToAllPeers("Game length will be chosen by players"); } // process_length_clear // ======================================================================== void CommandManager::process_direction(Context& context) { - getLobby()->sendStringToAllPeers(getSettings()->getDirectionAsString()); + Comm::sendStringToAllPeers(getSettings()->getDirectionAsString()); } // process_direction // ======================================================================== @@ -2421,7 +2422,7 @@ void CommandManager::process_direction_assign(Context& context) error(context); return; } - getLobby()->sendStringToAllPeers(getSettings()->getDirectionAsString(true)); + Comm::sendStringToAllPeers(getSettings()->getDirectionAsString(true)); } // process_direction_assign // ======================================================================== @@ -2535,7 +2536,7 @@ void CommandManager::process_queue_push(Context& context) } msg.pop_back(); - getLobby()->sendStringToAllPeers(msg); + Comm::sendStringToAllPeers(msg); getLobby()->updatePlayerList(); } // process_queue_push // ======================================================================== @@ -2585,7 +2586,7 @@ void CommandManager::process_queue_pop(Context& context) } } msg.pop_back(); - getLobby()->sendStringToAllPeers(msg); + Comm::sendStringToAllPeers(msg); getLobby()->updatePlayerList(); } // process_queue_pop // ======================================================================== @@ -2613,7 +2614,7 @@ void CommandManager::process_queue_clear(Context& context) } } msg.pop_back(); - getLobby()->sendStringToAllPeers(msg); + Comm::sendStringToAllPeers(msg); getLobby()->updatePlayerList(); } // process_queue_clear // ======================================================================== @@ -2653,7 +2654,7 @@ void CommandManager::process_queue_shuffle(Context& context) } } msg.pop_back(); - getLobby()->sendStringToAllPeers(msg); + Comm::sendStringToAllPeers(msg); getLobby()->updatePlayerList(); } // process_queue_shuffle // ======================================================================== @@ -2676,7 +2677,7 @@ void CommandManager::process_allowstart_assign(Context& context) return; } getSettings()->setAllowedToStart(argv[1] != "0"); - getLobby()->sendStringToAllPeers(getSettings()->getAllowedToStartAsString(true)); + Comm::sendStringToAllPeers(getSettings()->getAllowedToStartAsString(true)); } // process_allowstart_assign // ======================================================================== @@ -2696,7 +2697,7 @@ void CommandManager::process_shuffle_assign(Context& context) return; } getSettings()->setGPGridShuffled(argv[1] != "0"); - getLobby()->sendStringToAllPeers(getSettings()->getWhetherShuffledGPGridAsString(true)); + Comm::sendStringToAllPeers(getSettings()->getWhetherShuffledGPGridAsString(true)); } // process_shuffle_assign // ======================================================================== @@ -2858,7 +2859,7 @@ void CommandManager::process_resetgp(Context& context) getGameSetupFromCtx()->setGrandPrixTrack(number_of_games); } getGPManager()->resetGrandPrix(); - getLobby()->sendStringToAllPeers("GP is now reset"); + Comm::sendStringToAllPeers("GP is now reset"); } // process_resetgp // ======================================================================== @@ -2950,7 +2951,7 @@ void CommandManager::process_troll_assign(Context& context) hit_processor->setAntiTroll(true); msg = "Trolls will be kicked"; } - getLobby()->sendStringToAllPeers(msg); + Comm::sendStringToAllPeers(msg); } // process_troll_assign // ======================================================================== @@ -2985,7 +2986,7 @@ void CommandManager::process_hitmsg_assign(Context& context) hit_processor->setShowTeammateHits(true); msg = "Teammate hits will be sent to all players"; } - getLobby()->sendStringToAllPeers(msg); + Comm::sendStringToAllPeers(msg); } // process_hitmsg_assign // ======================================================================== @@ -3022,7 +3023,7 @@ void CommandManager::process_teamhit_assign(Context& context) hit_processor->setTeammateHitMode(true); msg = "Teammate hits are punished now"; } - getLobby()->sendStringToAllPeers(msg); + Comm::sendStringToAllPeers(msg); } // process_teamhit_assign // ======================================================================== @@ -3040,7 +3041,7 @@ void CommandManager::process_scoring_assign(Context& context) std::string cmd2; CommandManager::restoreCmdByArgv(cmd2, argv, ' ', '"', '"', '\\', 1); if (getGPManager()->trySettingGPScoring(cmd2)) - getLobby()->sendStringToAllPeers("Scoring set to \"" + cmd2 + "\""); + Comm::sendStringToAllPeers("Scoring set to \"" + cmd2 + "\""); else context.say("Scoring could not be parsed from \"" + cmd2 + "\""); } // process_scoring_assign @@ -3174,7 +3175,7 @@ void CommandManager::process_game(Context& context) msg += StringUtils::insertValues(" %d seconds", new_addition); getSettings()->setFixedLapCount(getSettings()->getFixedLapCount() + 1); } - getLobby()->sendStringToAllPeers(msg); + Comm::sendStringToAllPeers(msg); Log::info("CommandManager", "SoccerMatchLog: Game number changed from %d to %d", old_game_number, new_game_number); } // process_game @@ -3247,7 +3248,7 @@ void CommandManager::process_role(Context& context) { if (player_peer->hasPlayerProfiles()) getTeamManager()->setTeamInLobby(player_peer->getMainProfile(), KART_TEAM_RED); - getLobby()->sendStringToPeer(player_peer, + Comm::sendStringToPeer(player_peer, StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } break; @@ -3267,7 +3268,7 @@ void CommandManager::process_role(Context& context) { if (player_peer->hasPlayerProfiles()) getTeamManager()->setTeamInLobby(player_peer->getMainProfile(), KART_TEAM_BLUE); - getLobby()->sendStringToPeer(player_peer, + Comm::sendStringToPeer(player_peer, StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } break; @@ -3280,7 +3281,7 @@ void CommandManager::process_role(Context& context) { if (player_peer->hasPlayerProfiles()) getTeamManager()->setTeamInLobby(player_peer->getMainProfile(), KART_TEAM_NONE); - getLobby()->sendStringToPeer(player_peer, + Comm::sendStringToPeer(player_peer, StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } break; @@ -3291,7 +3292,7 @@ void CommandManager::process_role(Context& context) { if (player_peer->hasPlayerProfiles()) getTeamManager()->setTeamInLobby(player_peer->getMainProfile(), KART_TEAM_NONE); - getLobby()->sendStringToPeer(player_peer, + Comm::sendStringToPeer(player_peer, StringUtils::insertValues(role_changed, Conversions::roleCharToString(role_char))); } break; @@ -3335,7 +3336,7 @@ void CommandManager::process_stop(Context& context) return; SoccerWorld *sw = dynamic_cast(w); sw->stop(); - getLobby()->sendStringToAllPeers("The game is stopped."); + Comm::sendStringToAllPeers("The game is stopped."); Log::info("CommandManager", "SoccerMatchLog: The game is stopped"); } // process_stop // ======================================================================== @@ -3352,7 +3353,7 @@ void CommandManager::process_go(Context& context) return; SoccerWorld *sw = dynamic_cast(w); sw->resume(); - getLobby()->sendStringToAllPeers("The game is resumed."); + Comm::sendStringToAllPeers("The game is resumed."); Log::info("CommandManager", "SoccerMatchLog: The game is resumed"); } // process_go // ======================================================================== @@ -3369,7 +3370,7 @@ void CommandManager::process_lobby(Context& context) return; SoccerWorld *sw = dynamic_cast(w); sw->allToLobby(); - getLobby()->sendStringToAllPeers("The game will be restarted."); + Comm::sendStringToAllPeers("The game will be restarted."); } // process_lobby // ======================================================================== @@ -3443,7 +3444,7 @@ void CommandManager::process_test(Context& context) acting_peer->getMainProfile(), acting_peer.get()); } username = "{" + argv[1].substr(4) + "} " + username; - getLobby()->sendStringToAllPeers(username + ", " + argv[2] + ", " + argv[3]); + Comm::sendStringToAllPeers(username + ", " + argv[2] + ", " + argv[3]); } // process_test // ======================================================================== @@ -3482,7 +3483,7 @@ void CommandManager::process_slots_assign(Context& context) } getSettings()->setCurrentMaxPlayersInGame((unsigned)number); getLobby()->updatePlayerList(); - getLobby()->sendStringToAllPeers(StringUtils::insertValues( + Comm::sendStringToAllPeers(StringUtils::insertValues( "Number of playable slots is now %s", number)); } // process_slots_assign @@ -3548,7 +3549,7 @@ void CommandManager::process_preserve_assign(Context& context) "'%s' is now preserved on server reset", argv[1].c_str()); getSettings()->insertIntoPreserved(argv[1]); } - getLobby()->sendStringToAllPeers(msg); + Comm::sendStringToAllPeers(msg); } // process_preserve_assign // ======================================================================== @@ -3875,7 +3876,7 @@ bool CommandManager::hasTypo(std::shared_ptr acting_peer, std::shared_p if (closest_commands.empty()) { // kimden: HERE IT SHOULD BE SENT TO ANOTHER PEER - getLobby()->sendStringToPeer(peer, "Command " + cmd + " not found"); + Comm::sendStringToPeer(peer, "Command " + cmd + " not found"); return true; } bool no_zeros = closest_commands[0].second != 0; @@ -3913,7 +3914,7 @@ bool CommandManager::hasTypo(std::shared_ptr acting_peer, std::shared_p } argv[idx] = initial_argument; CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); - getLobby()->sendStringToPeer(peer, response); + Comm::sendStringToPeer(peer, response); return true; } @@ -4024,7 +4025,7 @@ void CommandManager::Context::say(const std::string& s) throw std::logic_error("Context::say: Peer has expired"); auto peer = m_peer.lock(); - m_lobby->sendStringToPeer(peer, s); + Comm::sendStringToPeer(peer, s); } // say //----------------------------------------------------------------------------- diff --git a/src/network/protocols/game_events_protocol.cpp b/src/network/protocols/game_events_protocol.cpp index 7a6eccc920e..1e39aae4580 100644 --- a/src/network/protocols/game_events_protocol.cpp +++ b/src/network/protocols/game_events_protocol.cpp @@ -15,6 +15,7 @@ #include "network/stk_host.hpp" #include "network/stk_peer.hpp" #include "race/race_manager.hpp" +#include "utils/communication.hpp" #include @@ -118,7 +119,7 @@ bool GameEventsProtocol::notifyEvent(Event* event) NetworkString *ns = getNetworkString(); ns->setSynchronous(true); ns->addUInt8(GE_STARTUP_BOOST).addUInt8(kart_id).addFloat(f); - sendMessageToPeers(ns, PRM_RELIABLE); + Comm::sendMessageToPeers(ns, PRM_RELIABLE); delete ns; } else @@ -164,7 +165,7 @@ void GameEventsProtocol::kartFinishedRace(AbstractKart *kart, float time) ns->setSynchronous(true); ns->addUInt8(GE_KART_FINISHED_RACE).addUInt8(kart->getWorldKartId()) .addFloat(time); - sendMessageToPeers(ns, PRM_RELIABLE); + Comm::sendMessageToPeers(ns, PRM_RELIABLE); delete ns; } // kartFinishedRace @@ -198,6 +199,6 @@ void GameEventsProtocol::sendStartupBoost(uint8_t kart_id) NetworkString *ns = getNetworkString(); ns->setSynchronous(true); ns->addUInt8(GE_STARTUP_BOOST).addUInt8(kart_id); - sendToServer(ns, PRM_RELIABLE); + Comm::sendToServer(ns, PRM_RELIABLE); delete ns; } // sendStartupBoost diff --git a/src/network/protocols/game_protocol.cpp b/src/network/protocols/game_protocol.cpp index 564a536549a..ed3144d202d 100644 --- a/src/network/protocols/game_protocol.cpp +++ b/src/network/protocols/game_protocol.cpp @@ -35,6 +35,7 @@ #include "network/stk_host.hpp" #include "network/stk_peer.hpp" #include "tracks/track.hpp" +#include "utils/communication.hpp" #include "utils/log.hpp" #include "utils/time.hpp" #include "main_loop.hpp" @@ -109,7 +110,7 @@ void GameProtocol::sendActions() } // for a in m_all_actions // FIXME: for now send reliable - sendToServer(m_data_to_send, PRM_RELIABLE); + Comm::sendToServer(m_data_to_send, PRM_RELIABLE); m_all_actions.clear(); } // sendActions @@ -261,7 +262,7 @@ void GameProtocol::sendItemEventConfirmation(int ticks) ns->addUInt8(GP_ITEM_CONFIRMATION).addUInt32(ticks); // This message can be sent unreliable, it's not critical if it doesn't // get delivered, a future update will come through - sendToServer(ns, PRM_UNRELIABLE); + Comm::sendToServer(ns, PRM_UNRELIABLE); delete ns; } // sendItemEventConfirmation @@ -333,7 +334,7 @@ void GameProtocol::finalizeState(std::vector& cur_rewinder) void GameProtocol::sendState() { assert(NetworkConfig::get()->isServer()); - sendMessageToPeers(m_data_to_send, PRM_UNRELIABLE); + Comm::sendMessageToPeers(m_data_to_send, PRM_UNRELIABLE); } // sendState // ---------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index b564f18b343..73eed8b0d04 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -46,11 +46,11 @@ #include "network/stk_ipv6.hpp" #include "network/stk_peer.hpp" #include "online/request_manager.hpp" -// #include "online/xml_request.hpp" #include "tracks/check_manager.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/chat_manager.hpp" +#include "utils/communication.hpp" #include "utils/crown_manager.hpp" #include "utils/kart_elimination.hpp" #include "utils/game_info.hpp" @@ -945,7 +945,7 @@ void ServerLobby::asynchronousUpdate() resetPeersReady(); m_state = LOAD_WORLD; - sendMessageToPeers(load_world_message); + Comm::sendMessageToPeers(load_world_message); // updatePlayerList so the in lobby players (if any) can see always // spectators join the game if (has_always_on_spectators || !previous_spectate_mode.empty()) @@ -1389,7 +1389,7 @@ void ServerLobby::update(int ticks) break; case 1: { - sendStringToPeer(peer, getSettings()->getTrollWarnMsg()); + Comm::sendStringToPeer(peer, getSettings()->getTrollWarnMsg()); std::string player_name = peer->getMainName(); Log::info("ServerLobby-AntiTroll", "Sent WARNING to %s", player_name.c_str()); break; @@ -1469,7 +1469,7 @@ void ServerLobby::update(int ticks) NetworkString* back_to_lobby = getNetworkString(2); back_to_lobby->setSynchronous(true); back_to_lobby->addUInt8(LE_BACK_LOBBY).addUInt8(BLR_NONE); - sendMessageToPeersInServer(back_to_lobby, PRM_RELIABLE); + Comm::sendMessageToPeersInServer(back_to_lobby, PRM_RELIABLE); delete back_to_lobby; RaceEventManager::get()->stop(); @@ -1506,7 +1506,7 @@ void ServerLobby::update(int ticks) back_lobby->setSynchronous(true); back_lobby->addUInt8(LE_BACK_LOBBY) .addUInt8(BLR_ONE_PLAYER_IN_RANKED_MATCH); - sendMessageToPeers(back_lobby, PRM_RELIABLE); + Comm::sendMessageToPeers(back_lobby, PRM_RELIABLE); delete back_lobby; resetVotingTime(); // m_game_setup->cancelOneRace(); @@ -1559,7 +1559,7 @@ void ServerLobby::update(int ticks) // result screen and go back to the lobby setTimeoutFromNow(15); m_state = RESULT_DISPLAY; - sendMessageToPeers(m_result_ns, PRM_RELIABLE); + Comm::sendMessageToPeers(m_result_ns, PRM_RELIABLE); delete m_result_ns; Log::info("ServerLobby", "End of game message sent"); break; @@ -1572,7 +1572,7 @@ void ServerLobby::update(int ticks) NetworkString* back_to_lobby = getNetworkString(2); back_to_lobby->setSynchronous(true); back_to_lobby->addUInt8(LE_BACK_LOBBY).addUInt8(BLR_NONE); - sendMessageToPeersInServer(back_to_lobby, PRM_RELIABLE); + Comm::sendMessageToPeersInServer(back_to_lobby, PRM_RELIABLE); delete back_to_lobby; m_rs_state.store(RS_ASYNC_RESET); } @@ -1692,12 +1692,12 @@ void ServerLobby::startSelection(const Event *event) { if (!getSettings()->isAllowedToStart()) { - sendStringToPeer(peer, "Starting the game is forbidden by server owner"); + Comm::sendStringToPeer(peer, "Starting the game is forbidden by server owner"); return; } if (!getCrownManager()->canRace(peer)) { - sendStringToPeer(peer, "You cannot play so pressing ready has no action"); + Comm::sendStringToPeer(peer, "You cannot play so pressing ready has no action"); return; } else @@ -1710,7 +1710,7 @@ void ServerLobby::startSelection(const Event *event) } if (!getSettings()->isAllowedToStart()) { - sendStringToPeer(peer, "Starting the game is forbidden by server owner"); + Comm::sendStringToPeer(peer, "Starting the game is forbidden by server owner"); return; } if (!hasHostRights(peer)) @@ -1725,7 +1725,7 @@ void ServerLobby::startSelection(const Event *event) } if (cooldown) { - sendStringToPeer(peer, "Starting the game is forbidden by server cooldown"); + Comm::sendStringToPeer(peer, "Starting the game is forbidden by server cooldown"); return; } } else { @@ -1817,7 +1817,7 @@ void ServerLobby::startSelection(const Event *event) // inside if to not produce log spam for ownerless Log::warn("ServerLobby", "An attempt to start a game while no one can play."); - sendStringToPeer(event->getPeerSP(), "No one can play!"); + Comm::sendStringToPeer(event->getPeerSP(), "No one can play!"); } addWaitingPlayersToGame(); return; @@ -1920,7 +1920,7 @@ void ServerLobby::startSelection(const Event *event) delete ns; if (getQueues()->areKartFiltersIgnoringKarts()) - sendStringToPeer(peer, "The server will ignore your kart choice"); + Comm::sendStringToPeer(peer, "The server will ignore your kart choice"); } m_state = SELECTING; @@ -2066,7 +2066,7 @@ void ServerLobby::checkRaceFinished() { std::string msg = getKartElimination()->onRaceFinished(); if (!msg.empty()) - sendStringToAllPeers(msg); + Comm::sendStringToAllPeers(msg); } if (getSettings()->isStoringResults()) @@ -2249,7 +2249,7 @@ bool ServerLobby::handleAssetsAndAddonScores(std::shared_ptr peer, { if (peer->isValidated()) { - sendStringToPeer(peer, "You deleted some assets that are required to stay on the server"); + Comm::sendStringToPeer(peer, "You deleted some assets that are required to stay on the server"); peer->kick(); } else @@ -2755,7 +2755,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, msg = "Recording ghost replays is disabled. " "The crowned player can change that " "using /replay 0 (to disable) or /replay 1 (to enable). "; - sendStringToPeer(peer, msg); + Comm::sendStringToPeer(peer, msg); } getMessagesFromHost(peer, online_id); @@ -3064,7 +3064,7 @@ void ServerLobby::handlePlayerVote(Event* event) other.addUInt8(LE_VOTE); other.addUInt32(event->getPeer()->getHostId()); vote.encode(&other); - sendMessageToPeers(&other); + Comm::sendMessageToPeers(&other); } // handlePlayerVote @@ -3326,7 +3326,7 @@ void ServerLobby::configPeersStartTime() ns->addUInt8(cc); *ns += *m_items_complete_state; m_client_starting_time = start_time; - sendMessageToPeers(ns, PRM_RELIABLE); + Comm::sendMessageToPeers(ns, PRM_RELIABLE); const unsigned jitter_tolerance = getSettings()->getJitterTolerance(); Log::info("ServerLobby", "Max ping from peers: %d, jitter tolerance: %d", @@ -3401,7 +3401,7 @@ void ServerLobby::resetServer() server_info->setSynchronous(true); server_info->addUInt8(LE_SERVER_INFO); m_game_setup->addServerInfo(server_info); - sendMessageToPeersInServer(server_info); + Comm::sendMessageToPeersInServer(server_info); delete server_info; setup(); m_state = NetworkConfig::get()->isLAN() ? @@ -3461,7 +3461,7 @@ void ServerLobby::getMessagesFromHost(std::shared_ptr peer, int online_ for (const auto& message: messages) { Log::info("ServerLobby", "A message from server was delivered"); - sendStringToPeer(peer, "A message from the server (" + + Comm::sendStringToPeer(peer, "A message from the server (" + std::string(message.timestamp) + "):\n" + std::string(message.message)); db_connector->deleteServerMessage(message.row_id); } @@ -3602,7 +3602,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, msg = "This mode is not permitted on this server"; else msg = "This difficulty is not permitted on this server"; - sendStringToPeer(peer, msg); + Comm::sendStringToPeer(peer, msg); return; } auto modes = ServerConfig::getLocalGameMode(mode); @@ -3694,7 +3694,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, server_info->setSynchronous(true); server_info->addUInt8(LE_SERVER_INFO); m_game_setup->addServerInfo(server_info); - sendMessageToPeers(server_info); + Comm::sendMessageToPeers(server_info); delete server_info; updatePlayerList(); @@ -3703,7 +3703,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) { getKartElimination()->disable(); - sendStringToAllPeers("Gnu Elimination is disabled because of non-racing mode"); + Comm::sendStringToAllPeers("Gnu Elimination is disabled because of non-racing mode"); } } // handleServerConfiguration //----------------------------------------------------------------------------- @@ -4028,7 +4028,7 @@ void ServerLobby::clientInGameWantsToBackLobby(Event* event) back_to_lobby->setSynchronous(true); back_to_lobby->addUInt8(LE_BACK_LOBBY) .addUInt8(BLR_SERVER_ONWER_QUITED_THE_GAME); - sendMessageToPeersInServer(back_to_lobby, PRM_RELIABLE); + Comm::sendMessageToPeersInServer(back_to_lobby, PRM_RELIABLE); delete back_to_lobby; m_rs_state.store(RS_ASYNC_RESET); return; @@ -4099,7 +4099,7 @@ void ServerLobby::clientSelectingAssetsWantsToBackLobby(Event* event) back_to_lobby->setSynchronous(true); back_to_lobby->addUInt8(LE_BACK_LOBBY) .addUInt8(BLR_SERVER_ONWER_QUITED_THE_GAME); - sendMessageToPeersInServer(back_to_lobby, PRM_RELIABLE); + Comm::sendMessageToPeersInServer(back_to_lobby, PRM_RELIABLE); delete back_to_lobby; resetVotingTime(); resetServer(); @@ -4230,33 +4230,6 @@ void ServerLobby::writeOwnReport(std::shared_ptr reporter, std::shared_ } // writeOwnReport //----------------------------------------------------------------------------- -void ServerLobby::sendStringToPeer(std::shared_ptr peer, const std::string& s) -{ - if (!peer) - { - sendStringToAllPeers(s); - return; - } - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16(StringUtils::utf8ToWide(s)); - peer->sendPacket(chat, PRM_RELIABLE); - delete chat; -} // sendStringToPeer -//----------------------------------------------------------------------------- - -void ServerLobby::sendStringToAllPeers(const std::string& s) -{ - NetworkString* chat = getNetworkString(); - chat->addUInt8(LE_CHAT); - chat->setSynchronous(true); - chat->encodeString16(StringUtils::utf8ToWide(s)); - sendMessageToPeers(chat, PRM_RELIABLE); - delete chat; -} // sendStringToAllPeers -//----------------------------------------------------------------------------- - std::string ServerLobby::encodeProfileNameForPeer( std::shared_ptr npp, STKPeer* peer) @@ -4459,7 +4432,7 @@ void ServerLobby::sendServerInfoToEveryone() const server_info->setSynchronous(true); server_info->addUInt8(LE_SERVER_INFO); m_game_setup->addServerInfo(server_info); - sendMessageToPeers(server_info); + Comm::sendMessageToPeers(server_info); delete server_info; } // sendServerInfoToEveryone //----------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index a97cf0f755c..44728e6d4de 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -334,13 +334,10 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser const std::string& info); // int getTrackMaxPlayers(std::string& name) const; - void sendStringToPeer(std::shared_ptr peer, const std::string& s); - // TODO: When using different decorators for everyone, you would need // a structure to store "player profile" placeholders in a string, so that // you can apply decorators at the very last moment inside sendStringToAllPeers // and similar functions. - void sendStringToAllPeers(const std::string& s); std::string encodeProfileNameForPeer( std::shared_ptr npp, STKPeer* peer); diff --git a/src/states_screens/dialogs/network_player_dialog.cpp b/src/states_screens/dialogs/network_player_dialog.cpp index 94957abc995..177915bf9e0 100644 --- a/src/states_screens/dialogs/network_player_dialog.cpp +++ b/src/states_screens/dialogs/network_player_dialog.cpp @@ -32,6 +32,7 @@ #include "states_screens/dialogs/general_text_field_dialog.hpp" #include "states_screens/dialogs/ranking_callback.hpp" #include "states_screens/state_manager.hpp" +#include "utils/communication.hpp" #include "utils/translation.hpp" #include @@ -205,7 +206,7 @@ void NetworkPlayerDialog::onUpdate(float dt) NetworkString report(PROTOCOL_LOBBY_ROOM); report.addUInt8(LobbyEvent::LE_REPORT_PLAYER) .addUInt32(host_id).encodeString16(info); - STKHost::get()->sendToServer(&report, PRM_RELIABLE); + Comm::sendToServer(&report, PRM_RELIABLE); return true; }); return; @@ -248,7 +249,7 @@ GUIEngine::EventPropagation { NetworkString kick(PROTOCOL_LOBBY_ROOM); kick.addUInt8(LobbyEvent::LE_KICK_HOST).addUInt32(m_host_id); - STKHost::get()->sendToServer(&kick, PRM_RELIABLE); + Comm::sendToServer(&kick, PRM_RELIABLE); m_self_destroy = true; return GUIEngine::EVENT_BLOCK; } @@ -258,7 +259,7 @@ GUIEngine::EventPropagation NetworkString change_team(PROTOCOL_LOBBY_ROOM); change_team.addUInt8(LobbyEvent::LE_CHANGE_TEAM) .addUInt8(m_local_id); - STKHost::get()->sendToServer(&change_team, PRM_RELIABLE); + Comm::sendToServer(&change_team, PRM_RELIABLE); m_self_destroy = true; return GUIEngine::EVENT_BLOCK; } @@ -273,7 +274,7 @@ GUIEngine::EventPropagation NetworkString change_handicap(PROTOCOL_LOBBY_ROOM); change_handicap.addUInt8(LobbyEvent::LE_CHANGE_HANDICAP) .addUInt8(m_local_id).addUInt8(new_handicap); - STKHost::get()->sendToServer(&change_handicap, PRM_RELIABLE); + Comm::sendToServer(&change_handicap, PRM_RELIABLE); m_self_destroy = true; return GUIEngine::EVENT_BLOCK; } diff --git a/src/states_screens/dialogs/race_paused_dialog.cpp b/src/states_screens/dialogs/race_paused_dialog.cpp index b454052260f..2c2ed1cfd90 100644 --- a/src/states_screens/dialogs/race_paused_dialog.cpp +++ b/src/states_screens/dialogs/race_paused_dialog.cpp @@ -48,6 +48,7 @@ #include "states_screens/race_setup_screen.hpp" #include "states_screens/options/options_screen_general.hpp" #include "states_screens/state_manager.hpp" +#include "utils/communication.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -388,7 +389,7 @@ GUIEngine::EventPropagation NetworkString back(PROTOCOL_LOBBY_ROOM); back.setSynchronous(true); back.addUInt8(LobbyEvent::LE_CLIENT_BACK_LOBBY); - STKHost::get()->sendToServer(&back, PRM_RELIABLE); + Comm::sendToServer(&back, PRM_RELIABLE); } else { diff --git a/src/states_screens/dialogs/server_configuration_dialog.cpp b/src/states_screens/dialogs/server_configuration_dialog.cpp index 6cc37bcf605..74fe5d0a577 100644 --- a/src/states_screens/dialogs/server_configuration_dialog.cpp +++ b/src/states_screens/dialogs/server_configuration_dialog.cpp @@ -26,6 +26,7 @@ #include "network/protocols/lobby_protocol.hpp" #include "network/stk_host.hpp" #include "states_screens/state_manager.hpp" +#include "utils/communication.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -122,7 +123,7 @@ GUIEngine::EventPropagation break; } } - STKHost::get()->sendToServer(&change, PRM_RELIABLE); + Comm::sendToServer(&change, PRM_RELIABLE); return GUIEngine::EVENT_BLOCK; } } diff --git a/src/states_screens/online/network_kart_selection.cpp b/src/states_screens/online/network_kart_selection.cpp index d99cb0a2836..8f64d40b277 100644 --- a/src/states_screens/online/network_kart_selection.cpp +++ b/src/states_screens/online/network_kart_selection.cpp @@ -30,6 +30,7 @@ #include "states_screens/state_manager.hpp" #include "states_screens/online/networking_lobby.hpp" #include "states_screens/online/tracks_screen.hpp" +#include "utils/communication.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -157,7 +158,7 @@ void NetworkKartSelectionScreen::allPlayersDone() kart_data.encode(&kart); } } - STKHost::get()->sendToServer(&kart, PRM_RELIABLE); + Comm::sendToServer(&kart, PRM_RELIABLE); // ---- Switch to assign mode input_manager->getDeviceManager()->setAssignMode(ASSIGN); @@ -188,7 +189,7 @@ bool NetworkKartSelectionScreen::onEscapePressed() m_exit_timeout = StkTime::getMonoTimeMs() + 5000; NetworkString back(PROTOCOL_LOBBY_ROOM); back.addUInt8(LobbyEvent::LE_CLIENT_BACK_LOBBY); - STKHost::get()->sendToServer(&back, PRM_RELIABLE); + Comm::sendToServer(&back, PRM_RELIABLE); } return false; } diff --git a/src/states_screens/online/networking_lobby.cpp b/src/states_screens/online/networking_lobby.cpp index 16e0f823f8d..0f5332e14bc 100644 --- a/src/states_screens/online/networking_lobby.cpp +++ b/src/states_screens/online/networking_lobby.cpp @@ -55,6 +55,7 @@ #include "states_screens/dialogs/server_configuration_dialog.hpp" #include "states_screens/state_manager.hpp" #include "tracks/track.hpp" +#include "utils/communication.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -863,7 +864,7 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name, // Send a message to the server to start NetworkString start(PROTOCOL_LOBBY_ROOM); start.addUInt8(LobbyEvent::LE_REQUEST_BEGIN); - STKHost::get()->sendToServer(&start, PRM_RELIABLE); + Comm::sendToServer(&start, PRM_RELIABLE); } } else if (name == m_config_button->m_properties[PROP_ID]) @@ -883,7 +884,7 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name, start.addUInt8(LobbyEvent::LE_LIVE_JOIN) // is spectating .addUInt8(1); - STKHost::get()->sendToServer(&start, PRM_RELIABLE); + Comm::sendToServer(&start, PRM_RELIABLE); return; } if (cl) diff --git a/src/states_screens/online/tracks_screen.cpp b/src/states_screens/online/tracks_screen.cpp index 50fe33386bf..59dfbc6f71e 100644 --- a/src/states_screens/online/tracks_screen.cpp +++ b/src/states_screens/online/tracks_screen.cpp @@ -44,6 +44,7 @@ #include "states_screens/track_info_screen.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" +#include "utils/communication.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -761,7 +762,7 @@ void TracksScreen::voteForPlayer() PeerVote pvote(vote); lp->addVote(STKHost::get()->getMyHostId(), pvote); } - STKHost::get()->sendToServer(&vote, PRM_RELIABLE); + Comm::sendToServer(&vote, PRM_RELIABLE); } // voteForPlayer // ----------------------------------------------------------------------------- diff --git a/src/states_screens/track_info_screen.cpp b/src/states_screens/track_info_screen.cpp index bfd629ffd66..946eaa648fa 100644 --- a/src/states_screens/track_info_screen.cpp +++ b/src/states_screens/track_info_screen.cpp @@ -42,7 +42,6 @@ #include "race/race_manager.hpp" #include "states_screens/state_manager.hpp" #include "tracks/track.hpp" -// #include "tracks/track_manager.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" diff --git a/src/tracks/terrain_info.cpp b/src/tracks/terrain_info.cpp index 31130ce91fb..fe37f686103 100644 --- a/src/tracks/terrain_info.cpp +++ b/src/tracks/terrain_info.cpp @@ -21,7 +21,6 @@ #include "physics/triangle_mesh.hpp" #include "race/race_manager.hpp" #include "tracks/track.hpp" -// #include "tracks/track_manager.hpp" #include "tracks/track_object_manager.hpp" #include "utils/constants.hpp" diff --git a/src/tracks/track_object_presentation.cpp b/src/tracks/track_object_presentation.cpp index 96ca28b001f..c05cadeb0d6 100644 --- a/src/tracks/track_object_presentation.cpp +++ b/src/tracks/track_object_presentation.cpp @@ -46,7 +46,6 @@ #include "tracks/check_trigger.hpp" #include "tracks/model_definition_loader.hpp" #include "tracks/track.hpp" -// #include "tracks/track_manager.hpp" #include "tracks/track_object_manager.hpp" #include "utils/stk_process.hpp" #include "utils/string_utils.hpp" diff --git a/src/utils/chat_manager.cpp b/src/utils/chat_manager.cpp index d483db03528..2f2abffd8ff 100644 --- a/src/utils/chat_manager.cpp +++ b/src/utils/chat_manager.cpp @@ -18,16 +18,17 @@ #include "utils/chat_manager.hpp" -#include "network/server_config.hpp" -#include "utils/string_utils.hpp" -#include "utils/tournament.hpp" -#include "network/protocols/server_lobby.hpp" -#include "utils/string_utils.hpp" -#include "network/stk_peer.hpp" #include "network/network_player_profile.hpp" #include "network/network_string.hpp" -#include "network/stk_host.hpp" +#include "network/protocols/server_lobby.hpp" #include "network/remote_kart_info.hpp" +#include "network/server_config.hpp" +#include "network/stk_host.hpp" +#include "network/stk_peer.hpp" +#include "utils/communication.hpp" +#include "utils/string_utils.hpp" +#include "utils/string_utils.hpp" +#include "utils/tournament.hpp" namespace { @@ -181,7 +182,7 @@ void ChatManager::handleNormalChatMessage(std::shared_ptr peer, if (interval > 0 && peer->getConsecutiveMessages() > interval / 2) { - getLobby()->sendStringToPeer(peer, "Spam detected"); + Comm::sendStringToPeer(peer, "Spam detected"); return; } @@ -192,7 +193,7 @@ void ChatManager::handleNormalChatMessage(std::shared_ptr peer, if (!StringUtils::startsWith(message, prefix)) { - getLobby()->sendStringToPeer(peer, "Don't try to impersonate others!"); + Comm::sendStringToPeer(peer, "Don't try to impersonate others!"); return; } diff --git a/src/utils/communication.cpp b/src/utils/communication.cpp new file mode 100644 index 00000000000..cc7ee3e5544 --- /dev/null +++ b/src/utils/communication.cpp @@ -0,0 +1,96 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/communication.hpp" + +#include "network/stk_host.hpp" +#include "network/packet_types.hpp" +#include "network/stk_peer.hpp" + +// Probably not needed when packets branch is merged +#include "utils/string_utils.hpp" +#include "network/protocol.hpp" + +namespace Comm +{ + +// ---------------------------------------------------------------------------- +/** Sends a message to all validated peers in game, encrypt the message if + * needed. The message is composed of a 1-byte message (usually the message + * type) followed by the actual message. + * \param message The actual message content. + * \param reliable Whether it should be in a reliable way or not. +*/ +void sendMessageToPeers(NetworkString *message, + PacketReliabilityMode reliable) +{ + STKHost::get()->sendPacketToAllPeers(message, reliable); +} // sendMessageToPeers + +// ---------------------------------------------------------------------------- +/** Sends a message to all validated peers in server, encrypt the message if + * needed. The message is composed of a 1-byte message (usually the message + * type) followed by the actual message. + * \param message The actual message content. + * \param reliable Whether it should be in a reliable way or not. +*/ +void sendMessageToPeersInServer(NetworkString* message, + PacketReliabilityMode reliable) +{ + STKHost::get()->sendPacketToAllPeersInServer(message, reliable); +} // sendMessageToPeersInServer + +// ---------------------------------------------------------------------------- +/** Sends a message from a client to the server. + * \param message The actual message content. + * \param reliable Whether it should be in a reliable way or not. + */ +void sendToServer(NetworkString *message, + PacketReliabilityMode reliable) +{ + STKHost::get()->sendToServer(message, reliable); +} // sendMessage +//----------------------------------------------------------------------------- + +void sendStringToPeer(std::shared_ptr peer, const std::string& s) +{ + if (!peer) + { + sendStringToAllPeers(s); + return; + } + NetworkString* chat = new NetworkString(ProtocolType::PROTOCOL_LOBBY_ROOM); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(StringUtils::utf8ToWide(s)); + peer->sendPacket(chat, PRM_RELIABLE); + delete chat; +} // sendStringToPeer +//----------------------------------------------------------------------------- + +void sendStringToAllPeers(const std::string& s) +{ + NetworkString* chat = new NetworkString(ProtocolType::PROTOCOL_LOBBY_ROOM); + chat->addUInt8(LE_CHAT); + chat->setSynchronous(true); + chat->encodeString16(StringUtils::utf8ToWide(s)); + sendMessageToPeers(chat, PRM_RELIABLE); + delete chat; +} // sendStringToAllPeers +//----------------------------------------------------------------------------- +} // namespace Comm diff --git a/src/utils/communication.hpp b/src/utils/communication.hpp new file mode 100644 index 00000000000..447a23bae31 --- /dev/null +++ b/src/utils/communication.hpp @@ -0,0 +1,47 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef COMMUNICATION_HPP +#define COMMUNICATION_HPP + +#include "network/network_string.hpp" +#include "utils/constants.hpp" + +/** A namespace with useful communication functions, + * previously located in server_lobby.cpp */ + +namespace Comm +{ + void sendMessageToPeers(NetworkString *message, + PacketReliabilityMode reliable = PRM_RELIABLE); + void sendMessageToPeersInServer(NetworkString *message, + PacketReliabilityMode reliable = PRM_RELIABLE); + void sendToServer(NetworkString *message, + PacketReliabilityMode reliable = PRM_RELIABLE); + + // Uses PROTOCOL_LOBBY_ROOM as chat is sent from there usually. + // Using in non-lobby classes would be strange but seemingly ok. + void sendStringToPeer(std::shared_ptr peer, const std::string& s); + + // Uses PROTOCOL_LOBBY_ROOM as chat is sent from there usually. + // Using in non-lobby classes would be strange but seemingly ok. + void sendStringToAllPeers(const std::string& s); +} + + +#endif // COMMUNICATION_HPP \ No newline at end of file diff --git a/src/utils/game_info.cpp b/src/utils/game_info.cpp index 85fa7cf3270..7c441612406 100644 --- a/src/utils/game_info.cpp +++ b/src/utils/game_info.cpp @@ -33,6 +33,7 @@ #include "network/remote_kart_info.hpp" #include "network/stk_peer.hpp" #include "race/race_manager.hpp" +#include "utils/communication.hpp" #include "utils/lobby_settings.hpp" #include "utils/string_utils.hpp" @@ -452,7 +453,7 @@ void GameInfo::fillAndStoreResults() StringUtils::timeToString(best_result), best_user); } if (!message.empty()) - getLobby()->sendStringToAllPeers(message); + Comm::sendStringToAllPeers(message); } } // fillAndStoreResults diff --git a/src/utils/hit_processor.cpp b/src/utils/hit_processor.cpp index 5cb17fd44d3..170356fa2d3 100644 --- a/src/utils/hit_processor.cpp +++ b/src/utils/hit_processor.cpp @@ -20,8 +20,8 @@ #include "karts/abstract_kart.hpp" #include "karts/kart_properties.hpp" #include "modes/world.hpp" -#include "network/protocols/server_lobby.hpp" #include "network/server_config.hpp" +#include "utils/communication.hpp" #include "utils/hit_processor.hpp" #include "utils/lobby_settings.hpp" #include "utils/string_utils.hpp" @@ -100,7 +100,7 @@ void HitProcessor::sendTeammateHitMsg(std::string& s) if (ticks - m_last_hit_msg > STKConfig::get()->time2Ticks(g_hit_message_delay)) { m_last_hit_msg = ticks; - getLobby()->sendStringToAllPeers(s); + Comm::sendStringToAllPeers(s); } } // sendTeammateHitMsg //----------------------------------------------------------------------------- diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index cbe8182f3c5..2d21c624073 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -32,6 +32,7 @@ #include "network/game_setup.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" +#include "utils/communication.hpp" #include "utils/game_info.hpp" #include "utils/kart_elimination.hpp" #include "utils/lobby_asset_manager.hpp" @@ -620,7 +621,7 @@ void LobbySettings::tryKickingAnotherPeer(std::shared_ptr initiator, if (!hasKicksAllowed()) { - getLobby()->sendStringToPeer(initiator, "Kicking players is not allowed on this server"); + Comm::sendStringToPeer(initiator, "Kicking players is not allowed on this server"); return; } @@ -629,7 +630,7 @@ void LobbySettings::tryKickingAnotherPeer(std::shared_ptr initiator, { if (target->hammerLevel() > 0) { - getLobby()->sendStringToPeer(initiator, "This player holds admin rights of this server, " + Comm::sendStringToPeer(initiator, "This player holds admin rights of this server, " "and is protected from your actions now"); return; } diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp index 5b358aad76b..52a16cefa52 100644 --- a/src/utils/team_manager.cpp +++ b/src/utils/team_manager.cpp @@ -451,14 +451,14 @@ std::string TeamManager::countTeamsAsString() ++counts[profile->getTemporaryTeam()]; } std::vector> sorted; - for (int i = 0; i < counts.size(); ++i) + for (int i = 0; i < (int)counts.size(); ++i) if (counts[i] > 0) sorted.emplace_back(-counts[i], i); std::sort(sorted.begin(), sorted.end()); std::string res = ""; - for (int i = 0; i < sorted.size(); ++i) + for (int i = 0; i < (int)sorted.size(); ++i) { if (i) res += ", "; From 87f2a3f39e87b8780c83415f28a4fe5754184608 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 3 Jun 2025 22:23:32 +0400 Subject: [PATCH 772/830] Add /network and /everynet --- data/commands.xml | 13 +++ src/network/protocols/command_manager.cpp | 98 +++++++++++++++++++++++ src/network/protocols/command_manager.hpp | 2 + src/network/stk_peer.cpp | 6 +- 4 files changed, 116 insertions(+), 3 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index 8e800c31f26..40ae715f758 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -1203,6 +1203,19 @@ here later. For now, please refer to the code for the strings being used. --> permissions-verbose="everyone; invokable for another player" state-scope="SS_ALWAYS" /> + + getPlayerProfiles().empty()) + { + Log::warn("CommandManager", "net: no existing player profiles??"); + error(context); + return; + } + player_name = acting_peer->getMainName(); + } + else + { + if (!validate(context, 1, TFT_PRESENT_USERS, false, false)) + return; + player_name = argv[1]; + } + std::shared_ptr player_peer = STKHost::get()->findPeerByName( + StringUtils::utf8ToWide(player_name)); + if (player_name.empty() || !player_peer) + { + error(context); + return; + } + + auto enet_peer = player_peer->getENetPeer(); + std::string decorated_name = getLobby()->encodeProfileNameForPeer( + player_peer->getMainProfile(), acting_peer.get()); + + context.say(StringUtils::insertValues( + "%s's network: ping: %s, packet loss: %s", + decorated_name.c_str(), + player_peer->getAveragePing(), + player_peer->getPacketLoss() + )); +} // process_net +// ======================================================================== + +void CommandManager::process_everynet(Context& context) +{ + auto acting_peer = context.actingPeer(); + auto argv = context.m_argv; + + std::string response = "Network stats:"; + using Pair = std::pair, std::vector>; + std::vector result; + for (const auto& p: STKHost::get()->getPeers()) + { + // if (p->isAIPeer()) + // continue; + if (!p->hasPlayerProfiles()) + continue; + + auto enet_peer = p->getENetPeer(); + std::vector overall; + overall.push_back(p->getAveragePing()); + overall.push_back(p->getPacketLoss()); + + result.emplace_back(p->getMainProfile(), overall); + } + + // Sorting order for equal players WILL DEPEND ON NAME DECORATOR! + // This sorting is clearly bad because we ask lobby every time. Change it later. + auto lobby = getLobby(); + std::stable_sort(result.begin(), result.end(), [lobby, acting_peer](const Pair& lhs, const Pair& rhs) -> bool { + return lobby->encodeProfileNameForPeer(lhs.first, acting_peer.get()) + < lobby->encodeProfileNameForPeer(rhs.first, acting_peer.get()); + }); + std::sort(result.begin(), result.end(), [](const Pair& lhs, const Pair& rhs) -> bool { + int diff = lhs.second[0] - rhs.second[0]; + return diff > 0; + }); + for (auto& row: result) + { + response += "\n"; + std::string decorated_name = getLobby()->encodeProfileNameForPeer(row.first, acting_peer.get()); + + std::string msg = StringUtils::insertValues( + "%s's network: ping: %s, packet loss: %s", + decorated_name.c_str(), + row.second[0], + row.second[1] + ); + + response += msg; + } + context.say(response); +} // process_everynet +// ======================================================================== + void CommandManager::process_temp250318(Context& context) { auto& argv = context.m_argv; diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 33c077ce2aa..848f2e5fc5d 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -368,6 +368,8 @@ class CommandManager: public LobbyContextComponent void process_cooldown(Context& context); void process_cooldown_assign(Context& context); void process_countteams(Context& context); + void process_net(Context& context); + void process_everynet(Context& context); // Temporary command void process_temp250318(Context& context); diff --git a/src/network/stk_peer.cpp b/src/network/stk_peer.cpp index 5d10a76218b..4b1a978376c 100644 --- a/src/network/stk_peer.cpp +++ b/src/network/stk_peer.cpp @@ -182,10 +182,10 @@ uint32_t STKPeer::getPing() while (m_previous_pings.size() > ap) { m_previous_pings.pop_front(); - m_average_ping.store( - (uint32_t)(std::accumulate(m_previous_pings.begin(), - m_previous_pings.end(), 0) / m_previous_pings.size())); } + m_average_ping.store( + (uint32_t)(std::accumulate(m_previous_pings.begin(), + m_previous_pings.end(), 0) / m_previous_pings.size())); } return m_enet_peer->roundTripTime; } // getPing From d197ff2aa703650ba51aa8ed8244e786711d22d4 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 6 Jun 2025 11:37:43 +0400 Subject: [PATCH 773/830] Update language version to C++17 (#31) Commit list (they are small and sometimes clueless so I squashed them) * Update to C++17 * Try to fix non-switch build * Try to fix build, with the help of upstream Link to the original commit for switch: https://github.com/supertuxkart/stk-code/commit/68c395a685456e37709426b71d5f2c1e5edbe4a4 * Revert apple.yml fix in attempt to fix iphoneOS build * Try again to fix iphoneos build * Try to use separately compiled apple dependencies except cctools * Use separately built cctools * Change macos 10.9 to 10.13 * Try to not optimize asm for macos * iphoneos 9.0 -> 10.0 * Change iphoneos to 10.0, not 10.13 --- .github/workflows/apple.yml | 6 +++--- .github/workflows/linux.yml | 2 +- CMakeLists.txt | 4 ++-- android/Android.mk | 4 ++-- android/make_deps.sh | 2 +- cmake/Toolchain-ios-xcode.cmake | 4 ++-- data/SuperTuxKart-Info.plist | 2 +- lib/angelscript/source/as_callfunc_x64_gcc.cpp | 6 ++++-- lib/dnsc/CMakeLists.txt | 6 ++++++ lib/graphics_engine/CMakeLists.txt | 2 +- lib/irrlicht/CMakeLists.txt | 2 +- lib/tinygettext/CMakeLists.txt | 2 +- src/karts/kart_properties_manager.cpp | 5 +++-- src/modes/three_strikes_battle.cpp | 5 +++-- src/states_screens/arenas_screen.cpp | 2 +- src/states_screens/easter_egg_screen.cpp | 3 ++- src/states_screens/online/tracks_screen.cpp | 3 ++- src/states_screens/tracks_and_gp_screen.cpp | 3 ++- src/tracks/track.cpp | 9 ++++++++- src/tracks/track.hpp | 5 +---- src/utils/random_generator.cpp | 9 +++++++++ src/utils/random_generator.hpp | 11 +++++++++++ 22 files changed, 67 insertions(+), 30 deletions(-) diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml index 7ba161194b7..e1df3fc058b 100644 --- a/.github/workflows/apple.yml +++ b/.github/workflows/apple.yml @@ -32,7 +32,7 @@ jobs: - name: Download cctools run: | cd /opt - wget https://github.com/supertuxkart/dependencies/releases/download/cctools/cctools-14.1.tar.xz + wget https://github.com/kimden/stk-dependencies/releases/download/cctools/cctools-14.1.tar.xz tar xf cctools-14.1.tar.xz rm cctools-14.1.tar.xz - name: Restore timestamps @@ -66,7 +66,7 @@ jobs: ${{ env.cache_9 }} - name: Download dependencies run: | - wget https://github.com/supertuxkart/dependencies/releases/download/preview/dependencies-${{ steps.sysroot.outputs.lowercase }}.tar.xz + wget https://github.com/kimden/stk-dependencies/releases/download/preview/dependencies-${{ steps.sysroot.outputs.lowercase }}.tar.xz tar xf dependencies-${{ steps.sysroot.outputs.lowercase }}.tar.xz - name: Configure clang runtime name run: | @@ -146,7 +146,7 @@ jobs: env: developer_id: "Developer ID Application: ${{ secrets.MAC_DEVELOPER_NAME }} (${{ secrets.MAC_DEVELOPER_TEAM }})" run: | - wget https://github.com/supertuxkart/dependencies/releases/download/preview/dependencies-macosx.tar.xz + wget https://github.com/kimden/stk-dependencies/releases/download/preview/dependencies-macosx.tar.xz tar xf dependencies-macosx.tar.xz HOMEBREW_NO_AUTO_UPDATE=1 brew install dylibbundler lipo -create ./macosx-x86_64/supertuxkart.app/Contents/MacOS/supertuxkart ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -output ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index a20c4c58218..40982f8b40e 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -137,7 +137,7 @@ jobs: $CXX --version mkdir "build" cd "build" - CFLAGS="-mmacosx-version-min=10.9" CXXFLAGS="-mmacosx-version-min=10.9" LINKFLAGS="-mmacosx-version-min=10.9" LDFLAGS="-mmacosx-version-min=10.9" /usr/local/opt/cmake/bin/cmake .. -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9 -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSERVER_ONLY=$SERVER_ONLY -DCHECK_ASSETS=off -DBUILD_RECORDER=off; + CFLAGS="-mmacosx-version-min=10.13" CXXFLAGS="-mmacosx-version-min=10.13" LINKFLAGS="-mmacosx-version-min=10.13" LDFLAGS="-mmacosx-version-min=10.13" /usr/local/opt/cmake/bin/cmake .. -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSERVER_ONLY=$SERVER_ONLY -DCHECK_ASSETS=off -DBUILD_RECORDER=off; - name: Build and install working-directory: build run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f6423e535f..549c582d385 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -523,7 +523,7 @@ endif() # Set some compiler options if(UNIX OR MINGW) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused-function") endif() @@ -624,7 +624,7 @@ else() add_executable(supertuxkart ${STK_SOURCES} ${STK_RESOURCES} ${STK_HEADERS} ${IOS_ASSETS_FILES}) set_target_properties(supertuxkart PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/data/SuperTuxKart-Info-iOS.plist - XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET 9.0 + XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET 10.0 XCODE_ATTRIBUTE_INSTALL_PATH /Applications XCODE_ATTRIBUTE_SKIP_INSTALL No XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon") diff --git a/android/Android.mk b/android/Android.mk index f0bcdd0c172..3fe29a77060 100644 --- a/android/Android.mk +++ b/android/Android.mk @@ -260,7 +260,7 @@ LOCAL_CFLAGS := -I../lib/irrlicht/source/Irrlicht/ \ -I../lib/graphics_engine/include \ -DMOBILE_STK \ -DANDROID_PACKAGE_CALLBACK_NAME=$(PACKAGE_CALLBACK_NAME) -LOCAL_CPPFLAGS := -std=gnu++0x +LOCAL_CPPFLAGS := -std=gnu++17 LOCAL_STATIC_LIBRARIES := libjpeg png zlib ifeq ($(TARGET_ARCH_ABI), armeabi-v7a) LOCAL_ARM_NEON := false @@ -363,7 +363,7 @@ LOCAL_CFLAGS := -I../lib/angelscript/include \ -DANDROID_APP_DIR_NAME=\"$(APP_DIR_NAME)\" \ -DSUPERTUXKART_VERSION=\"$(PROJECT_VERSION)\" \ -DANDROID_PACKAGE_CLASS_NAME=\"$(PACKAGE_CLASS_NAME)\" -LOCAL_CPPFLAGS := -std=gnu++0x +LOCAL_CPPFLAGS := -std=gnu++17 LOCAL_STATIC_LIBRARIES := irrlicht bullet enet ifaddrs angelscript mcpp SDL2 \ vorbisfile vorbis ogg openal curl libmbedtls \ diff --git a/android/make_deps.sh b/android/make_deps.sh index 445ac74c361..3af6c601c4a 100755 --- a/android/make_deps.sh +++ b/android/make_deps.sh @@ -151,7 +151,7 @@ build_deps() -DFREETYPE_INCLUDE_DIRS="$DIRNAME/deps-$ARCH_OPTION/freetype/include/" \ -DHB_HAVE_GLIB=OFF -DHB_HAVE_GOBJECT=OFF -DHB_HAVE_ICU=OFF \ -DHB_HAVE_FREETYPE=ON -DHB_BUILD_SUBSET=OFF \ - -DCMAKE_C_FLAGS="-fpic -O3 -g" -DCMAKE_CXX_FLAGS="-std=gnu++0x -fpic -O3 -g" && + -DCMAKE_C_FLAGS="-fpic -O3 -g" -DCMAKE_CXX_FLAGS="-std=gnu++17 -fpic -O3 -g" && make -j $(($(nproc) + 1)) check_error mkdir -p "$DIRNAME/deps-$ARCH_OPTION/harfbuzz/include/harfbuzz" diff --git a/cmake/Toolchain-ios-xcode.cmake b/cmake/Toolchain-ios-xcode.cmake index 25e52c030e6..f9b247616ef 100644 --- a/cmake/Toolchain-ios-xcode.cmake +++ b/cmake/Toolchain-ios-xcode.cmake @@ -111,8 +111,8 @@ set(USE_SQLITE3 FALSE CACHE BOOL "") set(USE_CRYPTO_OPENSSL FALSE CACHE BOOL "") set(IOS_LAUNCHSCREEN ${DEPS_PATH}/ios-icon/launch_screen.storyboard) set(IOS_IMAGES_XCASSETS ${DEPS_PATH}/ios-icon/Images.xcassets) -set(SDK_NAME_VERSION_FLAGS "-miphoneos-version-min=9.0") -set(CMAKE_OSX_DEPLOYMENT_TARGET 9.0 CACHE STRING "Set CMake deployment target" FORCE) +set(SDK_NAME_VERSION_FLAGS "-miphoneos-version-min=10.0") +set(CMAKE_OSX_DEPLOYMENT_TARGET 10.13 CACHE STRING "Set CMake deployment target" FORCE) set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64") set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "arm64") diff --git a/data/SuperTuxKart-Info.plist b/data/SuperTuxKart-Info.plist index 97841eeb1b8..357ba8ddde8 100644 --- a/data/SuperTuxKart-Info.plist +++ b/data/SuperTuxKart-Info.plist @@ -25,7 +25,7 @@ CSResourcesFileMapped LSMinimumSystemVersion - 10.9 + 10.13 NSHighResolutionCapable diff --git a/lib/angelscript/source/as_callfunc_x64_gcc.cpp b/lib/angelscript/source/as_callfunc_x64_gcc.cpp index ad6c27fb6d1..7ec828ada30 100644 --- a/lib/angelscript/source/as_callfunc_x64_gcc.cpp +++ b/lib/angelscript/source/as_callfunc_x64_gcc.cpp @@ -79,7 +79,8 @@ static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, i // Backup stack pointer in R15 that is guaranteed to maintain its value over function calls " movq %%rsp, %%r15 \n" -#ifdef __OPTIMIZE__ +// Doesn't compile on macos 10.13 in github actions for some reason. +#if defined(__OPTIMIZE__) && !defined(__APPLE__) // Make sure the stack unwind logic knows we've backed up the stack pointer in register r15 // This should only be done if any optimization is done. If no optimization (-O0) is used, // then the compiler already backups the rsp before entering the inline assembler code @@ -136,7 +137,8 @@ static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, i // Restore stack pointer " mov %%r15, %%rsp \n" -#ifdef __OPTIMIZE__ +// Doesn't compile on macos 10.13 in github actions for some reason. +#if defined(__OPTIMIZE__) && !defined(__APPLE__) // Inform the stack unwind logic that the stack pointer has been restored // This should only be done if any optimization is done. If no optimization (-O0) is used, // then the compiler already backups the rsp before entering the inline assembler code diff --git a/lib/dnsc/CMakeLists.txt b/lib/dnsc/CMakeLists.txt index fd966b52a70..ba94fa55f0e 100644 --- a/lib/dnsc/CMakeLists.txt +++ b/lib/dnsc/CMakeLists.txt @@ -1 +1,7 @@ add_library(dnsc STATIC dns.c) + +set_target_properties(dnsc PROPERTIES + C_STANDARD 99 + C_STANDARD_REQUIRED ON + C_EXTENSIONS OFF +) diff --git a/lib/graphics_engine/CMakeLists.txt b/lib/graphics_engine/CMakeLists.txt index 9de9bb6732e..cf5d21f1783 100644 --- a/lib/graphics_engine/CMakeLists.txt +++ b/lib/graphics_engine/CMakeLists.txt @@ -58,7 +58,7 @@ if(APPLE AND NOT DLOPEN_MOLTENVK) endif() if(UNIX OR MINGW) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17") endif() set(GE_SOURCES diff --git a/lib/irrlicht/CMakeLists.txt b/lib/irrlicht/CMakeLists.txt index 456886322b1..96656dff004 100644 --- a/lib/irrlicht/CMakeLists.txt +++ b/lib/irrlicht/CMakeLists.txt @@ -39,7 +39,7 @@ endif() add_definitions(-DNDEBUG=1 -DIRRLICHT_EXPORTS=1 -DPNG_THREAD_UNSAFE_OK -DPNG_NO_MMX_CODE -DPNG_NO_MNG_FEATURES) if(UNIX OR MINGW) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17") endif() if(WIN32) diff --git a/lib/tinygettext/CMakeLists.txt b/lib/tinygettext/CMakeLists.txt index 52d581fefa2..6c38d509a7e 100644 --- a/lib/tinygettext/CMakeLists.txt +++ b/lib/tinygettext/CMakeLists.txt @@ -82,7 +82,7 @@ add_definitions(-DDISABLE_ICONV) endif() if (UNIX OR MINGW) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17") endif() ## TinyGetText library compilation diff --git a/src/karts/kart_properties_manager.cpp b/src/karts/kart_properties_manager.cpp index 6d163d5095d..0ad6c8a7ad1 100644 --- a/src/karts/kart_properties_manager.cpp +++ b/src/karts/kart_properties_manager.cpp @@ -31,6 +31,7 @@ #include "karts/kart_properties.hpp" #include "karts/xml_characteristic.hpp" #include "utils/log.hpp" +#include "utils/random_generator.hpp" #include "utils/string_utils.hpp" #include @@ -687,8 +688,8 @@ void KartPropertiesManager::getRandomKartList(int count, assert(random_kart_queue.size() > 0); - std::random_shuffle(random_kart_queue.begin(), - random_kart_queue.end() ); + std::shuffle(random_kart_queue.begin(), + random_kart_queue.end(), GlobalMt19937::get()); } while (count > 0 && random_kart_queue.size() > 0) diff --git a/src/modes/three_strikes_battle.cpp b/src/modes/three_strikes_battle.cpp index 9449c827025..8a12061f5d2 100644 --- a/src/modes/three_strikes_battle.cpp +++ b/src/modes/three_strikes_battle.cpp @@ -37,6 +37,7 @@ #include "tracks/track.hpp" #include "tracks/track_object_manager.hpp" #include "utils/constants.hpp" +#include "utils/random_generator.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -708,8 +709,8 @@ void ThreeStrikesBattle::loadCustomModels() } // Find random nodes to pre-spawn spare tire karts - std::random_shuffle(sta_possible_nodes.begin(), - sta_possible_nodes.end()); + std::shuffle(sta_possible_nodes.begin(), + sta_possible_nodes.end(), GlobalMt19937::get()); // Compute a random kart list std::vector sta_list; diff --git a/src/states_screens/arenas_screen.cpp b/src/states_screens/arenas_screen.cpp index 222c1a48614..2a4dc75bd6f 100644 --- a/src/states_screens/arenas_screen.cpp +++ b/src/states_screens/arenas_screen.cpp @@ -354,7 +354,7 @@ void ArenasScreen::buildTrackList() w->addItem(_("Random Arena"), "random_track", "/gui/icons/track_random.png"); w->updateItemDisplay(); - std::random_shuffle( m_random_arena_list.begin(), m_random_arena_list.end() ); + std::shuffle( m_random_arena_list.begin(), m_random_arena_list.end(), GlobalMt19937::get() ); } // ------------------------------------------------------------------------------------------------------ diff --git a/src/states_screens/easter_egg_screen.cpp b/src/states_screens/easter_egg_screen.cpp index 4ef7394ad47..366c1cbf061 100644 --- a/src/states_screens/easter_egg_screen.cpp +++ b/src/states_screens/easter_egg_screen.cpp @@ -29,6 +29,7 @@ #include "states_screens/track_info_screen.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" +#include "utils/random_generator.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -292,7 +293,7 @@ void EasterEggScreen::buildTrackList() 0 /* no badge */, IconButtonWidget::ICON_PATH_TYPE_RELATIVE); tracks_widget->updateItemDisplay(); - std::random_shuffle( m_random_track_list.begin(), m_random_track_list.end() ); + std::shuffle( m_random_track_list.begin(), m_random_track_list.end(), GlobalMt19937::get() ); } // ----------------------------------------------------------------------------- diff --git a/src/states_screens/online/tracks_screen.cpp b/src/states_screens/online/tracks_screen.cpp index 59dfbc6f71e..35ddac920ef 100644 --- a/src/states_screens/online/tracks_screen.cpp +++ b/src/states_screens/online/tracks_screen.cpp @@ -45,6 +45,7 @@ #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/communication.hpp" +#include "utils/random_generator.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -703,7 +704,7 @@ void TracksScreen::buildTrackList() IconButtonWidget::ICON_PATH_TYPE_RELATIVE); tracks_widget->updateItemDisplay(); - std::random_shuffle( m_random_track_list.begin(), m_random_track_list.end() ); + std::shuffle( m_random_track_list.begin(), m_random_track_list.end(), GlobalMt19937::get() ); } // buildTrackList // ----------------------------------------------------------------------------- diff --git a/src/states_screens/tracks_and_gp_screen.cpp b/src/states_screens/tracks_and_gp_screen.cpp index 298581d1207..cb17b40581d 100644 --- a/src/states_screens/tracks_and_gp_screen.cpp +++ b/src/states_screens/tracks_and_gp_screen.cpp @@ -35,6 +35,7 @@ #include "states_screens/dialogs/message_dialog.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" +#include "utils/random_generator.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -375,7 +376,7 @@ void TracksAndGPScreen::buildTrackList() IconButtonWidget::ICON_PATH_TYPE_RELATIVE); tracks_widget->updateItemDisplay(); - std::random_shuffle( m_random_track_list.begin(), m_random_track_list.end() ); + std::shuffle( m_random_track_list.begin(), m_random_track_list.end(), GlobalMt19937::get() ); } // buildTrackList // ----------------------------------------------------------------------------- diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 1bc8e2c28d3..0afa549a42b 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -80,6 +80,7 @@ #include "tracks/track_object_manager.hpp" #include "utils/constants.hpp" #include "utils/log.hpp" +#include "utils/random_generator.hpp" #include "mini_glm.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -2534,7 +2535,13 @@ void Track::loadObjects(const XMLNode* root, const std::string& path, } } // for igetNumNodes() -} +} // loadObjects +//----------------------------------------------------------------------------- + +void Track::shuffleStartTransforms() +{ + std::shuffle(m_start_transforms.begin(), m_start_transforms.end(), GlobalMt19937::get()); +} // shuffleStartTransforms //----------------------------------------------------------------------------- /** Handles a sky-dome or sky-box. It takes the xml node with the diff --git a/src/tracks/track.hpp b/src/tracks/track.hpp index a55b2198af7..62b53c44bc0 100644 --- a/src/tracks/track.hpp +++ b/src/tracks/track.hpp @@ -561,10 +561,7 @@ class Track // ------------------------------------------------------------------------ /** Shuffles the start transformations */ - void shuffleStartTransforms() - { - std::random_shuffle(m_start_transforms.begin(), m_start_transforms.end()); - } + void shuffleStartTransforms(); // ------------------------------------------------------------------------ /** Sets pointer to the aabb of this track. */ void getAABB(const Vec3 **min, const Vec3 **max) const diff --git a/src/utils/random_generator.cpp b/src/utils/random_generator.cpp index 54b2371c44a..97cae6ad03d 100644 --- a/src/utils/random_generator.cpp +++ b/src/utils/random_generator.cpp @@ -66,3 +66,12 @@ int RandomGenerator::get(int n) } // get #endif // if 0 + +//----------------------------------------------------------------------------- + +std::mt19937& GlobalMt19937::get() +{ + static std::shared_ptr instance = std::make_shared(0xDEADBEEF); + return *instance; +} // get +//----------------------------------------------------------------------------- diff --git a/src/utils/random_generator.hpp b/src/utils/random_generator.hpp index 67cabed47ef..2582d6b1cb8 100644 --- a/src/utils/random_generator.hpp +++ b/src/utils/random_generator.hpp @@ -23,6 +23,9 @@ #include #include +#include +#include + /** A random number generator. Each objects that needs a random number uses its own number random generator. They are all seeded with number provided by the server. This guarantees that in a network game all 'random' values @@ -46,4 +49,12 @@ class RandomGenerator void seed(int s) {m_random_value = s;} }; // RandomGenerator +/** This is a temporary bad generator to use + * in what was std::random_shuffle before. */ +class GlobalMt19937 +{ +public: + static std::mt19937& get(); +}; + #endif // HEADER_RANDOM_GENERATOR_HPP From a0e5da6f45fc676bef8081616d66c74f64842025 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Mon, 9 Jun 2025 18:50:47 +0200 Subject: [PATCH 774/830] Improve the scaling of race GUI elements (powerups, speedometer, gauge) - Account for both width and height for scaling. This change is neutral for a 16:9 ratio, but avoids ridiculously large GUI elements in very wide ratios or way too small elements in tall ratios. - Ensure that race GUI elements in splitscreen are not too small (fix #5451) --- src/states_screens/race_gui.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/states_screens/race_gui.cpp b/src/states_screens/race_gui.cpp index 0f692d78283..bf437a12ff6 100644 --- a/src/states_screens/race_gui.cpp +++ b/src/states_screens/race_gui.cpp @@ -374,16 +374,20 @@ void RaceGUI::renderPlayerView(const Camera *camera, float dt) if (!isSpectatorCam) drawPlungerInFace(camera, dt); + // Scale race GUI along screen size + scaling *= sqrtf(float(viewport.getWidth()) / 800.0f); + scaling *= sqrtf(float(viewport.getHeight()) / 450.0f); + + // Scale X and Y separately in splitscreen for proper relative positioning if (viewport.getWidth() != (int)irr_driver->getActualScreenSize().Width || viewport.getHeight() != (int)irr_driver->getActualScreenSize().Height) { - scaling.X *= float(viewport.getWidth()) / float(irr_driver->getActualScreenSize().Width); // scale race GUI along screen size - scaling.Y *= float(viewport.getHeight()) / float(irr_driver->getActualScreenSize().Height); // scale race GUI along screen size - } - else - { - scaling *= float(viewport.getWidth()) / 800.0f; // scale race GUI along screen size + // This is tuned so that in 2-way splitscreen, the UI elements have a size + // close to the icons without splitscreen. + scaling.X *= 1.35f * float(viewport.getWidth()) / float(irr_driver->getActualScreenSize().Width); + scaling.Y *= 1.35f * float(viewport.getHeight()) / float(irr_driver->getActualScreenSize().Height); } + drawAllMessages(kart, viewport, scaling); From 48da00eb24c3f6c1517bb6d0258bc75fc164e250 Mon Sep 17 00:00:00 2001 From: Deve Date: Mon, 9 Jun 2025 23:31:46 +0200 Subject: [PATCH 775/830] Improve ghost shader via depth prepass --- data/shaders/sps_08_ghost.xml | 3 +- .../src/ge_vulkan_draw_call.cpp | 81 ++++++++++++++++--- src/graphics/sp/sp_base.cpp | 14 +++- src/graphics/sp/sp_shader_manager.cpp | 13 ++- 4 files changed, 93 insertions(+), 18 deletions(-) diff --git a/data/shaders/sps_08_ghost.xml b/data/shaders/sps_08_ghost.xml index 56d25a18241..dddc6c64f27 100644 --- a/data/shaders/sps_08_ghost.xml +++ b/data/shaders/sps_08_ghost.xml @@ -1,6 +1,7 @@ - diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index 1c552ccb951..b1dc10d87f4 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -33,9 +33,18 @@ #include "../source/Irrlicht/os.h" #include "quaternion.h" #define DEPTH_ONLY_FRAG_SHADER "depth_only.frag" +#define SKINNING_PIPELINE "_skinning" namespace GE { +// ============================================================================ +static void destroyPipeline(VkPipeline* p) +{ + vkDestroyPipeline(static_cast(getDriver())->getDevice(), + *p, NULL); + delete p; +} // destroyPipeline + // ============================================================================ void ObjectData::init(irr::scene::ISceneNode* node, int material_id, int skinning_offset, int irrlicht_material_id) @@ -489,7 +498,7 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) int material_id = m_texture_descriptor->getTextureID(list, cur_shader); if (skinning) - cur_shader += "_skinning"; + cur_shader += SKINNING_PIPELINE; if (m_graphics_pipelines.find(cur_shader) == m_graphics_pipelines.end()) continue; @@ -912,13 +921,34 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) settings.m_backface_culling = true; settings.m_alphablend = true; settings.m_drawing_priority = (char)9; - settings.m_fragment_shader = "ghost.frag"; + settings.m_fragment_shader = DEPTH_ONLY_FRAG_SHADER; settings.m_shader_name = "ghost"; - createPipeline(vk, settings, dp_cache); + if (doDepthOnlyRenderingFirst()) + { + m_graphics_pipelines["ghost"] = {}; + m_graphics_pipelines["ghost"].m_settings = settings; + m_graphics_pipelines["ghost"].m_pipeline = + dp_cache.at(settings.m_vertex_shader + settings.m_fragment_shader); + m_graphics_pipelines["ghost" SKINNING_PIPELINE] = {}; + m_graphics_pipelines["ghost" SKINNING_PIPELINE].m_settings = settings; + m_graphics_pipelines["ghost" SKINNING_PIPELINE].m_pipeline = + dp_cache.at(settings.m_skinning_vertex_shader + + settings.m_fragment_shader); + } + else + { + createPipeline(vk, settings, dp_cache); + } + settings.m_fragment_shader = "ghost.frag"; settings.m_depth_write = false; + settings.m_shader_name = "ghost_color"; + settings.m_depth_op = VK_COMPARE_OP_EQUAL; + createPipeline(vk, settings, dp_cache); + settings.m_backface_culling = false; settings.m_drawing_priority = (char)10; + settings.m_depth_op = VK_COMPARE_OP_LESS; settings.m_fragment_shader = "transparent.frag"; settings.m_shader_name = "alphablend"; @@ -1145,7 +1175,7 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, return false; std::string key = s.m_shader_name; if (skinning) - key += "_skinning"; + key += SKINNING_PIPELINE; if (m_graphics_pipelines.find(key) == m_graphics_pipelines.end()) { m_graphics_pipelines[key] = {}; @@ -1162,20 +1192,16 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, { std::string key = s.m_shader_name; if (skinning) - key += "_skinning"; + key += SKINNING_PIPELINE; if (m_graphics_pipelines.find(key) == m_graphics_pipelines.end()) { m_graphics_pipelines[key] = {}; m_graphics_pipelines[key].m_settings = s; } - auto dp = [vk](VkPipeline* p) - { - vkDestroyPipeline(vk->getDevice(), *p, NULL); - delete p; - }; if (depth_only) { - auto sp = std::shared_ptr(new VkPipeline(p), dp); + auto sp = std::shared_ptr(new VkPipeline(p), + destroyPipeline); m_graphics_pipelines[key].m_depth_only_pipeline = sp; std::string vs = skinning ? s.m_skinning_vertex_shader : s.m_vertex_shader; @@ -1183,7 +1209,8 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, } else m_graphics_pipelines[key].m_pipeline = - std::shared_ptr(new VkPipeline(p), dp); + std::shared_ptr(new VkPipeline(p), + destroyPipeline); }; VkPipeline graphics_pipeline; @@ -1680,6 +1707,17 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, dynamic_offsets); vkCmdDrawIndexedIndirect(cmd, indirect_buffer, indirect_offset, draw_count, indirect_size); + if (cur_pipeline.rfind("ghost", 0) == 0) + { + std::string gc = "ghost_color"; + if (cur_pipeline.find(SKINNING_PIPELINE) != + std::string::npos) + gc += SKINNING_PIPELINE; + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + *m_graphics_pipelines.at(gc).m_pipeline); + vkCmdDrawIndexedIndirect(cmd, indirect_buffer, + indirect_offset, draw_count, indirect_size); + } } indirect_offset += draw_count * indirect_size; if (!is_last_cmd) @@ -1804,6 +1842,25 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, cur_cmd.instanceCount, cur_cmd.firstIndex, cur_cmd.vertexOffset, use_base_vertex ? cur_cmd.firstInstance : 0); + if (cur_pipeline.rfind("ghost", 0) == 0) + { + std::string gc = "ghost_color"; + if (cur_pipeline.find(SKINNING_PIPELINE) != + std::string::npos) + gc += SKINNING_PIPELINE; + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + *m_graphics_pipelines.at(gc).m_pipeline); + vkCmdDrawIndexed(cmd, cur_cmd.indexCount, + cur_cmd.instanceCount, cur_cmd.firstIndex, + cur_cmd.vertexOffset, + use_base_vertex ? cur_cmd.firstInstance : 0); + if (i != m_cmds.size() - 1 && + m_cmds[i + 1].m_shader.rfind("ghost", 0) == 0) + { + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + *m_graphics_pipelines.at(cur_pipeline).m_pipeline); + } + } } } } diff --git a/src/graphics/sp/sp_base.cpp b/src/graphics/sp/sp_base.cpp index 3d1c32b57ac..ce1962d0a1c 100644 --- a/src/graphics/sp/sp_base.cpp +++ b/src/graphics/sp/sp_base.cpp @@ -448,8 +448,7 @@ void init() { int skinning_tbo_limit; glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE_ARB, &skinning_tbo_limit); - - g_skinning_use_tbo = skinning_tbo_limit >= stk_config->m_max_skinning_bones << 6; + g_skinning_use_tbo = (unsigned)skinning_tbo_limit >= stk_config->m_max_skinning_bones << 6; } else { @@ -1323,6 +1322,17 @@ void draw(RenderPass rp, DrawCallType dct) (p.second[j].second[k].first), &draw_call_uniforms, rp); p.second[j].second[k].first->draw(dct, p.second[j].second[k].second/*material_id*/); + if (p.first->getName().rfind("ghost", 0) == 0) + { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(GL_FALSE); + p.second[j].second[k].first->draw(dct, + p.second[j].second[k].second/*material_id*/); + p.first->use(rp); + } for (SPUniformAssigner* ua : draw_call_uniforms) { ua->reset(); diff --git a/src/graphics/sp/sp_shader_manager.cpp b/src/graphics/sp/sp_shader_manager.cpp index e5057fd525c..258a4182e22 100644 --- a/src/graphics/sp/sp_shader_manager.cpp +++ b/src/graphics/sp/sp_shader_manager.cpp @@ -123,9 +123,16 @@ SPShaderManager::SPShaderManager() glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glEnable(GL_CULL_FACE); - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + } + } + }; + + m_official_unuse_functions = + { + { "ghostUnuse", []() + { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } } }; From c563ba16584af14bdb97bb6149349735a00a9ccb Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Tue, 10 Jun 2025 19:47:33 +0200 Subject: [PATCH 776/830] Fix #5410 --- src/karts/ghost_kart.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/karts/ghost_kart.cpp b/src/karts/ghost_kart.cpp index 66cdb9b3ed0..60f5f9a8c90 100644 --- a/src/karts/ghost_kart.cpp +++ b/src/karts/ghost_kart.cpp @@ -247,7 +247,9 @@ void GhostKart::update(int ticks) // ---------------------------------------------------------------------------- void GhostKart::updateSound(float dt) { - if (!getController()) return; + if (!getController() || + World::getWorld()->getPhase() == World::IN_GAME_MENU_PHASE) + return; GhostController* gc = dynamic_cast(getController()); if (gc == NULL) return; From b43d9c644ec140f61c9b515ed4b1daf6002eace0 Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Thu, 12 Jun 2025 21:06:24 +0200 Subject: [PATCH 777/830] Improve the formula for font size Instead of being driven entirely by the dimension (vertical or horizontal) which is smallest relative to its base value, 3/8th of the effect for text size is always determined by the other dimension. As a result: - Text size changes smoothly when changing resolutions. Before this patch, text size would remain identical no matter how much one dimension was increased if it was not the smallest relative to its base value - Text size is generally bigger at ultra-wide and tall ratios. - This makes the visual feeling of a given font size setting more consistent across different aspect ratios Also: - Use 16:9 instead of 5:4 as the base aspect ratio from which deviations are measured At aspect ratios close to 16:9, changes are minimal. --- src/font/font_with_face.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/font/font_with_face.cpp b/src/font/font_with_face.cpp index 502de94042d..5dc987ce706 100644 --- a/src/font/font_with_face.cpp +++ b/src/font/font_with_face.cpp @@ -395,16 +395,19 @@ void FontWithFace::dumpGlyphPage() } // dumpGlyphPage // ---------------------------------------------------------------------------- -/** Set the face dpi which is resolution-dependent. - * Normal text will range from 0.8, in 640x* resolutions (won't scale below - * that) to 1.0, in 1024x* resolutions, and linearly up. - * Bold text will range from 0.2, in 640x* resolutions (won't scale below - * that) to 0.4, in 1024x* resolutions, and linearly up. +/** Set the face size which is resolution-dependent. */ void FontWithFace::setDPI() { - float scale = std::min(irr_driver->getActualScreenSize().Height / 720.0f, - irr_driver->getActualScreenSize().Width / 900.0f); + float width_factor = irr_driver->getActualScreenSize().Width / 1280.0f; + float height_factor = irr_driver->getActualScreenSize().Height / 720.0f; + float min_factor = std::min(width_factor, height_factor); + float base_factor = width_factor * width_factor * width_factor + * height_factor * height_factor * height_factor + * min_factor * min_factor; + // Scale increases linearly when the aspect ratio remains identical + float scale = sqrtf(sqrtf(sqrtf(base_factor))); + int factorTwo = getScalingFactorTwo(); if (UserConfigParams::m_font_size < 0) From 757503ee3607fb164f248068e4b628a1a75984ff Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Thu, 12 Jun 2025 21:08:44 +0200 Subject: [PATCH 778/830] Fix #5454 During resize, ribbon widgets were setting the extra label size only if it was not already set... Now, it is set to the new appropriate value even if a value was previously set. --- src/guiengine/widgets/ribbon_widget.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/guiengine/widgets/ribbon_widget.cpp b/src/guiengine/widgets/ribbon_widget.cpp index 79373adaee7..c5663639f11 100644 --- a/src/guiengine/widgets/ribbon_widget.cpp +++ b/src/guiengine/widgets/ribbon_widget.cpp @@ -964,11 +964,8 @@ void RibbonWidget::resize() IconButtonWidget* icon = ((IconButtonWidget*)m_active_children.get(i)); - if (icon->m_properties[PROP_EXTEND_LABEL].size() == 0) - { - icon->m_properties[PROP_EXTEND_LABEL] = - StringUtils::toString(one_button_width - icon->m_w); - } + // Update the extra size for the icon label + icon->m_properties[PROP_EXTEND_LABEL] = StringUtils::toString(one_button_width - icon->m_w); m_active_children.get(i)->resize(); // restore backuped size and location (see above for more info) From d63d0fbc9b602a4560c2c2c8dce8c25caa6a800e Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Thu, 12 Jun 2025 22:16:43 +0200 Subject: [PATCH 779/830] Increase density in the addons list by 1/3rd --- src/states_screens/addons_screen.cpp | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/states_screens/addons_screen.cpp b/src/states_screens/addons_screen.cpp index 3f2bd59245c..6ed51e55edb 100644 --- a/src/states_screens/addons_screen.cpp +++ b/src/states_screens/addons_screen.cpp @@ -92,8 +92,7 @@ void AddonsScreen::loadedFromFile() m_icon_loading = m_icon_bank->addTextureAsSprite(icon6); m_icon_needs_update = m_icon_bank->addTextureAsSprite(icon3); - GUIEngine::ListWidget* w_list = - getWidget("list_addons"); + GUIEngine::ListWidget* w_list = getWidget("list_addons"); w_list->setColumnListener(this); } // loadedFromFile @@ -102,8 +101,7 @@ void AddonsScreen::loadedFromFile() void AddonsScreen::beforeAddingWidget() { - GUIEngine::ListWidget* w_list = - getWidget("list_addons"); + GUIEngine::ListWidget* w_list = getWidget("list_addons"); assert(w_list != NULL); w_list->clearColumns(); w_list->addColumn( _("Add-on name"), 3 ); @@ -153,14 +151,12 @@ void AddonsScreen::init() if(UserConfigParams::logAddons()) Log::info("addons", "Using directory <%s>", file_manager->getAddonsDir().c_str()); - GUIEngine::ListWidget* w_list = - getWidget("list_addons"); + GUIEngine::ListWidget* w_list = getWidget("list_addons"); - // This defines the row height ! - m_icon_bank->setScale(1.0f / 72.0f); + m_icon_bank->setScale(1.0f / 96.0f); // 128 is the height of the image file m_icon_bank->setTargetIconSize(128, 128); - w_list->setIcons(m_icon_bank, 2.0f); + w_list->setIcons(m_icon_bank, 1.5f /* defines line height relative to text size */); m_type = "kart"; @@ -272,8 +268,7 @@ void AddonsScreen::loadList() } sorted_list.insertionSort(/*start=*/0, m_sort_desc); - GUIEngine::ListWidget* w_list = - getWidget("list_addons"); + GUIEngine::ListWidget* w_list = getWidget("list_addons"); w_list->clear(); for(unsigned int i=0; iinit(true); - GUIEngine::ListWidget* w_list = - getWidget("list_addons"); + GUIEngine::ListWidget* w_list = getWidget("list_addons"); w_list->clear(); w_list->addItem("spacer", L""); @@ -450,8 +444,7 @@ void AddonsScreen::eventCallback(GUIEngine::Widget* widget, else if (name == "list_addons") { - GUIEngine::ListWidget* list = - getWidget("list_addons"); + GUIEngine::ListWidget* list = getWidget("list_addons"); std::string id = list->getSelectionInternalName(); if (!id.empty() && addons_manager->getAddon(id) != NULL) @@ -498,8 +491,7 @@ void AddonsScreen::setLastSelected() { if(m_selected_index>-1) { - GUIEngine::ListWidget* list = - getWidget("list_addons"); + GUIEngine::ListWidget* list = getWidget("list_addons"); list->setFocusForPlayer(PLAYER_ID_GAME_MASTER); list->setSelectionID(m_selected_index); } From 46f9954378d99d6c62ca9c8d0ebec12e92afe497 Mon Sep 17 00:00:00 2001 From: Deve Date: Thu, 12 Jun 2025 23:25:38 +0200 Subject: [PATCH 780/830] Remove duplicated code in vulkan draw call --- .../include/ge_vulkan_driver.hpp | 3 + .../src/ge_vulkan_draw_call.cpp | 304 ++++++------------ .../src/ge_vulkan_draw_call.hpp | 58 ++-- lib/graphics_engine/src/ge_vulkan_driver.cpp | 39 ++- .../src/ge_vulkan_scene_manager.cpp | 2 +- 5 files changed, 178 insertions(+), 228 deletions(-) diff --git a/lib/graphics_engine/include/ge_vulkan_driver.hpp b/lib/graphics_engine/include/ge_vulkan_driver.hpp index 39735d87c35..5996f74c2c0 100644 --- a/lib/graphics_engine/include/ge_vulkan_driver.hpp +++ b/lib/graphics_engine/include/ge_vulkan_driver.hpp @@ -26,6 +26,7 @@ namespace GE { class GESPM; class GEVulkanAttachmentTexture; + class GEVulkanCameraSceneNode; class GEVulkanDrawCall; class GEVulkanDynamicSPMBuffer; class GEVulkanFBOTexture; @@ -378,6 +379,8 @@ namespace GE { m_dynamic_spm_buffers.insert(buffer); } void removeDynamicSPMBuffer(GEVulkanDynamicSPMBuffer* buffer) { m_dynamic_spm_buffers.erase(buffer); } + void renderDrawCalls(const std::vector >& p, + VkCommandBuffer cmd); private: struct SwapChainSupportDetails { diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index b1dc10d87f4..e7dfcc6bf1a 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -440,6 +440,7 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) mapped_addr += extra; } + size_t dynamic_spm_offset = 0; for (auto& p : m_dynamic_spm_buffers) { for (auto& q : p.second) @@ -459,9 +460,11 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) getShader(m)); ObjectData* data = (ObjectData*)mapped_addr; data->init(node, material_id, -1, 0); - m_dyspmb_materials[q.first] = material_id; + m_dyspmb_materials[q.first] = std::make_pair(material_id, + dynamic_spm_offset); written_size += dynamic_spm_size; mapped_addr += dynamic_spm_size; + dynamic_spm_offset += dynamic_spm_size; } } m_dynamic_spm_padded_size = written_size - skinning_data_padded_size; @@ -660,7 +663,7 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) std::string sorting_key = std::string(1, settings.m_drawing_priority) + cur_shader; m_cmds.push_back({ cmd, cur_shader, sorting_key, mb, material_id, - settings.isTransparent(), offset_map[cmd.firstInstance] }); + offset_map[cmd.firstInstance] }); if (!skip_instance_key && it == cur_key.end()) cur_key.push_back(key); } @@ -680,12 +683,6 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) return a.m_sorting_key < b.m_sorting_key; }); - std::stable_partition(m_cmds.begin(), m_cmds.end(), - [](const DrawCallData& a) - { - return !a.m_transparent; - }); - size_t object_data_padded_size = written_size - skinning_data_padded_size; if (object_data_padded_size > m_object_data_padded_size) { @@ -876,6 +873,7 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) settings.m_backface_culling = true; settings.m_depth_op = VK_COMPARE_OP_LESS; settings.m_vertex_description = getDefaultVertexDescription(); + settings.m_pipeline_type = GVPT_SOLID; settings.m_vertex_shader = "spm.vert"; settings.m_skinning_vertex_shader = "spm_skinning.vert"; @@ -916,6 +914,7 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) settings.m_skinning_vertex_shader = "spm_skinning.vert"; settings.m_depth_only_fragment_shader = ""; settings.m_push_constants_func = nullptr; + settings.m_pipeline_type = GVPT_GHOST_DEPTH; settings.m_depth_write = true; settings.m_backface_culling = true; @@ -927,22 +926,22 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) { m_graphics_pipelines["ghost"] = {}; m_graphics_pipelines["ghost"].m_settings = settings; - m_graphics_pipelines["ghost"].m_pipeline = + m_graphics_pipelines["ghost"].m_pipelines[GVPT_GHOST_DEPTH] = dp_cache.at(settings.m_vertex_shader + settings.m_fragment_shader); m_graphics_pipelines["ghost" SKINNING_PIPELINE] = {}; m_graphics_pipelines["ghost" SKINNING_PIPELINE].m_settings = settings; - m_graphics_pipelines["ghost" SKINNING_PIPELINE].m_pipeline = - dp_cache.at(settings.m_skinning_vertex_shader + - settings.m_fragment_shader); + m_graphics_pipelines["ghost" SKINNING_PIPELINE] + .m_pipelines[GVPT_GHOST_DEPTH] = dp_cache.at( + settings.m_skinning_vertex_shader + settings.m_fragment_shader); } else { createPipeline(vk, settings, dp_cache); } + settings.m_pipeline_type = GVPT_TRANSPARENT; settings.m_fragment_shader = "ghost.frag"; settings.m_depth_write = false; - settings.m_shader_name = "ghost_color"; settings.m_depth_op = VK_COMPARE_OP_EQUAL; createPipeline(vk, settings, dp_cache); @@ -961,6 +960,7 @@ void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) settings.m_drawing_priority = (char)11; createPipeline(vk, settings, dp_cache); + settings.m_pipeline_type = GVPT_SKYBOX; settings.m_alphablend = false; settings.m_additive = false; settings.m_custom_pl = m_skybox_layout; @@ -1181,7 +1181,7 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, m_graphics_pipelines[key] = {}; m_graphics_pipelines[key].m_settings = s; } - m_graphics_pipelines[key].m_depth_only_pipeline = it->second; + m_graphics_pipelines[key].m_pipelines[GVPT_DEPTH] = it->second; return true; }; @@ -1202,15 +1202,17 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, { auto sp = std::shared_ptr(new VkPipeline(p), destroyPipeline); - m_graphics_pipelines[key].m_depth_only_pipeline = sp; + m_graphics_pipelines[key].m_pipelines[GVPT_DEPTH] = sp; std::string vs = skinning ? s.m_skinning_vertex_shader : s.m_vertex_shader; dp_cache[vs + s.m_depth_only_fragment_shader] = sp; } else - m_graphics_pipelines[key].m_pipeline = + { + m_graphics_pipelines[key].m_pipelines[s.m_pipeline_type] = std::shared_ptr(new VkPipeline(p), destroyPipeline); + } }; VkPipeline graphics_pipeline; @@ -1485,7 +1487,7 @@ void GEVulkanDrawCall::uploadDynamicData(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, VkCommandBuffer custom_cmd) { - if (!m_dynamic_data || m_cmds.empty()) + if (!m_dynamic_data) return; VkCommandBuffer cmd = @@ -1567,23 +1569,18 @@ void GEVulkanDrawCall::bindBaseVertex(GEVulkanDriver* vk, VkCommandBuffer cmd) } // bindBaseVertex // ---------------------------------------------------------------------------- -void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, - VkCommandBuffer custom_cmd) +void GEVulkanDrawCall::prepareRendering(GEVulkanDriver* vk) { - if (m_data_layout == VK_NULL_HANDLE || m_cmds.empty()) - return; - - VkCommandBuffer cmd = - custom_cmd ? custom_cmd : vk->getCurrentCommandBuffer(); - int current_buffer_idx = vk->getCurrentBufferIdx(); - - const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering(); - const bool bind_mesh_textures = GEVulkanFeatures::supportsBindMeshTexturesAtOnce(); - updatePushConstants(); updateDataDescriptorSets(vk); m_texture_descriptor->updateDescriptor(); +} // prepareRendering +// ---------------------------------------------------------------------------- +void GEVulkanDrawCall::prepareViewport(GEVulkanDriver* vk, + GEVulkanCameraSceneNode* cam, + VkCommandBuffer cmd) +{ VkViewport vp; float scale = getGEConfig()->m_render_scale; if (vk->getSeparateRTTTexture()) @@ -1603,30 +1600,46 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, scissor.extent.width = vp.width; scissor.extent.height = vp.height; vkCmdSetScissor(cmd, 0, 1, &scissor); +} // prepareViewport - bool depth_only = doDepthOnlyRenderingFirst(); - bool bound_mesh_textures_once = false; - VkPipeline prev_dp = VK_NULL_HANDLE; -start: - std::string cur_pipeline = m_cmds[0].m_shader; +// ---------------------------------------------------------------------------- +std::vector GEVulkanDrawCall::getDefaultDynamicOffsets() const +{ + if (GEVulkanFeatures::supportsBindMeshTexturesAtOnce()) + return std::vector(5, 0); + else + return std::vector(4, 0); +} // getDefaultDynamicOffsets + +// ---------------------------------------------------------------------------- +void GEVulkanDrawCall::bindAllMaterials(VkCommandBuffer cmd) +{ + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + m_pipeline_layout, 0, 1, + m_texture_descriptor->getDescriptorSet(), 0, NULL); +} // bindAllMaterials + +// ---------------------------------------------------------------------------- +void GEVulkanDrawCall::renderPipeline(GEVulkanDriver* vk, VkCommandBuffer cmd, + GEVulkanPipelineType pt, + bool& rebind_base_vertex) +{ + if (m_data_layout == VK_NULL_HANDLE || m_cmds.empty()) + return; + + int current_buffer_idx = vk->getCurrentBufferIdx(); + + const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering(); + const bool bind_mesh_textures = GEVulkanFeatures::supportsBindMeshTexturesAtOnce(); + + VkPipeline prev_pipeline = VK_NULL_HANDLE; + std::string cur_pipeline; auto dynamic_spm_buffers = m_dynamic_spm_buffers; - bool drawn_skybox = false; bool bound = false; - size_t sbo_alignment = m_limits.minStorageBufferOffsetAlignment; - const size_t dynamic_spm_size = sizeof(ObjectData) + getPadding( - sizeof(ObjectData), sbo_alignment); - size_t dynamic_spm_offset = 0; int cur_mid = -1; - std::vector dynamic_offsets = - { - 0u, - 0u, - 0u, - 0u, - 0u, - }; - if (getGEConfig()->m_pbr) + std::vector dynamic_offsets = getDefaultDynamicOffsets(); + if (getGEConfig()->m_pbr && pt == GVPT_SOLID) { vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 2, 1, @@ -1634,13 +1647,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, } if (bind_mesh_textures) { - if (!bound_mesh_textures_once) - { - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - m_pipeline_layout, 0, 1, - m_texture_descriptor->getDescriptorSet(), 0, NULL); - bound_mesh_textures_once = true; - } + cur_pipeline = m_cmds[0].m_shader; size_t indirect_offset = getLightDataOffset(); if (m_light_handler) indirect_offset += m_light_handler->getSize(); @@ -1650,31 +1657,15 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, GEVulkanDynamicBuffer::supportsHostTransfer() ? m_dynamic_data->getHostBuffer()[current_buffer_idx] : m_dynamic_data->getLocalBuffer()[current_buffer_idx]; - bool rebind_base_vertex = true; for (unsigned i = 0; i < m_cmds.size(); i++) { - if (m_cmds[i].m_transparent && !drawn_skybox) - { - drawn_skybox = true; - if (!depth_only) - { - drawSkyBox(cmd, current_buffer_idx, dynamic_offsets); - - bindDataDescriptor(cmd, current_buffer_idx, - dynamic_offsets); - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, - 0, 1, m_texture_descriptor->getDescriptorSet(), 0, - NULL); - } - } bool is_last_cmd = (i == m_cmds.size() - 1); bool pipeline_change = !is_last_cmd && m_cmds[i + 1].m_shader != cur_pipeline; draw_count++; if (pipeline_change || is_last_cmd) { - bound = bindPipeline(cmd, cur_pipeline, depth_only, &prev_dp); + bound = bindPipeline(cmd, cur_pipeline, &prev_pipeline, pt); auto it = dynamic_spm_buffers.find( getDynamicBufferKey(cur_pipeline)); if (it != dynamic_spm_buffers.end()) @@ -1683,14 +1674,14 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, { if (bound) { - dynamic_offsets[1] = dynamic_spm_offset; + auto& dy_offsets = m_dyspmb_materials[buf.first]; + dynamic_offsets[1] = dy_offsets.second; rebind_base_vertex = true; bindDataDescriptor(cmd, current_buffer_idx, dynamic_offsets); buf.first->drawDynamicVertexIndexBuffer(cmd, current_buffer_idx); } - dynamic_spm_offset += dynamic_spm_size; } dynamic_spm_buffers.erase(it); } @@ -1707,17 +1698,6 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, dynamic_offsets); vkCmdDrawIndexedIndirect(cmd, indirect_buffer, indirect_offset, draw_count, indirect_size); - if (cur_pipeline.rfind("ghost", 0) == 0) - { - std::string gc = "ghost_color"; - if (cur_pipeline.find(SKINNING_PIPELINE) != - std::string::npos) - gc += SKINNING_PIPELINE; - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - *m_graphics_pipelines.at(gc).m_pipeline); - vkCmdDrawIndexedIndirect(cmd, indirect_buffer, - indirect_offset, draw_count, indirect_size); - } } indirect_offset += draw_count * indirect_size; if (!is_last_cmd) @@ -1730,86 +1710,35 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, } else { - dynamic_offsets.resize(4); - bool rebind_base_vertex = true; - bound = bindPipeline(cmd, cur_pipeline, depth_only, &prev_dp); - auto it = dynamic_spm_buffers.find( - getDynamicBufferKey(cur_pipeline)); - if (it != dynamic_spm_buffers.end()) - { - for (auto& buf : it->second) - { - int dy_mat = m_dyspmb_materials[buf.first]; - if (dy_mat != cur_mid) - { - cur_mid = dy_mat; - bindSingleMaterial(cmd, cur_pipeline, cur_mid, depth_only); - } - if (bound) - { - dynamic_offsets[1] = dynamic_spm_offset; - rebind_base_vertex = true; - bindDataDescriptor(cmd, current_buffer_idx, - dynamic_offsets); - buf.first->drawDynamicVertexIndexBuffer(cmd, - current_buffer_idx); - } - dynamic_spm_offset += dynamic_spm_size; - } - dynamic_spm_buffers.erase(it); - } - if (cur_mid != m_cmds[0].m_material_id) - { - cur_mid = m_cmds[0].m_material_id; - bindSingleMaterial(cmd, cur_pipeline, cur_mid, depth_only); - } for (unsigned i = 0; i < m_cmds.size(); i++) { const VkDrawIndexedIndirectCommand& cur_cmd = m_cmds[i].m_cmd; - if (m_cmds[i].m_transparent && !drawn_skybox) - { - drawn_skybox = true; - if (!depth_only) - { - drawSkyBox(cmd, current_buffer_idx, dynamic_offsets); - - bindDataDescriptor(cmd, current_buffer_idx, - dynamic_offsets); - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, - 1, &m_texture_descriptor->getDescriptorSet()[cur_mid], - 0, NULL); - if (use_base_vertex) - rebind_base_vertex = true; - } - } if (m_cmds[i].m_shader != cur_pipeline) { cur_pipeline = m_cmds[i].m_shader; - bound = bindPipeline(cmd, cur_pipeline, depth_only, &prev_dp); + bound = bindPipeline(cmd, cur_pipeline, &prev_pipeline, pt); auto it = dynamic_spm_buffers.find( getDynamicBufferKey(cur_pipeline)); if (it != dynamic_spm_buffers.end()) { for (auto& buf : it->second) { - int dy_mat = m_dyspmb_materials[buf.first]; + auto& dy_offsets = m_dyspmb_materials[buf.first]; + int dy_mat = dy_offsets.first; if (dy_mat != cur_mid) { cur_mid = dy_mat; - bindSingleMaterial(cmd, cur_pipeline, cur_mid, - depth_only); + bindSingleMaterial(cmd, cur_pipeline, cur_mid, pt); } if (bound) { - dynamic_offsets[1] = dynamic_spm_offset; + dynamic_offsets[1] = dy_offsets.second; rebind_base_vertex = true; bindDataDescriptor(cmd, current_buffer_idx, dynamic_offsets); buf.first->drawDynamicVertexIndexBuffer(cmd, current_buffer_idx); } - dynamic_spm_offset += dynamic_spm_size; } dynamic_spm_buffers.erase(it); } @@ -1818,18 +1747,18 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, if (cur_mid != mid) { cur_mid = mid; - bindSingleMaterial(cmd, cur_pipeline, cur_mid, depth_only); - } - if (use_base_vertex && rebind_base_vertex) - { - bindBaseVertex(vk, cmd); - rebind_base_vertex = false; - dynamic_offsets[1] = m_dynamic_spm_padded_size; - bindDataDescriptor(cmd, current_buffer_idx, - dynamic_offsets); + bindSingleMaterial(cmd, cur_pipeline, cur_mid, pt); } if (bound) { + if (use_base_vertex && rebind_base_vertex) + { + bindBaseVertex(vk, cmd); + rebind_base_vertex = false; + dynamic_offsets[1] = m_dynamic_spm_padded_size; + bindDataDescriptor(cmd, current_buffer_idx, + dynamic_offsets); + } if (!use_base_vertex) { dynamic_offsets[1] = m_dynamic_spm_padded_size + @@ -1842,72 +1771,37 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, cur_cmd.instanceCount, cur_cmd.firstIndex, cur_cmd.vertexOffset, use_base_vertex ? cur_cmd.firstInstance : 0); - if (cur_pipeline.rfind("ghost", 0) == 0) - { - std::string gc = "ghost_color"; - if (cur_pipeline.find(SKINNING_PIPELINE) != - std::string::npos) - gc += SKINNING_PIPELINE; - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - *m_graphics_pipelines.at(gc).m_pipeline); - vkCmdDrawIndexed(cmd, cur_cmd.indexCount, - cur_cmd.instanceCount, cur_cmd.firstIndex, - cur_cmd.vertexOffset, - use_base_vertex ? cur_cmd.firstInstance : 0); - if (i != m_cmds.size() - 1 && - m_cmds[i + 1].m_shader.rfind("ghost", 0) == 0) - { - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - *m_graphics_pipelines.at(cur_pipeline).m_pipeline); - } - } } } } - if (!drawn_skybox && !depth_only) - drawSkyBox(cmd, current_buffer_idx, dynamic_offsets); for (auto& p : dynamic_spm_buffers) { std::string dy_pipeline = getShaderFromKey(p.first); - bound = bindPipeline(cmd, dy_pipeline, depth_only, &prev_dp); + bound = bindPipeline(cmd, dy_pipeline, &prev_pipeline, pt); for (auto& buf : p.second) { - if (bind_mesh_textures) + auto& dy_offsets = m_dyspmb_materials[buf.first]; + if (!bind_mesh_textures) { - if (!drawn_skybox && !depth_only) - { - vkCmdBindDescriptorSets(cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, - 1, m_texture_descriptor->getDescriptorSet(), 0, NULL); - } - } - else - { - int dy_mat = m_dyspmb_materials[buf.first]; + int dy_mat = dy_offsets.first; if (dy_mat != cur_mid) { cur_mid = dy_mat; - bindSingleMaterial(cmd, dy_pipeline, cur_mid, depth_only); + bindSingleMaterial(cmd, dy_pipeline, cur_mid, pt); } } if (bound) { - dynamic_offsets[1] = dynamic_spm_offset; + dynamic_offsets[1] = dy_offsets.second; + rebind_base_vertex = true; bindDataDescriptor(cmd, current_buffer_idx, dynamic_offsets); buf.first->drawDynamicVertexIndexBuffer(cmd, current_buffer_idx); } - dynamic_spm_offset += dynamic_spm_size; } } - - if (depth_only) - { - depth_only = false; - goto start; - } -} // render +} // renderPipeline // ---------------------------------------------------------------------------- size_t GEVulkanDrawCall::getInitialSBOSize() const @@ -2061,32 +1955,38 @@ void GEVulkanDrawCall::addSkyBox(scene::ISceneNode* node) } // addSkyBox // ---------------------------------------------------------------------------- -void GEVulkanDrawCall::drawSkyBox(VkCommandBuffer cmd, int current_buffer_idx, - std::vector& dynamic_offsets) +bool GEVulkanDrawCall::renderSkyBox(GEVulkanDriver* vk, VkCommandBuffer cmd) { if (!m_skybox_renderer || !m_skybox_renderer->getDescriptorSet()) - return; + return false; vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - *m_graphics_pipelines["skybox"].m_pipeline.get()); + *m_graphics_pipelines["skybox"].m_pipelines[GVPT_SKYBOX].get()); vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_skybox_layout, 0, 1, m_skybox_renderer->getDescriptorSet(), 0, NULL); + int current_buffer_idx = vk->getCurrentBufferIdx(); + std::vector dynamic_offsets = getDefaultDynamicOffsets(); vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_skybox_layout, 1, 1, &m_data_descriptor_sets[current_buffer_idx], dynamic_offsets.size(), dynamic_offsets.data()); vkCmdDraw(cmd, 3, 1, 0, 0); -} // drawSkyBox + return true; +} // renderSkyBox // ---------------------------------------------------------------------------- void GEVulkanDrawCall::bindSingleMaterial(VkCommandBuffer cmd, const std::string& cur_pipeline, - int material_id, bool depth_only) + int material_id, + GEVulkanPipelineType pt) { + const PipelineData& data = m_graphics_pipelines.at(cur_pipeline); - const PipelineSettings s = data.m_settings; - if (depth_only && + if (data.m_pipelines.find(pt) == data.m_pipelines.end()) + return; + const PipelineSettings& s = data.m_settings; + if (pt == GVPT_GHOST_DEPTH || (pt == GVPT_DEPTH && (s.m_depth_only_fragment_shader == DEPTH_ONLY_FRAG_SHADER || - s.m_depth_only_fragment_shader.empty())) + s.m_depth_only_fragment_shader.empty()))) return; vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, 1, diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp index 9f421eb6dd1..aa0bdbcf5f2 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp @@ -72,6 +72,15 @@ struct ObjectData bool sky_particle, bool backface_culling); }; +enum GEVulkanPipelineType : unsigned +{ + GVPT_DEPTH = 1, + GVPT_SOLID, + GVPT_GHOST_DEPTH, + GVPT_TRANSPARENT, + GVPT_SKYBOX +}; + struct PipelineSettings { std::string m_vertex_shader; @@ -89,15 +98,15 @@ struct PipelineSettings VkPipelineLayout m_custom_pl; VkCompareOp m_depth_op; VertexDescription m_vertex_description; + GEVulkanPipelineType m_pipeline_type; bool isTransparent() const { return m_alphablend || m_additive; } }; - struct PipelineData { PipelineSettings m_settings; - std::shared_ptr m_pipeline, m_depth_only_pipeline; + std::unordered_map > m_pipelines; }; struct DrawCallData @@ -107,7 +116,6 @@ struct DrawCallData std::string m_sorting_key; GESPMBuffer* m_mb; int m_material_id; - bool m_transparent; uint32_t m_dynamic_offset; }; @@ -173,7 +181,7 @@ class GEVulkanDrawCall std::unordered_map m_graphics_pipelines; - std::unordered_map m_dyspmb_materials; + std::unordered_map > m_dyspmb_materials; GEVulkanSkyBoxRenderer* m_skybox_renderer; @@ -197,19 +205,15 @@ class GEVulkanDrawCall std::string getShader(irr::scene::ISceneNode* node, int material_id); // ------------------------------------------------------------------------ bool bindPipeline(VkCommandBuffer cmd, const std::string& name, - bool depth_only, VkPipeline* prev_dp) const + VkPipeline* prev_pipeline, GEVulkanPipelineType pt) const { auto& ret = m_graphics_pipelines.at(name); - VkPipeline p = *ret.m_pipeline.get(); - if (depth_only) - { - if (!ret.m_depth_only_pipeline) - return false; - p = *ret.m_depth_only_pipeline.get(); - if (*prev_dp == p) - return true; - *prev_dp = p; - } + if (ret.m_pipelines.find(pt) == ret.m_pipelines.end()) + return false; + VkPipeline p = *ret.m_pipelines.at(pt); + if (*prev_pipeline == p) + return true; + *prev_pipeline = p; vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, p); auto it = m_push_constants.find(ret.m_settings.m_shader_name); if (it != m_push_constants.end()) @@ -249,9 +253,6 @@ class GEVulkanDrawCall std::string getShaderFromKey(const std::string& key) const { return key.substr(2); } // ------------------------------------------------------------------------ - void drawSkyBox(VkCommandBuffer cmd, int current_buffer_idx, - std::vector& dynamic_offsets); - // ------------------------------------------------------------------------ void updatePushConstants() { for (auto& p : m_push_constants) @@ -269,7 +270,7 @@ class GEVulkanDrawCall // ------------------------------------------------------------------------ void bindSingleMaterial(VkCommandBuffer cmd, const std::string& cur_pipeline, - int material_id, bool depth_only); + int material_id, GEVulkanPipelineType pt); // ------------------------------------------------------------------------ void bindDataDescriptor(VkCommandBuffer cmd, int current_buffer_idx, std::vector& dynamic_offsets) @@ -280,11 +281,11 @@ class GEVulkanDrawCall dynamic_offsets.size(), dynamic_offsets.data()); } // ------------------------------------------------------------------------ - bool doDepthOnlyRenderingFirst(); - // ------------------------------------------------------------------------ VertexDescription getDefaultVertexDescription() const; // ------------------------------------------------------------------------ size_t getLightDataOffset() const; + // ------------------------------------------------------------------------ + std::vector getDefaultDynamicOffsets() const; public: // ------------------------------------------------------------------------ GEVulkanDrawCall(); @@ -303,8 +304,19 @@ class GEVulkanDrawCall void uploadDynamicData(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, VkCommandBuffer custom_cmd = VK_NULL_HANDLE); // ------------------------------------------------------------------------ - void render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, - VkCommandBuffer custom_cmd = VK_NULL_HANDLE); + bool doDepthOnlyRenderingFirst(); + // ------------------------------------------------------------------------ + void bindAllMaterials(VkCommandBuffer cmd); + // ------------------------------------------------------------------------ + void prepareRendering(GEVulkanDriver* vk); + // ------------------------------------------------------------------------ + void prepareViewport(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, + VkCommandBuffer cmd); + // ------------------------------------------------------------------------ + void renderPipeline(GEVulkanDriver* vk, VkCommandBuffer cmd, + GEVulkanPipelineType pt, bool& rebind_base_vertex); + // ------------------------------------------------------------------------ + bool renderSkyBox(GEVulkanDriver* vk, VkCommandBuffer cmd); // ------------------------------------------------------------------------ unsigned getPolyCount() const { diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index 387d9dd17eb..87944dd92de 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -2439,12 +2439,13 @@ void GEVulkanDriver::buildCommandBuffers() vkCmdBeginRenderPass(getCurrentCommandBuffer(), &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); + std::vector > dcs; for (auto& p : static_cast( m_irrlicht_device->getSceneManager())->getDrawCalls()) { - p.second->render(this, p.first); - PrimitivesDrawn += p.second->getPolyCount(); + dcs.emplace_back(p.second.get(), p.first); } + renderDrawCalls(dcs, getCurrentCommandBuffer()); if (m_rtt_texture) { @@ -2467,6 +2468,40 @@ void GEVulkanDriver::buildCommandBuffers() handleDeletedTextures(); } // buildCommandBuffers +// ---------------------------------------------------------------------------- +void GEVulkanDriver::renderDrawCalls( + const std::vector >& p, + VkCommandBuffer cmd) +{ + bool rebind_base_vertex = true; + const bool bind_mesh_textures = + GEVulkanFeatures::supportsBindMeshTexturesAtOnce(); + for (auto& q : p) + { + if (bind_mesh_textures) + q.first->bindAllMaterials(cmd); + else + rebind_base_vertex = true; + q.first->prepareRendering(this); + q.first->prepareViewport(this, q.second, cmd); + if (q.first->doDepthOnlyRenderingFirst()) + q.first->renderPipeline(this, cmd, GVPT_DEPTH, rebind_base_vertex); + q.first->renderPipeline(this, cmd, GVPT_SOLID, rebind_base_vertex); + if (q.first->renderSkyBox(this, cmd)) + { + if (bind_mesh_textures) + q.first->bindAllMaterials(cmd); + else + rebind_base_vertex = true; + } + q.first->renderPipeline(this, cmd, GVPT_GHOST_DEPTH, + rebind_base_vertex); + q.first->renderPipeline(this, cmd, GVPT_TRANSPARENT, + rebind_base_vertex); + PrimitivesDrawn += q.first->getPolyCount(); + } +} // renderDrawCalls + // ---------------------------------------------------------------------------- VkFormat GEVulkanDriver::findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, diff --git a/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp b/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp index b0f14b081eb..d47c83a9118 100644 --- a/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp +++ b/lib/graphics_engine/src/ge_vulkan_scene_manager.cpp @@ -212,7 +212,7 @@ void GEVulkanSceneManager::drawAll(irr::u32 flags) render_pass_info.pClearValues = &clear_values[0]; vkCmdBeginRenderPass(cmd, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); - dc->render(vk, cam, cmd); + vk->renderDrawCalls({{ dc.get(), cam }}, cmd); vk->addRTTPolyCount(dc->getPolyCount()); dc->reset(); From 45695dfa93bfb95d315d423d9ee4d5a782601e4a Mon Sep 17 00:00:00 2001 From: Alayan <25536748+Alayan-stk-2@users.noreply.github.com> Date: Fri, 13 Jun 2025 22:03:25 +0200 Subject: [PATCH 781/830] Minor cleanup --- src/guiengine/engine.cpp | 9 ++--- .../widgets/dynamic_ribbon_widget.cpp | 35 +++++-------------- 2 files changed, 11 insertions(+), 33 deletions(-) diff --git a/src/guiengine/engine.cpp b/src/guiengine/engine.cpp index 3c69828e983..30e95e906ef 100644 --- a/src/guiengine/engine.cpp +++ b/src/guiengine/engine.cpp @@ -1238,12 +1238,9 @@ namespace GUIEngine Private::font_height = g_font->getDimension( L"X" ).Height; Private::large_font_height = g_large_font->getDimension( L"X" ).Height; Private::small_font_height = g_small_font->getDimension( L"X" ).Height; - Private::title_font_height = - g_title_font->getDimension( L"X" ).Height; - Private::small_title_font_height = - g_small_title_font->getDimension( L"X" ).Height; - Private::tiny_title_font_height = - g_tiny_title_font->getDimension( L"X" ).Height; + Private::title_font_height = g_title_font->getDimension( L"X" ).Height; + Private::small_title_font_height = g_small_title_font->getDimension( L"X" ).Height; + Private::tiny_title_font_height = g_tiny_title_font->getDimension( L"X" ).Height; if (ScreenKeyboard::isActive()) ScreenKeyboard::getCurrent()->onResize(); if (ModalDialog::isADialogActive()) diff --git a/src/guiengine/widgets/dynamic_ribbon_widget.cpp b/src/guiengine/widgets/dynamic_ribbon_widget.cpp index bb6fbe0c0a6..e4c014a8f68 100644 --- a/src/guiengine/widgets/dynamic_ribbon_widget.cpp +++ b/src/guiengine/widgets/dynamic_ribbon_widget.cpp @@ -737,14 +737,13 @@ EventPropagation DynamicRibbonWidget::rightPressed(const int playerID) if (w != NULL) { updateLabel(); - propagateSelection(); const int listenerAmount = m_hover_listeners.size(); for (int n=0; ngetSelectionIDString(playerID), - getSelectedRibbon(playerID)->getSelectionText(playerID), playerID); + m_hover_listeners[n].onSelectionChanged(this, w->getSelectionIDString(playerID), + w->getSelectionText(playerID), playerID); } } //Log::info("DynamicRibbonWidget", "Rightpressed %s", m_properties[PROP_ID].c_str()); @@ -755,30 +754,16 @@ EventPropagation DynamicRibbonWidget::rightPressed(const int playerID) //Log::info("DynamicRibbonWidget", "Rightpressed returning EVENT_LET"); return EVENT_LET; -} +} // rightPressed + // ----------------------------------------------------------------------------- EventPropagation DynamicRibbonWidget::leftPressed(const int playerID) { - if (m_deactivated) return EVENT_LET; - - RibbonWidget* w = getSelectedRibbon(playerID); - if (w != NULL) - { - updateLabel(); - propagateSelection(); + // Left and right key presses use exactly the same propagation rules + // in dynamic ribbon widgets, we can avoid duplicating the code. + return rightPressed(playerID); +} // leftPressed - for_var_in (DynamicRibbonHoverListener*, listener, m_hover_listeners) - { - listener->onSelectionChanged(this, w->getSelectionIDString(playerID), - w->getSelectionText(playerID), playerID); - } - } - - assert(m_rows.size() >= 1); - if (m_rows[0].m_ribbon_type == RIBBON_TOOLBAR) return EVENT_BLOCK; - - return EVENT_LET; -} // ----------------------------------------------------------------------------- EventPropagation DynamicRibbonWidget::transmitEvent(Widget* w, const std::string& originator, @@ -964,10 +949,6 @@ void DynamicRibbonWidget::propagateSelection() { where = (float)relative_selection / (float)(selected_ribbon->m_children.size() - 1); } - else - { - where = 0.0f; - } if (where < 0.0f) where = 0.0f; else if (where > 1.0f) where = 1.0f; From feee5276c1ee26a6f3e43f91d966bfb774f0dc5c Mon Sep 17 00:00:00 2001 From: Deve Date: Fri, 13 Jun 2025 22:51:06 +0200 Subject: [PATCH 782/830] Remove hardcoded materials in vulkan --- data/shaders/ge_shaders/shader_settings.xml | 76 ++++++ lib/graphics_engine/CMakeLists.txt | 1 + .../include/ge_material_manager.hpp | 69 +++++ .../src/ge_material_manager.cpp | 227 ++++++++++++++++ .../src/ge_vulkan_draw_call.cpp | 252 +++++++++--------- .../src/ge_vulkan_draw_call.hpp | 66 +---- lib/graphics_engine/src/ge_vulkan_driver.cpp | 3 + lib/irrlicht/include/EMaterialTypes.h | 11 +- src/graphics/material.cpp | 24 +- 9 files changed, 522 insertions(+), 207 deletions(-) create mode 100644 data/shaders/ge_shaders/shader_settings.xml create mode 100644 lib/graphics_engine/include/ge_material_manager.hpp create mode 100644 lib/graphics_engine/src/ge_material_manager.cpp diff --git a/data/shaders/ge_shaders/shader_settings.xml b/data/shaders/ge_shaders/shader_settings.xml new file mode 100644 index 00000000000..38dc34bcd6e --- /dev/null +++ b/data/shaders/ge_shaders/shader_settings.xml @@ -0,0 +1,76 @@ + + + + + spm.vert + solid.frag + depth_only.frag + spm_skinning.vert + + + + + + solid + + + spm.vert + normalmap.frag + depth_only.frag + spm_skinning.vert + + + + + + spm.vert + decal.frag + depth_only.frag + spm_skinning.vert + + + + + + spm.vert + alphatest.frag + alphatest_depth.frag + spm_skinning.vert + + + + + + grass.vert + alphatest.frag + alphatest_depth.frag + + + + + + true + false + false + + + spm.vert + transparent.frag + spm_skinning.vert + + + + + + true + false + false + + + spm.vert + transparent.frag + spm_skinning.vert + + + + diff --git a/lib/graphics_engine/CMakeLists.txt b/lib/graphics_engine/CMakeLists.txt index 9de9bb6732e..68aec21756c 100644 --- a/lib/graphics_engine/CMakeLists.txt +++ b/lib/graphics_engine/CMakeLists.txt @@ -69,6 +69,7 @@ set(GE_SOURCES src/ge_culling_tool.cpp src/ge_dx9_texture.cpp src/ge_main.cpp + src/ge_material_manager.cpp src/ge_occlusion_culling.cpp src/ge_texture.cpp src/ge_vma.cpp diff --git a/lib/graphics_engine/include/ge_material_manager.hpp b/lib/graphics_engine/include/ge_material_manager.hpp new file mode 100644 index 00000000000..9d2228a2f89 --- /dev/null +++ b/lib/graphics_engine/include/ge_material_manager.hpp @@ -0,0 +1,69 @@ +#ifndef HEADER_GE_MATERIAL_MANAGER_HPP +#define HEADER_GE_MATERIAL_MANAGER_HPP + +#include +#include +#include +#include +#include +#include + +#include + +namespace GE +{ + +struct GEMaterial +{ + std::string m_vertex_shader; + std::string m_skinning_vertex_shader; + std::string m_fragment_shader; + std::string m_depth_only_fragment_shader; + std::function m_push_constants; + // Fallback material used when PBR is disabled + std::string m_nonpbr_fallback; + bool m_alphablend; + bool m_additive; + bool m_backface_culling; + bool m_depth_test; + bool m_depth_write; + // ------------------------------------------------------------------------ + GEMaterial() + { + m_alphablend = false; + m_additive = false; + m_backface_culling = true; + m_depth_test = true; + m_depth_write = true; + } + // ------------------------------------------------------------------------ + bool texturelessDepth() const + { + return m_depth_only_fragment_shader.empty() || + m_depth_only_fragment_shader == "depth_only.frag"; + } + // ------------------------------------------------------------------------ + bool isTransparent() const { return m_alphablend || m_additive; } +}; // GEMaterial + +namespace GEMaterialManager +{ +// ---------------------------------------------------------------------------- +extern std::vector > > + g_materials; +// ---------------------------------------------------------------------------- +void init(); +// ---------------------------------------------------------------------------- +void update(); +// ---------------------------------------------------------------------------- +irr::video::E_MATERIAL_TYPE getIrrMaterialType(const std::string& shader_name); +// ---------------------------------------------------------------------------- +const std::string& getShader(irr::video::E_MATERIAL_TYPE mt); +// ---------------------------------------------------------------------------- +std::shared_ptr getMaterial(const std::string& shader_name); + +}; // GEMaterialManager + +} + +#endif diff --git a/lib/graphics_engine/src/ge_material_manager.cpp b/lib/graphics_engine/src/ge_material_manager.cpp new file mode 100644 index 00000000000..bebcc2ef5d1 --- /dev/null +++ b/lib/graphics_engine/src/ge_material_manager.cpp @@ -0,0 +1,227 @@ +#include "ge_material_manager.hpp" + +#include "ge_main.hpp" +#include "ge_vulkan_driver.hpp" + +#include "vector3d.h" + +#include +#include +#include + +#include "../source/Irrlicht/os.h" + +namespace GE +{ +// ============================================================================ +namespace GEMaterialManager +{ +std::vector< + std::pair > > g_materials; + +irr::core::vector3df g_wind_direction; + +std::unordered_map > g_mat_map; + +std::unordered_map g_mat_id_map; + +std::unordered_map g_id_mat_map; + +std::unordered_map > + g_default_push_constants = + { + { + "grass", + [](uint32_t* size, void** data) + { + *size = sizeof(irr::core::vector3df); + *data = &g_wind_direction; + } + } + }; +// ============================================================================ +} // GEMaterialManager +// ---------------------------------------------------------------------------- +std::string readString(io::IXMLReaderUTF8* xml) +{ + if (xml->read() && xml->getNodeType() == io::EXN_TEXT) + return xml->getNodeData(); + return ""; +} // readString + +// ---------------------------------------------------------------------------- +bool readBool(io::IXMLReaderUTF8* xml) +{ + return readString(xml) == "true"; +} // readBool + +// ============================================================================ +void GEMaterialManager::init() +{ + std::array def_mappings = {}; + def_mappings[irr::video::EMT_SOLID] = "solid"; + def_mappings[irr::video::EMT_NORMAL_MAP_SOLID] = "normalmap"; + def_mappings[irr::video::EMT_SOLID_2_LAYER] = "decal"; + def_mappings[irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF] = "alphatest"; + def_mappings[irr::video::EMT_STK_GRASS] = "grass"; + def_mappings[irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL] = "alphablend"; + def_mappings[irr::video::EMT_TRANSPARENT_ADD_COLOR] = "additive"; + uint32_t mapping_cursor = 0; + + g_materials.clear(); + g_mat_map.clear(); + g_mat_id_map.clear(); + g_id_mat_map.clear(); + io::IXMLReaderUTF8* xml = + getDriver()->getFileSystem()->createXMLReaderUTF8( + (GE::getShaderFolder() + "shader_settings.xml").c_str()); + if (!xml) + throw std::runtime_error("Could not load shader_settings.xml"); + + while (xml->read()) + { + if (xml->getNodeType() == io::EXN_ELEMENT && + !strcmp(xml->getNodeName(), "setting")) + { + GEMaterial settings; + std::string name = xml->getAttributeValue("name"); + while (xml->read()) + { + if (xml->getNodeType() == io::EXN_ELEMENT) + { + if (!strcmp(xml->getNodeName(), "properties")) + { + while (xml->read()) + { + if (xml->getNodeType() == io::EXN_ELEMENT) + { + const char* node_name = xml->getNodeName(); + if (!strcmp(node_name, "depth-write")) + settings.m_depth_write = readBool(xml); + else if (!strcmp(node_name, "depth-test")) + settings.m_depth_test = readBool(xml); + else if (!strcmp(node_name, "backface-culling")) + settings.m_backface_culling = readBool(xml); + else if (!strcmp(node_name, "nonpbr-fallback")) + settings.m_nonpbr_fallback = readString(xml); + else if (!strcmp(node_name, "alphablend")) + settings.m_alphablend = readBool(xml); + else if (!strcmp(node_name, "additive")) + settings.m_additive = readBool(xml); + } + else if (xml->getNodeType() == io::EXN_ELEMENT_END && + !strcmp(xml->getNodeName(), "properties")) + break; + } + } + else if (!strcmp(xml->getNodeName(), "shaders")) + { + while (xml->read()) + { + if (xml->getNodeType() == io::EXN_ELEMENT) + { + const char* node_name = xml->getNodeName(); + if (!strcmp(node_name, "vertex")) + settings.m_vertex_shader = readString(xml); + else if (!strcmp(node_name, "fragment")) + settings.m_fragment_shader = readString(xml); + else if (!strcmp(node_name, "depth")) + settings.m_depth_only_fragment_shader = readString(xml); + else if (!strcmp(node_name, "skinning-vertex")) + settings.m_skinning_vertex_shader = readString(xml); + } + else if (xml->getNodeType() == io::EXN_ELEMENT_END && + !strcmp(xml->getNodeName(), "shaders")) + break; + } + } + } + else if (xml->getNodeType() == io::EXN_ELEMENT_END && + !strcmp(xml->getNodeName(), "setting")) + break; + } + if (g_default_push_constants.find(name) != + g_default_push_constants.end()) + { + settings.m_push_constants = g_default_push_constants.at(name); + } + + bool found = false; + for (uint32_t i = 0; i < def_mappings.size(); i++) + { + if (def_mappings[i] == name) + { + g_mat_id_map[name] = (irr::video::E_MATERIAL_TYPE)i; + g_id_mat_map[i] = name; + found = true; + break; + } + } + if (!found) + { + while (mapping_cursor < def_mappings.size() && + !def_mappings[mapping_cursor].empty()) + { + mapping_cursor = mapping_cursor + 1; + } + if (mapping_cursor < def_mappings.size()) + { + g_mat_id_map[name] = (irr::video::E_MATERIAL_TYPE)mapping_cursor; + g_id_mat_map[mapping_cursor] = name; + def_mappings[mapping_cursor] = name; + mapping_cursor = mapping_cursor + 1; + } + else + { + char msg[50] = {}; + snprintf(msg, 50, "Too many materials which exceeded %u.", + irr::video::EMT_MATERIAL_COUNT); + os::Printer::log("GEMaterialManager", msg); + xml->drop(); + return; + } + } + auto m = std::make_shared(settings); + g_materials.emplace_back(name, m); + g_mat_map[name] = m; + } + } + + xml->drop(); +} // init + +// ---------------------------------------------------------------------------- +void GEMaterialManager::update() +{ + g_wind_direction = irr::core::vector3df(1.0f, 0.0f, 0.0f) * + (getMonoTimeMs() / 1000.0f) * 1.5f; +} // update + +// ---------------------------------------------------------------------------- +irr::video::E_MATERIAL_TYPE + GEMaterialManager::getIrrMaterialType(const std::string& shader_name) +{ + if (g_mat_id_map.find(shader_name) != g_mat_id_map.end()) + return g_mat_id_map.at(shader_name); + return (irr::video::E_MATERIAL_TYPE)0; +} // getIrrMaterialType + +// ---------------------------------------------------------------------------- +const std::string& GEMaterialManager::getShader(irr::video::E_MATERIAL_TYPE mt) +{ + uint32_t id = mt; + if (g_id_mat_map.find(id) != g_id_mat_map.end()) + return g_id_mat_map.at(id); + return g_id_mat_map.at(0); +} // getShader + +// ---------------------------------------------------------------------------- +std::shared_ptr + GEMaterialManager::getMaterial(const std::string& shader_name) +{ + if (g_mat_map.find(shader_name) != g_mat_map.end()) + return g_mat_map.at(shader_name); + return nullptr; +} // getMaterial + +} diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index e7dfcc6bf1a..074b84e2f89 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -2,6 +2,7 @@ #include "ge_culling_tool.hpp" #include "ge_main.hpp" +#include "ge_material_manager.hpp" #include "ge_render_info.hpp" #include "ge_spm.hpp" #include "ge_vulkan_animated_mesh_scene_node.hpp" @@ -32,7 +33,6 @@ #include "../source/Irrlicht/os.h" #include "quaternion.h" -#define DEPTH_ONLY_FRAG_SHADER "depth_only.frag" #define SKINNING_PIPELINE "_skinning" namespace GE @@ -45,6 +45,23 @@ static void destroyPipeline(VkPipeline* p) delete p; } // destroyPipeline +// ============================================================================ +PipelineSettings::PipelineSettings() +{ + m_drawing_priority = (char)0; + m_custom_pl = VK_NULL_HANDLE; + m_depth_op = VK_COMPARE_OP_LESS; + m_pipeline_type = GVPT_SOLID; + GEMaterial default_material; + loadMaterial(default_material); +} // PipelineSettings::PipelineSettings + +// ============================================================================ +void PipelineSettings::loadMaterial(const GEMaterial& m) +{ + m_material = std::make_shared(m); +} // PipelineSettings::loadMaterial + // ============================================================================ void ObjectData::init(irr::scene::ISceneNode* node, int material_id, int skinning_offset, int irrlicht_material_id) @@ -605,7 +622,8 @@ void GEVulkanDrawCall::generate(GEVulkanDriver* vk) { obj[i].init(particles[i], material_id, m_billboard_rotation, m_view_position, flips, - sky_particle, settings.m_backface_culling); + sky_particle, + settings.m_material->m_backface_culling); written_size += sizeof(ObjectData); mapped_addr += sizeof(ObjectData); } @@ -816,36 +834,16 @@ std::string GEVulkanDrawCall::getShader(irr::scene::ISceneNode* node, // ---------------------------------------------------------------------------- std::string GEVulkanDrawCall::getShader(const irr::video::SMaterial& m) { - std::string shader; - switch (m.MaterialType) + std::string shader = GEMaterialManager::getShader(m.MaterialType); + auto material = GEMaterialManager::getMaterial(shader); + if (!getGEConfig()->m_pbr && !material->m_nonpbr_fallback.empty()) { - case irr::video::EMT_TRANSPARENT_ADD_COLOR: - shader = "additive"; - break; - case irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF: - shader = "alphatest"; - break; - case irr::video::EMT_ONETEXTURE_BLEND: - shader = "alphablend"; - break; - case irr::video::EMT_SOLID_2_LAYER: - shader = "decal"; - break; - case irr::video::EMT_NORMAL_MAP_SOLID: - shader = getGEConfig()->m_pbr ? "normalmap" : "solid"; - break; - case irr::video::EMT_STK_GRASS: - shader = "grass"; - break; - default: - shader = "solid"; - break; + shader = material->m_nonpbr_fallback; + material = GEMaterialManager::getMaterial(shader); } auto& ri = m.getRenderInfo(); // Use real transparent shader first - if (m.MaterialType != irr::video::EMT_TRANSPARENT_ADD_COLOR && - m.MaterialType != irr::video::EMT_ONETEXTURE_BLEND && - ri && ri->isTransparent()) + if (!material->isTransparent() && ri && ri->isTransparent()) return "ghost"; return shader; } // getShader @@ -866,113 +864,84 @@ void GEVulkanDrawCall::prepare(GEVulkanCameraSceneNode* cam) // ---------------------------------------------------------------------------- void GEVulkanDrawCall::createAllPipelines(GEVulkanDriver* vk) { - PipelineSettings settings = {}; - std::unordered_map > dp_cache; - settings.m_depth_test = true; - settings.m_depth_write = true; - settings.m_backface_culling = true; - settings.m_depth_op = VK_COMPARE_OP_LESS; + PipelineSettings settings; + GEMaterial def_mat = *GEMaterialManager::getMaterial("solid"); settings.m_vertex_description = getDefaultVertexDescription(); - settings.m_pipeline_type = GVPT_SOLID; - - settings.m_vertex_shader = "spm.vert"; - settings.m_skinning_vertex_shader = "spm_skinning.vert"; - settings.m_fragment_shader = "solid.frag"; - settings.m_depth_only_fragment_shader = DEPTH_ONLY_FRAG_SHADER; - settings.m_shader_name = "solid"; - createPipeline(vk, settings, dp_cache); - - settings.m_fragment_shader = "normalmap.frag"; - settings.m_shader_name = "normalmap"; - createPipeline(vk, settings, dp_cache); - - settings.m_fragment_shader = "decal.frag"; - settings.m_shader_name = "decal"; - createPipeline(vk, settings, dp_cache); - - settings.m_fragment_shader = "alphatest.frag"; - settings.m_shader_name = "alphatest"; - settings.m_depth_only_fragment_shader = "alphatest_depth.frag"; - settings.m_drawing_priority = (char)5; - createPipeline(vk, settings, dp_cache); - - settings.m_vertex_shader = "grass.vert"; - settings.m_skinning_vertex_shader = ""; - settings.m_shader_name = "grass"; - settings.m_drawing_priority = (char)5; - settings.m_push_constants_func = [](uint32_t* size, void** data) + std::unordered_map > dp_cache; + int drawing_order = 1; + for (auto& p : GEMaterialManager::g_materials) { - static irr::core::vector3df wind_direction; - wind_direction = irr::core::vector3df(1.0f, 0.0f, 0.0f) * - (getMonoTimeMs() / 1000.0f) * 1.5f; - *size = sizeof(irr::core::vector3df); - *data = &wind_direction; - }; - createPipeline(vk, settings, dp_cache); + if (p.second->isTransparent()) + continue; + if (!getGEConfig()->m_pbr && !p.second->m_nonpbr_fallback.empty()) + continue; + settings.m_drawing_priority = (char)drawing_order; + drawing_order = drawing_order + 1; + settings.m_shader_name = p.first; + settings.m_material = p.second; + createPipeline(vk, settings, dp_cache); + } - settings.m_vertex_shader = "spm.vert"; - settings.m_skinning_vertex_shader = "spm_skinning.vert"; - settings.m_depth_only_fragment_shader = ""; - settings.m_push_constants_func = nullptr; - settings.m_pipeline_type = GVPT_GHOST_DEPTH; + def_mat.m_fragment_shader = "depth_only.frag"; + def_mat.m_depth_only_fragment_shader = ""; + def_mat.m_alphablend = true; + settings.loadMaterial(def_mat); - settings.m_depth_write = true; - settings.m_backface_culling = true; - settings.m_alphablend = true; - settings.m_drawing_priority = (char)9; - settings.m_fragment_shader = DEPTH_ONLY_FRAG_SHADER; settings.m_shader_name = "ghost"; + settings.m_drawing_priority = (char)drawing_order; + settings.m_pipeline_type = GVPT_GHOST_DEPTH; if (doDepthOnlyRenderingFirst()) { m_graphics_pipelines["ghost"] = {}; m_graphics_pipelines["ghost"].m_settings = settings; m_graphics_pipelines["ghost"].m_pipelines[GVPT_GHOST_DEPTH] = - dp_cache.at(settings.m_vertex_shader + settings.m_fragment_shader); + dp_cache.at(def_mat.m_vertex_shader + def_mat.m_fragment_shader); m_graphics_pipelines["ghost" SKINNING_PIPELINE] = {}; m_graphics_pipelines["ghost" SKINNING_PIPELINE].m_settings = settings; m_graphics_pipelines["ghost" SKINNING_PIPELINE] .m_pipelines[GVPT_GHOST_DEPTH] = dp_cache.at( - settings.m_skinning_vertex_shader + settings.m_fragment_shader); + def_mat.m_skinning_vertex_shader + def_mat.m_fragment_shader); } else { createPipeline(vk, settings, dp_cache); } + def_mat.m_fragment_shader = "ghost.frag"; + def_mat.m_depth_write = false; + settings.loadMaterial(def_mat); + settings.m_pipeline_type = GVPT_TRANSPARENT; - settings.m_fragment_shader = "ghost.frag"; - settings.m_depth_write = false; settings.m_depth_op = VK_COMPARE_OP_EQUAL; createPipeline(vk, settings, dp_cache); - - settings.m_backface_culling = false; - settings.m_drawing_priority = (char)10; + drawing_order = drawing_order + 1; settings.m_depth_op = VK_COMPARE_OP_LESS; - settings.m_fragment_shader = "transparent.frag"; - settings.m_shader_name = "alphablend"; - createPipeline(vk, settings, dp_cache); + for (auto& p : GEMaterialManager::g_materials) + { + if (!p.second->isTransparent()) + continue; + if (!getGEConfig()->m_pbr && !p.second->m_nonpbr_fallback.empty()) + continue; + settings.m_drawing_priority = (char)drawing_order; + drawing_order = drawing_order + 1; + settings.m_shader_name = p.first; + settings.m_material = p.second; + createPipeline(vk, settings, dp_cache); + } - settings.m_alphablend = false; - settings.m_additive = true; - settings.m_fragment_shader = "transparent.frag"; - settings.m_shader_name = "additive"; - settings.m_drawing_priority = (char)11; - createPipeline(vk, settings, dp_cache); + def_mat.m_alphablend = false; + def_mat.m_skinning_vertex_shader = ""; + def_mat.m_vertex_shader = "fullscreen_quad.vert"; + def_mat.m_fragment_shader = "skybox.frag"; + settings.loadMaterial(def_mat); settings.m_pipeline_type = GVPT_SKYBOX; - settings.m_alphablend = false; - settings.m_additive = false; settings.m_custom_pl = m_skybox_layout; settings.m_depth_op = VK_COMPARE_OP_EQUAL; settings.m_vertex_description = {}; - settings.m_backface_culling = true; - settings.m_skinning_vertex_shader = ""; - settings.m_vertex_shader = "fullscreen_quad.vert"; - settings.m_fragment_shader = "skybox.frag"; settings.m_shader_name = "skybox"; createPipeline(vk, settings, dp_cache); - } // createAllPipelines // ---------------------------------------------------------------------------- @@ -1037,7 +1006,7 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, rasterizer.rasterizerDiscardEnable = VK_FALSE; rasterizer.polygonMode = VK_POLYGON_MODE_FILL; rasterizer.lineWidth = 1.0f; - rasterizer.cullMode = settings.m_backface_culling ? + rasterizer.cullMode = settings.m_material->m_backface_culling ? VK_CULL_MODE_BACK_BIT : VK_CULL_MODE_NONE; rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; rasterizer.depthBiasEnable = VK_FALSE; @@ -1049,8 +1018,8 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, VkPipelineDepthStencilStateCreateInfo depth_stencil = {}; depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depth_stencil.depthTestEnable = settings.m_depth_test; - depth_stencil.depthWriteEnable = settings.m_depth_write; + depth_stencil.depthTestEnable = settings.m_material->m_depth_test; + depth_stencil.depthWriteEnable = settings.m_material->m_depth_write; depth_stencil.depthCompareOp = settings.m_depth_op; depth_stencil.depthBoundsTestEnable = VK_FALSE; depth_stencil.stencilTestEnable = VK_FALSE; @@ -1059,8 +1028,8 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - color_blend_attachment.blendEnable = settings.isTransparent(); - if (settings.m_alphablend) + color_blend_attachment.blendEnable = settings.m_material->isTransparent(); + if (settings.m_material->m_alphablend) { color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; @@ -1069,7 +1038,7 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; } - if (settings.m_additive) + if (settings.m_material->m_additive) { color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE; @@ -1150,12 +1119,12 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, } shader_stages[0].module = GEVulkanShaderManager::getShader( - settings.m_vertex_shader); + settings.m_material->m_vertex_shader); shader_stages[1].module = GEVulkanShaderManager::getShader( - settings.m_fragment_shader); + settings.m_material->m_fragment_shader); bool depth_only = false; - std::string depth_only_fs = settings.m_depth_only_fragment_shader; + std::string depth_only_fs = settings.m_material->m_depth_only_fragment_shader; if (!doDepthOnlyRenderingFirst()) depth_only_fs = ""; if (!depth_only_fs.empty()) @@ -1169,8 +1138,9 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, bool skinning) { std::string vs = skinning ? - s.m_skinning_vertex_shader : s.m_vertex_shader; - auto it = dp_cache.find(vs + s.m_depth_only_fragment_shader); + s.m_material->m_skinning_vertex_shader : + s.m_material->m_vertex_shader; + auto it = dp_cache.find(vs + s.m_material->m_depth_only_fragment_shader); if (it == dp_cache.end()) return false; std::string key = s.m_shader_name; @@ -1204,8 +1174,9 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, destroyPipeline); m_graphics_pipelines[key].m_pipelines[GVPT_DEPTH] = sp; std::string vs = skinning ? - s.m_skinning_vertex_shader : s.m_vertex_shader; - dp_cache[vs + s.m_depth_only_fragment_shader] = sp; + s.m_material->m_skinning_vertex_shader : + s.m_material->m_vertex_shader; + dp_cache[vs + s.m_material->m_depth_only_fragment_shader] = sp; } else { @@ -1230,11 +1201,11 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, insert_pipeline(graphics_pipeline, settings, depth_only, false); } - if (!settings.m_skinning_vertex_shader.empty() && + if (!settings.m_material->m_skinning_vertex_shader.empty() && !insert_from_cache(settings, true)) { shader_stages[0].module = GEVulkanShaderManager::getShader( - settings.m_skinning_vertex_shader); + settings.m_material->m_skinning_vertex_shader); VkResult result = vkCreateGraphicsPipelines(vk->getDevice(), VK_NULL_HANDLE, 1, &pipeline_info, NULL, &graphics_pipeline); if (result != VK_SUCCESS) @@ -1253,9 +1224,9 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, color_after_depth.depthCompareOp = VK_COMPARE_OP_EQUAL; pipeline_info.pDepthStencilState = &color_after_depth; shader_stages[0].module = GEVulkanShaderManager::getShader( - settings.m_vertex_shader); + settings.m_material->m_vertex_shader); shader_stages[1].module = GEVulkanShaderManager::getShader( - settings.m_fragment_shader); + settings.m_material->m_fragment_shader); VkResult result = vkCreateGraphicsPipelines(vk->getDevice(), VK_NULL_HANDLE, 1, &pipeline_info, NULL, &graphics_pipeline); @@ -1266,11 +1237,11 @@ void GEVulkanDrawCall::createPipeline(GEVulkanDriver* vk, } insert_pipeline(graphics_pipeline, settings, depth_only, false); - if (settings.m_skinning_vertex_shader.empty()) + if (settings.m_material->m_skinning_vertex_shader.empty()) return; shader_stages[0].module = GEVulkanShaderManager::getShader( - settings.m_skinning_vertex_shader); + settings.m_material->m_skinning_vertex_shader); result = vkCreateGraphicsPipelines(vk->getDevice(), VK_NULL_HANDLE, 1, &pipeline_info, NULL, &graphics_pipeline); if (result != VK_SUCCESS) @@ -1448,14 +1419,6 @@ void GEVulkanDrawCall::createVulkanData() } createAllPipelines(vk); - for (auto& p : m_graphics_pipelines) - { - if (p.second.m_settings.m_push_constants_func) - { - m_push_constants[p.second.m_settings.m_shader_name] = - std::vector(); - } - } size_t extra_size = 0; const bool use_multidraw = @@ -1571,7 +1534,6 @@ void GEVulkanDrawCall::bindBaseVertex(GEVulkanDriver* vk, VkCommandBuffer cmd) // ---------------------------------------------------------------------------- void GEVulkanDrawCall::prepareRendering(GEVulkanDriver* vk) { - updatePushConstants(); updateDataDescriptorSets(vk); m_texture_descriptor->updateDescriptor(); } // prepareRendering @@ -1984,9 +1946,8 @@ void GEVulkanDrawCall::bindSingleMaterial(VkCommandBuffer cmd, if (data.m_pipelines.find(pt) == data.m_pipelines.end()) return; const PipelineSettings& s = data.m_settings; - if (pt == GVPT_GHOST_DEPTH || (pt == GVPT_DEPTH && - (s.m_depth_only_fragment_shader == DEPTH_ONLY_FRAG_SHADER || - s.m_depth_only_fragment_shader.empty()))) + if (pt == GVPT_GHOST_DEPTH ||(pt == GVPT_DEPTH && + s.m_material->texturelessDepth())) return; vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_layout, 0, 1, @@ -2119,4 +2080,29 @@ size_t GEVulkanDrawCall::getLightDataOffset() const getPadding(ubo_size, m_limits.minUniformBufferOffsetAlignment); } // getLightDataOffset +// ---------------------------------------------------------------------------- +bool GEVulkanDrawCall::bindPipeline(VkCommandBuffer cmd, + const std::string& name, + VkPipeline* prev_pipeline, + GEVulkanPipelineType pt) const +{ + auto& ret = m_graphics_pipelines.at(name); + if (ret.m_pipelines.find(pt) == ret.m_pipelines.end()) + return false; + VkPipeline p = *ret.m_pipelines.at(pt); + if (*prev_pipeline == p) + return true; + *prev_pipeline = p; + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, p); + if (ret.m_settings.m_material->m_push_constants) + { + uint32_t size; + void* data; + ret.m_settings.m_material->m_push_constants(&size, &data); + vkCmdPushConstants(cmd, m_pipeline_layout, + VK_SHADER_STAGE_ALL_GRAPHICS, 0, size, data); + } + return true; +} // bindPipeline + } diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp index aa0bdbcf5f2..c157c76f0e6 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp @@ -81,32 +81,26 @@ enum GEVulkanPipelineType : unsigned GVPT_SKYBOX }; +struct GEMaterial; + struct PipelineSettings { - std::string m_vertex_shader; - std::string m_skinning_vertex_shader; - std::string m_fragment_shader; - std::string m_depth_only_fragment_shader; std::string m_shader_name; - bool m_alphablend; - bool m_additive; - bool m_backface_culling; - bool m_depth_test; - bool m_depth_write; + std::shared_ptr m_material; char m_drawing_priority; - std::function m_push_constants_func; VkPipelineLayout m_custom_pl; VkCompareOp m_depth_op; VertexDescription m_vertex_description; GEVulkanPipelineType m_pipeline_type; - bool isTransparent() const { return m_alphablend || m_additive; } + PipelineSettings(); + void loadMaterial(const GEMaterial& m); }; struct PipelineData { PipelineSettings m_settings; - std::unordered_map > m_pipelines; + std::map > m_pipelines; }; struct DrawCallData @@ -175,8 +169,6 @@ class GEVulkanDrawCall std::vector m_data_descriptor_sets; - std::unordered_map > m_push_constants; - VkPipelineLayout m_pipeline_layout, m_skybox_layout; std::unordered_map m_graphics_pipelines; @@ -205,25 +197,8 @@ class GEVulkanDrawCall std::string getShader(irr::scene::ISceneNode* node, int material_id); // ------------------------------------------------------------------------ bool bindPipeline(VkCommandBuffer cmd, const std::string& name, - VkPipeline* prev_pipeline, GEVulkanPipelineType pt) const - { - auto& ret = m_graphics_pipelines.at(name); - if (ret.m_pipelines.find(pt) == ret.m_pipelines.end()) - return false; - VkPipeline p = *ret.m_pipelines.at(pt); - if (*prev_pipeline == p) - return true; - *prev_pipeline = p; - vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, p); - auto it = m_push_constants.find(ret.m_settings.m_shader_name); - if (it != m_push_constants.end()) - { - vkCmdPushConstants(cmd, m_pipeline_layout, - VK_SHADER_STAGE_ALL_GRAPHICS, 0, it->second.size(), - it->second.data()); - } - return true; - } + VkPipeline* prev_pipeline, + GEVulkanPipelineType pt) const; // ------------------------------------------------------------------------ TexturesList getTexturesList(const irr::video::SMaterial& m) { @@ -241,32 +216,15 @@ class GEVulkanDrawCall // ------------------------------------------------------------------------ std::string getDynamicBufferKey(const std::string& shader) const { - static PipelineSettings default_settings = {}; - const PipelineSettings* settings = &default_settings; + char drawing_priority = (char)1; auto it = m_graphics_pipelines.find(shader); if (it != m_graphics_pipelines.end()) - settings = &it->second.m_settings; - return std::string(1, settings->isTransparent() ? (char)1 : (char)0) + - std::string(1, settings->m_drawing_priority) + shader; + drawing_priority = it->second.m_settings.m_drawing_priority; + return std::string(1, drawing_priority) + shader; } // ------------------------------------------------------------------------ std::string getShaderFromKey(const std::string& key) const - { return key.substr(2); } - // ------------------------------------------------------------------------ - void updatePushConstants() - { - for (auto& p : m_push_constants) - { - auto& f = - m_graphics_pipelines.at(p.first).m_settings - .m_push_constants_func; - uint32_t size; - void* data; - f(&size, &data); - p.second.resize(size); - memcpy(p.second.data(), data, size); - } - } + { return key.substr(1); } // ------------------------------------------------------------------------ void bindSingleMaterial(VkCommandBuffer cmd, const std::string& cur_pipeline, diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index 87944dd92de..72fd728fabb 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -3,6 +3,7 @@ #include "ge_compressor_astc_4x4.hpp" #include "ge_compressor_bptc_bc7.hpp" #include "ge_main.hpp" +#include "ge_material_manager.hpp" #include "ge_spm.hpp" #include "ge_spm_buffer.hpp" @@ -639,6 +640,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params, GEVulkanFeatures::supportsBindMeshTexturesAtOnce()); GECompressorASTC4x4::init(); GECompressorBPTCBC7::init(); + GEMaterialManager::init(); GEVulkanFeatures::printStats(); } catch (std::exception& e) @@ -1689,6 +1691,7 @@ bool GEVulkanDriver::beginScene(bool backBuffer, bool zBuffer, SColor color, const SExposedVideoData& videoData, core::rect* sourceRect) { + GEMaterialManager::update(); if (m_billboard_quad == NULL && m_irrlicht_device->getSceneManager() && m_irrlicht_device->getSceneManager()->getMeshCache()) createBillboardQuad(); diff --git a/lib/irrlicht/include/EMaterialTypes.h b/lib/irrlicht/include/EMaterialTypes.h index e06a8879c7f..d56e9a6a247 100644 --- a/lib/irrlicht/include/EMaterialTypes.h +++ b/lib/irrlicht/include/EMaterialTypes.h @@ -5,13 +5,15 @@ #ifndef __E_MATERIAL_TYPES_H_INCLUDED__ #define __E_MATERIAL_TYPES_H_INCLUDED__ +#include + namespace irr { namespace video { //! Abstracted and easy to use fixed function/programmable pipeline material modes. - enum E_MATERIAL_TYPE + enum E_MATERIAL_TYPE : uint32_t { //! Standard solid material. /** Only first texture is used, which is supposed to be the @@ -192,11 +194,11 @@ namespace video /** Using only first texture. Generic blending method. */ EMT_ONETEXTURE_BLEND, - //! Alphatest material for grass without using vertex color in stk. */ + //! Alphatest material for grass without using vertex color in stk. EMT_STK_GRASS, - //! This value is not used. It only forces this enumeration to compile to 32 bit. - EMT_FORCE_32BIT = 0x7fffffff + //! This value is used in GEMaterialManager to save the default GEMaterial map. + EMT_MATERIAL_COUNT }; //! Array holding the built in material type names @@ -226,6 +228,7 @@ namespace video "parallaxmap_trans_add", "parallaxmap_trans_vertexalpha", "onetexture_blend", + "stk_grass", 0 }; diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index adc12471957..aed49a7b42d 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -48,6 +48,7 @@ #ifndef SERVER_ONLY #include +#include #include #include #endif @@ -575,7 +576,7 @@ void Material::install(std::function image_mani, m_texture->grab(); #ifndef SERVER_ONLY - if (!m && irr_driver->getVideoDriver()->getDriverType() != EDT_VULKAN) + if (irr_driver->getVideoDriver()->getDriverType() != EDT_VULKAN) return; for (unsigned i = 2; i < m_sampler_path.size(); i++) @@ -906,8 +907,6 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m video::EMFN_MODULATE_1X, video::EAS_TEXTURE | video::EAS_VERTEX_COLOR); - if (is_vk) - m->MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; } else if (m_shader_name == "grass") { @@ -926,22 +925,10 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m m->EmissiveColor = video::SColor(255, 150, 150, 150); m->SpecularColor = video::SColor(255, 150, 150, 150); } - if (is_vk) - m->MaterialType = video::EMT_STK_GRASS; #endif #endif } - else if (m_shader_name == "decal") - { - if (is_vk) - m->MaterialType = video::EMT_SOLID_2_LAYER; - } - else if (m_shader_name == "normalmap") - { - if (is_vk) - m->MaterialType = video::EMT_NORMAL_MAP_SOLID; - } if (isTransparent()) { @@ -1002,15 +989,20 @@ void Material::setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* m m->ColorMaterial = video::ECM_NONE; // Override one above } #endif +#ifndef SERVER_ONLY if (is_vk) { + m->MaterialType = + GE::GEMaterialManager::getIrrMaterialType(m_shader_name); + if (m_shader_name == "displace") + m->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; for (unsigned i = 2; i < m_sampler_path.size(); i++) { if (m_vk_textures[i - 2]) m->setTexture(i, m_vk_textures[i - 2]); } } - +#endif } // setMaterialProperties //----------------------------------------------------------------------------- From 3cc5915e97e2597f893d60533b8a884d940a18dd Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 14 Jun 2025 02:21:43 +0400 Subject: [PATCH 783/830] Remove newlines at the end of log strings --- src/audio/music_information.cpp | 8 ++-- src/challenges/challenge_data.cpp | 2 +- src/challenges/challenge_status.cpp | 2 +- src/challenges/unlock_manager.cpp | 2 +- src/graphics/irr_driver.cpp | 22 ++++----- src/graphics/material.cpp | 6 +-- src/graphics/mesh_tools.cpp | 2 +- .../abstract_top_level_container.hpp | 2 +- src/guiengine/layout_manager.cpp | 2 +- src/guiengine/skin.cpp | 8 ++-- src/guiengine/widgets/icon_button_widget.cpp | 4 +- src/items/rubber_ball.cpp | 2 +- .../controller/local_player_controller.cpp | 2 +- src/karts/kart.cpp | 2 +- src/main.cpp | 6 +-- src/modes/overworld.cpp | 2 +- src/modes/profile_world.cpp | 2 +- src/network/servers_manager.cpp | 2 +- src/race/grand_prix_manager.cpp | 2 +- src/race/highscore_manager.cpp | 14 +++--- src/race/race_manager.cpp | 6 +-- src/scriptengine/script_challenges.cpp | 4 +- src/scriptengine/script_engine.cpp | 2 +- .../dialogs/select_challenge.cpp | 6 +-- .../grand_prix_editor_screen.cpp | 2 +- src/states_screens/grand_prix_lose.cpp | 2 +- src/tracks/model_definition_loader.cpp | 4 +- src/tracks/track.cpp | 46 +++++++++---------- src/tracks/track_manager.cpp | 2 +- src/utils/leak_check.cpp | 2 +- src/utils/profiler.cpp | 2 +- src/utils/string_utils.cpp | 4 +- src/utils/time.cpp | 4 +- 33 files changed, 90 insertions(+), 90 deletions(-) diff --git a/src/audio/music_information.cpp b/src/audio/music_information.cpp index 80fbdc6c5a9..eab8fb8bf85 100644 --- a/src/audio/music_information.cpp +++ b/src/audio/music_information.cpp @@ -47,7 +47,7 @@ MusicInformation *MusicInformation::create(const std::string &filename) if(root->getName()!="music") { Log::error("MusicInformation", - "Music file '%s' does not contain music node.\n", + "Music file '%s' does not contain music node.", filename.c_str()); return NULL; } @@ -58,7 +58,7 @@ MusicInformation *MusicInformation::create(const std::string &filename) { Log::error("MusicInformation", "One of 'title' or 'file' attribute " - "is missing in the music XML file '%s'!\n", + "is missing in the music XML file '%s'!", filename.c_str()); return NULL; } @@ -195,7 +195,7 @@ void MusicInformation::startMusic() if (StringUtils::getExtension(m_normal_filename) != "ogg") { Log::warn("MusicInformation", "Music file %s is not found or file " - "format is not recognized.\n", m_normal_filename.c_str()); + "format is not recognized.", m_normal_filename.c_str()); return; } @@ -256,7 +256,7 @@ void MusicInformation::startMusic() delete m_fast_music; m_fast_music = NULL; Log::warn("MusicInformation", "Unabled to load fast music %s, not " - "supported or not found.\n", m_fast_filename.c_str()); + "supported or not found.", m_fast_filename.c_str()); return; } m_fast_music->setVolume(m_gain); diff --git a/src/challenges/challenge_data.cpp b/src/challenges/challenge_data.cpp index b9714f15b1a..f82fa97b99c 100644 --- a/src/challenges/challenge_data.cpp +++ b/src/challenges/challenge_data.cpp @@ -81,7 +81,7 @@ ChallengeData::ChallengeData(const std::string& filename) if(!unlock_manager->isSupportedVersion(*this)) { Log::warn("ChallengeData", "Challenge <%s> is older " - "or newer than this version of STK, will be ignored.\n", + "or newer than this version of STK, will be ignored.", filename.c_str()); return; } diff --git a/src/challenges/challenge_status.cpp b/src/challenges/challenge_status.cpp index 71cd39242cd..4ce647ffd38 100644 --- a/src/challenges/challenge_status.cpp +++ b/src/challenges/challenge_status.cpp @@ -38,7 +38,7 @@ void ChallengeStatus::load(const XMLNode* challenges_node) if(node == NULL) { Log::info("ChallengeStatus", "Couldn't find node <%s> in challenge list." - "(If this is the first time you play this is normal)\n", + "(If this is the first time you play this is normal)", m_data->getChallengeId().c_str()); return; } diff --git a/src/challenges/unlock_manager.cpp b/src/challenges/unlock_manager.cpp index f65892a1922..74623f2d64a 100644 --- a/src/challenges/unlock_manager.cpp +++ b/src/challenges/unlock_manager.cpp @@ -122,7 +122,7 @@ void UnlockManager::readAllChallengesInDirs(const std::vector* all_ catch (std::runtime_error& ex) { Log::warn("unlock_manager", "An error occurred while " - "loading challenge file '%s' : %s.\n" + "loading challenge file '%s' : %s." "Challenge will be ignored.", filename.c_str(), ex.what()); continue; diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index d57a9f8e191..2cfb1b12b5d 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -422,10 +422,10 @@ void IrrDriver::initDevice() { Log::warn("irr_driver", "!!!!! Performance warning: Irrlicht compiled with " - "debug mode.!!!!!\n"); + "debug mode.!!!!!"); Log::warn("irr_driver", "!!!!! This can have a significant performance " - "impact !!!!!\n"); + "impact !!!!!"); } } // end if firstTime @@ -552,7 +552,7 @@ void IrrDriver::initDevice() { if(UserConfigParams::logMisc()) Log::verbose("irr_driver", "Trying to create device with " - "%i bits\n", bits); + "%i bits", bits); params.DriverType = driver_created; params.PrivateData = NULL; @@ -595,7 +595,7 @@ void IrrDriver::initDevice() default: Log::error("irr_driver", "[IrrDriver] WARNING: Invalid value for " - "anti-alias setting : %i\n", + "anti-alias setting : %i", (int)UserConfigParams::m_antialiasing); } */ @@ -631,7 +631,7 @@ void IrrDriver::initDevice() if (m_device) { Log::verbose("irr_driver", "An invalid resolution was set in " - "the config file, reverting to saner values\n"); + "the config file, reverting to saner values"); } } } @@ -639,7 +639,7 @@ void IrrDriver::initDevice() if(!m_device) { - Log::fatal("irr_driver", "Couldn't initialise irrlicht device. Quitting.\n"); + Log::fatal("irr_driver", "Couldn't initialise irrlicht device. Quitting."); } m_actual_screen_size = m_device->getVideoDriver()->getCurrentRenderTargetSize(); UserConfigParams::m_width = m_actual_screen_size.Width; @@ -709,7 +709,7 @@ void IrrDriver::initDevice() if(!m_device) { - Log::fatal("irr_driver", "Couldn't initialise irrlicht device. Quitting.\n"); + Log::fatal("irr_driver", "Couldn't initialise irrlicht device. Quitting."); } GE::setVideoDriver(m_device->getVideoDriver()); @@ -1022,7 +1022,7 @@ bool IrrDriver::moveWindow(int x, int y) if (!success) { - Log::warn("irr_driver", "Could not set window location\n"); + Log::warn("irr_driver", "Could not set window location"); return false; } #endif @@ -1223,7 +1223,7 @@ void IrrDriver::printRenderStats() { io::IAttributes * attr = m_scene_manager->getParameters(); Log::verbose("irr_driver", - "[%ls], FPS:%3d Tri:%.03fm Cull %d/%d nodes (%d,%d,%d)\n", + "[%ls], FPS:%3d Tri:%.03fm Cull %d/%d nodes (%d,%d,%d)", m_video_driver->getName(), m_video_driver->getFPS (), (f32) m_video_driver->getPrimitiveCountDrawn( 0 ) * ( 1.f / 1000000.f ), @@ -1253,7 +1253,7 @@ scene::IAnimatedMesh *IrrDriver::getAnimatedMesh(const std::string &filename) /*ignorePath*/true, io::EFAT_ZIP)) { Log::error("irr_driver", - "getMesh: Failed to open zip file <%s>\n", + "getMesh: Failed to open zip file <%s>", filename.c_str()); return NULL; } @@ -1289,7 +1289,7 @@ scene::IMesh *IrrDriver::getMesh(const std::string &filename) scene::IAnimatedMesh* am = getAnimatedMesh(filename); if (am == NULL) { - Log::error("irr_driver", "Cannot load mesh <%s>\n", + Log::error("irr_driver", "Cannot load mesh <%s>", filename.c_str()); return NULL; } diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index a99f953427e..76b54ce7a45 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -706,7 +706,7 @@ void Material::initParticlesEffect(const XMLNode *node) if (base.size() < 1) { Log::warn("Material::initParticlesEffect" - "Invalid particle settings for material '%s'\n", + "Invalid particle settings for material '%s'", m_texname.c_str()); return; } @@ -719,14 +719,14 @@ void Material::initParticlesEffect(const XMLNode *node) if (particles == NULL) { Log::warn("Material::initParticlesEffect", - "Error loading particles '%s' for material '%s'\n", + "Error loading particles '%s' for material '%s'", base.c_str(), m_texname.c_str()); } } catch (...) { Log::warn("Material::initParticlesEffect", - "Cannot find particles '%s' for material '%s'\n", + "Cannot find particles '%s' for material '%s'", base.c_str(), m_texname.c_str()); return; } diff --git a/src/graphics/mesh_tools.cpp b/src/graphics/mesh_tools.cpp index 2a00cb6d8e3..33a1f78b420 100644 --- a/src/graphics/mesh_tools.cpp +++ b/src/graphics/mesh_tools.cpp @@ -92,7 +92,7 @@ void minMax3D(scene::IMesh* mesh, Vec3 *min, Vec3 *max) } else { - Log::warn("Tools", "minMax3D: Ignoring type '%d'!\n", + Log::warn("Tools", "minMax3D: Ignoring type '%d'!", mb->getVertexType()); } } // for i( out ); if (out != NULL && outCasted == NULL) Log::fatal("Screen::getWidget", "Widget '%s' of type '%s'" - "cannot be casted to requested type '%s'!\n", name, + "cannot be casted to requested type '%s'!", name, typeid(*out).name(), typeid(T).name()); return outCasted; } diff --git a/src/guiengine/layout_manager.cpp b/src/guiengine/layout_manager.cpp index 8c320830634..028546870c1 100644 --- a/src/guiengine/layout_manager.cpp +++ b/src/guiengine/layout_manager.cpp @@ -600,7 +600,7 @@ void LayoutManager::doCalculateLayout(PtrVector& widgets, AbstractTopLev if (widgets[n].m_h <= 0) { Log::warn("LayoutManager", "Widget '%s' has a height of %i (left_space = %i, " - "fraction = %f, max_width = %s)\n", widgets[n].m_properties[PROP_ID].c_str(), + "fraction = %f, max_width = %s)", widgets[n].m_properties[PROP_ID].c_str(), widgets[n].m_h, left_space, fraction, widgets[n].m_properties[PROP_MAX_WIDTH].c_str()); widgets[n].m_h = 1; } diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index 5fbffe83da4..24e19f1c8a7 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -87,14 +87,14 @@ namespace SkinConfig if (node->get("type", &type) == 0) { - Log::error("skin", "All elements must have a type\n"); + Log::error("skin", "All elements must have a type"); return; } node->get("state", &state); if (node->get("image", &image) == 0) { - Log::error("skin", "All elements must have an image\n"); + Log::error("skin", "All elements must have an image"); return; } @@ -163,7 +163,7 @@ namespace SkinConfig if(node->get("type", &type) == 0) { - Log::error("skin", "All elements must have a type\n"); + Log::error("skin", "All elements must have a type"); return; } node->get("state", &state); @@ -477,7 +477,7 @@ void BoxRenderParams::setTexture(ITexture* image) { if (image == NULL) { - Log::error("skin", "/!\\ WARNING: missing image in skin\n"); + Log::error("skin", "/!\\ WARNING: missing image in skin"); return; } diff --git a/src/guiengine/widgets/icon_button_widget.cpp b/src/guiengine/widgets/icon_button_widget.cpp index 01436e82fff..579b1f109e9 100644 --- a/src/guiengine/widgets/icon_button_widget.cpp +++ b/src/guiengine/widgets/icon_button_widget.cpp @@ -190,7 +190,7 @@ void IconButtonWidget::setImage(const char* path_to_texture, IconPathType pathTy if (!m_texture) { - Log::error("icon_button", "Texture '%s' not found!\n", + Log::error("icon_button", "Texture '%s' not found!", m_properties[PROP_ICON].c_str()); std::string file = file_manager->getAsset(FileManager::GUI_ICON,"main_help.png"); setTexture(irr_driver->getTexture(file)); @@ -208,7 +208,7 @@ void IconButtonWidget::setImage(ITexture* texture) else { Log::error("icon_button", - "setImage invoked with NULL image pointer\n"); + "setImage invoked with NULL image pointer"); std::string file = file_manager->getAsset(FileManager::GUI_ICON,"main_help.png"); setTexture(irr_driver->getTexture(file)); } diff --git a/src/items/rubber_ball.cpp b/src/items/rubber_ball.cpp index fef1cfe9572..329968ef2e9 100644 --- a/src/items/rubber_ball.cpp +++ b/src/items/rubber_ball.cpp @@ -338,7 +338,7 @@ void RubberBall::init(const XMLNode &node, scene::IMesh *rubberball) "No fast-ping-distance specified for basket ball."); if(m_st_fast_ping_distance < m_st_target_distance) Log::warn("powerup", - "Ping-distance is smaller than target distance.\n" + "Ping-distance is smaller than target distance." "That should not happen, but is ignored for now."); if(!node.get("early-target-factor", &m_st_early_target_factor)) Log::warn("powerup", diff --git a/src/karts/controller/local_player_controller.cpp b/src/karts/controller/local_player_controller.cpp index ba9d1c3336a..021a84de803 100644 --- a/src/karts/controller/local_player_controller.cpp +++ b/src/karts/controller/local_player_controller.cpp @@ -237,7 +237,7 @@ void LocalPlayerController::steer(int ticks, int steer_val) if(UserConfigParams::m_gamepad_debug) { - Log::debug("LocalPlayerController", " set to: %f\n", + Log::debug("LocalPlayerController", " set to: %f", m_controls->getSteer()); } } // steer diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index be3cd4316e9..22cfe0c5f0e 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -2453,7 +2453,7 @@ void Kart::crashed(const Material *m, const Vec3 &normal) else { Log::error("Kart","Unknown particles kind <%s> in material " - "crash-reset properties\n", particles.c_str()); + "crash-reset properties", particles.c_str()); } } #endif diff --git a/src/main.cpp b/src/main.cpp index 469debf60b0..e592a24a534 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1197,7 +1197,7 @@ int handleCmdLine(bool has_server_config, bool has_parent_process) int n = atoi(s.c_str()); if (n < 0 || n > RaceManager::DIFFICULTY_LAST) { - Log::warn("main", "Invalid difficulty '%s', use easy.\n", + Log::warn("main", "Invalid difficulty '%s', use easy.", s.c_str()); RaceManager::get()->setDifficulty(RaceManager::Difficulty(0)); ServerConfig::m_server_difficulty = 0; @@ -1717,7 +1717,7 @@ int handleCmdLine(bool has_server_config, bool has_parent_process) int laps = atoi(s.c_str()); if (laps < 0) { - Log::error("main", "Invalid number of laps: %s.\n", s.c_str()); + Log::error("main", "Invalid number of laps: %s.", s.c_str()); return 0; } else @@ -1895,7 +1895,7 @@ void initRest() if (irr_driver->getDevice() == NULL) { - Log::fatal("main", "Couldn't initialise irrlicht device. Quitting.\n"); + Log::fatal("main", "Couldn't initialise irrlicht device. Quitting."); } StkTime::init(); // grabs the timer object from the irrlicht device diff --git a/src/modes/overworld.cpp b/src/modes/overworld.cpp index 0fed626666e..34183837cd7 100644 --- a/src/modes/overworld.cpp +++ b/src/modes/overworld.cpp @@ -259,7 +259,7 @@ void OverWorld::onFirePressed(Controller* who) const ChallengeData* challenge = unlock_manager->getChallengeData(challenges[n].m_challenge_id); if (challenge == NULL) { - Log::error("track", "Cannot find challenge named '%s'\n", + Log::error("track", "Cannot find challenge named '%s'", challenges[n].m_challenge_id.c_str()); continue; } diff --git a/src/modes/profile_world.cpp b/src/modes/profile_world.cpp index 1c6f6d1986d..a8b6ad7fbb1 100644 --- a/src/modes/profile_world.cpp +++ b/src/modes/profile_world.cpp @@ -258,7 +258,7 @@ void ProfileWorld::enterRaceOverState() } // Print group statistics of all karts - Log::verbose("profile", "min %f max %f av %f\n", + Log::verbose("profile", "min %f max %f av %f", min_t, max_t, av_t/m_karts.size()); // Determine maximum length of group name diff --git a/src/network/servers_manager.cpp b/src/network/servers_manager.cpp index 19507e2f77e..8b3191ebc43 100644 --- a/src/network/servers_manager.cpp +++ b/src/network/servers_manager.cpp @@ -463,7 +463,7 @@ std::vector ServersManager::getBroadcastAddresses(bool ipv6) u = (((u + (u >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; Log::debug("ServerManager", - "Interface: %s\tAddress: %s\tmask: %x\n", p->ifa_name, + "Interface: %s\tAddress: %s\tmask: %x", p->ifa_name, saddr.toString().c_str(), u); addAllBroadcastAddresses(saddr, u, &result); } diff --git a/src/race/grand_prix_manager.cpp b/src/race/grand_prix_manager.cpp index 4f7aa46db5f..7e1b80c3682 100644 --- a/src/race/grand_prix_manager.cpp +++ b/src/race/grand_prix_manager.cpp @@ -97,7 +97,7 @@ void GrandPrixManager::load(const std::string& filename, enum GrandPrixData::GPG if (gp != NULL) delete gp; Log::error("GrandPrixManager", - "Ignoring Grand Prix %s (%s)\n", filename.c_str(), e.what()); + "Ignoring Grand Prix %s (%s)", filename.c_str(), e.what()); } } // load diff --git a/src/race/highscore_manager.cpp b/src/race/highscore_manager.cpp index 1c198e72ee8..146f28fabf2 100644 --- a/src/race/highscore_manager.cpp +++ b/src/race/highscore_manager.cpp @@ -77,7 +77,7 @@ void HighscoreManager::loadHighscores() saveHighscores(); if(m_can_write) { - Log::info("Highscore Manager", "New highscore file '%s' created.\n", + Log::info("Highscore Manager", "New highscore file '%s' created.", m_filename.c_str()); } delete root; @@ -97,7 +97,7 @@ void HighscoreManager::loadHighscores() int v; if (!root->get("version", &v) || v<(int)CURRENT_HSCORE_FILE_VERSION) { - Log::error("Highscore Manager", "Highscore file format too old, a new one will be created.\n"); + Log::error("Highscore Manager", "Highscore file format too old, a new one will be created."); irr::core::stringw warning = _("The highscore file was too old,\nall highscores have been erased."); user_config->setWarning( warning ); @@ -121,23 +121,23 @@ void HighscoreManager::loadHighscores() } catch (std::logic_error& e) { - Log::error("Highscore Manager", "Invalid highscore entry will be skipped : %s\n", e.what()); + Log::error("Highscore Manager", "Invalid highscore entry will be skipped : %s", e.what()); continue; } m_all_scores.push_back(std::unique_ptr(highscores)); } // next entry if(UserConfigParams::logMisc()) - Log::error("Highscore Manager", "Highscores will be saved in '%s'.\n", + Log::error("Highscore Manager", "Highscores will be saved in '%s'.", m_filename.c_str()); } catch(std::exception& err) { - Log::error("Highscore Manager", "Error while parsing highscore file '%s':\n", + Log::error("Highscore Manager", "Error while parsing highscore file '%s':", m_filename.c_str()); Log::error("Highscore Manager", "%s", err.what()); - Log::error("Highscore Manager", "\n"); - Log::error("Highscore Manager", "No old highscores will be available.\n"); + Log::error("Highscore Manager", ""); + Log::error("Highscore Manager", "No old highscores will be available."); } if(root) delete root; diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index a3e0239b9b4..e2a6e0d4748 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -454,7 +454,7 @@ void RaceManager::startNew(bool from_overworld) if (m_num_ghost_karts > 0) m_num_karts += m_num_ghost_karts; - Log::verbose("RaceManager", "Nb of karts=%u, ghost karts:%u ai:%lu players:%lu\n", + Log::verbose("RaceManager", "Nb of karts=%u, ghost karts:%u ai:%lu players:%lu", (unsigned int) m_num_karts, m_num_ghost_karts, m_ai_kart_list.size(), m_player_karts.size()); std::set used_karts; for (auto& kart : m_ai_kart_list) @@ -1024,7 +1024,7 @@ void RaceManager::exitRace(bool delete_world) else { Log::error("RaceManager", "There are no winners and no losers." - "This should have never happened\n"); + "This should have never happened"); std::vector > karts; karts.emplace_back(UserConfigParams::m_default_kart, 0.0f); used_karts.insert(UserConfigParams::m_default_kart); @@ -1226,7 +1226,7 @@ void RaceManager::startWatchingReplay(const std::string &track_ident, m_num_karts = ReplayPlay::get()->getNumGhostKart(); m_kart_status.clear(); - Log::verbose("RaceManager", "%u ghost kart(s) for watching replay only\n", + Log::verbose("RaceManager", "%u ghost kart(s) for watching replay only", (unsigned int)m_num_karts); int init_gp_rank = 0; diff --git a/src/scriptengine/script_challenges.cpp b/src/scriptengine/script_challenges.cpp index 0e683e2d417..1fda4f778de 100644 --- a/src/scriptengine/script_challenges.cpp +++ b/src/scriptengine/script_challenges.cpp @@ -75,7 +75,7 @@ namespace Scripting if (challenge == NULL) { if (*challenge_name != "tutorial") - Log::error("track", "Cannot find challenge named '%s'\n", + Log::error("track", "Cannot find challenge named '%s'", challenge_name->c_str()); return false; } @@ -94,7 +94,7 @@ namespace Scripting if (challenge == NULL) { if (*challenge_name != "tutorial") - Log::error("track", "Cannot find challenge named '%s'\n", + Log::error("track", "Cannot find challenge named '%s'", challenge_name->c_str()); return false; } diff --git a/src/scriptengine/script_engine.cpp b/src/scriptengine/script_engine.cpp index 8713278ceff..45cdce3bcd4 100644 --- a/src/scriptengine/script_engine.cpp +++ b/src/scriptengine/script_engine.cpp @@ -60,7 +60,7 @@ namespace Scripting else if (msg->type == asMSGTYPE_INFORMATION) type = "INFO"; - Log::warn("Scripting", "%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message); + Log::warn("Scripting", "%s (%d, %d) : %s : %s", msg->section, msg->row, msg->col, type, msg->message); } diff --git a/src/states_screens/dialogs/select_challenge.cpp b/src/states_screens/dialogs/select_challenge.cpp index fe7ca43c813..15f71f2f48d 100644 --- a/src/states_screens/dialogs/select_challenge.cpp +++ b/src/states_screens/dialogs/select_challenge.cpp @@ -263,7 +263,7 @@ GUIEngine::EventPropagation SelectChallengeDialog::processEvent(const std::strin { if (c_data == NULL) { - Log::error("SelectChallenge", "Cannot find challenge <%s>\n", + Log::error("SelectChallenge", "Cannot find challenge <%s>", m_challenge_id.c_str()); return GUIEngine::EVENT_LET; } @@ -334,7 +334,7 @@ GUIEngine::EventPropagation SelectChallengeDialog::processEvent(const std::strin } else { - Log::error("SelectChallenge", "Unknown widget <%s>\n", + Log::error("SelectChallenge", "Unknown widget <%s>", action.c_str()); //assert(false); return GUIEngine::EVENT_LET; @@ -371,7 +371,7 @@ GUIEngine::EventPropagation SelectChallengeDialog::processEvent(const std::strin } else { - Log::error("SelectChallenge", "Unknown widget <%s>\n", + Log::error("SelectChallenge", "Unknown widget <%s>", selected.c_str()); //assert(false); return GUIEngine::EVENT_LET; diff --git a/src/states_screens/grand_prix_editor_screen.cpp b/src/states_screens/grand_prix_editor_screen.cpp index ac58ed58256..90b7e728a94 100644 --- a/src/states_screens/grand_prix_editor_screen.cpp +++ b/src/states_screens/grand_prix_editor_screen.cpp @@ -202,7 +202,7 @@ void GrandPrixEditorScreen::loadTrackList (const std::string& gpname) if (curr == NULL) { Log::warn("GrandPrixEditor", - "Grand Prix '%s' refers to track '%s', which does not exist\n", + "Grand Prix '%s' refers to track '%s', which does not exist", gp->getId().c_str(), tracks[t].c_str()); } else diff --git a/src/states_screens/grand_prix_lose.cpp b/src/states_screens/grand_prix_lose.cpp index ef7a207a684..6847f8bc7cd 100644 --- a/src/states_screens/grand_prix_lose.cpp +++ b/src/states_screens/grand_prix_lose.cpp @@ -227,7 +227,7 @@ void GrandPrixLose::setKarts(std::vector > ident_a } else { - Log::warn("GrandPrixLose", "A kart named '%s' could not be found\n", + Log::warn("GrandPrixLose", "A kart named '%s' could not be found", ident_arg[n].first.c_str()); m_kart_node[n] = NULL; } // if kart != NULL diff --git a/src/tracks/model_definition_loader.cpp b/src/tracks/model_definition_loader.cpp index 0aa902cc949..cf8169435dd 100644 --- a/src/tracks/model_definition_loader.cpp +++ b/src/tracks/model_definition_loader.cpp @@ -82,7 +82,7 @@ LODNode* ModelDefinitionLoader::instanciateAsLOD(const XMLNode* node, scene::ISc scene::IAnimatedMesh* a_mesh = irr_driver->getAnimatedMesh(group[m].m_model_file); if (!a_mesh) { - Log::warn("LODNodeLoad", "Warning: object model '%s' not found, ignored.\n", + Log::warn("LODNodeLoad", "Warning: object model '%s' not found, ignored.", group[m].m_model_file.c_str()); continue; } @@ -123,7 +123,7 @@ LODNode* ModelDefinitionLoader::instanciateAsLOD(const XMLNode* node, scene::ISc scene::IMesh* a_mesh = irr_driver->getMesh(group[m].m_model_file); if (!a_mesh) { - Log::warn("LODNodeLoad", "Warning: object model '%s' not found, ignored.\n", + Log::warn("LODNodeLoad", "Warning: object model '%s' not found, ignored.", group[m].m_model_file.c_str()); continue; } diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 0afa549a42b..107787f1372 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -465,7 +465,7 @@ void Track::cleanup() if(UserConfigParams::logMemory()) { Log::debug("track", - "[memory] After cleaning '%s': mesh cache %d texture cache %d\n", + "[memory] After cleaning '%s': mesh cache %d texture cache %d", getIdent().c_str(), irr_driver->getSceneManager()->getMeshCache()->getMeshCount(), irr_driver->getVideoDriver()->getTextureCount()); @@ -481,7 +481,7 @@ void Track::cleanup() m_old_mesh_buffers.erase(p); else { - Log::debug("track", "[memory] Leaked mesh buffer '%s'.\n", + Log::debug("track", "[memory] Leaked mesh buffer '%s'.", name.getInternalName().c_str()); } // if name not found } // for i < cache size @@ -499,7 +499,7 @@ void Track::cleanup() } else { - Log::debug("track", "[memory] Leaked texture '%s'.\n", + Log::debug("track", "[memory] Leaked texture '%s'.", t->getName().getInternalName().c_str()); } } @@ -654,7 +654,7 @@ void Track::loadTrackInfo() else if ( (m_is_arena || m_is_soccer) && !m_dont_load_navmesh) { Log::warn("Track", "NavMesh is not found for arena %s, " - "disable AI for it.\n", m_name.c_str()); + "disable AI for it.", m_name.c_str()); } if (m_is_soccer) { @@ -706,7 +706,7 @@ void Track::getMusicInformation(std::vector& filenames, m_music.push_back(mi); else Log::warn("track", - "Music information file '%s' not found for track '%s' - ignored.\n", + "Music information file '%s' not found for track '%s' - ignored.", filenames[i].c_str(), m_name.c_str()); } // for i in filenames @@ -716,7 +716,7 @@ void Track::getMusicInformation(std::vector& filenames, m_music.push_back(STKConfig::get()->m_default_music); Log::warn("track", - "Music information for track '%s' replaced by default music.\n", + "Music information for track '%s' replaced by default music.", m_name.c_str()); } if (!m_music.empty()) @@ -764,7 +764,7 @@ void Track::loadArenaGraph(const XMLNode &node) if(Graph::get()->getNumNodes()==0) { - Log::warn("track", "No graph nodes defined for track '%s'\n", + Log::warn("track", "No graph nodes defined for track '%s'", m_filename.c_str()); } else @@ -818,12 +818,12 @@ void Track::loadDriveGraph(unsigned int mode_id, const bool reverse) if(DriveGraph::get()->getNumNodes()==0) { - Log::warn("track", "No graph nodes defined for track '%s'\n", + Log::warn("track", "No graph nodes defined for track '%s'", m_filename.c_str()); if (RaceManager::get()->getNumberOfKarts() > 1) { Log::fatal("track", "I can handle the lack of driveline in single" - "kart mode, but not with AIs\n"); + "kart mode, but not with AIs"); } } else @@ -870,7 +870,7 @@ void Track::createPhysicsModel(unsigned int main_track_count, if (m_track_mesh == NULL) { Log::error("track", - "m_track_mesh == NULL, cannot createPhysicsModel\n"); + "m_track_mesh == NULL, cannot createPhysicsModel"); return; } @@ -987,7 +987,7 @@ void Track::convertTrackToBullet(scene::ISceneNode *node, int type_as_int = node->getType(); char* type = (char*)&type_as_int; Log::debug("track", - "[convertTrackToBullet] Unknown scene node type : %c%c%c%c.\n", + "[convertTrackToBullet] Unknown scene node type : %c%c%c%c.", type[0], type[1], type[2], type[3]); return; } // switch node->getType() @@ -1010,7 +1010,7 @@ void Track::convertTrackToBullet(scene::ISceneNode *node, mb->getVertexType() != video::EVT_TANGENTS && mb->getVertexType() != video::EVT_SKINNED_MESH) { - Log::warn("track", "convertTrackToBullet: Ignoring type '%d'!\n", + Log::warn("track", "convertTrackToBullet: Ignoring type '%d'!", mb->getVertexType()); continue; } @@ -1289,7 +1289,7 @@ bool Track::loadMainTrack(const XMLNode &root) if(!mesh) { Log::fatal("track", - "Main track model '%s' in '%s' not found, aborting.\n", + "Main track model '%s' in '%s' not found, aborting.", track_node->getName().c_str(), model_name.c_str()); } scene::IAnimatedMesh* an_mesh = dynamic_cast(mesh); @@ -1402,7 +1402,7 @@ bool Track::loadMainTrack(const XMLNode &root) if(n->getName()!="static-object") { Log::error("track", - "Incorrect tag '%s' inside of scene file - ignored\n", + "Incorrect tag '%s' inside of scene file - ignored", n->getName().c_str()); continue; } @@ -1450,7 +1450,7 @@ bool Track::loadMainTrack(const XMLNode &root) scene::IMesh *a_mesh = irr_driver->getMesh(full_path); if(!a_mesh) { - Log::error("track", "Object model '%s' not found, ignored.\n", + Log::error("track", "Object model '%s' not found, ignored.", full_path.c_str()); continue; } @@ -1488,7 +1488,7 @@ bool Track::loadMainTrack(const XMLNode &root) c = unlock_manager->getChallengeData(challenge); if (c == NULL) { - Log::error("track", "Cannot find challenge named <%s>\n", + Log::error("track", "Cannot find challenge named <%s>", challenge.c_str()); scene_node->remove(); continue; @@ -1508,7 +1508,7 @@ bool Track::loadMainTrack(const XMLNode &root) Track* t = TrackManager::get()->getTrack(c->getTrackId()); if (t == NULL) { - Log::error("track", "Cannot find track named <%s>\n", + Log::error("track", "Cannot find track named <%s>", c->getTrackId().c_str()); continue; } @@ -1577,7 +1577,7 @@ bool Track::loadMainTrack(const XMLNode &root) if (m_track_mesh == NULL) { - Log::fatal("track", "m_track_mesh == NULL, cannot loadMainTrack\n"); + Log::fatal("track", "m_track_mesh == NULL, cannot loadMainTrack"); } m_gfx_effect_mesh->createCollisionShape(); @@ -1615,7 +1615,7 @@ void Track::handleAnimatedTextures(scene::ISceneNode *node, const XMLNode &xml) if(name=="") { Log::error("track", - "Animated texture: no texture name specified for track '%s'\n", + "Animated texture: no texture name specified for track '%s'", m_ident.c_str()); continue; } @@ -1807,7 +1807,7 @@ void Track::createWater(const XMLNode &node) if(!mesh || !scene_node) { - Log::error("track", "Water model '%s' in '%s' not found, ignored.\n", + Log::error("track", "Water model '%s' in '%s' not found, ignored.", node.getName().c_str(), model_name.c_str()); return; } @@ -1889,7 +1889,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) if(UserConfigParams::logMemory()) { Log::debug("[memory] Before loading '%s': mesh cache %d " - "texture cache %d\n", + "texture cache %d", getIdent().c_str(), irr_driver->getSceneManager()->getMeshCache()->getMeshCount(), irr_driver->getVideoDriver()->getTextureCount()); @@ -2364,7 +2364,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) if (UserConfigParams::logMemory()) { Log::debug("track", "[memory] After loading '%s': mesh cache %d " - "texture cache %d\n", getIdent().c_str(), + "texture cache %d", getIdent().c_str(), irr_driver->getSceneManager()->getMeshCache()->getMeshCount(), irr_driver->getVideoDriver()->getTextureCount()); } @@ -2768,7 +2768,7 @@ void Track::itemCommand(const XMLNode *node) if(!(RaceManager::get()->isEggHuntMode()) && type==Item::ITEM_EASTER_EGG) { Log::warn("track", - "Found easter egg in non-easter-egg mode - ignored.\n"); + "Found easter egg in non-easter-egg mode - ignored."); return; } diff --git a/src/tracks/track_manager.cpp b/src/tracks/track_manager.cpp index 61e9cc5a4d3..a46d94b71e8 100644 --- a/src/tracks/track_manager.cpp +++ b/src/tracks/track_manager.cpp @@ -221,7 +221,7 @@ bool TrackManager::loadTrack(const std::string& dirname) } catch (std::exception& e) { - Log::error("TrackManager", "Cannot load track <%s> : %s\n", + Log::error("TrackManager", "Cannot load track <%s> : %s", dirname.c_str(), e.what()); return false; } diff --git a/src/utils/leak_check.cpp b/src/utils/leak_check.cpp index 3869aff2097..0ea216178be 100644 --- a/src/utils/leak_check.cpp +++ b/src/utils/leak_check.cpp @@ -88,7 +88,7 @@ namespace MemoryLeaks # elif defined(__APPLE__) for (int i = 0; i < m_stack_size; ++i) { - Log::error("LeakCheck", " %s\n", m_stack[i]); + Log::error("LeakCheck", " %s", m_stack[i]); } # elif defined(WIN32) std::vector calls = StringUtils::split(m_stack, '\n'); diff --git a/src/utils/profiler.cpp b/src/utils/profiler.cpp index 344f327addc..49fb6dee10b 100644 --- a/src/utils/profiler.cpp +++ b/src/utils/profiler.cpp @@ -451,7 +451,7 @@ void Profiler::draw() float curr_val = 0; for (unsigned i = 0; i < Q_LAST; i++) { - //Log::info("GPU Perf", "Phase %d : %d us\n", i, + //Log::info("GPU Perf", "Phase %d : %d us", i, // irr_driver->getGPUTimer(i).elapsedTimeus()); float elapsed = float(m_gpu_times[indx*Q_LAST+i]); diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index 509c9a411cd..7eb8eeda32d 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -587,7 +587,7 @@ namespace StringUtils if (insertValID >= all_vals.size()) { Log::warn("StringUtils", "insertValues: " - "Invalid number of arguments in '%s'\n", + "Invalid number of arguments in '%s'", irr::core::stringc(s.c_str()).c_str()); new_string += "??"; new_string += sv[i].subString(2, sv[i].size()-2); @@ -617,7 +617,7 @@ namespace StringUtils if (index >= all_vals.size()) { Log::warn("StringUtils", "insertValues: " - "Invalid argument ID in '%s' : %i\n", + "Invalid argument ID in '%s' : %i", irr::core::stringc(s.c_str()).c_str(), index); new_string += "??"; diff --git a/src/utils/time.cpp b/src/utils/time.cpp index 27473440d19..001a6289a15 100644 --- a/src/utils/time.cpp +++ b/src/utils/time.cpp @@ -152,7 +152,7 @@ void StkTime::getDate(int *day, int *month, int *year) // ---------------------------------------------------------------------------- StkTime::ScopeProfiler::ScopeProfiler(const char* name) { - Log::info("ScopeProfiler", "%s {\n", name); + Log::info("ScopeProfiler", "%s {", name); m_time = getMonoTimeMs(); m_name = name; } // StkTime::ScopeProfiler::ScopeProfiler @@ -161,6 +161,6 @@ StkTime::ScopeProfiler::ScopeProfiler(const char* name) StkTime::ScopeProfiler::~ScopeProfiler() { uint64_t difference = getMonoTimeMs() - m_time; - Log::info("ScopeProfiler", "} // took %d ms (%s)\n", + Log::info("ScopeProfiler", "} // took %d ms (%s)", (int)difference, m_name.c_str()); } // StkTime::ScopeProfiler::ScopeProfiler From d24fe7c6e4129087221b24ec1b7c35a7e93ba5a2 Mon Sep 17 00:00:00 2001 From: Deve Date: Sat, 14 Jun 2025 21:31:48 +0200 Subject: [PATCH 784/830] Add unlit and splatting shaders for vulkan --- data/shaders/ge_shaders/alphatest.frag | 3 +- data/shaders/ge_shaders/decal.frag | 3 +- data/shaders/ge_shaders/grass.vert | 1 + data/shaders/ge_shaders/normalmap.frag | 3 +- data/shaders/ge_shaders/shader_settings.xml | 24 ++++++++ data/shaders/ge_shaders/solid.frag | 3 +- data/shaders/ge_shaders/splatting.frag | 59 +++++++++++++++++++ data/shaders/ge_shaders/spm.vert | 1 + data/shaders/ge_shaders/spm_skinning.vert | 1 + data/shaders/ge_shaders/unlit.frag | 33 +++++++++++ data/shaders/ge_shaders/utils/handle_pbr.glsl | 5 +- data/shaders/ge_shaders/utils/spm_layout.vert | 1 + .../include/ge_material_manager.hpp | 3 + .../src/ge_material_manager.cpp | 10 ++++ .../src/ge_vulkan_texture_descriptor.cpp | 7 ++- src/graphics/material_manager.cpp | 7 ++- src/graphics/stk_text_billboard.cpp | 3 +- src/items/rubber_band.cpp | 3 + 18 files changed, 158 insertions(+), 12 deletions(-) create mode 100644 data/shaders/ge_shaders/splatting.frag create mode 100644 data/shaders/ge_shaders/unlit.frag diff --git a/data/shaders/ge_shaders/alphatest.frag b/data/shaders/ge_shaders/alphatest.frag index 267f233665a..3c704394d79 100644 --- a/data/shaders/ge_shaders/alphatest.frag +++ b/data/shaders/ge_shaders/alphatest.frag @@ -4,6 +4,7 @@ layout(location = 3) flat in int f_material_id; layout(location = 4) in float f_hue_change; #ifdef PBR_ENABLED layout(location = 5) in vec3 f_normal; +layout(location = 8) in vec4 f_world_position; #endif layout(location = 0) out vec4 o_color; @@ -34,6 +35,6 @@ void main() vec3 diffuse_color = tex_color.xyz * f_vertex_color.xyz; vec3 normal = normalize(f_normal.xyz); vec3 pbr = sampleMeshTexture2(f_material_id, f_uv).xyz; - o_color = vec4(handlePBR(diffuse_color, pbr, normal), 1.0); + o_color = vec4(handlePBR(diffuse_color, pbr, f_world_position, normal), 1.0); #endif } diff --git a/data/shaders/ge_shaders/decal.frag b/data/shaders/ge_shaders/decal.frag index ca5f2e3849c..95f7223211d 100644 --- a/data/shaders/ge_shaders/decal.frag +++ b/data/shaders/ge_shaders/decal.frag @@ -3,6 +3,7 @@ layout(location = 2) in vec2 f_uv_two; layout(location = 3) flat in int f_material_id; #ifdef PBR_ENABLED layout(location = 5) in vec3 f_normal; +layout(location = 8) in vec4 f_world_position; #endif layout(location = 0) out vec4 o_color; @@ -23,6 +24,6 @@ void main() #else vec3 normal = normalize(f_normal.xyz); vec3 pbr = sampleMeshTexture2(f_material_id, f_uv).xyz; - o_color = vec4(handlePBR(final_color, vec3(0.0), normal), 1.0); + o_color = vec4(handlePBR(final_color, vec3(0.0), f_world_position, normal), 1.0); #endif } diff --git a/data/shaders/ge_shaders/grass.vert b/data/shaders/ge_shaders/grass.vert index e1137f81e25..6d7be5865bd 100644 --- a/data/shaders/ge_shaders/grass.vert +++ b/data/shaders/ge_shaders/grass.vert @@ -18,6 +18,7 @@ void main() v_color.r, u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, u_object_buffer.m_objects[gl_InstanceIndex].m_scale, v_position); + f_world_position = v_world_position; gl_Position = u_camera.m_projection_view_matrix * v_world_position; f_vertex_color = vec4(1.0); f_uv = v_uv; diff --git a/data/shaders/ge_shaders/normalmap.frag b/data/shaders/ge_shaders/normalmap.frag index dba754525ae..ab7049ce315 100644 --- a/data/shaders/ge_shaders/normalmap.frag +++ b/data/shaders/ge_shaders/normalmap.frag @@ -6,6 +6,7 @@ layout(location = 4) in float f_hue_change; layout(location = 5) in vec3 f_normal; layout(location = 6) in vec3 f_tangent; layout(location = 7) in vec3 f_bitangent; +layout(location = 8) in vec4 f_world_position; #endif layout(location = 0) out vec4 o_color; @@ -51,6 +52,6 @@ void main() vec3 normal = normalize(t_b_n * tangent_space_normal); vec3 pbr = sampleMeshTexture2(f_material_id, f_uv).xyz; - o_color = vec4(handlePBR(diffuse_color, pbr, normal), 1.0); + o_color = vec4(handlePBR(diffuse_color, pbr, f_world_position, normal), 1.0); #endif } diff --git a/data/shaders/ge_shaders/shader_settings.xml b/data/shaders/ge_shaders/shader_settings.xml index 38dc34bcd6e..f35ab76ddf8 100644 --- a/data/shaders/ge_shaders/shader_settings.xml +++ b/data/shaders/ge_shaders/shader_settings.xml @@ -30,6 +30,18 @@ + + + solid + YNYYYY + + + spm.vert + splatting.frag + depth_only.frag + + + spm.vert @@ -39,6 +51,18 @@ + + + alphatest + + + spm.vert + unlit.frag + alphatest_depth.frag + spm_skinning.vert + + + grass.vert diff --git a/data/shaders/ge_shaders/solid.frag b/data/shaders/ge_shaders/solid.frag index 662f35e6c58..534bae28451 100644 --- a/data/shaders/ge_shaders/solid.frag +++ b/data/shaders/ge_shaders/solid.frag @@ -4,6 +4,7 @@ layout(location = 3) flat in int f_material_id; layout(location = 4) in float f_hue_change; #ifdef PBR_ENABLED layout(location = 5) in vec3 f_normal; +layout(location = 8) in vec4 f_world_position; #endif layout(location = 0) out vec4 o_color; @@ -41,6 +42,6 @@ void main() vec3 diffuse_color = tex_color.xyz * f_vertex_color.xyz; vec3 normal = normalize(f_normal.xyz); vec3 pbr = sampleMeshTexture2(f_material_id, f_uv).xyz; - o_color = vec4(handlePBR(diffuse_color, pbr, normal), 1.0); + o_color = vec4(handlePBR(diffuse_color, pbr, f_world_position, normal), 1.0); #endif } diff --git a/data/shaders/ge_shaders/splatting.frag b/data/shaders/ge_shaders/splatting.frag new file mode 100644 index 00000000000..49e7655e29a --- /dev/null +++ b/data/shaders/ge_shaders/splatting.frag @@ -0,0 +1,59 @@ +layout(location = 1) in vec2 f_uv; +layout(location = 2) in vec2 f_uv_two; +layout(location = 3) flat in int f_material_id; +layout(location = 5) in vec3 f_normal; +layout(location = 8) in vec4 f_world_position; + +layout(location = 0) out vec4 o_color; + +#include "utils/sample_mesh_texture.glsl" +#include "utils/handle_pbr.glsl" + +#define HIGH_RES_SAMPLER 1.0f +#define LOW_RES_SAMPLER 0.5f + +#ifdef PBR_ENABLED +vec4 sampleMultiResTextureLayer2(float factor, int material_id, vec2 uv) +{ + return mix(sampleMeshTexture2(material_id, uv * HIGH_RES_SAMPLER), sampleMeshTexture2(material_id, uv * LOW_RES_SAMPLER), factor); +} + +vec4 sampleMultiResTextureLayer3(float factor, int material_id, vec2 uv) +{ + return mix(sampleMeshTexture3(material_id, uv * HIGH_RES_SAMPLER), sampleMeshTexture3(material_id, uv * LOW_RES_SAMPLER), factor); +} + +vec4 sampleMultiResTextureLayer4(float factor, int material_id, vec2 uv) +{ + return mix(sampleMeshTexture4(material_id, uv * HIGH_RES_SAMPLER), sampleMeshTexture4(material_id, uv * LOW_RES_SAMPLER), factor); +} + +vec4 sampleMultiResTextureLayer5(float factor, int material_id, vec2 uv) +{ + return mix(sampleMeshTexture5(material_id, uv * HIGH_RES_SAMPLER), sampleMeshTexture5(material_id, uv * LOW_RES_SAMPLER), factor); +} +#endif + +void main() +{ +#ifdef PBR_ENABLED + // mitigate repetitive patterns + float cam_dist = length(u_camera.m_view_matrix * f_world_position); + float mitigation = clamp(pow(cam_dist * 0.01, 2.0) - 0., 0., 1.); + + // Splatting part + vec4 splatting = sampleMeshTexture1(f_material_id, f_uv_two); + vec4 detail0 = sampleMultiResTextureLayer2(mitigation, f_material_id, f_uv); + vec4 detail1 = sampleMultiResTextureLayer3(mitigation, f_material_id, f_uv); + vec4 detail2 = sampleMultiResTextureLayer4(mitigation, f_material_id, f_uv); + vec4 detail3 = sampleMultiResTextureLayer5(mitigation, f_material_id, f_uv); + + vec4 splatted = splatting.r * detail0 + + splatting.g * detail1 + + splatting.b * detail2 + + max(0.0, (1.0 - splatting.r - splatting.g - splatting.b)) * detail3; + + vec3 normal = normalize(f_normal.xyz); + o_color = vec4(handlePBR(splatted.xyz, vec3(0.0), f_world_position, normal), 1.0); +#endif +} diff --git a/data/shaders/ge_shaders/spm.vert b/data/shaders/ge_shaders/spm.vert index 077552b747f..a040c3e66dc 100644 --- a/data/shaders/ge_shaders/spm.vert +++ b/data/shaders/ge_shaders/spm.vert @@ -10,6 +10,7 @@ void main() u_object_buffer.m_objects[gl_InstanceIndex].m_translation, u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, u_object_buffer.m_objects[gl_InstanceIndex].m_scale, v_position); + f_world_position = v_world_position; gl_Position = u_camera.m_projection_view_matrix * v_world_position; f_vertex_color = v_color.zyxw * getVertexColor( u_object_buffer.m_objects[gl_InstanceIndex].m_custom_vertex_color); diff --git a/data/shaders/ge_shaders/spm_skinning.vert b/data/shaders/ge_shaders/spm_skinning.vert index 3c4477bafaf..d8b87d88cc6 100644 --- a/data/shaders/ge_shaders/spm_skinning.vert +++ b/data/shaders/ge_shaders/spm_skinning.vert @@ -18,6 +18,7 @@ void main() u_object_buffer.m_objects[gl_InstanceIndex].m_rotation, u_object_buffer.m_objects[gl_InstanceIndex].m_scale, v_skinning_position.xyz); + f_world_position = v_world_position; gl_Position = u_camera.m_projection_view_matrix * v_world_position; f_vertex_color = v_color.zyxw * getVertexColor( u_object_buffer.m_objects[gl_InstanceIndex].m_custom_vertex_color); diff --git a/data/shaders/ge_shaders/unlit.frag b/data/shaders/ge_shaders/unlit.frag new file mode 100644 index 00000000000..92bf3ca004f --- /dev/null +++ b/data/shaders/ge_shaders/unlit.frag @@ -0,0 +1,33 @@ +layout(location = 0) in vec4 f_vertex_color; +layout(location = 1) in vec2 f_uv; +layout(location = 3) flat in int f_material_id; +layout(location = 4) in float f_hue_change; +layout(location = 5) in vec3 f_normal; +layout(location = 8) in vec4 f_world_position; + +layout(location = 0) out vec4 o_color; + +#include "utils/sample_mesh_texture.glsl" +#include "../utils/rgb_conversion.frag" +#include "utils/handle_pbr.glsl" + +void main() +{ +#ifdef PBR_ENABLED + vec4 tex_color = sampleMeshTexture0(f_material_id, f_uv); + if (tex_color.a * f_vertex_color.a < 0.5) + discard; + + if (f_hue_change > 0.0) + { + vec3 old_hsv = rgbToHsv(tex_color.rgb); + vec2 new_xy = vec2(f_hue_change, old_hsv.y); + vec3 new_color = hsvToRgb(vec3(new_xy.x, new_xy.y, old_hsv.z)); + tex_color = vec4(new_color.r, new_color.g, new_color.b, tex_color.a); + } + vec3 diffuse_color = tex_color.xyz * f_vertex_color.xyz; + vec3 normal = normalize(f_normal.xyz); + vec3 pbr = vec3(0.0, 0.0, 0.4); + o_color = vec4(handlePBR(diffuse_color, pbr, f_world_position, normal), 1.0); +#endif +} diff --git a/data/shaders/ge_shaders/utils/handle_pbr.glsl b/data/shaders/ge_shaders/utils/handle_pbr.glsl index 364e0ef6378..4421f1a9374 100644 --- a/data/shaders/ge_shaders/utils/handle_pbr.glsl +++ b/data/shaders/ge_shaders/utils/handle_pbr.glsl @@ -11,10 +11,9 @@ layout (set = 2, binding = 1) uniform samplerCube u_specular; #include "pbr_light.glsl" #include "sun_direction.glsl" -vec3 handlePBR(vec3 diffuse_color, vec3 pbr, vec3 world_normal) +vec3 handlePBR(vec3 diffuse_color, vec3 pbr, vec4 world_position, vec3 world_normal) { - vec3 xpos = getPosFromFragCoord(gl_FragCoord, u_camera.m_viewport, - u_camera.m_inverse_projection_matrix); + vec3 xpos = (u_camera.m_view_matrix * world_position).xyz; vec3 eyedir = -normalize(xpos); vec3 normal = (u_camera.m_view_matrix * vec4(world_normal, 0.0)).xyz; vec3 reflection = reflect(-eyedir, normal); diff --git a/data/shaders/ge_shaders/utils/spm_layout.vert b/data/shaders/ge_shaders/utils/spm_layout.vert index 1b1589cd890..1d12aecb263 100644 --- a/data/shaders/ge_shaders/utils/spm_layout.vert +++ b/data/shaders/ge_shaders/utils/spm_layout.vert @@ -15,3 +15,4 @@ layout(location = 4) out float f_hue_change; layout(location = 5) out vec3 f_normal; layout(location = 6) out vec3 f_tangent; layout(location = 7) out vec3 f_bitangent; +layout(location = 8) out vec4 f_world_position; diff --git a/lib/graphics_engine/include/ge_material_manager.hpp b/lib/graphics_engine/include/ge_material_manager.hpp index 9d2228a2f89..241e51bb82c 100644 --- a/lib/graphics_engine/include/ge_material_manager.hpp +++ b/lib/graphics_engine/include/ge_material_manager.hpp @@ -27,6 +27,7 @@ struct GEMaterial bool m_backface_culling; bool m_depth_test; bool m_depth_write; + std::vector m_srgb_settings; // ------------------------------------------------------------------------ GEMaterial() { @@ -35,6 +36,8 @@ struct GEMaterial m_backface_culling = true; m_depth_test = true; m_depth_write = true; + m_srgb_settings = + { true, true, false, false, false, false, false, false }; } // ------------------------------------------------------------------------ bool texturelessDepth() const diff --git a/lib/graphics_engine/src/ge_material_manager.cpp b/lib/graphics_engine/src/ge_material_manager.cpp index bebcc2ef5d1..0d9db12dd4e 100644 --- a/lib/graphics_engine/src/ge_material_manager.cpp +++ b/lib/graphics_engine/src/ge_material_manager.cpp @@ -5,6 +5,7 @@ #include "vector3d.h" +#include #include #include #include @@ -108,6 +109,15 @@ void GEMaterialManager::init() settings.m_alphablend = readBool(xml); else if (!strcmp(node_name, "additive")) settings.m_additive = readBool(xml); + else if (!strcmp(node_name, "srgb-settings")) + { + std::string srgb_str = readString(xml); + for (unsigned i = 0; i < std::min(srgb_str.size(), + settings.m_srgb_settings.size()); i++) + { + settings.m_srgb_settings[i] = (srgb_str[i] == 'Y'); + } + } } else if (xml->getNodeType() == io::EXN_ELEMENT_END && !strcmp(xml->getNodeName(), "properties")) diff --git a/lib/graphics_engine/src/ge_vulkan_texture_descriptor.cpp b/lib/graphics_engine/src/ge_vulkan_texture_descriptor.cpp index 84eb331bd67..6dd41b840cd 100644 --- a/lib/graphics_engine/src/ge_vulkan_texture_descriptor.cpp +++ b/lib/graphics_engine/src/ge_vulkan_texture_descriptor.cpp @@ -1,6 +1,7 @@ #include "ge_vulkan_texture_descriptor.hpp" #include "ge_main.hpp" +#include "ge_material_manager.hpp" #include "ge_vulkan_driver.hpp" #include "ge_vulkan_texture.hpp" @@ -204,14 +205,14 @@ int GEVulkanTextureDescriptor::getTextureID(const irr::video::ITexture** list, m_transparent_image, m_transparent_image }}; + const auto& material = GEMaterialManager::getMaterial(shader); for (unsigned i = 0; i < m_max_layer; i++) { - // Assume 0, 1 layer is srgb for pbr enabled currently if (list[i]) { key[i] = static_cast( - list[i])->getImageView(getGEConfig()->m_pbr && - !shader.empty() && i <= 1 ? true : false); + list[i])->getImageView(getGEConfig()->m_pbr && material ? + material->m_srgb_settings[i] : false); } } auto it = m_texture_list.find(key); diff --git a/src/graphics/material_manager.cpp b/src/graphics/material_manager.cpp index f068b95a5b9..2f268d2679a 100644 --- a/src/graphics/material_manager.cpp +++ b/src/graphics/material_manager.cpp @@ -143,6 +143,8 @@ Material* MaterialManager::getMaterialSPM(std::string lay_one_tex_lc, } } // for i } + if (def_shader_name.empty()) + return NULL; Log::debug("MaterialManager", "Couldn't find cached SP material! Opening default %s!", original_layer_one.c_str()); return getDefaultSPMaterial(def_shader_name, is_full_path ? @@ -205,7 +207,10 @@ Material* MaterialManager::getMaterialFor(video::ITexture* t, void MaterialManager::setAllMaterialFlags(video::ITexture* t, scene::IMeshBuffer *mb) { - Material* mat = getMaterialFor(t, mb); + io::path fp = file_manager->getFileSystem()->getAbsolutePath(t->getName()); + video::ITexture* t1 = mb->getMaterial().getTexture(1); + Material* mat = getMaterialSPM(fp.c_str(), + t1 ? StringUtils::getBasename(t1->getFullPath().c_str()) : "" , ""); if (mat != NULL) { mat->setMaterialProperties(&(mb->getMaterial()), mb); diff --git a/src/graphics/stk_text_billboard.cpp b/src/graphics/stk_text_billboard.cpp index 04d31ab50f7..e9c357ca5b9 100644 --- a/src/graphics/stk_text_billboard.cpp +++ b/src/graphics/stk_text_billboard.cpp @@ -23,6 +23,7 @@ #include "graphics/graphics_restrictions.hpp" #include +#include #include #include #include @@ -387,7 +388,7 @@ void STKTextBillboard::initLegacy(const core::stringw& text, FontWithFace* face) GE::GESPMBuffer* spm_mb = new GE::GESPMBuffer(); spm_mb->getMaterial().setTexture(0, p.first); spm_mb->getMaterial().MaterialType = - video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + GE::GEMaterialManager::getIrrMaterialType("unlit"); spm_mb->getMaterial().Lighting = false; for (auto& q : p.second) { diff --git a/src/items/rubber_band.cpp b/src/items/rubber_band.cpp index 3c13f17df67..2860686e9da 100644 --- a/src/items/rubber_band.cpp +++ b/src/items/rubber_band.cpp @@ -37,6 +37,7 @@ #ifndef SERVER_ONLY #include #include +#include #include #endif #include @@ -97,6 +98,8 @@ RubberBand::RubberBand(Plunger *plunger, AbstractKart *kart) {{ v, v, v, v }}; buffer->append(vertices.data(), vertices.size(), indices.data(), indices.size()); + buffer->getMaterial().MaterialType = + GE::GEMaterialManager::getIrrMaterialType("unlit"); } else { From b84d71ee8f8bd4cbe6e4fa57e3bc41b7839fc06b Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 15 Jun 2025 02:02:49 +0400 Subject: [PATCH 785/830] Fix length multiplier being applied as int --- src/utils/lobby_settings.cpp | 2 +- src/utils/lobby_settings.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index 2d21c624073..6d8cbc53a06 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -198,7 +198,7 @@ bool LobbySettings::hasFixedLapCount() const } // hasFixedLapCount //----------------------------------------------------------------------------- -int LobbySettings::getMultiplier() const +double LobbySettings::getMultiplier() const { return m_default_lap_multiplier; } // getMultiplier diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 23e0ad39ce3..4f9b227b039 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -58,7 +58,7 @@ class LobbySettings: public LobbyContextComponent bool hasNoLapRestrictions() const; bool hasMultiplier() const; bool hasFixedLapCount() const; - int getMultiplier() const; + double getMultiplier() const; int getFixedLapCount() const; void setMultiplier(double new_value); void setFixedLapCount(int new_value); From 0ed2a045495064c6170e023d4e95e93356e5a5b5 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 15 Jun 2025 03:58:13 +0400 Subject: [PATCH 786/830] Avoid extra lobby inactivity kicks by updating activity upon leaving the game --- src/network/protocols/server_lobby.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 73eed8b0d04..45ba2bb086f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -329,6 +329,7 @@ void ServerLobby::setup() m_server_started_at = m_server_delay = 0; getCommandManager()->onServerSetup(); m_game_info = {}; + Log::info("ServerLobby", "Resetting the server to its initial state."); } // setup @@ -1068,6 +1069,8 @@ void ServerLobby::rejectLiveJoin(std::shared_ptr peer, BackLobbyReason m_game_setup->addServerInfo(server_info); peer->sendPacket(server_info, PRM_RELIABLE); delete server_info; + + peer->updateLastActivity(); } // rejectLiveJoin //----------------------------------------------------------------------------- @@ -2636,6 +2639,8 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, peer->sendPacket(server_info); delete server_info; + peer->updateLastActivity(); + const bool game_started = m_state.load() != WAITING_FOR_START_GAME; NetworkString* message_ack = getNetworkString(4); message_ack->setSynchronous(true); @@ -3403,6 +3408,13 @@ void ServerLobby::resetServer() m_game_setup->addServerInfo(server_info); Comm::sendMessageToPeersInServer(server_info); delete server_info; + + for (auto p : m_peers_ready) + { + if (auto peer = p.first.lock()) + peer->updateLastActivity(); + } + setup(); m_state = NetworkConfig::get()->isLAN() ? WAITING_FOR_START_GAME : REGISTER_SELF_ADDRESS; @@ -3696,6 +3708,7 @@ void ServerLobby::handleServerConfiguration(std::shared_ptr peer, m_game_setup->addServerInfo(server_info); Comm::sendMessageToPeers(server_info); delete server_info; + updatePlayerList(); if (getKartElimination()->isEnabled() && @@ -4075,6 +4088,8 @@ void ServerLobby::clientInGameWantsToBackLobby(Event* event) m_game_setup->addServerInfo(server_info); peer->sendPacket(server_info, PRM_RELIABLE); delete server_info; + + peer->updateLastActivity(); } // clientInGameWantsToBackLobby //----------------------------------------------------------------------------- @@ -4123,6 +4138,8 @@ void ServerLobby::clientSelectingAssetsWantsToBackLobby(Event* event) m_game_setup->addServerInfo(server_info); peer->sendPacket(server_info, PRM_RELIABLE); delete server_info; + + peer->updateLastActivity(); } // clientSelectingAssetsWantsToBackLobby //----------------------------------------------------------------------------- From 1ae2518f9cfc0e2adc81dab4571c8f7c84b76356 Mon Sep 17 00:00:00 2001 From: Deve Date: Sun, 15 Jun 2025 22:05:01 +0200 Subject: [PATCH 787/830] Make loadAllShaders possible to reload shaders --- lib/graphics_engine/src/ge_vulkan_driver.cpp | 6 +- .../src/ge_vulkan_shader_manager.cpp | 78 +++++++++++-------- .../src/ge_vulkan_shader_manager.hpp | 2 +- 3 files changed, 47 insertions(+), 39 deletions(-) diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index 72fd728fabb..18b489a9e4f 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -2576,8 +2576,7 @@ void GEVulkanDriver::updateDriver(bool scale_changed, bool pbr_changed, destroySwapChainRelated(false/*handle_surface*/); if (pbr_changed) { - GEVulkanShaderManager::destroy(); - GEVulkanShaderManager::init(this); + GEVulkanShaderManager::loadAllShaders(); GEVulkanSampler sampler = m_mesh_texture_descriptor->getSamplerUse(); delete m_mesh_texture_descriptor; m_mesh_texture_descriptor = new GEVulkanTextureDescriptor( @@ -2628,8 +2627,7 @@ void GEVulkanDriver::reloadShaders() waitIdle(); setDisableWaitIdle(true); clearDrawCallsCache(); - GEVulkanShaderManager::destroy(); - GEVulkanShaderManager::init(this); + GEVulkanShaderManager::loadAllShaders(); for (auto& dc : static_cast( m_irrlicht_device->getSceneManager())->getDrawCalls()) dc.second = std::unique_ptr(new GEVulkanDrawCall); diff --git a/lib/graphics_engine/src/ge_vulkan_shader_manager.cpp b/lib/graphics_engine/src/ge_vulkan_shader_manager.cpp index ca336ec07fe..cc5864df344 100644 --- a/lib/graphics_engine/src/ge_vulkan_shader_manager.cpp +++ b/lib/graphics_engine/src/ge_vulkan_shader_manager.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -29,7 +30,21 @@ uint32_t g_mesh_texture_layer = 2; uint32_t g_sampler_size = 512; -std::map* > g_shaders; +struct ShaderHolder +{ + GESpinLock m_lock; + VkShaderModule m_shader_module; + ShaderHolder() : m_shader_module(VK_NULL_HANDLE) {} + ~ShaderHolder() + { + m_lock.lock(); + m_lock.unlock(); + if (g_vk && m_shader_module != VK_NULL_HANDLE) + vkDestroyShaderModule(g_vk->getDevice(), m_shader_module, NULL); + } +}; + +std::map > g_shaders; } // GEVulkanShaderManager // ============================================================================ @@ -51,7 +66,21 @@ void GEVulkanShaderManager::init(GEVulkanDriver* vk) { g_vk = vk; g_file_system = vk->getFileSystem(); + loadAllShaders(); +} // init +// ---------------------------------------------------------------------------- +void GEVulkanShaderManager::destroy() +{ + g_shaders.clear(); + g_vk = NULL; + g_file_system = NULL; +} // destroy + +// ---------------------------------------------------------------------------- +void GEVulkanShaderManager::loadAllShaders(const std::string& match_filename) +{ +#ifndef DISABLE_SHADERC std::ostringstream oss; oss << "#version 450\n"; if (getGEConfig()->m_pbr) @@ -79,28 +108,6 @@ void GEVulkanShaderManager::init(GEVulkanDriver* vk) oss << "#define SHADER_STORAGE_IMAGE_EXTENDED_FORMATS\n"; g_predefines = oss.str(); - loadAllShaders(); -} // init - -// ---------------------------------------------------------------------------- -void GEVulkanShaderManager::destroy() -{ - if (!g_vk) - return; - for (auto& p : g_shaders) - { - p.second->first.lock(); - p.second->first.unlock(); - vkDestroyShaderModule(g_vk->getDevice(), p.second->second, NULL); - delete p.second; - } - g_shaders.clear(); -} // destroy - -// ---------------------------------------------------------------------------- -void GEVulkanShaderManager::loadAllShaders() -{ -#ifndef DISABLE_SHADERC irr::io::IFileList* files = g_file_system->createFileList( getShaderFolder().c_str()); for (unsigned i = 0; i < files->getFileCount(); i++) @@ -108,6 +115,9 @@ void GEVulkanShaderManager::loadAllShaders() if (files->isDirectory(i)) continue; std::string filename = files->getFileName(i).c_str(); + if (!match_filename.empty() && + filename.find(match_filename) == std::string::npos) + continue; std::string ext = filename.substr(filename.find_last_of(".") + 1); shaderc_shader_kind kind; if (ext == "vert") @@ -122,21 +132,21 @@ void GEVulkanShaderManager::loadAllShaders() kind = shaderc_tess_evaluation_shader; else continue; - auto pair = new std::pair(); - g_shaders[filename] = pair; - pair->first.lock(); + g_shaders[filename] = std::unique_ptr(new ShaderHolder); + auto holder = g_shaders.at(filename).get(); + holder->m_lock.lock(); GEVulkanCommandLoader::addMultiThreadingCommand( - [pair, kind, filename]() + [holder, kind, filename]() { try { - pair->second = loadShader(kind, filename); + holder->m_shader_module = loadShader(kind, filename); } catch (std::exception& e) { printf("%s", e.what()); } - pair->first.unlock(); + holder->m_lock.unlock(); }); } files->drop(); @@ -278,12 +288,12 @@ unsigned GEVulkanShaderManager::getMeshTextureLayer() // ---------------------------------------------------------------------------- VkShaderModule GEVulkanShaderManager::getShader(const std::string& filename) { - auto it = g_shaders.at(filename); - it->first.lock(); - it->first.unlock(); - if (it->second == VK_NULL_HANDLE) + auto& it = g_shaders.at(filename); + it->m_lock.lock(); + it->m_lock.unlock(); + if (it->m_shader_module == VK_NULL_HANDLE) throw std::runtime_error(std::string("Missing shader ") + filename); - return it->second; + return it->m_shader_module; } // getShader } diff --git a/lib/graphics_engine/src/ge_vulkan_shader_manager.hpp b/lib/graphics_engine/src/ge_vulkan_shader_manager.hpp index c2f01b92cda..2b83979cf63 100644 --- a/lib/graphics_engine/src/ge_vulkan_shader_manager.hpp +++ b/lib/graphics_engine/src/ge_vulkan_shader_manager.hpp @@ -19,7 +19,7 @@ void init(GEVulkanDriver*); // ---------------------------------------------------------------------------- void destroy(); // ---------------------------------------------------------------------------- -void loadAllShaders(); +void loadAllShaders(const std::string& match_filename = ""); // ---------------------------------------------------------------------------- VkShaderModule getShader(const std::string& filename); // ---------------------------------------------------------------------------- From f5f767cd677774e3564d095e6e06b7d89cc42e93 Mon Sep 17 00:00:00 2001 From: martin Date: Mon, 16 Jun 2025 21:30:02 +0200 Subject: [PATCH 788/830] Fix use of uninitialized variable in PowerupManager (#5459) Also avoid a potenial null pointer dereference Remove two unused includes Minor cleanups --- src/items/powerup_manager.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/items/powerup_manager.cpp b/src/items/powerup_manager.cpp index e818e7d3793..d1758eb263d 100644 --- a/src/items/powerup_manager.cpp +++ b/src/items/powerup_manager.cpp @@ -17,10 +17,6 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "items/powerup_manager.hpp" - -#include -#include - #include "config/stk_config.hpp" #include "graphics/irr_driver.hpp" #include "graphics/sp/sp_base.hpp" @@ -41,7 +37,7 @@ #include -PowerupManager* powerup_manager=0; +PowerupManager* powerup_manager = nullptr; //----------------------------------------------------------------------------- /** The constructor initialises everything to zero. */ @@ -50,8 +46,8 @@ PowerupManager::PowerupManager() m_random_seed.store(0); for(int i=0; idrop(), // or delete them, or... - m_all_icons[i] = (Material*)NULL; + m_all_icons[i] = (Material*)nullptr; } } // removeTextures @@ -107,7 +103,7 @@ PowerupManager::PowerupType PowerupManager::getPowerupType(const std::string &name) const { // Must match the order of PowerupType in powerup_manager.hpp!! - static std::string powerup_names[] = { + static const std::string powerup_names[] = { "", /* Nothing */ "bubblegum", "cake", "bowling", "zipper", "plunger", "switch", "swatter", "rubber-ball", "parachute", "anchor" @@ -185,6 +181,7 @@ void PowerupManager::loadWeights(const XMLNode *powerup_node, Log::fatal("PowerupManager", "Cannot find node '%s' in powerup.xml file.", class_name.c_str()); + return; } for (unsigned int i = 0; i < node->getNumNodes(); i++) @@ -232,12 +229,19 @@ void PowerupManager::WeightsData::readData(int num_karts, const XMLNode *node) // Keep a reference for shorter access to the list std::vector &l = m_weights_for_section.back(); - for(unsigned int i=0; igetName().c_str()); + } } // Make sure we have the right number of entries if (l.size() < 2 * (int)POWERUP_LAST) @@ -472,8 +476,8 @@ void PowerupManager::loadPowerup(PowerupType type, const XMLNode &node) /*strip_path*/ false); - assert(m_all_icons[type] != NULL); - assert(m_all_icons[type]->getTexture() != NULL); + assert(m_all_icons[type] != nullptr); + assert(m_all_icons[type]->getTexture() != nullptr); std::string model(""); node.get("model", &model); From fc61b919cc350c817768b2905a21270909dd7f4a Mon Sep 17 00:00:00 2001 From: Deve Date: Mon, 16 Jun 2025 22:04:29 +0200 Subject: [PATCH 789/830] Fix compiler warnings --- lib/graphics_engine/src/ge_vulkan_environment_map.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/graphics_engine/src/ge_vulkan_environment_map.cpp b/lib/graphics_engine/src/ge_vulkan_environment_map.cpp index 50ebf781a47..05ddf731b3c 100644 --- a/lib/graphics_engine/src/ge_vulkan_environment_map.cpp +++ b/lib/graphics_engine/src/ge_vulkan_environment_map.cpp @@ -242,8 +242,8 @@ void GEVulkanEnvironmentMap::load() compute_info.stage.module = GEVulkanShaderManager::getShader("diffuse_irradiance.comp"); compute_info.layout = pipeline_layout; - if (vkCreateComputePipelines(vk->getDevice(), NULL, 1, &compute_info, - NULL, &diffuse_pipeline) != VK_SUCCESS) + if (vkCreateComputePipelines(vk->getDevice(), VK_NULL_HANDLE, 1, + &compute_info, NULL, &diffuse_pipeline) != VK_SUCCESS) { printf("vkCreateComputePipelines failed for " "GEVulkanEnvironmentMap::load"); @@ -252,8 +252,8 @@ void GEVulkanEnvironmentMap::load() compute_info.stage.module = GEVulkanShaderManager::getShader("specular_prefilter.comp"); - if (vkCreateComputePipelines(vk->getDevice(), NULL, 1, &compute_info, - NULL, &specular_pipeline) != VK_SUCCESS) + if (vkCreateComputePipelines(vk->getDevice(), VK_NULL_HANDLE, 1, + &compute_info, NULL, &specular_pipeline) != VK_SUCCESS) { printf("vkCreateComputePipelines failed for " "GEVulkanEnvironmentMap::load"); From 31695b53729ba550ddf29f83c3bf77aae79a414d Mon Sep 17 00:00:00 2001 From: Deve Date: Mon, 16 Jun 2025 22:17:07 +0200 Subject: [PATCH 790/830] Better warning message when shaderc is not enabled --- lib/graphics_engine/src/ge_vulkan_shader_manager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/graphics_engine/src/ge_vulkan_shader_manager.cpp b/lib/graphics_engine/src/ge_vulkan_shader_manager.cpp index cc5864df344..2d3626eeb97 100644 --- a/lib/graphics_engine/src/ge_vulkan_shader_manager.cpp +++ b/lib/graphics_engine/src/ge_vulkan_shader_manager.cpp @@ -288,6 +288,11 @@ unsigned GEVulkanShaderManager::getMeshTextureLayer() // ---------------------------------------------------------------------------- VkShaderModule GEVulkanShaderManager::getShader(const std::string& filename) { + if (g_shaders.empty()) + { + throw std::runtime_error("No vulkan shaders compiled, perhaps shaderc " + "is not enabled."); + } auto& it = g_shaders.at(filename); it->m_lock.lock(); it->m_lock.unlock(); From 352470386f6c11085249fba9410a0788ffc93b5f Mon Sep 17 00:00:00 2001 From: Deve Date: Mon, 16 Jun 2025 23:57:28 +0200 Subject: [PATCH 791/830] Enable BC7 texture compression with cross compiled ISPC --- .github/workflows/apple.yml | 54 ++++++++++-------- .github/workflows/windows.yml | 13 ++++- cmake/Toolchain-cctools.cmake | 8 +++ cmake/Toolchain-llvm-mingw.cmake | 11 ++++ cmake/Toolchain-mingw-64bit.cmake | 2 + cmake/Toolchain-mingw.cmake | 2 + lib/graphics_engine/CMakeLists.txt | 36 +++++++++++- lib/graphics_engine/src/libchkstk.S | 85 +++++++++++++++++++++++++++++ tools/build-cross-ispc.sh | 73 +++++++++++++++++++++++++ 9 files changed, 256 insertions(+), 28 deletions(-) create mode 100644 lib/graphics_engine/src/libchkstk.S create mode 100755 tools/build-cross-ispc.sh diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml index 311cfd2ced4..108014763fb 100644 --- a/.github/workflows/apple.yml +++ b/.github/workflows/apple.yml @@ -29,12 +29,15 @@ jobs: uses: ASzc/change-string-case-action@v1 with: string: ${{ matrix.platform }} - - name: Download cctools + - name: Download cctools and ISPC run: | cd /opt wget https://github.com/supertuxkart/dependencies/releases/download/cctools/cctools-14.1.tar.xz tar xf cctools-14.1.tar.xz rm cctools-14.1.tar.xz + wget https://github.com/supertuxkart/dependencies/releases/download/preview/ispc-cross-1.26.0.tar.xz + tar xf ispc-cross-1.26.0.tar.xz + rm ispc-cross-1.26.0.tar.xz - name: Restore timestamps run: | wget https://github.com/MestreLion/git-tools/archive/refs/heads/main.zip @@ -86,7 +89,8 @@ jobs: mkdir -p build cd build cmake .. -DCCTOOLS_PREFIX=/opt/cctools -DCCTOOLS_ARCH=${{ matrix.arch }} -DCCTOOLS_PLATFORM=${{ matrix.platform }} \ - -DRT=/opt/cctools/darwin/libclang_rt.${{ env.rt }}.a -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cctools.cmake -DCHECK_ASSETS=OFF + -DRT=/opt/cctools/darwin/libclang_rt.${{ env.rt }}.a -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cctools.cmake -DCHECK_ASSETS=OFF \ + -DBC7_ISPC=ON -DCMAKE_ISPC_COMPILER=/opt/ispc/bin/ispc - name: Build run: | cd build @@ -132,26 +136,25 @@ jobs: echo "${{ env.release_pre }}" - name: Download binaries uses: actions/download-artifact@v4 - - name: Mask developer name - run: | - echo "::add-mask::${{ secrets.MAC_DEVELOPER_NAME }}" - - name: Import certificates - if: ${{ env.release_tag != '' }} - uses: apple-actions/import-codesign-certs@v1 - with: - p12-file-base64: ${{ secrets.MAC_DEVELOPER_ID_P12_FILE }} - p12-password: ${{ secrets.MAC_DEVELOPER_ID_P12_PASSWORD }} + #- name: Mask developer name + # run: | + # echo "::add-mask::${{ secrets.MAC_DEVELOPER_NAME }}" + #- name: Import certificates + # if: ${{ env.release_tag != '' }} + # uses: apple-actions/import-codesign-certs@v1 + # with: + # p12-file-base64: ${{ secrets.MAC_DEVELOPER_ID_P12_FILE }} + # p12-password: ${{ secrets.MAC_DEVELOPER_ID_P12_PASSWORD }} - name: Run dylibbundler and sign STK if: ${{ env.release_tag != '' }} - env: - developer_id: "Developer ID Application: ${{ secrets.MAC_DEVELOPER_NAME }} (${{ secrets.MAC_DEVELOPER_TEAM }})" + # env: + # developer_id: "Developer ID Application: ${{ secrets.MAC_DEVELOPER_NAME }} (${{ secrets.MAC_DEVELOPER_TEAM }})" run: | wget https://github.com/supertuxkart/dependencies/releases/download/preview/dependencies-macosx.tar.xz tar xf dependencies-macosx.tar.xz HOMEBREW_NO_AUTO_UPDATE=1 brew install dylibbundler lipo -create ./macosx-x86_64/supertuxkart.app/Contents/MacOS/supertuxkart ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -output ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart chmod 755 ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart - install_name_tool -change libcurl.4.dylib @rpath/libcurl.4.dylib ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart install_name_tool -delete_rpath @loader_path/Frameworks ./dependencies-macosx/lib/libSDL2.dylib install_name_tool -delete_rpath @executable_path/Frameworks ./dependencies-macosx/lib/libSDL2.dylib dylibbundler -od -b -x ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -d ./macosx-arm64/supertuxkart.app/Contents/libs/ -p @executable_path/../libs/ -s ./dependencies-macosx/lib -ns @@ -163,16 +166,19 @@ jobs: rm stk-assets-full.zip cd ../../../../.. mv ./macosx-arm64/supertuxkart.app SuperTuxKart.app - codesign --force --sign "$developer_id" SuperTuxKart.app/Contents/libs/*.dylib - codesign --force --options=runtime --deep --sign "$developer_id" SuperTuxKart.app - - name: "Notarize release build" - if: ${{ env.release_tag != '' && github.ref != 'refs/heads/master' }} - run: | - ditto -c -k --sequesterRsrc --keepParent SuperTuxKart.app tmp.zip - xcrun notarytool submit tmp.zip --apple-id ${{ secrets.STK_NOTARIZATION_USERNAME }} \ - --password ${{ secrets.STK_NOTARIZATION_PASSWORD }} \ - --team-id ${{ secrets.MAC_DEVELOPER_TEAM }} --wait - xcrun stapler staple SuperTuxKart.app + # Use Ad Hoc certificate for now, previous certificate has been expired. + codesign --force -s - SuperTuxKart.app/Contents/libs/*.dylib + codesign --force --deep -s - SuperTuxKart.app + #codesign --force --sign "$developer_id" SuperTuxKart.app/Contents/libs/*.dylib + #codesign --force --options=runtime --deep --sign "$developer_id" SuperTuxKart.app + #- name: "Notarize release build" + # if: ${{ env.release_tag != '' && github.ref != 'refs/heads/master' }} + # run: | + # ditto -c -k --sequesterRsrc --keepParent SuperTuxKart.app tmp.zip + # xcrun notarytool submit tmp.zip --apple-id ${{ secrets.STK_NOTARIZATION_USERNAME }} \ + # --password ${{ secrets.STK_NOTARIZATION_PASSWORD }} \ + # --team-id ${{ secrets.MAC_DEVELOPER_TEAM }} --wait + # xcrun stapler staple SuperTuxKart.app - name: Archive if: ${{ env.release_tag != '' }} run: | diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 1867ca11aaf..b3b8b940e6a 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -78,6 +78,13 @@ jobs: run: | ${{ env.wget }} https://github.com/supertuxkart/dependencies/releases/download/preview/dependencies-win-${{ matrix.arch }}.zip ${{ env.unzip }} dependencies-win-${{ matrix.arch }}.zip + - name: Download ISPC for MinGW + if: ${{ matrix.os == 'ubuntu-latest' }} + run: | + cd /opt + wget https://github.com/supertuxkart/dependencies/releases/download/preview/ispc-cross-1.26.0.tar.xz + tar xf ispc-cross-1.26.0.tar.xz + rm ispc-cross-1.26.0.tar.xz - name: Install MinGW for i686 or x86_64 if: ${{ matrix.os == 'ubuntu-latest' && ( matrix.arch == 'i686' || matrix.arch == 'x86_64' ) }} run: | @@ -108,6 +115,7 @@ jobs: echo "set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)" >> toolchain.cmake echo "set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ALWAYS)" >> toolchain.cmake echo "set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)" >> toolchain.cmake + echo 'set(ISPC_ARCH "x86")' >> toolchain.cmake - name: Set up MinGW Toolchain for x86_64 if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch == 'x86_64' }} run: | @@ -119,6 +127,7 @@ jobs: echo "set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)" >> toolchain.cmake echo "set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ALWAYS)" >> toolchain.cmake echo "set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)" >> toolchain.cmake + echo 'set(ISPC_ARCH "x86-64")' >> toolchain.cmake # Manually specify CMAKE_SYSTEM_PROCESSOR, it can only be set together with -DDCMAKE_SYSTEM_NAME - name: Configure bulid for MSVC if: ${{ matrix.os == 'windows-latest' }} @@ -131,13 +140,13 @@ jobs: run: | mkdir -p build cd build - cmake .. -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCHECK_ASSETS=OFF -DUSE_DIRECTX=ON + cmake .. -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCHECK_ASSETS=OFF -DUSE_DIRECTX=ON -DBC7_ISPC=ON -DCMAKE_ISPC_COMPILER=/opt/ispc/bin/ispc - name: Configure bulid for MinGW (armv7 or aarch64) if: ${{ matrix.os == 'ubuntu-latest' && ( matrix.arch == 'armv7' || matrix.arch == 'aarch64' ) }} run: | mkdir -p build cd build - cmake .. -DLLVM_ARCH=${{ matrix.arch }} -DLLVM_PREFIX=/llvm-mingw -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-llvm-mingw.cmake -DCHECK_ASSETS=OFF -DUSE_DIRECTX=ON + cmake .. -DLLVM_ARCH=${{ matrix.arch }} -DLLVM_PREFIX=/llvm-mingw -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-llvm-mingw.cmake -DCHECK_ASSETS=OFF -DUSE_DIRECTX=ON -DBC7_ISPC=ON -DCMAKE_ISPC_COMPILER=/opt/ispc/bin/ispc - name: Build for MSVC if: ${{ matrix.os == 'windows-latest' }} working-directory: build diff --git a/cmake/Toolchain-cctools.cmake b/cmake/Toolchain-cctools.cmake index 7f6c430946c..d9dee71b3fc 100644 --- a/cmake/Toolchain-cctools.cmake +++ b/cmake/Toolchain-cctools.cmake @@ -46,3 +46,11 @@ set(USE_WIIUSE FALSE CACHE BOOL "") set(USE_SQLITE3 FALSE CACHE BOOL "") set(IOS TRUE CACHE BOOL "") endif() + +if(CCTOOLS_ARCH MATCHES "x86_64") + set(ISPC_ARCH "x86-64") +elseif(CCTOOLS_ARCH MATCHES "arm64") + set(ISPC_ARCH "aarch64") +else() + set(ISPC_ARCH unknown) +endif() diff --git a/cmake/Toolchain-llvm-mingw.cmake b/cmake/Toolchain-llvm-mingw.cmake index 9fea7488fe1..cdd17b57dff 100644 --- a/cmake/Toolchain-llvm-mingw.cmake +++ b/cmake/Toolchain-llvm-mingw.cmake @@ -26,3 +26,14 @@ SET(CMAKE_FIND_ROOT_PATH ${LLVM_PREFIX}/generic-w64-mingw32 ${LLVM_PREFIX}/${LLV set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ALWAYS) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +if(LLVM_ARCH MATCHES "i686") + set(ISPC_ARCH x86) +elseif(LLVM_ARCH MATCHES "x86_64") + set(ISPC_ARCH "x86-64") +elseif(LLVM_ARCH MATCHES "armv7") + # ISPC doesn't support armv7 windows + set(ISPC_ARCH unknown) +else() + set(ISPC_ARCH ${LLVM_ARCH}) +endif() diff --git a/cmake/Toolchain-mingw-64bit.cmake b/cmake/Toolchain-mingw-64bit.cmake index 73dab973463..9248a2a7896 100644 --- a/cmake/Toolchain-mingw-64bit.cmake +++ b/cmake/Toolchain-mingw-64bit.cmake @@ -21,3 +21,5 @@ SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32 /usr/x86_64-w64-mingw32/lib /us set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ALWAYS) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +set(ISPC_ARCH "x86-64") diff --git a/cmake/Toolchain-mingw.cmake b/cmake/Toolchain-mingw.cmake index 47e35d26d4e..1d464ea6924 100644 --- a/cmake/Toolchain-mingw.cmake +++ b/cmake/Toolchain-mingw.cmake @@ -21,3 +21,5 @@ SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32 /usr/i686-w64-mingw32/lib /usr/li set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ALWAYS) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +set(ISPC_ARCH "x86") diff --git a/lib/graphics_engine/CMakeLists.txt b/lib/graphics_engine/CMakeLists.txt index 68aec21756c..63bb570e425 100644 --- a/lib/graphics_engine/CMakeLists.txt +++ b/lib/graphics_engine/CMakeLists.txt @@ -105,24 +105,56 @@ if(NOT APPLE OR DLOPEN_MOLTENVK) endif() option(BC7_ISPC "Enable BC7 (BPTC) support (requires ispc and cmake >= 3.19)" OFF) -if(BC7_ISPC) +if(BC7_ISPC AND NOT ISPC_ARCH MATCHES "unknown") add_definitions(-DBC7_ISPC) enable_language(ISPC) set(CMAKE_ISPC_FLAGS "${CMAKE_ISPC_FLAGS} --opt=fast-math --opt=disable-assertions --pic") + if(ISPC_ARCH) + set(CMAKE_ISPC_FLAGS "${CMAKE_ISPC_FLAGS} --arch=${ISPC_ARCH}") + endif() + if(WIN32) + set(CMAKE_ISPC_FLAGS "${CMAKE_ISPC_FLAGS} --target-os=windows") + elseif(IOS) + set(CMAKE_ISPC_FLAGS "${CMAKE_ISPC_FLAGS} --target-os=ios") + elseif(APPLE) + set(CMAKE_ISPC_FLAGS "${CMAKE_ISPC_FLAGS} --target-os=macos") + else() + set(CMAKE_ISPC_FLAGS "${CMAKE_ISPC_FLAGS} --target-os=linux") + endif() set(GE_SOURCES ${GE_SOURCES} src/bc7e.ispc ) + if (MINGW AND NOT ISPC_ARCH MATCHES "aarch64") + enable_language(ASM) + set(GE_SOURCES + ${GE_SOURCES} + src/libchkstk.S) + if(LLVM_PREFIX) + set_source_files_properties(src/libchkstk.S PROPERTIES COMPILE_FLAGS "-DCHKSTK") + else() + set_source_files_properties(src/libchkstk.S PROPERTIES COMPILE_FLAGS "-DCHKSTK -Wa,--no-pad-sections") + endif() + set_source_files_properties(src/libchkstk.S PROPERTIES LANGUAGE ASM) + endif() include_directories("${CMAKE_CURRENT_BINARY_DIR}") endif() add_library(graphics_engine STATIC ${GE_SOURCES}) if(BC7_ISPC) - set_property(TARGET graphics_engine PROPERTY ISPC_INSTRUCTION_SETS avx2) + if(ISPC_ARCH MATCHES "aarch64") + set_property(TARGET graphics_engine PROPERTY ISPC_INSTRUCTION_SETS neon) + else() + set_property(TARGET graphics_engine PROPERTY ISPC_INSTRUCTION_SETS avx2) + endif() endif() target_link_libraries(graphics_engine ${SQUISH_LIBRARY}) +if(BC7_ISPC AND LLVM_PREFIX AND NOT ISPC_ARCH MATCHES "unknown") + target_link_libraries(graphics_engine ntdllcrt) +endif() + if(ENABLE_LIBASTCENC) target_link_libraries(graphics_engine ${LIBASTCENC_LIBRARY}) endif() diff --git a/lib/graphics_engine/src/libchkstk.S b/lib/graphics_engine/src/libchkstk.S new file mode 100644 index 00000000000..7e91a19bfdd --- /dev/null +++ b/lib/graphics_engine/src/libchkstk.S @@ -0,0 +1,85 @@ +#if 0 +# Implementations of ___chkstk_ms (GCC) and __chkstk (MSVC). Unlike +# libgcc, no work happens if the stack is already committed. Execute +# this source with a shell to build libchkstk.a. +# This is free and unencumbered software released into the public domain. +set -ex +${CC:-cc} -c -DCHKSTK_MS -Wa,--no-pad-sections -o chkstk_ms.o $0 +${CC:-cc} -c -DCHKSTK -Wa,--no-pad-sections -o chkstk.o $0 +rm -f "${DESTDIR}libchkstk.a" +${AR:-ar} r "${DESTDIR}libchkstk.a" chkstk_ms.o chkstk.o +rm chkstk_ms.o chkstk.o +exit 0 +#endif + +#if __amd64 +// On x64, ___chkstk_ms and __chkstk have identical semantics. Unlike +// x86 __chkstk, neither adjusts the stack pointer. This implementation +// preserves all registers. +// +// The frame size is passed in rax, and this function ensures that +// enough of the stack is committed for the frame. It commits stack +// pages by writing to the guard page, one page at a time. +# if CHKSTK_MS + .globl ___chkstk_ms +___chkstk_ms: +# elif CHKSTK + .globl __chkstk +__chkstk: +# endif + push %rax + push %rcx + mov %gs:(0x10), %rcx // rcx = stack low address + neg %rax // rax = frame low address + add %rsp, %rax // " + jb 1f // frame low address overflow? + xor %eax, %eax // overflowed: frame low address = null +0: sub $0x1000, %rcx // extend stack into guard page + test %eax, (%rcx) // commit page (two instruction bytes) +1: cmp %rax, %rcx + ja 0b + pop %rcx + pop %rax + ret +#endif // __amd64 + +#if __i386 +# if CHKSTK_MS +// Behaves exactly like x64 ___chkstk_ms. + .globl ___chkstk_ms +___chkstk_ms: + push %eax + push %ecx + mov %fs:(0x08), %ecx // ecx = stack low address + neg %eax // eax = frame low address + add %esp, %eax // " + jb 1f // frame low address overflow? + xor %eax, %eax // overflowed: frame low address = null +0: sub $0x1000, %ecx // extend stack into guard page + test %eax, (%ecx) // commit page (two instruction bytes) +1: cmp %eax, %ecx + ja 0b + pop %ecx + pop %eax + ret +# elif CHKSTK +// On x86, __chkstk allocates the new stack frame. This implementation +// clobbers eax. MSVC only seems to care about ebp and ecx (this). + .globl __chkstk +__chkstk: + push %ecx // preserve ecx + mov %fs:(0x08), %ecx // ecx = stack low address + neg %eax // eax = frame low address + lea 8(%esp,%eax), %eax // " + cmp %esp, %eax // frame low address overflow? + jb 1f // " + xor %eax, %eax // overflowed: frame low address = null +0: sub $0x1000, %ecx // extend stack into guard page + test %eax, (%ecx) // commit page (two instruction bytes) +1: cmp %eax, %ecx + ja 0b + pop %ecx // restore ecx + xchg %eax, %esp // allocate frame + jmp *(%eax) // return +# endif +#endif // __i386 diff --git a/tools/build-cross-ispc.sh b/tools/build-cross-ispc.sh new file mode 100755 index 00000000000..49e522b177f --- /dev/null +++ b/tools/build-cross-ispc.sh @@ -0,0 +1,73 @@ +#!/bin/sh +# Tested in Ubuntu Server 24.04.2 LTS + +patch_file=$(mktemp) +cat << 'EOF' > "$patch_file" +diff --git a/CMakeLists.txt b/CMakeLists.txt +index af9769a..3279caf 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -131,9 +131,7 @@ if (ISPC_CROSS) + message(STATUS "Using iOS SDK path ${ISPC_IOS_SDK_PATH}") + endif() + else() +- set(ISPC_WINDOWS_TARGET OFF) + set(ISPC_PS_TARGET OFF) +- set(ISPC_IOS_TARGET OFF) + if (ISPC_MACOS_TARGET AND NOT ISPC_MACOS_SDK_PATH) + message (FATAL_ERROR "Set ISPC_MACOS_SDK_PATH variable for cross compilation to MacOS e.g. /iusers/MacOSX10.14.sdk") + endif() +diff --git a/builtins/builtins-c-cpu.cpp b/builtins/builtins-c-cpu.cpp +index 140419c..65b4f8e 100644 +--- a/builtins/builtins-c-cpu.cpp ++++ b/builtins/builtins-c-cpu.cpp +@@ -39,11 +39,11 @@ + // In unistd.h we need the definition of sysconf and _SC_NPROCESSORS_ONLN used as its arguments. + // We should include unistd.h, but it doesn't really work well for cross compilation, as + // requires us to carry around unistd.h, which is not available on Windows out of the box. +-#include ++//#include + + // Just for the reference: these lines are eventually included from unistd.h +-// #define _SC_NPROCESSORS_ONLN 58 +-// long sysconf(int); ++ #define _SC_NPROCESSORS_ONLN 58 ++ long sysconf(int); + #endif // !_MSC_VER + + #endif // !WASM +diff --git a/cmake/GenerateBuiltins.cmake b/cmake/GenerateBuiltins.cmake +index f403b16..56961d6 100644 +--- a/cmake/GenerateBuiltins.cmake ++++ b/cmake/GenerateBuiltins.cmake +@@ -253,6 +253,10 @@ function (get_target_flags os arch out) + if (${os} STREQUAL "macos") + # -isystem/iusers/MacOSX10.14.sdk.tar/MacOSX10.14.sdk/usr/include + set(include -isystem${ISPC_MACOS_SDK_PATH}/usr/include) ++ elseif (${os} STREQUAL "ios") ++ set(include -isystem${ISPC_IOS_SDK_PATH}/usr/include) ++ elseif (${os} STREQUAL "windows") ++ set(include -I/usr/include) + elseif(NOT ${debian_triple} STREQUAL "") + # When compiling on Linux, there are two way to support cross targets: + # - add "foreign" architecture to the set of supported architectures and install corresponding toolchain. +EOF + +apt-get update +apt install -y build-essential llvm cmake clang m4 bison flex libtbb-dev libclang-18-dev libclang-cpp-dev gcc-multilib g++-multilib +cd /opt +wget https://github.com/supertuxkart/dependencies/releases/download/cctools/cctools-14.1.tar.xz +tar xf cctools-14.1.tar.xz +rm cctools-14.1.tar.xz +cd +git clone --branch v1.26.0 --depth=1 https://github.com/ispc/ispc +cd ispc +patch -p1 < "$patch_file" +rm "$patch_file" +mkdir build +cd build +cmake .. -DCMAKE_INSTALL_PREFIX=/opt/ispc -DISPC_CROSS=ON -DISPC_MACOS_TARGET=ON -DISPC_MACOS_SDK_PATH=/opt/cctools/sdk/MacOSX13.0.sdk -DISPC_IOS_SDK_PATH=/opt/cctools/sdk/iPhoneOS16.1.sdk -DISPC_INCLUDE_TESTS=OFF -DISPC_INCLUDE_EXAMPLES=OFF +make -j18 +make install +cd /opt +tar -cJvf /ispc-cross-1.26.0.tar.xz ispc From db16a190c92f8d02bbaa288c20b234df56ec02c8 Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 17 Jun 2025 07:00:11 +0200 Subject: [PATCH 792/830] Update path for android debug symbols --- tools/android_builder.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/android_builder.sh b/tools/android_builder.sh index f7846c1701c..128c3148515 100755 --- a/tools/android_builder.sh +++ b/tools/android_builder.sh @@ -193,9 +193,11 @@ cp ./android/build/outputs/apk/release/android-release.apk \ cp ./android/build/outputs/bundle/release/android-release.aab \ ./android-output/SuperTuxKart-$PROJECT_VERSION.aab -for arch in $(ls ./android/build/intermediates/merged_native_libs/release/out/lib); do - cp ./android/build/intermediates/merged_native_libs/release/out/lib/$arch/libmain.so \ +SYMBOLS_PATH="./android/build/intermediates/merged_native_libs/release/mergeReleaseNativeLibs/out/lib" + +for arch in $(ls "$SYMBOLS_PATH"); do + cp "$SYMBOLS_PATH/$arch/libmain.so" \ ./android-output/SuperTuxKart-$PROJECT_VERSION-$arch-libmain.so - cp ./android/build/intermediates/merged_native_libs/release/out/lib/$arch/libSDL2.so \ + cp "$SYMBOLS_PATH/$arch/libSDL2.so" \ ./android-output/SuperTuxKart-$PROJECT_VERSION-$arch-libSDL2.so done From e6d4695633d333f59f8a4fa12a0bec92e8abc4b6 Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 17 Jun 2025 22:15:24 +0200 Subject: [PATCH 793/830] Fix for kart selection screen on Android TV --- src/states_screens/kart_selection.cpp | 54 ++++++++++++++++++--------- src/states_screens/kart_selection.hpp | 1 + 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index ead587304e0..a18961060cc 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -369,6 +369,16 @@ void KartSelectionScreen::beforeAddingWidget() // ---------------------------------------------------------------------------- +void KartSelectionScreen::configureChooseKarts(bool enable) +{ + // Only allow keyboard and gamepad to choose kart without continue button in + // multitouch GUI, so mouse (touch) clicking can be used as previewing karts + getWidget("karts")->setEventCallbackActive(Input::IT_MOUSEBUTTON, + enable ? !useContinueButton() : true); +} // configureChooseKarts + +// ---------------------------------------------------------------------------- + void KartSelectionScreen::init() { #ifndef SERVER_ONLY @@ -409,9 +419,9 @@ void KartSelectionScreen::init() m_search_box->clearListeners(); m_search_box->addListener(this); + configureChooseKarts(true); DynamicRibbonWidget* w = getWidget("karts"); assert( w != NULL ); - KartHoverListener* karthoverListener = new KartHoverListener(this); w->registerHoverListener(karthoverListener); @@ -1152,39 +1162,47 @@ void KartSelectionScreen::eventCallback(Widget* widget, handleKartListFocus(); } + else if (name == "favorite") + { + bool state = getWidget("favorite")->getState(); + getWidget("continue")->setVisible(!state); + configureChooseKarts(!state); + } else if (name == "karts") { DynamicRibbonWidget* w = getWidget("karts"); assert(w != NULL); const std::string selection = w->getSelectionIDString(player_id); - if (getWidget("favorite")->getState() && player_id == PLAYER_ID_GAME_MASTER && !m_game_master_confirmed && - selection != RANDOM_KART_ID && !selection.empty()) + !selection.empty()) { - // Locked karts can't be set as favorites - if (StringUtils::startsWith(selection, ID_LOCKED)) - { - unlock_manager->playLockSound(); - } - else + if (selection != RANDOM_KART_ID) { - const KartProperties *kp = kart_properties_manager->getKart(selection); - - if (PlayerManager::getCurrentPlayer()->isFavoriteKart(kp->getIdent())) + // Locked karts can't be set as favorites + if (StringUtils::startsWith(selection, ID_LOCKED)) { - PlayerManager::getCurrentPlayer()->removeFavoriteKart(kp->getIdent()); + unlock_manager->playLockSound(); } else { - PlayerManager::getCurrentPlayer()->addFavoriteKart(kp->getIdent()); + const KartProperties *kp = kart_properties_manager->getKart(selection); + + if (PlayerManager::getCurrentPlayer()->isFavoriteKart(kp->getIdent())) + { + PlayerManager::getCurrentPlayer()->removeFavoriteKart(kp->getIdent()); + } + else + { + PlayerManager::getCurrentPlayer()->addFavoriteKart(kp->getIdent()); + } + setKartsFromCurrentGroup(); + + handleKartListFocus(); } - setKartsFromCurrentGroup(); - - handleKartListFocus(); } } - else if (m_kart_widgets.size() > unsigned(player_id) && !useContinueButton()) + else if (m_kart_widgets.size() > unsigned(player_id)) playerConfirm(player_id); } else if (name == "kart_class" && !m_game_master_confirmed) diff --git a/src/states_screens/kart_selection.hpp b/src/states_screens/kart_selection.hpp index e6471995af8..c93e49cf84e 100644 --- a/src/states_screens/kart_selection.hpp +++ b/src/states_screens/kart_selection.hpp @@ -139,6 +139,7 @@ class KartSelectionScreen : public GUIEngine::Screen, PtrVector getUsableKarts( const std::string& selected_kart_group); bool useContinueButton() const; + void configureChooseKarts(bool enable); public: /** Returns the current instance */ static KartSelectionScreen* getRunningInstance(); From 1aa74045fc889169c1673ec1f098efd6e8da57c7 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 18 Jun 2025 00:51:11 +0400 Subject: [PATCH 794/830] Get rid of some warnings --- src/addons/news_manager.cpp | 78 +++++++-------- src/addons/news_manager.hpp | 3 + src/graphics/sp/sp_base.cpp | 2 +- src/guiengine/widgets/CGUIEditBox.cpp | 2 +- src/guiengine/widgets/CGUISTKListBox.cpp | 4 +- src/modes/free_for_all.cpp | 2 +- src/modes/linear_world.cpp | 1 - src/network/protocols/command_manager.cpp | 4 +- src/states_screens/easter_egg_screen.cpp | 2 +- src/states_screens/kart_selection.cpp | 2 +- src/utils/utf8/checked.h | 111 +++++++++++----------- src/utils/utf8/unchecked.h | 9 +- 12 files changed, 110 insertions(+), 110 deletions(-) diff --git a/src/addons/news_manager.cpp b/src/addons/news_manager.cpp index 2fd6fd644dd..ac0fbfcc1a9 100644 --- a/src/addons/news_manager.cpp +++ b/src/addons/news_manager.cpp @@ -398,6 +398,24 @@ void NewsManager::addNewsMessage(NewsType type, const core::stringw &s) m_news[type].unlock(); } // addNewsMessage // ---------------------------------------------------------------------------- + +std::optional NewsManager::getCurrentNewsElement(NewsType type) +{ + m_news[type].lock(); + + std::optional res; + + if (m_current_news_ptr[type] >= 0 + && m_current_news_ptr[type] < (int)m_news[type].getData().size()) + { + res = m_news[type].getData()[m_current_news_ptr[type]]; + } + m_news[type].unlock(); + + return res; +} // getCurrentNewsElement +// ---------------------------------------------------------------------------- + /** Returns the message pointed by the current ptr */ const core::stringw NewsManager::getCurrentNewsMessage(NewsType type) @@ -405,73 +423,45 @@ const core::stringw NewsManager::getCurrentNewsMessage(NewsType type) // Only display error message in case of a problem. if (m_error_message.getAtomic().size()>0) return _(m_error_message.getAtomic().c_str()); - - core::stringw message = L""; - - m_news[type].lock(); - if (m_current_news_ptr[type] >= 0 - && m_current_news_ptr[type] < m_news[type].getData().size()) - { - message = m_news[type].getData()[m_current_news_ptr[type]].getNews(); - } - m_news[type].unlock(); + auto element = getCurrentNewsElement(type); + if (element.has_value()) + return element->getNews(); - return message; + return L""; } // getCurrentNewsMessage // ---------------------------------------------------------------------------- /** Returns the date of the news pointed by the current ptr */ const std::string NewsManager::getCurrentNewsDate(NewsType type) { - std::string date = ""; - - m_news[type].lock(); - - if (m_current_news_ptr[type] >= 0 - && m_current_news_ptr[type] < m_news[type].getData().size()) - { - date = m_news[type].getData()[m_current_news_ptr[type]].getDate(); - } - m_news[type].unlock(); + auto element = getCurrentNewsElement(type); + if (element.has_value()) + return element->getDate(); - return date; + return ""; } // getCurrentNewsMessage // ---------------------------------------------------------------------------- /** Returns the date of the news pointed by the current ptr */ const std::string NewsManager::getCurrentNewsLink(NewsType type) { - std::string link = ""; - - m_news[type].lock(); - - if (m_current_news_ptr[type] >= 0 - && m_current_news_ptr[type] < m_news[type].getData().size()) - { - link = m_news[type].getData()[m_current_news_ptr[type]].getLink(); - } - m_news[type].unlock(); + auto element = getCurrentNewsElement(type); + if (element.has_value()) + return element->getLink(); - return link; + return ""; } // getCurrentNewsMessage // ---------------------------------------------------------------------------- /** Returns the importance of the message pointed by the current ptr */ const bool NewsManager::isCurrentNewsImportant(NewsType type) { - bool importance = false; - - m_news[type].lock(); - - if (m_current_news_ptr[type] >= 0 - && m_current_news_ptr[type] < m_news[type].getData().size()) - { - importance = m_news[type].getData()[m_current_news_ptr[type]].isImportant(); - } - m_news[type].unlock(); + auto element = getCurrentNewsElement(type); + if (element.has_value()) + return element->isImportant(); - return importance; + return false; } // isCurrentNewsImportant // ---------------------------------------------------------------------------- diff --git a/src/addons/news_manager.hpp b/src/addons/news_manager.hpp index 5ee9571ba1d..5e37c79c9c9 100644 --- a/src/addons/news_manager.hpp +++ b/src/addons/news_manager.hpp @@ -30,6 +30,7 @@ using namespace irr; #include "utils/can_be_deleted.hpp" #include "utils/synchronised.hpp" +#include class XMLNode; @@ -135,6 +136,8 @@ class NewsManager : public CanBeDeleted NewsManager(); ~NewsManager(); + std::optional getCurrentNewsElement(NewsType type); + public: /** Singleton: if necessary create and get the news managers */ static NewsManager* get() diff --git a/src/graphics/sp/sp_base.cpp b/src/graphics/sp/sp_base.cpp index 754ed190de2..10444380d00 100644 --- a/src/graphics/sp/sp_base.cpp +++ b/src/graphics/sp/sp_base.cpp @@ -451,7 +451,7 @@ void init() int skinning_tbo_limit; glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE_ARB, &skinning_tbo_limit); - g_skinning_use_tbo = skinning_tbo_limit >= STKConfig::get()->m_max_skinning_bones << 6; + g_skinning_use_tbo = skinning_tbo_limit >= (int)(STKConfig::get()->m_max_skinning_bones << 6); } else { diff --git a/src/guiengine/widgets/CGUIEditBox.cpp b/src/guiengine/widgets/CGUIEditBox.cpp index 865997f24e1..aae78f6dde6 100644 --- a/src/guiengine/widgets/CGUIEditBox.cpp +++ b/src/guiengine/widgets/CGUIEditBox.cpp @@ -1093,7 +1093,7 @@ void CGUIEditBox::setMax(u32 max) { m_max_chars = max; if (m_max_chars != 0 && m_edit_text.size() > m_max_chars) - m_edit_text.substr(0, m_max_chars); + m_edit_text = m_edit_text.substr(0, m_max_chars); } diff --git a/src/guiengine/widgets/CGUISTKListBox.cpp b/src/guiengine/widgets/CGUISTKListBox.cpp index 2b197aa352f..fff17a4ab4c 100644 --- a/src/guiengine/widgets/CGUISTKListBox.cpp +++ b/src/guiengine/widgets/CGUISTKListBox.cpp @@ -467,9 +467,9 @@ void CGUISTKListBox::selectNew(s32 ypos, bool onlyHover) void CGUISTKListBox::updateAbsolutePosition() { IGUIElement::updateAbsolutePosition(); - for (int i = 0; i < Items.size(); i++) + for (size_t i = 0; i < Items.size(); i++) { - for (int j = 0; j < Items[i].m_contents.size(); j++) + for (size_t j = 0; j < Items[i].m_contents.size(); j++) { Items[i].m_contents[j].m_glyph_layouts.clear(); } diff --git a/src/modes/free_for_all.cpp b/src/modes/free_for_all.cpp index 3869d2407b4..b5ed87be4ef 100644 --- a/src/modes/free_for_all.cpp +++ b/src/modes/free_for_all.cpp @@ -239,7 +239,7 @@ std::pair FreeForAll::getSpeedometerDigit( // Fade from green to red std::vector sorted_scores; - for (int i = 0; i < m_scores.size(); i++) + for (int i = 0; i < (int)m_scores.size(); i++) { if (!getKart(i)->isEliminated()) { diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index 5aca21d7364..44935330ff1 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -911,7 +911,6 @@ void LinearWorld::updateRacePosition() setKartPosition(i, kart->getPosition()); continue; } - KartInfo& kart_info = m_kart_info[i]; int p = 1 ; diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 628481a0a9f..29df04239a3 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -3796,7 +3796,6 @@ void CommandManager::process_net(Context& context) return; } - auto enet_peer = player_peer->getENetPeer(); std::string decorated_name = getLobby()->encodeProfileNameForPeer( player_peer->getMainProfile(), acting_peer.get()); @@ -3823,8 +3822,7 @@ void CommandManager::process_everynet(Context& context) // continue; if (!p->hasPlayerProfiles()) continue; - - auto enet_peer = p->getENetPeer(); + std::vector overall; overall.push_back(p->getAveragePing()); overall.push_back(p->getPacketLoss()); diff --git a/src/states_screens/easter_egg_screen.cpp b/src/states_screens/easter_egg_screen.cpp index 366c1cbf061..df17beb97a3 100644 --- a/src/states_screens/easter_egg_screen.cpp +++ b/src/states_screens/easter_egg_screen.cpp @@ -263,7 +263,7 @@ void EasterEggScreen::buildTrackList() } tracks.insertionSort(); - for (int n=0; n - class iterator : public std::iterator { - octet_iterator it; - octet_iterator range_start; - octet_iterator range_end; - public: - iterator () {}; - explicit iterator (const octet_iterator& octet_it, - const octet_iterator& range_start, - const octet_iterator& range_end) : - it(octet_it), range_start(range_start), range_end(range_end) - { - if (it < range_start || it > range_end) - throw std::out_of_range("Invalid utf-8 iterator position"); - } - // the default "big three" are OK - octet_iterator base () const { return it; } - uint32_t operator * () const - { - octet_iterator temp = it; - return next(temp, range_end); - } - bool operator == (const iterator& rhs) const - { - if (range_start != rhs.range_start || range_end != rhs.range_end) - throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); - return (it == rhs.it); - } - bool operator != (const iterator& rhs) const - { - return !(operator == (rhs)); - } - iterator& operator ++ () - { - next(it, range_end); - return *this; - } - iterator operator ++ (int) - { - iterator temp = *this; - next(it, range_end); - return temp; - } - iterator& operator -- () - { - prior(it, range_start); - return *this; - } - iterator operator -- (int) - { - iterator temp = *this; - prior(it, range_start); - return temp; - } + class iterator { + using iterator_category = std::bidirectional_iterator_tag; + using value_type = uint32_t; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + octet_iterator it; + octet_iterator range_start; + octet_iterator range_end; + public: + iterator () {}; + explicit iterator (const octet_iterator& octet_it, + const octet_iterator& range_start, + const octet_iterator& range_end) : + it(octet_it), range_start(range_start), range_end(range_end) + { + if (it < range_start || it > range_end) + throw std::out_of_range("Invalid utf-8 iterator position"); + } + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return next(temp, range_end); + } + bool operator == (const iterator& rhs) const + { + if (range_start != rhs.range_start || range_end != rhs.range_end) + throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + next(it, range_end); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + next(it, range_end); + return temp; + } + iterator& operator -- () + { + prior(it, range_start); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + prior(it, range_start); + return temp; + } }; // class iterator } // namespace utf8 diff --git a/src/utils/utf8/unchecked.h b/src/utils/utf8/unchecked.h index dcc57a7b0e8..073aff1f13d 100644 --- a/src/utils/utf8/unchecked.h +++ b/src/utils/utf8/unchecked.h @@ -222,7 +222,12 @@ namespace utf8 // The iterator class template - class iterator : public std::iterator { + class iterator { + using iterator_category = std::bidirectional_iterator_tag; + using value_type = uint32_t; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; octet_iterator it; public: iterator () {}; @@ -264,7 +269,7 @@ namespace utf8 prior(it); return temp; } - }; // class iterator + }; // class iterator } // namespace utf8::unchecked } // namespace utf8 From e43acd5bd375265165498131ce886027b4637fea Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 17 Jun 2025 22:53:33 +0200 Subject: [PATCH 795/830] Some tweaks in android manifest --- android/AndroidManifest.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index dab237cb3a0..6554a0b5239 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -4,6 +4,8 @@ From ec0202a76f93ae5a849e3a8a3b4eaffb5923b3db Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 17 Jun 2025 23:19:38 +0200 Subject: [PATCH 796/830] Don't link against ntdllcrt This caused issues with snprintf, leading to an invalid config.xml file. --- lib/graphics_engine/CMakeLists.txt | 7 +++---- lib/graphics_engine/src/ge_compressor_bptc_bc7.cpp | 12 ++++++++++++ lib/graphics_engine/src/libchkstk.S | 2 ++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/graphics_engine/CMakeLists.txt b/lib/graphics_engine/CMakeLists.txt index 63bb570e425..8c7a6338b37 100644 --- a/lib/graphics_engine/CMakeLists.txt +++ b/lib/graphics_engine/CMakeLists.txt @@ -132,6 +132,9 @@ if(BC7_ISPC AND NOT ISPC_ARCH MATCHES "unknown") src/libchkstk.S) if(LLVM_PREFIX) set_source_files_properties(src/libchkstk.S PROPERTIES COMPILE_FLAGS "-DCHKSTK") + if(ISPC_ARCH MATCHES "x86" OR ISPC_ARCH MATCHES "x86-64") + set_source_files_properties(src/ge_compressor_bptc_bc7.cpp PROPERTIES COMPILE_FLAGS "-DLLVM_MINGW_FLTUSED") + endif() else() set_source_files_properties(src/libchkstk.S PROPERTIES COMPILE_FLAGS "-DCHKSTK -Wa,--no-pad-sections") endif() @@ -151,10 +154,6 @@ endif() target_link_libraries(graphics_engine ${SQUISH_LIBRARY}) -if(BC7_ISPC AND LLVM_PREFIX AND NOT ISPC_ARCH MATCHES "unknown") - target_link_libraries(graphics_engine ntdllcrt) -endif() - if(ENABLE_LIBASTCENC) target_link_libraries(graphics_engine ${LIBASTCENC_LIBRARY}) endif() diff --git a/lib/graphics_engine/src/ge_compressor_bptc_bc7.cpp b/lib/graphics_engine/src/ge_compressor_bptc_bc7.cpp index 4296bb9de47..d2bd78edecc 100644 --- a/lib/graphics_engine/src/ge_compressor_bptc_bc7.cpp +++ b/lib/graphics_engine/src/ge_compressor_bptc_bc7.cpp @@ -1,3 +1,15 @@ +#ifdef LLVM_MINGW_FLTUSED +// From https://stackoverflow.com/questions/1583196/building-visual-c-app-that-doesnt-use-crt-functions-still-references-some +#ifdef __cplusplus +extern "C" { +#endif +// It should be a single underscore since the double one is the mangled name +int _fltused = 0; +#ifdef __cplusplus +} +#endif +#endif + #include "ge_compressor_bptc_bc7.hpp" #include "ge_main.hpp" #include "ge_vulkan_features.hpp" diff --git a/lib/graphics_engine/src/libchkstk.S b/lib/graphics_engine/src/libchkstk.S index 7e91a19bfdd..2aa33f5139b 100644 --- a/lib/graphics_engine/src/libchkstk.S +++ b/lib/graphics_engine/src/libchkstk.S @@ -1,3 +1,5 @@ +// From https://github.com/skeeto/w64devkit/blob/master/src/libchkstk.S + #if 0 # Implementations of ___chkstk_ms (GCC) and __chkstk (MSVC). Unlike # libgcc, no work happens if the stack is already committed. Execute From b528010f24fbedc4485c64e3c5df1056670b9020 Mon Sep 17 00:00:00 2001 From: Deve Date: Tue, 17 Jun 2025 23:40:58 +0200 Subject: [PATCH 797/830] Fix uninitialized variable in PlayerKartWidget --- src/guiengine/widgets/player_kart_widget.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/guiengine/widgets/player_kart_widget.cpp b/src/guiengine/widgets/player_kart_widget.cpp index 55530d30140..2d61ebde0b6 100644 --- a/src/guiengine/widgets/player_kart_widget.cpp +++ b/src/guiengine/widgets/player_kart_widget.cpp @@ -49,6 +49,7 @@ PlayerKartWidget::PlayerKartWidget(KartSelectionScreen* parent, #endif m_ready_text = NULL; m_parent_screen = parent; + m_left_arrow_width = 0; m_associated_player = associated_player; x_speed = y_speed = w_speed = h_speed = 1.0f; @@ -352,18 +353,18 @@ void PlayerKartWidget::add() ->m_kart_widgets.contains(this)); if (m_associated_player) // if player is local { +#ifdef DEBUG bool mineInList = false; for (unsigned int p=0; pactivePlayerCount(); p++) { -#ifdef DEBUG assert(StateManager::get()->getActivePlayer(p)->ok()); -#endif if (StateManager::get()->getActivePlayer(p) == m_associated_player) { mineInList = true; } } assert(mineInList); +#endif } // the first player will have an ID of its own to allow for keyboard From 8835034142ec7b7fd096dd6f42df470cdcfa6c4f Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 18 Jun 2025 01:49:29 +0400 Subject: [PATCH 798/830] Fix my own memory leak First spotted in 57406988287f66a0edfdc4d95e4876d6bda71f0b --- src/utils/time.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/time.cpp b/src/utils/time.cpp index 001a6289a15..ce25dee3564 100644 --- a/src/utils/time.cpp +++ b/src/utils/time.cpp @@ -99,6 +99,7 @@ std::string StkTime::toString(int year, int month, int day) char s[64]; strftime(s, 64, date_format.c_str(), t); + delete t; return s; } // toString(3) From ad25726263556b50bf56fcb52884bc700b6259de Mon Sep 17 00:00:00 2001 From: martin Date: Fri, 20 Jun 2025 12:57:48 +0200 Subject: [PATCH 799/830] Fix a couple of clang-19 warnings (#5461) Remove unused functions in lib/irrlicht/source/Irrlicht/CBlit.h Handle unused debug variables --- lib/irrlicht/source/Irrlicht/CBlit.h | 461 ------------------- src/graphics/sp/sp_shader_manager.cpp | 2 +- src/guiengine/screen.cpp | 3 +- src/guiengine/widgets/player_kart_widget.cpp | 3 +- src/karts/controller/test_ai.cpp | 9 +- src/modes/linear_world.cpp | 1 - src/online/http_request.hpp | 4 +- src/race/race_manager.hpp | 4 +- src/states_screens/kart_selection.cpp | 2 + src/states_screens/race_result_gui.cpp | 2 + src/tracks/arena_graph.cpp | 6 +- src/utils/translation.cpp | 9 +- 12 files changed, 29 insertions(+), 477 deletions(-) diff --git a/lib/irrlicht/source/Irrlicht/CBlit.h b/lib/irrlicht/source/Irrlicht/CBlit.h index a8572e929bd..e782e7a0d7e 100644 --- a/lib/irrlicht/source/Irrlicht/CBlit.h +++ b/lib/irrlicht/source/Irrlicht/CBlit.h @@ -65,96 +65,6 @@ inline u32 GetClipCode( const AbsRectangle &r, const core::position2d &p ) return code; } - -/*! - Cohen Sutherland clipping - @return: 1 if valid -*/ - -static int ClipLine(const AbsRectangle &clipping, - core::position2d &p0, - core::position2d &p1, - const core::position2d& p0_in, - const core::position2d& p1_in) -{ - u32 code0; - u32 code1; - u32 code; - - p0 = p0_in; - p1 = p1_in; - - code0 = GetClipCode( clipping, p0 ); - code1 = GetClipCode( clipping, p1 ); - - // trivial accepted - while ( code0 | code1 ) - { - s32 x=0; - s32 y=0; - - // trivial reject - if ( code0 & code1 ) - return 0; - - if ( code0 ) - { - // clip first point - code = code0; - } - else - { - // clip last point - code = code1; - } - - if ( (code & CLIPCODE_BOTTOM) == CLIPCODE_BOTTOM ) - { - // clip bottom viewport - y = clipping.y1; - x = p0.X + ( p1.X - p0.X ) * ( y - p0.Y ) / ( p1.Y - p0.Y ); - } - else - if ( (code & CLIPCODE_TOP) == CLIPCODE_TOP ) - { - // clip to viewport - y = clipping.y0; - x = p0.X + ( p1.X - p0.X ) * ( y - p0.Y ) / ( p1.Y - p0.Y ); - } - else - if ( (code & CLIPCODE_RIGHT) == CLIPCODE_RIGHT ) - { - // clip right viewport - x = clipping.x1; - y = p0.Y + ( p1.Y - p0.Y ) * ( x - p0.X ) / ( p1.X - p0.X ); - } - else - if ( (code & CLIPCODE_LEFT) == CLIPCODE_LEFT ) - { - // clip left viewport - x = clipping.x0; - y = p0.Y + ( p1.Y - p0.Y ) * ( x - p0.X ) / ( p1.X - p0.X ); - } - - if ( code == code0 ) - { - // modify first point - p0.X = x; - p0.Y = y; - code0 = GetClipCode( clipping, p0 ); - } - else - { - // modify second point - p1.X = x; - p1.Y = y; - code1 = GetClipCode( clipping, p1 ); - } - } - - return 1; -} - /* */ inline void GetClip(AbsRectangle &clipping, video::IImage * t) @@ -205,272 +115,6 @@ inline u32 PixelLerp32(const u32 source, const u32 value) return srcRB | srcXG; } - -/* -*/ -static void RenderLine32_Decal(video::IImage *t, - const core::position2d &p0, - const core::position2d &p1, - u32 argb ) -{ - s32 dx = p1.X - p0.X; - s32 dy = p1.Y - p0.Y; - - s32 c; - s32 m; - s32 d = 0; - s32 run; - - s32 xInc = 4; - s32 yInc = (s32) t->getPitch(); - - if ( dx < 0 ) - { - xInc = -xInc; - dx = -dx; - } - - if ( dy < 0 ) - { - yInc = -yInc; - dy = -dy; - } - - u32 *dst; - dst = (u32*) ( (u8*) t->lock() + ( p0.Y * t->getPitch() ) + ( p0.X << 2 ) ); - - if ( dy > dx ) - { - s32 tmp; - tmp = dx; - dx = dy; - dy = tmp; - tmp = xInc; - xInc = yInc; - yInc = tmp; - } - - c = dx << 1; - m = dy << 1; - - run = dx; - do - { - *dst = argb; - - dst = (u32*) ( (u8*) dst + xInc ); // x += xInc - d += m; - if ( d > dx ) - { - dst = (u32*) ( (u8*) dst + yInc ); // y += yInc - d -= c; - } - run -= 1; - } while (run>=0); - - t->unlock(); -} - - -/* -*/ -static void RenderLine32_Blend(video::IImage *t, - const core::position2d &p0, - const core::position2d &p1, - u32 argb, u32 alpha) -{ - s32 dx = p1.X - p0.X; - s32 dy = p1.Y - p0.Y; - - s32 c; - s32 m; - s32 d = 0; - s32 run; - - s32 xInc = 4; - s32 yInc = (s32) t->getPitch(); - - if ( dx < 0 ) - { - xInc = -xInc; - dx = -dx; - } - - if ( dy < 0 ) - { - yInc = -yInc; - dy = -dy; - } - - u32 *dst; - dst = (u32*) ( (u8*) t->lock() + ( p0.Y * t->getPitch() ) + ( p0.X << 2 ) ); - - if ( dy > dx ) - { - s32 tmp; - tmp = dx; - dx = dy; - dy = tmp; - tmp = xInc; - xInc = yInc; - yInc = tmp; - } - - c = dx << 1; - m = dy << 1; - - run = dx; - const u32 packA = packAlpha ( alpha ); - do - { - *dst = packA | PixelBlend32( *dst, argb, alpha ); - - dst = (u32*) ( (u8*) dst + xInc ); // x += xInc - d += m; - if ( d > dx ) - { - dst = (u32*) ( (u8*) dst + yInc ); // y += yInc - d -= c; - } - run -= 1; - } while (run>=0); - - t->unlock(); -} - -/* -*/ -static void RenderLine16_Decal(video::IImage *t, - const core::position2d &p0, - const core::position2d &p1, - u32 argb ) -{ - s32 dx = p1.X - p0.X; - s32 dy = p1.Y - p0.Y; - - s32 c; - s32 m; - s32 d = 0; - s32 run; - - s32 xInc = 2; - s32 yInc = (s32) t->getPitch(); - - if ( dx < 0 ) - { - xInc = -xInc; - dx = -dx; - } - - if ( dy < 0 ) - { - yInc = -yInc; - dy = -dy; - } - - u16 *dst; - dst = (u16*) ( (u8*) t->lock() + ( p0.Y * t->getPitch() ) + ( p0.X << 1 ) ); - - if ( dy > dx ) - { - s32 tmp; - tmp = dx; - dx = dy; - dy = tmp; - tmp = xInc; - xInc = yInc; - yInc = tmp; - } - - c = dx << 1; - m = dy << 1; - - run = dx; - do - { - *dst = (u16)argb; - - dst = (u16*) ( (u8*) dst + xInc ); // x += xInc - d += m; - if ( d > dx ) - { - dst = (u16*) ( (u8*) dst + yInc ); // y += yInc - d -= c; - } - run -= 1; - } while (run>=0); - - t->unlock(); -} - -/* -*/ -static void RenderLine16_Blend(video::IImage *t, - const core::position2d &p0, - const core::position2d &p1, - u16 argb, - u16 alpha) -{ - s32 dx = p1.X - p0.X; - s32 dy = p1.Y - p0.Y; - - s32 c; - s32 m; - s32 d = 0; - s32 run; - - s32 xInc = 2; - s32 yInc = (s32) t->getPitch(); - - if ( dx < 0 ) - { - xInc = -xInc; - dx = -dx; - } - - if ( dy < 0 ) - { - yInc = -yInc; - dy = -dy; - } - - u16 *dst; - dst = (u16*) ( (u8*) t->lock() + ( p0.Y * t->getPitch() ) + ( p0.X << 1 ) ); - - if ( dy > dx ) - { - s32 tmp; - tmp = dx; - dx = dy; - dy = tmp; - tmp = xInc; - xInc = yInc; - yInc = tmp; - } - - c = dx << 1; - m = dy << 1; - - run = dx; - const u16 packA = alpha ? 0x8000 : 0; - do - { - *dst = packA | PixelBlend16( *dst, argb, alpha ); - - dst = (u16*) ( (u8*) dst + xInc ); // x += xInc - d += m; - if ( d > dx ) - { - dst = (u16*) ( (u8*) dst + yInc ); // y += yInc - d -= c; - } - run -= 1; - } while (run>=0); - - t->unlock(); -} - - /*! */ static void executeBlit_TextureCopy_x_to_x( const SBlitJob * job ) @@ -1162,111 +806,6 @@ static s32 Blit(eBlitter operation, return 1; } -static s32 StretchBlit(eBlitter operation, - video::IImage* dest, const core::rect *destRect, - const core::rect *srcRect, video::IImage* const source, - u32 argb) -{ - tExecuteBlit blitter = getBlitter2( operation, dest, source ); - if ( 0 == blitter ) - { - return 0; - } - - SBlitJob job; - - // Clipping - setClip ( job.Source, srcRect, source, 1 ); - setClip ( job.Dest, destRect, dest, 0 ); - - job.width = job.Dest.x1-job.Dest.x0; - job.height = job.Dest.y1-job.Dest.y0; - - job.argb = argb; - - // use original dest size, despite any clipping - job.x_stretch = (float)destRect->getWidth() / (float)(job.Source.x1-job.Source.x0); - job.y_stretch = (float)destRect->getHeight() / (float)(job.Source.y1-job.Source.y0); - job.stretch = (job.x_stretch != 1.f) || (job.y_stretch != 1.f); - - if ( source ) - { - job.srcPitch = source->getPitch(); - job.srcPixelMul = source->getBytesPerPixel(); - job.src = (void*) ( (u8*) source->lock() + ( job.Source.y0 * job.srcPitch ) + ( job.Source.x0 * job.srcPixelMul ) ); - } - else - { - // use srcPitch for color operation on dest - job.srcPitch = job.width * dest->getBytesPerPixel(); - } - - job.dstPitch = dest->getPitch(); - job.dstPixelMul = dest->getBytesPerPixel(); - job.dst = (void*) ( (u8*) dest->lock() + ( job.Dest.y0 * job.dstPitch ) + ( job.Dest.x0 * job.dstPixelMul ) ); - - blitter( &job ); - - if ( source ) - source->unlock(); - - if ( dest ) - dest->unlock(); - - return 1; -} - - -// Methods for Software drivers -//! draws a rectangle -static void drawRectangle(video::IImage* img, const core::rect& rect, const video::SColor &color) -{ - Blit(color.getAlpha() == 0xFF ? BLITTER_COLOR : BLITTER_COLOR_ALPHA, - img, 0, &rect.UpperLeftCorner, 0, &rect, color.color); -} - - -//! draws a line from to with color -static void drawLine(video::IImage* img, const core::position2d& from, - const core::position2d& to, const video::SColor &color) -{ - AbsRectangle clip; - GetClip(clip, img); - - core::position2d p[2]; - if (ClipLine( clip, p[0], p[1], from, to)) - { - u32 alpha = extractAlpha(color.color); - - switch(img->getColorFormat()) - { - case video::ECF_A1R5G5B5: - if (alpha == 256) - { - RenderLine16_Decal(img, p[0], p[1], video::A8R8G8B8toA1R5G5B5(color.color)); - } - else - { - RenderLine16_Blend(img, p[0], p[1], video::A8R8G8B8toA1R5G5B5(color.color), alpha >> 3); - } - break; - case video::ECF_A8R8G8B8: - if (alpha == 256) - { - RenderLine32_Decal(img, p[0], p[1], color.color); - } - else - { - RenderLine32_Blend(img, p[0], p[1], color.color, alpha); - } - break; - default: - break; - } - } -} - - } #endif diff --git a/src/graphics/sp/sp_shader_manager.cpp b/src/graphics/sp/sp_shader_manager.cpp index 258a4182e22..07cf0c4bd87 100644 --- a/src/graphics/sp/sp_shader_manager.cpp +++ b/src/graphics/sp/sp_shader_manager.cpp @@ -387,7 +387,7 @@ std::shared_ptr SPShaderManager::buildSPShader(const ShaderInfo& si, std::shared_ptr sps; #ifndef SERVER_ONLY sps = std::make_shared(si.m_shader_name, - [this, pi, ua, skinned](SPShader* shader) + [pi, ua, skinned](SPShader* shader) { // First pass assert(!pi[0].m_vertex_shader.empty() || diff --git a/src/guiengine/screen.cpp b/src/guiengine/screen.cpp index 7bc5e414204..be33ba940e5 100644 --- a/src/guiengine/screen.cpp +++ b/src/guiengine/screen.cpp @@ -152,12 +152,13 @@ void Screen::loadFromFile() void Screen::unload() { assert(m_magic_number == 0xCAFEC001); +#ifndef NDEBUG Widget* w; for_in (w, m_widgets) { assert(w->m_magic_number == 0xCAFEC001); } - +#endif m_loaded = false; m_widgets.clearAndDeleteAll(); diff --git a/src/guiengine/widgets/player_kart_widget.cpp b/src/guiengine/widgets/player_kart_widget.cpp index 2d61ebde0b6..760bfea28e3 100644 --- a/src/guiengine/widgets/player_kart_widget.cpp +++ b/src/guiengine/widgets/player_kart_widget.cpp @@ -351,6 +351,7 @@ void PlayerKartWidget::add() assert(KartSelectionScreen::getRunningInstance() ->m_kart_widgets.contains(this)); +#ifdef DEBUG if (m_associated_player) // if player is local { #ifdef DEBUG @@ -366,7 +367,7 @@ void PlayerKartWidget::add() assert(mineInList); #endif } - +#endif // the first player will have an ID of its own to allow for keyboard // navigation despite this widget being added last if (m_irrlicht_widget_id != -1) diff --git a/src/karts/controller/test_ai.cpp b/src/karts/controller/test_ai.cpp index be53f0e6e85..c2c4104740d 100644 --- a/src/karts/controller/test_ai.cpp +++ b/src/karts/controller/test_ai.cpp @@ -1552,16 +1552,17 @@ void SkiddingAI::handleRaceStart() // smaller depending on the difficulty. m_start_delay = stk_config->time2Ticks( m_ai_properties->m_min_start_delay - + (float) rand() / RAND_MAX - * (m_ai_properties->m_max_start_delay - - m_ai_properties->m_min_start_delay) ); + + static_cast( + static_cast(rand()) / static_cast(RAND_MAX) + * (m_ai_properties->m_max_start_delay - + m_ai_properties->m_min_start_delay))); float false_start_probability = m_superpower == RaceManager::SUPERPOWER_NOLOK_BOSS ? 0.0f : m_ai_properties->m_false_start_probability; // Now check for a false start. If so, add 1 second penalty time. - if (rand() < RAND_MAX * false_start_probability) + if (static_cast(rand()) < static_cast(RAND_MAX) * false_start_probability) { m_start_delay+=stk_config->m_penalty_ticks; return; diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index ad770659630..f0b115f544b 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -900,7 +900,6 @@ void LinearWorld::updateRacePosition() setKartPosition(i, kart->getPosition()); continue; } - KartInfo& kart_info = m_kart_info[i]; int p = 1 ; diff --git a/src/online/http_request.hpp b/src/online/http_request.hpp index 42edb25df1c..efcebda8fcc 100644 --- a/src/online/http_request.hpp +++ b/src/online/http_request.hpp @@ -31,11 +31,13 @@ #include #include -#if defined(CURLOPT_XFERINFODATA) +#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR > 31) +// Use CURLOPT_XFERINFOFUNCTION (introduced in 7.32.0) #define PROGRESSDATA CURLOPT_XFERINFODATA #define PROGRESSFUNCTION CURLOPT_XFERINFOFUNCTION typedef curl_off_t progress_t; #else +// Use CURLOPT_PROGRESSFUNCTION (deprecated since 7.32.0) #define PROGRESSDATA CURLOPT_PROGRESSDATA #define PROGRESSFUNCTION CURLOPT_PROGRESSFUNCTION typedef double progress_t; diff --git a/src/race/race_manager.hpp b/src/race/race_manager.hpp index 58c7c85cca4..e93078ccc6a 100644 --- a/src/race/race_manager.hpp +++ b/src/race/race_manager.hpp @@ -350,8 +350,8 @@ class RaceManager int m_skipped_tracks_in_gp; /** Time target for GP, used in Lap Trial mode */ float m_gp_time_target; - /** Total laps from every track, used in Lap Trial mode */ - int m_gp_total_laps; + /** Total laps from every track, used in Lap Trial mode + int m_gp_total_laps;*/ void startNextRace(); // start a next race friend bool operator< (const KartStatus& left, const KartStatus& right) diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index a18961060cc..220a67a6d17 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -1514,6 +1514,7 @@ bool KartSelectionScreen::validateIdentChoices() m_kart_widgets[n].m_player_ident_spinner->markAsCorrect(); // verify internal consistency in debug mode +#ifndef NDEBUG if (m_multiplayer) { int spinner_value = m_kart_widgets[n].m_player_ident_spinner->getValue(); @@ -1522,6 +1523,7 @@ bool KartSelectionScreen::validateIdentChoices() assert(m_kart_widgets[n].getAssociatedPlayer()->getProfile() == PlayerManager::get()->getPlayer(spinner_value)); } +#endif } } diff --git a/src/states_screens/race_result_gui.cpp b/src/states_screens/race_result_gui.cpp index 8353b986a28..d0f08abd0fa 100644 --- a/src/states_screens/race_result_gui.cpp +++ b/src/states_screens/race_result_gui.cpp @@ -1294,7 +1294,9 @@ void RaceResultGUI::renderGlobal(float dt) break; case RR_INCREASE_POINTS: { +#ifndef NDEBUG WorldWithRank *wwr = dynamic_cast(World::getWorld()); +#endif assert(wwr); ri->m_current_displayed_points += dt * m_most_points / time_for_points; if (ri->m_current_displayed_points > ri->m_new_overall_points) diff --git a/src/tracks/arena_graph.cpp b/src/tracks/arena_graph.cpp index b64743a42f9..cc82ffd81ec 100644 --- a/src/tracks/arena_graph.cpp +++ b/src/tracks/arena_graph.cpp @@ -458,7 +458,11 @@ void ArenaGraph::unitTesting() #endif } // for j } // for i - + if (error_count > 0) + { + Log::error("ArenaGraph", + "Found %d errors when comparing Dijkstra to Floyd-Warshall", error_count); + } delete ag; } // unitTesting diff --git a/src/utils/translation.cpp b/src/utils/translation.cpp index 4c2b433b770..de7af7dab9f 100644 --- a/src/utils/translation.cpp +++ b/src/utils/translation.cpp @@ -96,7 +96,10 @@ constexpr bool isThaiCP(char32_t c) // ============================================================================ +#if TRANSLATE_VERBOSE const bool REMOVE_BOM = false; +#endif + /** The list of available languages; this is global so that it is cached (and remains even if the translations object is deleted and re-created) */ typedef std::vector LanguageList; @@ -620,10 +623,9 @@ irr::core::stringw Translations::w_gettext(const char* original, const char* con // print //for (int n=0;; n+=4) const irr::core::stringw wide = StringUtils::utf8ToWide(original_t); +#if TRANSLATE_VERBOSE const wchar_t* out_ptr = wide.c_str(); if (REMOVE_BOM) out_ptr++; - -#if TRANSLATE_VERBOSE std::wcout << L" translation : " << out_ptr << std::endl; #endif @@ -699,10 +701,9 @@ irr::core::stringw Translations::w_ngettext(const char* singular, const char* pl m_dictionary->translate_ctxt_plural(context, singular, plural, num)); const irr::core::stringw wide = StringUtils::utf8ToWide(res); +#if TRANSLATE_VERBOSE const wchar_t* out_ptr = wide.c_str(); if (REMOVE_BOM) out_ptr++; - -#if TRANSLATE_VERBOSE std::wcout << L" translation : " << out_ptr << std::endl; #endif From b28979606f65fa320dd3fa5ea97a1a07ce1a3710 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 21 Jun 2025 15:15:20 +0400 Subject: [PATCH 800/830] Shorten recording replay message --- src/network/protocols/server_lobby.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 45ba2bb086f..ba4ad9509dc 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2752,14 +2752,9 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, { std::string msg; if (getSettings()->hasConsentOnReplays()) - msg = "Recording ghost replays is enabled. " - "The crowned player can change that " - "using /replay 0 (to disable) or /replay 1 (to enable). " - "Do not race under this feature if you don't want to be recorded."; + msg = "Recording ghost replays is enabled."; else - msg = "Recording ghost replays is disabled. " - "The crowned player can change that " - "using /replay 0 (to disable) or /replay 1 (to enable). "; + msg = "Recording ghost replays is disabled."; Comm::sendStringToPeer(peer, msg); } getMessagesFromHost(peer, online_id); From abde14f7b8967b2167d3b55cafaac09dc6653abb Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 1 Jul 2025 23:57:41 +0400 Subject: [PATCH 801/830] Logs: don't make non-format string format, remove extra []s Not all, however. For inspiration, check https://github.com/BcfWor/stk-code/commit/8500b80af2d0e9b9dee8b1db47f6045e254ad37d --- src/addons/news_manager.cpp | 6 +-- src/graphics/irr_driver.cpp | 8 +-- src/graphics/shader.cpp | 2 +- src/graphics/shader.hpp | 4 +- src/graphics/shader_files_manager.cpp | 2 +- src/graphics/sp/sp_shader.cpp | 2 +- src/guiengine/event_handler.cpp | 8 +-- src/guiengine/widgets/player_kart_widget.cpp | 2 +- src/guiengine/widgets/spinner_widget.cpp | 4 +- src/input/input_manager.cpp | 4 +- src/io/file_manager.cpp | 50 +++++++++---------- src/io/xml_node.cpp | 32 ++++++------ src/items/flyable.cpp | 2 +- src/items/item_manager.cpp | 10 ++-- src/items/rubber_ball.cpp | 16 +++--- src/karts/kart_gfx.cpp | 2 +- src/karts/kart_properties.cpp | 10 ++-- src/karts/kart_properties_manager.cpp | 10 ++-- src/main_loop.cpp | 2 +- src/modes/cutscene_world.cpp | 8 +-- src/modes/demo_world.cpp | 10 ++-- src/modes/easter_egg_hunt.cpp | 4 +- src/modes/follow_the_leader.cpp | 6 +-- src/modes/linear_world.cpp | 30 +++++------ src/modes/overworld.cpp | 2 +- src/modes/profile_world.cpp | 4 +- src/modes/world.cpp | 6 +-- src/modes/world_with_rank.cpp | 2 +- src/network/protocol.cpp | 2 +- src/network/protocol_manager.cpp | 4 +- src/online/online_player_profile.cpp | 2 +- src/scriptengine/script_engine.cpp | 2 +- src/states_screens/kart_selection.cpp | 2 +- .../online/create_server_screen.cpp | 4 +- src/tracks/drive_graph.cpp | 2 +- src/tracks/track.cpp | 2 +- src/tracks/track_object.cpp | 2 +- src/utils/debug.cpp | 2 +- 38 files changed, 136 insertions(+), 136 deletions(-) diff --git a/src/addons/news_manager.cpp b/src/addons/news_manager.cpp index ac0fbfcc1a9..78f2397ca7f 100644 --- a/src/addons/news_manager.cpp +++ b/src/addons/news_manager.cpp @@ -183,10 +183,10 @@ void NewsManager::downloadNews() // if the language is changed in the menu! error_message = N_("Error downloading news: '%s'."); const char *const curl_error = download_req->getDownloadErrorMessage(); + Log::error("news", core::stringc(error_message).c_str(), curl_error); error_message = StringUtils::insertValues(error_message, curl_error); addons_manager->setErrorState(); setErrorMessage(error_message); - Log::error("news", core::stringc(error_message).c_str()); } // hadDownloadError } // hadDownloadError @@ -240,7 +240,7 @@ void NewsManager::checkRedirect(const XMLNode *xml) { if (UserConfigParams::logAddons()) { - Log::info("[Addons]", "Current addons server: '%s'\n [Addons] New addons server: '%s'", + Log::info("Addons", "Current addons server: '%s'\n [Addons] New addons server: '%s'", stk_config->m_server_addons.c_str(), new_addons_server.c_str()); } stk_config->m_server_addons = new_addons_server; @@ -252,7 +252,7 @@ void NewsManager::checkRedirect(const XMLNode *xml) { if (UserConfigParams::logAddons()) { - Log::info("[Addons]", "Current API server: '%s'\n [Addons] New API server: '%s'", + Log::info("Addons", "Current API server: '%s'\n [Addons] New API server: '%s'", stk_config->m_server_api.c_str(), new_api_server.c_str()); } stk_config->m_server_api = new_api_server; diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 2cfb1b12b5d..e223d9c4728 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -2354,16 +2354,16 @@ bool IrrDriver::OnEvent(const irr::SEvent &event) switch (event.LogEvent.Level) { case ELL_DEBUG: - Log::debug("[IrrDriver Logger]", "%s", event.LogEvent.Text); + Log::debug("IrrDriver Logger", "%s", event.LogEvent.Text); break; case ELL_INFORMATION: - Log::info("[IrrDriver Logger]", "%s", event.LogEvent.Text); + Log::info("IrrDriver Logger", "%s", event.LogEvent.Text); break; case ELL_WARNING: - Log::warn("[IrrDriver Logger]", "%s", event.LogEvent.Text); + Log::warn("IrrDriver Logger", "%s", event.LogEvent.Text); break; case ELL_ERROR: - Log::error("[IrrDriver Logger]", "%s", event.LogEvent.Text); + Log::error("IrrDriver Logger", "%s", event.LogEvent.Text); break; default: break; diff --git a/src/graphics/shader.cpp b/src/graphics/shader.cpp index 1a11f643f09..de5330a1cd3 100644 --- a/src/graphics/shader.cpp +++ b/src/graphics/shader.cpp @@ -56,7 +56,7 @@ int ShaderBase::loadTFBProgram(const std::string &shader_name, glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &info_log_length); char *error_message = new char[info_log_length]; glGetProgramInfoLog(m_program, info_log_length, NULL, error_message); - Log::error("ShaderBase", error_message); + Log::error("ShaderBase", "%s", error_message); delete[] error_message; } diff --git a/src/graphics/shader.hpp b/src/graphics/shader.hpp index 0cb5d5d146d..c9e0f0de6f2 100644 --- a/src/graphics/shader.hpp +++ b/src/graphics/shader.hpp @@ -286,7 +286,7 @@ class Shader : public ShaderBase, public Singleton template void printFileList(GLint shader_type, const char *filepath, Types ... args) { - Log::error("shader", filepath); + Log::error("shader", "%s", filepath); printFileList(args...); } // printFileList @@ -369,7 +369,7 @@ class Shader : public ShaderBase, public Singleton glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &info_length); char *error_message = new char[info_length]; glGetProgramInfoLog(m_program, info_length, NULL, error_message); - Log::error("Shader", error_message); + Log::error("Shader", "%s", error_message); delete[] error_message; } // After linking all shaders can be detached diff --git a/src/graphics/shader_files_manager.cpp b/src/graphics/shader_files_manager.cpp index 348bd931e92..f04ccc31ed2 100644 --- a/src/graphics/shader_files_manager.cpp +++ b/src/graphics/shader_files_manager.cpp @@ -238,7 +238,7 @@ ShaderFilesManager::SharedShader ShaderFilesManager::loadShader char *error_message = new char[info_length]; error_message[0] = 0; glGetShaderInfoLog(*ss, info_length, NULL, error_message); - Log::error("ShaderFilesManager", error_message); + Log::error("ShaderFilesManager", "%s", error_message); delete[] error_message; if (UserConfigParams::m_artist_debug_mode) { diff --git a/src/graphics/sp/sp_shader.cpp b/src/graphics/sp/sp_shader.cpp index d175083116e..8b8cf25ab20 100644 --- a/src/graphics/sp/sp_shader.cpp +++ b/src/graphics/sp/sp_shader.cpp @@ -95,7 +95,7 @@ void SPShader::linkShaderFiles(RenderPass rp) glGetProgramiv(m_program[rp], GL_INFO_LOG_LENGTH, &info_length); char *error_message = new char[info_length]; glGetProgramInfoLog(m_program[rp], info_length, NULL, error_message); - Log::error("SPShader", error_message); + Log::error("SPShader", "%s", error_message); delete[] error_message; } // After linking all shaders can be detached diff --git a/src/guiengine/event_handler.cpp b/src/guiengine/event_handler.cpp index d38c6f697ef..133c546c370 100644 --- a/src/guiengine/event_handler.cpp +++ b/src/guiengine/event_handler.cpp @@ -240,14 +240,14 @@ bool EventHandler::OnEvent (const SEvent &event) if (event.LogEvent.Level == irr::ELL_WARNING) { if(error_info.size()>0) - Log::warn("EventHandler", error_info.c_str()); - Log::warn("Irrlicht", event.LogEvent.Text); + Log::warn("EventHandler", "%s", error_info.c_str()); + Log::warn("Irrlicht", "%s", event.LogEvent.Text); } else if (event.LogEvent.Level == irr::ELL_ERROR) { if(error_info.size()>0) - Log::error("EventHandler", error_info.c_str()); - Log::error("Irrlicht", event.LogEvent.Text); + Log::error("EventHandler", "%s", error_info.c_str()); + Log::error("Irrlicht", "%s", event.LogEvent.Text); } } return true; diff --git a/src/guiengine/widgets/player_kart_widget.cpp b/src/guiengine/widgets/player_kart_widget.cpp index ee8768ce178..2ab27c3568c 100644 --- a/src/guiengine/widgets/player_kart_widget.cpp +++ b/src/guiengine/widgets/player_kart_widget.cpp @@ -622,7 +622,7 @@ GUIEngine::EventPropagation PlayerKartWidget::transmitEvent(Widget* w, { if(UserConfigParams::logGUI()) { - Log::info("[KartSelectionScreen]", "Identity changed " + Log::info("KartSelectionScreen", "Identity changed " "for player %s : %s",m_player_id, irr::core::stringc( m_player_ident_spinner->getStringValue() diff --git a/src/guiengine/widgets/spinner_widget.cpp b/src/guiengine/widgets/spinner_widget.cpp index 1ac88c25331..104708fa33b 100644 --- a/src/guiengine/widgets/spinner_widget.cpp +++ b/src/guiengine/widgets/spinner_widget.cpp @@ -168,7 +168,7 @@ void SpinnerWidget::add() { if (!StringUtils::parseString(min_s, &m_min)) { - Log::warn("invalid value for spinner widget minimum value : %s", min_s.c_str()); + Log::warn("SpinnerWidget", "invalid value for spinner widget minimum value : %s", min_s.c_str()); } } @@ -176,7 +176,7 @@ void SpinnerWidget::add() { if (!StringUtils::parseString(max_s, &m_max)) { - Log::warn("invalid value for spinner widget maximum value : %s", max_s.c_str()); + Log::warn("SpinnerWidget", "invalid value for spinner widget maximum value : %s", max_s.c_str()); } } diff --git a/src/input/input_manager.cpp b/src/input/input_manager.cpp index 99cff967f5a..3cf533f4ec6 100644 --- a/src/input/input_manager.cpp +++ b/src/input/input_manager.cpp @@ -436,7 +436,7 @@ void InputManager::inputSensing(Input::InputType type, int deviceID, return; #if INPUT_MODE_DEBUG - Log::info("InputManager::inputSensing", store_new ? "storing it" : "ignoring it"); + Log::info("InputManager", "inputSensing %s", store_new ? "storing it" : "ignoring it"); #endif @@ -925,7 +925,7 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, void InputManager::setMasterPlayerOnly(bool enabled) { #if INPUT_MODE_DEBUG - Log::info("InputManager::setMasterPlayerOnly", enabled ? "enabled" : "disabled"); + Log::info("InputManager", "setMasterPlayerOnly %s", enabled ? "enabled" : "disabled"); #endif m_master_player_only = enabled; } diff --git a/src/io/file_manager.cpp b/src/io/file_manager.cpp index 77ccf5c886f..d265c2210db 100644 --- a/src/io/file_manager.cpp +++ b/src/io/file_manager.cpp @@ -88,7 +88,7 @@ std::string FileManager::m_stdout_dir; bool macSetBundlePathIfRelevant(std::string& data_dir) { - Log::debug("[FileManager]", "Checking whether we are using an app bundle... "); + Log::debug("FileManager", "Checking whether we are using an app bundle... "); // the following code will enable STK to find its data when placed in an // app bundle on mac OS X. // returns true if path is set, returns false if path was not set @@ -114,7 +114,7 @@ bool macSetBundlePathIfRelevant(std::string& data_dir) data_dir = contents; return true; #else - Log::debug("[FileManager]", "yes"); + Log::debug("FileManager", "yes"); // executable is inside an app bundle, use app bundle-relative paths data_dir = contents + std::string("/Resources/"); return true; @@ -122,7 +122,7 @@ bool macSetBundlePathIfRelevant(std::string& data_dir) } else { - Log::debug("[FileManager]", "no"); + Log::debug("FileManager", "no"); return false; } } @@ -306,15 +306,15 @@ void FileManager::discoverPaths() // We can't use _() here, since translations will only be initalised // after the filemanager (to get the path to the tranlsations from it) for(unsigned int i=0; iexistFile(io::path(path.c_str()))) return true; - Log::info("[FileManager]", "Creating directory(ies) '%s'", path.c_str()); + Log::info("FileManager", "Creating directory(ies) '%s'", path.c_str()); std::vector split = StringUtils::split(path,'/'); std::string current_path = ""; for (unsigned int i=0; i v = StringUtils::split(s,' '); if (v.size() != 3) { - Log::warn("[XMLNode]", "WARNING: Expected 3 floating-point values, but found '%s' in file %s", + Log::warn("XMLNode", "WARNING: Expected 3 floating-point values, but found '%s' in file %s", s.c_str(), m_file_name.c_str()); return 0; } @@ -252,7 +252,7 @@ int XMLNode::get(const std::string &attribute, Vec3 *value) const } else { - Log::warn("[XMLNode]", "WARNING: Expected 3 floating-point values, but found '%s' in file %s", + Log::warn("XMLNode", "WARNING: Expected 3 floating-point values, but found '%s' in file %s", s.c_str(), m_file_name.c_str()); return 0; } @@ -317,7 +317,7 @@ int XMLNode::get(const std::string &attribute, int32_t *value) const if (!StringUtils::parseString(s, value)) { - Log::warn("[XMLNode]", "WARNING: Expected int but found '%s' for attribute '%s' of node '%s' in file %s", + Log::warn("XMLNode", "WARNING: Expected int but found '%s' for attribute '%s' of node '%s' in file %s", s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str()); return 0; } @@ -333,7 +333,7 @@ int XMLNode::get(const std::string &attribute, int64_t *value) const if (!StringUtils::parseString(s, value)) { - Log::warn("[XMLNode]", "WARNING: Expected int but found '%s' for attribute '%s' of node '%s' in file %s", + Log::warn("XMLNode", "WARNING: Expected int but found '%s' for attribute '%s' of node '%s' in file %s", s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str()); return 0; } @@ -349,7 +349,7 @@ int XMLNode::get(const std::string &attribute, uint64_t *value) const if (!StringUtils::parseString(s, value)) { - Log::warn("[XMLNode]", "WARNING: Expected int but found '%s' for attribute '%s' of node '%s' in file %s", + Log::warn("XMLNode", "WARNING: Expected int but found '%s' for attribute '%s' of node '%s' in file %s", s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str()); return 0; } @@ -365,7 +365,7 @@ int XMLNode::get(const std::string &attribute, uint16_t *value) const if (!StringUtils::parseString(s, value)) { - Log::warn("[XMLNode]", "WARNING: Expected uint but found '%s' for attribute '%s' of node '%s' in file %s", + Log::warn("XMLNode", "WARNING: Expected uint but found '%s' for attribute '%s' of node '%s' in file %s", s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str()); return 0; } @@ -381,7 +381,7 @@ int XMLNode::get(const std::string &attribute, uint32_t *value) const if (!StringUtils::parseString(s, value)) { - Log::warn("[XMLNode]", "WARNING: Expected uint but found '%s' for attribute '%s' of node '%s' in file %s", + Log::warn("XMLNode", "WARNING: Expected uint but found '%s' for attribute '%s' of node '%s' in file %s", s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str()); return 0; } @@ -397,7 +397,7 @@ int XMLNode::get(const std::string &attribute, float *value) const if (!StringUtils::parseString(s, value)) { - Log::warn("[XMLNode]", "WARNING: Expected float but found '%s' for attribute '%s' of node '%s' in file %s", + Log::warn("XMLNode", "WARNING: Expected float but found '%s' for attribute '%s' of node '%s' in file %s", s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str()); return 0; } @@ -413,7 +413,7 @@ int XMLNode::get(const std::string &attribute, double *value) const if (!StringUtils::parseString(s, value)) { - Log::warn("[XMLNode]", "WARNING: Expected double but found '%s' for" + Log::warn("XMLNode", "WARNING: Expected double but found '%s' for" " attribute '%s' of node '%s' in file %s", s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str()); return 0; @@ -473,7 +473,7 @@ int XMLNode::get(const std::string &attribute, float curr; if (!StringUtils::parseString(v[i], &curr)) { - Log::warn("[XMLNode]", "WARNING: Expected float but found '%s' for attribute '%s' of node '%s' in file %s", + Log::warn("XMLNode", "WARNING: Expected float but found '%s' for attribute '%s' of node '%s' in file %s", v[i].c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str()); return 0; } @@ -504,7 +504,7 @@ int XMLNode::get(const std::string &attribute, std::vector *value) const int val; if (!StringUtils::parseString(v[i], &val)) { - Log::warn("[XMLNode]", "WARNING: Expected int but found '%s' for attribute '%s' of node '%s'", + Log::warn("XMLNode", "WARNING: Expected int but found '%s' for attribute '%s' of node '%s'", v[i].c_str(), attribute.c_str(), m_name.c_str()); return 0; } @@ -534,22 +534,22 @@ int XMLNode::get(const std::string &attribute, InterpolationArray *value) const std::vector pair = StringUtils::split(pairs[i],':'); if(pair.size()!=2) { - Log::fatal("[XMLNode]", "Incorrect interpolation pair '%s' in '%s'.", + Log::fatal("XMLNode", "Incorrect interpolation pair '%s' in '%s'.", pairs[i].c_str(), attribute.c_str()); - Log::fatal("[XMLNode]", "Must be x:y."); + Log::fatal("XMLNode", "Must be x:y."); exit(-1); } float x; if(!StringUtils::fromString(pair[0], x)) { - Log::fatal("[XMLNode]", "Incorrect x in pair '%s' of '%s'.", + Log::fatal("XMLNode", "Incorrect x in pair '%s' of '%s'.", pairs[i].c_str(), attribute.c_str()); exit(-1); } float y; if(!StringUtils::fromString(pair[1], y)) { - Log::fatal("[XMLNode]", "Incorrect y in pair '%s' in '%s'.", + Log::fatal("XMLNode", "Incorrect y in pair '%s' in '%s'.", pair[1].c_str(), attribute.c_str()); exit(-1); } diff --git a/src/items/flyable.cpp b/src/items/flyable.cpp index b305d886d96..cef9dcfded6 100644 --- a/src/items/flyable.cpp +++ b/src/items/flyable.cpp @@ -175,7 +175,7 @@ void Flyable::createPhysics(float forw_offset, const Vec3 &velocity, // Just to get some additional information if the assert is triggered if(std::isnan(v.getX()) || std::isnan(v.getY()) || std::isnan(v.getZ())) { - Log::debug("[Flyable]", "vel %f %f %f v %f %f %f", + Log::debug("Flyable", "vel %f %f %f v %f %f %f", velocity.getX(),velocity.getY(),velocity.getZ(), v.getX(),v.getY(),v.getZ()); } diff --git a/src/items/item_manager.cpp b/src/items/item_manager.cpp index e2e28cf8e38..f36ccf10cf3 100644 --- a/src/items/item_manager.cpp +++ b/src/items/item_manager.cpp @@ -94,7 +94,7 @@ void ItemManager::loadDefaultItemMeshes() scene::IMesh *mesh = irr_driver->getAnimatedMesh(model_filename); if(!node || model_filename.size()==0 || !mesh) { - Log::fatal("[ItemManager]", "Item model '%s' in items.xml could not be loaded " + Log::fatal("ItemManager", "Item model '%s' in items.xml could not be loaded " "- aborting", name.c_str()); exit(-1); } @@ -614,7 +614,7 @@ bool ItemManager::randomItemsForArena(const AlignedArray& pos) const unsigned int TOTAL_ITEM = MIN_DIST / 2; std::vector random_numbers; - Log::info("[ItemManager]","Creating %d random items for arena", TOTAL_ITEM); + Log::info("ItemManager","Creating %d random items for arena", TOTAL_ITEM); for (unsigned int i = 0; i < TOTAL_ITEM; i++) { int chosen_node = -1; @@ -623,12 +623,12 @@ bool ItemManager::randomItemsForArena(const AlignedArray& pos) if (used_location.size() - pos.size() + invalid_location.size() == ALL_NODES) { - Log::warn("[ItemManager]","Can't place more random items! " + Log::warn("ItemManager","Can't place more random items! " "Use default item location."); return false; } uint32_t number = m_random_engine(); - Log::debug("[ItemManager]", "%u from random engine.", number); + Log::debug("ItemManager", "%u from random engine.", number); const int node = number % ALL_NODES; // Check if tried @@ -703,7 +703,7 @@ bool ItemManager::randomItemsForArena(const AlignedArray& pos) } else { - Log::warn("[ItemManager]","Raycast to surface failed" + Log::warn("ItemManager","Raycast to surface failed" "from node %d", used_location[i]); placeItem(type, an->getCenter(), quad_normal); } diff --git a/src/items/rubber_ball.cpp b/src/items/rubber_ball.cpp index 329968ef2e9..bb6413e99ac 100644 --- a/src/items/rubber_ball.cpp +++ b/src/items/rubber_ball.cpp @@ -205,7 +205,7 @@ void RubberBall::computeTarget() if(m_target==m_owner && m_delete_ticks < 0) { #ifdef PRINT_BALL_REMOVE_INFO - Log::debug("[RubberBall]", + Log::debug("RubberBall", "ball %d removed because owner is target.", m_id); #endif m_delete_ticks = m_st_delete_ticks; @@ -218,7 +218,7 @@ void RubberBall::computeTarget() // aim at the owner (the ball is unlikely to hit it), and // this will trigger the usage of the delete time in updateAndDelete #ifdef PRINT_BALL_REMOVE_INFO - Log::debug("[RubberBall]" "ball %d removed because no more active target.", + Log::debug("RubberBall" "ball %d removed because no more active target.", m_id); #endif m_delete_ticks = m_st_delete_ticks; @@ -386,7 +386,7 @@ bool RubberBall::updateAndDelete(int ticks) { hit(NULL); #ifdef PRINT_BALL_REMOVE_INFO - Log::debug("[RubberBall]", "ball %d deleted.", m_id); + Log::debug("RubberBall", "ball %d deleted.", m_id); #endif removePingSFX(); return true; @@ -451,7 +451,7 @@ bool RubberBall::updateAndDelete(int ticks) float height = updateHeight()+m_extend.getY()*0.5f; if(UserConfigParams::logFlyable()) - Log::debug("[RubberBall]", "ball %d: %f %f %f height %f gethot %f terrain %d aim %d", + Log::debug("RubberBall", "ball %d: %f %f %f height %f gethot %f terrain %d aim %d", m_id, next_xyz.getX(), next_xyz.getY(), next_xyz.getZ(), height, getHoT(), isOnRoad(), m_aiming_at_target); @@ -665,7 +665,7 @@ bool RubberBall::checkTunneling() if(m_tunnel_count > 3) { #ifdef PRINT_BALL_REMOVE_INFO - Log::debug("[RubberBall]", + Log::debug("RubberBall", "Ball %d nearly tunneled at %f %f %f -> %f %f %f", m_id, m_previous_xyz.getX(),m_previous_xyz.getY(), m_previous_xyz.getZ(), @@ -788,7 +788,7 @@ void RubberBall::updateDistanceToTarget() m_distance_to_target += Track::getCurrentTrack()->getTrackLength(); } if(UserConfigParams::logFlyable()) - Log::debug("[RubberBall]", "ball %d: target %f %f %f distance_2_target %f", + Log::debug("RubberBall", "ball %d: target %f %f %f distance_2_target %f", m_id, m_target->getXYZ().getX(),m_target->getXYZ().getY(), m_target->getXYZ().getZ(),m_distance_to_target ); @@ -822,7 +822,7 @@ void RubberBall::updateDistanceToTarget() { m_delete_ticks = m_st_delete_ticks; #ifdef PRINT_BALL_REMOVE_INFO - Log::debug("[RubberBall]", "ball %d lost target (overtook?).", + Log::debug("RubberBall", "ball %d lost target (overtook?).", m_id); #endif @@ -858,7 +858,7 @@ bool RubberBall::hit(AbstractKart* kart, PhysicalObject* object) return false; #ifdef PRINT_BALL_REMOVE_INFO if(kart) - Log::debug("[RuberBall]", "ball %d hit kart.", m_id); + Log::debug("RuberBall", "ball %d hit kart.", m_id); #endif if(kart && kart!=m_target) { diff --git a/src/karts/kart_gfx.cpp b/src/karts/kart_gfx.cpp index 153f034c880..ebeeb224ae4 100644 --- a/src/karts/kart_gfx.cpp +++ b/src/karts/kart_gfx.cpp @@ -212,7 +212,7 @@ void KartGFX::addEffect(KartGFXType type, const std::string &file_name, // by adding a NULL to the list (which is tested for in all // cases). C++ guarantees that all memory allocated in the // constructor is properly freed. - Log::error("[KartGFX]", "%s",e.what()); + Log::error("KartGFX", "%s",e.what()); kind = NULL; emitter = NULL; } diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index 0dc2ef49751..8fdc1a8adbd 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -284,9 +284,9 @@ void KartProperties::load(const std::string &filename, const std::string &node) } catch(std::exception& err) { - Log::error("[KartProperties]", "Error while parsing KartProperties '%s':", + Log::error("KartProperties", "Error while parsing KartProperties '%s':", filename.c_str()); - Log::error("[KartProperties]", "%s", err.what()); + Log::error("KartProperties", "%s", err.what()); } if(root) delete root; @@ -521,7 +521,7 @@ void KartProperties::getAllData(const XMLNode * root) m_terrain_impulse_type = IMPULSE_TO_DRIVELINE; else { - Log::fatal("[KartProperties]", + Log::fatal("KartProperties", "Missing or incorrect value for impulse-type: '%s'.", s.c_str()); } @@ -583,7 +583,7 @@ void KartProperties::getAllData(const XMLNode * root) } else { - Log::error("[KartProperties]", + Log::error("KartProperties", "Kart '%s' has an invalid custom engine file '%s'.", m_name.c_str(), full_path.c_str()); m_engine_sfx_type = "engine_small"; @@ -599,7 +599,7 @@ void KartProperties::getAllData(const XMLNode * root) } else { - Log::error("[KartProperties]", + Log::error("KartProperties", "Kart '%s' has an invalid engine '%s'.", m_name.c_str(), s.c_str()); m_engine_sfx_type = "engine_small"; diff --git a/src/karts/kart_properties_manager.cpp b/src/karts/kart_properties_manager.cpp index 0ad6c8a7ad1..6ebf916f011 100644 --- a/src/karts/kart_properties_manager.cpp +++ b/src/karts/kart_properties_manager.cpp @@ -300,7 +300,7 @@ bool KartPropertiesManager::loadKart(const std::string &dir) } catch (std::runtime_error& err) { - Log::error("[KartPropertiesManager]", "Giving up loading '%s': %s", + Log::error("KartPropertiesManager", "Giving up loading '%s': %s", config_filename.c_str(), err.what()); return false; } @@ -312,7 +312,7 @@ bool KartPropertiesManager::loadKart(const std::string &dir) if (kart_properties->getVersion() < stk_config->m_min_kart_version || kart_properties->getVersion() > stk_config->m_max_kart_version) { - Log::warn("[KartPropertiesManager]", "Warning: kart '%s' is not " + Log::warn("KartPropertiesManager", "Warning: kart '%s' is not " "supported by this binary, ignored.", kart_properties->getIdent().c_str()); delete kart_properties; @@ -463,7 +463,7 @@ void KartPropertiesManager::setUnavailableKarts(std::vector karts) { m_kart_available[i] = false; - Log::error("[Kart_Properties_Manager]", + Log::error("Kart_Properties_Manager", "Kart '%s' not available on all clients, disabled.", m_karts_properties[i].getIdent().c_str()); } // kart not in list @@ -630,7 +630,7 @@ void KartPropertiesManager::getRandomKartList(int count, catch (std::runtime_error& ex) { (void)ex; - Log::error("[KartPropertiesManager]", "getRandomKartList : " + Log::error("KartPropertiesManager", "getRandomKartList : " "WARNING, can't find kart '%s'", (*existing_karts)[i].getKartName().c_str()); } @@ -646,7 +646,7 @@ void KartPropertiesManager::getRandomKartList(int count, catch (std::runtime_error &ex) { (void)ex; - Log::error("[KartPropertiesManager]", "getRandomKartList : WARNING, " + Log::error("KartPropertiesManager", "getRandomKartList : WARNING, " "can't find kart '%s'",(*ai_list)[i].c_str()); } } diff --git a/src/main_loop.cpp b/src/main_loop.cpp index 5a364bbb300..958091b3cff 100644 --- a/src/main_loop.cpp +++ b/src/main_loop.cpp @@ -270,7 +270,7 @@ double MainLoop::getLimitedDt() m_curr_time = std::chrono::steady_clock::now(); if (m_prev_time > m_curr_time) { - Log::error("MainLopp", "System clock keeps backwards!"); + Log::error("MainLoop", "System clock keeps backwards!"); m_prev_time = m_curr_time; } dt = convertToTime(m_curr_time, m_prev_time); diff --git a/src/modes/cutscene_world.cpp b/src/modes/cutscene_world.cpp index 85b883d5cb8..c5c30c7b7ef 100644 --- a/src/modes/cutscene_world.cpp +++ b/src/modes/cutscene_world.cpp @@ -109,7 +109,7 @@ void CutsceneWorld::init() if (!StringUtils::fromString(frameStr, frame)) { - Log::error("[CutsceneWorld]", "Invalid condition '%s'", + Log::error("CutsceneWorld", "Invalid condition '%s'", condition.c_str()); continue; } @@ -129,7 +129,7 @@ void CutsceneWorld::init() if (!StringUtils::fromString(frameStr, frame)) { - Log::error("[CutsceneWorld]", "Invalid condition '%s'", + Log::error("CutsceneWorld", "Invalid condition '%s'", condition.c_str()); continue; } @@ -144,7 +144,7 @@ void CutsceneWorld::init() if (!StringUtils::fromString(frameStr, frame)) { - Log::error("[CutsceneWorld]", "Invalid condition '%s'", + Log::error("CutsceneWorld", "Invalid condition '%s'", condition.c_str()); continue; } @@ -167,7 +167,7 @@ void CutsceneWorld::init() if (m_duration <= 0.0f) { - Log::error("[CutsceneWorld]", "WARNING: cutscene has no duration"); + Log::error("CutsceneWorld", "WARNING: cutscene has no duration"); } } // CutsceneWorld diff --git a/src/modes/demo_world.cpp b/src/modes/demo_world.cpp index d4a0c0f0d03..23ede7e4d1b 100644 --- a/src/modes/demo_world.cpp +++ b/src/modes/demo_world.cpp @@ -73,9 +73,9 @@ DemoWorld::DemoWorld() default: RaceManager::get()->setDifficulty(RaceManager::DIFFICULTY_HARD); break; } - Log::info("[DemoWorld]", "Reverse mode state: %d", RaceManager::get()->getReverseTrack()); - Log::info("[DemoWorld]", "Current game mode: %s", RaceManager::get()->getMinorModeName().c_str()); - Log::info("[DemoWorld]", "Current difficulty: %s", RaceManager::get()-> + Log::info("DemoWorld", "Reverse mode state: %d", RaceManager::get()->getReverseTrack()); + Log::info("DemoWorld", "Current game mode: %s", RaceManager::get()->getMinorModeName().c_str()); + Log::info("DemoWorld", "Current difficulty: %s", RaceManager::get()-> getDifficultyAsString(RaceManager::get()->getDifficulty()).c_str()); RaceManager::get()->setNumKarts(m_default_num_karts); @@ -156,7 +156,7 @@ bool DemoWorld::updateIdleTimeAndStartDemo(float dt) && m_demo_tracks.size() > 0) { if(!track) - Log::warn("[DemoWorld]", "Invalid demo track identifier '%s'.", + Log::warn("DemoWorld", "Invalid demo track identifier '%s'.", m_demo_tracks[0].c_str()); m_demo_tracks.erase(m_demo_tracks.begin()); track = track_manager->getTrack(m_demo_tracks[0]); @@ -166,7 +166,7 @@ bool DemoWorld::updateIdleTimeAndStartDemo(float dt) // be filled up with all the tracks. if(m_demo_tracks.size()==0) { - Log::warn("[DemoWorld]", "No valid tracks found, no demo started."); + Log::warn("DemoWorld", "No valid tracks found, no demo started."); return false; } diff --git a/src/modes/easter_egg_hunt.cpp b/src/modes/easter_egg_hunt.cpp index 7d74f0a37e9..1d27b2f4ca8 100644 --- a/src/modes/easter_egg_hunt.cpp +++ b/src/modes/easter_egg_hunt.cpp @@ -83,7 +83,7 @@ void EasterEggHunt::readData(const std::string &filename) if(easter->getName()!="EasterEggHunt") { - Log::error("[EasterEggHunt]", "Can't load easter egg file '%s' - no EasterEggHunt element.", + Log::error("EasterEggHunt", "Can't load easter egg file '%s' - no EasterEggHunt element.", filename.c_str()); return; } @@ -118,7 +118,7 @@ void EasterEggHunt::readData(const std::string &filename) const XMLNode *egg = data->getNode(i); if(egg->getName()!="easter-egg") { - Log::warn("[EasterEggHunt]", "Unknown node '%s' in easter egg level '%s' - ignored.", + Log::warn("EasterEggHunt", "Unknown node '%s' in easter egg level '%s' - ignored.", egg->getName().c_str(), RaceManager::get()->getDifficultyAsString(act_difficulty).c_str()); continue; diff --git a/src/modes/follow_the_leader.cpp b/src/modes/follow_the_leader.cpp index cffe3332698..8914ea932e3 100644 --- a/src/modes/follow_the_leader.cpp +++ b/src/modes/follow_the_leader.cpp @@ -142,11 +142,11 @@ void FollowTheLeaderRace::countdownReachedZero() AbstractKart *kart = getKartAtPosition(position_to_remove); if(!kart || kart->isEliminated()) { - Log::error("[FTL]", "Problem with removing leader: position %d not found", + Log::error("FTL", "Problem with removing leader: position %d not found", position_to_remove); for(unsigned int i=0; iisEliminated(), m_karts[i]->getPosition()); } // for i } // @@ -154,7 +154,7 @@ void FollowTheLeaderRace::countdownReachedZero() { if(UserConfigParams::m_ftl_debug) { - Log::debug("[FTL", "Eliminating kart '%s' at position %d.", + Log::debug("FTL", "Eliminating kart '%s' at position %d.", kart->getIdent().c_str(), position_to_remove); } eliminateKart(kart->getWorldKartId()); diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index 44935330ff1..9b170a7c11d 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -250,7 +250,7 @@ void LinearWorld::update(int ticks) { for(unsigned int j=0; jgetPosition(), m_karts[j]->hasFinishedRace(), @@ -785,9 +785,9 @@ float LinearWorld::estimateFinishTimeForKart(AbstractKart* kart) #ifdef DEBUG if(kart_info.m_overall_distance > full_distance) { - Log::debug("[LinearWorld]", "Full distance < distance covered for kart '%s':", + Log::debug("LinearWorld", "Full distance < distance covered for kart '%s':", kart->getIdent().c_str()); - Log::debug("[LinearWorld]", "%f < %f", full_distance, kart_info.m_overall_distance); + Log::debug("LinearWorld", "%f < %f", full_distance, kart_info.m_overall_distance); } #endif // Avoid potential problems (floating point issues, coding bug?) if a @@ -946,12 +946,12 @@ void LinearWorld::updateRacePosition() rank_changed |= kart->getPosition()!=p; if (!setKartPosition(i,p)) { - Log::error("[LinearWorld]", "Same rank used twice!!"); + Log::error("LinearWorld", "Same rank used twice!!"); - Log::debug("[LinearWorld]", "Info used to decide ranking :"); + Log::debug("LinearWorld", "Info used to decide ranking :"); for (unsigned int d=0; dgetIdent().c_str(), m_karts[d]->hasFinishedRace(), @@ -960,14 +960,14 @@ void LinearWorld::updateRacePosition() m_karts[d]->isEliminated()); } - Log::debug("[LinearWorld]", "Who has each ranking so far :"); + Log::debug("LinearWorld", "Who has each ranking so far :"); for (unsigned int d=0; dgetIdent().c_str(), + Log::debug("LinearWorld", "%s has rank %d", m_karts[d]->getIdent().c_str(), m_karts[d]->getPosition()); } - Log::debug("[LinearWorld]", " --> And %s is being set at rank %d", + Log::debug("LinearWorld", " --> And %s is being set at rank %d", kart->getIdent().c_str(), p); history->Save(); assert(false); @@ -982,11 +982,11 @@ void LinearWorld::updateRacePosition() #ifdef DEBUG_KART_RANK if(rank_changed) { - Log::debug("[LinearWorld]", "Counting laps at %u seconds.", getTime()); + Log::debug("LinearWorld", "Counting laps at %u seconds.", getTime()); for (unsigned int i=0; igetIdent().c_str(), m_kart_info[i].m_race_lap, @@ -1010,21 +1010,21 @@ void LinearWorld::updateRacePosition() if(j == my_id) continue; if(m_karts[j]->isEliminated()) { - Log::debug("[LinearWorld]", " %u: %s because it is eliminated.", + Log::debug("LinearWorld", " %u: %s because it is eliminated.", p, m_karts[j]->getIdent().c_str()); continue; } if(!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) { p++; - Log::debug("[LinearWorld]", " %u: %s because it has finished the race.", + Log::debug("LinearWorld", " %u: %s because it has finished the race.", p, m_karts[j]->getIdent().c_str()); continue; } if(m_kart_info[j].m_overall_distance > my_distance) { p++; - Log::debug("[LinearWorld]", " %u: %s because it is ahead %u.", + Log::debug("LinearWorld", " %u: %s because it is ahead %u.", p, m_karts[j]->getIdent().c_str(), m_kart_info[j].m_overall_distance); continue; @@ -1033,7 +1033,7 @@ void LinearWorld::updateRacePosition() m_karts[j]->getInitialPosition()getInitialPosition()) { p++; - Log::debug("[LinearWorld]"," %u: %s has same distance, but started ahead %d", + Log::debug("LinearWorld"," %u: %s has same distance, but started ahead %d", p, m_karts[j]->getIdent().c_str(), m_karts[j]->getInitialPosition()); } diff --git a/src/modes/overworld.cpp b/src/modes/overworld.cpp index 34183837cd7..f15d7dc5b06 100644 --- a/src/modes/overworld.cpp +++ b/src/modes/overworld.cpp @@ -88,7 +88,7 @@ void OverWorld::enterOverWorld() if (!kart_properties_manager->getKart(UserConfigParams::m_default_kart)) { - Log::warn("[overworld]", "cannot find kart '%s', " + Log::warn("overworld", "cannot find kart '%s', " "will revert to default", UserConfigParams::m_default_kart.c_str()); diff --git a/src/modes/profile_world.cpp b/src/modes/profile_world.cpp index a8b6ad7fbb1..833c3771803 100644 --- a/src/modes/profile_world.cpp +++ b/src/modes/profile_world.cpp @@ -254,7 +254,7 @@ void ProfileWorld::enterRaceOverState() ss << kart->getBonusCount() << " " << kart->getBananaCount() << " "; ss << kart->getSmallNitroCount() << " " << kart->getLargeNitroCount() << " "; ss << kart->getBubblegumCount() << " " << kart->getOffTrackCount() << " "; - Log::verbose("profile", ss.str().c_str()); + Log::verbose("profile", "%s", ss.str().c_str()); } // Print group statistics of all karts @@ -274,7 +274,7 @@ void ProfileWorld::enterRaceOverState() Log::verbose("profile", ""); ss << "name" << std::setw(max_len-4) << " " << "Strt End Time AvSp Top Skid Resc Rsc Brake Expl Exp Itm Ban SNitLNit Bub Off Energy"; - Log::verbose("profile", ss.str().c_str()); + Log::verbose("profile", "%s", ss.str().c_str()); for(std::set::iterator it = all_groups.begin(); it !=all_groups.end(); it++) { diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 56cc82efa7b..b3a2b618a65 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -602,7 +602,7 @@ Controller* World::loadAIController(AbstractKart* kart) controller = new SoccerAI(kart); break; default: - Log::warn("[World]", "Unknown AI, using default."); + Log::warn("World", "Unknown AI, using default."); controller = new SkiddingAI(kart); break; } @@ -1309,10 +1309,10 @@ void World::updateHighscores(int* best_highscore_rank) // no kart claimed to be in this position, most likely means // the kart location data is wrong #ifdef DEBUG - Log::error("[World]", "Incorrect kart positions:"); + Log::error("World", "Incorrect kart positions:"); for (unsigned int i=0; igetPosition()); } #endif diff --git a/src/modes/world_with_rank.cpp b/src/modes/world_with_rank.cpp index 4bc6cb8e1ed..d9f933a565d 100644 --- a/src/modes/world_with_rank.cpp +++ b/src/modes/world_with_rank.cpp @@ -129,7 +129,7 @@ bool WorldWithRank::setKartPosition(unsigned int kart_id, assert(m_position_setting_initialised); if(m_position_used[position-1]) { - Log::error("[WorldWithRank]", "== TWO KARTS ARE BEING GIVEN THE SAME POSITION!! =="); + Log::error("WorldWithRank", "== TWO KARTS ARE BEING GIVEN THE SAME POSITION!! =="); for (unsigned int j=0; j < m_position_index.size(); j++) { if (!m_position_used[j]) diff --git a/src/network/protocol.cpp b/src/network/protocol.cpp index 67cb744ca88..0a97e0d0dda 100644 --- a/src/network/protocol.cpp +++ b/src/network/protocol.cpp @@ -65,7 +65,7 @@ bool Protocol::checkDataSize(Event* event, unsigned int minimum_size) if (data.size() < minimum_size) { Log::warn("Protocol", "Receiving a badly formatted message:"); - Log::warn("Protocol", data.getLogMessage().c_str()); + Log::warn("Protocol", "%s", data.getLogMessage().c_str()); return false; } return true; diff --git a/src/network/protocol_manager.cpp b/src/network/protocol_manager.cpp index 61d1a258d10..faa8a319779 100644 --- a/src/network/protocol_manager.cpp +++ b/src/network/protocol_manager.cpp @@ -394,7 +394,7 @@ void ProtocolManager::update(int ticks) const std::string& name = (*i)->getPeer()->getAddress().toString(); Log::error("ProtocolManager", "Synchronous event error from %s: %s", name.c_str(), e.what()); - Log::error("ProtocolManager", (*i)->data().getLogMessage().c_str()); + Log::error("ProtocolManager", "%s", (*i)->data().getLogMessage().c_str()); } m_sync_events_to_process.lock(); if (can_be_deleted) @@ -457,7 +457,7 @@ void ProtocolManager::asynchronousUpdate() if (*i != nullptr && (*i)->hasValidData()) { // kimden: make sure you don't cause it to be nullptr yourself - Log::error("ProtocolManager", (*i)->data().getLogMessage().c_str()); + Log::error("ProtocolManager", "%s", (*i)->data().getLogMessage().c_str()); } else { diff --git a/src/online/online_player_profile.cpp b/src/online/online_player_profile.cpp index 6e21bdd5942..473e097e611 100644 --- a/src/online/online_player_profile.cpp +++ b/src/online/online_player_profile.cpp @@ -334,7 +334,7 @@ namespace Online Log::warn("OnlinePlayerProfile::signOut", "There were some connection issues while logging out. " "Report a bug if this caused issues."); - Log::warn("OnlinePlayerProfile::signOut", core::stringc(info.c_str()).c_str()); + Log::warn("OnlinePlayerProfile", "signOut %s", core::stringc(info.c_str()).c_str()); if (user_screen) user_screen->logoutError(info); } diff --git a/src/scriptengine/script_engine.cpp b/src/scriptengine/script_engine.cpp index 45cdce3bcd4..a8c1fb7b619 100644 --- a/src/scriptengine/script_engine.cpp +++ b/src/scriptengine/script_engine.cpp @@ -279,7 +279,7 @@ namespace Scripting asITypeInfo* type = obj->GetObjectType(); asIScriptFunction* method = type->GetMethodByName(methodName.c_str()); if (method == NULL) - Log::error("Scripting", ("runMethod: object does not implement method " + methodName).c_str()); + Log::error("Scripting", "%s", ("runMethod: object does not implement method " + methodName).c_str()); asIScriptContext *ctx = m_engine->CreateContext(); diff --git a/src/states_screens/kart_selection.cpp b/src/states_screens/kart_selection.cpp index 1c60385b823..be77a65c961 100644 --- a/src/states_screens/kart_selection.cpp +++ b/src/states_screens/kart_selection.cpp @@ -127,7 +127,7 @@ EventPropagation FocusDispatcher::focused(const int player_id) if (!m_is_initialised) return EVENT_LET; if(UserConfigParams::logGUI()) - Log::info("[KartSelectionScreen]", "FocusDispatcher focused by player %u", + Log::info("KartSelectionScreen", "FocusDispatcher focused by player %u", player_id); // since this screen is multiplayer, redirect focus to the right widget diff --git a/src/states_screens/online/create_server_screen.cpp b/src/states_screens/online/create_server_screen.cpp index 1e82d5daa96..ebd3abed2ad 100644 --- a/src/states_screens/online/create_server_screen.cpp +++ b/src/states_screens/online/create_server_screen.cpp @@ -295,7 +295,7 @@ void CreateServerScreen::createServer() RibbonWidget* difficulty_widget = getWidget("difficulty"); RibbonWidget* gamemode_widget = getWidget("gamemode"); - +/* if (name.size() < 4 || name.size() > 30) { //I18N: In the create server screen @@ -303,7 +303,7 @@ void CreateServerScreen::createServer() _("Name has to be between 4 and 30 characters long!"), false); SFXManager::get()->quickSound("anvil"); return; - } + }*/ assert(max_players > 1 && max_players <= UserConfigParams::m_max_players.getDefaultValue()); diff --git a/src/tracks/drive_graph.cpp b/src/tracks/drive_graph.cpp index c06439df5df..fe8ec0c43e9 100644 --- a/src/tracks/drive_graph.cpp +++ b/src/tracks/drive_graph.cpp @@ -95,7 +95,7 @@ void DriveGraph::load(const std::string &quad_file_name, XMLNode *quad = file_manager->createXMLTree(quad_file_name); if (!quad || quad->getName() != "quads") { - Log::error("DriveGraph : Quad xml '%s' not found.", filename.c_str()); + Log::error("DriveGraph", "Quad xml '%s' not found.", filename.c_str()); delete quad; return; } diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 107787f1372..661fe936033 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -1888,7 +1888,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id) assert(m_all_cached_meshes.size()==0); if(UserConfigParams::logMemory()) { - Log::debug("[memory] Before loading '%s': mesh cache %d " + Log::debug("memory Before loading '%s': mesh cache %d " "texture cache %d", getIdent().c_str(), irr_driver->getSceneManager()->getMeshCache()->getMeshCount(), diff --git a/src/tracks/track_object.cpp b/src/tracks/track_object.cpp index f7c1402a6df..476520127c7 100644 --- a/src/tracks/track_object.cpp +++ b/src/tracks/track_object.cpp @@ -369,7 +369,7 @@ void TrackObject::init(const XMLNode &xml_node, scene::ISceneNode* parent, catch (std::runtime_error& e) { #ifndef SERVER_ONLY - Log::debug("TrackObject", e.what()); + Log::debug("TrackObject", "%s", e.what()); #endif } } diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp index 0afd848f55d..b3d95d3d80c 100644 --- a/src/utils/debug.cpp +++ b/src/utils/debug.cpp @@ -275,7 +275,7 @@ LightNode* findNearestLight() Camera* camera = Camera::getActiveCamera(); if (camera == NULL) { - Log::error("[Debug Menu]", "No camera found."); + Log::error("Debug Menu", "No camera found."); return NULL; } From 6c23f944b0672ee42c243f2e520ea2dfc0ab8bcd Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 29 Jun 2025 17:09:01 +0400 Subject: [PATCH 802/830] Try to fix windows c++17 build --- .github/workflows/apple.yml | 388 +++++++++--------- .github/workflows/linux.yml | 324 +++++++-------- .github/workflows/switch.yml | 220 +++++----- .github/workflows/windows.yml | 10 +- CMakeLists.txt | 25 ++ src/font/font_manager.cpp | 2 +- src/io/file_manager.cpp | 2 +- src/io/rich_presence.cpp | 8 +- src/network/socket_address.hpp | 2 +- src/network/stk_ipv6.cpp | 2 +- .../options/options_screen_language.cpp | 4 +- src/utils/file_utils.cpp | 2 +- src/utils/file_utils.hpp | 4 +- src/utils/time.cpp | 2 +- src/utils/translation.cpp | 2 +- 15 files changed, 515 insertions(+), 482 deletions(-) diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml index b5f71e67140..3b6a49b78fd 100644 --- a/.github/workflows/apple.yml +++ b/.github/workflows/apple.yml @@ -1,196 +1,196 @@ -name: apple -on: - push: - branches: - - master - tags: - - '*' - pull_request: {} - workflow_dispatch: +# name: apple +# on: +# push: +# branches: +# - master +# tags: +# - '*' +# pull_request: {} +# workflow_dispatch: -jobs: - build: +# jobs: +# build: - strategy: - fail-fast: true - matrix: - platform: [iPhoneOS, MacOSX] - arch: [arm64, x86_64] - exclude: - - platform: iPhoneOS - arch: x86_64 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - submodules: true - - id: sysroot - uses: ASzc/change-string-case-action@v1 - with: - string: ${{ matrix.platform }} - - name: Download cctools and ISPC - run: | - cd /opt - wget https://github.com/kimden/stk-dependencies/releases/download/cctools/cctools-14.1.tar.xz - tar xf cctools-14.1.tar.xz - rm cctools-14.1.tar.xz - wget https://github.com/supertuxkart/dependencies/releases/download/preview/ispc-cross-1.26.0.tar.xz - tar xf ispc-cross-1.26.0.tar.xz - rm ispc-cross-1.26.0.tar.xz - - name: Restore timestamps - run: | - wget https://github.com/MestreLion/git-tools/archive/refs/heads/main.zip - unzip main.zip - python git-tools-main/git-restore-mtime - - name: List build cache restore keys - run: | - # Look for the last 9 build caches (GitHub supports max 10 including current one) - for number in 1 2 3 4 5 6 7 8 9 - do - id=$((${{ github.run_number }} - number)) - echo "cache_$number=apple-${{ github.ref }}-${{ matrix.arch }}-${{ matrix.platform }}-$id" >> $GITHUB_ENV - done - - name: Handle build cache - uses: actions/cache@v3 - with: - path: | - build - key: apple-${{ github.ref }}-${{ matrix.arch }}-${{ matrix.platform }}-${{ github.run_number }} - restore-keys: | - ${{ env.cache_1 }} - ${{ env.cache_2 }} - ${{ env.cache_3 }} - ${{ env.cache_4 }} - ${{ env.cache_5 }} - ${{ env.cache_6 }} - ${{ env.cache_7 }} - ${{ env.cache_8 }} - ${{ env.cache_9 }} - - name: Download dependencies - run: | - wget https://github.com/kimden/stk-dependencies/releases/download/preview/dependencies-${{ steps.sysroot.outputs.lowercase }}.tar.xz - tar xf dependencies-${{ steps.sysroot.outputs.lowercase }}.tar.xz - - name: Configure clang runtime name - run: | - if [ ${{ matrix.platform }} = "MacOSX" ]; then - echo "rt=osx" >> $GITHUB_ENV - elif [ ${{ matrix.platform }} = "iPhoneOS" ]; then - echo "rt=ios" >> $GITHUB_ENV - elif [ ${{ matrix.platform }} = "AppleTVOS" ]; then - echo "rt=tvos" >> $GITHUB_ENV - elif [ ${{ matrix.platform }} = "iPhoneSimulator" ]; then - echo "rt=iossim" >> $GITHUB_ENV - elif [ ${{ matrix.platform }} = "AppleTVSimulator" ]; then - echo "rt=tvossim" >> $GITHUB_ENV - fi - - name: Configure bulid - run: | - mkdir -p build - cd build - cmake .. -DCCTOOLS_PREFIX=/opt/cctools -DCCTOOLS_ARCH=${{ matrix.arch }} -DCCTOOLS_PLATFORM=${{ matrix.platform }} \ - -DRT=/opt/cctools/darwin/libclang_rt.${{ env.rt }}.a -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cctools.cmake -DCHECK_ASSETS=OFF \ - -DBC7_ISPC=ON -DCMAKE_ISPC_COMPILER=/opt/ispc/bin/ispc - - name: Build - run: | - cd build - make -j4 - mv bin ../${{ steps.sysroot.outputs.lowercase }}-${{ matrix.arch }} - - name: Upload binaries - uses: actions/upload-artifact@v4 - with: - name: ${{ steps.sysroot.outputs.lowercase }}-${{ matrix.arch }} - path: ${{ steps.sysroot.outputs.lowercase }}-${{ matrix.arch }} - packaging: - name: Packaging STK - needs: build - runs-on: macos-latest - steps: - - name: Configure packaging name for git master branch - if: ${{ github.ref == 'refs/heads/master' }} - run: | - echo "release_tag=git`date +%Y%m%d`" >> $GITHUB_ENV - echo "release_name=preview" >> $GITHUB_ENV - - name: Configure packaging name for tag - if: ${{ startsWith(github.ref, 'refs/tags/') }} - run: | - echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV - echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV - - name: Configure packaging name for non-releasing branch - if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) || github.repository_owner != 'supertuxkart' }} - run: | - echo "release_tag=" >> $GITHUB_ENV - echo "release_name=" >> $GITHUB_ENV - - name: Check for prerelease - if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'rc') || contains(github.ref, 'beta') }} - run: | - echo "release_pre=true" >> $GITHUB_ENV - - name: Check for non-prerelease - if: ${{ github.ref != 'refs/heads/master' && !contains(github.ref, 'rc') && !contains(github.ref, 'beta') }} - run: | - echo "release_pre=false" >> $GITHUB_ENV - - name: Show packaging name - run : | - echo "${{ env.release_tag }}" - echo "${{ env.release_name }}" - echo "${{ env.release_pre }}" - - name: Download binaries - uses: actions/download-artifact@v4 - #- name: Mask developer name - # run: | - # echo "::add-mask::${{ secrets.MAC_DEVELOPER_NAME }}" - #- name: Import certificates - # if: ${{ env.release_tag != '' }} - # uses: apple-actions/import-codesign-certs@v1 - # with: - # p12-file-base64: ${{ secrets.MAC_DEVELOPER_ID_P12_FILE }} - # p12-password: ${{ secrets.MAC_DEVELOPER_ID_P12_PASSWORD }} - - name: Run dylibbundler and sign STK - if: ${{ env.release_tag != '' }} - # env: - # developer_id: "Developer ID Application: ${{ secrets.MAC_DEVELOPER_NAME }} (${{ secrets.MAC_DEVELOPER_TEAM }})" - run: | - wget https://github.com/kimden/stk-dependencies/releases/download/preview/dependencies-macosx.tar.xz - tar xf dependencies-macosx.tar.xz - HOMEBREW_NO_AUTO_UPDATE=1 brew install dylibbundler - lipo -create ./macosx-x86_64/supertuxkart.app/Contents/MacOS/supertuxkart ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -output ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart - chmod 755 ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart - install_name_tool -delete_rpath @loader_path/Frameworks ./dependencies-macosx/lib/libSDL2.dylib - install_name_tool -delete_rpath @executable_path/Frameworks ./dependencies-macosx/lib/libSDL2.dylib - dylibbundler -od -b -x ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -d ./macosx-arm64/supertuxkart.app/Contents/libs/ -p @executable_path/../libs/ -s ./dependencies-macosx/lib -ns - # We use SDL_Vulkan_LoadLibrary for 10.9 compatibility, so otool -L supertuxkart has no libMoltenVK.dylib - cp ./dependencies-macosx/lib/libMoltenVK.dylib ./macosx-arm64/supertuxkart.app/Contents/libs/ - cd ./macosx-arm64/supertuxkart.app/Contents/Resources/data - wget https://github.com/supertuxkart/stk-assets-mobile/releases/download/git/stk-assets-full.zip - unzip stk-assets-full.zip - rm stk-assets-full.zip - cd ../../../../.. - mv ./macosx-arm64/supertuxkart.app SuperTuxKart.app - # Use Ad Hoc certificate for now, previous certificate has been expired. - codesign --force -s - SuperTuxKart.app/Contents/libs/*.dylib - codesign --force --deep -s - SuperTuxKart.app - #codesign --force --sign "$developer_id" SuperTuxKart.app/Contents/libs/*.dylib - #codesign --force --options=runtime --deep --sign "$developer_id" SuperTuxKart.app - #- name: "Notarize release build" - # if: ${{ env.release_tag != '' && github.ref != 'refs/heads/master' }} - # run: | - # ditto -c -k --sequesterRsrc --keepParent SuperTuxKart.app tmp.zip - # xcrun notarytool submit tmp.zip --apple-id ${{ secrets.STK_NOTARIZATION_USERNAME }} \ - # --password ${{ secrets.STK_NOTARIZATION_PASSWORD }} \ - # --team-id ${{ secrets.MAC_DEVELOPER_TEAM }} --wait - # xcrun stapler staple SuperTuxKart.app - - name: Archive - if: ${{ env.release_tag != '' }} - run: | - ditto -c -k --sequesterRsrc --keepParent SuperTuxKart.app SuperTuxKart-${{ env.release_tag }}-mac.zip - - name: Create release - if: ${{ env.release_tag != '' }} - uses: ncipollo/release-action@v1.8.8 - with: - token: ${{ secrets.GITHUB_TOKEN }} - artifacts: "SuperTuxKart*.zip" - tag: ${{ env.release_name }} - omitBodyDuringUpdate: true - omitNameDuringUpdate: true - allowUpdates: true - prerelease: ${{ env.release_pre }} +# strategy: +# fail-fast: true +# matrix: +# platform: [iPhoneOS, MacOSX] +# arch: [arm64, x86_64] +# exclude: +# - platform: iPhoneOS +# arch: x86_64 +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v2 +# with: +# fetch-depth: 0 +# submodules: true +# - id: sysroot +# uses: ASzc/change-string-case-action@v1 +# with: +# string: ${{ matrix.platform }} +# - name: Download cctools and ISPC +# run: | +# cd /opt +# wget https://github.com/kimden/stk-dependencies/releases/download/cctools/cctools-14.1.tar.xz +# tar xf cctools-14.1.tar.xz +# rm cctools-14.1.tar.xz +# wget https://github.com/supertuxkart/dependencies/releases/download/preview/ispc-cross-1.26.0.tar.xz +# tar xf ispc-cross-1.26.0.tar.xz +# rm ispc-cross-1.26.0.tar.xz +# - name: Restore timestamps +# run: | +# wget https://github.com/MestreLion/git-tools/archive/refs/heads/main.zip +# unzip main.zip +# python git-tools-main/git-restore-mtime +# - name: List build cache restore keys +# run: | +# # Look for the last 9 build caches (GitHub supports max 10 including current one) +# for number in 1 2 3 4 5 6 7 8 9 +# do +# id=$((${{ github.run_number }} - number)) +# echo "cache_$number=apple-${{ github.ref }}-${{ matrix.arch }}-${{ matrix.platform }}-$id" >> $GITHUB_ENV +# done +# - name: Handle build cache +# uses: actions/cache@v3 +# with: +# path: | +# build +# key: apple-${{ github.ref }}-${{ matrix.arch }}-${{ matrix.platform }}-${{ github.run_number }} +# restore-keys: | +# ${{ env.cache_1 }} +# ${{ env.cache_2 }} +# ${{ env.cache_3 }} +# ${{ env.cache_4 }} +# ${{ env.cache_5 }} +# ${{ env.cache_6 }} +# ${{ env.cache_7 }} +# ${{ env.cache_8 }} +# ${{ env.cache_9 }} +# - name: Download dependencies +# run: | +# wget https://github.com/kimden/stk-dependencies/releases/download/preview/dependencies-${{ steps.sysroot.outputs.lowercase }}.tar.xz +# tar xf dependencies-${{ steps.sysroot.outputs.lowercase }}.tar.xz +# - name: Configure clang runtime name +# run: | +# if [ ${{ matrix.platform }} = "MacOSX" ]; then +# echo "rt=osx" >> $GITHUB_ENV +# elif [ ${{ matrix.platform }} = "iPhoneOS" ]; then +# echo "rt=ios" >> $GITHUB_ENV +# elif [ ${{ matrix.platform }} = "AppleTVOS" ]; then +# echo "rt=tvos" >> $GITHUB_ENV +# elif [ ${{ matrix.platform }} = "iPhoneSimulator" ]; then +# echo "rt=iossim" >> $GITHUB_ENV +# elif [ ${{ matrix.platform }} = "AppleTVSimulator" ]; then +# echo "rt=tvossim" >> $GITHUB_ENV +# fi +# - name: Configure bulid +# run: | +# mkdir -p build +# cd build +# cmake .. -DCCTOOLS_PREFIX=/opt/cctools -DCCTOOLS_ARCH=${{ matrix.arch }} -DCCTOOLS_PLATFORM=${{ matrix.platform }} \ +# -DRT=/opt/cctools/darwin/libclang_rt.${{ env.rt }}.a -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cctools.cmake -DCHECK_ASSETS=OFF \ +# -DBC7_ISPC=ON -DCMAKE_ISPC_COMPILER=/opt/ispc/bin/ispc +# - name: Build +# run: | +# cd build +# make -j4 +# mv bin ../${{ steps.sysroot.outputs.lowercase }}-${{ matrix.arch }} +# - name: Upload binaries +# uses: actions/upload-artifact@v4 +# with: +# name: ${{ steps.sysroot.outputs.lowercase }}-${{ matrix.arch }} +# path: ${{ steps.sysroot.outputs.lowercase }}-${{ matrix.arch }} +# packaging: +# name: Packaging STK +# needs: build +# runs-on: macos-latest +# steps: +# - name: Configure packaging name for git master branch +# if: ${{ github.ref == 'refs/heads/master' }} +# run: | +# echo "release_tag=git`date +%Y%m%d`" >> $GITHUB_ENV +# echo "release_name=preview" >> $GITHUB_ENV +# - name: Configure packaging name for tag +# if: ${{ startsWith(github.ref, 'refs/tags/') }} +# run: | +# echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV +# echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV +# - name: Configure packaging name for non-releasing branch +# if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) || github.repository_owner != 'supertuxkart' }} +# run: | +# echo "release_tag=" >> $GITHUB_ENV +# echo "release_name=" >> $GITHUB_ENV +# - name: Check for prerelease +# if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'rc') || contains(github.ref, 'beta') }} +# run: | +# echo "release_pre=true" >> $GITHUB_ENV +# - name: Check for non-prerelease +# if: ${{ github.ref != 'refs/heads/master' && !contains(github.ref, 'rc') && !contains(github.ref, 'beta') }} +# run: | +# echo "release_pre=false" >> $GITHUB_ENV +# - name: Show packaging name +# run : | +# echo "${{ env.release_tag }}" +# echo "${{ env.release_name }}" +# echo "${{ env.release_pre }}" +# - name: Download binaries +# uses: actions/download-artifact@v4 +# #- name: Mask developer name +# # run: | +# # echo "::add-mask::${{ secrets.MAC_DEVELOPER_NAME }}" +# #- name: Import certificates +# # if: ${{ env.release_tag != '' }} +# # uses: apple-actions/import-codesign-certs@v1 +# # with: +# # p12-file-base64: ${{ secrets.MAC_DEVELOPER_ID_P12_FILE }} +# # p12-password: ${{ secrets.MAC_DEVELOPER_ID_P12_PASSWORD }} +# - name: Run dylibbundler and sign STK +# if: ${{ env.release_tag != '' }} +# # env: +# # developer_id: "Developer ID Application: ${{ secrets.MAC_DEVELOPER_NAME }} (${{ secrets.MAC_DEVELOPER_TEAM }})" +# run: | +# wget https://github.com/kimden/stk-dependencies/releases/download/preview/dependencies-macosx.tar.xz +# tar xf dependencies-macosx.tar.xz +# HOMEBREW_NO_AUTO_UPDATE=1 brew install dylibbundler +# lipo -create ./macosx-x86_64/supertuxkart.app/Contents/MacOS/supertuxkart ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -output ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart +# chmod 755 ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart +# install_name_tool -delete_rpath @loader_path/Frameworks ./dependencies-macosx/lib/libSDL2.dylib +# install_name_tool -delete_rpath @executable_path/Frameworks ./dependencies-macosx/lib/libSDL2.dylib +# dylibbundler -od -b -x ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -d ./macosx-arm64/supertuxkart.app/Contents/libs/ -p @executable_path/../libs/ -s ./dependencies-macosx/lib -ns +# # We use SDL_Vulkan_LoadLibrary for 10.9 compatibility, so otool -L supertuxkart has no libMoltenVK.dylib +# cp ./dependencies-macosx/lib/libMoltenVK.dylib ./macosx-arm64/supertuxkart.app/Contents/libs/ +# cd ./macosx-arm64/supertuxkart.app/Contents/Resources/data +# wget https://github.com/supertuxkart/stk-assets-mobile/releases/download/git/stk-assets-full.zip +# unzip stk-assets-full.zip +# rm stk-assets-full.zip +# cd ../../../../.. +# mv ./macosx-arm64/supertuxkart.app SuperTuxKart.app +# # Use Ad Hoc certificate for now, previous certificate has been expired. +# codesign --force -s - SuperTuxKart.app/Contents/libs/*.dylib +# codesign --force --deep -s - SuperTuxKart.app +# #codesign --force --sign "$developer_id" SuperTuxKart.app/Contents/libs/*.dylib +# #codesign --force --options=runtime --deep --sign "$developer_id" SuperTuxKart.app +# #- name: "Notarize release build" +# # if: ${{ env.release_tag != '' && github.ref != 'refs/heads/master' }} +# # run: | +# # ditto -c -k --sequesterRsrc --keepParent SuperTuxKart.app tmp.zip +# # xcrun notarytool submit tmp.zip --apple-id ${{ secrets.STK_NOTARIZATION_USERNAME }} \ +# # --password ${{ secrets.STK_NOTARIZATION_PASSWORD }} \ +# # --team-id ${{ secrets.MAC_DEVELOPER_TEAM }} --wait +# # xcrun stapler staple SuperTuxKart.app +# - name: Archive +# if: ${{ env.release_tag != '' }} +# run: | +# ditto -c -k --sequesterRsrc --keepParent SuperTuxKart.app SuperTuxKart-${{ env.release_tag }}-mac.zip +# - name: Create release +# if: ${{ env.release_tag != '' }} +# uses: ncipollo/release-action@v1.8.8 +# with: +# token: ${{ secrets.GITHUB_TOKEN }} +# artifacts: "SuperTuxKart*.zip" +# tag: ${{ env.release_name }} +# omitBodyDuringUpdate: true +# omitNameDuringUpdate: true +# allowUpdates: true +# prerelease: ${{ env.release_pre }} diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 40982f8b40e..9c02dae936c 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -1,169 +1,169 @@ -# Copyright (C) 2020-2021 Jacob Burroughs -# 2020-2021 A. Semphris -# -# Released under the Creative Commons Zero (CC0) license, available at: -# Legal code: https://creativecommons.org/publicdomain/zero/1.0/legalcode -# Information: https://creativecommons.org/share-your-work/public-domain/cc0/ +# # Copyright (C) 2020-2021 Jacob Burroughs +# # 2020-2021 A. Semphris +# # +# # Released under the Creative Commons Zero (CC0) license, available at: +# # Legal code: https://creativecommons.org/publicdomain/zero/1.0/legalcode +# # Information: https://creativecommons.org/share-your-work/public-domain/cc0/ -# Note: Parts of this code were taken from the SuperTux project. -# ~ Semphris (responsible for transfering and adapting the file) +# # Note: Parts of this code were taken from the SuperTux project. +# # ~ Semphris (responsible for transfering and adapting the file) -name: linux -on: - push: - branches: - - master - tags: - - '*' - pull_request: {} - workflow_dispatch: +# name: linux +# on: +# push: +# branches: +# - master +# tags: +# - '*' +# pull_request: {} +# workflow_dispatch: -jobs: - build: +# jobs: +# build: - strategy: - fail-fast: true - matrix: - os: [ubuntu-latest] - compiler: [gcc, clang] - build_type: [Debug, RelWithDebInfo, Release] - server_only: [ON, OFF] - exclude: - - os: macos-latest - compiler: gcc - - os: macos-latest - build_type: Debug +# strategy: +# fail-fast: true +# matrix: +# os: [ubuntu-latest] +# compiler: [gcc, clang] +# build_type: [Debug, RelWithDebInfo, Release] +# server_only: [ON, OFF] +# exclude: +# - os: macos-latest +# compiler: gcc +# - os: macos-latest +# build_type: Debug - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 1 - submodules: true - - name: Configure packaging name for git master branch - if: ${{ matrix.build_type == 'Release' && matrix.server_only == 'OFF' && - github.ref == 'refs/heads/master' }} - run: | - echo "release_tag=git`date +%Y%m%d`" >> $GITHUB_ENV - echo "release_name=preview" >> $GITHUB_ENV - - name: Configure packaging name for tag - if: ${{ matrix.build_type == 'Release' && matrix.server_only == 'OFF' && - startsWith(github.ref, 'refs/tags/') }} - run: | - echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV - echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV - - name: Configure packaging name for non-releasing branch - if: ${{ matrix.build_type != 'Release' || matrix.server_only != 'OFF' || - !(github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) || - github.repository_owner != 'supertuxkart' }} - run: | - echo "release_tag=" >> $GITHUB_ENV - echo "release_name=" >> $GITHUB_ENV - - name: Check for prerelease - if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'rc') || contains(github.ref, 'beta') }} - run: | - echo "release_pre=true" >> $GITHUB_ENV - - name: Check for non-prerelease - if: ${{ github.ref != 'refs/heads/master' && !contains(github.ref, 'rc') && !contains(github.ref, 'beta') }} - run: | - echo "release_pre=false" >> $GITHUB_ENV - - name: Show packaging name - run : | - echo "${{ env.release_tag }}" - echo "${{ env.release_name }}" - echo "${{ env.release_pre }}" - - name: Install linux dependencies - if: ${{ matrix.os == 'ubuntu-latest' }} - run: | - sudo apt-get update - sudo apt install -y build-essential cmake libbluetooth-dev libcurl4-gnutls-dev \ - libfreetype6-dev libharfbuzz-dev libjpeg-dev libogg-dev libopenal-dev \ - libpng-dev libsdl2-dev libvorbis-dev pkg-config zlib1g-dev clang - - name: Install dylibbundler for packaging osx binary - if: ${{ env.release_tag != '' && matrix.os == 'macos-latest' && matrix.build_type == 'Release' && matrix.server_only == 'OFF' }} - run: | - HOMEBREW_NO_AUTO_UPDATE=1 brew install dylibbundler - - name: Install macos dependencies - if: ${{ matrix.os == 'macos-latest' }} - run: | - # Something funky happens with freetype if mono is left - sudo mv /Library/Frameworks/Mono.framework /Library/Frameworks/Mono.framework-disabled - wget https://github.com/supertuxkart/dependencies/releases/download/preview/dependencies-mac.tar.xz - # Remove any existing installation to avoid conflict with bundled dependencies - rm -rf /usr/local/include/* - rm -rf /usr/local/opt/openssl@1.1/include - rm -rf /usr/local/opt/freetype - rm -rf /usr/local/opt/harfbuzz - tar xf dependencies-mac.tar.xz -C /usr/local - rm dependencies-mac.tar.xz - - name: Set compiler (gcc) - if: ${{ matrix.os == 'ubuntu-latest' && matrix.compiler == 'gcc' }} - run: | - echo "CXX=g++" >> $GITHUB_ENV - echo "CC=gcc" >> $GITHUB_ENV - - name: Set compiler (clang) - if: ${{ matrix.os == 'ubuntu-latest' && matrix.compiler == 'clang' }} - run: | - echo "CXX=clang++" >> $GITHUB_ENV - echo "CC=clang" >> $GITHUB_ENV - - name: Set compiler (macos) - if: ${{ matrix.os == 'macos-latest' }} - run: | - # This ensures for now we use clang11 - # Clang12 runs into a bunch of fun with `include location '/usr/local/include' is unsafe for cross-compilation` - # that we don't care about for now - echo "CXX=clang++" >> $GITHUB_ENV - echo "CC=clang" >> $GITHUB_ENV - - name: Configure bulid (linux) - if: ${{ matrix.os != 'macos-latest' }} - env: - BUILD_TYPE: ${{ matrix.build_type }} - SERVER_ONLY: ${{ matrix.server_only }} - run: | - cmake --version - $CXX --version - mkdir "build" - cd "build" - cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSERVER_ONLY=$SERVER_ONLY -DCHECK_ASSETS=off -DBUILD_RECORDER=off -DNO_SHADERC=on; - - name: Configure bulid (macos) - if: ${{ matrix.os == 'macos-latest' }} - env: - BUILD_TYPE: ${{ matrix.build_type }} - SERVER_ONLY: ${{ matrix.server_only }} - run: | - cmake --version - $CXX --version - mkdir "build" - cd "build" - CFLAGS="-mmacosx-version-min=10.13" CXXFLAGS="-mmacosx-version-min=10.13" LINKFLAGS="-mmacosx-version-min=10.13" LDFLAGS="-mmacosx-version-min=10.13" /usr/local/opt/cmake/bin/cmake .. -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSERVER_ONLY=$SERVER_ONLY -DCHECK_ASSETS=off -DBUILD_RECORDER=off; - - name: Build and install - working-directory: build - run: | - make -j3 VERBOSE=1 - make install DESTDIR="/tmp/stk" VERBOSE=1 - - name: Packaging (macos) - if: ${{ env.release_tag != '' && matrix.os == 'macos-latest' && matrix.build_type == 'Release' && matrix.server_only == 'OFF' }} - working-directory: build - run: | - /usr/local/opt/dylibbundler/bin/dylibbundler -od -b -x ./bin/SuperTuxKart.app/Contents/MacOS/supertuxkart -d ./bin/SuperTuxKart.app/Contents/libs/ -p @executable_path/../libs/ - wget https://github.com/supertuxkart/stk-assets-mobile/releases/download/git/stk-assets-full.zip - unzip stk-assets-full.zip -d ../data - rm stk-assets-full.zip - cd bin - # Fix the name on case insensitive filesystem - mv supertuxkart.app stk.app - mv stk.app SuperTuxKart.app - zip -r ../SuperTuxKart-${{ env.release_tag }}-mac.zip . - - name: Create Release (macos) - if: ${{ env.release_tag != '' && matrix.os == 'macos-latest' && matrix.build_type == 'Release' && matrix.server_only == 'OFF' }} - uses: ncipollo/release-action@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - artifacts: "build/SuperTuxKart-${{ env.release_tag }}-mac.zip" - tag: ${{ env.release_name }} - omitBodyDuringUpdate: true - omitNameDuringUpdate: true - allowUpdates: true - prerelease: ${{ env.release_pre }} +# runs-on: ${{ matrix.os }} +# steps: +# - uses: actions/checkout@v2 +# with: +# fetch-depth: 1 +# submodules: true +# - name: Configure packaging name for git master branch +# if: ${{ matrix.build_type == 'Release' && matrix.server_only == 'OFF' && +# github.ref == 'refs/heads/master' }} +# run: | +# echo "release_tag=git`date +%Y%m%d`" >> $GITHUB_ENV +# echo "release_name=preview" >> $GITHUB_ENV +# - name: Configure packaging name for tag +# if: ${{ matrix.build_type == 'Release' && matrix.server_only == 'OFF' && +# startsWith(github.ref, 'refs/tags/') }} +# run: | +# echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV +# echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV +# - name: Configure packaging name for non-releasing branch +# if: ${{ matrix.build_type != 'Release' || matrix.server_only != 'OFF' || +# !(github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) || +# github.repository_owner != 'supertuxkart' }} +# run: | +# echo "release_tag=" >> $GITHUB_ENV +# echo "release_name=" >> $GITHUB_ENV +# - name: Check for prerelease +# if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'rc') || contains(github.ref, 'beta') }} +# run: | +# echo "release_pre=true" >> $GITHUB_ENV +# - name: Check for non-prerelease +# if: ${{ github.ref != 'refs/heads/master' && !contains(github.ref, 'rc') && !contains(github.ref, 'beta') }} +# run: | +# echo "release_pre=false" >> $GITHUB_ENV +# - name: Show packaging name +# run : | +# echo "${{ env.release_tag }}" +# echo "${{ env.release_name }}" +# echo "${{ env.release_pre }}" +# - name: Install linux dependencies +# if: ${{ matrix.os == 'ubuntu-latest' }} +# run: | +# sudo apt-get update +# sudo apt install -y build-essential cmake libbluetooth-dev libcurl4-gnutls-dev \ +# libfreetype6-dev libharfbuzz-dev libjpeg-dev libogg-dev libopenal-dev \ +# libpng-dev libsdl2-dev libvorbis-dev pkg-config zlib1g-dev clang +# - name: Install dylibbundler for packaging osx binary +# if: ${{ env.release_tag != '' && matrix.os == 'macos-latest' && matrix.build_type == 'Release' && matrix.server_only == 'OFF' }} +# run: | +# HOMEBREW_NO_AUTO_UPDATE=1 brew install dylibbundler +# - name: Install macos dependencies +# if: ${{ matrix.os == 'macos-latest' }} +# run: | +# # Something funky happens with freetype if mono is left +# sudo mv /Library/Frameworks/Mono.framework /Library/Frameworks/Mono.framework-disabled +# wget https://github.com/supertuxkart/dependencies/releases/download/preview/dependencies-mac.tar.xz +# # Remove any existing installation to avoid conflict with bundled dependencies +# rm -rf /usr/local/include/* +# rm -rf /usr/local/opt/openssl@1.1/include +# rm -rf /usr/local/opt/freetype +# rm -rf /usr/local/opt/harfbuzz +# tar xf dependencies-mac.tar.xz -C /usr/local +# rm dependencies-mac.tar.xz +# - name: Set compiler (gcc) +# if: ${{ matrix.os == 'ubuntu-latest' && matrix.compiler == 'gcc' }} +# run: | +# echo "CXX=g++" >> $GITHUB_ENV +# echo "CC=gcc" >> $GITHUB_ENV +# - name: Set compiler (clang) +# if: ${{ matrix.os == 'ubuntu-latest' && matrix.compiler == 'clang' }} +# run: | +# echo "CXX=clang++" >> $GITHUB_ENV +# echo "CC=clang" >> $GITHUB_ENV +# - name: Set compiler (macos) +# if: ${{ matrix.os == 'macos-latest' }} +# run: | +# # This ensures for now we use clang11 +# # Clang12 runs into a bunch of fun with `include location '/usr/local/include' is unsafe for cross-compilation` +# # that we don't care about for now +# echo "CXX=clang++" >> $GITHUB_ENV +# echo "CC=clang" >> $GITHUB_ENV +# - name: Configure bulid (linux) +# if: ${{ matrix.os != 'macos-latest' }} +# env: +# BUILD_TYPE: ${{ matrix.build_type }} +# SERVER_ONLY: ${{ matrix.server_only }} +# run: | +# cmake --version +# $CXX --version +# mkdir "build" +# cd "build" +# cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSERVER_ONLY=$SERVER_ONLY -DCHECK_ASSETS=off -DBUILD_RECORDER=off -DNO_SHADERC=on; +# - name: Configure bulid (macos) +# if: ${{ matrix.os == 'macos-latest' }} +# env: +# BUILD_TYPE: ${{ matrix.build_type }} +# SERVER_ONLY: ${{ matrix.server_only }} +# run: | +# cmake --version +# $CXX --version +# mkdir "build" +# cd "build" +# CFLAGS="-mmacosx-version-min=10.13" CXXFLAGS="-mmacosx-version-min=10.13" LINKFLAGS="-mmacosx-version-min=10.13" LDFLAGS="-mmacosx-version-min=10.13" /usr/local/opt/cmake/bin/cmake .. -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSERVER_ONLY=$SERVER_ONLY -DCHECK_ASSETS=off -DBUILD_RECORDER=off; +# - name: Build and install +# working-directory: build +# run: | +# make -j3 VERBOSE=1 +# make install DESTDIR="/tmp/stk" VERBOSE=1 +# - name: Packaging (macos) +# if: ${{ env.release_tag != '' && matrix.os == 'macos-latest' && matrix.build_type == 'Release' && matrix.server_only == 'OFF' }} +# working-directory: build +# run: | +# /usr/local/opt/dylibbundler/bin/dylibbundler -od -b -x ./bin/SuperTuxKart.app/Contents/MacOS/supertuxkart -d ./bin/SuperTuxKart.app/Contents/libs/ -p @executable_path/../libs/ +# wget https://github.com/supertuxkart/stk-assets-mobile/releases/download/git/stk-assets-full.zip +# unzip stk-assets-full.zip -d ../data +# rm stk-assets-full.zip +# cd bin +# # Fix the name on case insensitive filesystem +# mv supertuxkart.app stk.app +# mv stk.app SuperTuxKart.app +# zip -r ../SuperTuxKart-${{ env.release_tag }}-mac.zip . +# - name: Create Release (macos) +# if: ${{ env.release_tag != '' && matrix.os == 'macos-latest' && matrix.build_type == 'Release' && matrix.server_only == 'OFF' }} +# uses: ncipollo/release-action@v1 +# with: +# token: ${{ secrets.GITHUB_TOKEN }} +# artifacts: "build/SuperTuxKart-${{ env.release_tag }}-mac.zip" +# tag: ${{ env.release_name }} +# omitBodyDuringUpdate: true +# omitNameDuringUpdate: true +# allowUpdates: true +# prerelease: ${{ env.release_pre }} diff --git a/.github/workflows/switch.yml b/.github/workflows/switch.yml index 0d79d845d08..4a1a0f87c5d 100644 --- a/.github/workflows/switch.yml +++ b/.github/workflows/switch.yml @@ -1,113 +1,113 @@ -name: switch -on: - push: - branches: - - master - - feature/gh-actions-switch-cache - tags: - - '*' - pull_request: {} - workflow_dispatch: +# name: switch +# on: +# push: +# branches: +# - master +# - feature/gh-actions-switch-cache +# tags: +# - '*' +# pull_request: {} +# workflow_dispatch: -jobs: - build_switch: - name: Build Switch - runs-on: ubuntu-latest - container: - image: 'devkitpro/devkita64' - steps: - - name: Checkout code - uses: actions/checkout@v2 - with: - # We need 0 so we get all commits for mtime! - fetch-depth: 0 - path: "./stk-code" - - name: Grab assets - run: | - wget -q https://github.com/supertuxkart/stk-assets-mobile/releases/download/git/stk-assets-full.zip - unzip -q stk-assets-full.zip -d stk-assets - rm stk-assets-full.zip - - name: Restore modified date - run: | - cd stk-code - git restore-mtime . - cd .. +# jobs: +# build_switch: +# name: Build Switch +# runs-on: ubuntu-latest +# container: +# image: 'devkitpro/devkita64' +# steps: +# - name: Checkout code +# uses: actions/checkout@v2 +# with: +# # We need 0 so we get all commits for mtime! +# fetch-depth: 0 +# path: "./stk-code" +# - name: Grab assets +# run: | +# wget -q https://github.com/supertuxkart/stk-assets-mobile/releases/download/git/stk-assets-full.zip +# unzip -q stk-assets-full.zip -d stk-assets +# rm stk-assets-full.zip +# - name: Restore modified date +# run: | +# cd stk-code +# git restore-mtime . +# cd .. - # Env setup! - - name: Configure packaging name for git master branch - if: ${{ github.ref == 'refs/heads/master' }} - run: | - echo "release_tag=git`date +%Y%m%d`" >> $GITHUB_ENV - echo "release_name=preview" >> $GITHUB_ENV - - name: Configure packaging name for tag - if: ${{ startsWith(github.ref, 'refs/tags/') }} - run: | - echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV - echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV - - name: Configure packaging name for non-releasing branch - if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) || github.repository_owner != 'supertuxkart' }} - run: | - echo "release_tag=" >> $GITHUB_ENV - echo "release_name=" >> $GITHUB_ENV - - name: Check for prerelease - if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'rc') || contains(github.ref, 'beta') }} - run: | - echo "release_pre=true" >> $GITHUB_ENV - - name: Check for non-prerelease - if: ${{ github.ref != 'refs/heads/master' && !contains(github.ref, 'rc') && !contains(github.ref, 'beta') }} - run: | - echo "release_pre=false" >> $GITHUB_ENV - - name: Show packaging name - run : | - echo "${{ env.release_tag }}" - echo "${{ env.release_name }}" - echo "${{ env.release_pre }}" - - name: List build cache restore keys - shell : bash - run: | - # Look for the last 9 build caches (GitHub supports max 10 including current one) - for number in 1 2 3 4 5 6 7 8 9 - do - id=$((${{ github.run_number }} - number)) - echo "cache_$number=switch-${{ github.ref }}-$id" >> $GITHUB_ENV - done - - name: Handle build cache - uses: actions/cache@v3 - with: - # This is unnecessarily verbose and might break, but again ! seems broken - # See: https://github.com/Mstrodl/stk-code/runs/2333673736?check_suite_focus=true#step:16:34 - path: | - stk-code/cmake_build/CMakeFiles - stk-code/cmake_build/Makefile - stk-code/cmake_build/lib - stk-code/cmake_build/bin/supertuxkart - stk-code/cmake_build/*.cmake - stk-code/cmake_build/*.txt +# # Env setup! +# - name: Configure packaging name for git master branch +# if: ${{ github.ref == 'refs/heads/master' }} +# run: | +# echo "release_tag=git`date +%Y%m%d`" >> $GITHUB_ENV +# echo "release_name=preview" >> $GITHUB_ENV +# - name: Configure packaging name for tag +# if: ${{ startsWith(github.ref, 'refs/tags/') }} +# run: | +# echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV +# echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV +# - name: Configure packaging name for non-releasing branch +# if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) || github.repository_owner != 'supertuxkart' }} +# run: | +# echo "release_tag=" >> $GITHUB_ENV +# echo "release_name=" >> $GITHUB_ENV +# - name: Check for prerelease +# if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'rc') || contains(github.ref, 'beta') }} +# run: | +# echo "release_pre=true" >> $GITHUB_ENV +# - name: Check for non-prerelease +# if: ${{ github.ref != 'refs/heads/master' && !contains(github.ref, 'rc') && !contains(github.ref, 'beta') }} +# run: | +# echo "release_pre=false" >> $GITHUB_ENV +# - name: Show packaging name +# run : | +# echo "${{ env.release_tag }}" +# echo "${{ env.release_name }}" +# echo "${{ env.release_pre }}" +# - name: List build cache restore keys +# shell : bash +# run: | +# # Look for the last 9 build caches (GitHub supports max 10 including current one) +# for number in 1 2 3 4 5 6 7 8 9 +# do +# id=$((${{ github.run_number }} - number)) +# echo "cache_$number=switch-${{ github.ref }}-$id" >> $GITHUB_ENV +# done +# - name: Handle build cache +# uses: actions/cache@v3 +# with: +# # This is unnecessarily verbose and might break, but again ! seems broken +# # See: https://github.com/Mstrodl/stk-code/runs/2333673736?check_suite_focus=true#step:16:34 +# path: | +# stk-code/cmake_build/CMakeFiles +# stk-code/cmake_build/Makefile +# stk-code/cmake_build/lib +# stk-code/cmake_build/bin/supertuxkart +# stk-code/cmake_build/*.cmake +# stk-code/cmake_build/*.txt - # Make sure PRs can't overwrite! - key: switch-${{ github.ref }}-${{ github.run_number }} - restore-keys: | - ${{ env.cache_1 }} - ${{ env.cache_2 }} - ${{ env.cache_3 }} - ${{ env.cache_4 }} - ${{ env.cache_5 }} - ${{ env.cache_6 }} - ${{ env.cache_7 }} - ${{ env.cache_8 }} - ${{ env.cache_9 }} - - name: Run build script - run: | - cd stk-code/switch - PROJECT_VERSION="${{ env.release_tag }}" ./make.sh - - name: Create release - uses: ncipollo/release-action@v1.8.8 - if: ${{ env.release_tag != '' }} - with: - token: ${{ secrets.GITHUB_TOKEN }} - artifacts: "stk-code/cmake_build/bin/SuperTuxKart-${{ env.release_tag }}-switch.zip" - tag: ${{ env.release_name }} - omitBodyDuringUpdate: true - omitNameDuringUpdate: true - allowUpdates: true - prerelease: ${{ env.release_pre }} +# # Make sure PRs can't overwrite! +# key: switch-${{ github.ref }}-${{ github.run_number }} +# restore-keys: | +# ${{ env.cache_1 }} +# ${{ env.cache_2 }} +# ${{ env.cache_3 }} +# ${{ env.cache_4 }} +# ${{ env.cache_5 }} +# ${{ env.cache_6 }} +# ${{ env.cache_7 }} +# ${{ env.cache_8 }} +# ${{ env.cache_9 }} +# - name: Run build script +# run: | +# cd stk-code/switch +# PROJECT_VERSION="${{ env.release_tag }}" ./make.sh +# - name: Create release +# uses: ncipollo/release-action@v1.8.8 +# if: ${{ env.release_tag != '' }} +# with: +# token: ${{ secrets.GITHUB_TOKEN }} +# artifacts: "stk-code/cmake_build/bin/SuperTuxKart-${{ env.release_tag }}-switch.zip" +# tag: ${{ env.release_name }} +# omitBodyDuringUpdate: true +# omitNameDuringUpdate: true +# allowUpdates: true +# prerelease: ${{ env.release_pre }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index b3b8b940e6a..b1313fe844f 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -11,7 +11,7 @@ on: jobs: build: strategy: - fail-fast: true + fail-fast: false matrix: arch: [i686, x86_64, armv7, aarch64] os: [windows-latest, ubuntu-latest] @@ -129,6 +129,14 @@ jobs: echo "set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)" >> toolchain.cmake echo 'set(ISPC_ARCH "x86-64")' >> toolchain.cmake # Manually specify CMAKE_SYSTEM_PROCESSOR, it can only be set together with -DDCMAKE_SYSTEM_NAME + # - name: Check compiler version for MSVC + # if: ${{ matrix.os == 'windows-latest' }} + # run: | + # cl.exe /? + - name: Check compiler version for MinGW + if: ${{ matrix.os == 'ubuntu-latest' }} + run: | + g++ --version - name: Configure bulid for MSVC if: ${{ matrix.os == 'windows-latest' }} run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 14e3f45ee45..7e5780eaf33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -530,6 +530,14 @@ if(UNIX OR MINGW) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused-function") endif() +if(MINGW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") +endif() + +if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17") +endif() + if(MINGW AND CMAKE_BUILD_TYPE MATCHES Release) SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--subsystem,windows") endif() @@ -853,6 +861,7 @@ if(USE_WIIUSE) endif() if(MSVC OR MINGW) + add_definitions(-DWIN_BUILD) target_link_libraries(supertuxkart iphlpapi.lib) add_custom_command(TARGET supertuxkart POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory @@ -958,3 +967,19 @@ if(MINGW) install(DIRECTORY ${CMAKE_BINARY_DIR}/bin/ DESTINATION ${STK_INSTALL_BINARY_DIR} FILES_MATCHING PATTERN "*.dll") endif() + +include(CheckCXXSourceCompiles) + +check_cxx_source_compiles(" + #include + int main() { + std::optional o; + return 0; + } +" HAS_STD_OPTIONAL) + +if(NOT HAS_STD_OPTIONAL) + message(FATAL_ERROR "The compiler does not support std::optional") +else() + message("The compiler supports std::optional") +endif() \ No newline at end of file diff --git a/src/font/font_manager.cpp b/src/font/font_manager.cpp index ab4bd79faf2..01e67ba8a30 100644 --- a/src/font/font_manager.cpp +++ b/src/font/font_manager.cpp @@ -909,7 +909,7 @@ void FontManager::unitTesting() // Hide gettext warning Log::setLogLevel(5); delete translations; -#ifdef WIN32 +#if defined(WIN_BUILD) std::string s=std::string("LANGUAGE=") + lang.c_str(); _putenv(s.c_str()); #else diff --git a/src/io/file_manager.cpp b/src/io/file_manager.cpp index 77ccf5c886f..47f4d19d025 100644 --- a/src/io/file_manager.cpp +++ b/src/io/file_manager.cpp @@ -921,7 +921,7 @@ bool FileManager::checkAndCreateDirectory(const std::string &path) Log::info("FileManager", "Creating directory '%s'.", path.c_str()); // Otherwise try to create the directory: -#if defined(WIN32) +#if defined(WIN_BUILD) bool error = _wmkdir(StringUtils::utf8ToWide(path).c_str()) != 0; #else bool error = mkdir(path.c_str(), 0777) != 0; diff --git a/src/io/rich_presence.cpp b/src/io/rich_presence.cpp index 694e3bac4c6..858c9b393ba 100644 --- a/src/io/rich_presence.cpp +++ b/src/io/rich_presence.cpp @@ -21,7 +21,7 @@ #include "online/request_manager.hpp" #include "online/http_request.hpp" -#if defined(__SWITCH__) || defined(MOBILE_STK) || defined(SERVER_ONLY) +#if defined(__SWITCH__) || defined(MOBILE_STK) || defined(SERVER_ONLY) || defined(__MINGW32__) || defined(__MINGW64__) #define DISABLE_RPC #endif @@ -77,7 +77,7 @@ void RichPresence::destroy() } RichPresence::RichPresence() : m_connected(false), m_ready(false), m_last(0), -#ifdef WIN32 +#if defined(WIN32) && !(defined(__MINGW32__) || defined(__MINGW64__)) m_socket(INVALID_HANDLE_VALUE), #else m_socket(-1), @@ -204,7 +204,7 @@ void RichPresence::readData() #ifndef DISABLE_RPC size_t baseLength = sizeof(int32_t) * 2; struct discordPacket* basePacket = (struct discordPacket*) malloc(baseLength); -#ifdef WIN32 +#if defined(WIN32) DWORD read; if (!ReadFile(m_socket, basePacket, baseLength, &read, NULL)) { @@ -229,7 +229,7 @@ void RichPresence::readData() // Copy over length and opcode from base packet memcpy(packet, basePacket, baseLength); free(basePacket); -#ifdef WIN32 +#if defined(WIN32) if (!ReadFile(m_socket, packet->data, packet->length, &read, NULL)) { Log::error("RichPresence", "Couldn't read from pipe! Error %x", GetLastError()); diff --git a/src/network/socket_address.hpp b/src/network/socket_address.hpp index 75c3c9922fc..5d0bb321ccb 100644 --- a/src/network/socket_address.hpp +++ b/src/network/socket_address.hpp @@ -23,7 +23,7 @@ #include "utils/types.hpp" -#ifdef WIN32 +#if defined(WIN32) || defined(__MINGW32__) || defined(__MINGW64__) # include # include #else diff --git a/src/network/stk_ipv6.cpp b/src/network/stk_ipv6.cpp index a91c9178caa..d91f4b6e52f 100644 --- a/src/network/stk_ipv6.cpp +++ b/src/network/stk_ipv6.cpp @@ -16,7 +16,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include -#ifdef WIN32 +#if defined(WIN32) || defined(__MINGW32__) || defined(__MINGW64__) #ifdef __GNUC__ # include // Mingw / gcc on windows # undef _WIN32_WINNT diff --git a/src/states_screens/options/options_screen_language.cpp b/src/states_screens/options/options_screen_language.cpp index 1967635fb43..ad315e7f34c 100644 --- a/src/states_screens/options/options_screen_language.cpp +++ b/src/states_screens/options/options_screen_language.cpp @@ -126,7 +126,7 @@ void OptionsScreenLanguage::eventCallback(Widget* widget, const std::string& nam if (selection == "system") { -#ifdef WIN32 +#ifdef WIN_BUILD _putenv("LANGUAGE="); #else unsetenv("LANGUAGE"); @@ -134,7 +134,7 @@ void OptionsScreenLanguage::eventCallback(Widget* widget, const std::string& nam } else { -#ifdef WIN32 +#ifdef WIN_BUILD std::string s=std::string("LANGUAGE=")+selection.c_str(); _putenv(s.c_str()); #else diff --git a/src/utils/file_utils.cpp b/src/utils/file_utils.cpp index b2ca319f3fa..acc3a51d64f 100644 --- a/src/utils/file_utils.cpp +++ b/src/utils/file_utils.cpp @@ -24,7 +24,7 @@ #include // ---------------------------------------------------------------------------- -#if defined(WIN32) +#if defined(WIN_BUILD) #include // ---------------------------------------------------------------------------- namespace u8checker diff --git a/src/utils/file_utils.hpp b/src/utils/file_utils.hpp index f7d2abd8bf7..1a42cfa91b5 100644 --- a/src/utils/file_utils.hpp +++ b/src/utils/file_utils.hpp @@ -43,7 +43,7 @@ namespace FileUtils * u8_path is unicode encoded. */ inline std::string getPortableWritingPath(const std::string& u8_path) { -#if defined(WIN32) +#if defined(WIN_BUILD) return Private::getShortPathWriting(u8_path); #else return u8_path; @@ -54,7 +54,7 @@ namespace FileUtils * is unicode encoded. */ inline std::string getPortableReadingPath(const std::string& u8_path) { -#if defined(WIN32) +#if defined(WIN_BUILD) return Private::getShortPath(u8_path); #else return u8_path; diff --git a/src/utils/time.cpp b/src/utils/time.cpp index ce25dee3564..88ae27c40c9 100644 --- a/src/utils/time.cpp +++ b/src/utils/time.cpp @@ -57,7 +57,7 @@ std::string StkTime::getLogTimeFormatted(std::string&& format) time_t time_now = 0; time(&time_now); std::tm timeptr = {}; -#ifdef WIN32 +#ifdef WIN_BUILD localtime_s(&timeptr, &time_now); #else localtime_r(&time_now, &timeptr); diff --git a/src/utils/translation.cpp b/src/utils/translation.cpp index de7af7dab9f..e5ab32e9422 100644 --- a/src/utils/translation.cpp +++ b/src/utils/translation.cpp @@ -309,7 +309,7 @@ Translations::Translations() //: m_dictionary_manager("UTF-16") // LC_ALL does not work, sscanf will then not always be able // to scan for example: s=-1.1,-2.3,-3.3 correctly, which is // used in driveline files. -#if defined(WIN32) && !defined(__CYGWIN__) +#if defined(WIN_BUILD) && !defined(__CYGWIN__) // Windows does not have LC_MESSAGES setlocale(LC_CTYPE, ""); #else From a08b7e403a96477b98bc3368b945d8f290944aa0 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 1 Jul 2025 02:39:59 +0400 Subject: [PATCH 803/830] Try to fix mxe --- .github/workflows/windows.yml | 38 ++++++++++++++++++++++------------- cmake/Toolchain-cctools.cmake | 2 +- tools/build-cross-ispc.sh | 2 +- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index b1313fe844f..761fd50091d 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -13,8 +13,10 @@ jobs: strategy: fail-fast: false matrix: - arch: [i686, x86_64, armv7, aarch64] - os: [windows-latest, ubuntu-latest] + arch: [i686, x86_64] + os: [ubuntu-latest] + # arch: [i686, x86_64, armv7, aarch64] + # os: [windows-latest, ubuntu-latest] exclude: - arch: armv7 os: windows-latest @@ -76,7 +78,7 @@ jobs: ${{ env.cache_9 }} - name: Download dependencies run: | - ${{ env.wget }} https://github.com/supertuxkart/dependencies/releases/download/preview/dependencies-win-${{ matrix.arch }}.zip + ${{ env.wget }} https://github.com/kimden/stk-dependencies/releases/download/preview/dependencies-win-${{ matrix.arch }}.zip ${{ env.unzip }} dependencies-win-${{ matrix.arch }}.zip - name: Download ISPC for MinGW if: ${{ matrix.os == 'ubuntu-latest' }} @@ -92,7 +94,7 @@ jobs: sudo mkdir -p /data/mxe/usr cd /data/mxe/usr # It's compiled from https://github.com/mxe/mxe - sudo wget https://github.com/supertuxkart/dependencies/releases/download/preview/mxe_static_mingw.zip + sudo wget https://github.com/kimden/stk-dependencies/releases/download/preview/mxe_static_mingw.zip sudo unzip mxe_static_mingw.zip sudo rm mxe_static_mingw.zip # For libfl.so.2 @@ -107,11 +109,13 @@ jobs: - name: Set up MinGW Toolchain for i686 if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch == 'i686' }} run: | + # export PATH=/data/mxe/usr/bin:$PATH echo "SET(CMAKE_SYSTEM_NAME Windows)" > toolchain.cmake echo "SET(CMAKE_C_COMPILER /data/mxe/usr/bin/i686-w64-mingw32.static.posix.dw2-gcc)" >> toolchain.cmake echo "SET(CMAKE_CXX_COMPILER /data/mxe/usr/bin/i686-w64-mingw32.static.posix.dw2-g++)" >> toolchain.cmake + #echo "SET(CMAKE_ASM_COMPILER /data/mxe/usr/bin/i686-w64-mingw32.static.posix.dw2-as)" >> toolchain.cmake echo "SET(CMAKE_RC_COMPILER /data/mxe/usr/bin/i686-w64-mingw32.static.posix.dw2-windres)" >> toolchain.cmake - echo "SET(CMAKE_FIND_ROOT_PATH \${PROJECT_SOURCE_DIR}/dependencies-win-i686 /data/mxe/usr/i686-w64-mingw32.static.posix.dw2/ /data/mxe/usr/lib/gcc/i686-w64-mingw32.static.posix.dw2/5.5.0/)" >> toolchain.cmake + echo "SET(CMAKE_FIND_ROOT_PATH \${PROJECT_SOURCE_DIR}/dependencies-win-i686 /data/mxe/usr/i686-w64-mingw32.static.posix.dw2/ /data/mxe/usr/lib/gcc/i686-w64-mingw32.static.posix.dw2/11.5.0/)" >> toolchain.cmake echo "set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)" >> toolchain.cmake echo "set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ALWAYS)" >> toolchain.cmake echo "set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)" >> toolchain.cmake @@ -119,11 +123,13 @@ jobs: - name: Set up MinGW Toolchain for x86_64 if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch == 'x86_64' }} run: | + # export PATH=/data/mxe/usr/bin:$PATH echo "SET(CMAKE_SYSTEM_NAME Windows)" > toolchain.cmake echo "SET(CMAKE_C_COMPILER /data/mxe/usr/bin/x86_64-w64-mingw32.static.posix.seh-gcc)" >> toolchain.cmake echo "SET(CMAKE_CXX_COMPILER /data/mxe/usr/bin/x86_64-w64-mingw32.static.posix.seh-g++)" >> toolchain.cmake + #echo "SET(CMAKE_ASM_COMPILER /data/mxe/usr/bin/x86_64-w64-mingw32.static.posix.seh-as)" >> toolchain.cmake echo "SET(CMAKE_RC_COMPILER /data/mxe/usr/bin/x86_64-w64-mingw32.static.posix.seh-windres)" >> toolchain.cmake - echo "SET(CMAKE_FIND_ROOT_PATH \${PROJECT_SOURCE_DIR}/dependencies-win-x86_64 /data/mxe/usr/x86_64-w64-mingw32.static.posix.seh/ /data/mxe/usr/lib/gcc/x86_64-w64-mingw32.static.posix.seh/5.5.0/)" >> toolchain.cmake + echo "SET(CMAKE_FIND_ROOT_PATH \${PROJECT_SOURCE_DIR}/dependencies-win-x86_64 /data/mxe/usr/x86_64-w64-mingw32.static.posix.seh/ /data/mxe/usr/lib/gcc/x86_64-w64-mingw32.static.posix.seh/11.5.0/)" >> toolchain.cmake echo "set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)" >> toolchain.cmake echo "set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ALWAYS)" >> toolchain.cmake echo "set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)" >> toolchain.cmake @@ -133,23 +139,27 @@ jobs: # if: ${{ matrix.os == 'windows-latest' }} # run: | # cl.exe /? - - name: Check compiler version for MinGW - if: ${{ matrix.os == 'ubuntu-latest' }} - run: | - g++ --version - - name: Configure bulid for MSVC + # - name: Check compiler version for MinGW i686 + # if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch == 'i686' }} + # run: | + # /data/mxe/usr/bin/i686-w64-mingw32.static.posix.dw2-g++ --version + # - name: Check compiler version for MinGW x86_64 + # if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch == 'x86_64' }} + # run: | + # /data/mxe/usr/bin/x86_64-w64-mingw32.static.posix.seh-g++ --version + - name: Configure build for MSVC if: ${{ matrix.os == 'windows-latest' }} run: | mkdir -Force build cd build cmake .. -G "Visual Studio 17 2022" -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_PROCESSOR=${{ matrix.arch }} -A ${{ env.cmake_arch }} -DCHECK_ASSETS=OFF - - name: Configure bulid for MinGW (i686 or x86_64) + - name: Configure build for MinGW (i686 or x86_64) if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch != 'armv7' && matrix.arch != 'aarch64' }} run: | mkdir -p build cd build - cmake .. -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCHECK_ASSETS=OFF -DUSE_DIRECTX=ON -DBC7_ISPC=ON -DCMAKE_ISPC_COMPILER=/opt/ispc/bin/ispc - - name: Configure bulid for MinGW (armv7 or aarch64) + cmake .. -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCHECK_ASSETS=OFF -DUSE_DIRECTX=ON -DBC7_ISPC=ON -DCMAKE_ISPC_COMPILER=/opt/ispc/bin/ispc + - name: Configure build for MinGW (armv7 or aarch64) if: ${{ matrix.os == 'ubuntu-latest' && ( matrix.arch == 'armv7' || matrix.arch == 'aarch64' ) }} run: | mkdir -p build diff --git a/cmake/Toolchain-cctools.cmake b/cmake/Toolchain-cctools.cmake index d9dee71b3fc..0a1767242f9 100644 --- a/cmake/Toolchain-cctools.cmake +++ b/cmake/Toolchain-cctools.cmake @@ -1,7 +1,7 @@ # Usage: # cmake .. -DCCTOOLS_PREFIX=/path/to/cctools -DCCTOOLS_ARCH=arch -DCCTOOLS_PLATFORM=platform \ # -DRT=/path/to/cctools/darwin/libclang_rt.{ios, iossim, osx, tvos, tvossim}.a -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cctools.cmake -# Download precompiled cctools at https://github.com/supertuxkart/dependencies/releases/download/preview/cctools.tar.xz +# Download precompiled cctools at https://github.com/kimden/stk-dependencies/releases/download/preview/cctools.tar.xz # Compiled in Ubuntu 18.04 # the name of the target operating system diff --git a/tools/build-cross-ispc.sh b/tools/build-cross-ispc.sh index 49e522b177f..cee5116537b 100755 --- a/tools/build-cross-ispc.sh +++ b/tools/build-cross-ispc.sh @@ -56,7 +56,7 @@ EOF apt-get update apt install -y build-essential llvm cmake clang m4 bison flex libtbb-dev libclang-18-dev libclang-cpp-dev gcc-multilib g++-multilib cd /opt -wget https://github.com/supertuxkart/dependencies/releases/download/cctools/cctools-14.1.tar.xz +wget https://github.com/kimden/stk-dependencies/releases/download/cctools/cctools-14.1.tar.xz tar xf cctools-14.1.tar.xz rm cctools-14.1.tar.xz cd From 31366bf0a8c0bc2fd9ea82081899616efe963ff2 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 4 Jul 2025 00:49:30 +0400 Subject: [PATCH 804/830] Cleanup after fixing windows build --- .github/workflows/apple.yml | 388 ++++++++++++++++----------------- .github/workflows/linux.yml | 324 +++++++++++++-------------- .github/workflows/switch.yml | 220 +++++++++---------- .github/workflows/windows.yml | 26 +-- CMakeLists.txt | 16 -- src/network/socket_address.hpp | 2 +- src/network/stk_ipv6.cpp | 2 +- 7 files changed, 472 insertions(+), 506 deletions(-) diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml index 3b6a49b78fd..b5f71e67140 100644 --- a/.github/workflows/apple.yml +++ b/.github/workflows/apple.yml @@ -1,196 +1,196 @@ -# name: apple -# on: -# push: -# branches: -# - master -# tags: -# - '*' -# pull_request: {} -# workflow_dispatch: +name: apple +on: + push: + branches: + - master + tags: + - '*' + pull_request: {} + workflow_dispatch: -# jobs: -# build: +jobs: + build: -# strategy: -# fail-fast: true -# matrix: -# platform: [iPhoneOS, MacOSX] -# arch: [arm64, x86_64] -# exclude: -# - platform: iPhoneOS -# arch: x86_64 -# runs-on: ubuntu-latest -# steps: -# - uses: actions/checkout@v2 -# with: -# fetch-depth: 0 -# submodules: true -# - id: sysroot -# uses: ASzc/change-string-case-action@v1 -# with: -# string: ${{ matrix.platform }} -# - name: Download cctools and ISPC -# run: | -# cd /opt -# wget https://github.com/kimden/stk-dependencies/releases/download/cctools/cctools-14.1.tar.xz -# tar xf cctools-14.1.tar.xz -# rm cctools-14.1.tar.xz -# wget https://github.com/supertuxkart/dependencies/releases/download/preview/ispc-cross-1.26.0.tar.xz -# tar xf ispc-cross-1.26.0.tar.xz -# rm ispc-cross-1.26.0.tar.xz -# - name: Restore timestamps -# run: | -# wget https://github.com/MestreLion/git-tools/archive/refs/heads/main.zip -# unzip main.zip -# python git-tools-main/git-restore-mtime -# - name: List build cache restore keys -# run: | -# # Look for the last 9 build caches (GitHub supports max 10 including current one) -# for number in 1 2 3 4 5 6 7 8 9 -# do -# id=$((${{ github.run_number }} - number)) -# echo "cache_$number=apple-${{ github.ref }}-${{ matrix.arch }}-${{ matrix.platform }}-$id" >> $GITHUB_ENV -# done -# - name: Handle build cache -# uses: actions/cache@v3 -# with: -# path: | -# build -# key: apple-${{ github.ref }}-${{ matrix.arch }}-${{ matrix.platform }}-${{ github.run_number }} -# restore-keys: | -# ${{ env.cache_1 }} -# ${{ env.cache_2 }} -# ${{ env.cache_3 }} -# ${{ env.cache_4 }} -# ${{ env.cache_5 }} -# ${{ env.cache_6 }} -# ${{ env.cache_7 }} -# ${{ env.cache_8 }} -# ${{ env.cache_9 }} -# - name: Download dependencies -# run: | -# wget https://github.com/kimden/stk-dependencies/releases/download/preview/dependencies-${{ steps.sysroot.outputs.lowercase }}.tar.xz -# tar xf dependencies-${{ steps.sysroot.outputs.lowercase }}.tar.xz -# - name: Configure clang runtime name -# run: | -# if [ ${{ matrix.platform }} = "MacOSX" ]; then -# echo "rt=osx" >> $GITHUB_ENV -# elif [ ${{ matrix.platform }} = "iPhoneOS" ]; then -# echo "rt=ios" >> $GITHUB_ENV -# elif [ ${{ matrix.platform }} = "AppleTVOS" ]; then -# echo "rt=tvos" >> $GITHUB_ENV -# elif [ ${{ matrix.platform }} = "iPhoneSimulator" ]; then -# echo "rt=iossim" >> $GITHUB_ENV -# elif [ ${{ matrix.platform }} = "AppleTVSimulator" ]; then -# echo "rt=tvossim" >> $GITHUB_ENV -# fi -# - name: Configure bulid -# run: | -# mkdir -p build -# cd build -# cmake .. -DCCTOOLS_PREFIX=/opt/cctools -DCCTOOLS_ARCH=${{ matrix.arch }} -DCCTOOLS_PLATFORM=${{ matrix.platform }} \ -# -DRT=/opt/cctools/darwin/libclang_rt.${{ env.rt }}.a -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cctools.cmake -DCHECK_ASSETS=OFF \ -# -DBC7_ISPC=ON -DCMAKE_ISPC_COMPILER=/opt/ispc/bin/ispc -# - name: Build -# run: | -# cd build -# make -j4 -# mv bin ../${{ steps.sysroot.outputs.lowercase }}-${{ matrix.arch }} -# - name: Upload binaries -# uses: actions/upload-artifact@v4 -# with: -# name: ${{ steps.sysroot.outputs.lowercase }}-${{ matrix.arch }} -# path: ${{ steps.sysroot.outputs.lowercase }}-${{ matrix.arch }} -# packaging: -# name: Packaging STK -# needs: build -# runs-on: macos-latest -# steps: -# - name: Configure packaging name for git master branch -# if: ${{ github.ref == 'refs/heads/master' }} -# run: | -# echo "release_tag=git`date +%Y%m%d`" >> $GITHUB_ENV -# echo "release_name=preview" >> $GITHUB_ENV -# - name: Configure packaging name for tag -# if: ${{ startsWith(github.ref, 'refs/tags/') }} -# run: | -# echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV -# echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV -# - name: Configure packaging name for non-releasing branch -# if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) || github.repository_owner != 'supertuxkart' }} -# run: | -# echo "release_tag=" >> $GITHUB_ENV -# echo "release_name=" >> $GITHUB_ENV -# - name: Check for prerelease -# if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'rc') || contains(github.ref, 'beta') }} -# run: | -# echo "release_pre=true" >> $GITHUB_ENV -# - name: Check for non-prerelease -# if: ${{ github.ref != 'refs/heads/master' && !contains(github.ref, 'rc') && !contains(github.ref, 'beta') }} -# run: | -# echo "release_pre=false" >> $GITHUB_ENV -# - name: Show packaging name -# run : | -# echo "${{ env.release_tag }}" -# echo "${{ env.release_name }}" -# echo "${{ env.release_pre }}" -# - name: Download binaries -# uses: actions/download-artifact@v4 -# #- name: Mask developer name -# # run: | -# # echo "::add-mask::${{ secrets.MAC_DEVELOPER_NAME }}" -# #- name: Import certificates -# # if: ${{ env.release_tag != '' }} -# # uses: apple-actions/import-codesign-certs@v1 -# # with: -# # p12-file-base64: ${{ secrets.MAC_DEVELOPER_ID_P12_FILE }} -# # p12-password: ${{ secrets.MAC_DEVELOPER_ID_P12_PASSWORD }} -# - name: Run dylibbundler and sign STK -# if: ${{ env.release_tag != '' }} -# # env: -# # developer_id: "Developer ID Application: ${{ secrets.MAC_DEVELOPER_NAME }} (${{ secrets.MAC_DEVELOPER_TEAM }})" -# run: | -# wget https://github.com/kimden/stk-dependencies/releases/download/preview/dependencies-macosx.tar.xz -# tar xf dependencies-macosx.tar.xz -# HOMEBREW_NO_AUTO_UPDATE=1 brew install dylibbundler -# lipo -create ./macosx-x86_64/supertuxkart.app/Contents/MacOS/supertuxkart ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -output ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -# chmod 755 ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -# install_name_tool -delete_rpath @loader_path/Frameworks ./dependencies-macosx/lib/libSDL2.dylib -# install_name_tool -delete_rpath @executable_path/Frameworks ./dependencies-macosx/lib/libSDL2.dylib -# dylibbundler -od -b -x ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -d ./macosx-arm64/supertuxkart.app/Contents/libs/ -p @executable_path/../libs/ -s ./dependencies-macosx/lib -ns -# # We use SDL_Vulkan_LoadLibrary for 10.9 compatibility, so otool -L supertuxkart has no libMoltenVK.dylib -# cp ./dependencies-macosx/lib/libMoltenVK.dylib ./macosx-arm64/supertuxkart.app/Contents/libs/ -# cd ./macosx-arm64/supertuxkart.app/Contents/Resources/data -# wget https://github.com/supertuxkart/stk-assets-mobile/releases/download/git/stk-assets-full.zip -# unzip stk-assets-full.zip -# rm stk-assets-full.zip -# cd ../../../../.. -# mv ./macosx-arm64/supertuxkart.app SuperTuxKart.app -# # Use Ad Hoc certificate for now, previous certificate has been expired. -# codesign --force -s - SuperTuxKart.app/Contents/libs/*.dylib -# codesign --force --deep -s - SuperTuxKart.app -# #codesign --force --sign "$developer_id" SuperTuxKart.app/Contents/libs/*.dylib -# #codesign --force --options=runtime --deep --sign "$developer_id" SuperTuxKart.app -# #- name: "Notarize release build" -# # if: ${{ env.release_tag != '' && github.ref != 'refs/heads/master' }} -# # run: | -# # ditto -c -k --sequesterRsrc --keepParent SuperTuxKart.app tmp.zip -# # xcrun notarytool submit tmp.zip --apple-id ${{ secrets.STK_NOTARIZATION_USERNAME }} \ -# # --password ${{ secrets.STK_NOTARIZATION_PASSWORD }} \ -# # --team-id ${{ secrets.MAC_DEVELOPER_TEAM }} --wait -# # xcrun stapler staple SuperTuxKart.app -# - name: Archive -# if: ${{ env.release_tag != '' }} -# run: | -# ditto -c -k --sequesterRsrc --keepParent SuperTuxKart.app SuperTuxKart-${{ env.release_tag }}-mac.zip -# - name: Create release -# if: ${{ env.release_tag != '' }} -# uses: ncipollo/release-action@v1.8.8 -# with: -# token: ${{ secrets.GITHUB_TOKEN }} -# artifacts: "SuperTuxKart*.zip" -# tag: ${{ env.release_name }} -# omitBodyDuringUpdate: true -# omitNameDuringUpdate: true -# allowUpdates: true -# prerelease: ${{ env.release_pre }} + strategy: + fail-fast: true + matrix: + platform: [iPhoneOS, MacOSX] + arch: [arm64, x86_64] + exclude: + - platform: iPhoneOS + arch: x86_64 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + submodules: true + - id: sysroot + uses: ASzc/change-string-case-action@v1 + with: + string: ${{ matrix.platform }} + - name: Download cctools and ISPC + run: | + cd /opt + wget https://github.com/kimden/stk-dependencies/releases/download/cctools/cctools-14.1.tar.xz + tar xf cctools-14.1.tar.xz + rm cctools-14.1.tar.xz + wget https://github.com/supertuxkart/dependencies/releases/download/preview/ispc-cross-1.26.0.tar.xz + tar xf ispc-cross-1.26.0.tar.xz + rm ispc-cross-1.26.0.tar.xz + - name: Restore timestamps + run: | + wget https://github.com/MestreLion/git-tools/archive/refs/heads/main.zip + unzip main.zip + python git-tools-main/git-restore-mtime + - name: List build cache restore keys + run: | + # Look for the last 9 build caches (GitHub supports max 10 including current one) + for number in 1 2 3 4 5 6 7 8 9 + do + id=$((${{ github.run_number }} - number)) + echo "cache_$number=apple-${{ github.ref }}-${{ matrix.arch }}-${{ matrix.platform }}-$id" >> $GITHUB_ENV + done + - name: Handle build cache + uses: actions/cache@v3 + with: + path: | + build + key: apple-${{ github.ref }}-${{ matrix.arch }}-${{ matrix.platform }}-${{ github.run_number }} + restore-keys: | + ${{ env.cache_1 }} + ${{ env.cache_2 }} + ${{ env.cache_3 }} + ${{ env.cache_4 }} + ${{ env.cache_5 }} + ${{ env.cache_6 }} + ${{ env.cache_7 }} + ${{ env.cache_8 }} + ${{ env.cache_9 }} + - name: Download dependencies + run: | + wget https://github.com/kimden/stk-dependencies/releases/download/preview/dependencies-${{ steps.sysroot.outputs.lowercase }}.tar.xz + tar xf dependencies-${{ steps.sysroot.outputs.lowercase }}.tar.xz + - name: Configure clang runtime name + run: | + if [ ${{ matrix.platform }} = "MacOSX" ]; then + echo "rt=osx" >> $GITHUB_ENV + elif [ ${{ matrix.platform }} = "iPhoneOS" ]; then + echo "rt=ios" >> $GITHUB_ENV + elif [ ${{ matrix.platform }} = "AppleTVOS" ]; then + echo "rt=tvos" >> $GITHUB_ENV + elif [ ${{ matrix.platform }} = "iPhoneSimulator" ]; then + echo "rt=iossim" >> $GITHUB_ENV + elif [ ${{ matrix.platform }} = "AppleTVSimulator" ]; then + echo "rt=tvossim" >> $GITHUB_ENV + fi + - name: Configure bulid + run: | + mkdir -p build + cd build + cmake .. -DCCTOOLS_PREFIX=/opt/cctools -DCCTOOLS_ARCH=${{ matrix.arch }} -DCCTOOLS_PLATFORM=${{ matrix.platform }} \ + -DRT=/opt/cctools/darwin/libclang_rt.${{ env.rt }}.a -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-cctools.cmake -DCHECK_ASSETS=OFF \ + -DBC7_ISPC=ON -DCMAKE_ISPC_COMPILER=/opt/ispc/bin/ispc + - name: Build + run: | + cd build + make -j4 + mv bin ../${{ steps.sysroot.outputs.lowercase }}-${{ matrix.arch }} + - name: Upload binaries + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.sysroot.outputs.lowercase }}-${{ matrix.arch }} + path: ${{ steps.sysroot.outputs.lowercase }}-${{ matrix.arch }} + packaging: + name: Packaging STK + needs: build + runs-on: macos-latest + steps: + - name: Configure packaging name for git master branch + if: ${{ github.ref == 'refs/heads/master' }} + run: | + echo "release_tag=git`date +%Y%m%d`" >> $GITHUB_ENV + echo "release_name=preview" >> $GITHUB_ENV + - name: Configure packaging name for tag + if: ${{ startsWith(github.ref, 'refs/tags/') }} + run: | + echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV + echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV + - name: Configure packaging name for non-releasing branch + if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) || github.repository_owner != 'supertuxkart' }} + run: | + echo "release_tag=" >> $GITHUB_ENV + echo "release_name=" >> $GITHUB_ENV + - name: Check for prerelease + if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'rc') || contains(github.ref, 'beta') }} + run: | + echo "release_pre=true" >> $GITHUB_ENV + - name: Check for non-prerelease + if: ${{ github.ref != 'refs/heads/master' && !contains(github.ref, 'rc') && !contains(github.ref, 'beta') }} + run: | + echo "release_pre=false" >> $GITHUB_ENV + - name: Show packaging name + run : | + echo "${{ env.release_tag }}" + echo "${{ env.release_name }}" + echo "${{ env.release_pre }}" + - name: Download binaries + uses: actions/download-artifact@v4 + #- name: Mask developer name + # run: | + # echo "::add-mask::${{ secrets.MAC_DEVELOPER_NAME }}" + #- name: Import certificates + # if: ${{ env.release_tag != '' }} + # uses: apple-actions/import-codesign-certs@v1 + # with: + # p12-file-base64: ${{ secrets.MAC_DEVELOPER_ID_P12_FILE }} + # p12-password: ${{ secrets.MAC_DEVELOPER_ID_P12_PASSWORD }} + - name: Run dylibbundler and sign STK + if: ${{ env.release_tag != '' }} + # env: + # developer_id: "Developer ID Application: ${{ secrets.MAC_DEVELOPER_NAME }} (${{ secrets.MAC_DEVELOPER_TEAM }})" + run: | + wget https://github.com/kimden/stk-dependencies/releases/download/preview/dependencies-macosx.tar.xz + tar xf dependencies-macosx.tar.xz + HOMEBREW_NO_AUTO_UPDATE=1 brew install dylibbundler + lipo -create ./macosx-x86_64/supertuxkart.app/Contents/MacOS/supertuxkart ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -output ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart + chmod 755 ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart + install_name_tool -delete_rpath @loader_path/Frameworks ./dependencies-macosx/lib/libSDL2.dylib + install_name_tool -delete_rpath @executable_path/Frameworks ./dependencies-macosx/lib/libSDL2.dylib + dylibbundler -od -b -x ./macosx-arm64/supertuxkart.app/Contents/MacOS/supertuxkart -d ./macosx-arm64/supertuxkart.app/Contents/libs/ -p @executable_path/../libs/ -s ./dependencies-macosx/lib -ns + # We use SDL_Vulkan_LoadLibrary for 10.9 compatibility, so otool -L supertuxkart has no libMoltenVK.dylib + cp ./dependencies-macosx/lib/libMoltenVK.dylib ./macosx-arm64/supertuxkart.app/Contents/libs/ + cd ./macosx-arm64/supertuxkart.app/Contents/Resources/data + wget https://github.com/supertuxkart/stk-assets-mobile/releases/download/git/stk-assets-full.zip + unzip stk-assets-full.zip + rm stk-assets-full.zip + cd ../../../../.. + mv ./macosx-arm64/supertuxkart.app SuperTuxKart.app + # Use Ad Hoc certificate for now, previous certificate has been expired. + codesign --force -s - SuperTuxKart.app/Contents/libs/*.dylib + codesign --force --deep -s - SuperTuxKart.app + #codesign --force --sign "$developer_id" SuperTuxKart.app/Contents/libs/*.dylib + #codesign --force --options=runtime --deep --sign "$developer_id" SuperTuxKart.app + #- name: "Notarize release build" + # if: ${{ env.release_tag != '' && github.ref != 'refs/heads/master' }} + # run: | + # ditto -c -k --sequesterRsrc --keepParent SuperTuxKart.app tmp.zip + # xcrun notarytool submit tmp.zip --apple-id ${{ secrets.STK_NOTARIZATION_USERNAME }} \ + # --password ${{ secrets.STK_NOTARIZATION_PASSWORD }} \ + # --team-id ${{ secrets.MAC_DEVELOPER_TEAM }} --wait + # xcrun stapler staple SuperTuxKart.app + - name: Archive + if: ${{ env.release_tag != '' }} + run: | + ditto -c -k --sequesterRsrc --keepParent SuperTuxKart.app SuperTuxKart-${{ env.release_tag }}-mac.zip + - name: Create release + if: ${{ env.release_tag != '' }} + uses: ncipollo/release-action@v1.8.8 + with: + token: ${{ secrets.GITHUB_TOKEN }} + artifacts: "SuperTuxKart*.zip" + tag: ${{ env.release_name }} + omitBodyDuringUpdate: true + omitNameDuringUpdate: true + allowUpdates: true + prerelease: ${{ env.release_pre }} diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 9c02dae936c..40982f8b40e 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -1,169 +1,169 @@ -# # Copyright (C) 2020-2021 Jacob Burroughs -# # 2020-2021 A. Semphris -# # -# # Released under the Creative Commons Zero (CC0) license, available at: -# # Legal code: https://creativecommons.org/publicdomain/zero/1.0/legalcode -# # Information: https://creativecommons.org/share-your-work/public-domain/cc0/ +# Copyright (C) 2020-2021 Jacob Burroughs +# 2020-2021 A. Semphris +# +# Released under the Creative Commons Zero (CC0) license, available at: +# Legal code: https://creativecommons.org/publicdomain/zero/1.0/legalcode +# Information: https://creativecommons.org/share-your-work/public-domain/cc0/ -# # Note: Parts of this code were taken from the SuperTux project. -# # ~ Semphris (responsible for transfering and adapting the file) +# Note: Parts of this code were taken from the SuperTux project. +# ~ Semphris (responsible for transfering and adapting the file) -# name: linux -# on: -# push: -# branches: -# - master -# tags: -# - '*' -# pull_request: {} -# workflow_dispatch: +name: linux +on: + push: + branches: + - master + tags: + - '*' + pull_request: {} + workflow_dispatch: -# jobs: -# build: +jobs: + build: -# strategy: -# fail-fast: true -# matrix: -# os: [ubuntu-latest] -# compiler: [gcc, clang] -# build_type: [Debug, RelWithDebInfo, Release] -# server_only: [ON, OFF] -# exclude: -# - os: macos-latest -# compiler: gcc -# - os: macos-latest -# build_type: Debug + strategy: + fail-fast: true + matrix: + os: [ubuntu-latest] + compiler: [gcc, clang] + build_type: [Debug, RelWithDebInfo, Release] + server_only: [ON, OFF] + exclude: + - os: macos-latest + compiler: gcc + - os: macos-latest + build_type: Debug -# runs-on: ${{ matrix.os }} -# steps: -# - uses: actions/checkout@v2 -# with: -# fetch-depth: 1 -# submodules: true -# - name: Configure packaging name for git master branch -# if: ${{ matrix.build_type == 'Release' && matrix.server_only == 'OFF' && -# github.ref == 'refs/heads/master' }} -# run: | -# echo "release_tag=git`date +%Y%m%d`" >> $GITHUB_ENV -# echo "release_name=preview" >> $GITHUB_ENV -# - name: Configure packaging name for tag -# if: ${{ matrix.build_type == 'Release' && matrix.server_only == 'OFF' && -# startsWith(github.ref, 'refs/tags/') }} -# run: | -# echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV -# echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV -# - name: Configure packaging name for non-releasing branch -# if: ${{ matrix.build_type != 'Release' || matrix.server_only != 'OFF' || -# !(github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) || -# github.repository_owner != 'supertuxkart' }} -# run: | -# echo "release_tag=" >> $GITHUB_ENV -# echo "release_name=" >> $GITHUB_ENV -# - name: Check for prerelease -# if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'rc') || contains(github.ref, 'beta') }} -# run: | -# echo "release_pre=true" >> $GITHUB_ENV -# - name: Check for non-prerelease -# if: ${{ github.ref != 'refs/heads/master' && !contains(github.ref, 'rc') && !contains(github.ref, 'beta') }} -# run: | -# echo "release_pre=false" >> $GITHUB_ENV -# - name: Show packaging name -# run : | -# echo "${{ env.release_tag }}" -# echo "${{ env.release_name }}" -# echo "${{ env.release_pre }}" -# - name: Install linux dependencies -# if: ${{ matrix.os == 'ubuntu-latest' }} -# run: | -# sudo apt-get update -# sudo apt install -y build-essential cmake libbluetooth-dev libcurl4-gnutls-dev \ -# libfreetype6-dev libharfbuzz-dev libjpeg-dev libogg-dev libopenal-dev \ -# libpng-dev libsdl2-dev libvorbis-dev pkg-config zlib1g-dev clang -# - name: Install dylibbundler for packaging osx binary -# if: ${{ env.release_tag != '' && matrix.os == 'macos-latest' && matrix.build_type == 'Release' && matrix.server_only == 'OFF' }} -# run: | -# HOMEBREW_NO_AUTO_UPDATE=1 brew install dylibbundler -# - name: Install macos dependencies -# if: ${{ matrix.os == 'macos-latest' }} -# run: | -# # Something funky happens with freetype if mono is left -# sudo mv /Library/Frameworks/Mono.framework /Library/Frameworks/Mono.framework-disabled -# wget https://github.com/supertuxkart/dependencies/releases/download/preview/dependencies-mac.tar.xz -# # Remove any existing installation to avoid conflict with bundled dependencies -# rm -rf /usr/local/include/* -# rm -rf /usr/local/opt/openssl@1.1/include -# rm -rf /usr/local/opt/freetype -# rm -rf /usr/local/opt/harfbuzz -# tar xf dependencies-mac.tar.xz -C /usr/local -# rm dependencies-mac.tar.xz -# - name: Set compiler (gcc) -# if: ${{ matrix.os == 'ubuntu-latest' && matrix.compiler == 'gcc' }} -# run: | -# echo "CXX=g++" >> $GITHUB_ENV -# echo "CC=gcc" >> $GITHUB_ENV -# - name: Set compiler (clang) -# if: ${{ matrix.os == 'ubuntu-latest' && matrix.compiler == 'clang' }} -# run: | -# echo "CXX=clang++" >> $GITHUB_ENV -# echo "CC=clang" >> $GITHUB_ENV -# - name: Set compiler (macos) -# if: ${{ matrix.os == 'macos-latest' }} -# run: | -# # This ensures for now we use clang11 -# # Clang12 runs into a bunch of fun with `include location '/usr/local/include' is unsafe for cross-compilation` -# # that we don't care about for now -# echo "CXX=clang++" >> $GITHUB_ENV -# echo "CC=clang" >> $GITHUB_ENV -# - name: Configure bulid (linux) -# if: ${{ matrix.os != 'macos-latest' }} -# env: -# BUILD_TYPE: ${{ matrix.build_type }} -# SERVER_ONLY: ${{ matrix.server_only }} -# run: | -# cmake --version -# $CXX --version -# mkdir "build" -# cd "build" -# cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSERVER_ONLY=$SERVER_ONLY -DCHECK_ASSETS=off -DBUILD_RECORDER=off -DNO_SHADERC=on; -# - name: Configure bulid (macos) -# if: ${{ matrix.os == 'macos-latest' }} -# env: -# BUILD_TYPE: ${{ matrix.build_type }} -# SERVER_ONLY: ${{ matrix.server_only }} -# run: | -# cmake --version -# $CXX --version -# mkdir "build" -# cd "build" -# CFLAGS="-mmacosx-version-min=10.13" CXXFLAGS="-mmacosx-version-min=10.13" LINKFLAGS="-mmacosx-version-min=10.13" LDFLAGS="-mmacosx-version-min=10.13" /usr/local/opt/cmake/bin/cmake .. -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSERVER_ONLY=$SERVER_ONLY -DCHECK_ASSETS=off -DBUILD_RECORDER=off; -# - name: Build and install -# working-directory: build -# run: | -# make -j3 VERBOSE=1 -# make install DESTDIR="/tmp/stk" VERBOSE=1 -# - name: Packaging (macos) -# if: ${{ env.release_tag != '' && matrix.os == 'macos-latest' && matrix.build_type == 'Release' && matrix.server_only == 'OFF' }} -# working-directory: build -# run: | -# /usr/local/opt/dylibbundler/bin/dylibbundler -od -b -x ./bin/SuperTuxKart.app/Contents/MacOS/supertuxkart -d ./bin/SuperTuxKart.app/Contents/libs/ -p @executable_path/../libs/ -# wget https://github.com/supertuxkart/stk-assets-mobile/releases/download/git/stk-assets-full.zip -# unzip stk-assets-full.zip -d ../data -# rm stk-assets-full.zip -# cd bin -# # Fix the name on case insensitive filesystem -# mv supertuxkart.app stk.app -# mv stk.app SuperTuxKart.app -# zip -r ../SuperTuxKart-${{ env.release_tag }}-mac.zip . -# - name: Create Release (macos) -# if: ${{ env.release_tag != '' && matrix.os == 'macos-latest' && matrix.build_type == 'Release' && matrix.server_only == 'OFF' }} -# uses: ncipollo/release-action@v1 -# with: -# token: ${{ secrets.GITHUB_TOKEN }} -# artifacts: "build/SuperTuxKart-${{ env.release_tag }}-mac.zip" -# tag: ${{ env.release_name }} -# omitBodyDuringUpdate: true -# omitNameDuringUpdate: true -# allowUpdates: true -# prerelease: ${{ env.release_pre }} + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 1 + submodules: true + - name: Configure packaging name for git master branch + if: ${{ matrix.build_type == 'Release' && matrix.server_only == 'OFF' && + github.ref == 'refs/heads/master' }} + run: | + echo "release_tag=git`date +%Y%m%d`" >> $GITHUB_ENV + echo "release_name=preview" >> $GITHUB_ENV + - name: Configure packaging name for tag + if: ${{ matrix.build_type == 'Release' && matrix.server_only == 'OFF' && + startsWith(github.ref, 'refs/tags/') }} + run: | + echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV + echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV + - name: Configure packaging name for non-releasing branch + if: ${{ matrix.build_type != 'Release' || matrix.server_only != 'OFF' || + !(github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) || + github.repository_owner != 'supertuxkart' }} + run: | + echo "release_tag=" >> $GITHUB_ENV + echo "release_name=" >> $GITHUB_ENV + - name: Check for prerelease + if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'rc') || contains(github.ref, 'beta') }} + run: | + echo "release_pre=true" >> $GITHUB_ENV + - name: Check for non-prerelease + if: ${{ github.ref != 'refs/heads/master' && !contains(github.ref, 'rc') && !contains(github.ref, 'beta') }} + run: | + echo "release_pre=false" >> $GITHUB_ENV + - name: Show packaging name + run : | + echo "${{ env.release_tag }}" + echo "${{ env.release_name }}" + echo "${{ env.release_pre }}" + - name: Install linux dependencies + if: ${{ matrix.os == 'ubuntu-latest' }} + run: | + sudo apt-get update + sudo apt install -y build-essential cmake libbluetooth-dev libcurl4-gnutls-dev \ + libfreetype6-dev libharfbuzz-dev libjpeg-dev libogg-dev libopenal-dev \ + libpng-dev libsdl2-dev libvorbis-dev pkg-config zlib1g-dev clang + - name: Install dylibbundler for packaging osx binary + if: ${{ env.release_tag != '' && matrix.os == 'macos-latest' && matrix.build_type == 'Release' && matrix.server_only == 'OFF' }} + run: | + HOMEBREW_NO_AUTO_UPDATE=1 brew install dylibbundler + - name: Install macos dependencies + if: ${{ matrix.os == 'macos-latest' }} + run: | + # Something funky happens with freetype if mono is left + sudo mv /Library/Frameworks/Mono.framework /Library/Frameworks/Mono.framework-disabled + wget https://github.com/supertuxkart/dependencies/releases/download/preview/dependencies-mac.tar.xz + # Remove any existing installation to avoid conflict with bundled dependencies + rm -rf /usr/local/include/* + rm -rf /usr/local/opt/openssl@1.1/include + rm -rf /usr/local/opt/freetype + rm -rf /usr/local/opt/harfbuzz + tar xf dependencies-mac.tar.xz -C /usr/local + rm dependencies-mac.tar.xz + - name: Set compiler (gcc) + if: ${{ matrix.os == 'ubuntu-latest' && matrix.compiler == 'gcc' }} + run: | + echo "CXX=g++" >> $GITHUB_ENV + echo "CC=gcc" >> $GITHUB_ENV + - name: Set compiler (clang) + if: ${{ matrix.os == 'ubuntu-latest' && matrix.compiler == 'clang' }} + run: | + echo "CXX=clang++" >> $GITHUB_ENV + echo "CC=clang" >> $GITHUB_ENV + - name: Set compiler (macos) + if: ${{ matrix.os == 'macos-latest' }} + run: | + # This ensures for now we use clang11 + # Clang12 runs into a bunch of fun with `include location '/usr/local/include' is unsafe for cross-compilation` + # that we don't care about for now + echo "CXX=clang++" >> $GITHUB_ENV + echo "CC=clang" >> $GITHUB_ENV + - name: Configure bulid (linux) + if: ${{ matrix.os != 'macos-latest' }} + env: + BUILD_TYPE: ${{ matrix.build_type }} + SERVER_ONLY: ${{ matrix.server_only }} + run: | + cmake --version + $CXX --version + mkdir "build" + cd "build" + cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSERVER_ONLY=$SERVER_ONLY -DCHECK_ASSETS=off -DBUILD_RECORDER=off -DNO_SHADERC=on; + - name: Configure bulid (macos) + if: ${{ matrix.os == 'macos-latest' }} + env: + BUILD_TYPE: ${{ matrix.build_type }} + SERVER_ONLY: ${{ matrix.server_only }} + run: | + cmake --version + $CXX --version + mkdir "build" + cd "build" + CFLAGS="-mmacosx-version-min=10.13" CXXFLAGS="-mmacosx-version-min=10.13" LINKFLAGS="-mmacosx-version-min=10.13" LDFLAGS="-mmacosx-version-min=10.13" /usr/local/opt/cmake/bin/cmake .. -DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSERVER_ONLY=$SERVER_ONLY -DCHECK_ASSETS=off -DBUILD_RECORDER=off; + - name: Build and install + working-directory: build + run: | + make -j3 VERBOSE=1 + make install DESTDIR="/tmp/stk" VERBOSE=1 + - name: Packaging (macos) + if: ${{ env.release_tag != '' && matrix.os == 'macos-latest' && matrix.build_type == 'Release' && matrix.server_only == 'OFF' }} + working-directory: build + run: | + /usr/local/opt/dylibbundler/bin/dylibbundler -od -b -x ./bin/SuperTuxKart.app/Contents/MacOS/supertuxkart -d ./bin/SuperTuxKart.app/Contents/libs/ -p @executable_path/../libs/ + wget https://github.com/supertuxkart/stk-assets-mobile/releases/download/git/stk-assets-full.zip + unzip stk-assets-full.zip -d ../data + rm stk-assets-full.zip + cd bin + # Fix the name on case insensitive filesystem + mv supertuxkart.app stk.app + mv stk.app SuperTuxKart.app + zip -r ../SuperTuxKart-${{ env.release_tag }}-mac.zip . + - name: Create Release (macos) + if: ${{ env.release_tag != '' && matrix.os == 'macos-latest' && matrix.build_type == 'Release' && matrix.server_only == 'OFF' }} + uses: ncipollo/release-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + artifacts: "build/SuperTuxKart-${{ env.release_tag }}-mac.zip" + tag: ${{ env.release_name }} + omitBodyDuringUpdate: true + omitNameDuringUpdate: true + allowUpdates: true + prerelease: ${{ env.release_pre }} diff --git a/.github/workflows/switch.yml b/.github/workflows/switch.yml index 4a1a0f87c5d..0d79d845d08 100644 --- a/.github/workflows/switch.yml +++ b/.github/workflows/switch.yml @@ -1,113 +1,113 @@ -# name: switch -# on: -# push: -# branches: -# - master -# - feature/gh-actions-switch-cache -# tags: -# - '*' -# pull_request: {} -# workflow_dispatch: +name: switch +on: + push: + branches: + - master + - feature/gh-actions-switch-cache + tags: + - '*' + pull_request: {} + workflow_dispatch: -# jobs: -# build_switch: -# name: Build Switch -# runs-on: ubuntu-latest -# container: -# image: 'devkitpro/devkita64' -# steps: -# - name: Checkout code -# uses: actions/checkout@v2 -# with: -# # We need 0 so we get all commits for mtime! -# fetch-depth: 0 -# path: "./stk-code" -# - name: Grab assets -# run: | -# wget -q https://github.com/supertuxkart/stk-assets-mobile/releases/download/git/stk-assets-full.zip -# unzip -q stk-assets-full.zip -d stk-assets -# rm stk-assets-full.zip -# - name: Restore modified date -# run: | -# cd stk-code -# git restore-mtime . -# cd .. +jobs: + build_switch: + name: Build Switch + runs-on: ubuntu-latest + container: + image: 'devkitpro/devkita64' + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + # We need 0 so we get all commits for mtime! + fetch-depth: 0 + path: "./stk-code" + - name: Grab assets + run: | + wget -q https://github.com/supertuxkart/stk-assets-mobile/releases/download/git/stk-assets-full.zip + unzip -q stk-assets-full.zip -d stk-assets + rm stk-assets-full.zip + - name: Restore modified date + run: | + cd stk-code + git restore-mtime . + cd .. -# # Env setup! -# - name: Configure packaging name for git master branch -# if: ${{ github.ref == 'refs/heads/master' }} -# run: | -# echo "release_tag=git`date +%Y%m%d`" >> $GITHUB_ENV -# echo "release_name=preview" >> $GITHUB_ENV -# - name: Configure packaging name for tag -# if: ${{ startsWith(github.ref, 'refs/tags/') }} -# run: | -# echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV -# echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV -# - name: Configure packaging name for non-releasing branch -# if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) || github.repository_owner != 'supertuxkart' }} -# run: | -# echo "release_tag=" >> $GITHUB_ENV -# echo "release_name=" >> $GITHUB_ENV -# - name: Check for prerelease -# if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'rc') || contains(github.ref, 'beta') }} -# run: | -# echo "release_pre=true" >> $GITHUB_ENV -# - name: Check for non-prerelease -# if: ${{ github.ref != 'refs/heads/master' && !contains(github.ref, 'rc') && !contains(github.ref, 'beta') }} -# run: | -# echo "release_pre=false" >> $GITHUB_ENV -# - name: Show packaging name -# run : | -# echo "${{ env.release_tag }}" -# echo "${{ env.release_name }}" -# echo "${{ env.release_pre }}" -# - name: List build cache restore keys -# shell : bash -# run: | -# # Look for the last 9 build caches (GitHub supports max 10 including current one) -# for number in 1 2 3 4 5 6 7 8 9 -# do -# id=$((${{ github.run_number }} - number)) -# echo "cache_$number=switch-${{ github.ref }}-$id" >> $GITHUB_ENV -# done -# - name: Handle build cache -# uses: actions/cache@v3 -# with: -# # This is unnecessarily verbose and might break, but again ! seems broken -# # See: https://github.com/Mstrodl/stk-code/runs/2333673736?check_suite_focus=true#step:16:34 -# path: | -# stk-code/cmake_build/CMakeFiles -# stk-code/cmake_build/Makefile -# stk-code/cmake_build/lib -# stk-code/cmake_build/bin/supertuxkart -# stk-code/cmake_build/*.cmake -# stk-code/cmake_build/*.txt + # Env setup! + - name: Configure packaging name for git master branch + if: ${{ github.ref == 'refs/heads/master' }} + run: | + echo "release_tag=git`date +%Y%m%d`" >> $GITHUB_ENV + echo "release_name=preview" >> $GITHUB_ENV + - name: Configure packaging name for tag + if: ${{ startsWith(github.ref, 'refs/tags/') }} + run: | + echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV + echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV + - name: Configure packaging name for non-releasing branch + if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) || github.repository_owner != 'supertuxkart' }} + run: | + echo "release_tag=" >> $GITHUB_ENV + echo "release_name=" >> $GITHUB_ENV + - name: Check for prerelease + if: ${{ github.ref == 'refs/heads/master' || contains(github.ref, 'rc') || contains(github.ref, 'beta') }} + run: | + echo "release_pre=true" >> $GITHUB_ENV + - name: Check for non-prerelease + if: ${{ github.ref != 'refs/heads/master' && !contains(github.ref, 'rc') && !contains(github.ref, 'beta') }} + run: | + echo "release_pre=false" >> $GITHUB_ENV + - name: Show packaging name + run : | + echo "${{ env.release_tag }}" + echo "${{ env.release_name }}" + echo "${{ env.release_pre }}" + - name: List build cache restore keys + shell : bash + run: | + # Look for the last 9 build caches (GitHub supports max 10 including current one) + for number in 1 2 3 4 5 6 7 8 9 + do + id=$((${{ github.run_number }} - number)) + echo "cache_$number=switch-${{ github.ref }}-$id" >> $GITHUB_ENV + done + - name: Handle build cache + uses: actions/cache@v3 + with: + # This is unnecessarily verbose and might break, but again ! seems broken + # See: https://github.com/Mstrodl/stk-code/runs/2333673736?check_suite_focus=true#step:16:34 + path: | + stk-code/cmake_build/CMakeFiles + stk-code/cmake_build/Makefile + stk-code/cmake_build/lib + stk-code/cmake_build/bin/supertuxkart + stk-code/cmake_build/*.cmake + stk-code/cmake_build/*.txt -# # Make sure PRs can't overwrite! -# key: switch-${{ github.ref }}-${{ github.run_number }} -# restore-keys: | -# ${{ env.cache_1 }} -# ${{ env.cache_2 }} -# ${{ env.cache_3 }} -# ${{ env.cache_4 }} -# ${{ env.cache_5 }} -# ${{ env.cache_6 }} -# ${{ env.cache_7 }} -# ${{ env.cache_8 }} -# ${{ env.cache_9 }} -# - name: Run build script -# run: | -# cd stk-code/switch -# PROJECT_VERSION="${{ env.release_tag }}" ./make.sh -# - name: Create release -# uses: ncipollo/release-action@v1.8.8 -# if: ${{ env.release_tag != '' }} -# with: -# token: ${{ secrets.GITHUB_TOKEN }} -# artifacts: "stk-code/cmake_build/bin/SuperTuxKart-${{ env.release_tag }}-switch.zip" -# tag: ${{ env.release_name }} -# omitBodyDuringUpdate: true -# omitNameDuringUpdate: true -# allowUpdates: true -# prerelease: ${{ env.release_pre }} + # Make sure PRs can't overwrite! + key: switch-${{ github.ref }}-${{ github.run_number }} + restore-keys: | + ${{ env.cache_1 }} + ${{ env.cache_2 }} + ${{ env.cache_3 }} + ${{ env.cache_4 }} + ${{ env.cache_5 }} + ${{ env.cache_6 }} + ${{ env.cache_7 }} + ${{ env.cache_8 }} + ${{ env.cache_9 }} + - name: Run build script + run: | + cd stk-code/switch + PROJECT_VERSION="${{ env.release_tag }}" ./make.sh + - name: Create release + uses: ncipollo/release-action@v1.8.8 + if: ${{ env.release_tag != '' }} + with: + token: ${{ secrets.GITHUB_TOKEN }} + artifacts: "stk-code/cmake_build/bin/SuperTuxKart-${{ env.release_tag }}-switch.zip" + tag: ${{ env.release_name }} + omitBodyDuringUpdate: true + omitNameDuringUpdate: true + allowUpdates: true + prerelease: ${{ env.release_pre }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 761fd50091d..79457639b82 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -11,12 +11,10 @@ on: jobs: build: strategy: - fail-fast: false + fail-fast: true matrix: - arch: [i686, x86_64] - os: [ubuntu-latest] - # arch: [i686, x86_64, armv7, aarch64] - # os: [windows-latest, ubuntu-latest] + arch: [i686, x86_64, armv7, aarch64] + os: [windows-latest, ubuntu-latest] exclude: - arch: armv7 os: windows-latest @@ -109,11 +107,9 @@ jobs: - name: Set up MinGW Toolchain for i686 if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch == 'i686' }} run: | - # export PATH=/data/mxe/usr/bin:$PATH echo "SET(CMAKE_SYSTEM_NAME Windows)" > toolchain.cmake echo "SET(CMAKE_C_COMPILER /data/mxe/usr/bin/i686-w64-mingw32.static.posix.dw2-gcc)" >> toolchain.cmake echo "SET(CMAKE_CXX_COMPILER /data/mxe/usr/bin/i686-w64-mingw32.static.posix.dw2-g++)" >> toolchain.cmake - #echo "SET(CMAKE_ASM_COMPILER /data/mxe/usr/bin/i686-w64-mingw32.static.posix.dw2-as)" >> toolchain.cmake echo "SET(CMAKE_RC_COMPILER /data/mxe/usr/bin/i686-w64-mingw32.static.posix.dw2-windres)" >> toolchain.cmake echo "SET(CMAKE_FIND_ROOT_PATH \${PROJECT_SOURCE_DIR}/dependencies-win-i686 /data/mxe/usr/i686-w64-mingw32.static.posix.dw2/ /data/mxe/usr/lib/gcc/i686-w64-mingw32.static.posix.dw2/11.5.0/)" >> toolchain.cmake echo "set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)" >> toolchain.cmake @@ -123,11 +119,9 @@ jobs: - name: Set up MinGW Toolchain for x86_64 if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch == 'x86_64' }} run: | - # export PATH=/data/mxe/usr/bin:$PATH echo "SET(CMAKE_SYSTEM_NAME Windows)" > toolchain.cmake echo "SET(CMAKE_C_COMPILER /data/mxe/usr/bin/x86_64-w64-mingw32.static.posix.seh-gcc)" >> toolchain.cmake echo "SET(CMAKE_CXX_COMPILER /data/mxe/usr/bin/x86_64-w64-mingw32.static.posix.seh-g++)" >> toolchain.cmake - #echo "SET(CMAKE_ASM_COMPILER /data/mxe/usr/bin/x86_64-w64-mingw32.static.posix.seh-as)" >> toolchain.cmake echo "SET(CMAKE_RC_COMPILER /data/mxe/usr/bin/x86_64-w64-mingw32.static.posix.seh-windres)" >> toolchain.cmake echo "SET(CMAKE_FIND_ROOT_PATH \${PROJECT_SOURCE_DIR}/dependencies-win-x86_64 /data/mxe/usr/x86_64-w64-mingw32.static.posix.seh/ /data/mxe/usr/lib/gcc/x86_64-w64-mingw32.static.posix.seh/11.5.0/)" >> toolchain.cmake echo "set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)" >> toolchain.cmake @@ -135,18 +129,6 @@ jobs: echo "set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)" >> toolchain.cmake echo 'set(ISPC_ARCH "x86-64")' >> toolchain.cmake # Manually specify CMAKE_SYSTEM_PROCESSOR, it can only be set together with -DDCMAKE_SYSTEM_NAME - # - name: Check compiler version for MSVC - # if: ${{ matrix.os == 'windows-latest' }} - # run: | - # cl.exe /? - # - name: Check compiler version for MinGW i686 - # if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch == 'i686' }} - # run: | - # /data/mxe/usr/bin/i686-w64-mingw32.static.posix.dw2-g++ --version - # - name: Check compiler version for MinGW x86_64 - # if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch == 'x86_64' }} - # run: | - # /data/mxe/usr/bin/x86_64-w64-mingw32.static.posix.seh-g++ --version - name: Configure build for MSVC if: ${{ matrix.os == 'windows-latest' }} run: | @@ -158,7 +140,7 @@ jobs: run: | mkdir -p build cd build - cmake .. -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCHECK_ASSETS=OFF -DUSE_DIRECTX=ON -DBC7_ISPC=ON -DCMAKE_ISPC_COMPILER=/opt/ispc/bin/ispc + cmake .. -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCHECK_ASSETS=OFF -DUSE_DIRECTX=ON -DBC7_ISPC=ON -DCMAKE_ISPC_COMPILER=/opt/ispc/bin/ispc - name: Configure build for MinGW (armv7 or aarch64) if: ${{ matrix.os == 'ubuntu-latest' && ( matrix.arch == 'armv7' || matrix.arch == 'aarch64' ) }} run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e5780eaf33..d4440383799 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -967,19 +967,3 @@ if(MINGW) install(DIRECTORY ${CMAKE_BINARY_DIR}/bin/ DESTINATION ${STK_INSTALL_BINARY_DIR} FILES_MATCHING PATTERN "*.dll") endif() - -include(CheckCXXSourceCompiles) - -check_cxx_source_compiles(" - #include - int main() { - std::optional o; - return 0; - } -" HAS_STD_OPTIONAL) - -if(NOT HAS_STD_OPTIONAL) - message(FATAL_ERROR "The compiler does not support std::optional") -else() - message("The compiler supports std::optional") -endif() \ No newline at end of file diff --git a/src/network/socket_address.hpp b/src/network/socket_address.hpp index 5d0bb321ccb..15343a0da51 100644 --- a/src/network/socket_address.hpp +++ b/src/network/socket_address.hpp @@ -23,7 +23,7 @@ #include "utils/types.hpp" -#if defined(WIN32) || defined(__MINGW32__) || defined(__MINGW64__) +#if defined(WIN_BUILD) # include # include #else diff --git a/src/network/stk_ipv6.cpp b/src/network/stk_ipv6.cpp index d91f4b6e52f..74cdb49139c 100644 --- a/src/network/stk_ipv6.cpp +++ b/src/network/stk_ipv6.cpp @@ -16,7 +16,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include -#if defined(WIN32) || defined(__MINGW32__) || defined(__MINGW64__) +#if defined(WIN_BUILD) #ifdef __GNUC__ # include // Mingw / gcc on windows # undef _WIN32_WINNT From 4a67afb0beef1c4725b932d2580a7b1989ed7166 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 4 Jul 2025 01:41:27 +0400 Subject: [PATCH 805/830] Remove forced empty release name --- .github/workflows/apple.yml | 2 +- .github/workflows/linux.yml | 3 +-- .github/workflows/switch.yml | 2 +- .github/workflows/windows.yml | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/apple.yml b/.github/workflows/apple.yml index b5f71e67140..2e72e8683ba 100644 --- a/.github/workflows/apple.yml +++ b/.github/workflows/apple.yml @@ -117,7 +117,7 @@ jobs: echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV - name: Configure packaging name for non-releasing branch - if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) || github.repository_owner != 'supertuxkart' }} + if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) }} run: | echo "release_tag=" >> $GITHUB_ENV echo "release_name=" >> $GITHUB_ENV diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 40982f8b40e..add1375097c 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -56,8 +56,7 @@ jobs: echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV - name: Configure packaging name for non-releasing branch if: ${{ matrix.build_type != 'Release' || matrix.server_only != 'OFF' || - !(github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) || - github.repository_owner != 'supertuxkart' }} + !(github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) }} run: | echo "release_tag=" >> $GITHUB_ENV echo "release_name=" >> $GITHUB_ENV diff --git a/.github/workflows/switch.yml b/.github/workflows/switch.yml index 0d79d845d08..372f0db9453 100644 --- a/.github/workflows/switch.yml +++ b/.github/workflows/switch.yml @@ -45,7 +45,7 @@ jobs: echo "release_tag=`basename $GITHUB_REF`" >> $GITHUB_ENV echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV - name: Configure packaging name for non-releasing branch - if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) || github.repository_owner != 'supertuxkart' }} + if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) }} run: | echo "release_tag=" >> $GITHUB_ENV echo "release_name=" >> $GITHUB_ENV diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 79457639b82..f1aa25cd0ea 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -204,7 +204,7 @@ jobs: echo "release_name=`basename $GITHUB_REF`" >> $GITHUB_ENV - name: Configure packaging name for non-releasing branch shell : bash - if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) || github.repository_owner != 'supertuxkart' }} + if: ${{ (github.ref != 'refs/heads/master' && !startsWith(github.ref, 'refs/tags/')) }} run: | echo "release_tag=" >> $GITHUB_ENV echo "release_name=" >> $GITHUB_ENV From 0fc190ccd0af0c9f9f0f7802bd5be40581977f57 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 4 Jul 2025 02:16:53 +0400 Subject: [PATCH 806/830] Fix wrongly merged shader --- data/shaders/pointlight.frag | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/data/shaders/pointlight.frag b/data/shaders/pointlight.frag index 8479781e097..381a1fbb4e5 100644 --- a/data/shaders/pointlight.frag +++ b/data/shaders/pointlight.frag @@ -44,21 +44,6 @@ void main() att *= (radius - d) / radius; if (att <= 0.) discard; - // Spotlight - float sscale = direction_scale_offset.z; - if (sscale != 0.) - { - vec3 sdir = vec3(direction_scale_offset.xy, 0.); - sdir.z = sqrt(1. - dot(sdir, sdir)) * sign(sscale); - sdir = (u_view_matrix * vec4(sdir, 0.0)).xyz; - vec3 light_to_frag = light_pos - xpos.xyz; - float offset = direction_scale_offset.w; - float sattenuation = clamp(dot(-sdir, normalize(light_to_frag)) * - abs(sscale) + offset, 0.0, 1.0); - att *= sattenuation * sattenuation; - } - if (att <= 0.) discard; - // Light Direction vec3 L = light_to_frag / d; // Spotlight From 9aa4c76510d7cc92de068df0791d66318553b4ae Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 5 Jul 2025 02:07:24 +0400 Subject: [PATCH 807/830] Words again [skip ci] --- FORK_CHANGES.md | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/FORK_CHANGES.md b/FORK_CHANGES.md index bd47a0030b2..b283b45e83a 100644 --- a/FORK_CHANGES.md +++ b/FORK_CHANGES.md @@ -1,4 +1,4 @@ -This page lists the major changes of this repository compared to standard STK code, as of March 2025. Most changes (sadly, not all of them) here are implemented as options, that is, you can disable them and return to standard behaviour. +This page lists the major changes of this repository compared to standard STK code, as of July 2025. Most changes (sadly, not all of them) here are implemented as options, that is, you can disable them and return to standard behaviour. You can find more information such as explanations and minor details in [wiki](https://github.com/kimden/stk-code/wiki/). It will be probably filled with even more data in the future. @@ -16,9 +16,9 @@ You can find more information such as explanations and minor details in [wiki](h * Game results for **all** modes can be saved to the database, together with game settings and kart statistics. * Public or private record tables can be created using that information -* Ghost replays can be recorded on servers if set if the config and if players agree +* Ghost replays can be recorded on servers if set if the config * Players who beat server records can be notified (includes separation of times set with different config files) -* Maximum replay size is increased +* Maximum replay size is increased to allow recording long games with many players ## Chat @@ -93,16 +93,32 @@ Separate changes for modes: * Supported player categories aka sets of players (for now only displaying their names, and some minor usage) * Minor additions in StringUtils used in typo fixing and string parsing -## Current and future feature plans +## Better code and future plans -Since 2025, my approach for developing the code in this repository has changed, as I stopped believing I should do everything in the same way as the developers of the main game, and stopped being afraid of merge conflicts. After all, I even submitted a couple big patches into the official repository that way, and it was fine... +Since 2025, my approach for developing the code in this repository has changed, as I stopped believing I should do everything in the same way as the developers of the main game, and stopped being afraid of merge conflicts. After all, I even submitted a couple of big patches into the official repository that way, and it was fine... -Currently, the big restructurization of the code is underway, and one of the biggest and most complicated files in STK, `server_lobby.cpp`, got split into several files so that each file contains methods about the area it corresponds to. It allowed to fix a few hidden bugs, and will allow adding features in a simpler way in the future. +That's why the big restructurization of the code started in 2025 (and is still underway). -Another big topic is STK network protocol. It is messy and it's spread all over the codebase, while it's often hard to understand what exactly is being sent. That prevents its modification and advanced usage, and it's planned to rework it, so that it at least is understandable (which would also make the other code near the network packets cleaner). +* One of the biggest and most complicated files in STK, `server_lobby.cpp`, that is also responsible for a lot of server-side logic, got split into several files so that each file contains methods about the area it corresponds to. -## Better code +For comparison, in this fork `server_lobby.cpp` now has 4.5k lines — less than in official code (4.8k) or a few other forks (7.3k, 12.1k). -The aforementioned `server_lobby.cpp` is heavily used in all server-side forks, and no wonder its size can skyrocket in them, as people want to add many commands. Several frequently used forks have 12.5k and 7.3k lines of code in that file, while the official code has 4.8k lines. This repository has even fewer lines there, but more smaller files — for most features, there are simply much better places and ways to use them! +* To allow using modern code practices, the code and most of its required dependencies are now built using C++17. -The code has no proprietary scripts that are hardcoded inside to be unusable by others, no hidden anti-features such as secretly logged private chats, and here we do credit contributors according to what they have done (as in, `git blame` works correctly). Sadly, that's not a frequent offer in the world of STK — but you can make this offer even better by contributing to it! +Even if not directly noticeable for general playing public, those changes will allow adding features in a simpler way in the future. The large sized planned changes alone include: + +* Clean (and after that, modifiable) network protocol +* Further server lobby splitting +* Advanced competition formats support + +## Designed for you, too! + +This fork also offers: + +* No proprietary scripts that are hardcoded inside to be unusable by others +* No hidden anti-features such as secretly logged 'private' chats +* Contributors to the fork are credited with `git blame` correctly + +It ain't much, but it's honest work. (Sadly, somehow it's not even a frequent offer in the world of STK.) + +Your feedback (especially constructive one) will be appreciated, together with that of quite a few people who hosted their own servers (or even clients) using this fork. Contributing to this repo is also possible — however, we have quite high standards for contributors. \ No newline at end of file From 92335d77c0256c3570a39d936e0f0e9a10e0263d Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 5 Jul 2025 16:34:54 +0400 Subject: [PATCH 808/830] Rework /version, don't show preview and ignored releases --- .gitignore | 3 ++ CMakeLists.txt | 17 +++++++---- src/network/protocols/command_manager.cpp | 14 ++++----- src/utils/version.hpp.in | 36 +++++++++++++++++++++++ 4 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 src/utils/version.hpp.in diff --git a/.gitignore b/.gitignore index 70be3aea0af..878d94847fd 100644 --- a/.gitignore +++ b/.gitignore @@ -93,3 +93,6 @@ lib/astc-encoder lib/shaderc .DS_Store + +# Auto-generated files +src/utils/version.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d4440383799..51c59bd044d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,12 +9,22 @@ execute_process( # Get the latest abbreviated commit hash of the working branch execute_process( - COMMAND git --no-pager describe --tags --always --dirty + COMMAND git --no-pager describe --tags --always --exclude "preview" --exclude "ign-*" --dirty WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_COMMIT_HASH + OUTPUT_VARIABLE GIT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) +message(STATUS "Configuring file from: ${CMAKE_SOURCE_DIR}/src/utils/version.hpp.in") +message(STATUS "Output file: ${CMAKE_SOURCE_DIR}/src/utils/version.hpp") + +configure_file( + ${CMAKE_SOURCE_DIR}/src/utils/version.hpp.in + ${CMAKE_SOURCE_DIR}/src/utils/version.hpp + @ONLY) + +include_directories(${CMAKE_BINARY_DIR}/generated) + # root CMakeLists for the SuperTuxKart project project(SuperTuxKart) set(PROJECT_VERSION "git") @@ -655,9 +665,6 @@ else() endif() endif() -target_compile_definitions(supertuxkart PRIVATE "-DGIT_BRANCH=\"${GIT_BRANCH}\"") -target_compile_definitions(supertuxkart PRIVATE "-DGIT_VERSION=\"${GIT_COMMIT_HASH}\"") - # check if linking against libatomic is required include(CheckCXXSourceCompiles) check_cxx_source_compiles(" diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 29df04239a3..1052eac9602 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -50,6 +50,7 @@ #include "utils/string_utils.hpp" #include "utils/team_manager.hpp" #include "utils/tournament.hpp" +#include "utils/version.hpp" #include #include @@ -623,13 +624,12 @@ void CommandManager::initCommands() addTextResponse("description", getSettings()->getMotd()); addTextResponse("moreinfo", getSettings()->getHelpMessage()); - std::string version = "1.3 k 210fff beta"; -#ifdef GIT_VERSION - version = std::string(GIT_VERSION); - #ifdef GIT_BRANCH - version += ", branch " + std::string(GIT_BRANCH); - #endif -#endif + + std::string version = Version::version(); + std::string branch = Version::branch(); + if (!branch.empty()) + version += ", branch " + branch; + addTextResponse("version", version); addTextResponse("clear", std::string(30, '\n')); diff --git a/src/utils/version.hpp.in b/src/utils/version.hpp.in new file mode 100644 index 00000000000..d1752da4326 --- /dev/null +++ b/src/utils/version.hpp.in @@ -0,0 +1,36 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +// version.hpp is generated from version.hpp.in. +// While making changes, make sure to edit the correct file. + +#ifndef VERSION_HPP +#define VERSION_HPP + +#define GIT_BRANCH "@GIT_BRANCH@" +#define GIT_VERSION "@GIT_VERSION@" + +#include + +struct Version +{ + static std::string branch() { return GIT_BRANCH; } + static std::string version() { return GIT_VERSION; } +}; + +#endif // VERSION_HPP \ No newline at end of file From 91b58428d135fff93434b2d97e187324bf16058b Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 8 Jul 2025 00:02:42 +0400 Subject: [PATCH 809/830] Fix replay color and ambiguous naming --- src/replay/replay_recorder.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/replay/replay_recorder.cpp b/src/replay/replay_recorder.cpp index 4ea878cb47f..f28c78a7c33 100644 --- a/src/replay/replay_recorder.cpp +++ b/src/replay/replay_recorder.cpp @@ -378,13 +378,12 @@ void ReplayRecorder::save() min_time = cur_time; } - int day, month, year; - StkTime::getDate(&day, &month, &year); std::string time = StringUtils::toString(min_time); std::replace(time.begin(), time.end(), '.', '_'); std::ostringstream oss; - oss << Track::getCurrentTrack()->getIdent() << "_" << year << month << day - << "_" << num_karts << "_" << time << ".replay"; + oss << Track::getCurrentTrack()->getIdent() << "_"; + oss << StkTime::getLogTimeFormatted("%Y%m%d"); + oss << "_" << num_karts << "_" << time << ".replay"; m_filename = oss.str(); FILE *fd = openReplayFile(/*writeable*/true); @@ -412,13 +411,15 @@ void ReplayRecorder::save() fprintf(fd, "kart: %s %s\n", kart->getIdent().c_str(), StringUtils::xmlEncode(kart->getController()->getName()).c_str()); -/* if (kart->getController()->isPlayerController()) - { - fprintf(fd, "kart_color: %f\n", StateManager::get()->getActivePlayer(player_count)->getConstProfile()->getDefaultKartColor()); - player_count++; - } - else*/ - fprintf(fd, "kart_color: 0\n"); + // if (kart->getController()->isPlayerController()) + // { + // fprintf(fd, "kart_color: %f\n", StateManager::get()->getActivePlayer(player_count)->getConstProfile()->getDefaultKartColor()); + // player_count++; + // } + // else + // fprintf(fd, "kart_color: 0\n"); + + fprintf(fd, "kart_color: %f\n", RaceManager::get()->getKartColor(real_karts)); } m_last_uid = computeUID(min_time); From 7e46f5a5657daa6464c5c9b467ba2a74dd337c8a Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 14 Jul 2025 23:09:04 +0400 Subject: [PATCH 810/830] A few quote corrections in database connector Proper rewrite of queries will be in separate commits, as the queries are quite big and it requires more testing. --- src/network/database_connector.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/network/database_connector.cpp b/src/network/database_connector.cpp index 1e56bee6a8f..a05e88ac962 100644 --- a/src/network/database_connector.cpp +++ b/src/network/database_connector.cpp @@ -694,7 +694,7 @@ bool DatabaseConnector::writeReport( "INSERT INTO %s " "(server_uid, reporter_ip, reporter_ipv6, reporter_online_id, reporter_username, " "info, reporting_ip, reporting_ipv6, reporting_online_id, reporting_username) " - "VALUES (%s, %u, \"%s\", %u, %s, %s, %u, \"%s\", %u, %s);", + "VALUES (%s, %u, '%s', %u, %s, %s, %u, '%s', %u, %s);", ServerConfig::m_player_reports_table.c_str(), Binder(coll, ServerConfig::m_server_uid, "server_uid"), !reporter->getAddress().isIPv6() ? reporter->getAddress().getIP() : 0, @@ -1018,7 +1018,7 @@ void DatabaseConnector::onPlayerJoinQueries(std::shared_ptr peer, "country_code, version, os, ping" ", addon_karts_count, addon_tracks_count" ", addon_arenas_count, addon_soccers_count) " - "VALUES (%u, 0, \"%s\", %u, %u, %s, %u, %s, %s, %s, %u" + "VALUES (%u, 0, '%s', %u, %u, %s, %u, %s, %s, %s, %u" ", %d, %d, %d, %d);", m_server_stats_table.c_str(), peer->getHostId(), @@ -1121,7 +1121,7 @@ DatabaseConnector::getServerMessages(uint32_t online_id) const "SELECT rowid, reported_time, info FROM \"%s\" " "WHERE reporter_online_id = %u " "AND reporting_online_id = -1 " - "AND (server_uid = \"\" OR server_uid = \"%s\") LIMIT 1;", + "AND (server_uid = '' OR server_uid = '%s') LIMIT 1;", ServerConfig::m_player_reports_table.c_str(), online_id, ServerConfig::m_server_uid.c_str()); @@ -1172,8 +1172,8 @@ bool DatabaseConnector::getBestResult(const GameInfo& game_info, // limits can be NULL instead. SQLite manual specifies that IS can be used // to compare strings just as = operator. std::string query = StringUtils::insertValues("SELECT username, " - "result FROM \"%s\" WHERE venue = %s AND reverse = \"%s\" " - "AND mode = \"%s\" AND value_limit = %s AND time_limit = %s " + "result FROM \"%s\" WHERE venue = %s AND reverse = '%s' " + "AND mode = '%s' AND value_limit = %s AND time_limit = %s " "AND config = %s AND items = %s AND is_not_full = 0 AND game_event = 0 " "ORDER BY result ASC, time ASC LIMIT 1;", ServerConfig::m_records_table_name.c_str(), @@ -1230,10 +1230,10 @@ void DatabaseConnector::insertManyResults(const GameInfo& game_info) "username, result, kart, kart_class, kart_color, team, handicap, start_pos, fastest_lap, sog_time, " "online_id, country_code, is_autofinish, is_not_full, game_duration, when_joined, when_left, " "game_event, other_info) " - "VALUES (%s, %s, \"%s\", \"%s\", %d, %f, " + "VALUES (%s, %s, '%s', '%s', %d, %f, " "%d, %s, %s, %d, %d, " //%s, " "%s, %f, %s, %s, %f, %d, %d, %d, %f, %f, " - "%d, \"%s\", %d, %d, %f, %f, %f, " + "%d, '%s', %d, %d, %f, %f, %f, " "%d, %s);", m_results_table_name.c_str(), Binder(coll, game_info.m_timestamp, "time"), From f3ede1d4a493fb44981abe22f3031438bdf79e4b Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 19 Jul 2025 16:09:19 +0400 Subject: [PATCH 811/830] Fix folder names and (hopefully) rich presence for cross win compilation --- src/io/file_manager.cpp | 24 +++++++++++++++++------- src/io/rich_presence.cpp | 9 +++++---- src/io/rich_presence.hpp | 4 ++-- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/io/file_manager.cpp b/src/io/file_manager.cpp index 9d6610d4862..6365c8358a0 100644 --- a/src/io/file_manager.cpp +++ b/src/io/file_manager.cpp @@ -979,17 +979,27 @@ void FileManager::checkAndCreateConfigDir() else { -#if defined(WIN32) + #if defined(WIN_BUILD) // Try to use the APPDATA directory to store config files and highscore // lists. If not defined, used the current directory. + + std::string dir = ""; + + #if defined(WIN32) std::vector env; // An environment variable has a maximum size limit of 32,767 characters env.resize(32767, 0); DWORD length = GetEnvironmentVariable(L"APPDATA", env.data(), 32767); if (length != 0) + dir = StringUtils::wideToUtf8(env.data()); + #else + dir = getenv("APPDATA"); + #endif + + if (!dir.empty()) { - m_user_config_dir = StringUtils::wideToUtf8(env.data()); + m_user_config_dir = dir; if (!checkAndCreateDirectory(m_user_config_dir)) { Log::error("FileManager", "Can't create config dir '%s" @@ -1097,7 +1107,7 @@ void FileManager::checkAndCreateConfigDir() */ void FileManager::checkAndCreateAddonsDir() { -#if defined(WIN32) +#if defined(WIN_BUILD) m_addons_dir = m_user_config_dir+"../addons/"; #elif defined(__HAIKU__) m_addons_dir = m_user_config_dir+"addons/"; @@ -1138,7 +1148,7 @@ void FileManager::checkAndCreateAddonsDir() */ void FileManager::checkAndCreateScreenshotDir() { -#if defined(WIN32) || defined(__HAIKU__) +#if defined(WIN_BUILD) || defined(__HAIKU__) m_screenshot_dir = m_user_config_dir+"screenshots/"; #elif defined(__APPLE__) m_screenshot_dir = getenv("HOME"); @@ -1164,7 +1174,7 @@ void FileManager::checkAndCreateScreenshotDir() */ void FileManager::checkAndCreateReplayDir() { -#if defined(WIN32) || defined(__HAIKU__) +#if defined(WIN_BUILD) || defined(__HAIKU__) m_replay_dir = m_user_config_dir + "replay/"; #elif defined(__APPLE__) m_replay_dir = getenv("HOME"); @@ -1190,7 +1200,7 @@ void FileManager::checkAndCreateReplayDir() */ void FileManager::checkAndCreateCachedTexturesDir() { -#if defined(WIN32) || defined(__HAIKU__) +#if defined(WIN_BUILD) || defined(__HAIKU__) m_cached_textures_dir = m_user_config_dir + "cached-textures/"; #elif defined(__APPLE__) m_cached_textures_dir = getenv("HOME"); @@ -1215,7 +1225,7 @@ void FileManager::checkAndCreateCachedTexturesDir() */ void FileManager::checkAndCreateGPDir() { -#if defined(WIN32) || defined(__HAIKU__) +#if defined(WIN_BUILD) || defined(__HAIKU__) m_gp_dir = m_user_config_dir + "grandprix/"; #elif defined(__APPLE__) m_gp_dir = getenv("HOME"); diff --git a/src/io/rich_presence.cpp b/src/io/rich_presence.cpp index 858c9b393ba..637bc17e9fa 100644 --- a/src/io/rich_presence.cpp +++ b/src/io/rich_presence.cpp @@ -21,7 +21,7 @@ #include "online/request_manager.hpp" #include "online/http_request.hpp" -#if defined(__SWITCH__) || defined(MOBILE_STK) || defined(SERVER_ONLY) || defined(__MINGW32__) || defined(__MINGW64__) +#if defined(__SWITCH__) || defined(MOBILE_STK) || defined(SERVER_ONLY) #define DISABLE_RPC #endif @@ -77,7 +77,8 @@ void RichPresence::destroy() } RichPresence::RichPresence() : m_connected(false), m_ready(false), m_last(0), -#if defined(WIN32) && !(defined(__MINGW32__) || defined(__MINGW64__)) +#if defined(WIN_BUILD) +// && !(defined(__MINGW32__) || defined(__MINGW64__)) m_socket(INVALID_HANDLE_VALUE), #else m_socket(-1), @@ -98,7 +99,7 @@ RichPresence::~RichPresence() void RichPresence::terminate() { #ifndef DISABLE_RPC -#ifdef WIN32 +#ifdef WIN_BUILD #define UNCLEAN m_socket != INVALID_HANDLE_VALUE #else #define UNCLEAN m_socket != -1 @@ -166,7 +167,7 @@ bool RichPresence::doConnect() basePath = "/tmp"; completed: basePath = basePath + "/"; -#elif defined(WIN32) +#elif defined(WIN_BUILD) // Windows uses named pipes std::string basePath = "\\\\?\\pipe\\"; #endif diff --git a/src/io/rich_presence.hpp b/src/io/rich_presence.hpp index c70ee18fb9e..9e34b2d5f23 100644 --- a/src/io/rich_presence.hpp +++ b/src/io/rich_presence.hpp @@ -1,5 +1,5 @@ #include -#ifdef WIN32 +#ifdef WIN_BUILD #include #endif #include @@ -26,7 +26,7 @@ namespace RichPresenceNS bool m_connected; std::atomic_bool m_ready; time_t m_last; -#ifdef WIN32 +#ifdef WIN_BUILD HANDLE m_socket; #else int m_socket; From f584ed51254b735215634efb7be46ef27d0398d4 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Thu, 7 Aug 2025 23:46:09 +0400 Subject: [PATCH 812/830] Fix #41, use temp teams instead of standard ones --- src/network/protocols/server_lobby.cpp | 8 ++++-- src/network/remote_kart_info.hpp | 19 ------------- src/utils/chat_manager.cpp | 37 +++++++++++--------------- src/utils/chat_manager.hpp | 9 +++---- src/utils/set_with_flip.hpp | 31 +++++++++++++++++++++ src/utils/string_utils.cpp | 2 +- src/utils/tournament.cpp | 4 +-- src/utils/tournament.hpp | 2 +- 8 files changed, 60 insertions(+), 52 deletions(-) diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 2b47cd2b50c..0d067ceafe6 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -397,8 +397,12 @@ void ServerLobby::handleChat(Event* event) if (event->data().size() > 0) target_team = (KartTeam)event->data().getUInt8(); - getChatManager()->handleNormalChatMessage(peer, - StringUtils::wideToUtf8(message), target_team, m_name_decorator); + getChatManager()->handleNormalChatMessage( + peer, + StringUtils::wideToUtf8(message), + TeamUtils::getIndexFromKartTeam(target_team), + m_name_decorator + ); } // handleChat //----------------------------------------------------------------------------- diff --git a/src/network/remote_kart_info.hpp b/src/network/remote_kart_info.hpp index 1ba403aed72..829ace8d4a2 100644 --- a/src/network/remote_kart_info.hpp +++ b/src/network/remote_kart_info.hpp @@ -38,25 +38,6 @@ enum KartTeam : int8_t KART_TEAM_BLUE=1, }; -struct KartTeamSet -{ - int state; - KartTeamSet(int x = 0): state(x) {} - - bool has (KartTeam team) const { return ((state >> (team + 1)) & 1); } - bool empty() const { return state == 0; } - - KartTeamSet operator + (KartTeam team) const { return KartTeamSet(state | (1 << (team + 1))); } - KartTeamSet operator - (KartTeam team) const { return KartTeamSet(state & ~(1 << (team + 1))); } - KartTeamSet operator ^ (KartTeam team) const { return KartTeamSet(state ^ (1 << (team + 1))); } - KartTeamSet operator & (KartTeamSet rhs) const { return KartTeamSet(state & rhs.state); } - - void add (KartTeam team) { state |= (1 << (team + 1)); } - void remove (KartTeam team) { state &= ~(1 << (team + 1)); } - void flip (KartTeam team) { state ^= (1 << (team + 1)); } - void intersect(KartTeamSet rhs) { state &= rhs.state; } -}; - /** Handicap per player. */ enum HandicapLevel : uint8_t { diff --git a/src/utils/chat_manager.cpp b/src/utils/chat_manager.cpp index 2f2abffd8ff..c0a920cb7d0 100644 --- a/src/utils/chat_manager.cpp +++ b/src/utils/chat_manager.cpp @@ -32,9 +32,7 @@ namespace { - const std::string g_red_team = StringUtils::utf32ToUtf8({0x1f7e5, 0x20}); - const std::string g_blue_team = StringUtils::utf32ToUtf8({0x1f7e6, 0x20}); - const std::string g_private_chat = StringUtils::utf32ToUtf8({0x1f512, 0x20}); + const std::string g_private_chat = StringUtils::utf32ToUtf8({0x1f512}); }; @@ -164,7 +162,7 @@ void ChatManager::onPeerDisconnect(std::shared_ptr peer) //----------------------------------------------------------------------------- void ChatManager::handleNormalChatMessage(std::shared_ptr peer, - std::string message, KartTeam target_team, + std::string message, int target_team, const std::shared_ptr& decorator) { // Update so that the peer is not kicked @@ -207,22 +205,17 @@ void ChatManager::handleNormalChatMessage(std::shared_ptr peer, const bool game_started = !getLobby()->isWaitingForStartGame(); auto can_receive = getMessageReceiversFor(peer); if (!can_receive.empty()) - message = g_private_chat + message; - - bool team_mode = ( - RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_SOCCER || - RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG - ); + message = g_private_chat + " " + message; bool team_speaker = isTeamSpeaker(peer); - KartTeamSet teams = getTeamsForPeer(peer); + SetWithFlip teams = getTeamsForPeer(peer); // Add team emojis - if (target_team == KART_TEAM_RED || (team_speaker && team_mode && teams.has(KART_TEAM_RED))) - message = g_red_team + message; - - if (target_team == KART_TEAM_BLUE || (team_speaker && team_mode && teams.has(KART_TEAM_BLUE))) - message = g_blue_team + message; + for (int i = 1; i <= TeamUtils::getNumberOfTeams(); ++i) + { + if (target_team == i || (team_speaker && teams.has(i))) + message = TeamUtils::getTeamByIndex(i).getEmoji() + " " + message; + } NetworkString* chat = getLobby()->getNetworkString(); chat->setSynchronous(true); @@ -246,7 +239,7 @@ void ChatManager::handleNormalChatMessage(std::shared_ptr peer, bool ChatManager::shouldMessageBeSent(std::shared_ptr sender, std::shared_ptr target, bool game_started, - KartTeam target_team) + int target_team) { if (sender == target) return true; @@ -255,7 +248,7 @@ bool ChatManager::shouldMessageBeSent(std::shared_ptr sender, if (target->isWaitingForGame() ^ sender->isWaitingForGame()) return false; - if (target_team != KART_TEAM_NONE) + if (target_team != TeamUtils::NO_TEAM) { if (target->isSpectator()) return false; @@ -270,7 +263,7 @@ bool ChatManager::shouldMessageBeSent(std::shared_ptr sender, if (tournament->cannotSendForSureDueToRoles(sender, target)) return false; - if (target_team != KART_TEAM_NONE) + if (target_team != TeamUtils::NO_TEAM) { if (!tournament->hasProfileThatSeesTeamchats(target) && !Tournament::hasProfileFromTeam(target, target_team)) @@ -294,12 +287,12 @@ bool ChatManager::shouldMessageBeSent(std::shared_ptr sender, //----------------------------------------------------------------------------- // Should be called not once per message. Fix later -KartTeamSet ChatManager::getTeamsForPeer(std::shared_ptr peer) const +SetWithFlip ChatManager::getTeamsForPeer(std::shared_ptr peer) const { - KartTeamSet teams; + SetWithFlip teams; for (auto& profile: peer->getPlayerProfiles()) - teams.add(profile->getTeam()); + teams.add(profile->getTemporaryTeam()); return teams; } // getTeamsForPeer diff --git a/src/utils/chat_manager.hpp b/src/utils/chat_manager.hpp index a060837c816..6962e754620 100644 --- a/src/utils/chat_manager.hpp +++ b/src/utils/chat_manager.hpp @@ -21,6 +21,7 @@ #include "irrString.h" #include "utils/lobby_context.hpp" +#include "utils/set_with_flip.hpp" #include "utils/types.hpp" #include @@ -29,8 +30,6 @@ #include class STKPeer; -enum KartTeam : int8_t; -struct KartTeamSet; class GenericDecorator; class ChatManager: public LobbyContextComponent @@ -79,15 +78,15 @@ class ChatManager: public LobbyContextComponent int getChatConsecutiveInterval() const { return m_chat_consecutive_interval; } void handleNormalChatMessage(std::shared_ptr peer, - std::string message, KartTeam target_team, + std::string message, int target_team, const std::shared_ptr& decorator); bool shouldMessageBeSent(std::shared_ptr sender, std::shared_ptr target, bool game_started, - KartTeam target_team); + int target_team); - KartTeamSet getTeamsForPeer(std::shared_ptr peer) const; + SetWithFlip getTeamsForPeer(std::shared_ptr peer) const; bool isInPrivateChatRecipients(std::shared_ptr sender, std::shared_ptr target) const; }; diff --git a/src/utils/set_with_flip.hpp b/src/utils/set_with_flip.hpp index 8130fbefec7..b54795664e1 100644 --- a/src/utils/set_with_flip.hpp +++ b/src/utils/set_with_flip.hpp @@ -30,6 +30,8 @@ enum Op: int SWF_OP_FLIP = -1, }; +// Add several implementations for different cases later +// (e.g. bitset at most 60 elements) template class SetWithFlip: public std::set { @@ -56,6 +58,11 @@ class SetWithFlip: public std::set return add(element); } + bool has(const T& element) + { + return this->find(element) != this->end(); + } + int set(const T& element, int type) { switch (type) @@ -69,6 +76,30 @@ class SetWithFlip: public std::set "defaulting to flip (%d).", type, SWF_OP_FLIP); return flip(element); } + + // Iterates over all elements, works in O(n log n). Use with caution. + SetWithFlip operator & (const SetWithFlip& rhs) const + { + auto it1 = this->cbegin(); + auto it2 = rhs.cbegin(); + SetWithFlip result; + while (it1 != this->cend() && it2 != rhs.cend()) + { + const T& a = *it1; + const T& b = *it2; + if (a == b) + { + result.insert(a); + ++it1; + ++it2; + } + else if (a < b) + ++it1; + else + ++it2; + } + return result; + } }; #endif \ No newline at end of file diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index c03ec85ad5f..af132c19aa6 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -993,7 +993,7 @@ namespace StringUtils } // wideToUtf8 // ------------------------------------------------------------------------ - /** Converts the irrlicht wide string to an utf8-encoded std::string. */ + /** Converts the utf8-encoded std::string to an irrlicht wide string. */ irr::core::stringw utf8ToWide(const char* input) { std::vector wchar_line; diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp index 0839584d624..d11b13feca1 100644 --- a/src/utils/tournament.cpp +++ b/src/utils/tournament.cpp @@ -505,11 +505,11 @@ bool Tournament::hasProfileThatSeesTeamchats(std::shared_ptr peer) cons } // hasProfileThatSeesTeamchats //----------------------------------------------------------------------------- -bool Tournament::hasProfileFromTeam(std::shared_ptr peer, KartTeam target_team) +bool Tournament::hasProfileFromTeam(std::shared_ptr peer, int target_team) { for (auto& player : peer->getPlayerProfiles()) { - if (player->getTeam() == target_team) + if (player->getTemporaryTeam() == target_team) return true; } return false; diff --git a/src/utils/tournament.hpp b/src/utils/tournament.hpp index 8479d5f1f4f..233998275bf 100644 --- a/src/utils/tournament.hpp +++ b/src/utils/tournament.hpp @@ -95,7 +95,7 @@ class Tournament: public LobbyContextComponent // Technically this should be either in STKPeer or in TeamManager, // quick fix is to just make it static - static bool hasProfileFromTeam(std::shared_ptr peer, KartTeam target_team); + static bool hasProfileFromTeam(std::shared_ptr peer, int target_team); private: From 41edb6911354d09ab81be22823bd959a4ca9e887 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Tue, 12 Aug 2025 22:19:14 +0400 Subject: [PATCH 813/830] Some whitespace and string cleanups --- src/network/protocols/command_manager.cpp | 10 +- src/utils/kart_elimination.cpp | 133 +++++++++++++++++----- src/utils/kart_elimination.hpp | 5 + src/utils/set_typo_fixer.cpp | 7 ++ src/utils/set_typo_fixer.hpp | 2 + src/utils/team_manager.cpp | 23 ++-- src/utils/team_manager.hpp | 3 +- src/utils/team_utils.hpp | 16 ++- 8 files changed, 142 insertions(+), 57 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 1052eac9602..728e06fa7a4 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -2114,19 +2114,19 @@ void CommandManager::process_gnu(Context& context) auto kart_elimination = getKartElimination(); if (turn_on && kart_elimination->isEnabled()) { - context.say("Gnu Elimination mode was already enabled!"); + context.say(kart_elimination->getAlreadyEnabledString()); return; } if (!turn_on && !kart_elimination->isEnabled()) { - context.say("Gnu Elimination mode was already off!"); + context.say(kart_elimination->getAlreadyOffString()); return; } if (turn_on && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_NORMAL_RACE && RaceManager::get()->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL) { - context.say("Gnu Elimination is available only with racing modes"); + context.say(kart_elimination->getOnlyRacingString()); return; } std::string kart; @@ -2166,7 +2166,7 @@ void CommandManager::process_gnu(Context& context) if (kart == "off") { kart_elimination->disable(); - Comm::sendStringToAllPeers("Gnu Elimination is now off"); + Comm::sendStringToAllPeers(kart_elimination->getNowOffMessage()); } else { @@ -3161,7 +3161,7 @@ void CommandManager::process_game(Context& context) if (tournament->hasColorsSwapped(new_game_number) ^ tournament->hasColorsSwapped(old_game_number)) { - getTeamManager()->changeColors(); + getTeamManager()->swapRedBlueTeams(); getLobby()->updatePlayerList(); } diff --git a/src/utils/kart_elimination.cpp b/src/utils/kart_elimination.cpp index 66512e6f4ab..291dc4eaf75 100644 --- a/src/utils/kart_elimination.cpp +++ b/src/utils/kart_elimination.cpp @@ -33,6 +33,49 @@ #include #include +namespace +{ + std::string g_default_kart = "gnu"; + + std::string g_start_message_gnu = + "Gnu Elimination starts now! " + "Use /standings after each race for results."; + + std::string g_start_message_generic = + "Gnu Elimination starts now (elimination kart: %s)! " + "Use /standings after each race for results."; + + std::string g_place_continues = "%s. %s"; + std::string g_place_eliminated = "[%s]. %s"; + + std::string g_warning_eliminated = + "Gnu Elimination is played right now on this server, " + "you will be forced to use kart %s until it ends."; + + std::string g_warning_continues = + "Gnu Elimination is played right now on this server " + "with kart %s. You are not eliminated yet."; + + std::string g_see_standings = "Use /standings to see the results."; + + std::string g_eliminated_alone = "is now eliminated."; + std::string g_eliminated_plural = "are now eliminated."; + + std::string g_finished_winner = + "Gnu Elimination has finished! Congratulations to %s !"; + + std::string g_elimination_running = "Gnu Elimination is running"; + std::string g_elimination_disabled = "Gnu Elimination is disabled"; + std::string g_before_standings_prefix = "standings"; + + std::string g_now_off = "Gnu Elimination is now off"; + std::string g_already_on = "Gnu Elimination mode was already enabled!"; + std::string g_already_off = "Gnu Elimination mode was already off!"; + std::string g_only_racing = "Gnu Elimination is available only with racing modes"; + +} // namespace +//----------------------------------------------------------------------------- + void KartElimination::setupContextUser() { m_enabled = false; @@ -65,20 +108,22 @@ std::set KartElimination::getRemainingParticipants() const std::string KartElimination::getStandings() const { - std::string result = "Gnu Elimination "; - if (m_enabled) - result += "is running"; - else - result += "is disabled"; + std::string result = (m_enabled ? g_elimination_running : g_elimination_disabled); + if (!m_participants.empty()) - result += ", standings:"; + result += ", " + g_before_standings_prefix + ":"; + for (int i = 0; i < (int)m_participants.size(); i++) { - std::string line = "\n" + (i < m_remained ? - std::to_string(i + 1) : "[" + std::to_string(i + 1) + "]"); - line += ". " + m_participants[i]; + std::string line = "\n"; + line += StringUtils::insertValues( + i < m_remained ? g_place_continues : g_place_eliminated, + i + 1, + m_participants[i] + ); result += line; } + return result; } // getStandings //----------------------------------------------------------------------------- @@ -103,23 +148,17 @@ void KartElimination::enable(std::string kart) std::string KartElimination::getStartingMessage() const { - if (m_kart == "gnu") - return "Gnu Elimination starts now! Use /standings " - "after each race for results."; + if (m_kart == g_default_kart) + return g_start_message_gnu; else - return StringUtils::insertValues("Gnu Elimination starts now " - "(elimination kart: %s)! Use /standings " - "after each race for results.", m_kart.c_str()); + return StringUtils::insertValues(g_start_message_generic, m_kart.c_str()); } // getStartingMessage //----------------------------------------------------------------------------- std::string KartElimination::getWarningMessage(bool isEliminated) const { - std::string what = "Gnu Elimination is played right now on this server"; - what += (isEliminated ? - ", you will be forced to use kart %s until it ends." : - " with kart %s. You are not eliminated yet."); - what += " Use /standings to see the results."; + std::string what = (isEliminated ? g_warning_eliminated : g_warning_continues); + what += " " + g_see_standings; return StringUtils::insertValues(what, m_kart.c_str()); } // getWarningMessage //----------------------------------------------------------------------------- @@ -127,7 +166,12 @@ std::string KartElimination::getWarningMessage(bool isEliminated) const std::string KartElimination::onRaceFinished() { World* w = World::getWorld(); - assert(w); + if (!w) + { + Log::error("KartElimination", "onRaceFinished aborted: World was not found."); + return ""; + } + int player_count = RaceManager::get()->getNumPlayers(); std::map order; for (int i = 0; i < player_count; i++) @@ -139,18 +183,23 @@ std::string KartElimination::onRaceFinished() order[username] = RaceManager::get()->getKartRaceTime(i); } - assert(m_remained != 0); + if (m_remained == 0) + { + Log::error("KartElimination", "onRaceFinished aborted: Number of remained karts was 0."); + return ""; + } + if (m_remained < 0) { m_remained = order.size(); for (const auto& p: order) m_participants.push_back(p.first); } + for (int i = 0; i < m_remained; i++) - { if (order.count(m_participants[i]) == 0) order[m_participants[i]] = KartElimination::INF_TIME; - } + std::stable_sort( m_participants.begin(), m_participants.begin() + m_remained, @@ -160,6 +209,7 @@ std::string KartElimination::onRaceFinished() return it1->second < it2->second; } ); + std::string msg = ""; msg += m_participants[--m_remained]; bool alone = true; @@ -169,16 +219,39 @@ std::string KartElimination::onRaceFinished() msg += ", " + m_participants[--m_remained]; alone = false; } - if (alone) - msg += " is now eliminated."; - else - msg += " are now eliminated."; + + msg += " " + (alone ? g_eliminated_alone : g_eliminated_plural); + if (m_remained <= 1) { m_enabled = false; - msg += "\nGnu Elimination has finished! " - "Congratulations to " + m_participants[0] + " !"; + msg += "\n"; + msg += StringUtils::insertValues(g_finished_winner, m_participants[0].c_str()); } return msg; } // onRaceFinished +//----------------------------------------------------------------------------- + +std::string KartElimination::getNowOffMessage() +{ + return g_now_off; +} // getNowOffMessage +//----------------------------------------------------------------------------- + +std::string KartElimination::getAlreadyEnabledString() +{ + return g_already_on; +} // getAlreadyEnabledString +//----------------------------------------------------------------------------- + +std::string KartElimination::getAlreadyOffString() +{ + return g_already_off; +} // getAlreadyOffString +//----------------------------------------------------------------------------- + +std::string KartElimination::getOnlyRacingString() +{ + return g_only_racing; +} // getOnlyRacingString //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/kart_elimination.hpp b/src/utils/kart_elimination.hpp index e1a3c139ff2..5e76ffdac6f 100644 --- a/src/utils/kart_elimination.hpp +++ b/src/utils/kart_elimination.hpp @@ -55,6 +55,11 @@ class KartElimination: public LobbyContextComponent std::string getStartingMessage() const; std::string getWarningMessage(bool isEliminated) const; std::string onRaceFinished(); + + static std::string getNowOffMessage(); + static std::string getAlreadyEnabledString(); + static std::string getAlreadyOffString(); + static std::string getOnlyRacingString(); }; #endif diff --git a/src/utils/set_typo_fixer.cpp b/src/utils/set_typo_fixer.cpp index 220a15fc23a..7f859e155f4 100644 --- a/src/utils/set_typo_fixer.cpp +++ b/src/utils/set_typo_fixer.cpp @@ -46,14 +46,17 @@ std::vector> SetTypoFixer::getClosest( { std::map ans_map; std::vector> ans; + if (m_set.empty()) return ans; + auto it = m_set.find(query); if (it != m_set.end()) { ans.emplace_back(m_map.find(query)->second, 0); return ans; } + const std::string& query_ref = query; for (const std::string& s: m_set) { @@ -66,8 +69,10 @@ std::vector> SetTypoFixer::getClosest( else ans_map[value] = distance; } + for (const auto& p: ans_map) ans.emplace_back(p.first, p.second); + std::sort(ans.begin(), ans.end(), [] (const std::pair& a, const std::pair& b) -> bool @@ -76,8 +81,10 @@ std::vector> SetTypoFixer::getClosest( return a.second < b.second; return a.first < b.first; }); + if ((int)ans.size() > count) ans.resize(count); + return ans; } // getClosest //----------------------------------------------------------------------------- diff --git a/src/utils/set_typo_fixer.hpp b/src/utils/set_typo_fixer.hpp index a961124a746..4105ce04512 100644 --- a/src/utils/set_typo_fixer.hpp +++ b/src/utils/set_typo_fixer.hpp @@ -40,10 +40,12 @@ class SetTypoFixer private: std::multiset m_set; std::map m_map; + public: void add(const std::string& key); void add(const std::string& key, const std::string& value); void remove(const std::string& key); + std::vector> getClosest( const std::string& query, int count = 3, bool case_sensitive = true) const; diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp index 52a16cefa52..a32c012494d 100644 --- a/src/utils/team_manager.cpp +++ b/src/utils/team_manager.cpp @@ -254,6 +254,7 @@ int TeamManager::getTeamForUsername(const std::string& name) auto it = m_team_for_player.find(name); if (it == m_team_for_player.end()) return TeamUtils::NO_TEAM; + return it->second; } // getTeamForUsername //----------------------------------------------------------------------------- @@ -274,29 +275,20 @@ void TeamManager::clearTemporaryTeams() clearTeams(); for (auto& peer : STKHost::get()->getPeers()) - { for (auto& profile : peer->getPlayerProfiles()) - { setTemporaryTeamInLobby(profile, TeamUtils::NO_TEAM); - } - } } // clearTemporaryTeams //----------------------------------------------------------------------------- void TeamManager::shuffleTemporaryTeams(const std::map& permutation) { applyPermutationToTeams(permutation); + for (auto& peer : STKHost::get()->getPeers()) - { for (auto &profile: peer->getPlayerProfiles()) - { - auto it = permutation.find(profile->getTemporaryTeam()); - if (it != permutation.end()) - { + if (auto it = permutation.find(profile->getTemporaryTeam()); it != permutation.end()) setTemporaryTeamInLobby(profile, it->second); - } - } - } + getGPManager()->shuffleGPScoresWithPermutation(permutation); } // shuffleTemporaryTeams //----------------------------------------------------------------------------- @@ -480,10 +472,9 @@ std::string TeamManager::countTeamsAsString() } // countTeamsAsString //----------------------------------------------------------------------------- -void TeamManager::changeColors() +// This command was made specifically for soccer. +void TeamManager::swapRedBlueTeams() { - // We assume here that it's soccer, as it's only called - // from tournament command auto peers = STKHost::get()->getPeers(); for (auto peer : peers) { @@ -498,5 +489,5 @@ void TeamManager::changeColors() setTeamInLobby(pp, KART_TEAM_RED); } } -} // changeColors +} // swapRedBlueTeams //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/team_manager.hpp b/src/utils/team_manager.hpp index 77b370e7d57..8431347ab5c 100644 --- a/src/utils/team_manager.hpp +++ b/src/utils/team_manager.hpp @@ -82,7 +82,8 @@ class TeamManager: public LobbyContextComponent bool assignRandomTeams(int intended_number, int* final_number, int* player_number); std::string countTeamsAsString(); - void changeColors(); + + void swapRedBlueTeams(); private: diff --git a/src/utils/team_utils.hpp b/src/utils/team_utils.hpp index a47e2ddd7a3..f56296478be 100644 --- a/src/utils/team_utils.hpp +++ b/src/utils/team_utils.hpp @@ -31,20 +31,22 @@ // A set of classes that will manipulate teams, their names // and representations such as emojis, and probably something else -// in the future. Those teams currently have no relation to soccer -// or CTF teams, but some kind of synchronization would be nice. +// in the future. TeamManager is synchronizing these teams with the 'standard' +// teams you typically see in soccer or CTF. // A class describing team properties. Properties are supposed to be // initialized and remain unchanged for now. class CustomTeam { private: + // Codes currently should start with different chars // as e.g. swapteams in CommandManager breaks otherwise std::vector m_codes; // Must contain at least 1 (primary) code std::vector m_names; // Must contain at least 1 (primary) name - float m_color; // One color only for now + float m_color; // One color only for now std::string m_emoji; // Currently only one emoji + public: CustomTeam(std::vector& codes, std::vector& names, @@ -70,26 +72,30 @@ class TeamsStorage std::vector m_teams; std::map m_finder_by_code; std::map m_finder_by_name; + void addTeam(std::string hardcoded_code, std::string hardcoded_name, float hardcoded_color, std::string hardcoded_emoji); + void addCode(int idx, std::string hardcoded_code); void addName(int idx, std::string hardcoded_name); + public: TeamsStorage(); + // Teams are indexed from 1 to N, 0 means no team set (or undefined). // Previously the code had 4-way inconsistent indexation // but hopefully it's fixed now const CustomTeam& operator[](int idx) const; int getIndexByCode(const std::string& code) const; int getIndexByName(const std::string& name) const; - int getNumberOfTeams() const - { return (int)m_teams.size() - 1; } + int getNumberOfTeams() const { return (int)m_teams.size() - 1; } }; class TeamUtils: public Singleton { public: static const int NO_TEAM = 0; + static const CustomTeam& getTeamByIndex(int idx) { return (*getInstance())[idx]; } static int getIndexByCode(const std::string& code) From c4669c4d55d1be1015549ac4812075285166e784 Mon Sep 17 00:00:00 2001 From: matahina Date: Wed, 13 Aug 2025 12:05:50 +0200 Subject: [PATCH 814/830] Missing line prevents compilation :( --- src/network/protocols/game_events_protocol.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/protocols/game_events_protocol.hpp b/src/network/protocols/game_events_protocol.hpp index 0cc05fcf616..073c3f4ca7a 100644 --- a/src/network/protocols/game_events_protocol.hpp +++ b/src/network/protocols/game_events_protocol.hpp @@ -3,6 +3,7 @@ #include "network/protocol.hpp" #include "utils/cpp2011.hpp" +#include class AbstractKart; From 429a92ae2b68ee6e009fe4c84446a955290218f8 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 16 Aug 2025 15:55:24 +0400 Subject: [PATCH 815/830] Allow booking slots for specified players (however, they might be unable to join the full server still) --- NETWORKING.md | 5 +- data/commands.xml | 18 +++++++ src/network/protocols/command_manager.cpp | 65 +++++++++++++++++++++++ src/network/protocols/command_manager.hpp | 1 + src/network/protocols/server_lobby.cpp | 13 +++++ src/network/server_config.hpp | 7 +++ src/network/stk_host.cpp | 14 +++-- src/network/stk_host.hpp | 9 +++- src/network/stk_peer.cpp | 1 + src/network/stk_peer.hpp | 9 ++++ src/utils/crown_manager.cpp | 3 ++ src/utils/lobby_settings.cpp | 64 +++++++++++++++++++++- src/utils/lobby_settings.hpp | 10 ++++ src/utils/set_with_flip.hpp | 10 +++- 14 files changed, 220 insertions(+), 9 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index 153981c25a0..8b4f3bcba59 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -400,9 +400,12 @@ A typical current server configuration xml that fits the current code version is - + + + + ``` diff --git a/data/commands.xml b/data/commands.xml index 40ae715f758..f9e25b61683 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -871,6 +871,24 @@ here later. For now, please refer to the code for the strings being used. --> description="Toggles whether a category is displayed in the player list." permissions="UP_HAMMER" /> + + + 2) + { + error(context); + return; + } + if (argv.size() == 2) + { + if (!validate(context, 1, TFT_PRESENT_USERS, false, true)) + return; + context.say(getSettings()->isSlotBookedForAsString(argv[1])); + } + else + { + context.say(getSettings()->getAllBookedSlotsAsString()); + } + + return; + } + if (argv[0] == "vip+") + { + if (argv.size() != 2) + { + error(context); + return; + } + if (!validate(context, 1, TFT_PRESENT_USERS, false, true)) + return; + std::string player = argv[1]; + getSettings()->bookSlotForPlayer(player); + getLobby()->updatePlayerList(); + context.say(StringUtils::insertValues( + "Booked a slot for %s", + player)); + return; + } + if (argv[0] == "vip-") + { + if (argv.size() != 2) + { + error(context); + return; + } + if (!validate(context, 1, TFT_PRESENT_USERS, false, true)) + return; + std::string player = argv[1]; + getSettings()->unbookSlotForPlayer(player); + getLobby()->updatePlayerList(); + context.say(StringUtils::insertValues( + "Unbooked a slot for %s", + player)); + return; + } +} // process_vip +// ======================================================================== + void CommandManager::process_troll(Context& context) { std::string msg; diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 848f2e5fc5d..7504d403278 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -333,6 +333,7 @@ class CommandManager: public LobbyContextComponent void process_randomteams(Context& context); void process_resetgp(Context& context); void process_cat(Context& context); + void process_vip(Context& context); void process_troll(Context& context); void process_troll_assign(Context& context); void process_hitmsg(Context& context); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 0d067ceafe6..3f6bf333e24 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -2583,6 +2583,10 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr peer, auto red_blue = STKHost::get()->getAllPlayersTeamInfo(); std::string utf8_online_name = StringUtils::wideToUtf8(online_name); + + if (online_id > 0 && getSettings()->isSlotBookedFor(utf8_online_name)) + peer->setBookedSlot(true); + for (unsigned i = 0; i < player_count; i++) { core::stringw name; @@ -2883,6 +2887,15 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) for (int i = angry_host; i > 0; --i) profile_name = StringUtils::utf32ToWide({0x1F528}) + profile_name; + auto peer = profile->getPeer(); + if (peer) + { + if (peer->hasSlotBooked() && peer->getMainProfile() == profile) + profile_name = StringUtils::utf32ToWide({ 0x1F22F }) + profile_name; + } + else + Log::error("ServerLobby", "updatePlayerList: profile has no peer!"); + std::string prefix = ""; for (const std::string& category: getTeamManager()->getVisibleCategoriesForPlayer(utf8_profile_name)) { diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index 34f6be92405..c135841ecf0 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -806,6 +806,13 @@ namespace ServerConfig "Timeout in seconds during which you cannot start the next game, " "regardless of hammers, votes, or buttons pressed.")); + SERVER_CFG_PREFIX StringServerConfigParam m_reserve_slots_for_players + SERVER_CFG_DEFAULT(StringServerConfigParam("", + "reserve-slots-for-players", + "Official players with these usernames will be allowed to enter " + "and take the playable slots of the server, even if the server " + "is full. Make sure to not specify too many of them!")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index c378114da14..a4406d4ee9a 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -1467,20 +1467,26 @@ std::shared_ptr STKHost::findPeerByHostId(uint32_t id) const //----------------------------------------------------------------------------- std::shared_ptr - STKHost::findPeerByName(const core::stringw& name) const + STKHost::findPeerByName(const core::stringw& name, + bool mustBeOfficial) const { std::lock_guard lock(m_peers_mutex); auto ret = std::find_if(m_peers.begin(), m_peers.end(), - [name](const std::pair >& p) + [name, mustBeOfficial](const std::pair >& p) { bool found = false; for (auto& profile : p.second->getPlayerProfiles()) { - if (profile->getName() == name) - { + if (profile->getName() == name && + (!mustBeOfficial || profile->getOnlineId() > 0)) + { found = true; break; } + + // Check only first profile if mustBeOfficial + if (mustBeOfficial) + break; } return found; }); diff --git a/src/network/stk_host.hpp b/src/network/stk_host.hpp index 8191568533c..20e26de91ae 100644 --- a/src/network/stk_host.hpp +++ b/src/network/stk_host.hpp @@ -268,8 +268,13 @@ class STKHost // ------------------------------------------------------------------------ std::shared_ptr findPeerByHostId(uint32_t id) const; // ------------------------------------------------------------------------ - std::shared_ptr findPeerByName(const core::stringw& name) const; - std::shared_ptr findPeerByWildcard(const core::stringw& name_pattern, std::string &name_found) const; + std::shared_ptr findPeerByName( + const core::stringw& name, + bool mustBeOfficial = false) const; + // ------------------------------------------------------------------------ + std::shared_ptr findPeerByWildcard( + const core::stringw& name_pattern, + std::string &name_found) const; // ------------------------------------------------------------------------ void sendPacketExcept(std::shared_ptr peer, NetworkString *data, PacketReliabilityMode reliable = PRM_RELIABLE); diff --git a/src/network/stk_peer.cpp b/src/network/stk_peer.cpp index 4b1a978376c..7ab96e3af21 100644 --- a/src/network/stk_peer.cpp +++ b/src/network/stk_peer.cpp @@ -58,6 +58,7 @@ STKPeer::STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id) m_last_message.store(0); m_angry_host.store(false); m_consecutive_messages = 0; + m_booked_slot.store(false); } // STKPeer //----------------------------------------------------------------------------- diff --git a/src/network/stk_peer.hpp b/src/network/stk_peer.hpp index ebed54e3d92..a7a19c782d8 100644 --- a/src/network/stk_peer.hpp +++ b/src/network/stk_peer.hpp @@ -140,6 +140,8 @@ class STKPeer : public NoCopy std::array m_addons_scores; std::atomic_int m_angry_host; + + std::atomic_bool m_booked_slot; public: STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id); // ------------------------------------------------------------------------ @@ -383,6 +385,13 @@ class STKPeer : public NoCopy // ------------------------------------------------------------------------ void setHammerLevel(int val) { m_angry_host.store(val); } // ------------------------------------------------------------------------ + bool hasSlotBooked() const { return m_booked_slot.load(); } + // ------------------------------------------------------------------------ + // Note that m_bookedSlot is just a copy from LobbySettings' setting. + // Setter provided here should not be used externally. + + void setBookedSlot(bool value) { m_booked_slot.store(value); } + // ------------------------------------------------------------------------ std::shared_ptr getMainProfile(); // ------------------------------------------------------------------------ std::string getMainName() const; diff --git a/src/utils/crown_manager.cpp b/src/utils/crown_manager.cpp index 39adf214200..7ae6a2eb7d8 100644 --- a/src/utils/crown_manager.cpp +++ b/src/utils/crown_manager.cpp @@ -229,6 +229,9 @@ bool CrownManager::defaultOrderComparator( const std::shared_ptr a, const std::shared_ptr b) { + if (a->hasSlotBooked() ^ b->hasSlotBooked()) + return a->hasSlotBooked(); + return a->getRejoinTime() < b->getRejoinTime(); } // defaultOrderComparator //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index 6d8cbc53a06..b7a81791ef8 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -125,6 +125,9 @@ void LobbySettings::setupContextUser() m_power_password_level_2 = ServerConfig::m_power_password_level_2; m_register_table_name = ServerConfig::m_register_table_name; m_lobby_cooldown = ServerConfig::m_lobby_cooldown; + + m_reserve_slots_for_players.fromVector( + StringUtils::split(ServerConfig::m_reserve_slots_for_players, ' ')); } // setupContextUser //----------------------------------------------------------------------------- @@ -693,4 +696,63 @@ std::string LobbySettings::getPowerPassword(int level) const Log::error("LobbySettings", "Invoked getPowerPassword with level = %d", level); return ""; -} +} // getPowerPassword +//----------------------------------------------------------------------------- + +bool LobbySettings::isSlotBookedFor(const std::string& username) const +{ + return m_reserve_slots_for_players.has(username); +} // isSlotBookedFor +//----------------------------------------------------------------------------- + +std::string LobbySettings::isSlotBookedForAsString(const std::string& username) const +{ + if (isSlotBookedFor(username)) + return StringUtils::insertValues("There's a booked slot for %s", username.c_str()); + + return StringUtils::insertValues("No booked slot for %s", username.c_str()); +} // isSlotBookedForAsString +//----------------------------------------------------------------------------- + +std::string LobbySettings::getAllBookedSlotsAsString() const +{ + bool first = true; + std::string res = StringUtils::insertValues( + "Players with booked slots: %s (", m_reserve_slots_for_players.size()); + + for (const auto& s: m_reserve_slots_for_players) + { + if (!first) + res += ", "; + else + first = false; + + res += s; + } + + res += ")"; + return res; +} // getAllBookedSlotsAsString +//----------------------------------------------------------------------------- + +void LobbySettings::bookSlotForPlayer(const std::string& username) +{ + m_reserve_slots_for_players.add(username); + + auto peer = STKHost::get()->findPeerByName( + StringUtils::utf8ToWide(username), true); + if (peer) + peer->setBookedSlot(true); +} // bookSlotForPlayer +//----------------------------------------------------------------------------- + +void LobbySettings::unbookSlotForPlayer(const std::string& username) +{ + m_reserve_slots_for_players.remove(username); + + auto peer = STKHost::get()->findPeerByName( + StringUtils::utf8ToWide(username), true); + if (peer) + peer->setBookedSlot(false); +} // unbookSlotForPlayer +//----------------------------------------------------------------------------- diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index 4f9b227b039..b9ed36e52b4 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -22,6 +22,7 @@ #include "irrString.h" #include "utils/lobby_context.hpp" #include "utils/team_utils.hpp" +#include "set_with_flip.hpp" #include @@ -102,6 +103,7 @@ class LobbySettings: public LobbyContextComponent void setLobbyCooldown(int value) { m_lobby_cooldown = value; } bool isCooldown() const; + bool isSavingServerConfig() const { return m_save_server_config; } void onServerSetup(); @@ -170,6 +172,12 @@ class LobbySettings: public LobbyContextComponent std::string getRegisterTableName() const { return m_register_table_name; } int getLobbyCooldown() const { return m_lobby_cooldown; } + bool isSlotBookedFor(const std::string& username) const; + std::string isSlotBookedForAsString(const std::string& username) const; + std::string getAllBookedSlotsAsString() const; + void bookSlotForPlayer(const std::string& username); + void unbookSlotForPlayer(const std::string& username); + // This one might not get into the config (as it originated from official // code's GP, where it is useless unless you want to make a private // server), however, it might be useful regardless @@ -260,6 +268,8 @@ class LobbySettings: public LobbyContextComponent std::string m_register_table_name; int m_lobby_cooldown; + SetWithFlip m_reserve_slots_for_players; + bool m_save_server_config; // Special, temporarily public diff --git a/src/utils/set_with_flip.hpp b/src/utils/set_with_flip.hpp index b54795664e1..764c5e8d0eb 100644 --- a/src/utils/set_with_flip.hpp +++ b/src/utils/set_with_flip.hpp @@ -58,7 +58,7 @@ class SetWithFlip: public std::set return add(element); } - bool has(const T& element) + bool has(const T& element) const { return this->find(element) != this->end(); } @@ -100,6 +100,14 @@ class SetWithFlip: public std::set } return result; } + + void fromVector(std::vector&& rhs) + { + const auto& vec = std::move(rhs); + this->clear(); + for (const auto& element: vec) + add(element); + } }; #endif \ No newline at end of file From 963a1d701c43aac18abfa311674a299afc53f158 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 20 Aug 2025 01:06:03 +0400 Subject: [PATCH 816/830] Tournament: fix default settings, add exception, don't show 0 when voting --- src/network/protocols/server_lobby.hpp | 1 - src/utils/tournament.cpp | 108 +++++++++++++------------ src/utils/tournament.hpp | 2 +- 3 files changed, 58 insertions(+), 53 deletions(-) diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index 44728e6d4de..c839b7f58bd 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -286,7 +286,6 @@ class ServerLobby : public LobbyProtocol, public LobbyContextUser void getMessagesFromHost(std::shared_ptr peer, int online_id); void writePlayerReport(Event* event); bool supportsAI(); - void initTournamentPlayers(); public: void changeLimitForTournament(bool goal_target); private: diff --git a/src/utils/tournament.cpp b/src/utils/tournament.cpp index d11b13feca1..8a1f9e39070 100644 --- a/src/utils/tournament.cpp +++ b/src/utils/tournament.cpp @@ -1,6 +1,6 @@ // // SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2024 kimden +// Copyright (C) 2025 kimden // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -33,11 +33,33 @@ namespace { static int g_history_limit = 100; + + static const std::string g_default_rules_config = + "nochat 10 TTTTG RRBBR +++++;;;not %1;not %1 %2;;;"; } void Tournament::setupContextUser() { - initTournamentPlayers(); + try + { + initTournamentPlayers( + (std::string)ServerConfig::m_soccer_tournament_match, + (std::string)ServerConfig::m_soccer_tournament_rules); + } + catch (std::exception& ex) + { + Log::error("Tournament", "Error while loading match config \"%s\": %s. " + "Falling back to default settings", + ServerConfig::m_soccer_tournament_rules.c_str(), + ex.what()); + + // There are no exceptions for _match yet. Add another handler when they appear + ServerConfig::m_soccer_tournament_rules = g_default_rules_config; + initTournamentPlayers( + (std::string)ServerConfig::m_soccer_tournament_match, + (std::string)ServerConfig::m_soccer_tournament_rules); + } + m_game = 0; m_extra_seconds = 0.0f; } // setupContextUser @@ -116,6 +138,7 @@ void Tournament::applyRestrictionsOnDefaultVote(PeerVote* default_vote) const void Tournament::applyRestrictionsOnVote(PeerVote* vote) const { + vote->m_num_laps = m_length; vote->m_reverse = false; } // applyRestrictionsOnVote //----------------------------------------------------------------------------- @@ -208,11 +231,11 @@ bool Tournament::hasColorsSwapped(int game) const } // hasColorsSwapped //----------------------------------------------------------------------------- -void Tournament::initTournamentPlayers() +// To be honest, way more validity checks are needed here. +void Tournament::initTournamentPlayers(const std::string& match, const std::string& rules) { // Init playing teams - std::vector tokens = StringUtils::split( - ServerConfig::m_soccer_tournament_match, ' '); + std::vector tokens = StringUtils::split(match, ' '); std::string type = ""; for (std::string& s: tokens) { @@ -239,58 +262,25 @@ void Tournament::initTournamentPlayers() else if (type == "J") m_referees.insert(s); } - for (const std::string& s: m_red_players) - { - Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to r", - s.c_str()); - } - for (const std::string& s: m_blue_players) - { - Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to b", - s.c_str()); - } - for (const std::string& s: m_referees) - { - Log::info("ServerLobby", "SoccerMatchLog: Role of %s is initially set to j", - s.c_str()); - } m_init_red = m_red_players; m_init_blue = m_blue_players; m_init_ref = m_referees; // Init tournament format - tokens = StringUtils::split( - ServerConfig::m_soccer_tournament_rules, ';'); - bool fallback = tokens.size() < 2; + tokens = StringUtils::split(rules, ';'); + if (tokens.size() < 2) + throw std::logic_error(StringUtils::insertValues( + "There should be at least 2 tokens, found %s", + tokens.size())); + std::vector general; - if (!fallback) - { - general = StringUtils::split(tokens[0], ' '); - if (general.size() < 5) - fallback = true; - } - if (fallback) - { - Log::warn("ServerLobby", "Tournament rules are not complete, fallback to default"); - general.clear(); - general.push_back("nochat"); - general.push_back("10"); - general.push_back("GGGGT"); - general.push_back("RRBBR"); - general.push_back("+++++"); - tokens.clear(); - tokens.push_back("nochat 10 GGGT RRBBR"); - tokens.push_back(""); - tokens.push_back(""); - tokens.push_back("not %0"); - tokens.push_back("not %0" " %1"); - tokens.push_back(""); - ServerConfig::m_soccer_tournament_rules = "nochat 10 TTTTG RRBBR +++++;" - ";;not %1;" - "not %1 " - "%2;;;"; - } - Log::info("ServerLobby", "SoccerMatchLog: Tournament rules are set to \"%s\"", + general = StringUtils::split(tokens[0], ' '); + if (general.size() < 5) + throw std::logic_error(StringUtils::insertValues( + "There should be at least 5 tokens in general section, found %s", + general.size())); + + Log::info("Tournament", "SoccerMatchLog: Tournament rules are set to \"%s\"", ServerConfig::m_soccer_tournament_rules.c_str()); m_limited_chat = false; m_length = 10; @@ -312,6 +302,22 @@ void Tournament::initTournamentPlayers() m_votability = general[4]; for (int i = 0; i < m_max_games; i++) m_track_filters.emplace_back(tokens[i + 1]); + + for (const std::string& s: m_red_players) + { + Log::info("Tournament", "SoccerMatchLog: Role of %s is initially set to r", + s.c_str()); + } + for (const std::string& s: m_blue_players) + { + Log::info("Tournament", "SoccerMatchLog: Role of %s is initially set to b", + s.c_str()); + } + for (const std::string& s: m_referees) + { + Log::info("Tournament", "SoccerMatchLog: Role of %s is initially set to j", + s.c_str()); + } } // initTournamentPlayers //----------------------------------------------------------------------------- diff --git a/src/utils/tournament.hpp b/src/utils/tournament.hpp index 233998275bf..036dfaf5a9e 100644 --- a/src/utils/tournament.hpp +++ b/src/utils/tournament.hpp @@ -47,7 +47,7 @@ class Tournament: public LobbyContextComponent Tournament(LobbyContext* context): LobbyContextComponent(context) {} void setupContextUser() OVERRIDE; - void initTournamentPlayers(); + void initTournamentPlayers(const std::string& match, const std::string& rules); void applyFiltersForThisGame(FilterContext& track_context); std::set getThoseWhoSeeTeamchats() const; bool checkSenderInRefsOrPlayers(std::shared_ptr sender) const; From 48c09ac03b520bf7c3580897be48bf1ed19a02f1 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 22 Aug 2025 03:12:26 +0400 Subject: [PATCH 817/830] Some external commands refactor [skip ci] --- src/network/protocols/command_manager.cpp | 225 +++--------------- src/network/protocols/command_manager.hpp | 176 ++------------ src/network/protocols/server_lobby.cpp | 4 +- .../command_manager/abstract_resource.hpp | 40 ++++ src/utils/command_manager/auth_resource.cpp | 51 ++++ src/utils/command_manager/auth_resource.hpp | 38 +++ src/utils/command_manager/command.cpp | 49 ++++ src/utils/command_manager/command.hpp | 111 +++++++++ src/utils/command_manager/context.cpp | 89 +++++++ src/utils/command_manager/context.hpp | 74 ++++++ src/utils/command_manager/file_resource.cpp | 78 ++++++ src/utils/command_manager/file_resource.hpp | 47 ++++ src/utils/command_manager/text_resource.cpp | 33 +++ src/utils/command_manager/text_resource.hpp | 47 ++++ 14 files changed, 711 insertions(+), 351 deletions(-) create mode 100644 src/utils/command_manager/abstract_resource.hpp create mode 100644 src/utils/command_manager/auth_resource.cpp create mode 100644 src/utils/command_manager/auth_resource.hpp create mode 100644 src/utils/command_manager/command.cpp create mode 100644 src/utils/command_manager/command.hpp create mode 100644 src/utils/command_manager/context.cpp create mode 100644 src/utils/command_manager/context.hpp create mode 100644 src/utils/command_manager/file_resource.cpp create mode 100644 src/utils/command_manager/file_resource.hpp create mode 100644 src/utils/command_manager/text_resource.cpp create mode 100644 src/utils/command_manager/text_resource.hpp diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 66ff144be67..880dbdc183e 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -21,7 +21,6 @@ #include "addons/addon.hpp" #include "io/file_manager.hpp" #include "modes/soccer_world.hpp" -#include "network/crypto.hpp" #include "network/database_connector.hpp" #include "network/event.hpp" #include "network/game_setup.hpp" @@ -62,6 +61,8 @@ // TODO: kimden: should decorators use acting_peer? +using Fn = std::function; + namespace { static const std::string g_addon_prefix = "addon_"; @@ -198,93 +199,6 @@ EnumExtendedReader CommandManager::permission_reader({ }); // ======================================================================== - -CommandManager::FileResource::FileResource(std::string file_name, uint64_t interval) -{ - m_file_name = std::move(file_name); - m_interval = interval; - m_contents = ""; - m_last_invoked = 0; - read(); -} // FileResource::FileResource -// ======================================================================== - -void CommandManager::FileResource::read() -{ - if (m_file_name.empty()) // in case it is not properly initialized - return; - // idk what to do with absolute or relative paths - const std::string& path = /*ServerConfig::getConfigDirectory() + "/" + */m_file_name; - std::ifstream message(FileUtils::getPortableReadingPath(path)); - std::string answer; - if (message.is_open()) - { - for (std::string line; std::getline(message, line); ) - { - answer += line; - answer.push_back('\n'); - } - if (!answer.empty()) - answer.pop_back(); - } - m_contents = answer; - m_last_invoked = StkTime::getMonoTimeMs(); -} // FileResource::read -// ======================================================================== - -std::string CommandManager::FileResource::get() -{ - uint64_t current_time = StkTime::getMonoTimeMs(); - if (m_interval == 0 || current_time < m_interval + m_last_invoked) - return m_contents; - read(); - return m_contents; -} // FileResource::get -// ======================================================================== - -CommandManager::AuthResource::AuthResource(std::string secret, std::string server, - std::string link_format): - m_secret(secret), m_server(server), m_link_format(link_format) -{ - -} // AuthResource::AuthResource -// ======================================================================== - -std::string CommandManager::AuthResource::get(const std::string& username, int online_id) const -{ -#ifdef ENABLE_CRYPTO_OPENSSL - std::string header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"; - uint64_t timestamp = StkTime::getTimeSinceEpoch(); - std::string payload = "{\"sub\":\"" + username + "/" + std::to_string(online_id) + "\","; - payload += "\"iat\":\"" + std::to_string(timestamp) + "\","; - payload += "\"iss\":\"" + m_server + "\"}"; - header = Crypto::base64url(StringUtils::toUInt8Vector(header)); - payload = Crypto::base64url(StringUtils::toUInt8Vector(payload)); - std::string message = header + "." + payload; - std::string signature = Crypto::base64url(Crypto::hmac_sha256_array(m_secret, message)); - std::string token = message + "." + signature; - std::string response = StringUtils::insertValues(m_link_format, token.c_str()); - return response; -#else - return "This command is currently only supported for OpenSSL"; -#endif -} // AuthResource::get -// ======================================================================== - -CommandManager::Command::Command(std::string name, - void (CommandManager::*f)(Context& context), - int permissions, - int mode_scope, - int state_scope): - m_name(name), m_action(f), m_permissions(permissions), - m_mode_scope(mode_scope), m_state_scope(state_scope), - m_omit_name(false) -{ - // Handling players who are allowed to run for anyone in any case - m_permissions |= UU_OTHERS_COMMANDS; -} // Command::Command(5) -// ======================================================================== - const SetTypoFixer& CommandManager::getFixer(TypoFixerType type) { switch (type) @@ -343,9 +257,9 @@ void CommandManager::initCommandsInfo() continue; // here the commands go std::string name = ""; - std::string text = ""; // for text-command - std::string file = ""; // for file-command - uint64_t interval = 0; // for file-command + // std::string text = ""; // for text-command + // std::string file = ""; // for file-command + // uint64_t interval = 0; // for file-command std::string usage = ""; std::string permissions_s = "UP_EVERYONE"; std::string mode_scope_s = "MS_DEFAULT"; @@ -357,9 +271,9 @@ void CommandManager::initCommandsInfo() std::string permissions_str = ""; std::string description = ""; std::string aliases = ""; - std::string secret = ""; // for auth-command - std::string link_format = ""; // for auth-command - std::string server = ""; // for auth-command + // std::string secret = ""; // for auth-command + // std::string link_format = ""; // for auth-command + // std::string server = ""; // for auth-command // Name is read before enabled/disabled property, because we want // to disable commands in "default" config that are present in @@ -422,23 +336,30 @@ void CommandManager::initCommandsInfo() else if (node_name == "text-command") { c = addChildCommand(command, name, &CommandManager::process_text, permissions, mode_scope, state_scope); - node->get("text", &text); - addTextResponse(c->getFullName(), text); + TextResource resource; + resource.fromXmlNode(node); + addTextResponse(c->getFullName(), resource); } else if (node_name == "file-command") { c = addChildCommand(command, name, &CommandManager::process_file, permissions, mode_scope, state_scope); - node->get("file", &file); - node->get("interval", &interval); - addFileResource(c->getFullName(), file, interval); + FileResource resource; + resource.fromXmlNode(node); + addFileResource(c->getFullName(), resource); } + // else if (node_name == "map-file-command") + // { + // c = addChildCommand(command, name, &CommandManager::process_file, permissions, mode_scope, state_scope); + // MapFileResource resource; + // resource.fromXmlNode(node); + // addMapFileResource(c->getFullName(), resource); + // } else if (node_name == "auth-command") { c = addChildCommand(command, name, &CommandManager::process_auth, permissions, mode_scope, state_scope); - node->get("secret", &secret); - node->get("server", &server); - node->get("link-format", &link_format); - addAuthResource(name, secret, server, link_format); + AuthResource resource; + resource.fromXmlNode(node); + addAuthResource(name, resource); } c->m_description = CommandDescription(usage, permissions_str, description); m_all_commands.emplace_back(c); @@ -463,13 +384,12 @@ void CommandManager::initCommandsInfo() void CommandManager::initCommands() { - using CM = CommandManager; auto& mp = m_full_name_to_command; m_root_command = std::make_shared("", &CM::special); initCommandsInfo(); - auto applyFunctionIfPossible = [&](std::string&& name, void (CM::*f)(Context& context)) { + auto applyFunctionIfPossible = [&](std::string&& name, Fn f) { auto it = mp.find(name); if (it == mp.end()) return; @@ -478,7 +398,7 @@ void CommandManager::initCommands() if (!command) return; - command->changeFunction(f); + command->changeFunction(std::move(f)); }; // special permissions according to ServerConfig options std::shared_ptr kick_command = mp["kick"].lock(); @@ -625,15 +545,15 @@ void CommandManager::initCommands() applyFunctionIfPossible("liststkaddon", &CM::special); applyFunctionIfPossible("listlocaladdon", &CM::special); - addTextResponse("description", getSettings()->getMotd()); - addTextResponse("moreinfo", getSettings()->getHelpMessage()); + addTextResponse("description", { getSettings()->getMotd() }); + addTextResponse("moreinfo", { getSettings()->getHelpMessage() }); std::string version = Version::version(); std::string branch = Version::branch(); if (!branch.empty()) version += ", branch " + branch; - addTextResponse("version", version); + addTextResponse("version", { version }); addTextResponse("clear", std::string(30, '\n')); // m_votables.emplace("replay", 1.0); @@ -1024,7 +944,7 @@ void CommandManager::execute(std::shared_ptr command, Context& context) context.m_command = command; try { - (this->*(command->m_action))(context); + (*(command->m_action))(context); } catch (std::exception& ex) { @@ -1078,7 +998,7 @@ void CommandManager::process_text(Context& context) "Error: a text command %s is defined without text", command->getFullName().c_str()); else - response = it->second; + response = it->second.get(); context.say(response); } // process_text // ======================================================================== @@ -1096,7 +1016,7 @@ void CommandManager::process_file(Context& context) else response = it->second.get(); context.say(response); -} // process_text +} // process_file // ======================================================================== void CommandManager::process_auth(Context& context) @@ -4104,7 +4024,7 @@ void CommandManager::onStartSelection() update(); } // onStartSelection // ======================================================================== -std::shared_ptr CommandManager::addChildCommand(std::shared_ptr target, +std::shared_ptr CommandManager::addChildCommand(std::shared_ptr target, std::string name, void (CommandManager::*f)(Context& context), int permissions, int mode_scope, int state_scope) { @@ -4121,85 +4041,6 @@ std::shared_ptr CommandManager::addChildCommand(std::sh } // addChildCommand // ======================================================================== -std::shared_ptr CommandManager::Context::peer() -{ - if (m_peer.expired()) - throw std::logic_error("Peer is expired"); - - auto peer = m_peer.lock(); - if (!peer) - throw std::logic_error("Peer is invalid"); - - return peer; -} // peer -//----------------------------------------------------------------------------- - -std::shared_ptr CommandManager::Context::peerMaybeNull() -{ - // if (m_peer.expired()) - // throw std::logic_error("Peer is expired"); - - auto peer = m_peer.lock(); - return peer; -} // peerMaybeNull -//----------------------------------------------------------------------------- - -std::shared_ptr CommandManager::Context::actingPeer() -{ - if (m_target_peer.expired()) - throw std::logic_error("Target peer is expired"); - - auto acting_peer = m_target_peer.lock(); - if (!acting_peer) - throw std::logic_error("Target peer is invalid"); - - return acting_peer; -} // actingPeer -//----------------------------------------------------------------------------- - -std::shared_ptr CommandManager::Context::actingPeerMaybeNull() -{ - // if (m_target_peer.expired()) - // throw std::logic_error("Target peer is expired"); - - auto acting_peer = m_target_peer.lock(); - return acting_peer; -} // actingPeerMaybeNull -//----------------------------------------------------------------------------- - -std::shared_ptr CommandManager::Context::command() -{ - if (m_command.expired()) - throw std::logic_error("Command is expired"); - - auto command = m_command.lock(); - if (!command) - throw std::logic_error("Command is invalid"); - - return command; -} // command -//----------------------------------------------------------------------------- - -void CommandManager::Context::say(const std::string& s) -{ - if (m_peer.expired()) - throw std::logic_error("Context::say: Peer has expired"); - - auto peer = m_peer.lock(); - Comm::sendStringToPeer(peer, s); -} // say -//----------------------------------------------------------------------------- - -void CommandManager::Command::changePermissions(int permissions, - int mode_scope, int state_scope) -{ - // Handling players who are allowed to run for anyone in any case - m_permissions = permissions | UU_OTHERS_COMMANDS; - m_mode_scope = mode_scope; - m_state_scope = state_scope; -} // changePermissions -// ======================================================================== - std::string CommandManager::getAddonPreferredType() const { int mode = getLobby()->getGameMode(); diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 7504d403278..89c3b7800c7 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -40,6 +40,11 @@ #include "network/protocols/command_voting.hpp" #include "network/protocols/command_permissions.hpp" +#include "utils/command_manager/auth_resource.hpp" +#include "utils/command_manager/command.hpp" +#include "utils/command_manager/context.hpp" +#include "utils/command_manager/file_resource.hpp" +#include "utils/command_manager/text_resource.hpp" #include "utils/enum_extended_reader.hpp" #include "utils/lobby_context.hpp" #include "utils/set_typo_fixer.hpp" @@ -55,47 +60,7 @@ class STKPeer; class CommandManager: public LobbyContextComponent { -public: - enum ModeScope: int - { - MS_DEFAULT = 1, - MS_SOCCER_TOURNAMENT = 2 - // add more powers of two if needed - }; - - enum StateScope: int - { - SS_LOBBY = 1, - SS_INGAME = 2, - SS_ALWAYS = SS_LOBBY | SS_INGAME - }; - private: - struct FileResource - { - std::string m_file_name; - uint64_t m_interval; - uint64_t m_last_invoked; - std::string m_contents; - - FileResource(std::string file_name = "", uint64_t interval = 0); - - void read(); - - std::string get(); - }; - - struct AuthResource - { - std::string m_secret; - std::string m_server; - std::string m_link_format; - - AuthResource(std::string secret = "", std::string server = "", - std::string link_format = ""); - - std::string get(const std::string& username, int online_id) const; - }; static EnumExtendedReader permission_reader; static EnumExtendedReader mode_scope_reader; @@ -106,115 +71,6 @@ class CommandManager: public LobbyContextComponent template void add_to_queue(int x, int mask, bool to_front, std::string& s) const; - struct Command; - - struct Context - { - ServerLobby* m_lobby; - - Event* m_event; - - std::weak_ptr m_peer; - - std::weak_ptr m_target_peer; - - std::vector m_argv; - - std::string m_cmd; - - std::weak_ptr m_command; - - int m_user_permissions; - - int m_acting_user_permissions; - - bool m_voting; - - Context(ServerLobby* lobby, Event* event, std::shared_ptr peer): - m_lobby(lobby), - m_event(event), m_peer(peer), m_target_peer(peer), m_argv(), - m_cmd(""), m_user_permissions(0), m_acting_user_permissions(0), m_voting(false) {} - - Context(ServerLobby* lobby, Event* event, std::shared_ptr peer, - std::vector& argv, std::string& cmd, - int user_permissions, int acting_user_permissions, bool voting): - m_lobby(lobby), - m_event(event), m_peer(peer), m_target_peer(peer), m_argv(argv), - m_cmd(cmd), m_user_permissions(user_permissions), - m_acting_user_permissions(acting_user_permissions), m_voting(voting) {} - - std::shared_ptr peer(); - std::shared_ptr peerMaybeNull(); - std::shared_ptr actingPeer(); - std::shared_ptr actingPeerMaybeNull(); - std::shared_ptr command(); - - void say(const std::string& s); - }; - - struct CommandDescription - { - std::string m_usage; - std::string m_permissions; - std::string m_description; - CommandDescription(std::string usage = "", std::string permissions = "", - std::string description = ""): m_usage(usage), - m_permissions(permissions), m_description(description) {} - - std::string getUsage() const { return "Usage: " + m_usage; } - - std::string getHelp() const - { - return "Usage: " + m_usage - + "\nAvailable to: " + m_permissions - + "\n" + m_description; - } - }; - - struct Command - { - std::string m_name; - - std::string m_prefix_name; - - void (CommandManager::*m_action)(Context& context); - - int m_permissions; - - int m_mode_scope; - - int m_state_scope; - - bool m_omit_name; - - CommandDescription m_description; - - std::weak_ptr m_parent; - - std::map> m_name_to_subcommand; - - std::vector> m_subcommands; - - SetTypoFixer m_stf_subcommand_names; - - Command() {} - - Command(std::string name, - void (CommandManager::*f)(Context& context), - int permissions = UP_EVERYONE, - int mode_scope = MS_DEFAULT, int state_scope = SS_ALWAYS); - - void changeFunction(void (CommandManager::*f)(Context& context)) - { m_action = f; } - void changePermissions(int permissions = UP_EVERYONE, - int mode_scope = MS_DEFAULT, - int state_scope = SS_ALWAYS); - - std::string getUsage() const { return m_description.getUsage(); } - std::string getHelp() const { return m_description.getHelp(); } - std::string getFullName() const { return m_prefix_name; } - }; - private: std::vector> m_all_commands; @@ -225,7 +81,7 @@ class CommandManager: public LobbyContextComponent std::multiset m_users; - std::map m_text_response; + std::map m_text_response; std::map m_file_resources; @@ -384,15 +240,21 @@ class CommandManager: public LobbyContextComponent void handleCommand(Event* event, std::shared_ptr peer); - template - void addTextResponse(std::string key, T&& value) - { m_text_response[key] = value; } + // template + // void addTextResponse(std::string key, T&& value) + // { m_text_response[key] = value; } + + void addTextResponse(std::string key, const TextResource& resource) + { m_text_response[key] = resource; } + + void addTextResponse(std::string key, TextResource&& resource) + { m_text_response[key] = std::move(resource); } - void addFileResource(std::string key, std::string file, uint64_t interval) - { m_file_resources[key] = FileResource(file, interval); } + void addFileResource(std::string key, const FileResource& resource) + { m_file_resources[key] = resource; } - void addAuthResource(std::string key, std::string secret, std::string server, std::string link_format) - { m_auth_resources[key] = AuthResource(secret, server, link_format); } + void addAuthResource(std::string key, const AuthResource& resource) + { m_auth_resources[key] = resource; } void addUser(std::string& s); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 3f6bf333e24..ff36ea5cd44 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -4501,8 +4501,8 @@ int ServerLobby::getCurrentStateScope() || state > RESULT_DISPLAY) return 0; if (state == WAITING_FOR_START_GAME) - return CommandManager::StateScope::SS_LOBBY; - return CommandManager::StateScope::SS_INGAME; + return StateScope::SS_LOBBY; + return StateScope::SS_INGAME; } // getCurrentStateScope //----------------------------------------------------------------------------- diff --git a/src/utils/command_manager/abstract_resource.hpp b/src/utils/command_manager/abstract_resource.hpp new file mode 100644 index 00000000000..e5a80725038 --- /dev/null +++ b/src/utils/command_manager/abstract_resource.hpp @@ -0,0 +1,40 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef ABSTRACT_RESOURCE_HPP +#define ABSTRACT_RESOURCE_HPP + +#include +#include "io/xml_node.hpp" + +/** + * AbstractResource represents a generic externally produced resource + * (that is, typically not produced inside the game, or produced inside the game, + * but further processed elsewhere). + */ +class AbstractResource +{ +public: + + virtual void fromXmlNode(const XMLNode* node) = 0; + + // virtual std::string process(Context& context) = 0; +}; + + +#endif // ABSTRACT_RESOURCE_HPP \ No newline at end of file diff --git a/src/utils/command_manager/auth_resource.cpp b/src/utils/command_manager/auth_resource.cpp new file mode 100644 index 00000000000..f706a75b950 --- /dev/null +++ b/src/utils/command_manager/auth_resource.cpp @@ -0,0 +1,51 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/command_manager/auth_resource.hpp" +#include "network/crypto.hpp" +#include "utils/string_utils.hpp" +#include "utils/time.hpp" + +void AuthResource::fromXmlNode(const XMLNode* node) +{ + node->get("secret", &m_secret); + node->get("server", &m_server); + node->get("link-format", &m_link_format); +} // AuthResource::AuthResource +//----------------------------------------------------------------------------- + +std::string AuthResource::get(const std::string& username, int online_id) +{ +#ifdef ENABLE_CRYPTO_OPENSSL + std::string header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"; + uint64_t timestamp = StkTime::getTimeSinceEpoch(); + std::string payload = "{\"sub\":\"" + username + "/" + std::to_string(online_id) + "\","; + payload += "\"iat\":\"" + std::to_string(timestamp) + "\","; + payload += "\"iss\":\"" + m_server + "\"}"; + header = Crypto::base64url(StringUtils::toUInt8Vector(header)); + payload = Crypto::base64url(StringUtils::toUInt8Vector(payload)); + std::string message = header + "." + payload; + std::string signature = Crypto::base64url(Crypto::hmac_sha256_array(m_secret, message)); + std::string token = message + "." + signature; + std::string response = StringUtils::insertValues(m_link_format, token.c_str()); + return response; +#else + return "This command is currently only supported for OpenSSL"; +#endif +} // AuthResource::get +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/command_manager/auth_resource.hpp b/src/utils/command_manager/auth_resource.hpp new file mode 100644 index 00000000000..3f8d40f0ada --- /dev/null +++ b/src/utils/command_manager/auth_resource.hpp @@ -0,0 +1,38 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef AUTH_RESOURCE_HPP +#define AUTH_RESOURCE_HPP + +#include +#include "utils/command_manager/abstract_resource.hpp" + +class AuthResource: public AbstractResource +{ +private: + std::string m_secret; + std::string m_server; + std::string m_link_format; + +public: + void fromXmlNode(const XMLNode* node) final; + + std::string get(const std::string& username, int online_id); +}; + +#endif // AUTH_RESOURCE_HPP \ No newline at end of file diff --git a/src/utils/command_manager/command.cpp b/src/utils/command_manager/command.cpp new file mode 100644 index 00000000000..141a89aa829 --- /dev/null +++ b/src/utils/command_manager/command.cpp @@ -0,0 +1,49 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/command_manager/command.hpp" + + + + +Command::Command(std::string name, + std::function f, + int permissions, + int mode_scope, + int state_scope) + : m_name(std::move(name)) + , m_action(std::move(f)) + , m_permissions(permissions) + , m_mode_scope(mode_scope) + , m_state_scope(state_scope) + , m_omit_name(false) +{ + // Handling players who are allowed to run for anyone in any case + m_permissions |= UU_OTHERS_COMMANDS; +} // Command::Command(5) +// ======================================================================== + +void Command::changePermissions(int permissions, + int mode_scope, int state_scope) +{ + // Handling players who are allowed to run for anyone in any case + m_permissions = permissions | UU_OTHERS_COMMANDS; + m_mode_scope = mode_scope; + m_state_scope = state_scope; +} // changePermissions +// ======================================================================== \ No newline at end of file diff --git a/src/utils/command_manager/command.hpp b/src/utils/command_manager/command.hpp new file mode 100644 index 00000000000..c9e4fa6fffa --- /dev/null +++ b/src/utils/command_manager/command.hpp @@ -0,0 +1,111 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef COMMAND_HPP +#define COMMAND_HPP + +#include +#include +#include +#include +#include + +#include "utils/set_typo_fixer.hpp" +#include "network/protocols/command_permissions.hpp" + +struct Context; + +enum ModeScope: int +{ + MS_DEFAULT = 1, + MS_SOCCER_TOURNAMENT = 2 + // add more powers of two if needed +}; + +enum StateScope: int +{ + SS_LOBBY = 1, + SS_INGAME = 2, + SS_ALWAYS = SS_LOBBY | SS_INGAME +}; + +struct CommandDescription +{ + std::string m_usage; + std::string m_permissions; + std::string m_description; + CommandDescription(std::string usage = "", std::string permissions = "", + std::string description = ""): m_usage(usage), + m_permissions(permissions), m_description(description) {} + + std::string getUsage() const { return "Usage: " + m_usage; } + + std::string getHelp() const + { + return "Usage: " + m_usage + + "\nAvailable to: " + m_permissions + + "\n" + m_description; + } +}; + +struct Command +{ + std::string m_name; + + std::string m_prefix_name; + + std::function m_action; + + int m_permissions; + + int m_mode_scope; + + int m_state_scope; + + bool m_omit_name; + + CommandDescription m_description; + + std::weak_ptr m_parent; + + std::map> m_name_to_subcommand; + + std::vector> m_subcommands; + + SetTypoFixer m_stf_subcommand_names; + + Command() {} + + Command(std::string name, + std::function f, + int permissions = UP_EVERYONE, + int mode_scope = MS_DEFAULT, int state_scope = SS_ALWAYS); + + void changeFunction(std::function f) + { m_action = std::move(f); } + + void changePermissions(int permissions = UP_EVERYONE, + int mode_scope = MS_DEFAULT, + int state_scope = SS_ALWAYS); + + std::string getUsage() const { return m_description.getUsage(); } + std::string getHelp() const { return m_description.getHelp(); } + std::string getFullName() const { return m_prefix_name; } +}; + +#endif // COMMAND_HPP \ No newline at end of file diff --git a/src/utils/command_manager/context.cpp b/src/utils/command_manager/context.cpp new file mode 100644 index 00000000000..91a6b791ac3 --- /dev/null +++ b/src/utils/command_manager/context.cpp @@ -0,0 +1,89 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/command_manager/context.hpp" +#include "utils/communication.hpp" + +std::shared_ptr Context::peer() +{ + if (m_peer.expired()) + throw std::logic_error("Peer is expired"); + + auto peer = m_peer.lock(); + if (!peer) + throw std::logic_error("Peer is invalid"); + + return peer; +} // peer +//----------------------------------------------------------------------------- + +std::shared_ptr Context::peerMaybeNull() +{ + // if (m_peer.expired()) + // throw std::logic_error("Peer is expired"); + + auto peer = m_peer.lock(); + return peer; +} // peerMaybeNull +//----------------------------------------------------------------------------- + +std::shared_ptr Context::actingPeer() +{ + if (m_target_peer.expired()) + throw std::logic_error("Target peer is expired"); + + auto acting_peer = m_target_peer.lock(); + if (!acting_peer) + throw std::logic_error("Target peer is invalid"); + + return acting_peer; +} // actingPeer +//----------------------------------------------------------------------------- + +std::shared_ptr Context::actingPeerMaybeNull() +{ + // if (m_target_peer.expired()) + // throw std::logic_error("Target peer is expired"); + + auto acting_peer = m_target_peer.lock(); + return acting_peer; +} // actingPeerMaybeNull +//----------------------------------------------------------------------------- + +std::shared_ptr Context::command() +{ + if (m_command.expired()) + throw std::logic_error("Command is expired"); + + auto command = m_command.lock(); + if (!command) + throw std::logic_error("Command is invalid"); + + return command; +} // command +//----------------------------------------------------------------------------- + +void Context::say(const std::string& s) +{ + if (m_peer.expired()) + throw std::logic_error("Context::say: Peer has expired"); + + auto peer = m_peer.lock(); + Comm::sendStringToPeer(peer, s); +} // say +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/command_manager/context.hpp b/src/utils/command_manager/context.hpp new file mode 100644 index 00000000000..d17a77625af --- /dev/null +++ b/src/utils/command_manager/context.hpp @@ -0,0 +1,74 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef CONTEXT_HPP +#define CONTEXT_HPP + +#include +#include +#include +#include "network/event.hpp" + +struct Command; +class ServerLobby; + +struct Context +{ + ServerLobby* m_lobby; + + Event* m_event; + + std::weak_ptr m_peer; + + std::weak_ptr m_target_peer; + + std::vector m_argv; + + std::string m_cmd; + + std::weak_ptr m_command; + + int m_user_permissions; + + int m_acting_user_permissions; + + bool m_voting; + + Context(ServerLobby* lobby, Event* event, std::shared_ptr peer): + m_lobby(lobby), + m_event(event), m_peer(peer), m_target_peer(peer), m_argv(), + m_cmd(""), m_user_permissions(0), m_acting_user_permissions(0), m_voting(false) {} + + Context(ServerLobby* lobby, Event* event, std::shared_ptr peer, + std::vector& argv, std::string& cmd, + int user_permissions, int acting_user_permissions, bool voting): + m_lobby(lobby), + m_event(event), m_peer(peer), m_target_peer(peer), m_argv(argv), + m_cmd(cmd), m_user_permissions(user_permissions), + m_acting_user_permissions(acting_user_permissions), m_voting(voting) {} + + std::shared_ptr peer(); + std::shared_ptr peerMaybeNull(); + std::shared_ptr actingPeer(); + std::shared_ptr actingPeerMaybeNull(); + std::shared_ptr command(); + + void say(const std::string& s); +}; + +#endif // CONTEXT_HPP \ No newline at end of file diff --git a/src/utils/command_manager/file_resource.cpp b/src/utils/command_manager/file_resource.cpp new file mode 100644 index 00000000000..cd99720e6e0 --- /dev/null +++ b/src/utils/command_manager/file_resource.cpp @@ -0,0 +1,78 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/command_manager/file_resource.hpp" + +#include +#include "utils/string_utils.hpp" +#include "utils/file_utils.hpp" +#include "utils/time.hpp" + + +void FileResource::fromXmlNode(const XMLNode* node) +{ + node->get("file", &m_file_name); + node->get("interval", &m_interval); + + m_contents = ""; + m_last_invoked = 0; + read(); +} // FileResource +//----------------------------------------------------------------------------- + +void FileResource::read() +{ + if (m_file_name.empty()) // in case it is not properly initialized + return; + + // idk what to do with absolute or relative paths + const std::string& path = /*ServerConfig::getConfigDirectory() + "/" + */m_file_name; + std::ifstream message(FileUtils::getPortableReadingPath(path)); + std::string answer; + + if (message.is_open()) + { + for (std::string line; std::getline(message, line); ) + { + answer += line; + answer.push_back('\n'); + } + if (!answer.empty()) + answer.pop_back(); + } + + m_contents = answer; + m_last_invoked = StkTime::getMonoTimeMs(); +} // read +//----------------------------------------------------------------------------- + +void FileResource::tryUpdate() +{ + uint64_t current_time = StkTime::getMonoTimeMs(); + if (m_interval != 0 && current_time >= m_interval + m_last_invoked) + read(); +} // tryUpdate +//----------------------------------------------------------------------------- + +std::string FileResource::get() +{ + tryUpdate(); + + return m_contents; +} // get +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/command_manager/file_resource.hpp b/src/utils/command_manager/file_resource.hpp new file mode 100644 index 00000000000..76ee4664c9e --- /dev/null +++ b/src/utils/command_manager/file_resource.hpp @@ -0,0 +1,47 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifndef FILE_RESOURCE_HPP +#define FILE_RESOURCE_HPP + +#include "utils/types.hpp" +#include "utils/command_manager/abstract_resource.hpp" +#include + +struct FileResource: public AbstractResource +{ +private: + std::string m_file_name; + uint64_t m_interval; + mutable uint64_t m_last_invoked; + std::string m_contents; + + void tryUpdate(); + +protected: + virtual void read(); + +public: + void fromXmlNode(const XMLNode* node) final; + + std::string get(); +}; + + +#endif // FILE_RESOURCE_HPP \ No newline at end of file diff --git a/src/utils/command_manager/text_resource.cpp b/src/utils/command_manager/text_resource.cpp new file mode 100644 index 00000000000..96cadbdf2a5 --- /dev/null +++ b/src/utils/command_manager/text_resource.cpp @@ -0,0 +1,33 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/command_manager/text_resource.hpp" + + + +void TextResource::fromXmlNode(const XMLNode* node) +{ + node->get("text", &m_text); +} // FileResource +//----------------------------------------------------------------------------- + +std::string TextResource::get() +{ + return m_text; +} // get +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/command_manager/text_resource.hpp b/src/utils/command_manager/text_resource.hpp new file mode 100644 index 00000000000..3320124df4b --- /dev/null +++ b/src/utils/command_manager/text_resource.hpp @@ -0,0 +1,47 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifndef TEXT_RESOURCE_HPP +#define TEXT_RESOURCE_HPP + +#include "utils/types.hpp" +#include "utils/command_manager/abstract_resource.hpp" +#include + +class TextResource: public AbstractResource +{ +private: + std::string m_text; + +public: + TextResource() {} + + template + TextResource(const T& str): m_text(str) {} + + template + TextResource(T&& str): m_text(std::move(str)) {} + + void fromXmlNode(const XMLNode* node) final; + + std::string get(); +}; + + +#endif // TEXT_RESOURCE_HPP \ No newline at end of file From 25bf7fb06b18ce4b2f360294d4b0ebc3499f4d75 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 23 Aug 2025 13:27:59 +0400 Subject: [PATCH 818/830] Fix compilation, don't pass CommandMgr to Command --- src/network/protocols/command_manager.cpp | 29 +++++++++++------------ src/utils/command_manager/command.cpp | 3 --- src/utils/command_manager/command.hpp | 10 -------- 3 files changed, 14 insertions(+), 28 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 880dbdc183e..1d88c15053a 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -61,8 +61,6 @@ // TODO: kimden: should decorators use acting_peer? -using Fn = std::function; - namespace { static const std::string g_addon_prefix = "addon_"; @@ -255,11 +253,9 @@ void CommandManager::initCommandsInfo() std::string node_name = node->getName(); if (node_name == "external-commands-file") continue; + // here the commands go std::string name = ""; - // std::string text = ""; // for text-command - // std::string file = ""; // for file-command - // uint64_t interval = 0; // for file-command std::string usage = ""; std::string permissions_s = "UP_EVERYONE"; std::string mode_scope_s = "MS_DEFAULT"; @@ -271,9 +267,6 @@ void CommandManager::initCommandsInfo() std::string permissions_str = ""; std::string description = ""; std::string aliases = ""; - // std::string secret = ""; // for auth-command - // std::string link_format = ""; // for auth-command - // std::string server = ""; // for auth-command // Name is read before enabled/disabled property, because we want // to disable commands in "default" config that are present in @@ -384,12 +377,15 @@ void CommandManager::initCommandsInfo() void CommandManager::initCommands() { + using CM = CommandManager; auto& mp = m_full_name_to_command; - m_root_command = std::make_shared("", &CM::special); + m_root_command = std::make_shared("", std::bind(&CM::special, this, std::placeholders::_1)); initCommandsInfo(); - auto applyFunctionIfPossible = [&](std::string&& name, Fn f) { + auto ptr = this; + + auto applyFunctionIfPossible = [ptr, &mp](std::string&& name, std::function f) { auto it = mp.find(name); if (it == mp.end()) return; @@ -397,8 +393,8 @@ void CommandManager::initCommands() std::shared_ptr command = it->second.lock(); if (!command) return; - - command->changeFunction(std::move(f)); + + command->changeFunction(std::bind(std::move(f), ptr, std::placeholders::_1)); }; // special permissions according to ServerConfig options std::shared_ptr kick_command = mp["kick"].lock(); @@ -944,7 +940,7 @@ void CommandManager::execute(std::shared_ptr command, Context& context) context.m_command = command; try { - (*(command->m_action))(context); + (command->m_action)(context); } catch (std::exception& ex) { @@ -4028,14 +4024,17 @@ std::shared_ptr CommandManager::addChildCommand(std::shared_ptr child = std::make_shared(name, f, - permissions, mode_scope, state_scope); + std::shared_ptr child = std::make_shared(name, + std::bind(f, this, std::placeholders::_1), permissions, mode_scope, state_scope); + target->m_subcommands.push_back(child); child->m_parent = std::weak_ptr(target); + if (target->m_prefix_name.empty()) child->m_prefix_name = name; else child->m_prefix_name = target->m_prefix_name + " " + name; + target->m_name_to_subcommand[name] = std::weak_ptr(child); return child; } // addChildCommand diff --git a/src/utils/command_manager/command.cpp b/src/utils/command_manager/command.cpp index 141a89aa829..86b2542cac4 100644 --- a/src/utils/command_manager/command.cpp +++ b/src/utils/command_manager/command.cpp @@ -18,9 +18,6 @@ #include "utils/command_manager/command.hpp" - - - Command::Command(std::string name, std::function f, int permissions, diff --git a/src/utils/command_manager/command.hpp b/src/utils/command_manager/command.hpp index c9e4fa6fffa..5f58d2d0a93 100644 --- a/src/utils/command_manager/command.hpp +++ b/src/utils/command_manager/command.hpp @@ -66,27 +66,17 @@ struct CommandDescription struct Command { std::string m_name; - std::string m_prefix_name; - std::function m_action; - int m_permissions; - int m_mode_scope; - int m_state_scope; - bool m_omit_name; CommandDescription m_description; - std::weak_ptr m_parent; - std::map> m_name_to_subcommand; - std::vector> m_subcommands; - SetTypoFixer m_stf_subcommand_names; Command() {} From f22b17ce5efb38254d94a73247adcafde7145d83 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 24 Aug 2025 00:53:30 +0400 Subject: [PATCH 819/830] Separate command reading from xml from CM --- data/commands.xml | 8 +- src/network/protocols/command_manager.cpp | 361 ++++++-------------- src/network/protocols/command_manager.hpp | 37 +- src/utils/command_manager/auth_resource.cpp | 26 +- src/utils/command_manager/auth_resource.hpp | 10 +- src/utils/command_manager/command.cpp | 258 +++++++++++++- src/utils/command_manager/command.hpp | 73 ++-- src/utils/command_manager/file_resource.cpp | 7 +- src/utils/command_manager/file_resource.hpp | 10 +- src/utils/command_manager/text_resource.cpp | 9 +- src/utils/command_manager/text_resource.hpp | 12 +- 11 files changed, 445 insertions(+), 366 deletions(-) diff --git a/data/commands.xml b/data/commands.xml index f9e25b61683..6c64e3bee34 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -148,14 +148,14 @@ here later. For now, please refer to the code for the strings being used. --> permissions-verbose="everyone" description="Lists players whom you blocked using /mute command." /> - - state-scope="SS_LOBBY" /> - - getNumNodes(); i++) { const XMLNode *node = current->getNode(i); - std::string node_name = node->getName(); - if (node_name == "external-commands-file") + + auto c = Command::unknownTypeFromXmlNode(node); + if (!c) continue; - // here the commands go - std::string name = ""; - std::string usage = ""; - std::string permissions_s = "UP_EVERYONE"; - std::string mode_scope_s = "MS_DEFAULT"; - std::string state_scope_s = "SS_ALWAYS"; - bool omit_name = false; - int permissions; - int mode_scope; - int state_scope; - std::string permissions_str = ""; - std::string description = ""; - std::string aliases = ""; - - // Name is read before enabled/disabled property, because we want - // to disable commands in "default" config that are present in - // "custom" config, regardless of server name - node->get("name", &name); - if (current == root2 && command == m_root_command - && used_commands.find(name) != used_commands.end()) - { + const std::string name = c->getShortName(); + + if (current == root2 && command == m_root_command && used_commands.find(name) != used_commands.end()) continue; - } else if (current == root) - { used_commands.insert(name); - } - // If enabled is not empty, command is added iff the server name is in enabled - // Otherwise it is added iff the server name is not in disabled - std::string enabled = ""; - std::string disabled = ""; - node->get("enabled", &enabled); - node->get("disabled", &disabled); - std::vector enabled_split = StringUtils::split(enabled, ' '); - std::vector disabled_split = StringUtils::split(disabled, ' '); - bool ok; - if (!enabled.empty()) - { - ok = false; - for (const std::string& s: enabled_split) - if (s == ServerConfig::m_server_uid) - ok = true; - } - else - { - ok = true; - for (const std::string& s: disabled_split) - if (s == ServerConfig::m_server_uid) - ok = false; - } - if (!ok) - continue; - - node->get("usage", &usage); - node->get("permissions", &permissions_s); - permissions = CommandManager::permission_reader.parse(permissions_s); - node->get("mode-scope", &mode_scope_s); - mode_scope = CommandManager::mode_scope_reader.parse(mode_scope_s); - node->get("state-scope", &state_scope_s); - state_scope = CommandManager::state_scope_reader.parse(state_scope_s); - node->get("permissions-verbose", &permissions_str); - node->get("description", &description); - node->get("omit-name", &omit_name); - node->get("aliases", &aliases); - std::vector aliases_split = StringUtils::split(aliases, ' '); - - std::shared_ptr c; - if (node_name == "command") - { - c = addChildCommand(command, name, &CommandManager::special, permissions, mode_scope, state_scope); - } - else if (node_name == "text-command") - { - c = addChildCommand(command, name, &CommandManager::process_text, permissions, mode_scope, state_scope); - TextResource resource; - resource.fromXmlNode(node); - addTextResponse(c->getFullName(), resource); - } - else if (node_name == "file-command") - { - c = addChildCommand(command, name, &CommandManager::process_file, permissions, mode_scope, state_scope); - FileResource resource; - resource.fromXmlNode(node); - addFileResource(c->getFullName(), resource); - } - // else if (node_name == "map-file-command") - // { - // c = addChildCommand(command, name, &CommandManager::process_file, permissions, mode_scope, state_scope); - // MapFileResource resource; - // resource.fromXmlNode(node); - // addMapFileResource(c->getFullName(), resource); - // } - else if (node_name == "auth-command") - { - c = addChildCommand(command, name, &CommandManager::process_auth, permissions, mode_scope, state_scope); - AuthResource resource; - resource.fromXmlNode(node); - addAuthResource(name, resource); - } - c->m_description = CommandDescription(usage, permissions_str, description); + command->addChild(c); m_all_commands.emplace_back(c); m_full_name_to_command[c->getFullName()] = std::weak_ptr(c); - c->m_omit_name = omit_name; - command->m_stf_subcommand_names.add(name); - for (const std::string& alias_name: aliases_split) - { - command->m_stf_subcommand_names.add(alias_name, name); - command->m_name_to_subcommand[alias_name] = command->m_name_to_subcommand[name]; - } dfs(node, c); } }; @@ -379,7 +237,9 @@ void CommandManager::initCommands() { using CM = CommandManager; auto& mp = m_full_name_to_command; - m_root_command = std::make_shared("", std::bind(&CM::special, this, std::placeholders::_1)); + m_root_command = std::make_shared(); + m_root_command->setFunction(getDefaultAction()); + // std::bind(&CM::special, this, std::placeholders::_1)); initCommandsInfo(); @@ -394,15 +254,44 @@ void CommandManager::initCommands() if (!command) return; - command->changeFunction(std::bind(std::move(f), ptr, std::placeholders::_1)); + command->setFunction(std::bind(std::move(f), ptr, std::placeholders::_1)); }; + + auto applyTextIfPossible = [ptr, &mp](std::string&& name, const std::string& value) { + auto it = mp.find(name); + if (it == mp.end()) + return; + + std::shared_ptr command = it->second.lock(); + if (!command) + return; + + std::shared_ptr resource = std::dynamic_pointer_cast(command); + if (!resource) + return; + + resource->setText(value); + }; + // special permissions according to ServerConfig options std::shared_ptr kick_command = mp["kick"].lock(); if (kick_command) { if (getSettings()->hasKicksAllowed()) - kick_command->m_permissions |= UU_CROWNED; + { + kick_command->changePermissions( + kick_command->getPermissions() | UU_CROWNED, + kick_command->getModeScope(), + kick_command->getStateScope() + ); + } else - kick_command->m_permissions &= ~UU_CROWNED; + { + kick_command->changePermissions( + kick_command->getPermissions() & (~UU_CROWNED), + kick_command->getModeScope(), + kick_command->getStateScope() + ); + } } applyFunctionIfPossible("commands", &CM::process_commands); @@ -428,8 +317,6 @@ void CommandManager::initCommands() applyFunctionIfPossible("mute", &CM::process_mute); applyFunctionIfPossible("unmute", &CM::process_unmute); applyFunctionIfPossible("listmute", &CM::process_listmute); - applyFunctionIfPossible("description", &CM::process_text); - applyFunctionIfPossible("moreinfo", &CM::process_text); applyFunctionIfPossible("gnu", &CM::process_gnu); applyFunctionIfPossible("nognu", &CM::process_gnu); applyFunctionIfPossible("tell", &CM::process_tell); @@ -488,8 +375,6 @@ void CommandManager::initCommands() applyFunctionIfPossible("teamhit =", &CM::process_teamhit_assign); applyFunctionIfPossible("scoring", &CM::process_scoring); applyFunctionIfPossible("scoring =", &CM::process_scoring_assign); - applyFunctionIfPossible("version", &CM::process_text); - applyFunctionIfPossible("clear", &CM::process_text); applyFunctionIfPossible("register", &CM::process_register); applyFunctionIfPossible("muteall", &CM::process_muteall); applyFunctionIfPossible("game", &CM::process_game); @@ -541,16 +426,24 @@ void CommandManager::initCommands() applyFunctionIfPossible("liststkaddon", &CM::special); applyFunctionIfPossible("listlocaladdon", &CM::special); - addTextResponse("description", { getSettings()->getMotd() }); - addTextResponse("moreinfo", { getSettings()->getHelpMessage() }); - std::string version = Version::version(); std::string branch = Version::branch(); if (!branch.empty()) version += ", branch " + branch; - addTextResponse("version", { version }); - addTextResponse("clear", std::string(30, '\n')); + applyTextIfPossible("description", getSettings()->getMotd()); + applyTextIfPossible("moreinfo", getSettings()->getHelpMessage()); + applyTextIfPossible("version", version); + applyTextIfPossible("clear", std::string(30, '\n')); + + for (auto& element: m_full_name_to_command) + { + std::shared_ptr command = element.second.lock(); + if (!command || !command->needsFunction() || command->hasFunction()) + continue; + + command->setFunction(getDefaultAction()); + }; // m_votables.emplace("replay", 1.0); m_votables.emplace("start", 0.81); @@ -732,20 +625,20 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) std::shared_ptr executed_command; for (int idx = 0; ; idx++) { - bool one_omittable_subcommand = (current_command->m_subcommands.size() == 1 - && current_command->m_subcommands[0]->m_omit_name); + const auto& subcommands = current_command->getSubcommands(); + bool one_omittable_subcommand = (subcommands.size() == 1 && subcommands[0]->omittedName()); std::shared_ptr command; if (one_omittable_subcommand) { - command = current_command->m_subcommands[0]; + command = subcommands[0]; } else { - if (hasTypo(target_peer_strong, peer, voting, argv, cmd, idx, current_command->m_stf_subcommand_names, 3, false, false)) + if (hasTypo(target_peer_strong, peer, voting, argv, cmd, idx, current_command->subcommandNamesTypoFixer(), 3, false, false)) return; - auto command_iterator = current_command->m_name_to_subcommand.find(argv[idx]); - command = command_iterator->second.lock(); + + command = current_command->findChild(argv[idx]); } if (!command) @@ -762,7 +655,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) // Note that we use caller's permissions to determine if the command can be invoked, // and during its invocation, we use acting peer's permissions. - int mask = ((permissions & command->m_permissions) & (~MASK_MANIPULATION)); + int mask = ((permissions & command->getPermissions()) & (~MASK_MANIPULATION)); if (mask == 0) { context.say("You don't have permissions to " + action + " this command"); @@ -771,7 +664,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) // kimden: both might be nullptr, which means different things if (target_peer.lock() != peer) { - int mask_manip = (permissions & command->m_permissions & MASK_MANIPULATION); + int mask_manip = (permissions & command->getPermissions() & MASK_MANIPULATION); if (mask_manip == 0) { context.say("You don't have permissions to " + action @@ -786,7 +679,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) if (one_omittable_subcommand) --idx; current_command = command; - if (idx + 1 == (int)argv.size() || command->m_subcommands.empty()) { + if (idx + 1 == (int)argv.size() || command->getSubcommands().empty()) { executed_command = command; execute(command, context); break; @@ -850,8 +743,8 @@ int CommandManager::getCurrentModeScope() bool CommandManager::isAvailable(std::shared_ptr c) { - return (getCurrentModeScope() & c->m_mode_scope) != 0 - && (getLobby()->getCurrentStateScope() & c->m_state_scope) != 0; + return (getCurrentModeScope() & c->getModeScope()) != 0 + && (getLobby()->getCurrentStateScope() & c->getStateScope()) != 0; } // getCurrentModeScope // ======================================================================== @@ -864,11 +757,11 @@ void CommandManager::vote(Context& context, std::string category, std::string va if (!acting_peer->hasPlayerProfiles()) return; std::string username = acting_peer->getMainName(); - auto& votable = m_votables[command->m_prefix_name]; + auto& votable = m_votables[command->getFullName()]; bool neededCheck = votable.needsCheck(); votable.castVote(username, category, value); if (votable.needsCheck() && !neededCheck) - m_triggered_votables.push(command->m_prefix_name); + m_triggered_votables.push(command->getFullName()); } // vote // ======================================================================== @@ -940,7 +833,7 @@ void CommandManager::execute(std::shared_ptr command, Context& context) context.m_command = command; try { - (command->m_action)(context); + command->execute(context); } catch (std::exception& ex) { @@ -964,15 +857,18 @@ void CommandManager::process_help(Context& context) auto peer = context.peer(); std::shared_ptr command = m_root_command; - for (int i = 1; i < (int)argv.size(); ++i) { - if (hasTypo(acting_peer, peer, context.m_voting, context.m_argv, context.m_cmd, i, command->m_stf_subcommand_names, 3, false, false)) + for (int i = 1; i < (int)argv.size(); ++i) + { + if (hasTypo(acting_peer, peer, context.m_voting, context.m_argv, context.m_cmd, i, command->subcommandNamesTypoFixer(), 3, false, false)) return; - auto ptr = command->m_name_to_subcommand[argv[i]].lock(); + + auto ptr = command->findChild(argv[i]); if (ptr) command = ptr; else break; - if (command->m_subcommands.empty()) + + if (command->getSubcommands().empty()) break; } if (command == m_root_command) @@ -984,63 +880,6 @@ void CommandManager::process_help(Context& context) } // process_help // ======================================================================== -void CommandManager::process_text(Context& context) -{ - std::string response; - auto command = context.command(); - auto it = m_text_response.find(command->getFullName()); - if (it == m_text_response.end()) - response = StringUtils::insertValues( - "Error: a text command %s is defined without text", - command->getFullName().c_str()); - else - response = it->second.get(); - context.say(response); -} // process_text -// ======================================================================== - -void CommandManager::process_file(Context& context) -{ - std::string response; - auto command = context.command(); - - auto it = m_file_resources.find(command->getFullName()); - if (it == m_file_resources.end()) - response = StringUtils::insertValues( - "Error: file not found for a file command %s", - command->getFullName().c_str()); - else - response = it->second.get(); - context.say(response); -} // process_file -// ======================================================================== - -void CommandManager::process_auth(Context& context) -{ - std::string response; - auto acting_peer = context.actingPeer(); - auto command = context.command(); - - auto it = m_auth_resources.find(command->getFullName()); - if (it == m_auth_resources.end()) - response = StringUtils::insertValues( - "Error: auth method not found for a command %s", - command->getFullName().c_str()); - else - { - auto profile = acting_peer->getMainProfile(); - std::string username = StringUtils::wideToUtf8(profile->getName()); - int online_id = profile->getOnlineId(); - if (online_id == 0) - response = "Error: you need to join with an " - "online account to use auth methods"; - else - response = it->second.get(username, online_id); - } - context.say(response); -} // process_text -// ======================================================================== - void CommandManager::process_commands(Context& context) { std::string result; @@ -1050,13 +889,16 @@ void CommandManager::process_commands(Context& context) auto& argv = context.m_argv; std::shared_ptr command = m_root_command; bool valid_prefix = true; - for (int i = 1; i < (int)argv.size(); ++i) { - if (hasTypo(acting_peer, peer, context.m_voting, context.m_argv, context.m_cmd, i, command->m_stf_subcommand_names, 3, false, false)) + for (int i = 1; i < (int)argv.size(); ++i) + { + if (hasTypo(acting_peer, peer, context.m_voting, context.m_argv, context.m_cmd, i, command->subcommandNamesTypoFixer(), 3, false, false)) return; - auto ptr = command->m_name_to_subcommand[argv[i]].lock(); + + auto ptr = command->findChild(argv[i]); if (!ptr) break; - if ((context.m_acting_user_permissions & ptr->m_permissions) != 0 + + if ((context.m_acting_user_permissions & ptr->getPermissions()) != 0 && isAvailable(ptr)) command = ptr; else @@ -1064,7 +906,7 @@ void CommandManager::process_commands(Context& context) valid_prefix = false; break; } - if (command->m_subcommands.empty()) + if (command->getSubcommands().empty()) break; } if (!valid_prefix) @@ -1077,19 +919,19 @@ void CommandManager::process_commands(Context& context) result += ":"; bool had_any_subcommands = false; std::map res; - for (std::shared_ptr& subcommand: command->m_subcommands) + for (const std::shared_ptr& subcommand: command->getSubcommands()) { - if ((context.m_acting_user_permissions & subcommand->m_permissions) != 0 + if ((context.m_acting_user_permissions & subcommand->getPermissions()) != 0 && isAvailable(subcommand)) { bool subcommands_available = false; - for (auto& c: subcommand->m_subcommands) + for (auto& c: subcommand->getSubcommands()) { - if ((context.m_acting_user_permissions & c->m_permissions) != 0 + if ((context.m_acting_user_permissions & c->getPermissions()) != 0 && isAvailable(c)) subcommands_available = true; } - res[subcommand->m_name] = subcommands_available; + res[subcommand->getShortName()] = subcommands_available; if (subcommands_available) had_any_subcommands = true; } @@ -4020,25 +3862,6 @@ void CommandManager::onStartSelection() update(); } // onStartSelection // ======================================================================== -std::shared_ptr CommandManager::addChildCommand(std::shared_ptr target, - std::string name, void (CommandManager::*f)(Context& context), - int permissions, int mode_scope, int state_scope) -{ - std::shared_ptr child = std::make_shared(name, - std::bind(f, this, std::placeholders::_1), permissions, mode_scope, state_scope); - - target->m_subcommands.push_back(child); - child->m_parent = std::weak_ptr(target); - - if (target->m_prefix_name.empty()) - child->m_prefix_name = name; - else - child->m_prefix_name = target->m_prefix_name + " " + name; - - target->m_name_to_subcommand[name] = std::weak_ptr(child); - return child; -} // addChildCommand -// ======================================================================== std::string CommandManager::getAddonPreferredType() const { @@ -4111,4 +3934,10 @@ void CommandManager::shift(std::string& cmd, std::vector& argv, CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); } // shift +//----------------------------------------------------------------------------- + +std::function CommandManager::getDefaultAction() +{ + return std::bind(&CommandManager::special, this, std::placeholders::_1); +} // getDefaultAction //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 89c3b7800c7..5ae687fba22 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -45,7 +45,6 @@ #include "utils/command_manager/context.hpp" #include "utils/command_manager/file_resource.hpp" #include "utils/command_manager/text_resource.hpp" -#include "utils/enum_extended_reader.hpp" #include "utils/lobby_context.hpp" #include "utils/set_typo_fixer.hpp" #include "utils/team_utils.hpp" @@ -61,11 +60,6 @@ class STKPeer; class CommandManager: public LobbyContextComponent { private: - - static EnumExtendedReader permission_reader; - static EnumExtendedReader mode_scope_reader; - static EnumExtendedReader state_scope_reader; - std::deque>& get_queue(int x) const; template @@ -81,12 +75,6 @@ class CommandManager: public LobbyContextComponent std::multiset m_users; - std::map m_text_response; - - std::map m_file_resources; - - std::map m_auth_resources; - std::map m_votables; std::queue m_triggered_votables; @@ -136,9 +124,6 @@ class CommandManager: public LobbyContextComponent void execute(std::shared_ptr command, Context& context); void process_help(Context& context); - void process_text(Context& context); - void process_file(Context& context); - void process_auth(Context& context); void process_commands(Context& context); void process_replay(Context& context); void process_start(Context& context); @@ -240,22 +225,6 @@ class CommandManager: public LobbyContextComponent void handleCommand(Event* event, std::shared_ptr peer); - // template - // void addTextResponse(std::string key, T&& value) - // { m_text_response[key] = value; } - - void addTextResponse(std::string key, const TextResource& resource) - { m_text_response[key] = resource; } - - void addTextResponse(std::string key, TextResource&& resource) - { m_text_response[key] = std::move(resource); } - - void addFileResource(std::string key, const FileResource& resource) - { m_file_resources[key] = resource; } - - void addAuthResource(std::string key, const AuthResource& resource) - { m_auth_resources[key] = resource; } - void addUser(std::string& s); void deleteUser(std::string& s); @@ -280,16 +249,14 @@ class CommandManager: public LobbyContextComponent std::vector getCurrentArgv() { return m_current_argv; } - std::shared_ptr addChildCommand(std::shared_ptr target, std::string name, - void (CommandManager::*f)(Context& context), int permissions = UP_EVERYONE, - int mode_scope = MS_DEFAULT, int state_scope = SS_ALWAYS); - // Helper functions, unrelated to CommandManager inner structure std::string getAddonPreferredType() const; void shift(std::string& cmd, std::vector& argv, const std::string& username, int count); + std::function getDefaultAction(); + }; #endif // COMMAND_MANAGER_HPP diff --git a/src/utils/command_manager/auth_resource.cpp b/src/utils/command_manager/auth_resource.cpp index f706a75b950..fe151f3ccb6 100644 --- a/src/utils/command_manager/auth_resource.cpp +++ b/src/utils/command_manager/auth_resource.cpp @@ -20,16 +20,19 @@ #include "network/crypto.hpp" #include "utils/string_utils.hpp" #include "utils/time.hpp" +#include "network/stk_peer.hpp" +#include "network/network_player_profile.hpp" void AuthResource::fromXmlNode(const XMLNode* node) -{ +{ + Command::fromXmlNode(node); node->get("secret", &m_secret); node->get("server", &m_server); node->get("link-format", &m_link_format); } // AuthResource::AuthResource //----------------------------------------------------------------------------- -std::string AuthResource::get(const std::string& username, int online_id) +std::string AuthResource::get(const std::string& username, int online_id) const { #ifdef ENABLE_CRYPTO_OPENSSL std::string header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"; @@ -48,4 +51,23 @@ std::string AuthResource::get(const std::string& username, int online_id) return "This command is currently only supported for OpenSSL"; #endif } // AuthResource::get +//----------------------------------------------------------------------------- + +void AuthResource::execute(Context& context) +{ + std::string response; + auto acting_peer = context.actingPeer(); + auto command = context.command(); + + auto profile = acting_peer->getMainProfile(); + std::string username = StringUtils::wideToUtf8(profile->getName()); + int online_id = profile->getOnlineId(); + if (online_id == 0) + response = "Error: you need to join with an " + "online account to use auth methods"; + else + response = get(username, online_id); + + context.say(response); +} // execute //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/command_manager/auth_resource.hpp b/src/utils/command_manager/auth_resource.hpp index 3f8d40f0ada..1c5c835cb56 100644 --- a/src/utils/command_manager/auth_resource.hpp +++ b/src/utils/command_manager/auth_resource.hpp @@ -20,19 +20,23 @@ #define AUTH_RESOURCE_HPP #include -#include "utils/command_manager/abstract_resource.hpp" +#include "utils/command_manager/command.hpp" -class AuthResource: public AbstractResource +class AuthResource: public Command { private: std::string m_secret; std::string m_server; std::string m_link_format; + std::string get(const std::string& username, int online_id) const; + public: + bool needsFunction() const final { return false; } + void fromXmlNode(const XMLNode* node) final; - std::string get(const std::string& username, int online_id); + void execute(Context& context) final; }; #endif // AUTH_RESOURCE_HPP \ No newline at end of file diff --git a/src/utils/command_manager/command.cpp b/src/utils/command_manager/command.cpp index 86b2542cac4..37c3c948844 100644 --- a/src/utils/command_manager/command.cpp +++ b/src/utils/command_manager/command.cpp @@ -17,23 +17,101 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "utils/command_manager/command.hpp" +#include "utils/string_utils.hpp" +#include "network/server_config.hpp" +#include "utils/enum_extended_reader.hpp" +#include "utils/log.hpp" -Command::Command(std::string name, - std::function f, - int permissions, - int mode_scope, - int state_scope) - : m_name(std::move(name)) - , m_action(std::move(f)) - , m_permissions(permissions) - , m_mode_scope(mode_scope) - , m_state_scope(state_scope) - , m_omit_name(false) +#include "utils/command_manager/auth_resource.hpp" +#include "utils/command_manager/file_resource.hpp" +#include "utils/command_manager/text_resource.hpp" + +// This is needed for default actions only for now... +#include "network/protocols/command_manager.hpp" + +#include + +namespace { - // Handling players who are allowed to run for anyone in any case - m_permissions |= UU_OTHERS_COMMANDS; -} // Command::Command(5) -// ======================================================================== + static EnumExtendedReader mode_scope_reader({ + {"MS_DEFAULT", MS_DEFAULT}, + {"MS_SOCCER_TOURNAMENT", MS_SOCCER_TOURNAMENT} + }); + + static EnumExtendedReader state_scope_reader({ + {"SS_LOBBY", SS_LOBBY}, + {"SS_INGAME", SS_INGAME}, + {"SS_ALWAYS", SS_ALWAYS} + }); + + static EnumExtendedReader permission_reader({ + {"PE_NONE", PE_NONE}, + {"UU_SPECTATOR", UU_SPECTATOR}, + {"UU_USUAL", UU_USUAL}, + {"UU_CROWNED", UU_CROWNED}, + {"UU_SINGLE", UU_SINGLE}, + {"UU_HAMMER", UU_HAMMER}, + {"UU_MANIPULATOR", UU_MANIPULATOR}, + {"UU_CONSOLE", UU_CONSOLE}, + {"PE_SPECTATOR", PE_SPECTATOR}, + {"PE_USUAL", PE_USUAL}, + {"PE_CROWNED", PE_CROWNED}, + {"PE_SINGLE", PE_SINGLE}, + {"PE_HAMMER", PE_HAMMER}, + {"PE_MANIPULATOR", PE_MANIPULATOR}, + {"PE_CONSOLE", PE_CONSOLE}, + {"UU_OWN_COMMANDS", UU_OWN_COMMANDS}, + {"UU_OTHERS_COMMANDS", UU_OTHERS_COMMANDS}, + {"PE_ALLOW_ANYONE", PE_ALLOW_ANYONE}, + {"PE_VOTED_SPECTATOR", PE_VOTED_SPECTATOR}, + {"PE_VOTED_NORMAL", PE_VOTED_NORMAL}, + {"PE_VOTED", PE_VOTED}, + {"UP_CONSOLE", UP_CONSOLE}, + {"UP_MANIPULATOR", UP_MANIPULATOR}, + {"UP_HAMMER", UP_HAMMER}, + {"UP_SINGLE", UP_SINGLE}, + {"UP_CROWNED", UP_CROWNED}, + {"UP_NORMAL", UP_NORMAL}, + {"UP_EVERYONE", UP_EVERYONE} + }); + + // C++20 compile-time string to class conversion + + // template + // struct XmlNameToClass; + + // template<> struct XmlNameToClass<"command"> { using type = Command; }; + // template<> struct XmlNameToClass<"text-command"> { using type = TextResource; }; + // template<> struct XmlNameToClass<"file-command"> { using type = FileResource; }; + // template<> struct XmlNameToClass<"auth-command"> { using type = AuthResource; }; + +} // namespace +//============================================================================= + +CommandDescription::CommandDescription(std::string usage, + std::string permissions, + std::string description) + : m_usage(std::move(usage)) + , m_permissions(std::move(permissions)) + , m_description(std::move(description)) +{} +//----------------------------------------------------------------------------- + +std::string CommandDescription::getUsage() const +{ + return StringUtils::insertValues("Usage: %s", m_usage.c_str()); +} // getUsage +//----------------------------------------------------------------------------- + +std::string CommandDescription::getHelp() const +{ + return StringUtils::insertValues("Usage: %s\nAvailable to: %s\n%s", + m_usage.c_str(), + m_permissions.c_str(), + m_description.c_str() + ); +} // getHelp +//============================================================================= void Command::changePermissions(int permissions, int mode_scope, int state_scope) @@ -42,5 +120,151 @@ void Command::changePermissions(int permissions, m_permissions = permissions | UU_OTHERS_COMMANDS; m_mode_scope = mode_scope; m_state_scope = state_scope; -} // changePermissions -// ======================================================================== \ No newline at end of file +} // changePermissions +//----------------------------------------------------------------------------- + + +std::shared_ptr Command::unknownTypeFromXmlNode(const XMLNode* node) +{ + std::string node_name = node->getName(); + if (node_name == "external-commands-file") + return {}; + + std::shared_ptr res; + if (node_name == "command") + res = std::make_shared(); + else if (node_name == "text-command") + res = std::make_shared(); + else if (node_name == "auth-command") + res = std::make_shared(); + else if (node_name == "file-command") + res = std::make_shared(); + else + { + Log::error("Command", "Unknown node name %s, treating as normal command.", node_name.c_str()); + res = std::make_shared(); + } + + try + { + res->fromXmlNode(node); + } + catch (std::exception& ex) + { + Log::error("Command", "unknownTypeFromXmlNode: error while calling fromXmlNode: %s", ex.what()); + return {}; + } + + return res; +} + +void Command::fromXmlNode(const XMLNode* node) +{ + std::string name = ""; + std::string usage = ""; + std::string permissions_s = "UP_EVERYONE"; + std::string mode_scope_s = "MS_DEFAULT"; + std::string state_scope_s = "SS_ALWAYS"; + bool omit_name = false; + int permissions; + int mode_scope; + int state_scope; + std::string permissions_str = ""; + std::string description = ""; + std::string aliases = ""; + + node->get("name", &name); + m_name = name; + + // If enabled is not empty, command is added iff the server name is in enabled + // Otherwise it is added iff the server name is not in disabled + std::string enabled = ""; + std::string disabled = ""; + node->get("enabled", &enabled); + node->get("disabled", &disabled); + bool ok; + if (!enabled.empty()) + { + std::vector enabled_split = StringUtils::split(enabled, ' '); + ok = false; + for (const std::string& s: enabled_split) + if (s == ServerConfig::m_server_uid) + ok = true; + } + else + { + std::vector disabled_split = StringUtils::split(disabled, ' '); + ok = true; + for (const std::string& s: disabled_split) + if (s == ServerConfig::m_server_uid) + ok = false; + } + + if (!ok) + { + throw std::logic_error(StringUtils::insertValues( + "The command %s is not loaded, as it was disabled in the config.", + name.c_str() + )); + } + + node->get("permissions", &permissions_s); + node->get("mode-scope", &mode_scope_s); + node->get("state-scope", &state_scope_s); + permissions = permission_reader.parse(permissions_s); + mode_scope = mode_scope_reader.parse(mode_scope_s); + state_scope = state_scope_reader.parse(state_scope_s); + changePermissions(permissions, mode_scope, state_scope); + + node->get("usage", &usage); + node->get("permissions-verbose", &permissions_str); + node->get("description", &description); + m_description = CommandDescription(usage, permissions_str, description); + + node->get("aliases", &aliases); + m_aliases = StringUtils::split(aliases, ' '); + + node->get("omit-name", &omit_name); + m_omit_name = omit_name; + + // m_action is set in CommandManager, as it knows better about implementation. + // CM::special is also set from there. +} // fromXmlNode +//----------------------------------------------------------------------------- + +void Command::addChild(const std::shared_ptr& child) +{ + child->m_parent = shared_from_this(); + const std::string name = child->m_name; + + m_subcommands.push_back(child); + child->m_prefix_name = + (m_prefix_name.empty() ? "" : m_prefix_name + " ") + name; + + auto weak = std::weak_ptr(child); + m_name_to_subcommand[name] = weak; + + m_stf_subcommand_names.add(name); + for (const std::string& alias_name: child->getAliases()) + { + m_stf_subcommand_names.add(alias_name, name); + m_name_to_subcommand[alias_name] = m_name_to_subcommand[name]; + } +} // addChild +//----------------------------------------------------------------------------- + +void Command::execute(Context& context) +{ + m_action(context); +} // execute +//----------------------------------------------------------------------------- + +std::shared_ptr Command::findChild(const std::string& name) const +{ + const auto& it = m_name_to_subcommand.find(name); + if (it == m_name_to_subcommand.end()) + return {}; + + return it->second.lock(); +} // findChild +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/command_manager/command.hpp b/src/utils/command_manager/command.hpp index 5f58d2d0a93..cec4551c896 100644 --- a/src/utils/command_manager/command.hpp +++ b/src/utils/command_manager/command.hpp @@ -25,8 +25,10 @@ #include #include -#include "utils/set_typo_fixer.hpp" #include "network/protocols/command_permissions.hpp" +#include "utils/set_typo_fixer.hpp" +#include "io/xml_node.hpp" +#include "utils/command_manager/context.hpp" struct Context; @@ -49,29 +51,26 @@ struct CommandDescription std::string m_usage; std::string m_permissions; std::string m_description; - CommandDescription(std::string usage = "", std::string permissions = "", - std::string description = ""): m_usage(usage), - m_permissions(permissions), m_description(description) {} - - std::string getUsage() const { return "Usage: " + m_usage; } - - std::string getHelp() const - { - return "Usage: " + m_usage - + "\nAvailable to: " + m_permissions - + "\n" + m_description; - } + CommandDescription(std::string usage = "", + std::string permissions = "", + std::string description = ""); + + std::string getUsage() const; + + std::string getHelp() const; }; -struct Command +struct Command: public std::enable_shared_from_this { +private: std::string m_name; std::string m_prefix_name; - std::function m_action; - int m_permissions; - int m_mode_scope; - int m_state_scope; + std::function m_action = nullptr; + int m_permissions = UP_EVERYONE; + int m_mode_scope = MS_DEFAULT; + int m_state_scope = SS_ALWAYS; bool m_omit_name; + std::vector m_aliases; CommandDescription m_description; std::weak_ptr m_parent; @@ -79,14 +78,22 @@ struct Command std::vector> m_subcommands; SetTypoFixer m_stf_subcommand_names; +protected: + virtual void fromXmlNode(const XMLNode* node); + +public: + virtual bool needsFunction() const { return true; } + Command() {} - Command(std::string name, - std::function f, - int permissions = UP_EVERYONE, - int mode_scope = MS_DEFAULT, int state_scope = SS_ALWAYS); + // Command(std::string name, + // std::function f, + // int permissions = UP_EVERYONE, + // int mode_scope = MS_DEFAULT, int state_scope = SS_ALWAYS); + + static std::shared_ptr unknownTypeFromXmlNode(const XMLNode* node); - void changeFunction(std::function f) + void setFunction(std::function f) { m_action = std::move(f); } void changePermissions(int permissions = UP_EVERYONE, @@ -96,6 +103,26 @@ struct Command std::string getUsage() const { return m_description.getUsage(); } std::string getHelp() const { return m_description.getHelp(); } std::string getFullName() const { return m_prefix_name; } + std::string getShortName() const { return m_name; } + int getPermissions() const { return m_permissions; } + int getModeScope() const { return m_mode_scope; } + int getStateScope() const { return m_state_scope; } + bool omittedName() const { return m_omit_name; } + bool hasFunction() const { return m_action != nullptr; } + + const SetTypoFixer& subcommandNamesTypoFixer() const + { return m_stf_subcommand_names; } + + std::shared_ptr findChild(const std::string& name) const; + + const std::vector>& getSubcommands() const + { return m_subcommands; } + + void addChild(const std::shared_ptr& child); + + const std::vector& getAliases() const { return m_aliases; } + + virtual void execute(Context& context); }; #endif // COMMAND_HPP \ No newline at end of file diff --git a/src/utils/command_manager/file_resource.cpp b/src/utils/command_manager/file_resource.cpp index cd99720e6e0..8e991a387e6 100644 --- a/src/utils/command_manager/file_resource.cpp +++ b/src/utils/command_manager/file_resource.cpp @@ -26,6 +26,7 @@ void FileResource::fromXmlNode(const XMLNode* node) { + Command::fromXmlNode(node); node->get("file", &m_file_name); node->get("interval", &m_interval); @@ -69,10 +70,10 @@ void FileResource::tryUpdate() } // tryUpdate //----------------------------------------------------------------------------- -std::string FileResource::get() +void FileResource::execute(Context& context) { tryUpdate(); - return m_contents; -} // get + context.say(m_contents); +} // execute //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/command_manager/file_resource.hpp b/src/utils/command_manager/file_resource.hpp index 76ee4664c9e..6bba151b9a9 100644 --- a/src/utils/command_manager/file_resource.hpp +++ b/src/utils/command_manager/file_resource.hpp @@ -21,10 +21,10 @@ #define FILE_RESOURCE_HPP #include "utils/types.hpp" -#include "utils/command_manager/abstract_resource.hpp" +#include "utils/command_manager/command.hpp" #include -struct FileResource: public AbstractResource +struct FileResource: public Command { private: std::string m_file_name; @@ -38,9 +38,11 @@ struct FileResource: public AbstractResource virtual void read(); public: - void fromXmlNode(const XMLNode* node) final; + bool needsFunction() const final { return false; } - std::string get(); + virtual void fromXmlNode(const XMLNode* node) override; + + virtual void execute(Context& context) override; }; diff --git a/src/utils/command_manager/text_resource.cpp b/src/utils/command_manager/text_resource.cpp index 96cadbdf2a5..80a28e9e510 100644 --- a/src/utils/command_manager/text_resource.cpp +++ b/src/utils/command_manager/text_resource.cpp @@ -18,16 +18,15 @@ #include "utils/command_manager/text_resource.hpp" - - void TextResource::fromXmlNode(const XMLNode* node) { + Command::fromXmlNode(node); node->get("text", &m_text); } // FileResource //----------------------------------------------------------------------------- -std::string TextResource::get() +void TextResource::execute(Context& context) { - return m_text; -} // get + context.say(m_text); +} // execute //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/command_manager/text_resource.hpp b/src/utils/command_manager/text_resource.hpp index 3320124df4b..c5695020d41 100644 --- a/src/utils/command_manager/text_resource.hpp +++ b/src/utils/command_manager/text_resource.hpp @@ -21,16 +21,18 @@ #define TEXT_RESOURCE_HPP #include "utils/types.hpp" -#include "utils/command_manager/abstract_resource.hpp" +#include "utils/command_manager/command.hpp" #include -class TextResource: public AbstractResource +class TextResource: public Command { private: std::string m_text; public: - TextResource() {} + bool needsFunction() const final { return false; } + + TextResource(): m_text("") {} template TextResource(const T& str): m_text(str) {} @@ -38,9 +40,11 @@ class TextResource: public AbstractResource template TextResource(T&& str): m_text(std::move(str)) {} + void setText(const std::string& str) { m_text = str; } + void fromXmlNode(const XMLNode* node) final; - std::string get(); + void execute(Context& context) final; }; From 2db2d731a0aeb3c75ac6e6bef1ddd6e406392044 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 24 Aug 2025 01:02:50 +0400 Subject: [PATCH 820/830] Delete unused AbstractResource which was merged into existing Command class --- .../command_manager/abstract_resource.hpp | 40 ------------------- 1 file changed, 40 deletions(-) delete mode 100644 src/utils/command_manager/abstract_resource.hpp diff --git a/src/utils/command_manager/abstract_resource.hpp b/src/utils/command_manager/abstract_resource.hpp deleted file mode 100644 index e5a80725038..00000000000 --- a/src/utils/command_manager/abstract_resource.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// SuperTuxKart - a fun racing game with go-kart -// Copyright (C) 2025 kimden -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 3 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#ifndef ABSTRACT_RESOURCE_HPP -#define ABSTRACT_RESOURCE_HPP - -#include -#include "io/xml_node.hpp" - -/** - * AbstractResource represents a generic externally produced resource - * (that is, typically not produced inside the game, or produced inside the game, - * but further processed elsewhere). - */ -class AbstractResource -{ -public: - - virtual void fromXmlNode(const XMLNode* node) = 0; - - // virtual std::string process(Context& context) = 0; -}; - - -#endif // ABSTRACT_RESOURCE_HPP \ No newline at end of file From 7afd1a7a950f824d128b41954f249a45f333aa16 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sun, 24 Aug 2025 02:38:48 +0400 Subject: [PATCH 821/830] Basic MapFileResource implementation + method moves - restoreCmdByArgv and error(context) were moved out of CommandManager - MapFileResource currently supports searching rows using a column specified in the config --- src/network/protocols/command_manager.cpp | 69 +++------ src/network/protocols/command_manager.hpp | 4 - src/utils/command_manager/command.cpp | 6 +- src/utils/command_manager/context.cpp | 32 ++++ src/utils/command_manager/context.hpp | 2 + src/utils/command_manager/file_resource.cpp | 9 +- src/utils/command_manager/file_resource.hpp | 7 +- .../command_manager/map_file_resource.cpp | 142 ++++++++++++++++++ .../command_manager/map_file_resource.hpp | 63 ++++++++ src/utils/set_typo_fixer.cpp | 7 + src/utils/set_typo_fixer.hpp | 1 + src/utils/string_utils.cpp | 16 ++ src/utils/string_utils.hpp | 3 + 13 files changed, 303 insertions(+), 58 deletions(-) create mode 100644 src/utils/command_manager/map_file_resource.cpp create mode 100644 src/utils/command_manager/map_file_resource.hpp diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 54cf9c9e24b..a173cb40881 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -124,6 +124,15 @@ namespace return QM_NONE; } // another_cyclic_queue // ==================================================================== + + void restoreCmdByArgv(std::string& cmd, + std::vector& argv, char c, char d, char e, char f, + int from = 0) + { + cmd = StringUtils::quoteEscapeArray(argv.begin() + from, argv.end(), + c, d, e, f); + } // restoreCmdByArgv + // ======================================================================== // Auxiliary things, should be moved somewhere because they just help @@ -520,7 +529,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); if (argv.empty()) return; - CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); permissions = getLobby()->getPermissions(peer); voting = false; @@ -543,7 +552,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); if (argv.empty()) return; - CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); voting = m_user_saved_voting[username]; target_peer = m_user_saved_acting_peer[username]; target_peer_strong = target_peer.lock(); @@ -717,7 +726,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) { std::string new_cmd = p.first + " " + p.second; auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '"', '\\'); - CommandManager::restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); + restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); std::string msg2 = StringUtils::insertValues( "Command \"/%s\" has been successfully voted", new_cmd.c_str()); @@ -778,7 +787,7 @@ void CommandManager::update() { std::string new_cmd = p.first + " " + p.second; auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '"', '\\'); - CommandManager::restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); + restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); std::string msg = StringUtils::insertValues( "Command \"/%s\" has been successfully voted", new_cmd.c_str()); @@ -802,29 +811,9 @@ void CommandManager::update() void CommandManager::error(Context& context, bool is_error) { - std::string msg; - if (is_error) - Log::error("CommandManager", "An error occurred while invoking %s", context.m_cmd.c_str()); - auto command = context.m_command.lock(); - auto peer = context.m_peer.lock(); - if (!command) { - Log::error("CommandManager", "CM::error: cannot load command"); - return; - } - if (!peer) { - Log::error("CommandManager", "CM::error: cannot load peer to send error"); - return; - } - msg = command->getUsage(); - if (msg.empty()) - msg = StringUtils::insertValues("An error occurred " - "while invoking command \"%s\".", - command->getFullName().c_str()); - - if (is_error) - msg += "\n/!\\ Please report this error to the server owner"; - context.say(msg); -} // error + // When you have no time, change all error(context) calls to context.error() + context.error(is_error); +} // error // ======================================================================== void CommandManager::execute(std::shared_ptr command, Context& context) @@ -2231,7 +2220,7 @@ void CommandManager::process_queue_push(Context& context) argv[2] = asset_manager->getRandomAddonMap(); std::string filter_text = ""; - CommandManager::restoreCmdByArgv(filter_text, argv, ' ', '"', '"', '\\', 2); + restoreCmdByArgv(filter_text, argv, ' ', '"', '"', '\\', 2); // Fix typos only if track queues are used (majority of cases anyway) // TODO: I don't know how to fix typos for both karts and tracks @@ -2864,7 +2853,7 @@ void CommandManager::process_scoring_assign(Context& context) auto& argv = context.m_argv; std::string cmd2; - CommandManager::restoreCmdByArgv(cmd2, argv, ' ', '"', '"', '\\', 1); + restoreCmdByArgv(cmd2, argv, ' ', '"', '"', '\\', 1); if (getGPManager()->trySettingGPScoring(cmd2)) Comm::sendStringToAllPeers("Scoring set to \"" + cmd2 + "\""); else @@ -3743,20 +3732,6 @@ void CommandManager::deleteUser(std::string& s) } // deleteUser // ======================================================================== -void CommandManager::restoreCmdByArgv(std::string& cmd, - std::vector& argv, char c, char d, char e, char f, - int from) -{ - cmd.clear(); - for (int i = from; i < (int)argv.size(); ++i) { - if (i > from) { - cmd.push_back(c); - } - cmd += StringUtils::quoteEscape(argv[i], c, d, e, f); - } -} // restoreCmdByArgv -// ======================================================================== - bool CommandManager::validate(Context& ctx, int idx, TypoFixerType fixer_type, bool case_sensitive, bool allow_as_is) { @@ -3827,12 +3802,12 @@ bool CommandManager::hasTypo(std::shared_ptr acting_peer, std::shared_p } for (unsigned i = 0; i < closest_commands.size(); ++i) { argv[idx] = prefix + closest_commands[i].first + suffix; - CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); m_user_command_replacements[username].push_back(cmd); response += "\ntype /" + std::to_string(i + 1) + " to choose \"" + closest_commands[i].first + "\""; } argv[idx] = initial_argument; - CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); Comm::sendStringToPeer(peer, response); return true; } @@ -3840,7 +3815,7 @@ bool CommandManager::hasTypo(std::shared_ptr acting_peer, std::shared_p if (!dont_replace) { argv[idx] = prefix + closest_commands[0].first + suffix; // converts case or regex - CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); } return false; } // hasTypo @@ -3932,7 +3907,7 @@ void CommandManager::shift(std::string& cmd, std::vector& argv, m_user_last_correct_argument[username].first -= count; - CommandManager::restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); } // shift //----------------------------------------------------------------------------- diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 5ae687fba22..2706d4d22f7 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -229,10 +229,6 @@ class CommandManager: public LobbyContextComponent void deleteUser(std::string& s); - static void restoreCmdByArgv(std::string& cmd, - std::vector& argv, char c, char d, char e, char f, - int from = 0); - // A simple version of hasTypo for validating simple arguments. // Returns the opposite bool value. bool validate(Context& ctx, int idx, diff --git a/src/utils/command_manager/command.cpp b/src/utils/command_manager/command.cpp index 37c3c948844..521dc55c457 100644 --- a/src/utils/command_manager/command.cpp +++ b/src/utils/command_manager/command.cpp @@ -24,11 +24,9 @@ #include "utils/command_manager/auth_resource.hpp" #include "utils/command_manager/file_resource.hpp" +#include "utils/command_manager/map_file_resource.hpp" #include "utils/command_manager/text_resource.hpp" -// This is needed for default actions only for now... -#include "network/protocols/command_manager.hpp" - #include namespace @@ -139,6 +137,8 @@ std::shared_ptr Command::unknownTypeFromXmlNode(const XMLNode* node) res = std::make_shared(); else if (node_name == "file-command") res = std::make_shared(); + else if (node_name == "map-file-command") + res = std::make_shared(); else { Log::error("Command", "Unknown node name %s, treating as normal command.", node_name.c_str()); diff --git a/src/utils/command_manager/context.cpp b/src/utils/command_manager/context.cpp index 91a6b791ac3..c9949ec950a 100644 --- a/src/utils/command_manager/context.cpp +++ b/src/utils/command_manager/context.cpp @@ -18,6 +18,9 @@ #include "utils/command_manager/context.hpp" #include "utils/communication.hpp" +#include "utils/command_manager/command.hpp" +#include "utils/string_utils.hpp" +#include "utils/log.hpp" std::shared_ptr Context::peer() { @@ -86,4 +89,33 @@ void Context::say(const std::string& s) auto peer = m_peer.lock(); Comm::sendStringToPeer(peer, s); } // say +//----------------------------------------------------------------------------- + +void Context::error(bool is_error) +{ + std::string msg; + if (is_error) + Log::error("CMContext", "An error occurred while invoking %s", m_cmd.c_str()); + + auto command = m_command.lock(); + auto peer = m_peer.lock(); + if (!command) { + Log::error("CMContext", "CM::error: cannot load command"); + return; + } + if (!peer) { + Log::error("CMContext", "CM::error: cannot load peer to send error"); + return; + } + msg = command->getUsage(); + if (msg.empty()) + msg = StringUtils::insertValues("An error occurred " + "while invoking command \"%s\".", + command->getFullName().c_str()); + + if (is_error) + msg += "\n/!\\ Please report this error to the server owner"; + + say(msg); +} // error //----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/command_manager/context.hpp b/src/utils/command_manager/context.hpp index d17a77625af..bad25ca5784 100644 --- a/src/utils/command_manager/context.hpp +++ b/src/utils/command_manager/context.hpp @@ -69,6 +69,8 @@ struct Context std::shared_ptr command(); void say(const std::string& s); + + void error(bool is_error = false); }; #endif // CONTEXT_HPP \ No newline at end of file diff --git a/src/utils/command_manager/file_resource.cpp b/src/utils/command_manager/file_resource.cpp index 8e991a387e6..96adcdbfa17 100644 --- a/src/utils/command_manager/file_resource.cpp +++ b/src/utils/command_manager/file_resource.cpp @@ -32,7 +32,6 @@ void FileResource::fromXmlNode(const XMLNode* node) m_contents = ""; m_last_invoked = 0; - read(); } // FileResource //----------------------------------------------------------------------------- @@ -57,8 +56,14 @@ void FileResource::read() answer.pop_back(); } - m_contents = answer; m_last_invoked = StkTime::getMonoTimeMs(); + + // Don't do anything if the file is the same + if (m_contents != answer) + { + m_contents = answer; + onContentChange(); + } } // read //----------------------------------------------------------------------------- diff --git a/src/utils/command_manager/file_resource.hpp b/src/utils/command_manager/file_resource.hpp index 6bba151b9a9..c9badea9716 100644 --- a/src/utils/command_manager/file_resource.hpp +++ b/src/utils/command_manager/file_resource.hpp @@ -30,12 +30,15 @@ struct FileResource: public Command std::string m_file_name; uint64_t m_interval; mutable uint64_t m_last_invoked; + + void read(); + +protected: std::string m_contents; void tryUpdate(); -protected: - virtual void read(); + virtual void onContentChange() {} public: bool needsFunction() const final { return false; } diff --git a/src/utils/command_manager/map_file_resource.cpp b/src/utils/command_manager/map_file_resource.cpp new file mode 100644 index 00000000000..48bc8c7d52d --- /dev/null +++ b/src/utils/command_manager/map_file_resource.cpp @@ -0,0 +1,142 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/command_manager/map_file_resource.hpp" + +#include "utils/string_utils.hpp" + +namespace +{ + int readChar(const XMLNode* node, std::string&& name, char* value) + { + std::string temp(1, *value); + auto res = node->get(std::move(name), &temp); + temp = StringUtils::wideToUtf8(StringUtils::xmlDecode(temp)); + if (res == 0 || temp.empty()) + return 0; + + *value = temp[0]; + return 1; + } +} // namespace +//----------------------------------------------------------------------------- + +void MapFileResource::fromXmlNode(const XMLNode* node) +{ + FileResource::fromXmlNode(node); + node->get("print-format", &m_print_format); + readChar(node, "line-delimiter", &m_line_delimiter); + readChar(node, "field-delimiter", &m_field_delimiter); + + if (!readChar(node, "out-line-delimiter", &m_out_line_delimiter)) + m_out_line_delimiter = m_line_delimiter; + if (!readChar(node, "out-field-delimiter", &m_out_field_delimiter)) + m_out_field_delimiter = m_field_delimiter; + + readChar(node, "out-field-delimiter", &m_out_field_delimiter); + readChar(node, "left-quote", &m_left_quote); + readChar(node, "right-quote", &m_right_quote); + readChar(node, "escape", &m_escape); + node->get("index", &m_index); +} // MapFileResource +//----------------------------------------------------------------------------- + +void MapFileResource::onContentChange() +{ + auto rows = StringUtils::splitQuoted(m_contents, m_line_delimiter, m_left_quote, m_right_quote, m_escape); + m_rows.resize(rows.size()); + for (size_t i = 0; i < m_rows.size(); ++i) + { + m_rows[i] = std::make_shared(); + m_rows[i]->cells = StringUtils::splitQuoted(rows[i], m_field_delimiter, m_left_quote, m_right_quote, m_escape); + } + + m_fixer.clear(); + m_indexed.clear(); + if (m_index >= 0) + { + for (size_t i = 0; i < m_rows.size(); ++i) + { + auto& container = m_rows[i]; + if (m_index < (int)container->cells.size()) + { + const std::string key = container->cells[m_index]; + m_fixer.add(key); + m_indexed[key].push_back(container); + } + } + } +} // onContentChange +//----------------------------------------------------------------------------- + +void MapFileResource::execute(Context& context) +{ + tryUpdate(); + + auto& argv = context.m_argv; + auto acting_peer = context.actingPeer(); + auto peer = context.peer(); + + if (argv.size() < 2) + { + context.error(); + return; + } + + // I'm not sure if we should search by username. + // After all, the search column might contain something else. + if (argv[1] == "search") + { + if (2 >= argv.size()) + { + context.error(); + return; + } + + std::string key = argv[2]; + // Add fixing typos later + auto it = m_indexed.find(key); + if (it == m_indexed.end()) + context.say(StringUtils::insertValues("Nothing found for %s", key.c_str())); + else + { + std::string msg = ""; + int sz = it->second.size(); + if (sz >= 2) + msg += StringUtils::insertValues("Found %s lines\n", sz); + for (auto& row: it->second) + { + if (row) + msg += StringUtils::quoteEscapeArray( + row->cells.begin(), row->cells.end(), m_out_field_delimiter, + m_left_quote, m_right_quote, m_escape); + + msg += "\n"; + } + msg.pop_back(); + context.say(msg); + } + } + else + { + // Implement /command to and /command from to later + context.error(); + return; + } +} // execute +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/command_manager/map_file_resource.hpp b/src/utils/command_manager/map_file_resource.hpp new file mode 100644 index 00000000000..e68088df710 --- /dev/null +++ b/src/utils/command_manager/map_file_resource.hpp @@ -0,0 +1,63 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2025 kimden +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +#ifndef MAP_FILE_RESOURCE_HPP +#define MAP_FILE_RESOURCE_HPP + +#include "utils/types.hpp" +#include "utils/command_manager/file_resource.hpp" +#include + +struct MapFileResource: public FileResource +{ +private: + std::string m_print_format; + char m_line_delimiter = '\n'; // Line breaks should be checked on Windows + char m_field_delimiter = ' '; + char m_out_line_delimiter; + char m_out_field_delimiter; + char m_left_quote = '"'; + char m_right_quote = '"'; + char m_escape = '\\'; + + // Technically nothing prevents us from making several indices. + // Except the lack of practical need, of course. + int m_index = 0; + + struct Row + { + std::vector cells; + }; + + std::vector> m_rows; + std::map>> m_indexed; + + SetTypoFixer m_fixer; + +protected: + void onContentChange() override; + +public: + virtual void fromXmlNode(const XMLNode* node) override; + + virtual void execute(Context& context) override; +}; + + +#endif // MAP_FILE_RESOURCE_HPP \ No newline at end of file diff --git a/src/utils/set_typo_fixer.cpp b/src/utils/set_typo_fixer.cpp index 7f859e155f4..8d57966ba51 100644 --- a/src/utils/set_typo_fixer.cpp +++ b/src/utils/set_typo_fixer.cpp @@ -41,6 +41,13 @@ void SetTypoFixer::remove(const std::string& key) } // remove //----------------------------------------------------------------------------- +void SetTypoFixer::clear() +{ + m_set.clear(); + m_map.clear(); +} // clear +//----------------------------------------------------------------------------- + std::vector> SetTypoFixer::getClosest( const std::string& query, int count, bool case_sensitive) const { diff --git a/src/utils/set_typo_fixer.hpp b/src/utils/set_typo_fixer.hpp index 4105ce04512..8a2d14469ec 100644 --- a/src/utils/set_typo_fixer.hpp +++ b/src/utils/set_typo_fixer.hpp @@ -45,6 +45,7 @@ class SetTypoFixer void add(const std::string& key); void add(const std::string& key, const std::string& value); void remove(const std::string& key); + void clear(); std::vector> getClosest( const std::string& query, int count = 3, diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index af132c19aa6..efb811a0f52 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -254,6 +254,22 @@ namespace StringUtils return ans; } // quoteEscape + + + std::string quoteEscapeArray(const std::vector::iterator begin, + const std::vector::iterator end, + char c, char d, char e, char f) + { + std::string res = ""; + for (auto it = begin; it != end; ++it) + { + if (it != begin) { + res.push_back(c); + } + res += StringUtils::quoteEscape(*it, c, d, e, f); + } + return res; + } // quoteEscapeArray //------------------------------------------------------------------------- /** Splits a string into substrings separated by a certain character, and * returns a std::vector of all those substring. E.g.: diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index d83586468e1..c6f824d8ccb 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -58,6 +58,9 @@ namespace StringUtils char d, char e, char f); std::string quoteEscape(const std::string& s, char c, char d, char e, char f); + std::string quoteEscapeArray(const std::vector::iterator begin, + const std::vector::iterator end, + char c, char d, char e, char f); std::vector split(const std::string& s, char c, bool keepSplitChar=false); std::vector split(const std::u32string& s, char32_t c, From cc98caaf3c9004ebc2f6fb99535605f5a02e2f59 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 25 Aug 2025 22:47:29 +0400 Subject: [PATCH 822/830] Implement segment view of MapFileResource --- .../command_manager/map_file_resource.cpp | 51 +++++++++++++++++-- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/src/utils/command_manager/map_file_resource.cpp b/src/utils/command_manager/map_file_resource.cpp index 48bc8c7d52d..9fc5f1eccd8 100644 --- a/src/utils/command_manager/map_file_resource.cpp +++ b/src/utils/command_manager/map_file_resource.cpp @@ -98,6 +98,8 @@ void MapFileResource::execute(Context& context) return; } + std::string msg = ""; + // I'm not sure if we should search by username. // After all, the search column might contain something else. if (argv[1] == "search") @@ -115,7 +117,6 @@ void MapFileResource::execute(Context& context) context.say(StringUtils::insertValues("Nothing found for %s", key.c_str())); else { - std::string msg = ""; int sz = it->second.size(); if (sz >= 2) msg += StringUtils::insertValues("Found %s lines\n", sz); @@ -129,14 +130,54 @@ void MapFileResource::execute(Context& context) msg += "\n"; } msg.pop_back(); - context.say(msg); } } else { - // Implement /command to and /command from to later - context.error(); - return; + int from, to; + bool has_from = (1 < argv.size() && StringUtils::parseString(argv[1], &from) && from != 0); + bool has_to = (2 < argv.size() && StringUtils::parseString(argv[2], &to) && to != 0); + if (!has_from || (!has_to && 2 < argv.size())) + { + context.error(); + return; + } + if (!has_to) + to = (from > 0 ? 1 : -1); + + if (from >= to) + std::swap(from, to); + + if (from >= 0) // 3 8 -> [2, 8) + --from; + else if (to < 0) // -8 -3 -> [-8, -2) + ++to; + // else nothing: -4 5 -> [-4, 5) + + int n = m_indexed.size(); + int shift = (from / n) * n + (from < 0 ? -n : 0); + from -= shift; + to -= shift; + if (to - from > 0) + to = from + (to - from - 1) % n + 1; + + int sz = to - from; + if (sz >= 2) + msg += StringUtils::insertValues("Found %s lines\n", sz); + + for (int i = from; i < to; ++i) + { + int x = (i >= n ? i - n : i); + auto& row = m_rows[x]; + if (row) + msg += StringUtils::quoteEscapeArray( + row->cells.begin(), row->cells.end(), m_out_field_delimiter, + m_left_quote, m_right_quote, m_escape); + + msg += "\n"; + } + msg.pop_back(); } + context.say(msg); } // execute //----------------------------------------------------------------------------- \ No newline at end of file From dbcd150b51fb7b0957f52b3c04003f39ca7882a8 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 29 Aug 2025 02:18:29 +0400 Subject: [PATCH 823/830] Minus includes, context.error() everywhere --- src/network/protocols/command_manager.cpp | 174 ++++++++++------------ src/network/protocols/command_manager.hpp | 1 - 2 files changed, 78 insertions(+), 97 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index a173cb40881..cd6f2e4c33e 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -21,14 +21,10 @@ #include "addons/addon.hpp" #include "io/file_manager.hpp" #include "modes/soccer_world.hpp" -#include "network/database_connector.hpp" -#include "network/event.hpp" #include "network/game_setup.hpp" #include "network/network_player_profile.hpp" #include "network/protocols/server_lobby.hpp" -#include "network/server_config.hpp" #include "network/stk_host.hpp" -#include "network/stk_peer.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/chat_manager.hpp" @@ -39,7 +35,6 @@ #include "utils/hourglass_reason.hpp" #include "utils/kart_elimination.hpp" #include "utils/lobby_asset_manager.hpp" -#include "utils/lobby_context.hpp" #include "utils/lobby_gp_manager.hpp" #include "utils/lobby_settings.hpp" #include "utils/lobby_queues.hpp" @@ -51,14 +46,6 @@ #include "utils/tournament.hpp" #include "utils/version.hpp" -#include -#include -#include -#include -#include -#include -#include - // TODO: kimden: should decorators use acting_peer? namespace @@ -73,13 +60,14 @@ namespace static const std::string g_type_soccer = "soccer"; const std::vector g_queue_names = { - "", "mqueue", "mcyclic", "mboth", - "kqueue", "qregular", "", "", - "kcyclic", "", "qcyclic", "", - "kboth", "", "", "qboth" + "", "mqueue", "mcyclic", "mboth", + "kqueue", "qregular", "", "", + "kcyclic", "", "qcyclic", "", + "kboth", "", "", "qboth" }; - enum QueueMask: int { + enum QueueMask: int + { QM_NONE = -1, QM_MAP_ONETIME = 1, QM_MAP_CYCLIC = 2, @@ -809,13 +797,6 @@ void CommandManager::update() } // update // ======================================================================== -void CommandManager::error(Context& context, bool is_error) -{ - // When you have no time, change all error(context) calls to context.error() - context.error(is_error); -} // error -// ======================================================================== - void CommandManager::execute(std::shared_ptr command, Context& context) { m_current_argv = context.m_argv; @@ -827,7 +808,7 @@ void CommandManager::execute(std::shared_ptr command, Context& context) catch (std::exception& ex) { // auto peer = context.m_peer.lock(); - error(context, true); + context.error(true); // // kimden: make error message better + add log // context.say(StringUtils::insertValues( @@ -862,7 +843,7 @@ void CommandManager::process_help(Context& context) } if (command == m_root_command) { - error(context); + context.error(); return; } context.say(command->getHelp()); @@ -1100,7 +1081,7 @@ void CommandManager::process_spectate(Context& context) if (argv.size() < 2 || !StringUtils::fromString(argv[1], value) || value < 0 || value > 2) { - error(context); + context.error(); return; } if (value >= 1) @@ -1272,7 +1253,7 @@ void CommandManager::process_checkaddon(Context& context) if (argv.size() < 2) { - error(context); + context.error(); return; } if (!validate(context, 1, TFT_ADDON_MAPS, false, true)) @@ -1388,7 +1369,7 @@ void CommandManager::process_id(Context& context) if (argv.size() < 2) { - error(context); + context.error(); return; } if (!validate(context, 1, TFT_ALL_MAPS, false, true)) @@ -1416,7 +1397,7 @@ void CommandManager::process_lsa(Context& context) (argv.size() == 2 && (argv[1].size() < 3 || has_options)) || (argv.size() == 3 && (!has_options || argv[2].size() < 3))) { - error(context); + context.error(); return; } std::string type = ""; @@ -1480,7 +1461,7 @@ void CommandManager::process_pha(Context& context) auto& argv = context.m_argv; if (argv.size() < 3) { - error(context); + context.error(); return; } @@ -1497,7 +1478,7 @@ void CommandManager::process_pha(Context& context) StringUtils::utf8ToWide(player_name)); if (player_name.empty() || !player_peer || addon_id.empty()) { - error(context); + context.error(); return; } @@ -1534,7 +1515,7 @@ void CommandManager::process_kick(Context& context) auto acting_peer = context.actingPeerMaybeNull(); if (argv.size() < 2) { - error(context); + context.error(); return; } @@ -1547,7 +1528,7 @@ void CommandManager::process_kick(Context& context) StringUtils::utf8ToWide(player_name)); if (player_name.empty() || !player_peer || player_peer->isAIPeer()) { - error(context); + context.error(); return; } if (player_peer->hammerLevel() > 0) @@ -1584,13 +1565,13 @@ void CommandManager::process_unban(Context& context) if (argv.size() < 2) { - error(context); + context.error(); return; } std::string player_name = argv[1]; if (player_name.empty()) { - error(context); + context.error(); return; } Log::info("CommandManager", "%s is now unbanned", player_name.c_str()); @@ -1606,13 +1587,13 @@ void CommandManager::process_ban(Context& context) auto& argv = context.m_argv; if (argv.size() < 2) { - error(context); + context.error(); return; } player_name = argv[1]; if (player_name.empty()) { - error(context); + context.error(); return; } Log::info("CommandManager", "%s is now banned", player_name.c_str()); @@ -1634,7 +1615,7 @@ void CommandManager::process_pas(Context& context) if (acting_peer->getPlayerProfiles().empty()) { Log::warn("CommandManager", "pas: no existing player profiles??"); - error(context); + context.error(); return; } player_name = acting_peer->getMainName(); @@ -1649,7 +1630,7 @@ void CommandManager::process_pas(Context& context) StringUtils::utf8ToWide(player_name)); if (player_name.empty() || !player_peer) { - error(context); + context.error(); return; } auto& scores = player_peer->getAddonsScores(); @@ -1766,7 +1747,7 @@ void CommandManager::process_sha(Context& context) auto& argv = context.m_argv; if (argv.size() != 2) { - error(context); + context.error(); return; } std::set total_addons; @@ -1797,7 +1778,7 @@ void CommandManager::process_mute(Context& context) if (argv.size() != 2 || argv[1].empty()) { - error(context); + context.error(); return; } @@ -1819,7 +1800,7 @@ void CommandManager::process_unmute(Context& context) if (argv.size() != 2 || argv[1].empty()) { - error(context); + context.error(); return; } @@ -1933,7 +1914,7 @@ void CommandManager::process_tell(Context& context) if (argv.size() == 1) { - error(context); + context.error(); return; } std::string ans; @@ -2003,7 +1984,7 @@ void CommandManager::process_to(Context& context) if (argv.size() == 1) { - error(context); + context.error(); return; } std::vector receivers; @@ -2035,7 +2016,7 @@ void CommandManager::process_record(Context& context) #ifdef ENABLE_SQLITE3 if (argv.size() < 5) { - error(context); + context.error(); return; } bool error = false; @@ -2122,7 +2103,7 @@ void CommandManager::process_length_multi(Context& context) if (argv.size() < 3 || !StringUtils::parseString(argv[2], &temp_double)) { - error(context); + context.error(); return; } double value = std::max(0.0, temp_double); @@ -2138,7 +2119,7 @@ void CommandManager::process_length_fixed(Context& context) if (argv.size() < 3 || !StringUtils::parseString(argv[2], &temp_int)) { - error(context); + context.error(); return; } int value = std::max(0, temp_int); @@ -2165,13 +2146,13 @@ void CommandManager::process_direction_assign(Context& context) auto& argv = context.m_argv; if (argv.size() < 2) { - error(context); + context.error(); return; } int temp_int = -1; if (!StringUtils::parseString(argv[1], &temp_int) || !getSettings()->setDirection(temp_int)) { - error(context); + context.error(); return; } Comm::sendStringToAllPeers(getSettings()->getDirectionAsString(true)); @@ -2207,7 +2188,7 @@ void CommandManager::process_queue_push(Context& context) if (argv.size() < 3) { - error(context); + context.error(); return; } int mask = get_queue_mask(argv[0]); @@ -2425,7 +2406,7 @@ void CommandManager::process_allowstart_assign(Context& context) // because of an extra cast. if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) { - error(context); + context.error(); return; } getSettings()->setAllowedToStart(argv[1] != "0"); @@ -2445,7 +2426,7 @@ void CommandManager::process_shuffle_assign(Context& context) // Move validation to lobby settings. if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) { - error(context); + context.error(); return; } getSettings()->setGPGridShuffled(argv[1] != "0"); @@ -2459,7 +2440,7 @@ void CommandManager::process_timeout(Context& context) auto& argv = context.m_argv; if (argv.size() < 2 || !StringUtils::parseString(argv[1], &seconds) || seconds <= 0) { - error(context); + context.error(); return; } getLobby()->setTimeoutFromNow(seconds); @@ -2474,7 +2455,7 @@ void CommandManager::process_team(Context& context) auto& argv = context.m_argv; if (argv.size() != 3) { - error(context); + context.error(); return; } if (!validate(context, 2, TFT_PRESENT_USERS, false, true)) @@ -2508,7 +2489,7 @@ void CommandManager::process_swapteams(Context& context) if (argv.size() != 2) { - error(context); + context.error(); return; } // todo move list of teams and checking teams to another unit later, @@ -2600,12 +2581,13 @@ void CommandManager::process_randomteams(Context& context) void CommandManager::process_resetgp(Context& context) { auto& argv = context.m_argv; - if (argv.size() >= 2) { + if (argv.size() >= 2) + { int number_of_games; if (!StringUtils::parseString(argv[1], &number_of_games) || number_of_games <= 0) { - error(context); + context.error(); return; } getGameSetupFromCtx()->setGrandPrixTrack(number_of_games); @@ -2624,7 +2606,7 @@ void CommandManager::process_cat(Context& context) { if (argv.size() != 3) { - error(context); + context.error(); return; } std::string category = argv[1]; @@ -2639,7 +2621,7 @@ void CommandManager::process_cat(Context& context) { if (argv.size() != 3) { - error(context); + context.error(); return; } std::string category = argv[1]; @@ -2660,7 +2642,7 @@ void CommandManager::process_cat(Context& context) if (argv.size() != 3 || !StringUtils::parseString(argv[2], &displayed) || displayed < -1 || displayed > 1) { - error(context); + context.error(); return; } } @@ -2681,7 +2663,7 @@ void CommandManager::process_vip(Context& context) { if (argv.size() > 2) { - error(context); + context.error(); return; } if (argv.size() == 2) @@ -2701,7 +2683,7 @@ void CommandManager::process_vip(Context& context) { if (argv.size() != 2) { - error(context); + context.error(); return; } if (!validate(context, 1, TFT_PRESENT_USERS, false, true)) @@ -2718,7 +2700,7 @@ void CommandManager::process_vip(Context& context) { if (argv.size() != 2) { - error(context); + context.error(); return; } if (!validate(context, 1, TFT_PRESENT_USERS, false, true)) @@ -2753,7 +2735,7 @@ void CommandManager::process_troll_assign(Context& context) auto& argv = context.m_argv; if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) { - error(context); + context.error(); return; } auto hit_processor = getHitProcessor(); @@ -2788,7 +2770,7 @@ void CommandManager::process_hitmsg_assign(Context& context) auto& argv = context.m_argv; if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) { - error(context); + context.error(); return; } auto hit_processor = getHitProcessor(); @@ -2823,7 +2805,7 @@ void CommandManager::process_teamhit_assign(Context& context) auto& argv = context.m_argv; if (argv.size() == 1 || !(argv[1] == "0" || argv[1] == "1")) { - error(context); + context.error(); return; } auto hit_processor = getHitProcessor(); @@ -2896,7 +2878,7 @@ void CommandManager::process_muteall(Context& context) auto tournament = getTournament(); if (!tournament) { - error(context, true); + context.error(true); return; } if (!acting_peer->hasPlayerProfiles()) @@ -2926,7 +2908,7 @@ void CommandManager::process_game(Context& context) auto tournament = getTournament(); if (!tournament) { - error(context, true); + context.error(true); return; } @@ -3001,12 +2983,12 @@ void CommandManager::process_role(Context& context) auto tournament = getTournament(); if (!tournament) { - error(context, true); + context.error(true); return; } if (argv.size() < 3) { - error(context); + context.error(); return; } if (argv[1].length() > argv[2].length()) @@ -3021,7 +3003,7 @@ void CommandManager::process_role(Context& context) (argv[3] == "p" || argv[3] == "permanent")); if (role.length() != 1) { - error(context); + context.error(); return; } char role_char = role[0]; @@ -3142,7 +3124,7 @@ void CommandManager::process_stop(Context& context) { if (!getTournament()) { - error(context, true); + context.error(true); return; } World* w = World::getWorld(); @@ -3159,7 +3141,7 @@ void CommandManager::process_go(Context& context) { if (!getTournament()) { - error(context, true); + context.error(true); return; } World* w = World::getWorld(); @@ -3176,7 +3158,7 @@ void CommandManager::process_lobby(Context& context) { if (!getTournament()) { - error(context, true); + context.error(true); return; } World* w = World::getWorld(); @@ -3193,7 +3175,7 @@ void CommandManager::process_init(Context& context) auto& argv = context.m_argv; if (!getTournament()) { - error(context, true); + context.error(true); return; } int red, blue; @@ -3201,7 +3183,7 @@ void CommandManager::process_init(Context& context) !StringUtils::parseString(argv[1], &red) || !StringUtils::parseString(argv[2], &blue)) { - error(context); + context.error(); return; } World* w = World::getWorld(); @@ -3243,7 +3225,7 @@ void CommandManager::process_test(Context& context) argv.resize(4, ""); if (argv[2] == "no" && argv[3] == "u") { - error(context); + context.error(); return; } if (context.m_voting) @@ -3287,7 +3269,7 @@ void CommandManager::process_slots_assign(Context& context) fail = true; if (fail) { - error(context); + context.error(); return; } if (context.m_voting) @@ -3348,7 +3330,7 @@ void CommandManager::process_preserve_assign(Context& context) std::string msg = ""; if (argv.size() != 3) { - error(context); + context.error(); return; } if (argv[2] == "0") @@ -3372,7 +3354,7 @@ void CommandManager::process_history(Context& context) auto tournament = getTournament(); if (!tournament) { - error(context, true); + context.error(true); return; } std::string msg = "Map history:"; @@ -3389,19 +3371,19 @@ void CommandManager::process_history_assign(Context& context) auto tournament = getTournament(); if (!tournament) { - error(context, true); + context.error(true); return; } std::string msg = ""; if (argv.size() != 3) { - error(context); + context.error(); return; } int index; if (!StringUtils::fromString(argv[1], index) || index < 0) { - error(context); + context.error(); return; } if (!validate(context, 2, TFT_ALL_MAPS, false, false)) @@ -3409,7 +3391,7 @@ void CommandManager::process_history_assign(Context& context) std::string id = argv[2]; if (!tournament->assignToHistory(index, id)) { - error(context); + context.error(); return; } @@ -3432,13 +3414,13 @@ void CommandManager::process_voting_assign(Context& context) std::string msg = ""; if (argv.size() < 2) { - error(context); + context.error(); return; } int value; if (!StringUtils::fromString(argv[1], value) || value < 0 || value > 1) { - error(context); + context.error(); return; } getMapVoteHandler()->setAlgorithm(value); @@ -3459,7 +3441,7 @@ void CommandManager::process_why_hourglass(Context& context) if (acting_peer->getPlayerProfiles().empty()) { Log::warn("CommandManager", "whyhourglass: no existing player profiles??"); - error(context); + context.error(); return; } player_name = acting_peer->getMainName(); @@ -3474,7 +3456,7 @@ void CommandManager::process_why_hourglass(Context& context) StringUtils::utf8ToWide(player_name)); if (player_name.empty() || !player_peer) { - error(context); + context.error(); return; } @@ -3501,7 +3483,7 @@ void CommandManager::process_available_teams_assign(Context& context) if (argv.size() < 2) { - error(context); + context.error(); return; } std::string value = ""; @@ -3552,14 +3534,14 @@ void CommandManager::process_cooldown_assign(Context& context) if (argv.size() < 2) { - error(context); + context.error(); return; } int new_cooldown = -1; // kimden: figure out what's with epsilons in STK if (!StringUtils::parseString(argv[1], &new_cooldown) || new_cooldown < 0) { - error(context); + context.error(); return; } getSettings()->setLobbyCooldown(new_cooldown); @@ -3589,7 +3571,7 @@ void CommandManager::process_net(Context& context) if (acting_peer->getPlayerProfiles().empty()) { Log::warn("CommandManager", "net: no existing player profiles??"); - error(context); + context.error(); return; } player_name = acting_peer->getMainName(); @@ -3604,7 +3586,7 @@ void CommandManager::process_net(Context& context) StringUtils::utf8ToWide(player_name)); if (player_name.empty() || !player_peer) { - error(context); + context.error(); return; } @@ -3678,7 +3660,7 @@ void CommandManager::process_temp250318(Context& context) int value = 0; if (argv.size() < 2 || !StringUtils::parseString(argv[1], &value)) { - error(context); + context.error(); return; } auto settings = getSettings(); diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 2706d4d22f7..410204ab530 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -119,7 +119,6 @@ class CommandManager: public LobbyContextComponent void vote(Context& context, std::string category, std::string value); void update(); - void error(Context& context, bool is_error = false); void execute(std::shared_ptr command, Context& context); From e0ae06d5b6c6dbdc979c9d8f0fff5e0f71a20607 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 29 Aug 2025 03:13:56 +0400 Subject: [PATCH 824/830] Minor queue command improvements (not all of them) --- src/network/protocols/command_manager.cpp | 216 +++++++++++----------- 1 file changed, 109 insertions(+), 107 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index cd6f2e4c33e..62bd40ff0f5 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -86,7 +86,7 @@ namespace return i; return QueueMask::QM_NONE; } // get_queue_mask - // ==================================================================== + //------------------------------------------------------------------------- std::string get_queue_name(int x) { @@ -101,7 +101,7 @@ namespace return StringUtils::insertValues( "[Error QN%d: please report with /tell about it] queue", x); } // get_queue_name - // ==================================================================== + //------------------------------------------------------------------------- int another_cyclic_queue(int x) { @@ -111,7 +111,18 @@ namespace // return QM_KART_CYCLIC; return QM_NONE; } // another_cyclic_queue - // ==================================================================== + //------------------------------------------------------------------------- + + template + void forAllQueuesInMask(int mask, Fn&& fn) + { + for (int x = QM_START; x < QM_END; x <<= 1) + { + if (mask & x) + fn(x); + } + } // forAllQueuesInMask + //------------------------------------------------------------------------- void restoreCmdByArgv(std::string& cmd, std::vector& argv, char c, char d, char e, char f, @@ -120,7 +131,7 @@ namespace cmd = StringUtils::quoteEscapeArray(argv.begin() + from, argv.end(), c, d, e, f); } // restoreCmdByArgv - // ======================================================================== + //------------------------------------------------------------------------- // Auxiliary things, should be moved somewhere because they just help @@ -211,7 +222,8 @@ void CommandManager::initCommandsInfo() const std::string name = c->getShortName(); - if (current == root2 && command == m_root_command && used_commands.find(name) != used_commands.end()) + if (current == root2 && command == m_root_command + && used_commands.find(name) != used_commands.end()) continue; else if (current == root) used_commands.insert(name); @@ -222,9 +234,11 @@ void CommandManager::initCommandsInfo() dfs(node, c); } }; + dfs(root, m_root_command); if (root2) dfs(root2, m_root_command); + delete root; delete root2; } // initCommandsInfo @@ -2163,18 +2177,19 @@ void CommandManager::process_queue(Context& context) { std::string msg = ""; int mask = get_queue_mask(context.m_argv[0]); - for (int x = QM_START; x < QM_END; x <<= 1) + + forAllQueuesInMask(mask, [&](int x) { - if (mask & x) - { - auto& queue = get_queue(x); - msg += StringUtils::insertValues("%s (size = %d):", - get_queue_name(x), (int)queue.size()); - for (std::shared_ptr& s: queue) - msg += " " + s->toString(); - msg += "\n"; - } - } + auto& queue = get_queue(x); + + msg += StringUtils::insertValues("%s (size = %d):", + get_queue_name(x), (int)queue.size()); + + for (std::shared_ptr& s: queue) + msg += " " + s->toString(); + msg += "\n"; + }); + msg.pop_back(); context.say(msg); } // process_queue @@ -2242,31 +2257,23 @@ void CommandManager::process_queue_push(Context& context) std::string msg = ""; - for (int x = QM_START; x < QM_END; x <<= 1) + forAllQueuesInMask(mask, [&](int x) { - if (mask & x) - { - if (mask & QM_ALL_KART_QUEUES) - { - // TODO Make sure to update the next branch too; unite them somehow? - add_to_queue(x, mask, to_front, filter_text); - } - else - { - // TODO Make sure to update the previous branch too; unite them somehow? - add_to_queue(x, mask, to_front, filter_text); - } + // TODO: Make sure to update both branches if at all + if (mask & QM_ALL_KART_QUEUES) + add_to_queue(x, mask, to_front, filter_text); + else + add_to_queue(x, mask, to_front, filter_text); - msg += StringUtils::insertValues( - "Pushed { %s } to the %s of %s, current queue size: %d", - filter_text.c_str(), - (to_front ? "front" : "back"), - get_queue_name(x).c_str(), - get_queue(x).size() - ); - msg += "\n"; - } - } + msg += StringUtils::insertValues( + "Pushed { %s } to the %s of %s, current queue size: %d", + filter_text.c_str(), + (to_front ? "front" : "back"), + get_queue_name(x).c_str(), + get_queue(x).size() + ); + msg += "\n"; + }); msg.pop_back(); Comm::sendStringToAllPeers(msg); @@ -2282,42 +2289,41 @@ void CommandManager::process_queue_pop(Context& context) int mask = get_queue_mask(argv[0]); bool from_back = (argv[1] == "pop_back"); - for (int x = QM_START; x < QM_END; x <<= 1) + forAllQueuesInMask(mask, [&](int x) { - if (mask & x) + int another = another_cyclic_queue(x); + + if (get_queue(x).empty()) { - int another = another_cyclic_queue(x); - if (get_queue(x).empty()) { - msg += "The " + get_queue_name(x) + " was empty before.\n"; - } - else - { - auto object = (from_back ? get_queue(x).back() : get_queue(x).front()); - msg += "Popped " + object->toString() - + " from the " + (from_back ? "back" : "front") + " of the " - + get_queue_name(x) + ","; - if (from_back) - { - get_queue(x).pop_back(); - } - else - { - get_queue(x).pop_front(); - } - if (another >= QM_START && !(mask & another)) - { - // here you have to pop from FRONT and not back because it - // was pushed to the front - see process_queue_push - auto& q = get_queue(another); - if (!q.empty() && q.front()->isPlaceholder()) - q.pop_front(); - } - msg += " current queue size: " - + std::to_string(get_queue(x).size()); - msg += "\n"; - } + msg += StringUtils::insertValues( + "The %s was empty before.\n", get_queue_name(x).c_str()); + return; } - } + + auto object = (from_back ? get_queue(x).back() : get_queue(x).front()); + msg += StringUtils::insertValues("Popped %s from the %s of the %s,", + object->toString().c_str(), + (from_back ? "back" : "front"), + get_queue_name(x).c_str() + ); + + if (from_back) + get_queue(x).pop_back(); + else + get_queue(x).pop_front(); + + if (another >= QM_START && !(mask & another)) + { + // here you have to pop from FRONT and not back because it + // was pushed to the front - see process_queue_push + auto& q = get_queue(another); + if (!q.empty() && q.front()->isPlaceholder()) + q.pop_front(); + } + msg += StringUtils::insertValues(" current queue size: %s\n", + get_queue(x).size()); + }); + msg.pop_back(); Comm::sendStringToAllPeers(msg); getLobby()->updatePlayerList(); @@ -2328,24 +2334,22 @@ void CommandManager::process_queue_clear(Context& context) { int mask = get_queue_mask(context.m_argv[0]); std::string msg = ""; - for (int x = QM_START; x < QM_END; x <<= 1) + forAllQueuesInMask(mask, [&](int x) { - if (mask & x) - { - int another = another_cyclic_queue(x); - msg += StringUtils::insertValues( - "The " + get_queue_name(x) + " is now empty (previous size: %d)", - (int)get_queue(x).size()) + "\n"; - get_queue(x).clear(); + int another = another_cyclic_queue(x); - if (another >= QM_START && !(mask & another)) - { - auto& q = get_queue(another); - while (!q.empty() && q.front()->isPlaceholder()) - q.pop_front(); - } + msg += StringUtils::insertValues( + "The " + get_queue_name(x) + " is now empty (previous size: %d)", + (int)get_queue(x).size()) + "\n"; + get_queue(x).clear(); + + if (another >= QM_START && !(mask & another)) + { + auto& q = get_queue(another); + while (!q.empty() && q.front()->isPlaceholder()) + q.pop_front(); } - } + }); msg.pop_back(); Comm::sendStringToAllPeers(msg); getLobby()->updatePlayerList(); @@ -2364,28 +2368,26 @@ void CommandManager::process_queue_shuffle(Context& context) // we don't have to do anything with placeholders for the corresponding // cyclic queue, BUT we have to not shuffle the placeholders in the // current queue itself - for (int x = QM_START; x < QM_END; x <<= 1) - { - if (mask & x) + forAllQueuesInMask(mask, [&](int x) + { + auto& queue = get_queue(x); + // As the placeholders can be only at the start of a queue, + // let's just do a binary search - in case there are many placeholders + int L = -1; + int R = queue.size(); + int mid; + while (R - L > 1) { - auto& queue = get_queue(x); - // As the placeholders can be only at the start of a queue, - // let's just do a binary search - in case there are many placeholders - int L = -1; - int R = queue.size(); - int mid; - while (R - L > 1) - { - mid = (L + R) / 2; - if (queue[mid]->isPlaceholder()) - L = mid; - else - R = mid; - } - std::shuffle(queue.begin() + R, queue.end(), g); - msg += "The " + get_queue_name(x) + " is now shuffled\n"; + mid = (L + R) / 2; + if (queue[mid]->isPlaceholder()) + L = mid; + else + R = mid; } - } + std::shuffle(queue.begin() + R, queue.end(), g); + msg += "The " + get_queue_name(x) + " is now shuffled\n"; + }); + msg.pop_back(); Comm::sendStringToAllPeers(msg); getLobby()->updatePlayerList(); From af4ae1a4cd1fa3ff403c885e41ac14891ab4bbe8 Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Sat, 30 Aug 2025 03:35:19 +0400 Subject: [PATCH 825/830] Move restoreCmdFromArgv to StringUtils I'll make a structure for chars later, as well as bigger changes that I planned to do but didn't want to confuse them together --- src/network/protocols/command_manager.cpp | 28 +++++++++++++---------- src/utils/lobby_queues.hpp | 3 --- src/utils/string_utils.cpp | 14 ++++++++++-- src/utils/string_utils.hpp | 8 +++++-- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index 62bd40ff0f5..d494d235a2a 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -124,13 +124,13 @@ namespace } // forAllQueuesInMask //------------------------------------------------------------------------- - void restoreCmdByArgv(std::string& cmd, + void restoreCmdFromArgv(std::string& cmd, std::vector& argv, char c, char d, char e, char f, int from = 0) { cmd = StringUtils::quoteEscapeArray(argv.begin() + from, argv.end(), c, d, e, f); - } // restoreCmdByArgv + } // restoreCmdFromArgv //------------------------------------------------------------------------- @@ -531,7 +531,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); if (argv.empty()) return; - restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + StringUtils::restoreCmdFromArgv(cmd, argv, ' ', '"', '"', '\\'); permissions = getLobby()->getPermissions(peer); voting = false; @@ -554,7 +554,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) argv = StringUtils::splitQuoted(cmd, ' ', '"', '"', '\\'); if (argv.empty()) return; - restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + StringUtils::restoreCmdFromArgv(cmd, argv, ' ', '"', '"', '\\'); voting = m_user_saved_voting[username]; target_peer = m_user_saved_acting_peer[username]; target_peer_strong = target_peer.lock(); @@ -728,7 +728,7 @@ void CommandManager::handleCommand(Event* event, std::shared_ptr peer) { std::string new_cmd = p.first + " " + p.second; auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '"', '\\'); - restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); + StringUtils::restoreCmdFromArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); std::string msg2 = StringUtils::insertValues( "Command \"/%s\" has been successfully voted", new_cmd.c_str()); @@ -789,7 +789,7 @@ void CommandManager::update() { std::string new_cmd = p.first + " " + p.second; auto new_argv = StringUtils::splitQuoted(new_cmd, ' ', '"', '"', '\\'); - restoreCmdByArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); + StringUtils::restoreCmdFromArgv(new_cmd, new_argv, ' ', '"', '"', '\\'); std::string msg = StringUtils::insertValues( "Command \"/%s\" has been successfully voted", new_cmd.c_str()); @@ -2216,7 +2216,7 @@ void CommandManager::process_queue_push(Context& context) argv[2] = asset_manager->getRandomAddonMap(); std::string filter_text = ""; - restoreCmdByArgv(filter_text, argv, ' ', '"', '"', '\\', 2); + restoreCmdFromArgv(filter_text, argv, ' ', '"', '"', '\\', 2); // Fix typos only if track queues are used (majority of cases anyway) // TODO: I don't know how to fix typos for both karts and tracks @@ -2837,7 +2837,7 @@ void CommandManager::process_scoring_assign(Context& context) auto& argv = context.m_argv; std::string cmd2; - restoreCmdByArgv(cmd2, argv, ' ', '"', '"', '\\', 1); + StringUtils::restoreCmdFromArgv(cmd2, argv, ' ', '"', '"', '\\', 1); if (getGPManager()->trySettingGPScoring(cmd2)) Comm::sendStringToAllPeers("Scoring set to \"" + cmd2 + "\""); else @@ -3734,13 +3734,16 @@ bool CommandManager::hasTypo(std::shared_ptr acting_peer, std::shared_p { if (!acting_peer.get()) // voted return false; + std::string username = ""; if (peer->hasPlayerProfiles()) username = peer->getMainName(); + auto it = m_user_last_correct_argument.find(username); if (it != m_user_last_correct_argument.end() && std::make_pair(idx, subidx) <= it->second) return false; + std::string text = argv[idx]; std::string prefix = ""; std::string suffix = ""; @@ -3750,6 +3753,7 @@ bool CommandManager::hasTypo(std::shared_ptr acting_peer, std::shared_p suffix = text.substr(substr_r); text = text.substr(substr_l, substr_r - substr_l); } + auto closest_commands = stf.getClosest(text, top, case_sensitive); if (closest_commands.empty()) { @@ -3786,12 +3790,12 @@ bool CommandManager::hasTypo(std::shared_ptr acting_peer, std::shared_p } for (unsigned i = 0; i < closest_commands.size(); ++i) { argv[idx] = prefix + closest_commands[i].first + suffix; - restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + StringUtils::restoreCmdFromArgv(cmd, argv, ' ', '"', '"', '\\'); m_user_command_replacements[username].push_back(cmd); response += "\ntype /" + std::to_string(i + 1) + " to choose \"" + closest_commands[i].first + "\""; } argv[idx] = initial_argument; - restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + StringUtils::restoreCmdFromArgv(cmd, argv, ' ', '"', '"', '\\'); Comm::sendStringToPeer(peer, response); return true; } @@ -3799,7 +3803,7 @@ bool CommandManager::hasTypo(std::shared_ptr acting_peer, std::shared_p if (!dont_replace) { argv[idx] = prefix + closest_commands[0].first + suffix; // converts case or regex - restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + StringUtils::restoreCmdFromArgv(cmd, argv, ' ', '"', '"', '\\'); } return false; } // hasTypo @@ -3891,7 +3895,7 @@ void CommandManager::shift(std::string& cmd, std::vector& argv, m_user_last_correct_argument[username].first -= count; - restoreCmdByArgv(cmd, argv, ' ', '"', '"', '\\'); + StringUtils::restoreCmdFromArgv(cmd, argv, ' ', '"', '"', '\\'); } // shift //----------------------------------------------------------------------------- diff --git a/src/utils/lobby_queues.hpp b/src/utils/lobby_queues.hpp index 7b88d2ba05f..dc94fb34ac1 100644 --- a/src/utils/lobby_queues.hpp +++ b/src/utils/lobby_queues.hpp @@ -49,11 +49,8 @@ class LobbyQueues: public LobbyContextComponent private: Queue m_onetime_tracks_queue; - Queue m_cyclic_tracks_queue; - Queue m_onetime_karts_queue; - Queue m_cyclic_karts_queue; // Temporary reference getters diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp index efb811a0f52..175cb6182b1 100644 --- a/src/utils/string_utils.cpp +++ b/src/utils/string_utils.cpp @@ -256,8 +256,8 @@ namespace StringUtils } // quoteEscape - std::string quoteEscapeArray(const std::vector::iterator begin, - const std::vector::iterator end, + std::string quoteEscapeArray(const std::vector::const_iterator begin, + const std::vector::const_iterator end, char c, char d, char e, char f) { std::string res = ""; @@ -271,6 +271,16 @@ namespace StringUtils return res; } // quoteEscapeArray //------------------------------------------------------------------------- + + void restoreCmdFromArgv(std::string& cmd, + const std::vector& argv, + char c, char d, char e, char f, + int from) + { + cmd = quoteEscapeArray(argv.begin() + from, argv.end(), c, d, e, f); + } // restoreCmdFromArgv + //------------------------------------------------------------------------- + /** Splits a string into substrings separated by a certain character, and * returns a std::vector of all those substring. E.g.: * split("a b=c d=e",' ') --> ["a", "b=c", "d=e"] diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index c6f824d8ccb..8d5eb791629 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -58,9 +58,13 @@ namespace StringUtils char d, char e, char f); std::string quoteEscape(const std::string& s, char c, char d, char e, char f); - std::string quoteEscapeArray(const std::vector::iterator begin, - const std::vector::iterator end, + std::string quoteEscapeArray(const std::vector::const_iterator begin, + const std::vector::const_iterator end, char c, char d, char e, char f); + void restoreCmdFromArgv(std::string& cmd, + const std::vector& argv, + char c, char d, char e, char f, + int from = 0); std::vector split(const std::string& s, char c, bool keepSplitChar=false); std::vector split(const std::u32string& s, char32_t c, From 1c428113d83107655cbc013adb3bba92435bc88e Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 5 Sep 2025 22:29:56 +0400 Subject: [PATCH 826/830] Revert having fixed stun server list --- src/network/stk_host.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index a4406d4ee9a..b51848b8366 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -654,8 +654,8 @@ void STKHost::setPublicAddress(short family) stunv6_map[s.first] = 0; } - auto& stun_map = family == AF_INET ? UserConfigParams::m_stun_servers_v4 : - UserConfigParams::m_stun_servers; + auto& stun_map = family == AF_INET ? stunv4_map : + stunv6_map; std::vector > untried_server; for (auto& p : stun_map) untried_server.push_back(p); From 4940952ee63d82428b00b382dfaf950228bd8ebf Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 17 Sep 2025 21:19:29 +0400 Subject: [PATCH 827/830] Initial commit on public values For now they are not refreshing themselves. On player list update it refreshes, and on command usage it updates the file itself (like it was before), but doesn't refresh on the screen. Likely will be done, but later. --- src/network/protocols/server_lobby.cpp | 6 +++ .../command_manager/map_file_resource.cpp | 30 ++++++++++- .../command_manager/map_file_resource.hpp | 2 + src/utils/public_player_value.cpp | 21 ++++++++ src/utils/public_player_value.hpp | 48 +++++++++++++++++ src/utils/public_player_value_storage.cpp | 54 +++++++++++++++++++ src/utils/public_player_value_storage.hpp | 41 ++++++++++++++ 7 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 src/utils/public_player_value.cpp create mode 100644 src/utils/public_player_value.hpp create mode 100644 src/utils/public_player_value_storage.cpp create mode 100644 src/utils/public_player_value_storage.hpp diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index ff36ea5cd44..29034af3b8f 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -61,6 +61,7 @@ #include "utils/lobby_queues.hpp" #include "utils/map_vote_handler.hpp" #include "utils/name_decorators/generic_decorator.hpp" +#include "utils/public_player_value_storage.hpp" #include "utils/team_manager.hpp" #include "utils/tournament.hpp" #include "utils/translation.hpp" @@ -2911,6 +2912,11 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server) prefix = TeamUtils::getTeamByIndex(team).getEmoji() + " " + prefix; } + PublicPlayerValueStorage::tryUpdate(); + std::string public_values = PublicPlayerValueStorage::get(utf8_profile_name); + if (!public_values.empty()) + prefix = "{" + public_values + "} " + prefix; + profile_name = StringUtils::utf8ToWide(prefix) + profile_name; packet.host_id = profile->getHostId(); diff --git a/src/utils/command_manager/map_file_resource.cpp b/src/utils/command_manager/map_file_resource.cpp index 9fc5f1eccd8..ef2d4848f30 100644 --- a/src/utils/command_manager/map_file_resource.cpp +++ b/src/utils/command_manager/map_file_resource.cpp @@ -19,6 +19,8 @@ #include "utils/command_manager/map_file_resource.hpp" #include "utils/string_utils.hpp" +#include "utils/public_player_value_storage.hpp" +#include namespace { @@ -53,7 +55,33 @@ void MapFileResource::fromXmlNode(const XMLNode* node) readChar(node, "right-quote", &m_right_quote); readChar(node, "escape", &m_escape); node->get("index", &m_index); -} // MapFileResource + node->get("public", &m_public); + if (m_public >= 0) + { + PublicPlayerValueStorage::add( + std::make_shared( + [this](const std::string& name) -> std::optional { + auto it = m_indexed.find(name); + if (it == m_indexed.end() || it->second.empty()) + return std::nullopt; + + // We don't care about non-first rows for now. + auto& vec = it->second[0]->cells; + if (m_public >= (int)vec.size()) + return std::nullopt; + + return { vec[m_public] }; + }, + [this]() { + tryUpdate(); + } + ) + ); + + // We usually don't call it immediately, but if we have it published, we have to call + tryUpdate(); + } +} // fromXmlNode //----------------------------------------------------------------------------- void MapFileResource::onContentChange() diff --git a/src/utils/command_manager/map_file_resource.hpp b/src/utils/command_manager/map_file_resource.hpp index e68088df710..2b9ac4bd492 100644 --- a/src/utils/command_manager/map_file_resource.hpp +++ b/src/utils/command_manager/map_file_resource.hpp @@ -40,6 +40,8 @@ struct MapFileResource: public FileResource // Except the lack of practical need, of course. int m_index = 0; + int m_public = -1; + struct Row { std::vector cells; diff --git a/src/utils/public_player_value.cpp b/src/utils/public_player_value.cpp new file mode 100644 index 00000000000..0313dd420ef --- /dev/null +++ b/src/utils/public_player_value.cpp @@ -0,0 +1,21 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2018 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/public_player_value.hpp" + +// Nothing for now \ No newline at end of file diff --git a/src/utils/public_player_value.hpp b/src/utils/public_player_value.hpp new file mode 100644 index 00000000000..cf24ffa4a54 --- /dev/null +++ b/src/utils/public_player_value.hpp @@ -0,0 +1,48 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2018 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef PUBLIC_PLAYER_VALUE_HPP +#define PUBLIC_PLAYER_VALUE_HPP + +#include +#include +#include + +/** + * A class that allows to show various (currently file-based) stats for players. + */ +class PublicPlayerValue +{ + using Handler = std::function(const std::string&)>; + using Updater = std::function; +private: + Handler m_method; + Updater m_updater; + +public: + PublicPlayerValue(Handler method, Updater updater) + : m_method(method), m_updater(updater) + {} + + std::optional get(const std::string& player_name) const + { return m_method(player_name); } + + void tryUpdate() const { m_updater(); } +}; + +#endif // PUBLIC_PLAYER_VALUE_HPP \ No newline at end of file diff --git a/src/utils/public_player_value_storage.cpp b/src/utils/public_player_value_storage.cpp new file mode 100644 index 00000000000..d317d0735e9 --- /dev/null +++ b/src/utils/public_player_value_storage.cpp @@ -0,0 +1,54 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2018 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "utils/public_player_value_storage.hpp" + +std::vector> PublicPlayerValueStorage::values = {}; + +// Currently supported only for players with account, +// however, currently we'll show it for local accounts too +// if they have a corresponding name. +std::string PublicPlayerValueStorage::get(const std::string& player_name) +{ + // might add caching later + + std::string res; + for (const auto& ppv: values) + { + const auto item = ppv->get(player_name); + if (!item.has_value()) + continue; + + std::string value = item.value(); + if (!value.empty()) + { + if (!res.empty()) + res += ", "; + res += value; + } + } + return res; +} // get +//----------------------------------------------------------------------------- + +void PublicPlayerValueStorage::tryUpdate() +{ + for (const auto& ppv: values) + ppv->tryUpdate(); +} // tryUpdate +//----------------------------------------------------------------------------- \ No newline at end of file diff --git a/src/utils/public_player_value_storage.hpp b/src/utils/public_player_value_storage.hpp new file mode 100644 index 00000000000..2f1c9e26b53 --- /dev/null +++ b/src/utils/public_player_value_storage.hpp @@ -0,0 +1,41 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2018 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef PUBLIC_PLAYER_VALUE_STORAGE_HPP +#define PUBLIC_PLAYER_VALUE_STORAGE_HPP + +#include +#include +#include +#include "utils/public_player_value.hpp" + +class PublicPlayerValueStorage +{ + static std::vector> values; + +public: + static void add(const std::shared_ptr& value) + { + values.push_back(value); + } + + static std::string get(const std::string& player_name); + static void tryUpdate(); +}; + +#endif // PUBLIC_PLAYER_VALUE_STORAGE_HPP From 00f167b25a5bf1742dda31d1b150ae0edf4e3faf Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Wed, 17 Sep 2025 21:43:41 +0400 Subject: [PATCH 828/830] Make /MapFileResource bigNumber show all entries, remove division by zero --- .../command_manager/map_file_resource.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/utils/command_manager/map_file_resource.cpp b/src/utils/command_manager/map_file_resource.cpp index ef2d4848f30..bd2482e7889 100644 --- a/src/utils/command_manager/map_file_resource.cpp +++ b/src/utils/command_manager/map_file_resource.cpp @@ -128,6 +128,15 @@ void MapFileResource::execute(Context& context) std::string msg = ""; + int n = m_indexed.size(); + if (n == 0) + { + // Might be bad to say it without even reading arguments, + // but for now I guess it's fine + context.say("Nothing found"); + return; + } + // I'm not sure if we should search by username. // After all, the search column might contain something else. if (argv[1] == "search") @@ -170,8 +179,16 @@ void MapFileResource::execute(Context& context) context.error(); return; } + + // Happily n is not zero if (!has_to) + { to = (from > 0 ? 1 : -1); + if (from > 0) + from = std::min(from, n); + else + from = std::max(from, -n); + } if (from >= to) std::swap(from, to); @@ -182,7 +199,7 @@ void MapFileResource::execute(Context& context) ++to; // else nothing: -4 5 -> [-4, 5) - int n = m_indexed.size(); + // Happily n is not zero int shift = (from / n) * n + (from < 0 ? -n : 0); from -= shift; to -= shift; From 3c03b89676c6a937fc3f537224683974f9301b4e Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Mon, 8 Dec 2025 03:31:48 +0400 Subject: [PATCH 829/830] Avoid throwing when saying to nullptr peer for some voted commands --- src/network/protocols/command_manager.cpp | 8 +++++--- src/utils/command_manager/context.cpp | 4 ++-- src/utils/command_manager/context.hpp | 4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/network/protocols/command_manager.cpp b/src/network/protocols/command_manager.cpp index d494d235a2a..203c7499c85 100644 --- a/src/network/protocols/command_manager.cpp +++ b/src/network/protocols/command_manager.cpp @@ -1568,7 +1568,8 @@ void CommandManager::process_kick(Context& context) Log::info("CommandManager", "%s is now banned", player_name.c_str()); getSettings()->tempBan(player_name); context.say(StringUtils::insertValues( - "%s is now banned", player_name.c_str())); + "%s is now banned", player_name.c_str()), + true); } } // process_kick // ======================================================================== @@ -2571,11 +2572,12 @@ void CommandManager::process_randomteams(Context& context) msg = "No one can play!"; else msg = "Teams are currently not allowed"; - context.say(msg); + context.say(msg, true); return; } context.say(StringUtils::insertValues( - "Created %d teams for %d players", final_number, players_number)); + "Created %d teams for %d players", final_number, players_number), + true); getLobby()->updatePlayerList(); } // process_randomteams // ======================================================================== diff --git a/src/utils/command_manager/context.cpp b/src/utils/command_manager/context.cpp index c9949ec950a..fb01f6ace67 100644 --- a/src/utils/command_manager/context.cpp +++ b/src/utils/command_manager/context.cpp @@ -81,9 +81,9 @@ std::shared_ptr Context::command() } // command //----------------------------------------------------------------------------- -void Context::say(const std::string& s) +void Context::say(const std::string& s, bool allow_nullptr) { - if (m_peer.expired()) + if (!allow_nullptr && m_peer.expired()) throw std::logic_error("Context::say: Peer has expired"); auto peer = m_peer.lock(); diff --git a/src/utils/command_manager/context.hpp b/src/utils/command_manager/context.hpp index bad25ca5784..ec8ad7a04db 100644 --- a/src/utils/command_manager/context.hpp +++ b/src/utils/command_manager/context.hpp @@ -68,7 +68,9 @@ struct Context std::shared_ptr actingPeerMaybeNull(); std::shared_ptr command(); - void say(const std::string& s); + // Might be better to introduce a separate function + // instead of 2nd param for readability + void say(const std::string& s, bool allow_nullptr = false); void error(bool is_error = false); }; From 152069c8b432592dfdf50321ad520342fde5a5ed Mon Sep 17 00:00:00 2001 From: kimden <23140380+kimden@users.noreply.github.com> Date: Fri, 12 Dec 2025 04:18:14 +0400 Subject: [PATCH 830/830] Improvements for random teams - Can be invoked with a certain probability upon selection start if config/command allowed that - Still distributes the same quantities of the same teams, but first does it for all ingame players, then adds the rest of colors to waiting players. --- NETWORKING.md | 3 ++ data/commands.xml | 15 ++++++++++ src/network/protocols/command_manager.cpp | 35 ++++++++++++++++++++++- src/network/protocols/command_manager.hpp | 2 ++ src/network/protocols/server_lobby.cpp | 28 +++++++++++++++++- src/network/server_config.hpp | 4 +++ src/utils/lobby_settings.cpp | 1 + src/utils/lobby_settings.hpp | 5 ++++ src/utils/team_manager.cpp | 35 ++++++++++++++++------- src/utils/team_manager.hpp | 3 +- 10 files changed, 117 insertions(+), 14 deletions(-) diff --git a/NETWORKING.md b/NETWORKING.md index 8b4f3bcba59..db98d3bc752 100644 --- a/NETWORKING.md +++ b/NETWORKING.md @@ -406,6 +406,9 @@ A typical current server configuration xml that fits the current code version is + + + ``` diff --git a/data/commands.xml b/data/commands.xml index 6c64e3bee34..1fad48ca6c2 100644 --- a/data/commands.xml +++ b/data/commands.xml @@ -1214,6 +1214,21 @@ here later. For now, please refer to the code for the strings being used. --> permissions="UP_HAMMER" /> + + + forceRandomTeamsStart())); +} // process_cooldown +// ======================================================================== + +void CommandManager::process_forcerandom_assign(Context& context) +{ + auto& argv = context.m_argv; + + if (argv.size() < 2) + { + context.error(); + return; + } + float new_probability = -1; + if (!StringUtils::parseString(argv[1], &new_probability)) + { + context.error(); + return; + } + getSettings()->setForceRandomTeamsStart(new_probability); + + context.say(StringUtils::insertValues( + "Set probability for force shuffling teams to %s", + new_probability)); +} // process_forcerandom_assign +// ======================================================================== + void CommandManager::process_countteams(Context& context) { context.say(StringUtils::insertValues("Teams composition: %s", getTeamManager()->countTeamsAsString().c_str())); -} // process_cooldown +} // process_countteams // ======================================================================== void CommandManager::process_net(Context& context) diff --git a/src/network/protocols/command_manager.hpp b/src/network/protocols/command_manager.hpp index 410204ab530..33f3824304b 100644 --- a/src/network/protocols/command_manager.hpp +++ b/src/network/protocols/command_manager.hpp @@ -208,6 +208,8 @@ class CommandManager: public LobbyContextComponent void process_available_teams_assign(Context& context); void process_cooldown(Context& context); void process_cooldown_assign(Context& context); + void process_forcerandom(Context& context); + void process_forcerandom_assign(Context& context); void process_countteams(Context& context); void process_net(Context& context); void process_everynet(Context& context); diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 29034af3b8f..90004309ced 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -1865,6 +1865,18 @@ void ServerLobby::startSelection(const Event *event) peer->setWaitingForGame(true); } + // Bad but enough for the purpose + auto& rg = GlobalMt19937::get(); + double random_value = rg() % (0xFFFF) / (double)0x10000; + bool shuffled_teams = false; + if (random_value < getSettings()->forceRandomTeamsStart()) + { + shuffled_teams = true; + int final_number, players_number; + getTeamManager()->clearTeams(); + getTeamManager()->assignRandomTeams(-1, &final_number, &players_number); + } + getAssetManager()->eraseAssetsWithPeers(erasingPeers); max_player = 0; @@ -1949,8 +1961,22 @@ void ServerLobby::startSelection(const Event *event) peer->sendPacket(ns, PRM_RELIABLE); delete ns; + std::string message = ""; + const auto main_profile = peer->getMainProfile(); + + if (shuffled_teams && main_profile) + message += StringUtils::insertValues( + "You are now in team %s\n", + TeamUtils::getTeamByIndex(main_profile->getTemporaryTeam()).getNameWithEmoji().c_str()); + if (getQueues()->areKartFiltersIgnoringKarts()) - Comm::sendStringToPeer(peer, "The server will ignore your kart choice"); + message += "The server will ignore your kart choice\n"; + + if (!message.empty()) + { + message.pop_back(); + Comm::sendStringToPeer(peer, message); + } } m_state = SELECTING; diff --git a/src/network/server_config.hpp b/src/network/server_config.hpp index c135841ecf0..d1d0097e5bf 100644 --- a/src/network/server_config.hpp +++ b/src/network/server_config.hpp @@ -813,6 +813,10 @@ namespace ServerConfig "and take the playable slots of the server, even if the server " "is full. Make sure to not specify too many of them!")); + SERVER_CFG_PREFIX FloatServerConfigParam m_force_random_teams_start + SERVER_CFG_DEFAULT(FloatServerConfigParam(0.0f, "force-random-teams-start-probability", + "With this probability, the teams will be randomly assigned upon selection start.")); + // ======================================================================== /** Server version, will be advanced if there are protocol changes. */ static const uint32_t m_server_version = 6; diff --git a/src/utils/lobby_settings.cpp b/src/utils/lobby_settings.cpp index b7a81791ef8..cceb84b829f 100644 --- a/src/utils/lobby_settings.cpp +++ b/src/utils/lobby_settings.cpp @@ -125,6 +125,7 @@ void LobbySettings::setupContextUser() m_power_password_level_2 = ServerConfig::m_power_password_level_2; m_register_table_name = ServerConfig::m_register_table_name; m_lobby_cooldown = ServerConfig::m_lobby_cooldown; + m_force_random_teams_start = ServerConfig::m_force_random_teams_start; m_reserve_slots_for_players.fromVector( StringUtils::split(ServerConfig::m_reserve_slots_for_players, ' ')); diff --git a/src/utils/lobby_settings.hpp b/src/utils/lobby_settings.hpp index b9ed36e52b4..3003b6d7a52 100644 --- a/src/utils/lobby_settings.hpp +++ b/src/utils/lobby_settings.hpp @@ -101,6 +101,8 @@ class LobbySettings: public LobbyContextComponent // { m_battle_hit_capture_limit = value; } // void setBattleTimeLimit(float value) { m_battle_time_limit = value; } void setLobbyCooldown(int value) { m_lobby_cooldown = value; } + void setForceRandomTeamsStart(float value) + { m_force_random_teams_start = value; } bool isCooldown() const; @@ -184,6 +186,8 @@ class LobbySettings: public LobbyContextComponent bool isLegacyGPMode() const { return m_legacy_gp_mode; } bool isLegacyGPModeStarted() const { return m_legacy_gp_mode_started; } + float forceRandomTeamsStart() const { return m_force_random_teams_start; } + private: int m_battle_hit_capture_limit; @@ -267,6 +271,7 @@ class LobbySettings: public LobbyContextComponent std::string m_power_password_level_2; std::string m_register_table_name; int m_lobby_cooldown; + float m_force_random_teams_start; SetWithFlip m_reserve_slots_for_players; diff --git a/src/utils/team_manager.cpp b/src/utils/team_manager.cpp index a32c012494d..81d34db8b2a 100644 --- a/src/utils/team_manager.cpp +++ b/src/utils/team_manager.cpp @@ -360,13 +360,18 @@ bool TeamManager::assignRandomTeams(int intended_number, int teams_number = intended_number; *final_number = teams_number; int player_number = 0; + int ingame_player_number = 0; for (auto& p : STKHost::get()->getPeers()) { if (!getCrownManager()->canRace(p)) continue; if (p->alwaysSpectateButNotNeutral()) continue; - player_number += p->getPlayerProfiles().size(); + + size_t size = p->getPlayerProfiles().size(); + player_number += size; + if (!p->isWaitingForGame()) + ingame_player_number += size; } if (player_number == 0) { *final_number = teams_number; @@ -403,20 +408,28 @@ bool TeamManager::assignRandomTeams(int intended_number, for (int i = 0; i < player_number; ++i) profile_colors.push_back(available_colors[i % teams_number]); - std::shuffle(profile_colors.begin(), profile_colors.end(), g); + const auto it = profile_colors.begin() + ingame_player_number; + std::shuffle(profile_colors.begin(), it, g); + std::shuffle(it, profile_colors.end(), g); + std::reverse(profile_colors.begin(), profile_colors.end()); clearTemporaryTeams(); - for (auto& p : STKHost::get()->getPeers()) + for (int group = 0; group < 2; ++group) { - if (!getCrownManager()->canRace(p)) - continue; - if (p->alwaysSpectateButNotNeutral()) - continue; - for (auto& profile : p->getPlayerProfiles()) + for (auto& p : STKHost::get()->getPeers()) { - setTemporaryTeamInLobby(profile, profile_colors.back()); - if (profile_colors.size() > 1) // prevent crash just in case - profile_colors.pop_back(); + if (!getCrownManager()->canRace(p)) + continue; + if (p->alwaysSpectateButNotNeutral()) + continue; + if ((!p->isWaitingForGame()) ^ (group == 0)) + continue; + for (auto& profile : p->getPlayerProfiles()) + { + setTemporaryTeamInLobby(profile, profile_colors.back()); + if (profile_colors.size() > 1) // prevent crash just in case + profile_colors.pop_back(); + } } } return true; diff --git a/src/utils/team_manager.hpp b/src/utils/team_manager.hpp index 8431347ab5c..5d23b8d5672 100644 --- a/src/utils/team_manager.hpp +++ b/src/utils/team_manager.hpp @@ -80,7 +80,8 @@ class TeamManager: public LobbyContextComponent // The functions below reset/set ASM_NO_TEAM if needed by team changing procedure. void checkNoTeamSpectator(std::shared_ptr peer); - bool assignRandomTeams(int intended_number, int* final_number, int* player_number); + bool assignRandomTeams(int intended_number, + int* final_number, int* player_number); std::string countTeamsAsString(); void swapRedBlueTeams();

    (PxS*Jt){>q`Y-BF9(v}nL4Na5-)<08dU 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 YG1Of)&v+%^RcL^steQ-Xltsk<0f*Pyt^fc4 literal 5344 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